--- linux-3.13.0.orig/dropped.txt +++ linux-3.13.0/dropped.txt @@ -0,0 +1,4 @@ +UBUNTU: SAUCE: (no-up) Bluetooth: Implement broadcom patchram firmware loader +UBUNTU: SAUCE: (no-up) Bluetooth: Add support for 13d3:3388 and 13d3:3389 +UBUNTU: SAUCE: (no-up) mac80211_hwsim: Register and bind to driver +UBUNTU: SAUCE: AppArmor: basic networking rules --- linux-3.13.0.orig/MAINTAINERS +++ linux-3.13.0/MAINTAINERS @@ -665,6 +665,23 @@ F: drivers/net/appletalk/ F: net/appletalk/ +APPLIEDMICRO (APM) X-GENE SOC QUEUE MANAGER/TRAFFIC MANAGER (QMTM) DRIVER +M: Ravi Patel +M: Keyur Chudgar +S: Maintained +F: drivers/misc/xgene/ +F: include/misc/xgene/xgene_qmtm.h +F: Documentation/devicetree/bindings/misc/apm-xgene-qmtm.txt +F: Documentation/misc-devices/apm-xgene-qmtm + +APPLIEDMICRO (APM) X-GENE SOC ETHERNET DRIVER +M: Keyur Chudgar +M: Iyappan Subramanian +M: Ravi Patel +S: Maintained +F: drivers/net/ethernet/apm/ +F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt + APTINA CAMERA SENSOR PLL M: Laurent Pinchart L: linux-media@vger.kernel.org @@ -6345,6 +6362,13 @@ F: include/scsi/osd_* F: fs/exofs/ +OVERLAYFS FILESYSTEM +M: Miklos Szeredi +L: linux-fsdevel@vger.kernel.org +S: Supported +F: fs/overlayfs/* +F: Documentation/filesystems/overlayfs.txt + P54 WIRELESS DRIVER M: Christian Lamparter L: linux-wireless@vger.kernel.org @@ -6533,6 +6557,13 @@ S: Maintained F: drivers/pci/host/*designware* +PCI DRIVER FOR APPLIEDMICRO XGENE +M: Tanmay Inamdar +L: linux-pci@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: drivers/pci/host/pci-xgene.c + PCMCIA SUBSYSTEM P: Linux PCMCIA Team L: linux-pcmcia@lists.infradead.org --- linux-3.13.0.orig/Makefile +++ linux-3.13.0/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 13 -SUBLEVEL = 0 +SUBLEVEL = 8 EXTRAVERSION = NAME = One Giant Leap for Frogkind @@ -352,6 +352,12 @@ AFLAGS_KERNEL = CFLAGS_GCOV = -fprofile-arcs -ftest-coverage +# Prefer linux-backports-modules +ifneq ($(KBUILD_SRC),) +ifneq ($(shell if test -e $(KBUILD_OUTPUT)/ubuntu-build; then echo yes; fi),yes) +UBUNTUINCLUDE := -I/usr/src/linux-headers-lbm-$(KERNELRELEASE) +endif +endif # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ @@ -364,12 +370,16 @@ # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option LINUXINCLUDE := \ + $(UBUNTUINCLUDE) \ -I$(srctree)/arch/$(hdr-arch)/include \ -Iarch/$(hdr-arch)/include/generated \ $(if $(KBUILD_SRC), -I$(srctree)/include) \ -Iinclude \ $(USERINCLUDE) +# UBUNTU: Include our third party driver stuff too +LINUXINCLUDE += -Iubuntu/include $(if $(KBUILD_SRC),-I$(srctree)/ubuntu/include) + KBUILD_CPPFLAGS := -D__KERNEL__ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ @@ -522,7 +532,7 @@ # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ -drivers-y := drivers/ sound/ firmware/ +drivers-y := drivers/ sound/ firmware/ ubuntu/ net-y := net/ libs-y := lib/ core-y := usr/ @@ -940,6 +950,7 @@ $(error Headers not exportable for the $(SRCARCH) architecture)) $(Q)$(MAKE) $(hdr-inst)=include/uapi $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) + $(Q)$(MAKE) $(hdr-inst)=ubuntu/include dst=include oldheaders= PHONY += headers_check_all headers_check_all: headers_install_all @@ -949,6 +960,7 @@ headers_check: headers_install $(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1 $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) HDRCHECK=1 + $(Q)$(MAKE) $(hdr-inst)=ubuntu/include dst=include oldheaders= HDRCHECK=1 # --------------------------------------------------------------------------- # Modules --- linux-3.13.0.orig/drivers/Kconfig +++ linux-3.13.0/drivers/Kconfig @@ -170,4 +170,6 @@ source "drivers/powercap/Kconfig" +source "drivers/net/dpa/NetCommSw/Kconfig" + endmenu --- linux-3.13.0.orig/drivers/regulator/core.c +++ linux-3.13.0/drivers/regulator/core.c @@ -953,6 +953,8 @@ return 0; } +static int _regulator_do_enable(struct regulator_dev *rdev); + /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source @@ -1013,10 +1015,9 @@ /* If the constraints say the regulator should be on at this point * and we have control then make sure it is enabled. */ - if ((rdev->constraints->always_on || rdev->constraints->boot_on) && - ops->enable) { - ret = ops->enable(rdev); - if (ret < 0) { + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + ret = _regulator_do_enable(rdev); + if (ret < 0 && ret != -EINVAL) { rdev_err(rdev, "failed to enable\n"); goto out; } @@ -1272,6 +1273,8 @@ if (r->dev.parent && node == r->dev.of_node) return r; + *ret = -EPROBE_DEFER; + return NULL; } else { /* * If we couldn't even get the node then it's @@ -1312,7 +1315,7 @@ struct regulator_dev *rdev; struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); const char *devname = NULL; - int ret = -EPROBE_DEFER; + int ret; if (id == NULL) { pr_err("get() with no identifier\n"); @@ -1322,6 +1325,11 @@ if (dev) devname = dev_name(dev); + if (have_full_constraints()) + ret = -ENODEV; + else + ret = -EPROBE_DEFER; + mutex_lock(®ulator_list_mutex); rdev = regulator_dev_lookup(dev, id, &ret); @@ -1352,7 +1360,7 @@ rdev = dummy_regulator_rdev; goto found; } else { - dev_err(dev, "dummy supplies not allowed\n"); + dev_warn(dev, "dummy supplies not allowed\n"); } mutex_unlock(®ulator_list_mutex); @@ -1900,8 +1908,6 @@ trace_regulator_disable_complete(rdev_get_name(rdev)); - _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, - NULL); return 0; } @@ -1925,6 +1931,8 @@ rdev_err(rdev, "failed to disable\n"); return ret; } + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, + NULL); } rdev->use_count = 0; @@ -1977,20 +1985,16 @@ { int ret = 0; - /* force disable */ - if (rdev->desc->ops->disable) { - /* ah well, who wants to live forever... */ - ret = rdev->desc->ops->disable(rdev); - if (ret < 0) { - rdev_err(rdev, "failed to force disable\n"); - return ret; - } - /* notify other consumers that power has been forced off */ - _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | - REGULATOR_EVENT_DISABLE, NULL); + ret = _regulator_do_disable(rdev); + if (ret < 0) { + rdev_err(rdev, "failed to force disable\n"); + return ret; } - return ret; + _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | + REGULATOR_EVENT_DISABLE, NULL); + + return 0; } /** @@ -3623,23 +3627,18 @@ mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, ®ulator_list, list) { - struct regulator_ops *ops = rdev->desc->ops; - mutex_lock(&rdev->mutex); - if ((rdev->use_count > 0 || rdev->constraints->always_on) && - ops->enable) { - error = ops->enable(rdev); + if (rdev->use_count > 0 || rdev->constraints->always_on) { + error = _regulator_do_enable(rdev); if (error) ret = error; } else { if (!have_full_constraints()) goto unlock; - if (!ops->disable) - goto unlock; if (!_regulator_is_enabled(rdev)) goto unlock; - error = ops->disable(rdev); + error = _regulator_do_disable(rdev); if (error) ret = error; } @@ -3813,7 +3812,7 @@ ops = rdev->desc->ops; c = rdev->constraints; - if (!ops->disable || (c && c->always_on)) + if (c && c->always_on) continue; mutex_lock(&rdev->mutex); @@ -3834,7 +3833,7 @@ /* We log since this may kill the system if it * goes wrong. */ rdev_info(rdev, "disabling\n"); - ret = ops->disable(rdev); + ret = _regulator_do_disable(rdev); if (ret != 0) { rdev_err(rdev, "couldn't disable: %d\n", ret); } --- linux-3.13.0.orig/drivers/regulator/da9063-regulator.c +++ linux-3.13.0/drivers/regulator/da9063-regulator.c @@ -1,3 +1,4 @@ + /* * Regulator driver for DA9063 PMIC series * @@ -60,7 +61,8 @@ .desc.ops = &da9063_ldo_ops, \ .desc.min_uV = (min_mV) * 1000, \ .desc.uV_step = (step_mV) * 1000, \ - .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \ + .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1 \ + + (DA9063_V##regl_name##_BIAS)), \ .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \ .desc.enable_mask = DA9063_LDO_EN, \ .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \ --- linux-3.13.0.orig/drivers/firewire/sbp2.c +++ linux-3.13.0/drivers/firewire/sbp2.c @@ -146,6 +146,7 @@ */ int generation; int retries; + work_func_t workfn; struct delayed_work work; bool has_sdev; bool blocked; @@ -864,7 +865,7 @@ /* set appropriate retry limit(s) in BUSY_TIMEOUT register */ sbp2_set_busy_timeout(lu); - PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect); + lu->workfn = sbp2_reconnect; sbp2_agent_reset(lu); /* This was a re-login. */ @@ -918,7 +919,7 @@ * If a bus reset happened, sbp2_update will have requeued * lu->work already. Reset the work from reconnect to login. */ - PREPARE_DELAYED_WORK(&lu->work, sbp2_login); + lu->workfn = sbp2_login; } static void sbp2_reconnect(struct work_struct *work) @@ -952,7 +953,7 @@ lu->retries++ >= 5) { dev_err(tgt_dev(tgt), "failed to reconnect\n"); lu->retries = 0; - PREPARE_DELAYED_WORK(&lu->work, sbp2_login); + lu->workfn = sbp2_login; } sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); @@ -972,6 +973,13 @@ sbp2_conditionally_unblock(lu); } +static void sbp2_lu_workfn(struct work_struct *work) +{ + struct sbp2_logical_unit *lu = container_of(to_delayed_work(work), + struct sbp2_logical_unit, work); + lu->workfn(work); +} + static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) { struct sbp2_logical_unit *lu; @@ -998,7 +1006,8 @@ lu->blocked = false; ++tgt->dont_block; INIT_LIST_HEAD(&lu->orb_list); - INIT_DELAYED_WORK(&lu->work, sbp2_login); + lu->workfn = sbp2_login; + INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn); list_add_tail(&lu->link, &tgt->lu_list); return 0; --- linux-3.13.0.orig/drivers/firewire/ohci.c +++ linux-3.13.0/drivers/firewire/ohci.c @@ -290,7 +290,6 @@ #define QUIRK_NO_MSI 0x10 #define QUIRK_TI_SLLZ059 0x20 #define QUIRK_IR_WAKE 0x40 -#define QUIRK_PHY_LCTRL_TIMEOUT 0x80 /* In case of multiple matches in ohci_quirks[], only the first one is used. */ static const struct { @@ -303,10 +302,7 @@ QUIRK_BE_HEADERS}, {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, - QUIRK_PHY_LCTRL_TIMEOUT | QUIRK_NO_MSI}, - - {PCI_VENDOR_ID_ATT, PCI_ANY_ID, PCI_ANY_ID, - QUIRK_PHY_LCTRL_TIMEOUT}, + QUIRK_NO_MSI}, {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID, QUIRK_RESET_PACKET}, @@ -353,7 +349,6 @@ ", disable MSI = " __stringify(QUIRK_NO_MSI) ", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059) ", IR wake unreliable = " __stringify(QUIRK_IR_WAKE) - ", phy LCtrl timeout = " __stringify(QUIRK_PHY_LCTRL_TIMEOUT) ")"); #define OHCI_PARAM_DEBUG_AT_AR 1 @@ -2295,9 +2290,6 @@ * TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but * cannot actually use the phy at that time. These need tens of * millisecods pause between LPS write and first phy access too. - * - * But do not wait for 50msec on Agere/LSI cards. Their phy - * arbitration state machine may time out during such a long wait. */ reg_write(ohci, OHCI1394_HCControlSet, @@ -2305,11 +2297,8 @@ OHCI1394_HCControl_postedWriteEnable); flush_writes(ohci); - if (!(ohci->quirks & QUIRK_PHY_LCTRL_TIMEOUT)) + for (lps = 0, i = 0; !lps && i < 3; i++) { msleep(50); - - for (lps = 0, i = 0; !lps && i < 150; i++) { - msleep(1); lps = reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS; } --- linux-3.13.0.orig/drivers/firewire/core-device.c +++ linux-3.13.0/drivers/firewire/core-device.c @@ -916,7 +916,7 @@ old->config_rom_retries = 0; fw_notice(card, "rediscovered device %s\n", dev_name(dev)); - PREPARE_DELAYED_WORK(&old->work, fw_device_update); + old->workfn = fw_device_update; fw_schedule_device_work(old, 0); if (current_node == card->root_node) @@ -1075,7 +1075,7 @@ if (atomic_cmpxchg(&device->state, FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_GONE) { - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); + device->workfn = fw_device_shutdown; fw_schedule_device_work(device, SHUTDOWN_DELAY); } else { fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n", @@ -1196,13 +1196,20 @@ dev_name(&device->device), fw_rcode_string(ret)); gone: atomic_set(&device->state, FW_DEVICE_GONE); - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); + device->workfn = fw_device_shutdown; fw_schedule_device_work(device, SHUTDOWN_DELAY); out: if (node_id == card->root_node->node_id) fw_schedule_bm_work(card, 0); } +static void fw_device_workfn(struct work_struct *work) +{ + struct fw_device *device = container_of(to_delayed_work(work), + struct fw_device, work); + device->workfn(work); +} + void fw_node_event(struct fw_card *card, struct fw_node *node, int event) { struct fw_device *device; @@ -1252,7 +1259,8 @@ * power-up after getting plugged in. We schedule the * first config rom scan half a second after bus reset. */ - INIT_DELAYED_WORK(&device->work, fw_device_init); + device->workfn = fw_device_init; + INIT_DELAYED_WORK(&device->work, fw_device_workfn); fw_schedule_device_work(device, INITIAL_DELAY); break; @@ -1268,7 +1276,7 @@ if (atomic_cmpxchg(&device->state, FW_DEVICE_RUNNING, FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { - PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); + device->workfn = fw_device_refresh; fw_schedule_device_work(device, device->is_local ? 0 : INITIAL_DELAY); } @@ -1283,7 +1291,7 @@ smp_wmb(); /* update node_id before generation */ device->generation = card->generation; if (atomic_read(&device->state) == FW_DEVICE_RUNNING) { - PREPARE_DELAYED_WORK(&device->work, fw_device_update); + device->workfn = fw_device_update; fw_schedule_device_work(device, 0); } break; @@ -1308,7 +1316,7 @@ device = node->data; if (atomic_xchg(&device->state, FW_DEVICE_GONE) == FW_DEVICE_RUNNING) { - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); + device->workfn = fw_device_shutdown; fw_schedule_device_work(device, list_empty(&card->link) ? 0 : SHUTDOWN_DELAY); } --- linux-3.13.0.orig/drivers/firewire/net.c +++ linux-3.13.0/drivers/firewire/net.c @@ -929,8 +929,6 @@ if (rcode == RCODE_COMPLETE) { fwnet_transmit_packet_done(ptask); } else { - fwnet_transmit_packet_failed(ptask); - if (printk_timed_ratelimit(&j, 1000) || rcode != last_rcode) { dev_err(&ptask->dev->netdev->dev, "fwnet_write_complete failed: %x (skipped %d)\n", @@ -938,8 +936,10 @@ errors_skipped = 0; last_rcode = rcode; - } else + } else { errors_skipped++; + } + fwnet_transmit_packet_failed(ptask); } } --- linux-3.13.0.orig/drivers/infiniband/ulp/isert/ib_isert.h +++ linux-3.13.0/drivers/infiniband/ulp/isert/ib_isert.h @@ -6,6 +6,7 @@ #define ISERT_RDMA_LISTEN_BACKLOG 10 #define ISCSI_ISER_SG_TABLESIZE 256 +#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL enum isert_desc_type { ISCSI_TX_CONTROL, @@ -45,6 +46,7 @@ struct isert_cmd *isert_cmd; struct llist_node *comp_llnode_batch; struct llist_node comp_llnode; + bool llnode_active; struct ib_send_wr send_wr; } __packed; @@ -116,8 +118,8 @@ struct isert_device *conn_device; struct work_struct conn_logout_work; struct mutex conn_mutex; - wait_queue_head_t conn_wait; - wait_queue_head_t conn_wait_comp_err; + struct completion conn_wait; + struct completion conn_wait_comp_err; struct kref conn_kref; struct list_head conn_frwr_pool; int conn_frwr_pool_size; @@ -126,7 +128,6 @@ #define ISERT_COMP_BATCH_COUNT 8 int conn_comp_batch; struct llist_head conn_comp_llist; - struct mutex conn_comp_mutex; }; #define ISERT_MAX_CQ 64 --- linux-3.13.0.orig/drivers/infiniband/ulp/isert/ib_isert.c +++ linux-3.13.0/drivers/infiniband/ulp/isert/ib_isert.c @@ -497,12 +497,11 @@ isert_conn->state = ISER_CONN_INIT; INIT_LIST_HEAD(&isert_conn->conn_accept_node); init_completion(&isert_conn->conn_login_comp); - init_waitqueue_head(&isert_conn->conn_wait); - init_waitqueue_head(&isert_conn->conn_wait_comp_err); + init_completion(&isert_conn->conn_wait); + init_completion(&isert_conn->conn_wait_comp_err); kref_init(&isert_conn->conn_kref); kref_get(&isert_conn->conn_kref); mutex_init(&isert_conn->conn_mutex); - mutex_init(&isert_conn->conn_comp_mutex); spin_lock_init(&isert_conn->conn_lock); cma_id->context = isert_conn; @@ -671,11 +670,11 @@ pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); mutex_lock(&isert_conn->conn_mutex); - isert_conn->state = ISER_CONN_DOWN; + if (isert_conn->state == ISER_CONN_UP) + isert_conn->state = ISER_CONN_TERMINATING; if (isert_conn->post_recv_buf_count == 0 && atomic_read(&isert_conn->post_send_buf_count) == 0) { - pr_debug("Calling wake_up(&isert_conn->conn_wait);\n"); mutex_unlock(&isert_conn->conn_mutex); goto wake_up; } @@ -695,7 +694,7 @@ mutex_unlock(&isert_conn->conn_mutex); wake_up: - wake_up(&isert_conn->conn_wait); + complete(&isert_conn->conn_wait); isert_put_conn(isert_conn); } @@ -871,16 +870,17 @@ * Coalesce send completion interrupts by only setting IB_SEND_SIGNALED * bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls. */ - mutex_lock(&isert_conn->conn_comp_mutex); - if (coalesce && + mutex_lock(&isert_conn->conn_mutex); + if (coalesce && isert_conn->state == ISER_CONN_UP && ++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) { + tx_desc->llnode_active = true; llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist); - mutex_unlock(&isert_conn->conn_comp_mutex); + mutex_unlock(&isert_conn->conn_mutex); return; } isert_conn->conn_comp_batch = 0; tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist); - mutex_unlock(&isert_conn->conn_comp_mutex); + mutex_unlock(&isert_conn->conn_mutex); send_wr->send_flags = IB_SEND_SIGNALED; } @@ -1447,7 +1447,7 @@ case ISCSI_OP_SCSI_CMD: spin_lock_bh(&conn->cmd_lock); if (!list_empty(&cmd->i_conn_node)) - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); if (cmd->data_direction == DMA_TO_DEVICE) @@ -1459,7 +1459,7 @@ case ISCSI_OP_SCSI_TMFUNC: spin_lock_bh(&conn->cmd_lock); if (!list_empty(&cmd->i_conn_node)) - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); transport_generic_free_cmd(&cmd->se_cmd, 0); @@ -1469,7 +1469,7 @@ case ISCSI_OP_TEXT: spin_lock_bh(&conn->cmd_lock); if (!list_empty(&cmd->i_conn_node)) - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); /* @@ -1532,6 +1532,7 @@ iscsit_stop_dataout_timer(cmd); device->unreg_rdma_mem(isert_cmd, isert_conn); cmd->write_data_done = wr->cur_rdma_length; + wr->send_wr_num = 0; pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd); spin_lock_bh(&cmd->istate_lock); @@ -1572,7 +1573,7 @@ pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n"); /* * Call atomic_dec(&isert_conn->post_send_buf_count) - * from isert_free_conn() + * from isert_wait_conn() */ isert_conn->logout_posted = true; iscsit_logout_post_handler(cmd, cmd->conn); @@ -1596,6 +1597,7 @@ struct ib_device *ib_dev) { struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; + struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; if (cmd->i_state == ISTATE_SEND_TASKMGTRSP || cmd->i_state == ISTATE_SEND_LOGOUTRSP || @@ -1607,7 +1609,7 @@ queue_work(isert_comp_wq, &isert_cmd->comp_work); return; } - atomic_dec(&isert_conn->post_send_buf_count); + atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); cmd->i_state = ISTATE_SENT_STATUS; isert_completion_put(tx_desc, isert_cmd, ib_dev); @@ -1645,7 +1647,7 @@ case ISER_IB_RDMA_READ: pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n"); - atomic_dec(&isert_conn->post_send_buf_count); + atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count); isert_completion_rdma_read(tx_desc, isert_cmd); break; default: @@ -1674,31 +1676,76 @@ } static void -isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) +isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev) +{ + struct llist_node *llnode; + struct isert_rdma_wr *wr; + struct iser_tx_desc *t; + + mutex_lock(&isert_conn->conn_mutex); + llnode = llist_del_all(&isert_conn->conn_comp_llist); + isert_conn->conn_comp_batch = 0; + mutex_unlock(&isert_conn->conn_mutex); + + while (llnode) { + t = llist_entry(llnode, struct iser_tx_desc, comp_llnode); + llnode = llist_next(llnode); + wr = &t->isert_cmd->rdma_wr; + + atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); + isert_completion_put(t, t->isert_cmd, ib_dev); + } +} + +static void +isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) { struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_cmd *isert_cmd = tx_desc->isert_cmd; + struct llist_node *llnode = tx_desc->comp_llnode_batch; + struct isert_rdma_wr *wr; + struct iser_tx_desc *t; - if (tx_desc) { - struct isert_cmd *isert_cmd = tx_desc->isert_cmd; + while (llnode) { + t = llist_entry(llnode, struct iser_tx_desc, comp_llnode); + llnode = llist_next(llnode); + wr = &t->isert_cmd->rdma_wr; - if (!isert_cmd) - isert_unmap_tx_desc(tx_desc, ib_dev); - else - isert_completion_put(tx_desc, isert_cmd, ib_dev); + atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); + isert_completion_put(t, t->isert_cmd, ib_dev); } + tx_desc->comp_llnode_batch = NULL; - if (isert_conn->post_recv_buf_count == 0 && - atomic_read(&isert_conn->post_send_buf_count) == 0) { - pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - pr_debug("Calling wake_up from isert_cq_comp_err\n"); + if (!isert_cmd) + isert_unmap_tx_desc(tx_desc, ib_dev); + else + isert_completion_put(tx_desc, isert_cmd, ib_dev); +} - mutex_lock(&isert_conn->conn_mutex); - if (isert_conn->state != ISER_CONN_DOWN) - isert_conn->state = ISER_CONN_TERMINATING; - mutex_unlock(&isert_conn->conn_mutex); +static void +isert_cq_rx_comp_err(struct isert_conn *isert_conn) +{ + struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct iscsi_conn *conn = isert_conn->conn; - wake_up(&isert_conn->conn_wait_comp_err); + if (isert_conn->post_recv_buf_count) + return; + + isert_cq_drain_comp_llist(isert_conn, ib_dev); + + if (conn->sess) { + target_sess_cmd_list_set_waiting(conn->sess->se_sess); + target_wait_for_sess_cmds(conn->sess->se_sess); } + + while (atomic_read(&isert_conn->post_send_buf_count)) + msleep(3000); + + mutex_lock(&isert_conn->conn_mutex); + isert_conn->state = ISER_CONN_DOWN; + mutex_unlock(&isert_conn->conn_mutex); + + complete(&isert_conn->conn_wait_comp_err); } static void @@ -1723,8 +1770,14 @@ pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n"); pr_debug("TX wc.status: 0x%08x\n", wc.status); pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err); - atomic_dec(&isert_conn->post_send_buf_count); - isert_cq_comp_err(tx_desc, isert_conn); + + if (wc.wr_id != ISER_FASTREG_LI_WRID) { + if (tx_desc->llnode_active) + continue; + + atomic_dec(&isert_conn->post_send_buf_count); + isert_cq_tx_comp_err(tx_desc, isert_conn); + } } } @@ -1767,7 +1820,7 @@ wc.vendor_err); } isert_conn->post_recv_buf_count--; - isert_cq_comp_err(NULL, isert_conn); + isert_cq_rx_comp_err(isert_conn); } } @@ -2189,6 +2242,7 @@ if (!fr_desc->valid) { memset(&inv_wr, 0, sizeof(inv_wr)); + inv_wr.wr_id = ISER_FASTREG_LI_WRID; inv_wr.opcode = IB_WR_LOCAL_INV; inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey; wr = &inv_wr; @@ -2199,6 +2253,7 @@ /* Prepare FASTREG WR */ memset(&fr_wr, 0, sizeof(fr_wr)); + fr_wr.wr_id = ISER_FASTREG_LI_WRID; fr_wr.opcode = IB_WR_FAST_REG_MR; fr_wr.wr.fast_reg.iova_start = fr_desc->data_frpl->page_list[0] + page_off; @@ -2364,12 +2419,12 @@ isert_init_send_wr(isert_conn, isert_cmd, &isert_cmd->tx_desc.send_wr, true); - atomic_inc(&isert_conn->post_send_buf_count); + atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed); if (rc) { pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n"); - atomic_dec(&isert_conn->post_send_buf_count); + atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); } pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n", isert_cmd); @@ -2397,12 +2452,12 @@ return rc; } - atomic_inc(&isert_conn->post_send_buf_count); + atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count); rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed); if (rc) { pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n"); - atomic_dec(&isert_conn->post_send_buf_count); + atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count); } pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n", isert_cmd); @@ -2689,22 +2744,11 @@ kfree(isert_np); } -static int isert_check_state(struct isert_conn *isert_conn, int state) -{ - int ret; - - mutex_lock(&isert_conn->conn_mutex); - ret = (isert_conn->state == state); - mutex_unlock(&isert_conn->conn_mutex); - - return ret; -} - -static void isert_free_conn(struct iscsi_conn *conn) +static void isert_wait_conn(struct iscsi_conn *conn) { struct isert_conn *isert_conn = conn->context; - pr_debug("isert_free_conn: Starting \n"); + pr_debug("isert_wait_conn: Starting \n"); /* * Decrement post_send_buf_count for special case when called * from isert_do_control_comp() -> iscsit_logout_post_handler() @@ -2714,38 +2758,29 @@ atomic_dec(&isert_conn->post_send_buf_count); if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) { - pr_debug("Calling rdma_disconnect from isert_free_conn\n"); + pr_debug("Calling rdma_disconnect from isert_wait_conn\n"); rdma_disconnect(isert_conn->conn_cm_id); } /* * Only wait for conn_wait_comp_err if the isert_conn made it * into full feature phase.. */ - if (isert_conn->state == ISER_CONN_UP) { - pr_debug("isert_free_conn: Before wait_event comp_err %d\n", - isert_conn->state); - mutex_unlock(&isert_conn->conn_mutex); - - wait_event(isert_conn->conn_wait_comp_err, - (isert_check_state(isert_conn, ISER_CONN_TERMINATING))); - - wait_event(isert_conn->conn_wait, - (isert_check_state(isert_conn, ISER_CONN_DOWN))); - - isert_put_conn(isert_conn); - return; - } if (isert_conn->state == ISER_CONN_INIT) { mutex_unlock(&isert_conn->conn_mutex); - isert_put_conn(isert_conn); return; } - pr_debug("isert_free_conn: wait_event conn_wait %d\n", - isert_conn->state); + if (isert_conn->state == ISER_CONN_UP) + isert_conn->state = ISER_CONN_TERMINATING; mutex_unlock(&isert_conn->conn_mutex); - wait_event(isert_conn->conn_wait, - (isert_check_state(isert_conn, ISER_CONN_DOWN))); + wait_for_completion(&isert_conn->conn_wait_comp_err); + + wait_for_completion(&isert_conn->conn_wait); +} + +static void isert_free_conn(struct iscsi_conn *conn) +{ + struct isert_conn *isert_conn = conn->context; isert_put_conn(isert_conn); } @@ -2758,6 +2793,7 @@ .iscsit_setup_np = isert_setup_np, .iscsit_accept_np = isert_accept_np, .iscsit_free_np = isert_free_np, + .iscsit_wait_conn = isert_wait_conn, .iscsit_free_conn = isert_free_conn, .iscsit_get_login_rx = isert_get_login_rx, .iscsit_put_login_tx = isert_put_login_tx, --- linux-3.13.0.orig/drivers/infiniband/hw/qib/qib_iba7322.c +++ linux-3.13.0/drivers/infiniband/hw/qib/qib_iba7322.c @@ -2395,6 +2395,11 @@ qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a); qib_write_kreg(dd, kr_scratch, 0ULL); + /* ensure previous Tx parameters are not still forced */ + qib_write_kreg_port(ppd, krp_tx_deemph_override, + SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, + reset_tx_deemphasis_override)); + if (qib_compat_ddr_negotiate) { ppd->cpspec->ibdeltainprog = 1; ppd->cpspec->ibsymsnap = read_7322_creg32_port(ppd, --- linux-3.13.0.orig/drivers/infiniband/hw/qib/qib_ud.c +++ linux-3.13.0/drivers/infiniband/hw/qib/qib_ud.c @@ -57,13 +57,20 @@ struct qib_sge *sge; struct ib_wc wc; u32 length; + enum ib_qp_type sqptype, dqptype; qp = qib_lookup_qpn(ibp, swqe->wr.wr.ud.remote_qpn); if (!qp) { ibp->n_pkt_drops++; return; } - if (qp->ibqp.qp_type != sqp->ibqp.qp_type || + + sqptype = sqp->ibqp.qp_type == IB_QPT_GSI ? + IB_QPT_UD : sqp->ibqp.qp_type; + dqptype = qp->ibqp.qp_type == IB_QPT_GSI ? + IB_QPT_UD : qp->ibqp.qp_type; + + if (dqptype != sqptype || !(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) { ibp->n_pkt_drops++; goto drop; --- linux-3.13.0.orig/drivers/bluetooth/btusb.c +++ linux-3.13.0/drivers/bluetooth/btusb.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 #define BTUSB_INTEL 0x100 +#define BTUSB_BCM_PATCHRAM 0x800 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -105,13 +107,20 @@ { USB_DEVICE(0x0b05, 0x17cb) }, { USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x0489, 0xe042) }, - { USB_DEVICE(0x413c, 0x8197) }, + { USB_DEVICE(0x13d3, 0x3388), .driver_info = BTUSB_BCM_PATCHRAM }, + { USB_DEVICE(0x13d3, 0x3389), .driver_info = BTUSB_BCM_PATCHRAM }, + { USB_DEVICE(0x413c, 0x8197), .driver_info = BTUSB_BCM_PATCHRAM }, + { USB_DEVICE(0x413c, 0x8143), .driver_info = BTUSB_BCM_PATCHRAM }, + + /* Broadcom BCM43142A0 */ + { USB_DEVICE(0x04ca, 0x2007), .driver_info = BTUSB_BCM_PATCHRAM }, + { USB_DEVICE(0x105b, 0xe065), .driver_info = BTUSB_BCM_PATCHRAM }, /* Foxconn - Hon Hai */ - { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, /*Broadcom devices with vendor specific id */ - { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, @@ -1331,6 +1340,71 @@ return 0; } +static int btusb_setup_patchram_packet(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + kfree_skb(skb); + return 0; +} + +#define PATCHRAM_NAME_LEN 20 + +static int btusb_setup_patchram(struct hci_dev *hdev) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct usb_device *udev = data->udev; + size_t pos = 0; + int err = 0; + char filename[PATCHRAM_NAME_LEN]; + const struct firmware *fw; + u8 val = 0x00; + + snprintf(filename, PATCHRAM_NAME_LEN, "fw-%04x_%04x.hcd", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + if (request_firmware(&fw, (const char *) filename, &udev->dev) < 0) { + BT_INFO("can't load firmware, may not work correctly"); + return 0; + } + + err = btusb_setup_patchram_packet(hdev, 0x0c03, 1, &val); + if (err) + goto out; + + err = btusb_setup_patchram_packet(hdev, 0xfc2e, 1, &val); + if (err) + goto out; + + msleep(1000); + while (pos < fw->size) { + size_t len; + len = fw->data[pos + 2] + 3; + if (pos + len > fw->size) { + err = -EINVAL; + goto out; + } + err = btusb_setup_patchram_packet(hdev, le16_to_cpu(*(u16*)(fw->data + pos)), + fw->data[pos + 2] , &fw->data[pos + 3]); + if (err) + goto out; + pos += len; + } + + err = btusb_setup_patchram_packet(hdev, 0x0c03, 1, &val); +out: + release_firmware(fw); + if (err) { + BT_INFO("fail to load firmware"); + return err; + } + BT_INFO("firmware loaded"); + return 0; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1439,6 +1513,9 @@ if (id->driver_info & BTUSB_INTEL) hdev->setup = btusb_setup_intel; + if (id->driver_info & BTUSB_BCM_PATCHRAM) + hdev->setup = btusb_setup_patchram; + /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); --- linux-3.13.0.orig/drivers/power/max17040_battery.c +++ linux-3.13.0/drivers/power/max17040_battery.c @@ -148,7 +148,7 @@ { struct max17040_chip *chip = i2c_get_clientdata(client); - if (chip->pdata->battery_online) + if (chip->pdata && chip->pdata->battery_online) chip->online = chip->pdata->battery_online(); else chip->online = 1; @@ -158,7 +158,8 @@ { struct max17040_chip *chip = i2c_get_clientdata(client); - if (!chip->pdata->charger_online || !chip->pdata->charger_enable) { + if (!chip->pdata || !chip->pdata->charger_online + || !chip->pdata->charger_enable) { chip->status = POWER_SUPPLY_STATUS_UNKNOWN; return; } --- linux-3.13.0.orig/drivers/power/reset/syscon-reboot.c +++ linux-3.13.0/drivers/power/reset/syscon-reboot.c @@ -0,0 +1,100 @@ +/* + * Generic Syscon Reboot Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Author: Feng Kan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * This driver provides system reboot functionality for APM X-Gene SoC. + * For system shutdown, this is board specify. If a board designer + * implements GPIO shutdown, use the gpio-poweroff.c driver. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct syscon_reboot_context { + struct regmap *map; + u32 offset; + u32 mask; +}; + +static struct syscon_reboot_context *syscon_reboot_ctx; + +static void syscon_restart(enum reboot_mode reboot_mode, const char *cmd) +{ + struct syscon_reboot_context *ctx = syscon_reboot_ctx; + unsigned long timeout; + + /* Issue the reboot */ + if (ctx->map) + regmap_write(ctx->map, ctx->offset, ctx->mask); + + timeout = jiffies + HZ; + while (time_before(jiffies, timeout)) + cpu_relax(); + + pr_emerg("Unable to restart system\n"); +} + +static int syscon_reboot_probe(struct platform_device *pdev) +{ + struct syscon_reboot_context *ctx; + struct device *dev = &pdev->dev; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + dev_err(&pdev->dev, "out of memory for context\n"); + return -ENOMEM; + } + + ctx->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); + if (IS_ERR(ctx->map)) + return PTR_ERR(ctx->map); + + if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset)) + return -EINVAL; + + if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask)) + return -EINVAL; + + arm_pm_restart = syscon_restart; + syscon_reboot_ctx = ctx; + + return 0; +} + +static struct of_device_id syscon_reboot_of_match[] = { + { .compatible = "syscon-reboot" }, + {} +}; + +static struct platform_driver syscon_reboot_driver = { + .probe = syscon_reboot_probe, + .driver = { + .name = "syscon-reboot", + .of_match_table = syscon_reboot_of_match, + }, +}; +module_platform_driver(syscon_reboot_driver); --- linux-3.13.0.orig/drivers/power/reset/Makefile +++ linux-3.13.0/drivers/power/reset/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o +obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o --- linux-3.13.0.orig/drivers/power/reset/Kconfig +++ linux-3.13.0/drivers/power/reset/Kconfig @@ -51,3 +51,11 @@ depends on POWER_RESET help Reboot support for the APM SoC X-Gene Eval boards. + +config POWER_RESET_SYSCON + bool "Generic SYSCON regmap reset driver" + depends on MFD_SYSCON + depends on POWER_RESET + depends on ARCH_XGENE + help + Reboot support for generic SYSCON mapped register reset. --- linux-3.13.0.orig/drivers/phy/phy-core.c +++ linux-3.13.0/drivers/phy/phy-core.c @@ -161,6 +161,8 @@ dev_err(&phy->dev, "phy init failed --> %d\n", ret); goto out; } + } else { + ret = 0; /* Override possible ret == -ENOTSUPP */ } out: @@ -209,6 +211,8 @@ dev_err(&phy->dev, "phy poweron failed --> %d\n", ret); goto out; } + } else { + ret = 0; /* Override possible ret == -ENOTSUPP */ } out: --- linux-3.13.0.orig/drivers/phy/phy-xgene.c +++ linux-3.13.0/drivers/phy/phy-xgene.c @@ -0,0 +1,1750 @@ +/* + * AppliedMicro X-Gene Multi-purpose PHY driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Loc Ho + * Tuan Phan + * Suman Tripathi + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * The APM X-Gene PHY consists of two PLL clock macro's (CMU) and lanes. + * The first PLL clock macro is used for internal reference clock. The second + * PLL clock macro is used to generate the clock for the PHY. This driver + * configures the first PLL CMU, the second PLL CMU, and programs the PHY to + * operate according to the mode of operation. The first PLL CMU is only + * required if internal clock is enabled. + * + * Logical Layer Out Of HW module units: + * + * ----------------- + * | Internal | |------| + * | Ref PLL CMU |----| | ------------- --------- + * ------------ ---- | MUX |-----|PHY PLL CMU|----| Serdes| + * | | | | --------- + * External Clock ------| | ------------- + * |------| + * + * The Ref PLL CMU CSR (Configuration System Registers) is accessed + * indirectly from the SDS offset at 0x2000. It is only required for + * internal reference clock. + * The PHY PLL CMU CSR is accessed indirectly from the SDS offset at 0x0000. + * The Serdes CSR is accessed indirectly from the SDS offset at 0x0400. + * + * The Ref PLL CMU can be located within the same PHY IP or outside the PHY IP + * due to shared Ref PLL CMU. For PHY with Ref PLL CMU shared with another IP, + * it is located outside the PHY IP. This is the case for the PHY located + * at 0x1f23a000 (SATA Port 4/5). For such PHY, another resource is required + * to located the SDS/Ref PLL CMU module and its clock for that IP enabled. + * + * Currently, this driver only supports Gen3 SATA mode with external clock. + */ +#include +#include +#include +#include +#include +#include + +/* Max 2 lanes per a PHY unit */ +#define MAX_LANE 2 + +/* Register offset inside the PHY */ +#define SERDES_PLL_INDIRECT_OFFSET 0x0000 +#define SERDES_PLL_REF_INDIRECT_OFFSET 0x2000 +#define SERDES_INDIRECT_OFFSET 0x0400 +#define SERDES_LANE_STRIDE 0x0200 + +/* Some default Serdes parameters */ +#define DEFAULT_SATA_TXBOOST_GAIN { 0x1e, 0x1e, 0x1e } +#define DEFAULT_SATA_TXEYEDIRECTION { 0x0, 0x0, 0x0 } +#define DEFAULT_SATA_TXEYETUNING { 0xa, 0xa, 0xa } +#define DEFAULT_SATA_SPD_SEL { 0x1, 0x3, 0x7 } +#define DEFAULT_SATA_TXAMP { 0x8, 0x8, 0x8 } +#define DEFAULT_SATA_TXCN1 { 0x2, 0x2, 0x2 } +#define DEFAULT_SATA_TXCN2 { 0x0, 0x0, 0x0 } +#define DEFAULT_SATA_TXCP1 { 0xa, 0xa, 0xa } + +#define SATA_SPD_SEL_GEN3 0x7 +#define SATA_SPD_SEL_GEN2 0x3 +#define SATA_SPD_SEL_GEN1 0x1 + +#define SSC_DISABLE 0 +#define SSC_ENABLE 1 + +#define FBDIV_VAL_50M 0x77 +#define REFDIV_VAL_50M 0x1 +#define FBDIV_VAL_100M 0x3B +#define REFDIV_VAL_100M 0x0 + +/* SATA Clock/Reset CSR */ +#define SATACLKENREG 0x00000000 +#define SATA0_CORE_CLKEN 0x00000002 +#define SATA1_CORE_CLKEN 0x00000004 +#define SATASRESETREG 0x00000004 +#define SATA_MEM_RESET_MASK 0x00000020 +#define SATA_MEM_RESET_RD(src) (((src) & 0x00000020) >> 5) +#define SATA_SDS_RESET_MASK 0x00000004 +#define SATA_CSR_RESET_MASK 0x00000001 +#define SATA_CORE_RESET_MASK 0x00000002 +#define SATA_PMCLK_RESET_MASK 0x00000010 +#define SATA_PCLK_RESET_MASK 0x00000008 + +/* SDS CSR used for PHY Indirect access */ +#define SATA_ENET_SDS_PCS_CTL0 0x00000000 +#define REGSPEC_CFG_I_TX_WORDMODE0_SET(dst, src) \ + (((dst) & ~0x00070000) | (((u32) (src) << 16) & 0x00070000)) +#define REGSPEC_CFG_I_RX_WORDMODE0_SET(dst, src) \ + (((dst) & ~0x00e00000) | (((u32) (src) << 21) & 0x00e00000)) +#define SATA_ENET_SDS_CTL0 0x0000000c +#define REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(dst, src) \ + (((dst) & ~0x00007fff) | (((u32) (src)) & 0x00007fff)) +#define SATA_ENET_SDS_CTL1 0x00000010 +#define CFG_I_SPD_SEL_CDR_OVR1_SET(dst, src) \ + (((dst) & ~0x0000000f) | (((u32) (src)) & 0x0000000f)) +#define SATA_ENET_SDS_RST_CTL 0x00000024 +#define SATA_ENET_SDS_IND_CMD_REG 0x0000003c +#define CFG_IND_WR_CMD_MASK 0x00000001 +#define CFG_IND_RD_CMD_MASK 0x00000002 +#define CFG_IND_CMD_DONE_MASK 0x00000004 +#define CFG_IND_ADDR_SET(dst, src) \ + (((dst) & ~0x003ffff0) | (((u32) (src) << 4) & 0x003ffff0)) +#define SATA_ENET_SDS_IND_RDATA_REG 0x00000040 +#define SATA_ENET_SDS_IND_WDATA_REG 0x00000044 +#define SATA_ENET_CLK_MACRO_REG 0x0000004c +#define I_RESET_B_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32) (src)) & 0x00000001)) +#define I_PLL_FBDIV_SET(dst, src) \ + (((dst) & ~0x001ff000) | (((u32) (src) << 12) & 0x001ff000)) +#define I_CUSTOMEROV_SET(dst, src) \ + (((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80)) +#define O_PLL_LOCK_RD(src) (((src) & 0x40000000) >> 30) +#define O_PLL_READY_RD(src) (((src) & 0x80000000) >> 31) + +/* PLL Clock Macro Unit (CMU) CSR accessing from SDS indirectly */ +#define CMU_REG0 0x00000 +#define CMU_REG0_PLL_REF_SEL_MASK 0x00002000 +#define CMU_REG0_PLL_REF_SEL_SET(dst, src) \ + (((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000)) +#define CMU_REG0_PDOWN_MASK 0x00004000 +#define CMU_REG0_CAL_COUNT_RESOL_SET(dst, src) \ + (((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0)) +#define CMU_REG1 0x00002 +#define CMU_REG1_PLL_CP_SET(dst, src) \ + (((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00)) +#define CMU_REG1_PLL_MANUALCAL_SET(dst, src) \ + (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008)) +#define CMU_REG1_PLL_CP_SEL_SET(dst, src) \ + (((dst) & ~0x000003e0) | (((u32) (src) << 5) & 0x000003e0)) +#define CMU_REG1_REFCLK_CMOS_SEL_MASK 0x00000001 +#define CMU_REG1_REFCLK_CMOS_SEL_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001)) +#define CMU_REG2 0x00004 +#define CMU_REG2_PLL_REFDIV_SET(dst, src) \ + (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000)) +#define CMU_REG2_PLL_LFRES_SET(dst, src) \ + (((dst) & ~0x0000001e) | (((u32) (src) << 1) & 0x0000001e)) +#define CMU_REG2_PLL_FBDIV_SET(dst, src) \ + (((dst) & ~0x00003fe0) | (((u32) (src) << 5) & 0x00003fe0)) +#define CMU_REG3 0x00006 +#define CMU_REG3_VCOVARSEL_SET(dst, src) \ + (((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f)) +#define CMU_REG3_VCO_MOMSEL_INIT_SET(dst, src) \ + (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0)) +#define CMU_REG3_VCO_MANMOMSEL_SET(dst, src) \ + (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00)) +#define CMU_REG4 0x00008 +#define CMU_REG5 0x0000a +#define CMU_REG5_PLL_LFSMCAP_SET(dst, src) \ + (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000)) +#define CMU_REG5_PLL_LOCK_RESOLUTION_SET(dst, src) \ + (((dst) & ~0x0000000e) | (((u32) (src) << 1) & 0x0000000e)) +#define CMU_REG5_PLL_LFCAP_SET(dst, src) \ + (((dst) & ~0x00003000) | (((u32) (src) << 12) & 0x00003000)) +#define CMU_REG5_PLL_RESETB_MASK 0x00000001 +#define CMU_REG6 0x0000c +#define CMU_REG6_PLL_VREGTRIM_SET(dst, src) \ + (((dst) & ~0x00000600) | (((u32) (src) << 9) & 0x00000600)) +#define CMU_REG6_MAN_PVT_CAL_SET(dst, src) \ + (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004)) +#define CMU_REG7 0x0000e +#define CMU_REG7_PLL_CALIB_DONE_RD(src) ((0x00004000 & (u32) (src)) >> 14) +#define CMU_REG7_VCO_CAL_FAIL_RD(src) ((0x00000c00 & (u32) (src)) >> 10) +#define CMU_REG8 0x00010 +#define CMU_REG9 0x00012 +#define CMU_REG9_WORD_LEN_8BIT 0x000 +#define CMU_REG9_WORD_LEN_10BIT 0x001 +#define CMU_REG9_WORD_LEN_16BIT 0x002 +#define CMU_REG9_WORD_LEN_20BIT 0x003 +#define CMU_REG9_WORD_LEN_32BIT 0x004 +#define CMU_REG9_WORD_LEN_40BIT 0x005 +#define CMU_REG9_WORD_LEN_64BIT 0x006 +#define CMU_REG9_WORD_LEN_66BIT 0x007 +#define CMU_REG9_TX_WORD_MODE_CH1_SET(dst, src) \ + (((dst) & ~0x00000380) | (((u32) (src) << 7) & 0x00000380)) +#define CMU_REG9_TX_WORD_MODE_CH0_SET(dst, src) \ + (((dst) & ~0x00000070) | (((u32) (src) << 4) & 0x00000070)) +#define CMU_REG9_PLL_POST_DIVBY2_SET(dst, src) \ + (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008)) +#define CMU_REG9_VBG_BYPASSB_SET(dst, src) \ + (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004)) +#define CMU_REG9_IGEN_BYPASS_SET(dst, src) \ + (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002)) +#define CMU_REG10 0x00014 +#define CMU_REG10_VREG_REFSEL_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001)) +#define CMU_REG11 0x00016 +#define CMU_REG12 0x00018 +#define CMU_REG12_STATE_DELAY9_SET(dst, src) \ + (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0)) +#define CMU_REG13 0x0001a +#define CMU_REG14 0x0001c +#define CMU_REG15 0x0001e +#define CMU_REG16 0x00020 +#define CMU_REG16_PVT_DN_MAN_ENA_MASK 0x00000001 +#define CMU_REG16_PVT_UP_MAN_ENA_MASK 0x00000002 +#define CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(dst, src) \ + (((dst) & ~0x0000001c) | (((u32) (src) << 2) & 0x0000001c)) +#define CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(dst, src) \ + (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040)) +#define CMU_REG16_BYPASS_PLL_LOCK_SET(dst, src) \ + (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020)) +#define CMU_REG17 0x00022 +#define CMU_REG17_PVT_CODE_R2A_SET(dst, src) \ + (((dst) & ~0x00007f00) | (((u32) (src) << 8) & 0x00007f00)) +#define CMU_REG17_RESERVED_7_SET(dst, src) \ + (((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0)) +#define CMU_REG17_PVT_TERM_MAN_ENA_MASK 0x00008000 +#define CMU_REG18 0x00024 +#define CMU_REG19 0x00026 +#define CMU_REG20 0x00028 +#define CMU_REG21 0x0002a +#define CMU_REG22 0x0002c +#define CMU_REG23 0x0002e +#define CMU_REG24 0x00030 +#define CMU_REG25 0x00032 +#define CMU_REG26 0x00034 +#define CMU_REG26_FORCE_PLL_LOCK_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001)) +#define CMU_REG27 0x00036 +#define CMU_REG28 0x00038 +#define CMU_REG29 0x0003a +#define CMU_REG30 0x0003c +#define CMU_REG30_LOCK_COUNT_SET(dst, src) \ + (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006)) +#define CMU_REG30_PCIE_MODE_SET(dst, src) \ + (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008)) +#define CMU_REG31 0x0003e +#define CMU_REG32 0x00040 +#define CMU_REG32_FORCE_VCOCAL_START_MASK 0x00004000 +#define CMU_REG32_PVT_CAL_WAIT_SEL_SET(dst, src) \ + (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006)) +#define CMU_REG32_IREF_ADJ_SET(dst, src) \ + (((dst) & ~0x00000180) | (((u32) (src) << 7) & 0x00000180)) +#define CMU_REG33 0x00042 +#define CMU_REG34 0x00044 +#define CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(dst, src) \ + (((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f)) +#define CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(dst, src) \ + (((dst) & ~0x00000f00) | (((u32) (src) << 8) & 0x00000f00)) +#define CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(dst, src) \ + (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0)) +#define CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(dst, src) \ + (((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000)) +#define CMU_REG35 0x00046 +#define CMU_REG35_PLL_SSC_MOD_SET(dst, src) \ + (((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00)) +#define CMU_REG36 0x00048 +#define CMU_REG36_PLL_SSC_EN_SET(dst, src) \ + (((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010)) +#define CMU_REG36_PLL_SSC_VSTEP_SET(dst, src) \ + (((dst) & ~0x0000ffc0) | (((u32) (src) << 6) & 0x0000ffc0)) +#define CMU_REG36_PLL_SSC_DSMSEL_SET(dst, src) \ + (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020)) +#define CMU_REG37 0x0004a +#define CMU_REG38 0x0004c +#define CMU_REG39 0x0004e + +/* PHY lane CSR accessing from SDS indirectly */ +#define RXTX_REG0 0x000 +#define RXTX_REG0_CTLE_EQ_HR_SET(dst, src) \ + (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800)) +#define RXTX_REG0_CTLE_EQ_QR_SET(dst, src) \ + (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0)) +#define RXTX_REG0_CTLE_EQ_FR_SET(dst, src) \ + (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e)) +#define RXTX_REG1 0x002 +#define RXTX_REG1_RXACVCM_SET(dst, src) \ + (((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000)) +#define RXTX_REG1_CTLE_EQ_SET(dst, src) \ + (((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80)) +#define RXTX_REG1_RXVREG1_SET(dst, src) \ + (((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060)) +#define RXTX_REG1_RXIREF_ADJ_SET(dst, src) \ + (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006)) +#define RXTX_REG2 0x004 +#define RXTX_REG2_VTT_ENA_SET(dst, src) \ + (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100)) +#define RXTX_REG2_TX_FIFO_ENA_SET(dst, src) \ + (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020)) +#define RXTX_REG2_VTT_SEL_SET(dst, src) \ + (((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0)) +#define RXTX_REG4 0x008 +#define RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK 0x00000040 +#define RXTX_REG4_TX_DATA_RATE_SET(dst, src) \ + (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000)) +#define RXTX_REG4_TX_WORD_MODE_SET(dst, src) \ + (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800)) +#define RXTX_REG5 0x00a +#define RXTX_REG5_TX_CN1_SET(dst, src) \ + (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800)) +#define RXTX_REG5_TX_CP1_SET(dst, src) \ + (((dst) & ~0x000007e0) | (((u32) (src) << 5) & 0x000007e0)) +#define RXTX_REG5_TX_CN2_SET(dst, src) \ + (((dst) & ~0x0000001f) | (((u32) (src) << 0) & 0x0000001f)) +#define RXTX_REG6 0x00c +#define RXTX_REG6_TXAMP_CNTL_SET(dst, src) \ + (((dst) & ~0x00000780) | (((u32) (src) << 7) & 0x00000780)) +#define RXTX_REG6_TXAMP_ENA_SET(dst, src) \ + (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040)) +#define RXTX_REG6_RX_BIST_ERRCNT_RD_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001)) +#define RXTX_REG6_TX_IDLE_SET(dst, src) \ + (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008)) +#define RXTX_REG6_RX_BIST_RESYNC_SET(dst, src) \ + (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002)) +#define RXTX_REG7 0x00e +#define RXTX_REG7_RESETB_RXD_MASK 0x00000100 +#define RXTX_REG7_RESETB_RXA_MASK 0x00000080 +#define RXTX_REG7_BIST_ENA_RX_SET(dst, src) \ + (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040)) +#define RXTX_REG7_RX_WORD_MODE_SET(dst, src) \ + (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800)) +#define RXTX_REG8 0x010 +#define RXTX_REG8_CDR_LOOP_ENA_SET(dst, src) \ + (((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000)) +#define RXTX_REG8_CDR_BYPASS_RXLOS_SET(dst, src) \ + (((dst) & ~0x00000800) | (((u32) (src) << 11) & 0x00000800)) +#define RXTX_REG8_SSC_ENABLE_SET(dst, src) \ + (((dst) & ~0x00000200) | (((u32) (src) << 9) & 0x00000200)) +#define RXTX_REG8_SD_VREF_SET(dst, src) \ + (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0)) +#define RXTX_REG8_SD_DISABLE_SET(dst, src) \ + (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100)) +#define RXTX_REG7 0x00e +#define RXTX_REG7_RESETB_RXD_SET(dst, src) \ + (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100)) +#define RXTX_REG7_RESETB_RXA_SET(dst, src) \ + (((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080)) +#define RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK 0x00004000 +#define RXTX_REG7_LOOP_BACK_ENA_CTLE_SET(dst, src) \ + (((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000)) +#define RXTX_REG11 0x016 +#define RXTX_REG11_PHASE_ADJUST_LIMIT_SET(dst, src) \ + (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800)) +#define RXTX_REG12 0x018 +#define RXTX_REG12_LATCH_OFF_ENA_SET(dst, src) \ + (((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000)) +#define RXTX_REG12_SUMOS_ENABLE_SET(dst, src) \ + (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004)) +#define RXTX_REG12_RX_DET_TERM_ENABLE_MASK 0x00000002 +#define RXTX_REG12_RX_DET_TERM_ENABLE_SET(dst, src) \ + (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002)) +#define RXTX_REG13 0x01a +#define RXTX_REG14 0x01c +#define RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(dst, src) \ + (((dst) & ~0x0000003f) | (((u32) (src) << 0) & 0x0000003f)) +#define RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(dst, src) \ + (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040)) +#define RXTX_REG26 0x034 +#define RXTX_REG26_PERIOD_ERROR_LATCH_SET(dst, src) \ + (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800)) +#define RXTX_REG26_BLWC_ENA_SET(dst, src) \ + (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008)) +#define RXTX_REG21 0x02a +#define RXTX_REG21_DO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10) +#define RXTX_REG21_XO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4) +#define RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(src) ((0x0000000f & (u32)(src))) +#define RXTX_REG22 0x02c +#define RXTX_REG22_SO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4) +#define RXTX_REG22_EO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10) +#define RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(src) ((0x0000000f & (u32)(src))) +#define RXTX_REG23 0x02e +#define RXTX_REG23_DE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10) +#define RXTX_REG23_XE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4) +#define RXTX_REG24 0x030 +#define RXTX_REG24_EE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10) +#define RXTX_REG24_SE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4) +#define RXTX_REG27 0x036 +#define RXTX_REG28 0x038 +#define RXTX_REG31 0x03e +#define RXTX_REG38 0x04c +#define RXTX_REG38_CUSTOMER_PINMODE_INV_SET(dst, src) \ + (((dst) & 0x0000fffe) | (((u32) (src) << 1) & 0x0000fffe)) +#define RXTX_REG39 0x04e +#define RXTX_REG40 0x050 +#define RXTX_REG41 0x052 +#define RXTX_REG42 0x054 +#define RXTX_REG43 0x056 +#define RXTX_REG44 0x058 +#define RXTX_REG45 0x05a +#define RXTX_REG46 0x05c +#define RXTX_REG47 0x05e +#define RXTX_REG48 0x060 +#define RXTX_REG49 0x062 +#define RXTX_REG50 0x064 +#define RXTX_REG51 0x066 +#define RXTX_REG52 0x068 +#define RXTX_REG53 0x06a +#define RXTX_REG54 0x06c +#define RXTX_REG55 0x06e +#define RXTX_REG61 0x07a +#define RXTX_REG61_ISCAN_INBERT_SET(dst, src) \ + (((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010)) +#define RXTX_REG61_LOADFREQ_SHIFT_SET(dst, src) \ + (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008)) +#define RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(dst, src) \ + (((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0)) +#define RXTX_REG61_SPD_SEL_CDR_SET(dst, src) \ + (((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00)) +#define RXTX_REG62 0x07c +#define RXTX_REG62_PERIOD_H1_QLATCH_SET(dst, src) \ + (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800)) +#define RXTX_REG81 0x0a2 +#define RXTX_REG89_MU_TH7_SET(dst, src) \ + (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800)) +#define RXTX_REG89_MU_TH8_SET(dst, src) \ + (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0)) +#define RXTX_REG89_MU_TH9_SET(dst, src) \ + (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e)) +#define RXTX_REG96 0x0c0 +#define RXTX_REG96_MU_FREQ1_SET(dst, src) \ + (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800)) +#define RXTX_REG96_MU_FREQ2_SET(dst, src) \ + (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0)) +#define RXTX_REG96_MU_FREQ3_SET(dst, src) \ + (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e)) +#define RXTX_REG99 0x0c6 +#define RXTX_REG99_MU_PHASE1_SET(dst, src) \ + (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800)) +#define RXTX_REG99_MU_PHASE2_SET(dst, src) \ + (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0)) +#define RXTX_REG99_MU_PHASE3_SET(dst, src) \ + (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e)) +#define RXTX_REG102 0x0cc +#define RXTX_REG102_FREQLOOP_LIMIT_SET(dst, src) \ + (((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060)) +#define RXTX_REG114 0x0e4 +#define RXTX_REG121 0x0f2 +#define RXTX_REG121_SUMOS_CAL_CODE_RD(src) ((0x0000003e & (u32)(src)) >> 0x1) +#define RXTX_REG125 0x0fa +#define RXTX_REG125_PQ_REG_SET(dst, src) \ + (((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00)) +#define RXTX_REG125_SIGN_PQ_SET(dst, src) \ + (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100)) +#define RXTX_REG125_SIGN_PQ_2C_SET(dst, src) \ + (((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080)) +#define RXTX_REG125_PHZ_MANUALCODE_SET(dst, src) \ + (((dst) & ~0x0000007c) | (((u32) (src) << 2) & 0x0000007c)) +#define RXTX_REG125_PHZ_MANUAL_SET(dst, src) \ + (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002)) +#define RXTX_REG127 0x0fe +#define RXTX_REG127_FORCE_SUM_CAL_START_MASK 0x00000002 +#define RXTX_REG127_FORCE_LAT_CAL_START_MASK 0x00000004 +#define RXTX_REG127_FORCE_SUM_CAL_START_SET(dst, src) \ + (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002)) +#define RXTX_REG127_FORCE_LAT_CAL_START_SET(dst, src) \ + (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004)) +#define RXTX_REG127_LATCH_MAN_CAL_ENA_SET(dst, src) \ + (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008)) +#define RXTX_REG127_DO_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00)) +#define RXTX_REG127_XO_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0)) +#define RXTX_REG128 0x100 +#define RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(dst, src) \ + (((dst) & ~0x0000000c) | (((u32) (src) << 2) & 0x0000000c)) +#define RXTX_REG128_EO_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00)) +#define RXTX_REG128_SO_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0)) +#define RXTX_REG129 0x102 +#define RXTX_REG129_DE_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00)) +#define RXTX_REG129_XE_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0)) +#define RXTX_REG130 0x104 +#define RXTX_REG130_EE_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00)) +#define RXTX_REG130_SE_LATCH_MANCAL_SET(dst, src) \ + (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0)) +#define RXTX_REG145 0x122 +#define RXTX_REG145_TX_IDLE_SATA_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001)) +#define RXTX_REG145_RXES_ENA_SET(dst, src) \ + (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002)) +#define RXTX_REG145_RXDFE_CONFIG_SET(dst, src) \ + (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000)) +#define RXTX_REG145_RXVWES_LATENA_SET(dst, src) \ + (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004)) +#define RXTX_REG147 0x126 +#define RXTX_REG148 0x128 + +/* Clock macro type */ +enum cmu_type_t { + REF_CMU = 0, /* Clock macro is the internal reference clock */ + PHY_CMU = 1, /* Clock macro is the PLL for the Serdes */ +}; + +enum mux_type_t { + MUX_SELECT_ATA = 0, /* Switch the MUX to ATA */ + MUX_SELECT_SGMMII = 0, /* Switch the MUX to SGMII */ +}; + +enum clk_type_t { + CLK_EXT_DIFF = 0, /* External differential */ + CLK_INT_DIFF = 1, /* Internal differential */ + CLK_INT_SING = 2, /* Internal single ended */ +}; + +enum phy_mode { + MODE_SATA = 0, /* List them for simple reference */ + MODE_SGMII = 1, + MODE_PCIE = 2, + MODE_USB = 3, + MODE_XFI = 4, + MODE_MAX +}; + +struct xgene_sata_override_param { + u32 speed[MAX_LANE]; /* Index for override parameter per lane */ + u32 txspeed[3]; /* Tx speed */ + u32 txboostgain[MAX_LANE*3]; /* Tx freq boost and gain control */ + u32 txeyetuning[MAX_LANE*3]; /* Tx eye tuning */ + u32 txeyedirection[MAX_LANE*3]; /* Tx eye tuning direction */ + u32 txamplitude[MAX_LANE*3]; /* Tx amplitude control */ + u32 txprecursor_cn1[MAX_LANE*3]; /* Tx emphasis taps 1st pre-cursor */ + u32 txprecursor_cn2[MAX_LANE*3]; /* Tx emphasis taps 2nd pre-cursor */ + u32 txpostcursor_cp1[MAX_LANE*3]; /* Tx emphasis taps post-cursor */ +}; + +struct xgene_phy_ctx { + struct device *dev; + struct phy *phy; + enum phy_mode mode; /* Mode of operation */ + enum clk_type_t clk_type; /* Input clock selection */ + void __iomem *sds_base; /* PHY CSR base addr */ + struct clk *clk; /* Optional clock */ + + /* Override Serdes parameters */ + struct xgene_sata_override_param sata_param; +}; + +/* + * For chip earlier than A3 version, enable this flag. + * To enable, pass boot argument phy_xgene.preA3Chip=1 + */ +static int preA3Chip; +MODULE_PARM_DESC(preA3Chip, "Enable pre-A3 chip support (1=enable 0=disable)"); +module_param_named(preA3Chip, preA3Chip, int, 0444); + +static void sds_wr(void __iomem *csr_base, u32 indirect_cmd_reg, + u32 indirect_data_reg, u32 addr, u32 data) +{ + unsigned long deadline = jiffies + HZ; + u32 val; + u32 cmd; + + cmd = CFG_IND_WR_CMD_MASK | CFG_IND_CMD_DONE_MASK; + cmd = CFG_IND_ADDR_SET(cmd, addr); + writel(data, csr_base + indirect_data_reg); + readl(csr_base + indirect_data_reg); /* Force a barrier */ + writel(cmd, csr_base + indirect_cmd_reg); + readl(csr_base + indirect_cmd_reg); /* Force a barrier */ + do { + val = readl(csr_base + indirect_cmd_reg); + } while (!(val & CFG_IND_CMD_DONE_MASK) && + time_before(jiffies, deadline)); + if (!(val & CFG_IND_CMD_DONE_MASK)) + pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n", + csr_base + indirect_cmd_reg, addr, data); +} + +static void sds_rd(void __iomem *csr_base, u32 indirect_cmd_reg, + u32 indirect_data_reg, u32 addr, u32 *data) +{ + unsigned long deadline = jiffies + HZ; + u32 val; + u32 cmd; + + cmd = CFG_IND_RD_CMD_MASK | CFG_IND_CMD_DONE_MASK; + cmd = CFG_IND_ADDR_SET(cmd, addr); + writel(cmd, csr_base + indirect_cmd_reg); + readl(csr_base + indirect_cmd_reg); /* Force a barrier */ + do { + val = readl(csr_base + indirect_cmd_reg); + } while (!(val & CFG_IND_CMD_DONE_MASK) && + time_before(jiffies, deadline)); + *data = readl(csr_base + indirect_data_reg); + if (!(val & CFG_IND_CMD_DONE_MASK)) + pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n", + csr_base + indirect_cmd_reg, addr, *data); +} + +static void cmu_wr(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type, + u32 reg, u32 data) +{ + void __iomem *sds_base = ctx->sds_base; + u32 val; + + if (cmu_type == REF_CMU) + reg += SERDES_PLL_REF_INDIRECT_OFFSET; + else + reg += SERDES_PLL_INDIRECT_OFFSET; + sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG, + SATA_ENET_SDS_IND_WDATA_REG, reg, data); + sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG, + SATA_ENET_SDS_IND_RDATA_REG, reg, &val); + pr_debug("CMU WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data, val); +} + +static void cmu_rd(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type, + u32 reg, u32 *data) +{ + void __iomem *sds_base = ctx->sds_base; + + if (cmu_type == REF_CMU) + reg += SERDES_PLL_REF_INDIRECT_OFFSET; + else + reg += SERDES_PLL_INDIRECT_OFFSET; + sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG, + SATA_ENET_SDS_IND_RDATA_REG, reg, data); + pr_debug("CMU RD addr 0x%X value 0x%08X\n", reg, *data); +} + +static void cmu_toggle1to0(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type, + u32 reg, u32 bits) +{ + u32 val; + + cmu_rd(ctx, cmu_type, reg, &val); + val |= bits; + cmu_wr(ctx, cmu_type, reg, val); + cmu_rd(ctx, cmu_type, reg, &val); + val &= ~bits; + cmu_wr(ctx, cmu_type, reg, val); +} + +static void cmu_clrbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type, + u32 reg, u32 bits) +{ + u32 val; + + cmu_rd(ctx, cmu_type, reg, &val); + val &= ~bits; + cmu_wr(ctx, cmu_type, reg, val); +} + +static void cmu_setbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type, + u32 reg, u32 bits) +{ + u32 val; + + cmu_rd(ctx, cmu_type, reg, &val); + val |= bits; + cmu_wr(ctx, cmu_type, reg, val); +} + +static void serdes_wr(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 data) +{ + void __iomem *sds_base = ctx->sds_base; + u32 val; + + reg += SERDES_INDIRECT_OFFSET; + reg += lane * SERDES_LANE_STRIDE; + sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG, + SATA_ENET_SDS_IND_WDATA_REG, reg, data); + sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG, + SATA_ENET_SDS_IND_RDATA_REG, reg, &val); + pr_debug("SERDES WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data, + val); +} + +static void serdes_rd(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 *data) +{ + void __iomem *sds_base = ctx->sds_base; + + reg += SERDES_INDIRECT_OFFSET; + reg += lane * SERDES_LANE_STRIDE; + sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG, + SATA_ENET_SDS_IND_RDATA_REG, reg, data); + pr_debug("SERDES RD addr 0x%X value 0x%08X\n", reg, *data); +} + +static void serdes_clrbits(struct xgene_phy_ctx *ctx, int lane, u32 reg, + u32 bits) +{ + u32 val; + + serdes_rd(ctx, lane, reg, &val); + val &= ~bits; + serdes_wr(ctx, lane, reg, val); +} + +static void serdes_setbits(struct xgene_phy_ctx *ctx, int lane, u32 reg, + u32 bits) +{ + u32 val; + + serdes_rd(ctx, lane, reg, &val); + val |= bits; + serdes_wr(ctx, lane, reg, val); +} + +static void xgene_phy_cfg_cmu_clk_type(struct xgene_phy_ctx *ctx, + enum cmu_type_t cmu_type, + enum clk_type_t clk_type) +{ + u32 val; + + /* Set the reset sequence delay for TX ready assertion */ + cmu_rd(ctx, cmu_type, CMU_REG12, &val); + val = CMU_REG12_STATE_DELAY9_SET(val, 0x1); + cmu_wr(ctx, cmu_type, CMU_REG12, val); + /* Set the programmable stage delays between various enable stages */ + cmu_wr(ctx, cmu_type, CMU_REG13, 0x0222); + cmu_wr(ctx, cmu_type, CMU_REG14, 0x2225); + + /* Configure clock type */ + if (clk_type == CLK_EXT_DIFF) { + /* Select external clock mux */ + cmu_rd(ctx, cmu_type, CMU_REG0, &val); + val = CMU_REG0_PLL_REF_SEL_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG0, val); + /* Select CMOS as reference clock */ + cmu_rd(ctx, cmu_type, CMU_REG1, &val); + val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG1, val); + dev_dbg(ctx->dev, "Set external reference clock\n"); + } else if (clk_type == CLK_INT_DIFF) { + /* Select internal clock mux */ + cmu_rd(ctx, cmu_type, CMU_REG0, &val); + val = CMU_REG0_PLL_REF_SEL_SET(val, 0x1); + cmu_wr(ctx, cmu_type, CMU_REG0, val); + /* Select CMOS as reference clock */ + cmu_rd(ctx, cmu_type, CMU_REG1, &val); + val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1); + cmu_wr(ctx, cmu_type, CMU_REG1, val); + dev_dbg(ctx->dev, "Set internal reference clock\n"); + } else if (clk_type == CLK_INT_SING) { + /* + * NOTE: This clock type is NOT support for controller + * whose internal clock shared in the PCIe controller + * + * Select internal clock mux + */ + cmu_rd(ctx, cmu_type, CMU_REG1, &val); + val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1); + cmu_wr(ctx, cmu_type, CMU_REG1, val); + /* Select CML as reference clock */ + cmu_rd(ctx, cmu_type, CMU_REG1, &val); + val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG1, val); + dev_dbg(ctx->dev, + "Set internal single ended reference clock\n"); + } +} + +static void xgene_phy_sata_cfg_cmu_core(struct xgene_phy_ctx *ctx, + enum cmu_type_t cmu_type, + enum clk_type_t clk_type) +{ + u32 val; + int ref_100MHz; + + if (cmu_type == REF_CMU) { + /* Set VCO calibration voltage threshold */ + cmu_rd(ctx, cmu_type, CMU_REG34, &val); + val = CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(val, 0x7); + val = CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(val, 0xc); + val = CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(val, 0x3); + val = CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(val, 0x8); + cmu_wr(ctx, cmu_type, CMU_REG34, val); + } + + /* Set the VCO calibration counter */ + cmu_rd(ctx, cmu_type, CMU_REG0, &val); + if (cmu_type == REF_CMU || preA3Chip) + val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x4); + else + val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x7); + cmu_wr(ctx, cmu_type, CMU_REG0, val); + + /* Configure PLL for calibration */ + cmu_rd(ctx, cmu_type, CMU_REG1, &val); + val = CMU_REG1_PLL_CP_SET(val, 0x1); + if (cmu_type == REF_CMU || preA3Chip) + val = CMU_REG1_PLL_CP_SEL_SET(val, 0x5); + else + val = CMU_REG1_PLL_CP_SEL_SET(val, 0x3); + if (cmu_type == REF_CMU) + val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0); + else + val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x1); + cmu_wr(ctx, cmu_type, CMU_REG1, val); + + if (cmu_type != REF_CMU) + cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK); + + /* Configure the PLL for either 100MHz or 50MHz */ + cmu_rd(ctx, cmu_type, CMU_REG2, &val); + if (cmu_type == REF_CMU) { + val = CMU_REG2_PLL_LFRES_SET(val, 0xa); + ref_100MHz = 1; + } else { + val = CMU_REG2_PLL_LFRES_SET(val, 0x3); + if (clk_type == CLK_EXT_DIFF) + ref_100MHz = 0; + else + ref_100MHz = 1; + } + if (ref_100MHz) { + val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_100M); + val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_100M); + } else { + val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_50M); + val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_50M); + } + cmu_wr(ctx, cmu_type, CMU_REG2, val); + + /* Configure the VCO */ + cmu_rd(ctx, cmu_type, CMU_REG3, &val); + if (cmu_type == REF_CMU) { + val = CMU_REG3_VCOVARSEL_SET(val, 0x3); + val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x10); + } else { + val = CMU_REG3_VCOVARSEL_SET(val, 0xF); + if (preA3Chip) + val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x15); + else + val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x1a); + val = CMU_REG3_VCO_MANMOMSEL_SET(val, 0x15); + } + cmu_wr(ctx, cmu_type, CMU_REG3, val); + + /* Disable force PLL lock */ + cmu_rd(ctx, cmu_type, CMU_REG26, &val); + val = CMU_REG26_FORCE_PLL_LOCK_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG26, val); + + /* Setup PLL loop filter */ + cmu_rd(ctx, cmu_type, CMU_REG5, &val); + val = CMU_REG5_PLL_LFSMCAP_SET(val, 0x3); + val = CMU_REG5_PLL_LFCAP_SET(val, 0x3); + if (cmu_type == REF_CMU || !preA3Chip) + val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x7); + else + val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x4); + cmu_wr(ctx, cmu_type, CMU_REG5, val); + + /* Enable or disable manual calibration */ + cmu_rd(ctx, cmu_type, CMU_REG6, &val); + val = CMU_REG6_PLL_VREGTRIM_SET(val, preA3Chip ? 0x0 : 0x2); + val = CMU_REG6_MAN_PVT_CAL_SET(val, preA3Chip ? 0x1 : 0x0); + cmu_wr(ctx, cmu_type, CMU_REG6, val); + + /* Configure lane for 20-bits */ + if (cmu_type == PHY_CMU) { + cmu_rd(ctx, cmu_type, CMU_REG9, &val); + val = CMU_REG9_TX_WORD_MODE_CH1_SET(val, + CMU_REG9_WORD_LEN_20BIT); + val = CMU_REG9_TX_WORD_MODE_CH0_SET(val, + CMU_REG9_WORD_LEN_20BIT); + val = CMU_REG9_PLL_POST_DIVBY2_SET(val, 0x1); + if (!preA3Chip) { + val = CMU_REG9_VBG_BYPASSB_SET(val, 0x0); + val = CMU_REG9_IGEN_BYPASS_SET(val , 0x0); + } + cmu_wr(ctx, cmu_type, CMU_REG9, val); + + if (!preA3Chip) { + cmu_rd(ctx, cmu_type, CMU_REG10, &val); + val = CMU_REG10_VREG_REFSEL_SET(val, 0x1); + cmu_wr(ctx, cmu_type, CMU_REG10, val); + } + } + + cmu_rd(ctx, cmu_type, CMU_REG16, &val); + val = CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(val, 0x1); + val = CMU_REG16_BYPASS_PLL_LOCK_SET(val, 0x1); + if (cmu_type == REF_CMU || preA3Chip) + val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x4); + else + val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7); + cmu_wr(ctx, cmu_type, CMU_REG16, val); + + /* Configure for SATA */ + cmu_rd(ctx, cmu_type, CMU_REG30, &val); + val = CMU_REG30_PCIE_MODE_SET(val, 0x0); + val = CMU_REG30_LOCK_COUNT_SET(val, 0x3); + cmu_wr(ctx, cmu_type, CMU_REG30, val); + + /* Disable state machine bypass */ + cmu_wr(ctx, cmu_type, CMU_REG31, 0xF); + + cmu_rd(ctx, cmu_type, CMU_REG32, &val); + val = CMU_REG32_PVT_CAL_WAIT_SEL_SET(val, 0x3); + if (cmu_type == REF_CMU || preA3Chip) + val = CMU_REG32_IREF_ADJ_SET(val, 0x3); + else + val = CMU_REG32_IREF_ADJ_SET(val, 0x1); + cmu_wr(ctx, cmu_type, CMU_REG32, val); + + /* Set VCO calibration threshold */ + if (cmu_type != REF_CMU && preA3Chip) + cmu_wr(ctx, cmu_type, CMU_REG34, 0x8d27); + else + cmu_wr(ctx, cmu_type, CMU_REG34, 0x873c); + + /* Set CTLE Override and override waiting from state machine */ + cmu_wr(ctx, cmu_type, CMU_REG37, 0xF00F); +} + +static void xgene_phy_ssc_enable(struct xgene_phy_ctx *ctx, + enum cmu_type_t cmu_type) +{ + u32 val; + + /* Set SSC modulation value */ + cmu_rd(ctx, cmu_type, CMU_REG35, &val); + val = CMU_REG35_PLL_SSC_MOD_SET(val, 98); + cmu_wr(ctx, cmu_type, CMU_REG35, val); + + /* Enable SSC, set vertical step and DSM value */ + cmu_rd(ctx, cmu_type, CMU_REG36, &val); + val = CMU_REG36_PLL_SSC_VSTEP_SET(val, 30); + val = CMU_REG36_PLL_SSC_EN_SET(val, 1); + val = CMU_REG36_PLL_SSC_DSMSEL_SET(val, 1); + cmu_wr(ctx, cmu_type, CMU_REG36, val); + + /* Reset the PLL */ + cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK); + cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK); + + /* Force VCO calibration to restart */ + cmu_toggle1to0(ctx, cmu_type, CMU_REG32, + CMU_REG32_FORCE_VCOCAL_START_MASK); +} + +static void xgene_phy_sata_cfg_lanes(struct xgene_phy_ctx *ctx) +{ + u32 val; + u32 reg; + int i; + int lane; + + for (lane = 0; lane < MAX_LANE; lane++) { + serdes_wr(ctx, lane, RXTX_REG147, 0x6); + + /* Set boost control for quarter, half, and full rate */ + serdes_rd(ctx, lane, RXTX_REG0, &val); + val = RXTX_REG0_CTLE_EQ_HR_SET(val, 0x10); + val = RXTX_REG0_CTLE_EQ_QR_SET(val, 0x10); + val = RXTX_REG0_CTLE_EQ_FR_SET(val, 0x10); + serdes_wr(ctx, lane, RXTX_REG0, val); + + /* Set boost control value */ + serdes_rd(ctx, lane, RXTX_REG1, &val); + val = RXTX_REG1_RXACVCM_SET(val, 0x7); + val = RXTX_REG1_CTLE_EQ_SET(val, + ctx->sata_param.txboostgain[lane * 3 + + ctx->sata_param.speed[lane]]); + serdes_wr(ctx, lane, RXTX_REG1, val); + + /* Latch VTT value based on the termination to ground and + enable TX FIFO */ + serdes_rd(ctx, lane, RXTX_REG2, &val); + val = RXTX_REG2_VTT_ENA_SET(val, 0x1); + val = RXTX_REG2_VTT_SEL_SET(val, 0x1); + val = RXTX_REG2_TX_FIFO_ENA_SET(val, 0x1); + serdes_wr(ctx, lane, RXTX_REG2, val); + + /* Configure Tx for 20-bits */ + serdes_rd(ctx, lane, RXTX_REG4, &val); + val = RXTX_REG4_TX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT); + serdes_wr(ctx, lane, RXTX_REG4, val); + + if (!preA3Chip) { + serdes_rd(ctx, lane, RXTX_REG1, &val); + val = RXTX_REG1_RXVREG1_SET(val, 0x2); + val = RXTX_REG1_RXIREF_ADJ_SET(val, 0x2); + serdes_wr(ctx, lane, RXTX_REG1, val); + } + + /* Set pre-emphasis first 1 and 2, and post-emphasis values */ + serdes_rd(ctx, lane, RXTX_REG5, &val); + val = RXTX_REG5_TX_CN1_SET(val, + ctx->sata_param.txprecursor_cn1[lane * 3 + + ctx->sata_param.speed[lane]]); + val = RXTX_REG5_TX_CP1_SET(val, + ctx->sata_param.txpostcursor_cp1[lane * 3 + + ctx->sata_param.speed[lane]]); + val = RXTX_REG5_TX_CN2_SET(val, + ctx->sata_param.txprecursor_cn2[lane * 3 + + ctx->sata_param.speed[lane]]); + serdes_wr(ctx, lane, RXTX_REG5, val); + + /* Set TX amplitude value */ + serdes_rd(ctx, lane, RXTX_REG6, &val); + val = RXTX_REG6_TXAMP_CNTL_SET(val, + ctx->sata_param.txamplitude[lane * 3 + + ctx->sata_param.speed[lane]]); + val = RXTX_REG6_TXAMP_ENA_SET(val, 0x1); + val = RXTX_REG6_TX_IDLE_SET(val, 0x0); + val = RXTX_REG6_RX_BIST_RESYNC_SET(val, 0x0); + val = RXTX_REG6_RX_BIST_ERRCNT_RD_SET(val, 0x0); + serdes_wr(ctx, lane, RXTX_REG6, val); + + /* Configure Rx for 20-bits */ + serdes_rd(ctx, lane, RXTX_REG7, &val); + val = RXTX_REG7_BIST_ENA_RX_SET(val, 0x0); + val = RXTX_REG7_RX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT); + serdes_wr(ctx, lane, RXTX_REG7, val); + + /* Set CDR and LOS values and enable Rx SSC */ + serdes_rd(ctx, lane, RXTX_REG8, &val); + val = RXTX_REG8_CDR_LOOP_ENA_SET(val, 0x1); + val = RXTX_REG8_CDR_BYPASS_RXLOS_SET(val, 0x0); + val = RXTX_REG8_SSC_ENABLE_SET(val, 0x1); + val = RXTX_REG8_SD_DISABLE_SET(val, 0x0); + val = RXTX_REG8_SD_VREF_SET(val, 0x4); + serdes_wr(ctx, lane, RXTX_REG8, val); + + /* Set phase adjust upper/lower limits */ + serdes_rd(ctx, lane, RXTX_REG11, &val); + val = RXTX_REG11_PHASE_ADJUST_LIMIT_SET(val, 0x0); + serdes_wr(ctx, lane, RXTX_REG11, val); + + /* Enable Latch Off; disable SUMOS and Tx termination */ + serdes_rd(ctx, lane, RXTX_REG12, &val); + val = RXTX_REG12_LATCH_OFF_ENA_SET(val, 0x1); + val = RXTX_REG12_SUMOS_ENABLE_SET(val, 0x0); + val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0x0); + serdes_wr(ctx, lane, RXTX_REG12, val); + + /* Set period error latch to 512T and enable BWL */ + serdes_rd(ctx, lane, RXTX_REG26, &val); + val = RXTX_REG26_PERIOD_ERROR_LATCH_SET(val, 0x0); + val = RXTX_REG26_BLWC_ENA_SET(val, 0x1); + serdes_wr(ctx, lane, RXTX_REG26, val); + + serdes_wr(ctx, lane, RXTX_REG28, 0x0); + + /* Set DFE loop preset value */ + serdes_wr(ctx, lane, RXTX_REG31, 0x0); + + /* Set Eye Monitor counter width to 12-bit */ + serdes_rd(ctx, lane, RXTX_REG61, &val); + val = RXTX_REG61_ISCAN_INBERT_SET(val, 0x1); + val = RXTX_REG61_LOADFREQ_SHIFT_SET(val, 0x0); + val = RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(val, 0x0); + serdes_wr(ctx, lane, RXTX_REG61, val); + + serdes_rd(ctx, lane, RXTX_REG62, &val); + val = RXTX_REG62_PERIOD_H1_QLATCH_SET(val, 0x0); + serdes_wr(ctx, lane, RXTX_REG62, val); + + /* Set BW select tap X for DFE loop */ + for (i = 0; i < 9; i++) { + reg = RXTX_REG81 + i * 2; + serdes_rd(ctx, lane, reg, &val); + val = RXTX_REG89_MU_TH7_SET(val, 0xe); + val = RXTX_REG89_MU_TH8_SET(val, 0xe); + val = RXTX_REG89_MU_TH9_SET(val, 0xe); + serdes_wr(ctx, lane, reg, val); + } + + /* Set BW select tap X for frequency adjust loop */ + for (i = 0; i < 3; i++) { + reg = RXTX_REG96 + i * 2; + serdes_rd(ctx, lane, reg, &val); + val = RXTX_REG96_MU_FREQ1_SET(val, 0x10); + val = RXTX_REG96_MU_FREQ2_SET(val, 0x10); + val = RXTX_REG96_MU_FREQ3_SET(val, 0x10); + serdes_wr(ctx, lane, reg, val); + } + + /* Set BW select tap X for phase adjust loop */ + for (i = 0; i < 3; i++) { + reg = RXTX_REG99 + i * 2; + serdes_rd(ctx, lane, reg, &val); + val = RXTX_REG99_MU_PHASE1_SET(val, 0x7); + val = RXTX_REG99_MU_PHASE2_SET(val, 0x7); + val = RXTX_REG99_MU_PHASE3_SET(val, 0x7); + serdes_wr(ctx, lane, reg, val); + } + + serdes_rd(ctx, lane, RXTX_REG102, &val); + val = RXTX_REG102_FREQLOOP_LIMIT_SET(val, 0x0); + serdes_wr(ctx, lane, RXTX_REG102, val); + + serdes_wr(ctx, lane, RXTX_REG114, 0xffe0); + + serdes_rd(ctx, lane, RXTX_REG125, &val); + val = RXTX_REG125_SIGN_PQ_SET(val, + ctx->sata_param.txeyedirection[lane * 3 + + ctx->sata_param.speed[lane]]); + val = RXTX_REG125_PQ_REG_SET(val, + ctx->sata_param.txeyetuning[lane * 3 + + ctx->sata_param.speed[lane]]); + val = RXTX_REG125_PHZ_MANUAL_SET(val, 0x1); + serdes_wr(ctx, lane, RXTX_REG125, val); + + serdes_rd(ctx, lane, RXTX_REG127, &val); + val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x0); + serdes_wr(ctx, lane, RXTX_REG127, val); + + serdes_rd(ctx, lane, RXTX_REG128, &val); + val = RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(val, 0x3); + serdes_wr(ctx, lane, RXTX_REG128, val); + + serdes_rd(ctx, lane, RXTX_REG145, &val); + val = RXTX_REG145_RXDFE_CONFIG_SET(val, 0x3); + val = RXTX_REG145_TX_IDLE_SATA_SET(val, 0x0); + if (preA3Chip) { + val = RXTX_REG145_RXES_ENA_SET(val, 0x1); + val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x1); + } else { + val = RXTX_REG145_RXES_ENA_SET(val, 0x0); + val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x0); + } + serdes_wr(ctx, lane, RXTX_REG145, val); + + /* + * Set Rx LOS filter clock rate, sample rate, and threshold + * windows + */ + for (i = 0; i < 4; i++) { + reg = RXTX_REG148 + i * 2; + serdes_wr(ctx, lane, reg, 0xFFFF); + } + } +} + +static int xgene_phy_cal_rdy_chk(struct xgene_phy_ctx *ctx, + enum cmu_type_t cmu_type, + enum clk_type_t clk_type) +{ + void __iomem *csr_serdes = ctx->sds_base; + int loop; + u32 val; + + /* Release PHY main reset */ + writel(0xdf, csr_serdes + SATA_ENET_SDS_RST_CTL); + readl(csr_serdes + SATA_ENET_SDS_RST_CTL); /* Force a barrier */ + + if (cmu_type != REF_CMU) { + cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK); + /* + * As per PHY design spec, the PLL reset requires a minimum + * of 800us. + */ + usleep_range(800, 1000); + + cmu_rd(ctx, cmu_type, CMU_REG1, &val); + val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG1, val); + /* + * As per PHY design spec, the PLL auto calibration requires + * a minimum of 800us. + */ + usleep_range(800, 1000); + + cmu_toggle1to0(ctx, cmu_type, CMU_REG32, + CMU_REG32_FORCE_VCOCAL_START_MASK); + /* + * As per PHY design spec, the PLL requires a minimum of + * 800us to settle. + */ + usleep_range(800, 1000); + } + + if (!preA3Chip) + goto skip_manual_cal; + + /* + * Configure the termination resister calibration + * The serial receive pins, RXP/RXN, have TERMination resistor + * that is required to be calibrated. + */ + cmu_rd(ctx, cmu_type, CMU_REG17, &val); + val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x12); + val = CMU_REG17_RESERVED_7_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG17, val); + cmu_toggle1to0(ctx, cmu_type, CMU_REG17, + CMU_REG17_PVT_TERM_MAN_ENA_MASK); + /* + * The serial transmit pins, TXP/TXN, have Pull-UP and Pull-DOWN + * resistors that are required to the calibrated. + * Configure the pull DOWN calibration + */ + cmu_rd(ctx, cmu_type, CMU_REG17, &val); + val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x29); + val = CMU_REG17_RESERVED_7_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG17, val); + cmu_toggle1to0(ctx, cmu_type, CMU_REG16, + CMU_REG16_PVT_DN_MAN_ENA_MASK); + /* Configure the pull UP calibration */ + cmu_rd(ctx, cmu_type, CMU_REG17, &val); + val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x28); + val = CMU_REG17_RESERVED_7_SET(val, 0x0); + cmu_wr(ctx, cmu_type, CMU_REG17, val); + cmu_toggle1to0(ctx, cmu_type, CMU_REG16, + CMU_REG16_PVT_UP_MAN_ENA_MASK); + +skip_manual_cal: + /* Poll the PLL calibration completion status for at least 1 ms */ + loop = 100; + do { + cmu_rd(ctx, cmu_type, CMU_REG7, &val); + if (CMU_REG7_PLL_CALIB_DONE_RD(val)) + break; + /* + * As per PHY design spec, PLL calibration status requires + * a minimum of 10us to be updated. + */ + usleep_range(10, 100); + } while (--loop > 0); + + cmu_rd(ctx, cmu_type, CMU_REG7, &val); + dev_dbg(ctx->dev, "PLL calibration %s\n", + CMU_REG7_PLL_CALIB_DONE_RD(val) ? "done" : "failed"); + if (CMU_REG7_VCO_CAL_FAIL_RD(val)) { + dev_err(ctx->dev, + "PLL calibration failed due to VCO failure\n"); + return -1; + } + dev_dbg(ctx->dev, "PLL calibration successful\n"); + + cmu_rd(ctx, cmu_type, CMU_REG15, &val); + dev_dbg(ctx->dev, "PHY Tx is %sready\n", val & 0x300 ? "" : "not "); + return 0; +} + +static void xgene_phy_pdwn_force_vco(struct xgene_phy_ctx *ctx, + enum cmu_type_t cmu_type, + enum clk_type_t clk_type) +{ + u32 val; + + dev_dbg(ctx->dev, "Reset VCO and re-start again\n"); + if (cmu_type == PHY_CMU) { + cmu_rd(ctx, cmu_type, CMU_REG16, &val); + val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7); + cmu_wr(ctx, cmu_type, CMU_REG16, val); + } + + cmu_toggle1to0(ctx, cmu_type, CMU_REG0, CMU_REG0_PDOWN_MASK); + cmu_toggle1to0(ctx, cmu_type, CMU_REG32, + CMU_REG32_FORCE_VCOCAL_START_MASK); +} + +static int xgene_phy_hw_init_sata(struct xgene_phy_ctx *ctx, + enum clk_type_t clk_type, int ssc_enable) +{ + void __iomem *sds_base = ctx->sds_base; + u32 val; + int i; + + /* Configure the PHY for operation */ + dev_dbg(ctx->dev, "Reset PHY\n"); + /* Place PHY into reset */ + writel(0x0, sds_base + SATA_ENET_SDS_RST_CTL); + val = readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */ + /* Release PHY lane from reset (active high) */ + writel(0x20, sds_base + SATA_ENET_SDS_RST_CTL); + readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */ + /* Release all PHY module out of reset except PHY main reset */ + writel(0xde, sds_base + SATA_ENET_SDS_RST_CTL); + readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */ + + /* Set the operation speed */ + val = readl(sds_base + SATA_ENET_SDS_CTL1); + val = CFG_I_SPD_SEL_CDR_OVR1_SET(val, + ctx->sata_param.txspeed[ctx->sata_param.speed[0]]); + writel(val, sds_base + SATA_ENET_SDS_CTL1); + + dev_dbg(ctx->dev, "Set the customer pin mode to SATA\n"); + val = readl(sds_base + SATA_ENET_SDS_CTL0); + val = REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(val, 0x4421); + writel(val, sds_base + SATA_ENET_SDS_CTL0); + + /* Configure the clock macro unit (CMU) clock type */ + xgene_phy_cfg_cmu_clk_type(ctx, PHY_CMU, clk_type); + + /* Configure the clock macro */ + xgene_phy_sata_cfg_cmu_core(ctx, PHY_CMU, clk_type); + + /* Enable SSC if enabled */ + if (ssc_enable) + xgene_phy_ssc_enable(ctx, PHY_CMU); + + /* Configure PHY lanes */ + xgene_phy_sata_cfg_lanes(ctx); + + /* Set Rx/Tx 20-bit */ + val = readl(sds_base + SATA_ENET_SDS_PCS_CTL0); + val = REGSPEC_CFG_I_RX_WORDMODE0_SET(val, 0x3); + val = REGSPEC_CFG_I_TX_WORDMODE0_SET(val, 0x3); + writel(val, sds_base + SATA_ENET_SDS_PCS_CTL0); + + /* Start PLL calibration and try for three times */ + i = 10; + do { + if (!xgene_phy_cal_rdy_chk(ctx, PHY_CMU, clk_type)) + break; + /* If failed, toggle the VCO power signal and start again */ + xgene_phy_pdwn_force_vco(ctx, PHY_CMU, clk_type); + } while (--i > 0); + /* Even on failure, allow to continue any way */ + if (i <= 0) + dev_err(ctx->dev, "PLL calibration failed\n"); + + return 0; +} + +static int xgene_phy_hw_initialize(struct xgene_phy_ctx *ctx, + enum clk_type_t clk_type, + int ssc_enable) +{ + int rc; + + dev_dbg(ctx->dev, "PHY init clk type %d\n", clk_type); + + if (ctx->mode == MODE_SATA) { + rc = xgene_phy_hw_init_sata(ctx, clk_type, ssc_enable); + if (rc) + return rc; + } else { + dev_err(ctx->dev, "Un-supported customer pin mode %d\n", + ctx->mode); + return -ENODEV; + } + + return 0; +} + +/* + * Receiver Offset Calibration: + * + * Calibrate the receiver signal path offset in two steps - summar and + * latch calibrations + */ +static void xgene_phy_force_lat_summer_cal(struct xgene_phy_ctx *ctx, int lane) +{ + int i; + struct { + u32 reg; + u32 val; + } serdes_reg[] = { + {RXTX_REG38, 0x0}, + {RXTX_REG39, 0xff00}, + {RXTX_REG40, 0xffff}, + {RXTX_REG41, 0xffff}, + {RXTX_REG42, 0xffff}, + {RXTX_REG43, 0xffff}, + {RXTX_REG44, 0xffff}, + {RXTX_REG45, 0xffff}, + {RXTX_REG46, 0xffff}, + {RXTX_REG47, 0xfffc}, + {RXTX_REG48, 0x0}, + {RXTX_REG49, 0x0}, + {RXTX_REG50, 0x0}, + {RXTX_REG51, 0x0}, + {RXTX_REG52, 0x0}, + {RXTX_REG53, 0x0}, + {RXTX_REG54, 0x0}, + {RXTX_REG55, 0x0}, + }; + + /* Start SUMMER calibration */ + serdes_setbits(ctx, lane, RXTX_REG127, + RXTX_REG127_FORCE_SUM_CAL_START_MASK); + /* + * As per PHY design spec, the Summer calibration requires a minimum + * of 100us to complete. + */ + usleep_range(100, 500); + serdes_clrbits(ctx, lane, RXTX_REG127, + RXTX_REG127_FORCE_SUM_CAL_START_MASK); + /* + * As per PHY design spec, the auto calibration requires a minimum + * of 100us to complete. + */ + usleep_range(100, 500); + + /* Start latch calibration */ + serdes_setbits(ctx, lane, RXTX_REG127, + RXTX_REG127_FORCE_LAT_CAL_START_MASK); + /* + * As per PHY design spec, the latch calibration requires a minimum + * of 100us to complete. + */ + usleep_range(100, 500); + serdes_clrbits(ctx, lane, RXTX_REG127, + RXTX_REG127_FORCE_LAT_CAL_START_MASK); + + /* Configure the PHY lane for calibration */ + serdes_wr(ctx, lane, RXTX_REG28, 0x7); + serdes_wr(ctx, lane, RXTX_REG31, 0x7e00); + serdes_clrbits(ctx, lane, RXTX_REG4, + RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK); + serdes_clrbits(ctx, lane, RXTX_REG7, + RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK); + for (i = 0; i < ARRAY_SIZE(serdes_reg); i++) + serdes_wr(ctx, lane, serdes_reg[i].reg, + serdes_reg[i].val); +} + +static void xgene_phy_reset_rxd(struct xgene_phy_ctx *ctx, int lane) +{ + /* Reset digital Rx */ + serdes_clrbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK); + /* As per PHY design spec, the reset requires a minimum of 100us. */ + usleep_range(100, 150); + serdes_setbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK); +} + +static int xgene_phy_get_avg(int accum, int samples) +{ + return (accum + (samples / 2)) / samples; +} + +static void xgene_phy_gen_avg_val(struct xgene_phy_ctx *ctx, int lane) +{ + int max_loop = 10; + int avg_loop = 0; + int lat_do = 0, lat_xo = 0, lat_eo = 0, lat_so = 0; + int lat_de = 0, lat_xe = 0, lat_ee = 0, lat_se = 0; + int sum_cal = 0; + int lat_do_itr, lat_xo_itr, lat_eo_itr, lat_so_itr; + int lat_de_itr, lat_xe_itr, lat_ee_itr, lat_se_itr; + int sum_cal_itr; + int fail_even; + int fail_odd; + u32 val; + + dev_dbg(ctx->dev, "Generating avg calibration value for lane %d\n", + lane); + + /* Enable RX Hi-Z termination */ + serdes_setbits(ctx, lane, RXTX_REG12, + RXTX_REG12_RX_DET_TERM_ENABLE_MASK); + /* Turn off DFE */ + serdes_wr(ctx, lane, RXTX_REG28, 0x0000); + /* DFE Presets to zero */ + serdes_wr(ctx, lane, RXTX_REG31, 0x0000); + + /* + * Receiver Offset Calibration: + * Calibrate the receiver signal path offset in two steps - summar + * and latch calibration. + * Runs the "Receiver Offset Calibration multiple times to determine + * the average value to use. + */ + while (avg_loop < max_loop) { + /* Start the calibration */ + xgene_phy_force_lat_summer_cal(ctx, lane); + + serdes_rd(ctx, lane, RXTX_REG21, &val); + lat_do_itr = RXTX_REG21_DO_LATCH_CALOUT_RD(val); + lat_xo_itr = RXTX_REG21_XO_LATCH_CALOUT_RD(val); + fail_odd = RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(val); + + serdes_rd(ctx, lane, RXTX_REG22, &val); + lat_eo_itr = RXTX_REG22_EO_LATCH_CALOUT_RD(val); + lat_so_itr = RXTX_REG22_SO_LATCH_CALOUT_RD(val); + fail_even = RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(val); + + serdes_rd(ctx, lane, RXTX_REG23, &val); + lat_de_itr = RXTX_REG23_DE_LATCH_CALOUT_RD(val); + lat_xe_itr = RXTX_REG23_XE_LATCH_CALOUT_RD(val); + + serdes_rd(ctx, lane, RXTX_REG24, &val); + lat_ee_itr = RXTX_REG24_EE_LATCH_CALOUT_RD(val); + lat_se_itr = RXTX_REG24_SE_LATCH_CALOUT_RD(val); + + serdes_rd(ctx, lane, RXTX_REG121, &val); + sum_cal_itr = RXTX_REG121_SUMOS_CAL_CODE_RD(val); + + /* Check for failure. If passed, sum them for averaging */ + if ((fail_even == 0 || fail_even == 1) && + (fail_odd == 0 || fail_odd == 1)) { + lat_do += lat_do_itr; + lat_xo += lat_xo_itr; + lat_eo += lat_eo_itr; + lat_so += lat_so_itr; + lat_de += lat_de_itr; + lat_xe += lat_xe_itr; + lat_ee += lat_ee_itr; + lat_se += lat_se_itr; + sum_cal += sum_cal_itr; + + dev_dbg(ctx->dev, "Iteration %d:\n", avg_loop); + dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n", + lat_do_itr, lat_xo_itr, lat_eo_itr, + lat_so_itr); + dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n", + lat_de_itr, lat_xe_itr, lat_ee_itr, + lat_se_itr); + dev_dbg(ctx->dev, "SUM 0x%x\n", sum_cal_itr); + ++avg_loop; + } else { + dev_err(ctx->dev, + "Receiver calibration failed at %d loop\n", + avg_loop); + } + xgene_phy_reset_rxd(ctx, lane); + } + + /* Update latch manual calibration with average value */ + serdes_rd(ctx, lane, RXTX_REG127, &val); + val = RXTX_REG127_DO_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_do, max_loop)); + val = RXTX_REG127_XO_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_xo, max_loop)); + serdes_wr(ctx, lane, RXTX_REG127, val); + + serdes_rd(ctx, lane, RXTX_REG128, &val); + val = RXTX_REG128_EO_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_eo, max_loop)); + val = RXTX_REG128_SO_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_so, max_loop)); + serdes_wr(ctx, lane, RXTX_REG128, val); + + serdes_rd(ctx, lane, RXTX_REG129, &val); + val = RXTX_REG129_DE_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_de, max_loop)); + val = RXTX_REG129_XE_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_xe, max_loop)); + serdes_wr(ctx, lane, RXTX_REG129, val); + + serdes_rd(ctx, lane, RXTX_REG130, &val); + val = RXTX_REG130_EE_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_ee, max_loop)); + val = RXTX_REG130_SE_LATCH_MANCAL_SET(val, + xgene_phy_get_avg(lat_se, max_loop)); + serdes_wr(ctx, lane, RXTX_REG130, val); + + /* Update SUMMER calibration with average value */ + serdes_rd(ctx, lane, RXTX_REG14, &val); + val = RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(val, + xgene_phy_get_avg(sum_cal, max_loop)); + serdes_wr(ctx, lane, RXTX_REG14, val); + + dev_dbg(ctx->dev, "Average Value:\n"); + dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n", + xgene_phy_get_avg(lat_do, max_loop), + xgene_phy_get_avg(lat_xo, max_loop), + xgene_phy_get_avg(lat_eo, max_loop), + xgene_phy_get_avg(lat_so, max_loop)); + dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n", + xgene_phy_get_avg(lat_de, max_loop), + xgene_phy_get_avg(lat_xe, max_loop), + xgene_phy_get_avg(lat_ee, max_loop), + xgene_phy_get_avg(lat_se, max_loop)); + dev_dbg(ctx->dev, "SUM 0x%x\n", + xgene_phy_get_avg(sum_cal, max_loop)); + + serdes_rd(ctx, lane, RXTX_REG14, &val); + val = RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(val, 0x1); + serdes_wr(ctx, lane, RXTX_REG14, val); + dev_dbg(ctx->dev, "Enable Manual Summer calibration\n"); + + serdes_rd(ctx, lane, RXTX_REG127, &val); + val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x1); + dev_dbg(ctx->dev, "Enable Manual Latch calibration\n"); + serdes_wr(ctx, lane, RXTX_REG127, val); + + /* Disable RX Hi-Z termination */ + serdes_rd(ctx, lane, RXTX_REG12, &val); + val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0); + serdes_wr(ctx, lane, RXTX_REG12, val); + /* Turn on DFE */ + serdes_wr(ctx, lane, RXTX_REG28, 0x0007); + /* Set DFE preset */ + serdes_wr(ctx, lane, RXTX_REG31, 0x7e00); +} + +static int xgene_phy_hw_init(struct phy *phy) +{ + struct xgene_phy_ctx *ctx = phy_get_drvdata(phy); + int rc; + int i; + + rc = xgene_phy_hw_initialize(ctx, CLK_EXT_DIFF, SSC_DISABLE); + if (rc) { + dev_err(ctx->dev, "PHY initialize failed %d\n", rc); + return rc; + } + + /* Setup clock properly after PHY configuration */ + if (!IS_ERR(ctx->clk)) { + /* HW requires an toggle of the clock */ + clk_prepare_enable(ctx->clk); + clk_disable_unprepare(ctx->clk); + clk_prepare_enable(ctx->clk); + } + + /* Compute average value */ + for (i = 0; i < MAX_LANE; i++) + xgene_phy_gen_avg_val(ctx, i); + + dev_dbg(ctx->dev, "PHY initialized\n"); + return 0; +} + +static const struct phy_ops xgene_phy_ops = { + .init = xgene_phy_hw_init, + .owner = THIS_MODULE, +}; + +static struct phy *xgene_phy_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct xgene_phy_ctx *ctx = dev_get_drvdata(dev); + + if (args->args_count <= 0) + return ERR_PTR(-EINVAL); + if (args->args[0] < MODE_SATA || args->args[0] >= MODE_MAX) + return ERR_PTR(-EINVAL); + + ctx->mode = args->args[0]; + return ctx->phy; +} + +static void xgene_phy_get_param(struct platform_device *pdev, + const char *name, u32 *buffer, + int count, u32 *default_val, + u32 conv_factor) +{ + int i; + + if (!of_property_read_u32_array(pdev->dev.of_node, name, buffer, + count)) { + for (i = 0; i < count; i++) + buffer[i] /= conv_factor; + return; + } + /* Does not exist, load default */ + for (i = 0; i < count; i++) + buffer[i] = default_val[i % 3]; +} + +static int xgene_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct xgene_phy_ctx *ctx; + struct resource *res; + int rc = 0; + u32 default_spd[] = DEFAULT_SATA_SPD_SEL; + u32 default_txboost_gain[] = DEFAULT_SATA_TXBOOST_GAIN; + u32 default_txeye_direction[] = DEFAULT_SATA_TXEYEDIRECTION; + u32 default_txeye_tuning[] = DEFAULT_SATA_TXEYETUNING; + u32 default_txamp[] = DEFAULT_SATA_TXAMP; + u32 default_txcn1[] = DEFAULT_SATA_TXCN1; + u32 default_txcn2[] = DEFAULT_SATA_TXCN2; + u32 default_txcp1[] = DEFAULT_SATA_TXCP1; + int i; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ctx->sds_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ctx->sds_base)) { + rc = PTR_ERR(ctx->sds_base); + goto error; + } + + /* Retrieve optional clock */ + ctx->clk = clk_get(&pdev->dev, NULL); + + /* Load override paramaters */ + xgene_phy_get_param(pdev, "apm,tx-eye-tuning", + ctx->sata_param.txeyetuning, 6, default_txeye_tuning, 1); + xgene_phy_get_param(pdev, "apm,tx-eye-direction", + ctx->sata_param.txeyedirection, 6, default_txeye_direction, 1); + xgene_phy_get_param(pdev, "apm,tx-boost-gain", + ctx->sata_param.txboostgain, 6, default_txboost_gain, 1); + xgene_phy_get_param(pdev, "apm,tx-amplitude", + ctx->sata_param.txamplitude, 6, default_txamp, 13300); + xgene_phy_get_param(pdev, "apm,tx-pre-cursor1", + ctx->sata_param.txprecursor_cn1, 6, default_txcn1, 18200); + xgene_phy_get_param(pdev, "apm,tx-pre-cursor2", + ctx->sata_param.txprecursor_cn2, 6, default_txcn2, 18200); + xgene_phy_get_param(pdev, "apm,tx-post-cursor", + ctx->sata_param.txpostcursor_cp1, 6, default_txcp1, 18200); + xgene_phy_get_param(pdev, "apm,tx-speed", + ctx->sata_param.txspeed, 3, default_spd, 1); + for (i = 0; i < MAX_LANE; i++) + ctx->sata_param.speed[i] = 2; /* Default to Gen3 */ + + ctx->dev = &pdev->dev; + platform_set_drvdata(pdev, ctx); + + ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops, NULL); + if (IS_ERR(ctx->phy)) { + dev_dbg(&pdev->dev, "Failed to create PHY\n"); + rc = PTR_ERR(ctx->phy); + goto error; + } + phy_set_drvdata(ctx->phy, ctx); + + phy_provider = devm_of_phy_provider_register(ctx->dev, + xgene_phy_xlate); + if (IS_ERR(phy_provider)) { + rc = PTR_ERR(phy_provider); + goto error; + } + + return 0; + +error: + return rc; +} + +static const struct of_device_id xgene_phy_of_match[] = { + {.compatible = "apm,xgene-phy",}, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_phy_of_match); + +static struct platform_driver xgene_phy_driver = { + .probe = xgene_phy_probe, + .driver = { + .name = "xgene-phy", + .owner = THIS_MODULE, + .of_match_table = xgene_phy_of_match, + }, +}; +module_platform_driver(xgene_phy_driver); + +MODULE_DESCRIPTION("APM X-Gene Multi-Purpose PHY driver"); +MODULE_AUTHOR("Loc Ho "); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); --- linux-3.13.0.orig/drivers/phy/Makefile +++ linux-3.13.0/drivers/phy/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o +obj-$(CONFIG_PHY_XGENE) += phy-xgene.o --- linux-3.13.0.orig/drivers/phy/Kconfig +++ linux-3.13.0/drivers/phy/Kconfig @@ -51,4 +51,11 @@ help Support for Display Port PHY found on Samsung EXYNOS SoCs. +config PHY_XGENE + tristate "APM X-Gene 15Gbps PHY support" + depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) + select GENERIC_PHY + help + This option enables support for APM X-Gene SoC multi-purpose PHY. + endmenu --- linux-3.13.0.orig/drivers/vme/bridges/vme_ca91cx42.c +++ linux-3.13.0/drivers/vme/bridges/vme_ca91cx42.c @@ -884,7 +884,7 @@ if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { *(u8 *)(buf + done) = ioread8(addr + done); done += 1; @@ -938,7 +938,7 @@ if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { iowrite8(*(u8 *)(buf + done), addr + done); done += 1; --- linux-3.13.0.orig/drivers/vme/bridges/vme_tsi148.c +++ linux-3.13.0/drivers/vme/bridges/vme_tsi148.c @@ -1289,7 +1289,7 @@ if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { *(u8 *)(buf + done) = ioread8(addr + done); done += 1; @@ -1371,7 +1371,7 @@ if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { iowrite8(*(u8 *)(buf + done), addr + done); done += 1; --- linux-3.13.0.orig/drivers/edac/i7300_edac.c +++ linux-3.13.0/drivers/edac/i7300_edac.c @@ -943,33 +943,35 @@ /* Attempt to 'get' the MCH register we want */ pdev = NULL; - while (!pvt->pci_dev_16_1_fsb_addr_map || - !pvt->pci_dev_16_2_fsb_err_regs) { - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev); - if (!pdev) { - /* End of list, leave */ - i7300_printk(KERN_ERR, - "'system address,Process Bus' " - "device not found:" - "vendor 0x%x device 0x%x ERR funcs " - "(broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); - goto error; - } - + while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, + pdev))) { /* Store device 16 funcs 1 and 2 */ switch (PCI_FUNC(pdev->devfn)) { case 1: - pvt->pci_dev_16_1_fsb_addr_map = pdev; + if (!pvt->pci_dev_16_1_fsb_addr_map) + pvt->pci_dev_16_1_fsb_addr_map = + pci_dev_get(pdev); break; case 2: - pvt->pci_dev_16_2_fsb_err_regs = pdev; + if (!pvt->pci_dev_16_2_fsb_err_regs) + pvt->pci_dev_16_2_fsb_err_regs = + pci_dev_get(pdev); break; } } + if (!pvt->pci_dev_16_1_fsb_addr_map || + !pvt->pci_dev_16_2_fsb_err_regs) { + /* At least one device was not found */ + i7300_printk(KERN_ERR, + "'system address,Process Bus' device not found:" + "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); + goto error; + } + edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s %x:%x\n", pci_name(pvt->pci_dev_16_0_fsb_ctlr), pvt->pci_dev_16_0_fsb_ctlr->vendor, --- linux-3.13.0.orig/drivers/edac/edac_mc_sysfs.c +++ linux-3.13.0/drivers/edac/edac_mc_sysfs.c @@ -52,18 +52,20 @@ static int edac_set_poll_msec(const char *val, struct kernel_param *kp) { - long l; + unsigned long l; int ret; if (!val) return -EINVAL; - ret = kstrtol(val, 0, &l); + ret = kstrtoul(val, 0, &l); if (ret) return ret; - if ((int)l != l) + + if (l < 1000) return -EINVAL; - *((int *)kp->arg) = l; + + *((unsigned long *)kp->arg) = l; /* notify edac_mc engine to reset the poll period */ edac_mc_reset_delay_period(l); --- linux-3.13.0.orig/drivers/edac/edac_mc.c +++ linux-3.13.0/drivers/edac/edac_mc.c @@ -559,7 +559,8 @@ * * called with the mem_ctls_mutex held */ -static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) +static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, + bool init) { edac_dbg(0, "\n"); @@ -567,7 +568,9 @@ if (mci->op_state != OP_RUNNING_POLL) return; - INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); + if (init) + INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); + mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); } @@ -601,7 +604,7 @@ * user space has updated our poll period value, need to * reset our workq delays */ -void edac_mc_reset_delay_period(int value) +void edac_mc_reset_delay_period(unsigned long value) { struct mem_ctl_info *mci; struct list_head *item; @@ -611,7 +614,7 @@ list_for_each(item, &mc_devices) { mci = list_entry(item, struct mem_ctl_info, link); - edac_mc_workq_setup(mci, (unsigned long) value); + edac_mc_workq_setup(mci, value, false); } mutex_unlock(&mem_ctls_mutex); @@ -782,7 +785,7 @@ /* This instance is NOW RUNNING */ mci->op_state = OP_RUNNING_POLL; - edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); + edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true); } else { mci->op_state = OP_RUNNING_INTERRUPT; } --- linux-3.13.0.orig/drivers/edac/edac_module.h +++ linux-3.13.0/drivers/edac/edac_module.h @@ -52,7 +52,7 @@ extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); extern void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, unsigned long value); -extern void edac_mc_reset_delay_period(int value); +extern void edac_mc_reset_delay_period(unsigned long value); extern void *edac_align_ptr(void **p, unsigned size, int n_elems); --- linux-3.13.0.orig/drivers/edac/e752x_edac.c +++ linux-3.13.0/drivers/edac/e752x_edac.c @@ -1182,9 +1182,11 @@ pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, pvt->dev_info->err_dev, pvt->bridge_ck); - if (pvt->bridge_ck == NULL) + if (pvt->bridge_ck == NULL) { pvt->bridge_ck = pci_scan_single_device(pdev->bus, PCI_DEVFN(0, 1)); + pci_dev_get(pvt->bridge_ck); + } if (pvt->bridge_ck == NULL) { e752x_printk(KERN_ERR, "error reporting device not found:" --- linux-3.13.0.orig/drivers/edac/i7core_edac.c +++ linux-3.13.0/drivers/edac/i7core_edac.c @@ -1334,14 +1334,19 @@ * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) { + pci_dev_get(*prev); /* pci_get_device will put it */ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); + } - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && + !pdev) { + pci_dev_get(*prev); /* pci_get_device will put it */ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, *prev); + } if (!pdev) { if (*prev) { --- linux-3.13.0.orig/drivers/cdrom/cdrom.c +++ linux-3.13.0/drivers/cdrom/cdrom.c @@ -289,7 +289,7 @@ /* default compatibility mode */ static bool autoclose=1; static bool autoeject; -static bool lockdoor = 1; +static bool lockdoor = 0; /* will we ever get to use this... sigh. */ static bool check_media_type; /* automatically restart mrw format */ --- linux-3.13.0.orig/drivers/rapidio/devices/tsi721.h +++ linux-3.13.0/drivers/rapidio/devices/tsi721.h @@ -678,6 +678,7 @@ struct list_head free_list; dma_cookie_t completed_cookie; struct tasklet_struct tasklet; + bool active; }; #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ --- linux-3.13.0.orig/drivers/rapidio/devices/tsi721_dma.c +++ linux-3.13.0/drivers/rapidio/devices/tsi721_dma.c @@ -206,8 +206,8 @@ { /* Disable BDMA channel interrupts */ iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE); - - tasklet_schedule(&bdma_chan->tasklet); + if (bdma_chan->active) + tasklet_schedule(&bdma_chan->tasklet); } #ifdef CONFIG_PCI_MSI @@ -562,7 +562,7 @@ } #endif /* CONFIG_PCI_MSI */ - tasklet_enable(&bdma_chan->tasklet); + bdma_chan->active = true; tsi721_bdma_interrupt_enable(bdma_chan, 1); return bdma_chan->bd_num - 1; @@ -576,9 +576,7 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan) { struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); -#ifdef CONFIG_PCI_MSI struct tsi721_device *priv = to_tsi721(dchan->device); -#endif LIST_HEAD(list); dev_dbg(dchan->device->dev, "%s: Entry\n", __func__); @@ -589,14 +587,25 @@ BUG_ON(!list_empty(&bdma_chan->active_list)); BUG_ON(!list_empty(&bdma_chan->queue)); - tasklet_disable(&bdma_chan->tasklet); + tsi721_bdma_interrupt_enable(bdma_chan, 0); + bdma_chan->active = false; + +#ifdef CONFIG_PCI_MSI + if (priv->flags & TSI721_USING_MSIX) { + synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE + + bdma_chan->id].vector); + synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT + + bdma_chan->id].vector); + } else +#endif + synchronize_irq(priv->pdev->irq); + + tasklet_kill(&bdma_chan->tasklet); spin_lock_bh(&bdma_chan->lock); list_splice_init(&bdma_chan->free_list, &list); spin_unlock_bh(&bdma_chan->lock); - tsi721_bdma_interrupt_enable(bdma_chan, 0); - #ifdef CONFIG_PCI_MSI if (priv->flags & TSI721_USING_MSIX) { free_irq(priv->msix[TSI721_VECT_DMA0_DONE + @@ -790,6 +799,7 @@ bdma_chan->dchan.cookie = 1; bdma_chan->dchan.chan_id = i; bdma_chan->id = i; + bdma_chan->active = false; spin_lock_init(&bdma_chan->lock); @@ -799,7 +809,6 @@ tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet, (unsigned long)bdma_chan); - tasklet_disable(&bdma_chan->tasklet); list_add_tail(&bdma_chan->dchan.device_node, &mport->dma.channels); } --- linux-3.13.0.orig/drivers/mfd/max77686.c +++ linux-3.13.0/drivers/mfd/max77686.c @@ -104,7 +104,7 @@ max77686->irq_gpio = pdata->irq_gpio; max77686->irq = i2c->irq; - max77686->regmap = regmap_init_i2c(i2c, &max77686_regmap_config); + max77686->regmap = devm_regmap_init_i2c(i2c, &max77686_regmap_config); if (IS_ERR(max77686->regmap)) { ret = PTR_ERR(max77686->regmap); dev_err(max77686->dev, "Failed to allocate register map: %d\n", --- linux-3.13.0.orig/drivers/mfd/da9055-i2c.c +++ linux-3.13.0/drivers/mfd/da9055-i2c.c @@ -53,17 +53,25 @@ return 0; } +/* + * DO NOT change the device Ids. The naming is intentionally specific as both + * the PMIC and CODEC parts of this chip are instantiated separately as I2C + * devices (both have configurable I2C addresses, and are to all intents and + * purposes separate). As a result there are specific DA9055 ids for PMIC + * and CODEC, which must be different to operate together. + */ static struct i2c_device_id da9055_i2c_id[] = { - {"da9055", 0}, + {"da9055-pmic", 0}, { } }; +MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); static struct i2c_driver da9055_i2c_driver = { .probe = da9055_i2c_probe, .remove = da9055_i2c_remove, .id_table = da9055_i2c_id, .driver = { - .name = "da9055", + .name = "da9055-pmic", .owner = THIS_MODULE, }, }; --- linux-3.13.0.orig/drivers/gpu/drm/drm_crtc.c +++ linux-3.13.0/drivers/gpu/drm/drm_crtc.c @@ -675,6 +675,29 @@ EXPORT_SYMBOL(drm_crtc_cleanup); /** + * drm_crtc_index - find the index of a registered CRTC + * @crtc: CRTC to find index for + * + * Given a registered CRTC, return the index of that CRTC within a DRM + * device's list of CRTCs. + */ +unsigned int drm_crtc_index(struct drm_crtc *crtc) +{ + unsigned int index = 0; + struct drm_crtc *tmp; + + list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { + if (tmp == crtc) + return index; + + index++; + } + + BUG(); +} +EXPORT_SYMBOL(drm_crtc_index); + +/** * drm_mode_probed_add - add a mode to a connector's probed mode list * @connector: connector the new mode * @mode: mode data --- linux-3.13.0.orig/drivers/gpu/drm/drm_irq.c +++ linux-3.13.0/drivers/gpu/drm/drm_irq.c @@ -445,20 +445,22 @@ * adjustments into account. * * @crtc drm_crtc whose timestamp constants should be updated. + * @mode display mode containing the scanout timings * */ -void drm_calc_timestamping_constants(struct drm_crtc *crtc) +void drm_calc_timestamping_constants(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; u64 dotclock; /* Dot clock in Hz: */ - dotclock = (u64) crtc->hwmode.clock * 1000; + dotclock = (u64) mode->clock * 1000; /* Fields of interlaced scanout modes are only half a frame duration. * Double the dotclock to get half the frame-/line-/pixelduration. */ - if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE) + if (mode->flags & DRM_MODE_FLAG_INTERLACE) dotclock *= 2; /* Valid dotclock? */ @@ -469,10 +471,9 @@ * nanoseconds: */ pixeldur_ns = (s64) div64_u64(1000000000, dotclock); - linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * + linedur_ns = (s64) div64_u64(((u64) mode->crtc_htotal * 1000000000), dotclock); - frame_size = crtc->hwmode.crtc_htotal * - crtc->hwmode.crtc_vtotal; + frame_size = mode->crtc_htotal * mode->crtc_vtotal; framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000, dotclock); } else @@ -484,8 +485,8 @@ crtc->framedur_ns = framedur_ns; DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", - crtc->base.id, crtc->hwmode.crtc_htotal, - crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); + crtc->base.id, mode->crtc_htotal, + mode->crtc_vtotal, mode->crtc_vdisplay); DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", crtc->base.id, (int) dotclock/1000, (int) framedur_ns, (int) linedur_ns, (int) pixeldur_ns); @@ -521,6 +522,7 @@ * 0 = Default. * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. * @refcrtc: drm_crtc* of crtc which defines scanout timing. + * @mode: mode which defines the scanout timings * * Returns negative value on error, failure or if not supported in current * video mode: @@ -540,11 +542,11 @@ int *max_error, struct timeval *vblank_time, unsigned flags, - struct drm_crtc *refcrtc) + const struct drm_crtc *refcrtc, + const struct drm_display_mode *mode) { ktime_t stime, etime, mono_time_offset; struct timeval tv_etime; - struct drm_display_mode *mode; int vbl_status, vtotal, vdisplay; int vpos, hpos, i; s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; @@ -561,7 +563,6 @@ return -EIO; } - mode = &refcrtc->hwmode; vtotal = mode->crtc_vtotal; vdisplay = mode->crtc_vdisplay; @@ -590,7 +591,7 @@ * Get vertical and horizontal scanout position vpos, hpos, * and bounding timestamps stime, etime, pre/post query. */ - vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, + vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos, &hpos, &stime, &etime); /* --- linux-3.13.0.orig/drivers/gpu/drm/drm_gem.c +++ linux-3.13.0/drivers/gpu/drm/drm_gem.c @@ -129,11 +129,12 @@ { struct file *filp; + drm_gem_private_object_init(dev, obj, size); + filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); if (IS_ERR(filp)) return PTR_ERR(filp); - drm_gem_private_object_init(dev, obj, size); obj->filp = filp; return 0; --- linux-3.13.0.orig/drivers/gpu/drm/drm_crtc_helper.c +++ linux-3.13.0/drivers/gpu/drm/drm_crtc_helper.c @@ -324,35 +324,6 @@ } EXPORT_SYMBOL(drm_helper_disable_unused_functions); -/** - * drm_encoder_crtc_ok - can a given crtc drive a given encoder? - * @encoder: encoder to test - * @crtc: crtc to test - * - * Return false if @encoder can't be driven by @crtc, true otherwise. - */ -static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, - struct drm_crtc *crtc) -{ - struct drm_device *dev; - struct drm_crtc *tmp; - int crtc_mask = 1; - - WARN(!crtc, "checking null crtc?\n"); - - dev = crtc->dev; - - list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { - if (tmp == crtc) - break; - crtc_mask <<= 1; - } - - if (encoder->possible_crtcs & crtc_mask) - return true; - return false; -} - /* * Check the CRTC we're going to map each output to vs. its current * CRTC. If they don't match, we have to disable the output and the CRTC @@ -536,7 +507,7 @@ * are later needed by vblank and swap-completion * timestamping. They are derived from true hwmode. */ - drm_calc_timestamping_constants(crtc); + drm_calc_timestamping_constants(crtc, &crtc->hwmode); /* FIXME: add subpixel order */ done: --- linux-3.13.0.orig/drivers/gpu/drm/gma500/gma_display.c +++ linux-3.13.0/drivers/gpu/drm/gma500/gma_display.c @@ -349,6 +349,7 @@ /* If we didn't get a handle then turn the cursor off */ if (!handle) { temp = CURSOR_MODE_DISABLE; + mutex_lock(&dev->struct_mutex); if (gma_power_begin(dev, false)) { REG_WRITE(control, temp); @@ -365,6 +366,7 @@ gma_crtc->cursor_obj = NULL; } + mutex_unlock(&dev->struct_mutex); return 0; } @@ -374,9 +376,12 @@ return -EINVAL; } + mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file_priv, handle); - if (!obj) - return -ENOENT; + if (!obj) { + ret = -ENOENT; + goto unlock; + } if (obj->size < width * height * 4) { dev_dbg(dev->dev, "Buffer is too small\n"); @@ -440,10 +445,13 @@ } gma_crtc->cursor_obj = obj; +unlock: + mutex_unlock(&dev->struct_mutex); return ret; unref_cursor: drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return ret; } --- linux-3.13.0.orig/drivers/gpu/drm/ttm/ttm_bo.c +++ linux-3.13.0/drivers/gpu/drm/ttm/ttm_bo.c @@ -351,9 +351,11 @@ moved: if (bo->evicted) { - ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement); - if (ret) - pr_err("Can not flush read caches\n"); + if (bdev->driver->invalidate_caches) { + ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement); + if (ret) + pr_err("Can not flush read caches\n"); + } bo->evicted = false; } --- linux-3.13.0.orig/drivers/gpu/drm/ttm/ttm_object.c +++ linux-3.13.0/drivers/gpu/drm/ttm/ttm_object.c @@ -68,7 +68,7 @@ struct ttm_object_file { struct ttm_object_device *tdev; - rwlock_t lock; + spinlock_t lock; struct list_head ref_list; struct drm_open_hash ref_hash[TTM_REF_NUM]; struct kref refcount; @@ -118,6 +118,7 @@ */ struct ttm_ref_object { + struct rcu_head rcu_head; struct drm_hash_item hash; struct list_head head; struct kref kref; @@ -210,10 +211,9 @@ * call_rcu() or ttm_base_object_kfree(). */ - if (base->refcount_release) { - ttm_object_file_unref(&base->tfile); + ttm_object_file_unref(&base->tfile); + if (base->refcount_release) base->refcount_release(&base); - } } void ttm_base_object_unref(struct ttm_base_object **p_base) @@ -229,32 +229,46 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, uint32_t key) { - struct ttm_object_device *tdev = tfile->tdev; - struct ttm_base_object *uninitialized_var(base); + struct ttm_base_object *base = NULL; struct drm_hash_item *hash; + struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; int ret; rcu_read_lock(); - ret = drm_ht_find_item_rcu(&tdev->object_hash, key, &hash); + ret = drm_ht_find_item_rcu(ht, key, &hash); if (likely(ret == 0)) { - base = drm_hash_entry(hash, struct ttm_base_object, hash); - ret = kref_get_unless_zero(&base->refcount) ? 0 : -EINVAL; + base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; + if (!kref_get_unless_zero(&base->refcount)) + base = NULL; } rcu_read_unlock(); - if (unlikely(ret != 0)) - return NULL; + return base; +} +EXPORT_SYMBOL(ttm_base_object_lookup); - if (tfile != base->tfile && !base->shareable) { - pr_err("Attempted access of non-shareable object\n"); - ttm_base_object_unref(&base); - return NULL; +struct ttm_base_object * +ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) +{ + struct ttm_base_object *base = NULL; + struct drm_hash_item *hash; + struct drm_open_hash *ht = &tdev->object_hash; + int ret; + + rcu_read_lock(); + ret = drm_ht_find_item_rcu(ht, key, &hash); + + if (likely(ret == 0)) { + base = drm_hash_entry(hash, struct ttm_base_object, hash); + if (!kref_get_unless_zero(&base->refcount)) + base = NULL; } + rcu_read_unlock(); return base; } -EXPORT_SYMBOL(ttm_base_object_lookup); +EXPORT_SYMBOL(ttm_base_object_lookup_for_ref); int ttm_ref_object_add(struct ttm_object_file *tfile, struct ttm_base_object *base, @@ -266,21 +280,25 @@ struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; int ret = -EINVAL; + if (base->tfile != tfile && !base->shareable) + return -EPERM; + if (existed != NULL) *existed = true; while (ret == -EINVAL) { - read_lock(&tfile->lock); - ret = drm_ht_find_item(ht, base->hash.key, &hash); + rcu_read_lock(); + ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); if (ret == 0) { ref = drm_hash_entry(hash, struct ttm_ref_object, hash); - kref_get(&ref->kref); - read_unlock(&tfile->lock); - break; + if (kref_get_unless_zero(&ref->kref)) { + rcu_read_unlock(); + break; + } } - read_unlock(&tfile->lock); + rcu_read_unlock(); ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), false, false); if (unlikely(ret != 0)) @@ -297,19 +315,19 @@ ref->ref_type = ref_type; kref_init(&ref->kref); - write_lock(&tfile->lock); - ret = drm_ht_insert_item(ht, &ref->hash); + spin_lock(&tfile->lock); + ret = drm_ht_insert_item_rcu(ht, &ref->hash); if (likely(ret == 0)) { list_add_tail(&ref->head, &tfile->ref_list); kref_get(&base->refcount); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); if (existed != NULL) *existed = false; break; } - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); BUG_ON(ret != -EINVAL); ttm_mem_global_free(mem_glob, sizeof(*ref)); @@ -330,17 +348,17 @@ struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; ht = &tfile->ref_hash[ref->ref_type]; - (void)drm_ht_remove_item(ht, &ref->hash); + (void)drm_ht_remove_item_rcu(ht, &ref->hash); list_del(&ref->head); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) base->ref_obj_release(base, ref->ref_type); ttm_base_object_unref(&ref->obj); ttm_mem_global_free(mem_glob, sizeof(*ref)); - kfree(ref); - write_lock(&tfile->lock); + kfree_rcu(ref, rcu_head); + spin_lock(&tfile->lock); } int ttm_ref_object_base_unref(struct ttm_object_file *tfile, @@ -351,15 +369,15 @@ struct drm_hash_item *hash; int ret; - write_lock(&tfile->lock); + spin_lock(&tfile->lock); ret = drm_ht_find_item(ht, key, &hash); if (unlikely(ret != 0)) { - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); return -EINVAL; } ref = drm_hash_entry(hash, struct ttm_ref_object, hash); kref_put(&ref->kref, ttm_ref_object_release); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); return 0; } EXPORT_SYMBOL(ttm_ref_object_base_unref); @@ -372,7 +390,7 @@ struct ttm_object_file *tfile = *p_tfile; *p_tfile = NULL; - write_lock(&tfile->lock); + spin_lock(&tfile->lock); /* * Since we release the lock within the loop, we have to @@ -388,7 +406,7 @@ for (i = 0; i < TTM_REF_NUM; ++i) drm_ht_remove(&tfile->ref_hash[i]); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); ttm_object_file_unref(&tfile); } EXPORT_SYMBOL(ttm_object_file_release); @@ -404,7 +422,7 @@ if (unlikely(tfile == NULL)) return NULL; - rwlock_init(&tfile->lock); + spin_lock_init(&tfile->lock); tfile->tdev = tdev; kref_init(&tfile->refcount); INIT_LIST_HEAD(&tfile->ref_list); --- linux-3.13.0.orig/drivers/gpu/drm/armada/armada_drv.c +++ linux-3.13.0/drivers/gpu/drm/armada/armada_drv.c @@ -68,15 +68,7 @@ { struct armada_private *priv = dev->dev_private; - /* - * Yes, we really must jump through these hoops just to store a - * _pointer_ to something into the kfifo. This is utterly insane - * and idiotic, because it kfifo requires the _data_ pointed to by - * the pointer const, not the pointer itself. Not only that, but - * you have to pass a pointer _to_ the pointer you want stored. - */ - const struct drm_framebuffer *silly_api_alert = fb; - WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert)); + WARN_ON(!kfifo_put(&priv->fb_unref, fb)); schedule_work(&priv->fb_unref_work); } --- linux-3.13.0.orig/drivers/gpu/drm/ast/ast_fb.c +++ linux-3.13.0/drivers/gpu/drm/ast/ast_fb.c @@ -65,7 +65,7 @@ * then the BO is being moved and we should * store up the damage until later. */ - if (!in_interrupt()) + if (drm_can_sleep()) ret = ast_bo_reserve(bo, true); if (ret) { if (ret != -EBUSY) --- linux-3.13.0.orig/drivers/gpu/drm/mgag200/mgag200_cursor.c +++ linux-3.13.0/drivers/gpu/drm/mgag200/mgag200_cursor.c @@ -22,8 +22,10 @@ { WREG8(MGA_CURPOSXL, 0); WREG8(MGA_CURPOSXH, 0); - mgag200_bo_unpin(mdev->cursor.pixels_1); - mgag200_bo_unpin(mdev->cursor.pixels_2); + if (mdev->cursor.pixels_1->pin_count) + mgag200_bo_unpin(mdev->cursor.pixels_1); + if (mdev->cursor.pixels_2->pin_count) + mgag200_bo_unpin(mdev->cursor.pixels_2); } int mga_crtc_cursor_set(struct drm_crtc *crtc, @@ -32,7 +34,7 @@ uint32_t width, uint32_t height) { - struct drm_device *dev = (struct drm_device *)file_priv->minor->dev; + struct drm_device *dev = crtc->dev; struct mga_device *mdev = (struct mga_device *)dev->dev_private; struct mgag200_bo *pixels_1 = mdev->cursor.pixels_1; struct mgag200_bo *pixels_2 = mdev->cursor.pixels_2; --- linux-3.13.0.orig/drivers/gpu/drm/mgag200/mgag200_fb.c +++ linux-3.13.0/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -41,7 +41,7 @@ * then the BO is being moved and we should * store up the damage until later. */ - if (!in_interrupt()) + if (drm_can_sleep()) ret = mgag200_bo_reserve(bo, true); if (ret) { if (ret != -EBUSY) --- linux-3.13.0.orig/drivers/gpu/drm/mgag200/mgag200_mode.c +++ linux-3.13.0/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1519,11 +1519,11 @@ (mga_vga_calculate_mode_bandwidth(mode, bpp) > (32700 * 1024))) { return MODE_BANDWIDTH; - } else if (mode->type == G200_EH && + } else if (mdev->type == G200_EH && (mga_vga_calculate_mode_bandwidth(mode, bpp) > (37500 * 1024))) { return MODE_BANDWIDTH; - } else if (mode->type == G200_ER && + } else if (mdev->type == G200_ER && (mga_vga_calculate_mode_bandwidth(mode, bpp) > (55000 * 1024))) { return MODE_BANDWIDTH; --- linux-3.13.0.orig/drivers/gpu/drm/cirrus/cirrus_mode.c +++ linux-3.13.0/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -273,8 +273,8 @@ sr07 |= 0x11; break; case 16: - sr07 |= 0xc1; - hdr = 0xc0; + sr07 |= 0x17; + hdr = 0xc1; break; case 24: sr07 |= 0x15; --- linux-3.13.0.orig/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ linux-3.13.0/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -39,7 +39,7 @@ * then the BO is being moved and we should * store up the damage until later. */ - if (!in_interrupt()) + if (drm_can_sleep()) ret = cirrus_bo_reserve(bo, true); if (ret) { if (ret != -EBUSY) --- linux-3.13.0.orig/drivers/gpu/drm/nouveau/nouveau_display.c +++ linux-3.13.0/drivers/gpu/drm/nouveau/nouveau_display.c @@ -603,6 +603,14 @@ if (!s) return -ENOMEM; + if (new_bo != old_bo) { + ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); + if (ret) + goto fail_free; + } + + mutex_lock(&chan->cli->mutex); + /* synchronise rendering channel with the kernel's channel */ spin_lock(&new_bo->bo.bdev->fence_lock); fence = nouveau_fence_ref(new_bo->bo.sync_obj); @@ -610,15 +618,8 @@ ret = nouveau_fence_sync(fence, chan); nouveau_fence_unref(&fence); if (ret) - goto fail_free; - - if (new_bo != old_bo) { - ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); - if (ret) - goto fail_free; - } + goto fail_unpin; - mutex_lock(&chan->cli->mutex); ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); if (ret) goto fail_unpin; --- linux-3.13.0.orig/drivers/gpu/drm/nouveau/nouveau_drm.c +++ linux-3.13.0/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -376,6 +376,8 @@ if (ret) goto fail_device; + dev->irq_enabled = true; + /* workaround an odd issue on nvc1 by disabling the device's * nosnoop capability. hopefully won't cause issues until a * better fix is found - assuming there is one... @@ -475,6 +477,7 @@ struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_object *device; + dev->irq_enabled = false; device = drm->client.base.device; drm_put_dev(dev); --- linux-3.13.0.orig/drivers/gpu/drm/nouveau/nouveau_bo.c +++ linux-3.13.0/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -798,25 +798,25 @@ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) { struct nouveau_mem *node = old_mem->mm_node; - struct nouveau_bo *nvbo = nouveau_bo(bo); u64 length = (new_mem->num_pages << PAGE_SHIFT); u64 src_offset = node->vma[0].offset; u64 dst_offset = node->vma[1].offset; + int src_tiled = !!node->memtype; + int dst_tiled = !!((struct nouveau_mem *)new_mem->mm_node)->memtype; int ret; while (length) { u32 amount, stride, height; + ret = RING_SPACE(chan, 18 + 6 * (src_tiled + dst_tiled)); + if (ret) + return ret; + amount = min(length, (u64)(4 * 1024 * 1024)); stride = 16 * 4; height = amount / stride; - if (old_mem->mem_type == TTM_PL_VRAM && - nouveau_bo_tile_layout(nvbo)) { - ret = RING_SPACE(chan, 8); - if (ret) - return ret; - + if (src_tiled) { BEGIN_NV04(chan, NvSubCopy, 0x0200, 7); OUT_RING (chan, 0); OUT_RING (chan, 0); @@ -826,19 +826,10 @@ OUT_RING (chan, 0); OUT_RING (chan, 0); } else { - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_NV04(chan, NvSubCopy, 0x0200, 1); OUT_RING (chan, 1); } - if (new_mem->mem_type == TTM_PL_VRAM && - nouveau_bo_tile_layout(nvbo)) { - ret = RING_SPACE(chan, 8); - if (ret) - return ret; - + if (dst_tiled) { BEGIN_NV04(chan, NvSubCopy, 0x021c, 7); OUT_RING (chan, 0); OUT_RING (chan, 0); @@ -848,18 +839,10 @@ OUT_RING (chan, 0); OUT_RING (chan, 0); } else { - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_NV04(chan, NvSubCopy, 0x021c, 1); OUT_RING (chan, 1); } - ret = RING_SPACE(chan, 14); - if (ret) - return ret; - BEGIN_NV04(chan, NvSubCopy, 0x0238, 2); OUT_RING (chan, upper_32_bits(src_offset)); OUT_RING (chan, upper_32_bits(dst_offset)); --- linux-3.13.0.orig/drivers/gpu/drm/nouveau/nouveau_bios.c +++ linux-3.13.0/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -352,7 +352,7 @@ /* Apple cards don't have the fp table; the laptops use DDC */ /* The table is also missing on some x86 IGPs */ #ifndef __powerpc__ - NV_ERROR(drm, "Pointer to flat panel table invalid\n"); + NV_WARN(drm, "Pointer to flat panel table invalid\n"); #endif bios->digital_min_front_porch = 0x4b; return 0; @@ -936,7 +936,7 @@ tmdstableptr = ROM16(bios->data[bitentry->offset]); if (!tmdstableptr) { - NV_ERROR(drm, "Pointer to TMDS table invalid\n"); + NV_WARN(drm, "Pointer to TMDS table invalid\n"); return -EINVAL; } --- linux-3.13.0.orig/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c +++ linux-3.13.0/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c @@ -36,7 +36,7 @@ .fini = _nouveau_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv10_ram_oclass, + .base.ram = &nv1a_ram_oclass, .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, --- linux-3.13.0.orig/drivers/gpu/drm/nouveau/core/engine/falcon.c +++ linux-3.13.0/drivers/gpu/drm/nouveau/core/engine/falcon.c @@ -56,6 +56,16 @@ nv_wr32(falcon, falcon->addr + addr, data); } +static void * +vmemdup(const void *src, size_t len) +{ + void *p = vmalloc(len); + + if (p) + memcpy(p, src, len); + return p; +} + int _nouveau_falcon_init(struct nouveau_object *object) { @@ -111,7 +121,7 @@ ret = request_firmware(&fw, name, &device->pdev->dev); if (ret == 0) { - falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL); + falcon->code.data = vmemdup(fw->data, fw->size); falcon->code.size = fw->size; falcon->data.data = NULL; falcon->data.size = 0; @@ -134,7 +144,7 @@ return ret; } - falcon->data.data = kmemdup(fw->data, fw->size, GFP_KERNEL); + falcon->data.data = vmemdup(fw->data, fw->size); falcon->data.size = fw->size; release_firmware(fw); if (!falcon->data.data) @@ -149,7 +159,7 @@ return ret; } - falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL); + falcon->code.data = vmemdup(fw->data, fw->size); falcon->code.size = fw->size; release_firmware(fw); if (!falcon->code.data) @@ -235,8 +245,8 @@ if (!suspend) { nouveau_gpuobj_ref(NULL, &falcon->core); if (falcon->external) { - kfree(falcon->data.data); - kfree(falcon->code.data); + vfree(falcon->data.data); + vfree(falcon->code.data); falcon->code.data = NULL; } } --- linux-3.13.0.orig/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ linux-3.13.0/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -1112,7 +1112,7 @@ if (conf != ~0) { if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) { u32 soff = (ffs(outp.or) - 1) * 0x08; - u32 ctrl = nv_rd32(priv, 0x610798 + soff); + u32 ctrl = nv_rd32(priv, 0x610794 + soff); u32 datarate; switch ((ctrl & 0x000f0000) >> 16) { --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -40,6 +40,10 @@ static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED; +static uint32_t sys_ne_placement_flags = TTM_PL_FLAG_SYSTEM | + TTM_PL_FLAG_CACHED | + TTM_PL_FLAG_NO_EVICT; + static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED; @@ -47,6 +51,9 @@ TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT; +static uint32_t mob_placement_flags = VMW_PL_FLAG_MOB | + TTM_PL_FLAG_CACHED; + struct ttm_placement vmw_vram_placement = { .fpfn = 0, .lpfn = 0, @@ -116,16 +123,26 @@ .busy_placement = &sys_placement_flags }; +struct ttm_placement vmw_sys_ne_placement = { + .fpfn = 0, + .lpfn = 0, + .num_placement = 1, + .placement = &sys_ne_placement_flags, + .num_busy_placement = 1, + .busy_placement = &sys_ne_placement_flags +}; + static uint32_t evictable_placement_flags[] = { TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED, - VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED + VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED, + VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED }; struct ttm_placement vmw_evictable_placement = { .fpfn = 0, .lpfn = 0, - .num_placement = 3, + .num_placement = 4, .placement = evictable_placement_flags, .num_busy_placement = 1, .busy_placement = &sys_placement_flags @@ -140,10 +157,21 @@ .busy_placement = gmr_vram_placement_flags }; +struct ttm_placement vmw_mob_placement = { + .fpfn = 0, + .lpfn = 0, + .num_placement = 1, + .num_busy_placement = 1, + .placement = &mob_placement_flags, + .busy_placement = &mob_placement_flags +}; + struct vmw_ttm_tt { struct ttm_dma_tt dma_ttm; struct vmw_private *dev_priv; int gmr_id; + struct vmw_mob *mob; + int mem_type; struct sg_table sgt; struct vmw_sg_table vsgt; uint64_t sg_alloc_size; @@ -244,6 +272,7 @@ viter->dma_address = &__vmw_piter_dma_addr; viter->page = &__vmw_piter_non_sg_page; viter->addrs = vsgt->addrs; + viter->pages = vsgt->pages; break; case vmw_dma_map_populate: case vmw_dma_map_bind: @@ -424,6 +453,63 @@ vmw_tt->mapped = false; } + +/** + * vmw_bo_map_dma - Make sure buffer object pages are visible to the device + * + * @bo: Pointer to a struct ttm_buffer_object + * + * Wrapper around vmw_ttm_map_dma, that takes a TTM buffer object pointer + * instead of a pointer to a struct vmw_ttm_backend as argument. + * Note that the buffer object must be either pinned or reserved before + * calling this function. + */ +int vmw_bo_map_dma(struct ttm_buffer_object *bo) +{ + struct vmw_ttm_tt *vmw_tt = + container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm); + + return vmw_ttm_map_dma(vmw_tt); +} + + +/** + * vmw_bo_unmap_dma - Make sure buffer object pages are visible to the device + * + * @bo: Pointer to a struct ttm_buffer_object + * + * Wrapper around vmw_ttm_unmap_dma, that takes a TTM buffer object pointer + * instead of a pointer to a struct vmw_ttm_backend as argument. + */ +void vmw_bo_unmap_dma(struct ttm_buffer_object *bo) +{ + struct vmw_ttm_tt *vmw_tt = + container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm); + + vmw_ttm_unmap_dma(vmw_tt); +} + + +/** + * vmw_bo_sg_table - Return a struct vmw_sg_table object for a + * TTM buffer object + * + * @bo: Pointer to a struct ttm_buffer_object + * + * Returns a pointer to a struct vmw_sg_table object. The object should + * not be freed after use. + * Note that for the device addresses to be valid, the buffer object must + * either be reserved or pinned. + */ +const struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo) +{ + struct vmw_ttm_tt *vmw_tt = + container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm); + + return &vmw_tt->vsgt; +} + + static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) { struct vmw_ttm_tt *vmw_be = @@ -435,9 +521,27 @@ return ret; vmw_be->gmr_id = bo_mem->start; + vmw_be->mem_type = bo_mem->mem_type; + + switch (bo_mem->mem_type) { + case VMW_PL_GMR: + return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt, + ttm->num_pages, vmw_be->gmr_id); + case VMW_PL_MOB: + if (unlikely(vmw_be->mob == NULL)) { + vmw_be->mob = + vmw_mob_create(ttm->num_pages); + if (unlikely(vmw_be->mob == NULL)) + return -ENOMEM; + } - return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt, - ttm->num_pages, vmw_be->gmr_id); + return vmw_mob_bind(vmw_be->dev_priv, vmw_be->mob, + &vmw_be->vsgt, ttm->num_pages, + vmw_be->gmr_id); + default: + BUG(); + } + return 0; } static int vmw_ttm_unbind(struct ttm_tt *ttm) @@ -445,7 +549,16 @@ struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm); - vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id); + switch (vmw_be->mem_type) { + case VMW_PL_GMR: + vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id); + break; + case VMW_PL_MOB: + vmw_mob_unbind(vmw_be->dev_priv, vmw_be->mob); + break; + default: + BUG(); + } if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind) vmw_ttm_unmap_dma(vmw_be); @@ -453,6 +566,7 @@ return 0; } + static void vmw_ttm_destroy(struct ttm_tt *ttm) { struct vmw_ttm_tt *vmw_be = @@ -463,9 +577,14 @@ ttm_dma_tt_fini(&vmw_be->dma_ttm); else ttm_tt_fini(ttm); + + if (vmw_be->mob) + vmw_mob_destroy(vmw_be->mob); + kfree(vmw_be); } + static int vmw_ttm_populate(struct ttm_tt *ttm) { struct vmw_ttm_tt *vmw_tt = @@ -500,6 +619,12 @@ struct vmw_private *dev_priv = vmw_tt->dev_priv; struct ttm_mem_global *glob = vmw_mem_glob(dev_priv); + + if (vmw_tt->mob) { + vmw_mob_destroy(vmw_tt->mob); + vmw_tt->mob = NULL; + } + vmw_ttm_unmap_dma(vmw_tt); if (dev_priv->map_mode == vmw_dma_alloc_coherent) { size_t size = @@ -517,7 +642,7 @@ .destroy = vmw_ttm_destroy, }; -struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, +static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, struct page *dummy_read_page) { @@ -530,6 +655,7 @@ vmw_be->dma_ttm.ttm.func = &vmw_ttm_func; vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev); + vmw_be->mob = NULL; if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent) ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags, @@ -546,12 +672,12 @@ return NULL; } -int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) +static int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) { return 0; } -int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, +static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, struct ttm_mem_type_manager *man) { switch (type) { @@ -571,6 +697,7 @@ man->default_caching = TTM_PL_FLAG_CACHED; break; case VMW_PL_GMR: + case VMW_PL_MOB: /* * "Guest Memory Regions" is an aperture like feature with * one slot per bo. There is an upper limit of the number of @@ -589,7 +716,7 @@ return 0; } -void vmw_evict_flags(struct ttm_buffer_object *bo, +static void vmw_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { *placement = vmw_sys_placement; @@ -618,6 +745,7 @@ switch (mem->mem_type) { case TTM_PL_SYSTEM: case VMW_PL_GMR: + case VMW_PL_MOB: return 0; case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; @@ -677,6 +805,38 @@ VMW_FENCE_WAIT_TIMEOUT); } +/** + * vmw_move_notify - TTM move_notify_callback + * + * @bo: The TTM buffer object about to move. + * @mem: The truct ttm_mem_reg indicating to what memory + * region the move is taking place. + * + * Calls move_notify for all subsystems needing it. + * (currently only resources). + */ +static void vmw_move_notify(struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem) +{ + vmw_resource_move_notify(bo, mem); +} + + +/** + * vmw_swap_notify - TTM move_notify_callback + * + * @bo: The TTM buffer object about to be swapped out. + */ +static void vmw_swap_notify(struct ttm_buffer_object *bo) +{ + struct ttm_bo_device *bdev = bo->bdev; + + spin_lock(&bdev->fence_lock); + ttm_bo_wait(bo, false, false, false); + spin_unlock(&bdev->fence_lock); +} + + struct ttm_bo_driver vmw_bo_driver = { .ttm_tt_create = &vmw_ttm_tt_create, .ttm_tt_populate = &vmw_ttm_populate, @@ -691,8 +851,8 @@ .sync_obj_flush = vmw_sync_obj_flush, .sync_obj_unref = vmw_sync_obj_unref, .sync_obj_ref = vmw_sync_obj_ref, - .move_notify = NULL, - .swap_notify = NULL, + .move_notify = vmw_move_notify, + .swap_notify = vmw_swap_notify, .fault_reserve_notify = &vmw_ttm_fault_reserve_notify, .io_mem_reserve = &vmw_ttm_io_mem_reserve, .io_mem_free = &vmw_ttm_io_mem_free, --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -271,7 +271,7 @@ spin_unlock_irq(&fman->lock); } -void vmw_fences_perform_actions(struct vmw_fence_manager *fman, +static void vmw_fences_perform_actions(struct vmw_fence_manager *fman, struct list_head *list) { struct vmw_fence_action *action, *next_action; @@ -897,7 +897,7 @@ * Note that the action callbacks may be executed before this function * returns. */ -void vmw_fence_obj_add_action(struct vmw_fence_obj *fence, +static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence, struct vmw_fence_action *action) { struct vmw_fence_manager *fman = fence->fman; @@ -993,7 +993,7 @@ struct drm_vmw_event_fence event; }; -int vmw_event_fence_action_create(struct drm_file *file_priv, +static int vmw_event_fence_action_create(struct drm_file *file_priv, struct vmw_fence_obj *fence, uint32_t flags, uint64_t user_data, @@ -1080,7 +1080,8 @@ */ if (arg->handle) { struct ttm_base_object *base = - ttm_base_object_lookup(vmw_fp->tfile, arg->handle); + ttm_base_object_lookup_for_ref(dev_priv->tdev, + arg->handle); if (unlikely(base == NULL)) { DRM_ERROR("Fence event invalid fence object handle " --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -35,6 +35,23 @@ uint32_t fifo_min, hwversion; const struct vmw_fifo_state *fifo = &dev_priv->fifo; + if (!(dev_priv->capabilities & SVGA_CAP_3D)) + return false; + + if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { + uint32_t result; + + if (!dev_priv->has_mob) + return false; + + mutex_lock(&dev_priv->hw_mutex); + vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_3D); + result = vmw_read(dev_priv, SVGA_REG_DEV_CAP); + mutex_unlock(&dev_priv->hw_mutex); + + return (result != 0); + } + if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) return false; @@ -511,24 +528,16 @@ } /** - * vmw_fifo_emit_dummy_query - emits a dummy query to the fifo. + * vmw_fifo_emit_dummy_legacy_query - emits a dummy query to the fifo using + * legacy query commands. * * @dev_priv: The device private structure. * @cid: The hardware context id used for the query. * - * This function is used to emit a dummy occlusion query with - * no primitives rendered between query begin and query end. - * It's used to provide a query barrier, in order to know that when - * this query is finished, all preceding queries are also finished. - * - * A Query results structure should have been initialized at the start - * of the dev_priv->dummy_query_bo buffer object. And that buffer object - * must also be either reserved or pinned when this function is called. - * - * Returns -ENOMEM on failure to reserve fifo space. + * See the vmw_fifo_emit_dummy_query documentation. */ -int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv, - uint32_t cid) +static int vmw_fifo_emit_dummy_legacy_query(struct vmw_private *dev_priv, + uint32_t cid) { /* * A query wait without a preceding query end will @@ -566,3 +575,75 @@ return 0; } + +/** + * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using + * guest-backed resource query commands. + * + * @dev_priv: The device private structure. + * @cid: The hardware context id used for the query. + * + * See the vmw_fifo_emit_dummy_query documentation. + */ +static int vmw_fifo_emit_dummy_gb_query(struct vmw_private *dev_priv, + uint32_t cid) +{ + /* + * A query wait without a preceding query end will + * actually finish all queries for this cid + * without writing to the query result structure. + */ + + struct ttm_buffer_object *bo = dev_priv->dummy_query_bo; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdWaitForGBQuery body; + } *cmd; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + + if (unlikely(cmd == NULL)) { + DRM_ERROR("Out of fifo space for dummy query.\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_WAIT_FOR_GB_QUERY; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = cid; + cmd->body.type = SVGA3D_QUERYTYPE_OCCLUSION; + BUG_ON(bo->mem.mem_type != VMW_PL_MOB); + cmd->body.mobid = bo->mem.start; + cmd->body.offset = 0; + + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + + +/** + * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using + * appropriate resource query commands. + * + * @dev_priv: The device private structure. + * @cid: The hardware context id used for the query. + * + * This function is used to emit a dummy occlusion query with + * no primitives rendered between query begin and query end. + * It's used to provide a query barrier, in order to know that when + * this query is finished, all preceding queries are also finished. + * + * A Query results structure should have been initialized at the start + * of the dev_priv->dummy_query_bo buffer object. And that buffer object + * must also be either reserved or pinned when this function is called. + * + * Returns -ENOMEM on failure to reserve fifo space. + */ +int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv, + uint32_t cid) +{ + if (dev_priv->has_mob) + return vmw_fifo_emit_dummy_gb_query(dev_priv, cid); + + return vmw_fifo_emit_dummy_legacy_query(dev_priv, cid); +} --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/svga3d_reg.h +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/svga3d_reg.h @@ -34,6 +34,8 @@ #include "svga_reg.h" +typedef uint32 PPN; +typedef __le64 PPN64; /* * 3D Hardware Version @@ -71,6 +73,9 @@ #define SVGA3D_MAX_CONTEXT_IDS 256 #define SVGA3D_MAX_SURFACE_IDS (32 * 1024) +#define SVGA3D_NUM_TEXTURE_UNITS 32 +#define SVGA3D_NUM_LIGHTS 8 + /* * Surface formats. * @@ -81,6 +86,7 @@ */ typedef enum SVGA3dSurfaceFormat { + SVGA3D_FORMAT_MIN = 0, SVGA3D_FORMAT_INVALID = 0, SVGA3D_X8R8G8B8 = 1, @@ -134,12 +140,6 @@ SVGA3D_RG_S10E5 = 35, SVGA3D_RG_S23E8 = 36, - /* - * Any surface can be used as a buffer object, but SVGA3D_BUFFER is - * the most efficient format to use when creating new surfaces - * expressly for index or vertex data. - */ - SVGA3D_BUFFER = 37, SVGA3D_Z_D24X8 = 38, @@ -159,15 +159,109 @@ /* Video format with alpha */ SVGA3D_AYUV = 45, + SVGA3D_R32G32B32A32_TYPELESS = 46, + SVGA3D_R32G32B32A32_FLOAT = 25, + SVGA3D_R32G32B32A32_UINT = 47, + SVGA3D_R32G32B32A32_SINT = 48, + SVGA3D_R32G32B32_TYPELESS = 49, + SVGA3D_R32G32B32_FLOAT = 50, + SVGA3D_R32G32B32_UINT = 51, + SVGA3D_R32G32B32_SINT = 52, + SVGA3D_R16G16B16A16_TYPELESS = 53, + SVGA3D_R16G16B16A16_FLOAT = 24, + SVGA3D_R16G16B16A16_UNORM = 41, + SVGA3D_R16G16B16A16_UINT = 54, + SVGA3D_R16G16B16A16_SNORM = 55, + SVGA3D_R16G16B16A16_SINT = 56, + SVGA3D_R32G32_TYPELESS = 57, + SVGA3D_R32G32_FLOAT = 36, + SVGA3D_R32G32_UINT = 58, + SVGA3D_R32G32_SINT = 59, + SVGA3D_R32G8X24_TYPELESS = 60, + SVGA3D_D32_FLOAT_S8X24_UINT = 61, + SVGA3D_R32_FLOAT_X8X24_TYPELESS = 62, + SVGA3D_X32_TYPELESS_G8X24_UINT = 63, + SVGA3D_R10G10B10A2_TYPELESS = 64, + SVGA3D_R10G10B10A2_UNORM = 26, + SVGA3D_R10G10B10A2_UINT = 65, + SVGA3D_R11G11B10_FLOAT = 66, + SVGA3D_R8G8B8A8_TYPELESS = 67, + SVGA3D_R8G8B8A8_UNORM = 68, + SVGA3D_R8G8B8A8_UNORM_SRGB = 69, + SVGA3D_R8G8B8A8_UINT = 70, + SVGA3D_R8G8B8A8_SNORM = 28, + SVGA3D_R8G8B8A8_SINT = 71, + SVGA3D_R16G16_TYPELESS = 72, + SVGA3D_R16G16_FLOAT = 35, + SVGA3D_R16G16_UNORM = 40, + SVGA3D_R16G16_UINT = 73, + SVGA3D_R16G16_SNORM = 39, + SVGA3D_R16G16_SINT = 74, + SVGA3D_R32_TYPELESS = 75, + SVGA3D_D32_FLOAT = 76, + SVGA3D_R32_FLOAT = 34, + SVGA3D_R32_UINT = 77, + SVGA3D_R32_SINT = 78, + SVGA3D_R24G8_TYPELESS = 79, + SVGA3D_D24_UNORM_S8_UINT = 80, + SVGA3D_R24_UNORM_X8_TYPELESS = 81, + SVGA3D_X24_TYPELESS_G8_UINT = 82, + SVGA3D_R8G8_TYPELESS = 83, + SVGA3D_R8G8_UNORM = 84, + SVGA3D_R8G8_UINT = 85, + SVGA3D_R8G8_SNORM = 27, + SVGA3D_R8G8_SINT = 86, + SVGA3D_R16_TYPELESS = 87, + SVGA3D_R16_FLOAT = 33, + SVGA3D_D16_UNORM = 8, + SVGA3D_R16_UNORM = 88, + SVGA3D_R16_UINT = 89, + SVGA3D_R16_SNORM = 90, + SVGA3D_R16_SINT = 91, + SVGA3D_R8_TYPELESS = 92, + SVGA3D_R8_UNORM = 93, + SVGA3D_R8_UINT = 94, + SVGA3D_R8_SNORM = 95, + SVGA3D_R8_SINT = 96, + SVGA3D_A8_UNORM = 32, + SVGA3D_R1_UNORM = 97, + SVGA3D_R9G9B9E5_SHAREDEXP = 98, + SVGA3D_R8G8_B8G8_UNORM = 99, + SVGA3D_G8R8_G8B8_UNORM = 100, + SVGA3D_BC1_TYPELESS = 101, + SVGA3D_BC1_UNORM = 15, + SVGA3D_BC1_UNORM_SRGB = 102, + SVGA3D_BC2_TYPELESS = 103, + SVGA3D_BC2_UNORM = 17, + SVGA3D_BC2_UNORM_SRGB = 104, + SVGA3D_BC3_TYPELESS = 105, + SVGA3D_BC3_UNORM = 19, + SVGA3D_BC3_UNORM_SRGB = 106, + SVGA3D_BC4_TYPELESS = 107, SVGA3D_BC4_UNORM = 108, + SVGA3D_BC4_SNORM = 109, + SVGA3D_BC5_TYPELESS = 110, SVGA3D_BC5_UNORM = 111, + SVGA3D_BC5_SNORM = 112, + SVGA3D_B5G6R5_UNORM = 3, + SVGA3D_B5G5R5A1_UNORM = 5, + SVGA3D_B8G8R8A8_UNORM = 2, + SVGA3D_B8G8R8X8_UNORM = 1, + SVGA3D_R10G10B10_XR_BIAS_A2_UNORM = 113, + SVGA3D_B8G8R8A8_TYPELESS = 114, + SVGA3D_B8G8R8A8_UNORM_SRGB = 115, + SVGA3D_B8G8R8X8_TYPELESS = 116, + SVGA3D_B8G8R8X8_UNORM_SRGB = 117, /* Advanced D3D9 depth formats. */ SVGA3D_Z_DF16 = 118, SVGA3D_Z_DF24 = 119, SVGA3D_Z_D24S8_INT = 120, - SVGA3D_FORMAT_MAX + /* Planar video formats. */ + SVGA3D_YV12 = 121, + + SVGA3D_FORMAT_MAX = 122, } SVGA3dSurfaceFormat; typedef uint32 SVGA3dColor; /* a, r, g, b */ @@ -957,15 +1051,21 @@ } SVGA3dCubeFace; typedef enum { + SVGA3D_SHADERTYPE_INVALID = 0, + SVGA3D_SHADERTYPE_MIN = 1, SVGA3D_SHADERTYPE_VS = 1, SVGA3D_SHADERTYPE_PS = 2, - SVGA3D_SHADERTYPE_MAX + SVGA3D_SHADERTYPE_MAX = 3, + SVGA3D_SHADERTYPE_GS = 3, } SVGA3dShaderType; +#define SVGA3D_NUM_SHADERTYPE (SVGA3D_SHADERTYPE_MAX - SVGA3D_SHADERTYPE_MIN) + typedef enum { SVGA3D_CONST_TYPE_FLOAT = 0, SVGA3D_CONST_TYPE_INT = 1, SVGA3D_CONST_TYPE_BOOL = 2, + SVGA3D_CONST_TYPE_MAX } SVGA3dShaderConstType; #define SVGA3D_MAX_SURFACE_FACES 6 @@ -1056,9 +1156,84 @@ #define SVGA_3D_CMD_GENERATE_MIPMAPS SVGA_3D_CMD_BASE + 31 #define SVGA_3D_CMD_ACTIVATE_SURFACE SVGA_3D_CMD_BASE + 40 #define SVGA_3D_CMD_DEACTIVATE_SURFACE SVGA_3D_CMD_BASE + 41 -#define SVGA_3D_CMD_MAX SVGA_3D_CMD_BASE + 42 +#define SVGA_3D_CMD_SCREEN_DMA 1082 +#define SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE 1083 +#define SVGA_3D_CMD_OPEN_CONTEXT_SURFACE 1084 + +#define SVGA_3D_CMD_LOGICOPS_BITBLT 1085 +#define SVGA_3D_CMD_LOGICOPS_TRANSBLT 1086 +#define SVGA_3D_CMD_LOGICOPS_STRETCHBLT 1087 +#define SVGA_3D_CMD_LOGICOPS_COLORFILL 1088 +#define SVGA_3D_CMD_LOGICOPS_ALPHABLEND 1089 +#define SVGA_3D_CMD_LOGICOPS_CLEARTYPEBLEND 1090 + +#define SVGA_3D_CMD_SET_OTABLE_BASE 1091 +#define SVGA_3D_CMD_READBACK_OTABLE 1092 + +#define SVGA_3D_CMD_DEFINE_GB_MOB 1093 +#define SVGA_3D_CMD_DESTROY_GB_MOB 1094 +#define SVGA_3D_CMD_REDEFINE_GB_MOB 1095 +#define SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING 1096 + +#define SVGA_3D_CMD_DEFINE_GB_SURFACE 1097 +#define SVGA_3D_CMD_DESTROY_GB_SURFACE 1098 +#define SVGA_3D_CMD_BIND_GB_SURFACE 1099 +#define SVGA_3D_CMD_COND_BIND_GB_SURFACE 1100 +#define SVGA_3D_CMD_UPDATE_GB_IMAGE 1101 +#define SVGA_3D_CMD_UPDATE_GB_SURFACE 1102 +#define SVGA_3D_CMD_READBACK_GB_IMAGE 1103 +#define SVGA_3D_CMD_READBACK_GB_SURFACE 1104 +#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE 1105 +#define SVGA_3D_CMD_INVALIDATE_GB_SURFACE 1106 + +#define SVGA_3D_CMD_DEFINE_GB_CONTEXT 1107 +#define SVGA_3D_CMD_DESTROY_GB_CONTEXT 1108 +#define SVGA_3D_CMD_BIND_GB_CONTEXT 1109 +#define SVGA_3D_CMD_READBACK_GB_CONTEXT 1110 +#define SVGA_3D_CMD_INVALIDATE_GB_CONTEXT 1111 + +#define SVGA_3D_CMD_DEFINE_GB_SHADER 1112 +#define SVGA_3D_CMD_DESTROY_GB_SHADER 1113 +#define SVGA_3D_CMD_BIND_GB_SHADER 1114 + +#define SVGA_3D_CMD_SET_OTABLE_BASE64 1115 + +#define SVGA_3D_CMD_BEGIN_GB_QUERY 1116 +#define SVGA_3D_CMD_END_GB_QUERY 1117 +#define SVGA_3D_CMD_WAIT_FOR_GB_QUERY 1118 + +#define SVGA_3D_CMD_NOP 1119 + +#define SVGA_3D_CMD_ENABLE_GART 1120 +#define SVGA_3D_CMD_DISABLE_GART 1121 +#define SVGA_3D_CMD_MAP_MOB_INTO_GART 1122 +#define SVGA_3D_CMD_UNMAP_GART_RANGE 1123 + +#define SVGA_3D_CMD_DEFINE_GB_SCREENTARGET 1124 +#define SVGA_3D_CMD_DESTROY_GB_SCREENTARGET 1125 +#define SVGA_3D_CMD_BIND_GB_SCREENTARGET 1126 +#define SVGA_3D_CMD_UPDATE_GB_SCREENTARGET 1127 + +#define SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL 1128 +#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129 + +#define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE 1130 +#define SVGA_3D_CMD_GB_SCREEN_DMA 1131 +#define SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH 1132 +#define SVGA_3D_CMD_GB_MOB_FENCE 1133 +#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 1134 +#define SVGA_3D_CMD_DEFINE_GB_MOB64 1135 +#define SVGA_3D_CMD_REDEFINE_GB_MOB64 1136 +#define SVGA_3D_CMD_NOP_ERROR 1137 + +#define SVGA_3D_CMD_RESERVED1 1138 +#define SVGA_3D_CMD_RESERVED2 1139 +#define SVGA_3D_CMD_RESERVED3 1140 +#define SVGA_3D_CMD_RESERVED4 1141 +#define SVGA_3D_CMD_RESERVED5 1142 -#define SVGA_3D_CMD_FUTURE_MAX 2000 +#define SVGA_3D_CMD_MAX 1142 +#define SVGA_3D_CMD_FUTURE_MAX 3000 /* * Common substructures used in multiple FIFO commands: @@ -1750,6 +1925,507 @@ /* + * Guest-backed surface definitions. + */ + +typedef uint32 SVGAMobId; + +typedef enum SVGAMobFormat { + SVGA3D_MOBFMT_INVALID = SVGA3D_INVALID_ID, + SVGA3D_MOBFMT_PTDEPTH_0 = 0, + SVGA3D_MOBFMT_PTDEPTH_1 = 1, + SVGA3D_MOBFMT_PTDEPTH_2 = 2, + SVGA3D_MOBFMT_RANGE = 3, + SVGA3D_MOBFMT_PTDEPTH64_0 = 4, + SVGA3D_MOBFMT_PTDEPTH64_1 = 5, + SVGA3D_MOBFMT_PTDEPTH64_2 = 6, + SVGA3D_MOBFMT_MAX, +} SVGAMobFormat; + +/* + * Sizes of opaque types. + */ + +#define SVGA3D_OTABLE_MOB_ENTRY_SIZE 16 +#define SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE 8 +#define SVGA3D_OTABLE_SURFACE_ENTRY_SIZE 64 +#define SVGA3D_OTABLE_SHADER_ENTRY_SIZE 16 +#define SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE 64 +#define SVGA3D_CONTEXT_DATA_SIZE 16384 + +/* + * SVGA3dCmdSetOTableBase -- + * + * This command allows the guest to specify the base PPN of the + * specified object table. + */ + +typedef enum { + SVGA_OTABLE_MOB = 0, + SVGA_OTABLE_MIN = 0, + SVGA_OTABLE_SURFACE = 1, + SVGA_OTABLE_CONTEXT = 2, + SVGA_OTABLE_SHADER = 3, + SVGA_OTABLE_SCREEN_TARGET = 4, + SVGA_OTABLE_DX9_MAX = 5, + SVGA_OTABLE_MAX = 8 +} SVGAOTableType; + +typedef +struct { + SVGAOTableType type; + PPN baseAddress; + uint32 sizeInBytes; + uint32 validSizeInBytes; + SVGAMobFormat ptDepth; +} __packed +SVGA3dCmdSetOTableBase; /* SVGA_3D_CMD_SET_OTABLE_BASE */ + +typedef +struct { + SVGAOTableType type; + PPN64 baseAddress; + uint32 sizeInBytes; + uint32 validSizeInBytes; + SVGAMobFormat ptDepth; +} __packed +SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */ + +typedef +struct { + SVGAOTableType type; +} __packed +SVGA3dCmdReadbackOTable; /* SVGA_3D_CMD_READBACK_OTABLE */ + +/* + * Define a memory object (Mob) in the OTable. + */ + +typedef +struct SVGA3dCmdDefineGBMob { + SVGAMobId mobid; + SVGAMobFormat ptDepth; + PPN base; + uint32 sizeInBytes; +} __packed +SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */ + + +/* + * Destroys an object in the OTable. + */ + +typedef +struct SVGA3dCmdDestroyGBMob { + SVGAMobId mobid; +} __packed +SVGA3dCmdDestroyGBMob; /* SVGA_3D_CMD_DESTROY_GB_MOB */ + +/* + * Redefine an object in the OTable. + */ + +typedef +struct SVGA3dCmdRedefineGBMob { + SVGAMobId mobid; + SVGAMobFormat ptDepth; + PPN base; + uint32 sizeInBytes; +} __packed +SVGA3dCmdRedefineGBMob; /* SVGA_3D_CMD_REDEFINE_GB_MOB */ + +/* + * Define a memory object (Mob) in the OTable with a PPN64 base. + */ + +typedef +struct SVGA3dCmdDefineGBMob64 { + SVGAMobId mobid; + SVGAMobFormat ptDepth; + PPN64 base; + uint32 sizeInBytes; +} __packed +SVGA3dCmdDefineGBMob64; /* SVGA_3D_CMD_DEFINE_GB_MOB64 */ + +/* + * Redefine an object in the OTable with PPN64 base. + */ + +typedef +struct SVGA3dCmdRedefineGBMob64 { + SVGAMobId mobid; + SVGAMobFormat ptDepth; + PPN64 base; + uint32 sizeInBytes; +} __packed +SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */ + +/* + * Notification that the page tables have been modified. + */ + +typedef +struct SVGA3dCmdUpdateGBMobMapping { + SVGAMobId mobid; +} __packed +SVGA3dCmdUpdateGBMobMapping; /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */ + +/* + * Define a guest-backed surface. + */ + +typedef +struct SVGA3dCmdDefineGBSurface { + uint32 sid; + SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurfaceFormat format; + uint32 numMipLevels; + uint32 multisampleCount; + SVGA3dTextureFilter autogenFilter; + SVGA3dSize size; +} __packed +SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */ + +/* + * Destroy a guest-backed surface. + */ + +typedef +struct SVGA3dCmdDestroyGBSurface { + uint32 sid; +} __packed +SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */ + +/* + * Bind a guest-backed surface to an object. + */ + +typedef +struct SVGA3dCmdBindGBSurface { + uint32 sid; + SVGAMobId mobid; +} __packed +SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */ + +/* + * Conditionally bind a mob to a guest backed surface if testMobid + * matches the currently bound mob. Optionally issue a readback on + * the surface while it is still bound to the old mobid if the mobid + * is changed by this command. + */ + +#define SVGA3D_COND_BIND_GB_SURFACE_FLAG_READBACK (1 << 0) + +typedef +struct{ + uint32 sid; + SVGAMobId testMobid; + SVGAMobId mobid; + uint32 flags; +} __packed +SVGA3dCmdCondBindGBSurface; /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */ + +/* + * Update an image in a guest-backed surface. + * (Inform the device that the guest-contents have been updated.) + */ + +typedef +struct SVGA3dCmdUpdateGBImage { + SVGA3dSurfaceImageId image; + SVGA3dBox box; +} __packed +SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */ + +/* + * Update an entire guest-backed surface. + * (Inform the device that the guest-contents have been updated.) + */ + +typedef +struct SVGA3dCmdUpdateGBSurface { + uint32 sid; +} __packed +SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */ + +/* + * Readback an image in a guest-backed surface. + * (Request the device to flush the dirty contents into the guest.) + */ + +typedef +struct SVGA3dCmdReadbackGBImage { + SVGA3dSurfaceImageId image; +} __packed +SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/ + +/* + * Readback an entire guest-backed surface. + * (Request the device to flush the dirty contents into the guest.) + */ + +typedef +struct SVGA3dCmdReadbackGBSurface { + uint32 sid; +} __packed +SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */ + +/* + * Readback a sub rect of an image in a guest-backed surface. After + * issuing this command the driver is required to issue an update call + * of the same region before issuing any other commands that reference + * this surface or rendering is not guaranteed. + */ + +typedef +struct SVGA3dCmdReadbackGBImagePartial { + SVGA3dSurfaceImageId image; + SVGA3dBox box; + uint32 invertBox; +} __packed +SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */ + +/* + * Invalidate an image in a guest-backed surface. + * (Notify the device that the contents can be lost.) + */ + +typedef +struct SVGA3dCmdInvalidateGBImage { + SVGA3dSurfaceImageId image; +} __packed +SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */ + +/* + * Invalidate an entire guest-backed surface. + * (Notify the device that the contents if all images can be lost.) + */ + +typedef +struct SVGA3dCmdInvalidateGBSurface { + uint32 sid; +} __packed +SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */ + +/* + * Invalidate a sub rect of an image in a guest-backed surface. After + * issuing this command the driver is required to issue an update call + * of the same region before issuing any other commands that reference + * this surface or rendering is not guaranteed. + */ + +typedef +struct SVGA3dCmdInvalidateGBImagePartial { + SVGA3dSurfaceImageId image; + SVGA3dBox box; + uint32 invertBox; +} __packed +SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */ + +/* + * Define a guest-backed context. + */ + +typedef +struct SVGA3dCmdDefineGBContext { + uint32 cid; +} __packed +SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */ + +/* + * Destroy a guest-backed context. + */ + +typedef +struct SVGA3dCmdDestroyGBContext { + uint32 cid; +} __packed +SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */ + +/* + * Bind a guest-backed context. + * + * validContents should be set to 0 for new contexts, + * and 1 if this is an old context which is getting paged + * back on to the device. + * + * For new contexts, it is recommended that the driver + * issue commands to initialize all interesting state + * prior to rendering. + */ + +typedef +struct SVGA3dCmdBindGBContext { + uint32 cid; + SVGAMobId mobid; + uint32 validContents; +} __packed +SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */ + +/* + * Readback a guest-backed context. + * (Request that the device flush the contents back into guest memory.) + */ + +typedef +struct SVGA3dCmdReadbackGBContext { + uint32 cid; +} __packed +SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */ + +/* + * Invalidate a guest-backed context. + */ +typedef +struct SVGA3dCmdInvalidateGBContext { + uint32 cid; +} __packed +SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */ + +/* + * Define a guest-backed shader. + */ + +typedef +struct SVGA3dCmdDefineGBShader { + uint32 shid; + SVGA3dShaderType type; + uint32 sizeInBytes; +} __packed +SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */ + +/* + * Bind a guest-backed shader. + */ + +typedef struct SVGA3dCmdBindGBShader { + uint32 shid; + SVGAMobId mobid; + uint32 offsetInBytes; +} __packed +SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */ + +/* + * Destroy a guest-backed shader. + */ + +typedef struct SVGA3dCmdDestroyGBShader { + uint32 shid; +} __packed +SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */ + +typedef +struct { + uint32 cid; + uint32 regStart; + SVGA3dShaderType shaderType; + SVGA3dShaderConstType constType; + + /* + * Followed by a variable number of shader constants. + * + * Note that FLOAT and INT constants are 4-dwords in length, while + * BOOL constants are 1-dword in length. + */ +} __packed +SVGA3dCmdSetGBShaderConstInline; +/* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */ + +typedef +struct { + uint32 cid; + SVGA3dQueryType type; +} __packed +SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */ + +typedef +struct { + uint32 cid; + SVGA3dQueryType type; + SVGAMobId mobid; + uint32 offset; +} __packed +SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */ + + +/* + * SVGA_3D_CMD_WAIT_FOR_GB_QUERY -- + * + * The semantics of this command are identical to the + * SVGA_3D_CMD_WAIT_FOR_QUERY except that the results are written + * to a Mob instead of a GMR. + */ + +typedef +struct { + uint32 cid; + SVGA3dQueryType type; + SVGAMobId mobid; + uint32 offset; +} __packed +SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */ + +typedef +struct { + SVGAMobId mobid; + uint32 fbOffset; + uint32 initalized; +} __packed +SVGA3dCmdEnableGart; /* SVGA_3D_CMD_ENABLE_GART */ + +typedef +struct { + SVGAMobId mobid; + uint32 gartOffset; +} __packed +SVGA3dCmdMapMobIntoGart; /* SVGA_3D_CMD_MAP_MOB_INTO_GART */ + + +typedef +struct { + uint32 gartOffset; + uint32 numPages; +} __packed +SVGA3dCmdUnmapGartRange; /* SVGA_3D_CMD_UNMAP_GART_RANGE */ + + +/* + * Screen Targets + */ +#define SVGA_STFLAG_PRIMARY (1 << 0) + +typedef +struct { + uint32 stid; + uint32 width; + uint32 height; + int32 xRoot; + int32 yRoot; + uint32 flags; +} __packed +SVGA3dCmdDefineGBScreenTarget; /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */ + +typedef +struct { + uint32 stid; +} __packed +SVGA3dCmdDestroyGBScreenTarget; /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */ + +typedef +struct { + uint32 stid; + SVGA3dSurfaceImageId image; +} __packed +SVGA3dCmdBindGBScreenTarget; /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */ + +typedef +struct { + uint32 stid; + SVGA3dBox box; +} __packed +SVGA3dCmdUpdateGBScreenTarget; /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */ + +/* * Capability query index. * * Notes: @@ -1879,10 +2555,41 @@ SVGA3D_DEVCAP_SURFACEFMT_BC5_UNORM = 83, /* - * Don't add new caps into the previous section; the values in this - * enumeration must not change. You can put new values right before - * SVGA3D_DEVCAP_MAX. + * Deprecated. + */ + SVGA3D_DEVCAP_VGPU10 = 84, + + /* + * This contains several SVGA_3D_CAPS_VIDEO_DECODE elements + * ored together, one for every type of video decoding supported. */ + SVGA3D_DEVCAP_VIDEO_DECODE = 85, + + /* + * This contains several SVGA_3D_CAPS_VIDEO_PROCESS elements + * ored together, one for every type of video processing supported. + */ + SVGA3D_DEVCAP_VIDEO_PROCESS = 86, + + SVGA3D_DEVCAP_LINE_AA = 87, /* boolean */ + SVGA3D_DEVCAP_LINE_STIPPLE = 88, /* boolean */ + SVGA3D_DEVCAP_MAX_LINE_WIDTH = 89, /* float */ + SVGA3D_DEVCAP_MAX_AA_LINE_WIDTH = 90, /* float */ + + SVGA3D_DEVCAP_SURFACEFMT_YV12 = 91, + + /* + * Does the host support the SVGA logic ops commands? + */ + SVGA3D_DEVCAP_LOGICOPS = 92, + + /* + * What support does the host have for screen targets? + * + * See the SVGA3D_SCREENTARGET_CAP bits below. + */ + SVGA3D_DEVCAP_SCREENTARGETS = 93, + SVGA3D_DEVCAP_MAX /* This must be the last index. */ } SVGA3dDevCapIndex; @@ -1893,4 +2600,28 @@ float f; } SVGA3dDevCapResult; +typedef enum { + SVGA3DCAPS_RECORD_UNKNOWN = 0, + SVGA3DCAPS_RECORD_DEVCAPS_MIN = 0x100, + SVGA3DCAPS_RECORD_DEVCAPS = 0x100, + SVGA3DCAPS_RECORD_DEVCAPS_MAX = 0x1ff, +} SVGA3dCapsRecordType; + +typedef +struct SVGA3dCapsRecordHeader { + uint32 length; + SVGA3dCapsRecordType type; +} +SVGA3dCapsRecordHeader; + +typedef +struct SVGA3dCapsRecord { + SVGA3dCapsRecordHeader header; + uint32 data[1]; +} +SVGA3dCapsRecord; + + +typedef uint32 SVGA3dCapPair[2]; + #endif /* _SVGA3D_REG_H_ */ --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -125,181 +125,27 @@ } -static void vmw_gmr_free_descriptors(struct device *dev, dma_addr_t desc_dma, - struct list_head *desc_pages) -{ - struct page *page, *next; - struct svga_guest_mem_descriptor *page_virtual; - unsigned int desc_per_page = PAGE_SIZE / - sizeof(struct svga_guest_mem_descriptor) - 1; - - if (list_empty(desc_pages)) - return; - - list_for_each_entry_safe(page, next, desc_pages, lru) { - list_del_init(&page->lru); - - if (likely(desc_dma != DMA_ADDR_INVALID)) { - dma_unmap_page(dev, desc_dma, PAGE_SIZE, - DMA_TO_DEVICE); - } - - page_virtual = kmap_atomic(page); - desc_dma = (dma_addr_t) - le32_to_cpu(page_virtual[desc_per_page].ppn) << - PAGE_SHIFT; - kunmap_atomic(page_virtual); - - __free_page(page); - } -} - -/** - * FIXME: Adjust to the ttm lowmem / highmem storage to minimize - * the number of used descriptors. - * - */ - -static int vmw_gmr_build_descriptors(struct device *dev, - struct list_head *desc_pages, - struct vmw_piter *iter, - unsigned long num_pages, - dma_addr_t *first_dma) -{ - struct page *page; - struct svga_guest_mem_descriptor *page_virtual = NULL; - struct svga_guest_mem_descriptor *desc_virtual = NULL; - unsigned int desc_per_page; - unsigned long prev_pfn; - unsigned long pfn; - int ret; - dma_addr_t desc_dma; - - desc_per_page = PAGE_SIZE / - sizeof(struct svga_guest_mem_descriptor) - 1; - - while (likely(num_pages != 0)) { - page = alloc_page(__GFP_HIGHMEM); - if (unlikely(page == NULL)) { - ret = -ENOMEM; - goto out_err; - } - - list_add_tail(&page->lru, desc_pages); - page_virtual = kmap_atomic(page); - desc_virtual = page_virtual - 1; - prev_pfn = ~(0UL); - - while (likely(num_pages != 0)) { - pfn = vmw_piter_dma_addr(iter) >> PAGE_SHIFT; - - if (pfn != prev_pfn + 1) { - - if (desc_virtual - page_virtual == - desc_per_page - 1) - break; - - (++desc_virtual)->ppn = cpu_to_le32(pfn); - desc_virtual->num_pages = cpu_to_le32(1); - } else { - uint32_t tmp = - le32_to_cpu(desc_virtual->num_pages); - desc_virtual->num_pages = cpu_to_le32(tmp + 1); - } - prev_pfn = pfn; - --num_pages; - vmw_piter_next(iter); - } - - (++desc_virtual)->ppn = DMA_PAGE_INVALID; - desc_virtual->num_pages = cpu_to_le32(0); - kunmap_atomic(page_virtual); - } - - desc_dma = 0; - list_for_each_entry_reverse(page, desc_pages, lru) { - page_virtual = kmap_atomic(page); - page_virtual[desc_per_page].ppn = cpu_to_le32 - (desc_dma >> PAGE_SHIFT); - kunmap_atomic(page_virtual); - desc_dma = dma_map_page(dev, page, 0, PAGE_SIZE, - DMA_TO_DEVICE); - - if (unlikely(dma_mapping_error(dev, desc_dma))) - goto out_err; - } - *first_dma = desc_dma; - - return 0; -out_err: - vmw_gmr_free_descriptors(dev, DMA_ADDR_INVALID, desc_pages); - return ret; -} - -static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv, - int gmr_id, dma_addr_t desc_dma) -{ - mutex_lock(&dev_priv->hw_mutex); - - vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); - wmb(); - vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, desc_dma >> PAGE_SHIFT); - mb(); - - mutex_unlock(&dev_priv->hw_mutex); - -} - int vmw_gmr_bind(struct vmw_private *dev_priv, const struct vmw_sg_table *vsgt, unsigned long num_pages, int gmr_id) { - struct list_head desc_pages; - dma_addr_t desc_dma = 0; - struct device *dev = dev_priv->dev->dev; struct vmw_piter data_iter; - int ret; vmw_piter_start(&data_iter, vsgt, 0); if (unlikely(!vmw_piter_next(&data_iter))) return 0; - if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) - return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id); - - if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR))) - return -EINVAL; - - if (vsgt->num_regions > dev_priv->max_gmr_descriptors) + if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR2))) return -EINVAL; - INIT_LIST_HEAD(&desc_pages); - - ret = vmw_gmr_build_descriptors(dev, &desc_pages, &data_iter, - num_pages, &desc_dma); - if (unlikely(ret != 0)) - return ret; - - vmw_gmr_fire_descriptors(dev_priv, gmr_id, desc_dma); - vmw_gmr_free_descriptors(dev, desc_dma, &desc_pages); - - return 0; + return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id); } void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id) { - if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) { + if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) vmw_gmr2_unbind(dev_priv, gmr_id); - return; - } - - mutex_lock(&dev_priv->hw_mutex); - vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); - wmb(); - vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, 0); - mb(); - mutex_unlock(&dev_priv->hw_mutex); } --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/svga_reg.h +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -169,7 +169,17 @@ SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */ SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */ SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */ - SVGA_REG_TOP = 48, /* Must be 1 more than the last register */ + SVGA_REG_COMMAND_LOW = 48, /* Lower 32 bits and submits commands */ + SVGA_REG_COMMAND_HIGH = 49, /* Upper 32 bits of command buffer PA */ + SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, /* Max primary memory */ + SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Suggested limit on mob mem */ + SVGA_REG_DEV_CAP = 52, /* Write dev cap index, read value */ + SVGA_REG_CMD_PREPEND_LOW = 53, + SVGA_REG_CMD_PREPEND_HIGH = 54, + SVGA_REG_SCREENTARGET_MAX_WIDTH = 55, + SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56, + SVGA_REG_MOB_MAX_SIZE = 57, + SVGA_REG_TOP = 58, /* Must be 1 more than the last register */ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */ @@ -431,7 +441,10 @@ #define SVGA_CAP_TRACES 0x00200000 #define SVGA_CAP_GMR2 0x00400000 #define SVGA_CAP_SCREEN_OBJECT_2 0x00800000 - +#define SVGA_CAP_COMMAND_BUFFERS 0x01000000 +#define SVGA_CAP_DEAD1 0x02000000 +#define SVGA_CAP_CMD_BUFFERS_2 0x04000000 +#define SVGA_CAP_GBOBJECTS 0x08000000 /* * FIFO register indices. --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/Makefile +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/Makefile @@ -6,6 +6,6 @@ vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \ - vmwgfx_surface.o vmwgfx_prime.o + vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -29,12 +29,18 @@ #include #include "vmwgfx_kms.h" +struct svga_3d_compat_cap { + SVGA3dCapsRecordHeader header; + SVGA3dCapPair pairs[SVGA3D_DEVCAP_MAX]; +}; + int vmw_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct vmw_private *dev_priv = vmw_priv(dev); struct drm_vmw_getparam_arg *param = (struct drm_vmw_getparam_arg *)data; + struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); switch (param->param) { case DRM_VMW_PARAM_NUM_STREAMS: @@ -53,13 +59,18 @@ param->value = dev_priv->fifo.capabilities; break; case DRM_VMW_PARAM_MAX_FB_SIZE: - param->value = dev_priv->vram_size; + param->value = dev_priv->prim_bb_mem; break; case DRM_VMW_PARAM_FIFO_HW_VERSION: { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; const struct vmw_fifo_state *fifo = &dev_priv->fifo; + if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) { + param->value = SVGA3D_HWVERSION_WS8_B1; + break; + } + param->value = ioread32(fifo_mem + ((fifo->capabilities & @@ -69,7 +80,30 @@ break; } case DRM_VMW_PARAM_MAX_SURF_MEMORY: - param->value = dev_priv->memory_size; + if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) && + !vmw_fp->gb_aware) + param->value = dev_priv->max_mob_pages * PAGE_SIZE / 2; + else + param->value = dev_priv->memory_size; + break; + case DRM_VMW_PARAM_3D_CAPS_SIZE: + if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) && + vmw_fp->gb_aware) + param->value = SVGA3D_DEVCAP_MAX * sizeof(uint32_t); + else if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) + param->value = sizeof(struct svga_3d_compat_cap) + + sizeof(uint32_t); + else + param->value = (SVGA_FIFO_3D_CAPS_LAST - + SVGA_FIFO_3D_CAPS + 1) * + sizeof(uint32_t); + break; + case DRM_VMW_PARAM_MAX_MOB_MEMORY: + vmw_fp->gb_aware = true; + param->value = dev_priv->max_mob_pages * PAGE_SIZE; + break; + case DRM_VMW_PARAM_MAX_MOB_SIZE: + param->value = dev_priv->max_mob_size; break; default: DRM_ERROR("Illegal vmwgfx get param request: %d\n", @@ -80,6 +114,38 @@ return 0; } +static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce, + size_t size) +{ + struct svga_3d_compat_cap *compat_cap = + (struct svga_3d_compat_cap *) bounce; + unsigned int i; + size_t pair_offset = offsetof(struct svga_3d_compat_cap, pairs); + unsigned int max_size; + + if (size < pair_offset) + return -EINVAL; + + max_size = (size - pair_offset) / sizeof(SVGA3dCapPair); + + if (max_size > SVGA3D_DEVCAP_MAX) + max_size = SVGA3D_DEVCAP_MAX; + + compat_cap->header.length = + (pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32); + compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS; + + mutex_lock(&dev_priv->hw_mutex); + for (i = 0; i < max_size; ++i) { + vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); + compat_cap->pairs[i][0] = i; + compat_cap->pairs[i][1] = vmw_read(dev_priv, SVGA_REG_DEV_CAP); + } + mutex_unlock(&dev_priv->hw_mutex); + + return 0; +} + int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -92,29 +158,58 @@ void __user *buffer = (void __user *)((unsigned long)(arg->buffer)); void *bounce; int ret; + bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS); + struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); if (unlikely(arg->pad64 != 0)) { DRM_ERROR("Illegal GET_3D_CAP argument.\n"); return -EINVAL; } - size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) << 2; + if (gb_objects && vmw_fp->gb_aware) + size = SVGA3D_DEVCAP_MAX * sizeof(uint32_t); + else if (gb_objects) + size = sizeof(struct svga_3d_compat_cap) + sizeof(uint32_t); + else + size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) * + sizeof(uint32_t); if (arg->max_size < size) size = arg->max_size; - bounce = vmalloc(size); + bounce = vzalloc(size); if (unlikely(bounce == NULL)) { DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n"); return -ENOMEM; } - fifo_mem = dev_priv->mmio_virt; - memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size); + if (gb_objects && vmw_fp->gb_aware) { + int i, num; + uint32_t *bounce32 = (uint32_t *) bounce; + + num = size / sizeof(uint32_t); + if (num > SVGA3D_DEVCAP_MAX) + num = SVGA3D_DEVCAP_MAX; + + mutex_lock(&dev_priv->hw_mutex); + for (i = 0; i < num; ++i) { + vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); + *bounce32++ = vmw_read(dev_priv, SVGA_REG_DEV_CAP); + } + mutex_unlock(&dev_priv->hw_mutex); + } else if (gb_objects) { + ret = vmw_fill_compat_cap(dev_priv, bounce, size); + if (unlikely(ret != 0)) + goto out_err; + } else { + fifo_mem = dev_priv->mmio_virt; + memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size); + } ret = copy_to_user(buffer, bounce, size); if (ret) ret = -EFAULT; +out_err: vfree(bounce); if (unlikely(ret != 0)) --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -41,7 +41,6 @@ struct ttm_prime_object prime; struct vmw_surface srf; uint32_t size; - uint32_t backup_handle; }; /** @@ -68,6 +67,14 @@ struct ttm_validate_buffer *val_buf); static int vmw_legacy_srf_create(struct vmw_resource *res); static int vmw_legacy_srf_destroy(struct vmw_resource *res); +static int vmw_gb_surface_create(struct vmw_resource *res); +static int vmw_gb_surface_bind(struct vmw_resource *res, + struct ttm_validate_buffer *val_buf); +static int vmw_gb_surface_unbind(struct vmw_resource *res, + bool readback, + struct ttm_validate_buffer *val_buf); +static int vmw_gb_surface_destroy(struct vmw_resource *res); + static const struct vmw_user_resource_conv user_surface_conv = { .object_type = VMW_RES_SURFACE, @@ -93,6 +100,18 @@ .unbind = &vmw_legacy_srf_unbind }; +static const struct vmw_res_func vmw_gb_surface_func = { + .res_type = vmw_res_surface, + .needs_backup = true, + .may_evict = true, + .type_name = "guest backed surfaces", + .backup_placement = &vmw_mob_placement, + .create = vmw_gb_surface_create, + .destroy = vmw_gb_surface_destroy, + .bind = vmw_gb_surface_bind, + .unbind = vmw_gb_surface_unbind +}; + /** * struct vmw_surface_dma - SVGA3D DMA command */ @@ -291,6 +310,11 @@ struct vmw_surface *srf; void *cmd; + if (res->func->destroy == vmw_gb_surface_destroy) { + (void) vmw_gb_surface_destroy(res); + return; + } + if (res->id != -1) { cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size()); @@ -549,12 +573,15 @@ struct vmw_resource *res = &srf->res; BUG_ON(res_free == NULL); - (void) vmw_3d_resource_inc(dev_priv, false); + if (!dev_priv->has_mob) + (void) vmw_3d_resource_inc(dev_priv, false); ret = vmw_resource_init(dev_priv, res, true, res_free, + (dev_priv->has_mob) ? &vmw_gb_surface_func : &vmw_legacy_surface_func); if (unlikely(ret != 0)) { - vmw_3d_resource_dec(dev_priv, false); + if (!dev_priv->has_mob) + vmw_3d_resource_dec(dev_priv, false); res_free(res); return ret; } @@ -750,7 +777,7 @@ srf->base_size = *srf->sizes; srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; - srf->multisample_count = 1; + srf->multisample_count = 0; cur_bo_offset = 0; cur_offset = srf->offsets; @@ -803,6 +830,24 @@ if (unlikely(ret != 0)) goto out_unlock; + /* + * A gb-aware client referencing a shared surface will + * expect a backup buffer to be present. + */ + if (dev_priv->has_mob && req->shareable) { + uint32_t backup_handle; + + ret = vmw_user_dmabuf_alloc(dev_priv, tfile, + res->backup_size, + true, + &backup_handle, + &res->backup); + if (unlikely(ret != 0)) { + vmw_resource_unreference(&res); + goto out_unlock; + } + } + tmp = vmw_resource_reference(&srf->res); ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, req->shareable, VMW_RES_SURFACE, @@ -843,6 +888,7 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct vmw_private *dev_priv = vmw_priv(dev); union drm_vmw_surface_reference_arg *arg = (union drm_vmw_surface_reference_arg *)data; struct drm_vmw_surface_arg *req = &arg->req; @@ -854,7 +900,7 @@ struct ttm_base_object *base; int ret = -EINVAL; - base = ttm_base_object_lookup(tfile, req->sid); + base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); if (unlikely(base == NULL)) { DRM_ERROR("Could not find surface to reference.\n"); return -EINVAL; @@ -880,8 +926,8 @@ rep->size_addr; if (user_sizes) - ret = copy_to_user(user_sizes, srf->sizes, - srf->num_sizes * sizeof(*srf->sizes)); + ret = copy_to_user(user_sizes, &srf->base_size, + sizeof(srf->base_size)); if (unlikely(ret != 0)) { DRM_ERROR("copy_to_user failed %p %u\n", user_sizes, srf->num_sizes); @@ -892,4 +938,437 @@ ttm_base_object_unref(&base); return ret; +} + +/** + * vmw_surface_define_encode - Encode a surface_define command. + * + * @srf: Pointer to a struct vmw_surface object. + * @cmd_space: Pointer to memory area in which the commands should be encoded. + */ +static int vmw_gb_surface_create(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct vmw_surface *srf = vmw_res_to_srf(res); + uint32_t cmd_len, submit_len; + int ret; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDefineGBSurface body; + } *cmd; + + if (likely(res->id != -1)) + return 0; + + (void) vmw_3d_resource_inc(dev_priv, false); + ret = vmw_resource_alloc_id(res); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to allocate a surface id.\n"); + goto out_no_id; + } + + if (unlikely(res->id >= VMWGFX_NUM_GB_SURFACE)) { + ret = -EBUSY; + goto out_no_fifo; + } + + cmd_len = sizeof(cmd->body); + submit_len = sizeof(*cmd); + cmd = vmw_fifo_reserve(dev_priv, submit_len); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for surface " + "creation.\n"); + ret = -ENOMEM; + goto out_no_fifo; + } + + cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SURFACE; + cmd->header.size = cmd_len; + cmd->body.sid = srf->res.id; + cmd->body.surfaceFlags = srf->flags; + cmd->body.format = cpu_to_le32(srf->format); + cmd->body.numMipLevels = srf->mip_levels[0]; + cmd->body.multisampleCount = srf->multisample_count; + cmd->body.autogenFilter = srf->autogen_filter; + cmd->body.size.width = srf->base_size.width; + cmd->body.size.height = srf->base_size.height; + cmd->body.size.depth = srf->base_size.depth; + vmw_fifo_commit(dev_priv, submit_len); + + return 0; + +out_no_fifo: + vmw_resource_release_id(res); +out_no_id: + vmw_3d_resource_dec(dev_priv, false); + return ret; +} + + +static int vmw_gb_surface_bind(struct vmw_resource *res, + struct ttm_validate_buffer *val_buf) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBSurface body; + } *cmd1; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBSurface body; + } *cmd2; + uint32_t submit_size; + struct ttm_buffer_object *bo = val_buf->bo; + + BUG_ON(bo->mem.mem_type != VMW_PL_MOB); + + submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0); + + cmd1 = vmw_fifo_reserve(dev_priv, submit_size); + if (unlikely(cmd1 == NULL)) { + DRM_ERROR("Failed reserving FIFO space for surface " + "binding.\n"); + return -ENOMEM; + } + + cmd1->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; + cmd1->header.size = sizeof(cmd1->body); + cmd1->body.sid = res->id; + cmd1->body.mobid = bo->mem.start; + if (res->backup_dirty) { + cmd2 = (void *) &cmd1[1]; + cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE; + cmd2->header.size = sizeof(cmd2->body); + cmd2->body.sid = res->id; + res->backup_dirty = false; + } + vmw_fifo_commit(dev_priv, submit_size); + + return 0; +} + +static int vmw_gb_surface_unbind(struct vmw_resource *res, + bool readback, + struct ttm_validate_buffer *val_buf) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct ttm_buffer_object *bo = val_buf->bo; + struct vmw_fence_obj *fence; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdReadbackGBSurface body; + } *cmd1; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdInvalidateGBSurface body; + } *cmd2; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBSurface body; + } *cmd3; + uint32_t submit_size; + uint8_t *cmd; + + + BUG_ON(bo->mem.mem_type != VMW_PL_MOB); + + submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2)); + cmd = vmw_fifo_reserve(dev_priv, submit_size); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for surface " + "unbinding.\n"); + return -ENOMEM; + } + + if (readback) { + cmd1 = (void *) cmd; + cmd1->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE; + cmd1->header.size = sizeof(cmd1->body); + cmd1->body.sid = res->id; + cmd3 = (void *) &cmd1[1]; + } else { + cmd2 = (void *) cmd; + cmd2->header.id = SVGA_3D_CMD_INVALIDATE_GB_SURFACE; + cmd2->header.size = sizeof(cmd2->body); + cmd2->body.sid = res->id; + cmd3 = (void *) &cmd2[1]; + } + + cmd3->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; + cmd3->header.size = sizeof(cmd3->body); + cmd3->body.sid = res->id; + cmd3->body.mobid = SVGA3D_INVALID_ID; + + vmw_fifo_commit(dev_priv, submit_size); + + /* + * Create a fence object and fence the backup buffer. + */ + + (void) vmw_execbuf_fence_commands(NULL, dev_priv, + &fence, NULL); + + vmw_fence_single_bo(val_buf->bo, fence); + + if (likely(fence != NULL)) + vmw_fence_obj_unreference(&fence); + + return 0; +} + +static int vmw_gb_surface_destroy(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDestroyGBSurface body; + } *cmd; + + if (likely(res->id == -1)) + return 0; + + mutex_lock(&dev_priv->binding_mutex); + vmw_context_binding_res_list_scrub(&res->binding_head); + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for surface " + "destruction.\n"); + mutex_unlock(&dev_priv->binding_mutex); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SURFACE; + cmd->header.size = sizeof(cmd->body); + cmd->body.sid = res->id; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + mutex_unlock(&dev_priv->binding_mutex); + vmw_resource_release_id(res); + vmw_3d_resource_dec(dev_priv, false); + + return 0; +} + +/** + * vmw_gb_surface_define_ioctl - Ioctl function implementing + * the user surface define functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_user_surface *user_srf; + struct vmw_surface *srf; + struct vmw_resource *res; + struct vmw_resource *tmp; + union drm_vmw_gb_surface_create_arg *arg = + (union drm_vmw_gb_surface_create_arg *)data; + struct drm_vmw_gb_surface_create_req *req = &arg->req; + struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + int ret; + uint32_t size; + struct vmw_master *vmaster = vmw_master(file_priv->master); + const struct svga3d_surface_desc *desc; + uint32_t backup_handle; + + if (unlikely(vmw_user_surface_size == 0)) + vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + + 128; + + size = vmw_user_surface_size + 128; + + desc = svga3dsurface_get_desc(req->format); + if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) { + DRM_ERROR("Invalid surface format for surface creation.\n"); + return -EINVAL; + } + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), + size, false, true); + if (unlikely(ret != 0)) { + if (ret != -ERESTARTSYS) + DRM_ERROR("Out of graphics memory for surface" + " creation.\n"); + goto out_unlock; + } + + user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); + if (unlikely(user_srf == NULL)) { + ret = -ENOMEM; + goto out_no_user_srf; + } + + srf = &user_srf->srf; + res = &srf->res; + + srf->flags = req->svga3d_flags; + srf->format = req->format; + srf->scanout = req->drm_surface_flags & drm_vmw_surface_flag_scanout; + srf->mip_levels[0] = req->mip_levels; + srf->num_sizes = 1; + srf->sizes = NULL; + srf->offsets = NULL; + user_srf->size = size; + srf->base_size = req->base_size; + srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; + srf->multisample_count = req->multisample_count; + res->backup_size = svga3dsurface_get_serialized_size + (srf->format, srf->base_size, srf->mip_levels[0], + srf->flags & SVGA3D_SURFACE_CUBEMAP); + + user_srf->prime.base.shareable = false; + user_srf->prime.base.tfile = NULL; + + /** + * From this point, the generic resource management functions + * destroy the object on failure. + */ + + ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); + if (unlikely(ret != 0)) + goto out_unlock; + + if (req->buffer_handle != SVGA3D_INVALID_ID) { + ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle, + &res->backup); + } else if (req->drm_surface_flags & + drm_vmw_surface_flag_create_buffer) + ret = vmw_user_dmabuf_alloc(dev_priv, tfile, + res->backup_size, + req->drm_surface_flags & + drm_vmw_surface_flag_shareable, + &backup_handle, + &res->backup); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&res); + goto out_unlock; + } + + tmp = vmw_resource_reference(&srf->res); + ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, + req->drm_surface_flags & + drm_vmw_surface_flag_shareable, + VMW_RES_SURFACE, + &vmw_user_surface_base_release, NULL); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&tmp); + vmw_resource_unreference(&res); + goto out_unlock; + } + + rep->handle = user_srf->prime.base.hash.key; + rep->backup_size = res->backup_size; + if (res->backup) { + rep->buffer_map_handle = + drm_vma_node_offset_addr(&res->backup->base.vma_node); + rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; + rep->buffer_handle = backup_handle; + } else { + rep->buffer_map_handle = 0; + rep->buffer_size = 0; + rep->buffer_handle = SVGA3D_INVALID_ID; + } + + vmw_resource_unreference(&res); + + ttm_read_unlock(&vmaster->lock); + return 0; +out_no_user_srf: + ttm_mem_global_free(vmw_mem_glob(dev_priv), size); +out_unlock: + ttm_read_unlock(&vmaster->lock); + return ret; +} + +/** + * vmw_gb_surface_reference_ioctl - Ioctl function implementing + * the user surface reference functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + union drm_vmw_gb_surface_reference_arg *arg = + (union drm_vmw_gb_surface_reference_arg *)data; + struct drm_vmw_surface_arg *req = &arg->req; + struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_surface *srf; + struct vmw_user_surface *user_srf; + struct ttm_base_object *base; + uint32_t backup_handle; + int ret = -EINVAL; + + base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); + if (unlikely(base == NULL)) { + DRM_ERROR("Could not find surface to reference.\n"); + return -EINVAL; + } + + if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) + goto out_bad_resource; + + user_srf = container_of(base, struct vmw_user_surface, prime.base); + srf = &user_srf->srf; + if (srf->res.backup == NULL) { + DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); + goto out_bad_resource; + } + + ret = ttm_ref_object_add(tfile, &user_srf->prime.base, + TTM_REF_USAGE, NULL); + if (unlikely(ret != 0)) { + DRM_ERROR("Could not add a reference to a GB surface.\n"); + goto out_bad_resource; + } + + mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ + ret = vmw_user_dmabuf_reference(tfile, srf->res.backup, + &backup_handle); + mutex_unlock(&dev_priv->cmdbuf_mutex); + + if (unlikely(ret != 0)) { + DRM_ERROR("Could not add a reference to a GB surface " + "backup buffer.\n"); + (void) ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, + req->sid, + TTM_REF_USAGE); + goto out_bad_resource; + } + + rep->creq.svga3d_flags = srf->flags; + rep->creq.format = srf->format; + rep->creq.mip_levels = srf->mip_levels[0]; + rep->creq.drm_surface_flags = 0; + rep->creq.multisample_count = srf->multisample_count; + rep->creq.autogen_filter = srf->autogen_filter; + rep->creq.buffer_handle = backup_handle; + rep->creq.base_size = srf->base_size; + rep->crep.handle = user_srf->prime.base.hash.key; + rep->crep.backup_size = srf->res.backup_size; + rep->crep.buffer_handle = backup_handle; + rep->crep.buffer_map_handle = + drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); + rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; + +out_bad_resource: + ttm_base_object_unref(&base); + + return ret; } --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -32,12 +32,30 @@ struct vmw_user_context { struct ttm_base_object base; struct vmw_resource res; + struct vmw_ctx_binding_state cbs; }; + + +typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool); + static void vmw_user_context_free(struct vmw_resource *res); static struct vmw_resource * vmw_user_context_base_to_res(struct ttm_base_object *base); +static int vmw_gb_context_create(struct vmw_resource *res); +static int vmw_gb_context_bind(struct vmw_resource *res, + struct ttm_validate_buffer *val_buf); +static int vmw_gb_context_unbind(struct vmw_resource *res, + bool readback, + struct ttm_validate_buffer *val_buf); +static int vmw_gb_context_destroy(struct vmw_resource *res); +static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind); +static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi, + bool rebind); +static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind); +static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs); +static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs); static uint64_t vmw_user_context_size; static const struct vmw_user_resource_conv user_context_conv = { @@ -62,6 +80,23 @@ .unbind = NULL }; +static const struct vmw_res_func vmw_gb_context_func = { + .res_type = vmw_res_context, + .needs_backup = true, + .may_evict = true, + .type_name = "guest backed contexts", + .backup_placement = &vmw_mob_placement, + .create = vmw_gb_context_create, + .destroy = vmw_gb_context_destroy, + .bind = vmw_gb_context_bind, + .unbind = vmw_gb_context_unbind +}; + +static const vmw_scrub_func vmw_scrub_funcs[vmw_ctx_binding_max] = { + [vmw_ctx_binding_shader] = vmw_context_scrub_shader, + [vmw_ctx_binding_rt] = vmw_context_scrub_render_target, + [vmw_ctx_binding_tex] = vmw_context_scrub_texture }; + /** * Context management: */ @@ -76,6 +111,20 @@ } *cmd; + if (res->func->destroy == vmw_gb_context_destroy) { + mutex_lock(&dev_priv->cmdbuf_mutex); + mutex_lock(&dev_priv->binding_mutex); + (void) vmw_context_binding_state_kill + (&container_of(res, struct vmw_user_context, res)->cbs); + (void) vmw_gb_context_destroy(res); + if (dev_priv->pinned_bo != NULL && + !dev_priv->query_cid_valid) + __vmw_execbuf_release_pinned_bo(dev_priv, NULL); + mutex_unlock(&dev_priv->binding_mutex); + mutex_unlock(&dev_priv->cmdbuf_mutex); + return; + } + vmw_execbuf_release_pinned_bo(dev_priv); cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); if (unlikely(cmd == NULL)) { @@ -92,6 +141,33 @@ vmw_3d_resource_dec(dev_priv, false); } +static int vmw_gb_context_init(struct vmw_private *dev_priv, + struct vmw_resource *res, + void (*res_free) (struct vmw_resource *res)) +{ + int ret; + struct vmw_user_context *uctx = + container_of(res, struct vmw_user_context, res); + + ret = vmw_resource_init(dev_priv, res, true, + res_free, &vmw_gb_context_func); + res->backup_size = SVGA3D_CONTEXT_DATA_SIZE; + + if (unlikely(ret != 0)) { + if (res_free) + res_free(res); + else + kfree(res); + return ret; + } + + memset(&uctx->cbs, 0, sizeof(uctx->cbs)); + INIT_LIST_HEAD(&uctx->cbs.list); + + vmw_resource_activate(res, vmw_hw_context_destroy); + return 0; +} + static int vmw_context_init(struct vmw_private *dev_priv, struct vmw_resource *res, void (*res_free) (struct vmw_resource *res)) @@ -103,6 +179,9 @@ SVGA3dCmdDefineContext body; } *cmd; + if (dev_priv->has_mob) + return vmw_gb_context_init(dev_priv, res, res_free); + ret = vmw_resource_init(dev_priv, res, false, res_free, &vmw_legacy_context_func); @@ -154,6 +233,180 @@ return (ret == 0) ? res : NULL; } + +static int vmw_gb_context_create(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + int ret; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDefineGBContext body; + } *cmd; + + if (likely(res->id != -1)) + return 0; + + ret = vmw_resource_alloc_id(res); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to allocate a context id.\n"); + goto out_no_id; + } + + if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) { + ret = -EBUSY; + goto out_no_fifo; + } + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for context " + "creation.\n"); + ret = -ENOMEM; + goto out_no_fifo; + } + + cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = res->id; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + (void) vmw_3d_resource_inc(dev_priv, false); + + return 0; + +out_no_fifo: + vmw_resource_release_id(res); +out_no_id: + return ret; +} + +static int vmw_gb_context_bind(struct vmw_resource *res, + struct ttm_validate_buffer *val_buf) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBContext body; + } *cmd; + struct ttm_buffer_object *bo = val_buf->bo; + + BUG_ON(bo->mem.mem_type != VMW_PL_MOB); + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for context " + "binding.\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = res->id; + cmd->body.mobid = bo->mem.start; + cmd->body.validContents = res->backup_dirty; + res->backup_dirty = false; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + +static int vmw_gb_context_unbind(struct vmw_resource *res, + bool readback, + struct ttm_validate_buffer *val_buf) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct ttm_buffer_object *bo = val_buf->bo; + struct vmw_fence_obj *fence; + struct vmw_user_context *uctx = + container_of(res, struct vmw_user_context, res); + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdReadbackGBContext body; + } *cmd1; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBContext body; + } *cmd2; + uint32_t submit_size; + uint8_t *cmd; + + + BUG_ON(bo->mem.mem_type != VMW_PL_MOB); + + mutex_lock(&dev_priv->binding_mutex); + vmw_context_binding_state_scrub(&uctx->cbs); + + submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0); + + cmd = vmw_fifo_reserve(dev_priv, submit_size); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for context " + "unbinding.\n"); + mutex_unlock(&dev_priv->binding_mutex); + return -ENOMEM; + } + + cmd2 = (void *) cmd; + if (readback) { + cmd1 = (void *) cmd; + cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT; + cmd1->header.size = sizeof(cmd1->body); + cmd1->body.cid = res->id; + cmd2 = (void *) (&cmd1[1]); + } + cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; + cmd2->header.size = sizeof(cmd2->body); + cmd2->body.cid = res->id; + cmd2->body.mobid = SVGA3D_INVALID_ID; + + vmw_fifo_commit(dev_priv, submit_size); + mutex_unlock(&dev_priv->binding_mutex); + + /* + * Create a fence object and fence the backup buffer. + */ + + (void) vmw_execbuf_fence_commands(NULL, dev_priv, + &fence, NULL); + + vmw_fence_single_bo(bo, fence); + + if (likely(fence != NULL)) + vmw_fence_obj_unreference(&fence); + + return 0; +} + +static int vmw_gb_context_destroy(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDestroyGBContext body; + } *cmd; + + if (likely(res->id == -1)) + return 0; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for context " + "destruction.\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = res->id; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + if (dev_priv->query_cid == res->id) + dev_priv->query_cid_valid = false; + vmw_resource_release_id(res); + vmw_3d_resource_dec(dev_priv, false); + + return 0; +} + /** * User-space context management: */ @@ -272,3 +525,380 @@ return ret; } + +/** + * vmw_context_scrub_shader - scrub a shader binding from a context. + * + * @bi: single binding information. + * @rebind: Whether to issue a bind instead of scrub command. + */ +static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind) +{ + struct vmw_private *dev_priv = bi->ctx->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdSetShader body; + } *cmd; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for shader " + "unbinding.\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_SET_SHADER; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = bi->ctx->id; + cmd->body.type = bi->i1.shader_type; + cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + +/** + * vmw_context_scrub_render_target - scrub a render target binding + * from a context. + * + * @bi: single binding information. + * @rebind: Whether to issue a bind instead of scrub command. + */ +static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi, + bool rebind) +{ + struct vmw_private *dev_priv = bi->ctx->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdSetRenderTarget body; + } *cmd; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for render target " + "unbinding.\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_SETRENDERTARGET; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = bi->ctx->id; + cmd->body.type = bi->i1.rt_type; + cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); + cmd->body.target.face = 0; + cmd->body.target.mipmap = 0; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + +/** + * vmw_context_scrub_texture - scrub a texture binding from a context. + * + * @bi: single binding information. + * @rebind: Whether to issue a bind instead of scrub command. + * + * TODO: Possibly complement this function with a function that takes + * a list of texture bindings and combines them to a single command. + */ +static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, + bool rebind) +{ + struct vmw_private *dev_priv = bi->ctx->dev_priv; + struct { + SVGA3dCmdHeader header; + struct { + SVGA3dCmdSetTextureState c; + SVGA3dTextureState s1; + } body; + } *cmd; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for texture " + "unbinding.\n"); + return -ENOMEM; + } + + + cmd->header.id = SVGA_3D_CMD_SETTEXTURESTATE; + cmd->header.size = sizeof(cmd->body); + cmd->body.c.cid = bi->ctx->id; + cmd->body.s1.stage = bi->i1.texture_stage; + cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE; + cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + +/** + * vmw_context_binding_drop: Stop tracking a context binding + * + * @cb: Pointer to binding tracker storage. + * + * Stops tracking a context binding, and re-initializes its storage. + * Typically used when the context binding is replaced with a binding to + * another (or the same, for that matter) resource. + */ +static void vmw_context_binding_drop(struct vmw_ctx_binding *cb) +{ + list_del(&cb->ctx_list); + if (!list_empty(&cb->res_list)) + list_del(&cb->res_list); + cb->bi.ctx = NULL; +} + +/** + * vmw_context_binding_add: Start tracking a context binding + * + * @cbs: Pointer to the context binding state tracker. + * @bi: Information about the binding to track. + * + * Performs basic checks on the binding to make sure arguments are within + * bounds and then starts tracking the binding in the context binding + * state structure @cbs. + */ +int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs, + const struct vmw_ctx_bindinfo *bi) +{ + struct vmw_ctx_binding *loc; + + switch (bi->bt) { + case vmw_ctx_binding_rt: + if (unlikely((unsigned)bi->i1.rt_type >= SVGA3D_RT_MAX)) { + DRM_ERROR("Illegal render target type %u.\n", + (unsigned) bi->i1.rt_type); + return -EINVAL; + } + loc = &cbs->render_targets[bi->i1.rt_type]; + break; + case vmw_ctx_binding_tex: + if (unlikely((unsigned)bi->i1.texture_stage >= + SVGA3D_NUM_TEXTURE_UNITS)) { + DRM_ERROR("Illegal texture/sampler unit %u.\n", + (unsigned) bi->i1.texture_stage); + return -EINVAL; + } + loc = &cbs->texture_units[bi->i1.texture_stage]; + break; + case vmw_ctx_binding_shader: + if (unlikely((unsigned)bi->i1.shader_type >= + SVGA3D_SHADERTYPE_MAX)) { + DRM_ERROR("Illegal shader type %u.\n", + (unsigned) bi->i1.shader_type); + return -EINVAL; + } + loc = &cbs->shaders[bi->i1.shader_type]; + break; + default: + BUG(); + } + + if (loc->bi.ctx != NULL) + vmw_context_binding_drop(loc); + + loc->bi = *bi; + loc->bi.scrubbed = false; + list_add_tail(&loc->ctx_list, &cbs->list); + INIT_LIST_HEAD(&loc->res_list); + + return 0; +} + +/** + * vmw_context_binding_transfer: Transfer a context binding tracking entry. + * + * @cbs: Pointer to the persistent context binding state tracker. + * @bi: Information about the binding to track. + * + */ +static void vmw_context_binding_transfer(struct vmw_ctx_binding_state *cbs, + const struct vmw_ctx_bindinfo *bi) +{ + struct vmw_ctx_binding *loc; + + switch (bi->bt) { + case vmw_ctx_binding_rt: + loc = &cbs->render_targets[bi->i1.rt_type]; + break; + case vmw_ctx_binding_tex: + loc = &cbs->texture_units[bi->i1.texture_stage]; + break; + case vmw_ctx_binding_shader: + loc = &cbs->shaders[bi->i1.shader_type]; + break; + default: + BUG(); + } + + if (loc->bi.ctx != NULL) + vmw_context_binding_drop(loc); + + if (bi->res != NULL) { + loc->bi = *bi; + list_add_tail(&loc->ctx_list, &cbs->list); + list_add_tail(&loc->res_list, &bi->res->binding_head); + } +} + +/** + * vmw_context_binding_kill - Kill a binding on the device + * and stop tracking it. + * + * @cb: Pointer to binding tracker storage. + * + * Emits FIFO commands to scrub a binding represented by @cb. + * Then stops tracking the binding and re-initializes its storage. + */ +static void vmw_context_binding_kill(struct vmw_ctx_binding *cb) +{ + if (!cb->bi.scrubbed) { + (void) vmw_scrub_funcs[cb->bi.bt](&cb->bi, false); + cb->bi.scrubbed = true; + } + vmw_context_binding_drop(cb); +} + +/** + * vmw_context_binding_state_kill - Kill all bindings associated with a + * struct vmw_ctx_binding state structure, and re-initialize the structure. + * + * @cbs: Pointer to the context binding state tracker. + * + * Emits commands to scrub all bindings associated with the + * context binding state tracker. Then re-initializes the whole structure. + */ +static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs) +{ + struct vmw_ctx_binding *entry, *next; + + list_for_each_entry_safe(entry, next, &cbs->list, ctx_list) + vmw_context_binding_kill(entry); +} + +/** + * vmw_context_binding_state_scrub - Scrub all bindings associated with a + * struct vmw_ctx_binding state structure. + * + * @cbs: Pointer to the context binding state tracker. + * + * Emits commands to scrub all bindings associated with the + * context binding state tracker. + */ +static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs) +{ + struct vmw_ctx_binding *entry; + + list_for_each_entry(entry, &cbs->list, ctx_list) { + if (!entry->bi.scrubbed) { + (void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false); + entry->bi.scrubbed = true; + } + } +} + +/** + * vmw_context_binding_res_list_kill - Kill all bindings on a + * resource binding list + * + * @head: list head of resource binding list + * + * Kills all bindings associated with a specific resource. Typically + * called before the resource is destroyed. + */ +void vmw_context_binding_res_list_kill(struct list_head *head) +{ + struct vmw_ctx_binding *entry, *next; + + list_for_each_entry_safe(entry, next, head, res_list) + vmw_context_binding_kill(entry); +} + +/** + * vmw_context_binding_res_list_scrub - Scrub all bindings on a + * resource binding list + * + * @head: list head of resource binding list + * + * Scrub all bindings associated with a specific resource. Typically + * called before the resource is evicted. + */ +void vmw_context_binding_res_list_scrub(struct list_head *head) +{ + struct vmw_ctx_binding *entry; + + list_for_each_entry(entry, head, res_list) { + if (!entry->bi.scrubbed) { + (void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false); + entry->bi.scrubbed = true; + } + } +} + +/** + * vmw_context_binding_state_transfer - Commit staged binding info + * + * @ctx: Pointer to context to commit the staged binding info to. + * @from: Staged binding info built during execbuf. + * + * Transfers binding info from a temporary structure to the persistent + * structure in the context. This can be done once commands + */ +void vmw_context_binding_state_transfer(struct vmw_resource *ctx, + struct vmw_ctx_binding_state *from) +{ + struct vmw_user_context *uctx = + container_of(ctx, struct vmw_user_context, res); + struct vmw_ctx_binding *entry, *next; + + list_for_each_entry_safe(entry, next, &from->list, ctx_list) + vmw_context_binding_transfer(&uctx->cbs, &entry->bi); +} + +/** + * vmw_context_rebind_all - Rebind all scrubbed bindings of a context + * + * @ctx: The context resource + * + * Walks through the context binding list and rebinds all scrubbed + * resources. + */ +int vmw_context_rebind_all(struct vmw_resource *ctx) +{ + struct vmw_ctx_binding *entry; + struct vmw_user_context *uctx = + container_of(ctx, struct vmw_user_context, res); + struct vmw_ctx_binding_state *cbs = &uctx->cbs; + int ret; + + list_for_each_entry(entry, &cbs->list, ctx_list) { + if (likely(!entry->bi.scrubbed)) + continue; + + if (WARN_ON(entry->bi.res == NULL || entry->bi.res->id == + SVGA3D_INVALID_ID)) + continue; + + ret = vmw_scrub_funcs[entry->bi.bt](&entry->bi, true); + if (unlikely(ret != 0)) + return ret; + + entry->bi.scrubbed = false; + } + + return 0; +} + +/** + * vmw_context_binding_list - Return a list of context bindings + * + * @ctx: The context resource + * + * Returns the current list of bindings of the given context. Note that + * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked. + */ +struct list_head *vmw_context_binding_list(struct vmw_resource *ctx) +{ + return &(container_of(ctx, struct vmw_user_context, res)->cbs.list); +} --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -0,0 +1,812 @@ +/************************************************************************** + * + * Copyright © 2009-2012 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "vmwgfx_drv.h" +#include "vmwgfx_resource_priv.h" +#include "ttm/ttm_placement.h" + +#define VMW_COMPAT_SHADER_HT_ORDER 12 + +struct vmw_shader { + struct vmw_resource res; + SVGA3dShaderType type; + uint32_t size; +}; + +struct vmw_user_shader { + struct ttm_base_object base; + struct vmw_shader shader; +}; + +/** + * enum vmw_compat_shader_state - Staging state for compat shaders + */ +enum vmw_compat_shader_state { + VMW_COMPAT_COMMITED, + VMW_COMPAT_ADD, + VMW_COMPAT_DEL +}; + +/** + * struct vmw_compat_shader - Metadata for compat shaders. + * + * @handle: The TTM handle of the guest backed shader. + * @tfile: The struct ttm_object_file the guest backed shader is registered + * with. + * @hash: Hash item for lookup. + * @head: List head for staging lists or the compat shader manager list. + * @state: Staging state. + * + * The structure is protected by the cmdbuf lock. + */ +struct vmw_compat_shader { + u32 handle; + struct ttm_object_file *tfile; + struct drm_hash_item hash; + struct list_head head; + enum vmw_compat_shader_state state; +}; + +/** + * struct vmw_compat_shader_manager - Compat shader manager. + * + * @shaders: Hash table containing staged and commited compat shaders + * @list: List of commited shaders. + * @dev_priv: Pointer to a device private structure. + * + * @shaders and @list are protected by the cmdbuf mutex for now. + */ +struct vmw_compat_shader_manager { + struct drm_open_hash shaders; + struct list_head list; + struct vmw_private *dev_priv; +}; + +static void vmw_user_shader_free(struct vmw_resource *res); +static struct vmw_resource * +vmw_user_shader_base_to_res(struct ttm_base_object *base); + +static int vmw_gb_shader_create(struct vmw_resource *res); +static int vmw_gb_shader_bind(struct vmw_resource *res, + struct ttm_validate_buffer *val_buf); +static int vmw_gb_shader_unbind(struct vmw_resource *res, + bool readback, + struct ttm_validate_buffer *val_buf); +static int vmw_gb_shader_destroy(struct vmw_resource *res); + +static uint64_t vmw_user_shader_size; + +static const struct vmw_user_resource_conv user_shader_conv = { + .object_type = VMW_RES_SHADER, + .base_obj_to_res = vmw_user_shader_base_to_res, + .res_free = vmw_user_shader_free +}; + +const struct vmw_user_resource_conv *user_shader_converter = + &user_shader_conv; + + +static const struct vmw_res_func vmw_gb_shader_func = { + .res_type = vmw_res_shader, + .needs_backup = true, + .may_evict = true, + .type_name = "guest backed shaders", + .backup_placement = &vmw_mob_placement, + .create = vmw_gb_shader_create, + .destroy = vmw_gb_shader_destroy, + .bind = vmw_gb_shader_bind, + .unbind = vmw_gb_shader_unbind +}; + +/** + * Shader management: + */ + +static inline struct vmw_shader * +vmw_res_to_shader(struct vmw_resource *res) +{ + return container_of(res, struct vmw_shader, res); +} + +static void vmw_hw_shader_destroy(struct vmw_resource *res) +{ + (void) vmw_gb_shader_destroy(res); +} + +static int vmw_gb_shader_init(struct vmw_private *dev_priv, + struct vmw_resource *res, + uint32_t size, + uint64_t offset, + SVGA3dShaderType type, + struct vmw_dma_buffer *byte_code, + void (*res_free) (struct vmw_resource *res)) +{ + struct vmw_shader *shader = vmw_res_to_shader(res); + int ret; + + ret = vmw_resource_init(dev_priv, res, true, + res_free, &vmw_gb_shader_func); + + + if (unlikely(ret != 0)) { + if (res_free) + res_free(res); + else + kfree(res); + return ret; + } + + res->backup_size = size; + if (byte_code) { + res->backup = vmw_dmabuf_reference(byte_code); + res->backup_offset = offset; + } + shader->size = size; + shader->type = type; + + vmw_resource_activate(res, vmw_hw_shader_destroy); + return 0; +} + +static int vmw_gb_shader_create(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct vmw_shader *shader = vmw_res_to_shader(res); + int ret; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDefineGBShader body; + } *cmd; + + if (likely(res->id != -1)) + return 0; + + ret = vmw_resource_alloc_id(res); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to allocate a shader id.\n"); + goto out_no_id; + } + + if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) { + ret = -EBUSY; + goto out_no_fifo; + } + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for shader " + "creation.\n"); + ret = -ENOMEM; + goto out_no_fifo; + } + + cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER; + cmd->header.size = sizeof(cmd->body); + cmd->body.shid = res->id; + cmd->body.type = shader->type; + cmd->body.sizeInBytes = shader->size; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + (void) vmw_3d_resource_inc(dev_priv, false); + + return 0; + +out_no_fifo: + vmw_resource_release_id(res); +out_no_id: + return ret; +} + +static int vmw_gb_shader_bind(struct vmw_resource *res, + struct ttm_validate_buffer *val_buf) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBShader body; + } *cmd; + struct ttm_buffer_object *bo = val_buf->bo; + + BUG_ON(bo->mem.mem_type != VMW_PL_MOB); + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for shader " + "binding.\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; + cmd->header.size = sizeof(cmd->body); + cmd->body.shid = res->id; + cmd->body.mobid = bo->mem.start; + cmd->body.offsetInBytes = 0; + res->backup_dirty = false; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + +static int vmw_gb_shader_unbind(struct vmw_resource *res, + bool readback, + struct ttm_validate_buffer *val_buf) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBShader body; + } *cmd; + struct vmw_fence_obj *fence; + + BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB); + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for shader " + "unbinding.\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; + cmd->header.size = sizeof(cmd->body); + cmd->body.shid = res->id; + cmd->body.mobid = SVGA3D_INVALID_ID; + cmd->body.offsetInBytes = 0; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + /* + * Create a fence object and fence the backup buffer. + */ + + (void) vmw_execbuf_fence_commands(NULL, dev_priv, + &fence, NULL); + + vmw_fence_single_bo(val_buf->bo, fence); + + if (likely(fence != NULL)) + vmw_fence_obj_unreference(&fence); + + return 0; +} + +static int vmw_gb_shader_destroy(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDestroyGBShader body; + } *cmd; + + if (likely(res->id == -1)) + return 0; + + mutex_lock(&dev_priv->binding_mutex); + vmw_context_binding_res_list_scrub(&res->binding_head); + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for shader " + "destruction.\n"); + mutex_unlock(&dev_priv->binding_mutex); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER; + cmd->header.size = sizeof(cmd->body); + cmd->body.shid = res->id; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + mutex_unlock(&dev_priv->binding_mutex); + vmw_resource_release_id(res); + vmw_3d_resource_dec(dev_priv, false); + + return 0; +} + +/** + * User-space shader management: + */ + +static struct vmw_resource * +vmw_user_shader_base_to_res(struct ttm_base_object *base) +{ + return &(container_of(base, struct vmw_user_shader, base)-> + shader.res); +} + +static void vmw_user_shader_free(struct vmw_resource *res) +{ + struct vmw_user_shader *ushader = + container_of(res, struct vmw_user_shader, shader.res); + struct vmw_private *dev_priv = res->dev_priv; + + ttm_base_object_kfree(ushader, base); + ttm_mem_global_free(vmw_mem_glob(dev_priv), + vmw_user_shader_size); +} + +/** + * This function is called when user space has no more references on the + * base object. It releases the base-object's reference on the resource object. + */ + +static void vmw_user_shader_base_release(struct ttm_base_object **p_base) +{ + struct ttm_base_object *base = *p_base; + struct vmw_resource *res = vmw_user_shader_base_to_res(base); + + *p_base = NULL; + vmw_resource_unreference(&res); +} + +int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + + return ttm_ref_object_base_unref(tfile, arg->handle, + TTM_REF_USAGE); +} + +static int vmw_shader_alloc(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buffer, + size_t shader_size, + size_t offset, + SVGA3dShaderType shader_type, + struct ttm_object_file *tfile, + u32 *handle) +{ + struct vmw_user_shader *ushader; + struct vmw_resource *res, *tmp; + int ret; + + /* + * Approximate idr memory usage with 128 bytes. It will be limited + * by maximum number_of shaders anyway. + */ + if (unlikely(vmw_user_shader_size == 0)) + vmw_user_shader_size = + ttm_round_pot(sizeof(struct vmw_user_shader)) + 128; + + ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), + vmw_user_shader_size, + false, true); + if (unlikely(ret != 0)) { + if (ret != -ERESTARTSYS) + DRM_ERROR("Out of graphics memory for shader " + "creation.\n"); + goto out; + } + + ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); + if (unlikely(ushader == NULL)) { + ttm_mem_global_free(vmw_mem_glob(dev_priv), + vmw_user_shader_size); + ret = -ENOMEM; + goto out; + } + + res = &ushader->shader.res; + ushader->base.shareable = false; + ushader->base.tfile = NULL; + + /* + * From here on, the destructor takes over resource freeing. + */ + + ret = vmw_gb_shader_init(dev_priv, res, shader_size, + offset, shader_type, buffer, + vmw_user_shader_free); + if (unlikely(ret != 0)) + goto out; + + tmp = vmw_resource_reference(res); + ret = ttm_base_object_init(tfile, &ushader->base, false, + VMW_RES_SHADER, + &vmw_user_shader_base_release, NULL); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&tmp); + goto out_err; + } + + if (handle) + *handle = ushader->base.hash.key; +out_err: + vmw_resource_unreference(&res); +out: + return ret; +} + + +int vmw_shader_define_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_vmw_shader_create_arg *arg = + (struct drm_vmw_shader_create_arg *)data; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_master *vmaster = vmw_master(file_priv->master); + struct vmw_dma_buffer *buffer = NULL; + SVGA3dShaderType shader_type; + int ret; + + if (arg->buffer_handle != SVGA3D_INVALID_ID) { + ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle, + &buffer); + if (unlikely(ret != 0)) { + DRM_ERROR("Could not find buffer for shader " + "creation.\n"); + return ret; + } + + if ((u64)buffer->base.num_pages * PAGE_SIZE < + (u64)arg->size + (u64)arg->offset) { + DRM_ERROR("Illegal buffer- or shader size.\n"); + ret = -EINVAL; + goto out_bad_arg; + } + } + + switch (arg->shader_type) { + case drm_vmw_shader_type_vs: + shader_type = SVGA3D_SHADERTYPE_VS; + break; + case drm_vmw_shader_type_ps: + shader_type = SVGA3D_SHADERTYPE_PS; + break; + case drm_vmw_shader_type_gs: + shader_type = SVGA3D_SHADERTYPE_GS; + break; + default: + DRM_ERROR("Illegal shader type.\n"); + ret = -EINVAL; + goto out_bad_arg; + } + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + goto out_bad_arg; + + ret = vmw_shader_alloc(dev_priv, buffer, arg->size, arg->offset, + shader_type, tfile, &arg->shader_handle); + + ttm_read_unlock(&vmaster->lock); +out_bad_arg: + vmw_dmabuf_unreference(&buffer); + return ret; +} + +/** + * vmw_compat_shader_lookup - Look up a compat shader + * + * @man: Pointer to the compat shader manager. + * @shader_type: The shader type, that combined with the user_key identifies + * the shader. + * @user_key: On entry, this should be a pointer to the user_key. + * On successful exit, it will contain the guest-backed shader's TTM handle. + * + * Returns 0 on success. Non-zero on failure, in which case the value pointed + * to by @user_key is unmodified. + */ +int vmw_compat_shader_lookup(struct vmw_compat_shader_manager *man, + SVGA3dShaderType shader_type, + u32 *user_key) +{ + struct drm_hash_item *hash; + int ret; + unsigned long key = *user_key | (shader_type << 24); + + ret = drm_ht_find_item(&man->shaders, key, &hash); + if (unlikely(ret != 0)) + return ret; + + *user_key = drm_hash_entry(hash, struct vmw_compat_shader, + hash)->handle; + + return 0; +} + +/** + * vmw_compat_shader_free - Free a compat shader. + * + * @man: Pointer to the compat shader manager. + * @entry: Pointer to a struct vmw_compat_shader. + * + * Frees a struct vmw_compat_shder entry and drops its reference to the + * guest backed shader. + */ +static void vmw_compat_shader_free(struct vmw_compat_shader_manager *man, + struct vmw_compat_shader *entry) +{ + list_del(&entry->head); + WARN_ON(drm_ht_remove_item(&man->shaders, &entry->hash)); + WARN_ON(ttm_ref_object_base_unref(entry->tfile, entry->handle, + TTM_REF_USAGE)); + kfree(entry); +} + +/** + * vmw_compat_shaders_commit - Commit a list of compat shader actions. + * + * @man: Pointer to the compat shader manager. + * @list: Caller's list of compat shader actions. + * + * This function commits a list of compat shader additions or removals. + * It is typically called when the execbuf ioctl call triggering these + * actions has commited the fifo contents to the device. + */ +void vmw_compat_shaders_commit(struct vmw_compat_shader_manager *man, + struct list_head *list) +{ + struct vmw_compat_shader *entry, *next; + + list_for_each_entry_safe(entry, next, list, head) { + list_del(&entry->head); + switch (entry->state) { + case VMW_COMPAT_ADD: + entry->state = VMW_COMPAT_COMMITED; + list_add_tail(&entry->head, &man->list); + break; + case VMW_COMPAT_DEL: + ttm_ref_object_base_unref(entry->tfile, entry->handle, + TTM_REF_USAGE); + kfree(entry); + break; + default: + BUG(); + break; + } + } +} + +/** + * vmw_compat_shaders_revert - Revert a list of compat shader actions + * + * @man: Pointer to the compat shader manager. + * @list: Caller's list of compat shader actions. + * + * This function reverts a list of compat shader additions or removals. + * It is typically called when the execbuf ioctl call triggering these + * actions failed for some reason, and the command stream was never + * submitted. + */ +void vmw_compat_shaders_revert(struct vmw_compat_shader_manager *man, + struct list_head *list) +{ + struct vmw_compat_shader *entry, *next; + int ret; + + list_for_each_entry_safe(entry, next, list, head) { + switch (entry->state) { + case VMW_COMPAT_ADD: + vmw_compat_shader_free(man, entry); + break; + case VMW_COMPAT_DEL: + ret = drm_ht_insert_item(&man->shaders, &entry->hash); + list_del(&entry->head); + list_add_tail(&entry->head, &man->list); + entry->state = VMW_COMPAT_COMMITED; + break; + default: + BUG(); + break; + } + } +} + +/** + * vmw_compat_shader_remove - Stage a compat shader for removal. + * + * @man: Pointer to the compat shader manager + * @user_key: The key that is used to identify the shader. The key is + * unique to the shader type. + * @shader_type: Shader type. + * @list: Caller's list of staged shader actions. + * + * This function stages a compat shader for removal and removes the key from + * the shader manager's hash table. If the shader was previously only staged + * for addition it is completely removed (But the execbuf code may keep a + * reference if it was bound to a context between addition and removal). If + * it was previously commited to the manager, it is staged for removal. + */ +int vmw_compat_shader_remove(struct vmw_compat_shader_manager *man, + u32 user_key, SVGA3dShaderType shader_type, + struct list_head *list) +{ + struct vmw_compat_shader *entry; + struct drm_hash_item *hash; + int ret; + + ret = drm_ht_find_item(&man->shaders, user_key | (shader_type << 24), + &hash); + if (likely(ret != 0)) + return -EINVAL; + + entry = drm_hash_entry(hash, struct vmw_compat_shader, hash); + + switch (entry->state) { + case VMW_COMPAT_ADD: + vmw_compat_shader_free(man, entry); + break; + case VMW_COMPAT_COMMITED: + (void) drm_ht_remove_item(&man->shaders, &entry->hash); + list_del(&entry->head); + entry->state = VMW_COMPAT_DEL; + list_add_tail(&entry->head, list); + break; + default: + BUG(); + break; + } + + return 0; +} + +/** + * vmw_compat_shader_add - Create a compat shader and add the + * key to the manager + * + * @man: Pointer to the compat shader manager + * @user_key: The key that is used to identify the shader. The key is + * unique to the shader type. + * @bytecode: Pointer to the bytecode of the shader. + * @shader_type: Shader type. + * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is + * to be created with. + * @list: Caller's list of staged shader actions. + * + * Note that only the key is added to the shader manager's hash table. + * The shader is not yet added to the shader manager's list of shaders. + */ +int vmw_compat_shader_add(struct vmw_compat_shader_manager *man, + u32 user_key, const void *bytecode, + SVGA3dShaderType shader_type, + size_t size, + struct ttm_object_file *tfile, + struct list_head *list) +{ + struct vmw_dma_buffer *buf; + struct ttm_bo_kmap_obj map; + bool is_iomem; + struct vmw_compat_shader *compat; + u32 handle; + int ret; + + if (user_key > ((1 << 24) - 1) || (unsigned) shader_type > 16) + return -EINVAL; + + /* Allocate and pin a DMA buffer */ + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (unlikely(buf == NULL)) + return -ENOMEM; + + ret = vmw_dmabuf_init(man->dev_priv, buf, size, &vmw_sys_ne_placement, + true, vmw_dmabuf_bo_free); + if (unlikely(ret != 0)) + goto out; + + ret = ttm_bo_reserve(&buf->base, false, true, false, NULL); + if (unlikely(ret != 0)) + goto no_reserve; + + /* Map and copy shader bytecode. */ + ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT, + &map); + if (unlikely(ret != 0)) { + ttm_bo_unreserve(&buf->base); + goto no_reserve; + } + + memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); + WARN_ON(is_iomem); + + ttm_bo_kunmap(&map); + ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, false, true); + WARN_ON(ret != 0); + ttm_bo_unreserve(&buf->base); + + /* Create a guest-backed shader container backed by the dma buffer */ + ret = vmw_shader_alloc(man->dev_priv, buf, size, 0, shader_type, + tfile, &handle); + vmw_dmabuf_unreference(&buf); + if (unlikely(ret != 0)) + goto no_reserve; + /* + * Create a compat shader structure and stage it for insertion + * in the manager + */ + compat = kzalloc(sizeof(*compat), GFP_KERNEL); + if (compat == NULL) + goto no_compat; + + compat->hash.key = user_key | (shader_type << 24); + ret = drm_ht_insert_item(&man->shaders, &compat->hash); + if (unlikely(ret != 0)) + goto out_invalid_key; + + compat->state = VMW_COMPAT_ADD; + compat->handle = handle; + compat->tfile = tfile; + list_add_tail(&compat->head, list); + + return 0; + +out_invalid_key: + kfree(compat); +no_compat: + ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); +no_reserve: +out: + return ret; +} + +/** + * vmw_compat_shader_man_create - Create a compat shader manager + * + * @dev_priv: Pointer to a device private structure. + * + * Typically done at file open time. If successful returns a pointer to a + * compat shader manager. Otherwise returns an error pointer. + */ +struct vmw_compat_shader_manager * +vmw_compat_shader_man_create(struct vmw_private *dev_priv) +{ + struct vmw_compat_shader_manager *man; + int ret; + + man = kzalloc(sizeof(*man), GFP_KERNEL); + if (man == NULL) + return ERR_PTR(-ENOMEM); + + man->dev_priv = dev_priv; + INIT_LIST_HEAD(&man->list); + ret = drm_ht_create(&man->shaders, VMW_COMPAT_SHADER_HT_ORDER); + if (ret == 0) + return man; + + kfree(man); + return ERR_PTR(ret); +} + +/** + * vmw_compat_shader_man_destroy - Destroy a compat shader manager + * + * @man: Pointer to the shader manager to destroy. + * + * Typically done at file close time. + */ +void vmw_compat_shader_man_destroy(struct vmw_compat_shader_manager *man) +{ + struct vmw_compat_shader *entry, *next; + + mutex_lock(&man->dev_priv->cmdbuf_mutex); + list_for_each_entry_safe(entry, next, &man->list, head) + vmw_compat_shader_free(man, entry); + + mutex_unlock(&man->dev_priv->cmdbuf_mutex); + kfree(man); +} --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -54,6 +54,8 @@ * @res: Ref-counted pointer to the resource. * @switch_backup: Boolean whether to switch backup buffer on unreserve. * @new_backup: Refcounted pointer to the new backup buffer. + * @staged_bindings: If @res is a context, tracks bindings set up during + * the command batch. Otherwise NULL. * @new_backup_offset: New backup buffer offset if @new_backup is non-NUll. * @first_usage: Set to true the first time the resource is referenced in * the command stream. @@ -65,12 +67,32 @@ struct drm_hash_item hash; struct vmw_resource *res; struct vmw_dma_buffer *new_backup; + struct vmw_ctx_binding_state *staged_bindings; unsigned long new_backup_offset; bool first_usage; bool no_buffer_needed; }; /** + * struct vmw_cmd_entry - Describe a command for the verifier + * + * @user_allow: Whether allowed from the execbuf ioctl. + * @gb_disable: Whether disabled if guest-backed objects are available. + * @gb_enable: Whether enabled iff guest-backed objects are available. + */ +struct vmw_cmd_entry { + int (*func) (struct vmw_private *, struct vmw_sw_context *, + SVGA3dCmdHeader *); + bool user_allow; + bool gb_disable; + bool gb_enable; +}; + +#define VMW_CMD_DEF(_cmd, _func, _user_allow, _gb_disable, _gb_enable) \ + [(_cmd) - SVGA_3D_CMD_BASE] = {(_func), (_user_allow),\ + (_gb_disable), (_gb_enable)} + +/** * vmw_resource_unreserve - unreserve resources previously reserved for * command submission. * @@ -87,6 +109,18 @@ struct vmw_dma_buffer *new_backup = backoff ? NULL : val->new_backup; + /* + * Transfer staged context bindings to the + * persistent context binding tracker. + */ + if (unlikely(val->staged_bindings)) { + if (!backoff) { + vmw_context_binding_state_transfer + (val->res, val->staged_bindings); + } + kfree(val->staged_bindings); + val->staged_bindings = NULL; + } vmw_resource_unreserve(res, new_backup, val->new_backup_offset); vmw_dmabuf_unreference(&val->new_backup); @@ -146,6 +180,44 @@ } /** + * vmw_resource_context_res_add - Put resources previously bound to a context on + * the validation list + * + * @dev_priv: Pointer to a device private structure + * @sw_context: Pointer to a software context used for this command submission + * @ctx: Pointer to the context resource + * + * This function puts all resources that were previously bound to @ctx on + * the resource validation list. This is part of the context state reemission + */ +static int vmw_resource_context_res_add(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + struct vmw_resource *ctx) +{ + struct list_head *binding_list; + struct vmw_ctx_binding *entry; + int ret = 0; + struct vmw_resource *res; + + mutex_lock(&dev_priv->binding_mutex); + binding_list = vmw_context_binding_list(ctx); + + list_for_each_entry(entry, binding_list, ctx_list) { + res = vmw_resource_reference_unless_doomed(entry->bi.res); + if (unlikely(res == NULL)) + continue; + + ret = vmw_resource_val_add(sw_context, entry->bi.res, NULL); + vmw_resource_unreference(&res); + if (unlikely(ret != 0)) + break; + } + + mutex_unlock(&dev_priv->binding_mutex); + return ret; +} + +/** * vmw_resource_relocation_add - Add a relocation to the relocation list * * @list: Pointer to head of relocation list. @@ -201,8 +273,12 @@ { struct vmw_resource_relocation *rel; - list_for_each_entry(rel, list, head) - cb[rel->offset] = rel->res->id; + list_for_each_entry(rel, list, head) { + if (likely(rel->res != NULL)) + cb[rel->offset] = rel->res->id; + else + cb[rel->offset] = SVGA_3D_CMD_NOP; + } } static int vmw_cmd_invalid(struct vmw_private *dev_priv, @@ -224,6 +300,7 @@ * * @sw_context: The software context used for this command submission batch. * @bo: The buffer object to add. + * @validate_as_mob: Validate this buffer as a MOB. * @p_val_node: If non-NULL Will be updated with the validate node number * on return. * @@ -232,6 +309,7 @@ */ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, struct ttm_buffer_object *bo, + bool validate_as_mob, uint32_t *p_val_node) { uint32_t val_node; @@ -244,6 +322,10 @@ &hash) == 0)) { vval_buf = container_of(hash, struct vmw_validate_buffer, hash); + if (unlikely(vval_buf->validate_as_mob != validate_as_mob)) { + DRM_ERROR("Inconsistent buffer usage.\n"); + return -EINVAL; + } val_buf = &vval_buf->base; val_node = vval_buf - sw_context->val_bufs; } else { @@ -266,6 +348,7 @@ val_buf->bo = ttm_bo_reference(bo); val_buf->reserved = false; list_add_tail(&val_buf->head, &sw_context->validate_nodes); + vval_buf->validate_as_mob = validate_as_mob; } sw_context->fence_flags |= DRM_VMW_FENCE_FLAG_EXEC; @@ -302,7 +385,8 @@ struct ttm_buffer_object *bo = &res->backup->base; ret = vmw_bo_to_validate_list - (sw_context, bo, NULL); + (sw_context, bo, + vmw_resource_needs_backup(res), NULL); if (unlikely(ret != 0)) return ret; @@ -339,22 +423,27 @@ } /** - * vmw_cmd_res_check - Check that a resource is present and if so, put it + * vmw_cmd_compat_res_check - Check that a resource is present and if so, put it * on the resource validate list unless it's already there. * * @dev_priv: Pointer to a device private structure. * @sw_context: Pointer to the software context. * @res_type: Resource type. * @converter: User-space visisble type specific information. - * @id: Pointer to the location in the command buffer currently being + * @id: user-space resource id handle. + * @id_loc: Pointer to the location in the command buffer currently being * parsed from where the user-space resource id handle is located. + * @p_val: Pointer to pointer to resource validalidation node. Populated + * on exit. */ -static int vmw_cmd_res_check(struct vmw_private *dev_priv, - struct vmw_sw_context *sw_context, - enum vmw_res_type res_type, - const struct vmw_user_resource_conv *converter, - uint32_t *id, - struct vmw_resource_val_node **p_val) +static int +vmw_cmd_compat_res_check(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + enum vmw_res_type res_type, + const struct vmw_user_resource_conv *converter, + uint32_t id, + uint32_t *id_loc, + struct vmw_resource_val_node **p_val) { struct vmw_res_cache_entry *rcache = &sw_context->res_cache[res_type]; @@ -362,15 +451,22 @@ struct vmw_resource_val_node *node; int ret; - if (*id == SVGA3D_INVALID_ID) + if (id == SVGA3D_INVALID_ID) { + if (p_val) + *p_val = NULL; + if (res_type == vmw_res_context) { + DRM_ERROR("Illegal context invalid id.\n"); + return -EINVAL; + } return 0; + } /* * Fastpath in case of repeated commands referencing the same * resource */ - if (likely(rcache->valid && *id == rcache->handle)) { + if (likely(rcache->valid && id == rcache->handle)) { const struct vmw_resource *res = rcache->res; rcache->node->first_usage = false; @@ -379,28 +475,28 @@ return vmw_resource_relocation_add (&sw_context->res_relocations, res, - id - sw_context->buf_start); + id_loc - sw_context->buf_start); } ret = vmw_user_resource_lookup_handle(dev_priv, - sw_context->tfile, - *id, + sw_context->fp->tfile, + id, converter, &res); if (unlikely(ret != 0)) { DRM_ERROR("Could not find or use resource 0x%08x.\n", - (unsigned) *id); + (unsigned) id); dump_stack(); return ret; } rcache->valid = true; rcache->res = res; - rcache->handle = *id; + rcache->handle = id; ret = vmw_resource_relocation_add(&sw_context->res_relocations, res, - id - sw_context->buf_start); + id_loc - sw_context->buf_start); if (unlikely(ret != 0)) goto out_no_reloc; @@ -411,6 +507,22 @@ rcache->node = node; if (p_val) *p_val = node; + + if (dev_priv->has_mob && node->first_usage && + res_type == vmw_res_context) { + ret = vmw_resource_context_res_add(dev_priv, sw_context, res); + if (unlikely(ret != 0)) + goto out_no_reloc; + node->staged_bindings = + kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL); + if (node->staged_bindings == NULL) { + DRM_ERROR("Failed to allocate context binding " + "information.\n"); + goto out_no_reloc; + } + INIT_LIST_HEAD(&node->staged_bindings->list); + } + vmw_resource_unreference(&res); return 0; @@ -422,6 +534,59 @@ } /** + * vmw_cmd_res_check - Check that a resource is present and if so, put it + * on the resource validate list unless it's already there. + * + * @dev_priv: Pointer to a device private structure. + * @sw_context: Pointer to the software context. + * @res_type: Resource type. + * @converter: User-space visisble type specific information. + * @id_loc: Pointer to the location in the command buffer currently being + * parsed from where the user-space resource id handle is located. + * @p_val: Pointer to pointer to resource validalidation node. Populated + * on exit. + */ +static int +vmw_cmd_res_check(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + enum vmw_res_type res_type, + const struct vmw_user_resource_conv *converter, + uint32_t *id_loc, + struct vmw_resource_val_node **p_val) +{ + return vmw_cmd_compat_res_check(dev_priv, sw_context, res_type, + converter, *id_loc, id_loc, p_val); +} + +/** + * vmw_rebind_contexts - Rebind all resources previously bound to + * referenced contexts. + * + * @sw_context: Pointer to the software context. + * + * Rebind context binding points that have been scrubbed because of eviction. + */ +static int vmw_rebind_contexts(struct vmw_sw_context *sw_context) +{ + struct vmw_resource_val_node *val; + int ret; + + list_for_each_entry(val, &sw_context->resource_list, head) { + if (likely(!val->staged_bindings)) + continue; + + ret = vmw_context_rebind_all(val->res); + if (unlikely(ret != 0)) { + if (ret != -ERESTARTSYS) + DRM_ERROR("Failed to rebind context.\n"); + return ret; + } + } + + return 0; +} + +/** * vmw_cmd_cid_check - Check a command header for valid context information. * * @dev_priv: Pointer to a device private structure. @@ -437,7 +602,7 @@ { struct vmw_cid_cmd { SVGA3dCmdHeader header; - __le32 cid; + uint32_t cid; } *cmd; cmd = container_of(header, struct vmw_cid_cmd, header); @@ -453,17 +618,35 @@ SVGA3dCmdHeader header; SVGA3dCmdSetRenderTarget body; } *cmd; + struct vmw_resource_val_node *ctx_node; + struct vmw_resource_val_node *res_node; int ret; - ret = vmw_cmd_cid_check(dev_priv, sw_context, header); + cmd = container_of(header, struct vmw_sid_cmd, header); + + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, + user_context_converter, &cmd->body.cid, + &ctx_node); if (unlikely(ret != 0)) return ret; - cmd = container_of(header, struct vmw_sid_cmd, header); ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, - &cmd->body.target.sid, NULL); - return ret; + &cmd->body.target.sid, &res_node); + if (unlikely(ret != 0)) + return ret; + + if (dev_priv->has_mob) { + struct vmw_ctx_bindinfo bi; + + bi.ctx = ctx_node->res; + bi.res = res_node ? res_node->res : NULL; + bi.bt = vmw_ctx_binding_rt; + bi.i1.rt_type = cmd->body.type; + return vmw_context_binding_add(ctx_node->staged_bindings, &bi); + } + + return 0; } static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, @@ -519,11 +702,6 @@ cmd = container_of(header, struct vmw_sid_cmd, header); - if (unlikely(!sw_context->kernel)) { - DRM_ERROR("Kernel only SVGA3d command: %u.\n", cmd->header.id); - return -EPERM; - } - return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->body.srcImage.sid, NULL); @@ -541,11 +719,6 @@ cmd = container_of(header, struct vmw_sid_cmd, header); - if (unlikely(!sw_context->kernel)) { - DRM_ERROR("Kernel only SVGA3d command: %u.\n", cmd->header.id); - return -EPERM; - } - return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->body.sid, NULL); @@ -586,7 +759,7 @@ sw_context->needs_post_query_barrier = true; ret = vmw_bo_to_validate_list(sw_context, sw_context->cur_query_bo, - NULL); + dev_priv->has_mob, NULL); if (unlikely(ret != 0)) return ret; } @@ -594,7 +767,7 @@ ret = vmw_bo_to_validate_list(sw_context, dev_priv->dummy_query_bo, - NULL); + dev_priv->has_mob, NULL); if (unlikely(ret != 0)) return ret; @@ -672,6 +845,66 @@ } /** + * vmw_translate_mob_pointer - Prepare to translate a user-space buffer + * handle to a MOB id. + * + * @dev_priv: Pointer to a device private structure. + * @sw_context: The software context used for this command batch validation. + * @id: Pointer to the user-space handle to be translated. + * @vmw_bo_p: Points to a location that, on successful return will carry + * a reference-counted pointer to the DMA buffer identified by the + * user-space handle in @id. + * + * This function saves information needed to translate a user-space buffer + * handle to a MOB id. The translation does not take place immediately, but + * during a call to vmw_apply_relocations(). This function builds a relocation + * list and a list of buffers to validate. The former needs to be freed using + * either vmw_apply_relocations() or vmw_free_relocations(). The latter + * needs to be freed using vmw_clear_validations. + */ +static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGAMobId *id, + struct vmw_dma_buffer **vmw_bo_p) +{ + struct vmw_dma_buffer *vmw_bo = NULL; + struct ttm_buffer_object *bo; + uint32_t handle = *id; + struct vmw_relocation *reloc; + int ret; + + ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo); + if (unlikely(ret != 0)) { + DRM_ERROR("Could not find or use MOB buffer.\n"); + return -EINVAL; + } + bo = &vmw_bo->base; + + if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) { + DRM_ERROR("Max number relocations per submission" + " exceeded\n"); + ret = -EINVAL; + goto out_no_reloc; + } + + reloc = &sw_context->relocs[sw_context->cur_reloc++]; + reloc->mob_loc = id; + reloc->location = NULL; + + ret = vmw_bo_to_validate_list(sw_context, bo, true, &reloc->index); + if (unlikely(ret != 0)) + goto out_no_reloc; + + *vmw_bo_p = vmw_bo; + return 0; + +out_no_reloc: + vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_p = NULL; + return ret; +} + +/** * vmw_translate_guest_pointer - Prepare to translate a user-space buffer * handle to a valid SVGAGuestPtr * @@ -701,7 +934,7 @@ struct vmw_relocation *reloc; int ret; - ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo); + ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo); if (unlikely(ret != 0)) { DRM_ERROR("Could not find or use GMR region.\n"); return -EINVAL; @@ -718,7 +951,7 @@ reloc = &sw_context->relocs[sw_context->cur_reloc++]; reloc->location = ptr; - ret = vmw_bo_to_validate_list(sw_context, bo, &reloc->index); + ret = vmw_bo_to_validate_list(sw_context, bo, false, &reloc->index); if (unlikely(ret != 0)) goto out_no_reloc; @@ -732,6 +965,30 @@ } /** + * vmw_cmd_begin_gb_query - validate a SVGA_3D_CMD_BEGIN_GB_QUERY command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context used for this command submission. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_begin_gb_query(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_begin_gb_query_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdBeginGBQuery q; + } *cmd; + + cmd = container_of(header, struct vmw_begin_gb_query_cmd, + header); + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, + user_context_converter, &cmd->q.cid, + NULL); +} + +/** * vmw_cmd_begin_query - validate a SVGA_3D_CMD_BEGIN_QUERY command. * * @dev_priv: Pointer to a device private struct. @@ -750,12 +1007,64 @@ cmd = container_of(header, struct vmw_begin_query_cmd, header); + if (unlikely(dev_priv->has_mob)) { + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBeginGBQuery q; + } gb_cmd; + + BUG_ON(sizeof(gb_cmd) != sizeof(*cmd)); + + gb_cmd.header.id = SVGA_3D_CMD_BEGIN_GB_QUERY; + gb_cmd.header.size = cmd->header.size; + gb_cmd.q.cid = cmd->q.cid; + gb_cmd.q.type = cmd->q.type; + + memcpy(cmd, &gb_cmd, sizeof(*cmd)); + return vmw_cmd_begin_gb_query(dev_priv, sw_context, header); + } + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, user_context_converter, &cmd->q.cid, NULL); } /** + * vmw_cmd_end_gb_query - validate a SVGA_3D_CMD_END_GB_QUERY command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context used for this command submission. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_dma_buffer *vmw_bo; + struct vmw_query_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdEndGBQuery q; + } *cmd; + int ret; + + cmd = container_of(header, struct vmw_query_cmd, header); + ret = vmw_cmd_cid_check(dev_priv, sw_context, header); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_translate_mob_ptr(dev_priv, sw_context, + &cmd->q.mobid, + &vmw_bo); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context); + + vmw_dmabuf_unreference(&vmw_bo); + return ret; +} + +/** * vmw_cmd_end_query - validate a SVGA_3D_CMD_END_QUERY command. * * @dev_priv: Pointer to a device private struct. @@ -774,6 +1083,25 @@ int ret; cmd = container_of(header, struct vmw_query_cmd, header); + if (dev_priv->has_mob) { + struct { + SVGA3dCmdHeader header; + SVGA3dCmdEndGBQuery q; + } gb_cmd; + + BUG_ON(sizeof(gb_cmd) != sizeof(*cmd)); + + gb_cmd.header.id = SVGA_3D_CMD_END_GB_QUERY; + gb_cmd.header.size = cmd->header.size; + gb_cmd.q.cid = cmd->q.cid; + gb_cmd.q.type = cmd->q.type; + gb_cmd.q.mobid = cmd->q.guestResult.gmrId; + gb_cmd.q.offset = cmd->q.guestResult.offset; + + memcpy(cmd, &gb_cmd, sizeof(*cmd)); + return vmw_cmd_end_gb_query(dev_priv, sw_context, header); + } + ret = vmw_cmd_cid_check(dev_priv, sw_context, header); if (unlikely(ret != 0)) return ret; @@ -790,7 +1118,40 @@ return ret; } -/* +/** + * vmw_cmd_wait_gb_query - validate a SVGA_3D_CMD_WAIT_GB_QUERY command. + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context used for this command submission. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_wait_gb_query(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_dma_buffer *vmw_bo; + struct vmw_query_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdWaitForGBQuery q; + } *cmd; + int ret; + + cmd = container_of(header, struct vmw_query_cmd, header); + ret = vmw_cmd_cid_check(dev_priv, sw_context, header); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_translate_mob_ptr(dev_priv, sw_context, + &cmd->q.mobid, + &vmw_bo); + if (unlikely(ret != 0)) + return ret; + + vmw_dmabuf_unreference(&vmw_bo); + return 0; +} + +/** * vmw_cmd_wait_query - validate a SVGA_3D_CMD_WAIT_QUERY command. * * @dev_priv: Pointer to a device private struct. @@ -809,6 +1170,25 @@ int ret; cmd = container_of(header, struct vmw_query_cmd, header); + if (dev_priv->has_mob) { + struct { + SVGA3dCmdHeader header; + SVGA3dCmdWaitForGBQuery q; + } gb_cmd; + + BUG_ON(sizeof(gb_cmd) != sizeof(*cmd)); + + gb_cmd.header.id = SVGA_3D_CMD_WAIT_FOR_GB_QUERY; + gb_cmd.header.size = cmd->header.size; + gb_cmd.q.cid = cmd->q.cid; + gb_cmd.q.type = cmd->q.type; + gb_cmd.q.mobid = cmd->q.guestResult.gmrId; + gb_cmd.q.offset = cmd->q.guestResult.offset; + + memcpy(cmd, &gb_cmd, sizeof(*cmd)); + return vmw_cmd_wait_gb_query(dev_priv, sw_context, header); + } + ret = vmw_cmd_cid_check(dev_priv, sw_context, header); if (unlikely(ret != 0)) return ret; @@ -853,7 +1233,8 @@ srf = vmw_res_to_srf(sw_context->res_cache[vmw_res_surface].res); - vmw_kms_cursor_snoop(srf, sw_context->tfile, &vmw_bo->base, header); + vmw_kms_cursor_snoop(srf, sw_context->fp->tfile, &vmw_bo->base, + header); out_no_surface: vmw_dmabuf_unreference(&vmw_bo); @@ -921,15 +1302,22 @@ struct vmw_tex_state_cmd { SVGA3dCmdHeader header; SVGA3dCmdSetTextureState state; - }; + } *cmd; SVGA3dTextureState *last_state = (SVGA3dTextureState *) ((unsigned long) header + header->size + sizeof(header)); SVGA3dTextureState *cur_state = (SVGA3dTextureState *) ((unsigned long) header + sizeof(struct vmw_tex_state_cmd)); + struct vmw_resource_val_node *ctx_node; + struct vmw_resource_val_node *res_node; int ret; - ret = vmw_cmd_cid_check(dev_priv, sw_context, header); + cmd = container_of(header, struct vmw_tex_state_cmd, + header); + + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, + user_context_converter, &cmd->state.cid, + &ctx_node); if (unlikely(ret != 0)) return ret; @@ -939,9 +1327,20 @@ ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, - &cur_state->value, NULL); + &cur_state->value, &res_node); if (unlikely(ret != 0)) return ret; + + if (dev_priv->has_mob) { + struct vmw_ctx_bindinfo bi; + + bi.ctx = ctx_node->res; + bi.res = res_node ? res_node->res : NULL; + bi.bt = vmw_ctx_binding_tex; + bi.i1.texture_stage = cur_state->stage; + vmw_context_binding_add(ctx_node->staged_bindings, + &bi); + } } return 0; @@ -971,6 +1370,314 @@ } /** + * vmw_cmd_switch_backup - Utility function to handle backup buffer switching + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @res_type: The resource type. + * @converter: Information about user-space binding for this resource type. + * @res_id: Pointer to the user-space resource handle in the command stream. + * @buf_id: Pointer to the user-space backup buffer handle in the command + * stream. + * @backup_offset: Offset of backup into MOB. + * + * This function prepares for registering a switch of backup buffers + * in the resource metadata just prior to unreserving. + */ +static int vmw_cmd_switch_backup(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + enum vmw_res_type res_type, + const struct vmw_user_resource_conv + *converter, + uint32_t *res_id, + uint32_t *buf_id, + unsigned long backup_offset) +{ + int ret; + struct vmw_dma_buffer *dma_buf; + struct vmw_resource_val_node *val_node; + + ret = vmw_cmd_res_check(dev_priv, sw_context, res_type, + converter, res_id, &val_node); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf); + if (unlikely(ret != 0)) + return ret; + + if (val_node->first_usage) + val_node->no_buffer_needed = true; + + vmw_dmabuf_unreference(&val_node->new_backup); + val_node->new_backup = dma_buf; + val_node->new_backup_offset = backup_offset; + + return 0; +} + +/** + * vmw_cmd_bind_gb_surface - Validate an SVGA_3D_CMD_BIND_GB_SURFACE + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_bind_gb_surface(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_bind_gb_surface_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBSurface body; + } *cmd; + + cmd = container_of(header, struct vmw_bind_gb_surface_cmd, header); + + return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.sid, &cmd->body.mobid, + 0); +} + +/** + * vmw_cmd_update_gb_image - Validate an SVGA_3D_CMD_UPDATE_GB_IMAGE + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_update_gb_image(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_gb_surface_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBImage body; + } *cmd; + + cmd = container_of(header, struct vmw_gb_surface_cmd, header); + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.image.sid, NULL); +} + +/** + * vmw_cmd_update_gb_surface - Validate an SVGA_3D_CMD_UPDATE_GB_SURFACE + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_update_gb_surface(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_gb_surface_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBSurface body; + } *cmd; + + cmd = container_of(header, struct vmw_gb_surface_cmd, header); + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.sid, NULL); +} + +/** + * vmw_cmd_readback_gb_image - Validate an SVGA_3D_CMD_READBACK_GB_IMAGE + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_readback_gb_image(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_gb_surface_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdReadbackGBImage body; + } *cmd; + + cmd = container_of(header, struct vmw_gb_surface_cmd, header); + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.image.sid, NULL); +} + +/** + * vmw_cmd_readback_gb_surface - Validate an SVGA_3D_CMD_READBACK_GB_SURFACE + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_readback_gb_surface(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_gb_surface_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdReadbackGBSurface body; + } *cmd; + + cmd = container_of(header, struct vmw_gb_surface_cmd, header); + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.sid, NULL); +} + +/** + * vmw_cmd_invalidate_gb_image - Validate an SVGA_3D_CMD_INVALIDATE_GB_IMAGE + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_invalidate_gb_image(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_gb_surface_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdInvalidateGBImage body; + } *cmd; + + cmd = container_of(header, struct vmw_gb_surface_cmd, header); + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.image.sid, NULL); +} + +/** + * vmw_cmd_invalidate_gb_surface - Validate an + * SVGA_3D_CMD_INVALIDATE_GB_SURFACE command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_invalidate_gb_surface(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_gb_surface_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdInvalidateGBSurface body; + } *cmd; + + cmd = container_of(header, struct vmw_gb_surface_cmd, header); + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.sid, NULL); +} + + +/** + * vmw_cmd_shader_define - Validate an SVGA_3D_CMD_SHADER_DEFINE + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_shader_define(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_shader_define_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdDefineShader body; + } *cmd; + int ret; + size_t size; + + cmd = container_of(header, struct vmw_shader_define_cmd, + header); + + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, + user_context_converter, &cmd->body.cid, + NULL); + if (unlikely(ret != 0)) + return ret; + + if (unlikely(!dev_priv->has_mob)) + return 0; + + size = cmd->header.size - sizeof(cmd->body); + ret = vmw_compat_shader_add(sw_context->fp->shman, + cmd->body.shid, cmd + 1, + cmd->body.type, size, + sw_context->fp->tfile, + &sw_context->staged_shaders); + if (unlikely(ret != 0)) + return ret; + + return vmw_resource_relocation_add(&sw_context->res_relocations, + NULL, &cmd->header.id - + sw_context->buf_start); + + return 0; +} + +/** + * vmw_cmd_shader_destroy - Validate an SVGA_3D_CMD_SHADER_DESTROY + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_shader_destroy_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdDestroyShader body; + } *cmd; + int ret; + + cmd = container_of(header, struct vmw_shader_destroy_cmd, + header); + + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, + user_context_converter, &cmd->body.cid, + NULL); + if (unlikely(ret != 0)) + return ret; + + if (unlikely(!dev_priv->has_mob)) + return 0; + + ret = vmw_compat_shader_remove(sw_context->fp->shman, + cmd->body.shid, + cmd->body.type, + &sw_context->staged_shaders); + if (unlikely(ret != 0)) + return ret; + + return vmw_resource_relocation_add(&sw_context->res_relocations, + NULL, &cmd->header.id - + sw_context->buf_start); + + return 0; +} + +/** * vmw_cmd_set_shader - Validate an SVGA_3D_CMD_SET_SHADER * command * @@ -986,18 +1693,105 @@ SVGA3dCmdHeader header; SVGA3dCmdSetShader body; } *cmd; + struct vmw_resource_val_node *ctx_node; int ret; cmd = container_of(header, struct vmw_set_shader_cmd, header); - ret = vmw_cmd_cid_check(dev_priv, sw_context, header); + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, + user_context_converter, &cmd->body.cid, + &ctx_node); + if (unlikely(ret != 0)) + return ret; + + if (dev_priv->has_mob) { + struct vmw_ctx_bindinfo bi; + struct vmw_resource_val_node *res_node; + u32 shid = cmd->body.shid; + + if (shid != SVGA3D_INVALID_ID) + (void) vmw_compat_shader_lookup(sw_context->fp->shman, + cmd->body.type, + &shid); + + ret = vmw_cmd_compat_res_check(dev_priv, sw_context, + vmw_res_shader, + user_shader_converter, + shid, + &cmd->body.shid, &res_node); + if (unlikely(ret != 0)) + return ret; + + bi.ctx = ctx_node->res; + bi.res = res_node ? res_node->res : NULL; + bi.bt = vmw_ctx_binding_shader; + bi.i1.shader_type = cmd->body.type; + return vmw_context_binding_add(ctx_node->staged_bindings, &bi); + } + + return 0; +} + +/** + * vmw_cmd_set_shader_const - Validate an SVGA_3D_CMD_SET_SHADER_CONST + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_set_shader_const(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_set_shader_const_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdSetShaderConst body; + } *cmd; + int ret; + + cmd = container_of(header, struct vmw_set_shader_const_cmd, + header); + + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, + user_context_converter, &cmd->body.cid, + NULL); if (unlikely(ret != 0)) return ret; + if (dev_priv->has_mob) + header->id = SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE; + return 0; } +/** + * vmw_cmd_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_SHADER + * command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_bind_gb_shader(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct vmw_bind_gb_shader_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBShader body; + } *cmd; + + cmd = container_of(header, struct vmw_bind_gb_shader_cmd, + header); + + return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_shader, + user_shader_converter, + &cmd->body.shid, &cmd->body.mobid, + cmd->body.offsetInBytes); +} + static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, void *buf, uint32_t *size) @@ -1041,50 +1835,173 @@ return 0; } -typedef int (*vmw_cmd_func) (struct vmw_private *, - struct vmw_sw_context *, - SVGA3dCmdHeader *); - -#define VMW_CMD_DEF(cmd, func) \ - [cmd - SVGA_3D_CMD_BASE] = func - -static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = { - VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid), - VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid), - VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check), - VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check), - VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma), - VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid), - VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid), - VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check), +static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { + VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check, + true, false, false), VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET, - &vmw_cmd_set_render_target_check), - VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state), - VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SETCLIPPLANE, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_CLEAR, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check), - VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader), - VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw), - VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check), - VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_begin_query), - VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query), - VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query), - VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok), + &vmw_cmd_set_render_target_check, true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETCLIPPLANE, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_CLEAR, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_shader_define, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_shader_destroy, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_set_shader_const, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_begin_query, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query, + true, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok, + true, false, false), VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN, - &vmw_cmd_blt_surf_screen_check), - VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE_V2, &vmw_cmd_invalid), - VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid), - VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid), - VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid), + &vmw_cmd_blt_surf_screen_check, false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE_V2, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SCREEN_DMA, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_OPEN_CONTEXT_SURFACE, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_BITBLT, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_TRANSBLT, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_STRETCHBLT, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_COLORFILL, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_ALPHABLEND, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_CLEARTYPEBLEND, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_SET_OTABLE_BASE, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_READBACK_OTABLE, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_MOB, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_MOB, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_REDEFINE_GB_MOB, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SURFACE, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SURFACE, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SURFACE, &vmw_cmd_bind_gb_surface, + true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_COND_BIND_GB_SURFACE, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_IMAGE, &vmw_cmd_update_gb_image, + true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_SURFACE, + &vmw_cmd_update_gb_surface, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_IMAGE, + &vmw_cmd_readback_gb_image, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_SURFACE, + &vmw_cmd_readback_gb_surface, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE, + &vmw_cmd_invalidate_gb_image, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_SURFACE, + &vmw_cmd_invalidate_gb_surface, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_CONTEXT, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_CONTEXT, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_CONTEXT, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_CONTEXT, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_CONTEXT, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SHADER, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SHADER, &vmw_cmd_bind_gb_shader, + true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SHADER, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_SET_OTABLE_BASE64, &vmw_cmd_invalid, + false, false, false), + VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_GB_QUERY, &vmw_cmd_begin_gb_query, + true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_END_GB_QUERY, &vmw_cmd_end_gb_query, + true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_GB_QUERY, &vmw_cmd_wait_gb_query, + true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_NOP, &vmw_cmd_ok, + true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_ENABLE_GART, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DISABLE_GART, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_MAP_MOB_INTO_GART, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_UNMAP_GART_RANGE, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SCREENTARGET, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SCREENTARGET, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SCREENTARGET, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_SCREENTARGET, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL, &vmw_cmd_invalid, + false, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE, &vmw_cmd_cid_check, + true, false, true) }; static int vmw_cmd_check(struct vmw_private *dev_priv, @@ -1095,6 +2012,8 @@ uint32_t size_remaining = *size; SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf; int ret; + const struct vmw_cmd_entry *entry; + bool gb = dev_priv->capabilities & SVGA_CAP_GBOBJECTS; cmd_id = le32_to_cpu(((uint32_t *)buf)[0]); /* Handle any none 3D commands */ @@ -1107,18 +2026,43 @@ cmd_id -= SVGA_3D_CMD_BASE; if (unlikely(*size > size_remaining)) - goto out_err; + goto out_invalid; if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE)) - goto out_err; + goto out_invalid; + + entry = &vmw_cmd_entries[cmd_id]; + if (unlikely(!entry->func)) + goto out_invalid; + + if (unlikely(!entry->user_allow && !sw_context->kernel)) + goto out_privileged; + + if (unlikely(entry->gb_disable && gb)) + goto out_old; - ret = vmw_cmd_funcs[cmd_id](dev_priv, sw_context, header); + if (unlikely(entry->gb_enable && !gb)) + goto out_new; + + ret = entry->func(dev_priv, sw_context, header); if (unlikely(ret != 0)) - goto out_err; + goto out_invalid; return 0; -out_err: - DRM_ERROR("Illegal / Invalid SVGA3D command: %d\n", +out_invalid: + DRM_ERROR("Invalid SVGA3D command: %d\n", + cmd_id + SVGA_3D_CMD_BASE); + return -EINVAL; +out_privileged: + DRM_ERROR("Privileged SVGA3D command: %d\n", + cmd_id + SVGA_3D_CMD_BASE); + return -EPERM; +out_old: + DRM_ERROR("Deprecated (disallowed) SVGA3D command: %d\n", + cmd_id + SVGA_3D_CMD_BASE); + return -EINVAL; +out_new: + DRM_ERROR("SVGA3D command: %d not supported by virtual hardware.\n", cmd_id + SVGA_3D_CMD_BASE); return -EINVAL; } @@ -1174,6 +2118,9 @@ case VMW_PL_GMR: reloc->location->gmrId = bo->mem.start; break; + case VMW_PL_MOB: + *reloc->mob_loc = bo->mem.start; + break; default: BUG(); } @@ -1198,6 +2145,8 @@ list_for_each_entry_safe(val, val_next, list, head) { list_del_init(&val->head); vmw_resource_unreference(&val->res); + if (unlikely(val->staged_bindings)) + kfree(val->staged_bindings); kfree(val); } } @@ -1224,7 +2173,8 @@ } static int vmw_validate_single_buffer(struct vmw_private *dev_priv, - struct ttm_buffer_object *bo) + struct ttm_buffer_object *bo, + bool validate_as_mob) { int ret; @@ -1238,6 +2188,9 @@ dev_priv->dummy_query_bo_pinned)) return 0; + if (validate_as_mob) + return ttm_bo_validate(bo, &vmw_mob_placement, true, false); + /** * Put BO in VRAM if there is space, otherwise as a GMR. * If there is no space in VRAM and GMR ids are all used up, @@ -1259,7 +2212,6 @@ return ret; } - static int vmw_validate_buffers(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context) { @@ -1267,7 +2219,8 @@ int ret; list_for_each_entry(entry, &sw_context->validate_nodes, base.head) { - ret = vmw_validate_single_buffer(dev_priv, entry->base.bo); + ret = vmw_validate_single_buffer(dev_priv, entry->base.bo, + entry->validate_as_mob); if (unlikely(ret != 0)) return ret; } @@ -1461,7 +2414,7 @@ } else sw_context->kernel = true; - sw_context->tfile = vmw_fpriv(file_priv)->tfile; + sw_context->fp = vmw_fpriv(file_priv); sw_context->cur_reloc = 0; sw_context->cur_val_buf = 0; sw_context->fence_flags = 0; @@ -1478,16 +2431,17 @@ goto out_unlock; sw_context->res_ht_initialized = true; } + INIT_LIST_HEAD(&sw_context->staged_shaders); INIT_LIST_HEAD(&resource_list); ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands, command_size); if (unlikely(ret != 0)) - goto out_err; + goto out_err_nores; ret = vmw_resources_reserve(sw_context); if (unlikely(ret != 0)) - goto out_err; + goto out_err_nores; ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes); if (unlikely(ret != 0)) @@ -1509,11 +2463,23 @@ goto out_err; } + ret = mutex_lock_interruptible(&dev_priv->binding_mutex); + if (unlikely(ret != 0)) { + ret = -ERESTARTSYS; + goto out_err; + } + + if (dev_priv->has_mob) { + ret = vmw_rebind_contexts(sw_context); + if (unlikely(ret != 0)) + goto out_unlock_binding; + } + cmd = vmw_fifo_reserve(dev_priv, command_size); if (unlikely(cmd == NULL)) { DRM_ERROR("Failed reserving fifo space for commands.\n"); ret = -ENOMEM; - goto out_err; + goto out_unlock_binding; } vmw_apply_relocations(sw_context); @@ -1538,6 +2504,8 @@ DRM_ERROR("Fence submission error. Syncing.\n"); vmw_resource_list_unreserve(&sw_context->resource_list, false); + mutex_unlock(&dev_priv->binding_mutex); + ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes, (void *) fence); @@ -1558,6 +2526,8 @@ } list_splice_init(&sw_context->resource_list, &resource_list); + vmw_compat_shaders_commit(sw_context->fp->shman, + &sw_context->staged_shaders); mutex_unlock(&dev_priv->cmdbuf_mutex); /* @@ -1568,11 +2538,14 @@ return 0; +out_unlock_binding: + mutex_unlock(&dev_priv->binding_mutex); out_err: - vmw_resource_relocations_free(&sw_context->res_relocations); - vmw_free_relocations(sw_context); ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes); +out_err_nores: vmw_resource_list_unreserve(&sw_context->resource_list, true); + vmw_resource_relocations_free(&sw_context->res_relocations); + vmw_free_relocations(sw_context); vmw_clear_validations(sw_context); if (unlikely(dev_priv->pinned_bo != NULL && !dev_priv->query_cid_valid)) @@ -1581,6 +2554,8 @@ list_splice_init(&sw_context->resource_list, &resource_list); error_resource = sw_context->error_resource; sw_context->error_resource = NULL; + vmw_compat_shaders_revert(sw_context->fp->shman, + &sw_context->staged_shaders); mutex_unlock(&dev_priv->cmdbuf_mutex); /* --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h @@ -38,11 +38,15 @@ #define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) #define max_t(type, x, y) ((x) > (y) ? (x) : (y)) +#define min_t(type, x, y) ((x) < (y) ? (x) : (y)) #define surf_size_struct SVGA3dSize #define u32 uint32 +#define u64 uint64_t #endif /* __KERNEL__ */ +#define U32_MAX ((u32)~0U) + #include "svga3d_reg.h" /* @@ -704,8 +708,8 @@ static inline u32 clamped_umul32(u32 a, u32 b) { - uint64_t tmp = (uint64_t) a*b; - return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp; + u64 tmp = (u64) a*b; + return (tmp > (u64) U32_MAX) ? U32_MAX : tmp; } static inline const struct svga3d_surface_desc * @@ -834,7 +838,7 @@ bool cubemap) { const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format); - u32 total_size = 0; + u64 total_size = 0; u32 mip; for (mip = 0; mip < num_mip_levels; mip++) { @@ -847,7 +851,7 @@ if (cubemap) total_size *= SVGA3D_MAX_SURFACE_FACES; - return total_size; + return (u32) min_t(u64, total_size, (u64) U32_MAX); } --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -0,0 +1,656 @@ +/************************************************************************** + * + * Copyright © 2012 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "vmwgfx_drv.h" + +/* + * If we set up the screen target otable, screen objects stop working. + */ + +#define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) ? 0 : 1) + +#ifdef CONFIG_64BIT +#define VMW_PPN_SIZE 8 +#define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH64_0 +#define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH64_1 +#define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH64_2 +#else +#define VMW_PPN_SIZE 4 +#define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH_0 +#define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH_1 +#define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH_2 +#endif + +/* + * struct vmw_mob - Structure containing page table and metadata for a + * Guest Memory OBject. + * + * @num_pages Number of pages that make up the page table. + * @pt_level The indirection level of the page table. 0-2. + * @pt_root_page DMA address of the level 0 page of the page table. + */ +struct vmw_mob { + struct ttm_buffer_object *pt_bo; + unsigned long num_pages; + unsigned pt_level; + dma_addr_t pt_root_page; + uint32_t id; +}; + +/* + * struct vmw_otable - Guest Memory OBject table metadata + * + * @size: Size of the table (page-aligned). + * @page_table: Pointer to a struct vmw_mob holding the page table. + */ +struct vmw_otable { + unsigned long size; + struct vmw_mob *page_table; +}; + +static int vmw_mob_pt_populate(struct vmw_private *dev_priv, + struct vmw_mob *mob); +static void vmw_mob_pt_setup(struct vmw_mob *mob, + struct vmw_piter data_iter, + unsigned long num_data_pages); + +/* + * vmw_setup_otable_base - Issue an object table base setup command to + * the device + * + * @dev_priv: Pointer to a device private structure + * @type: Type of object table base + * @offset Start of table offset into dev_priv::otable_bo + * @otable Pointer to otable metadata; + * + * This function returns -ENOMEM if it fails to reserve fifo space, + * and may block waiting for fifo space. + */ +static int vmw_setup_otable_base(struct vmw_private *dev_priv, + SVGAOTableType type, + unsigned long offset, + struct vmw_otable *otable) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdSetOTableBase64 body; + } *cmd; + struct vmw_mob *mob; + const struct vmw_sg_table *vsgt; + struct vmw_piter iter; + int ret; + + BUG_ON(otable->page_table != NULL); + + vsgt = vmw_bo_sg_table(dev_priv->otable_bo); + vmw_piter_start(&iter, vsgt, offset >> PAGE_SHIFT); + WARN_ON(!vmw_piter_next(&iter)); + + mob = vmw_mob_create(otable->size >> PAGE_SHIFT); + if (unlikely(mob == NULL)) { + DRM_ERROR("Failed creating OTable page table.\n"); + return -ENOMEM; + } + + if (otable->size <= PAGE_SIZE) { + mob->pt_level = VMW_MOBFMT_PTDEPTH_0; + mob->pt_root_page = vmw_piter_dma_addr(&iter); + } else if (vsgt->num_regions == 1) { + mob->pt_level = SVGA3D_MOBFMT_RANGE; + mob->pt_root_page = vmw_piter_dma_addr(&iter); + } else { + ret = vmw_mob_pt_populate(dev_priv, mob); + if (unlikely(ret != 0)) + goto out_no_populate; + + vmw_mob_pt_setup(mob, iter, otable->size >> PAGE_SHIFT); + mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1; + } + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for OTable setup.\n"); + ret = -ENOMEM; + goto out_no_fifo; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE64; + cmd->header.size = sizeof(cmd->body); + cmd->body.type = type; + cmd->body.baseAddress = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT); + cmd->body.sizeInBytes = otable->size; + cmd->body.validSizeInBytes = 0; + cmd->body.ptDepth = mob->pt_level; + + /* + * The device doesn't support this, But the otable size is + * determined at compile-time, so this BUG shouldn't trigger + * randomly. + */ + BUG_ON(mob->pt_level == VMW_MOBFMT_PTDEPTH_2); + + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + otable->page_table = mob; + + return 0; + +out_no_fifo: +out_no_populate: + vmw_mob_destroy(mob); + return ret; +} + +/* + * vmw_takedown_otable_base - Issue an object table base takedown command + * to the device + * + * @dev_priv: Pointer to a device private structure + * @type: Type of object table base + * + */ +static void vmw_takedown_otable_base(struct vmw_private *dev_priv, + SVGAOTableType type, + struct vmw_otable *otable) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdSetOTableBase body; + } *cmd; + struct ttm_buffer_object *bo; + + if (otable->page_table == NULL) + return; + + bo = otable->page_table->pt_bo; + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for OTable " + "takedown.\n"); + } else { + memset(cmd, 0, sizeof(*cmd)); + cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE; + cmd->header.size = sizeof(cmd->body); + cmd->body.type = type; + cmd->body.baseAddress = 0; + cmd->body.sizeInBytes = 0; + cmd->body.validSizeInBytes = 0; + cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + } + + if (bo) { + int ret; + + ret = ttm_bo_reserve(bo, false, true, false, NULL); + BUG_ON(ret != 0); + + vmw_fence_single_bo(bo, NULL); + ttm_bo_unreserve(bo); + } + + vmw_mob_destroy(otable->page_table); + otable->page_table = NULL; +} + +/* + * vmw_otables_setup - Set up guest backed memory object tables + * + * @dev_priv: Pointer to a device private structure + * + * Takes care of the device guest backed surface + * initialization, by setting up the guest backed memory object tables. + * Returns 0 on success and various error codes on failure. A succesful return + * means the object tables can be taken down using the vmw_otables_takedown + * function. + */ +int vmw_otables_setup(struct vmw_private *dev_priv) +{ + unsigned long offset; + unsigned long bo_size; + struct vmw_otable *otables; + SVGAOTableType i; + int ret; + + otables = kzalloc(SVGA_OTABLE_DX9_MAX * sizeof(*otables), + GFP_KERNEL); + if (unlikely(otables == NULL)) { + DRM_ERROR("Failed to allocate space for otable " + "metadata.\n"); + return -ENOMEM; + } + + otables[SVGA_OTABLE_MOB].size = + VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE; + otables[SVGA_OTABLE_SURFACE].size = + VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE; + otables[SVGA_OTABLE_CONTEXT].size = + VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE; + otables[SVGA_OTABLE_SHADER].size = + VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE; + otables[SVGA_OTABLE_SCREEN_TARGET].size = + VMWGFX_NUM_GB_SCREEN_TARGET * + SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE; + + bo_size = 0; + for (i = 0; i < SVGA_OTABLE_DX9_MAX; ++i) { + otables[i].size = + (otables[i].size + PAGE_SIZE - 1) & PAGE_MASK; + bo_size += otables[i].size; + } + + ret = ttm_bo_create(&dev_priv->bdev, bo_size, + ttm_bo_type_device, + &vmw_sys_ne_placement, + 0, false, NULL, + &dev_priv->otable_bo); + + if (unlikely(ret != 0)) + goto out_no_bo; + + ret = ttm_bo_reserve(dev_priv->otable_bo, false, true, false, NULL); + BUG_ON(ret != 0); + ret = vmw_bo_driver.ttm_tt_populate(dev_priv->otable_bo->ttm); + if (unlikely(ret != 0)) + goto out_unreserve; + ret = vmw_bo_map_dma(dev_priv->otable_bo); + if (unlikely(ret != 0)) + goto out_unreserve; + + ttm_bo_unreserve(dev_priv->otable_bo); + + offset = 0; + for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i) { + ret = vmw_setup_otable_base(dev_priv, i, offset, + &otables[i]); + if (unlikely(ret != 0)) + goto out_no_setup; + offset += otables[i].size; + } + + dev_priv->otables = otables; + return 0; + +out_unreserve: + ttm_bo_unreserve(dev_priv->otable_bo); +out_no_setup: + for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i) + vmw_takedown_otable_base(dev_priv, i, &otables[i]); + + ttm_bo_unref(&dev_priv->otable_bo); +out_no_bo: + kfree(otables); + return ret; +} + + +/* + * vmw_otables_takedown - Take down guest backed memory object tables + * + * @dev_priv: Pointer to a device private structure + * + * Take down the Guest Memory Object tables. + */ +void vmw_otables_takedown(struct vmw_private *dev_priv) +{ + SVGAOTableType i; + struct ttm_buffer_object *bo = dev_priv->otable_bo; + int ret; + + for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i) + vmw_takedown_otable_base(dev_priv, i, + &dev_priv->otables[i]); + + ret = ttm_bo_reserve(bo, false, true, false, NULL); + BUG_ON(ret != 0); + + vmw_fence_single_bo(bo, NULL); + ttm_bo_unreserve(bo); + + ttm_bo_unref(&dev_priv->otable_bo); + kfree(dev_priv->otables); + dev_priv->otables = NULL; +} + + +/* + * vmw_mob_calculate_pt_pages - Calculate the number of page table pages + * needed for a guest backed memory object. + * + * @data_pages: Number of data pages in the memory object buffer. + */ +static unsigned long vmw_mob_calculate_pt_pages(unsigned long data_pages) +{ + unsigned long data_size = data_pages * PAGE_SIZE; + unsigned long tot_size = 0; + + while (likely(data_size > PAGE_SIZE)) { + data_size = DIV_ROUND_UP(data_size, PAGE_SIZE); + data_size *= VMW_PPN_SIZE; + tot_size += (data_size + PAGE_SIZE - 1) & PAGE_MASK; + } + + return tot_size >> PAGE_SHIFT; +} + +/* + * vmw_mob_create - Create a mob, but don't populate it. + * + * @data_pages: Number of data pages of the underlying buffer object. + */ +struct vmw_mob *vmw_mob_create(unsigned long data_pages) +{ + struct vmw_mob *mob = kzalloc(sizeof(*mob), GFP_KERNEL); + + if (unlikely(mob == NULL)) + return NULL; + + mob->num_pages = vmw_mob_calculate_pt_pages(data_pages); + + return mob; +} + +/* + * vmw_mob_pt_populate - Populate the mob pagetable + * + * @mob: Pointer to the mob the pagetable of which we want to + * populate. + * + * This function allocates memory to be used for the pagetable, and + * adjusts TTM memory accounting accordingly. Returns ENOMEM if + * memory resources aren't sufficient and may cause TTM buffer objects + * to be swapped out by using the TTM memory accounting function. + */ +static int vmw_mob_pt_populate(struct vmw_private *dev_priv, + struct vmw_mob *mob) +{ + int ret; + BUG_ON(mob->pt_bo != NULL); + + ret = ttm_bo_create(&dev_priv->bdev, mob->num_pages * PAGE_SIZE, + ttm_bo_type_device, + &vmw_sys_ne_placement, + 0, false, NULL, &mob->pt_bo); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_bo_reserve(mob->pt_bo, false, true, false, NULL); + + BUG_ON(ret != 0); + ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm); + if (unlikely(ret != 0)) + goto out_unreserve; + ret = vmw_bo_map_dma(mob->pt_bo); + if (unlikely(ret != 0)) + goto out_unreserve; + + ttm_bo_unreserve(mob->pt_bo); + + return 0; + +out_unreserve: + ttm_bo_unreserve(mob->pt_bo); + ttm_bo_unref(&mob->pt_bo); + + return ret; +} + +/** + * vmw_mob_assign_ppn - Assign a value to a page table entry + * + * @addr: Pointer to pointer to page table entry. + * @val: The page table entry + * + * Assigns a value to a page table entry pointed to by *@addr and increments + * *@addr according to the page table entry size. + */ +#if (VMW_PPN_SIZE == 8) +static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val) +{ + *((__le64 *) *addr) = cpu_to_le64(val >> PAGE_SHIFT); + *addr += 2; +} +#else +static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val) +{ + *(*addr)++ = cpu_to_le32(val >> PAGE_SHIFT); +} +#endif + +/* + * vmw_mob_build_pt - Build a pagetable + * + * @data_addr: Array of DMA addresses to the underlying buffer + * object's data pages. + * @num_data_pages: Number of buffer object data pages. + * @pt_pages: Array of page pointers to the page table pages. + * + * Returns the number of page table pages actually used. + * Uses atomic kmaps of highmem pages to avoid TLB thrashing. + */ +static unsigned long vmw_mob_build_pt(struct vmw_piter *data_iter, + unsigned long num_data_pages, + struct vmw_piter *pt_iter) +{ + unsigned long pt_size = num_data_pages * VMW_PPN_SIZE; + unsigned long num_pt_pages = DIV_ROUND_UP(pt_size, PAGE_SIZE); + unsigned long pt_page; + __le32 *addr, *save_addr; + unsigned long i; + struct page *page; + + for (pt_page = 0; pt_page < num_pt_pages; ++pt_page) { + page = vmw_piter_page(pt_iter); + + save_addr = addr = kmap_atomic(page); + + for (i = 0; i < PAGE_SIZE / VMW_PPN_SIZE; ++i) { + vmw_mob_assign_ppn(&addr, + vmw_piter_dma_addr(data_iter)); + if (unlikely(--num_data_pages == 0)) + break; + WARN_ON(!vmw_piter_next(data_iter)); + } + kunmap_atomic(save_addr); + vmw_piter_next(pt_iter); + } + + return num_pt_pages; +} + +/* + * vmw_mob_build_pt - Set up a multilevel mob pagetable + * + * @mob: Pointer to a mob whose page table needs setting up. + * @data_addr Array of DMA addresses to the buffer object's data + * pages. + * @num_data_pages: Number of buffer object data pages. + * + * Uses tail recursion to set up a multilevel mob page table. + */ +static void vmw_mob_pt_setup(struct vmw_mob *mob, + struct vmw_piter data_iter, + unsigned long num_data_pages) +{ + unsigned long num_pt_pages = 0; + struct ttm_buffer_object *bo = mob->pt_bo; + struct vmw_piter save_pt_iter; + struct vmw_piter pt_iter; + const struct vmw_sg_table *vsgt; + int ret; + + ret = ttm_bo_reserve(bo, false, true, false, NULL); + BUG_ON(ret != 0); + + vsgt = vmw_bo_sg_table(bo); + vmw_piter_start(&pt_iter, vsgt, 0); + BUG_ON(!vmw_piter_next(&pt_iter)); + mob->pt_level = 0; + while (likely(num_data_pages > 1)) { + ++mob->pt_level; + BUG_ON(mob->pt_level > 2); + save_pt_iter = pt_iter; + num_pt_pages = vmw_mob_build_pt(&data_iter, num_data_pages, + &pt_iter); + data_iter = save_pt_iter; + num_data_pages = num_pt_pages; + } + + mob->pt_root_page = vmw_piter_dma_addr(&save_pt_iter); + ttm_bo_unreserve(bo); +} + +/* + * vmw_mob_destroy - Destroy a mob, unpopulating first if necessary. + * + * @mob: Pointer to a mob to destroy. + */ +void vmw_mob_destroy(struct vmw_mob *mob) +{ + if (mob->pt_bo) + ttm_bo_unref(&mob->pt_bo); + kfree(mob); +} + +/* + * vmw_mob_unbind - Hide a mob from the device. + * + * @dev_priv: Pointer to a device private. + * @mob_id: Device id of the mob to unbind. + */ +void vmw_mob_unbind(struct vmw_private *dev_priv, + struct vmw_mob *mob) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDestroyGBMob body; + } *cmd; + int ret; + struct ttm_buffer_object *bo = mob->pt_bo; + + if (bo) { + ret = ttm_bo_reserve(bo, false, true, false, NULL); + /* + * Noone else should be using this buffer. + */ + BUG_ON(ret != 0); + } + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for Memory " + "Object unbinding.\n"); + } else { + cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB; + cmd->header.size = sizeof(cmd->body); + cmd->body.mobid = mob->id; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + } + if (bo) { + vmw_fence_single_bo(bo, NULL); + ttm_bo_unreserve(bo); + } + vmw_3d_resource_dec(dev_priv, false); +} + +/* + * vmw_mob_bind - Make a mob visible to the device after first + * populating it if necessary. + * + * @dev_priv: Pointer to a device private. + * @mob: Pointer to the mob we're making visible. + * @data_addr: Array of DMA addresses to the data pages of the underlying + * buffer object. + * @num_data_pages: Number of data pages of the underlying buffer + * object. + * @mob_id: Device id of the mob to bind + * + * This function is intended to be interfaced with the ttm_tt backend + * code. + */ +int vmw_mob_bind(struct vmw_private *dev_priv, + struct vmw_mob *mob, + const struct vmw_sg_table *vsgt, + unsigned long num_data_pages, + int32_t mob_id) +{ + int ret; + bool pt_set_up = false; + struct vmw_piter data_iter; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDefineGBMob64 body; + } *cmd; + + mob->id = mob_id; + vmw_piter_start(&data_iter, vsgt, 0); + if (unlikely(!vmw_piter_next(&data_iter))) + return 0; + + if (likely(num_data_pages == 1)) { + mob->pt_level = VMW_MOBFMT_PTDEPTH_0; + mob->pt_root_page = vmw_piter_dma_addr(&data_iter); + } else if (vsgt->num_regions == 1) { + mob->pt_level = SVGA3D_MOBFMT_RANGE; + mob->pt_root_page = vmw_piter_dma_addr(&data_iter); + } else if (unlikely(mob->pt_bo == NULL)) { + ret = vmw_mob_pt_populate(dev_priv, mob); + if (unlikely(ret != 0)) + return ret; + + vmw_mob_pt_setup(mob, data_iter, num_data_pages); + pt_set_up = true; + mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1; + } + + (void) vmw_3d_resource_inc(dev_priv, false); + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for Memory " + "Object binding.\n"); + goto out_no_cmd_space; + } + + cmd->header.id = SVGA_3D_CMD_DEFINE_GB_MOB64; + cmd->header.size = sizeof(cmd->body); + cmd->body.mobid = mob_id; + cmd->body.ptDepth = mob->pt_level; + cmd->body.base = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT); + cmd->body.sizeInBytes = num_data_pages * PAGE_SIZE; + + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; + +out_no_cmd_space: + vmw_3d_resource_dec(dev_priv, false); + if (pt_set_up) + ttm_bo_unref(&mob->pt_bo); + + return -ENOMEM; +} --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -125,10 +125,21 @@ return -ENOMEM; spin_lock_init(&gman->lock); - gman->max_gmr_pages = dev_priv->max_gmr_pages; gman->used_gmr_pages = 0; ida_init(&gman->gmr_ida); - gman->max_gmr_ids = p_size; + + switch (p_size) { + case VMW_PL_GMR: + gman->max_gmr_ids = dev_priv->max_gmr_ids; + gman->max_gmr_pages = dev_priv->max_gmr_pages; + break; + case VMW_PL_MOB: + gman->max_gmr_ids = VMWGFX_NUM_MOB; + gman->max_gmr_pages = dev_priv->max_mob_pages; + break; + default: + BUG(); + } man->priv = (void *) gman; return 0; } --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -112,6 +112,21 @@ #define DRM_IOCTL_VMW_UPDATE_LAYOUT \ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \ struct drm_vmw_update_layout_arg) +#define DRM_IOCTL_VMW_CREATE_SHADER \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_SHADER, \ + struct drm_vmw_shader_create_arg) +#define DRM_IOCTL_VMW_UNREF_SHADER \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_SHADER, \ + struct drm_vmw_shader_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_CREATE \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE, \ + union drm_vmw_gb_surface_create_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_REF \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF, \ + union drm_vmw_gb_surface_reference_arg) +#define DRM_IOCTL_VMW_SYNCCPU \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_SYNCCPU, \ + struct drm_vmw_synccpu_arg) /** * The core DRM version of this macro doesn't account for @@ -177,6 +192,21 @@ VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, DRM_MASTER | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_CREATE_SHADER, + vmw_shader_define_ioctl, + DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_UNREF_SHADER, + vmw_shader_destroy_ioctl, + DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE, + vmw_gb_surface_define_ioctl, + DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_GB_SURFACE_REF, + vmw_gb_surface_reference_ioctl, + DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_SYNCCPU, + vmw_user_dmabuf_synccpu_ioctl, + DRM_AUTH | DRM_UNLOCKED), }; static struct pci_device_id vmw_pci_id_list[] = { @@ -189,6 +219,7 @@ static int vmw_force_iommu; static int vmw_restrict_iommu; static int vmw_force_coherent; +static int vmw_restrict_dma_mask; static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static void vmw_master_init(struct vmw_master *); @@ -203,6 +234,8 @@ module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600); MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); module_param_named(force_coherent, vmw_force_coherent, int, 0600); +MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU"); +module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600); static void vmw_print_capabilities(uint32_t capabilities) @@ -240,38 +273,52 @@ DRM_INFO(" GMR2.\n"); if (capabilities & SVGA_CAP_SCREEN_OBJECT_2) DRM_INFO(" Screen Object 2.\n"); + if (capabilities & SVGA_CAP_COMMAND_BUFFERS) + DRM_INFO(" Command Buffers.\n"); + if (capabilities & SVGA_CAP_CMD_BUFFERS_2) + DRM_INFO(" Command Buffers 2.\n"); + if (capabilities & SVGA_CAP_GBOBJECTS) + DRM_INFO(" Guest Backed Resources.\n"); } - /** - * vmw_execbuf_prepare_dummy_query - Initialize a query result structure at - * the start of a buffer object. + * vmw_dummy_query_bo_create - create a bo to hold a dummy query result * - * @dev_priv: The device private structure. + * @dev_priv: A device private structure. * - * This function will idle the buffer using an uninterruptible wait, then - * map the first page and initialize a pending occlusion query result structure, - * Finally it will unmap the buffer. + * This function creates a small buffer object that holds the query + * result for dummy queries emitted as query barriers. + * The function will then map the first page and initialize a pending + * occlusion query result structure, Finally it will unmap the buffer. + * No interruptible waits are done within this function. * - * TODO: Since we're only mapping a single page, we should optimize the map - * to use kmap_atomic / iomap_atomic. + * Returns an error if bo creation or initialization fails. */ -static void vmw_dummy_query_bo_prepare(struct vmw_private *dev_priv) +static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) { + int ret; + struct ttm_buffer_object *bo; struct ttm_bo_kmap_obj map; volatile SVGA3dQueryResult *result; bool dummy; - int ret; - struct ttm_bo_device *bdev = &dev_priv->bdev; - struct ttm_buffer_object *bo = dev_priv->dummy_query_bo; - ttm_bo_reserve(bo, false, false, false, 0); - spin_lock(&bdev->fence_lock); - ret = ttm_bo_wait(bo, false, false, false); - spin_unlock(&bdev->fence_lock); + /* + * Create the bo as pinned, so that a tryreserve will + * immediately succeed. This is because we're the only + * user of the bo currently. + */ + ret = ttm_bo_create(&dev_priv->bdev, + PAGE_SIZE, + ttm_bo_type_device, + &vmw_sys_ne_placement, + 0, false, NULL, + &bo); + if (unlikely(ret != 0)) - (void) vmw_fallback_wait(dev_priv, false, true, 0, false, - 10*HZ); + return ret; + + ret = ttm_bo_reserve(bo, false, true, false, 0); + BUG_ON(ret != 0); ret = ttm_bo_kmap(bo, 0, 1, &map); if (likely(ret == 0)) { @@ -280,34 +327,19 @@ result->state = SVGA3D_QUERYSTATE_PENDING; result->result32 = 0xff; ttm_bo_kunmap(&map); - } else - DRM_ERROR("Dummy query buffer map failed.\n"); + } + vmw_bo_pin(bo, false); ttm_bo_unreserve(bo); -} + if (unlikely(ret != 0)) { + DRM_ERROR("Dummy query buffer map failed.\n"); + ttm_bo_unref(&bo); + } else + dev_priv->dummy_query_bo = bo; -/** - * vmw_dummy_query_bo_create - create a bo to hold a dummy query result - * - * @dev_priv: A device private structure. - * - * This function creates a small buffer object that holds the query - * result for dummy queries emitted as query barriers. - * No interruptible waits are done within this function. - * - * Returns an error if bo creation fails. - */ -static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) -{ - return ttm_bo_create(&dev_priv->bdev, - PAGE_SIZE, - ttm_bo_type_device, - &vmw_vram_sys_placement, - 0, false, NULL, - &dev_priv->dummy_query_bo); + return ret; } - static int vmw_request_device(struct vmw_private *dev_priv) { int ret; @@ -318,14 +350,24 @@ return ret; } vmw_fence_fifo_up(dev_priv->fman); + if (dev_priv->has_mob) { + ret = vmw_otables_setup(dev_priv); + if (unlikely(ret != 0)) { + DRM_ERROR("Unable to initialize " + "guest Memory OBjects.\n"); + goto out_no_mob; + } + } ret = vmw_dummy_query_bo_create(dev_priv); if (unlikely(ret != 0)) goto out_no_query_bo; - vmw_dummy_query_bo_prepare(dev_priv); return 0; out_no_query_bo: + if (dev_priv->has_mob) + vmw_otables_takedown(dev_priv); +out_no_mob: vmw_fence_fifo_down(dev_priv->fman); vmw_fifo_release(dev_priv, &dev_priv->fifo); return ret; @@ -341,10 +383,13 @@ BUG_ON(dev_priv->pinned_bo != NULL); ttm_bo_unref(&dev_priv->dummy_query_bo); + if (dev_priv->has_mob) + vmw_otables_takedown(dev_priv); vmw_fence_fifo_down(dev_priv->fman); vmw_fifo_release(dev_priv, &dev_priv->fifo); } + /** * Increase the 3d resource refcount. * If the count was prevously zero, initialize the fifo, switching to svga @@ -510,6 +555,33 @@ return 0; } +/** + * vmw_dma_masks - set required page- and dma masks + * + * @dev: Pointer to struct drm-device + * + * With 32-bit we can only handle 32 bit PFNs. Optionally set that + * restriction also for 64-bit systems. + */ +#ifdef CONFIG_INTEL_IOMMU +static int vmw_dma_masks(struct vmw_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + + if (intel_iommu_enabled && + (sizeof(unsigned long) == 4 || vmw_restrict_dma_mask)) { + DRM_INFO("Restricting DMA addresses to 44 bits.\n"); + return dma_set_mask(dev->dev, DMA_BIT_MASK(44)); + } + return 0; +} +#else +static int vmw_dma_masks(struct vmw_private *dev_priv) +{ + return 0; +} +#endif + static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) { struct vmw_private *dev_priv; @@ -532,6 +604,7 @@ mutex_init(&dev_priv->hw_mutex); mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->release_mutex); + mutex_init(&dev_priv->binding_mutex); rwlock_init(&dev_priv->resource_lock); for (i = vmw_res_context; i < vmw_res_max; ++i) { @@ -578,14 +651,9 @@ vmw_get_initial_size(dev_priv); - if (dev_priv->capabilities & SVGA_CAP_GMR) { - dev_priv->max_gmr_descriptors = - vmw_read(dev_priv, - SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH); + if (dev_priv->capabilities & SVGA_CAP_GMR2) { dev_priv->max_gmr_ids = vmw_read(dev_priv, SVGA_REG_GMR_MAX_IDS); - } - if (dev_priv->capabilities & SVGA_CAP_GMR2) { dev_priv->max_gmr_pages = vmw_read(dev_priv, SVGA_REG_GMRS_MAX_PAGES); dev_priv->memory_size = @@ -598,23 +666,45 @@ */ dev_priv->memory_size = 512*1024*1024; } + dev_priv->max_mob_pages = 0; + dev_priv->max_mob_size = 0; + if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { + uint64_t mem_size = + vmw_read(dev_priv, + SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB); + + dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE; + dev_priv->prim_bb_mem = + vmw_read(dev_priv, + SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM); + dev_priv->max_mob_size = + vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); + } else + dev_priv->prim_bb_mem = dev_priv->vram_size; + + ret = vmw_dma_masks(dev_priv); + if (unlikely(ret != 0)) { + mutex_unlock(&dev_priv->hw_mutex); + goto out_err0; + } + + if (unlikely(dev_priv->prim_bb_mem < dev_priv->vram_size)) + dev_priv->prim_bb_mem = dev_priv->vram_size; mutex_unlock(&dev_priv->hw_mutex); vmw_print_capabilities(dev_priv->capabilities); - if (dev_priv->capabilities & SVGA_CAP_GMR) { + if (dev_priv->capabilities & SVGA_CAP_GMR2) { DRM_INFO("Max GMR ids is %u\n", (unsigned)dev_priv->max_gmr_ids); - DRM_INFO("Max GMR descriptors is %u\n", - (unsigned)dev_priv->max_gmr_descriptors); - } - if (dev_priv->capabilities & SVGA_CAP_GMR2) { DRM_INFO("Max number of GMR pages is %u\n", (unsigned)dev_priv->max_gmr_pages); DRM_INFO("Max dedicated hypervisor surface memory is %u kiB\n", (unsigned)dev_priv->memory_size / 1024); } + DRM_INFO("Maximum display memory size is %u kiB\n", + dev_priv->prim_bb_mem / 1024); DRM_INFO("VRAM at 0x%08x size is %u kiB\n", dev_priv->vram_start, dev_priv->vram_size / 1024); DRM_INFO("MMIO at 0x%08x size is %u kiB\n", @@ -649,12 +739,22 @@ dev_priv->has_gmr = true; if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, - dev_priv->max_gmr_ids) != 0) { + VMW_PL_GMR) != 0) { DRM_INFO("No GMR memory available. " "Graphics memory resources are very limited.\n"); dev_priv->has_gmr = false; } + if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { + dev_priv->has_mob = true; + if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB, + VMW_PL_MOB) != 0) { + DRM_INFO("No MOB memory available. " + "3D will be disabled.\n"); + dev_priv->has_mob = false; + } + } + dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start, dev_priv->mmio_size); @@ -757,6 +857,8 @@ iounmap(dev_priv->mmio_virt); out_err3: arch_phys_wc_del(dev_priv->mmio_mtrr); + if (dev_priv->has_mob) + (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); if (dev_priv->has_gmr) (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); @@ -801,6 +903,8 @@ ttm_object_device_release(&dev_priv->tdev); iounmap(dev_priv->mmio_virt); arch_phys_wc_del(dev_priv->mmio_mtrr); + if (dev_priv->has_mob) + (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); if (dev_priv->has_gmr) (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); @@ -840,6 +944,7 @@ drm_master_put(&vmw_fp->locked_master); } + vmw_compat_shader_man_destroy(vmw_fp->shman); ttm_object_file_release(&vmw_fp->tfile); kfree(vmw_fp); } @@ -859,11 +964,17 @@ if (unlikely(vmw_fp->tfile == NULL)) goto out_no_tfile; + vmw_fp->shman = vmw_compat_shader_man_create(dev_priv); + if (IS_ERR(vmw_fp->shman)) + goto out_no_shman; + file_priv->driver_priv = vmw_fp; dev_priv->bdev.dev_mapping = dev->dev_mapping; return 0; +out_no_shman: + ttm_object_file_release(&vmw_fp->tfile); out_no_tfile: kfree(vmw_fp); return ret; --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,9 +40,9 @@ #include #include "vmwgfx_fence.h" -#define VMWGFX_DRIVER_DATE "20120209" +#define VMWGFX_DRIVER_DATE "20140228" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 4 +#define VMWGFX_DRIVER_MINOR 5 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -50,19 +50,39 @@ #define VMWGFX_MAX_VALIDATIONS 2048 #define VMWGFX_MAX_DISPLAYS 16 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768 +#define VMWGFX_ENABLE_SCREEN_TARGET_OTABLE 0 + +/* + * Perhaps we should have sysfs entries for these. + */ +#define VMWGFX_NUM_GB_CONTEXT 256 +#define VMWGFX_NUM_GB_SHADER 20000 +#define VMWGFX_NUM_GB_SURFACE 32768 +#define VMWGFX_NUM_GB_SCREEN_TARGET VMWGFX_MAX_DISPLAYS +#define VMWGFX_NUM_MOB (VMWGFX_NUM_GB_CONTEXT +\ + VMWGFX_NUM_GB_SHADER +\ + VMWGFX_NUM_GB_SURFACE +\ + VMWGFX_NUM_GB_SCREEN_TARGET) #define VMW_PL_GMR TTM_PL_PRIV0 #define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0 +#define VMW_PL_MOB TTM_PL_PRIV1 +#define VMW_PL_FLAG_MOB TTM_PL_FLAG_PRIV1 #define VMW_RES_CONTEXT ttm_driver_type0 #define VMW_RES_SURFACE ttm_driver_type1 #define VMW_RES_STREAM ttm_driver_type2 #define VMW_RES_FENCE ttm_driver_type3 +#define VMW_RES_SHADER ttm_driver_type4 + +struct vmw_compat_shader_manager; struct vmw_fpriv { struct drm_master *locked_master; struct ttm_object_file *tfile; struct list_head fence_events; + bool gb_aware; + struct vmw_compat_shader_manager *shman; }; struct vmw_dma_buffer { @@ -82,6 +102,7 @@ struct vmw_validate_buffer { struct ttm_validate_buffer base; struct drm_hash_item hash; + bool validate_as_mob; }; struct vmw_res_func; @@ -98,6 +119,7 @@ const struct vmw_res_func *func; struct list_head lru_head; /* Protected by the resource lock */ struct list_head mob_head; /* Protected by @backup reserved */ + struct list_head binding_head; /* Protected by binding_mutex */ void (*res_free) (struct vmw_resource *res); void (*hw_destroy) (struct vmw_resource *res); }; @@ -106,6 +128,7 @@ vmw_res_context, vmw_res_surface, vmw_res_stream, + vmw_res_shader, vmw_res_max }; @@ -154,6 +177,7 @@ }; struct vmw_relocation { + SVGAMobId *mob_loc; SVGAGuestPtr *location; uint32_t index; }; @@ -229,11 +253,77 @@ struct page *(*page)(struct vmw_piter *); }; +/* + * enum vmw_ctx_binding_type - abstract resource to context binding types + */ +enum vmw_ctx_binding_type { + vmw_ctx_binding_shader, + vmw_ctx_binding_rt, + vmw_ctx_binding_tex, + vmw_ctx_binding_max +}; + +/** + * struct vmw_ctx_bindinfo - structure representing a single context binding + * + * @ctx: Pointer to the context structure. NULL means the binding is not + * active. + * @res: Non ref-counted pointer to the bound resource. + * @bt: The binding type. + * @i1: Union of information needed to unbind. + */ +struct vmw_ctx_bindinfo { + struct vmw_resource *ctx; + struct vmw_resource *res; + enum vmw_ctx_binding_type bt; + bool scrubbed; + union { + SVGA3dShaderType shader_type; + SVGA3dRenderTargetType rt_type; + uint32 texture_stage; + } i1; +}; + +/** + * struct vmw_ctx_binding - structure representing a single context binding + * - suitable for tracking in a context + * + * @ctx_list: List head for context. + * @res_list: List head for bound resource. + * @bi: Binding info + */ +struct vmw_ctx_binding { + struct list_head ctx_list; + struct list_head res_list; + struct vmw_ctx_bindinfo bi; +}; + + +/** + * struct vmw_ctx_binding_state - context binding state + * + * @list: linked list of individual bindings. + * @render_targets: Render target bindings. + * @texture_units: Texture units/samplers bindings. + * @shaders: Shader bindings. + * + * Note that this structure also provides storage space for the individual + * struct vmw_ctx_binding objects, so that no dynamic allocation is needed + * for individual bindings. + * + */ +struct vmw_ctx_binding_state { + struct list_head list; + struct vmw_ctx_binding render_targets[SVGA3D_RT_MAX]; + struct vmw_ctx_binding texture_units[SVGA3D_NUM_TEXTURE_UNITS]; + struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_MAX]; +}; + struct vmw_sw_context{ struct drm_open_hash res_ht; bool res_ht_initialized; bool kernel; /**< is the called made from the kernel */ - struct ttm_object_file *tfile; + struct vmw_fpriv *fp; struct list_head validate_nodes; struct vmw_relocation relocs[VMWGFX_MAX_RELOCATIONS]; uint32_t cur_reloc; @@ -250,6 +340,8 @@ struct vmw_resource *last_query_ctx; bool needs_post_query_barrier; struct vmw_resource *error_resource; + struct vmw_ctx_binding_state staged_bindings; + struct list_head staged_shaders; }; struct vmw_legacy_display; @@ -281,6 +373,7 @@ unsigned int io_start; uint32_t vram_start; uint32_t vram_size; + uint32_t prim_bb_mem; uint32_t mmio_start; uint32_t mmio_size; uint32_t fb_max_width; @@ -290,11 +383,13 @@ __le32 __iomem *mmio_virt; int mmio_mtrr; uint32_t capabilities; - uint32_t max_gmr_descriptors; uint32_t max_gmr_ids; uint32_t max_gmr_pages; + uint32_t max_mob_pages; + uint32_t max_mob_size; uint32_t memory_size; bool has_gmr; + bool has_mob; struct mutex hw_mutex; /* @@ -370,6 +465,7 @@ struct vmw_sw_context ctx; struct mutex cmdbuf_mutex; + struct mutex binding_mutex; /** * Operating mode. @@ -415,6 +511,12 @@ * DMA mapping stuff. */ enum vmw_dma_map_mode map_mode; + + /* + * Guest Backed stuff + */ + struct ttm_buffer_object *otable_bo; + struct vmw_otable *otables; }; static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res) @@ -471,23 +573,14 @@ * Resource utilities - vmwgfx_resource.c */ struct vmw_user_resource_conv; -extern const struct vmw_user_resource_conv *user_surface_converter; -extern const struct vmw_user_resource_conv *user_context_converter; -extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv); extern void vmw_resource_unreference(struct vmw_resource **p_res); extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res); +extern struct vmw_resource * +vmw_resource_reference_unless_doomed(struct vmw_resource *res); extern int vmw_resource_validate(struct vmw_resource *res); extern int vmw_resource_reserve(struct vmw_resource *res, bool no_backup); extern bool vmw_resource_needs_backup(const struct vmw_resource *res); -extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_context_define_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_context_check(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - int id, - struct vmw_resource **p_res); extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, uint32_t handle, @@ -499,18 +592,6 @@ uint32_t handle, const struct vmw_user_resource_conv *converter, struct vmw_resource **p_res); -extern void vmw_surface_res_free(struct vmw_resource *res); -extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_surface_check(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t handle, int *id); -extern int vmw_surface_validate(struct vmw_private *dev_priv, - struct vmw_surface *srf); extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo); extern int vmw_dmabuf_init(struct vmw_private *dev_priv, struct vmw_dma_buffer *vmw_bo, @@ -519,10 +600,21 @@ void (*bo_free) (struct ttm_buffer_object *bo)); extern int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, struct ttm_object_file *tfile); +extern int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t size, + bool shareable, + uint32_t *handle, + struct vmw_dma_buffer **p_dma_buf); +extern int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, + struct vmw_dma_buffer *dma_buf, + uint32_t *handle); extern int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo, uint32_t cur_validate_node); extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo); @@ -622,10 +714,16 @@ extern struct ttm_placement vmw_vram_gmr_placement; extern struct ttm_placement vmw_vram_gmr_ne_placement; extern struct ttm_placement vmw_sys_placement; +extern struct ttm_placement vmw_sys_ne_placement; extern struct ttm_placement vmw_evictable_placement; extern struct ttm_placement vmw_srf_placement; +extern struct ttm_placement vmw_mob_placement; extern struct ttm_bo_driver vmw_bo_driver; extern int vmw_dma_quiescent(struct drm_device *dev); +extern int vmw_bo_map_dma(struct ttm_buffer_object *bo); +extern void vmw_bo_unmap_dma(struct ttm_buffer_object *bo); +extern const struct vmw_sg_table * +vmw_bo_sg_table(struct ttm_buffer_object *bo); extern void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt, unsigned long p_offs); @@ -832,6 +930,101 @@ uint32_t handle, uint32_t flags, int *prime_fd); +/* + * MemoryOBject management - vmwgfx_mob.c + */ +struct vmw_mob; +extern int vmw_mob_bind(struct vmw_private *dev_priv, struct vmw_mob *mob, + const struct vmw_sg_table *vsgt, + unsigned long num_data_pages, int32_t mob_id); +extern void vmw_mob_unbind(struct vmw_private *dev_priv, + struct vmw_mob *mob); +extern void vmw_mob_destroy(struct vmw_mob *mob); +extern struct vmw_mob *vmw_mob_create(unsigned long data_pages); +extern int vmw_otables_setup(struct vmw_private *dev_priv); +extern void vmw_otables_takedown(struct vmw_private *dev_priv); + +/* + * Context management - vmwgfx_context.c + */ + +extern const struct vmw_user_resource_conv *user_context_converter; + +extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv); + +extern int vmw_context_check(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + int id, + struct vmw_resource **p_res); +extern int vmw_context_define_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs, + const struct vmw_ctx_bindinfo *ci); +extern void +vmw_context_binding_state_transfer(struct vmw_resource *res, + struct vmw_ctx_binding_state *cbs); +extern void vmw_context_binding_res_list_kill(struct list_head *head); +extern void vmw_context_binding_res_list_scrub(struct list_head *head); +extern int vmw_context_rebind_all(struct vmw_resource *ctx); +extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx); + +/* + * Surface management - vmwgfx_surface.c + */ + +extern const struct vmw_user_resource_conv *user_surface_converter; + +extern void vmw_surface_res_free(struct vmw_resource *res); +extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_surface_check(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t handle, int *id); +extern int vmw_surface_validate(struct vmw_private *dev_priv, + struct vmw_surface *srf); + +/* + * Shader management - vmwgfx_shader.c + */ + +extern const struct vmw_user_resource_conv *user_shader_converter; + +extern int vmw_shader_define_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_compat_shader_lookup(struct vmw_compat_shader_manager *man, + SVGA3dShaderType shader_type, + u32 *user_key); +extern void vmw_compat_shaders_commit(struct vmw_compat_shader_manager *man, + struct list_head *list); +extern void vmw_compat_shaders_revert(struct vmw_compat_shader_manager *man, + struct list_head *list); +extern int vmw_compat_shader_remove(struct vmw_compat_shader_manager *man, + u32 user_key, + SVGA3dShaderType shader_type, + struct list_head *list); +extern int vmw_compat_shader_add(struct vmw_compat_shader_manager *man, + u32 user_key, const void *bytecode, + SVGA3dShaderType shader_type, + size_t size, + struct ttm_object_file *tfile, + struct list_head *list); +extern struct vmw_compat_shader_manager * +vmw_compat_shader_man_create(struct vmw_private *dev_priv); +extern void +vmw_compat_shader_man_destroy(struct vmw_compat_shader_manager *man); + /** * Inline helper functions --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -88,6 +88,11 @@ return res; } +struct vmw_resource * +vmw_resource_reference_unless_doomed(struct vmw_resource *res) +{ + return kref_get_unless_zero(&res->kref) ? res : NULL; +} /** * vmw_resource_release_id - release a resource id to the id manager. @@ -136,8 +141,12 @@ vmw_dmabuf_unreference(&res->backup); } - if (likely(res->hw_destroy != NULL)) + if (likely(res->hw_destroy != NULL)) { res->hw_destroy(res); + mutex_lock(&dev_priv->binding_mutex); + vmw_context_binding_res_list_kill(&res->binding_head); + mutex_unlock(&dev_priv->binding_mutex); + } id = res->id; if (res->res_free != NULL) @@ -215,6 +224,7 @@ res->func = func; INIT_LIST_HEAD(&res->lru_head); INIT_LIST_HEAD(&res->mob_head); + INIT_LIST_HEAD(&res->binding_head); res->id = -1; res->backup = NULL; res->backup_offset = 0; @@ -417,8 +427,7 @@ INIT_LIST_HEAD(&vmw_bo->res_list); ret = ttm_bo_init(bdev, &vmw_bo->base, size, - (user) ? ttm_bo_type_device : - ttm_bo_type_kernel, placement, + ttm_bo_type_device, placement, 0, interruptible, NULL, acc_size, NULL, bo_free); return ret; @@ -441,6 +450,21 @@ ttm_bo_unref(&bo); } +static void vmw_user_dmabuf_ref_obj_release(struct ttm_base_object *base, + enum ttm_ref_type ref_type) +{ + struct vmw_user_dma_buffer *user_bo; + user_bo = container_of(base, struct vmw_user_dma_buffer, prime.base); + + switch (ref_type) { + case TTM_REF_SYNCCPU_WRITE: + ttm_bo_synccpu_write_release(&user_bo->dma.base); + break; + default: + BUG(); + } +} + /** * vmw_user_dmabuf_alloc - Allocate a user dma buffer * @@ -471,6 +495,8 @@ } ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size, + (dev_priv->has_mob) ? + &vmw_sys_placement : &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) @@ -482,7 +508,8 @@ &user_bo->prime, shareable, ttm_buffer_type, - &vmw_user_dmabuf_release, NULL); + &vmw_user_dmabuf_release, + &vmw_user_dmabuf_ref_obj_release); if (unlikely(ret != 0)) { ttm_bo_unref(&tmp); goto out_no_base_object; @@ -515,6 +542,130 @@ vmw_user_bo->prime.base.shareable) ? 0 : -EPERM; } +/** + * vmw_user_dmabuf_synccpu_grab - Grab a struct vmw_user_dma_buffer for cpu + * access, idling previous GPU operations on the buffer and optionally + * blocking it for further command submissions. + * + * @user_bo: Pointer to the buffer object being grabbed for CPU access + * @tfile: Identifying the caller. + * @flags: Flags indicating how the grab should be performed. + * + * A blocking grab will be automatically released when @tfile is closed. + */ +static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo, + struct ttm_object_file *tfile, + uint32_t flags) +{ + struct ttm_buffer_object *bo = &user_bo->dma.base; + bool existed; + int ret; + + if (flags & drm_vmw_synccpu_allow_cs) { + struct ttm_bo_device *bdev = bo->bdev; + + spin_lock(&bdev->fence_lock); + ret = ttm_bo_wait(bo, false, true, + !!(flags & drm_vmw_synccpu_dontblock)); + spin_unlock(&bdev->fence_lock); + return ret; + } + + ret = ttm_bo_synccpu_write_grab + (bo, !!(flags & drm_vmw_synccpu_dontblock)); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_ref_object_add(tfile, &user_bo->prime.base, + TTM_REF_SYNCCPU_WRITE, &existed); + if (ret != 0 || existed) + ttm_bo_synccpu_write_release(&user_bo->dma.base); + + return ret; +} + +/** + * vmw_user_dmabuf_synccpu_release - Release a previous grab for CPU access, + * and unblock command submission on the buffer if blocked. + * + * @handle: Handle identifying the buffer object. + * @tfile: Identifying the caller. + * @flags: Flags indicating the type of release. + */ +static int vmw_user_dmabuf_synccpu_release(uint32_t handle, + struct ttm_object_file *tfile, + uint32_t flags) +{ + if (!(flags & drm_vmw_synccpu_allow_cs)) + return ttm_ref_object_base_unref(tfile, handle, + TTM_REF_SYNCCPU_WRITE); + + return 0; +} + +/** + * vmw_user_dmabuf_synccpu_release - ioctl function implementing the synccpu + * functionality. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * + * This function checks the ioctl arguments for validity and calls the + * relevant synccpu functions. + */ +int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_synccpu_arg *arg = + (struct drm_vmw_synccpu_arg *) data; + struct vmw_dma_buffer *dma_buf; + struct vmw_user_dma_buffer *user_bo; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + int ret; + + if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0 + || (arg->flags & ~(drm_vmw_synccpu_read | drm_vmw_synccpu_write | + drm_vmw_synccpu_dontblock | + drm_vmw_synccpu_allow_cs)) != 0) { + DRM_ERROR("Illegal synccpu flags.\n"); + return -EINVAL; + } + + switch (arg->op) { + case drm_vmw_synccpu_grab: + ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf); + if (unlikely(ret != 0)) + return ret; + + user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, + dma); + ret = vmw_user_dmabuf_synccpu_grab(user_bo, tfile, arg->flags); + vmw_dmabuf_unreference(&dma_buf); + if (unlikely(ret != 0 && ret != -ERESTARTSYS && + ret != -EBUSY)) { + DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n", + (unsigned int) arg->handle); + return ret; + } + break; + case drm_vmw_synccpu_release: + ret = vmw_user_dmabuf_synccpu_release(arg->handle, tfile, + arg->flags); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed synccpu release on handle 0x%08x.\n", + (unsigned int) arg->handle); + return ret; + } + break; + default: + DRM_ERROR("Invalid synccpu operation.\n"); + return -EINVAL; + } + + return 0; +} + int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -591,7 +742,8 @@ } int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, - struct vmw_dma_buffer *dma_buf) + struct vmw_dma_buffer *dma_buf, + uint32_t *handle) { struct vmw_user_dma_buffer *user_bo; @@ -599,6 +751,8 @@ return -EINVAL; user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, dma); + + *handle = user_bo->prime.base.hash.key; return ttm_ref_object_add(tfile, &user_bo->prime.base, TTM_REF_USAGE, NULL); } @@ -1291,11 +1445,54 @@ * @mem: The truct ttm_mem_reg indicating to what memory * region the move is taking place. * - * For now does nothing. + * Evicts the Guest Backed hardware resource if the backup + * buffer is being moved out of MOB memory. + * Note that this function should not race with the resource + * validation code as long as it accesses only members of struct + * resource that remain static while bo::res is !NULL and + * while we have @bo reserved. struct resource::backup is *not* a + * static member. The resource validation code will take care + * to set @bo::res to NULL, while having @bo reserved when the + * buffer is no longer bound to the resource, so @bo:res can be + * used to determine whether there is a need to unbind and whether + * it is safe to unbind. */ void vmw_resource_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) { + struct vmw_dma_buffer *dma_buf; + + if (mem == NULL) + return; + + if (bo->destroy != vmw_dmabuf_bo_free && + bo->destroy != vmw_user_dmabuf_destroy) + return; + + dma_buf = container_of(bo, struct vmw_dma_buffer, base); + + if (mem->mem_type != VMW_PL_MOB) { + struct vmw_resource *res, *n; + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_validate_buffer val_buf; + + val_buf.bo = bo; + + list_for_each_entry_safe(res, n, &dma_buf->res_list, mob_head) { + + if (unlikely(res->func->unbind == NULL)) + continue; + + (void) res->func->unbind(res, true, &val_buf); + res->backup_dirty = true; + res->res_dirty = false; + list_del_init(&res->mob_head); + } + + spin_lock(&bdev->fence_lock); + (void) ttm_bo_wait(bo, false, false, false); + spin_unlock(&bdev->fence_lock); + } } /** --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -290,8 +290,7 @@ /** * vmw_bo_pin - Pin or unpin a buffer object without moving it. * - * @bo: The buffer object. Must be reserved, and present either in VRAM - * or GMR memory. + * @bo: The buffer object. Must be reserved. * @pin: Whether to pin or unpin. * */ @@ -303,10 +302,9 @@ int ret; lockdep_assert_held(&bo->resv->lock.base); - BUG_ON(old_mem_type != TTM_PL_VRAM && - old_mem_type != VMW_PL_GMR); - pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED; + pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB + | TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED; if (pin) pl_flags |= TTM_PL_FLAG_NO_EVICT; --- linux-3.13.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ linux-3.13.0/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -40,7 +40,7 @@ * Clip @num_rects number of @rects against @clip storing the * results in @out_rects and the number of passed rects in @out_num. */ -void vmw_clip_cliprects(struct drm_clip_rect *rects, +static void vmw_clip_cliprects(struct drm_clip_rect *rects, int num_rects, struct vmw_clip_rect clip, SVGASignedRect *out_rects, @@ -423,7 +423,7 @@ struct drm_master *master; }; -void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) +static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) { struct vmw_framebuffer_surface *vfbs = vmw_framebuffer_to_vfbs(framebuffer); @@ -589,7 +589,7 @@ return ret; } -int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, +static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, @@ -665,9 +665,9 @@ if (unlikely(surface->mip_levels[0] != 1 || surface->num_sizes != 1 || - surface->sizes[0].width < mode_cmd->width || - surface->sizes[0].height < mode_cmd->height || - surface->sizes[0].depth != 1)) { + surface->base_size.width < mode_cmd->width || + surface->base_size.height < mode_cmd->height || + surface->base_size.depth != 1)) { DRM_ERROR("Incompatible surface dimensions " "for requested mode.\n"); return -EINVAL; @@ -754,7 +754,7 @@ struct vmw_dma_buffer *buffer; }; -void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) +static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) { struct vmw_framebuffer_dmabuf *vfbd = vmw_framebuffer_to_vfbd(framebuffer); @@ -940,7 +940,7 @@ return ret; } -int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, +static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, @@ -1631,7 +1631,7 @@ uint32_t pitch, uint32_t height) { - return ((u64) pitch * (u64) height) < (u64) dev_priv->vram_size; + return ((u64) pitch * (u64) height) < (u64) dev_priv->prim_bb_mem; } @@ -1663,7 +1663,7 @@ * Small shared kms functions. */ -int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, +static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, struct drm_vmw_rect *rects) { struct drm_device *dev = dev_priv->dev; --- linux-3.13.0.orig/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ linux-3.13.0/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -104,6 +104,15 @@ { struct rcar_du_group *rgrp = plane->group; unsigned int index = plane->hwindex; + u32 mwr; + + /* Memory pitch (expressed in pixels) */ + if (plane->format->planes == 2) + mwr = plane->pitch; + else + mwr = plane->pitch * 8 / plane->format->bpp; + + rcar_du_plane_write(rgrp, index, PnMWR, mwr); /* The Y position is expressed in raster line units and must be doubled * for 32bpp formats, according to the R8A7790 datasheet. No mention of @@ -133,6 +142,8 @@ { struct drm_gem_cma_object *gem; + plane->pitch = fb->pitches[0]; + gem = drm_fb_cma_get_gem_obj(fb, 0); plane->dma[0] = gem->paddr + fb->offsets[0]; @@ -209,7 +220,6 @@ struct rcar_du_group *rgrp = plane->group; u32 ddcr2 = PnDDCR2_CODE; u32 ddcr4; - u32 mwr; /* Data format * @@ -240,14 +250,6 @@ rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); - /* Memory pitch (expressed in pixels) */ - if (plane->format->planes == 2) - mwr = plane->pitch; - else - mwr = plane->pitch * 8 / plane->format->bpp; - - rcar_du_plane_write(rgrp, index, PnMWR, mwr); - /* Destination position and size */ rcar_du_plane_write(rgrp, index, PnDSXR, plane->width); rcar_du_plane_write(rgrp, index, PnDSYR, plane->height); @@ -309,7 +311,6 @@ rplane->crtc = crtc; rplane->format = format; - rplane->pitch = fb->pitches[0]; rplane->src_x = src_x >> 16; rplane->src_y = src_y >> 16; --- linux-3.13.0.orig/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ linux-3.13.0/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -371,7 +371,6 @@ goto error; rcrtc->plane->format = format; - rcrtc->plane->pitch = crtc->fb->pitches[0]; rcrtc->plane->src_x = x; rcrtc->plane->src_y = y; --- linux-3.13.0.orig/drivers/gpu/drm/radeon/r600_cs.c +++ linux-3.13.0/drivers/gpu/drm/radeon/r600_cs.c @@ -749,7 +749,10 @@ } for (i = 0; i < 8; i++) { - if ((tmp >> (i * 4)) & 0xF) { + u32 format = G_0280A0_FORMAT(track->cb_color_info[i]); + + if (format != V_0280A0_COLOR_INVALID && + (tmp >> (i * 4)) & 0xF) { /* at least one component is enabled */ if (track->cb_color_bo[i] == NULL) { dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n", --- linux-3.13.0.orig/drivers/gpu/drm/radeon/sid.h +++ linux-3.13.0/drivers/gpu/drm/radeon/sid.h @@ -815,7 +815,7 @@ # define GRPH_PFLIP_INT_MASK (1 << 0) # define GRPH_PFLIP_INT_TYPE (1 << 8) -#define DACA_AUTODETECT_INT_CONTROL 0x66c8 +#define DAC_AUTODETECT_INT_CONTROL 0x67c8 #define DC_HPD1_INT_STATUS 0x601c #define DC_HPD2_INT_STATUS 0x6028 --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_mode.h +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_mode.h @@ -766,6 +766,7 @@ int x, int y); extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, + unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_atombios.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_atombios.c @@ -3944,6 +3944,10 @@ /* tell the bios not to handle mode switching */ bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH; + /* clear the vbios dpms state */ + if (ASIC_IS_DCE4(rdev)) + bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE; + if (rdev->family >= CHIP_R600) { WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/rv770.c +++ linux-3.13.0/drivers/gpu/drm/radeon/rv770.c @@ -1665,14 +1665,6 @@ rv770_mc_program(rdev); - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = r600_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - if (rdev->flags & RADEON_IS_AGP) { rv770_agp_enable(rdev); } else { @@ -1876,6 +1868,14 @@ if (r) return r; + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = r600_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -1921,9 +1921,9 @@ radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); - rv770_pcie_gart_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); + rv770_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_kms.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_kms.c @@ -33,6 +33,13 @@ #include #include #include + +#if defined(CONFIG_VGA_SWITCHEROO) +bool radeon_is_px(void); +#else +static inline bool radeon_is_px(void) { return false; } +#endif + /** * radeon_driver_unload_kms - Main unload function for KMS. * @@ -130,7 +137,8 @@ "Error during ACPI methods call\n"); } - if (radeon_runtime_pm != 0) { + if ((radeon_runtime_pm == 1) || + ((radeon_runtime_pm == -1) && radeon_is_px())) { pm_runtime_use_autosuspend(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, 5000); pm_runtime_set_active(dev->dev); @@ -530,6 +538,10 @@ radeon_vm_init(rdev, &fpriv->vm); + r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); + if (r) + return r; + /* map the ib pool buffer read only into * virtual address space */ bo_va = radeon_vm_bo_add(rdev, &fpriv->vm, @@ -537,6 +549,8 @@ r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET, RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); + + radeon_bo_unreserve(rdev->ring_tmp_bo.bo); if (r) { radeon_vm_fini(rdev, &fpriv->vm); kfree(fpriv); @@ -712,7 +726,7 @@ /* Helper routine in DRM core does all the work: */ return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, vblank_time, flags, - drmcrtc); + drmcrtc, &drmcrtc->hwmode); } #define KMS_INVALID_IOCTL(name) \ --- linux-3.13.0.orig/drivers/gpu/drm/radeon/atombios_crtc.c +++ linux-3.13.0/drivers/gpu/drm/radeon/atombios_crtc.c @@ -209,6 +209,16 @@ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +static const u32 vga_control_regs[6] = +{ + AVIVO_D1VGA_CONTROL, + AVIVO_D2VGA_CONTROL, + EVERGREEN_D3VGA_CONTROL, + EVERGREEN_D4VGA_CONTROL, + EVERGREEN_D5VGA_CONTROL, + EVERGREEN_D6VGA_CONTROL, +}; + static void atombios_blank_crtc(struct drm_crtc *crtc, int state) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -216,13 +226,23 @@ struct radeon_device *rdev = dev->dev_private; int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); BLANK_CRTC_PS_ALLOCATION args; + u32 vga_control = 0; memset(&args, 0, sizeof(args)); + if (ASIC_IS_DCE8(rdev)) { + vga_control = RREG32(vga_control_regs[radeon_crtc->crtc_id]); + WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control | 1); + } + args.ucCRTC = radeon_crtc->crtc_id; args.ucBlanking = state; atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + if (ASIC_IS_DCE8(rdev)) { + WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control); + } } static void atombios_powergate_crtc(struct drm_crtc *crtc, int state) @@ -938,11 +958,14 @@ radeon_atombios_get_ppll_ss_info(rdev, &radeon_crtc->ss, ATOM_DP_SS_ID1); - } else + } else { radeon_crtc->ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &radeon_crtc->ss, ATOM_DP_SS_ID1); + } + /* disable spread spectrum on DCE3 DP */ + radeon_crtc->ss_enabled = false; } break; case ATOM_ENCODER_MODE_LVDS: @@ -1146,7 +1169,7 @@ evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); /* Set NUM_BANKS. */ - if (rdev->family >= CHIP_BONAIRE) { + if (rdev->family >= CHIP_TAHITI) { unsigned tileb, index, num_banks, tile_split_bytes; /* Calculate the macrotile mode index. */ @@ -1164,13 +1187,14 @@ return -EINVAL; } - num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; + if (rdev->family >= CHIP_BONAIRE) + num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; + else + num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3; fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks); } else { - /* SI and older. */ - if (rdev->family >= CHIP_TAHITI) - tmp = rdev->config.si.tile_config; - else if (rdev->family >= CHIP_CAYMAN) + /* NI and older. */ + if (rdev->family >= CHIP_CAYMAN) tmp = rdev->config.cayman.tile_config; else tmp = rdev->config.evergreen.tile_config; @@ -1743,6 +1767,20 @@ return ATOM_PPLL1; DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; + } else if (ASIC_IS_DCE41(rdev)) { + /* Don't share PLLs on DCE4.1 chips */ + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { + if (rdev->clock.dp_extclk) + /* skip PPLL programming if using ext clock */ + return ATOM_PPLL_INVALID; + } + pll_in_use = radeon_get_pll_use_mask(crtc); + if (!(pll_in_use & (1 << ATOM_PPLL1))) + return ATOM_PPLL1; + if (!(pll_in_use & (1 << ATOM_PPLL2))) + return ATOM_PPLL2; + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; } else if (ASIC_IS_DCE4(rdev)) { /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, * depending on the asic: @@ -1770,7 +1808,7 @@ if (pll != ATOM_PPLL_INVALID) return pll; } - } else if (!ASIC_IS_DCE41(rdev)) { /* Don't share PLLs on DCE4.1 chips */ + } else { /* use the same PPLL for all monitors with the same clock */ pll = radeon_get_shared_nondp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) --- linux-3.13.0.orig/drivers/gpu/drm/radeon/evergreen_cs.c +++ linux-3.13.0/drivers/gpu/drm/radeon/evergreen_cs.c @@ -967,7 +967,10 @@ if (track->cb_dirty) { tmp = track->cb_target_mask; for (i = 0; i < 8; i++) { - if ((tmp >> (i * 4)) & 0xF) { + u32 format = G_028C70_FORMAT(track->cb_color_info[i]); + + if (format != V_028C70_COLOR_INVALID && + (tmp >> (i * 4)) & 0xF) { /* at least one component is enabled */ if (track->cb_color_bo[i] == NULL) { dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n", --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_drv.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_drv.c @@ -109,6 +109,7 @@ void radeon_gem_object_close(struct drm_gem_object *obj, struct drm_file *file_priv); extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, + unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime); extern const struct drm_ioctl_desc radeon_ioctls_kms[]; @@ -400,6 +401,9 @@ if (radeon_runtime_pm == 0) return -EINVAL; + if (radeon_runtime_pm == -1 && !radeon_is_px()) + return -EINVAL; + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(drm_dev); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); @@ -422,6 +426,9 @@ if (radeon_runtime_pm == 0) return -EINVAL; + if (radeon_runtime_pm == -1 && !radeon_is_px()) + return -EINVAL; + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; pci_set_power_state(pdev, PCI_D0); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_ttm.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_ttm.c @@ -712,6 +712,9 @@ DRM_ERROR("Failed initializing VRAM heap.\n"); return r; } + /* Change the size here instead of the init above so only lpfn is affected */ + radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); + r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->stollen_vga_memory); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/dce6_afmt.c +++ linux-3.13.0/drivers/gpu/drm/radeon/dce6_afmt.c @@ -283,7 +283,7 @@ bool enable) { WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL, - AUDIO_ENABLED); + enable ? AUDIO_ENABLED : 0); DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id); } --- linux-3.13.0.orig/drivers/gpu/drm/radeon/cik_sdma.c +++ linux-3.13.0/drivers/gpu/drm/radeon/cik_sdma.c @@ -88,6 +88,35 @@ } /** + * cik_sdma_hdp_flush_ring_emit - emit an hdp flush on the DMA ring + * + * @rdev: radeon_device pointer + * @ridx: radeon ring index + * + * Emit an hdp flush packet on the requested DMA ring. + */ +static void cik_sdma_hdp_flush_ring_emit(struct radeon_device *rdev, + int ridx) +{ + struct radeon_ring *ring = &rdev->ring[ridx]; + u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) | + SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */ + u32 ref_and_mask; + + if (ridx == R600_RING_TYPE_DMA_INDEX) + ref_and_mask = SDMA0; + else + ref_and_mask = SDMA1; + + radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); + radeon_ring_write(ring, GPU_HDP_FLUSH_DONE); + radeon_ring_write(ring, GPU_HDP_FLUSH_REQ); + radeon_ring_write(ring, ref_and_mask); /* reference */ + radeon_ring_write(ring, ref_and_mask); /* mask */ + radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */ +} + +/** * cik_sdma_fence_ring_emit - emit a fence on the DMA ring * * @rdev: radeon_device pointer @@ -111,12 +140,7 @@ /* generate an interrupt */ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0)); /* flush HDP */ - /* We should be using the new POLL_REG_MEM special op packet here - * but it causes sDMA to hang sometimes - */ - radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); - radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); - radeon_ring_write(ring, 0); + cik_sdma_hdp_flush_ring_emit(rdev, fence->ring); } /** @@ -169,6 +193,8 @@ WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl); WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0); } + rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; + rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false; } /** @@ -196,6 +222,11 @@ u32 me_cntl, reg_offset; int i; + if (enable == false) { + cik_sdma_gfx_stop(rdev); + cik_sdma_rlc_stop(rdev); + } + for (i = 0; i < 2; i++) { if (i == 0) reg_offset = SDMA0_REGISTER_OFFSET; @@ -323,10 +354,6 @@ if (!rdev->sdma_fw) return -EINVAL; - /* stop the gfx rings and rlc compute queues */ - cik_sdma_gfx_stop(rdev); - cik_sdma_rlc_stop(rdev); - /* halt the MEs */ cik_sdma_enable(rdev, false); @@ -395,9 +422,6 @@ */ void cik_sdma_fini(struct radeon_device *rdev) { - /* stop the gfx rings and rlc compute queues */ - cik_sdma_gfx_stop(rdev); - cik_sdma_rlc_stop(rdev); /* halt the MEs */ cik_sdma_enable(rdev, false); radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]); @@ -747,12 +771,7 @@ radeon_ring_write(ring, VMID(0)); /* flush HDP */ - /* We should be using the new POLL_REG_MEM special op packet here - * but it causes sDMA to hang sometimes - */ - radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); - radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); - radeon_ring_write(ring, 0); + cik_sdma_hdp_flush_ring_emit(rdev, ridx); /* flush TLB */ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_semaphore.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -34,14 +34,15 @@ int radeon_semaphore_create(struct radeon_device *rdev, struct radeon_semaphore **semaphore) { + uint32_t *cpu_addr; int i, r; *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL); if (*semaphore == NULL) { return -ENOMEM; } - r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, - &(*semaphore)->sa_bo, 8, 8, true); + r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo, + 8 * RADEON_NUM_SYNCS, 8, true); if (r) { kfree(*semaphore); *semaphore = NULL; @@ -49,7 +50,10 @@ } (*semaphore)->waiters = 0; (*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo); - *((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0; + + cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo); + for (i = 0; i < RADEON_NUM_SYNCS; ++i) + cpu_addr[i] = 0; for (i = 0; i < RADEON_NUM_RINGS; ++i) (*semaphore)->sync_to[i] = NULL; @@ -125,6 +129,7 @@ struct radeon_semaphore *semaphore, int ring) { + unsigned count = 0; int i, r; for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -140,6 +145,12 @@ return -EINVAL; } + if (++count > RADEON_NUM_SYNCS) { + /* not enough room, wait manually */ + radeon_fence_wait_locked(fence); + continue; + } + /* allocate enough space for sync command */ r = radeon_ring_alloc(rdev, &rdev->ring[i], 16); if (r) { @@ -164,6 +175,8 @@ radeon_ring_commit(rdev, &rdev->ring[i]); radeon_fence_note_sync(fence, ring); + + semaphore->gpu_addr += 8; } return 0; --- linux-3.13.0.orig/drivers/gpu/drm/radeon/si.c +++ linux-3.13.0/drivers/gpu/drm/radeon/si.c @@ -5566,7 +5566,7 @@ } if (!ASIC_IS_NODCE(rdev)) { - WREG32(DACA_AUTODETECT_INT_CONTROL, 0); + WREG32(DAC_AUTODETECT_INT_CONTROL, 0); tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY; WREG32(DC_HPD1_INT_CONTROL, tmp); @@ -6222,6 +6222,10 @@ break; } break; + case 124: /* UVD */ + DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); + radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); + break; case 146: case 147: addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); @@ -6324,15 +6328,6 @@ si_mc_program(rdev); - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || - !rdev->rlc_fw || !rdev->mc_fw) { - r = si_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - r = si_mc_load_microcode(rdev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); @@ -6600,6 +6595,15 @@ if (r) return r; + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || + !rdev->rlc_fw || !rdev->mc_fw) { + r = si_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_uvd.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_uvd.c @@ -91,6 +91,7 @@ case CHIP_VERDE: case CHIP_PITCAIRN: case CHIP_ARUBA: + case CHIP_OLAND: fw_name = FIRMWARE_TAHITI; break; @@ -170,6 +171,8 @@ radeon_bo_unref(&rdev->uvd.vcpu_bo); + radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]); + release_firmware(rdev->uvd_fw); } --- linux-3.13.0.orig/drivers/gpu/drm/radeon/ni_dpm.c +++ linux-3.13.0/drivers/gpu/drm/radeon/ni_dpm.c @@ -2586,7 +2586,7 @@ if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT)) enable_sq_ramping = false; - if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) + if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) enable_sq_ramping = false; for (i = 0; i < state->performance_level_count; i++) { --- linux-3.13.0.orig/drivers/gpu/drm/radeon/nid.h +++ linux-3.13.0/drivers/gpu/drm/radeon/nid.h @@ -1154,6 +1154,7 @@ # define PACKET3_DB_ACTION_ENA (1 << 26) # define PACKET3_SH_ACTION_ENA (1 << 27) # define PACKET3_SX_ACTION_ENA (1 << 28) +# define PACKET3_ENGINE_ME (1 << 31) #define PACKET3_ME_INITIALIZE 0x44 #define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16) #define PACKET3_COND_WRITE 0x45 --- linux-3.13.0.orig/drivers/gpu/drm/radeon/evergreen_smc.h +++ linux-3.13.0/drivers/gpu/drm/radeon/evergreen_smc.h @@ -57,7 +57,7 @@ #define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100 -#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x0 +#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x8 #define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable 0xC #define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20 --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_display.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_display.c @@ -306,7 +306,7 @@ * to complete in this vblank? */ if (update_pending && - (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, + (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, &vpos, &hpos, NULL, NULL)) && ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) { @@ -1601,6 +1601,7 @@ * * \param dev Device to query. * \param crtc Crtc to query. + * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). * \param *vpos Location where vertical scanout position should be stored. * \param *hpos Location where horizontal scanout position should go. * \param *stime Target location for timestamp taken immediately before @@ -1622,8 +1623,8 @@ * unknown small number of scanlines wrt. real scanout position. * */ -int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos, - ktime_t *stime, ktime_t *etime) +int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, + int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) { u32 stat_crtc = 0, vbl = 0, position = 0; int vbl_start, vbl_end, vtotal, ret = 0; --- linux-3.13.0.orig/drivers/gpu/drm/radeon/uvd_v2_2.c +++ linux-3.13.0/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -153,6 +153,7 @@ chip_id = 0x01000015; break; case CHIP_PITCAIRN: + case CHIP_OLAND: chip_id = 0x01000016; break; case CHIP_ARUBA: --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_ring.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_ring.c @@ -139,7 +139,7 @@ } /* 64 dwords should be enough for fence too */ - r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 8); + r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8); if (r) { dev_err(rdev->dev, "scheduling IB failed (%d).\n", r); return r; --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon.h +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon.h @@ -134,6 +134,9 @@ /* R600+ */ #define R600_RING_TYPE_UVD_INDEX 5 +/* number of hw syncs before falling back on blocking */ +#define RADEON_NUM_SYNCS 4 + /* hardcode those limit for now */ #define RADEON_VA_IB_OFFSET (1 << 20) #define RADEON_VA_RESERVED_SIZE (8 << 20) @@ -544,7 +547,6 @@ /* * Semaphores. */ -/* everything here is constant */ struct radeon_semaphore { struct radeon_sa_bo *sa_bo; signed waiters; --- linux-3.13.0.orig/drivers/gpu/drm/radeon/r600d.h +++ linux-3.13.0/drivers/gpu/drm/radeon/r600d.h @@ -1575,6 +1575,7 @@ # define PACKET3_CP_DMA_CMD_DAIC (1 << 29) #define PACKET3_SURFACE_SYNC 0x43 # define PACKET3_CB0_DEST_BASE_ENA (1 << 6) +# define PACKET3_FULL_CACHE_ENA (1 << 20) /* r7xx+ only */ # define PACKET3_TC_ACTION_ENA (1 << 23) # define PACKET3_VC_ACTION_ENA (1 << 24) # define PACKET3_CB_ACTION_ENA (1 << 25) --- linux-3.13.0.orig/drivers/gpu/drm/radeon/atombios_encoders.c +++ linux-3.13.0/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1313,7 +1313,7 @@ } if (is_dp) args.v5.ucLaneNum = dp_lane_count; - else if (radeon_encoder->pixel_clock > 165000) + else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) args.v5.ucLaneNum = 8; else args.v5.ucLaneNum = 4; --- linux-3.13.0.orig/drivers/gpu/drm/radeon/evergreen.c +++ linux-3.13.0/drivers/gpu/drm/radeon/evergreen.c @@ -4298,8 +4298,8 @@ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } - /* only one DAC on DCE6 */ - if (!ASIC_IS_DCE6(rdev)) + /* only one DAC on DCE5 */ + if (!ASIC_IS_DCE5(rdev)) WREG32(DACA_AUTODETECT_INT_CONTROL, 0); WREG32(DACB_AUTODETECT_INT_CONTROL, 0); @@ -5110,26 +5110,11 @@ evergreen_mc_program(rdev); if (ASIC_IS_DCE5(rdev)) { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { - r = ni_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } r = ni_mc_load_microcode(rdev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); return r; } - } else { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = r600_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } } if (rdev->flags & RADEON_IS_AGP) { @@ -5357,6 +5342,24 @@ if (r) return r; + if (ASIC_IS_DCE5(rdev)) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { + r = ni_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } else { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = r600_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } + rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -5418,9 +5421,9 @@ radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); - evergreen_pcie_gart_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); + evergreen_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_pm.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_pm.c @@ -1010,8 +1010,10 @@ rdev->pm.current_clock_mode_index = 0; rdev->pm.current_sclk = rdev->pm.default_sclk; rdev->pm.current_mclk = rdev->pm.default_mclk; - rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; - rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; + if (rdev->pm.power_state) { + rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; + } if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; @@ -1228,6 +1230,9 @@ case CHIP_RV670: case CHIP_RS780: case CHIP_RS880: + case CHIP_BARTS: + case CHIP_TURKS: + case CHIP_CAICOS: case CHIP_CAYMAN: case CHIP_BONAIRE: case CHIP_KABINI: @@ -1257,9 +1262,6 @@ case CHIP_PALM: case CHIP_SUMO: case CHIP_SUMO2: - case CHIP_BARTS: - case CHIP_TURKS: - case CHIP_CAICOS: case CHIP_ARUBA: case CHIP_TAHITI: case CHIP_PITCAIRN: @@ -1464,7 +1466,7 @@ */ for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { if (rdev->pm.active_crtcs & (1 << crtc)) { - vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos, NULL, NULL); + vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL); if ((vbl_status & DRM_SCANOUTPOS_VALID) && !(vbl_status & DRM_SCANOUTPOS_INVBL)) in_vbl = false; --- linux-3.13.0.orig/drivers/gpu/drm/radeon/si_dpm.c +++ linux-3.13.0/drivers/gpu/drm/radeon/si_dpm.c @@ -2396,7 +2396,7 @@ if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT)) enable_sq_ramping = false; - if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) + if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) enable_sq_ramping = false; for (i = 0; i < state->performance_level_count; i++) { @@ -3591,10 +3591,9 @@ /* Setting this to false forces the performance state to low if the crtcs are disabled. * This can be a problem on PowerXpress systems or if you want to use the card - * for offscreen rendering or compute if there are no crtcs enabled. Set it to - * true for now so that performance scales even if the displays are off. + * for offscreen rendering or compute if there are no crtcs enabled. */ - si_notify_smc_display_change(rdev, true /*rdev->pm.dpm.new_active_crtc_count > 0*/); + si_notify_smc_display_change(rdev, rdev->pm.dpm.new_active_crtc_count > 0); } static void si_enable_spread_spectrum(struct radeon_device *rdev, bool enable) @@ -5414,7 +5413,7 @@ for (i = 0, j = 0; j < si_pi->mc_reg_table.last; j++) { if (si_pi->mc_reg_table.valid_flag & (1 << j)) { - if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) + if (i >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) break; mc_reg_table->address[i].s0 = cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s0); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_i2c.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1020,6 +1020,9 @@ /* Add the default buses */ void radeon_i2c_init(struct radeon_device *rdev) { + if (radeon_hw_i2c) + DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n"); + if (rdev->is_atom_bios) radeon_atombios_i2c_init(rdev); else --- linux-3.13.0.orig/drivers/gpu/drm/radeon/ni.c +++ linux-3.13.0/drivers/gpu/drm/radeon/ni.c @@ -1330,13 +1330,12 @@ { struct radeon_ring *ring = &rdev->ring[fence->ring]; u64 addr = rdev->fence_drv[fence->ring].gpu_addr; + u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA | + PACKET3_SH_ACTION_ENA; /* flush read cache over gart for this vmid */ - radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); - radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2); - radeon_ring_write(ring, 0); radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); - radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA); + radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl); radeon_ring_write(ring, 0xFFFFFFFF); radeon_ring_write(ring, 0); radeon_ring_write(ring, 10); /* poll interval */ @@ -1352,6 +1351,8 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) { struct radeon_ring *ring = &rdev->ring[ib->ring]; + u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA | + PACKET3_SH_ACTION_ENA; /* set to DX10/11 mode */ radeon_ring_write(ring, PACKET3(PACKET3_MODE_CONTROL, 0)); @@ -1376,14 +1377,11 @@ (ib->vm ? (ib->vm->id << 24) : 0)); /* flush read cache over gart for this vmid */ - radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); - radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2); - radeon_ring_write(ring, ib->vm ? ib->vm->id : 0); radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); - radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA); + radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl); radeon_ring_write(ring, 0xFFFFFFFF); radeon_ring_write(ring, 0); - radeon_ring_write(ring, 10); /* poll interval */ + radeon_ring_write(ring, ((ib->vm ? ib->vm->id : 0) << 24) | 10); /* poll interval */ } static void cayman_cp_enable(struct radeon_device *rdev, bool enable) @@ -1878,23 +1876,7 @@ evergreen_mc_program(rdev); - if (rdev->flags & RADEON_IS_IGP) { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = ni_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - } else { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { - r = ni_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - + if (!(rdev->flags & RADEON_IS_IGP)) { r = ni_mc_load_microcode(rdev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); @@ -2145,6 +2127,24 @@ if (r) return r; + if (rdev->flags & RADEON_IS_IGP) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = ni_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } else { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { + r = ni_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } + ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/r600.c +++ linux-3.13.0/drivers/gpu/drm/radeon/r600.c @@ -2607,14 +2607,17 @@ struct radeon_fence *fence) { struct radeon_ring *ring = &rdev->ring[fence->ring]; + u32 cp_coher_cntl = PACKET3_TC_ACTION_ENA | PACKET3_VC_ACTION_ENA | + PACKET3_SH_ACTION_ENA; + + if (rdev->family >= CHIP_RV770) + cp_coher_cntl |= PACKET3_FULL_CACHE_ENA; if (rdev->wb.use_event) { u64 addr = rdev->fence_drv[fence->ring].gpu_addr; /* flush read cache over gart */ radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); - radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | - PACKET3_VC_ACTION_ENA | - PACKET3_SH_ACTION_ENA); + radeon_ring_write(ring, cp_coher_cntl); radeon_ring_write(ring, 0xFFFFFFFF); radeon_ring_write(ring, 0); radeon_ring_write(ring, 10); /* poll interval */ @@ -2628,9 +2631,7 @@ } else { /* flush read cache over gart */ radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); - radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | - PACKET3_VC_ACTION_ENA | - PACKET3_SH_ACTION_ENA); + radeon_ring_write(ring, cp_coher_cntl); radeon_ring_write(ring, 0xFFFFFFFF); radeon_ring_write(ring, 0); radeon_ring_write(ring, 10); /* poll interval */ @@ -2775,14 +2776,6 @@ r600_mc_program(rdev); - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = r600_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - if (rdev->flags & RADEON_IS_AGP) { r600_agp_enable(rdev); } else { @@ -2970,6 +2963,14 @@ if (r) return r; + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = r600_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -3903,6 +3904,10 @@ break; } break; + case 124: /* UVD */ + DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); + radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); + break; case 176: /* CP_INT in ring buffer */ case 177: /* CP_INT in IB1 */ case 178: /* CP_INT in IB2 */ --- linux-3.13.0.orig/drivers/gpu/drm/radeon/rv770_dpm.c +++ linux-3.13.0/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2531,6 +2531,12 @@ (rdev->pdev->subsystem_device == 0x1c42)) switch_limit = 200; + /* RV770 */ + /* mclk switching doesn't seem to work reliably on desktop RV770s */ + if ((rdev->family == CHIP_RV770) && + !(rdev->flags & RADEON_IS_MOBILITY)) + switch_limit = 0xffffffff; /* disable mclk switching */ + if (vblank_time < switch_limit) return true; else --- linux-3.13.0.orig/drivers/gpu/drm/radeon/cik.c +++ linux-3.13.0/drivers/gpu/drm/radeon/cik.c @@ -3566,8 +3566,6 @@ struct radeon_semaphore *semaphore, bool emit_wait) { -/* TODO: figure out why semaphore cause lockups */ -#if 0 uint64_t addr = semaphore->gpu_addr; unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL; @@ -3576,9 +3574,6 @@ radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel); return true; -#else - return false; -#endif } /** @@ -4074,8 +4069,11 @@ { if (enable) WREG32(CP_MEC_CNTL, 0); - else + else { WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT)); + rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false; + rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false; + } udelay(50); } @@ -7503,26 +7501,7 @@ cik_mc_program(rdev); - if (rdev->flags & RADEON_IS_IGP) { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || - !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) { - r = cik_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - } else { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || - !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw || - !rdev->mc_fw) { - r = cik_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - + if (!(rdev->flags & RADEON_IS_IGP)) { r = ci_mc_load_microcode(rdev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); @@ -7835,6 +7814,27 @@ if (r) return r; + if (rdev->flags & RADEON_IS_IGP) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || + !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) { + r = cik_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } else { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || + !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw || + !rdev->mc_fw) { + r = cik_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } + ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); --- linux-3.13.0.orig/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ linux-3.13.0/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -219,7 +219,8 @@ memcpy(&output, info->buffer.pointer, size); /* TODO: check version? */ - printk("ATPX version %u\n", output.version); + printk("ATPX version %u, functions 0x%08x\n", + output.version, output.function_bits); radeon_atpx_parse_functions(&atpx->functions, output.function_bits); --- linux-3.13.0.orig/drivers/gpu/drm/i915/i915_dma.c +++ linux-3.13.0/drivers/gpu/drm/i915/i915_dma.c @@ -1679,6 +1679,7 @@ intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); + pm_qos_remove_request(&dev_priv->pm_qos); destroy_workqueue(dev_priv->wq); out_mtrrfree: arch_phys_wc_del(dev_priv->gtt.mtrr); @@ -1910,6 +1911,7 @@ DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); --- linux-3.13.0.orig/drivers/gpu/drm/i915/intel_ringbuffer.h +++ linux-3.13.0/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -233,6 +233,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); +int __must_check intel_ring_cacheline_align(struct intel_ring_buffer *ring); static inline void intel_ring_emit(struct intel_ring_buffer *ring, u32 data) { --- linux-3.13.0.orig/drivers/gpu/drm/i915/intel_display.c +++ linux-3.13.0/drivers/gpu/drm/i915/intel_display.c @@ -8335,6 +8335,20 @@ if (ring->id == RCS) len += 6; + /* + * BSpec MI_DISPLAY_FLIP for IVB: + * "The full packet must be contained within the same cache line." + * + * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same + * cacheline, if we ever start emitting more commands before + * the MI_DISPLAY_FLIP we may need to first emit everything else, + * then do the cacheline alignment, and finally emit the + * MI_DISPLAY_FLIP. + */ + ret = intel_ring_cacheline_align(ring); + if (ret) + goto err_unpin; + ret = intel_ring_begin(ring, len); if (ret) goto err_unpin; @@ -9449,7 +9463,8 @@ * are later needed by vblank and swap-completion * timestamping. They are derived from true hwmode. */ - drm_calc_timestamping_constants(crtc); + drm_calc_timestamping_constants(crtc, + &pipe_config->adjusted_mode); } /* FIXME: add subpixel order */ --- linux-3.13.0.orig/drivers/gpu/drm/i915/i915_gem_stolen.c +++ linux-3.13.0/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -201,6 +201,13 @@ struct drm_i915_private *dev_priv = dev->dev_private; int bios_reserved = 0; +#ifdef CONFIG_INTEL_IOMMU + if (intel_iommu_gfx_mapped) { + DRM_INFO("DMAR active, disabling use of stolen memory\n"); + return 0; + } +#endif + if (dev_priv->gtt.stolen_size == 0) return 0; @@ -250,7 +257,7 @@ } sg = st->sgl; - sg->offset = offset; + sg->offset = 0; sg->length = size; sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset; --- linux-3.13.0.orig/drivers/gpu/drm/i915/i915_reg.h +++ linux-3.13.0/drivers/gpu/drm/i915/i915_reg.h @@ -2117,9 +2117,13 @@ * Please check the detailed lore in the commit message for for experimental * evidence. */ -#define PORTD_HOTPLUG_LIVE_STATUS (1 << 29) -#define PORTC_HOTPLUG_LIVE_STATUS (1 << 28) -#define PORTB_HOTPLUG_LIVE_STATUS (1 << 27) +#define PORTD_HOTPLUG_LIVE_STATUS_G4X (1 << 29) +#define PORTC_HOTPLUG_LIVE_STATUS_G4X (1 << 28) +#define PORTB_HOTPLUG_LIVE_STATUS_G4X (1 << 27) +/* VLV DP/HDMI bits again match Bspec */ +#define PORTD_HOTPLUG_LIVE_STATUS_VLV (1 << 27) +#define PORTC_HOTPLUG_LIVE_STATUS_VLV (1 << 28) +#define PORTB_HOTPLUG_LIVE_STATUS_VLV (1 << 29) #define PORTD_HOTPLUG_INT_STATUS (3 << 21) #define PORTC_HOTPLUG_INT_STATUS (3 << 19) #define PORTB_HOTPLUG_INT_STATUS (3 << 17) --- linux-3.13.0.orig/drivers/gpu/drm/i915/i915_drv.c +++ linux-3.13.0/drivers/gpu/drm/i915/i915_drv.c @@ -385,9 +385,7 @@ INTEL_HSW_D_IDS(&intel_haswell_d_info), \ INTEL_HSW_M_IDS(&intel_haswell_m_info), \ INTEL_VLV_M_IDS(&intel_valleyview_m_info), \ - INTEL_VLV_D_IDS(&intel_valleyview_d_info), \ - INTEL_BDW_M_IDS(&intel_broadwell_m_info), \ - INTEL_BDW_D_IDS(&intel_broadwell_d_info) + INTEL_VLV_D_IDS(&intel_valleyview_d_info) static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_PCI_IDS, @@ -401,7 +399,7 @@ void intel_detect_pch(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct pci_dev *pch; + struct pci_dev *pch = NULL; /* In all current cases, num_pipes is equivalent to the PCH_NOP setting * (which really amounts to a PCH but no South Display). @@ -422,12 +420,9 @@ * all the ISA bridge devices and check for the first match, instead * of only checking the first one. */ - pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); - while (pch) { - struct pci_dev *curr = pch; + while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) { if (pch->vendor == PCI_VENDOR_ID_INTEL) { - unsigned short id; - id = pch->device & INTEL_PCH_DEVICE_ID_MASK; + unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK; dev_priv->pch_id = id; if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { @@ -459,18 +454,16 @@ DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); WARN_ON(!IS_ULT(dev)); - } else { - goto check_next; - } - pci_dev_put(pch); + } else + continue; + break; } -check_next: - pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr); - pci_dev_put(curr); } if (!pch) - DRM_DEBUG_KMS("No PCH found?\n"); + DRM_DEBUG_KMS("No PCH found.\n"); + + pci_dev_put(pch); } bool i915_semaphore_is_enabled(struct drm_device *dev) @@ -1024,8 +1017,13 @@ driver.driver_features &= ~DRIVER_MODESET; #endif - if (!(driver.driver_features & DRIVER_MODESET)) + if (!(driver.driver_features & DRIVER_MODESET)) { driver.get_vblank_timestamp = NULL; +#ifndef CONFIG_DRM_I915_UMS + /* Silently fail loading to not upset userspace. */ + return 0; +#endif + } return drm_pci_init(&driver, &i915_pci_driver); } --- linux-3.13.0.orig/drivers/gpu/drm/i915/intel_hdmi.c +++ linux-3.13.0/drivers/gpu/drm/i915/intel_hdmi.c @@ -845,7 +845,7 @@ { struct drm_device *dev = intel_hdmi_to_dev(hdmi); - if (IS_G4X(dev)) + if (!hdmi->has_hdmi_sink || IS_G4X(dev)) return 165000; else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) return 300000; @@ -898,8 +898,8 @@ * outputs. We also need to check that the higher clock still fits * within limits. */ - if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit - && HAS_PCH_SPLIT(dev)) { + if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink && + clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) { DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); desired_bpp = 12*3; --- linux-3.13.0.orig/drivers/gpu/drm/i915/intel_uncore.c +++ linux-3.13.0/drivers/gpu/drm/i915/intel_uncore.c @@ -687,6 +687,40 @@ return 0; } +int i915_get_reset_stats_ioctl(struct drm_device *dev, + void *data, struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_reset_stats *args = data; + struct i915_ctx_hang_stats *hs; + int ret; + + if (args->ctx_id == DEFAULT_CONTEXT_ID && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + hs = i915_gem_context_get_hang_stats(dev, file, args->ctx_id); + if (IS_ERR(hs)) { + mutex_unlock(&dev->struct_mutex); + return PTR_ERR(hs); + } + + if (capable(CAP_SYS_ADMIN)) + args->reset_count = i915_reset_count(&dev_priv->gpu_error); + else + args->reset_count = 0; + + args->batch_active = hs->batch_active; + args->batch_pending = hs->batch_pending; + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int i965_reset_complete(struct drm_device *dev) { u8 gdrst; --- linux-3.13.0.orig/drivers/gpu/drm/i915/intel_ringbuffer.c +++ linux-3.13.0/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1611,8 +1611,8 @@ return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); } -static int __intel_ring_begin(struct intel_ring_buffer *ring, - int bytes) +static int __intel_ring_prepare(struct intel_ring_buffer *ring, + int bytes) { int ret; @@ -1628,7 +1628,6 @@ return ret; } - ring->space -= bytes; return 0; } @@ -1643,12 +1642,38 @@ if (ret) return ret; + ret = __intel_ring_prepare(ring, num_dwords * sizeof(uint32_t)); + if (ret) + return ret; + /* Preallocate the olr before touching the ring */ ret = intel_ring_alloc_seqno(ring); if (ret) return ret; - return __intel_ring_begin(ring, num_dwords * sizeof(uint32_t)); + ring->space -= num_dwords * sizeof(uint32_t); + return 0; +} + +/* Align the ring tail to a cacheline boundary */ +int intel_ring_cacheline_align(struct intel_ring_buffer *ring) +{ + int num_dwords = (64 - (ring->tail & 63)) / sizeof(uint32_t); + int ret; + + if (num_dwords == 0) + return 0; + + ret = intel_ring_begin(ring, num_dwords); + if (ret) + return ret; + + while (num_dwords--) + intel_ring_emit(ring, MI_NOOP); + + intel_ring_advance(ring); + + return 0; } void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno) --- linux-3.13.0.orig/drivers/gpu/drm/i915/Kconfig +++ linux-3.13.0/drivers/gpu/drm/i915/Kconfig @@ -35,12 +35,11 @@ config DRM_I915_KMS bool "Enable modesetting on intel by default" depends on DRM_I915 + default y help - Choose this option if you want kernel modesetting enabled by default, - and you have a new enough userspace to support this. Running old - userspaces with this enabled will cause pain. Note that this causes - the driver to bind to PCI devices, which precludes loading things - like intelfb. + Choose this option if you want kernel modesetting enabled by default. + + If in doubt, say "Y". config DRM_I915_FBDEV bool "Enable legacy fbdev support for the modesettting intel driver" @@ -55,9 +54,12 @@ support. Note that this support also provide the linux console support on top of the intel modesetting driver. + If in doubt, say "Y". + config DRM_I915_PRELIMINARY_HW_SUPPORT bool "Enable preliminary support for prerelease Intel hardware by default" depends on DRM_I915 + default n help Choose this option if you have prerelease Intel hardware and want the i915 driver to support it by default. You can enable such support at @@ -65,3 +67,15 @@ option changes the default for that module option. If in doubt, say "N". + +config DRM_I915_UMS + bool "Enable userspace modesetting on Intel hardware (DEPRECATED)" + depends on DRM_I915 + default n + help + Choose this option if you still need userspace modesetting. + + Userspace modesetting is deprecated for quite some time now, so + enable this only if you have ancient versions of the DDX drivers. + + If in doubt, say "N". --- linux-3.13.0.orig/drivers/gpu/drm/i915/i915_irq.c +++ linux-3.13.0/drivers/gpu/drm/i915/i915_irq.c @@ -567,8 +567,7 @@ vbl_start = mode->crtc_vblank_start * mode->crtc_htotal; } else { - enum transcoder cpu_transcoder = - intel_pipe_to_cpu_transcoder(dev_priv, pipe); + enum transcoder cpu_transcoder = (enum transcoder) pipe; u32 htotal; htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1; @@ -675,7 +674,8 @@ } static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, - int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) + unsigned int flags, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; @@ -809,7 +809,8 @@ /* Helper routine in DRM core does all the work: */ return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, vblank_time, flags, - crtc); + crtc, + &to_intel_crtc(crtc)->config.adjusted_mode); } static bool intel_hpd_irq_event(struct drm_device *dev, @@ -1993,7 +1994,7 @@ kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, reset_done_event); } else { - atomic_set(&error->reset_counter, I915_WEDGED); + atomic_set_mask(I915_WEDGED, &error->reset_counter); } /* @@ -2761,10 +2762,9 @@ return; if (HAS_PCH_IBX(dev)) { - mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER | - SDE_TRANSA_FIFO_UNDER | SDE_POISON; + mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; } else { - mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT; + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; I915_WRITE(SERR_INT, I915_READ(SERR_INT)); } @@ -2824,20 +2824,19 @@ display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB | DE_PLANEB_FLIP_DONE_IVB | - DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB | - DE_ERR_INT_IVB); + DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB); extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB | - DE_PIPEA_VBLANK_IVB); + DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB); I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); } else { display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | DE_AUX_CHANNEL_A | - DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN | DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE | DE_POISON); - extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT; + extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT | + DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN; } dev_priv->irq_mask = ~display_mask; @@ -2953,9 +2952,9 @@ struct drm_device *dev = dev_priv->dev; uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE | GEN8_PIPE_CDCLK_CRC_DONE | - GEN8_PIPE_FIFO_UNDERRUN | GEN8_DE_PIPE_IRQ_FAULT_ERRORS; - uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK; + uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | + GEN8_PIPE_FIFO_UNDERRUN; int pipe; dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked; dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked; --- linux-3.13.0.orig/drivers/gpu/drm/i915/i915_gpu_error.c +++ linux-3.13.0/drivers/gpu/drm/i915/i915_gpu_error.c @@ -146,7 +146,10 @@ va_list tmp; va_copy(tmp, args); - if (!__i915_error_seek(e, vsnprintf(NULL, 0, f, tmp))) + len = vsnprintf(NULL, 0, f, tmp); + va_end(tmp); + + if (!__i915_error_seek(e, len)) return; } @@ -239,6 +242,9 @@ unsigned ring) { BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */ + if (!error->ring[ring].valid) + return; + err_printf(m, "%s command stream:\n", ring_str(ring)); err_printf(m, " HEAD: 0x%08x\n", error->head[ring]); err_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); @@ -294,7 +300,6 @@ struct drm_device *dev = error_priv->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_state *error = error_priv->error; - struct intel_ring_buffer *ring; int i, j, page, offset, elt; if (!error) { @@ -329,7 +334,7 @@ if (INTEL_INFO(dev)->gen == 7) err_printf(m, "ERR_INT: 0x%08x\n", error->err_int); - for_each_ring(ring, dev_priv, i) + for (i = 0; i < ARRAY_SIZE(error->ring); i++) i915_ring_error_state(m, dev, error, i); if (error->active_bo) @@ -386,8 +391,7 @@ } } - obj = error->ring[i].ctx; - if (obj) { + if ((obj = error->ring[i].ctx)) { err_printf(m, "%s --- HW Context = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); @@ -668,7 +672,8 @@ return NULL; obj = ring->scratch.obj; - if (acthd >= i915_gem_obj_ggtt_offset(obj) && + if (obj != NULL && + acthd >= i915_gem_obj_ggtt_offset(obj) && acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size) return i915_error_object_create(dev_priv, obj); } @@ -775,11 +780,17 @@ struct drm_i915_error_state *error) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; struct drm_i915_gem_request *request; int i, count; - for_each_ring(ring, dev_priv, i) { + for (i = 0; i < I915_NUM_RINGS; i++) { + struct intel_ring_buffer *ring = &dev_priv->ring[i]; + + if (ring->dev == NULL) + continue; + + error->ring[i].valid = true; + i915_record_ring_state(dev, error, ring); error->ring[i].batchbuffer = --- linux-3.13.0.orig/drivers/gpu/drm/i915/i915_drv.h +++ linux-3.13.0/drivers/gpu/drm/i915/i915_drv.h @@ -317,6 +317,7 @@ u64 fence[I915_MAX_NUM_FENCES]; struct timeval time; struct drm_i915_error_ring { + bool valid; struct drm_i915_error_object { int page_count; u32 gtt_offset; @@ -1077,34 +1078,30 @@ unsigned long missed_irq_rings; /** - * State variable and reset counter controlling the reset flow + * State variable controlling the reset flow and count * - * Upper bits are for the reset counter. This counter is used by the - * wait_seqno code to race-free noticed that a reset event happened and - * that it needs to restart the entire ioctl (since most likely the - * seqno it waited for won't ever signal anytime soon). + * This is a counter which gets incremented when reset is triggered, + * and again when reset has been handled. So odd values (lowest bit set) + * means that reset is in progress and even values that + * (reset_counter >> 1):th reset was successfully completed. + * + * If reset is not completed succesfully, the I915_WEDGE bit is + * set meaning that hardware is terminally sour and there is no + * recovery. All waiters on the reset_queue will be woken when + * that happens. + * + * This counter is used by the wait_seqno code to notice that reset + * event happened and it needs to restart the entire ioctl (since most + * likely the seqno it waited for won't ever signal anytime soon). * * This is important for lock-free wait paths, where no contended lock * naturally enforces the correct ordering between the bail-out of the * waiter and the gpu reset work code. - * - * Lowest bit controls the reset state machine: Set means a reset is in - * progress. This state will (presuming we don't have any bugs) decay - * into either unset (successful reset) or the special WEDGED value (hw - * terminally sour). All waiters on the reset_queue will be woken when - * that happens. */ atomic_t reset_counter; - /** - * Special values/flags for reset_counter - * - * Note that the code relies on - * I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG - * being true. - */ #define I915_RESET_IN_PROGRESS_FLAG 1 -#define I915_WEDGED 0xffffffff +#define I915_WEDGED (1 << 31) /** * Waitqueue to signal when the reset has completed. Used by clients @@ -2063,12 +2060,17 @@ static inline bool i915_reset_in_progress(struct i915_gpu_error *error) { return unlikely(atomic_read(&error->reset_counter) - & I915_RESET_IN_PROGRESS_FLAG); + & (I915_RESET_IN_PROGRESS_FLAG | I915_WEDGED)); } static inline bool i915_terminally_wedged(struct i915_gpu_error *error) { - return atomic_read(&error->reset_counter) == I915_WEDGED; + return atomic_read(&error->reset_counter) & I915_WEDGED; +} + +static inline u32 i915_reset_count(struct i915_gpu_error *error) +{ + return ((atomic_read(&error->reset_counter) & ~I915_WEDGED) + 1) / 2; } void i915_gem_reset(struct drm_device *dev); @@ -2398,6 +2400,8 @@ extern bool i915_semaphore_is_enabled(struct drm_device *dev); int i915_reg_read_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); /* overlay */ extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); --- linux-3.13.0.orig/drivers/gpu/drm/i915/intel_dp.c +++ linux-3.13.0/drivers/gpu/drm/i915/intel_dp.c @@ -537,6 +537,7 @@ uint8_t msg[20]; int msg_bytes; uint8_t ack; + int retry; if (WARN_ON(send_bytes > 16)) return -E2BIG; @@ -548,18 +549,20 @@ msg[3] = send_bytes - 1; memcpy(&msg[4], send, send_bytes); msg_bytes = send_bytes + 4; - for (;;) { + for (retry = 0; retry < 7; retry++) { ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1); if (ret < 0) return ret; if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) - break; + return send_bytes; else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) - udelay(100); + usleep_range(400, 500); else return -EIO; } - return send_bytes; + + DRM_ERROR("too many retries, giving up\n"); + return -EIO; } /* Write a single byte to the aux channel in native mode */ @@ -581,6 +584,7 @@ int reply_bytes; uint8_t ack; int ret; + int retry; if (WARN_ON(recv_bytes > 19)) return -E2BIG; @@ -594,7 +598,7 @@ msg_bytes = 4; reply_bytes = recv_bytes + 1; - for (;;) { + for (retry = 0; retry < 7; retry++) { ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, reply, reply_bytes); if (ret == 0) @@ -607,10 +611,13 @@ return ret - 1; } else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) - udelay(100); + usleep_range(400, 500); else return -EIO; } + + DRM_ERROR("too many retries, giving up\n"); + return -EIO; } static int @@ -1627,7 +1634,7 @@ val |= EDP_PSR_LINK_DISABLE; I915_WRITE(EDP_PSR_CTL(dev), val | - IS_BROADWELL(dev) ? 0 : link_entry_time | + (IS_BROADWELL(dev) ? 0 : link_entry_time) | max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT | idle_frames << EDP_PSR_IDLE_FRAME_SHIFT | EDP_PSR_ENABLE); @@ -1865,10 +1872,12 @@ mutex_unlock(&dev_priv->dpio_lock); - /* init power sequencer on this pipe and port */ - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + if (is_edp(intel_dp)) { + /* init power sequencer on this pipe and port */ + intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, + &power_seq); + } intel_enable_dp(encoder); @@ -3020,18 +3029,34 @@ return status; } - switch (intel_dig_port->port) { - case PORT_B: - bit = PORTB_HOTPLUG_LIVE_STATUS; - break; - case PORT_C: - bit = PORTC_HOTPLUG_LIVE_STATUS; - break; - case PORT_D: - bit = PORTD_HOTPLUG_LIVE_STATUS; - break; - default: - return connector_status_unknown; + if (IS_VALLEYVIEW(dev)) { + switch (intel_dig_port->port) { + case PORT_B: + bit = PORTB_HOTPLUG_LIVE_STATUS_VLV; + break; + case PORT_C: + bit = PORTC_HOTPLUG_LIVE_STATUS_VLV; + break; + case PORT_D: + bit = PORTD_HOTPLUG_LIVE_STATUS_VLV; + break; + default: + return connector_status_unknown; + } + } else { + switch (intel_dig_port->port) { + case PORT_B: + bit = PORTB_HOTPLUG_LIVE_STATUS_G4X; + break; + case PORT_C: + bit = PORTC_HOTPLUG_LIVE_STATUS_G4X; + break; + case PORT_D: + bit = PORTD_HOTPLUG_LIVE_STATUS_G4X; + break; + default: + return connector_status_unknown; + } } if ((I915_READ(PORT_HOTPLUG_STAT) & bit) == 0) --- linux-3.13.0.orig/drivers/hwmon/max1668.c +++ linux-3.13.0/drivers/hwmon/max1668.c @@ -243,7 +243,7 @@ data->temp_min[index] = clamp_val(temp/1000, -128, 127); if (i2c_smbus_write_byte_data(client, MAX1668_REG_LIML_WR(index), - data->temp_max[index])) + data->temp_min[index])) count = -EIO; mutex_unlock(&data->update_lock); --- linux-3.13.0.orig/drivers/hwmon/ntc_thermistor.c +++ linux-3.13.0/drivers/hwmon/ntc_thermistor.c @@ -145,7 +145,7 @@ static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata) { struct iio_channel *channel = pdata->chan; - unsigned int result; + s64 result; int val, ret; ret = iio_read_channel_raw(channel, &val); @@ -155,10 +155,10 @@ } /* unit: mV */ - result = pdata->pullup_uv * val; + result = pdata->pullup_uv * (s64) val; result >>= 12; - return result; + return (int)result; } static const struct of_device_id ntc_match[] = { --- linux-3.13.0.orig/drivers/hwmon/k10temp.c +++ linux-3.13.0/drivers/hwmon/k10temp.c @@ -210,6 +210,7 @@ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, {} }; --- linux-3.13.0.orig/drivers/usb/phy/phy-fsl-usb.c +++ linux-3.13.0/drivers/usb/phy/phy-fsl-usb.c @@ -76,7 +76,7 @@ .otg_port = 1, }; -#ifdef CONFIG_PPC32 +#ifdef CONFIG_PPC static u32 _fsl_readl_be(const unsigned __iomem *p) { return in_be32(p); @@ -106,7 +106,7 @@ #else #define fsl_readl(addr) readl(addr) #define fsl_writel(val, addr) writel(val, addr) -#endif /* CONFIG_PPC32 */ +#endif /* CONFIG_PPC */ /* Routines to access transceiver ULPI registers */ u8 view_ulpi(u8 addr) @@ -914,6 +914,7 @@ if (pdata->init && pdata->init(pdev) != 0) return -EINVAL; +#ifdef CONFIG_PPC if (pdata->big_endian_mmio) { _fsl_readl = _fsl_readl_be; _fsl_writel = _fsl_writel_be; @@ -921,6 +922,7 @@ _fsl_readl = _fsl_readl_le; _fsl_writel = _fsl_writel_le; } +#endif /* request irq */ p_otg->irq = platform_get_irq(pdev, 0); --- linux-3.13.0.orig/drivers/usb/gadget/bcm63xx_udc.c +++ linux-3.13.0/drivers/usb/gadget/bcm63xx_udc.c @@ -361,24 +361,30 @@ bcm_writel(val, udc->iudma_regs + off); } -static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan) { - return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off); + return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off, + int chan) { - bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off); + bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan) { - return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off); + return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off, + int chan) { - bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off); + bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled) @@ -639,7 +645,7 @@ } while (!last_bd); usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK, - ENETDMAC_CHANCFG_REG(iudma->ch_idx)); + ENETDMAC_CHANCFG_REG, iudma->ch_idx); } /** @@ -695,9 +701,9 @@ bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num)); /* stop DMA, then wait for the hardware to wrap up */ - usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx)); + usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx); - while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) & + while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) & ENETDMAC_CHANCFG_EN_MASK) { udelay(1); @@ -714,10 +720,10 @@ dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n", ch_idx); usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK, - ENETDMAC_CHANCFG_REG(ch_idx)); + ENETDMAC_CHANCFG_REG, ch_idx); } } - usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx)); + usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx); /* don't leave "live" HW-owned entries for the next guy to step on */ for (d = iudma->bd_ring; d <= iudma->end_bd; d++) @@ -729,11 +735,11 @@ /* set up IRQs, UBUS burst size, and BD base for this channel */ usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, - ENETDMAC_IRMASK_REG(ch_idx)); - usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx)); + ENETDMAC_IRMASK_REG, ch_idx); + usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx); - usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx)); - usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx)); + usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx); + usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx); } /** @@ -2036,7 +2042,7 @@ spin_lock(&udc->lock); usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, - ENETDMAC_IR_REG(iudma->ch_idx)); + ENETDMAC_IR_REG, iudma->ch_idx); bep = iudma->bep; rc = iudma_read(udc, iudma); @@ -2176,18 +2182,18 @@ seq_printf(s, " [ep%d]:\n", max_t(int, iudma_defaults[ch_idx].ep_num, 0)); seq_printf(s, " cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n", - usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx))); + usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx)); - sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx)); - sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx)); + sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx); + sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx); seq_printf(s, " base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n", - usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)), + usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx), sram2 >> 16, sram2 & 0xffff, sram3 >> 16, sram3 & 0xffff, - usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx))); + usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx)); seq_printf(s, " desc: %d/%d used", iudma->n_bds_used, iudma->n_bds); --- linux-3.13.0.orig/drivers/usb/dwc3/dwc3-exynos.c +++ linux-3.13.0/drivers/usb/dwc3/dwc3-exynos.c @@ -50,6 +50,7 @@ exynos->usb2_phy = pdev; pdata.type = USB_PHY_TYPE_USB2; + pdata.gpio_reset = -1; ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata)); if (ret) --- linux-3.13.0.orig/drivers/usb/dwc3/dwc3-pci.c +++ linux-3.13.0/drivers/usb/dwc3/dwc3-pci.c @@ -52,6 +52,7 @@ glue->usb2_phy = pdev; pdata.type = USB_PHY_TYPE_USB2; + pdata.gpio_reset = -1; ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); if (ret) --- linux-3.13.0.orig/drivers/usb/host/xhci-pci.c +++ linux-3.13.0/drivers/usb/host/xhci-pci.c @@ -142,6 +142,11 @@ "QUIRK: Resetting on resume"); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + pdev->device == 0x0015 && + pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG && + pdev->subsystem_device == 0xc0cd) + xhci->quirks |= XHCI_RESET_ON_RESUME; if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; } --- linux-3.13.0.orig/drivers/usb/host/xhci-ring.c +++ linux-3.13.0/drivers/usb/host/xhci-ring.c @@ -2973,58 +2973,8 @@ } while (1) { - if (room_on_ring(xhci, ep_ring, num_trbs)) { - union xhci_trb *trb = ep_ring->enqueue; - unsigned int usable = ep_ring->enq_seg->trbs + - TRBS_PER_SEGMENT - 1 - trb; - u32 nop_cmd; - - /* - * Section 4.11.7.1 TD Fragments states that a link - * TRB must only occur at the boundary between - * data bursts (eg 512 bytes for 480M). - * While it is possible to split a large fragment - * we don't know the size yet. - * Simplest solution is to fill the trb before the - * LINK with nop commands. - */ - if (num_trbs == 1 || num_trbs <= usable || usable == 0) - break; - - if (ep_ring->type != TYPE_BULK) - /* - * While isoc transfers might have a buffer that - * crosses a 64k boundary it is unlikely. - * Since we can't add NOPs without generating - * gaps in the traffic just hope it never - * happens at the end of the ring. - * This could be fixed by writing a LINK TRB - * instead of the first NOP - however the - * TRB_TYPE_LINK_LE32() calls would all need - * changing to check the ring length. - */ - break; - - if (num_trbs >= TRBS_PER_SEGMENT) { - xhci_err(xhci, "Too many fragments %d, max %d\n", - num_trbs, TRBS_PER_SEGMENT - 1); - return -ENOMEM; - } - - nop_cmd = cpu_to_le32(TRB_TYPE(TRB_TR_NOOP) | - ep_ring->cycle_state); - ep_ring->num_trbs_free -= usable; - do { - trb->generic.field[0] = 0; - trb->generic.field[1] = 0; - trb->generic.field[2] = 0; - trb->generic.field[3] = nop_cmd; - trb++; - } while (--usable); - ep_ring->enqueue = trb; - if (room_on_ring(xhci, ep_ring, num_trbs)) - break; - } + if (room_on_ring(xhci, ep_ring, num_trbs)) + break; if (ep_ring == xhci->cmd_ring) { xhci_err(xhci, "Do not support expand command ring\n"); --- linux-3.13.0.orig/drivers/usb/host/xhci.c +++ linux-3.13.0/drivers/usb/host/xhci.c @@ -321,6 +321,9 @@ struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + if (xhci->quirks & XHCI_PLAT) + return; + xhci_free_irq(xhci); if (xhci->msix_entries) { --- linux-3.13.0.orig/drivers/usb/host/ehci.h +++ linux-3.13.0/drivers/usb/host/ehci.h @@ -225,6 +225,7 @@ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ unsigned need_oc_pp_cycle:1; /* MPC834X port power */ + unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) @@ -728,6 +729,18 @@ #endif } +#ifdef CONFIG_SOC_IMX28 +static inline void imx28_ehci_writel(const unsigned int val, + volatile __u32 __iomem *addr) +{ + __asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr)); +} +#else +static inline void imx28_ehci_writel(const unsigned int val, + volatile __u32 __iomem *addr) +{ +} +#endif static inline void ehci_writel(const struct ehci_hcd *ehci, const unsigned int val, __u32 __iomem *regs) { @@ -736,7 +749,10 @@ writel_be(val, regs) : writel(val, regs); #else - writel(val, regs); + if (ehci->imx28_write_fix) + imx28_ehci_writel(val, regs); + else + writel(val, regs); #endif } --- linux-3.13.0.orig/drivers/usb/host/ehci-hcd.c +++ linux-3.13.0/drivers/usb/host/ehci-hcd.c @@ -686,8 +686,15 @@ struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status, masked_status, pcd_status = 0, cmd; int bh; + unsigned long flags; - spin_lock (&ehci->lock); + /* + * For threadirqs option we use spin_lock_irqsave() variant to prevent + * deadlock with ehci hrtimer callback, because hrtimer callbacks run + * in interrupt context even when threadirqs is specified. We can go + * back to spin_lock() variant when hrtimer callbacks become threaded. + */ + spin_lock_irqsave(&ehci->lock, flags); status = ehci_readl(ehci, &ehci->regs->status); @@ -705,7 +712,7 @@ /* Shared IRQ? */ if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { - spin_unlock(&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); return IRQ_NONE; } @@ -823,7 +830,7 @@ if (bh) ehci_work (ehci); - spin_unlock (&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); if (pcd_status) usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; --- linux-3.13.0.orig/drivers/usb/host/ehci-hub.c +++ linux-3.13.0/drivers/usb/host/ehci-hub.c @@ -238,6 +238,7 @@ int port; int mask; int changed; + bool fs_idle_delay; ehci_dbg(ehci, "suspend root hub\n"); @@ -272,6 +273,7 @@ ehci->bus_suspended = 0; ehci->owned_ports = 0; changed = 0; + fs_idle_delay = false; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; @@ -300,16 +302,32 @@ } if (t1 != t2) { + /* + * On some controllers, Wake-On-Disconnect will + * generate false wakeup signals until the bus + * switches over to full-speed idle. For their + * sake, add a delay if we need one. + */ + if ((t2 & PORT_WKDISC_E) && + ehci_port_speed(ehci, t2) == + USB_PORT_STAT_HIGH_SPEED) + fs_idle_delay = true; ehci_writel(ehci, t2, reg); changed = 1; } } + spin_unlock_irq(&ehci->lock); + + if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) { + /* + * Wait for HCD to enter low-power mode or for the bus + * to switch to full-speed idle. + */ + usleep_range(5000, 5500); + } if (changed && ehci->has_tdi_phy_lpm) { - spin_unlock_irq(&ehci->lock); - msleep(5); /* 5 ms for HCD to enter low-power mode */ spin_lock_irq(&ehci->lock); - port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -322,8 +340,8 @@ port, (t3 & HOSTPC_PHCD) ? "succeeded" : "failed"); } + spin_unlock_irq(&ehci->lock); } - spin_unlock_irq(&ehci->lock); /* Apparently some devices need a >= 1-uframe delay here */ if (ehci->bus_suspended) --- linux-3.13.0.orig/drivers/usb/class/cdc-wdm.c +++ linux-3.13.0/drivers/usb/class/cdc-wdm.c @@ -432,6 +432,38 @@ return rv < 0 ? rv : count; } +/* + * clear WDM_READ flag and possibly submit the read urb if resp_count + * is non-zero. + * + * Called with desc->iuspin locked + */ +static int clear_wdm_read_flag(struct wdm_device *desc) +{ + int rv = 0; + + clear_bit(WDM_READ, &desc->flags); + + /* submit read urb only if the device is waiting for it */ + if (!desc->resp_count || !--desc->resp_count) + goto out; + + set_bit(WDM_RESPONDING, &desc->flags); + spin_unlock_irq(&desc->iuspin); + rv = usb_submit_urb(desc->response, GFP_KERNEL); + spin_lock_irq(&desc->iuspin); + if (rv) { + dev_err(&desc->intf->dev, + "usb_submit_urb failed with result %d\n", rv); + + /* make sure the next notification trigger a submit */ + clear_bit(WDM_RESPONDING, &desc->flags); + desc->resp_count = 0; + } +out: + return rv; +} + static ssize_t wdm_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos) { @@ -503,8 +535,10 @@ if (!desc->reslength) { /* zero length read */ dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); - clear_bit(WDM_READ, &desc->flags); + rv = clear_wdm_read_flag(desc); spin_unlock_irq(&desc->iuspin); + if (rv < 0) + goto err; goto retry; } cntr = desc->length; @@ -526,37 +560,9 @@ desc->length -= cntr; /* in case we had outstanding data */ - if (!desc->length) { - clear_bit(WDM_READ, &desc->flags); - - if (--desc->resp_count) { - set_bit(WDM_RESPONDING, &desc->flags); - spin_unlock_irq(&desc->iuspin); - - rv = usb_submit_urb(desc->response, GFP_KERNEL); - if (rv) { - dev_err(&desc->intf->dev, - "%s: usb_submit_urb failed with result %d\n", - __func__, rv); - spin_lock_irq(&desc->iuspin); - clear_bit(WDM_RESPONDING, &desc->flags); - spin_unlock_irq(&desc->iuspin); - - if (rv == -ENOMEM) { - rv = schedule_work(&desc->rxwork); - if (rv) - dev_err(&desc->intf->dev, "Cannot schedule work\n"); - } else { - spin_lock_irq(&desc->iuspin); - desc->resp_count = 0; - spin_unlock_irq(&desc->iuspin); - } - } - } else - spin_unlock_irq(&desc->iuspin); - } else - spin_unlock_irq(&desc->iuspin); - + if (!desc->length) + clear_wdm_read_flag(desc); + spin_unlock_irq(&desc->iuspin); rv = cntr; err: --- linux-3.13.0.orig/drivers/usb/storage/scsiglue.c +++ linux-3.13.0/drivers/usb/storage/scsiglue.c @@ -78,6 +78,8 @@ static int slave_alloc (struct scsi_device *sdev) { + struct us_data *us = host_to_us(sdev->host); + /* * Set the INQUIRY transfer length to 36. We don't use any of * the extra data and many devices choke if asked for more or @@ -102,6 +104,10 @@ */ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); + /* Tell the SCSI layer if we know there is more than one LUN */ + if (us->protocol == USB_PR_BULK && us->max_lun > 0) + sdev->sdev_bflags |= BLIST_FORCELUN; + return 0; } --- linux-3.13.0.orig/drivers/usb/storage/unusual_cypress.h +++ linux-3.13.0/drivers/usb/storage/unusual_cypress.h @@ -31,7 +31,7 @@ "Cypress ISD-300LP", USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), -UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x0219, +UNUSUAL_DEV( 0x14cd, 0x6116, 0x0160, 0x0160, "Super Top", "USB 2.0 SATA BRIDGE", USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), --- linux-3.13.0.orig/drivers/usb/storage/Kconfig +++ linux-3.13.0/drivers/usb/storage/Kconfig @@ -18,7 +18,9 @@ This option depends on 'SCSI' support being enabled, but you probably also need 'SCSI device support: SCSI disk support' - (BLK_DEV_SD) for most USB storage devices. + (BLK_DEV_SD) for most USB storage devices. Some devices also + will require 'Probe all LUNs on each SCSI device' + (SCSI_MULTI_LUN). To compile this driver as a module, choose M here: the module will be called usb-storage. --- linux-3.13.0.orig/drivers/usb/storage/unusual_devs.h +++ linux-3.13.0/drivers/usb/storage/unusual_devs.h @@ -234,6 +234,13 @@ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), +/* Patch submitted by Mikhail Zolotaryov */ +UNUSUAL_DEV( 0x0421, 0x06aa, 0x1110, 0x1110, + "Nokia", + "502", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + #ifdef NO_SDDR09 UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, "Microtech", @@ -1191,6 +1198,13 @@ USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, 0), +/* Reported by Timo Aaltonen */ +UNUSUAL_DEV( 0x0af0, 0x7011, 0x0000, 0x9999, + "Option", + "Mass Storage", + USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, + 0 ), + /* Reported by F. Aben * This device (wrongly) has a vendor-specific device descriptor. * The entry is needed so usb-storage can bind to it's mass-storage @@ -1448,6 +1462,13 @@ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Moritz Moeller-Herrmann */ +UNUSUAL_DEV( 0x0fca, 0x8004, 0x0201, 0x0201, + "Research In Motion", + "BlackBerry Bold 9000", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Michael Stattmann */ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, "Sony Ericsson", --- linux-3.13.0.orig/drivers/usb/serial/qcserial.c +++ linux-3.13.0/drivers/usb/serial/qcserial.c @@ -139,6 +139,9 @@ {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 0)}, /* Sierra Wireless EM7700 Device Management */ {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 2)}, /* Sierra Wireless EM7700 NMEA */ {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 3)}, /* Sierra Wireless EM7700 Modem */ + {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 0)}, /* Netgear AirCard 340U Device Management */ + {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 2)}, /* Netgear AirCard 340U NMEA */ + {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 3)}, /* Netgear AirCard 340U Modem */ { } /* Terminating entry */ }; --- linux-3.13.0.orig/drivers/usb/serial/option.c +++ linux-3.13.0/drivers/usb/serial/option.c @@ -320,6 +320,9 @@ * It seems to contain a Qualcomm QSC6240/6290 chipset */ #define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 +/* iBall 3.5G connect wireless modem */ +#define IBALL_3_5G_CONNECT 0x9605 + /* Zoom */ #define ZOOM_PRODUCT_4597 0x9607 @@ -1359,7 +1362,8 @@ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) }, @@ -1447,6 +1451,17 @@ .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8e, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff90, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff91, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) }, /* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), @@ -1489,6 +1504,7 @@ .driver_info = (kernel_ulong_t)&four_g_w14_blacklist }, { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, + { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) }, { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, /* Pirelli */ { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) }, @@ -1510,7 +1526,8 @@ /* Cinterion */ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, --- linux-3.13.0.orig/drivers/usb/serial/usb-serial-simple.c +++ linux-3.13.0/drivers/usb/serial/usb-serial-simple.c @@ -72,7 +72,8 @@ /* Suunto ANT+ USB Driver */ #define SUUNTO_IDS() \ - { USB_DEVICE(0x0fcf, 0x1008) } + { USB_DEVICE(0x0fcf, 0x1008) }, \ + { USB_DEVICE(0x0fcf, 0x1009) } /* Dynastream ANT USB-m Stick */ DEVICE(suunto, SUUNTO_IDS); /* Siemens USB/MPI adapter */ --- linux-3.13.0.orig/drivers/usb/serial/ftdi_sio.c +++ linux-3.13.0/drivers/usb/serial/ftdi_sio.c @@ -153,6 +153,7 @@ { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, @@ -192,6 +193,8 @@ { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) }, { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, @@ -905,6 +908,8 @@ /* Crucible Devices */ { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) }, + /* Cressi Devices */ + { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) }, { } /* Terminating entry */ }; @@ -2124,10 +2129,20 @@ } /* - * All FTDI UART chips are limited to CS7/8. We won't pretend to + * All FTDI UART chips are limited to CS7/8. We shouldn't pretend to * support CS5/6 and revert the CSIZE setting instead. + * + * CS5 however is used to control some smartcard readers which abuse + * this limitation to switch modes. Original FTDI chips fall back to + * eight data bits. + * + * TODO: Implement a quirk to only allow this with mentioned + * readers. One I know of (Argolis Smartreader V1) + * returns "USB smartcard server" as iInterface string. + * The vendor didn't bother with a custom VID/PID of + * course. */ - if ((C_CSIZE(tty) != CS8) && (C_CSIZE(tty) != CS7)) { + if (C_CSIZE(tty) == CS6) { dev_warn(ddev, "requested CSIZE setting not supported\n"); termios->c_cflag &= ~CSIZE; @@ -2174,6 +2189,9 @@ urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE; } switch (cflag & CSIZE) { + case CS5: + dev_dbg(ddev, "Setting CS5 quirk\n"); + break; case CS7: urb_value |= 7; dev_dbg(ddev, "Setting CS7\n"); --- linux-3.13.0.orig/drivers/usb/serial/pl2303.c +++ linux-3.13.0/drivers/usb/serial/pl2303.c @@ -142,6 +142,8 @@ spinlock_t lock; u8 line_control; u8 line_status; + + u8 line_settings[7]; }; static int pl2303_vendor_read(__u16 value, __u16 index, @@ -339,11 +341,6 @@ int i; u8 control; - /* - * The PL2303 is reported to lose bytes if you change serial settings - * even to the same values as before. Thus we actually need to filter - * in this specific case. - */ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; @@ -428,10 +425,29 @@ dev_dbg(&port->dev, "parity = none\n"); } - i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i); + /* + * Some PL2303 are known to lose bytes if you change serial settings + * even to the same values as before. Thus we actually need to filter + * in this specific case. + * + * Note that the tty_termios_hw_change check above is not sufficient + * as a previously requested baud rate may differ from the one + * actually used (and stored in old_termios). + * + * NOTE: No additional locking needed for line_settings as it is + * only used in set_termios, which is serialised against itself. + */ + if (!old_termios || memcmp(buf, priv->line_settings, 7)) { + i = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + + dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i); + + if (i == 7) + memcpy(priv->line_settings, buf, 7); + } /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); --- linux-3.13.0.orig/drivers/usb/serial/cypress_m8.h +++ linux-3.13.0/drivers/usb/serial/cypress_m8.h @@ -63,7 +63,7 @@ #define UART_DSR 0x20 /* data set ready - flow control - device to host */ #define CONTROL_RTS 0x10 /* request to send - flow control - host to device */ #define UART_CTS 0x10 /* clear to send - flow control - device to host */ -#define UART_RI 0x10 /* ring indicator - modem - device to host */ +#define UART_RI 0x80 /* ring indicator - modem - device to host */ #define UART_CD 0x40 /* carrier detect - modem - device to host */ #define CYP_ERROR 0x08 /* received from input report - device to host */ /* Note - the below has nothing to do with the "feature report" reset */ --- linux-3.13.0.orig/drivers/usb/serial/ftdi_sio_ids.h +++ linux-3.13.0/drivers/usb/serial/ftdi_sio_ids.h @@ -50,6 +50,7 @@ #define TI_XDS100V2_PID 0xa6d0 #define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ +#define FTDI_EV3CON_PID 0xABB9 /* Mindstorms EV3 Console Adapter */ /* US Interface Navigator (http://www.usinterface.com/) */ #define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */ @@ -363,6 +364,12 @@ /* Sprog II (Andrew Crosland's SprogII DCC interface) */ #define FTDI_SPROG_II 0xF0C8 +/* + * Two of the Tagsys RFID Readers + */ +#define FTDI_TAGSYS_LP101_PID 0xF0E9 /* Tagsys L-P101 RFID*/ +#define FTDI_TAGSYS_P200X_PID 0xF0EE /* Tagsys Medio P200x RFID*/ + /* an infrared receiver for user access control with IR tags */ #define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ @@ -1313,3 +1320,9 @@ * Manufacturer: Smart GSM Team */ #define FTDI_Z3X_PID 0x0011 + +/* + * Product: Cressi PC Interface + * Manufacturer: Cressi + */ +#define FTDI_CRESSI_PID 0x87d0 --- linux-3.13.0.orig/drivers/usb/core/hcd.c +++ linux-3.13.0/drivers/usb/core/hcd.c @@ -1031,7 +1031,6 @@ dev_name(&usb_dev->dev), retval); return retval; } - usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev); } retval = usb_new_device (usb_dev); --- linux-3.13.0.orig/drivers/usb/core/config.c +++ linux-3.13.0/drivers/usb/core/config.c @@ -651,10 +651,6 @@ * * hub-only!! ... and only in reset path, or usb_new_device() * (used by real hubs and virtual root hubs) - * - * NOTE: if this is a WUSB device and is not authorized, we skip the - * whole thing. A non-authorized USB device has no - * configurations. */ int usb_get_configuration(struct usb_device *dev) { @@ -666,8 +662,6 @@ struct usb_config_descriptor *desc; cfgno = 0; - if (dev->authorized == 0) /* Not really an error */ - goto out_not_authorized; result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " @@ -724,6 +718,10 @@ result = -ENOMEM; goto err; } + + if (dev->quirks & USB_QUIRK_DELAY_INIT) + msleep(100); + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); if (result < 0) { @@ -751,7 +749,6 @@ err: kfree(desc); -out_not_authorized: dev->descriptor.bNumConfigurations = cfgno; err2: if (result == -ENOMEM) --- linux-3.13.0.orig/drivers/usb/core/hub.c +++ linux-3.13.0/drivers/usb/core/hub.c @@ -135,7 +135,7 @@ return usb_get_intfdata(hdev->actconfig->interface[0]); } -int usb_device_supports_lpm(struct usb_device *udev) +static int usb_device_supports_lpm(struct usb_device *udev) { /* USB 2.1 (and greater) devices indicate LPM support through * their USB 2.0 Extended Capabilities BOS descriptor. @@ -156,11 +156,6 @@ "Power management will be impacted.\n"); return 0; } - - /* udev is root hub */ - if (!udev->parent) - return 1; - if (udev->parent->lpm_capable) return 1; @@ -1607,7 +1602,7 @@ { struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = interface_to_usbdev(intf); - int i; + int port1; /* Take the hub off the event list and don't let it be added again */ spin_lock_irq(&hub_event_lock); @@ -1622,11 +1617,15 @@ hub->error = 0; hub_quiesce(hub, HUB_DISCONNECT); - usb_set_intfdata (intf, NULL); + /* Avoid races with recursively_mark_NOTATTACHED() */ + spin_lock_irq(&device_state_lock); + port1 = hdev->maxchild; + hdev->maxchild = 0; + usb_set_intfdata(intf, NULL); + spin_unlock_irq(&device_state_lock); - for (i = 0; i < hdev->maxchild; i++) - usb_hub_remove_port_device(hub, i + 1); - hub->hdev->maxchild = 0; + for (; port1 > 0; --port1) + usb_hub_remove_port_device(hub, port1); if (hub->hdev->speed == USB_SPEED_HIGH) highspeed_hubs--; @@ -2235,17 +2234,13 @@ return err; } } - if (udev->wusb == 1 && udev->authorized == 0) { - udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); - udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); - udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - } else { - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - } + + /* read the standard strings and cache them if present */ + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); + err = usb_enumerate_device_otg(udev); if (err < 0) return err; @@ -2427,16 +2422,6 @@ usb_dev->authorized = 0; usb_set_configuration(usb_dev, -1); - kfree(usb_dev->product); - usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); - kfree(usb_dev->manufacturer); - usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); - kfree(usb_dev->serial); - usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - - usb_destroy_configuration(usb_dev); - usb_dev->descriptor.bNumConfigurations = 0; - out_unauthorized: usb_unlock_device(usb_dev); return 0; @@ -2464,17 +2449,7 @@ goto error_device_descriptor; } - kfree(usb_dev->product); - usb_dev->product = NULL; - kfree(usb_dev->manufacturer); - usb_dev->manufacturer = NULL; - kfree(usb_dev->serial); - usb_dev->serial = NULL; - usb_dev->authorized = 1; - result = usb_enumerate_device(usb_dev); - if (result < 0) - goto error_enumerate; /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ @@ -2490,7 +2465,6 @@ } dev_info(&usb_dev->dev, "authorized to connect\n"); -error_enumerate: error_device_descriptor: usb_autosuspend_device(usb_dev); error_autoresume: --- linux-3.13.0.orig/drivers/usb/core/usb.h +++ linux-3.13.0/drivers/usb/core/usb.h @@ -35,7 +35,6 @@ unsigned int size); extern int usb_get_bos_descriptor(struct usb_device *dev); extern void usb_release_bos_descriptor(struct usb_device *dev); -extern int usb_device_supports_lpm(struct usb_device *udev); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_choose_configuration(struct usb_device *udev); --- linux-3.13.0.orig/drivers/usb/core/quirks.c +++ linux-3.13.0/drivers/usb/core/quirks.c @@ -47,6 +47,10 @@ /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech HD Pro Webcams C920 and C930e */ + { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Logitech Quickcam Fusion */ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, --- linux-3.13.0.orig/drivers/usb/chipidea/core.c +++ linux-3.13.0/drivers/usb/chipidea/core.c @@ -554,6 +554,8 @@ ci->dev = dev; ci->platdata = dev->platform_data; + ci->imx28_write_fix = !!(ci->platdata->flags & + CI_HDRC_IMX28_WRITE_FIX); ret = hw_device_init(ci, base); if (ret < 0) { --- linux-3.13.0.orig/drivers/usb/chipidea/ci.h +++ linux-3.13.0/drivers/usb/chipidea/ci.h @@ -135,6 +135,7 @@ * @id_event: indicates there is an id event, and handled at ci_otg_work * @b_sess_valid_event: indicates there is a vbus event, and handled * at ci_otg_work + * @imx28_write_fix: Freescale imx28 needs swp instruction for writing */ struct ci_hdrc { struct device *dev; @@ -173,6 +174,7 @@ struct dentry *debugfs; bool id_event; bool b_sess_valid_event; + bool imx28_write_fix; }; static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) @@ -253,6 +255,26 @@ return ioread32(ci->hw_bank.regmap[reg]) & mask; } +#ifdef CONFIG_SOC_IMX28 +static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr) +{ + __asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr)); +} +#else +static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr) +{ +} +#endif + +static inline void __hw_write(struct ci_hdrc *ci, u32 val, + void __iomem *addr) +{ + if (ci->imx28_write_fix) + imx28_ci_writel(val, addr); + else + iowrite32(val, addr); +} + /** * hw_write: writes to a hw register * @reg: register index @@ -266,7 +288,7 @@ data = (ioread32(ci->hw_bank.regmap[reg]) & ~mask) | (data & mask); - iowrite32(data, ci->hw_bank.regmap[reg]); + __hw_write(ci, data, ci->hw_bank.regmap[reg]); } /** @@ -281,7 +303,7 @@ { u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask; - iowrite32(val, ci->hw_bank.regmap[reg]); + __hw_write(ci, val, ci->hw_bank.regmap[reg]); return val; } --- linux-3.13.0.orig/drivers/usb/chipidea/udc.c +++ linux-3.13.0/drivers/usb/chipidea/udc.c @@ -105,7 +105,7 @@ do { /* flush any pending transfer */ - hw_write(ci, OP_ENDPTFLUSH, BIT(n), BIT(n)); + hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n)); while (hw_read(ci, OP_ENDPTFLUSH, BIT(n))) cpu_relax(); } while (hw_read(ci, OP_ENDPTSTAT, BIT(n))); @@ -205,7 +205,7 @@ if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) return -EAGAIN; - hw_write(ci, OP_ENDPTPRIME, BIT(n), BIT(n)); + hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n)); while (hw_read(ci, OP_ENDPTPRIME, BIT(n))) cpu_relax(); @@ -393,6 +393,14 @@ node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES)); node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES); node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE); + if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) { + u32 mul = hwreq->req.length / hwep->ep.maxpacket; + + if (hwreq->req.length == 0 + || hwreq->req.length % hwep->ep.maxpacket) + mul++; + node->ptr->token |= mul << __ffs(TD_MULTO); + } temp = (u32) (hwreq->req.dma + hwreq->req.actual); if (length) { @@ -515,10 +523,11 @@ hwep->qh.ptr->td.token &= cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE)); - if (hwep->type == USB_ENDPOINT_XFER_ISOC) { + if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == RX) { u32 mul = hwreq->req.length / hwep->ep.maxpacket; - if (hwreq->req.length % hwep->ep.maxpacket) + if (hwreq->req.length == 0 + || hwreq->req.length % hwep->ep.maxpacket) mul++; hwep->qh.ptr->cap |= mul << __ffs(QH_MULT); } @@ -1173,6 +1182,12 @@ if (hwep->num) cap |= QH_ZLT; cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT; + /* + * For ISO-TX, we set mult at QH as the largest value, and use + * MultO at TD as real mult value. + */ + if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) + cap |= 3 << __ffs(QH_MULT); hwep->qh.ptr->cap = cpu_to_le32(cap); --- linux-3.13.0.orig/drivers/usb/chipidea/otg.h +++ linux-3.13.0/drivers/usb/chipidea/otg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2014 Freescale Semiconductor, Inc. * * Author: Peter Chen * @@ -19,12 +19,12 @@ static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) { - hw_write(ci, OP_OTGSC, bits, bits); + hw_write(ci, OP_OTGSC, bits | OTGSC_INT_STATUS_BITS, bits); } static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) { - hw_write(ci, OP_OTGSC, bits, 0); + hw_write(ci, OP_OTGSC, bits | OTGSC_INT_STATUS_BITS, 0); } int ci_hdrc_otg_init(struct ci_hdrc *ci); --- linux-3.13.0.orig/drivers/usb/chipidea/host.c +++ linux-3.13.0/drivers/usb/chipidea/host.c @@ -65,6 +65,7 @@ ehci->caps = ci->hw_bank.cap; ehci->has_hostpc = ci->hw_bank.lpm; ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; + ehci->imx28_write_fix = ci->imx28_write_fix; if (ci->platdata->reg_vbus) { ret = regulator_enable(ci->platdata->reg_vbus); --- linux-3.13.0.orig/drivers/usb/chipidea/ci_hdrc_imx.c +++ linux-3.13.0/drivers/usb/chipidea/ci_hdrc_imx.c @@ -23,6 +23,26 @@ #include "ci.h" #include "ci_hdrc_imx.h" +#define CI_HDRC_IMX_IMX28_WRITE_FIX BIT(0) + +struct ci_hdrc_imx_platform_flag { + unsigned int flags; +}; + +static const struct ci_hdrc_imx_platform_flag imx27_usb_data = { +}; + +static const struct ci_hdrc_imx_platform_flag imx28_usb_data = { + .flags = CI_HDRC_IMX_IMX28_WRITE_FIX, +}; + +static const struct of_device_id ci_hdrc_imx_dt_ids[] = { + { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data}, + { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); + struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; @@ -82,6 +102,9 @@ CI_HDRC_DISABLE_STREAMING, }; int ret; + const struct of_device_id *of_id = + of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); + const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { @@ -115,6 +138,9 @@ pdata.phy = data->phy; + if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX) + pdata.flags |= CI_HDRC_IMX28_WRITE_FIX; + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) goto err_clk; @@ -173,12 +199,6 @@ return 0; } -static const struct of_device_id ci_hdrc_imx_dt_ids[] = { - { .compatible = "fsl,imx27-usb", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); - static struct platform_driver ci_hdrc_imx_driver = { .probe = ci_hdrc_imx_probe, .remove = ci_hdrc_imx_remove, --- linux-3.13.0.orig/drivers/xen/pci.c +++ linux-3.13.0/drivers/xen/pci.c @@ -26,7 +26,9 @@ #include #include #include "../pci/pci.h" +#ifdef CONFIG_PCI_MMCONFIG #include +#endif static bool __read_mostly pci_seg_supported = true; --- linux-3.13.0.orig/drivers/xen/xenbus/xenbus_probe_frontend.c +++ linux-3.13.0/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -496,7 +496,7 @@ #ifndef MODULE static int __init boot_wait_for_devices(void) { - if (xen_hvm_domain() && !xen_platform_pci_unplug) + if (!xen_has_pv_devices()) return -ENODEV; ready_to_wait_for_devices = 1; --- linux-3.13.0.orig/drivers/pinctrl/core.c +++ linux-3.13.0/drivers/pinctrl/core.c @@ -851,7 +851,9 @@ kref_init(&p->users); /* Add the pinctrl handle to the global list */ + mutex_lock(&pinctrl_list_mutex); list_add_tail(&p->node, &pinctrl_list); + mutex_unlock(&pinctrl_list_mutex); return p; } --- linux-3.13.0.orig/drivers/pinctrl/pinctrl-sunxi.c +++ linux-3.13.0/drivers/pinctrl/pinctrl-sunxi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -469,12 +470,6 @@ return val; } -static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - return pinctrl_gpio_direction_output(chip->base + offset); -} - static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { @@ -498,6 +493,13 @@ spin_unlock_irqrestore(&pctl->lock, flags); } +static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + sunxi_pinctrl_gpio_set(chip, offset, value); + return pinctrl_gpio_direction_output(chip->base + offset); +} + static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags) @@ -664,6 +666,7 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) { + struct irq_chip *chip = irq_get_chip(irq); struct sunxi_pinctrl *pctl = irq_get_handler_data(irq); const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG); @@ -673,10 +676,12 @@ if (reg) { int irqoffset; + chained_irq_enter(chip, desc); for_each_set_bit(irqoffset, ®, SUNXI_IRQ_NUMBER) { int pin_irq = irq_find_mapping(pctl->domain, irqoffset); generic_handle_irq(pin_irq); } + chained_irq_exit(chip, desc); } } --- linux-3.13.0.orig/drivers/pinctrl/pinctrl-imx1-core.c +++ linux-3.13.0/drivers/pinctrl/pinctrl-imx1-core.c @@ -45,7 +45,7 @@ #define MX1_DDIR 0x00 #define MX1_OCR 0x04 #define MX1_ICONFA 0x0c -#define MX1_ICONFB 0x10 +#define MX1_ICONFB 0x14 #define MX1_GIUS 0x20 #define MX1_GPR 0x38 #define MX1_PUEN 0x40 @@ -97,13 +97,13 @@ u32 old_val; u32 new_val; - dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n", - reg, offset, value); - /* Use the next register if the pin's port pin number is >=16 */ if (pin_id % 32 >= 16) reg += 0x04; + dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n", + reg, offset, value); + /* Get current state of pins */ old_val = readl(reg); old_val &= mask; @@ -139,7 +139,7 @@ u32 reg_offset) { void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; - int offset = pin_id % 16; + int offset = (pin_id % 16) * 2; /* Use the next register if the pin's port pin number is >=16 */ if (pin_id % 32 >= 16) --- linux-3.13.0.orig/drivers/pinctrl/pinctrl-at91.c +++ linux-3.13.0/drivers/pinctrl/pinctrl-at91.c @@ -1260,22 +1260,22 @@ switch (type) { case IRQ_TYPE_EDGE_RISING: - irq_set_handler(d->irq, handle_simple_irq); + __irq_set_handler_locked(d->irq, handle_simple_irq); writel_relaxed(mask, pio + PIO_ESR); writel_relaxed(mask, pio + PIO_REHLSR); break; case IRQ_TYPE_EDGE_FALLING: - irq_set_handler(d->irq, handle_simple_irq); + __irq_set_handler_locked(d->irq, handle_simple_irq); writel_relaxed(mask, pio + PIO_ESR); writel_relaxed(mask, pio + PIO_FELLSR); break; case IRQ_TYPE_LEVEL_LOW: - irq_set_handler(d->irq, handle_level_irq); + __irq_set_handler_locked(d->irq, handle_level_irq); writel_relaxed(mask, pio + PIO_LSR); writel_relaxed(mask, pio + PIO_FELLSR); break; case IRQ_TYPE_LEVEL_HIGH: - irq_set_handler(d->irq, handle_level_irq); + __irq_set_handler_locked(d->irq, handle_level_irq); writel_relaxed(mask, pio + PIO_LSR); writel_relaxed(mask, pio + PIO_REHLSR); break; @@ -1284,7 +1284,7 @@ * disable additional interrupt modes: * fall back to default behavior */ - irq_set_handler(d->irq, handle_simple_irq); + __irq_set_handler_locked(d->irq, handle_simple_irq); writel_relaxed(mask, pio + PIO_AIMDR); return 0; case IRQ_TYPE_NONE: --- linux-3.13.0.orig/drivers/pinctrl/vt8500/pinctrl-wmt.c +++ linux-3.13.0/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -276,7 +276,20 @@ if (!configs) return -ENOMEM; - configs[0] = pull; + switch (pull) { + case 0: + configs[0] = PIN_CONFIG_BIAS_DISABLE; + break; + case 1: + configs[0] = PIN_CONFIG_BIAS_PULL_DOWN; + break; + case 2: + configs[0] = PIN_CONFIG_BIAS_PULL_UP; + break; + default: + configs[0] = PIN_CONFIG_BIAS_DISABLE; + dev_err(data->dev, "invalid pull state %d - disabling\n", pull); + } map->type = PIN_MAP_TYPE_CONFIGS_PIN; map->data.configs.group_or_pin = data->groups[group]; --- linux-3.13.0.orig/drivers/ata/libata-pmp.c +++ linux-3.13.0/drivers/ata/libata-pmp.c @@ -447,8 +447,11 @@ * otherwise. Don't try hard to recover it. */ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; - } else if (vendor == 0x197b && devid == 0x2352) { - /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */ + } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) { + /* + * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350? + * 0x0325: jmicron JMB394. + */ ata_for_each_link(link, ap, EDGE) { /* SRST breaks detection and disks get misclassified * LPM disabled to avoid potential problems --- linux-3.13.0.orig/drivers/ata/ahci_xgene.c +++ linux-3.13.0/drivers/ata/ahci_xgene.c @@ -0,0 +1,486 @@ +/* + * AppliedMicro X-Gene SoC SATA Host Controller Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Loc Ho + * Tuan Phan + * Suman Tripathi + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * NOTE: PM support is not currently available. + * + */ +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +/* Max # of disk per a controller */ +#define MAX_AHCI_CHN_PERCTR 2 + +/* MUX CSR */ +#define SATA_ENET_CONFIG_REG 0x00000000 +#define CFG_SATA_ENET_SELECT_MASK 0x00000001 + +/* SATA core host controller CSR */ +#define SLVRDERRATTRIBUTES 0x00000000 +#define SLVWRERRATTRIBUTES 0x00000004 +#define MSTRDERRATTRIBUTES 0x00000008 +#define MSTWRERRATTRIBUTES 0x0000000c +#define BUSCTLREG 0x00000014 +#define IOFMSTRWAUX 0x00000018 +#define INTSTATUSMASK 0x0000002c +#define ERRINTSTATUS 0x00000030 +#define ERRINTSTATUSMASK 0x00000034 + +/* SATA host AHCI CSR */ +#define PORTCFG 0x000000a4 +#define PORTADDR_SET(dst, src) \ + (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f)) +#define PORTPHY1CFG 0x000000a8 +#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \ + (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000)) +#define PORTPHY2CFG 0x000000ac +#define PORTPHY3CFG 0x000000b0 +#define PORTPHY4CFG 0x000000b4 +#define PORTPHY5CFG 0x000000b8 +#define SCTL0 0x0000012C +#define PORTPHY5CFG_RTCHG_SET(dst, src) \ + (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000)) +#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \ + (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000)) +#define PORTAXICFG 0x000000bc +#define PORTAXICFG_OUTTRANS_SET(dst, src) \ + (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000)) + +/* SATA host controller AXI CSR */ +#define INT_SLV_TMOMASK 0x00000010 + +/* SATA diagnostic CSR */ +#define CFG_MEM_RAM_SHUTDOWN 0x00000070 +#define BLOCK_MEM_RDY 0x00000074 + +struct xgene_ahci_context { + struct ahci_host_priv *hpriv; + struct device *dev; + void __iomem *csr_core; /* Core CSR address of IP */ + void __iomem *csr_diag; /* Diag CSR address of IP */ + void __iomem *csr_axi; /* AXI CSR address of IP */ + void __iomem *csr_mux; /* MUX CSR address of IP */ +}; + +static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) +{ + dev_dbg(ctx->dev, "Release memory from shutdown\n"); + writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); + readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */ + msleep(1); /* reset may take up to 1ms */ + if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) { + dev_err(ctx->dev, "failed to release memory from shutdown\n"); + return -ENODEV; + } + return 0; +} + +/** + * xgene_ahci_read_id - Read ID data from the specified device + * @dev: device + * @tf: proposed taskfile + * @id: data buffer + * + * This custom read ID function is required due to the fact that the HW + * does not support DEVSLP and the controller state machine may get stuck + * after processing the ID query command. + */ +static unsigned int xgene_ahci_read_id(struct ata_device *dev, + struct ata_taskfile *tf, u16 *id) +{ + u32 err_mask; + void __iomem *port_mmio = ahci_port_base(dev->link->ap); + + err_mask = ata_do_dev_read_id(dev, tf, id); + if (err_mask) + return err_mask; + + /* + * Mask reserved area. Word78 spec of Link Power Management + * bit15-8: reserved + * bit7: NCQ autosence + * bit6: Software settings preservation supported + * bit5: reserved + * bit4: In-order sata delivery supported + * bit3: DIPM requests supported + * bit2: DMA Setup FIS Auto-Activate optimization supported + * bit1: DMA Setup FIX non-Zero buffer offsets supported + * bit0: Reserved + * + * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP + */ + id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); + + /* + * Due to HW errata, restart the port if no other command active. + * Otherwise the controller may get stuck. + */ + if (!readl(port_mmio + PORT_CMD_ISSUE)) { + writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); /* Force a barrier */ + writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); /* Force a barrier */ + } + return 0; +} + +static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) +{ + void __iomem *mmio = ctx->hpriv->mmio; + u32 val; + + dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n", + mmio, channel); + val = readl(mmio + PORTCFG); + val = PORTADDR_SET(val, channel == 0 ? 2 : 3); + writel(val, mmio + PORTCFG); + readl(mmio + PORTCFG); /* Force a barrier */ + /* Disable fix rate */ + writel(0x0001fffe, mmio + PORTPHY1CFG); + readl(mmio + PORTPHY1CFG); /* Force a barrier */ + writel(0x5018461c, mmio + PORTPHY2CFG); + readl(mmio + PORTPHY2CFG); /* Force a barrier */ + writel(0x1c081907, mmio + PORTPHY3CFG); + readl(mmio + PORTPHY3CFG); /* Force a barrier */ + writel(0x1c080815, mmio + PORTPHY4CFG); + readl(mmio + PORTPHY4CFG); /* Force a barrier */ + /* Set window negotiation */ + val = readl(mmio + PORTPHY5CFG); + val = PORTPHY5CFG_RTCHG_SET(val, 0x300); + writel(val, mmio + PORTPHY5CFG); + readl(mmio + PORTPHY5CFG); /* Force a barrier */ + val = readl(mmio + PORTAXICFG); + val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */ + val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */ + writel(val, mmio + PORTAXICFG); + readl(mmio + PORTAXICFG); /* Force a barrier */ +} + +/** + * xgene_ahci_do_hardreset - Issue the actual COMRESET + * @link: link to reset + * @deadline: deadline jiffies for the operation + * @online: Return value to indicate if device online + * + * Due to the limitation of the hardware PHY, a difference set of setting is + * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps), + * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will + * report disparity error and etc. In addition, during COMRESET, there can + * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and + * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following + * algorithm is followed to proper configure the hardware PHY during COMRESET: + * + * Alg Part 1: + * 1. Start the PHY at Gen3 speed (default setting) + * 2. Issue the COMRESET + * 3. If no link, go to Alg Part 3 + * 4. If link up, determine if the negotiated speed matches the PHY + * configured speed + * 5. If they matched, go to Alg Part 2 + * 6. If they do not matched and first time, configure the PHY for the linked + * up disk speed and repeat step 2 + * 7. Go to Alg Part 2 + * + * Alg Part 2: + * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error + * reported in the register PORT_SCR_ERR, then reset the PHY receiver line + * 2. Go to Alg Part 3 + * + * Alg Part 3: + * 1. Clear any pending from register PORT_SCR_ERR. + * + * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition + * and until the underlying PHY supports an method to reset the receiver + * line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors, + * an warning message will be printed. + */ +static int xgene_ahci_do_hardreset(struct ata_link *link, + unsigned long deadline, bool *online) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; + struct xgene_ahci_context *ctx = hpriv->plat_data; + struct ahci_port_priv *pp = ap->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + void __iomem *port_mmio = ahci_port_base(ap); + struct ata_taskfile tf; + int rc; + u32 val; + + /* clear D2H reception area to properly wait for D2H FIS */ + ata_tf_init(link->device, &tf); + tf.command = ATA_BUSY; + ata_tf_to_fis(&tf, 0, 0, d2h_fis); + rc = sata_link_hardreset(link, timing, deadline, online, + ahci_check_ready); + + val = readl(port_mmio + PORT_SCR_ERR); + if (val & (SERR_DISPARITY | SERR_10B_8B_ERR)) + dev_warn(ctx->dev, "link has error\n"); + + /* clear all errors if any pending */ + val = readl(port_mmio + PORT_SCR_ERR); + writel(val, port_mmio + PORT_SCR_ERR); + + return rc; +} + +static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + bool online; + int rc; + u32 portcmd_saved; + u32 portclb_saved; + u32 portclbhi_saved; + u32 portrxfis_saved; + u32 portrxfishi_saved; + + /* As hardreset resets these CSR, save it to restore later */ + portcmd_saved = readl(port_mmio + PORT_CMD); + portclb_saved = readl(port_mmio + PORT_LST_ADDR); + portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI); + portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); + portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); + + ahci_stop_engine(ap); + + rc = xgene_ahci_do_hardreset(link, deadline, &online); + + /* As controller hardreset clears them, restore them */ + writel(portcmd_saved, port_mmio + PORT_CMD); + writel(portclb_saved, port_mmio + PORT_LST_ADDR); + writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI); + writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR); + writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI); + + hpriv->start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); + + return rc; +} + +static void xgene_ahci_host_stop(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; + + ahci_platform_disable_resources(hpriv); +} + +static struct ata_port_operations xgene_ahci_ops = { + .inherits = &ahci_ops, + .host_stop = xgene_ahci_host_stop, + .hardreset = xgene_ahci_hardreset, + .read_id = xgene_ahci_read_id, +}; + +static const struct ata_port_info xgene_ahci_port_info = { + AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &xgene_ahci_ops, +}; + +static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) +{ + struct xgene_ahci_context *ctx = hpriv->plat_data; + int i; + int rc; + u32 val; + + /* Remove IP RAM out of shutdown */ + rc = xgene_ahci_init_memram(ctx); + if (rc) + return rc; + + for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++) + xgene_ahci_set_phy_cfg(ctx, i); + + /* AXI disable Mask */ + writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT); + readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */ + writel(0, ctx->csr_core + INTSTATUSMASK); + val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */ + dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n", + INTSTATUSMASK, val); + + writel(0x0, ctx->csr_core + ERRINTSTATUSMASK); + readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */ + writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK); + readl(ctx->csr_axi + INT_SLV_TMOMASK); + + /* Enable AXI Interrupt */ + writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES); + writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES); + writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES); + writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES); + + /* Enable coherency */ + val = readl(ctx->csr_core + BUSCTLREG); + val &= ~0x00000002; /* Enable write coherency */ + val &= ~0x00000001; /* Enable read coherency */ + writel(val, ctx->csr_core + BUSCTLREG); + + val = readl(ctx->csr_core + IOFMSTRWAUX); + val |= (1 << 3); /* Enable read coherency */ + val |= (1 << 9); /* Enable write coherency */ + writel(val, ctx->csr_core + IOFMSTRWAUX); + val = readl(ctx->csr_core + IOFMSTRWAUX); + dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n", + IOFMSTRWAUX, val); + + return rc; +} + +static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx) +{ + u32 val; + + /* Check for optional MUX resource */ + if (IS_ERR(ctx->csr_mux)) + return 0; + + val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); + val &= ~CFG_SATA_ENET_SELECT_MASK; + writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG); + val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); + return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0; +} + +static int xgene_ahci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct xgene_ahci_context *ctx; + struct resource *res; + int rc; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + hpriv->plat_data = ctx; + ctx->hpriv = hpriv; + ctx->dev = dev; + + /* Retrieve the IP core resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ctx->csr_core = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->csr_core)) + return PTR_ERR(ctx->csr_core); + + /* Retrieve the IP diagnostic resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + ctx->csr_diag = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->csr_diag)) + return PTR_ERR(ctx->csr_diag); + + /* Retrieve the IP AXI resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 3); + ctx->csr_axi = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->csr_axi)) + return PTR_ERR(ctx->csr_axi); + + /* Retrieve the optional IP mux resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 4); + ctx->csr_mux = devm_ioremap_resource(dev, res); + + dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, + hpriv->mmio); + + /* Select ATA */ + if ((rc = xgene_ahci_mux_select(ctx))) { + dev_err(dev, "SATA mux selection failed error %d\n", rc); + return -ENODEV; + } + + /* Due to errata, HW requires full toggle transition */ + rc = ahci_platform_enable_clks(hpriv); + if (rc) + goto disable_resources; + ahci_platform_disable_clks(hpriv); + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + goto disable_resources; + + /* Configure the host controller */ + xgene_ahci_hw_init(hpriv); + + /* + * Setup DMA mask. This is preliminary until the DMA range is sorted + * out. + */ + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (rc) { + dev_err(dev, "Unable to set dma mask\n"); + goto disable_resources; + } + + rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0); + if (rc) + goto disable_resources; + + dev_dbg(dev, "X-Gene SATA host controller initialized\n"); + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + return rc; +} + +static const struct of_device_id xgene_ahci_of_match[] = { + {.compatible = "apm,xgene-ahci"}, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); + +static struct platform_driver xgene_ahci_driver = { + .probe = xgene_ahci_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = "xgene-ahci", + .owner = THIS_MODULE, + .of_match_table = xgene_ahci_of_match, + }, +}; + +module_platform_driver(xgene_ahci_driver); + +MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver"); +MODULE_AUTHOR("Loc Ho "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.4"); --- linux-3.13.0.orig/drivers/ata/ahci_platform.c +++ linux-3.13.0/drivers/ata/ahci_platform.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "ahci.h" static void ahci_host_stop(struct ata_host *host); @@ -87,78 +89,284 @@ AHCI_SHT("ahci_platform"), }; -static int ahci_probe(struct platform_device *pdev) +/** + * ahci_platform_enable_clks - Enable platform clocks + * @hpriv: host private area to store config values + * + * This function enables all the clks found in hpriv->clks, starting at + * index 0. If any clk fails to enable it disables all the clks already + * enabled in reverse order, and then returns an error. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv) +{ + int c, rc; + + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) { + rc = clk_prepare_enable(hpriv->clks[c]); + if (rc) + goto disable_unprepare_clk; + } + return 0; + +disable_unprepare_clk: + while (--c >= 0) + clk_disable_unprepare(hpriv->clks[c]); + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_enable_clks); + +/** + * ahci_platform_disable_clks - Disable platform clocks + * @hpriv: host private area to store config values + * + * This function disables all the clks found in hpriv->clks, in reverse + * order of ahci_platform_enable_clks (starting at the end of the array). + */ +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) +{ + int c; + + for (c = AHCI_MAX_CLKS - 1; c >= 0; c--) + if (hpriv->clks[c]) + clk_disable_unprepare(hpriv->clks[c]); +} +EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); + +/** + * ahci_platform_enable_resources - Enable platform resources + * @hpriv: host private area to store config values + * + * This function enables all ahci_platform managed resources in the + * following order: + * 1) Regulator + * 2) Clocks (through ahci_platform_enable_clks) + * 3) Phy + * + * If resource enabling fails at any point the previous enabled resources + * are disabled in reverse order. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) { - struct device *dev = &pdev->dev; - struct ahci_platform_data *pdata = dev_get_platdata(dev); - const struct platform_device_id *id = platform_get_device_id(pdev); - struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0]; - const struct ata_port_info *ppi[] = { &pi, NULL }; - struct ahci_host_priv *hpriv; - struct ata_host *host; - struct resource *mem; - int irq; - int n_ports; - int i; int rc; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(dev, "no mmio space\n"); - return -EINVAL; + if (hpriv->target_pwr) { + rc = regulator_enable(hpriv->target_pwr); + if (rc) + return rc; } - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(dev, "no irq\n"); - return -EINVAL; + rc = ahci_platform_enable_clks(hpriv); + if (rc) + goto disable_regulator; + + if (hpriv->phy) { + rc = phy_init(hpriv->phy); + if (rc) + goto disable_clks; + + rc = phy_power_on(hpriv->phy); + if (rc) { + phy_exit(hpriv->phy); + goto disable_clks; + } } - if (pdata && pdata->ata_port_info) - pi = *pdata->ata_port_info; + return 0; - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) { - dev_err(dev, "can't alloc ahci_host_priv\n"); - return -ENOMEM; +disable_clks: + ahci_platform_disable_clks(hpriv); + +disable_regulator: + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); + +/** + * ahci_platform_disable_resources - Disable platform resources + * @hpriv: host private area to store config values + * + * This function disables all ahci_platform managed resources in the + * following order: + * 1) Phy + * 2) Clocks (through ahci_platform_disable_clks) + * 3) Regulator + */ +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) +{ + if (hpriv->phy) { + phy_power_off(hpriv->phy); + phy_exit(hpriv->phy); } - hpriv->flags |= (unsigned long)pi.private_data; + ahci_platform_disable_clks(hpriv); + + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); +} +EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); + +static void ahci_platform_put_resources(struct device *dev, void *res) +{ + struct ahci_host_priv *hpriv = res; + int c; + + if (hpriv->got_runtime_pm) { + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + } + + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) + clk_put(hpriv->clks[c]); +} - hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); +/** + * ahci_platform_get_resources - Get platform resources + * @pdev: platform device to get resources for + * + * This function allocates an ahci_host_priv struct, and gets the following + * resources, storing a reference to them inside the returned struct: + * + * 1) mmio registers (IORESOURCE_MEM 0, mandatory) + * 2) regulator for controlling the targets power (optional) + * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, + * or for non devicetree enabled platforms a single clock + * 4) phy (optional) + * + * RETURNS: + * The allocated ahci_host_priv on success, otherwise an ERR_PTR value + */ +struct ahci_host_priv *ahci_platform_get_resources( + struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct clk *clk; + int i, rc = -ENOMEM; + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return ERR_PTR(-ENOMEM); + + hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv), + GFP_KERNEL); + if (!hpriv) + goto err_out; + + devres_add(dev, hpriv); + + hpriv->mmio = devm_ioremap_resource(dev, + platform_get_resource(pdev, IORESOURCE_MEM, 0)); if (!hpriv->mmio) { - dev_err(dev, "can't map %pR\n", mem); - return -ENOMEM; + dev_err(dev, "no mmio space\n"); + goto err_out; } - hpriv->clk = clk_get(dev, NULL); - if (IS_ERR(hpriv->clk)) { - dev_err(dev, "can't get clock\n"); - } else { - rc = clk_prepare_enable(hpriv->clk); - if (rc) { - dev_err(dev, "clock prepare enable failed"); - goto free_clk; + hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); + if (IS_ERR(hpriv->target_pwr)) { + rc = PTR_ERR(hpriv->target_pwr); + if (rc == -EPROBE_DEFER) + goto err_out; + hpriv->target_pwr = NULL; + } + + for (i = 0; i < AHCI_MAX_CLKS; i++) { + /* + * For now we must use clk_get(dev, NULL) for the first clock, + * because some platforms (da850, spear13xx) are not yet + * converted to use devicetree for clocks. For new platforms + * this is equivalent to of_clk_get(dev->of_node, 0). + */ + if (i == 0) + clk = clk_get(dev, NULL); + else + clk = of_clk_get(dev->of_node, i); + + if (IS_ERR(clk)) { + rc = PTR_ERR(clk); + if (rc == -EPROBE_DEFER) + goto err_out; + break; } + hpriv->clks[i] = clk; } - /* - * Some platforms might need to prepare for mmio region access, - * which could be done in the following init call. So, the mmio - * region shouldn't be accessed before init (if provided) has - * returned successfully. - */ - if (pdata && pdata->init) { - rc = pdata->init(dev, hpriv->mmio); - if (rc) - goto disable_unprepare_clk; + hpriv->phy = devm_phy_get(dev, "sata-phy"); + if (IS_ERR(hpriv->phy)) { + rc = PTR_ERR(hpriv->phy); + switch (rc) { + case -ENODEV: + case -ENOSYS: + /* continue normally */ + hpriv->phy = NULL; + break; + + case -EPROBE_DEFER: + goto err_out; + + default: + dev_err(dev, "couldn't get sata-phy\n"); + goto err_out; + } } - ahci_save_initial_config(dev, hpriv, - pdata ? pdata->force_port_map : 0, - pdata ? pdata->mask_port_map : 0); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + hpriv->got_runtime_pm = true; + + devres_remove_group(dev, NULL); + return hpriv; + +err_out: + devres_release_group(dev, NULL); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(ahci_platform_get_resources); + +/** + * ahci_platform_init_host - Bring up an ahci-platform host + * @pdev: platform device pointer for the host + * @hpriv: ahci-host private data for the host + * @pi_template: template for the ata_port_info to use + * @force_port_map: param passed to ahci_save_initial_config + * @mask_port_map: param passed to ahci_save_initial_config + * + * This function does all the usual steps needed to bring up an + * ahci-platform host, note any necessary resources (ie clks, phy, etc.) + * must be initialized / enabled before calling this. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_init_host(struct platform_device *pdev, + struct ahci_host_priv *hpriv, + const struct ata_port_info *pi_template, + unsigned int force_port_map, + unsigned int mask_port_map) +{ + struct device *dev = &pdev->dev; + struct ata_port_info pi = *pi_template; + const struct ata_port_info *ppi[] = { &pi, NULL }; + struct ata_host *host; + int i, irq, n_ports, rc; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "no irq\n"); + return -EINVAL; + } /* prepare host */ + hpriv->flags |= (unsigned long)pi.private_data; + + ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map); + if (hpriv->cap & HOST_CAP_NCQ) pi.flags |= ATA_FLAG_NCQ; @@ -175,10 +383,8 @@ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); host = ata_host_alloc_pinfo(dev, ppi, n_ports); - if (!host) { - rc = -ENOMEM; - goto pdata_exit; - } + if (!host) + return -ENOMEM; host->private_data = hpriv; @@ -193,7 +399,8 @@ for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - ata_port_desc(ap, "mmio %pR", mem); + ata_port_desc(ap, "mmio %pR", + platform_get_resource(pdev, IORESOURCE_MEM, 0)); ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); /* set enclosure management message type */ @@ -207,13 +414,53 @@ rc = ahci_reset_controller(host); if (rc) - goto pdata_exit; + return rc; ahci_init_controller(host); ahci_print_info(host, "platform"); - rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, - &ahci_platform_sht); + return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, + &ahci_platform_sht); +} +EXPORT_SYMBOL_GPL(ahci_platform_init_host); + +static int ahci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_platform_data *pdata = dev_get_platdata(dev); + const struct platform_device_id *id = platform_get_device_id(pdev); + const struct ata_port_info *pi_template; + struct ahci_host_priv *hpriv; + int rc; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + + /* + * Some platforms might need to prepare for mmio region access, + * which could be done in the following init call. So, the mmio + * region shouldn't be accessed before init (if provided) has + * returned successfully. + */ + if (pdata && pdata->init) { + rc = pdata->init(dev, hpriv->mmio); + if (rc) + goto disable_resources; + } + + if (pdata && pdata->ata_port_info) + pi_template = pdata->ata_port_info; + else + pi_template = &ahci_port_info[id ? id->driver_data : 0]; + + rc = ahci_platform_init_host(pdev, hpriv, pi_template, + pdata ? pdata->force_port_map : 0, + pdata ? pdata->mask_port_map : 0); if (rc) goto pdata_exit; @@ -221,12 +468,8 @@ pdata_exit: if (pdata && pdata->exit) pdata->exit(dev); -disable_unprepare_clk: - if (!IS_ERR(hpriv->clk)) - clk_disable_unprepare(hpriv->clk); -free_clk: - if (!IS_ERR(hpriv->clk)) - clk_put(hpriv->clk); +disable_resources: + ahci_platform_disable_resources(hpriv); return rc; } @@ -239,21 +482,27 @@ if (pdata && pdata->exit) pdata->exit(dev); - if (!IS_ERR(hpriv->clk)) { - clk_disable_unprepare(hpriv->clk); - clk_put(hpriv->clk); - } + ahci_platform_disable_resources(hpriv); } #ifdef CONFIG_PM_SLEEP -static int ahci_suspend(struct device *dev) +/** + * ahci_platform_suspend_host - Suspend an ahci-platform host + * @dev: device pointer for the host + * + * This function does all the usual steps needed to suspend an + * ahci-platform host, note any necessary resources (ie clks, phy, etc.) + * must be disabled after calling this. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_suspend_host(struct device *dev) { - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; void __iomem *mmio = hpriv->mmio; u32 ctl; - int rc; if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { dev_err(dev, "firmware update required for suspend/resume\n"); @@ -270,61 +519,118 @@ writel(ctl, mmio + HOST_CTL); readl(mmio + HOST_CTL); /* flush */ - rc = ata_host_suspend(host, PMSG_SUSPEND); + return ata_host_suspend(host, PMSG_SUSPEND); +} +EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); + +/** + * ahci_platform_resume_host - Resume an ahci-platform host + * @dev: device pointer for the host + * + * This function does all the usual steps needed to resume an ahci-platform + * host, note any necessary resources (ie clks, phy, etc.) must be + * initialized / enabled before calling this. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_resume_host(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + int rc; + + if (dev->power.power_state.event == PM_EVENT_SUSPEND) { + rc = ahci_reset_controller(host); + if (rc) + return rc; + + ahci_init_controller(host); + } + + ata_host_resume(host); + + return 0; +} +EXPORT_SYMBOL_GPL(ahci_platform_resume_host); + +/** + * ahci_platform_suspend - Suspend an ahci-platform device + * @dev: the platform device to suspend + * + * This function suspends the host associated with the device, followed by + * disabling all the resources of the device. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_suspend(struct device *dev) +{ + struct ahci_platform_data *pdata = dev_get_platdata(dev); + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + int rc; + + rc = ahci_platform_suspend_host(dev); if (rc) return rc; if (pdata && pdata->suspend) return pdata->suspend(dev); - if (!IS_ERR(hpriv->clk)) - clk_disable_unprepare(hpriv->clk); + ahci_platform_disable_resources(hpriv); return 0; } +EXPORT_SYMBOL_GPL(ahci_platform_suspend); -static int ahci_resume(struct device *dev) +/** + * ahci_platform_resume - Resume an ahci-platform device + * @dev: the platform device to resume + * + * This function enables all the resources of the device followed by + * resuming the host associated with the device. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_resume(struct device *dev) { struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; int rc; - if (!IS_ERR(hpriv->clk)) { - rc = clk_prepare_enable(hpriv->clk); - if (rc) { - dev_err(dev, "clock prepare enable failed"); - return rc; - } - } + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; if (pdata && pdata->resume) { rc = pdata->resume(dev); if (rc) - goto disable_unprepare_clk; + goto disable_resources; } - if (dev->power.power_state.event == PM_EVENT_SUSPEND) { - rc = ahci_reset_controller(host); - if (rc) - goto disable_unprepare_clk; - - ahci_init_controller(host); - } + rc = ahci_platform_resume_host(dev); + if (rc) + goto disable_resources; - ata_host_resume(host); + /* We resumed so update PM runtime state */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); return 0; -disable_unprepare_clk: - if (!IS_ERR(hpriv->clk)) - clk_disable_unprepare(hpriv->clk); +disable_resources: + ahci_platform_disable_resources(hpriv); return rc; } +EXPORT_SYMBOL_GPL(ahci_platform_resume); #endif -static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); +static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend, + ahci_platform_resume); static const struct of_device_id ahci_of_match[] = { { .compatible = "snps,spear-ahci", }, --- linux-3.13.0.orig/drivers/ata/sata_highbank.c +++ linux-3.13.0/drivers/ata/sata_highbank.c @@ -404,6 +404,7 @@ static const unsigned long timing[] = { 5, 100, 500}; struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; bool online; @@ -432,7 +433,7 @@ break; } while (!online && retry--); - ahci_start_engine(ap); + hpriv->start_engine(ap); if (online) *class = ahci_dev_classify(ap); --- linux-3.13.0.orig/drivers/ata/sata_sil.c +++ linux-3.13.0/drivers/ata/sata_sil.c @@ -157,6 +157,7 @@ { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, { "ST3120022ASL", SIL_QUIRK_MOD15WRITE }, { "ST3160021ASL", SIL_QUIRK_MOD15WRITE }, + { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE }, { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX }, { } }; --- linux-3.13.0.orig/drivers/ata/ahci.c +++ linux-3.13.0/drivers/ata/ahci.c @@ -61,6 +61,7 @@ /* board IDs by feature in alphabetical order */ board_ahci, board_ahci_ign_iferr, + board_ahci_noncq, board_ahci_nosntf, board_ahci_yes_fbs, @@ -119,6 +120,13 @@ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_noncq] = { + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_nosntf] = { AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF), .flags = AHCI_FLAG_COMMON, @@ -450,6 +458,12 @@ { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ + /* + * Samsung SSDs found on some macbooks. NCQ times out. + * https://bugzilla.kernel.org/show_bug.cgi?id=60731 + */ + { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq }, + /* Enmotus */ { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, @@ -562,6 +576,7 @@ unsigned long deadline) { struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; bool online; int rc; @@ -572,7 +587,7 @@ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline, &online, NULL); - ahci_start_engine(ap); + hpriv->start_engine(ap); DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); @@ -587,6 +602,7 @@ { struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; bool online; @@ -602,7 +618,7 @@ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline, &online, NULL); - ahci_start_engine(ap); + hpriv->start_engine(ap); /* The pseudo configuration device on SIMG4726 attached to * ASUS P5W-DH Deluxe doesn't send signature FIS after --- linux-3.13.0.orig/drivers/ata/libahci.c +++ linux-3.13.0/drivers/ata/libahci.c @@ -394,6 +394,9 @@ * * If inconsistent, config values are fixed up by this function. * + * If it is not set already this function sets hpriv->start_engine to + * ahci_start_engine. + * * LOCKING: * None. */ @@ -500,6 +503,9 @@ hpriv->cap = cap; hpriv->cap2 = cap2; hpriv->port_map = port_map; + + if (!hpriv->start_engine) + hpriv->start_engine = ahci_start_engine; } EXPORT_SYMBOL_GPL(ahci_save_initial_config); @@ -766,7 +772,7 @@ /* enable DMA */ if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE)) - ahci_start_engine(ap); + hpriv->start_engine(ap); /* turn on LEDs */ if (ap->flags & ATA_FLAG_EM) { @@ -1234,7 +1240,7 @@ /* restart engine */ out_restart: - ahci_start_engine(ap); + hpriv->start_engine(ap); return rc; } EXPORT_SYMBOL_GPL(ahci_kick_engine); @@ -1426,6 +1432,7 @@ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; bool online; @@ -1443,7 +1450,7 @@ rc = sata_link_hardreset(link, timing, deadline, &online, ahci_check_ready); - ahci_start_engine(ap); + hpriv->start_engine(ap); if (online) *class = ahci_dev_classify(ap); @@ -2007,10 +2014,12 @@ void ahci_error_handler(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { /* restart engine */ ahci_stop_engine(ap); - ahci_start_engine(ap); + hpriv->start_engine(ap); } sata_pmp_error_handler(ap); @@ -2031,6 +2040,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) { + struct ahci_host_priv *hpriv = ap->host->private_data; void __iomem *port_mmio = ahci_port_base(ap); struct ata_device *dev = ap->link.device; u32 devslp, dm, dito, mdat, deto; @@ -2094,7 +2104,7 @@ PORT_DEVSLP_ADSE); writel(devslp, port_mmio + PORT_DEVSLP); - ahci_start_engine(ap); + hpriv->start_engine(ap); /* enable device sleep feature for the drive */ err_mask = ata_dev_set_feature(dev, @@ -2106,6 +2116,7 @@ static void ahci_enable_fbs(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); u32 fbs; @@ -2134,11 +2145,12 @@ } else dev_err(ap->host->dev, "Failed to enable FBS\n"); - ahci_start_engine(ap); + hpriv->start_engine(ap); } static void ahci_disable_fbs(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); u32 fbs; @@ -2166,7 +2178,7 @@ pp->fbs_enabled = false; } - ahci_start_engine(ap); + hpriv->start_engine(ap); } static void ahci_pmp_attach(struct ata_port *ap) --- linux-3.13.0.orig/drivers/ata/Makefile +++ linux-3.13.0/drivers/ata/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o obj-$(CONFIG_AHCI_IMX) += ahci_imx.o +obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o --- linux-3.13.0.orig/drivers/ata/Kconfig +++ linux-3.13.0/drivers/ata/Kconfig @@ -106,6 +106,13 @@ If unsure, say N. +config AHCI_XGENE + tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support" + depends on SATA_AHCI_PLATFORM && (ARM64 || COMPILE_TEST) + select PHY_XGENE + help + This option enables support for APM X-Gene SoC SATA host controller. + config SATA_FSL tristate "Freescale 3.0Gbps SATA support" depends on FSL_SOC --- linux-3.13.0.orig/drivers/ata/sata_mv.c +++ linux-3.13.0/drivers/ata/sata_mv.c @@ -304,6 +304,7 @@ MV5_LTMODE = 0x30, MV5_PHY_CTL = 0x0C, SATA_IFCFG = 0x050, + LP_PHY_CTL = 0x058, MV_M2_PREAMP_MASK = 0x7e0, @@ -431,6 +432,7 @@ MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */ + MV_HP_FIX_LP_PHY_CTL = (1 << 13), /* fix speed in LP_PHY_CTL ? */ /* Port private flags (pp_flags) */ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ @@ -1358,6 +1360,7 @@ if (ofs != 0xffffffffU) { void __iomem *addr = mv_ap_base(link->ap) + ofs; + struct mv_host_priv *hpriv = link->ap->host->private_data; if (sc_reg_in == SCR_CONTROL) { /* * Workaround for 88SX60x1 FEr SATA#26: @@ -1374,6 +1377,18 @@ */ if ((val & 0xf) == 1 || (readl(addr) & 0xf) == 1) val |= 0xf000; + + if (hpriv->hp_flags & MV_HP_FIX_LP_PHY_CTL) { + void __iomem *lp_phy_addr = + mv_ap_base(link->ap) + LP_PHY_CTL; + /* + * Set PHY speed according to SControl speed. + */ + if ((val & 0xf0) == 0x10) + writelfl(0x7, lp_phy_addr); + else + writelfl(0x227, lp_phy_addr); + } } writelfl(val, addr); return 0; @@ -4110,6 +4125,15 @@ if (rc) goto err; + /* + * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be + * updated in the LP_PHY_CTL register. + */ + if (pdev->dev.of_node && + of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-370-sata")) + hpriv->hp_flags |= MV_HP_FIX_LP_PHY_CTL; + /* initialize adapter */ rc = mv_init_host(host); if (rc) @@ -4209,6 +4233,7 @@ #ifdef CONFIG_OF static struct of_device_id mv_sata_dt_ids[] = { + { .compatible = "marvell,armada-370-sata", }, { .compatible = "marvell,orion-sata", }, {}, }; --- linux-3.13.0.orig/drivers/ata/ahci.h +++ linux-3.13.0/drivers/ata/ahci.h @@ -37,6 +37,8 @@ #include #include +#include +#include /* Enclosure Management Control */ #define EM_CTRL_MSG_TYPE 0x000f0000 @@ -51,6 +53,7 @@ enum { AHCI_MAX_PORTS = 32, + AHCI_MAX_CLKS = 3, AHCI_MAX_SG = 168, /* hardware max is 64K */ AHCI_DMA_BOUNDARY = 0xffffffff, AHCI_MAX_CMDS = 32, @@ -321,8 +324,17 @@ u32 em_loc; /* enclosure management location */ u32 em_buf_sz; /* EM buffer size in byte */ u32 em_msg_type; /* EM message type */ - struct clk *clk; /* Only for platforms supporting clk */ + bool got_runtime_pm; /* Did we do pm_runtime_get? */ + struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ + struct regulator *target_pwr; /* Optional */ + struct phy *phy; /* If platform uses phy */ void *plat_data; /* Other platform data */ + /* + * Optional ahci_start_engine override, if not set this gets set to the + * default ahci_start_engine during ahci_save_initial_config, this can + * be overridden anytime before the host is activated. + */ + void (*start_engine)(struct ata_port *ap); }; extern int ahci_ignore_sss; --- linux-3.13.0.orig/drivers/ata/libata-core.c +++ linux-3.13.0/drivers/ata/libata-core.c @@ -2222,6 +2222,16 @@ if (rc) return rc; + /* some WD SATA-1 drives have issues with LPM, turn on NOLPM for them */ + if ((dev->horkage & ATA_HORKAGE_WD_BROKEN_LPM) && + (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2) + dev->horkage |= ATA_HORKAGE_NOLPM; + + if (dev->horkage & ATA_HORKAGE_NOLPM) { + ata_dev_warn(dev, "LPM support broken, forcing max_power\n"); + dev->link->ap->target_lpm_policy = ATA_LPM_MAX_POWER; + } + /* let ACPI work its magic */ rc = ata_acpi_on_devcfg(dev); if (rc) @@ -4165,6 +4175,7 @@ /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */ { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA }, + { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ @@ -4214,7 +4225,24 @@ /* devices that don't properly handle queued TRIM commands */ { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, - { "Crucial_CT???M500SSD1", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + + /* + * Some WD SATA-I drives spin up and down erratically when the link + * is put into the slumber mode. We don't have full list of the + * affected devices. Disable LPM if the device matches one of the + * known prefixes and is SATA-1. As a side effect LPM partial is + * lost too. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=57211 + */ + { "WDC WD800JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD1200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD1600JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD2000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD2500JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD3000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD3200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, /* End Marker */ { } --- linux-3.13.0.orig/drivers/ata/libata-scsi.c +++ linux-3.13.0/drivers/ata/libata-scsi.c @@ -111,12 +111,14 @@ [ATA_LPM_MIN_POWER] = "min_power", }; -static ssize_t ata_scsi_lpm_store(struct device *dev, +static ssize_t ata_scsi_lpm_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(dev); + struct Scsi_Host *shost = class_to_shost(device); struct ata_port *ap = ata_shost_to_port(shost); + struct ata_link *link; + struct ata_device *dev; enum ata_lpm_policy policy; unsigned long flags; @@ -132,10 +134,20 @@ return -EINVAL; spin_lock_irqsave(ap->lock, flags); + + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, &ap->link, ENABLED) { + if (dev->horkage & ATA_HORKAGE_NOLPM) { + count = -EOPNOTSUPP; + goto out_unlock; + } + } + } + ap->target_lpm_policy = policy; ata_port_schedule_eh(ap); +out_unlock: spin_unlock_irqrestore(ap->lock, flags); - return count; } --- linux-3.13.0.orig/drivers/of/address.c +++ linux-3.13.0/drivers/of/address.c @@ -99,11 +99,12 @@ static int of_bus_pci_match(struct device_node *np) { /* + * "pciex" is PCI Express * "vci" is for the /chaos bridge on 1st-gen PCI powermacs * "ht" is hypertransport */ - return !strcmp(np->type, "pci") || !strcmp(np->type, "vci") || - !strcmp(np->type, "ht"); + return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex") || + !strcmp(np->type, "vci") || !strcmp(np->type, "ht"); } static void of_bus_pci_count_cells(struct device_node *np, --- linux-3.13.0.orig/drivers/of/of_mdio.c +++ linux-3.13.0/drivers/of/of_mdio.c @@ -247,3 +247,17 @@ return IS_ERR(phy) ? NULL : phy; } EXPORT_SYMBOL(of_phy_connect_fixed_link); + +/* XXX add comment */ +struct phy_device *of_phy_attach(struct net_device *dev, + struct device_node *phy_np, u32 flags, + phy_interface_t iface) +{ + struct phy_device *phy = of_phy_find_device(phy_np); + + if (!phy) + return NULL; + + return phy_attach_direct(dev, phy, flags, iface) ? NULL : phy; +} +EXPORT_SYMBOL(of_phy_attach); --- linux-3.13.0.orig/drivers/pci/pci.c +++ linux-3.13.0/drivers/pci/pci.c @@ -1120,6 +1120,8 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; + u16 cmd; + u8 pin; err = pci_set_power_state(dev, PCI_D0); if (err < 0 && err != -EIO) @@ -1129,6 +1131,17 @@ return err; pci_fixup_device(pci_fixup_enable, dev); + if (dev->msi_enabled || dev->msix_enabled) + return 0; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_INTX_DISABLE) + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~PCI_COMMAND_INTX_DISABLE); + } + return 0; } --- linux-3.13.0.orig/drivers/pci/Makefile +++ linux-3.13.0/drivers/pci/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o obj-$(CONFIG_M68K) += setup-bus.o setup-irq.o +obj-$(CONFIG_ARM64) += setup-bus.o setup-irq.o # # ACPI Related PCI FW Functions --- linux-3.13.0.orig/drivers/pci/quirks.c +++ linux-3.13.0/drivers/pci/quirks.c @@ -40,6 +40,21 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); +/* The BAR0 ~ BAR4 of Marvell 9125 device can't be accessed +* by IO resource file, and need to skip the files +*/ +static void quirk_marvell_mask_bar(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < 5; i++) + if (dev->resource[i].start) + dev->resource[i].start = + dev->resource[i].end = 0; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9125, + quirk_marvell_mask_bar); + /* The Mellanox Tavor device gives false positive parity errors * Mark this device with a broken_parity_status, to allow * PCI scanning code to "skip" this now blacklisted device. --- linux-3.13.0.orig/drivers/pci/xen-pcifront.c +++ linux-3.13.0/drivers/pci/xen-pcifront.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #define INVALID_GRANT_REF (0) @@ -1138,6 +1139,9 @@ if (!xen_pv_domain() || xen_initial_domain()) return -ENODEV; + if (!xen_has_pv_devices()) + return -ENODEV; + pci_frontend_registrar(1 /* enable */); return xenbus_register_frontend(&xenpci_driver); --- linux-3.13.0.orig/drivers/pci/host/pci-xgene.c +++ linux-3.13.0/drivers/pci/host/pci-xgene.c @@ -0,0 +1,784 @@ +/** + * APM X-Gene PCIe Driver + * + * Copyright (c) 2013 Applied Micro Circuits Corporation. + * + * Author: Tanmay Inamdar . + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCIECORE_LTSSM 0x4c +#define PCIECORE_CTLANDSTATUS 0x50 +#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe) +#define INTXSTATUSMASK 0x6c +#define PIM1_1L 0x80 +#define IBAR2 0x98 +#define IR2MSK 0x9c +#define PIM2_1L 0xa0 +#define IBAR3L 0xb4 +#define IR3MSKL 0xbc +#define PIM3_1L 0xc4 +#define OMR1BARL 0x100 +#define OMR2BARL 0x118 +#define CFGBARL 0x154 +#define CFGBARH 0x158 +#define CFGCTL 0x15c +#define RTDID 0x160 +#define BRIDGE_CFG_0 0x2000 +#define BRIDGE_CFG_1 0x2004 +#define BRIDGE_CFG_4 0x2010 +#define BRIDGE_CFG_32 0x2030 +#define BRIDGE_CFG_14 0x2038 +#define BRIDGE_CTRL_1 0x2204 +#define BRIDGE_CTRL_2 0x2208 +#define BRIDGE_CTRL_5 0x2214 +#define BRIDGE_STATUS_0 0x2600 +#define MEM_RAM_SHUTDOWN 0xd070 +#define BLOCK_MEM_RDY 0xd074 + +#define DEVICE_PORT_TYPE_MASK 0x03c00000 +#define PM_FORCE_RP_MODE_MASK 0x00000400 +#define SWITCH_PORT_MODE_MASK 0x00000800 +#define CLASS_CODE_MASK 0xffffff00 +#define LINK_UP_MASK 0x00000100 +#define AER_OPTIONAL_ERROR_EN 0xffc00000 +#define XGENE_PCIE_DEV_CTRL 0x2f0f +#define AXI_EP_CFG_ACCESS 0x10000 +#define ENABLE_ASPM 0x08000000 +#define XGENE_PORT_TYPE_RC 0x05000000 +#define BLOCK_MEM_RDY_VAL 0xFFFFFFFF +#define EN_COHERENCY 0xF0000000 +#define EN_REG 0x00000001 +#define OB_LO_IO 0x00000002 +#define XGENE_PCIE_VENDORID 0xE008 +#define XGENE_PCIE_DEVICEID 0xE004 +#define XGENE_PCIE_TIMEOUT (500*1000) /* us */ +#define XGENE_LTSSM_DETECT_WAIT 20 +#define XGENE_LTSSM_L0_WAIT 4 +#define SZ_1T (SZ_1G*1024ULL) + +struct xgene_res_cfg { + struct resource res; + u64 pci_addr; +}; + +struct xgene_pcie_port { + struct device_node *node; + struct device *dev; + struct clk *clk; + struct xgene_res_cfg mem; + struct xgene_res_cfg io; + struct resource realio; + void __iomem *csr_base; + void __iomem *cfg_base; + u8 link_up; +}; + +static inline u32 pcie_bar_low_val(u32 addr, u32 flags) +{ + return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags; +} + +static inline struct xgene_pcie_port * +xgene_pcie_bus_to_port(struct pci_bus *bus) +{ + struct pci_sys_data *sys = bus->sysdata; + return sys->private_data; +} + +/* PCIE Configuration Out/In */ +static inline void xgene_pcie_cfg_out32(void __iomem *addr, u32 val) +{ + writel(val, addr); +} + +static inline void xgene_pcie_cfg_out16(void __iomem *addr, u16 val) +{ + u64 temp_addr = (u64)addr & ~0x3; + u32 val32 = readl((void __iomem *)temp_addr); + + switch ((u64) addr & 0x3) { + case 2: + val32 &= ~0xFFFF0000; + val32 |= (u32) val << 16; + break; + case 0: + default: + val32 &= ~0xFFFF; + val32 |= val; + break; + } + writel(val32, (void __iomem *)temp_addr); +} + +static inline void xgene_pcie_cfg_out8(void __iomem *addr, u8 val) +{ + phys_addr_t temp_addr = (u64) addr & ~0x3; + u32 val32 = readl((void __iomem *)temp_addr); + + switch ((u64) addr & 0x3) { + case 0: + val32 &= ~0xFF; + val32 |= val; + break; + case 1: + val32 &= ~0xFF00; + val32 |= (u32) val << 8; + break; + case 2: + val32 &= ~0xFF0000; + val32 |= (u32) val << 16; + break; + case 3: + default: + val32 &= ~0xFF000000; + val32 |= (u32) val << 24; + break; + } + writel(val32, (void __iomem *)temp_addr); +} + +static inline void xgene_pcie_cfg_in32(void __iomem *addr, u32 *val) +{ + *val = readl(addr); +} + +static inline void xgene_pcie_cfg_in16(void __iomem *addr, u16 *val) +{ + u64 temp_addr = (u64)addr & ~0x3; + u32 val32; + + val32 = readl((void __iomem *)temp_addr); + + switch ((u64)addr & 0x3) { + case 2: + *val = val32 >> 16; + break; + case 0: + default: + *val = val32; + break; + } +} + +static inline void xgene_pcie_cfg_in8(void __iomem *addr, u8 *val) +{ + u64 temp_addr = (u64)addr & ~0x3; + u32 val32; + + val32 = readl((void __iomem *)temp_addr); + + switch ((u64)addr & 0x3) { + case 3: + *val = val32 >> 24; + break; + case 2: + *val = val32 >> 16; + break; + case 1: + *val = val32 >> 8; + break; + case 0: + default: + *val = val32; + break; + } +} + +/* When the address bit [17:16] is 2'b01, the Configuration access will be + * treated as Type 1 and it will be forwarded to external PCIe device. + */ +static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) +{ + struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); + + if (bus->number >= (bus->primary + 1)) + return port->cfg_base + AXI_EP_CFG_ACCESS; + + return port->cfg_base; +} + +/* For Configuration request, RTDID register is used as Bus Number, + * Device Number and Function number of the header fields. + */ +static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn) +{ + struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); + unsigned int b, d, f; + u32 rtdid_val = 0; + + b = bus->number; + d = PCI_SLOT(devfn); + f = PCI_FUNC(devfn); + + if (!pci_is_root_bus(bus)) + rtdid_val = (b << 8) | (d << 3) | f; + + writel(rtdid_val, port->csr_base + RTDID); + /* read the register back to ensure flush */ + readl(port->csr_base + RTDID); +} + +static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); + void __iomem *addr; + u8 val8; + u16 val16; + + if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up) + return PCIBIOS_DEVICE_NOT_FOUND; + + xgene_pcie_set_rtdid_reg(bus, devfn); + addr = xgene_pcie_get_cfg_base(bus); + switch (len) { + case 1: + xgene_pcie_cfg_in8(addr + offset, &val8); + *val = val8; + break; + case 2: + xgene_pcie_cfg_in16(addr + offset, &val16); + *val = val16; + break; + default: + xgene_pcie_cfg_in32(addr + offset, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); + void __iomem *addr; + + if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up) + return PCIBIOS_DEVICE_NOT_FOUND; + + xgene_pcie_set_rtdid_reg(bus, devfn); + addr = xgene_pcie_get_cfg_base(bus); + switch (len) { + case 1: + xgene_pcie_cfg_out8(addr + offset, (u8) val); + break; + case 2: + xgene_pcie_cfg_out16(addr + offset, (u16) val); + break; + default: + xgene_pcie_cfg_out32(addr + offset, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops xgene_pcie_ops = { + .read = xgene_pcie_read_config, + .write = xgene_pcie_write_config +}; + +static void xgene_pcie_program_core(void __iomem *csr_base) +{ + u32 val; + + val = readl(csr_base + BRIDGE_CFG_0); + val |= AER_OPTIONAL_ERROR_EN; + writel(val, csr_base + BRIDGE_CFG_0); + writel(0x0, csr_base + INTXSTATUSMASK); + val = readl(csr_base + BRIDGE_CTRL_1); + val = (val & ~0xffff) | XGENE_PCIE_DEV_CTRL; + writel(val, csr_base + BRIDGE_CTRL_1); +} + +static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr, + u32 flags, u64 size) +{ + u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags; + u32 val32 = 0; + u32 val; + + val32 = readl(csr_base + addr); + val = (val32 & 0x0000ffff) | (lower_32_bits(mask) << 16); + writel(val, csr_base + addr); + + val32 = readl(csr_base + addr + 0x04); + val = (val32 & 0xffff0000) | (lower_32_bits(mask) >> 16); + writel(val, csr_base + addr + 0x04); + + val32 = readl(csr_base + addr + 0x04); + val = (val32 & 0x0000ffff) | (upper_32_bits(mask) << 16); + writel(val, csr_base + addr + 0x04); + + val32 = readl(csr_base + addr + 0x08); + val = (val32 & 0xffff0000) | (upper_32_bits(mask) >> 16); + writel(val, csr_base + addr + 0x08); + + return mask; +} + +static void xgene_pcie_poll_linkup(struct xgene_pcie_port *port, + u32 *lanes, u32 *speed) +{ + void __iomem *csr_base = port->csr_base; + u32 val32; + u64 start_time, time; + + /* + * A component enters the LTSSM Detect state within + * 20ms of the end of fundamental core reset. + */ + msleep(XGENE_LTSSM_DETECT_WAIT); + port->link_up = 0; + start_time = jiffies; + do { + val32 = readl(csr_base + PCIECORE_CTLANDSTATUS); + if (val32 & LINK_UP_MASK) { + port->link_up = 1; + *speed = PIPE_PHY_RATE_RD(val32); + val32 = readl(csr_base + BRIDGE_STATUS_0); + *lanes = val32 >> 26; + } + time = jiffies_to_msecs(jiffies - start_time); + } while ((!port->link_up) && (time <= XGENE_LTSSM_L0_WAIT)); +} + +static void xgene_pcie_setup_root_complex(struct xgene_pcie_port *port) +{ + void __iomem *csr_base = port->csr_base; + u32 val; + + val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID; + writel(val, csr_base + BRIDGE_CFG_0); + + val = readl(csr_base + BRIDGE_CFG_1); + val &= ~CLASS_CODE_MASK; + val |= PCI_CLASS_BRIDGE_PCI << 16; + writel(val, csr_base + BRIDGE_CFG_1); + + val = readl(csr_base + BRIDGE_CFG_14); + val |= SWITCH_PORT_MODE_MASK; + val &= ~PM_FORCE_RP_MODE_MASK; + writel(val, csr_base + BRIDGE_CFG_14); + + val = readl(csr_base + BRIDGE_CTRL_5); + val &= ~DEVICE_PORT_TYPE_MASK; + val |= XGENE_PORT_TYPE_RC; + writel(val, csr_base + BRIDGE_CTRL_5); + + val = readl(csr_base + BRIDGE_CTRL_2); + val |= ENABLE_ASPM; + writel(val, csr_base + BRIDGE_CTRL_2); + + val = readl(csr_base + BRIDGE_CFG_32); + writel(val | (1 << 19), csr_base + BRIDGE_CFG_32); +} + +/* Return 0 on success */ +static int xgene_pcie_init_ecc(struct xgene_pcie_port *port) +{ + void __iomem *csr_base = port->csr_base; + int timeout = XGENE_PCIE_TIMEOUT; + u32 val; + + val = readl(csr_base + MEM_RAM_SHUTDOWN); + if (val == 0) + return 0; + writel(0x0, csr_base + MEM_RAM_SHUTDOWN); + do { + val = readl(csr_base + BLOCK_MEM_RDY); + udelay(1); + } while ((val != BLOCK_MEM_RDY_VAL) && timeout--); + + return !(timeout > 0); +} + +static int xgene_pcie_init_port(struct xgene_pcie_port *port) +{ + int rc; + + port->clk = clk_get(port->dev, NULL); + if (IS_ERR_OR_NULL(port->clk)) { + dev_err(port->dev, "clock not available\n"); + return -ENODEV; + } + + rc = clk_prepare_enable(port->clk); + if (rc) { + dev_err(port->dev, "clock enable failed\n"); + return rc; + } + + rc = xgene_pcie_init_ecc(port); + if (rc) { + dev_err(port->dev, "memory init failed\n"); + return rc; + } + + return 0; +} + +struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) +{ + struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); + + return of_node_get(port->node); +} + +static void xgene_pcie_fixup_bridge(struct pci_dev *dev) +{ + int i; + + /* Hide the PCI host BARs from the kernel as their content doesn't + * fit well in the resource management + */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + dev_info(&dev->dev, "Hiding X-Gene pci host bridge resources %s\n", + pci_name(dev)); +} +DECLARE_PCI_FIXUP_HEADER(XGENE_PCIE_VENDORID, XGENE_PCIE_DEVICEID, + xgene_pcie_fixup_bridge); + +static int xgene_pcie_map_reg(struct xgene_pcie_port *port, + struct platform_device *pdev, u64 *cfg_addr) +{ + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr"); + port->csr_base = devm_ioremap_resource(port->dev, res); + if (IS_ERR(port->csr_base)) + return PTR_ERR(port->csr_base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); + port->cfg_base = devm_ioremap_resource(port->dev, res); + if (IS_ERR(port->cfg_base)) + return PTR_ERR(port->cfg_base); + *cfg_addr = res->start; + + return 0; +} + +static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port, + u32 addr, u32 restype) +{ + struct resource *res; + void __iomem *base = port->csr_base + addr; + resource_size_t size; + u64 cpu_addr, pci_addr; + u64 mask = 0; + u32 min_size; + u32 flag = EN_REG; + + if (restype == IORESOURCE_MEM) { + res = &port->mem.res; + pci_addr = port->mem.pci_addr; + min_size = SZ_128M; + } else { + res = &port->io.res; + pci_addr = port->io.pci_addr; + min_size = 128; + flag |= OB_LO_IO; + } + size = resource_size(res); + if (size >= min_size) + mask = ~(size - 1) | flag; + else + dev_warn(port->dev, "res size 0x%llx less than minimum 0x%x\n", + (u64)size, min_size); + cpu_addr = res->start; + writel(lower_32_bits(cpu_addr), base); + writel(upper_32_bits(cpu_addr), base + 0x04); + writel(lower_32_bits(mask), base + 0x08); + writel(upper_32_bits(mask), base + 0x0c); + writel(lower_32_bits(pci_addr), base + 0x10); + writel(upper_32_bits(pci_addr), base + 0x14); +} + +static void xgene_pcie_setup_cfg_reg(void __iomem *csr_base, u64 addr) +{ + writel(lower_32_bits(addr), csr_base + CFGBARL); + writel(upper_32_bits(addr), csr_base + CFGBARH); + writel(EN_REG, csr_base + CFGCTL); +} + +static int xgene_pcie_parse_map_ranges(struct xgene_pcie_port *port, + u64 cfg_addr) +{ + struct device_node *np = port->node; + struct of_pci_range range; + struct of_pci_range_parser parser; + struct device *dev = port->dev; + + if (of_pci_range_parser_init(&parser, np)) { + dev_err(dev, "missing ranges property\n"); + return -EINVAL; + } + + /* Get the I/O, memory ranges from DT */ + for_each_of_pci_range(&parser, &range) { + struct resource *res = NULL; + u64 restype = range.flags & IORESOURCE_TYPE_BITS; + u64 end = range.cpu_addr + range.size - 1; + dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", + range.flags, range.cpu_addr, end, range.pci_addr); + + switch (restype) { + case IORESOURCE_IO: + res = &port->io.res; + port->io.pci_addr = range.pci_addr; + of_pci_range_to_resource(&range, np, res); + xgene_pcie_setup_ob_reg(port, OMR1BARL, restype); + break; + case IORESOURCE_MEM: + res = &port->mem.res; + port->mem.pci_addr = range.pci_addr; + of_pci_range_to_resource(&range, np, res); + xgene_pcie_setup_ob_reg(port, OMR2BARL, restype); + break; + default: + dev_err(dev, "invalid io resource!"); + return -EINVAL; + } + } + xgene_pcie_setup_cfg_reg(port->csr_base, cfg_addr); + return 0; +} + +static void xgene_pcie_setup_pims(void *addr, u64 pim, u64 size) +{ + writel(lower_32_bits(pim), addr); + writel(upper_32_bits(pim) | EN_COHERENCY, addr + 0x04); + writel(lower_32_bits(size), addr + 0x10); + writel(upper_32_bits(size), addr + 0x14); +} + +/* + * X-Gene PCIe support maximum 3 inbound memory regions + * This function helps to select a region based on size of region + */ +static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) +{ + if ((size > 4) && (size < SZ_16M) && !(*ib_reg_mask & (1 << 1))) { + *ib_reg_mask |= (1 << 1); + return 1; + } + + if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) { + *ib_reg_mask |= (1 << 0); + return 0; + } + + if ((size > SZ_1M) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 2))) { + *ib_reg_mask |= (1 << 2); + return 2; + } + return -EINVAL; +} + +static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, + struct of_pci_range *range, u8 *ib_reg_mask) +{ + void __iomem *csr_base = port->csr_base; + void __iomem *cfg_base = port->cfg_base; + void *bar_addr; + void *pim_addr; + u64 restype = range->flags & IORESOURCE_TYPE_BITS; + u64 cpu_addr = range->cpu_addr; + u64 pci_addr = range->pci_addr; + u64 size = range->size; + u64 mask = ~(size - 1) | EN_REG; + u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64; + u32 bar_low; + int region; + + region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size); + if (region < 0) { + dev_warn(port->dev, "invalid pcie dma-range config\n"); + return; + } + + if (restype == PCI_BASE_ADDRESS_MEM_PREFETCH) + flags |= PCI_BASE_ADDRESS_MEM_PREFETCH; + + bar_low = pcie_bar_low_val((u32)cpu_addr, flags); + switch (region) { + case 0: + xgene_pcie_set_ib_mask(csr_base, BRIDGE_CFG_4, flags, size); + bar_addr = cfg_base + PCI_BASE_ADDRESS_0; + writel(bar_low, bar_addr); + writel(upper_32_bits(cpu_addr), bar_addr + 0x4); + pim_addr = csr_base + PIM1_1L; + break; + case 1: + bar_addr = csr_base + IBAR2; + writel(bar_low, bar_addr); + writel(lower_32_bits(mask), csr_base + IR2MSK); + pim_addr = csr_base + PIM2_1L; + break; + case 2: + bar_addr = csr_base + IBAR3L; + writel(bar_low, bar_addr); + writel(upper_32_bits(cpu_addr), bar_addr + 0x4); + writel(lower_32_bits(mask), csr_base + IR3MSKL); + writel(upper_32_bits(mask), csr_base + IR3MSKL + 0x4); + pim_addr = csr_base + PIM3_1L; + break; + } + + xgene_pcie_setup_pims(pim_addr, pci_addr, size); +} + +static int pci_dma_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node) +{ + const int na = 3, ns = 2; + int rlen; + + parser->node = node; + parser->pna = of_n_addr_cells(node); + parser->np = parser->pna + na + ns; + + parser->range = of_get_property(node, "dma-ranges", &rlen); + if (!parser->range) + return -ENOENT; + + parser->end = parser->range + rlen / sizeof(__be32); + return 0; +} + +static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port) +{ + struct device_node *np = port->node; + struct of_pci_range range; + struct of_pci_range_parser parser; + struct device *dev = port->dev; + u8 ib_reg_mask = 0; + + if (pci_dma_range_parser_init(&parser, np)) { + dev_err(dev, "missing dma-ranges property\n"); + return -EINVAL; + } + + /* Get the dma-ranges from DT */ + for_each_of_pci_range(&parser, &range) { + u64 end = range.cpu_addr + range.size - 1; + dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", + range.flags, range.cpu_addr, end, range.pci_addr); + xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask); + } + return 0; +} + +static int xgene_pcie_setup(int nr, struct pci_sys_data *sys) +{ + struct xgene_pcie_port *pp = sys->private_data; + struct resource *io = &pp->realio; + + io->start = sys->domain * SZ_64K; + io->end = io->start + SZ_64K; + io->flags = pp->io.res.flags; + io->name = "PCI IO"; + pci_ioremap_io(io->start, pp->io.res.start); + + pci_add_resource_offset(&sys->resources, io, sys->io_offset); + sys->mem_offset = pp->mem.res.start - pp->mem.pci_addr; + pci_add_resource_offset(&sys->resources, &pp->mem.res, + sys->mem_offset); + return 1; +} + +static int xgene_pcie_probe_bridge(struct platform_device *pdev) +{ + struct device_node *np = of_node_get(pdev->dev.of_node); + struct xgene_pcie_port *port; + struct hw_pci xgene_pcie_hw; + u32 lanes = 0, speed = 0; + u64 cfg_addr = 0; + static u32 domain; + int ret; + + port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + port->node = np; + port->dev = &pdev->dev; + + ret = xgene_pcie_map_reg(port, pdev, &cfg_addr); + if (ret) + return ret; + + ret = xgene_pcie_init_port(port); + if (ret) + goto skip; + xgene_pcie_program_core(port->csr_base); + xgene_pcie_setup_root_complex(port); + ret = xgene_pcie_parse_map_ranges(port, cfg_addr); + if (ret) + goto skip; + ret = xgene_pcie_parse_map_dma_ranges(port); + if (ret) + goto skip; + xgene_pcie_poll_linkup(port, &lanes, &speed); +skip: + if (!port->link_up) + dev_info(port->dev, "(rc) link down\n"); + else + dev_info(port->dev, "(rc) x%d gen-%d link up\n", + lanes, speed + 1); + platform_set_drvdata(pdev, port); + memset(&xgene_pcie_hw, 0, sizeof(xgene_pcie_hw)); + xgene_pcie_hw.domain = domain++; + xgene_pcie_hw.private_data = (void **)&port; + xgene_pcie_hw.nr_controllers = 1; + xgene_pcie_hw.setup = xgene_pcie_setup; + xgene_pcie_hw.map_irq = of_irq_parse_and_map_pci; + xgene_pcie_hw.ops = &xgene_pcie_ops; + pci_common_init(&xgene_pcie_hw); + return 0; +} + +static const struct of_device_id xgene_pcie_match_table[] = { + {.compatible = "apm,xgene-pcie",}, + {}, +}; + +static struct platform_driver xgene_pcie_driver = { + .driver = { + .name = "xgene-pcie", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(xgene_pcie_match_table), + }, + .probe = xgene_pcie_probe_bridge, +}; +module_platform_driver(xgene_pcie_driver); + +MODULE_AUTHOR("Tanmay Inamdar "); +MODULE_DESCRIPTION("APM X-Gene PCIe driver"); +MODULE_LICENSE("GPL v2"); --- linux-3.13.0.orig/drivers/pci/host/Makefile +++ linux-3.13.0/drivers/pci/host/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o +obj-$(CONFIG_PCI_XGENE) += pci-xgene.o --- linux-3.13.0.orig/drivers/pci/host/pci-mvebu.c +++ linux-3.13.0/drivers/pci/host/pci-mvebu.c @@ -60,14 +60,6 @@ #define PCIE_DEBUG_CTRL 0x1a60 #define PCIE_DEBUG_SOFT_RESET BIT(20) -/* - * This product ID is registered by Marvell, and used when the Marvell - * SoC is not the root complex, but an endpoint on the PCIe bus. It is - * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI - * bridge. - */ -#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846 - /* PCI configuration space of a PCI-to-PCI bridge */ struct mvebu_sw_pci_bridge { u16 vendor; @@ -377,7 +369,8 @@ bridge->class = PCI_CLASS_BRIDGE_PCI; bridge->vendor = PCI_VENDOR_ID_MARVELL; - bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID; + bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16; + bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff; bridge->header_type = PCI_HEADER_TYPE_BRIDGE; bridge->cache_line_size = 0x10; --- linux-3.13.0.orig/drivers/pci/host/Kconfig +++ linux-3.13.0/drivers/pci/host/Kconfig @@ -33,4 +33,14 @@ There are 3 internal PCI controllers available with a single built-in EHCI/OHCI host controller present on each one. +config PCI_XGENE + bool "X-Gene PCIe controller" + depends on ARCH_XGENE + depends on OF + select PCIEPORTBUS + help + Say Y here if you want internal PCI support on APM X-Gene SoC. + There are 5 internal PCIe ports available. Each port is GEN3 capable + and have varied lanes from x1 to x8. + endmenu --- linux-3.13.0.orig/drivers/pci/hotplug/acpiphp_glue.c +++ linux-3.13.0/drivers/pci/hotplug/acpiphp_glue.c @@ -706,6 +706,17 @@ return (unsigned int)sta; } +static inline bool device_status_valid(unsigned int sta) +{ + /* + * ACPI spec says that _STA may return bit 0 clear with bit 3 set + * if the device is valid but does not require a device driver to be + * loaded (Section 6.3.7 of ACPI 5.0A). + */ + unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING; + return (sta & mask) == mask; +} + /** * trim_stale_devices - remove PCI devices that are not responding. * @dev: PCI device to start walking the hierarchy from. @@ -721,7 +732,7 @@ unsigned long long sta; status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) + alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) || acpiphp_no_hotplug(handle); } if (!alive) { @@ -764,7 +775,7 @@ mutex_lock(&slot->crit_sect); if (slot_no_hotplug(slot)) { ; /* do nothing */ - } else if (get_slot_status(slot) == ACPI_STA_ALL) { + } else if (device_status_valid(get_slot_status(slot))) { /* remove stale devices if any */ list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) --- linux-3.13.0.orig/drivers/i2c/busses/i2c-cpm.c +++ linux-3.13.0/drivers/i2c/busses/i2c-cpm.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include --- linux-3.13.0.orig/drivers/i2c/busses/Kconfig +++ linux-3.13.0/drivers/i2c/busses/Kconfig @@ -152,6 +152,7 @@ ATI SB700/SP5100 ATI SB800 AMD Hudson-2 + AMD ML AMD CZ Serverworks OSB4 Serverworks CSB5 @@ -386,7 +387,7 @@ config I2C_CPM tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)" - depends on (CPM1 || CPM2) && OF_I2C + depends on CPM1 || CPM2 help This supports the use of the I2C interface on Freescale processors with CPM1 or CPM2. --- linux-3.13.0.orig/drivers/i2c/busses/i2c-piix4.c +++ linux-3.13.0/drivers/i2c/busses/i2c-piix4.c @@ -22,7 +22,7 @@ Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100 ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800 - AMD Hudson-2, CZ + AMD Hudson-2, ML, CZ SMSC Victory66 Note: we assume there can only be one device, with one or more @@ -235,7 +235,8 @@ { unsigned short piix4_smba; unsigned short smba_idx = 0xcd6; - u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en; + u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status; + u8 i2ccfg, i2ccfg_offset = 0x10; /* SB800 and later SMBus does not support forcing address */ if (force || force_addr) { @@ -245,7 +246,15 @@ } /* Determine the address of the SMBus areas */ - smb_en = (aux) ? 0x28 : 0x2c; + if ((PIIX4_dev->vendor == PCI_VENDOR_ID_AMD && + PIIX4_dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS && + PIIX4_dev->revision >= 0x41) || + (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD && + PIIX4_dev->device == 0x790b && + PIIX4_dev->revision >= 0x49)) + smb_en = 0x00; + else + smb_en = (aux) ? 0x28 : 0x2c; if (!request_region(smba_idx, 2, "smba_idx")) { dev_err(&PIIX4_dev->dev, "SMBus base address index region " @@ -258,13 +267,22 @@ smba_en_hi = inb_p(smba_idx + 1); release_region(smba_idx, 2); - if ((smba_en_lo & 1) == 0) { + if (!smb_en) { + smb_en_status = smba_en_lo & 0x10; + piix4_smba = smba_en_hi << 8; + if (aux) + piix4_smba |= 0x20; + } else { + smb_en_status = smba_en_lo & 0x01; + piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0; + } + + if (!smb_en_status) { dev_err(&PIIX4_dev->dev, "Host SMBus controller not enabled!\n"); return -ENODEV; } - piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0; if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) return -ENODEV; @@ -277,7 +295,8 @@ /* Aux SMBus does not support IRQ information */ if (aux) { dev_info(&PIIX4_dev->dev, - "SMBus Host Controller at 0x%x\n", piix4_smba); + "Auxiliary SMBus Host Controller at 0x%x\n", + piix4_smba); return piix4_smba; } --- linux-3.13.0.orig/drivers/i2c/busses/i2c-mv64xxx.c +++ linux-3.13.0/drivers/i2c/busses/i2c-mv64xxx.c @@ -97,7 +97,6 @@ enum { MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_CONTINUE, - MV64XXX_I2C_ACTION_OFFLOAD_SEND_START, MV64XXX_I2C_ACTION_SEND_START, MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_OFFLOAD_RESTART, @@ -204,6 +203,9 @@ unsigned long ctrl_reg; struct i2c_msg *msg = drv_data->msgs; + if (!drv_data->offload_enabled) + return -EOPNOTSUPP; + drv_data->msg = msg; drv_data->byte_posn = 0; drv_data->bytes_left = msg->len; @@ -433,8 +435,7 @@ drv_data->msgs++; drv_data->num_msgs--; - if (!(drv_data->offload_enabled && - mv64xxx_i2c_offload_msg(drv_data))) { + if (mv64xxx_i2c_offload_msg(drv_data) < 0) { drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; writel(drv_data->cntl_bits, drv_data->reg_base + drv_data->reg_offsets.control); @@ -458,15 +459,14 @@ drv_data->reg_base + drv_data->reg_offsets.control); break; - case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START: - if (!mv64xxx_i2c_offload_msg(drv_data)) - break; - else - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; - /* FALLTHRU */ case MV64XXX_I2C_ACTION_SEND_START: - writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, - drv_data->reg_base + drv_data->reg_offsets.control); + /* Can we offload this msg ? */ + if (mv64xxx_i2c_offload_msg(drv_data) < 0) { + /* No, switch to standard path */ + mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, + drv_data->reg_base + drv_data->reg_offsets.control); + } break; case MV64XXX_I2C_ACTION_SEND_ADDR_1: @@ -625,15 +625,10 @@ unsigned long flags; spin_lock_irqsave(&drv_data->lock, flags); - if (drv_data->offload_enabled) { - drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; - } else { - mv64xxx_i2c_prepare_for_io(drv_data, msg); - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; - } + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; + drv_data->send_stop = is_last; drv_data->block = 1; mv64xxx_i2c_do_action(drv_data); @@ -692,6 +687,7 @@ { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i}, { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, + { .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, {} }; MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); @@ -783,6 +779,10 @@ drv_data->errata_delay = true; } + if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) { + drv_data->offload_enabled = false; + drv_data->errata_delay = true; + } out: return rc; #endif --- linux-3.13.0.orig/drivers/parport/parport_pc.c +++ linux-3.13.0/drivers/parport/parport_pc.c @@ -2600,8 +2600,6 @@ syba_2p_epp, syba_1p_ecp, titan_010l, - titan_1284p1, - titan_1284p2, avlab_1p, avlab_2p, oxsemi_952, @@ -2660,8 +2658,6 @@ /* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } }, /* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } }, /* titan_010l */ { 1, { { 3, -1 }, } }, - /* titan_1284p1 */ { 1, { { 0, 1 }, } }, - /* titan_1284p2 */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* avlab_1p */ { 1, { { 0, 1}, } }, /* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} }, /* The Oxford Semi cards are unusual: 954 doesn't support ECP, @@ -2677,8 +2673,8 @@ /* netmos_9705 */ { 1, { { 0, -1 }, } }, /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, - /* netmos_9805 */ { 1, { { 0, -1 }, } }, - /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, + /* netmos_9805 */ { 1, { { 0, 1 }, } }, + /* netmos_9815 */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* netmos_9901 */ { 1, { { 0, -1 }, } }, /* netmos_9865 */ { 1, { { 0, -1 }, } }, /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, @@ -2722,8 +2718,6 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L, PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l }, - { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 }, - { 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 }, /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ /* AFAVLAB_TK9902 */ { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, --- linux-3.13.0.orig/drivers/platform/x86/intel_ips.c +++ linux-3.13.0/drivers/platform/x86/intel_ips.c @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include "intel_ips.h" @@ -250,6 +251,8 @@ static const int IPS_ADJUST_PERIOD = 5000; /* ms */ static bool late_i915_load = false; +int i915_bdw_enabled = 0; +EXPORT_SYMBOL(i915_bdw_enabled); /* For initial average collection */ static const int IPS_SAMPLE_PERIOD = 200; /* ms */ @@ -1421,8 +1424,43 @@ * enable graphics turbo, otherwise we must disable it to avoid exceeding * thermal and power limits in the MCP. */ +static bool ips_get_i915_bdw_syms(struct ips_driver *ips) +{ + ips->read_mch_val = symbol_get(i915_bdw_read_mch_val); + if (!ips->read_mch_val) + goto out_err; + ips->gpu_raise = symbol_get(i915_bdw_gpu_raise); + if (!ips->gpu_raise) + goto out_put_mch; + ips->gpu_lower = symbol_get(i915_bdw_gpu_lower); + if (!ips->gpu_lower) + goto out_put_raise; + ips->gpu_busy = symbol_get(i915_bdw_gpu_busy); + if (!ips->gpu_busy) + goto out_put_lower; + ips->gpu_turbo_disable = symbol_get(i915_bdw_gpu_turbo_disable); + if (!ips->gpu_turbo_disable) + goto out_put_busy; + + return true; + +out_put_busy: + symbol_put(i915_bdw_gpu_busy); +out_put_lower: + symbol_put(i915_bdw_gpu_lower); +out_put_raise: + symbol_put(i915_bdw_gpu_raise); +out_put_mch: + symbol_put(i915_bdw_read_mch_val); +out_err: + return false; +} + static bool ips_get_i915_syms(struct ips_driver *ips) { + if (ips_get_i915_bdw_syms(ips) != false) + return true; + ips->read_mch_val = symbol_get(i915_read_mch_val); if (!ips->read_mch_val) goto out_err; @@ -1501,6 +1539,14 @@ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook"), }, }, + { + .callback = ips_blacklist_callback, + .ident = "G60JX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "G60JX"), + }, + }, { } /* terminating entry */ }; --- linux-3.13.0.orig/drivers/platform/x86/dell-wmi.c +++ linux-3.13.0/drivers/platform/x86/dell-wmi.c @@ -166,7 +166,7 @@ u16 *buffer_entry = (u16 *)obj->buffer.pointer; if (dell_new_hk_type && (buffer_entry[1] != 0x10)) { - pr_info("Received unknown WMI event (0x%x)\n", + pr_debug("Received unknown WMI event (0x%x)\n", buffer_entry[1]); kfree(obj); return; --- linux-3.13.0.orig/drivers/platform/x86/hp_accel.c +++ linux-3.13.0/drivers/platform/x86/hp_accel.c @@ -77,6 +77,7 @@ static struct acpi_device_id lis3lv02d_device_ids[] = { {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ {"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */ + {"HPQ6007", 0}, /* HP Mobile Data Protection System PNP */ {"", 0}, }; MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); --- linux-3.13.0.orig/drivers/platform/x86/sony-laptop.c +++ linux-3.13.0/drivers/platform/x86/sony-laptop.c @@ -2917,6 +2917,10 @@ struct sonypi_event *events; }; +struct sony_pic_quirk_entry { + u8 set_wwan_power; +}; + struct sony_pic_dev { struct acpi_device *acpi_dev; struct sony_pic_irq *cur_irq; @@ -2927,6 +2931,7 @@ struct sonypi_eventtypes *event_types; int (*handle_irq)(const u8, const u8); int model; + struct sony_pic_quirk_entry *quirks; u16 evport_offset; u8 camera_power; u8 bluetooth_power; @@ -4362,6 +4367,12 @@ if (result) goto err_remove_pf; + if (spic_dev.quirks && spic_dev.quirks->set_wwan_power) { + /* + * Power isn't enabled by default. + */ + __sony_pic_set_wwanpower(1); + } return 0; err_remove_pf: @@ -4436,6 +4447,16 @@ .drv.pm = &sony_pic_pm, }; +static struct sony_pic_quirk_entry sony_pic_vaio_vgn = { + .set_wwan_power = 1, +}; + +static int dmi_matched(const struct dmi_system_id *dmi) +{ + spic_dev.quirks = dmi->driver_data; + return 0; +} + static struct dmi_system_id __initdata sonypi_dmi_table[] = { { .ident = "Sony Vaio", @@ -4450,6 +4471,8 @@ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), }, + .callback = dmi_matched, + .driver_data = &sony_pic_vaio_vgn, }, { } }; --- linux-3.13.0.orig/drivers/crypto/omap-aes.c +++ linux-3.13.0/drivers/crypto/omap-aes.c @@ -784,6 +784,7 @@ static int omap_aes_cra_init(struct crypto_tfm *tfm) { struct omap_aes_dev *dd = NULL; + int err; /* Find AES device, currently picks the first device */ spin_lock_bh(&list_lock); @@ -792,7 +793,13 @@ } spin_unlock_bh(&list_lock); - pm_runtime_get_sync(dd->dev); + err = pm_runtime_get_sync(dd->dev); + if (err < 0) { + dev_err(dd->dev, "%s: failed to get_sync(%d)\n", + __func__, err); + return err; + } + tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx); return 0; @@ -1182,7 +1189,12 @@ dd->phys_base = res.start; pm_runtime_enable(dev); - pm_runtime_get_sync(dev); + err = pm_runtime_get_sync(dev); + if (err < 0) { + dev_err(dev, "%s: failed to get_sync(%d)\n", + __func__, err); + goto err_res; + } omap_aes_dma_stop(dd); --- linux-3.13.0.orig/drivers/pnp/isapnp/core.c +++ linux-3.13.0/drivers/pnp/isapnp/core.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include "../base.h" @@ -990,7 +991,7 @@ .disable = isapnp_disable_resources, }; -static int __init isapnp_init(void) +static int __init real_isapnp_init(void) { int cards; struct pnp_card *card; @@ -1084,6 +1085,16 @@ return 0; } +static void __init async_isapnp_init(void *unused, async_cookie_t cookie) +{ + (void)real_isapnp_init(); +} + +static int __init isapnp_init(void) +{ + async_schedule(async_isapnp_init, NULL); + return 0; +} device_initcall(isapnp_init); /* format is: noisapnp */ --- linux-3.13.0.orig/drivers/pnp/pnpacpi/rsparser.c +++ linux-3.13.0/drivers/pnp/pnpacpi/rsparser.c @@ -183,9 +183,7 @@ struct resource r = {0}; int i, flags; - if (acpi_dev_resource_memory(res, &r) - || acpi_dev_resource_io(res, &r) - || acpi_dev_resource_address_space(res, &r) + if (acpi_dev_resource_address_space(res, &r) || acpi_dev_resource_ext_address_space(res, &r)) { pnp_add_resource(dev, &r); return AE_OK; @@ -217,6 +215,17 @@ } switch (res->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + if (acpi_dev_resource_memory(res, &r)) + pnp_add_resource(dev, &r); + break; + case ACPI_RESOURCE_TYPE_IO: + case ACPI_RESOURCE_TYPE_FIXED_IO: + if (acpi_dev_resource_io(res, &r)) + pnp_add_resource(dev, &r); + break; case ACPI_RESOURCE_TYPE_DMA: dma = &res->data.dma; if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) --- linux-3.13.0.orig/drivers/block/loop.c +++ linux-3.13.0/drivers/block/loop.c @@ -691,6 +691,24 @@ return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; } +/* + * for AUFS + * no get/put for file. + */ +struct file *loop_backing_file(struct super_block *sb) +{ + struct file *ret; + struct loop_device *l; + + ret = NULL; + if (MAJOR(sb->s_dev) == LOOP_MAJOR) { + l = sb->s_bdev->bd_disk->private_data; + ret = l->lo_backing_file; + } + return ret; +} +EXPORT_SYMBOL(loop_backing_file); + /* loop sysfs attributes */ static ssize_t loop_attr_show(struct device *dev, char *page, --- linux-3.13.0.orig/drivers/block/nvme-core.c +++ linux-3.13.0/drivers/block/nvme-core.c @@ -46,7 +46,6 @@ #define NVME_Q_DEPTH 1024 #define SQ_SIZE(depth) (depth * sizeof(struct nvme_command)) #define CQ_SIZE(depth) (depth * sizeof(struct nvme_completion)) -#define NVME_MINORS 64 #define ADMIN_TIMEOUT (60 * HZ) static int nvme_major; @@ -58,6 +57,17 @@ static DEFINE_SPINLOCK(dev_list_lock); static LIST_HEAD(dev_list); static struct task_struct *nvme_thread; +static struct workqueue_struct *nvme_workq; + +static void nvme_reset_failed_dev(struct work_struct *ws); + +struct async_cmd_info { + struct kthread_work work; + struct kthread_worker *worker; + u32 result; + int status; + void *ctx; +}; /* * An NVM Express queue. Each device has at least two (one for admin @@ -66,6 +76,7 @@ struct nvme_queue { struct device *q_dmadev; struct nvme_dev *dev; + char irqname[24]; /* nvme4294967295-65535\0 */ spinlock_t q_lock; struct nvme_command *sq_cmds; volatile struct nvme_completion *cqes; @@ -80,9 +91,11 @@ u16 sq_head; u16 sq_tail; u16 cq_head; + u16 qid; u8 cq_phase; u8 cqe_seen; u8 q_suspended; + struct async_cmd_info cmdinfo; unsigned long cmdid_data[]; }; @@ -97,6 +110,7 @@ BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64); BUILD_BUG_ON(sizeof(struct nvme_features) != 64); BUILD_BUG_ON(sizeof(struct nvme_format_cmd) != 64); + BUILD_BUG_ON(sizeof(struct nvme_abort_cmd) != 64); BUILD_BUG_ON(sizeof(struct nvme_command) != 64); BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != 4096); BUILD_BUG_ON(sizeof(struct nvme_id_ns) != 4096); @@ -111,6 +125,7 @@ nvme_completion_fn fn; void *ctx; unsigned long timeout; + int aborted; }; static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq) @@ -154,6 +169,7 @@ info[cmdid].fn = handler; info[cmdid].ctx = ctx; info[cmdid].timeout = jiffies + timeout; + info[cmdid].aborted = 0; return cmdid; } @@ -172,6 +188,7 @@ #define CMD_CTX_COMPLETED (0x310 + CMD_CTX_BASE) #define CMD_CTX_INVALID (0x314 + CMD_CTX_BASE) #define CMD_CTX_FLUSH (0x318 + CMD_CTX_BASE) +#define CMD_CTX_ABORT (0x31C + CMD_CTX_BASE) static void special_completion(struct nvme_dev *dev, void *ctx, struct nvme_completion *cqe) @@ -180,6 +197,10 @@ return; if (ctx == CMD_CTX_FLUSH) return; + if (ctx == CMD_CTX_ABORT) { + ++dev->abort_limit; + return; + } if (ctx == CMD_CTX_COMPLETED) { dev_warn(&dev->pci_dev->dev, "completed id %d twice on queue %d\n", @@ -196,6 +217,15 @@ dev_warn(&dev->pci_dev->dev, "Unknown special completion %p\n", ctx); } +static void async_completion(struct nvme_dev *dev, void *ctx, + struct nvme_completion *cqe) +{ + struct async_cmd_info *cmdinfo = ctx; + cmdinfo->result = le32_to_cpup(&cqe->result); + cmdinfo->status = le16_to_cpup(&cqe->status) >> 1; + queue_kthread_work(cmdinfo->worker, &cmdinfo->work); +} + /* * Called with local interrupts disabled and the q_lock held. May not sleep. */ @@ -775,7 +805,7 @@ if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) return 0; - writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride)); + writel(head, nvmeq->q_db + nvmeq->dev->db_stride); nvmeq->cq_head = head; nvmeq->cq_phase = phase; @@ -886,12 +916,34 @@ return cmdinfo.status; } +static int nvme_submit_async_cmd(struct nvme_queue *nvmeq, + struct nvme_command *cmd, + struct async_cmd_info *cmdinfo, unsigned timeout) +{ + int cmdid; + + cmdid = alloc_cmdid_killable(nvmeq, cmdinfo, async_completion, timeout); + if (cmdid < 0) + return cmdid; + cmdinfo->status = -EINTR; + cmd->common.command_id = cmdid; + nvme_submit_cmd(nvmeq, cmd); + return 0; +} + int nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd, u32 *result) { return nvme_submit_sync_cmd(dev->queues[0], cmd, result, ADMIN_TIMEOUT); } +static int nvme_submit_admin_cmd_async(struct nvme_dev *dev, + struct nvme_command *cmd, struct async_cmd_info *cmdinfo) +{ + return nvme_submit_async_cmd(dev->queues[0], cmd, cmdinfo, + ADMIN_TIMEOUT); +} + static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) { int status; @@ -1002,6 +1054,56 @@ } /** + * nvme_abort_cmd - Attempt aborting a command + * @cmdid: Command id of a timed out IO + * @queue: The queue with timed out IO + * + * Schedule controller reset if the command was already aborted once before and + * still hasn't been returned to the driver, or if this is the admin queue. + */ +static void nvme_abort_cmd(int cmdid, struct nvme_queue *nvmeq) +{ + int a_cmdid; + struct nvme_command cmd; + struct nvme_dev *dev = nvmeq->dev; + struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); + + if (!nvmeq->qid || info[cmdid].aborted) { + if (work_busy(&dev->reset_work)) + return; + list_del_init(&dev->node); + dev_warn(&dev->pci_dev->dev, + "I/O %d QID %d timeout, reset controller\n", cmdid, + nvmeq->qid); + PREPARE_WORK(&dev->reset_work, nvme_reset_failed_dev); + queue_work(nvme_workq, &dev->reset_work); + return; + } + + if (!dev->abort_limit) + return; + + a_cmdid = alloc_cmdid(dev->queues[0], CMD_CTX_ABORT, special_completion, + ADMIN_TIMEOUT); + if (a_cmdid < 0) + return; + + memset(&cmd, 0, sizeof(cmd)); + cmd.abort.opcode = nvme_admin_abort_cmd; + cmd.abort.cid = cmdid; + cmd.abort.sqid = cpu_to_le16(nvmeq->qid); + cmd.abort.command_id = a_cmdid; + + --dev->abort_limit; + info[cmdid].aborted = 1; + info[cmdid].timeout = jiffies + ADMIN_TIMEOUT; + + dev_warn(nvmeq->q_dmadev, "Aborting I/O %d QID %d\n", cmdid, + nvmeq->qid); + nvme_submit_cmd(dev->queues[0], &cmd); +} + +/** * nvme_cancel_ios - Cancel outstanding I/Os * @queue: The queue to cancel I/Os on * @timeout: True to only cancel I/Os which have timed out @@ -1024,7 +1126,12 @@ continue; if (info[cmdid].ctx == CMD_CTX_CANCELLED) continue; - dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid); + if (timeout && nvmeq->dev->initialized) { + nvme_abort_cmd(cmdid, nvmeq); + continue; + } + dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d QID %d\n", cmdid, + nvmeq->qid); ctx = cancel_cmdid(nvmeq, cmdid, &fn); fn(nvmeq->dev, ctx, &cqe); } @@ -1046,26 +1153,31 @@ kfree(nvmeq); } -static void nvme_free_queues(struct nvme_dev *dev) +static void nvme_free_queues(struct nvme_dev *dev, int lowest) { int i; - for (i = dev->queue_count - 1; i >= 0; i--) { + for (i = dev->queue_count - 1; i >= lowest; i--) { nvme_free_queue(dev->queues[i]); dev->queue_count--; dev->queues[i] = NULL; } } -static void nvme_disable_queue(struct nvme_dev *dev, int qid) +/** + * nvme_suspend_queue - put queue into suspended state + * @nvmeq - queue to suspend + * + * Returns 1 if already suspended, 0 otherwise. + */ +static int nvme_suspend_queue(struct nvme_queue *nvmeq) { - struct nvme_queue *nvmeq = dev->queues[qid]; - int vector = dev->entry[nvmeq->cq_vector].vector; + int vector = nvmeq->dev->entry[nvmeq->cq_vector].vector; spin_lock_irq(&nvmeq->q_lock); if (nvmeq->q_suspended) { spin_unlock_irq(&nvmeq->q_lock); - return; + return 1; } nvmeq->q_suspended = 1; spin_unlock_irq(&nvmeq->q_lock); @@ -1073,18 +1185,35 @@ irq_set_affinity_hint(vector, NULL); free_irq(vector, nvmeq); - /* Don't tell the adapter to delete the admin queue */ - if (qid) { - adapter_delete_sq(dev, qid); - adapter_delete_cq(dev, qid); - } + return 0; +} +static void nvme_clear_queue(struct nvme_queue *nvmeq) +{ spin_lock_irq(&nvmeq->q_lock); nvme_process_cq(nvmeq); nvme_cancel_ios(nvmeq, false); spin_unlock_irq(&nvmeq->q_lock); } +static void nvme_disable_queue(struct nvme_dev *dev, int qid) +{ + struct nvme_queue *nvmeq = dev->queues[qid]; + + if (!nvmeq) + return; + if (nvme_suspend_queue(nvmeq)) + return; + + /* Don't tell the adapter to delete the admin queue. + * Don't tell a removed adapter to delete IO queues. */ + if (qid && readl(&dev->bar->csts) != -1) { + adapter_delete_sq(dev, qid); + adapter_delete_cq(dev, qid); + } + nvme_clear_queue(nvmeq); +} + static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth, int vector) { @@ -1107,15 +1236,18 @@ nvmeq->q_dmadev = dmadev; nvmeq->dev = dev; + snprintf(nvmeq->irqname, sizeof(nvmeq->irqname), "nvme%dq%d", + dev->instance, qid); spin_lock_init(&nvmeq->q_lock); nvmeq->cq_head = 0; nvmeq->cq_phase = 1; init_waitqueue_head(&nvmeq->sq_full); init_waitqueue_entry(&nvmeq->sq_cong_wait, nvme_thread); bio_list_init(&nvmeq->sq_cong); - nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; nvmeq->q_depth = depth; nvmeq->cq_vector = vector; + nvmeq->qid = qid; nvmeq->q_suspended = 1; dev->queue_count++; @@ -1134,11 +1266,10 @@ { if (use_threaded_interrupts) return request_threaded_irq(dev->entry[nvmeq->cq_vector].vector, - nvme_irq_check, nvme_irq, - IRQF_DISABLED | IRQF_SHARED, + nvme_irq_check, nvme_irq, IRQF_SHARED, name, nvmeq); return request_irq(dev->entry[nvmeq->cq_vector].vector, nvme_irq, - IRQF_DISABLED | IRQF_SHARED, name, nvmeq); + IRQF_SHARED, name, nvmeq); } static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) @@ -1149,7 +1280,7 @@ nvmeq->sq_tail = 0; nvmeq->cq_head = 0; nvmeq->cq_phase = 1; - nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; memset(nvmeq->cmdid_data, 0, extra); memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth)); nvme_cancel_ios(nvmeq, false); @@ -1169,13 +1300,13 @@ if (result < 0) goto release_cq; - result = queue_request_irq(dev, nvmeq, "nvme"); + result = queue_request_irq(dev, nvmeq, nvmeq->irqname); if (result < 0) goto release_sq; - spin_lock(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->q_lock); nvme_init_queue(nvmeq, qid); - spin_unlock(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->q_lock); return result; @@ -1287,13 +1418,13 @@ if (result) return result; - result = queue_request_irq(dev, nvmeq, "nvme admin"); + result = queue_request_irq(dev, nvmeq, nvmeq->irqname); if (result) return result; - spin_lock(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->q_lock); nvme_init_queue(nvmeq, 0); - spin_unlock(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->q_lock); return result; } @@ -1569,10 +1700,47 @@ } } +#ifdef CONFIG_COMPAT +static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct nvme_ns *ns = bdev->bd_disk->private_data; + + switch (cmd) { + case SG_IO: + return nvme_sg_io32(ns, arg); + } + return nvme_ioctl(bdev, mode, cmd, arg); +} +#else +#define nvme_compat_ioctl NULL +#endif + +static int nvme_open(struct block_device *bdev, fmode_t mode) +{ + struct nvme_ns *ns = bdev->bd_disk->private_data; + struct nvme_dev *dev = ns->dev; + + kref_get(&dev->kref); + return 0; +} + +static void nvme_free_dev(struct kref *kref); + +static void nvme_release(struct gendisk *disk, fmode_t mode) +{ + struct nvme_ns *ns = disk->private_data; + struct nvme_dev *dev = ns->dev; + + kref_put(&dev->kref, nvme_free_dev); +} + static const struct block_device_operations nvme_fops = { .owner = THIS_MODULE, .ioctl = nvme_ioctl, - .compat_ioctl = nvme_ioctl, + .compat_ioctl = nvme_compat_ioctl, + .open = nvme_open, + .release = nvme_release, }; static void nvme_resubmit_bios(struct nvme_queue *nvmeq) @@ -1596,13 +1764,25 @@ static int nvme_kthread(void *data) { - struct nvme_dev *dev; + struct nvme_dev *dev, *next; while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); spin_lock(&dev_list_lock); - list_for_each_entry(dev, &dev_list, node) { + list_for_each_entry_safe(dev, next, &dev_list, node) { int i; + if (readl(&dev->bar->csts) & NVME_CSTS_CFS && + dev->initialized) { + if (work_busy(&dev->reset_work)) + continue; + list_del_init(&dev->node); + dev_warn(&dev->pci_dev->dev, + "Failed status, reset controller\n"); + PREPARE_WORK(&dev->reset_work, + nvme_reset_failed_dev); + queue_work(nvme_workq, &dev->reset_work); + continue; + } for (i = 0; i < dev->queue_count; i++) { struct nvme_queue *nvmeq = dev->queues[i]; if (!nvmeq) @@ -1623,33 +1803,6 @@ return 0; } -static DEFINE_IDA(nvme_index_ida); - -static int nvme_get_ns_idx(void) -{ - int index, error; - - do { - if (!ida_pre_get(&nvme_index_ida, GFP_KERNEL)) - return -1; - - spin_lock(&dev_list_lock); - error = ida_get_new(&nvme_index_ida, &index); - spin_unlock(&dev_list_lock); - } while (error == -EAGAIN); - - if (error) - index = -1; - return index; -} - -static void nvme_put_ns_idx(int index) -{ - spin_lock(&dev_list_lock); - ida_remove(&nvme_index_ida, index); - spin_unlock(&dev_list_lock); -} - static void nvme_config_discard(struct nvme_ns *ns) { u32 logical_block_size = queue_logical_block_size(ns->queue); @@ -1683,7 +1836,7 @@ ns->dev = dev; ns->queue->queuedata = ns; - disk = alloc_disk(NVME_MINORS); + disk = alloc_disk(0); if (!disk) goto out_free_queue; ns->ns_id = nsid; @@ -1696,12 +1849,12 @@ blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors); disk->major = nvme_major; - disk->minors = NVME_MINORS; - disk->first_minor = NVME_MINORS * nvme_get_ns_idx(); + disk->first_minor = 0; disk->fops = &nvme_fops; disk->private_data = ns; disk->queue = ns->queue; disk->driverfs_dev = &dev->pci_dev->dev; + disk->flags = GENHD_FL_EXT_DEVT; sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid); set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9)); @@ -1717,15 +1870,6 @@ return NULL; } -static void nvme_ns_free(struct nvme_ns *ns) -{ - int index = ns->disk->first_minor / NVME_MINORS; - put_disk(ns->disk); - nvme_put_ns_idx(index); - blk_cleanup_queue(ns->queue); - kfree(ns); -} - static int set_queue_count(struct nvme_dev *dev, int count) { int status; @@ -1741,11 +1885,12 @@ static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) { - return 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); + return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride); } static int nvme_setup_io_queues(struct nvme_dev *dev) { + struct nvme_queue *adminq = dev->queues[0]; struct pci_dev *pdev = dev->pci_dev; int result, cpu, i, vecs, nr_io_queues, size, q_depth; @@ -1772,7 +1917,7 @@ } /* Deregister the admin queue's interrupt */ - free_irq(dev->entry[0].vector, dev->queues[0]); + free_irq(dev->entry[0].vector, adminq); vecs = nr_io_queues; for (i = 0; i < vecs; i++) @@ -1810,9 +1955,9 @@ */ nr_io_queues = vecs; - result = queue_request_irq(dev, dev->queues[0], "nvme admin"); + result = queue_request_irq(dev, adminq, adminq->irqname); if (result) { - dev->queues[0]->q_suspended = 1; + adminq->q_suspended = 1; goto free_queues; } @@ -1821,9 +1966,9 @@ for (i = dev->queue_count - 1; i > nr_io_queues; i--) { struct nvme_queue *nvmeq = dev->queues[i]; - spin_lock(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->q_lock); nvme_cancel_ios(nvmeq, false); - spin_unlock(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->q_lock); nvme_free_queue(nvmeq); dev->queue_count--; @@ -1864,7 +2009,7 @@ return 0; free_queues: - nvme_free_queues(dev); + nvme_free_queues(dev, 1); return result; } @@ -1876,6 +2021,7 @@ */ static int nvme_dev_add(struct nvme_dev *dev) { + struct pci_dev *pdev = dev->pci_dev; int res; unsigned nn, i; struct nvme_ns *ns; @@ -1885,8 +2031,7 @@ dma_addr_t dma_addr; int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12; - mem = dma_alloc_coherent(&dev->pci_dev->dev, 8192, &dma_addr, - GFP_KERNEL); + mem = dma_alloc_coherent(&pdev->dev, 8192, &dma_addr, GFP_KERNEL); if (!mem) return -ENOMEM; @@ -1899,13 +2044,14 @@ ctrl = mem; nn = le32_to_cpup(&ctrl->nn); dev->oncs = le16_to_cpup(&ctrl->oncs); + dev->abort_limit = ctrl->acl + 1; memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn)); memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn)); memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); if (ctrl->mdts) dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9); - if ((dev->pci_dev->vendor == PCI_VENDOR_ID_INTEL) && - (dev->pci_dev->device == 0x0953) && ctrl->vs[3]) + if ((pdev->vendor == PCI_VENDOR_ID_INTEL) && + (pdev->device == 0x0953) && ctrl->vs[3]) dev->stripe_size = 1 << (ctrl->vs[3] + shift); id_ns = mem; @@ -1953,16 +2099,21 @@ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) goto disable; - pci_set_drvdata(pdev, dev); dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); if (!dev->bar) goto disable; - - dev->db_stride = NVME_CAP_STRIDE(readq(&dev->bar->cap)); + if (readl(&dev->bar->csts) == -1) { + result = -ENODEV; + goto unmap; + } + dev->db_stride = 1 << NVME_CAP_STRIDE(readq(&dev->bar->cap)); dev->dbs = ((void __iomem *)dev->bar) + 4096; return 0; + unmap: + iounmap(dev->bar); + dev->bar = NULL; disable: pci_release_regions(pdev); disable_pci: @@ -1980,37 +2131,183 @@ if (dev->bar) { iounmap(dev->bar); dev->bar = NULL; + pci_release_regions(dev->pci_dev); } - pci_release_regions(dev->pci_dev); if (pci_is_enabled(dev->pci_dev)) pci_disable_device(dev->pci_dev); } +struct nvme_delq_ctx { + struct task_struct *waiter; + struct kthread_worker *worker; + atomic_t refcount; +}; + +static void nvme_wait_dq(struct nvme_delq_ctx *dq, struct nvme_dev *dev) +{ + dq->waiter = current; + mb(); + + for (;;) { + set_current_state(TASK_KILLABLE); + if (!atomic_read(&dq->refcount)) + break; + if (!schedule_timeout(ADMIN_TIMEOUT) || + fatal_signal_pending(current)) { + set_current_state(TASK_RUNNING); + + nvme_disable_ctrl(dev, readq(&dev->bar->cap)); + nvme_disable_queue(dev, 0); + + send_sig(SIGKILL, dq->worker->task, 1); + flush_kthread_worker(dq->worker); + return; + } + } + set_current_state(TASK_RUNNING); +} + +static void nvme_put_dq(struct nvme_delq_ctx *dq) +{ + atomic_dec(&dq->refcount); + if (dq->waiter) + wake_up_process(dq->waiter); +} + +static struct nvme_delq_ctx *nvme_get_dq(struct nvme_delq_ctx *dq) +{ + atomic_inc(&dq->refcount); + return dq; +} + +static void nvme_del_queue_end(struct nvme_queue *nvmeq) +{ + struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx; + + nvme_clear_queue(nvmeq); + nvme_put_dq(dq); +} + +static int adapter_async_del_queue(struct nvme_queue *nvmeq, u8 opcode, + kthread_work_func_t fn) +{ + struct nvme_command c; + + memset(&c, 0, sizeof(c)); + c.delete_queue.opcode = opcode; + c.delete_queue.qid = cpu_to_le16(nvmeq->qid); + + init_kthread_work(&nvmeq->cmdinfo.work, fn); + return nvme_submit_admin_cmd_async(nvmeq->dev, &c, &nvmeq->cmdinfo); +} + +static void nvme_del_cq_work_handler(struct kthread_work *work) +{ + struct nvme_queue *nvmeq = container_of(work, struct nvme_queue, + cmdinfo.work); + nvme_del_queue_end(nvmeq); +} + +static int nvme_delete_cq(struct nvme_queue *nvmeq) +{ + return adapter_async_del_queue(nvmeq, nvme_admin_delete_cq, + nvme_del_cq_work_handler); +} + +static void nvme_del_sq_work_handler(struct kthread_work *work) +{ + struct nvme_queue *nvmeq = container_of(work, struct nvme_queue, + cmdinfo.work); + int status = nvmeq->cmdinfo.status; + + if (!status) + status = nvme_delete_cq(nvmeq); + if (status) + nvme_del_queue_end(nvmeq); +} + +static int nvme_delete_sq(struct nvme_queue *nvmeq) +{ + return adapter_async_del_queue(nvmeq, nvme_admin_delete_sq, + nvme_del_sq_work_handler); +} + +static void nvme_del_queue_start(struct kthread_work *work) +{ + struct nvme_queue *nvmeq = container_of(work, struct nvme_queue, + cmdinfo.work); + allow_signal(SIGKILL); + if (nvme_delete_sq(nvmeq)) + nvme_del_queue_end(nvmeq); +} + +static void nvme_disable_io_queues(struct nvme_dev *dev) +{ + int i; + DEFINE_KTHREAD_WORKER_ONSTACK(worker); + struct nvme_delq_ctx dq; + struct task_struct *kworker_task = kthread_run(kthread_worker_fn, + &worker, "nvme%d", dev->instance); + + if (IS_ERR(kworker_task)) { + dev_err(&dev->pci_dev->dev, + "Failed to create queue del task\n"); + for (i = dev->queue_count - 1; i > 0; i--) + nvme_disable_queue(dev, i); + return; + } + + dq.waiter = NULL; + atomic_set(&dq.refcount, 0); + dq.worker = &worker; + for (i = dev->queue_count - 1; i > 0; i--) { + struct nvme_queue *nvmeq = dev->queues[i]; + + if (nvme_suspend_queue(nvmeq)) + continue; + nvmeq->cmdinfo.ctx = nvme_get_dq(&dq); + nvmeq->cmdinfo.worker = dq.worker; + init_kthread_work(&nvmeq->cmdinfo.work, nvme_del_queue_start); + queue_kthread_work(dq.worker, &nvmeq->cmdinfo.work); + } + nvme_wait_dq(&dq, dev); + kthread_stop(kworker_task); +} + static void nvme_dev_shutdown(struct nvme_dev *dev) { int i; - for (i = dev->queue_count - 1; i >= 0; i--) - nvme_disable_queue(dev, i); + dev->initialized = 0; spin_lock(&dev_list_lock); list_del_init(&dev->node); spin_unlock(&dev_list_lock); - if (dev->bar) + if (!dev->bar || (dev->bar && readl(&dev->bar->csts) == -1)) { + for (i = dev->queue_count - 1; i >= 0; i--) { + struct nvme_queue *nvmeq = dev->queues[i]; + nvme_suspend_queue(nvmeq); + nvme_clear_queue(nvmeq); + } + } else { + nvme_disable_io_queues(dev); nvme_shutdown_ctrl(dev); + nvme_disable_queue(dev, 0); + } nvme_dev_unmap(dev); } static void nvme_dev_remove(struct nvme_dev *dev) { - struct nvme_ns *ns, *next; + struct nvme_ns *ns; - list_for_each_entry_safe(ns, next, &dev->namespaces, list) { - list_del(&ns->list); - del_gendisk(ns->disk); - nvme_ns_free(ns); + list_for_each_entry(ns, &dev->namespaces, list) { + if (ns->disk->flags & GENHD_FL_UP) + del_gendisk(ns->disk); + if (!blk_queue_dying(ns->queue)) + blk_cleanup_queue(ns->queue); } } @@ -2067,14 +2364,22 @@ spin_unlock(&dev_list_lock); } +static void nvme_free_namespaces(struct nvme_dev *dev) +{ + struct nvme_ns *ns, *next; + + list_for_each_entry_safe(ns, next, &dev->namespaces, list) { + list_del(&ns->list); + put_disk(ns->disk); + kfree(ns); + } +} + static void nvme_free_dev(struct kref *kref) { struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref); - nvme_dev_remove(dev); - nvme_dev_shutdown(dev); - nvme_free_queues(dev); - nvme_release_instance(dev); - nvme_release_prp_pools(dev); + + nvme_free_namespaces(dev); kfree(dev->queues); kfree(dev->entry); kfree(dev); @@ -2138,6 +2443,7 @@ return result; disable: + nvme_disable_queue(dev, 0); spin_lock(&dev_list_lock); list_del_init(&dev->node); spin_unlock(&dev_list_lock); @@ -2146,6 +2452,71 @@ return result; } +static int nvme_remove_dead_ctrl(void *arg) +{ + struct nvme_dev *dev = (struct nvme_dev *)arg; + struct pci_dev *pdev = dev->pci_dev; + + if (pci_get_drvdata(pdev)) + pci_stop_and_remove_bus_device(pdev); + kref_put(&dev->kref, nvme_free_dev); + return 0; +} + +static void nvme_remove_disks(struct work_struct *ws) +{ + int i; + struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work); + + nvme_dev_remove(dev); + spin_lock(&dev_list_lock); + for (i = dev->queue_count - 1; i > 0; i--) { + BUG_ON(!dev->queues[i] || !dev->queues[i]->q_suspended); + nvme_free_queue(dev->queues[i]); + dev->queue_count--; + dev->queues[i] = NULL; + } + spin_unlock(&dev_list_lock); +} + +static int nvme_dev_resume(struct nvme_dev *dev) +{ + int ret; + + ret = nvme_dev_start(dev); + if (ret && ret != -EBUSY) + return ret; + if (ret == -EBUSY) { + spin_lock(&dev_list_lock); + PREPARE_WORK(&dev->reset_work, nvme_remove_disks); + queue_work(nvme_workq, &dev->reset_work); + spin_unlock(&dev_list_lock); + } + dev->initialized = 1; + return 0; +} + +static void nvme_dev_reset(struct nvme_dev *dev) +{ + nvme_dev_shutdown(dev); + if (nvme_dev_resume(dev)) { + dev_err(&dev->pci_dev->dev, "Device failed to resume\n"); + kref_get(&dev->kref); + if (IS_ERR(kthread_run(nvme_remove_dead_ctrl, dev, "nvme%d", + dev->instance))) { + dev_err(&dev->pci_dev->dev, + "Failed to start controller remove task\n"); + kref_put(&dev->kref, nvme_free_dev); + } + } +} + +static void nvme_reset_failed_dev(struct work_struct *ws) +{ + struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work); + nvme_dev_reset(dev); +} + static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int result = -ENOMEM; @@ -2164,8 +2535,9 @@ goto free; INIT_LIST_HEAD(&dev->namespaces); + INIT_WORK(&dev->reset_work, nvme_reset_failed_dev); dev->pci_dev = pdev; - + pci_set_drvdata(pdev, dev); result = nvme_set_instance(dev); if (result) goto free; @@ -2181,6 +2553,7 @@ goto release_pools; } + kref_init(&dev->kref); result = nvme_dev_add(dev); if (result) goto shutdown; @@ -2195,15 +2568,16 @@ if (result) goto remove; - kref_init(&dev->kref); + dev->initialized = 1; return 0; remove: nvme_dev_remove(dev); + nvme_free_namespaces(dev); shutdown: nvme_dev_shutdown(dev); release_pools: - nvme_free_queues(dev); + nvme_free_queues(dev, 0); nvme_release_prp_pools(dev); release: nvme_release_instance(dev); @@ -2214,10 +2588,28 @@ return result; } +static void nvme_shutdown(struct pci_dev *pdev) +{ + struct nvme_dev *dev = pci_get_drvdata(pdev); + nvme_dev_shutdown(dev); +} + static void nvme_remove(struct pci_dev *pdev) { struct nvme_dev *dev = pci_get_drvdata(pdev); + + spin_lock(&dev_list_lock); + list_del_init(&dev->node); + spin_unlock(&dev_list_lock); + + pci_set_drvdata(pdev, NULL); + flush_work(&dev->reset_work); misc_deregister(&dev->miscdev); + nvme_dev_remove(dev); + nvme_dev_shutdown(dev); + nvme_free_queues(dev, 0); + nvme_release_instance(dev); + nvme_release_prp_pools(dev); kref_put(&dev->kref, nvme_free_dev); } @@ -2241,13 +2633,12 @@ { struct pci_dev *pdev = to_pci_dev(dev); struct nvme_dev *ndev = pci_get_drvdata(pdev); - int ret; - ret = nvme_dev_start(ndev); - /* XXX: should remove gendisks if resume fails */ - if (ret) - nvme_free_queues(ndev); - return ret; + if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) { + PREPARE_WORK(&ndev->reset_work, nvme_reset_failed_dev); + queue_work(nvme_workq, &ndev->reset_work); + } + return 0; } static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume); @@ -2274,6 +2665,7 @@ .id_table = nvme_id_table, .probe = nvme_probe, .remove = nvme_remove, + .shutdown = nvme_shutdown, .driver = { .pm = &nvme_dev_pm_ops, }, @@ -2288,9 +2680,14 @@ if (IS_ERR(nvme_thread)) return PTR_ERR(nvme_thread); + result = -ENOMEM; + nvme_workq = create_singlethread_workqueue("nvme"); + if (!nvme_workq) + goto kill_kthread; + result = register_blkdev(nvme_major, "nvme"); if (result < 0) - goto kill_kthread; + goto kill_workq; else if (result > 0) nvme_major = result; @@ -2301,6 +2698,8 @@ unregister_blkdev: unregister_blkdev(nvme_major, "nvme"); + kill_workq: + destroy_workqueue(nvme_workq); kill_kthread: kthread_stop(nvme_thread); return result; @@ -2310,6 +2709,7 @@ { pci_unregister_driver(&nvme_driver); unregister_blkdev(nvme_major, "nvme"); + destroy_workqueue(nvme_workq); kthread_stop(nvme_thread); } --- linux-3.13.0.orig/drivers/block/nvme-scsi.c +++ linux-3.13.0/drivers/block/nvme-scsi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -3038,6 +3039,152 @@ return retcode; } +#ifdef CONFIG_COMPAT +typedef struct sg_io_hdr32 { + compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ + compat_int_t dxfer_direction; /* [i] data transfer direction */ + unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char mx_sb_len; /* [i] max length to write to sbp */ + unsigned short iovec_count; /* [i] 0 implies no scatter gather */ + compat_uint_t dxfer_len; /* [i] byte count of data transfer */ + compat_uint_t dxferp; /* [i], [*io] points to data transfer memory + or scatter gather list */ + compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ + compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ + compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ + compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ + compat_int_t pack_id; /* [i->o] unused internally (normally) */ + compat_uptr_t usr_ptr; /* [i->o] unused internally */ + unsigned char status; /* [o] scsi status */ + unsigned char masked_status; /* [o] shifted, masked scsi status */ + unsigned char msg_status; /* [o] messaging level data (optional) */ + unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ + unsigned short host_status; /* [o] errors from host adapter */ + unsigned short driver_status; /* [o] errors from software driver */ + compat_int_t resid; /* [o] dxfer_len - actual_transferred */ + compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ + compat_uint_t info; /* [o] auxiliary information */ +} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ + +typedef struct sg_iovec32 { + compat_uint_t iov_base; + compat_uint_t iov_len; +} sg_iovec32_t; + +static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count) +{ + sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1); + sg_iovec32_t __user *iov32 = dxferp; + int i; + + for (i = 0; i < iovec_count; i++) { + u32 base, len; + + if (get_user(base, &iov32[i].iov_base) || + get_user(len, &iov32[i].iov_len) || + put_user(compat_ptr(base), &iov[i].iov_base) || + put_user(len, &iov[i].iov_len)) + return -EFAULT; + } + + if (put_user(iov, &sgio->dxferp)) + return -EFAULT; + return 0; +} + +int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg) +{ + sg_io_hdr32_t __user *sgio32 = (sg_io_hdr32_t __user *)arg; + sg_io_hdr_t __user *sgio; + u16 iovec_count; + u32 data; + void __user *dxferp; + int err; + int interface_id; + + if (get_user(interface_id, &sgio32->interface_id)) + return -EFAULT; + if (interface_id != 'S') + return -EINVAL; + + if (get_user(iovec_count, &sgio32->iovec_count)) + return -EFAULT; + + { + void __user *top = compat_alloc_user_space(0); + void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) + + (iovec_count * sizeof(sg_iovec_t))); + if (new > top) + return -EINVAL; + + sgio = new; + } + + /* Ok, now construct. */ + if (copy_in_user(&sgio->interface_id, &sgio32->interface_id, + (2 * sizeof(int)) + + (2 * sizeof(unsigned char)) + + (1 * sizeof(unsigned short)) + + (1 * sizeof(unsigned int)))) + return -EFAULT; + + if (get_user(data, &sgio32->dxferp)) + return -EFAULT; + dxferp = compat_ptr(data); + if (iovec_count) { + if (sg_build_iovec(sgio, dxferp, iovec_count)) + return -EFAULT; + } else { + if (put_user(dxferp, &sgio->dxferp)) + return -EFAULT; + } + + { + unsigned char __user *cmdp; + unsigned char __user *sbp; + + if (get_user(data, &sgio32->cmdp)) + return -EFAULT; + cmdp = compat_ptr(data); + + if (get_user(data, &sgio32->sbp)) + return -EFAULT; + sbp = compat_ptr(data); + + if (put_user(cmdp, &sgio->cmdp) || + put_user(sbp, &sgio->sbp)) + return -EFAULT; + } + + if (copy_in_user(&sgio->timeout, &sgio32->timeout, + 3 * sizeof(int))) + return -EFAULT; + + if (get_user(data, &sgio32->usr_ptr)) + return -EFAULT; + if (put_user(compat_ptr(data), &sgio->usr_ptr)) + return -EFAULT; + + err = nvme_sg_io(ns, sgio); + if (err >= 0) { + void __user *datap; + + if (copy_in_user(&sgio32->pack_id, &sgio->pack_id, + sizeof(int)) || + get_user(datap, &sgio->usr_ptr) || + put_user((u32)(unsigned long)datap, + &sgio32->usr_ptr) || + copy_in_user(&sgio32->status, &sgio->status, + (4 * sizeof(unsigned char)) + + (2 * sizeof(unsigned short)) + + (3 * sizeof(int)))) + err = -EFAULT; + } + + return err; +} +#endif + int nvme_sg_get_version_num(int __user *ip) { return put_user(sg_version_num, ip); --- linux-3.13.0.orig/drivers/block/xen-blkfront.c +++ linux-3.13.0/drivers/block/xen-blkfront.c @@ -1356,7 +1356,7 @@ char *type; int len; /* no unplug has been done: do not hook devices != xen vbds */ - if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY) { + if (xen_has_pv_and_legacy_disk_devices()) { int major; if (!VDEV_IS_EXTENDED(vdevice)) @@ -1904,13 +1904,16 @@ case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateConnected: blkfront_connect(info); break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's Closing state -- fallthrough */ case XenbusStateClosing: blkfront_closing(info); break; @@ -2079,7 +2082,7 @@ if (!xen_domain()) return -ENODEV; - if (xen_hvm_domain() && !xen_platform_pci_unplug) + if (!xen_has_pv_disk_devices()) return -ENODEV; if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) { --- linux-3.13.0.orig/drivers/block/nbd.c +++ linux-3.13.0/drivers/block/nbd.c @@ -57,7 +57,7 @@ static unsigned int nbds_max = 16; static struct nbd_device *nbd_dev; -static int max_part; +static int max_part = 15; /* * Use just one lock (or at most 1 per NIC). Two arguments for this: --- linux-3.13.0.orig/drivers/md/dm.c +++ linux-3.13.0/drivers/md/dm.c @@ -200,8 +200,8 @@ /* forced geometry settings */ struct hd_geometry geometry; - /* sysfs handle */ - struct kobject kobj; + /* kobject and completion */ + struct dm_kobject_holder kobj_holder; /* zero-length flush that will be cloned and submitted to targets */ struct bio flush_bio; @@ -2041,6 +2041,7 @@ init_waitqueue_head(&md->wait); INIT_WORK(&md->work, dm_wq_work); init_waitqueue_head(&md->eventq); + init_completion(&md->kobj_holder.completion); md->disk->major = _major; md->disk->first_minor = minor; @@ -2899,23 +2900,18 @@ { return md->disk; } +EXPORT_SYMBOL_GPL(dm_disk); struct kobject *dm_kobject(struct mapped_device *md) { - return &md->kobj; + return &md->kobj_holder.kobj; } -/* - * struct mapped_device should not be exported outside of dm.c - * so use this check to verify that kobj is part of md structure - */ struct mapped_device *dm_get_from_kobject(struct kobject *kobj) { struct mapped_device *md; - md = container_of(kobj, struct mapped_device, kobj); - if (&md->kobj != kobj) - return NULL; + md = container_of(kobj, struct mapped_device, kobj_holder.kobj); if (test_bit(DMF_FREEING, &md->flags) || dm_deleting_md(md)) --- linux-3.13.0.orig/drivers/md/raid5.c +++ linux-3.13.0/drivers/md/raid5.c @@ -675,8 +675,10 @@ || !conf->inactive_blocked), *(conf->hash_locks + hash)); conf->inactive_blocked = 0; - } else + } else { init_stripe(sh, sector, previous); + atomic_inc(&sh->count); + } } else { spin_lock(&conf->device_lock); if (atomic_read(&sh->count)) { @@ -695,13 +697,11 @@ sh->group = NULL; } } + atomic_inc(&sh->count); spin_unlock(&conf->device_lock); } } while (sh == NULL); - if (sh) - atomic_inc(&sh->count); - spin_unlock_irq(conf->hash_locks + hash); return sh; } @@ -2111,6 +2111,7 @@ set_bit(R5_MadeGoodRepl, &sh->dev[i].flags); } else { if (!uptodate) { + set_bit(STRIPE_DEGRADED, &sh->state); set_bit(WriteErrorSeen, &rdev->flags); set_bit(R5_WriteError, &sh->dev[i].flags); if (!test_and_set_bit(WantReplacement, &rdev->flags)) @@ -5511,23 +5512,43 @@ return sectors * (raid_disks - conf->max_degraded); } +static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu) +{ + safe_put_page(percpu->spare_page); + kfree(percpu->scribble); + percpu->spare_page = NULL; + percpu->scribble = NULL; +} + +static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu) +{ + if (conf->level == 6 && !percpu->spare_page) + percpu->spare_page = alloc_page(GFP_KERNEL); + if (!percpu->scribble) + percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); + + if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) { + free_scratch_buffer(conf, percpu); + return -ENOMEM; + } + + return 0; +} + static void raid5_free_percpu(struct r5conf *conf) { - struct raid5_percpu *percpu; unsigned long cpu; if (!conf->percpu) return; - get_online_cpus(); - for_each_possible_cpu(cpu) { - percpu = per_cpu_ptr(conf->percpu, cpu); - safe_put_page(percpu->spare_page); - kfree(percpu->scribble); - } #ifdef CONFIG_HOTPLUG_CPU unregister_cpu_notifier(&conf->cpu_notify); #endif + + get_online_cpus(); + for_each_possible_cpu(cpu) + free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); put_online_cpus(); free_percpu(conf->percpu); @@ -5554,15 +5575,7 @@ switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - if (conf->level == 6 && !percpu->spare_page) - percpu->spare_page = alloc_page(GFP_KERNEL); - if (!percpu->scribble) - percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); - - if (!percpu->scribble || - (conf->level == 6 && !percpu->spare_page)) { - safe_put_page(percpu->spare_page); - kfree(percpu->scribble); + if (alloc_scratch_buffer(conf, percpu)) { pr_err("%s: failed memory allocation for cpu%ld\n", __func__, cpu); return notifier_from_errno(-ENOMEM); @@ -5570,10 +5583,7 @@ break; case CPU_DEAD: case CPU_DEAD_FROZEN: - safe_put_page(percpu->spare_page); - kfree(percpu->scribble); - percpu->spare_page = NULL; - percpu->scribble = NULL; + free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); break; default: break; @@ -5585,40 +5595,29 @@ static int raid5_alloc_percpu(struct r5conf *conf) { unsigned long cpu; - struct page *spare_page; - struct raid5_percpu __percpu *allcpus; - void *scribble; - int err; + int err = 0; - allcpus = alloc_percpu(struct raid5_percpu); - if (!allcpus) + conf->percpu = alloc_percpu(struct raid5_percpu); + if (!conf->percpu) return -ENOMEM; - conf->percpu = allcpus; + +#ifdef CONFIG_HOTPLUG_CPU + conf->cpu_notify.notifier_call = raid456_cpu_notify; + conf->cpu_notify.priority = 0; + err = register_cpu_notifier(&conf->cpu_notify); + if (err) + return err; +#endif get_online_cpus(); - err = 0; for_each_present_cpu(cpu) { - if (conf->level == 6) { - spare_page = alloc_page(GFP_KERNEL); - if (!spare_page) { - err = -ENOMEM; - break; - } - per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page; - } - scribble = kmalloc(conf->scribble_len, GFP_KERNEL); - if (!scribble) { - err = -ENOMEM; + err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); + if (err) { + pr_err("%s: failed memory allocation for cpu%ld\n", + __func__, cpu); break; } - per_cpu_ptr(conf->percpu, cpu)->scribble = scribble; } -#ifdef CONFIG_HOTPLUG_CPU - conf->cpu_notify.notifier_call = raid456_cpu_notify; - conf->cpu_notify.priority = 0; - if (err == 0) - err = register_cpu_notifier(&conf->cpu_notify); -#endif put_online_cpus(); return err; --- linux-3.13.0.orig/drivers/md/raid1.c +++ linux-3.13.0/drivers/md/raid1.c @@ -1952,11 +1952,15 @@ for (i = 0; i < conf->raid_disks * 2; i++) { int j; int size; + int uptodate; struct bio *b = r1_bio->bios[i]; if (b->bi_end_io != end_sync_read) continue; - /* fixup the bio for reuse */ + /* fixup the bio for reuse, but preserve BIO_UPTODATE */ + uptodate = test_bit(BIO_UPTODATE, &b->bi_flags); bio_reset(b); + if (!uptodate) + clear_bit(BIO_UPTODATE, &b->bi_flags); b->bi_vcnt = vcnt; b->bi_size = r1_bio->sectors << 9; b->bi_sector = r1_bio->sector + @@ -1989,11 +1993,14 @@ int j; struct bio *pbio = r1_bio->bios[primary]; struct bio *sbio = r1_bio->bios[i]; + int uptodate = test_bit(BIO_UPTODATE, &sbio->bi_flags); if (sbio->bi_end_io != end_sync_read) continue; + /* Now we can 'fixup' the BIO_UPTODATE flag */ + set_bit(BIO_UPTODATE, &sbio->bi_flags); - if (test_bit(BIO_UPTODATE, &sbio->bi_flags)) { + if (uptodate) { for (j = vcnt; j-- ; ) { struct page *p, *s; p = pbio->bi_io_vec[j].bv_page; @@ -2008,7 +2015,7 @@ if (j >= 0) atomic64_add(r1_bio->sectors, &mddev->resync_mismatches); if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery) - && test_bit(BIO_UPTODATE, &sbio->bi_flags))) { + && uptodate)) { /* No need to write to this device. */ sbio->bi_end_io = NULL; rdev_dec_pending(conf->mirrors[i].rdev, mddev); --- linux-3.13.0.orig/drivers/md/dm-builtin.c +++ linux-3.13.0/drivers/md/dm-builtin.c @@ -0,0 +1,48 @@ +#include "dm.h" + +/* + * The kobject release method must not be placed in the module itself, + * otherwise we are subject to module unload races. + * + * The release method is called when the last reference to the kobject is + * dropped. It may be called by any other kernel code that drops the last + * reference. + * + * The release method suffers from module unload race. We may prevent the + * module from being unloaded at the start of the release method (using + * increased module reference count or synchronizing against the release + * method), however there is no way to prevent the module from being + * unloaded at the end of the release method. + * + * If this code were placed in the dm module, the following race may + * happen: + * 1. Some other process takes a reference to dm kobject + * 2. The user issues ioctl function to unload the dm device + * 3. dm_sysfs_exit calls kobject_put, however the object is not released + * because of the other reference taken at step 1 + * 4. dm_sysfs_exit waits on the completion + * 5. The other process that took the reference in step 1 drops it, + * dm_kobject_release is called from this process + * 6. dm_kobject_release calls complete() + * 7. a reschedule happens before dm_kobject_release returns + * 8. dm_sysfs_exit continues, the dm device is unloaded, module reference + * count is decremented + * 9. The user unloads the dm module + * 10. The other process that was rescheduled in step 7 continues to run, + * it is now executing code in unloaded module, so it crashes + * + * Note that if the process that takes the foreign reference to dm kobject + * has a low priority and the system is sufficiently loaded with + * higher-priority processes that prevent the low-priority process from + * being scheduled long enough, this bug may really happen. + * + * In order to fix this module unload race, we place the release method + * into a helper code that is compiled directly into the kernel. + */ + +void dm_kobject_release(struct kobject *kobj) +{ + complete(dm_get_completion_from_kobject(kobj)); +} + +EXPORT_SYMBOL(dm_kobject_release); --- linux-3.13.0.orig/drivers/md/dm-mpath.c +++ linux-3.13.0/drivers/md/dm-mpath.c @@ -1626,8 +1626,11 @@ /* * Only pass ioctls through if the device sizes match exactly. */ - if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) - r = scsi_verify_blk_ioctl(NULL, cmd); + if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) { + int err = scsi_verify_blk_ioctl(NULL, cmd); + if (err) + r = err; + } if (r == -ENOTCONN && !fatal_signal_pending(current)) queue_work(kmultipathd, &m->process_queued_ios); --- linux-3.13.0.orig/drivers/md/dm-thin-metadata.c +++ linux-3.13.0/drivers/md/dm-thin-metadata.c @@ -1349,6 +1349,12 @@ return td->id; } +/* + * Check whether @time (of block creation) is older than @td's last snapshot. + * If so then the associated block is shared with the last snapshot device. + * Any block on a device created *after* the device last got snapshotted is + * necessarily not shared. + */ static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time) { return td->snapshotted_time > time; @@ -1458,6 +1464,20 @@ return r; } +int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result) +{ + int r; + uint32_t ref_count; + + down_read(&pmd->root_lock); + r = dm_sm_get_count(pmd->data_sm, b, &ref_count); + if (!r) + *result = (ref_count != 0); + up_read(&pmd->root_lock); + + return r; +} + bool dm_thin_changed_this_transaction(struct dm_thin_device *td) { int r; @@ -1468,6 +1488,23 @@ return r; } + +bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd) +{ + bool r = false; + struct dm_thin_device *td, *tmp; + + down_read(&pmd->root_lock); + list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) { + if (td->changed) { + r = td->changed; + break; + } + } + up_read(&pmd->root_lock); + + return r; +} bool dm_thin_aborted_changes(struct dm_thin_device *td) { --- linux-3.13.0.orig/drivers/md/dm-thin.c +++ linux-3.13.0/drivers/md/dm-thin.c @@ -512,6 +512,7 @@ unsigned quiesced:1; unsigned prepared:1; unsigned pass_discard:1; + unsigned definitely_not_shared:1; struct thin_c *tc; dm_block_t virt_block; @@ -683,7 +684,15 @@ cell_defer_no_holder(tc, m->cell2); if (m->pass_discard) - remap_and_issue(tc, m->bio, m->data_block); + if (m->definitely_not_shared) + remap_and_issue(tc, m->bio, m->data_block); + else { + bool used = false; + if (dm_pool_block_is_used(tc->pool->pmd, m->data_block, &used) || used) + bio_endio(m->bio, 0); + else + remap_and_issue(tc, m->bio, m->data_block); + } else bio_endio(m->bio, 0); @@ -751,13 +760,17 @@ static struct dm_thin_new_mapping *get_next_mapping(struct pool *pool) { - struct dm_thin_new_mapping *r = pool->next_mapping; + struct dm_thin_new_mapping *m = pool->next_mapping; BUG_ON(!pool->next_mapping); + memset(m, 0, sizeof(struct dm_thin_new_mapping)); + INIT_LIST_HEAD(&m->list); + m->bio = NULL; + pool->next_mapping = NULL; - return r; + return m; } static void schedule_copy(struct thin_c *tc, dm_block_t virt_block, @@ -769,15 +782,10 @@ struct pool *pool = tc->pool; struct dm_thin_new_mapping *m = get_next_mapping(pool); - INIT_LIST_HEAD(&m->list); - m->quiesced = 0; - m->prepared = 0; m->tc = tc; m->virt_block = virt_block; m->data_block = data_dest; m->cell = cell; - m->err = 0; - m->bio = NULL; if (!dm_deferred_set_add_work(pool->shared_read_ds, &m->list)) m->quiesced = 1; @@ -840,15 +848,12 @@ struct pool *pool = tc->pool; struct dm_thin_new_mapping *m = get_next_mapping(pool); - INIT_LIST_HEAD(&m->list); m->quiesced = 1; m->prepared = 0; m->tc = tc; m->virt_block = virt_block; m->data_block = data_block; m->cell = cell; - m->err = 0; - m->bio = NULL; /* * If the whole block of data is being overwritten or we are not @@ -1040,12 +1045,12 @@ */ m = get_next_mapping(pool); m->tc = tc; - m->pass_discard = (!lookup_result.shared) && pool->pf.discard_passdown; + m->pass_discard = pool->pf.discard_passdown; + m->definitely_not_shared = !lookup_result.shared; m->virt_block = block; m->data_block = lookup_result.block; m->cell = cell; m->cell2 = cell2; - m->err = 0; m->bio = bio; if (!dm_deferred_set_add_work(pool->all_io_ds, &m->list)) { @@ -1349,7 +1354,8 @@ bio_list_init(&pool->deferred_flush_bios); spin_unlock_irqrestore(&pool->lock, flags); - if (bio_list_empty(&bios) && !need_commit_due_to_time(pool)) + if (bio_list_empty(&bios) && + !(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool))) return; if (commit(pool)) { @@ -1390,16 +1396,16 @@ return pool->pf.mode; } -static void set_pool_mode(struct pool *pool, enum pool_mode mode) +static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) { int r; + enum pool_mode old_mode = pool->pf.mode; - pool->pf.mode = mode; - - switch (mode) { + switch (new_mode) { case PM_FAIL: - DMERR("%s: switching pool to failure mode", - dm_device_name(pool->pool_md)); + if (old_mode != new_mode) + DMERR("%s: switching pool to failure mode", + dm_device_name(pool->pool_md)); dm_pool_metadata_read_only(pool->pmd); pool->process_bio = process_bio_fail; pool->process_discard = process_bio_fail; @@ -1408,13 +1414,15 @@ break; case PM_READ_ONLY: - DMERR("%s: switching pool to read-only mode", - dm_device_name(pool->pool_md)); + if (old_mode != new_mode) + DMERR("%s: switching pool to read-only mode", + dm_device_name(pool->pool_md)); r = dm_pool_abort_metadata(pool->pmd); if (r) { DMERR("%s: aborting transaction failed", dm_device_name(pool->pool_md)); - set_pool_mode(pool, PM_FAIL); + new_mode = PM_FAIL; + set_pool_mode(pool, new_mode); } else { dm_pool_metadata_read_only(pool->pmd); pool->process_bio = process_bio_read_only; @@ -1425,6 +1433,9 @@ break; case PM_WRITE: + if (old_mode != new_mode) + DMINFO("%s: switching pool to write mode", + dm_device_name(pool->pool_md)); dm_pool_metadata_read_write(pool->pmd); pool->process_bio = process_bio; pool->process_discard = process_discard; @@ -1432,6 +1443,8 @@ pool->process_prepared_discard = process_prepared_discard; break; } + + pool->pf.mode = new_mode; } /*----------------------------------------------------------------*/ @@ -1648,6 +1661,17 @@ enum pool_mode new_mode = pt->adjusted_pf.mode; /* + * Don't change the pool's mode until set_pool_mode() below. + * Otherwise the pool's process_* function pointers may + * not match the desired pool mode. + */ + pt->adjusted_pf.mode = old_mode; + + pool->ti = ti; + pool->pf = pt->adjusted_pf; + pool->low_water_blocks = pt->low_water_blocks; + + /* * If we were in PM_FAIL mode, rollback of metadata failed. We're * not going to recover without a thin_repair. So we never let the * pool move out of the old mode. On the other hand a PM_READ_ONLY @@ -1657,10 +1681,6 @@ if (old_mode == PM_FAIL) new_mode = old_mode; - pool->ti = ti; - pool->low_water_blocks = pt->low_water_blocks; - pool->pf = pt->adjusted_pf; - set_pool_mode(pool, new_mode); return 0; @@ -2828,6 +2848,7 @@ if (get_pool_mode(tc->pool) == PM_FAIL) { ti->error = "Couldn't open thin device, Pool is in fail mode"; + r = -EINVAL; goto bad_thin_open; } @@ -2839,7 +2860,7 @@ r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block); if (r) - goto bad_thin_open; + goto bad_target_max_io_len; ti->num_flush_bios = 1; ti->flush_supported = true; @@ -2860,6 +2881,8 @@ return 0; +bad_target_max_io_len: + dm_pool_close_thin_device(tc->td); bad_thin_open: __pool_dec(tc->pool); bad_pool_lookup: --- linux-3.13.0.orig/drivers/md/dm-crypt.c +++ linux-3.13.0/drivers/md/dm-crypt.c @@ -2003,6 +2003,12 @@ return fn(ti, cc->dev, cc->start, ti->len, data); } +static void crypt_io_hints(struct dm_target *ti, + struct queue_limits *limits) +{ + limits->max_write_same_sectors = 0; +} + static struct target_type crypt_target = { .name = "crypt", .version = {1, 13, 0}, @@ -2017,6 +2023,7 @@ .message = crypt_message, .merge = crypt_merge, .iterate_devices = crypt_iterate_devices, + .io_hints = crypt_io_hints, }; static int __init dm_crypt_init(void) --- linux-3.13.0.orig/drivers/md/dm.h +++ linux-3.13.0/drivers/md/dm.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "dm-stats.h" @@ -148,12 +150,27 @@ /* * sysfs interface */ +struct dm_kobject_holder { + struct kobject kobj; + struct completion completion; +}; + +static inline struct completion *dm_get_completion_from_kobject(struct kobject *kobj) +{ + return &container_of(kobj, struct dm_kobject_holder, kobj)->completion; +} + int dm_sysfs_init(struct mapped_device *md); void dm_sysfs_exit(struct mapped_device *md); struct kobject *dm_kobject(struct mapped_device *md); struct mapped_device *dm_get_from_kobject(struct kobject *kobj); /* + * The kobject helper + */ +void dm_kobject_release(struct kobject *kobj); + +/* * Targets for linear and striped mappings */ int dm_linear_init(void); --- linux-3.13.0.orig/drivers/md/dm-cache-target.c +++ linux-3.13.0/drivers/md/dm-cache-target.c @@ -283,6 +283,7 @@ bool tick:1; unsigned req_nr:2; struct dm_deferred_entry *all_io_entry; + struct dm_hook_info hook_info; /* * writethrough fields. These MUST remain at the end of this @@ -291,7 +292,6 @@ */ struct cache *cache; dm_cblock_t cblock; - struct dm_hook_info hook_info; struct dm_bio_details bio_details; }; @@ -970,12 +970,13 @@ int r; struct dm_io_region o_region, c_region; struct cache *cache = mg->cache; + sector_t cblock = from_cblock(mg->cblock); o_region.bdev = cache->origin_dev->bdev; o_region.count = cache->sectors_per_block; c_region.bdev = cache->cache_dev->bdev; - c_region.sector = from_cblock(mg->cblock) * cache->sectors_per_block; + c_region.sector = cblock * cache->sectors_per_block; c_region.count = cache->sectors_per_block; if (mg->writeback || mg->demote) { @@ -2453,20 +2454,18 @@ bool discarded_block; struct dm_bio_prison_cell *cell; struct policy_result lookup_result; - struct per_bio_data *pb; + struct per_bio_data *pb = init_per_bio_data(bio, pb_data_size); - if (from_oblock(block) > from_oblock(cache->origin_blocks)) { + if (unlikely(from_oblock(block) >= from_oblock(cache->origin_blocks))) { /* * This can only occur if the io goes to a partial block at * the end of the origin device. We don't cache these. * Just remap to the origin and carry on. */ - remap_to_origin_clear_discard(cache, bio, block); + remap_to_origin(cache, bio); return DM_MAPIO_REMAPPED; } - pb = init_per_bio_data(bio, pb_data_size); - if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) { defer_bio(cache, bio); return DM_MAPIO_SUBMITTED; --- linux-3.13.0.orig/drivers/md/Makefile +++ linux-3.13.0/drivers/md/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_BCACHE) += bcache/ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o +obj-$(CONFIG_BLK_DEV_DM_BUILTIN) += dm-builtin.o obj-$(CONFIG_DM_BUFIO) += dm-bufio.o obj-$(CONFIG_DM_BIO_PRISON) += dm-bio-prison.o obj-$(CONFIG_DM_CRYPT) += dm-crypt.o --- linux-3.13.0.orig/drivers/md/Kconfig +++ linux-3.13.0/drivers/md/Kconfig @@ -176,8 +176,12 @@ source "drivers/md/bcache/Kconfig" +config BLK_DEV_DM_BUILTIN + boolean + config BLK_DEV_DM tristate "Device mapper support" + select BLK_DEV_DM_BUILTIN ---help--- Device-mapper is a low level volume manager. It works by allowing people to specify mappings for ranges of logical sectors. Various --- linux-3.13.0.orig/drivers/md/dm-thin-metadata.h +++ linux-3.13.0/drivers/md/dm-thin-metadata.h @@ -161,6 +161,8 @@ */ bool dm_thin_changed_this_transaction(struct dm_thin_device *td); +bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd); + bool dm_thin_aborted_changes(struct dm_thin_device *td); int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, @@ -181,6 +183,8 @@ int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result); +int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result); + /* * Returns -ENOSPC if the new size is too small and already allocated * blocks would be lost. --- linux-3.13.0.orig/drivers/md/dm-sysfs.c +++ linux-3.13.0/drivers/md/dm-sysfs.c @@ -86,6 +86,7 @@ static struct kobj_type dm_ktype = { .sysfs_ops = &dm_sysfs_ops, .default_attrs = dm_attrs, + .release = dm_kobject_release, }; /* @@ -104,5 +105,7 @@ */ void dm_sysfs_exit(struct mapped_device *md) { - kobject_put(dm_kobject(md)); + struct kobject *kobj = dm_kobject(md); + kobject_put(kobj); + wait_for_completion(dm_get_completion_from_kobject(kobj)); } --- linux-3.13.0.orig/drivers/md/dm-cache-policy-mq.c +++ linux-3.13.0/drivers/md/dm-cache-policy-mq.c @@ -869,7 +869,7 @@ { struct mq_policy *mq = to_mq_policy(p); - kfree(mq->table); + vfree(mq->table); epool_exit(&mq->cache_pool); epool_exit(&mq->pre_cache_pool); kfree(mq); @@ -1224,7 +1224,7 @@ mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16); mq->hash_bits = ffs(mq->nr_buckets) - 1; - mq->table = kzalloc(sizeof(*mq->table) * mq->nr_buckets, GFP_KERNEL); + mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets); if (!mq->table) goto bad_alloc_table; --- linux-3.13.0.orig/drivers/md/bcache/bset.c +++ linux-3.13.0/drivers/md/bcache/bset.c @@ -955,7 +955,7 @@ *i = iter->data[--iter->used]; } -static void btree_sort_fixup(struct btree_iter *iter) +static struct bkey *btree_sort_fixup(struct btree_iter *iter, struct bkey *tmp) { while (iter->used > 1) { struct btree_iter_set *top = iter->data, *i = top + 1; @@ -983,9 +983,22 @@ } else { /* can't happen because of comparison func */ BUG_ON(!bkey_cmp(&START_KEY(top->k), &START_KEY(i->k))); - bch_cut_back(&START_KEY(i->k), top->k); + + if (bkey_cmp(i->k, top->k) < 0) { + bkey_copy(tmp, top->k); + + bch_cut_back(&START_KEY(i->k), tmp); + bch_cut_front(i->k, top->k); + heap_sift(iter, 0, btree_iter_cmp); + + return tmp; + } else { + bch_cut_back(&START_KEY(i->k), top->k); + } } } + + return NULL; } static void btree_mergesort(struct btree *b, struct bset *out, @@ -993,15 +1006,20 @@ bool fixup, bool remove_stale) { struct bkey *k, *last = NULL; + BKEY_PADDED(k) tmp; bool (*bad)(struct btree *, const struct bkey *) = remove_stale ? bch_ptr_bad : bch_ptr_invalid; while (!btree_iter_end(iter)) { if (fixup && !b->level) - btree_sort_fixup(iter); + k = btree_sort_fixup(iter, &tmp.k); + else + k = NULL; + + if (!k) + k = bch_btree_iter_next(iter); - k = bch_btree_iter_next(iter); if (bad(b, k)) continue; --- linux-3.13.0.orig/drivers/md/bcache/bcache.h +++ linux-3.13.0/drivers/md/bcache/bcache.h @@ -209,7 +209,9 @@ #define GC_MARK_RECLAIMABLE 0 #define GC_MARK_DIRTY 1 #define GC_MARK_METADATA 2 -BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, 13); +#define GC_SECTORS_USED_SIZE 13 +#define MAX_GC_SECTORS_USED (~(~0ULL << GC_SECTORS_USED_SIZE)) +BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, GC_SECTORS_USED_SIZE); BITMASK(GC_MOVE, struct bucket, gc_mark, 15, 1); #include "journal.h" --- linux-3.13.0.orig/drivers/md/bcache/btree.c +++ linux-3.13.0/drivers/md/bcache/btree.c @@ -1163,7 +1163,7 @@ /* guard against overflow */ SET_GC_SECTORS_USED(g, min_t(unsigned, GC_SECTORS_USED(g) + KEY_SIZE(k), - (1 << 14) - 1)); + MAX_GC_SECTORS_USED)); BUG_ON(!GC_SECTORS_USED(g)); } --- linux-3.13.0.orig/drivers/md/persistent-data/dm-space-map-common.c +++ linux-3.13.0/drivers/md/persistent-data/dm-space-map-common.c @@ -245,6 +245,10 @@ return -EINVAL; } + /* + * We need to set this before the dm_tm_new_block() call below. + */ + ll->nr_blocks = nr_blocks; for (i = old_blocks; i < blocks; i++) { struct dm_block *b; struct disk_index_entry idx; @@ -252,6 +256,7 @@ r = dm_tm_new_block(ll->tm, &dm_sm_bitmap_validator, &b); if (r < 0) return r; + idx.blocknr = cpu_to_le64(dm_block_location(b)); r = dm_tm_unlock(ll->tm, b); @@ -266,7 +271,6 @@ return r; } - ll->nr_blocks = nr_blocks; return 0; } --- linux-3.13.0.orig/drivers/md/persistent-data/dm-space-map-metadata.c +++ linux-3.13.0/drivers/md/persistent-data/dm-space-map-metadata.c @@ -91,6 +91,69 @@ dm_block_t block; }; +struct bop_ring_buffer { + unsigned begin; + unsigned end; + struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1]; +}; + +static void brb_init(struct bop_ring_buffer *brb) +{ + brb->begin = 0; + brb->end = 0; +} + +static bool brb_empty(struct bop_ring_buffer *brb) +{ + return brb->begin == brb->end; +} + +static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old) +{ + unsigned r = old + 1; + return (r >= (sizeof(brb->bops) / sizeof(*brb->bops))) ? 0 : r; +} + +static int brb_push(struct bop_ring_buffer *brb, + enum block_op_type type, dm_block_t b) +{ + struct block_op *bop; + unsigned next = brb_next(brb, brb->end); + + /* + * We don't allow the last bop to be filled, this way we can + * differentiate between full and empty. + */ + if (next == brb->begin) + return -ENOMEM; + + bop = brb->bops + brb->end; + bop->type = type; + bop->block = b; + + brb->end = next; + + return 0; +} + +static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result) +{ + struct block_op *bop; + + if (brb_empty(brb)) + return -ENODATA; + + bop = brb->bops + brb->begin; + result->type = bop->type; + result->block = bop->block; + + brb->begin = brb_next(brb, brb->begin); + + return 0; +} + +/*----------------------------------------------------------------*/ + struct sm_metadata { struct dm_space_map sm; @@ -101,25 +164,20 @@ unsigned recursion_count; unsigned allocated_this_transaction; - unsigned nr_uncommitted; - struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS]; + struct bop_ring_buffer uncommitted; struct threshold threshold; }; static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b) { - struct block_op *op; + int r = brb_push(&smm->uncommitted, type, b); - if (smm->nr_uncommitted == MAX_RECURSIVE_ALLOCATIONS) { + if (r) { DMERR("too many recursive allocations"); return -ENOMEM; } - op = smm->uncommitted + smm->nr_uncommitted++; - op->type = type; - op->block = b; - return 0; } @@ -158,11 +216,17 @@ return -ENOMEM; } - if (smm->recursion_count == 1 && smm->nr_uncommitted) { - while (smm->nr_uncommitted && !r) { - smm->nr_uncommitted--; - r = commit_bop(smm, smm->uncommitted + - smm->nr_uncommitted); + if (smm->recursion_count == 1) { + while (!brb_empty(&smm->uncommitted)) { + struct block_op bop; + + r = brb_pop(&smm->uncommitted, &bop); + if (r) { + DMERR("bug in bop ring buffer"); + break; + } + + r = commit_bop(smm, &bop); if (r) break; } @@ -217,7 +281,8 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b, uint32_t *result) { - int r, i; + int r; + unsigned i; struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); unsigned adjustment = 0; @@ -225,8 +290,10 @@ * We may have some uncommitted adjustments to add. This list * should always be really short. */ - for (i = 0; i < smm->nr_uncommitted; i++) { - struct block_op *op = smm->uncommitted + i; + for (i = smm->uncommitted.begin; + i != smm->uncommitted.end; + i = brb_next(&smm->uncommitted, i)) { + struct block_op *op = smm->uncommitted.bops + i; if (op->block != b) continue; @@ -254,7 +321,8 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm, dm_block_t b, int *result) { - int r, i, adjustment = 0; + int r, adjustment = 0; + unsigned i; struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); uint32_t rc; @@ -262,8 +330,11 @@ * We may have some uncommitted adjustments to add. This list * should always be really short. */ - for (i = 0; i < smm->nr_uncommitted; i++) { - struct block_op *op = smm->uncommitted + i; + for (i = smm->uncommitted.begin; + i != smm->uncommitted.end; + i = brb_next(&smm->uncommitted, i)) { + + struct block_op *op = smm->uncommitted.bops + i; if (op->block != b) continue; @@ -608,20 +679,38 @@ * Flick into a mode where all blocks get allocated in the new area. */ smm->begin = old_len; - memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm)); + memcpy(sm, &bootstrap_ops, sizeof(*sm)); /* * Extend. */ r = sm_ll_extend(&smm->ll, extra_blocks); + if (r) + goto out; /* - * Switch back to normal behaviour. + * We repeatedly increment then commit until the commit doesn't + * allocate any new blocks. */ - memcpy(&smm->sm, &ops, sizeof(smm->sm)); - for (i = old_len; !r && i < smm->begin; i++) - r = sm_ll_inc(&smm->ll, i, &ev); + do { + for (i = old_len; !r && i < smm->begin; i++) { + r = sm_ll_inc(&smm->ll, i, &ev); + if (r) + goto out; + } + old_len = smm->begin; + + r = sm_ll_commit(&smm->ll); + if (r) + goto out; + + } while (old_len != smm->begin); +out: + /* + * Switch back to normal behaviour. + */ + memcpy(sm, &ops, sizeof(*sm)); return r; } @@ -653,7 +742,7 @@ smm->begin = superblock + 1; smm->recursion_count = 0; smm->allocated_this_transaction = 0; - smm->nr_uncommitted = 0; + brb_init(&smm->uncommitted); threshold_init(&smm->threshold); memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm)); @@ -695,7 +784,7 @@ smm->begin = 0; smm->recursion_count = 0; smm->allocated_this_transaction = 0; - smm->nr_uncommitted = 0; + brb_init(&smm->uncommitted); threshold_init(&smm->threshold); memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll)); --- linux-3.13.0.orig/drivers/thermal/x86_pkg_temp_thermal.c +++ linux-3.13.0/drivers/thermal/x86_pkg_temp_thermal.c @@ -68,6 +68,10 @@ struct thermal_zone_device *tzone; }; +static const struct thermal_zone_params pkg_temp_tz_params = { + .no_hwmon = true, +}; + /* List maintaining number of package instances */ static LIST_HEAD(phy_dev_list); static DEFINE_MUTEX(phy_dev_list_mutex); @@ -446,7 +450,7 @@ thres_count, (thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01, - phy_dev_entry, &tzone_ops, NULL, 0, 0); + phy_dev_entry, &tzone_ops, &pkg_temp_tz_params, 0, 0); if (IS_ERR(phy_dev_entry->tzone)) { err = PTR_ERR(phy_dev_entry->tzone); goto err_ret_free; --- linux-3.13.0.orig/drivers/net/vxlan.c +++ linux-3.13.0/drivers/net/vxlan.c @@ -1047,6 +1047,15 @@ if (!vs) goto drop; + /* If the NIC driver gave us an encapsulated packet + * with the encapsulation mark, the device checksummed it + * for us. Otherwise force the upper layers to verify it. + */ + if (skb->ip_summed != CHECKSUM_UNNECESSARY || !skb->encapsulation) + skb->ip_summed = CHECKSUM_NONE; + + skb->encapsulation = 0; + vs->rcv(vs, skb, vxh->vx_vni); return 0; @@ -1105,17 +1114,6 @@ skb_reset_network_header(skb); - /* If the NIC driver gave us an encapsulated packet with - * CHECKSUM_UNNECESSARY and Rx checksum feature is enabled, - * leave the CHECKSUM_UNNECESSARY, the device checksummed it - * for us. Otherwise force the upper layers to verify it. - */ - if (skb->ip_summed != CHECKSUM_UNNECESSARY || !skb->encapsulation || - !(vxlan->dev->features & NETIF_F_RXCSUM)) - skb->ip_summed = CHECKSUM_NONE; - - skb->encapsulation = 0; - if (oip6) err = IP6_ECN_decapsulate(oip6, skb); if (oip) --- linux-3.13.0.orig/drivers/net/virtio_net.c +++ linux-3.13.0/drivers/net/virtio_net.c @@ -1645,7 +1645,8 @@ /* If we can receive ANY GSO packets, we must allocate large ones. */ if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) || + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO)) vi->big_packets = true; if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) --- linux-3.13.0.orig/drivers/net/xen-netfront.c +++ linux-3.13.0/drivers/net/xen-netfront.c @@ -117,6 +117,7 @@ } tx_skbs[NET_TX_RING_SIZE]; grant_ref_t gref_tx_head; grant_ref_t grant_tx_ref[NET_TX_RING_SIZE]; + struct page *grant_tx_page[NET_TX_RING_SIZE]; unsigned tx_skb_freelist; spinlock_t rx_lock ____cacheline_aligned_in_smp; @@ -396,6 +397,7 @@ gnttab_release_grant_reference( &np->gref_tx_head, np->grant_tx_ref[id]); np->grant_tx_ref[id] = GRANT_INVALID_REF; + np->grant_tx_page[id] = NULL; add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id); dev_kfree_skb_irq(skb); } @@ -452,6 +454,7 @@ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly); + np->grant_tx_page[id] = virt_to_page(data); tx->gref = np->grant_tx_ref[id] = ref; tx->offset = offset; tx->size = len; @@ -497,6 +500,7 @@ np->xbdev->otherend_id, mfn, GNTMAP_readonly); + np->grant_tx_page[id] = page; tx->gref = np->grant_tx_ref[id] = ref; tx->offset = offset; tx->size = bytes; @@ -596,6 +600,7 @@ mfn = virt_to_mfn(data); gnttab_grant_foreign_access_ref( ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly); + np->grant_tx_page[id] = virt_to_page(data); tx->gref = np->grant_tx_ref[id] = ref; tx->offset = offset; tx->size = len; @@ -1122,10 +1127,11 @@ continue; skb = np->tx_skbs[i].skb; - gnttab_end_foreign_access_ref(np->grant_tx_ref[i], - GNTMAP_readonly); - gnttab_release_grant_reference(&np->gref_tx_head, - np->grant_tx_ref[i]); + get_page(np->grant_tx_page[i]); + gnttab_end_foreign_access(np->grant_tx_ref[i], + GNTMAP_readonly, + (unsigned long)page_address(np->grant_tx_page[i])); + np->grant_tx_page[i] = NULL; np->grant_tx_ref[i] = GRANT_INVALID_REF; add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i); dev_kfree_skb_irq(skb); @@ -1134,78 +1140,35 @@ static void xennet_release_rx_bufs(struct netfront_info *np) { - struct mmu_update *mmu = np->rx_mmu; - struct multicall_entry *mcl = np->rx_mcl; - struct sk_buff_head free_list; - struct sk_buff *skb; - unsigned long mfn; - int xfer = 0, noxfer = 0, unused = 0; int id, ref; - dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n", - __func__); - return; - - skb_queue_head_init(&free_list); - spin_lock_bh(&np->rx_lock); for (id = 0; id < NET_RX_RING_SIZE; id++) { - ref = np->grant_rx_ref[id]; - if (ref == GRANT_INVALID_REF) { - unused++; - continue; - } + struct sk_buff *skb; + struct page *page; skb = np->rx_skbs[id]; - mfn = gnttab_end_foreign_transfer_ref(ref); - gnttab_release_grant_reference(&np->gref_rx_head, ref); - np->grant_rx_ref[id] = GRANT_INVALID_REF; - - if (0 == mfn) { - skb_shinfo(skb)->nr_frags = 0; - dev_kfree_skb(skb); - noxfer++; + if (!skb) continue; - } - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* Remap the page. */ - const struct page *page = - skb_frag_page(&skb_shinfo(skb)->frags[0]); - unsigned long pfn = page_to_pfn(page); - void *vaddr = page_address(page); + ref = np->grant_rx_ref[id]; + if (ref == GRANT_INVALID_REF) + continue; - MULTI_update_va_mapping(mcl, (unsigned long)vaddr, - mfn_pte(mfn, PAGE_KERNEL), - 0); - mcl++; - mmu->ptr = ((u64)mfn << PAGE_SHIFT) - | MMU_MACHPHYS_UPDATE; - mmu->val = pfn; - mmu++; + page = skb_frag_page(&skb_shinfo(skb)->frags[0]); - set_phys_to_machine(pfn, mfn); - } - __skb_queue_tail(&free_list, skb); - xfer++; - } - - dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n", - __func__, xfer, noxfer, unused); + /* gnttab_end_foreign_access() needs a page ref until + * foreign access is ended (which may be deferred). + */ + get_page(page); + gnttab_end_foreign_access(ref, 0, + (unsigned long)page_address(page)); + np->grant_rx_ref[id] = GRANT_INVALID_REF; - if (xfer) { - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* Do all the remapping work and M2P updates. */ - MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu, - NULL, DOMID_SELF); - mcl++; - HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl); - } + kfree_skb(skb); } - __skb_queue_purge(&free_list); - spin_unlock_bh(&np->rx_lock); } @@ -1358,6 +1321,7 @@ for (i = 0; i < NET_RX_RING_SIZE; i++) { np->rx_skbs[i] = NULL; np->grant_rx_ref[i] = GRANT_INVALID_REF; + np->grant_tx_page[i] = NULL; } /* A grant for every tx ring slot */ @@ -2115,7 +2079,7 @@ if (!xen_domain()) return -ENODEV; - if (xen_hvm_domain() && !xen_platform_pci_unplug) + if (!xen_has_pv_nic_devices()) return -ENODEV; pr_info("Initialising Xen virtual ethernet driver\n"); --- linux-3.13.0.orig/drivers/net/tun.c +++ linux-3.13.0/drivers/net/tun.c @@ -1651,7 +1651,9 @@ TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; dev->features = dev->hw_features; - dev->vlan_features = dev->features; + dev->vlan_features = dev->features & + ~(NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX); INIT_LIST_HEAD(&tun->disabled); err = tun_attach(tun, file, false); --- linux-3.13.0.orig/drivers/net/veth.c +++ linux-3.13.0/drivers/net/veth.c @@ -285,7 +285,8 @@ dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->features |= VETH_FEATURES; - dev->vlan_features = dev->features; + dev->vlan_features = dev->features & + ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX); dev->destructor = veth_dev_free; dev->hw_features = VETH_FEATURES; --- linux-3.13.0.orig/drivers/net/Makefile +++ linux-3.13.0/drivers/net/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_WLAN) += wireless/ obj-$(CONFIG_WIMAX) += wimax/ obj-$(CONFIG_IEEE802154) += ieee802154/ +obj-$(if $(CONFIG_DPA),y) += dpa/ obj-$(CONFIG_VMXNET3) += vmxnet3/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o --- linux-3.13.0.orig/drivers/net/Kconfig +++ linux-3.13.0/drivers/net/Kconfig @@ -341,7 +341,6 @@ The corresponding Linux frontend driver is enabled by the CONFIG_XEN_NETDEV_FRONTEND configuration option. - The backend driver presents a standard network device endpoint for each paravirtual network device to the driver domain network stack. These can then be bridged or routed @@ -353,12 +352,63 @@ will be called xen-netback. config VMXNET3 - tristate "VMware VMXNET3 ethernet driver" - depends on PCI && INET + tristate "VMware VMXNET3 ethernet driver" + depends on PCI && INET + help + This driver supports VMware's vmxnet3 virtual ethernet NIC. + To compile this driver as a module, choose M here: the + module will be called vmxnet3. + +config DPA + bool "Freescale Data Path Frame Manager Ethernet" + depends on FSL_SOC && FSL_BMAN_PORTAL && FSL_QMAN_PORTAL && FSL_FMAN + select PHYLIB + +config DPA_OFFLINE_PORTS + bool "Offline Ports support" + depends on DPA + default y + help + The Offline Parsing / Host Command ports (short: OH ports, of Offline ports) provide + most of the functionality of the regular, online ports, except they receive their + frames from a core or an accelerator on the SoC, via QMan frame queues, + rather than directly from the network. + Offline ports are configured via PCD (Parse-Classify-Distribute) schemes, just like + any online FMan port. They deliver the processed frames to frame queues, according + to the applied PCD configurations. + + Choosing this feature will not impact the functionality and/or performance of the system, + so it is safe to have it. + +config DPA_MAX_FRM_SIZE + int "Maximum L2 frame size" + depends on DPA + range 64 9600 + default "1522" help - This driver supports VMware's vmxnet3 virtual ethernet NIC. - To compile this driver as a module, choose M here: the - module will be called vmxnet3. + Configure this in relation to the maximum possible MTU of your network configuration. In particular, + one would need to increase this value in order to use jumbo frames. DPA_MAX_FRM_SIZE must accomodate + the Ethernet FCS (4 bytes) and one ETH+VLAN header (18 bytes), to a total of 22 bytes in excess of + the desired L3 MTU. + + Note that having too large a DPA_MAX_FRM_SIZE (much larger than the actual MTU) may lead to buffer + exhaustion, especially in the case of badly fragmented datagrams on the Rx path. Conversely, + having a DPA_MAX_FRM_SIZE smaller than the actual MTU will lead to frames being dropped. + + This can be overridden by specifying "fsl_fman_phy_max_frm" in the kernel bootargs: + * in Hypervisor-based scenarios, by adding a "chosen" node with the "bootargs" property specifying + "fsl_fman_phy_max_frm="; + * in non-Hypervisor-based scenarios, via u-boot's env, by modifying the "bootargs" env variable. + +config FSL_DPA_1588 + tristate "IEEE 1588-compliant timestamping" + depends on DPA + default n + +config DPAA_ETH_UNIT_TESTS + bool "Run Unit Tests for DPAA Ethernet" + depends on DPA + default y source "drivers/net/hyperv/Kconfig" --- linux-3.13.0.orig/drivers/net/macvlan.c +++ linux-3.13.0/drivers/net/macvlan.c @@ -507,6 +507,9 @@ static struct lock_class_key macvlan_netdev_xmit_lock_key; static struct lock_class_key macvlan_netdev_addr_lock_key; +#define ALWAYS_ON_FEATURES \ + (NETIF_F_SG | NETIF_F_GEN_CSUM | NETIF_F_GSO_SOFTWARE | NETIF_F_LLTX) + #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ @@ -540,7 +543,7 @@ dev->state = (dev->state & ~MACVLAN_STATE_MASK) | (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; - dev->features |= NETIF_F_LLTX; + dev->features |= ALWAYS_ON_FEATURES; dev->gso_max_size = lowerdev->gso_max_size; dev->iflink = lowerdev->ifindex; dev->hard_header_len = lowerdev->hard_header_len; @@ -700,7 +703,7 @@ features = netdev_increment_features(vlan->lowerdev->features, features, mask); - features |= NETIF_F_LLTX; + features |= ALWAYS_ON_FEATURES; return features; } --- linux-3.13.0.orig/drivers/net/phy/vitesse.c +++ linux-3.13.0/drivers/net/phy/vitesse.c @@ -74,7 +74,7 @@ MODULE_AUTHOR("Kriston Carson"); MODULE_LICENSE("GPL"); -static int vsc824x_add_skew(struct phy_device *phydev) +int vsc824x_add_skew(struct phy_device *phydev) { int err; int extcon; @@ -94,6 +94,7 @@ return err; } +EXPORT_SYMBOL(vsc824x_add_skew); static int vsc824x_config_init(struct phy_device *phydev) { --- linux-3.13.0.orig/drivers/net/phy/fixed.c +++ linux-3.13.0/drivers/net/phy/fixed.c @@ -5,6 +5,7 @@ * Anton Vorontsov * * Copyright (c) 2006-2007 MontaVista Software, Inc. + * Copyright 2009 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +57,9 @@ bmcr |= BMCR_FULLDPLX; switch (fp->status.speed) { + case 10000: + fp->regs[MDIO_STAT2] = MDIO_STAT2_DEVPRST_VAL; + break; case 1000: bmsr |= BMSR_ESTATEN; bmcr |= BMCR_SPEED1000; @@ -75,6 +80,9 @@ } } else { switch (fp->status.speed) { + case 10000: + fp->regs[MDIO_STAT2] = MDIO_STAT2_DEVPRST_VAL; + break; case 1000: bmsr |= BMSR_ESTATEN; bmcr |= BMCR_SPEED1000; --- linux-3.13.0.orig/drivers/net/phy/phy_device.c +++ linux-3.13.0/drivers/net/phy/phy_device.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -54,15 +55,13 @@ } static struct phy_driver genphy_driver; +static struct phy_driver gen10g_driver; extern int mdio_bus_init(void); extern void mdio_bus_exit(void); static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, - u32 flags, phy_interface_t interface); - /* * Creates a new phy_fixup and adds it to the list * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID) @@ -520,13 +519,13 @@ * * Description: Called by drivers to attach to a particular PHY * device. The phy_device is found, and properly hooked up - * to the phy_driver. If no driver is attached, then the - * genphy_driver is used. The phy_device is given a ptr to + * to the phy_driver. If no driver is attached, then a + * generic driver is used. The phy_device is given a ptr to * the attaching device, and given a callback for link status * change. The phy_device is returned to the attaching driver. */ -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, - u32 flags, phy_interface_t interface) +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + u32 flags, phy_interface_t interface) { struct device *d = &phydev->dev; int err; @@ -534,12 +533,10 @@ /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ if (NULL == d->driver) { - if (phydev->is_c45) { - pr_err("No driver for phy %x\n", phydev->phy_id); - return -ENODEV; - } - - d->driver = &genphy_driver.driver; + if (phydev->is_c45) + d->driver = &gen10g_driver.driver; + else + d->driver = &genphy_driver.driver; err = d->driver->probe(d); if (err >= 0) @@ -572,6 +569,7 @@ return err; } +EXPORT_SYMBOL(phy_attach_direct); /** * phy_attach - attach a network device to a particular PHY device @@ -622,6 +620,8 @@ * real driver could be loaded */ if (phydev->dev.driver == &genphy_driver.driver) device_release_driver(&phydev->dev); + else if (phydev->dev.driver == &gen10g_driver.driver) + device_release_driver(&phydev->dev); } EXPORT_SYMBOL(phy_detach); @@ -689,6 +689,13 @@ return changed; } +int gen10g_config_advert(struct phy_device *dev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_config_advert); + + /** * genphy_setup_forced - configures/forces speed/duplex from @phydev * @phydev: target phy_device struct @@ -742,6 +749,12 @@ } EXPORT_SYMBOL(genphy_restart_aneg); +int gen10g_restart_aneg(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_restart_aneg); + /** * genphy_config_aneg - restart auto-negotiation or write BMCR @@ -784,6 +797,13 @@ } EXPORT_SYMBOL(genphy_config_aneg); +int gen10g_config_aneg(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_config_aneg); + + /** * genphy_update_link - update link status in @phydev * @phydev: target phy_device struct @@ -867,6 +887,16 @@ lpa &= adv; + err = phy_read(phydev, MII_BMSR); + + if (err < 0) + return err; + + /* if the link changed while reading speed and duplex + * abort the speed and duplex update */ + if (((err & BMSR_LSTATUS) == 0) != (phydev->link == 0)) + return 0; + phydev->speed = SPEED_10; phydev->duplex = DUPLEX_HALF; phydev->pause = phydev->asym_pause = 0; @@ -913,6 +943,34 @@ } EXPORT_SYMBOL(genphy_read_status); +int gen10g_read_status(struct phy_device *phydev) +{ + int devad, reg; + u32 mmd_mask = phydev->c45_ids.devices_in_package; + + phydev->link = 1; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = 10000; + phydev->duplex = DUPLEX_FULL; + + for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { + if (!mmd_mask & 1) + continue; + + /* Read twice because link state is latched and a + * read moves the current state into the register */ + phy_read_mmd(phydev, devad, MDIO_STAT1); + reg = phy_read_mmd(phydev, devad, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + phydev->link = 0; + } + + return 0; +} +EXPORT_SYMBOL(gen10g_read_status); + + static int genphy_config_init(struct phy_device *phydev) { int val; @@ -959,6 +1017,15 @@ return 0; } + +static int gen10g_config_init(struct phy_device *phydev) +{ + /* Temporarily just say we support everything */ + phydev->supported = phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + int genphy_suspend(struct phy_device *phydev) { int value; @@ -974,6 +1041,13 @@ } EXPORT_SYMBOL(genphy_suspend); +int gen10g_suspend(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_suspend); + + int genphy_resume(struct phy_device *phydev) { int value; @@ -989,6 +1063,13 @@ } EXPORT_SYMBOL(genphy_resume); +int gen10g_resume(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_resume); + + /** * phy_probe - probe and init a PHY device * @dev: device to probe and init @@ -1129,6 +1210,20 @@ .driver = {.owner= THIS_MODULE, }, }; +static struct phy_driver gen10g_driver = { + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, + .read_status = gen10g_read_status, + .suspend = gen10g_suspend, + .resume = gen10g_resume, + .driver = {.owner = THIS_MODULE, }, +}; + + static int __init phy_init(void) { int rc; @@ -1139,13 +1234,25 @@ rc = phy_driver_register(&genphy_driver); if (rc) - mdio_bus_exit(); + goto genphy_register_failed; + + rc = phy_driver_register(&gen10g_driver); + if (rc) + goto gen10g_register_failed; + + return rc; + +gen10g_register_failed: + phy_driver_unregister(&genphy_driver); +genphy_register_failed: + mdio_bus_exit(); return rc; } static void __exit phy_exit(void) { + phy_driver_unregister(&gen10g_driver); phy_driver_unregister(&genphy_driver); mdio_bus_exit(); } --- linux-3.13.0.orig/drivers/net/usb/smsc95xx.c +++ linux-3.13.0/drivers/net/usb/smsc95xx.c @@ -1725,6 +1725,10 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + while (skb->len > 0) { u32 header, align_count; struct sk_buff *ax_skb; --- linux-3.13.0.orig/drivers/net/usb/mcs7830.c +++ linux-3.13.0/drivers/net/usb/mcs7830.c @@ -528,8 +528,9 @@ { u8 status; - if (skb->len == 0) { - dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) { + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); return 0; } --- linux-3.13.0.orig/drivers/net/usb/rndis_host.c +++ linux-3.13.0/drivers/net/usb/rndis_host.c @@ -494,6 +494,10 @@ */ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + /* peripheral may have batched packets to us... */ while (likely(skb->len)) { struct rndis_data_hdr *hdr = (void *)skb->data; --- linux-3.13.0.orig/drivers/net/usb/gl620a.c +++ linux-3.13.0/drivers/net/usb/gl620a.c @@ -86,6 +86,10 @@ u32 size; u32 count; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + header = (struct gl_header *) skb->data; // get the packet count of the received skb --- linux-3.13.0.orig/drivers/net/usb/ax88179_178a.c +++ linux-3.13.0/drivers/net/usb/ax88179_178a.c @@ -1030,20 +1030,12 @@ dev->mii.phy_id = 0x03; dev->mii.supports_gmii = 1; - if (usb_device_no_sg_constraint(dev->udev)) - dev->can_dma_sg = 1; - dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; - if (dev->can_dma_sg) { - dev->net->features |= NETIF_F_SG | NETIF_F_TSO; - dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO; - } - /* Enable checksum offload */ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; @@ -1119,6 +1111,10 @@ u16 hdr_off; u32 *pkt_hdr; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + skb_trim(skb, skb->len - 4); memcpy(&rx_hdr, skb_tail_pointer(skb), 4); le32_to_cpus(&rx_hdr); @@ -1418,6 +1414,19 @@ .tx_fixup = ax88179_tx_fixup, }; +static const struct driver_info lenovo_info = { + .description = "Lenovo OneLinkDock Gigabit LAN", + .bind = ax88179_bind, + .unbind = ax88179_unbind, + .status = ax88179_status, + .link_reset = ax88179_link_reset, + .reset = ax88179_reset, + .stop = ax88179_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88179_rx_fixup, + .tx_fixup = ax88179_tx_fixup, +}; + static const struct usb_device_id products[] = { { /* ASIX AX88179 10/100/1000 */ @@ -1435,6 +1444,10 @@ /* Samsung USB Ethernet Adapter */ USB_DEVICE(0x04e8, 0xa100), .driver_info = (unsigned long)&samsung_info, +}, { + /* Lenovo OneLinkDock Gigabit LAN */ + USB_DEVICE(0x17ef, 0x304b), + .driver_info = (unsigned long)&lenovo_info, }, { }, }; --- linux-3.13.0.orig/drivers/net/usb/qmi_wwan.c +++ linux-3.13.0/drivers/net/usb/qmi_wwan.c @@ -80,10 +80,10 @@ { __be16 proto; - /* usbnet rx_complete guarantees that skb->len is at least - * hard_header_len, so we can inspect the dest address without - * checking skb->len - */ + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + switch (skb->data[0] & 0xf0) { case 0x40: proto = htons(ETH_P_IP); @@ -723,6 +723,7 @@ {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ + {QMI_FIXED_INTF(0x1199, 0x9051, 8)}, /* Netgear AirCard 340U */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ --- linux-3.13.0.orig/drivers/net/usb/smsc75xx.c +++ linux-3.13.0/drivers/net/usb/smsc75xx.c @@ -2108,6 +2108,10 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + while (skb->len > 0) { u32 rx_cmd_a, rx_cmd_b, align_count, size; struct sk_buff *ax_skb; --- linux-3.13.0.orig/drivers/net/usb/net1080.c +++ linux-3.13.0/drivers/net/usb/net1080.c @@ -366,6 +366,10 @@ struct nc_trailer *trailer; u16 hdr_len, packet_len; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + if (!(skb->len & 0x01)) { netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n", skb->len, dev->net->hard_header_len, dev->hard_mtu, --- linux-3.13.0.orig/drivers/net/usb/usbnet.c +++ linux-3.13.0/drivers/net/usb/usbnet.c @@ -543,17 +543,19 @@ } // else network stack removes extra byte if we forced a short packet - if (skb->len) { - /* all data was already cloned from skb inside the driver */ - if (dev->driver_info->flags & FLAG_MULTI_PACKET) - dev_kfree_skb_any(skb); - else - usbnet_skb_return(dev, skb); + /* all data was already cloned from skb inside the driver */ + if (dev->driver_info->flags & FLAG_MULTI_PACKET) + goto done; + + if (skb->len < ETH_HLEN) { + dev->net->stats.rx_errors++; + dev->net->stats.rx_length_errors++; + netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len); + } else { + usbnet_skb_return(dev, skb); return; } - netif_dbg(dev, rx_err, dev->net, "drop\n"); - dev->net->stats.rx_errors++; done: skb_queue_tail(&dev->done, skb); } @@ -575,13 +577,6 @@ switch (urb_status) { /* success */ case 0: - if (skb->len < dev->net->hard_header_len) { - state = rx_cleanup; - dev->net->stats.rx_errors++; - dev->net->stats.rx_length_errors++; - netif_dbg(dev, rx_err, dev->net, - "rx length %d\n", skb->len); - } break; /* stalls need manual reset. this is rare ... except that --- linux-3.13.0.orig/drivers/net/usb/asix_devices.c +++ linux-3.13.0/drivers/net/usb/asix_devices.c @@ -918,7 +918,8 @@ .status = asix_status, .link_reset = ax88178_link_reset, .reset = ax88178_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | + FLAG_MULTI_PACKET, .rx_fixup = asix_rx_fixup_common, .tx_fixup = asix_tx_fixup, }; --- linux-3.13.0.orig/drivers/net/dpa/mac-api.c +++ linux-3.13.0/drivers/net/dpa/mac-api.c @@ -0,0 +1,674 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "dpaa_eth-common.h" +#include "dpaa_eth.h" +#include "mac.h" + +#include "error_ext.h" /* GET_ERROR_TYPE, E_OK */ +#include "fm_mac_ext.h" +#include "fm_rtc_ext.h" + +#define MAC_DESCRIPTION "FSL FMan MAC API based driver" + +MODULE_LICENSE("Dual BSD/GPL"); + +MODULE_AUTHOR("Emil Medve "); + +MODULE_DESCRIPTION(MAC_DESCRIPTION); + +struct mac_priv_s { + t_Handle mac; +}; + +const char *mac_driver_description __initconst = MAC_DESCRIPTION; +const size_t mac_sizeof_priv[] = { + [DTSEC] = sizeof(struct mac_priv_s), + [XGMAC] = sizeof(struct mac_priv_s) +}; + +static const e_EnetMode _100[] = +{ + [PHY_INTERFACE_MODE_MII] = e_ENET_MODE_MII_100, + [PHY_INTERFACE_MODE_RMII] = e_ENET_MODE_RMII_100 +}; + +static const e_EnetMode _1000[] = +{ + [PHY_INTERFACE_MODE_GMII] = e_ENET_MODE_GMII_1000, + [PHY_INTERFACE_MODE_SGMII] = e_ENET_MODE_SGMII_1000, + [PHY_INTERFACE_MODE_TBI] = e_ENET_MODE_TBI_1000, + [PHY_INTERFACE_MODE_RGMII] = e_ENET_MODE_RGMII_1000, + [PHY_INTERFACE_MODE_RGMII_ID] = e_ENET_MODE_RGMII_1000, + [PHY_INTERFACE_MODE_RGMII_RXID] = e_ENET_MODE_RGMII_1000, + [PHY_INTERFACE_MODE_RGMII_TXID] = e_ENET_MODE_RGMII_1000, + [PHY_INTERFACE_MODE_RTBI] = e_ENET_MODE_RTBI_1000 +}; + +static e_EnetMode __cold __attribute__((nonnull)) +macdev2enetinterface(const struct mac_device *mac_dev) +{ + switch (mac_dev->max_speed) { + case SPEED_100: + return _100[mac_dev->phy_if]; + case SPEED_1000: + return _1000[mac_dev->phy_if]; + case SPEED_10000: + return e_ENET_MODE_XGMII_10000; + default: + return e_ENET_MODE_MII_100; + } +} + +static void mac_exception(t_Handle _mac_dev, e_FmMacExceptions exception) +{ + struct mac_device *mac_dev; + + mac_dev = (struct mac_device *)_mac_dev; + + if (e_FM_MAC_EX_10G_RX_FIFO_OVFL == exception) { + /* don't flag RX FIFO after the first */ + FM_MAC_SetException( + ((struct mac_priv_s *)macdev_priv(_mac_dev))->mac, + e_FM_MAC_EX_10G_RX_FIFO_OVFL, false); + printk(KERN_ERR "10G MAC got RX FIFO Error = %x\n", exception); + } + + cpu_dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", __file__, __func__, + exception); +} + +static int __cold init(struct mac_device *mac_dev) +{ + int _errno; + t_Error err; + struct mac_priv_s *priv; + t_FmMacParams param; + uint32_t version; + + priv = macdev_priv(mac_dev); + + param.baseAddr = (typeof(param.baseAddr))(uintptr_t)devm_ioremap( + mac_dev->dev, mac_dev->res->start, 0x2000); + param.enetMode = macdev2enetinterface(mac_dev); + memcpy(¶m.addr, mac_dev->addr, min(sizeof(param.addr), + sizeof(mac_dev->addr))); + param.macId = mac_dev->cell_index; + param.h_Fm = (t_Handle)mac_dev->fm; + param.mdioIrq = NO_IRQ; + param.f_Exception = mac_exception; + param.f_Event = mac_exception; + param.h_App = mac_dev; + + priv->mac = FM_MAC_Config(¶m); + if (unlikely(priv->mac == NULL)) { + dpaa_eth_err(mac_dev->dev, "FM_MAC_Config() failed\n"); + _errno = -EINVAL; + goto _return; + } + + err = FM_MAC_ConfigMaxFrameLength(priv->mac, fsl_fman_phy_maxfrm); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_ConfigMaxFrameLength() = 0x%08x\n", err); + goto _return_fm_mac_free; + } + + if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) { + /* 10G always works with pad and CRC */ + err = FM_MAC_ConfigPadAndCrc(priv->mac, true); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_ConfigPadAndCrc() = 0x%08x\n", err); + goto _return_fm_mac_free; + } + + err = FM_MAC_ConfigHalfDuplex(priv->mac, mac_dev->half_duplex); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_ConfigHalfDuplex() = 0x%08x\n", err); + goto _return_fm_mac_free; + } + } + else { + err = FM_MAC_ConfigResetOnInit(priv->mac, true); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_ConfigResetOnInit() = 0x%08x\n", err); + goto _return_fm_mac_free; + } + } + + err = FM_MAC_Init(priv->mac); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, "FM_MAC_Init() = 0x%08x\n", err); + goto _return_fm_mac_free; + } + +#ifndef CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN + /* For 1G MAC, disable by default the MIB counters overflow interrupt */ + if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) { + err = FM_MAC_SetException(priv->mac, + e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, FALSE); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_SetException() = 0x%08x\n", err); + goto _return_fm_mac_free; + } + } +#endif /* !CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN */ + + /* For 10G MAC, disable Tx ECC exception */ + if (macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) { + err = FM_MAC_SetException(priv->mac, + e_FM_MAC_EX_10G_1TX_ECC_ER, FALSE); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_SetException() = 0x%08x\n", err); + goto _return_fm_mac_free; + } + } + + err = FM_MAC_GetVesrion(priv->mac, &version); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) { + dpaa_eth_err(mac_dev->dev, "FM_MAC_GetVesrion() = 0x%08x\n", + err); + goto _return_fm_mac_free; + } + cpu_dev_info(mac_dev->dev, "FMan %s version: 0x%08x\n", + ((macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ? + "dTSEC" : "XGEC"), version); + + goto _return; + + +_return_fm_mac_free: + err = FM_MAC_Free(priv->mac); + if (unlikely(-GET_ERROR_TYPE(err) < 0)) + dpaa_eth_err(mac_dev->dev, "FM_MAC_Free() = 0x%08x\n", err); +_return: + return _errno; +} + +static int __cold start(struct mac_device *mac_dev) +{ + int _errno; + t_Error err; + struct phy_device *phy_dev = mac_dev->phy_dev; + + err = FM_MAC_Enable(((struct mac_priv_s *)macdev_priv(mac_dev))->mac, + e_COMM_MODE_RX_AND_TX); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_MAC_Enable() = 0x%08x\n", err); + + if (phy_dev) { + if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) + phy_start(phy_dev); + else if (phy_dev->drv->read_status) + phy_dev->drv->read_status(phy_dev); + } + + return _errno; +} + +static int __cold stop(struct mac_device *mac_dev) +{ + int _errno; + t_Error err; + + if (mac_dev->phy_dev && + (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000)) + phy_stop(mac_dev->phy_dev); + + err = FM_MAC_Disable(((struct mac_priv_s *)macdev_priv(mac_dev))->mac, + e_COMM_MODE_RX_AND_TX); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_MAC_Disable() = 0x%08x\n", err); + + return _errno; +} + +static int __cold change_promisc(struct mac_device *mac_dev) +{ + int _errno; + t_Error err; + + err = FM_MAC_SetPromiscuous( + ((struct mac_priv_s *)macdev_priv(mac_dev))->mac, + mac_dev->promisc = !mac_dev->promisc); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, + "FM_MAC_SetPromiscuous() = 0x%08x\n", err); + + return _errno; +} + +static int __cold set_multi(struct net_device *net_dev) +{ + struct dpa_priv_s *priv; + struct mac_device *mac_dev; + struct mac_priv_s *mac_priv; + struct mac_address *old_addr, *tmp; + struct netdev_hw_addr *ha; + int _errno; + t_Error err; + + priv = netdev_priv(net_dev); + mac_dev = priv->mac_dev; + mac_priv = macdev_priv(mac_dev); + + /* Clear previous address list */ + list_for_each_entry_safe(old_addr, tmp, &mac_dev->mc_addr_list, list) { + err = FM_MAC_RemoveHashMacAddr(mac_priv->mac, + (t_EnetAddr *)old_addr->addr); + _errno = -GET_ERROR_TYPE(err); + if (_errno < 0) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_RemoveHashMacAddr() = 0x%08x\n", err); + return _errno; + } + list_del(&old_addr->list); + kfree(old_addr); + } + + /* Add all the addresses from the new list */ + netdev_for_each_mc_addr(ha, net_dev) { + err = FM_MAC_AddHashMacAddr(mac_priv->mac, + (t_EnetAddr *)ha->addr); + _errno = -GET_ERROR_TYPE(err); + if (_errno < 0) { + dpaa_eth_err(mac_dev->dev, + "FM_MAC_AddHashMacAddr() = 0x%08x\n", err); + return _errno; + } + tmp = kmalloc(sizeof(struct mac_address), GFP_ATOMIC); + if (!tmp) { + dpaa_eth_err(mac_dev->dev, "Out of memory\n"); + return -ENOMEM; + } + memcpy(tmp->addr, ha->addr, ETH_ALEN); + list_add(&tmp->list, &mac_dev->mc_addr_list); + } + return 0; +} + +static int __cold change_addr(struct mac_device *mac_dev, uint8_t *addr) +{ + int _errno; + t_Error err; + + err = FM_MAC_ModifyMacAddr( + ((struct mac_priv_s *)macdev_priv(mac_dev))->mac, + (t_EnetAddr *)addr); + _errno = -GET_ERROR_TYPE(err); + if (_errno < 0) + dpaa_eth_err(mac_dev->dev, + "FM_MAC_ModifyMacAddr() = 0x%08x\n", err); + + return _errno; +} + +static void adjust_link(struct net_device *net_dev) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + struct phy_device *phy_dev = mac_dev->phy_dev; + int _errno; + t_Error err; + + if (!phy_dev->link) + return; + + err = FM_MAC_AdjustLink( + ((struct mac_priv_s *)macdev_priv(mac_dev))->mac, + phy_dev->speed, phy_dev->duplex); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_MAC_AdjustLink() = 0x%08x\n", + err); + + return; +} + +/* Initializes driver's PHY state, and attaches to the PHY. + * Returns 0 on success. + */ +static int dtsec_init_phy(struct net_device *net_dev) +{ + struct dpa_priv_s *priv; + struct mac_device *mac_dev; + struct phy_device *phy_dev; + + priv = netdev_priv(net_dev); + mac_dev = priv->mac_dev; + + if (!mac_dev->phy_node) + phy_dev = phy_connect(net_dev, mac_dev->fixed_bus_id, + &adjust_link, mac_dev->phy_if); + else + phy_dev = of_phy_connect(net_dev, mac_dev->phy_node, + &adjust_link, 0, mac_dev->phy_if); + if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) { + cpu_netdev_err(net_dev, "Could not connect to PHY %s\n", + mac_dev->phy_node ? + mac_dev->phy_node->full_name : + mac_dev->fixed_bus_id); + return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev); + } + + /* Remove any features not supported by the controller */ + phy_dev->supported &= priv->mac_dev->if_support; + phy_dev->advertising = phy_dev->supported; + + priv->mac_dev->phy_dev = phy_dev; + + return 0; +} + +static int xgmac_init_phy(struct net_device *net_dev) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + struct phy_device *phy_dev; + + if (!mac_dev->phy_node) + phy_dev = phy_attach(net_dev, mac_dev->fixed_bus_id, + mac_dev->phy_if); + else + phy_dev = of_phy_attach(net_dev, mac_dev->phy_node, 0, + mac_dev->phy_if); + if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) { + cpu_netdev_err(net_dev, "Could not attach to PHY %s\n", + mac_dev->phy_node ? + mac_dev->phy_node->full_name : + mac_dev->fixed_bus_id); + return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev); + } + + phy_dev->supported &= priv->mac_dev->if_support; + phy_dev->advertising = phy_dev->supported; + + mac_dev->phy_dev = phy_dev; + + return 0; +} + +static int __cold uninit(struct mac_device *mac_dev) +{ + int _errno, __errno; + t_Error err; + const struct mac_priv_s *priv; + + priv = macdev_priv(mac_dev); + + err = FM_MAC_Disable(priv->mac, e_COMM_MODE_RX_AND_TX); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_MAC_Disable() = 0x%08x\n", err); + + err = FM_MAC_Free(priv->mac); + __errno = -GET_ERROR_TYPE(err); + if (unlikely(__errno < 0)) { + dpaa_eth_err(mac_dev->dev, "FM_MAC_Free() = 0x%08x\n", err); + if (_errno < 0) + _errno = __errno; + } + + return _errno; +} + +static int __cold ptp_enable(struct mac_device *mac_dev) +{ + int _errno; + t_Error err; + const struct mac_priv_s *priv; + + priv = macdev_priv(mac_dev); + + err = FM_MAC_Enable1588TimeStamp(priv->mac); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_MAC_Enable1588TimeStamp()" + "= 0x%08x\n", err); + return _errno; +} + +static int __cold ptp_disable(struct mac_device *mac_dev) +{ + int _errno; + t_Error err; + const struct mac_priv_s *priv; + + priv = macdev_priv(mac_dev); + + err = FM_MAC_Disable1588TimeStamp(priv->mac); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_MAC_Disable1588TimeStamp()" + "= 0x%08x\n", err); + return _errno; +} + +static int __cold fm_rtc_enable(struct net_device *net_dev) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + int _errno; + t_Error err; + + err = FM_RTC_Enable(fm_get_rtc_handle(mac_dev->fm_dev), 0); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_Enable = 0x%08x\n", err); + + return _errno; +} + +static int __cold fm_rtc_disable(struct net_device *net_dev) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + int _errno; + t_Error err; + + err = FM_RTC_Disable(fm_get_rtc_handle(mac_dev->fm_dev)); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_Disable = 0x%08x\n", err); + + return _errno; +} + +static int __cold fm_rtc_get_cnt(struct net_device *net_dev, uint64_t *ts) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + int _errno; + t_Error err; + + err = FM_RTC_GetCurrentTime(fm_get_rtc_handle(mac_dev->fm_dev), ts); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_GetCurrentTime = 0x%08x\n", + err); + + return _errno; +} + +static int __cold fm_rtc_set_cnt(struct net_device *net_dev, uint64_t ts) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + int _errno; + t_Error err; + + err = FM_RTC_SetCurrentTime(fm_get_rtc_handle(mac_dev->fm_dev), ts); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_SetCurrentTime = 0x%08x\n", + err); + + return _errno; +} + +static int __cold fm_rtc_get_drift(struct net_device *net_dev, uint32_t *drift) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + int _errno; + t_Error err; + + err = FM_RTC_GetFreqCompensation(fm_get_rtc_handle(mac_dev->fm_dev), + drift); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_GetFreqCompensation =" + "0x%08x\n", err); + + return _errno; +} + +static int __cold fm_rtc_set_drift(struct net_device *net_dev, uint32_t drift) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + int _errno; + t_Error err; + + err = FM_RTC_SetFreqCompensation(fm_get_rtc_handle(mac_dev->fm_dev), + drift); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_SetFreqCompensation =" + "0x%08x\n", err); + + return _errno; +} + +static int __cold fm_rtc_set_alarm(struct net_device *net_dev, uint32_t id, + uint64_t time) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + t_FmRtcAlarmParams alarm; + int _errno; + t_Error err; + + alarm.alarmId = id; + alarm.alarmTime = time; + alarm.f_AlarmCallback = NULL; + err = FM_RTC_SetAlarm(fm_get_rtc_handle(mac_dev->fm_dev), + &alarm); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_SetAlarm =" + "0x%08x\n", err); + + return _errno; +} + +static int __cold fm_rtc_set_fiper(struct net_device *net_dev, uint32_t id, + uint64_t fiper) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct mac_device *mac_dev = priv->mac_dev; + t_FmRtcPeriodicPulseParams pp; + int _errno; + t_Error err; + + pp.periodicPulseId = id; + pp.periodicPulsePeriod = fiper; + pp.f_PeriodicPulseCallback = NULL; + err = FM_RTC_SetPeriodicPulse(fm_get_rtc_handle(mac_dev->fm_dev), &pp); + _errno = -GET_ERROR_TYPE(err); + if (unlikely(_errno < 0)) + dpaa_eth_err(mac_dev->dev, "FM_RTC_SetPeriodicPulse =" + "0x%08x\n", err); + + return _errno; +} + +static void __cold setup_dtsec(struct mac_device *mac_dev) +{ + mac_dev->init_phy = dtsec_init_phy; + mac_dev->init = init; + mac_dev->start = start; + mac_dev->stop = stop; + mac_dev->change_promisc = change_promisc; + mac_dev->change_addr = change_addr; + mac_dev->set_multi = set_multi; + mac_dev->uninit = uninit; + mac_dev->ptp_enable = ptp_enable; + mac_dev->ptp_disable = ptp_disable; + mac_dev->fm_rtc_enable = fm_rtc_enable; + mac_dev->fm_rtc_disable = fm_rtc_disable; + mac_dev->fm_rtc_get_cnt = fm_rtc_get_cnt; + mac_dev->fm_rtc_set_cnt = fm_rtc_set_cnt; + mac_dev->fm_rtc_get_drift = fm_rtc_get_drift; + mac_dev->fm_rtc_set_drift = fm_rtc_set_drift; + mac_dev->fm_rtc_set_alarm = fm_rtc_set_alarm; + mac_dev->fm_rtc_set_fiper = fm_rtc_set_fiper; +} + +static void __cold setup_xgmac(struct mac_device *mac_dev) +{ + mac_dev->init_phy = xgmac_init_phy; + mac_dev->init = init; + mac_dev->start = start; + mac_dev->stop = stop; + mac_dev->change_promisc = change_promisc; + mac_dev->change_addr = change_addr; + mac_dev->set_multi = set_multi; + mac_dev->uninit = uninit; +} + +void (*const mac_setup[])(struct mac_device *mac_dev) = { + [DTSEC] = setup_dtsec, + [XGMAC] = setup_xgmac +}; --- linux-3.13.0.orig/drivers/net/dpa/dpaa_eth.c +++ linux-3.13.0/drivers/net/dpa/dpaa_eth.c @@ -0,0 +1,3237 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* arp_hdr_len() */ +#include /* VLAN_HLEN */ +#include /* struct icmphdr */ +#include /* struct iphdr */ +#include /* struct ipv6hdr */ +#include /* struct udphdr */ +#include /* struct tcphdr */ +#include /* net_ratelimit() */ +#include /* ETH_P_IP and ETH_P_IPV6 */ +#include +#include +#include +#include /* get_hard_smp_processor_id() */ +#include +#ifdef CONFIG_DEBUG_FS +#include +#endif +#include + +#include "fsl_fman.h" +#include "fm_ext.h" +#include "fm_port_ext.h" + +#include "mac.h" +#include "dpaa_eth.h" +#include "dpaa_1588.h" + +#define ARRAY2_SIZE(arr) (ARRAY_SIZE(arr) * ARRAY_SIZE((arr)[0])) + +#define DPA_NETIF_FEATURES (NETIF_F_HW_QDISC) +#define DEFAULT_COUNT 64 +#define DEFAULT_BUF_SIZE DPA_BP_SIZE(fsl_fman_phy_maxfrm); +#define DPA_MAX_TX_BACKLOG 512 +#define DPA_NAPI_WEIGHT 64 + +#define DPA_BP_REFILL (1 | (smp_processor_id() << 16)) +#define DPA_BP_FINE ((smp_processor_id() << 16)) +#define DPA_BP_REFILL_NEEDED 1 + +/* Bootarg used to override the Kconfig DPA_MAX_FRM_SIZE value */ +#define FSL_FMAN_PHY_MAXFRM_BOOTARG "fsl_fman_phy_max_frm" + +/* + * Values for the L3R field of the FM Parse Results + */ +/* L3 Type field: First IP Present IPv4 */ +#define FM_L3_PARSE_RESULT_IPV4 0x8000 +/* L3 Type field: First IP Present IPv6 */ +#define FM_L3_PARSE_RESULT_IPV6 0x4000 + +/* + * Values for the L4R field of the FM Parse Results + */ +/* L4 Type field: UDP */ +#define FM_L4_PARSE_RESULT_UDP 0x40 +/* L4 Type field: TCP */ +#define FM_L4_PARSE_RESULT_TCP 0x20 + +/* + * FD status field indicating whether the FM Parser has attempted to validate + * the L4 csum of the frame. + * Note that having this bit set doesn't necessarily imply that the checksum + * is valid. One would have to check the parse results to find that out. + */ +#define FM_FD_STAT_L4CV 0x00000004 + +#define DPA_DESCRIPTION "FSL DPAA Ethernet driver" + +MODULE_LICENSE("Dual BSD/GPL"); + +MODULE_AUTHOR("Andy Fleming "); + +MODULE_DESCRIPTION(DPA_DESCRIPTION); + +static uint8_t debug = -1; +module_param(debug, byte, S_IRUGO); +MODULE_PARM_DESC(debug, "Module/Driver verbosity level"); + +static uint16_t tx_timeout = 1000; +module_param(tx_timeout, ushort, S_IRUGO); +MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms"); + +#ifdef CONFIG_DEBUG_FS +static struct dentry *dpa_debugfs_root; +#endif + +/* + * Max frame size, across all interfaces. + * Configurable from Kconfig or bootargs, to avoid allocating + * oversized (socket) buffers when not using jumbo frames. + * Must be large enough to accomodate the network MTU, but small enough + * to avoid wasting skb memory. + * + * Could be overridden once, at boot-time, via the + * fsl_fman_phy_set_max_frm() callback. + */ +int fsl_fman_phy_maxfrm = CONFIG_DPA_MAX_FRM_SIZE; + +static const char rtx[][3] = { + [RX] = "RX", + [TX] = "TX" +}; + +struct dpa_fq { + struct qman_fq fq_base; + struct list_head list; + struct net_device *net_dev; + bool init; + uint32_t fqid; + uint32_t flags; + uint16_t channel; + uint8_t wq; +}; + +/* BM */ + +#ifdef DEBUG +#define GFP_DPA_BP (GFP_DMA | __GFP_ZERO | GFP_ATOMIC) +#else +#define GFP_DPA_BP (GFP_DMA | GFP_ATOMIC) +#endif + +#define DPA_BP_HEAD (DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE + \ + DPA_HASH_RESULTS_SIZE) +#define DPA_BP_SIZE(s) (DPA_BP_HEAD + (s)) + +#define DPAA_ETH_MAX_PAD (L1_CACHE_BYTES * 8) + +#define FM_FD_STAT_ERRORS \ + (FM_PORT_FRM_ERR_DMA | FM_PORT_FRM_ERR_PHYSICAL | \ + FM_PORT_FRM_ERR_SIZE | FM_PORT_FRM_ERR_CLS_DISCARD | \ + FM_PORT_FRM_ERR_EXTRACTION | FM_PORT_FRM_ERR_NO_SCHEME | \ + FM_PORT_FRM_ERR_ILL_PLCR | FM_PORT_FRM_ERR_PRS_TIMEOUT | \ + FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | FM_PORT_FRM_ERR_PRS_HDR_ERR) + +static struct dpa_bp *dpa_bp_array[64]; + +static struct dpa_bp *default_pool; + +static struct dpa_bp *dpa_bpid2pool(int bpid) +{ + return dpa_bp_array[bpid]; +} + +static void dpa_bp_depletion(struct bman_portal *portal, + struct bman_pool *pool, void *cb_ctx, int depleted) +{ + if (net_ratelimit()) + pr_err("Invalid Pool depleted notification!\n"); +} + +static void bmb_free(struct dpa_bp *bp, struct bm_buffer *bmb) +{ + int i; + struct sk_buff **skbh; + struct sk_buff *skb; + + for (i = 0; i < 8; i++) { + dma_addr_t addr = bm_buf_addr(&bmb[i]); + if (!addr) + break; + + skbh = (struct sk_buff **)phys_to_virt(addr); + skb = *skbh; + + dma_unmap_single(bp->dev, addr, bp->size, DMA_FROM_DEVICE); + + dev_kfree_skb(skb); + } +} + +static void dpa_bp_add_8(struct dpa_bp *dpa_bp) +{ + struct bm_buffer bmb[8]; + struct sk_buff **skbh; + dma_addr_t addr; + int i; + struct sk_buff *skb; + int err; + int *count_ptr; + + count_ptr = per_cpu_ptr(dpa_bp->percpu_count, smp_processor_id()); + + for (i = 0; i < 8; i++) { + /* + * The buffers tend to be aligned all to the same cache + * index. A standard dequeue operation pulls in 15 packets. + * This means that when it stashes, it evicts half of the + * packets it's stashing. In order to prevent that, we pad + * by a variable number of cache lines, to reduce collisions. + * We always pad by at least 1 cache line, because we want + * a little extra room at the beginning for IPSec and to + * accommodate NET_IP_ALIGN. + */ + int pad = (i + 1) * L1_CACHE_BYTES; + + skb = dev_alloc_skb(dpa_bp->size + pad); + if (unlikely(!skb)) { + printk(KERN_ERR "dev_alloc_skb() failed for %d bytes\n", dpa_bp->size + pad); + bm_buffer_set64(&bmb[i], 0); + break; + } + + skbh = (struct sk_buff **)(skb->head + pad); + *skbh = skb; + + addr = dma_map_single(dpa_bp->dev, skb->head + pad, + dpa_bp->size, DMA_FROM_DEVICE); + + bm_buffer_set64(&bmb[i], addr); + } + + /* Avoid releasing a completely null buffer; bman_release() requires + * at least one buf. */ + if (likely(i)) { + err = bman_release(dpa_bp->pool, bmb, i, 0); + + if (unlikely(err < 0)) + bmb_free(dpa_bp, bmb); + else + *count_ptr += i; + } +} + +static void dpa_make_private_pool(struct dpa_bp *dpa_bp) +{ + int i; + + dpa_bp->percpu_count = __alloc_percpu(sizeof(*dpa_bp->percpu_count), + __alignof__(*dpa_bp->percpu_count)); + + /* Give each cpu an allotment of "count" buffers */ + for_each_online_cpu(i) { + int *thiscount; + int *countptr; + int j; + thiscount = per_cpu_ptr(dpa_bp->percpu_count, + smp_processor_id()); + countptr = per_cpu_ptr(dpa_bp->percpu_count, i); + + for (j = 0; j < dpa_bp->count; j += 8) + dpa_bp_add_8(dpa_bp); + + /* Adjust the counts */ + *countptr = j; + + if (countptr != thiscount) + *thiscount = *thiscount - j; + } +} + + +static void dpaa_eth_seed_pool(struct dpa_bp *bp) +{ + size_t count = bp->count; + size_t addr = bp->paddr; + + while (count) { + struct bm_buffer bufs[8]; + int num_bufs = 0; + + do { + BUG_ON(addr > 0xffffffffffffull); + bufs[num_bufs].bpid = bp->bpid; + bm_buffer_set64(&bufs[num_bufs++], addr); + addr += bp->size; + + } while (--count && (num_bufs < 8)); + + while (bman_release(bp->pool, bufs, num_bufs, 0)) + cpu_relax(); + } +} + +static int dpa_make_shared_pool(struct dpa_bp *bp) +{ + devm_request_mem_region(bp->dev, bp->paddr, bp->size * bp->count, + KBUILD_MODNAME); + bp->vaddr = devm_ioremap_prot(bp->dev, bp->paddr, + bp->size * bp->count, 0); + if (bp->vaddr == NULL) { + cpu_pr_err("Could not map memory for pool %d\n", bp->bpid); + return -EIO; + } + + if (bp->seed_pool) + dpaa_eth_seed_pool(bp); + + return 0; +} + +static int __must_check __attribute__((nonnull)) +dpa_bp_alloc(struct dpa_bp *dpa_bp) +{ + int err = 0; + struct bman_pool_params bp_params; + struct platform_device *pdev; + + BUG_ON(dpa_bp->size == 0); + BUG_ON(dpa_bp->count == 0); + + bp_params.flags = BMAN_POOL_FLAG_DEPLETION; + bp_params.cb = dpa_bp_depletion; + bp_params.cb_ctx = dpa_bp; + + /* We support two options. Either a global shared pool, or + * a specified pool. If the pool is specified, we only + * create one per bpid */ + if (dpa_bp->kernel_pool && default_pool) { + atomic_inc(&default_pool->refs); + return 0; + } + + if (dpa_bp_array[dpa_bp->bpid]) { + atomic_inc(&dpa_bp_array[dpa_bp->bpid]->refs); + return 0; + } + + if (dpa_bp->bpid == 0) + bp_params.flags |= BMAN_POOL_FLAG_DYNAMIC_BPID; + else + bp_params.bpid = dpa_bp->bpid; + + dpa_bp->pool = bman_new_pool(&bp_params); + if (unlikely(dpa_bp->pool == NULL)) { + cpu_pr_err("bman_new_pool() failed\n"); + return -ENODEV; + } + + dpa_bp->bpid = bman_get_params(dpa_bp->pool)->bpid; + + pdev = platform_device_register_simple("dpaa_eth_bpool", + dpa_bp->bpid, NULL, 0); + if (IS_ERR(pdev)) { + err = PTR_ERR(pdev); + goto pdev_register_failed; + } + + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(40))) + goto pdev_mask_failed; + + dpa_bp->dev = &pdev->dev; + + if (dpa_bp->kernel_pool) { + dpa_make_private_pool(dpa_bp); + if (!default_pool) + default_pool = dpa_bp; + } else { + err = dpa_make_shared_pool(dpa_bp); + if (err) + goto make_shared_pool_failed; + } + + dpa_bp_array[dpa_bp->bpid] = dpa_bp; + + atomic_set(&dpa_bp->refs, 1); + + return 0; + +make_shared_pool_failed: +pdev_mask_failed: + platform_device_unregister(pdev); +pdev_register_failed: + bman_free_pool(dpa_bp->pool); + + return err; +} + +static void __cold __attribute__((nonnull)) +_dpa_bp_free(struct dpa_bp *dpa_bp) +{ + struct dpa_bp *bp = dpa_bpid2pool(dpa_bp->bpid); + + if (!atomic_dec_and_test(&bp->refs)) + return; + + if (bp->kernel_pool) { + int num; + + do { + struct bm_buffer bmb[8]; + int i; + + num = bman_acquire(bp->pool, bmb, 8, 0); + + for (i = 0; i < num; i++) { + dma_addr_t addr = bm_buf_addr(&bmb[i]); + struct sk_buff **skbh = phys_to_virt(addr); + struct sk_buff *skb = *skbh; + + dma_unmap_single(bp->dev, addr, bp->size, + DMA_FROM_DEVICE); + + dev_kfree_skb_any(skb); + } + } while (num == 8); + } + + dpa_bp_array[bp->bpid] = 0; + bman_free_pool(bp->pool); +} + +static void __cold __attribute__((nonnull)) +dpa_bp_free(struct dpa_priv_s *priv, struct dpa_bp *dpa_bp) +{ + int i; + + for (i = 0; i < priv->bp_count; i++) + _dpa_bp_free(&priv->dpa_bp[i]); +} + +/* QM */ + +static int __must_check __attribute__((nonnull)) +_dpa_fq_alloc(struct list_head *list, struct dpa_fq *dpa_fq) +{ + int _errno; + const struct dpa_priv_s *priv; + struct device *dev; + struct qman_fq *fq; + struct qm_mcc_initfq initfq; + /* Set the QMan taildrop threshold high enough to accomodate + * one 64k frame, plus an extra (here, 16k) for + * other frames awaiting Tx. */ + const u32 qman_taildrop_threshold = 0x14000; + + priv = netdev_priv(dpa_fq->net_dev); + dev = dpa_fq->net_dev->dev.parent; + + if (dpa_fq->fqid == 0) + dpa_fq->flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; + + dpa_fq->init = !(dpa_fq->flags & QMAN_FQ_FLAG_NO_MODIFY); + + _errno = qman_create_fq(dpa_fq->fqid, dpa_fq->flags, &dpa_fq->fq_base); + if (_errno) { + dpaa_eth_err(dev, "qman_create_fq() failed\n"); + return _errno; + } + fq = &dpa_fq->fq_base; + + if (dpa_fq->init) { + initfq.we_mask = QM_INITFQ_WE_DESTWQ; + initfq.fqd.dest.channel = dpa_fq->channel; + initfq.fqd.dest.wq = dpa_fq->wq; + initfq.we_mask |= QM_INITFQ_WE_TDTHRESH | QM_INITFQ_WE_FQCTRL; + qm_fqd_taildrop_set(&initfq.fqd.td, qman_taildrop_threshold, 1); + initfq.fqd.fq_ctrl = QM_FQCTRL_TDE | QM_FQCTRL_PREFERINCACHE; + if (dpa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) { + initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; + initfq.fqd.fq_ctrl |= + QM_FQCTRL_CTXASTASHING | QM_FQCTRL_AVOIDBLOCK; + initfq.fqd.context_a.stashing.exclusive = + QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX | + QM_STASHING_EXCL_ANNOTATION; + initfq.fqd.context_a.stashing.data_cl = 2; + initfq.fqd.context_a.stashing.annotation_cl = 1; + initfq.fqd.context_a.stashing.context_cl = + DIV_ROUND_UP(sizeof(struct qman_fq), 64); + }; + + _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq); + if (_errno < 0) { + dpaa_eth_err(dev, "qman_init_fq(%u) = %d\n", + qman_fq_fqid(fq), _errno); + qman_destroy_fq(fq, 0); + return _errno; + } + } + + dpa_fq->fqid = qman_fq_fqid(fq); + list_add_tail(&dpa_fq->list, list); + + return 0; +} + +static int __cold __attribute__((nonnull)) +_dpa_fq_free(struct device *dev, struct qman_fq *fq) +{ + int _errno, __errno; + struct dpa_fq *dpa_fq; + const struct dpa_priv_s *priv; + + _errno = 0; + + dpa_fq = container_of(fq, struct dpa_fq, fq_base); + priv = netdev_priv(dpa_fq->net_dev); + + if (dpa_fq->init) { + _errno = qman_retire_fq(fq, NULL); + if (unlikely(_errno < 0) && netif_msg_drv(priv)) + dpaa_eth_err(dev, "qman_retire_fq(%u) = %d\n", + qman_fq_fqid(fq), _errno); + + __errno = qman_oos_fq(fq); + if (unlikely(__errno < 0) && netif_msg_drv(priv)) { + dpaa_eth_err(dev, "qman_oos_fq(%u) = %d\n", + qman_fq_fqid(fq), __errno); + if (_errno >= 0) + _errno = __errno; + } + } + + qman_destroy_fq(fq, 0); + list_del(&dpa_fq->list); + + return _errno; +} + +static int __cold __attribute__((nonnull)) +dpa_fq_free(struct device *dev, struct list_head *list) +{ + int _errno, __errno; + struct dpa_fq *dpa_fq, *tmp; + + _errno = 0; + list_for_each_entry_safe(dpa_fq, tmp, list, list) { + __errno = _dpa_fq_free(dev, (struct qman_fq *)dpa_fq); + if (unlikely(__errno < 0) && _errno >= 0) + _errno = __errno; + } + + return _errno; +} + + +static inline ssize_t __const __must_check __attribute__((nonnull)) +dpa_fd_length(const struct qm_fd *fd) +{ + return fd->length20; +} + +static inline ssize_t __const __must_check __attribute__((nonnull)) +dpa_fd_offset(const struct qm_fd *fd) +{ + return fd->offset; +} + +static int __must_check __attribute__((nonnull)) +dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd) +{ + int _errno, __errno, i, j; + const struct dpa_priv_s *priv; + const struct qm_sg_entry *sgt; + struct dpa_bp *_dpa_bp, *dpa_bp; + struct bm_buffer _bmb, bmb[8]; + + priv = netdev_priv(net_dev); + + _bmb.hi = fd->addr_hi; + _bmb.lo = fd->addr_lo; + + _dpa_bp = dpa_bpid2pool(fd->bpid); + BUG_ON(IS_ERR(_dpa_bp)); + + _errno = 0; + if (fd->format == qm_fd_sg) { + sgt = (phys_to_virt(bm_buf_addr(&_bmb)) + dpa_fd_offset(fd)); + + i = 0; + do { + dpa_bp = dpa_bpid2pool(sgt[i].bpid); + BUG_ON(IS_ERR(dpa_bp)); + + j = 0; + do { + BUG_ON(sgt[i].extension); + + bmb[j].hi = sgt[i].addr_hi; + bmb[j].lo = sgt[i].addr_lo; + j++; i++; + } while (j < ARRAY_SIZE(bmb) && + !sgt[i-1].final && + sgt[i-1].bpid == sgt[i].bpid); + + __errno = bman_release(dpa_bp->pool, bmb, j, 0); + if (unlikely(__errno < 0)) { + if (netif_msg_drv(priv) && net_ratelimit()) + cpu_netdev_err(net_dev, + "bman_release(%hu) = %d\n", + dpa_bp->bpid, _errno); + if (_errno >= 0) + _errno = __errno; + } + } while (!sgt[i-1].final); + } + + __errno = bman_release(_dpa_bp->pool, &_bmb, 1, 0); + if (unlikely(__errno < 0)) { + if (netif_msg_drv(priv) && net_ratelimit()) + cpu_netdev_err(net_dev, "bman_release(%hu) = %d\n", + _dpa_bp->bpid, __errno); + if (_errno >= 0) + _errno = __errno; + } + + return _errno; +} + +/* net_device */ + +#define NN_ALLOCATED_SPACE(net_dev) \ + max((size_t)arp_hdr_len(net_dev), sizeof(struct iphdr)) +#define NN_RESERVED_SPACE(net_dev) \ + min((size_t)arp_hdr_len(net_dev), sizeof(struct iphdr)) + +#define TT_ALLOCATED_SPACE(net_dev) \ + max(sizeof(struct icmphdr), max(sizeof(struct udphdr), \ + sizeof(struct tcphdr))) +#define TT_RESERVED_SPACE(net_dev) \ + min(sizeof(struct icmphdr), min(sizeof(struct udphdr), \ + sizeof(struct tcphdr))) + +static struct net_device_stats * __cold +dpa_get_stats(struct net_device *net_dev) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + unsigned long *netstats; + unsigned long *cpustats; + int i, j; + struct dpa_percpu_priv_s *percpu_priv; + int numstats = sizeof(net_dev->stats) / sizeof(unsigned long); + + netstats = (unsigned long *)&net_dev->stats; + + memset(netstats, 0, sizeof(net_dev->stats)); + + for_each_online_cpu(i) { + percpu_priv = per_cpu_ptr(priv->percpu_priv, i); + + cpustats = (unsigned long *)&percpu_priv->stats; + + for (j = 0; j < numstats; j++) + netstats[j] += cpustats[j]; + } + + return &net_dev->stats; +} + +static int dpa_change_mtu(struct net_device *net_dev, int new_mtu) +{ + const struct dpa_priv_s *priv; + const int max_mtu = fsl_fman_phy_maxfrm - (VLAN_ETH_HLEN + ETH_FCS_LEN); + const int min_mtu = 64; + + priv = netdev_priv(net_dev); + + /* Make sure we don't exceed the Ethernet controller's MAXFRM */ + if (new_mtu < min_mtu || new_mtu > max_mtu) { + cpu_netdev_err(net_dev, "Invalid L3 mtu %d " + "(must be between %d and %d).\n", + new_mtu, min_mtu, max_mtu); + return -EINVAL; + } + net_dev->mtu = new_mtu; + + return 0; +} + +static int dpa_set_mac_address(struct net_device *net_dev, void *addr) +{ + const struct dpa_priv_s *priv; + int _errno; + + priv = netdev_priv(net_dev); + + _errno = eth_mac_addr(net_dev, addr); + if (_errno < 0) { + if (netif_msg_drv(priv)) + cpu_netdev_err(net_dev, + "eth_mac_addr() = %d\n", + _errno); + return _errno; + } + + if (!priv->mac_dev) + /* MAC-less interface, so nothing more to do here */ + return 0; + + _errno = priv->mac_dev->change_addr(priv->mac_dev, net_dev->dev_addr); + if (_errno < 0) { + if (netif_msg_drv(priv)) + cpu_netdev_err(net_dev, + "mac_dev->change_addr() = %d\n", + _errno); + return _errno; + } + + return 0; +} + +static void __cold dpa_change_rx_flags(struct net_device *net_dev, int flags) +{ + int _errno; + const struct dpa_priv_s *priv; + + priv = netdev_priv(net_dev); + + if (!priv->mac_dev) + return; + + if ((flags & IFF_PROMISC) != 0) { + _errno = priv->mac_dev->change_promisc(priv->mac_dev); + if (unlikely(_errno < 0) && netif_msg_drv(priv)) + cpu_netdev_err(net_dev, + "mac_dev->change_promisc() = %d\n", + _errno); + } +} + +static void dpa_set_multicast_list(struct net_device *net_dev) +{ + int _errno; + struct dpa_priv_s *priv; + + priv = netdev_priv(net_dev); + + if (!priv->mac_dev) { + if (netif_msg_drv(priv)) + cpu_netdev_warn(net_dev, + "%s() called on MAC-less interface\n", + __func__); + return; + } + + _errno = priv->mac_dev->set_multi(net_dev); + if ((_errno < 0) && netif_msg_drv(priv)) + cpu_netdev_err(net_dev, "mac_dev->set_multi() = %d\n", _errno); +} + +static int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct dpa_priv_s *priv = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + +#ifdef CONFIG_FSL_DPA_1588 + if ((cmd >= PTP_ENBL_TXTS_IOCTL) && (cmd <= PTP_CLEANUP_TS)) { + int ret = -ENODEV; + + if (priv->tsu && priv->tsu->valid) + ret = dpa_ioctl_1588(dev, rq, cmd); + + return ret; + } +#endif + + return phy_mii_ioctl(priv->mac_dev->phy_dev, rq, cmd); +} + +/* + * When we put the buffer into the pool, we purposefully added + * some padding to the address so that the buffers wouldn't all + * be page-aligned. But the skb has been reset to a default state, + * so it is pointing up to DPAA_ETH_MAX_PAD - L1_CACHE_BYTES bytes + * before the actual data. We subtract skb->head from the fd addr, + * and then mask off the translated part to get the actual distance. + */ +static int dpa_process_one(struct dpa_percpu_priv_s *percpu_priv, + struct sk_buff *skb, struct dpa_bp *bp, const struct qm_fd *fd) +{ + dma_addr_t addr = qm_fd_addr(fd); + u32 addrlo = lower_32_bits(addr); + u32 skblo = lower_32_bits((unsigned long)skb->head); + u32 pad = (addrlo - skblo) & (PAGE_SIZE - 1); + unsigned int data_start; + + (*percpu_priv->dpa_bp_count)--; + + /* + * The skb is currently pointed at head + NET_SKB_PAD. The packet + * starts at skb->head + pad + fd offset. + */ + data_start = pad + dpa_fd_offset(fd) - NET_SKB_PAD; + skb_put(skb, dpa_fd_length(fd) + data_start); + skb_pull(skb, data_start); + + return 0; +} + +static void _dpa_rx_error(struct net_device *net_dev, + const struct dpa_priv_s *priv, + struct dpa_percpu_priv_s *percpu_priv, + const struct qm_fd *fd) +{ + int _errno; + + if (netif_msg_hw(priv) && net_ratelimit()) + cpu_netdev_warn(net_dev, "FD status = 0x%08x\n", + fd->status & FM_FD_STAT_ERRORS); + + percpu_priv->stats.rx_errors++; + + _errno = dpa_fd_release(net_dev, fd); + if (unlikely(_errno < 0)) { + dump_stack(); + panic("Can't release buffer to the BM during RX\n"); + } +} + +static void _dpa_tx_error(struct net_device *net_dev, + const struct dpa_priv_s *priv, + struct dpa_percpu_priv_s *percpu_priv, + const struct qm_fd *fd) +{ + struct sk_buff *skb; + struct sk_buff **skbh; + dma_addr_t addr = qm_fd_addr(fd); + struct dpa_bp *bp = priv->dpa_bp; + + if (netif_msg_hw(priv) && net_ratelimit()) + cpu_netdev_warn(net_dev, "FD status = 0x%08x\n", + fd->status & FM_FD_STAT_ERRORS); + + percpu_priv->stats.tx_errors++; + + skbh = (struct sk_buff **)phys_to_virt(addr); + skb = *skbh; + + dma_unmap_single(bp->dev, addr, bp->size, DMA_TO_DEVICE); + + dev_kfree_skb(skb); +} + +static void __hot _dpa_rx(struct net_device *net_dev, + const struct dpa_priv_s *priv, + struct dpa_percpu_priv_s *percpu_priv, + const struct qm_fd *fd) +{ + int _errno; + struct dpa_bp *dpa_bp; + struct sk_buff *skb; + struct sk_buff **skbh; + dma_addr_t addr = qm_fd_addr(fd); + + skbh = (struct sk_buff **)phys_to_virt(addr); + + if (unlikely(fd->status & FM_FD_STAT_ERRORS) != 0) { + if (netif_msg_hw(priv) && net_ratelimit()) + cpu_netdev_warn(net_dev, "FD status = 0x%08x\n", + fd->status & FM_FD_STAT_ERRORS); + + percpu_priv->stats.rx_errors++; + + goto _return_dpa_fd_release; + } + + if (unlikely(fd->format != qm_fd_contig)) { + percpu_priv->stats.rx_dropped++; + if (netif_msg_rx_status(priv) && net_ratelimit()) + cpu_netdev_warn(net_dev, "Dropping a SG frame\n"); + goto _return_dpa_fd_release; + } + + dpa_bp = dpa_bpid2pool(fd->bpid); + + dma_unmap_single(dpa_bp->dev, qm_fd_addr(fd), dpa_bp->size, + DMA_FROM_DEVICE); + + skb = *skbh; + prefetch(skb); + + /* Fill the SKB */ + dpa_process_one(percpu_priv, skb, dpa_bp, fd); + + prefetch(skb_shinfo(skb)); + +#ifdef CONFIG_FSL_DPA_1588 + if (priv->tsu && priv->tsu->valid) + dpa_ptp_store_rxstamp(net_dev, skb, fd); +#endif + + skb->protocol = eth_type_trans(skb, net_dev); + + if (unlikely(skb->len > net_dev->mtu)) { + if ((skb->protocol != ETH_P_8021Q) || + (skb->len > net_dev->mtu + 4)) { + percpu_priv->stats.rx_dropped++; + goto drop_large_frame; + } + } + + /* Check if the FMan Parser has already validated the L4 csum. */ + if (fd->status & FM_FD_STAT_L4CV) { + /* If we're here, the csum must be valid (if it hadn't, + * the frame would have been received on the Error FQ, + * respectively on the _dpa_rx_error() path). */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + skb->ip_summed = CHECKSUM_NONE; + + if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) + percpu_priv->stats.rx_dropped++; + else { + percpu_priv->stats.rx_packets++; + percpu_priv->stats.rx_bytes += dpa_fd_length(fd); + } + + net_dev->last_rx = jiffies; + + return; + +drop_large_frame: + (*percpu_priv->dpa_bp_count)++; +_return_dpa_fd_release: + _errno = dpa_fd_release(net_dev, fd); + if (unlikely(_errno < 0)) { + dump_stack(); + panic("Can't release buffer to the BM during RX\n"); + } +} + +static void dpaa_eth_napi_disable(struct dpa_priv_s *priv) +{ + struct dpa_percpu_priv_s *percpu_priv; + int i; + + if (priv->shared) + return; + + for_each_online_cpu(i) { + percpu_priv = per_cpu_ptr(priv->percpu_priv, i); + napi_disable(&percpu_priv->napi); + } +} + +static void dpaa_eth_napi_enable(struct dpa_priv_s *priv) +{ + struct dpa_percpu_priv_s *percpu_priv; + int i; + + if (priv->shared) + return; + + for_each_online_cpu(i) { + percpu_priv = per_cpu_ptr(priv->percpu_priv, i); + napi_enable(&percpu_priv->napi); + } +} + +static int dpaa_eth_poll(struct napi_struct *napi, int budget) +{ + struct dpa_percpu_priv_s *percpu_priv; + int cleaned = qman_poll_dqrr(budget); + int count; + + percpu_priv = container_of(napi, struct dpa_percpu_priv_s, napi); + + count = *percpu_priv->dpa_bp_count; + + if (count < DEFAULT_COUNT / 4) { + int i; + + for (i = count; i < DEFAULT_COUNT; i += 8) + dpa_bp_add_8(percpu_priv->dpa_bp); + } + + if (cleaned < budget) { + int tmp; + napi_complete(napi); + tmp = qman_irqsource_add(QM_PIRQ_DQRI); + BUG_ON(tmp); + } + + return cleaned; +} + +static void __hot _dpa_tx(struct net_device *net_dev, + const struct dpa_priv_s *priv, + struct dpa_percpu_priv_s *percpu_priv, + const struct qm_fd *fd) +{ + struct sk_buff **skbh; + struct sk_buff *skb; + dma_addr_t addr = qm_fd_addr(fd); + struct dpa_bp *bp = priv->dpa_bp; + + /* This might not perfectly reflect the reality, if the core dequeueing + * the Tx confirmation is different from the one that did the enqueue, + * but at least it'll show up in the total count. */ + percpu_priv->tx_confirm++; + + if (unlikely(fd->status & FM_FD_STAT_ERRORS) != 0) { + if (netif_msg_hw(priv) && net_ratelimit()) + cpu_netdev_warn(net_dev, "FD status = 0x%08x\n", + fd->status & FM_FD_STAT_ERRORS); + + percpu_priv->stats.tx_errors++; + } + + skbh = (struct sk_buff **)phys_to_virt(addr); + skb = *skbh; + +#ifdef CONFIG_FSL_DPA_1588 + if (priv->tsu && priv->tsu->valid) + dpa_ptp_store_txstamp(net_dev, skb, fd); +#endif + + dma_unmap_single(bp->dev, addr, bp->size, DMA_TO_DEVICE); + + dev_kfree_skb(skb); +} + +static struct dpa_bp *dpa_size2pool(struct dpa_priv_s *priv, size_t size) +{ + int i; + + for (i = 0; i < priv->bp_count; i++) + if (DPA_BP_SIZE(size) <= priv->dpa_bp[i].size) + return dpa_bpid2pool(priv->dpa_bp[i].bpid); + return ERR_PTR(-ENODEV); +} + +static inline void * __must_check __attribute__((nonnull)) +dpa_phys2virt(const struct dpa_bp *dpa_bp, dma_addr_t addr) +{ + return dpa_bp->vaddr + (addr - dpa_bp->paddr); +} + +/** + * Turn on HW checksum computation for this outgoing frame. + * If the current protocol is not something we support in this regard + * (or if the stack has already computed the SW checksum), we do nothing. + * + * Returns 0 if all goes well (or HW csum doesn't apply), and a negative value + * otherwise. + * + * Note that this function may modify the fd->cmd field and the skb data buffer + * (the Parse Results area). + */ +static inline int dpa_enable_tx_csum(struct dpa_priv_s *priv, + struct sk_buff *skb, struct qm_fd *fd, char *parse_results) +{ + t_FmPrsResult *parse_result; + struct iphdr *iph; + struct ipv6hdr *ipv6h = NULL; + int l4_proto; + int ethertype = ntohs(skb->protocol); + int retval = 0; + + if (!priv->mac_dev || skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + /* Note: L3 csum seems to be already computed in sw, but we can't choose + * L4 alone from the FM configuration anyway. */ + + /* Fill in some fields of the Parse Results array, so the FMan + * can find them as if they came from the FMan Parser. */ + parse_result = (t_FmPrsResult *)parse_results; + + /* If we're dealing with VLAN, get the real Ethernet type */ + if (ethertype == ETH_P_8021Q) { + /* We can't always assume the MAC header is set correctly + * by the stack, so reset to beginning of skb->data */ + skb_reset_mac_header(skb); + ethertype = ntohs(vlan_eth_hdr(skb)->h_vlan_encapsulated_proto); + } + + /* Fill in the relevant L3 parse result fields + * and read the L4 protocol type */ + switch (ethertype) { + case ETH_P_IP: + parse_result->l3r = FM_L3_PARSE_RESULT_IPV4; + iph = ip_hdr(skb); + BUG_ON(iph == NULL); + l4_proto = ntohs(iph->protocol); + break; + case ETH_P_IPV6: + parse_result->l3r = FM_L3_PARSE_RESULT_IPV6; + ipv6h = ipv6_hdr(skb); + BUG_ON(ipv6h == NULL); + l4_proto = ntohs(ipv6h->nexthdr); + break; + default: + /* We shouldn't even be here */ + if (netif_msg_tx_err(priv) && net_ratelimit()) + cpu_netdev_alert(priv->net_dev, "Can't compute HW csum " + "for L3 proto 0x%x\n", ntohs(skb->protocol)); + retval = -EIO; + goto return_error; + } + + /* Fill in the relevant L4 parse result fields */ + switch (l4_proto) { + case IPPROTO_UDP: + parse_result->l4r = FM_L4_PARSE_RESULT_UDP; + break; + case IPPROTO_TCP: + parse_result->l4r = FM_L4_PARSE_RESULT_TCP; + break; + default: + /* This can as well be a BUG() */ + if (netif_msg_tx_err(priv) && net_ratelimit()) + cpu_netdev_alert(priv->net_dev, "Can't compute HW csum " + "for L4 proto 0x%x\n", l4_proto); + retval = -EIO; + goto return_error; + } + + /* At index 0 is IPOffset_1 as defined in the Parse Results */ + parse_result->ip_off[0] = skb_network_offset(skb); + parse_result->l4_off = skb_transport_offset(skb); + + /* Enable L3 (and L4, if TCP or UDP) HW checksum. */ + fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC; + +return_error: + return retval; +} + +static inline int __hot dpa_xmit(struct dpa_priv_s *priv, + struct dpa_percpu_priv_s *percpu, int queue, + struct qm_fd *fd) +{ + int err; + + prefetchw(&percpu->start_tx); + err = qman_enqueue(priv->egress_fqs[queue], fd, 0); + if (unlikely(err < 0)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + cpu_netdev_err(priv->net_dev, "qman_enqueue() = %d\n", + err); + percpu->stats.tx_errors++; + percpu->stats.tx_fifo_errors++; + return err; + } + + percpu->stats.tx_packets++; + percpu->stats.tx_bytes += dpa_fd_length(fd); + + return NETDEV_TX_OK; +} + +static int __hot dpa_shared_tx(struct sk_buff *skb, struct net_device *net_dev) +{ + struct dpa_bp *dpa_bp; + struct bm_buffer bmb; + struct dpa_percpu_priv_s *percpu_priv; + struct dpa_priv_s *priv; + struct device *dev; + struct qm_fd fd; + int queue_mapping; + int err; + void *dpa_bp_vaddr; + + priv = netdev_priv(net_dev); + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + dev = net_dev->dev.parent; + + memset(&fd, 0, sizeof(fd)); + fd.format = qm_fd_contig; + + queue_mapping = skb_get_queue_mapping(skb); + + dpa_bp = dpa_size2pool(priv, skb_headlen(skb)); + if (unlikely(IS_ERR(dpa_bp))) { + err = PTR_ERR(dpa_bp); + goto bpools_too_small_error; + } + + err = bman_acquire(dpa_bp->pool, &bmb, 1, 0); + if (unlikely(err <= 0)) { + percpu_priv->stats.tx_errors++; + if (err == 0) + err = -ENOMEM; + goto buf_acquire_failed; + } + fd.bpid = dpa_bp->bpid; + + fd.length20 = skb_headlen(skb); + fd.cmd = FM_FD_CMD_FCO; + fd.addr_hi = bmb.hi; + fd.addr_lo = bmb.lo; + fd.offset = DPA_BP_HEAD; + + dpa_bp_vaddr = dpa_phys2virt(dpa_bp, bm_buf_addr(&bmb)); + + /* Copy the packet payload */ + skb_copy_from_linear_data(skb, dpa_bp_vaddr + dpa_fd_offset(&fd), + dpa_fd_length(&fd)); + + /* Enable L3/L4 hardware checksum computation, if applicable */ + err = dpa_enable_tx_csum(priv, skb, &fd, + dpa_bp_vaddr + DPA_PRIV_DATA_SIZE); + if (unlikely(err < 0)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + cpu_netdev_err(net_dev, "Tx HW csum error: %d\n", err); + percpu_priv->stats.tx_errors++; + goto l3_l4_csum_failed; + } + + err = dpa_xmit(priv, percpu_priv, queue_mapping, &fd); + +l3_l4_csum_failed: +bpools_too_small_error: +buf_acquire_failed: + /* We're done with the skb */ + dev_kfree_skb(skb); + + return err; +} + +static int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev) +{ + struct dpa_priv_s *priv; + struct device *dev; + struct qm_fd fd; + unsigned int headroom; + struct dpa_percpu_priv_s *percpu_priv; + struct sk_buff **skbh; + dma_addr_t addr; + struct dpa_bp *dpa_bp; + int queue_mapping; + int err; + unsigned int pad; + + priv = netdev_priv(net_dev); + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + dev = net_dev->dev.parent; + + memset(&fd, 0, sizeof(fd)); + fd.format = qm_fd_contig; + + headroom = skb_headroom(skb); + queue_mapping = skb_get_queue_mapping(skb); + + if (headroom < DPA_BP_HEAD) { + struct sk_buff *skb_new; + + skb_new = skb_realloc_headroom(skb, DPA_BP_HEAD); + if (!skb_new) { + percpu_priv->stats.tx_errors++; + kfree_skb(skb); + return NETDEV_TX_OK; + } + kfree_skb(skb); + skb = skb_new; + headroom = skb_headroom(skb); + } + + skb = skb_unshare(skb, GFP_ATOMIC); + + if (!skb) + return NETDEV_TX_OK; + + /* + * We are guaranteed that we have at least DPA_BP_HEAD of headroom. + * Buffers we allocated are padded to improve cache usage. In order + * to increase buffer re-use, we aim to keep any such buffers the + * same. This means the address passed to the FM should be DPA_BP_HEAD + * before the data, and we might as well do the same for buffers + * from elsewhere in the kernel. + */ + skbh = (struct sk_buff **)(skb->data - DPA_BP_HEAD); + pad = headroom - DPA_BP_HEAD; + + *skbh = skb; + + dpa_bp = priv->dpa_bp; + + /* Enable L3/L4 hardware checksum computation. + * + * We must do this before dma_map_single(DMA_TO_DEVICE), because we may + * need to write into the skb. */ + err = dpa_enable_tx_csum(priv, skb, &fd, + ((char *)skbh) + DPA_PRIV_DATA_SIZE); + + if (unlikely(err < 0)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + cpu_netdev_err(net_dev, "HW csum error: %d\n", err); + percpu_priv->stats.tx_errors++; + goto l3_l4_csum_failed; + } + +#ifdef CONFIG_FSL_DPA_1588 + if (priv->tsu && priv->tsu->valid) + fd.cmd |= FM_FD_CMD_UPD; +#endif + + fd.length20 = skb->len; + fd.offset = DPA_BP_HEAD; /* This is now guaranteed */ + + addr = dma_map_single(dpa_bp->dev, skbh, dpa_bp->size, DMA_TO_DEVICE); + if (unlikely(addr == 0)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + cpu_netdev_err(net_dev, "dma_map_single() failed\n"); + goto dma_map_failed; + } + + fd.addr_hi = upper_32_bits(addr); + fd.addr_lo = lower_32_bits(addr); + + if (unlikely(dpa_xmit(priv, percpu_priv, queue_mapping, &fd) < 0)) + goto xmit_failed; + + net_dev->trans_start = jiffies; + + return NETDEV_TX_OK; + +xmit_failed: + dma_unmap_single(dev, addr, dpa_bp->size, DMA_TO_DEVICE); + +dma_map_failed: + if (fd.cmd & FM_FD_CMD_FCO) + (*percpu_priv->dpa_bp_count)--; + +l3_l4_csum_failed: + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static enum qman_cb_dqrr_result +ingress_rx_error_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + struct net_device *net_dev; + struct dpa_priv_s *priv; + struct dpa_percpu_priv_s *percpu_priv; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + if (dpaa_eth_napi_schedule(percpu_priv)) { + percpu_priv->in_interrupt++; + return qman_cb_dqrr_stop; + } + + _dpa_rx_error(net_dev, priv, percpu_priv, &dq->fd); + + return qman_cb_dqrr_consume; +} + +static enum qman_cb_dqrr_result __hot +shared_rx_dqrr(struct qman_portal *portal, struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + struct net_device *net_dev; + struct dpa_priv_s *priv; + struct dpa_percpu_priv_s *percpu_priv; + int err; + const struct qm_fd *fd = &dq->fd; + struct dpa_bp *dpa_bp; + size_t size; + struct sk_buff *skb; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + if (unlikely(fd->status & FM_FD_STAT_ERRORS) != 0) { + if (netif_msg_hw(priv) && net_ratelimit()) + cpu_netdev_warn(net_dev, "FD status = 0x%08x\n", + fd->status & FM_FD_STAT_ERRORS); + + percpu_priv->stats.rx_errors++; + + goto out; + } + + + dpa_bp = dpa_bpid2pool(fd->bpid); + BUG_ON(IS_ERR(dpa_bp)); + + if (fd->format == qm_fd_sg) { + percpu_priv->stats.rx_dropped++; + if (netif_msg_rx_status(priv) && net_ratelimit()) + cpu_netdev_warn(net_dev, + "%s:%hu:%s(): Dropping a SG frame\n", + __file__, __LINE__, __func__); + goto out; + } + + size = dpa_fd_length(fd); + + skb = __netdev_alloc_skb(net_dev, DPA_BP_HEAD + size, GFP_ATOMIC); + if (unlikely(skb == NULL)) { + if (netif_msg_rx_err(priv) && net_ratelimit()) + cpu_netdev_err(net_dev, "Could not alloc skb\n"); + + percpu_priv->stats.rx_dropped++; + + goto out; + } + + skb_reserve(skb, DPA_BP_HEAD); + + /* Fill the SKB */ + memcpy(skb_put(skb, dpa_fd_length(fd)), + dpa_phys2virt(dpa_bp, qm_fd_addr(fd)) + + dpa_fd_offset(fd), dpa_fd_length(fd)); + + skb->protocol = eth_type_trans(skb, net_dev); + + if (unlikely(skb->len > net_dev->mtu)) { + if ((skb->protocol != ETH_P_8021Q) || + (skb->len > net_dev->mtu + 4)) { + percpu_priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + goto out; + } + } + + if (unlikely(netif_rx(skb) != NET_RX_SUCCESS)) + percpu_priv->stats.rx_dropped++; + else { + percpu_priv->stats.rx_packets++; + percpu_priv->stats.rx_bytes += dpa_fd_length(fd); + } + + net_dev->last_rx = jiffies; + +out: + err = dpa_fd_release(net_dev, fd); + if (unlikely(err < 0)) { + dump_stack(); + panic("Can't release buffer to the BM during RX\n"); + } + + return qman_cb_dqrr_consume; +} + + +static enum qman_cb_dqrr_result __hot +ingress_rx_default_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + struct net_device *net_dev; + struct dpa_priv_s *priv; + struct dpa_percpu_priv_s *percpu_priv; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + if (unlikely(dpaa_eth_napi_schedule(percpu_priv))) { + percpu_priv->in_interrupt++; + return qman_cb_dqrr_stop; + } + + prefetchw(&percpu_priv->ingress_calls); + + _dpa_rx(net_dev, priv, percpu_priv, &dq->fd); + + return qman_cb_dqrr_consume; +} + +static enum qman_cb_dqrr_result +ingress_tx_error_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + struct net_device *net_dev; + struct dpa_priv_s *priv; + struct dpa_percpu_priv_s *percpu_priv; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + if (dpaa_eth_napi_schedule(percpu_priv)) { + percpu_priv->in_interrupt++; + return qman_cb_dqrr_stop; + } + + _dpa_tx_error(net_dev, priv, percpu_priv, &dq->fd); + + return qman_cb_dqrr_consume; +} + +static enum qman_cb_dqrr_result __hot +ingress_tx_default_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + struct net_device *net_dev; + struct dpa_priv_s *priv; + struct dpa_percpu_priv_s *percpu_priv; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + if (dpaa_eth_napi_schedule(percpu_priv)) { + percpu_priv->in_interrupt++; + return qman_cb_dqrr_stop; + } + + _dpa_tx(net_dev, priv, percpu_priv, &dq->fd); + + return qman_cb_dqrr_consume; +} + +static void shared_ern(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + struct net_device *net_dev; + const struct dpa_priv_s *priv; + int err; + struct dpa_percpu_priv_s *percpu_priv; + struct dpa_fq *dpa_fq = (struct dpa_fq *)fq; + + net_dev = dpa_fq->net_dev; + priv = netdev_priv(net_dev); + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + err = dpa_fd_release(net_dev, &msg->ern.fd); + if (unlikely(err < 0)) { + dump_stack(); + panic("Can't release buffer to the BM during a TX\n"); + } + + percpu_priv->stats.tx_dropped++; + percpu_priv->stats.tx_fifo_errors++; +} + +static void egress_ern(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + struct net_device *net_dev; + const struct dpa_priv_s *priv; + struct sk_buff *skb; + struct sk_buff **skbh; + struct dpa_percpu_priv_s *percpu_priv; + dma_addr_t addr = qm_fd_addr(&msg->ern.fd); + struct dpa_bp *bp; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + bp = priv->dpa_bp; + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + percpu_priv->stats.tx_dropped++; + percpu_priv->stats.tx_fifo_errors++; + + /* + * If we intended this buffer to go into the pool + * when the FM was done, we need to put it in + * manually. + */ + if (msg->ern.fd.cmd & FM_FD_CMD_FCO) { + struct bm_buffer bmb; + + bm_buffer_set64(&bmb, addr); + while (bman_release(bp->pool, &bmb, 1, 0)) + cpu_relax(); + + return; + } + + skbh = (struct sk_buff **)phys_to_virt(addr); + skb = *skbh; + + dma_unmap_single(bp->dev, addr, bp->size, DMA_TO_DEVICE); + + dev_kfree_skb_any(skb); +} + +static const struct qman_fq rx_shared_fq = { + .cb = {shared_rx_dqrr, NULL, NULL, NULL} +}; +static const struct qman_fq rx_private_defq = { + .cb = {ingress_rx_default_dqrr, NULL, NULL, NULL} +}; +static const struct qman_fq rx_private_errq = { + .cb = {ingress_rx_error_dqrr, NULL, NULL, NULL} +}; +static const struct qman_fq tx_private_defq = { + .cb = {ingress_tx_default_dqrr, NULL, NULL, NULL} +}; +static const struct qman_fq tx_private_errq = { + .cb = {ingress_tx_error_dqrr, NULL, NULL, NULL} +}; +static const struct qman_fq dummyq = { + .cb = {NULL, NULL, NULL, NULL} +}; +static const struct qman_fq private_egress_fq = { + .cb = {NULL, egress_ern, NULL, NULL} +}; +static const struct qman_fq shared_egress_fq = { + .cb = {NULL, shared_ern, NULL, NULL} +}; + +#ifdef CONFIG_DPAA_ETH_UNIT_TESTS +static bool tx_unit_test_passed = true; + +static void tx_unit_test_ern(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + struct net_device *net_dev; + struct dpa_priv_s *priv; + struct sk_buff **skbh; + struct sk_buff *skb; + const struct qm_fd *fd; + dma_addr_t addr; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + + tx_unit_test_passed = false; + + fd = &msg->ern.fd; + + addr = qm_fd_addr(fd); + + skbh = (struct sk_buff **)phys_to_virt(addr); + skb = *skbh; + + if (!skb || !is_kernel_addr((unsigned long)skb)) + panic("Corrupt skb in ERN!\n"); + + kfree_skb(skb); +} + +static unsigned char *tx_unit_skb_head; +static unsigned char *tx_unit_skb_end; +static int tx_unit_tested; + +static enum qman_cb_dqrr_result tx_unit_test_dqrr( + struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + struct net_device *net_dev; + struct dpa_priv_s *priv; + struct sk_buff **skbh; + struct sk_buff *skb; + const struct qm_fd *fd; + dma_addr_t addr; + unsigned char *startaddr; + struct dpa_percpu_priv_s *percpu_priv; + + tx_unit_test_passed = false; + + tx_unit_tested++; + + net_dev = ((struct dpa_fq *)fq)->net_dev; + priv = netdev_priv(net_dev); + + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + fd = &dq->fd; + + addr = qm_fd_addr(fd); + + skbh = (struct sk_buff **)phys_to_virt(addr); + startaddr = (unsigned char *)skbh; + skb = *skbh; + + if (!skb || !is_kernel_addr((unsigned long)skb)) + panic("Invalid skb address in TX Unit Test FD\n"); + + /* Make sure we're dealing with the same skb */ + if (skb->head != tx_unit_skb_head + || skb_end_pointer(skb) != tx_unit_skb_end) + goto out; + + /* + * If we recycled, then there must be enough room between fd.addr + * and skb->end for a new RX buffer + */ + if (fd->cmd & FM_FD_CMD_FCO) { + size_t bufsize = skb_end_pointer(skb) - startaddr; + + if (bufsize < fsl_fman_phy_maxfrm) + goto out; + } else { + /* + * If we didn't recycle, but the buffer was big enough, + * increment the counter to put it back + */ + if (skb_end_pointer(skb) - skb->head >= fsl_fman_phy_maxfrm) + (*percpu_priv->dpa_bp_count)++; + + /* If we didn't recycle, the data pointer should be good */ + if (skb->data != startaddr + dpa_fd_offset(fd)) + goto out; + } + + tx_unit_test_passed = true; +out: + /* The skb is no longer needed, and belongs to us */ + kfree_skb(skb); + + return qman_cb_dqrr_consume; +} + +static const struct qman_fq tx_unit_test_fq = { + .cb = {tx_unit_test_dqrr, tx_unit_test_ern, NULL, NULL} +}; + +static struct dpa_fq unit_fq; + +static bool tx_unit_test_ran; /* Starts as false */ + +static int dpa_tx_unit_test(struct net_device *net_dev) +{ + /* Create a new FQ */ + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct qman_fq *oldq; + int size, headroom; + struct dpa_percpu_priv_s *percpu_priv; + cpumask_t *oldcpus; + int test_count = 0; + int err = 0; + int tests_failed = 0; + const cpumask_t *cpus = qman_affine_cpus(); + + oldcpus = tsk_cpus_allowed(current); + set_cpus_allowed_ptr(current, cpus); + /* disable bottom halves */ + local_bh_disable(); + + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + qman_irqsource_remove(QM_PIRQ_DQRI); + unit_fq.net_dev = net_dev; + unit_fq.fq_base = tx_unit_test_fq; + + /* Save old queue */ + oldq = priv->egress_fqs[smp_processor_id()]; + + err = qman_create_fq(0, QMAN_FQ_FLAG_DYNAMIC_FQID, &unit_fq.fq_base); + + if (err < 0) { + pr_err("UNIT test FQ create failed: %d\n", err); + goto fq_create_fail; + } + + err = qman_init_fq(&unit_fq.fq_base, + QMAN_INITFQ_FLAG_SCHED | QMAN_INITFQ_FLAG_LOCAL, NULL); + if (err < 0) { + pr_err("UNIT test FQ init failed: %d\n", err); + goto fq_init_fail; + } + + pr_err("TX Unit Test using FQ %d\n", qman_fq_fqid(&unit_fq.fq_base)); + + /* Replace queue 0 with this queue */ + priv->egress_fqs[smp_processor_id()] = &unit_fq.fq_base; + + /* Try packet sizes from 64-bytes to just above the maximum */ + for (size = 64; size <= 9600 + 128; size += 64) { + for (headroom = DPA_BP_HEAD; headroom < 0x800; headroom += 16) { + int ret; + struct sk_buff *skb; + + test_count++; + + skb = dev_alloc_skb(size + headroom); + + if (!skb) { + pr_err("Failed to allocate skb\n"); + err = -ENOMEM; + goto end_test; + } + + if (skb_end_pointer(skb) - skb->head >= + fsl_fman_phy_maxfrm) + (*percpu_priv->dpa_bp_count)--; + + skb_put(skb, size + headroom); + skb_pull(skb, headroom); + + tx_unit_skb_head = skb->head; + tx_unit_skb_end = skb_end_pointer(skb); + + skb_set_queue_mapping(skb, smp_processor_id()); + + /* tx */ + ret = net_dev->netdev_ops->ndo_start_xmit(skb, net_dev); + + if (ret != NETDEV_TX_OK) { + pr_err("Failed to TX with err %d\n", ret); + err = -EIO; + goto end_test; + } + + /* Wait for it to arrive */ + ret = spin_event_timeout(qman_poll_dqrr(1) != 0, + 100000, 1); + + if (!ret) + pr_err("TX Packet never arrived\n"); + + /* Was it good? */ + if (tx_unit_test_passed == false) { + pr_err("Test failed:\n"); + pr_err("size: %d pad: %d head: %p end: %p\n", + size, headroom, tx_unit_skb_head, + tx_unit_skb_end); + tests_failed++; + } + } + } + +end_test: + err = qman_retire_fq(&unit_fq.fq_base, NULL); + if (unlikely(err < 0)) + pr_err("Could not retire TX Unit Test FQ (%d)\n", err); + + err = qman_oos_fq(&unit_fq.fq_base); + if (unlikely(err < 0)) + pr_err("Could not OOS TX Unit Test FQ (%d)\n", err); + +fq_init_fail: + qman_destroy_fq(&unit_fq.fq_base, 0); + +fq_create_fail: + priv->egress_fqs[smp_processor_id()] = oldq; + local_bh_enable(); + qman_irqsource_add(QM_PIRQ_DQRI); + tx_unit_test_ran = true; + set_cpus_allowed_ptr(current, oldcpus); + + pr_err("Tested %d/%d packets. %d failed\n", test_count, tx_unit_tested, + tests_failed); + + if (tests_failed) + err = -EINVAL; + + return err; +} +#endif + +static int __cold dpa_start(struct net_device *net_dev) +{ + int err, i; + struct dpa_priv_s *priv; + struct mac_device *mac_dev; + + priv = netdev_priv(net_dev); + mac_dev = priv->mac_dev; + + if (!mac_dev) + goto no_mac; + +#ifdef CONFIG_FSL_DPA_1588 + if (priv->tsu && priv->tsu->valid) { + if (mac_dev->fm_rtc_enable) + mac_dev->fm_rtc_enable(net_dev); + } +#endif + + dpaa_eth_napi_enable(priv); + + err = mac_dev->init_phy(net_dev); + if (err < 0) { + if (netif_msg_ifup(priv)) + cpu_netdev_err(net_dev, "init_phy() = %d\n", err); + goto init_phy_failed; + } + + for_each_port_device(i, mac_dev->port_dev) + fm_port_enable(mac_dev->port_dev[i]); + + err = priv->mac_dev->start(mac_dev); + if (err < 0) { + if (netif_msg_ifup(priv)) + cpu_netdev_err(net_dev, "mac_dev->start() = %d\n", err); + goto mac_start_failed; + } + +no_mac: + netif_tx_start_all_queues(net_dev); + + return 0; + +mac_start_failed: + for_each_port_device(i, mac_dev->port_dev) + fm_port_disable(mac_dev->port_dev[i]); + +init_phy_failed: + dpaa_eth_napi_disable(priv); + + return err; +} + +static int __cold dpa_stop(struct net_device *net_dev) +{ + int _errno, i; + struct dpa_priv_s *priv; + struct mac_device *mac_dev; + + priv = netdev_priv(net_dev); + mac_dev = priv->mac_dev; + + netif_tx_stop_all_queues(net_dev); + + if (!mac_dev) + return 0; + +#ifdef CONFIG_FSL_DPA_1588 + if (priv->tsu && priv->tsu->valid) { + if (mac_dev->fm_rtc_disable) + mac_dev->fm_rtc_disable(net_dev); + } +#endif + + _errno = mac_dev->stop(mac_dev); + if (unlikely(_errno < 0)) + if (netif_msg_ifdown(priv)) + cpu_netdev_err(net_dev, "mac_dev->stop() = %d\n", + _errno); + + for_each_port_device(i, mac_dev->port_dev) + fm_port_disable(mac_dev->port_dev[i]); + + if (mac_dev->phy_dev) + phy_disconnect(mac_dev->phy_dev); + mac_dev->phy_dev = NULL; + + dpaa_eth_napi_disable(priv); + + return _errno; +} + +static void __cold dpa_timeout(struct net_device *net_dev) +{ + const struct dpa_priv_s *priv; + struct dpa_percpu_priv_s *percpu_priv; + + priv = netdev_priv(net_dev); + percpu_priv = per_cpu_ptr(priv->percpu_priv, smp_processor_id()); + + if (netif_msg_timer(priv)) + cpu_netdev_crit(net_dev, "Transmit timeout latency: %lu ms\n", + (jiffies - net_dev->trans_start) * 1000 / HZ); + + percpu_priv->stats.tx_errors++; +} + +static int dpa_bp_cmp(const void *dpa_bp0, const void *dpa_bp1) +{ + return ((struct dpa_bp *)dpa_bp0)->size - + ((struct dpa_bp *)dpa_bp1)->size; +} + +static struct dpa_bp * __cold __must_check __attribute__((nonnull)) +dpa_bp_probe(struct platform_device *_of_dev, size_t *count) +{ + int i, lenp, na, ns; + struct device *dev; + struct device_node *dev_node; + const phandle *phandle_prop; + const uint32_t *bpid; + const uint32_t *bpool_cfg; + struct dpa_bp *dpa_bp; + int has_kernel_pool = 0; + int has_shared_pool = 0; + + dev = &_of_dev->dev; + + /* The default is one, if there's no property */ + *count = 1; + + /* There are three types of buffer pool configuration: + * 1) No bp assignment + * 2) A static assignment to an empty configuration + * 3) A static assignment to one or more configured pools + * + * We don't support using multiple unconfigured pools. + */ + + /* Get the buffer pools to be used */ + phandle_prop = of_get_property(dev->of_node, + "fsl,bman-buffer-pools", &lenp); + + if (phandle_prop) + *count = lenp / sizeof(phandle); + else { + if (default_pool) + return default_pool; + + has_kernel_pool = 1; + } + + dpa_bp = devm_kzalloc(dev, *count * sizeof(*dpa_bp), GFP_KERNEL); + if (unlikely(dpa_bp == NULL)) { + dpaa_eth_err(dev, "devm_kzalloc() failed\n"); + return ERR_PTR(-ENOMEM); + } + + dev_node = of_find_node_by_path("/"); + if (unlikely(dev_node == NULL)) { + dpaa_eth_err(dev, "of_find_node_by_path(/) failed\n"); + return ERR_PTR(-EINVAL); + } + + na = of_n_addr_cells(dev_node); + ns = of_n_size_cells(dev_node); + + for (i = 0; i < *count && phandle_prop; i++) { + of_node_put(dev_node); + dev_node = of_find_node_by_phandle(phandle_prop[i]); + if (unlikely(dev_node == NULL)) { + dpaa_eth_err(dev, "of_find_node_by_phandle() failed\n"); + return ERR_PTR(-EFAULT); + } + + if (unlikely(!of_device_is_compatible(dev_node, "fsl,bpool"))) { + dpaa_eth_err(dev, + "!of_device_is_compatible(%s, fsl,bpool)\n", + dev_node->full_name); + dpa_bp = ERR_PTR(-EINVAL); + goto _return_of_node_put; + } + + bpid = of_get_property(dev_node, "fsl,bpid", &lenp); + if ((bpid == NULL) || (lenp != sizeof(*bpid))) { + dpaa_eth_err(dev, "fsl,bpid property not found.\n"); + dpa_bp = ERR_PTR(-EINVAL); + goto _return_of_node_put; + } + dpa_bp[i].bpid = *bpid; + + bpool_cfg = of_get_property(dev_node, "fsl,bpool-ethernet-cfg", + &lenp); + if (bpool_cfg && (lenp == (2 * ns + na) * sizeof(*bpool_cfg))) { + const uint32_t *seed_pool; + + dpa_bp[i].count = of_read_number(bpool_cfg, ns); + dpa_bp[i].size = of_read_number(bpool_cfg + ns, ns); + dpa_bp[i].paddr = + of_read_number(bpool_cfg + 2 * ns, na); + + seed_pool = of_get_property(dev_node, + "fsl,bpool-ethernet-seeds", &lenp); + dpa_bp[i].seed_pool = !!seed_pool; + + has_shared_pool = 1; + } else { + has_kernel_pool = 1; + } + + if (i > 0) + has_shared_pool = 1; + } + + if (has_kernel_pool && has_shared_pool) { + dpaa_eth_err(dev, "Invalid buffer pool configuration " + "for node %s\n", dev_node->full_name); + dpa_bp = ERR_PTR(-EINVAL); + goto _return_of_node_put; + } else if (has_kernel_pool) { + dpa_bp->count = DEFAULT_COUNT; + dpa_bp->size = DEFAULT_BUF_SIZE; + dpa_bp->kernel_pool = 1; + } + + sort(dpa_bp, *count, sizeof(*dpa_bp), dpa_bp_cmp, NULL); + + return dpa_bp; + +_return_of_node_put: + if (dev_node) + of_node_put(dev_node); + + return dpa_bp; +} + +static int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp, + size_t count) +{ + struct dpa_priv_s *priv = netdev_priv(net_dev); + int i; + + if (dpa_bp->kernel_pool) { + priv->shared = 0; + + if (netif_msg_probe(priv)) + cpu_dev_info(net_dev->dev.parent, + "Using private BM buffer pools\n"); + } else { + priv->shared = 1; + } + + priv->dpa_bp = dpa_bp; + priv->bp_count = count; + + for (i = 0; i < count; i++) { + int err; + err = dpa_bp_alloc(&dpa_bp[i]); + if (err < 0) { + dpa_bp_free(priv, dpa_bp); + priv->dpa_bp = NULL; + return err; + } + + /* For now, just point to the default pool. + * We can add support for more pools, later + */ + if (dpa_bp->kernel_pool) + priv->dpa_bp = default_pool; + } + + return 0; +} + +static struct mac_device * __cold __must_check +__attribute__((nonnull)) +dpa_mac_probe(struct platform_device *_of_dev) +{ + struct device *dpa_dev, *dev; + struct device_node *mac_node; + int lenp; + const phandle *phandle_prop; + struct platform_device *of_dev; + struct mac_device *mac_dev; +#ifdef CONFIG_FSL_DPA_1588 + struct net_device *net_dev = NULL; + struct dpa_priv_s *priv = NULL; + struct device_node *timer_node; +#endif + + phandle_prop = of_get_property(_of_dev->dev.of_node, "fsl,fman-mac", &lenp); + if (phandle_prop == NULL) + return NULL; + + BUG_ON(lenp != sizeof(phandle)); + + dpa_dev = &_of_dev->dev; + + mac_node = of_find_node_by_phandle(*phandle_prop); + if (unlikely(mac_node == NULL)) { + dpaa_eth_err(dpa_dev, "of_find_node_by_phandle() failed\n"); + return ERR_PTR(-EFAULT); + } + + of_dev = of_find_device_by_node(mac_node); + if (unlikely(of_dev == NULL)) { + dpaa_eth_err(dpa_dev, "of_find_device_by_node(%s) failed\n", + mac_node->full_name); + of_node_put(mac_node); + return ERR_PTR(-EINVAL); + } + of_node_put(mac_node); + + dev = &of_dev->dev; + + mac_dev = dev_get_drvdata(dev); + if (unlikely(mac_dev == NULL)) { + dpaa_eth_err(dpa_dev, "dev_get_drvdata(%s) failed\n", + dev_name(dev)); + return ERR_PTR(-EINVAL); + } + +#ifdef CONFIG_FSL_DPA_1588 + phandle_prop = of_get_property(mac_node, "ptimer-handle", &lenp); + if (phandle_prop && ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) || + ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) && + (mac_dev->speed == SPEED_1000)))) { + timer_node = of_find_node_by_phandle(*phandle_prop); + if (timer_node && (net_dev = dev_get_drvdata(dpa_dev))) { + priv = netdev_priv(net_dev); + if (!dpa_ptp_init(priv)) + dpaa_eth_info(dev, "%s: ptp-timer enabled\n", + mac_node->full_name); + } + } +#endif + + return mac_dev; +} + +static const char fsl_qman_frame_queues[][25] = { + [RX] = "fsl,qman-frame-queues-rx", + [TX] = "fsl,qman-frame-queues-tx" +}; + +#ifdef CONFIG_DEBUG_FS +static int __cold dpa_debugfs_show(struct seq_file *file, void *offset) +{ + int i; + struct dpa_priv_s *priv; + struct dpa_percpu_priv_s *percpu_priv, total; + struct dpa_bp *dpa_bp; + unsigned int count_total = 0; + + BUG_ON(offset == NULL); + + priv = netdev_priv((struct net_device *)file->private); + + dpa_bp = priv->dpa_bp; + + memset(&total, 0, sizeof(total)); + + seq_printf(file, "\tirqs\trx\ttx\trecycle\tconfirm\ttx err\trx err" \ + "\tbp count\n"); + for_each_online_cpu(i) { + percpu_priv = per_cpu_ptr(priv->percpu_priv, i); + + total.in_interrupt += percpu_priv->in_interrupt; + total.ingress_calls += percpu_priv->stats.rx_packets; + total.stats.tx_packets += percpu_priv->stats.tx_packets; + total.tx_returned += percpu_priv->tx_returned; + total.tx_confirm += percpu_priv->tx_confirm; + total.stats.tx_errors += percpu_priv->stats.tx_errors; + total.stats.rx_errors += percpu_priv->stats.rx_errors; + count_total += *percpu_priv->dpa_bp_count; + + seq_printf(file, "%hu/%hu\t%u\t%lu\t%lu\t%u\t%u\t%lu\t%lu" \ + "\t%d\n", + get_hard_smp_processor_id(i), i, + percpu_priv->in_interrupt, + percpu_priv->stats.rx_packets, + percpu_priv->stats.tx_packets, + percpu_priv->tx_returned, + percpu_priv->tx_confirm, + percpu_priv->stats.tx_errors, + percpu_priv->stats.rx_errors, + *percpu_priv->dpa_bp_count); + } + seq_printf(file, "Total\t%u\t%u\t%lu\t%u\t%u\t%lu\t%lu\t%d\n", + total.in_interrupt, + total.ingress_calls, + total.stats.tx_packets, + total.tx_returned, + total.tx_confirm, + total.stats.tx_errors, + total.stats.rx_errors, + count_total); + + return 0; +} + +static int __cold dpa_debugfs_open(struct inode *inode, struct file *file) +{ + int _errno; + const struct net_device *net_dev; + + _errno = single_open(file, dpa_debugfs_show, inode->i_private); + if (unlikely(_errno < 0)) { + net_dev = (struct net_device *)inode->i_private; + + if (netif_msg_drv((struct dpa_priv_s *)netdev_priv(net_dev))) + cpu_netdev_err(net_dev, "single_open() = %d\n", + _errno); + } + return _errno; +} + +static const struct file_operations dpa_debugfs_fops = { + .open = dpa_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +static u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb) +{ + return smp_processor_id(); +} + +static const struct net_device_ops dpa_private_ops = { + .ndo_open = dpa_start, + .ndo_start_xmit = dpa_tx, + .ndo_stop = dpa_stop, + .ndo_change_rx_flags = dpa_change_rx_flags, + .ndo_tx_timeout = dpa_timeout, + .ndo_get_stats = dpa_get_stats, + .ndo_set_mac_address = dpa_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_select_queue = dpa_select_queue, + .ndo_change_mtu = dpa_change_mtu, + .ndo_set_rx_mode = dpa_set_multicast_list, + .ndo_do_ioctl = dpa_ioctl, +}; + +static const struct net_device_ops dpa_shared_ops = { + .ndo_open = dpa_start, + .ndo_start_xmit = dpa_shared_tx, + .ndo_stop = dpa_stop, + .ndo_change_rx_flags = dpa_change_rx_flags, + .ndo_tx_timeout = dpa_timeout, + .ndo_get_stats = dpa_get_stats, + .ndo_set_mac_address = dpa_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = dpa_set_multicast_list, + .ndo_do_ioctl = dpa_ioctl, +}; + +static int dpa_get_channel(struct device *dev, + struct device_node *dpa_node) +{ + struct device_node *dev_node; + const uint32_t *channel_id; + int lenp; + + dev_node = of_parse_phandle(dpa_node, "fsl,qman-channel", 0); + if (dev_node == NULL) { + dpaa_eth_err(dev, "Could not find fsl,qman-channel property\n"); + return -EFAULT; + } + + channel_id = of_get_property(dev_node, "fsl,qman-channel-id", &lenp); + if ((channel_id == NULL) || (lenp < sizeof(*channel_id))) { + dpaa_eth_err(dev, "Could not get fsl,qman-channel-id in %s\n", + dev_node->full_name); + of_node_put(dev_node); + return -EINVAL; + } + of_node_put(dev_node); + return *channel_id; +} + +struct fqid_cell { + uint32_t start; + uint32_t count; +}; + +static const struct fqid_cell default_fqids[][3] = { + [RX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_RX_QUEUES} }, + [TX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_TX_QUEUES} } +}; + +static int +dpa_fq_probe(struct platform_device *_of_dev, struct list_head *list, + struct dpa_fq **defq, struct dpa_fq **errq, + struct dpa_fq **fqs, int ptype) +{ + struct device *dev = &_of_dev->dev; + struct device_node *np = dev->of_node; + const struct fqid_cell *fqids; + int i, j, lenp; + int num_fqids; + struct dpa_fq *dpa_fq; + int err = 0; + + fqids = of_get_property(np, fsl_qman_frame_queues[ptype], &lenp); + if (fqids == NULL) { + fqids = default_fqids[ptype]; + num_fqids = 3; + } else + num_fqids = lenp / sizeof(*fqids); + + for (i = 0; i < num_fqids; i++) { + dpa_fq = devm_kzalloc(dev, sizeof(*dpa_fq) * fqids[i].count, + GFP_KERNEL); + if (dpa_fq == NULL) { + dpaa_eth_err(dev, "devm_kzalloc() failed\n"); + return -ENOMEM; + } + + /* The first queue is the Error queue */ + if (i == 0 && errq) { + *errq = dpa_fq; + + if (fqids[i].count != 1) { + dpaa_eth_err(dev, "Too many error queues!\n"); + err = -EINVAL; + goto invalid_error_queues; + } + } + + /* The second queue is the the Default queue */ + if (i == 1 && defq) { + *defq = dpa_fq; + + if (fqids[i].count != 1) { + dpaa_eth_err(dev, "Too many default queues!\n"); + err = -EINVAL; + goto invalid_default_queues; + } + } + + /* + * All subsequent queues are gathered together. + * The first 8 will be used by the private linux interface + * if these are TX queues + */ + if (i == 2 || (!errq && i == 0 && fqs)) + *fqs = dpa_fq; + +#warning We lost the 8-queue enforcement + +#define DPA_NUM_WQS 8 + for (j = 0; j < fqids[i].count; j++) { + dpa_fq[j].fqid = fqids[i].start ? + fqids[i].start + j : 0; + dpa_fq[j].wq = dpa_fq[j].fqid ? + dpa_fq[j].fqid % DPA_NUM_WQS : DPA_NUM_WQS - 1; + list_add_tail(&dpa_fq[j].list, list); + } + } + +invalid_default_queues: +invalid_error_queues: + return err; +} + +static void dpa_setup_ingress(struct dpa_priv_s *priv, struct dpa_fq *fq, + const struct qman_fq *template) +{ + fq->fq_base = *template; + fq->net_dev = priv->net_dev; + + fq->flags = QMAN_FQ_FLAG_NO_ENQUEUE; + fq->channel = priv->channel; +} + +static void dpa_setup_egress(struct dpa_priv_s *priv, + struct list_head *head, struct dpa_fq *fq, + struct fm_port *port) +{ + struct list_head *ptr = &fq->list; + int i = 0; + + while (true) { + struct dpa_fq *iter = list_entry(ptr, struct dpa_fq, list); + if (priv->shared) + iter->fq_base = shared_egress_fq; + else + iter->fq_base = private_egress_fq; + + iter->net_dev = priv->net_dev; + priv->egress_fqs[i++] = &iter->fq_base; + + if (port) { + iter->flags = QMAN_FQ_FLAG_TO_DCPORTAL; + iter->channel = fm_get_tx_port_channel(port); + } else + iter->flags = QMAN_FQ_FLAG_NO_MODIFY; + + if (list_is_last(ptr, head)) + break; + + ptr = ptr->next; + } +} + +static void dpa_setup_ingress_queues(struct dpa_priv_s *priv, + struct list_head *head, struct dpa_fq *fq) +{ + struct list_head *ptr = &fq->list; + u32 fqid; + int portals[NR_CPUS]; + int num_portals; + int i; + struct device_node *qm_node; + struct device_node *cpu_node; + const uint32_t *uint32_prop; + const phandle *ph; + int lenp; + int cpu; + bool found; + const cpumask_t *affine_cpus = qman_affine_cpus(); + + /* + * Make a list of the available portals. + * We're only interested in those portals which have an affine core + * and moreover that core is included in the cpumask provided by QMan + */ + num_portals = 0; + for_each_compatible_node(qm_node, NULL, "fsl,qman-portal") { + /* Check if portal has an affine core */ + ph = of_get_property(qm_node, "cpu-handle", &lenp); + if (!ph || (lenp != sizeof(phandle))) + continue; + + /* Get the hardware id of the affine core */ + cpu_node = of_find_node_by_phandle(*ph); + if (!cpu_node) + continue; + uint32_prop = of_get_property(cpu_node, "reg", &lenp); + if (!uint32_prop || (lenp != sizeof(uint32_t))) { + dpaa_eth_err(fq->net_dev->dev.parent, + "failed to get property %s for node %s", + "reg", cpu_node->full_name); + continue; + } + + /* If it's not included in the cpumask we got from QMan, + * skip portal */ + found = false; + for_each_cpu(cpu, affine_cpus) { + if (*uint32_prop == get_hard_smp_processor_id(cpu) + && !of_get_property(qm_node, + "fsl,usdpaa-portal", NULL)) { + found = true; + break; + } + } + if (!found) + continue; + + /* This portal is good, store its sw channel */ + uint32_prop = of_get_property(qm_node, + "fsl,qman-channel-id", &lenp); + if (!uint32_prop || (lenp != sizeof(uint32_t))) { + dpaa_eth_err(fq->net_dev->dev.parent, + "Failed to get property %s for node %s", + "fsl,qman-channel-id", qm_node->full_name); + continue; + } + portals[num_portals++] = *uint32_prop; + } + if (num_portals == 0) { + dpaa_eth_err(fq->net_dev->dev.parent, + "No adequate Qman portals found"); + return; + } + + i = 0; + fqid = 0; + if (priv->mac_dev) + fqid = (priv->mac_dev->res->start & 0x1fffff) >> 6; + + while (true) { + struct dpa_fq *iter = list_entry(ptr, struct dpa_fq, list); + + if (priv->shared) + dpa_setup_ingress(priv, iter, &rx_shared_fq); + else + dpa_setup_ingress(priv, iter, &rx_private_defq); + + if (!iter->fqid) + iter->fqid = fqid++; + + /* Assign the queues to a channel in a round-robin fashion */ + iter->channel = portals[i]; + i = (i + 1) % num_portals; + + if (list_is_last(ptr, head)) + break; + + ptr = ptr->next; + } +} + +static void +dpaa_eth_init_tx_port(struct fm_port *port, struct dpa_fq *errq, + struct dpa_fq *defq, bool has_timer) +{ + struct fm_port_non_rx_params tx_port_param; + + dpaa_eth_init_port(tx, port, tx_port_param, errq->fqid, defq->fqid, + has_timer); +} + +static void +dpaa_eth_init_rx_port(struct fm_port *port, struct dpa_bp *bp, size_t count, + struct dpa_fq *errq, struct dpa_fq *defq, bool has_timer) +{ + struct fm_port_rx_params rx_port_param; + int i; + + count = min(ARRAY_SIZE(rx_port_param.pool_param), count); + rx_port_param.num_pools = count; + for (i = 0; i < count; i++) { + if (i >= rx_port_param.num_pools) + break; + + rx_port_param.pool_param[i].id = bp[i].bpid; + rx_port_param.pool_param[i].size = bp[i].size; + } + + dpaa_eth_init_port(rx, port, rx_port_param, errq->fqid, defq->fqid, + has_timer); +} + +static void dpa_rx_fq_init(struct dpa_priv_s *priv, struct list_head *head, + struct dpa_fq *defq, struct dpa_fq *errq, + struct dpa_fq *fqs) +{ + if (fqs) + dpa_setup_ingress_queues(priv, head, fqs); + + /* Only real devices need default/error queues set up */ + if (!priv->mac_dev) + return; + + if (defq->fqid == 0 && netif_msg_probe(priv)) + cpu_pr_info("Using dynamic RX QM frame queues\n"); + + if (priv->shared) { + dpa_setup_ingress(priv, defq, &rx_shared_fq); + dpa_setup_ingress(priv, errq, &rx_shared_fq); + } else { + dpa_setup_ingress(priv, defq, &rx_private_defq); + dpa_setup_ingress(priv, errq, &rx_private_errq); + } +} + +static void dpa_tx_fq_init(struct dpa_priv_s *priv, struct list_head *head, + struct dpa_fq *defq, struct dpa_fq *errq, + struct dpa_fq *fqs, struct fm_port *port) +{ + if (fqs) + dpa_setup_egress(priv, head, fqs, port); + + /* Only real devices need default/error queues set up */ + if (!priv->mac_dev) + return; + + if (defq->fqid == 0 && netif_msg_probe(priv)) + cpu_pr_info("Using dynamic TX QM frame queues\n"); + + /* The shared driver doesn't use tx confirmation */ + if (priv->shared) { + dpa_setup_ingress(priv, defq, &dummyq); + dpa_setup_ingress(priv, errq, &dummyq); + } else { + dpa_setup_ingress(priv, defq, &tx_private_defq); + dpa_setup_ingress(priv, errq, &tx_private_errq); + } +} + +static int dpa_netdev_init(struct device_node *dpa_node, + struct net_device *net_dev) +{ + int err; + const uint8_t *mac_addr; + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct device *dev = net_dev->dev.parent; + + net_dev->features |= DPA_NETIF_FEATURES; + net_dev->vlan_features |= DPA_NETIF_FEATURES; + + if (!priv->mac_dev) { + /* Get the MAC address */ + mac_addr = of_get_mac_address(dpa_node); + if (mac_addr == NULL) { + if (netif_msg_probe(priv)) + dpaa_eth_err(dev, "No MAC address found!\n"); + return -EINVAL; + } + } else { + net_dev->mem_start = priv->mac_dev->res->start; + net_dev->mem_end = priv->mac_dev->res->end; + + mac_addr = priv->mac_dev->addr; + net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + net_dev->vlan_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + } + + memcpy(net_dev->perm_addr, mac_addr, net_dev->addr_len); + memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len); + + SET_ETHTOOL_OPS(net_dev, &dpa_ethtool_ops); + net_dev->needed_headroom = DPA_BP_HEAD; + net_dev->watchdog_timeo = tx_timeout * HZ / 1000; + + err = register_netdev(net_dev); + if (err < 0) { + dpaa_eth_err(dev, "register_netdev() = %d\n", err); + return err; + } + +#ifdef CONFIG_DEBUG_FS + priv->debugfs_file = debugfs_create_file(net_dev->name, S_IRUGO, + dpa_debugfs_root, net_dev, + &dpa_debugfs_fops); + if (unlikely(priv->debugfs_file == NULL)) { + cpu_netdev_err(net_dev, "debugfs_create_file(%s/%s/%s) = %d\n", + powerpc_debugfs_root->d_iname, + dpa_debugfs_root->d_iname, + net_dev->name, err); + + unregister_netdev(net_dev); + return -ENOMEM; + } +#endif + + return 0; +} + +static int dpa_shared_netdev_init(struct device_node *dpa_node, + struct net_device *net_dev) +{ + net_dev->netdev_ops = &dpa_shared_ops; + + return dpa_netdev_init(dpa_node, net_dev); +} + +static int dpa_private_netdev_init(struct device_node *dpa_node, + struct net_device *net_dev) +{ + int i; + struct dpa_priv_s *priv = netdev_priv(net_dev); + struct dpa_percpu_priv_s *percpu_priv; + + for_each_online_cpu(i) { + percpu_priv = per_cpu_ptr(priv->percpu_priv, i); + percpu_priv->net_dev = net_dev; + + percpu_priv->dpa_bp = priv->dpa_bp; + percpu_priv->dpa_bp_count = + per_cpu_ptr(priv->dpa_bp->percpu_count, i); + netif_napi_add(net_dev, &percpu_priv->napi, dpaa_eth_poll, + DPA_NAPI_WEIGHT); + } + + net_dev->netdev_ops = &dpa_private_ops; + + return dpa_netdev_init(dpa_node, net_dev); +} + +static int dpa_alloc_pcd_fqids(struct device *dev, uint32_t num, + uint8_t alignment, uint32_t *base_fqid) +{ + dpaa_eth_crit(dev, "callback not implemented!\n"); + BUG(); + + return 0; +} + +static int dpa_free_pcd_fqids(struct device *dev, uint32_t base_fqid) +{ + + dpaa_eth_crit(dev, "callback not implemented!\n"); + BUG(); + + return 0; +} + +static ssize_t dpaa_eth_show_addr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); + struct mac_device *mac_dev = priv->mac_dev; + + if (mac_dev) + return sprintf(buf, "%llx", + (unsigned long long)mac_dev->res->start); + else + return sprintf(buf, "none"); +} + +static DEVICE_ATTR(device_addr, S_IRUGO, dpaa_eth_show_addr, NULL); + +static ssize_t dpaa_eth_show_fqids(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); + ssize_t bytes = 0; + int i = 0; + char *str; + struct dpa_fq *fq; + struct dpa_fq *tmp; + struct dpa_fq *prev = NULL; + u32 first_fqid = 0; + u32 last_fqid = 0; + char *prevstr = NULL; + + list_for_each_entry_safe(fq, tmp, &priv->dpa_fq_list, list) { + void *dqrr = fq->fq_base.cb.dqrr; + if (dqrr == ingress_rx_error_dqrr) + str = "error"; + else if (i == 1 && dqrr == ingress_rx_default_dqrr) + str = "default"; + else if (dqrr == ingress_rx_error_dqrr || + dqrr == ingress_rx_default_dqrr) + str = "RX"; + else if (dqrr == ingress_tx_default_dqrr) + str = "TX confirmation"; + else if (dqrr == ingress_tx_error_dqrr) + str = "TX error"; + else if (dqrr == NULL) + str = "TX"; + else + str = "unknown"; + + if (prev && (abs(fq->fqid - prev->fqid) != 1 || + str != prevstr)) { + if (last_fqid == first_fqid) + bytes += sprintf(buf + bytes, + "%s: %d\n", prevstr, prev->fqid); + else + bytes += sprintf(buf + bytes, + "%s: %d - %d\n", prevstr, + first_fqid, last_fqid); + } + + if (prev && abs(fq->fqid - prev->fqid) == 1 && str == prevstr) + last_fqid = fq->fqid; + else + first_fqid = last_fqid = fq->fqid; + + prev = fq; + prevstr = str; + i++; + } + + if (last_fqid == first_fqid) + bytes += sprintf(buf + bytes, "%s: %d\n", prevstr, prev->fqid); + else + bytes += sprintf(buf + bytes, "%s: %d - %d\n", prevstr, + first_fqid, last_fqid); + + return bytes; +} + +static DEVICE_ATTR(fqids, S_IRUGO, dpaa_eth_show_fqids, NULL); + + +static void dpaa_eth_sysfs_init(struct device *dev) +{ + if (device_create_file(dev, &dev_attr_device_addr)) + dev_err(dev, "Error creating dpaa_eth addr file\n"); + if (device_create_file(dev, &dev_attr_fqids)) + dev_err(dev, "Error creating dpaa_eth fqids file\n"); +} +static const struct of_device_id dpa_match[] ; +static int +dpaa_eth_probe(struct platform_device *_of_dev) +{ + int err, i; + struct device *dev; + struct device_node *dpa_node; + struct dpa_bp *dpa_bp; + struct dpa_fq *dpa_fq, *tmp; + struct list_head rxfqlist; + struct list_head txfqlist; + size_t count; + struct net_device *net_dev = NULL; + struct dpa_priv_s *priv = NULL; + struct dpa_fq *rxdefault = NULL; + struct dpa_fq *txdefault = NULL; + struct dpa_fq *rxerror = NULL; + struct dpa_fq *txerror = NULL; + struct dpa_fq *rxextra = NULL; + struct dpa_fq *txfqs = NULL; + struct fm_port *rxport = NULL; + struct fm_port *txport = NULL; + bool has_timer = FALSE; + struct mac_device *mac_dev; + int proxy_enet; + const struct of_device_id *match; + + dev = &_of_dev->dev; + + dpa_node = dev->of_node; + + match = of_match_device(dpa_match, dev); + if (!match) + return -EINVAL; + + if (!of_device_is_available(dpa_node)) + return -ENODEV; + + /* + * If it's not an fsl,dpa-ethernet node, we just serve as a proxy + * initializer driver, and don't do any linux device setup + */ + proxy_enet = strcmp(match->compatible, "fsl,dpa-ethernet"); + + /* + * Allocate this early, so we can store relevant information in + * the private area + */ + if (!proxy_enet) { + net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA_ETH_TX_QUEUES); + if (!net_dev) { + dpaa_eth_err(dev, "alloc_etherdev_mq() failed\n"); + return -ENOMEM; + } + + /* Do this here, so we can be verbose early */ + SET_NETDEV_DEV(net_dev, dev); + dev_set_drvdata(dev, net_dev); + + priv = netdev_priv(net_dev); + priv->net_dev = net_dev; + + priv->msg_enable = netif_msg_init(debug, -1); + } + + /* Get the buffer pools assigned to this interface */ + dpa_bp = dpa_bp_probe(_of_dev, &count); + if (IS_ERR(dpa_bp)) { + err = PTR_ERR(dpa_bp); + goto bp_probe_failed; + } + + mac_dev = dpa_mac_probe(_of_dev); + if (IS_ERR(mac_dev)) { + err = PTR_ERR(mac_dev); + goto mac_probe_failed; + } else if (mac_dev) { + rxport = mac_dev->port_dev[RX]; + txport = mac_dev->port_dev[TX]; + } + + INIT_LIST_HEAD(&rxfqlist); + INIT_LIST_HEAD(&txfqlist); + + if (rxport) + err = dpa_fq_probe(_of_dev, &rxfqlist, &rxdefault, &rxerror, + &rxextra, RX); + else + err = dpa_fq_probe(_of_dev, &rxfqlist, NULL, NULL, + &rxextra, RX); + + if (err < 0) + goto rx_fq_probe_failed; + + if (txport) + err = dpa_fq_probe(_of_dev, &txfqlist, &txdefault, &txerror, + &txfqs, TX); + else + err = dpa_fq_probe(_of_dev, &txfqlist, NULL, NULL, &txfqs, TX); + + if (err < 0) + goto tx_fq_probe_failed; + + /* + * Now we have all of the configuration information. + * We support a number of configurations: + * 1) Private interface - An optimized linux ethernet driver with + * a real network connection. + * 2) Shared interface - A device intended for virtual connections + * or for a real interface that is shared between partitions + * 3) Proxy initializer - Just configures the MAC on behalf of + * another partition + */ + + /* bp init */ + if (net_dev) { + err = dpa_bp_create(net_dev, dpa_bp, count); + + if (err < 0) + goto bp_create_failed; + + priv->mac_dev = mac_dev; + + priv->channel = dpa_get_channel(dev, dpa_node); + + if (priv->channel < 0) { + err = priv->channel; + goto get_channel_failed; + } + + dpa_rx_fq_init(priv, &rxfqlist, rxdefault, rxerror, rxextra); + dpa_tx_fq_init(priv, &txfqlist, txdefault, txerror, txfqs, + txport); + + /* Add the FQs to the interface, and make them active */ + INIT_LIST_HEAD(&priv->dpa_fq_list); + + list_for_each_entry_safe(dpa_fq, tmp, &rxfqlist, list) { + err = _dpa_fq_alloc(&priv->dpa_fq_list, dpa_fq); + if (err < 0) + goto fq_alloc_failed; + } + + list_for_each_entry_safe(dpa_fq, tmp, &txfqlist, list) { + err = _dpa_fq_alloc(&priv->dpa_fq_list, dpa_fq); + if (err < 0) + goto fq_alloc_failed; + } + + if (priv->tsu && priv->tsu->valid) + has_timer = TRUE; + } + + /* All real interfaces need their ports initialized */ + if (mac_dev) { + struct fm_port_pcd_param rx_port_pcd_param; + + dpaa_eth_init_rx_port(rxport, dpa_bp, count, rxerror, + rxdefault, has_timer); + dpaa_eth_init_tx_port(txport, txerror, txdefault, has_timer); + + rx_port_pcd_param.cba = dpa_alloc_pcd_fqids; + rx_port_pcd_param.cbf = dpa_free_pcd_fqids; + rx_port_pcd_param.dev = dev; + fm_port_pcd_bind(rxport, &rx_port_pcd_param); + } + + /* + * Proxy interfaces need to be started, and the allocated + * memory freed + */ + if (!net_dev) { + devm_kfree(&_of_dev->dev, dpa_bp); + devm_kfree(&_of_dev->dev, rxdefault); + devm_kfree(&_of_dev->dev, rxerror); + devm_kfree(&_of_dev->dev, txdefault); + devm_kfree(&_of_dev->dev, txerror); + + if (mac_dev) + for_each_port_device(i, mac_dev->port_dev) + fm_port_enable(mac_dev->port_dev[i]); + + return 0; + } + + /* Now we need to initialize either a private or shared interface */ + priv->percpu_priv = __alloc_percpu(sizeof(*priv->percpu_priv), + __alignof__(*priv->percpu_priv)); + if (priv->percpu_priv == NULL) { + dpaa_eth_err(dev, "__alloc_percpu() failed\n"); + err = -ENOMEM; + goto alloc_percpu_failed; + } + + if (priv->shared) + err = dpa_shared_netdev_init(dpa_node, net_dev); + else + err = dpa_private_netdev_init(dpa_node, net_dev); + + if (err < 0) + goto netdev_init_failed; + + dpaa_eth_sysfs_init(&net_dev->dev); + +#ifdef CONFIG_DPAA_ETH_UNIT_TESTS + /* The unit test is designed to test private interfaces */ + if (!priv->shared && !tx_unit_test_ran) { + err = dpa_tx_unit_test(net_dev); + + BUG_ON(err); + } +#endif + + return 0; + +netdev_init_failed: + if (net_dev) + free_percpu(priv->percpu_priv); +alloc_percpu_failed: +fq_alloc_failed: + if (net_dev) + dpa_fq_free(dev, &priv->dpa_fq_list); +get_channel_failed: + if (net_dev) + dpa_bp_free(priv, priv->dpa_bp); +bp_create_failed: +tx_fq_probe_failed: +rx_fq_probe_failed: +mac_probe_failed: +bp_probe_failed: + dev_set_drvdata(dev, NULL); + if (net_dev) + free_netdev(net_dev); + + return err; +} + +static const struct of_device_id dpa_match[] = { + { + .compatible = "fsl,dpa-ethernet" + }, + { + .compatible = "fsl,dpa-ethernet-init" + }, + {} +}; +MODULE_DEVICE_TABLE(of, dpa_match); + +static int __cold dpa_remove(struct platform_device *of_dev) +{ + int err; + struct device *dev; + struct net_device *net_dev; + struct dpa_priv_s *priv; + + dev = &of_dev->dev; + net_dev = dev_get_drvdata(dev); + priv = netdev_priv(net_dev); + + dev_set_drvdata(dev, NULL); + unregister_netdev(net_dev); + + err = dpa_fq_free(dev, &priv->dpa_fq_list); + + free_percpu(priv->percpu_priv); + + dpa_bp_free(priv, priv->dpa_bp); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove(priv->debugfs_file); +#endif + +#ifdef CONFIG_FSL_DPA_1588 + if (priv->tsu && priv->tsu->valid) + dpa_ptp_cleanup(priv); +#endif + + free_netdev(net_dev); + + return err; +} + +static struct platform_driver dpa_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = dpa_match, + .owner = THIS_MODULE, + }, + .probe = dpaa_eth_probe, + .remove = dpa_remove, +}; + +static int __init __cold dpa_load(void) +{ + int _errno; + + cpu_pr_info(KBUILD_MODNAME ": " DPA_DESCRIPTION " (" VERSION ")\n"); + +#ifdef CONFIG_DEBUG_FS + dpa_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, + powerpc_debugfs_root); + if (unlikely(dpa_debugfs_root == NULL)) { + _errno = -ENOMEM; + cpu_pr_err(KBUILD_MODNAME ": %s:%hu:%s(): " + "debugfs_create_dir(%s/"KBUILD_MODNAME") = %d\n", + __file__, __LINE__, __func__, + powerpc_debugfs_root->d_iname, _errno); + goto _return; + } +#endif + + _errno = platform_driver_register(&dpa_driver); + if (unlikely(_errno < 0)) { + cpu_pr_err(KBUILD_MODNAME + ": %s:%hu:%s(): platform_driver_register() = %d\n", + __file__, __LINE__, __func__, _errno); + goto _return_debugfs_remove; + } + + goto _return; + +_return_debugfs_remove: +#ifdef CONFIG_DEBUG_FS + debugfs_remove(dpa_debugfs_root); +#endif +_return: + cpu_pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", __file__, __func__); + + return _errno; +} +module_init(dpa_load); + +static void __exit __cold dpa_unload(void) +{ + cpu_pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", __file__, __func__); + + platform_driver_unregister(&dpa_driver); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove(dpa_debugfs_root); +#endif + + cpu_pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", __file__, __func__); +} +module_exit(dpa_unload); + +static int __init fsl_fman_phy_set_max_frm(char *str) +{ + int ret = 0; + + ret = get_option(&str, &fsl_fman_phy_maxfrm); + if (ret != 1) { + /* This will only work if CONFIG_EARLY_PRINTK is compiled in, + * and something like "earlyprintk=serial,uart0,115200" is + * specified in the bootargs */ + printk(KERN_WARNING "No suitable %s= prop in bootargs; " + "will use the default DPA_MAX_FRM_SIZE (%d) " + "from Kconfig.\n", + FSL_FMAN_PHY_MAXFRM_BOOTARG, CONFIG_DPA_MAX_FRM_SIZE); + + fsl_fman_phy_maxfrm = CONFIG_DPA_MAX_FRM_SIZE; + return 1; + } + + /* Don't allow invalid bootargs; fallback to the Kconfig value */ + if (fsl_fman_phy_maxfrm < 64 || fsl_fman_phy_maxfrm > 9600) { + printk(KERN_WARNING "Invalid %s=%d in bootargs, valid range is " + "64-9600. Falling back to the DPA_MAX_FRM_SIZE (%d) " + "from Kconfig.\n", + FSL_FMAN_PHY_MAXFRM_BOOTARG, fsl_fman_phy_maxfrm, + CONFIG_DPA_MAX_FRM_SIZE); + + fsl_fman_phy_maxfrm = CONFIG_DPA_MAX_FRM_SIZE; + return 1; + } + + printk(KERN_INFO "Using fsl_fman_phy_maxfrm=%d from bootargs\n", + fsl_fman_phy_maxfrm); + return 0; +} +early_param(FSL_FMAN_PHY_MAXFRM_BOOTARG, fsl_fman_phy_set_max_frm); --- linux-3.13.0.orig/drivers/net/dpa/dpa-ethtool.c +++ linux-3.13.0/drivers/net/dpa/dpa-ethtool.c @@ -0,0 +1,201 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "dpaa_eth.h" + +static int __cold dpa_get_settings(struct net_device *net_dev, struct ethtool_cmd *et_cmd) +{ + int _errno; + struct dpa_priv_s *priv; + + priv = netdev_priv(net_dev); + + if (priv->mac_dev == NULL) { + cpu_netdev_info(net_dev, "This is a MAC-less interface\n"); + return -ENODEV; + } + if (unlikely(priv->mac_dev->phy_dev == NULL)) { + cpu_netdev_err(net_dev, "phy device not initialized\n"); + return -ENODEV; + } + + _errno = phy_ethtool_gset(priv->mac_dev->phy_dev, et_cmd); + if (unlikely(_errno < 0)) + cpu_netdev_err(net_dev, "phy_ethtool_gset() = %d\n", _errno); + + return _errno; +} + +static int __cold dpa_set_settings(struct net_device *net_dev, struct ethtool_cmd *et_cmd) +{ + int _errno; + struct dpa_priv_s *priv; + + priv = netdev_priv(net_dev); + + if (priv->mac_dev == NULL) { + cpu_netdev_info(net_dev, "This is a MAC-less interface\n"); + return -ENODEV; + } + if (unlikely(priv->mac_dev->phy_dev == NULL)) { + cpu_netdev_err(net_dev, "phy device not initialized\n"); + return -ENODEV; + } + + _errno = phy_ethtool_sset(priv->mac_dev->phy_dev, et_cmd); + if (unlikely(_errno < 0)) + cpu_netdev_err(net_dev, "phy_ethtool_sset() = %d\n", _errno); + + return _errno; +} + +static void __cold dpa_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *drvinfo) +{ + int _errno; + + strncpy(drvinfo->driver, KBUILD_MODNAME, + sizeof(drvinfo->driver) - 1)[sizeof(drvinfo->driver)-1] = 0; + strncpy(drvinfo->version, VERSION, + sizeof(drvinfo->driver) - 1)[sizeof(drvinfo->version)-1] = 0; + _errno = snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%X", 0); + + if (unlikely(_errno >= sizeof(drvinfo->fw_version))) { /* Truncated output */ + cpu_netdev_notice(net_dev, "snprintf() = %d\n", _errno); + } else if (unlikely(_errno < 0)) { + cpu_netdev_warn(net_dev, "snprintf() = %d\n", _errno); + memset(drvinfo->fw_version, 0, sizeof(drvinfo->fw_version)); + } + strncpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent), + sizeof(drvinfo->bus_info) - 1)[sizeof(drvinfo->bus_info)-1] = 0; +} + +uint32_t __cold dpa_get_msglevel(struct net_device *net_dev) +{ + return ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable; +} + +void __cold dpa_set_msglevel(struct net_device *net_dev, uint32_t msg_enable) +{ + ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable = msg_enable; +} + +int __cold dpa_nway_reset(struct net_device *net_dev) +{ + int _errno; + struct dpa_priv_s *priv; + + priv = netdev_priv(net_dev); + + if (priv->mac_dev == NULL) { + cpu_netdev_info(net_dev, "This is a MAC-less interface\n"); + return -ENODEV; + } + if (unlikely(priv->mac_dev->phy_dev == NULL)) { + cpu_netdev_err(net_dev, "phy device not initialized\n"); + return -ENODEV; + } + + _errno = 0; + if (priv->mac_dev->phy_dev->autoneg) { + _errno = phy_start_aneg(priv->mac_dev->phy_dev); + if (unlikely(_errno < 0)) + cpu_netdev_err(net_dev, "phy_start_aneg() = %d\n", + _errno); + } + + return _errno; +} + +void __cold dpa_get_ringparam(struct net_device *net_dev, struct ethtool_ringparam *et_ringparam) +{ + et_ringparam->rx_max_pending = 0; + et_ringparam->rx_mini_max_pending = 0; + et_ringparam->rx_jumbo_max_pending = 0; + et_ringparam->tx_max_pending = 0; + + et_ringparam->rx_pending = 0; + et_ringparam->rx_mini_pending = 0; + et_ringparam->rx_jumbo_pending = 0; + et_ringparam->tx_pending = 0; +} + +void __cold dpa_get_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *et_pauseparam) +{ + struct dpa_priv_s *priv; + + priv = netdev_priv(net_dev); + + if (priv->mac_dev == NULL) { + cpu_netdev_info(net_dev, "This is a MAC-less interface\n"); + return; + } + if (unlikely(priv->mac_dev->phy_dev == NULL)) { + cpu_netdev_err(net_dev, "phy device not initialized\n"); + return; + } + + et_pauseparam->autoneg = priv->mac_dev->phy_dev->autoneg; +} + +int __cold dpa_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *et_pauseparam) +{ + struct dpa_priv_s *priv; + + priv = netdev_priv(net_dev); + + if (priv->mac_dev == NULL) { + cpu_netdev_info(net_dev, "This is a MAC-less interface\n"); + return -ENODEV; + } + if (unlikely(priv->mac_dev->phy_dev == NULL)) { + cpu_netdev_err(net_dev, "phy device not initialized\n"); + return -ENODEV; + } + + priv->mac_dev->phy_dev->autoneg = et_pauseparam->autoneg; + + return 0; +} + +const struct ethtool_ops dpa_ethtool_ops = { + .get_settings = dpa_get_settings, + .set_settings = dpa_set_settings, + .get_drvinfo = dpa_get_drvinfo, + .get_msglevel = dpa_get_msglevel, + .set_msglevel = dpa_set_msglevel, + .nway_reset = dpa_nway_reset, + .get_link = ethtool_op_get_link, + .get_ringparam = dpa_get_ringparam, + .get_pauseparam = dpa_get_pauseparam, + .set_pauseparam = dpa_set_pauseparam, +}; --- linux-3.13.0.orig/drivers/net/dpa/dpaa_1588.c +++ linux-3.13.0/drivers/net/dpa/dpaa_1588.c @@ -0,0 +1,562 @@ +/* + * drivers/net/dpa/dpaa_1588.c + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Copyright (C) 2009 IXXAT Automation, GmbH + * + * DPAA Ethernet Driver -- IEEE 1588 interface functionality + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dpaa_eth.h" +#include "dpaa_1588.h" + +static int dpa_ptp_init_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size) +{ + struct circ_buf *circ_buf = &ptp_buf->circ_buf; + + circ_buf->buf = vmalloc(sizeof(struct dpa_ptp_data) * size); + if (!circ_buf->buf) + return 1; + + circ_buf->head = 0; + circ_buf->tail = 0; + ptp_buf->size = size; + spin_lock_init(&ptp_buf->ptp_lock); + + return 0; +} + +static void dpa_ptp_reset_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size) +{ + struct circ_buf *circ_buf = &ptp_buf->circ_buf; + + circ_buf->head = 0; + circ_buf->tail = 0; + ptp_buf->size = size; +} + +static int dpa_ptp_insert(struct dpa_ptp_circ_buf *ptp_buf, + struct dpa_ptp_data *data) +{ + struct circ_buf *circ_buf = &ptp_buf->circ_buf; + int size = ptp_buf->size; + struct dpa_ptp_data *tmp; + unsigned long flags; + int head, tail; + + spin_lock_irqsave(&ptp_buf->ptp_lock, flags); + + head = circ_buf->head; + tail = circ_buf->tail; + + if (CIRC_SPACE(head, tail, size) <= 0) { + spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); + return 1; + } + + tmp = (struct dpa_ptp_data *)(circ_buf->buf) + head; + memcpy(tmp, data, sizeof(struct dpa_ptp_data)); + + circ_buf->head = (head + 1) & (size - 1); + + spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); + + return 0; +} + +static int dpa_ptp_is_ident_match(struct dpa_ptp_ident *dst, + struct dpa_ptp_ident *src) +{ + int ret; + + if ((dst->version != src->version) || (dst->msg_type != src->msg_type)) + return 0; + + if ((dst->netw_prot == src->netw_prot) + || src->netw_prot == DPA_PTP_PROT_DONTCARE) { + if (dst->seq_id != src->seq_id) + return 0; + + ret = memcmp(dst->snd_port_id, src->snd_port_id, + DPA_PTP_SOURCE_PORT_LENGTH); + if (ret) + return 0; + else + return 1; + } + + return 0; +} + +static int dpa_ptp_find_and_remove(struct dpa_ptp_circ_buf *ptp_buf, + struct dpa_ptp_ident *ident, + struct dpa_ptp_time *ts) +{ + struct circ_buf *circ_buf = &ptp_buf->circ_buf; + int size = ptp_buf->size; + int head, tail, idx; + unsigned long flags; + struct dpa_ptp_data *tmp; + struct dpa_ptp_ident *tmp_ident; + + spin_lock_irqsave(&ptp_buf->ptp_lock, flags); + + head = circ_buf->head; + tail = idx = circ_buf->tail; + + if (CIRC_CNT_TO_END(head, tail, size) == 0) { + spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); + return 1; + } + + while (idx != head) { + tmp = (struct dpa_ptp_data *)(circ_buf->buf) + idx; + tmp_ident = &tmp->ident; + if (dpa_ptp_is_ident_match(tmp_ident, ident)) + break; + idx = (idx + 1) & (size - 1); + } + + if (idx == head) { + circ_buf->tail = head; + spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); + return 1; + } + + ts->sec = tmp->ts.sec; + ts->nsec = tmp->ts.nsec; + + circ_buf->tail = (idx + 1) & (size - 1); + + spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); + + return 0; +} + +static int dpa_ptp_get_time(dma_addr_t fd_addr, u32 *high, u32 *low) +{ + u8 *ts_addr = (u8 *)phys_to_virt(fd_addr); + u32 sec, nsec, mod; + u64 tmp; + + ts_addr += DPA_PTP_TIMESTAMP_OFFSET; + sec = *((u32 *)ts_addr); + nsec = *(((u32 *)ts_addr) + 1); + tmp = ((u64)sec << 32 | nsec) * DPA_PTP_NOMINAL_FREQ_PERIOD; + + mod = do_div(tmp, NANOSEC_PER_SECOND); + *high = (u32)tmp; + *low = mod; + + return 0; +} + +/* + * Parse the PTP packets + * + * The PTP header can be found in an IPv4 packet, IPv6 patcket or in + * an IEEE802.3 ethernet frame. This function returns the position of + * the PTP packet or NULL if no PTP found + */ +static u8 *dpa_ptp_parse_packet(struct sk_buff *skb, u16 *eth_type) +{ + u8 *pos = skb->data + ETH_ALEN + ETH_ALEN; + u8 *ptp_loc = NULL; + u8 msg_type; + struct iphdr *iph; + struct udphdr *udph; + struct ipv6hdr *ipv6h; + + *eth_type = *((u16 *)pos); + + /* Check if inner tag is here */ + if (*eth_type == ETH_P_8021Q) { + pos += DPA_VLAN_TAG_LEN; + *eth_type = *((u16 *)pos); + } + + pos += DPA_ETYPE_LEN; + + switch (*eth_type) { + /* Transport of PTP over Ethernet */ + case ETH_P_1588: + ptp_loc = pos; + msg_type = *((u8 *)(ptp_loc + PTP_OFFS_MSG_TYPE)) & 0xf; + if ((msg_type == PTP_MSGTYPE_SYNC) + || (msg_type == PTP_MSGTYPE_DELREQ) + || (msg_type == PTP_MSGTYPE_PDELREQ) + || (msg_type == PTP_MSGTYPE_PDELRESP)) + return ptp_loc; + break; + /* Transport of PTP over IPv4 */ + case ETH_P_IP: + iph = (struct iphdr *)pos; + if (ntohs(iph->protocol) != IPPROTO_UDP) + return NULL; + + pos += iph->ihl * 4; + udph = (struct udphdr *)pos; + if (ntohs(udph->dest) != 319) + return NULL; + ptp_loc = pos + sizeof(struct udphdr); + break; + /* Transport of PTP over IPv6 */ + case ETH_P_IPV6: + ipv6h = (struct ipv6hdr *)pos; + if (ntohs(ipv6h->nexthdr) != IPPROTO_UDP) + return NULL; + + pos += sizeof(struct ipv6hdr); + udph = (struct udphdr *)pos; + if (ntohs(udph->dest) != 319) + return NULL; + ptp_loc = pos + sizeof(struct udphdr); + break; + default: + break; + } + + return ptp_loc; +} + +static int dpa_ptp_store_stamp(struct net_device *dev, struct sk_buff *skb, + dma_addr_t fd_addr, struct dpa_ptp_data *ptp_data) +{ + u32 sec, nsec; + u8 *ptp_loc; + u16 eth_type; + + ptp_loc = dpa_ptp_parse_packet(skb, ð_type); + if (!ptp_loc) + return -EINVAL; + + switch (eth_type) { + case ETH_P_IP: + ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV4; + break; + case ETH_P_IPV6: + ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV6; + break; + case ETH_P_1588: + ptp_data->ident.netw_prot = DPA_PTP_PROT_802_3; + break; + default: + return -EINVAL; + } + + ptp_data->ident.version = *(ptp_loc + PTP_OFFS_VER_PTP) & 0xf; + ptp_data->ident.msg_type = *(ptp_loc + PTP_OFFS_MSG_TYPE) & 0xf; + ptp_data->ident.seq_id = *((u16 *)(ptp_loc + PTP_OFFS_SEQ_ID)); + memcpy(ptp_data->ident.snd_port_id, ptp_loc + PTP_OFFS_SRCPRTID, + DPA_PTP_SOURCE_PORT_LENGTH); + + dpa_ptp_get_time(fd_addr, &sec, &nsec); + ptp_data->ts.sec = (u64)sec; + ptp_data->ts.nsec = nsec; + + return 0; +} + +void dpa_ptp_store_txstamp(struct net_device *dev, struct sk_buff *skb, + const struct qm_fd *fd) +{ + struct dpa_priv_s *priv = netdev_priv(dev); + struct dpa_ptp_tsu *tsu = priv->tsu; + struct dpa_ptp_data ptp_tx_data; + dma_addr_t fd_addr = qm_fd_addr(fd); + int ret; + + ret = dpa_ptp_store_stamp(dev, skb, fd_addr, &ptp_tx_data); + if (ret) + return; + dpa_ptp_insert(&tsu->tx_timestamps, &ptp_tx_data); +} + +void dpa_ptp_store_rxstamp(struct net_device *dev, struct sk_buff *skb, + const struct qm_fd *fd) +{ + struct dpa_priv_s *priv = netdev_priv(dev); + struct dpa_ptp_tsu *tsu = priv->tsu; + struct dpa_ptp_data ptp_rx_data; + dma_addr_t fd_addr = qm_fd_addr(fd); + int ret; + + ret = dpa_ptp_store_stamp(dev, skb, fd_addr, &ptp_rx_data); + if (ret) + return; + dpa_ptp_insert(&tsu->rx_timestamps, &ptp_rx_data); +} + +static uint8_t dpa_get_tx_timestamp(struct dpa_ptp_tsu *ptp_tsu, + struct dpa_ptp_ident *ident, + struct dpa_ptp_time *ts) +{ + struct dpa_ptp_tsu *tsu = ptp_tsu; + struct dpa_ptp_time tmp; + int flag; + + flag = dpa_ptp_find_and_remove(&tsu->tx_timestamps, ident, &tmp); + if (!flag) { + ts->sec = tmp.sec; + ts->nsec = tmp.nsec; + return 0; + } + + return -1; +} + +static uint8_t dpa_get_rx_timestamp(struct dpa_ptp_tsu *ptp_tsu, + struct dpa_ptp_ident *ident, + struct dpa_ptp_time *ts) +{ + struct dpa_ptp_tsu *tsu = ptp_tsu; + struct dpa_ptp_time tmp; + int flag; + + flag = dpa_ptp_find_and_remove(&tsu->rx_timestamps, ident, &tmp); + if (!flag) { + ts->sec = tmp.sec; + ts->nsec = tmp.nsec; + return 0; + } + + return -1; +} + +static void dpa_set_fiper_alarm(struct dpa_ptp_tsu *tsu, + struct dpa_ptp_time *cnt_time) +{ + struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; + u64 tmp, fiper; + + if (mac_dev->fm_rtc_disable) + mac_dev->fm_rtc_disable(tsu->dpa_priv->net_dev); + + /* TMR_FIPER1 will pulse every second after ALARM1 expired */ + tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec; + fiper = NANOSEC_PER_SECOND - DPA_PTP_NOMINAL_FREQ_PERIOD; + if (mac_dev->fm_rtc_set_alarm) + mac_dev->fm_rtc_set_alarm(tsu->dpa_priv->net_dev, 0, tmp); + if (mac_dev->fm_rtc_set_fiper) + mac_dev->fm_rtc_set_fiper(tsu->dpa_priv->net_dev, 0, fiper); + + if (mac_dev->fm_rtc_enable) + mac_dev->fm_rtc_enable(tsu->dpa_priv->net_dev); +} + +static void dpa_get_curr_cnt(struct dpa_ptp_tsu *tsu, + struct dpa_ptp_time *curr_time) +{ + struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; + u64 tmp; + u32 mod; + + if (mac_dev->fm_rtc_get_cnt) + mac_dev->fm_rtc_get_cnt(tsu->dpa_priv->net_dev, &tmp); + + mod = do_div(tmp, NANOSEC_PER_SECOND); + curr_time->sec = (u32)tmp; + curr_time->nsec = mod; +} + +static void dpa_set_1588cnt(struct dpa_ptp_tsu *tsu, + struct dpa_ptp_time *cnt_time) +{ + struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; + u64 tmp; + + tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec; + + if (mac_dev->fm_rtc_set_cnt) + mac_dev->fm_rtc_set_cnt(tsu->dpa_priv->net_dev, tmp); + + /* Restart fiper two seconds later */ + cnt_time->sec += 2; + cnt_time->nsec = 0; + dpa_set_fiper_alarm(tsu, cnt_time); +} + +static void dpa_get_drift(struct dpa_ptp_tsu *tsu, u32 *addend) +{ + struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; + u32 drift; + + if (mac_dev->fm_rtc_get_drift) + mac_dev->fm_rtc_get_drift(tsu->dpa_priv->net_dev, &drift); + + *addend = drift; +} + +static void dpa_set_drift(struct dpa_ptp_tsu *tsu, u32 addend) +{ + struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; + + if (mac_dev->fm_rtc_set_drift) + mac_dev->fm_rtc_set_drift(tsu->dpa_priv->net_dev, addend); +} + +static void dpa_flush_timestamp(struct dpa_ptp_tsu *tsu) +{ + dpa_ptp_reset_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ); + dpa_ptp_reset_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ); +} + +int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct dpa_priv_s *priv = netdev_priv(dev); + struct dpa_ptp_tsu *tsu = priv->tsu; + struct mac_device *mac_dev = priv->mac_dev; + struct dpa_ptp_data ptp_data; + struct dpa_ptp_data *ptp_data_user; + struct dpa_ptp_time act_time; + u32 addend; + int retval = 0; + + if (!tsu || !tsu->valid) + return -ENODEV; + + switch (cmd) { + case PTP_ENBL_TXTS_IOCTL: + tsu->hwts_tx_en_ioctl = 1; + if (mac_dev->ptp_enable) + mac_dev->ptp_enable(mac_dev); + break; + case PTP_DSBL_TXTS_IOCTL: + tsu->hwts_tx_en_ioctl = 0; + if (mac_dev->ptp_disable) + mac_dev->ptp_disable(mac_dev); + break; + case PTP_ENBL_RXTS_IOCTL: + tsu->hwts_rx_en_ioctl = 1; + break; + case PTP_DSBL_RXTS_IOCTL: + tsu->hwts_rx_en_ioctl = 0; + break; + case PTP_GET_RX_TIMESTAMP: + ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data; + if (copy_from_user(&ptp_data.ident, + &ptp_data_user->ident, sizeof(ptp_data.ident))) + return -EINVAL; + + if (dpa_get_rx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts)) + return -EAGAIN; + + if (copy_to_user((void __user *)&ptp_data_user->ts, + &ptp_data.ts, sizeof(ptp_data.ts))) + return -EFAULT; + break; + case PTP_GET_TX_TIMESTAMP: + ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data; + if (copy_from_user(&ptp_data.ident, + &ptp_data_user->ident, sizeof(ptp_data.ident))) + return -EINVAL; + + if (dpa_get_tx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts)) + return -EAGAIN; + + if (copy_to_user((void __user *)&ptp_data_user->ts, + &ptp_data.ts, sizeof(ptp_data.ts))) + return -EFAULT; + break; + case PTP_GET_TIME: + dpa_get_curr_cnt(tsu, &act_time); + if (copy_to_user(ifr->ifr_data, &act_time, sizeof(act_time))) + return -EFAULT; + break; + case PTP_SET_TIME: + if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time))) + return -EINVAL; + dpa_set_1588cnt(tsu, &act_time); + break; + case PTP_GET_ADJ: + dpa_get_drift(tsu, &addend); + if (copy_to_user(ifr->ifr_data, &addend, sizeof(addend))) + return -EFAULT; + break; + case PTP_SET_ADJ: + if (copy_from_user(&addend, ifr->ifr_data, sizeof(addend))) + return -EINVAL; + dpa_set_drift(tsu, addend); + break; + case PTP_SET_FIPER_ALARM: + if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time))) + return -EINVAL; + dpa_set_fiper_alarm(tsu, &act_time); + break; + case PTP_CLEANUP_TS: + dpa_flush_timestamp(tsu); + break; + default: + return -EINVAL; + } + + return retval; +} + +int dpa_ptp_init(struct dpa_priv_s *priv) +{ + struct dpa_ptp_tsu *tsu; + + /* Allocate memory for PTP structure */ + tsu = kzalloc(sizeof(struct dpa_ptp_tsu), GFP_KERNEL); + if (!tsu) + return -ENOMEM; + + memset(tsu, 0, sizeof(*tsu)); + tsu->valid = TRUE; + tsu->dpa_priv = priv; + + dpa_ptp_init_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ); + dpa_ptp_init_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ); + + priv->tsu = tsu; + + return 0; +} +EXPORT_SYMBOL(dpa_ptp_init); + +void dpa_ptp_cleanup(struct dpa_priv_s *priv) +{ + struct dpa_ptp_tsu *tsu = priv->tsu; + + tsu->valid = FALSE; + vfree(tsu->rx_timestamps.circ_buf.buf); + vfree(tsu->tx_timestamps.circ_buf.buf); + + kfree(tsu); +} +EXPORT_SYMBOL(dpa_ptp_cleanup); + +static int __init __cold dpa_ptp_load(void) +{ + return 0; +} +module_init(dpa_ptp_load); + +static void __exit __cold dpa_ptp_unload(void) +{ +} +module_exit(dpa_ptp_unload); --- linux-3.13.0.orig/drivers/net/dpa/dpaa_eth.h +++ linux-3.13.0/drivers/net/dpa/dpaa_eth.h @@ -0,0 +1,127 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DPA_H +#define __DPA_H + +#include /* struct ethtool_ops */ +#include +#include /* struct list_head */ +#include /* struct work_struct */ +#include +#include +#ifdef CONFIG_DEBUG_FS +#include /* struct dentry */ +#endif + +#include /* struct qman_fq */ + +#include "dpaa_eth-common.h" + +#include "mac.h" /* struct mac_device */ + + +/* number of Tx queues to FMan */ +#define DPAA_ETH_TX_QUEUES 8 +#define DPAA_ETH_RX_QUEUES 128 + +struct pcd_range { + uint32_t base; + uint32_t count; +}; + +struct dpa_bp { + struct bman_pool *pool; + uint8_t bpid; + struct device *dev; + size_t count; + size_t size; + bool seed_pool; + dma_addr_t paddr; + void *vaddr; + int kernel_pool; + int *percpu_count; + int *needs_refill; + atomic_t refs; +}; + +struct dpa_percpu_priv_s { + struct net_device *net_dev; + int *dpa_bp_count; + struct dpa_bp *dpa_bp; + struct napi_struct napi; + u32 start_tx; + u32 in_interrupt; + u32 ingress_calls; + u32 tx_returned; + u32 tx_confirm; + struct net_device_stats stats; +}; + +struct dpa_priv_s { + struct dpa_bp *dpa_bp; + size_t bp_count; + int shared; + struct net_device *net_dev; + + uint16_t channel; /* "fsl,qman-channel-id" */ + struct list_head dpa_fq_list; + struct qman_fq *egress_fqs[DPAA_ETH_TX_QUEUES]; + + struct mac_device *mac_dev; + + struct dpa_percpu_priv_s *percpu_priv; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_file; +#endif + + uint32_t msg_enable; /* net_device message level */ + struct dpa_ptp_tsu *tsu; +}; + +extern const struct ethtool_ops dpa_ethtool_ops; +extern int fsl_fman_phy_maxfrm; + +static inline int dpaa_eth_napi_schedule(struct dpa_percpu_priv_s *percpu_priv) +{ + if (unlikely(in_irq())) { + /* Disable QMan IRQ and invoke NAPI */ + int ret = qman_irqsource_remove(QM_PIRQ_DQRI); + if (likely(!ret)) { + napi_schedule(&percpu_priv->napi); + return 1; + } + } + return 0; +} + +#endif /* __DPA_H */ --- linux-3.13.0.orig/drivers/net/dpa/offline_port.c +++ linux-3.13.0/drivers/net/dpa/offline_port.c @@ -0,0 +1,340 @@ +/* + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Offline Parsing / Host Command port driver for FSL QorIQ FMan. + * Validates device-tree configuration and sets up the offline ports. + */ + +#include +#include +#include + +#include "offline_port.h" +#include "dpaa_eth-common.h" + +#define OH_MOD_DESCRIPTION "FSL FMan Offline Parsing port driver" + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Bogdan Hamciuc "); +MODULE_DESCRIPTION(OH_MOD_DESCRIPTION); + + +static const struct of_device_id oh_port_match_table[] = { + { + .compatible = "fsl,dpa-oh" + }, + { + .compatible = "fsl,dpa-oh-shared" + }, + {} +}; +MODULE_DEVICE_TABLE(of, oh_port_match_table); + +static int oh_port_remove(struct platform_device *_of_dev); +static int oh_port_probe(struct platform_device *_of_dev); + +static struct platform_driver oh_port_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = oh_port_match_table, + .owner = THIS_MODULE, + }, + .probe = oh_port_probe, + .remove = oh_port_remove, +}; + +/* Allocation code for the OH port's PCD frame queues */ +static int __cold oh_alloc_pcd_fqids(struct device *dev, + uint32_t num, + uint8_t alignment, + uint32_t *base_fqid) +{ + cpu_dev_crit(dev, "callback not implemented!\n"); + BUG(); + + return 0; +} + +static int __cold oh_free_pcd_fqids(struct device *dev, uint32_t base_fqid) +{ + dpaa_eth_crit(dev, "callback not implemented!\n"); + BUG(); + + return 0; +} + +static int +oh_port_probe(struct platform_device *_of_dev) +{ + struct device *dpa_oh_dev; + struct device_node *dpa_oh_node; + int lenp, _errno = 0, fq_idx; + const phandle *oh_port_handle; + struct platform_device *oh_of_dev; + struct device_node *oh_node; + struct device *oh_dev; + struct dpa_oh_config_s *oh_config; + uint32_t *oh_all_queues; + uint32_t queues_count; + uint32_t crt_fqid_base; + uint32_t crt_fq_count; + struct fm_port_non_rx_params oh_port_tx_params; + struct fm_port_pcd_param oh_port_pcd_params; + /* True if the current partition owns the OH port. */ + bool init_oh_port; + const struct of_device_id *match; + + dpa_oh_dev = &_of_dev->dev; + dpa_oh_node = dpa_oh_dev->of_node; + BUG_ON(dpa_oh_node == NULL); + + match = of_match_device(oh_port_match_table, dpa_oh_dev); + if (!match) + return -EINVAL; + + cpu_dev_dbg(dpa_oh_dev, "Probing OH port...\n"); + + /* + * Find the referenced OH node + */ + + oh_port_handle = of_get_property(dpa_oh_node, + "fsl,fman-oh-port", &lenp); + if (oh_port_handle == NULL) { + cpu_dev_err(dpa_oh_dev, "No OH port handle found in node %s\n", + dpa_oh_node->full_name); + return -EINVAL; + } + + BUG_ON(lenp % sizeof(*oh_port_handle)); + if (lenp != sizeof(*oh_port_handle)) { + cpu_dev_err(dpa_oh_dev, "Found %lu OH port bindings in node %s, " + "only 1 phandle is allowed.\n", + (unsigned long int)(lenp / sizeof(*oh_port_handle)), dpa_oh_node->full_name); + return -EINVAL; + } + + /* Read configuration for the OH port */ + oh_node = of_find_node_by_phandle(*oh_port_handle); + if (oh_node == NULL) { + cpu_dev_err(dpa_oh_dev, "Can't find OH node referenced from " + "node %s\n", dpa_oh_node->full_name); + return -EINVAL; + } + cpu_dev_info(dpa_oh_dev, "Found OH node handle compatible with %s.\n", + match->compatible); + + oh_of_dev = of_find_device_by_node(oh_node); + BUG_ON(oh_of_dev == NULL); + oh_dev = &oh_of_dev->dev; + of_node_put(oh_node); + + /* + * The OH port must be initialized exactly once. + * The following scenarios are of interest: + * - the node is Linux-private (will always initialize it); + * - the node is shared between two Linux partitions + * (only one of them will initialize it); + * - the node is shared between a Linux and a LWE partition + * (Linux will initialize it) - "fsl,dpa-oh-shared" + */ + + /* Check if the current partition owns the OH port + * and ought to initialize it. It may be the case that we leave this + * to another (also Linux) partition. */ + init_oh_port = strcmp(match->compatible, "fsl,dpa-oh-shared"); + + /* If we aren't the "owner" of the OH node, we're done here. */ + if (!init_oh_port) { + cpu_dev_dbg(dpa_oh_dev, "Not owning the shared OH port %s, " + "will not initialize it.\n", oh_node->full_name); + return 0; + } + + /* Allocate OH dev private data */ + oh_config = devm_kzalloc(dpa_oh_dev, sizeof(*oh_config), GFP_KERNEL); + if (oh_config == NULL) { + cpu_dev_err(dpa_oh_dev, "Can't allocate private data for " + "OH node %s referenced from node %s!\n", + oh_node->full_name, dpa_oh_node->full_name); + return -ENOMEM; + } + + /* + * Read FQ ids/nums for the DPA OH node + */ + oh_all_queues = (uint32_t *)of_get_property(dpa_oh_node, + "fsl,qman-frame-queues-oh", &lenp); + if (oh_all_queues == NULL) { + cpu_dev_err(dpa_oh_dev, "No frame queues have been " + "defined for OH node %s referenced from node %s\n", + oh_node->full_name, dpa_oh_node->full_name); + _errno = -EINVAL; + goto return_kfree; + } + + /* Check that the OH error and default FQs are there */ + BUG_ON(lenp % (2 * sizeof(*oh_all_queues))); + queues_count = lenp / (2 * sizeof(*oh_all_queues)); + if (queues_count != 2) { + dpaa_eth_err(dpa_oh_dev, "Error and Default queues must be " + "defined for OH node %s referenced from node %s\n", + oh_node->full_name, dpa_oh_node->full_name); + _errno = -EINVAL; + goto return_kfree; + } + + /* Read the FQIDs defined for this OH port */ + cpu_dev_dbg(dpa_oh_dev, "Reading %d queues...\n", queues_count); + fq_idx = 0; + + /* Error FQID - must be present */ + crt_fqid_base = oh_all_queues[fq_idx++]; + crt_fq_count = oh_all_queues[fq_idx++]; + if (crt_fq_count != 1) { + cpu_dev_err(dpa_oh_dev, "Only 1 Error FQ allowed in OH node %s " + "referenced from node %s (read: %d FQIDs).\n", + oh_node->full_name, dpa_oh_node->full_name, + crt_fq_count); + _errno = -EINVAL; + goto return_kfree; + } + oh_config->error_fqid = crt_fqid_base; + cpu_dev_dbg(dpa_oh_dev, "Read Error FQID 0x%x for OH port %s.\n", + oh_config->error_fqid, oh_node->full_name); + + /* Default FQID - must be present */ + crt_fqid_base = oh_all_queues[fq_idx++]; + crt_fq_count = oh_all_queues[fq_idx++]; + if (crt_fq_count != 1) { + cpu_dev_err(dpa_oh_dev, "Only 1 Default FQ allowed " + "in OH node %s referenced from %s (read: %d FQIDs).\n", + oh_node->full_name, dpa_oh_node->full_name, + crt_fq_count); + _errno = -EINVAL; + goto return_kfree; + } + oh_config->default_fqid = crt_fqid_base; + cpu_dev_dbg(dpa_oh_dev, "Read Default FQID 0x%x for OH port %s.\n", + oh_config->default_fqid, oh_node->full_name); + + /* Get a handle to the fm_port so we can set + * its configuration params */ + oh_config->oh_port = fm_port_bind(oh_dev); + if (oh_config->oh_port == NULL) { + cpu_dev_err(dpa_oh_dev, "NULL drvdata from fm port dev %s!\n", + oh_node->full_name); + _errno = -EINVAL; + goto return_kfree; + } + + /* Set Tx params */ + dpaa_eth_init_port(tx, oh_config->oh_port, oh_port_tx_params, + oh_config->error_fqid, oh_config->default_fqid, FALSE); + /* Set PCD params */ + oh_port_pcd_params.cba = oh_alloc_pcd_fqids; + oh_port_pcd_params.cbf = oh_free_pcd_fqids; + oh_port_pcd_params.dev = dpa_oh_dev; + fm_port_pcd_bind(oh_config->oh_port, &oh_port_pcd_params); + + dev_set_drvdata(dpa_oh_dev, oh_config); + + /* Enable the OH port */ + fm_port_enable(oh_config->oh_port); + cpu_dev_info(dpa_oh_dev, "OH port %s enabled.\n", oh_node->full_name); + + return 0; + +return_kfree: + devm_kfree(dpa_oh_dev, oh_config); + return _errno; +} + +static int __cold oh_port_remove(struct platform_device *_of_dev) +{ + int _errno = 0; + struct dpa_oh_config_s *oh_config; + + cpu_pr_info("Removing OH port...\n"); + + oh_config = dev_get_drvdata(&_of_dev->dev); + if (oh_config == NULL) { + cpu_pr_err(KBUILD_MODNAME + ": %s:%hu:%s(): No OH config in device private data!\n", + __file__, __LINE__, __func__); + _errno = -ENODEV; + goto return_error; + } + if (oh_config->oh_port == NULL) { + cpu_pr_err(KBUILD_MODNAME + ": %s:%hu:%s(): No fm port in device private data!\n", + __file__, __LINE__, __func__); + _errno = -EINVAL; + goto return_error; + } + + fm_port_disable(oh_config->oh_port); + devm_kfree(&_of_dev->dev, oh_config); + dev_set_drvdata(&_of_dev->dev, NULL); + +return_error: + return _errno; +} + +static int __init __cold oh_port_load(void) +{ + int _errno; + + cpu_pr_info(KBUILD_MODNAME ": " OH_MOD_DESCRIPTION " (" VERSION ")\n"); + + _errno = platform_driver_register(&oh_port_driver); + if (_errno < 0) { + cpu_pr_err(KBUILD_MODNAME + ": %s:%hu:%s(): platform_driver_register() = %d\n", + __file__, __LINE__, __func__, _errno); + } + + cpu_pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", __file__, __func__); + return _errno; +} +module_init(oh_port_load); + +static void __exit __cold oh_port_unload(void) +{ + cpu_pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", __file__, __func__); + + platform_driver_unregister(&oh_port_driver); + + cpu_pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", __file__, __func__); +} +module_exit(oh_port_unload); --- linux-3.13.0.orig/drivers/net/dpa/Makefile +++ linux-3.13.0/drivers/net/dpa/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +EXTRA_CFLAGS += -I$(NET_DPA) + +#Netcomm SW tree +obj-$(CONFIG_FSL_FMAN) += NetCommSw/ +obj-$(CONFIG_FSL_DPA_1588) += dpaa_1588.o +obj-$(CONFIG_DPA) += fsl-mac.o fsl-dpa.o +obj-$(CONFIG_DPA_OFFLINE_PORTS) += fsl-oh.o + +fsl-dpa-objs := dpa-ethtool.o dpaa_eth.o +fsl-mac-objs := mac.o mac-api.o +fsl-oh-objs := offline_port.o --- linux-3.13.0.orig/drivers/net/dpa/mac.h +++ linux-3.13.0/drivers/net/dpa/mac.h @@ -0,0 +1,113 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MAC_H +#define __MAC_H + +#include /* struct device, BUS_ID_SIZE */ +#include /* ETH_ALEN */ +#include /* phy_interface_t, struct phy_device */ +#include + +#include "fsl_fman.h" /* struct port_device */ + +#ifndef CONFIG_DPA_MAX_FRM_SIZE +#define CONFIG_DPA_MAX_FRM_SIZE 0 +#endif + +enum {DTSEC, XGMAC}; + +struct mac_device { + struct device *dev; + void *priv; + uint8_t cell_index; + struct resource *res; + void *vaddr; + uint8_t addr[ETH_ALEN]; + bool promisc; + + struct fm *fm_dev; + struct fm_port *port_dev[2]; + + phy_interface_t phy_if; + u32 if_support; + bool link; + bool half_duplex; + uint16_t speed; + uint16_t max_speed; + struct device_node *phy_node; + char fixed_bus_id[MII_BUS_ID_SIZE + 3]; + struct device_node *tbi_node; + struct phy_device *phy_dev; + void *fm; + /* List of multicast addresses */ + struct list_head mc_addr_list; + + int (*init_phy)(struct net_device *net_dev); + int (*init)(struct mac_device *mac_dev); + int (*start)(struct mac_device *mac_dev); + int (*stop)(struct mac_device *mac_dev); + int (*change_promisc)(struct mac_device *mac_dev); + int (*change_addr)(struct mac_device *mac_dev, uint8_t *addr); + int (*set_multi)(struct net_device *net_dev); + int (*uninit)(struct mac_device *mac_dev); + int (*ptp_enable)(struct mac_device *mac_dev); + int (*ptp_disable)(struct mac_device *mac_dev); + int (*fm_rtc_enable)(struct net_device *net_dev); + int (*fm_rtc_disable)(struct net_device *net_dev); + int (*fm_rtc_get_cnt)(struct net_device *net_dev, uint64_t *ts); + int (*fm_rtc_set_cnt)(struct net_device *net_dev, uint64_t ts); + int (*fm_rtc_get_drift)(struct net_device *net_dev, uint32_t *drift); + int (*fm_rtc_set_drift)(struct net_device *net_dev, uint32_t drift); + int (*fm_rtc_set_alarm)(struct net_device *net_dev, uint32_t id, + uint64_t time); + int (*fm_rtc_set_fiper)(struct net_device *net_dev, uint32_t id, + uint64_t fiper); +}; + +struct mac_address { + uint8_t addr[ETH_ALEN]; + struct list_head list; +}; + +#define for_each_port_device(i, port_dev) \ + for (i = 0; i < ARRAY_SIZE(port_dev); i++) + +static inline void * __attribute((nonnull)) macdev_priv(const struct mac_device *mac_dev) +{ + return (void *)mac_dev + sizeof(*mac_dev); +} + +extern const char *mac_driver_description; +extern const size_t mac_sizeof_priv[]; +extern void (*const mac_setup[])(struct mac_device *mac_dev); + +#endif /* __MAC_H */ --- linux-3.13.0.orig/drivers/net/dpa/mac.c +++ linux-3.13.0/drivers/net/dpa/mac.c @@ -0,0 +1,428 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dpaa_eth-common.h" + +#include "lnxwrp_fm_ext.h" + +#include "mac.h" + +#define DTSEC_SUPPORTED \ + (SUPPORTED_10baseT_Half \ + | SUPPORTED_10baseT_Full \ + | SUPPORTED_100baseT_Half \ + | SUPPORTED_100baseT_Full \ + | SUPPORTED_Autoneg \ + | SUPPORTED_MII) + +static const char phy_str[][11] = +{ + [PHY_INTERFACE_MODE_MII] = "mii", + [PHY_INTERFACE_MODE_GMII] = "gmii", + [PHY_INTERFACE_MODE_SGMII] = "sgmii", + [PHY_INTERFACE_MODE_TBI] = "tbi", + [PHY_INTERFACE_MODE_RMII] = "rmii", + [PHY_INTERFACE_MODE_RGMII] = "rgmii", + [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id", + [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid", + [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid", + [PHY_INTERFACE_MODE_RTBI] = "rtbi", + [PHY_INTERFACE_MODE_XGMII] = "xgmii" +}; + +static phy_interface_t __pure __attribute__((nonnull)) str2phy(const char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(phy_str); i++) + if (strcmp(str, phy_str[i]) == 0) + return (phy_interface_t)i; + + return PHY_INTERFACE_MODE_MII; +} + +static const uint16_t phy2speed[] = +{ + [PHY_INTERFACE_MODE_MII] = SPEED_100, + [PHY_INTERFACE_MODE_GMII] = SPEED_1000, + [PHY_INTERFACE_MODE_SGMII] = SPEED_1000, + [PHY_INTERFACE_MODE_TBI] = SPEED_1000, + [PHY_INTERFACE_MODE_RMII] = SPEED_100, + [PHY_INTERFACE_MODE_RGMII] = SPEED_1000, + [PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000, + [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000, + [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000, + [PHY_INTERFACE_MODE_RTBI] = SPEED_1000, + [PHY_INTERFACE_MODE_XGMII] = SPEED_10000 +}; + +static struct mac_device * __cold +alloc_macdev(struct device *dev, size_t sizeof_priv, void (*setup)(struct mac_device *mac_dev)) +{ + struct mac_device *mac_dev; + + mac_dev = devm_kzalloc(dev, sizeof(*mac_dev) + sizeof_priv, GFP_KERNEL); + if (unlikely(mac_dev == NULL)) + mac_dev = ERR_PTR(-ENOMEM); + else { + mac_dev->dev = dev; + dev_set_drvdata(dev, mac_dev); + setup(mac_dev); + } + + return mac_dev; +} + +static int __cold free_macdev(struct mac_device *mac_dev) +{ + dev_set_drvdata(mac_dev->dev, NULL); + + return mac_dev->uninit(mac_dev); +} + +static const struct of_device_id mac_match[] = { + [DTSEC] = { + .compatible = "fsl,fman-1g-mac" + }, + [XGMAC] = { + .compatible = "fsl,fman-10g-mac" + }, + {} +}; +MODULE_DEVICE_TABLE(of, mac_match); + +static int __cold mac_probe(struct platform_device *_of_dev) +{ + int _errno, i, lenp; + struct device *dev; + struct device_node *mac_node, *dev_node; + struct mac_device *mac_dev; + struct platform_device *of_dev; + struct resource res; + const uint8_t *mac_addr; + const char *char_prop; + const phandle *phandle_prop; + const uint32_t *uint32_prop; + const struct of_device_id *match; + + dev = &_of_dev->dev; + mac_node = dev->of_node; + + match = of_match_device(mac_match, dev); + if (!match) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(mac_match) - 1 && match != mac_match + i; i++); + BUG_ON(i >= ARRAY_SIZE(mac_match) - 1); + + mac_dev = alloc_macdev(dev, mac_sizeof_priv[i], mac_setup[i]); + if (IS_ERR(mac_dev)) { + _errno = PTR_ERR(mac_dev); + dpaa_eth_err(dev, "alloc_macdev() = %d\n", _errno); + goto _return; + } + + INIT_LIST_HEAD(&mac_dev->mc_addr_list); + + /* Get the FM node */ + dev_node = of_get_parent(mac_node); + if (unlikely(dev_node == NULL)) { + dpaa_eth_err(dev, "of_get_parent(%s) failed\n", + mac_node->full_name); + _errno = -EINVAL; + goto _return_dev_set_drvdata; + } + + of_dev = of_find_device_by_node(dev_node); + if (unlikely(of_dev == NULL)) { + dpaa_eth_err(dev, "of_find_device_by_node(%s) failed\n", + dev_node->full_name); + _errno = -EINVAL; + goto _return_of_node_put; + } + + mac_dev->fm_dev = fm_bind(&of_dev->dev); + if (unlikely(mac_dev->fm_dev == NULL)) { + dpaa_eth_err(dev, "fm_bind(%s) failed\n", dev_node->full_name); + _errno = -ENODEV; + goto _return_of_node_put; + } + + mac_dev->fm = (void *)fm_get_handle(mac_dev->fm_dev); + of_node_put(dev_node); + + /* Get the address of the memory mapped registers */ + _errno = of_address_to_resource(mac_node, 0, &res); + if (unlikely(_errno < 0)) { + dpaa_eth_err(dev, "of_address_to_resource(%s) = %d\n", + mac_node->full_name, _errno); + goto _return_dev_set_drvdata; + } + + mac_dev->res = __devm_request_region( + dev, + fm_get_mem_region(mac_dev->fm_dev), + res.start, res.end + 1 - res.start, "mac"); + if (unlikely(mac_dev->res == NULL)) { + dpaa_eth_err(dev, "__devm_request_mem_region(mac) failed\n"); + _errno = -EBUSY; + goto _return_dev_set_drvdata; + } + + mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start, + mac_dev->res->end + 1 - mac_dev->res->start); + if (unlikely(mac_dev->vaddr == NULL)) { + dpaa_eth_err(dev, "devm_ioremap() failed\n"); + _errno = -EIO; + goto _return_dev_set_drvdata; + } + + /* + * XXX: Warning, future versions of Linux will most likely not even + * call the driver code to allow us to override the TBIPA value, + * we'll need to address this when we move to newer kernel rev + */ +#define TBIPA_OFFSET 0x1c +#define TBIPA_DEFAULT_ADDR 5 + mac_dev->tbi_node = of_parse_phandle(mac_node, "tbi-handle", 0); + if (mac_dev->tbi_node) { + u32 tbiaddr = TBIPA_DEFAULT_ADDR; + + uint32_prop = of_get_property(mac_dev->tbi_node, "reg", NULL); + if (uint32_prop) + tbiaddr = *uint32_prop; + out_be32(mac_dev->vaddr + TBIPA_OFFSET, tbiaddr); + } + + if (!of_device_is_available(mac_node)) { + devm_iounmap(dev, mac_dev->vaddr); + __devm_release_region(dev, fm_get_mem_region(mac_dev->fm_dev), + res.start, res.end + 1 - res.start); + fm_unbind(mac_dev->fm_dev); + devm_kfree(dev, mac_dev); + dev_set_drvdata(dev, NULL); + return -ENODEV; + } + + /* Get the cell-index */ + uint32_prop = of_get_property(mac_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + dpaa_eth_err(dev, "of_get_property(%s, cell-index) failed\n", + mac_node->full_name); + _errno = -EINVAL; + goto _return_dev_set_drvdata; + } + BUG_ON(lenp != sizeof(uint32_t)); + mac_dev->cell_index = *uint32_prop; + + /* Get the MAC address */ + mac_addr = of_get_mac_address(mac_node); + if (unlikely(mac_addr == NULL)) { + dpaa_eth_err(dev, "of_get_mac_address(%s) failed\n", + mac_node->full_name); + _errno = -EINVAL; + goto _return_dev_set_drvdata; + } + memcpy(mac_dev->addr, mac_addr, sizeof(mac_dev->addr)); + + /* Get the port handles */ + phandle_prop = of_get_property(mac_node, "fsl,port-handles", &lenp); + if (unlikely(phandle_prop == NULL)) { + dpaa_eth_err(dev, "of_get_property(%s, port-handles) failed\n", + mac_node->full_name); + _errno = -EINVAL; + goto _return_dev_set_drvdata; + } + BUG_ON(lenp != sizeof(phandle) * ARRAY_SIZE(mac_dev->port_dev)); + + for_each_port_device(i, mac_dev->port_dev) { + /* Find the port node */ + dev_node = of_find_node_by_phandle(phandle_prop[i]); + if (unlikely(dev_node == NULL)) { + dpaa_eth_err(dev, "of_find_node_by_phandle() failed\n"); + _errno = -EINVAL; + goto _return_of_node_put; + } + + of_dev = of_find_device_by_node(dev_node); + if (unlikely(of_dev == NULL)) { + dpaa_eth_err(dev, "of_find_device_by_node(%s) failed\n", + dev_node->full_name); + _errno = -EINVAL; + goto _return_of_node_put; + } + + mac_dev->port_dev[i] = fm_port_bind(&of_dev->dev); + if (unlikely(mac_dev->port_dev[i] == NULL)) { + dpaa_eth_err(dev, "dev_get_drvdata(%s) failed\n", + dev_node->full_name); + _errno = -EINVAL; + goto _return_of_node_put; + } + of_node_put(dev_node); + } + + /* Get the PHY connection type */ + char_prop = (const char *)of_get_property(mac_node, + "phy-connection-type", NULL); + if (unlikely(char_prop == NULL)) { + dpaa_eth_warning(dev, + "of_get_property(%s, phy-connection-type) " + "failed. Defaulting to MII\n", + mac_node->full_name); + mac_dev->phy_if = PHY_INTERFACE_MODE_MII; + } else + mac_dev->phy_if = str2phy(char_prop); + + mac_dev->link = false; + mac_dev->half_duplex = false; + mac_dev->speed = phy2speed[mac_dev->phy_if]; + mac_dev->max_speed = mac_dev->speed; + mac_dev->if_support = DTSEC_SUPPORTED; + /* We don't support half-duplex in SGMII mode */ + if (strstr(char_prop, "sgmii")) + mac_dev->if_support &= ~(SUPPORTED_10baseT_Half | + SUPPORTED_100baseT_Half); + + /* Gigabit support (no half-duplex) */ + if (mac_dev->max_speed == 1000) + mac_dev->if_support |= SUPPORTED_1000baseT_Full; + + /* The 10G interface only supports one mode */ + if (strstr(char_prop, "xgmii")) + mac_dev->if_support = SUPPORTED_10000baseT_Full; + + /* Get the rest of the PHY information */ + mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0); + if (mac_dev->phy_node == NULL) { + int sz; + const u32 *phy_id = of_get_property(mac_node, "fixed-link", + &sz); + if (!phy_id || sz < sizeof(*phy_id)) { + cpu_dev_err(dev, "No PHY (or fixed link) found\n"); + _errno = -EINVAL; + goto _return_dev_set_drvdata; + } + + sprintf(mac_dev->fixed_bus_id, PHY_ID_FMT, "0", phy_id[0]); + } + + _errno = mac_dev->init(mac_dev); + if (unlikely(_errno < 0)) { + dpaa_eth_err(dev, "mac_dev->init() = %d\n", _errno); + goto _return_dev_set_drvdata; + } + + cpu_dev_info(dev, + "FMan MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", + mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2], + mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]); + + goto _return; + +_return_of_node_put: + of_node_put(dev_node); +_return_dev_set_drvdata: + dev_set_drvdata(dev, NULL); +_return: + return _errno; +} + +static int __cold mac_remove(struct platform_device *of_dev) +{ + int i, _errno; + struct device *dev; + struct mac_device *mac_dev; + + dev = &of_dev->dev; + mac_dev = (struct mac_device *)dev_get_drvdata(dev); + + for_each_port_device(i, mac_dev->port_dev) + fm_port_unbind(mac_dev->port_dev[i]); + + fm_unbind(mac_dev->fm_dev); + + _errno = free_macdev(mac_dev); + + return _errno; +} + +static struct platform_driver mac_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = mac_match, + .owner = THIS_MODULE, + }, + .probe = mac_probe, + .remove = mac_remove, +}; + +static int __init __cold mac_load(void) +{ + int _errno; + + cpu_pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", __file__, __func__); + + cpu_pr_info(KBUILD_MODNAME ": %s (" VERSION ")\n", mac_driver_description); + + _errno = platform_driver_register(&mac_driver); + if (unlikely(_errno < 0)) { + cpu_pr_err(KBUILD_MODNAME ": %s:%hu:%s(): of_register_platform_driver() = %d\n", + __file__, __LINE__, __func__, _errno); + goto _return; + } + + goto _return; + +_return: + cpu_pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", __file__, __func__); + + return _errno; +} +module_init(mac_load); + +static void __exit __cold mac_unload(void) +{ + cpu_pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", __file__, __func__); + + platform_driver_unregister(&mac_driver); + + cpu_pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", __file__, __func__); +} +module_exit(mac_unload); --- linux-3.13.0.orig/drivers/net/dpa/offline_port.h +++ linux-3.13.0/drivers/net/dpa/offline_port.h @@ -0,0 +1,45 @@ +/* + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __OFFLINE_PORT_H +#define __OFFLINE_PORT_H + +#include "fsl_fman.h" + +/* OH port configuration */ +struct dpa_oh_config_s { + uint32_t error_fqid; + uint32_t default_fqid; + struct fm_port *oh_port; +}; + +#endif /* __OFFLINE_PORT_H */ --- linux-3.13.0.orig/drivers/net/dpa/dpaa_1588.h +++ linux-3.13.0/drivers/net/dpa/dpaa_1588.h @@ -0,0 +1,141 @@ +/* + * drivers/net/dpa/dpaa_1588.h + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef __DPAA_1588_H__ +#define __DPAA_1588_H__ + +#include +#include +#include +#include + +#define DEFAULT_PTP_RX_BUF_SZ 2048 +#define DEFAULT_PTP_TX_BUF_SZ 512 + +/* 1588 private ioctl calls */ +#define PTP_ENBL_TXTS_IOCTL SIOCDEVPRIVATE +#define PTP_DSBL_TXTS_IOCTL (SIOCDEVPRIVATE + 1) +#define PTP_ENBL_RXTS_IOCTL (SIOCDEVPRIVATE + 2) +#define PTP_DSBL_RXTS_IOCTL (SIOCDEVPRIVATE + 3) +#define PTP_GET_TX_TIMESTAMP (SIOCDEVPRIVATE + 4) +#define PTP_GET_RX_TIMESTAMP (SIOCDEVPRIVATE + 5) +#define PTP_SET_TIME (SIOCDEVPRIVATE + 6) +#define PTP_GET_TIME (SIOCDEVPRIVATE + 7) +#define PTP_SET_FIPER_ALARM (SIOCDEVPRIVATE + 8) +#define PTP_SET_ADJ (SIOCDEVPRIVATE + 9) +#define PTP_GET_ADJ (SIOCDEVPRIVATE + 10) +#define PTP_CLEANUP_TS (SIOCDEVPRIVATE + 11) + +/* PTP V2 message type */ +enum { + PTP_MSGTYPE_SYNC = 0x0, + PTP_MSGTYPE_DELREQ = 0x1, + PTP_MSGTYPE_PDELREQ = 0x2, + PTP_MSGTYPE_PDELRESP = 0x3, + PTP_MSGTYPE_FLWUP = 0x8, + PTP_MSGTYPE_DELRESP = 0x9, + PTP_MSGTYPE_PDELRES_FLWUP = 0xA, + PTP_MSGTYPE_ANNOUNCE = 0xB, + PTP_MSGTYPE_SGNLNG = 0xC, + PTP_MSGTYPE_MNGMNT = 0xD, +}; + +/* Byte offset of data in the PTP V2 headers */ +#define PTP_OFFS_MSG_TYPE 0 +#define PTP_OFFS_VER_PTP 1 +#define PTP_OFFS_MSG_LEN 2 +#define PTP_OFFS_DOM_NMB 4 +#define PTP_OFFS_FLAGS 6 +#define PTP_OFFS_CORFIELD 8 +#define PTP_OFFS_SRCPRTID 20 +#define PTP_OFFS_SEQ_ID 30 +#define PTP_OFFS_CTRL 32 +#define PTP_OFFS_LOGMEAN 33 + +#define PTP_IP_OFFS 14 +#define PTP_UDP_OFFS 34 +#define PTP_HEADER_OFFS 42 +#define PTP_MSG_TYPE_OFFS (PTP_HEADER_OFFS + PTP_OFFS_MSG_TYPE) +#define PTP_SPORT_ID_OFFS (PTP_HEADER_OFFS + PTP_OFFS_SRCPRTID) +#define PTP_SEQ_ID_OFFS (PTP_HEADER_OFFS + PTP_OFFS_SEQ_ID) +#define PTP_CTRL_OFFS (PTP_HEADER_OFFS + PTP_OFFS_CTRL) + +/* 1588-2008 network protocol enumeration values */ +#define DPA_PTP_PROT_IPV4 1 +#define DPA_PTP_PROT_IPV6 2 +#define DPA_PTP_PROT_802_3 3 +#define DPA_PTP_PROT_DONTCARE 0xFFFF + +#define DPA_PTP_SOURCE_PORT_LENGTH 10 +#define DPA_PTP_HEADER_SZE 34 +#define DPA_ETYPE_LEN 2 +#define DPA_VLAN_TAG_LEN 4 + +#define DPA_PTP_TIMESTAMP_OFFSET 0x30 +#define DPA_PTP_NOMINAL_FREQ_PERIOD 0xa /* 10ns -> 100M */ +#define NANOSEC_PER_SECOND 1000000000 + +/* Struct needed to identify a timestamp */ +struct dpa_ptp_ident { + u8 version; + u8 msg_type; + u16 netw_prot; + u16 seq_id; + u8 snd_port_id[DPA_PTP_SOURCE_PORT_LENGTH]; +}; + +/* Timestamp format in 1588-2008 */ +struct dpa_ptp_time { + u64 sec; /* just 48 bit used */ + u32 nsec; +}; + +/* needed for timestamp data over ioctl */ +struct dpa_ptp_data { + struct dpa_ptp_ident ident; + struct dpa_ptp_time ts; +}; + +struct dpa_ptp_circ_buf { + struct circ_buf circ_buf; + u32 size; + spinlock_t ptp_lock; +}; + +/* PTP TSU control structure */ +struct dpa_ptp_tsu { + struct dpa_priv_s *dpa_priv; + bool valid; + struct dpa_ptp_circ_buf rx_timestamps; + struct dpa_ptp_circ_buf tx_timestamps; + + /* HW timestamping over ioctl enabled flag */ + int hwts_tx_en_ioctl; + int hwts_rx_en_ioctl; +}; + +extern int dpa_ptp_init(struct dpa_priv_s *priv); +extern void dpa_ptp_cleanup(struct dpa_priv_s *priv); +extern void dpa_ptp_store_txstamp(struct net_device *dev, struct sk_buff *skb, + const struct qm_fd *fd); +extern void dpa_ptp_store_rxstamp(struct net_device *dev, struct sk_buff *skb, + const struct qm_fd *fd); +extern int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd); +#endif --- linux-3.13.0.orig/drivers/net/dpa/dpaa_eth-common.h +++ linux-3.13.0/drivers/net/dpa/dpaa_eth-common.h @@ -0,0 +1,150 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DPA_COMMON_H +#define __DPA_COMMON_H + +#include /* pr_*() */ +#include /* dev_*() */ +#include /* smp_processor_id() */ + +/* The basename of the source file is being compiled */ +#define __file__ KBUILD_BASENAME".c" + +#define __hot + +#define cpu_printk(level, format, arg...) \ + pr_##level("cpu%d: " format, smp_processor_id(), ##arg) + +#define cpu_pr_emerg(format, arg...) \ + cpu_printk(emerg, format, ##arg) +#define cpu_pr_alert(format, arg...) \ + cpu_printk(alert, format, ##arg) +#define cpu_pr_crit(format, arg...) \ + cpu_printk(crit, format, ##arg) +#define cpu_pr_err(format, arg...) \ + cpu_printk(err, format, ##arg) +#define cpu_pr_warning(format, arg...) \ + cpu_printk(warning, format, ##arg) +#define cpu_pr_notice(format, arg...) \ + cpu_printk(notice, format, ##arg) +#define cpu_pr_info(format, arg...) \ + cpu_printk(info, format, ##arg) +#define cpu_pr_debug(format, arg...) \ + cpu_printk(debug, format, ##arg) + +/* Keep this in sync with the dev_*() definitions from linux/device.h */ +#define cpu_dev_printk(level, dev, format, arg...) \ + cpu_pr_##level("%s: %s: " format, dev_driver_string(dev), \ + dev_name(dev), ##arg) + +#define cpu_dev_emerg(dev, format, arg...) \ + cpu_dev_printk(emerg, dev, format, ##arg) +#define cpu_dev_alert(dev, format, arg...) \ + cpu_dev_printk(alert, dev, format, ##arg) +#define cpu_dev_crit(dev, format, arg...) \ + cpu_dev_printk(crit, dev, format, ##arg) +#define cpu_dev_err(dev, format, arg...) \ + cpu_dev_printk(err, dev, format, ##arg) +#define cpu_dev_warn(dev, format, arg...) \ + cpu_dev_printk(warning, dev, format, ##arg) +#define cpu_dev_notice(dev, format, arg...) \ + cpu_dev_printk(notice, dev, format, ##arg) +#define cpu_dev_info(dev, format, arg...) \ + cpu_dev_printk(info, dev, format, ##arg) +#define cpu_dev_dbg(dev, format, arg...) \ + cpu_dev_printk(debug, dev, format, ##arg) + +#define dpaa_eth_printk(level, dev, format, arg...) \ + cpu_dev_printk(level, dev, "%s:%hu:%s() " format, \ + __file__, __LINE__, __func__, ##arg) + +#define dpaa_eth_emerg(dev, format, arg...) \ + dpaa_eth_printk(emerg, dev, format, ##arg) +#define dpaa_eth_alert(dev, format, arg...) \ + dpaa_eth_printk(alert, dev, format, ##arg) +#define dpaa_eth_crit(dev, format, arg...) \ + dpaa_eth_printk(crit, dev, format, ##arg) +#define dpaa_eth_err(dev, format, arg...) \ + dpaa_eth_printk(err, dev, format, ##arg) +#define dpaa_eth_warning(dev, format, arg...) \ + dpaa_eth_printk(warning, dev, format, ##arg) +#define dpaa_eth_notice(dev, format, arg...) \ + dpaa_eth_printk(notice, dev, format, ##arg) +#define dpaa_eth_info(dev, format, arg...) \ + dpaa_eth_printk(info, dev, format, ##arg) +#define dpaa_eth_debug(dev, format, arg...) \ + dpaa_eth_printk(debug, dev, format, ##arg) + +#define cpu_netdev_emerg(net_dev, format, arg...) \ + dpaa_eth_emerg((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) +#define cpu_netdev_alert(net_dev, format, arg...) \ + dpaa_eth_alert((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) +#define cpu_netdev_crit(net_dev, format, arg...) \ + dpaa_eth_crit((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) +#define cpu_netdev_err(net_dev, format, arg...) \ + dpaa_eth_err((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) +#define cpu_netdev_warn(net_dev, format, arg...) \ + dpaa_eth_warning((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) +#define cpu_netdev_notice(net_dev, format, arg...) \ + dpaa_eth_notice((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) +#define cpu_netdev_info(net_dev, format, arg...) \ + dpaa_eth_info((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) +#define cpu_netdev_dbg(net_dev, format, arg...) \ + dpaa_eth_debug((net_dev)->dev.parent, "%s: " format, \ + (net_dev)->name , ##arg) + +enum {RX, TX}; + +#define DPA_PRIV_DATA_SIZE 16 +#define DPA_PARSE_RESULTS_SIZE sizeof(t_FmPrsResult) +#define DPA_HASH_RESULTS_SIZE 16 + +#define dpaa_eth_init_port(type, port, param, errq_id, defq_id, has_timer) \ +{ \ + param.errq = errq_id; \ + param.defq = defq_id; \ + param.priv_data_size = DPA_PRIV_DATA_SIZE; \ + param.parse_results = true; \ + param.hash_results = true; \ + param.time_stamp = has_timer; \ + fm_set_##type##_port_params(port, ¶m); \ +} + +#endif /* __DPA_COMMON_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/ncsw_config.mk +++ linux-3.13.0/drivers/net/dpa/NetCommSw/ncsw_config.mk @@ -0,0 +1,34 @@ +# +# Makefile config for the Freescale NetcommSW +# +NET_DPA = $(srctree)/drivers/net/ethernet/freescale +DRV_DPA = $(srctree)/drivers/net/dpa +NCSW = $(srctree)/drivers/net/dpa/NetCommSw + +ifdef CONFIG_FMAN_P3040_P4080_P5020 +EXTRA_CFLAGS +=-include $(NCSW)/p3040_4080_5020_dflags.h +endif +ifdef CONFIG_FMAN_P1023 +EXTRA_CFLAGS +=-include $(NCSW)/p1023_dflags.h +endif + +EXTRA_CFLAGS += -I$(DRV_DPA)/ +EXTRA_CFLAGS += -I$(NCSW)/inc +EXTRA_CFLAGS += -I$(NCSW)/inc/cores +EXTRA_CFLAGS += -I$(NCSW)/inc/etc +EXTRA_CFLAGS += -I$(NCSW)/inc/Peripherals + +ifdef CONFIG_FMAN_P3040_P4080_P5020 +EXTRA_CFLAGS += -I$(NCSW)/inc/integrations/P3040_P4080_P5020 +endif +ifdef CONFIG_FMAN_P1023 +EXTRA_CFLAGS += -I$(NCSW)/inc/integrations/P1023 +endif + +EXTRA_CFLAGS += -I$(NCSW)/src/inc +EXTRA_CFLAGS += -I$(NCSW)/src/inc/system +EXTRA_CFLAGS += -I$(NCSW)/src/inc/wrapper +EXTRA_CFLAGS += -I$(NCSW)/src/inc/xx +EXTRA_CFLAGS += -I$(srctree)/include/linux/fmd +EXTRA_CFLAGS += -I$(srctree)/include/linux/fmd/Peripherals +EXTRA_CFLAGS += -I$(srctree)/include/linux/fmd/integrations --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk +# +obj-y += etc/ +obj-${CONFIG_FMAN_P3040_P4080_P5020} += integrations/P3040_P4080_P5020/ +obj-${CONFIG_FMAN_P1023} += integrations/P1023/ +obj-y += Peripherals/FM/ +obj-y += src/ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Kconfig +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Kconfig @@ -0,0 +1,57 @@ +menu "Frame Manager support" + +menuconfig FSL_FMAN + bool "Freescale Frame Manager (datapath) support" + # depends on PPC_E500MC + default y + ---help--- + If unsure, say Y. + +if FSL_FMAN + +config FSL_FMAN_TEST + bool "FMan test module" + default n + ---help--- + This option compiles test code for FMan. + +menu "FMAN Processor support" +choice + depends on FSL_FMAN + prompt "Processor Type" + +config FMAN_P3040_P4080_P5020 + bool "P3040 P4080 5020" + +config FMAN_P1023 + bool "P1023" + +endchoice +endmenu + +config FMAN_RESOURCE_ALLOCATION_ALGORITHM + bool "Enable FMan dynamic resource allocation algorithm" + default n + ---help--- + Enables algorithm for dynamic resource allocation + +config FMAN_DISABLE_OH_TO_REUSE_RESOURCES + depends on FMAN_RESOURCE_ALLOCATION_ALGORITHM + bool "Disable offline parsing ports to reuse resources" + default n + ---help--- + Redistributes FMan OH's resources to all other ports, + thus enabling other configurations. + +config FMAN_MIB_CNT_OVF_IRQ_EN + bool "Enable the dTSEC MIB counters overflow interrupt" + default n + ---help--- + Enable the dTSEC MIB counters overflow interrupt to get + accurate MIB counters values. Enabled it compensates + for the counters overflow but reduces performance and + triggers error messages in HV setups. + +endif # FSL_FMAN + +endmenu --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/p3040_4080_5020_dflags.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/p3040_4080_5020_dflags.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __dflags_h +#define __dflags_h + + +#define NCSW_LINUX + +#define P4080 +#define NCSW_PPC_CORE + +#define DEBUG_ERRORS 1 + +#if defined(DEBUG) +#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO + +#define DEBUG_XX_MALLOC +#define DEBUG_MEM_LEAKS + +#else +#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_MAJOR +#endif /* (DEBUG) */ + +#define REPORT_EVENTS 0 +#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR + +#ifdef CONFIG_P4080_SIM +#define SIMULATOR +#endif /* CONFIG_P4080_SIM */ + + +#endif /* __dflags_h */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/p1023_dflags.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/p1023_dflags.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __dflags_h +#define __dflags_h + + +#define NCSW_LINUX +#if 0 +#define DEBUG +#endif + +#define P1023 +#define NCSW_PPC_CORE + +#define DEBUG_ERRORS 1 + +#if defined(DEBUG) +#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO + +#define DEBUG_XX_MALLOC +#define DEBUG_MEM_LEAKS + +#else +#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING +#endif /* (DEBUG) */ + +#define REPORT_EVENTS 1 +#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR + +#ifdef CONFIG_P4080_SIM +#error "Do not define CONFIG_P4080_SIM..." +#endif + + +#endif /* __dflags_h */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/endian_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/endian_ext.h @@ -0,0 +1,446 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + + @File endian_ext.h + + @Description Big/little endian swapping routines. +*//***************************************************************************/ + +#ifndef __ENDIAN_EXT_H +#define __ENDIAN_EXT_H + +#include "std_ext.h" + + +/**************************************************************************//** + @Group gen_id General Drivers Utilities + + @Description General usage API. This API is intended for usage by both the + internal modules and the user's application. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group endian_id Big/Little-Endian Conversion + + @Description Routines and macros for Big/Little-Endian conversion and + general byte swapping. + + All routines and macros are expecting unsigned values as + parameters, but will generate the correct result also for + signed values. Therefore, signed/unsigned casting is allowed. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection Byte-Swap Macros + + Macros for swapping byte order. + + @Cautions The parameters of these macros are evaluated multiple times. + For calculated expressions or expressions that contain function + calls it is recommended to use the byte-swap routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description Swaps the byte order of a given 16-bit value. + + @Param[in] val - The 16-bit value to swap. + + @Return The byte-swapped value.. + + @Cautions The given value is evaluated multiple times by this macro. + For calculated expressions or expressions that contain function + calls it is recommended to use the SwapUint16() routine. + + @hideinitializer +*//***************************************************************************/ +#define SWAP_UINT16(val) \ + ((uint16_t)((((val) & 0x00FF) << 8) | (((val) & 0xFF00) >> 8))) + +/**************************************************************************//** + @Description Swaps the byte order of a given 32-bit value. + + @Param[in] val - The 32-bit value to swap. + + @Return The byte-swapped value.. + + @Cautions The given value is evaluated multiple times by this macro. + For calculated expressions or expressions that contain function + calls it is recommended to use the SwapUint32() routine. + + @hideinitializer +*//***************************************************************************/ +#define SWAP_UINT32(val) \ + ((uint32_t)((((val) & 0x000000FF) << 24) | \ + (((val) & 0x0000FF00) << 8) | \ + (((val) & 0x00FF0000) >> 8) | \ + (((val) & 0xFF000000) >> 24))) + +/**************************************************************************//** + @Description Swaps the byte order of a given 64-bit value. + + @Param[in] val - The 64-bit value to swap. + + @Return The byte-swapped value.. + + @Cautions The given value is evaluated multiple times by this macro. + For calculated expressions or expressions that contain function + calls it is recommended to use the SwapUint64() routine. + + @hideinitializer +*//***************************************************************************/ +#define SWAP_UINT64(val) \ + ((uint64_t)((((val) & 0x00000000000000FFULL) << 56) | \ + (((val) & 0x000000000000FF00ULL) << 40) | \ + (((val) & 0x0000000000FF0000ULL) << 24) | \ + (((val) & 0x00000000FF000000ULL) << 8) | \ + (((val) & 0x000000FF00000000ULL) >> 8) | \ + (((val) & 0x0000FF0000000000ULL) >> 24) | \ + (((val) & 0x00FF000000000000ULL) >> 40) | \ + (((val) & 0xFF00000000000000ULL) >> 56))) + +/* @} */ + +/**************************************************************************//** + @Collection Byte-Swap Routines + + Routines for swapping the byte order of a given parameter and + returning the swapped value. + + These inline routines are safer than the byte-swap macros, + because they evaluate the parameter expression only once. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function SwapUint16 + + @Description Returns the byte-swapped value of a given 16-bit value. + + @Param[in] val - The 16-bit value. + + @Return The byte-swapped value of the parameter. +*//***************************************************************************/ +static __inline__ uint16_t SwapUint16(uint16_t val) +{ + return (uint16_t)(((val & 0x00FF) << 8) | + ((val & 0xFF00) >> 8)); +} + +/**************************************************************************//** + @Function SwapUint32 + + @Description Returns the byte-swapped value of a given 32-bit value. + + @Param[in] val - The 32-bit value. + + @Return The byte-swapped value of the parameter. +*//***************************************************************************/ +static __inline__ uint32_t SwapUint32(uint32_t val) +{ + return (uint32_t)(((val & 0x000000FF) << 24) | + ((val & 0x0000FF00) << 8) | + ((val & 0x00FF0000) >> 8) | + ((val & 0xFF000000) >> 24)); +} + +/**************************************************************************//** + @Function SwapUint64 + + @Description Returns the byte-swapped value of a given 64-bit value. + + @Param[in] val - The 64-bit value. + + @Return The byte-swapped value of the parameter. +*//***************************************************************************/ +static __inline__ uint64_t SwapUint64(uint64_t val) +{ + return (uint64_t)(((val & 0x00000000000000FFULL) << 56) | + ((val & 0x000000000000FF00ULL) << 40) | + ((val & 0x0000000000FF0000ULL) << 24) | + ((val & 0x00000000FF000000ULL) << 8) | + ((val & 0x000000FF00000000ULL) >> 8) | + ((val & 0x0000FF0000000000ULL) >> 24) | + ((val & 0x00FF000000000000ULL) >> 40) | + ((val & 0xFF00000000000000ULL) >> 56)); +} + +/* @} */ + +/**************************************************************************//** + @Collection In-place Byte-Swap-And-Set Routines + + Routines for swapping the byte order of a given variable and + setting the swapped value back to the same variable. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function SwapUint16P + + @Description Swaps the byte order of a given 16-bit variable. + + @Param[in] p_Val - Pointer to the 16-bit variable. + + @Return None. +*//***************************************************************************/ +static __inline__ void SwapUint16P(uint16_t *p_Val) +{ + *p_Val = SwapUint16(*p_Val); +} + +/**************************************************************************//** + @Function SwapUint32P + + @Description Swaps the byte order of a given 32-bit variable. + + @Param[in] p_Val - Pointer to the 32-bit variable. + + @Return None. +*//***************************************************************************/ +static __inline__ void SwapUint32P(uint32_t *p_Val) +{ + *p_Val = SwapUint32(*p_Val); +} + +/**************************************************************************//** + @Function SwapUint64P + + @Description Swaps the byte order of a given 64-bit variable. + + @Param[in] p_Val - Pointer to the 64-bit variable. + + @Return None. +*//***************************************************************************/ +static __inline__ void SwapUint64P(uint64_t *p_Val) +{ + *p_Val = SwapUint64(*p_Val); +} + +/* @} */ + + +/**************************************************************************//** + @Collection Little-Endian Conversion Macros + + These macros convert given parameters to or from Little-Endian + format. Use these macros when you want to read or write a specific + Little-Endian value in memory, without a-priori knowing the CPU + byte order. + + These macros use the byte-swap routines. For conversion of + constants in initialization structures, you may use the CONST + versions of these macros (see below), which are using the + byte-swap macros instead. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description Converts a given 16-bit value from CPU byte order to + Little-Endian byte order. + + @Param[in] val - The 16-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CPU_TO_LE16(val) SwapUint16(val) + +/**************************************************************************//** + @Description Converts a given 32-bit value from CPU byte order to + Little-Endian byte order. + + @Param[in] val - The 32-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CPU_TO_LE32(val) SwapUint32(val) + +/**************************************************************************//** + @Description Converts a given 64-bit value from CPU byte order to + Little-Endian byte order. + + @Param[in] val - The 64-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CPU_TO_LE64(val) SwapUint64(val) + + +/**************************************************************************//** + @Description Converts a given 16-bit value from Little-Endian byte order to + CPU byte order. + + @Param[in] val - The 16-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define LE16_TO_CPU(val) CPU_TO_LE16(val) + +/**************************************************************************//** + @Description Converts a given 32-bit value from Little-Endian byte order to + CPU byte order. + + @Param[in] val - The 32-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define LE32_TO_CPU(val) CPU_TO_LE32(val) + +/**************************************************************************//** + @Description Converts a given 64-bit value from Little-Endian byte order to + CPU byte order. + + @Param[in] val - The 64-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define LE64_TO_CPU(val) CPU_TO_LE64(val) + +/* @} */ + +/**************************************************************************//** + @Collection Little-Endian Constant Conversion Macros + + These macros convert given constants to or from Little-Endian + format. Use these macros when you want to read or write a specific + Little-Endian constant in memory, without a-priori knowing the + CPU byte order. + + These macros use the byte-swap macros, therefore can be used for + conversion of constants in initialization structures. + + @Cautions The parameters of these macros are evaluated multiple times. + For non-constant expressions, use the non-CONST macro versions. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description Converts a given 16-bit constant from CPU byte order to + Little-Endian byte order. + + @Param[in] val - The 16-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CONST_CPU_TO_LE16(val) SWAP_UINT16(val) + +/**************************************************************************//** + @Description Converts a given 32-bit constant from CPU byte order to + Little-Endian byte order. + + @Param[in] val - The 32-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CONST_CPU_TO_LE32(val) SWAP_UINT32(val) + +/**************************************************************************//** + @Description Converts a given 64-bit constant from CPU byte order to + Little-Endian byte order. + + @Param[in] val - The 64-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CONST_CPU_TO_LE64(val) SWAP_UINT64(val) + + +/**************************************************************************//** + @Description Converts a given 16-bit constant from Little-Endian byte order + to CPU byte order. + + @Param[in] val - The 16-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CONST_LE16_TO_CPU(val) CONST_CPU_TO_LE16(val) + +/**************************************************************************//** + @Description Converts a given 32-bit constant from Little-Endian byte order + to CPU byte order. + + @Param[in] val - The 32-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CONST_LE32_TO_CPU(val) CONST_CPU_TO_LE32(val) + +/**************************************************************************//** + @Description Converts a given 64-bit constant from Little-Endian byte order + to CPU byte order. + + @Param[in] val - The 64-bit value to convert. + + @Return The converted value. + + @hideinitializer +*//***************************************************************************/ +#define CONST_LE64_TO_CPU(val) CONST_CPU_TO_LE64(val) + +/* @} */ + + +/** @} */ /* end of endian_id group */ +/** @} */ /* end of gen_id group */ + + +#endif /* __ENDIAN_EXT_H */ + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/xx_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/xx_ext.h @@ -0,0 +1,881 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File xx_ext.h + + @Description Prototypes, externals and typedefs for system-supplied + (external) routines +*//***************************************************************************/ + +#ifndef __XX_EXT_H +#define __XX_EXT_H + +#include "std_ext.h" +#include "part_ext.h" + +#if defined(__MWERKS__) && defined(OPTIMIZED_FOR_SPEED) +#include "xx_integration_ext.h" +#endif /* defined(__MWERKS__) && defined(OPTIMIZED_FOR_SPEED) */ + + +/**************************************************************************//** + @Group xx_id XX Interface (System call hooks) + + @Description Prototypes, externals and typedefs for system-supplied + (external) routines + + @{ +*//***************************************************************************/ + +#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0)) +/**************************************************************************//** + @Function XX_EventById + + @Description Event reporting routine - executed only when REPORT_EVENTS=1. + + @Param[in] event - Event code (e_Event). + @Param[in] appId - Application identifier. + @Param[in] flags - Event flags. + @Param[in] msg - Event message. + + @Return None +*//***************************************************************************/ +void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg); + +#else /* not REPORT_EVENTS */ +#define XX_EventById(event, appId, flags, msg) +#endif /* REPORT_EVENTS */ + + + +#ifdef DEBUG_XX_MALLOC +void * XX_MallocDebug(uint32_t size, char *fname, int line); + +void * XX_MallocSmartDebug(uint32_t size, + int memPartitionId, + uint32_t alignment, + char *fname, + int line); + +#define XX_Malloc(sz) \ + XX_MallocDebug((sz), __FILE__, __LINE__) + +#define XX_MallocSmart(sz, memt, al) \ + XX_MallocSmartDebug((sz), (memt), (al), __FILE__, __LINE__) + +#else /* not DEBUG_XX_MALLOC */ +/**************************************************************************//** + @Function XX_Malloc + + @Description allocates contiguous block of memory. + + @Param[in] size - Number of bytes to allocate. + + @Return The address of the newly allocated block on success, NULL on failure. +*//***************************************************************************/ +void * XX_Malloc(uint32_t size); + +/**************************************************************************//** + @Function XX_MallocSmart + + @Description Allocates contiguous block of memory in a specified + alignment and from the specified segment. + + @Param[in] size - Number of bytes to allocate. + @Param[in] memPartitionId - Memory partition ID; The value zero must + be mapped to the default heap partition. + @Param[in] alignment - Required memory alignment (in bytes). + + @Return The address of the newly allocated block on success, NULL on failure. +*//***************************************************************************/ +void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment); +#endif /* not DEBUG_XX_MALLOC */ + +/**************************************************************************//** + @Function XX_FreeSmart + + @Description Frees the memory block pointed to by "p". + Only for memory allocated by XX_MallocSmart + + @Param[in] p_Memory - pointer to the memory block. + + @Return None. +*//***************************************************************************/ +void XX_FreeSmart(void *p_Memory); + +/**************************************************************************//** + @Function XX_Free + + @Description frees the memory block pointed to by "p". + + @Param[in] p_Memory - pointer to the memory block. + + @Return None. +*//***************************************************************************/ +void XX_Free(void *p_Memory); + +#ifndef NCSW_LINUX +/**************************************************************************//** + @Function XX_GetMemPartitionBase + + @Description This routine gets the address of a memory segment according to + the memory type. + + @Param[in] memPartitionId - Memory partition ID; The value zero must + be mapped to the default heap partition. + + @Return The address of the required memory type. +*//***************************************************************************/ +void * XX_GetMemPartitionBase(int memPartitionId); +#endif + +/**************************************************************************//** + @Function XX_Print + + @Description print a string. + + @Param[in] str - string to print. + + @Return None. +*//***************************************************************************/ +void XX_Print(char *str, ...); + +/**************************************************************************//** + @Function XX_GetChar + + @Description Get character from console. + + @Return Character is returned on success. Zero is returned otherwise. +*//***************************************************************************/ +char XX_GetChar(void); + +/**************************************************************************//** + @Function XX_SetIntr + + @Description Set an interrupt service routine for a specific interrupt source. + + @Param[in] irq - Interrupt ID (system-specific number). + @Param[in] f_Isr - Callback routine that will be called when the interrupt occurs. + @Param[in] handle - The argument for the user callback routine. + + @Return E_OK on success; error code otherwise.. +*//***************************************************************************/ +t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle); + +/**************************************************************************//** + @Function XX_FreeIntr + + @Description Free a specific interrupt and a specific callback routine. + + @Param[in] irq - Interrupt ID (system-specific number). + + @Return E_OK on success; error code otherwise.. +*//***************************************************************************/ +t_Error XX_FreeIntr(int irq); + +/**************************************************************************//** + @Function XX_EnableIntr + + @Description Enable a specific interrupt. + + @Param[in] irq - Interrupt ID (system-specific number). + + @Return E_OK on success; error code otherwise.. +*//***************************************************************************/ +t_Error XX_EnableIntr(int irq); + +/**************************************************************************//** + @Function XX_DisableIntr + + @Description Disable a specific interrupt. + + @Param[in] irq - Interrupt ID (system-specific number). + + @Return E_OK on success; error code otherwise.. +*//***************************************************************************/ +t_Error XX_DisableIntr(int irq); + +#if !(defined(__MWERKS__) && defined(OPTIMIZED_FOR_SPEED)) +/**************************************************************************//** + @Function XX_DisableAllIntr + + @Description Disable all interrupts by masking them at the CPU. + + @Return A value that represents the interrupts state before the + operation, and should be passed to the matching + XX_RestoreAllIntr() call. +*//***************************************************************************/ +uint32_t XX_DisableAllIntr(void); + +/**************************************************************************//** + @Function XX_RestoreAllIntr + + @Description Restore previous state of interrupts level at the CPU. + + @Param[in] flags - A value that represents the interrupts state to restore, + as returned by the matching call for XX_DisableAllIntr(). + + @Return None. +*//***************************************************************************/ +void XX_RestoreAllIntr(uint32_t flags); +#endif /* !(defined(__MWERKS__) && defined(OPTIMIZED_FOR_SPEED)) */ + +/**************************************************************************//** + @Function XX_Call + + @Description Call a service in another task. + + Activate the routine "f" via the queue identified by "IntrManagerId". The + parameter to "f" is Id - the handle of the destination object + + @Param[in] intrManagerId - Queue ID. + @Param[in] f - routine pointer. + @Param[in] Id - the parameter to be passed to f(). + @Param[in] h_App - Application handle. + @Param[in] flags - Unused, + + @Return E_OK is returned on success. E_FAIL is returned otherwise (usually an operating system level failure). +*//***************************************************************************/ +t_Error XX_Call( uint32_t intrManagerId, + t_Error (* f)(t_Handle), + t_Handle Id, + t_Handle h_App, + uint16_t flags ); + +/**************************************************************************//** + @Function XX_Exit + + @Description Stop execution and report status (where it is applicable) + + @Param[in] status - exit status +*//***************************************************************************/ +void XX_Exit(int status); + +/*****************************************************************************/ +/* Tasklet Service Routines */ +/*****************************************************************************/ +typedef t_Handle t_TaskletHandle; + +/**************************************************************************//** + @Function XX_InitTasklet + + @Description Create and initialize a tasklet object. + + @Param[in] routine - A routine to be ran as a tasklet. + @Param[in] data - An argument to pass to the tasklet. + + @Return Tasklet handle is returned on success. NULL is returned otherwise. +*//***************************************************************************/ +t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data); + +/**************************************************************************//** + @Function XX_FreeTasklet + + @Description Free a tasklet object. + + @Param[in] h_Tasklet - A handle to a tasklet to be free. + + @Return None. +*//***************************************************************************/ +void XX_FreeTasklet (t_TaskletHandle h_Tasklet); + +/**************************************************************************//** + @Function XX_ScheduleTask + + @Description Schedule a tasklet object. + + @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. + @Param[in] immediate - Indicate whether to schedule this tasklet on + the immediate queue or on the delayed one. + + @Return 0 - on success. Error code - otherwise. +*//***************************************************************************/ +int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate); + +/**************************************************************************//** + @Function XX_FlushScheduledTasks + + @Description Flush all tasks there are in the scheduled tasks queue. + + @Return None. +*//***************************************************************************/ +void XX_FlushScheduledTasks(void); + +/**************************************************************************//** + @Function XX_TaskletIsQueued + + @Description Check if task is queued. + + @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. + + @Return 1 - task is queued. 0 - otherwise. +*//***************************************************************************/ +int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet); + +/**************************************************************************//** + @Function XX_SetTaskletData + + @Description Set data to a scheduled task. Used to change data of already + scheduled task. + + @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. + @Param[in] data - Data to be set. +*//***************************************************************************/ +void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data); + +/**************************************************************************//** + @Function XX_GetTaskletData + + @Description Get the data of scheduled task. + + @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. + + @Return handle to the data of the task. +*//***************************************************************************/ +t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet); + +/**************************************************************************//** + @Function XX_BottomHalf + + @Description Bottom half implementation, invoked by the interrupt handler. + + This routine handles all bottom-half tasklets with interrupts + enabled. + + @Return None. +*//***************************************************************************/ +void XX_BottomHalf(void); + + +/*****************************************************************************/ +/* Spinlock Service Routines */ +/*****************************************************************************/ + +/**************************************************************************//** + @Function XX_InitSpinlock + + @Description Creates a spinlock. + + @Return Spinlock handle is returned on success; NULL otherwise. +*//***************************************************************************/ +t_Handle XX_InitSpinlock(void); + +/**************************************************************************//** + @Function XX_FreeSpinlock + + @Description Frees the memory allocated for the spinlock creation. + + @Param[in] h_Spinlock - A handle to a spinlock. + + @Return None. +*//***************************************************************************/ +void XX_FreeSpinlock(t_Handle h_Spinlock); + +/**************************************************************************//** + @Function XX_LockSpinlock + + @Description Locks a spinlock. + + @Param[in] h_Spinlock - A handle to a spinlock. + + @Return None. +*//***************************************************************************/ +void XX_LockSpinlock(t_Handle h_Spinlock); + +/**************************************************************************//** + @Function XX_UnlockSpinlock + + @Description Unlocks a spinlock. + + @Param[in] h_Spinlock - A handle to a spinlock. + + @Return None. +*//***************************************************************************/ +void XX_UnlockSpinlock(t_Handle h_Spinlock); + +/**************************************************************************//** + @Function XX_LockIntrSpinlock + + @Description Locks a spinlock (interrupt safe). + + @Param[in] h_Spinlock - A handle to a spinlock. + + @Return A value that represents the interrupts state before the + operation, and should be passed to the matching + XX_UnlockIntrSpinlock() call. +*//***************************************************************************/ +uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock); + +/**************************************************************************//** + @Function XX_UnlockIntrSpinlock + + @Description Unlocks a spinlock (interrupt safe). + + @Param[in] h_Spinlock - A handle to a spinlock. + @Param[in] intrFlags - A value that represents the interrupts state to + restore, as returned by the matching call for + XX_LockIntrSpinlock(). + + @Return None. +*//***************************************************************************/ +void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags); + + +/*****************************************************************************/ +/* Timers Service Routines */ +/*****************************************************************************/ + +/**************************************************************************//** + @Function XX_CurrentTime + + @Description Returns current system time. + + @Return Current system time (in milliseconds). +*//***************************************************************************/ +uint32_t XX_CurrentTime(void); + +/**************************************************************************//** + @Function XX_CreateTimer + + @Description Creates a timer. + + @Return Timer handle is returned on success; NULL otherwise. +*//***************************************************************************/ +t_Handle XX_CreateTimer(void); + +/**************************************************************************//** + @Function XX_FreeTimer + + @Description Frees the memory allocated for the timer creation. + + @Param[in] h_Timer - A handle to a timer. + + @Return None. +*//***************************************************************************/ +void XX_FreeTimer(t_Handle h_Timer); + +/**************************************************************************//** + @Function XX_StartTimer + + @Description Starts a timer. + + The user can select to start the timer as periodic timer or as + one-shot timer. The user should provide a callback routine that + will be called when the timer expires. + + @Param[in] h_Timer - A handle to a timer. + @Param[in] msecs - Timer expiration period (in milliseconds). + @Param[in] periodic - TRUE for a periodic timer; + FALSE for a one-shot timer.. + @Param[in] f_TimerExpired - A callback routine to be called when the + timer expires. + @Param[in] h_Arg - The argument to pass in the timer-expired + callback routine. + + @Return None. +*//***************************************************************************/ +void XX_StartTimer(t_Handle h_Timer, + uint32_t msecs, + bool periodic, + void (*f_TimerExpired)(t_Handle h_Arg), + t_Handle h_Arg); + +/**************************************************************************//** + @Function XX_StopTimer + + @Description Frees the memory allocated for the timer creation. + + @Param[in] h_Timer - A handle to a timer. + + @Return None. +*//***************************************************************************/ +void XX_StopTimer(t_Handle h_Timer); + +/**************************************************************************//** + @Function XX_GetExpirationTime + + @Description Returns the time (in milliseconds) remaining until the + expiration of a timer. + + @Param[in] h_Timer - A handle to a timer. + + @Return The time left until the timer expires. +*//***************************************************************************/ +uint32_t XX_GetExpirationTime(t_Handle h_Timer); + +/**************************************************************************//** + @Function XX_ModTimer + + @Description Updates the expiration time of a timer. + + This routine adds the given time to the current system time, + and sets this value as the new expiration time of the timer. + + @Param[in] h_Timer - A handle to a timer. + @Param[in] msecs - The new interval until timer expiration + (in milliseconds). + + @Return None. +*//***************************************************************************/ +void XX_ModTimer(t_Handle h_Timer, uint32_t msecs); + +/**************************************************************************//** + @Function XX_TimerIsActive + + @Description Checks whether a timer is active (pending) or not. + + @Param[in] h_Timer - A handle to a timer. + + @Return 0 - the timer is inactive; Non-zero value - the timer is active; +*//***************************************************************************/ +int XX_TimerIsActive(t_Handle h_Timer); + +/**************************************************************************//** + @Function XX_Sleep + + @Description Non-busy wait until the desired time (in milliseconds) has passed. + + @Param[in] msecs - The requested sleep time (in milliseconds). + + @Return None. + + @Cautions This routine enables interrupts during its wait time. +*//***************************************************************************/ +uint32_t XX_Sleep(uint32_t msecs); + +/**************************************************************************//** + @Function XX_UDelay + + @Description Busy-wait until the desired time (in microseconds) has passed. + + @Param[in] usecs - The requested delay time (in microseconds). + + @Return None. + + @Cautions It is highly unrecommended to call this routine during interrupt + time, because the system time may not be updated properly during + the delay loop. The behavior of this routine during interrupt + time is unexpected. +*//***************************************************************************/ +void XX_UDelay(uint32_t usecs); + + +/*****************************************************************************/ +/* Other Service Routines */ +/*****************************************************************************/ + +/**************************************************************************//** + @Function XX_PhysToVirt + + @Description Translates a physical address to the matching virtual address. + + @Param[in] addr - The physical address to translate. + + @Return Virtual address. +*//***************************************************************************/ +void * XX_PhysToVirt(physAddress_t addr); + +/**************************************************************************//** + @Function XX_VirtToPhys + + @Description Translates a virtual address to the matching physical address. + + @Param[in] addr - The virtual address to translate. + + @Return Physical address. +*//***************************************************************************/ +physAddress_t XX_VirtToPhys(void *addr); + + +/**************************************************************************//** + @Group xx_ipc XX Inter-Partition-Communication API + + @Description The following API is to be used when working with multiple + partitions configuration. + + @{ +*//***************************************************************************/ + +#define XX_IPC_MAX_ADDR_NAME_LENGTH 16 /**< Maximum length of an endpoint name string; + The IPC service can use this constant to limit + the storage space for IPC endpoint names. */ + + +/**************************************************************************//** + @Function t_IpcMsgCompletion + + @Description Callback function used upon IPC non-blocking transaction completion + to return message buffer to the caller and to forward reply if available. + + This callback function may be attached by the source endpoint to any outgoing + IPC message to indicate a non-blocking send (see also XX_IpcSendMessage() routine). + Upon completion of an IPC transaction (consisting of a message and an optional reply), + the IPC service invokes this callback routine to return the message buffer to the sender + and to provide the received reply, if requested. + + User provides this function. Driver invokes it. + + @Param[in] h_Module - Abstract handle to the sending module - the same handle as was passed + in the XX_IpcSendMessage() function; This handle is typically used to point + to the internal data structure of the source endpoint. + @Param[in] p_Msg - Pointer to original (sent) message buffer; + The source endpoint can free (or reuse) this buffer when message + completion callback is called. + @Param[in] p_Reply - Pointer to (received) reply buffer; + This pointer is the same as was provided by the source endpoint in + XX_IpcSendMessage(). + @Param[in] replyLength - Length (in bytes) of actual data in the reply buffer. + @Param[in] status - Completion status - E_OK or failure indication, e.g. IPC transaction completion + timeout. + + @Return None + *//***************************************************************************/ +typedef void (t_IpcMsgCompletion)(t_Handle h_Module, + uint8_t *p_Msg, + uint8_t *p_Reply, + uint32_t replyLength, + t_Error status); + +/**************************************************************************//** + @Function t_IpcMsgHandler + + @Description Callback function used as IPC message handler. + + The IPC service invokes message handlers for each IPC message received. + The actual function pointer should be registered by each destination endpoint + via the XX_IpcRegisterMsgHandler() routine. + + User provides this function. Driver invokes it. + + @Param[in] h_Module - Abstract handle to the message handling module - the same handle as + was passed in the XX_IpcRegisterMsgHandler() function; this handle is + typically used to point to the internal data structure of the destination + endpoint. + @Param[in] p_Msg - Pointer to message buffer with data received from peer. + @Param[in] msgLength - Length (in bytes) of message data. + @Param[in] p_Reply - Pointer to reply buffer, to be filled by the message handler and then sent + by the IPC service; + The reply buffer is allocated by the IPC service with size equals to the + replyLength parameter provided in message handler registration (see + XX_IpcRegisterMsgHandler() function); + If replyLength was initially specified as zero during message handler registration, + the IPC service may set this pointer to NULL and assume that a reply is not needed; + The IPC service is also responsible for freeing the reply buffer after the + reply has been sent or dismissed. + @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function: + [In] equals the replyLength parameter provided in message handler + registration (see XX_IpcRegisterMsgHandler() function), and + [Out] should be updated by message handler to the actual reply length; if + this value is set to zero, the IPC service must assume that a reply should + not be sent; + Note: If p_Reply is not NULL, p_ReplyLength must not be NULL as well. + + @Return E_OK on success; Error code otherwise. + *//***************************************************************************/ +typedef t_Error (t_IpcMsgHandler)(t_Handle h_Module, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength); + +/**************************************************************************//** + @Function XX_IpcRegisterMsgHandler + + @Description IPC mailbox registration. + + This function is used for registering an IPC message handler in the IPC service. + This function is called by each destination endpoint to indicate that it is ready + to handle incoming messages. The IPC service invokes the message handler upon receiving + a message addressed to the specified destination endpoint. + + @Param[in] addr - The address name string associated with the destination endpoint; + This address must be unique across the IPC service domain to ensure + correct message routing. + @Param[in] f_MsgHandler - Pointer to the message handler callback for processing incoming + message; invoked by the IPC service upon receiving a message + addressed to the destination endpoint specified by the addr + parameter. + @Param[in] h_Module - Abstract handle to the message handling module, passed unchanged + to f_MsgHandler callback function. + @Param[in] replyLength - The maximal data length (in bytes) of any reply that the specified message handler + may generate; the IPC service provides the message handler with buffer + for reply according to the length specified here (refer also to the description + of #t_IpcMsgHandler callback function type); + This size shall be zero if the message handler never generates replies. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], + t_IpcMsgHandler *f_MsgHandler, + t_Handle h_Module, + uint32_t replyLength); + +/**************************************************************************//** + @Function XX_IpcUnregisterMsgHandler + + @Description Release IPC mailbox routine. + + This function is used for unregistering an IPC message handler from the IPC service. + This function is called by each destination endpoint to indicate that it is no longer + capable of handling incoming messages. + + @Param[in] addr - The address name string associated with the destination endpoint; + This address is the same as was used when the message handler was + registered via XX_IpcRegisterMsgHandler(). + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]); + +/**************************************************************************//** + @Function XX_IpcInitSession + + @Description This function is used for creating an IPC session between the source endpoint + and the destination endpoint. + + The actual implementation and representation of a session is left for the IPC service. + The function returns an abstract handle to the created session. This handle shall be used + by the source endpoint in subsequent calls to XX_IpcSendMessage(). + The IPC service assumes that before this function is called, no messages are sent from + the specified source endpoint to the specified destination endpoint. + + The IPC service may use a connection-oriented approach or a connectionless approach (or both) + as described below. + + @par Connection-Oriented Approach + + The IPC service may implement a session in a connection-oriented approach - when this function is called, + the IPC service should take the necessary steps to bring up a source-to-destination channel for messages + and a destination-to-source channel for replies. The returned handle should represent the internal + representation of these channels. + + @par Connectionless Approach + + The IPC service may implement a session in a connectionless approach - when this function is called, the + IPC service should not perform any particular steps, but it must store the pair of source and destination + addresses in some session representation and return it as a handle. When XX_IpcSendMessage() shall be + called, the IPC service may use this handle to provide the necessary identifiers for routing the messages + through the connectionless medium. + + @Param[in] destAddr - The address name string associated with the destination endpoint. + @Param[in] srcAddr - The address name string associated with the source endpoint. + + @Return Abstract handle to the initialized session, or NULL on error. +*//***************************************************************************/ +t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], + char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]); + +/**************************************************************************//** + @Function XX_IpcFreeSession + + @Description This function is used for terminating an existing IPC session between a source endpoint + and a destination endpoint. + + The IPC service assumes that after this function is called, no messages shall be sent from + the associated source endpoint to the associated destination endpoint. + + @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally + returned by the XX_IpcInitSession() function. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error XX_IpcFreeSession(t_Handle h_Session); + +/**************************************************************************//** + @Function XX_IpcSendMessage + + @Description IPC message send routine. + + This function may be used by a source endpoint to send an IPC message to a destination + endpoint. The source endpoint cannot send a message to the destination endpoint without + first initiating a session with that destination endpoint via XX_IpcInitSession() routine. + + The source endpoint must provide the buffer pointer and length of the outgoing message. + Optionally, it may also provide a buffer for an expected reply. In the latter case, the + transaction is not considered complete by the IPC service until the reply has been received. + If the source endpoint does not provide a reply buffer, the transaction is considered + complete after the message has been sent. The source endpoint must keep the message (and + optional reply) buffers valid until the transaction is complete. + + @par Non-blocking mode + + The source endpoint may request a non-blocking send by providing a non-NULL pointer to a message + completion callback function (f_Completion). Upon completion of the IPC transaction (consisting of a + message and an optional reply), the IPC service invokes this callback routine to return the message + buffer to the sender and to provide the received reply, if requested. + + @par Blocking mode + + The source endpoint may request a blocking send by setting f_Completion to NULL. The function is + expected to block until the IPC transaction is complete - either the reply has been received or (if no reply + was requested) the message has been sent. + + @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally + returned by the XX_IpcInitSession() function. + @Param[in] p_Msg - Pointer to message buffer to send. + @Param[in] msgLength - Length (in bytes) of actual data in the message buffer. + @Param[in] p_Reply - Pointer to reply buffer - if this buffer is not NULL, the IPC service + fills this buffer with the received reply data; + In blocking mode, the reply data must be valid when the function returns; + In non-blocking mode, the reply data is valid when f_Completion is called; + If this pointer is NULL, no reply is expected. + @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function: + [In] specifies the maximal length (in bytes) of the reply buffer pointed by + p_Reply, and + [Out] in non-blocking mode this value is updated by the IPC service to the + actual reply length (in bytes). + @Param[in] f_Completion - Pointer to a completion callback to be used in non-blocking send mode; + The completion callback is invoked by the IPC service upon + completion of the IPC transaction (consisting of a message and an optional + reply); + If this pointer is NULL, the function is expected to block until the IPC + transaction is complete. + @Param[in] h_Arg - Abstract handle to the sending module; passed unchanged to the f_Completion + callback function as the first argument. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error XX_IpcSendMessage(t_Handle h_Session, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength, + t_IpcMsgCompletion *f_Completion, + t_Handle h_Arg); + + +/** @} */ /* end of xx_ipc group */ +/** @} */ /* end of xx_id group */ + + +#endif /* __XX_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/enet_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/enet_ext.h @@ -0,0 +1,154 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File enet_ext.h + + @Description Ethernet generic definitions and enums. +*//***************************************************************************/ + +#ifndef __ENET_EXT_H +#define __ENET_EXT_H + + +#define ENET_NUM_OCTETS_PER_ADDRESS 6 /**< Number of octets (8-bit bytes) in an ethernet address */ +#define ENET_GROUP_ADDR 0x01 /**< Group address mask for ethernet addresses */ + + +/**************************************************************************//** + @Description Ethernet Address +*//***************************************************************************/ +typedef uint8_t t_EnetAddr[ENET_NUM_OCTETS_PER_ADDRESS]; + +/**************************************************************************//** + @Description Ethernet Address Type. +*//***************************************************************************/ +typedef enum e_EnetAddrType +{ + e_ENET_ADDR_TYPE_INDIVIDUAL, /**< Individual (unicast) address */ + e_ENET_ADDR_TYPE_GROUP, /**< Group (multicast) address */ + e_ENET_ADDR_TYPE_BROADCAST /**< Broadcast address */ +} e_EnetAddrType; + + +/**************************************************************************//** + @Description Ethernet MAC-PHY Interface +*//***************************************************************************/ +typedef enum e_EnetInterface +{ + e_ENET_IF_MII = 0x00010000, /**< MII interface */ + e_ENET_IF_RMII = 0x00020000, /**< RMII interface */ + e_ENET_IF_SMII = 0x00030000, /**< SMII interface */ + e_ENET_IF_GMII = 0x00040000, /**< GMII interface */ + e_ENET_IF_RGMII = 0x00050000, /**< RGMII interface */ + e_ENET_IF_TBI = 0x00060000, /**< TBI interface */ + e_ENET_IF_RTBI = 0x00070000, /**< RTBI interface */ + e_ENET_IF_SGMII = 0x00080000, /**< SGMII interface */ + e_ENET_IF_XGMII = 0x00090000, /**< XGMII interface */ + e_ENET_IF_QSGMII= 0x000a0000 /**< QSGMII interface */ +} e_EnetInterface; + +/**************************************************************************//** + @Description Ethernet Duplex Mode +*//***************************************************************************/ +typedef enum e_EnetDuplexMode +{ + e_ENET_HALF_DUPLEX, /**< Half-Duplex mode */ + e_ENET_FULL_DUPLEX /**< Full-Duplex mode */ +} e_EnetDuplexMode; + +/**************************************************************************//** + @Description Ethernet Speed (nominal data rate) +*//***************************************************************************/ +typedef enum e_EnetSpeed +{ + e_ENET_SPEED_10 = 10, /**< 10 Mbps */ + e_ENET_SPEED_100 = 100, /**< 100 Mbps */ + e_ENET_SPEED_1000 = 1000, /**< 1000 Mbps = 1 Gbps */ + e_ENET_SPEED_10000 = 10000 /**< 10000 Mbps = 10 Gbps */ +} e_EnetSpeed; + +/**************************************************************************//** + @Description Ethernet mode (combination of MAC-PHY interface and speed) +*//***************************************************************************/ +typedef enum e_EnetMode +{ + e_ENET_MODE_INVALID = 0, /**< Invalid Ethernet mode */ + e_ENET_MODE_MII_10 = (e_ENET_IF_MII | e_ENET_SPEED_10), /**< 10 Mbps MII */ + e_ENET_MODE_MII_100 = (e_ENET_IF_MII | e_ENET_SPEED_100), /**< 100 Mbps MII */ + e_ENET_MODE_RMII_10 = (e_ENET_IF_RMII | e_ENET_SPEED_10), /**< 10 Mbps RMII */ + e_ENET_MODE_RMII_100 = (e_ENET_IF_RMII | e_ENET_SPEED_100), /**< 100 Mbps RMII */ + e_ENET_MODE_SMII_10 = (e_ENET_IF_SMII | e_ENET_SPEED_10), /**< 10 Mbps SMII */ + e_ENET_MODE_SMII_100 = (e_ENET_IF_SMII | e_ENET_SPEED_100), /**< 100 Mbps SMII */ + e_ENET_MODE_GMII_1000 = (e_ENET_IF_GMII | e_ENET_SPEED_1000), /**< 1000 Mbps GMII */ + e_ENET_MODE_RGMII_10 = (e_ENET_IF_RGMII | e_ENET_SPEED_10), /**< 10 Mbps RGMII */ + e_ENET_MODE_RGMII_100 = (e_ENET_IF_RGMII | e_ENET_SPEED_100), /**< 100 Mbps RGMII */ + e_ENET_MODE_RGMII_1000 = (e_ENET_IF_RGMII | e_ENET_SPEED_1000), /**< 1000 Mbps RGMII */ + e_ENET_MODE_TBI_1000 = (e_ENET_IF_TBI | e_ENET_SPEED_1000), /**< 1000 Mbps TBI */ + e_ENET_MODE_RTBI_1000 = (e_ENET_IF_RTBI | e_ENET_SPEED_1000), /**< 1000 Mbps RTBI */ + e_ENET_MODE_SGMII_10 = (e_ENET_IF_SGMII | e_ENET_SPEED_10), /**< 10 Mbps SGMII */ + e_ENET_MODE_SGMII_100 = (e_ENET_IF_SGMII | e_ENET_SPEED_100), /**< 100 Mbps SGMII */ + e_ENET_MODE_SGMII_1000 = (e_ENET_IF_SGMII | e_ENET_SPEED_1000), /**< 1000 Mbps SGMII */ + e_ENET_MODE_XGMII_10000 = (e_ENET_IF_XGMII | e_ENET_SPEED_10000), /**< 10000 Mbps XGMII */ + e_ENET_MODE_QSGMII_1000 = (e_ENET_IF_QSGMII| e_ENET_SPEED_1000) /**< 1000 Mbps QSGMII */ +} e_EnetMode; + + +#define IS_ENET_MODE_VALID(mode) \ + (((mode) == e_ENET_MODE_MII_10 ) || \ + ((mode) == e_ENET_MODE_MII_100 ) || \ + ((mode) == e_ENET_MODE_RMII_10 ) || \ + ((mode) == e_ENET_MODE_RMII_100 ) || \ + ((mode) == e_ENET_MODE_SMII_10 ) || \ + ((mode) == e_ENET_MODE_SMII_100 ) || \ + ((mode) == e_ENET_MODE_GMII_1000 ) || \ + ((mode) == e_ENET_MODE_RGMII_10 ) || \ + ((mode) == e_ENET_MODE_RGMII_100 ) || \ + ((mode) == e_ENET_MODE_RGMII_1000 ) || \ + ((mode) == e_ENET_MODE_TBI_1000 ) || \ + ((mode) == e_ENET_MODE_RTBI_1000 ) || \ + ((mode) == e_ENET_MODE_SGMII_10 ) || \ + ((mode) == e_ENET_MODE_SGMII_100 ) || \ + ((mode) == e_ENET_MODE_SGMII_1000 ) || \ + ((mode) == e_ENET_MODE_XGMII_10000) || \ + ((mode) == e_ENET_MODE_QSGMII_1000)) + + +#define MAKE_ENET_MODE(_interface, _speed) (e_EnetMode)((_interface) | (_speed)) + +#define ENET_INTERFACE_FROM_MODE(mode) (e_EnetInterface)((mode) & 0xFFFF0000) +#define ENET_SPEED_FROM_MODE(mode) (e_EnetSpeed)((mode) & 0x0000FFFF) + + + +#endif /* __ENET_EXT_H */ + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/ncsw_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/ncsw_ext.h @@ -0,0 +1,430 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /**************************************************************************//** + @File ncsw_ext.h + + @Description General NetCommSw Standard Definitions +*//***************************************************************************/ + +#ifndef __NCSW_EXT_H +#define __NCSW_EXT_H + +#include "memcpy_ext.h" + + +#define WRITE_BLOCK IOMemSet32 +#define COPY_BLOCK Mem2IOCpy32 + +#define PTR_TO_UINT(_ptr) ((uintptr_t)(_ptr)) +#define UINT_TO_PTR(_val) ((void*)(uintptr_t)(_val)) + +#define PTR_MOVE(_ptr, _offset) (void*)((uint8_t*)(_ptr) + (_offset)) + + +#define WRITE_UINT8_UINT24(arg, data08, data24) WRITE_UINT32(arg,((uint32_t)(data08)<<24)|((uint32_t)(data24)&0x00FFFFFF)) +#define WRITE_UINT24_UINT8(arg, data24, data08) WRITE_UINT32(arg,((uint32_t)(data24)<< 8)|((uint32_t)(data08)&0x000000FF)) + +/* Little-Endian access macros */ + +#define WRITE_UINT16_LE(arg, data) \ + WRITE_UINT16((arg), SwapUint16(data)) + +#define WRITE_UINT32_LE(arg, data) \ + WRITE_UINT32((arg), SwapUint32(data)) + +#define WRITE_UINT64_LE(arg, data) \ + WRITE_UINT64((arg), SwapUint64(data)) + +#define GET_UINT16_LE(arg) \ + SwapUint16(GET_UINT16(arg)) + +#define GET_UINT32_LE(arg) \ + SwapUint32(GET_UINT32(arg)) + +#define GET_UINT64_LE(arg) \ + SwapUint64(GET_UINT64(arg)) + +/* Write and Read again macros */ +#define WRITE_UINT_SYNC(size, arg, data) \ + do { \ + WRITE_UINT##size((arg), (data)); \ + CORE_MemoryBarrier(); \ + } while (0) + +#define WRITE_UINT8_SYNC(arg, data) WRITE_UINT_SYNC(8, (arg), (data)) + +#define WRITE_UINT16_SYNC(arg, data) WRITE_UINT_SYNC(16, (arg), (data)) +#define WRITE_UINT32_SYNC(arg, data) WRITE_UINT_SYNC(32, (arg), (data)) + +#define MAKE_UINT64(high32, low32) (((uint64_t)high32 << 32) | (low32)) + + +/*----------------------*/ +/* Miscellaneous macros */ +/*----------------------*/ + +#define UNUSED(X) (X=X) + +#define KILOBYTE 0x400UL /* 1024 */ +#define MEGABYTE (KILOBYTE * KILOBYTE) /* 1024*1024 */ +#define GIGABYTE (KILOBYTE * MEGABYTE) /* 1024*1024*1024 */ + +#undef NO_IRQ +#define NO_IRQ (-1) +#define NCSW_MASTER_ID (0) + +/* Macro for checking if a number is a power of 2 */ +#define POWER_OF_2(n) (!((n) & ((n)-1))) + +/* Macro for calculating log of base 2 */ +#define LOG2(num, log2Num) \ + do \ + { \ + uint64_t tmp = (num); \ + log2Num = 0; \ + while (tmp > 1) \ + { \ + log2Num++; \ + tmp >>= 1; \ + } \ + } while (0) + +#define NEXT_POWER_OF_2(_num, _nextPow) \ +do \ +{ \ + if (POWER_OF_2(_num)) \ + _nextPow = (_num); \ + else \ + { \ + uint64_t tmp = (_num); \ + _nextPow = 1; \ + while (tmp) \ + { \ + _nextPow <<= 1; \ + tmp >>= 1; \ + } \ + } \ +} while (0) + +/* Ceiling division - not the fastest way, but safer in terms of overflow */ +#define DIV_CEIL(x,y) (((x)/(y)) + ((((((x)/(y)))*(y)) == (x)) ? 0 : 1)) + +/* Round up a number to be a multiple of a second number */ +#define ROUND_UP(x,y) ((((x) + (y) - 1) / (y)) * (y)) + +/* Timing macro for converting usec units to number of ticks. */ +/* (number of usec * clock_Hz) / 1,000,000) - since */ +/* clk is in MHz units, no division needed. */ +#define USEC_TO_CLK(usec,clk) ((usec) * (clk)) +#define CYCLES_TO_USEC(cycles,clk) ((cycles) / (clk)) + +/* Timing macros for converting between nsec units and number of clocks. */ +#define NSEC_TO_CLK(nsec,clk) DIV_CEIL(((nsec) * (clk)), 1000) +#define CYCLES_TO_NSEC(cycles,clk) (((cycles) * 1000) / (clk)) + +/* Timing macros for converting between psec units and number of clocks. */ +#define PSEC_TO_CLK(psec,clk) DIV_CEIL(((psec) * (clk)), 1000000) +#define CYCLES_TO_PSEC(cycles,clk) (((cycles) * 1000000) / (clk)) + +/* Min, Max macros */ +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define IN_RANGE(min,val,max) ((min)<=(val) && (val)<=(max)) + +#define ABS(a) ((a<0)?(a*-1):a) + +#if !(defined(ARRAY_SIZE)) +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif /* !defined(ARRAY_SIZE) */ + + +/* possible alignments */ +#define HALF_WORD_ALIGNMENT 2 +#define WORD_ALIGNMENT 4 +#define DOUBLE_WORD_ALIGNMENT 8 +#define BURST_ALIGNMENT 32 + +#define HALF_WORD_ALIGNED 0x00000001 +#define WORD_ALIGNED 0x00000003 +#define DOUBLE_WORD_ALIGNED 0x00000007 +#define BURST_ALIGNED 0x0000001f +#ifndef IS_ALIGNED +#define IS_ALIGNED(n,align) (!((uint32_t)(n) & (align - 1))) +#endif /* IS_ALIGNED */ + + +#define LAST_BUF 1 +#define FIRST_BUF 2 +#define SINGLE_BUF (LAST_BUF | FIRST_BUF) +#define MIDDLE_BUF 4 + +#define ARRAY_END -1 + +#define ILLEGAL_BASE (~0) + +#define BUF_POSITION(first, last) state[(!!(last))<<1 | !!(first)] +#define DECLARE_POSITION static uint8_t state[4] = { (uint8_t)MIDDLE_BUF, (uint8_t)FIRST_BUF, (uint8_t)LAST_BUF, (uint8_t)SINGLE_BUF }; + + +/**************************************************************************//** + @Description Timers operation mode +*//***************************************************************************/ +typedef enum e_TimerMode +{ + e_TIMER_MODE_INVALID = 0, + e_TIMER_MODE_FREE_RUN, /**< Free run - counter continues to increase + after reaching the reference value. */ + e_TIMER_MODE_PERIODIC, /**< Periodic - counter restarts counting from 0 + after reaching the reference value. */ + e_TIMER_MODE_SINGLE /**< Single (one-shot) - counter stops counting + after reaching the reference value. */ +} e_TimerMode; + + +/**************************************************************************//** + @Description Enumeration (bit flags) of communication modes (Transmit, + receive or both). +*//***************************************************************************/ +typedef enum e_CommMode +{ + e_COMM_MODE_NONE = 0, /**< No transmit/receive communication */ + e_COMM_MODE_RX = 1, /**< Only receive communication */ + e_COMM_MODE_TX = 2, /**< Only transmit communication */ + e_COMM_MODE_RX_AND_TX = 3 /**< Both transmit and receive communication */ +} e_CommMode; + +/**************************************************************************//** + @Description General Diagnostic Mode +*//***************************************************************************/ +typedef enum e_DiagMode +{ + e_DIAG_MODE_NONE = 0, /**< Normal operation; no diagnostic mode */ + e_DIAG_MODE_CTRL_LOOPBACK, /**< Loopback in the controller */ + e_DIAG_MODE_CHIP_LOOPBACK, /**< Loopback in the chip but not in the + controller; e.g. IO-pins, SerDes, etc. */ + e_DIAG_MODE_PHY_LOOPBACK, /**< Loopback in the external PHY */ + e_DIAG_MODE_EXT_LOOPBACK, /**< Loopback in the external line (beyond the PHY) */ + e_DIAG_MODE_CTRL_ECHO, /**< Echo incoming data by the controller */ + e_DIAG_MODE_PHY_ECHO /**< Echo incoming data by the PHY */ +} e_DiagMode; + +/**************************************************************************//** + @Description Possible RxStore callback responses. +*//***************************************************************************/ +typedef enum e_RxStoreResponse +{ + e_RX_STORE_RESPONSE_PAUSE /**< Pause invoking callback with received data; + in polling mode, start again invoking callback + only next time user invokes the receive routine; + in interrupt mode, start again invoking callback + only next time a receive event triggers an interrupt; + in all cases, received data that are pending are not + lost, rather, their processing is temporarily deferred; + in all cases, received data are processed in the order + in which they were received. */ + , e_RX_STORE_RESPONSE_CONTINUE /**< Continue invoking callback with received data. */ +} e_RxStoreResponse; + + +/**************************************************************************//** + @Description General Handle +*//***************************************************************************/ +typedef void * t_Handle; /**< handle, used as object's descriptor */ + +/**************************************************************************//** + @Description MUTEX type +*//***************************************************************************/ +typedef uint32_t t_Mutex; + +/**************************************************************************//** + @Description Error Code. + + The high word of the error code is the code of the software + module (driver). The low word is the error type (e_ErrorType). + To get the values from the error code, use GET_ERROR_TYPE() + and GET_ERROR_MODULE(). +*//***************************************************************************/ +typedef uint32_t t_Error; + +/**************************************************************************//** + @Description General prototype of interrupt service routine (ISR). + + @Param[in] handle - Optional handle of the module handling the interrupt. + + @Return None + *//***************************************************************************/ +typedef void (t_Isr)(t_Handle handle); + +/**************************************************************************//** + @Anchor mem_attr + + @Collection Memory Attributes + + Various attributes of memory partitions. These values may be + or'ed together to create a mask of all memory attributes. + @{ +*//***************************************************************************/ +#define MEMORY_ATTR_CACHEABLE 0x00000001 + /**< Memory is cacheable */ +#define MEMORY_ATTR_QE_2ND_BUS_ACCESS 0x00000002 + /**< Memory can be accessed by QUICC Engine + through its secondary bus interface */ + +/* @} */ + + +/**************************************************************************//** + @Function t_GetBufFunction + + @Description User callback function called by driver to get data buffer. + + User provides this function. Driver invokes it. + + @Param[in] h_BufferPool - A handle to buffer pool manager + @Param[out] p_BufContextHandle - Returns the user's private context that + should be associated with the buffer + + @Return Pointer to data buffer, NULL if error + *//***************************************************************************/ +typedef uint8_t * (t_GetBufFunction)(t_Handle h_BufferPool, + t_Handle *p_BufContextHandle); + +/**************************************************************************//** + @Function t_PutBufFunction + + @Description User callback function called by driver to return data buffer. + + User provides this function. Driver invokes it. + + @Param[in] h_BufferPool - A handle to buffer pool manager + @Param[in] p_Buffer - A pointer to buffer to return + @Param[in] h_BufContext - The user's private context associated with + the returned buffer + + @Return E_OK on success; Error code otherwise + *//***************************************************************************/ +typedef t_Error (t_PutBufFunction)(t_Handle h_BufferPool, + uint8_t *p_Buffer, + t_Handle h_BufContext); + +/**************************************************************************//** + @Function t_PhysToVirt + + @Description Translates a physical address to the matching virtual address. + + @Param[in] addr - The physical address to translate. + + @Return Virtual address. +*//***************************************************************************/ +typedef void * t_PhysToVirt(physAddress_t addr); + +/**************************************************************************//** + @Function t_VirtToPhys + + @Description Translates a virtual address to the matching physical address. + + @Param[in] addr - The virtual address to translate. + + @Return Physical address. +*//***************************************************************************/ +typedef physAddress_t t_VirtToPhys(void *addr); + +/**************************************************************************//** + @Description Buffer Pool Information Structure. +*//***************************************************************************/ +typedef struct t_BufferPoolInfo +{ + t_Handle h_BufferPool; /**< A handle to the buffer pool manager */ + t_GetBufFunction *f_GetBuf; /**< User callback to get a free buffer */ + t_PutBufFunction *f_PutBuf; /**< User callback to return a buffer */ + uint16_t bufferSize; /**< Buffer size (in bytes) */ + + t_PhysToVirt *f_PhysToVirt; /**< User callback to translate pool buffers + physical addresses to virtual addresses */ + t_VirtToPhys *f_VirtToPhys; /**< User callback to translate pool buffers + virtual addresses to physical addresses */ +} t_BufferPoolInfo; + + +/**************************************************************************//** + @Description User callback function called by driver when transmit completed. + + User provides this function. Driver invokes it. + + @Param[in] h_App - Application's handle, as was provided to the + driver by the user + @Param[in] queueId - Transmit queue ID + @Param[in] p_Data - Pointer to the data buffer + @Param[in] h_BufContext - The user's private context associated with + the given data buffer + @Param[in] status - Transmit status and errors + @Param[in] flags - Driver-dependent information + *//***************************************************************************/ +typedef void (t_TxConfFunction)(t_Handle h_App, + uint32_t queueId, + uint8_t *p_Data, + t_Handle h_BufContext, + uint16_t status, + uint32_t flags); + +/**************************************************************************//** + @Description User callback function called by driver with receive data. + + User provides this function. Driver invokes it. + + @Param[in] h_App - Application's handle, as was provided to the + driver by the user + @Param[in] queueId - Receive queue ID + @Param[in] p_Data - Pointer to the buffer with received data + @Param[in] h_BufContext - The user's private context associated with + the given data buffer + @Param[in] length - Length of received data + @Param[in] status - Receive status and errors + @Param[in] position - Position of buffer in frame + @Param[in] flags - Driver-dependent information + + @Retval e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx + operation for all ready data. + @Retval e_RX_STORE_RESPONSE_PAUSE - order the driver to stop Rx operation. + *//***************************************************************************/ +typedef e_RxStoreResponse (t_RxStoreFunction)(t_Handle h_App, + uint32_t queueId, + uint8_t *p_Data, + t_Handle h_BufContext, + uint32_t length, + uint16_t status, + uint8_t position, + uint32_t flags); + + +#endif /* __NCSW_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/ctype_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/ctype_ext.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CTYPE_EXT_H +#define __CTYPE_EXT_H + + +#if defined(NCSW_LINUX) && defined(__KERNEL__) +/* + * NOTE! This ctype does not handle EOF like the standard C + * library is required to. + */ + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern unsigned char _ctype[]; + +#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) + +#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) +#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) +#define iscntrl(c) ((__ismask(c)&(_C)) != 0) +#define isdigit(c) ((__ismask(c)&(_D)) != 0) +#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) +#define islower(c) ((__ismask(c)&(_L)) != 0) +#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) +#define ispunct(c) ((__ismask(c)&(_P)) != 0) +#define isspace(c) ((__ismask(c)&(_S)) != 0) +#define isupper(c) ((__ismask(c)&(_U)) != 0) +#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define toascii(c) (((unsigned char)(c))&0x7f) + +static __inline__ unsigned char __tolower(unsigned char c) +{ + if (isupper(c)) + c -= 'A'-'a'; + return c; +} + +static __inline__ unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + +#define tolower(c) __tolower(c) +#define toupper(c) __toupper(c) + +#else +#include +#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ + + +#endif /* __CTYPE_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/debug_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/debug_ext.h @@ -0,0 +1,259 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File debug_ext.h + + @Description Debug mode definitions. +*//***************************************************************************/ + +#ifndef __DEBUG_EXT_H +#define __DEBUG_EXT_H + +#include "std_ext.h" +#include "xx_ext.h" +#include "memcpy_ext.h" +#if (DEBUG_ERRORS > 0) +#include "sprint_ext.h" +#include "string_ext.h" +#endif /* DEBUG_ERRORS > 0 */ + + +#if (DEBUG_ERRORS > 0) + +/* Internally used macros */ + +#define DUMP_Print XX_Print +#define DUMP_MAX_LEVELS 6 +#define DUMP_MAX_STR 64 + + +#define _CREATE_DUMP_SUBSTR(phrase) \ + dumpTmpLevel = 0; dumpSubStr[0] = '\0'; \ + sprintf(dumpTmpStr, "%s", #phrase); \ + p_DumpToken = strtok(dumpTmpStr, (dumpIsArr[0] ? "[" : ".")); \ + while (p_DumpToken != NULL) \ + { \ + strcat(dumpSubStr, p_DumpToken); \ + if (dumpIsArr[dumpTmpLevel]) \ + { \ + strcat(dumpSubStr, dumpIdxStr[dumpTmpLevel]); \ + p_DumpToken = strtok(NULL, "."); \ + } \ + if ((p_DumpToken = strtok(NULL, (dumpIsArr[++dumpTmpLevel] ? "[" : "."))) != 0) \ + strcat(dumpSubStr, "."); \ + }\ + + +/**************************************************************************//** + @Group gen_id General Drivers Utilities + + @Description External routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group dump_id Memory and Registers Dump Mechanism + + @Description Macros for dumping memory mapped structures. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description Declaration of dump mechanism variables. + + This macro must be declared at the beginning of each routine + which uses the dump mechanism macros, before the routine's code + starts. +*//***************************************************************************/ +#define DECLARE_DUMP \ + char dumpIdxStr[DUMP_MAX_LEVELS + 1][6] = { "", }; \ + char dumpSubStr[DUMP_MAX_STR] = ""; \ + char dumpTmpStr[DUMP_MAX_STR] = ""; \ + char *p_DumpToken = NULL; \ + int dumpArrIdx = 0, dumpArrSize = 0, dumpVarSize = 0, dumpLevel = 0, dumpTmpLevel = 0; \ + uint8_t dumpIsArr[DUMP_MAX_LEVELS + 1] = { 0 }; \ + /* Prevent warnings if not all used */ \ + UNUSED(dumpIdxStr[0][0]); \ + UNUSED(dumpSubStr[0]); \ + UNUSED(dumpTmpStr[0]); \ + UNUSED(p_DumpToken); \ + UNUSED(dumpArrIdx); \ + UNUSED(dumpArrSize); \ + UNUSED(dumpVarSize); \ + UNUSED(dumpLevel); \ + UNUSED(dumpTmpLevel); \ + UNUSED(dumpIsArr[0]); + + +/**************************************************************************//** + @Description Prints a title for a subsequent dumped structure or memory. + + The inputs for this macro are the structure/memory title and + its base addresses. +*//***************************************************************************/ +#define DUMP_TITLE(addr, msg) \ + DUMP_Print("\r\n"); DUMP_Print msg; \ + DUMP_Print(" (0x%p)\r\n" \ + "---------------------------------------------------------\r\n", \ + (addr)) + +/**************************************************************************//** + @Description Prints a subtitle for a subsequent dumped sub-structure (optional). + + The inputs for this macro are the sub-structure subtitle. + A separating line with this subtitle will be printed. +*//***************************************************************************/ +#define DUMP_SUBTITLE(subtitle) \ + DUMP_Print("----------- "); DUMP_Print subtitle; DUMP_Print("\r\n") + + +/**************************************************************************//** + @Description Dumps a memory region in 4-bytes aligned format. + + The inputs for this macro are the base addresses and size + (in bytes) of the memory region. +*//***************************************************************************/ +#define DUMP_MEMORY(addr, size) \ + MemDisp((uint8_t *)(addr), (int)(size)) + + +/**************************************************************************//** + @Description Declares a dump loop, for dumping a sub-structure array. + + The inputs for this macro are: + - idx: an index variable, for indexing the sub-structure items + inside the loop. This variable must be declared separately + in the beginning of the routine. + - cnt: the number of times to repeat the loop. This number should + equal the number of items in the sub-structures array. + + Note, that the body of the loop must be written inside brackets. +*//***************************************************************************/ +#define DUMP_SUBSTRUCT_ARRAY(idx, cnt) \ + for (idx=0, dumpIsArr[dumpLevel++] = 1; \ + (idx < cnt) && sprintf(dumpIdxStr[dumpLevel-1], "[%d]", idx); \ + idx++, ((idx < cnt) || ((dumpIsArr[--dumpLevel] = 0) == 0))) + + +/**************************************************************************//** + @Description Dumps a structure's member variable. + + The input for this macro is the full reference for the member + variable, where the structure is referenced using a pointer. + + Note, that a members array must be dumped using DUMP_ARR macro, + rather than using this macro. + + If the member variable is part of a sub-structure hierarchy, + the full hierarchy (including array indexing) must be specified. + + Examples: p_Struct->member + p_Struct->sub.member + p_Struct->sub[i].member +*//***************************************************************************/ +#define DUMP_VAR(st, phrase) \ + do { \ + void *addr = (void *)&((st)->phrase); \ + _CREATE_DUMP_SUBSTR(phrase); \ + dumpVarSize = sizeof((st)->phrase); \ + switch (dumpVarSize) \ + { \ + case 1: DUMP_Print("0x%08X: 0x%02x%14s\t%s\r\n", \ + addr, GET_UINT8(*(uint8_t*)addr), "", dumpSubStr); break; \ + case 2: DUMP_Print("0x%08X: 0x%04x%12s\t%s\r\n", \ + addr, GET_UINT16(*(uint16_t*)addr), "", dumpSubStr); break; \ + case 4: DUMP_Print("0x%08X: 0x%08x%8s\t%s\r\n", \ + addr, GET_UINT32(*(uint32_t*)addr), "", dumpSubStr); break; \ + case 8: DUMP_Print("0x%08X: 0x%016llx\t%s\r\n", \ + addr, GET_UINT64(*(uint64_t*)addr), dumpSubStr); break; \ + default: DUMP_Print("Bad size %d (" #st "->" #phrase ")\r\n", dumpVarSize); \ + } \ + } while (0) + + +/**************************************************************************//** + @Description Dumps a structure's members array. + + The input for this macro is the full reference for the members + array, where the structure is referenced using a pointer. + + If the members array is part of a sub-structure hierarchy, + the full hierarchy (including array indexing) must be specified. + + Examples: p_Struct->array + p_Struct->sub.array + p_Struct->sub[i].array +*//***************************************************************************/ +#define DUMP_ARR(st, phrase) \ + do { \ + _CREATE_DUMP_SUBSTR(phrase); \ + dumpArrSize = ARRAY_SIZE((st)->phrase); \ + dumpVarSize = sizeof((st)->phrase[0]); \ + switch (dumpVarSize) \ + { \ + case 1: \ + for (dumpArrIdx=0; dumpArrIdx < dumpArrSize; dumpArrIdx++) { \ + DUMP_Print("0x%08X: 0x%02x%14s\t%s[%d]\r\n", \ + &((st)->phrase[dumpArrIdx]), GET_UINT8((st)->phrase[dumpArrIdx]), "", dumpSubStr, dumpArrIdx); \ + } break; \ + case 2: \ + for (dumpArrIdx=0; dumpArrIdx < dumpArrSize; dumpArrIdx++) { \ + DUMP_Print("0x%08X: 0x%04x%12s\t%s[%d]\r\n", \ + &((st)->phrase[dumpArrIdx]), GET_UINT16((st)->phrase[dumpArrIdx]), "", dumpSubStr, dumpArrIdx); \ + } break; \ + case 4: \ + for (dumpArrIdx=0; dumpArrIdx < dumpArrSize; dumpArrIdx++) { \ + DUMP_Print("0x%08X: 0x%08x%8s\t%s[%d]\r\n", \ + &((st)->phrase[dumpArrIdx]), GET_UINT32((st)->phrase[dumpArrIdx]), "", dumpSubStr, dumpArrIdx); \ + } break; \ + case 8: \ + for (dumpArrIdx=0; dumpArrIdx < dumpArrSize; dumpArrIdx++) { \ + DUMP_Print("0x%08X: 0x%016llx\t%s[%d]\r\n", \ + &((st)->phrase[dumpArrIdx]), GET_UINT64((st)->phrase[dumpArrIdx]), dumpSubStr, dumpArrIdx); \ + } break; \ + default: DUMP_Print("Bad size %d (" #st "->" #phrase "[0])\r\n", dumpVarSize); \ + } \ + } while (0) + + +#endif /* DEBUG_ERRORS > 0 */ + + +/** @} */ /* end of dump_id group */ +/** @} */ /* end of gen_id group */ + + +#endif /* __DEBUG_EXT_H */ + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/string_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/string_ext.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STRING_EXT_H +#define __STRING_EXT_H + + +#if defined(NCSW_LINUX) && defined(__KERNEL__) +#include +#include +extern char * strtok ( char * str, const char * delimiters ); + +#elif defined(__KERNEL__) +#include "linux/types.h" +#include "linux/posix_types.h" +#include "linux/string.h" + +#else +#include + +#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ + +#include "std_ext.h" + + +#endif /* __STRING_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/error_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/error_ext.h @@ -0,0 +1,553 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @File error_ext.h + + @Description Error definitions. +*//***************************************************************************/ + +#ifndef __ERROR_EXT_H +#define __ERROR_EXT_H + +#include "std_ext.h" +#include "xx_ext.h" +#include "core_ext.h" + +/**************************************************************************//** + @Group gen_id General Drivers Utilities + + @Description External routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group gen_error_id Errors, Events and Debug + + @Description External routines. + + @{ +*//***************************************************************************/ + +/****************************************************************************** +The scheme below provides the bits description for error codes: + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +| Reserved (should be zero) | Module ID | + + 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 +| Error Type | +******************************************************************************/ + +#define ERROR_CODE(_err) ((((uint32_t)_err) & 0x0000FFFF) | __ERR_MODULE__) + +#define GET_ERROR_TYPE(_errcode) ((_errcode) & 0x0000FFFF) + /**< Extract module code from error code (#t_Error) */ + +#define GET_ERROR_MODULE(_errcode) ((_errcode) & 0x00FF0000) + /**< Extract error type (#e_ErrorType) from + error code (#t_Error) */ + + +/**************************************************************************//** + @Description Error Type Enumeration +*//***************************************************************************/ +typedef enum e_ErrorType /* Comments / Associated Message Strings */ +{ /* ------------------------------------------------------------ */ + E_OK = 0 /* Never use "RETURN_ERROR" with E_OK; Use "return E_OK;" */ + + /* Invalid Function Calls */ + ,E_INVALID_STATE /**< The operation is not allowed in current module state. */ + /* String: none. */ + ,E_INVALID_OPERATION /**< The operation/command is invalid (unrecognized). */ + /* String: none. */ + ,E_NOT_SUPPORTED /**< The function is not supported or not implemented. */ + /* String: none. */ + ,E_NO_DEVICE /**< The associated device is not initialized. */ + /* String: none. */ + + /* Invalid Parameters */ + ,E_INVALID_HANDLE /**< Invalid handle of module or object. */ + /* String: none, unless the function takes in more than one + handle (in this case add the handle description) */ + ,E_INVALID_ID /**< Invalid module ID (usually enumeration or index). */ + /* String: none, unless the function takes in more than one + ID (in this case add the ID description) */ + ,E_NULL_POINTER /**< Unexpected NULL pointer. */ + /* String: pointer description. */ + ,E_INVALID_VALUE /**< Invalid value. */ + /* Use for non-enumeration parameters, and + only when other error types are not suitable. + String: parameter description + "(should be )", + e.g: "Maximum Rx buffer length (should be divisible by 8)", + "Channel number (should be even)". */ + ,E_INVALID_SELECTION /**< Invalid selection or mode. */ + /* Use for enumeration values, only when other error types + are not suitable. + String: parameter description. */ + ,E_INVALID_COMM_MODE /**< Invalid communication mode. */ + /* String: none, unless the function takes in more than one + communication mode indications (in this case add + parameter description). */ + ,E_INVALID_BYTE_ORDER /**< Invalid byte order. */ + /* String: none, unless the function takes in more than one + byte order indications (in this case add parameter + description). */ + ,E_INVALID_MEMORY_TYPE /**< Invalid memory type. */ + /* String: none, unless the function takes in more than one + memory types (in this case add memory description, + e.g: "Data memory", "Buffer descriptors memory"). */ + ,E_INVALID_INTR_QUEUE /**< Invalid interrupt queue. */ + /* String: none, unless the function takes in more than one + interrupt queues (in this case add queue description, + e.g: "Rx interrupt queue", "Tx interrupt queue"). */ + ,E_INVALID_PRIORITY /**< Invalid priority. */ + /* String: none, unless the function takes in more than one + priority (in this case add priority description). */ + ,E_INVALID_CLOCK /**< Invalid clock. */ + /* String: none, unless the function takes in more than one + clocks (in this case add clock description, + e.g: "Rx clock", "Tx clock"). */ + ,E_INVALID_RATE /**< Invalid rate value. */ + /* String: none, unless the function takes in more than one + rate values (in this case add rate description). */ + ,E_INVALID_ADDRESS /**< Invalid address. */ + /* String: description of the specific violation. */ + ,E_INVALID_BUS /**< Invalid bus type. */ + /* String: none, unless the function takes in more than one + bus parameters (in this case add bus description). */ + ,E_BUS_CONFLICT /**< Bus (or memory) type conflicts with another setting. */ + /* String: description of the conflicting buses/memories. */ + ,E_CONFLICT /**< Some setting conflicts with another setting. */ + /* String: description of the conflicting settings. */ + ,E_NOT_ALIGNED /**< Non-aligned address. */ + /* String: parameter description + "(should be %d-bytes aligned)", + e.g: "Rx data buffer (should be 32-bytes aligned)". */ + ,E_NOT_IN_RANGE /**< Parameter value is out of range. */ + /* Don't use this error for enumeration parameters. + String: parameter description + "(should be %d-%d)", + e.g: "Number of pad characters (should be 0-15)". */ + + /* Frame/Buffer Errors */ + ,E_INVALID_FRAME /**< Invalid frame object (NULL handle or missing buffers). */ + /* String: none. */ + ,E_EMPTY_FRAME /**< Frame object is empty (has no buffers). */ + /* String: none. */ + ,E_EMPTY_BUFFER /**< Buffer object is empty (no data, or zero data length). */ + /* String: none. */ + + /* Resource Errors */ + ,E_NO_MEMORY /**< External memory allocation failed. */ + /* String: description of item for which allocation failed. */ + ,E_NOT_FOUND /**< Requested resource or item was not found. */ + /* Use only when the resource/item is uniquely identified. + String: none, unless the operation is not the main goal + of the function (in this case add item description). */ + ,E_NOT_AVAILABLE /**< Resource is unavailable. */ + /* String: none, unless the operation is not the main goal + of the function (in this case add resource description). */ + ,E_ALREADY_EXISTS /**< Requested resource or item already exists. */ + /* Use when resource duplication or sharing are not allowed. + String: none, unless the operation is not the main goal + of the function (in this case add item description). */ + ,E_FULL /**< Resource is full. */ + /* String: none, unless the operation is not the main goal + of the function (in this case add resource description). */ + ,E_EMPTY /**< Resource is empty. */ + /* String: none, unless the operation is not the main goal + of the function (in this case add resource description). */ + ,E_BUSY /**< Resource or module is busy. */ + /* String: none, unless the operation is not the main goal + of the function (in this case add resource description). */ + ,E_ALREADY_FREE /**< Specified resource or item is already free or deleted. */ + /* String: none, unless the operation is not the main goal + of the function (in this case add item description). */ + + /* Read/Write Access Errors */ + ,E_READ_FAILED /**< Read access failed on memory/device. */ + /* String: none, or device name. */ + ,E_WRITE_FAILED /**< Write access failed on memory/device. */ + /* String: none, or device name. */ + + /* Send/Receive Failures */ + ,E_SEND_FAILED /**< Send operation failed on device. */ + /* String: none, or device name. */ + ,E_RECEIVE_FAILED /**< Receive operation failed on device. */ + /* String: none, or device name. */ + + /* Operation time-out */ + ,E_TIMEOUT /**< The operation timed out. */ + /* String: none. */ + + ,E_DUMMY_LAST /* NEVER USED */ + +} e_ErrorType; + + +/**************************************************************************//** + @Description Event Type Enumeration +*//***************************************************************************/ +typedef enum e_Event /* Comments / Associated Flags and Message Strings */ +{ /* ------------------------------------------------------------ */ + EV_NO_EVENT = 0 /**< No event; Never used. */ + + ,EV_RX_DISCARD /**< Received packet discarded (by the driver, and only for + complete packets); + Flags: error flags in case of error, zero otherwise. */ + /* String: reason for discard, e.g: "Error in frame", + "Disordered frame", "Incomplete frame", "No frame object". */ + ,EV_RX_ERROR /**< Receive error (by hardware/firmware); + Flags: usually status flags from the buffer descriptor. */ + /* String: none. */ + ,EV_TX_ERROR /**< Transmit error (by hardware/firmware); + Flags: usually status flags from the buffer descriptor. */ + /* String: none. */ + ,EV_NO_BUFFERS /**< System ran out of buffer objects; + Flags: zero. */ + /* String: none. */ + ,EV_NO_MB_FRAMES /**< System ran out of multi-buffer frame objects; + Flags: zero. */ + /* String: none. */ + ,EV_NO_SB_FRAMES /**< System ran out of single-buffer frame objects; + Flags: zero. */ + /* String: none. */ + ,EV_TX_QUEUE_FULL /**< Transmit queue is full; + Flags: zero. */ + /* String: none. */ + ,EV_RX_QUEUE_FULL /**< Receive queue is full; + Flags: zero. */ + /* String: none. */ + ,EV_INTR_QUEUE_FULL /**< Interrupt queue overflow; + Flags: zero. */ + /* String: none. */ + ,EV_NO_DATA_BUFFER /**< Data buffer allocation (from higher layer) failed; + Flags: zero. */ + /* String: none. */ + ,EV_OBJ_POOL_EMPTY /**< Objects pool is empty; + Flags: zero. */ + /* String: object description (name). */ + ,EV_BUS_ERROR /**< Illegal access on bus; + Flags: the address (if available) or bus identifier */ + /* String: bus/address/module description. */ + ,EV_PTP_TXTS_QUEUE_FULL /**< PTP Tx timestamps queue is full; + Flags: zero. */ + /* String: none. */ + ,EV_PTP_RXTS_QUEUE_FULL /**< PTP Rx timestamps queue is full; + Flags: zero. */ + /* String: none. */ + ,EV_DUMMY_LAST + +} e_Event; + + +/**************************************************************************//** + @Collection Debug Levels for Errors and Events + + The level description refers to errors only. + For events, classification is done by the user. + + The TRACE, INFO and WARNING levels are allowed only when using + the DBG macro, and are not allowed when using the error macros + (RETURN_ERROR or REPORT_ERROR). + @{ +*//***************************************************************************/ +#define REPORT_LEVEL_CRITICAL 1 /**< Crasher: Incorrect flow, NULL pointers/handles. */ +#define REPORT_LEVEL_MAJOR 2 /**< Cannot proceed: Invalid operation, parameters or + configuration. */ +#define REPORT_LEVEL_MINOR 3 /**< Recoverable problem: a repeating call with the same + parameters may be successful. */ +#define REPORT_LEVEL_WARNING 4 /**< Something is not exactly right, yet it is not an error. */ +#define REPORT_LEVEL_INFO 5 /**< Messages which may be of interest to user/programmer. */ +#define REPORT_LEVEL_TRACE 6 /**< Program flow messages. */ + +#define EVENT_DISABLED 0xFF /**< Disabled event (not reported at all) */ + +/* @} */ + + + +#define NO_MSG ("") + +#ifndef DEBUG_GLOBAL_LEVEL +#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING +#endif /* DEBUG_GLOBAL_LEVEL */ + +#ifndef ERROR_GLOBAL_LEVEL +#define ERROR_GLOBAL_LEVEL DEBUG_GLOBAL_LEVEL +#endif /* ERROR_GLOBAL_LEVEL */ + +#ifndef EVENT_GLOBAL_LEVEL +#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR +#endif /* EVENT_GLOBAL_LEVEL */ + +#ifdef EVENT_LOCAL_LEVEL +#define EVENT_DYNAMIC_LEVEL EVENT_LOCAL_LEVEL +#else +#define EVENT_DYNAMIC_LEVEL EVENT_GLOBAL_LEVEL +#endif /* EVENT_LOCAL_LEVEL */ + + +#ifndef DEBUG_DYNAMIC_LEVEL +#define DEBUG_USING_STATIC_LEVEL + +#ifdef DEBUG_STATIC_LEVEL +#define DEBUG_DYNAMIC_LEVEL DEBUG_STATIC_LEVEL +#else +#define DEBUG_DYNAMIC_LEVEL DEBUG_GLOBAL_LEVEL +#endif /* DEBUG_STATIC_LEVEL */ + +#else /* DEBUG_DYNAMIC_LEVEL */ +#ifdef DEBUG_STATIC_LEVEL +#error "Please use either DEBUG_STATIC_LEVEL or DEBUG_DYNAMIC_LEVEL (not both)" +#else +int DEBUG_DYNAMIC_LEVEL = DEBUG_GLOBAL_LEVEL; +#endif /* DEBUG_STATIC_LEVEL */ +#endif /* !DEBUG_DYNAMIC_LEVEL */ + + +#ifndef ERROR_DYNAMIC_LEVEL + +#ifdef ERROR_STATIC_LEVEL +#define ERROR_DYNAMIC_LEVEL ERROR_STATIC_LEVEL +#else +#define ERROR_DYNAMIC_LEVEL ERROR_GLOBAL_LEVEL +#endif /* ERROR_STATIC_LEVEL */ + +#else /* ERROR_DYNAMIC_LEVEL */ +#ifdef ERROR_STATIC_LEVEL +#error "Please use either ERROR_STATIC_LEVEL or ERROR_DYNAMIC_LEVEL (not both)" +#else +int ERROR_DYNAMIC_LEVEL = ERROR_GLOBAL_LEVEL; +#endif /* ERROR_STATIC_LEVEL */ +#endif /* !ERROR_DYNAMIC_LEVEL */ + +#define PRINT_FORMAT "[CPU%02d, %s:%d %s]" +#define PRINT_FMT_PARAMS CORE_GetId(), __FILE__, __LINE__, __FUNCTION__ + +#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) +/* No debug/error/event messages at all */ +#define DBG(_level, _vmsg) + +#define REPORT_ERROR(_level, _err, _vmsg) + +#define RETURN_ERROR(_level, _err, _vmsg) \ + return ERROR_CODE(_err) + +#if (REPORT_EVENTS > 0) + +#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \ + do { \ + if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \ + XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \ + } \ + } while (0) + +#else + +#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) + +#endif /* (REPORT_EVENTS > 0) */ + + +#else /* DEBUG_ERRORS > 0 */ + +extern const char *dbgLevelStrings[]; +extern const char *errTypeStrings[]; +extern const char *moduleStrings[]; +#if (REPORT_EVENTS > 0) +extern const char *eventStrings[]; +#endif /* (REPORT_EVENTS > 0) */ + + +#if ((defined(DEBUG_USING_STATIC_LEVEL)) && (DEBUG_DYNAMIC_LEVEL < REPORT_LEVEL_WARNING)) +/* No need for DBG macro - debug level is higher anyway */ +#define DBG(_level, _vmsg) +#else +#define DBG(_level, _vmsg) \ + do { \ + if (REPORT_LEVEL_##_level <= DEBUG_DYNAMIC_LEVEL) { \ + XX_Print("> %s (%s) " PRINT_FORMAT ": ", \ + dbgLevelStrings[REPORT_LEVEL_##_level - 1], \ + moduleStrings[__ERR_MODULE__ >> 16], \ + PRINT_FMT_PARAMS); \ + XX_Print _vmsg; \ + XX_Print("\r\n"); \ + } \ + } while (0) +#endif /* (defined(DEBUG_USING_STATIC_LEVEL) && (DEBUG_DYNAMIC_LEVEL < WARNING)) */ + + +#define REPORT_ERROR(_level, _err, _vmsg) \ + do { \ + if (REPORT_LEVEL_##_level <= ERROR_DYNAMIC_LEVEL) { \ + XX_Print("! %s %s Error " PRINT_FORMAT ": %s; ", \ + dbgLevelStrings[REPORT_LEVEL_##_level - 1], \ + moduleStrings[__ERR_MODULE__ >> 16], \ + PRINT_FMT_PARAMS, \ + errTypeStrings[(GET_ERROR_TYPE(_err) - E_OK - 1)]); \ + XX_Print _vmsg; \ + XX_Print("\r\n"); \ + } \ + } while (0) + + +#define RETURN_ERROR(_level, _err, _vmsg) \ + do { \ + REPORT_ERROR(_level, (_err), _vmsg); \ + return ERROR_CODE(_err); \ + } while (0) + + +#if (REPORT_EVENTS > 0) + +#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \ + do { \ + if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \ + XX_Print("~ %s %s Event " PRINT_FORMAT ": %s (flags: 0x%04x); ", \ + dbgLevelStrings[_ev##_LEVEL - 1], \ + moduleStrings[__ERR_MODULE__ >> 16], \ + PRINT_FMT_PARAMS, \ + eventStrings[((_ev) - EV_NO_EVENT - 1)], \ + (uint16_t)(_flg)); \ + XX_Print _vmsg; \ + XX_Print("\r\n"); \ + XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \ + } \ + } while (0) + +#else /* not REPORT_EVENTS */ + +#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) + +#endif /* (REPORT_EVENTS > 0) */ + +#endif /* (DEBUG_ERRORS > 0) */ + + +/**************************************************************************//** + @Function ASSERT_COND + + @Description Assertion macro. + + @Param[in] _cond - The condition being checked, in positive form; + Failure of the condition triggers the assert. +*//***************************************************************************/ +#ifdef DISABLE_ASSERTIONS +#define ASSERT_COND(_cond) +#else +#define ASSERT_COND(_cond) \ + do { \ + if (!(_cond)) { \ + XX_Print("*** ASSERT_COND failed " PRINT_FORMAT "\r\n", \ + PRINT_FMT_PARAMS); \ + XX_Exit(1); \ + } \ + } while (0) +#endif /* DISABLE_ASSERTIONS */ + + +#ifdef DISABLE_INIT_PARAMETERS_CHECK + +#define CHECK_INIT_PARAMETERS(handle, f_check) +#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval) + +#else + +#define CHECK_INIT_PARAMETERS(handle, f_check) \ + do { \ + t_Error err = f_check(handle); \ + if (err != E_OK) { \ + RETURN_ERROR(MAJOR, err, NO_MSG); \ + } \ + } while (0) + +#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval) \ + do { \ + t_Error err = f_check(handle); \ + if (err != E_OK) { \ + REPORT_ERROR(MAJOR, err, NO_MSG); \ + return (retval); \ + } \ + } while (0) + +#endif /* DISABLE_INIT_PARAMETERS_CHECK */ + +#ifdef DISABLE_SANITY_CHECKS + +#define SANITY_CHECK_RETURN_ERROR(_cond, _err) +#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval) +#define SANITY_CHECK_RETURN(_cond, _err) +#define SANITY_CHECK_EXIT(_cond, _err) + +#else /* DISABLE_SANITY_CHECKS */ + +#define SANITY_CHECK_RETURN_ERROR(_cond, _err) \ + do { \ + if (!(_cond)) { \ + RETURN_ERROR(CRITICAL, (_err), NO_MSG); \ + } \ + } while (0) + +#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval) \ + do { \ + if (!(_cond)) { \ + REPORT_ERROR(CRITICAL, (_err), NO_MSG); \ + return (retval); \ + } \ + } while (0) + +#define SANITY_CHECK_RETURN(_cond, _err) \ + do { \ + if (!(_cond)) { \ + REPORT_ERROR(CRITICAL, (_err), NO_MSG); \ + return; \ + } \ + } while (0) + +#define SANITY_CHECK_EXIT(_cond, _err) \ + do { \ + if (!(_cond)) { \ + REPORT_ERROR(CRITICAL, (_err), NO_MSG); \ + XX_Exit(1); \ + } \ + } while (0) + +#endif /* DISABLE_SANITY_CHECKS */ + +/** @} */ /* end of Debug/error Utils group */ + +/** @} */ /* end of General Utils group */ + +#endif /* __ERROR_EXT_H */ + + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/types_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/types_ext.h @@ -0,0 +1,111 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /**************************************************************************//** + @File types_ext.h + + @Description General types Standard Definitions +*//***************************************************************************/ + +#ifndef __TYPES_EXT_H +#define __TYPES_EXT_H + + +#if defined(NCSW_LINUX) +#include "types_linux.h" + +#elif defined(NCSW_LINUX_USD) +#include "types_linux_usd.h" + +#elif defined(NCSW_VXWORKS) +#include "types_vxworks.h" + +#elif defined(__MWERKS__) && defined(__GNUC__) && defined(__cplusplus) +#include "types_bb_gpp.h" + +#elif defined(__MWERKS__) && defined(__GNUC__) +#include "types_bb_gcc.h" + +#elif defined(__ghs__) +#include "types_ghs.h" + +#else +#include "types_dflt.h" +#endif /* defined (__ROCOO__) */ + + +static __inline__ void TypesChecker(void) +{ +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + _Packed struct strct { + __volatile__ int vi; + } _PackedType; +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + size_t size = 0; + bool tr = TRUE, fls = FALSE; + struct strct *p_Strct = NULL; + physAddress_t addr = 0x100; + + tr = fls; + p_Strct = p_Strct; + size++; + if (tr) size++; + + WRITE_UINT8(*((uint8_t*)((size_t)(addr))), + GET_UINT8(*((uint8_t*)((size_t)(addr))))); + + WRITE_UINT8(*((uint8_t*)((size_t)(UINT8_MAX))), + GET_UINT8(*((uint8_t*)((size_t)(UINT8_MAX))))); + WRITE_UINT16(*((uint16_t*)((size_t)(UINT16_MAX))), + GET_UINT16(*((uint16_t*)((size_t)(UINT16_MAX))))); + WRITE_UINT32(*((uint32_t*)((size_t)(UINT32_MAX))), + GET_UINT32(*((uint32_t*)((size_t)(UINT32_MAX))))); + WRITE_UINT64(*((uint64_t*)((size_t)(UINT64_MAX))), + GET_UINT64(*((uint64_t*)((size_t)(UINT64_MAX))))); + WRITE_UINT8(*((uint8_t*)((size_t)(INT8_MAX))), + GET_UINT8(*((uint8_t*)((size_t)(INT8_MIN))))); + WRITE_UINT16(*((uint16_t*)((size_t)(INT16_MAX))), + GET_UINT16(*((uint16_t*)((size_t)(INT16_MIN))))); + WRITE_UINT32(*((uint32_t*)((size_t)(INT32_MAX))), + GET_UINT32(*((uint32_t*)((size_t)(INT32_MIN))))); + WRITE_UINT64(*((uint64_t*)((size_t)(INT64_MAX))), + GET_UINT64(*((uint64_t*)((size_t)(INT64_MIN))))); +} + + +#endif /* __TYPES_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/math_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/math_ext.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MATH_EXT_H +#define __MATH_EXT_H + + +#if defined(NCSW_LINUX) && defined(__KERNEL__) +#include + +#elif defined(__MWERKS__) +#define LOW(x) ( sizeof(x)==8 ? *(1+(int32_t*)&x) : (*(int32_t*)&x)) +#define HIGH(x) (*(int32_t*)&x) +#define ULOW(x) ( sizeof(x)==8 ? *(1+(uint32_t*)&x) : (*(uint32_t*)&x)) +#define UHIGH(x) (*(uint32_t*)&x) + +static const double big = 1.0e300; + +/* Macro for checking if a number is a power of 2 */ +static __inline__ double ceil(double x) +{ + int32_t i0,i1,j0; /*- cc 020130 -*/ + uint32_t i,j; /*- cc 020130 -*/ + i0 = HIGH(x); + i1 = LOW(x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(big+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;i1=0;} + else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} + } + } else { + i = (uint32_t)(0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(big+x>0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((uint32_t)(0xffffffff))>>(j0-20); /*- cc 020130 -*/ + if((i1&i)==0) return x; /* x is integral */ + if(big+x>0.0) { /* raise inexact flag */ + if(i0>0) { + if(j0==20) i0+=1; + else { + j = (uint32_t)(i1 + (1<<(52-j0))); + if(j +#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ + + +#endif /* __MATH_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/stdarg_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/stdarg_ext.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STDARG_EXT_H +#define __STDARG_EXT_H + + +#if defined(NCSW_LINUX) && defined(__KERNEL__) +#include + +#else +#include + +#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ + +#include "std_ext.h" + + +#endif /* __STDARG_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/net_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/net_ext.h @@ -0,0 +1,388 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File net_ext.h + + @Description This file contains common and general netcomm headers definitions. +*//***************************************************************************/ +#ifndef __NET_EXT_H +#define __NET_EXT_H + +#include "std_ext.h" + + +typedef uint8_t headerFieldPpp_t; + +#define NET_HEADER_FIELD_PPP_PID (1) +#define NET_HEADER_FIELD_PPP_COMPRESSED (NET_HEADER_FIELD_PPP_PID << 1) +#define NET_HEADER_FIELD_PPP_ALL_FIELDS ((NET_HEADER_FIELD_PPP_PID << 2) - 1) + + +typedef uint8_t headerFieldPppoe_t; + +#define NET_HEADER_FIELD_PPPoE_VER (1) +#define NET_HEADER_FIELD_PPPoE_TYPE (NET_HEADER_FIELD_PPPoE_VER << 1) +#define NET_HEADER_FIELD_PPPoE_CODE (NET_HEADER_FIELD_PPPoE_VER << 2) +#define NET_HEADER_FIELD_PPPoE_SID (NET_HEADER_FIELD_PPPoE_VER << 3) +#define NET_HEADER_FIELD_PPPoE_LEN (NET_HEADER_FIELD_PPPoE_VER << 4) +#define NET_HEADER_FIELD_PPPoE_SESSION (NET_HEADER_FIELD_PPPoE_VER << 5) +#define NET_HEADER_FIELD_PPPoE_PID (NET_HEADER_FIELD_PPPoE_VER << 6) +#define NET_HEADER_FIELD_PPPoE_ALL_FIELDS ((NET_HEADER_FIELD_PPPoE_VER << 7) - 1) + +#define NET_HEADER_FIELD_PPPMUX_PID (1) +#define NET_HEADER_FIELD_PPPMUX_CKSUM (NET_HEADER_FIELD_PPPMUX_PID << 1) +#define NET_HEADER_FIELD_PPPMUX_COMPRESSED (NET_HEADER_FIELD_PPPMUX_PID << 2) +#define NET_HEADER_FIELD_PPPMUX_ALL_FIELDS ((NET_HEADER_FIELD_PPPMUX_PID << 3) - 1) + +#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF (1) +#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1) +#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2) +#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3) +#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4) +#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS ((NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1) + + +typedef uint8_t headerFieldEth_t; + +#define NET_HEADER_FIELD_ETH_DA (1) +#define NET_HEADER_FIELD_ETH_SA (NET_HEADER_FIELD_ETH_DA << 1) +#define NET_HEADER_FIELD_ETH_LENGTH (NET_HEADER_FIELD_ETH_DA << 2) +#define NET_HEADER_FIELD_ETH_TYPE (NET_HEADER_FIELD_ETH_DA << 3) +#define NET_HEADER_FIELD_ETH_FINAL_CKSUM (NET_HEADER_FIELD_ETH_DA << 4) +#define NET_HEADER_FIELD_ETH_PADDING (NET_HEADER_FIELD_ETH_DA << 5) +#define NET_HEADER_FIELD_ETH_ALL_FIELDS ((NET_HEADER_FIELD_ETH_DA << 6) - 1) + + +typedef uint16_t headerFieldIpv4_t; + +#define NET_HEADER_FIELD_IPv4_VER (1) +#define NET_HEADER_FIELD_IPv4_HDR_LEN (NET_HEADER_FIELD_IPv4_VER << 1) +#define NET_HEADER_FIELD_IPv4_TOS (NET_HEADER_FIELD_IPv4_VER << 2) +#define NET_HEADER_FIELD_IPv4_TOTAL_LEN (NET_HEADER_FIELD_IPv4_VER << 3) +#define NET_HEADER_FIELD_IPv4_ID (NET_HEADER_FIELD_IPv4_VER << 4) +#define NET_HEADER_FIELD_IPv4_FLAG_D (NET_HEADER_FIELD_IPv4_VER << 5) +#define NET_HEADER_FIELD_IPv4_FLAG_M (NET_HEADER_FIELD_IPv4_VER << 6) +#define NET_HEADER_FIELD_IPv4_OFFSET (NET_HEADER_FIELD_IPv4_VER << 7) +#define NET_HEADER_FIELD_IPv4_TTL (NET_HEADER_FIELD_IPv4_VER << 8) +#define NET_HEADER_FIELD_IPv4_PROTO (NET_HEADER_FIELD_IPv4_VER << 9) +#define NET_HEADER_FIELD_IPv4_CKSUM (NET_HEADER_FIELD_IPv4_VER << 10) +#define NET_HEADER_FIELD_IPv4_SRC_IP (NET_HEADER_FIELD_IPv4_VER << 11) +#define NET_HEADER_FIELD_IPv4_DST_IP (NET_HEADER_FIELD_IPv4_VER << 12) +#define NET_HEADER_FIELD_IPv4_OPTS (NET_HEADER_FIELD_IPv4_VER << 13) +#define NET_HEADER_FIELD_IPv4_OPTS_COUNT (NET_HEADER_FIELD_IPv4_VER << 14) +#define NET_HEADER_FIELD_IPv4_ALL_FIELDS ((NET_HEADER_FIELD_IPv4_VER << 15) - 1) + + +typedef uint8_t headerFieldIpv6_t; + +#define NET_HEADER_FIELD_IPv6_VER (1) +#define NET_HEADER_FIELD_IPv6_TC (NET_HEADER_FIELD_IPv6_VER << 1) +#define NET_HEADER_FIELD_IPv6_SRC_IP (NET_HEADER_FIELD_IPv6_VER << 2) +#define NET_HEADER_FIELD_IPv6_DST_IP (NET_HEADER_FIELD_IPv6_VER << 3) +#define NET_HEADER_FIELD_IPv6_NEXT_HDR (NET_HEADER_FIELD_IPv6_VER << 4) +#define NET_HEADER_FIELD_IPv6_FL (NET_HEADER_FIELD_IPv6_VER << 5) +#define NET_HEADER_FIELD_IPv6_HOP_LIMIT (NET_HEADER_FIELD_IPv6_VER << 6) +#define NET_HEADER_FIELD_IPv6_ALL_FIELDS ((NET_HEADER_FIELD_IPv6_VER << 7) - 1) + +#define NET_HEADER_FIELD_ICMP_TYPE (1) +#define NET_HEADER_FIELD_ICMP_CODE (NET_HEADER_FIELD_ICMP_TYPE << 1) +#define NET_HEADER_FIELD_ICMP_CKSUM (NET_HEADER_FIELD_ICMP_TYPE << 2) +#define NET_HEADER_FIELD_ICMP_ID (NET_HEADER_FIELD_ICMP_TYPE << 3) +#define NET_HEADER_FIELD_ICMP_SQ_NUM (NET_HEADER_FIELD_ICMP_TYPE << 4) +#define NET_HEADER_FIELD_ICMP_ALL_FIELDS ((NET_HEADER_FIELD_ICMP_TYPE << 5) - 1) + +#define NET_HEADER_FIELD_IGMP_VERSION (1) +#define NET_HEADER_FIELD_IGMP_TYPE (NET_HEADER_FIELD_IGMP_VERSION << 1) +#define NET_HEADER_FIELD_IGMP_CKSUM (NET_HEADER_FIELD_IGMP_VERSION << 2) +#define NET_HEADER_FIELD_IGMP_DATA (NET_HEADER_FIELD_IGMP_VERSION << 3) +#define NET_HEADER_FIELD_IGMP_ALL_FIELDS ((NET_HEADER_FIELD_IGMP_VERSION << 4) - 1) + + +typedef uint16_t headerFieldTcp_t; + +#define NET_HEADER_FIELD_TCP_PORT_SRC (1) +#define NET_HEADER_FIELD_TCP_PORT_DST (NET_HEADER_FIELD_TCP_PORT_SRC << 1) +#define NET_HEADER_FIELD_TCP_SEQ (NET_HEADER_FIELD_TCP_PORT_SRC << 2) +#define NET_HEADER_FIELD_TCP_ACK (NET_HEADER_FIELD_TCP_PORT_SRC << 3) +#define NET_HEADER_FIELD_TCP_OFFSET (NET_HEADER_FIELD_TCP_PORT_SRC << 4) +#define NET_HEADER_FIELD_TCP_FLAGS (NET_HEADER_FIELD_TCP_PORT_SRC << 5) +#define NET_HEADER_FIELD_TCP_WINDOW (NET_HEADER_FIELD_TCP_PORT_SRC << 6) +#define NET_HEADER_FIELD_TCP_CKSUM (NET_HEADER_FIELD_TCP_PORT_SRC << 7) +#define NET_HEADER_FIELD_TCP_URGPTR (NET_HEADER_FIELD_TCP_PORT_SRC << 8) +#define NET_HEADER_FIELD_TCP_OPTS (NET_HEADER_FIELD_TCP_PORT_SRC << 9) +#define NET_HEADER_FIELD_TCP_OPTS_COUNT (NET_HEADER_FIELD_TCP_PORT_SRC << 10) +#define NET_HEADER_FIELD_TCP_ALL_FIELDS ((NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1) + + +typedef uint8_t headerFieldSctp_t; + +#define NET_HEADER_FIELD_SCTP_PORT_SRC (1) +#define NET_HEADER_FIELD_SCTP_PORT_DST (NET_HEADER_FIELD_SCTP_PORT_SRC << 1) +#define NET_HEADER_FIELD_SCTP_VER_TAG (NET_HEADER_FIELD_SCTP_PORT_SRC << 2) +#define NET_HEADER_FIELD_SCTP_CKSUM (NET_HEADER_FIELD_SCTP_PORT_SRC << 3) +#define NET_HEADER_FIELD_SCTP_ALL_FIELDS ((NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1) + + +typedef uint8_t headerFieldDccp_t; + +#define NET_HEADER_FIELD_DCCP_PORT_SRC (1) +#define NET_HEADER_FIELD_DCCP_PORT_DST (NET_HEADER_FIELD_DCCP_PORT_SRC << 1) +#define NET_HEADER_FIELD_DCCP_ALL_FIELDS ((NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1) + + +typedef uint8_t headerFieldUdp_t; + +#define NET_HEADER_FIELD_UDP_PORT_SRC (1) +#define NET_HEADER_FIELD_UDP_PORT_DST (NET_HEADER_FIELD_UDP_PORT_SRC << 1) +#define NET_HEADER_FIELD_UDP_LEN (NET_HEADER_FIELD_UDP_PORT_SRC << 2) +#define NET_HEADER_FIELD_UDP_CKSUM (NET_HEADER_FIELD_UDP_PORT_SRC << 3) +#define NET_HEADER_FIELD_UDP_ALL_FIELDS ((NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1) + +typedef uint8_t headerFieldUdpEncapEsp_t; + +#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC (1) +#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1) +#define NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2) +#define NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3) +#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4) +#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5) +#define NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS ((NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1) + +#define NET_HEADER_FIELD_IPHC_CID (1) +#define NET_HEADER_FIELD_IPHC_CID_TYPE (NET_HEADER_FIELD_IPHC_CID << 1) +#define NET_HEADER_FIELD_IPHC_HCINDEX (NET_HEADER_FIELD_IPHC_CID << 2) +#define NET_HEADER_FIELD_IPHC_GEN (NET_HEADER_FIELD_IPHC_CID << 3) +#define NET_HEADER_FIELD_IPHC_D_BIT (NET_HEADER_FIELD_IPHC_CID << 4) +#define NET_HEADER_FIELD_IPHC_ALL_FIELDS ((NET_HEADER_FIELD_IPHC_CID << 5) - 1) + +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE (1) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_END (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9) +#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS ((NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1) + +#define NET_HEADER_FIELD_L2TPv2_TYPE_BIT (1) +#define NET_HEADER_FIELD_L2TPv2_LENGTH_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 1) +#define NET_HEADER_FIELD_L2TPv2_SEQUENCE_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 2) +#define NET_HEADER_FIELD_L2TPv2_OFFSET_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 3) +#define NET_HEADER_FIELD_L2TPv2_PRIORITY_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 4) +#define NET_HEADER_FIELD_L2TPv2_VERSION (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 5) +#define NET_HEADER_FIELD_L2TPv2_LEN (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 6) +#define NET_HEADER_FIELD_L2TPv2_TUNNEL_ID (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 7) +#define NET_HEADER_FIELD_L2TPv2_SESSION_ID (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 8) +#define NET_HEADER_FIELD_L2TPv2_NS (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 9) +#define NET_HEADER_FIELD_L2TPv2_NR (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 10) +#define NET_HEADER_FIELD_L2TPv2_OFFSET_SIZE (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 11) +#define NET_HEADER_FIELD_L2TPv2_FIRST_BYTE (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 12) +#define NET_HEADER_FIELD_L2TPv2_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 13) - 1) + +#define NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT (1) +#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH_BIT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 1) +#define NET_HEADER_FIELD_L2TPv3_CTRL_SEQUENCE_BIT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 2) +#define NET_HEADER_FIELD_L2TPv3_CTRL_VERSION (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 3) +#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 4) +#define NET_HEADER_FIELD_L2TPv3_CTRL_CONTROL (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 5) +#define NET_HEADER_FIELD_L2TPv3_CTRL_SENT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 6) +#define NET_HEADER_FIELD_L2TPv3_CTRL_RECV (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 7) +#define NET_HEADER_FIELD_L2TPv3_CTRL_FIRST_BYTE (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 8) +#define NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 9) - 1) + +#define NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT (1) +#define NET_HEADER_FIELD_L2TPv3_SESS_VERSION (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 1) +#define NET_HEADER_FIELD_L2TPv3_SESS_ID (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 2) +#define NET_HEADER_FIELD_L2TPv3_SESS_COOKIE (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 3) +#define NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 4) - 1) + + +typedef uint8_t headerFieldVlan_t; + +#define NET_HEADER_FIELD_VLAN_VPRI (1) +#define NET_HEADER_FIELD_VLAN_CFI (NET_HEADER_FIELD_VLAN_VPRI << 1) +#define NET_HEADER_FIELD_VLAN_VID (NET_HEADER_FIELD_VLAN_VPRI << 2) +#define NET_HEADER_FIELD_VLAN_LENGTH (NET_HEADER_FIELD_VLAN_VPRI << 3) +#define NET_HEADER_FIELD_VLAN_TYPE (NET_HEADER_FIELD_VLAN_VPRI << 4) +#define NET_HEADER_FIELD_VLAN_ALL_FIELDS ((NET_HEADER_FIELD_VLAN_VPRI << 5) - 1) + +#define NET_HEADER_FIELD_VLAN_TCI (NET_HEADER_FIELD_VLAN_VPRI | \ + NET_HEADER_FIELD_VLAN_CFI | \ + NET_HEADER_FIELD_VLAN_VID) + + +typedef uint8_t headerFieldLlc_t; + +#define NET_HEADER_FIELD_LLC_DSAP (1) +#define NET_HEADER_FIELD_LLC_SSAP (NET_HEADER_FIELD_LLC_DSAP << 1) +#define NET_HEADER_FIELD_LLC_CTRL (NET_HEADER_FIELD_LLC_DSAP << 2) +#define NET_HEADER_FIELD_LLC_ALL_FIELDS ((NET_HEADER_FIELD_LLC_DSAP << 3) - 1) + +#define NET_HEADER_FIELD_NLPID_NLPID (1) +#define NET_HEADER_FIELD_NLPID_ALL_FIELDS ((NET_HEADER_FIELD_NLPID_NLPID << 1) - 1) + + +typedef uint8_t headerFieldSnap_t; + +#define NET_HEADER_FIELD_SNAP_OUI (1) +#define NET_HEADER_FIELD_SNAP_PID (NET_HEADER_FIELD_SNAP_OUI << 1) +#define NET_HEADER_FIELD_SNAP_ALL_FIELDS ((NET_HEADER_FIELD_SNAP_OUI << 2) - 1) + + +typedef uint8_t headerFieldLlcSnap_t; + +#define NET_HEADER_FIELD_LLC_SNAP_TYPE (1) +#define NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS ((NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1) + +#define NET_HEADER_FIELD_ARP_HTYPE (1) +#define NET_HEADER_FIELD_ARP_PTYPE (NET_HEADER_FIELD_ARP_HTYPE << 1) +#define NET_HEADER_FIELD_ARP_HLEN (NET_HEADER_FIELD_ARP_HTYPE << 2) +#define NET_HEADER_FIELD_ARP_PLEN (NET_HEADER_FIELD_ARP_HTYPE << 3) +#define NET_HEADER_FIELD_ARP_OPER (NET_HEADER_FIELD_ARP_HTYPE << 4) +#define NET_HEADER_FIELD_ARP_SHA (NET_HEADER_FIELD_ARP_HTYPE << 5) +#define NET_HEADER_FIELD_ARP_SPA (NET_HEADER_FIELD_ARP_HTYPE << 6) +#define NET_HEADER_FIELD_ARP_THA (NET_HEADER_FIELD_ARP_HTYPE << 7) +#define NET_HEADER_FIELD_ARP_TPA (NET_HEADER_FIELD_ARP_HTYPE << 8) +#define NET_HEADER_FIELD_ARP_ALL_FIELDS ((NET_HEADER_FIELD_ARP_HTYPE << 9) - 1) + +#define NET_HEADER_FIELD_RFC2684_LLC (1) +#define NET_HEADER_FIELD_RFC2684_NLPID (NET_HEADER_FIELD_RFC2684_LLC << 1) +#define NET_HEADER_FIELD_RFC2684_OUI (NET_HEADER_FIELD_RFC2684_LLC << 2) +#define NET_HEADER_FIELD_RFC2684_PID (NET_HEADER_FIELD_RFC2684_LLC << 3) +#define NET_HEADER_FIELD_RFC2684_VPN_OUI (NET_HEADER_FIELD_RFC2684_LLC << 4) +#define NET_HEADER_FIELD_RFC2684_VPN_IDX (NET_HEADER_FIELD_RFC2684_LLC << 5) +#define NET_HEADER_FIELD_RFC2684_ALL_FIELDS ((NET_HEADER_FIELD_RFC2684_LLC << 6) - 1) + +#define NET_HEADER_FIELD_USER_DEFINED_SRCPORT (1) +#define NET_HEADER_FIELD_USER_DEFINED_PCDID (NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1) +#define NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS ((NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1) + +#define NET_HEADER_FIELD_PAYLOAD_BUFFER (1) +#define NET_HEADER_FIELD_PAYLOAD_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 1) +#define NET_HEADER_FIELD_MAX_FRM_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 2) +#define NET_HEADER_FIELD_MIN_FRM_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 3) +#define NET_HEADER_FIELD_PAYLOAD_TYPE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 4) +#define NET_HEADER_FIELD_FRAME_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 5) +#define NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS ((NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1) + + +typedef uint8_t headerFieldGre_t; + +#define NET_HEADER_FIELD_GRE_TYPE (1) +#define NET_HEADER_FIELD_GRE_ALL_FIELDS ((NET_HEADER_FIELD_GRE_TYPE << 1) - 1) + + +typedef uint8_t headerFieldMinencap_t; + +#define NET_HEADER_FIELD_MINENCAP_SRC_IP (1) +#define NET_HEADER_FIELD_MINENCAP_DST_IP (NET_HEADER_FIELD_MINENCAP_SRC_IP << 1) +#define NET_HEADER_FIELD_MINENCAP_TYPE (NET_HEADER_FIELD_MINENCAP_SRC_IP << 2) +#define NET_HEADER_FIELD_MINENCAP_ALL_FIELDS ((NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1) + + +typedef uint8_t headerFieldIpsecAh_t; + +#define NET_HEADER_FIELD_IPSEC_AH_SPI (1) +#define NET_HEADER_FIELD_IPSEC_AH_NH (NET_HEADER_FIELD_IPSEC_AH_SPI << 1) +#define NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS ((NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1) + + +typedef uint8_t headerFieldIpsecEsp_t; + +#define NET_HEADER_FIELD_IPSEC_ESP_SPI (1) +#define NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM (NET_HEADER_FIELD_IPSEC_ESP_SPI << 1) +#define NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS ((NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1) + + +typedef uint8_t headerFieldMpls_t; + +#define NET_HEADER_FIELD_MPLS_LABEL_STACK (1) +#define NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS ((NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1) + + +typedef uint8_t headerFieldMacsec_t; + +#define NET_HEADER_FIELD_MACSEC_SECTAG (1) +#define NET_HEADER_FIELD_MACSEC_ALL_FIELDS ((NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1) + + +typedef enum { + HEADER_TYPE_NONE = 0, + HEADER_TYPE_PAYLOAD, + HEADER_TYPE_ETH, + HEADER_TYPE_VLAN, + HEADER_TYPE_IPv4, + HEADER_TYPE_IPv6, + HEADER_TYPE_TCP, + HEADER_TYPE_UDP, + HEADER_TYPE_IPHC, + HEADER_TYPE_SCTP, + HEADER_TYPE_SCTP_CHUNK_DATA, + HEADER_TYPE_PPPoE, + HEADER_TYPE_PPP, + HEADER_TYPE_PPPMUX, + HEADER_TYPE_PPPMUX_SUBFRAME, + HEADER_TYPE_L2TPv2, + HEADER_TYPE_L2TPv3_CTRL, + HEADER_TYPE_L2TPv3_SESS, + HEADER_TYPE_LLC, + HEADER_TYPE_LLC_SNAP, + HEADER_TYPE_NLPID, + HEADER_TYPE_SNAP, + HEADER_TYPE_MPLS, + HEADER_TYPE_IPSEC_AH, + HEADER_TYPE_IPSEC_ESP, + HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */ + HEADER_TYPE_MACSEC, + HEADER_TYPE_GRE, + HEADER_TYPE_MINENCAP, + HEADER_TYPE_DCCP, + HEADER_TYPE_ICMP, + HEADER_TYPE_IGMP, + HEADER_TYPE_ARP, + HEADER_TYPE_CAPWAP, + HEADER_TYPE_CAPWAP_DTLS, + HEADER_TYPE_RFC2684, + HEADER_TYPE_USER_DEFINED_L2, + HEADER_TYPE_USER_DEFINED_L3, + HEADER_TYPE_USER_DEFINED_L4, + HEADER_TYPE_USER_DEFINED_SHIM1, + HEADER_TYPE_USER_DEFINED_SHIM2, + MAX_HEADER_TYPE_COUNT +} e_NetHeaderType; + + +#endif /* __NET_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/stdlib_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/stdlib_ext.h @@ -0,0 +1,161 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __STDLIB_EXT_H +#define __STDLIB_EXT_H + + +#if (defined(NCSW_LINUX)) && defined(__KERNEL__) +#include "stdarg_ext.h" +#include "std_ext.h" + + +/** + * strtoul - convert a string to an uint32_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +uint32_t strtoul(const char *cp,char **endp,uint32_t base); + +/** + * strtol - convert a string to a int32_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long strtol(const char *cp,char **endp,uint32_t base); + +/** + * strtoull - convert a string to an uint64_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +uint64_t strtoull(const char *cp,char **endp,uint32_t base); + +/** + * strtoll - convert a string to a int64 long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long long strtoll(const char *cp,char **endp,uint32_t base); + +/** + * atoi - convert a character to a int + * @s: The start of the string + */ +int atoi(const char *s); + +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char * s, size_t count); + +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char * s); + +/** + * strtok - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * WARNING: strtok is deprecated, use strsep instead. + */ +char * strtok(char * s,const char * ct); + +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ +char * strncpy(char * dest,const char *src,size_t count); + +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ +char * strcpy(char * dest,const char *src); + +/** + * vsscanf - Unformat a buffer into a list of arguments + * @buf: input buffer + * @fmt: format of buffer + * @args: arguments + */ +int vsscanf(const char * buf, const char * fmt, va_list args); + +/** + * vsnprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @size: The size of the buffer, including the trailing null space + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want snprintf instead. + */ +int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); + +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf instead. + */ +int vsprintf(char *buf, const char *fmt, va_list args); + +#else +#include +#include +#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ + +#include "std_ext.h" + + +#endif /* __STDLIB_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/core_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/core_ext.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File core_ext.h + + @Description Generic interface to basic core operations. + + The system integrator must ensure that this interface is + mapped to a specific core implementation, by including the + appropriate header file. +*//***************************************************************************/ +#ifndef __CORE_EXT_H +#define __CORE_EXT_H + + +#ifdef NCSW_PPC_CORE +#include "ppc_ext.h" +#elif defined(NCSW_VXWORKS) +#include "core_vxw_ext.h" +#else +#error "Core is not defined!" +#endif /* NCSW_CORE */ + +#if (!defined(CORE_IS_LITTLE_ENDIAN) && !defined(CORE_IS_BIG_ENDIAN)) +#error "Must define core as little-endian or big-endian!" +#endif /* (!defined(CORE_IS_LITTLE_ENDIAN) && ... */ + + +/**************************************************************************//** + @Function CORE_GetId + + @Description Returns the core ID in the system. + + @Return Core ID. +*//***************************************************************************/ +uint32_t CORE_GetId(void); + +/**************************************************************************//** + @Function CORE_MemoryBarrier + + @Description This routine will cause the core to stop executing any commands + until all previous memory read/write commands are completely out + of the core's pipeline. + + @Return None. +*//***************************************************************************/ +void CORE_MemoryBarrier(void); + + +#endif /* __CORE_EXT_H */ + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/std_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/std_ext.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /**************************************************************************//** + + @File std_ext.h + + @Description General Standard Definitions +*//***************************************************************************/ + +#ifndef __STD_EXT_H +#define __STD_EXT_H + + +#include "types_ext.h" +#include "ncsw_ext.h" + + +#endif /* __STD_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/etc/list_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/etc/list_ext.h @@ -0,0 +1,357 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + + @File list_ext.h + + @Description External prototypes for list.c +*//***************************************************************************/ + +#ifndef __LIST_EXT_H +#define __LIST_EXT_H + + +#include "std_ext.h" + + +/**************************************************************************//** + @Group etc_id Utility Library Application Programming Interface + + @Description External routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group list_id List + + @Description List module functions,definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description List structure. +*//***************************************************************************/ +typedef struct List +{ + struct List *p_Next; /**< A pointer to the next list object */ + struct List *p_Prev; /**< A pointer to the previous list object */ +} t_List; + + +/**************************************************************************//** + @Function LIST_FIRST/LIST_LAST/LIST_NEXT/LIST_PREV + + @Description Macro to get first/last/next/previous entry in a list. + + @Param[in] p_List - A pointer to a list. +*//***************************************************************************/ +#define LIST_FIRST(p_List) (p_List)->p_Next +#define LIST_LAST(p_List) (p_List)->p_Prev +#define LIST_NEXT LIST_FIRST +#define LIST_PREV LIST_LAST + + +/**************************************************************************//** + @Function LIST_INIT + + @Description Macro for initialization of a list struct. + + @Param[in] lst - The t_List object to initialize. +*//***************************************************************************/ +#define LIST_INIT(lst) {&(lst), &(lst)} + + +/**************************************************************************//** + @Function LIST + + @Description Macro to declare of a list. + + @Param[in] listName - The list object name. +*//***************************************************************************/ +#define LIST(listName) t_List listName = LIST_INIT(listName) + + +/**************************************************************************//** + @Function INIT_LIST + + @Description Macro to initialize a list pointer. + + @Param[in] p_List - The list pointer. +*//***************************************************************************/ +#define INIT_LIST(p_List) LIST_FIRST(p_List) = LIST_LAST(p_List) = (p_List) + + +/**************************************************************************//** + @Function LIST_OBJECT + + @Description Macro to get the struct (object) for this entry. + + @Param[in] type - The type of the struct (object) this list is embedded in. + @Param[in] member - The name of the t_List object within the struct. + + @Return The structure pointer for this entry. +*//***************************************************************************/ +#define MEMBER_OFFSET(type, member) (PTR_TO_UINT(&((type *)0)->member)) +#define LIST_OBJECT(p_List, type, member) \ + ((type *)((char *)(p_List)-MEMBER_OFFSET(type, member))) + + +/**************************************************************************//** + @Function LIST_FOR_EACH + + @Description Macro to iterate over a list. + + @Param[in] p_Pos - A pointer to a list to use as a loop counter. + @Param[in] p_Head - A pointer to the head for your list pointer. + + @Cautions You can't delete items with this routine. + For deletion use LIST_FOR_EACH_SAFE(). +*//***************************************************************************/ +#define LIST_FOR_EACH(p_Pos, p_Head) \ + for (p_Pos = LIST_FIRST(p_Head); p_Pos != (p_Head); p_Pos = LIST_NEXT(p_Pos)) + + +/**************************************************************************//** + @Function LIST_FOR_EACH_SAFE + + @Description Macro to iterate over a list safe against removal of list entry. + + @Param[in] p_Pos - A pointer to a list to use as a loop counter. + @Param[in] p_Tmp - Another pointer to a list to use as temporary storage. + @Param[in] p_Head - A pointer to the head for your list pointer. +*//***************************************************************************/ +#define LIST_FOR_EACH_SAFE(p_Pos, p_Tmp, p_Head) \ + for (p_Pos = LIST_FIRST(p_Head), p_Tmp = LIST_FIRST(p_Pos); \ + p_Pos != (p_Head); \ + p_Pos = p_Tmp, p_Tmp = LIST_NEXT(p_Pos)) + + +/**************************************************************************//** + @Function LIST_FOR_EACH_OBJECT_SAFE + + @Description Macro to iterate over list of given type safely. + + @Param[in] p_Pos - A pointer to a list to use as a loop counter. + @Param[in] p_Tmp - Another pointer to a list to use as temporary storage. + @Param[in] type - The type of the struct this is embedded in. + @Param[in] p_Head - A pointer to the head for your list pointer. + @Param[in] member - The name of the list_struct within the struct. + + @Cautions You can't delete items with this routine. + For deletion use LIST_FOR_EACH_SAFE(). +*//***************************************************************************/ +#define LIST_FOR_EACH_OBJECT_SAFE(p_Pos, p_Tmp, p_Head, type, member) \ + for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member), \ + p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member); \ + &p_Pos->member != (p_Head); \ + p_Pos = p_Tmp, \ + p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member)) + +/**************************************************************************//** + @Function LIST_FOR_EACH_OBJECT + + @Description Macro to iterate over list of given type. + + @Param[in] p_Pos - A pointer to a list to use as a loop counter. + @Param[in] type - The type of the struct this is embedded in. + @Param[in] p_Head - A pointer to the head for your list pointer. + @Param[in] member - The name of the list_struct within the struct. + + @Cautions You can't delete items with this routine. + For deletion use LIST_FOR_EACH_SAFE(). +*//***************************************************************************/ +#define LIST_FOR_EACH_OBJECT(p_Pos, type, p_Head, member) \ + for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member); \ + &p_Pos->member != (p_Head); \ + p_Pos = LIST_OBJECT(LIST_FIRST(&(p_Pos->member)), type, member)) + + +/**************************************************************************//** + @Function LIST_Add + + @Description Add a new entry to a list. + + Insert a new entry after the specified head. + This is good for implementing stacks. + + @Param[in] p_New - A pointer to a new list entry to be added. + @Param[in] p_Head - A pointer to a list head to add it after. + + @Return none. +*//***************************************************************************/ +static __inline__ void LIST_Add(t_List *p_New, t_List *p_Head) +{ + LIST_PREV(LIST_NEXT(p_Head)) = p_New; + LIST_NEXT(p_New) = LIST_NEXT(p_Head); + LIST_PREV(p_New) = p_Head; + LIST_NEXT(p_Head) = p_New; +} + + +/**************************************************************************//** + @Function LIST_AddToTail + + @Description Add a new entry to a list. + + Insert a new entry before the specified head. + This is useful for implementing queues. + + @Param[in] p_New - A pointer to a new list entry to be added. + @Param[in] p_Head - A pointer to a list head to add it after. + + @Return none. +*//***************************************************************************/ +static __inline__ void LIST_AddToTail(t_List *p_New, t_List *p_Head) +{ + LIST_NEXT(LIST_PREV(p_Head)) = p_New; + LIST_PREV(p_New) = LIST_PREV(p_Head); + LIST_NEXT(p_New) = p_Head; + LIST_PREV(p_Head) = p_New; +} + + +/**************************************************************************//** + @Function LIST_Del + + @Description Deletes entry from a list. + + @Param[in] p_Entry - A pointer to the element to delete from the list. + + @Return none. + + @Cautions LIST_IsEmpty() on entry does not return true after this, + the entry is in an undefined state. +*//***************************************************************************/ +static __inline__ void LIST_Del(t_List *p_Entry) +{ + LIST_PREV(LIST_NEXT(p_Entry)) = LIST_PREV(p_Entry); + LIST_NEXT(LIST_PREV(p_Entry)) = LIST_NEXT(p_Entry); +} + + +/**************************************************************************//** + @Function LIST_DelAndInit + + @Description Deletes entry from list and reinitialize it. + + @Param[in] p_Entry - A pointer to the element to delete from the list. + + @Return none. +*//***************************************************************************/ +static __inline__ void LIST_DelAndInit(t_List *p_Entry) +{ + LIST_Del(p_Entry); + INIT_LIST(p_Entry); +} + + +/**************************************************************************//** + @Function LIST_Move + + @Description Delete from one list and add as another's head. + + @Param[in] p_Entry - A pointer to the list entry to move. + @Param[in] p_Head - A pointer to the list head that will precede our entry. + + @Return none. +*//***************************************************************************/ +static __inline__ void LIST_Move(t_List *p_Entry, t_List *p_Head) +{ + LIST_Del(p_Entry); + LIST_Add(p_Entry, p_Head); +} + + +/**************************************************************************//** + @Function LIST_MoveToTail + + @Description Delete from one list and add as another's tail. + + @Param[in] p_Entry - A pointer to the entry to move. + @Param[in] p_Head - A pointer to the list head that will follow our entry. + + @Return none. +*//***************************************************************************/ +static __inline__ void LIST_MoveToTail(t_List *p_Entry, t_List *p_Head) +{ + LIST_Del(p_Entry); + LIST_AddToTail(p_Entry, p_Head); +} + + +/**************************************************************************//** + @Function LIST_IsEmpty + + @Description Tests whether a list is empty. + + @Param[in] p_List - A pointer to the list to test. + + @Return 1 if the list is empty, 0 otherwise. +*//***************************************************************************/ +static __inline__ int LIST_IsEmpty(t_List *p_List) +{ + return (LIST_FIRST(p_List) == p_List); +} + + +/**************************************************************************//** + @Function LIST_Append + + @Description Join two lists. + + @Param[in] p_NewList - A pointer to the new list to add. + @Param[in] p_Head - A pointer to the place to add it in the first list. + + @Return none. +*//***************************************************************************/ +void LIST_Append(t_List *p_NewList, t_List *p_Head); + + +/**************************************************************************//** + @Function LIST_NumOfObjs + + @Description Counts number of objects in the list + + @Param[in] p_List - A pointer to the list which objects are to be counted. + + @Return Number of objects in the list. +*//***************************************************************************/ +int LIST_NumOfObjs(t_List *p_List); + +/** @} */ /* end of list_id group */ +/** @} */ /* end of etc_id group */ + + +#endif /* __LIST_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/etc/sprint_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/etc/sprint_ext.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + + @File sprint_ext.h + + @Description Debug routines (externals). + +*//***************************************************************************/ + +#ifndef __SPRINT_EXT_H +#define __SPRINT_EXT_H + + +#if defined(NCSW_LINUX) && defined(__KERNEL__) +#include + +#elif defined(NCSW_LINUX_USD) +#include +#include "stdarg_ext.h" +#include "std_ext.h" + +extern int vsscanf(const char *, const char *, va_list); + +#elif defined(NCSW_VXWORKS) +#include "private/stdioP.h" + +#else +#include +#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ + +#include "std_ext.h" + + +/**************************************************************************//** + @Group etc_id Utility Library Application Programming Interface + + @Description External routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group sprint_id Sprint + + @Description Sprint & Sscan module functions,definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function Sprint + + @Description Format a string and place it in a buffer. + + @Param[in] buff - The buffer to place the result into. + @Param[in] str - The format string to use. + @Param[in] ... - Arguments for the format string. + + @Return Number of bytes formatted. +*//***************************************************************************/ +int Sprint(char *buff, const char *str, ...); + +/**************************************************************************//** + @Function Snprint + + @Description Format a string and place it in a buffer. + + @Param[in] buf - The buffer to place the result into. + @Param[in] size - The size of the buffer, including the trailing null space. + @Param[in] fmt - The format string to use. + @Param[in] ... - Arguments for the format string. + + @Return Number of bytes formatted. +*//***************************************************************************/ +int Snprint(char * buf, uint32_t size, const char *fmt, ...); + +/**************************************************************************//** + @Function Sscan + + @Description Unformat a buffer into a list of arguments. + + @Param[in] buf - input buffer. + @Param[in] fmt - formatting of buffer. + @Param[out] ... - resulting arguments. + + @Return Number of bytes unformatted. +*//***************************************************************************/ +int Sscan(const char * buf, const char * fmt, ...); + +/** @} */ /* end of sprint_id group */ +/** @} */ /* end of etc_id group */ + + +#endif /* __SPRINT_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/etc/mem_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/etc/mem_ext.h @@ -0,0 +1,317 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + + @File mem_ext.h + + @Description External prototypes for the memory manager object +*//***************************************************************************/ + +#ifndef __MEM_EXT_H +#define __MEM_EXT_H + +#include "std_ext.h" +#include "part_ext.h" + + +/**************************************************************************//** + @Group etc_id Utility Library Application Programming Interface + + @Description External routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group mem_id Slab Memory Manager + + @Description Slab Memory Manager module functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/* Each block is of the following structure: + * + * + * +-----------+----------+---------------------------+-----------+-----------+ + * | Alignment | Prefix | Data | Postfix | Alignment | + * | field | field | field | field | Padding | + * | | | | | | + * +-----------+----------+---------------------------+-----------+-----------+ + * and at the beginning of all bytes, an additional optional padding might reside + * to ensure that the first blocks data field is aligned as requested. + */ + + +#define MEM_MAX_NAME_LENGTH 8 + +/**************************************************************************//* + @Description Memory Segment structure +*//***************************************************************************/ + +typedef struct +{ + char name[MEM_MAX_NAME_LENGTH]; + /* The segment's name */ + uint8_t **p_Bases; /* Base addresses of the segments */ + uint8_t **p_BlocksStack; /* Array of pointers to blocks */ + t_Handle h_Spinlock; + uint16_t dataSize; /* Size of each data block */ + uint16_t prefixSize; /* How many bytes to reserve before the data */ + uint16_t postfixSize; /* How many bytes to reserve after the data */ + uint16_t alignment; /* Requested alignment for the data field */ + int allocOwner; /* Memory allocation owner */ + uint32_t getFailures; /* Number of times get failed */ + uint32_t num; /* Number of blocks in segment */ + uint32_t current; /* Current block */ + bool consecutiveMem; /* Allocate consecutive data blocks memory */ +#ifdef DEBUG_MEM_LEAKS + void *p_MemDbg; /* MEM debug database (MEM leaks detection) */ + uint32_t blockOffset; + uint32_t blockSize; +#endif /* DEBUG_MEM_LEAKS */ +} t_MemorySegment; + + + +/**************************************************************************//** + @Function MEM_Init + + @Description Create a new memory segment. + + @Param[in] name - Name of memory partition. + @Param[in] p_Handle - Handle to new segment is returned through here. + @Param[in] num - Number of blocks in new segment. + @Param[in] dataSize - Size of blocks in segment. + @Param[in] prefixSize - How many bytes to allocate before the data. + @Param[in] postfixSize - How many bytes to allocate after the data. + @Param[in] alignment - Requested alignment for data field (in bytes). + + @Return E_OK - success, E_NO_MEMORY - out of memory. +*//***************************************************************************/ +t_Error MEM_Init(char name[], + t_Handle *p_Handle, + uint32_t num, + uint16_t dataSize, + uint16_t prefixSize, + uint16_t postfixSize, + uint16_t alignment); + +/**************************************************************************//** + @Function MEM_InitSmart + + @Description Create a new memory segment. + + @Param[in] name - Name of memory partition. + @Param[in] p_Handle - Handle to new segment is returned through here. + @Param[in] num - Number of blocks in new segment. + @Param[in] dataSize - Size of blocks in segment. + @Param[in] prefixSize - How many bytes to allocate before the data. + @Param[in] postfixSize - How many bytes to allocate after the data. + @Param[in] alignment - Requested alignment for data field (in bytes). + @Param[in] memPartitionId - Memory partition ID for allocation. + @Param[in] consecutiveMem - Whether to allocate the memory blocks + continuously or not. + + @Return E_OK - success, E_NO_MEMORY - out of memory. +*//***************************************************************************/ +t_Error MEM_InitSmart(char name[], + t_Handle *p_Handle, + uint32_t num, + uint16_t dataSize, + uint16_t prefixSize, + uint16_t postfixSize, + uint16_t alignment, + uint8_t memPartitionId, + bool consecutiveMem); + +/**************************************************************************//** + @Function MEM_InitByAddress + + @Description Create a new memory segment with a specified base address. + + @Param[in] name - Name of memory partition. + @Param[in] p_Handle - Handle to new segment is returned through here. + @Param[in] num - Number of blocks in new segment. + @Param[in] dataSize - Size of blocks in segment. + @Param[in] prefixSize - How many bytes to allocate before the data. + @Param[in] postfixSize - How many bytes to allocate after the data. + @Param[in] alignment - Requested alignment for data field (in bytes). + @Param[in] address - The required base address. + + @Return E_OK - success, E_NO_MEMORY - out of memory. + *//***************************************************************************/ +t_Error MEM_InitByAddress(char name[], + t_Handle *p_Handle, + uint32_t num, + uint16_t dataSize, + uint16_t prefixSize, + uint16_t postfixSize, + uint16_t alignment, + uint8_t *address); + +/**************************************************************************//** + @Function MEM_Free + + @Description Free a specific memory segment. + + @Param[in] h_Mem - Handle to memory segment. + + @Return None. +*//***************************************************************************/ +void MEM_Free(t_Handle h_Mem); + +/**************************************************************************//** + @Function MEM_Get + + @Description Get a block of memory from a segment. + + @Param[in] h_Mem - Handle to memory segment. + + @Return Pointer to new memory block on success,0 otherwise. +*//***************************************************************************/ +void * MEM_Get(t_Handle h_Mem); + +/**************************************************************************//** + @Function MEM_GetN + + @Description Get up to N blocks of memory from a segment. + + The blocks are assumed to be of a fixed size (one size per segment). + + @Param[in] h_Mem - Handle to memory segment. + @Param[in] num - Number of blocks to allocate. + @Param[out] array - Array of at least num pointers to which the addresses + of the allocated blocks are written. + + @Return The number of blocks actually allocated. + + @Cautions Interrupts are disabled for all of the allocation loop. + Although this loop is very short for each block (several machine + instructions), you should not allocate a very large number + of blocks via this routine. +*//***************************************************************************/ +uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[]); + +/**************************************************************************//** + @Function MEM_Put + + @Description Put a block of memory back to a segment. + + @Param[in] h_Mem - Handle to memory segment. + @Param[in] p_Block - The block to return. + + @Return Pointer to new memory block on success,0 otherwise. +*//***************************************************************************/ +t_Error MEM_Put(t_Handle h_Mem, void *p_Block); + +/**************************************************************************//** + @Function MEM_ComputePartitionSize + + @Description calculate a tight upper boundary of the size of a partition with + given attributes. + + The returned value is suitable if one wants to use MEM_InitByAddress(). + + @Param[in] num - The number of blocks in the segment. + @Param[in] dataSize - Size of block to get. + @Param[in] prefixSize - The prefix size + @Param postfixSize - The postfix size + @Param[in] alignment - The requested alignment value (in bytes) + + @Return The memory block size a segment with the given attributes needs. +*//***************************************************************************/ +uint32_t MEM_ComputePartitionSize(uint32_t num, + uint16_t dataSize, + uint16_t prefixSize, + uint16_t postfixSize, + uint16_t alignment); + +#ifdef DEBUG_MEM_LEAKS +#if !(defined(__MWERKS__) && (__dest_os == __ppc_eabi)) +#error "Memory-Leaks-Debug option is supported only for freescale CodeWarrior" +#endif /* !(defined(__MWERKS__) && ... */ + +/**************************************************************************//** + @Function MEM_CheckLeaks + + @Description Report MEM object leaks. + + This routine is automatically called by the MEM_Free() routine, + but it can also be invoked while the MEM object is alive. + + @Param[in] h_Mem - Handle to memory segment. + + @Return None. +*//***************************************************************************/ +void MEM_CheckLeaks(t_Handle h_Mem); + +#else /* not DEBUG_MEM_LEAKS */ +#define MEM_CheckLeaks(h_Mem) +#endif /* not DEBUG_MEM_LEAKS */ + +/**************************************************************************//** + @Description Get base of MEM +*//***************************************************************************/ +#define MEM_GetBase(h_Mem) ((t_MemorySegment *)(h_Mem))->p_Bases[0] + +/**************************************************************************//** + @Description Get size of MEM block +*//***************************************************************************/ +#define MEM_GetSize(h_Mem) ((t_MemorySegment *)(h_Mem))->dataSize + +/**************************************************************************//** + @Description Get prefix size of MEM block +*//***************************************************************************/ +#define MEM_GetPrefixSize(h_Mem) ((t_MemorySegment *)(h_Mem))->prefixSize + +/**************************************************************************//** + @Description Get postfix size of MEM block +*//***************************************************************************/ +#define MEM_GetPostfixSize(h_Mem) ((t_MemorySegment *)(h_Mem))->postfixSize + +/**************************************************************************//** + @Description Get alignment of MEM block (in bytes) +*//***************************************************************************/ +#define MEM_GetAlignment(h_Mem) ((t_MemorySegment *)(h_Mem))->alignment + +/**************************************************************************//** + @Description Get the number of blocks in the segment +*//***************************************************************************/ +#define MEM_GetNumOfBlocks(h_Mem) ((t_MemorySegment *)(h_Mem))->num + +/** @} */ /* end of MEM group */ +/** @} */ /* end of etc_id group */ + + +#endif /* __MEM_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/etc/mm_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/etc/mm_ext.h @@ -0,0 +1,300 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /**************************************************************************//** + + @File mm_ext.h + + @Description Memory Manager Application Programming Interface +*//***************************************************************************/ +#ifndef __MM_EXT +#define __MM_EXT + +#include "std_ext.h" + +#define MM_MAX_ALIGNMENT 20 /* Alignments from 2 to 128 are available + where maximum alignment defined as + MM_MAX_ALIGNMENT power of 2 */ + +#define MM_MAX_NAME_LEN 32 + +/**************************************************************************//** + @Group etc_id Utility Library Application Programming Interface + + @Description External routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group mm_grp Flexible Memory Manager + + @Description Flexible Memory Manager module functions,definitions and enums. + (All of the following functions,definitions and enums can be found in mm_ext.h) + + @{ +*//***************************************************************************/ + + +/**************************************************************************//** + @Function MM_Init + + @Description Initializes a new MM object. + + It initializes a new memory block consisting of base address + and size of the available memory by calling to MemBlock_Init + routine. It is also initializes a new free block for each + by calling FreeBlock_Init routine, which is pointed to + the almost all memory started from the required alignment + from the base address and to the end of the memory. + The handle to the new MM object is returned via "MM" + argument (passed by reference). + + @Param[in] h_MM - Handle to the MM object. + @Param[in] base - Base address of the MM. + @Param[in] size - Size of the MM. + + @Return E_OK is returned on success. E_NOMEMORY is returned if the new MM object or a new free block can not be initialized. +*//***************************************************************************/ +t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size); + +/**************************************************************************//** + @Function MM_Get + + @Description Allocates a block of memory according to the given size and the alignment. + + The Alignment argument tells from which + free list allocate a block of memory. 2^alignment indicates + the alignment that the base address of the allocated block + should have. So, the only values 1, 2, 4, 8, 16, 32 and 64 + are available for the alignment argument. + The routine passes through the specific free list of free + blocks and seeks for a first block that have anough memory + that is required (best fit). + After the block is found and data is allocated, it calls + the internal MM_CutFree routine to update all free lists + do not include a just allocated block. Of course, each + free list contains a free blocks with the same alignment. + It is also creates a busy block that holds + information about an allocated block. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] size - Size of the MM. + @Param[in] alignment - Index as a power of two defines a required + alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64 + @Param[in] name - The name that specifies an allocated block. + + @Return base address of an allocated block ILLEGAL_BASE if can't allocate a block +*//***************************************************************************/ +uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char *name); + +/**************************************************************************//** + @Function MM_GetBase + + @Description Gets the base address of the required MM objects. + + @Param[in] h_MM - Handle to the MM object. + + @Return base address of the block. +*//***************************************************************************/ +uint64_t MM_GetBase(t_Handle h_MM); + +/**************************************************************************//** + @Function MM_GetForce + + @Description Force memory allocation. + + It means to allocate a block of memory of the given + size from the given base address. + The routine checks if the required block can be allocated + (that is it is free) and then, calls the internal MM_CutFree + routine to update all free lists do not include that block. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] base - Base address of the MM. + @Param[in] size - Size of the MM. + @Param[in] name - Name that specifies an allocated block. + + @Return base address of an allocated block, ILLEGAL_BASE if can't allocate a block. +*//***************************************************************************/ +uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char *name); + +/**************************************************************************//** + @Function MM_GetForceMin + + @Description Allocates a block of memory according to the given size, the alignment and minimum base address. + + The Alignment argument tells from which + free list allocate a block of memory. 2^alignment indicates + the alignment that the base address of the allocated block + should have. So, the only values 1, 2, 4, 8, 16, 32 and 64 + are available for the alignment argument. + The minimum baser address forces the location of the block + to be from a given address onward. + The routine passes through the specific free list of free + blocks and seeks for the first base address equal or smaller + than the required minimum address and end address larger than + than the required base + its size - i.e. that may contain + the required block. + After the block is found and data is allocated, it calls + the internal MM_CutFree routine to update all free lists + do not include a just allocated block. Of course, each + free list contains a free blocks with the same alignment. + It is also creates a busy block that holds + information about an allocated block. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] size - Size of the MM. + @Param[in] alignment - Index as a power of two defines a required + alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64 + @Param[in] min - The minimum base address of the block. + @Param[in] name - Name that specifies an allocated block. + + @Return base address of an allocated block,ILLEGAL_BASE if can't allocate a block. +*//***************************************************************************/ +uint64_t MM_GetForceMin(t_Handle h_MM, + uint64_t size, + uint64_t alignment, + uint64_t min, + char *name); + +/**************************************************************************//** + @Function MM_Put + + @Description Puts a block of memory of the given base address back to the memory. + + It checks if there is a busy block with the + given base address. If not, it returns 0, that + means can't free a block. Otherwise, it gets parameters of + the busy block and after it updates lists of free blocks, + removes that busy block from the list by calling to MM_CutBusy + routine. + After that it calls to MM_AddFree routine to add a new free + block to the free lists. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] base - Base address of the MM. + + @Return The size of bytes released, 0 if failed. +*//***************************************************************************/ +uint64_t MM_Put(t_Handle h_MM, uint64_t base); + +/**************************************************************************//** + @Function MM_PutForce + + @Description Releases a block of memory of the required size from the required base address. + + First, it calls to MM_CutBusy routine + to cut a free block from the busy list. And then, calls to + MM_AddFree routine to add the free block to the free lists. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] base - Base address of of a block to free. + @Param[in] size - Size of a block to free. + + @Return The number of bytes released, 0 on failure. +*//***************************************************************************/ +uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size); + +/**************************************************************************//** + @Function MM_Add + + @Description Adds a new memory block for memory allocation. + + When a new memory block is initialized and added to the + memory list, it calls to MM_AddFree routine to add the + new free block to the free lists. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] base - Base address of the memory block. + @Param[in] size - Size of the memory block. + + @Return E_OK on success, otherwise returns an error code. +*//***************************************************************************/ +t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size); + +/**************************************************************************//** + @Function MM_Dump + + @Description Prints results of free and busy lists into the file. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] buff - A pointer to a buffer +*//***************************************************************************/ +void MM_Dump(t_Handle h_MM, void *buff); + +/**************************************************************************//** + @Function MM_Free + + @Description Releases memory allocated for MM object. + + @Param[in] h_MM - Handle of the MM object. +*//***************************************************************************/ +void MM_Free(t_Handle h_MM); + +/**************************************************************************//** + @Function MM_GetMemBlock + + @Description Returns base address of the memory block specified by the index. + + If index is 0, returns base address + of the first memory block, 1 - returns base address + of the second memory block, etc. + Note, those memory blocks are allocated by the + application before MM_Init or MM_Add and have to + be released by the application before or after invoking + the MM_Free routine. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] index - Index of the memory block. + + @Return valid base address or ILLEGAL_BASE if no memory block specified by the index. +*//***************************************************************************/ +uint64_t MM_GetMemBlock(t_Handle h_MM, int index); + +/**************************************************************************//** + @Function MM_InRange + + @Description Checks if a specific address is in the memory range of the passed MM object. + + @Param[in] h_MM - Handle to the MM object. + @Param[in] addr - The address to be checked. + + @Return TRUE if the address is in the address range of the block, FALSE otherwise. +*//***************************************************************************/ +bool MM_InRange(t_Handle h_MM, uint64_t addr); + + +/** @} */ /* end of mm_grp group */ +/** @} */ /* end of etc_id group */ + +#endif /* __MM_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/etc/memcpy_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/etc/memcpy_ext.h @@ -0,0 +1,173 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + + @File memcpy_ext.h + + @Description Efficient functions for copying and setting blocks of memory. +*//***************************************************************************/ + +#ifndef __MEMCPY_EXT_H +#define __MEMCPY_EXT_H + +#include "std_ext.h" + + +/**************************************************************************//** + @Group etc_id Utility Library Application Programming Interface + + @Description External routines. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group mem_cpy Memory Copy + + @Description Memory Copy module functions,definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function MemCpy32 + + @Description Copies one memory buffer into another one in 4-byte chunks! + Which should be more efficient than byte by byte. + + For large buffers (over 60 bytes) this function is about 4 times + more efficient than the trivial memory copy. For short buffers + it is reduced to the trivial copy and may be a bit worse. + + @Param[in] pDst - The address of the destination buffer. + @Param[in] pSrc - The address of the source buffer. + @Param[in] size - The number of bytes that will be copied from pSrc to pDst. + + @Return pDst (the address of the destination buffer). + + @Cautions There is no parameter or boundary checking! It is up to the user + to supply non-null parameters as source & destination and size + that actually fits into the destination buffer. +*//***************************************************************************/ +void * MemCpy32(void* pDst,void* pSrc, uint32_t size); +void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size); +void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size); +void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size); + +/**************************************************************************//** + @Function MemCpy64 + + @Description Copies one memory buffer into another one in 8-byte chunks! + Which should be more efficient than byte by byte. + + For large buffers (over 60 bytes) this function is about 8 times + more efficient than the trivial memory copy. For short buffers + it is reduced to the trivial copy and may be a bit worse. + + Some testing suggests that MemCpy32() preforms better than + MemCpy64() over small buffers. On average they break even at + 100 byte buffers. For buffers larger than that MemCpy64 is + superior. + + @Param[in] pDst - The address of the destination buffer. + @Param[in] pSrc - The address of the source buffer. + @Param[in] size - The number of bytes that will be copied from pSrc to pDst. + + @Return pDst (the address of the destination buffer). + + @Cautions There is no parameter or boundary checking! It is up to the user + to supply non null parameters as source & destination and size + that actually fits into their buffer. + + Do not use under Linux. +*//***************************************************************************/ +void * MemCpy64(void* pDst,void* pSrc, uint32_t size); + +/**************************************************************************//** + @Function MemSet32 + + @Description Sets all bytes of a memory buffer to a specific value, in + 4-byte chunks. + + @Param[in] pDst - The address of the destination buffer. + @Param[in] val - Value to set destination bytes to. + @Param[in] size - The number of bytes that will be set to val. + + @Return pDst (the address of the destination buffer). + + @Cautions There is no parameter or boundary checking! It is up to the user + to supply non null parameter as destination and size + that actually fits into the destination buffer. +*//***************************************************************************/ +void * MemSet32(void* pDst, uint8_t val, uint32_t size); +void * IOMemSet32(void* pDst, uint8_t val, uint32_t size); + +/**************************************************************************//** + @Function MemSet64 + + @Description Sets all bytes of a memory buffer to a specific value, in + 8-byte chunks. + + @Param[in] pDst - The address of the destination buffer. + @Param[in] val - Value to set destination bytes to. + @Param[in] size - The number of bytes that will be set to val. + + @Return pDst (the address of the destination buffer). + + @Cautions There is no parameter or boundary checking! It is up to the user + to supply non null parameter as destination and size + that actually fits into the destination buffer. +*//***************************************************************************/ +void * MemSet64(void* pDst, uint8_t val, uint32_t size); + +/**************************************************************************//** + @Function MemDisp + + @Description Displays a block of memory in chunks of 32 bits. + + @Param[in] addr - The address of the memory to display. + @Param[in] size - The number of bytes that will be displayed. + + @Return None. + + @Cautions There is no parameter or boundary checking! It is up to the user + to supply non null parameter as destination and size + that actually fits into the destination buffer. +*//***************************************************************************/ +void MemDisp(uint8_t *addr, int size); + +/** @} */ /* end of mem_cpy group */ +/** @} */ /* end of etc_id group */ + + +#endif /* __MEMCPY_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/integrations/P3040_P4080_P5020/part_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/integrations/P3040_P4080_P5020/part_ext.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + + @File part_ext.h + + @Description Definitions for the part (integration) module. +*//***************************************************************************/ + +#ifndef __PART_EXT_H +#define __PART_EXT_H + +#include "std_ext.h" +#include "part_integration_ext.h" + + +#if !(defined(MPC8306) || \ + defined(MPC8309) || \ + defined(MPC834x) || \ + defined(MPC836x) || \ + defined(MPC832x) || \ + defined(MPC837x) || \ + defined(MPC8568) || \ + defined(MPC8569) || \ + defined(P1020) || \ + defined(P1021) || \ + defined(P1022) || \ + defined(P1023) || \ + defined(P2020) || \ + defined(P2040) || \ + defined(P3041) || \ + defined(P4080) || \ + defined(SC4080) || \ + defined(P5020) || \ + defined(MSC814x)) +#error "unable to proceed without chip-definition" +#endif /* !(defined(MPC834x) || ... */ + + +/**************************************************************************//* + @Description Part data structure - must be contained in any integration + data structure. +*//***************************************************************************/ +typedef struct t_Part +{ + uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId); + /**< Returns the address of the module's memory map base. */ + e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress); + /**< Returns the module's ID according to its memory map base. */ +} t_Part; + + +#endif /* __PART_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/integrations/P3040_P4080_P5020/part_integration_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/integrations/P3040_P4080_P5020/part_integration_ext.h @@ -0,0 +1,331 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + + @File part_integration_ext.h + + @Description P3040/P4080/P5020 external definitions and structures. +*//***************************************************************************/ +#ifndef __PART_INTEGRATION_EXT_H +#define __PART_INTEGRATION_EXT_H + +#include "std_ext.h" +#include "dpaa_integration_ext.h" + + +/**************************************************************************//** + @Group P3040/P4080/P5020_chip_id P5020 Application Programming Interface + + @Description P3040/P4080/P5020 Chip functions,definitions and enums. + + @{ +*//***************************************************************************/ + +#define CORE_E500MC + +#define INTG_MAX_NUM_OF_CORES 1 + + +/**************************************************************************//** + @Description Module types. +*//***************************************************************************/ +typedef enum e_ModuleId +{ + e_MODULE_ID_DUART_1 = 0, + e_MODULE_ID_DUART_2, + e_MODULE_ID_DUART_3, + e_MODULE_ID_DUART_4, + e_MODULE_ID_LAW, + e_MODULE_ID_LBC, + e_MODULE_ID_PAMU, + e_MODULE_ID_QM, /**< Queue manager module */ + e_MODULE_ID_BM, /**< Buffer manager module */ + e_MODULE_ID_QM_CE_PORTAL_0, + e_MODULE_ID_QM_CI_PORTAL_0, + e_MODULE_ID_QM_CE_PORTAL_1, + e_MODULE_ID_QM_CI_PORTAL_1, + e_MODULE_ID_QM_CE_PORTAL_2, + e_MODULE_ID_QM_CI_PORTAL_2, + e_MODULE_ID_QM_CE_PORTAL_3, + e_MODULE_ID_QM_CI_PORTAL_3, + e_MODULE_ID_QM_CE_PORTAL_4, + e_MODULE_ID_QM_CI_PORTAL_4, + e_MODULE_ID_QM_CE_PORTAL_5, + e_MODULE_ID_QM_CI_PORTAL_5, + e_MODULE_ID_QM_CE_PORTAL_6, + e_MODULE_ID_QM_CI_PORTAL_6, + e_MODULE_ID_QM_CE_PORTAL_7, + e_MODULE_ID_QM_CI_PORTAL_7, + e_MODULE_ID_QM_CE_PORTAL_8, + e_MODULE_ID_QM_CI_PORTAL_8, + e_MODULE_ID_QM_CE_PORTAL_9, + e_MODULE_ID_QM_CI_PORTAL_9, + e_MODULE_ID_BM_CE_PORTAL_0, + e_MODULE_ID_BM_CI_PORTAL_0, + e_MODULE_ID_BM_CE_PORTAL_1, + e_MODULE_ID_BM_CI_PORTAL_1, + e_MODULE_ID_BM_CE_PORTAL_2, + e_MODULE_ID_BM_CI_PORTAL_2, + e_MODULE_ID_BM_CE_PORTAL_3, + e_MODULE_ID_BM_CI_PORTAL_3, + e_MODULE_ID_BM_CE_PORTAL_4, + e_MODULE_ID_BM_CI_PORTAL_4, + e_MODULE_ID_BM_CE_PORTAL_5, + e_MODULE_ID_BM_CI_PORTAL_5, + e_MODULE_ID_BM_CE_PORTAL_6, + e_MODULE_ID_BM_CI_PORTAL_6, + e_MODULE_ID_BM_CE_PORTAL_7, + e_MODULE_ID_BM_CI_PORTAL_7, + e_MODULE_ID_BM_CE_PORTAL_8, + e_MODULE_ID_BM_CI_PORTAL_8, + e_MODULE_ID_BM_CE_PORTAL_9, + e_MODULE_ID_BM_CI_PORTAL_9, + e_MODULE_ID_FM1, /**< Frame manager #1 module */ + e_MODULE_ID_FM1_RTC, /**< FM Real-Time-Clock */ + e_MODULE_ID_FM1_MURAM, /**< FM Multi-User-RAM */ + e_MODULE_ID_FM1_BMI, /**< FM BMI block */ + e_MODULE_ID_FM1_QMI, /**< FM QMI block */ + e_MODULE_ID_FM1_PRS, /**< FM parser block */ + e_MODULE_ID_FM1_PORT_HO0, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM1_PORT_HO1, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM1_PORT_HO2, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM1_PORT_HO3, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM1_PORT_HO4, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM1_PORT_HO5, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM1_PORT_HO6, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM1_PORT_1GRx0, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GRx1, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GRx2, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GRx3, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GRx4, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_10GRx0, /**< FM Rx 10G MAC port block */ + e_MODULE_ID_FM1_PORT_1GTx0, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GTx1, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GTx2, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GTx3, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_1GTx4, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM1_PORT_10GTx0, /**< FM Tx 10G MAC port block */ + e_MODULE_ID_FM1_PLCR, /**< FM Policer */ + e_MODULE_ID_FM1_KG, /**< FM Keygen */ + e_MODULE_ID_FM1_DMA, /**< FM DMA */ + e_MODULE_ID_FM1_FPM, /**< FM FPM */ + e_MODULE_ID_FM1_IRAM, /**< FM Instruction-RAM */ + e_MODULE_ID_FM1_1GMDIO0, /**< FM 1G MDIO MAC 0*/ + e_MODULE_ID_FM1_1GMDIO1, /**< FM 1G MDIO MAC 1*/ + e_MODULE_ID_FM1_1GMDIO2, /**< FM 1G MDIO MAC 2*/ + e_MODULE_ID_FM1_1GMDIO3, /**< FM 1G MDIO MAC 3*/ + e_MODULE_ID_FM1_10GMDIO, /**< FM 10G MDIO */ + e_MODULE_ID_FM1_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ + e_MODULE_ID_FM1_1GMAC0, /**< FM 1G MAC #0 */ + e_MODULE_ID_FM1_1GMAC1, /**< FM 1G MAC #1 */ + e_MODULE_ID_FM1_1GMAC2, /**< FM 1G MAC #2 */ + e_MODULE_ID_FM1_1GMAC3, /**< FM 1G MAC #3 */ + e_MODULE_ID_FM1_10GMAC0, /**< FM 10G MAC #0 */ + + e_MODULE_ID_FM2, /**< Frame manager #2 module */ + e_MODULE_ID_FM2_RTC, /**< FM Real-Time-Clock */ + e_MODULE_ID_FM2_MURAM, /**< FM Multi-User-RAM */ + e_MODULE_ID_FM2_BMI, /**< FM BMI block */ + e_MODULE_ID_FM2_QMI, /**< FM QMI block */ + e_MODULE_ID_FM2_PRS, /**< FM parser block */ + e_MODULE_ID_FM2_PORT_HO0, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM2_PORT_HO1, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM2_PORT_HO2, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM2_PORT_HO3, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM2_PORT_HO4, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM2_PORT_HO5, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM2_PORT_HO6, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM2_PORT_1GRx0, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_1GRx1, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_1GRx2, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_1GRx3, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_10GRx0, /**< FM Rx 10G MAC port block */ + e_MODULE_ID_FM2_PORT_1GTx0, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_1GTx1, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_1GTx2, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_1GTx3, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM2_PORT_10GTx0, /**< FM Tx 10G MAC port block */ + e_MODULE_ID_FM2_PLCR, /**< FM Policer */ + e_MODULE_ID_FM2_KG, /**< FM Keygen */ + e_MODULE_ID_FM2_DMA, /**< FM DMA */ + e_MODULE_ID_FM2_FPM, /**< FM FPM */ + e_MODULE_ID_FM2_IRAM, /**< FM Instruction-RAM */ + e_MODULE_ID_FM2_1GMDIO0, /**< FM 1G MDIO MAC 0*/ + e_MODULE_ID_FM2_1GMDIO1, /**< FM 1G MDIO MAC 1*/ + e_MODULE_ID_FM2_1GMDIO2, /**< FM 1G MDIO MAC 2*/ + e_MODULE_ID_FM2_1GMDIO3, /**< FM 1G MDIO MAC 3*/ + e_MODULE_ID_FM2_10GMDIO, /**< FM 10G MDIO */ + e_MODULE_ID_FM2_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ + e_MODULE_ID_FM2_1GMAC0, /**< FM 1G MAC #0 */ + e_MODULE_ID_FM2_1GMAC1, /**< FM 1G MAC #1 */ + e_MODULE_ID_FM2_1GMAC2, /**< FM 1G MAC #2 */ + e_MODULE_ID_FM2_1GMAC3, /**< FM 1G MAC #3 */ + e_MODULE_ID_FM2_10GMAC0, /**< FM 10G MAC #0 */ + + e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */ + e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */ + e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */ + e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */ + e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */ + e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */ + e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */ + e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */ + e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */ + e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */ + e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */ + e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */ + + e_MODULE_ID_MPIC, /**< MPIC */ + e_MODULE_ID_GPIO, /**< GPIO */ + e_MODULE_ID_SERDES, /**< SERDES */ + e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */ + e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */ + + e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */ + e_MODULE_ID_SRIO_MU, /**< RapidIO messaging unit module */ + + e_MODULE_ID_DUMMY_LAST +} e_ModuleId; + +#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST + + +/***************************************************************************** + INTEGRATION-SPECIFIC MODULE CODES +******************************************************************************/ +#define MODULE_UNKNOWN 0x00000000 +#define MODULE_MEM 0x00010000 +#define MODULE_MM 0x00020000 +#define MODULE_CORE 0x00030000 +#define MODULE_CHIP 0x00040000 +#define MODULE_PLTFRM 0x00050000 +#define MODULE_PM 0x00060000 +#define MODULE_MMU 0x00070000 +#define MODULE_PIC 0x00080000 +#define MODULE_CPC 0x00090000 +#define MODULE_DUART 0x000a0000 +#define MODULE_SERDES 0x000b0000 +#define MODULE_PIO 0x000c0000 +#define MODULE_QM 0x000d0000 +#define MODULE_BM 0x000e0000 +#define MODULE_SEC 0x000f0000 +#define MODULE_LAW 0x00100000 +#define MODULE_LBC 0x00110000 +#define MODULE_PAMU 0x00120000 +#define MODULE_FM 0x00130000 +#define MODULE_FM_MURAM 0x00140000 +#define MODULE_FM_PCD 0x00150000 +#define MODULE_FM_RTC 0x00160000 +#define MODULE_FM_MAC 0x00170000 +#define MODULE_FM_PORT 0x00180000 +#define MODULE_DPA 0x00190000 +#define MODULE_SRIO 0x00200000 +#define MODULE_DMA 0x00100000 + +/***************************************************************************** + PAMU INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define PAMU_NUM_OF_PARTITIONS 5 + +#define PAMU_PICS_AVICS_ERRATA_PAMU3 + +/***************************************************************************** + LAW INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define LAW_NUM_OF_WINDOWS 32 +#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4KB */ +#define LAW_MAX_WINDOW_SIZE 0x0000002000000000LL /**< 64GB */ + + +/***************************************************************************** + LBC INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +/**************************************************************************//** + @Group lbc_exception_grp LBC Exception Unit + + @Description LBC Exception unit API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Anchor lbc_exbm + + @Collection LBC Errors Bit Mask + + These errors are reported through the exceptions callback.. + The values can be or'ed in any combination in the errors mask + parameter of the errors report structure. + + These errors can also be passed as a bit-mask to + LBC_EnableErrorChecking() or LBC_DisableErrorChecking(), + for enabling or disabling error checking. + @{ +*//***************************************************************************/ +#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */ +#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */ +#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */ +#define LBC_ERR_ATOMIC_WRITE 0x00800000 /**< Atomic write error */ +#define LBC_ERR_ATOMIC_READ 0x00400000 /**< Atomic read error */ +#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */ + +#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \ + LBC_ERR_WRITE_PROTECT | LBC_ERR_ATOMIC_WRITE | \ + LBC_ERR_ATOMIC_READ | LBC_ERR_CHIP_SELECT) + /**< All possible errors */ +/* @} */ +/** @} */ /* end of lbc_exception_grp group */ + +#define LBC_INCORRECT_ERROR_REPORT_ERRATA + +#define LBC_NUM_OF_BANKS 8 +#define LBC_MAX_CS_SIZE 0x0000000100000000LL +#define LBC_ATOMIC_OPERATION_SUPPORT +#define LBC_PARITY_SUPPORT +#define LBC_ADDRESS_HOLD_TIME_CTRL +#define LBC_HIGH_CLK_DIVIDERS +#define LBC_FCM_AVAILABLE + +/***************************************************************************** + GPIO INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define GPIO_NUM_OF_PORTS 1 /**< Number of ports in GPIO module; + Each port contains up to 32 i/O pins. */ + +#define GPIO_VALID_PIN_MASKS \ + { /* Port A */ 0xFFFFFFFF } + +#define GPIO_VALID_INTR_MASKS \ + { /* Port A */ 0xFFFFFFFF } + +#endif /* __PART_INTEGRATION_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h @@ -0,0 +1,452 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + + @File dpaa_integration_ext.h + + @Description P4080 FM external definitions and structures. +*//***************************************************************************/ +#ifndef __DPAA_INTEGRATION_EXT_H +#define __DPAA_INTEGRATION_EXT_H + +#include "std_ext.h" + + +typedef enum { + e_DPAA_SWPORTAL0 = 0, + e_DPAA_SWPORTAL1, + e_DPAA_SWPORTAL2, + e_DPAA_SWPORTAL3, + e_DPAA_SWPORTAL4, + e_DPAA_SWPORTAL5, + e_DPAA_SWPORTAL6, + e_DPAA_SWPORTAL7, + e_DPAA_SWPORTAL8, + e_DPAA_SWPORTAL9, + e_DPAA_SWPORTAL_DUMMY_LAST +} e_DpaaSwPortal; + +typedef enum { + e_DPAA_DCPORTAL0 = 0, + e_DPAA_DCPORTAL1, + e_DPAA_DCPORTAL2, + e_DPAA_DCPORTAL3, + e_DPAA_DCPORTAL4, + e_DPAA_DCPORTAL_DUMMY_LAST +} e_DpaaDcPortal; + +#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST +#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST + +/***************************************************************************** + QMan INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define QMAN_PM_DCP_COUNTERS_ERRATA_QMAN1 +#define QMAN_FQD_AVOID_BLK_ERRATA_QMAN2 +#define QMAN_DBG_TRC_EV_ERRATA_QMAN3 +#define QMAN_WQ_CS_CFG_ERRATA_QMAN4 +#define QMAN_SFDR_LEAK_ERRATA_QMAN5 +#define QMAN_FQ_TD_THRESH_ERRATA_QMAN6 +#define QMAN_FQ_INIT_ON_PARKED_ERRATA_QMAN7 +#define QMAN_NESN_ORR_ERRATA_QMAN8 +#define QMAN_ERN_REJ_CODE6_ERRATA_QMAN9 +#define QMAN_ERN_MOULTI_CORE_ERRATA_QMAN10 +#define QMAN_PERFMON_FOR_DCP_FQD_ERRATA_QMAN11 + +#define QM_MAX_NUM_OF_POOL_CHANNELS 15 +#define QM_MAX_NUM_OF_WQ 8 +#define QM_MAX_NUM_OF_SWP_AS 4 +#define QM_MAX_NUM_OF_CGS 256 +#define QM_MAX_NUM_OF_FQIDS (16*MEGABYTE) + +/**************************************************************************//** + @Description Work Queue Channel assignments in QMan. +*//***************************************************************************/ +typedef enum +{ + e_QM_FQ_CHANNEL_SWPORTAL0 = 0, /**< Dedicated channels serviced by software portals 0 to 9 */ + e_QM_FQ_CHANNEL_SWPORTAL1, + e_QM_FQ_CHANNEL_SWPORTAL2, + e_QM_FQ_CHANNEL_SWPORTAL3, + e_QM_FQ_CHANNEL_SWPORTAL4, + e_QM_FQ_CHANNEL_SWPORTAL5, + e_QM_FQ_CHANNEL_SWPORTAL6, + e_QM_FQ_CHANNEL_SWPORTAL7, + e_QM_FQ_CHANNEL_SWPORTAL8, + e_QM_FQ_CHANNEL_SWPORTAL9, + + e_QM_FQ_CHANNEL_POOL1 = 0x21, /**< Pool channels that can be serviced by any of the software portals */ + e_QM_FQ_CHANNEL_POOL2, + e_QM_FQ_CHANNEL_POOL3, + e_QM_FQ_CHANNEL_POOL4, + e_QM_FQ_CHANNEL_POOL5, + e_QM_FQ_CHANNEL_POOL6, + e_QM_FQ_CHANNEL_POOL7, + e_QM_FQ_CHANNEL_POOL8, + e_QM_FQ_CHANNEL_POOL9, + e_QM_FQ_CHANNEL_POOL10, + e_QM_FQ_CHANNEL_POOL11, + e_QM_FQ_CHANNEL_POOL12, + e_QM_FQ_CHANNEL_POOL13, + e_QM_FQ_CHANNEL_POOL14, + e_QM_FQ_CHANNEL_POOL15, + + e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40, /**< Dedicated channels serviced by Direct Connect Portal 0: + connected to FMan 0; assigned in incrementing order to + each sub-portal (SP) in the portal */ + e_QM_FQ_CHANNEL_FMAN0_SP1, + e_QM_FQ_CHANNEL_FMAN0_SP2, + e_QM_FQ_CHANNEL_FMAN0_SP3, + e_QM_FQ_CHANNEL_FMAN0_SP4, + e_QM_FQ_CHANNEL_FMAN0_SP5, + e_QM_FQ_CHANNEL_FMAN0_SP6, + e_QM_FQ_CHANNEL_FMAN0_SP7, + e_QM_FQ_CHANNEL_FMAN0_SP8, + e_QM_FQ_CHANNEL_FMAN0_SP9, + e_QM_FQ_CHANNEL_FMAN0_SP10, + e_QM_FQ_CHANNEL_FMAN0_SP11, + + e_QM_FQ_CHANNEL_FMAN1_SP0 = 0x60, + e_QM_FQ_CHANNEL_FMAN1_SP1, + e_QM_FQ_CHANNEL_FMAN1_SP2, + e_QM_FQ_CHANNEL_FMAN1_SP3, + e_QM_FQ_CHANNEL_FMAN1_SP4, + e_QM_FQ_CHANNEL_FMAN1_SP5, + e_QM_FQ_CHANNEL_FMAN1_SP6, + e_QM_FQ_CHANNEL_FMAN1_SP7, + e_QM_FQ_CHANNEL_FMAN1_SP8, + e_QM_FQ_CHANNEL_FMAN1_SP9, + e_QM_FQ_CHANNEL_FMAN1_SP10, + e_QM_FQ_CHANNEL_FMAN1_SP11, + + e_QM_FQ_CHANNEL_CAAM = 0x80, /**< Dedicated channel serviced by Direct Connect Portal 2: + connected to SEC 4.x */ + + e_QM_FQ_CHANNEL_PME = 0xA0, /**< Dedicated channel serviced by Direct Connect Portal 3: + connected to PME */ +} e_QmFQChannel; + +/* p4080-rev1 unique features */ +#define QM_CGS_NO_FRAME_MODE + +/***************************************************************************** + BMan INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define BM_MAX_NUM_OF_POOLS 64 + +/***************************************************************************** + SEC INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +/* SEC erratas */ +#ifdef UNDER_CONSTRUCTION_IPSEC +#define SEC_IPV6_UDP_CHECKSUM_UPDATE +#define SEC_UDP_LENGTH_UPDATE +#endif /* UNDER_CONSTRUCTION_IPSEC */ + +/***************************************************************************** + FM INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define INTG_MAX_NUM_OF_FM 2 + +/* Ports defines */ +#define FM_MAX_NUM_OF_1G_RX_PORTS 5 +#define FM_MAX_NUM_OF_10G_RX_PORTS 1 +#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS+FM_MAX_NUM_OF_1G_RX_PORTS) +#define FM_MAX_NUM_OF_1G_TX_PORTS 5 +#define FM_MAX_NUM_OF_10G_TX_PORTS 1 +#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS+FM_MAX_NUM_OF_1G_TX_PORTS) +#define FM_MAX_NUM_OF_OH_PORTS 7 +#define FM_MAX_NUM_OF_1G_MACS (FM_MAX_NUM_OF_1G_RX_PORTS) +#define FM_MAX_NUM_OF_10G_MACS (FM_MAX_NUM_OF_10G_RX_PORTS) +#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS+FM_MAX_NUM_OF_10G_MACS) + + +#define FM_PORT_MAX_NUM_OF_EXT_POOLS 8 /**< Number of external BM pools per Rx port */ +#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */ +#define FM_MAX_NUM_OF_SUB_PORTALS 12 +#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0 + +/* RAMs defines */ +#define FM_MURAM_SIZE (160 * KILOBYTE) +#define FM_IRAM_SIZE ( 64 * KILOBYTE) + +/* PCD defines */ +#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */ +#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */ +#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */ + +/* RTC defines */ +#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */ +#define FM_RTC_NUM_OF_PERIODIC_PULSES 2 /**< RTC number of periodic pulses */ +#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */ + +/* QMI defines */ +#define QMI_MAX_NUM_OF_TNUMS 64 +#define MAX_QMI_DEQ_SUBPORTAL 12 +#define QMI_DEF_TNUMS_THRESH 48 + +/* FPM defines */ +#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 + +/* DMA defines */ +#define DMA_THRESH_MAX_COMMQ 31 +#define DMA_THRESH_MAX_BUF 127 + +/* BMI defines */ +#define BMI_MAX_NUM_OF_TASKS 128 +#define BMI_MAX_NUM_OF_DMAS 32 +#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) +#define PORT_MAX_WEIGHT 16 + +#ifdef UNDER_CONSTRUCTION_FRAG_REASSEMBLY +/* Reassembly defines */ +#define FM_MAX_NUM_OF_REASSEMBLY_PORTS 4 +#endif /* UNDER_CONSTRUCTION_FRAG_REASSEMBLY */ + + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ +typedef enum e_FmEventModules{ + e_FM_MOD_PRS, /**< Parser event */ + e_FM_MOD_KG, /**< Keygen event */ + e_FM_MOD_PLCR, /**< Policer event */ + e_FM_MOD_10G_MAC, /**< 10G MAC error event */ + e_FM_MOD_1G_MAC, /**< 1G MAC error event */ + e_FM_MOD_TMR, /**< Timer event */ + e_FM_MOD_1G_MAC_TMR, /**< 1G MAC timer event */ + e_FM_MOD_FMAN_CTRL, /**< FMAN Controller timer event */ + e_FM_MOD_DUMMY_LAST +} e_FmEventModules; + +/**************************************************************************//** + @Description Enum for interrupts types +*//***************************************************************************/ +typedef enum e_FmIntrType { + e_FM_INTR_TYPE_ERR, + e_FM_INTR_TYPE_NORMAL +} e_FmIntrType; + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ +typedef enum e_FmInterModuleEvent { + e_FM_EV_PRS, /**< Parser event */ + e_FM_EV_ERR_PRS, /**< Parser error event */ + e_FM_EV_KG, /**< Keygen event */ + e_FM_EV_ERR_KG, /**< Keygen error event */ + e_FM_EV_PLCR, /**< Policer event */ + e_FM_EV_ERR_PLCR, /**< Policer error event */ + e_FM_EV_ERR_10G_MAC0, /**< 10G MAC 0 error event */ + e_FM_EV_ERR_1G_MAC0, /**< 1G MAC 0 error event */ + e_FM_EV_ERR_1G_MAC1, /**< 1G MAC 1 error event */ + e_FM_EV_ERR_1G_MAC2, /**< 1G MAC 2 error event */ + e_FM_EV_ERR_1G_MAC3, /**< 1G MAC 3 error event */ + e_FM_EV_ERR_1G_MAC4, /**< 1G MAC 4 error event */ + e_FM_EV_TMR, /**< Timer event */ + e_FM_EV_1G_MAC1, /**< 1G MAC 1 event */ + e_FM_EV_1G_MAC2, /**< 1G MAC 2 event */ + e_FM_EV_1G_MAC3, /**< 1G MAC 3 event */ + e_FM_EV_1G_MAC4, /**< 1G MAC 3 event */ + e_FM_EV_1G_MAC0_TMR, /**< 1G MAC 0 Timer event */ + e_FM_EV_1G_MAC1_TMR, /**< 1G MAC 1 Timer event */ + e_FM_EV_1G_MAC2_TMR, /**< 1G MAC 2 Timer event */ + e_FM_EV_1G_MAC3_TMR, /**< 1G MAC 3 Timer event */ + e_FM_EV_1G_MAC4_TMR, /**< 1G MAC 4 Timer event */ + e_FM_EV_FMAN_CTRL_0, /**< Fman controller event 0 */ + e_FM_EV_FMAN_CTRL_1, /**< Fman controller event 1 */ + e_FM_EV_FMAN_CTRL_2, /**< Fman controller event 2 */ + e_FM_EV_FMAN_CTRL_3, /**< Fman controller event 3 */ + e_FM_EV_DUMMY_LAST +} e_FmInterModuleEvent; + +#define GET_FM_MODULE_EVENT(mod, id, intrType, event) \ + switch(mod){ \ + case e_FM_MOD_PRS: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PRS : e_FM_EV_PRS; \ + break; \ + case e_FM_MOD_KG: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_KG : e_FM_EV_DUMMY_LAST; \ + break; \ + case e_FM_MOD_PLCR: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PLCR : e_FM_EV_PLCR; \ + break; \ + case e_FM_MOD_10G_MAC: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_10G_MAC0 : e_FM_EV_DUMMY_LAST;\ + break; \ + case e_FM_MOD_1G_MAC: \ + switch(id){ \ + case(0): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC0 : e_FM_EV_DUMMY_LAST; break; \ + case(1): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC1 : e_FM_EV_DUMMY_LAST; break; \ + case(2): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC2 : e_FM_EV_DUMMY_LAST; break; \ + case(3): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC3 : e_FM_EV_DUMMY_LAST; break; \ + case(4): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC4 : e_FM_EV_DUMMY_LAST; break; \ + } \ + break; \ + case e_FM_MOD_TMR: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_TMR; \ + break; \ + case e_FM_MOD_1G_MAC_TMR: \ + switch(id){ \ + case(0): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_1G_MAC0_TMR; break;\ + case(1): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_1G_MAC1_TMR; break;\ + case(2): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_1G_MAC2_TMR; break;\ + case(3): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_1G_MAC3_TMR; break;\ + case(4): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_1G_MAC4_TMR; break;\ + } \ + break; \ + case e_FM_MOD_FMAN_CTRL: \ + if (intrType == e_FM_INTR_TYPE_ERR) event = e_FM_EV_DUMMY_LAST; \ + else switch(id){ \ + case(0): event = e_FM_EV_FMAN_CTRL_0; break; \ + case(1): event = e_FM_EV_FMAN_CTRL_1; break; \ + case(2): event = e_FM_EV_FMAN_CTRL_2; break; \ + case(3): event = e_FM_EV_FMAN_CTRL_3; break; \ + } \ + break; \ + default: event = e_FM_EV_DUMMY_LAST; \ + break;} + +#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE + +/* p4080-rev1 unique features */ +#define FM_PARTITION_ARRAY +#define FM_PPPOE_NO_MTU_CHECK + +/* p4080 unique features */ +#ifdef UNDER_CONSTRUCTION_IPSEC +#define FM_ETH_TYPE_FIX +#define FM_DISABLE_SEC_ERRORS +#endif /* UNDER_CONSTRUCTION_IPSEC */ +#define FM_QMI_DEQ_OPTIONS_SUPPORT +#define FM_NO_DISPATCH_RAM_ECC +#define FM_FIFO_ALLOCATION_OLD_ALG +#define FM_NO_WATCHDOG +#define FM_NO_TNUM_AGING +#define FM_NO_TGEC_LOOPBACK +#define FM_KG_NO_BYPASS_FQID_GEN +#define FM_KG_NO_BYPASS_PLCR_PROFILE_GEN +#define FM_NO_BACKUP_POOLS +#define FM_NO_OP_OBSERVED_POOLS +#define FM_NO_ADVANCED_RATE_LIMITER +#define FM_NO_OP_OBSERVED_CGS + +/* FM erratas */ +#define FM_SINGLE_MDIO_ERRATA_GEN8 /* implemented in platform */ +#define FM_HALT_SIG_ERRATA_GEN12 + +#define FM_10G_MDIO_HOLD_ERRATA_XAUI3 /* implemented in platform */ +#define FM_10G_PCS_ALIGNMENT_ERRATA_XAUI4 /* implemented in platform */ + +#define FM_IEEE_BAD_TS_ERRATA_IEEE1588_A001 /* No implementation, Out of LLD scope */ + +#define FM_FALSE_RDRP_ERRATA_10GMAC_A001 /* No implementation, Out of LLD scope */ +#define FM_RX_EXTRA_BYTES_ERRATA_10GMAC_A002 /* No implementation, Out of LLD scope */ +#define FM_TX_PAUSE_ON_ENABLE_ERRATA_10GMAC_A003 /* No implementation, Out of LLD scope */ +#define FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +#define FM_TX_SHORT_FRAME_BAD_TS_ERRATA_10GMAC_A006 /* No implementation, Out of LLD scope */ +#define FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 +#define FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 + +#define FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 + +#define FM_NO_RX_PREAM_ERRATA_DTSECx1 +#define FM_RX_PREAM_4_ERRATA_DTSEC_A001 FM_NO_RX_PREAM_ERRATA_DTSECx1 +#define FM_GRS_ERRATA_DTSEC_A002 +#define FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 +#define FM_GTS_ERRATA_DTSEC_A004 +#define FM_PAUSE_BLOCK_ERRATA_DTSEC_A006 /* do nothing */ +#define FM_RESERVED_ACCESS_TO_DISABLED_DEV_ERRATA_DTSEC_A0011 /* do nothing */ +#define FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012 FM_GTS_ERRATA_DTSEC_A004 + +#define FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 +#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2 /* No implementation, Out of LLD scope */ +#define FM_10_100_SGMII_NO_TS_ERRATA_DTSEC3 +#define FM_TX_LOCKUP_ERRATA_DTSEC6 + +#define FM_IM_TX_SYNC_SKIP_TNUM_ERRATA_FMAN_A001 /* Implemented by ucode */ +#define FM_RX_PIPELINE_OF_DATA_CORRUPTION_ERRATA_FMAN_A002 /* No implementation, Out of LLD scope */ +#define FM_HC_DEF_FQID_ONLY_ERRATA_FMAN_A003 /* Implemented by ucode */ + +#define FM_1588_SRC_CLK_ERRATA_FMAN1 +#define FM_NO_RUNNING_SUM_FOR_DBG_N_SWPRS_ERRATA_FMAN2 /* No implementation, Out of LLD scope */ +#define FM_IM_TX_SHARED_TNUM_ERRATA_FMAN4 /* Implemented by ucode */ +#define FM_IM_GS_DEADLOCK_ERRATA_FMAN5 /* Implemented by ucode */ +#define FM_PORT_SYNC_ERRATA_FMAN6 +#define FM_RAM_LIST_ERR_IRQ_ERRATA_FMAN8 +#define FM_BMI_PIPELINE_ERR_IRQ_ERRATA_FMAN9 +#define FM_IM_DEQ_PIPELINE_DEPTH_ERRATA_FMAN10 /* Implemented by ucode */ +#define FM_CC_GEN6_MISSMATCH_ERRATA_FMAN12 /* Implemented by ucode */ +#define FM_CC_CHANGE_SHARED_TNUM_ERRATA_FMAN13 /* Implemented by ucode */ +#define FM_IM_LARGE_MRBLR_ERRATA_FMAN15 /* Implemented by ucode */ +#define FM_RESET_ERRATA_FMAN16 /* No implementation, Out of LLD scope */ +#define FM_IPV4_HDRLEN0_ERRATA_FMAN17 /* No implementation, Out of LLD scope */ +#define FM_INCORRECT_CS_ERRATA_FMAN18 +#define FM_ILLEGAL_FRM_LEN_ERRATA_FMAN20 /* No implementation, Out of LLD scope */ +#define FM_OP_PORT_QMAN_REJECT_ERRATA_FMAN21 + +#define FM_PRS_L4_SHELL_ERRATA_FMANb +#define FM_BMI_TO_RISC_ENQ_ERRATA_FMANc +#define FM_INVALID_SWPRS_DATA_ERRATA_FMANd /* No implementation, Out of LLD scope */ +//#define FM_PRS_L4_NO_CLEAR_ERRATA_FMANe /* No implementation, No patch yet */ +//#define FM_PRS_MPLS_ERROR_ERRATA_FMANf /* No implementation, No patch yet */ +#define FM_PORT_COUNTERS_ERRATA_FMANg +#define FM_BAD_RX_FD_ERRATA_FMANh /* No implementation, Out of LLD scope */ +//#define FM_PRS_MPLS_SSA_ERRATA_FMANj /* No implementation, No patch yet */ +//#define FM_PRS_INITIAL_PLANID_ERRATA_FMANk /* No implementation, No patch yet */ + + +#define FM_OP_PARTITION_ERRATA_FMANx8 +#define FM_PORT_DISABLED_ERRATA_FMANx9 +#define FM_TX_PORT_IM_OR_ERRATA_FMANx11 /* Implemented by ucode */ +#define FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 +#define FM_PORT_OTF_CHANGES_ERRATA_FMANx12 FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 +#define FM_SOFT_RESET_ERRATA_FMANx15 /* No implementation, Out of LLD scope */ + +#define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 + +#define FM_PRS_MEM_ERRATA_FMAN_SW003 +#define FM_LEN_CHECK_ERRATA_FMAN_SW002 +#define FM_10G_REM_N_LCL_FLT_EX_ERRATA_10GMAC001 + +#ifdef UNDER_CONSTRUCTION_IPSEC +#define FM_NO_COPY_CTXA_CTXB_ERRATA_FMAN_SW001 +#endif /* UNDER_CONSTRUCTION_IPSEC */ + + +#endif /* __DPAA_INTEGRATION_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/integrations/P1023/part_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/integrations/P1023/part_ext.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + + @File part_ext.h + + @Description Definitions for the part (integration) module. +*//***************************************************************************/ + +#ifndef __PART_EXT_H +#define __PART_EXT_H + +#include "std_ext.h" +#include "part_integration_ext.h" + + +#if !(defined(MPC8306) || \ + defined(MPC8309) || \ + defined(MPC834x) || \ + defined(MPC836x) || \ + defined(MPC832x) || \ + defined(MPC837x) || \ + defined(MPC8568) || \ + defined(MPC8569) || \ + defined(P1020) || \ + defined(P1021) || \ + defined(P1022) || \ + defined(P1023) || \ + defined(P2020) || \ + defined(P3041) || \ + defined(P4080) || \ + defined(P5020) || \ + defined(MSC814x)) +#error "unable to proceed without chip-definition" +#endif + + +/**************************************************************************//* + @Description Part data structure - must be contained in any integration + data structure. +*//***************************************************************************/ +typedef struct t_Part +{ + uint64_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId); + /**< Returns the address of the module's memory map base. */ + e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uint64_t baseAddress); + /**< Returns the module's ID according to its memory map base. */ +} t_Part; + + +#endif /* __PART_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/integrations/P1023/part_integration_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/integrations/P1023/part_integration_ext.h @@ -0,0 +1,659 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + + @File part_integration_ext.h + + @Description P1023 external definitions and structures. +*//***************************************************************************/ +#ifndef __PART_INTEGRATION_EXT_H +#define __PART_INTEGRATION_EXT_H + +#include "std_ext.h" +#ifndef NCSW_LINUX +#include "ddr_std_ext.h" +#endif +#include "dpaa_integration_ext.h" + + +/**************************************************************************//** + @Group 1023_chip_id P1023 Application Programming Interface + + @Description P1023 Chip functions,definitions and enums. + + @{ +*//***************************************************************************/ + +#define INTG_MAX_NUM_OF_CORES 1 + + +/**************************************************************************//** + @Description Module types. +*//***************************************************************************/ +typedef enum e_ModuleId +{ + e_MODULE_ID_LAW, /**< Local Access module */ + e_MODULE_ID_ECM, /**< e500 Coherency Module */ + e_MODULE_ID_DDR, /**< DDR memory controller */ + e_MODULE_ID_I2C_1, /**< I2C 1 */ + e_MODULE_ID_I2C_2, /**< I2C 1 */ + e_MODULE_ID_DUART_1, /**< DUART module 1 */ + e_MODULE_ID_DUART_2, /**< DUART module 2 */ + e_MODULE_ID_LBC, /**< Local bus memory controller module */ + e_MODULE_ID_PCIE_1, /**< PCI Express 1 controller module */ + e_MODULE_ID_PCIE_ATMU_1, /**< PCI 1 ATMU Window */ + e_MODULE_ID_PCIE_2, /**< PCI Express 2 controller module */ + e_MODULE_ID_PCIE_ATMU_2, /**< PCI 2 ATMU Window */ + e_MODULE_ID_PCIE_3, /**< PCI Express 3 controller module */ + e_MODULE_ID_PCIE_ATMU_3, /**< PCI 3 ATMU Window */ + e_MODULE_ID_MSI, /**< MSI registers */ + e_MODULE_ID_L2_SRAM, /**< L2/SRAM Memory-Mapped controller module */ + e_MODULE_ID_DMA_1, /**< DMA controller 1 */ + e_MODULE_ID_DMA_2, /**< DMA controller 2 */ + e_MODULE_ID_EPIC, /**< Programmable interrupt controller */ + e_MODULE_ID_ESPI, /**< ESPI module */ + e_MODULE_ID_GPIO, /**< General Purpose I/O */ + e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */ + e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */ + e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */ + e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */ + e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */ + e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */ + e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */ + e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */ + e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */ + e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */ + e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */ + e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */ + e_MODULE_ID_USB_DR_1, /**< USB 2.0 module 1 */ + e_MODULE_ID_USB_DR_2, /**< USB 2.0 module 2 */ + e_MODULE_ID_ETSEC_MII_MNG, /**< MII MNG registers */ + e_MODULE_ID_ETSEC_1, /**< ETSEC module 1 */ + e_MODULE_ID_ETSEC_2, /**< ETSEC module 2 */ + e_MODULE_ID_GUTS, /**< Serial DMA */ + e_MODULE_ID_PM, /**< Performance Monitor module */ + e_MODULE_ID_QM, /**< Queue manager module */ + e_MODULE_ID_BM, /**< Buffer manager module */ + e_MODULE_ID_QM_CE_PORTAL, + e_MODULE_ID_QM_CI_PORTAL, + e_MODULE_ID_BM_CE_PORTAL, + e_MODULE_ID_BM_CI_PORTAL, + e_MODULE_ID_FM, /**< Frame manager #1 module */ + e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */ + e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */ + e_MODULE_ID_FM_BMI, /**< FM BMI block */ + e_MODULE_ID_FM_QMI, /**< FM QMI block */ + e_MODULE_ID_FM_PRS, /**< FM parser block */ + e_MODULE_ID_FM_PORT_HO0, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */ + e_MODULE_ID_FM_PORT_1GRx0, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */ + e_MODULE_ID_FM_PORT_1GTx0, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */ + e_MODULE_ID_FM_PLCR, /**< FM Policer */ + e_MODULE_ID_FM_KG, /**< FM Keygen */ + e_MODULE_ID_FM_DMA, /**< FM DMA */ + e_MODULE_ID_FM_FPM, /**< FM FPM */ + e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */ + e_MODULE_ID_FM_1GMDIO0, /**< FM 1G MDIO MAC 0*/ + e_MODULE_ID_FM_1GMDIO1, /**< FM 1G MDIO MAC 1*/ + e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ + e_MODULE_ID_FM_RISC0, /**< FM risc #0 */ + e_MODULE_ID_FM_RISC1, /**< FM risc #1 */ + e_MODULE_ID_FM_1GMAC0, /**< FM 1G MAC #0 */ + e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */ + e_MODULE_ID_FM_MACSEC, /**< FM MACSEC */ + + e_MODULE_ID_DUMMY_LAST +} e_ModuleId; + +#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST + + +#define P1023_OFFSET_LAW 0x00000C08 +#define P1023_OFFSET_ECM 0x00001000 +#define P1023_OFFSET_DDR 0x00002000 +#define P1023_OFFSET_I2C1 0x00003000 +#define P1023_OFFSET_I2C2 0x00003100 +#define P1023_OFFSET_DUART1 0x00004500 +#define P1023_OFFSET_DUART2 0x00004600 +#define P1023_OFFSET_LBC 0x00005000 +#define P1023_OFFSET_ESPI 0x00007000 +#define P1023_OFFSET_PCIE2 0x00009000 +#define P1023_OFFSET_PCIE2_ATMU 0x00009C00 +#define P1023_OFFSET_PCIE1 0x0000A000 +#define P1023_OFFSET_PCIE1_ATMU 0x0000AC00 +#define P1023_OFFSET_PCIE3 0x0000B000 +#define P1023_OFFSET_PCIE3_ATMU 0x0000BC00 +#define P1023_OFFSET_DMA2 0x0000C100 +#define P1023_OFFSET_GPIO 0x0000F000 +#define P1023_OFFSET_L2_SRAM 0x00020000 +#define P1023_OFFSET_DMA1 0x00021100 +#define P1023_OFFSET_USB1 0x00022000 +#define P1023_OFFSET_SEC_GEN 0x00030000 +#define P1023_OFFSET_SEC_JQ0 0x00031000 +#define P1023_OFFSET_SEC_JQ1 0x00032000 +#define P1023_OFFSET_SEC_JQ2 0x00033000 +#define P1023_OFFSET_SEC_JQ3 0x00034000 +#define P1023_OFFSET_SEC_RTIC 0x00036000 +#define P1023_OFFSET_SEC_QI 0x00037000 +#define P1023_OFFSET_SEC_DECO0_CCB0 0x00038000 +#define P1023_OFFSET_SEC_DECO1_CCB1 0x00039000 +#define P1023_OFFSET_SEC_DECO2_CCB2 0x0003a000 +#define P1023_OFFSET_SEC_DECO3_CCB3 0x0003b000 +#define P1023_OFFSET_SEC_DECO4_CCB4 0x0003c000 +#define P1023_OFFSET_PIC 0x00040000 +#define P1023_OFFSET_MSI 0x00041600 +#define P1023_OFFSET_AXI 0x00081000 +#define P1023_OFFSET_QM 0x00088000 +#define P1023_OFFSET_BM 0x0008A000 +#define P1022_OFFSET_PM 0x000E1000 + +#define P1023_OFFSET_GUTIL 0x000E0000 +#define P1023_OFFSET_PM 0x000E1000 +#define P1023_OFFSET_DEBUG 0x000E2000 +#define P1023_OFFSET_SERDES 0x000E3000 +#define P1023_OFFSET_ROM 0x000F0000 +#define P1023_OFFSET_FM 0x00100000 + +#define P1023_OFFSET_FM_MURAM (P1023_OFFSET_FM + 0x00000000) +#define P1023_OFFSET_FM_BMI (P1023_OFFSET_FM + 0x00080000) +#define P1023_OFFSET_FM_QMI (P1023_OFFSET_FM + 0x00080400) +#define P1023_OFFSET_FM_PRS (P1023_OFFSET_FM + 0x00080800) +#define P1023_OFFSET_FM_PORT_HO0 (P1023_OFFSET_FM + 0x00081000) +#define P1023_OFFSET_FM_PORT_HO1 (P1023_OFFSET_FM + 0x00082000) +#define P1023_OFFSET_FM_PORT_HO2 (P1023_OFFSET_FM + 0x00083000) +#define P1023_OFFSET_FM_PORT_HO3 (P1023_OFFSET_FM + 0x00084000) +#define P1023_OFFSET_FM_PORT_HO4 (P1023_OFFSET_FM + 0x00085000) +#define P1023_OFFSET_FM_PORT_1GRX0 (P1023_OFFSET_FM + 0x00088000) +#define P1023_OFFSET_FM_PORT_1GRX1 (P1023_OFFSET_FM + 0x00089000) +#define P1023_OFFSET_FM_PORT_1GTX0 (P1023_OFFSET_FM + 0x000A8000) +#define P1023_OFFSET_FM_PORT_1GTX1 (P1023_OFFSET_FM + 0x000A9000) +#define P1023_OFFSET_FM_PLCR (P1023_OFFSET_FM + 0x000C0000) +#define P1023_OFFSET_FM_KG (P1023_OFFSET_FM + 0x000C1000) +#define P1023_OFFSET_FM_DMA (P1023_OFFSET_FM + 0x000C2000) +#define P1023_OFFSET_FM_FPM (P1023_OFFSET_FM + 0x000C3000) +#define P1023_OFFSET_FM_IRAM (P1023_OFFSET_FM + 0x000C4000) +#define P1023_OFFSET_FM_PRS_IRAM (P1023_OFFSET_FM + 0x000C7000) +#define P1023_OFFSET_FM_RISC0 (P1023_OFFSET_FM + 0x000D0000) +#define P1023_OFFSET_FM_RISC1 (P1023_OFFSET_FM + 0x000D0400) +#define P1023_OFFSET_FM_MACSEC (P1023_OFFSET_FM + 0x000D8000) +#define P1023_OFFSET_FM_1GMAC0 (P1023_OFFSET_FM + 0x000E0000) +#define P1023_OFFSET_FM_1GMDIO0 (P1023_OFFSET_FM + 0x000E1120) +#define P1023_OFFSET_FM_1GMAC1 (P1023_OFFSET_FM + 0x000E2000) +#define P1023_OFFSET_FM_1GMDIO1 (P1023_OFFSET_FM + 0x000E3000) +#define P1023_OFFSET_FM_RTC (P1023_OFFSET_FM + 0x000FE000) + +/* Offsets relative to QM or BM portals base */ +#define P1023_OFFSET_PORTALS_CE_AREA 0x00000000 /* cache enabled area */ +#define P1023_OFFSET_PORTALS_CI_AREA 0x00100000 /* cache inhibited area */ + +#define P1023_OFFSET_PORTALS_CE(portal) (P1023_OFFSET_PORTALS_CE_AREA + 0x4000 * (portal)) +#define P1023_OFFSET_PORTALS_CI(portal) (P1023_OFFSET_PORTALS_CI_AREA + 0x1000 * (portal)) + +/**************************************************************************//** + @Description Transaction source ID (for memory controllers error reporting). +*//***************************************************************************/ +typedef enum e_TransSrc +{ + e_TRANS_SRC_PCIE_2 = 0x01, /**< PCIe port 2 */ + e_TRANS_SRC_PCIE_1 = 0x02, /**< PCIe port 1 */ + e_TRANS_SRC_PCIE_3 = 0x03, /**< PCIe port 3 */ + e_TRANS_SRC_LBC = 0x04, /**< Enhanced local bus */ + e_TRANS_SRC_DPAA_SW_PORTALS = 0x0E, /**< DPAA software portals or SRAM */ + e_TRANS_SRC_DDR = 0x0F, /**< DDR controller */ + e_TRANS_SRC_CORE_INS_FETCH = 0x10, /**< Processor (instruction) */ + e_TRANS_SRC_CORE_DATA = 0x11, /**< Processor (data) */ + e_TRANS_SRC_DMA = 0x15 /**< DMA */ +} e_TransSrc; + +/**************************************************************************//** + @Description Local Access Window Target interface ID +*//***************************************************************************/ +typedef enum e_P1023LawTargetId +{ + e_P1023_LAW_TARGET_PCIE_2 = 0x01, /**< PCI Express 2 target interface */ + e_P1023_LAW_TARGET_PCIE_1 = 0x02, /**< PCI Express 1 target interface */ + e_P1023_LAW_TARGET_PCIE_3 = 0x03, /**< PCI Express 3 target interface */ + e_P1023_LAW_TARGET_LBC = 0x04, /**< Local bus target interface */ + e_P1023_LAW_TARGET_QM_PORTALS = 0x0E, /**< Queue Manager Portals */ + e_P1023_LAW_TARGET_BM_PORTALS = 0x0E, /**< Buffer Manager Portals */ + e_P1023_LAW_TARGET_SRAM = 0x0E, /**< SRAM scratchpad */ + e_P1023_LAW_TARGET_DDR = 0x0F, /**< DDR target interface */ + e_P1023_LAW_TARGET_NONE = 0xFF /**< Invalid target interface */ +} e_P1023LawTargetId; + + +/**************************************************************************//** + @Group 1023_init_grp P1023 Initialization Unit + + @Description P1023 initialization unit API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description Part ID and revision number +*//***************************************************************************/ +typedef enum e_P1023DeviceName +{ + e_P1023_REV_INVALID = 0x00000000, /**< Invalid revision */ + e_SC1023_REV_1_0 = (int)0x80FC0010, /**< SC1023 rev 1.0 */ + e_SC1023_REV_1_1 = (int)0x80FC0011, /**< SC1023 rev 1.1 */ + e_P1023_REV_1_0 = (int)0x80FE0010, /**< P1023 rev 1.0 with security */ + e_P1023_REV_1_1 = (int)0x80FE0011, /**< P1023 rev 1.1 with security */ + e_P1023_REV_1_0_NO_SEC = (int)0x80F60010, /**< P1023 rev 1.0 without security */ + e_P1023_REV_1_1_NO_SEC = (int)0x80F60011 /**< P1023 rev 1.1 without security */ +} e_P1023DeviceName; + +/**************************************************************************//** + @Description structure representing P1023 initialization parameters +*//***************************************************************************/ +typedef struct t_P1023Params +{ + uintptr_t ccsrBaseAddress; /**< CCSR base address (virtual) */ + uintptr_t bmPortalsBaseAddress; /**< Portals base address (virtual) */ + uintptr_t qmPortalsBaseAddress; /**< Portals base address (virtual) */ +} t_P1023Params; + +/**************************************************************************//** + @Function P1023_ConfigAndInit + + @Description General initiation of the chip registers. + + @Param[in] p_P1023Params - A pointer to data structure of parameters + + @Return A handle to the P1023 data structure. +*//***************************************************************************/ +t_Handle P1023_ConfigAndInit(t_P1023Params *p_P1023Params); + +/**************************************************************************//** + @Function P1023_Free + + @Description Free all resources. + + @Param h_P1023 - (In) The handle of the initialized P1023 object. + + @Return E_OK on success; Other value otherwise. +*//***************************************************************************/ +t_Error P1023_Free(t_Handle h_P1023); + +/**************************************************************************//** + @Function P1023_GetRevInfo + + @Description This routine enables access to chip and revision information. + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + + @Return Part ID and revision. +*//***************************************************************************/ +e_P1023DeviceName P1023_GetRevInfo(uintptr_t gutilBase); + +/**************************************************************************//** + @Function P1023_GetE500Factor + + @Description Returns E500 core clock multiplication factor. + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + @Param[in] coreId - Id of the requested core. + @Param[out] p_E500MulFactor - Returns E500 to CCB multification factor. + @Param[out] p_E500DivFactor - Returns E500 to CCB division factor. + + @Return E_OK on success; Other value otherwise. +* +*//***************************************************************************/ +t_Error P1023_GetE500Factor(uintptr_t gutilBase, + uint32_t coreId, + uint32_t *p_E500MulFactor, + uint32_t *p_E500DivFactor); + +/**************************************************************************//** + @Function P1023_GetFmFactor + + @Description returns FM multiplication factors. (This value is returned using + two parameters to avoid using float parameter). + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + @Param[out] p_FmMulFactor - returns E500 to CCB multification factor. + @Param[out] p_FmDivFactor - returns E500 to CCB division factor. + + @Return E_OK on success; Other value otherwise. +*//***************************************************************************/ +t_Error P1023_GetFmFactor(uintptr_t gutilBase, uint32_t *p_FmMulFactor, uint32_t *p_FmDivFactor); + +/**************************************************************************//** + @Function P1023_GetCcbFactor + + @Description returns system multiplication factor. + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + + @Return System multiplication factor. +*//***************************************************************************/ +uint32_t P1023_GetCcbFactor(uintptr_t gutilBase); + +/**************************************************************************//** + @Function P1023_GetDdrFactor + + @Description returns the multiplication factor of the clock in for the DDR clock . + Note: assumes the ddr_in_clk is identical to the sys_in_clk + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + @Param p_DdrMulFactor - returns DDR in clk multification factor. + @Param p_DdrDivFactor - returns DDR division factor. + + @Return E_OK on success; Other value otherwise.. +*//***************************************************************************/ +t_Error P1023_GetDdrFactor( uintptr_t gutilBase, + uint32_t *p_DdrMulFactor, + uint32_t *p_DdrDivFactor); + + +/**************************************************************************//** + @Function P1023_GetDdrType + + @Description returns the multiplication factor of the clock in for the DDR clock . + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + @Param p_DdrType - (Out) returns DDR type DDR1/DDR2/DDR3. + + @Return E_OK on success; Other value otherwise. +*//***************************************************************************/ +#ifndef NCSW_LINUX +t_Error P1023_GetDdrType(uintptr_t gutilBase, e_DdrType *p_DdrType ); +#endif + + +/** @} */ /* end of 1023_init_grp group */ +/** @} */ /* end of 1023_grp group */ + +#define CORE_E500V2 + +/***************************************************************************** + INTEGRATION-SPECIFIC MODULE CODES +******************************************************************************/ +#define MODULE_UNKNOWN 0x00000000 +#define MODULE_MEM 0x00010000 +#define MODULE_MM 0x00020000 +#define MODULE_CORE 0x00030000 +#define MODULE_P1023 0x00040000 +#define MODULE_MII 0x00050000 +#define MODULE_PM 0x00060000 +#define MODULE_MMU 0x00070000 +#define MODULE_PIC 0x00080000 +#define MODULE_L2_CACHE 0x00090000 +#define MODULE_DUART 0x000a0000 +#define MODULE_SERDES 0x000b0000 +#define MODULE_PIO 0x000c0000 +#define MODULE_QM 0x000d0000 +#define MODULE_BM 0x000e0000 +#define MODULE_SEC 0x000f0000 +#define MODULE_FM 0x00100000 +#define MODULE_FM_MURAM 0x00110000 +#define MODULE_FM_PCD 0x00120000 +#define MODULE_FM_RTC 0x00130000 +#define MODULE_FM_MAC 0x00140000 +#define MODULE_FM_PORT 0x00150000 +#define MODULE_FM_MACSEC 0x00160000 +#define MODULE_FM_MACSEC_SECY 0x00170000 +#define MODULE_ECM 0x00180000 +#define MODULE_DMA 0x00190000 +#define MODULE_DDR 0x001a0000 +#define MODULE_LAW 0x001b0000 +#define MODULE_LBC 0x001c0000 +#define MODULE_I2C 0x001d0000 +#define MODULE_ESPI 0x001e0000 +#define MODULE_PCI 0x001f0000 +#define MODULE_DPA 0x00200000 +#define MODULE_USB 0x00210000 + +/***************************************************************************** + LBC INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +/**************************************************************************//** + @Group lbc_exception_grp LBC Exception Unit + + @Description LBC Exception unit API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Anchor lbc_exbm + + @Collection LBC Errors Bit Mask + + These errors are reported through the exceptions callback.. + The values can be or'ed in any combination in the errors mask + parameter of the errors report structure. + + These errors can also be passed as a bit-mask to + LBC_EnableErrorChecking() or LBC_DisableErrorChecking(), + for enabling or disabling error checking. + @{ +*//***************************************************************************/ +#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */ +#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */ +#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */ +#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */ + +#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \ + LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT) + /**< All possible errors */ +/* @} */ +/** @} */ /* end of lbc_exception_grp group */ + +#define LBC_NUM_OF_BANKS 2 +#define LBC_MAX_CS_SIZE 0x0000000100000000LL +#define LBC_ATOMIC_OPERATION_SUPPORT +#define LBC_PARITY_SUPPORT +#define LBC_ADDRESS_SHIFT_SUPPORT +#define LBC_ADDRESS_HOLD_TIME_CTRL +#define LBC_HIGH_CLK_DIVIDERS +#define LBC_FCM_AVAILABLE + + +/***************************************************************************** + LAW INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define LAW_ARCH_CCB +#define LAW_NUM_OF_WINDOWS 12 +#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4KB */ +#define LAW_MAX_WINDOW_SIZE 0x0000001000000000LL /**< 32GB */ + + +/***************************************************************************** + SPI INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define SPI_NUM_OF_CONTROLLERS 1 + +/***************************************************************************** + PCI/PCIe INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ + +#define PCI_MAX_INBOUND_WINDOWS_NUM 4 +#define PCI_MAX_OUTBOUND_WINDOWS_NUM 5 + +/**************************************************************************//** + @Description Target interface of an inbound window +*//***************************************************************************/ +typedef enum e_PciTargetInterface +{ + e_PCI_TARGET_PCIE_2 = 0x1, /**< PCI Express target interface 2 */ + e_PCI_TARGET_PCIE_1 = 0x2, /**< PCI Express target interface 1 */ + e_PCI_TARGET_PCIE_3 = 0x3, /**< PCI Express target interface 3 */ + e_PCI_TARGET_LOCAL_MEMORY = 0xF /**< Local Memory (DDR SDRAM, Local Bus, SRAM) target interface */ + +} e_PciTargetInterface; + +/***************************************************************************** + DDR INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define DDR_NUM_OF_VALID_CS 2 + +/***************************************************************************** + SEC INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define SEC_ERRATA_STAT_REGS_UNUSABLE + +/***************************************************************************** + DMA INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define DMA_NUM_OF_CONTROLLERS 1 + + + + +/***************************************************************************** + 1588 INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define PTP_V2 + +/**************************************************************************//** + @Function P1023_GetMuxControlReg + + @Description Returns the value of PMUXCR (Alternate Function Signal Multiplex + Control Register) + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + + @Return Value of PMUXCR +*//***************************************************************************/ +uint32_t P1023_GetMuxControlReg(uintptr_t gutilBase); + +/**************************************************************************//** + @Function P1023_SetMuxControlReg + + @Description Sets the value of PMUXCR (Alternate Function Signal Multiplex + Control Register) + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + @Param[in] val - the new value for PMUXCR. + + @Return None +*//***************************************************************************/ +void P1023_SetMuxControlReg(uintptr_t gutilBase, uint32_t val); + +/**************************************************************************//** + @Function P1023_GetPowerMngClkDisableReg + + @Description Returns the value of PMCDR (Power Management Clock Disable Register) + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + + @Return Value of PMCDR +*//***************************************************************************/ +uint32_t P1023_GetPowerMngClkDisableReg(uintptr_t gutilBase); + +/**************************************************************************//** + @Function P1023_SetPowerMngClkDisableReg + + @Description Sets the value of PMCDR ((Power Management Clock Disable Register)) + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + @Param[in] val - the new value for PMCDR. + + @Return None +*//***************************************************************************/ +void P1023_SetPowerMngClkDisableReg(uintptr_t gutilBase, uint32_t val); + +/**************************************************************************//** + @Function P1023_GetDeviceDisableStatusRegister + + @Description Returns the value of DEVDISR (Device Disable Register) + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + + @Return Value of DEVDISR +*//***************************************************************************/ +uint32_t P1023_GetDeviceDisableStatusRegister(uintptr_t gutilBase); + +/**************************************************************************//** + @Function P1023_GetPorDeviceStatusRegister + + @Description Returns the value of POR Device Status Register + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + + @Return POR Device Status Register +*//***************************************************************************/ +uint32_t P1023_GetPorDeviceStatusRegister(uintptr_t gutilBase); + +/**************************************************************************//** + @Function P1023_GetPorBootModeStatusRegister + + @Description Returns the value of POR Boot Mode Status Register + + @Param[in] gutilBase - Base address of P1023 GUTIL registers. + + @Return POR Boot Mode Status Register value +*//***************************************************************************/ +uint32_t P1023_GetPorBootModeStatusRegister(uintptr_t gutilBase); + + +#define PORDEVSR_SGMII1_DIS 0x10000000 +#define PORDEVSR_SGMII2_DIS 0x08000000 +#define PORDEVSR_ECP1 0x02000000 +#define PORDEVSR_IO_SEL 0x00780000 +#define PORDEVSR_IO_SEL_SHIFT 19 +#define PORBMSR_HA 0x00070000 +#define PORBMSR_HA_SHIFT 16 + +#define DEVDISR_QM_BM 0x80000000 +#define DEVDISR_FM 0x40000000 +#define DEVDISR_PCIE1 0x20000000 +#define DEVDISR_MAC_SEC 0x10000000 +#define DEVDISR_ELBC 0x08000000 +#define DEVDISR_PCIE2 0x04000000 +#define DEVDISR_PCIE3 0x02000000 +#define DEVDISR_CAAM 0x01000000 +#define DEVDISR_USB0 0x00800000 +#define DEVDISR_1588 0x00020000 +#define DEVDISR_CORE0 0x00008000 +#define DEVDISR_TB0 0x00004000 +#define DEVDISR_CORE1 0x00002000 +#define DEVDISR_TB1 0x00001000 +#define DEVDISR_DMA1 0x00000400 +#define DEVDISR_DMA2 0x00000200 +#define DEVDISR_DDR 0x00000010 +#define DEVDISR_TSEC1 0x00000080 +#define DEVDISR_TSEC2 0x00000040 +#define DEVDISR_SPI 0x00000008 +#define DEVDISR_I2C 0x00000004 +#define DEVDISR_DUART 0x00000002 + + +#endif /* __PART_INTEGRATION_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/integrations/P1023/dpaa_integration_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/integrations/P1023/dpaa_integration_ext.h @@ -0,0 +1,328 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + + @File dpaa_integration_ext.h + + @Description P1023 FM external definitions and structures. +*//***************************************************************************/ +#ifndef __DPAA_INTEGRATION_EXT_H +#define __DPAA_INTEGRATION_EXT_H + +#include "std_ext.h" + + +typedef enum e_DpaaSwPortal { + e_DPAA_SWPORTAL0 = 0, + e_DPAA_SWPORTAL1, + e_DPAA_SWPORTAL2 +} e_DpaaSwPortal; + +typedef enum { + e_DPAA_DCPORTAL0 = 0, + e_DPAA_DCPORTAL1, + e_DPAA_DCPORTAL2, + e_DPAA_DCPORTAL3 +} e_DpaaDcPortal; + +#define DPAA_MAX_NUM_OF_SW_PORTALS 3 +#define DPAA_MAX_NUM_OF_DC_PORTALS 3 + +/***************************************************************************** + QMAN INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define QM_MAX_NUM_OF_POOL_CHANNELS 3 +#define QM_MAX_NUM_OF_WQ 8 +#define QM_MAX_NUM_OF_SWP_AS 2 +#define QM_MAX_NUM_OF_CGS 64 +#define QM_MAX_NUM_OF_FQIDS (16*MEGABYTE) + +typedef enum { + e_QM_FQ_CHANNEL_SWPORTAL0 = 0, + e_QM_FQ_CHANNEL_SWPORTAL1, + e_QM_FQ_CHANNEL_SWPORTAL2, + + e_QM_FQ_CHANNEL_POOL1 = 0x21, + e_QM_FQ_CHANNEL_POOL2, + e_QM_FQ_CHANNEL_POOL3, + + e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40, + e_QM_FQ_CHANNEL_FMAN0_SP1, + e_QM_FQ_CHANNEL_FMAN0_SP2, + e_QM_FQ_CHANNEL_FMAN0_SP3, + e_QM_FQ_CHANNEL_FMAN0_SP4, + e_QM_FQ_CHANNEL_FMAN0_SP5, + e_QM_FQ_CHANNEL_FMAN0_SP6, + + + e_QM_FQ_CHANNEL_CAAM = 0x80 +} e_QmFQChannel; + +/***************************************************************************** + BMAN INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define BM_MAX_NUM_OF_POOLS 8 + +/***************************************************************************** + FM INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define INTG_MAX_NUM_OF_FM 1 + +/* Ports defines */ +#define FM_MAX_NUM_OF_1G_RX_PORTS 2 +#define FM_MAX_NUM_OF_10G_RX_PORTS 0 +#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS+FM_MAX_NUM_OF_1G_RX_PORTS) +#define FM_MAX_NUM_OF_1G_TX_PORTS 2 +#define FM_MAX_NUM_OF_10G_TX_PORTS 0 +#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS+FM_MAX_NUM_OF_1G_TX_PORTS) +#define FM_MAX_NUM_OF_OH_PORTS 5 +#define FM_MAX_NUM_OF_1G_MACS (FM_MAX_NUM_OF_1G_RX_PORTS) +#define FM_MAX_NUM_OF_10G_MACS (FM_MAX_NUM_OF_10G_RX_PORTS) +#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS+FM_MAX_NUM_OF_10G_MACS) +#define FM_MAX_NUM_OF_MACSECS 1 + +#if 0 +#define FM_MACSEC_SUPPORT +#define FM_CAPWAP_SUPPORT +#endif + +#define FM_LOW_END_RESTRICTION /* prevents the use of TX port 1 with OP port 0 */ + +#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */ +#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 2 /**< Number of Offline parsing port external BM pools per Rx port */ +#define FM_PORT_NUM_OF_CONGESTION_GRPS 32 /**< Total number of congestion groups in QM */ +#define FM_MAX_NUM_OF_SUB_PORTALS 7 + +/* Rams defines */ +#define FM_MURAM_SIZE (64*KILOBYTE) +#define FM_IRAM_SIZE (32*KILOBYTE) + +/* PCD defines */ +#define FM_PCD_PLCR_NUM_ENTRIES 32 /**< Total number of policer profiles */ +#define FM_PCD_KG_NUM_OF_SCHEMES 16 /**< Total number of KG schemes */ +#define FM_PCD_MAX_NUM_OF_CLS_PLANS 128 /**< Number of classification plan entries. */ + +/* RTC defines */ +#define FM_RTC_NUM_OF_ALARMS 2 +#define FM_RTC_NUM_OF_PERIODIC_PULSES 2 +#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 + +/* QMI defines */ +#define QMI_MAX_NUM_OF_TNUMS 15 +#define MAX_QMI_DEQ_SUBPORTAL 7 + +/* FPM defines */ +#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 + +/* DMA defines */ +#define DMA_THRESH_MAX_COMMQ 15 +#define DMA_THRESH_MAX_BUF 7 + +/* BMI defines */ +#define BMI_MAX_NUM_OF_TASKS 64 +#define BMI_MAX_NUM_OF_DMAS 16 +#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) +#define PORT_MAX_WEIGHT 4 + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ +typedef enum e_FmEventModules{ + e_FM_MOD_PRS, /**< Parser event */ + e_FM_MOD_KG, /**< Keygen event */ + e_FM_MOD_PLCR, /**< Policer event */ + e_FM_MOD_10G_MAC, /**< 10G MAC error event */ + e_FM_MOD_1G_MAC, /**< 1G MAC error event */ + e_FM_MOD_TMR, /**< Timer event */ + e_FM_MOD_1G_MAC_TMR, /**< 1G MAC Timer event */ + e_FM_MOD_FMAN_CTRL, /**< FMAN Controller Timer event */ + e_FM_MOD_MACSEC, + e_FM_MOD_DUMMY_LAST +} e_FmEventModules; + +/**************************************************************************//** + @Description Enum for interrupts types +*//***************************************************************************/ +typedef enum e_FmIntrType { + e_FM_INTR_TYPE_ERR, + e_FM_INTR_TYPE_NORMAL +} e_FmIntrType; + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ +typedef enum e_FmInterModuleEvent { + e_FM_EV_PRS, /**< Parser event */ + e_FM_EV_ERR_PRS, /**< Parser error event */ + e_FM_EV_KG, /**< Keygen event */ + e_FM_EV_ERR_KG, /**< Keygen error event */ + e_FM_EV_PLCR, /**< Policer event */ + e_FM_EV_ERR_PLCR, /**< Policer error event */ + e_FM_EV_ERR_10G_MAC0, /**< 10G MAC 0 error event */ + e_FM_EV_ERR_1G_MAC0, /**< 1G MAC 0 error event */ + e_FM_EV_ERR_1G_MAC1, /**< 1G MAC 1 error event */ + e_FM_EV_ERR_1G_MAC2, /**< 1G MAC 2 error event */ + e_FM_EV_ERR_1G_MAC3, /**< 1G MAC 3 error event */ + e_FM_EV_ERR_MACSEC_MAC0, /**< MACSEC MAC 0 error event */ + e_FM_EV_TMR, /**< Timer event */ + e_FM_EV_1G_MAC0_TMR, /**< 1G MAC 0 Timer event */ + e_FM_EV_1G_MAC1_TMR, /**< 1G MAC 1 Timer event */ + e_FM_EV_1G_MAC2_TMR, /**< 1G MAC 2 Timer event */ + e_FM_EV_1G_MAC3_TMR, /**< 1G MAC 3 Timer event */ + e_FM_EV_MACSEC_MAC0, /**< MACSEC MAC 0 event */ + e_FM_EV_FMAN_CTRL_0, /**< Fman controller event 0 */ + e_FM_EV_FMAN_CTRL_1, /**< Fman controller event 1 */ + e_FM_EV_FMAN_CTRL_2, /**< Fman controller event 2 */ + e_FM_EV_FMAN_CTRL_3, /**< Fman controller event 3 */ + e_FM_EV_DUMMY_LAST +} e_FmInterModuleEvent; + +#define GET_FM_MODULE_EVENT(mod, id, intrType, event) \ + switch(mod){ \ + case e_FM_MOD_PRS: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PRS:e_FM_EV_PRS; \ + break; \ + case e_FM_MOD_KG: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_KG:e_FM_EV_DUMMY_LAST; \ + break; \ + case e_FM_MOD_PLCR: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PLCR:e_FM_EV_PLCR; \ + break; \ + case e_FM_MOD_1G_MAC: \ + switch(id){ \ + case(0): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC0:e_FM_EV_DUMMY_LAST; break; \ + case(1): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC1:e_FM_EV_DUMMY_LAST; break; \ + case(2): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC2:e_FM_EV_DUMMY_LAST; break; \ + case(3): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_1G_MAC3:e_FM_EV_DUMMY_LAST; break; \ + } \ + break; \ + case e_FM_MOD_TMR: \ + if (id) event = e_FM_EV_DUMMY_LAST; \ + else event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST:e_FM_EV_TMR; \ + break; \ + case e_FM_MOD_1G_MAC_TMR: \ + switch(id){ \ + case(0): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST:e_FM_EV_1G_MAC0_TMR; break; \ + case(1): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST:e_FM_EV_1G_MAC1_TMR; break; \ + case(2): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST:e_FM_EV_1G_MAC2_TMR; break; \ + case(3): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST:e_FM_EV_1G_MAC3_TMR; break; \ + } \ + break; \ + case e_FM_MOD_MACSEC: \ + switch(id){ \ + case(0): event = (intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_MACSEC_MAC0:e_FM_EV_MACSEC_MAC0; break; \ + } \ + break; \ + case e_FM_MOD_FMAN_CTRL: \ + if (intrType == e_FM_INTR_TYPE_ERR) event = e_FM_EV_DUMMY_LAST; \ + else switch(id){ \ + case(0): event = e_FM_EV_FMAN_CTRL_0; break; \ + case(1): event = e_FM_EV_FMAN_CTRL_1; break; \ + case(2): event = e_FM_EV_FMAN_CTRL_2; break; \ + case(3): event = e_FM_EV_FMAN_CTRL_3; break; \ + } \ + break; \ + default:event = e_FM_EV_DUMMY_LAST; \ + break;} + +/***************************************************************************** + FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS +******************************************************************************/ +#define NUM_OF_RX_SC 16 +#define NUM_OF_TX_SC 16 + +#define NUM_OF_SA_PER_RX_SC 2 +#define NUM_OF_SA_PER_TX_SC 2 + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ + +typedef enum e_FmMacsecEventModules{ + e_FM_MACSEC_MOD_SC_TX, + e_FM_MACSEC_MOD_DUMMY_LAST +} e_FmMacsecEventModules; + +typedef enum e_FmMacsecInterModuleEvent { + e_FM_MACSEC_EV_SC_TX, + e_FM_MACSEC_EV_ERR_SC_TX, + e_FM_MACSEC_EV_DUMMY_LAST +} e_FmMacsecInterModuleEvent; + +#define NUM_OF_INTER_MODULE_EVENTS (NUM_OF_TX_SC * 2) + +#define GET_MACSEC_MODULE_EVENT(mod, id, intrType, event) \ + switch(mod){ \ + case e_FM_MACSEC_MOD_SC_TX: \ + event = (intrType == e_FM_INTR_TYPE_ERR) ? \ + e_FM_MACSEC_EV_ERR_SC_TX: \ + e_FM_MACSEC_EV_SC_TX; \ + event += (uint8_t)(2 * id);break; \ + break; \ + default:event = e_FM_MACSEC_EV_DUMMY_LAST; \ + break;} + + +/* 1023 unique features */ +#define FM_QMI_NO_ECC_EXCEPTIONS +#define FM_CSI_CFED_LIMIT +#define FM_PEDANTIC_DMA + +/* FM erratas */ +#define FM_NO_RX_PREAM_ERRATA_DTSECx1 +#define FM_RX_PREAM_4_ERRATA_DTSEC_A001 FM_NO_RX_PREAM_ERRATA_DTSECx1 +#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2 /* No implementation, Out of LLD scope */ + +#define FM_IM_TX_SYNC_SKIP_TNUM_ERRATA_FMAN_A001 /* Implemented by ucode */ +#define FM_HC_DEF_FQID_ONLY_ERRATA_FMAN_A003 /* Implemented by ucode */ +#define FM_IM_TX_SHARED_TNUM_ERRATA_FMAN4 /* Implemented by ucode */ +#define FM_IM_GS_DEADLOCK_ERRATA_FMAN5 /* Implemented by ucode */ +#define FM_IM_DEQ_PIPELINE_DEPTH_ERRATA_FMAN10 /* Implemented by ucode */ +#define FM_CC_GEN6_MISSMATCH_ERRATA_FMAN12 /* Implemented by ucode */ +#define FM_CC_CHANGE_SHARED_TNUM_ERRATA_FMAN13 /* Implemented by ucode */ +#define FM_IM_LARGE_MRBLR_ERRATA_FMAN15 /* Implemented by ucode */ + +/* #define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + +/* ??? */ +#define FM_GRS_ERRATA_DTSEC_A002 +#define FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 +#define FM_GTS_ERRATA_DTSEC_A004 +#define FM_TX_LOCKUP_ERRATA_DTSEC6 + +#define FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 + +#endif /* __FM_INTEGRATION_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/cores/ppc_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/cores/ppc_ext.h @@ -0,0 +1,130 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File ppc_ext.h + + @Description Core API for PowerPC cores + + These routines must be implemented by each specific PowerPC + core driver. +*//***************************************************************************/ +#ifndef __PPC_EXT_H +#define __PPC_EXT_H + +#include "part_ext.h" + + +#define CORE_IS_BIG_ENDIAN + + +/**************************************************************************//** + @Function CORE_TestAndSet + + @Description This routine tries to atomically test-and-set an integer + in memory to a non-zero value. + + The memory will be set only if it is tested as zero, in which + case the routine returns the new non-zero value; otherwise the + routine returns zero. + + @Param[in] p - pointer to a volatile int in memory, on which test-and-set + operation should be made. + + @Retval Zero - Operation failed - memory was already set. + @Retval Non-zero - Operation succeeded - memory has been set. +*//***************************************************************************/ +int CORE_TestAndSet(volatile int *p); + +/**************************************************************************//** + @Function CORE_InstructionSync + + @Description This routine will cause the core to wait for previous instructions + (including any interrupts they generate) to complete before the + synchronization command executes, which purges all instructions + from the processor's pipeline and refetches the next instruction. + + @Return None. +*//***************************************************************************/ +void CORE_InstructionSync(void); + +/**************************************************************************//** + @Function CORE_DCacheEnable + + @Description Enables the data cache for memory pages that are + not cache inhibited. + + @Return None. +*//***************************************************************************/ +void CORE_DCacheEnable(void); + +/**************************************************************************//** + @Function CORE_ICacheEnable + + @Description Enables the instruction cache for memory pages that are + not cache inhibited. + + @Return None. +*//***************************************************************************/ +void CORE_ICacheEnable(void); + +/**************************************************************************//** + @Function CORE_DCacheDisable + + @Description Disables the data cache. + + @Return None. +*//***************************************************************************/ +void CORE_DCacheDisable(void); + +/**************************************************************************//** + @Function CORE_ICacheDisable + + @Description Disables the instruction cache. + + @Return None. +*//***************************************************************************/ +void CORE_ICacheDisable(void); + + + + +#if defined(CORE_E300) +#include "e300_ext.h" +#elif defined(CORE_E500V2) || defined(CORE_E500MC) +#include "e500v2_ext.h" +#else +#error "Core not defined!" +#endif + + +#endif /* __PPC_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/cores/e500v2_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/cores/e500v2_ext.h @@ -0,0 +1,413 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File e500v2_ext.h + + @Description E500 external definitions prototypes + This file is not included by the E500 + source file as it is an assembly file. It is used + only for prototypes exposure, for inclusion + by user and other modules. +*//***************************************************************************/ + +#ifndef __E500V2_EXT_H +#define __E500V2_EXT_H + +#include "std_ext.h" + + +/* Layer 1 Cache Manipulations + *============================== + * Should not be called directly by the user. + */ +void L1DCache_Invalidate (void); +void L1ICache_Invalidate(void); +void L1DCache_Enable(void); +void L1ICache_Enable(void); +void L1DCache_Disable(void); +void L1ICache_Disable(void); +void L1DCache_Flush(void); +void L1ICache_Flush(void); +/* + * + */ +uint32_t L1DCache_LineLock(uint32_t addr); +uint32_t L1ICache_LineLock(uint32_t addr); +void L1Cache_BroadCastEnable(void); +void L1Cache_BroadCastDisable(void); + + +#define CORE_DCacheEnable E500_DCacheEnable +#define CORE_ICacheEnable E500_ICacheEnable +#define CORE_DCacheDisable E500_DCacheDisable +#define CORE_ICacheDisable E500_ICacheDisable +#define CORE_GetId E500_GetId +#define CORE_TestAndSet E500_TestAndSet +#define CORE_MemoryBarrier E500_MemoryBarrier +#define CORE_InstructionSync E500_InstructionSync + +#define CORE_SetDozeMode E500_SetDozeMode +#define CORE_SetNapMode E500_SetNapMode +#define CORE_SetSleepMode E500_SetSleepMode +#define CORE_SetJogMode E500_SetJogMode +#define CORE_SetDeepSleepMode E500_SetDeepSleepMode + +#define CORE_RecoverDozeMode E500_RecoverDozeMode +#define CORE_RecoverNapMode E500_RecoverNapMode +#define CORE_RecoverSleepMode E500_RecoverSleepMode +#define CORE_RecoverJogMode E500_RecoverJogMode + +void E500_SetDozeMode(void); +void E500_SetNapMode(void); +void E500_SetSleepMode(void); +void E500_SetJogMode(void); +t_Error E500_SetDeepSleepMode(uint32_t bptrAddress); + +void E500_RecoverDozeMode(void); +void E500_RecoverNapMode(void); +void E500_RecoverSleepMode(void); +void E500_RecoverJogMode(void); + + +/**************************************************************************//** + @Group E500_id E500 Application Programming Interface + + @Description E500 API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group E500_init_grp E500 Initialization Unit + + @Description E500 initialization unit API functions, definitions and enums + + @{ +*//***************************************************************************/ + + +/**************************************************************************//** + @Function E500_DCacheEnable + + @Description Enables the data cache for memory pages that are + not cache inhibited. + + @Return None. +*//***************************************************************************/ +void E500_DCacheEnable(void); + +/**************************************************************************//** + @Function E500_ICacheEnable + + @Description Enables the instruction cache for memory pages that are + not cache inhibited. + + @Return None. +*//***************************************************************************/ +void E500_ICacheEnable(void); + +/**************************************************************************//** + @Function E500_DCacheDisable + + @Description Disables the data cache. + + @Return None. +*//***************************************************************************/ +void E500_DCacheDisable(void); + +/**************************************************************************//** + @Function E500_ICacheDisable + + @Description Disables the instruction cache. + + @Return None. +*//***************************************************************************/ +void E500_ICacheDisable(void); + +/**************************************************************************//** + @Function E500_DCacheFlush + + @Description Flushes the data cache + + @Return None. +*//***************************************************************************/ +void E500_DCacheFlush(void); + +/**************************************************************************//** + @Function E500_ICacheFlush + + @Description Flushes the instruction cache. + + @Return None. +*//***************************************************************************/ +void E500_ICacheFlush(void); + +/**************************************************************************//** + @Function E500_DCacheSetStashId + + @Description Set Stash Id for data cache + + @Param[in] stashId the stash id to be set. + + @Return None. +*//***************************************************************************/ +void E500_DCacheSetStashId(uint8_t stashId); + +/**************************************************************************//** + @Description E500mc L2 Cache Operation Mode +*//***************************************************************************/ +typedef enum e_E500mcL2CacheMode +{ + e_L2_CACHE_MODE_DATA_ONLY = 0x00000001, /**< Cache data only */ + e_L2_CACHE_MODE_INST_ONLY = 0x00000002, /**< Cache instructions only */ + e_L2_CACHE_MODE_DATA_AND_INST = 0x00000003 /**< Cache data and instructions */ +} e_E500mcL2CacheMode; + +/**************************************************************************//** + @Function E500_L2CacheEnable + + @Description Enables the cache for memory pages that are not cache inhibited. + + @param[in] mode - L2 cache mode: data only, instruction only or instruction and data. + + @Return None. + + @Cautions This routine must be call only ONCE for both caches. I.e. it is + not possible to call this routine for i-cache and than to call + again for d-cache; The second call will override the first one. +*//***************************************************************************/ +void E500_L2CacheEnable(e_E500mcL2CacheMode mode); + +/**************************************************************************//** + @Function E500_L2CacheDisable + + @Description Disables the cache (data instruction or both). + + @Return None. + +*//***************************************************************************/ +void E500_L2CacheDisable(void); + +/**************************************************************************//** + @Function E500_L2CacheFlush + + @Description Flushes the cache. + + @Return None. +*//***************************************************************************/ +void E500_L2CacheFlush(void); + +/**************************************************************************//** + @Function E500_L2SetStashId + + @Description Set Stash Id + + @Param[in] stashId the stash id to be set. + + @Return None. +*//***************************************************************************/ +void E500_L2SetStashId(uint8_t stashId); + +/**************************************************************************//** + @Function E500_AddressBusStreamingEnable + + @Description Enables address bus streaming on the CCB. + + This setting, along with the ECM streaming configuration + parameters, enables address bus streaming on the CCB. + + @Return None. +*//***************************************************************************/ +void E500_AddressBusStreamingEnable(void); + +/**************************************************************************//** + @Function E500_AddressBusStreamingDisable + + @Description Disables address bus streaming on the CCB. + + @Return None. +*//***************************************************************************/ +void E500_AddressBusStreamingDisable(void); + +/**************************************************************************//** + @Function E500_AddressBroadcastEnable + + @Description Enables address broadcast. + + The e500 broadcasts cache management instructions (dcbst, dcblc + (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi) + based on ABE. ABE must be set to allow management of external + L2 caches. + + @Return None. +*//***************************************************************************/ +void E500_AddressBroadcastEnable(void); + +/**************************************************************************//** + @Function E500_AddressBroadcastDisable + + @Description Disables address broadcast. + + The e500 broadcasts cache management instructions (dcbst, dcblc + (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi) + based on ABE. ABE must be set to allow management of external + L2 caches. + + @Return None. +*//***************************************************************************/ +void E500_AddressBroadcastDisable(void); + +/**************************************************************************//** + @Function E500_IsTaskletSupported + + @Description Checks if tasklets are supported by the e500 interrupt handler. + + @Retval TRUE - Tasklets are supported. + @Retval FALSE - Tasklets are not supported. +*//***************************************************************************/ +bool E500_IsTaskletSupported(void); + +void E500_EnableTimeBase(void); +void E500_DisableTimeBase(void); + +uint64_t E500_GetTimeBaseTime(void); + +void E500_GenericIntrInit(void); + +t_Error E500_SetIntr(int ppcIntrSrc, + void (* Isr)(t_Handle handle), + t_Handle handle); + +t_Error E500_ClearIntr(int ppcIntrSrc); + +/**************************************************************************//** + @Function E500_GenericIntrHandler + + @Description This is the general e500 interrupt handler. + + It is called by the main assembly interrupt handler + when an exception occurs and no other function has been + assigned to this exception. + + @Param intrEntry - (In) The exception interrupt vector entry. +*//***************************************************************************/ +void E500_GenericIntrHandler(uint32_t intrEntry); + +/**************************************************************************//** + @Function CriticalIntr + + @Description This is the specific critical e500 interrupt handler. + + It is called by the main assembly interrupt handler + when an critical interrupt. + + @Param intrEntry - (In) The exception interrupt vector entry. +*//***************************************************************************/ +void CriticalIntr(uint32_t intrEntry); + + +/**************************************************************************//** + @Function E500_GetId + + @Description Returns the core ID in the system. + + @Return Core ID. +*//***************************************************************************/ +uint32_t E500_GetId(void); + +/**************************************************************************//** + @Function E500_TestAndSet + + @Description This routine tries to atomically test-and-set an integer + in memory to a non-zero value. + + The memory will be set only if it is tested as zero, in which + case the routine returns the new non-zero value; otherwise the + routine returns zero. + + @Param[in] p - pointer to a volatile int in memory, on which test-and-set + operation should be made. + + @Retval Zero - Operation failed - memory was already set. + @Retval Non-zero - Operation succeeded - memory has been set. +*//***************************************************************************/ +int E500_TestAndSet(volatile int *p); + +/**************************************************************************//** + @Function E500_MemoryBarrier + + @Description This routine will cause the core to stop executing any commands + until all previous memory read/write commands are completely out + of the core's pipeline. + + @Return None. +*//***************************************************************************/ +static __inline__ void E500_MemoryBarrier(void) +{ +#ifdef CORE_E500MC + __asm__ ("mbar 1"); +#else + /**** ERRATA WORK AROUND START ****/ + /* ERRATA num: CPU1 */ + /* Description: "mbar MO = 1" instruction fails to order caching-inhibited + guarded loads and stores. */ + + /* "msync" instruction is used instead */ + + __asm__ ("msync"); + + /**** ERRATA WORK AROUND END ****/ +#endif +} + +/**************************************************************************//** + @Function E500_InstructionSync + + @Description This routine will cause the core to wait for previous instructions + (including any interrupts they generate) to complete before the + synchronization command executes, which purges all instructions + from the processor's pipeline and refetches the next instruction. + + @Return None. +*//***************************************************************************/ +static __inline__ void E500_InstructionSync(void) +{ + __asm__ ("isync"); +} + + +/** @} */ /* end of E500_init_grp group */ +/** @} */ /* end of E500_grp group */ + + +#endif /* __E500V2_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_mac_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_mac_ext.h @@ -0,0 +1,713 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_mac_ext.h + + @Description FM MAC ... +*//***************************************************************************/ +#ifndef __FM_MAC_EXT_H +#define __FM_MAC_EXT_H + +#include "std_ext.h" +#include "enet_ext.h" + + +/**************************************************************************//** + + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_mac_grp FM MAC + + @Description FM MAC API functions, definitions and enums + + @{ +*//***************************************************************************/ + + +/**************************************************************************//** + @Description FM MAC Exceptions +*//***************************************************************************/ +typedef enum e_FmMacExceptions { + e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0 + ,e_FM_MAC_EX_10G_MDIO_CMD_CMPL + ,e_FM_MAC_EX_10G_REM_FAULT + ,e_FM_MAC_EX_10G_LOC_FAULT + ,e_FM_MAC_EX_10G_1TX_ECC_ER + ,e_FM_MAC_EX_10G_TX_FIFO_UNFL + ,e_FM_MAC_EX_10G_TX_FIFO_OVFL + ,e_FM_MAC_EX_10G_TX_ER + ,e_FM_MAC_EX_10G_RX_FIFO_OVFL + ,e_FM_MAC_EX_10G_RX_ECC_ER + ,e_FM_MAC_EX_10G_RX_JAB_FRM + ,e_FM_MAC_EX_10G_RX_OVRSZ_FRM + ,e_FM_MAC_EX_10G_RX_RUNT_FRM + ,e_FM_MAC_EX_10G_RX_FRAG_FRM + ,e_FM_MAC_EX_10G_RX_LEN_ER + ,e_FM_MAC_EX_10G_RX_CRC_ER + ,e_FM_MAC_EX_10G_RX_ALIGN_ER + ,e_FM_MAC_EX_1G_BAB_RX + ,e_FM_MAC_EX_1G_RX_CTL + ,e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET + ,e_FM_MAC_EX_1G_BAB_TX + ,e_FM_MAC_EX_1G_TX_CTL + ,e_FM_MAC_EX_1G_TX_ERR + ,e_FM_MAC_EX_1G_LATE_COL + ,e_FM_MAC_EX_1G_COL_RET_LMT + ,e_FM_MAC_EX_1G_TX_FIFO_UNDRN + ,e_FM_MAC_EX_1G_MAG_PCKT + ,e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET + ,e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET + ,e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET + ,e_FM_MAC_EX_1G_TX_DATA_ERR + ,e_FM_MAC_EX_1G_RX_DATA_ERR + ,e_FM_MAC_EX_1G_1588_TS_RX_ERR + ,e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL +} e_FmMacExceptions; + +/**************************************************************************//** + @Description TM MAC statistics level +*//***************************************************************************/ +typedef enum e_FmMacStatisticsLevel { + e_FM_MAC_NONE_STATISTICS = 0, /**< No statistics */ + e_FM_MAC_PARTIAL_STATISTICS, /**< Only error counters are available. Optimized for performance */ + e_FM_MAC_FULL_STATISTICS /**< All counters available. Not optimized for performance */ +} e_FmMacStatisticsLevel; + + +/**************************************************************************//** + @Function t_FmMacExceptionCallback + + @Description Fm Mac Exception Callback from FM MAC to the user + + @Param[in] h_App - Handle to the upper layer handler + + @Param[in] exceptions - The exception that occurred + + + @Return void. +*//***************************************************************************/ +typedef void (t_FmMacExceptionCallback)(t_Handle h_App, e_FmMacExceptions exceptions); + + +/**************************************************************************//** + @Description TM MAC statistics rfc3635 +*//***************************************************************************/ +typedef struct t_FmMacStatistics { +/* RMON */ + uint64_t eStatPkts64; /**< r-10G tr-DT 64 byte frame counter */ + uint64_t eStatPkts65to127; /**< r-10G 65 to 127 byte frame counter */ + uint64_t eStatPkts128to255; /**< r-10G 128 to 255 byte frame counter */ + uint64_t eStatPkts256to511; /**< r-10G 256 to 511 byte frame counter */ + uint64_t eStatPkts512to1023; /**< r-10G 512 to 1023 byte frame counter */ + uint64_t eStatPkts1024to1518; /**< r-10G 1024 to 1518 byte frame counter */ + uint64_t eStatPkts1519to1522; /**< r-10G 1519 to 1522 byte good frame count */ +/* */ + uint64_t eStatFragments; /**< Total number of packets that were less than 64 octets long with a wrong CRC.*/ + uint64_t eStatJabbers; /**< Total number of packets longer than valid maximum length octets */ + uint64_t eStatsDropEvents; /**< number of dropped packets due to internal errors of the MAC Client. */ + uint64_t eStatCRCAlignErrors; /**< Incremented when frames of correct length but with CRC error are received.*/ + uint64_t eStatUndersizePkts; /**< Total number of packets that were less than 64 octets long with a good CRC.*/ + uint64_t eStatOversizePkts; /**< T,B.D*/ +/* Pause */ + uint64_t teStatPause; /**< Pause MAC Control received */ + uint64_t reStatPause; /**< Pause MAC Control sent */ + +/* MIB II */ + uint64_t ifInOctets; /**< Total number of byte received. */ + uint64_t ifInPkts; /**< Total number of packets received.*/ + uint64_t ifInMcastPkts; /**< Total number of multicast frame received*/ + uint64_t ifInBcastPkts; /**< Total number of broadcast frame received */ + uint64_t ifInDiscards; /**< Frames received, but discarded due to problems within the MAC RX. */ + uint64_t ifInErrors; /**< Number of frames received with error: + - FIFO Overflow Error + - CRC Error + - Frame Too Long Error + - Alignment Error + - The dedicated Error Code (0xfe, not a code error) was received */ + uint64_t ifOutOctets; /**< Total number of byte sent. */ + uint64_t ifOutPkts; /**< Total number of packets sent .*/ + uint64_t ifOutMcastPkts; /**< Total number of multicast frame sent */ + uint64_t ifOutBcastPkts; /**< Total number of multicast frame sent */ + uint64_t ifOutDiscards; /**< Frames received, but discarded due to problems within the MAC TX N/A!.*/ + uint64_t ifOutErrors; /**< Number of frames transmitted with error: + - FIFO Overflow Error + - FIFO Underflow Error + - Other */ +} t_FmMacStatistics; + + +/**************************************************************************//** + @Group FM_mac_init_grp Initialization Unit + + @Description FM MAC Initialization Unit + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description FM MAC config input +*//***************************************************************************/ +typedef struct t_FmMacParams { + uintptr_t baseAddr; /**< Base of memory mapped FM MAC registers */ + t_EnetAddr addr; /**< MAC address of device; First octet is sent first */ + uint8_t macId; /**< MAC ID <10G 0> */ + e_EnetMode enetMode; /**< Ethernet operation mode (MAC-PHY interface and speed) */ + t_Handle h_Fm; /**< A handle to the FM object this port related to */ + int mdioIrq; /**< MDIO exceptions interrupt source - not valid for all + MACs; MUST be set to 'NO_IRQ' for MACs that don't have + mdio-irq, or for polling */ + t_FmMacExceptionCallback *f_Event; /**< MDIO Events Callback Routine */ + t_FmMacExceptionCallback *f_Exception; /**< Exception Callback Routine */ + t_Handle h_App; /**< A handle to an application layer object; This handle will + be passed by the driver upon calling the above callbacks */ +} t_FmMacParams; + + +/**************************************************************************//** + @Function FM_MAC_Config + + @Description Creates descriptor for the FM MAC module. + + The routine returns a handle (descriptor) to the FM MAC object. + This descriptor must be passed as first parameter to all other + FM MAC function calls. + + No actual initialization or configuration of FM MAC hardware is + done by this routine. + + @Param[in] p_FmMacParam - Pointer to data structure of parameters + + @Retval Handle to FM MAC object, or NULL for Failure. +*//***************************************************************************/ +t_Handle FM_MAC_Config (t_FmMacParams *p_FmMacParam); + +/**************************************************************************//** + @Function FM_MAC_Init + + @Description Initializes the FM MAC module + + @Param[in] h_FmMac - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_MAC_Init (t_Handle h_FmMac); + +/**************************************************************************//** + @Function FM_Free + + @Description Frees all resources that were assigned to FM MAC module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmMac - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_MAC_Free (t_Handle h_FmMac); + + +/**************************************************************************//** + @Group FM_mac_advanced_init_grp Advanced Configuration Unit + + @Description Configuration functions used to change default values. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function FM_MAC_ConfigResetOnInit + + @Description Tell the driver whether to reset the FM MAC before initialization or + not. It changes the default configuration [FALSE]. + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] enable When TRUE, FM will be reset before any initialization. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigResetOnInit (t_Handle h_FmMac, bool enable); + +/**************************************************************************//** + @Function FM_MAC_ConfigLoopback + + @Description Enable/Disable internal loopback mode + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] enable TRUE to enable or FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigLoopback (t_Handle h_FmMac, bool enable); + +/**************************************************************************//** + @Function FM_MAC_ConfigMaxFrameLength + + @Description Setup maximum Frame Length + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] newVal MAX Frame length + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigMaxFrameLength (t_Handle h_FmMac, uint16_t newVal); + +/**************************************************************************//** + @Function FM_MAC_ConfigWan + + @Description ENABLE WAN mode in 10G MAC + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] enable TRUE to enable or FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigWan (t_Handle h_FmMac, bool enable); + +/**************************************************************************//** + @Function FM_MAC_ConfigPadAndCrc + + @Description Config PAD and CRC mode + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] enable TRUE to enable or FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigPadAndCrc (t_Handle h_FmMac, bool enable); + +/**************************************************************************//** + @Function FM_MAC_ConfigHalfDuplex + + @Description Config Half Duplex Mode + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] enable TRUE to enable or FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigHalfDuplex (t_Handle h_FmMac, bool enable); + +/**************************************************************************//** + @Function FM_MAC_ConfigLengthCheck + + @Description Configure thef frame length checking. + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] enable TRUE to enable or FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigLengthCheck (t_Handle h_FmMac, bool enable); + +/**************************************************************************//** + @Function FM_MAC_ConfigException + + @Description Change Exception selection from default + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] ex Type of the desired exceptions + @Param[in] enable TRUE to enable the specified exception, FALSE to disable it. + + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ConfigException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac); +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ +/** @} */ /* end of FM_mac_advanced_init_grp group */ +/** @} */ /* end of FM_mac_init_grp group */ + + +/**************************************************************************//** + @Group FM_mac_runtime_control_grp Runtime Control Unit + + @Description FM MAC Runtime control unit API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function FM_MAC_Enable + + @Description Enable the MAC + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] mode Mode of operation (RX, TX, Both) + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_Enable (t_Handle h_FmMac, e_CommMode mode); + +/**************************************************************************//** + @Function FM_MAC_Disable + + @Description DISABLE the MAC + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] mode Define what part to Disable (RX, TX or BOTH) + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_Disable (t_Handle h_FmMac, e_CommMode mode); + +/**************************************************************************//** + @Function FM_MAC_Enable1588TimeStamp + + @Description Enables the TSU operation. + + @Param[in] h_Fm - Handle to the PTP as returned from the FM_MAC_PtpConfig. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_Enable1588TimeStamp(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_MAC_Disable1588TimeStamp + + @Description Disables the TSU operation. + + @Param[in] h_Fm - Handle to the PTP as returned from the FM_MAC_PtpConfig. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_Disable1588TimeStamp(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_MAC_SetTxAutoPauseFrames + + @Description Enable/Disable transmition of Pause-Frames. + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] pauseTime Pause quanta value used with transmitted pause frames. + Each quanta represents a 512 bit-times; Note that '0' + as an input here will be used as disabling the + transmission of the pause-frames. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_SetTxAutoPauseFrames (t_Handle h_FmMac, uint16_t pauseTime); + +/**************************************************************************//** + @Function FM_MAC_SetRxIgnorePauseFrames + + @Description Enable/Disable ignoring of Pause-Frames. + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] en boolean indicates whether to ignore the incoming pause + frames or not. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_SetRxIgnorePauseFrames (t_Handle h_FmMac, bool en); + +/**************************************************************************//** + @Function FM_MAC_ResetCounters + + @Description reset all statistics counters + + @Param[in] h_FmMac A handle to a FM MAC Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ResetCounters (t_Handle h_FmMac); + +/**************************************************************************//** + @Function FM_MAC_SetException + + @Description Enable/Disable a specific Exception + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] ex Type of the desired exceptions + @Param[in] enable TRUE to enable the specified exception, FALSE to disable it. + + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); + +/**************************************************************************//** + @Function FM_MAC_SetStatistics + + @Description Define Statistics level. + Where applicable, the routine also enables the MIB counters + overflow interrupt in order to keep counters accurate + and account for overflows. + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] statisticsLevel Full statistics level provides all standard counters but may + reduce performance. Partial statistics provides only special + event counters (errors etc.). If selected, regular counters (such as + byte/packet) will be invalid and will return -1. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_SetStatistics (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel); + +/**************************************************************************//** + @Function FM_MAC_GetStatistics + + @Description get all statistics counters + + @Param[in] h_FmMac A handle to a FM MAC Module. + @Param[in] p_Statistics Staructure with statistics + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FM_MAC_GetStatistics (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics); + +/**************************************************************************//** + @Function FM_MAC_ModifyMacAddr + + @Description Replace the main MAC Address + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] p_EnetAddr - Ethernet Mac address + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + +/**************************************************************************//** + @Function FM_MAC_AddHashMacAddr + + @Description Add an Address to the hash table. This is for filter purpose only. + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] p_EnetAddr - Ethernet Mac address + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). It is a filter only address. + @Cautions Some address need to be filterd out in upper FM blocks. +*//***************************************************************************/ +t_Error FM_MAC_AddHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + +/**************************************************************************//** + @Function FM_MAC_RemoveHashMacAddr + + @Description Delete an Address to the hash table. This is for filter purpose only. + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] p_EnetAddr - Ethernet Mac address + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_RemoveHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + +/**************************************************************************//** + @Function FM_MAC_AddExactMatchMacAddr + + @Description Add a unicast or multicast mac address for exact-match filtering + (8 on dTSEC, 2 for 10G-MAC) + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] p_EnetAddr - MAC Address to ADD + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_AddExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + +/**************************************************************************//** + @Function FM_MAC_RemovelExactMatchMacAddr + + @Description Remove a uni cast or multi cast mac address. + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] p_EnetAddr - MAC Address to remove + + @Return E_OK on success; Error code otherwise.. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_RemovelExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + +/**************************************************************************//** + @Function FM_MAC_SetPromiscuous + + @Description Enable/Disable MAC Promiscuous mode for ALL mac addresses. + + @Param[in] h_FmMac - A handle to a FM MAC Module. + @Param[in] enable - TRUE to enable or FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_SetPromiscuous (t_Handle h_FmMac, bool enable); + +/**************************************************************************//** + @Function FM_MAC_AdjustLink + + @Description Adjusts the Ethernet link with new speed/duplex setup. + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] speed - Ethernet speed. + @Param[in] fullDuplex - TRUE for Full-Duplex mode; + FALSE for Half-Duplex mode. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex); + +/**************************************************************************//** + @Function FM_MAC_GetId + + @Description Return the MAC ID + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[out] p_MacId - MAC ID of device + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_GetId (t_Handle h_FmMac, uint32_t *p_MacId); + +/**************************************************************************//** + @Function FM_MAC_GetVesrion + + @Description Return Mac HW chip version + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[out] p_MacVresion - Mac version as defined by the chip + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_GetVesrion (t_Handle h_FmMac, uint32_t *p_MacVresion); + +/**************************************************************************//** + @Function FM_MAC_MII_WritePhyReg + + @Description Write data into Phy Register + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] phyAddr - Phy Address on the MII bus + @Param[in] reg - Register Number. + @Param[in] data - Data to write. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_MII_WritePhyReg (t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data); + +/**************************************************************************//** + @Function FM_MAC_MII_ReadPhyReg + + @Description Read data from Phy Register + + @Param[in] h_FmMac - A handle to a FM Module. + @Param[in] phyAddr - Phy Address on the MII bus + @Param[in] reg - Register Number. + @Param[out] p_Data - Data from PHY. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/**************************************************************************//** + @Function FM_MAC_DumpRegs + + @Description Dump internal registers + + @Param[in] h_FmMac - A handle to a FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only after FM_MAC_Init(). +*//***************************************************************************/ +t_Error FM_MAC_DumpRegs(t_Handle h_FmMac); +#endif /* (defined(DEBUG_ERRORS) && ... */ + +/** @} */ /* end of FM_mac_runtime_control_grp group */ +/** @} */ /* end of FM_mac_grp group */ +/** @} */ /* end of FM_grp group */ + + + +#endif /* __FM_MAC_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_ext.h @@ -0,0 +1,1347 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_ext.h + + @Description FM Application Programming Interface. +*//***************************************************************************/ +#ifndef __FM_EXT +#define __FM_EXT + +#include "error_ext.h" +#include "std_ext.h" +#include "dpaa_ext.h" + + +/**************************************************************************//** + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_lib_grp FM library + + @Description FM API functions, definitions and enums + The FM module is the main driver module and is a mandatory module + for FM driver users. Before any further module initialization, + this module must be initialized. + The FM is a "singletone" module. It is responsible of the common + HW modules: FPM, DMA, common QMI, common BMI initializations and + run-time control routines. This module must be initialized always + when working with any of the FM modules. + NOTE - We assumes that the FML will be initialize only by core No. 0! + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description enum for defining port types +*//***************************************************************************/ +typedef enum e_FmPortType { + e_FM_PORT_TYPE_OH_OFFLINE_PARSING = 0, /**< Offline parsing port (id's: 0-6, share id's with + host command, so must have exclusive id) */ + e_FM_PORT_TYPE_OH_HOST_COMMAND, /**< Host command port (id's: 0-6, share id's with + offline parsing ports, so must have exclusive id) */ + e_FM_PORT_TYPE_RX, /**< 1G Rx port (id's: 0-3) */ + e_FM_PORT_TYPE_RX_10G, /**< 10G Rx port (id's: 0) */ + e_FM_PORT_TYPE_TX, /**< 1G Tx port (id's: 0-3) */ + e_FM_PORT_TYPE_TX_10G, /**< 10G Tx port (id's: 0) */ + e_FM_PORT_TYPE_DUMMY +} e_FmPortType; + +/**************************************************************************//** + @Collection General FM defines +*//***************************************************************************/ +#define FM_MAX_NUM_OF_PARTITIONS 64 /**< Maximum number of partitions */ +#define FM_PHYS_ADDRESS_SIZE 6 /**< FM Physical address size */ +/* @} */ + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/**************************************************************************//** + @Description FM physical Address +*//***************************************************************************/ +typedef _Packed struct t_FmPhysAddr { + volatile uint8_t high; /**< High part of the physical address */ + volatile uint32_t low; /**< Low part of the physical address */ +} _PackedType t_FmPhysAddr; + +/**************************************************************************//** + @Description Parse results memory layout +*//***************************************************************************/ +typedef _Packed struct t_FmPrsResult { + volatile uint8_t lpid; /**< Logical port id */ + volatile uint8_t shimr; /**< Shim header result */ + volatile uint16_t l2r; /**< Layer 2 result */ + volatile uint16_t l3r; /**< Layer 3 result */ + volatile uint8_t l4r; /**< Layer 4 result */ + volatile uint8_t cplan; /**< Classification plan id */ + volatile uint16_t nxthdr; /**< Next Header */ + volatile uint16_t cksum; /**< Checksum */ + volatile uint32_t lcv; /**< LCV */ + volatile uint8_t shim_off[3]; /**< Shim offset */ + volatile uint8_t eth_off; /**< ETH offset */ + volatile uint8_t llc_snap_off; /**< LLC_SNAP offset */ + volatile uint8_t vlan_off[2]; /**< VLAN offset */ + volatile uint8_t etype_off; /**< ETYPE offset */ + volatile uint8_t pppoe_off; /**< PPP offset */ + volatile uint8_t mpls_off[2]; /**< MPLS offset */ + volatile uint8_t ip_off[2]; /**< IP offset */ + volatile uint8_t gre_off; /**< GRE offset */ + volatile uint8_t l4_off; /**< Layer 4 offset */ + volatile uint8_t nxthdr_off; /**< Parser end point */ +} _PackedType t_FmPrsResult; + +/**************************************************************************//** + @Collection FM Parser results +*//***************************************************************************/ +#define FM_PR_L2_VLAN_STACK 0x00000100 /**< Parse Result: VLAN stack */ +#define FM_PR_L2_ETHERNET 0x00008000 /**< Parse Result: Ethernet*/ +#define FM_PR_L2_VLAN 0x00004000 /**< Parse Result: VLAN */ +#define FM_PR_L2_LLC_SNAP 0x00002000 /**< Parse Result: LLC_SNAP */ +#define FM_PR_L2_MPLS 0x00001000 /**< Parse Result: MPLS */ +#define FM_PR_L2_PPPoE 0x00000800 /**< Parse Result: PPPoE */ +/* @} */ + +/**************************************************************************//** + @Collection FM Frame descriptor macros +*//***************************************************************************/ +#define FM_FD_CMD_FCO 0x80000000 /**< Frame queue Context Override */ +#define FM_FD_CMD_RPD 0x40000000 /**< Read Prepended Data */ +#define FM_FD_CMD_UPD 0x20000000 /**< Update Prepended Data */ +#define FM_FD_CMD_DTC 0x10000000 /**< Do L4 Checksum */ +#define FM_FD_CMD_DCL4C 0x10000000 /**< Didn't calculate L4 Checksum */ +#define FM_FD_CMD_CFQ 0x00ffffff /**< Confirmation Frame Queue */ + +#define FM_FD_TX_STATUS_ERR_MASK 0x07000000 /**< TX Error FD bits */ +#define FM_FD_RX_STATUS_ERR_MASK 0x070ee3f8 /**< RX Error FD bits */ +/* @} */ + +/**************************************************************************//** + @Description Context A +*//***************************************************************************/ +typedef _Packed struct t_FmContextA { + volatile uint32_t command; /**< ContextA Command */ + volatile uint8_t res0[4]; /**< ContextA Reserved bits */ +} _PackedType t_FmContextA; + +/**************************************************************************//** + @Description Context B +*//***************************************************************************/ +typedef uint32_t t_FmContextB; + +/**************************************************************************//** + @Collection Context A macros +*//***************************************************************************/ +#define FM_CONTEXTA_OVERRIDE_MASK 0x80000000 +#define FM_CONTEXTA_ICMD_MASK 0x40000000 +#define FM_CONTEXTA_A1_VALID_MASK 0x20000000 +#define FM_CONTEXTA_MACCMD_MASK 0x00ff0000 +#define FM_CONTEXTA_MACCMD_VALID_MASK 0x00800000 +#define FM_CONTEXTA_MACCMD_SECURED_MASK 0x00100000 +#define FM_CONTEXTA_MACCMD_SC_MASK 0x000f0000 +#define FM_CONTEXTA_A1_MASK 0x0000ffff + +#define FM_CONTEXTA_GET_OVERRIDE(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_OVERRIDE_MASK) >> (31-0)) +#define FM_CONTEXTA_GET_ICMD(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_ICMD_MASK) >> (31-1)) +#define FM_CONTEXTA_GET_A1_VALID(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_VALID_MASK) >> (31-2)) +#define FM_CONTEXTA_GET_A1(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_MASK) >> (31-31)) +#define FM_CONTEXTA_GET_MACCMD(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_MASK) >> (31-15)) +#define FM_CONTEXTA_GET_MACCMD_VALID(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_VALID_MASK) >> (31-8)) +#define FM_CONTEXTA_GET_MACCMD_SECURED(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SECURED_MASK) >> (31-11)) +#define FM_CONTEXTA_GET_MACCMD_SECURE_CHANNEL(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SC_MASK) >> (31-15)) + +#define FM_CONTEXTA_SET_OVERRIDE(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_OVERRIDE_MASK) | (((uint32_t)(val) << (31-0)) & FM_CONTEXTA_OVERRIDE_MASK) )) +#define FM_CONTEXTA_SET_ICMD(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_ICMD_MASK) | (((val) << (31-1)) & FM_CONTEXTA_ICMD_MASK) )) +#define FM_CONTEXTA_SET_A1_VALID(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_VALID_MASK) | (((val) << (31-2)) & FM_CONTEXTA_A1_VALID_MASK) )) +#define FM_CONTEXTA_SET_A1(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_MASK) | (((val) << (31-31)) & FM_CONTEXTA_A1_MASK) )) +#define FM_CONTEXTA_SET_MACCMD(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_MASK) )) +#define FM_CONTEXTA_SET_MACCMD_VALID(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_VALID_MASK) | (((val) << (31-8)) & FM_CONTEXTA_MACCMD_VALID_MASK) )) +#define FM_CONTEXTA_SET_MACCMD_SECURED(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SECURED_MASK) | (((val) << (31-11)) & FM_CONTEXTA_MACCMD_SECURED_MASK) )) +#define FM_CONTEXTA_SET_MACCMD_SECURE_CHANNEL(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SC_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_SC_MASK) )) +/* @} */ + +/**************************************************************************//** + @Collection Context B macros +*//***************************************************************************/ +#define FM_CONTEXTB_FQID_MASK 0x00ffffff + +#define FM_CONTEXTB_GET_FQID(contextB) (*((t_FmContextB *)contextB) & FM_CONTEXTB_FQID_MASK) +#define FM_CONTEXTB_SET_FQID(contextB,val) (*((t_FmContextB *)contextB) = ((*((t_FmContextB *)contextB) & ~FM_CONTEXTB_FQID_MASK) | ((val) & FM_CONTEXTB_FQID_MASK))) +/* @} */ + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/**************************************************************************//** + @Description FM Exceptions +*//***************************************************************************/ +typedef enum e_FmExceptions { + e_FM_EX_DMA_BUS_ERROR, /**< DMA bus error. */ + e_FM_EX_DMA_READ_ECC, /**< Read Buffer ECC error */ + e_FM_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC error on system side */ + e_FM_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side */ + e_FM_EX_FPM_STALL_ON_TASKS, /**< Stall of tasks on FPM */ + e_FM_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */ + e_FM_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */ + e_FM_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */ + e_FM_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occurred on QMI */ + e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< Dequeu from unknown port id */ + e_FM_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */ + e_FM_EX_BMI_PIPELINE_ECC, /**< Pipeline Table ECC Error */ + e_FM_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics Count RAM ECC Error Enable */ + e_FM_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */ + e_FM_EX_IRAM_ECC, /**< Double bit ECC occurred on IRAM*/ + e_FM_EX_MURAM_ECC /**< Double bit ECC occurred on MURAM*/ +} e_FmExceptions; + +/**************************************************************************//** + @Group FM_init_grp FM Initialization Unit + + @Description FM Initialization Unit + + Initialization Flow + Initialization of the FM Module will be carried out by the application + according to the following sequence: + a. Calling the configuration routine with basic parameters. + b. Calling the advance initialization routines to change driver's defaults. + c. Calling the initialization routine. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function t_FmExceptionsCallback + + @Description Exceptions user callback routine, will be called upon an + exception passing the exception identification. + + @Param[in] h_App - User's application descriptor. + @Param[in] exception - The exception. +*//***************************************************************************/ +typedef void (t_FmExceptionsCallback) (t_Handle h_App, + e_FmExceptions exception); + +/**************************************************************************//** + @Function t_FmBusErrorCallback + + @Description Bus error user callback routine, will be called upon a + bus error, passing parameters describing the errors and the owner. + + @Param[in] h_App - User's application descriptor. + @Param[in] portType - Port type (e_FmPortType) + @Param[in] portId - Port id - relative to type. + @Param[in] addr - Address that caused the error + @Param[in] tnum - Owner of error + @Param[in] liodn - Logical IO device number +*//***************************************************************************/ +typedef void (t_FmBusErrorCallback) (t_Handle h_App, + e_FmPortType portType, + uint8_t portId, + uint64_t addr, + uint8_t tnum, + uint16_t liodn); + +/**************************************************************************//** + @Description structure for defining Ucode patch for loading. +*//***************************************************************************/ +typedef struct t_FmPcdFirmwareParams { + uint32_t size; /**< Size of uCode */ + uint32_t *p_Code; /**< A pointer to the uCode */ +} t_FmPcdFirmwareParams; + +/**************************************************************************//** + @Description structure representing FM initialization parameters +*//***************************************************************************/ +#define FM_SIZE_OF_LIODN_TABLE 64 +typedef struct t_FmParams { + uint8_t fmId; /**< Index of the FM */ + + uint8_t guestId; /**< FM Partition Id */ + + uintptr_t baseAddr; /**< Relevant when guestId = NCSW_MASSTER_ID only. + A pointer to base of memory mapped FM registers (virtual); + NOTE that this should include ALL common regs of the FM including + the PCD regs area. */ + t_Handle h_FmMuram; /**< Relevant when guestId = NCSW_MASSTER_ID only. + A handle of an initialized MURAM object, + to be used by the FM */ + uint16_t fmClkFreq; /**< Relevant when guestId = NCSW_MASSTER_ID only. + In Mhz */ +#ifdef FM_PARTITION_ARRAY + uint16_t liodnBasePerPort[FM_SIZE_OF_LIODN_TABLE]; + /**< Relevant when guestId = NCSW_MASSTER_ID only. + For each partition, LIODN should be configured here. */ +#endif /* FM_PARTITION_ARRAY */ + t_FmExceptionsCallback *f_Exception; /**< Relevant when guestId = NCSW_MASSTER_ID only. + An application callback routine to + handle exceptions.*/ + t_FmBusErrorCallback *f_BusError; /**< Relevant when guestId = NCSW_MASSTER_ID only. + An application callback routine to + handle exceptions.*/ + t_Handle h_App; /**< Relevant when guestId = NCSW_MASSTER_ID only. + A handle to an application layer object; This handle will + be passed by the driver upon calling the above callbacks */ + int irq; /**< Relevant when guestId = NCSW_MASSTER_ID only. + FM interrupt source for normal events */ + int errIrq; /**< Relevant when guestId = NCSW_MASSTER_ID only. + FM interrupt source for errors */ + t_FmPcdFirmwareParams firmware; /**< Relevant when guestId = NCSW_MASSTER_ID only. + Ucode */ +} t_FmParams; + + +/**************************************************************************//** + @Function FM_Config + + @Description Creates descriptor for the FM module. + + The routine returns a handle (descriptor) to the FM object. + This descriptor must be passed as first parameter to all other + FM function calls. + + No actual initialization or configuration of FM hardware is + done by this routine. + + @Param[in] p_FmParams - A pointer to data structure of parameters + + @Return Handle to FM object, or NULL for Failure. +*//***************************************************************************/ +t_Handle FM_Config(t_FmParams *p_FmParams); + +/**************************************************************************//** + @Function FM_Init + + @Description Initializes the FM module + + @Param[in] h_Fm - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_Init(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_Free + + @Description Frees all resources that were assigned to FM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_Fm - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_Free(t_Handle h_Fm); + + +/**************************************************************************//** + @Group FM_advanced_init_grp FM Advanced Configuration Unit + + @Description Configuration functions used to change default values; + Note: Advanced init routines are not available for guest partition. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description DMA debug mode +*//***************************************************************************/ +typedef enum e_FmDmaDbgCntMode { + e_FM_DMA_DBG_NO_CNT = 0, /**< No counting */ + e_FM_DMA_DBG_CNT_DONE, /**< Count DONE commands */ + e_FM_DMA_DBG_CNT_COMM_Q_EM, /**< count command queue emergency signals */ + e_FM_DMA_DBG_CNT_INT_READ_EM, /**< Count Internal Read buffer emergency signal */ + e_FM_DMA_DBG_CNT_INT_WRITE_EM, /**< Count Internal Write buffer emergency signal */ + e_FM_DMA_DBG_CNT_FPM_WAIT, /**< Count FPM WAIT signal */ + e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC, /**< Single bit ECC errors. */ + e_FM_DMA_DBG_CNT_RAW_WAR_PROT /**< Number of times there was a need for RAW & WAR protection. */ +} e_FmDmaDbgCntMode; + +/**************************************************************************//** + @Description DMA Cache Override +*//***************************************************************************/ +typedef enum e_FmDmaCacheOverride { + e_FM_DMA_NO_CACHE_OR = 0, /**< No override of the Cache field */ + e_FM_DMA_NO_STASH_DATA, /**< Data should not be stashed in system level cache */ + e_FM_DMA_MAY_STASH_DATA, /**< Data may be stashed in system level cache */ + e_FM_DMA_STASH_DATA /**< Data should be stashed in system level cache */ +} e_FmDmaCacheOverride; + +/**************************************************************************//** + @Description DMA External Bus Priority +*//***************************************************************************/ +typedef enum e_FmDmaExtBusPri { + e_FM_DMA_EXT_BUS_NORMAL = 0, /**< Normal priority */ + e_FM_DMA_EXT_BUS_EBS, /**< AXI extended bus service priority */ + e_FM_DMA_EXT_BUS_SOS, /**< AXI sos priority */ + e_FM_DMA_EXT_BUS_EBS_AND_SOS /**< AXI ebs + sos priority */ +} e_FmDmaExtBusPri; + +/**************************************************************************//** + @Description enum for choosing the field that will be output on AID +*//***************************************************************************/ +typedef enum e_FmDmaAidMode { + e_FM_DMA_AID_OUT_PORT_ID = 0, /**< 4 LSB of PORT_ID */ + e_FM_DMA_AID_OUT_TNUM /**< 4 LSB of TNUM */ +} e_FmDmaAidMode; + +/**************************************************************************//** + @Description FPM Catasrophic error behaviour +*//***************************************************************************/ +typedef enum e_FmCatastrophicErr { + e_FM_CATASTROPHIC_ERR_STALL_PORT = 0, /**< Port_ID is stalled (only reset can release it) */ + e_FM_CATASTROPHIC_ERR_STALL_TASK /**< Only errornous task is stalled */ +} e_FmCatastrophicErr; + +/**************************************************************************//** + @Description FPM DMA error behaviour +*//***************************************************************************/ +typedef enum e_FmDmaErr { + e_FM_DMA_ERR_CATASTROPHIC = 0, /**< Dma error is treated as a catastrophic error */ + e_FM_DMA_ERR_REPORT /**< Dma error is just reported */ +} e_FmDmaErr; + +/**************************************************************************//** + @Description DMA Emergency level by BMI emergency signal +*//***************************************************************************/ +typedef enum e_FmDmaEmergencyLevel { + e_FM_DMA_EM_EBS = 0, /**< EBS emergency */ + e_FM_DMA_EM_SOS /**< SOS emergency */ +} e_FmDmaEmergencyLevel; + +/**************************************************************************//** + @Collection DMA emergency options +*//***************************************************************************/ +typedef uint32_t fmEmergencyBus_t; /**< DMA emergency options */ + +#define FM_DMA_MURAM_READ_EMERGENCY 0x00800000 /**< Enable emergency for MURAM1 */ +#define FM_DMA_MURAM_WRITE_EMERGENCY 0x00400000 /**< Enable emergency for MURAM2 */ +#define FM_DMA_EXT_BUS_EMERGENCY 0x00100000 /**< Enable emergency for external bus */ +/* @} */ + +/**************************************************************************//** + @Description A structure for defining DMA emergency level +*//***************************************************************************/ +typedef struct t_FmDmaEmergency { + fmEmergencyBus_t emergencyBusSelect; /**< An OR of the busses where emergency + should be enabled */ + e_FmDmaEmergencyLevel emergencyLevel; /**< EBS/SOS */ +} t_FmDmaEmergency; + +/**************************************************************************//** + @Description structure for defining FM threshold +*//***************************************************************************/ +typedef struct t_FmThresholds { + uint8_t dispLimit; /**< The number of times a frames may + be passed in the FM before assumed to + be looping. */ + uint8_t prsDispTh; /**< This is the number pf packets that may be + queued in the parser dispatch queue*/ + uint8_t plcrDispTh; /**< This is the number pf packets that may be + queued in the policer dispatch queue*/ + uint8_t kgDispTh; /**< This is the number pf packets that may be + queued in the keygen dispatch queue*/ + uint8_t bmiDispTh; /**< This is the number pf packets that may be + queued in the BMI dispatch queue*/ + uint8_t qmiEnqDispTh; /**< This is the number pf packets that may be + queued in the QMI enqueue dispatch queue*/ + uint8_t qmiDeqDispTh; /**< This is the number pf packets that may be + queued in the QMI dequeue dispatch queue*/ + uint8_t fmCtl1DispTh; /**< This is the number pf packets that may be + queued in fmCtl1 dispatch queue*/ + uint8_t fmCtl2DispTh; /**< This is the number pf packets that may be + queued in fmCtl2 dispatch queue*/ +} t_FmThresholds; + + +/**************************************************************************//** + @Description structure for defining DMA thresholds +*//***************************************************************************/ +typedef struct t_FmDmaThresholds { + uint8_t assertEmergency; /**< When this value is reached, + assert emergency (Threshold)*/ + uint8_t clearEmergency; /**< After emergency is asserted, it is held + until this value is reached (Hystheresis) */ +} t_FmDmaThresholds; + + +/**************************************************************************//** + @Function FM_ConfigResetOnInit + + @Description Tell the driver whether to reset the FM before initialization or + not. It changes the default configuration [FALSE]. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] enable When TRUE, FM will be reset before any initialization. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable); + +/**************************************************************************//** + @Function FM_ConfigTotalNumOfTasks + + @Description Change the total number of tasks from its default + configuration [BMI_MAX_NUM_OF_TASKS] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] totalNumOfTasks The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigTotalNumOfTasks(t_Handle h_Fm, uint8_t totalNumOfTasks); + +/**************************************************************************//** + @Function FM_ConfigTotalFifoSize + + @Description Change the total Fifo size from its default + configuration [BMI_MAX_FIFO_SIZE] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] totalFifoSize The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize); + +/**************************************************************************//** + @Function FM_ConfigMaxNumOfOpenDmas + + @Description Change the maximum allowed open DMA's for this FM from its default + configuration [BMI_MAX_NUM_OF_DMAS] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] maxNumOfOpenDmas The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigMaxNumOfOpenDmas(t_Handle h_Fm, uint8_t maxNumOfOpenDmas); + +/**************************************************************************//** + @Function FM_ConfigThresholds + + @Description Calling this routine changes the internal driver data base + from its default FM threshold configuration: + dispLimit: [0] + prsDispTh: [16] + plcrDispTh: [16] + kgDispTh: [16] + bmiDispTh: [16] + qmiEnqDispTh: [16] + qmiDeqDispTh: [16] + fmCtl1DispTh: [16] + fmCtl2DispTh: [16] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] p_FmThresholds A structure of threshold parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds); + + /**************************************************************************//** + @Function FM_ConfigDmaCacheOverride + + @Description Calling this routine changes the internal driver data base + from its default configuration of cache override mode [e_FM_DMA_NO_CACHE_OR] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] cacheOverride The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride); + +/**************************************************************************//** + @Function FM_ConfigDmaAidOverride + + @Description Calling this routine changes the internal driver data base + from its default configuration of aid override mode [TRUE] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] aidOverride The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride); + +/**************************************************************************//** + @Function FM_ConfigDmaAidMode + + @Description Calling this routine changes the internal driver data base + from its default configuration of aid mode [e_FM_DMA_AID_OUT_TNUM] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] aidMode The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode); + +/**************************************************************************//** + @Function FM_ConfigDmaAxiDbgNumOfBeats + + @Description Calling this routine changes the internal driver data base + from its default configuration of axi debug [1] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] axiDbgNumOfBeats The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats); + +/**************************************************************************//** + @Function FM_ConfigDmaCamNumOfEntries + + @Description Calling this routine changes the internal driver data base + from its default configuration of number of CAM entries [32] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] numOfEntries The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries); + +/**************************************************************************//** + @Function FM_ConfigDmaWatchdog + + @Description Calling this routine changes the internal driver data base + from its default watchdog configuration, which is disabled + [0]. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] watchDogValue The selected new value - in microseconds. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchDogValue); + +/**************************************************************************//** + @Function FM_ConfigDmaWriteBufThresholds + + @Description Calling this routine changes the internal driver data base + from its default configuration of DMA write buffer threshold + assertEmergency: [DMA_THRESH_MAX_BUF] + clearEmergency: [DMA_THRESH_MAX_BUF] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior - + When 'assertEmergency' value is reached, emergency is asserted, + then it is held until 'clearEmergency' value is reached. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds); + + /**************************************************************************//** + @Function FM_ConfigDmaCommQThresholds + + @Description Calling this routine changes the internal driver data base + from its default configuration of DMA command queue threshold + assertEmergency: [DMA_THRESH_MAX_COMMQ] + clearEmergency: [DMA_THRESH_MAX_COMMQ] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior - + When 'assertEmergency' value is reached, emergency is asserted, + then it is held until 'clearEmergency' value is reached.. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds); + +/**************************************************************************//** + @Function FM_ConfigDmaReadBufThresholds + + @Description Calling this routine changes the internal driver data base + from its default configuration of DMA read buffer threshold + assertEmergency: [DMA_THRESH_MAX_BUF] + clearEmergency: [DMA_THRESH_MAX_BUF] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior - + When 'assertEmergency' value is reached, emergency is asserted, + then it is held until 'clearEmergency' value is reached.. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds); + +/**************************************************************************//** + @Function FM_ConfigDmaSosEmergencyThreshold + + @Description Calling this routine changes the internal driver data base + from its default dma SOS emergency configuration [0] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] dmaSosEmergency The selected new value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency); + +/**************************************************************************//** + @Function FM_ConfigEnableCounters + + @Description Calling this routine changes the internal driver data base + from its default counters configuration where counters are disabled. + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigEnableCounters(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_ConfigDmaDbgCounter + + @Description Calling this routine changes the internal driver data base + from its default DMA debug counters configuration [e_FM_DMA_DBG_NO_CNT] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] fmDmaDbgCntMode An enum selecting the debug counter mode. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode); + +/**************************************************************************//** + @Function FM_ConfigDmaStopOnBusErr + + @Description Calling this routine changes the internal driver data base + from its default selection of bus error behavior [FALSE] + + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] stop TRUE to stop on bus error, FALSE to continue. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). + Only if bus error is enabled. +*//***************************************************************************/ +t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop); + +/**************************************************************************//** + @Function FM_ConfigDmaEmergency + + @Description Calling this routine changes the internal driver data base + from its default selection of DMA emergency where's it's disabled. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] p_Emergency An OR mask of all required options. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency); + +/**************************************************************************//** + @Function FM_ConfigDmaEmergencySmoother + + @Description sets the minimum amount of DATA beats transferred on the AXI + READ and WRITE ports before lowering the emergency level. + By default smother is disabled. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] emergencyCnt emergency switching counter. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt); + +/**************************************************************************//** + @Function FM_ConfigDmaErr + + @Description Calling this routine changes the internal driver data base + from its default DMA error treatment [e_FM_DMA_ERR_CATASTROPHIC] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] dmaErr The selected new choice. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr); + +/**************************************************************************//** + @Function FM_ConfigCatastrophicErr + + @Description Calling this routine changes the internal driver data base + from its default behavior on catastrophic error [e_FM_CATASTROPHIC_ERR_STALL_PORT] + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] catastrophicErr The selected new choice. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr); + +/**************************************************************************//** + @Function FM_ConfigEnableMuramTestMode + + @Description Calling this routine changes the internal driver data base + from its default selection of test mode where it's disabled. + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_ConfigEnableIramTestMode + + @Description Calling this routine changes the internal driver data base + from its default selection of test mode where it's disabled. + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_ConfigHaltOnExternalActivation + + @Description Calling this routine changes the internal driver data base + from its default selection of FM behaviour on external halt + activation [FALSE]. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] enable TRUE to enable halt on external halt + activation. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable); + +/**************************************************************************//** + @Function FM_ConfigHaltOnUnrecoverableEccError + + @Description Calling this routine changes the internal driver data base + from its default selection of FM behaviour on unrecoverable + Ecc error [FALSE]. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] enable TRUE to enable halt on unrecoverable Ecc error + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable); + +/**************************************************************************//** + @Function FM_ConfigException + + @Description Calling this routine changes the internal driver data base + from its default selection of exceptions enablement. + By default all exceptions are enabled. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] exception The exception to be selected. + @Param[in] enable TRUE to enable interrupt, FALSE to mask it. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable); + +/**************************************************************************//** + @Function FM_ConfigExternalEccRamsEnable + + @Description Calling this routine changes the internal driver data base + from its default [FALSE]. + When this option is enabled Rams ECC enable is not effected + by the FPM RCR bit, but by a JTAG. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] enable TRUE to enable this option. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable); + +/**************************************************************************//** + @Function FM_ConfigTnumAgingPeriod + + @Description Calling this routine changes the internal driver data base + from its default configuration for aging of dequeue TNUM's + in the QMI.[0] + Note that this functionality is not available in all chips. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] tnumAgingPeriod Tnum Aging Period in microseconds. + Note that period is recalculated in units of + 64 FM clocks. Driver will pick the closest + possible period. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod); + +/** @} */ /* end of FM_advanced_init_grp group */ +/** @} */ /* end of FM_init_grp group */ + + +/**************************************************************************//** + @Group FM_runtime_control_grp FM Runtime Control Unit + + @Description FM Runtime control unit API functions, definitions and enums. + The FM driver provides a set of control routines for each module. + These routines may only be called after the module was fully + initialized (both configuration and initialization routines were + called). They are typically used to get information from hardware + (status, counters/statistics, revision etc.), to modify a current + state or to force/enable a required action. Run-time control may + be called whenever necessary and as many times as needed. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection General FM defines. +*//***************************************************************************/ +#define FM_MAX_NUM_OF_VALID_PORTS (FM_MAX_NUM_OF_OH_PORTS + \ + FM_MAX_NUM_OF_1G_RX_PORTS + \ + FM_MAX_NUM_OF_10G_RX_PORTS + \ + FM_MAX_NUM_OF_1G_TX_PORTS + \ + FM_MAX_NUM_OF_10G_TX_PORTS) +/* @} */ + +/**************************************************************************//** + @Description Structure for Port bandwidth requirement. Port is identified + by type and relative id. +*//***************************************************************************/ +typedef struct t_FmPortBandwidth { + e_FmPortType type; /**< FM port type */ + uint8_t relativePortId; /**< Type relative port id */ + uint8_t bandwidth; /**< bandwidth - (in term of percents) */ +} t_FmPortBandwidth; + +/**************************************************************************//** + @Description A Structure containing an array of Port bandwidth requirements. + The user should state the ports requiring bandwidth in terms of + percentage - i.e. all port's bandwidths in the array must add + up to 100. +*//***************************************************************************/ +typedef struct t_FmPortsBandwidthParams { + uint8_t numOfPorts; /**< num of ports listed in the array below */ + t_FmPortBandwidth portsBandwidths[FM_MAX_NUM_OF_VALID_PORTS]; + /**< for each port, it's bandwidth (all port's + bandwidths must add up to 100.*/ +} t_FmPortsBandwidthParams; + +/**************************************************************************//** + @Description DMA Emergency control on MURAM +*//***************************************************************************/ +typedef enum e_FmDmaMuramPort { + e_FM_DMA_MURAM_PORT_WRITE, /**< MURAM write port */ + e_FM_DMA_MURAM_PORT_READ /**< MURAM read port */ +} e_FmDmaMuramPort; + +/**************************************************************************//** + @Description enum for defining FM counters +*//***************************************************************************/ +typedef enum e_FmCounters { + e_FM_COUNTERS_ENQ_TOTAL_FRAME = 0, /**< QMI total enqueued frames counter */ + e_FM_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI total dequeued frames counter */ + e_FM_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */ + e_FM_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */ + e_FM_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */ + e_FM_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */ + e_FM_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI dequeue from default queue counter */ + e_FM_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI dequeue from FQ context counter */ + e_FM_COUNTERS_DEQ_FROM_FD, /**< QMI dequeue from FD command field counter */ + e_FM_COUNTERS_DEQ_CONFIRM, /**< QMI dequeue confirm counter */ + e_FM_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT, /**< DMA semaphor reject due to full entry counter */ + e_FM_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT, /**< DMA semaphor reject due to full CAM queue counter */ + e_FM_COUNTERS_SEMAPHOR_SYNC_REJECT /**< DMA semaphor reject due to sync counter */ +} e_FmCounters; + +/**************************************************************************//** + @Description structure for returning revision information +*//***************************************************************************/ +typedef struct t_FmRevisionInfo { + uint8_t majorRev; /**< Major revision */ + uint8_t minorRev; /**< Minor revision */ +} t_FmRevisionInfo; + +/**************************************************************************//** + @Description struct for defining DMA status +*//***************************************************************************/ +typedef struct t_FmDmaStatus { + bool cmqNotEmpty; /**< Command queue is not empty */ + bool busError; /**< Bus error occurred */ + bool readBufEccError; /**< Double ECC error on buffer Read */ + bool writeBufEccSysError; /**< Double ECC error on buffer write from system side */ + bool writeBufEccFmError; /**< Double ECC error on buffer write from FM side */ +} t_FmDmaStatus; + + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/**************************************************************************//** + @Function FM_DumpRegs + + @Description Dumps all FM registers + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; + + @Cautions Allowed only FM_Init(). +*//***************************************************************************/ +t_Error FM_DumpRegs(t_Handle h_Fm); +#endif /* (defined(DEBUG_ERRORS) && ... */ + +/**************************************************************************//** + @Function FM_SetException + + @Description Calling this routine enables/disables the specified exception. + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] exception The exception to be selected. + @Param[in] enable TRUE to enable interrupt, FALSE to mask it. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable); + +/**************************************************************************//** + @Function FM_SetPortsBandwidth + + @Description Sets relative weights between ports when accessing common resources. + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] p_PortsBandwidth A structure of ports bandwidths in percentage, i.e. + total must equal 100. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth); + +/**************************************************************************//** + @Function FM_EnableRamsEcc + + @Description Enables ECC mechanism for all the different FM RAM's; E.g. IRAM, + MURAM, Parser, Keygen, Policer, etc. + Note: + If FM_ConfigExternalEccRamsEnable was called to enable external + setting of ECC, this routine effects IRAM ECC only. + This routine is also called by the driver if an ECC exception is + enabled. + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_EnableRamsEcc(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_DisableRamsEcc + + @Description Disables ECC mechanism for all the different FM RAM's; E.g. IRAM, + MURAM, Parser, Keygen, Policer, etc. + Note: + If FM_ConfigExternalEccRamsEnable was called to enable external + setting of ECC, this routine effects IRAM ECC only. + In opposed to FM_EnableRamsEcc, this routine must be called + explicitly to disable all Rams ECC. + Note: Not available for guest partition. + + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Config() and before FM_Init(). +*//***************************************************************************/ +t_Error FM_DisableRamsEcc(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_GetRevision + + @Description Returns the FM revision + + @Param[in] h_Fm A handle to an FM Module. + @Param[out] p_FmRevisionInfo A structure of revision information parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo); + +/**************************************************************************//** + @Function FM_GetCounter + + @Description Reads one of the FM counters. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] counter The requested counter. + + @Return Counter's current value. + + @Cautions Allowed only following FM_Init(). + Note that it is user's responsibility to call this routine only + for enabled counters, and there will be no indication if a + disabled counter is accessed. +*//***************************************************************************/ +uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter); + +/**************************************************************************//** + @Function FM_ModifyCounter + + @Description Sets a value to an enabled counter. Use "0" to reset the counter. + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] counter The requested counter. + @Param[in] val The requested value to be written into the counter. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val); + +/**************************************************************************//** + @Function FM_Resume + + @Description Release FM after halt FM command or after unrecoverable ECC error. + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +void FM_Resume(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_SetDmaEmergency + + @Description Manual emergency set + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] muramPort MURAM direction select. + @Param[in] enable TRUE to manually enable emergency, FALSE to disable. + + @Return None. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable); + +/**************************************************************************//** + @Function FM_SetDmaExtBusPri + + @Description Manual emergency set + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] pri External bus priority select + + @Return None. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri); + +/**************************************************************************//** + @Function FM_ForceIntr + + @Description Causes an interrupt event on the requested source. + Note: Not available for guest partition. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] exception An exception to be forced. + + @Return E_OK on success; Error code if the exception is not enabled, + or is not able to create interrupt. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception); + +/**************************************************************************//** + @Function FM_GetDmaStatus + + @Description Reads the DMA current status + + @Param[in] h_Fm A handle to an FM Module. + @Param[out] p_FmDmaStatus A structure of DMA status parameters. + + @Return None + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus); + +/**************************************************************************//** + @Function FM_GetPcdHandle + + @Description Used by FMC in order to get PCD handle + + @Param[in] h_Fm A handle to an FM Module. + + @Return A handle to the PCD module, NULL if uninitialized. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Handle FM_GetPcdHandle(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_ErrorIsr + Note: Not available for guest partition. + + @Description FM interrupt-service-routine for errors. + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; E_EMPTY if no errors found in register, other + error code otherwise. + + @Cautions Allowed only following FM_Init(). + This routine should NOT be called from guest-partition + (i.e. guestId != NCSW_MASTER_ID) +*//***************************************************************************/ +t_Error FM_ErrorIsr(t_Handle h_Fm); + +/**************************************************************************//** + @Function FM_EventIsr + Note: Not available for guest partition. + + @Description FM interrupt-service-routine for normal events. + + @Param[in] h_Fm A handle to an FM Module. + + @Cautions Allowed only following FM_Init(). + This routine should NOT be called from guest-partition + (i.e. guestId != NCSW_MASTER_ID) +*//***************************************************************************/ +void FM_EventIsr(t_Handle h_Fm); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/**************************************************************************//** + @Function FmDumpPortRegs + + @Description Dumps FM port registers which are part of FM common registers + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] hardwarePortId HW port id. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only FM_Init(). +*//***************************************************************************/ +t_Error FmDumpPortRegs(t_Handle h_Fm,uint8_t hardwarePortId); +#endif /* (defined(DEBUG_ERRORS) && ... */ + + +/** @} */ /* end of FM_runtime_control_grp group */ +/** @} */ /* end of FM_lib_grp group */ +/** @} */ /* end of FM_grp group */ + +#endif /* __FM_EXT */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_pcd_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_pcd_ext.h @@ -0,0 +1,2160 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_pcd_ext.h + + @Description FM PCD ... +*//***************************************************************************/ +#ifndef __FM_PCD_EXT +#define __FM_PCD_EXT + +#include "std_ext.h" +#include "net_ext.h" +#include "list_ext.h" +#include "fm_ext.h" + + +/**************************************************************************//** + + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_PCD_grp FM PCD + + @Description FM PCD API functions, definitions and enums + + The FM PCD module is responsible for the initialization of all + global classifying FM modules. This includes the parser general and + common registers, the key generator global and common registers, + and the Policer global and common registers. + In addition, the FM PCD SW module will initialize all required + key generator schemes, coarse classification flows, and Policer + profiles. When An FM module is configured to work with one of these + entities, it will register to it using the FM PORT API. The PCD + module will manage the PCD resources - i.e. resource management of + Keygen schemes, etc. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection General PCD defines +*//***************************************************************************/ +typedef uint32_t fmPcdEngines_t; /**< options as defined below: */ + +#define FM_PCD_NONE 0 /**< No PCD Engine indicated */ +#define FM_PCD_PRS 0x80000000 /**< Parser indicated */ +#define FM_PCD_KG 0x40000000 /**< Keygen indicated */ +#define FM_PCD_CC 0x20000000 /**< Coarse classification indicated */ +#define FM_PCD_PLCR 0x10000000 /**< Policer indicated */ +#define FM_PCD_MANIP 0x08000000 /**< Manipulation indicated */ + +#define FM_PCD_MAX_NUM_OF_PRIVATE_HDRS 2 /**< Number of units/headers saved for user */ + +#define FM_PCD_PRS_NUM_OF_HDRS 16 /**< Number of headers supported by HW parser */ +#define FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS (32 - FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) + /**< number of distinction units is limited by + register size (32), - reserved bits for + private headers. */ + +#define FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS 4 /**< Maximum number of interchangeable headers in a distinction unit */ +#define FM_PCD_KG_NUM_OF_GENERIC_REGS 8 /**< Total number of generic KG registers */ +#define FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY 35 /**< Max number allowed on any configuration. + For reason of HW implementation, in most + cases less than this will be allowed. The + driver will return error in initialization + time if resource is overused. */ +#define FM_PCD_KG_NUM_OF_EXTRACT_MASKS 4 /**< Total number of masks allowed on KG extractions. */ +#define FM_PCD_KG_NUM_OF_DEFAULT_GROUPS 16 /**< Number of default value logical groups */ + +#define FM_PCD_PRS_NUM_OF_LABELS 32 /**< Max number of SW parser label */ +#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of sw parser area */ +#define FM_PCD_PRS_SW_OFFSET 0x00000040 /**< Size of illegal addresses at the beginning + of the SW parser area */ +#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000200 /**< Number of bytes saved for patches */ +#define FM_PCD_PRS_SW_TAIL_SIZE 4 /**< Number of bytes that must be cleared at + the end of the SW parser area */ +#define FM_SW_PRS_MAX_IMAGE_SIZE (FM_PCD_SW_PRS_SIZE-FM_PCD_PRS_SW_OFFSET-FM_PCD_PRS_SW_TAIL_SIZE-FM_PCD_PRS_SW_PATCHES_SIZE) + /**< Max possible size of SW parser code */ + +#define FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE 128 /**< Max possible size of insertion template for + insert manipulation*/ +/* @} */ + + +/**************************************************************************//** + @Group FM_PCD_init_grp FM PCD Initialization Unit + + @Description FM PCD Initialization Unit + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description PCD counters +*//***************************************************************************/ +typedef enum e_FmPcdCounters { + e_FM_PCD_KG_COUNTERS_TOTAL, /**< Policer counter */ + e_FM_PCD_PLCR_COUNTERS_YELLOW, /**< Policer counter */ + e_FM_PCD_PLCR_COUNTERS_RED, /**< Policer counter */ + e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, /**< Policer counter */ + e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, /**< Policer counter */ + e_FM_PCD_PLCR_COUNTERS_TOTAL, /**< Policer counter */ + e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, /**< Policer counter */ + e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, /**< Parser counter */ + e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, /**< MURAM counter */ + e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, /**< MURAM counter */ + e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, /**< MURAM counter */ + e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, /**< MURAM counter */ + e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES /**< FPM counter */ +} e_FmPcdCounters; + +/**************************************************************************//** + @Description PCD interrupts +*//***************************************************************************/ +typedef enum e_FmPcdExceptions { + e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, /**< Keygen ECC error */ + e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, /**< Read Buffer ECC error */ + e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, /**< Write Buffer ECC error on system side */ + e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, /**< Write Buffer ECC error on FM side */ + e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, /**< Self init complete */ + e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, /**< Atomic action complete */ + e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, /**< Parser ECC error */ + e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC /**< Parser single ECC */ +} e_FmPcdExceptions; + + +/**************************************************************************//** + @Description Exceptions user callback routine, will be called upon an + exception passing the exception identification. + + @Param[in] h_App - User's application descriptor. + @Param[in] exception - The exception. + *//***************************************************************************/ +typedef void (t_FmPcdExceptionCallback) (t_Handle h_App, e_FmPcdExceptions exception); + +/**************************************************************************//** + @Description Exceptions user callback routine, will be called upon an exception + passing the exception identification. + + @Param[in] h_App - User's application descriptor. + @Param[in] exception - The exception. + @Param[in] index - id of the relevant source (may be scheme or profile id). + *//***************************************************************************/ +typedef void (t_FmPcdIdExceptionCallback) ( t_Handle h_App, + e_FmPcdExceptions exception, + uint16_t index); + +/**************************************************************************//** + @Description A callback for enqueuing frame onto a QM queue. + + @Param[in] h_App - User's application descriptor. + @Param[in] p_Fd - Frame descriptor for the frame. + + @Return E_OK on success; Error code otherwise. + *//***************************************************************************/ +typedef t_Error (t_FmPcdQmEnqueueCallback) (t_Handle h_QmArg, void *p_Fd); + +/**************************************************************************//** + @Description A structure for Host-Command + When using Host command for PCD functionalities, a dedicated port + must be used. If this routine is called for a PCD in a single partition + environment, or it is the Master partition in a Multi partition + environment, The port will be initialized by the PCD driver + initialization routine. + *//***************************************************************************/ +typedef struct t_FmPcdHcParams { + uintptr_t portBaseAddr; /**< Host-Command Port Virtual Address of + memory mapped registers.*/ + uint8_t portId; /**< Host-Command Port Id (0-6 relative + to Host-Command/Offline parsing ports) */ + uint16_t liodnBase; /**< Irrelevant for P4080 rev 1. LIODN base for this port, to be + used together with LIODN offset. */ + uint32_t errFqid; /**< Host-Command Port Error Queue Id. */ + uint32_t confFqid; /**< Host-Command Port Confirmation queue Id. */ + uint32_t qmChannel; /**< Host-Command port - QM-channel dedicated to + this port will be used by the FM for dequeue. */ + t_FmPcdQmEnqueueCallback *f_QmEnqueue; /**< Call back routine for enqueuing a frame to the QM */ + t_Handle h_QmArg; /**< A handle of the QM module */ +} t_FmPcdHcParams; + +/**************************************************************************//** + @Description The main structure for PCD initialization + *//***************************************************************************/ +typedef struct t_FmPcdParams { + bool prsSupport; /**< TRUE if Parser will be used for any + of the FM ports */ + bool ccSupport; /**< TRUE if Coarse Classification will be used for any + of the FM ports */ + bool kgSupport; /**< TRUE if Keygen will be used for any + of the FM ports */ + bool plcrSupport; /**< TRUE if Policer will be used for any + of the FM ports */ + t_Handle h_Fm; /**< A handle to the FM module */ + uint8_t numOfSchemes; /**< Number of schemes dedicated to this partition. */ + bool useHostCommand; /**< Optional for single partition, Mandatory for Multi partition */ + t_FmPcdHcParams hc; /**< Relevant only if useHostCommand=TRUE. + Host Command parameters. */ + + t_FmPcdExceptionCallback *f_Exception; /**< Relevant for master (or single) partition only: Callback routine + to be called of PCD exception */ + t_FmPcdIdExceptionCallback *f_ExceptionId; /**< Relevant for master (or single) partition only: Callback routine + to be used for a single scheme and + profile exceptions */ + t_Handle h_App; /**< Relevant for master (or single) partition only: A handle to an + application layer object; This handle will + be passed by the driver upon calling the above callbacks */ +} t_FmPcdParams; + + +/**************************************************************************//** + @Function FM_PCD_Config + + @Description Basic configuration of the PCD module. + Creates descriptor for the FM PCD module. + + @Param[in] p_FmPcdParams A structure of parameters for the initialization of PCD. + + @Return A handle to the initialized module. +*//***************************************************************************/ +t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams); + +/**************************************************************************//** + @Function FM_PCD_Init + + @Description Initialization of the PCD module. + + @Param[in] h_FmPcd - FM PCD module descriptor. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PCD_Init(t_Handle h_FmPcd); + +/**************************************************************************//** + @Function FM_PCD_Free + + @Description Frees all resources that were assigned to FM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmPcd - FM PCD module descriptor. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PCD_Free(t_Handle h_FmPcd); + +/**************************************************************************//** + @Group FM_PCD_advanced_init_grp FM PCD Advanced Configuration Unit + + @Description Configuration functions used to change default values. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function FM_PCD_ConfigPlcrNumOfSharedProfiles + + @Description Calling this routine changes the internal driver data base + from its default selection of exceptions enablement. + [4]. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] numOfSharedPlcrProfiles Number of profiles to + be shared between ports on this partition + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles); + +/**************************************************************************//** + @Function FM_PCD_ConfigException + + @Description Calling this routine changes the internal driver data base + from its default selection of exceptions enablement. + By default all exceptions are enabled. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] exception The exception to be selected. + @Param[in] enable TRUE to enable interrupt, FALSE to mask it. + + @Return E_OK on success; Error code otherwise. + + @Cautions Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable); + +/**************************************************************************//** + @Function FM_PCD_ConfigPlcrAutoRefreshMode + + @Description Calling this routine changes the internal driver data base + from its default selection of exceptions enablement. + By default autorefresh is enabled. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] enable TRUE to enable, FALSE to disable + + @Return E_OK on success; Error code otherwise. + + @Cautions Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable); + +/**************************************************************************//** + @Function FM_PCD_ConfigPrsMaxCycleLimit + + @Description Calling this routine changes the internal data structure for + the maximum parsing time from its default value + [0]. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] value 0 to disable the mechanism, or new + maximum parsing time. + + @Return E_OK on success; Error code otherwise. + + @Cautions Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value); + +/** @} */ /* end of FM_PCD_advanced_init_grp group */ +/** @} */ /* end of FM_PCD_init_grp group */ + + +/**************************************************************************//** + @Group FM_PCD_Runtime_grp FM PCD Runtime Unit + + @Description FM PCD Runtime Unit + + The runtime control allows creation of PCD infrastructure modules + such as Network Environment Characteristics, Classification Plan + Groups and Coarse Classification Trees. + It also allows on-the-fly initialization, modification and removal + of PCD modules such as Keygen schemes, coarse classification nodes + and Policer profiles. + + + In order to explain the programming model of the PCD driver interface + a few terms should be explained, and will be used below. + * Distinction Header - One of the 16 protocols supported by the FM parser, + or one of the shim headers (1 or 2). May be a header with a special + option (see below). + * Interchangeable Headers Group- This is a group of Headers recognized + by either one of them. For example, if in a specific context the user + chooses to treat IPv4 and IPV6 in the same way, they may create an + interchangeable Headers Unit consisting of these 2 headers. + * A Distinction Unit - a Distinction Header or an Interchangeable Headers + Group. + * Header with special option - applies to ethernet, mpls, vlan, ipv4 and + ipv6, includes multicast, broadcast and other protocol specific options. + In terms of hardware it relates to the options available in the classification + plan. + * Network Environment Characteristics - a set of Distinction Units that define + the total recognizable header selection for a certain environment. This is + NOT the list of all headers that will ever appear in a flow, but rather + everything that needs distinction in a flow, where distinction is made by keygen + schemes and coarse classification action descriptors. + + The PCD runtime modules initialization is done in stages. The first stage after + initializing the PCD module itself is to establish a Network Flows Environment + Definition. The application may choose to establish one or more such environments. + Later, when needed, the application will have to state, for some of its modules, + to which single environment it belongs. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description A structure for sw parser labels + *//***************************************************************************/ +typedef struct t_FmPcdPrsLabelParams { + uint32_t instructionOffset; /**< SW parser label instruction offset (2 bytes + resolution), relative to Parser RAM. */ + e_NetHeaderType hdr; /**< The existance of this header will envoke + the sw parser code. */ + uint8_t indexPerHdr; /**< Normally 0, if more than one sw parser + attachments for the same header, use this + index to distinguish between them. */ +} t_FmPcdPrsLabelParams; + +/**************************************************************************//** + @Description A structure for sw parser + *//***************************************************************************/ +typedef struct t_FmPcdPrsSwParams { + bool override; /**< FALSE to invoke a check that nothing else + was loaded to this address, including + internal patches. + TRUE to override any existing code.*/ + uint32_t size; /**< SW parser code size */ + uint16_t base; /**< SW parser base (in instruction counts! + must be larger than 0x20)*/ + uint8_t *p_Code; /**< SW parser code */ + uint32_t swPrsDataParams[FM_PCD_PRS_NUM_OF_HDRS]; + /**< SW parser data (parameters) */ + uint8_t numOfLabels; /**< Number of labels for SW parser. */ + t_FmPcdPrsLabelParams labelsTable[FM_PCD_PRS_NUM_OF_LABELS]; + /**< SW parser labels table, containing + numOfLabels entries */ +} t_FmPcdPrsSwParams; + + +/**************************************************************************//** + @Function FM_PCD_Enable + + @Description This routine should be called after PCD is initialized for enabling all + PCD engines according to their existing configuration. + + @Param[in] h_FmPcd FM PCD module descriptor. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. +*//***************************************************************************/ +t_Error FM_PCD_Enable(t_Handle h_FmPcd); + +/**************************************************************************//** + @Function FM_PCD_Disable + + @Description This routine may be called when PCD is enabled in order to + disable all PCD engines. It may be called + only when none of the ports in the system are using the PCD. + + @Param[in] h_FmPcd FM PCD module descriptor. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init() and when PCD is enabled. +*//***************************************************************************/ +t_Error FM_PCD_Disable(t_Handle h_FmPcd); + + +/**************************************************************************//** + @Function FM_PCD_GetCounter + + @Description Reads one of the FM PCD counters. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] counter The requested counter. + + @Return Counter's current value. + + @Cautions Allowed only following FM_PCD_Init(). + Note that it is user's responsibility to call this routine only + for enabled counters, and there will be no indication if a + disabled counter is accessed. +*//***************************************************************************/ +uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter); + +/**************************************************************************//** +@Function FM_PCD_PrsLoadSw + +@Description This routine may be called in order to load software parsing code. + + +@Param[in] h_FmPcd FM PCD module descriptor. +@Param[in] p_SwPrs A pointer to a structure of software + parser parameters, including the software + parser image. + +@Return E_OK on success; Error code otherwise. + +@Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. + Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs); + +/**************************************************************************//** + @Function FM_PCD_KgSetDfltValue + + @Description Calling this routine sets a global default value to be used + by the keygen when parser does not recognize a required + field/header. + By default default values are 0. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] valueId 0,1 - one of 2 global default values. + @Param[in] value The requested default value. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. + Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value); + +/**************************************************************************//** + @Function FM_PCD_KgSetAdditionalDataAfterParsing + + @Description Calling this routine allows the keygen to access data past + the parser finishing point. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] payloadOffset the number of bytes beyond the parser location. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. + Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset); + +/**************************************************************************//** + @Function FM_PCD_SetException + + @Description Calling this routine enables/disables PCD interrupts. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] exception The exception to be selected. + @Param[in] enable TRUE to enable interrupt, FALSE to mask it. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). + Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable); + +/**************************************************************************//** + @Function FM_PCD_ModifyCounter + + @Description Sets a value to an enabled counter. Use "0" to reset the counter. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] counter The requested counter. + @Param[in] value The requested value to be written into the counter. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). + Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value); + +/**************************************************************************//** + @Function FM_PCD_SetPlcrStatistics + + @Description This routine may be used to enable/disable policer statistics + counter. By default the statistics is enabled. + + @Param[in] h_FmPcd FM PCD module descriptor + @Param[in] enable TRUE to enable, FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). + Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable); + +/**************************************************************************//** + @Function FM_PCD_SetPrsStatistics + + @Description Defines whether to gather parser statistics including all ports. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] enable TRUE to enable, FALSE to disable. + + @Return None + + @Cautions Allowed only following FM_PCD_Init(). + Not available for guest partition. +*//***************************************************************************/ +void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable); + +/**************************************************************************//** + @Function FM_PCD_ForceIntr + + @Description Causes an interrupt event on the requested source. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] exception An exception to be forced. + + @Return E_OK on success; Error code if the exception is not enabled, + or is not able to create interrupt. + + @Cautions Allowed only following FM_PCD_Init(). + Not available for guest partition. +*//***************************************************************************/ +t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception); + +/**************************************************************************//** + @Function FM_PCD_HcTxConf + + @Description This routine should be called to confirm frames that were + received on the HC confirmation queue. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] p_Fd Frame descriptor of the received frame. + + @Cautions Allowed only following FM_PCD_Init(). Allowed only if 'useHostCommand' + option was selected in the initialization. +*//***************************************************************************/ +void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/**************************************************************************//** + @Function FM_PCD_DumpRegs + + @Description Dumps all PCD registers + + @Param[in] h_FmPcd A handle to an FM PCD Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_DumpRegs(t_Handle h_FmPcd); + +/**************************************************************************//** + @Function FM_PCD_KgDumpRegs + + @Description Dumps all PCD KG registers + + @Param[in] h_FmPcd A handle to an FM PCD Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_KgDumpRegs(t_Handle h_FmPcd); + +/**************************************************************************//** + @Function FM_PCD_PlcrDumpRegs + + @Description Dumps all PCD Plcr registers + + @Param[in] h_FmPcd A handle to an FM PCD Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_PlcrDumpRegs(t_Handle h_FmPcd); + +/**************************************************************************//** + @Function FM_PCD_PlcrProfileDumpRegs + + @Description Dumps all PCD Plcr registers + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_Profile A handle to a profile. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_PlcrProfileDumpRegs(t_Handle h_FmPcd, t_Handle h_Profile); + +/**************************************************************************//** + @Function FM_PCD_PrsDumpRegs + + @Description Dumps all PCD Prs registers + + @Param[in] h_FmPcd A handle to an FM PCD Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_PrsDumpRegs(t_Handle h_FmPcd); + +/**************************************************************************//** + @Function FM_PCD_HcDumpRegs + + @Description Dumps HC Port registers + + @Param[in] h_FmPcd A handle to an FM PCD Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_HcDumpRegs(t_Handle h_FmPcd); +#endif /* (defined(DEBUG_ERRORS) && ... */ + + + +/**************************************************************************//** + @Group FM_PCD_Runtime_tree_buildgrp FM PCD Tree building Unit + + @Description FM PCD Runtime Unit + + This group contains routines for setting, deleting and modifying + PCD resources, for defining the total PCD tree. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection Definitions of coarse classification + parameters as required by keygen (when coarse classification + is the next engine after this scheme). +*//***************************************************************************/ +#define FM_PCD_MAX_NUM_OF_CC_NODES 255 +#define FM_PCD_MAX_NUM_OF_CC_TREES 8 +#define FM_PCD_MAX_NUM_OF_CC_GROUPS 16 +#define FM_PCD_MAX_NUM_OF_CC_UNITS 4 +#define FM_PCD_MAX_NUM_OF_KEYS 256 +#define FM_PCD_MAX_SIZE_OF_KEY 56 +#define FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP 16 +/* @} */ + +/**************************************************************************//** + @Collection A set of definitions to allow protocol + special option description. +*//***************************************************************************/ +typedef uint32_t protocolOpt_t; /**< A general type to define a protocol option. */ + +typedef protocolOpt_t ethProtocolOpt_t; /**< Ethernet protocol options. */ +#define ETH_BROADCAST 0x80000000 /**< Ethernet Broadcast. */ +#define ETH_MULTICAST 0x40000000 /**< Ethernet Multicast. */ + +typedef protocolOpt_t vlanProtocolOpt_t; /**< Vlan protocol options. */ +#define VLAN_STACKED 0x20000000 /**< Vlan Stacked. */ + +typedef protocolOpt_t mplsProtocolOpt_t; /**< MPLS protocol options. */ +#define MPLS_STACKED 0x10000000 /**< MPLS Stacked. */ + +typedef protocolOpt_t ipv4ProtocolOpt_t; /**< IPv4 protocol options. */ +#define IPV4_BROADCAST_1 0x08000000 /**< IPv4 Broadcast. */ +#define IPV4_MULTICAST_1 0x04000000 /**< IPv4 Multicast. */ +#define IPV4_UNICAST_2 0x02000000 /**< Tunneled IPv4 - Unicast. */ +#define IPV4_MULTICAST_BROADCAST_2 0x01000000 /**< Tunneled IPv4 - Broadcast/Multicast. */ + +typedef protocolOpt_t ipv6ProtocolOpt_t; /**< IPv6 protocol options. */ +#define IPV6_MULTICAST_1 0x00800000 /**< IPv6 Multicast. */ +#define IPV6_UNICAST_2 0x00400000 /**< Tunneled IPv6 - Unicast. */ +#define IPV6_MULTICAST_2 0x00200000 /**< Tunneled IPv6 - Multicast. */ +/* @} */ + +/**************************************************************************//** + @Description A type used for returning the order of the key extraction. + each value in this array represents the index of the extraction + command as defined by the user in the initialization extraction array. + The valid size of this array is the user define number of extractions + required (also marked by the second '0' in this array). +*//***************************************************************************/ +typedef uint8_t t_FmPcdKgKeyOrder [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; + +/**************************************************************************//** + @Description All PCD engines +*//***************************************************************************/ +typedef enum e_FmPcdEngine { + e_FM_PCD_INVALID = 0, /**< Invalid PCD engine indicated*/ + e_FM_PCD_DONE, /**< No PCD Engine indicated */ + e_FM_PCD_KG, /**< Keygen indicated */ + e_FM_PCD_CC, /**< Coarse classification indicated */ + e_FM_PCD_PLCR, /**< Policer indicated */ + e_FM_PCD_PRS /**< Parser indicated */ +} e_FmPcdEngine; + +/**************************************************************************//** + @Description An enum for selecting extraction by header types +*//***************************************************************************/ +typedef enum e_FmPcdExtractByHdrType { + e_FM_PCD_EXTRACT_FROM_HDR, /**< Extract bytes from header */ + e_FM_PCD_EXTRACT_FROM_FIELD, /**< Extract bytes from header field */ + e_FM_PCD_EXTRACT_FULL_FIELD /**< Extract a full field */ +} e_FmPcdExtractByHdrType; + +/**************************************************************************//** + @Description An enum for selecting extraction source + (when it is not the header) +*//***************************************************************************/ +typedef enum e_FmPcdExtractFrom { + e_FM_PCD_EXTRACT_FROM_FRAME_START, /**< KG & CC: Extract from beginning of frame */ + e_FM_PCD_EXTRACT_FROM_DFLT_VALUE, /**< KG only: Extract from a default value */ + e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE, /**< KG only: Extract from the point where parsing had finished */ + e_FM_PCD_EXTRACT_FROM_KEY, /**< CC only: Field where saved KEY */ + e_FM_PCD_EXTRACT_FROM_HASH, /**< CC only: Field where saved HASH */ + e_FM_PCD_EXTRACT_FROM_PARSE_RESULT, /**< KG & CC: Extract from the parser result */ + e_FM_PCD_EXTRACT_FROM_ENQ_FQID, /**< KG & CC: Extract from enqueue FQID */ + e_FM_PCD_EXTRACT_FROM_FLOW_ID /**< CC only: Field where saved Dequeue FQID */ +} e_FmPcdExtractFrom; + +/**************************************************************************//** + @Description An enum for selecting extraction type +*//***************************************************************************/ +typedef enum e_FmPcdExtractType { + e_FM_PCD_EXTRACT_BY_HDR, /**< Extract according to header */ + e_FM_PCD_EXTRACT_NON_HDR, /**< Extract from data that is not the header */ + e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO /**< Extract private info as specified by user */ +} e_FmPcdExtractType; + +/**************************************************************************//** + @Description An enum for selecting a default +*//***************************************************************************/ +typedef enum e_FmPcdKgExtractDfltSelect { + e_FM_PCD_KG_DFLT_GBL_0, /**< Default selection is KG register 0 */ + e_FM_PCD_KG_DFLT_GBL_1, /**< Default selection is KG register 1 */ + e_FM_PCD_KG_DFLT_PRIVATE_0, /**< Default selection is a per scheme register 0 */ + e_FM_PCD_KG_DFLT_PRIVATE_1, /**< Default selection is a per scheme register 1 */ + e_FM_PCD_KG_DFLT_ILLEGAL /**< Illegal selection */ +} e_FmPcdKgExtractDfltSelect; + +/**************************************************************************//** + @Description An enum defining all default groups - + each group shares a default value, one of 4 user + initialized values. +*//***************************************************************************/ +typedef enum e_FmPcdKgKnownFieldsDfltTypes { + e_FM_PCD_KG_MAC_ADDR, /**< MAC Address */ + e_FM_PCD_KG_TCI, /**< TCI field */ + e_FM_PCD_KG_ENET_TYPE, /**< ENET Type */ + e_FM_PCD_KG_PPP_SESSION_ID, /**< PPP Session id */ + e_FM_PCD_KG_PPP_PROTOCOL_ID, /**< PPP Protocol id */ + e_FM_PCD_KG_MPLS_LABEL, /**< MPLS label */ + e_FM_PCD_KG_IP_ADDR, /**< IP addr */ + e_FM_PCD_KG_PROTOCOL_TYPE, /**< Protocol type */ + e_FM_PCD_KG_IP_TOS_TC, /**< TOS or TC */ + e_FM_PCD_KG_IPV6_FLOW_LABEL, /**< IPV6 flow label */ + e_FM_PCD_KG_IPSEC_SPI, /**< IPSEC SPI */ + e_FM_PCD_KG_L4_PORT, /**< L4 Port */ + e_FM_PCD_KG_TCP_FLAG, /**< TCP Flag */ + e_FM_PCD_KG_GENERIC_FROM_DATA, /**< grouping implemented by sw, + any data extraction that is not the full + field described above */ + e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V, /**< grouping implemented by sw, + any data extraction without validation */ + e_FM_PCD_KG_GENERIC_NOT_FROM_DATA /**< grouping implemented by sw, + extraction from parser result or + direct use of default value */ +} e_FmPcdKgKnownFieldsDfltTypes; + +/**************************************************************************//** + @Description enum for defining header index when headers may repeat +*//***************************************************************************/ +typedef enum e_FmPcdHdrIndex { + e_FM_PCD_HDR_INDEX_NONE = 0, /**< used when multiple headers not used, also + to specify regular IP (not tunneled). */ + e_FM_PCD_HDR_INDEX_1, /**< may be used for VLAN, MPLS, tunneled IP */ + e_FM_PCD_HDR_INDEX_2, /**< may be used for MPLS, tunneled IP */ + e_FM_PCD_HDR_INDEX_3, /**< may be used for MPLS */ + e_FM_PCD_HDR_INDEX_LAST = 0xFF /**< may be used for VLAN, MPLS */ +} e_FmPcdHdrIndex; + +/**************************************************************************//** + @Description A structure for selcting the policer profile functional type +*//***************************************************************************/ +typedef enum e_FmPcdProfileTypeSelection { + e_FM_PCD_PLCR_PORT_PRIVATE, /**< Port dedicated profile */ + e_FM_PCD_PLCR_SHARED /**< Shared profile (shared within partition) */ +} e_FmPcdProfileTypeSelection; + +/**************************************************************************//** + @Description A structure for selcting the policer profile algorithem +*//***************************************************************************/ +typedef enum e_FmPcdPlcrAlgorithmSelection { + e_FM_PCD_PLCR_PASS_THROUGH, /**< Policer pass through */ + e_FM_PCD_PLCR_RFC_2698, /**< Policer algorythm RFC 2698 */ + e_FM_PCD_PLCR_RFC_4115 /**< Policer algorythm RFC 4115 */ +} e_FmPcdPlcrAlgorithmSelection; + +/**************************************************************************//** + @Description A structure for selcting the policer profile color mode +*//***************************************************************************/ +typedef enum e_FmPcdPlcrColorMode { + e_FM_PCD_PLCR_COLOR_BLIND, /**< Color blind */ + e_FM_PCD_PLCR_COLOR_AWARE /**< Color aware */ +} e_FmPcdPlcrColorMode; + +/**************************************************************************//** + @Description A structure for selcting the policer profile color functional mode +*//***************************************************************************/ +typedef enum e_FmPcdPlcrColor { + e_FM_PCD_PLCR_GREEN, /**< Green */ + e_FM_PCD_PLCR_YELLOW, /**< Yellow */ + e_FM_PCD_PLCR_RED, /**< Red */ + e_FM_PCD_PLCR_OVERRIDE /**< Color override */ +} e_FmPcdPlcrColor; + +/**************************************************************************//** + @Description A structure for selcting the policer profile packet frame length selector +*//***************************************************************************/ +typedef enum e_FmPcdPlcrFrameLengthSelect { + e_FM_PCD_PLCR_L2_FRM_LEN, /**< L2 frame length */ + e_FM_PCD_PLCR_L3_FRM_LEN, /**< L3 frame length */ + e_FM_PCD_PLCR_L4_FRM_LEN, /**< L4 frame length */ + e_FM_PCD_PLCR_FULL_FRM_LEN /**< Full frame length */ +} e_FmPcdPlcrFrameLengthSelect; + +/**************************************************************************//** + @Description An enum for selecting rollback frame +*//***************************************************************************/ +typedef enum e_FmPcdPlcrRollBackFrameSelect { + e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN, /**< Rollback L2 frame length */ + e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN /**< Rollback Full frame length */ +} e_FmPcdPlcrRollBackFrameSelect; + +/**************************************************************************//** + @Description A structure for selcting the policer profile packet or byte mode +*//***************************************************************************/ +typedef enum e_FmPcdPlcrRateMode { + e_FM_PCD_PLCR_BYTE_MODE, /**< Byte mode */ + e_FM_PCD_PLCR_PACKET_MODE /**< Packet mode */ +} e_FmPcdPlcrRateMode; + +/**************************************************************************//** + @Description An enum for defining action of frame +*//***************************************************************************/ +typedef enum e_FmPcdDoneAction { + e_FM_PCD_ENQ_FRAME = 0, /**< Enqueue frame */ + e_FM_PCD_DROP_FRAME /**< Drop frame */ +} e_FmPcdDoneAction; + +/**************************************************************************//** + @Description A structure for selecting the policer counter +*//***************************************************************************/ +typedef enum e_FmPcdPlcrProfileCounters { + e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER, /**< Green packets counter */ + e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER, /**< Yellow packets counter */ + e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER, /**< Red packets counter */ + e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER, /**< Recolored yellow packets counter */ + e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER /**< Recolored red packets counter */ +} e_FmPcdPlcrProfileCounters; + +/**************************************************************************//** + @Description A structure for selecting action +*//***************************************************************************/ +typedef enum e_FmPcdAction { + e_FM_PCD_ACTION_NONE, /**< NONE */ + e_FM_PCD_ACTION_EXACT_MATCH, /**< Exact match on the selected extraction*/ + e_FM_PCD_ACTION_INDEXED_LOOKUP /**< Indexed lookup on the selected extraction*/ +} e_FmPcdAction; + +#if defined(FM_CAPWAP_SUPPORT) +/**************************************************************************//** + @Description An enum for selecting type of insert manipulation +*//***************************************************************************/ +typedef enum e_FmPcdManipInsrtType { + e_FM_PCD_MANIP_INSRT_NONE = 0, /**< No insertion */ + e_FM_PCD_MANIP_INSRT_TO_START_OF_FRAME_INT_FRAME_HDR, /**< Insert internal frame header to start of frame */ + e_FM_PCD_MANIP_INSRT_TO_START_OF_FRAME_TEMPLATE /**< Insert template to start of frame*/ +} e_FmPcdManipInsrtType; + +/**************************************************************************//** + @Description An enum for selecting type of remove manipulation +*//***************************************************************************/ +typedef enum e_FmPcdManipRmvParamsType { + e_FM_PCD_MANIP_RMV_NONE = 0, /**< No remove */ + e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_TILL_SPECIFIC_LOCATION, /**< Remove from start of frame till (excluding) specified indication */ + e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_INCLUDE_SPECIFIC_LOCATION, /**< Remove from start of frame till (including) specified indication */ + e_FM_PCD_MANIP_RMV_INT_FRAME_HDR /**< Remove internal frame header to start of frame */ +} e_FmPcdManipRmvParamsType; + +/**************************************************************************//** + @Description An enum for selecting type of location +*//***************************************************************************/ +typedef enum e_FmPcdManipLocateType { + e_FM_PCD_MANIP_LOC_BY_HDR = 0, /**< Locate according to header */ + e_FM_PCD_MANIP_LOC_NON_HDR /**< Locate from data that is not the header */ +} e_FmPcdManipLocateType; + +/**************************************************************************//** + @Description An enum for selecting type of Timeout mode +*//***************************************************************************/ +typedef enum e_FmPcdManipReassemTimeOutMode { + e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES, /**< limits the time of the reassm process from the first frag to the last */ + e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG /**< limits the time of receiving the fragment */ +} e_FmPcdManipReassemTimeOutMode; + +/**************************************************************************//** + @Description An enum for selecting type of WaysNumber mode +*//***************************************************************************/ +typedef enum e_FmPcdManipReassemWaysNumber { + e_FM_PCD_MANIP_ONE_WAY_HASH = 1, /**< -------------- */ + e_FM_PCD_MANIP_TWO_WAYS_HASH, /**< -------------- */ + e_FM_PCD_MANIP_THREE_WAYS_HASH, /**< -------------- */ + e_FM_PCD_MANIP_FOUR_WAYS_HASH, /**< four ways hash */ + e_FM_PCD_MANIP_FIVE_WAYS_HASH, /**< -------------- */ + e_FM_PCD_MANIP_SIX_WAYS_HASH, /**< -------------- */ + e_FM_PCD_MANIP_SEVEN_WAYS_HASH, /**< -------------- */ + e_FM_PCD_MANIP_EIGHT_WAYS_HASH /**< eight ways hash*/ +} e_FmPcdManipReassemWaysNumber; + +/**************************************************************************//** + @Description An enum for selecting type of statistics mode +*//***************************************************************************/ +typedef enum e_FmPcdStatsType { + e_FM_PCD_STATS_PER_FLOWID = 0 /**< type where flowId used as index for getting statistics */ +} e_FmPcdStatsType; + +#endif /* FM_CAPWAP_SUPPORT */ + + +/**************************************************************************//** + @Description A Union of protocol dependent special options +*//***************************************************************************/ +typedef union u_FmPcdHdrProtocolOpt { + ethProtocolOpt_t ethOpt; /**< Ethernet options */ + vlanProtocolOpt_t vlanOpt; /**< Vlan options */ + mplsProtocolOpt_t mplsOpt; /**< MPLS options */ + ipv4ProtocolOpt_t ipv4Opt; /**< IPv4 options */ + ipv6ProtocolOpt_t ipv6Opt; /**< IPv6 options */ +} u_FmPcdHdrProtocolOpt; + +/**************************************************************************//** + @Description A union holding all known protocol fields +*//***************************************************************************/ +typedef union t_FmPcdFields { + headerFieldEth_t eth; /**< eth */ + headerFieldVlan_t vlan; /**< vlan */ + headerFieldLlcSnap_t llcSnap; /**< llcSnap */ + headerFieldPppoe_t pppoe; /**< pppoe */ + headerFieldMpls_t mpls; /**< mpls */ + headerFieldIpv4_t ipv4; /**< ipv4 */ + headerFieldIpv6_t ipv6; /**< ipv6 */ + headerFieldUdp_t udp; /**< udp */ + headerFieldTcp_t tcp; /**< tcp */ + headerFieldSctp_t sctp; /**< sctp */ + headerFieldDccp_t dccp; /**< dccp */ + headerFieldGre_t gre; /**< gre */ + headerFieldMinencap_t minencap; /**< minencap */ + headerFieldIpsecAh_t ipsecAh; /**< ipsecAh */ + headerFieldIpsecEsp_t ipsecEsp; /**< ipsecEsp */ + headerFieldUdpEncapEsp_t udpEncapEsp; /**< udpEncapEsp */ +} t_FmPcdFields; + +/**************************************************************************//** + @Description structure for defining header extraction for key generation +*//***************************************************************************/ +typedef struct t_FmPcdFromHdr { + uint8_t size; /**< Size in byte */ + uint8_t offset; /**< Byte offset */ +} t_FmPcdFromHdr; + +/**************************************************************************//** + @Description structure for defining field extraction for key generation +*//***************************************************************************/ +typedef struct t_FmPcdFromField { + t_FmPcdFields field; /**< Field selection */ + uint8_t size; /**< Size in byte */ + uint8_t offset; /**< Byte offset */ +} t_FmPcdFromField; + +/**************************************************************************//** + @Description A structure of parameters used to define a single network + environment unit. + A unit should be defined if it will later be used by one or + more PCD engines to distinguich between flows. +*//***************************************************************************/ +typedef struct t_FmPcdDistinctionUnit { + struct { + e_NetHeaderType hdr; /**< One of the headers supported by the FM */ + u_FmPcdHdrProtocolOpt opt; /**< only one option !! */ + } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS]; +} t_FmPcdDistinctionUnit; + +/**************************************************************************//** + @Description A structure of parameters used to define the different + units supported by a specific PCD Network Environment + Characteristics module. Each unit represent + a protocol or a group of protocols that may be used later + by the different PCD engined to distinguich between flows. +*//***************************************************************************/ +typedef struct t_FmPcdNetEnvParams { + uint8_t numOfDistinctionUnits; /**< Number of different units to be identified */ + t_FmPcdDistinctionUnit units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /**< An array of numOfDistinctionUnits of the + different units to be identified */ +} t_FmPcdNetEnvParams; + +/**************************************************************************//** + @Description structure for defining a single extraction action + when creating a key +*//***************************************************************************/ +typedef struct t_FmPcdExtractEntry { + e_FmPcdExtractType type; /**< Extraction type select */ + union { + struct { + e_NetHeaderType hdr; /**< Header selection */ + bool ignoreProtocolValidation; + /**< Ignore protocol validation */ + e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled + IP. Otherwise should be cleared.*/ + e_FmPcdExtractByHdrType type; /**< Header extraction type select */ + union { + t_FmPcdFromHdr fromHdr; /**< Extract bytes from header parameters */ + t_FmPcdFromField fromField; /**< Extract bytes from field parameters*/ + t_FmPcdFields fullField; /**< Extract full filed parameters*/ + } extractByHdrType; + } extractByHdr; /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */ + struct { + e_FmPcdExtractFrom src; /**< Non-header extraction source */ + e_FmPcdAction action; /**< Relevant for CC Only */ + uint16_t icIndxMask; /**< Relevant only for CC where + action=e_FM_PCD_ACTION_INDEXED_LOOKUP */ + uint8_t offset; /**< Byte offset */ + uint8_t size; /**< Size in byte */ + } extractNonHdr; /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */ + }; +} t_FmPcdExtractEntry; + +/**************************************************************************//** + @Description A structure for defining masks for each extracted + field in the key. +*//***************************************************************************/ +typedef struct t_FmPcdKgExtractMask { + uint8_t extractArrayIndex; /**< Index in the extraction array, as initialized by user */ + uint8_t offset; /**< Byte offset */ + uint8_t mask; /**< A byte mask (selected bits will be used) */ +} t_FmPcdKgExtractMask; + +/**************************************************************************//** + @Description A structure for defining default selection per groups + of fields +*//***************************************************************************/ +typedef struct t_FmPcdKgExtractDflt { + e_FmPcdKgKnownFieldsDfltTypes type; /**< Default type select*/ + e_FmPcdKgExtractDfltSelect dfltSelect; /**< Default register select */ +} t_FmPcdKgExtractDflt; + +/**************************************************************************//** + @Description A structure for defining all parameters needed for + generation a key and using a hash function +*//***************************************************************************/ +typedef struct t_FmPcdKgKeyExtractAndHashParams { + uint32_t privateDflt0; /**< Scheme default register 0 */ + uint32_t privateDflt1; /**< Scheme default register 1 */ + uint8_t numOfUsedExtracts; /**< defines the valid size of the following array */ + t_FmPcdExtractEntry extractArray [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; /**< An array of extractions definition. */ + uint8_t numOfUsedDflts; /**< defines the valid size of the following array */ + t_FmPcdKgExtractDflt dflts[FM_PCD_KG_NUM_OF_DEFAULT_GROUPS]; + /**< For each extraction used in this scheme, specify the required + default register to be used when header is not found. + types not specified in this array will get undefined value. */ + uint8_t numOfUsedMasks; /**< defines the valid size of the following array */ + t_FmPcdKgExtractMask masks[FM_PCD_KG_NUM_OF_EXTRACT_MASKS]; + uint8_t hashShift; /**< hash result right shift. Select the 24 bits out of the 64 hash + result. 0 means using the 24 LSB's, otherwise use the + 24 LSB's after shifting right.*/ + uint32_t hashDistributionNumOfFqids; /**< must be > 1 and a power of 2. Represents the range + of queues for the key and hash functionality */ + uint8_t hashDistributionFqidsShift; /**< selects the FQID bits that will be effected by the hash */ + bool symmetricHash; /**< TRUE to generate the same hash for frames with swapped source and + destination fields on all layers; If TRUE, driver will check that for + all layers, if SRC extraction is selected, DST extraction must also be + selected, and vice versa. */ +} t_FmPcdKgKeyExtractAndHashParams; + +/**************************************************************************//** + @Description A structure of parameters for defining a single + Fqid mask (extracted OR). +*//***************************************************************************/ +typedef struct t_FmPcdKgExtractedOrParams { + e_FmPcdExtractType type; /**< Extraction type select */ + union { + struct { /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */ + e_NetHeaderType hdr; + e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled + IP. Otherwise should be cleared.*/ + bool ignoreProtocolValidation; + /**< continue extraction even if protocol is not recognized */ + } extractByHdr; + e_FmPcdExtractFrom src; /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */ + }; + uint8_t extractionOffset; /**< Offset for extraction (in bytes). */ + e_FmPcdKgExtractDfltSelect dfltValue; /**< Select register from which extraction is taken if + field not found */ + uint8_t mask; /**< Extraction mask (specified bits are used) */ + uint8_t bitOffsetInFqid; /**< 0-31, Selects which bits of the 24 FQID bits to effect using + the extracted byte; Assume byte is placed as the 8 MSB's in + a 32 bit word where the lower bits + are the FQID; i.e if bitOffsetInFqid=1 than its LSB + will effect the FQID MSB, if bitOffsetInFqid=24 than the + extracted byte will effect the 8 LSB's of the FQID, + if bitOffsetInFqid=31 than the byte's MSB will effect + the FQID's LSB; 0 means - no effect on FQID; + Note that one, and only one of + bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e, + extracted byte must effect either FQID or Policer profile).*/ + uint8_t bitOffsetInPlcrProfile; + /**< 0-15, Selects which bits of the 8 policer profile id bits to + effect using the extracted byte; Assume byte is placed + as the 8 MSB's in a 16 bit word where the lower bits + are the policer profile id; i.e if bitOffsetInPlcrProfile=1 + than its LSB will effect the profile MSB, if bitOffsetInFqid=8 + than the extracted byte will effect the whole policer profile id, + if bitOffsetInFqid=15 than the byte's MSB will effect + the Policer Profile id's LSB; + 0 means - no effect on policer profile; Note that one, and only one of + bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e, + extracted byte must effect either FQID or Policer profile).*/ +} t_FmPcdKgExtractedOrParams; + +/**************************************************************************//** + @Description A structure for configuring scheme counter +*//***************************************************************************/ +typedef struct t_FmPcdKgSchemeCounter { + bool update; /**< FALSE to keep the current counter state + and continue from that point, TRUE to update/reset + the counter when the scheme is written. */ + uint32_t value; /**< If update=TRUE, this value will be written into the + counter. clear this field to reset the counter. */ +} t_FmPcdKgSchemeCounter; + +/**************************************************************************//** + @Description A structure for defining policer profile + parameters as required by keygen (when policer + is the next engine after this scheme). +*//***************************************************************************/ +typedef struct t_FmPcdKgPlcrProfile { + bool sharedProfile; /**< TRUE if this profile is shared between ports + (i.e. managed by master partition) May not be TRUE + if profile is after Coarse Classification*/ + bool direct; /**< if TRUE, directRelativeProfileId only selects the profile + id, if FALSE fqidOffsetRelativeProfileIdBase is used + together with fqidOffsetShift and numOfProfiles + parameters, to define a range of profiles from + which the keygen result will determine the + destination policer profile. */ + union { + uint16_t directRelativeProfileId; /**< Used if 'direct' is TRUE, to select policer profile. + This parameter should + indicate the policer profile offset within the port's + policer profiles or SHARED window. */ + struct { + uint8_t fqidOffsetShift; /**< shift of KG results without the qid base */ + uint8_t fqidOffsetRelativeProfileIdBase; + /**< OR of KG results without the qid base + This parameter should indicate the policer profile + offset within the port's policer profiles window or + SHARED window depends on sharedProfile */ + uint8_t numOfProfiles; /**< Range of profiles starting at base */ + } indirectProfile; + } profileSelect; +} t_FmPcdKgPlcrProfile; + +/**************************************************************************//** + @Description A structure for CC parameters if CC is the next engine after KG +*//***************************************************************************/ +typedef struct t_FmPcdKgCc { + t_Handle h_CcTree; /**< A handle to a CC Tree */ + uint8_t grpId; /**< CC group id within the CC tree */ + bool plcrNext; /**< TRUE if after CC, in case of data frame, + policing is required. */ + bool bypassPlcrProfileGeneration; + /**< TRUE to bypass keygen policer profile + generation (profile selected is the one selected at + port initialization). */ + t_FmPcdKgPlcrProfile plcrProfile; /**< only if plcrNext=TRUE and bypassPlcrProfileGeneration=FALSE */ +} t_FmPcdKgCc; + +/**************************************************************************//** + @Description A structure for initializing a keygen single scheme +*//***************************************************************************/ +typedef struct t_FmPcdKgSchemeParams { + bool modify; /**< TRUE to change an existing scheme */ + union + { + uint8_t relativeSchemeId; /**< if modify=FALSE:Partition relative scheme id */ + t_Handle h_Scheme; /**< if modify=TRUE: a handle of the existing scheme */ + }id; + bool alwaysDirect; /**< This scheme is reached only directly, i.e. no need for match vector. Keygen will ignore + it when matching */ + struct { /**< HL Relevant only if alwaysDirect = FALSE */ + t_Handle h_NetEnv; /**< A handle to the Network environment as returned + by FM_PCD_SetNetEnvCharacteristics() */ + uint8_t numOfDistinctionUnits; /**< Number of netenv units listed in unitIds array */ + uint8_t unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + /**< Indexes as passed to SetNetEnvCharacteristics array*/ + } netEnvParams; + bool useHash; /**< use the KG Hash functionality */ + t_FmPcdKgKeyExtractAndHashParams keyExtractAndHashParams; + /**< used only if useHash = TRUE */ + bool bypassFqidGeneration; /**< Normally - FALSE, TRUE to avoid FQID update in the IC; + In such a case FQID after KG will be the default FQID + defined for the relevant port, or the FQID defined by CC + in cases where CC was the previous engine. */ + uint32_t baseFqid; /**< Base FQID; Relevant only if bypassFqidGeneration = FALSE; + If hash is used and an even distribution is expected + according to hashDistributionNumOfFqids, baseFqid must be aligned to + hashDistributionNumOfFqids. */ + uint8_t numOfUsedExtractedOrs; /**< Number of Fqid masks listed in extractedOrs array*/ + t_FmPcdKgExtractedOrParams extractedOrs[FM_PCD_KG_NUM_OF_GENERIC_REGS]; + /**< IN: FM_PCD_KG_NUM_OF_GENERIC_REGS + registers are shared between qidMasks + functionality and some of the extraction + actions; Normally only some will be used + for qidMask. Driver will return error if + resource is full at initialization time. */ + e_FmPcdEngine nextEngine; /**< may be BMI, PLCR or CC */ + union { /**< depends on nextEngine */ + e_FmPcdDoneAction doneAction; /**< Used when next engine is BMI (done) */ + t_FmPcdKgPlcrProfile plcrProfile; /**< Used when next engine is PLCR */ + t_FmPcdKgCc cc; /**< Used when next engine is CC */ + } kgNextEngineParams; + t_FmPcdKgSchemeCounter schemeCounter; /**< A structure of parameters for updating + the scheme counter */ +} t_FmPcdKgSchemeParams; + +/**************************************************************************//** + @Description A structure for defining CC params when CC is the + next engine after a CC node. +*//***************************************************************************/ +typedef struct t_FmPcdCcNextCcParams { + t_Handle h_CcNode; /**< A handle of the next CC node */ +} t_FmPcdCcNextCcParams; + +/**************************************************************************//** + @Description A structure for defining PLCR params when PLCR is the + next engine after a CC node. +*//***************************************************************************/ +typedef struct t_FmPcdCcNextPlcrParams { + bool overrideParams; /**< TRUE if CC override previously decided parameters*/ + bool sharedProfile; /**< Relevant only if overrideParams=TRUE: + TRUE if this profile is shared between ports */ + uint16_t newRelativeProfileId; /**< Relevant only if overrideParams=TRUE: + (otherwise profile id is taken from keygen); + This parameter should indicate the policer + profile offset within the port's + policer profiles or from SHARED window.*/ + uint32_t newFqid; /**< Relevant only if overrideParams=TRUE: + FQID for enqueuing the frame; + In earlier chips if policer next engine is KEYGEN, + this parameter can be 0, because the KEYGEN + always decides the enqueue FQID.*/ + bool statisticsEn; /**< In the case of TRUE Statistic counter is + incremented for each received frame passed through + this Coarse Classification entry.*/ +} t_FmPcdCcNextPlcrParams; + +/**************************************************************************//** + @Description A structure for defining enqueue params when BMI is the + next engine after a CC node. +*//***************************************************************************/ +typedef struct t_FmPcdCcNextEnqueueParams { + + e_FmPcdDoneAction action; /**< Action - when next engine is BMI (done) */ + bool overrideFqid; /**< TRUE if CC override previously decided Fqid(by Keygen), + relevant if action = e_FM_PCD_ENQ_FRAME */ + uint32_t newFqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame + (otherwise FQID is taken from keygen), + relevant if action = e_FM_PCD_ENQ_FRAME*/ + bool statisticsEn; /**< In the case of TRUE Statistic counter is + incremented for each received frame passed through + this Coarse Classification entry.*/ +} t_FmPcdCcNextEnqueueParams; + +/**************************************************************************//** + @Description A structure for defining KG params when KG is the + next engine after a CC node. +*//***************************************************************************/ +typedef struct t_FmPcdCcNextKgParams { + bool overrideFqid; /**< TRUE if CC override previously decided Fqid (by keygen), + Note - this parameters irrelevant for earlier chips*/ + uint32_t newFqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame + (otherwise FQID is taken from keygen), + Note - this parameters irrelevant for earlier chips*/ + t_Handle h_DirectScheme; /**< Direct scheme handle to go to. */ + bool statisticsEn; /**< In the case of TRUE Statistic counter is + incremented for each received frame passed through + this Coarse Classification entry.*/ +} t_FmPcdCcNextKgParams; + +/**************************************************************************//** + @Description A structure for defining next engine params after a CC node. +*//***************************************************************************/ +typedef struct t_FmPcdCcNextEngineParams { + e_FmPcdEngine nextEngine; /**< User has to initialize parameters + according to nextEngine definition */ + union { + t_FmPcdCcNextCcParams ccParams; /**< Parameters in case next engine is CC */ + t_FmPcdCcNextPlcrParams plcrParams; /**< Parameters in case next engine is PLCR */ + t_FmPcdCcNextEnqueueParams enqueueParams; /**< Parameters in case next engine is BMI */ + t_FmPcdCcNextKgParams kgParams; /**< Parameters in case next engine is KG */ + } params; +#if defined(FM_CAPWAP_SUPPORT) + t_Handle h_Manip; /**< Handler to headerManip. + Relevant if next engine of the type result + (e_FM_PCD_PLCR, e_FM_PCD_KG, e_FM_PCD_DONE) */ +#endif /* defined(FM_CAPWAP_SUPPORT) || ... */ +} t_FmPcdCcNextEngineParams; + +/**************************************************************************//** + @Description A structure for defining a single CC Key parameters +*//***************************************************************************/ +typedef struct t_FmPcdCcKeyParams { + uint8_t *p_Key; /**< pointer to the key of the size defined in keySize*/ + uint8_t *p_Mask; /**< pointer to the Mask per key of the size defined + in keySize. p_Key and p_Mask (if defined) has to be + of the same size defined in the keySize */ + t_FmPcdCcNextEngineParams ccNextEngineParams; + /**< parameters for the next for the defined Key in + the p_Key */ +} t_FmPcdCcKeyParams; + +/**************************************************************************//** + @Description A structure for defining CC Keys parameters +*//***************************************************************************/ +typedef struct t_KeysParams { + uint8_t numOfKeys; /**< Number Of relevant Keys */ + uint8_t keySize; /**< size of the key - in the case of the extraction of + the type FULL_FIELD keySize has to be as standard size of the relevant + key. In the another type of extraction keySize has to be as size of extraction. + In the case of action = e_FM_PCD_ACTION_INDEXED_LOOKUP the size of keySize has to be 2*/ + t_FmPcdCcKeyParams keyParams[FM_PCD_MAX_NUM_OF_KEYS]; + /**< it's array with numOfKeys entries each entry in + the array of the type t_FmPcdCcKeyParams */ + t_FmPcdCcNextEngineParams ccNextEngineParamsForMiss; + /**< parameters for the next step of + unfound (or undefined) key . Not relevant in the case + of action = e_FM_PCD_ACTION_INDEXED_LOOKUP*/ +} t_KeysParams; + +/**************************************************************************//** + @Description A structure for defining the CC node params +*//***************************************************************************/ +typedef struct t_FmPcdCcNodeParams { + t_FmPcdExtractEntry extractCcParams; /**< params which defines extraction parameters */ + t_KeysParams keysParams; /**< params which defines Keys parameters of the + extraction defined in extractCcParams */ +} t_FmPcdCcNodeParams; + +/**************************************************************************//** + @Description A structure for defining each CC tree group in term of + NetEnv units and the action to be taken in each case. + the unitIds list must be in order from lower to higher indexes. + + t_FmPcdCcNextEngineParams is a list of 2^numOfDistinctionUnits + structures where each defines the next action to be taken for + each units combination. for example: + numOfDistinctionUnits = 2 + unitIds = {1,3} + p_NextEnginePerEntriesInGrp[0] = t_FmPcdCcNextEngineParams for the case that + unit 1 - not found; unit 3 - not found; + p_NextEnginePerEntriesInGrp[1] = t_FmPcdCcNextEngineParams for the case that + unit 1 - not found; unit 3 - found; + p_NextEnginePerEntriesInGrp[2] = t_FmPcdCcNextEngineParams for the case that + unit 1 - found; unit 3 - not found; + p_NextEnginePerEntriesInGrp[3] = t_FmPcdCcNextEngineParams for the case that + unit 1 - found; unit 3 - found; +*//***************************************************************************/ +typedef struct t_FmPcdCcGrpParams { + uint8_t numOfDistinctionUnits; /**< up to 4 */ + uint8_t unitIds[FM_PCD_MAX_NUM_OF_CC_UNITS]; + /**< Indexes of the units as defined in + FM_PCD_SetNetEnvCharacteristics() */ + t_FmPcdCcNextEngineParams nextEnginePerEntriesInGrp[FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP]; + /**< Max size is 16 - if only one group used */ +} t_FmPcdCcGrpParams; + +/**************************************************************************//** + @Description A structure for defining the CC tree groups +*//***************************************************************************/ +typedef struct t_FmPcdCcTreeParams { + t_Handle h_NetEnv; /**< A handle to the Network environment as returned + by FM_PCD_SetNetEnvCharacteristics() */ + uint8_t numOfGrps; /**< Number of CC groups within the CC tree */ + t_FmPcdCcGrpParams ccGrpParams[FM_PCD_MAX_NUM_OF_CC_GROUPS]; /**< Parameters for each group. */ +} t_FmPcdCcTreeParams; + +/**************************************************************************//** + @Description A structure for defining parameters for byte rate +*//***************************************************************************/ +typedef struct t_FmPcdPlcrByteRateModeParams { + e_FmPcdPlcrFrameLengthSelect frameLengthSelection; /**< Frame length selection */ + e_FmPcdPlcrRollBackFrameSelect rollBackFrameSelection; /**< relevant option only e_FM_PCD_PLCR_L2_FRM_LEN, + e_FM_PCD_PLCR_FULL_FRM_LEN */ +} t_FmPcdPlcrByteRateModeParams; + +/**************************************************************************//** + @Description A structure for selcting the policer profile RFC-2698 or + RFC-4115 parameters +*//***************************************************************************/ +typedef struct t_FmPcdPlcrNonPassthroughAlgParams { + e_FmPcdPlcrRateMode rateMode; /**< Byte / Packet */ + t_FmPcdPlcrByteRateModeParams byteModeParams; /**< Valid for Byte NULL for Packet */ + uint32_t comittedInfoRate; /**< KBits/Sec or Packets/Sec */ + uint32_t comittedBurstSize; /**< Bytes/Packets */ + uint32_t peakOrAccessiveInfoRate; /**< KBits/Sec or Packets/Sec */ + uint32_t peakOrAccessiveBurstSize; /**< Bytes/Packets */ +} t_FmPcdPlcrNonPassthroughAlgParams; + +/**************************************************************************//** + @Description A union for defining Policer next engine parameters +*//***************************************************************************/ +typedef union u_FmPcdPlcrNextEngineParams { + e_FmPcdDoneAction action; /**< Action - when next engine is BMI (done) */ + t_Handle h_Profile; /**< Policer profile handle - used when next engine + is PLCR, must be a SHARED profile */ + t_Handle h_DirectScheme; /**< Direct scheme select - when next engine is Keygen */ +} u_FmPcdPlcrNextEngineParams; + +/**************************************************************************//** + @Description A structure for selecting the policer profile entry parameters +*//***************************************************************************/ +typedef struct t_FmPcdPlcrProfileParams { + bool modify; /**< TRUE to change an existing profile */ + union { + struct { + e_FmPcdProfileTypeSelection profileType; /**< Type of policer profile */ + t_Handle h_FmPort; /**< Relevant for per-port profiles only */ + uint16_t relativeProfileId; /**< Profile id - relative to shared group or to port */ + } newParams; /**< use it when modify=FALSE */ + t_Handle h_Profile; /**< A handle to a profile - use it when modify=TRUE */ + } id; + e_FmPcdPlcrAlgorithmSelection algSelection; /**< Profile Algorithm PASS_THROUGH, RFC_2698, RFC_4115 */ + e_FmPcdPlcrColorMode colorMode; /**< COLOR_BLIND, COLOR_AWARE */ + + union { + e_FmPcdPlcrColor dfltColor; /**< For Color-Blind Pass-Through mode. the policer will re-color + any incoming packet with the default value. */ + e_FmPcdPlcrColor override; /**< For Color-Aware modes. The profile response to a + pre-color value of 2'b11. */ + } color; + + t_FmPcdPlcrNonPassthroughAlgParams nonPassthroughAlgParams; /**< RFC2698 or RFC4115 params */ + + e_FmPcdEngine nextEngineOnGreen; /**< Green next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnGreen; /**< Green next engine params */ + + e_FmPcdEngine nextEngineOnYellow; /**< Yellow next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnYellow; /**< Yellow next engine params */ + + e_FmPcdEngine nextEngineOnRed; /**< Red next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnRed; /**< Red next engine params */ + + bool trapProfileOnFlowA; /**< Trap on flow A */ + bool trapProfileOnFlowB; /**< Trap on flow B */ + bool trapProfileOnFlowC; /**< Trap on flow C */ +} t_FmPcdPlcrProfileParams; + +#if defined(FM_CAPWAP_SUPPORT) +/**************************************************************************//** + @Description A structure for selecting the location of manipulation +*//***************************************************************************/ +typedef struct t_FmPcdManipLocationParams { + e_FmPcdManipLocateType type; /**< location of manipulation type select */ + struct { /**< used when type = e_FM_PCD_MANIP_BY_HDR */ + e_NetHeaderType hdr; /**< Header selection */ + e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled + IP. Otherwise should be cleared. */ + bool byField; /**< TRUE if the location of manipulation is according to some field in the specific header*/ + t_FmPcdFields fullField; /**< Relevant only when byField = TRUE: Extract field */ + } manipByHdr; +} t_FmPcdManipLocationParams; + +/**************************************************************************//** + @Description structure for defining insert manipulation + of the type e_FM_PCD_MANIP_INSRT_TO_START_OF_FRAME_TEMPLATE +*//***************************************************************************/ +typedef struct t_FmPcdManipInsrtByTemplateParams { + uint8_t size; /**< size of insert template to the start of the frame. */ + uint8_t hdrTemplate[FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE]; + /**< array of the insertion template. */ + + bool modifyOuterIp; /**< TRUE if user want to modify some fields in outer IP. */ + struct { + uint16_t ipOuterOffset; /**< offset of outer IP in the insert template, relevant if modifyOuterIp = TRUE.*/ + uint16_t dscpEcn; /**< value of dscpEcn in IP outer, relevant if modifyOuterIp = TRUE. + in IPV4 dscpEcn only byte - it has to be adjusted to the right*/ + bool udpPresent; /**< TRUE if UDP is present in the insert template, relevant if modifyOuterIp = TRUE.*/ + uint8_t udpOffset; /**< offset in the insert template of UDP, relevant if modifyOuterIp = TRUE and udpPresent=TRUE.*/ + uint8_t ipIdentGenId; /**< Used by FMan-CTRL to calculate IP-identification field,relevant if modifyOuterIp = TRUE.*/ + bool recalculateLength; /**< TRUE if recalculate length has to be performed due to the engines in the path which can change the frame later, relevant if modifyOuterIp = TRUE.*/ + struct { + uint8_t blockSize; /**< The CAAM block-size; Used by FMan-CTRL to calculate the IP-total-len field.*/ + uint8_t extraBytesAddedAlignedToBlockSize; /**< Used by FMan-CTRL to calculate the IP-total-len field and UDP length*/ + uint8_t extraBytesAddedNotAlignedToBlockSize;/**< Used by FMan-CTRL to calculate the IP-total-len field and UDP length.*/ + } recalculateLengthParams; /**< recalculate length parameters - relevant if modifyOuterIp = TRUE and recalculateLength = TRUE */ + } modifyOuterIpParams; /**< Outer IP modification parameters - ignored if modifyOuterIp is FALSE */ + + bool modifyOuterVlan; /**< TRUE if user wants to modify vpri field in the outer VLAN header*/ + struct { + uint8_t vpri; /**< value of vpri, relevant if modifyOuterVlan = TRUE + vpri only 3 bits, it has to be adjusted to the right*/ + } modifyOuterVlanParams; +} t_FmPcdManipInsrtByTemplateParams; +#endif /* defined(FM_CAPWAP_SUPPORT) || ... */ + + +#ifdef FM_CAPWAP_SUPPORT +/**************************************************************************//** + @Description structure for defining CAPWAP fragmentation +*//***************************************************************************/ +typedef struct t_CapwapFragmentationParams { + uint16_t sizeForFragmentation; /**< if length of the frame is greater than this value, CAPWAP fragmentation will be executed.*/ + bool headerOptionsCompr; /**< TRUE - first fragment include the CAPWAP header options field, + and all other fragments exclude the CAPWAP options field, + FALSE - all fragments include CAPWAP header options field. */ +} t_CapwapFragmentationParams; + +/**************************************************************************//** + @Description structure for defining CAPWAP Re-assembly +*//***************************************************************************/ +typedef struct t_CapwapReassemblyParams { + uint16_t maxNumFramesInProcess; /**< Number of frames which can be processed by Reassembly in the same time. + It has to be power of 2. + In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH, + maxNumFramesInProcess has to be in the range of 4 - 512, + In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH, + maxNumFramesInProcess has to be in the range of 8 - 2048 */ + bool haltOnDuplicationFrag; /**< In the case of TRUE, Reassembly process halted due to duplicated fragment, + and all processed fragments passed for enqueue with error indication. + In the case of FALSE, only duplicated fragment passed for enqueue with error indication */ + + e_FmPcdManipReassemTimeOutMode timeOutMode; /**< Expiration delay initialized by Reassembly process */ + uint32_t fqidForTimeOutFrames; /**< Fqid in which time out frames will enqueue during Time Out Process */ + uint32_t timeoutRoutineRequestTime; + /**< Represents the time interval in microseconds between consecutive + timeout routine requests It has to be power of 2. */ + uint32_t timeoutThresholdForReassmProcess; + /**< Represents the time interval in microseconds which defines + if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/ + + e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry;/**< Number of frames per hash entry needed for reassembly process */ +} t_CapwapReassemblyParams; +#endif /* FM_CAPWAP_SUPPORT */ + + +#if defined(FM_CAPWAP_SUPPORT) +/**************************************************************************//** + @Description structure for defining fragmentation/reassembly +*//***************************************************************************/ +typedef struct t_FmPcdManipFragOrReasmParams { + bool frag; /**< TRUE if using the structure for fragmentation, + otherwise this structure is used for reassembly */ + uint8_t extBufPoolIndx; /**< Index of the buffer pool ID which was configured for port + and can be used for manipulation; + NOTE: This field is relevant only for CAPWAP fragmentation + and reassembly */ + e_NetHeaderType hdr; /**< Header selection */ + union { +#ifdef FM_CAPWAP_SUPPORT + t_CapwapFragmentationParams capwapFragParams; /**< Structure for CAPWAP fragmentation, relevant if frag = TRUE, hdr = HEADER_TYPE_CAPWAP */ + t_CapwapReassemblyParams capwapReasmParams; /**< Structure for CAPWAP reassembly, relevant if frag = FALSE, hdr = HEADER_TYPE_CAPWAP */ +#endif /* FM_CAPWAP_SUPPORT */ + }; +} t_FmPcdManipFragOrReasmParams; + +/**************************************************************************//** + @Description structure for defining insert manipulation +*//***************************************************************************/ +typedef struct t_FmPcdManipInsrtParams { + e_FmPcdManipInsrtType type; /**< Type of insert manipulation */ + union { + t_FmPcdManipInsrtByTemplateParams insrtByTemplateParams; + /**< parameters for insert manipulation, relevant if + type = e_FM_PCD_MANIP_INSRT_TO_START_OF_FRAME_TEMPLATE */ + }; +} t_FmPcdManipInsrtParams; + +/**************************************************************************//** + @Description structure for defining remove manipulation +*//***************************************************************************/ +typedef struct t_FmPcdManipRmvParams { + e_FmPcdManipRmvParamsType type; /**< Type of remove manipulation */ + t_FmPcdManipLocationParams rmvSpecificLocationParams; + /**< Specified location of remove manipulation; + This params should be initialized in cases: + - e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_TILL_SPECIFIC_LOCATION + - e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_INCLUDE_SPECIFIC_LOCATION */ +} t_FmPcdManipRmvParams; + +/**************************************************************************//** + @Description structure for defining manipulation +*//***************************************************************************/ +typedef struct t_FmPcdManipParams { + bool rmv; /**< TRUE, if defined remove manipulation */ + t_FmPcdManipRmvParams rmvParams; /**< Parameters for remove manipulation, relevant if rmv = TRUE */ + + bool insrt; /**< TRUE, if defined insert manipulation */ + t_FmPcdManipInsrtParams insrtParams; /**< Parameters for insert manipulation, relevant if insrt = TRUE */ + + bool fragOrReasm; /**< TRUE, if defined fragmentation/reassembly manipulation */ + t_FmPcdManipFragOrReasmParams fragOrReasmParams; /**< Parameters for fragmentation/reassembly manipulation, relevant if fragOrReasm = TRUE */ + + /**< General parameters */ + bool treatFdStatusFieldsAsErrors; + /**< Set to TRUE when the port that is using this manip is chained + to SEC (i.e. the traffic was forwarded from SEC) */ +} t_FmPcdManipParams; + +/**************************************************************************//** + @Description structure for defining statistics node +*//***************************************************************************/ +typedef struct t_FmPcdStatsParams { + e_FmPcdStatsType type; /**< type of statistics node */ +} t_FmPcdStatsParams; +#endif /* defined(FM_CAPWAP_SUPPORT) || ... */ + + +/**************************************************************************//** + @Function FM_PCD_SetNetEnvCharacteristics + + @Description Define a set of Network Environment Characteristics. + When setting an environment it is important to understand its + application. It is not meant to describe the flows that will run + on the ports using this environment, but what the user means TO DO + with the PCD mechanisms in order to parse-classify-distribute those + frames. + By specifying a distinction unit, the user means it would use that option + for distinction between frames at either a keygen scheme keygen or a coarse + classification action descriptor. Using interchangeable headers to define a + unit means that the user is indifferent to which of the interchangeable + headers is present in the frame, and they want the distinction to be based + on the presence of either one of them. + Depending on context, there are limitations to the use of environments. A + port using the PCD functionality is bound to an environment. Some or even + all ports may share an environment but also an environment per port is + possible. When initializing a scheme, a classification plan group (see below), + or a coarse classification tree, one of the initialized environments must be + stated and related to. When a port is bound to a scheme, a classification + plan group, or a coarse classification tree, it MUST be bound to the same + environment. + The different PCD modules, may relate (for flows definition) ONLY on + distinction units as defined by their environment. When initializing a + scheme for example, it may not choose to select IPV4 as a match for + recognizing flows unless it was defined in the relating environment. In + fact, to guide the user through the configuration of the PCD, each module's + characterization in terms of flows is not done using protocol names, but using + environment indexes. + In terms of HW implementation, the list of distinction units sets the LCV vectors + and later used for match vector, classification plan vectors and coarse classification + indexing. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] p_NetEnvParams A structure of parameters for the initialization of + the network environment. + + @Return A handle to the initialized object on success; NULL code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Handle FM_PCD_SetNetEnvCharacteristics(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams); + +/**************************************************************************//** + @Function FM_PCD_DeleteNetEnvCharacteristics + + @Description Deletes a set of Network Environment Characteristics. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] h_NetEnv A handle to the Network environment. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PCD_DeleteNetEnvCharacteristics(t_Handle h_FmPcd, t_Handle h_NetEnv); + +/**************************************************************************//** + @Function FM_PCD_KgSetScheme + + @Description Initializing or modifying and enabling a scheme for the keygen. + This routine should be called for adding or modifying a scheme. + When a scheme needs modifying, the API requires that it will be + rewritten. In such a case 'modify' should be TRUE. If the + routine is called for a valid scheme and 'modify' is FALSE, + it will return error. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in,out] p_Scheme A structure of parameters for defining the scheme + + @Return A handle to the initialized scheme on success; NULL code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Handle FM_PCD_KgSetScheme (t_Handle h_FmPcd, + t_FmPcdKgSchemeParams *p_Scheme); + +/**************************************************************************//** + @Function FM_PCD_KgDeleteScheme + + @Description Deleting an initialized scheme. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSetScheme + + @Return E_OK on success; Error code otherwise. + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_KgDeleteScheme(t_Handle h_FmPcd, t_Handle h_Scheme); + +/**************************************************************************//** + @Function FM_PCD_KgGetSchemeCounter + + @Description Reads scheme packet counter. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSetScheme. + + @Return Counter's current value. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +uint32_t FM_PCD_KgGetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme); + +/**************************************************************************//** + @Function FM_PCD_KgSetSchemeCounter + + @Description Writes scheme packet counter. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSetScheme. + @Param[in] value New scheme counter value - typically '0' for + resetting the counter. + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_KgSetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t value); + +/**************************************************************************//** + @Function FM_PCD_CcBuildTree + + @Description This routine must be called to define a complete coarse + classification tree. This is the way to define coarse + classification to a certain flow - the keygen schemes + may point only to trees defined in this way. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] p_FmPcdCcTreeParams A structure of parameters to define the tree. + + @Return A handle to the initialized object on success; NULL code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Handle FM_PCD_CcBuildTree (t_Handle h_FmPcd, + t_FmPcdCcTreeParams *p_FmPcdCcTreeParams); + +/**************************************************************************//** + @Function FM_PCD_CcDeleteTree + + @Description Deleting an built tree. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcTree A handle to a CC tree. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_CcDeleteTree(t_Handle h_FmPcd, t_Handle h_CcTree); + +/**************************************************************************//** + @Function FM_PCD_CcSetNode + + @Description This routine should be called for each CC (coarse classification) + node. The whole CC tree should be built bottom up so that each + node points to already defined nodes. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] p_CcNodeParam A structure of parameters defining the CC node + + @Return A handle to the initialized object on success; NULL code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Handle FM_PCD_CcSetNode(t_Handle h_FmPcd, + t_FmPcdCcNodeParams *p_CcNodeParam); + +/**************************************************************************//** + @Function FM_PCD_CcDeleteNode + + @Description Deleting an built node. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to a CC node. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_CcDeleteNode(t_Handle h_FmPcd, t_Handle h_CcNode); + +/**************************************************************************//** + @Function FM_PCD_CcTreeModifyNextEngine + + @Description Modify the Next Engine Parameters in the entry of the tree. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcTree A handle to the tree + @Param[in] grpId A Group index in the tree + @Param[in] index Entry index in the group defined by grpId + @Param[in] p_FmPcdCcNextEngineParams A structure for defining new next engine params + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcBuildTree(). +*//***************************************************************************/ +t_Error FM_PCD_CcTreeModifyNextEngine(t_Handle h_FmPcd, t_Handle h_CcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); + +/**************************************************************************//** + @Function FM_PCD_CcNodeModifyNextEngine + + @Description Modify the Next Engine Parameters in the relevant key entry of the node. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to the node + @Param[in] keyIndex Key index for Next Engine Params modifications + @Param[in] p_FmPcdCcNextEngineParams A structure for defining new next engine params + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode(). +*//***************************************************************************/ +t_Error FM_PCD_CcNodeModifyNextEngine(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); + +/**************************************************************************//** + @Function FM_PCD_CcNodeModifyMissNextEngine + + @Description Modify the Next Engine Parameters of the Miss key case of the node. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to the node + @Param[in] p_FmPcdCcNextEngineParams A structure for defining new next engine params + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode(). +*//***************************************************************************/ +t_Error FM_PCD_CcNodeModifyMissNextEngine(t_Handle h_FmPcd, t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); + +/**************************************************************************//** + @Function FM_PCD_CcNodeRemoveKey + + @Description Remove the key (include Next Engine Parameters of this key) defined by the index of the relevant node . + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to the node + @Param[in] keyIndex Key index for removing + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevant node but also + the node that points to this node +*//***************************************************************************/ +t_Error FM_PCD_CcNodeRemoveKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex); + +/**************************************************************************//** + @Function FM_PCD_CcNodeAddKey + + @Description Add the key(include Next Engine Parameters of this key)in the index defined by the keyIndex . + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to the node + @Param[in] keyIndex Key index for adding + @Param[in] keySize Key size of added key + @Param[in] p_KeyParams A pointer to the parameters includes new key with Next Engine Parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevant node but also + the node that points to this node +*//***************************************************************************/ +t_Error FM_PCD_CcNodeAddKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams); + +/**************************************************************************//** + @Function FM_PCD_CcNodeModifyKeyAndNextEngine + + @Description Modify the key and Next Engine Parameters of this key in the index defined by the keyIndex . + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to the node + @Param[in] keyIndex Key index for adding + @Param[in] keySize Key size of added key + @Param[in] p_KeyParams A pointer to the parameters includes modified key and modified Next Engine Parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevant node but also + the node that points to this node +*//***************************************************************************/ +t_Error FM_PCD_CcNodeModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams); + +/**************************************************************************//** + @Function FM_PCD_CcNodeModifyKey + + @Description Modify the key in the index defined by the keyIndex . + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to the node + @Param[in] keyIndex Key index for adding + @Param[in] keySize Key size of added key + @Param[in] p_Key A pointer to the new key + @Param[in] p_Mask A pointer to the new mask if relevant, otherwise pointer to NULL + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevant node but also + the node that points to this node +*//***************************************************************************/ +t_Error FM_PCD_CcNodeModifyKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask); + +/**************************************************************************//** + @Function FM_PCD_CcNodeGetKeyCounter + + @Description This routine may be used to get a counter of specific key in a CC + Node; This counter reflects how many frames passed that were matched + this key. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_CcNode A handle to the node + @Param[in] keyIndex Key index for adding + + @Return The specific key counter. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevant node but also + the node that points to this node +*//***************************************************************************/ +uint32_t FM_PCD_CcNodeGetKeyCounter(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex); + +/**************************************************************************//** + @Function FM_PCD_PlcrSetProfile + + @Description Sets a profile entry in the policer profile table. + The routine overrides any existing value. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] p_Profile A structure of parameters for defining a + policer profile entry. + + @Return A handle to the initialized object on success; NULL code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Handle FM_PCD_PlcrSetProfile(t_Handle h_FmPcd, + t_FmPcdPlcrProfileParams *p_Profile); + +/**************************************************************************//** + @Function FM_PCD_PlcrDeleteProfile + + @Description Delete a profile entry in the policer profile table. + The routine set entry to invalid. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_Profile A handle to the profile. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_PlcrDeleteProfile(t_Handle h_FmPcd, t_Handle h_Profile); + +/**************************************************************************//** + @Function FM_PCD_PlcrGetProfileCounter + + @Description Sets an entry in the classification plan. + The routine overrides any existing value. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_Profile A handle to the profile. + @Param[in] counter Counter selector. + + @Return specific counter value. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +uint32_t FM_PCD_PlcrGetProfileCounter(t_Handle h_FmPcd, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter); + +/**************************************************************************//** + @Function FM_PCD_PlcrSetProfileCounter + + @Description Sets an entry in the classification plan. + The routine overrides any existing value. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_Profile A handle to the profile. + @Param[in] counter Counter selector. + @Param[in] value value to set counter with. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_PlcrSetProfileCounter(t_Handle h_FmPcd, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value); + +#if defined(FM_CAPWAP_SUPPORT) +/**************************************************************************//** + @Function FM_PCD_ManipSetNode + + @Description This routine should be called for defining a manipulation + node. A manipulation node must be defined before the CC node + that precedes it. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] p_FmPcdManipParams A structure of parameters defining the manipulation + + @Return A handle to the initialized object on success; NULL code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Handle FM_PCD_ManipSetNode(t_Handle h_FmPcd, t_FmPcdManipParams *p_FmPcdManipParams); + +/**************************************************************************//** + @Function FM_PCD_ManipDeleteNode + + @Description Delete an existing manip node. + + @Param[in] h_FmPcd A handle to an FM PCD Module. + @Param[in] h_HdrManipNode A handle to a Manip node. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Error FM_PCD_ManipDeleteNode(t_Handle h_FmPcd, t_Handle h_HdrManipNode); +#endif /* defined(FM_CAPWAP_SUPPORT) || ... */ + + +#ifdef FM_CAPWAP_SUPPORT +/**************************************************************************//** + @Function FM_PCD_StatisticsSetNode + + @Description This routine should be called for defining a statistics + node. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] p_FmPcdstatsParams A structure of parameters defining the statistics + + @Return A handle to the initialized object on success; NULL code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_FmPcdstatsParams); +#endif /* FM_CAPWAP_SUPPORT */ + +/** @} */ /* end of FM_PCD_Runtime_tree_buildgrp group */ +/** @} */ /* end of FM_PCD_Runtime_grp group */ +/** @} */ /* end of FM_PCD_grp group */ +/** @} */ /* end of FM_grp group */ + + + +#endif /* __FM_PCD_EXT */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/crc_mac_addr_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/crc_mac_addr_ext.h @@ -0,0 +1,363 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*------------------------------------------------------*/ +/* */ +/* File: crc_mac_addr_ext.h */ +/* */ +/* Description: */ +/* Define a macro that calculate the crc value of */ +/* an Ethernet MAC address (48 bitd address */ +/*------------------------------------------------------*/ + +#ifndef __crc_mac_addr_ext_h +#define __crc_mac_addr_ext_h + +#include "std_ext.h" + + +static uint32_t crc_table[256] = +{ + 0x00000000, + 0x77073096, + 0xee0e612c, + 0x990951ba, + 0x076dc419, + 0x706af48f, + 0xe963a535, + 0x9e6495a3, + 0x0edb8832, + 0x79dcb8a4, + 0xe0d5e91e, + 0x97d2d988, + 0x09b64c2b, + 0x7eb17cbd, + 0xe7b82d07, + 0x90bf1d91, + 0x1db71064, + 0x6ab020f2, + 0xf3b97148, + 0x84be41de, + 0x1adad47d, + 0x6ddde4eb, + 0xf4d4b551, + 0x83d385c7, + 0x136c9856, + 0x646ba8c0, + 0xfd62f97a, + 0x8a65c9ec, + 0x14015c4f, + 0x63066cd9, + 0xfa0f3d63, + 0x8d080df5, + 0x3b6e20c8, + 0x4c69105e, + 0xd56041e4, + 0xa2677172, + 0x3c03e4d1, + 0x4b04d447, + 0xd20d85fd, + 0xa50ab56b, + 0x35b5a8fa, + 0x42b2986c, + 0xdbbbc9d6, + 0xacbcf940, + 0x32d86ce3, + 0x45df5c75, + 0xdcd60dcf, + 0xabd13d59, + 0x26d930ac, + 0x51de003a, + 0xc8d75180, + 0xbfd06116, + 0x21b4f4b5, + 0x56b3c423, + 0xcfba9599, + 0xb8bda50f, + 0x2802b89e, + 0x5f058808, + 0xc60cd9b2, + 0xb10be924, + 0x2f6f7c87, + 0x58684c11, + 0xc1611dab, + 0xb6662d3d, + 0x76dc4190, + 0x01db7106, + 0x98d220bc, + 0xefd5102a, + 0x71b18589, + 0x06b6b51f, + 0x9fbfe4a5, + 0xe8b8d433, + 0x7807c9a2, + 0x0f00f934, + 0x9609a88e, + 0xe10e9818, + 0x7f6a0dbb, + 0x086d3d2d, + 0x91646c97, + 0xe6635c01, + 0x6b6b51f4, + 0x1c6c6162, + 0x856530d8, + 0xf262004e, + 0x6c0695ed, + 0x1b01a57b, + 0x8208f4c1, + 0xf50fc457, + 0x65b0d9c6, + 0x12b7e950, + 0x8bbeb8ea, + 0xfcb9887c, + 0x62dd1ddf, + 0x15da2d49, + 0x8cd37cf3, + 0xfbd44c65, + 0x4db26158, + 0x3ab551ce, + 0xa3bc0074, + 0xd4bb30e2, + 0x4adfa541, + 0x3dd895d7, + 0xa4d1c46d, + 0xd3d6f4fb, + 0x4369e96a, + 0x346ed9fc, + 0xad678846, + 0xda60b8d0, + 0x44042d73, + 0x33031de5, + 0xaa0a4c5f, + 0xdd0d7cc9, + 0x5005713c, + 0x270241aa, + 0xbe0b1010, + 0xc90c2086, + 0x5768b525, + 0x206f85b3, + 0xb966d409, + 0xce61e49f, + 0x5edef90e, + 0x29d9c998, + 0xb0d09822, + 0xc7d7a8b4, + 0x59b33d17, + 0x2eb40d81, + 0xb7bd5c3b, + 0xc0ba6cad, + 0xedb88320, + 0x9abfb3b6, + 0x03b6e20c, + 0x74b1d29a, + 0xead54739, + 0x9dd277af, + 0x04db2615, + 0x73dc1683, + 0xe3630b12, + 0x94643b84, + 0x0d6d6a3e, + 0x7a6a5aa8, + 0xe40ecf0b, + 0x9309ff9d, + 0x0a00ae27, + 0x7d079eb1, + 0xf00f9344, + 0x8708a3d2, + 0x1e01f268, + 0x6906c2fe, + 0xf762575d, + 0x806567cb, + 0x196c3671, + 0x6e6b06e7, + 0xfed41b76, + 0x89d32be0, + 0x10da7a5a, + 0x67dd4acc, + 0xf9b9df6f, + 0x8ebeeff9, + 0x17b7be43, + 0x60b08ed5, + 0xd6d6a3e8, + 0xa1d1937e, + 0x38d8c2c4, + 0x4fdff252, + 0xd1bb67f1, + 0xa6bc5767, + 0x3fb506dd, + 0x48b2364b, + 0xd80d2bda, + 0xaf0a1b4c, + 0x36034af6, + 0x41047a60, + 0xdf60efc3, + 0xa867df55, + 0x316e8eef, + 0x4669be79, + 0xcb61b38c, + 0xbc66831a, + 0x256fd2a0, + 0x5268e236, + 0xcc0c7795, + 0xbb0b4703, + 0x220216b9, + 0x5505262f, + 0xc5ba3bbe, + 0xb2bd0b28, + 0x2bb45a92, + 0x5cb36a04, + 0xc2d7ffa7, + 0xb5d0cf31, + 0x2cd99e8b, + 0x5bdeae1d, + 0x9b64c2b0, + 0xec63f226, + 0x756aa39c, + 0x026d930a, + 0x9c0906a9, + 0xeb0e363f, + 0x72076785, + 0x05005713, + 0x95bf4a82, + 0xe2b87a14, + 0x7bb12bae, + 0x0cb61b38, + 0x92d28e9b, + 0xe5d5be0d, + 0x7cdcefb7, + 0x0bdbdf21, + 0x86d3d2d4, + 0xf1d4e242, + 0x68ddb3f8, + 0x1fda836e, + 0x81be16cd, + 0xf6b9265b, + 0x6fb077e1, + 0x18b74777, + 0x88085ae6, + 0xff0f6a70, + 0x66063bca, + 0x11010b5c, + 0x8f659eff, + 0xf862ae69, + 0x616bffd3, + 0x166ccf45, + 0xa00ae278, + 0xd70dd2ee, + 0x4e048354, + 0x3903b3c2, + 0xa7672661, + 0xd06016f7, + 0x4969474d, + 0x3e6e77db, + 0xaed16a4a, + 0xd9d65adc, + 0x40df0b66, + 0x37d83bf0, + 0xa9bcae53, + 0xdebb9ec5, + 0x47b2cf7f, + 0x30b5ffe9, + 0xbdbdf21c, + 0xcabac28a, + 0x53b39330, + 0x24b4a3a6, + 0xbad03605, + 0xcdd70693, + 0x54de5729, + 0x23d967bf, + 0xb3667a2e, + 0xc4614ab8, + 0x5d681b02, + 0x2a6f2b94, + 0xb40bbe37, + 0xc30c8ea1, + 0x5a05df1b, + 0x2d02ef8d +}; + + +#define GET_MAC_ADDR_CRC(addr, crc) \ +{ \ + uint32_t i; \ + uint8_t data; \ + \ + /* CRC calculation */ \ + crc = 0xffffffff; \ + for (i=0; i < 6; i++) \ + { \ + data = (uint8_t)(addr >> ((5-i)*8)); \ + crc = crc^data; \ + crc = crc_table[crc&0xff] ^ (crc>>8); \ + } \ +} \ + +/* Define a macro for getting the mirrored value of */ +/* a byte size number. (0x11010011 --> 0x11001011) */ +/* Sometimes the mirrored value of the CRC is required */ +static __inline__ uint8_t GetMirror(uint8_t n) +{ + uint8_t mirror[16] = + { + 0x00, + 0x08, + 0x04, + 0x0c, + 0x02, + 0x0a, + 0x06, + 0x0e, + 0x01, + 0x09, + 0x05, + 0x0d, + 0x03, + 0x0b, + 0x07, + 0x0f + }; + return ((uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4])))); +} + +static __inline__ uint32_t GetMirror32(uint32_t n) +{ + return (((uint32_t)GetMirror((uint8_t)(n))<<24) | + ((uint32_t)GetMirror((uint8_t)(n>>8))<<16) | + ((uint32_t)GetMirror((uint8_t)(n>>16))<<8) | + ((uint32_t)GetMirror((uint8_t)(n>>24)))); +} + +#define MIRROR GetMirror +#define MIRROR_32 GetMirror32 + + +#endif /* __crc_mac_addr_ext_h */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/dpaa_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/dpaa_ext.h @@ -0,0 +1,206 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File dpaa_ext.h + + @Description DPAA Application Programming Interface. +*//***************************************************************************/ +#ifndef __DPAA_EXT_H +#define __DPAA_EXT_H + +#include "std_ext.h" +#include "error_ext.h" + + +/**************************************************************************//** + @Group DPAA_grp Data Path Acceleration Architecture API + + @Description DPAA API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/**************************************************************************//** + @Description Frame descriptor +*//***************************************************************************/ +typedef _Packed struct t_DpaaFD { + volatile uint32_t id; /**< FD id */ + volatile uint32_t addrl; /**< Data Address */ + volatile uint32_t length; /**< Frame length */ + volatile uint32_t status; /**< FD status */ +} _PackedType t_DpaaFD; + +/**************************************************************************//** + @Description enum for defining frame format +*//***************************************************************************/ +typedef enum e_DpaaFDFormatType { + e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF = 0x0, /**< Simple frame Single buffer; Offset and + small length (9b OFFSET, 20b LENGTH) */ + e_DPAA_FD_FORMAT_TYPE_LONG_SBSF = 0x2, /**< Simple frame, single buffer; big length + (29b LENGTH ,No OFFSET) */ + e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF = 0x4, /**< Simple frame, Scatter Gather table; Offset + and small length (9b OFFSET, 20b LENGTH) */ + e_DPAA_FD_FORMAT_TYPE_LONG_MBSF = 0x6, /**< Simple frame, Scatter Gather table; + big length (29b LENGTH ,No OFFSET) */ + e_DPAA_FD_FORMAT_TYPE_COMPOUND = 0x1, /**< Compound Frame (29b CONGESTION-WEIGHT + No LENGTH or OFFSET) */ + e_DPAA_FD_FORMAT_TYPE_DUMMY +} e_DpaaFDFormatType; + +/**************************************************************************//** + @Collection Frame descriptor macros +*//***************************************************************************/ +#define DPAA_FD_DD_MASK 0xc0000000 /**< FD DD field mask */ +#define DPAA_FD_PID_MASK 0x3f000000 /**< FD PID field mask */ +#define DPAA_FD_ELIODN_MASK 0x0000f000 /**< FD ELIODN field mask */ +#define DPAA_FD_BPID_MASK 0x00ff0000 /**< FD BPID field mask */ +#define DPAA_FD_ADDRH_MASK 0x000000ff /**< FD ADDRH field mask */ +#define DPAA_FD_ADDRL_MASK 0xffffffff /**< FD ADDRL field mask */ +#define DPAA_FD_FORMAT_MASK 0xe0000000 /**< FD FORMAT field mask */ +#define DPAA_FD_OFFSET_MASK 0x1ff00000 /**< FD OFFSET field mask */ +#define DPAA_FD_LENGTH_MASK 0x000fffff /**< FD LENGTH field mask */ + +#define DPAA_FD_GET_DD(fd) ((((t_DpaaFD *)fd)->id & DPAA_FD_DD_MASK) >> (31-1)) /**< Macro to get FD DD field */ +#define DPAA_FD_GET_PID(fd) (((((t_DpaaFD *)fd)->id & DPAA_FD_PID_MASK) >> (31-7)) | \ + ((((t_DpaaFD *)fd)->id & DPAA_FD_ELIODN_MASK) >> (31-19-6))) /**< Macro to get FD PID field */ +#define DPAA_FD_GET_BPID(fd) ((((t_DpaaFD *)fd)->id & DPAA_FD_BPID_MASK) >> (31-15)) /**< Macro to get FD BPID field */ +#define DPAA_FD_GET_ADDRH(fd) (((t_DpaaFD *)fd)->id & DPAA_FD_ADDRH_MASK) /**< Macro to get FD ADDRH field */ +#define DPAA_FD_GET_ADDRL(fd) ((t_DpaaFD *)fd)->addrl /**< Macro to get FD ADDRL field */ +#define DPAA_FD_GET_PHYS_ADDR(fd) ((physAddress_t)(((uint64_t)DPAA_FD_GET_ADDRH(fd) << 32) | (uint64_t)DPAA_FD_GET_ADDRL(fd))) /**< Macro to get FD ADDR field */ +#define DPAA_FD_GET_FORMAT(fd) ((((t_DpaaFD *)fd)->length & DPAA_FD_FORMAT_MASK) >> (31-2)) /**< Macro to get FD FORMAT field */ +#define DPAA_FD_GET_OFFSET(fd) ((((t_DpaaFD *)fd)->length & DPAA_FD_OFFSET_MASK) >> (31-11)) /**< Macro to get FD OFFSET field */ +#define DPAA_FD_GET_LENGTH(fd) (((t_DpaaFD *)fd)->length & DPAA_FD_LENGTH_MASK) /**< Macro to get FD LENGTH field */ +#define DPAA_FD_GET_STATUS(fd) ((t_DpaaFD *)fd)->status /**< Macro to get FD STATUS field */ +#define DPAA_FD_GET_ADDR(fd) XX_PhysToVirt(DPAA_FD_GET_PHYS_ADDR(fd)) + +#define DPAA_FD_SET_DD(fd,val) (((t_DpaaFD *)fd)->id = ((((t_DpaaFD *)fd)->id & ~DPAA_FD_DD_MASK) | (((val) << (31-1)) & DPAA_FD_DD_MASK ))) /**< Macro to set FD DD field */ + /**< Macro to set FD PID field or LIODN offset*/ +#define DPAA_FD_SET_PID(fd,val) (((t_DpaaFD *)fd)->id = ((((t_DpaaFD *)fd)->id & ~(DPAA_FD_PID_MASK|DPAA_FD_ELIODN_MASK)) | ((((val) << (31-7)) & DPAA_FD_PID_MASK) | ((((val)>>6) << (31-19)) & DPAA_FD_ELIODN_MASK)))) +#define DPAA_FD_SET_BPID(fd,val) (((t_DpaaFD *)fd)->id = ((((t_DpaaFD *)fd)->id & ~DPAA_FD_BPID_MASK) | (((val) << (31-15)) & DPAA_FD_BPID_MASK))) /**< Macro to set FD BPID field */ +#define DPAA_FD_SET_ADDRH(fd,val) (((t_DpaaFD *)fd)->id = ((((t_DpaaFD *)fd)->id & ~DPAA_FD_ADDRH_MASK) | ((val) & DPAA_FD_ADDRH_MASK))) /**< Macro to set FD ADDRH field */ +#define DPAA_FD_SET_ADDRL(fd,val) ((t_DpaaFD *)fd)->addrl = (val) /**< Macro to set FD ADDRL field */ +#define DPAA_FD_SET_ADDR(fd,val) \ +do { \ + uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val)); \ + DPAA_FD_SET_ADDRH(fd, ((uint32_t)(physAddr >> 32))); \ + DPAA_FD_SET_ADDRL(fd, (uint32_t)physAddr); \ +} while (0) /**< Macro to set FD ADDR field */ +#define DPAA_FD_SET_FORMAT(fd,val) (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_FORMAT_MASK) | (((val) << (31-2))& DPAA_FD_FORMAT_MASK))) /**< Macro to set FD FORMAT field */ +#define DPAA_FD_SET_OFFSET(fd,val) (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_OFFSET_MASK) | (((val) << (31-11))& DPAA_FD_OFFSET_MASK) )) /**< Macro to set FD OFFSET field */ +#define DPAA_FD_SET_LENGTH(fd,val) (((t_DpaaFD *)fd)->length = (((t_DpaaFD *)fd)->length & ~DPAA_FD_LENGTH_MASK) | ((val) & DPAA_FD_LENGTH_MASK)) /**< Macro to set FD LENGTH field */ +#define DPAA_FD_SET_STATUS(fd,val) ((t_DpaaFD *)fd)->status = (val) /**< Macro to set FD STATUS field */ +/* @} */ + +/**************************************************************************//** + @Description Frame Scatter/Gather Table Entry +*//***************************************************************************/ +typedef _Packed struct t_DpaaSGTE { + volatile uint32_t addrh; /**< Buffer Address high */ + volatile uint32_t addrl; /**< Buffer Address low */ + volatile uint32_t length; /**< Buffer length */ + volatile uint32_t offset; /**< SGTE offset */ +} _PackedType t_DpaaSGTE; + +#define DPAA_NUM_OF_SG_TABLE_ENTRY 16 + +/**************************************************************************//** + @Description Frame Scatter/Gather Table +*//***************************************************************************/ +typedef _Packed struct t_DpaaSGT { + t_DpaaSGTE tableEntry[DPAA_NUM_OF_SG_TABLE_ENTRY]; + /**< structure that hold the information about + a single S/G entry. */ +} _PackedType t_DpaaSGT; + +/**************************************************************************//** + @Description Compound Frame Table +*//***************************************************************************/ +typedef _Packed struct t_DpaaCompTbl { + t_DpaaSGTE outputBuffInfo; /**< structure that holds the information about + the compound-frame output buffer; + NOTE: this may point to a S/G table */ + t_DpaaSGTE inputBuffInfo; /**< structure that holds the information about + the compound-frame input buffer; + NOTE: this may point to a S/G table */ +} _PackedType t_DpaaCompTbl; + +/**************************************************************************//** + @Collection Frame Scatter/Gather Table Entry macros +*//***************************************************************************/ +#define DPAA_SGTE_ADDRH_MASK 0x000000ff /**< SGTE ADDRH field mask */ +#define DPAA_SGTE_ADDRL_MASK 0xffffffff /**< SGTE ADDRL field mask */ +#define DPAA_SGTE_E_MASK 0x80000000 /**< SGTE Extension field mask */ +#define DPAA_SGTE_F_MASK 0x40000000 /**< SGTE Final field mask */ +#define DPAA_SGTE_LENGTH_MASK 0x3fffffff /**< SGTE LENGTH field mask */ +#define DPAA_SGTE_BPID_MASK 0x00ff0000 /**< SGTE BPID field mask */ +#define DPAA_SGTE_OFFSET_MASK 0x00001fff /**< SGTE OFFSET field mask */ + +#define DPAA_SGTE_GET_ADDRH(sgte) (((t_DpaaSGTE *)sgte)->addrh & DPAA_SGTE_ADDRH_MASK) /**< Macro to get SGTE ADDRH field */ +#define DPAA_SGTE_GET_ADDRL(sgte) ((t_DpaaSGTE *)sgte)->addrl /**< Macro to get SGTE ADDRL field */ +#define DPAA_SGTE_GET_PHYS_ADDR(sgte) ((physAddress_t)(((uint64_t)DPAA_SGTE_GET_ADDRH(sgte) << 32) | (uint64_t)DPAA_SGTE_GET_ADDRL(sgte))) /**< Macro to get FD ADDR field */ +#define DPAA_SGTE_GET_EXTENSION(sgte) ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_E_MASK) >> (31-0)) /**< Macro to get SGTE EXTENSION field */ +#define DPAA_SGTE_GET_FINAL(sgte) ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_F_MASK) >> (31-1)) /**< Macro to get SGTE FINAL field */ +#define DPAA_SGTE_GET_LENGTH(sgte) (((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_LENGTH_MASK) /**< Macro to get SGTE LENGTH field */ +#define DPAA_SGTE_GET_BPID(sgte) ((((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_BPID_MASK) >> (31-15)) /**< Macro to get SGTE BPID field */ +#define DPAA_SGTE_GET_OFFSET(sgte) (((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_OFFSET_MASK) /**< Macro to get SGTE OFFSET field */ +#define DPAA_SGTE_GET_ADDR(sgte) XX_PhysToVirt(DPAA_SGTE_GET_PHYS_ADDR(sgte)) + +#define DPAA_SGTE_SET_ADDRH(sgte,val) (((t_DpaaSGTE *)sgte)->addrh = ((((t_DpaaSGTE *)sgte)->addrh & ~DPAA_SGTE_ADDRH_MASK) | ((val) & DPAA_SGTE_ADDRH_MASK))) /**< Macro to set SGTE ADDRH field */ +#define DPAA_SGTE_SET_ADDRL(sgte,val) ((t_DpaaSGTE *)sgte)->addrl = (val) /**< Macro to set SGTE ADDRL field */ +#define DPAA_SGTE_SET_ADDR(sgte,val) \ +do { \ + uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val)); \ + DPAA_SGTE_SET_ADDRH(sgte, ((uint32_t)(physAddr >> 32))); \ + DPAA_SGTE_SET_ADDRL(sgte, (uint32_t)physAddr); \ +} while (0) /**< Macro to set SGTE ADDR field */ +#define DPAA_SGTE_SET_EXTENSION(sgte,val) (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_E_MASK) | (((val) << (31-0))& DPAA_SGTE_E_MASK))) /**< Macro to set SGTE EXTENSION field */ +#define DPAA_SGTE_SET_FINAL(sgte,val) (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_F_MASK) | (((val) << (31-1))& DPAA_SGTE_F_MASK))) /**< Macro to set SGTE FINAL field */ +#define DPAA_SGTE_SET_LENGTH(sgte,val) (((t_DpaaSGTE *)sgte)->length = (((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_LENGTH_MASK) | ((val) & DPAA_SGTE_LENGTH_MASK)) /**< Macro to set SGTE LENGTH field */ +#define DPAA_SGTE_SET_BPID(sgte,val) (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_BPID_MASK) | (((val) << (31-15))& DPAA_SGTE_BPID_MASK))) /**< Macro to set SGTE BPID field */ +#define DPAA_SGTE_SET_OFFSET(sgte,val) (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_OFFSET_MASK) | (((val) << (31-31))& DPAA_SGTE_OFFSET_MASK) )) /**< Macro to set SGTE OFFSET field */ +/* @} */ + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + +/** @} */ /* end of DPAA_grp group */ + + +#endif /* __DPAA_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_port_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_port_ext.h @@ -0,0 +1,2196 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_port_ext.h + + @Description FM-Port Application Programming Interface. +*//***************************************************************************/ +#ifndef __FM_PORT_EXT +#define __FM_PORT_EXT + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_pcd_ext.h" +#include "fm_ext.h" +#include "net_ext.h" + + +/**************************************************************************//** + + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_PORT_grp FM Port + + @Description FM Port API + + The FM uses a general module called "port" to represent a Tx port + (MAC), an Rx port (MAC), offline parsing flow or host command + flow. There may be up to 17 (may change) ports in an FM - 5 Tx + ports (4 for the 1G MACs, 1 for the 10G MAC), 5 Rx Ports, and 7 + Host command/Offline parsing ports. The SW driver manages these + ports as sub-modules of the FM, i.e. after an FM is initialized, + its ports may be initialized and operated upon. + + The port is initialized aware of its type, but other functions on + a port may be indifferent to its type. When necessary, the driver + verifies coherency and returns error if applicable. + + On initialization, user specifies the port type and it's index + (relative to the port's type). Host command and Offline parsing + ports share the same id range, I.e user may not initialized host + command port 0 and offline parsing port 0. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description An enum for defining port PCD modes. + This enum defines the superset of PCD engines support - i.e. not + all engines have to be used, but all have to be enabled. The real + flow of a specific frame depends on the PCD configuration and the + frame headers and payload. +*//***************************************************************************/ +typedef enum e_FmPortPcdSupport { + e_FM_PORT_PCD_SUPPORT_NONE = 0, /**< BMI to BMI, PCD is not used */ + e_FM_PORT_PCD_SUPPORT_PRS_ONLY, /**< Use only Parser */ + e_FM_PORT_PCD_SUPPORT_PLCR_ONLY, /**< Use only Policer */ + e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR, /**< Use Parser and Policer */ + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG, /**< Use Parser and Keygen */ + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC, /**< Use Parser, Keygen and Coarse Classification */ + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR, + /**< Use all PCD engines */ + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR /**< Use Parser, Keygen and Policer */ +#ifdef FM_CAPWAP_SUPPORT + , + e_FM_PORT_PCD_SUPPORT_CC_ONLY, /**< Use only Coarse Classification */ + e_FM_PORT_PCD_SUPPORT_CC_AND_KG, /**< Use Coarse Classification,and Keygen */ + e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR /**< Use Coarse Classification, Keygen and Policer */ +#endif /* FM_CAPWAP_SUPPORT */ +} e_FmPortPcdSupport; + +/**************************************************************************//** + @Description Port interrupts +*//***************************************************************************/ +typedef enum e_FmPortExceptions { + e_FM_PORT_EXCEPTION_IM_BUSY /**< Independent-Mode Rx-BUSY */ +} e_FmPortExceptions; + + +/**************************************************************************//** + @Collection General FM Port defines +*//***************************************************************************/ +#define FM_PORT_PRS_RESULT_NUM_OF_WORDS 8 /**< Number of 4 bytes words in parser result */ +/* @} */ + +/**************************************************************************//** + @Collection FM Frame error +*//***************************************************************************/ +typedef uint32_t fmPortFrameErrSelect_t; /**< typedef for defining Frame Descriptor errors */ + +#define FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT 0x04000000 /**< Offline parsing only! Unsupported Format */ +#define FM_PORT_FRM_ERR_LENGTH 0x02000000 /**< Offline parsing only! Length Error */ +#define FM_PORT_FRM_ERR_DMA 0x01000000 /**< DMA Data error */ +#ifdef FM_CAPWAP_SUPPORT +#define FM_PORT_FRM_ERR_NON_FM 0x00400000 /**< non Frame-Manager error; probably come from SEC that + was chained to FM */ +#endif /* FM_CAPWAP_SUPPORT */ +#define FM_PORT_FRM_ERR_PHYSICAL 0x00080000 /**< Rx FIFO overflow, FCS error, code error, running disparity + error (SGMII and TBI modes), FIFO parity error. PHY + Sequence error, PHY error control character detected. */ +#define FM_PORT_FRM_ERR_SIZE 0x00040000 /**< Frame too long OR Frame size exceeds max_length_frame */ +#define FM_PORT_FRM_ERR_CLS_DISCARD 0x00020000 /**< classification discard */ +#define FM_PORT_FRM_ERR_EXTRACTION 0x00008000 /**< Extract Out of Frame */ +#define FM_PORT_FRM_ERR_NO_SCHEME 0x00004000 /**< No Scheme Selected */ +#define FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW 0x00002000 /**< Keysize Overflow */ +#define FM_PORT_FRM_ERR_COLOR_YELLOW 0x00000400 /**< Frame color is yellow */ +#define FM_PORT_FRM_ERR_COLOR_RED 0x00000800 /**< Frame color is red */ +#define FM_PORT_FRM_ERR_ILL_PLCR 0x00000200 /**< Illegal Policer Profile selected */ +#define FM_PORT_FRM_ERR_PLCR_FRAME_LEN 0x00000100 /**< Policer frame length error */ +#define FM_PORT_FRM_ERR_PRS_TIMEOUT 0x00000080 /**< Parser Time out Exceed */ +#define FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT 0x00000040 /**< Invalid Soft Parser instruction */ +#define FM_PORT_FRM_ERR_PRS_HDR_ERR 0x00000020 /**< Header error was identified during parsing */ +#define FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED 0x00000008 /**< Frame parsed beyind 256 first bytes */ +#define FM_PORT_FRM_ERR_PROCESS_TIMEOUT 0x00000001 /**< FPM Frame Processing Timeout Exceeded */ +/* @} */ + + + +/**************************************************************************//** + @Group FM_PORT_init_grp FM Port Initialization Unit + + @Description FM Port Initialization Unit + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description Exceptions user callback routine, will be called upon an + exception passing the exception identification. + + @Param[in] h_App - User's application descriptor. + @Param[in] exception - The exception. + *//***************************************************************************/ +typedef void (t_FmPortExceptionCallback) (t_Handle h_App, e_FmPortExceptions exception); + +/**************************************************************************//** + @Description User callback function called by driver with received data. + + User provides this function. Driver invokes it. + + @Param[in] h_App Application's handle originally specified to + the API Config function + @Param[in] p_Data A pointer to data received + @Param[in] length length of received data + @Param[in] status receive status and errors + @Param[in] position position of buffer in frame + @Param[in] h_BufContext A handle of the user acossiated with this buffer + + @Retval e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx + operation for all ready data. + @Retval e_RX_STORE_RESPONSE_PAUSE - order the driver to stop Rx operation. +*//***************************************************************************/ +typedef e_RxStoreResponse (t_FmPortImRxStoreCallback) (t_Handle h_App, + uint8_t *p_Data, + uint16_t length, + uint16_t status, + uint8_t position, + t_Handle h_BufContext); + +/**************************************************************************//** + @Description User callback function called by driver when transmit completed. + + User provides this function. Driver invokes it. + + @Param[in] h_App Application's handle originally specified to + the API Config function + @Param[in] p_Data A pointer to data received + @Param[in] status transmit status and errors + @Param[in] lastBuffer is last buffer in frame + @Param[in] h_BufContext A handle of the user acossiated with this buffer + *//***************************************************************************/ +typedef void (t_FmPortImTxConfCallback) (t_Handle h_App, + uint8_t *p_Data, + uint16_t status, + t_Handle h_BufContext); + +/**************************************************************************//** + @Description A structure of information about each of the external + buffer pools used by the port, +*//***************************************************************************/ +typedef struct t_FmPortExtPoolParams { + uint8_t id; /**< External buffer pool id */ + uint16_t size; /**< External buffer pool buffer size */ +} t_FmPortExtPoolParams; + +/**************************************************************************//** + @Description A structure for informing the driver about the external + buffer pools allocated in the BM and used by this port. +*//***************************************************************************/ +typedef struct t_FmPortExtPools { + uint8_t numOfPoolsUsed; /**< Number of pools use by this port */ + t_FmPortExtPoolParams extBufPool[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + /**< Parameters for each port */ +} t_FmPortExtPools; + +/**************************************************************************//** + @Description structure for additional Rx port parameters +*//***************************************************************************/ +typedef struct t_FmPortRxParams { + uint32_t errFqid; /**< Error Queue Id. */ + uint32_t dfltFqid; /**< Default Queue Id. */ + uint16_t liodnOffset; /**< Port's LIODN offset. */ + t_FmPortExtPools extBufPools; /**< Which external buffer pools are used + (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. */ +} t_FmPortRxParams; + +/**************************************************************************//** + @Description structure for additional non-Rx port parameters +*//***************************************************************************/ +typedef struct t_FmPortNonRxParams { + uint32_t errFqid; /**< Error Queue Id. */ + uint32_t dfltFqid; /**< For Tx and HC - Default Confirmation queue, + 0 means no Tx confirmation for processed + frames. For OP - default Rx queue. */ + uint32_t qmChannel; /**< QM-channel dedicated to this port; will be used + by the FM for dequeue. */ +#ifdef FM_OP_PARTITION_ERRATA_FMANx8 + uint16_t opLiodnOffset; /**< For Offline Parsing ports only. Port's LIODN offset. */ +#endif /* FM_OP_PARTITION_ERRATA_FMANx8 */ +} t_FmPortNonRxParams; + +/**************************************************************************//** + @Description structure for additional Rx port parameters +*//***************************************************************************/ +typedef struct t_FmPortImRxTxParams { + t_Handle h_FmMuram; /**< A handle of the FM-MURAM partition */ + uint16_t liodnOffset; /**< For Rx ports only. Port's LIODN Offset. */ + uint8_t dataMemId; /**< Memory partition ID for data buffers */ + uint32_t dataMemAttributes; /**< Memory attributes for data buffers */ + t_BufferPoolInfo rxPoolParams; /**< For Rx ports only. */ + t_FmPortImRxStoreCallback *f_RxStore; /**< For Rx ports only. */ + t_FmPortImTxConfCallback *f_TxConf; /**< For Tx ports only. */ +} t_FmPortImRxTxParams; + +/**************************************************************************//** + @Description Union for additional parameters depending on port type +*//***************************************************************************/ +typedef union u_FmPortSpecificParams { + t_FmPortImRxTxParams imRxTxParams; /**< Rx/Tx Independent-Mode port parameter structure */ + t_FmPortRxParams rxParams; /**< Rx port parameters structure */ + t_FmPortNonRxParams nonRxParams; /**< Non-Rx port parameters structure */ +} u_FmPortSpecificParams; + +/**************************************************************************//** + @Description structure representing FM initialization parameters +*//***************************************************************************/ +typedef struct t_FmPortParams { + uintptr_t baseAddr; /**< Virtual Address of memory mapped FM Port registers.*/ + t_Handle h_Fm; /**< A handle to the FM object this port related to */ + e_FmPortType portType; /**< Port type */ + uint8_t portId; /**< Port Id - relative to type */ + bool independentModeEnable; + /**< This port is Independent-Mode - Used for Rx/Tx ports only! */ + uint16_t liodnBase; /**< Irrelevant for P4080 rev 1. LIODN base for this port, to be + used together with LIODN offset. */ + u_FmPortSpecificParams specificParams; /**< Additional parameters depending on port + type. */ + + t_FmPortExceptionCallback *f_Exception; /**< Callback routine to be called of PCD exception */ + t_Handle h_App; /**< A handle to an application layer object; This handle will + be passed by the driver upon calling the above callbacks */ +} t_FmPortParams; + + +/**************************************************************************//** + @Function FM_PORT_Config + + @Description Creates descriptor for the FM PORT module. + + The routine returns a handle (descriptor) to the FM PORT object. + This descriptor must be passed as first parameter to all other + FM PORT function calls. + + No actual initialization or configuration of FM hardware is + done by this routine. + + @Param[in] p_FmPortParams - Pointer to data structure of parameters + + @Retval Handle to FM object, or NULL for Failure. +*//***************************************************************************/ +t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams); + +/**************************************************************************//** + @Function FM_PORT_Init + + @Description Initializes the FM PORT module + + @Param[in] h_FmPort - FM PORT module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PORT_Init(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_Free + + @Description Frees all resources that were assigned to FM PORT module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmPort - FM PORT module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PORT_Free(t_Handle h_FmPort); + + +/**************************************************************************//** + @Group FM_PORT_advanced_init_grp FM Port Advanced Configuration Unit + + @Description Configuration functions used to change default values. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description enum for defining QM frame dequeue +*//***************************************************************************/ +typedef enum e_FmPortDeqType { + e_FM_PORT_DEQ_TYPE1, /**< Dequeue from the SP channel - with priority precedence, + and Intra-Class Scheduling respected. */ + e_FM_PORT_DEQ_TYPE2, /**< Dequeue from the SP channel - with active FQ precedence, + and Intra-Class Scheduling respected. */ + e_FM_PORT_DEQ_TYPE3 /**< Dequeue from the SP channel - with active FQ precedence, + and override Intra-Class Scheduling */ +} e_FmPortDeqType; + +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT +/**************************************************************************//** + @Description enum for defining QM frame dequeue +*//***************************************************************************/ +typedef enum e_FmPortDeqPrefetchOption { + e_FM_PORT_DEQ_NO_PREFETCH, /**< QMI preforms a dequeue action for a single frame + only when a dedicated portID Tnum is waiting. */ + e_FM_PORT_DEQ_PARTIAL_PREFETCH, /**< QMI preforms a dequeue action for 3 frames when + one dedicated portId tnum is waiting. */ + e_FM_PORT_DEQ_FULL_PREFETCH /**< QMI preforms a dequeue action for 3 frames when + no dedicated portId tnums are waiting. */ + +} e_FmPortDeqPrefetchOption; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + +/**************************************************************************//** + @Description enum for defining port DMA swap mode +*//***************************************************************************/ +typedef enum e_FmPortDmaSwap { + e_FM_PORT_DMA_NO_SWP, /**< No swap, transfer data as is.*/ + e_FM_PORT_DMA_SWP_PPC_LE, /**< The transferred data should be swapped + in PowerPc Little Endian mode. */ + e_FM_PORT_DMA_SWP_BE /**< The transferred data should be swapped + in Big Endian mode */ +} e_FmPortDmaSwap; + +/**************************************************************************//** + @Description enum for defining port DMA cache attributes +*//***************************************************************************/ +typedef enum e_FmPortDmaCache { + e_FM_PORT_DMA_NO_STASH = 0, /**< Cacheable, no Allocate (No Stashing) */ + e_FM_PORT_DMA_STASH = 1 /**< Cacheable and Allocate (Stashing on) */ +} e_FmPortDmaCache; + +/**************************************************************************//** + @Description enum for defining port default color +*//***************************************************************************/ +typedef enum e_FmPortColor { + e_FM_PORT_COLOR_GREEN, /**< Default port color is green */ + e_FM_PORT_COLOR_YELLOW, /**< Default port color is yellow */ + e_FM_PORT_COLOR_RED, /**< Default port color is red */ + e_FM_PORT_COLOR_OVERRIDE /**< Ignore color */ +} e_FmPortColor; + +/**************************************************************************//** + @Description struct for defining Dual Tx rate limiting scale +*//***************************************************************************/ +typedef enum e_FmPortDualRateLimiterScaleDown { + e_FM_PORT_DUAL_RATE_LIMITER_NONE = 0, /**< Use only single rate limiter */ + e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2, /**< Divide high rate limiter by 2 */ + e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4, /**< Divide high rate limiter by 4 */ + e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 /**< Divide high rate limiter by 8 */ +} e_FmPortDualRateLimiterScaleDown; + + +/**************************************************************************//** + @Description struct for defining FM port resources +*//***************************************************************************/ +typedef struct t_FmPortRsrc { + uint32_t num; /**< Committed required resource */ + uint32_t extra; /**< Extra (not committed) required resource */ +} t_FmPortRsrc; + +/**************************************************************************//** + @Description struct for defining pool depletion criteria +*//***************************************************************************/ +typedef struct t_FmPortBufPoolDepletion { + bool numberOfPoolsModeEnable; /**< select mode in which pause frames will be sent after + a number of pools are depleted */ + uint8_t numOfPools; /**< the minimum number of depleted pools that will + invoke pause frames transmission. */ + bool poolsToConsider[BM_MAX_NUM_OF_POOLS]; + /**< For each pool, TRUE if it should be considered for + depletion (Note - this pool must be used by this port!) */ + bool singlePoolModeEnable; /**< select mode in which pause frames will be sent after + a single of pools are depleted */ + bool poolsToConsiderForSingleMode[BM_MAX_NUM_OF_POOLS]; + /**< For each pool, TRUE if it should be considered for + depletion (Note - this pool must be used by this port!) */ +} t_FmPortBufPoolDepletion; + +/**************************************************************************//** + @Description struct for defining observed pool depletion +*//***************************************************************************/ +typedef struct t_FmPortObservedBufPoolDepletion { + t_FmPortBufPoolDepletion poolDepletionParams;/**< parameters to define pool depletion */ + t_FmPortExtPools poolsParams; /**< Which external buffer pools are observed + (up to FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS), + and their sizes. */ +} t_FmPortObservedBufPoolDepletion; + +/**************************************************************************//** + @Description struct for defining Tx rate limiting +*//***************************************************************************/ +typedef struct t_FmPortRateLimit { + uint16_t maxBurstSize; /**< in kBytes for Tx ports, in frames + for offline parsing ports. (note that + for early chips burst size is + rounded up to a multiply of 1000 frames).*/ + uint32_t rateLimit; /**< in Kb/sec for Tx ports, in frame/sec for + offline parsing ports. Rate limit refers to + data rate (rather than line rate). */ + e_FmPortDualRateLimiterScaleDown rateLimitDivider; /**< For offline parsing ports only. Not-valid + for some earlier chip revisions */ +} t_FmPortRateLimit; + +/**************************************************************************//** + @Description struct for defining define the parameters of + the Rx port performance counters +*//***************************************************************************/ +typedef struct t_FmPortPerformanceCnt { + uint8_t taskCompVal; /**< Task compare value */ + uint8_t queueCompVal; /**< Rx queue/Tx confirm queue compare + value (unused for H/O) */ + uint8_t dmaCompVal; /**< Dma compare value */ + uint32_t fifoCompVal; /**< Fifo compare value (in bytes) */ +} t_FmPortPerformanceCnt; + +/**************************************************************************//** + @Description struct for defining buffer content. +*//***************************************************************************/ +typedef struct t_FmPortBufferPrefixContent { + uint16_t privDataSize; /**< Number of bytes to be left at the beginning + of the external buffer */ + bool passPrsResult; /**< TRUE to pass the parse result to/from the FM */ + bool passTimeStamp; /**< TRUE to pass the timeStamp to/from the FM */ + bool passHashResult; /**< TRUE to pass the KG hash result to/from the FM */ + bool passAllOtherPCDInfo;/**< Add all other Internal-Context information: + AD, hash-result, key, etc. */ + uint16_t dataAlign; /**< 0 to use driver's default alignment, other value + for selecting a data alignment (must be a + power of 2) */ +#ifdef DEBUG + bool passDebugInfo; /**< Debug-information */ +#endif /* DEBUG */ +#ifdef FM_CAPWAP_SUPPORT + uint8_t manipExtraSpace; /**< Maximum extra size needed (insertion-size minus removal-size) */ +#endif /* FM_CAPWAP_SUPPORT */ +} t_FmPortBufferPrefixContent; + +/**************************************************************************//** + @Description struct for defining backup Bm Pools. +*//***************************************************************************/ +typedef struct t_FmPortBackupBmPools { + uint8_t numOfBackupPools; /**< Number of BM backup pools - + must be smaller than the total number of + pools defined for the specified port.*/ + uint8_t poolIds[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + /**< numOfBackupPools pool id's, specifying which + pools should be used only as backup. Pool + id's specified here must be a subset of the + pools used by the specified port.*/ +} t_FmPortBackupBmPools; + + +/**************************************************************************//** + @Function FM_PORT_ConfigDeqHighPriority + + @Description Calling this routine changes the dequeue priority in the + internal driver data base from its default configuration + [TRUE] + + May be used for Non-Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] highPri TRUE to select high priority, FALSE for normal operation. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri); + +/**************************************************************************//** + @Function FM_PORT_ConfigDeqType + + @Description Calling this routine changes the dequeue type parameter in the + internal driver data base from its default configuration + [e_FM_PORT_DEQ_TYPE1]. + + May be used for Non-Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] deqType According to QM definition. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType); + +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT +/**************************************************************************//** + @Function FM_PORT_ConfigDeqPrefetchOption + + @Description Calling this routine changes the dequeue prefetch option parameter in the + internal driver data base from its default configuration + [e_FM_PORT_DEQ_FULL_PREFETCH] + Note: Available for some chips only + + May be used for Non-Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] deqPrefetchOption New option + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDeqPrefetchOption(t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption); +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + +/**************************************************************************//** + @Function FM_PORT_ConfigDeqByteCnt + + @Description Calling this routine changes the dequeue byte count parameter in + the internal driver data base from its default configuration [2000]. + + May be used for Non-Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] deqByteCnt New byte count + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt); + +/**************************************************************************//** + @Function FM_PORT_ConfigTxFifoMinFillLevel + + @Description Calling this routine changes the fifo minimum + fill level parameter in the internal driver data base + from its default configuration [0] + + May be used for Tx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] minFillLevel New value + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, uint32_t minFillLevel); + +/**************************************************************************//** + @Function FM_PORT_ConfigTxFifoDeqPipelineDepth + + @Description Calling this routine changes the fifo dequeue + pipeline depth parameter in the internal driver data base + + from its default configuration: 1G ports: [2], + 10G port: [8] + + May be used for Tx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] deqPipelineDepth New value + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigTxFifoDeqPipelineDepth(t_Handle h_FmPort, uint8_t deqPipelineDepth); + +/**************************************************************************//** + @Function FM_PORT_ConfigTxFifoLowComfLevel + + @Description Calling this routine changes the fifo low comfort level + parameter in internal driver data base + from its default configuration [5] + + May be used for Tx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] fifoLowComfLevel New value + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, uint32_t fifoLowComfLevel); + +/**************************************************************************//** + @Function FM_PORT_ConfigRxFifoThreshold + + @Description Calling this routine changes the threshold of the FIFO + fill level parameter in the internal driver data base + from its default configuration [BMI_MAX_FIFO_SIZE] + + If the total number of buffers which are + currently in use and associated with the + specific RX port exceed this threshold, the + BMI will signal the MAC to send a pause frame + over the link. + + May be used for Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] fifoThreshold New value + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold); + +/**************************************************************************//** + @Function FM_PORT_ConfigRxFifoPriElevationLevel + + @Description Calling this routine changes the priority elevation level + parameter in the internal driver data base from its default + configuration [BMI_MAX_FIFO_SIZE] + + If the total number of buffers which are currently in use and + associated with the specific RX port exceed the amount specified + in priElevationLevel, BMI will signal the main FM's DMA to + elevate the FM priority on the system bus. + + May be used for Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] priElevationLevel New value + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, uint32_t priElevationLevel); + +/**************************************************************************//** + @Function FM_PORT_ConfigBufferPrefixContent + + @Description Defines the structure, size and content of the application buffer. + The prefix will + In Tx ports, if 'passPrsResult', the application + should set a value to their offsets in the prefix of + the FM will save the first 'privDataSize', than, + depending on 'passPrsResult' and 'passTimeStamp', copy parse result + and timeStamp, and the packet itself (in this order), to the + application buffer, and to offset. + Calling this routine changes the buffer margins definitions + in the internal driver data base from its default + configuration: Data size: [0] + Pass Parser result: [FALSE]. + Pass timestamp: [FALSE]. + + May be used for all ports + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in,out] p_FmPortBufferPrefixContent A structure of parameters describing the + structure of the buffer. + Out parameter: Start margin - offset + of data from start of external buffer. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigBufferPrefixContent(t_Handle h_FmPort, t_FmPortBufferPrefixContent *p_FmPortBufferPrefixContent); + + +/**************************************************************************//** + @Function FM_PORT_ConfigCheksumLastBytesIgnore + + @Description Calling this routine changes the number of checksum bytes to ignore + parameter in the internal driver data base from its default configuration + [0] + + May be used by Tx & Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] cheksumLastBytesIgnore New value + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, uint8_t cheksumLastBytesIgnore); + +/**************************************************************************//** + @Function FM_PORT_ConfigCutBytesFromEnd + + @Description Calling this routine changes the number of bytes to cut from a + frame's end parameter in the internal driver data base + from its default configuration [4] + Note that if the result of (frame length before chop - cutBytesFromEnd) is + less than 14 bytes, the chop operation is not executed. + + May be used for Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] cutBytesFromEnd New value + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, uint8_t cutBytesFromEnd); + +/**************************************************************************//** + @Function FM_PORT_ConfigPoolDepletion + + @Description Calling this routine enables pause frame generation depending on the + depletion status of BM pools. It also defines the conditions to activate + this functionality. By default, this functionality is disabled. + + May be used for Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_BufPoolDepletion A structure of pool depletion parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, t_FmPortBufPoolDepletion *p_BufPoolDepletion); + +/**************************************************************************//** + @Function FM_PORT_ConfigObservedPoolDepletion + + @Description Calling this routine enables a mechanism to stop port enqueue + depending on the depletion status of selected BM pools. + It also defines the conditions to activate + this functionality. By default, this functionality is disabled. + + Note: Available for some chips only + + May be used for Offline Parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_FmPortObservedBufPoolDepletion A structure of parameters for pool depletion. + + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigObservedPoolDepletion(t_Handle h_FmPort, t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion); + +/**************************************************************************//** + @Function FM_PORT_ConfigExtBufPools + + @Description This routine should be called for offline parsing ports + that internally use BM buffer pools. In such cases, e.g. for fragmentation and + re-assembly, the FM needs new BM buffers. By calling this routine the user + specifies the BM buffer pools that should be used. + + Note: Available for some chips only + + May be used for Offline Parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_FmPortExtPools A structure of parameters for the external pools. + + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmPortExtPools *p_FmPortExtPools); + +/**************************************************************************//** + @Function FM_PORT_ConfigBackupPools + + @Description Calling this routine allows the configuration of some of the BM pools + defined for this port as backup pools. + A pool configured to be a backup pool will be used only if all other + enabled non-backup pools are depleted. + + May be used for Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_FmPortBackupBmPools An array of pool id's. All pools specified here will + be defined as backup pools. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, t_FmPortBackupBmPools *p_FmPortBackupBmPools); + +/**************************************************************************//** + @Function FM_PORT_ConfigFrmDiscardOverride + + @Description Calling this routine changes the error frames destination parameter + in the internal driver data base from its default configuration: + override = [FALSE] + + May be used for Rx and offline parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] override TRUE to override dicarding of error frames and + enqueueing them to error queue. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override); + +/**************************************************************************//** + @Function FM_PORT_ConfigErrorsToDiscard + + @Description Calling this routine changes the behaviour on error parameter + in the internal driver data base from its default configuration: + [FM_PORT_FRM_ERR_CLS_DISCARD]. + If a requested error was previously defined as "ErrorsToEnqueue" it's + definition will change and the frame will be discarded. + Errors that were not defined either as "ErrorsToEnqueue" nor as + "ErrorsToDiscard", will be forwarded to CPU. + + + May be used for Rx and offline parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] errs A list of errors to discard + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, fmPortFrameErrSelect_t errs); + +/**************************************************************************//** + @Function FM_PORT_ConfigDmaSwapData + + @Description Calling this routine changes the DMA swap data aparameter + in the internal driver data base from its default + configuration [e_FM_PORT_DMA_NO_SWP] + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] swapData New selection + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmPortDmaSwap swapData); + +/**************************************************************************//** + @Function FM_PORT_ConfigDmaIcCacheAttr + + @Description Calling this routine changes the internal context cache + attribute parameter in the internal driver data base + from its default configuration [e_FM_PORT_DMA_NO_STASH] + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] intContextCacheAttr New selection + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, e_FmPortDmaCache intContextCacheAttr); + +/**************************************************************************//** + @Function FM_PORT_ConfigDmaHdrAttr + + @Description Calling this routine changes the header cache + attribute parameter in the internal driver data base + from its default configuration [e_FM_PORT_DMA_NO_STASH] + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] headerCacheAttr New selection + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, e_FmPortDmaCache headerCacheAttr); + +/**************************************************************************//** + @Function FM_PORT_ConfigDmaScatterGatherAttr + + @Description Calling this routine changes the scatter gather cache + attribute parameter in the internal driver data base + from its default configuration [e_FM_PORT_DMA_NO_STASH] + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] scatterGatherCacheAttr New selection + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDmaScatterGatherAttr(t_Handle h_FmPort, e_FmPortDmaCache scatterGatherCacheAttr); + +/**************************************************************************//** + @Function FM_PORT_ConfigDmaWriteOptimize + + @Description Calling this routine changes the write optimization + parameter in the internal driver data base + from its default configuration: optimize = [TRUE] + + May be used for non-Tx port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] optimize TRUE to enable optimization, FALSE for normal operation + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize); + +/**************************************************************************//** + @Function FM_PORT_ConfigDfltColor + + @Description Calling this routine changes the internal default color parameter + in the internal driver data base + from its default configuration [e_FM_PORT_COLOR_GREEN] + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] color New selection + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color); + +/**************************************************************************//** + @Function FM_PORT_ConfigSyncReq + + @Description Calling this routine changes the synchronization attribute parameter + in the internal driver data base from its default configuration: + syncReq = [TRUE] + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] syncReq TRUE to request synchronization, FALSE otherwize. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq); + +/**************************************************************************//** + @Function FM_PORT_ConfigForwardReuseIntContext + + @Description This routine is relevant for Rx ports that are routed to offline + parsing. It changes the internal context reuse option + in the internal driver data base from its default configuration: + reuse = [FALSE] + + May be used for Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] reuse TRUE to reuse internal context on frames + forwarded to offline parsing. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, bool reuse); + +/**************************************************************************//** + @Function FM_PORT_ConfigDontReleaseTxBufToBM + + @Description This routine should be called if no Tx confirmation + is done, and yet buffers should not be released to the BM. + Normally, buffers are returned using the Tx confirmation + process. When Tx confirmation is not used (defFqid=0), + buffers are typically released to the BM. This routine + may be called to avoid this behavior and not release the + buffers. + + May be used for Tx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_ConfigIMMaxRxBufLength + + @Description Changes the maximum receive buffer length from its default + configuration: Closest rounded down power of 2 value of the + data buffer size. + + The maximum receive buffer length directly affects the structure + of received frames (single- or multi-buffered) and the performance + of both the FM and the driver. + + The selection between single- or multi-buffered frames should be + done according to the characteristics of the specific application. + The recommended mode is to use a single data buffer per packet, + as this mode provides the best performance. However, the user can + select to use multiple data buffers per packet. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] newVal Maximum receive buffer length (in bytes). + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). + This routine is to be used only if Independent-Mode is enabled. +*//***************************************************************************/ +t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal); + +/**************************************************************************//** + @Function FM_PORT_ConfigIMRxBdRingLength + + @Description Changes the receive BD ring length from its default + configuration:[128] + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] newVal The desired BD ring length. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). + This routine is to be used only if Independent-Mode is enabled. +*//***************************************************************************/ +t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal); + +/**************************************************************************//** + @Function FM_PORT_ConfigIMTxBdRingLength + + @Description Changes the transmit BD ring length from its default + configuration:[16] + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] newVal The desired BD ring length. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). + This routine is to be used only if Independent-Mode is enabled. +*//***************************************************************************/ +t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal); + +/**************************************************************************//** + @Function FM_PORT_ConfigIMFmanCtrlExternalStructsMemory + + @Description Configures memory partition and attributes for FMan-Controller + data structures (e.g. BD rings). + Calling this routine changes the internal driver data base + from its default configuration + [0 , MEMORY_ATTR_CACHEABLE]. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] memId Memory partition ID. + @Param[in] memAttributes Memory attributes mask (a combination of MEMORY_ATTR_x flags). + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, + uint8_t memId, + uint32_t memAttributes); + +/**************************************************************************//** + @Function FM_PORT_ConfigIMPolling + + @Description Changes the Rx flow from interrupt driven (default) to polling. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). + This routine is to be used only if Independent-Mode is enabled. +*//***************************************************************************/ +t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort); + +/** @} */ /* end of FM_PORT_advanced_init_grp group */ +/** @} */ /* end of FM_PORT_init_grp group */ + + +/**************************************************************************//** + @Group FM_PORT_runtime_control_grp FM Port Runtime Control Unit + + @Description FM Port Runtime control unit API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description enum for defining FM Port counters +*//***************************************************************************/ +typedef enum e_FmPortCounters { + e_FM_PORT_COUNTERS_CYCLE, /**< BMI performance counter */ + e_FM_PORT_COUNTERS_TASK_UTIL, /**< BMI performance counter */ + e_FM_PORT_COUNTERS_QUEUE_UTIL, /**< BMI performance counter */ + e_FM_PORT_COUNTERS_DMA_UTIL, /**< BMI performance counter */ + e_FM_PORT_COUNTERS_FIFO_UTIL, /**< BMI performance counter */ + e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION, /**< BMI Rx only performance counter */ + e_FM_PORT_COUNTERS_FRAME, /**< BMI statistics counter */ + e_FM_PORT_COUNTERS_DISCARD_FRAME, /**< BMI statistics counter */ + e_FM_PORT_COUNTERS_DEALLOC_BUF, /**< BMI deallocate buffer statistics counter */ + e_FM_PORT_COUNTERS_RX_BAD_FRAME, /**< BMI Rx only statistics counter */ + e_FM_PORT_COUNTERS_RX_LARGE_FRAME, /**< BMI Rx only statistics counter */ + e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, /**< BMI Rx only statistics counter */ + e_FM_PORT_COUNTERS_RX_FILTER_FRAME, /**< BMI Rx & OP only statistics counter */ + e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR, /**< BMI Rx, OP & HC only statistics counter */ + e_FM_PORT_COUNTERS_WRED_DISCARD, /**< BMI OP & HC only statistics counter */ + e_FM_PORT_COUNTERS_LENGTH_ERR, /**< BMI non-Rx statistics counter */ + e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, /**< BMI non-Rx statistics counter */ + e_FM_PORT_COUNTERS_DEQ_TOTAL, /**< QMI counter */ + e_FM_PORT_COUNTERS_ENQ_TOTAL, /**< QMI counter */ + e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI counter */ + e_FM_PORT_COUNTERS_DEQ_CONFIRM /**< QMI counter */ +} e_FmPortCounters; + +/**************************************************************************//** + @Description Structure for Port id parameters. + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. +*//***************************************************************************/ +typedef struct t_FmPortCongestionGrps { + uint16_t numOfCongestionGrpsToConsider; /**< The number of required congestion groups + to define the size of the following array */ + uint8_t congestionGrpsToConsider[FM_PORT_NUM_OF_CONGESTION_GRPS]; + /**< An array of 'numOfCongestionGrpsToConsider' + describing the groups */ +} t_FmPortCongestionGrps; + + + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/**************************************************************************//** + @Function FM_PORT_DumpRegs + + @Description Dump all regs. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmPort - FM PORT module descriptor + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_DumpRegs(t_Handle h_FmPort); +#endif /* (defined(DEBUG_ERRORS) && ... */ + +/**************************************************************************//** + @Function FM_PORT_GetBufferDataOffset + + @Description Relevant for Rx ports. + Returns the data offset from the beginning of the data buffer + + @Param[in] h_FmPort - FM PORT module descriptor + + @Return data offset. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_GetBufferICInfo + + @Description Returns the Internal Context offset from the beginning of the data buffer + + @Param[in] h_FmPort - FM PORT module descriptor + @Param[in] p_Data - A pointer to the data buffer. + + @Return Internal context info pointer on success, NULL if 'allOtherInfo' was not + configured for this port. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data); + +#ifdef DEBUG +/**************************************************************************//** + @Function FM_PORT_GetBufferDebugInfo + + @Description Returns the debug info offset from the beginning of the data buffer + + @Param[in] h_FmPort - FM PORT module descriptor + @Param[in] p_Data - A pointer to the data buffer. + + @Return Debug info pointer on success, NULL if 'passDebugInfo' was not + configured for this port. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +uint8_t * FM_PORT_GetBufferDebugInfo(t_Handle h_FmPort, char *p_Data); +#endif /* DEBUG */ + +/**************************************************************************//** + @Function FM_PORT_GetBufferPrsResult + + @Description Returns the pointer to the parse result in the data buffer. + In Rx ports this is relevant after reception, if parse + result is configured to be part of the data passed to the + application. For non Rx ports it may be used to get the pointer + of the area in the buffer where parse result should be + initialized - if so configured. + See FM_PORT_ConfigBufferPrefixContent for data buffer prefix + configuration. + + @Param[in] h_FmPort - FM PORT module descriptor + @Param[in] p_Data - A pointer to the data buffer. + + @Return Parse result pointer on success, NULL if parse result was not + configured for this port. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data); + +/**************************************************************************//** + @Function FM_PORT_GetBufferTimeStamp + + @Description Returns the time stamp in the data buffer. + Relevant for Rx ports for getting the buffer time stamp. + See FM_PORT_ConfigBufferPrefixContent for data buffer prefix + configuration. + + @Param[in] h_FmPort - FM PORT module descriptor + @Param[in] p_Data - A pointer to the data buffer. + + @Return A pointer to the hash result on success, NULL otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data); + +/**************************************************************************//** + @Function FM_PORT_GetBufferHashResult + + @Description Given a data buffer, on the condition that hash result was defined + as a part of the buffer content (see FM_PORT_ConfigBufferPrefixContent) + this routine will return the pointer to the hash result location in the + buffer prefix. + + @Param[in] h_FmPort - FM PORT module descriptor + @Param[in] p_Data - A pointer to the data buffer. + + @Return A pointer to the hash result on success, NULL otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data); + +/**************************************************************************//** + @Function FM_PORT_Disable + + @Description Gracefully disable an FM port. The port will not start new tasks after all + tasks associated with the port are terminated. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). + This is a blocking routine, it returns after port is + gracefully stopped, i.e. the port will not except new frames, + but it will finish all frames or tasks which were already began +*//***************************************************************************/ +t_Error FM_PORT_Disable(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_Enable + + @Description A runtime routine provided to allow disable/enable of port. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_Enable(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_SetRateLimit + + @Description Calling this routine enables rate limit algorithm. + By default, this functionality is disabled. + Note that rate-limit mechanism uses the FM time stamp. + The selected rate limit specified here would be + rounded DOWN to the nearest 16M. + + May be used for Tx and offline parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_RateLimit A structure of rate limit parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit); + +/**************************************************************************//** + @Function FM_PORT_DeleteRateLimit + + @Description Calling this routine disables and clears rate limit + initialization. + + May be used for Tx and offline parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_SetStatisticsCounters + + @Description Calling this routine enables/disables port's statistics counters. + By default, counters are enabled. + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] enable TRUE to enable, FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable); + +/**************************************************************************//** + @Function FM_PORT_SetFrameQueueCounters + + @Description Calling this routine enables/disables port's enqueue/dequeue counters. + By default, counters are enabled. + + May be used for all ports + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] enable TRUE to enable, FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable); + +/**************************************************************************//** + @Function FM_PORT_SetPerformanceCounters + + @Description Calling this routine enables/disables port's performance counters. + By default, counters are enabled. + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] enable TRUE to enable, FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable); + +/**************************************************************************//** + @Function FM_PORT_SetPerformanceCounters + + @Description Calling this routine defines port's performance + counters parameters. + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_FmPortPerformanceCnt A pointer to a structure of performance + counters parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetPerformanceCountersParams(t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt); + +/**************************************************************************//** + @Function FM_PORT_AnalyzePerformanceParams + + @Description User may call this routine to so the driver will analyze if the + basic performance parameters are correct and also the driver may + suggest of improvments; The basic parameters are FIFO sizes, number + of DMAs and number of TNUMs for the port. + + May be used for all port types + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_SetNumOfOpenDmas + + @Description Calling this routine updates the number of open DMA requested for + this port. + + + May be used for all port types. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_NumOfOpenDmas A structure of resource requested parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfOpenDmas); + +/**************************************************************************//** + @Function FM_PORT_SetNumOfTasks + + @Description Calling this routine updates the number of tasks requested for + this port. + + May be used for all port types. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_NumOfTasks A structure of resource requested parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks); + +/**************************************************************************//** + @Function FM_PORT_SetSizeOfFifo + + @Description Calling this routine updates the Fifo size resource requested for + this port. + + May be used for all port types - note that only Rx has 'extra' + fifo size. For other ports 'extra' field must be disabled. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_SizeOfFifo A structure of resource requested parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo); + +/**************************************************************************//** + @Function FM_PORT_SetAllocBufCounter + + @Description Calling this routine enables/disables BM pool allocate + buffer counters. + By default, counters are enabled. + + May be used for Rx ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] poolId BM pool id. + @Param[in] enable TRUE to enable, FALSE to disable. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, bool enable); + +/**************************************************************************//** + @Function FM_PORT_GetCounter + + @Description Reads one of the FM PORT counters. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] fmPortCounter The requested counter. + + @Return Counter's current value. + + @Cautions Allowed only following FM_PORT_Init(). + Note that it is user's responsibility to call this routine only + for enabled counters, and there will be no indication if a + disabled counter is accessed. +*//***************************************************************************/ +uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter); + +/**************************************************************************//** + @Function FM_PORT_ModifyCounter + + @Description Sets a value to an enabled counter. Use "0" to reset the counter. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] fmPortCounter The requested counter. + @Param[in] value The requested value to be written into the counter. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter, uint32_t value); + +/**************************************************************************//** + @Function FM_PORT_GetAllocBufCounter + + @Description Reads one of the FM PORT buffer counters. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] poolId The requested pool. + + @Return Counter's current value. + + @Cautions Allowed only following FM_PORT_Init(). + Note that it is user's responsibility to call this routine only + for enabled counters, and there will be no indication if a + disabled counter is accessed. +*//***************************************************************************/ +uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId); + +/**************************************************************************//** + @Function FM_PORT_ModifyAllocBufCounter + + @Description Sets a value to an enabled counter. Use "0" to reset the counter. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] poolId The requested pool. + @Param[in] value The requested value to be written into the counter. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, uint32_t value); + +/**************************************************************************//** + @Function FM_PORT_AddCongestionGrps + + @Description This routine effects the corresponding Tx port. + It should be called in order to enable pause + frame transmission in case of congestion in one or more + of the congestion groups relevant to this port. + Each call to this routine may add one or more congestion + groups to be considered relevant to this port. + + May be used for Rx, or RX+OP ports only (depending on chip) + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_CongestionGrps A pointer to an array of congestion groups + id's to consider. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps); + +/**************************************************************************//** + @Function FM_PORT_RemoveCongestionGrps + + @Description This routine effects the corresponding Tx port. It should be + called when congestion groups were + defined for this port and are no longer relevant, or pause + frames transmitting is not required on their behalf. + Each call to this routine may remove one or more congestion + groups to be considered relevant to this port. + + May be used for Rx, or RX+OP ports only (depending on chip) + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_CongestionGrps A pointer to an array of congestion groups + id's to consider. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps); + +/**************************************************************************//** + @Function FM_PORT_IsStalled + + @Description A routine for checking whether the specified port is stalled. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return TRUE if port is stalled, FALSE otherwize + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +bool FM_PORT_IsStalled(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_ReleaseStalled + + @Description This routine may be called in case the port was stalled and may + now be released. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_SetRxL4ChecksumVerify + + @Description This routine is relevant for Rx ports (1G and 10G). The routine + set/clear the L3/L4 checksum verification (on RX side). + Note that this takes affect only if hw-parser is enabled! + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] l4Checksum boolean indicates whether to do L3/L4 checksum + on frames or not. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum); + +/**************************************************************************//** + @Function FM_PORT_SetErrorsRoute + + @Description Errors selected for this routine will cause a frame with that error + to be enqueued to error queue. + Errors not selected for this routine will cause a frame with that error + to be enqueued to the one of the other port queues. + By default all errors are defined to be enqueued to error queue. + Errors that were configured to be discarded (at initialization) + may not be selected here. + + May be used for Rx and offline parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] errs A list of errors to enqueue to error queue + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs); + +/**************************************************************************//** + @Function FM_PORT_SetIMExceptions + + @Description Calling this routine enables/disables FM PORT interrupts. + Note: Not available for guest partition. + + @Param[in] h_FmPort FM PORT module descriptor. + @Param[in] exception The exception to be selected. + @Param[in] enable TRUE to enable interrupt, FALSE to mask it. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable); + + + +/**************************************************************************//** + @Group FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime Control Unit + + @Description FM Port PCD Runtime control unit API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description A structure defining the KG scheme after the parser. + This is relevant only to change scheme selection mode - from + direct to indirect and vice versa, or when the scheme is selected directly, + to select the scheme id. + +*//***************************************************************************/ +typedef struct t_FmPcdKgSchemeSelect { + bool direct; /**< TRUE to use 'h_Scheme' directly, FALSE to use LCV.*/ + t_Handle h_DirectScheme; /**< Relevant for 'direct'=TRUE only. + 'h_DirectScheme' selects the scheme after parser. */ +} t_FmPcdKgSchemeSelect; + +/**************************************************************************//** + @Description A structure of scheme parameters +*//***************************************************************************/ +typedef struct t_FmPcdPortSchemesParams { + uint8_t numOfSchemes; /**< Number of schemes for port to be bound to. */ + t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; /**< Array of 'numOfSchemes' schemes for the + port to be bound to */ +} t_FmPcdPortSchemesParams; + +/**************************************************************************//** + @Description Union for defining port protocol parameters for parser +*//***************************************************************************/ +typedef union u_FmPcdHdrPrsOpts { + /* MPLS */ + struct { + bool labelInterpretationEnable; /**< When this bit is set, the last MPLS label will be + interpreted as described in HW spec table. When the bit + is cleared, the parser will advance to MPLS next parse */ + e_NetHeaderType nextParse; /**< must be equal or higher than IPv4 */ + } mplsPrsOptions; + /* VLAN */ + struct { + uint16_t tagProtocolId1; /**< User defined Tag Protocol Identifier, to be recognized + on VLAN TAG on top of 0x8100 and 0x88A8 */ + uint16_t tagProtocolId2; /**< User defined Tag Protocol Identifier, to be recognized + on VLAN TAG on top of 0x8100 and 0x88A8 */ + } vlanPrsOptions; + /* PPP */ + struct{ + bool enableMTUCheck; /**< Check validity of MTU according to RFC2516 */ + } pppoePrsOptions; + + /* IPV6 */ + struct{ + bool routingHdrDisable; /**< Disable routing header */ + } ipv6PrsOptions; + + /* UDP */ + struct{ + bool padIgnoreChecksum; /**< TRUE to ignore pad in checksum */ + } udpPrsOptions; + + /* TCP */ + struct { + bool padIgnoreChecksum; /**< TRUE to ignore pad in checksum */ + } tcpPrsOptions; +} u_FmPcdHdrPrsOpts; + +/**************************************************************************//** + @Description A structure for defining each header for the parser +*//***************************************************************************/ +typedef struct t_FmPcdPrsAdditionalHdrParams { + e_NetHeaderType hdr; /**< Selected header */ + bool errDisable; /**< TRUE to disable error indication */ + bool swPrsEnable; /**< Enable jump to SW parser when this + header is recognized by the HW parser. */ + uint8_t indexPerHdr; /**< Normally 0, if more than one sw parser + attachments exists for the same header, + (in the main sw parser code) use this + index to distinguish between them. */ + bool usePrsOpts; /**< TRUE to use parser options. */ + u_FmPcdHdrPrsOpts prsOpts; /**< A union according to header type, + defining the parser options selected.*/ +} t_FmPcdPrsAdditionalHdrParams; + +/**************************************************************************//** + @Description struct for defining port PCD parameters +*//***************************************************************************/ +typedef struct t_FmPortPcdPrsParams { + uint8_t prsResultPrivateInfo; /**< The private info provides a method of inserting + port information into the parser result. This information + may be extracted by Keygen and be used for frames + distribution when a per-port distinction is required, + it may also be used as a port logical id for analyzing + incoming frames. */ + uint8_t parsingOffset; /**< Number of bytes from beginning of packet to start parsing */ + e_NetHeaderType firstPrsHdr; /**< The type of the first header expected at 'parsingOffset' */ + bool includeInPrsStatistics; /**< TRUE to include this port in the parser statistics; + NOTE: this field is not valid when the FN is in "guest" mode. */ + uint8_t numOfHdrsWithAdditionalParams; /**< Normally 0, some headers may get + special parameters */ + t_FmPcdPrsAdditionalHdrParams additionalParams[FM_PCD_PRS_NUM_OF_HDRS]; + /**< 'numOfHdrsWithAdditionalParams' structures + of additional parameters + for each header that requires them */ + bool setVlanTpid1; /**< TRUE to configure user selection of Ethertype to + indicate a VLAN tag (in addition to the TPID values + 0x8100 and 0x88A8). */ + uint16_t vlanTpid1; /**< extra tag to use if setVlanTpid1=TRUE. */ + bool setVlanTpid2; /**< TRUE to configure user selection of Ethertype to + indicate a VLAN tag (in addition to the TPID values + 0x8100 and 0x88A8). */ + uint16_t vlanTpid2; /**< extra tag to use if setVlanTpid1=TRUE. */ +} t_FmPortPcdPrsParams; + +/**************************************************************************//** + @Description struct for defining coarse alassification parameters +*//***************************************************************************/ +typedef struct t_FmPortPcdCcParams { + t_Handle h_CcTree; /**< A handle to a CC tree */ +} t_FmPortPcdCcParams; + +/**************************************************************************//** + @Description struct for defining keygen parameters +*//***************************************************************************/ +typedef struct t_FmPortPcdKgParams { + uint8_t numOfSchemes; /**< Number of schemes for port to be bound to. */ + t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; + /**< Array of 'numOfSchemes' schemes handles for the + port to be bound to */ + bool directScheme; /**< TRUE for going from parser to a specific scheme, + regardless of parser result */ + t_Handle h_DirectScheme; /**< relevant only if direct == TRUE, Scheme handle, + as returned by FM_PCD_KgSetScheme */ +} t_FmPortPcdKgParams; + +/**************************************************************************//** + @Description struct for defining policer parameters +*//***************************************************************************/ +typedef struct t_FmPortPcdPlcrParams { + t_Handle h_Profile; /**< Selected profile handle; Relevant for one of + following cases: + e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or + e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR were selected, + or if any flow uses a KG scheme were policer + profile is not generated + (bypassPlcrProfileGeneration selected) */ +} t_FmPortPcdPlcrParams; + +/**************************************************************************//** + @Description struct for defining port PCD parameters +*//***************************************************************************/ +typedef struct t_FmPortPcdParams { + e_FmPortPcdSupport pcdSupport; /**< Relevant for Rx and offline ports only. + Describes the active PCD engines for this port. */ + t_Handle h_NetEnv; /**< HL Unused in PLCR only mode */ + t_FmPortPcdPrsParams *p_PrsParams; /**< Parser parameters for this port */ + t_FmPortPcdCcParams *p_CcParams; /**< Coarse classification parameters for this port */ + t_FmPortPcdKgParams *p_KgParams; /**< Keygen parameters for this port */ + t_FmPortPcdPlcrParams *p_PlcrParams; /**< Policer parameters for this port */ +} t_FmPortPcdParams; + +/**************************************************************************//** + @Description A structure for defining the Parser starting point +*//***************************************************************************/ +typedef struct t_FmPcdPrsStart { + uint8_t parsingOffset; /**< Number of bytes from beginning of packet to + start parsing */ + e_NetHeaderType firstPrsHdr; /**< The type of the first header axpected at + 'parsingOffset' */ +} t_FmPcdPrsStart; + + +/**************************************************************************//** + @Function FM_PORT_SetPCD + + @Description Calling this routine defines the port's PCD configuration. + It changes it from its default configuration which is PCD + disabled (BMI to BMI) and configures it according to the passed + parameters. + + May be used for Rx and offline parsing ports only + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_FmPortPcd A Structure of parameters defining the port's PCD + configuration. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_FmPortPcd); + +/**************************************************************************//** + @Function FM_PORT_DeletePCD + + @Description Calling this routine releases the port's PCD configuration. + The port returns to its default configuration which is PCD + disabled (BMI to BMI) and all PCD configuration is removed. + + May be used for Rx and offline parsing ports which are + in PCD mode only + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_DeletePCD(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_AttachPCD + + @Description This routine may be called after FM_PORT_DetachPCD was called, + to return to the originally configured PCD support flow. + The couple of routines are used to allow PCD configuration changes + that demand that PCD will not be used while changes take place. + + May be used for Rx and offline parsing ports which are + in PCD mode only + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +t_Error FM_PORT_AttachPCD(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_DetachPCD + + @Description Calling this routine detaches the port from its PCD functionality. + The port returns to its default flow which is BMI to BMI. + + May be used for Rx and offline parsing ports which are + in PCD mode only + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_AttachPCD(). +*//***************************************************************************/ +t_Error FM_PORT_DetachPCD(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_PcdPlcrAllocProfiles + + @Description This routine may be called only for ports that use the Policer in + order to allocate private policer profiles. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] numOfProfiles The number of required policer profiles + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(), and before FM_PORT_SetPCD(). +*//***************************************************************************/ +t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles); + +/**************************************************************************//** + @Function FM_PORT_PcdPlcrFreeProfiles + + @Description This routine should be called for freeing private policer profiles. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(), and before FM_PORT_SetPCD(). +*//***************************************************************************/ +t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_PcdKgModifyInitialScheme + + @Description This routine may be called only for ports that use the keygen in + order to change the initial scheme frame should be routed to. + The change may be of a scheme id (in case of direct mode), + from direct to indirect, or from indirect to direct - specifying the scheme id. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_FmPcdKgScheme A structure of parameters for defining whether + a scheme is direct/indirect, and if direct - scheme id. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). +*//***************************************************************************/ +t_Error FM_PORT_PcdKgModifyInitialScheme (t_Handle h_FmPort, t_FmPcdKgSchemeSelect *p_FmPcdKgScheme); + +/**************************************************************************//** + @Function FM_PORT_PcdPlcrModifyInitialProfile + + @Description This routine may be called for ports with flows + e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR + only, to change the initial Policer profile frame should be + routed to. The change may be of a profile and/or absolute/direct + mode selection. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] h_Profile Policer profile handle + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). +*//***************************************************************************/ +t_Error FM_PORT_PcdPlcrModifyInitialProfile (t_Handle h_FmPort, t_Handle h_Profile); + +/**************************************************************************//** + @Function FM_PORT_PcdCcModifyTree + + @Description This routine may be called for ports that use coarse classification tree + if the user wishes to replace the tree. The routine may not be called while port + receives packets using the PCD functionalities, therefor port must be first detached + from the PCD, only than the routine may be called, and than port be attached to PCD again. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] h_CcTree A CC tree that was already built. The tree id as returned from + the BuildTree routine. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(), FM_PORT_SetPCD() and FM_PORT_DetachPCD() +*//***************************************************************************/ +t_Error FM_PORT_PcdCcModifyTree (t_Handle h_FmPort, t_Handle h_CcTree); + +/**************************************************************************//** + @Function FM_PORT_PcdKgBindSchemes + + @Description These routines may be called for adding more schemes for the + port to be bound to. The selected schemes are not added, + just this specific port starts using them. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_PortScheme A structure defining the list of schemes to be added. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). +*//***************************************************************************/ +t_Error FM_PORT_PcdKgBindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme); + +/**************************************************************************//** + @Function FM_PORT_PcdKgUnbindSchemes + + @Description These routines may be called for adding more schemes for the + port to be bound to. The selected schemes are not removed or invalidated, + just this specific port stops using them. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_PortScheme A structure defining the list of schemes to be added. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). +*//***************************************************************************/ +t_Error FM_PORT_PcdKgUnbindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme); + +/**************************************************************************//** + @Function FM_PORT_PcdPrsModifyStartOffset + + @Description Runtime change of the parser start offset within the header. + The routine may not be called while port + receives packets using the PCD functionalities, therefore port must be first detached + from the PCD, only than the routine may be called, and than port be attached to PCD again. + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_FmPcdPrsStart A structure of parameters for defining the + start point for the parser. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(), FM_PORT_SetPCD() and FM_PORT_DetatchPCD(). +*//***************************************************************************/ +t_Error FM_PORT_PcdPrsModifyStartOffset (t_Handle h_FmPort, t_FmPcdPrsStart *p_FmPcdPrsStart); + +/** @} */ /* end of FM_PORT_pcd_runtime_control_grp group */ +/** @} */ /* end of FM_PORT_runtime_control_grp group */ + + +/**************************************************************************//** + @Group FM_PORT_runtime_data_grp FM Port Runtime Data-path Unit + + @Description FM Port Runtime data unit API functions, definitions and enums. + This API is valid only if working in Independent-Mode. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function FM_PORT_ImTx + + @Description Tx function, called to transmit a data buffer on the port. + + @Param[in] h_FmPort A handle to a FM Port module. + @Param[in] p_Data A pointer to an LCP data buffer. + @Param[in] length Size of data for transmission. + @Param[in] lastBuffer Buffer position - TRUE for the last buffer + of a frame, including a single buffer frame + @Param[in] h_BufContext A handle of the user acossiated with this buffer + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). + NOTE - This routine can be used only when working in + Independent-Mode mode. +*//***************************************************************************/ +t_Error FM_PORT_ImTx( t_Handle h_FmPort, + uint8_t *p_Data, + uint16_t length, + bool lastBuffer, + t_Handle h_BufContext); + +/**************************************************************************//** + @Function FM_PORT_ImTxConf + + @Description Tx port confirmation routine, optional, may be called to verify + transmission of all frames. The procedure performed by this + routine will be performed automatically on next buffer transmission, + but if desired, calling this routine will invoke this action on + demand. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Cautions Allowed only following FM_PORT_Init(). + NOTE - This routine can be used only when working in + Independent-Mode mode. +*//***************************************************************************/ +void FM_PORT_ImTxConf(t_Handle h_FmPort); + +/**************************************************************************//** + @Function FM_PORT_ImRx + + @Description Rx function, may be called to poll for received buffers. + Normally, Rx process is invoked by the driver on Rx interrupt. + Alternatively, this routine may be called on demand. + + @Param[in] h_FmPort A handle to a FM Port module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). + NOTE - This routine can be used only when working in + Independent-Mode mode. +*//***************************************************************************/ +t_Error FM_PORT_ImRx(t_Handle h_FmPort); + +/** @} */ /* end of FM_PORT_runtime_data_grp group */ +/** @} */ /* end of FM_PORT_grp group */ +/** @} */ /* end of FM_grp group */ + + + + +#endif /* __FM_PORT_EXT */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_rtc_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_rtc_ext.h @@ -0,0 +1,592 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_rtc_ext.h + + @Description External definitions and API for FM RTC IEEE1588 Timer Module. + + @Cautions None. +*//***************************************************************************/ + +#ifndef __FM_RTC_EXT_H__ +#define __FM_RTC_EXT_H__ + + +#include "error_ext.h" +#include "std_ext.h" + + +/**************************************************************************//** + + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group fm_rtc_grp FM RTC + + @Description FM RTC functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group fm_rtc_init_grp FM RTC Initialization Unit + + @Description FM RTC initialization API. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description FM RTC Alarm Polarity Options. +*//***************************************************************************/ +typedef enum e_FmRtcAlarmPolarity +{ + e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH, /**< Active-high output polarity */ + e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW /**< Active-low output polarity */ +} e_FmRtcAlarmPolarity; + +/**************************************************************************//** + @Description FM RTC Trigger Polarity Options. +*//***************************************************************************/ +typedef enum e_FmRtcTriggerPolarity +{ + e_FM_RTC_TRIGGER_ON_RISING_EDGE, /**< Trigger on rising edge */ + e_FM_RTC_TRIGGER_ON_FALLING_EDGE /**< Trigger on falling edge */ +} e_FmRtcTriggerPolarity; + +/**************************************************************************//** + @Description IEEE1588 Timer Module FM RTC Optional Clock Sources. +*//***************************************************************************/ +typedef enum e_FmSrcClock +{ + e_FM_RTC_SOURCE_CLOCK_EXTERNAL, /**< external high precision timer reference clock */ + e_FM_RTC_SOURCE_CLOCK_SYSTEM, /**< MAC system clock */ + e_FM_RTC_SOURCE_CLOCK_OSCILATOR /**< RTC clock oscilator */ +}e_FmSrcClk; + +/**************************************************************************//** + @Description FM RTC configuration parameters structure. + + This structure should be passed to FM_RTC_Config(). +*//***************************************************************************/ +typedef struct t_FmRtcParams +{ + t_Handle h_Fm; /**< FM Handle*/ + uintptr_t baseAddress; /**< Base address of FM RTC registers */ + t_Handle h_App; /**< A handle to an application layer object; This handle will + be passed by the driver upon calling the above callbacks */ +} t_FmRtcParams; + + +/**************************************************************************//** + @Function FM_RTC_Config + + @Description Configures the FM RTC module according to user's parameters. + + The driver assigns default values to some FM RTC parameters. + These parameters can be overwritten using the advanced + configuration routines. + + @Param[in] p_FmRtcParam - FM RTC configuration parameters. + + @Return Handle to the new FM RTC object; NULL pointer on failure. + + @Cautions None +*//***************************************************************************/ +t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam); + +/**************************************************************************//** + @Function FM_RTC_Init + + @Description Initializes the FM RTC driver and hardware. + + @Param[in] h_FmRtc - Handle to FM RTC object. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_Init(t_Handle h_FmRtc); + +/**************************************************************************//** + @Function FM_RTC_Free + + @Description Frees the FM RTC object and all allocated resources. + + @Param[in] h_FmRtc - Handle to FM RTC object. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_Free(t_Handle h_FmRtc); + + +/**************************************************************************//** + @Group fm_rtc_adv_config_grp FM RTC Advanced Configuration Unit + + @Description FM RTC advanced configuration functions. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function FM_RTC_ConfigPeriod + + @Description Configures the period of the timestamp if different than + default [1000]. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] period - Period in nano-seconds. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period); + +/**************************************************************************//** + @Function FM_RTC_ConfigSourceClock + + @Description Configures the source clock of the RTC. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] srcClk - Source clock selection. + @Param[in] freqInMhz - the source-clock frequency (in MHz). + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc, + e_FmSrcClk srcClk, + uint32_t freqInMhz); + +/**************************************************************************//** + @Function FM_RTC_ConfigPulseRealignment + + @Description Configures the RTC to automatic FIPER pulse realignment in + response to timer adjustments [FALSE] + + In this mode, the RTC clock is identical to the source clock. + This feature can be useful when the system contains an external + RTC with inherent frequency compensation. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] enable - TRUE to enable automatic realignment. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable); + +/**************************************************************************//** + @Function FM_RTC_ConfigFrequencyBypass + + @Description Configures the RTC to bypass the frequency compensation + mechanism. [FALSE] + + In this mode, the RTC clock is identical to the source clock. + This feature can be useful when the system contains an external + RTC with inherent frequency compensation. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] enabled - TRUE to bypass frequency compensation; + FALSE otherwise. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled); + +/**************************************************************************//** + @Function FM_RTC_ConfigInvertedInputClockPhase + + @Description Configures the RTC to invert the source clock phase on input. + [FALSE] + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] inverted - TRUE to invert the source clock phase on input. + FALSE otherwise. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted); + +/**************************************************************************//** + @Function FM_RTC_ConfigInvertedOutputClockPhase + + @Description Configures the RTC to invert the output clock phase. + [FALSE] + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] inverted - TRUE to invert the output clock phase. + FALSE otherwise. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted); + +/**************************************************************************//** + @Function FM_RTC_ConfigOutputClockDivisor + + @Description Configures the divisor for generating the output clock from + the RTC clock. [0x00000002] + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] divisor - Divisor for generation of the output clock. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor); + +/**************************************************************************//** + @Function FM_RTC_ConfigAlarmPolarity + + @Description Configures the polarity (active-high/active-low) of a specific + alarm signal. [e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH] + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] alarmId - Alarm ID. + @Param[in] alarmPolarity - Alarm polarity. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc, + uint8_t alarmId, + e_FmRtcAlarmPolarity alarmPolarity); + +/**************************************************************************//** + @Function FM_RTC_ConfigExternalTriggerPolarity + + @Description Configures the polarity (rising/falling edge) of a specific + external trigger signal. [e_FM_RTC_TRIGGER_ON_FALLING_EDGE] + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] triggerId - Trigger ID. + @Param[in] triggerPolarity - Trigger polarity. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). +*//***************************************************************************/ +t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc, + uint8_t triggerId, + e_FmRtcTriggerPolarity triggerPolarity); + +/** @} */ /* end of fm_rtc_adv_config_grp */ +/** @} */ /* end of fm_rtc_init_grp */ + + +/**************************************************************************//** + @Group fm_rtc_control_grp FM RTC Control Unit + + @Description FM RTC runtime control API. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function t_FmRtcExceptionsCallback + + @Description Exceptions user callback routine, used for RTC different mechanisms. + + @Param[in] h_App - User's application descriptor. + @Param[in] id - source id. +*//***************************************************************************/ +typedef void (t_FmRtcExceptionsCallback) ( t_Handle h_App, uint8_t id); + +/**************************************************************************//** + @Description FM RTC alarm parameters. +*//***************************************************************************/ +typedef struct t_FmRtcAlarmParams { + uint8_t alarmId; /**< 0 or 1 */ + uint64_t alarmTime; /**< In nanoseconds, the time when the alarm + should go off - must be a multiple of + the RTC period */ + t_FmRtcExceptionsCallback *f_AlarmCallback; /**< This routine will be called when RTC + reaches alarmTime */ + bool clearOnExpiration; /**< TRUE to turn off the alarm once expired. */ +} t_FmRtcAlarmParams; + +/**************************************************************************//** + @Description FM RTC Periodic Pulse parameters. +*//***************************************************************************/ +typedef struct t_FmRtcPeriodicPulseParams { + uint8_t periodicPulseId; /**< 0 or 1 */ + uint64_t periodicPulsePeriod; /**< In Nanoseconds. Must be + a multiple of the RTC period */ + t_FmRtcExceptionsCallback *f_PeriodicPulseCallback; /**< This routine will be called every + periodicPulsePeriod. */ +} t_FmRtcPeriodicPulseParams; + +/**************************************************************************//** + @Description FM RTC Periodic Pulse parameters. +*//***************************************************************************/ +typedef struct t_FmRtcExternalTriggerParams { + uint8_t externalTriggerId; /**< 0 or 1 */ + bool usePulseAsInput; /**< Use the pulse interrupt instead of + an external signal */ + t_FmRtcExceptionsCallback *f_ExternalTriggerCallback; /**< This routine will be called every + periodicPulsePeriod. */ +} t_FmRtcExternalTriggerParams; + + +/**************************************************************************//** + @Function FM_RTC_Enable + + @Description Enable the RTC (time count is started). + + The user can select to resume the time count from previous + point, or to restart the time count. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] resetClock - Restart the time count from zero. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock); + +/**************************************************************************//** + @Function FM_RTC_Disable + + @Description Disables the RTC (time count is stopped). + + @Param[in] h_FmRtc - Handle to FM RTC object. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_Disable(t_Handle h_FmRtc); + +/**************************************************************************//** + @Function FM_RTC_SetClockOffset + + @Description Sets the clock offset (usually relative to another clock). + + The user can pass a negative offset value. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] offset - New clock offset (in nanoseconds). + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset); + +/**************************************************************************//** + @Function FM_RTC_SetAlarm + + @Description Schedules an alarm event to a given RTC time. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] p_FmRtcAlarmParams - Alarm parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). + Must be called only prior to FM_RTC_Enable(). +*//***************************************************************************/ +t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams); + +/**************************************************************************//** + @Function FM_RTC_SetPeriodicPulse + + @Description Sets a periodic pulse. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] p_FmRtcPeriodicPulseParams - Periodic pulse parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). + Must be called only prior to FM_RTC_Enable(). +*//***************************************************************************/ +t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams); + +/**************************************************************************//** + @Function FM_RTC_ClearPeriodicPulse + + @Description Clears a periodic pulse. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] periodicPulseId - Periodic pulse id. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId); + +/**************************************************************************//** + @Function FM_RTC_SetExternalTrigger + + @Description Sets an external trigger indication and define a callback + routine to be called on such event. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] p_FmRtcExternalTriggerParams - External Trigger parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams); + +/**************************************************************************//** + @Function FM_RTC_ClearExternalTrigger + + @Description Clears external trigger indication. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] id - External Trigger id. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t id); + +/**************************************************************************//** + @Function FM_RTC_GetExternalTriggerTimeStamp + + @Description Reads the External Trigger TimeStamp. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] triggerId - External Trigger id. + @Param[out] p_TimeStamp - External Trigger timestamp (in nanoseconds). + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc, + uint8_t triggerId, + uint64_t *p_TimeStamp); + +/**************************************************************************//** + @Function FM_RTC_GetCurrentTime + + @Description Returns the current RTC time. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[out] p_Ts - returned time stamp (in nanoseconds). + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts); + +/**************************************************************************//** + @Function FM_RTC_SetCurrentTime + + @Description Sets the current RTC time. + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] ts - The new time stamp (in nanoseconds). + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts); + +/**************************************************************************//** + @Function FM_RTC_GetFreqCompensation + + @Description TODO + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[out] p_Compensation - A pointer to the returned value of compensation. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation); + +/**************************************************************************//** + @Function FM_RTC_SetFreqCompensation + + @Description TODO + + @Param[in] h_FmRtc - Handle to FM RTC object. + @Param[in] freqCompensation - the new desired compensation value to be set. + + @Return E_OK on success; Error code otherwise. + + @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). +*//***************************************************************************/ +t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/**************************************************************************//** + @Function FM_RTC_DumpRegs + + @Description Dumps all FM registers + + @Param[in] h_FmRtc A handle to an FM RTC Module. + + @Return E_OK on success; + + @Cautions Allowed only FM_Init(). +*//***************************************************************************/ +t_Error FM_RTC_DumpRegs(t_Handle h_FmRtc); +#endif /* (defined(DEBUG_ERRORS) && ... */ + +/** @} */ /* end of fm_rtc_control_grp */ +/** @} */ /* end of fm_rtc_grp */ +/** @} */ /* end of FM_grp group */ + + +#endif /* __FM_RTC_EXT_H__ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_muram_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/fm_muram_ext.h @@ -0,0 +1,158 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_muram_ext.h + + @Description FM MURAM Application Programming Interface. +*//***************************************************************************/ +#ifndef __FM_MURAM_EXT +#define __FM_MURAM_EXT + +#include "error_ext.h" +#include "std_ext.h" + + +/**************************************************************************//** + + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_muram_grp FM MURAM + + @Description FM MURAM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_muram_init_grp FM MURAM Initialization + + @Description FM MURAM initialization API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function FM_MURAM_ConfigAndInit + + @Description Creates partition in the MURAM. + + The routine returns a handle (descriptor) to the MURAM partition. + This descriptor must be passed as first parameter to all other + FM-MURAM function calls. + + No actual initialization or configuration of FM_MURAM hardware is + done by this routine. + + @Param[in] baseAddress - Pointer to base of memory mapped FM-MURAM. + @Param[in] size - Size of the FM-MURAM partition. + + @Return Handle to FM-MURAM object, or NULL for Failure. +*//***************************************************************************/ +t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size); + +/**************************************************************************//** + @Function FM_MURAM_Free + + @Description Frees all resources that were assigned to FM-MURAM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmMuram - FM-MURAM module descriptor. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_MURAM_Free(t_Handle h_FmMuram); + +/** @} */ /* end of FM_muram_init_grp group */ + + +/**************************************************************************//** + @Group FM_muram_ctrl_grp FM MURAM Control + + @Description FM MURAM control API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Function FM_MURAM_AllocMem + + @Description Allocate some memory from FM-MURAM partition. + + @Param[in] h_FmMuram - FM-MURAM module descriptor. + @Param[in] size - size of the memory to be allocated. + @Param[in] align - Alignment of the memory. + + @Return address of the allocated memory; NULL otherwise. +*//***************************************************************************/ +void * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align); + +/**************************************************************************//** + @Function FM_MURAM_AllocMemForce + + @Description Allocate some specific memory from FM-MURAM partition (according + to base). + + @Param[in] h_FmMuram - FM-MURAM module descriptor. + @Param[in] base - the desired base-address to be allocated. + @Param[in] size - size of the memory to be allocated. + + @Return address of the allocated memory; NULL otherwise. +*//***************************************************************************/ +void * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size); + +/**************************************************************************//** + @Function FM_MURAM_FreeMem + + @Description Free an allocated memory from FM-MURAM partition. + + @Param[in] h_FmMuram - FM-MURAM module descriptor. + @Param[in] ptr - A pointer to an allocated memory. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr); + +/** @} */ /* end of FM_muram_ctrl_grp group */ +/** @} */ /* end of FM_muram_grp group */ +/** @} */ /* end of FM_grp group */ + + + +#endif /* __FM_MURAM_EXT */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/inc/Peripherals/mii_acc_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/inc/Peripherals/mii_acc_ext.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __MII_ACC_EXT_H +#define __MII_ACC_EXT_H + + +/**************************************************************************//** + @Function MII_ReadPhyReg + + @Description This routine is called to read a specified PHY + register value. + + @Param[in] h_MiiAccess - Handle to MII configuration access registers + @Param[in] phyAddr - PHY address (0-31). + @Param[in] reg - PHY register to read + @Param[out] p_Data - Gets the register value. + + @Return Always zero (success). +*//***************************************************************************/ +int MII_ReadPhyReg(t_Handle h_MiiAccess, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data); + +/**************************************************************************//** + @Function MII_WritePhyReg + + @Description This routine is called to write data to a specified PHY + register. + + @Param[in] h_MiiAccess - Handle to MII configuration access registers + @Param[in] phyAddr - PHY address (0-31). + @Param[in] reg - PHY register to write + @Param[in] data - Data to write in register. + + @Return Always zero (success). +*//***************************************************************************/ +int MII_WritePhyReg(t_Handle h_MiiAccess, + uint8_t phyAddr, + uint8_t reg, + uint16_t data); + + +#endif /* __MII_ACC_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/etc/memcpy.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/etc/memcpy.c @@ -0,0 +1,665 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "std_ext.h" +#include "xx_ext.h" +#include "memcpy_ext.h" + + +#ifdef CORE_8BIT_ACCESS_ERRATA +static void MY_MY_WRITE_UINT8(uint8_t *addr, uint8_t val) +{ + uint32_t newAddr, newVal; + newAddr = (uint32_t)addr & ~0x3L; + switch ((uint32_t)addr%4) + { + case (0): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0x00ffffff) | (((uint32_t)val)<<24); + WRITE_UINT32(*(uint32_t*)newAddr, newVal); + break; + case (1): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0xff00ffff) | (((uint32_t)val)<<16); + WRITE_UINT32(*(uint32_t*)newAddr, newVal); + break; + case (2): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0xffff00ff) | (((uint32_t)val)<<8); + WRITE_UINT32(*(uint32_t*)newAddr, newVal); + break; + case (3): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0xffffff00) | val; + WRITE_UINT32(*(uint32_t*)newAddr, newVal); + break; + } +} + +static uint8_t MY_MY_GET_UINT8(uint8_t *addr) +{ + uint32_t newAddr, newVal=0; + newAddr = (uint32_t)addr & ~0x3L; + switch ((uint32_t)addr%4) + { + case (0): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0xff000000)>>24; + break; + case (1): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0x00ff0000)>>16; + break; + case (2): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0x0000ff00)>>8; + break; + case (3): + newVal = GET_UINT32(*(uint32_t*)newAddr); + newVal = (newVal & 0x000000ff); + break; + } + + return (uint8_t)newVal; +} + +#define MY_WRITE_UINT8(addr,val) MY_MY_WRITE_UINT8(&addr,val) +#define MY_GET_UINT8(addr) MY_MY_GET_UINT8(&addr) +#else +#define MY_WRITE_UINT8 WRITE_UINT8 +#define MY_GET_UINT8 GET_UINT8 +#endif /* CORE_8BIT_ACCESS_ERRATA */ + + +void * MemCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + *p_Dst32++ = *p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = *p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = *p_Src32; + *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign); + lastWord = currWord; + p_Src32++; + p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + *p_Dst8++ = *p_Src8++; + + return pDst; +} + +void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + MY_WRITE_UINT8(*p_Dst8, MY_GET_UINT8(*p_Src8)); + p_Dst8++;p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + MY_WRITE_UINT8(*p_Dst8, MY_GET_UINT8(*p_Src8)); + p_Dst8++;p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + WRITE_UINT32(*p_Dst32, GET_UINT32(*p_Src32)); + p_Dst32++;p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = GET_UINT32(*p_Src32); + p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = GET_UINT32(*p_Src32); + WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign)); + lastWord = currWord; + p_Src32++;p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + { + MY_WRITE_UINT8(*p_Dst8, MY_GET_UINT8(*p_Src8)); + p_Dst8++;p_Src8++; + } + + return pDst; +} + +void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + MY_WRITE_UINT8(*p_Dst8, *p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + MY_WRITE_UINT8(*p_Dst8, *p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + WRITE_UINT32(*p_Dst32, *p_Src32); + p_Dst32++;p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = *p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = *p_Src32; + WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign)); + lastWord = currWord; + p_Src32++;p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + { + MY_WRITE_UINT8(*p_Dst8, *p_Src8); + p_Dst8++;p_Src8++; + } + + return pDst; +} + +void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + *p_Dst8 = MY_GET_UINT8(*p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + *p_Dst8 = MY_GET_UINT8(*p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + *p_Dst32 = GET_UINT32(*p_Src32); + p_Dst32++;p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = GET_UINT32(*p_Src32); + p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = GET_UINT32(*p_Src32); + *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign); + lastWord = currWord; + p_Src32++;p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + { + *p_Dst8 = MY_GET_UINT8(*p_Src8); + p_Dst8++;p_Src8++; + } + + return pDst; +} + +void * MemCpy64(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint64_t lastWord; + uint64_t currWord; + uint64_t *pSrc64; + uint64_t *pDst64; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessarily to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 7) && size) /* (pSrc mod 8) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 7) << 3); /* leftAlign = (pSrc mod 8)*8 */ + rightAlign = 64 - leftAlign; + + + if (leftAlign == 0) + { + /* source is also aligned */ + pSrc64 = (uint64_t*)(p_Src8); + pDst64 = (uint64_t*)(p_Dst8); + while (size >> 3) /* size >= 8 */ + { + *pDst64++ = *pSrc64++; + size -= 8; + } + p_Src8 = (uint8_t*)(pSrc64); + p_Dst8 = (uint8_t*)(pDst64); + } + else + { + /* source is not aligned (destination is aligned)*/ + pSrc64 = (uint64_t*)(p_Src8 - (leftAlign >> 3)); + pDst64 = (uint64_t*)(p_Dst8); + lastWord = *pSrc64++; + while(size >> 4) /* size >= 16 */ + { + currWord = *pSrc64; + *pDst64 = (lastWord << leftAlign) | (currWord >> rightAlign); + lastWord = currWord; + pSrc64++; + pDst64++; + size -= 8; + } + p_Dst8 = (uint8_t*)(pDst64); + p_Src8 = (uint8_t*)(pSrc64) - 8 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + *p_Dst8++ = *p_Src8++; + + return pDst; +} + +void * MemSet32(void* pDst, uint8_t val, uint32_t size) +{ + uint32_t val32; + uint32_t *p_Dst32; + uint8_t *p_Dst8; + + p_Dst8 = (uint8_t*)(pDst); + + /* generate four 8-bit val's in 32-bit container */ + val32 = (uint32_t) val; + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + /* align destination to 32 */ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + *p_Dst8++ = val; + size--; + } + + /* 32-bit chunks */ + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + *p_Dst32++ = val32; + size -= 4; + } + + /* complete the leftovers */ + p_Dst8 = (uint8_t*)(p_Dst32); + while (size--) + *p_Dst8++ = val; + + return pDst; +} + +void * IOMemSet32(void* pDst, uint8_t val, uint32_t size) +{ + uint32_t val32; + uint32_t *p_Dst32; + uint8_t *p_Dst8; + + p_Dst8 = (uint8_t*)(pDst); + + /* generate four 8-bit val's in 32-bit container */ + val32 = (uint32_t) val; + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + /* align destination to 32 */ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + MY_WRITE_UINT8(*p_Dst8, val); + p_Dst8++; + size--; + } + + /* 32-bit chunks */ + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + WRITE_UINT32(*p_Dst32, val32); + p_Dst32++; + size -= 4; + } + + /* complete the leftovers */ + p_Dst8 = (uint8_t*)(p_Dst32); + while (size--) + { + MY_WRITE_UINT8(*p_Dst8, val); + p_Dst8++; + } + + return pDst; +} + +void * MemSet64(void* pDst, uint8_t val, uint32_t size) +{ + uint64_t val64; + uint64_t *pDst64; + uint8_t *p_Dst8; + + p_Dst8 = (uint8_t*)(pDst); + + /* generate four 8-bit val's in 32-bit container */ + val64 = (uint64_t) val; + val64 |= (val64 << 8); + val64 |= (val64 << 16); + val64 |= (val64 << 24); + val64 |= (val64 << 32); + + /* align destination to 64 */ + while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */ + { + *p_Dst8++ = val; + size--; + } + + /* 64-bit chunks */ + pDst64 = (uint64_t*)(p_Dst8); + while (size >> 4) /* size >= 8 */ + { + *pDst64++ = val64; + size -= 8; + } + + /* complete the leftovers */ + p_Dst8 = (uint8_t*)(pDst64); + while (size--) + *p_Dst8++ = val; + + return pDst; +} + +void MemDisp(uint8_t *p, int size) +{ + uint32_t space = (uint32_t)(PTR_TO_UINT(p) & 0x3); + uint8_t *p_Limit; + + if (space) + { + p_Limit = (p - space + 4); + + XX_Print("0x%08X: ", (p - space)); + + while (space--) + { + XX_Print("--"); + } + while (size && (p < p_Limit)) + { + XX_Print("%02x", *(uint8_t*)p); + size--; + p++; + } + + XX_Print(" "); + p_Limit += 12; + + while ((size > 3) && (p < p_Limit)) + { + XX_Print("%08x ", *(uint32_t*)p); + size -= 4; + p += 4; + } + XX_Print("\r\n"); + } + + while (size > 15) + { + XX_Print("0x%08X: %08x %08x %08x %08x\r\n", + p, *(uint32_t *)p, *(uint32_t *)(p + 4), + *(uint32_t *)(p + 8), *(uint32_t *)(p + 12)); + size -= 16; + p += 16; + } + + if (size) + { + XX_Print("0x%08X: ", p); + + while (size > 3) + { + XX_Print("%08x ", *(uint32_t *)p); + size -= 4; + p += 4; + } + while (size) + { + XX_Print("%02x", *(uint8_t *)p); + size--; + p++; + } + + XX_Print("\r\n"); + } +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/etc/error.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/etc/error.c @@ -0,0 +1,118 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + + @File error.c + + @Description General errors and events reporting utilities. +*//***************************************************************************/ + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + +const char *dbgLevelStrings[] = +{ + "CRITICAL" + ,"MAJOR" + ,"MINOR" + ,"WARNING" + ,"INFO" + ,"TRACE" +}; + +const char *errTypeStrings[] = +{ + "Invalid State" /* E_INVALID_STATE */ + ,"Invalid Operation" /* E_INVALID_OPERATION */ + ,"Unsupported Operation" /* E_NOT_SUPPORTED */ + ,"No Device" /* E_NO_DEVICE */ + ,"Invalid Handle" /* E_INVALID_HANDLE */ + ,"Invalid ID" /* E_INVALID_ID */ + ,"Unexpected NULL Pointer" /* E_NULL_POINTER */ + ,"Invalid Value" /* E_INVALID_VALUE */ + ,"Invalid Selection" /* E_INVALID_SELECTION */ + ,"Invalid Communication Mode" /* E_INVALID_COMM_MODE */ + ,"Invalid Byte Order" /* E_INVALID_BYTE_ORDER */ + ,"Invalid Memory Type" /* E_INVALID_MEMORY_TYPE */ + ,"Invalid Interrupt Queue" /* E_INVALID_INTR_QUEUE */ + ,"Invalid Priority" /* E_INVALID_PRIORITY */ + ,"Invalid Clock" /* E_INVALID_CLOCK */ + ,"Invalid Rate" /* E_INVALID_RATE */ + ,"Invalid Address" /* E_INVALID_ADDRESS */ + ,"Invalid Bus" /* E_INVALID_BUS */ + ,"Conflict In Bus Selection" /* E_BUS_CONFLICT */ + ,"Conflict In Settings" /* E_CONFLICT */ + ,"Incorrect Alignment" /* E_NOT_ALIGNED */ + ,"Value Out Of Range" /* E_NOT_IN_RANGE */ + ,"Invalid Frame" /* E_INVALID_FRAME */ + ,"Frame Is Empty" /* E_EMPTY_FRAME */ + ,"Buffer Is Empty" /* E_EMPTY_BUFFER */ + ,"Memory Allocation Failed" /* E_NO_MEMORY */ + ,"Resource Not Found" /* E_NOT_FOUND */ + ,"Resource Is Unavailable" /* E_NOT_AVAILABLE */ + ,"Resource Already Exists" /* E_ALREADY_EXISTS */ + ,"Resource Is Full" /* E_FULL */ + ,"Resource Is Empty" /* E_EMPTY */ + ,"Resource Is Busy" /* E_BUSY */ + ,"Resource Already Free" /* E_ALREADY_FREE */ + ,"Read Access Failed" /* E_READ_FAILED */ + ,"Write Access Failed" /* E_WRITE_FAILED */ + ,"Send Operation Failed" /* E_SEND_FAILED */ + ,"Receive Operation Failed" /* E_RECEIVE_FAILED */ + ,"Operation Timed Out" /* E_TIMEOUT */ +}; + + +#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0)) + +const char *eventStrings[] = +{ + "Rx Discard" /* EV_RX_DISCARD */ + ,"Rx Error" /* EV_RX_ERROR */ + ,"Tx Error" /* EV_TX_ERROR */ + ,"No Buffer Objects" /* EV_NO_BUFFERS */ + ,"No MB-Frame Objects" /* EV_NO_MB_FRAMES */ + ,"No SB-Frame Objects" /* EV_NO_SB_FRAMES */ + ,"Tx Queue Is Full" /* EV_TX_QUEUE_FULL */ + ,"Rx Queue Is Full" /* EV_RX_QUEUE_FULL */ + ,"Interrupts Queue Is Full" /* EV_INTR_QUEUE_FULL */ + ,"Data Buffer Is Unavailable" /* EV_NO_DATA_BUFFER */ + ,"Objects Pool Is Empty" /* EV_OBJ_POOL_EMPTY */ + ,"Illegal bus access" /* EV_BUS_ERROR */ + ,"PTP Tx Timestamps Queue Is Full" /* EV_PTP_TXTS_QUEUE_FULL */ + ,"PTP Rx Timestamps Queue Is Full" /* EV_PTP_RXTS_QUEUE_FULL */ +}; + +#endif /* (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0)) */ + +#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/etc/mm.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/etc/mm.c @@ -0,0 +1,1109 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "string_ext.h" +#include "error_ext.h" +#include "std_ext.h" +#include "sprint_ext.h" +#include "part_ext.h" +#include "xx_ext.h" + +#include "mm.h" + + + + +/********************************************************************** + * MM internal routines set * + **********************************************************************/ + +/**************************************************************** + * Routine: CreateBusyBlock + * + * Description: + * Initializes a new busy block of "size" bytes and started + * rom "base" address. Each busy block has a name that + * specified the purpose of the memory allocation. + * + * Arguments: + * base - base address of the busy block + * size - size of the busy block + * name - name that specified the busy block + * + * Return value: + * A pointer to new created structure returned on success; + * Otherwise, NULL. + ****************************************************************/ +static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name) +{ + t_BusyBlock *p_BusyBlock; + uint32_t n; + + p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock)); + if ( !p_BusyBlock ) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + p_BusyBlock->base = base; + p_BusyBlock->end = base + size; + + n = strlen(name); + if (n >= MM_MAX_NAME_LEN) + n = MM_MAX_NAME_LEN - 1; + strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1); + p_BusyBlock->name[n] = '\0'; + p_BusyBlock->p_Next = 0; + + return p_BusyBlock; +} + +/**************************************************************** + * Routine: CreateNewBlock + * + * Description: + * Initializes a new memory block of "size" bytes and started + * from "base" address. + * + * Arguments: + * base - base address of the memory block + * size - size of the memory block + * + * Return value: + * A pointer to new created structure returned on success; + * Otherwise, NULL. + ****************************************************************/ +static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size) +{ + t_MemBlock *p_MemBlock; + + p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock)); + if ( !p_MemBlock ) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + p_MemBlock->base = base; + p_MemBlock->end = base+size; + p_MemBlock->p_Next = 0; + + return p_MemBlock; +} + +/**************************************************************** + * Routine: CreateFreeBlock + * + * Description: + * Initializes a new free block of of "size" bytes and + * started from "base" address. + * + * Arguments: + * base - base address of the free block + * size - size of the free block + * + * Return value: + * A pointer to new created structure returned on success; + * Otherwise, NULL. + ****************************************************************/ +static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size) +{ + t_FreeBlock *p_FreeBlock; + + p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock)); + if ( !p_FreeBlock ) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + p_FreeBlock->base = base; + p_FreeBlock->end = base + size; + p_FreeBlock->p_Next = 0; + + return p_FreeBlock; +} + +/**************************************************************** + * Routine: AddFree + * + * Description: + * Adds a new free block to the free lists. It updates each + * free list to include a new free block. + * Note, that all free block in each free list are ordered + * by their base address. + * + * Arguments: + * p_MM - pointer to the MM object + * base - base address of a given free block + * end - end address of a given free block + * + * Return value: + * + * + ****************************************************************/ +static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end) +{ + t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB; + uint64_t alignment; + uint64_t alignBase; + int i; + + /* Updates free lists to include a just released block */ + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + p_PrevB = p_NewB = 0; + p_CurrB = p_MM->freeBlocks[i]; + + alignment = (uint64_t)(0x1 << i); + alignBase = MAKE_ALIGNED(base, alignment); + + /* Goes to the next free list if there is no block to free */ + if (alignBase >= end) + continue; + + /* Looks for a free block that should be updated */ + while ( p_CurrB ) + { + if ( alignBase <= p_CurrB->end ) + { + if ( end > p_CurrB->end ) + { + t_FreeBlock *p_NextB; + while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end ) + { + p_NextB = p_CurrB->p_Next; + p_CurrB->p_Next = p_CurrB->p_Next->p_Next; + XX_Free(p_NextB); + } + + p_NextB = p_CurrB->p_Next; + if ( !p_NextB || (p_NextB && end < p_NextB->base) ) + { + p_CurrB->end = end; + } + else + { + p_CurrB->end = p_NextB->end; + p_CurrB->p_Next = p_NextB->p_Next; + XX_Free(p_NextB); + } + } + else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) ) + { + if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + + p_NewB->p_Next = p_CurrB; + if (p_PrevB) + p_PrevB->p_Next = p_NewB; + else + p_MM->freeBlocks[i] = p_NewB; + break; + } + + if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base)) + { + p_CurrB->base = alignBase; + } + + /* if size of the free block is less then alignment + * deletes that free block from the free list. */ + if ( (p_CurrB->end - p_CurrB->base) < alignment) + { + if ( p_PrevB ) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->freeBlocks[i] = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + break; + } + else + { + p_PrevB = p_CurrB; + p_CurrB = p_CurrB->p_Next; + } + } + + /* If no free block found to be updated, insert a new free block + * to the end of the free list. + */ + if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) ) + { + if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + + if (p_PrevB) + p_PrevB->p_Next = p_NewB; + else + p_MM->freeBlocks[i] = p_NewB; + } + + /* Update boundaries of the new free block */ + if ((alignment == 1) && !p_NewB) + { + if ( p_CurrB && base > p_CurrB->base ) + base = p_CurrB->base; + if ( p_CurrB && end < p_CurrB->end ) + end = p_CurrB->end; + } + } + + return (E_OK); +} + +/**************************************************************** + * Routine: CutFree + * + * Description: + * Cuts a free block from holdBase to holdEnd from the free lists. + * That is, it updates all free lists of the MM object do + * not include a block of memory from holdBase to holdEnd. + * For each free lists it seek for a free block that holds + * either holdBase or holdEnd. If such block is found it updates it. + * + * Arguments: + * p_MM - pointer to the MM object + * holdBase - base address of the allocated block + * holdEnd - end address of the allocated block + * + * Return value: + * E_OK is returned on success, + * otherwise returns an error code. + * + ****************************************************************/ +static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd) +{ + t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB; + uint64_t alignBase, base, end; + uint64_t alignment; + int i; + + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + p_PrevB = p_NewB = 0; + p_CurrB = p_MM->freeBlocks[i]; + + alignment = (uint64_t)(0x1 << i); + alignBase = MAKE_ALIGNED(holdEnd, alignment); + + while ( p_CurrB ) + { + base = p_CurrB->base; + end = p_CurrB->end; + + if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) ) + { + if ( alignBase >= end || + (alignBase < end && ((end-alignBase) < alignment)) ) + { + if (p_PrevB) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->freeBlocks[i] = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + else + { + p_CurrB->base = alignBase; + } + break; + } + else if ( (holdBase > base) && (holdEnd <= end) ) + { + if ( (holdBase-base) >= alignment ) + { + if ( (alignBase < end) && ((end-alignBase) >= alignment) ) + { + if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + p_NewB->p_Next = p_CurrB->p_Next; + p_CurrB->p_Next = p_NewB; + } + p_CurrB->end = holdBase; + } + else if ( (alignBase < end) && ((end-alignBase) >= alignment) ) + { + p_CurrB->base = alignBase; + } + else + { + if (p_PrevB) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->freeBlocks[i] = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + break; + } + else + { + p_PrevB = p_CurrB; + p_CurrB = p_CurrB->p_Next; + } + } + } + + return (E_OK); +} + +/**************************************************************** + * Routine: AddBusy + * + * Description: + * Adds a new busy block to the list of busy blocks. Note, + * that all busy blocks are ordered by their base address in + * the busy list. + * + * Arguments: + * MM - handler to the MM object + * p_NewBusyB - pointer to the a busy block + * + * Return value: + * None. + * + ****************************************************************/ +static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB) +{ + t_BusyBlock *p_CurrBusyB, *p_PrevBusyB; + + /* finds a place of a new busy block in the list of busy blocks */ + p_PrevBusyB = 0; + p_CurrBusyB = p_MM->busyBlocks; + + while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base ) + { + p_PrevBusyB = p_CurrBusyB; + p_CurrBusyB = p_CurrBusyB->p_Next; + } + + /* insert the new busy block into the list of busy blocks */ + if ( p_CurrBusyB ) + p_NewBusyB->p_Next = p_CurrBusyB; + if ( p_PrevBusyB ) + p_PrevBusyB->p_Next = p_NewBusyB; + else + p_MM->busyBlocks = p_NewBusyB; +} + +/**************************************************************** + * Routine: CutBusy + * + * Description: + * Cuts a block from base to end from the list of busy blocks. + * This is done by updating the list of busy blocks do not + * include a given block, that block is going to be free. If a + * given block is a part of some other busy block, so that + * busy block is updated. If there are number of busy blocks + * included in the given block, so all that blocks are removed + * from the busy list and the end blocks are updated. + * If the given block devides some block into two parts, a new + * busy block is added to the busy list. + * + * Arguments: + * p_MM - pointer to the MM object + * base - base address of a given busy block + * end - end address of a given busy block + * + * Return value: + * E_OK on success, E_NOMEMORY otherwise. + * + ****************************************************************/ +static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end) +{ + t_BusyBlock *p_CurrB, *p_PrevB, *p_NewB; + + p_CurrB = p_MM->busyBlocks; + p_PrevB = p_NewB = 0; + + while ( p_CurrB ) + { + if ( base < p_CurrB->end ) + { + if ( end > p_CurrB->end ) + { + t_BusyBlock *p_NextB; + while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end ) + { + p_NextB = p_CurrB->p_Next; + p_CurrB->p_Next = p_CurrB->p_Next->p_Next; + XX_Free(p_NextB); + } + + p_NextB = p_CurrB->p_Next; + if ( p_NextB && end > p_NextB->base ) + { + p_NextB->base = end; + } + } + + if ( base <= p_CurrB->base ) + { + if ( end < p_CurrB->end && end > p_CurrB->base ) + { + p_CurrB->base = end; + } + else if ( end >= p_CurrB->end ) + { + if ( p_PrevB ) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->busyBlocks = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + } + else + { + if ( end < p_CurrB->end && end > p_CurrB->base ) + { + if ((p_NewB = CreateBusyBlock(end, + p_CurrB->end-end, + p_CurrB->name)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + p_NewB->p_Next = p_CurrB->p_Next; + p_CurrB->p_Next = p_NewB; + } + p_CurrB->end = base; + } + break; + } + else + { + p_PrevB = p_CurrB; + p_CurrB = p_CurrB->p_Next; + } + } + + return (E_OK); +} + +/**************************************************************** + * Routine: MmGetGreaterAlignment + * + * Description: + * Allocates a block of memory according to the given size + * and the alignment. That routine is called from the MM_Get + * routine if the required alignment is greater then MM_MAX_ALIGNMENT. + * In that case, it goes over free blocks of 64 byte align list + * and checks if it has the required size of bytes of the required + * alignment. If no blocks found returns ILLEGAL_BASE. + * After the block is found and data is allocated, it calls + * the internal CutFree routine to update all free lists + * do not include a just allocated block. Of course, each + * free list contains a free blocks with the same alignment. + * It is also creates a busy block that holds + * information about an allocated block. + * + * Arguments: + * MM - handle to the MM object + * size - size of the MM + * alignment - index as a power of two defines + * a required alignment that is greater then 64. + * name - the name that specifies an allocated block. + * + * Return value: + * base address of an allocated block. + * ILLEGAL_BASE if can't allocate a block + * + ****************************************************************/ +static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name) +{ + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint64_t holdBase, holdEnd, alignBase = 0; + + /* goes over free blocks of the 64 byte alignment list + and look for a block of the suitable size and + base address according to the alignment. */ + p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT]; + + while ( p_FreeB ) + { + alignBase = MAKE_ALIGNED(p_FreeB->base, alignment); + + /* the block is found if the aligned base inside the block + * and has the anough size. */ + if ( alignBase >= p_FreeB->base && + alignBase < p_FreeB->end && + size <= (p_FreeB->end - alignBase) ) + break; + else + p_FreeB = p_FreeB->p_Next; + } + + /* If such block isn't found */ + if ( !p_FreeB ) + return (uint64_t)(ILLEGAL_BASE); + + holdBase = alignBase; + holdEnd = alignBase + size; + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) + return (uint64_t)(ILLEGAL_BASE); + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK ) + return (uint64_t)(ILLEGAL_BASE); + + /* insert the new busy block into the list of busy blocks */ + AddBusy ( p_MM, p_NewBusyB ); + + return (holdBase); +} + + +/********************************************************************** + * MM API routines set * + **********************************************************************/ + +/*****************************************************************************/ +t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size) +{ + t_MM *p_MM; + uint64_t newBase, newSize; + int i; + + if (!size) + { + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)")); + } + + /* Initializes a new MM object */ + p_MM = (t_MM *)XX_Malloc(sizeof(t_MM)); + if (!p_MM) + { + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + } + + p_MM->h_Spinlock = XX_InitSpinlock(); + if (!p_MM->h_Spinlock) + { + XX_Free(p_MM); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!")); + } + + /* initializes a new memory block */ + if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + + /* A busy list is empty */ + p_MM->busyBlocks = 0; + + /*Initializes a new free block for each free list*/ + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + newBase = MAKE_ALIGNED( base, (0x1 << i) ); + newSize = size - (newBase - base); + + if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + } + + *h_MM = p_MM; + + return (E_OK); +} + +/*****************************************************************************/ +void MM_Free(t_Handle h_MM) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_MemBlock *p_MemBlock; + t_BusyBlock *p_BusyBlock; + t_FreeBlock *p_FreeBlock; + void *p_Block; + int i; + + ASSERT_COND(p_MM); + + /* release memory allocated for busy blocks */ + p_BusyBlock = p_MM->busyBlocks; + while ( p_BusyBlock ) + { + p_Block = p_BusyBlock; + p_BusyBlock = p_BusyBlock->p_Next; + XX_Free(p_Block); + } + + /* release memory allocated for free blocks */ + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + p_FreeBlock = p_MM->freeBlocks[i]; + while ( p_FreeBlock ) + { + p_Block = p_FreeBlock; + p_FreeBlock = p_FreeBlock->p_Next; + XX_Free(p_Block); + } + } + + /* release memory allocated for memory blocks */ + p_MemBlock = p_MM->memBlocks; + while ( p_MemBlock ) + { + p_Block = p_MemBlock; + p_MemBlock = p_MemBlock->p_Next; + XX_Free(p_Block); + } + + if (p_MM->h_Spinlock) + XX_FreeSpinlock(p_MM->h_Spinlock); + + /* release memory allocated for MM object itself */ + XX_Free(p_MM); +} + +/*****************************************************************************/ +uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint64_t holdBase, holdEnd, j, i = 0; + uint32_t intFlags; + + SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE); + + /* checks that alignment value is greater then zero */ + if (alignment == 0) + { + alignment = 1; + } + + j = alignment; + + /* checks if alignment is a power of two, if it correct and if the + required size is multiple of the given alignment. */ + while ((j & 0x1) == 0) + { + i++; + j = j >> 1; + } + + /* if the given alignment isn't power of two, returns an error */ + if (j != 1) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)")); + return (uint64_t)ILLEGAL_BASE; + } + + if (i > MM_MAX_ALIGNMENT) + { + return (MmGetGreaterAlignment(p_MM, size, alignment, name)); + } + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + /* look for a block of the size greater or equal to the required size. */ + p_FreeB = p_MM->freeBlocks[i]; + while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size ) + p_FreeB = p_FreeB->p_Next; + + /* If such block is found */ + if ( !p_FreeB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + holdBase = p_FreeB->base; + holdEnd = holdBase + size; + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* insert the new busy block into the list of busy blocks */ + AddBusy ( p_MM, p_NewBusyB ); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (holdBase); +} + +/*****************************************************************************/ +uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint32_t intFlags; + bool blockIsFree = FALSE; + + ASSERT_COND(p_MM); + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the + free list with alignment 1 */ + + while ( p_FreeB ) + { + if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end ) + { + blockIsFree = TRUE; + break; + } + else + p_FreeB = p_FreeB->p_Next; + } + + if ( !blockIsFree ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree ( p_MM, base, base+size ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* insert the new busy block into the list of busy blocks */ + AddBusy ( p_MM, p_NewBusyB ); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (base); +} + +/*****************************************************************************/ +uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint64_t holdBase, holdEnd, j = alignment, i=0; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + /* checks if alignment is a power of two, if it correct and if the + required size is multiple of the given alignment. */ + while ((j & 0x1) == 0) + { + i++; + j = j >> 1; + } + + if ( (j != 1) || (i > MM_MAX_ALIGNMENT) ) + { + return (uint64_t)(ILLEGAL_BASE); + } + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + p_FreeB = p_MM->freeBlocks[i]; + + /* look for the first block that contains the minimum + base address. If the whole required size may be fit + into it, use that block, otherwise look for the next + block of size greater or equal to the required size. */ + while ( p_FreeB && (min >= p_FreeB->end)) + p_FreeB = p_FreeB->p_Next; + + /* If such block is found */ + if ( !p_FreeB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* if this block is large enough, use this block */ + holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min; + if ((holdBase + size) <= p_FreeB->end ) + { + holdEnd = holdBase + size; + } + else + { + p_FreeB = p_FreeB->p_Next; + while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) ) + p_FreeB = p_FreeB->p_Next; + + /* If such block is found */ + if ( !p_FreeB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + holdBase = p_FreeB->base; + holdEnd = holdBase + size; + } + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* insert the new busy block into the list of busy blocks */ + AddBusy( p_MM, p_NewBusyB ); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (holdBase); +} + +/*****************************************************************************/ +uint64_t MM_Put(t_Handle h_MM, uint64_t base) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_BusyBlock *p_BusyB, *p_PrevBusyB; + uint64_t size; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + /* Look for a busy block that have the given base value. + * That block will be returned back to the memory. + */ + p_PrevBusyB = 0; + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + p_BusyB = p_MM->busyBlocks; + while ( p_BusyB && base != p_BusyB->base ) + { + p_PrevBusyB = p_BusyB; + p_BusyB = p_BusyB->p_Next; + } + + if ( !p_BusyB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + + if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + + /* removes a busy block form the list of busy blocks */ + if ( p_PrevBusyB ) + p_PrevBusyB->p_Next = p_BusyB->p_Next; + else + p_MM->busyBlocks = p_BusyB->p_Next; + + size = p_BusyB->end - p_BusyB->base; + + XX_Free(p_BusyB); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (size); +} + +/*****************************************************************************/ +uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size) +{ + t_MM *p_MM = (t_MM *)h_MM; + uint64_t end = base + size; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + if ( CutBusy( p_MM, base, end ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + + if ( AddFree ( p_MM, base, end ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (size); +} + +/*****************************************************************************/ +t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_MemBlock *p_MemB, *p_NewMemB; + t_Error errCode; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + /* find a last block in the list of memory blocks to insert a new + * memory block + */ + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + p_MemB = p_MM->memBlocks; + while ( p_MemB->p_Next ) + { + if ( base >= p_MemB->base && base < p_MemB->end ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + } + p_MemB = p_MemB->p_Next; + } + /* check for a last memory block */ + if ( base >= p_MemB->base && base < p_MemB->end ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + } + + /* create a new memory block */ + if ((p_NewMemB = CreateNewBlock(base, size)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + } + + /* append a new memory block to the end of the list of memory blocks */ + p_MemB->p_Next = p_NewMemB; + + /* add a new free block to the free lists */ + errCode = AddFree(p_MM, base, base+size); + if (errCode) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + p_MemB->p_Next = 0; + XX_Free(p_NewMemB); + return ((t_Error)errCode); + } + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (E_OK); +} + +/*****************************************************************************/ +uint64_t MM_GetMemBlock(t_Handle h_MM, int index) +{ + t_MM *p_MM = (t_MM*)h_MM; + t_MemBlock *p_MemBlock; + int i; + + ASSERT_COND(p_MM); + + p_MemBlock = p_MM->memBlocks; + for (i=0; i < index; i++) + p_MemBlock = p_MemBlock->p_Next; + + if ( p_MemBlock ) + return (p_MemBlock->base); + else + return (uint64_t)ILLEGAL_BASE; +} + +/*****************************************************************************/ +uint64_t MM_GetBase(t_Handle h_MM) +{ + t_MM *p_MM = (t_MM*)h_MM; + t_MemBlock *p_MemBlock; + + ASSERT_COND(p_MM); + + p_MemBlock = p_MM->memBlocks; + return p_MemBlock->base; +} + +/*****************************************************************************/ +bool MM_InRange(t_Handle h_MM, uint64_t addr) +{ + t_MM *p_MM = (t_MM*)h_MM; + t_MemBlock *p_MemBlock; + + ASSERT_COND(p_MM); + + p_MemBlock = p_MM->memBlocks; + + if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end)) + return TRUE; + else + return FALSE; +} + +/*****************************************************************************/ +void MM_Dump(t_Handle h_MM, void *buff) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_BusyB; + int i; + + p_BusyB = p_MM->busyBlocks; + Sprint(buff, "List of busy blocks:\n"); + while (p_BusyB) + { + Sprint(buff, "\t0x%p: (%s: b=0x%lx, e=0x%lx)\n", + p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end ); + p_BusyB = p_BusyB->p_Next; + } + + Sprint(buff, "\nLists of free blocks according to alignment:\n"); + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + Sprint(buff, "%d alignment:\n", (0x1 << i)); + p_FreeB = p_MM->freeBlocks[i]; + while (p_FreeB) + { + Sprint(buff, "\t0x%p: (b=0x%lx, e=0x%lx)\n", + p_FreeB, p_FreeB->base, p_FreeB->end); + p_FreeB = p_FreeB->p_Next; + } + Sprint(buff, "\n"); + } +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/etc/sprint.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/etc/sprint.c @@ -0,0 +1,81 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*------------------------------------------------------*/ +/* File: sprint.c */ +/* */ +/* Description: */ +/* Debug routines (externals) */ +/*------------------------------------------------------*/ +#include "string_ext.h" +#include "stdlib_ext.h" +#include "ctype_ext.h" +#include "stdarg_ext.h" +#include "sprint_ext.h" +#include "std_ext.h" +#include "xx_ext.h" + + +int Sprint(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +int Snprint(char * buf, uint32_t size, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsnprintf(buf,size,fmt,args); + va_end(args); + return i; +} + +#ifndef NCSW_VXWORKS +int Sscan(const char * buf, const char * fmt, ...) +{ + va_list args; + int i; + + va_start(args,fmt); + i = vsscanf(buf,fmt,args); + va_end(args); + return i; +} +#endif /* NCSW_VXWORKS */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/etc/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/etc/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +obj-y += fsl-ncsw-etc.o + +fsl-ncsw-etc-objs := mm.o memcpy.o sprint.o list.o error.o --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/etc/list.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/etc/list.c @@ -0,0 +1,70 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + + @File list.c + + @Description Implementation of list. +*//***************************************************************************/ +#include "std_ext.h" +#include "list_ext.h" + + +void LIST_Append(t_List *p_NewList, t_List *p_Head) +{ + t_List *p_First = LIST_FIRST(p_NewList); + + if (p_First != p_NewList) + { + t_List *p_Last = LIST_LAST(p_NewList); + t_List *p_Cur = LIST_NEXT(p_Head); + + LIST_PREV(p_First) = p_Head; + LIST_FIRST(p_Head) = p_First; + LIST_NEXT(p_Last) = p_Cur; + LIST_LAST(p_Cur) = p_Last; + } +} + + +int LIST_NumOfObjs(t_List *p_List) +{ + t_List *p_Tmp; + int numOfObjs = 0; + + if (!LIST_IsEmpty(p_List)) + LIST_FOR_EACH(p_Tmp, p_List) + numOfObjs++; + + return numOfObjs; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/etc/mm.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/etc/mm.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************** + * + * File: mm.h + * + * + * Description: + * MM (Memory Management) object definitions. + * It also includes definitions of the Free Block, Busy Block + * and Memory Block structures used by the MM object. + * + ****************************************************************/ + +#ifndef __MM_H +#define __MM_H + + +#include "mm_ext.h" + +#define __ERR_MODULE__ MODULE_MM + + +#define MAKE_ALIGNED(addr, align) \ + (((uint64_t)(addr) + ((align) - 1)) & (~(((uint64_t)align) - 1))) + + +/* t_MemBlock data stucutre defines parameters of the Memory Block */ +typedef struct t_MemBlock +{ + struct t_MemBlock *p_Next; /* Pointer to the next memory block */ + + uint64_t base; /* Base address of the memory block */ + uint64_t end; /* End address of the memory block */ +} t_MemBlock; + + +/* t_FreeBlock data stucutre defines parameters of the Free Block */ +typedef struct t_FreeBlock +{ + struct t_FreeBlock *p_Next; /* Pointer to the next free block */ + + uint64_t base; /* Base address of the block */ + uint64_t end; /* End address of the block */ +} t_FreeBlock; + + +/* t_BusyBlock data stucutre defines parameters of the Busy Block */ +typedef struct t_BusyBlock +{ + struct t_BusyBlock *p_Next; /* Pointer to the next free block */ + + uint64_t base; /* Base address of the block */ + uint64_t end; /* End address of the block */ + char name[MM_MAX_NAME_LEN]; /* That block of memory was allocated for + something specified by the Name */ +} t_BusyBlock; + + +/* t_MM data structure defines parameters of the MM object */ +typedef struct t_MM +{ + t_MemBlock *memBlocks; /* List of memory blocks (Memory list) */ + t_BusyBlock *busyBlocks; /* List of busy blocks (Busy list) */ + t_FreeBlock *freeBlocks[MM_MAX_ALIGNMENT + 1]; + /* Alignment lists of free blocks (Free lists) */ + t_Handle h_Spinlock; +} t_MM; + + +#endif /* __MM_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/integrations/P3040_P4080_P5020/module_strings.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/integrations/P3040_P4080_P5020/module_strings.c @@ -0,0 +1,62 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Module names for debug messages */ +const char *moduleStrings[] = +{ + "???" /* MODULE_UNKNOWN */ + ,"MEM" /* MODULE_ */ + ,"MM" /* MODULE_MM */ + ,"CORE" /* MODULE_CORE */ + ,"P4080" /* MODULE_P4080 */ + ,"P4080-Platform" /* MODULE_P4080_PLTFRM */ + ,"PM" /* MODULE_PM */ + ,"MMU" /* MODULE_MMU */ + ,"PIC" /* MODULE_PIC */ + ,"L3 cache (CPC)" /* MODULE_CPC */ + ,"DUART" /* MODULE_DUART */ + ,"SerDes" /* MODULE_SERDES */ + ,"PIO" /* MODULE_PIO */ + ,"QM" /* MODULE_QM */ + ,"BM" /* MODULE_BM */ + ,"SEC" /* MODULE_SEC */ + ,"LAW" /* MODULE_LAW */ + ,"LBC" /* MODULE_LBC */ + ,"PAMU" /* MODULE_PAMU */ + ,"FM" /* MODULE_FM */ + ,"FM-MURAM" /* MODULE_FM_MURAM */ + ,"FM-PCD" /* MODULE_FM_PCD */ + ,"FM-RTC" /* MODULE_FM_RTC */ + ,"FM-MAC" /* MODULE_FM_MAC */ + ,"FM-Port" /* MODULE_FM_PORT */ + ,"DPA" /* MODULE_DPA */ +}; --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/integrations/P3040_P4080_P5020/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/integrations/P3040_P4080_P5020/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +obj-y += module_strings.o --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/integrations/P1023/module_strings.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/integrations/P1023/module_strings.c @@ -0,0 +1,71 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* Module names for debug messages */ +const char *moduleStrings[] = +{ + "" /* MODULE_UNKNOWN */ + ,"MEM" /* MODULE_ */ + ,"MM" /* MODULE_MM */ + ,"CORE" /* MODULE_CORE */ + ,"P1023" /* MODULE_P1023 */ + ,"MII" /* MODULE_MII */ + ,"PM" /* MODULE_PM */ + ,"MMU" /* MODULE_MMU */ + ,"PIC" /* MODULE_PIC */ + ,"L2 cache" /* MODULE_L2_CACHE */ + ,"DUART" /* MODULE_DUART */ + ,"SerDes" /* MODULE_SERDES */ + ,"PIO" /* MODULE_PIO */ + ,"QM" /* MODULE_QM */ + ,"BM" /* MODULE_BM */ + ,"SEC" /* MODULE_SEC */ + ,"FM" /* MODULE_FM */ + ,"FM-MURAM" /* MODULE_FM_MURAM */ + ,"FM-PCD" /* MODULE_FM_PCD */ + ,"FM-RTC" /* MODULE_FM_RTC */ + ,"FM-MAC" /* MODULE_FM_MAC */ + ,"FM-Port" /* MODULE_FM_PORT */ + ,"FM-MACSEC" /* MODULE_FM_MACSEC */ + ,"FM-MACSEC-SecY" /* MODULE_FM_MACSEC_SECY */ + ,"ECM" /* MODULE_ECM */ + ,"DMA" /* MODULE_DMA */ + ,"DDR" /* MODULE_DDR */ + ,"LAW" /* MODULE_LAW */ + ,"LBC" /* MODULE_LBC */ + ,"I2C" /* MODULE_I2C */ + ,"ESPI" /* MODULE_ESPI */ + ,"PCI" /* MODULE_PCI */ + ,"DPA" /* MODULE_DPA */ + ,"USB" /* MODULE_USB */ +}; --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/integrations/P1023/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/integrations/P1023/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +obj-y += module_strings.o --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk +# +obj-y += system/ +obj-y += wrapper/ +obj-y += xx/ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/xx/udivdi3.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/xx/udivdi3.c @@ -0,0 +1,132 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ + +#include +#include +#include + + +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) + + +typedef unsigned int UQItype __attribute__ ((mode (QI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); + +struct DIstruct {SItype low, high;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + + +/* bit divisor, dividend and result. dynamic precision */ +static __inline__ uint64_t _div64_64(uint64_t dividend, uint64_t divisor) +{ + uint32_t d = divisor; + + if (divisor > 0xffffffffULL) + { + unsigned int shift = fls(divisor >> 32); + + d = divisor >> shift; + dividend >>= shift; + } + + /* avoid 64 bit division if possible */ + if (dividend >> 32) + do_div(dividend, d); + else + dividend = (uint32_t) dividend / d; + + return dividend; +} + +UDItype __udivdi3 (UDItype n, UDItype d) +{ + return _div64_64(n, d); +} + +DItype __divdi3 (DItype n, DItype d) +{ + DItype sign = 1; + if (n<0) + { + sign *= -1; + n *= -1; + } + if (d<0) + { + sign *= -1; + d *= -1; + } + return sign*_div64_64((UDItype)n, (UDItype)d); +} + +UDItype __umoddi3 (UDItype n, UDItype d) +{ + return n-(_div64_64(n, d)*d); +} + +#ifdef MODULE +word_type __ucmpdi2 (DItype a, DItype b) +{ + DIunion au, bu; + + au.ll = a, bu.ll = b; + + if ((USItype) au.s.high < (USItype) bu.s.high) + return 0; + else if ((USItype) au.s.high > (USItype) bu.s.high) + return 2; + if ((USItype) au.s.low < (USItype) bu.s.low) + return 0; + else if ((USItype) au.s.low > (USItype) bu.s.low) + return 2; + return 1; +} +#endif /* MODULE */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/xx/stdlib.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/xx/stdlib.c @@ -0,0 +1,264 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*------------------------------------------------------*/ +/* */ +/* File: stdlib.c */ +/* */ +/* Description: */ +/* Standard library routines (externals) */ +/* */ +/* Modifications: */ +/* ============== */ +/* */ +/*------------------------------------------------------*/ +#include "stdlib_ext.h" +#include "stdarg_ext.h" +#include "ctype_ext.h" +#include "string_ext.h" +#include "std_ext.h" +#include "xx_ext.h" + + +#ifdef MODULE +/** + * strtoul - convert a string to an uint32_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +uint32_t strtoul(const char *cp,char **endp,uint32_t base) +{ + uint32_t result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && + (value = (uint32_t)(isdigit(*cp) ? *cp-'0' : toupper((uint8_t)(*cp))-'A'+10)) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +/** + * strtol - convert a string to a int32_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long strtol(const char *cp,char **endp,uint32_t base) +{ + if(*cp=='-') + return (long)(-strtoul(cp+1,endp,base)); + return (long)strtoul(cp,endp,base); +} + +/** + * strtoull - convert a string to an uint64_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +uint64_t strtoull(const char *cp,char **endp,uint32_t base) +{ + uint64_t result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper((uint8_t)(*cp)) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +/** + * strtoll - convert a string to a int64 + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long long strtoll(const char *cp,char **endp,uint32_t base) +{ + if(*cp=='-') + return (long long)(-strtoull(cp+1,endp,base)); + return (long long)(strtoull(cp,endp,base)); +} + +/** + * atoi - convert a string to a int + * @s: The start of the string + */ +int atoi(const char *s) +{ + int i=0; + const char **tmp_s = &s; + + while (isdigit(**tmp_s)) + i = i*10 + *((*tmp_s)++) - '0'; + return i; +} + +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + + return sc - s; +} + +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + + return sc - s; +} + +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ +char * strcpy(char * dest,const char *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} +#endif /* MODULE */ + +/** + * strtok - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * WARNING: strtok is deprecated, use strsep instead. + */ +char *___strtok; + +char * strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} + + +#ifdef MODULE +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ +char * strncpy(char * dest,const char *src,size_t count) +{ + char *tmp = dest; + + while (count-- && (*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} + +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf instead. + */ +int vsprintf(char *buf, const char *fmt, va_list args) +{ + return vsnprintf(buf, INT32_MAX, fmt, args); +} +#endif /* MODULE */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/xx/xx_linux.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/xx/xx_linux.c @@ -0,0 +1,901 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File xx_linux.c + + @Description XX routines implementation for Linux. +*//***************************************************************************/ +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef BIGPHYSAREA_ENABLE +#include +#endif /* BIGPHYSAREA_ENABLE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "error_ext.h" +#include "std_ext.h" +#include "list_ext.h" +#include "mm_ext.h" +#include "sys_io_ext.h" +#include "xx.h" + + +#define __ERR_MODULE__ MODULE_UNKNOWN + +#ifdef BIGPHYSAREA_ENABLE +#define MAX_ALLOCATION_SIZE 128 * 1024 /* Maximum size allocated with kmalloc is 128K */ + + +/* TODO: large allocations => use big phys area */ +/****************************************************************************** + * routine: get_nr_pages + * + * description: + * calculates the number of memory pages for a given size (in bytes) + * + * arguments: + * size - the number of bytes + * + * return code: + * The number of pages + * + *****************************************************************************/ +static __inline__ uint32_t get_nr_pages (uint32_t size) +{ + return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0)); +} + +static bool in_big_phys_area (uint32_t addr) +{ + uint32_t base, size; + + bigphysarea_get_details (&base, &size); + return ((addr >= base) && (addr < base + size)); +} +#endif /* BIGPHYSAREA_ENABLE */ + +void * xx_Malloc(uint32_t n) +{ + void *a; + uint32_t flags; + + flags = XX_DisableAllIntr(); +#ifdef BIGPHYSAREA_ENABLE + if (n >= MAX_ALLOCATION_SIZE) + a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC); + else +#endif /* BIGPHYSAREA_ENABLE */ + a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC); + if (!a) + XX_Print("No memory for XX_Malloc\n"); + XX_RestoreAllIntr(flags); + + return a; +} + +void xx_Free(void *p) +{ +#ifdef BIGPHYSAREA_ENABLE + if (in_big_phys_area ((uint32_t)p)) + bigphysarea_free_pages(p); + else +#endif /* BIGPHYSAREA_ENABLE */ + kfree(p); +} + +void XX_Exit(int status) +{ + WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n"); +} + +#define BUF_SIZE 512 +void XX_Print(char *str, ...) +{ + va_list args; +#ifdef CONFIG_SMP + char buf[BUF_SIZE]; +#endif /* CONFIG_SMP */ + + va_start(args, str); +#ifdef CONFIG_SMP + if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) + printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); + printk (KERN_WARNING "cpu%d/%d: %s",hard_smp_processor_id(), smp_processor_id(), buf); +#else + vprintk(str, args); +#endif /* CONFIG_SMP */ + va_end(args); +} + +void XX_Fprint(void *file, char *str, ...) +{ + va_list args; +#ifdef CONFIG_SMP + char buf[BUF_SIZE]; +#endif /* CONFIG_SMP */ + + va_start(args, str); +#ifdef CONFIG_SMP + if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) + printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); + printk (KERN_CRIT "cpu%d/%d: %s",hard_smp_processor_id(), smp_processor_id(), buf); +#else + vprintk(str, args); +#endif /* CONFIG_SMP */ + va_end(args); +} + +#ifdef DEBUG_XX_MALLOC +typedef void (*t_ffn)(void *); +typedef struct { + t_ffn f_free; + void *mem; + char *fname; + int fline; + uint32_t size; + t_List node; +} t_MemDebug; +#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node) + +LIST(memDbgLst); + + +void * XX_MallocDebug(uint32_t size, char *fname, int line) +{ + void *mem; + t_MemDebug *p_MemDbg; + + p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug)); + if (p_MemDbg == NULL) + return NULL; + + mem = xx_Malloc(size); + if (mem == NULL) + { + XX_Free(p_MemDbg); + return NULL; + } + + INIT_LIST(&p_MemDbg->node); + p_MemDbg->f_free = xx_Free; + p_MemDbg->mem = mem; + p_MemDbg->fname = fname; + p_MemDbg->fline = line; + p_MemDbg->size = size+sizeof(t_MemDebug); + LIST_AddToTail(&p_MemDbg->node, &memDbgLst); + + return mem; +} + +void * XX_MallocSmartDebug(uint32_t size, + int memPartitionId, + uint32_t align, + char *fname, + int line) +{ + void *mem; + t_MemDebug *p_MemDbg; + + p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug)); + if (p_MemDbg == NULL) + return NULL; + + mem = xx_MallocSmart((uint32_t)size, memPartitionId, align); + if (mem == NULL) + { + XX_Free(p_MemDbg); + return NULL; + } + + INIT_LIST(&p_MemDbg->node); + p_MemDbg->f_free = xx_FreeSmart; + p_MemDbg->mem = mem; + p_MemDbg->fname = fname; + p_MemDbg->fline = line; + p_MemDbg->size = size+sizeof(t_MemDebug); + LIST_AddToTail(&p_MemDbg->node, &memDbgLst); + + return mem; +} + +static void debug_free(void *mem) +{ + t_List *p_MemDbgLh = NULL; + t_MemDebug *p_MemDbg; + bool found = FALSE; + + if (LIST_IsEmpty(&memDbgLst)) + { + REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem)); + return; + } + + LIST_FOR_EACH(p_MemDbgLh, &memDbgLst) + { + p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh); + if (p_MemDbg->mem == mem) + { + found = TRUE; + break; + } + } + + if (!found) + { + REPORT_ERROR(MAJOR, E_NOT_FOUND, + ("Attempt to free unallocated address (0x%08x)",mem)); + dump_stack(); + return; + } + + LIST_Del(p_MemDbgLh); + p_MemDbg->f_free(mem); + p_MemDbg->f_free(p_MemDbg); +} + +void XX_FreeSmart(void *p) +{ + debug_free(p); +} + + +void XX_Free(void *p) +{ + debug_free(p); +} + +#else /* not DEBUG_XX_MALLOC */ +void * XX_Malloc(uint32_t size) +{ + return xx_Malloc(size); +} + +void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) +{ + return xx_MallocSmart(size,memPartitionId, alignment); +} + +void XX_FreeSmart(void *p) +{ + xx_FreeSmart(p); +} + + +void XX_Free(void *p) +{ + xx_Free(p); +} +#endif /* not DEBUG_XX_MALLOC */ + + +#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0)) +void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg) +{ + e_Event eventCode = (e_Event)event; + + UNUSED(eventCode); + UNUSED(appId); + UNUSED(flags); + UNUSED(msg); +} +#endif /* (defined(REPORT_EVENTS) && ... */ + + +uint32_t XX_DisableAllIntr(void) +{ + unsigned long flags; + + local_irq_save(flags); + + return (uint32_t)flags; +} + +void XX_RestoreAllIntr(uint32_t flags) +{ + local_irq_restore((unsigned long)flags); +} + +t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags ) +{ + UNUSED(qid); + UNUSED(appId); + UNUSED(flags); + + return f(id); +} + +int XX_IsICacheEnable(void) +{ + return TRUE; +} + +int XX_IsDCacheEnable(void) +{ + return TRUE; +} + + +typedef struct { + t_Isr *f_Isr; + t_Handle handle; +} t_InterruptHandler; + + +t_Handle interruptHandlers[0x00010000]; + +static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id) +{ + t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id; + p_IntrHndl->f_Isr(p_IntrHndl->handle); + return IRQ_HANDLED; +} + +t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle) +{ + const char *device; + t_InterruptHandler *p_IntrHndl; + + device = GetDeviceName(irq); + if (device == NULL) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq)); + + p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler)); + if (p_IntrHndl == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + p_IntrHndl->f_Isr = f_Isr; + p_IntrHndl->handle = handle; + interruptHandlers[irq] = p_IntrHndl; + + if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0) + RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device)); + disable_irq(GetDeviceIrqNum(irq)); + + return E_OK; +} + +t_Error XX_FreeIntr(int irq) +{ + t_InterruptHandler *p_IntrHndl = interruptHandlers[irq]; + free_irq(GetDeviceIrqNum(irq), p_IntrHndl); + XX_Free(p_IntrHndl); + interruptHandlers[irq] = 0; + return E_OK; +} + +t_Error XX_EnableIntr(int irq) +{ + enable_irq(GetDeviceIrqNum(irq)); + return E_OK; +} + +t_Error XX_DisableIntr(int irq) +{ + disable_irq(GetDeviceIrqNum(irq)); + return E_OK; +} + + +/*****************************************************************************/ +/* Tasklet Service Routines */ +/*****************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +typedef struct +{ + t_Handle h_Data; + void (*f_Callback) (void *); + struct delayed_work dwork; +} t_Tasklet; + +static void GenericTaskletCallback(struct work_struct *p_Work) +{ + t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work); + + p_Task->f_Callback(p_Task->h_Data); +} +#endif /* LINUX_VERSION_CODE */ + + +t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + struct work_struct *p_Task; + p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct)); + INIT_WORK(p_Task, routine, data); +#else + t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet)); + p_Task->h_Data = data; + p_Task->f_Callback = routine; + INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback); +#endif /* LINUX_VERSION_CODE */ + + return (t_TaskletHandle)p_Task; +} + + +void XX_FreeTasklet (t_TaskletHandle h_Tasklet) +{ + if (h_Tasklet) + XX_Free(h_Tasklet); +} + +int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate) +{ + int ans; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + if (immediate) + ans = schedule_work(h_Tasklet); + else + ans = schedule_delayed_work(h_Tasklet, 1); +#else + if (immediate) + ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0); + else + ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ); +#endif /* LINUX_VERSION_CODE */ + + return ans; +} + +void XX_FlushScheduledTasks(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + flush_scheduled_tasks(); +#else + flush_scheduled_work(); +#endif /* LINUX_VERSION_CODE */ +} + +int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + return (int)(((struct work_struct *)h_Tasklet)->pending); +#else + return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork); +#endif /* LINUX_VERSION_CODE */ +} + +void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + ((struct tq_struct *)h_Tasklet)->data = data; +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + ((struct work_struct *)h_Tasklet)->data = data; +#else + ((t_Tasklet *)h_Tasklet)->h_Data = data; +#endif /* LINUX_VERSION_CODE */ +} + +t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + return (t_Handle)(((struct work_struct *)h_Tasklet)->data); +#else + return ((t_Tasklet *)h_Tasklet)->h_Data; +#endif /* LINUX_VERSION_CODE */ +} + + +/*****************************************************************************/ +/* Spinlock Service Routines */ +/*****************************************************************************/ + +t_Handle XX_InitSpinlock(void) +{ + spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t)); + if (!p_Spinlock) + return NULL; + + spin_lock_init(p_Spinlock); + + return (t_Handle)p_Spinlock; +} + +void XX_FreeSpinlock(t_Handle h_Spinlock) +{ + if (h_Spinlock) + XX_Free(h_Spinlock); +} + +void XX_LockSpinlock(t_Handle h_Spinlock) +{ + spin_lock((spinlock_t *)h_Spinlock); +} + +void XX_UnlockSpinlock(t_Handle h_Spinlock) +{ + spin_unlock((spinlock_t *)h_Spinlock); +} + +uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock) +{ + unsigned long intrFlags; + spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags); + return intrFlags; +} + +void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags) +{ + spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags); +} + + +/*****************************************************************************/ +/* Timers Service Routines */ +/*****************************************************************************/ +/* The time now is in mili sec. resolution */ +uint32_t XX_CurrentTime(void) +{ + return (jiffies*1000)/HZ; +} + + +t_Handle XX_CreateTimer(void) +{ + struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list)); + if (p_Timer) + { + memset(p_Timer, 0, sizeof(struct timer_list)); + init_timer(p_Timer); + } + return (t_Handle)p_Timer; +} + +void XX_FreeTimer(t_Handle h_Timer) +{ + if (h_Timer) + XX_Free(h_Timer); +} + +void XX_StartTimer(t_Handle h_Timer, + uint32_t msecs, + bool periodic, + void (*f_TimerExpired)(t_Handle), + t_Handle h_Arg) +{ + int tmp_jiffies = (msecs*HZ)/1000; + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED); + + p_Timer->function = (void (*)(unsigned long))f_TimerExpired; + p_Timer->data = (unsigned long)h_Arg; + if ((msecs*HZ)%1000) + tmp_jiffies++; + p_Timer->expires = (jiffies + tmp_jiffies); + + add_timer((struct timer_list *)h_Timer); +} + +void XX_SetTimerData(t_Handle h_Timer, t_Handle data) +{ + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + p_Timer->data = (unsigned long)data; +} + +t_Handle XX_GetTimerData(t_Handle h_Timer) +{ + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + return (t_Handle)p_Timer->data; +} + +uint32_t XX_GetExpirationTime(t_Handle h_Timer) +{ + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + return (uint32_t)p_Timer->expires; +} + +void XX_StopTimer(t_Handle h_Timer) +{ + del_timer((struct timer_list *)h_Timer); +} + +void XX_ModTimer(t_Handle h_Timer, uint32_t msecs) +{ + int tmp_jiffies = (msecs*HZ)/1000; + + if ((msecs*HZ)%1000) + tmp_jiffies++; + mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies); +} + +int XX_TimerIsActive(t_Handle h_Timer) +{ + return timer_pending((struct timer_list *)h_Timer); +} + +uint32_t XX_Sleep(uint32_t msecs) +{ + int tmp_jiffies = (msecs*HZ)/1000; + + if ((msecs*HZ)%1000) + tmp_jiffies++; + return schedule_timeout(tmp_jiffies); +} + +/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/ +void XX_UDelay(uint32_t usecs) +{ + udelay(usecs); +} + +/* TODO: verify that these are correct */ +#define MSG_BODY_SIZE 512 +typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]); +typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]); +t_Error XX_SendMessage(char *p_DestAddr, + uint32_t msgId, + uint8_t msgBody[MSG_BODY_SIZE], + t_MsgCompletionCB *f_CompletionCB, + t_Handle h_CBArg); + +typedef struct { + char *p_Addr; + t_MsgHandler *f_MsgHandlerCB; + t_Handle h_Mod; + t_List node; +} t_MsgHndlr; +#define MSG_HNDLR_OBJECT(ptr) LIST_OBJECT(ptr, t_MsgHndlr, node) + +LIST(msgHndlrList); + +static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr) +{ + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList); + XX_RestoreAllIntr(intFlags); +} +/* TODO: add this for multi-platform support +static t_MsgHndlr * DequeueMsgHndlr(void) +{ + t_MsgHndlr *p_MsgHndlr = NULL; + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + if (!LIST_IsEmpty(&msgHndlrList)) + { + p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next); + LIST_DelAndInit(&p_MsgHndlr->node); + } + XX_RestoreAllIntr(intFlags); + + return p_MsgHndlr; +} +*/ +static t_MsgHndlr * FindMsgHndlr(char *p_Addr) +{ + t_MsgHndlr *p_MsgHndlr; + t_List *p_Pos; + + LIST_FOR_EACH(p_Pos, &msgHndlrList) + { + p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos); + if (strstr(p_MsgHndlr->p_Addr, p_Addr)) + return p_MsgHndlr; + } + + return NULL; +} + +t_Error XX_RegisterMessageHandler (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod) +{ + t_MsgHndlr *p_MsgHndlr; + uint32_t len; + + p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr)); + if (!p_MsgHndlr) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!")); + memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr)); + + len = strlen(p_Addr); + p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1); + strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1)); + + p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB; + p_MsgHndlr->h_Mod = h_Mod; + INIT_LIST(&p_MsgHndlr->node); + EnqueueMsgHndlr(p_MsgHndlr); + + return E_OK; +} + +t_Error XX_UnregisterMessageHandler (char *p_Addr) +{ + t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr); + if (!p_MsgHndlr) + RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); + + LIST_Del(&p_MsgHndlr->node); + XX_Free(p_MsgHndlr->p_Addr); + XX_Free(p_MsgHndlr); + + return E_OK; +} + +t_Error XX_SendMessage(char *p_DestAddr, + uint32_t msgId, + uint8_t msgBody[MSG_BODY_SIZE], + t_MsgCompletionCB *f_CompletionCB, + t_Handle h_CBArg) +{ + t_Error ans; + t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_DestAddr); + if (!p_MsgHndlr) + RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); + + ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody); + + if (f_CompletionCB) + f_CompletionCB(h_CBArg, msgBody); + + return ans; +} + +t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], + t_IpcMsgHandler *f_MsgHandler, + t_Handle h_Module, + uint32_t replyLength) +{ + UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength); + return E_OK; +} + +t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]) +{ + UNUSED(addr); + return E_OK; +} + + +t_Error XX_IpcSendMessage(t_Handle h_Session, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength, + t_IpcMsgCompletion *f_Completion, + t_Handle h_Arg) +{ + UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply); + UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg); + return E_OK; +} + +t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], + char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]) +{ + UNUSED(destAddr); UNUSED(srcAddr); + return E_OK; +} + +/*Forced to introduce due to PRINT_FMT_PARAMS define*/ +uint32_t E500_GetId(void) +{ + return smp_processor_id(); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +int GetDeviceIrqNum(int irq) +{ + struct device_node *iPar; + struct irq_domain *irqHost; + uint32_t hwIrq; + + /* Get the interrupt controller */ + iPar = of_find_node_by_name(NULL, "mpic"); + hwIrq = 0; + + ASSERT_COND(iPar != NULL); + /* Get the irq host */ + irqHost = irq_find_host(iPar); + of_node_put(iPar); + + /* Create irq mapping */ + return irq_create_mapping(irqHost, hwIrq); +} +#else +#error "kernel not supported!!!" +#endif /* LINUX_VERSION_CODE */ + +void * XX_PhysToVirt(physAddress_t addr) +{ + return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr)); +} + +physAddress_t XX_VirtToPhys(void * addr) +{ + return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr)); +} + +void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) +{ + uintptr_t *returnCode, tmp; + + if (alignment < sizeof(uintptr_t)) + alignment = sizeof(uintptr_t); + size += alignment + sizeof(returnCode); + tmp = (uintptr_t)xx_Malloc(size); + if (tmp == 0) + return NULL; + returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1)); + *(returnCode - 1) = tmp; + + return (void*)returnCode; +} + +void xx_FreeSmart(void *p) +{ + xx_Free((void*)(*((uintptr_t *)(p) - 1))); +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/xx/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/xx/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +obj-y += fsl-ncsw-xx.o + +fsl-ncsw-xx-objs := xx_linux.o udivdi3.o stdlib.o + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/inc/types_linux.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/inc/types_linux.h @@ -0,0 +1,200 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TYPES_LINUX_H__ +#define __TYPES_LINUX_H__ + +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ + +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) + #error "This kernel is probably not supported!!!" +#elif (!((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) || \ + (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)) || \ + (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30)))) + #warning "This kernel is probably not supported!!! You may need to add some fixes." +#endif /* LINUX_VERSION_CODE */ + + +typedef float float_t; /* Single precision floating point */ +typedef double double_t; /* Double precision floating point */ + + +#define _Packed +#define _PackedType __attribute__ ((packed)) + +typedef phys_addr_t physAddress_t; + +#define UINT8_MAX 0xFF +#define UINT8_MIN 0 +#define UINT16_MAX 0xFFFF +#define UINT16_MIN 0 +#define UINT32_MAX 0xFFFFFFFF +#define UINT32_MIN 0 +#define UINT64_MAX 0xFFFFFFFFFFFFFFFFLL +#define UINT64_MIN 0 +#define INT8_MAX 0x7F +#define INT8_MIN 0x80 +#define INT16_MAX 0x7FFF +#define INT16_MIN 0x8000 +#define INT32_MAX 0x7FFFFFFF +#define INT32_MIN 0x80000000 +#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL +#define INT64_MIN 0x8000000000000000LL + +#define ON 1 +#define OFF 0 + +#define FALSE false +#define TRUE true + + +/************************/ +/* memory access macros */ +/************************/ +#define GET_UINT8(arg) *(volatile uint8_t *)(&(arg)) +#define GET_UINT16(arg) in_be16(&(arg))//*(volatile uint16_t*)(&(arg)) +#define GET_UINT32(arg) in_be32(&(arg))//*(volatile uint32_t*)(&(arg)) +#define GET_UINT64(arg) *(volatile uint64_t*)(&(arg)) + +#ifdef VERBOSE_WRITE +void XX_Print(char *str, ...); +#define WRITE_UINT8(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%02x\r\n", (uint32_t)&(arg), (data)); *(volatile uint8_t *)(&(arg)) = (data); } while (0) +#define WRITE_UINT16(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%04x\r\n", (uint32_t)&(arg), (data)); out_be16(&(arg), data); /* *(volatile uint16_t*)(&(arg)) = (data);*/ } while (0) +#define WRITE_UINT32(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%08x\r\n", (uint32_t)&(arg), (data)); out_be32(&(arg), data); /* *(volatile uint32_t*)(&(arg)) = (data);*/ } while (0) +#define WRITE_UINT64(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%016llx\r\n", (uint32_t)&(arg), (data)); *(volatile uint64_t*)(&(arg)) = (data); } while (0) + +#else /* not VERBOSE_WRITE */ +#define WRITE_UINT8(arg, data) *(volatile uint8_t *)(&(arg)) = (data) +#define WRITE_UINT16(arg, data) out_be16(&(arg), data)//*(volatile uint16_t*)(&(arg)) = (data) +#define WRITE_UINT32(arg, data) out_be32(&(arg), data)//*(volatile unsigned int *)(&(arg)) = (data) +#define WRITE_UINT64(arg, data) *(volatile uint64_t*)(&(arg)) = (data) +#endif /* not VERBOSE_WRITE */ + + +/*****************************************************************************/ +/* General stuff */ +/*****************************************************************************/ +#ifdef ARRAY_SIZE +#undef ARRAY_SIZE +#endif /* ARRAY_SIZE */ + +#ifdef MAJOR +#undef MAJOR +#endif /* MAJOR */ + +#ifdef MINOR +#undef MINOR +#endif /* MINOR */ + +#ifdef QE_SIZEOF_BD +#undef QE_SIZEOF_BD +#endif /* QE_SIZEOF_BD */ + +#ifdef BD_BUFFER_CLEAR +#undef BD_BUFFER_CLEAR +#endif /* BD_BUFFER_CLEAR */ + +#ifdef BD_BUFFER +#undef BD_BUFFER +#endif /* BD_BUFFER */ + +#ifdef BD_STATUS_AND_LENGTH_SET +#undef BD_STATUS_AND_LENGTH_SET +#endif /* BD_STATUS_AND_LENGTH_SET */ + +#ifdef BD_STATUS_AND_LENGTH +#undef BD_STATUS_AND_LENGTH +#endif /* BD_STATUS_AND_LENGTH */ + +#ifdef BD_BUFFER_ARG +#undef BD_BUFFER_ARG +#endif /* BD_BUFFER_ARG */ + +#ifdef BD_GET_NEXT +#undef BD_GET_NEXT +#endif /* BD_GET_NEXT */ + +#ifdef QE_SDEBCR_BA_MASK +#undef QE_SDEBCR_BA_MASK +#endif /* QE_SDEBCR_BA_MASK */ + +#ifdef BD_BUFFER_SET +#undef BD_BUFFER_SET +#endif /* BD_BUFFER_SET */ + +#ifdef UPGCR_PROTOCOL +#undef UPGCR_PROTOCOL +#endif /* UPGCR_PROTOCOL */ + +#ifdef UPGCR_TMS +#undef UPGCR_TMS +#endif /* UPGCR_TMS */ + +#ifdef UPGCR_RMS +#undef UPGCR_RMS +#endif /* UPGCR_RMS */ + +#ifdef UPGCR_ADDR +#undef UPGCR_ADDR +#endif /* UPGCR_ADDR */ + +#ifdef UPGCR_DIAG +#undef UPGCR_DIAG +#endif /* UPGCR_DIAG */ + +#ifdef PARAMS +#undef PARAMS +#endif /* PARAMS */ + +#ifdef NO_IRQ +#undef NO_IRQ +#endif /* NO_IRQ */ + +#define PRINT_LINE XX_Print("%s:\n %s [%d]\n",__FILE__,__FUNCTION__,__LINE__); + + +#endif /* __TYPES_LINUX_H__ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/inc/xx/xx.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/inc/xx/xx.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XX_H +#define __XX_H + +#include "xx_ext.h" + +void * xx_Malloc(uint32_t n); +void xx_Free(void *p); + +void *xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t align); +void xx_FreeSmart(void *p); + +/* never used: */ +#define GetDeviceName(irq) ((char *)NULL) + +int GetDeviceIrqNum(int irq); + + +#endif /* __XX_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/inc/wrapper/lnxwrp_fm_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/inc/wrapper/lnxwrp_fm_ext.h @@ -0,0 +1,162 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File lnxwrp_fm_ext.h + + @Description TODO +*//***************************************************************************/ + +#ifndef __LNXWRP_FM_EXT_H +#define __LNXWRP_FM_EXT_H + +#include "std_ext.h" +#include "sys_ext.h" +#include "fm_ext.h" +#include "fm_muram_ext.h" +#include "fm_pcd_ext.h" +#include "fm_port_ext.h" +#include "fm_mac_ext.h" +#include "fm_rtc_ext.h" + + +/**************************************************************************//** + @Group FM_LnxKern_grp Frame Manager Linux wrapper API + + @Description FM API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_LnxKern_init_grp Initialization Unit + + @Description Initialization Unit + + Initialization Flow: + Initialization of the FM Module will be carried out by the Linux + kernel according to the following sequence: + a. Calling the initialization routine with no parameters. + b. The driver will register to the Device-Tree. + c. The Linux Device-Tree will initiate a call to the driver for + initialization. + d. The driver will read the appropriate information from the Device-Tree + e. [Optional] Calling the advance initialization routines to change + driver's defaults. + f. Initialization of the device will be automatically upon using it. + + @{ +*//***************************************************************************/ + +typedef struct t_WrpFmDevSettings +{ + t_FmParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmDevSettings; + +typedef struct t_WrpFmPcdDevSettings +{ + t_FmPcdParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmPcdDevSettings; + +typedef struct t_WrpFmPortDevSettings +{ + t_FmPortParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmPortDevSettings; + +typedef struct t_WrpFmMacDevSettings +{ + t_FmMacParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmMacDevSettings; + + +/**************************************************************************//** + @Function LNXWRP_FM_Init + + @Description Initialize the FM linux wrapper. + + @Return A handle (descriptor) of the newly created FM Linux wrapper + structure. +*//***************************************************************************/ +t_Handle LNXWRP_FM_Init(void); + +/**************************************************************************//** + @Function LNXWRP_FM_Free + + @Description Free the FM linux wrapper. + + @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm); + +/**************************************************************************//** + @Function LNXWRP_FM_GetMacHandle + + @Description Get the FM-MAC LLD handle from the FM linux wrapper. + + @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper. + @Param[in] fmId - Index of the FM device to get the MAC handle from. + @Param[in] macId - Index of the mac handle. + + @Return A handle of the LLD compressor. +*//***************************************************************************/ +t_Handle LNXWRP_FM_GetMacHandle(t_Handle h_LnxWrpFm, uint8_t fmId, uint8_t macId); + +#ifdef CONFIG_FSL_FMAN_TEST +t_Handle LNXWRP_FM_TEST_Init(void); +t_Error LNXWRP_FM_TEST_Free(t_Handle h_FmTestLnxWrp); +#endif /* CONFIG_FSL_FMAN_TEST */ + +/** @} */ /* end of FM_LnxKern_init_grp group */ + + +/**************************************************************************//** + @Group FM_LnxKern_ctrl_grp Control Unit + + @Description Control Unit + + TODO + @{ +*//***************************************************************************/ + +#include "fsl_fman.h" + +/** @} */ /* end of FM_LnxKern_ctrl_grp group */ +/** @} */ /* end of FM_LnxKern_grp group */ + + +#endif /* __LNXWRP_FM_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/inc/wrapper/fsl_fman_test.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/inc/wrapper/fsl_fman_test.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fsl_fman_test.h + + @Description +*//***************************************************************************/ + +#ifndef __FSL_FMAN_TEST_H +#define __FSL_FMAN_TEST_H + +#include + + +#define FMT_RX_ERR_Q 0xffffffff +#define FMT_RX_DFLT_Q 0xfffffffe +#define FMT_TX_ERR_Q 0xfffffffd +#define FMT_TX_CONF_Q 0xfffffffc + + +/**************************************************************************//** + @Function is_fman_test + + @Description Check if arriving frame belong to the test + + @Param[in] mac_dev - TODO + @Param[in] queueId - TODO + @Param[in] buffer - A pointer to the buffer to check. + @Param[in] size - size of the given buffer. + + @Return true if this buffer belongs to FMan test application; false otherwise. + + @Cautions Allowed only the port is initialized. +*//***************************************************************************/ +bool is_fman_test (void *mac_dev, + uint32_t queueId, + uint8_t *buffer, + uint32_t size); + +/**************************************************************************//** + @Function fman_test_ip_manip + + @Description IP header manipulation + + @Param[in] mac_dev - TODO + @Param[in] data - A pointer to the data (payload) to manipulate. + + @Cautions Allowed only the port is initialized. +*//***************************************************************************/ +void fman_test_ip_manip (void *mac_dev, uint8_t *data); + + +#endif /* __FSL_FMAN_TEST_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/inc/wrapper/fsl_fman.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/inc/wrapper/fsl_fman.h @@ -0,0 +1,279 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fsl_fman.h + + @Description Linux internal kernel API +*//***************************************************************************/ + +#ifndef __FSL_FMAN_H +#define __FSL_FMAN_H + +#include +#include /* struct device */ +#include /* struct qman_fq */ +#include "dpaa_integration_ext.h" + +/**************************************************************************//** + @Group FM_LnxKern_grp Frame Manager Linux wrapper API + + @Description FM API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_LnxKern_ctrl_grp Control Unit + + @Description Control Unit + + Internal Kernel Control Unit API + @{ +*//***************************************************************************/ + +/*****************************************************************************/ +/* Internal Linux kernel routines */ +/*****************************************************************************/ + +/**************************************************************************//** + @Description A structure .., +*//***************************************************************************/ +struct fm; + +/**************************************************************************//** + @Description A structure .., +*//***************************************************************************/ +struct fm_port; + +typedef int (*alloc_pcd_fqids)(struct device *dev, + uint32_t num, + uint8_t alignment, + uint32_t *base_fqid); + +typedef int (*free_pcd_fqids)(struct device *dev, + uint32_t base_fqid); + +struct fm_port_pcd_param { + alloc_pcd_fqids cba; + free_pcd_fqids cbf; + struct device *dev; +}; + +/**************************************************************************//** + @Description A structure of information about each of the external + buffer pools used by the port, +*//***************************************************************************/ +struct fm_port_pool_param { + uint8_t id; /**< External buffer pool id */ + uint16_t size; /**< External buffer pool buffer size */ +}; + +/**************************************************************************//** + @Description structure for additional Rx port parameters +*//***************************************************************************/ +struct fm_port_rx_params { + uint32_t errq; /**< Error Queue Id. */ + uint32_t defq; /**< Default Queue Id. */ + uint8_t num_pools; /**< Number of pools use by this port */ + struct fm_port_pool_param pool_param[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + /**< Parameters for each pool */ + uint16_t priv_data_size; /**< Area that user may save for his own need (E.g. save the SKB) */ + bool parse_results; /**< Whether to have the parser-results in the Received buffer */ + bool hash_results; /**< Whether to have the hash-results in the Received buffer */ + bool time_stamp; /**< Whether to have the time-stamp in the Received buffer */ +}; + +/**************************************************************************//** + @Description structure for additional non-Rx port parameters +*//***************************************************************************/ +struct fm_port_non_rx_params { + uint32_t errq; /**< Error Queue Id. */ + uint32_t defq; /**< For Tx and HC - Default Confirmation queue, + 0 means no Tx confirmation for processed + frames. For OP - default Rx queue. */ + uint16_t priv_data_size; /**< Area that user may save for his own need (E.g. save the SKB) */ + bool parse_results; /**< Whether to put the parser-results in the Transmitted buffer */ + bool hash_results; /**< Whether to have the hash-results in the Received buffer */ + bool time_stamp; /**< Whether to have the time-stamp in the Received buffer */ +}; + + +/**************************************************************************//** + @Function fm_bind + + @Description Bind to a specific FM device. + + @Param[in] fm_dev - the OF handle of the FM device. + + @Return A handle of the FM device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +struct fm * fm_bind (struct device *fm_dev); + +/**************************************************************************//** + @Function fm_unbind + + @Description Un-bind from a specific FM device. + + @Param[in] fm - A handle of the FM device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +void fm_unbind(struct fm *fm); + +void * fm_get_handle(struct fm *fm); +void * fm_get_rtc_handle(struct fm *fm); +struct resource * fm_get_mem_region(struct fm *fm); + +/**************************************************************************//** + @Function fm_port_bind + + @Description Bind to a specific FM-port device (may be Rx or Tx port). + + @Param[in] fm_port_dev - the OF handle of the FM port device. + + @Return A handle of the FM port device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +struct fm_port * fm_port_bind (struct device *fm_port_dev); + +/**************************************************************************//** + @Function fm_port_unbind + + @Description Un-bind from a specific FM-port device (may be Rx or Tx port). + + @Param[in] port - A handle of the FM port device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +void fm_port_unbind(struct fm_port *port); + +/**************************************************************************//** + @Function fm_set_rx_port_params + + @Description Configure parameters for a specific Rx FM-port device. + + @Param[in] port - A handle of the FM port device. + @Param[in] params - Rx port parameters + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +void fm_set_rx_port_params(struct fm_port *port, struct fm_port_rx_params *params); + +/**************************************************************************//** + @Function fm_port_pcd_bind + + @Description Bind as a listener on a port PCD. + + @Param[in] port - A handle of the FM port device. + @Param[in] params - PCD port parameters + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params); + +/**************************************************************************//** + @Function fm_get_tx_port_channel + + @Description Get qman-channel number for this Tx port. + + @Param[in] port - A handle of the FM port device. + + @Return qman-channel number for this Tx port. + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +int fm_get_tx_port_channel(struct fm_port *port); + +/**************************************************************************//** + @Function fm_set_tx_port_params + + @Description Configure parameters for a specific Tx FM-port device + + @Param[in] port - A handle of the FM port device. + @Param[in] params - Tx port parameters + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +void fm_set_tx_port_params(struct fm_port *port, struct fm_port_non_rx_params *params); + +/**************************************************************************//** + @Function fm_port_enable + + @Description Enable specific FM-port device (may be Rx or Tx port). + + @Param[in] port - A handle of the FM port device. + + @Cautions Allowed only the port is initialized. +*//***************************************************************************/ +int fm_port_enable (struct fm_port *port); + +/**************************************************************************//** + @Function fm_port_disable + + @Description Disable specific FM-port device (may be Rx or Tx port). + + @Param[in] port - A handle of the FM port device. + + @Cautions Allowed only the port is initialized. +*//***************************************************************************/ +void fm_port_disable(struct fm_port *port); + +void * fm_port_get_handle(struct fm_port *port); + +/**************************************************************************//** + @Description Get base address of this port. Useful for accessing + port-specific registers (i.e., not common ones). + + @Param[in] port - A handle of the FM port device. + @Param[out] base_addr - The port's base addr (virtual address). +*//***************************************************************************/ +void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr); + +/**************************************************************************//** + @Description Lock function required before any FMD/LLD call. +*//***************************************************************************/ +void fm_mutex_lock(void); + +/**************************************************************************//** + @Description Unlock function required after any FMD/LLD call. +*//***************************************************************************/ +void fm_mutex_unlock(void); + +/** @} */ /* end of FM_LnxKern_ctrl_grp group */ +/** @} */ /* end of FM_LnxKern_grp group */ + + +#endif /* __FSL_FMAN_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/inc/system/sys_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/inc/system/sys_ext.h @@ -0,0 +1,118 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYS_EXT_H +#define __SYS_EXT_H + +#include "std_ext.h" + + +/**************************************************************************//** + @Group sys_grp System Interfaces + + @Description Linux system programming interfaces. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group sys_gen_grp System General Interface + + @Description General definitions, structures and routines of the linux + system programming interface. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection Macros for Advanced Configuration Requests + @{ +*//***************************************************************************/ +#define SYS_MAX_ADV_CONFIG_ARGS 4 + /**< Maximum number of arguments in + an advanced configuration entry */ +/* @} */ + +/**************************************************************************//** + @Description System Object Advanced Configuration Entry + + This structure represents a single request for an advanced + configuration call on the initialized object. An array of such + requests may be contained in the settings structure of the + corresponding object. + + The maximum number of arguments is limited to #SYS_MAX_ADV_CONFIG_ARGS. +*//***************************************************************************/ +typedef struct t_SysObjectAdvConfigEntry +{ + void *p_Function; /**< Pointer to advanced configuration routine */ + + uintptr_t args[SYS_MAX_ADV_CONFIG_ARGS]; + /**< Array of arguments for the specified routine; + All arguments should be casted to uint32_t. */ +} t_SysObjectAdvConfigEntry; + + +/** @} */ /* end of sys_gen_grp */ +/** @} */ /* end of sys_grp */ + +#define PARAMS(_num, _params) ADV_CONFIG_PARAMS_##_num _params + +#define ADV_CONFIG_PARAMS_1(_type) \ + , (_type)p_Entry->args[0] + +#define SET_ADV_CONFIG_ARGS_1(_arg0) \ + p_Entry->args[0] = (uintptr_t )(_arg0); \ + +#define ARGS(_num, _params) SET_ADV_CONFIG_ARGS_##_num _params + +#define ADD_ADV_CONFIG_START(_p_Entries, _maxEntries) \ + { \ + t_SysObjectAdvConfigEntry *p_Entry; \ + t_SysObjectAdvConfigEntry *p_Entrys = (_p_Entries); \ + int i=0, max = (_maxEntries); \ + +#define ADD_ADV_CONFIG_END \ + } + +#define ADV_CONFIG_CHECK_START(_p_Entry) \ + { \ + t_SysObjectAdvConfigEntry *p_Entry = _p_Entry; \ + t_Error errCode; \ + +#define ADV_CONFIG_CHECK(_handle, _func, _params) \ + if (p_Entry->p_Function == _func) \ + { \ + errCode = _func(_handle _params); \ + } else + +#endif /* __SYS_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/inc/system/sys_io_ext.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/inc/system/sys_io_ext.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYS_IO_EXT_H +#define __SYS_IO_EXT_H + +#include "std_ext.h" +#include "error_ext.h" + + +t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size); +t_Error SYS_UnregisterIoMap (uint64_t virtAddr); +uint64_t SYS_PhysToVirt (uint64_t addr); +uint64_t SYS_VirtToPhys (uint64_t addr); + + +#endif /* __SYS_IO_EXT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm_port.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm_port.c @@ -0,0 +1,364 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_sysfs_fm_port.c + + @Description FM port sysfs related functions. + +*/ + +#include "lnxwrp_sysfs.h" +#include "lnxwrp_fm.h" + +static const struct SysfsStats_t portSysfsStats[] = { + /* RX/TX/OH common statistics */ + { + .statisticName = "port_frame", + .statisticCounter = e_FM_PORT_COUNTERS_FRAME, + }, + { + .statisticName = "port_discard_frame", + .statisticCounter = e_FM_PORT_COUNTERS_DISCARD_FRAME, + }, + { + .statisticName = "port_dealloc_buf", + .statisticCounter = e_FM_PORT_COUNTERS_DEALLOC_BUF, + }, + { + .statisticName = "port_enq_total", + .statisticCounter = e_FM_PORT_COUNTERS_ENQ_TOTAL, + }, + /* TX/OH */ + { + .statisticName = "port_length_err", + .statisticCounter = e_FM_PORT_COUNTERS_LENGTH_ERR, + }, + { + .statisticName = "port_unsupprted_format", + .statisticCounter = e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, + }, + { + .statisticName = "port_deq_total", + .statisticCounter = e_FM_PORT_COUNTERS_DEQ_TOTAL, + }, + { + .statisticName = "port_deq_from_default", + .statisticCounter = e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, + }, + { + .statisticName = "port_deq_confirm", + .statisticCounter = e_FM_PORT_COUNTERS_DEQ_CONFIRM, + }, + /* RX/OH */ + { + .statisticName = "port_rx_bad_frame", + .statisticCounter = e_FM_PORT_COUNTERS_RX_BAD_FRAME, + }, + { + .statisticName = "port_rx_large_frame", + .statisticCounter = e_FM_PORT_COUNTERS_RX_LARGE_FRAME, + }, + { + .statisticName = "port_rx_out_of_buffers_discard", + .statisticCounter = e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, + }, + { + .statisticName = "port_rx_filter_frame", + .statisticCounter = e_FM_PORT_COUNTERS_RX_FILTER_FRAME, + }, + /* TODO: Particular statistics for OH ports */ + {} +}; + +static ssize_t show_fm_port_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + t_LnxWrpFmDev *p_LnxWrpFmDev; + unsigned long flags; + int n = 0; + uint8_t counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmPortDev == NULL)) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + + if (!p_LnxWrpFmPortDev->h_Dev) { + n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); + return n; + } + + counter = + fm_find_statistic_counter_by_name(attr->attr.name, + (struct SysfsStats_t *) & + portSysfsStats[0], NULL); + + if (counter == e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR) { + uint32_t fmRev = 0; + fmRev = 0xffff & ioread32(UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr + + 0x000c30c4)); + + if (fmRev == 0x0100) { + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "counter not available for revision 1\n"); + local_irq_restore(flags); + } + return n; + } + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, "\tFM %d Port %d counter: %d\n", + p_LnxWrpFmDev->id, + p_LnxWrpFmPortDev->id, + FM_PORT_GetCounter(p_LnxWrpFmPortDev->h_Dev, + (e_FmPortCounters) counter)); + local_irq_restore(flags); + + return n; +} + +/* FM PORT RX/TX/OH statistics */ +static DEVICE_ATTR(port_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_discard_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_dealloc_buf, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_enq_total, S_IRUGO, show_fm_port_stats, NULL); +/* FM PORT TX/OH statistics */ +static DEVICE_ATTR(port_length_err, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_unsupprted_format, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_deq_total, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_deq_from_default, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_deq_confirm, S_IRUGO, show_fm_port_stats, NULL); +/* FM PORT RX/OH statistics */ +static DEVICE_ATTR(port_rx_bad_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_rx_large_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_rx_out_of_buffers_discard, S_IRUGO, + show_fm_port_stats, NULL); +static DEVICE_ATTR(port_rx_filter_frame, S_IRUGO, show_fm_port_stats, NULL); + +/* FM PORT TX statistics */ +static struct attribute *fm_tx_port_dev_stats_attributes[] = { + &dev_attr_port_frame.attr, + &dev_attr_port_discard_frame.attr, + &dev_attr_port_dealloc_buf.attr, + &dev_attr_port_enq_total.attr, + &dev_attr_port_length_err.attr, + &dev_attr_port_unsupprted_format.attr, + &dev_attr_port_deq_total.attr, + &dev_attr_port_deq_from_default.attr, + &dev_attr_port_deq_confirm.attr, + NULL +}; + +static const struct attribute_group fm_tx_port_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_tx_port_dev_stats_attributes +}; + +/* FM PORT RX statistics */ +static struct attribute *fm_rx_port_dev_stats_attributes[] = { + &dev_attr_port_frame.attr, + &dev_attr_port_discard_frame.attr, + &dev_attr_port_dealloc_buf.attr, + &dev_attr_port_enq_total.attr, + &dev_attr_port_rx_bad_frame.attr, + &dev_attr_port_rx_large_frame.attr, + &dev_attr_port_rx_out_of_buffers_discard.attr, + &dev_attr_port_rx_filter_frame.attr, + NULL +}; + +static const struct attribute_group fm_rx_port_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_rx_port_dev_stats_attributes +}; + +/* TODO: add particular OH ports statistics */ +static struct attribute *fm_oh_port_dev_stats_attributes[] = { + &dev_attr_port_frame.attr, + &dev_attr_port_discard_frame.attr, + &dev_attr_port_dealloc_buf.attr, + &dev_attr_port_enq_total.attr, + /*TX*/ &dev_attr_port_length_err.attr, + &dev_attr_port_unsupprted_format.attr, + &dev_attr_port_deq_total.attr, + &dev_attr_port_deq_from_default.attr, + &dev_attr_port_deq_confirm.attr, + /*RX*/ &dev_attr_port_rx_bad_frame.attr, + &dev_attr_port_rx_large_frame.attr, + &dev_attr_port_rx_out_of_buffers_discard.attr, + /*&dev_attr_port_rx_filter_frame.attr, */ + NULL +}; + +static const struct attribute_group fm_oh_port_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_oh_port_dev_stats_attributes +}; + +static ssize_t show_fm_port_regs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long flags; + unsigned n = 0; +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = + (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); +#endif + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + local_irq_save(flags); + + if (!p_LnxWrpFmPortDev->h_Dev) { + n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); + return n; + } else { + n = snprintf(buf, PAGE_SIZE, + "FM port driver registers dump.\n"); + FM_PORT_DumpRegs(p_LnxWrpFmPortDev->h_Dev); + } + + local_irq_restore(flags); + + return n; +#else + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "Debug level is too low to dump registers!!!\n"); + local_irq_restore(flags); + + return n; +#endif +} + +static DEVICE_ATTR(fm_port_regs, 0x644, show_fm_port_regs, NULL); + +int fm_port_sysfs_create(struct device *dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + + if (dev == NULL) + return -EINVAL; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmPortDev == NULL)) + return -EINVAL; + + /* store to remove them when module is disabled */ + p_LnxWrpFmPortDev->dev_attr_regs = &dev_attr_fm_port_regs; + + /* Registers dump entry - in future will be moved to debugfs */ + if (device_create_file(dev, &dev_attr_fm_port_regs) != 0) + return -EIO; + + /* FM Ports statistics */ + switch (p_LnxWrpFmPortDev->settings.param.portType) { + case e_FM_PORT_TYPE_TX: + case e_FM_PORT_TYPE_TX_10G: + if (sysfs_create_group + (&dev->kobj, &fm_tx_port_dev_stats_attr_grp) != 0) + return -EIO; + break; + case e_FM_PORT_TYPE_RX: + case e_FM_PORT_TYPE_RX_10G: + if (sysfs_create_group + (&dev->kobj, &fm_rx_port_dev_stats_attr_grp) != 0) + return -EIO; + break; + case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: + case e_FM_PORT_TYPE_OH_HOST_COMMAND: + if (sysfs_create_group + (&dev->kobj, &fm_oh_port_dev_stats_attr_grp) != 0) + return -EIO; + break; + case e_FM_PORT_TYPE_DUMMY: + default: + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + return -EINVAL; + break; + }; + + return 0; +} + +void fm_port_sysfs_destroy(struct device *dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL; + + /* this function has never been tested !!! */ + + if (WARN_ON(dev == NULL)) + return; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmPortDev == NULL)) + return; + + /* The name attribute will be freed also by these 2 functions? */ + switch (p_LnxWrpFmPortDev->settings.param.portType) { + case e_FM_PORT_TYPE_TX: + case e_FM_PORT_TYPE_TX_10G: + sysfs_remove_group(&dev->kobj, &fm_tx_port_dev_stats_attr_grp); + break; + case e_FM_PORT_TYPE_RX: + case e_FM_PORT_TYPE_RX_10G: + sysfs_remove_group(&dev->kobj, &fm_rx_port_dev_stats_attr_grp); + break; + case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: + case e_FM_PORT_TYPE_OH_HOST_COMMAND: + sysfs_remove_group(&dev->kobj, &fm_oh_port_dev_stats_attr_grp); + break; + case e_FM_PORT_TYPE_DUMMY: + default: + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + break; + }; + + device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_regs); +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_fm_port.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_fm_port.c @@ -0,0 +1,1183 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_fm_port.c + + @Description FMD wrapper - FMan port functions. + +*/ + +#include +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ +#include +#include +#include +#include +#include +#include +#include + +#include "sprint_ext.h" +#include "fm_port_ext.h" +#include "fm_ioctls.h" +#include "lnxwrp_resources.h" +#include "lnxwrp_sysfs_fm_port.h" + +/* TODO: duplicated, see lnxwrp_fm.c */ +#define ADD_ADV_CONFIG_NO_RET(_func, _param)\ +do {\ + if (i < max) {\ + p_Entry = &p_Entrys[i];\ + p_Entry->p_Function = _func;\ + _param\ + i++;\ + } else {\ + REPORT_ERROR(MAJOR, E_INVALID_VALUE,\ + ("Number of advanced-configuration entries exceeded"));\ + } \ +} while (0) + + +static volatile int hcFrmRcv/* = 0 */; +static spinlock_t lock; + +static enum qman_cb_dqrr_result qm_tx_conf_dqrr_cb(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry + *dq) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_FmTestFq *) fq)->h_Arg; + unsigned long flags; + + FM_PCD_HcTxConf(p_LnxWrpFmDev->h_PcdDev, (t_DpaaFD *)&dq->fd); + spin_lock_irqsave(&lock, flags); + hcFrmRcv--; + spin_unlock_irqrestore(&lock, flags); + + return qman_cb_dqrr_consume; +} + +static enum qman_cb_dqrr_result qm_tx_dqrr_cb(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + return qman_cb_dqrr_consume; +} + +static void qm_err_cb(struct qman_portal *portal, + struct qman_fq *fq, const struct qm_mr_entry *msg) +{ + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); +} + +static struct qman_fq *FqAlloc(t_LnxWrpFmDev * p_LnxWrpFmDev, + uint32_t fqid, + uint32_t flags, uint16_t channel, uint8_t wq) +{ + int _errno; + struct qman_fq *fq = NULL; + t_FmTestFq *p_FmtFq; + struct qm_mcc_initfq initfq; + + p_FmtFq = (t_FmTestFq *) XX_Malloc(sizeof(t_FmTestFq)); + if (!p_FmtFq) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!")); + return NULL; + } + + p_FmtFq->fq_base.cb.dqrr = + (QMAN_FQ_FLAG_NO_ENQUEUE ? qm_tx_conf_dqrr_cb : + qm_tx_dqrr_cb); + p_FmtFq->fq_base.cb.ern = qm_err_cb; + p_FmtFq->fq_base.cb.dc_ern = qm_err_cb; + /* p_FmtFq->fq_base.cb.fqs = qm_err_cb; */ + /* qm_err_cb wrongly called when the FQ is parked */ + p_FmtFq->fq_base.cb.fqs = NULL; + p_FmtFq->h_Arg = (t_Handle) p_LnxWrpFmDev; + if (fqid == 0) { + flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; + flags &= ~QMAN_FQ_FLAG_NO_MODIFY; + } else { + flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID; + } + + if (qman_create_fq(fqid, flags, &p_FmtFq->fq_base)) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj - qman_new_fq!!!")); + XX_Free(p_FmtFq); + return NULL; + } + fq = &p_FmtFq->fq_base; + + if (!(flags & QMAN_FQ_FLAG_NO_MODIFY)) { + initfq.we_mask = QM_INITFQ_WE_DESTWQ; + initfq.fqd.dest.channel = channel; + initfq.fqd.dest.wq = wq; + + _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, + ("FQ obj - qman_init_fq!!!")); + qman_destroy_fq(fq, 0); + XX_Free(p_FmtFq); + return NULL; + } + } + + DBG(TRACE, + ("fqid %d, flags 0x%08x, channel %d, wq %d", qman_fq_fqid(fq), + flags, channel, wq)); + + return fq; +} + +static void FqFree(struct qman_fq *fq) +{ + int _errno; + + _errno = qman_retire_fq(fq, NULL); + if (unlikely(_errno < 0)) + printk(KERN_WARNING "qman_retire_fq(%u) = %d\n", qman_fq_fqid(fq), _errno); + + _errno = qman_oos_fq(fq); + if (unlikely(_errno < 0)) + printk(KERN_WARNING "qman_oos_fq(%u) = %d\n", qman_fq_fqid(fq), _errno); + + qman_destroy_fq(fq, 0); + XX_Free((t_FmTestFq *) fq); +} + +static t_Error QmEnqueueCB(t_Handle h_Arg, void *p_Fd) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_Arg; + int _errno, timeout = 1000000; + unsigned long flags; + + ASSERT_COND(p_LnxWrpFmDev); + + spin_lock_irqsave(&lock, flags); + hcFrmRcv++; + spin_unlock_irqrestore(&lock, flags); + + _errno = qman_enqueue(p_LnxWrpFmDev->hc_tx_fq, (struct qm_fd *) p_Fd, + 0); + if (_errno) + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("qman_enqueue() failed")); + + while (hcFrmRcv && --timeout) { + udelay(1); + cpu_relax(); + } + if (timeout == 0) { + dump_stack(); + RETURN_ERROR(MINOR, E_WRITE_FAILED, + ("timeout waiting for Tx confirmation")); + return E_WRITE_FAILED; + } + + return E_OK; +} + +static t_LnxWrpFmPortDev *ReadFmPortDevTreeNode(struct platform_device + *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + struct device_node *fm_node, *port_node; + struct resource res; + const uint32_t *uint32_prop; + int _errno = 0, lenp; +#ifdef CONFIG_FMAN_P1023 + static unsigned char have_oh_port/* = 0 */; +#endif + + port_node = of_node_get(of_dev->dev.of_node); + + /* Get the FM node */ + fm_node = of_get_parent(port_node); + if (unlikely(fm_node == NULL)) { + REPORT_ERROR(MAJOR, E_NO_DEVICE, + ("of_get_parent() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev = + dev_get_drvdata(&of_find_device_by_node(fm_node)->dev); + of_node_put(fm_node); + + /* if fm_probe() failed, no point in going further with port probing */ + if (p_LnxWrpFmDev == NULL) + return NULL; + + uint32_prop = + (uint32_t *) of_get_property(port_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + if (of_device_is_compatible(port_node, "fsl,fman-port-oh")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_OH_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + +#ifdef CONFIG_FMAN_P1023 + /* Beware, this can be done when there is only + one FMan to be initialized */ + if (!have_oh_port) { + have_oh_port = 1; /* first OP/HC port + is used for host command */ +#else + /* Here it is hardcoded the use of the OH port 1 + (with cell-index 0) */ + if (*uint32_prop == 0) { +#endif + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; + p_LnxWrpFmPortDev->id = 0; + /* + p_LnxWrpFmPortDev->id = *uint32_prop-1; + p_LnxWrpFmPortDev->id = *uint32_prop; + */ + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_OH_HOST_COMMAND; + } else { + p_LnxWrpFmPortDev = + &p_LnxWrpFmDev->opPorts[*uint32_prop - 1]; + p_LnxWrpFmPortDev->id = *uint32_prop - 1; + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_OH_OFFLINE_PARSING; + } + p_LnxWrpFmPortDev->settings.param.portId = *uint32_prop; + + uint32_prop = + (uint32_t *) of_get_property(port_node, + "fsl,qman-channel-id", + &lenp); + if (uint32_prop == NULL) { + /* + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("missing fsl,qman-channel-id")); + */ + XX_Print("FM warning: missing fsl,qman-channel-id" + " for OH port.\n"); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmPortDev->txCh = *uint32_prop; + + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. + qmChannel = p_LnxWrpFmPortDev->txCh; + } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-tx") || + of_device_is_compatible(port_node, "fsl,fman-port-10g-tx")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_TX_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + if (of_device_is_compatible + (port_node, "fsl,fman-port-10g-tx")) + p_LnxWrpFmPortDev = + &p_LnxWrpFmDev->txPorts[*uint32_prop + + FM_MAX_NUM_OF_1G_TX_PORTS]; + else + p_LnxWrpFmPortDev = + &p_LnxWrpFmDev->txPorts[*uint32_prop]; + + p_LnxWrpFmPortDev->id = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.portId = + p_LnxWrpFmPortDev->id; + if (of_device_is_compatible + (port_node, "fsl,fman-port-10g-tx")) + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_TX_10G; + else + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_TX; + + uint32_prop = + (uint32_t *) of_get_property(port_node, + "fsl,qman-channel-id", + &lenp); + if (uint32_prop == NULL) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("missing fsl,qman-channel-id")); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmPortDev->txCh = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. + qmChannel = p_LnxWrpFmPortDev->txCh; + } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-rx") || + of_device_is_compatible(port_node, "fsl,fman-port-10g-rx")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_RX_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + if (of_device_is_compatible + (port_node, "fsl,fman-port-10g-rx")) + p_LnxWrpFmPortDev = + &p_LnxWrpFmDev->rxPorts[*uint32_prop + + FM_MAX_NUM_OF_1G_RX_PORTS]; + else + p_LnxWrpFmPortDev = + &p_LnxWrpFmDev->rxPorts[*uint32_prop]; + + p_LnxWrpFmPortDev->id = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.portId = + p_LnxWrpFmPortDev->id; + if (of_device_is_compatible + (port_node, "fsl,fman-port-10g-rx")) + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_RX_10G; + else + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_RX; + + if (p_LnxWrpFmDev->pcdActive) + p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd; + } else { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type")); + return NULL; + } + + _errno = of_address_to_resource(port_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmPortDev->dev = &of_dev->dev; + p_LnxWrpFmPortDev->baseAddr = 0; + p_LnxWrpFmPortDev->phys_baseAddr = res.start; + p_LnxWrpFmPortDev->memSize = res.end + 1 - res.start; + p_LnxWrpFmPortDev->settings.param.h_Fm = p_LnxWrpFmDev->h_Dev; + p_LnxWrpFmPortDev->h_LnxWrpFmDev = (t_Handle) p_LnxWrpFmDev; + + of_node_put(port_node); + + p_LnxWrpFmPortDev->active = TRUE; + +#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) + /* for performance mode no OH port available. */ + if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_LnxWrpFmPortDev->active = FALSE; +#endif + + return p_LnxWrpFmPortDev; +} + +static t_Error ConfigureFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct resource *dev_res; + + if (!p_LnxWrpFmPortDev->active) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("FM port not configured!!!")); + + dev_res = + __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, + p_LnxWrpFmPortDev->phys_baseAddr, + p_LnxWrpFmPortDev->memSize, + "fman-port-hc"); + if (unlikely(dev_res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("__devm_request_region() failed")); + p_LnxWrpFmPortDev->baseAddr = + PTR_TO_UINT(devm_ioremap + (p_LnxWrpFmDev->dev, + p_LnxWrpFmPortDev->phys_baseAddr, + p_LnxWrpFmPortDev->memSize)); + if (unlikely(p_LnxWrpFmPortDev->baseAddr == 0)) + REPORT_ERROR(MAJOR, E_INVALID_STATE, + ("devm_ioremap() failed")); + + p_LnxWrpFmPortDev->settings.param.baseAddr = + p_LnxWrpFmPortDev->baseAddr; + + return E_OK; +} + +static t_Error InitFmPort3TupleDefPcd(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + t_FmPcdNetEnvParams *p_netEnvParam = NULL; + t_FmPcdKgSchemeParams *p_schemeParam = NULL; + t_FmPortPcdParams pcdParam; + t_FmPortPcdPrsParams prsParam; + t_FmPortPcdKgParams kgParam; + uint8_t i, j; + + if (!p_LnxWrpFmDev->kgActive) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("keygen must be enabled for 3-tuple PCD!")); + + if (!p_LnxWrpFmDev->prsActive) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("parser must be enabled for 3-tuple PCD!")); + + if (p_LnxWrpFmPortDev->pcdNumOfQs < 9) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("Need to save at least 18 queues for" + "3-tuple PCD!!!")); + + p_LnxWrpFmPortDev->totalNumOfSchemes = + p_LnxWrpFmPortDev->numOfSchemesUsed = 2; + + if (AllocSchemesForPort + (p_LnxWrpFmDev, p_LnxWrpFmPortDev->totalNumOfSchemes, + &p_LnxWrpFmPortDev->schemesBase) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("No schemes for Rx or OP port for" + " 3-tuple PCD!!!")); + + p_netEnvParam = kzalloc(sizeof(*p_netEnvParam), GFP_KERNEL); + if (!p_netEnvParam) { + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("Failed to allocate p_netEnvParam")); + } + /* set netEnv */ + p_netEnvParam->numOfDistinctionUnits = 2; + p_netEnvParam->units[0].hdrs[0].hdr = + HEADER_TYPE_IPv4; /* no special options */ + p_netEnvParam->units[1].hdrs[0].hdr = HEADER_TYPE_ETH; + p_LnxWrpFmPortDev->h_DefNetEnv = + FM_PCD_SetNetEnvCharacteristics(p_LnxWrpFmDev->h_PcdDev, + p_netEnvParam); + kfree(p_netEnvParam); + if (!p_LnxWrpFmPortDev->h_DefNetEnv) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM PCD!")); + + p_schemeParam = kmalloc(sizeof(*p_schemeParam), GFP_KERNEL); + if (!p_schemeParam) { + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("Failed to allocate p_schemeParam")); + } + for (i = 0; i < p_LnxWrpFmPortDev->numOfSchemesUsed; i++) { + memset(p_schemeParam, 0, sizeof(*p_schemeParam)); + p_schemeParam->modify = FALSE; + p_schemeParam->id.relativeSchemeId = + i + p_LnxWrpFmPortDev->schemesBase; + p_schemeParam->alwaysDirect = FALSE; + p_schemeParam->netEnvParams.h_NetEnv = + p_LnxWrpFmPortDev->h_DefNetEnv; + p_schemeParam->schemeCounter.update = TRUE; + p_schemeParam->schemeCounter.value = 0; + + switch (i) { + case (0): /* catch IPv4 */ + p_schemeParam->netEnvParams.numOfDistinctionUnits = 1; + p_schemeParam->netEnvParams.unitIds[0] = 0; + p_schemeParam->baseFqid = p_LnxWrpFmPortDev->pcdBaseQ; + p_schemeParam->nextEngine = e_FM_PCD_DONE; + p_schemeParam->numOfUsedExtractedOrs = 0; + p_schemeParam->useHash = TRUE; + p_schemeParam->keyExtractAndHashParams. + numOfUsedExtracts = 3; + for (j = 0; + j < + p_schemeParam->keyExtractAndHashParams. + numOfUsedExtracts; j++) { + p_schemeParam->keyExtractAndHashParams. + extractArray[j].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_schemeParam->keyExtractAndHashParams. + extractArray[j].extractByHdr.hdr = + HEADER_TYPE_IPv4; + p_schemeParam->keyExtractAndHashParams. + extractArray[j].extractByHdr. + ignoreProtocolValidation = FALSE; + p_schemeParam->keyExtractAndHashParams. + extractArray[j].extractByHdr.type = + e_FM_PCD_EXTRACT_FULL_FIELD; + } + p_schemeParam->keyExtractAndHashParams. + extractArray[0].extractByHdr.extractByHdrType. + fullField.ipv4 = NET_HEADER_FIELD_IPv4_PROTO; + p_schemeParam->keyExtractAndHashParams. + extractArray[1].extractByHdr.extractByHdrType. + fullField.ipv4 = NET_HEADER_FIELD_IPv4_SRC_IP; + p_schemeParam->keyExtractAndHashParams. + extractArray[2].extractByHdr.extractByHdrType. + fullField.ipv4 = NET_HEADER_FIELD_IPv4_DST_IP; + + if (p_schemeParam->useHash) { + p_schemeParam->keyExtractAndHashParams. + privateDflt0 = 0x01020304; + p_schemeParam->keyExtractAndHashParams. + privateDflt1 = 0x11121314; + p_schemeParam->keyExtractAndHashParams. + numOfUsedDflts = + FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; + for (j = 0; + j < FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; + j++) { + /* all types */ + p_schemeParam->keyExtractAndHashParams.dflts[j].type = + (e_FmPcdKgKnownFieldsDfltTypes) j; + p_schemeParam-> + keyExtractAndHashParams. + dflts[j].dfltSelect = + e_FM_PCD_KG_DFLT_GBL_0; + } + p_schemeParam->keyExtractAndHashParams. + numOfUsedMasks = 0; + p_schemeParam->keyExtractAndHashParams. + hashShift = 0; + p_schemeParam->keyExtractAndHashParams. + hashDistributionNumOfFqids = 8; + } + break; + + case (1): /* Garbage collector */ + p_schemeParam->netEnvParams.numOfDistinctionUnits = 0; + p_schemeParam->baseFqid = + p_LnxWrpFmPortDev->pcdBaseQ + 8; + break; + + default: + break; + } + + p_LnxWrpFmPortDev->h_Schemes[i] = + FM_PCD_KgSetScheme(p_LnxWrpFmDev->h_PcdDev, + p_schemeParam); + if (!p_LnxWrpFmPortDev->h_Schemes[i]) { + kfree(p_schemeParam); + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, + ("FM_PCD_KgSetScheme failed")); + } + } + kfree(p_schemeParam); + + /* initialize PCD parameters */ + memset(&pcdParam, 0, sizeof(t_FmPortPcdParams)); + pcdParam.h_NetEnv = p_LnxWrpFmPortDev->h_DefNetEnv; + pcdParam.pcdSupport = e_FM_PORT_PCD_SUPPORT_PRS_AND_KG; + + /* initialize Keygen parameters */ + memset(&prsParam, 0, sizeof(t_FmPortPcdPrsParams)); + + prsParam.parsingOffset = 0; + prsParam.firstPrsHdr = HEADER_TYPE_ETH; + pcdParam.p_PrsParams = &prsParam; + + /* initialize Parser parameters */ + memset(&kgParam, 0, sizeof(t_FmPortPcdKgParams)); + kgParam.numOfSchemes = p_LnxWrpFmPortDev->numOfSchemesUsed; + for (i = 0; i < kgParam.numOfSchemes; i++) + kgParam.h_Schemes[i] = p_LnxWrpFmPortDev->h_Schemes[i]; + + pcdParam.p_KgParams = &kgParam; + + return FM_PORT_SetPCD(p_LnxWrpFmPortDev->h_Dev, &pcdParam); +} + +static t_Error InitFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ +#define MY_ADV_CONFIG_CHECK_END \ + RETURN_ERROR(MAJOR, E_INVALID_SELECTION,\ + ("Advanced configuration routine"));\ + if (errCode != E_OK)\ + RETURN_ERROR(MAJOR, errCode, NO_MSG);\ + } + + int i = 0; + + if (!p_LnxWrpFmPortDev->active || p_LnxWrpFmPortDev->h_Dev) + return E_INVALID_STATE; + + p_LnxWrpFmPortDev->h_Dev = + FM_PORT_Config(&p_LnxWrpFmPortDev->settings.param); + if (p_LnxWrpFmPortDev->h_Dev == NULL) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-port")); + + if ((p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) + || (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX)) { + t_Error errCode = E_OK; + errCode = + FM_PORT_ConfigDeqHighPriority(p_LnxWrpFmPortDev->h_Dev, + TRUE); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + errCode = + FM_PORT_ConfigDeqPrefetchOption(p_LnxWrpFmPortDev->h_Dev, + e_FM_PORT_DEQ_FULL_PREFETCH); + if (errCode + != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + } + +/* Call the driver's advanced configuration routines, if requested: + Compare the function pointer of each entry to the available routines, + and invoke the matching routine with proper casting of arguments. */ + while (p_LnxWrpFmPortDev->settings.advConfig[i].p_Function + && (i < FM_MAX_NUM_OF_ADV_SETTINGS)) { + ADV_CONFIG_CHECK_START(& + (p_LnxWrpFmPortDev->settings. + advConfig[i])) + + ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev, + FM_PORT_ConfigBufferPrefixContent, + PARAMS(1, + (t_FmPortBufferPrefixContent + *))) + + MY_ADV_CONFIG_CHECK_END + /* Advance to next advanced configuration entry */ + i++; + } + + if (FM_PORT_Init(p_LnxWrpFmPortDev->h_Dev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); +#if defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) + /* even if these functions return w/ error, do not crash kernel. + Do not return anything because the container function is not + linux complient (it should return -EIO). */ + fm_set_precalculate_fifosize(p_LnxWrpFmPortDev); + fm_set_precalculate_open_dma(p_LnxWrpFmPortDev); + fm_set_precalculate_tnums(p_LnxWrpFmPortDev); +#endif + +/* FMan Fifo sizes behind the scene": + * Using the following formulae (*), under a set of simplifying assumptions (.): + * . all ports are configured in Normal Mode (rather than Independent Mode) + * . the DPAA Eth driver allocates buffers of size: + * . MAXFRM + NET_IP_ALIGN + DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE + * + DPA_HASH_RESULTS_SIZE, i.e.: + * MAXFRM + 2 + 16 + sizeof(t_FmPrsResult) + 16, i.e.: + * MAXFRM + 66 + * . excessive buffer pools not accounted for + * + * * for Rx ports on P4080: + * . IFSZ = ceil(max(FMBM_EBMPI[PBS]) / 256) * 256 + 7 * 256 + * . no internal frame offset (FMBM_RIM[FOF] == 0) - otherwise, + * add up to 256 to the above + * + * * for Rx ports on P1023: + * . IFSZ = ceil(second_largest(FMBM_EBMPI[PBS] / 256)) * 256 + 7 * 256, + * if at least 2 bpools are configured + * . IFSZ = 8 * 256, if only a single bpool is configured + * + * * for Tx ports: + * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 + * + FMBM_TFP[DPDE] * 256, i.e.: + * IFSZ = ceil(MAXFRM / 256) * 256 + 3 x 256 + FMBM_TFP[DPDE] * 256 + * + * * for OH ports on P4080: + * . IFSZ = ceil(frame_size / 256) * 256 + 1 * 256 + FMBM_PP[MXT] * 256 + * * for OH ports on P1023: + * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 + FMBM_TFP[DPDE] * 256 + * * for both P4080 and P1023: + * . (conservative decisions, assuming that BMI must bring the entire + * frame, not only the frame header) + * . no internal frame offset (FMBM_OIM[FOF] == 0) - otherwise, + * add up to 256 to the above + * + * . for P4080/P5020/P3041/P2040, DPDE is: + * > 0 or 1, for 1Gb ports, HW default: 0 + * > 2..7 (recommended: 3..7) for 10Gb ports, HW default: 3 + * . for P1023, DPDE should be 1 + * + * . for P1023, MXT is in range (0..31) + * . for P4080, MXT is in range (0..63) + * + */ + + if ((p_LnxWrpFmPortDev->defPcd != e_NO_PCD) && + (InitFmPort3TupleDefPcd(p_LnxWrpFmPortDev) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + return E_OK; +} + +void fm_set_rx_port_params(struct fm_port *port, + struct fm_port_rx_params *params) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port; + int i; + + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.errFqid = + params->errq; + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.dfltFqid = + params->defq; + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools. + numOfPoolsUsed = params->num_pools; + for (i = 0; i < params->num_pools; i++) { + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. + extBufPools.extBufPool[i].id = + params->pool_param[i].id; + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. + extBufPools.extBufPool[i].size = + params->pool_param[i].size; + } + + p_LnxWrpFmPortDev->buffPrefixContent.privDataSize = + params->priv_data_size; + p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult = + params->parse_results; + p_LnxWrpFmPortDev->buffPrefixContent.passHashResult = + params->hash_results; + p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp = + params->time_stamp; + + ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig, + FM_MAX_NUM_OF_ADV_SETTINGS) + + ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent, + ARGS(1, + (&p_LnxWrpFmPortDev-> + buffPrefixContent))); + + ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev); +} +EXPORT_SYMBOL(fm_set_rx_port_params); + +void fm_set_tx_port_params(struct fm_port *port, + struct fm_port_non_rx_params *params) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port; + + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.errFqid = + params->errq; + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. + dfltFqid = params->defq; + + p_LnxWrpFmPortDev->buffPrefixContent.privDataSize = + params->priv_data_size; + p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult = + params->parse_results; + p_LnxWrpFmPortDev->buffPrefixContent.passHashResult = + params->hash_results; + p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp = + params->time_stamp; + + ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig, + FM_MAX_NUM_OF_ADV_SETTINGS) + + ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent, + ARGS(1, + (&p_LnxWrpFmPortDev-> + buffPrefixContent))); + + ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev); +} +EXPORT_SYMBOL(fm_set_tx_port_params); + +static void LnxwrpFmPcdDevExceptionsCb(t_Handle h_App, + e_FmPcdExceptions exception) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + DBG(INFO, ("got fm-pcd exception %d", exception)); + + /* do nothing */ + UNUSED(exception); +} + +static void LnxwrpFmPcdDevIndexedExceptionsCb(t_Handle h_App, + e_FmPcdExceptions exception, + uint16_t index) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + DBG(INFO, + ("got fm-pcd-indexed exception %d, indx %d", exception, index)); + + /* do nothing */ + UNUSED(exception); + UNUSED(index); +} + +static t_Error InitFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + spin_lock_init(&lock); + + if (p_LnxWrpFmDev->pcdActive) { + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; + t_FmPcdParams fmPcdParams; + t_Error err; + + memset(&fmPcdParams, 0, sizeof(fmPcdParams)); + fmPcdParams.h_Fm = p_LnxWrpFmDev->h_Dev; + fmPcdParams.prsSupport = p_LnxWrpFmDev->prsActive; + fmPcdParams.kgSupport = p_LnxWrpFmDev->kgActive; + fmPcdParams.plcrSupport = p_LnxWrpFmDev->plcrActive; + fmPcdParams.ccSupport = p_LnxWrpFmDev->ccActive; + fmPcdParams.numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES; + +#ifndef CONFIG_GUEST_PARTITION + fmPcdParams.f_Exception = LnxwrpFmPcdDevExceptionsCb; + if (fmPcdParams.kgSupport) + fmPcdParams.f_ExceptionId = + LnxwrpFmPcdDevIndexedExceptionsCb; + fmPcdParams.h_App = p_LnxWrpFmDev; +#endif /* !CONFIG_GUEST_PARTITION */ + +#ifdef CONFIG_MULTI_PARTITION_SUPPORT + fmPcdParams.numOfSchemes = 0; + fmPcdParams.numOfClsPlanEntries = 0; + fmPcdParams.partitionId = 0; +#endif /* CONFIG_MULTI_PARTITION_SUPPORT */ + fmPcdParams.useHostCommand = TRUE; + + p_LnxWrpFmDev->hc_tx_fq = + FqAlloc(p_LnxWrpFmDev, + 0, + QMAN_FQ_FLAG_TO_DCPORTAL, + p_LnxWrpFmPortDev->txCh, 0); + if (!p_LnxWrpFmDev->hc_tx_fq) + RETURN_ERROR(MAJOR, E_NULL_POINTER, + ("Frame queue allocation failed...")); + + p_LnxWrpFmDev->hc_tx_conf_fq = + FqAlloc(p_LnxWrpFmDev, + 0, + QMAN_FQ_FLAG_NO_ENQUEUE, + p_LnxWrpFmDev->hcCh, 7); + if (!p_LnxWrpFmDev->hc_tx_conf_fq) + RETURN_ERROR(MAJOR, E_NULL_POINTER, + ("Frame queue allocation failed...")); + + p_LnxWrpFmDev->hc_tx_err_fq = + FqAlloc(p_LnxWrpFmDev, + 0, + QMAN_FQ_FLAG_NO_ENQUEUE, + p_LnxWrpFmDev->hcCh, 7); + if (!p_LnxWrpFmDev->hc_tx_err_fq) + RETURN_ERROR(MAJOR, E_NULL_POINTER, + ("Frame queue allocation failed...")); + + fmPcdParams.hc.portBaseAddr = p_LnxWrpFmPortDev->baseAddr; + fmPcdParams.hc.portId = + p_LnxWrpFmPortDev->settings.param.portId; + fmPcdParams.hc.liodnBase = + p_LnxWrpFmPortDev->settings.param.liodnBase; + fmPcdParams.hc.errFqid = + qman_fq_fqid(p_LnxWrpFmDev->hc_tx_err_fq); + fmPcdParams.hc.confFqid = + qman_fq_fqid(p_LnxWrpFmDev->hc_tx_conf_fq); + fmPcdParams.hc.qmChannel = p_LnxWrpFmPortDev->txCh; + fmPcdParams.hc.f_QmEnqueue = QmEnqueueCB; + fmPcdParams.hc.h_QmArg = (t_Handle) p_LnxWrpFmDev; + + p_LnxWrpFmDev->h_PcdDev = FM_PCD_Config(&fmPcdParams); + if (!p_LnxWrpFmDev->h_PcdDev) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM PCD!")); + + err = + FM_PCD_ConfigPlcrNumOfSharedProfiles(p_LnxWrpFmDev->h_PcdDev, + LNXWRP_FM_NUM_OF_SHARED_PROFILES); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = FM_PCD_Init(p_LnxWrpFmDev->h_PcdDev); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (p_LnxWrpFmDev->err_irq == 0) { + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC, + FALSE); + } + } + + return E_OK; +} + +void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + + if (p_LnxWrpFmDev->h_PcdDev) + FM_PCD_Free(p_LnxWrpFmDev->h_PcdDev); + + if (p_LnxWrpFmDev->hc_tx_err_fq) + FqFree(p_LnxWrpFmDev->hc_tx_err_fq); + + if (p_LnxWrpFmDev->hc_tx_conf_fq) + FqFree(p_LnxWrpFmDev->hc_tx_conf_fq); + + if (p_LnxWrpFmDev->hc_tx_fq) + FqFree(p_LnxWrpFmDev->hc_tx_fq); +} + +static void FreeFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + + if (!p_LnxWrpFmPortDev->active) + return; + + if (p_LnxWrpFmPortDev->h_Dev) + FM_PORT_Free(p_LnxWrpFmPortDev->h_Dev); + + devm_iounmap(p_LnxWrpFmDev->dev, + UINT_TO_PTR(p_LnxWrpFmPortDev->baseAddr)); + __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, + p_LnxWrpFmPortDev->phys_baseAddr, + p_LnxWrpFmPortDev->memSize); +} + +static int fm_port_probe(struct platform_device *of_dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device *dev; + + dev = &of_dev->dev; + + p_LnxWrpFmPortDev = ReadFmPortDevTreeNode(of_dev); + if (p_LnxWrpFmPortDev == NULL) + return -EIO; + /* Port can be inactive, thus will not be probed: + - in performance mode, OH ports are disabled + ... + */ + if (!p_LnxWrpFmPortDev->active) + return 0; + + if (ConfigureFmPortDev(p_LnxWrpFmPortDev) != E_OK) + return -EIO; + + dev_set_drvdata(dev, p_LnxWrpFmPortDev); + + if ((p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_HOST_COMMAND) + && + (InitFmPcdDev((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev) + != E_OK)) + return -EIO; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + DEV_FM_RX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d", + p_LnxWrpFmDev->name, + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS + + DEV_FM_RX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + DEV_FM_TX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d", + p_LnxWrpFmDev->name, + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS + + DEV_FM_TX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_HOST_COMMAND) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + DEV_FM_OH_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_OFFLINE_PARSING) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id + 1); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + 1 + + DEV_FM_OH_PORTS_MINOR_BASE; + } + + device_create(p_LnxWrpFmDev->fm_class, NULL, + MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor), + NULL, p_LnxWrpFmPortDev->name); + + /* create sysfs entries for stats and regs */ + + if (fm_port_sysfs_create(dev) != 0) { + FreeFmPortDev(p_LnxWrpFmPortDev); + REPORT_ERROR(MAJOR, E_INVALID_STATE, + ("Unable to create sys entry - fm port!!!")); + return -EIO; + } + +#ifdef FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 + FM_DisableRamsEcc(p_LnxWrpFmDev->h_Dev); +#endif /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 */ + + DBG(TRACE, ("%s probed", p_LnxWrpFmPortDev->name)); + + return 0; +} + +static int fm_port_remove(struct platform_device *of_dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device *dev; + + dev = &of_dev->dev; + p_LnxWrpFmPortDev = dev_get_drvdata(dev); + + fm_port_sysfs_destroy(dev); + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + device_destroy(p_LnxWrpFmDev->fm_class, + MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor)); + + FreeFmPortDev(p_LnxWrpFmPortDev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct of_device_id fm_port_match[] = { + { + .compatible = "fsl,fman-port-oh"}, + { + .compatible = "fsl,fman-port-1g-rx"}, + { + .compatible = "fsl,fman-port-10g-rx"}, + { + .compatible = "fsl,fman-port-1g-tx"}, + { + .compatible = "fsl,fman-port-10g-tx"}, + {} +}; + +#ifndef MODULE +MODULE_DEVICE_TABLE(of, fm_port_match); +#endif /* !MODULE */ + +static struct platform_driver fm_port_driver = { + + .driver = { + .name = "fsl-fman-port", + .of_match_table = fm_port_match, + .owner = THIS_MODULE, + }, + .probe = fm_port_probe, + .remove = fm_port_remove, +}; + + +t_Error LNXWRP_FM_Port_Init(void) +{ + /* Register to the DTB for basic FM port API */ + if (platform_driver_register(&fm_port_driver)) + return E_NO_DEVICE; + + return E_OK; +} + +void LNXWRP_FM_Port_Free(void) +{ + platform_driver_unregister(&fm_port_driver); +} + +static int __init __cold fm_port_load(void) +{ + if (LNXWRP_FM_Port_Init() != E_OK) { + printk(KERN_CRIT "Failed to init FM Ports wrapper!\n"); + return -ENODEV; + } + + printk(KERN_INFO "Freescale FM Ports module (" __DATE__ ":" __TIME__ ")\n"); + + return 0; +} + +static void __exit __cold fm_port_unload(void) +{ + LNXWRP_FM_Port_Free(); +} + +module_init(fm_port_load); +module_exit(fm_port_unload); --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_ioctls_fm_compat.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_ioctls_fm_compat.c @@ -0,0 +1,789 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_fm_compat_ioctls.c + + @Description FM PCD compat functions + +*/ + +#if !defined(CONFIG_COMPAT) +#error "missing COMPAT layer..." +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "part_ext.h" +#include "fm_ioctls.h" +#include "fm_pcd_ioctls.h" +#include "fm_port_ioctls.h" +#include "lnxwrp_ioctls_fm_compat.h" + +/* debug dump */ +#if 0 +static void hex_dump(void * p_addr, unsigned int size) +{ + int i; + + for(i=0; i ", p);*/ + + if(!p) + return 0; + + for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++) + if(compat_ptr2id_array[k] == NULL) + { + compat_ptr2id_array[k] = p; + /*printk("0x%08x\n", k | COMPAT_PTR2ID_WATERMARK);*/ + return k | COMPAT_PTR2ID_WATERMARK; + } + + return 0; +} + +compat_uptr_t compat_get_ptr2id(void *p) +{ + compat_uptr_t k; + + /*printk("\ncompat_get_ptr2id(%p) -> ", p);*/ + + for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++) + if(compat_ptr2id_array[k] == p) { + /*printk("0x%08x\n", k | COMPAT_PTR2ID_WATERMARK);*/ + return k | COMPAT_PTR2ID_WATERMARK; + } + + return 0; +} + +void *compat_get_id2ptr(compat_uptr_t comp) +{ + + /*printk("\ncompat_get_id2ptr(0x%08x) -> ", comp);*/ + + if((COMPAT_PTR2ID_WM_MASK & comp) != COMPAT_PTR2ID_WATERMARK) { + /*printk("Error, invalid watermark!\n\n"); + dump_stack();*/ + return compat_ptr(comp); + } + + comp &= ~COMPAT_PTR2ID_WM_MASK; + + if((0 < comp) && (comp < COMPAT_PTR2ID_ARRAY_MAX) && (compat_ptr2id_array[comp] != NULL)) { + /*printk("%p\n", compat_ptr2id_array[comp]);*/ + return compat_ptr2id_array[comp]; + } + return NULL; +} +/* } maping kernel pointers w/ UserSpace id's */ + +static inline void compat_copy_fm_pcd_plcr_next_engine( + ioc_compat_fm_pcd_plcr_next_engine_params_u *compat_param, + ioc_fm_pcd_plcr_next_engine_params_u *param, + ioc_fm_pcd_engine next_engine, + uint8_t compat) +{ + switch (next_engine) + { + case e_IOC_FM_PCD_PLCR: + if (compat) + param->p_profile = compat_ptr(compat_param->p_profile); + else + compat_param->p_profile = ptr_to_compat(param->p_profile); + break; + + case e_IOC_FM_PCD_KG: + if (compat) + param->p_direct_scheme = compat_ptr(compat_param->p_direct_scheme); + else + compat_param->p_direct_scheme = ptr_to_compat(param->p_direct_scheme); + break; + + default: + if (compat) + param->action = compat_param->action; + else + compat_param->action = param->action; + } +} + +void compat_copy_fm_pcd_plcr_profile( + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param, + ioc_fm_pcd_plcr_profile_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->modify = compat_param->modify; + + /* profile_select */ + if (!compat_param->modify) + { + param->profile_select.new_params.profile_type = + compat_param->profile_select.new_params.profile_type; + param->profile_select.new_params.p_port = + compat_ptr(compat_param->profile_select.new_params.p_port); + param->profile_select.new_params.relative_profile_id = + compat_param->profile_select.new_params.relative_profile_id; + } + else + param->profile_select.p_profile = + compat_ptr(compat_param->profile_select.p_profile); + + param->alg_selection = compat_param->alg_selection; + param->color_mode = compat_param->color_mode; + + /* both parameters in the union has the same size, so memcpy works */ + memcpy(¶m->color, &compat_param->color, sizeof(param->color)); + + memcpy(¶m->non_passthrough_alg_param, &compat_param->non_passthrough_alg_param, sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t)); + + param->next_engine_on_green = compat_param->next_engine_on_green; + param->next_engine_on_yellow = compat_param->next_engine_on_yellow; + param->next_engine_on_red = compat_param->next_engine_on_red; + + param->trap_profile_on_flow_A = compat_param->trap_profile_on_flow_A; + param->trap_profile_on_flow_B = compat_param->trap_profile_on_flow_B; + param->trap_profile_on_flow_C = compat_param->trap_profile_on_flow_C; + + param->id = compat_ptr(compat_param->id); + } + else + { + compat_param->modify = param->modify; + + /* profile_select */ + if(!param->modify){ + compat_param->profile_select.new_params.profile_type = + param->profile_select.new_params.profile_type; + compat_param->profile_select.new_params.p_port = + ptr_to_compat(param->profile_select.new_params.p_port); + compat_param->profile_select.new_params.relative_profile_id = + param->profile_select.new_params.relative_profile_id; + } + else + compat_param->profile_select.p_profile = + ptr_to_compat(param->profile_select.p_profile); + + compat_param->alg_selection = param->alg_selection; + compat_param->color_mode = param->color_mode; + + /* both parameters in the union has the same size, so memcpy works */ + memcpy(&compat_param->color, ¶m->color, sizeof(compat_param->color)); + + memcpy(&compat_param->non_passthrough_alg_param, ¶m->non_passthrough_alg_param, sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t)); + + compat_param->next_engine_on_green = param->next_engine_on_green; + compat_param->next_engine_on_yellow = param->next_engine_on_yellow; + compat_param->next_engine_on_red = param->next_engine_on_red; + + compat_param->trap_profile_on_flow_A = param->trap_profile_on_flow_A; + compat_param->trap_profile_on_flow_B = param->trap_profile_on_flow_B; + compat_param->trap_profile_on_flow_C = param->trap_profile_on_flow_C; + + compat_param->id = ptr_to_compat(param->id); + } + + compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_green, + ¶m->params_on_green, param->next_engine_on_green, compat); + + compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_yellow, + ¶m->params_on_yellow, param->next_engine_on_yellow, compat); + + compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_red, + ¶m->params_on_red, param->next_engine_on_red, compat); +} + +static inline void compat_copy_fm_pcd_cc_next_kg( + ioc_compat_fm_pcd_cc_next_kg_params_t *compat_param, + ioc_fm_pcd_cc_next_kg_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->new_fqid = compat_param->new_fqid; + param->override_fqid = compat_param->override_fqid; + param->p_direct_scheme = compat_ptr(compat_param->p_direct_scheme); + } + else + { + compat_param->new_fqid = param->new_fqid; + compat_param->override_fqid = param->override_fqid; + compat_param->p_direct_scheme = ptr_to_compat(param->p_direct_scheme); + } +} + +static inline void compat_copy_fm_pcd_cc_next_cc( + ioc_compat_fm_pcd_cc_next_cc_params_t *compat_param, + ioc_fm_pcd_cc_next_cc_params_t *param, + uint8_t compat) +{ + if (compat) + param->cc_node_id = compat_get_id2ptr(compat_param->cc_node_id); + else + compat_param->cc_node_id = compat_get_ptr2id(param->cc_node_id); +} + +static inline void compat_copy_fm_pcd_cc_next_engine( + ioc_compat_fm_pcd_cc_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_next_engine_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->next_engine = compat_param->next_engine; + + switch (compat_param->next_engine) + { + case e_IOC_FM_PCD_KG: + compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, ¶m->params.kg_params, compat); + break; + case e_IOC_FM_PCD_CC: + compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, ¶m->params.cc_params, compat); + break; + default: + memcpy(¶m->params, &compat_param->params, sizeof(param->params)); + break; + } +#ifdef FM_PCD_CC_MANIP + param->p_manip = compat_ptr(compat_param->p_manip); +#endif + } + else + { + compat_param->next_engine = param->next_engine; + + switch (compat_param->next_engine) + { + case e_IOC_FM_PCD_KG: + compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, ¶m->params.kg_params, compat); + break; + case e_IOC_FM_PCD_CC: + compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, ¶m->params.cc_params, compat); + break; + default: + memcpy(&compat_param->params, ¶m->params, sizeof(compat_param->params)); + break; + } + +#ifdef FM_PCD_CC_MANIP + compat_param->p_manip = ptr_to_compat(param->p_manip); +#endif + } +} + +void compat_copy_fm_pcd_cc_key( + ioc_compat_fm_pcd_cc_key_params_t *compat_param, + ioc_fm_pcd_cc_key_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->p_key = compat_ptr(compat_param->p_key); + param->p_mask = compat_ptr(compat_param->p_mask); + } + else + { + compat_param->p_key = ptr_to_compat(param->p_key); + compat_param->p_mask = ptr_to_compat(param->p_mask); + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params, + ¶m->cc_next_engine_params, + compat); +} + +void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine( + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->id = compat_ptr(compat_param->id); + param->key_indx = compat_param->key_indx; + param->key_size = compat_param->key_indx; + compat_copy_fm_pcd_cc_key( + &compat_param->key_params, + ¶m->key_params, + compat); + } + else + { + compat_param->id = ptr_to_compat(param->id); + compat_param->key_indx = param->key_indx; + compat_param->key_size = param->key_indx; + compat_copy_fm_pcd_cc_key( + &compat_param->key_params, + ¶m->key_params, + compat); + } +} + +void compat_copy_fm_pcd_cc_node_modify_next_engine( + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->id = compat_ptr(compat_param->id); + param->key_indx = compat_param->key_indx; + param->key_size = compat_param->key_size; + } + else + { + compat_param->id = ptr_to_compat(param->id); + compat_param->key_indx = param->key_indx; + compat_param->key_size = param->key_size; + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params, + ¶m->cc_next_engine_params, + compat); +} + +void compat_fm_pcd_cc_tree_modify_next_engine( + ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->id = compat_ptr(compat_param->id); + param->grp_indx = compat_param->grp_indx; + param->indx = compat_param->indx; + } + else + { + compat_param->id = ptr_to_compat(param->id); + compat_param->grp_indx = param->grp_indx; + compat_param->indx = param->indx; + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params, + ¶m->cc_next_engine_params, + compat); +} + +void compat_copy_fm_pcd_cc_grp( + ioc_compat_fm_pcd_cc_grp_params_t *compat_param, + ioc_fm_pcd_cc_grp_params_t *param, + uint8_t compat) +{ + int k; + + if (compat) + { + param->num_of_distinction_units = compat_param->num_of_distinction_units; + memcpy(param->unit_ids, compat_param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS); + } + else + { + compat_param->num_of_distinction_units = param->num_of_distinction_units; + memcpy(compat_param->unit_ids, param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS); + } + + for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP; k++) + compat_copy_fm_pcd_cc_next_engine( + &compat_param->next_engine_per_entries_in_grp[k], + ¶m->next_engine_per_entries_in_grp[k], + compat); +} + +void compat_copy_fm_pcd_cc_tree( + ioc_compat_fm_pcd_cc_tree_params_t *compat_param, + ioc_fm_pcd_cc_tree_params_t *param, + uint8_t compat) +{ + int k; + + if (compat) + { + param->net_env_id = compat_ptr(compat_param->net_env_id); + param->num_of_groups = compat_param->num_of_groups; + + for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS; k++) + compat_copy_fm_pcd_cc_grp( + &compat_param->fm_pcd_cc_group_params[k], + ¶m->fm_pcd_cc_group_params[k], + compat); + param->id = compat_ptr(compat_param->id); + } + else + { + compat_param->net_env_id = ptr_to_compat(param->net_env_id); + compat_param->num_of_groups = param->num_of_groups; + for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS; k++) + compat_copy_fm_pcd_cc_grp( + &compat_param->fm_pcd_cc_group_params[k], + ¶m->fm_pcd_cc_group_params[k], + compat); + compat_param->id = ptr_to_compat(param->id); + } +} + +void compat_fm_pcd_prs_sw( + ioc_compat_fm_pcd_prs_sw_params_t *compat_param, + ioc_fm_pcd_prs_sw_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->override = compat_param->override; + param->size = compat_param->size; + param->base = compat_param->base; + param->p_code = compat_ptr(compat_param->p_code); + memcpy(param->sw_prs_data_params,compat_param->sw_prs_data_params,IOC_FM_PCD_PRS_NUM_OF_HDRS*sizeof(uint32_t)); + param->num_of_labels = compat_param->num_of_labels; + memcpy(param->labels_table,compat_param->labels_table,IOC_FM_PCD_PRS_NUM_OF_LABELS*sizeof(ioc_fm_pcd_prs_label_params_t)); + return; + } + + WARN(1, "\n\nFMD: fatal error, feature not implemented!\n\n"); +} + +void compat_copy_fm_pcd_kg_scheme( + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param, + ioc_fm_pcd_kg_scheme_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->modify = compat_param->modify; + + /* scm_id */ + if(compat_param->modify) + param->scm_id.scheme_id = compat_ptr(compat_param->scm_id.scheme_id); + else + param->scm_id.relative_scheme_id = compat_param->scm_id.relative_scheme_id; + + param->always_direct = compat_param->always_direct; + /* netEnvParams */ + param->netEnvParams.net_env_id = compat_ptr(compat_param->netEnvParams.net_env_id); + param->netEnvParams.num_of_distinction_units = compat_param->netEnvParams.num_of_distinction_units; + memcpy(param->netEnvParams.unit_ids, + compat_param->netEnvParams.unit_ids, + IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + + param->use_hash = compat_param->use_hash; + memcpy(¶m->key_extract_and_hash_params, + &compat_param->key_extract_and_hash_params, + sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t)); + param->bypass_fqid_generation = compat_param->bypass_fqid_generation; + param->base_fqid = compat_param->base_fqid; + param->numOfUsedExtractedOrs = compat_param->numOfUsedExtractedOrs; + memcpy(param->extracted_ors, compat_param->extracted_ors, IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t)); + param->next_engine = compat_param->next_engine; + + /* kg_next_engine_params */ + if(param->next_engine == e_IOC_FM_PCD_CC){ + param->kg_next_engine_params.cc.tree_id = compat_get_id2ptr(compat_param->kg_next_engine_params.cc.tree_id); + param->kg_next_engine_params.cc.grp_id = compat_param->kg_next_engine_params.cc.grp_id; + param->kg_next_engine_params.cc.plcr_next = compat_param->kg_next_engine_params.cc.plcr_next; + param->kg_next_engine_params.cc.bypass_plcr_profile_generation = compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation; + memcpy(¶m->kg_next_engine_params.cc.plcr_profile, + &compat_param->kg_next_engine_params.cc.plcr_profile, + sizeof(ioc_fm_pcd_kg_plcr_profile_t)); + } + else + memcpy(¶m->kg_next_engine_params, + &compat_param->kg_next_engine_params, + sizeof(param->kg_next_engine_params)); + + memcpy(¶m->scheme_counter, &compat_param->scheme_counter, sizeof(ioc_fm_pcd_kg_scheme_counter_t)); + param->id = compat_ptr(compat_param->id); + } + else + { + compat_param->modify = param->modify; + + /* scm_id */ + if(param->modify) + compat_param->scm_id.scheme_id = ptr_to_compat(param->scm_id.scheme_id); + else + compat_param->scm_id.relative_scheme_id = param->scm_id.relative_scheme_id; + + compat_param->always_direct = param->always_direct; + + /* netEnvParams */ + compat_param->netEnvParams.net_env_id = ptr_to_compat(param->netEnvParams.net_env_id); + compat_param->netEnvParams.num_of_distinction_units = param->netEnvParams.num_of_distinction_units; + memcpy(compat_param->netEnvParams.unit_ids, param->netEnvParams.unit_ids, IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + + compat_param->use_hash = param->use_hash; + memcpy(&compat_param->key_extract_and_hash_params, ¶m->key_extract_and_hash_params, sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t)); + compat_param->bypass_fqid_generation = param->bypass_fqid_generation; + compat_param->base_fqid = param->base_fqid; + compat_param->numOfUsedExtractedOrs = param->numOfUsedExtractedOrs; + memcpy(compat_param->extracted_ors, param->extracted_ors, IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t)); + compat_param->next_engine = param->next_engine; + + /* kg_next_engine_params */ + if(compat_param->next_engine == e_IOC_FM_PCD_CC){ + compat_param->kg_next_engine_params.cc.tree_id = compat_get_ptr2id(param->kg_next_engine_params.cc.tree_id); + compat_param->kg_next_engine_params.cc.grp_id = param->kg_next_engine_params.cc.grp_id; + compat_param->kg_next_engine_params.cc.plcr_next = param->kg_next_engine_params.cc.plcr_next; + compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation = param->kg_next_engine_params.cc.bypass_plcr_profile_generation; + memcpy(&compat_param->kg_next_engine_params.cc.plcr_profile, ¶m->kg_next_engine_params.cc.plcr_profile, sizeof(ioc_fm_pcd_kg_plcr_profile_t)); + } + else + memcpy(¶m->kg_next_engine_params, &compat_param->kg_next_engine_params, sizeof(compat_param->kg_next_engine_params)); + + memcpy(&compat_param->scheme_counter, ¶m->scheme_counter, sizeof(ioc_fm_pcd_kg_scheme_counter_t)); + compat_param->id = ptr_to_compat(param->id); + } +} + +void compat_copy_fm_pcd_kg_scheme_select( + ioc_compat_fm_pcd_kg_scheme_select_t *compat_param, + ioc_fm_pcd_kg_scheme_select_t *param, + uint8_t compat) +{ + if (compat){ + param->direct = compat_param->direct; + param->scheme_id = compat_ptr(compat_param->direct); + } + else { + printk(" %s:%u feature not implemented... \n", __func__, __LINE__); + } +} + +void compat_copy_fm_pcd_kg_schemes_params( + ioc_compat_fm_pcd_port_schemes_params_t *compat_param, + ioc_fm_pcd_port_schemes_params_t *param, + uint8_t compat) +{ + int k; + + if (compat) { + param->num_of_schemes = compat_param->num_of_schemes; + for(k=0; k < IOC_FM_PCD_KG_NUM_OF_SCHEMES; k++) + param->scheme_ids[k] = compat_ptr(compat_param->schemes_ids[k]); + } + else { + printk(" %s:%u feature not implemented... \n", __func__, __LINE__); + } +} + +void compat_copy_fm_port_pcd_kg( + ioc_compat_fm_port_pcd_kg_params_t *compat_param, + ioc_fm_port_pcd_kg_params_t *param, + uint8_t compat) +{ + if (compat){ + uint8_t k; + param->num_of_schemes = compat_param->num_of_schemes; + for(k=0;kschemes_ids[k] = compat_ptr(compat_param->schemes_ids[k]); + param->direct_scheme = compat_param->direct_scheme; + param->direct_scheme_id = compat_ptr(compat_param->direct_scheme_id); + } + else { + printk(" %s:%u feature not implemented... \n", __func__, __LINE__);; + } +} + +void compat_copy_fm_port_pcd( + ioc_compat_fm_port_pcd_params_t *compat_param, + ioc_fm_port_pcd_params_t *param, + uint8_t compat) +{ + if (compat){ + param->pcd_support = compat_param->pcd_support; + param->net_env_id = compat_ptr(compat_param->net_env_id); + param->p_prs_params = compat_ptr(compat_param->p_prs_params); /* same structure */ + param->p_cc_params = compat_ptr(compat_param->p_cc_params); + param->p_kg_params = compat_ptr(compat_param->p_kg_params); + param->p_plcr_params = compat_ptr(compat_param->p_plcr_params); + } + else { + compat_param->pcd_support = param->pcd_support; + compat_param->net_env_id = ptr_to_compat(param->net_env_id); + compat_param->p_prs_params = ptr_to_compat(param->p_prs_params); /* same structure */ + compat_param->p_cc_params = ptr_to_compat(param->p_cc_params); + compat_param->p_kg_params = ptr_to_compat(param->p_kg_params); + compat_param->p_plcr_params = ptr_to_compat(param->p_plcr_params); + } +} + +void compat_copy_fm_pcd_net_env( + ioc_compat_fm_pcd_net_env_params_t *compat_param, + ioc_fm_pcd_net_env_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->num_of_distinction_units = compat_param->num_of_distinction_units; + memcpy(param->units, compat_param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + param->id = compat_ptr(compat_param->id); + } + else + { + compat_param->num_of_distinction_units = param->num_of_distinction_units; + memcpy(compat_param->units, param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + compat_param->id = ptr_to_compat(param->id); + } +} + +void compat_copy_fm_pcd_cc_node_modify_key( + ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_params_t *param, + uint8_t compat) +{ + if (compat) + { + param->id = compat_ptr(compat_param->id); + param->key_indx = compat_param->key_indx; + param->key_size = compat_param->key_size; + param->p_key = (uint8_t *)compat_ptr(compat_param->p_key); + param->p_mask = (uint8_t *)compat_ptr(compat_param->p_mask); + } + else + { + compat_param->id = ptr_to_compat(param->id); + compat_param->key_indx = param->key_indx; + compat_param->key_size = param->key_size; + compat_param->p_key = ptr_to_compat((void *)param->p_key); + compat_param->p_mask = ptr_to_compat((void *)param->p_mask); + } +} + +void compat_copy_keys( + ioc_compat_keys_params_t *compat_param, + ioc_keys_params_t *param, + uint8_t compat) +{ + int k = 0; + if (compat){ + param->num_of_keys = compat_param->num_of_keys; + param->key_size = compat_param->key_size; + + for(k=0;kkey_params[k], + ¶m->key_params[k], + compat); + + } + else { + + compat_param->num_of_keys = param->num_of_keys; + compat_param->key_size = param->key_size; + + for(k=0;kkey_params[k], + ¶m->key_params[k], + compat); + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params_for_miss, + ¶m->cc_next_engine_params_for_miss, + compat); + +} + +void compat_copy_fm_pcd_cc_node( + ioc_compat_fm_pcd_cc_node_params_t *compat_param, + ioc_fm_pcd_cc_node_params_t *param, + uint8_t compat) +{ + if (compat) + { + /* no pointer inside, so sizeof US and KS are the same - memcpy is ok */ + memcpy(¶m->extract_cc_params, &compat_param->extract_cc_params, sizeof(ioc_fm_pcd_extract_entry_t)); + + compat_copy_keys(&compat_param->keys_params, ¶m->keys_params, compat); + + param->id = compat_get_id2ptr(compat_param->id); + } + else + { + /* no pointer inside, so sizeof US and KS are the same - memcpy is ok */ + memcpy(&compat_param->extract_cc_params, ¶m->extract_cc_params, sizeof(ioc_fm_pcd_extract_entry_t)); + + compat_copy_keys(&compat_param->keys_params, ¶m->keys_params, compat); + + compat_param->id = ptr_to_compat(param->id); + } +} + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_sysfs_fm.h + + @Description FM sysfs functions. + +*/ + +#ifndef LNXWRP_SYSFS_FM_H_ +#define LNXWRP_SYSFS_FM_H_ + +#include "lnxwrp_sysfs.h" + +int fm_sysfs_create(struct device *dev); +void fm_sysfs_destroy(struct device *dev); + +#endif /* LNXWRP_SYSFS_FM_H_ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm_port.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm_port.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_sysfs_fm_port.h + + @Description FM port sysfs functions. + +*/ + +#ifndef LNXWRP_SYSFS_FM_PORT_H_ +#define LNXWRP_SYSFS_FM_PORT_H_ + +#include "lnxwrp_sysfs.h" + +int fm_port_sysfs_create(struct device *dev); +void fm_port_sysfs_destroy(struct device *dev); + +#endif /* LNXWRP_SYSFS_FM_PORT_H_ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_resources.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_resources.c @@ -0,0 +1,1172 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_resources.c + + @Description FMD wrapper resource allocation functions. + +*/ + +#include +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ +#include +#include +#include +#include + +#include "lnxwrp_resources.h" + +extern int fsl_fman_phy_maxfrm; /* MAC file */ + +static struct device_node *match_mac_to_dpaa_port(struct device_node + *enet_mac_node) +{ + struct device_node *dpaa_node = NULL; + struct device_node *dpaa_itf = NULL; + + /* find DPAA node starting from root */ + dpaa_node = of_find_compatible_node(NULL, NULL, "fsl,dpaa"); + if (dpaa_node) { + /* for all dpaa ports check which one refers this mac node. */ + for_each_child_of_node(dpaa_node, dpaa_itf) { + struct device_node *by_handle_enet_mac_node = NULL; + const phandle *phandle_prop = NULL; + int lenp = 0; + + phandle_prop = + (typeof(phandle_prop)) + of_get_property(dpaa_itf, "fsl,fman-mac", + &lenp); + if (phandle_prop == NULL) + continue; + + if (WARN_ON(lenp != sizeof(phandle))) + return NULL; + + by_handle_enet_mac_node = + of_find_node_by_phandle(*phandle_prop); + if (unlikely(by_handle_enet_mac_node == NULL)) + return NULL; + + /* check */ + if (by_handle_enet_mac_node == enet_mac_node) { + of_node_put(by_handle_enet_mac_node); + return dpaa_itf; + } + + of_node_put(by_handle_enet_mac_node); + } + of_node_put(dpaa_node); + } + + return NULL; +} + +static struct device_node *match_fman_port_to_mac(struct device_node *fm_node, + struct device_node + *fm_port_node) +{ + struct device_node *fm_node_idx = NULL; + + /* for all enet nodes (macs) check which one refers this FMan port. */ + for_each_child_of_node(fm_node, fm_node_idx) { + if (of_device_is_compatible(fm_node_idx, "fsl,fman-1g-mac") || + of_device_is_compatible(fm_node_idx, + "fsl,fman-10g-mac")) { + struct device_node *fman_port_node_rx = NULL; + struct device_node *fman_port_node_tx = NULL; + /* RX is first */ + fman_port_node_rx = of_parse_phandle(fm_node_idx, + "fsl,port-handles", 0); + if (unlikely(fman_port_node_rx == NULL)) + continue; + /* TX is second */ + fman_port_node_tx = of_parse_phandle(fm_node_idx, + "fsl,port-handles", 1); + if (unlikely(fman_port_node_tx == NULL)) { + of_node_put(fman_port_node_rx); + continue; + } + + /* check */ + if (fman_port_node_rx == fm_port_node + || fman_port_node_tx == fm_port_node) { + of_node_put(fman_port_node_rx); + of_node_put(fman_port_node_tx); + return fm_node_idx; + } + + of_node_put(fman_port_node_rx); + of_node_put(fman_port_node_tx); + } + } + + return NULL; +} + +static bool is_fman_port_active(struct device_node *fm_node, + struct device_node *fm_port_node) +{ + struct device_node *enet_mac_node = NULL; + struct device_node *itf_node = NULL; + + /* Which MAC node refers to this FMan port. */ + enet_mac_node = match_fman_port_to_mac(fm_node, fm_port_node); + + if (unlikely(enet_mac_node == NULL)) + return false; + + /* Which dpaa port node refers this MAC node. */ + itf_node = match_mac_to_dpaa_port(enet_mac_node); + of_node_put(enet_mac_node); + + if (unlikely(!itf_node)) + return false; + + /* check if itf (DPAA ports) is available. + * if available, means that the FMan port is + * also available - return true + */ + if (!of_device_is_available(itf_node)) { + of_node_put(itf_node); + return false; + } + of_node_put(itf_node); + + return true; +} + +int fm_set_active_fman_ports(struct platform_device *of_dev, + t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + struct device_node *fm_node = NULL; + struct device_node *fm_port_node = NULL; + + memset(&p_LnxWrpFmDev->fm_active_ports_info, 0, + sizeof(struct fm_active_ports)); + + /* get FMan node */ + fm_node = of_dev->dev.of_node; + + /* for all ports which belong to this FMan, check if they are active. + * If active, set their parameters. */ + for_each_child_of_node(fm_node, fm_port_node) { + + /* OH FMan ports */ + if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-oh")) + /* all oh ports are active */ + p_LnxWrpFmDev->fm_active_ports_info.num_oh_ports++; + + if (!is_fman_port_active(fm_node, fm_port_node)) + continue; + + /* 10g TX FMan ports */ + if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-10g-tx")) + p_LnxWrpFmDev->fm_active_ports_info.num_tx10_ports++; + + /* 10g RX FMan ports */ + else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-10g-rx")) + p_LnxWrpFmDev->fm_active_ports_info.num_rx10_ports++; + + /* 1G TX FMan ports */ + else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-1g-tx")) + p_LnxWrpFmDev->fm_active_ports_info.num_tx_ports++; + + /* 1G RX FMan ports */ + else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-1g-rx")) + p_LnxWrpFmDev->fm_active_ports_info.num_rx_ports++; + } + + /* If performance is needed no oh port is probed + * except the one used for host command. */ +#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) + if (p_LnxWrpFmDev->fm_active_ports_info.num_oh_ports) + p_LnxWrpFmDev->fm_active_ports_info.num_oh_ports = 1; + + printk(KERN_WARNING "FMAN(%u)-Performance mode - no OH support...\n", + p_LnxWrpFmDev->id); +#endif + + return 0; +} + +#ifdef FM_FIFO_ALLOCATION_OLD_ALG +/* BPOOL size is constant and equal w/ DPA_BP_SIZE */ +static uint32_t get_largest_buf_size(uint32_t max_rx_frame_size, uint32_t buf_size) +{ + uint32_t priv_data_size = 16; /* DPA_PRIV_DATA_SIZE */ + uint32_t hash_results_size = 16; /* DPA_HASH_RESULTS_SIZE */ + uint32_t parse_results_size = + sizeof(t_FmPrsResult); /* DPA_PARSE_RESULTS_SIZE */ + uint32_t bp_head = priv_data_size + hash_results_size + + parse_results_size; /* DPA_BP_HEAD */ + uint32_t bp_size = bp_head + max_rx_frame_size + + NET_IP_ALIGN; /* DPA_BP_SIZE */ + + return CEIL_DIV(bp_size, buf_size); +} +#endif + +/* Calculate the fifosize based on MURAM allocation, number of ports, dpde + value and s/g software support (! Kernel does not suport s/g). + + Algorithm summary: + - Calculate the the minimum fifosize required for every type of port + (TX,RX for 1G, 2.5G and 10G). + - Set TX the minimum fifosize required. + - Distribute the remaining buffers (after all TX were set) to RX ports + based on: + 1G RX = Remaining_buffers * 1/(1+2.5+10) + 2.5G RX = Remaining_buffers * 2.5/(1+2.5+10) + 10G RX = Remaining_buffers * 10/(1+2.5+10) + - if the RX is smaller than the minimum required, then set the minimum + required + - In the end distribuite the leftovers if there are any (due to + unprecise calculus) or if over allocation cat some buffers from all RX + ports w/o pass over minimum required treshold, but if there must be + pass the treshold in order to cat the over allocation ,then this + configuration can not be set - KERN_ALERT. +*/ +int fm_precalculate_fifosizes(t_LnxWrpFmDev *p_LnxWrpFmDev, int muram_fifo_size) +{ + + /* input parameters */ + struct fm_active_ports *fm_active_ports_info = NULL; + int num_1g_ports = 0; + int num_2g5_ports = 0; + int num_10g_ports = 0; + int num_oh_ports = 0; + + /* output parameters */ + struct fm_resource_settings *fm_resource_settings_info = NULL; + int oh_buff = 0; + int tx_1g_bufs = 0, rx_1g_bufs = 0; + int tx_2g5_bufs = 0, rx_2g5_bufs = 0; + int tx_10g_bufs = 0, rx_10g_bufs = 0; + int err = 0; + + /* throughput parameters: divide it by 10 when used */ + int gb1g = 10, gb2g5 = 25, gb10g = 100, gb_sum = 0; + + /* buffers parameters */ + int buf_size = 0x100; /* Buffer unit size */ + int total_no_buffers = 0; /* Calculus based on MURAM size for + fifos and buf. unit size */ + + int shared_ext_buff = 0; /* External buffers allocated - LLD + boundaries:DEFAULT_PORT_extraSizeOfFifo */ + + int min_tx_1g_2g5_bufs = 0; /* minimum TX1g buffers required + (see refman.) */ + int min_tx_10g_bufs = 0; /* minimum TX10g buffers required + (see refman.) */ + int min_rx_bufs = 0; /* minimum RX buffers required (see refman.) */ + + /* Buffer sizes calculus */ + int max_frame_size = + fsl_fman_phy_maxfrm ? fsl_fman_phy_maxfrm : + CONFIG_DPA_MAX_FRM_SIZE; + int remaining_bufs = 0; + int rx_1g_bufs_ceil = 0, rx_2g5_bufs_ceil = 0, rx_10g_bufs_ceil = 0; + int rx_2g5_max_bufs = 0, rx_10g_max_bufs = 0; + int rx_1g_used = 0, rx_1g_2g5_used = 0, rx_1g_10g_used =0, + rx_2g5_used = 0, rx_2g5_10g_used = 0, rx_1g_2g5_10g_used = 0; + + /* overflow checking */ + int tot_rx_buffs, tot_tx_buffs, tot_oh_buffs, tot_used_buffs, + leftovers = 0; + int overflow = 0; + bool loop = false; + + /* check input parameters correctness */ + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + ASSERT_COND(fm_active_ports_info != NULL); + ASSERT_COND(fm_resource_settings_info != NULL); + ASSERT_COND(fm_active_ports_info->num_tx_ports == + fm_active_ports_info->num_rx_ports); + ASSERT_COND(fm_active_ports_info->num_tx25_ports == + fm_active_ports_info->num_tx25_ports); + ASSERT_COND(fm_active_ports_info->num_tx10_ports == + fm_active_ports_info->num_tx10_ports); + ASSERT_COND(max_frame_size != 0); + ASSERT_COND(muram_fifo_size != 0); + + /* set input parameters */ + num_1g_ports = fm_active_ports_info->num_tx_ports; + num_2g5_ports = fm_active_ports_info->num_tx25_ports; + num_10g_ports = fm_active_ports_info->num_tx10_ports; + num_oh_ports = fm_active_ports_info->num_oh_ports; + + /* throughput calculus */ + gb_sum = gb1g * num_1g_ports + gb2g5 * num_2g5_ports + + gb10g * num_10g_ports; /* divide it by 10 */ + + /* Base buffer calculus */ + oh_buff = DPDE_1G + 4; /* should be: + get_largest_buf_size(max_frame_size, buf_size), + but LLD: DPDE + 4 */ + total_no_buffers = muram_fifo_size / buf_size; + + min_tx_1g_2g5_bufs = CEIL_DIV(max_frame_size, buf_size) + + DPDE_1G + 3 + 1; /* +1 to handle Jumbo Frames */ + min_tx_10g_bufs = CEIL_DIV(max_frame_size, buf_size) + + DPDE_10G + 3 + 1; /* +1 to handle Jumbo Frames */ + + { +#ifdef FM_FIFO_ALLOCATION_OLD_ALG + uint8_t fm_rev_major = 0; + fm_rev_major = + (uint8_t) ((* + ((volatile uint32_t *) + UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr + + 0x000c30c4)) & 0xff00) >> 8); + + if (fm_rev_major < 4) + min_rx_bufs = + get_largest_buf_size(max_frame_size, + buf_size) + 7; + else +#endif + min_rx_bufs = 8; + } + + shared_ext_buff = num_10g_ports ? 32 : 16; /* LLD boundaries: + DEFAULT_PORT_extraSizeOfFifo */ + + /* TX ports will have minimum required buffers + Calculus of the remaining buffers for all RX ports */ + tx_1g_bufs = num_1g_ports ? min_tx_1g_2g5_bufs : 0; + tx_2g5_bufs = num_2g5_ports ? min_tx_1g_2g5_bufs : 0; + tx_10g_bufs = num_10g_ports ? min_tx_10g_bufs : 0; + + remaining_bufs = total_no_buffers - + oh_buff * num_oh_ports - + num_1g_ports * min_tx_1g_2g5_bufs - + num_2g5_ports * min_tx_1g_2g5_bufs - + num_10g_ports * min_tx_10g_bufs - shared_ext_buff; + + if (remaining_bufs < 0) { + printk(KERN_ALERT + "This configuration will not work due to low number of" + " buffers (%u buffers)...\n", + total_no_buffers); + err = -1; + goto precalculated_fifosize_out; + } + + /* Per port buffer size calculus + . for TX ports give always minimum required + . for RX ports give whatever left scaled per port type */ + /* ------------------------------------------------------- */ + if (num_1g_ports) { + rx_1g_bufs_ceil = + (gb_sum / + 10) ? CEIL_DIV(((remaining_bufs * gb1g) / 10), + (gb_sum / 10)) : 0; + rx_1g_bufs = MAX(min_rx_bufs, rx_1g_bufs_ceil); + rx_1g_used = rx_1g_bufs - rx_1g_bufs_ceil; /* always >= 0 */ + /* distribute to 2.5g and 10g ports */ + rx_1g_2g5_used = + (num_2g5_ports + + num_10g_ports) ? CEIL_DIV(rx_1g_used * num_1g_ports * + num_2g5_ports, + num_2g5_ports + + num_10g_ports) : 0; + rx_1g_10g_used = + (num_2g5_ports + + num_10g_ports) ? CEIL_DIV(rx_1g_used * num_1g_ports * + num_10g_ports, + num_2g5_ports + + num_10g_ports) : 0; + } + + if (num_2g5_ports) { + rx_2g5_bufs_ceil = + (gb_sum / + 10) ? CEIL_DIV(((remaining_bufs * gb2g5) / 10), + (gb_sum / 10)) : 0; + rx_2g5_max_bufs = MAX(min_rx_bufs, rx_2g5_bufs_ceil); + rx_2g5_bufs = + MAX(min_rx_bufs, rx_2g5_max_bufs - rx_1g_2g5_used); + rx_2g5_used = rx_2g5_bufs - rx_2g5_bufs_ceil; /* always >= 0 */ + /* distribute to 10g ports */ + rx_2g5_10g_used = + num_10g_ports ? CEIL_DIV(rx_2g5_used * num_2g5_ports, + num_10g_ports) : 0; + } + + if (num_10g_ports) { + rx_10g_bufs_ceil = + (gb_sum / + 10) ? CEIL_DIV(((remaining_bufs * gb10g) / 10), + (gb_sum / 10)) : 0; + rx_10g_max_bufs = MAX(min_rx_bufs, rx_10g_bufs_ceil); + /* keep count of all distribution */ + rx_1g_2g5_10g_used = rx_1g_10g_used + rx_2g5_10g_used; + rx_10g_bufs = + MAX(min_rx_bufs, + rx_10g_max_bufs - rx_1g_2g5_10g_used); + } + + /* overflow-leftover calculus */ + tot_rx_buffs = rx_1g_bufs * num_1g_ports + + rx_2g5_bufs * num_2g5_ports + rx_10g_bufs * num_10g_ports; + tot_tx_buffs = tx_1g_bufs * num_1g_ports + + tx_2g5_bufs * num_2g5_ports + tx_10g_bufs * num_10g_ports; + tot_oh_buffs = oh_buff * num_oh_ports; + tot_used_buffs = + tot_oh_buffs + tot_tx_buffs + tot_rx_buffs + shared_ext_buff; + + overflow = tot_used_buffs - total_no_buffers; + /* used more than available */ + if (overflow > 0) { + loop = true; + while (overflow > 0 && loop) { + loop = false; + if (overflow && num_10g_ports + && rx_10g_bufs > min_rx_bufs) { + rx_10g_bufs--; + overflow -= num_10g_ports; + loop = true; + } + if (overflow && num_2g5_ports + && rx_2g5_bufs > min_rx_bufs) { + rx_2g5_bufs--; + overflow -= num_2g5_ports; + loop = true; + } + if (overflow && num_1g_ports + && rx_1g_bufs > min_rx_bufs) { + rx_1g_bufs--; + overflow -= num_1g_ports; + loop = true; + } + } + + if (overflow > 0) { + printk(KERN_ALERT + "This configuration will not work due to over" + " buffer allocation (%d buffers)...\n", + overflow); + err = -1; + goto precalculated_fifosize_out; + } + } + /* left a few buffers */ + else if (overflow < 0) { + leftovers = total_no_buffers - tot_used_buffs; + loop = true; + while (leftovers > 0 && loop) { + loop = false; + if (leftovers && num_1g_ports) { + rx_1g_bufs++; + leftovers -= num_1g_ports; + loop = true; + } + + if (leftovers && num_2g5_ports) { + rx_2g5_bufs++; + leftovers -= num_2g5_ports; + loop = true; + } + + if (leftovers && num_10g_ports) { + rx_10g_bufs++; + leftovers -= num_10g_ports; + loop = true; + } + } + } + + /* set fifosizes for this FMan ports */ + fm_resource_settings_info->tx1g_num_buffers = tx_1g_bufs; + fm_resource_settings_info->rx1g_num_buffers = rx_1g_bufs; + fm_resource_settings_info->tx2g5_num_buffers = tx_2g5_bufs; + fm_resource_settings_info->rx2g5_num_buffers = rx_2g5_bufs; + fm_resource_settings_info->tx10g_num_buffers = tx_10g_bufs; + fm_resource_settings_info->rx10g_num_buffers = rx_10g_bufs; + fm_resource_settings_info->oh_num_buffers = oh_buff; + fm_resource_settings_info->shared_ext_buffers = shared_ext_buff; + +precalculated_fifosize_out: + printk(KERN_INFO " FMAN(%u) Fifo size settings:\n", + p_LnxWrpFmDev->id); + printk(KERN_INFO " - Total buffers available(%u - 256B/buffer)\n", + total_no_buffers); + printk(KERN_INFO " - Total throughput(%uGbps)\n", (gb_sum / 10)); + printk(KERN_INFO " - Max frame size(%uB)\n", max_frame_size); + if (num_1g_ports) { + printk(KERN_INFO + " - 1G ports TX %u(%u bufs set (min: %u))\n", + num_1g_ports, tx_1g_bufs, min_tx_1g_2g5_bufs); + printk(KERN_INFO + " - 1G ports RX %u(%u bufs set (min: %u))\n", + num_1g_ports, rx_1g_bufs, min_rx_bufs); + } + if (num_2g5_ports) { + printk(KERN_INFO + " - 2.5G ports TX %u(%u bufs set (min: %u))\n", + num_2g5_ports, tx_2g5_bufs, min_tx_1g_2g5_bufs); + printk(KERN_INFO + " - 2.5G ports RX %u(%u bufs set (min: %u))\n", + num_2g5_ports, rx_2g5_bufs, min_rx_bufs); + } + if (num_10g_ports) { + printk(KERN_INFO + " - 10G ports TX %u(%u bufs set (min: %u))\n", + num_10g_ports, tx_10g_bufs, min_tx_10g_bufs); + printk(KERN_INFO + " - 10G ports RX %u(%u bufs set (min: %u))\n", + num_10g_ports, rx_10g_bufs, min_rx_bufs); + } + if (num_oh_ports) + printk(KERN_INFO " - OH-HC ports %u(%u)\n", num_oh_ports, + oh_buff); + printk(KERN_INFO " - Shared extra buffers(%u)\n", shared_ext_buff); + + return err; +} + +int fm_set_precalculate_fifosize(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct fm_resource_settings *fm_resource_settings_info = NULL; + struct fm_active_ports *fm_active_ports_info = NULL; + t_FmPortRsrc portRsrc; + t_Error errCode; + uint32_t buf_size = 0x100; + + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + + memset(&portRsrc, 0, sizeof(t_FmPortRsrc)); + +/* IF 1G PORT */ + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) { + portRsrc.num = + fm_resource_settings_info->tx1g_num_buffers * buf_size; + portRsrc.extra = 0; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX) { + portRsrc.num = + fm_resource_settings_info->rx1g_num_buffers * buf_size; + portRsrc.extra = + fm_resource_settings_info->shared_ext_buffers * + buf_size; + } +/* IF 2.5G PORT */ + /* TODO: Not supported by LLD yet. */ + +/* IF 10G PORT */ + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) { + portRsrc.num = + fm_resource_settings_info->tx10g_num_buffers * + buf_size; + portRsrc.extra = 0; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) { + portRsrc.num = + fm_resource_settings_info->rx10g_num_buffers * + buf_size; + portRsrc.extra = + fm_resource_settings_info->shared_ext_buffers * + buf_size; + } else { /* IF OH PORT */ + portRsrc.num = + fm_resource_settings_info->oh_num_buffers * buf_size; + portRsrc.extra = 0; + } + + errCode = FM_PORT_SetSizeOfFifo(p_LnxWrpFmPortDev->h_Dev, &portRsrc); + if (errCode != E_OK) { + printk(KERN_WARNING + "FM_PORT_SetSizeOfFifo failed (errCode:0x%2x)", + errCode); + return -EIO; + } + + return 0; +} + +/* Compute FMan open DMA based on total number of open DMAs and + * number of available FMan ports. + * + * By default 10g ports are set to input parameters. The other ports + * tries to keep the proportion rx=2tx open DMAs or thresholds. + * + * If leftovers, then those will be set as shared. + * + * If after computing overflow appears, then it decrements open DMA + * for all ports w/o cross the thresholds. If the thresholds are meet + * and is still overflow, then it returns error. + */ +int fm_precalculate_open_dma(t_LnxWrpFmDev *p_LnxWrpFmDev, + int max_fm_open_dma, + int default_tx_10g_dmas, + int default_rx_10g_dmas, + int min_tx_10g_treshold, int min_rx_10g_treshold) +{ + /* input parameters */ + struct fm_active_ports *fm_active_ports_info = NULL; + int num_1g_ports = 0; + int num_2g5_ports = 0; + int num_10g_ports = 0; + int num_oh_ports = 0; + + /* output parameters */ + struct fm_resource_settings *fm_resource_settings_info = NULL; + int tx_1g_dmas = 0, rx_1g_dmas = 0; + int tx_2g5_dmas = 0, rx_2g5_dmas = 0; + int tx_10g_dmas = 0, rx_10g_dmas = 0; + int oh_dmas = 0; + int shared_ext_open_dma = 0; + int err = 0; + + /* open dma calculus */ + int remaing_dmas = 0; + int rx_tx_raport = + FM_OPENDMA_RX_TX_RAPORT; /* RX = FM_OPENDMA_RX_TX_RAPORT *TX */ + int min_tx_1_2g5_treshold = 1; + int min_rx_1_2g5_treshold = 1; + int max_open_dma_treshold = 16; /* LLD: MAX_NUM_OF_DMAS */ + int max_ext_open_dma_treshold = 8; /* LLD: MAX_NUM_OF_EXTRA_DMAS */ + + int open_dmas_computed = 0; + int weighted_remaining_ports = 0; + int overflow = 0; + bool re_loop = false; + + /* check input parameters correctness */ + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + ASSERT_COND(fm_active_ports_info != NULL); + ASSERT_COND(fm_resource_settings_info != NULL); + ASSERT_COND(fm_active_ports_info->num_tx_ports == + fm_active_ports_info->num_rx_ports); + ASSERT_COND(fm_active_ports_info->num_tx25_ports == + fm_active_ports_info->num_tx25_ports); + ASSERT_COND(fm_active_ports_info->num_tx10_ports == + fm_active_ports_info->num_tx10_ports); + ASSERT_COND(min_tx_10g_treshold <= max_open_dma_treshold); + ASSERT_COND(min_tx_10g_treshold <= max_open_dma_treshold); + + /* set input parameters */ + num_1g_ports = fm_active_ports_info->num_tx_ports; + num_2g5_ports = fm_active_ports_info->num_tx25_ports; + num_10g_ports = fm_active_ports_info->num_tx10_ports; + num_oh_ports = fm_active_ports_info->num_oh_ports; + + /* compute open DMAs per port */ + /* ------------------------------------------------------- */ + if (num_10g_ports) { + tx_10g_dmas = default_tx_10g_dmas; /* per 10G TX port */ + rx_10g_dmas = default_rx_10g_dmas; /* per 10G RX port */ + } + if (num_oh_ports) + oh_dmas = 1; /* per OH port */ + + /* should this be null? or LLD: + DEFAULT_PORT_extraNumOfOpenDmas:10g-8,else 1 */ + shared_ext_open_dma = 0; + + /* based on total number of ports set open DMAs for all other ports */ + remaing_dmas = max_fm_open_dma - + (oh_dmas * num_oh_ports) - + (tx_10g_dmas * num_10g_ports + rx_10g_dmas * num_10g_ports) - + shared_ext_open_dma; + + if (remaing_dmas < 0) { + printk(KERN_ALERT + "This configuration will not work due to low number" + " of open dmas (%u open dmas)...\n", + max_fm_open_dma); + err = -1; + goto precalculated_open_dma_out; + } + + weighted_remaining_ports = + /*tx */ num_1g_ports * rx_tx_raport + /*rx */ num_1g_ports + + /*tx */ num_2g5_ports * rx_tx_raport + /*rx */ num_2g5_ports; + + /* compute the other ports */ + if (num_1g_ports) { + tx_1g_dmas = + MAX(MIN + (ROUND_DIV + (remaing_dmas, weighted_remaining_ports), + max_open_dma_treshold), min_tx_1_2g5_treshold); + rx_1g_dmas = + MAX(MIN + (ROUND_DIV + ((remaing_dmas * rx_tx_raport), + weighted_remaining_ports), + max_open_dma_treshold), min_rx_1_2g5_treshold); + } + if (num_2g5_ports) { + tx_2g5_dmas = + MAX(MIN + (CEIL_DIV(remaing_dmas, weighted_remaining_ports), + max_open_dma_treshold), min_tx_1_2g5_treshold); + rx_2g5_dmas = + MAX(MIN + (CEIL_DIV + ((remaing_dmas * rx_tx_raport), + weighted_remaining_ports), + max_open_dma_treshold), min_rx_1_2g5_treshold); + + } + + /* Check if these settings is not exceding treshold */ + open_dmas_computed = num_1g_ports * tx_1g_dmas + + num_1g_ports * rx_1g_dmas + + num_2g5_ports * tx_2g5_dmas + + num_2g5_ports * rx_2g5_dmas + + num_10g_ports * tx_10g_dmas + + num_10g_ports * rx_10g_dmas + + num_oh_ports * oh_dmas + shared_ext_open_dma; + + /* overflow-leftover calculus */ + overflow = open_dmas_computed - max_fm_open_dma; + re_loop = true; + while (overflow > 0 && re_loop == true) { + re_loop = false; + if (num_1g_ports && overflow + && rx_1g_dmas > min_rx_1_2g5_treshold) { + rx_1g_dmas--; + overflow -= num_1g_ports; + re_loop = true; + } + if (num_2g5_ports && overflow + && rx_2g5_dmas > min_rx_1_2g5_treshold) { + rx_2g5_dmas--; + overflow -= num_2g5_ports; + re_loop = true; + } + if (num_10g_ports && overflow + && rx_10g_dmas > min_rx_10g_treshold) { + rx_10g_dmas--; + overflow -= num_10g_ports; + re_loop = true; + } + + if (num_1g_ports && overflow + && tx_1g_dmas > min_tx_1_2g5_treshold) { + tx_1g_dmas--; + overflow -= num_1g_ports; + re_loop = true; + } + if (num_2g5_ports && overflow + && tx_2g5_dmas > min_tx_1_2g5_treshold) { + tx_2g5_dmas--; + overflow -= num_2g5_ports; + re_loop = true; + } + if (num_10g_ports && overflow + && tx_10g_dmas > min_tx_10g_treshold) { + tx_10g_dmas--; + overflow -= num_10g_ports; + re_loop = true; + } + } + + if (overflow > 0) { + printk(KERN_ALERT + "This configuration will not work due to over open dma" + " allocation (%d open dmas)...\n", + overflow); + err = -1; + goto precalculated_open_dma_out; + } + + /* could remain leftovers... e.g. overflow=1, + 2ports => leftover=1 => shared=1 */ + open_dmas_computed = num_1g_ports * tx_1g_dmas + + num_1g_ports * rx_1g_dmas + + num_2g5_ports * tx_2g5_dmas + + num_2g5_ports * rx_2g5_dmas + + num_10g_ports * tx_10g_dmas + + num_10g_ports * rx_10g_dmas + + num_oh_ports * oh_dmas + shared_ext_open_dma; + + if (max_fm_open_dma - open_dmas_computed > 0) + shared_ext_open_dma = + MIN(shared_ext_open_dma + max_fm_open_dma - + open_dmas_computed, max_ext_open_dma_treshold); + + /* set open dmas */ + fm_resource_settings_info->tx_1g_dmas = tx_1g_dmas; + fm_resource_settings_info->rx_1g_dmas = rx_1g_dmas; + fm_resource_settings_info->tx_2g5_dmas = tx_2g5_dmas; + fm_resource_settings_info->rx_2g5_dmas = rx_2g5_dmas; + fm_resource_settings_info->tx_10g_dmas = tx_10g_dmas; + fm_resource_settings_info->rx_10g_dmas = rx_10g_dmas; + fm_resource_settings_info->oh_dmas = oh_dmas; + fm_resource_settings_info->shared_ext_open_dma = shared_ext_open_dma; + +precalculated_open_dma_out: + printk(KERN_INFO " FMAN(%u) open dma settings:\n", + p_LnxWrpFmDev->id); + printk(KERN_INFO " - Total open dma available(%u)\n", + max_fm_open_dma); + if (num_1g_ports) { + printk(KERN_INFO " - 1G ports TX %u(%u)\n", num_1g_ports, + tx_1g_dmas); + printk(KERN_INFO " - 1G ports RX %u(%u)\n", num_1g_ports, + rx_1g_dmas); + } + if (num_2g5_ports) { + printk(KERN_INFO " - 2.5G ports TX %u(%u)\n", num_2g5_ports, + tx_2g5_dmas); + printk(KERN_INFO " - 2.5G ports RX %u(%u)\n", num_2g5_ports, + tx_2g5_dmas); + } + if (num_10g_ports) { + printk(KERN_INFO " - 10G ports TX %u(%u)\n", num_10g_ports, + tx_10g_dmas); + printk(KERN_INFO " - 10G ports RX %u(%u)\n", num_10g_ports, + rx_10g_dmas); + } + if (num_oh_ports) + printk(KERN_INFO " - OH-HC ports %u(%u)\n", num_oh_ports, + oh_dmas); + printk(KERN_INFO " - Shared extra open dma(%u)\n", + shared_ext_open_dma ? shared_ext_open_dma : 0); + + return err; +} + +int fm_set_precalculate_open_dma(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct fm_resource_settings *fm_resource_settings_info = NULL; + t_FmPortRsrc numOfOpenDmas; + t_Error errCode; + + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + + memset(&numOfOpenDmas, 0, sizeof(t_FmPortRsrc)); + +/* IF 1G PORT */ + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) + numOfOpenDmas.num = fm_resource_settings_info->tx_1g_dmas; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX) + numOfOpenDmas.num = fm_resource_settings_info->rx_1g_dmas; +/* IF 2.5G PORT*/ + /* TODO: Not supported by LLD yet. */ + +/* IF 10G PORT */ + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) + numOfOpenDmas.num = fm_resource_settings_info->tx_10g_dmas; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) + numOfOpenDmas.num = fm_resource_settings_info->rx_10g_dmas; +/* IF OH PORT */ + else + numOfOpenDmas.num = fm_resource_settings_info->oh_dmas; + + numOfOpenDmas.extra = fm_resource_settings_info->shared_ext_open_dma; + + errCode = FM_PORT_SetNumOfOpenDmas(p_LnxWrpFmPortDev->h_Dev, + &numOfOpenDmas); + if (errCode != E_OK) { + printk(KERN_WARNING + "FM_PORT_SetNumOfOpenDmas failed (errCode:0x%2x)", + errCode); + return -EIO; + } + + return 0; +} + +/* Compute FMan tnums based on available tnums and number of ports. + Set defaults (minim tresholds) and then distribute leftovers.*/ +int fm_precalculate_tnums(t_LnxWrpFmDev *p_LnxWrpFmDev, int max_fm_tnums) +{ + /* input parameters */ + struct fm_active_ports *fm_active_ports_info = NULL; + int num_1g_ports = 0; + int num_2g5_ports = 0; + int num_10g_ports = 0; + int num_oh_ports = 0; + + /* output parameters */ + struct fm_resource_settings *fm_resource_settings_info = NULL; + int tx_1g_tnums = 0, rx_1g_tnums = 0; + int tx_2g5_tnums = 0, rx_2g5_tnums = 0; + int tx_10g_tnums = 0, rx_10g_tnums = 0; + int oh_tnums = 0; + int shared_ext_tnums = 0; + int err = 0; + + /* open dma calculus */ + int default_and_treshold_rx_tx_10g_tnums = 16; /* DPDE_10g */ + int default_and_treshold_rx_tx_1g_2g5_tnums = 4; /* DPDE_1g */ + int default_and_treshold_oh_tnums = 2; /* Hell knows why */ + int max_tnums_treshold = 64; /* LLD: MAX_NUM_OF_TASKS */ + int max_ext_tnums_treshold = 8; /* LLD: MAX_NUM_OF_EXTRA_TASKS */ + int remaing_tnums = 0; + int tnums_computed = 0; + int leftovers = 0; + bool re_loop = true; + + /* check input parameters correctness */ + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + ASSERT_COND(fm_active_ports_info != NULL); + ASSERT_COND(fm_resource_settings_info != NULL); + ASSERT_COND(fm_active_ports_info->num_tx_ports == + fm_active_ports_info->num_rx_ports); + ASSERT_COND(fm_active_ports_info->num_tx25_ports == + fm_active_ports_info->num_tx25_ports); + ASSERT_COND(fm_active_ports_info->num_tx10_ports == + fm_active_ports_info->num_tx10_ports); + + /* set input parameters */ + num_1g_ports = fm_active_ports_info->num_tx_ports; + num_2g5_ports = fm_active_ports_info->num_tx25_ports; + num_10g_ports = fm_active_ports_info->num_tx10_ports; + num_oh_ports = fm_active_ports_info->num_oh_ports; + + /* compute FMan TNUMs per port */ + /* ------------------------------------------------------- */ + if (num_1g_ports) { + tx_1g_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + rx_1g_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + } + if (num_2g5_ports) { + tx_2g5_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + rx_2g5_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + } + if (num_10g_ports) { + tx_10g_tnums = default_and_treshold_rx_tx_10g_tnums; + rx_10g_tnums = default_and_treshold_rx_tx_10g_tnums; + } + if (num_oh_ports) + oh_tnums = default_and_treshold_oh_tnums; + + shared_ext_tnums = num_10g_ports ? + max_ext_tnums_treshold : 2; /* DEFAULT_PORT_extraNumOfTasks */ + + /* based on total number of ports set open DMAs for all other ports */ + remaing_tnums = max_fm_tnums - + (oh_tnums * num_oh_ports) - + (tx_1g_tnums * num_1g_ports + rx_1g_tnums * num_1g_ports) - + (tx_2g5_tnums * num_2g5_ports + rx_2g5_tnums * num_2g5_ports) - + (tx_10g_tnums * num_10g_ports + rx_10g_tnums * num_10g_ports) - + shared_ext_tnums; + + if (remaing_tnums < 0) { + printk(KERN_ALERT + "This configuration will not work due to low number" + " of tnums (%u tnums) and number of total ports" + " available...\n", + max_fm_tnums); + err = -1; + goto precalculated_tnums_out; + } + + leftovers = remaing_tnums; + re_loop = true; + while (leftovers > 0 && re_loop == true) { + re_loop = false; + if (num_10g_ports && (leftovers - (int) num_10g_ports) >= 0 + && (rx_10g_tnums < max_tnums_treshold)) { + rx_10g_tnums++; + leftovers -= num_10g_ports; + re_loop = true; + } + + if (num_10g_ports && (leftovers - (int) num_10g_ports) >= 0 + && (tx_10g_tnums < max_tnums_treshold)) { + tx_10g_tnums++; + leftovers -= num_10g_ports; + re_loop = true; + } + + if (num_2g5_ports && (leftovers - (int) num_2g5_ports) >= 0 + && (rx_2g5_tnums < max_tnums_treshold)) { + rx_2g5_tnums++; + leftovers -= num_2g5_ports; + re_loop = true; + } + + if (num_2g5_ports && (leftovers - (int) num_2g5_ports) >= 0 + && (tx_2g5_tnums < max_tnums_treshold)) { + tx_2g5_tnums++; + leftovers -= num_2g5_ports; + re_loop = true; + } + + if (num_1g_ports && (leftovers - (int) num_1g_ports) >= 0 + && (rx_1g_tnums < max_tnums_treshold)) { + rx_1g_tnums++; + leftovers -= num_1g_ports; + re_loop = true; + } + + if (num_1g_ports && (leftovers - (int) num_1g_ports) >= 0 + && (tx_1g_tnums < max_tnums_treshold)) { + tx_1g_tnums++; + leftovers -= num_1g_ports; + re_loop = true; + } + } + + tnums_computed = + num_1g_ports * tx_1g_tnums + + num_1g_ports * rx_1g_tnums + + num_2g5_ports * tx_2g5_tnums + + num_2g5_ports * rx_2g5_tnums + + num_10g_ports * tx_10g_tnums + + num_10g_ports * rx_10g_tnums + + num_oh_ports * oh_tnums + + shared_ext_tnums; + + if (leftovers > 0) + shared_ext_tnums = + MIN(shared_ext_tnums + max_fm_tnums - tnums_computed, + max_ext_tnums_treshold); + + ASSERT_COND((oh_tnums * num_oh_ports) + + (tx_1g_tnums * num_1g_ports + rx_1g_tnums * num_1g_ports) + + (tx_2g5_tnums * num_2g5_ports + + rx_2g5_tnums * num_2g5_ports) + + (tx_10g_tnums * num_10g_ports + + rx_10g_tnums * num_10g_ports) + shared_ext_tnums <= + max_fm_tnums); + + /* set computed tnums */ + fm_resource_settings_info->tx_1g_tnums = tx_1g_tnums; + fm_resource_settings_info->rx_1g_tnums = rx_1g_tnums; + fm_resource_settings_info->tx_2g5_tnums = tx_2g5_tnums; + fm_resource_settings_info->rx_2g5_tnums = rx_2g5_tnums; + fm_resource_settings_info->tx_10g_tnums = tx_10g_tnums; + fm_resource_settings_info->rx_10g_tnums = rx_10g_tnums; + fm_resource_settings_info->oh_tnums = oh_tnums; + fm_resource_settings_info->shared_ext_tnums = shared_ext_tnums; + +precalculated_tnums_out: + printk(KERN_INFO " FMAN(%u) Tnums settings:\n", p_LnxWrpFmDev->id); + printk(KERN_INFO " - Total Tnums available(%u)\n", max_fm_tnums); + if (num_1g_ports) { + printk(KERN_INFO " - 1G ports TX %u(%u)\n", num_1g_ports, + tx_1g_tnums); + printk(KERN_INFO " - 1G ports RX %u(%u)\n", num_1g_ports, + rx_1g_tnums); + } + if (num_2g5_ports) { + printk(KERN_INFO " - 2.5G ports TX %u(%u)\n", num_2g5_ports, + tx_2g5_tnums); + printk(KERN_INFO " - 2.5G ports RX %u(%u)\n", num_2g5_ports, + rx_2g5_tnums); + } + if (num_10g_ports) { + printk(KERN_INFO " - 10G ports TX %u(%u)\n", num_10g_ports, + tx_10g_tnums); + printk(KERN_INFO " - 10G ports RX %u(%u)\n", num_10g_ports, + rx_10g_tnums); + } + if (num_oh_ports) + printk(KERN_INFO " - OH-HC ports %u(%u)\n", num_oh_ports, + oh_tnums); + printk(KERN_INFO " - Shared extra tnums(%u)\n", shared_ext_tnums); + + return err; +} + +int fm_set_precalculate_tnums(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct fm_resource_settings *fm_resource_settings_info = NULL; + t_FmPortRsrc numOfTask; + t_Error errCode; + + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + + memset(&numOfTask, 0, sizeof(t_FmPortRsrc)); + +/* IF 1G PORT */ + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) + numOfTask.num = fm_resource_settings_info->tx_1g_tnums; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX) + numOfTask.num = fm_resource_settings_info->rx_1g_tnums; +/* IF 2.5G PORT*/ + /* TODO: Not supported by LLD yet. */ + +/* IF 10G PORT */ + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) + numOfTask.num = fm_resource_settings_info->tx_10g_tnums; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) + numOfTask.num = fm_resource_settings_info->rx_10g_tnums; +/* IF OH PORT */ + else + numOfTask.num = fm_resource_settings_info->oh_dmas; + + numOfTask.extra = fm_resource_settings_info->shared_ext_tnums; + + errCode = FM_PORT_SetNumOfTasks(p_LnxWrpFmPortDev->h_Dev, &numOfTask); + if (errCode != E_OK) { + printk(KERN_WARNING + "FM_PORT_SetNumOfTasks failed (errCode:0x%2x)", + errCode); + return -EIO; + } + + return 0; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/fman_test.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/fman_test.c @@ -0,0 +1,1076 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File fman_test.c + + @Author Moti Bar + + @Description FM Linux test + +*/ + +/* Linux Headers ------------------- */ +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ + +#include +#include +#include +#include +#include +#include +#include +#include /*struct qman_fq */ +#include +#include +#include /*for mixed environment */ +#include +#include + +/* NetCommSw Headers --------------- */ +#include "std_ext.h" +#include "error_ext.h" +#include "debug_ext.h" +#include "list_ext.h" +#include "fm_ext.h" + +#include "fm_test_ioctls.h" +#include "fsl_fman.h" +#include "fsl_fman_test.h" +#include "fm_port_ext.h" + + +#define __ERR_MODULE__ MODULE_FM + +#define FMT_FRM_WATERMARK 0xdeadbeefdeadbeeaLL + +#ifdef CONFIG_COMPAT +/* Define this for KS64b - US32b */ +#define FMAN_TEST_CONFIG_COMPAT +#warning Please make sure you have the right value for FMAN_TEST_CONFIG_COMPAT +#endif + +typedef struct { + ioc_fmt_buff_desc_t buff; + t_List node; +} t_FmTestFrame; + +#define FMT_FRAME_OBJECT(ptr) LIST_OBJECT(ptr, t_FmTestFrame, node) + +typedef struct t_FmTestFq { + struct qman_fq fq_base; + struct list_head list; + void *port; + bool init; +} t_FmTestFq; + +typedef struct { + bool valid; + uint8_t id; + ioc_fmt_port_type portType; + ioc_diag_mode diag; + bool echo; + bool ip_header_manip; + struct fm_port *p_TxPort; + t_Handle h_TxFmPortDev; + struct fm_port *p_RxPort; + t_Handle h_RxFmPortDev; + t_Handle h_Mac; + uint64_t fmPhysBaseAddr; + t_List rxFrmsQ; + + int numOfTxQs; + struct qman_fq *p_TxFqs[8]; +} t_FmTestPort; + +typedef struct { + int major; + t_FmTestPort ports[IOC_FMT_MAX_NUM_OF_PORTS]; + struct class *fm_test_class; +} t_FmTest; + + +static t_FmTest fmTest; + + +static t_Error Set1GMacIntLoopback(t_FmTestPort *p_FmTestPort, bool en) +{ +#define FM_1GMAC0_OFFSET 0x000e0000 +#define FM_1GMAC_CMD_CONF_CTRL_OFFSET 0x100 +#define MACCFG1_LOOPBACK 0x00000100 + + uint64_t baseAddr, regAddr; + uint32_t tmpVal; + + baseAddr = p_FmTestPort->fmPhysBaseAddr + (FM_1GMAC0_OFFSET + (p_FmTestPort->id*0x2000)); + + baseAddr = PTR_TO_UINT(ioremap(baseAddr, 0x1000)); + + regAddr = baseAddr + FM_1GMAC_CMD_CONF_CTRL_OFFSET; + tmpVal = GET_UINT32(*((uint32_t *)UINT_TO_PTR(regAddr))); + if (en) + tmpVal |= MACCFG1_LOOPBACK; + else + tmpVal &= ~MACCFG1_LOOPBACK; + WRITE_UINT32(*((uint32_t *)UINT_TO_PTR(regAddr)), tmpVal); + + iounmap(UINT_TO_PTR(baseAddr)); + + return E_OK; +} + +#ifndef FM_10G_MAC_NO_CTRL_LOOPBACK +static t_Error Set10GMacIntLoopback(t_FmTestPort *p_FmTestPort, bool en) +{ +#define FM_10GMAC0_OFFSET 0x000f0000 +#define FM_10GMAC_CMD_CONF_CTRL_OFFSET 0x8 +#define CMD_CFG_LOOPBACK_EN 0x00000400 + + uint64_t baseAddr, regAddr; + uint32_t tmpVal; + + baseAddr = p_FmTestPort->fmPhysBaseAddr + (FM_10GMAC0_OFFSET + ((p_FmTestPort->id-FM_MAX_NUM_OF_1G_RX_PORTS)*0x2000)); + + baseAddr = PTR_TO_UINT(ioremap(baseAddr, 0x1000)); + + regAddr = baseAddr + FM_10GMAC_CMD_CONF_CTRL_OFFSET; + tmpVal = GET_UINT32(*((uint32_t *)UINT_TO_PTR(regAddr))); + if (en) + tmpVal |= CMD_CFG_LOOPBACK_EN; + else + tmpVal &= ~CMD_CFG_LOOPBACK_EN; + WRITE_UINT32(*((uint32_t *)UINT_TO_PTR(regAddr)), tmpVal); + + iounmap(UINT_TO_PTR(baseAddr)); + + return E_OK; +} +#endif /* !FM_10G_MAC_NO_CTRL_LOOPBACK */ + +static t_Error SetMacIntLoopback(t_FmTestPort *p_FmTestPort, bool en) +{ + + if (p_FmTestPort->portType == e_IOC_FMT_PORT_T_RXTX) + { + if (p_FmTestPort->id < FM_MAX_NUM_OF_1G_RX_PORTS) + return Set1GMacIntLoopback(p_FmTestPort, en); + else if ((p_FmTestPort->id >= FM_MAX_NUM_OF_1G_RX_PORTS) && (p_FmTestPort->id < FM_MAX_NUM_OF_1G_RX_PORTS + FM_MAX_NUM_OF_10G_RX_PORTS)) +#ifndef FM_10G_MAC_NO_CTRL_LOOPBACK + return Set10GMacIntLoopback(p_FmTestPort, en); +#else + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("TGEC don't have internal-loopback")); +#endif /* !FM_10G_MAC_NO_CTRL_LOOPBACK */ + } + else if (p_FmTestPort->portType == e_IOC_FMT_PORT_T_OP) + return E_OK; /* no Mac loopback can be set on OH ports */ + else + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("fm-port-test id!")); + RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); +} + +static void EnqueueFrameToRxQ(t_FmTestPort *p_FmTestPort, t_FmTestFrame *p_FmTestFrame) +{ + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + LIST_AddToTail(&p_FmTestFrame->node, &p_FmTestPort->rxFrmsQ); + XX_RestoreAllIntr(intFlags); +} + +static t_FmTestFrame * DequeueFrameFromRxQ(t_FmTestPort *p_FmTestPort) +{ + t_FmTestFrame *p_FmTestFrame = NULL; + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + if (!LIST_IsEmpty(&p_FmTestPort->rxFrmsQ)) + { + p_FmTestFrame = FMT_FRAME_OBJECT(p_FmTestPort->rxFrmsQ.p_Next); + LIST_DelAndInit(&p_FmTestFrame->node); + } + XX_RestoreAllIntr(intFlags); + + return p_FmTestFrame; +} + +static enum qman_cb_dqrr_result egress_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + return qman_cb_dqrr_consume; +} + +static void egress_ern(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); +} + +static struct qman_fq * FqAlloc(t_FmTestPort *p_FmTestPort, + uint32_t fqid, + uint32_t flags, + uint16_t channel, + uint8_t wq) +{ + int _errno; + struct qman_fq *fq = NULL; + t_FmTestFq *p_FmtFq; + struct qm_mcc_initfq initfq; + + p_FmtFq = (t_FmTestFq *)XX_Malloc(sizeof(t_FmTestFq)); + if (!p_FmtFq) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!")); + return NULL; + } + + p_FmtFq->fq_base.cb.dqrr = egress_dqrr; + p_FmtFq->fq_base.cb.ern = p_FmtFq->fq_base.cb.dc_ern = p_FmtFq->fq_base.cb.fqs = egress_ern; + p_FmtFq->port = (void *)p_FmTestPort; + if (fqid == 0) { + flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; + flags &= ~QMAN_FQ_FLAG_NO_MODIFY; + } else { + flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID; + } + + p_FmtFq->init = !(flags & QMAN_FQ_FLAG_NO_MODIFY); + + DBG(TRACE, ("fqid %d, flags 0x%08x, channel %d, wq %d",fqid,flags,channel,wq)); + + _errno = qman_create_fq(fqid, flags, &p_FmtFq->fq_base); + if (unlikely(_errno)) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj - qman_new_fq!!!")); + XX_Free(p_FmtFq); + return NULL; + } + fq = &p_FmtFq->fq_base; + + if (p_FmtFq->init) { + initfq.we_mask = QM_INITFQ_WE_DESTWQ; + initfq.fqd.dest.channel = channel; + initfq.fqd.dest.wq = wq; + + _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj - qman_init_fq!!!")); + qman_destroy_fq(fq, 0); + XX_Free(p_FmtFq); + return NULL; + } + } + + return fq; +} + +static t_Error PortInit (t_FmTestPort *p_FmTestPort, ioc_fmt_port_param_t *p_Params) +{ + struct device_node *fm_node, *fm_port_node; + const uint32_t *uint32_prop; + int _errno=0, lenp; + uint32_t i; + static struct of_device_id fm_node_of_match[] = { + { .compatible = "fsl,fman", }, + { /* end of list */ }, + }; + + INIT_LIST(&p_FmTestPort->rxFrmsQ); + p_FmTestPort->numOfTxQs = p_Params->num_tx_queues; + p_FmTestPort->id = p_Params->fm_port_id; + p_FmTestPort->portType = p_Params->fm_port_type; + p_FmTestPort->diag = e_IOC_DIAG_MODE_NONE; + p_FmTestPort->ip_header_manip = FALSE; + + /* Get all the FM nodes */ + for_each_matching_node(fm_node, fm_node_of_match) { + + uint32_prop = (uint32_t *)of_get_property(fm_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) failed", fm_node->full_name)); + } + if (WARN_ON(lenp != sizeof(uint32_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) invalid", fm_node->full_name)); + if (*uint32_prop == p_Params->fm_id) { + struct resource res; + /* Get the FM address */ + _errno = of_address_to_resource(fm_node, 0, &res); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + + p_FmTestPort->fmPhysBaseAddr = res.start; + + for_each_child_of_node(fm_node, fm_port_node) { + struct platform_device *of_dev; + + uint32_prop = (uint32_t *)of_get_property(fm_port_node, "cell-index", &lenp); + if (uint32_prop == NULL) + continue; + + if (of_device_is_compatible(fm_port_node, "fsl,fman-port-oh") && + (p_FmTestPort->portType == e_IOC_FMT_PORT_T_OP)) { + if (*uint32_prop == p_FmTestPort->id) + { + of_dev = of_find_device_by_node(fm_port_node); + if (unlikely(of_dev == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + p_FmTestPort->p_TxPort = fm_port_bind(&of_dev->dev); + p_FmTestPort->h_TxFmPortDev = (t_Handle)fm_port_get_handle(p_FmTestPort->p_TxPort); + p_FmTestPort->h_RxFmPortDev = p_FmTestPort->h_TxFmPortDev; + p_FmTestPort->h_Mac = NULL; + break; + } + } + else if ((*uint32_prop == p_FmTestPort->id) && + p_FmTestPort->portType == e_IOC_FMT_PORT_T_RXTX) { + of_dev = of_find_device_by_node(fm_port_node); + if (unlikely(of_dev == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + if(of_device_is_compatible(fm_port_node, "fsl,fman-port-1g-tx")) + { + p_FmTestPort->p_TxPort = fm_port_bind(&of_dev->dev); + p_FmTestPort->h_TxFmPortDev = (t_Handle)fm_port_get_handle(p_FmTestPort->p_TxPort); + } + else if(of_device_is_compatible(fm_port_node, "fsl,fman-port-1g-rx")) + { + p_FmTestPort->p_RxPort = fm_port_bind(&of_dev->dev); + p_FmTestPort->h_RxFmPortDev = (t_Handle)fm_port_get_handle(p_FmTestPort->p_RxPort); + } + else if (of_device_is_compatible(fm_port_node, "fsl,fman-1g-mac")) + p_FmTestPort->h_Mac = (typeof(p_FmTestPort->h_Mac))dev_get_drvdata(&of_dev->dev); + else + continue; + if(p_FmTestPort->h_TxFmPortDev && p_FmTestPort->h_RxFmPortDev && p_FmTestPort->h_Mac) + break; + } + else if (((*uint32_prop + FM_MAX_NUM_OF_1G_RX_PORTS )== p_FmTestPort->id) && + p_FmTestPort->portType == e_IOC_FMT_PORT_T_RXTX) { + of_dev = of_find_device_by_node(fm_port_node); + if (unlikely(of_dev == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + if(of_device_is_compatible(fm_port_node, "fsl,fman-port-10g-tx")) + { + p_FmTestPort->p_TxPort = fm_port_bind(&of_dev->dev); + p_FmTestPort->h_TxFmPortDev = (t_Handle)fm_port_get_handle(p_FmTestPort->p_TxPort); + } + else if(of_device_is_compatible(fm_port_node, "fsl,fman-port-10g-rx")) + { + p_FmTestPort->p_RxPort = fm_port_bind(&of_dev->dev); + p_FmTestPort->h_RxFmPortDev = (t_Handle)fm_port_get_handle(p_FmTestPort->p_RxPort); + } + else if (of_device_is_compatible(fm_port_node, "fsl,fman-10g-mac")) + p_FmTestPort->h_Mac = (typeof(p_FmTestPort->h_Mac))dev_get_drvdata(&of_dev->dev); + else + continue; + if(p_FmTestPort->h_TxFmPortDev && p_FmTestPort->h_RxFmPortDev && p_FmTestPort->h_Mac) + break; + } + } //for_each_child + } + } //for each matching node + + DBG(TRACE, ("h_TxFmPortDev - 0x%08x, h_RxFmPortDev - 0x%08x, h_Mac - 0x%08x\n", + p_FmTestPort->h_TxFmPortDev,p_FmTestPort->h_RxFmPortDev,p_FmTestPort->h_Mac)); + + if(p_FmTestPort->h_TxFmPortDev == 0 || p_FmTestPort->h_RxFmPortDev == 0) + RETURN_ERROR(MINOR, E_INVALID_ADDRESS, ("Bad pointers!")); + + //init Queues + for (i=0; inumOfTxQs; i++) { + p_FmTestPort->p_TxFqs[i] = + FqAlloc(p_FmTestPort, + 0, + QMAN_FQ_FLAG_TO_DCPORTAL, + fm_get_tx_port_channel(p_FmTestPort->p_TxPort), + i); + if (IS_ERR(p_FmTestPort->p_TxFqs[i])) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Tx FQs!")); + } + + p_FmTestPort->valid = TRUE; + + return E_OK; +} + + +bool is_fman_test (void *mac_dev, + uint32_t queueId, + uint8_t *buffer, + uint32_t size) +{ + t_FmTest *p_FmTest = &fmTest; + t_FmTestPort *p_FmTestPort=NULL; + t_FmTestFrame *p_FmTestFrame; + uint32_t count=size-7; + uint64_t temp; + uint8_t *temp_buf=buffer, i; + bool fman_test_flag = false; + uint32_t dataOffset; + struct fm_port *fm_port = (struct fm_port *) mac_dev; + +#if 0 + if ((queueId == FMT_TX_CONF_Q) || (queueId == FMT_TX_ERR_Q)) + { + /* Check for the FM-test-port object existence, otherwise we make wrong frees all the time */ + for (i=0; iports[i].h_Mac) + p_FmTestPort = &p_FmTest->ports[i]; + if (!p_FmTestPort) + return false; + + if (buffer != NULL) + XX_Free(buffer); + return true; + } +#endif + + /* Get the FM-test-port object */ + for (i=0; iports[i].h_Mac && mac_dev == p_FmTest->ports[i].h_Mac) || + fm_port == p_FmTest->ports[i].p_TxPort) + { + p_FmTestPort = &p_FmTest->ports[i]; + break; + } + if (!p_FmTestPort) + return false; + + /* Check according to watermark if this frame is for FM-test */ + while(count--) + { + temp = *(uint64_t *)temp_buf; + if (temp == FMT_FRM_WATERMARK) + { + fman_test_flag = true; + break; + } + temp_buf++; + } + + if (fman_test_flag /*|| p_FmTestPort->echo*/) + { + if ((queueId == FMT_TX_CONF_Q) || (queueId == FMT_TX_ERR_Q)) + { + if (buffer != NULL) + XX_Free(buffer); + return true; + } + + DBG(TRACE, ("Port %d got FMUC frame\n", p_FmTestPort->id)); + dataOffset = FM_PORT_GetBufferDataOffset(p_FmTestPort->h_RxFmPortDev); + + p_FmTestFrame = (t_FmTestFrame *)XX_Malloc(sizeof(t_FmTestFrame)); + /* dump frame... no more space left on device */ + if(p_FmTestFrame == NULL) + return false; + + memset(p_FmTestFrame, 0, sizeof(t_FmTestFrame)); + INIT_LIST(&p_FmTestFrame->node); + + p_FmTestFrame->buff.p_data = (uint8_t *)XX_Malloc(size * sizeof(uint8_t)); + /* No more space left on device*/ + if(p_FmTestFrame->buff.p_data == NULL){ + XX_Free(p_FmTestFrame); + return false; + } + + p_FmTestFrame->buff.size = size-dataOffset; + p_FmTestFrame->buff.qid = queueId; + + memcpy(p_FmTestFrame->buff.p_data, + (uint8_t *)PTR_MOVE(buffer, dataOffset), + p_FmTestFrame->buff.size); + + memcpy(p_FmTestFrame->buff.buff_context.fm_prs_res, + FM_PORT_GetBufferPrsResult(p_FmTestPort->h_RxFmPortDev, (char*)buffer), + 32); + + EnqueueFrameToRxQ(p_FmTestPort, p_FmTestFrame); + return true; + } + + return false; +} + +void fman_test_ip_manip (void *mac_dev, uint8_t *data) +{ + t_FmTest *p_FmTest = &fmTest; + t_FmTestPort *p_FmTestPort=NULL; + struct iphdr *iph; + uint32_t *p_Data = (uint32_t *)data; + uint32_t net; + uint32_t saddr, daddr; + uint8_t i; + + /* Get the FM-test-port object */ + for (i=0; iports[i].h_Mac) + p_FmTestPort = &p_FmTest->ports[i]; + if (!p_FmTestPort || !p_FmTestPort->ip_header_manip) + return; + + iph = (struct iphdr *)p_Data; + saddr = iph->saddr; + daddr = iph->daddr; + + /* If it is ARP packet ... */ + if (*p_Data == 0x00010800) + { + saddr = *((uint32_t *)PTR_MOVE(p_Data, 14)); + daddr = *((uint32_t *)PTR_MOVE(p_Data, 24)); + } + + DBG(TRACE, + ("\nSrc IP before header-manipulation: %d.%d.%d.%d" + "\nDest IP before header-manipulation: %d.%d.%d.%d", + (int)((saddr & 0xff000000) >> 24), + (int)((saddr & 0x00ff0000) >> 16), + (int)((saddr & 0x0000ff00) >> 8), + (int)((saddr & 0x000000ff) >> 0), + (int)((daddr & 0xff000000) >> 24), + (int)((daddr & 0x00ff0000) >> 16), + (int)((daddr & 0x0000ff00) >> 8), + (int)((daddr & 0x000000ff) >> 0))); + + if ((p_FmTestPort->diag == e_IOC_DIAG_MODE_CTRL_LOOPBACK) || + (p_FmTestPort->diag == e_IOC_DIAG_MODE_CHIP_LOOPBACK) || + (p_FmTestPort->diag == e_IOC_DIAG_MODE_PHY_LOOPBACK) || + (p_FmTestPort->diag == e_IOC_DIAG_MODE_LINE_LOOPBACK)) + { + net = saddr; + saddr = daddr; + daddr = net; + } + else + { + /* We allow only up to 10 eth ports */ + net = ((daddr & 0x000000ff) % 10); + saddr = (uint32_t)((saddr & ~0x0000ff00) | (net << 8)); + daddr = (uint32_t)((daddr & ~0x0000ff00) | (net << 8)); + } + + /* If not ARP ... */ + if (*p_Data != 0x00010800) + { + iph->check = 0; + + iph->saddr = saddr; + iph->daddr = daddr; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + } + else /* The packet is ARP */ + { + *((uint32_t *)PTR_MOVE(p_Data, 14)) = saddr; + *((uint32_t *)PTR_MOVE(p_Data, 24)) = daddr; + } + + DBG(TRACE, + ("\nSrc IP after header-manipulation: %d.%d.%d.%d" + "\nDest IP after header-manipulation: %d.%d.%d.%d", + (int)((saddr & 0xff000000) >> 24), + (int)((saddr & 0x00ff0000) >> 16), + (int)((saddr & 0x0000ff00) >> 8), + (int)((saddr & 0x000000ff) >> 0), + (int)((daddr & 0xff000000) >> 24), + (int)((daddr & 0x00ff0000) >> 16), + (int)((daddr & 0x0000ff00) >> 8), + (int)((daddr & 0x000000ff) >> 0))); +} + + +/*****************************************************************************/ +/* API routines for the FM Linux Device */ +/*****************************************************************************/ + +static int fm_test_open(struct inode *inode, struct file *file) +{ + t_FmTest *p_FmTest = &fmTest; + //unsigned int major = imajor(inode); + unsigned int minor = iminor(inode); + + DBG(TRACE, ("Opening minor - %d - ", minor)); + + if (file->private_data != NULL) + return 0; + + if ((minor >= DEV_FM_TEST_PORTS_MINOR_BASE) && + (minor < DEV_FM_TEST_MAX_MINORS)) + file->private_data = &p_FmTest->ports[minor]; + else + return -ENXIO; + + return 0; +} + +static int fm_test_close(struct inode *inode, struct file *file) +{ + t_FmTestPort *p_FmTestPort; + unsigned int minor = iminor(inode); + int err = 0; + + DBG(TRACE, ("Closing minor - %d - ", minor)); + + p_FmTestPort = file->private_data; + if (!p_FmTestPort) + return -ENODEV; + + p_FmTestPort->valid = FALSE; + + /* Complete!!! */ + return err; +} + +static int fm_test_ioctls(unsigned int minor, struct file *file, unsigned int cmd, unsigned long arg, bool compat) +{ + t_FmTestPort *p_FmTestPort; + + DBG(TRACE, ("IOCTL minor - %d, cmd - 0x%08x, arg - 0x%08x", minor, cmd, arg)); + + p_FmTestPort = file->private_data; + if (!p_FmTestPort) + return -ENODEV; + + switch (cmd) + { + case FMT_PORT_IOC_INIT: + { + ioc_fmt_port_param_t param; + + if (p_FmTestPort->valid) { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("port is already initialized!!!")); + return -EFAULT; + } +#if defined(FMAN_TEST_CONFIG_COMPAT) + if (compat){ + if (copy_from_user(¶m, (ioc_fmt_port_param_t *)compat_ptr(arg), sizeof(ioc_fmt_port_param_t))) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -EFAULT; + } + } +#endif + else{ + if (copy_from_user(¶m, (ioc_fmt_port_param_t *) arg, sizeof(ioc_fmt_port_param_t))) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -EFAULT; + } + } + + return PortInit(p_FmTestPort, ¶m); + } + + case FMT_PORT_IOC_SET_DIAG_MODE: + { + if (get_user(p_FmTestPort->diag, (ioc_diag_mode *)arg)) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -EFAULT; + } + + if (p_FmTestPort->diag == e_IOC_DIAG_MODE_CTRL_LOOPBACK) + return SetMacIntLoopback(p_FmTestPort, TRUE); + else + return SetMacIntLoopback(p_FmTestPort, FALSE); + break; + } + + case FMT_PORT_IOC_SET_DPAECHO_MODE: + { +#if defined(FMAN_TEST_CONFIG_COMPAT) + if (compat){ + if (get_user(p_FmTestPort->echo, (int *)compat_ptr(arg))) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -EFAULT; + } + } + else +#endif + { + if (get_user(p_FmTestPort->echo, (int *)arg)) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -EFAULT; + } + } + break; + } + + case FMT_PORT_IOC_SET_IP_HEADER_MANIP: + { +#if defined(FMAN_TEST_CONFIG_COMPAT) + if (compat){ + if (get_user(p_FmTestPort->ip_header_manip, (int *)compat_ptr(arg))) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -EFAULT; + } + } + else +#endif + { + if (get_user(p_FmTestPort->ip_header_manip, (int *)arg)) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -EFAULT; + } + } + break; + } + + default: + REPORT_ERROR(MINOR, E_INVALID_SELECTION, ("IOCTL TEST cmd (0x%08lx):(0x%02lx:0x%02lx)!", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd))); + return -EFAULT; + } + + return 0; +} + +#ifdef FMAN_TEST_CONFIG_COMPAT +static long fm_test_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + + return fm_test_ioctls(minor, file, cmd, arg, true); +} +#endif + +static long fm_test_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + unsigned int res; + + fm_mutex_lock(); + res = fm_test_ioctls(minor, file, cmd, arg, false); + fm_mutex_unlock(); + + return res; +} + +#ifdef FMAN_TEST_CONFIG_COMPAT +void copy_compat_test_frame_buffer(ioc_fmt_buff_desc_t *buff, ioc_fmt_compat_buff_desc_t *compat_buff) +{ + compat_buff->qid = buff->qid; + compat_buff->p_data = ptr_to_compat(buff->p_data); + compat_buff->size = buff->size; + compat_buff->status = buff->status; + + compat_buff->buff_context.p_user_priv = ptr_to_compat(buff->buff_context.p_user_priv); + memcpy(compat_buff->buff_context.fm_prs_res,buff->buff_context.fm_prs_res,FM_PRS_MAX * sizeof(uint8_t)); + memcpy(compat_buff->buff_context.fm_time_stamp,buff->buff_context.fm_time_stamp,FM_TIME_STAMP_MAX * sizeof(uint8_t)); +} +#endif + +ssize_t fm_test_read (struct file *file, char __user *buf, size_t size, loff_t *ppos) +{ + t_FmTestPort *p_FmTestPort; + t_FmTestFrame *p_FmTestFrame; + ssize_t cnt = 0; + + p_FmTestPort = file->private_data; + if (!p_FmTestPort || !p_FmTestPort->valid) + return -ENODEV; + + p_FmTestFrame = DequeueFrameFromRxQ(p_FmTestPort); + if (!p_FmTestFrame) + return 0; + + if (!p_FmTestPort->echo) { +#ifdef FMAN_TEST_CONFIG_COMPAT + cnt = sizeof(ioc_fmt_compat_buff_desc_t); +#else + cnt = sizeof(ioc_fmt_buff_desc_t); +#endif + if (sizebuff.p_data); + XX_Free(p_FmTestFrame); + REPORT_ERROR(MINOR, E_NO_MEMORY, ("Illegal buffer-size!")); + return 0; + } + + /* Copy structure */ +#ifdef FMAN_TEST_CONFIG_COMPAT + { + ioc_fmt_compat_buff_desc_t compat_buff; + copy_compat_test_frame_buffer(&p_FmTestFrame->buff, &compat_buff); + + if (copy_to_user(buf, &compat_buff, cnt)) { + XX_Free(p_FmTestFrame->buff.p_data); + XX_Free(p_FmTestFrame); + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return 0; + } + } + + ((ioc_fmt_compat_buff_desc_t *)buf)->p_data = ptr_to_compat(buf+sizeof(ioc_fmt_compat_buff_desc_t)); + cnt += MIN(p_FmTestFrame->buff.size, size-cnt); +#else + if (copy_to_user(buf, &p_FmTestFrame->buff, cnt)) { + XX_Free(p_FmTestFrame->buff.p_data); + XX_Free(p_FmTestFrame); + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return 0; + } + + ((ioc_fmt_buff_desc_t *)buf)->p_data = buf+sizeof(ioc_fmt_buff_desc_t); + cnt += MIN(p_FmTestFrame->buff.size, size-cnt); +#endif + + if (sizebuff.p_data); + XX_Free(p_FmTestFrame); + REPORT_ERROR(MINOR, E_NO_MEMORY, ("Illegal buffer-size!")); + return 0; + } + + /* copy frame */ +#ifdef FMAN_TEST_CONFIG_COMPAT + if (copy_to_user(buf+sizeof(ioc_fmt_compat_buff_desc_t), p_FmTestFrame->buff.p_data, cnt)) { + XX_Free(p_FmTestFrame->buff.p_data); + XX_Free(p_FmTestFrame); + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return 0; + } +#else + if (copy_to_user(buf+sizeof(ioc_fmt_buff_desc_t), p_FmTestFrame->buff.p_data, cnt)) { + XX_Free(p_FmTestFrame->buff.p_data); + XX_Free(p_FmTestFrame); + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return 0; + } +#endif + + XX_Free(p_FmTestFrame->buff.p_data); + XX_Free(p_FmTestFrame); + } + else { + uint8_t *p_Data = NULL; + uint32_t frameSize =0; + t_DpaaFD fd; + int _errno = 0; + + p_Data = (uint8_t *)p_FmTestFrame->buff.p_data; + frameSize = p_FmTestFrame->buff.size; + + /* paranoia ...*/ + if(!p_Data){ + XX_Free(p_FmTestFrame); + return 0; + } + + /* Set frame descriptor... */ + memset(&fd, 0, sizeof(fd)); + DPAA_FD_SET_ADDR(&fd, p_Data); + DPAA_FD_SET_OFFSET(&fd, 0); + DPAA_FD_SET_LENGTH(&fd, frameSize); + + /* Enqueue frame... */ + _errno = qman_enqueue(p_FmTestPort->p_TxFqs[0], (struct qm_fd*)&fd, 0); + if (_errno) { + XX_Free(p_FmTestFrame); + XX_Free(p_Data); + return 0; + } + + XX_Free(p_FmTestFrame); + } + + return cnt; +} + +ssize_t fm_test_write (struct file *file, const char __user *buf, size_t size, loff_t *ppos) +{ + t_FmTestPort *p_FmTestPort; + + ioc_fmt_buff_desc_t buffDesc; +#ifdef FMAN_TEST_CONFIG_COMPAT + ioc_fmt_compat_buff_desc_t compatBuffDesc; +#endif + t_DpaaFD fd; + uint8_t *p_Data; + uint32_t dataOffset; + int _errno; + + p_FmTestPort = file->private_data; + if (!p_FmTestPort || !p_FmTestPort->valid) { + REPORT_ERROR(MINOR, E_INVALID_HANDLE, NO_MSG); + return -1; + } + + /* If Compat (32B UserSpace - 64B KernelSpace) */ +#ifdef FMAN_TEST_CONFIG_COMPAT + if (copy_from_user(&compatBuffDesc, buf, sizeof(ioc_fmt_compat_buff_desc_t))) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -1; + } + + buffDesc.qid = compatBuffDesc.qid; + buffDesc.p_data = compat_ptr(compatBuffDesc.p_data); + buffDesc.size = compatBuffDesc.size; + buffDesc.status = compatBuffDesc.status; + + buffDesc.buff_context.p_user_priv = compat_ptr(compatBuffDesc.buff_context.p_user_priv); + memcpy(buffDesc.buff_context.fm_prs_res, compatBuffDesc.buff_context.fm_prs_res, FM_PRS_MAX * sizeof(uint8_t)); + memcpy(buffDesc.buff_context.fm_time_stamp, compatBuffDesc.buff_context.fm_time_stamp, FM_TIME_STAMP_MAX * sizeof(uint8_t)); +#else + if (copy_from_user(&buffDesc, (ioc_fmt_buff_desc_t *)buf, sizeof(ioc_fmt_buff_desc_t))) { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return -1; + } +#endif + + dataOffset = FM_PORT_GetBufferDataOffset(p_FmTestPort->h_TxFmPortDev); + p_Data = (uint8_t*)XX_Malloc(buffDesc.size+dataOffset); + if (!p_Data) { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("data buff!")); + return -1; + } + + /* If Compat (32UserSpace - 64KernelSpace) the buffDesc.p_data is ok */ + if (copy_from_user ((uint8_t *)PTR_MOVE(p_Data, dataOffset), + buffDesc.p_data, + buffDesc.size)) { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("data buff!")); + XX_Free(p_Data); + return -1; + } + + memset(&fd, 0, sizeof(fd)); + DPAA_FD_SET_ADDR(&fd, p_Data); + DPAA_FD_SET_OFFSET(&fd, dataOffset); + DPAA_FD_SET_LENGTH(&fd, buffDesc.size); + + DBG(TRACE, ("buffDesc qId %d, fqid %d, frame len %d, fq 0x%8x\n", + buffDesc.qid, qman_fq_fqid(p_FmTestPort->p_TxFqs[buffDesc.qid]), buffDesc.size, p_FmTestPort->p_TxFqs[buffDesc.qid])); + + _errno = qman_enqueue(p_FmTestPort->p_TxFqs[buffDesc.qid], (struct qm_fd*)&fd, 0); + if (_errno) { + buffDesc.status = (uint32_t)_errno; + if (copy_to_user((ioc_fmt_buff_desc_t*)buf, &buffDesc, sizeof(ioc_fmt_buff_desc_t))) { + REPORT_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + XX_Free(p_Data); + return -1; + } + } + return buffDesc.size; +} + +/* Globals for FM character device */ +static struct file_operations fm_test_fops = +{ + owner: THIS_MODULE, +#ifdef FMAN_TEST_CONFIG_COMPAT + compat_ioctl:fm_test_compat_ioctl, +#endif + unlocked_ioctl: fm_test_ioctl, + open: fm_test_open, + release: fm_test_close, + read: fm_test_read, + write: fm_test_write, +}; + +t_Handle LNXWRP_FM_TEST_Init(void) +{ + t_FmTest *p_FmTest = &fmTest; + int id; + + /* Register to the /dev for IOCTL API */ + /* Register dynamically a new major number for the character device: */ + if ((p_FmTest->major = register_chrdev(0, DEV_FM_TEST_NAME, &fm_test_fops)) <= 0) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Failed to allocate a major number for device \"%s\"", DEV_FM_TEST_NAME)); + return NULL; + } + + /* Creating class for FMan_test */ + DBG(TRACE ,("class_create fm_test_class")); + p_FmTest->fm_test_class = class_create(THIS_MODULE, DEV_FM_TEST_NAME); + if (IS_ERR(p_FmTest->fm_test_class)) { + unregister_chrdev(p_FmTest->major, DEV_FM_TEST_NAME); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("class_create error fm_test_class")); + return NULL; + } + + for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++) + if(NULL == device_create(p_FmTest->fm_test_class, NULL, MKDEV(p_FmTest->major, DEV_FM_TEST_PORTS_MINOR_BASE + id), NULL, + DEV_FM_TEST_NAME "%d", id)) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Error creating device.\n")); + return NULL; + } + + /* Seed the QMan allocator so we'll have enough queues to run PCD with + dinamically fqid-range allocation */ + qman_release_fqid_range(0x100, 0x400); + + return p_FmTest; +} + +t_Error LNXWRP_FM_TEST_Free(t_Handle h_FmTestLnxWrp) +{ + t_FmTest *p_FmTest = (t_FmTest*)h_FmTestLnxWrp; + int id; + + DBG(TRACE, ("destroy fm_test_class")); + for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++) + device_destroy(p_FmTest->fm_test_class, MKDEV(p_FmTest->major, DEV_FM_TEST_PORTS_MINOR_BASE + id)); + class_destroy(p_FmTest->fm_test_class); + + return E_OK; +} + +static t_Handle h_FmTestLnxWrp; + +static int __init __cold fm_test_load (void) +{ + if ((h_FmTestLnxWrp = LNXWRP_FM_TEST_Init()) == NULL) + { + printk("Failed to init FM-test wrapper!\n"); + if (h_FmTestLnxWrp) + LNXWRP_FM_TEST_Free(h_FmTestLnxWrp); + return -ENODEV; + } + + printk (KERN_CRIT "Freescale FM test module ("__DATE__ ":"__TIME__")\n"); + + return 0; +} + +static void __exit __cold fm_test_unload (void) +{ + if (h_FmTestLnxWrp) + LNXWRP_FM_TEST_Free(h_FmTestLnxWrp); +} + +module_init (fm_test_load); +module_exit (fm_test_unload); --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_sysfs.h + + @Description FM sysfs functions. + +*/ + +#ifndef LNXWRP_SYSFS_H_ +#define LNXWRP_SYSFS_H_ + +/* Linux Headers ------------------- */ +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ + +#include +#include +#include +#include + +struct SysfsStats_t { + const char *statisticName; + uint8_t statisticCounter; +}; + +uint8_t fm_find_statistic_counter_by_name(const char *attr_name, + struct SysfsStats_t *sysfs_stats, + uint8_t *offset); + +#endif /* LNXWRP_SYSFS_H_ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) +EXTRA_CFLAGS += -I$(NET_DPA) + +obj-y += fsl-ncsw-PFM.o +obj-$(CONFIG_FSL_FMAN_TEST) += fman_test.o + +fsl-ncsw-PFM-objs := lnxwrp_fm.o lnxwrp_fm_port.o lnxwrp_ioctls_fm.o \ + lnxwrp_sysfs.o lnxwrp_sysfs_fm.o lnxwrp_sysfs_fm_port.o \ + lnxwrp_resources.o +obj-$(CONFIG_COMPAT) += lnxwrp_ioctls_fm_compat.o --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_fm.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_fm.c @@ -0,0 +1,1204 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_fm.c + + @Author Shlomi Gridish + + @Description FM Linux wrapper functions. + +*/ + +#include +#include +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For struct qe_firmware */ +#include +#include /* For file access mask */ +#include +#include +#include + +/* NetCommSw Headers --------------- */ +#include "std_ext.h" +#include "error_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "sys_io_ext.h" + +#include "fm_ioctls.h" + +#include "lnxwrp_fm.h" +#include "lnxwrp_resources.h" +#include "lnxwrp_sysfs_fm.h" +#include "lnxwrp_sysfs_fm_port.h" + +#define PROC_PRINT(args...) offset += sprintf(buf+offset,args) + +#define ADD_ADV_CONFIG_NO_RET(_func, _param) \ + do { \ + if (ip_Function = _func; \ + _param \ + i++; \ + } \ + else \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE,\ + ("Number of advanced-configuration entries exceeded"));\ + } while (0) + +static t_LnxWrpFm lnxWrpFm; + + +static irqreturn_t fm_irq(int irq, void *_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev; + + if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev) + return IRQ_NONE; + + FM_EventIsr(p_LnxWrpFmDev->h_Dev); + + return IRQ_HANDLED; +} + +static irqreturn_t fm_err_irq(int irq, void *_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev; + + if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev) + return IRQ_NONE; + + if (FM_ErrorIsr(p_LnxWrpFmDev->h_Dev) == E_OK) + return IRQ_HANDLED; + + return IRQ_NONE; +} + +/* used to protect FMD/LLD from concurrent calls in functions fm_mutex_lock / fm_mutex_unlock */ +static struct mutex lnxwrp_mutex; + +static t_LnxWrpFmDev * CreateFmDev(uint8_t id) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + int j; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *)XX_Malloc(sizeof(t_LnxWrpFmDev)); + if (!p_LnxWrpFmDev) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + memset(p_LnxWrpFmDev, 0, sizeof(t_LnxWrpFmDev)); + p_LnxWrpFmDev->fmDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->fmDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + p_LnxWrpFmDev->fmPcdDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->fmPcdDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + p_LnxWrpFmDev->hcPort.settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->hcPort.settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + for (j=0; jrxPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->rxPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + } + for (j=0; jtxPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->txPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + } + for (j=0; jopPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->opPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + } + + return p_LnxWrpFmDev; +} + +static void DestroyFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + int j; + + for (j=0; jopPorts[j].settings.advConfig) + XX_Free(p_LnxWrpFmDev->opPorts[j].settings.advConfig); + for (j=0; jtxPorts[j].settings.advConfig) + XX_Free(p_LnxWrpFmDev->txPorts[j].settings.advConfig); + for (j=0; jrxPorts[j].settings.advConfig) + XX_Free(p_LnxWrpFmDev->rxPorts[j].settings.advConfig); + if (p_LnxWrpFmDev->hcPort.settings.advConfig) + XX_Free(p_LnxWrpFmDev->hcPort.settings.advConfig); + if (p_LnxWrpFmDev->fmPcdDevSettings.advConfig) + XX_Free(p_LnxWrpFmDev->fmPcdDevSettings.advConfig); + if (p_LnxWrpFmDev->fmDevSettings.advConfig) + XX_Free(p_LnxWrpFmDev->fmDevSettings.advConfig); + + XX_Free(p_LnxWrpFmDev); +} + +static t_Error FillRestFmInfo(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ +#define FM_BMI_PPIDS_OFFSET 0x00080304 +#define FM_DMA_PLR_OFFSET 0x000c2060 +#define FM_FPM_IP_REV_1_OFFSET 0x000c30c4 +#define DMA_HIGH_LIODN_MASK 0x0FFF0000 +#define DMA_LOW_LIODN_MASK 0x00000FFF +#define DMA_LIODN_SHIFT 16 + +typedef _Packed struct { + uint32_t plr[32]; +} _PackedType t_Plr; + +typedef _Packed struct { + volatile uint32_t fmbm_ppid[63]; +} _PackedType t_Ppids; + + t_Plr *p_Plr; + t_Ppids *p_Ppids; + int i,j; + uint32_t fmRev; + + static const uint8_t phys1GRxPortId[] = {0x8,0x9,0xa,0xb,0xc}; + static const uint8_t phys10GRxPortId[] = {0x10}; + static const uint8_t physOhPortId[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7}; + static const uint8_t phys1GTxPortId[] = {0x28,0x29,0x2a,0x2b,0x2c}; + static const uint8_t phys10GTxPortId[] = {0x30}; + + fmRev = (uint32_t)(*((volatile uint32_t *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_FPM_IP_REV_1_OFFSET))); + fmRev &= 0xffff; + + p_Plr = (t_Plr *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_DMA_PLR_OFFSET); +#ifdef MODULE + for (i=0;iplr[i] = 0; +#endif /* MODULE */ + + for (i=0; iplr[i/2] & DMA_LOW_LIODN_MASK) : + ((p_Plr->plr[i/2] & DMA_HIGH_LIODN_MASK) >> DMA_LIODN_SHIFT)); +#ifdef FM_PARTITION_ARRAY + /* TODO: this was .liodnPerPartition[i] = liodnBase; is the index meaning the same? */ + p_LnxWrpFmDev->fmDevSettings.param.liodnBasePerPort[i] = liodnBase; +#endif /* FM_PARTITION_ARRAY */ + + if ((i >= phys1GRxPortId[0]) && + (i <= phys1GRxPortId[FM_MAX_NUM_OF_1G_RX_PORTS-1])) + { + for (j=0; jrxPorts[j].settings.param.liodnBase = liodnBase; + } + else if (FM_MAX_NUM_OF_10G_RX_PORTS && + (i >= phys10GRxPortId[0]) && + (i <= phys10GRxPortId[FM_MAX_NUM_OF_10G_RX_PORTS-1])) + { + for (j=0; jrxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+j].settings.param.liodnBase = liodnBase; + } + else if ((i >= physOhPortId[0]) && + (i <= physOhPortId[FM_MAX_NUM_OF_OH_PORTS-1])) + { + for (j=0; jhcPort.settings.param.liodnBase = liodnBase; + else + p_LnxWrpFmDev->opPorts[j - 1].settings.param.liodnBase = liodnBase; + } + else if ((i >= phys1GTxPortId[0]) && + (i <= phys1GTxPortId[FM_MAX_NUM_OF_1G_TX_PORTS-1])) + { + for (j=0; jtxPorts[j].settings.param.liodnBase = liodnBase; + } + else if (FM_MAX_NUM_OF_10G_TX_PORTS && + (i >= phys10GTxPortId[0]) && + (i <= phys10GTxPortId[FM_MAX_NUM_OF_10G_TX_PORTS-1])) + { + for (j=0; jtxPorts[FM_MAX_NUM_OF_1G_TX_PORTS+j].settings.param.liodnBase = liodnBase; + } + } + + p_Ppids = (t_Ppids *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_BMI_PPIDS_OFFSET); + + for (i=0; irxPorts[i].settings.param.specificParams.rxParams.liodnOffset = + p_Ppids->fmbm_ppid[phys1GRxPortId[i]-1]; + + for (i=0; irxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+i].settings.param.specificParams.rxParams.liodnOffset = + p_Ppids->fmbm_ppid[phys10GRxPortId[i]-1]; + +#ifdef FM_OP_PARTITION_ERRATA_FMANx8 + for (i=0; iopPorts[i-1].settings.param.specificParams.nonRxParams.opLiodnOffset = + p_Ppids->fmbm_ppid[physOhPortId[i]-1]; + } +#endif /* FM_OP_PARTITION_ERRATA_FMANx8 */ + + return E_OK; +} + +/* The default address for the Fman microcode in flash. Having a default + * allows older systems to continue functioning. 0xEF000000 is the address + * where the firmware is normally on a P4080DS. + */ +#ifdef CONFIG_PHYS_64BIT +static phys_addr_t P4080_UCAddr = 0xfef000000ull; +#else +static phys_addr_t P4080_UCAddr = 0xef000000; +#endif + + +/** + * FmanUcodeAddrParam - process the fman_ucode kernel command-line parameter + * + * This function is called when the kernel encounters a fman_ucode command- + * line parameter. This parameter contains the address of the Fman microcode + * in flash. + */ +static int FmanUcodeAddrParam(char *str) +{ + unsigned long long l; + int ret; + + ret = strict_strtoull(str, 0, &l); + if (!ret) + P4080_UCAddr = (phys_addr_t) l; + + return ret; +} +__setup("fman_ucode=", FmanUcodeAddrParam); + +/** + * FindFmanMicrocode - find the Fman microcode in memory + * + * This function returns a pointer to the QE Firmware blob that holds + * the Fman microcode. We use the QE Firmware structure because Fman microcode + * is similar to QE microcode, so there's no point in defining a new layout. + * + * Current versions of U-Boot embed the Fman firmware into the device tree, + * so we check for that first. Each Fman node in the device tree contains a + * node or a pointer to node that holds the firmware. Technically, we should + * be fetching the firmware node for the current Fman, but we don't have that + * information any more, so we assume that there is only one firmware node in + * the device tree, and that all Fmen use the same firmware. + * + * If we have an older U-Boot, then we assume that the firmware is located in + * flash at physical address 'P4080_UCAddr' + */ +static const struct qe_firmware *FindFmanMicrocode(void) +{ + static const struct qe_firmware *P4080_UCPatch; + struct device_node *np; +#ifdef FMAN_READ_MICROCODE_FROM_NOR_FLASH + unsigned long P4080_UCSize; + const struct qe_header *hdr; +#endif + + if (P4080_UCPatch) + return P4080_UCPatch; + + /* The firmware should be inside the device tree. */ + np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware"); + if (np) { + P4080_UCPatch = of_get_property(np, "fsl,firmware", NULL); + of_node_put(np); + if (P4080_UCPatch) + return P4080_UCPatch; + else + REPORT_ERROR(WARNING, E_NOT_FOUND, ("firmware node is incomplete")); + } + +#ifdef FMAN_READ_MICROCODE_FROM_NOR_FLASH + /* If not, then we have a legacy U-Boot. The firmware is in flash. */ + /* Only map enough to the get the core structure */ + P4080_UCPatch = ioremap(P4080_UCAddr, sizeof(struct qe_firmware)); + if (!P4080_UCPatch) { + REPORT_ERROR(MAJOR, E_NULL_POINTER, ("ioremap(%llx) returned NULL", (u64) P4080_UCAddr)); + return NULL; + } + /* Make sure it really is a QE Firmware blob */ + hdr = &P4080_UCPatch->header; + if (!hdr || + (hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || + (hdr->magic[2] != 'F')) { + REPORT_ERROR(MAJOR, E_NOT_FOUND, ("data at %llx is not a Fman microcode", (u64) P4080_UCAddr)); + return NULL; + } + + /* Now we call ioremap again, this time to pick up the whole blob. We never + * iounmap() the memory because we might reset the Fman at any time. + */ + /* TODO: ionumap() should be performed when unloading the driver */ + P4080_UCSize = sizeof(u32) * P4080_UCPatch->microcode[0].count; + iounmap((void *)P4080_UCPatch); + P4080_UCPatch = ioremap(P4080_UCAddr, P4080_UCSize); + if (!P4080_UCPatch) { + REPORT_ERROR(MAJOR, E_NULL_POINTER, ("ioremap(%llx) returned NULL", (u64) P4080_UCAddr)); + return NULL; + } +#else + /* Returning NULL here forces the reuse of the IRAM content */ + P4080_UCPatch = NULL; +#endif /* FMAN_READ_MICROCODE_FROM_NOR_FLASH */ + return P4080_UCPatch; +} + +static t_LnxWrpFmDev * ReadFmDevTreeNode (struct platform_device *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device_node *fm_node, *dev_node, *dpa_node; + struct of_device_id name; + struct resource res; + const uint32_t *uint32_prop; + int _errno=0, lenp; + static struct of_device_id dpa_eth_node_of_match[] = { + { .compatible = "fsl,dpa-ethernet", }, + { /* end of list */ }, + }; + + fm_node = of_node_get(of_dev->dev.of_node); + + uint32_prop = (uint32_t *)of_get_property(fm_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) failed", fm_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + if (*uint32_prop > INTG_MAX_NUM_OF_FM) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + return NULL; + } + p_LnxWrpFmDev = CreateFmDev(*uint32_prop); + if (!p_LnxWrpFmDev) { + REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG); + return NULL; + } + p_LnxWrpFmDev->dev = &of_dev->dev; + p_LnxWrpFmDev->id = *uint32_prop; + + /* Get the FM interrupt */ + p_LnxWrpFmDev->irq = of_irq_to_resource(fm_node, 0, NULL); + if (unlikely(p_LnxWrpFmDev->irq == /*NO_IRQ*/0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ)); + return NULL; + } + + /* Get the FM error interrupt */ + p_LnxWrpFmDev->err_irq = of_irq_to_resource(fm_node, 1, NULL); + /* TODO - un-comment it once there will be err_irq in the DTS */ +#if 0 + if (unlikely(p_LnxWrpFmDev->err_irq == /*NO_IRQ*/0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ)); + return NULL; + } +#endif /* 0 */ + + /* Get the FM address */ + _errno = of_address_to_resource(fm_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev->fmBaseAddr = 0; + p_LnxWrpFmDev->fmPhysBaseAddr = res.start; + p_LnxWrpFmDev->fmMemSize = res.end + 1 - res.start; + + uint32_prop = (uint32_t *)of_get_property(fm_node, "clock-frequency", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, clock-frequency) failed", fm_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmDev->fmDevSettings.param.fmClkFreq = (*uint32_prop + 500000)/1000000; /* In MHz, rounded */ + + /* Get the MURAM base address and size */ + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("muram") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "muram"); + if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-muram"); + for_each_child_of_node(fm_node, dev_node) { + if (likely(of_match_node(&name, dev_node) != NULL)) { + _errno = of_address_to_resource(dev_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev->fmMuramBaseAddr = 0; + p_LnxWrpFmDev->fmMuramPhysBaseAddr = res.start; + p_LnxWrpFmDev->fmMuramMemSize = res.end + 1 - res.start; + } + } + + /* Get the RTC base address and size */ + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("rtc") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "rtc"); + if (WARN_ON(strlen("fsl,fman-rtc") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-rtc"); + for_each_child_of_node(fm_node, dev_node) { + if (likely(of_match_node(&name, dev_node) != NULL)) { + _errno = of_address_to_resource(dev_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev->fmRtcBaseAddr = 0; + p_LnxWrpFmDev->fmRtcPhysBaseAddr = res.start; + p_LnxWrpFmDev->fmRtcMemSize = res.end + 1 - res.start; + } + } + + /* Get all PCD nodes */ + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("parser") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "parser"); + if (WARN_ON(strlen("fsl,fman-parser") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-parser"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->prsActive = TRUE; + + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("keygen") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "keygen"); + if (WARN_ON(strlen("fsl,fman-keygen") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-keygen"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->kgActive = TRUE; + + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("cc") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "cc"); + if (WARN_ON(strlen("fsl,fman-cc") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-cc"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->ccActive = TRUE; + + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("policer") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "policer"); + if (WARN_ON(strlen("fsl,fman-policer") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-policer"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->plcrActive = TRUE; + + if (p_LnxWrpFmDev->prsActive || p_LnxWrpFmDev->kgActive || + p_LnxWrpFmDev->ccActive || p_LnxWrpFmDev->plcrActive) + p_LnxWrpFmDev->pcdActive = TRUE; + + if (p_LnxWrpFmDev->pcdActive) + { + const char *str_prop = (char *)of_get_property(fm_node, "fsl,default-pcd", &lenp); + if (str_prop) { + if (strncmp(str_prop, "3-tuple", strlen("3-tuple")) == 0) + p_LnxWrpFmDev->defPcd = e_FM_PCD_3_TUPLE; + } + else + p_LnxWrpFmDev->defPcd = e_NO_PCD; + } + + of_node_put(fm_node); + + for_each_matching_node(dpa_node, dpa_eth_node_of_match) { + struct device_node *mac_node; + const phandle *phandle_prop; + + phandle_prop = (typeof(phandle_prop))of_get_property(dpa_node, "fsl,fman-mac", &lenp); + if (phandle_prop == NULL) + continue; + + if (WARN_ON(lenp != sizeof(phandle))) + return NULL; + + mac_node = of_find_node_by_phandle(*phandle_prop); + if (unlikely(mac_node == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_find_node_by_phandle() failed")); + return NULL; + } + + fm_node = of_get_parent(mac_node); + of_node_put(mac_node); + if (unlikely(fm_node == NULL)) { + REPORT_ERROR(MAJOR, E_NO_DEVICE, ("of_get_parent() = %d", _errno)); + return NULL; + } + + uint32_prop = (uint32_t *)of_get_property(fm_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + of_node_put(fm_node); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) failed", fm_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + of_node_put(fm_node); + + if (*uint32_prop == p_LnxWrpFmDev->id) { + phandle_prop = (typeof(phandle_prop))of_get_property(dpa_node, "fsl,qman-channel", &lenp); + if (unlikely(phandle_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, fsl,qman-channel) failed", dpa_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(phandle))) + return NULL; + + dev_node = of_find_node_by_phandle(*phandle_prop); + if (unlikely(dev_node == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_find_node_by_phandle() failed")); + return NULL; + } + + uint32_prop = (typeof(uint32_prop))of_get_property(dev_node, "fsl,qman-channel-id", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, fsl,qman-channel-id) failed", dev_node->full_name)); + of_node_put(dev_node); + return NULL; + } + of_node_put(dev_node); + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmDev->hcCh = *uint32_prop; + break; + } + } + + p_LnxWrpFmDev->active = TRUE; + + return p_LnxWrpFmDev; +} + +static void LnxwrpFmDevExceptionsCb(t_Handle h_App, e_FmExceptions exception) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + DBG(INFO, ("got fm exception %d", exception)); + + /* do nothing */ + UNUSED(exception); +} + +static void LnxwrpFmDevBusErrorCb(t_Handle h_App, + e_FmPortType portType, + uint8_t portId, + uint64_t addr, + uint8_t tnum, + uint16_t liodn) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + /* do nothing */ + UNUSED(portType);UNUSED(portId);UNUSED(addr);UNUSED(tnum);UNUSED(liodn); +} + +static t_Error ConfigureFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + struct resource *dev_res; + int _errno; + + if (!p_LnxWrpFmDev->active) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!")); + +#ifndef MODULE + _errno = can_request_irq(p_LnxWrpFmDev->irq, 0); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno)); +#endif + _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, fm_irq, 0, "fman", p_LnxWrpFmDev); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->irq, _errno)); + + if (p_LnxWrpFmDev->err_irq != 0) { +#ifndef MODULE + _errno = can_request_irq(p_LnxWrpFmDev->err_irq, 0); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno)); +#endif + _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, fm_err_irq, IRQF_SHARED, "fman-err", p_LnxWrpFmDev); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->err_irq, _errno)); + } + + p_LnxWrpFmDev->res = devm_request_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize, "fman"); + if (unlikely(p_LnxWrpFmDev->res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_mem_region() failed")); + + p_LnxWrpFmDev->fmBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize)); + if (unlikely(p_LnxWrpFmDev->fmBaseAddr == 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); + + if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmBaseAddr, (uint64_t)p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM memory map")); + + dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize, "fman-muram"); + if (unlikely(dev_res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); + + p_LnxWrpFmDev->fmMuramBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)); + if (unlikely(p_LnxWrpFmDev->fmMuramBaseAddr == 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); + + if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmMuramBaseAddr, (uint64_t)p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM MURAM memory map")); + + if (p_LnxWrpFmDev->fmRtcPhysBaseAddr) + { + dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-rtc"); + if (unlikely(dev_res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); + + p_LnxWrpFmDev->fmRtcBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize)); + if (unlikely(p_LnxWrpFmDev->fmRtcBaseAddr == 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); + + if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmRtcBaseAddr, (uint64_t)p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC memory map")); + } + + p_LnxWrpFmDev->fmDevSettings.param.baseAddr = p_LnxWrpFmDev->fmBaseAddr; + p_LnxWrpFmDev->fmDevSettings.param.fmId = p_LnxWrpFmDev->id; + p_LnxWrpFmDev->fmDevSettings.param.irq = NO_IRQ; + p_LnxWrpFmDev->fmDevSettings.param.errIrq = NO_IRQ; + p_LnxWrpFmDev->fmDevSettings.param.f_Exception = LnxwrpFmDevExceptionsCb; + p_LnxWrpFmDev->fmDevSettings.param.f_BusError = LnxwrpFmDevBusErrorCb; + p_LnxWrpFmDev->fmDevSettings.param.h_App = p_LnxWrpFmDev; + + return FillRestFmInfo(p_LnxWrpFmDev); +} + +static t_Error InitFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + const struct qe_firmware *fw; + + if (!p_LnxWrpFmDev->active) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!")); + + if ((p_LnxWrpFmDev->h_MuramDev = FM_MURAM_ConfigAndInit(p_LnxWrpFmDev->fmMuramBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)) == NULL) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM!")); + + /* Loading the fman-controller code */ + fw = FindFmanMicrocode(); + + if (!fw) { +#ifdef FMAN_READ_MICROCODE_FROM_NOR_FLASH + /* We already reported an error, so just return NULL*/ + return ERROR_CODE(E_NULL_POINTER); +#else + /* this forces the reuse of the current IRAM content */ + p_LnxWrpFmDev->fmDevSettings.param.firmware.size = 0; + p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = NULL; +#endif + } else { + p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = + (void *) fw + fw->microcode[0].code_offset; + p_LnxWrpFmDev->fmDevSettings.param.firmware.size = + sizeof(u32) * fw->microcode[0].count; + DBG(INFO, ("Loading fman-controller code version %d.%d.%d", + fw->microcode[0].major, + fw->microcode[0].minor, + fw->microcode[0].revision)); + } + + p_LnxWrpFmDev->fmDevSettings.param.h_FmMuram = p_LnxWrpFmDev->h_MuramDev; + + if ((p_LnxWrpFmDev->h_Dev = FM_Config(&p_LnxWrpFmDev->fmDevSettings.param)) == NULL) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM")); + + if (FM_ConfigMaxNumOfOpenDmas(p_LnxWrpFmDev->h_Dev,BMI_MAX_NUM_OF_DMAS) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); + + if (FM_ConfigResetOnInit(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); + +#ifdef CONFIG_FMAN_P1023 + if (FM_ConfigDmaAidOverride(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); +#endif + + /* Use the entire amount of TNUMS, maybe performance will improve... + for OPEN DMAs - are all by default = 32 and fifosize = MURAM*3/4 and + the rest of it is for PCD */ + FM_ConfigTotalNumOfTasks(p_LnxWrpFmDev->h_Dev, BMI_MAX_NUM_OF_TASKS); + +#if defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) && defined(CONFIG_FMAN_P3040_P4080_P5020) + /* Enable 14g w/ jumbo frames following HW suggestion. */ + FM_ConfigTotalFifoSize(p_LnxWrpFmDev->h_Dev, 128*KILOBYTE); +#endif + + if (FM_Init(p_LnxWrpFmDev->h_Dev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); + + if (p_LnxWrpFmDev->err_irq == 0) { + FM_SetException(p_LnxWrpFmDev->h_Dev, e_FM_EX_DMA_BUS_ERROR,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_READ_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SYSTEM_WRITE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_FM_WRITE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_STALL_ON_TASKS , FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_DOUBLE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_IRAM_ECC,FALSE); + /* TODO: FmDisableRamsEcc assert for ramsEccOwners. + * FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_MURAM_ECC,FALSE);*/ + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DOUBLE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_LIST_RAM_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_PIPELINE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STATISTICS_RAM_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_SINGLE_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_SINGLE_ECC, FALSE); + } + + if (p_LnxWrpFmDev->fmRtcBaseAddr) + { + t_FmRtcParams fmRtcParam; + + memset(&fmRtcParam, 0, sizeof(fmRtcParam)); + fmRtcParam.h_App = p_LnxWrpFmDev; + fmRtcParam.h_Fm = p_LnxWrpFmDev->h_Dev; + fmRtcParam.baseAddress = p_LnxWrpFmDev->fmRtcBaseAddr; + + if(!(p_LnxWrpFmDev->h_RtcDev = FM_RTC_Config(&fmRtcParam))) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-RTC")); + + if (FM_RTC_ConfigPeriod(p_LnxWrpFmDev->h_RtcDev, 10) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC")); + + if (FM_RTC_Init(p_LnxWrpFmDev->h_RtcDev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC")); + } + + return E_OK; +} + +/* TODO: to be moved back here */ +extern void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev); + +static void FreeFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + if (!p_LnxWrpFmDev->active) + return; + + FreeFmPcdDev(p_LnxWrpFmDev); + + if (p_LnxWrpFmDev->h_RtcDev) + FM_RTC_Free(p_LnxWrpFmDev->h_RtcDev); + + if (p_LnxWrpFmDev->h_Dev) + FM_Free(p_LnxWrpFmDev->h_Dev); + + if (p_LnxWrpFmDev->h_MuramDev) + FM_MURAM_Free(p_LnxWrpFmDev->h_MuramDev); + + if (p_LnxWrpFmDev->fmRtcBaseAddr) + { + SYS_UnregisterIoMap(p_LnxWrpFmDev->fmRtcBaseAddr); + devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmRtcBaseAddr)); + __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize); + } + SYS_UnregisterIoMap(p_LnxWrpFmDev->fmMuramBaseAddr); + devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmMuramBaseAddr)); + __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize); + SYS_UnregisterIoMap(p_LnxWrpFmDev->fmBaseAddr); + devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr)); + devm_release_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize); + if (p_LnxWrpFmDev->err_irq != 0) { + devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, p_LnxWrpFmDev); + } + + devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, p_LnxWrpFmDev); +} + +/* FMan character device file operations */ +extern struct file_operations fm_fops; + +static int fm_probe(struct platform_device *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + + if ((p_LnxWrpFmDev = ReadFmDevTreeNode(of_dev)) == NULL) + return -EIO; + if (ConfigureFmDev(p_LnxWrpFmDev) != E_OK) + return -EIO; + if (InitFmDev(p_LnxWrpFmDev) != E_OK) + return -EIO; + + Sprint (p_LnxWrpFmDev->name, "%s%d", DEV_FM_NAME, p_LnxWrpFmDev->id); + + /* Register to the /dev for IOCTL API */ + /* Register dynamically a new major number for the character device: */ + if ((p_LnxWrpFmDev->major = register_chrdev(0, p_LnxWrpFmDev->name, &fm_fops)) <= 0) { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Failed to allocate a major number for device \"%s\"", p_LnxWrpFmDev->name)); + return -EIO; + } + + /* Creating classes for FM */ + DBG(TRACE ,("class_create fm_class")); + p_LnxWrpFmDev->fm_class = class_create(THIS_MODULE, p_LnxWrpFmDev->name); + if (IS_ERR(p_LnxWrpFmDev->fm_class)) { + unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("class_create error fm_class")); + return -EIO; + } + + device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE), NULL, + "fm%d", p_LnxWrpFmDev->id); + device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE), NULL, + "fm%d-pcd", p_LnxWrpFmDev->id); + dev_set_drvdata(p_LnxWrpFmDev->dev, p_LnxWrpFmDev); + + /* create sysfs entries for stats and regs */ + if ( fm_sysfs_create(p_LnxWrpFmDev->dev) !=0 ) + { + FreeFmDev(p_LnxWrpFmDev); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unable to create sysfs entry - fm!!!")); + return -EIO; + } + + DBG(TRACE, ("FM%d probed", p_LnxWrpFmDev->id)); + +#if defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) + /* Precalculate resources for FMAN based on number of + * FMan ports available + */ + if(fm_set_active_fman_ports(of_dev, p_LnxWrpFmDev)!= 0) + return -EIO; + +#if defined(CONFIG_FMAN_P3040_P4080_P5020) + /* 128K MURAM for p3,p4 and p5 */ + if(fm_precalculate_fifosizes( + p_LnxWrpFmDev, + 128*KILOBYTE) + != 0) + return -EIO; +#else + /* for all other platforms: MURAM Space for fifosize=3/4 * MURAM_SIZE*/ + if(fm_precalculate_fifosizes( + p_LnxWrpFmDev, + CEIL_DIV((3*FM_MURAM_SIZE-1),4)) + != 0) + return -EIO; +#endif + if(fm_precalculate_open_dma( + p_LnxWrpFmDev, + BMI_MAX_NUM_OF_DMAS, /* max open dmas:dpaa_integration_ext.h */ + FM_DEFAULT_TX10G_OPENDMA, /* default TX 10g open dmas */ + FM_DEFAULT_RX10G_OPENDMA, /* default RX 10g open dmas */ + FM_10G_OPENDMA_MIN_TRESHOLD,/* TX 10g minimum treshold */ + FM_10G_OPENDMA_MIN_TRESHOLD)/* RX 10g minimum treshold */ + != 0) + return -EIO; + if(fm_precalculate_tnums( + p_LnxWrpFmDev, + BMI_MAX_NUM_OF_TASKS) /* max TNUMS: dpa integration file. */ + != 0) + return -EIO; +#endif + + return 0; +} + +static int fm_remove(struct platform_device *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device *dev; + + dev = &of_dev->dev; + p_LnxWrpFmDev = dev_get_drvdata(dev); + + fm_sysfs_destroy(dev); + + DBG(TRACE, ("destroy fm_class")); + device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE)); + device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE)); + class_destroy(p_LnxWrpFmDev->fm_class); + + /* Destroy chardev */ + unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name); + + FreeFmDev(p_LnxWrpFmDev); + + DestroyFmDev(p_LnxWrpFmDev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct of_device_id fm_match[] = { + { + .compatible = "fsl,fman" + }, + {} +}; +#ifndef MODULE +MODULE_DEVICE_TABLE(of, fm_match); +#endif /* !MODULE */ + +static struct platform_driver fm_driver = { + .driver = { + .name = "fsl-fman", + .of_match_table = fm_match, + .owner = THIS_MODULE, + }, + .probe = fm_probe, + .remove = fm_remove, +}; + +t_Handle LNXWRP_FM_Init(void) +{ + memset(&lnxWrpFm, 0, sizeof(lnxWrpFm)); + mutex_init(&lnxwrp_mutex); + + /* Register to the DTB for basic FM API */ + platform_driver_register(&fm_driver); + + return &lnxWrpFm; +} + +t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm) +{ + platform_driver_unregister(&fm_driver); + mutex_destroy(&lnxwrp_mutex); + + return E_OK; +} + + +struct fm * fm_bind(struct device *fm_dev) +{ + return (struct fm *)(dev_get_drvdata(get_device(fm_dev))); +} +EXPORT_SYMBOL(fm_bind); + +void fm_unbind(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + put_device(p_LnxWrpFmDev->dev); +} +EXPORT_SYMBOL(fm_unbind); + +struct resource * fm_get_mem_region(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + return p_LnxWrpFmDev->res; +} +EXPORT_SYMBOL(fm_get_mem_region); + +void * fm_get_handle(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + return (void *)p_LnxWrpFmDev->h_Dev; +} +EXPORT_SYMBOL(fm_get_handle); + +void * fm_get_rtc_handle(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + return (void *)p_LnxWrpFmDev->h_RtcDev; +} +EXPORT_SYMBOL(fm_get_rtc_handle); + +struct fm_port * fm_port_bind (struct device *fm_port_dev) +{ + return (struct fm_port *)(dev_get_drvdata(get_device(fm_port_dev))); +} +EXPORT_SYMBOL(fm_port_bind); + +void fm_port_unbind(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + put_device(p_LnxWrpFmPortDev->dev); +} +EXPORT_SYMBOL(fm_port_unbind); + +void * fm_port_get_handle(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + return (void *)p_LnxWrpFmPortDev->h_Dev; +} +EXPORT_SYMBOL(fm_port_get_handle); + +void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; + + *base_addr = p_LnxWrpFmPortDev->settings.param.baseAddr; +} +EXPORT_SYMBOL(fm_port_get_base_addr); + +void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + p_LnxWrpFmPortDev->pcd_owner_params.cba = params->cba; + p_LnxWrpFmPortDev->pcd_owner_params.cbf = params->cbf; + p_LnxWrpFmPortDev->pcd_owner_params.dev = params->dev; +} +EXPORT_SYMBOL(fm_port_pcd_bind); + +int fm_get_tx_port_channel(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + return p_LnxWrpFmPortDev->txCh; +} +EXPORT_SYMBOL(fm_get_tx_port_channel); + +int fm_port_enable (struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev); + + return 0; +} +EXPORT_SYMBOL(fm_port_enable); + +void fm_port_disable(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev); +} +EXPORT_SYMBOL(fm_port_disable); + +void fm_mutex_lock(void) +{ + mutex_lock(&lnxwrp_mutex); +} +EXPORT_SYMBOL(fm_mutex_lock); + +void fm_mutex_unlock(void) +{ + mutex_unlock(&lnxwrp_mutex); +} +EXPORT_SYMBOL(fm_mutex_unlock); + +static t_Handle h_FmLnxWrp; + +static int __init __cold fm_load (void) +{ + if ((h_FmLnxWrp = LNXWRP_FM_Init()) == NULL) + { + printk("Failed to init FM wrapper!\n"); + return -ENODEV; + } + + printk (KERN_INFO "Freescale FM module ("__DATE__ ":"__TIME__")\n"); + + return 0; +} + +static void __exit __cold fm_unload (void) +{ + if (h_FmLnxWrp) + LNXWRP_FM_Free(h_FmLnxWrp); +} + +module_init (fm_load); +module_exit (fm_unload); --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_ioctls_fm_compat.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_ioctls_fm_compat.h @@ -0,0 +1,379 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_ioctls_fm_compat.h + + @Description FM PCD compat structures definition. + +*/ + +#ifndef __FM_COMPAT_IOCTLS_H +#define __FM_COMPAT_IOCTLS_H + +#include + +#define COMPAT_K_TO_US 0 /* copy from Kernel to User */ +#define COMPAT_US_TO_K 1 /* copy from User to Kernel */ + +#define COMPAT_COPY_K2US(dest, src, type) compat_copy_##type(src, dest, 0) +#define COMPAT_COPY_US2K(dest, src, type) compat_copy_##type(dest, src, 1) + +/* maping kernel pointers w/ UserSpace id's { */ +/* Because compat_ptr(ptr_to_compat(X)) != X, this way we cannot exchange pointers + back and forth (US - KS). compat_ptr is a cast and pointers are broken. */ +#define COMPAT_PTR2ID_ARRAY_MAX (256+1) /* first location is not used */ +#define COMPAT_PTR2ID_WATERMARK 0xface0000 +#define COMPAT_PTR2ID_WM_MASK 0xffff0000 + +void compat_del_ptr2id(void *p); +compat_uptr_t compat_add_ptr2id(void *p); +compat_uptr_t compat_get_ptr2id(void *p); +void *compat_get_id2ptr(compat_uptr_t comp); +/* } maping kernel pointers w/ UserSpace id's */ + +/* pcd compat structures { */ +typedef struct ioc_compat_fm_pcd_cc_node_remove_key_params_t { + compat_uptr_t id; + uint8_t key_indx; +} ioc_compat_fm_pcd_cc_node_remove_key_params_t; + +typedef union ioc_compat_fm_pcd_plcr_next_engine_params_u { + ioc_fm_pcd_done_action action; + compat_uptr_t p_profile; + compat_uptr_t p_direct_scheme; +} ioc_compat_fm_pcd_plcr_next_engine_params_u; + +typedef struct ioc_compat_fm_pcd_plcr_profile_params_t { + bool modify; + union { + struct { + ioc_fm_pcd_profile_type_selection profile_type; + compat_uptr_t p_port; + uint16_t relative_profile_id; + } new_params; + compat_uptr_t p_profile; + } profile_select; + ioc_fm_pcd_plcr_algorithm_selection alg_selection; + ioc_fm_pcd_plcr_color_mode color_mode; + + union { + ioc_fm_pcd_plcr_color dflt_color; + ioc_fm_pcd_plcr_color override; + } color; + + ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param; + + ioc_fm_pcd_engine next_engine_on_green; + ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_green; + + ioc_fm_pcd_engine next_engine_on_yellow; + ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_yellow; + + ioc_fm_pcd_engine next_engine_on_red; + ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_red; + + bool trap_profile_on_flow_A; + bool trap_profile_on_flow_B; + bool trap_profile_on_flow_C; + compat_uptr_t id; +} ioc_compat_fm_pcd_plcr_profile_params_t; + +typedef struct ioc_compat_fm_obj_t { + compat_uptr_t obj; +} ioc_compat_fm_obj_t; + +typedef struct ioc_compat_fm_pcd_kg_scheme_select_t { + bool direct; + compat_uptr_t scheme_id; +} ioc_compat_fm_pcd_kg_scheme_select_t; + +typedef struct ioc_compat_fm_pcd_port_schemes_params_t { + uint8_t num_of_schemes; + compat_uptr_t schemes_ids [IOC_FM_PCD_KG_NUM_OF_SCHEMES]; +} ioc_compat_fm_pcd_port_schemes_params_t; + +typedef struct ioc_compat_fm_pcd_net_env_params_t { + uint8_t num_of_distinction_units; + ioc_fm_pcd_distinction_unit_t units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* same structure*/ + compat_uptr_t id; +} ioc_compat_fm_pcd_net_env_params_t; + +typedef struct ioc_compat_fm_pcd_prs_sw_params_t { + bool override; + uint32_t size; + uint16_t base; + compat_uptr_t p_code; + uint32_t sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS]; + uint8_t num_of_labels; + ioc_fm_pcd_prs_label_params_t labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS]; +} ioc_compat_fm_pcd_prs_sw_params_t; + +typedef struct ioc_compat_fm_pcd_cc_next_kg_params_t { + bool override_fqid; + uint32_t new_fqid; + compat_uptr_t p_direct_scheme; +} ioc_compat_fm_pcd_cc_next_kg_params_t; + +typedef struct ioc_compat_fm_pcd_cc_next_cc_params_t { + compat_uptr_t cc_node_id; +} ioc_compat_fm_pcd_cc_next_cc_params_t; + +typedef struct ioc_compat_fm_pcd_cc_next_engine_params_t { + ioc_fm_pcd_engine next_engine; + union { + ioc_compat_fm_pcd_cc_next_cc_params_t cc_params; /**< compat structure*/ + ioc_fm_pcd_cc_next_plcr_params_t plcr_params; /**< same structure*/ + ioc_fm_pcd_cc_next_enqueue_params_t enqueue_params; /**< same structure*/ + ioc_compat_fm_pcd_cc_next_kg_params_t kg_params; /**< compat structure*/ + } params; +#ifdef FM_PCD_CC_MANIP + compat_uptr_t p_manip; +#endif +} ioc_compat_fm_pcd_cc_next_engine_params_t; + + +typedef struct ioc_compat_fm_pcd_cc_grp_params_t { + uint8_t num_of_distinction_units; /**< up to 4 */ + uint8_t unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS]; + /**< Indexes of the units as defined in + FM_PCD_SetNetEnvCharacteristics */ + ioc_compat_fm_pcd_cc_next_engine_params_t next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP]; + /**< Max size is 16 - if only one group used */ +} ioc_compat_fm_pcd_cc_grp_params_t; + +typedef struct ioc_compat_fm_pcd_cc_tree_params_t { + compat_uptr_t net_env_id; + uint8_t num_of_groups; + ioc_compat_fm_pcd_cc_grp_params_t fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS]; + compat_uptr_t id; +} ioc_compat_fm_pcd_cc_tree_params_t; + +typedef struct ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t { + compat_uptr_t id; + uint8_t grp_indx; + uint8_t indx; + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; +} ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t; + +typedef struct ioc_compat_fm_pcd_cc_key_params_t { + compat_uptr_t p_key; + compat_uptr_t p_mask; + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; /**< compat structure*/ +} ioc_compat_fm_pcd_cc_key_params_t; + +typedef struct ioc_compat_keys_params_t { + uint8_t num_of_keys; + uint8_t key_size; + ioc_compat_fm_pcd_cc_key_params_t key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS]; /**< compat structure*/ + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; /**< compat structure*/ +} ioc_compat_keys_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_params_t { + ioc_fm_pcd_extract_entry_t extract_cc_params; /**< same structure*/ + ioc_compat_keys_params_t keys_params; /**< compat structure*/ + compat_uptr_t id; +} ioc_compat_fm_pcd_cc_node_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_modify_key_params_t { + compat_uptr_t id; + uint8_t key_indx; + uint8_t key_size; + compat_uptr_t p_key; + compat_uptr_t p_mask; +} ioc_compat_fm_pcd_cc_node_modify_key_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t { + compat_uptr_t id; + uint8_t key_indx; + uint8_t key_size; + ioc_compat_fm_pcd_cc_key_params_t key_params; +} ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t; + +typedef struct ioc_compat_fm_port_pcd_plcr_params_t { + compat_uptr_t plcr_profile_id; +} ioc_compat_fm_port_pcd_plcr_params_t; + +typedef struct ioc_compat_fm_port_pcd_cc_params_t { + compat_uptr_t cc_tree_id; +} ioc_compat_fm_port_pcd_cc_params_t; + +typedef struct ioc_compat_fm_port_pcd_kg_params_t { + uint8_t num_of_schemes; + compat_uptr_t schemes_ids[IOC_FM_PCD_KG_NUM_OF_SCHEMES]; + bool direct_scheme; + compat_uptr_t direct_scheme_id; +} ioc_compat_fm_port_pcd_kg_params_t; + +typedef struct ioc_compat_fm_port_pcd_params_t { + ioc_fm_port_pcd_support pcd_support; + compat_uptr_t net_env_id; + compat_uptr_t p_prs_params; + compat_uptr_t p_cc_params; + compat_uptr_t p_kg_params; + compat_uptr_t p_plcr_params; +} ioc_compat_fm_port_pcd_params_t; + +typedef struct ioc_compat_fm_pcd_kg_cc_t { + compat_uptr_t tree_id; + uint8_t grp_id; + bool plcr_next; + bool bypass_plcr_profile_generation; + ioc_fm_pcd_kg_plcr_profile_t plcr_profile; +} ioc_compat_fm_pcd_kg_cc_t; + +typedef struct ioc_compat_fm_pcd_kg_scheme_params_t { + bool modify; + union + { + uint8_t relative_scheme_id; + compat_uptr_t scheme_id; + } scm_id; + bool always_direct; + struct + { + compat_uptr_t net_env_id; + uint8_t num_of_distinction_units; + uint8_t unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + } netEnvParams; + bool use_hash; + ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params; + bool bypass_fqid_generation; + uint32_t base_fqid; + uint8_t numOfUsedExtractedOrs; + ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS]; + ioc_fm_pcd_engine next_engine; + union{ + ioc_fm_pcd_done_action done_action; + ioc_fm_pcd_kg_plcr_profile_t plcr_profile; + ioc_compat_fm_pcd_kg_cc_t cc; + } kg_next_engine_params; + ioc_fm_pcd_kg_scheme_counter_t scheme_counter; + compat_uptr_t id; +} ioc_compat_fm_pcd_kg_scheme_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t { + compat_uptr_t id; + uint8_t key_indx; + uint8_t key_size; + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; +} ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t; +/* } pcd compat structures */ + +/* pcd compat functions { */ +void compat_copy_fm_pcd_plcr_profile( + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param, + ioc_fm_pcd_plcr_profile_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_key( + ioc_compat_fm_pcd_cc_key_params_t *compat_param, + ioc_fm_pcd_cc_key_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine( + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node_modify_next_engine( + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param, + uint8_t compat); + +void compat_fm_pcd_cc_tree_modify_next_engine( + ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_grp( + ioc_compat_fm_pcd_cc_grp_params_t *compat_param, + ioc_fm_pcd_cc_grp_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_tree( + ioc_compat_fm_pcd_cc_tree_params_t *compat_param, + ioc_fm_pcd_cc_tree_params_t *param, + uint8_t compat); + +void compat_fm_pcd_prs_sw( + ioc_compat_fm_pcd_prs_sw_params_t *compat_param, + ioc_fm_pcd_prs_sw_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_kg_scheme( + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param, + ioc_fm_pcd_kg_scheme_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_kg_scheme_select( + ioc_compat_fm_pcd_kg_scheme_select_t *compat_param, + ioc_fm_pcd_kg_scheme_select_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_kg_schemes_params( + ioc_compat_fm_pcd_port_schemes_params_t *compat_param, + ioc_fm_pcd_port_schemes_params_t *param, + uint8_t compat); + +void compat_copy_fm_port_pcd_kg( + ioc_compat_fm_port_pcd_kg_params_t *compat_param, + ioc_fm_port_pcd_kg_params_t *param, + uint8_t compat); + +void compat_copy_fm_port_pcd( + ioc_compat_fm_port_pcd_params_t *compat_param, + ioc_fm_port_pcd_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_net_env( + ioc_compat_fm_pcd_net_env_params_t *compat_param, + ioc_fm_pcd_net_env_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node_modify_key( + ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_params_t *param, + uint8_t compat); + +void compat_copy_keys( + ioc_compat_keys_params_t *compat_param, + ioc_keys_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node( + ioc_compat_fm_pcd_cc_node_params_t *compat_param, + ioc_fm_pcd_cc_node_params_t *param, + uint8_t compat); + +/* } pcd compat functions */ +#endif --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_resources.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_resources.h @@ -0,0 +1,111 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_resources.h + + @Description FMD wrapper resource allocation functions. + +*/ + +#ifndef LNXWRP_RESOURCES_H_ +#define LNXWRP_RESOURCES_H_ + +#include "lnxwrp_fm.h" + +#define ROUND(X) ((2*(X)+1)/2) +#define CEIL(X) ((X)+1) +/* #define ROUND_DIV(X, Y) (((X)+(Y)/2)/(Y)) */ +#define ROUND_DIV(X, Y) ((2*(X)+(Y))/(2*(Y))) +#define CEIL_DIV(X, Y) (((X)+(Y)-1)/(Y)) + +/* used for resource calculus */ +#define DPDE_1G 2 /* DQDP 1g - from LLD: + DEFAULT_PORT_txFifoDeqPipelineDepth_1G */ +#define DPDE_10G 8 /* DQDP 10g - from LLD: + DEFAULT_PORT_txFifoDeqPipelineDepth_10G */ + +int fm_set_active_fman_ports(struct platform_device *of_dev, + t_LnxWrpFmDev *p_LnxWrpFmDev); + +/* Calculate the fifosize based on MURAM allocation, number of ports, dpde + * value and s/g software support (! Kernel does not suport s/g). + * + * Algorithm summary: + * - Calculate the the minimum fifosize required for every type of port + * (TX,RX for 1G, 2.5G and 10G). + * - Set TX the minimum fifosize required. + * - Distribute the remaining buffers (after all TX were set) to RX ports + * based on: + * 1G RX = Remaining_buffers * 1/(1+2.5+10) + * 2.5G RX = Remaining_buffers * 2.5/(1+2.5+10) + * 10G RX = Remaining_buffers * 10/(1+2.5+10) + * - if the RX is smaller than the minimum required, then set the minimum + * required + * - In the end distribuite the leftovers if there are any (due to + * unprecise calculus) or if over allocation cat some buffers from all RX + * ports w/o pass over minimum required treshold, but if there must be + * pass the treshold in order to cat the over allocation ,then this + * configuration can not be set - KERN_ALERT. +*/ +int fm_precalculate_fifosizes(t_LnxWrpFmDev *p_LnxWrpFmDev, + int muram_fifo_size); + +int fm_set_precalculate_fifosize(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); + +/* Compute FMan open DMA based on total number of open DMAs and + * number of available fman ports. + * + * By default 10g ports are set to input parameters. The other ports + * tries to keep the proportion rx=2tx open dmas or tresholds. + * + * If leftovers, then those will be set as shared. + * + * If after computing overflow appears, then it decrements open dma + * for all ports w/o cross the tresholds. If the tresholds are meet + * and is still overflow, then it returns error. +*/ +int fm_precalculate_open_dma(t_LnxWrpFmDev *p_LnxWrpFmDev, + int max_fm_open_dma, + int default_tx_10g_dmas, + int default_rx_10g_dmas, + int min_tx_10g_treshold, int min_rx_10g_treshold); + +int fm_set_precalculate_open_dma(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); + +/* Compute FMan tnums based on available tnums and number of ports. + * Set defaults (minim tresholds) and then distribute leftovers.*/ +int fm_precalculate_tnums(t_LnxWrpFmDev *p_LnxWrpFmDev, int max_fm_tnums); + +int fm_set_precalculate_tnums(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); + +#endif /* LNXWRP_RESOURCES_H_ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_ioctls_fm.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_ioctls_fm.c @@ -0,0 +1,2648 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_ioctls_fm.c + + @Author Shlomi Gridish + + @Description FM Linux wrapper functions. + +*/ + +/* Linux Headers ------------------- */ +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_COMPAT) +#include +#endif + +#include "part_ext.h" +#include "fm_ioctls.h" +#include "fm_pcd_ioctls.h" +#include "fm_port_ioctls.h" + +#if defined(CONFIG_COMPAT) +#include "lnxwrp_ioctls_fm_compat.h" +#endif + +#include "lnxwrp_fm.h" + +#define CMP_IOC_DEFINE(def) (IOC_##def != def) + +/* fm_pcd_ioctls.h === fm_pcd_ext.h assertions */ +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_HDRS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_SCHEMES) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) +#error Error: please synchronize IOC_ defines! +#endif + +/* please check for this one in fm_common.h: */ +#define FM_PCD_MAX_NUM_OF_OPTIONS(clsPlanEntries) ((clsPlanEntries==256)? 8:((clsPlanEntries==128)? 7: ((clsPlanEntries==64)? 6: ((clsPlanEntries==32)? 5:0)))) +#if (IOC_FM_PCD_MAX_NUM_OF_OPTIONS != FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)) +#error Error: please synchronize IOC_ defines! +#endif +#undef FM_PCD_MAX_NUM_OF_OPTIONS + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_GENERIC_REGS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CLS_PLANS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_EXTRACT_MASKS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_DEFAULT_GROUPS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_LABELS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_NODES) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_TREES) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_GROUPS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_UNITS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_KEYS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_SIZE_OF_KEY) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP) +#error Error: please synchronize IOC_ defines! +#endif + +/* net_ioctls.h === net_ext.h assertions */ +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPoE_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ETH_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv4_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv6_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ICMP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IGMP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_TCP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_DCCP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPHC_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv2_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_VLAN_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_NLPID_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SNAP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS) +#warning Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ARP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_RFC2684_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_GRE_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MINENCAP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MACSEC_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +/* fm_ioctls.h === fm_ext.h assertions */ +#if CMP_IOC_DEFINE(FM_MAX_NUM_OF_VALID_PORTS) +#error Error: please synchronize IOC_ defines! +#endif + +/* fm_port_ioctls.h === dpaa_integrations_ext.h assertions */ +#if CMP_IOC_DEFINE(FM_PORT_NUM_OF_CONGESTION_GRPS) +#error Error: please synchronize IOC_ defines! +#endif + +#define ASSERT_IOC_NET_ENUM(def) ASSERT_COND((unsigned long)e_IOC_NET_##def == (unsigned long)def) + +static void LnxwrpAssertions(void) +{ + /* sampling checks */ + ASSERT_IOC_NET_ENUM(HEADER_TYPE_MACSEC); + ASSERT_IOC_NET_ENUM(HEADER_TYPE_PPP); + ASSERT_IOC_NET_ENUM(MAX_HEADER_TYPE_COUNT); + ASSERT_COND((unsigned long)e_IOC_FM_PORT_TYPE_DUMMY == (unsigned long)e_FM_PORT_TYPE_DUMMY); + ASSERT_COND((unsigned long)e_IOC_FM_EX_MURAM_ECC == (unsigned long)e_FM_EX_MURAM_ECC); + ASSERT_COND((unsigned long)e_IOC_FM_COUNTERS_SEMAPHOR_SYNC_REJECT == (unsigned long)e_FM_COUNTERS_SEMAPHOR_SYNC_REJECT); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES == (unsigned long)e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC == (unsigned long)e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS == (unsigned long)e_FM_PCD_PRS); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FULL_FIELD == (unsigned long)e_FM_PCD_EXTRACT_FULL_FIELD); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID == (unsigned long)e_FM_PCD_EXTRACT_FROM_FLOW_ID); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO == (unsigned long)e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_DFLT_ILLEGAL == (unsigned long)e_FM_PCD_KG_DFLT_ILLEGAL); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA == (unsigned long)e_FM_PCD_KG_GENERIC_NOT_FROM_DATA); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_HDR_INDEX_3 == (unsigned long)e_FM_PCD_HDR_INDEX_3); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_SHARED == (unsigned long)e_FM_PCD_PLCR_SHARED); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_RFC_4115 == (unsigned long)e_FM_PCD_PLCR_RFC_4115); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_COLOR_AWARE == (unsigned long)e_FM_PCD_PLCR_COLOR_AWARE); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_OVERRIDE == (unsigned long)e_FM_PCD_PLCR_OVERRIDE); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_FULL_FRM_LEN); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PACKET_MODE == (unsigned long)e_FM_PCD_PLCR_PACKET_MODE); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_DROP_FRAME == (unsigned long)e_FM_PCD_DROP_FRAME); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER == (unsigned long)e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP == (unsigned long)e_FM_PCD_ACTION_INDEXED_LOOKUP); + ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR); +#ifdef FM_CAPWAP_SUPPORT + ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR); +#endif + ASSERT_COND((unsigned long)e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_PORT_COUNTERS_DEQ_CONFIRM); + ASSERT_COND((unsigned long)e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 == (unsigned long)e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8); +} + +static t_Error LnxwrpFmPcdIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat) +{ + t_Error err = E_READ_FAILED; + + /* can be moved from here */ + LnxwrpAssertions(); + + switch (cmd) + { +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_PRS_LOAD_SW_COMPAT: +#endif + case FM_PCD_IOC_PRS_LOAD_SW: + { + ioc_fm_pcd_prs_sw_params_t *param; + uint8_t *p_code; + + ASSERT_COND(sizeof(ioc_fm_pcd_prs_sw_params_t) == sizeof(t_FmPcdPrsSwParams)); + + param = (ioc_fm_pcd_prs_sw_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_prs_sw_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_prs_sw_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_prs_sw_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_prs_sw_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_prs_sw_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_prs_sw_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_fm_pcd_prs_sw(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_prs_sw_params_t *)arg, + sizeof(ioc_fm_pcd_prs_sw_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + p_code = (uint8_t *) XX_Malloc(param->size); + if (!p_code) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + if (copy_from_user(p_code, param->p_code, param->size)) { + XX_Free(p_code); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + param->p_code = p_code; + + err = FM_PCD_PrsLoadSw(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPrsSwParams*)param); + XX_Free(p_code); + XX_Free(param); + break; + } + + case FM_PCD_IOC_ENABLE: + return FM_PCD_Enable(p_LnxWrpFmDev->h_PcdDev); + + case FM_PCD_IOC_DISABLE: + return FM_PCD_Disable(p_LnxWrpFmDev->h_PcdDev); + + case FM_PCD_IOC_FORCE_INTR: + { + int exception; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(exception, (int *) compat_ptr(arg))) + break; + } + else +#endif + { + if (get_user(exception, (int *)arg)) + break; + } + + return FM_PCD_ForceIntr(p_LnxWrpFmDev->h_PcdDev, (e_FmPcdExceptions)exception); + } + + case FM_PCD_IOC_SET_EXCEPTION: + { + ioc_fm_pcd_exception_params_t *param; + + param = (ioc_fm_pcd_exception_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_exception_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)compat_ptr(arg), + sizeof(ioc_fm_pcd_exception_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)arg, + sizeof(ioc_fm_pcd_exception_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, param->exception, param->enable); + XX_Free(param); + break; + } + + case FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING: + { + uint8_t payloadOffset; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(payloadOffset, (uint8_t*) compat_ptr(arg))) + break; + } + else +#endif + { + if (get_user(payloadOffset, (uint8_t*) arg)) + break; + } + + return FM_PCD_KgSetAdditionalDataAfterParsing(p_LnxWrpFmDev->h_PcdDev, payloadOffset); + } + + case FM_PCD_IOC_KG_SET_DFLT_VALUE: + { + ioc_fm_pcd_kg_dflt_value_params_t *param; + + param = (ioc_fm_pcd_kg_dflt_value_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_kg_dflt_value_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)compat_ptr(arg), + sizeof(ioc_fm_pcd_kg_dflt_value_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)arg, + sizeof(ioc_fm_pcd_kg_dflt_value_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_KgSetDfltValue(p_LnxWrpFmDev->h_PcdDev, param->valueId, param->value); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS_COMPAT: +#endif + case FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS: + { + ioc_fm_pcd_net_env_params_t *param; + + param = (ioc_fm_pcd_net_env_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_net_env_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_net_env_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_net_env_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_net_env_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_US_TO_K); + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_net_env_params_t *) arg, + sizeof(ioc_fm_pcd_net_env_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + param->id = FM_PCD_SetNetEnvCharacteristics(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdNetEnvParams*)param); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_net_env_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_net_env_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_K_TO_US); + + if (param->id && !copy_to_user((ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_net_env_params_t))) + err = E_OK; + + XX_Free(compat_param); + } + else +#endif + { + if (param->id && !copy_to_user((ioc_fm_pcd_net_env_params_t *)arg, param, sizeof(ioc_fm_pcd_net_env_params_t))) + err = E_OK; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS_COMPAT: +#endif + case FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + break; + + id.obj = compat_ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PCD_DeleteNetEnvCharacteristics(p_LnxWrpFmDev->h_PcdDev, id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_KG_SET_SCHEME_COMPAT: +#endif + case FM_PCD_IOC_KG_SET_SCHEME: + { + ioc_fm_pcd_kg_scheme_params_t *param; + + ASSERT_COND(sizeof(t_FmPcdKgSchemeParams) + sizeof(void *) == sizeof(ioc_fm_pcd_kg_scheme_params_t)); + param = (ioc_fm_pcd_kg_scheme_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param = NULL; + + compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_params_t *)arg, + sizeof(ioc_fm_pcd_kg_scheme_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + param->id = FM_PCD_KgSetScheme(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdKgSchemeParams*)param); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param = NULL; + + compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_K_TO_US); + + if (param->id && !copy_to_user((ioc_compat_fm_pcd_kg_scheme_params_t *)compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t))) + err = E_OK; + XX_Free(compat_param); + } + else +#endif + { + if (param->id && !copy_to_user((ioc_fm_pcd_kg_scheme_params_t *)arg, + param, + sizeof(ioc_fm_pcd_kg_scheme_params_t))) + err = E_OK; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_KG_DEL_SCHEME_COMPAT: +#endif + case FM_PCD_IOC_KG_DEL_SCHEME: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + break; + + id.obj = compat_ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PCD_KgDeleteScheme(p_LnxWrpFmDev->h_PcdDev, id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_SET_NODE_COMPAT: +#endif + case FM_PCD_IOC_CC_SET_NODE: + { + ioc_fm_pcd_cc_node_params_t *param; + uint8_t *keys; + uint8_t *masks; + int i,k; + + ASSERT_COND(sizeof(t_FmPcdCcNodeParams) + sizeof(void *) == sizeof(ioc_fm_pcd_cc_node_params_t)); + + param = (ioc_fm_pcd_cc_node_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + + keys = (uint8_t *) (param + 1); + masks = keys + IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY; + memset(keys, 0, 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_params_t *)arg, sizeof(ioc_fm_pcd_cc_node_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + ASSERT_COND(param->keys_params.num_of_keys <= IOC_FM_PCD_MAX_NUM_OF_KEYS); + ASSERT_COND(param->keys_params.key_size <= IOC_FM_PCD_MAX_SIZE_OF_KEY); + + /* support for indexed lookup */ + if( !(param->extract_cc_params.type == e_IOC_FM_PCD_EXTRACT_NON_HDR && + param->extract_cc_params.extract_params.extract_non_hdr.src == e_IOC_FM_PCD_EXTRACT_FROM_HASH && + param->extract_cc_params.extract_params.extract_non_hdr.action == e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP)) + { + for (i=0, k=0; + i < param->keys_params.num_of_keys; + i++, k += IOC_FM_PCD_MAX_SIZE_OF_KEY) + { + if (copy_from_user(&keys[k], + param->keys_params.key_params[i].p_key, + param->keys_params.key_size)) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + param->keys_params.key_params[i].p_key = &keys[k]; + + if (param->keys_params.key_params[i].p_mask) + { + if (copy_from_user(&masks[k], + param->keys_params.key_params[i].p_mask, + param->keys_params.key_size)) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + param->keys_params.key_params[i].p_mask = &masks[k]; + } + } + } + + param->id = FM_PCD_CcSetNode(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcNodeParams*)param); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_params_t *compat_param; + compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + + /* setup user space structure */ + compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_K_TO_US); + + compat_param->id = compat_add_ptr2id(param->id); + + if (param->id && !copy_to_user((ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_cc_node_params_t))) + err = E_OK; + + XX_Free(compat_param); + } + else +#endif + { + if (param->id && !copy_to_user((ioc_fm_pcd_cc_node_params_t *)arg, param, sizeof(ioc_fm_pcd_cc_node_params_t))) + err = E_OK; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_DELETE_NODE_COMPAT: +#endif + case FM_PCD_IOC_CC_DELETE_NODE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + break; + + id.obj = compat_get_id2ptr(compat_id.obj); + compat_del_ptr2id(id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PCD_CcDeleteNode(p_LnxWrpFmDev->h_PcdDev, id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_BUILD_TREE_COMPAT: +#endif + case FM_PCD_IOC_CC_BUILD_TREE: + { + ioc_fm_pcd_cc_tree_params_t *param; + + ASSERT_COND(sizeof(t_FmPcdCcTreeParams) + sizeof(void *) == sizeof(ioc_fm_pcd_cc_tree_params_t)); + + param = (ioc_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_cc_tree_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_tree_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_tree_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_tree_params_t *)arg, + sizeof(ioc_fm_pcd_cc_tree_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + param->id = FM_PCD_CcBuildTree(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcTreeParams*)param); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_tree_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + + compat_add_ptr2id(param->id); + param->id = (void *)(uint64_t)compat_get_ptr2id(param->id); + + compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_K_TO_US); + + if (param->id && !copy_to_user((ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_cc_tree_params_t))) + err = E_OK; + + XX_Free(compat_param); + } + else +#endif + { + if (param->id && !copy_to_user((ioc_fm_pcd_cc_tree_params_t *)arg, param, sizeof(ioc_fm_pcd_cc_tree_params_t))) + err = E_OK; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_DELETE_TREE_COMPAT: +#endif + case FM_PCD_IOC_CC_DELETE_TREE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + break; + + id.obj = compat_get_id2ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PCD_CcDeleteTree(p_LnxWrpFmDev->h_PcdDev, id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_PLCR_SET_PROFILE_COMPAT: +#endif + case FM_PCD_IOC_PLCR_SET_PROFILE: + { + ioc_fm_pcd_plcr_profile_params_t *param; + + ASSERT_COND(sizeof(t_FmPcdPlcrProfileParams) + sizeof(void *) == sizeof(ioc_fm_pcd_plcr_profile_params_t)); + + param = (ioc_fm_pcd_plcr_profile_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_plcr_profile_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_plcr_profile_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t))) { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_plcr_profile_params_t *)arg, + sizeof(ioc_fm_pcd_plcr_profile_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + if (!param->modify && + (((t_FmPcdPlcrProfileParams*)param)->id.newParams.profileType != e_FM_PCD_PLCR_SHARED)) + { + t_Handle h_Port; + fm_pcd_port_params_t *port_params; + + port_params = (fm_pcd_port_params_t*) XX_Malloc(sizeof(fm_pcd_port_params_t)); + if (!port_params) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(port_params, (fm_pcd_port_params_t*)((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort, + sizeof(fm_pcd_port_params_t))) + { + XX_Free(port_params); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + switch(port_params->port_type) + { + case (e_IOC_FM_PORT_TYPE_RX): + h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev; + break; + case (e_IOC_FM_PORT_TYPE_RX_10G): + h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id + FM_MAX_NUM_OF_1G_RX_PORTS].h_Dev; + break; + case (e_IOC_FM_PORT_TYPE_OFFLINE_PARSING): + if (port_params->port_id) + { + h_Port = p_LnxWrpFmDev->opPorts[port_params->port_id - 1].h_Dev; + break; + } + default: + XX_Free(port_params); + XX_Free(param); + RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); + } + + ((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort = h_Port; + XX_Free(port_params); + } + + param->id = FM_PCD_PlcrSetProfile(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPlcrProfileParams*)param); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_K_TO_US); + + if (param->id && !copy_to_user((ioc_compat_fm_pcd_plcr_profile_params_t *) compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t))) + err = E_OK; + + XX_Free(compat_param); + } + else +#endif + { + if (param->id && !copy_to_user((ioc_fm_pcd_plcr_profile_params_t *)arg, param, sizeof(ioc_fm_pcd_plcr_profile_params_t))) + err = E_OK; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_PLCR_DEL_PROFILE_COMPAT: +#endif + case FM_PCD_IOC_PLCR_DEL_PROFILE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + break; + + id.obj = compat_ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PCD_PlcrDeleteProfile(p_LnxWrpFmDev->h_PcdDev, id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE: + { + ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param; + + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_engine_params_t) == sizeof(t_FmPcdCcNextEngineParams)); + + param = (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t))) + { + XX_Free(param); + XX_Free(compat_param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_fm_pcd_cc_tree_modify_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_CcTreeModifyNextEngine(p_LnxWrpFmDev->h_PcdDev, + param->id, + param->grp_indx, + param->indx, + (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE: + { + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param; + + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_engine_params_t) == sizeof(t_FmPcdCcNextEngineParams)); + + param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(param); + XX_Free(compat_param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_CcNodeModifyNextEngine(p_LnxWrpFmDev->h_PcdDev, + param->id, + param->key_indx, + (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE: + { + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param; + + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_engine_params_t) == sizeof(t_FmPcdCcNextEngineParams)); + + param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(param); + XX_Free(compat_param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) arg, + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_CcNodeModifyMissNextEngine(p_LnxWrpFmDev->h_PcdDev, param->id, + (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_NODE_REMOVE_KEY_COMPAT: +#endif + case FM_PCD_IOC_CC_NODE_REMOVE_KEY: + { + ioc_fm_pcd_cc_node_remove_key_params_t *param; + + param = (ioc_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_remove_key_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_remove_key_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_remove_key_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t))) + { + XX_Free(param); + XX_Free(compat_param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + param->id = compat_ptr(compat_param->id); + param->key_indx = compat_param->key_indx; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_remove_key_params_t *) arg, + sizeof(ioc_fm_pcd_cc_node_remove_key_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_CcNodeRemoveKey(p_LnxWrpFmDev->h_PcdDev, param->id, param->key_indx); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_NODE_ADD_KEY_COMPAT: +#endif + case FM_PCD_IOC_CC_NODE_ADD_KEY: + { + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param; + + ASSERT_COND(sizeof(ioc_fm_pcd_cc_key_params_t) == sizeof(t_FmPcdCcKeyParams)); + + param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(param); + XX_Free(compat_param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_CcNodeAddKey(p_LnxWrpFmDev->h_PcdDev, + param->id, + param->key_indx, + param->key_size, + (t_FmPcdCcKeyParams*)(¶m->key_params)); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE: + { + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param; + + ASSERT_COND(sizeof(ioc_fm_pcd_cc_key_params_t) == sizeof(t_FmPcdCcKeyParams)); + + param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!compat_param) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + err = FM_PCD_CcNodeModifyKeyAndNextEngine(p_LnxWrpFmDev->h_PcdDev, + param->id, + param->key_indx, + param->key_size, + (t_FmPcdCcKeyParams*)(¶m->key_params)); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_NODE_MODIFY_KEY_COMPAT: +#endif + case FM_PCD_IOC_CC_NODE_MODIFY_KEY: + { + ioc_fm_pcd_cc_node_modify_key_params_t *param = NULL; + uint8_t *key = NULL; + uint8_t *mask = NULL; + + param = (ioc_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_key_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param = NULL; + compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t)); + if (!param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_key_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_key(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_key_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + if (param->p_key) + { + key = (uint8_t *) XX_Malloc(sizeof(uint8_t)*IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!key) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key")); + } + memset(key, 0, sizeof(uint8_t)*IOC_FM_PCD_MAX_SIZE_OF_KEY); + + if (copy_from_user(key, param->p_key, param->key_size)) + { + XX_Free(key); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + param->p_key = key; + } + + if (param->p_mask) + { + mask = (uint8_t *) XX_Malloc(sizeof(uint8_t)*IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!mask) + { + if (key) + XX_Free(key); + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD mask")); + } + memset(mask, 0, sizeof(uint8_t)*IOC_FM_PCD_MAX_SIZE_OF_KEY); + + if (copy_from_user(mask, param->p_mask, param->key_size)) + { + if (mask) + XX_Free(mask); + if (key) + XX_Free(key); + XX_Free(param); + RETURN_ERROR(MINOR, err, NO_MSG); + } + param->p_mask = mask; + } + + err = FM_PCD_CcNodeModifyKey(p_LnxWrpFmDev->h_PcdDev, + param->id, + param->key_indx, + param->key_size, + param->p_key, + param->p_mask); + if (mask) + XX_Free(mask); + if (key) + XX_Free(key); + XX_Free(param); + break; + } + + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("IOCTL cmd (0x%08x):(0x%02x:0x%02x)!", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd))); + break; + } + + return err; +} + +t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat) +{ + t_Error err = E_READ_FAILED; + + DBG(TRACE, ("p_LnxWrpFmDev - 0x%08lx, cmd - 0x%08x, arg - 0x%08lx \n", (uintptr_t)p_LnxWrpFmDev, cmd, arg)); + + switch (cmd) + { + case FM_IOC_SET_PORTS_BANDWIDTH: + { + ioc_fm_port_bandwidth_params *param; + + ASSERT_COND(sizeof(t_FmPortsBandwidthParams) == sizeof(ioc_fm_port_bandwidth_params)); + + param = (ioc_fm_port_bandwidth_params*) XX_Malloc(sizeof(ioc_fm_port_bandwidth_params)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)compat_ptr(arg), sizeof(ioc_fm_port_bandwidth_params))) + { + XX_Free(param); + return err; + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)arg, sizeof(ioc_fm_port_bandwidth_params))) + { + XX_Free(param); + return err; + } + } + + err = FM_SetPortsBandwidth(p_LnxWrpFmDev->h_Dev, (t_FmPortsBandwidthParams*) param); + XX_Free(param); + return err; + } + + case FM_IOC_GET_REVISION: + { + ioc_fm_revision_info_t *param; + + ASSERT_COND(sizeof(t_FmRevisionInfo) == sizeof(ioc_fm_revision_info_t)); + + param = (ioc_fm_revision_info_t *) XX_Malloc(sizeof(ioc_fm_revision_info_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + FM_GetRevision(p_LnxWrpFmDev->h_Dev, (t_FmRevisionInfo*)param); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_to_user((ioc_fm_revision_info_t *)compat_ptr(arg), + param, + sizeof(ioc_fm_revision_info_t))) + err = E_WRITE_FAILED; + else + err = E_OK; + } + else +#endif + { + if (copy_to_user((ioc_fm_revision_info_t *)arg, + param, + sizeof(ioc_fm_revision_info_t))) + err = E_WRITE_FAILED; + else + err = E_OK; + } + + XX_Free(param); + return err; + } + + case FM_IOC_SET_COUNTER: + { + ioc_fm_counters_params_t *param; + + param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + return err; + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + return err; + } + } + + err = FM_ModifyCounter(p_LnxWrpFmDev->h_Dev, param->cnt, param->val); + + XX_Free(param); + return err; + } + + case FM_IOC_GET_COUNTER: + { + ioc_fm_counters_params_t *param; + + param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + return err; + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + return err; + } + } + + param->val = FM_GetCounter(p_LnxWrpFmDev->h_Dev, param->cnt); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_to_user((ioc_fm_counters_params_t *)compat_ptr(arg), param, sizeof(ioc_fm_counters_params_t))) + err = E_WRITE_FAILED; + } + else +#endif + { + if (copy_to_user((ioc_fm_counters_params_t *)arg, param, sizeof(ioc_fm_counters_params_t))) + err = E_WRITE_FAILED; + } + + XX_Free(param); + return err; + } + + case FM_IOC_FORCE_INTR: + { + ioc_fm_exceptions param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(param, (ioc_fm_exceptions*) compat_ptr(arg))) + break; + } + else +#endif + { + if (get_user(param, (ioc_fm_exceptions*)arg)) + break; + } + + return FM_ForceIntr(p_LnxWrpFmDev->h_Dev, (e_FmExceptions)param); + } + + default: + return LnxwrpFmPcdIOCTL(p_LnxWrpFmDev, cmd, arg, compat); + } + + RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM")); +} + +t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat) +{ + t_Error err = E_READ_FAILED; + DBG(TRACE, ("p_LnxWrpFmPortDev - 0x%08lx, cmd - 0x%08x, arg - 0x%08lx", (uintptr_t)p_LnxWrpFmPortDev, cmd, arg)); + + switch (cmd) + { + case FM_PORT_IOC_DISABLE: + FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev); + return E_OK; + + case FM_PORT_IOC_ENABLE: + FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev); + return E_OK; + + case FM_PORT_IOC_SET_ERRORS_ROUTE: + { + ioc_fm_port_frame_err_select_t errs; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(errs, (ioc_fm_port_frame_err_select_t*)compat_ptr(arg))) + break; + } + else +#endif + { + if (get_user(errs, (ioc_fm_port_frame_err_select_t*)arg)) + break; + } + + return FM_PORT_SetErrorsRoute(p_LnxWrpFmPortDev->h_Dev, (fmPortFrameErrSelect_t)errs); + } + + case FM_PORT_IOC_SET_RATE_LIMIT: + { + ioc_fm_port_rate_limit_t *param; + + ASSERT_COND(sizeof(t_FmPortRateLimit) == sizeof(ioc_fm_port_rate_limit_t)); + + param = (ioc_fm_port_rate_limit_t *) XX_Malloc(sizeof(ioc_fm_port_rate_limit_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)compat_ptr(arg), sizeof(ioc_fm_port_rate_limit_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_READ_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)arg, sizeof(ioc_fm_port_rate_limit_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_READ_FAILED, NO_MSG); + } + } + + err = FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, (t_FmPortRateLimit *)param); + + XX_Free(param); + return err; + } + + case FM_PORT_IOC_REMOVE_RATE_LIMIT: + FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev); + return E_OK; + + case FM_PORT_IOC_ALLOC_PCD_FQIDS: + { + ioc_fm_port_pcd_fqids_params_t *param; + + if (!p_LnxWrpFmPortDev->pcd_owner_params.cba) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!")); + + param = (ioc_fm_port_pcd_fqids_params_t *) XX_Malloc(sizeof(ioc_fm_port_pcd_fqids_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg), + sizeof(ioc_fm_port_pcd_fqids_params_t))) + { + XX_Free(param); + return err; + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)arg, + sizeof(ioc_fm_port_pcd_fqids_params_t))) + { + XX_Free(param); + return err; + } + } + + if (p_LnxWrpFmPortDev->pcd_owner_params.cba(p_LnxWrpFmPortDev->pcd_owner_params.dev, + param->num_fqids, + param->alignment, + ¶m->base_fqid)) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_INVALID_STATE, ("can't allocate fqids for PCD!!!")); + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg), + param, sizeof(ioc_fm_port_pcd_fqids_params_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)arg, + param, sizeof(ioc_fm_port_pcd_fqids_params_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_WRITE_FAILED, NO_MSG); + } + } + + XX_Free(param); + return E_OK; + } + + case FM_PORT_IOC_FREE_PCD_FQIDS: + { + uint32_t base_fqid; + + if (!p_LnxWrpFmPortDev->pcd_owner_params.cbf) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(base_fqid, (uint32_t*) compat_ptr(arg))) + break; + } + else +#endif + { + if (get_user(base_fqid, (uint32_t*)arg)) + break; + } + + if (p_LnxWrpFmPortDev->pcd_owner_params.cbf(p_LnxWrpFmPortDev->pcd_owner_params.dev, base_fqid)) + RETURN_ERROR(MAJOR, E_WRITE_FAILED, NO_MSG); + + return E_OK; + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_SET_PCD_COMPAT: +#endif + case FM_PORT_IOC_SET_PCD: + { + ioc_fm_port_pcd_params_t *port_pcd_params; + ioc_fm_port_pcd_prs_params_t *port_pcd_prs_params; + ioc_fm_port_pcd_cc_params_t *port_pcd_cc_params; + ioc_fm_port_pcd_kg_params_t *port_pcd_kg_params; + ioc_fm_port_pcd_plcr_params_t *port_pcd_plcr_params; + + long copy_fail = 0; + + ASSERT_COND(sizeof(t_FmPortPcdParams) == sizeof(ioc_fm_port_pcd_params_t)); + + port_pcd_params = (ioc_fm_port_pcd_params_t *) XX_Malloc( + sizeof(ioc_fm_port_pcd_params_t) + + sizeof(ioc_fm_port_pcd_prs_params_t) + + sizeof(ioc_fm_port_pcd_cc_params_t) + + sizeof(ioc_fm_port_pcd_kg_params_t) + + sizeof(ioc_fm_port_pcd_plcr_params_t)); + if (!port_pcd_params) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (port_pcd_params + 1); + port_pcd_cc_params = (ioc_fm_port_pcd_cc_params_t *) (port_pcd_prs_params + 1); + port_pcd_kg_params = (ioc_fm_port_pcd_kg_params_t *) (port_pcd_cc_params + 1); + port_pcd_plcr_params = (ioc_fm_port_pcd_plcr_params_t *) (port_pcd_kg_params + 1); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_port_pcd_params_t *compat_port_pcd_params; + ioc_fm_port_pcd_prs_params_t *same_port_pcd_prs_params; + ioc_compat_fm_port_pcd_cc_params_t *compat_port_pcd_cc_params; + ioc_compat_fm_port_pcd_kg_params_t *compat_port_pcd_kg_params; + ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params; + + compat_port_pcd_params = (ioc_compat_fm_port_pcd_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_port_pcd_params_t) + + sizeof(ioc_fm_port_pcd_prs_params_t) + + sizeof(ioc_compat_fm_port_pcd_cc_params_t) + + sizeof(ioc_compat_fm_port_pcd_kg_params_t) + + sizeof(ioc_compat_fm_port_pcd_plcr_params_t)); + if (!compat_port_pcd_params) + { + XX_Free(port_pcd_params); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + } + + same_port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (compat_port_pcd_params + 1); + compat_port_pcd_cc_params = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1); + compat_port_pcd_kg_params = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1); + compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1); + + /* Pseudo-while */ + while (!(copy_fail = copy_from_user(compat_port_pcd_params, + (ioc_compat_fm_port_pcd_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_port_pcd_params_t)))) + { + compat_copy_fm_port_pcd(compat_port_pcd_params, port_pcd_params, COMPAT_US_TO_K); + + /* the prs member is the same, no compat structure...memcpy only */ + if (port_pcd_params->p_prs_params && !copy_fail) + { + if(!(copy_fail = copy_from_user(same_port_pcd_prs_params, + port_pcd_params->p_prs_params, + sizeof(ioc_fm_port_pcd_prs_params_t)))) + { + memcpy(port_pcd_prs_params, same_port_pcd_prs_params, sizeof(ioc_fm_port_pcd_prs_params_t)); + port_pcd_params->p_prs_params = port_pcd_prs_params; + } + else + break; + } + + if (port_pcd_params->p_cc_params && !copy_fail) + { + if(!(copy_fail = copy_from_user(compat_port_pcd_cc_params, + port_pcd_params->p_cc_params, + sizeof(ioc_compat_fm_port_pcd_cc_params_t)))) + { + port_pcd_params->p_cc_params = port_pcd_cc_params; + port_pcd_params->p_cc_params->cc_tree_id = compat_get_id2ptr(compat_port_pcd_cc_params->cc_tree_id); + } + else + break; + } + + if (port_pcd_params->p_kg_params && !copy_fail) + { + if(!(copy_fail = copy_from_user(compat_port_pcd_kg_params, + port_pcd_params->p_kg_params, + sizeof(ioc_compat_fm_port_pcd_kg_params_t)))) + { + compat_copy_fm_port_pcd_kg(compat_port_pcd_kg_params, port_pcd_kg_params, COMPAT_US_TO_K); + port_pcd_params->p_kg_params = port_pcd_kg_params; + } + else + break; + } + + if (port_pcd_params->p_plcr_params && !copy_fail) + { + if(!(copy_fail = copy_from_user(compat_port_pcd_plcr_params, + port_pcd_params->p_plcr_params, + sizeof(ioc_compat_fm_port_pcd_plcr_params_t)))) + { + port_pcd_params->p_plcr_params = port_pcd_plcr_params; + port_pcd_params->p_plcr_params->plcr_profile_id = compat_ptr(compat_port_pcd_plcr_params->plcr_profile_id); + } + } + + /* always run once! */ + break; + } + + XX_Free(compat_port_pcd_params); + } + else +#endif + { + /* Pseudo-while */ + while (!(copy_fail = copy_from_user(port_pcd_params, + (ioc_fm_port_pcd_params_t *)arg, + sizeof(ioc_fm_port_pcd_params_t)))) + { + if (port_pcd_params->p_prs_params && !copy_fail) + { + if (!(copy_fail = copy_from_user(port_pcd_prs_params, + port_pcd_params->p_prs_params, + sizeof(ioc_fm_port_pcd_prs_params_t)))) + port_pcd_params->p_prs_params = port_pcd_prs_params; + else + break; + } + + if (port_pcd_params->p_cc_params && !copy_fail) + { + if (!(copy_fail = copy_from_user(port_pcd_cc_params, + port_pcd_params->p_cc_params, + sizeof(ioc_fm_port_pcd_cc_params_t)))) + port_pcd_params->p_cc_params = port_pcd_cc_params; + else + break; + } + + if (port_pcd_params->p_kg_params && !copy_fail) + { + if (!(copy_fail = copy_from_user(port_pcd_kg_params, + port_pcd_params->p_kg_params, + sizeof(ioc_fm_port_pcd_kg_params_t)))) + port_pcd_params->p_kg_params = port_pcd_kg_params; + else + break; + } + + if (port_pcd_params->p_plcr_params && !copy_fail) + { + if (!(copy_fail = copy_from_user(port_pcd_plcr_params, + port_pcd_params->p_plcr_params, + sizeof(ioc_fm_port_pcd_plcr_params_t)))) + port_pcd_params->p_plcr_params = port_pcd_plcr_params; + } + + /* always run once! */ + break; + } + } + + if (!copy_fail) + err = FM_PORT_SetPCD(p_LnxWrpFmPortDev->h_Dev, (t_FmPortPcdParams*) port_pcd_params); + else + err = E_READ_FAILED; + + XX_Free(port_pcd_params); + + return err; + } + + case FM_PORT_IOC_DELETE_PCD: + return FM_PORT_DeletePCD(p_LnxWrpFmPortDev->h_Dev); + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT: +#endif + case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME: + { + ioc_fm_pcd_kg_scheme_select_t *param; + + ASSERT_COND(sizeof(t_FmPcdKgSchemeSelect) == sizeof(ioc_fm_pcd_kg_scheme_select_t)); + + param = (ioc_fm_pcd_kg_scheme_select_t *) XX_Malloc( + sizeof(ioc_fm_pcd_kg_scheme_select_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_kg_scheme_select_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_kg_scheme_select_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_kg_scheme_select_t)); + if (!compat_param){ + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + } + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_kg_scheme_select_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_kg_scheme_select_t))) + { + XX_Free(param); + XX_Free(compat_param); + RETURN_ERROR(MAJOR, E_READ_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_kg_scheme_select(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_select_t *)arg, + sizeof(ioc_fm_pcd_kg_scheme_select_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_READ_FAILED, NO_MSG); + } + } + + err = FM_PORT_PcdKgModifyInitialScheme(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdKgSchemeSelect *)param); + + XX_Free(param); + return err; + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT: +#endif + case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); +#if defined(CONFIG_COMPAT) + if (compat) { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + break; + + id.obj = compat_ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PORT_PcdPlcrModifyInitialProfile(p_LnxWrpFmPortDev->h_Dev, id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT: +#endif + case FM_PORT_IOC_PCD_KG_BIND_SCHEMES: + { + ioc_fm_pcd_port_schemes_params_t *param; + + ASSERT_COND(sizeof(t_FmPcdPortSchemesParams) == sizeof(ioc_fm_pcd_port_schemes_params_t)); + + param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_port_schemes_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(¶m, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_port_schemes_params_t compat_param; + + if (copy_from_user(&compat_param, + (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_port_schemes_params_t))) + break; + + compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg, + sizeof(ioc_fm_pcd_port_schemes_params_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PORT_PcdKgBindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param); + + XX_Free(param); + return err; + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT: +#endif + case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES: + { + ioc_fm_pcd_port_schemes_params_t *param; + + ASSERT_COND(sizeof(t_FmPcdPortSchemesParams) == sizeof(ioc_fm_pcd_port_schemes_params_t)); + + param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_port_schemes_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(¶m, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_port_schemes_params_t compat_param; + + if (copy_from_user(&compat_param, + (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_port_schemes_params_t))) + break; + + compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg, + sizeof(ioc_fm_pcd_port_schemes_params_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PORT_PcdKgUnbindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param); + + XX_Free(param); + return err; + } + + case FM_PORT_IOC_PCD_PRS_MODIFY_START_OFFSET: + { + ioc_fm_pcd_prs_start_t *param; + + ASSERT_COND(sizeof(t_FmPcdPrsStart) == sizeof(ioc_fm_pcd_prs_start_t)); + + param = (ioc_fm_pcd_prs_start_t *) XX_Malloc(sizeof(ioc_fm_pcd_prs_start_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_pcd_prs_start_t *)compat_ptr(arg), + sizeof(ioc_fm_pcd_prs_start_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_prs_start_t *)arg, + sizeof(ioc_fm_pcd_prs_start_t))) + { + XX_Free(param); + RETURN_ERROR(MAJOR, E_WRITE_FAILED, NO_MSG); + } + } + err = FM_PORT_PcdPrsModifyStartOffset(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPrsStart *)param); + + XX_Free(param); + return err; + } + + case FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES: + { + uint16_t num; + if (get_user(num, (uint16_t*) arg)) + break; + return FM_PORT_PcdPlcrAllocProfiles(p_LnxWrpFmPortDev->h_Dev, num); + } + + case FM_PORT_IOC_PCD_PLCR_FREE_PROFILES: + return FM_PORT_PcdPlcrFreeProfiles(p_LnxWrpFmPortDev->h_Dev); + + case FM_PORT_IOC_DETACH_PCD: + return FM_PORT_DetachPCD(p_LnxWrpFmPortDev->h_Dev); + + case FM_PORT_IOC_ATTACH_PCD: + return FM_PORT_AttachPCD(p_LnxWrpFmPortDev->h_Dev); + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT: +#endif + case FM_PORT_IOC_PCD_CC_MODIFY_TREE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + break; + + id.obj = compat_get_id2ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PORT_PcdCcModifyTree(p_LnxWrpFmPortDev->h_Dev, id.obj); + } + + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("IOCTL cmd (0x%08x):(0x%02x:0x%02x)!", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd))); + } + + RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL port")); +} + +/*****************************************************************************/ +/* API routines for the FM Linux Device */ +/*****************************************************************************/ + +static int fm_open(struct inode *inode, struct file *file) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL; + unsigned int major = imajor(inode); + unsigned int minor = iminor(inode); + struct device_node *fm_node; + static struct of_device_id fm_node_of_match[] = { + { .compatible = "fsl,fman", }, + { /* end of list */ }, + }; + + DBG(TRACE, ("Opening minor - %d - ", minor)); + + if (file->private_data != NULL) + return 0; + + /* Get all the FM nodes */ + for_each_matching_node(fm_node, fm_node_of_match) { + struct platform_device *of_dev; + + of_dev = of_find_device_by_node(fm_node); + if (unlikely(of_dev == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + return -ENXIO; + } + + p_LnxWrpFmDev = (t_LnxWrpFmDev *)fm_bind(&of_dev->dev); + if (p_LnxWrpFmDev->major == major) + break; + fm_unbind((struct fm *)p_LnxWrpFmDev); + p_LnxWrpFmDev = NULL; + } + + if (!p_LnxWrpFmDev) + return -ENODEV; + + if (minor == DEV_FM_MINOR_BASE) + file->private_data = p_LnxWrpFmDev; + else if (minor == DEV_FM_PCD_MINOR_BASE) + file->private_data = p_LnxWrpFmDev; + else { + if (minor == DEV_FM_OH_PORTS_MINOR_BASE) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; + else if ((minor > DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->opPorts[minor-DEV_FM_OH_PORTS_MINOR_BASE-1]; + else if ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[minor-DEV_FM_RX_PORTS_MINOR_BASE]; + else if ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS)) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[minor-DEV_FM_TX_PORTS_MINOR_BASE]; + else + return -EINVAL; + + /* if trying to open port, check if it initialized */ + if (!p_LnxWrpFmPortDev->h_Dev) + return -ENODEV; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)fm_port_bind(p_LnxWrpFmPortDev->dev); + file->private_data = p_LnxWrpFmPortDev; + fm_unbind((struct fm *)p_LnxWrpFmDev); + } + + if (file->private_data == NULL) + return -ENXIO; + + return 0; +} + +static int fm_close(struct inode *inode, struct file *file) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + unsigned int minor = iminor(inode); + int err = 0; + + DBG(TRACE, ("Closing minor - %d - ", minor)); + + if ((minor == DEV_FM_MINOR_BASE) || + (minor == DEV_FM_PCD_MINOR_BASE)) + { + p_LnxWrpFmDev = (t_LnxWrpFmDev*)file->private_data; + if (!p_LnxWrpFmDev) + return -ENODEV; + fm_unbind((struct fm *)p_LnxWrpFmDev); + } + else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))) + { + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)file->private_data; + if (!p_LnxWrpFmPortDev) + return -ENODEV; + fm_port_unbind((struct fm_port *)p_LnxWrpFmPortDev); + } + + return err; +} + +static int fm_ioctls(unsigned int minor, struct file *file, unsigned int cmd, unsigned long arg, bool compat) +{ + DBG(TRACE, ("IOCTL minor - %u, cmd - 0x%08x, arg - 0x%08lx \n", minor, cmd, arg)); + + if ((minor == DEV_FM_MINOR_BASE) || + (minor == DEV_FM_PCD_MINOR_BASE)) + { + t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_LnxWrpFmDev*)file->private_data); + if (!p_LnxWrpFmDev) + return -ENODEV; + if (LnxwrpFmIOCTL(p_LnxWrpFmDev, cmd, arg, compat)) + return -EFAULT; + } + else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))) + { + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = ((t_LnxWrpFmPortDev*)file->private_data); + if (!p_LnxWrpFmPortDev) + return -ENODEV; + if (LnxwrpFmPortIOCTL(p_LnxWrpFmPortDev, cmd, arg, compat)) + return -EFAULT; + } + else + { + REPORT_ERROR(MINOR, E_INVALID_VALUE, ("minor")); + return -ENODEV; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long fm_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + long res; + + fm_mutex_lock(); + res = fm_ioctls(minor, file, cmd, arg, true); + fm_mutex_unlock(); + + return res; +} +#endif + +static long fm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + long res; + + fm_mutex_lock(); + res = fm_ioctls(minor, file, cmd, arg, false); + fm_mutex_unlock(); + + return res; +} + +/* Globals for FM character device */ +struct file_operations fm_fops = +{ + .owner = THIS_MODULE, + .unlocked_ioctl = fm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fm_compat_ioctl, +#endif + .open = fm_open, + .release = fm_close, +}; --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs_fm.c @@ -0,0 +1,575 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_sysfs_fm.c + + @Description FM sysfs related functions. + +*/ + +#include "lnxwrp_sysfs.h" +#include "lnxwrp_fm.h" + +enum e_FmDmaMatchStatistics { + e_FM_DMA_COUNTERS_CMQ_NOT_EMPTY, + e_FM_DMA_COUNTERS_BUS_ERROR, + e_FM_DMA_COUNTERS_READ_BUF_ECC_ERROR, + e_FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR, + e_FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR +}; + +static const struct SysfsStats_t fmSysfsStats[] = { + /* FM statistics */ + { + .statisticName = "enq_total_frame", + .statisticCounter = e_FM_COUNTERS_ENQ_TOTAL_FRAME, + }, + { + .statisticName = "deq_total_frame", + .statisticCounter = e_FM_COUNTERS_DEQ_TOTAL_FRAME, + }, + { + .statisticName = "deq_0", + .statisticCounter = e_FM_COUNTERS_DEQ_0, + }, + { + .statisticName = "deq_1", + .statisticCounter = e_FM_COUNTERS_DEQ_1, + }, + { + .statisticName = "deq_2", + .statisticCounter = e_FM_COUNTERS_DEQ_2, + }, + { + .statisticName = "deq_from_default", + .statisticCounter = e_FM_COUNTERS_DEQ_FROM_DEFAULT, + }, + { + .statisticName = "deq_from_context", + .statisticCounter = e_FM_COUNTERS_DEQ_FROM_CONTEXT, + }, + { + .statisticName = "deq_from_fd", + .statisticCounter = e_FM_COUNTERS_DEQ_FROM_FD, + }, + { + .statisticName = "deq_confirm", + .statisticCounter = e_FM_COUNTERS_DEQ_CONFIRM, + }, + /* FM:DMA statistics */ + { + .statisticName = "cmq_not_empty", + .statisticCounter = e_FM_DMA_COUNTERS_CMQ_NOT_EMPTY, + }, + { + .statisticName = "bus_error", + .statisticCounter = e_FM_DMA_COUNTERS_BUS_ERROR, + }, + { + .statisticName = "read_buf_ecc_error", + .statisticCounter = e_FM_DMA_COUNTERS_READ_BUF_ECC_ERROR, + }, + { + .statisticName = "write_buf_ecc_sys_error", + .statisticCounter = e_FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR, + }, + { + .statisticName = "write_buf_ecc_fm_error", + .statisticCounter = e_FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR, + }, + /* FM:PCD statistics */ + { + .statisticName = "pcd_enq_total_frame", + .statisticCounter = e_FM_COUNTERS_ENQ_TOTAL_FRAME, + }, + { + .statisticName = "pcd_kg_total", + .statisticCounter = e_FM_PCD_KG_COUNTERS_TOTAL, + }, + { + .statisticName = "pcd_plcr_yellow", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_YELLOW, + }, + { + .statisticName = "pcd_plcr_red", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_RED, + }, + { + .statisticName = "pcd_plcr_recolored_to_red", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, + }, + { + .statisticName = "pcd_plcr_recolored_to_yellow", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, + }, + { + .statisticName = "pcd_plcr_total", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_TOTAL, + }, + { + .statisticName = "pcd_plcr_length_mismatch", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, + }, + { + .statisticName = "pcd_prs_parse_dispatch", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, + }, + { + .statisticName = "pcd_prs_l2_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_l3_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_l4_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_shim_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_l2_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_l3_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_l4_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_shim_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_soft_prs_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, + }, + { + .statisticName = "pcd_prs_soft_prs_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_hard_prs_cycle_incl_stall_cycles", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_read_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_read_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_write_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_write_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_fpm_command_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES, + }, + {} +}; + +/* Fm stats and regs dumps via sysfs */ +static ssize_t show_fm_dma_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + t_FmDmaStatus fmDmaStatus; + unsigned long flags = 0; + unsigned n = 0; + uint8_t counter_value = 0, counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + + counter = + fm_find_statistic_counter_by_name(attr->attr.name, + (struct SysfsStats_t *) + &fmSysfsStats[0], NULL); + + local_irq_save(flags); + + memset(&fmDmaStatus, 0, sizeof(fmDmaStatus)); + FM_GetDmaStatus(p_LnxWrpFmDev->h_Dev, &fmDmaStatus); + + switch (counter) { + case e_FM_DMA_COUNTERS_CMQ_NOT_EMPTY: + counter_value = fmDmaStatus.cmqNotEmpty; + break; + case e_FM_DMA_COUNTERS_BUS_ERROR: + counter_value = fmDmaStatus.busError; + break; + case e_FM_DMA_COUNTERS_READ_BUF_ECC_ERROR: + counter_value = fmDmaStatus.readBufEccError; + break; + case e_FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR: + counter_value = fmDmaStatus.writeBufEccSysError; + break; + case e_FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR: + counter_value = fmDmaStatus.writeBufEccFmError; + break; + default: + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + break; + }; + + n = snprintf(buf, PAGE_SIZE, "\tFM %u counter: %c\n", + p_LnxWrpFmDev->id, counter_value ? 'T' : 'F'); + + local_irq_restore(flags); + + return n; +} + +static ssize_t show_fm_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + unsigned long flags = 0; + unsigned n = 0, counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + + counter = + fm_find_statistic_counter_by_name(attr->attr.name, + (struct SysfsStats_t *) + &fmSysfsStats[0], NULL); + + local_irq_save(flags); + + n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n", + p_LnxWrpFmDev->id, + FM_GetCounter(p_LnxWrpFmDev->h_Dev, + (e_FmCounters) counter)); + + local_irq_restore(flags); + + return n; +} + +static ssize_t show_fm_pcd_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + unsigned long flags = 0; + unsigned n = 0, counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + + counter = + fm_find_statistic_counter_by_name(attr->attr.name, + (struct SysfsStats_t *) + &fmSysfsStats[0], NULL); + + local_irq_save(flags); + + n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n", + p_LnxWrpFmDev->id, + FM_PCD_GetCounter(p_LnxWrpFmDev->h_PcdDev, + (e_FmPcdCounters) counter)); + + local_irq_restore(flags); + + return n; +} + +/* FM */ +static DEVICE_ATTR(enq_total_frame, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_total_frame, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_0, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_1, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_2, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_from_default, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_from_context, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_from_fd, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_confirm, S_IRUGO, show_fm_stats, NULL); +/* FM:DMA */ +static DEVICE_ATTR(cmq_not_empty, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(bus_error, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(read_buf_ecc_error, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(write_buf_ecc_sys_error, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(write_buf_ecc_fm_error, S_IRUGO, show_fm_dma_stats, NULL); +/* FM:PCD */ +static DEVICE_ATTR(pcd_enq_total_frame, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_kg_total, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_yellow, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_red, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_recolored_to_red, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_plcr_recolored_to_yellow, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_plcr_total, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_length_mismatch, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_parse_dispatch, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l2_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l3_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l4_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_shim_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l2_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l3_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l4_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_shim_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_soft_prs_cycles, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_soft_prs_stall_cycles, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_hard_prs_cycle_incl_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_muram_read_cycles, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_muram_read_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_muram_write_cycles, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_muram_write_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_fpm_command_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); + +static struct attribute *fm_dev_stats_attributes[] = { + &dev_attr_enq_total_frame.attr, + &dev_attr_deq_total_frame.attr, + &dev_attr_deq_0.attr, + &dev_attr_deq_1.attr, + &dev_attr_deq_2.attr, + &dev_attr_deq_from_default.attr, + &dev_attr_deq_from_context.attr, + &dev_attr_deq_from_fd.attr, + &dev_attr_deq_confirm.attr, + &dev_attr_cmq_not_empty.attr, + &dev_attr_bus_error.attr, + &dev_attr_read_buf_ecc_error.attr, + &dev_attr_write_buf_ecc_sys_error.attr, + &dev_attr_write_buf_ecc_fm_error.attr, + &dev_attr_pcd_enq_total_frame.attr, + &dev_attr_pcd_kg_total.attr, + &dev_attr_pcd_plcr_yellow.attr, + &dev_attr_pcd_plcr_red.attr, + &dev_attr_pcd_plcr_recolored_to_red.attr, + &dev_attr_pcd_plcr_recolored_to_yellow.attr, + &dev_attr_pcd_plcr_total.attr, + &dev_attr_pcd_plcr_length_mismatch.attr, + &dev_attr_pcd_prs_parse_dispatch.attr, + &dev_attr_pcd_prs_l2_parse_result_returned.attr, + &dev_attr_pcd_prs_l3_parse_result_returned.attr, + &dev_attr_pcd_prs_l4_parse_result_returned.attr, + &dev_attr_pcd_prs_shim_parse_result_returned.attr, + &dev_attr_pcd_prs_l2_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_l3_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_l4_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_shim_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_soft_prs_cycles.attr, + &dev_attr_pcd_prs_soft_prs_stall_cycles.attr, + &dev_attr_pcd_prs_hard_prs_cycle_incl_stall_cycles.attr, + &dev_attr_pcd_prs_muram_read_cycles.attr, + &dev_attr_pcd_prs_muram_read_stall_cycles.attr, + &dev_attr_pcd_prs_muram_write_cycles.attr, + &dev_attr_pcd_prs_muram_write_stall_cycles.attr, + &dev_attr_pcd_prs_fpm_command_stall_cycles.attr, + NULL +}; + +static const struct attribute_group fm_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_dev_stats_attributes +}; + +static ssize_t show_fm_regs(struct device *dev, struct device_attribute *attr, + char *buf) +{ + unsigned long flags; + unsigned n = 0; +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; +#endif + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + local_irq_save(flags); + + n = snprintf(buf, PAGE_SIZE, "FM driver registers dump.\n"); + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + else + FM_DumpRegs(p_LnxWrpFmDev->h_Dev); + + local_irq_restore(flags); +#else + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "Debug level is too low to dump registers!!!\n"); + local_irq_restore(flags); +#endif /* (defined(DEBUG_ERRORS) && ... */ + + return n; +} + +static ssize_t show_pcd_regs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long flags; + unsigned n = 0; +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; +#endif + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, "FM driver registers dump.\n"); + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_PcdDev) + return -EIO; + else + FM_PCD_DumpRegs(p_LnxWrpFmDev->h_PcdDev); + + local_irq_restore(flags); +#else + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "Debug level is too low to dump registers!!!\n"); + local_irq_restore(flags); + +#endif /* (defined(DEBUG_ERRORS) && ... */ + + return n; +} + +static DEVICE_ATTR(fm_regs, S_IRUGO, show_fm_regs, NULL); +static DEVICE_ATTR(fm_pcd_regs, S_IRUGO, show_pcd_regs, NULL); + +int fm_sysfs_create(struct device *dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + + if (dev == NULL) + return -EIO; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + + /* store to remove them when module is disabled */ + p_LnxWrpFmDev->dev_attr_regs = &dev_attr_fm_regs; + p_LnxWrpFmDev->dev_pcd_attr_regs = &dev_attr_fm_pcd_regs; + + /* Create sysfs statistics group for FM module */ + if (sysfs_create_group(&dev->kobj, &fm_dev_stats_attr_grp) != 0) + return -EIO; + + /* Registers dump entry - in future will be moved to debugfs */ + if (device_create_file(dev, &dev_attr_fm_regs) != 0 || + device_create_file(dev, &dev_attr_fm_pcd_regs) != 0) + return -EIO; + + return 0; +} + +void fm_sysfs_destroy(struct device *dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + + if (WARN_ON(dev == NULL)) + return; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return; + + sysfs_remove_group(&dev->kobj, &fm_dev_stats_attr_grp); + device_remove_file(dev, p_LnxWrpFmDev->dev_attr_regs); + device_remove_file(dev, p_LnxWrpFmDev->dev_pcd_attr_regs); +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_fm.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_fm.h @@ -0,0 +1,257 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_fm.h + + @Author Shlomi Gridish + + @Description FM Linux wrapper functions. + +*/ + +#ifndef __LNXWRP_FM_H__ +#define __LNXWRP_FM_H__ + +#include /* struct qman_fq */ + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "lnxwrp_fm_ext.h" + +#define __ERR_MODULE__ MODULE_FM + +#define FM_MAX_NUM_OF_ADV_SETTINGS 10 + +#define LNXWRP_FM_NUM_OF_SHARED_PROFILES 16 + +#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) +#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */ +#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */ +#else +#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */ +#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */ +#endif +#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */ +#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */ + +typedef enum { + e_NO_PCD = 0, + e_FM_PCD_3_TUPLE +} e_LnxWrpFmPortPcdDefUseCase; + + +typedef struct t_FmTestFq { + struct qman_fq fq_base; + t_Handle h_Arg; +} t_FmTestFq; + +typedef struct { + uint8_t id; /* sw port id, see SW_PORT_ID_TO_HW_PORT_ID() in fm_common.h */ + int minor; + char name[20]; + bool active; + uint64_t phys_baseAddr; + uint64_t baseAddr; /* Port's *virtual* address */ + uint32_t memSize; + t_WrpFmPortDevSettings settings; + uint8_t totalNumOfSchemes; + uint8_t schemesBase; + uint8_t numOfSchemesUsed; + uint32_t pcdBaseQ; + uint16_t pcdNumOfQs; + struct fm_port_pcd_param pcd_owner_params; + e_LnxWrpFmPortPcdDefUseCase defPcd; + t_Handle h_DefNetEnv; + t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; + t_FmPortBufferPrefixContent buffPrefixContent; + t_Handle h_Dev; + t_Handle h_LnxWrpFmDev; + uint16_t txCh; + struct device *dev; + struct device_attribute *dev_attr_stats; + struct device_attribute *dev_attr_regs; +} t_LnxWrpFmPortDev; + +typedef struct { + uint8_t id; + bool active; + uint64_t baseAddr; + uint32_t memSize; + t_WrpFmMacDevSettings settings; + t_Handle h_Dev; + t_Handle h_LnxWrpFmDev; +} t_LnxWrpFmMacDev; + +/* information about all active ports for an FMan. + * !Some ports may be disabled by u-boot, thus will not be available */ +struct fm_active_ports { + uint32_t num_oh_ports; + uint32_t num_tx_ports; + uint32_t num_rx_ports; + uint32_t num_tx25_ports; + uint32_t num_rx25_ports; + uint32_t num_tx10_ports; + uint32_t num_rx10_ports; +}; + +/* FMan resources precalculated at fm probe based + * on available FMan port. */ +struct fm_resource_settings { + /* buffers - fifo sizes */ + uint32_t tx1g_num_buffers; + uint32_t rx1g_num_buffers; + uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */ + uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */ + uint32_t tx10g_num_buffers; + uint32_t rx10g_num_buffers; + uint32_t oh_num_buffers; + uint32_t shared_ext_buffers; + + /* open DMAs */ + uint32_t tx_1g_dmas; + uint32_t rx_1g_dmas; + uint32_t tx_2g5_dmas; /* Not supported yet by LLD */ + uint32_t rx_2g5_dmas; /* Not supported yet by LLD */ + uint32_t tx_10g_dmas; + uint32_t rx_10g_dmas; + uint32_t oh_dmas; + uint32_t shared_ext_open_dma; + + /* Tnums */ + uint32_t tx_1g_tnums; + uint32_t rx_1g_tnums; + uint32_t tx_2g5_tnums; /* Not supported yet by LLD */ + uint32_t rx_2g5_tnums; /* Not supported yet by LLD */ + uint32_t tx_10g_tnums; + uint32_t rx_10g_tnums; + uint32_t oh_tnums; + uint32_t shared_ext_tnums; +}; + +typedef struct { + uint8_t id; + char name[10]; + bool active; + bool pcdActive; + bool prsActive; + bool kgActive; + bool ccActive; + bool plcrActive; + e_LnxWrpFmPortPcdDefUseCase defPcd; + uint32_t usedSchemes; + uint8_t totalNumOfSharedSchemes; + uint8_t sharedSchemesBase; + uint8_t numOfSchemesUsed; + uint8_t defNetEnvId; + uint64_t fmPhysBaseAddr; + uint64_t fmBaseAddr; + uint32_t fmMemSize; + uint64_t fmMuramPhysBaseAddr; + uint64_t fmMuramBaseAddr; + uint32_t fmMuramMemSize; + uint64_t fmRtcPhysBaseAddr; + uint64_t fmRtcBaseAddr; + uint32_t fmRtcMemSize; + int irq; + int err_irq; + t_WrpFmDevSettings fmDevSettings; + t_WrpFmPcdDevSettings fmPcdDevSettings; + t_Handle h_Dev; + uint16_t hcCh; + + t_Handle h_MuramDev; + t_Handle h_PcdDev; + t_Handle h_RtcDev; + + t_LnxWrpFmPortDev hcPort; + t_LnxWrpFmPortDev opPorts[FM_MAX_NUM_OF_OH_PORTS-1]; + t_LnxWrpFmPortDev rxPorts[FM_MAX_NUM_OF_RX_PORTS]; + t_LnxWrpFmPortDev txPorts[FM_MAX_NUM_OF_TX_PORTS]; + t_LnxWrpFmMacDev macs[FM_MAX_NUM_OF_MACS]; + struct fm_active_ports fm_active_ports_info; + struct fm_resource_settings fm_resource_settings_info; + + struct device *dev; + struct resource *res; + int major; + struct class *fm_class; + struct device_attribute *dev_attr_stats; + struct device_attribute *dev_attr_regs; + + struct device_attribute *dev_pcd_attr_stats; + struct device_attribute *dev_pcd_attr_regs; + + struct qman_fq *hc_tx_conf_fq, *hc_tx_err_fq, *hc_tx_fq; +} t_LnxWrpFmDev; + +typedef struct { + t_LnxWrpFmDev *p_FmDevs[INTG_MAX_NUM_OF_FM]; +} t_LnxWrpFm; +#define LNXWRP_FM_OBJECT(ptr) LIST_OBJECT(ptr, t_LnxWrpFm, fms[((t_LnxWrpFmDev *)ptr)->id]) + + +t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat); +t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat); + + +static __inline__ t_Error AllocSchemesForPort(t_LnxWrpFmDev *p_LnxWrpFmDev, uint8_t numSchemes, uint8_t *p_BaseSchemeNum) +{ + uint32_t schemeMask; + uint8_t i; + + if (!numSchemes) + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + + schemeMask = 0x80000000; + *p_BaseSchemeNum = 0xff; + + for (i=0; schemeMask && numSchemes; schemeMask>>=1, i++) + if ((p_LnxWrpFmDev->usedSchemes & schemeMask) == 0) + { + p_LnxWrpFmDev->usedSchemes |= schemeMask; + numSchemes--; + if (*p_BaseSchemeNum==0xff) + *p_BaseSchemeNum = i; + } + else if (*p_BaseSchemeNum!=0xff) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Fragmentation on schemes array!!!")); + + if (numSchemes) + RETURN_ERROR(MINOR, E_FULL, ("schemes!!!")); + return E_OK; +} + + +#endif /* __LNXWRP_FM_H__ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/wrapper/lnxwrp_sysfs.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + + @File lnxwrp_sysfs.c + + @Description FM wrapper sysfs related functions. + +*/ + +#include +#include "lnxwrp_sysfs.h" + +uint8_t fm_find_statistic_counter_by_name(const char *attr_name, + struct SysfsStats_t *sysfs_stats, + uint8_t *offset) +{ + int i = 0; + + while (sysfs_stats[i].statisticName != NULL) { + if (strcmp(sysfs_stats[i].statisticName, attr_name) == 0) { + if (offset != NULL) + *offset = i; + return sysfs_stats[i].statisticCounter; + } + + i++; + } + WARN(1, "FMD: Should never get here!"); + return 0; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/system/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/system/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk +# + +obj-y += sys_io.o --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/src/system/sys_io.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/src/system/sys_io.c @@ -0,0 +1,171 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#include +#else +#include +#endif /* LINUX_VERSION_CODE */ +#endif /* MODVERSIONS */ + +#include +#include + +#include + +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "list_ext.h" +#include "sys_io_ext.h" + + +#define __ERR_MODULE__ MODULE_UNKNOWN + + +typedef struct { + uint64_t virtAddr; + uint64_t physAddr; + uint32_t size; + t_List node; +} t_IoMap; +#define IOMAP_OBJECT(ptr) LIST_OBJECT(ptr, t_IoMap, node) + +LIST(mapsList); + + +static void EnqueueIoMap(t_IoMap *p_IoMap) +{ + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + LIST_AddToTail(&p_IoMap->node, &mapsList); + XX_RestoreAllIntr(intFlags); +} + +static t_IoMap * FindIoMapByVirtAddr(uint64_t addr) +{ + t_IoMap *p_IoMap; + t_List *p_Pos; + + LIST_FOR_EACH(p_Pos, &mapsList) + { + p_IoMap = IOMAP_OBJECT(p_Pos); + if ((addr >= p_IoMap->virtAddr) && (addr < p_IoMap->virtAddr+p_IoMap->size)) + return p_IoMap; + } + + return NULL; +} + +static t_IoMap * FindIoMapByPhysAddr(uint64_t addr) +{ + t_IoMap *p_IoMap; + t_List *p_Pos; + + LIST_FOR_EACH(p_Pos, &mapsList) + { + p_IoMap = IOMAP_OBJECT(p_Pos); + if ((addr >= p_IoMap->physAddr) && (addr < p_IoMap->physAddr+p_IoMap->size)) + return p_IoMap; + } + + return NULL; +} + +t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size) +{ + t_IoMap *p_IoMap; + + p_IoMap = (t_IoMap*)XX_Malloc(sizeof(t_IoMap)); + if (!p_IoMap) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!")); + memset(p_IoMap, 0, sizeof(t_IoMap)); + + p_IoMap->virtAddr = virtAddr; + p_IoMap->physAddr = physAddr; + p_IoMap->size = size; + + INIT_LIST(&p_IoMap->node); + EnqueueIoMap(p_IoMap); + + return E_OK; +} + +t_Error SYS_UnregisterIoMap (uint64_t virtAddr) +{ + t_IoMap *p_IoMap = FindIoMapByVirtAddr(virtAddr); + if (!p_IoMap) + RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); + + LIST_Del(&p_IoMap->node); + XX_Free(p_IoMap); + + return E_OK; +} + +uint64_t SYS_PhysToVirt(uint64_t addr) +{ + t_IoMap *p_IoMap = FindIoMapByPhysAddr(addr); + if (p_IoMap) + { + /* This is optimization - put the latest in the list-head - like a cache */ + if (mapsList.p_Next != &p_IoMap->node) + { + uint32_t intFlags = XX_DisableAllIntr(); + LIST_DelAndInit(&p_IoMap->node); + LIST_Add(&p_IoMap->node, &mapsList); + XX_RestoreAllIntr(intFlags); + } + return (uint64_t)(addr - p_IoMap->physAddr + p_IoMap->virtAddr); + } + return PTR_TO_UINT(phys_to_virt((unsigned long)addr)); +} + +uint64_t SYS_VirtToPhys(uint64_t addr) +{ + t_IoMap *p_IoMap; + + if (addr == 0) + return 0; + + p_IoMap = FindIoMapByVirtAddr(addr); + if (p_IoMap) + return (uint64_t)(addr - p_IoMap->virtAddr + p_IoMap->physAddr); + return (uint64_t)virt_to_phys(UINT_TO_PTR(addr)); +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/fm.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/fm.h @@ -0,0 +1,699 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm.h + + @Description FM internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_H +#define __FM_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_ext.h" +#include "fm_ipc.h" + + +#define __ERR_MODULE__ MODULE_FM + +#define FM_MAX_NUM_OF_HW_PORT_IDS 64 +#define FM_MAX_NUM_OF_GUESTS 100 + +/**************************************************************************//** + @Description Exceptions +*//***************************************************************************/ +#define FM_EX_DMA_BUS_ERROR 0x80000000 /**< DMA bus error. */ +#define FM_EX_DMA_READ_ECC 0x40000000 +#define FM_EX_DMA_SYSTEM_WRITE_ECC 0x20000000 +#define FM_EX_DMA_FM_WRITE_ECC 0x10000000 +#define FM_EX_FPM_STALL_ON_TASKS 0x08000000 /**< Stall of tasks on FPM */ +#define FM_EX_FPM_SINGLE_ECC 0x04000000 /**< Single ECC on FPM */ +#define FM_EX_FPM_DOUBLE_ECC 0x02000000 +#define FM_EX_QMI_SINGLE_ECC 0x01000000 /**< Single ECC on FPM */ +#define FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID 0x00800000 /**< Dequeu from default queue id */ +#define FM_EX_QMI_DOUBLE_ECC 0x00400000 +#define FM_EX_BMI_LIST_RAM_ECC 0x00200000 +#define FM_EX_BMI_PIPELINE_ECC 0x00100000 +#define FM_EX_BMI_STATISTICS_RAM_ECC 0x00080000 +#define FM_EX_IRAM_ECC 0x00040000 +#define FM_EX_NURAM_ECC 0x00020000 +#define FM_EX_BMI_DISPATCH_RAM_ECC 0x00010000 + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch(exception){ \ + case e_FM_EX_DMA_BUS_ERROR: \ + bitMask = FM_EX_DMA_BUS_ERROR; break; \ + case e_FM_EX_DMA_READ_ECC: \ + bitMask = FM_EX_DMA_READ_ECC; break; \ + case e_FM_EX_DMA_SYSTEM_WRITE_ECC: \ + bitMask = FM_EX_DMA_SYSTEM_WRITE_ECC; break; \ + case e_FM_EX_DMA_FM_WRITE_ECC: \ + bitMask = FM_EX_DMA_FM_WRITE_ECC; break; \ + case e_FM_EX_FPM_STALL_ON_TASKS: \ + bitMask = FM_EX_FPM_STALL_ON_TASKS; break; \ + case e_FM_EX_FPM_SINGLE_ECC: \ + bitMask = FM_EX_FPM_SINGLE_ECC; break; \ + case e_FM_EX_FPM_DOUBLE_ECC: \ + bitMask = FM_EX_FPM_DOUBLE_ECC; break; \ + case e_FM_EX_QMI_SINGLE_ECC: \ + bitMask = FM_EX_QMI_SINGLE_ECC; break; \ + case e_FM_EX_QMI_DOUBLE_ECC: \ + bitMask = FM_EX_QMI_DOUBLE_ECC; break; \ + case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: \ + bitMask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID; break; \ + case e_FM_EX_BMI_LIST_RAM_ECC: \ + bitMask = FM_EX_BMI_LIST_RAM_ECC; break; \ + case e_FM_EX_BMI_PIPELINE_ECC: \ + bitMask = FM_EX_BMI_PIPELINE_ECC; break; \ + case e_FM_EX_BMI_STATISTICS_RAM_ECC: \ + bitMask = FM_EX_BMI_STATISTICS_RAM_ECC; break; \ + case e_FM_EX_BMI_DISPATCH_RAM_ECC: \ + bitMask = FM_EX_BMI_DISPATCH_RAM_ECC; break; \ + case e_FM_EX_IRAM_ECC: \ + bitMask = FM_EX_IRAM_ECC; break; \ + case e_FM_EX_MURAM_ECC: \ + bitMask = FM_EX_NURAM_ECC; break; \ + default: bitMask = 0;break;} + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ +#define DEFAULT_exceptions (FM_EX_DMA_BUS_ERROR |\ + FM_EX_DMA_READ_ECC |\ + FM_EX_DMA_SYSTEM_WRITE_ECC |\ + FM_EX_DMA_FM_WRITE_ECC |\ + FM_EX_FPM_STALL_ON_TASKS |\ + FM_EX_FPM_SINGLE_ECC |\ + FM_EX_FPM_DOUBLE_ECC |\ + FM_EX_QMI_SINGLE_ECC |\ + FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID|\ + FM_EX_QMI_DOUBLE_ECC |\ + FM_EX_BMI_LIST_RAM_ECC |\ + FM_EX_BMI_PIPELINE_ECC |\ + FM_EX_BMI_STATISTICS_RAM_ECC |\ + FM_EX_BMI_DISPATCH_RAM_ECC |\ + FM_EX_IRAM_ECC |\ + FM_EX_NURAM_ECC ) +#define DEFAULT_totalNumOfTasks (BMI_MAX_NUM_OF_TASKS*3/4) +#define DEFAULT_totalFifoSize (BMI_MAX_FIFO_SIZE*3/4) +#define DEFAULT_maxNumOfOpenDmas (BMI_MAX_NUM_OF_DMAS*3/4) +#define DEFAULT_eccEnable FALSE +#define DEFAULT_dispLimit 0 +#define DEFAULT_prsDispTh 16 +#define DEFAULT_plcrDispTh 16 +#define DEFAULT_kgDispTh 16 +#define DEFAULT_bmiDispTh 16 +#define DEFAULT_qmiEnqDispTh 16 +#define DEFAULT_qmiDeqDispTh 16 +#define DEFAULT_fmCtl1DispTh 16 +#define DEFAULT_fmCtl2DispTh 16 +#define DEFAULT_cacheOverride e_FM_DMA_NO_CACHE_OR +#ifdef FM_PEDANTIC_DMA +#define DEFAULT_aidOverride TRUE +#else +#define DEFAULT_aidOverride FALSE +#endif /* FM_PEDANTIC_DMA */ +#define DEFAULT_aidMode e_FM_DMA_AID_OUT_TNUM +#define DEFAULT_dmaStopOnBusError FALSE +#define DEFAULT_stopAtBusError FALSE +#define DEFAULT_axiDbgNumOfBeats 1 +#define DEFAULT_dmaCamNumOfEntries 32 +#define DEFAULT_dmaCommQLow ((DMA_THRESH_MAX_COMMQ+1)/2) +#define DEFAULT_dmaCommQHigh ((DMA_THRESH_MAX_COMMQ+1)*3/4) +#define DEFAULT_dmaReadIntBufLow ((DMA_THRESH_MAX_BUF+1)/2) +#define DEFAULT_dmaReadIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4) +#define DEFAULT_dmaWriteIntBufLow ((DMA_THRESH_MAX_BUF+1)/2) +#define DEFAULT_dmaWriteIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4) +#define DEFAULT_dmaSosEmergency 0 +#define DEFAULT_dmaDbgCntMode e_FM_DMA_DBG_NO_CNT +#define DEFAULT_catastrophicErr e_FM_CATASTROPHIC_ERR_STALL_PORT +#define DEFAULT_dmaErr e_FM_DMA_ERR_CATASTROPHIC +#define DEFAULT_resetOnInit FALSE +#define DEFAULT_haltOnExternalActivation FALSE /* do not change! if changed, must be disabled for rev1 ! */ +#define DEFAULT_haltOnUnrecoverableEccError FALSE /* do not change! if changed, must be disabled for rev1 ! */ +#define DEFAULT_externalEccRamsEnable FALSE +#define DEFAULT_VerifyUcode FALSE +#define DEFAULT_tnumAgingPeriod 0 +#define DEFAULT_dmaWatchdog 0 /* disabled */ +#define DEFAULT_mtu 9600 + +/**************************************************************************//** + @Description Modules registers offsets +*//***************************************************************************/ +#define FM_MM_MURAM 0x00000000 +#define FM_MM_BMI 0x00080000 +#define FM_MM_QMI 0x00080400 +#define FM_MM_PRS 0x000c7000 +#define FM_MM_KG 0x000C1000 +#define FM_MM_DMA 0x000C2000 +#define FM_MM_FPM 0x000C3000 +#define FM_MM_PLCR 0x000C0000 +#define FM_MM_IMEM 0x000C4000 + +/**************************************************************************//** + @Description Interrupt Enable/Mask +*//***************************************************************************/ + +/**************************************************************************//** + @Description Memory Mapped Registers +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +typedef _Packed struct +{ + volatile uint32_t fpmtnc; /**< FPM TNUM Control */ + volatile uint32_t fpmpr; /**< FPM Port_ID FmCtl Association */ + volatile uint32_t brkc; /**< FPM Breakpoint Control */ + volatile uint32_t fpmflc; /**< FPM Flush Control */ + volatile uint32_t fpmdis1; /**< FPM Dispatch Thresholds1 */ + volatile uint32_t fpmdis2; /**< FPM Dispatch Thresholds2 */ + volatile uint32_t fmepi; /**< FM Error Pending Interrupts */ + volatile uint32_t fmrie; /**< FM Error Interrupt Enable */ + volatile uint32_t fmfpfcev[4]; /**< FPM FMan-Controller Event 1-4 */ + volatile uint8_t res1[16]; /**< reserved */ + volatile uint32_t fmfpfcee[4]; /**< PM FMan-Controller Event 1-4 */ + volatile uint8_t res2[16]; /**< reserved */ + volatile uint32_t fpmtsc1; /**< FPM TimeStamp Control1 */ + volatile uint32_t fpmtsc2; /**< FPM TimeStamp Control2 */ + volatile uint32_t fpmtsp; /**< FPM Time Stamp */ + volatile uint32_t fpmtsf; /**< FPM Time Stamp Fraction */ + volatile uint32_t fmrcr; /**< FM Rams Control */ + volatile uint32_t fpmextc; /**< FPM External Requests Control */ + volatile uint32_t fpmext1; /**< FPM External Requests Config1 */ + volatile uint32_t fpmext2; /**< FPM External Requests Config2 */ + volatile uint32_t fpmdrd[16]; /**< FPM Data_Ram Data 0-15 */ + volatile uint32_t fpmdra; /**< FPM Data Ram Access */ + volatile uint32_t fm_ip_rev_1; /**< FM IP Block Revision 1 */ + volatile uint32_t fm_ip_rev_2; /**< FM IP Block Revision 2 */ + volatile uint32_t fmrstc; /**< FM Reset Command */ + volatile uint32_t fmcld; /**< FM Classifier Debug */ + volatile uint32_t fmnpi; /**< FM Normal Pending Interrupts */ + volatile uint32_t fmfp_exte; /**< FPM External Requests Enable */ + volatile uint32_t fpmem; /**< FPM Event & Mask */ + volatile uint32_t fpmcev[4]; /**< FPM CPU Event 1-4 */ + volatile uint8_t res4[16]; /**< reserved */ + volatile uint32_t fmfp_ps[0x40]; /**< FPM Port Status */ + volatile uint8_t reserved1[0x260]; + volatile uint32_t fpmts[128]; /**< 0x400: FPM Task Status */ +} _PackedType t_FmFpmRegs; + +#define NUM_OF_DBG_TRAPS 3 + +typedef _Packed struct +{ + volatile uint32_t fmbm_init; /**< BMI Initialization */ + volatile uint32_t fmbm_cfg1; /**< BMI Configuration 1 */ + volatile uint32_t fmbm_cfg2; /**< BMI Configuration 2 */ + volatile uint32_t reserved[5]; + volatile uint32_t fmbm_ievr; /**< Interrupt Event Register */ + volatile uint32_t fmbm_ier; /**< Interrupt Enable Register */ + volatile uint32_t fmbm_ifr; /**< Interrupt Force Register */ + volatile uint32_t reserved1[5]; + volatile uint32_t fmbm_arb[8]; /**< BMI Arbitration */ + volatile uint32_t reserved2[12]; + volatile uint32_t fmbm_dtc[NUM_OF_DBG_TRAPS]; /**< BMI Debug Trap Counter */ + volatile uint32_t reserved3; + volatile uint32_t fmbm_dcv[NUM_OF_DBG_TRAPS][4]; /**< BMI Debug Compare Value */ + volatile uint32_t fmbm_dcm[NUM_OF_DBG_TRAPS][4]; /**< BMI Debug Compare Mask */ + volatile uint32_t fmbm_gde; /**< BMI Global Debug Enable */ + volatile uint32_t fmbm_pp[63]; /**< BMI Port Parameters */ + volatile uint32_t reserved4; + volatile uint32_t fmbm_pfs[63]; /**< BMI Port FIFO Size */ + volatile uint32_t reserved5; + volatile uint32_t fmbm_ppid[63]; /**< Port Partition ID */ +} _PackedType t_FmBmiRegs; + +typedef _Packed struct +{ + volatile uint32_t fmqm_gc; /**< General Configuration Register */ + volatile uint32_t Reserved0; + volatile uint32_t fmqm_eie; /**< Error Interrupt Event Register */ + volatile uint32_t fmqm_eien; /**< Error Interrupt Enable Register */ + volatile uint32_t fmqm_eif; /**< Error Interrupt Force Register */ + volatile uint32_t fmqm_ie; /**< Interrupt Event Register */ + volatile uint32_t fmqm_ien; /**< Interrupt Enable Register */ + volatile uint32_t fmqm_if; /**< Interrupt Force Register */ + volatile uint32_t fmqm_gs; /**< Global Status Register */ + volatile uint32_t fmqm_ts; /**< Task Status Register */ + volatile uint32_t fmqm_etfc; /**< Enqueue Total Frame Counter */ + volatile uint32_t fmqm_dtfc; /**< Dequeue Total Frame Counter */ + volatile uint32_t fmqm_dc0; /**< Dequeue Counter 0 */ + volatile uint32_t fmqm_dc1; /**< Dequeue Counter 1 */ + volatile uint32_t fmqm_dc2; /**< Dequeue Counter 2 */ + volatile uint32_t fmqm_dc3; /**< Dequeue Counter 3 */ + volatile uint32_t fmqm_dfdc; /**< Dequeue FQID from Default Counter */ + volatile uint32_t fmqm_dfcc; /**< Dequeue FQID from Context Counter */ + volatile uint32_t fmqm_dffc; /**< Dequeue FQID from FD Counter */ + volatile uint32_t fmqm_dcc; /**< Dequeue Confirm Counter */ + volatile uint32_t Reserved1a[7]; + volatile uint32_t fmqm_tapc; /**< Tnum Aging Period Control */ + volatile uint32_t fmqm_dmcvc; /**< Dequeue MAC Command Valid Counter */ + volatile uint32_t fmqm_difdcc; /**< Dequeue Invalid FD Command Counter */ + volatile uint32_t fmqm_da1v; /**< Dequeue A1 Valid Counter */ + volatile uint32_t Reserved1b; + volatile uint32_t fmqm_dtc; /**< 0x0080 Debug Trap Counter */ + volatile uint32_t fmqm_efddd; /**< 0x0084 Enqueue Frame Descriptor Dynamic Debug */ + volatile uint32_t Reserved3[2]; + _Packed struct { + volatile uint32_t fmqm_dtcfg1; /**< 0x0090 Debug Trap Configuration 1 Register */ + volatile uint32_t fmqm_dtval1; /**< Debug Trap Value 1 Register */ + volatile uint32_t fmqm_dtm1; /**< Debug Trap Mask 1 Register */ + volatile uint32_t fmqm_dtc1; /**< Debug Trap Counter 1 Register */ + volatile uint32_t fmqm_dtcfg2; /**< Debug Trap Configuration 2 Register */ + volatile uint32_t fmqm_dtval2; /**< Debug Trap Value 2 Register */ + volatile uint32_t fmqm_dtm2; /**< Debug Trap Mask 2 Register */ + volatile uint32_t Reserved1; + } _PackedType dbgTraps[NUM_OF_DBG_TRAPS]; +} _PackedType t_FmQmiRegs; + +typedef _Packed struct +{ + volatile uint32_t fmdmsr; /**< FM DMA status register 0x04 */ + volatile uint32_t fmdmmr; /**< FM DMA mode register 0x08 */ + volatile uint32_t fmdmtr; /**< FM DMA bus threshold register 0x0c */ + volatile uint32_t fmdmhy; /**< FM DMA bus hysteresis register 0x10 */ + volatile uint32_t fmdmsetr; /**< FM DMA SOS emergency Threshold Register 0x14 */ + volatile uint32_t fmdmtah; /**< FM DMA transfer bus address high register 0x18 */ + volatile uint32_t fmdmtal; /**< FM DMA transfer bus address low register 0x1C */ + volatile uint32_t fmdmtcid; /**< FM DMA transfer bus communication ID register 0x20 */ + volatile uint32_t fmdmra; /**< FM DMA bus internal ram address register 0x24 */ + volatile uint32_t fmdmrd; /**< FM DMA bus internal ram data register 0x28 */ + volatile uint32_t fmdmwcr; /**< FM DMA CAM watchdog counter value 0x2C */ + volatile uint32_t fmdmebcr; /**< FM DMA CAM base in MURAM register 0x30 */ + volatile uint32_t fmdmccqdr; /**< FM DMA CAM and CMD Queue Debug register 0x34 */ + volatile uint32_t fmdmccqvr1; /**< FM DMA CAM and CMD Queue Value register #1 0x38 */ + volatile uint32_t fmdmccqvr2; /**< FM DMA CAM and CMD Queue Value register #2 0x3C */ + volatile uint32_t fmdmcqvr3; /**< FM DMA CMD Queue Value register #3 0x40 */ + volatile uint32_t fmdmcqvr4; /**< FM DMA CMD Queue Value register #4 0x44 */ + volatile uint32_t fmdmcqvr5; /**< FM DMA CMD Queue Value register #5 0x48 */ + volatile uint32_t fmdmsefrc; /**< FM DMA Semaphore Entry Full Reject Counter 0x50 */ + volatile uint32_t fmdmsqfrc; /**< FM DMA Semaphore Queue Full Reject Counter 0x54 */ + volatile uint32_t fmdmssrc; /**< FM DMA Semaphore SYNC Reject Counter 0x54 */ + volatile uint32_t fmdmdcr; /**< FM DMA Debug Counter */ + volatile uint32_t fmdmemsr; /**< FM DMA Emrgency Smoother Register */ + volatile uint32_t reserved; + volatile uint32_t fmdmplr[FM_SIZE_OF_LIODN_TABLE/2]; + /**< FM DMA PID-LIODN # register */ +} _PackedType t_FmDmaRegs; + +typedef _Packed struct +{ + volatile uint32_t iadd; /**< FM IRAM instruction address register */ + volatile uint32_t idata; /**< FM IRAM instruction data register */ + volatile uint32_t itcfg; /**< FM IRAM timing config register */ + volatile uint32_t iready; /**< FM IRAM ready register */ + volatile uint8_t res[0x80000-0x10]; +} _PackedType t_FMIramRegs; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/**************************************************************************//** + @Description General defines +*//***************************************************************************/ + +#define FM_DEBUG_STATUS_REGISTER_OFFSET 0x000d1084UL +#define FM_UCODE_DEBUG_INSTRUCTION 0x6ffff805UL + + +/**************************************************************************//** + @Description DMA definitions +*//***************************************************************************/ + +/* masks */ +#define DMA_MODE_AID_OR 0x20000000 +#define DMA_MODE_SBER 0x10000000 +#define DMA_MODE_BER 0x00200000 +#define DMA_MODE_ECC 0x00000020 +#define DMA_MODE_PRIVILEGE_PROT 0x00001000 +#define DMA_MODE_SECURE_PROT 0x00000800 +#define DMA_MODE_EMERGENCY_READ 0x00080000 +#define DMA_MODE_EMERGENCY_WRITE 0x00040000 + +#define DMA_TRANSFER_PORTID_MASK 0xFF000000 +#define DMA_TRANSFER_TNUM_MASK 0x00FF0000 +#define DMA_TRANSFER_LIODN_MASK 0x00000FFF + +#define DMA_HIGH_LIODN_MASK 0x0FFF0000 +#define DMA_LOW_LIODN_MASK 0x00000FFF + +#define DMA_STATUS_CMD_QUEUE_NOT_EMPTY 0x10000000 +#define DMA_STATUS_BUS_ERR 0x08000000 +#define DMA_STATUS_READ_ECC 0x04000000 +#define DMA_STATUS_SYSTEM_WRITE_ECC 0x02000000 +#define DMA_STATUS_FM_WRITE_ECC 0x01000000 +#define DMA_STATUS_SYSTEM_DPEXT_ECC 0x00800000 +#define DMA_STATUS_FM_DPEXT_ECC 0x00400000 +#define DMA_STATUS_SYSTEM_DPDAT_ECC 0x00200000 +#define DMA_STATUS_FM_DPDAT_ECC 0x00100000 +#define DMA_STATUS_FM_SPDAT_ECC 0x00080000 + +#define FM_LIODN_BASE_MASK 0x00000FFF + +/* shifts */ +#define DMA_MODE_CACHE_OR_SHIFT 30 +#define DMA_MODE_BUS_PRI_SHIFT 16 +#define DMA_MODE_AXI_DBG_SHIFT 24 +#define DMA_MODE_CEN_SHIFT 13 +#define DMA_MODE_BUS_PROT_SHIFT 10 +#define DMA_MODE_DBG_SHIFT 7 +#define DMA_MODE_EMERGENCY_LEVEL_SHIFT 6 +#define DMA_MODE_AID_MODE_SHIFT 4 +#define DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS 16 +#define DMA_MODE_MAX_CAM_NUM_OF_ENTRIES 32 + +#define DMA_THRESH_COMMQ_SHIFT 24 +#define DMA_THRESH_READ_INT_BUF_SHIFT 16 + +#define DMA_LIODN_SHIFT 16 + +#define DMA_TRANSFER_PORTID_SHIFT 24 +#define DMA_TRANSFER_TNUM_SHIFT 16 + +/* sizes */ +#define DMA_MAX_WATCHDOG 0xffffffff + +/* others */ +#define DMA_CAM_SIZEOF_ENTRY 0x40 +#define DMA_CAM_ALIGN 0x1000 +#define DMA_CAM_UNITS 8 + + +/**************************************************************************//** + @Description FPM defines +*//***************************************************************************/ + +/* masks */ +#define FPM_EV_MASK_DOUBLE_ECC 0x80000000 +#define FPM_EV_MASK_STALL 0x40000000 +#define FPM_EV_MASK_SINGLE_ECC 0x20000000 +#define FPM_EV_MASK_RELEASE_FM 0x00010000 +#define FPM_EV_MASK_DOUBLE_ECC_EN 0x00008000 +#define FPM_EV_MASK_STALL_EN 0x00004000 +#define FPM_EV_MASK_SINGLE_ECC_EN 0x00002000 +#define FPM_EV_MASK_EXTERNAL_HALT 0x00000008 +#define FPM_EV_MASK_ECC_ERR_HALT 0x00000004 + +#define FPM_RAM_CTL_RAMS_ECC_EN 0x80000000 +#define FPM_RAM_CTL_IRAM_ECC_EN 0x40000000 +#define FPM_RAM_CTL_MURAM_ECC 0x00008000 +#define FPM_RAM_CTL_IRAM_ECC 0x00004000 +#define FPM_RAM_CTL_MURAM_TEST_ECC 0x20000000 +#define FPM_RAM_CTL_IRAM_TEST_ECC 0x10000000 +#define FPM_RAM_CTL_RAMS_ECC_EN_SRC_SEL 0x08000000 + +#define FPM_IRAM_ECC_ERR_EX_EN 0x00020000 +#define FPM_MURAM_ECC_ERR_EX_EN 0x00040000 + +#define FPM_REV1_MAJOR_MASK 0x0000FF00 +#define FPM_REV1_MINOR_MASK 0x000000FF + +#define FPM_REV2_INTEG_MASK 0x00FF0000 +#define FPM_REV2_ERR_MASK 0x0000FF00 +#define FPM_REV2_CFG_MASK 0x000000FF + +#define FPM_TS_FRACTION_MASK 0x0000FFFF +#define FPM_TS_CTL_EN 0x80000000 + +#define FPM_PORT_FM_CTL1 0x00000001 +#define FPM_PORT_FM_CTL2 0x00000002 +#define FPM_PRC_REALSE_STALLED 0x00800000 + +#define FPM_PS_STALLED 0x00800000 +#define FPM_PS_FM_CTL1_SEL 0x80000000 +#define FPM_PS_FM_CTL2_SEL 0x40000000 +#define FPM_PS_FM_CTL_SEL_MASK (FPM_PS_FM_CTL1_SEL | FPM_PS_FM_CTL2_SEL) + +#define FPM_RSTC_FM_RESET 0x80000000 +#define FPM_RSTC_10G0_RESET 0x04000000 +#define FPM_RSTC_1G0_RESET 0x40000000 +#define FPM_RSTC_1G1_RESET 0x20000000 +#define FPM_RSTC_1G2_RESET 0x10000000 +#define FPM_RSTC_1G3_RESET 0x08000000 +#define FPM_RSTC_1G4_RESET 0x02000000 + + +/* shifts */ +#define FPM_DISP_LIMIT_SHIFT 24 + +#define FPM_THR1_PRS_SHIFT 24 +#define FPM_THR1_KG_SHIFT 16 +#define FPM_THR1_PLCR_SHIFT 8 +#define FPM_THR1_BMI_SHIFT 0 + +#define FPM_THR2_QMI_ENQ_SHIFT 24 +#define FPM_THR2_QMI_DEQ_SHIFT 0 +#define FPM_THR2_FM_CTL1_SHIFT 16 +#define FPM_THR2_FM_CTL2_SHIFT 8 + +#define FPM_EV_MASK_CAT_ERR_SHIFT 1 +#define FPM_EV_MASK_DMA_ERR_SHIFT 0 + +#define FPM_REV1_MAJOR_SHIFT 8 +#define FPM_REV1_MINOR_SHIFT 0 + +#define FPM_REV2_INTEG_SHIFT 16 +#define FPM_REV2_ERR_SHIFT 8 +#define FPM_REV2_CFG_SHIFT 0 + +#define FPM_TS_INT_SHIFT 16 + +#define FPM_PORT_FM_CTL_PORTID_SHIFT 24 + +#define FPM_PS_FM_CTL_SEL_SHIFT 30 +#define FPM_PRC_ORA_FM_CTL_SEL_SHIFT 16 + +/* Interrupts defines */ +#define FPM_EVENT_FM_CTL_0 0x00008000 +#define FPM_EVENT_FM_CTL 0x0000FF00 +#define FPM_EVENT_FM_CTL_BRK 0x00000080 + +/* others */ +#define FPM_MAX_DISP_LIMIT 31 + +/**************************************************************************//** + @Description BMI defines +*//***************************************************************************/ +/* masks */ +#define BMI_INIT_START 0x80000000 +#define BMI_ERR_INTR_EN_PIPELINE_ECC 0x80000000 +#define BMI_ERR_INTR_EN_LIST_RAM_ECC 0x40000000 +#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC 0x20000000 +#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC 0x10000000 +#define BMI_NUM_OF_TASKS_MASK 0x3F000000 +#define BMI_NUM_OF_EXTRA_TASKS_MASK 0x000F0000 +#define BMI_NUM_OF_DMAS_MASK 0x00000F00 +#define BMI_NUM_OF_EXTRA_DMAS_MASK 0x0000000F +#define BMI_FIFO_SIZE_MASK 0x000003FF +#define BMI_EXTRA_FIFO_SIZE_MASK 0x03FF0000 +#define BMI_CFG2_DMAS_MASK 0x0000003F + +/* shifts */ +#define BMI_CFG2_TASKS_SHIFT 16 +#define BMI_CFG2_DMAS_SHIFT 0 +#define BMI_CFG1_FIFO_SIZE_SHIFT 16 +#define BMI_FIFO_SIZE_SHIFT 0 +#define BMI_EXTRA_FIFO_SIZE_SHIFT 16 +#define BMI_NUM_OF_TASKS_SHIFT 24 +#define BMI_EXTRA_NUM_OF_TASKS_SHIFT 16 +#define BMI_NUM_OF_DMAS_SHIFT 8 +#define BMI_EXTRA_NUM_OF_DMAS_SHIFT 0 + +/* others */ +#define BMI_FIFO_ALIGN 0x100 + + +/**************************************************************************//** + @Description QMI defines +*//***************************************************************************/ +/* masks */ +#define QMI_CFG_ENQ_EN 0x80000000 +#define QMI_CFG_DEQ_EN 0x40000000 +#define QMI_CFG_EN_COUNTERS 0x10000000 +#define QMI_CFG_SOFT_RESET 0x01000000 +#define QMI_CFG_DEQ_MASK 0x0000003F +#define QMI_CFG_ENQ_MASK 0x00003F00 + +#define QMI_ERR_INTR_EN_DOUBLE_ECC 0x80000000 +#define QMI_ERR_INTR_EN_DEQ_FROM_DEF 0x40000000 +#define QMI_INTR_EN_SINGLE_ECC 0x80000000 + +/* shifts */ +#define QMI_CFG_ENQ_SHIFT 8 +#define QMI_TAPC_TAP 22 + + +/**************************************************************************//** + @Description IRAM defines +*//***************************************************************************/ +/* masks */ +#define IRAM_IADD_AIE 0x80000000 +#define IRAM_READY 0x80000000 + +typedef struct { + void (*f_Isr) (t_Handle h_Arg, uint32_t event); + t_Handle h_SrcHandle; +} t_FmanCtrlIntrSrc; + + +typedef struct +{ + /* uint8_t numOfPartitions; */ + bool resetOnInit; +#ifdef FM_PARTITION_ARRAY + uint16_t liodnBasePerPort[FM_SIZE_OF_LIODN_TABLE]; +#endif + bool enCounters; + t_FmThresholds thresholds; + e_FmDmaCacheOverride dmaCacheOverride; + e_FmDmaAidMode dmaAidMode; + bool dmaAidOverride; + uint8_t dmaAxiDbgNumOfBeats; + uint8_t dmaCamNumOfEntries; + uint32_t dmaWatchdog; + t_FmDmaThresholds dmaCommQThresholds; + t_FmDmaThresholds dmaWriteBufThresholds; + t_FmDmaThresholds dmaReadBufThresholds; + uint32_t dmaSosEmergency; + e_FmDmaDbgCntMode dmaDbgCntMode; + bool dmaStopOnBusError; + bool dmaEnEmergency; + t_FmDmaEmergency dmaEmergency; + bool dmaEnEmergencySmoother; + uint32_t dmaEmergencySwitchCounter; + bool haltOnExternalActivation; + bool haltOnUnrecoverableEccError; + e_FmCatastrophicErr catastrophicErr; + e_FmDmaErr dmaErr; + bool enMuramTestMode; + bool enIramTestMode; + bool externalEccRamsEnable; + uint16_t tnumAgingPeriod; + t_FmPcdFirmwareParams firmware; + bool fwVerify; +} t_FmDriverParam; + +typedef void (t_FmanCtrlIsr)( t_Handle h_Fm, uint32_t event); + +typedef struct +{ +/***************************/ +/* Master/Guest parameters */ +/***************************/ + uint8_t fmId; + e_FmPortType portsTypes[FM_MAX_NUM_OF_HW_PORT_IDS]; + uint16_t fmClkFreq; +/**************************/ +/* Master Only parameters */ +/**************************/ + bool enabledTimeStamp; + uint8_t count1MicroBit; + uint8_t totalNumOfTasks; + uint32_t totalFifoSize; + uint8_t maxNumOfOpenDmas; + uint8_t accumulatedNumOfTasks; + uint32_t accumulatedFifoSize; + uint8_t accumulatedNumOfOpenDmas; +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + uint8_t accumulatedNumOfDeqTnums; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ +#ifdef FM_LOW_END_RESTRICTION + bool lowEndRestriction; +#endif /* FM_LOW_END_RESTRICTION */ + uint32_t exceptions; + int irq; + int errIrq; + bool ramsEccEnable; + bool explicitEnable; + bool internalCall; + uint8_t ramsEccOwners; + uint32_t extraFifoPoolSize; + uint8_t extraTasksPoolSize; + uint8_t extraOpenDmasPoolSize; +#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) + uint16_t macMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS]; +#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) */ + uint16_t macMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS]; +} t_FmStateStruct; + +typedef struct +{ +/***************************/ +/* Master/Guest parameters */ +/***************************/ +/* locals for recovery */ + uintptr_t baseAddr; + +/* un-needed for recovery */ + t_Handle h_Pcd; + char fmModuleName[MODULE_NAME_SIZE]; + char fmIpcHandlerModuleName[FM_MAX_NUM_OF_GUESTS][MODULE_NAME_SIZE]; + t_Handle h_IpcSessions[FM_MAX_NUM_OF_GUESTS]; + t_FmIntrSrc intrMng[e_FM_EV_DUMMY_LAST]; /* FM exceptions user callback */ + uint8_t guestId; +/**************************/ +/* Master Only parameters */ +/**************************/ +/* locals for recovery */ + t_FmFpmRegs *p_FmFpmRegs; + t_FmBmiRegs *p_FmBmiRegs; + t_FmQmiRegs *p_FmQmiRegs; + t_FmDmaRegs *p_FmDmaRegs; + t_FmExceptionsCallback *f_Exception; + t_FmBusErrorCallback *f_BusError; + t_Handle h_App; /* Application handle */ + t_Handle h_Spinlock; + bool recoveryMode; + t_FmStateStruct *p_FmStateStruct; + +/* un-needed for recovery */ + t_FmDriverParam *p_FmDriverParam; + t_Handle h_FmMuram; + uint64_t fmMuramPhysBaseAddr; + bool independentMode; + bool hcPortInitialized; + uintptr_t camBaseAddr; /* save for freeing */ + uintptr_t resAddr; + uintptr_t fifoBaseAddr; /* save for freeing */ + t_FmanCtrlIntrSrc fmanCtrlIntr[FM_NUM_OF_FMAN_CTRL_EVENT_REGS]; /* FM exceptions user callback */ + bool usedEventRegs[FM_NUM_OF_FMAN_CTRL_EVENT_REGS]; +} t_Fm; + + +#endif /* __FM_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/fm.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/fm.c @@ -0,0 +1,4605 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm.c + + @Description FM driver routines implementation. +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "fm_muram_ext.h" + +#include "fm_common.h" +#include "fm_ipc.h" +#include "fm.h" + + +/****************************************/ +/* static functions */ +/****************************************/ + +static volatile bool blockingFlag = FALSE; +static void IpcMsgCompletionCB(t_Handle h_Fm, + uint8_t *p_Msg, + uint8_t *p_Reply, + uint32_t replyLength, + t_Error status) +{ + UNUSED(h_Fm);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status); + blockingFlag = FALSE; +} + +static bool IsFmanCtrlCodeLoaded(t_Fm *p_Fm) +{ + t_FMIramRegs *p_Iram; + + ASSERT_COND(p_Fm); + p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + + return (bool)!!(GET_UINT32(p_Iram->iready) & IRAM_READY); +} + +static t_Error CheckFmParameters(t_Fm *p_Fm) +{ + if (IsFmanCtrlCodeLoaded(p_Fm) && !p_Fm->p_FmDriverParam->resetOnInit) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old FMan CTRL code is loaded; FM must be reset!")); + if(!p_Fm->p_FmDriverParam->dmaAxiDbgNumOfBeats || (p_Fm->p_FmDriverParam->dmaAxiDbgNumOfBeats > DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("axiDbgNumOfBeats has to be in the range 1 - %d", DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)); + if(p_Fm->p_FmDriverParam->dmaCamNumOfEntries % DMA_CAM_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaCamNumOfEntries has to be divisble by %d", DMA_CAM_UNITS)); + if(!p_Fm->p_FmDriverParam->dmaCamNumOfEntries || (p_Fm->p_FmDriverParam->dmaCamNumOfEntries > DMA_MODE_MAX_CAM_NUM_OF_ENTRIES)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaCamNumOfEntries has to be in the range 1 - %d", DMA_MODE_MAX_CAM_NUM_OF_ENTRIES)); + if(p_Fm->p_FmDriverParam->dmaCommQThresholds.assertEmergency > DMA_THRESH_MAX_COMMQ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaCommQThresholds.assertEmergency can not be larger than %d", DMA_THRESH_MAX_COMMQ)); + if(p_Fm->p_FmDriverParam->dmaCommQThresholds.clearEmergency > DMA_THRESH_MAX_COMMQ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaCommQThresholds.clearEmergency can not be larger than %d", DMA_THRESH_MAX_COMMQ)); + if(p_Fm->p_FmDriverParam->dmaCommQThresholds.clearEmergency >= p_Fm->p_FmDriverParam->dmaCommQThresholds.assertEmergency) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaCommQThresholds.clearEmergency must be smaller than dmaCommQThresholds.assertEmergency")); + if(p_Fm->p_FmDriverParam->dmaReadBufThresholds.assertEmergency > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaReadBufThresholds.assertEmergency can not be larger than %d", DMA_THRESH_MAX_BUF)); + if(p_Fm->p_FmDriverParam->dmaReadBufThresholds.clearEmergency > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaReadBufThresholds.clearEmergency can not be larger than %d", DMA_THRESH_MAX_BUF)); + if(p_Fm->p_FmDriverParam->dmaReadBufThresholds.clearEmergency >= p_Fm->p_FmDriverParam->dmaReadBufThresholds.assertEmergency) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaReadBufThresholds.clearEmergency must be smaller than dmaReadBufThresholds.assertEmergency")); + if(p_Fm->p_FmDriverParam->dmaWriteBufThresholds.assertEmergency > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaWriteBufThresholds.assertEmergency can not be larger than %d", DMA_THRESH_MAX_BUF)); + if(p_Fm->p_FmDriverParam->dmaWriteBufThresholds.clearEmergency > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaWriteBufThresholds.clearEmergency can not be larger than %d", DMA_THRESH_MAX_BUF)); + if(p_Fm->p_FmDriverParam->dmaWriteBufThresholds.clearEmergency >= p_Fm->p_FmDriverParam->dmaWriteBufThresholds.assertEmergency) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dmaWriteBufThresholds.clearEmergency must be smaller than dmaWriteBufThresholds.assertEmergency")); + + if(!p_Fm->p_FmStateStruct->fmClkFreq) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fmClkFreq must be set.")); + if (USEC_TO_CLK(p_Fm->p_FmDriverParam->dmaWatchdog, p_Fm->p_FmStateStruct->fmClkFreq) > DMA_MAX_WATCHDOG) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("dmaWatchdog depends on FM clock. dmaWatchdog(in microseconds) * clk (in Mhz), may not exceed 0x08x", DMA_MAX_WATCHDOG)); + +#ifdef FM_PARTITION_ARRAY + { + t_FmRevisionInfo revInfo; + uint8_t i; + + FM_GetRevision(p_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + for (i=0; ip_FmDriverParam->liodnBasePerPort[i] & ~FM_LIODN_BASE_MASK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodn number is out of range")); + } +#endif /* FM_PARTITION_ARRAY */ + + if(p_Fm->p_FmStateStruct->totalFifoSize % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalFifoSize number has to be divisible by %d", BMI_FIFO_UNITS)); + if(!p_Fm->p_FmStateStruct->totalFifoSize || (p_Fm->p_FmStateStruct->totalFifoSize > BMI_MAX_FIFO_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalFifoSize number has to be in the range 256 - %d", BMI_MAX_FIFO_SIZE)); + if(!p_Fm->p_FmStateStruct->totalNumOfTasks || (p_Fm->p_FmStateStruct->totalNumOfTasks > BMI_MAX_NUM_OF_TASKS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalNumOfTasks number has to be in the range 1 - %d", BMI_MAX_NUM_OF_TASKS)); + if(!p_Fm->p_FmStateStruct->maxNumOfOpenDmas || (p_Fm->p_FmStateStruct->maxNumOfOpenDmas > BMI_MAX_NUM_OF_DMAS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfOpenDmas number has to be in the range 1 - %d", BMI_MAX_NUM_OF_DMAS)); + + if(p_Fm->p_FmDriverParam->thresholds.dispLimit > FPM_MAX_DISP_LIMIT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("thresholds.dispLimit can't be greater than %d", FPM_MAX_DISP_LIMIT)); + + if(!p_Fm->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); + if(!p_Fm->f_BusError) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); + + return E_OK; +} + +static void SendIpcIsr(t_Fm *p_Fm, uint32_t macEvent, uint32_t pendingReg) +{ + t_Error err; + t_FmIpcIsr fmIpcIsr; + t_FmIpcMsg msg; + + ASSERT_COND(p_Fm->guestId == NCSW_MASTER_ID); + ASSERT_COND(p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId]); + if (p_Fm->intrMng[macEvent].guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_GUEST_ISR; + fmIpcIsr.pendingReg = pendingReg; + fmIpcIsr.boolErr = FALSE; + memcpy(msg.msgBody, &fmIpcIsr, sizeof(fmIpcIsr)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(fmIpcIsr), + NULL, + NULL, + NULL, + NULL)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + else + p_Fm->intrMng[macEvent].f_Isr(p_Fm->intrMng[macEvent].h_SrcHandle); +} + +static void BmiErrEvent(t_Fm *p_Fm) +{ + uint32_t event, mask, force; + + event = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_ievr); + mask = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier); + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_ifr); + if(force & event) + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ifr, force & ~event); + + + /* clear the acknowledged events */ + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ievr, event); + + if(event & BMI_ERR_INTR_EN_PIPELINE_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_PIPELINE_ECC); + if(event & BMI_ERR_INTR_EN_LIST_RAM_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_LIST_RAM_ECC); + if(event & BMI_ERR_INTR_EN_STATISTICS_RAM_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STATISTICS_RAM_ECC); + if(event & BMI_ERR_INTR_EN_DISPATCH_RAM_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_DISPATCH_RAM_ECC); +} + +static void QmiErrEvent(t_Fm *p_Fm) +{ + uint32_t event, mask, force; + + event = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_eie); + mask = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_eien); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_eif); + if(force & event) + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eif, force & ~event); + + /* clear the acknowledged events */ + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eie, event); + + if(event & QMI_ERR_INTR_EN_DOUBLE_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DOUBLE_ECC); + if(event & QMI_ERR_INTR_EN_DEQ_FROM_DEF) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID); +} + +static void DmaErrEvent(t_Fm *p_Fm) +{ + uint64_t addr=0; + uint32_t status, mask, tmpReg=0; + uint8_t tnum; + uint8_t hardwarePortId; + uint8_t relativePortId; + uint16_t liodn; + + status = GET_UINT32(p_Fm->p_FmDmaRegs->fmdmsr); + mask = GET_UINT32(p_Fm->p_FmDmaRegs->fmdmmr); + + /* get bus error regs befor clearing BER */ + if ((status & DMA_STATUS_BUS_ERR) && (mask & DMA_MODE_BER)) + { + addr = (uint64_t)GET_UINT32(p_Fm->p_FmDmaRegs->fmdmtal); + addr |= ((uint64_t)(GET_UINT32(p_Fm->p_FmDmaRegs->fmdmtah)) << 32); + + /* get information about the owner of that bus error */ + tmpReg = GET_UINT32(p_Fm->p_FmDmaRegs->fmdmtcid); + } + + /* clear set events */ + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmsr, status); + + if ((status & DMA_STATUS_BUS_ERR) && (mask & DMA_MODE_BER)) + { + hardwarePortId = (uint8_t)(((tmpReg & DMA_TRANSFER_PORTID_MASK) >> DMA_TRANSFER_PORTID_SHIFT)); + HW_PORT_ID_TO_SW_PORT_ID(relativePortId, hardwarePortId); + tnum = (uint8_t)((tmpReg & DMA_TRANSFER_TNUM_MASK) >> DMA_TRANSFER_TNUM_SHIFT); + liodn = (uint16_t)(tmpReg & DMA_TRANSFER_LIODN_MASK); + ASSERT_COND(p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] != e_FM_PORT_TYPE_DUMMY); + p_Fm->f_BusError(p_Fm->h_App, p_Fm->p_FmStateStruct->portsTypes[hardwarePortId], relativePortId, addr, tnum, liodn); + } + if(mask & DMA_MODE_ECC) + { + if (status & DMA_STATUS_READ_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_READ_ECC); + if (status & DMA_STATUS_SYSTEM_WRITE_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SYSTEM_WRITE_ECC); + if (status & DMA_STATUS_FM_WRITE_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_FM_WRITE_ECC); + } +} + +static void FpmErrEvent(t_Fm *p_Fm) +{ + uint32_t event; + + event = GET_UINT32(p_Fm->p_FmFpmRegs->fpmem); + + /* clear the all occurred events */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmem, event); + + if((event & FPM_EV_MASK_DOUBLE_ECC) && (event & FPM_EV_MASK_DOUBLE_ECC_EN)) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_DOUBLE_ECC); + if((event & FPM_EV_MASK_STALL) && (event & FPM_EV_MASK_STALL_EN)) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_STALL_ON_TASKS); + if((event & FPM_EV_MASK_SINGLE_ECC) && (event & FPM_EV_MASK_SINGLE_ECC_EN)) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_SINGLE_ECC); +} + +static void MuramErrIntr(t_Fm *p_Fm) +{ + uint32_t event, mask; + + event = GET_UINT32(p_Fm->p_FmFpmRegs->fmrcr); + mask = GET_UINT32(p_Fm->p_FmFpmRegs->fmrie); + + /* clear MURAM event bit */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, event & ~FPM_RAM_CTL_IRAM_ECC); + + ASSERT_COND(event & FPM_RAM_CTL_MURAM_ECC); + ASSERT_COND(event & FPM_RAM_CTL_RAMS_ECC_EN); + + if ((mask & FPM_MURAM_ECC_ERR_EX_EN)) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_MURAM_ECC); +} + +static void IramErrIntr(t_Fm *p_Fm) +{ + uint32_t event, mask; + + event = GET_UINT32(p_Fm->p_FmFpmRegs->fmrcr) ; + mask = GET_UINT32(p_Fm->p_FmFpmRegs->fmrie); + /* clear the acknowledged events (do not clear IRAM event) */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, event & ~FPM_RAM_CTL_MURAM_ECC); + + ASSERT_COND(event & FPM_RAM_CTL_IRAM_ECC); + ASSERT_COND(event & FPM_RAM_CTL_IRAM_ECC_EN); + + if ((mask & FPM_IRAM_ECC_ERR_EX_EN)) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_IRAM_ECC); +} + +static void QmiEvent(t_Fm *p_Fm) +{ + uint32_t event, mask, force; + + event = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_ie); + mask = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_ien); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_if); + if(force & event) + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_if, force & ~event); + + /* clear the acknowledged events */ + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_ie, event); + + if(event & QMI_INTR_EN_SINGLE_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_SINGLE_ECC); +} + +static void UnimplementedIsr(t_Handle h_Arg) +{ + UNUSED(h_Arg); + + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented Isr!")); +} + +static void UnimplementedFmanCtrlIsr(t_Handle h_Arg, uint32_t event) +{ + UNUSED(h_Arg); UNUSED(event); + + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented FmCtl Isr!")); +} + +static void FmEnableTimeStamp(t_Fm *p_Fm) +{ + uint32_t tmpReg; + uint64_t fraction; + uint32_t integer; + uint8_t count1MicroBit = 8; + uint32_t tsFrequency = (uint32_t)(1<p_FmStateStruct->fmClkFreq; + /* we multiply by 2^16 to keep the fraction of the division */ + /* we do not divid back, since we write this value as fraction - see spec */ + fraction = ((tsFrequency << 16) - (integer << 16)*p_Fm->p_FmStateStruct->fmClkFreq)/p_Fm->p_FmStateStruct->fmClkFreq; + /* we check remainder of the division in order to round up if not integer */ + if(((tsFrequency << 16) - (integer << 16)*p_Fm->p_FmStateStruct->fmClkFreq) % p_Fm->p_FmStateStruct->fmClkFreq) + fraction++; + + tmpReg = (integer << FPM_TS_INT_SHIFT) | (uint16_t)fraction; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmtsc2, tmpReg); + + /* enable timestamp with original clock */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmtsc1, FPM_TS_CTL_EN); + + p_Fm->p_FmStateStruct->count1MicroBit = count1MicroBit; + p_Fm->p_FmStateStruct->enabledTimeStamp = TRUE; +} + +static void FreeInitResources(t_Fm *p_Fm) +{ + if (p_Fm->camBaseAddr) + FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr)); + if (p_Fm->fifoBaseAddr) + FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->fifoBaseAddr)); + if (p_Fm->resAddr) + FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->resAddr)); +} + +static t_Error ClearIRam(t_Fm *p_Fm) +{ + t_FMIramRegs *p_Iram; + int i; + + ASSERT_COND(p_Fm); + p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + + /* Enable the auto-increment */ + WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); + while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; + + for (i=0; i < (FM_IRAM_SIZE/4); i++) + WRITE_UINT32(p_Iram->idata, 0xffffffff); + + WRITE_UINT32(p_Iram->iadd, FM_IRAM_SIZE - 4); + CORE_MemoryBarrier(); + while (GET_UINT32(p_Iram->idata) != 0xffffffff) ; + + return E_OK; +} + +static t_Error LoadFmanCtrlCode(t_Fm *p_Fm) +{ + t_FMIramRegs *p_Iram; + int i; + uint32_t tmp; + uint8_t compTo16; + + ASSERT_COND(p_Fm); + p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + + /* Enable the auto-increment */ + WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); + while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; + + for (i=0; i < (p_Fm->p_FmDriverParam->firmware.size / 4); i++) + WRITE_UINT32(p_Iram->idata, p_Fm->p_FmDriverParam->firmware.p_Code[i]); + + compTo16 = (uint8_t)(p_Fm->p_FmDriverParam->firmware.size % 16); + if(compTo16) + for (i=0; i < ((16-compTo16) / 4); i++) + WRITE_UINT32(p_Iram->idata, 0xffffffff); + + WRITE_UINT32(p_Iram->iadd,p_Fm->p_FmDriverParam->firmware.size-4); + while(GET_UINT32(p_Iram->iadd) != (p_Fm->p_FmDriverParam->firmware.size-4)) ; + + /* verify that writing has completed */ + while (GET_UINT32(p_Iram->idata) != p_Fm->p_FmDriverParam->firmware.p_Code[(p_Fm->p_FmDriverParam->firmware.size / 4)-1]) ; + + if (p_Fm->p_FmDriverParam->fwVerify) + { + WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); + while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; + for (i=0; i < (p_Fm->p_FmDriverParam->firmware.size / 4); i++) + if ((tmp=GET_UINT32(p_Iram->idata)) != p_Fm->p_FmDriverParam->firmware.p_Code[i]) + RETURN_ERROR(MAJOR, E_WRITE_FAILED, + ("UCode write error : write 0x%x, read 0x%x", + p_Fm->p_FmDriverParam->firmware.p_Code[i],tmp)); + WRITE_UINT32(p_Iram->iadd, 0x0); + } + + /* Enable patch from IRAM */ + WRITE_UINT32(p_Iram->iready, IRAM_READY); + XX_UDelay(1000); + + DBG(INFO, ("FMan-Controller code (ver %d.%d) loaded to IRAM.", + ((uint8_t *)p_Fm->p_FmDriverParam->firmware.p_Code)[5], + ((uint8_t *)p_Fm->p_FmDriverParam->firmware.p_Code)[7])); + + return E_OK; +} + +static void GuestErrorIsr(t_Fm *p_Fm, uint32_t pending) +{ +#define FM_G_CALL_1G_MAC_ERR_ISR(_id) \ +do { \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\ +} while (0) +#define FM_G_CALL_10G_MAC_ERR_ISR(_id) \ +do { \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\ +} while (0) + + /* error interrupts */ + if (pending & ERR_INTR_EN_1G_MAC0) + FM_G_CALL_1G_MAC_ERR_ISR(0); + if (pending & ERR_INTR_EN_1G_MAC1) + FM_G_CALL_1G_MAC_ERR_ISR(1); + if (pending & ERR_INTR_EN_1G_MAC2) + FM_G_CALL_1G_MAC_ERR_ISR(2); + if (pending & ERR_INTR_EN_1G_MAC3) + FM_G_CALL_1G_MAC_ERR_ISR(3); + if (pending & ERR_INTR_EN_1G_MAC4) + FM_G_CALL_1G_MAC_ERR_ISR(4); + if (pending & ERR_INTR_EN_10G_MAC0) + FM_G_CALL_10G_MAC_ERR_ISR(0); +} + +static void GuestEventIsr(t_Fm *p_Fm, uint32_t pending) +{ +#define FM_G_CALL_1G_MAC_TMR_ISR(_id) \ +do { \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0_TMR+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0_TMR+_id)].h_SrcHandle);\ +} while (0) + + if (pending & INTR_EN_1G_MAC0_TMR) + FM_G_CALL_1G_MAC_TMR_ISR(0); + if (pending & INTR_EN_1G_MAC1_TMR) + FM_G_CALL_1G_MAC_TMR_ISR(1); + if (pending & INTR_EN_1G_MAC2_TMR) + FM_G_CALL_1G_MAC_TMR_ISR(2); + if (pending & INTR_EN_1G_MAC3_TMR) + FM_G_CALL_1G_MAC_TMR_ISR(3); + if (pending & INTR_EN_1G_MAC4_TMR) + FM_G_CALL_1G_MAC_TMR_ISR(4); + if(pending & INTR_EN_TMR) + p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle); +} + + +/****************************************/ +/* Inter-Module functions */ +/****************************************/ +static t_Error FmGuestHandleIpcMsgCB(t_Handle h_Fm, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg; + + UNUSED(p_Reply); + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((msgLength > sizeof(uint32_t)), E_INVALID_VALUE); + +#ifdef DISABLE_SANITY_CHECKS + UNUSED(msgLength); +#endif /* DISABLE_SANITY_CHECKS */ + + ASSERT_COND(p_Msg); + + *p_ReplyLength = 0; + + switch(p_IpcMsg->msgId) + { + case (FM_GUEST_ISR): + { + t_FmIpcIsr ipcIsr; + + memcpy((uint8_t*)&ipcIsr, p_IpcMsg->msgBody, sizeof(t_FmIpcIsr)); + if(ipcIsr.boolErr) + GuestErrorIsr(p_Fm, ipcIsr.pendingReg); + else + GuestEventIsr(p_Fm, ipcIsr.pendingReg); + break; + } + default: + *p_ReplyLength = 0; + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); + } + return E_OK; +} + +static t_Error FmHandleIpcMsgCB(t_Handle h_Fm, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg; + t_FmIpcReply *p_IpcReply = (t_FmIpcReply*)p_Reply; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE); + +#ifdef DISABLE_SANITY_CHECKS + UNUSED(msgLength); +#endif /* DISABLE_SANITY_CHECKS */ + + ASSERT_COND(p_IpcMsg); + + memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_IPC_MAX_REPLY_SIZE)); + *p_ReplyLength = 0; + + switch(p_IpcMsg->msgId) + { + case (FM_GET_SET_PORT_PARAMS): + { + t_FmIpcPortInInitParams ipcInitParams; + t_FmInterModulePortInitParams initParams; + t_FmIpcPhysAddr ipcPhysAddr; + + memcpy((uint8_t*)&ipcInitParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortInInitParams)); + initParams.hardwarePortId = ipcInitParams.hardwarePortId; + initParams.portType = (e_FmPortType)ipcInitParams.enumPortType; + initParams.independentMode = (bool)(ipcInitParams.boolIndependentMode); + initParams.liodnOffset = ipcInitParams.liodnOffset; + initParams.numOfTasks = ipcInitParams.numOfTasks; + initParams.numOfExtraTasks = ipcInitParams.numOfExtraTasks; + initParams.numOfOpenDmas = ipcInitParams.numOfOpenDmas; + initParams.numOfExtraOpenDmas = ipcInitParams.numOfExtraOpenDmas; + initParams.sizeOfFifo = ipcInitParams.sizeOfFifo; + initParams.extraSizeOfFifo = ipcInitParams.extraSizeOfFifo; + initParams.deqPipelineDepth = ipcInitParams.deqPipelineDepth; + initParams.liodnBase = ipcInitParams.liodnBase; + + p_IpcReply->error = (uint32_t)FmGetSetPortParams(h_Fm, &initParams); + ipcPhysAddr.high = initParams.fmMuramPhysBaseAddr.high; + ipcPhysAddr.low = initParams.fmMuramPhysBaseAddr.low; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcPhysAddr, sizeof(t_FmIpcPhysAddr)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPhysAddr); + break; + } + case (FM_SET_SIZE_OF_FIFO): + { + t_FmIpcPortFifoParams ipcPortFifoParams; + t_FmInterModulePortRxPoolsParams rxPoolsParams; + + memcpy((uint8_t*)&ipcPortFifoParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortFifoParams)); + rxPoolsParams.numOfPools = ipcPortFifoParams.numOfPools; + rxPoolsParams.secondLargestBufSize = ipcPortFifoParams.secondLargestBufSize; + rxPoolsParams.largestBufSize = ipcPortFifoParams.largestBufSize; + + p_IpcReply->error = (uint32_t)FmSetSizeOfFifo(h_Fm, ipcPortFifoParams.rsrcParams.hardwarePortId, + (e_FmPortType)ipcPortFifoParams.enumPortType, + (bool)ipcPortFifoParams.boolIndependentMode, + &ipcPortFifoParams.rsrcParams.val, + ipcPortFifoParams.rsrcParams.extra, + ipcPortFifoParams.deqPipelineDepth, + &rxPoolsParams, + (bool)ipcPortFifoParams.boolInitialConfig); + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcPortFifoParams.rsrcParams.val, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_SET_NUM_OF_TASKS): + { + t_FmIpcPortRsrcParams ipcPortRsrcParams; + + memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); + p_IpcReply->error = (uint32_t)FmSetNumOfTasks(h_Fm, ipcPortRsrcParams.hardwarePortId, + (uint8_t)ipcPortRsrcParams.val, + (uint8_t)ipcPortRsrcParams.extra, + (bool)ipcPortRsrcParams.boolInitialConfig); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_SET_NUM_OF_OPEN_DMAS): + { + t_FmIpcPortRsrcParams ipcPortRsrcParams; + + memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); + p_IpcReply->error = (uint32_t)FmSetNumOfOpenDmas(h_Fm, ipcPortRsrcParams.hardwarePortId, + (uint8_t)ipcPortRsrcParams.val, + (uint8_t)ipcPortRsrcParams.extra, + (bool)ipcPortRsrcParams.boolInitialConfig); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_RESUME_STALLED_PORT): + *p_ReplyLength = sizeof(uint32_t); + p_IpcReply->error = (uint32_t)FmResumeStalledPort(h_Fm, p_IpcMsg->msgBody[0]); + break; + case (FM_MASTER_IS_ALIVE): + { + uint8_t guestId = p_IpcMsg->msgBody[0]; + /* build the FM master partition IPC address */ + memset(p_Fm->fmIpcHandlerModuleName[guestId], 0, (sizeof(char)) * MODULE_NAME_SIZE); + if(Sprint (p_Fm->fmIpcHandlerModuleName[guestId], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, guestId) != (guestId<10 ? 6:7)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + p_Fm->h_IpcSessions[guestId] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[guestId], p_Fm->fmModuleName); + if (p_Fm->h_IpcSessions[guestId] == NULL) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Master IPC session for guest %d", guestId)); + *(uint8_t*)(p_IpcReply->replyBody) = 1; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + } + case (FM_IS_PORT_STALLED): + { + bool tmp; + + p_IpcReply->error = (uint32_t)FmIsPortStalled(h_Fm, p_IpcMsg->msgBody[0], &tmp); + *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)tmp; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + } + case (FM_RESET_MAC): + { + t_FmIpcMacParams ipcMacParams; + + memcpy((uint8_t*)&ipcMacParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacParams)); + p_IpcReply->error = (uint32_t)FmResetMac(p_Fm, + (e_FmMacType)(ipcMacParams.enumType), + ipcMacParams.id); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_SET_MAC_MAX_FRAME): + { + t_Error err; + t_FmIpcMacMaxFrameParams ipcMacMaxFrameParams; + + memcpy((uint8_t*)&ipcMacMaxFrameParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacMaxFrameParams)); + if ((err = FmSetMacMaxFrame(p_Fm, + (e_FmMacType)(ipcMacMaxFrameParams.macParams.enumType), + ipcMacMaxFrameParams.macParams.id, + ipcMacMaxFrameParams.maxFrameLength)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } + case (FM_GET_CLK_FREQ): + memcpy(p_IpcReply->replyBody, (uint8_t*)&p_Fm->p_FmStateStruct->fmClkFreq, sizeof(uint16_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint16_t); + break; + case (FM_FREE_PORT): + { + t_FmInterModulePortFreeParams portParams; + t_FmIpcPortFreeParams ipcPortParams; + + memcpy((uint8_t*)&ipcPortParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortFreeParams)); + portParams.hardwarePortId = ipcPortParams.hardwarePortId; + portParams.portType = (e_FmPortType)(ipcPortParams.enumPortType); +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + portParams.deqPipelineDepth = ipcPortParams.deqPipelineDepth; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + FmFreePortParams(h_Fm, &portParams); + break; + } + case (FM_REGISTER_INTR): + { + t_FmIpcRegisterIntr ipcRegIntr; + + memcpy((uint8_t*)&ipcRegIntr, p_IpcMsg->msgBody, sizeof(ipcRegIntr)); + p_Fm->intrMng[ipcRegIntr.event].guestId = ipcRegIntr.guestId; + break; + } +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + case (FM_DUMP_REGS): + { + t_Error err; + if ((err = FM_DumpRegs(h_Fm)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } + case (FM_DUMP_PORT_REGS): + { + t_Error err; + + if ((err = FmDumpPortRegs(h_Fm, p_IpcMsg->msgBody[0])) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } +#endif /* (defined(DEBUG_ERRORS) && ... */ + case (FM_GET_REV): + { + t_FmRevisionInfo revInfo; + t_FmIpcRevisionInfo ipcRevInfo; + + p_IpcReply->error = (uint32_t)FM_GetRevision(h_Fm, &revInfo); + ipcRevInfo.majorRev = revInfo.majorRev; + ipcRevInfo.minorRev = revInfo.minorRev; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcRevInfo, sizeof(t_FmIpcRevisionInfo)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcRevisionInfo); + break; + } + case (FM_DMA_STAT): + { + t_FmDmaStatus dmaStatus; + t_FmIpcDmaStatus ipcDmaStatus; + + FM_GetDmaStatus(h_Fm, &dmaStatus); + ipcDmaStatus.boolCmqNotEmpty = (uint8_t)dmaStatus.cmqNotEmpty; + ipcDmaStatus.boolBusError = (uint8_t)dmaStatus.busError; + ipcDmaStatus.boolReadBufEccError = (uint8_t)dmaStatus.readBufEccError; + ipcDmaStatus.boolWriteBufEccSysError = (uint8_t)dmaStatus.writeBufEccSysError; + ipcDmaStatus.boolWriteBufEccFmError = (uint8_t)dmaStatus.writeBufEccFmError; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcDmaStatus, sizeof(t_FmIpcDmaStatus)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus); + break; + } + case (FM_ALLOC_FMAN_CTRL_EVENT_REG): + p_IpcReply->error = (uint32_t)FmAllocFmanCtrlEventReg(h_Fm, (uint8_t*)p_IpcReply->replyBody); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + case (FM_FREE_FMAN_CTRL_EVENT_REG): + FmFreeFmanCtrlEventReg(h_Fm, p_IpcMsg->msgBody[0]); + break; + case (FM_GET_TIMESTAMP_SCALE): + { + uint32_t timeStamp = FmGetTimeStampScale(h_Fm); + + memcpy(p_IpcReply->replyBody, (uint8_t*)&timeStamp, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_GET_COUNTER): + { + e_FmCounters inCounter; + uint32_t outCounter; + + memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t)); + outCounter = FM_GetCounter(h_Fm, inCounter); + memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_SET_FMAN_CTRL_EVENTS_ENABLE): + { + t_FmIpcFmanEvents ipcFmanEvents; + + memcpy((uint8_t*)&ipcFmanEvents, p_IpcMsg->msgBody, sizeof(t_FmIpcFmanEvents)); + FmSetFmanCtrlIntr(h_Fm, + ipcFmanEvents.eventRegId, + ipcFmanEvents.enableEvents); + break; + } + case (FM_GET_FMAN_CTRL_EVENTS_ENABLE): + { + uint32_t tmp = FmGetFmanCtrlIntr(h_Fm, p_IpcMsg->msgBody[0]); + + memcpy(p_IpcReply->replyBody, (uint8_t*)&tmp, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_GET_PHYS_MURAM_BASE): + { + t_FmPhysAddr physAddr; + t_FmIpcPhysAddr ipcPhysAddr; + + FmGetPhysicalMuramBase(h_Fm, &physAddr); + ipcPhysAddr.high = physAddr.high; + ipcPhysAddr.low = physAddr.low; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcPhysAddr, sizeof(t_FmIpcPhysAddr)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPhysAddr); + break; + } + case (FM_ENABLE_RAM_ECC): + { + t_Error err; + + if (((err = FM_EnableRamsEcc(h_Fm)) != E_OK) || + ((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, TRUE)) != E_OK) || + ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, TRUE)) != E_OK)) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } + case (FM_DISABLE_RAM_ECC): + { + t_Error err; + + if (((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, FALSE)) != E_OK) || + ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, FALSE)) != E_OK) || + ((err = FM_DisableRamsEcc(h_Fm)) != E_OK)) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } + case (FM_SET_NUM_OF_FMAN_CTRL): + { + t_Error err; + t_FmIpcPortNumOfFmanCtrls ipcPortNumOfFmanCtrls; + + memcpy((uint8_t*)&ipcPortNumOfFmanCtrls, p_IpcMsg->msgBody, sizeof(t_FmIpcPortNumOfFmanCtrls)); + if ((err = FmSetNumOfRiscsPerPort(h_Fm, + ipcPortNumOfFmanCtrls.hardwarePortId, + ipcPortNumOfFmanCtrls.numOfFmanCtrls)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + case (FM_10G_TX_ECC_WA): + p_IpcReply->error = (uint32_t)Fm10GTxEccWorkaround(h_Fm, p_IpcMsg->msgBody[0]); + *p_ReplyLength = sizeof(uint32_t); + break; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + default: + *p_ReplyLength = 0; + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); + } + return E_OK; +} + +static void ErrorIsrCB(t_Handle h_Fm) +{ +#define FM_M_CALL_1G_MAC_ERR_ISR(_id) \ + { \ + if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].guestId) \ + SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id), pending); \ + else \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\ + } + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t pending; + + SANITY_CHECK_RETURN(h_Fm, E_INVALID_HANDLE); + + /* error interrupts */ + pending = GET_UINT32(p_Fm->p_FmFpmRegs->fmepi); + if (!pending) + return; + + if(pending & ERR_INTR_EN_BMI) + BmiErrEvent(p_Fm); + if(pending & ERR_INTR_EN_QMI) + QmiErrEvent(p_Fm); + if(pending & ERR_INTR_EN_FPM) + FpmErrEvent(p_Fm); + if(pending & ERR_INTR_EN_DMA) + DmaErrEvent(p_Fm); + if(pending & ERR_INTR_EN_IRAM) + IramErrIntr(p_Fm); + if(pending & ERR_INTR_EN_MURAM) + MuramErrIntr(p_Fm); + if(pending & ERR_INTR_EN_PRS) + p_Fm->intrMng[e_FM_EV_ERR_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PRS].h_SrcHandle); + if(pending & ERR_INTR_EN_PLCR) + p_Fm->intrMng[e_FM_EV_ERR_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PLCR].h_SrcHandle); + if(pending & ERR_INTR_EN_KG) + p_Fm->intrMng[e_FM_EV_ERR_KG].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_KG].h_SrcHandle); + + /* MAC events may belong to different partitions */ + if(pending & ERR_INTR_EN_1G_MAC0) + FM_M_CALL_1G_MAC_ERR_ISR(0); + if(pending & ERR_INTR_EN_1G_MAC1) + FM_M_CALL_1G_MAC_ERR_ISR(1); + if(pending & ERR_INTR_EN_1G_MAC2) + FM_M_CALL_1G_MAC_ERR_ISR(2); + if(pending & ERR_INTR_EN_1G_MAC3) + FM_M_CALL_1G_MAC_ERR_ISR(3); + if(pending & ERR_INTR_EN_1G_MAC4) + FM_M_CALL_1G_MAC_ERR_ISR(4); + if(pending & ERR_INTR_EN_10G_MAC0) + { + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_ERR_10G_MAC0].guestId) + SendIpcIsr(p_Fm, e_FM_EV_ERR_10G_MAC0, pending); + else + p_Fm->intrMng[e_FM_EV_ERR_10G_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_10G_MAC0].h_SrcHandle); + } +} + + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + int timeout = 1000; + t_Error err = E_OK; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + uint8_t rxHardwarePortId, txHardwarePortId; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_10G_TX_ECC_WA; + msg.msgBody[0] = macId; + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(macId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + + SANITY_CHECK_RETURN_ERROR((macId == 0), E_NOT_SUPPORTED); + SANITY_CHECK_RETURN_ERROR(IsFmanCtrlCodeLoaded(p_Fm), E_INVALID_STATE); + + SW_PORT_ID_TO_HW_PORT_ID(rxHardwarePortId, e_FM_PORT_TYPE_RX_10G, macId); + SW_PORT_ID_TO_HW_PORT_ID(txHardwarePortId, e_FM_PORT_TYPE_TX_10G, macId); + if ((p_Fm->p_FmStateStruct->portsTypes[rxHardwarePortId] != e_FM_PORT_TYPE_DUMMY) || + (p_Fm->p_FmStateStruct->portsTypes[txHardwarePortId] != e_FM_PORT_TYPE_DUMMY)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("MAC should be initialized prior to rx and tx ports!")); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmextc, 0x40000000); + CORE_MemoryBarrier(); + while ((GET_UINT32(p_Fm->p_FmFpmRegs->fpmextc) & 0x40000000) && + --timeout) ; + if (!timeout) + return ERROR_CODE(E_TIMEOUT); + return E_OK; +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + + if(p_Fm->guestId != NCSW_MASTER_ID) + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Guset")); + + return (p_Fm->baseAddr + FM_MM_PRS); +} + +uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + + if(p_Fm->guestId != NCSW_MASTER_ID) + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Guset")); + + return (p_Fm->baseAddr + FM_MM_KG); +} + +uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + + if(p_Fm->guestId != NCSW_MASTER_ID) + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Guset")); + + return (p_Fm->baseAddr + FM_MM_PLCR); +} + +t_Handle FmGetMuramHandle(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL); + + return (p_Fm->h_FmMuram); +} + +void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *p_FmPhysAddr) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + t_FmIpcPhysAddr ipcPhysAddr; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_PHYS_MURAM_BASE; + replyLength = sizeof(uint32_t) + sizeof(t_FmPhysAddr); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmPhysAddr))) + { + REPORT_ERROR(MINOR, E_INVALID_VALUE,("IPC reply length mismatch")); + return; + } + memcpy((uint8_t*)&ipcPhysAddr, reply.replyBody, sizeof(t_FmIpcPhysAddr)); + p_FmPhysAddr->high = ipcPhysAddr.high; + p_FmPhysAddr->low = ipcPhysAddr.low; + return ; + } + + /* General FM driver initialization */ + p_FmPhysAddr->low = (uint32_t)p_Fm->fmMuramPhysBaseAddr; + p_FmPhysAddr->high = (uint8_t)((p_Fm->fmMuramPhysBaseAddr & 0x000000ff00000000LL) >> 32); +} + +t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint8_t i; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_ALLOC_FMAN_CTRL_EVENT_REG; + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + *p_EventId = *(uint8_t*)(reply.replyBody); + + return (t_Error)(reply.error); + } + + for(i=0;iusedEventRegs[i]) + { + p_Fm->usedEventRegs[i] = TRUE; + *p_EventId = i; + break; + } + + if (i==FM_NUM_OF_FMAN_CTRL_EVENT_REGS) + RETURN_ERROR(MAJOR, E_BUSY, ("No resource - Fman controller event register.")); + + return E_OK; +} + +void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + t_FmIpcMsg msg; + + if(((t_Fm *)h_Fm)->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_FREE_FMAN_CTRL_EVENT_REG; + msg.msgBody[0] = eventId; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(eventId), + NULL, + NULL, + NULL, + NULL)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + + ((t_Fm*)h_Fm)->usedEventRegs[eventId] = FALSE; +} + +void FmRegisterIntr(t_Handle h_Fm, + e_FmEventModules module, + uint8_t modId, + e_FmIntrType intrType, + void (*f_Isr) (t_Handle h_Arg), + t_Handle h_Arg) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint8_t event= 0; + t_FmIpcRegisterIntr fmIpcRegisterIntr; + t_Error err; + t_FmIpcMsg msg; + + ASSERT_COND(h_Fm); + + GET_FM_MODULE_EVENT(module, modId,intrType, event); + + /* register in local FM structure */ + ASSERT_COND(event != e_FM_EV_DUMMY_LAST); + p_Fm->intrMng[event].f_Isr = f_Isr; + p_Fm->intrMng[event].h_SrcHandle = h_Arg; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + if(p_Fm->h_IpcSessions[0]) + { + /* register in Master FM structure */ + fmIpcRegisterIntr.event = event; + fmIpcRegisterIntr.guestId = p_Fm->guestId; + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_REGISTER_INTR; + memcpy(msg.msgBody, &fmIpcRegisterIntr, sizeof(fmIpcRegisterIntr)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(fmIpcRegisterIntr), + NULL, + NULL, + NULL, + NULL)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + } + else + DBG(WARNING,("'Register interrupt' - unavailable - No IPC")); + } + +} + +void FmUnregisterIntr(t_Handle h_Fm, + e_FmEventModules module, + uint8_t modId, + e_FmIntrType intrType) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint8_t event= 0; + + ASSERT_COND(h_Fm); + + GET_FM_MODULE_EVENT(module, modId,intrType, event); + + ASSERT_COND(event != e_FM_EV_DUMMY_LAST); + p_Fm->intrMng[event].f_Isr = UnimplementedIsr; + p_Fm->intrMng[event].h_SrcHandle = NULL; +} + +void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmIpcFmanEvents fmanCtrl; + t_Error err; + t_FmIpcMsg msg; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + fmanCtrl.eventRegId = eventRegId; + fmanCtrl.enableEvents = enableEvents; + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_SET_FMAN_CTRL_EVENTS_ENABLE; + memcpy(msg.msgBody, &fmanCtrl, sizeof(fmanCtrl)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(fmanCtrl), + NULL, + NULL, + NULL, + NULL)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + + ASSERT_COND(eventRegId < FM_NUM_OF_FMAN_CTRL_EVENT_REGS); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfpfcee[eventRegId], enableEvents); +} + +uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength, ctrlIntr; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_FMAN_CTRL_EVENTS_ENABLE; + msg.msgBody[0] = eventRegId; + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(eventRegId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return 0; + } + if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) + { + REPORT_ERROR(MINOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return 0; + } + memcpy((uint8_t*)&ctrlIntr, reply.replyBody, sizeof(uint32_t)); + return ctrlIntr; + } + + return GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcee[eventRegId]); +} + +void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Arg, uint32_t event), t_Handle h_Arg) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + ASSERT_COND(eventRegIdguestId != NCSW_MASTER_ID) + { + ASSERT_COND(0); + /* TODO */ + } + + p_Fm->fmanCtrlIntr[eventRegId].f_Isr = f_Isr; + p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = h_Arg; +} + +void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + ASSERT_COND(eventRegIdguestId != NCSW_MASTER_ID) + { + ASSERT_COND(0); + /* TODO */ + } + + p_Fm->fmanCtrlIntr[eventRegId].f_Isr = UnimplementedFmanCtrlIsr; + p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = NULL; +} + +void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + if(p_Fm->h_Pcd) + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("PCD already set")); + + p_Fm->h_Pcd = h_FmPcd; + +} + +void FmUnregisterPcd(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + if(!p_Fm->h_Pcd) + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("No PCD")); + + p_Fm->h_Pcd = NULL; + +} + +t_Handle FmGetPcdHandle(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + return p_Fm->h_Pcd; +} + +uint8_t FmGetId(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0xff); + + return p_Fm->p_FmStateStruct->fmId; +} + +t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, uint8_t hardwarePortId, uint8_t numOfFmanCtrls) +{ + + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg = 0; + t_Error err; + t_FmIpcPortNumOfFmanCtrls params; + t_FmIpcMsg msg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((numOfFmanCtrls > 0) && (numOfFmanCtrls < 3)) , E_INVALID_HANDLE); + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + params.hardwarePortId = hardwarePortId; + params.numOfFmanCtrls = numOfFmanCtrls; + msg.msgId = FM_SET_NUM_OF_FMAN_CTRL; + memcpy(msg.msgBody, ¶ms, sizeof(params)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(params), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; + } + + XX_LockSpinlock(p_Fm->h_Spinlock); + + tmpReg = (uint32_t)(hardwarePortId << FPM_PORT_FM_CTL_PORTID_SHIFT); + + /*TODO - maybe to put CTL# according to another criteria*/ + + if(numOfFmanCtrls == 2) + tmpReg = FPM_PORT_FM_CTL2 | FPM_PORT_FM_CTL1; + + /* order restoration */ + if(hardwarePortId%2) + tmpReg |= (FPM_PORT_FM_CTL1 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PORT_FM_CTL1; + else + tmpReg |= (FPM_PORT_FM_CTL2 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PORT_FM_CTL2; + + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmpr, tmpReg); + XX_UnlockSpinlock(p_Fm->h_Spinlock); + + return E_OK; +} + +t_Error FmGetSetPortParams(t_Handle h_Fm,t_FmInterModulePortInitParams *p_PortParams) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + uint8_t hardwarePortId = p_PortParams->hardwarePortId; + t_FmIpcPortInInitParams portInParams; + t_FmIpcPhysAddr ipcPhysAddr; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + portInParams.hardwarePortId = p_PortParams->hardwarePortId; + portInParams.enumPortType = (uint32_t)p_PortParams->portType; + portInParams.boolIndependentMode = (uint8_t)p_PortParams->independentMode; + portInParams.liodnOffset = p_PortParams->liodnOffset; + portInParams.numOfTasks = p_PortParams->numOfTasks; + portInParams.numOfExtraTasks = p_PortParams->numOfExtraTasks; + portInParams.numOfOpenDmas = p_PortParams->numOfOpenDmas; + portInParams.numOfExtraOpenDmas = p_PortParams->numOfExtraOpenDmas; + portInParams.sizeOfFifo = p_PortParams->sizeOfFifo; + portInParams.extraSizeOfFifo = p_PortParams->extraSizeOfFifo; + portInParams.deqPipelineDepth = p_PortParams->deqPipelineDepth; + portInParams.liodnBase = p_PortParams->liodnBase; + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_SET_PORT_PARAMS; + memcpy(msg.msgBody, &portInParams, sizeof(portInParams)); + replyLength = (sizeof(uint32_t) + sizeof(p_PortParams->fmMuramPhysBaseAddr)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(portInParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(p_PortParams->fmMuramPhysBaseAddr))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)&ipcPhysAddr, reply.replyBody, sizeof(t_FmIpcPhysAddr)); + p_PortParams->fmMuramPhysBaseAddr.high = ipcPhysAddr.high; + p_PortParams->fmMuramPhysBaseAddr.low = ipcPhysAddr.low; + + return (t_Error)(reply.error); + } + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + XX_LockSpinlock(p_Fm->h_Spinlock); + + if(p_PortParams->independentMode) + { + /* set port parameters */ + p_Fm->independentMode = p_PortParams->independentMode; + /* disable dispatch limit */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmflc, 0); + } + + if(p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + { + if(p_Fm->hcPortInitialized) + { + XX_UnlockSpinlock(p_Fm->h_Spinlock); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Only one host command port is allowed.")); + } + else + p_Fm->hcPortInitialized = TRUE; + } + p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = p_PortParams->portType; + + err = FmSetNumOfTasks(p_Fm, p_PortParams->hardwarePortId, p_PortParams->numOfTasks, p_PortParams->numOfExtraTasks, TRUE); + if(err) + { + XX_UnlockSpinlock(p_Fm->h_Spinlock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + if((p_PortParams->portType != e_FM_PORT_TYPE_RX) && (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G)) + /* for transmit & O/H ports */ + { + uint8_t enqTh; + uint8_t deqTh; + bool update = FALSE; + + /* update qmi ENQ/DEQ threshold */ + p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums += p_PortParams->deqPipelineDepth; + tmpReg = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc); + enqTh = (uint8_t)(tmpReg>>8); + /* if enqTh is too big, we reduce it to the max value that is still OK */ + if(enqTh >= (QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums)) + { + enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1); + tmpReg &= ~QMI_CFG_ENQ_MASK; + tmpReg |= ((uint32_t)enqTh << 8); + update = TRUE; + } + + deqTh = (uint8_t)tmpReg; + /* if deqTh is too small, we enlarge it to the min value that is still OK. + deqTh may not be larger than 63 (QMI_MAX_NUM_OF_TNUMS-1). */ + if((deqTh <= p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums) && (deqTh < QMI_MAX_NUM_OF_TNUMS-1)) + { + deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1); + tmpReg &= ~QMI_CFG_DEQ_MASK; + tmpReg |= (uint32_t)deqTh; + update = TRUE; + } + if(update) + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc, tmpReg); + } +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + +#ifdef FM_LOW_END_RESTRICTION + if((hardwarePortId==0x1) || (hardwarePortId==0x29)) + { + if(p_Fm->p_FmStateStruct->lowEndRestriction) + { + XX_UnlockSpinlock(p_Fm->h_Spinlock); + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("OP #0 cannot work with Tx Port #1.")); + } + else + p_Fm->p_FmStateStruct->lowEndRestriction = TRUE; + } +#endif /* FM_LOW_END_RESTRICTION */ + + err = FmSetSizeOfFifo(p_Fm, + p_PortParams->hardwarePortId, + p_PortParams->portType, + p_PortParams->independentMode, + &p_PortParams->sizeOfFifo, + p_PortParams->extraSizeOfFifo, + p_PortParams->deqPipelineDepth, + NULL, + TRUE); + if(err) + { + XX_UnlockSpinlock(p_Fm->h_Spinlock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = FmSetNumOfOpenDmas(p_Fm, p_PortParams->hardwarePortId, p_PortParams->numOfOpenDmas, p_PortParams->numOfExtraOpenDmas, TRUE); + if(err) + { + XX_UnlockSpinlock(p_Fm->h_Spinlock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ppid[hardwarePortId-1], (uint32_t)p_PortParams->liodnOffset); + + tmpReg = (uint32_t)(hardwarePortId << FPM_PORT_FM_CTL_PORTID_SHIFT); + if(p_PortParams->independentMode) + { + if((p_PortParams->portType==e_FM_PORT_TYPE_RX) || (p_PortParams->portType==e_FM_PORT_TYPE_RX_10G)) + tmpReg |= (FPM_PORT_FM_CTL1 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) |FPM_PORT_FM_CTL1; + else + tmpReg |= (FPM_PORT_FM_CTL2 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) |FPM_PORT_FM_CTL2; + } + else + { + tmpReg |= (FPM_PORT_FM_CTL2|FPM_PORT_FM_CTL1); + + /* order restoration */ + if(hardwarePortId%2) + tmpReg |= (FPM_PORT_FM_CTL1 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT); + else + tmpReg |= (FPM_PORT_FM_CTL2 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT); + } + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmpr, tmpReg); + + { +#ifdef FM_PARTITION_ARRAY + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_Fm, &revInfo); + if (revInfo.majorRev >= 2) +#endif /* FM_PARTITION_ARRAY */ + { + /* set LIODN base for this port */ + tmpReg = GET_UINT32(p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2]); + if(hardwarePortId%2) + { + tmpReg &= ~FM_LIODN_BASE_MASK; + tmpReg |= (uint32_t)p_PortParams->liodnBase; + } + else + { + tmpReg &= ~(FM_LIODN_BASE_MASK<< DMA_LIODN_SHIFT); + tmpReg |= (uint32_t)p_PortParams->liodnBase << DMA_LIODN_SHIFT; + } + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], tmpReg); + } + } + + FmGetPhysicalMuramBase(p_Fm, &p_PortParams->fmMuramPhysBaseAddr); + XX_UnlockSpinlock(p_Fm->h_Spinlock); + + return E_OK; +} + +void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + uint8_t hardwarePortId = p_PortParams->hardwarePortId; + uint8_t numOfTasks; + t_Error err; + t_FmIpcPortFreeParams portParams; + t_FmIpcMsg msg; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + portParams.hardwarePortId = p_PortParams->hardwarePortId; + portParams.enumPortType = (uint32_t)p_PortParams->portType; +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + portParams.deqPipelineDepth = p_PortParams->deqPipelineDepth; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_FREE_PORT; + memcpy(msg.msgBody, &portParams, sizeof(portParams)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(portParams), + NULL, + NULL, + NULL, + NULL)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + XX_LockSpinlock(p_Fm->h_Spinlock); + + + if(p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + { + ASSERT_COND(p_Fm->hcPortInitialized); + p_Fm->hcPortInitialized = FALSE; + } + + p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = e_FM_PORT_TYPE_DUMMY; + + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1]); + /* free numOfTasks */ + numOfTasks = (uint8_t)(((tmpReg & BMI_NUM_OF_TASKS_MASK) >> BMI_NUM_OF_TASKS_SHIFT) + 1); + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= numOfTasks); + p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= numOfTasks; + + /* free numOfOpenDmas */ + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= ((tmpReg & BMI_NUM_OF_DMAS_MASK) >> BMI_NUM_OF_DMAS_SHIFT) + 1); + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= (((tmpReg & BMI_NUM_OF_DMAS_MASK) >> BMI_NUM_OF_DMAS_SHIFT) + 1); + + /* update total num of DMA's with committed number of open DMAS, and max uncommitted pool. */ + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg2) & ~BMI_CFG2_DMAS_MASK; + tmpReg |= (uint32_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize - 1) << BMI_CFG2_DMAS_SHIFT; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg2, tmpReg); + + /* free sizeOfFifo */ + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1]); + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= + (((tmpReg & BMI_FIFO_SIZE_MASK) + 1) * BMI_FIFO_UNITS)); + p_Fm->p_FmStateStruct->accumulatedFifoSize -= + (((tmpReg & BMI_FIFO_SIZE_MASK) + 1) * BMI_FIFO_UNITS); + + /* clear registers */ + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], 0); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], 0); + /* WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ppid[hardwarePortId-1], 0); */ + +#ifdef FM_PORT_DISABLED_ERRATA_FMANx9 + /* this errata means that when a port is taken down, other port may not use its + * resources for a while as it may still be using it (in case of reject). + */ + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + XX_UDelay(100000); + } +#endif /* FM_PORT_DISABLED_ERRATA_FMANx9 */ + +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + if((p_PortParams->portType != e_FM_PORT_TYPE_RX) && (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G)) + /* for transmit & O/H ports */ + { + uint8_t enqTh; + uint8_t deqTh; + + tmpReg = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc); + /* update qmi ENQ/DEQ threshold */ + p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums -= p_PortParams->deqPipelineDepth; + + /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller, + so we can enlarge enqTh */ + enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1); + tmpReg &= ~QMI_CFG_ENQ_MASK; + tmpReg |= ((uint32_t)enqTh << QMI_CFG_ENQ_SHIFT); + + /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller, + so we can reduce deqTh */ + deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1); + tmpReg &= ~QMI_CFG_DEQ_MASK; + tmpReg |= (uint32_t)deqTh; + + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc, tmpReg); + } +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + +#ifdef FM_LOW_END_RESTRICTION + if((hardwarePortId==0x1) || (hardwarePortId==0x29)) + p_Fm->p_FmStateStruct->lowEndRestriction = FALSE; +#endif /* FM_LOW_END_RESTRICTION */ + XX_UnlockSpinlock(p_Fm->h_Spinlock); +} + +t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_IS_PORT_STALLED; + msg.msgBody[0] = hardwarePortId; + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(hardwarePortId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + *p_IsStalled = (bool)!!(*(uint8_t*)(reply.replyBody)); + + return (t_Error)(reply.error); + } + + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId]); + *p_IsStalled = (bool)!!(tmpReg & FPM_PS_STALLED); + + return E_OK; +} + +t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + t_Error err; + bool isStalled; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_RESUME_STALLED_PORT; + msg.msgBody[0] = hardwarePortId; + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(hardwarePortId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + + /* Get port status */ + err = FmIsPortStalled(h_Fm, hardwarePortId, &isStalled); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't get port status")); + if (!isStalled) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port is not stalled")); + + tmpReg = (uint32_t)((hardwarePortId << FPM_PORT_FM_CTL_PORTID_SHIFT) | FPM_PRC_REALSE_STALLED); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmpr, tmpReg); + + return E_OK; +} + +t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t bitMask, timeout = 1000; + t_FmIpcMacParams macParams; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + if(p_Fm->h_IpcSessions[0]) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + macParams.id = macId; + macParams.enumType = (uint32_t)type; + msg.msgId = FM_RESET_MAC; + memcpy(msg.msgBody, &macParams, sizeof(macParams)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(macParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + else + if(!p_Fm->p_FmFpmRegs) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("No IPC and no registers address")); + } + + /* Get the relevant bit mask */ + if (type == e_FM_MAC_10G) + { + switch(macId) + { + case(0): + bitMask = FPM_RSTC_10G0_RESET; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Illegal MAC Id")); + } + } + else + { + switch(macId) + { + case(0): + bitMask = FPM_RSTC_1G0_RESET; + break; + case(1): + bitMask = FPM_RSTC_1G1_RESET; + break; + case(2): + bitMask = FPM_RSTC_1G2_RESET; + break; + case(3): + bitMask = FPM_RSTC_1G3_RESET; + break; + case(4): + bitMask = FPM_RSTC_1G4_RESET; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Illegal MAC Id")); + } + } + + /* reset */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrstc, bitMask); + while ((GET_UINT32(p_Fm->p_FmFpmRegs->fmrstc) & bitMask) && + --timeout) ; + if (!timeout) + return ERROR_CODE(E_TIMEOUT); + return E_OK; +} + +t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmIpcMacMaxFrameParams macMaxFrameLengthParams; + t_Error err; + t_FmIpcMsg msg; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + macMaxFrameLengthParams.macParams.id = macId; + macMaxFrameLengthParams.macParams.enumType = (uint32_t)type; + macMaxFrameLengthParams.maxFrameLength = (uint16_t)mtu; + msg.msgId = FM_SET_MAC_MAX_FRAME; + memcpy(msg.msgBody, &macMaxFrameLengthParams, sizeof(macMaxFrameLengthParams)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(macMaxFrameLengthParams), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + +#if (defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)) + if (type == e_FM_MAC_10G) + p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId] = mtu; + else +#else + UNUSED(type); +#endif /* (defined(FM_MAX_NUM_OF_10G_MACS) && ... */ + p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId] = mtu; + + return E_OK; +} + +uint16_t FmGetClockFreq(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + /* for MC environment: this depends on the + * fact that fmClkFreq was properly initialized at "init". */ + return p_Fm->p_FmStateStruct->fmClkFreq; +} + +uint32_t FmGetTimeStampScale(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength, timeStamp; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_TIMESTAMP_SCALE; + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if(replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + memcpy((uint8_t*)&timeStamp, reply.replyBody, sizeof(uint32_t)); + return timeStamp; + } + + if(!p_Fm->p_FmStateStruct->enabledTimeStamp) + FmEnableTimeStamp(p_Fm); + + return p_Fm->p_FmStateStruct->count1MicroBit; +} + +bool FmRamsEccIsExternalCtl(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fmrcr); + if(tmpReg & FPM_RAM_CTL_RAMS_ECC_EN_SRC_SEL) + return TRUE; + else + return FALSE; +} + +t_Error FmEnableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + p_Fm->p_FmStateStruct->ramsEccOwners++; + p_Fm->p_FmStateStruct->internalCall = TRUE; + + return FM_EnableRamsEcc(p_Fm); +} + +t_Error FmDisableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + ASSERT_COND(p_Fm->p_FmStateStruct->ramsEccOwners); + p_Fm->p_FmStateStruct->ramsEccOwners--; + + if(p_Fm->p_FmStateStruct->ramsEccOwners==0) + { + p_Fm->p_FmStateStruct->internalCall = TRUE; + return FM_DisableRamsEcc(p_Fm); + } + return E_OK; +} + +uint8_t FmGetGuestId(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + return p_Fm->guestId; +} + +bool FmIsMaster(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + return (p_Fm->guestId == NCSW_MASTER_ID); +} + +t_Error FmSetSizeOfFifo(t_Handle h_Fm, + uint8_t hardwarePortId, + e_FmPortType portType, + bool independentMode, + uint32_t *p_SizeOfFifo, + uint32_t extraSizeOfFifo, + uint8_t deqPipelineDepth, + t_FmInterModulePortRxPoolsParams *p_RxPoolsParams, + bool initialConfig) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint8_t relativePortId; + uint16_t macMaxFrameLength = 0, oldVal; + uint32_t minFifoSizeRequired = 0, sizeOfFifo, tmpReg = 0; + t_FmIpcPortFifoParams fifoParams; + t_Error err; + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + ASSERT_COND(initialConfig || p_RxPoolsParams); + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + ASSERT_COND(p_RxPoolsParams); + + memset(&fifoParams, 0, sizeof(fifoParams)); + fifoParams.rsrcParams.hardwarePortId = hardwarePortId; + fifoParams.rsrcParams.val = *p_SizeOfFifo; + fifoParams.rsrcParams.extra = extraSizeOfFifo; + fifoParams.enumPortType = (uint32_t)portType; + fifoParams.boolIndependentMode = (uint8_t)independentMode; + fifoParams.deqPipelineDepth = deqPipelineDepth; + fifoParams.numOfPools = p_RxPoolsParams->numOfPools; + fifoParams.secondLargestBufSize = p_RxPoolsParams->secondLargestBufSize; + fifoParams.largestBufSize = p_RxPoolsParams->largestBufSize; + fifoParams.boolInitialConfig = (uint8_t)initialConfig; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_SET_SIZE_OF_FIFO; + memcpy(msg.msgBody, &fifoParams, sizeof(fifoParams)); + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(fifoParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)p_SizeOfFifo, reply.replyBody, sizeof(uint32_t)); + + return (t_Error)(reply.error); + } + sizeOfFifo = *p_SizeOfFifo; + /* if neseccary (cases where frame length is relevant), update sizeOfFifo field. */ + if((portType == e_FM_PORT_TYPE_TX) || ((portType == e_FM_PORT_TYPE_RX) && independentMode)) + { + HW_PORT_ID_TO_SW_PORT_ID(relativePortId, hardwarePortId); + ASSERT_COND(relativePortId < FM_MAX_NUM_OF_1G_MACS); + macMaxFrameLength = p_Fm->p_FmStateStruct->macMaxFrameLengths1G[relativePortId]; + } + +#if (defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)) + if((portType == e_FM_PORT_TYPE_TX_10G) || ((portType == e_FM_PORT_TYPE_RX_10G) && independentMode)) + { + HW_PORT_ID_TO_SW_PORT_ID(relativePortId, hardwarePortId); + ASSERT_COND(relativePortId < FM_MAX_NUM_OF_10G_MACS); + macMaxFrameLength = p_Fm->p_FmStateStruct->macMaxFrameLengths10G[relativePortId]; + } +#endif /* (defined(FM_MAX_NUM_OF_10G_MACS) && ... */ + + /*************************/ + /* TX PORTS */ + /*************************/ + if((portType == e_FM_PORT_TYPE_TX) || (portType == e_FM_PORT_TYPE_TX_10G)) + { + if(independentMode) + minFifoSizeRequired = (uint32_t)((macMaxFrameLength % BMI_FIFO_UNITS ? + (macMaxFrameLength/BMI_FIFO_UNITS + 1) * BMI_FIFO_UNITS : + macMaxFrameLength) + + (3*BMI_FIFO_UNITS)); + else + minFifoSizeRequired = (uint32_t)((macMaxFrameLength % BMI_FIFO_UNITS ? + (macMaxFrameLength/BMI_FIFO_UNITS + 1) * BMI_FIFO_UNITS : + macMaxFrameLength) + + (deqPipelineDepth+3)*BMI_FIFO_UNITS); + } + /*************************/ + /* RX IM PORTS */ + /*************************/ + else if(((portType == e_FM_PORT_TYPE_RX) || (portType == e_FM_PORT_TYPE_RX_10G)) && independentMode) + minFifoSizeRequired = (uint32_t)(((macMaxFrameLength % BMI_FIFO_UNITS) ? + ((macMaxFrameLength/BMI_FIFO_UNITS + 1) * BMI_FIFO_UNITS) : + macMaxFrameLength) + + (4*BMI_FIFO_UNITS)); + + /* for Rx (non-Im) ports or OP, buffer pools are relevant for fifo size. + If this routine is called as part of the "GetSet" routine, initialConfig is TRUE + and these checks where done in the port routine. + If it is called by an explicit user request ("SetSizeOfFifo"), than these parameters + should be checked/updated */ + if(!initialConfig && + ((portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || + (((portType == e_FM_PORT_TYPE_RX) || (portType == e_FM_PORT_TYPE_RX_10G)) && !independentMode))) + { + if((portType == e_FM_PORT_TYPE_RX) || (portType == e_FM_PORT_TYPE_RX_10G)) + { + /*************************/ + /* RX non-IM PORTS */ + /*************************/ +#ifdef FM_FIFO_ALLOCATION_OLD_ALG + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_Fm, &revInfo); + if(revInfo.majorRev != 4) + minFifoSizeRequired = (uint32_t)(((p_RxPoolsParams->largestBufSize % BMI_FIFO_UNITS) ? + ((p_RxPoolsParams->largestBufSize/BMI_FIFO_UNITS + 1) * BMI_FIFO_UNITS) : + p_RxPoolsParams->largestBufSize) + + (7*BMI_FIFO_UNITS)); + else +#endif /* FM_FIFO_ALLOCATION_OLD_ALG */ + { + if(p_RxPoolsParams->numOfPools == 1) + minFifoSizeRequired = 8*BMI_FIFO_UNITS; + else + { + minFifoSizeRequired = (uint32_t)(((p_RxPoolsParams->secondLargestBufSize % BMI_FIFO_UNITS) ? + ((p_RxPoolsParams->secondLargestBufSize/BMI_FIFO_UNITS + 1) * BMI_FIFO_UNITS) : + p_RxPoolsParams->secondLargestBufSize) + + (7*BMI_FIFO_UNITS)); + if((sizeOfFifo < minFifoSizeRequired)) + { + DBG(WARNING, ("User set FIFO size for Rx port is not optimized. (not modified by driver)")); + minFifoSizeRequired = 8*BMI_FIFO_UNITS; + } + } + } + } + else + { + /*************************/ + /* OP PORTS */ + /*************************/ + /* check if pool size is not too big */ + if(p_RxPoolsParams->largestBufSize > sizeOfFifo ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Largest pool size is bigger than ports committed fifo size")); + } + } + + + if (minFifoSizeRequired && (sizeOfFifo < minFifoSizeRequired)) + { + sizeOfFifo = minFifoSizeRequired; + DBG(WARNING, ("FIFO size enlarged to %d for port %#x", minFifoSizeRequired, hardwarePortId)); + } + + if(initialConfig) + oldVal = 0; + else + { + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1]); + /* read into oldVal the current extra fifo size */ + oldVal = (uint16_t)((((tmpReg & BMI_EXTRA_FIFO_SIZE_MASK) + 1)*BMI_FIFO_UNITS) >> BMI_EXTRA_FIFO_SIZE_SHIFT); + } + + if(extraSizeOfFifo > oldVal) + p_Fm->p_FmStateStruct->extraFifoPoolSize = MAX(p_Fm->p_FmStateStruct->extraFifoPoolSize, extraSizeOfFifo); + + if(!initialConfig) + /* read into oldVal the current num of tasks */ + oldVal = (uint16_t)(((tmpReg & BMI_FIFO_SIZE_MASK) + 1)*BMI_FIFO_UNITS); + + /* check that there are enough uncommitted fifo size */ + if((p_Fm->p_FmStateStruct->accumulatedFifoSize - oldVal + sizeOfFifo) > + (p_Fm->p_FmStateStruct->totalFifoSize - p_Fm->p_FmStateStruct->extraFifoPoolSize)) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Requested fifo size and extra size exceed total FIFO size.")); + else + { + /* update acummulated */ + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= oldVal); + p_Fm->p_FmStateStruct->accumulatedFifoSize -= oldVal; + p_Fm->p_FmStateStruct->accumulatedFifoSize += sizeOfFifo; + /* calculate reg */ + tmpReg = (uint32_t)((sizeOfFifo/BMI_FIFO_UNITS - 1) | + ((extraSizeOfFifo/BMI_FIFO_UNITS) << BMI_EXTRA_FIFO_SIZE_SHIFT)); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], tmpReg); + } + *p_SizeOfFifo = sizeOfFifo; + + return E_OK; +} + +t_Error FmSetNumOfTasks(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t numOfTasks, + uint8_t numOfExtraTasks, + bool initialConfig) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + uint8_t oldVal; + uint32_t tmpReg = 0; + t_FmIpcPortRsrcParams rsrcParams; + t_Error err; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + rsrcParams.hardwarePortId = hardwarePortId; + rsrcParams.val = numOfTasks; + rsrcParams.extra = numOfExtraTasks; + rsrcParams.boolInitialConfig = (uint8_t)initialConfig; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_SET_NUM_OF_TASKS; + memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(rsrcParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + if(initialConfig) + oldVal = 0; + else + { + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1]); + /* read into oldVal the current extra tasks */ + oldVal = (uint8_t)((tmpReg & BMI_NUM_OF_EXTRA_TASKS_MASK) >> BMI_EXTRA_NUM_OF_TASKS_SHIFT); + } + + if(numOfExtraTasks > oldVal) + p_Fm->p_FmStateStruct->extraTasksPoolSize = (uint8_t)MAX(p_Fm->p_FmStateStruct->extraTasksPoolSize, numOfExtraTasks); + + if(!initialConfig) + /* read into oldVal the current num of tasks */ + oldVal = (uint8_t)(((tmpReg & BMI_NUM_OF_TASKS_MASK) >> BMI_NUM_OF_TASKS_SHIFT) + 1); + + /* check that there are enough uncommitted tasks */ + if((p_Fm->p_FmStateStruct->accumulatedNumOfTasks - oldVal + numOfTasks) > + (p_Fm->p_FmStateStruct->totalNumOfTasks - p_Fm->p_FmStateStruct->extraTasksPoolSize)) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, + ("Requested numOfTasks and extra tasks pool for fm%d exceed total numOfTasks.", + p_Fm->p_FmStateStruct->fmId)); + else + { + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= oldVal); + /* update acummulated */ + p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= oldVal; + p_Fm->p_FmStateStruct->accumulatedNumOfTasks += numOfTasks; + /* calculate reg */ + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1]) & ~(BMI_NUM_OF_TASKS_MASK | BMI_NUM_OF_EXTRA_TASKS_MASK); + tmpReg |= (uint32_t)(((numOfTasks-1) << BMI_NUM_OF_TASKS_SHIFT) | + (numOfExtraTasks << BMI_EXTRA_NUM_OF_TASKS_SHIFT)); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1],tmpReg); + } + + return E_OK; +} + +t_Error FmSetNumOfOpenDmas(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t numOfOpenDmas, + uint8_t numOfExtraOpenDmas, + bool initialConfig) + +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + uint8_t oldVal; + uint32_t tmpReg = 0; + t_FmIpcPortRsrcParams rsrcParams; + t_Error err; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + rsrcParams.hardwarePortId = hardwarePortId; + rsrcParams.val = numOfOpenDmas; + rsrcParams.extra = numOfExtraOpenDmas; + rsrcParams.boolInitialConfig = (uint8_t)initialConfig; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_SET_NUM_OF_OPEN_DMAS; + memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(rsrcParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + if(initialConfig) + oldVal = 0; + else + { + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1]); + /* read into oldVal the current extra tasks */ + oldVal = (uint8_t)((tmpReg & BMI_NUM_OF_EXTRA_DMAS_MASK) >> BMI_EXTRA_NUM_OF_DMAS_SHIFT); + } + + if(numOfExtraOpenDmas > oldVal) + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize = (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, numOfExtraOpenDmas); + + if(!initialConfig) + /* read into oldVal the current num of tasks */ + oldVal = (uint8_t)(((tmpReg & BMI_NUM_OF_DMAS_MASK) >> BMI_NUM_OF_DMAS_SHIFT) + 1); + + /* check that there are enough uncommitted open DMA's */ + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= oldVal); + if((p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - oldVal + numOfOpenDmas) > + p_Fm->p_FmStateStruct->maxNumOfOpenDmas) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, + ("Requested numOfOpenDmas for fm%d exceeds total numOfOpenDmas.", + p_Fm->p_FmStateStruct->fmId)); + else + { + /* update acummulated */ + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= oldVal; + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += numOfOpenDmas; + /* calculate reg */ + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1]) & ~(BMI_NUM_OF_DMAS_MASK | BMI_NUM_OF_EXTRA_DMAS_MASK); + tmpReg |= (uint32_t)(((numOfOpenDmas-1) << BMI_NUM_OF_DMAS_SHIFT) | + (numOfExtraOpenDmas << BMI_EXTRA_NUM_OF_DMAS_SHIFT)); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], tmpReg); + + /* update total num of DMA's with committed number of open DMAS, and max uncommitted pool. */ + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg2) & ~BMI_CFG2_DMAS_MASK; + tmpReg |= (uint32_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize - 1) << BMI_CFG2_DMAS_SHIFT; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg2, tmpReg); + } + + return E_OK; +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FmDumpPortRegs (t_Handle h_Fm,uint8_t hardwarePortId) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + t_FmIpcMsg msg; + t_Error err; + + DECLARE_DUMP; + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_DUMP_PORT_REGS; + msg.msgBody[0] = hardwarePortId; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(hardwarePortId), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], ("fmbm_pp for port %u", (hardwarePortId))); + DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], sizeof(uint32_t)); + + DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], ("fmbm_pfs for port %u", (hardwarePortId ))); + DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], sizeof(uint32_t)); + + DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_ppid[hardwarePortId-1], ("bm_ppid for port %u", (hardwarePortId))); + DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_ppid[hardwarePortId-1], sizeof(uint32_t)); + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ + + +/*****************************************************************************/ +/* API Init unit functions */ +/*****************************************************************************/ +t_Handle FM_Config(t_FmParams *p_FmParam) +{ + t_Fm *p_Fm; + uint8_t i; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmParam, E_NULL_POINTER, NULL); + SANITY_CHECK_RETURN_VALUE(((p_FmParam->firmware.p_Code && p_FmParam->firmware.size) || + (!p_FmParam->firmware.p_Code && !p_FmParam->firmware.size)), + E_INVALID_VALUE, NULL); + + baseAddr = p_FmParam->baseAddr; + + /* Allocate FM structure */ + p_Fm = (t_Fm *) XX_Malloc(sizeof(t_Fm)); + if (!p_Fm) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver structure")); + return NULL; + } + memset(p_Fm, 0, sizeof(t_Fm)); + + p_Fm->p_FmStateStruct = (t_FmStateStruct *) XX_Malloc(sizeof(t_FmStateStruct)); + if (!p_Fm->p_FmStateStruct) + { + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Status structure")); + return NULL; + } + memset(p_Fm->p_FmStateStruct, 0, sizeof(t_FmStateStruct)); + + /* Initialize FM parameters which will be kept by the driver */ + p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId; + p_Fm->guestId = p_FmParam->guestId; + + for(i=0; ip_FmStateStruct->portsTypes[i] = e_FM_PORT_TYPE_DUMMY; + + /* Allocate the FM driver's parameters structure */ + p_Fm->p_FmDriverParam = (t_FmDriverParam *)XX_Malloc(sizeof(t_FmDriverParam)); + if (!p_Fm->p_FmDriverParam) + { + XX_Free(p_Fm->p_FmStateStruct); + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver parameters")); + return NULL; + } + memset(p_Fm->p_FmDriverParam, 0, sizeof(t_FmDriverParam)); + + /* Initialize FM parameters which will be kept by the driver */ + p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId; + p_Fm->h_FmMuram = p_FmParam->h_FmMuram; + p_Fm->h_App = p_FmParam->h_App; + p_Fm->p_FmStateStruct->fmClkFreq = p_FmParam->fmClkFreq; + p_Fm->f_Exception = p_FmParam->f_Exception; + p_Fm->f_BusError = p_FmParam->f_BusError; + p_Fm->p_FmFpmRegs = (t_FmFpmRegs *)UINT_TO_PTR(baseAddr + FM_MM_FPM); + p_Fm->p_FmBmiRegs = (t_FmBmiRegs *)UINT_TO_PTR(baseAddr + FM_MM_BMI); + p_Fm->p_FmQmiRegs = (t_FmQmiRegs *)UINT_TO_PTR(baseAddr + FM_MM_QMI); + p_Fm->p_FmDmaRegs = (t_FmDmaRegs *)UINT_TO_PTR(baseAddr + FM_MM_DMA); + p_Fm->baseAddr = baseAddr; + p_Fm->p_FmStateStruct->irq = p_FmParam->irq; + p_Fm->p_FmStateStruct->errIrq = p_FmParam->errIrq; + p_Fm->hcPortInitialized = FALSE; + p_Fm->independentMode = FALSE; + p_Fm->p_FmStateStruct->ramsEccEnable = FALSE; + p_Fm->p_FmStateStruct->totalNumOfTasks = DEFAULT_totalNumOfTasks; + p_Fm->p_FmStateStruct->totalFifoSize = DEFAULT_totalFifoSize; + p_Fm->p_FmStateStruct->maxNumOfOpenDmas = DEFAULT_maxNumOfOpenDmas; + p_Fm->p_FmStateStruct->extraFifoPoolSize = FM_MAX_NUM_OF_RX_PORTS*BMI_FIFO_UNITS; + p_Fm->p_FmStateStruct->exceptions = DEFAULT_exceptions; + for(i = 0;ip_FmStateStruct->macMaxFrameLengths1G[i] = DEFAULT_mtu; +#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) + for(i = 0;ip_FmStateStruct->macMaxFrameLengths10G[i] = DEFAULT_mtu; +#endif /*defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)*/ + + p_Fm->h_Spinlock = XX_InitSpinlock(); + if (!p_Fm->h_Spinlock) + { + XX_Free(p_Fm->p_FmDriverParam); + XX_Free(p_Fm->p_FmStateStruct); + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("cant allocate spinlock!")); + return NULL; + } + +#ifdef FM_PARTITION_ARRAY + /* Initialize FM driver parameters parameters (for initialization phase only) */ + memcpy(p_Fm->p_FmDriverParam->liodnBasePerPort, p_FmParam->liodnBasePerPort, FM_SIZE_OF_LIODN_TABLE*sizeof(uint16_t)); +#endif /* FM_PARTITION_ARRAY */ + + /*p_Fm->p_FmDriverParam->numOfPartitions = p_FmParam->numOfPartitions; */ + p_Fm->p_FmDriverParam->enCounters = FALSE; + + p_Fm->p_FmDriverParam->resetOnInit = DEFAULT_resetOnInit; + + p_Fm->p_FmDriverParam->thresholds.dispLimit = DEFAULT_dispLimit; + p_Fm->p_FmDriverParam->thresholds.prsDispTh = DEFAULT_prsDispTh; + p_Fm->p_FmDriverParam->thresholds.plcrDispTh = DEFAULT_plcrDispTh; + p_Fm->p_FmDriverParam->thresholds.kgDispTh = DEFAULT_kgDispTh; + p_Fm->p_FmDriverParam->thresholds.bmiDispTh = DEFAULT_bmiDispTh; + p_Fm->p_FmDriverParam->thresholds.qmiEnqDispTh = DEFAULT_qmiEnqDispTh; + p_Fm->p_FmDriverParam->thresholds.qmiDeqDispTh = DEFAULT_qmiDeqDispTh; + p_Fm->p_FmDriverParam->thresholds.fmCtl1DispTh = DEFAULT_fmCtl1DispTh; + p_Fm->p_FmDriverParam->thresholds.fmCtl2DispTh = DEFAULT_fmCtl2DispTh; + + p_Fm->p_FmDriverParam->dmaStopOnBusError = DEFAULT_dmaStopOnBusError; + + p_Fm->p_FmDriverParam->dmaCacheOverride = DEFAULT_cacheOverride; + p_Fm->p_FmDriverParam->dmaAidMode = DEFAULT_aidMode; + p_Fm->p_FmDriverParam->dmaAidOverride = DEFAULT_aidOverride; + p_Fm->p_FmDriverParam->dmaAxiDbgNumOfBeats = DEFAULT_axiDbgNumOfBeats; + p_Fm->p_FmDriverParam->dmaCamNumOfEntries = DEFAULT_dmaCamNumOfEntries; + p_Fm->p_FmDriverParam->dmaWatchdog = DEFAULT_dmaWatchdog; + + p_Fm->p_FmDriverParam->dmaCommQThresholds.clearEmergency = DEFAULT_dmaCommQLow; + p_Fm->p_FmDriverParam->dmaCommQThresholds.assertEmergency = DEFAULT_dmaCommQHigh; + p_Fm->p_FmDriverParam->dmaReadBufThresholds.clearEmergency = DEFAULT_dmaReadIntBufLow; + p_Fm->p_FmDriverParam->dmaReadBufThresholds.assertEmergency = DEFAULT_dmaReadIntBufHigh; + p_Fm->p_FmDriverParam->dmaWriteBufThresholds.clearEmergency = DEFAULT_dmaWriteIntBufLow; + p_Fm->p_FmDriverParam->dmaWriteBufThresholds.assertEmergency = DEFAULT_dmaWriteIntBufHigh; + p_Fm->p_FmDriverParam->dmaSosEmergency = DEFAULT_dmaSosEmergency; + + p_Fm->p_FmDriverParam->dmaDbgCntMode = DEFAULT_dmaDbgCntMode; + + p_Fm->p_FmDriverParam->dmaEnEmergency = FALSE; + p_Fm->p_FmDriverParam->dmaEnEmergencySmoother = FALSE; + p_Fm->p_FmDriverParam->catastrophicErr = DEFAULT_catastrophicErr; + p_Fm->p_FmDriverParam->dmaErr = DEFAULT_dmaErr; + p_Fm->p_FmDriverParam->haltOnExternalActivation = DEFAULT_haltOnExternalActivation; + p_Fm->p_FmDriverParam->haltOnUnrecoverableEccError = DEFAULT_haltOnUnrecoverableEccError; + p_Fm->p_FmDriverParam->enIramTestMode = FALSE; + p_Fm->p_FmDriverParam->enMuramTestMode = FALSE; + p_Fm->p_FmDriverParam->externalEccRamsEnable = DEFAULT_externalEccRamsEnable; + + p_Fm->p_FmDriverParam->fwVerify = DEFAULT_VerifyUcode; + p_Fm->p_FmDriverParam->firmware.size = p_FmParam->firmware.size; + if (p_Fm->p_FmDriverParam->firmware.size) + { + p_Fm->p_FmDriverParam->firmware.p_Code = (uint32_t *)XX_Malloc(p_Fm->p_FmDriverParam->firmware.size); + if (!p_Fm->p_FmDriverParam->firmware.p_Code) + { + XX_FreeSpinlock(p_Fm->h_Spinlock); + XX_Free(p_Fm->p_FmStateStruct); + XX_Free(p_Fm->p_FmDriverParam); + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM firmware code")); + return NULL; + } + memcpy(p_Fm->p_FmDriverParam->firmware.p_Code, p_FmParam->firmware.p_Code, p_Fm->p_FmDriverParam->firmware.size); + } + + return p_Fm; +} + +/**************************************************************************//** + @Function FM_Init + + @Description Initializes the FM module + + @Param[in] h_Fm - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_Init(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmDriverParam *p_FmDriverParam = NULL; + t_Error err = E_OK; + uint32_t tmpReg, cfgReg = 0; + int i; + uint16_t periodInFmClocks; + uint8_t remainder; + t_FmRevisionInfo revInfo; + + SANITY_CHECK_RETURN_ERROR(h_Fm, E_INVALID_HANDLE); + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + uint8_t isMasterAlive; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + /* build the FM guest partition IPC address */ + if(Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, p_Fm->guestId) != (p_Fm->guestId<10 ? 6:7)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + + /* build the FM master partition IPC address */ + memset(p_Fm->fmIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if(Sprint (p_Fm->fmIpcHandlerModuleName[0], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + + for(i=0;iintrMng[i].f_Isr = UnimplementedIsr; + + p_Fm->h_IpcSessions[0] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[0], p_Fm->fmModuleName); + if (p_Fm->h_IpcSessions[0]) + { + err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmGuestHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_MASTER_IS_ALIVE; + msg.msgBody[0] = p_Fm->guestId; + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + do + { + blockingFlag = TRUE; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(p_Fm->guestId), + (uint8_t*)&reply, + &replyLength, + IpcMsgCompletionCB, + h_Fm)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + while(blockingFlag) ; + if(replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + isMasterAlive = *(uint8_t*)(reply.replyBody); + } while (!isMasterAlive); + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_CLK_FREQ; + replyLength = sizeof(uint32_t) + sizeof(p_Fm->p_FmStateStruct->fmClkFreq); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if(replyLength != (sizeof(uint32_t) + sizeof(p_Fm->p_FmStateStruct->fmClkFreq))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)&p_Fm->p_FmStateStruct->fmClkFreq, reply.replyBody, sizeof(uint16_t)); + } + else + { + DBG(WARNING, ("FM Guest mode - without IPC")); + if(!p_Fm->p_FmStateStruct->fmClkFreq ) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("No fmClkFreq configured for guest without IPC")); + if(!p_Fm->baseAddr) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("No baseAddr configured for guest without IPC")); + } + + XX_Free(p_Fm->p_FmDriverParam); + p_Fm->p_FmDriverParam = NULL; + + if ((p_Fm->guestId == NCSW_MASTER_ID) || + (p_Fm->h_IpcSessions[0])) + { + FM_DisableRamsEcc(p_Fm); + FmMuramClear(p_Fm->h_FmMuram); + FM_EnableRamsEcc(p_Fm); + } + + return E_OK; + } + + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + FM_GetRevision(p_Fm, &revInfo); + +#ifdef FM_NO_DISPATCH_RAM_ECC + if (revInfo.majorRev != 4) + p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_BMI_DISPATCH_RAM_ECC; +#endif /* FM_NO_DISPATCH_RAM_ECC */ + +#ifdef FM_RAM_LIST_ERR_IRQ_ERRATA_FMAN8 + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_BMI_LIST_RAM_ECC; +#endif /* FM_RAM_LIST_ERR_IRQ_ERRATA_FMAN8 */ + +#ifdef FM_BMI_PIPELINE_ERR_IRQ_ERRATA_FMAN9 + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_BMI_PIPELINE_ECC; +#endif /* FM_BMI_PIPELINE_ERR_IRQ_ERRATA_FMAN9 */ + +#ifdef FM_QMI_NO_ECC_EXCEPTIONS + if (revInfo.majorRev == 4) + p_Fm->p_FmStateStruct->exceptions &= ~(FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC); +#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ + + CHECK_INIT_PARAMETERS(p_Fm, CheckFmParameters); + + p_FmDriverParam = p_Fm->p_FmDriverParam; + + FmMuramClear(p_Fm->h_FmMuram); + +#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 + if (p_FmDriverParam->resetOnInit) + { + t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + uint32_t debug_reg; + + /* write to IRAM first location the debug instruction */ + WRITE_UINT32(p_Iram->iadd, 0); + while (GET_UINT32(p_Iram->iadd) != 0) ; + WRITE_UINT32(p_Iram->idata, FM_UCODE_DEBUG_INSTRUCTION); + + WRITE_UINT32(p_Iram->iadd, 0); + while (GET_UINT32(p_Iram->iadd) != 0) ; + while (GET_UINT32(p_Iram->idata) != FM_UCODE_DEBUG_INSTRUCTION) ; + + /* Enable patch from IRAM */ + WRITE_UINT32(p_Iram->iready, IRAM_READY); + XX_UDelay(100); + + /* reset FMAN */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrstc, FPM_RSTC_FM_RESET); + XX_UDelay(100); + + /* verify breakpoint debug status register */ + debug_reg = GET_UINT32(*(uint32_t *)UINT_TO_PTR(p_Fm->baseAddr + FM_DEBUG_STATUS_REGISTER_OFFSET)); +#ifndef NCSW_LINUX + if(!debug_reg) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Invalid debug status register value = 0")); +#else + if(!debug_reg) + DBG(INFO,("Invalid debug status register value = 0")); +#endif + /*************************************/ + /* Load FMan-Controller code to Iram */ + /*************************************/ + if (ClearIRam(p_Fm) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + if (p_Fm->p_FmDriverParam->firmware.p_Code && + (LoadFmanCtrlCode(p_Fm) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + XX_UDelay(100); + + /* reset FMAN again to start the microcode */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrstc, FPM_RSTC_FM_RESET); + XX_UDelay(1000); + } + else + { +#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + if(p_FmDriverParam->resetOnInit) + { + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrstc, FPM_RSTC_FM_RESET); + XX_UDelay(100); + } + + /*************************************/ + /* Load FMan-Controller code to Iram */ + /*************************************/ + if (ClearIRam(p_Fm) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + if (p_Fm->p_FmDriverParam->firmware.p_Code && + (LoadFmanCtrlCode(p_Fm) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); +#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 + } +#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + +#ifdef FM_CAPWAP_SUPPORT + /* save first 256 byte in MURAM */ + p_Fm->resAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, 256, 0)); + if (!p_Fm->resAddr) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for reserved Area failed")); + + WRITE_BLOCK(UINT_TO_PTR(p_Fm->resAddr), 0, 256); +#endif /* FM_CAPWAP_SUPPORT */ + + /* General FM driver initialization */ + p_Fm->fmMuramPhysBaseAddr = (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM))); + for(i=0;iintrMng[i].f_Isr = UnimplementedIsr; + for(i=0;ifmanCtrlIntr[i].f_Isr = UnimplementedFmanCtrlIsr; + + /**********************/ + /* Init DMA Registers */ + /**********************/ + /* clear status reg events */ + tmpReg = (DMA_STATUS_BUS_ERR | DMA_STATUS_READ_ECC | DMA_STATUS_SYSTEM_WRITE_ECC | DMA_STATUS_FM_WRITE_ECC); + /*tmpReg |= (DMA_STATUS_SYSTEM_DPEXT_ECC | DMA_STATUS_FM_DPEXT_ECC | DMA_STATUS_SYSTEM_DPDAT_ECC | DMA_STATUS_FM_DPDAT_ECC | DMA_STATUS_FM_SPDAT_ECC);*/ + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmsr, GET_UINT32(p_Fm->p_FmDmaRegs->fmdmsr) | tmpReg); + + /* configure mode register */ + tmpReg = 0; + tmpReg |= p_FmDriverParam->dmaCacheOverride << DMA_MODE_CACHE_OR_SHIFT; + if(p_FmDriverParam->dmaAidOverride) + tmpReg |= DMA_MODE_AID_OR; + if (p_Fm->p_FmStateStruct->exceptions & FM_EX_DMA_BUS_ERROR) + tmpReg |= DMA_MODE_BER; + if ((p_Fm->p_FmStateStruct->exceptions & FM_EX_DMA_SYSTEM_WRITE_ECC) | (p_Fm->p_FmStateStruct->exceptions & FM_EX_DMA_READ_ECC) | (p_Fm->p_FmStateStruct->exceptions & FM_EX_DMA_FM_WRITE_ECC)) + tmpReg |= DMA_MODE_ECC; + if(p_FmDriverParam->dmaStopOnBusError) + tmpReg |= DMA_MODE_SBER; + tmpReg |= (uint32_t)(p_FmDriverParam->dmaAxiDbgNumOfBeats - 1) << DMA_MODE_AXI_DBG_SHIFT; + if (p_FmDriverParam->dmaEnEmergency) + { + tmpReg |= p_FmDriverParam->dmaEmergency.emergencyBusSelect; + tmpReg |= p_FmDriverParam->dmaEmergency.emergencyLevel << DMA_MODE_EMERGENCY_LEVEL_SHIFT; + if(p_FmDriverParam->dmaEnEmergencySmoother) + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmemsr, p_FmDriverParam->dmaEmergencySwitchCounter); + } + tmpReg |= ((p_FmDriverParam->dmaCamNumOfEntries/DMA_CAM_UNITS) - 1) << DMA_MODE_CEN_SHIFT; + + tmpReg |= DMA_MODE_SECURE_PROT; + tmpReg |= p_FmDriverParam->dmaDbgCntMode << DMA_MODE_DBG_SHIFT; + tmpReg |= p_FmDriverParam->dmaAidMode << DMA_MODE_AID_MODE_SHIFT; + +#ifdef FM_PEDANTIC_DMA + tmpReg |= DMA_MODE_EMERGENCY_READ; +#endif /* FM_PEDANTIC_DMA */ + + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmmr, tmpReg); + + /* configure thresholds register */ + tmpReg = ((uint32_t)p_FmDriverParam->dmaCommQThresholds.assertEmergency << DMA_THRESH_COMMQ_SHIFT) | + ((uint32_t)p_FmDriverParam->dmaReadBufThresholds.assertEmergency << DMA_THRESH_READ_INT_BUF_SHIFT) | + ((uint32_t)p_FmDriverParam->dmaWriteBufThresholds.assertEmergency); + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmtr, tmpReg); + + /* configure hysteresis register */ + tmpReg = ((uint32_t)p_FmDriverParam->dmaCommQThresholds.clearEmergency << DMA_THRESH_COMMQ_SHIFT) | + ((uint32_t)p_FmDriverParam->dmaReadBufThresholds.clearEmergency << DMA_THRESH_READ_INT_BUF_SHIFT) | + ((uint32_t)p_FmDriverParam->dmaWriteBufThresholds.clearEmergency); + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmhy, tmpReg); + + /* configure emergency threshold */ + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmsetr, p_FmDriverParam->dmaSosEmergency); + + /* configure Watchdog */ + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmwcr, USEC_TO_CLK(p_FmDriverParam->dmaWatchdog, p_Fm->p_FmStateStruct->fmClkFreq)); + + /* Allocate MURAM for CAM */ + p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, + (uint32_t)(p_FmDriverParam->dmaCamNumOfEntries*DMA_CAM_SIZEOF_ENTRY), + DMA_CAM_ALIGN)); + if (!p_Fm->camBaseAddr ) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed")); + + WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr), 0, (uint32_t)(p_FmDriverParam->dmaCamNumOfEntries*DMA_CAM_SIZEOF_ENTRY)); + + /* VirtToPhys */ + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmebcr, + (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->camBaseAddr)) - p_Fm->fmMuramPhysBaseAddr)); + +#ifdef FM_PARTITION_ARRAY + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + /* liodn-partitions */ + for (i=0 ; iliodnBasePerPort[i] << DMA_LIODN_SHIFT) | + (uint32_t)p_FmDriverParam->liodnBasePerPort[i+1]); + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmplr[i/2], tmpReg); + } + } +#endif /* FM_PARTITION_ARRAY */ + + /**********************/ + /* Init FPM Registers */ + /**********************/ + tmpReg = (uint32_t)(p_FmDriverParam->thresholds.dispLimit << FPM_DISP_LIMIT_SHIFT); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmflc, tmpReg); + + tmpReg = (((uint32_t)p_FmDriverParam->thresholds.prsDispTh << FPM_THR1_PRS_SHIFT) | + ((uint32_t)p_FmDriverParam->thresholds.kgDispTh << FPM_THR1_KG_SHIFT) | + ((uint32_t)p_FmDriverParam->thresholds.plcrDispTh << FPM_THR1_PLCR_SHIFT) | + ((uint32_t)p_FmDriverParam->thresholds.bmiDispTh << FPM_THR1_BMI_SHIFT)); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmdis1, tmpReg); + + tmpReg = (((uint32_t)p_FmDriverParam->thresholds.qmiEnqDispTh << FPM_THR2_QMI_ENQ_SHIFT) | + ((uint32_t)p_FmDriverParam->thresholds.qmiDeqDispTh << FPM_THR2_QMI_DEQ_SHIFT) | + ((uint32_t)p_FmDriverParam->thresholds.fmCtl1DispTh << FPM_THR2_FM_CTL1_SHIFT) | + ((uint32_t)p_FmDriverParam->thresholds.fmCtl2DispTh << FPM_THR2_FM_CTL2_SHIFT)); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmdis2, tmpReg); + + /* define exceptions and error behavior */ + tmpReg = 0; + /* Clear events */ + tmpReg |= (FPM_EV_MASK_STALL | FPM_EV_MASK_DOUBLE_ECC | FPM_EV_MASK_SINGLE_ECC); + /* enable interrupts */ + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_FPM_STALL_ON_TASKS) + tmpReg |= FPM_EV_MASK_STALL_EN; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_FPM_SINGLE_ECC) + tmpReg |= FPM_EV_MASK_SINGLE_ECC_EN; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_FPM_DOUBLE_ECC) + tmpReg |= FPM_EV_MASK_DOUBLE_ECC_EN; + tmpReg |= (p_Fm->p_FmDriverParam->catastrophicErr << FPM_EV_MASK_CAT_ERR_SHIFT); + tmpReg |= (p_Fm->p_FmDriverParam->dmaErr << FPM_EV_MASK_DMA_ERR_SHIFT); + if(!p_Fm->p_FmDriverParam->haltOnExternalActivation) + tmpReg |= FPM_EV_MASK_EXTERNAL_HALT; + if(!p_Fm->p_FmDriverParam->haltOnUnrecoverableEccError) + tmpReg |= FPM_EV_MASK_ECC_ERR_HALT; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmem, tmpReg); + + /* clear all fmCtls event registers */ + for(i=0;ip_FmFpmRegs->fpmcev[i], 0xFFFFFFFF); + + /* RAM ECC - enable and clear events*/ + /* first we need to clear all parser memory, as it is uninitialized and + may cause ECC errors */ + tmpReg = 0; + /* event bits */ + tmpReg = (FPM_RAM_CTL_MURAM_ECC | FPM_RAM_CTL_IRAM_ECC); + /* Rams enable is not effected by the RCR bit, but by a COP configuration */ + if(p_Fm->p_FmDriverParam->externalEccRamsEnable) + tmpReg |= FPM_RAM_CTL_RAMS_ECC_EN_SRC_SEL; + + /* enable test mode */ + if(p_FmDriverParam->enMuramTestMode) + tmpReg |= FPM_RAM_CTL_MURAM_TEST_ECC; + if(p_FmDriverParam->enIramTestMode) + tmpReg |= FPM_RAM_CTL_IRAM_TEST_ECC; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, tmpReg); + + tmpReg = 0; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_IRAM_ECC) + { + tmpReg |= FPM_IRAM_ECC_ERR_EX_EN; + FmEnableRamsEcc(p_Fm); + } + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_NURAM_ECC) + { + tmpReg |= FPM_MURAM_ECC_ERR_EX_EN; + FmEnableRamsEcc(p_Fm); + } + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrie, tmpReg); + + /**********************/ + /* Init BMI Registers */ + /**********************/ + + /* define common resources */ + /* allocate MURAM for FIFO according to total size */ + p_Fm->fifoBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, + p_Fm->p_FmStateStruct->totalFifoSize, + BMI_FIFO_ALIGN)); + if (!p_Fm->fifoBaseAddr) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for FIFO failed")); + } + + tmpReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->fifoBaseAddr)) - p_Fm->fmMuramPhysBaseAddr); + tmpReg = tmpReg / BMI_FIFO_ALIGN; + + tmpReg |= ((p_Fm->p_FmStateStruct->totalFifoSize/BMI_FIFO_UNITS - 1) << BMI_CFG1_FIFO_SIZE_SHIFT); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg1, tmpReg); + + tmpReg = ((uint32_t)(p_Fm->p_FmStateStruct->totalNumOfTasks - 1) << BMI_CFG2_TASKS_SHIFT ); + /* num of DMA's will be dynamically updated when each port is set */ + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg2, tmpReg); + + /* define unmaskable exceptions, enable and clear events */ + tmpReg = 0; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ievr, (BMI_ERR_INTR_EN_LIST_RAM_ECC | + BMI_ERR_INTR_EN_PIPELINE_ECC | + BMI_ERR_INTR_EN_STATISTICS_RAM_ECC | + BMI_ERR_INTR_EN_DISPATCH_RAM_ECC)); + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_LIST_RAM_ECC) + tmpReg |= BMI_ERR_INTR_EN_LIST_RAM_ECC; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_PIPELINE_ECC) + tmpReg |= BMI_ERR_INTR_EN_PIPELINE_ECC; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STATISTICS_RAM_ECC) + tmpReg |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_DISPATCH_RAM_ECC) + tmpReg |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier, tmpReg); + + /**********************/ + /* Init QMI Registers */ + /**********************/ + /* Clear error interrupt events */ + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eie, (QMI_ERR_INTR_EN_DOUBLE_ECC | QMI_ERR_INTR_EN_DEQ_FROM_DEF)); + tmpReg = 0; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID) + tmpReg |= QMI_ERR_INTR_EN_DEQ_FROM_DEF; + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DOUBLE_ECC) + tmpReg |= QMI_ERR_INTR_EN_DOUBLE_ECC; + /* enable events */ + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eien, tmpReg); + + if(p_Fm->p_FmDriverParam->tnumAgingPeriod) + { + /* tnumAgingPeriod is in units of microseconds, p_FmClockFreq is in Mhz */ + periodInFmClocks = (uint16_t)(p_Fm->p_FmDriverParam->tnumAgingPeriod*p_Fm->p_FmStateStruct->fmClkFreq); + /* periodInFmClocks must be a 64 multiply */ + remainder = (uint8_t)(periodInFmClocks % 64); + if (remainder > 64) + tmpReg = (uint32_t)((periodInFmClocks/64) + 1); + else + { + tmpReg = (uint32_t)(periodInFmClocks/64); + if(!tmpReg) + tmpReg = 1; + } + tmpReg <<= QMI_TAPC_TAP; + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_tapc, tmpReg); + + } + tmpReg = 0; + /* Clear interrupt events */ + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_ie, QMI_INTR_EN_SINGLE_ECC); + if(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_SINGLE_ECC) + tmpReg |= QMI_INTR_EN_SINGLE_ECC; + /* enable events */ + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_ien, tmpReg); + + /* clear & enable global counters - calculate reg and save for later, + because it's the same reg for QMI enable */ + if(p_Fm->p_FmDriverParam->enCounters) + cfgReg = QMI_CFG_EN_COUNTERS; +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + cfgReg |= (uint32_t)(((QMI_DEF_TNUMS_THRESH) << 8) | (uint32_t)QMI_DEF_TNUMS_THRESH); +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + + if (p_Fm->p_FmStateStruct->irq != NO_IRQ) + { + XX_SetIntr(p_Fm->p_FmStateStruct->irq, FM_EventIsr, p_Fm); + XX_EnableIntr(p_Fm->p_FmStateStruct->irq); + } + + if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ) + { + XX_SetIntr(p_Fm->p_FmStateStruct->errIrq, ErrorIsrCB, p_Fm); + XX_EnableIntr(p_Fm->p_FmStateStruct->errIrq); + } + + /* build the FM master partition IPC address */ + if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + + err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /**********************/ + /* Enable all modules */ + /**********************/ + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_init, BMI_INIT_START); + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc, cfgReg | QMI_CFG_ENQ_EN | QMI_CFG_DEQ_EN); + + if (p_Fm->p_FmDriverParam->firmware.p_Code) + { + XX_Free(p_Fm->p_FmDriverParam->firmware.p_Code); + p_Fm->p_FmDriverParam->firmware.p_Code = NULL; + } + + XX_Free(p_Fm->p_FmDriverParam); + p_Fm->p_FmDriverParam = NULL; + + return E_OK; +} + +/**************************************************************************//** + @Function FM_Free + + @Description Frees all resources that were assigned to FM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_Fm - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_Free(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName); + + if(!p_Fm->recoveryMode) + XX_Free(p_Fm->p_FmStateStruct); + + XX_Free(p_Fm); + + return E_OK; + } + + /* disable BMI and QMI */ + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_init, 0); + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc, 0); + + /* release BMI resources */ + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg2, 0); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_cfg1, 0); + + /* disable ECC */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, 0); + + if ((p_Fm->guestId == NCSW_MASTER_ID) && (p_Fm->fmModuleName[0] != 0)) + XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName); + + if (p_Fm->p_FmStateStruct) + { + if (p_Fm->p_FmStateStruct->irq != NO_IRQ) + { + XX_DisableIntr(p_Fm->p_FmStateStruct->irq); + XX_FreeIntr(p_Fm->p_FmStateStruct->irq); + } + if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ) + { + XX_DisableIntr(p_Fm->p_FmStateStruct->errIrq); + XX_FreeIntr(p_Fm->p_FmStateStruct->errIrq); + } + } + + if (p_Fm->h_Spinlock) + XX_FreeSpinlock(p_Fm->h_Spinlock); + + if (p_Fm->p_FmDriverParam) + { + if (p_Fm->p_FmDriverParam->firmware.p_Code) + XX_Free(p_Fm->p_FmDriverParam->firmware.p_Code); + XX_Free(p_Fm->p_FmDriverParam); + p_Fm->p_FmDriverParam = NULL; + } + + FreeInitResources(p_Fm); + + if (!p_Fm->recoveryMode && p_Fm->p_FmStateStruct) + XX_Free(p_Fm->p_FmStateStruct); + + XX_Free(p_Fm); + + return E_OK; +} + +/*************************************************/ +/* API Advanced Init unit functions */ +/*************************************************/ + +t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable) +{ + + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->resetOnInit = enable; + + return E_OK; +} + + +t_Error FM_ConfigTotalNumOfTasks(t_Handle h_Fm, uint8_t totalNumOfTasks) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmStateStruct->totalNumOfTasks = totalNumOfTasks; + + return E_OK; +} + +t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmStateStruct->totalFifoSize = totalFifoSize; + + return E_OK; +} + +t_Error FM_ConfigMaxNumOfOpenDmas(t_Handle h_Fm, uint8_t maxNumOfOpenDmas) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmStateStruct->maxNumOfOpenDmas = maxNumOfOpenDmas; + + return E_OK; +} + +t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + memcpy(&p_Fm->p_FmDriverParam->thresholds, p_FmThresholds, sizeof(t_FmThresholds)); + + return E_OK; +} + +t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaCacheOverride = cacheOverride; + + return E_OK; +} + +t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaAidOverride = aidOverride; + + return E_OK; +} + +t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaAidMode = aidMode; + + return E_OK; +} + +t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaAxiDbgNumOfBeats = axiDbgNumOfBeats; + + return E_OK; +} + +t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaCamNumOfEntries = numOfEntries; + + return E_OK; +} + +t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchdogValue) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + +#ifdef FM_NO_WATCHDOG + { + t_FmRevisionInfo revInfo; + FM_GetRevision(h_Fm, &revInfo); + if (revInfo.majorRev != 4) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("watchdog!")); + } +#endif /* FM_NO_WATCHDOG */ + + p_Fm->p_FmDriverParam->dmaWatchdog = watchdogValue; + + return E_OK; +} + +t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) + +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + memcpy(&p_Fm->p_FmDriverParam->dmaWriteBufThresholds, p_FmDmaThresholds, sizeof(t_FmDmaThresholds)); + + return E_OK; +} + +t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + memcpy(&p_Fm->p_FmDriverParam->dmaCommQThresholds, p_FmDmaThresholds, sizeof(t_FmDmaThresholds)); + + return E_OK; +} + +t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + memcpy(&p_Fm->p_FmDriverParam->dmaReadBufThresholds, p_FmDmaThresholds, sizeof(t_FmDmaThresholds)); + + return E_OK; +} + +t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaEnEmergency = TRUE; + memcpy(&p_Fm->p_FmDriverParam->dmaEmergency, p_Emergency, sizeof(t_FmDmaEmergency)); + + return E_OK; +} + +t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + if(!p_Fm->p_FmDriverParam->dmaEnEmergency) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FM_ConfigEnDmaEmergencySmoother may be called only after FM_ConfigEnDmaEmergency")); + + p_Fm->p_FmDriverParam->dmaEnEmergencySmoother = TRUE; + p_Fm->p_FmDriverParam->dmaEmergencySwitchCounter = emergencyCnt; + + return E_OK; +} + +t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaDbgCntMode = fmDmaDbgCntMode; + + return E_OK; +} + +t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaStopOnBusError = stop; + + return E_OK; +} + +t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaSosEmergency = dmaSosEmergency; + + return E_OK; +} + +t_Error FM_ConfigEnableCounters(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->enCounters = TRUE; + + return E_OK; +} + +t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->dmaErr = dmaErr; + + return E_OK; +} + +t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->catastrophicErr = catastrophicErr; + + return E_OK; +} + +t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->enMuramTestMode = TRUE; + + return E_OK; +} + +t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->enIramTestMode = TRUE; + + return E_OK; +} + +t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + +#ifdef FM_HALT_SIG_ERRATA_GEN12 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("HaltOnExternalActivation!")); + } +#endif /* FM_HALT_SIG_ERRATA_GEN12 */ + + p_Fm->p_FmDriverParam->haltOnExternalActivation = enable; + + return E_OK; +} + +t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + +#ifdef FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("HaltOnEccError!")); +#endif /* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 */ + + p_Fm->p_FmDriverParam->haltOnUnrecoverableEccError = enable; + + return E_OK; +} + +t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t bitMask = 0; + t_FmRevisionInfo revInfo; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + FM_GetRevision(p_Fm, &revInfo); +#ifdef FM_BMI_PIPELINE_ERR_IRQ_ERRATA_FMAN9 + if((exception == e_FM_EX_BMI_PIPELINE_ECC) && (enable)) + { + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_BMI_PIPELINE_ECC!")); + return E_OK; + } + } +#endif /* FM_BMI_PIPELINE_ERR_IRQ_ERRATA_FMAN9 */ +#ifdef FM_RAM_LIST_ERR_IRQ_ERRATA_FMAN8 + if((exception == e_FM_EX_BMI_LIST_RAM_ECC) && (enable)) + { + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_BMI_LIST_RAM_ECC!")); + return E_OK; + } + } +#endif /* FM_RAM_LIST_ERR_IRQ_ERRATA_FMAN8 */ +#ifdef FM_QMI_NO_ECC_EXCEPTIONS + if(((exception == e_FM_EX_QMI_SINGLE_ECC) || (exception == e_FM_EX_QMI_DOUBLE_ECC)) && + enable) + { + if (revInfo.majorRev == 4) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("QMI ECC exception!")); + return E_OK; + } + } +#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ +#ifdef FM_NO_DISPATCH_RAM_ECC + if((exception == e_FM_EX_BMI_DISPATCH_RAM_ECC) && (enable)) + { + if (revInfo.majorRev != 4) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_BMI_DISPATCH_RAM_ECC!")); + return E_OK; + } + } +#endif /* FM_NO_DISPATCH_RAM_ECC */ + + GET_EXCEPTION_FLAG(bitMask, exception); + if(bitMask) + { + if (enable) + p_Fm->p_FmStateStruct->exceptions |= bitMask; + else + p_Fm->p_FmStateStruct->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + p_Fm->p_FmDriverParam->externalEccRamsEnable = enable; + + return E_OK; +} + +t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; +#ifdef FM_NO_TNUM_AGING + t_FmRevisionInfo revInfo; +#endif /* FM_NO_TNUM_AGING */ + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + +#ifdef FM_NO_TNUM_AGING + FM_GetRevision(h_Fm, &revInfo); + if (revInfo.majorRev != 4) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("FM_ConfigTnumAgingPeriod!")); +#endif /* FM_NO_TNUM_AGING */ + + p_Fm->p_FmDriverParam->tnumAgingPeriod = tnumAgingPeriod; + + return E_OK; + +} + +/****************************************************/ +/* API Run-time Control uint functions */ +/****************************************************/ +t_Handle FM_GetPcdHandle(t_Handle h_Fm) +{ + SANITY_CHECK_RETURN_VALUE(h_Fm, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!((t_Fm*)h_Fm)->p_FmDriverParam, E_INVALID_STATE, NULL); + + return ((t_Fm*)h_Fm)->h_Pcd; +} + +void FM_EventIsr(t_Handle h_Fm) +{ +#define FM_M_CALL_1G_MAC_TMR_ISR(_id) \ + { \ + if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0_TMR+_id)].guestId) \ + SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_1G_MAC0_TMR+_id), pending); \ + else \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0_TMR+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0_TMR+_id)].h_SrcHandle);\ + } + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t pending, event; + + SANITY_CHECK_RETURN(h_Fm, E_INVALID_HANDLE); + + /* normal interrupts */ + pending = GET_UINT32(p_Fm->p_FmFpmRegs->fmnpi); + ASSERT_COND(pending); + if (pending & INTR_EN_BMI) + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("BMI Event - undefined!")); + if (pending & INTR_EN_QMI) + QmiEvent(p_Fm); + if (pending & INTR_EN_PRS) + p_Fm->intrMng[e_FM_EV_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_PRS].h_SrcHandle); + if (pending & INTR_EN_PLCR) + p_Fm->intrMng[e_FM_EV_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_PLCR].h_SrcHandle); + if (pending & INTR_EN_KG) + p_Fm->intrMng[e_FM_EV_KG].f_Isr(p_Fm->intrMng[e_FM_EV_KG].h_SrcHandle); + if (pending & INTR_EN_TMR) + p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle); + + /* MAC events may belong to different partitions */ + if (pending & INTR_EN_1G_MAC0_TMR) + FM_M_CALL_1G_MAC_TMR_ISR(0); + if (pending & INTR_EN_1G_MAC1_TMR) + FM_M_CALL_1G_MAC_TMR_ISR(1); + if (pending & INTR_EN_1G_MAC2_TMR) + FM_M_CALL_1G_MAC_TMR_ISR(2); + if (pending & INTR_EN_1G_MAC3_TMR) + FM_M_CALL_1G_MAC_TMR_ISR(3); + if (pending & INTR_EN_1G_MAC4_TMR) + FM_M_CALL_1G_MAC_TMR_ISR(4); + + /* IM port events may belong to different partitions */ + if (pending & INTR_EN_REV0) + { + event = GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcev[0]) & GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcee[0]); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmcev[0], event); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_0].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_0, pending); */ + else + p_Fm->fmanCtrlIntr[0].f_Isr(p_Fm->fmanCtrlIntr[0].h_SrcHandle, event); + + } + if (pending & INTR_EN_REV1) + { + event = GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcev[1]) & GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcee[1]); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmcev[1], event); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_1].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_1, pending); */ + else + p_Fm->fmanCtrlIntr[1].f_Isr(p_Fm->fmanCtrlIntr[1].h_SrcHandle, event); + + } + if (pending & INTR_EN_REV2) + { + event = GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcev[2]) & GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcee[2]); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmcev[2], event); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_2].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pending); */ + else + p_Fm->fmanCtrlIntr[2].f_Isr(p_Fm->fmanCtrlIntr[2].h_SrcHandle, event); + } + if (pending & INTR_EN_REV3) + { + event = GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcev[3]) & GET_UINT32(p_Fm->p_FmFpmRegs->fmfpfcee[3]); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmcev[3], event); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_3].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pendin3); */ + else + p_Fm->fmanCtrlIntr[3].f_Isr(p_Fm->fmanCtrlIntr[3].h_SrcHandle, event); + } +} + +t_Error FM_ErrorIsr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(h_Fm, E_INVALID_HANDLE); + + /* error interrupts */ + if (GET_UINT32(p_Fm->p_FmFpmRegs->fmepi) == 0) + return ERROR_CODE(E_EMPTY); + + ErrorIsrCB(p_Fm); + return E_OK; +} + +t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + int i; + uint8_t sum; + uint8_t hardwarePortId; + uint32_t tmpRegs[8] = {0,0,0,0,0,0,0,0}; + uint8_t relativePortId, shift, weight, maxPercent = 0; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + /* check that all ports add up to 100% */ + sum = 0; + for (i=0;inumOfPorts;i++) + sum +=p_PortsBandwidth->portsBandwidths[i].bandwidth; + if (sum != 100) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Sum of ports bandwidth differ from 100%")); + + /* find highest precent */ + for (i=0;inumOfPorts;i++) + { + if (p_PortsBandwidth->portsBandwidths[i].bandwidth > maxPercent) + maxPercent = p_PortsBandwidth->portsBandwidths[i].bandwidth; + } + + /* calculate weight for each port */ + for (i=0;inumOfPorts;i++) + { + weight = (uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT )/maxPercent); + /* we want even division between 1-to-PORT_MAX_WEIGHT. so if exect division + is not reached, we round up so that: + 0 until maxPercent/PORT_MAX_WEIGHT get "1" + maxPercent/PORT_MAX_WEIGHT+1 until (maxPercent/PORT_MAX_WEIGHT)*2 get "2" + ... + maxPercent - maxPercent/PORT_MAX_WEIGHT until maxPercent get "PORT_MAX_WEIGHT: */ + if ((uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) % maxPercent)) + weight++; + + /* find the location of this port within the register */ + SW_PORT_ID_TO_HW_PORT_ID(hardwarePortId, + p_PortsBandwidth->portsBandwidths[i].type, + p_PortsBandwidth->portsBandwidths[i].relativePortId); + relativePortId = (uint8_t)(hardwarePortId % 8); + shift = (uint8_t)(32-4*(relativePortId+1)); + + + if(weight > 1) + /* Add this port to tmpReg */ + /* (each 8 ports result in one register)*/ + tmpRegs[hardwarePortId/8] |= ((weight-1) << shift); + } + + for(i=0;i<8;i++) + if(tmpRegs[i]) + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_arb[i], tmpRegs[i]); + + return E_OK; +} + +t_Error FM_EnableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + t_FmIpcMsg msg; + t_Error err; + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_ENABLE_RAM_ECC; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + + if(!p_Fm->p_FmStateStruct->internalCall) + p_Fm->p_FmStateStruct->explicitEnable = TRUE; + p_Fm->p_FmStateStruct->internalCall = FALSE; + + if(p_Fm->p_FmStateStruct->ramsEccEnable) + return E_OK; + else + { + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fmrcr); + if(tmpReg & FPM_RAM_CTL_RAMS_ECC_EN_SRC_SEL) + { + DBG(WARNING, ("Rams ECC is configured to be controlled through JTAG")); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, tmpReg | FPM_RAM_CTL_IRAM_ECC_EN); + } + else + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, tmpReg | (FPM_RAM_CTL_RAMS_ECC_EN | FPM_RAM_CTL_IRAM_ECC_EN)); + p_Fm->p_FmStateStruct->ramsEccEnable = TRUE; + } + + return E_OK; +} + +t_Error FM_DisableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + bool explicitDisable = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + t_Error err; + t_FmIpcMsg msg; + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_DISABLE_RAM_ECC; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + + if(!p_Fm->p_FmStateStruct->internalCall) + explicitDisable = TRUE; + p_Fm->p_FmStateStruct->internalCall = FALSE; + + /* if rams are already disabled, or if rams were explicitly enabled and are + currently called indirectly (not explicitly), ignore this call. */ + if(!p_Fm->p_FmStateStruct->ramsEccEnable || (p_Fm->p_FmStateStruct->explicitEnable && !explicitDisable)) + return E_OK; + else + { + if(p_Fm->p_FmStateStruct->explicitEnable) + /* This is the case were both explicit are TRUE. + Turn off this flag for cases were following ramsEnable + routines are called */ + p_Fm->p_FmStateStruct->explicitEnable = FALSE; + + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fmrcr); + if(tmpReg & FPM_RAM_CTL_RAMS_ECC_EN_SRC_SEL) + { + DBG(WARNING, ("Rams ECC is configured to be controlled through JTAG")); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, tmpReg & ~FPM_RAM_CTL_IRAM_ECC_EN); + } + else + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrcr, tmpReg & ~(FPM_RAM_CTL_RAMS_ECC_EN | FPM_RAM_CTL_IRAM_ECC_EN)); + p_Fm->p_FmStateStruct->ramsEccEnable = FALSE; + } + + return E_OK; +} + +t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t bitMask = 0; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if(bitMask) + { + if (enable) + p_Fm->p_FmStateStruct->exceptions |= bitMask; + else + p_Fm->p_FmStateStruct->exceptions &= ~bitMask; + + switch(exception) + { + case(e_FM_EX_DMA_BUS_ERROR): + tmpReg = GET_UINT32(p_Fm->p_FmDmaRegs->fmdmmr); + if(enable) + tmpReg |= DMA_MODE_BER; + else + tmpReg &= ~DMA_MODE_BER; + /* disable bus error */ + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmmr, tmpReg); + break; + case(e_FM_EX_DMA_READ_ECC): + case(e_FM_EX_DMA_SYSTEM_WRITE_ECC): + case(e_FM_EX_DMA_FM_WRITE_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmDmaRegs->fmdmmr); + if(enable) + tmpReg |= DMA_MODE_ECC; + else + tmpReg &= ~DMA_MODE_ECC; + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmmr, tmpReg); + break; + case(e_FM_EX_FPM_STALL_ON_TASKS): + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fpmem); + if(enable) + tmpReg |= FPM_EV_MASK_STALL_EN; + else + tmpReg &= ~FPM_EV_MASK_STALL_EN; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmem, tmpReg); + break; + case(e_FM_EX_FPM_SINGLE_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fpmem); + if(enable) + tmpReg |= FPM_EV_MASK_SINGLE_ECC_EN; + else + tmpReg &= ~FPM_EV_MASK_SINGLE_ECC_EN; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmem, tmpReg); + break; + case( e_FM_EX_FPM_DOUBLE_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fpmem); + if(enable) + tmpReg |= FPM_EV_MASK_DOUBLE_ECC_EN; + else + tmpReg &= ~FPM_EV_MASK_DOUBLE_ECC_EN; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmem, tmpReg); + break; + case( e_FM_EX_QMI_SINGLE_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_ien); + if(enable) + { +#ifdef FM_QMI_NO_ECC_EXCEPTIONS + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Fm, &revInfo); + if (revInfo.majorRev == 4) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_QMI_SINGLE_ECC")); + return E_OK; + } +#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ + tmpReg |= QMI_INTR_EN_SINGLE_ECC; + } + else + tmpReg &= ~QMI_INTR_EN_SINGLE_ECC; + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_ien, tmpReg); + break; + case(e_FM_EX_QMI_DOUBLE_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_eien); + if(enable) + { +#ifdef FM_QMI_NO_ECC_EXCEPTIONS + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Fm, &revInfo); + if (revInfo.majorRev == 4) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_QMI_DOUBLE_ECC")); + return E_OK; + } +#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ + tmpReg |= QMI_ERR_INTR_EN_DOUBLE_ECC; + } + else + tmpReg &= ~QMI_ERR_INTR_EN_DOUBLE_ECC; + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eien, tmpReg); + break; + case(e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID): + tmpReg = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_eien); + if(enable) + tmpReg |= QMI_ERR_INTR_EN_DEQ_FROM_DEF; + else + tmpReg &= ~QMI_ERR_INTR_EN_DEQ_FROM_DEF; + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eien, tmpReg); + break; + case(e_FM_EX_BMI_LIST_RAM_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier); + if(enable) + { +#ifdef FM_RAM_LIST_ERR_IRQ_ERRATA_FMAN8 + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_BMI_LIST_RAM_ECC")); + return E_OK; + } +#endif /* FM_RAM_LIST_ERR_IRQ_ERRATA_FMAN8 */ + tmpReg |= BMI_ERR_INTR_EN_LIST_RAM_ECC; + } + else + tmpReg &= ~BMI_ERR_INTR_EN_LIST_RAM_ECC; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier, tmpReg); + break; + case(e_FM_EX_BMI_PIPELINE_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier); + if(enable) + { +#ifdef FM_BMI_PIPELINE_ERR_IRQ_ERRATA_FMAN9 + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_BMI_PIPELINE_ECCBMI_LIST_RAM_ECC")); + return E_OK; + } +#endif /* FM_BMI_PIPELINE_ERR_IRQ_ERRATA_FMAN9 */ + tmpReg |= BMI_ERR_INTR_EN_PIPELINE_ECC; + } + else + tmpReg &= ~BMI_ERR_INTR_EN_PIPELINE_ECC; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier, tmpReg); + break; + case(e_FM_EX_BMI_STATISTICS_RAM_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier); + if(enable) + tmpReg |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; + else + tmpReg &= ~BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier, tmpReg); + break; + case(e_FM_EX_BMI_DISPATCH_RAM_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier); + if(enable) + { +#ifdef FM_NO_DISPATCH_RAM_ECC + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Fm, &revInfo); + if (revInfo.majorRev != 4) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_EX_BMI_DISPATCH_RAM_ECC")); + return E_OK; + } +#endif /* FM_NO_DISPATCH_RAM_ECC */ + tmpReg |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; + } + else + tmpReg &= ~BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ier, tmpReg); + break; + case(e_FM_EX_IRAM_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fmrie); + if(enable) + { + /* enable ECC if not enabled */ + FmEnableRamsEcc(p_Fm); + /* enable ECC interrupts */ + tmpReg |= FPM_IRAM_ECC_ERR_EX_EN; + } + else + { + /* ECC mechanism may be disabled, depending on driver status */ + FmDisableRamsEcc(p_Fm); + tmpReg &= ~FPM_IRAM_ECC_ERR_EX_EN; + } + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrie, tmpReg); + break; + + case(e_FM_EX_MURAM_ECC): + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fmrie); + if(enable) + { + /* enable ECC if not enabled */ + FmEnableRamsEcc(p_Fm); + /* enable ECC interrupts */ + tmpReg |= FPM_MURAM_ECC_ERR_EX_EN; + } + else + { + /* ECC mechanism may be disabled, depending on driver status */ + FmDisableRamsEcc(p_Fm); + tmpReg &= ~FPM_MURAM_ECC_ERR_EX_EN; + } + + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmrie, tmpReg); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); + } + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + t_FmIpcRevisionInfo ipcRevInfo; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_REV; + replyLength = sizeof(uint32_t) + sizeof(t_FmRevisionInfo); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmRevisionInfo))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)&ipcRevInfo, reply.replyBody, sizeof(t_FmRevisionInfo)); + p_FmRevisionInfo->majorRev = ipcRevInfo.majorRev; + p_FmRevisionInfo->minorRev = ipcRevInfo.minorRev; + return (t_Error)(reply.error); + } + + /* read revision register 1 */ + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fm_ip_rev_1); + p_FmRevisionInfo->majorRev = (uint8_t)((tmpReg & FPM_REV1_MAJOR_MASK) >> FPM_REV1_MAJOR_SHIFT); + p_FmRevisionInfo->minorRev = (uint8_t)((tmpReg & FPM_REV1_MINOR_MASK) >> FPM_REV1_MINOR_SHIFT); + + return E_OK; +} + +uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + uint32_t counterValue; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength, outCounter; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0); + + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_COUNTER; + memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t)); + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(counterValue), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if(replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t)); + + return outCounter; + } + + switch(counter) + { + case(e_FM_COUNTERS_ENQ_TOTAL_FRAME): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_etfc); + case(e_FM_COUNTERS_DEQ_TOTAL_FRAME): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dtfc); + case(e_FM_COUNTERS_DEQ_0): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc0); + case(e_FM_COUNTERS_DEQ_1): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc1); + case(e_FM_COUNTERS_DEQ_2): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc2); + case(e_FM_COUNTERS_DEQ_3): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc3); + case(e_FM_COUNTERS_DEQ_FROM_DEFAULT): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dfdc); + case(e_FM_COUNTERS_DEQ_FROM_CONTEXT): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dfcc); + case(e_FM_COUNTERS_DEQ_FROM_FD): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dffc); + case(e_FM_COUNTERS_DEQ_CONFIRM): + return GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_dcc); + case(e_FM_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT): + return GET_UINT32(p_Fm->p_FmDmaRegs->fmdmsefrc); + case(e_FM_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT): + return GET_UINT32(p_Fm->p_FmDmaRegs->fmdmsqfrc); + case(e_FM_COUNTERS_SEMAPHOR_SYNC_REJECT): + return GET_UINT32(p_Fm->p_FmDmaRegs->fmdmssrc); + default: + break; + } + /* should never get here */ + ASSERT_COND(FALSE); + + return 0; +} + +t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + /* When applicable (when there is an 'enable counters' bit, + check that counters are enabled */ + switch(counter) + { + case(e_FM_COUNTERS_ENQ_TOTAL_FRAME): + case(e_FM_COUNTERS_DEQ_TOTAL_FRAME): + case(e_FM_COUNTERS_DEQ_0): + case(e_FM_COUNTERS_DEQ_1): + case(e_FM_COUNTERS_DEQ_2): + case(e_FM_COUNTERS_DEQ_3): + case(e_FM_COUNTERS_DEQ_FROM_DEFAULT): + case(e_FM_COUNTERS_DEQ_FROM_CONTEXT): + case(e_FM_COUNTERS_DEQ_FROM_FD): + case(e_FM_COUNTERS_DEQ_CONFIRM): + if(!(GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc) & QMI_CFG_EN_COUNTERS)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + break; + default: + break; + } + + /* Set counter */ + switch(counter) + { + case(e_FM_COUNTERS_ENQ_TOTAL_FRAME): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_etfc, val); + break; + case(e_FM_COUNTERS_DEQ_TOTAL_FRAME): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dtfc, val); + break; + case(e_FM_COUNTERS_DEQ_0): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc0, val); + break; + case(e_FM_COUNTERS_DEQ_1): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc1, val); + break; + case(e_FM_COUNTERS_DEQ_2): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc2, val); + break; + case(e_FM_COUNTERS_DEQ_3): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dc3, val); + break; + case(e_FM_COUNTERS_DEQ_FROM_DEFAULT): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dfdc, val); + break; + case(e_FM_COUNTERS_DEQ_FROM_CONTEXT): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dfcc, val); + break; + case(e_FM_COUNTERS_DEQ_FROM_FD): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dffc, val); + break; + case(e_FM_COUNTERS_DEQ_CONFIRM): + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_dcc, val); + break; + case(e_FM_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT): + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmsefrc, val); + break; + case(e_FM_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT): + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmsqfrc, val); + break; + case(e_FM_COUNTERS_SEMAPHOR_SYNC_REJECT): + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmssrc, val); + break; + default: + break; + } + + return E_OK; +} + +void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t bitMask; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + bitMask = (uint32_t)((muramPort==e_FM_DMA_MURAM_PORT_WRITE) ? DMA_MODE_EMERGENCY_WRITE : DMA_MODE_EMERGENCY_READ); + + if(enable) + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmmr, GET_UINT32(p_Fm->p_FmDmaRegs->fmdmmr) | bitMask); + else /* disable */ + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmmr, GET_UINT32(p_Fm->p_FmDmaRegs->fmdmmr) & ~bitMask); + + return; +} + +void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + WRITE_UINT32(p_Fm->p_FmDmaRegs->fmdmmr, GET_UINT32(p_Fm->p_FmDmaRegs->fmdmmr) | ((uint32_t)pri << DMA_MODE_BUS_PRI_SHIFT) ); + + return; +} + +void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + t_FmIpcDmaStatus ipcDmaStatus; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_DMA_STAT; + replyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus))) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return; + } + memcpy((uint8_t*)&ipcDmaStatus, reply.replyBody, sizeof(t_FmIpcDmaStatus)); + + p_FmDmaStatus->cmqNotEmpty = (bool)ipcDmaStatus.boolCmqNotEmpty; /**< Command queue is not empty */ + p_FmDmaStatus->busError = (bool)ipcDmaStatus.boolBusError; /**< Bus error occurred */ + p_FmDmaStatus->readBufEccError = (bool)ipcDmaStatus.boolReadBufEccError; /**< Double ECC error on buffer Read */ + p_FmDmaStatus->writeBufEccSysError =(bool)ipcDmaStatus.boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */ + p_FmDmaStatus->writeBufEccFmError = (bool)ipcDmaStatus.boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */ + return; + } + + tmpReg = GET_UINT32(p_Fm->p_FmDmaRegs->fmdmsr); + + p_FmDmaStatus->cmqNotEmpty = (bool)(tmpReg & DMA_STATUS_CMD_QUEUE_NOT_EMPTY); + p_FmDmaStatus->busError = (bool)(tmpReg & DMA_STATUS_BUS_ERR); + p_FmDmaStatus->readBufEccError = (bool)(tmpReg & DMA_STATUS_READ_ECC); + p_FmDmaStatus->writeBufEccSysError = (bool)(tmpReg & DMA_STATUS_SYSTEM_WRITE_ECC); + p_FmDmaStatus->writeBufEccFmError = (bool)(tmpReg & DMA_STATUS_FM_WRITE_ECC); + return; +} + +t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + switch(exception) + { + case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eif, QMI_ERR_INTR_EN_DEQ_FROM_DEF); + break; + case e_FM_EX_QMI_SINGLE_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_SINGLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_if, QMI_INTR_EN_SINGLE_ECC); + break; + case e_FM_EX_QMI_DOUBLE_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_Fm->p_FmQmiRegs->fmqm_eif, QMI_ERR_INTR_EN_DOUBLE_ECC); + break; + case e_FM_EX_BMI_LIST_RAM_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_LIST_RAM_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ifr, BMI_ERR_INTR_EN_LIST_RAM_ECC); + break; + case e_FM_EX_BMI_PIPELINE_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_PIPELINE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ifr, BMI_ERR_INTR_EN_PIPELINE_ECC); + break; + case e_FM_EX_BMI_STATISTICS_RAM_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STATISTICS_RAM_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ifr, BMI_ERR_INTR_EN_STATISTICS_RAM_ECC); + break; + case e_FM_EX_BMI_DISPATCH_RAM_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_DISPATCH_RAM_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_Fm->p_FmBmiRegs->fmbm_ifr, BMI_ERR_INTR_EN_DISPATCH_RAM_ECC); + break; + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception may not be forced")); + } + + return E_OK; +} + +void FM_Resume(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t tmpReg; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + if (p_Fm->guestId == NCSW_MASTER_ID) + { + tmpReg = GET_UINT32(p_Fm->p_FmFpmRegs->fpmem); + /* clear tmpReg event bits in order not to clear standing events */ + tmpReg &= ~(FPM_EV_MASK_DOUBLE_ECC | FPM_EV_MASK_STALL | FPM_EV_MASK_SINGLE_ECC); + WRITE_UINT32(p_Fm->p_FmFpmRegs->fpmem, tmpReg | FPM_EV_MASK_RELEASE_FM); + } + else + ASSERT_COND(0); /* TODO */ +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FM_DumpRegs(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + uint8_t i = 0; + t_Error err; + t_FmIpcMsg msg; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + + if(p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_DUMP_REGS; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + + + DUMP_SUBTITLE(("\n")); + + DUMP_TITLE(p_Fm->p_FmFpmRegs, ("FmFpmRegs Regs")); + + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmtnc); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmpr); + DUMP_VAR(p_Fm->p_FmFpmRegs,brkc); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmflc); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmdis1); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmdis2); + DUMP_VAR(p_Fm->p_FmFpmRegs,fmepi); + DUMP_VAR(p_Fm->p_FmFpmRegs,fmrie); + + DUMP_TITLE(&p_Fm->p_FmFpmRegs->fmfpfcev, ("fmfpfcev")); + DUMP_SUBSTRUCT_ARRAY(i, 4) + { + DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fmfpfcev[i], sizeof(uint32_t)); + } + + DUMP_TITLE(&p_Fm->p_FmFpmRegs->fmfpfcee, ("fmfpfcee")); + DUMP_SUBSTRUCT_ARRAY(i, 4) + { + DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fmfpfcee[i], sizeof(uint32_t)); + } + + DUMP_SUBTITLE(("\n")); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmtsc1); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmtsc2); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmtsp); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmtsf); + DUMP_VAR(p_Fm->p_FmFpmRegs,fmrcr); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmextc); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmext1); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmext2); + + DUMP_TITLE(&p_Fm->p_FmFpmRegs->fpmdrd, ("fpmdrd")); + DUMP_SUBSTRUCT_ARRAY(i, 16) + { + DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fpmdrd[i], sizeof(uint32_t)); + } + + DUMP_SUBTITLE(("\n")); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmdra); + DUMP_VAR(p_Fm->p_FmFpmRegs,fm_ip_rev_1); + DUMP_VAR(p_Fm->p_FmFpmRegs,fm_ip_rev_2); + DUMP_VAR(p_Fm->p_FmFpmRegs,fmrstc); + DUMP_VAR(p_Fm->p_FmFpmRegs,fmcld); + DUMP_VAR(p_Fm->p_FmFpmRegs,fmnpi); + DUMP_VAR(p_Fm->p_FmFpmRegs,fpmem); + + DUMP_TITLE(&p_Fm->p_FmFpmRegs->fpmcev, ("fpmcev")); + DUMP_SUBSTRUCT_ARRAY(i, 4) + { + DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fpmcev[i], sizeof(uint32_t)); + } + + DUMP_TITLE(&p_Fm->p_FmFpmRegs->fmfp_ps, ("fmfp_ps")); + DUMP_SUBSTRUCT_ARRAY(i, 64) + { + DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fmfp_ps[i], sizeof(uint32_t)); + } + + + DUMP_TITLE(p_Fm->p_FmDmaRegs, ("p_FmDmaRegs Regs")); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmsr); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmmr); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmtr); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmhy); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmsetr); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmtah); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmtal); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmtcid); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmra); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmrd); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmwcr); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmebcr); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmccqdr); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmccqvr1); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmccqvr2); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmcqvr3); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmcqvr4); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmcqvr5); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmsefrc); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmsqfrc); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmssrc); + DUMP_VAR(p_Fm->p_FmDmaRegs,fmdmdcr); + + DUMP_TITLE(&p_Fm->p_FmDmaRegs->fmdmplr, ("fmdmplr")); + + DUMP_SUBSTRUCT_ARRAY(i, FM_SIZE_OF_LIODN_TABLE/2) + { + DUMP_MEMORY(&p_Fm->p_FmDmaRegs->fmdmplr[i], sizeof(uint32_t)); + } + + DUMP_TITLE(p_Fm->p_FmBmiRegs, ("p_FmBmiRegs COMMON Regs")); + DUMP_VAR(p_Fm->p_FmBmiRegs,fmbm_init); + DUMP_VAR(p_Fm->p_FmBmiRegs,fmbm_cfg1); + DUMP_VAR(p_Fm->p_FmBmiRegs,fmbm_cfg2); + DUMP_VAR(p_Fm->p_FmBmiRegs,fmbm_ievr); + DUMP_VAR(p_Fm->p_FmBmiRegs,fmbm_ier); + + DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_arb, ("fmbm_arb")); + DUMP_SUBSTRUCT_ARRAY(i, 8) + { + DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_arb[i], sizeof(uint32_t)); + } + + + DUMP_TITLE(p_Fm->p_FmQmiRegs, ("p_FmQmiRegs COMMON Regs")); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_gc); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_eie); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_eien); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_eif); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_ie); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_ien); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_if); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_gs); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_ts); + DUMP_VAR(p_Fm->p_FmQmiRegs,fmqm_etfc); + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk +NCSW_FM_INC = $(srctree)/drivers/net/dpa/NetCommSw/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) + + +obj-y += fsl-ncsw-PFM1.o + +fsl-ncsw-PFM1-objs := fm.o fm_muram.o + +obj-y += MAC/ +obj-y += Pcd/ +obj-y += Port/ +obj-y += HC/ +obj-y += Rtc/ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/fm_ipc.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/fm_ipc.h @@ -0,0 +1,449 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_ipc.h + + @Description FM Inter-Partition prototypes, structures and definitions. +*//***************************************************************************/ +#ifndef __FM_IPC_H +#define __FM_IPC_H + +#include "error_ext.h" +#include "std_ext.h" + + +/**************************************************************************//** + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_IPC_grp FM Inter-Partition messaging Unit + + @Description FM Inter-Partition messaging unit API definitions and enums. + + @{ +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/**************************************************************************//** + @Description enum for defining MAC types +*//***************************************************************************/ + +/**************************************************************************//** + @Description A structure of parameters for specifying a MAC. +*//***************************************************************************/ +typedef _Packed struct +{ + uint8_t id; + uint32_t enumType; +} _PackedType t_FmIpcMacParams; + +/**************************************************************************//** + @Description A structure of parameters for specifying a MAC. +*//***************************************************************************/ +typedef _Packed struct +{ + t_FmIpcMacParams macParams; + uint16_t maxFrameLength; +} _PackedType t_FmIpcMacMaxFrameParams; + +/**************************************************************************//** + @Description FM physical Address +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPhysAddr +{ + volatile uint8_t high; + volatile uint32_t low; +} _PackedType t_FmIpcPhysAddr; + +/**************************************************************************//** + @Description Structure for IPC communication during FM_PORT_Init. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortInInitParams { + uint8_t hardwarePortId; /**< IN. port Id */ + uint32_t enumPortType; /**< IN. Port type */ + uint8_t boolIndependentMode;/**< IN. TRUE if FM Port operates in independent mode */ + uint16_t liodnOffset; /**< IN. Port's requested resource */ + uint8_t numOfTasks; /**< IN. Port's requested resource */ + uint8_t numOfExtraTasks; /**< IN. Port's requested resource */ + uint8_t numOfOpenDmas; /**< IN. Port's requested resource */ + uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */ + uint32_t sizeOfFifo; /**< IN. Port's requested resource */ + uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */ + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ + uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1. + LIODN base for this port, to be + used together with LIODN offset. */ +} _PackedType t_FmIpcPortInInitParams; + + +/**************************************************************************//** + @Description Structure for IPC communication between port and FM + regarding tasks and open DMA resources management. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortRsrcParams { + uint8_t hardwarePortId; /**< IN. port Id */ + uint32_t val; /**< IN. Port's requested resource */ + uint32_t extra; /**< IN. Port's requested resource */ + uint8_t boolInitialConfig; +} _PackedType t_FmIpcPortRsrcParams; + + +/**************************************************************************//** + @Description Structure for IPC communication between port and FM + regarding tasks and open DMA resources management. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortFifoParams { + t_FmIpcPortRsrcParams rsrcParams; + uint32_t enumPortType; + uint8_t boolIndependentMode; + uint8_t deqPipelineDepth; + uint8_t numOfPools; + uint16_t secondLargestBufSize; + uint16_t largestBufSize; + uint8_t boolInitialConfig; +} _PackedType t_FmIpcPortFifoParams; + +/**************************************************************************//** + @Description Structure for port-FM communication during FM_PORT_Free. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortFreeParams { + uint8_t hardwarePortId; /**< IN. port Id */ + uint32_t enumPortType; /**< IN. Port type */ +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ +} _PackedType t_FmIpcPortFreeParams; + +/**************************************************************************//** + @Description Structure for defining DMA status +*//***************************************************************************/ +typedef _Packed struct t_FmIpcDmaStatus { + uint8_t boolCmqNotEmpty; /**< Command queue is not empty */ + uint8_t boolBusError; /**< Bus error occurred */ + uint8_t boolReadBufEccError; /**< Double ECC error on buffer Read */ + uint8_t boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */ + uint8_t boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */ +} _PackedType t_FmIpcDmaStatus; + +typedef _Packed struct t_FmIpcRegisterIntr +{ + uint8_t guestId; /* IN */ + uint32_t event; /* IN */ +} _PackedType t_FmIpcRegisterIntr; + +typedef _Packed struct t_FmIpcIsr +{ + uint8_t boolErr; /* IN */ + uint32_t pendingReg; /* IN */ +} _PackedType t_FmIpcIsr; + +/**************************************************************************//** + @Description structure for returning revision information +*//***************************************************************************/ +typedef _Packed struct t_FmIpcRevisionInfo { + uint8_t majorRev; /**< OUT: Major revision */ + uint8_t minorRev; /**< OUT: Minor revision */ +} _PackedType t_FmIpcRevisionInfo; + +/**************************************************************************//** + @Description Structure for defining Fm number of Fman controlers +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortNumOfFmanCtrls { + uint8_t hardwarePortId; /**< IN. port Id */ + uint8_t numOfFmanCtrls; /**< IN. Port type */ +} t_FmIpcPortNumOfFmanCtrls; + +/**************************************************************************//** + @Description structure for setting Fman contriller events +*//***************************************************************************/ +typedef _Packed struct t_FmIpcFmanEvents { + uint8_t eventRegId; /**< IN: Fman controller event register id */ + uint32_t enableEvents; /**< IN/OUT: required enabled events mask */ +} _PackedType t_FmIpcFmanEvents; + +#define FM_IPC_MAX_REPLY_BODY_SIZE 16 +#define FM_IPC_MAX_REPLY_SIZE (FM_IPC_MAX_REPLY_BODY_SIZE + sizeof(uint32_t)) +#define FM_IPC_MAX_MSG_SIZE 30 +typedef _Packed struct t_FmIpcMsg +{ + uint32_t msgId; + uint8_t msgBody[FM_IPC_MAX_MSG_SIZE]; +} _PackedType t_FmIpcMsg; + +typedef _Packed struct t_FmIpcReply +{ + uint32_t error; + uint8_t replyBody[FM_IPC_MAX_REPLY_BODY_SIZE]; +} _PackedType t_FmIpcReply; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/***************************************************************************/ +/************************ FRONT-END-TO-BACK-END*****************************/ +/***************************************************************************/ + +/**************************************************************************//** + @Function FM_GET_TIMESTAMP_SCALE + + @Description Used by FM front-end. + + @Param[out] uint32_t Pointer +*//***************************************************************************/ +#define FM_GET_TIMESTAMP_SCALE 1 + +/**************************************************************************//** + @Function FM_GET_COUNTER + + @Description Used by FM front-end. + + @Param[in/out] t_FmIpcGetCounter Pointer +*//***************************************************************************/ +#define FM_GET_COUNTER 2 + +/**************************************************************************//** + @Function FM_DUMP_REGS + + @Description Used by FM front-end for the PORT module in order to set and get + parameters in/from master FM module on FM PORT initialization time. + + @Param None +*//***************************************************************************/ +#define FM_DUMP_REGS 3 + +/**************************************************************************//** + @Function FM_GET_SET_PORT_PARAMS + + @Description Used by FM front-end for the PORT module in order to set and get + parameters in/from master FM module on FM PORT initialization time. + + @Param[in/out] t_FmIcPortInitParams Pointer +*//***************************************************************************/ +#define FM_GET_SET_PORT_PARAMS 4 + +/**************************************************************************//** + @Function FM_FREE_PORT + + @Description Used by FM front-end for the PORT module when a port is freed + to free all FM PORT resources. + + @Param[in] uint8_t Pointer +*//***************************************************************************/ +#define FM_FREE_PORT 5 + +/**************************************************************************//** + @Function FM_RESET_MAC + + @Description Used by front-end for the MAC module to reset the MAC registers + + @Param[in] t_FmIpcMacParams Pointer . +*//***************************************************************************/ +#define FM_RESET_MAC 6 + +/**************************************************************************//** + @Function FM_RESUME_STALLED_PORT + + @Description Used by FM front-end for the PORT module in order to + release a stalled FM Port. + + @Param[in] uint8_t Pointer +*//***************************************************************************/ +#define FM_RESUME_STALLED_PORT 7 + +/**************************************************************************//** + @Function FM_IS_PORT_STALLED + + @Description Used by FM front-end for the PORT module in order to check whether + an FM port is stalled. + + @Param[in/out] t_FmIcPortIsStalled Pointer +*//***************************************************************************/ +#define FM_IS_PORT_STALLED 8 + +/**************************************************************************//** + @Function FM_DUMP_PORT_REGS + + @Description Used by FM front-end for the PORT module in order to dump + all port registers. + + @Param[in] uint8_t Pointer +*//***************************************************************************/ +#define FM_DUMP_PORT_REGS 9 + +/**************************************************************************//** + @Function FM_GET_REV + + @Description Used by FM front-end for the PORT module in order to dump + all port registers. + + @Param[in] uint8_t Pointer +*//***************************************************************************/ +#define FM_GET_REV 10 + +/**************************************************************************//** + @Function FM_REGISTER_INTR + + @Description Used by FM front-end to register an interrupt handler to + be called upon interrupt for guest. + + @Param[out] t_FmIpcRegisterIntr Pointer +*//***************************************************************************/ +#define FM_REGISTER_INTR 11 + +/**************************************************************************//** + @Function FM_GET_CLK_FREQ + + @Description Used by FM Front-end to read the FM clock frequency. + + @Param[out] uint32_t Pointer +*//***************************************************************************/ +#define FM_GET_CLK_FREQ 12 + +/**************************************************************************//** + @Function FM_DMA_STAT + + @Description Used by FM front-end to read the FM DMA status. + + @Param[out] t_FmIpcDmaStatus Pointer +*//***************************************************************************/ +#define FM_DMA_STAT 13 + +/**************************************************************************//** + @Function FM_ALLOC_FMAN_CTRL_EVENT_REG + + @Description Used by FM front-end to allocate event register. + + @Param[out] Event register id Pointer +*//***************************************************************************/ +#define FM_ALLOC_FMAN_CTRL_EVENT_REG 14 + +/**************************************************************************//** + @Function FM_FREE_FMAN_CTRL_EVENT_REG + + @Description Used by FM front-end to free locate event register. + + @Param[in] uint8_t Pointer - Event register id +*//***************************************************************************/ +#define FM_FREE_FMAN_CTRL_EVENT_REG 15 + +/**************************************************************************//** + @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE + + @Description Used by FM front-end to enable events in the FPM + Fman controller event register. + + @Param[in] t_FmIpcFmanEvents Pointer +*//***************************************************************************/ +#define FM_SET_FMAN_CTRL_EVENTS_ENABLE 16 + +/**************************************************************************//** + @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE + + @Description Used by FM front-end to enable events in the FPM + Fman controller event register. + + @Param[in/out] t_FmIpcFmanEvents Pointer +*//***************************************************************************/ +#define FM_GET_FMAN_CTRL_EVENTS_ENABLE 17 + +/**************************************************************************//** + @Function FM_SET_MAC_MAX_FRAME + + @Description Used by FM front-end to set MAC's MTU/RTU's in + back-end. + + @Param[in/out] t_FmIpcMacMaxFrameParams Pointer +*//***************************************************************************/ +#define FM_SET_MAC_MAX_FRAME 18 + +/**************************************************************************//** + @Function FM_GET_PHYS_MURAM_BASE + + @Description Used by FM front-end in order to get MURAM base address + + @Param[in/out] t_FmIpcPhysAddr Pointer +*//***************************************************************************/ +#define FM_GET_PHYS_MURAM_BASE 19 + +/**************************************************************************//** + @Function FM_MASTER_IS_ALIVE + + @Description Used by FM front-end in order to verify Master is up + + @Param[in/out] bool +*//***************************************************************************/ +#define FM_MASTER_IS_ALIVE 20 + +#define FM_ENABLE_RAM_ECC 21 +#define FM_DISABLE_RAM_ECC 22 +#define FM_SET_NUM_OF_FMAN_CTRL 23 +#define FM_SET_SIZE_OF_FIFO 24 +#define FM_SET_NUM_OF_TASKS 25 +#define FM_SET_NUM_OF_OPEN_DMAS 26 + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +#define FM_10G_TX_ECC_WA 100 +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +/***************************************************************************/ +/************************ BACK-END-TO-FRONT-END*****************************/ +/***************************************************************************/ + +/**************************************************************************//** + @Function FM_GUEST_ISR + + @Description Used by FM back-end to report an interrupt to the front-end. + + @Param[out] t_FmIpcIsr Pointer +*//***************************************************************************/ +#define FM_GUEST_ISR 1 + + + +/** @} */ /* end of FM_IPC_grp group */ +/** @} */ /* end of FM_grp group */ + + +#endif /* __FM_IPC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/fm_muram.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/fm_muram.c @@ -0,0 +1,164 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File FM_muram.c + + @Description FM MURAM ... +*//***************************************************************************/ +#include "error_ext.h" +#include "std_ext.h" +#include "mm_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "fm_muram_ext.h" +#include "fm_common.h" + + +#define __ERR_MODULE__ MODULE_FM_MURAM + + +typedef struct +{ + t_Handle h_Mem; + uintptr_t baseAddr; + uint32_t size; +} t_FmMuram; + + +void FmMuramClear(t_Handle h_FmMuram) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + + SANITY_CHECK_RETURN(h_FmMuram, E_INVALID_HANDLE); + IOMemSet32(UINT_TO_PTR(p_FmMuram->baseAddr), 0, p_FmMuram->size); +} + + +t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size) +{ + t_Handle h_Mem; + t_FmMuram *p_FmMuram; + + if (!baseAddress) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress 0 is not supported")); + return NULL; + } + + if (baseAddress%4) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress not 4 bytes aligned!")); + return NULL; + } + + /* Allocate FM MURAM structure */ + p_FmMuram = (t_FmMuram *) XX_Malloc(sizeof(t_FmMuram)); + if (!p_FmMuram) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MURAM driver structure")); + return NULL; + } + memset(p_FmMuram, 0, sizeof(t_FmMuram)); + + + if ((MM_Init(&h_Mem, baseAddress, size) != E_OK) || (!h_Mem)) + { + XX_Free(p_FmMuram); + REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM partition!!!")); + return NULL; + } + + /* Initialize FM MURAM parameters which will be kept by the driver */ + p_FmMuram->baseAddr = baseAddress; + p_FmMuram->size = size; + p_FmMuram->h_Mem = h_Mem; + + return p_FmMuram; +} + +t_Error FM_MURAM_Free(t_Handle h_FmMuram) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + + if (p_FmMuram->h_Mem) + MM_Free(p_FmMuram->h_Mem); + + XX_Free(h_FmMuram); + + return E_OK; +} + +void * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + uintptr_t addr; + + SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL); + + addr = (uintptr_t)MM_Get(p_FmMuram->h_Mem, size, align ,"FM MURAM"); + + if (addr == ILLEGAL_BASE) + return NULL; + + return UINT_TO_PTR(addr); +} + +void * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + uintptr_t addr; + + SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL); + + addr = (uintptr_t)MM_GetForce(p_FmMuram->h_Mem, base, size, "FM MURAM"); + + if (addr == ILLEGAL_BASE) + return NULL; + + return UINT_TO_PTR(addr); +} + +t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + + SANITY_CHECK_RETURN_ERROR(h_FmMuram, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMuram->h_Mem, E_INVALID_HANDLE); + + if (MM_Put(p_FmMuram->h_Mem, PTR_TO_UINT(ptr)) == 0) + RETURN_ERROR(MINOR, E_INVALID_HANDLE, ("memory pointer!!!")); + + return E_OK; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/HC/hc.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/HC/hc.c @@ -0,0 +1,1584 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "std_ext.h" +#include "error_ext.h" +#include "sprint_ext.h" +#include "string_ext.h" + +#include "fm_common.h" +#include "fm_hc.h" + + +#define HC_HCOR_OPCODE_PLCR_PRFL 0x0 +#define HC_HCOR_OPCODE_KG_SCM 0x1 +#define HC_HCOR_OPCODE_SYNC 0x2 +#define HC_HCOR_OPCODE_CC 0x3 +#define HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT 0x5 + +#define HC_HCOR_GBL 0x20000000 + +#define SIZE_OF_HC_FRAME_PORT_REGS (sizeof(t_HcFrame)-sizeof(t_FmPcdKgInterModuleSchemeRegs)+sizeof(t_FmPcdKgPortRegs)) +#define SIZE_OF_HC_FRAME_SCHEME_REGS sizeof(t_HcFrame) +#define SIZE_OF_HC_FRAME_PROFILES_REGS (sizeof(t_HcFrame)-sizeof(t_FmPcdKgInterModuleSchemeRegs)+sizeof(t_FmPcdPlcrInterModuleProfileRegs)) +#define SIZE_OF_HC_FRAME_PROFILE_CNT (sizeof(t_HcFrame)-sizeof(t_FmPcdPlcrInterModuleProfileRegs)+sizeof(uint32_t)) +#define SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC 16 + +#define BUILD_FD(len) \ +do { \ + memset(&fmFd, 0, sizeof(t_DpaaFD)); \ + DPAA_FD_SET_ADDR(&fmFd, p_HcFrame); \ + DPAA_FD_SET_OFFSET(&fmFd, 0); \ + DPAA_FD_SET_LENGTH(&fmFd, len); \ +} while (0) + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/**************************************************************************//** + @Description PCD KG scheme registers +*//***************************************************************************/ +typedef _Packed struct t_FmPcdKgSchemeRegsWithoutCounter { + volatile uint32_t kgse_mode; /**< MODE */ + volatile uint32_t kgse_ekfc; /**< Extract Known Fields Command */ + volatile uint32_t kgse_ekdv; /**< Extract Known Default Value */ + volatile uint32_t kgse_bmch; /**< Bit Mask Command High */ + volatile uint32_t kgse_bmcl; /**< Bit Mask Command Low */ + volatile uint32_t kgse_fqb; /**< Frame Queue Base */ + volatile uint32_t kgse_hc; /**< Hash Command */ + volatile uint32_t kgse_ppc; /**< Policer Profile Command */ + volatile uint32_t kgse_gec[FM_PCD_KG_NUM_OF_GENERIC_REGS]; + /**< Generic Extract Command */ + volatile uint32_t kgse_dv0; /**< KeyGen Scheme Entry Default Value 0 */ + volatile uint32_t kgse_dv1; /**< KeyGen Scheme Entry Default Value 1 */ + volatile uint32_t kgse_ccbs; /**< KeyGen Scheme Entry Coarse Classification Bit*/ + volatile uint32_t kgse_mv; /**< KeyGen Scheme Entry Match vector */ +} _PackedType t_FmPcdKgSchemeRegsWithoutCounter; + +typedef _Packed struct t_FmPcdKgPortRegs { + volatile uint32_t spReg; + volatile uint32_t cppReg; +} _PackedType t_FmPcdKgPortRegs; + +typedef _Packed struct t_HcFrame { + volatile uint32_t opcode; + volatile uint32_t actionReg; + volatile uint32_t extraReg; + volatile uint32_t commandSequence; + union { + t_FmPcdKgInterModuleSchemeRegs schemeRegs; + t_FmPcdKgInterModuleSchemeRegs schemeRegsWithoutCounter; + t_FmPcdPlcrInterModuleProfileRegs profileRegs; + volatile uint32_t singleRegForWrite; /* for writing SP, CPP, profile counter */ + t_FmPcdKgPortRegs portRegsForRead; + volatile uint32_t clsPlanEntries[CLS_PLAN_NUM_PER_GRP]; + t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeout; + } hcSpecificData; +} _PackedType t_HcFrame; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +typedef struct t_FmHc { + t_Handle h_FmPcd; + t_Handle h_HcPortDev; + t_FmPcdQmEnqueueCallback *f_QmEnqueue; /**< A callback for enqueuing frames to the QM */ + t_Handle h_QmArg; /**< A handle to the QM module */ + uint8_t padTill16; + + uint32_t seqNum; + volatile bool wait[32]; +} t_FmHc; + + +static __inline__ t_Error EnQFrm(t_FmHc *p_FmHc, t_DpaaFD *p_FmFd, volatile uint32_t *p_SeqNum) +{ + t_Error err = E_OK; + uint32_t savedSeqNum; + uint32_t intFlags; + uint32_t timeout=100; + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + *p_SeqNum = p_FmHc->seqNum; + savedSeqNum = p_FmHc->seqNum; + p_FmHc->seqNum = (uint32_t)((p_FmHc->seqNum+1)%32); + ASSERT_COND(!p_FmHc->wait[savedSeqNum]); + p_FmHc->wait[savedSeqNum] = TRUE; + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + DBG(TRACE, ("Send Hc, SeqNum %d, FD@0x%x, fd offset 0x%x", + savedSeqNum,DPAA_FD_GET_ADDR(p_FmFd),DPAA_FD_GET_OFFSET(p_FmFd))); + err = p_FmHc->f_QmEnqueue(p_FmHc->h_QmArg, (void *)p_FmFd); + if(err) + RETURN_ERROR(MINOR, err, ("HC enqueue failed")); + + while (p_FmHc->wait[savedSeqNum] && --timeout) + XX_UDelay(100); + + if (!timeout) + RETURN_ERROR(MINOR, E_TIMEOUT, ("HC Callback, timeout exceeded")); + + return err; +} + +static t_Error CcHcDoDynamicChange(t_FmHc *p_FmHc, t_Handle p_OldPointer, t_Handle p_NewPointer) +{ + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err = E_OK; + + ASSERT_COND(p_FmHc); + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC); + p_HcFrame->actionReg = FmPcdCcGetNodeAddrOffsetFromNodeInfo(p_FmHc->h_FmPcd, p_NewPointer); + if(p_HcFrame->actionReg == (uint32_t)ILLEGAL_BASE) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something wrong with base address")); + } + + p_HcFrame->actionReg |= 0xc0000000; + p_HcFrame->extraReg = FmPcdCcGetNodeAddrOffsetFromNodeInfo(p_FmHc->h_FmPcd, p_OldPointer); + if(p_HcFrame->extraReg == (uint32_t)ILLEGAL_BASE) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something wrong with base address")); + } + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + XX_FreeSmart(p_HcFrame); + + return E_OK; +} + +static t_Error HcDynamicChange(t_FmHc *p_FmHc,t_List *h_OldPointersLst, t_List *h_NewPointersLst, t_Handle *h_Params) +{ + + t_List *p_PosOld, *p_PosNew; + uint16_t i = 0; + t_Error err = E_OK; + uint8_t numOfModifiedPtr; + + SANITY_CHECK_RETURN_ERROR((LIST_NumOfObjs(h_NewPointersLst) == LIST_NumOfObjs(h_OldPointersLst)),E_INVALID_STATE); + + numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_NewPointersLst); + p_PosNew = LIST_FIRST(h_NewPointersLst); + p_PosOld = LIST_FIRST(h_OldPointersLst); + for(i = 0; i < numOfModifiedPtr; i++) + { + err = CcHcDoDynamicChange(p_FmHc, p_PosOld, p_PosNew); + if(err) + { + FmPcdCcReleaseModifiedDataStructure(p_FmHc->h_FmPcd, h_OldPointersLst, h_NewPointersLst, i, h_Params); + RETURN_ERROR(MAJOR, err, ("For part of nodes changes are done - situation is danger")); + } + p_PosNew = LIST_NEXT(p_PosNew); + p_PosOld = LIST_NEXT(p_PosOld); + } + + err = FmPcdCcReleaseModifiedDataStructure(p_FmHc->h_FmPcd, h_OldPointersLst, h_NewPointersLst, i, h_Params); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + + +t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams) +{ + t_FmHc *p_FmHc; + t_FmPortParams fmPortParam; + t_Error err = E_OK; + + p_FmHc = (t_FmHc *)XX_Malloc(sizeof(t_FmHc)); + if (!p_FmHc) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC obj")); + return NULL; + } + memset(p_FmHc,0,sizeof(t_FmHc)); + + p_FmHc->h_FmPcd = p_FmHcParams->h_FmPcd; + p_FmHc->f_QmEnqueue = p_FmHcParams->params.f_QmEnqueue; + p_FmHc->h_QmArg = p_FmHcParams->params.h_QmArg; + + if (!FmIsMaster(p_FmHcParams->h_Fm)) + return (t_Handle)p_FmHc; + +/* +TKT056919 - axi12axi0 can hang if read request follows the single byte write on the very next cycle +TKT038900 - FM dma lockup occur due to AXI slave protocol violation +*/ +#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 + p_FmHc->padTill16 = 16 - (sizeof(t_FmHc) % 16); +#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */ + memset(&fmPortParam, 0, sizeof(fmPortParam)); + fmPortParam.baseAddr = p_FmHcParams->params.portBaseAddr; + fmPortParam.portType = e_FM_PORT_TYPE_OH_HOST_COMMAND; + fmPortParam.portId = p_FmHcParams->params.portId; + fmPortParam.liodnBase = p_FmHcParams->params.liodnBase; + fmPortParam.h_Fm = p_FmHcParams->h_Fm; + + fmPortParam.specificParams.nonRxParams.errFqid = p_FmHcParams->params.errFqid; + fmPortParam.specificParams.nonRxParams.dfltFqid = p_FmHcParams->params.confFqid; + fmPortParam.specificParams.nonRxParams.qmChannel = p_FmHcParams->params.qmChannel; + + p_FmHc->h_HcPortDev = FM_PORT_Config(&fmPortParam); + if(!p_FmHc->h_HcPortDev) + { + REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM HC port!")); + XX_Free(p_FmHc); + return NULL; + } + + /* final init */ + if ((err = FM_PORT_Init(p_FmHc->h_HcPortDev)) != E_OK) + { + REPORT_ERROR(MAJOR, err, ("FM HC port!")); + FmHcFree(p_FmHc); + return NULL; + } + + if ((err = FM_PORT_Enable(p_FmHc->h_HcPortDev)) != E_OK) + { + REPORT_ERROR(MAJOR, err, ("FM HC port!")); + FmHcFree(p_FmHc); + return NULL; + } + + return (t_Handle)p_FmHc; +} + +void FmHcFree(t_Handle h_FmHc) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + + if (!p_FmHc) + return; + + if (p_FmHc->h_HcPortDev) + FM_PORT_Free(p_FmHc->h_HcPortDev); + + XX_Free(p_FmHc); +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FmHcDumpRegs(t_Handle h_FmHc) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + + SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmHc->h_HcPortDev, E_INVALID_HANDLE); + + return FM_PORT_DumpRegs(p_FmHc->h_HcPortDev); + +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + +void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + uint32_t intFlags; + + ASSERT_COND(p_FmHc); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + p_HcFrame = (t_HcFrame *)PTR_MOVE(DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd)); + + DBG(TRACE, ("Hc Conf, SeqNum %d, FD@0x%x, fd offset 0x%x", + p_HcFrame->commandSequence, DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd))); + + if (!(p_FmHc->wait[p_HcFrame->commandSequence])) + REPORT_ERROR(MINOR, E_INVALID_FRAME, ("Not an Host-Command frame received!")); + else + p_FmHc->wait[p_HcFrame->commandSequence] = FALSE; + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); +} + +t_Handle FmHcPcdKgSetScheme(t_Handle h_FmHc, t_FmPcdKgSchemeParams *p_Scheme) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_FmPcdKgInterModuleSchemeRegs schemeRegs; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t intFlags; + uint8_t physicalSchemeId, relativeSchemeId; + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + return NULL; + } + + if(!p_Scheme->modify) + { + /* check that schemeId is in range */ + if(p_Scheme->id.relativeSchemeId >= FmPcdKgGetNumOfPartitionSchemes(p_FmHc->h_FmPcd)) + { + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of range")); + XX_FreeSmart(p_HcFrame); + return NULL; + } + + relativeSchemeId = p_Scheme->id.relativeSchemeId; + + if (FmPcdKgSchemeTryLock(p_FmHc->h_FmPcd, relativeSchemeId, FALSE)) + { + XX_FreeSmart(p_HcFrame); + return NULL; + } + + physicalSchemeId = FmPcdKgGetPhysicalSchemeId(p_FmHc->h_FmPcd, relativeSchemeId); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + p_HcFrame->extraReg = 0xFFFFF800; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + REPORT_ERROR(MINOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return NULL; + } + + /* check if this scheme is already used */ + if (FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode)) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is already used")); + XX_FreeSmart(p_HcFrame); + return NULL; + } + } + else + { + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_Scheme->id.h_Scheme)-1); + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + if( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + { + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + XX_FreeSmart(p_HcFrame); + return NULL; + } + err = FmPcdKgSchemeTryLock(p_FmHc->h_FmPcd, relativeSchemeId, TRUE); + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + if (err) + { + XX_FreeSmart(p_HcFrame); + return NULL; + } + } + + err = FmPcdKgBuildScheme(p_FmHc->h_FmPcd, p_Scheme, &schemeRegs); + if(err) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + REPORT_ERROR(MAJOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return NULL; + } + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_Scheme->schemeCounter.update); + p_HcFrame->extraReg = 0xFFFFF800; + memcpy(&p_HcFrame->hcSpecificData.schemeRegs, &schemeRegs, sizeof(t_FmPcdKgInterModuleSchemeRegs)); + if(!p_Scheme->schemeCounter.update) + { + p_HcFrame->hcSpecificData.schemeRegs.kgse_dv0 = schemeRegs.kgse_dv0; + p_HcFrame->hcSpecificData.schemeRegs.kgse_dv1 = schemeRegs.kgse_dv1; + p_HcFrame->hcSpecificData.schemeRegs.kgse_ccbs = schemeRegs.kgse_ccbs; + p_HcFrame->hcSpecificData.schemeRegs.kgse_mv = schemeRegs.kgse_mv; + } + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + REPORT_ERROR(MINOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return NULL; + } + + FmPcdKgValidateSchemeSw(p_FmHc->h_FmPcd, relativeSchemeId); + + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + + XX_FreeSmart(p_HcFrame); + + return (t_Handle)(UINT_TO_PTR(physicalSchemeId + 1)); +} + +t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + + if ((err = FmPcdKgSchemeTryLock(p_FmHc->h_FmPcd, relativeSchemeId, FALSE)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if(relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + } + + err = FmPcdKgCheckInvalidateSchemeSw(p_FmHc->h_FmPcd, relativeSchemeId); + if (err) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + } + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); + p_HcFrame->extraReg = 0xFFFFF800; + memset(&p_HcFrame->hcSpecificData.schemeRegs, 0, sizeof(t_FmPcdKgInterModuleSchemeRegs)); + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + FmPcdKgInvalidateSchemeSw(p_FmHc->h_FmPcd, relativeSchemeId); + + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + + XX_FreeSmart(p_HcFrame); + + return E_OK; +} + +t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + uint32_t tmpReg32 = 0; + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + if( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if (FmPcdKgSchemeTryLock(p_FmHc->h_FmPcd, relativeSchemeId, FALSE)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Lock of the scheme FAILED")); + + if(!FmPcdKgGetPointedOwners(p_FmHc->h_FmPcd, relativeSchemeId) || + !(FmPcdKgGetRequiredAction(p_FmHc->h_FmPcd, relativeSchemeId) & requiredAction)) + { + + if(requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + { + if((FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_DONE) && (FmPcdKgGetDoneAction(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_ENQ_FRAME)) + + { + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + } + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + p_HcFrame->extraReg = 0xFFFFF800; + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* check if this scheme is already used */ + if (!FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode)) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is already used")); + } + tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode; + + ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); + + p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + p_HcFrame->extraReg = 0x80000000; + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + XX_FreeSmart(p_HcFrame); + } + else if (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_PLCR) + { + + if((FmPcdKgIsDirectPlcr(p_FmHc->h_FmPcd, relativeSchemeId) == FALSE) || + (FmPcdKgIsDistrOnPlcrProfile(p_FmHc->h_FmPcd, relativeSchemeId) == TRUE)) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared")); + } + err = FmPcdPlcrCcGetSetParams(p_FmHc->h_FmPcd, FmPcdKgGetRelativeProfileId(p_FmHc->h_FmPcd, relativeSchemeId), requiredAction); + if(err) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + } + } + + FmPcdKgUpatePointedOwner(p_FmHc->h_FmPcd, relativeSchemeId,TRUE); + FmPcdKgUpdateRequiredAction(p_FmHc->h_FmPcd, relativeSchemeId,requiredAction); + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + + return E_OK; +} + +uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t retVal; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + if( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + { + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + return 0; + } + + if ((err = FmPcdKgSchemeTryLock(p_FmHc->h_FmPcd, relativeSchemeId, FALSE)) != E_OK) + { + REPORT_ERROR(MAJOR, err, ("Scheme lock")); + return 0; + } + + /* first read scheme and check that it is valid */ + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + return 0; + } + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + p_HcFrame->extraReg = 0xFFFFF800; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + REPORT_ERROR(MINOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return 0; + } + + if (!FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode)) + { + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is invalid")); + XX_FreeSmart(p_HcFrame); + return 0; + } + + retVal = p_HcFrame->hcSpecificData.schemeRegs.kgse_spc; + + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + + XX_FreeSmart(p_HcFrame); + + return retVal; +} + +t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t relativeSchemeId, physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + if( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if ((err = FmPcdKgSchemeTryLock(p_FmHc->h_FmPcd, relativeSchemeId, FALSE)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /* first read scheme and check that it is valid */ + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + p_HcFrame->extraReg = 0xFFFFF800; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* check that scheme is valid */ + if (!FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode)) + { + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is invalid")); + } + + /* Write scheme back, with modified counter */ + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); + p_HcFrame->extraReg = 0xFFFFF800; + /* write counter */ + p_HcFrame->hcSpecificData.schemeRegs.kgse_spc = value; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence); + + FmPcdKgReleaseSchemeLock(p_FmHc->h_FmPcd, relativeSchemeId); + XX_FreeSmart(p_HcFrame); + + return err; +} + +t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t i; + t_Error err = E_OK; + + ASSERT_COND(p_FmHc); + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + + for(i=p_Set->baseEntry;ibaseEntry+p_Set->numOfClsPlanEntries;i+=8) + { + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP)); + p_HcFrame->extraReg = 0xFFFFF800; + memcpy((void*)&p_HcFrame->hcSpecificData.clsPlanEntries, (void *)&p_Set->vectors[i-p_Set->baseEntry], CLS_PLAN_NUM_PER_GRP*sizeof(uint32_t)); + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + XX_FreeSmart(p_HcFrame); + + return err; +} + +t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t grpId) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; + + /* clear clsPlan entries in memory */ + p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); + if (!p_ClsPlanSet) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("memory allocation failed for p_ClsPlanSetd")); + memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); + + p_ClsPlanSet->baseEntry = FmPcdKgGetClsPlanGrpBase(p_FmHc->h_FmPcd, grpId); + p_ClsPlanSet->numOfClsPlanEntries = FmPcdKgGetClsPlanGrpSize(p_FmHc->h_FmPcd, grpId); + ASSERT_COND(p_ClsPlanSet->numOfClsPlanEntries <= FM_PCD_MAX_NUM_OF_CLS_PLANS); + + if (FmHcPcdKgSetClsPlan(p_FmHc, p_ClsPlanSet) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + XX_Free(p_ClsPlanSet); + + FmPcdKgDestroyClsPlanGrp(p_FmHc->h_FmPcd, grpId); + + return E_OK; +} + +t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams ) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + uint32_t intFlags; + t_DpaaFD fmFd; + t_Error err; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT); + memcpy(&p_HcFrame->hcSpecificData.ccCapwapReassmTimeout, p_CcCapwapReassmTimeoutParams, sizeof(t_FmPcdCcCapwapReassmTimeoutParams)); + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence); + + XX_FreeSmart(p_HcFrame); + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return err; +} + + +t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err; + uint32_t tmpReg32 = 0; + uint32_t requiredActionTmp, pointedOwnersTmp; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile out of range")); + + if (FmPcdPlcrProfileTryLock(p_FmHc->h_FmPcd, absoluteProfileId, FALSE)) + return ERROR_CODE(E_BUSY); + + + requiredActionTmp = FmPcdPlcrGetRequiredAction(p_FmHc->h_FmPcd, absoluteProfileId); + pointedOwnersTmp = FmPcdPlcrGetPointedOwners(p_FmHc->h_FmPcd, absoluteProfileId); + + if(!pointedOwnersTmp || !(requiredActionTmp & requiredAction)) + { + + if(requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + { + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + /* first read scheme and check that it is valid */ + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); + p_HcFrame->extraReg = 0x00008000; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* check that profile is valid */ + if (!FmPcdPlcrHwProfileIsValid(p_HcFrame->hcSpecificData.profileRegs.fmpl_pemode)) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer is already used")); + } + + tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegnia; + if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(TRUE, FALSE, FALSE); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_peynia; + if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, TRUE, FALSE); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pernia; + if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, FALSE, TRUE); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + XX_FreeSmart(p_HcFrame); + } + } + + FmPcdPlcrUpatePointedOwner(p_FmHc->h_FmPcd, absoluteProfileId, TRUE); + FmPcdPlcrUpdateRequiredAction(p_FmHc->h_FmPcd, absoluteProfileId, requiredAction); + + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + + return E_OK; +} + +t_Handle FmHcPcdPlcrSetProfile(t_Handle h_FmHc,t_FmPcdPlcrProfileParams *p_Profile) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_FmPcdPlcrInterModuleProfileRegs profileRegs; + t_Error err = E_OK; + uint32_t intFlags; + uint16_t profileIndx; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + + if (p_Profile->modify) + { + profileIndx = (uint16_t)(PTR_TO_UINT(p_Profile->id.h_Profile)-1); + if (FmPcdPlcrProfileTryLock(p_FmHc->h_FmPcd, profileIndx, FALSE)) + return NULL; + } + else + { + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + err = FmPcdPlcrGetAbsoluteProfileId(p_FmHc->h_FmPcd, + p_Profile->id.newParams.profileType, + p_Profile->id.newParams.h_FmPort, + p_Profile->id.newParams.relativeProfileId, + &profileIndx); + if (err) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + err = FmPcdPlcrProfileTryLock(p_FmHc->h_FmPcd, profileIndx, TRUE); + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + if (err) + return NULL; + } + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + return NULL; + } + + if(!p_Profile->modify) + { + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(profileIndx); + p_HcFrame->extraReg = 0x00008000; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, profileIndx); + REPORT_ERROR(MINOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return NULL; + } + + /* check if this scheme is already used */ + if (FmPcdPlcrHwProfileIsValid(p_HcFrame->hcSpecificData.profileRegs.fmpl_pemode)) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, profileIndx); + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer is already used")); + XX_FreeSmart(p_HcFrame); + return NULL; + } + } + + memset(&profileRegs, 0, sizeof(t_FmPcdPlcrInterModuleProfileRegs)); + err = FmPcdPlcrBuildProfile(p_FmHc->h_FmPcd, p_Profile, &profileRegs); + if(err) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, profileIndx); + REPORT_ERROR(MAJOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return NULL; + } + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx); + p_HcFrame->extraReg = 0x00008000; + memcpy(&p_HcFrame->hcSpecificData.profileRegs, &profileRegs, sizeof(t_FmPcdPlcrInterModuleProfileRegs)); + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, profileIndx); + REPORT_ERROR(MINOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return NULL; + } + + FmPcdPlcrValidateProfileSw(p_FmHc->h_FmPcd, profileIndx); + + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, profileIndx); + + XX_FreeSmart(p_HcFrame); + + return UINT_TO_PTR((uint64_t)profileIndx+1); +} + +t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + uint16_t absoluteProfileId = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + + if (FmPcdPlcrProfileTryLock(p_FmHc->h_FmPcd, absoluteProfileId, FALSE)) + return ERROR_CODE(E_BUSY); + + FmPcdPlcrInvalidateProfileSw(p_FmHc->h_FmPcd, absoluteProfileId); + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= 0x00008000; + p_HcFrame->extraReg = 0x00008000; + memset(&p_HcFrame->hcSpecificData.profileRegs, 0, sizeof(t_FmPcdPlcrInterModuleProfileRegs)); + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + + XX_FreeSmart(p_HcFrame); + + return E_OK; +} + +t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value) +{ + + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + uint16_t absoluteProfileId = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + + if (FmPcdPlcrProfileTryLock(p_FmHc->h_FmPcd, absoluteProfileId, FALSE)) + return ERROR_CODE(E_BUSY); + + /* first read scheme and check that it is valid */ + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); + p_HcFrame->extraReg = 0x00008000; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* check that profile is valid */ + if (!FmPcdPlcrHwProfileIsValid(p_HcFrame->hcSpecificData.profileRegs.fmpl_pemode)) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer is already used")); + } + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildCounterProfileReg(counter); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = value; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + + XX_FreeSmart(p_HcFrame); + + return E_OK; +} + +uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + uint16_t absoluteProfileId = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t retVal = 0; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + if (FmPcdPlcrProfileTryLock(p_FmHc->h_FmPcd, absoluteProfileId, FALSE)) + return 0; + + /* first read scheme and check that it is valid */ + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + return 0; + } + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); + p_HcFrame->extraReg = 0x00008000; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + REPORT_ERROR(MINOR, err, NO_MSG); + XX_FreeSmart(p_HcFrame); + return 0; + } + + /* check that profile is valid */ + if (!FmPcdPlcrHwProfileIsValid(p_HcFrame->hcSpecificData.profileRegs.fmpl_pemode)) + { + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + XX_FreeSmart(p_HcFrame); + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("invalid Policer profile")); + return 0; + } + + switch (counter) + { + case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegpc; + break; + case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_peypc; + break; + case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perpc; + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perypc; + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perrpc; + break; + default: + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + FmPcdPlcrReleaseProfileLock(p_FmHc->h_FmPcd, absoluteProfileId); + + XX_FreeSmart(p_HcFrame); + + return retVal; +} + +t_Error FmHcPcdCcModifyTreeNextEngine(t_Handle h_FmHc, t_Handle h_CcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + uint32_t intFlags; + t_List h_OldPointersLst, h_NewPointersLst; + t_Handle h_Params; + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + err = FmPcdCcTreeTryLock(h_CcTree); + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + if (err) + return err; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + err = FmPcdCcModifyNextEngineParamTree(p_FmHc->h_FmPcd, h_CcTree, grpId, index, p_FmPcdCcNextEngineParams, + &h_OldPointersLst, &h_NewPointersLst, &h_Params); + if(err) + { + FmPcdCcTreeReleaseLock(h_CcTree); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = HcDynamicChange(p_FmHc, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + + FmPcdCcTreeReleaseLock(h_CcTree); + + return err; +} + + +t_Error FmHcPcdCcModifyNodeMissNextEngine(t_Handle h_FmHc, t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Handle h_Params; + t_List h_OldPointersLst, h_NewPointersLst; + t_Error err = E_OK; + t_List h_List; + uint32_t intFlags; + + INIT_LIST(&h_List); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + + if ((err = FmPcdCcNodeTreeTryLock(p_FmHc->h_FmPcd, h_CcNode, &h_List)) != E_OK) + { + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return err; + } + + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + err = FmPcdCcModifyMissNextEngineParamNode(p_FmHc->h_FmPcd, h_CcNode, p_FmPcdCcNextEngineParams, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + if(err) + { + FmPcdCcNodeTreeReleaseLock(&h_List); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = HcDynamicChange(p_FmHc, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + + FmPcdCcNodeTreeReleaseLock(&h_List); + + + return E_OK; +} + +t_Error FmHcPcdCcRemoveKey(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Handle h_Params; + t_List h_OldPointersLst, h_NewPointersLst; + t_Error err = E_OK; + t_List h_List; + uint32_t intFlags; + + INIT_LIST(&h_List); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + + if ((err = FmPcdCcNodeTreeTryLock(p_FmHc->h_FmPcd, h_CcNode, &h_List)) != E_OK) + { + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return err; + } + + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + + err = FmPcdCcRemoveKey(p_FmHc->h_FmPcd,h_CcNode,keyIndex, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + if(err) + { + FmPcdCcNodeTreeReleaseLock(&h_List); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = HcDynamicChange(p_FmHc, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + + FmPcdCcNodeTreeReleaseLock(&h_List); + + return err; + +} + +t_Error FmHcPcdCcAddKey(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Handle h_Params; + t_List h_OldPointersLst, h_NewPointersLst; + t_Error err = E_OK; + t_List h_List; + uint32_t intFlags; + + INIT_LIST(&h_List); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + + if ((err = FmPcdCcNodeTreeTryLock(p_FmHc->h_FmPcd, h_CcNode, &h_List)) != E_OK) + { + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return err; + } + + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + + err = FmPcdCcAddKey(p_FmHc->h_FmPcd,h_CcNode,keyIndex,keySize, p_KeyParams, &h_OldPointersLst,&h_NewPointersLst, &h_Params); + if(err) + { + FmPcdCcNodeTreeReleaseLock(&h_List); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = HcDynamicChange(p_FmHc, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + + FmPcdCcNodeTreeReleaseLock(&h_List); + + return err; +} + + +t_Error FmHcPcdCcModifyKey(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_List h_OldPointersLst, h_NewPointersLst; + t_Error err = E_OK; + t_List h_List; + uint32_t intFlags; + t_Handle h_Params; + + UNUSED(keySize); + + INIT_LIST(&h_List); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + + if ((err = FmPcdCcNodeTreeTryLock(p_FmHc->h_FmPcd, h_CcNode, &h_List)) != E_OK) + { + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return err; + } + + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + err = FmPcdCcModifyKey(p_FmHc->h_FmPcd, h_CcNode, keyIndex, keySize, p_Key, p_Mask, &h_OldPointersLst,&h_NewPointersLst, &h_Params); + if(err) + { + FmPcdCcNodeTreeReleaseLock(&h_List); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = HcDynamicChange(p_FmHc, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + + FmPcdCcNodeTreeReleaseLock(&h_List); + + return err; +} + +t_Error FmHcPcdCcModifyNodeNextEngine(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_List h_OldPointersLst, h_NewPointersLst; + t_List h_List; + uint32_t intFlags; + t_Handle h_Params; + + INIT_LIST(&h_List); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + + if ((err = FmPcdCcNodeTreeTryLock(p_FmHc->h_FmPcd, h_CcNode, &h_List)) != E_OK) + { + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return err; + } + + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + err = FmPcdCcModiyNextEngineParamNode(p_FmHc->h_FmPcd, h_CcNode, keyIndex, p_FmPcdCcNextEngineParams, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + if(err) + { + FmPcdCcNodeTreeReleaseLock(&h_List); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = HcDynamicChange(p_FmHc, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + FmPcdCcNodeTreeReleaseLock(&h_List); + return err; +} + + +t_Error FmHcPcdCcModifyKeyAndNextEngine(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_List h_OldPointersLst, h_NewPointersLst; + t_Error err = E_OK; + t_List h_List; + uint32_t intFlags; + t_Handle h_Params; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + INIT_LIST(&h_List); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + + if ((err = FmPcdCcNodeTreeTryLock(p_FmHc->h_FmPcd, h_CcNode, &h_List)) != E_OK) + { + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return err; + } + + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + + + err = FmPcdCcModifyKeyAndNextEngine(p_FmHc->h_FmPcd,h_CcNode,keyIndex,keySize, p_KeyParams, &h_OldPointersLst,&h_NewPointersLst, &h_Params); + if(err) + { + FmPcdCcNodeTreeReleaseLock(&h_List); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = HcDynamicChange(p_FmHc, &h_OldPointersLst, &h_NewPointersLst, &h_Params); + + FmPcdCcNodeTreeReleaseLock(&h_List); + + + return err; +} + + +t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err = E_OK; + + ASSERT_COND(p_FmHc); + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + /* first read SP register */ + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId); + p_HcFrame->extraReg = 0xFFFFF800; + + BUILD_FD(SIZE_OF_HC_FRAME_PORT_REGS); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* spReg is the first reg, so we can use it both for read and for write */ + if(add) + p_HcFrame->hcSpecificData.portRegsForRead.spReg |= spReg; + else + p_HcFrame->hcSpecificData.portRegsForRead.spReg &= ~spReg; + + p_HcFrame->actionReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId); + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + XX_FreeSmart(p_HcFrame); + + return E_OK; +} + +t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err = E_OK; + + ASSERT_COND(p_FmHc); + + p_HcFrame = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + p_FmHc->padTill16), 0, 16); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame obj")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + /* first read SP register */ + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId); + p_HcFrame->extraReg = 0xFFFFF800; + p_HcFrame->hcSpecificData.singleRegForWrite = cppReg; + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, &p_HcFrame->commandSequence)) != E_OK) + { + XX_FreeSmart(p_HcFrame); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + XX_FreeSmart(p_HcFrame); + + return E_OK; +} + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/HC/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/HC/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/dpa/NetCommSw/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-Hc.o + +fsl-ncsw-Hc-objs := hc.o --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/fm_port_im.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/fm_port_im.c @@ -0,0 +1,789 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_port_im.c + + @Description FM Port Independent-Mode ... +*//***************************************************************************/ +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "fm_muram_ext.h" + +#include "fm_port.h" + + +#define TX_CONF_STATUS_UNSENT 0x1 + +#ifdef CORE_8BIT_ACCESS_ERRATA +#undef WRITE_UINT16 +#undef GET_UINT16 + +#define WRITE_UINT16(addr, val) \ + do{ \ + if((int)&(addr) % 4) \ + WRITE_UINT32(*(uint32_t*)(uint32_t)((uint32_t)&addr & ~0x3L), \ + ((GET_UINT32(*(uint32_t*)(uint32_t)((uint32_t)&addr & ~0x3L)) & 0xffff0000) | (uint32_t)val)); \ + else \ + WRITE_UINT32(*(uint32_t*)&addr, \ + ((GET_UINT32(*(uint32_t*)&addr) & 0x0000ffff) | (uint32_t)val<<16)); \ + }while(0); + +#define GET_UINT16(addr) (((uint32_t)&addr%4) ? \ + ((uint16_t)GET_UINT32(*(uint32_t*)(uint32_t)((uint32_t)&addr & ~0x3L))): \ + ((uint16_t)(GET_UINT32(*(uint32_t*)(uint32_t)&addr) >> 16))) +#endif /* CORE_8BIT_ACCESS_ERRATA */ + + +typedef enum e_TxConfType +{ + e_TX_CONF_TYPE_CHECK = 0 /**< check if all the buffers were touched by the muxator, no confirmation callback */ + ,e_TX_CONF_TYPE_CALLBACK = 1 /**< confirm to user all the available sent buffers */ + ,e_TX_CONF_TYPE_FLUSH = 3 /**< confirm all buffers plus the unsent one with an appropriate status */ +} e_TxConfType; + + +static void ImException(t_Handle h_FmPort, uint32_t event) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + ASSERT_COND(((event & IM_EV_RX) && FmIsMaster(p_FmPort->h_Fm)) || + !FmIsMaster(p_FmPort->h_Fm)); + + if (event & IM_EV_RX) + FmPortImRx(p_FmPort); + if ((event & IM_EV_BSY) && p_FmPort->f_Exception) + p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY); +} + + +static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType) +{ + t_Error retVal = E_BUSY; + uint32_t bdStatus; + uint16_t savedStartBdId, confBdId; + + ASSERT_COND(p_FmPort); + + /* + if (confType==e_TX_CONF_TYPE_CHECK) + return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY); + */ + + confBdId = savedStartBdId = p_FmPort->im.currBdId; + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); + + /* If R bit is set, we don't enter, or we break. + we run till we get to R, or complete the loop */ + while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK)) + { + if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */ + BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0); + + /* case 1: R bit is 0 and Length is set -> confirm! */ + if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK)) + { + if (p_FmPort->im.f_TxConf) + { + if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E)) + p_FmPort->im.f_TxConf(p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), + TX_CONF_STATUS_UNSENT, + p_FmPort->im.p_BdShadow[confBdId]); + else + p_FmPort->im.f_TxConf(p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), + 0, + p_FmPort->im.p_BdShadow[confBdId]); + } + } + /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */ + + confBdId = GetNextBdId(p_FmPort, confBdId); + if (confBdId == savedStartBdId) + retVal = E_OK; + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); + } + + return retVal; +} + +t_Error FmPortImEnable(t_FmPort *p_FmPort) +{ + uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP)); + return E_OK; +} + +t_Error FmPortImDisable(t_FmPort *p_FmPort) +{ + uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP)); + return E_OK; +} + +t_Error FmPortImRx(t_FmPort *p_FmPort) +{ + t_Handle h_CurrUserPriv, h_NewUserPriv; + uint32_t bdStatus; + volatile uint8_t buffPos; + uint16_t length; + uint16_t errors/*, reportErrors*/; + uint8_t *p_CurData, *p_Data; + uint32_t flags; + + ASSERT_COND(p_FmPort); + + flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock); + if (p_FmPort->lock) + { + XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); + return E_OK; + } + p_FmPort->lock = TRUE; + XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + + while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */ + { + if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL) + { + p_FmPort->lock = FALSE; + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); + } + + if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) + p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; + + errors = 0; + p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); + h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]; + length = (uint16_t)((bdStatus & BD_L) ? + ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength): + (bdStatus & BD_LENGTH_MASK)); + p_FmPort->im.rxFrameAccumLength += length; + + /* determine whether buffer is first, last, first and last (single */ + /* buffer frame) or middle (not first and not last) */ + buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ? + ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) : + ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF)); + + if (bdStatus & BD_L) + { + p_FmPort->im.rxFrameAccumLength = 0; + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); + + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E); + + errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16); + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv; + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4)); + /* Pass the buffer if one of the conditions is true: + - There are no errors + - This is a part of a larger frame ( the application has already received some buffers ) + - There is an error, but it was defined to be passed anyway. */ + if ((buffPos != SINGLE_BUF) || !errors || (errors & (uint16_t)(BD_ERROR_PASS_FRAME>>16))) + { + if (p_FmPort->im.f_RxStore(p_FmPort->h_App, + p_CurData, + length, + errors, + buffPos, + h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE) + break; + } + else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, + p_CurData, + h_CurrUserPriv)) + { + p_FmPort->lock = FALSE; + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer")); + } + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + } + p_FmPort->lock = FALSE; + return E_OK; +} + +void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams) +{ + ASSERT_COND(p_FmPort); + + SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.h_FmMuram = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram; + p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.imRxTxParams.liodnOffset; + p_FmPort->im.dataMemId = p_FmPortParams->specificParams.imRxTxParams.dataMemId; + p_FmPort->im.dataMemAttributes = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes; + + p_FmPort->im.fwExtStructsMemId = DEFAULT_PORT_ImfwExtStructsMemId; + p_FmPort->im.fwExtStructsMemAttr = DEFAULT_PORT_ImfwExtStructsMemAttr; + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + p_FmPort->im.rxPool.h_BufferPool = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool; + p_FmPort->im.rxPool.f_GetBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf; + p_FmPort->im.rxPool.f_PutBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf; + p_FmPort->im.rxPool.bufferSize = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize; + p_FmPort->im.rxPool.f_PhysToVirt = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt; + if (!p_FmPort->im.rxPool.f_PhysToVirt) + p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt; + p_FmPort->im.rxPool.f_VirtToPhys = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys; + if (!p_FmPort->im.rxPool.f_VirtToPhys) + p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys; + p_FmPort->im.f_RxStore = p_FmPortParams->specificParams.imRxTxParams.f_RxStore; + + p_FmPort->im.mrblr = 0x8000; + while (p_FmPort->im.mrblr) + { + if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr) + break; + p_FmPort->im.mrblr >>= 1; + } + if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize) + DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr)); + p_FmPort->im.bdRingSize = DEFAULT_PORT_rxBdRingLength; + p_FmPort->exceptions = DEFAULT_exception; + if (FmIsMaster(p_FmPort->h_Fm)) + p_FmPort->polling = FALSE; + else + p_FmPort->polling = TRUE; + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + p_FmPort->im.f_TxConf = p_FmPortParams->specificParams.imRxTxParams.f_TxConf; + + p_FmPort->im.bdRingSize = DEFAULT_PORT_txBdRingLength; + } +} + +t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort) +{ + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (!POWER_OF_2(p_FmPort->im.mrblr)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!")); + if (p_FmPort->im.mrblr < 256) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!")); + if(p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); +#ifdef FM_PARTITION_ARRAY + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + if(p_FmPort->p_FmPortDriverParam->liodnOffset >= MAX_LIODN_OFFSET) + { + p_FmPort->p_FmPortDriverParam->liodnOffset = + (uint16_t)(p_FmPort->p_FmPortDriverParam->liodnOffset & (MAX_LIODN_OFFSET-1)); + DBG(WARNING, ("liodnOffset number is out of rev1 range - MSB bits cleard.")); + } + } + } +#endif /* FM_PARTITION_ARRAY */ +/* TODO - add checks */ + } + else + { +/* TODO - add checks */ + } + + return E_OK; +} + +t_Error FmPortImInit(t_FmPort *p_FmPort) +{ + t_FmImBd *p_Bd=NULL; + t_Handle h_BufContext; + uint64_t tmpPhysBase; + uint16_t log2Num; + uint8_t *p_Data/*, *p_Tmp*/; + int i; + t_Error err; + uint16_t tmpReg16; + uint32_t tmpReg32; + + ASSERT_COND(p_FmPort); + + p_FmPort->im.p_FmPortImPram = + (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN); + if (!p_FmPort->im.p_FmPortImPram) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!")); + WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram)); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); + if (!p_FmPort->im.p_BdRing) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!")); + IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + if (!p_FmPort->im.p_BdShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); + memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + + /* Initialize the Rx-BD ring */ + for (i=0; iim.bdRingSize; i++) + { + p_Bd = BD_GET(i); + BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E); + + if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data); + p_FmPort->im.p_BdShadow[i] = h_BufContext; + } + + if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || + (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); + else + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); + + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->p_FmPortDriverParam->fmMuramPhysBaseAddr + 0x20)); + + LOG2((uint64_t)p_FmPort->im.mrblr, log2Num); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num); + + /* Initialize Rx QD */ + tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); + SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + /* Update the IM PRAM address in the BMI */ + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->p_FmPortDriverParam->fmMuramPhysBaseAddr)); + if (!p_FmPort->polling || p_FmPort->exceptions) + { + /* Allocate, configure and register interrupts */ + err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); + tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK); + tmpReg32 = 0; + + if(p_FmPort->exceptions & IM_EV_BSY) + { + tmpReg16 |= IM_RXQD_BSYINTM; + tmpReg32 |= IM_EV_BSY; + } + if(!p_FmPort->polling) + { + tmpReg16 |= IM_RXQD_RXFINTM; + tmpReg32 |= IM_EV_RX; + } + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + + FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort); + + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + else + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); + if (!p_FmPort->im.p_BdRing) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!")); + IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + if (!p_FmPort->im.p_BdShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); + memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + + if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || + (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); + else + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); + + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->p_FmPortDriverParam->fmMuramPhysBaseAddr + 0x40)); + + /* Initialize Tx QD */ + tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); + SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + /* Update the IM PRAM address in the BMI */ + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->p_FmPortDriverParam->fmMuramPhysBaseAddr)); + } + + + return E_OK; +} + +void FmPortImFree(t_FmPort *p_FmPort) +{ + uint32_t bdStatus; + uint8_t *p_CurData; + + ASSERT_COND(p_FmPort); + ASSERT_COND(p_FmPort->im.p_FmPortImPram); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (!p_FmPort->polling || p_FmPort->exceptions) + { + /* Deallocate and unregister interrupts */ + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); + + FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); + + FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + } + /* Try first clean what has received */ + FmPortImRx(p_FmPort); + + /* Now, get rid of the the empty buffer! */ + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + + while (bdStatus & BD_R_E) /* while there is data in the Rx BD */ + { + p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); + + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL); + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0); + + p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, + p_CurData, + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + } + } + else + TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH); + + FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram); + + if (p_FmPort->im.p_BdShadow) + XX_Free(p_FmPort->im.p_BdShadow); + + if (p_FmPort->im.p_BdRing) + XX_FreeSmart(p_FmPort->im.p_BdRing); +} + + +t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.mrblr = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.bdRingSize = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.bdRingSize = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, + uint8_t memId, + uint32_t memAttributes) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.fwExtStructsMemId = memId; + p_FmPort->im.fwExtStructsMemAttr = memAttributes; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only")); + + if (!FmIsMaster(p_FmPort->h_Fm)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;" + "in guest-partitions, IM is always in polling!")); + + p_FmPort->polling = TRUE; + + return E_OK; +} + +t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + uint16_t tmpReg16; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if(exception == e_FM_PORT_EXCEPTION_IM_BUSY) + { + if(enable) + { + p_FmPort->exceptions |= IM_EV_BSY; + if(p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ) + { + /* Allocate, configure and register interrupts */ + err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); + + FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort); + tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM); + tmpReg32 = IM_EV_BSY; + } + else + { + tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM); + tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY; + } + + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + else + { + p_FmPort->exceptions &= ~IM_EV_BSY; + if (!p_FmPort->exceptions && p_FmPort->polling) + { + FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY; + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + } + } + else + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception.")); + + return E_OK; +} + +t_Error FM_PORT_ImTx( t_Handle h_FmPort, + uint8_t *p_Data, + uint16_t length, + bool lastBuffer, + t_Handle h_BufContext) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint16_t nextBdId; + uint32_t bdStatus, nextBdStatus; + bool firstBuffer; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId)); + + if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E)) + { + /* Confirm the current BD - BD is available */ + if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf)) + p_FmPort->im.f_TxConf (p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)), + 0, + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); + + bdStatus = length; + + /* if this is the first BD of a frame */ + if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) + { + firstBuffer = TRUE; + p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E); + + if (!lastBuffer) + p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; + } + else + firstBuffer = FALSE; + + BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext; + + /* deal with last */ + if (lastBuffer) + { + /* if single buffer frame */ + if (firstBuffer) + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L); + else + { + /* Set the last BD of the frame */ + BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L)); + /* Set the first BD of the frame */ + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus); + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4)); + } + else if (!firstBuffer) /* mid frame buffer */ + BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E); + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + } + else + { + /* Discard current frame. Return error. */ + if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID) + { + /* Error: No free BD */ + /* Response: Discard current frame. Return error. */ + uint16_t cleanBdId = p_FmPort->im.firstBdOfFrameId; + + ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId); + + /* Since firstInFrame is not NULL, one buffer at least has already been + inserted into the BD ring. Using do-while covers the situation of a + frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented + prior to testing whether or not it's equal to TxBd). */ + do + { + BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0); + /* Advance BD pointer */ + cleanBdId = GetNextBdId(p_FmPort, cleanBdId); + } while (cleanBdId != p_FmPort->im.currBdId); + + p_FmPort->im.currBdId = cleanBdId; + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + + return ERROR_CODE(E_FULL); + } + + return E_OK; +} + +void FM_PORT_ImTxConf(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK); +} + +t_Error FM_PORT_ImRx(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + return FmPortImRx(p_FmPort); +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/fm_port.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/fm_port.h @@ -0,0 +1,894 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_port.h + + @Description FM Port internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_PORT_H +#define __FM_PORT_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_port_ext.h" + +#include "fm_common.h" + + +#define __ERR_MODULE__ MODULE_FM_PORT + + +#define MIN_EXT_BUF_SIZE 64 +#define DATA_ALIGNMENT 64 +#define MAX_LIODN_OFFSET 64 + +/**************************************************************************//** + @Description Memory Map defines +*//***************************************************************************/ +#define BMI_PORT_REGS_OFFSET 0 +#define QMI_PORT_REGS_OFFSET 0x400 +#define PRS_PORT_REGS_OFFSET 0x800 + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ +#define DEFAULT_PORT_deqHighPriority TRUE +#define DEFAULT_PORT_deqType e_FM_PORT_DEQ_TYPE1 +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT +#define DEFAULT_PORT_deqPrefetchOption e_FM_PORT_DEQ_FULL_PREFETCH +#define DEFAULT_PORT_deqPrefetchOption_HC e_FM_PORT_DEQ_NO_PREFETCH +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ +#define DEFAULT_PORT_deqByteCnt 2000 +#define DEFAULT_PORT_bufferPrefixContent_privDataSize 0 +#define DEFAULT_PORT_bufferPrefixContent_passPrsResult FALSE +#define DEFAULT_PORT_bufferPrefixContent_passTimeStamp FALSE +#define DEFAULT_PORT_bufferPrefixContent_allOtherPCDInfo FALSE +#ifdef DEBUG +#define DEFAULT_PORT_bufferPrefixContent_debugInfo FALSE +#endif /* DEBUG */ +#define DEFAULT_PORT_bufferPrefixContent_dataAlign DATA_ALIGNMENT +#define DEFAULT_PORT_cheksumLastBytesIgnore 0 +#define DEFAULT_PORT_cutBytesFromEnd 4 +#define DEFAULT_PORT_txFifoMinFillLevel 0 +#define DEFAULT_PORT_txFifoDeqPipelineDepth_IM 2 +#define DEFAULT_PORT_txFifoDeqPipelineDepth_1G 2 +#define DEFAULT_PORT_txFifoDeqPipelineDepth_10G 8 +#define DEFAULT_PORT_txFifoLowComfLevel (5*KILOBYTE) +#define DEFAULT_PORT_rxFifoPriElevationLevel BMI_MAX_FIFO_SIZE +#define DEFAULT_PORT_rxFifoThreshold (BMI_MAX_FIFO_SIZE*3/4) +#define DEFAULT_PORT_frmDiscardOverride FALSE +#define DEFAULT_PORT_dmaSwapData e_FM_PORT_DMA_NO_SWP +#define DEFAULT_PORT_dmaIntContextCacheAttr e_FM_PORT_DMA_NO_STASH +#define DEFAULT_PORT_dmaHeaderCacheAttr e_FM_PORT_DMA_NO_STASH +#define DEFAULT_PORT_dmaScatterGatherCacheAttr e_FM_PORT_DMA_NO_STASH +#define DEFAULT_PORT_dmaWriteOptimize TRUE +#define DEFAULT_PORT_forwardIntContextReuse FALSE +#define DEFAULT_PORT_BufMargins_startMargins 32 +#define DEFAULT_PORT_BufMargins_endMargins 0 +#define DEFAULT_PORT_syncReq TRUE +#define DEFAULT_PORT_syncReqForHc FALSE +#define DEFAULT_PORT_color e_FM_PORT_COLOR_GREEN +#define DEFAULT_PORT_errorsToDiscard FM_PORT_FRM_ERR_CLS_DISCARD +#define DEFAULT_dualRateLimitScaleDown e_FM_PORT_DUAL_RATE_LIMITER_NONE +#define DEFAULT_rateLimitBurstSizeHighGranularity FALSE +#define DEFAULT_exception IM_EV_BSY + +/* Host command port MUST NOT be changed to more than 1 !!! */ +#define DEFAULT_PORT_numOfTasks(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 16 : \ + ((((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX) || \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 3 : 1)) + +#define DEFAULT_PORT_extraNumOfTasks(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 8 : \ + ((((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX) || \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 2 : 0)) + +#define DEFAULT_PORT_numOfOpenDmas(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_TX_10G) ? 8 : \ + (((type) == e_FM_PORT_TYPE_RX_10G) ? 4 : 1)) + +#define DEFAULT_PORT_extraNumOfOpenDmas(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 8 : \ + ((((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX) || \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 1 : 0)) + +#if defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) +/* Let LLD to set minimum fifosize, otherwise fifosize settings will not work */ +#define DEFAULT_PORT_sizeOfFifo(type) \ + (uint32_t)(KILOBYTE) +#else +#define DEFAULT_PORT_sizeOfFifo(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? (16*KILOBYTE) : \ + ((((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX) || \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? (4*KILOBYTE) : (1536))) +#endif + +#define DEFAULT_PORT_extraSizeOfFifo(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? (8*KILOBYTE) : \ + (((type) == e_FM_PORT_TYPE_RX) ? (4*KILOBYTE) : (0))) + +#define DEFAULT_PORT_txBdRingLength 16 +#define DEFAULT_PORT_rxBdRingLength 128 +#define DEFAULT_PORT_ImfwExtStructsMemId 0 +#define DEFAULT_PORT_ImfwExtStructsMemAttr MEMORY_ATTR_CACHEABLE + +#define OH_PIPELINE_DEPTH 2 + +/**************************************************************************//** + @Description Memory Mapped Registers +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +#define FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS 8 +#define FM_PORT_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256 + +typedef _Packed struct +{ + volatile uint32_t fmbm_rcfg; /**< Rx Configuration */ + volatile uint32_t fmbm_rst; /**< Rx Status */ + volatile uint32_t fmbm_rda; /**< Rx DMA attributes*/ + volatile uint32_t fmbm_rfp; /**< Rx FIFO Parameters*/ + volatile uint32_t fmbm_rfed; /**< Rx Frame End Data*/ + volatile uint32_t fmbm_ricp; /**< Rx Internal Context Parameters*/ + volatile uint32_t fmbm_rim; /**< Rx Internal Buffer Margins*/ + volatile uint32_t fmbm_rebm; /**< Rx External Buffer Margins*/ + volatile uint32_t fmbm_rfne; /**< Rx Frame Next Engine*/ + volatile uint32_t fmbm_rfca; /**< Rx Frame Command Attributes.*/ + volatile uint32_t fmbm_rfpne; /**< Rx Frame Parser Next Engine*/ + volatile uint32_t fmbm_rpso; /**< Rx Parse Start Offset*/ + volatile uint32_t fmbm_rpp; /**< Rx Policer Profile */ + volatile uint32_t fmbm_rccb; /**< Rx Coarse Classification Base */ + volatile uint32_t fmbm_reth; /**< Rx Excessive Threshold */ + volatile uint32_t reserved1[1]; /**< (0x03C 0x03F) */ + volatile uint32_t fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /**< Rx Parse Results Array Initialization*/ + volatile uint32_t fmbm_rfqid; /**< Rx Frame Queue ID*/ + volatile uint32_t fmbm_refqid; /**< Rx Error Frame Queue ID*/ + volatile uint32_t fmbm_rfsdm; /**< Rx Frame Status Discard Mask*/ + volatile uint32_t fmbm_rfsem; /**< Rx Frame Status Error Mask*/ + volatile uint32_t fmbm_rfene; /**< Rx Frame Enqueue Next Engine */ + volatile uint32_t reserved2[0x23];/**< (0x074 0x0FF) */ + volatile uint32_t fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; + /**< Buffer Manager pool Information-*/ + volatile uint32_t fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; + /**< Allocate Counter-*/ + volatile uint32_t reserved3[8]; + /**< 0x130/0x140 - 0x15F reserved -*/ + volatile uint32_t fmbm_cgm[FM_PORT_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS/32]; + /**< Congestion Group Map*/ + volatile uint32_t fmbm_mpd; /**< BM Pool Depletion */ + volatile uint32_t reserved4[0x1F];/**< (0x184 0x1FF) */ + volatile uint32_t fmbm_rstc; /**< Rx Statistics Counters*/ + volatile uint32_t fmbm_rfrc; /**< Rx Frame Counter*/ + volatile uint32_t fmbm_rfbc; /**< Rx Bad Frames Counter*/ + volatile uint32_t fmbm_rlfc; /**< Rx Large Frames Counter*/ + volatile uint32_t fmbm_rffc; /**< Rx Filter Frames Counter*/ + volatile uint32_t fmbm_rfcd; /**< Rx Frame Discard Counter*/ + volatile uint32_t fmbm_rfldec; /**< Rx Frames List DMA Error Counter*/ + volatile uint32_t fmbm_rodc; /**< Rx Out of Buffers Discard Counter-*/ + volatile uint32_t fmbm_rbdc; /**< Rx Buffers Deallocate Counter-*/ + volatile uint32_t reserved5[0x17];/**< (0x224 0x27F) */ + volatile uint32_t fmbm_rpc; /**< Rx Performance Counters*/ + volatile uint32_t fmbm_rpcp; /**< Rx Performance Count Parameters*/ + volatile uint32_t fmbm_rccn; /**< Rx Cycle Counter*/ + volatile uint32_t fmbm_rtuc; /**< Rx Tasks Utilization Counter*/ + volatile uint32_t fmbm_rrquc; /**< Rx Receive Queue Utilization Counter*/ + volatile uint32_t fmbm_rduc; /**< Rx DMA Utilization Counter*/ + volatile uint32_t fmbm_rfuc; /**< Rx FIFO Utilization Counter*/ + volatile uint32_t fmbm_rpac; /**< Rx Pause Activation Counter*/ + volatile uint32_t reserved6[0x18];/**< (0x2A0 0x2FF) */ + volatile uint32_t fmbm_rdbg; /**< Rx Debug-*/ +} _PackedType t_FmPortRxBmiRegs; + +typedef _Packed struct +{ + volatile uint32_t fmbm_tcfg; /**< Tx Configuration */ + volatile uint32_t fmbm_tst; /**< Tx Status */ + volatile uint32_t fmbm_tda; /**< Tx DMA attributes */ + volatile uint32_t fmbm_tfp; /**< Tx FIFO Parameters */ + volatile uint32_t fmbm_tfed; /**< Tx Frame End Data */ + volatile uint32_t fmbm_ticp; /**< Tx Internal Context Parameters */ + volatile uint32_t fmbm_tfne; /**< Tx Frame Next Engine. */ + volatile uint32_t fmbm_tfca; /**< Tx Frame Command attribute. */ + volatile uint32_t fmbm_tcfqid; /**< Tx Confirmation Frame Queue ID. */ + volatile uint32_t fmbm_tfeqid; /**< Tx Frame Error Queue ID */ + volatile uint32_t fmbm_tfene; /**< Tx Frame Enqueue Next Engine */ + volatile uint32_t fmbm_trlmts; /**< Tx Rate Limiter Scale */ + volatile uint32_t fmbm_trlmt; /**< Tx Rate Limiter */ + volatile uint32_t reserved0[0x73];/**< (0x038-0x200) */ + volatile uint32_t fmbm_tstc; /**< Tx Statistics Counters */ + volatile uint32_t fmbm_tfrc; /**< Tx Frame Counter */ + volatile uint32_t fmbm_tfdc; /**< Tx Frames Discard Counter */ + volatile uint32_t fmbm_tfledc; /**< Tx Frame Length error discard counter */ + volatile uint32_t fmbm_tfufdc; /**< Tx Frame unsupported format discard Counter */ + volatile uint32_t fmbm_tbdc; /**< Tx Buffers Deallocate Counter */ + volatile uint32_t reserved1[0x1A];/**< (0x218-0x280) */ + volatile uint32_t fmbm_tpc; /**< Tx Performance Counters*/ + volatile uint32_t fmbm_tpcp; /**< Tx Performance Count Parameters*/ + volatile uint32_t fmbm_tccn; /**< Tx Cycle Counter*/ + volatile uint32_t fmbm_ttuc; /**< Tx Tasks Utilization Counter*/ + volatile uint32_t fmbm_ttcquc; /**< Tx Transmit Confirm Queue Utilization Counter*/ + volatile uint32_t fmbm_tduc; /**< Tx DMA Utilization Counter*/ + volatile uint32_t fmbm_tfuc; /**< Tx FIFO Utilization Counter*/ +} _PackedType t_FmPortTxBmiRegs; + +typedef _Packed struct +{ + volatile uint32_t fmbm_ocfg; /**< O/H Configuration */ + volatile uint32_t fmbm_ost; /**< O/H Status */ + volatile uint32_t fmbm_oda; /**< O/H DMA attributes */ + volatile uint32_t fmbm_oicp; /**< O/H Internal Context Parameters */ + volatile uint32_t fmbm_ofdne; /**< O/H Frame Dequeue Next Engine */ + volatile uint32_t fmbm_ofne; /**< O/H Frame Next Engine */ + volatile uint32_t fmbm_ofca; /**< O/H Frame Command Attributes. */ + volatile uint32_t fmbm_ofpne; /**< O/H Frame Parser Next Engine */ + volatile uint32_t fmbm_opso; /**< O/H Parse Start Offset */ + volatile uint32_t fmbm_opp; /**< O/H Policer Profile */ + volatile uint32_t fmbm_occb; /**< O/H Coarse Classification base */ + volatile uint32_t fmbm_oim; /**< O/H Internal margins*/ + volatile uint32_t reserved0[4]; /**< (0x030 - 0x03F) */ + volatile uint32_t fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /**< O/H Parse Results Array Initialization */ + volatile uint32_t fmbm_ofqid; /**< O/H Frame Queue ID */ + volatile uint32_t fmbm_oefqid; /**< O/H Error Frame Queue ID */ + volatile uint32_t fmbm_ofsdm; /**< O/H Frame Status Discard Mask */ + volatile uint32_t fmbm_ofsem; /**< O/H Frame Status Error Mask */ + volatile uint32_t fmbm_ofene; /**< O/H Frame Enqueue Next Engine */ + volatile uint32_t fmbm_orlmts; /**< O/H Rate Limiter Scale */ + volatile uint32_t fmbm_orlmt; /**< O/H Rate Limiter */ + volatile uint32_t reserved0a[0x21]; + /**< 0x07C - 0x0FF Reserved */ + union + { + volatile uint32_t fmbm_oebmpi[FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS]; + /**< Buffer Manager Observed Pool Information */ + volatile uint32_t reserved0b[0x18]; + }; /**< 0x100 - 0x15F Reserved */ + volatile uint32_t fmbm_ocgm; /**< Observed Congestion Group Map */ + volatile uint32_t reserved0c[0x7];/**< 0x164 - 0x17F Reserved */ + volatile uint32_t fmbm_ompd; /**< Observed BMan Pool Depletion */ + volatile uint32_t reserved0d[0x1F]; + /**< 0x184 - 0x1FF Reserved */ + volatile uint32_t fmbm_ostc; /**< O/H Statistics Counters */ + volatile uint32_t fmbm_ofrc; /**< O/H Frame Counter */ + volatile uint32_t fmbm_ofdc; /**< O/H Frames Discard Counter */ + volatile uint32_t fmbm_ofledc; /**< O/H Frames Length Error Discard Counter */ + volatile uint32_t fmbm_ofufdc; /**< O/H Frames Unsupported Format Discard Counter */ + volatile uint32_t fmbm_offc; /**< O/H Filter Frames Counter */ + volatile uint32_t fmbm_ofwdc; /**< - Rx Frames WRED Discard Counter */ + volatile uint32_t fmbm_ofldec; /**< O/H Frames List DMA Error Counter */ + volatile uint32_t fmbm_obdc; /**< O/H Buffers Deallocate Counter */ + volatile uint32_t reserved2[0x17];/**< (0x218 - 0x27F) */ + volatile uint32_t fmbm_opc; /**< O/H Performance Counters */ + volatile uint32_t fmbm_opcp; /**< O/H Performance Count Parameters */ + volatile uint32_t fmbm_occn; /**< O/H Cycle Counter */ + volatile uint32_t fmbm_otuc; /**< O/H Tasks Utilization Counter */ + volatile uint32_t fmbm_oduc; /**< O/H DMA Utilization Counter */ + volatile uint32_t fmbm_ofuc; /**< O/H FIFO Utilization Counter */ +} _PackedType t_FmPortOhBmiRegs; + +typedef _Packed union +{ + t_FmPortRxBmiRegs rxPortBmiRegs; + t_FmPortTxBmiRegs txPortBmiRegs; + t_FmPortOhBmiRegs ohPortBmiRegs; +} _PackedType u_FmPortBmiRegs; + +typedef _Packed struct +{ + volatile uint32_t reserved1[2]; /**< 0xn024 - 0x02B */ + volatile uint32_t fmqm_pndn; /**< PortID n Dequeue NIA Register */ + volatile uint32_t fmqm_pndc; /**< PortID n Dequeue Config Register */ + volatile uint32_t fmqm_pndtfc; /**< PortID n Dequeue Total Frame Counter */ + volatile uint32_t fmqm_pndfdc; /**< PortID n Dequeue FQID from Default Counter */ + volatile uint32_t fmqm_pndcc; /**< PortID n Dequeue Confirm Counter */ +} _PackedType t_FmPortNonRxQmiRegs; + +typedef _Packed struct +{ + volatile uint32_t fmqm_pnc; /**< PortID n Configuration Register */ + volatile uint32_t fmqm_pns; /**< PortID n Status Register */ + volatile uint32_t fmqm_pnts; /**< PortID n Task Status Register */ + volatile uint32_t reserved0[4]; /**< 0xn00C - 0xn01B */ + volatile uint32_t fmqm_pnen; /**< PortID n Enqueue NIA Register */ + volatile uint32_t fmqm_pnetfc; /**< PortID n Enqueue Total Frame Counter */ + t_FmPortNonRxQmiRegs nonRxQmiRegs; /**< Registers for Tx Hc & Op ports */ +} _PackedType t_FmPortQmiRegs; + +typedef _Packed struct +{ + _Packed struct + { + volatile uint32_t softSeqAttach; /**< Soft Sequence Attachment */ + volatile uint32_t lcv; /**< Line-up Enable Confirmation Mask */ + } _PackedType hdrs[FM_PCD_PRS_NUM_OF_HDRS]; + volatile uint8_t reserved0[0x378]; + volatile uint32_t pcac; /**< Parse Internal Memory Configuration Access Control Register */ + volatile uint32_t pctpid; /**< Parse Internal Memory Configured TPID Register */ +} _PackedType t_FmPortPrsRegs; + +/**************************************************************************//* + @Description Basic buffer descriptor (BD) structure +*//***************************************************************************/ +typedef _Packed struct +{ + volatile uint16_t status; + volatile uint16_t length; + volatile uint8_t reserved0[0x6]; + volatile uint8_t reserved1[0x1]; + volatile t_FmPhysAddr buff; +} _PackedType t_FmImBd; + +typedef _Packed struct +{ + volatile uint16_t gen; /**< tbd */ + volatile uint8_t reserved0[0x1]; + volatile t_FmPhysAddr bdRingBase; /**< tbd */ + volatile uint16_t bdRingSize; /**< tbd */ + volatile uint16_t offsetIn; /**< tbd */ + volatile uint16_t offsetOut; /**< tbd */ + volatile uint8_t reserved1[0x12]; /**< 0x0e - 0x1f */ +} _PackedType t_FmPortImQd; + +typedef _Packed struct +{ + volatile uint32_t mode; /**< Mode register */ + volatile uint32_t rxQdPtr; /**< tbd */ + volatile uint32_t txQdPtr; /**< tbd */ + volatile uint16_t mrblr; /**< tbd */ + volatile uint16_t rxQdBsyCnt; /**< tbd */ + volatile uint8_t reserved0[0x10]; /**< 0x10 - 0x1f */ + t_FmPortImQd rxQd; + t_FmPortImQd txQd; + volatile uint8_t reserved1[0xa0]; /**< 0x60 - 0xff */ +} _PackedType t_FmPortImPram; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/**************************************************************************//** + @Description Registers bit fields +*//***************************************************************************/ + +/**************************************************************************//** + @Description BMI defines +*//***************************************************************************/ +#define BMI_PORT_CFG_EN 0x80000000 +#define BMI_PORT_CFG_EN_MACSEC 0x00800000 +#define BMI_PORT_CFG_FDOVR 0x02000000 +#define BMI_PORT_CFG_IM 0x01000000 +#define BMI_PORT_STATUS_BSY 0x80000000 +#define BMI_COUNTERS_EN 0x80000000 +#define BMI_DMA_ATTR_WRITE_OPTIMIZE 0x00100000 +#define BMI_PORT_RFNE_FRWD_DCL4C 0x10000000 +#define BMI_PORT_RFNE_FRWD_RPD 0x40000000 +#define BMI_RFNE_FDCS_MASK 0xFF000000 + +#define BMI_CMD_MR_LEAC 0x00200000 +#define BMI_CMD_MR_SLEAC 0x00100000 +#define BMI_CMD_MR_MA 0x00080000 +#define BMI_CMD_MR_DEAS 0x00040000 +#define BMI_CMD_TX_MR_DEF (0) +#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \ + BMI_CMD_MR_SLEAC | \ + BMI_CMD_MR_MA | \ + BMI_CMD_MR_DEAS) +#define BMI_CMD_ATTR_ORDER 0x80000000 +#define BMI_CMD_ATTR_SYNC 0x02000000 +#define BMI_CMD_ATTR_MACCMD_MASK 0x0000ff00 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE 0x00008000 +#define BMI_CMD_ATTR_MACCMD_SECURED 0x00001000 +#define BMI_CMD_ATTR_MACCMD_SC_MASK 0x00000f00 + +#define BMI_EXT_BUF_POOL_VALID 0x80000000 +#define BMI_EXT_BUF_POOL_EN_COUNTER 0x40000000 +#define BMI_EXT_BUF_POOL_BACKUP 0x20000000 +#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000 +#define BMI_STATUS_RX_MASK_UNUSED (uint32_t)(~(FM_PORT_FRM_ERR_DMA | \ + FM_PORT_FRM_ERR_PHYSICAL | \ + FM_PORT_FRM_ERR_SIZE | \ + FM_PORT_FRM_ERR_CLS_DISCARD | \ + FM_PORT_FRM_ERR_EXTRACTION | \ + FM_PORT_FRM_ERR_NO_SCHEME | \ + FM_PORT_FRM_ERR_COLOR_RED | \ + FM_PORT_FRM_ERR_COLOR_YELLOW | \ + FM_PORT_FRM_ERR_ILL_PLCR | \ + FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ + FM_PORT_FRM_ERR_PRS_TIMEOUT | \ + FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ + FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ + FM_PORT_FRM_ERR_PRS_HDR_ERR | \ + FM_PORT_FRM_ERR_PROCESS_TIMEOUT | \ + FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW)) + +#define BMI_STATUS_OP_MASK_UNUSED (uint32_t)(BMI_STATUS_RX_MASK_UNUSED & \ + ~(FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)) + +#define BMI_RATE_LIMIT_EN 0x80000000 +#define BMI_RATE_LIMIT_BURST_SIZE_GRAN 0x80000000 +#define BMI_RATE_LIMIT_SCALE_BY_2 0x00000001 +#define BMI_RATE_LIMIT_SCALE_BY_4 0x00000002 +#define BMI_RATE_LIMIT_SCALE_BY_8 0x00000003 + +#define BMI_RX_FIFO_THRESHOLD_BC 0x80000000 + +#define BMI_PRS_RESULT_HIGH 0x00000000 +#define BMI_PRS_RESULT_LOW 0xFFFFFFFF + +#define RX_ERRS_TO_ENQ (FM_PORT_FRM_ERR_DMA | \ + FM_PORT_FRM_ERR_PHYSICAL | \ + FM_PORT_FRM_ERR_SIZE | \ + FM_PORT_FRM_ERR_EXTRACTION | \ + FM_PORT_FRM_ERR_NO_SCHEME | \ + FM_PORT_FRM_ERR_ILL_PLCR | \ + FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ + FM_PORT_FRM_ERR_PRS_TIMEOUT | \ + FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ + FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ + FM_PORT_FRM_ERR_PRS_HDR_ERR | \ + FM_PORT_FRM_ERR_PROCESS_TIMEOUT | \ + FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW) + +#ifdef FM_CAPWAP_SUPPORT +#define OP_ERRS_TO_ENQ (RX_ERRS_TO_ENQ | \ + FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_NON_FM | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT) + +#else +#define OP_ERRS_TO_ENQ (RX_ERRS_TO_ENQ | \ + FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT) +#endif /* FM_CAPWAP_SUPPORT */ + +/* shifts */ +#define BMI_PORT_CFG_MS_SEL_SHIFT 16 +#define BMI_DMA_ATTR_SWP_SHIFT 30 +#define BMI_DMA_ATTR_IC_CACHE_SHIFT 28 +#define BMI_DMA_ATTR_HDR_CACHE_SHIFT 26 +#define BMI_DMA_ATTR_SG_CACHE_SHIFT 24 + +#define BMI_IM_FOF_SHIFT 28 +#define BMI_PR_PORTID_SHIFT 24 + +#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16 +#define BMI_RX_FIFO_THRESHOLD_SHIFT 0 + +#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24 +#define BMI_RX_FRAME_END_CUT_SHIFT 16 + +#define BMI_IC_TO_EXT_SHIFT 16 +#define BMI_IC_FROM_INT_SHIFT 8 +#define BMI_IC_SIZE_SHIFT 0 + +#define BMI_INT_BUF_MARG_SHIFT 28 + +#define BMI_EXT_BUF_MARG_START_SHIFT 16 +#define BMI_EXT_BUF_MARG_END_SHIFT 0 + +#define BMI_CMD_ATTR_COLOR_SHIFT 26 +#define BMI_CMD_ATTR_COM_MODE_SHIFT 16 +#define BMI_CMD_ATTR_MACCMD_SHIFT 8 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE_SHIFT 15 +#define BMI_CMD_ATTR_MACCMD_SECURED_SHIFT 12 +#define BMI_CMD_ATTR_MACCMD_SC_SHIFT 8 + +#define BMI_POOL_DEP_NUM_OF_POOLS_SHIFT 16 +#define BMI_POOL_DEP_NUM_OF_POOLS_VECTOR_SHIFT 24 + +#define BMI_EXT_BUF_POOL_ID_SHIFT 16 + +#define BMI_TX_FIFO_MIN_FILL_SHIFT 16 +#define BMI_TX_FIFO_PIPELINE_DEPTH_SHIFT 12 +#define BMI_TX_LOW_COMF_SHIFT 0 + +#define BMI_TX_FRAME_END_CS_IGNORE_SHIFT 24 + +#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24 +#define BMI_PERFORMANCE_PORT_COMP_SHIFT 16 +#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12 +#define BMI_PERFORMANCE_FIFO_COMP_SHIFT 0 + +#define BMI_MAX_BURST_SHIFT 16 +#define BMI_COUNT_RATE_UNIT_SHIFT 16 + +/* sizes */ +#define FRAME_END_DATA_SIZE 16 +#define OFFSET_UNITS 16 +#define FRAME_OFFSET_UNITS 16 +#define MAX_EXT_OFFSET 496 +#define MAX_EXT_BUFFER_OFFSET 511 +#define MAX_INT_OFFSET 240 +#define MIN_TX_INT_OFFSET 16 +#define MAX_IC_SIZE 256 +#define MAX_FRAME_OFFSET 64 +#define MAX_FIFO_PIPELINE_DEPTH 8 +#define MAX_PERFORMANCE_TASK_COMP 64 +#define MAX_PERFORMANCE_TX_QUEUE_COMP 8 +#define MAX_PERFORMANCE_RX_QUEUE_COMP 64 +#define MAX_PERFORMANCE_DMA_COMP 16 +#define MAX_NUM_OF_TASKS 64 +#define MAX_NUM_OF_EXTRA_TASKS 8 +#define MAX_NUM_OF_DMAS 16 +#define MAX_NUM_OF_EXTRA_DMAS 8 +#define MAX_BURST_SIZE 1024 +#define FRAG_EXTRA_SPACE 32 + +/**************************************************************************//** + @Description QMI defines +*//***************************************************************************/ +/* masks */ +#define QMI_PORT_CFG_EN 0x80000000 +#define QMI_PORT_CFG_EN_COUNTERS 0x10000000 +#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000 +#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000 + +#define QMI_DEQ_CFG_PREFETCH_NO_TNUM 0x02000000 +#define QMI_DEQ_CFG_PREFETCH_WAITING_TNUM 0 +#define QMI_DEQ_CFG_PREFETCH_1_FRAME 0 +#define QMI_DEQ_CFG_PREFETCH_3_FRAMES 0x01000000 + +#define QMI_DEQ_CFG_PRI 0x80000000 +#define QMI_DEQ_CFG_TYPE1 0x10000000 +#define QMI_DEQ_CFG_TYPE2 0x20000000 +#define QMI_DEQ_CFG_TYPE3 0x30000000 + +#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f +#define QMI_DEQ_CFG_SUBPORTAL_SHIFT 20 + +/**************************************************************************//** + @Description PARSER defines +*//***************************************************************************/ +/* masks */ +#define PRS_HDR_ERROR_DIS 0x00000800 +#define PRS_HDR_SW_PRS_EN 0x00000400 +#define PRS_CP_OFFSET_MASK 0x0000000F +#define PRS_TPID1_MASK 0xFFFF0000 +#define PRS_TPID2_MASK 0x0000FFFF +#define PRS_TPID_DFLT 0x91009100 + +#define PRS_HDR_MPLS_LBL_INTER_EN 0x00200000 +#define PRS_HDR_IPV6_ROUTE_HDR_DIS 0x00008000 +#define PRS_HDR_PPPOE_MTU_CHECK_EN 0x80000000 +#define PRS_HDR_UDP_PAD_REMOVAL 0x80000000 +#define PRS_HDR_TCP_PAD_REMOVAL 0x80000000 +#define PRS_CAC_STOP 0x00000001 +#define PRS_CAC_ACTIVE 0x00000100 + +/* shifts */ +#define PRS_PCTPID_SHIFT 16 +#define PRS_HDR_MPLS_NEXT_HDR_SHIFT 22 +#define PRS_HDR_ETH_BC_SHIFT 28 +#define PRS_HDR_ETH_MC_SHIFT 24 +#define PRS_HDR_VLAN_STACKED_SHIFT 16 +#define PRS_HDR_MPLS_STACKED_SHIFT 16 +#define PRS_HDR_IPV4_1_BC_SHIFT 28 +#define PRS_HDR_IPV4_1_MC_SHIFT 24 +#define PRS_HDR_IPV4_2_UC_SHIFT 20 +#define PRS_HDR_IPV4_2_MC_BC_SHIFT 16 +#define PRS_HDR_IPV6_1_MC_SHIFT 24 +#define PRS_HDR_IPV6_2_UC_SHIFT 20 +#define PRS_HDR_IPV6_2_MC_SHIFT 16 + +#define PRS_HDR_ETH_BC_MASK 0x0fffffff +#define PRS_HDR_ETH_MC_MASK 0xf0ffffff +#define PRS_HDR_VLAN_STACKED_MASK 0xfff0ffff +#define PRS_HDR_MPLS_STACKED_MASK 0xfff0ffff +#define PRS_HDR_IPV4_1_BC_MASK 0x0fffffff +#define PRS_HDR_IPV4_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV4_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV4_2_MC_BC_MASK 0xfff0ffff +#define PRS_HDR_IPV6_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV6_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV6_2_MC_MASK 0xfff0ffff + +/* others */ +#define PRS_HDR_ENTRY_SIZE 8 +#define DEFAULT_CLS_PLAN_VECTOR 0xFFFFFFFF + +#define IPSEC_SW_PATCH_START 0x20 +#define SCTP_SW_PATCH_START 0x4D +#define DCCP_SW_PATCH_START 0x41 + +#define IP_FRAG_SW_PATCH_IPv4 0x300 +#define IP_FRAG_SW_PATCH_IPv6_0 0x320 +#define IP_FRAG_SW_PATCH_IPv6_1 0x372 + +/**************************************************************************//** + @Description IM defines +*//***************************************************************************/ +#define BD_R_E 0x80000000 +#define BD_L 0x08000000 + +#define BD_RX_CRE 0x00080000 +#define BD_RX_FTL 0x00040000 +#define BD_RX_FTS 0x00020000 +#define BD_RX_OV 0x00010000 + +#define BD_RX_ERRORS (BD_RX_CRE | BD_RX_FTL | BD_RX_FTS | BD_RX_OV) +#define BD_ERROR_PASS_FRAME BD_RX_ERRORS + +#define FM_IM_SIZEOF_BD sizeof(t_FmImBd) + +#define BD_STATUS_MASK 0xffff0000 +#define BD_LENGTH_MASK 0x0000ffff + +#define BD_STATUS_AND_LENGTH_SET(bd, val) WRITE_UINT32(*(volatile uint32_t*)(bd), (val)) + +#define BD_STATUS_AND_LENGTH(bd) GET_UINT32(*(volatile uint32_t*)(bd)) + +#define BD_GET(id) &p_FmPort->im.p_BdRing[id] + +#define IM_ILEGAL_BD_ID 0xffff + +/* others */ +#define IM_PRAM_ALIGN 0x100 + +/* masks */ +#define IM_MODE_GBL 0x20000000 +#define IM_MODE_BO_MASK 0x18000000 +#define IM_MODE_BO_SHIFT 3 +#define IM_MODE_GRC_STP 0x00800000 + +#define IM_MODE_SET_BO(val) (uint32_t)((val << (31-IM_MODE_BO_SHIFT)) & IM_MODE_BO_MASK) + +#define IM_RXQD_BSYINTM 0x0008 +#define IM_RXQD_RXFINTM 0x0010 +#define IM_RXQD_FPMEVT_SEL_MASK 0x0003 + +#define IM_EV_BSY 0x40000000 +#define IM_EV_RX 0x80000000 + +typedef struct { + t_Handle h_FmMuram; + t_FmPortImPram *p_FmPortImPram; + uint8_t fwExtStructsMemId; + uint32_t fwExtStructsMemAttr; + uint16_t bdRingSize; + t_FmImBd *p_BdRing; + t_Handle *p_BdShadow; + uint16_t currBdId; + uint16_t firstBdOfFrameId; + + /* Rx port parameters */ + uint8_t dataMemId; /**< Memory partition ID for data buffers */ + uint32_t dataMemAttributes; /**< Memory attributes for data buffers */ + t_BufferPoolInfo rxPool; + uint16_t mrblr; + uint16_t rxFrameAccumLength; + t_FmPortImRxStoreCallback *f_RxStore; + + /* Tx port parameters */ + uint32_t txFirstBdStatus; + t_FmPortImTxConfCallback *f_TxConf; +} t_FmMacIm; + +/**************************************************************************//** + @Description structure for defining internal context copying +*//***************************************************************************/ +typedef struct +{ + uint16_t extBufOffset; /**< Offset in External buffer to which internal + context is copied to (Rx) or taken from (Tx, Op). */ + uint8_t intContextOffset; /**< Offset within internal context to copy from + (Rx) or to copy to (Tx, Op). */ + uint16_t size; /**< Internal offset size to be copied */ +} t_FmPortIntContextDataCopy; + +/**************************************************************************//** + @Description struct for defining external buffer margins +*//***************************************************************************/ +typedef struct { + uint16_t startMargins; /**< Number of bytes to be left at the beginning + of the external buffer (must be divisible by 16) */ + uint16_t endMargins; /**< number of bytes to be left at the end + of the external buffer(must be divisible by 16) */ +} t_FmPortBufMargins; + +typedef struct { + uint32_t dataOffset; + uint32_t prsResultOffset; + uint32_t timeStampOffset; + uint32_t hashResultOffset; + uint32_t pcdInfoOffset; + uint32_t manipOffset; +#ifdef DEBUG + uint32_t debugOffset; +#endif /* DEBUG */ +} t_FmPortBufferOffsets; + +typedef struct { + uint32_t dfltFqid; + uint32_t confFqid; + uint32_t errFqid; + uintptr_t baseAddr; + uint8_t deqSubPortal; + bool deqHighPriority; + e_FmPortDeqType deqType; +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + e_FmPortDeqPrefetchOption deqPrefetchOption; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + uint16_t deqByteCnt; + uint8_t cheksumLastBytesIgnore; + uint8_t cutBytesFromEnd; + t_FmPortBufPoolDepletion bufPoolDepletion; + uint8_t pipelineDepth; + uint16_t fifoLowComfLevel; + bool frmDiscardOverride; + bool enRateLimit; + t_FmPortRateLimit rateLimit; + e_FmPortDualRateLimiterScaleDown rateLimitDivider; + bool enBufPoolDepletion; + uint16_t liodnOffset; + uint16_t liodnBase; + t_FmPortExtPools extBufPools; + e_FmPortDmaSwap dmaSwapData; + e_FmPortDmaCache dmaIntContextCacheAttr; + e_FmPortDmaCache dmaHeaderCacheAttr; + e_FmPortDmaCache dmaScatterGatherCacheAttr; + bool dmaReadOptimize; + bool dmaWriteOptimize; + uint32_t txFifoMinFillLevel; + uint32_t txFifoLowComfLevel; + uint32_t rxFifoPriElevationLevel; + uint32_t rxFifoThreshold; + t_FmPortBufMargins bufMargins; + t_FmPortIntContextDataCopy intContext; + bool syncReq; + e_FmPortColor color; + fmPortFrameErrSelect_t errorsToDiscard; + fmPortFrameErrSelect_t errorsToEnq; + uint64_t fmMuramPhysBaseAddr; + bool forwardReuseIntContext; + t_FmPortBufferPrefixContent bufferPrefixContent; + uint8_t internalBufferOffset; + t_FmPortBackupBmPools *p_BackupBmPools; + bool dontReleaseBuf; +} t_FmPortDriverParam; + +typedef struct { + t_Handle h_Fm; + t_Handle h_FmPcd; + uint8_t portId; + e_FmPortType portType; + int enabled; + char name[MODULE_NAME_SIZE]; + uint8_t hardwarePortId; + uint16_t fmClkFreq; + t_FmPortQmiRegs *p_FmPortQmiRegs; + u_FmPortBmiRegs *p_FmPortBmiRegs; + t_FmPortPrsRegs *p_FmPortPrsRegs; + fmPcdEngines_t pcdEngines; + uint32_t savedBmiNia; + uint8_t netEnvId; + uint32_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; + uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS]; + uint8_t privateInfo; + uint32_t schemesPerPortVector; + bool useClsPlan; + uint8_t clsPlanGrpId; + t_Handle ccTreeId; + t_Handle completeArg; + void (*f_Complete)(t_Handle arg); + t_FmPortBufferOffsets bufferOffsets; + /* Independent-Mode parameters support */ + bool imEn; + t_FmMacIm im; + uint8_t txFifoDeqPipelineDepth; + volatile bool lock; + t_Handle h_Spinlock; + t_FmPortExceptionCallback *f_Exception; + t_Handle h_App; + uint8_t internalBufferOffset; + uint8_t fmanCtrlEventId; + uint32_t exceptions; + bool polling; + uint8_t numOfTasks; + t_FmPortExtPools extBufPools; + uint32_t requiredAction; + uint32_t savedQmiPnen; + uint32_t savedNonRxQmiRegsPndn; + int savedPrsStartOffset; + t_FmPortRsrc openDmas; + t_FmPortRsrc tasks; + t_FmPortRsrc fifoBufs; + t_FmInterModulePortRxPoolsParams rxPoolsParams; + t_FmPortDriverParam *p_FmPortDriverParam; +} t_FmPort; + +#define CHECK_FM_CTL_AC_POST_FETCH_PCD(savedBmiNia) \ + ((((savedBmiNia) & NIA_ENG_MASK) == NIA_ENG_FM_CTL) && \ + ((((savedBmiNia) & NIA_FM_CTL_AC_MASK) == NIA_FM_CTL_AC_POST_FETCH_PCD) || \ + (((savedBmiNia) & NIA_FM_CTL_AC_MASK) == NIA_FM_CTL_AC_POST_FETCH_PCD_UDP_LEN))) + +void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams); +t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort); + +t_Error FmPortImInit(t_FmPort *p_FmPort); +void FmPortImFree(t_FmPort *p_FmPort); + +t_Error FmPortImEnable (t_FmPort *p_FmPort); +t_Error FmPortImDisable (t_FmPort *p_FmPort); +t_Error FmPortImRx (t_FmPort *p_FmPort); + +void FmPortSetMacsecLcv(t_Handle h_FmPort); +void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci); + + +static __inline__ uint8_t * BdBufferGet (t_PhysToVirt *f_PhysToVirt, t_FmImBd *p_Bd) +{ + uint64_t physAddr = (uint64_t)((uint64_t)GET_UINT8(p_Bd->buff.high) << 32); + physAddr |= GET_UINT32(p_Bd->buff.low); + + return (uint8_t *)f_PhysToVirt((physAddress_t)(physAddr)); +} + +static __inline__ void SET_ADDR(volatile t_FmPhysAddr *fmPhysAddr, uint64_t value) +{ + WRITE_UINT8(fmPhysAddr->high,(uint8_t)((value & 0x000000ff00000000LL) >> 32)); + WRITE_UINT32(fmPhysAddr->low,(uint32_t)value); +} + +static __inline__ void BdBufferSet(t_VirtToPhys *f_VirtToPhys, t_FmImBd *p_Bd, uint8_t *p_Buffer) +{ + uint64_t physAddr = (uint64_t)(f_VirtToPhys(p_Buffer)); + SET_ADDR(&p_Bd->buff, physAddr); +} + +static __inline__ uint16_t GetNextBdId(t_FmPort *p_FmPort, uint16_t id) +{ + if (id < p_FmPort->im.bdRingSize-1) + return (uint16_t)(id+1); + else + return 0; +} + + +#endif /* __FM_PORT_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/dpa/NetCommSw/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-Pcd.o + +fsl-ncsw-Pcd-objs := fm_port.o fm_port_im.o + + + + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/fm_port.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Port/fm_port.c @@ -0,0 +1,5060 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_port.c + + @Description FM driver routines implementation. +*//***************************************************************************/ +#include "error_ext.h" +#include "std_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "fm_pcd_ext.h" + +#include "fm_port.h" + + +/****************************************/ +/* static functions */ +/****************************************/ + +static t_Error CheckInitParameters(t_FmPort *p_FmPort) +{ + t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam; + t_Error ans = E_OK; + uint32_t unusedMask; + uint8_t i; + uint8_t j; + bool found; + + if (p_FmPort->imEn) + { + if ((ans = FmPortImCheckInitParameters(p_FmPort)) != E_OK) + return ERROR_CODE(ans); + } + else + { + /****************************************/ + /* Rx only */ + /****************************************/ + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* external buffer pools */ + if(!p_Params->extBufPools.numOfPoolsUsed) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.numOfPoolsUsed=0. At least one buffer pool must be defined")); + + if(p_Params->extBufPools.numOfPoolsUsed > FM_PORT_MAX_NUM_OF_EXT_POOLS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfPoolsUsed can't be larger than %d", FM_PORT_MAX_NUM_OF_EXT_POOLS)); + + for(i=0;iextBufPools.numOfPoolsUsed;i++) + { + if(p_Params->extBufPools.extBufPool[i].id >= BM_MAX_NUM_OF_POOLS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].id can't be larger than %d", i, BM_MAX_NUM_OF_POOLS)); + if(!p_Params->extBufPools.extBufPool[i].size) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].size is 0", i)); + } + + /* backup BM pools indication is valid only for some chip deriviatives + (limited by the config routine) */ + if(p_Params->p_BackupBmPools) + { + if(p_Params->p_BackupBmPools->numOfBackupPools >= p_Params->extBufPools.numOfPoolsUsed) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_BackupBmPools must be smaller than extBufPools.numOfPoolsUsed")); + found = FALSE; + for(i = 0;ip_BackupBmPools->numOfBackupPools;i++) + for(j=0;jextBufPools.numOfPoolsUsed;j++) + if(p_Params->p_BackupBmPools->poolIds[i] == p_Params->extBufPools.extBufPool[j].id) + found = TRUE; + if (!found) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("All p_BackupBmPools.poolIds must be included in extBufPools.extBufPool[n].id")); + } + + /* up to extBufPools.numOfPoolsUsed pools may be defined */ + if(p_Params->bufPoolDepletion.numberOfPoolsModeEnable) + { + if((p_Params->bufPoolDepletion.numOfPools > p_Params->extBufPools.numOfPoolsUsed)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools can't be larger than %d and can't be larger than numOfPoolsUsed", FM_PORT_MAX_NUM_OF_EXT_POOLS)); + + if(!p_Params->bufPoolDepletion.numOfPools) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPoolsToConsider can not be 0 when numberOfPoolsModeEnable=TRUE")); + } + /* Check that part of IC that needs copying is small enough to enter start margin */ + if(p_Params->intContext.size + p_Params->intContext.extBufOffset > p_Params->bufMargins.startMargins) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size is larger than start margins")); + + if(p_Params->liodnOffset & ~FM_LIODN_OFFSET_MASK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); +#ifdef FM_PARTITION_ARRAY + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + if(p_Params->liodnOffset >= MAX_LIODN_OFFSET) + { + p_Params->liodnOffset = (uint16_t)(p_Params->liodnOffset & (MAX_LIODN_OFFSET-1)); + DBG(WARNING, ("liodnOffset number is out of rev1 range - MSB bits cleard.")); + } + } + } +#endif /* FM_PARTITION_ARRAY */ + } + + /****************************************/ + /* Non Rx ports */ + /****************************************/ + else + { + if(p_Params->deqSubPortal >= MAX_QMI_DEQ_SUBPORTAL) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" deqSubPortal has to be in the range of 0 - %d", MAX_QMI_DEQ_SUBPORTAL)); + + /* to protect HW internal-context from overwrite */ + if((p_Params->intContext.size) && (p_Params->intContext.intContextOffset < MIN_TX_INT_OFFSET)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("non-Rx intContext.intContextOffset can't be smaller than %d", MIN_TX_INT_OFFSET)); + } + + /****************************************/ + /* Rx Or Offline Parsing */ + /****************************************/ + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + + if(!p_Params->dfltFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dfltFqid must be between 1 and 2^24-1")); +#if defined(FM_CAPWAP_SUPPORT) && defined(FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004) + if(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace % 16) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufferPrefixContent.manipExtraSpace has to be devidable by 16")); +#endif /* defined(FM_CAPWAP_SUPPORT) && ... */ + } + + /****************************************/ + /* All ports */ + /****************************************/ + /* common BMI registers values */ + /* Check that Queue Id is not larger than 2^24, and is not 0 */ + if((p_Params->errFqid & ~0x00FFFFFF) || !p_Params->errFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("errFqid must be between 1 and 2^24-1")); + if(p_Params->dfltFqid & ~0x00FFFFFF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dfltFqid must be between 1 and 2^24-1")); + } + + /****************************************/ + /* Rx only */ + /****************************************/ + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* Check that divisible by 256 and not larger than 256 */ + if(p_Params->rxFifoPriElevationLevel % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("rxFifoPriElevationLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if(!p_Params->rxFifoPriElevationLevel || (p_Params->rxFifoPriElevationLevel > BMI_MAX_FIFO_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("rxFifoPriElevationLevel has to be in the range of 256 - %d", BMI_MAX_FIFO_SIZE)); + if(p_Params->rxFifoThreshold % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("rxFifoThreshold has to be divisible by %d", BMI_FIFO_UNITS)); + if(!p_Params->rxFifoThreshold ||(p_Params->rxFifoThreshold > BMI_MAX_FIFO_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("rxFifoThreshold has to be in the range of 256 - %d", BMI_MAX_FIFO_SIZE)); + + /* Check that not larger than 16 */ + if(p_Params->cutBytesFromEnd > FRAME_END_DATA_SIZE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); + + /* Check the margin definition */ + if(p_Params->bufMargins.startMargins > MAX_EXT_BUFFER_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.startMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET)); + if(p_Params->bufMargins.endMargins > MAX_EXT_BUFFER_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.endMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET)); + + /* extra FIFO size (allowed only to Rx ports) */ + if(p_FmPort->fifoBufs.extra % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fifoBufs.extra has to be divisible by %d", BMI_FIFO_UNITS)); + + if(p_Params->bufPoolDepletion.numberOfPoolsModeEnable && + !p_Params->bufPoolDepletion.numOfPools) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPoolsToConsider can not be 0 when numberOfPoolsModeEnable=TRUE")); +#ifdef FM_CSI_CFED_LIMIT + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + + if (revInfo.majorRev == 4) + { + /* Check that not larger than 16 */ + if(p_Params->cutBytesFromEnd + p_Params->cheksumLastBytesIgnore > FRAME_END_DATA_SIZE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cheksumLastBytesIgnore + cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); + } + } +#endif /* FM_CSI_CFED_LIMIT */ + + } + + /****************************************/ + /* Non Rx ports */ + /****************************************/ + else + /* extra FIFO size (allowed only to Rx ports) */ + if(p_FmPort->fifoBufs.extra) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" No fifoBufs.extra for non Rx ports")); + + /****************************************/ + /* Rx & Tx */ + /****************************************/ + if((p_FmPort->portType == e_FM_PORT_TYPE_TX) || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* Check that not larger than 16 */ + if(p_Params->cheksumLastBytesIgnore > FRAME_END_DATA_SIZE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cheksumLastBytesIgnore can't be larger than %d", FRAME_END_DATA_SIZE)); + } + + /****************************************/ + /* Tx only */ + /****************************************/ + if((p_FmPort->portType == e_FM_PORT_TYPE_TX) || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + { + /* Check that divisible by 256 and not larger than 256 */ + if(p_Params->txFifoMinFillLevel % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("txFifoMinFillLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if(p_Params->txFifoMinFillLevel > (BMI_MAX_FIFO_SIZE - 256)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("txFifoMinFillLevel has to be in the range of 0 - %d", BMI_MAX_FIFO_SIZE)); + if(p_Params->txFifoLowComfLevel % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("txFifoLowComfLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if(!p_Params->txFifoLowComfLevel || (p_Params->txFifoLowComfLevel > BMI_MAX_FIFO_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("txFifoLowComfLevel has to be in the range of 256 - %d", BMI_MAX_FIFO_SIZE)); + + /* Check that not larger than 8 */ + if((!p_FmPort->txFifoDeqPipelineDepth) ||( p_FmPort->txFifoDeqPipelineDepth > MAX_FIFO_PIPELINE_DEPTH)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("txFifoDeqPipelineDepth can't be larger than %d", MAX_FIFO_PIPELINE_DEPTH)); + if(p_FmPort->portType == e_FM_PORT_TYPE_TX) + if(p_FmPort->txFifoDeqPipelineDepth > 2) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("txFifoDeqPipelineDepth for !G can't be larger than 2")); + } + else + /****************************************/ + /* Non Tx Ports */ + /****************************************/ + { + /* If discard override was selected , no frames may be discarded. */ + if(p_Params->frmDiscardOverride && p_Params->errorsToDiscard) + RETURN_ERROR(MAJOR, E_CONFLICT, ("errorsToDiscard is not empty, but frmDiscardOverride selected (all discarded frames to be enqueued to error queue).")); + } + + /****************************************/ + /* Rx and Offline parsing */ + /****************************************/ + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + if(p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + unusedMask = BMI_STATUS_OP_MASK_UNUSED; + else + unusedMask = BMI_STATUS_RX_MASK_UNUSED; + + /* Check that no common bits with BMI_STATUS_MASK_UNUSED */ + if(p_Params->errorsToDiscard & unusedMask) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("errorsToDiscard contains undefined bits")); + } + + /****************************************/ + /* All ports */ + /****************************************/ + + /* Check that divisible by 16 and not larger than 240 */ + if(p_Params->intContext.intContextOffset >MAX_INT_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset can't be larger than %d", MAX_INT_OFFSET)); + if(p_Params->intContext.intContextOffset % OFFSET_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset has to be divisible by %d", OFFSET_UNITS)); + + /* check that ic size+ic internal offset, does not exceed ic block size */ + if(p_Params->intContext.size + p_Params->intContext.intContextOffset > MAX_IC_SIZE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size + intContext.intContextOffset has to be smaller than %d", MAX_IC_SIZE)); + /* Check that divisible by 16 and not larger than 256 */ + if(p_Params->intContext.size % OFFSET_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size has to be divisible by %d", OFFSET_UNITS)); + + /* Check that divisible by 16 and not larger than 4K */ + if(p_Params->intContext.extBufOffset > MAX_EXT_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset can't be larger than %d", MAX_EXT_OFFSET)); + if(p_Params->intContext.extBufOffset % OFFSET_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset has to be divisible by %d", OFFSET_UNITS)); + + /* common BMI registers values */ + if((!p_FmPort->tasks.num) || (p_FmPort->tasks.num > MAX_NUM_OF_TASKS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("tasks.num can't be larger than %d", MAX_NUM_OF_TASKS)); + if(p_FmPort->tasks.extra > MAX_NUM_OF_EXTRA_TASKS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("tasks.extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); + if((!p_FmPort->openDmas.num) || (p_FmPort->openDmas.num > MAX_NUM_OF_DMAS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("openDmas.num can't be larger than %d", MAX_NUM_OF_DMAS)); + if(p_FmPort->openDmas.extra > MAX_NUM_OF_EXTRA_DMAS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("openDmas.extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); + if(!p_FmPort->fifoBufs.num || (p_FmPort->fifoBufs.num > BMI_MAX_FIFO_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fifoBufs.num has to be in the range of 256 - %d", BMI_MAX_FIFO_SIZE)); + if(p_FmPort->fifoBufs.num % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fifoBufs.num has to be divisible by %d", BMI_FIFO_UNITS)); + + return E_OK; +} + +static void FmPortDriverParamFree(t_FmPort *p_FmPort) +{ + if(p_FmPort->p_FmPortDriverParam) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + p_FmPort->p_FmPortDriverParam = NULL; + } +} + +static t_Error SetExtBufferPools(t_FmPort *p_FmPort) +{ + t_FmPortExtPools *p_ExtBufPools = &p_FmPort->p_FmPortDriverParam->extBufPools; + t_FmPortBufPoolDepletion *p_BufPoolDepletion = &p_FmPort->p_FmPortDriverParam->bufPoolDepletion; + volatile uint32_t *p_ExtBufRegs; + volatile uint32_t *p_BufPoolDepletionReg; + bool rxPort; + bool found; + uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + uint16_t sizesArray[BM_MAX_NUM_OF_POOLS]; + uint8_t count = 0; + uint8_t numOfPools; + uint16_t bufSize = 0, largestBufSize = 0; + int i=0, j=0, k=0; + uint32_t tmpReg, vector, minFifoSizeRequired=0; + + memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS); + memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS); + memcpy(&p_FmPort->extBufPools, p_ExtBufPools, sizeof(t_FmPortExtPools)); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_ExtBufRegs = p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_ebmpi; + p_BufPoolDepletionReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_mpd; + rxPort = TRUE; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_ExtBufRegs = p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_oebmpi; + p_BufPoolDepletionReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ompd; + rxPort = FALSE; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Not available for port type")); + } + + /* First we copy the external buffers pools information to an ordered local array */ + for(i=0;inumOfPoolsUsed;i++) + { + /* get pool size */ + bufSize = p_ExtBufPools->extBufPool[i].size; + + /* keep sizes in an array according to poolId for direct access */ + sizesArray[p_ExtBufPools->extBufPool[i].id] = bufSize; + + /* save poolId in an ordered array according to size */ + for (j=0;j<=i;j++) + { + /* this is the next free place in the array */ + if (j==i) + orderedArray[i] = p_ExtBufPools->extBufPool[i].id; + else + { + /* find the right place for this poolId */ + if(bufSize < sizesArray[orderedArray[j]]) + { + /* move the poolIds one place ahead to make room for this poolId */ + for(k=i;k>j;k--) + orderedArray[k] = orderedArray[k-1]; + + /* now k==j, this is the place for the new size */ + orderedArray[k] = p_ExtBufPools->extBufPool[i].id; + break; + } + } + } + } + + /* build the register value */ + + for(i=0;inumOfPoolsUsed;i++) + { + tmpReg = BMI_EXT_BUF_POOL_VALID | BMI_EXT_BUF_POOL_EN_COUNTER; + tmpReg |= ((uint32_t)orderedArray[i] << BMI_EXT_BUF_POOL_ID_SHIFT); + tmpReg |= sizesArray[orderedArray[i]]; + /* functionality available only for some deriviatives (limited by config) */ + if(p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + for(j=0;jp_FmPortDriverParam->p_BackupBmPools->numOfBackupPools;j++) + if(orderedArray[i] == p_FmPort->p_FmPortDriverParam->p_BackupBmPools->poolIds[j]) + { + tmpReg |= BMI_EXT_BUF_POOL_BACKUP; + break; + } + WRITE_UINT32(*(p_ExtBufRegs+i), tmpReg); + } + + if(p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + XX_Free(p_FmPort->p_FmPortDriverParam->p_BackupBmPools); + + numOfPools = (uint8_t)(rxPort ? FM_PORT_MAX_NUM_OF_EXT_POOLS:FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS); + + /* clear unused pools */ + for(i=p_ExtBufPools->numOfPoolsUsed;irxPoolsParams.largestBufSize = largestBufSize = sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed-1]]; + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { +#ifdef FM_FIFO_ALLOCATION_OLD_ALG + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + + if(revInfo.majorRev != 4) + { + minFifoSizeRequired = (uint32_t)(((largestBufSize % BMI_FIFO_UNITS) ? + ((largestBufSize/BMI_FIFO_UNITS + 1) * BMI_FIFO_UNITS) : + largestBufSize) + + (7*BMI_FIFO_UNITS)); + } + else +#endif /* FM_FIFO_ALLOCATION_OLD_ALG */ + { + p_FmPort->rxPoolsParams.numOfPools = p_ExtBufPools->numOfPoolsUsed; + if(p_ExtBufPools->numOfPoolsUsed == 1) + minFifoSizeRequired = 8*BMI_FIFO_UNITS; + else + { + uint16_t secondLargestBufSize = sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed-2]]; + p_FmPort->rxPoolsParams.secondLargestBufSize = secondLargestBufSize; + minFifoSizeRequired = (uint32_t)(((secondLargestBufSize % BMI_FIFO_UNITS) ? + ((secondLargestBufSize/BMI_FIFO_UNITS + 1) * BMI_FIFO_UNITS) : + secondLargestBufSize) + + (7*BMI_FIFO_UNITS)); + } + } + if(p_FmPort->fifoBufs.num < minFifoSizeRequired) + { + p_FmPort->fifoBufs.num = minFifoSizeRequired; + DBG(INFO, ("FIFO size for Rx port enlarged to %d",minFifoSizeRequired)); + } + } + + /* check if pool size is not too big */ + /* This is a definition problem in which if the fifo for the RX port + is lower than the largest pool size the hardware will allocate scatter gather + buffers even though the frame size can fit in a single buffer. */ + if (largestBufSize > p_FmPort->fifoBufs.num) + DBG(WARNING, ("Frame larger than port Fifo size (%u) will be split to more than a single buffer (S/G) even if shorter than largest buffer size (%u)", + p_FmPort->fifoBufs.num, largestBufSize)); + + /* pool depletion */ + tmpReg = 0; + if(p_BufPoolDepletion->numberOfPoolsModeEnable) + { + /* calculate vector for number of pools depletion */ + found = FALSE; + vector = 0; + count = 0; + for(i=0;ipoolsToConsider[i]) + { + for(j=0;jnumOfPoolsUsed;j++) + { + if (i == orderedArray[j]) + { + vector |= 0x80000000 >> j; + found = TRUE; + count++; + break; + } + } + if (!found) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used.")); + else + found = FALSE; + } + } + if (count < p_BufPoolDepletion->numOfPools) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools is larger than the number of pools defined.")); + + /* configure num of pools and vector for number of pools mode */ + tmpReg |= (((uint32_t)p_BufPoolDepletion->numOfPools - 1) << BMI_POOL_DEP_NUM_OF_POOLS_SHIFT); + tmpReg |= vector; + } + + if(p_BufPoolDepletion->singlePoolModeEnable) + { + /* calculate vector for number of pools depletion */ + found = FALSE; + vector = 0; + count = 0; + for(i=0;ipoolsToConsiderForSingleMode[i]) + { + for(j=0;jnumOfPoolsUsed;j++) + { + if (i == orderedArray[j]) + { + vector |= 0x00000080 >> j; + found = TRUE; + count++; + break; + } + } + if (!found) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used.")); + else + found = FALSE; + } + } + if (!count) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("No pools defined for single buffer mode pool depletion.")); + + /* configure num of pools and vector for number of pools mode */ + tmpReg |= vector; + } + + WRITE_UINT32(*p_BufPoolDepletionReg, tmpReg); + + return E_OK; +} + +static t_Error ClearPerfCnts(t_FmPort *p_FmPort) +{ + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL, 0); + return E_OK; +} + +static t_Error BmiRxPortInit(t_FmPort *p_FmPort) +{ + t_FmPortRxBmiRegs *p_Regs = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs; + uint32_t tmpReg; + t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam; + uint32_t errorsToEnq = 0; + t_FmPortPerformanceCnt performanceContersParams; + t_Error err; + + /* check that port is not busy */ + if (GET_UINT32(p_Regs->fmbm_rcfg) & BMI_PORT_CFG_EN) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Port(%d,%d) is already enabled",p_FmPort->portType, p_FmPort->portId)); + + /* Set Config register */ + tmpReg = 0; + if (p_FmPort->imEn) + tmpReg |= BMI_PORT_CFG_IM; + /* No discard - all error frames go to error queue */ + else if (p_Params->frmDiscardOverride) + tmpReg |= BMI_PORT_CFG_FDOVR; + + WRITE_UINT32(p_Regs->fmbm_rcfg, tmpReg); + + /* Configure dma attributes */ + tmpReg = 0; + tmpReg |= (uint32_t)p_Params->dmaSwapData << BMI_DMA_ATTR_SWP_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaIntContextCacheAttr << BMI_DMA_ATTR_IC_CACHE_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaHeaderCacheAttr << BMI_DMA_ATTR_HDR_CACHE_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaScatterGatherCacheAttr << BMI_DMA_ATTR_SG_CACHE_SHIFT; + if(p_Params->dmaWriteOptimize) + tmpReg |= BMI_DMA_ATTR_WRITE_OPTIMIZE; + + WRITE_UINT32(p_Regs->fmbm_rda, tmpReg); + + /* Configure Rx Fifo params */ + tmpReg = 0; + tmpReg |= ((p_Params->rxFifoPriElevationLevel/BMI_FIFO_UNITS - 1) << BMI_RX_FIFO_PRI_ELEVATION_SHIFT); + tmpReg |= ((p_Params->rxFifoThreshold/BMI_FIFO_UNITS - 1) << BMI_RX_FIFO_THRESHOLD_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_rfp, tmpReg); + + { +#ifdef FM_NO_THRESHOLD_REG + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev > 1) +#endif /* FM_NO_THRESHOLD_REG */ + /* always allow access to the extra resources */ + WRITE_UINT32(p_Regs->fmbm_reth, BMI_RX_FIFO_THRESHOLD_BC); + } + + /* frame end parameters */ + tmpReg = 0; + tmpReg |= ((uint32_t)p_Params->cheksumLastBytesIgnore << BMI_RX_FRAME_END_CS_IGNORE_SHIFT); + tmpReg |= ((uint32_t)p_Params->cutBytesFromEnd<< BMI_RX_FRAME_END_CUT_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_rfed, tmpReg); + + /* IC parameters */ + tmpReg = 0; + tmpReg |= (((uint32_t)p_Params->intContext.extBufOffset/OFFSET_UNITS) << BMI_IC_TO_EXT_SHIFT); + tmpReg |= (((uint32_t)p_Params->intContext.intContextOffset/OFFSET_UNITS) << BMI_IC_FROM_INT_SHIFT); + tmpReg |= (((uint32_t)p_Params->intContext.size/OFFSET_UNITS) << BMI_IC_SIZE_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_ricp, tmpReg); + + if (!p_FmPort->imEn) + { + /* check if the largest external buffer pool is large enough */ + if(p_Params->bufMargins.startMargins + MIN_EXT_BUF_SIZE + p_Params->bufMargins.endMargins > p_FmPort->rxPoolsParams.largestBufSize) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.startMargins (%d) + minimum buf size (64) + bufMargins.endMargins (%d) is larger than maximum external buffer size (%d)", + p_Params->bufMargins.startMargins, p_Params->bufMargins.endMargins, p_FmPort->rxPoolsParams.largestBufSize)); + + /* buffer margins */ + tmpReg = 0; + tmpReg |= (((uint32_t)p_Params->bufMargins.startMargins) << BMI_EXT_BUF_MARG_START_SHIFT); + tmpReg |= (((uint32_t)p_Params->bufMargins.endMargins) << BMI_EXT_BUF_MARG_END_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_rebm, tmpReg); + } + + + if(p_FmPort->internalBufferOffset) + { + tmpReg = (uint32_t)((p_FmPort->internalBufferOffset % OFFSET_UNITS) ? + (p_FmPort->internalBufferOffset/OFFSET_UNITS + 1): + (p_FmPort->internalBufferOffset/OFFSET_UNITS)); + p_FmPort->internalBufferOffset = (uint8_t)(tmpReg * OFFSET_UNITS); + WRITE_UINT32(p_Regs->fmbm_rim, tmpReg << BMI_IM_FOF_SHIFT); + } + + /* NIA */ + if (p_FmPort->imEn) + WRITE_UINT32(p_Regs->fmbm_rfne, NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_RX); + else + { + tmpReg = 0; + if (p_Params->forwardReuseIntContext) + tmpReg |= BMI_PORT_RFNE_FRWD_RPD; + /* L3/L4 checksum verify is enabled by default. */ + /*tmpReg |= BMI_PORT_RFNE_FRWD_DCL4C;*/ + WRITE_UINT32(p_Regs->fmbm_rfne, tmpReg | NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); + } + WRITE_UINT32(p_Regs->fmbm_rfene, NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + + /* command attribute */ + tmpReg = BMI_CMD_RX_MR_DEF; + if (!p_FmPort->imEn) + { + tmpReg |= BMI_CMD_ATTR_ORDER; + if(p_Params->syncReq) + tmpReg |= BMI_CMD_ATTR_SYNC; + tmpReg |= ((uint32_t)p_Params->color << BMI_CMD_ATTR_COLOR_SHIFT); + } + + WRITE_UINT32(p_Regs->fmbm_rfca, tmpReg); + + /* default queues */ + if (!p_FmPort->imEn) + { + WRITE_UINT32(p_Regs->fmbm_rfqid, p_Params->dfltFqid); + WRITE_UINT32(p_Regs->fmbm_refqid, p_Params->errFqid); + } + + /* set counters */ + WRITE_UINT32(p_Regs->fmbm_rstc, BMI_COUNTERS_EN); + + performanceContersParams.taskCompVal = (uint8_t)p_FmPort->tasks.num; + performanceContersParams.queueCompVal = 1; + performanceContersParams.dmaCompVal =(uint8_t) p_FmPort->openDmas.num; + performanceContersParams.fifoCompVal = p_FmPort->fifoBufs.num; + if((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &performanceContersParams)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + WRITE_UINT32(p_Regs->fmbm_rpc, BMI_COUNTERS_EN); + + /* error/status mask - check that if discard OV is set, no + discard is required for specific errors.*/ + WRITE_UINT32(p_Regs->fmbm_rfsdm, p_Params->errorsToDiscard); + + errorsToEnq = (RX_ERRS_TO_ENQ & ~p_Params->errorsToDiscard); + WRITE_UINT32(p_Regs->fmbm_rfsem, errorsToEnq); + +#ifdef FM_BMI_TO_RISC_ENQ_ERRATA_FMANc + if((GET_UINT32(p_Regs->fmbm_rfene) && NIA_ENG_MASK)== NIA_ENG_FM_CTL) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("NIA not supported at this stage")); +#endif /* FM_BMI_TO_RISC_ENQ_ERRATA_FMANc */ + + return E_OK; +} + +static t_Error BmiTxPortInit(t_FmPort *p_FmPort) +{ + t_FmPortTxBmiRegs *p_Regs = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs; + uint32_t tmpReg; + t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam; + /*uint32_t rateCountUnit;*/ + t_FmPortPerformanceCnt performanceContersParams; + + /* check that port is not busy */ + if (GET_UINT32(p_Regs->fmbm_tcfg) & BMI_PORT_CFG_EN) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port is already enabled")); + + tmpReg = 0; + if (p_FmPort->imEn) + tmpReg |= BMI_PORT_CFG_IM; + + WRITE_UINT32(p_Regs->fmbm_tcfg, tmpReg); + + /* Configure dma attributes */ + tmpReg = 0; + tmpReg |= (uint32_t)p_Params->dmaSwapData << BMI_DMA_ATTR_SWP_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaIntContextCacheAttr << BMI_DMA_ATTR_IC_CACHE_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaHeaderCacheAttr << BMI_DMA_ATTR_HDR_CACHE_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaScatterGatherCacheAttr << BMI_DMA_ATTR_SG_CACHE_SHIFT; + + WRITE_UINT32(p_Regs->fmbm_tda, tmpReg); + + /* Configure Tx Fifo params */ + tmpReg = 0; + tmpReg |= ((p_Params->txFifoMinFillLevel/BMI_FIFO_UNITS) << BMI_TX_FIFO_MIN_FILL_SHIFT); + tmpReg |= (((uint32_t)p_FmPort->txFifoDeqPipelineDepth - 1) << BMI_TX_FIFO_PIPELINE_DEPTH_SHIFT); + tmpReg |= ((p_Params->txFifoLowComfLevel/BMI_FIFO_UNITS - 1) << BMI_TX_LOW_COMF_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_tfp, tmpReg); + + /* frame end parameters */ + tmpReg = 0; + tmpReg |= ((uint32_t)p_Params->cheksumLastBytesIgnore << BMI_TX_FRAME_END_CS_IGNORE_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_tfed, tmpReg); + + if (!p_FmPort->imEn) + { + /* IC parameters */ + tmpReg = 0; + tmpReg |= (((uint32_t)p_Params->intContext.extBufOffset/OFFSET_UNITS) << BMI_IC_TO_EXT_SHIFT); + tmpReg |= (((uint32_t)p_Params->intContext.intContextOffset/OFFSET_UNITS) << BMI_IC_FROM_INT_SHIFT); + tmpReg |= (((uint32_t)p_Params->intContext.size/OFFSET_UNITS) << BMI_IC_SIZE_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_ticp, tmpReg); + } + + /* NIA */ + if (p_FmPort->imEn) + { + WRITE_UINT32(p_Regs->fmbm_tfne, NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX); + WRITE_UINT32(p_Regs->fmbm_tfene, NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX); + } + else + { + WRITE_UINT32(p_Regs->fmbm_tfne, NIA_ENG_QMI_DEQ); + WRITE_UINT32(p_Regs->fmbm_tfene, NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + /* The line bellow is a trick so the FM will not release the buffer + to BM nor will try to enq the frame to QM */ + if(!p_Params->dfltFqid && p_Params->dontReleaseBuf) + { + /* override fmbm_tcfqid 0 with a false non-0 value. This will force FM to + * act acording to tfene. Otherwise, if fmbm_tcfqid is 0 the FM will release + * buffers to BM regardless of fmbm_tfene + */ + WRITE_UINT32(p_Regs->fmbm_tcfqid, 0xFFFFFF); + WRITE_UINT32(p_Regs->fmbm_tfene, NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); + } + } + + /* command attribute */ + tmpReg = BMI_CMD_TX_MR_DEF; + if (p_FmPort->imEn) + tmpReg |= BMI_CMD_MR_DEAS; + else + { + tmpReg |= BMI_CMD_ATTR_ORDER; + /* if we set syncReq, we may get stuck when HC command is running */ + /*if(p_Params->syncReq) + tmpReg |= BMI_CMD_ATTR_SYNC;*/ + tmpReg |= ((uint32_t)p_Params->color << BMI_CMD_ATTR_COLOR_SHIFT); + } + + WRITE_UINT32(p_Regs->fmbm_tfca, tmpReg); + + /* default queues */ + if (!p_FmPort->imEn) + { + if(p_Params->dfltFqid || !p_Params->dontReleaseBuf) + WRITE_UINT32(p_Regs->fmbm_tcfqid, p_Params->dfltFqid); + WRITE_UINT32(p_Regs->fmbm_tfeqid, p_Params->errFqid); + } + + /* statistics & performance counters */ + WRITE_UINT32(p_Regs->fmbm_tstc, BMI_COUNTERS_EN); + + performanceContersParams.taskCompVal = (uint8_t)p_FmPort->tasks.num; + performanceContersParams.queueCompVal = 1; + performanceContersParams.dmaCompVal = (uint8_t)p_FmPort->openDmas.num; + performanceContersParams.fifoCompVal = p_FmPort->fifoBufs.num; + FM_PORT_SetPerformanceCountersParams(p_FmPort, &performanceContersParams); + + WRITE_UINT32(p_Regs->fmbm_tpc, BMI_COUNTERS_EN); + + return E_OK; +} + +static t_Error BmiOhPortInit(t_FmPort *p_FmPort) +{ + t_FmPortOhBmiRegs *p_Regs = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs; + uint32_t tmpReg, errorsToEnq = 0; + t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam; + t_FmPortPerformanceCnt performanceContersParams; + t_Error err; + + /* check that port is not busy */ + if (GET_UINT32(p_Regs->fmbm_ocfg) & BMI_PORT_CFG_EN) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port is already enabled")); + + /* Configure dma attributes */ + tmpReg = 0; + tmpReg |= (uint32_t)p_Params->dmaSwapData << BMI_DMA_ATTR_SWP_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaIntContextCacheAttr << BMI_DMA_ATTR_IC_CACHE_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaHeaderCacheAttr << BMI_DMA_ATTR_HDR_CACHE_SHIFT; + tmpReg |= (uint32_t)p_Params->dmaScatterGatherCacheAttr << BMI_DMA_ATTR_SG_CACHE_SHIFT; + if(p_Params->dmaWriteOptimize) + tmpReg |= BMI_DMA_ATTR_WRITE_OPTIMIZE; + + WRITE_UINT32(p_Regs->fmbm_oda, tmpReg); + + /* IC parameters */ + tmpReg = 0; + tmpReg |= (((uint32_t)p_Params->intContext.extBufOffset/OFFSET_UNITS) << BMI_IC_TO_EXT_SHIFT); + tmpReg |= (((uint32_t)p_Params->intContext.intContextOffset/OFFSET_UNITS) << BMI_IC_FROM_INT_SHIFT); + tmpReg |= (((uint32_t)p_Params->intContext.size/OFFSET_UNITS) << BMI_IC_SIZE_SHIFT); + + WRITE_UINT32(p_Regs->fmbm_oicp, tmpReg); + + /* NIA */ + WRITE_UINT32(p_Regs->fmbm_ofdne, NIA_ENG_QMI_DEQ); + + if (p_FmPort->portType==e_FM_PORT_TYPE_OH_HOST_COMMAND) + WRITE_UINT32(p_Regs->fmbm_ofene, NIA_ENG_QMI_ENQ); + else + WRITE_UINT32(p_Regs->fmbm_ofene, NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + + /* command attribute */ + if (p_FmPort->portType==e_FM_PORT_TYPE_OH_HOST_COMMAND) + tmpReg = BMI_CMD_MR_DEAS | BMI_CMD_MR_MA; + else + tmpReg = BMI_CMD_ATTR_ORDER | BMI_CMD_MR_DEAS | BMI_CMD_MR_MA; + + if(p_Params->syncReq) + tmpReg |= BMI_CMD_ATTR_SYNC; + tmpReg |= ((uint32_t)p_Params->color << BMI_CMD_ATTR_COLOR_SHIFT); + WRITE_UINT32(p_Regs->fmbm_ofca, tmpReg); + + /* No discard - all error frames go to error queue */ + if (p_Params->frmDiscardOverride) + tmpReg = BMI_PORT_CFG_FDOVR; + else + tmpReg = 0; + WRITE_UINT32(p_Regs->fmbm_ocfg, tmpReg); + + if(p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { + WRITE_UINT32(p_Regs->fmbm_ofsdm, p_Params->errorsToDiscard); + + errorsToEnq = (OP_ERRS_TO_ENQ & ~p_Params->errorsToDiscard); + WRITE_UINT32(p_Regs->fmbm_ofsem, errorsToEnq); + + /* NIA */ + WRITE_UINT32(p_Regs->fmbm_ofne, NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); + { +#ifdef FM_NO_OP_OBSERVED_POOLS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 4) && (p_Params->enBufPoolDepletion)) +#endif /* FM_NO_OP_OBSERVED_POOLS */ + { + /* define external buffer pools */ + err = SetExtBufferPools(p_FmPort); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + } + else + /* NIA */ + WRITE_UINT32(p_Regs->fmbm_ofne, NIA_ENG_FM_CTL | NIA_FM_CTL_AC_HC); + + /* default queues */ + WRITE_UINT32(p_Regs->fmbm_ofqid, p_Params->dfltFqid); + WRITE_UINT32(p_Regs->fmbm_oefqid, p_Params->errFqid); + + if(p_FmPort->internalBufferOffset) + { + tmpReg = (uint32_t)((p_FmPort->internalBufferOffset % OFFSET_UNITS) ? + (p_FmPort->internalBufferOffset/OFFSET_UNITS + 1): + (p_FmPort->internalBufferOffset/OFFSET_UNITS)); + p_FmPort->internalBufferOffset = (uint8_t)(tmpReg * OFFSET_UNITS); + WRITE_UINT32(p_Regs->fmbm_oim, tmpReg << BMI_IM_FOF_SHIFT); + } + /* statistics & performance counters */ + WRITE_UINT32(p_Regs->fmbm_ostc, BMI_COUNTERS_EN); + + performanceContersParams.taskCompVal = (uint8_t)p_FmPort->tasks.num; + performanceContersParams.queueCompVal = 0; + performanceContersParams.dmaCompVal = (uint8_t)p_FmPort->openDmas.num; + performanceContersParams.fifoCompVal = p_FmPort->fifoBufs.num; + FM_PORT_SetPerformanceCountersParams(p_FmPort, &performanceContersParams); + + WRITE_UINT32(p_Regs->fmbm_opc, BMI_COUNTERS_EN); + + return E_OK; +} + +static t_Error QmiInit(t_FmPort *p_FmPort) +{ + t_FmPortDriverParam *p_Params = NULL; + uint32_t tmpReg; + + p_Params = p_FmPort->p_FmPortDriverParam; + + /* check that port is not busy */ + if(((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) && + (GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc) & QMI_PORT_CFG_EN)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port is already enabled")); + + /* enable & clear counters */ + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc, QMI_PORT_CFG_EN_COUNTERS); + + /* The following is done for non-Rx ports only */ + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + { + if((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) || + (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + { + /* define dequeue NIA */ + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, NIA_ENG_BMI | NIA_BMI_AC_TX); + /* define enqueue NIA */ + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); + } + else /* for HC & OP */ + { + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, NIA_ENG_BMI | NIA_BMI_AC_FETCH); + /* define enqueue NIA */ + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, NIA_ENG_BMI | NIA_BMI_AC_RELEASE); + } + + /* configure dequeue */ + tmpReg = 0; + if(p_Params->deqHighPriority) + tmpReg |= QMI_DEQ_CFG_PRI; + + switch(p_Params->deqType) + { + case(e_FM_PORT_DEQ_TYPE1): + tmpReg |= QMI_DEQ_CFG_TYPE1; + break; + case(e_FM_PORT_DEQ_TYPE2): + tmpReg |= QMI_DEQ_CFG_TYPE2; + break; + case(e_FM_PORT_DEQ_TYPE3): + tmpReg |= QMI_DEQ_CFG_TYPE3; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid dequeue type")); + } + +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + switch(p_Params->deqPrefetchOption) + { + case(e_FM_PORT_DEQ_NO_PREFETCH): + /* Do nothing - QMI_DEQ_CFG_PREFETCH_WAITING_TNUM | QMI_DEQ_CFG_PREFETCH_1_FRAME = 0 */ + break; + case(e_FM_PORT_DEQ_PARTIAL_PREFETCH): + tmpReg |= QMI_DEQ_CFG_PREFETCH_WAITING_TNUM | QMI_DEQ_CFG_PREFETCH_3_FRAMES; + break; + case(e_FM_PORT_DEQ_FULL_PREFETCH): + tmpReg |= QMI_DEQ_CFG_PREFETCH_NO_TNUM | QMI_DEQ_CFG_PREFETCH_3_FRAMES; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid dequeue prefetch option")); + } +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + + tmpReg |= p_Params->deqByteCnt; + tmpReg |= (uint32_t)p_Params->deqSubPortal << QMI_DEQ_CFG_SUBPORTAL_SHIFT; + + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndc, tmpReg); + } + else /* rx port */ + /* define enqueue NIA */ + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, NIA_ENG_BMI | NIA_BMI_AC_RELEASE); + + return E_OK; +} + +static t_Error BmiRxPortCheckAndGetCounterPtr(t_FmPort *p_FmPort, e_FmPortCounters counter, volatile uint32_t **p_Ptr) +{ + t_FmPortRxBmiRegs *p_BmiRegs = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs; + + /* check that counters are enabled */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_CYCLE): + case(e_FM_PORT_COUNTERS_TASK_UTIL): + case(e_FM_PORT_COUNTERS_QUEUE_UTIL): + case(e_FM_PORT_COUNTERS_DMA_UTIL): + case(e_FM_PORT_COUNTERS_FIFO_UTIL): + case(e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + /* performance counters - may be read when disabled */ + break; + case(e_FM_PORT_COUNTERS_FRAME): + case(e_FM_PORT_COUNTERS_DISCARD_FRAME): + case(e_FM_PORT_COUNTERS_RX_BAD_FRAME): + case(e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + case(e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + case(e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case(e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + case(e_FM_PORT_COUNTERS_DEALLOC_BUF): + if(!(GET_UINT32(p_BmiRegs->fmbm_rstc) & BMI_COUNTERS_EN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for Rx ports")); + } + + /* Set counter */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_CYCLE): + *p_Ptr = &p_BmiRegs->fmbm_rccn; + break; + case(e_FM_PORT_COUNTERS_TASK_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_rtuc; + break; + case(e_FM_PORT_COUNTERS_QUEUE_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_rrquc; + break; + case(e_FM_PORT_COUNTERS_DMA_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_rduc; + break; + case(e_FM_PORT_COUNTERS_FIFO_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_rfuc; + break; + case(e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + *p_Ptr = &p_BmiRegs->fmbm_rpac; + break; + case(e_FM_PORT_COUNTERS_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_rfrc; + break; + case(e_FM_PORT_COUNTERS_DISCARD_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_rfcd; + break; + case(e_FM_PORT_COUNTERS_RX_BAD_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_rfbc; + break; + case(e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_rlfc; + break; + case(e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_rffc; + break; + case(e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): +#ifdef FM_PORT_COUNTERS_ERRATA_FMANg + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Requested counter is not available in rev1")); + } +#endif /* FM_PORT_COUNTERS_ERRATA_FMANg */ + *p_Ptr = &p_BmiRegs->fmbm_rfldec; + break; + case(e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + *p_Ptr = &p_BmiRegs->fmbm_rodc; + break; + case(e_FM_PORT_COUNTERS_DEALLOC_BUF): + *p_Ptr = &p_BmiRegs->fmbm_rbdc; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for Rx ports")); + } + + return E_OK; +} + +static t_Error BmiTxPortCheckAndGetCounterPtr(t_FmPort *p_FmPort, e_FmPortCounters counter, volatile uint32_t **p_Ptr) +{ + t_FmPortTxBmiRegs *p_BmiRegs = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs; + + /* check that counters are enabled */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_CYCLE): + case(e_FM_PORT_COUNTERS_TASK_UTIL): + case(e_FM_PORT_COUNTERS_QUEUE_UTIL): + case(e_FM_PORT_COUNTERS_DMA_UTIL): + case(e_FM_PORT_COUNTERS_FIFO_UTIL): + /* performance counters - may be read when disabled */ + break; + case(e_FM_PORT_COUNTERS_FRAME): + case(e_FM_PORT_COUNTERS_DISCARD_FRAME): + case(e_FM_PORT_COUNTERS_LENGTH_ERR): + case(e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case(e_FM_PORT_COUNTERS_DEALLOC_BUF): + if(!(GET_UINT32(p_BmiRegs->fmbm_tstc) & BMI_COUNTERS_EN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for Tx ports")); + } + + /* Set counter */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_CYCLE): + *p_Ptr = &p_BmiRegs->fmbm_tccn; + break; + case(e_FM_PORT_COUNTERS_TASK_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_ttuc; + break; + case(e_FM_PORT_COUNTERS_QUEUE_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_ttcquc; + break; + case(e_FM_PORT_COUNTERS_DMA_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_tduc; + break; + case(e_FM_PORT_COUNTERS_FIFO_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_tfuc; + break; + case(e_FM_PORT_COUNTERS_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_tfrc; + break; + case(e_FM_PORT_COUNTERS_DISCARD_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_tfdc; + break; + case(e_FM_PORT_COUNTERS_LENGTH_ERR): + *p_Ptr = &p_BmiRegs->fmbm_tfledc; + break; + case(e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + *p_Ptr = &p_BmiRegs->fmbm_tfufdc; + break; + case(e_FM_PORT_COUNTERS_DEALLOC_BUF): + *p_Ptr = &p_BmiRegs->fmbm_tbdc; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for Tx ports")); + } + + return E_OK; +} + +static t_Error BmiOhPortCheckAndGetCounterPtr(t_FmPort *p_FmPort, e_FmPortCounters counter, volatile uint32_t **p_Ptr) +{ + t_FmPortOhBmiRegs *p_BmiRegs = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs; + + /* check that counters are enabled */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_CYCLE): + case(e_FM_PORT_COUNTERS_TASK_UTIL): + case(e_FM_PORT_COUNTERS_DMA_UTIL): + case(e_FM_PORT_COUNTERS_FIFO_UTIL): + /* performance counters - may be read when disabled */ + break; + case(e_FM_PORT_COUNTERS_FRAME): + case(e_FM_PORT_COUNTERS_DISCARD_FRAME): + case(e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case(e_FM_PORT_COUNTERS_WRED_DISCARD): + case(e_FM_PORT_COUNTERS_LENGTH_ERR): + case(e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case(e_FM_PORT_COUNTERS_DEALLOC_BUF): + if(!(GET_UINT32(p_BmiRegs->fmbm_ostc) & BMI_COUNTERS_EN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + break; + case(e_FM_PORT_COUNTERS_RX_FILTER_FRAME): /* only valid for offline parsing */ + if(p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for Host Command ports")); + if(!(GET_UINT32(p_BmiRegs->fmbm_ostc) & BMI_COUNTERS_EN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for O/H ports")); + } + + /* Set counter */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_CYCLE): + *p_Ptr = &p_BmiRegs->fmbm_occn; + break; + case(e_FM_PORT_COUNTERS_TASK_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_otuc; + break; + case(e_FM_PORT_COUNTERS_DMA_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_oduc; + break; + case(e_FM_PORT_COUNTERS_FIFO_UTIL): + *p_Ptr = &p_BmiRegs->fmbm_ofuc; + break; + case(e_FM_PORT_COUNTERS_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_ofrc; + break; + case(e_FM_PORT_COUNTERS_DISCARD_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_ofdc; + break; + case(e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + *p_Ptr = &p_BmiRegs->fmbm_offc; + break; + case(e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): +#ifdef FM_PORT_COUNTERS_ERRATA_FMANg + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Requested counter is not available in rev1")); + } +#endif /* FM_PORT_COUNTERS_ERRATA_FMANg */ + *p_Ptr = &p_BmiRegs->fmbm_ofldec; + break; + case(e_FM_PORT_COUNTERS_WRED_DISCARD): + *p_Ptr = &p_BmiRegs->fmbm_ofwdc; + break; + case(e_FM_PORT_COUNTERS_LENGTH_ERR): + *p_Ptr = &p_BmiRegs->fmbm_ofledc; + break; + case(e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + *p_Ptr = &p_BmiRegs->fmbm_ofufdc; + break; + case(e_FM_PORT_COUNTERS_DEALLOC_BUF): + *p_Ptr = &p_BmiRegs->fmbm_obdc; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for O/H ports")); + } + + return E_OK; +} + +static t_Error AdditionalPrsParams(t_FmPort *p_FmPort, t_FmPcdPrsAdditionalHdrParams *p_HdrParams, uint32_t *p_SoftSeqAttachReg) +{ + uint8_t hdrNum, Ipv4HdrNum; + u_FmPcdHdrPrsOpts *p_prsOpts; + uint32_t tmpReg = 0, tmpPrsOffset; + + if(IS_PRIVATE_HEADER(p_HdrParams->hdr) || IS_SPECIAL_HEADER(p_HdrParams->hdr)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("No additional parameters for private or special headers.")); + + if(p_HdrParams->errDisable) + tmpReg |= PRS_HDR_ERROR_DIS; + + /* Set parser options */ + if(p_HdrParams->usePrsOpts) + { + p_prsOpts = &p_HdrParams->prsOpts; + switch(p_HdrParams->hdr) + { + case(HEADER_TYPE_MPLS): + if(p_prsOpts->mplsPrsOptions.labelInterpretationEnable) + tmpReg |= PRS_HDR_MPLS_LBL_INTER_EN; + GET_PRS_HDR_NUM(hdrNum, p_prsOpts->mplsPrsOptions.nextParse); + if(hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + GET_PRS_HDR_NUM(Ipv4HdrNum, HEADER_TYPE_IPv4); + if(hdrNum < Ipv4HdrNum) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Header must be equal or higher than IPv4")); + tmpReg |= ((uint32_t)hdrNum * PRS_HDR_ENTRY_SIZE) << PRS_HDR_MPLS_NEXT_HDR_SHIFT; + break; + case(HEADER_TYPE_PPPoE): + if(p_prsOpts->pppoePrsOptions.enableMTUCheck) + { +#ifdef FM_PPPOE_NO_MTU_CHECK + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Invalid parser option")); + else +#endif /* FM_PPPOE_NO_MTU_CHECK */ + tmpReg |= PRS_HDR_PPPOE_MTU_CHECK_EN; + } + break; + case(HEADER_TYPE_IPv6): + if(p_prsOpts->ipv6PrsOptions.routingHdrDisable) + tmpReg |= PRS_HDR_IPV6_ROUTE_HDR_DIS; + break; + case(HEADER_TYPE_TCP): + if(p_prsOpts->tcpPrsOptions.padIgnoreChecksum) + tmpReg |= PRS_HDR_TCP_PAD_REMOVAL; + break; + case(HEADER_TYPE_UDP): + if(p_prsOpts->udpPrsOptions.padIgnoreChecksum) + tmpReg |= PRS_HDR_TCP_PAD_REMOVAL; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header")); + } + } + + /* set software parsing (address is devided in 2 since parser uses 2 byte access. */ + if(p_HdrParams->swPrsEnable) + { + tmpPrsOffset = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, p_HdrParams->hdr, p_HdrParams->indexPerHdr); + if(tmpPrsOffset == ILLEGAL_BASE) + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + tmpReg |= (PRS_HDR_SW_PRS_EN | tmpPrsOffset); + } + *p_SoftSeqAttachReg = tmpReg; + + return E_OK; +} + +static uint32_t GetPortSchemeBindParams(t_Handle h_FmPort, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t walking1Mask = 0x80000000, tmp; + uint8_t idx = 0; + + p_SchemeBind->netEnvId = p_FmPort->netEnvId; + p_SchemeBind->hardwarePortId = p_FmPort->hardwarePortId; + p_SchemeBind->useClsPlan = p_FmPort->useClsPlan; + p_SchemeBind->numOfSchemes = 0; + tmp = p_FmPort->schemesPerPortVector; + if(tmp) + { + while (tmp) + { + if(tmp & walking1Mask) + { + p_SchemeBind->schemesIds[p_SchemeBind->numOfSchemes] = FmPcdKgGetSchemeSwId(p_FmPort->h_FmPcd, idx); + p_SchemeBind->numOfSchemes++; + tmp &= ~walking1Mask; + } + walking1Mask >>= 1; + idx++; + } + } + + return tmp; +} + +static t_Error BuildBufferStructure(t_FmPort *p_FmPort) +{ + uint32_t tmp; + + ASSERT_COND(p_FmPort); + + /* Align start of internal context data to 16 byte */ + p_FmPort->p_FmPortDriverParam->intContext.extBufOffset = + (uint16_t)((p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize & (OFFSET_UNITS-1)) ? + ((p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize + OFFSET_UNITS) & ~(uint16_t)(OFFSET_UNITS-1)) : + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize); + + /* Translate margin and intContext params to FM parameters */ +#ifdef FM_INCORRECT_CS_ERRATA_FMAN18 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + uint8_t mod = p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign % 256; + if(mod) + { + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign += (256-mod); + DBG(WARNING,("dataAlign modified to next 256 to conform with FMAN18 errata\n")); + } + } + } +#endif /* FM_INCORRECT_CS_ERRATA_FMAN18 */ + + /* Initialize with illegal value. Later we'll set legal values. */ + p_FmPort->bufferOffsets.prsResultOffset = (uint32_t)ILLEGAL_BASE; + p_FmPort->bufferOffsets.timeStampOffset = (uint32_t)ILLEGAL_BASE; + p_FmPort->bufferOffsets.hashResultOffset= (uint32_t)ILLEGAL_BASE; + p_FmPort->bufferOffsets.pcdInfoOffset = (uint32_t)ILLEGAL_BASE; +#ifdef DEBUG + p_FmPort->bufferOffsets.debugOffset = (uint32_t)ILLEGAL_BASE; +#endif /* DEBUG */ + + /* Internally the driver supports 4 options + 1. prsResult/timestamp/hashResult selection (in fact 8 options, but for simplicity we'll + relate to it as 1). + 2. All IC context (from AD) except debug. + 3. Debug information only. + 4. All IC context (from AD) including debug. + Note, that if user asks for prsResult/timestamp/hashResult and Debug, we give them (4) */ + + /* This 'if' covers options 2 & 4. We copy from beginning of context with or without debug. */ + /* If passAllOtherPCDInfo explicitly requested, or passDebugInfo+prs/ts --> we also take passAllOtherPCDInfo */ + if ((p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo) +#ifdef DEBUG + || (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passDebugInfo && + (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult || + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp || + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passHashResult)) +#endif /* DEBUG */ + ) + { +#ifdef DEBUG + if(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passDebugInfo) + { + p_FmPort->p_FmPortDriverParam->intContext.size = 240; + p_FmPort->bufferOffsets.debugOffset = + (uint32_t)(p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + 128); + } + else +#endif /* DEBUG */ + p_FmPort->p_FmPortDriverParam->intContext.size = 128; /* must be aligned to 16 */ + /* Start copying data after 16 bytes (FD) from the beginning of the internal context */ + p_FmPort->p_FmPortDriverParam->intContext.intContextOffset = 16; + + if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo) + p_FmPort->bufferOffsets.pcdInfoOffset = p_FmPort->p_FmPortDriverParam->intContext.extBufOffset; + if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult) + p_FmPort->bufferOffsets.prsResultOffset = + (uint32_t)(p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + 16); + if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp) + p_FmPort->bufferOffsets.timeStampOffset = + (uint32_t)(p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + 48); + if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passHashResult) + p_FmPort->bufferOffsets.hashResultOffset = + (uint32_t)(p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + 56); + } + else + { +#ifdef DEBUG + if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passDebugInfo) + { + /* This case covers option 3 */ + p_FmPort->p_FmPortDriverParam->intContext.size = 112; + p_FmPort->p_FmPortDriverParam->intContext.intContextOffset = 144; + p_FmPort->bufferOffsets.debugOffset = p_FmPort->p_FmPortDriverParam->intContext.extBufOffset; + } + else +#endif /* DEBUG */ + { + /* This case covers the options under 1 */ + /* Copy size must be in 16-byte granularity. */ + p_FmPort->p_FmPortDriverParam->intContext.size = + (uint16_t)((p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult ? 32 : 0) + + ((p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp || + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passHashResult) ? 16 : 0)); + + /* Align start of internal context data to 16 byte */ + p_FmPort->p_FmPortDriverParam->intContext.intContextOffset = + (uint8_t)(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult ? 32 : + ((p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp || + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passHashResult) ? 64 : 0)); + + if(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult) + p_FmPort->bufferOffsets.prsResultOffset = p_FmPort->p_FmPortDriverParam->intContext.extBufOffset; + if(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp) + p_FmPort->bufferOffsets.timeStampOffset = p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult ? + (p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + sizeof(t_FmPrsResult)) : + p_FmPort->p_FmPortDriverParam->intContext.extBufOffset; + if(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passHashResult) + /* If PR is not requested, whether TS is requested or not, IC will be copied from TS */ + p_FmPort->bufferOffsets.hashResultOffset = p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult ? + (p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + sizeof(t_FmPrsResult) + 8) : + p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + 8; + } + } + + p_FmPort->p_FmPortDriverParam->bufMargins.startMargins = + (uint16_t)(p_FmPort->p_FmPortDriverParam->intContext.extBufOffset + + p_FmPort->p_FmPortDriverParam->intContext.size); +#ifdef FM_CAPWAP_SUPPORT + /* save extra space for manip in both external and internal buffers */ + if(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace) + { + if((p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace + FRAG_EXTRA_SPACE) >= 256) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace + 32 can not be equal or larger to 256")); + p_FmPort->bufferOffsets.manipOffset = p_FmPort->p_FmPortDriverParam->bufMargins.startMargins; + p_FmPort->p_FmPortDriverParam->bufMargins.startMargins += (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace + FRAG_EXTRA_SPACE); + p_FmPort->p_FmPortDriverParam->internalBufferOffset = + (uint8_t)(p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace + FRAG_EXTRA_SPACE); + } +#endif /* FM_CAPWAP_SUPPORT */ + + /* align data start */ + tmp = (uint32_t)(p_FmPort->p_FmPortDriverParam->bufMargins.startMargins % + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign); + if (tmp) + p_FmPort->p_FmPortDriverParam->bufMargins.startMargins += (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign-tmp); + p_FmPort->bufferOffsets.dataOffset = p_FmPort->p_FmPortDriverParam->bufMargins.startMargins; + p_FmPort->internalBufferOffset = p_FmPort->p_FmPortDriverParam->internalBufferOffset; + + return E_OK; +} + +static t_Error SetPcd(t_Handle h_FmPort, t_FmPortPcdParams *p_PcdParams) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + uint32_t tmpReg; + volatile uint32_t *p_BmiNia=NULL; + volatile uint32_t *p_BmiPrsNia=NULL; + volatile uint32_t *p_BmiPrsStartOffset=NULL; + volatile uint32_t *p_BmiInitPrsResult=NULL; + volatile uint32_t *p_BmiCcBase=NULL; + uint8_t hdrNum, L3HdrNum, greHdrNum; + int i; + bool isEmptyClsPlanGrp; + uint32_t tmpHxs[FM_PCD_PRS_NUM_OF_HDRS]; + uint16_t absoluteProfileId; + uint8_t physicalSchemeId; + uint32_t ccTreePhysOffset; + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + + p_FmPort->netEnvId = (uint8_t)(PTR_TO_UINT(p_PcdParams->h_NetEnv)-1); + + p_FmPort->pcdEngines = 0; + + /* initialize p_FmPort->pcdEngines field in port's structure */ + switch(p_PcdParams->pcdSupport) + { + case(e_FM_PORT_PCD_SUPPORT_NONE): + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("No PCD configuration required if e_FM_PORT_PCD_SUPPORT_NONE selected")); + case(e_FM_PORT_PCD_SUPPORT_PRS_ONLY): + p_FmPort->pcdEngines |= FM_PCD_PRS; + break; + case(e_FM_PORT_PCD_SUPPORT_PLCR_ONLY): + if (CHECK_FM_CTL_AC_POST_FETCH_PCD(p_FmPort->savedBmiNia)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("parser support is required")); + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + +#ifdef FM_CAPWAP_SUPPORT + case(e_FM_PORT_PCD_SUPPORT_CC_ONLY): + if (CHECK_FM_CTL_AC_POST_FETCH_PCD(p_FmPort->savedBmiNia)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("parser support is required")); + p_FmPort->pcdEngines |= FM_PCD_CC; + break; + case(e_FM_PORT_PCD_SUPPORT_CC_AND_KG): + if (CHECK_FM_CTL_AC_POST_FETCH_PCD(p_FmPort->savedBmiNia)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("parser support is required")); + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case(e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR): + if (CHECK_FM_CTL_AC_POST_FETCH_PCD(p_FmPort->savedBmiNia)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("parser support is required")); + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; +#endif /* FM_CAPWAP_SUPPORT */ + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid pcdSupport")); + } + + if((p_FmPort->pcdEngines & FM_PCD_PRS) && (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams > FM_PCD_PRS_NUM_OF_HDRS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Port parser numOfHdrsWithAdditionalParams may not exceed %d", FM_PCD_PRS_NUM_OF_HDRS)); + + /* check that parameters exist for each and only each defined engine */ + if((!!(p_FmPort->pcdEngines & FM_PCD_PRS) != !!p_PcdParams->p_PrsParams) || + (!!(p_FmPort->pcdEngines & FM_PCD_KG) != !!p_PcdParams->p_KgParams) || + (!!(p_FmPort->pcdEngines & FM_PCD_CC) != !!p_PcdParams->p_CcParams)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("PCD initialization structure is not consistant with pcdSupport")); + + /* get PCD registers pointers */ + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne; + p_BmiPrsNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne; + p_BmiPrsStartOffset = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpso; + p_BmiInitPrsResult = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rprai[0]; + p_BmiCcBase = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rccb; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofne; + p_BmiPrsNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofpne; + p_BmiPrsStartOffset = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opso; + p_BmiInitPrsResult = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_oprai[0]; + p_BmiCcBase = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_occb; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if(p_FmPort->pcdEngines & FM_PCD_KG) + { + + if(p_PcdParams->p_KgParams->numOfSchemes == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("For ports using Keygen, at lease one scheme must be bound. ")); + /* for each scheme */ + for(i = 0; ip_KgParams->numOfSchemes; i++) + { + physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_PcdParams->p_KgParams->h_Schemes[i])-1); + /* build vector */ + p_FmPort->schemesPerPortVector |= 1 << (31 - (uint32_t)physicalSchemeId); + } + + err = FmPcdKgSetOrBindToClsPlanGrp(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, + p_FmPort->netEnvId, + p_FmPort->optArray, + &p_FmPort->clsPlanGrpId, + &isEmptyClsPlanGrp); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FmPcdKgSetOrBindToClsPlanGrp failed. ")); + + p_FmPort->useClsPlan = !isEmptyClsPlanGrp; + } + + /* set PCD port parameter */ + if(p_FmPort->pcdEngines & FM_PCD_CC) + { + err = FmPcdCcBindTree(p_FmPort->h_FmPcd, p_PcdParams->p_CcParams->h_CcTree, &ccTreePhysOffset, h_FmPort); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + + WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); + p_FmPort->ccTreeId = p_PcdParams->p_CcParams->h_CcTree; + } + + /***************************/ + /* configure NIA after BMI */ + /***************************/ + if (!CHECK_FM_CTL_AC_POST_FETCH_PCD(p_FmPort->savedBmiNia)) + /* rfne may contain FDCS bits, so first we read them. */ + p_FmPort->savedBmiNia = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; + + /* If policer is used directly after BMI or PRS */ + if((p_FmPort->pcdEngines & FM_PCD_PLCR) && + ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PLCR_ONLY) || + (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR))) + { + absoluteProfileId = (uint16_t)(PTR_TO_UINT(p_PcdParams->p_PlcrParams->h_Profile)-1); + + if(!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Private port profile not valid.")); + + tmpReg = (uint32_t)(absoluteProfileId | NIA_PLCR_ABSOLUTE); + + if(p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ + { + /* update BMI HPNIA */ + WRITE_UINT32(*p_BmiPrsNia, (uint32_t)(NIA_ENG_PLCR | tmpReg)); + } + else /* e_FM_PCD_SUPPORT_PLCR_ONLY */ + /* update BMI NIA */ + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PLCR); + } + +#ifdef FM_CAPWAP_SUPPORT + /* if CC is used directly after BMI */ + if((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_ONLY) || + (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG) || + (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR)) + { + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("e_FM_PORT_PCD_SUPPORT_CC_xx available for offline parsing ports only")); + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC); + /* check that prs start offset == RIM[FOF] */ + } +#endif /* FM_CAPWAP_SUPPORT */ + + if (p_FmPort->pcdEngines & FM_PCD_PRS) + { + ASSERT_COND(p_PcdParams->p_PrsParams); + /* if PRS is used it is always first */ + GET_PRS_HDR_NUM(hdrNum, p_PcdParams->p_PrsParams->firstPrsHdr); + if (hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header.")); + if (!CHECK_FM_CTL_AC_POST_FETCH_PCD(p_FmPort->savedBmiNia)) + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PRS | (uint32_t)(hdrNum)); + /* set after parser NIA */ + tmpReg = 0; + switch(p_PcdParams->pcdSupport) + { + case(e_FM_PORT_PCD_SUPPORT_PRS_ONLY): + WRITE_UINT32(*p_BmiPrsNia, NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); + break; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): + tmpReg = NIA_KG_CC_EN; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): + if(p_PcdParams->p_KgParams->directScheme) + { + physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_PcdParams->p_KgParams->h_DirectScheme)-1); + /* check that this scheme was bound to this port */ + for(i=0 ; ip_KgParams->numOfSchemes; i++) + if(p_PcdParams->p_KgParams->h_DirectScheme == p_PcdParams->p_KgParams->h_Schemes[i]) + break; + if(i == p_PcdParams->p_KgParams->numOfSchemes) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Direct scheme is not one of the port selected schemes.")); + tmpReg |= (uint32_t)(NIA_KG_DIRECT | physicalSchemeId); + } + WRITE_UINT32(*p_BmiPrsNia, NIA_ENG_KG | tmpReg); + break; + case(e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid PCD support")); + } + + /* set start parsing offset */ + /* WRITE_UINT32(*p_BmiPrsStartOffset, p_PcdParams->p_PrsParams->parsingOffset); */ + + /************************************/ + /* Parser port parameters */ + /************************************/ + /* stop before configuring */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while(GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) ; + + /* set soft seq attachment register */ + memset(tmpHxs, 0, FM_PCD_PRS_NUM_OF_HDRS*sizeof(uint32_t)); + + /* set protocol options */ + for(i=0;p_FmPort->optArray[i];i++) + switch(p_FmPort->optArray[i]) + { + case(ETH_BROADCAST): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_ETH) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_ETH_BC_SHIFT; + break; + case(ETH_MULTICAST): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_ETH) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_ETH_MC_SHIFT; + break; + case(VLAN_STACKED): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_VLAN) + tmpHxs[hdrNum] |= (i+1)<< PRS_HDR_VLAN_STACKED_SHIFT; + break; + case(MPLS_STACKED): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_MPLS) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_MPLS_STACKED_SHIFT; + break; + case(IPV4_BROADCAST_1): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPv4) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_IPV4_1_BC_SHIFT; + break; + case(IPV4_MULTICAST_1): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPv4) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_IPV4_1_MC_SHIFT; + break; + case(IPV4_UNICAST_2): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPv4) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_IPV4_2_UC_SHIFT; + break; + case(IPV4_MULTICAST_BROADCAST_2): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPv4) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_IPV4_2_MC_BC_SHIFT; + break; + case(IPV6_MULTICAST_1): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPv6) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_IPV6_1_MC_SHIFT; + break; + case(IPV6_UNICAST_2): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPv6) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_IPV6_2_UC_SHIFT; + break; + case(IPV6_MULTICAST_2): + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPv6) + tmpHxs[hdrNum] |= (i+1) << PRS_HDR_IPV6_2_MC_SHIFT; + break; + } + + if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP)) + { + p_PcdParams->p_PrsParams->additionalParams + [p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].hdr = HEADER_TYPE_UDP; + p_PcdParams->p_PrsParams->additionalParams + [p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].swPrsEnable = TRUE; + p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams++; + } + + /* set MPLS default next header - HW reset workaround */ + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_MPLS) + tmpHxs[hdrNum] |= PRS_HDR_MPLS_LBL_INTER_EN; + GET_PRS_HDR_NUM(L3HdrNum, HEADER_TYPE_USER_DEFINED_L3); + tmpHxs[hdrNum] |= (uint32_t)L3HdrNum << PRS_HDR_MPLS_NEXT_HDR_SHIFT; + + /* for GRE, disable errors */ + GET_PRS_HDR_NUM(greHdrNum, HEADER_TYPE_GRE); + tmpHxs[greHdrNum] |= PRS_HDR_ERROR_DIS; + + /* config additional params for specific headers */ + for(i=0 ; ip_PrsParams->numOfHdrsWithAdditionalParams ; i++) + { + GET_PRS_HDR_NUM(hdrNum, p_PcdParams->p_PrsParams->additionalParams[i].hdr); + if(hdrNum== ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + if(hdrNum==NO_HDR_NUM) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Private headers may not use additional parameters")); + + err = AdditionalPrsParams(p_FmPort, &p_PcdParams->p_PrsParams->additionalParams[i], &tmpReg); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + tmpHxs[hdrNum] |= tmpReg; + } +#ifdef FM_PRS_L4_SHELL_ERRATA_FMANb + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + /* link to sw parser code for L4 shells - only if no other code is applied. */ + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_SCTP) + if(!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | SCTP_SW_PATCH_START); + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_DCCP) + if(!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | DCCP_SW_PATCH_START); + GET_PRS_HDR_NUM(hdrNum, HEADER_TYPE_IPSEC_AH) + if(!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | IPSEC_SW_PATCH_START); + } + } +#endif /* FM_PRS_L4_SHELL_ERRATA_FMANb */ + + for(i=0 ; ip_FmPortPrsRegs->hdrs[i].lcv, FmPcdGetLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId, (uint8_t)i)); + /* set HXS register according to default+Additional params+protocol options */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[i].softSeqAttach, tmpHxs[i]); + } + + /* set tpid. */ + tmpReg = PRS_TPID_DFLT; + if(p_PcdParams->p_PrsParams->setVlanTpid1) + { + tmpReg &= PRS_TPID2_MASK; + tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid1 << PRS_PCTPID_SHIFT; + } + if(p_PcdParams->p_PrsParams->setVlanTpid2) + { + tmpReg &= PRS_TPID1_MASK; + tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid2; + } + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pctpid, tmpReg); + + /* enable parser */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, 0); + + if(p_PcdParams->p_PrsParams->prsResultPrivateInfo) + p_FmPort->privateInfo = p_PcdParams->p_PrsParams->prsResultPrivateInfo; + + } /* end parser */ + else + p_FmPort->privateInfo = 0; + + WRITE_UINT32(*p_BmiPrsStartOffset, GET_UINT32(*p_BmiPrsStartOffset) + p_FmPort->internalBufferOffset); + + /* set initial parser result - used for all engines */ + for (i=0;iprivateInfo << BMI_PR_PORTID_SHIFT) + | BMI_PRS_RESULT_HIGH)); + else + if (i< FM_PORT_PRS_RESULT_NUM_OF_WORDS/2) + WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_HIGH); + else + WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_LOW); + } + + return E_OK; +} + +static t_Error DeletePcd(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + volatile uint32_t *p_BmiNia=NULL; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + + if(!p_FmPort->pcdEngines) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("called for non PCD port")); + + /* get PCD registers pointers */ + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofne; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if((GET_UINT32(*p_BmiNia) & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) != (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("port has to be detached previousely")); + + /* "cut" PCD out of the port's flow - go to BMI */ + /* WRITE_UINT32(*p_BmiNia, (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); */ + + if(p_FmPort->pcdEngines | FM_PCD_PRS) + { + /* stop parser */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while(GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) ; + } + + if(p_FmPort->pcdEngines & FM_PCD_KG) + { + err = FmPcdKgDeleteOrUnbindPortToClsPlanGrp(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId, p_FmPort->clsPlanGrpId); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + p_FmPort->useClsPlan = FALSE; + } + + if(p_FmPort->pcdEngines & FM_PCD_CC) + { + /* unbind - we need to get the treeId too */ + err = FmPcdCcUnbindTree(p_FmPort->h_FmPcd, p_FmPort->ccTreeId); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + } + + p_FmPort->pcdEngines = 0; + + return E_OK; +} + + +/********************************************/ +/* Inter-module API */ +/********************************************/ +void FmPortSetMacsecLcv(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + uint32_t macsecEn = BMI_PORT_CFG_EN_MACSEC; + uint32_t lcv, walking1Mask = 0x80000000; + uint8_t cnt = 0; + + SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + { + REPORT_ERROR(MAJOR, E_INVALID_OPERATION, ("The routine is relevant for Rx ports only")); + return; + } + + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg; + /* get LCV for MACSEC */ + if ((p_FmPort->h_FmPcd) && ((lcv = FmPcdGetMacsecLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId))!= 0)) + { + while(!(lcv & walking1Mask)) + { + cnt++; + walking1Mask >>= 1; + } + + macsecEn |= (uint32_t)cnt << BMI_PORT_CFG_MS_SEL_SHIFT; + } + + WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) | macsecEn); +} + +void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + uint32_t tmpReg; + + SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + { + REPORT_ERROR(MAJOR, E_INVALID_OPERATION, ("The routine is relevant for Tx ports only")); + return; + } + + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfca; + tmpReg = GET_UINT32(*p_BmiCfgReg) & ~BMI_CMD_ATTR_MACCMD_MASK; + tmpReg |= BMI_CMD_ATTR_MACCMD_SECURED; + tmpReg |= (((uint32_t)dfltSci << BMI_CMD_ATTR_MACCMD_SC_SHIFT) & BMI_CMD_ATTR_MACCMD_SC_MASK); + + WRITE_UINT32(*p_BmiCfgReg, tmpReg); +} + +uint8_t FmPortGetNetEnvId(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->netEnvId; +} + +uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->hardwarePortId; +} + +uint32_t FmPortGetPcdEngines(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->pcdEngines; +} + +t_Error FmPortAttachPCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiNia=NULL; + +/*TODO - to take care about the chnges that were made in the port because of the previously assigned tree. +pndn, pnen ... maybe were changed because of the Tree requirement*/ + + /* get PCD registers pointers */ + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofne; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + } + + if(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if(FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 1)!= E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + /* check that current NIA is BMI to BMI */ + if((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) != (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("may be called only for ports in BMI-to-BMI state.")); + + WRITE_UINT32(*p_BmiNia, p_FmPort->savedBmiNia); + + if(p_FmPort->requiredAction & UPDATE_NIA_PNEN) + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, p_FmPort->savedQmiPnen); + + if(p_FmPort->requiredAction & UPDATE_NIA_PNDN) + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, p_FmPort->savedNonRxQmiRegsPndn); + + + return E_OK; +} + +t_Error FmPortGetSetCcParams(t_Handle h_FmPort, t_FmPortGetSetCcParams *p_CcParams) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int tmpInt; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + + /* this function called from Cc for pass and receive parameters port params between CC and PORT*/ + + if((p_CcParams->getCcParams.type & OFFSET_OF_PR) && (p_FmPort->bufferOffsets.prsResultOffset != ILLEGAL_BASE)) + { + p_CcParams->getCcParams.prOffset = (uint8_t)p_FmPort->bufferOffsets.prsResultOffset; + p_CcParams->getCcParams.type &= ~OFFSET_OF_PR; + } + if(p_CcParams->getCcParams.type & HW_PORT_ID) + { + p_CcParams->getCcParams.hardwarePortId = (uint8_t)p_FmPort->hardwarePortId; + p_CcParams->getCcParams.type &= ~HW_PORT_ID; + } + if((p_CcParams->getCcParams.type & OFFSET_OF_DATA) && (p_FmPort->bufferOffsets.dataOffset != ILLEGAL_BASE)) + { + p_CcParams->getCcParams.dataOffset = (uint16_t)p_FmPort->bufferOffsets.dataOffset; + p_CcParams->getCcParams.type &= ~OFFSET_OF_DATA; + } + if(p_CcParams->getCcParams.type & NUM_OF_TASKS) + { + p_CcParams->getCcParams.numOfTasks = p_FmPort->numOfTasks; + p_CcParams->getCcParams.type &= ~NUM_OF_TASKS; + } + if(p_CcParams->getCcParams.type & BUFFER_POOL_ID_FOR_MANIP) + { + if(p_CcParams->getCcParams.poolIndex < p_FmPort->extBufPools.numOfPoolsUsed) + { + p_CcParams->getCcParams.poolIdForManip = p_FmPort->extBufPools.extBufPool[p_CcParams->getCcParams.poolIndex].id; + p_CcParams->getCcParams.type &= ~BUFFER_POOL_ID_FOR_MANIP; + } + } + + if((p_CcParams->setCcParams.type & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) && !(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)) + { + p_FmPort->requiredAction |= UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; + } + + if((p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) && !(p_FmPort->requiredAction & UPDATE_NIA_PNEN)) + { + p_FmPort->savedQmiPnen = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_PNEN; + } + else if (p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) + { + if(p_FmPort->savedQmiPnen != p_CcParams->setCcParams.nia) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("pnen was defined previously different")); + } + + if((p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) && !(p_FmPort->requiredAction & UPDATE_NIA_PNDN)) + { + p_FmPort->savedNonRxQmiRegsPndn = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_PNDN; + } + else if(p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) + { + if(p_FmPort->savedNonRxQmiRegsPndn != p_CcParams->setCcParams.nia) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("pndn was defined previously different")); + } + + + if((p_CcParams->setCcParams.type & UPDATE_PSO) && !(p_FmPort->requiredAction & UPDATE_PSO)) + { + /* get PCD registers pointers */ + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiPrsStartOffset = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpso; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiPrsStartOffset = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opso; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + /* set start parsing offset */ + tmpInt = (int)GET_UINT32(*p_BmiPrsStartOffset)+ p_CcParams->setCcParams.psoSize; + if(tmpInt>0) + WRITE_UINT32(*p_BmiPrsStartOffset, (uint32_t)tmpInt); + + p_FmPort->requiredAction |= UPDATE_PSO; + p_FmPort->savedPrsStartOffset = p_CcParams->setCcParams.psoSize; + + } + else if (p_CcParams->setCcParams.type & UPDATE_PSO) + { + if(p_FmPort->savedPrsStartOffset != p_CcParams->setCcParams.psoSize) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("parser start offset was defoned previousley different")); + } + return E_OK; +} +/********************************** End of inter-module routines ********************************/ + +/****************************************/ +/* API Init unit functions */ +/****************************************/ +t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams) +{ + t_FmPort *p_FmPort; + uintptr_t baseAddr = p_FmPortParams->baseAddr; + + /* Allocate FM structure */ + p_FmPort = (t_FmPort *) XX_Malloc(sizeof(t_FmPort)); + if (!p_FmPort) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver structure")); + return NULL; + } + memset(p_FmPort, 0, sizeof(t_FmPort)); + + /* Allocate the FM driver's parameters structure */ + p_FmPort->p_FmPortDriverParam = (t_FmPortDriverParam *)XX_Malloc(sizeof(t_FmPortDriverParam)); + if (!p_FmPort->p_FmPortDriverParam) + { + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver parameters")); + return NULL; + } + memset(p_FmPort->p_FmPortDriverParam, 0, sizeof(t_FmPortDriverParam)); + + /* Initialize FM port parameters which will be kept by the driver */ + p_FmPort->portType = p_FmPortParams->portType; + p_FmPort->portId = p_FmPortParams->portId; + p_FmPort->pcdEngines = FM_PCD_NONE; + p_FmPort->f_Exception = p_FmPortParams->f_Exception; + p_FmPort->h_App = p_FmPortParams->h_App; + p_FmPort->h_Fm = p_FmPortParams->h_Fm; + + /* calculate global portId number */ + SW_PORT_ID_TO_HW_PORT_ID(p_FmPort->hardwarePortId, p_FmPort->portType, p_FmPortParams->portId); + + /* Initialize FM port parameters for initialization phase only */ + p_FmPort->p_FmPortDriverParam->baseAddr = baseAddr; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize = DEFAULT_PORT_bufferPrefixContent_privDataSize; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult= DEFAULT_PORT_bufferPrefixContent_passPrsResult; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp= DEFAULT_PORT_bufferPrefixContent_passTimeStamp; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo + = DEFAULT_PORT_bufferPrefixContent_passTimeStamp; +#ifdef DEBUG + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passDebugInfo= DEFAULT_PORT_bufferPrefixContent_debugInfo; +#endif /* DEBUG */ + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = DEFAULT_PORT_bufferPrefixContent_dataAlign; + p_FmPort->p_FmPortDriverParam->dmaSwapData = DEFAULT_PORT_dmaSwapData; + p_FmPort->p_FmPortDriverParam->dmaIntContextCacheAttr = DEFAULT_PORT_dmaIntContextCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaHeaderCacheAttr = DEFAULT_PORT_dmaHeaderCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaScatterGatherCacheAttr = DEFAULT_PORT_dmaScatterGatherCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaWriteOptimize = DEFAULT_PORT_dmaWriteOptimize; + p_FmPort->p_FmPortDriverParam->liodnBase = p_FmPortParams->liodnBase; + + /* resource distribution. */ + p_FmPort->fifoBufs.num = DEFAULT_PORT_sizeOfFifo(p_FmPort->portType); + p_FmPort->fifoBufs.extra = DEFAULT_PORT_extraSizeOfFifo(p_FmPort->portType); + p_FmPort->openDmas.num = DEFAULT_PORT_numOfOpenDmas(p_FmPort->portType); + p_FmPort->openDmas.extra = DEFAULT_PORT_extraNumOfOpenDmas(p_FmPort->portType); + p_FmPort->tasks.num = DEFAULT_PORT_numOfTasks(p_FmPort->portType); + p_FmPort->tasks.extra = DEFAULT_PORT_extraNumOfTasks(p_FmPort->portType); + p_FmPort->numOfTasks = (uint8_t)p_FmPort->tasks.num; +#ifdef FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + p_FmPort->fifoBufs.extra = 0; + p_FmPort->openDmas.extra = 0; + p_FmPort->tasks.extra = 0; + } + } +#endif /* FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 */ + + p_FmPort->p_FmPortDriverParam->color = DEFAULT_PORT_color; +#ifdef FM_OP_PORT_QMAN_REJECT_ERRATA_FMAN21 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0) && + (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + p_FmPort->p_FmPortDriverParam->color = e_FM_PORT_COLOR_OVERRIDE; + } +#endif /* FM_OP_PORT_QMAN_REJECT_ERRATA_FMAN21 */ + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + p_FmPort->p_FmPortDriverParam->syncReq = DEFAULT_PORT_syncReqForHc; + else + p_FmPort->p_FmPortDriverParam->syncReq = DEFAULT_PORT_syncReq; + +#ifdef FM_PORT_SYNC_ERRATA_FMAN6 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0) && + (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + p_FmPort->p_FmPortDriverParam->syncReq = FALSE; + } +#endif /* FM_PORT_SYNC_ERRATA_FMAN6 */ + + /* Port type specific initialization: */ + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) + p_FmPort->p_FmPortDriverParam->frmDiscardOverride = DEFAULT_PORT_frmDiscardOverride; + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX): + case(e_FM_PORT_TYPE_RX_10G): + /* Initialize FM port parameters for initialization phase only */ + p_FmPort->p_FmPortDriverParam->cutBytesFromEnd = DEFAULT_PORT_cutBytesFromEnd; + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = FALSE; + p_FmPort->p_FmPortDriverParam->frmDiscardOverride = DEFAULT_PORT_frmDiscardOverride; + p_FmPort->p_FmPortDriverParam->rxFifoPriElevationLevel = DEFAULT_PORT_rxFifoPriElevationLevel; + p_FmPort->p_FmPortDriverParam->rxFifoThreshold = DEFAULT_PORT_rxFifoThreshold; + p_FmPort->p_FmPortDriverParam->bufMargins.endMargins = DEFAULT_PORT_BufMargins_endMargins; + p_FmPort->p_FmPortDriverParam->errorsToDiscard = DEFAULT_PORT_errorsToDiscard; + p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = DEFAULT_PORT_cheksumLastBytesIgnore; + p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = DEFAULT_PORT_forwardIntContextReuse; + break; + + case(e_FM_PORT_TYPE_TX): + p_FmPort->txFifoDeqPipelineDepth = DEFAULT_PORT_txFifoDeqPipelineDepth_1G; + p_FmPort->p_FmPortDriverParam->dontReleaseBuf = FALSE; + case(e_FM_PORT_TYPE_TX_10G): + if(p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + p_FmPort->txFifoDeqPipelineDepth = DEFAULT_PORT_txFifoDeqPipelineDepth_10G; + p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = DEFAULT_PORT_cheksumLastBytesIgnore; + p_FmPort->p_FmPortDriverParam->txFifoMinFillLevel = DEFAULT_PORT_txFifoMinFillLevel; + p_FmPort->p_FmPortDriverParam->txFifoLowComfLevel = DEFAULT_PORT_txFifoLowComfLevel; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_FmPort->p_FmPortDriverParam->deqHighPriority = DEFAULT_PORT_deqHighPriority; + p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType; +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = DEFAULT_PORT_deqPrefetchOption; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + p_FmPort->p_FmPortDriverParam->deqByteCnt = DEFAULT_PORT_deqByteCnt; + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_FmPort->p_FmPortDriverParam->errorsToDiscard = DEFAULT_PORT_errorsToDiscard; + break; + + default: + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + return NULL; + } +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = DEFAULT_PORT_deqPrefetchOption_HC; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || + (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + p_FmPort->txFifoDeqPipelineDepth = OH_PIPELINE_DEPTH; + + p_FmPort->imEn = p_FmPortParams->independentModeEnable; + + if (p_FmPort->imEn) + { + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) || + (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + p_FmPort->txFifoDeqPipelineDepth = DEFAULT_PORT_txFifoDeqPipelineDepth_IM; + FmPortConfigIM(p_FmPort, p_FmPortParams); + } + else + { + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX): + case(e_FM_PORT_TYPE_RX_10G): + /* Initialize FM port parameters for initialization phase only */ + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, + &p_FmPortParams->specificParams.rxParams.extBufPools, + sizeof(t_FmPortExtPools)); + p_FmPort->p_FmPortDriverParam->errFqid = p_FmPortParams->specificParams.rxParams.errFqid; + p_FmPort->p_FmPortDriverParam->dfltFqid = p_FmPortParams->specificParams.rxParams.dfltFqid; + p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.rxParams.liodnOffset; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): +#ifdef FM_OP_PARTITION_ERRATA_FMANx8 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.nonRxParams.opLiodnOffset; + } +#endif /* FM_OP_PARTITION_ERRATA_FMANx8 */ + case(e_FM_PORT_TYPE_TX): + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_FmPort->p_FmPortDriverParam->errFqid = p_FmPortParams->specificParams.nonRxParams.errFqid; + p_FmPort->p_FmPortDriverParam->deqSubPortal = + (uint8_t)(p_FmPortParams->specificParams.nonRxParams.qmChannel & QMI_DEQ_CFG_SUBPORTAL_MASK); + p_FmPort->p_FmPortDriverParam->dfltFqid = p_FmPortParams->specificParams.nonRxParams.dfltFqid; + break; + default: + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + return NULL; + } + } + + memset(p_FmPort->name, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if(Sprint (p_FmPort->name, "FM-%d-port-%s-%d", + FmGetId(p_FmPort->h_Fm), + ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING || + (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ? + "OH" : (p_FmPort->portType == e_FM_PORT_TYPE_RX ? + "1g-RX" : (p_FmPort->portType == e_FM_PORT_TYPE_TX ? + "1g-TX" : (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G ? + "10g-RX" : "10g-TX")))), + p_FmPort->portId) == 0) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + return NULL; + } + + p_FmPort->h_Spinlock = XX_InitSpinlock(); + if (!p_FmPort->h_Spinlock) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + return NULL; + } + + return p_FmPort; +} + +/**************************************************************************//** + @Function FM_PORT_Init + + @Description Initializes the FM module + + @Param[in] h_FmPort - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PORT_Init(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPortDriverParam *p_Params; + t_Error err = E_OK; + t_FmInterModulePortInitParams fmParams; + uint32_t minFifoSizeRequired = 0; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((err = BuildBufferStructure(p_FmPort)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + CHECK_INIT_PARAMETERS(p_FmPort, CheckInitParameters); + + p_Params = p_FmPort->p_FmPortDriverParam; + + /* set memory map pointers */ + p_FmPort->p_FmPortQmiRegs = (t_FmPortQmiRegs *)UINT_TO_PTR(p_Params->baseAddr + QMI_PORT_REGS_OFFSET); + p_FmPort->p_FmPortBmiRegs = (u_FmPortBmiRegs *)UINT_TO_PTR(p_Params->baseAddr + BMI_PORT_REGS_OFFSET); + p_FmPort->p_FmPortPrsRegs = (t_FmPortPrsRegs *)UINT_TO_PTR(p_Params->baseAddr + PRS_PORT_REGS_OFFSET); + + /* For O/H ports, check fifo size and update if necessary */ + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { + minFifoSizeRequired = (uint32_t)((p_FmPort->txFifoDeqPipelineDepth+4)*BMI_FIFO_UNITS); + if (p_FmPort->fifoBufs.num < minFifoSizeRequired) + { + p_FmPort->fifoBufs.num = minFifoSizeRequired; + DBG(WARNING, ("FIFO size enlarged to %d due to txFifoDeqPipelineDepth size", minFifoSizeRequired)); + } + } + + /* For Rx Ports, call the external Buffer routine which also checks fifo + size and updates it if necessary */ + if(((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + && !p_FmPort->imEn) + { + /* define external buffer pools and pool depletion*/ + err = SetExtBufferPools(p_FmPort); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /************************************************************/ + /* Call FM module routine for communicating parameters */ + /************************************************************/ + memset(&fmParams, 0, sizeof(fmParams)); + fmParams.hardwarePortId = p_FmPort->hardwarePortId; + fmParams.portType = (e_FmPortType)p_FmPort->portType; + fmParams.numOfTasks = (uint8_t)p_FmPort->tasks.num; + fmParams.numOfExtraTasks = (uint8_t)p_FmPort->tasks.extra; + fmParams.numOfOpenDmas = (uint8_t)p_FmPort->openDmas.num; + fmParams.numOfExtraOpenDmas = (uint8_t)p_FmPort->openDmas.extra; + fmParams.sizeOfFifo = p_FmPort->fifoBufs.num; + fmParams.extraSizeOfFifo = p_FmPort->fifoBufs.extra; + fmParams.independentMode = p_FmPort->imEn; + fmParams.liodnOffset = p_Params->liodnOffset; + fmParams.liodnBase = p_Params->liodnBase; + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + fmParams.deqPipelineDepth = p_FmPort->txFifoDeqPipelineDepth; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + } + + err = FmGetSetPortParams(p_FmPort->h_Fm, &fmParams); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + p_FmPort->tasks.num = fmParams.numOfTasks; + p_FmPort->tasks.extra = fmParams.numOfExtraTasks; + p_FmPort->openDmas.num = fmParams.numOfOpenDmas; + p_FmPort->openDmas.extra = fmParams.numOfExtraOpenDmas; + p_FmPort->fifoBufs.num = fmParams.sizeOfFifo; + p_FmPort->fifoBufs.extra = fmParams.extraSizeOfFifo; + + /* get params for use in init */ + p_Params->fmMuramPhysBaseAddr = + (uint64_t)((uint64_t)(fmParams.fmMuramPhysBaseAddr.low) | + ((uint64_t)(fmParams.fmMuramPhysBaseAddr.high) << 32)); + + /**********************/ + /* Init BMI Registers */ + /**********************/ + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + err = BmiRxPortInit(p_FmPort); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + err = BmiTxPortInit(p_FmPort); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + err = BmiOhPortInit(p_FmPort); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + } + + /**********************/ + /* Init QMI Registers */ + /**********************/ + if (!p_FmPort->imEn && ((err = QmiInit(p_FmPort)) != E_OK)) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (p_FmPort->imEn && ((err = FmPortImInit(p_FmPort)) != E_OK)) + RETURN_ERROR(MAJOR, err, NO_MSG); + + FmPortDriverParamFree(p_FmPort); + + return E_OK; +} + +/**************************************************************************//** + @Function FM_PORT_Free + + @Description Frees all resources that were assigned to FM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmPort - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_PORT_Free(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmInterModulePortFreeParams fmParams; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + if(p_FmPort->pcdEngines) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Trying to free a port with PCD. FM_PORT_DeletePCD must be called first.")); + + if (p_FmPort->enabled) + { + if (FM_PORT_Disable(p_FmPort) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM_PORT_Disable FAILED")); + } + + if (p_FmPort->h_Spinlock) + XX_FreeSpinlock(p_FmPort->h_Spinlock); + + FmPortDriverParamFree(p_FmPort); + + if (p_FmPort->imEn) + FmPortImFree(p_FmPort); + + fmParams.hardwarePortId = p_FmPort->hardwarePortId; + fmParams.portType = (e_FmPortType)p_FmPort->portType; +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + fmParams.deqPipelineDepth = p_FmPort->txFifoDeqPipelineDepth; +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + + FmFreePortParams(p_FmPort->h_Fm, &fmParams); + + XX_Free(p_FmPort); + + return E_OK; +} + + +/*************************************************/ +/* API Advanced Init unit functions */ +/*************************************************/ + +t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->deqHighPriority = highPri; + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->deqType = deqType; + + return E_OK; +} + +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT +t_Error FM_PORT_ConfigDeqPrefetchOption(t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("not available for Rx ports")); + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = deqPrefetchOption; + return E_OK; +} +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ + +t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, t_FmPortBackupBmPools *p_BackupBmPools) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; +#ifdef FM_NO_BACKUP_POOLS + t_FmRevisionInfo revInfo; +#endif /* FM_NO_BACKUP_POOLS */ + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + +#ifdef FM_NO_BACKUP_POOLS + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev != 4) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("FM_PORT_ConfigBackupPools")); +#endif /* FM_NO_BACKUP_POOLS */ + + p_FmPort->p_FmPortDriverParam->p_BackupBmPools = (t_FmPortBackupBmPools *)XX_Malloc(sizeof(t_FmPortBackupBmPools)); + if(!p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed")); + memcpy(p_FmPort->p_FmPortDriverParam->p_BackupBmPools, p_BackupBmPools, sizeof(t_FmPortBackupBmPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->deqByteCnt = deqByteCnt; + + return E_OK; +} + +t_Error FM_PORT_ConfigBufferPrefixContent(t_Handle h_FmPort, t_FmPortBufferPrefixContent *p_FmPortBufferPrefixContent) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + memcpy(&p_FmPort->p_FmPortDriverParam->bufferPrefixContent, p_FmPortBufferPrefixContent, sizeof(t_FmPortBufferPrefixContent)); + /* if dataAlign was not initialized by user, we return to driver's deafult */ + if (!p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign) + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = DEFAULT_PORT_bufferPrefixContent_dataAlign; + + return E_OK; +} + +t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, uint8_t cheksumLastBytesIgnore) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx & Tx ports only")); + + p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = cheksumLastBytesIgnore; + + return E_OK; +} + +t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, uint8_t cutBytesFromEnd) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->cutBytesFromEnd = cutBytesFromEnd; + + return E_OK; +} + +t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, t_FmPortBufPoolDepletion *p_BufPoolDepletion) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; + memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, p_BufPoolDepletion, sizeof(t_FmPortBufPoolDepletion)); + + return E_OK; +} + +t_Error FM_PORT_ConfigObservedPoolDepletion(t_Handle h_FmPort, t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if(p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for OP ports only")); + + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; + memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, &p_FmPortObservedBufPoolDepletion->poolDepletionParams, sizeof(t_FmPortBufPoolDepletion)); + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, &p_FmPortObservedBufPoolDepletion->poolsParams, sizeof(t_FmPortExtPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmPortExtPools *p_FmPortExtPools) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if(p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for OP ports only")); + + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, p_FmPortExtPools, sizeof(t_FmPortExtPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->rxFifoThreshold = fifoThreshold; + + return E_OK; +} + +t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, uint32_t priElevationLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->rxFifoPriElevationLevel = priElevationLevel; + + return E_OK; +} + +t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, uint32_t minFillLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->txFifoMinFillLevel = minFillLevel; + + return E_OK; +} + +t_Error FM_PORT_ConfigTxFifoDeqPipelineDepth(t_Handle h_FmPort, uint8_t deqPipelineDepth) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Tx ports only")); + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Not available for IM ports!")); + + p_FmPort->txFifoDeqPipelineDepth = deqPipelineDepth; + + return E_OK; +} + +t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, uint32_t fifoLowComfLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->txFifoLowComfLevel = fifoLowComfLevel; + + return E_OK; +} + +t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->dontReleaseBuf = TRUE; + + return E_OK; +} + +t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); +#ifdef FM_OP_PORT_QMAN_REJECT_ERRATA_FMAN21 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("FM_PORT_ConfigDfltColor!")); + } +#endif /* FM_OP_PORT_QMAN_REJECT_ERRATA_FMAN21 */ + p_FmPort->p_FmPortDriverParam->color = color; + + return E_OK; +} + +t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); +#ifdef FM_PORT_SYNC_ERRATA_FMAN6 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("port-sync!")); + } +#endif /* FM_PORT_SYNC_ERRATA_FMAN6 */ + + p_FmPort->p_FmPortDriverParam->syncReq = syncReq; + + return E_OK; +} + + +t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) && (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->frmDiscardOverride = override; + + return E_OK; +} + +t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, fmPortFrameErrSelect_t errs) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + + p_FmPort->p_FmPortDriverParam->errorsToDiscard = errs; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmPortDmaSwap swapData) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dmaSwapData = swapData; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, e_FmPortDmaCache intContextCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dmaIntContextCacheAttr = intContextCacheAttr; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, e_FmPortDmaCache headerCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dmaHeaderCacheAttr = headerCacheAttr; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaScatterGatherAttr(t_Handle h_FmPort, e_FmPortDmaCache scatterGatherCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dmaScatterGatherCacheAttr = scatterGatherCacheAttr; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->dmaWriteOptimize = optimize; + + return E_OK; +} + +t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, bool forwardReuse) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = forwardReuse; + + return E_OK; +} + + +/****************************************************/ +/* PCD Advaced config API */ +/****************************************************/ + +/****************************************************/ +/* API Run-time Control unit functions */ +/****************************************************/ + +t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfOpenDmas) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + +#ifdef FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0) && + (p_NumOfOpenDmas->extra)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("excessive resources")); + } +#endif /* FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 */ + + if((!p_NumOfOpenDmas->num) || (p_NumOfOpenDmas->num > MAX_NUM_OF_DMAS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("openDmas-num can't be larger than %d", MAX_NUM_OF_DMAS)); + if(p_NumOfOpenDmas->extra > MAX_NUM_OF_EXTRA_DMAS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("openDmas-extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); + err = FmSetNumOfOpenDmas(p_FmPort->h_Fm, p_FmPort->hardwarePortId, (uint8_t)p_NumOfOpenDmas->num, (uint8_t)p_NumOfOpenDmas->extra, FALSE); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + + memcpy(&p_FmPort->openDmas, p_NumOfOpenDmas, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("not available for host command port where number is always 1")); + +#ifdef FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0) && + (p_NumOfTasks->extra)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("excessive resources")); + } +#endif /* FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 */ + + if((!p_NumOfTasks->num) || (p_NumOfTasks->num > MAX_NUM_OF_TASKS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("NumOfTasks-num can't be larger than %d", MAX_NUM_OF_TASKS)); + if(p_NumOfTasks->extra > MAX_NUM_OF_EXTRA_TASKS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("NumOfTasks-extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); + + err = FmSetNumOfTasks(p_FmPort->h_Fm, p_FmPort->hardwarePortId, (uint8_t)p_NumOfTasks->num, (uint8_t)p_NumOfTasks->extra, FALSE); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* update driver's struct */ + memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc)); + return E_OK; +} + +t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + t_FmInterModulePortRxPoolsParams rxPoolsParams; + uint32_t minFifoSizeRequired; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + +#ifdef FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0) && + (p_SizeOfFifo->extra)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("excessive resources")); + } +#endif /* FM_PORT_EXCESSIVE_BUDGET_ERRATA_FMANx16 */ + if(!p_SizeOfFifo->num || (p_SizeOfFifo->num > BMI_MAX_FIFO_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SizeOfFifo-num has to be in the range of 256 - %d", BMI_MAX_FIFO_SIZE)); + if(p_SizeOfFifo->num % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SizeOfFifo-num has to be divisible by %d", BMI_FIFO_UNITS)); + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* extra FIFO size (allowed only to Rx ports) */ + if(p_SizeOfFifo->extra % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SizeOfFifo-extra has to be divisible by %d", BMI_FIFO_UNITS)); + } + else + if(p_SizeOfFifo->extra) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" No SizeOfFifo-extra for non Rx ports")); + + /* For O/H ports, check fifo size and update if necessary */ + if((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { + minFifoSizeRequired = (uint32_t)((p_FmPort->txFifoDeqPipelineDepth+4)*BMI_FIFO_UNITS); + if (p_FmPort->fifoBufs.num < minFifoSizeRequired) + { + p_FmPort->fifoBufs.num = minFifoSizeRequired; + DBG(INFO, ("FIFO size enlarged to %d", minFifoSizeRequired)); + } + } + memcpy(&rxPoolsParams, &p_FmPort->rxPoolsParams, sizeof(rxPoolsParams)); + err = FmSetSizeOfFifo(p_FmPort->h_Fm, + p_FmPort->hardwarePortId, + p_FmPort->portType, + p_FmPort->imEn, + &p_SizeOfFifo->num, + p_SizeOfFifo->extra, + p_FmPort->txFifoDeqPipelineDepth, + &rxPoolsParams, + FALSE); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* update driver's structure AFTER the FM routine, as it may change by the FM. */ + memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, 0); + + return p_FmPort->bufferOffsets.dataOffset; +} + +uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, 0); + + if(p_FmPort->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.pcdInfoOffset); +} + +#ifdef DEBUG +uint8_t * FM_PORT_GetBufferDebugInfo(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, 0); + + if(p_FmPort->bufferOffsets.debugOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.debugOffset); +} +#endif /* DEBUG */ + +t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, NULL); + + if(p_FmPort->bufferOffsets.prsResultOffset == ILLEGAL_BASE) + return NULL; + + return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.prsResultOffset); +} + +uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, NULL); + + if(p_FmPort->bufferOffsets.timeStampOffset == ILLEGAL_BASE) + return NULL; + + return (uint64_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.timeStampOffset); +} + +uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, 0); + + if(p_FmPort->bufferOffsets.hashResultOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.hashResultOffset); +} + +t_Error FM_PORT_Disable(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + volatile uint32_t *p_BmiStatusReg = NULL; + bool rxPort = FALSE; + int tries; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg; + p_BmiStatusReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rst; + rxPort = TRUE; + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg; + p_BmiStatusReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tst; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ocfg; + p_BmiStatusReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ost; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + /* check if port is already disabled */ + if(!(GET_UINT32(*p_BmiCfgReg) & BMI_PORT_CFG_EN)) + { + if (!rxPort && !p_FmPort->imEn) + { + if(!(GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc)& QMI_PORT_CFG_EN)) + /* port is disabled */ + return E_OK; + else + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Inconsistency: Port's QMI is enabled but BMI disabled")); + } + /* port is disabled */ + return E_OK; + } + + /* Disable QMI */ + if (!rxPort && !p_FmPort->imEn) + { + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc, + GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc) & ~QMI_PORT_CFG_EN); + /* wait for QMI to finish Handling dequeue tnums */ + tries=1000; + while ((GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pns) & QMI_PORT_STATUS_DEQ_FD_BSY) && + --tries) + XX_UDelay(1); + if (!tries) + RETURN_ERROR(MINOR, E_BUSY, ("%s: can't disable!", p_FmPort->name)); + } + + /* Disable BMI */ + WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) & ~BMI_PORT_CFG_EN); + + if (p_FmPort->imEn) + FmPortImDisable(p_FmPort); + + tries=5000; + while ((GET_UINT32(*p_BmiStatusReg) & BMI_PORT_STATUS_BSY) && + --tries) + XX_UDelay(1); + + if (!tries) + RETURN_ERROR(MINOR, E_BUSY, ("%s: can't disable!", p_FmPort->name)); + + p_FmPort->enabled = 0; + + return E_OK; +} + +t_Error FM_PORT_Enable(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + bool rxPort = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg; + rxPort = TRUE; + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_BmiCfgReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ocfg; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + /* check if port is already enabled */ + if(GET_UINT32(*p_BmiCfgReg) & BMI_PORT_CFG_EN) + { + if (!rxPort && !p_FmPort->imEn) + { + if(GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc)& QMI_PORT_CFG_EN) + /* port is enabled */ + return E_OK; + else + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Inconsistency: Port's BMI is enabled but QMI disabled")); + } + /* port is enabled */ + return E_OK; + } + + if (p_FmPort->imEn) + FmPortImEnable(p_FmPort); + + /* Enable QMI */ + if (!rxPort && !p_FmPort->imEn) + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc, + GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc) | QMI_PORT_CFG_EN); + + /* Enable BMI */ + WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) | BMI_PORT_CFG_EN); + + p_FmPort->enabled = 1; + + return E_OK; +} + +t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpRateLimit, tmpRateLimitScale; + volatile uint32_t *p_RateLimitReg, *p_RateLimitScaleReg; + uint8_t factor, countUnitBit; + uint16_t baseGran; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Tx and Offline parsing ports only")); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + p_RateLimitReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_trlmt; + p_RateLimitScaleReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_trlmts; + baseGran = 16000; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_RateLimitReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_orlmt; + p_RateLimitScaleReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_orlmts; + baseGran = 10000; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + countUnitBit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); /* TimeStamp per nano seconds units */ + /* normally, we use 1 usec as the reference count */ + factor = 1; + /* if ratelimit is too small for a 1usec factor, multiply the factor */ + while (p_RateLimit->rateLimit < baseGran/factor) + { + if (countUnitBit==31) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too small")); + + countUnitBit++; + factor <<= 1; + } + /* if ratelimit is too large for a 1usec factor, it is also larger than max rate*/ + if (p_RateLimit->rateLimit > ((uint32_t)baseGran * (1<<10) * (uint32_t)factor)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too large")); + + tmpRateLimit = (uint32_t)(p_RateLimit->rateLimit*factor/baseGran - 1); + + if(!p_RateLimit->maxBurstSize || (p_RateLimit->maxBurstSize > MAX_BURST_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxBurstSize must be between 1K and %dk", MAX_BURST_SIZE)); + + tmpRateLimitScale = ((31 - (uint32_t)countUnitBit) << BMI_COUNT_RATE_UNIT_SHIFT) | BMI_RATE_LIMIT_EN; + + if(p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + tmpRateLimit |= (uint32_t)(p_RateLimit->maxBurstSize - 1) << BMI_MAX_BURST_SHIFT; + else + { +#ifndef FM_NO_ADVANCED_RATE_LIMITER + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev == 4) + { + switch(p_RateLimit->rateLimitDivider) + { + case(e_FM_PORT_DUAL_RATE_LIMITER_NONE): + break; + case(e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2): + tmpRateLimitScale |= BMI_RATE_LIMIT_SCALE_BY_2; + break; + case(e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4): + tmpRateLimitScale |= BMI_RATE_LIMIT_SCALE_BY_4; + break; + case(e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8): + tmpRateLimitScale |= BMI_RATE_LIMIT_SCALE_BY_8; + break; + default: + break; + } + tmpRateLimit |= BMI_RATE_LIMIT_BURST_SIZE_GRAN; + } + else +#endif /* ! FM_NO_ADVANCED_RATE_LIMITER */ + { + if(p_RateLimit->rateLimitDivider != e_FM_PORT_DUAL_RATE_LIMITER_NONE) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("FM_PORT_ConfigDualRateLimitScaleDown")); + + if(p_RateLimit->maxBurstSize % 1000) + { + p_RateLimit->maxBurstSize = (uint16_t)((p_RateLimit->maxBurstSize/1000)+1); + DBG(WARNING, ("rateLimit.maxBurstSize rounded up to %d", (p_RateLimit->maxBurstSize/1000+1)*1000)); + } + else + p_RateLimit->maxBurstSize = (uint16_t)(p_RateLimit->maxBurstSize/1000); + } + tmpRateLimit |= (uint32_t)(p_RateLimit->maxBurstSize - 1) << BMI_MAX_BURST_SHIFT; + + } + WRITE_UINT32(*p_RateLimitScaleReg, tmpRateLimitScale); + WRITE_UINT32(*p_RateLimitReg, tmpRateLimit); + + return E_OK; +} + +t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_RateLimitReg, *p_RateLimitScaleReg; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Tx and Offline parsing ports only")); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + p_RateLimitReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_trlmt; + p_RateLimitScaleReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_trlmts; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_RateLimitReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_orlmt; + p_RateLimitScaleReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_orlmts; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + WRITE_UINT32(*p_RateLimitScaleReg, 0); + WRITE_UINT32(*p_RateLimitReg, 0); + + return E_OK; +} + + +t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + tmpReg = GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc); + if(enable) + tmpReg |= QMI_PORT_CFG_EN_COUNTERS ; + else + tmpReg &= ~QMI_PORT_CFG_EN_COUNTERS; + + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc, tmpReg); + + return E_OK; +} + +t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiPcReg = NULL; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiPcReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpc; + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + p_BmiPcReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpc; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_BmiPcReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opc; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if(enable) + WRITE_UINT32(*p_BmiPcReg, BMI_COUNTERS_EN); + else + WRITE_UINT32(*p_BmiPcReg, 0); + + return E_OK; +} + +t_Error FM_PORT_SetPerformanceCountersParams(t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpReg; + volatile uint32_t *p_BmiPcpReg = NULL; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiPcpReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpcp; + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + p_BmiPcpReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpcp; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_BmiPcpReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opcp; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + /* check parameters */ + if (!p_FmPortPerformanceCnt->taskCompVal || + (p_FmPortPerformanceCnt->taskCompVal > p_FmPort->tasks.num)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("performanceCnt.taskCompVal has to be in the range of 1 - %d (current value)!", + p_FmPort->tasks.num)); + if (!p_FmPortPerformanceCnt->dmaCompVal || + (p_FmPortPerformanceCnt->dmaCompVal > p_FmPort->openDmas.num)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("performanceCnt.dmaCompVal has to be in the range of 1 - %d (current value)!", + p_FmPort->openDmas.num)); + if (!p_FmPortPerformanceCnt->fifoCompVal || + (p_FmPortPerformanceCnt->fifoCompVal > p_FmPort->fifoBufs.num)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("performanceCnt.fifoCompVal has to be in the range of 256 - %d (current value)!", + p_FmPort->fifoBufs.num)); + if (p_FmPortPerformanceCnt->fifoCompVal % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("performanceCnt.fifoCompVal has to be divisible by %d", + BMI_FIFO_UNITS)); + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + if (!p_FmPortPerformanceCnt->queueCompVal || + (p_FmPortPerformanceCnt->queueCompVal > MAX_PERFORMANCE_RX_QUEUE_COMP)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("performanceCnt.queueCompVal for Rx has to be in the range of 1 - %d", + MAX_PERFORMANCE_RX_QUEUE_COMP)); + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + if (!p_FmPortPerformanceCnt->queueCompVal || + (p_FmPortPerformanceCnt->queueCompVal > MAX_PERFORMANCE_TX_QUEUE_COMP)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("performanceCnt.queueCompVal for Tx has to be in the range of 1 - %d", + MAX_PERFORMANCE_TX_QUEUE_COMP)); + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + if (p_FmPortPerformanceCnt->queueCompVal) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("performanceCnt.queueCompVal is not relevant for H/O ports.")); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + tmpReg = 0; + tmpReg |= ((uint32_t)(p_FmPortPerformanceCnt->queueCompVal - 1) << BMI_PERFORMANCE_PORT_COMP_SHIFT); + tmpReg |= ((uint32_t)(p_FmPortPerformanceCnt->dmaCompVal- 1) << BMI_PERFORMANCE_DMA_COMP_SHIFT); + tmpReg |= ((uint32_t)(p_FmPortPerformanceCnt->fifoCompVal/BMI_FIFO_UNITS - 1) << BMI_PERFORMANCE_FIFO_COMP_SHIFT); + if ((p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && (p_FmPort->portType != e_FM_PORT_TYPE_OH_HOST_COMMAND)) + tmpReg |= ((uint32_t)(p_FmPortPerformanceCnt->taskCompVal - 1) << BMI_PERFORMANCE_TASK_COMP_SHIFT); + + WRITE_UINT32(*p_BmiPcpReg, tmpReg); + + return E_OK; +} + +t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPortPerformanceCnt currParams, savedParams; + t_Error err; + bool underTest, failed = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + XX_Print("Analyzing Performance parameters for port (type %d, id%d)\n", + p_FmPort->portType, p_FmPort->portId); + + currParams.taskCompVal = (uint8_t)p_FmPort->tasks.num; + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || + (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + currParams.queueCompVal = 0; + else + currParams.queueCompVal = 1; + currParams.dmaCompVal =(uint8_t) p_FmPort->openDmas.num; + currParams.fifoCompVal = p_FmPort->fifoBufs.num; + + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + ClearPerfCnts(p_FmPort); + if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); + XX_UDelay(1000000); + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) + { + XX_Print ("Max num of defined port tasks (%d) utilized - Please enlarge\n",p_FmPort->tasks.num); + failed = TRUE; + } + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) + { + XX_Print ("Max num of defined port openDmas (%d) utilized - Please enlarge\n",p_FmPort->openDmas.num); + failed = TRUE; + } + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) + { + XX_Print ("Max size of defined port fifo (%d) utilized - Please enlarge\n",p_FmPort->fifoBufs.num*BMI_FIFO_UNITS); + failed = TRUE; + } + if (failed) + RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + + memset(&savedParams, 0, sizeof(savedParams)); + while (TRUE) + { + underTest = FALSE; + if ((currParams.taskCompVal != 1) && !savedParams.taskCompVal) + { + currParams.taskCompVal--; + underTest = TRUE; + } + if ((currParams.dmaCompVal != 1) && !savedParams.dmaCompVal) + { + currParams.dmaCompVal--; + underTest = TRUE; + } + if ((currParams.fifoCompVal != BMI_FIFO_UNITS) && !savedParams.fifoCompVal) + { + currParams.fifoCompVal -= BMI_FIFO_UNITS; + underTest = TRUE; + } + if (!underTest) + break; + + ClearPerfCnts(p_FmPort); + if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); + XX_UDelay(1000000); + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + + if (!savedParams.taskCompVal && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) + savedParams.taskCompVal = (uint8_t)(currParams.taskCompVal+2); + if (!savedParams.dmaCompVal && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) + savedParams.dmaCompVal = (uint8_t)(currParams.dmaCompVal+2); + if (!savedParams.fifoCompVal && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) + savedParams.fifoCompVal = currParams.fifoCompVal+2; + } + + XX_Print("best vals: tasks %d, dmas %d, fifos %d\n", + savedParams.taskCompVal, savedParams.dmaCompVal, savedParams.fifoCompVal); + return E_OK; +} + +t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpReg; + volatile uint32_t *p_BmiStcReg = NULL; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiStcReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rstc; + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + p_BmiStcReg = &p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tstc; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_BmiStcReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ostc; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + tmpReg = GET_UINT32(*p_BmiStcReg); + + if(enable) + tmpReg |= BMI_COUNTERS_EN; + else + tmpReg &= ~BMI_COUNTERS_EN; + + WRITE_UINT32(*p_BmiStcReg, tmpReg); + + return E_OK; +} + +t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_ErrQReg, *p_ErrDiscard; + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_ErrQReg = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsem; + p_ErrDiscard = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_ErrQReg = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsem; + p_ErrDiscard = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + } + + if (GET_UINT32(*p_ErrDiscard) & errs) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Selectd Errors that were configured to cause frame discard.")); + + WRITE_UINT32(*p_ErrQReg, errs); + + return E_OK; +} + +t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpReg; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(poolIdp_FmPortDriverParam, E_INVALID_STATE); + + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + + for(i=0 ; i< FM_PORT_MAX_NUM_OF_EXT_POOLS ; i++) + { + tmpReg = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_ebmpi[i]); + if ((uint8_t)((tmpReg & BMI_EXT_BUF_POOL_ID_MASK) >> BMI_EXT_BUF_POOL_ID_SHIFT) == poolId) + { + if(enable) + tmpReg |= BMI_EXT_BUF_POOL_EN_COUNTER; + else + tmpReg &= ~BMI_EXT_BUF_POOL_EN_COUNTER; + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_ebmpi[i], tmpReg); + break; + } + } + if (i == FM_PORT_MAX_NUM_OF_EXT_POOLS) + RETURN_ERROR(MINOR, E_INVALID_VALUE,("poolId %d is not included in this ports pools", poolId)); + + return E_OK; +} + +uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters counter) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool bmiCounter = FALSE; + volatile uint32_t *p_Reg; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch(counter) + { + case(e_FM_PORT_COUNTERS_DEQ_TOTAL): + case(e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + case(e_FM_PORT_COUNTERS_DEQ_CONFIRM ): + /* check that counter is available for the port type */ + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for Rx ports")); + return 0; + } + bmiCounter = FALSE; + case(e_FM_PORT_COUNTERS_ENQ_TOTAL): + bmiCounter = FALSE; + break; + default: /* BMI counters (or error - will be checked in BMI routine )*/ + bmiCounter = TRUE; + break; + } + + if(bmiCounter) + { + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + if(BmiRxPortCheckAndGetCounterPtr(p_FmPort, counter, &p_Reg)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return 0; + } + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + if(BmiTxPortCheckAndGetCounterPtr(p_FmPort, counter, &p_Reg)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return 0; + } + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + if(BmiOhPortCheckAndGetCounterPtr(p_FmPort, counter, &p_Reg)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + return 0; + } + break; + default: + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Unsupported port type")); + return 0; + } + return GET_UINT32(*p_Reg); + } + else /* QMI counter */ + { + + /* check that counters are enabled */ + if(!(GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc) & QMI_PORT_CFG_EN_COUNTERS)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + return 0; + } + + /* Set counter */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_ENQ_TOTAL): + return GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnetfc); + case(e_FM_PORT_COUNTERS_DEQ_TOTAL): + return GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndtfc); + case(e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + return GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndfdc); + case(e_FM_PORT_COUNTERS_DEQ_CONFIRM): + return GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndcc); + default: + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available")); + return 0; + } + } + + return 0; +} + +t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters counter, uint32_t value) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool bmiCounter = FALSE; + volatile uint32_t *p_Reg; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch(counter) + { + case(e_FM_PORT_COUNTERS_DEQ_TOTAL): + case(e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + case(e_FM_PORT_COUNTERS_DEQ_CONFIRM ): + /* check that counter is available for the port type */ + if((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for Rx ports")); + case(e_FM_PORT_COUNTERS_ENQ_TOTAL): + bmiCounter = FALSE; + break; + default: /* BMI counters (or error - will be checked in BMI routine )*/ + bmiCounter = TRUE; + break; + } + + if(bmiCounter) + { + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + if(BmiRxPortCheckAndGetCounterPtr(p_FmPort, counter, &p_Reg)) + RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + break; + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + if(BmiTxPortCheckAndGetCounterPtr(p_FmPort, counter, &p_Reg)) + RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + if(BmiOhPortCheckAndGetCounterPtr(p_FmPort, counter, &p_Reg)) + RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported port type")); + } + WRITE_UINT32(*p_Reg, value); + } + else /* QMI counter */ + { + + /* check that counters are enabled */ + if(!(GET_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnc) & QMI_PORT_CFG_EN_COUNTERS)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + + /* Set counter */ + switch(counter) + { + case(e_FM_PORT_COUNTERS_ENQ_TOTAL): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnetfc, value); + break; + case(e_FM_PORT_COUNTERS_DEQ_TOTAL): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndtfc, value); + break; + case(e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndfdc, value); + break; + case(e_FM_PORT_COUNTERS_DEQ_CONFIRM): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndcc, value); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available")); + } + } + + return E_OK; +} + +uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t extPoolReg; + uint8_t tmpPool; + uint8_t i; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if((p_FmPort->portType != e_FM_PORT_TYPE_RX) && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for non-Rx ports")); + return 0; + } + + for(i=0;ip_FmPortBmiRegs->rxPortBmiRegs.fmbm_ebmpi[i]); + if (extPoolReg & BMI_EXT_BUF_POOL_VALID) + { + tmpPool = (uint8_t)((extPoolReg & BMI_EXT_BUF_POOL_ID_MASK) >> BMI_EXT_BUF_POOL_ID_SHIFT); + if(tmpPool == poolId) + { + if(extPoolReg & BMI_EXT_BUF_POOL_EN_COUNTER) + return GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_acnt[i]); + else + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not enabled")); + return 0; + } + } + } + } + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Pool %d is not used", poolId)); + return 0; +} + +t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, uint32_t value) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPort; + uint32_t extPoolReg; + uint8_t tmpPool; + uint8_t i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if((p_FmPort->portType != e_FM_PORT_TYPE_RX) && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for non-Rx ports")); + + + for(i=0;ip_FmPortBmiRegs->rxPortBmiRegs.fmbm_ebmpi[i]); + if (extPoolReg & BMI_EXT_BUF_POOL_VALID) + { + tmpPool = (uint8_t)((extPoolReg & BMI_EXT_BUF_POOL_ID_MASK) >> BMI_EXT_BUF_POOL_ID_SHIFT); + if(tmpPool == poolId) + { + if(extPoolReg & BMI_EXT_BUF_POOL_EN_COUNTER) + { + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_acnt[i], value); + return E_OK; + } + else + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not enabled")); + } + } + } + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Pool %d is not used", poolId)); +} + +bool FM_PORT_IsStalled(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + bool isStalled; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, FALSE); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, FALSE); + + err = FmIsPortStalled(p_FmPort->h_Fm, p_FmPort->hardwarePortId, &isStalled); + if(err != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return TRUE; + } + return isStalled; +} + +t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + return FmResumeStalledPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId); +} + +t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx ports only")); + + tmpReg = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); + if (l4Checksum) + tmpReg &= ~BMI_PORT_RFNE_FRWD_DCL4C; + else + tmpReg |= BMI_PORT_RFNE_FRWD_DCL4C; + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, tmpReg); + + return E_OK; +} + + +/* API Run-time PCD Control unit functions */ + +t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); + ASSERT_COND(p_FmPort->h_FmPcd); + + if(numOfProfiles) + { + err = FmPcdPlcrAllocProfiles(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId, numOfProfiles); + if(err) + RETURN_ERROR(MAJOR, err,NO_MSG); + } + FmPcdPortRegister(p_FmPort->h_FmPcd, h_FmPort, p_FmPort->hardwarePortId); + + return E_OK; +} + +t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + err = FmPcdPlcrFreeProfiles(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId); + if(err) + RETURN_ERROR(MAJOR, err,NO_MSG); + return E_OK; +} + +t_Error FM_PORT_PcdKgModifyInitialScheme (t_Handle h_FmPort, t_FmPcdKgSchemeSelect *p_FmPcdKgScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiHpnia = NULL; + uint32_t tmpReg; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG , E_INVALID_STATE); + + tmpReg = (uint32_t)((p_FmPort->pcdEngines & FM_PCD_CC)? NIA_KG_CC_EN:0); + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiHpnia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiHpnia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofpne; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + /* if we want to change to direct scheme, we need to check that this scheme is valid */ + if(p_FmPcdKgScheme->direct) + { + physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_FmPcdKgScheme->h_DirectScheme)-1); + /* check that this scheme is bound to this port */ + if(!(p_FmPort->schemesPerPortVector & (uint32_t)(1 << (31 - (uint32_t)physicalSchemeId)))) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("called with a scheme that is not bound to this port")); + } + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPort->h_FmPcd, physicalSchemeId); + if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("called with invalid Scheme ")); + } + + if(!FmPcdKgIsSchemeValidSw(p_FmPort->h_FmPcd, relativeSchemeId)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("called with uninitialized Scheme ")); + } + + WRITE_UINT32(*p_BmiHpnia, NIA_ENG_KG | tmpReg | NIA_KG_DIRECT | (uint32_t)physicalSchemeId); + } + else /* change to indirect scheme */ + WRITE_UINT32(*p_BmiHpnia, NIA_ENG_KG | tmpReg); + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_PcdPlcrModifyInitialProfile (t_Handle h_FmPort, t_Handle h_Profile) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiNia; + volatile uint32_t *p_BmiHpnia; + uint32_t tmpReg; + uint16_t absoluteProfileId = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_PLCR , E_INVALID_STATE); + + /* check relevancy of this routine - only when policer is used + directly after BMI or Parser */ + if((p_FmPort->pcdEngines & FM_PCD_KG) || (p_FmPort->pcdEngines & FM_PCD_CC)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("relevant only when PCD support mode is e_FM_PCD_SUPPORT_PLCR_ONLY or e_FM_PCD_SUPPORT_PRS_AND_PLCR")); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne; + p_BmiHpnia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne; + tmpReg = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofne; + p_BmiHpnia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofpne; + tmpReg = 0; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + if(!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Invalid profile")); + } + + tmpReg = (uint32_t)(NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId); + + if(p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ + { + /* update BMI HPNIA */ + WRITE_UINT32(*p_BmiHpnia, tmpReg); + } + else /* e_FM_PCD_SUPPORT_PLCR_ONLY */ + { + /* rfne may contain FDCS bits, so first we read them. */ + tmpReg |= (GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK); + /* update BMI NIA */ + WRITE_UINT32(*p_BmiNia, tmpReg); + } + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + + +t_Error FM_PORT_PcdCcModifyTree (t_Handle h_FmPort, t_Handle h_CcTree) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + volatile uint32_t *p_BmiCcBase=NULL; + volatile uint32_t *p_BmiNia=NULL; + uint32_t ccTreePhysOffset; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_VALUE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for non-independant mode ports only")); + + /* get PCD registers pointers */ + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofne; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + } + + /* check that current NIA is BMI to BMI */ + if((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) != (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("may be called only for ports in BMI-to-BMI state.")); + +/*TODO - to take care of changes due to previous tree. Maybe in the previous tree where chnged pndn, pnen ... + it has to be returned to the default state - initially*/ + + p_FmPort->requiredAction = 0; + + if(p_FmPort->pcdEngines & FM_PCD_CC) + { + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiCcBase = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rccb; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiCcBase = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_occb; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + err = FmPcdCcBindTree(p_FmPort->h_FmPcd, h_CcTree, &ccTreePhysOffset, h_FmPort); + if(err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MINOR, err, NO_MSG); + } + WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); + + p_FmPort->ccTreeId = h_CcTree; + RELEASE_LOCK(p_FmPort->lock); + } + else + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Coarse CLassification not defined for this port.")); + + return E_OK; +} + +t_Error FM_PORT_AttachPCD(t_Handle h_FmPort) +{ + + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for non-independant mode ports only")); + + /* TODO - may add here checks for: + SP (or in sw: schemes) + CPP (or in sw clsPlan) + Parser enabled and configured(?) + Tree(?) + Profile - only if direct. + Scheme - only if direct + */ + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + err = FmPortAttachPCD(h_FmPort); + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_DetachPCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiNia=NULL; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for non-independant mode ports only")); + + /* get PCD registers pointers */ + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofne; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + } + + WRITE_UINT32(*p_BmiNia, (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); + +/*TODO - not atomic - it seems that port has to be disabled*/ + if(p_FmPort->requiredAction & UPDATE_NIA_PNEN) + { + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); + break; + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case(e_FM_PORT_TYPE_RX): + case(e_FM_PORT_TYPE_RX_10G): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, NIA_ENG_BMI | NIA_BMI_AC_RELEASE); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Can not reach this stage")); + } + } + + if(p_FmPort->requiredAction & UPDATE_NIA_PNDN) + { + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_TX_10G): + case(e_FM_PORT_TYPE_TX): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, NIA_ENG_BMI | NIA_BMI_AC_TX); + break; + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, NIA_ENG_BMI | NIA_BMI_AC_FETCH); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Can not reach this stage")); + } + } + + + if(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if(FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 2)!= E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + return E_OK; +} + +t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_PcdParams) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + uint8_t i; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for non-independent mode ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); + ASSERT_COND(p_FmPort->h_FmPcd); + + err = SetPcd( h_FmPort, p_PcdParams); + if(err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if(p_FmPort->pcdEngines & FM_PCD_KG) + { + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PcdParams->p_KgParams->numOfSchemes; + schemeBind.useClsPlan = p_FmPort->useClsPlan; + for(i = 0;ip_KgParams->h_Schemes[i])-1); + + err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if(err) + { + DeletePcd(p_FmPort); + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + if ((p_FmPort->pcdEngines & FM_PCD_PRS) && (p_PcdParams->p_PrsParams->includeInPrsStatistics)) + FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId, TRUE); + + FmPcdIncNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); + + err = FmPortAttachPCD(h_FmPort); + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_DeletePCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for non-independant mode ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + + err = FM_PORT_DetachPCD(h_FmPort); + if(err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + FmPcdDecNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); + + /* we do it anyway, instead of checking if included */ + if (FmIsMaster(p_FmPort->h_Fm) && + (p_FmPort->pcdEngines & FM_PCD_PRS)) + FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId, FALSE); + + if(p_FmPort->pcdEngines & FM_PCD_KG) + { + /* unbind all schemes */ + p_FmPort->schemesPerPortVector = GetPortSchemeBindParams(p_FmPort, &schemeBind); + + err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if(err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + err = DeletePcd(h_FmPort); + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_PcdKgBindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + uint32_t tmpScmVec=0; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG , E_INVALID_STATE); + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; + schemeBind.useClsPlan = p_FmPort->useClsPlan; + for (i=0; ih_Schemes[i])-1); + /* build vector */ + tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err == E_OK) + p_FmPort->schemesPerPortVector |= tmpScmVec; + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_PcdKgUnbindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + uint32_t tmpScmVec=0; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG , E_INVALID_STATE); + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; + for (i=0; ih_Schemes[i])-1); + /* build vector */ + tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err == E_OK) + p_FmPort->schemesPerPortVector &= ~tmpScmVec; + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_PcdPrsModifyStartOffset (t_Handle h_FmPort, t_FmPcdPrsStart *p_FmPcdPrsStart) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + volatile uint32_t *p_BmiNia = NULL; + uint32_t tmpReg; + uint8_t hdrNum; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_PRS , E_INVALID_STATE); + + switch(p_FmPort->portType) + { + case(e_FM_PORT_TYPE_RX_10G): + case(e_FM_PORT_TYPE_RX): + p_BmiPrsStartOffset = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpso; + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne; + tmpReg = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; + break; + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiPrsStartOffset = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opso; + p_BmiNia = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofne; + tmpReg = 0; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("available for Rx and offline parsing ports only")); + } + + /* check that current NIA is BMI to BMI */ + if((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) != (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("may be called only for ports in BMI-to-BMI state.")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + return ERROR_CODE(E_BUSY); + /* set the first header */ + GET_PRS_HDR_NUM(hdrNum, p_FmPcdPrsStart->firstPrsHdr); + if ((hdrNum == ILLEGAL_HDR_NUM) || (hdrNum == NO_HDR_NUM)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header.")); + } + WRITE_UINT32(*p_BmiNia, (uint32_t)(NIA_ENG_PRS | (uint32_t)hdrNum | tmpReg)); + + /* set start parsing offset */ + WRITE_UINT32(*p_BmiPrsStartOffset, (uint32_t)(p_FmPcdPrsStart->parsingOffset + p_FmPort->internalBufferOffset)); + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FM_PORT_DumpRegs(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + char arr[30]; + uint8_t flag; + int i=0; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortQmiRegs, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortBmiRegs, E_INVALID_HANDLE); + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + strcpy(arr, "PORT_TYPE_OFFLINE_PARSING"); + flag = 0; + break; + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + strcpy(arr, "PORT_TYPE_HOST_COMMAND"); + flag = 0; + break; + case (e_FM_PORT_TYPE_RX): + strcpy(arr, "PORT_TYPE_RX"); + flag = 1; + break; + case (e_FM_PORT_TYPE_RX_10G): + strcpy(arr, "PORT_TYPE_RX_10G"); + flag = 1; + break; + case (e_FM_PORT_TYPE_TX): + strcpy(arr, "PORT_TYPE_TX"); + flag = 2; + break; + case (e_FM_PORT_TYPE_TX_10G): + strcpy(arr, "PORT_TYPE_TX_10G"); + flag = 2; + break; + default: + return ERROR_CODE(E_INVALID_VALUE); + } + + DUMP_TITLE(UINT_TO_PTR(p_FmPort->hardwarePortId), ("PortId for %s %d", arr, p_FmPort->portId )); + DUMP_TITLE(p_FmPort->p_FmPortBmiRegs, ("Bmi Port Regs")); + + err = FmDumpPortRegs(p_FmPort->h_Fm, p_FmPort->hardwarePortId); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + switch(flag) + { + case(0): + + DUMP_SUBTITLE(("\n")); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ocfg); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ost); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_oda); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofdne); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofne); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofca); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofpne); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_opso); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_opp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_occb); + + DUMP_TITLE(&(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_oprai), ("fmbm_oprai")); + DUMP_SUBSTRUCT_ARRAY(i, FM_PORT_PRS_RESULT_NUM_OF_WORDS) + { + DUMP_MEMORY(&(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_oprai[i]), sizeof(uint32_t)); + } + DUMP_SUBTITLE(("\n")); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofqid ); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_oefqid); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofsdm ); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofsem ); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofene ); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_orlmts); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_orlmt); + + { +#ifndef FM_NO_OP_OBSERVED_POOLS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev == 4) +#endif /* !FM_NO_OP_OBSERVED_POOLS */ + { + DUMP_TITLE(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_oebmpi, ("fmbm_oebmpi")); + + DUMP_SUBSTRUCT_ARRAY(i, FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS) + { + DUMP_MEMORY(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_oebmpi[i], sizeof(uint32_t)); + } + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ocgm); + } + } + + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ostc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofrc ); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofdc ); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofledc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofufdc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_offc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofwdc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofldec); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_opc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_opcp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_occn); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_otuc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_oduc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs,fmbm_ofuc); + break; + case(1): + DUMP_SUBTITLE(("\n")); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rcfg); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rst); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rda); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_reth); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfed); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_ricp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rebm); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfne); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfca); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfpne); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rpso); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rpp); + + DUMP_TITLE(&(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rprai), ("fmbm_rprai")); + DUMP_SUBSTRUCT_ARRAY(i, FM_PORT_PRS_RESULT_NUM_OF_WORDS) + { + DUMP_MEMORY(&(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rprai[i]), sizeof(uint32_t)); + } + DUMP_SUBTITLE(("\n")); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfqid); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_refqid); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfsdm); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfsem); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfene); + DUMP_TITLE(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_ebmpi, ("fmbm_ebmpi")); + DUMP_SUBSTRUCT_ARRAY(i, FM_PORT_MAX_NUM_OF_EXT_POOLS) + { + DUMP_MEMORY(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_ebmpi[i], sizeof(uint32_t)); + } + DUMP_TITLE(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_acnt, ("fmbm_acnt")); + DUMP_SUBSTRUCT_ARRAY(i, FM_PORT_MAX_NUM_OF_EXT_POOLS) + { + DUMP_MEMORY(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_acnt[i], sizeof(uint32_t)); + } + DUMP_TITLE(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_cgm, ("fmbm_cgm")); + DUMP_SUBSTRUCT_ARRAY(i, FM_PORT_NUM_OF_CONGESTION_GRPS/32) + { + DUMP_MEMORY(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_cgm[i], sizeof(uint32_t)); + } + DUMP_SUBTITLE(("\n")); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_mpd); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rstc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfrc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfbc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rlfc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rffc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfcd); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfldec); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rodc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rpc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rpcp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rccn); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rtuc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rrquc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rduc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rfuc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rpac); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs,fmbm_rdbg); + break; + case(2): + + DUMP_SUBTITLE(("\n")); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tcfg); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tst); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tda); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfed); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_ticp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfne); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfca); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tcfqid); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfeqid); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfene); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_trlmts); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_trlmt); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tstc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfrc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfdc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfledc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfufdc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tpc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tpcp); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tccn); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_ttuc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_ttcquc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tduc); + DUMP_VAR(&p_FmPort->p_FmPortBmiRegs->txPortBmiRegs,fmbm_tfuc); + break; + + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid flag")); + } + + DUMP_TITLE(p_FmPort->p_FmPortQmiRegs, ("Qmi Port Regs")); + + DUMP_VAR(p_FmPort->p_FmPortQmiRegs,fmqm_pnc); + DUMP_VAR(p_FmPort->p_FmPortQmiRegs,fmqm_pns); + DUMP_VAR(p_FmPort->p_FmPortQmiRegs,fmqm_pnts); + DUMP_VAR(p_FmPort->p_FmPortQmiRegs,fmqm_pnen); + DUMP_VAR(p_FmPort->p_FmPortQmiRegs,fmqm_pnetfc); + + if(flag !=1) + { + DUMP_VAR(&p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs,fmqm_pndn); + DUMP_VAR(&p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs,fmqm_pndc); + DUMP_VAR(&p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs,fmqm_pndtfc); + DUMP_VAR(&p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs,fmqm_pndfdc); + DUMP_VAR(&p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs,fmqm_pndcc); + } + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + +t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool tmpArray[FM_PORT_NUM_OF_CONGESTION_GRPS], opPort; + int i; + uint8_t mod; + uint32_t tmpReg = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + { +#ifdef FM_NO_OP_OBSERVED_CGS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev != 4) + { + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); + } + else +#endif /* FM_NO_OP_OBSERVED_CGS */ + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx & OP ports only")); + } + + opPort = (bool)((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ? TRUE:FALSE); + + /* to minimize memory access (groups may belong to the same regsiter, and may + be out of order), we first collect all information into a 256 booleans array, + representing each possible group. */ + + memset(&tmpArray, 0, FM_PORT_NUM_OF_CONGESTION_GRPS*sizeof(bool)); + for(i=0;inumOfCongestionGrpsToConsider;i++) + tmpArray[p_CongestionGrps->congestionGrpsToConsider[i]] = TRUE; + + for(i=0;ip_FmPortBmiRegs->ohPortBmiRegs.fmbm_ocgm): + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_cgm[7-i/32]); + + /* set in the register, the bit representing the relevant congestion group. */ + if(tmpArray[i]) + tmpReg |= (0x00000001 << (uint32_t)mod); + + if (mod == 31) /* last in a 32 bunch of congestion groups - write the corresponding register */ + { + if(opPort) + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ocgm, tmpReg); + else + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_cgm[7-i/32], tmpReg); + } + } + + return E_OK; +} + +t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool tmpArray[FM_PORT_NUM_OF_CONGESTION_GRPS], opPort; + int i; + uint8_t mod; + uint32_t tmpReg = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + { +#ifdef FM_NO_OP_OBSERVED_CGS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev != 4) + { + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); + } + else +#endif /* FM_NO_OP_OBSERVED_CGS */ + if((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx & OP ports only")); + } + + opPort = (bool)((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ? TRUE:FALSE); + + /* to minimize memory access (groups may belong to the same regsiter, and may + be out of order), we first collect all information into a 256 booleans array, + representing each possible group. */ + memset(&tmpArray, 0, FM_PORT_NUM_OF_CONGESTION_GRPS*sizeof(bool)); + for(i=0;inumOfCongestionGrpsToConsider;i++) + tmpArray[p_CongestionGrps->congestionGrpsToConsider[i]] = TRUE; + + for(i=0;ip_FmPortBmiRegs->ohPortBmiRegs.fmbm_ocgm): + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_cgm[7-i/32]); + + /* set in the register, the bit representing the relevant congestion group. */ + if(tmpArray[i]) + tmpReg &= ~(0x00000001 << (uint32_t)mod); + + if (mod == 31) /* last in a 32 bunch of congestion groups - write the corresponding register */ + { + if(opPort) + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ocgm, tmpReg); + else + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_cgm[7-i/32], tmpReg); + } + } + + return E_OK; +} + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec_mii_acc.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec_mii_acc.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DTSEC_MII_ACC_H +#define __DTSEC_MII_ACC_H + +#include "std_ext.h" + + +/* MII Management Configuration Register */ +#define MIIMCFG_RESET_MGMT 0x80000000 +#define MIIMCFG_MGMT_CLOCK_SELECT 0x00000007 + +/* MII Management Command Register */ +#define MIIMCOM_READ_CYCLE 0x00000001 +#define MIIMCOM_SCAN_CYCLE 0x00000002 + +/* MII Management Address Register */ +#define MIIMADD_PHY_ADDR_SHIFT 8 + +/* MII Management Indicator Register */ +#define MIIMIND_BUSY 0x00000001 + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/*----------------------------------------------------*/ +/* MII Configuration Control Memory Map Registers */ +/*----------------------------------------------------*/ +typedef _Packed struct t_MiiAccessMemMap +{ + volatile uint32_t miimcfg; /* MII Mgmt:configuration */ + volatile uint32_t miimcom; /* MII Mgmt:command */ + volatile uint32_t miimadd; /* MII Mgmt:address */ + volatile uint32_t miimcon; /* MII Mgmt:control 3 */ + volatile uint32_t miimstat; /* MII Mgmt:status */ + volatile uint32_t miimind; /* MII Mgmt:indicators */ +} _PackedType t_MiiAccessMemMap ; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +#endif /* __DTSEC_MII_ACC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec.h @@ -0,0 +1,634 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File dtsec.h + + @Description FM dTSEC ... +*//***************************************************************************/ +#ifndef __DTSEC_H +#define __DTSEC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "dtsec_mii_acc.h" +#include "fm_mac.h" + + +#define PEMASK_TSRE 0x00010000 + +#define IMASK_BREN 0x80000000 +#define IMASK_RXCEN 0x40000000 +#define IMASK_MSROEN 0x04000000 +#define IMASK_GTSCEN 0x02000000 +#define IMASK_BTEN 0x01000000 +#define IMASK_TXCEN 0x00800000 +#define IMASK_TXEEN 0x00400000 +#define IMASK_LCEN 0x00040000 +#define IMASK_CRLEN 0x00020000 +#define IMASK_XFUNEN 0x00010000 +#define IMASK_ABRTEN 0x00008000 +#define IMASK_IFERREN 0x00004000 +#define IMASK_MAGEN 0x00000800 +#define IMASK_MMRDEN 0x00000400 +#define IMASK_MMWREN 0x00000200 +#define IMASK_GRSCEN 0x00000100 +#define IMASK_TDPEEN 0x00000002 +#define IMASK_RDPEEN 0x00000001 + +#define EVENTS_MASK ((uint32_t)(IMASK_BREN | \ + IMASK_RXCEN | \ + IMASK_MSROEN | \ + IMASK_GTSCEN | \ + IMASK_BTEN | \ + IMASK_TXCEN | \ + IMASK_TXEEN | \ + IMASK_ABRTEN | \ + IMASK_LCEN | \ + IMASK_CRLEN | \ + IMASK_XFUNEN | \ + IMASK_IFERREN | \ + IMASK_MAGEN | \ + IMASK_MMRDEN | \ + IMASK_MMWREN | \ + IMASK_GRSCEN | \ + IMASK_TDPEEN | \ + IMASK_RDPEEN)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch(exception){ \ + case e_FM_MAC_EX_1G_BAB_RX: \ + bitMask = IMASK_BREN; break; \ + case e_FM_MAC_EX_1G_RX_CTL: \ + bitMask = IMASK_RXCEN; break; \ + case e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET: \ + bitMask = IMASK_GTSCEN ; break; \ + case e_FM_MAC_EX_1G_BAB_TX: \ + bitMask = IMASK_BTEN ; break; \ + case e_FM_MAC_EX_1G_TX_CTL: \ + bitMask = IMASK_TXCEN ; break; \ + case e_FM_MAC_EX_1G_TX_ERR: \ + bitMask = IMASK_TXEEN ; break; \ + case e_FM_MAC_EX_1G_LATE_COL: \ + bitMask = IMASK_LCEN ; break; \ + case e_FM_MAC_EX_1G_COL_RET_LMT: \ + bitMask = IMASK_CRLEN ; break; \ + case e_FM_MAC_EX_1G_TX_FIFO_UNDRN: \ + bitMask = IMASK_XFUNEN ; break; \ + case e_FM_MAC_EX_1G_MAG_PCKT: \ + bitMask = IMASK_MAGEN ; break; \ + case e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET: \ + bitMask = IMASK_MMRDEN; break; \ + case e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET: \ + bitMask = IMASK_MMWREN ; break; \ + case e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET: \ + bitMask = IMASK_GRSCEN; break; \ + case e_FM_MAC_EX_1G_TX_DATA_ERR: \ + bitMask = IMASK_TDPEEN; break; \ + case e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL: \ + bitMask = IMASK_MSROEN ; break; \ + default: bitMask = 0;break;} + + +#define MAX_PACKET_ALIGNMENT 31 +#define MAX_INTER_PACKET_GAP 0x7f +#define MAX_INTER_PALTERNATE_BEB 0x0f +#define MAX_RETRANSMISSION 0x0f +#define MAX_COLLISION_WINDOW 0x03ff + + +/********************* From mac ext ******************************************/ +typedef uint32_t t_ErrorDisable; + +#define ERROR_DISABLE_TRANSMIT 0x00400000 +#define ERROR_DISABLE_LATE_COLLISION 0x00040000 +#define ERROR_DISABLE_COLLISION_RETRY_LIMIT 0x00020000 +#define ERROR_DISABLE_TxFIFO_UNDERRUN 0x00010000 +#define ERROR_DISABLE_TxABORT 0x00008000 +#define ERROR_DISABLE_INTERFACE 0x00004000 +#define ERROR_DISABLE_TxDATA_PARITY 0x00000002 +#define ERROR_DISABLE_RxDATA_PARITY 0x00000001 + +/*****************************************************************************/ +#define DTSEC_NUM_OF_PADDRS 15 /* number of pattern match registers (entries) */ + +#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ + +#define HASH_TABLE_SIZE 256 /* Hash table size (= 32 bits * 8 regs) */ + +#define DTSEC_TO_MII_OFFSET 0x1120 /* number of pattern match registers (entries) */ + +#define DEFAULT_errorDisabled 0 +#define DEFAULT_promiscuousEnable FALSE +#define DEFAULT_pauseExtended 0x0 +#define DEFAULT_pauseTime 0xf000 +#define DEFAULT_halfDuplex FALSE +#define DEFAULT_halfDulexFlowControlEn FALSE +#define DEFAULT_txTimeStampEn FALSE +#define DEFAULT_rxTimeStampEn FALSE +#define DEFAULT_packetAlignment 0 +#define DEFAULT_controlFrameAccept FALSE +#define DEFAULT_groupHashExtend FALSE +#define DEFAULT_broadcReject FALSE +#define DEFAULT_rxShortFrame TRUE +#define DEFAULT_exactMatch FALSE +#define DEFAULT_debugMode FALSE +#define DEFAULT_loopback FALSE +#define DEFAULT_actOnRxPauseFrame TRUE +#define DEFAULT_actOnTxPauseFrame TRUE + +#define DEFAULT_PreAmLength 0x7 +#define DEFAULT_PreAmRxEn FALSE +#define DEFAULT_PreAmTxEn FALSE +#define DEFAULT_lengthCheckEnable FALSE +#define DEFAULT_padAndCrcEnable TRUE +#define DEFAULT_crcEnable FALSE + +#define DEFAULT_nonBackToBackIpg1 0x40 +#define DEFAULT_nonBackToBackIpg2 0x60 +#define DEFAULT_minIfgEnforcement 0x50 +#define DEFAULT_backToBackIpg 0x60 + +#define DEFAULT_altBackoffVal 0x0A +#define DEFAULT_altBackoffEnable FALSE +#define DEFAULT_backPressureNoBackoff FALSE +#define DEFAULT_noBackoff FALSE +#define DEFAULT_excessDefer TRUE +#define DEFAULT_maxRetransmission 0x0F +#define DEFAULT_collisionWindow 0x37 + +#define DEFAULT_maxFrameLength 0x600 + +#define DEFAULT_collisionWindow 0x37 + +#define DEFAULT_fifoTxThr 0x10 +#define DEFAULT_fifoTxWatermarkH 0x7e +#define DEFAULT_fifoRxWatermarkL 0x08 +#define DEFAULT_tbiPhyAddr 5 + +#define DEFAULT_exceptions ((uint32_t)(IMASK_BREN | \ + IMASK_RXCEN | \ + IMASK_BTEN | \ + IMASK_TXCEN | \ + IMASK_TXEEN | \ + IMASK_ABRTEN | \ + IMASK_LCEN | \ + IMASK_CRLEN | \ + IMASK_XFUNEN | \ + IMASK_IFERREN | \ + IMASK_MAGEN | \ + IMASK_TDPEEN | \ + IMASK_RDPEEN)) + + +#define MAX_PHYS 32 /* maximum number of phys */ + +#define DTSEC_ID1_ID 0xffff0000 +#define DTSEC_ID1_REV_MJ 0x0000FF00 +#define DTSEC_ID1_REV_MN 0x000000ff + +#define ID2_INT_REDUCED_OFF 0x00010000 +#define ID2_INT_NORMAL_OFF 0x00020000 + +#define ECNTRL_CLRCNT 0x00004000 +#define ECNTRL_AUTOZ 0x00002000 +#define ECNTRL_STEN 0x00001000 +#define ECNTRL_CFG_RO 0x80000000 +#define ECNTRL_GMIIM 0x00000040 +#define ECNTRL_TBIM 0x00000020 +#define ECNTRL_SGMIIM 0x00000002 +#define ECNTRL_RPM 0x00000010 +#define ECNTRL_R100M 0x00000008 +#define ECNTRL_RMM 0x00000004 +#define ECNTRL_QSGMIIM 0x00000001 + +#define TCTRL_THDF 0x00000800 +#define TCTRL_TTSE 0x00000040 +#define TCTRL_GTS 0x00000020 +#define TCTRL_TFC_PAUSE 0x00000010 + +/* PTV offsets */ +#define PTV_PTE_OFST 16 + +#define RCTRL_CFA 0x00008000 +#define RCTRL_GHTX 0x00000400 +#define RCTRL_RTSE 0x00000040 +#define RCTRL_GRS 0x00000020 +#define RCTRL_BC_REJ 0x00000010 +#define RCTRL_MPROM 0x00000008 +#define RCTRL_RSF 0x00000004 +#define RCTRL_EMEN 0x00000002 +#define RCTRL_UPROM 0x00000001 +#define RCTRL_PROM (RCTRL_UPROM | RCTRL_MPROM) + +#define TMR_CTL_ESFDP 0x00000800 +#define TMR_CTL_ESFDE 0x00000400 + +#define TSEC_ID1_DEBUG 0x00e00c00 +#define DEBUG_ENABLE 0x80000000 +#define DPERROR_Tx_ERROR_ON_SEC 0x00400000 +#define DPERROR_Tx_ERROR_ON_WRITE 0x10000000 +#define DPERROR_Rx_ERROR_ON_SEC 0x00000040 +#define DPERROR_Rx_ERROR_ON_WRITE 0x00001000 +#define DPERROR_STT 0x80000000 +#define DPERROR_STR 0x00008000 + +#define MACCFG1_SOFT_RESET 0x80000000 +#define MACCFG1_LOOPBACK 0x00000100 +#define MACCFG1_RX_FLOW 0x00000020 +#define MACCFG1_TX_FLOW 0x00000010 +#define MACCFG1_TX_EN 0x00000001 +#define MACCFG1_RX_EN 0x00000004 +#define MACCFG1_RESET_RxMC 0x00080000 +#define MACCFG1_RESET_TxMC 0x00040000 +#define MACCFG1_RESET_RxFUN 0x00020000 +#define MACCFG1_RESET_TxFUN 0x00010000 + +#define MACCFG2_NIBBLE_MODE 0x00000100 +#define MACCFG2_BYTE_MODE 0x00000200 +#define MACCFG2_PRE_AM_Rx_EN 0x00000080 +#define MACCFG2_PRE_AM_Tx_EN 0x00000040 +#define MACCFG2_LENGTH_CHECK 0x00000010 +#define MACCFG2_MAGIC_PACKET_EN 0x00000008 +#define MACCFG2_PAD_CRC_EN 0x00000004 +#define MACCFG2_CRC_EN 0x00000002 +#define MACCFG2_FULL_DUPLEX 0x00000001 + +#define PREAMBLE_LENGTH_SHIFT 12 + +#define IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT 24 +#define IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT 16 +#define IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT 8 + +#define IPGIFG_NON_BACK_TO_BACK_IPG_1 0x7F000000 +#define IPGIFG_NON_BACK_TO_BACK_IPG_2 0x007F0000 +#define IPGIFG_MIN_IFG_ENFORCEMENT 0x0000FF00 +#define IPGIFG_BACK_TO_BACK_IPG 0x0000007F + +#define HAFDUP_ALT_BEB 0x00080000 +#define HAFDUP_BP_NO_BACKOFF 0x00040000 +#define HAFDUP_NO_BACKOFF 0x00020000 +#define HAFDUP_EXCESS_DEFER 0x00010000 +#define HAFDUP_COLLISION_WINDOW 0x000003ff + +#define HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT 20 +#define HAFDUP_RETRANSMISSION_MAX_SHIFT 12 +#define HAFDUP_RETRANSMISSION_MAX 0x0000f000 + +#define NUM_OF_HASH_REGS 8 /* Number of hash table registers */ + +#define DEBUG_GET_FIFO_READ_INDEX 0x007f0000 +#define DEBUG_GET_FIFO_WRITE_INDEX 0x0000007f +/* Pause Time Value Register */ +#define PTV_PTE_SHIFT 16 + +#define MASK22BIT 0x003FFFFF +#define MASK16BIT 0x0000FFFF +#define MASK12BIT 0x00000FFF +#define MASK8BIT 0x000000FF + +#define VAL32BIT 0x100000000LL +#define VAL22BIT 0x00400000 +#define VAL16BIT 0x00010000 +#define VAL12BIT 0x00001000 + +/* PHY Control Register */ +#define PHY_CR_LOOPBACK 0x4000 +#define PHY_CR_SPEED0 0x2000 +#define PHY_CR_ANE 0x1000 +#define PHY_CR_FULLDUPLEX 0x0100 +#define PHY_CR_SPEED1 0x0040 + +#define PHY_TBICON_SRESET 0x8000 +#define PHY_TBICON_SPEED2 0x0020 + +/* CAR1/2 bits */ +#define CAR1_TR64 0x80000000 +#define CAR1_TR127 0x40000000 +#define CAR1_TR255 0x20000000 +#define CAR1_TR511 0x10000000 +#define CAR1_TRK1 0x08000000 +#define CAR1_TRMAX 0x04000000 +#define CAR1_TRMGV 0x02000000 + +#define CAR1_RBYT 0x00010000 +#define CAR1_RPKT 0x00008000 +#define CAR1_RMCA 0x00002000 +#define CAR1_RBCA 0x00001000 +#define CAR1_RXPF 0x00000400 +#define CAR1_RALN 0x00000100 +#define CAR1_RFLR 0x00000080 +#define CAR1_RCDE 0x00000040 +#define CAR1_RCSE 0x00000020 +#define CAR1_RUND 0x00000010 +#define CAR1_ROVR 0x00000008 +#define CAR1_RFRG 0x00000004 +#define CAR1_RJBR 0x00000002 +#define CAR1_RDRP 0x00000001 + +#define CAR2_TFCS 0x00040000 +#define CAR2_TBYT 0x00002000 +#define CAR2_TPKT 0x00001000 +#define CAR2_TMCA 0x00000800 +#define CAR2_TBCA 0x00000400 +#define CAR2_TXPF 0x00000200 +#define CAR2_TDRP 0x00000001 + +#define CAM1_ERRORS_ONLY (CAR1_RXPF | \ + CAR1_RALN | \ + CAR1_RFLR | \ + CAR1_RCDE | \ + CAR1_RCSE | \ + CAR1_RUND | \ + CAR1_ROVR | \ + CAR1_RFRG | \ + CAR1_RJBR | \ + CAR1_RDRP) + +#define CAM2_ERRORS_ONLY (CAR2_TFCS | CAR2_TXPF | CAR2_TDRP) + +typedef struct t_InternalStatistics +{ + uint64_t tr64; + uint64_t tr127; + uint64_t tr255; + uint64_t tr511; + uint64_t tr1k; + uint64_t trmax; + uint64_t trmgv; + uint64_t rfrg; + uint64_t rjbr; + uint64_t rdrp; + uint64_t raln; + uint64_t rund; + uint64_t rovr; + uint64_t rxpf; + uint64_t txpf; + uint64_t rbyt; + uint64_t rpkt; + uint64_t rmca; + uint64_t rbca; + uint64_t rflr; + uint64_t rcde; + uint64_t rcse; + uint64_t tbyt; + uint64_t tpkt; + uint64_t tmca; + uint64_t tbca; + uint64_t tdrp; + uint64_t tfcs; +} t_InternalStatistics; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +typedef _Packed struct +{ + uint32_t exact_match1; /* octets 1-4 */ + uint32_t exact_match2; /* octets 5-6 */ +} _PackedType macRegs; + +typedef _Packed struct +{ + volatile uint32_t tsec_id1; /* 0x000 ETSEC_ID register */ + volatile uint32_t tsec_id2; /* 0x004 ETSEC_ID2 register */ + volatile uint32_t ievent; /* 0x008 Interrupt event register */ + volatile uint32_t imask; /* 0x00C Interrupt mask register */ + volatile uint32_t edis; /* 0x010 Error disabled register */ + volatile uint32_t ecntrl; /* 0x014 E control register */ + volatile uint32_t ptv; /* 0x018 Pause time value register */ + volatile uint32_t tbipa; /* 0x01C TBI PHY address register */ + volatile uint32_t tmr_ctrl; /* 0x020 Time-stamp Control register */ + volatile uint32_t tmr_pevent; /* 0x024 Time-stamp event register */ + volatile uint32_t tmr_pemask; /* 0x028 Timer event mask register */ + volatile uint32_t DTSEC_RESERVED2; /* 0x02C */ + volatile uint32_t iobistctl; /* 0x030 IO BIST Control register */ + volatile uint32_t DTSEC_RESERVED3[3]; /* 0x034 */ + + volatile uint32_t tctrl; /* 0x040 Transmit control register */ + volatile uint32_t DTSEC_RESERVED4[3]; /* 0x044-0x04C */ + volatile uint32_t rctrl; /* 0x050 Receive control register */ + volatile uint32_t DTSEC_RESERVED5[11]; /* 0x054- 0x07C */ + + volatile uint32_t igaddr[8]; /* 0x080-0x09C Individual/group address registers 0-7 */ + volatile uint32_t gaddr[8]; /* 0x0A0-0x0BC Group address registers 0-7 */ + volatile uint32_t ETSEC_RESERVED6[16]; /* 0x0C0-0x0FC */ + + volatile uint32_t maccfg1; /* 0x100 MAC configuration #1 */ + volatile uint32_t maccfg2; /* 0x104 MAC configuration #2 */ + volatile uint32_t ipgifg; /* 0x108 IPG/IFG */ + volatile uint32_t hafdup; /* 0x10C Half-duplex */ + volatile uint32_t maxfrm; /* 0x110 Maximum frame */ + volatile uint32_t DTSEC_RESERVED7[3]; /* 0x114-0x11C register */ + t_MiiAccessMemMap miiMemMap; + volatile uint32_t ifctrl; /* 0x138 MII Mgmt:interface control */ + volatile uint32_t ifstat; /* 0x13C Interface status */ + volatile uint32_t macstnaddr1; /* 0x140 Station Address,part 1 */ + volatile uint32_t macstnaddr2; /* 0x144 Station Address,part 2 */ + volatile macRegs macaddr[DTSEC_NUM_OF_PADDRS]; /* 0x148-0x1BC mac exact match addresses 1-15, parts 1-2 */ + volatile uint32_t DTSEC_RESERVED8[16]; /* 0x1C0-0x1FC register */ + + /* RMON MIB REGISTERS */ + /* TRANSMIT and RECEIVE COUNTERS */ + + volatile uint32_t tr64; /* 0x200 transmit and receive 64 byte frame counter */ + volatile uint32_t tr127; /* 0x204 transmit and receive 65 to 127 byte frame counter */ + volatile uint32_t tr255; /* 0x208 transmit and receive 128 to 255 byte frame counter */ + volatile uint32_t tr511; /* 0x20C transmit and receive 256 to 511 byte frame counter */ + volatile uint32_t tr1k; /* 0x210 transmit and receive 512 to 1023 byte frame counter */ + volatile uint32_t trmax; /* 0x214 transmit and receive 1024 to 1518 byte frame counter */ + volatile uint32_t trmgv; /* 0x218 transmit and receive 1519 to 1522 byte good VLAN frame count */ + + /* RECEIVE COUNTERS */ + volatile uint32_t rbyt; /* 0x21C receive byte counter */ + volatile uint32_t rpkt; /* 0x220 receive packet counter */ + volatile uint32_t rfcs; /* 0x224 receive FCS error counter */ + volatile uint32_t rmca; /* 0x228 RMCA receive multicast packet counter */ + volatile uint32_t rbca; /* 0x22C receive broadcast packet counter */ + volatile uint32_t rxcf; /* 0x230 receive control frame packet counter */ + volatile uint32_t rxpf; /* 0x234 receive PAUSE frame packet counter */ + volatile uint32_t rxuo; /* 0x238 receive unknown OP code counter */ + volatile uint32_t raln; /* 0x23C receive alignment error counter */ + volatile uint32_t rflr; /* 0x240 receive frame length error counter */ + volatile uint32_t rcde; /* 0x244 receive code error counter */ + volatile uint32_t rcse; /* 0x248 receive carrier sense error counter */ + volatile uint32_t rund; /* 0x24C receive undersize packet counter */ + volatile uint32_t rovr; /* 0x250 receive oversize packet counter */ + volatile uint32_t rfrg; /* 0x254 receive fragments counter */ + volatile uint32_t rjbr; /* 0x258 receive jabber counter */ + volatile uint32_t rdrp; /* 0x25C receive drop */ + + /* TRANSMIT COUNTERS */ + volatile uint32_t tbyt; /* 0x260 transmit byte counter */ + volatile uint32_t tpkt; /* 0x264 transmit packet counter */ + volatile uint32_t tmca; /* 0x268 transmit multicast packet counter */ + volatile uint32_t tbca; /* 0x26C transmit broadcast packet counter */ + volatile uint32_t txpf; /* 0x270 transmit PAUSE control frame counter */ + volatile uint32_t tdfr; /* 0x274 transmit deferral packet counter */ + volatile uint32_t tedf; /* 0x278 transmit excessive deferral packet counter */ + volatile uint32_t tscl; /* 0x27C transmit single collision packet counter */ + volatile uint32_t tmcl; /* 0x280 transmit multiple collision packet counter */ + volatile uint32_t tlcl; /* 0x284 transmit late collision packet counter */ + volatile uint32_t txcl; /* 0x288 transmit excessive collision packet counter */ + volatile uint32_t tncl; /* 0x28C transmit total collision counter */ + volatile uint32_t DTSEC_RESERVED9; /* 0x290 */ + volatile uint32_t tdrp; /* 0x294 transmit drop frame counter */ + volatile uint32_t tjbr; /* 0x298 transmit jabber frame counter */ + volatile uint32_t tfcs; /* 0x29C transmit FCS error counter */ + volatile uint32_t txcf; /* 0x2A0 transmit control frame counter */ + volatile uint32_t tovr; /* 0x2A4 transmit oversize frame counter */ + volatile uint32_t tund; /* 0x2A8 transmit undersize frame counter */ + volatile uint32_t tfrg; /* 0x2AC transmit fragments frame counter */ + + /* GENERAL REGISTERS */ + volatile uint32_t car1; /* 0x2B0 carry register one register* */ + volatile uint32_t car2; /* 0x2B4 carry register two register* */ + volatile uint32_t cam1; /* 0x2B8 carry register one mask register */ + volatile uint32_t cam2; /* 0x2BC carry register two mask register */ + volatile uint32_t DTSEC_RESERVED10[16]; /* 0x2C0-0x2FC */ + + /* Debug and Factory Test Registers */ + volatile uint32_t debug; /* 0x300 DEBUG - Debug Register */ + volatile uint32_t dperror; /* 0x304 DPERROR - Parity Error Register */ + volatile uint32_t hwassert; /* 0x308 HWASSERT */ + volatile uint32_t RESERVED11; /* 0x30C Reserved */ + volatile uint32_t rx_fifo_ptr; /* 0x310 RXFIFOPTR - Rx FIFO R/W Pointer Register */ + volatile uint32_t rx_fifo_dath; /* 0x314 RXFIFODATH - Rx FIFO Data Register */ + volatile uint32_t rx_fifo_datl; /* 0x318 RXFIFODATL - Rx FIFO Data Register */ + volatile uint32_t rx_fifo_stat; /* 0x31C RXFIFOSTAT - Rx FIFO Status Register */ + volatile uint32_t tx_fifo_ptr; /* 0x320 TXFIFOPTR - Tx FIFO R/W Pointer Register */ + volatile uint32_t tx_fifo_dath; /* 0x324 TXFIFODATH - Rx FIFO Data Register */ + volatile uint32_t tx_fifo_datl; /* 0x328 TXFIFODATL - Rx FIFO Data Register */ + volatile uint32_t tx_fifo_stat; /* 0x32C TXFIFOSTAT - Tx FIFO Status Register */ + volatile uint32_t pkt_rcv_cnt; /* 0x330 PKTRCVCNT - Number of packets accepted and written to Rx FIFO */ + volatile uint32_t RESERVED12[3]; /* 0x334-0x33C Reserved */ + volatile uint32_t tx_threshold; /* 0x340 Transmit threshold; Number of entries (4 bytes units) before starting to transmit to the MAC */ + volatile uint32_t tx_watermark_high;/* 0x344 Transmit watermark high; Number of entries (4 byte units) before de-asserting Ready to packet Interface */ + volatile uint32_t rx_watermark_low; /* 0x348 Receive watermark low; Number of entries (4 byte units) before unloading to packet Interface */ +} _PackedType t_DtsecMemMap; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +typedef struct { + uint32_t errorDisabled; + bool halfDuplex; + uint16_t pauseTime; + uint16_t pauseExtended; + uint8_t tbiPhyAddr; /**< TBI Physical address (1-31) [DEFAULT_tbiPhyAddr] */ + + bool autoZeroCounters; + bool promiscuousEnable; + + bool halfDulexFlowControlEn; + bool txTimeStampEn; + bool rxTimeStampEn; + + uint8_t packetAlignmentPadding; + bool controlFrameAccept; + bool groupHashExtend; + bool broadcReject; + bool rxShortFrame; + bool exactMatch; + + bool debugMode; + + bool loopback; + bool actOnRxPauseFrame; + bool actOnTxPauseFrame; + + uint8_t nonBackToBackIpg1; + uint8_t nonBackToBackIpg2; + uint8_t minIfgEnforcement; + uint8_t backToBackIpg; + + uint8_t preambleLength; + bool preambleRxEn; + bool preambleTxEn; + bool lengthCheckEnable; + bool magicPacketEnable; + bool padAndCrcEnable; + bool crcEnable; + + bool alternateBackoffEnable; + uint8_t alternateBackoffVal; + bool backPressureNoBackoff; + bool noBackoff; + bool excessDefer; + uint8_t maxRetransmission; + uint16_t collisionWindow; + + uint16_t maxFrameLength; + + uint8_t fifoTxThr; + uint8_t fifoTxWatermarkH; + uint8_t fifoRxWatermarkL; +} t_DtsecDriverParam; + +typedef struct { + t_FmMacControllerDriver fmMacControllerDriver; + t_Handle h_App; /**< Handle to the upper layer application */ + t_DtsecMemMap *p_MemMap; /**< pointer to dTSEC memory mapped registers. */ + t_MiiAccessMemMap *p_MiiMemMap; /**< pointer to dTSEC MII memory mapped registers. */ + uint64_t addr; /**< MAC address of device; */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[DTSEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[DTSEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + bool debugMode; + bool halfDuplex; + t_InternalStatistics internalStatistics; + t_EthHash *p_MulticastAddrHash; /* pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /* pointer to driver's individual address hash table */ + uint8_t macId; + uint32_t exceptions; + bool ptpTsuEnabled; + bool enTsuErrExeption; + e_FmMacStatisticsLevel statisticsLevel; + + t_DtsecDriverParam *p_DtsecDriverParam; +} t_Dtsec; + + +t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + + +#endif /* __DTSEC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec.c @@ -0,0 +1,1943 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File dtsec.c + + @Description FM dTSEC ... +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "crc_mac_addr_ext.h" +#include "debug_ext.h" + +#include "fm_common.h" +#include "dtsec.h" + + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +static t_Error CheckInitParameters(t_Dtsec *p_Dtsec) +{ + if(ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_10000) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 1G MAC driver only supports 1G or lower speeds")); + if(p_Dtsec->macId >= FM_MAX_NUM_OF_1G_MACS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId can not be greater than the number of 1G MACs")); + if(p_Dtsec->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC Must have a valid MAC Address")); + if(((p_Dtsec->enetMode == e_ENET_MODE_SGMII_1000) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_1000) || + (p_Dtsec->enetMode == e_ENET_MODE_QSGMII_1000)) && + p_Dtsec->p_DtsecDriverParam->halfDuplex) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC 1G can't work in half duplex")); + if(p_Dtsec->p_DtsecDriverParam->halfDuplex && (p_Dtsec->p_DtsecDriverParam)->loopback) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("LoopBack is not supported in halfDuplex mode")); +#ifdef FM_NO_RX_PREAM_ERRATA_DTSECx1 + if(p_Dtsec->p_DtsecDriverParam->preambleRxEn) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("preambleRxEn")); +#endif /* FM_NO_RX_PREAM_ERRATA_DTSECx1 */ + if(((p_Dtsec->p_DtsecDriverParam)->preambleTxEn || (p_Dtsec->p_DtsecDriverParam)->preambleRxEn) &&( (p_Dtsec->p_DtsecDriverParam)->preambleLength != 0x7)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Preamble length should be 0x7 bytes")); + if((p_Dtsec->p_DtsecDriverParam)->fifoTxWatermarkH<((p_Dtsec->p_DtsecDriverParam)->fifoTxThr+8)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fifoTxWatermarkH has to be at least 8 larger than fifoTxThr")); + if((p_Dtsec->p_DtsecDriverParam)->halfDuplex && + (p_Dtsec->p_DtsecDriverParam->txTimeStampEn || p_Dtsec->p_DtsecDriverParam->rxTimeStampEn)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dTSEC in half duplex mode has to be with 1588 timeStamping diable")); + if((p_Dtsec->p_DtsecDriverParam)->actOnRxPauseFrame && (p_Dtsec->p_DtsecDriverParam)->controlFrameAccept ) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Receive control frame are not passed to the system memory so it can not be accept ")); + if((p_Dtsec->p_DtsecDriverParam)->packetAlignmentPadding > MAX_PACKET_ALIGNMENT) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("packetAlignmentPadding can't be greater than %d ",MAX_PACKET_ALIGNMENT )); + if(((p_Dtsec->p_DtsecDriverParam)->nonBackToBackIpg1 > MAX_INTER_PACKET_GAP) || + ((p_Dtsec->p_DtsecDriverParam)->nonBackToBackIpg2 > MAX_INTER_PACKET_GAP) || + ((p_Dtsec->p_DtsecDriverParam)->backToBackIpg > MAX_INTER_PACKET_GAP)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inter packet gap can't be greater than %d ",MAX_INTER_PACKET_GAP )); + if((p_Dtsec->p_DtsecDriverParam)->alternateBackoffVal > MAX_INTER_PALTERNATE_BEB) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("alternateBackoffVal can't be greater than %d ",MAX_INTER_PALTERNATE_BEB )); + if((p_Dtsec->p_DtsecDriverParam)->maxRetransmission > MAX_RETRANSMISSION) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("maxRetransmission can't be greater than %d ",MAX_RETRANSMISSION )); + if((p_Dtsec->p_DtsecDriverParam)->collisionWindow > MAX_COLLISION_WINDOW) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("collisionWindow can't be greater than %d ",MAX_COLLISION_WINDOW )); + + /* If Auto negotiation process is disabled, need to */ + /* Set up the PHY using the MII Management Interface */ + if (p_Dtsec->p_DtsecDriverParam->tbiPhyAddr > MAX_PHYS) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("PHY address (should be 0-%d)", MAX_PHYS)); + if(!p_Dtsec->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Exception")); + if(!p_Dtsec->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Event")); + return E_OK; +} + +static uint8_t GetMiiDiv(int32_t refClk) +{ + uint32_t div,tmpClk; + int minRange; + + div = 1; + minRange = (int)(refClk/40 - 1); + + tmpClk = (uint32_t)ABS(refClk/60 - 1); + if (tmpClk < minRange) + { + div = 2; + minRange = (int)tmpClk; + } + tmpClk = (uint32_t)ABS(refClk/60 - 1); + if (tmpClk < minRange) + { + div = 3; + minRange = (int)tmpClk; + } + tmpClk = (uint32_t)ABS(refClk/80 - 1); + if (tmpClk < minRange) + { + div = 4; + minRange = (int)tmpClk; + } + tmpClk = (uint32_t)ABS(refClk/100 - 1); + if (tmpClk < minRange) + { + div = 5; + minRange = (int)tmpClk; + } + tmpClk = (uint32_t)ABS(refClk/140 - 1); + if (tmpClk < minRange) + { + div = 6; + minRange = (int)tmpClk; + } + tmpClk = (uint32_t)ABS(refClk/280 - 1); + if (tmpClk < minRange) + { + div = 7; + minRange = (int)tmpClk; + } + + return (uint8_t)div; +} + +/* ........................................................................... */ + +static void SetDefaultParam(t_DtsecDriverParam *p_DtsecDriverParam) +{ + p_DtsecDriverParam->errorDisabled = DEFAULT_errorDisabled; + + p_DtsecDriverParam->promiscuousEnable = DEFAULT_promiscuousEnable; + + p_DtsecDriverParam->pauseExtended = DEFAULT_pauseExtended; + p_DtsecDriverParam->pauseTime = DEFAULT_pauseTime; + + p_DtsecDriverParam->halfDuplex = DEFAULT_halfDuplex; + p_DtsecDriverParam->halfDulexFlowControlEn = DEFAULT_halfDulexFlowControlEn; + p_DtsecDriverParam->txTimeStampEn = DEFAULT_txTimeStampEn; + p_DtsecDriverParam->rxTimeStampEn = DEFAULT_rxTimeStampEn; + + p_DtsecDriverParam->packetAlignmentPadding = DEFAULT_packetAlignment; + p_DtsecDriverParam->controlFrameAccept = DEFAULT_controlFrameAccept; + p_DtsecDriverParam->groupHashExtend = DEFAULT_groupHashExtend; + p_DtsecDriverParam->broadcReject = DEFAULT_broadcReject; + p_DtsecDriverParam->rxShortFrame = DEFAULT_rxShortFrame; + p_DtsecDriverParam->exactMatch = DEFAULT_exactMatch; + p_DtsecDriverParam->debugMode = DEFAULT_debugMode; + + p_DtsecDriverParam->loopback = DEFAULT_loopback; + p_DtsecDriverParam->tbiPhyAddr = DEFAULT_tbiPhyAddr; + p_DtsecDriverParam->actOnRxPauseFrame = DEFAULT_actOnRxPauseFrame; + p_DtsecDriverParam->actOnTxPauseFrame = DEFAULT_actOnTxPauseFrame; + + p_DtsecDriverParam->preambleLength = DEFAULT_PreAmLength; + p_DtsecDriverParam->preambleRxEn = DEFAULT_PreAmRxEn; + p_DtsecDriverParam->preambleTxEn = DEFAULT_PreAmTxEn; + p_DtsecDriverParam->lengthCheckEnable = DEFAULT_lengthCheckEnable; + p_DtsecDriverParam->padAndCrcEnable = DEFAULT_padAndCrcEnable; + p_DtsecDriverParam->crcEnable = DEFAULT_crcEnable; + + p_DtsecDriverParam->nonBackToBackIpg1 = DEFAULT_nonBackToBackIpg1; + p_DtsecDriverParam->nonBackToBackIpg2 = DEFAULT_nonBackToBackIpg2; + p_DtsecDriverParam->minIfgEnforcement = DEFAULT_minIfgEnforcement; + p_DtsecDriverParam->backToBackIpg = DEFAULT_backToBackIpg; + + p_DtsecDriverParam->alternateBackoffVal = DEFAULT_altBackoffVal; + p_DtsecDriverParam->alternateBackoffEnable = DEFAULT_altBackoffEnable; + p_DtsecDriverParam->backPressureNoBackoff = DEFAULT_backPressureNoBackoff; + p_DtsecDriverParam->noBackoff = DEFAULT_noBackoff; + p_DtsecDriverParam->excessDefer = DEFAULT_excessDefer; + p_DtsecDriverParam->maxRetransmission = DEFAULT_maxRetransmission; + p_DtsecDriverParam->collisionWindow = DEFAULT_collisionWindow; + + p_DtsecDriverParam->maxFrameLength = DEFAULT_maxFrameLength; + + p_DtsecDriverParam->fifoTxThr = DEFAULT_fifoTxThr; + p_DtsecDriverParam->fifoTxWatermarkH = DEFAULT_fifoTxWatermarkH; + + p_DtsecDriverParam->fifoRxWatermarkL = DEFAULT_fifoRxWatermarkL; +} + +static void DtsecException(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + t_DtsecMemMap *p_DtsecMemMap; + + ASSERT_COND(p_Dtsec); + p_DtsecMemMap = p_Dtsec->p_MemMap; + ASSERT_COND(p_DtsecMemMap); + + event = GET_UINT32(p_DtsecMemMap->ievent); + /* handle only MDIO events */ + event &= (IMASK_MMRDEN | IMASK_MMWREN); + if(event) + { + event &= GET_UINT32(p_DtsecMemMap->imask); + + WRITE_UINT32(p_DtsecMemMap->ievent, event); + + if(event & IMASK_MMRDEN) + p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET); + if(event & IMASK_MMWREN) + p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET); + } +} + +static void UpdateStatistics(t_Dtsec *p_Dtsec) +{ + t_DtsecMemMap *p_DtsecMemMap = p_Dtsec->p_MemMap; + uint32_t car1 = GET_UINT32(p_DtsecMemMap->car1); + uint32_t car2 = GET_UINT32(p_DtsecMemMap->car2); + + if(car1) + { + WRITE_UINT32(p_DtsecMemMap->car1, car1); + if(car1 & CAR1_TR64) + p_Dtsec->internalStatistics.tr64 += VAL22BIT; + if(car1 & CAR1_TR127) + p_Dtsec->internalStatistics.tr127 += VAL22BIT; + if(car1 & CAR1_TR255) + p_Dtsec->internalStatistics.tr255 += VAL22BIT; + if(car1 & CAR1_TR511) + p_Dtsec->internalStatistics.tr511 += VAL22BIT; + if(car1 & CAR1_TRK1) + p_Dtsec->internalStatistics.tr1k += VAL22BIT; + if(car1 & CAR1_TRMAX) + p_Dtsec->internalStatistics.trmax += VAL22BIT; + if(car1 & CAR1_TRMGV) + p_Dtsec->internalStatistics.trmgv += VAL22BIT; + if(car1 & CAR1_RBYT) + p_Dtsec->internalStatistics.rbyt += (uint64_t)VAL32BIT; + if(car1 & CAR1_RPKT) + p_Dtsec->internalStatistics.rpkt += VAL22BIT; + if(car1 & CAR1_RMCA) + p_Dtsec->internalStatistics.rmca += VAL22BIT; + if(car1 & CAR1_RBCA) + p_Dtsec->internalStatistics.rbca += VAL22BIT; + if(car1 & CAR1_RXPF) + p_Dtsec->internalStatistics.rxpf += VAL16BIT; + if(car1 & CAR1_RALN) + p_Dtsec->internalStatistics.raln += VAL16BIT; + if(car1 & CAR1_RFLR) + p_Dtsec->internalStatistics.rflr += VAL16BIT; + if(car1 & CAR1_RCDE) + p_Dtsec->internalStatistics.rcde += VAL16BIT; + if(car1 & CAR1_RCSE) + p_Dtsec->internalStatistics.rcse += VAL16BIT; + if(car1 & CAR1_RUND) + p_Dtsec->internalStatistics.rund += VAL16BIT; + if(car1 & CAR1_ROVR) + p_Dtsec->internalStatistics.rovr += VAL16BIT; + if(car1 & CAR1_RFRG) + p_Dtsec->internalStatistics.rfrg += VAL16BIT; + if(car1 & CAR1_RJBR) + p_Dtsec->internalStatistics.rjbr += VAL16BIT; + if(car1 & CAR1_RDRP) + p_Dtsec->internalStatistics.rdrp += VAL16BIT; + } + if(car2) + { + WRITE_UINT32(p_DtsecMemMap->car2, car2); + if(car2 & CAR2_TFCS) + p_Dtsec->internalStatistics.tfcs += VAL12BIT; + if(car2 & CAR2_TBYT) + p_Dtsec->internalStatistics.tbyt += (uint64_t)VAL32BIT; + if(car2 & CAR2_TPKT) + p_Dtsec->internalStatistics.tpkt += VAL22BIT; + if(car2 & CAR2_TMCA) + p_Dtsec->internalStatistics.tmca += VAL22BIT; + if(car2 & CAR2_TBCA) + p_Dtsec->internalStatistics.tbca += VAL22BIT; + if(car2 & CAR2_TXPF) + p_Dtsec->internalStatistics.txpf += VAL16BIT; + if(car2 & CAR2_TDRP) + p_Dtsec->internalStatistics.tdrp += VAL16BIT; + } +} + +/* .............................................................................. */ + +static uint16_t DtsecGetMaxFrameLength(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_VALUE(p_Dtsec, E_INVALID_HANDLE, 0); + + return (uint16_t)GET_UINT32(p_Dtsec->p_MemMap->maxfrm); +} + +static void DtsecErrException(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + t_DtsecMemMap *p_DtsecMemMap = p_Dtsec->p_MemMap; + + event = GET_UINT32(p_DtsecMemMap->ievent); + /* do not handle MDIO events */ + event &= ~(IMASK_MMRDEN | IMASK_MMWREN); + + event &= GET_UINT32(p_DtsecMemMap->imask); + + WRITE_UINT32(p_DtsecMemMap->ievent, event); + + if(event & IMASK_BREN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_RX); + if(event & IMASK_RXCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_CTL); + if(event & IMASK_MSROEN) + UpdateStatistics(p_Dtsec); + if(event & IMASK_GTSCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET); + if(event & IMASK_BTEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_TX); + if(event & IMASK_TXCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_CTL); + if(event & IMASK_TXEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_ERR); + if(event & IMASK_LCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_LATE_COL); + if(event & IMASK_CRLEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_COL_RET_LMT); + if(event & IMASK_XFUNEN) + { +#ifdef FM_TX_LOCKUP_ERRATA_DTSEC6 + uint32_t tpkt1, tmpReg1, tpkt2, tmpReg2, i; + /* a. Write 0x00E0_0C00 to DTSEC_ID */ + /* This is a read only regidter */ + + /* b. Read and save the value of TPKT */ + tpkt1 = GET_UINT32(p_DtsecMemMap->tpkt); + + /* c. Read the register at dTSEC address offset 0x32C */ + tmpReg1 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); + + /* d. Compare bits [9:15] to bits [25:31] of the register at address offset 0x32C. */ + if((tmpReg1 & 0x007F0000) != (tmpReg1 & 0x0000007F)) + { + /* If they are not equal, save the value of this register and wait for at least + * MAXFRM*16 ns */ + XX_UDelay((uint32_t)(MIN(DtsecGetMaxFrameLength(p_Dtsec)*16/1000, 1))); + } + + /* e. Read and save TPKT again and read the register at dTSEC address offset + 0x32C again*/ + tpkt2 = GET_UINT32(p_DtsecMemMap->tpkt); + tmpReg2 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); + + /* f. Compare the value of TPKT saved in step b to value read in step e. Also + compare bits [9:15] of the register at offset 0x32C saved in step d to the value + of bits [9:15] saved in step e. If the two registers values are unchanged, then + the transmit portion of the dTSEC controller is locked up and the user should + proceed to the recover sequence. */ + if((tpkt1 == tpkt2) && ((tmpReg1 & 0x007F0000) == (tmpReg2 & 0x007F0000))) + { + /* recover sequence */ + + /* a.Write a 1 to RCTRL[GRS]*/ + + WRITE_UINT32(p_DtsecMemMap->rctrl, GET_UINT32(p_DtsecMemMap->rctrl) | RCTRL_GRS); + + /* b.Wait until IEVENT[GRSC]=1, or at least 100 us has elapsed. */ + for(i = 0 ; i < 100 ; i++ ) + { + if(GET_UINT32(p_DtsecMemMap->ievent) & IMASK_GRSCEN) + break; + XX_UDelay(1); + } + if(GET_UINT32(p_DtsecMemMap->ievent) & IMASK_GRSCEN) + WRITE_UINT32(p_DtsecMemMap->ievent, IMASK_GRSCEN); + else + DBG(INFO,("Rx lockup due to dTSEC Tx lockup")); + + + /* c.Write a 1 to bit n of FM_RSTC (offset 0x0CC of FPM)*/ + FmResetMac(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, p_Dtsec->fmMacControllerDriver.macId); + + /* d.Wait 4 Tx clocks (32 ns) */ + XX_UDelay(1); + + /* e.Write a 0 to bit n of FM_RSTC. */ + /* cleared by FMAN */ + } + else + { + /* If either value has changed, the dTSEC controller is not locked up and the + controller should be allowed to proceed normally by writing the reset value + of 0x0824_0101 to DTSEC_ID. */ + /* Register is read only */ + } +#endif /* FM_TX_LOCKUP_ERRATA_DTSEC6 */ + + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_FIFO_UNDRN); + } + if(event & IMASK_MAGEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_MAG_PCKT); + if(event & IMASK_GRSCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET); + if(event & IMASK_TDPEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_DATA_ERR); + if(event & IMASK_RDPEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_DATA_ERR); + + /* - masked interrupts */ + ASSERT_COND(!(event & IMASK_ABRTEN)); + ASSERT_COND(!(event & IMASK_IFERREN)); +} + +static void Dtsec1588Exception(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + t_DtsecMemMap *p_DtsecMemMap = p_Dtsec->p_MemMap; + + if (p_Dtsec->ptpTsuEnabled) + { + event = GET_UINT32(p_DtsecMemMap->tmr_pevent); + event &= GET_UINT32(p_DtsecMemMap->tmr_pemask); + if(event) + { + WRITE_UINT32(p_DtsecMemMap->tmr_pevent, event); + ASSERT_COND(event & PEMASK_TSRE); + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_1588_TS_RX_ERR); + } + } +} + +/* ........................................................................... */ + +static void FreeInitResources(t_Dtsec *p_Dtsec) +{ + /*TODO - need to ask why with mdioIrq != 0*/ + if ((p_Dtsec->mdioIrq != 0) && (p_Dtsec->mdioIrq != NO_IRQ)) + { + XX_DisableIntr(p_Dtsec->mdioIrq); + XX_FreeIntr(p_Dtsec->mdioIrq); + } + else if (p_Dtsec->mdioIrq == 0) + FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL); + FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_ERR); + FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC_TMR, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL); + + /* release the driver's group hash table */ + FreeHashTable(p_Dtsec->p_MulticastAddrHash); + p_Dtsec->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Dtsec->p_UnicastAddrHash); + p_Dtsec->p_UnicastAddrHash = NULL; +} + +/* ........................................................................... */ + +static void HardwareClearAddrInPaddr(t_Dtsec *p_Dtsec, uint8_t paddrNum) +{ + WRITE_UINT32(((t_DtsecMemMap*)p_Dtsec->p_MemMap)->macaddr[paddrNum].exact_match1, 0x0); + WRITE_UINT32(((t_DtsecMemMap*)p_Dtsec->p_MemMap)->macaddr[paddrNum].exact_match2, 0x0); +} + +/* ........................................................................... */ + +static void HardwareAddAddrInPaddr(t_Dtsec *p_Dtsec, uint64_t *p_Addr, uint8_t paddrNum) +{ + uint32_t tmpReg32 = 0; + uint64_t addr = *p_Addr; + t_DtsecMemMap *p_DtsecMemMap = (t_DtsecMemMap*)p_Dtsec->p_MemMap; + + tmpReg32 = (uint32_t)(addr); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_DtsecMemMap->macaddr[paddrNum].exact_match1, tmpReg32); + + tmpReg32 = (uint32_t)(addr>>32); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_DtsecMemMap->macaddr[paddrNum].exact_match2, tmpReg32); +} + +/* ........................................................................... */ + +static t_Error GracefulStop(t_Dtsec *p_Dtsec, e_CommMode mode) +{ + t_DtsecMemMap *p_MemMap; + + ASSERT_COND(p_Dtsec); + + p_MemMap= (t_DtsecMemMap*)(p_Dtsec->p_MemMap); + ASSERT_COND(p_MemMap); + + /* Assert the graceful transmit stop bit */ + if (mode & e_COMM_MODE_RX) + WRITE_UINT32(p_MemMap->rctrl, + GET_UINT32(p_MemMap->rctrl) | RCTRL_GRS); + +#ifdef FM_GRS_ERRATA_DTSEC_A002 + XX_UDelay(100); +#endif /* FM_GRS_ERRATA_DTSEC_A002 */ + +#ifdef FM_GTS_ERRATA_DTSEC_A004 + DBG(INFO, ("GTS not supported due to DTSEC_A004 errata.")); +#else /* not FM_GTS_ERRATA_DTSEC_A004 */ + if (mode & e_COMM_MODE_TX) + WRITE_UINT32(p_MemMap->tctrl, + GET_UINT32(p_MemMap->tctrl) | TCTRL_GTS); +#endif /* not FM_GTS_ERRATA_DTSEC_A004 */ + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error GracefulRestart(t_Dtsec *p_Dtsec, e_CommMode mode) +{ + t_DtsecMemMap *p_MemMap; + + ASSERT_COND(p_Dtsec); + + p_MemMap= (t_DtsecMemMap*)(p_Dtsec->p_MemMap); + ASSERT_COND(p_MemMap); + + /* clear the graceful receive stop bit */ + if(mode & e_COMM_MODE_TX) + WRITE_UINT32(p_MemMap->tctrl, + GET_UINT32(p_MemMap->tctrl) & ~TCTRL_GTS); + + if(mode & e_COMM_MODE_RX) + WRITE_UINT32(p_MemMap->rctrl, + GET_UINT32(p_MemMap->rctrl) & ~RCTRL_GRS); + + return E_OK; +} + + +/*****************************************************************************/ +/* dTSEC Configs modification functions */ +/*****************************************************************************/ + + +/* .............................................................................. */ + +static t_Error DtsecConfigLoopback(t_Handle h_Dtsec, bool newVal) +{ + + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->loopback = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigMaxFrameLength(t_Handle h_Dtsec, uint16_t newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->maxFrameLength = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigPadAndCrc(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->padAndCrcEnable = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigHalfDuplex(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->halfDuplex = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigLengthCheck(t_Handle h_Dtsec, bool newVal) +{ +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 +UNUSED(h_Dtsec); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); + +#else + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->lengthCheckEnable = newVal; + + return E_OK; +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ +} + +static t_Error DtsecConfigException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + if(exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) + { + GET_EXCEPTION_FLAG(bitMask, exception); + if(bitMask) + { + if (enable) + p_Dtsec->exceptions |= bitMask; + else + p_Dtsec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + } + else + { + if(!p_Dtsec->ptpTsuEnabled) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); + switch(exception){ + case(e_FM_MAC_EX_1G_1588_TS_RX_ERR): + if(enable) + p_Dtsec->enTsuErrExeption = TRUE; + else + p_Dtsec->enTsuErrExeption = FALSE; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + } + } + return E_OK; +} +/*****************************************************************************/ +/* dTSEC Run Time API functions */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error DtsecEnable(t_Handle h_Dtsec, e_CommMode mode) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_MemMap ; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_INVALID_HANDLE); + + p_MemMap= (t_DtsecMemMap*)(p_Dtsec->p_MemMap); + + tmpReg32 = GET_UINT32(p_MemMap->maccfg1); + if (mode & e_COMM_MODE_RX) + tmpReg32 |= MACCFG1_RX_EN; + if (mode & e_COMM_MODE_TX) + tmpReg32 |= MACCFG1_TX_EN; + WRITE_UINT32(p_MemMap->maccfg1, tmpReg32); + + GracefulRestart(p_Dtsec, mode); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDisable (t_Handle h_Dtsec, e_CommMode mode) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_MemMap ; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_INVALID_HANDLE); + + p_MemMap = (t_DtsecMemMap*)(p_Dtsec->p_MemMap); + + GracefulStop(p_Dtsec, mode); + + tmpReg32 = GET_UINT32(p_MemMap->maccfg1); + if (mode & e_COMM_MODE_RX) + tmpReg32 &= ~MACCFG1_RX_EN; + if (mode & e_COMM_MODE_TX) + tmpReg32 &= ~MACCFG1_TX_EN; + WRITE_UINT32(p_MemMap->maccfg1, tmpReg32); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecTxMacPause(t_Handle h_Dtsec, uint16_t pauseTime) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t ptv = 0; + t_DtsecMemMap *p_MemMap; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_INVALID_STATE); + + p_MemMap = (t_DtsecMemMap*)(p_Dtsec->p_MemMap); + + if (pauseTime) + { +#ifdef FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 + { + if (pauseTime <= 320) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("This pause-time value of %d is illegal due to errata dTSEC-A003!" + " value should be greater than 320.")); + } +#endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */ + +#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Dtsec->fmMacControllerDriver.h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + pauseTime += 2; + } +#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */ + + ptv = GET_UINT32(p_MemMap->ptv); + ptv |= pauseTime; + WRITE_UINT32(p_MemMap->ptv, ptv); + + /* trigger the transmission of a flow-control pause frame */ + WRITE_UINT32(p_MemMap->maccfg1, + GET_UINT32(p_MemMap->maccfg1) | MACCFG1_TX_FLOW); + } + else + { + WRITE_UINT32(p_MemMap->maccfg1, + GET_UINT32(p_MemMap->maccfg1) & ~MACCFG1_TX_FLOW); + } + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecRxIgnoreMacPause(t_Handle h_Dtsec, bool en) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_MemMap; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_INVALID_STATE); + + p_MemMap = (t_DtsecMemMap*)(p_Dtsec->p_MemMap); + + tmpReg32 = GET_UINT32(p_MemMap->maccfg1); + if (en) + tmpReg32 &= ~MACCFG1_RX_FLOW; + else + tmpReg32 |= MACCFG1_RX_FLOW; + WRITE_UINT32(p_MemMap->maccfg1, tmpReg32); + + return E_OK; +} + + +/* .............................................................................. */ + +static t_Error DtsecEnable1588TimeStamp(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); +#ifdef FM_10_100_SGMII_NO_TS_ERRATA_DTSEC3 + if((p_Dtsec->enetMode == e_ENET_MODE_SGMII_10) || (p_Dtsec->enetMode == e_ENET_MODE_SGMII_100)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("1588TimeStamp in 10/100 SGMII")); +#endif /* FM_10_100_SGMII_NO_TS_ERRATA_DTSEC3 */ + p_Dtsec->ptpTsuEnabled = TRUE; + WRITE_UINT32(p_Dtsec->p_MemMap->rctrl, GET_UINT32(p_Dtsec->p_MemMap->rctrl) | RCTRL_RTSE); + WRITE_UINT32(p_Dtsec->p_MemMap->tctrl, GET_UINT32(p_Dtsec->p_MemMap->tctrl) | TCTRL_TTSE); + + return E_OK; +} + +static t_Error DtsecDisable1588TimeStamp(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->ptpTsuEnabled = FALSE; + WRITE_UINT32(p_Dtsec->p_MemMap->rctrl, GET_UINT32(p_Dtsec->p_MemMap->rctrl) & ~RCTRL_RTSE); + WRITE_UINT32(p_Dtsec->p_MemMap->tctrl, GET_UINT32(p_Dtsec->p_MemMap->tctrl) & ~TCTRL_TTSE); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetStatistics(t_Handle h_Dtsec, t_FmMacStatistics *p_Statistics) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + + if (p_Dtsec->statisticsLevel == e_FM_MAC_NONE_STATISTICS) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Statistics disabled")); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + memset(p_Statistics, 0xff, sizeof(t_FmMacStatistics)); + + if (p_Dtsec->statisticsLevel == e_FM_MAC_FULL_STATISTICS) + { + p_Statistics->eStatPkts64 = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tr64)) + + p_Dtsec->internalStatistics.tr64; /**< r-10G tr-DT 64 byte frame counter */ + p_Statistics->eStatPkts65to127 = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tr127)) + + p_Dtsec->internalStatistics.tr127; /**< r-10G 65 to 127 byte frame counter */ + p_Statistics->eStatPkts128to255 = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tr255)) + + p_Dtsec->internalStatistics.tr255; /**< r-10G 128 to 255 byte frame counter */ + p_Statistics->eStatPkts256to511 = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tr511)) + + p_Dtsec->internalStatistics.tr511; /**< r-10G 256 to 511 byte frame counter */ + p_Statistics->eStatPkts512to1023 = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tr1k)) + + p_Dtsec->internalStatistics.tr1k; /**< r-10G 512 to 1023 byte frame counter */ + p_Statistics->eStatPkts1024to1518 = (MASK22BIT & GET_UINT32(p_DtsecMemMap->trmax)) + + p_Dtsec->internalStatistics.trmax; /**< r-10G 1024 to 1518 byte frame counter */ + p_Statistics->eStatPkts1519to1522 = (MASK22BIT & GET_UINT32(p_DtsecMemMap->trmgv)) + + p_Dtsec->internalStatistics.trmgv; /**< r-10G 1519 to 1522 byte good frame count */ + /* MIB II */ + p_Statistics->ifInOctets = GET_UINT32(p_DtsecMemMap->rbyt) + + p_Dtsec->internalStatistics.rbyt; /**< Total number of byte received. */ + p_Statistics->ifInPkts = (MASK22BIT & GET_UINT32(p_DtsecMemMap->rpkt)) + + p_Dtsec->internalStatistics.rpkt; /**< Total number of packets received.*/ + p_Statistics->ifInMcastPkts = (MASK22BIT & GET_UINT32(p_DtsecMemMap->rmca)) + + p_Dtsec->internalStatistics.rmca; /**< Total number of multicast frame received*/ + p_Statistics->ifInBcastPkts = (MASK22BIT & GET_UINT32(p_DtsecMemMap->rbca)) + + p_Dtsec->internalStatistics.rbca; /**< Total number of broadcast frame received */ + p_Statistics->ifOutOctets = GET_UINT32(p_DtsecMemMap->tbyt) + + p_Dtsec->internalStatistics.tbyt; /**< Total number of byte sent. */ + p_Statistics->ifOutPkts = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tpkt)) + + p_Dtsec->internalStatistics.tpkt; /**< Total number of packets sent .*/ + p_Statistics->ifOutMcastPkts = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tmca)) + + p_Dtsec->internalStatistics.tmca; /**< Total number of multicast frame sent */ + p_Statistics->ifOutBcastPkts = (MASK22BIT & GET_UINT32(p_DtsecMemMap->tbca)) + + p_Dtsec->internalStatistics.tbca; /**< Total number of multicast frame sent */ + } +/* */ + p_Statistics->eStatFragments = (MASK16BIT & GET_UINT32(p_DtsecMemMap->rfrg)) + + p_Dtsec->internalStatistics.rfrg; /**< Total number of packets that were less than 64 octets long with a wrong CRC.*/ + p_Statistics->eStatJabbers = (MASK16BIT & GET_UINT32(p_DtsecMemMap->rjbr)) + + p_Dtsec->internalStatistics.rjbr; /**< Total number of packets longer than valid maximum length octets */ + + p_Statistics->eStatsDropEvents = (MASK16BIT & GET_UINT32(p_DtsecMemMap->rdrp)) + + p_Dtsec->internalStatistics.rdrp; /**< number of dropped packets due to internal errors of the MAC Client. */ + p_Statistics->eStatCRCAlignErrors = (MASK16BIT & GET_UINT32(p_DtsecMemMap->raln)) + + p_Dtsec->internalStatistics.raln; /**< Incremented when frames of correct length but with CRC error are received.*/ + + p_Statistics->eStatUndersizePkts = (MASK16BIT & GET_UINT32(p_DtsecMemMap->rund)) + + p_Dtsec->internalStatistics.rund; /**< Total number of packets that were less than 64 octets long with a good CRC.*/ + p_Statistics->eStatOversizePkts = (MASK16BIT & GET_UINT32(p_DtsecMemMap->rovr)) + + p_Dtsec->internalStatistics.rovr; /**< T,B.D*/ +/* Pause */ + p_Statistics->reStatPause = (MASK16BIT & GET_UINT32(p_DtsecMemMap->rxpf)) + + p_Dtsec->internalStatistics.rxpf; /**< Pause MAC Control received */ + p_Statistics->teStatPause = (MASK16BIT & GET_UINT32(p_DtsecMemMap->txpf)) + + p_Dtsec->internalStatistics.txpf; /**< Pause MAC Control sent */ + + p_Statistics->ifInDiscards = p_Statistics->eStatsDropEvents; /**< Frames received, but discarded due to problems within the MAC RX. */ + + p_Statistics->ifInErrors = p_Statistics->eStatsDropEvents + + p_Statistics->eStatCRCAlignErrors + + (MASK16BIT & GET_UINT32(p_DtsecMemMap->rflr)) + + p_Dtsec->internalStatistics.rflr + + (MASK16BIT & GET_UINT32(p_DtsecMemMap->rcde)) + + p_Dtsec->internalStatistics.rcde + + (MASK16BIT & GET_UINT32(p_DtsecMemMap->rcse)) + + p_Dtsec->internalStatistics.rcse; + + p_Statistics->ifOutDiscards = (MASK16BIT & GET_UINT32(p_DtsecMemMap->tdrp)) + + p_Dtsec->internalStatistics.tdrp; /**< Frames received, but discarded due to problems within the MAC TX N/A!.*/ + p_Statistics->ifOutErrors = p_Statistics->ifOutDiscards /**< Number of frames transmitted with error: */ + + (MASK12BIT & GET_UINT32(p_DtsecMemMap->tfcs)) + + p_Dtsec->internalStatistics.tfcs; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecModifyMacAddress (t_Handle h_Dtsec, t_EnetAddr *p_EnetAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + uint32_t tmpReg32 = 0; + uint64_t addr; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + /* Initialize MAC Station Address registers (1 & 2) */ + /* Station address have to be swapped (big endian to little endian */ + addr = ((*(uint64_t *)p_EnetAddr) >> 16); + p_Dtsec->addr = addr; + + tmpReg32 = (uint32_t)(addr); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_DtsecMemMap->macstnaddr1, tmpReg32); + + tmpReg32 = (uint32_t)(addr>>32); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_DtsecMemMap->macstnaddr2, tmpReg32); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecResetCounters (t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + + /* clear HW counters */ + WRITE_UINT32(p_Dtsec->p_MemMap->ecntrl, GET_UINT32(p_Dtsec->p_MemMap->ecntrl) | ECNTRL_CLRCNT); + + /* clear SW counters holding carries */ + memset((char *)&p_Dtsec->internalStatistics, (char)0x0, sizeof(t_InternalStatistics)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecAddExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + if (p_Dtsec->indAddrRegUsed[paddrNum]) + if (p_Dtsec->paddr[paddrNum] == ethAddr) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + if (!(p_Dtsec->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Dtsec->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Dtsec->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + HardwareAddAddrInPaddr(p_Dtsec, ðAddr, paddrNum); + p_Dtsec->numOfIndAddrInRegs++; + + return E_OK; + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error DtsecDelExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Dtsec->indAddrRegUsed[paddrNum]) && + (p_Dtsec->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Dtsec->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + HardwareClearAddrInPaddr(p_Dtsec, paddrNum); + p_Dtsec->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error DtsecAddHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + uint32_t crc; + uint8_t crcMirror, reg; + uint32_t bitMask; + t_EthHashEntry *p_HashEntry; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + + /* calculate the "crc mirror" */ + crcMirror = MIRROR((uint8_t)crc); + + /* 3 MSB bits define the register */ + reg = (uint8_t)(crcMirror >> 5); + /* 5 LSB bits define the bit within the register */ + bitMask = 0x80000000 >> (crcMirror & 0x1f); + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + if (ethAddr & GROUP_ADDRESS) + { + /* Group Address */ + LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_MulticastAddrHash->p_Lsts[crcMirror])); + /* Set the appropriate bit in GADDR0-7 */ + WRITE_UINT32(p_DtsecMemMap->gaddr[reg], + GET_UINT32(p_DtsecMemMap->gaddr[reg]) | bitMask); + } + else + { + LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_UnicastAddrHash->p_Lsts[crcMirror])); + /* Set the appropriate bit in IADDR0-7 */ + WRITE_UINT32(p_DtsecMemMap->igaddr[reg], + GET_UINT32(p_DtsecMemMap->igaddr[reg]) | bitMask); + } + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDelHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + t_List *p_Pos; + uint32_t crc; + uint8_t crcMirror, reg; + uint32_t bitMask; + t_EthHashEntry *p_HashEntry = NULL; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + + /* calculate the "crc mirror" */ + crcMirror = MIRROR((uint8_t)crc); + + /* 3 MSB bits define the register */ + reg =(uint8_t)( crcMirror >> 5); + /* 5 LSB bits define the bit within the register */ + bitMask = 0x80000000 >> (crcMirror & 0x1f); + + if (ethAddr & GROUP_ADDRESS) + { + /* Group Address */ + LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_MulticastAddrHash->p_Lsts[crcMirror])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if(p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if(LIST_IsEmpty(&p_Dtsec->p_MulticastAddrHash->p_Lsts[crcMirror])) + WRITE_UINT32(p_DtsecMemMap->gaddr[reg], + GET_UINT32(p_DtsecMemMap->gaddr[reg]) & ~bitMask); + } + else + { + /* Individual Address */ + LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_UnicastAddrHash->p_Lsts[crcMirror])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if(p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if(LIST_IsEmpty(&p_Dtsec->p_UnicastAddrHash->p_Lsts[crcMirror])) + WRITE_UINT32(p_DtsecMemMap->igaddr[reg], + GET_UINT32(p_DtsecMemMap->igaddr[reg]) & ~bitMask); + } + + /* address does not exist */ + ASSERT_COND(p_HashEntry != NULL); + + return E_OK; +} + + +/* .............................................................................. */ + +static t_Error DtsecSetPromiscuous(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + + tmpReg32 = GET_UINT32(p_DtsecMemMap->rctrl); + + if (newVal) + tmpReg32 |= RCTRL_PROM; + else + tmpReg32 &= ~RCTRL_PROM; + + WRITE_UINT32(p_DtsecMemMap->rctrl, tmpReg32); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetStatistics(t_Handle h_Dtsec, e_FmMacStatisticsLevel statisticsLevel) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + + p_Dtsec->statisticsLevel = statisticsLevel; + + switch (p_Dtsec->statisticsLevel) + { + case(e_FM_MAC_NONE_STATISTICS): + WRITE_UINT32(p_DtsecMemMap->cam1,0xffffffff); + WRITE_UINT32(p_DtsecMemMap->cam2,0xffffffff); + WRITE_UINT32(p_DtsecMemMap->ecntrl, GET_UINT32(p_DtsecMemMap->ecntrl) & ~ECNTRL_STEN); + WRITE_UINT32(p_DtsecMemMap->imask, GET_UINT32(p_DtsecMemMap->imask) & ~IMASK_MSROEN); + p_Dtsec->exceptions &= ~IMASK_MSROEN; + break; + case(e_FM_MAC_PARTIAL_STATISTICS): + WRITE_UINT32(p_DtsecMemMap->cam1, CAM1_ERRORS_ONLY); + WRITE_UINT32(p_DtsecMemMap->cam2, CAM2_ERRORS_ONLY); + WRITE_UINT32(p_DtsecMemMap->ecntrl, GET_UINT32(p_DtsecMemMap->ecntrl) | ECNTRL_STEN); + WRITE_UINT32(p_DtsecMemMap->imask, GET_UINT32(p_DtsecMemMap->imask) | IMASK_MSROEN); + p_Dtsec->exceptions |= IMASK_MSROEN; + break; + case(e_FM_MAC_FULL_STATISTICS): + WRITE_UINT32(p_DtsecMemMap->cam1,0); + WRITE_UINT32(p_DtsecMemMap->cam2,0); + WRITE_UINT32(p_DtsecMemMap->ecntrl, GET_UINT32(p_DtsecMemMap->ecntrl) | ECNTRL_STEN); + WRITE_UINT32(p_DtsecMemMap->imask, GET_UINT32(p_DtsecMemMap->imask) | IMASK_MSROEN); + p_Dtsec->exceptions |= IMASK_MSROEN; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); + } + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecAdjustLink(t_Handle h_Dtsec, e_EnetSpeed speed, bool fullDuplex) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_HANDLE); + p_DtsecMemMap = p_Dtsec->p_MemMap; + SANITY_CHECK_RETURN_ERROR(p_DtsecMemMap, E_INVALID_HANDLE); + + if (!fullDuplex && + ((speed >= e_ENET_SPEED_1000) || + (ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode) == e_ENET_IF_SGMII))) + RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode")); + + p_Dtsec->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode), speed); + p_Dtsec->halfDuplex = !fullDuplex; + + tmpReg32 = GET_UINT32(p_DtsecMemMap->maccfg2); + if(p_Dtsec->halfDuplex) + tmpReg32 &= ~MACCFG2_FULL_DUPLEX; + else + tmpReg32 |= MACCFG2_FULL_DUPLEX; + + tmpReg32 &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE); + if((p_Dtsec->enetMode == e_ENET_MODE_RGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_100)|| + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_100)) + tmpReg32 |= MACCFG2_NIBBLE_MODE; + else if((p_Dtsec->enetMode == e_ENET_MODE_RGMII_1000) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_1000)|| + (p_Dtsec->enetMode == e_ENET_MODE_GMII_1000)) + tmpReg32 |= MACCFG2_BYTE_MODE; + WRITE_UINT32(p_DtsecMemMap->maccfg2, tmpReg32); + + tmpReg32 = GET_UINT32(p_DtsecMemMap->ecntrl); + if (!(tmpReg32 & ECNTRL_CFG_RO)) + { + if ((p_Dtsec->enetMode == e_ENET_MODE_RGMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_100)) + tmpReg32 |= ECNTRL_R100M; + else + tmpReg32 &= ~ECNTRL_R100M; + WRITE_UINT32(p_DtsecMemMap->ecntrl, tmpReg32); + } + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetId(t_Handle h_Dtsec, uint32_t *macId) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_HANDLE); + + *macId = p_Dtsec->macId; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetVersion(t_Handle h_Dtsec, uint32_t *macVersion) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecMemMap *p_DtsecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + *macVersion = GET_UINT32(p_DtsecMemMap->tsec_id1); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t tmpReg, bitMask = 0; + t_DtsecMemMap *p_DtsecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + + if(exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) + { + GET_EXCEPTION_FLAG(bitMask, exception); + if(bitMask) + { + if (enable) + p_Dtsec->exceptions |= bitMask; + else + p_Dtsec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + tmpReg = GET_UINT32(p_DtsecMemMap->imask); + if(enable) + tmpReg |= bitMask; + else + tmpReg &= ~bitMask; + WRITE_UINT32(p_DtsecMemMap->imask, tmpReg); + + /* warn if MIB OVFL is disabled and statistic gathering is enabled */ + if((exception == e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL) && + !enable && + (p_Dtsec->statisticsLevel != e_FM_MAC_NONE_STATISTICS)) + DBG(WARNING, ("Disabled MIB counters overflow exceptions. Counters value may be inaccurate due to unregistered overflow")); + + } + else + { + if(!p_Dtsec->ptpTsuEnabled) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); + tmpReg = GET_UINT32(p_DtsecMemMap->tmr_pemask); + switch(exception){ + case(e_FM_MAC_EX_1G_1588_TS_RX_ERR): + if(enable) + { + p_Dtsec->enTsuErrExeption = TRUE; + WRITE_UINT32(p_DtsecMemMap->tmr_pemask, tmpReg | PEMASK_TSRE); + } + else + { + p_Dtsec->enTsuErrExeption = FALSE; + WRITE_UINT32(p_DtsecMemMap->tmr_pemask, tmpReg & ~PEMASK_TSRE); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + } + } + + return E_OK; +} + +/* ........................................................................... */ + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +static t_Error DtsecDumpRegs(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + int i = 0; + + DECLARE_DUMP; + + if (p_Dtsec->p_MemMap) + { + + DUMP_TITLE(p_Dtsec->p_MemMap, ("MAC %d: ", p_Dtsec->macId)); + DUMP_VAR(p_Dtsec->p_MemMap, tsec_id1); + DUMP_VAR(p_Dtsec->p_MemMap, tsec_id2); + DUMP_VAR(p_Dtsec->p_MemMap, ievent); + DUMP_VAR(p_Dtsec->p_MemMap, imask); + DUMP_VAR(p_Dtsec->p_MemMap, edis); + DUMP_VAR(p_Dtsec->p_MemMap, ecntrl); + DUMP_VAR(p_Dtsec->p_MemMap, ptv); + DUMP_VAR(p_Dtsec->p_MemMap, tmr_ctrl); + DUMP_VAR(p_Dtsec->p_MemMap, tmr_pevent); + DUMP_VAR(p_Dtsec->p_MemMap, tmr_pemask); + DUMP_VAR(p_Dtsec->p_MemMap, tctrl); + DUMP_VAR(p_Dtsec->p_MemMap, rctrl); + DUMP_VAR(p_Dtsec->p_MemMap, maccfg1); + DUMP_VAR(p_Dtsec->p_MemMap, maccfg2); + DUMP_VAR(p_Dtsec->p_MemMap, ipgifg); + DUMP_VAR(p_Dtsec->p_MemMap, hafdup); + DUMP_VAR(p_Dtsec->p_MemMap, maxfrm); + + DUMP_VAR(p_Dtsec->p_MemMap, macstnaddr1); + DUMP_VAR(p_Dtsec->p_MemMap, macstnaddr2); + + DUMP_SUBSTRUCT_ARRAY(i, 8) + { + DUMP_VAR(p_Dtsec->p_MemMap, macaddr[i].exact_match1); + DUMP_VAR(p_Dtsec->p_MemMap, macaddr[i].exact_match2); + } + } + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + + +/*****************************************************************************/ +/* FM Init & Free API */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error DtsecInit(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_DtsecDriverParam *p_DtsecDriverParam; + t_DtsecMemMap *p_DtsecMemMap; + int i; + uint32_t tmpReg32; + uint64_t addr; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MemMap, E_INVALID_STATE); + + CHECK_INIT_PARAMETERS(p_Dtsec, CheckInitParameters); + + p_DtsecDriverParam = p_Dtsec->p_DtsecDriverParam; + p_Dtsec->halfDuplex = p_DtsecDriverParam->halfDuplex; + p_Dtsec->debugMode = p_DtsecDriverParam->debugMode; + p_DtsecMemMap = p_Dtsec->p_MemMap; + + /*************dtsec_id2******************/ + tmpReg32 = GET_UINT32(p_DtsecMemMap->tsec_id2); + + if ((p_Dtsec->enetMode == e_ENET_MODE_RGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_1000) || + (p_Dtsec->enetMode == e_ENET_MODE_RMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_RMII_100)) + if(tmpReg32 & ID2_INT_REDUCED_OFF) + { + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("no support for reduced interface in current DTSEC version")); + } + + if ((p_Dtsec->enetMode == e_ENET_MODE_SGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_1000)|| + (p_Dtsec->enetMode == e_ENET_MODE_MII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_MII_100)) + if(tmpReg32 & ID2_INT_NORMAL_OFF) + { + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("no support for normal interface in current DTSEC version")); + } + /*************dtsec_id2******************/ + + /***************EDIS************************/ + WRITE_UINT32(p_DtsecMemMap->edis, p_DtsecDriverParam->errorDisabled); + /***************EDIS************************/ + + /***************ECNTRL************************/ + tmpReg32 = 0; + if ((p_Dtsec->enetMode == e_ENET_MODE_RGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_1000) || + (p_Dtsec->enetMode == e_ENET_MODE_GMII_1000)) + tmpReg32 |= ECNTRL_GMIIM; + if ((p_Dtsec->enetMode == e_ENET_MODE_SGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_1000)) + tmpReg32 |= (ECNTRL_SGMIIM | ECNTRL_TBIM); + if (p_Dtsec->enetMode == e_ENET_MODE_QSGMII_1000) + tmpReg32 |= (ECNTRL_SGMIIM | ECNTRL_TBIM | ECNTRL_QSGMIIM); + if ((p_Dtsec->enetMode == e_ENET_MODE_RGMII_1000) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_10)|| + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_100)) + tmpReg32 |= ECNTRL_RPM; + if ((p_Dtsec->enetMode == e_ENET_MODE_RGMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_RMII_100)) + tmpReg32 |= ECNTRL_R100M; + if ((p_Dtsec->enetMode == e_ENET_MODE_RMII_10) || (p_Dtsec->enetMode == e_ENET_MODE_RMII_100)) + tmpReg32 |= ECNTRL_RMM; + WRITE_UINT32(p_DtsecMemMap->ecntrl, tmpReg32); + /***************ECNTRL************************/ + + /***************PTV************************/ + tmpReg32 = 0; +#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Dtsec->fmMacControllerDriver.h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + p_DtsecDriverParam->pauseTime += 2; + } +#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */ + if (p_DtsecDriverParam->pauseTime) + tmpReg32 |= (uint32_t)p_DtsecDriverParam->pauseTime; + + if (p_DtsecDriverParam->pauseExtended) + tmpReg32 |= ((uint32_t)p_DtsecDriverParam->pauseExtended) << PTV_PTE_OFST; + WRITE_UINT32(p_DtsecMemMap->ptv, tmpReg32); + /***************PTV************************/ + + /***************TCTRL************************/ + tmpReg32 = 0; + if(p_DtsecDriverParam->halfDuplex) + { + if(p_DtsecDriverParam->halfDulexFlowControlEn) + tmpReg32 |= TCTRL_THDF; + } + else + { + if(p_DtsecDriverParam->txTimeStampEn) + tmpReg32 |= TCTRL_TTSE; + } + WRITE_UINT32(p_DtsecMemMap->tctrl, tmpReg32); + /***************TCTRL************************/ + + /***************RCTRL************************/ + tmpReg32 = 0; + if (p_DtsecDriverParam->packetAlignmentPadding) + tmpReg32 |= ((uint32_t)(0x0000001f & p_DtsecDriverParam->packetAlignmentPadding)) << 16; + if (p_DtsecDriverParam->controlFrameAccept) + tmpReg32 |= RCTRL_CFA; + if (p_DtsecDriverParam->groupHashExtend) + tmpReg32 |= RCTRL_GHTX; + if(p_DtsecDriverParam->rxTimeStampEn) + tmpReg32 |= RCTRL_RTSE; + if (p_DtsecDriverParam->broadcReject) + tmpReg32 |= RCTRL_BC_REJ; + if (p_DtsecDriverParam->rxShortFrame) + tmpReg32 |= RCTRL_RSF; + if (p_DtsecDriverParam->promiscuousEnable) + tmpReg32 |= RCTRL_PROM; + if (p_DtsecDriverParam->exactMatch) + tmpReg32 |= RCTRL_EMEN; + + WRITE_UINT32(p_DtsecMemMap->rctrl, tmpReg32); + /***************RCTRL************************/ + + /* Assign a Phy Address to the TBI (TBIPA). */ + /* Done also in case that TBI is not selected to avoid */ + /* conflict with the external PHY’s Physical address */ + WRITE_UINT32(p_DtsecMemMap->tbipa, p_DtsecDriverParam->tbiPhyAddr); + + /* Reset the management interface */ + WRITE_UINT32(p_Dtsec->p_MiiMemMap->miimcfg, MIIMCFG_RESET_MGMT); + WRITE_UINT32(p_Dtsec->p_MiiMemMap->miimcfg, ~MIIMCFG_RESET_MGMT); + /* Setup the MII Mgmt clock speed */ + WRITE_UINT32(p_Dtsec->p_MiiMemMap->miimcfg, + (uint32_t)GetMiiDiv((int32_t)(((p_Dtsec->fmMacControllerDriver.clkFreq*10)/2)/8))); + + if(p_Dtsec->enetMode == e_ENET_MODE_SGMII_1000) + { + uint16_t tmpReg16; + + /* Configure the TBI PHY Control Register */ + tmpReg16 = PHY_TBICON_SPEED2 | PHY_TBICON_SRESET; + + DTSEC_MII_WritePhyReg(p_Dtsec, p_DtsecDriverParam->tbiPhyAddr, 17, tmpReg16); + + tmpReg16 = PHY_TBICON_SPEED2; + + DTSEC_MII_WritePhyReg(p_Dtsec, p_DtsecDriverParam->tbiPhyAddr, 17, tmpReg16); + + if(!p_DtsecDriverParam->halfDuplex) + tmpReg16 |= PHY_CR_FULLDUPLEX | 0x8000 | PHY_CR_ANE; + + DTSEC_MII_WritePhyReg(p_Dtsec, p_DtsecDriverParam->tbiPhyAddr, 0, tmpReg16); + + tmpReg16 = 0x01a0; + DTSEC_MII_WritePhyReg(p_Dtsec, p_DtsecDriverParam->tbiPhyAddr, 4, tmpReg16); + + tmpReg16 = 0x1340; + DTSEC_MII_WritePhyReg(p_Dtsec, p_DtsecDriverParam->tbiPhyAddr, 0, tmpReg16); + } + + /***************TMR_CTL************************/ + WRITE_UINT32(p_DtsecMemMap->tmr_ctrl, 0); + + if(p_Dtsec->ptpTsuEnabled) + { + tmpReg32 = 0; + if (p_Dtsec->enTsuErrExeption) + tmpReg32 |= PEMASK_TSRE; + WRITE_UINT32(p_DtsecMemMap->tmr_pemask, tmpReg32); + WRITE_UINT32(p_DtsecMemMap->tmr_pevent, tmpReg32); + } + + /***************DEBUG************************/ + tmpReg32 = 0; + if(p_DtsecDriverParam->debugMode) + WRITE_UINT32(p_DtsecMemMap->tsec_id1, TSEC_ID1_DEBUG); + /***************DEBUG************************/ + + /***************MACCFG1***********************/ + WRITE_UINT32(p_DtsecMemMap->maccfg1, MACCFG1_SOFT_RESET); + WRITE_UINT32(p_DtsecMemMap->maccfg1, 0); + tmpReg32 = 0; + if(p_DtsecDriverParam->loopback) + tmpReg32 |= MACCFG1_LOOPBACK; + if(p_DtsecDriverParam->actOnRxPauseFrame) + tmpReg32 |= MACCFG1_RX_FLOW; + if(p_DtsecDriverParam->actOnTxPauseFrame) + tmpReg32 |= MACCFG1_TX_FLOW; + WRITE_UINT32(p_DtsecMemMap->maccfg1, tmpReg32); + /***************MACCFG1***********************/ + + /***************MACCFG2***********************/ + tmpReg32 = 0; + if( (p_Dtsec->enetMode == e_ENET_MODE_RMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_RMII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_MII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_MII_100) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_RGMII_100)|| + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_10) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_100)) + tmpReg32 |= MACCFG2_NIBBLE_MODE; + else if((p_Dtsec->enetMode == e_ENET_MODE_RGMII_1000) || + (p_Dtsec->enetMode == e_ENET_MODE_SGMII_1000)|| + (p_Dtsec->enetMode == e_ENET_MODE_GMII_1000)|| + (p_Dtsec->enetMode == e_ENET_MODE_QSGMII_1000)) + tmpReg32 |= MACCFG2_BYTE_MODE; + + tmpReg32 |= (((uint32_t)p_DtsecDriverParam->preambleLength) & 0x0000000f)<< PREAMBLE_LENGTH_SHIFT; + + if(p_DtsecDriverParam->preambleRxEn) + tmpReg32 |= MACCFG2_PRE_AM_Rx_EN; + if(p_DtsecDriverParam->preambleTxEn) + tmpReg32 |= MACCFG2_PRE_AM_Tx_EN; + if(p_DtsecDriverParam->lengthCheckEnable) + tmpReg32 |= MACCFG2_LENGTH_CHECK; + if(p_DtsecDriverParam->padAndCrcEnable) + tmpReg32 |= MACCFG2_PAD_CRC_EN; + if(p_DtsecDriverParam->crcEnable) + tmpReg32 |= MACCFG2_CRC_EN; + if(!p_DtsecDriverParam->halfDuplex) + tmpReg32 |= MACCFG2_FULL_DUPLEX; + WRITE_UINT32(p_DtsecMemMap->maccfg2, tmpReg32); + /***************MACCFG2***********************/ + + /***************IPGIFG************************/ + tmpReg32 = 0; + ASSERT_COND(p_DtsecDriverParam->nonBackToBackIpg1 <= p_DtsecDriverParam->nonBackToBackIpg2); + tmpReg32 = (uint32_t)((((uint32_t)p_DtsecDriverParam->nonBackToBackIpg1 << + IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT) & IPGIFG_NON_BACK_TO_BACK_IPG_1) | + (((uint32_t)p_DtsecDriverParam->nonBackToBackIpg2 << + IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT) & IPGIFG_NON_BACK_TO_BACK_IPG_2) | + (((uint32_t)p_DtsecDriverParam->minIfgEnforcement << + IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT) & IPGIFG_MIN_IFG_ENFORCEMENT) | + ((uint32_t)p_DtsecDriverParam->backToBackIpg & IPGIFG_BACK_TO_BACK_IPG)); + WRITE_UINT32(p_DtsecMemMap->ipgifg, tmpReg32); + /***************IPGIFG************************/ + + /***************HAFDUP************************/ + tmpReg32 = 0; + if(p_DtsecDriverParam->alternateBackoffEnable) + { + tmpReg32 = (uint32_t) (HAFDUP_ALT_BEB | (((uint32_t)p_DtsecDriverParam->alternateBackoffVal & 0x0000000f) << + HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT)); + } + + if(p_DtsecDriverParam->backPressureNoBackoff) + tmpReg32 |= HAFDUP_BP_NO_BACKOFF; + if(p_DtsecDriverParam->noBackoff) + tmpReg32 |= HAFDUP_NO_BACKOFF; + if(p_DtsecDriverParam->excessDefer) + tmpReg32 |= HAFDUP_EXCESS_DEFER; + tmpReg32 |= (((uint32_t)p_DtsecDriverParam->maxRetransmission << + HAFDUP_RETRANSMISSION_MAX_SHIFT )& HAFDUP_RETRANSMISSION_MAX); + tmpReg32|= ((uint32_t)p_DtsecDriverParam->collisionWindow & HAFDUP_COLLISION_WINDOW); + + WRITE_UINT32(p_DtsecMemMap->hafdup, tmpReg32); + /***************HAFDUP************************/ + + /***************MAXFRM************************/ + /* Initialize MAXFRM */ + WRITE_UINT32(p_DtsecMemMap->maxfrm, + p_DtsecDriverParam->maxFrameLength); + err = FmSetMacMaxFrame(p_Dtsec->fmMacControllerDriver.h_Fm, + e_FM_MAC_1G, + p_Dtsec->fmMacControllerDriver.macId, + p_DtsecDriverParam->maxFrameLength); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + /***************MAXFRM************************/ + + /***************CAM1************************/ + WRITE_UINT32(p_DtsecMemMap->cam1,0xffffffff); + WRITE_UINT32(p_DtsecMemMap->cam2,0xffffffff); + + /***************IMASK************************/ + WRITE_UINT32(p_DtsecMemMap->imask, p_Dtsec->exceptions); + /***************IMASK************************/ + + /***************IEVENT************************/ + WRITE_UINT32(p_DtsecMemMap->ievent, EVENTS_MASK); + + /***************MACSTNADDR1/2*****************/ + /* Initialize MAC Station Address registers (1 & 2) */ + /* Station address have to be swapped (big endian to little endian */ + addr = p_Dtsec->addr; + + tmpReg32 = (uint32_t)(addr); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_DtsecMemMap->macstnaddr1, tmpReg32); + + tmpReg32 = (uint32_t)(addr>>32); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_DtsecMemMap->macstnaddr2, tmpReg32); + /***************MACSTNADDR1/2*****************/ + + /***************DEBUG*****************/ + WRITE_UINT32(p_DtsecMemMap->tx_threshold, (uint32_t)(p_DtsecDriverParam->fifoTxThr & 0x7f)); + WRITE_UINT32(p_DtsecMemMap->tx_watermark_high, (uint32_t)(p_DtsecDriverParam->fifoTxWatermarkH & 0x7f)); + WRITE_UINT32(p_DtsecMemMap->rx_watermark_low, (uint32_t)(p_DtsecDriverParam->fifoRxWatermarkL & 0x7f)); + /***************DEBUG*****************/ + + /*****************HASH************************/ + for(i=0 ; iigaddr[i], 0); + /* Initialize GADDRx */ + WRITE_UINT32(p_DtsecMemMap->gaddr[i], 0); + } + + p_Dtsec->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if(!p_Dtsec->p_MulticastAddrHash) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MC hash table is FAILED")); + } + + p_Dtsec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if(!p_Dtsec->p_UnicastAddrHash) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("UC hash table is FAILED")); + } + + /* register err intr handler for dtsec to FPM (err)*/ + FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_ERR, DtsecErrException , p_Dtsec); + /* register 1588 intr handler for TMR to FPM (normal)*/ + FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC_TMR, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL, Dtsec1588Exception , p_Dtsec); + /* register normal intr handler for dtsec to main interrupt controller. */ + if (p_Dtsec->mdioIrq != NO_IRQ) + { + XX_SetIntr(p_Dtsec->mdioIrq, DtsecException, p_Dtsec); + XX_EnableIntr(p_Dtsec->mdioIrq); + } + + XX_Free(p_DtsecDriverParam); + p_Dtsec->p_DtsecDriverParam = NULL; + + err = DtsecSetStatistics(p_Dtsec, e_FM_MAC_FULL_STATISTICS); + if(err) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; +} + +/* ........................................................................... */ + +static t_Error DtsecFree(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + + FreeInitResources(p_Dtsec); + + if (p_Dtsec->p_DtsecDriverParam) + { + XX_Free(p_Dtsec->p_DtsecDriverParam); + p_Dtsec->p_DtsecDriverParam = NULL; + } + XX_Free (h_Dtsec); + + return E_OK; +} + +/* .............................................................................. */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = DtsecInit; + p_FmMacControllerDriver->f_FM_MAC_Free = DtsecFree; + + p_FmMacControllerDriver->f_FM_MAC_SetStatistics = DtsecSetStatistics; + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = DtsecConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = DtsecConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = NULL; /* Not supported on dTSEC */ + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = DtsecConfigPadAndCrc; + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = DtsecConfigHalfDuplex; + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = DtsecConfigLengthCheck; + p_FmMacControllerDriver->f_FM_MAC_ConfigException = DtsecConfigException; + + p_FmMacControllerDriver->f_FM_MAC_Enable = DtsecEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = DtsecDisable; + + p_FmMacControllerDriver->f_FM_MAC_SetException = DtsecSetException; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = DtsecSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = DtsecAdjustLink; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = DtsecEnable1588TimeStamp; + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = DtsecDisable1588TimeStamp; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = DtsecTxMacPause; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = DtsecRxIgnoreMacPause; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = DtsecResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = DtsecGetStatistics; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = DtsecModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = DtsecAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = DtsecDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = DtsecAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = DtsecDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = DtsecGetId; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = DtsecGetVersion; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = DtsecGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = DTSEC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = DTSEC_MII_ReadPhyReg; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + p_FmMacControllerDriver->f_FM_MAC_DumpRegs = DtsecDumpRegs; +#endif /* (defined(DEBUG_ERRORS) && ... */ +} + + +/*****************************************************************************/ +/* dTSEC Config Main Entry */ +/*****************************************************************************/ + +/* .............................................................................. */ + +t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Dtsec *p_Dtsec; + t_DtsecDriverParam *p_DtsecDriverParam; + uintptr_t baseAddr; + uint8_t i; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + /* allocate memory for the UCC GETH data structure. */ + p_Dtsec = (t_Dtsec *) XX_Malloc(sizeof(t_Dtsec)); + if (!p_Dtsec) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver structure")); + return NULL; + } + /* Zero out * p_Dtsec */ + memset(p_Dtsec, 0, sizeof(t_Dtsec)); + InitFmMacControllerDriver(&p_Dtsec->fmMacControllerDriver); + + /* allocate memory for the dTSEC driver parameters data structure. */ + p_DtsecDriverParam = (t_DtsecDriverParam *) XX_Malloc(sizeof(t_DtsecDriverParam)); + if (!p_DtsecDriverParam) + { + XX_Free(p_Dtsec); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver parameters")); + return NULL; + } + /* Zero out */ + memset(p_DtsecDriverParam, 0, sizeof(t_DtsecDriverParam)); + + /* Plant parameter structure pointer */ + p_Dtsec->p_DtsecDriverParam = p_DtsecDriverParam; + + SetDefaultParam(p_DtsecDriverParam); + + for (i=0; i < sizeof(p_FmMacParam->addr); i++) + p_Dtsec->addr |= ((uint64_t)p_FmMacParam->addr[i] << ((5-i) * 8)); + + p_Dtsec->p_MemMap = (t_DtsecMemMap *)UINT_TO_PTR(baseAddr); + p_Dtsec->p_MiiMemMap = (t_MiiAccessMemMap *)UINT_TO_PTR(baseAddr + DTSEC_TO_MII_OFFSET); + p_Dtsec->enetMode = p_FmMacParam->enetMode; + p_Dtsec->macId = p_FmMacParam->macId; + p_Dtsec->exceptions = DEFAULT_exceptions; + p_Dtsec->mdioIrq = p_FmMacParam->mdioIrq; + p_Dtsec->f_Exception = p_FmMacParam->f_Exception; + p_Dtsec->f_Event = p_FmMacParam->f_Event; + p_Dtsec->h_App = p_FmMacParam->h_App; + + return p_Dtsec; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec.h @@ -0,0 +1,482 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File tgec.h + + @Description FM 10G MAC ... +*//***************************************************************************/ +#ifndef __TGEC_H +#define __TGEC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "tgec_mii_acc.h" +#include "fm_mac.h" + + +/* Interrupt Mask Register (IMASK) */ +#define IMASK_MDIO_SCAN_EVENTMDIO 0x00010000 /* MDIO_SCAN_EVENTMDIO scan event interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_MDIO_CMD_CMPL 0x00008000 /* 16 MDIO_CMD_CMPL MDIO command completion interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_REM_FAULT 0x00004000 /* 17 REM_FAULT Remote fault interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_LOC_FAULT 0x00002000 /* 18 LOC_FAULT Local fault interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_1TX_ECC_ER 0x00001000 /* 19 TX_ECC_ER Transmit frame ECC error interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_TX_FIFO_UNFL 0x00000800 /* 20 TX_FIFO_UNFL Transmit FIFO underflow interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_TX_FIFO_OVFL 0x00000400 /* 21 TX_FIFO_OVFL Transmit FIFO overflow interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_TX_ER 0x00000200 /* 22 TX_ER Transmit frame error interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_FIFO_OVFL 0x00000100 /* 23 RX_FIFO_OVFL Receive FIFO overflow interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_ECC_ER 0x00000080 /* 24 RX_ECC_ER Receive frame ECC error interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_JAB_FRM 0x00000040 /* 25 RX_JAB_FRM Receive jabber frame interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_OVRSZ_FRM 0x00000020 /* 26 RX_OVRSZ_FRM Receive oversized frame interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_RUNT_FRM 0x00000010 /* 27 RX_RUNT_FRM Receive runt frame interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_FRAG_FRM 0x00000008 /* 28 RX_FRAG_FRM Receive fragment frame interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_LEN_ER 0x00000004 /* 29 RX_LEN_ER Receive payload length error interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_CRC_ER 0x00000002 /* 30 RX_CRC_ER Receive CRC error interrupt mask. + * 0 masked + * 1 enabled + */ +#define IMASK_RX_ALIGN_ER 0x00000001 /* 31 RX_ALIGN_ER Receive alignment error interrupt mask. + * 0 masked + * 1 enabled + */ + +#define EVENTS_MASK ((uint32_t)(IMASK_MDIO_SCAN_EVENTMDIO | \ + IMASK_MDIO_CMD_CMPL | \ + IMASK_REM_FAULT | \ + IMASK_LOC_FAULT | \ + IMASK_1TX_ECC_ER | \ + IMASK_TX_FIFO_UNFL | \ + IMASK_TX_FIFO_OVFL | \ + IMASK_TX_ER | \ + IMASK_RX_FIFO_OVFL | \ + IMASK_RX_ECC_ER | \ + IMASK_RX_JAB_FRM | \ + IMASK_RX_OVRSZ_FRM | \ + IMASK_RX_RUNT_FRM | \ + IMASK_RX_FRAG_FRM | \ + IMASK_RX_LEN_ER | \ + IMASK_RX_CRC_ER | \ + IMASK_RX_ALIGN_ER)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch(exception){ \ + case e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO: \ + bitMask = IMASK_MDIO_SCAN_EVENTMDIO; break; \ + case e_FM_MAC_EX_10G_MDIO_CMD_CMPL: \ + bitMask = IMASK_MDIO_CMD_CMPL ; break; \ + case e_FM_MAC_EX_10G_REM_FAULT: \ + bitMask = IMASK_REM_FAULT ; break; \ + case e_FM_MAC_EX_10G_LOC_FAULT: \ + bitMask = IMASK_LOC_FAULT ; break; \ + case e_FM_MAC_EX_10G_1TX_ECC_ER: \ + bitMask = IMASK_1TX_ECC_ER ; break; \ + case e_FM_MAC_EX_10G_TX_FIFO_UNFL: \ + bitMask = IMASK_TX_FIFO_UNFL ; break; \ + case e_FM_MAC_EX_10G_TX_FIFO_OVFL: \ + bitMask = IMASK_TX_FIFO_OVFL ; break; \ + case e_FM_MAC_EX_10G_TX_ER: \ + bitMask = IMASK_TX_ER ; break; \ + case e_FM_MAC_EX_10G_RX_FIFO_OVFL: \ + bitMask = IMASK_RX_FIFO_OVFL ; break; \ + case e_FM_MAC_EX_10G_RX_ECC_ER: \ + bitMask = IMASK_RX_ECC_ER ; break; \ + case e_FM_MAC_EX_10G_RX_JAB_FRM: \ + bitMask = IMASK_RX_JAB_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_OVRSZ_FRM: \ + bitMask = IMASK_RX_OVRSZ_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_RUNT_FRM: \ + bitMask = IMASK_RX_RUNT_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_FRAG_FRM: \ + bitMask = IMASK_RX_FRAG_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_LEN_ER: \ + bitMask = IMASK_RX_LEN_ER ; break; \ + case e_FM_MAC_EX_10G_RX_CRC_ER: \ + bitMask = IMASK_RX_CRC_ER ; break; \ + case e_FM_MAC_EX_10G_RX_ALIGN_ER: \ + bitMask = IMASK_RX_ALIGN_ER ; break; \ + default: bitMask = 0;break;} + + +/* Default Config Params */ +#define DEFAULT_wanModeEnable FALSE +#define DEFAULT_promiscuousModeEnable FALSE + + +#define DEFAULT_pauseForwardEnable FALSE +#define DEFAULT_pauseIgnore FALSE +#define DEFAULT_txAddrInsEnable FALSE + +#define DEFAULT_loopbackEnable FALSE +#define DEFAULT_cmdFrameEnable FALSE +#define DEFAULT_rxErrorDiscard FALSE +#define DEFAULT_phyTxenaOn FALSE +#define DEFAULT_sendIdleEnable FALSE +#define DEFAULT_noLengthCheckEnable TRUE +#define DEFAULT_lgthCheckNostdr FALSE +#define DEFAULT_timeStampEnable FALSE +#define DEFAULT_rxSfdAny FALSE +#define DEFAULT_rxPblFwd FALSE +#define DEFAULT_txPblFwd FALSE +#define DEFAULT_txIpgLength 12 + +#define DEFAULT_maxFrameLength 0x600 + +#define DEFAULT_debugMode FALSE +#define DEFAULT_pauseTime 0xf000 +#define DEFAULT_imask 0xf000 +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +#define DEFAULT_skipFman11Workaround FALSE +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +#define DEFAULT_exceptions ((uint32_t)(IMASK_MDIO_SCAN_EVENTMDIO | \ + IMASK_REM_FAULT | \ + IMASK_LOC_FAULT | \ + IMASK_1TX_ECC_ER | \ + IMASK_TX_FIFO_UNFL | \ + IMASK_TX_FIFO_OVFL | \ + IMASK_TX_ER | \ + IMASK_RX_FIFO_OVFL | \ + IMASK_RX_ECC_ER | \ + IMASK_RX_JAB_FRM | \ + IMASK_RX_OVRSZ_FRM | \ + IMASK_RX_RUNT_FRM | \ + IMASK_RX_FRAG_FRM | \ + IMASK_RX_CRC_ER | \ + IMASK_RX_ALIGN_ER)) + +#define MAX_PACKET_ALIGNMENT 31 +#define MAX_INTER_PACKET_GAP 0x7f +#define MAX_INTER_PALTERNATE_BEB 0x0f +#define MAX_RETRANSMISSION 0x0f +#define MAX_COLLISION_WINDOW 0x03ff + + +#define TGEC_NUM_OF_PADDRS 1 /* number of pattern match registers (entries) */ + +#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ + +#define HASH_TABLE_SIZE 512 /* Hash table size (= 32 bits * 8 regs) */ + +#define TGEC_TO_MII_OFFSET 0x1030 /* Offset from the MEM map to the MDIO mem map */ + +/* 10-gigabit Ethernet MAC Controller ID (10GEC_ID) */ +#define TGEC_ID_ID 0xffff0000 +#define TGEC_ID_MAC_VERSION 0x0000FF00 +#define TGEC_ID_MAC_REV 0x000000ff + +/* Command and Configuration Register (COMMAND_CONFIG) */ +#define CMD_CFG_TX_PBL_FWD 0x00800000 /* 08 Transmit Preamble Forwarding (custom preamble). + */ +#define CMD_CFG_RX_PBL_FWD 0x00400000 /* 09 Receive Preamble Forwarding (custom preamble). + */ +#define RX_SFD_ANY 0x00200000 /* 10 Enables, when set, that any character is allowed at the SFD position of the preamble and the frame will be accepted. + */ +#define CMD_CFG_EN_TIMESTAMP 0x00100000 /* 11 EN_TIMESTAMP IEEE 1588 timeStamp functionality control. + * 0 disabled + * 1 enabled + */ +#define CMD_CFG_TX_ADDR_INS_SEL 0x00080000 /* 12 TX_ADDR_INS_SEL Transmit MAC address select + * 0 insert using first MAC address + * 1 insert using second MAC address + */ +#define CMD_CFG_LEN_CHK_NOSTDR 0x00040000 /* 13 LEN_CHK_NOSTDR + */ +#define CMD_CFG_NO_LEN_CHK 0x00020000 /* 14 NO_LEN_CHK Payload length check disable + * 0 MAC compares the frame payload length with the frame length/type field. + * 1 Payload length check is disabled. + */ +#define CMD_CFG_SEND_IDLE 0x00010000 /* 15 SEND_IDLE Force idle generation + * 0 Normal operation. + * 1 MAC permanently sends XGMII idle sequences even when faults are received. + */ +#define CMD_CFG_PHY_TX_EN 0x00008000 /* 16 PHY_TX_EN PHY transmit enable + * 0 PHY transmit is disabled. + * 1 PHY transmit is enabled. + */ +#define CMD_CFG_RX_ER_DISC 0x00004000 /* 17 RX_ER_DISC Receive error frame discard enable + * 0 Received error frames are processed. + * 1 Any frame received with an error is discarded. + */ +#define CMD_CFG_CMD_FRM_EN 0x00002000 /* 18 CMD_FRM_EN Command frame reception enable + * 0 Only Pause frames are accepted (all other command frames are rejected). + * 1 All command frames are accepted. + */ +#define CMD_CFG_STAT_CLR 0x00001000 /* 19 STAT_CLR Clear statistics + * 0 Normal operations. + * 1 All statistics counters are cleared. + */ +#define CMD_CFG_LOOPBACK_EN 0x00000400 /* 21 LOOPBAC_EN PHY interface loopback enable + * 0 Configure PHY for normal operation. + * 1 Configure PHY for loopback mode. + */ +#define CMD_CFG_TX_ADDR_INS 0x00000200 /* 22 TX_ADDR_INS Transmit source MAC address insertion + * 0 MAC transmits the source MAC address unmodified. + * 1 MAC overwrites the source MAC address with address specified by COMMAND_CONFIG[TX_ADDR_INS_SEL]. + */ +#define CMD_CFG_PAUSE_IGNORE 0x00000100 /* 23 PAUSE_IGNORE Ignore Pause frame quanta + * 0 MAC stops transmit process for the duration specified in the Pause frame quanta of a received Pause frame. + * 1 MAC ignores received Pause frames. + */ +#define CMD_CFG_PAUSE_FWD 0x00000080 /* 24 PAUSE_FWD Terminate/forward received Pause frames + * 0 MAC terminates and discards received Pause frames. + * 1 MAC forwards Pause frames to the user application. + */ +#define CMD_CFG_PROMIS_EN 0x00000010 /* 27 PROMIS_EN Promiscuous operation enable + * 0 Unicast frames with a destination address not matching the core MAC address (defined by registers, MAC_ADDR_0 and MAC_ADDR_1) are rejected. + * 1 All frames are received without any MAC address filtering. + */ +#define CMD_CFG_WAN_MODE 0x00000008 /* 28 WAN_MODE WAN mode enable + * 0 Configure MAC for LAN mode. + * 1 Configure MAC for WAN mode. + */ +#define CMD_CFG_RX_EN 0x00000002 /* 30 RX_EN MAC receive path enable + * 0 MAC receive path is disabled + * 1 MAC receive path is enabled. + */ +#define CMD_CFG_TX_EN 0x00000001 /* 31 TX_EN MAC transmit path enable + * 0 MAC transmit path is disabled + * 1 MAC transmit path is enabled. + */ + +/* Hashtable Control Register (HASHTABLE_CTRL) */ +#define HASH_CTRL_MCAST_SHIFT 23 + +#define HASH_CTRL_MCAST_RD 0x00000400 /* 22 MCAST_READ Entry Multicast frame reception for the hash entry. + * 0 disabled + * 1 enabled + */ +#define HASH_CTRL_MCAST_EN 0x00000200 /* 22 MCAST_EN Multicast frame reception for the hash entry. + * 0 disabled + * 1 enabled + */ +#define HASH_ADDR_MASK 0x000001ff /* 23-31 HASH_ADDR Hash table address code. + */ + +/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */ +#define TX_IPG_LENGTH_MASK 0x000003ff + + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/* + * 10G memory map + */ +typedef _Packed struct { +/* 10Ge General Control and Status */ + volatile uint32_t tgec_id; /* 0x000 10GEC_ID - Controller ID register */ + volatile uint32_t scratch; /* 0x004 */ + volatile uint32_t cmd_conf_ctrl; /* 0x008 COMMAND_CONFIG - Control and configuration register */ + volatile uint32_t mac_addr_0; /* 0x00C MAC_ADDR_0 - Lower 32 bits of the first 48-bit MAC address */ + volatile uint32_t mac_addr_1; /* 0x010 MAC_ADDR_1 - Upper 16 bits of the first 48-bit MAC address */ + volatile uint32_t maxfrm; /* 0x014 MAXFRM - Maximum frame length register */ + volatile uint32_t pause_quant; /* 0x018 PAUSE_QUANT - Pause quanta register */ + volatile uint32_t rx_fifo_sections; /* 0x01c */ + volatile uint32_t tx_fifo_sections; /* 0x020 */ + volatile uint32_t rx_fifo_almost_f_e; /* 0x024 */ + volatile uint32_t tx_fifo_almost_f_e; /* 0x028 */ + volatile uint32_t hashtable_ctrl; /* 0x02C HASHTABLE_CTRL - Hash table control register */ + volatile uint32_t mdio_cfg_status; /* 0x030 */ + volatile uint32_t mdio_command; /* 0x034 */ + volatile uint32_t mdio_data; /* 0x038 */ + volatile uint32_t mdio_regaddr; /* 0x03c */ + volatile uint32_t status; /* 0x040 */ + volatile uint32_t tx_ipg_len; /* 0x044 TX_IPG_LENGTH - Transmitter inter-packet-gap register */ + volatile uint32_t mac_addr_2; /* 0x048 MAC_ADDR_2 - Lower 32 bits of the second 48-bit MAC address */ + volatile uint32_t mac_addr_3; /* 0x04C MAC_ADDR_3 - Upper 16 bits of the second 48-bit MAC address */ + volatile uint32_t rx_fifo_ptr_rd; /* 0x050 */ + volatile uint32_t rx_fifo_ptr_wr; /* 0x054 */ + volatile uint32_t tx_fifo_ptr_rd; /* 0x058 */ + volatile uint32_t tx_fifo_ptr_wr; /* 0x05c */ + volatile uint32_t imask; /* 0x060 IMASK - Interrupt mask register */ + volatile uint32_t ievent; /* 0x064 IEVENT - Interrupt event register */ + volatile uint32_t udp_port; /* 0x068 Defines a UDP Port number. When an UDP/IP frame is received with a matching UDP destination port, the receive status indication pin ff_rx_ts_frm will be asserted.*/ + volatile uint32_t type_1588v2; /* 0x06c Type field for 1588v2 layer 2 frames. IEEE1588 defines the type 0x88f7 for 1588 frames. */ + volatile uint32_t TENGEC_RESERVED4[4]; +/*10Ge Statistics Counter */ + volatile uint64_t TFRM; /* 80 aFramesTransmittedOK */ + volatile uint64_t RFRM; /* 88 aFramesReceivedOK */ + volatile uint64_t RFCS; /* 90 aFrameCheckSequenceErrors */ + volatile uint64_t RALN; /* 98 aAlignmentErrors */ + volatile uint64_t TXPF; /* A0 aPAUSEMACCtrlFramesTransmitted */ + volatile uint64_t RXPF; /* A8 aPAUSEMACCtrlFramesReceived */ + volatile uint64_t RLONG; /* B0 aFrameTooLongErrors */ + volatile uint64_t RFLR; /* B8 aInRangeLengthErrors */ + volatile uint64_t TVLAN; /* C0 VLANTransmittedOK */ + volatile uint64_t RVLAN; /* C8 VLANReceivedOK */ + volatile uint64_t TOCT; /* D0 ifOutOctets */ + volatile uint64_t ROCT; /* D8 ifInOctets */ + volatile uint64_t RUCA; /* E0 ifInUcastPkts */ + volatile uint64_t RMCA; /* E8 ifInMulticastPkts */ + volatile uint64_t RBCA; /* F0 ifInBroadcastPkts */ + volatile uint64_t TERR; /* F8 ifOutErrors */ + volatile uint32_t TENGEC_RESERVED6[2]; + volatile uint64_t TUCA; /* 108 ifOutUcastPkts */ + volatile uint64_t TMCA; /* 110 ifOutMulticastPkts */ + volatile uint64_t TBCA; /* 118 ifOutBroadcastPkts */ + volatile uint64_t RDRP; /* 120 etherStatsDropEvents */ + volatile uint64_t REOCT; /* 128 etherStatsOctets */ + volatile uint64_t RPKT; /* 130 etherStatsPkts */ + volatile uint64_t TRUND; /* 138 etherStatsUndersizePkts */ + volatile uint64_t R64; /* 140 etherStatsPkts64Octets */ + volatile uint64_t R127; /* 148 etherStatsPkts65to127Octets */ + volatile uint64_t R255; /* 150 etherStatsPkts128to255Octets */ + volatile uint64_t R511; /* 158 etherStatsPkts256to511Octets */ + volatile uint64_t R1023; /* 160 etherStatsPkts512to1023Octets */ + volatile uint64_t R1518; /* 168 etherStatsPkts1024to1518Octets */ + volatile uint64_t R1519X; /* 170 etherStatsPkts1519toX */ + volatile uint64_t TROVR; /* 178 etherStatsOversizePkts */ + volatile uint64_t TRJBR; /* 180 etherStatsJabbers */ + volatile uint64_t TRFRG; /* 188 etherStatsFragments */ + volatile uint64_t RERR; /* 190 ifInErrors */ +} _PackedType t_TgecMemMap; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +typedef struct { + bool wanModeEnable; /* WAN Mode Enable. Sets WAN mode (1) or LAN mode (0, default) of operation. */ + bool promiscuousModeEnable; /* Enables MAC promiscuous operation. When set to '1', all frames are received without any MAC address filtering, when set to '0' (Reset value) Unicast Frames with a destination address not matching the Core MAC Address (MAC Address programmed in Registers MAC_ADDR_0 and MAC_ADDR_1 or the MAC address programmed in Registers MAC_ADDR_2 and MAC_ADDR_3 ) are rejected. */ + bool pauseForwardEnable; /* Terminate / Forward Pause Frames. If set to '1' pause frames are forwarded to the user application. When set to '0' (Reset value) pause frames are terminated and discarded within the MAC. */ + bool pauseIgnore; /* Ignore Pause Frame Quanta. If set to '1' received pause frames are ignored by the MAC. When set to '0' (Reset value) the transmit process is stopped for the amount of time specified in the pause quanta received within a pause frame. */ + bool txAddrInsEnable; /* Set Source MAC Address on Transmit. + If set to '1' the MAC overwrites the source MAC address received from the Client Interface with one of the MAC addresses (Refer to section 10.4) + If set to '0' (Reset value), the source MAC address from the Client Interface is transmitted unmodified to the line. */ + bool loopbackEnable; /* PHY Interface Loopback. When set to '1', the signal loop_ena is set to '1', when set to '0' (Reset value) the signal loop_ena is set to '0'. */ + bool cmdFrameEnable; /* Enables reception of all command frames. When set to '1' all Command Frames are accepted, when set to '0' (Reset Value) only Pause Frames are accepted and all other Command Frames are rejected. */ + bool rxErrorDiscard; /* Receive Errored Frame Discard Enable. When set to ‘1’, any frame received with an error is discarded in the Core and not forwarded to the Client interface. When set to ‘0’ (Reset value), errored Frames are forwarded to the Client interface with ff_rx_err asserted. */ + bool phyTxenaOn; /* PHY Transmit Enable. When set to '1', the signal phy_txena is set to '1', when set to '0' (Reset value) the signal phy_txena is set to '0' */ + bool sendIdleEnable; /* Force Idle Generation. When set to '1', the MAC permanently sends XGMII Idle sequences even when faults are received. */ + bool noLengthCheckEnable; /* Payload Length Check Disable. When set to ‘0’ (Reset value), the Core checks the frame's payload length with the Frame Length/Type field, when set to ‘1’, the payload length check is disabled. */ + bool lgthCheckNostdr; /* The Core interprets the Length/Type field differently depending on the value of this Bit */ + bool timeStampEnable; /* This bit selects between enabling and disabling the IEEE 1588 functionality. + 1: IEEE 1588 is enabled. + 0: IEEE 1588 is disabled. */ + bool rxSfdAny; /* Enables, when set, that any character is allowed at the SFD position of the preamble and the frame will be accepted. + If cleared (default) the frame is accepted only if the 8th byte of the preamble contains the SFD value 0xd5. If another value is received, the frame is discarded and the alignment error counter increments. */ + bool rxPblFwd; /* Receive Preamble Forwarding (custom preamble). + If set, the first word (ff_rx_sop) of every received frame contains the preamble of the frame. The frame data starts with the 2nd word from the FIFO. + If the bit is cleared (default) the preamble is removed from the frame before it is written into the receive FIFO. */ + bool txPblFwd; /* Transmit Preamble Forwarding (custom preamble). + If set, the first word written into the TX FIFO is considered as frame preamble. The MAC will not add a preamble in front of the frame. Note that bits 7:0 of the preamble word will still be overwritten with the XGMII start character upon transmission. + If cleared (default) the MAC */ + uint32_t txIpgLength; /*Transmit Inter-Packet-Gap (IPG) value. + A 6-bit value: Depending on LAN or WAN mode of operation (see COMMAND_CONFIG, 19.2.1 page 91) the value has the following meaning: + - LAN Mode: Number of octets in steps of 4. Valid values are 8, 12, 16, ... 100. DIC is fully supported (see 10.6.1 page 49) for any setting. A default of 12 (reset value) must be set to conform to IEEE802.3ae. Warning: When set to 8, PCS layers may not be able to perform clock rate compensation. + - WAN Mode: Stretch factor. Valid values are 4..15. The stretch factor is calculated as (value+1)*8. A default of 12 (reset value) must be set to conform to IEEE 802.3ae (i.e. 13*8=104). A larger value shrinks the IPG (increasing bandwidth). */ +/*.. */ + uint16_t maxFrameLength; + bool debugMode; + uint16_t pauseTime; +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + bool skipFman11Workaround; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ +} t_TgecDriverParam; + +typedef struct { + t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */ + t_Handle h_App; /**< Handle to the upper layer application */ + t_TgecMemMap *p_MemMap; /**< pointer to 10G memory mapped registers. */ + t_TgecMiiAccessMemMap *p_MiiMemMap; /**< pointer to MII memory mapped registers. */ + uint64_t addr; /**< MAC address of device; */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[TGEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[TGEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + t_EthHash *p_MulticastAddrHash; /**< pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /**< pointer to driver's individual address hash table */ + bool debugMode; + uint8_t macId; + uint32_t exceptions; + t_TgecDriverParam *p_TgecDriverParam; +} t_Tgec; + + +t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + + +#endif /* __TGEC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec_mii_acc.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/dtsec_mii_acc.c @@ -0,0 +1,120 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File dtsec_mii_acc.c + + @Description FM dtsec MII register access MAC ... +*//***************************************************************************/ + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "dtsec.h" + + +/*****************************************************************************/ +t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_MiiAccessMemMap *p_MiiAccess; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Dtsec->p_MiiMemMap; + + /* Stop the MII management read cycle */ + WRITE_UINT32(p_MiiAccess->miimcom, 0); + /* Dummy read to make sure MIIMCOM is written */ + tmpReg = GET_UINT32(p_MiiAccess->miimcom); + + /* Setting up MII Management Address Register */ + tmpReg = (uint32_t)((phyAddr << MIIMADD_PHY_ADDR_SHIFT) | reg); + WRITE_UINT32(p_MiiAccess->miimadd, tmpReg); + + /* Setting up MII Management Control Register with data */ + WRITE_UINT32(p_MiiAccess->miimcon, (uint32_t)data); + /* Dummy read to make sure MIIMCON is written */ + tmpReg = GET_UINT32(p_MiiAccess->miimcon); + + /* Wait till MII management write is complete */ + while ((GET_UINT32(p_MiiAccess->miimind)) & MIIMIND_BUSY) ; + + return E_OK; +} + +/*****************************************************************************/ +t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_MiiAccessMemMap *p_MiiAccess; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Dtsec->p_MiiMemMap; + + /* Setting up the MII Management Address Register */ + tmpReg = (uint32_t)((phyAddr << MIIMADD_PHY_ADDR_SHIFT) | reg); + WRITE_UINT32(p_MiiAccess->miimadd, tmpReg); + + /* Perform an MII management read cycle */ + WRITE_UINT32(p_MiiAccess->miimcom, MIIMCOM_READ_CYCLE); + /* Dummy read to make sure MIIMCOM is written */ + tmpReg = GET_UINT32(p_MiiAccess->miimcom); + + /* Wait till MII management read is complete */ + while ((GET_UINT32(p_MiiAccess->miimind)) & MIIMIND_BUSY) ; + + /* Read MII management status */ + *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->miimstat); + + WRITE_UINT32(p_MiiAccess->miimcom, 0); + /* Dummy read to make sure MIIMCOM is written */ + tmpReg = GET_UINT32(p_MiiAccess->miimcom); + + if (*p_Data == 0xffff) + RETURN_ERROR(MINOR, E_NO_DEVICE, + ("Read wrong data (0xffff): phyAddr 0x%x, reg 0x%x", + phyAddr, reg)); + + return E_OK; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec.c @@ -0,0 +1,1268 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File tgec.c + + @Description FM 10G MAC ... +*//***************************************************************************/ + +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "crc_mac_addr_ext.h" +#include "debug_ext.h" + +#include "fm_common.h" +#include "tgec.h" + + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +static t_Error CheckInitParameters(t_Tgec *p_Tgec) +{ + if(ENET_SPEED_FROM_MODE(p_Tgec->enetMode) < e_ENET_SPEED_10000) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC driver only support 10G speed")); +#if (FM_MAX_NUM_OF_10G_MACS > 0) + if(p_Tgec->macId >= FM_MAX_NUM_OF_10G_MACS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId of 10G can not be greater than 0")); +#endif + if(p_Tgec->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC Must have a valid MAC Address")); + if(!p_Tgec->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Exception")); + if(!p_Tgec->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Event")); + return E_OK; +} + +/* .............................................................................. */ + +static void SetDefaultParam(t_TgecDriverParam *p_TgecDriverParam) +{ + p_TgecDriverParam->wanModeEnable = DEFAULT_wanModeEnable; + p_TgecDriverParam->promiscuousModeEnable = DEFAULT_promiscuousModeEnable; + p_TgecDriverParam->pauseForwardEnable = DEFAULT_pauseForwardEnable; + p_TgecDriverParam->pauseIgnore = DEFAULT_pauseIgnore; + p_TgecDriverParam->txAddrInsEnable = DEFAULT_txAddrInsEnable; + + p_TgecDriverParam->loopbackEnable = DEFAULT_loopbackEnable; + p_TgecDriverParam->cmdFrameEnable = DEFAULT_cmdFrameEnable; + p_TgecDriverParam->rxErrorDiscard = DEFAULT_rxErrorDiscard; + p_TgecDriverParam->phyTxenaOn = DEFAULT_phyTxenaOn; + p_TgecDriverParam->sendIdleEnable = DEFAULT_sendIdleEnable; + p_TgecDriverParam->noLengthCheckEnable = DEFAULT_noLengthCheckEnable; + p_TgecDriverParam->lgthCheckNostdr = DEFAULT_lgthCheckNostdr; + p_TgecDriverParam->timeStampEnable = DEFAULT_timeStampEnable; + p_TgecDriverParam->rxSfdAny = DEFAULT_rxSfdAny; + p_TgecDriverParam->rxPblFwd = DEFAULT_rxPblFwd; + p_TgecDriverParam->txPblFwd = DEFAULT_txPblFwd; + + p_TgecDriverParam->txIpgLength = DEFAULT_txIpgLength; + p_TgecDriverParam->maxFrameLength = DEFAULT_maxFrameLength; + + p_TgecDriverParam->debugMode = DEFAULT_debugMode; + + p_TgecDriverParam->pauseTime = DEFAULT_pauseTime; + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + p_TgecDriverParam->skipFman11Workaround = DEFAULT_skipFman11Workaround; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ +} + +/* ........................................................................... */ + +static void TgecErrException(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t event; + t_TgecMemMap *p_TgecMemMap = p_Tgec->p_MemMap; + + event = GET_UINT32(p_TgecMemMap->ievent); + /* do not handle MDIO events */ + event &= ~(IMASK_MDIO_SCAN_EVENTMDIO | IMASK_MDIO_CMD_CMPL); + + event &= GET_UINT32(p_TgecMemMap->imask); + + WRITE_UINT32(p_TgecMemMap->ievent, event); + + if (event & IMASK_REM_FAULT) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_REM_FAULT); + if (event & IMASK_LOC_FAULT) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_LOC_FAULT); + if (event & IMASK_1TX_ECC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER); + if (event & IMASK_TX_FIFO_UNFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_UNFL); + if (event & IMASK_TX_FIFO_OVFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_OVFL); + if (event & IMASK_TX_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_ER); + if (event & IMASK_RX_FIFO_OVFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FIFO_OVFL); + if (event & IMASK_RX_ECC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ECC_ER); + if (event & IMASK_RX_JAB_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_JAB_FRM); + if (event & IMASK_RX_OVRSZ_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_OVRSZ_FRM); + if (event & IMASK_RX_RUNT_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_RUNT_FRM); + if (event & IMASK_RX_FRAG_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FRAG_FRM); + if (event & IMASK_RX_LEN_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_LEN_ER); + if (event & IMASK_RX_CRC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_CRC_ER); + if (event & IMASK_RX_ALIGN_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ALIGN_ER); +} + +static void TgecException(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t event; + t_TgecMemMap *p_TgecMemMap = p_Tgec->p_MemMap; + + event = GET_UINT32(p_TgecMemMap->ievent); + /* handle only MDIO events */ + event &= (IMASK_MDIO_SCAN_EVENTMDIO | IMASK_MDIO_CMD_CMPL); + event &= GET_UINT32(p_TgecMemMap->imask); + + WRITE_UINT32(p_TgecMemMap->ievent, event); + + if(event & IMASK_MDIO_SCAN_EVENTMDIO) + p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO); + if(event & IMASK_MDIO_CMD_CMPL) + p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_CMD_CMPL); +} + +static void FreeInitResources(t_Tgec *p_Tgec) +{ + if ((p_Tgec->mdioIrq != 0) && (p_Tgec->mdioIrq != NO_IRQ)) + { + XX_DisableIntr(p_Tgec->mdioIrq); + XX_FreeIntr(p_Tgec->mdioIrq); + } + else if (p_Tgec->mdioIrq == 0) + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, (NO_MSG)); + FmUnregisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Tgec->macId, e_FM_INTR_TYPE_ERR); + + /* release the driver's group hash table */ + FreeHashTable(p_Tgec->p_MulticastAddrHash); + p_Tgec->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Tgec->p_UnicastAddrHash); + p_Tgec->p_UnicastAddrHash = NULL; +} + +/* .............................................................................. */ + +static void HardwareClearAddrInPaddr(t_Tgec *p_Tgec, uint8_t paddrNum) +{ + if (paddrNum != 0) + return; /* At this time MAC has only one address */ + + WRITE_UINT32(p_Tgec->p_MemMap->mac_addr_2, 0x0); + WRITE_UINT32(p_Tgec->p_MemMap->mac_addr_3, 0x0); +} + +/* ........................................................................... */ + +static void HardwareAddAddrInPaddr(t_Tgec *p_Tgec, uint64_t *p_Addr, uint8_t paddrNum) +{ + uint32_t tmpReg32 = 0; + uint64_t addr = *p_Addr; + t_TgecMemMap *p_TgecMemMap = p_Tgec->p_MemMap; + + if (paddrNum != 0) + return; /* At this time MAC has only one address */ + + tmpReg32 = (uint32_t)(addr>>16); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_TgecMemMap->mac_addr_2, tmpReg32); + + tmpReg32 = (uint32_t)(addr); + SwapUint32P(&tmpReg32); + tmpReg32 >>= 16; + WRITE_UINT32(p_TgecMemMap->mac_addr_3, tmpReg32); +} + +/*****************************************************************************/ +/* 10G MAC API routines */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error TgecEnable(t_Handle h_Tgec, e_CommMode mode) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_MemMap ; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_INVALID_HANDLE); + + p_MemMap= (t_TgecMemMap*)(p_Tgec->p_MemMap); + + tmpReg32 = GET_UINT32(p_MemMap->cmd_conf_ctrl); + + switch (mode) + { + case e_COMM_MODE_NONE: + tmpReg32 &= ~(CMD_CFG_TX_EN | CMD_CFG_RX_EN); + break; + case e_COMM_MODE_RX : + tmpReg32 |= CMD_CFG_RX_EN ; + break; + case e_COMM_MODE_TX : + tmpReg32 |= CMD_CFG_TX_EN ; + break; + case e_COMM_MODE_RX_AND_TX: + tmpReg32 |= (CMD_CFG_TX_EN | CMD_CFG_RX_EN); + break; + } + + WRITE_UINT32(p_MemMap->cmd_conf_ctrl, tmpReg32); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecDisable (t_Handle h_Tgec, e_CommMode mode) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_MemMap ; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_INVALID_HANDLE); + + p_MemMap= (t_TgecMemMap*)(p_Tgec->p_MemMap); + + tmpReg32 = GET_UINT32(p_MemMap->cmd_conf_ctrl); + switch (mode) + { + case e_COMM_MODE_RX: + tmpReg32 &= ~CMD_CFG_RX_EN; + break; + case e_COMM_MODE_TX: + tmpReg32 &= ~CMD_CFG_TX_EN; + break; + case e_COMM_MODE_RX_AND_TX: + tmpReg32 &= ~(CMD_CFG_TX_EN | CMD_CFG_RX_EN); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); + } + WRITE_UINT32(p_MemMap->cmd_conf_ctrl, tmpReg32); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecSetPromiscuous(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + + tmpReg32 = GET_UINT32(p_TgecMemMap->cmd_conf_ctrl); + + if (newVal) + tmpReg32 |= CMD_CFG_PROMIS_EN; + else + tmpReg32 &= ~CMD_CFG_PROMIS_EN; + + WRITE_UINT32(p_TgecMemMap->cmd_conf_ctrl, tmpReg32); + + return E_OK; +} + + +/*****************************************************************************/ +/* Tgec Configs modification functions */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error TgecConfigLoopback(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + +#ifdef FM_NO_TGEC_LOOPBACK + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("no loopback in this chip rev!")); + } +#endif /* FM_NO_TGEC_LOOPBACK */ + + p_Tgec->p_TgecDriverParam->loopbackEnable = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecConfigWan(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->wanModeEnable = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecConfigMaxFrameLength(t_Handle h_Tgec, uint16_t newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->maxFrameLength = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecConfigLengthCheck(t_Handle h_Tgec, bool newVal) +{ +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 +UNUSED(h_Tgec); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); + +#else + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + UNUSED(newVal); + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->noLengthCheckEnable = !newVal; + + return E_OK; +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ +} + +/* .............................................................................. */ + +static t_Error TgecConfigException(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); +#ifdef FM_10G_REM_N_LCL_FLT_EX_ERRATA_10GMAC001 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &revInfo); + if((revInfo.majorRev <=2) && + enable && + ((exception == e_FM_MAC_EX_10G_LOC_FAULT) || (exception == e_FM_MAC_EX_10G_REM_FAULT))) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_MAC_EX_10G_LOC_FAULT and e_FM_MAC_EX_10G_REM_FAULT !")); + } +#endif /* FM_10G_REM_N_LCL_FLT_EX_ERRATA_10GMAC001 */ + + GET_EXCEPTION_FLAG(bitMask, exception); + if(bitMask) + { + if (enable) + p_Tgec->exceptions |= bitMask; + else + p_Tgec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +/* .............................................................................. */ + +static t_Error TgecConfigSkipFman11Workaround(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->skipFman11Workaround = TRUE; + + return E_OK; +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + +/*****************************************************************************/ +/* Tgec Run Time API functions */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error TgecTxMacPause(t_Handle h_Tgec, uint16_t pauseTime) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t ptv = 0; + t_TgecMemMap *p_MemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_INVALID_STATE); + + p_MemMap = (t_TgecMemMap*)(p_Tgec->p_MemMap); + + ptv = (uint32_t)pauseTime; + + WRITE_UINT32(p_MemMap->pause_quant, ptv); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecRxIgnoreMacPause(t_Handle h_Tgec, bool en) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_MemMap; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_INVALID_STATE); + + p_MemMap = (t_TgecMemMap*)(p_Tgec->p_MemMap); + tmpReg32 = GET_UINT32(p_MemMap->cmd_conf_ctrl); + if (en) + tmpReg32 |= CMD_CFG_PAUSE_IGNORE; + else + tmpReg32 &= ~CMD_CFG_PAUSE_IGNORE; + WRITE_UINT32(p_MemMap->cmd_conf_ctrl, tmpReg32); + + return E_OK; +} + +/* Counters handling */ +/* .............................................................................. */ + +static t_Error TgecGetStatistics(t_Handle h_Tgec, t_FmMacStatistics *p_Statistics) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + + p_Statistics->eStatPkts64 = GET_UINT64(p_TgecMemMap->R64); + p_Statistics->eStatPkts65to127 = GET_UINT64(p_TgecMemMap->R127); + p_Statistics->eStatPkts128to255 = GET_UINT64(p_TgecMemMap->R255); + p_Statistics->eStatPkts256to511 = GET_UINT64(p_TgecMemMap->R511); + p_Statistics->eStatPkts512to1023 = GET_UINT64(p_TgecMemMap->R1023); + p_Statistics->eStatPkts1024to1518 = GET_UINT64(p_TgecMemMap->R1518); + p_Statistics->eStatPkts1519to1522 = GET_UINT64(p_TgecMemMap->R1519X); +/* */ + p_Statistics->eStatFragments = GET_UINT64(p_TgecMemMap->TRFRG); + p_Statistics->eStatJabbers = GET_UINT64(p_TgecMemMap->TRJBR); + + p_Statistics->eStatsDropEvents = GET_UINT64(p_TgecMemMap->RDRP); + p_Statistics->eStatCRCAlignErrors = GET_UINT64(p_TgecMemMap->RALN); + + p_Statistics->eStatUndersizePkts = GET_UINT64(p_TgecMemMap->TRUND); + p_Statistics->eStatOversizePkts = GET_UINT64(p_TgecMemMap->TROVR); +/* Pause */ + p_Statistics->reStatPause = GET_UINT64(p_TgecMemMap->RXPF); + p_Statistics->teStatPause = GET_UINT64(p_TgecMemMap->TXPF); + + +/* MIB II */ + p_Statistics->ifInOctets = GET_UINT64(p_TgecMemMap->ROCT); + p_Statistics->ifInMcastPkts = GET_UINT64(p_TgecMemMap->RMCA); + p_Statistics->ifInBcastPkts = GET_UINT64(p_TgecMemMap->RBCA); + p_Statistics->ifInPkts = GET_UINT64(p_TgecMemMap->RUCA) + + p_Statistics->ifInMcastPkts + + p_Statistics->ifInBcastPkts; + p_Statistics->ifInDiscards = 0; + p_Statistics->ifInErrors = GET_UINT64(p_TgecMemMap->RERR); + + p_Statistics->ifOutOctets = GET_UINT64(p_TgecMemMap->TOCT); + p_Statistics->ifOutMcastPkts = GET_UINT64(p_TgecMemMap->TMCA); + p_Statistics->ifOutBcastPkts = GET_UINT64(p_TgecMemMap->TBCA); + p_Statistics->ifOutPkts = GET_UINT64(p_TgecMemMap->TUCA); + p_Statistics->ifOutDiscards = 0; + p_Statistics->ifOutErrors = GET_UINT64(p_TgecMemMap->TERR); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecEnable1588TimeStamp(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_TgecMemMap = p_Tgec->p_MemMap; + SANITY_CHECK_RETURN_ERROR(p_TgecMemMap, E_INVALID_HANDLE); + + WRITE_UINT32(p_TgecMemMap->cmd_conf_ctrl, GET_UINT32(p_TgecMemMap->cmd_conf_ctrl) | CMD_CFG_EN_TIMESTAMP); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecDisable1588TimeStamp(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_TgecMemMap = p_Tgec->p_MemMap; + SANITY_CHECK_RETURN_ERROR(p_TgecMemMap, E_INVALID_HANDLE); + + WRITE_UINT32(p_TgecMemMap->cmd_conf_ctrl, GET_UINT32(p_TgecMemMap->cmd_conf_ctrl) & ~CMD_CFG_EN_TIMESTAMP); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecModifyMacAddress (t_Handle h_Tgec, t_EnetAddr *p_EnetAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + uint32_t tmpReg32 = 0; + uint64_t addr; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + + /* Initialize MAC Station Address registers (1 & 2) */ + /* Station address have to be swapped (big endian to little endian */ + + addr = ((*(uint64_t *)p_EnetAddr) >> 16); + p_Tgec->addr = addr; + + tmpReg32 = (uint32_t)(addr>>16); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_TgecMemMap->mac_addr_0, tmpReg32); + + tmpReg32 = (uint32_t)(addr); + SwapUint32P(&tmpReg32); + tmpReg32 >>= 16; + WRITE_UINT32(p_TgecMemMap->mac_addr_1, tmpReg32); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecResetCounters (t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_MemMap ; + uint32_t tmpReg32, cmdConfCtrl; + int i; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_INVALID_HANDLE); + + p_MemMap= (t_TgecMemMap*)(p_Tgec->p_MemMap); + + cmdConfCtrl = GET_UINT32(p_MemMap->cmd_conf_ctrl); + + cmdConfCtrl |= CMD_CFG_STAT_CLR; + + WRITE_UINT32(p_MemMap->cmd_conf_ctrl, cmdConfCtrl); + + for (i=0; i<1000; i++) + { + tmpReg32 = GET_UINT32(p_MemMap->cmd_conf_ctrl); + if (!(tmpReg32 & CMD_CFG_STAT_CLR)) + break; + } + + cmdConfCtrl &= ~CMD_CFG_STAT_CLR; + WRITE_UINT32(p_MemMap->cmd_conf_ctrl, cmdConfCtrl); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecAddExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + { + if (p_Tgec->indAddrRegUsed[paddrNum]) + { + if (p_Tgec->paddr[paddrNum] == ethAddr) + { + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + } + } + } + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + { + if (!(p_Tgec->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Tgec->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Tgec->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + HardwareAddAddrInPaddr(p_Tgec, ðAddr, paddrNum); + p_Tgec->numOfIndAddrInRegs++; + + return E_OK; + } + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error TgecDelExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_INVALID_HANDLE); + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Tgec->indAddrRegUsed[paddrNum]) && + (p_Tgec->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Tgec->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + HardwareClearAddrInPaddr(p_Tgec, paddrNum); + p_Tgec->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error TgecAddHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + t_EthHashEntry *p_HashEntry; + uint32_t crc; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + if (!(ethAddr & GROUP_ADDRESS)) + /* Unicast addresses not supported in hash */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address")); + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + crc = MIRROR_32(crc); + + hash = (crc >> HASH_CTRL_MCAST_SHIFT) & HASH_ADDR_MASK; /* Take 9 MSB bits */ + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + LIST_AddToTail(&(p_HashEntry->node), &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])); + WRITE_UINT32(p_TgecMemMap->hashtable_ctrl, (hash | HASH_CTRL_MCAST_EN)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecDelHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + t_EthHashEntry *p_HashEntry = NULL; + t_List *p_Pos; + uint32_t crc; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + crc = MIRROR_32(crc); + + hash = (crc >> HASH_CTRL_MCAST_SHIFT) & HASH_ADDR_MASK; /* Take 9 MSB bits */ + + LIST_FOR_EACH(p_Pos, &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) + { + + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if(p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if(LIST_IsEmpty(&p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) + WRITE_UINT32(p_TgecMemMap->hashtable_ctrl, (hash & ~HASH_CTRL_MCAST_EN)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecGetId(t_Handle h_Tgec, uint32_t *macId) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_NULL_POINTER); + + UNUSED(p_Tgec); + UNUSED(macId); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("TgecGetId Not Supported")); +} + +/* .............................................................................. */ + +static t_Error TgecGetVersion(t_Handle h_Tgec, uint32_t *macVersion) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMemMap *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + *macVersion = GET_UINT32(p_TgecMemMap->tgec_id); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecSetExcpetion(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t bitMask = 0, tmpReg; + t_TgecMemMap *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; +#ifdef FM_10G_REM_N_LCL_FLT_EX_ERRATA_10GMAC001 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &revInfo); + if((revInfo.majorRev <=2) && + enable && + ((exception == e_FM_MAC_EX_10G_LOC_FAULT) || (exception == e_FM_MAC_EX_10G_REM_FAULT))) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("e_FM_MAC_EX_10G_LOC_FAULT and e_FM_MAC_EX_10G_REM_FAULT !")); + } +#endif /* FM_10G_REM_N_LCL_FLT_EX_ERRATA_10GMAC001 */ + + GET_EXCEPTION_FLAG(bitMask, exception); + if(bitMask) + { + if (enable) + p_Tgec->exceptions |= bitMask; + else + p_Tgec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + tmpReg = GET_UINT32(p_TgecMemMap->imask); + if(enable) + tmpReg |= bitMask; + else + tmpReg &= ~bitMask; + WRITE_UINT32(p_TgecMemMap->imask, tmpReg); + return E_OK; +} + +/* .............................................................................. */ + +static uint16_t TgecGetMaxFrameLength(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_VALUE(p_Tgec, E_INVALID_HANDLE, 0); + + return (uint16_t)GET_UINT32(p_Tgec->p_MemMap->maxfrm); +} + +/* .............................................................................. */ + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +static t_Error TgecTxEccWorkaround(t_Tgec *p_Tgec) +{ + t_Error err; + + XX_Print("Applying 10G tx-ecc error workaround (10GMAC-A004) ..."); + /* enable and set promiscuous */ + WRITE_UINT32(p_Tgec->p_MemMap->cmd_conf_ctrl, CMD_CFG_PROMIS_EN | CMD_CFG_TX_EN | CMD_CFG_RX_EN); + err = Fm10GTxEccWorkaround(p_Tgec->fmMacControllerDriver.h_Fm, p_Tgec->macId); + /* disable */ + WRITE_UINT32(p_Tgec->p_MemMap->cmd_conf_ctrl, 0); + if (err) + XX_Print("FAILED!\n"); + else + XX_Print("done.\n"); + TgecResetCounters (p_Tgec); + + return err; +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +/* .............................................................................. */ + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +static t_Error TgecDumpRegs(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + DECLARE_DUMP; + + if (p_Tgec->p_MemMap) + { + DUMP_TITLE(p_Tgec->p_MemMap, ("10G MAC %d: ", p_Tgec->macId)); + DUMP_VAR(p_Tgec->p_MemMap, tgec_id); + DUMP_VAR(p_Tgec->p_MemMap, scratch); + DUMP_VAR(p_Tgec->p_MemMap, cmd_conf_ctrl); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_0); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_1); + DUMP_VAR(p_Tgec->p_MemMap, maxfrm); + DUMP_VAR(p_Tgec->p_MemMap, pause_quant); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_sections); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_sections); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_almost_f_e); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_almost_f_e); + DUMP_VAR(p_Tgec->p_MemMap, hashtable_ctrl); + DUMP_VAR(p_Tgec->p_MemMap, mdio_cfg_status); + DUMP_VAR(p_Tgec->p_MemMap, mdio_command); + DUMP_VAR(p_Tgec->p_MemMap, mdio_data); + DUMP_VAR(p_Tgec->p_MemMap, mdio_regaddr); + DUMP_VAR(p_Tgec->p_MemMap, status); + DUMP_VAR(p_Tgec->p_MemMap, tx_ipg_len); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_2); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_3); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_ptr_rd); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_ptr_wr); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_ptr_rd); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_ptr_wr); + DUMP_VAR(p_Tgec->p_MemMap, imask); + DUMP_VAR(p_Tgec->p_MemMap, ievent); + DUMP_VAR(p_Tgec->p_MemMap, udp_port); + DUMP_VAR(p_Tgec->p_MemMap, type_1588v2); + } + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + + +/*****************************************************************************/ +/* FM Init & Free API */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error TgecInit(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecDriverParam *p_TgecDriverParam; + t_TgecMemMap *p_MemMap; + uint64_t addr; + uint32_t tmpReg32; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MemMap, E_INVALID_HANDLE); + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + if (!p_Tgec->p_TgecDriverParam->skipFman11Workaround && + ((err = TgecTxEccWorkaround(p_Tgec)) != E_OK)) +#ifdef NCSW_LINUX + { + /* the workaround fails in simics, just report and continue initialization */ + REPORT_ERROR(MAJOR, err, ("TgecTxEccWorkaround FAILED, skipping workaround")); + } +#else + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, err, ("TgecTxEccWorkaround FAILED")); + } +#endif +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + CHECK_INIT_PARAMETERS(p_Tgec, CheckInitParameters); + + p_TgecDriverParam = p_Tgec->p_TgecDriverParam; + p_MemMap = p_Tgec->p_MemMap; + + /* MAC Address */ + addr = p_Tgec->addr; + tmpReg32 = (uint32_t)(addr>>16); + SwapUint32P(&tmpReg32); + WRITE_UINT32(p_MemMap->mac_addr_0, tmpReg32); + + tmpReg32 = (uint32_t)(addr); + SwapUint32P(&tmpReg32); + tmpReg32 >>= 16; + WRITE_UINT32(p_MemMap->mac_addr_1, tmpReg32); + + /* Config */ + tmpReg32 = 0; + if (p_TgecDriverParam->wanModeEnable) + tmpReg32 |= CMD_CFG_WAN_MODE; + if (p_TgecDriverParam->promiscuousModeEnable) + tmpReg32 |= CMD_CFG_PROMIS_EN; + if (p_TgecDriverParam->pauseForwardEnable) + tmpReg32 |= CMD_CFG_PAUSE_FWD; + if (p_TgecDriverParam->pauseIgnore) + tmpReg32 |= CMD_CFG_PAUSE_IGNORE; + if (p_TgecDriverParam->txAddrInsEnable) + tmpReg32 |= CMD_CFG_TX_ADDR_INS; + if (p_TgecDriverParam->loopbackEnable) + tmpReg32 |= CMD_CFG_LOOPBACK_EN; + if (p_TgecDriverParam->cmdFrameEnable) + tmpReg32 |= CMD_CFG_CMD_FRM_EN; + if (p_TgecDriverParam->rxErrorDiscard) + tmpReg32 |= CMD_CFG_RX_ER_DISC; + if (p_TgecDriverParam->phyTxenaOn) + tmpReg32 |= CMD_CFG_PHY_TX_EN; + if (p_TgecDriverParam->sendIdleEnable) + tmpReg32 |= CMD_CFG_SEND_IDLE; + if (p_TgecDriverParam->noLengthCheckEnable) + tmpReg32 |= CMD_CFG_NO_LEN_CHK; + if (p_TgecDriverParam->lgthCheckNostdr) + tmpReg32 |= CMD_CFG_LEN_CHK_NOSTDR; + if (p_TgecDriverParam->timeStampEnable) + tmpReg32 |= CMD_CFG_EN_TIMESTAMP; + if (p_TgecDriverParam->rxSfdAny) + tmpReg32 |= RX_SFD_ANY; + if (p_TgecDriverParam->rxPblFwd) + tmpReg32 |= CMD_CFG_RX_PBL_FWD; + if (p_TgecDriverParam->txPblFwd) + tmpReg32 |= CMD_CFG_TX_PBL_FWD; + tmpReg32 |= 0x40; + WRITE_UINT32(p_MemMap->cmd_conf_ctrl, tmpReg32); + + /* Max Frame Length */ + WRITE_UINT32(p_MemMap->maxfrm, (uint32_t)p_TgecDriverParam->maxFrameLength); + err = FmSetMacMaxFrame(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MAC_10G, p_Tgec->fmMacControllerDriver.macId, p_TgecDriverParam->maxFrameLength); + if(err) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /* Pause Time */ + WRITE_UINT32(p_MemMap->pause_quant, p_TgecDriverParam->pauseTime); + +#ifdef FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 + WRITE_UINT32(p_Tgec->p_MemMap->tx_ipg_len, + (GET_UINT32(p_Tgec->p_MemMap->tx_ipg_len) & ~TX_IPG_LENGTH_MASK) | DEFAULT_txIpgLength); +#endif /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 */ + + /* Configure MII */ + tmpReg32 = GET_UINT32(p_Tgec->p_MiiMemMap->mdio_cfg_status); +#ifdef FM_10G_MDIO_HOLD_ERRATA_XAUI3 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + tmpReg32 |= (MIIMCOM_MDIO_HOLD_4_REG_CLK << 2); + } +#endif /* FM_10G_MDIO_HOLD_ERRATA_XAUI3 */ + tmpReg32 &= ~MIIMCOM_DIV_MASK; + /* (one half of fm clock => 2.5Mhz) */ + tmpReg32 |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT); + WRITE_UINT32(p_Tgec->p_MiiMemMap->mdio_cfg_status, tmpReg32); + + p_Tgec->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if(!p_Tgec->p_MulticastAddrHash) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + p_Tgec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if(!p_Tgec->p_UnicastAddrHash) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + /* interrupts */ +#ifdef FM_10G_REM_N_LCL_FLT_EX_ERRATA_10GMAC001 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &revInfo); + if (revInfo.majorRev <=2) + p_Tgec->exceptions &= ~(IMASK_REM_FAULT | IMASK_LOC_FAULT); + } +#endif /* FM_10G_REM_N_LCL_FLT_EX_ERRATA_10GMAC001 */ + WRITE_UINT32(p_MemMap->ievent, EVENTS_MASK); + WRITE_UINT32(p_MemMap->imask, p_Tgec->exceptions); + + FmRegisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Tgec->macId, e_FM_INTR_TYPE_ERR, TgecErrException , p_Tgec); + if ((p_Tgec->mdioIrq != 0) && (p_Tgec->mdioIrq != NO_IRQ)) + { + XX_SetIntr(p_Tgec->mdioIrq, TgecException, p_Tgec); + XX_EnableIntr(p_Tgec->mdioIrq); + } + else if (p_Tgec->mdioIrq == 0) + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, (NO_MSG)); + + XX_Free(p_TgecDriverParam); + p_Tgec->p_TgecDriverParam = NULL; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error TgecFree(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + + FreeInitResources(p_Tgec); + + if (p_Tgec->p_TgecDriverParam) + { + XX_Free(p_Tgec->p_TgecDriverParam); + p_Tgec->p_TgecDriverParam = NULL; + } + XX_Free (p_Tgec); + + return E_OK; +} + +/* .............................................................................. */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = TgecInit; + p_FmMacControllerDriver->f_FM_MAC_Free = TgecFree; + + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = TgecConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = TgecConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = TgecConfigWan; + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = NULL; /* TGEC always works with pad+crc */ + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is not supported in xgec */ + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = TgecConfigLengthCheck; + p_FmMacControllerDriver->f_FM_MAC_ConfigException = TgecConfigException; + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround= TgecConfigSkipFman11Workaround; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + p_FmMacControllerDriver->f_FM_MAC_SetException = TgecSetExcpetion; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = TgecEnable1588TimeStamp; + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = TgecDisable1588TimeStamp; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = TgecSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = NULL; + + p_FmMacControllerDriver->f_FM_MAC_Enable = TgecEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = TgecDisable; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = TgecTxMacPause; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = TgecRxIgnoreMacPause; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = TgecResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = TgecGetStatistics; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = TgecModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = TgecAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = TgecDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = TgecAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = TgecDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = TgecGetId; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = TgecGetVersion; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = TgecGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = TGEC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = TGEC_MII_ReadPhyReg; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + p_FmMacControllerDriver->f_FM_MAC_DumpRegs = TgecDumpRegs; +#endif /* (defined(DEBUG_ERRORS) && ... */ +} + + +/*****************************************************************************/ +/* Tgec Config Main Entry */ +/*****************************************************************************/ + +/* .............................................................................. */ + +t_Handle TGEC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Tgec *p_Tgec; + t_TgecDriverParam *p_TgecDriverParam; + uintptr_t baseAddr; + uint8_t i; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + /* allocate memory for the UCC GETH data structure. */ + p_Tgec = (t_Tgec *) XX_Malloc(sizeof(t_Tgec)); + if (!p_Tgec) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver structure")); + return NULL; + } + /* Zero out * p_Tgec */ + memset(p_Tgec, 0, sizeof(t_Tgec)); + InitFmMacControllerDriver(&p_Tgec->fmMacControllerDriver); + + /* allocate memory for the 10G MAC driver parameters data structure. */ + p_TgecDriverParam = (t_TgecDriverParam *) XX_Malloc(sizeof(t_TgecDriverParam)); + if (!p_TgecDriverParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver parameters")); + TgecFree(p_Tgec); + return NULL; + } + /* Zero out */ + memset(p_TgecDriverParam, 0, sizeof(t_TgecDriverParam)); + + /* Plant parameter structure pointer */ + p_Tgec->p_TgecDriverParam = p_TgecDriverParam; + + SetDefaultParam(p_TgecDriverParam); + + for (i=0; i < sizeof(p_FmMacParam->addr); i++) + p_Tgec->addr |= ((uint64_t)p_FmMacParam->addr[i] << ((5-i) * 8)); + + p_Tgec->p_MemMap = (t_TgecMemMap *)UINT_TO_PTR(baseAddr); + p_Tgec->p_MiiMemMap = (t_TgecMiiAccessMemMap *)UINT_TO_PTR(baseAddr + TGEC_TO_MII_OFFSET); + p_Tgec->enetMode = p_FmMacParam->enetMode; + p_Tgec->macId = p_FmMacParam->macId; + p_Tgec->exceptions = DEFAULT_exceptions; + p_Tgec->mdioIrq = p_FmMacParam->mdioIrq; + p_Tgec->f_Exception = p_FmMacParam->f_Exception; + p_Tgec->f_Event = p_FmMacParam->f_Event; + p_Tgec->h_App = p_FmMacParam->h_App; + + return p_Tgec; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec_mii_acc.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec_mii_acc.c @@ -0,0 +1,121 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "tgec.h" +#include "xx_ext.h" + + +/*****************************************************************************/ +t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMiiAccessMemMap *p_MiiAccess; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Tgec->p_MiiMemMap; + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); + + WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_data, data); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) + XX_UDelay (1); + + return E_OK; +} + +/*****************************************************************************/ +t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMiiAccessMemMap *p_MiiAccess; + uint32_t cfg_status; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Tgec->p_MiiMemMap; + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); + + WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, (uint32_t)(phyAddr | MIIMCOM_READ_CYCLE)); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) + XX_UDelay (1); + + *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->mdio_data); + + cfg_status = GET_UINT32(p_MiiAccess->mdio_cfg_status); + + if (cfg_status & MIIMIND_READ_ERROR) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("Read Error: phyAddr 0x%x, dev 0x%x, reg 0x%x, cfg_status 0x%x", + ((phyAddr & 0xe0)>>5), (phyAddr & 0x1f), reg, cfg_status)); + + return E_OK; +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk +NCSW_FM_INC = $(srctree)/drivers/net/dpa/NetCommSw/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-MAC.o + +fsl-ncsw-MAC-objs := dtsec.o dtsec_mii_acc.o fm_mac.o tgec.o tgec_mii_acc.o --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/fm_mac.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/fm_mac.c @@ -0,0 +1,560 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_mac.c + + @Description FM MAC ... +*//***************************************************************************/ +#include "std_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "error_ext.h" +#include "fm_ext.h" + +#include "fm_common.h" +#include "fm_mac.h" + + +/* ........................................................................... */ + +t_Handle FM_MAC_Config (t_FmMacParams *p_FmMacParam) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_INVALID_HANDLE, NULL); + + if(ENET_SPEED_FROM_MODE(p_FmMacParam->enetMode) < e_ENET_SPEED_10000) + p_FmMacControllerDriver = (t_FmMacControllerDriver *)DTSEC_Config(p_FmMacParam); + else + p_FmMacControllerDriver = (t_FmMacControllerDriver *)TGEC_Config(p_FmMacParam); + + if (!p_FmMacControllerDriver) + return NULL; + + p_FmMacControllerDriver->h_Fm = p_FmMacParam->h_Fm; + p_FmMacControllerDriver->enetMode = p_FmMacParam->enetMode; + p_FmMacControllerDriver->macId = p_FmMacParam->macId; + p_FmMacControllerDriver->resetOnInit = DEFAULT_resetOnInit; + + return (t_Handle)p_FmMacControllerDriver; +} + +/* ........................................................................... */ + +t_Error FM_MAC_Init (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->resetOnInit && + (FmResetMac(p_FmMacControllerDriver->h_Fm, + ((ENET_INTERFACE_FROM_MODE(p_FmMacControllerDriver->enetMode) == e_ENET_IF_XGMII) ? e_FM_MAC_10G : e_FM_MAC_1G), + p_FmMacControllerDriver->macId) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't reset MAC!")); + + if ((p_FmMacControllerDriver->clkFreq = FmGetClockFreq(p_FmMacControllerDriver->h_Fm)) == 0) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't get clock for MAC!")); + + if (p_FmMacControllerDriver->f_FM_MAC_Init) + return p_FmMacControllerDriver->f_FM_MAC_Init(h_FmMac); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_Free (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Free) + return p_FmMacControllerDriver->f_FM_MAC_Free(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigResetOnInit (t_Handle h_FmMac, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + p_FmMacControllerDriver->resetOnInit = enable; + + return E_OK; +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigLoopback (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback) + return p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigMaxFrameLength (t_Handle h_FmMac, uint16_t newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength) + return p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength(h_FmMac, newVal); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigWan (t_Handle h_FmMac, bool flag) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigWan) + return p_FmMacControllerDriver->f_FM_MAC_ConfigWan(h_FmMac, flag); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigPadAndCrc (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc) + return p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigHalfDuplex (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex) + return p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigLengthCheck (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck) + return p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ConfigException (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigException) + return p_FmMacControllerDriver->f_FM_MAC_ConfigException(h_FmMac, ex, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +/* ........................................................................... */ + +t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround) + return p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + +/*****************************************************************************/ +/* Run Time Control */ +/*****************************************************************************/ + +/* ........................................................................... */ + +t_Error FM_MAC_Enable (t_Handle h_FmMac, e_CommMode mode) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Enable) + return p_FmMacControllerDriver->f_FM_MAC_Enable(h_FmMac, mode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_Disable (t_Handle h_FmMac, e_CommMode mode) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Disable) + return p_FmMacControllerDriver->f_FM_MAC_Disable(h_FmMac, mode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_Enable1588TimeStamp (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp) + return p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_Disable1588TimeStamp (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp) + return p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_SetTxAutoPauseFrames (t_Handle h_FmMac, uint16_t pauseTime) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames(h_FmMac, pauseTime); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_SetRxIgnorePauseFrames (t_Handle h_FmMac, bool en) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames(h_FmMac, en); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ResetCounters (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ResetCounters) + return p_FmMacControllerDriver->f_FM_MAC_ResetCounters(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetException) + return p_FmMacControllerDriver->f_FM_MAC_SetException(h_FmMac, ex, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_SetStatistics (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetStatistics) + return p_FmMacControllerDriver->f_FM_MAC_SetStatistics(h_FmMac, statisticsLevel); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_GetStatistics (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetStatistics) + return p_FmMacControllerDriver->f_FM_MAC_GetStatistics(h_FmMac, p_Statistics); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_AddHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_RemoveHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_AddExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_RemovelExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_GetVesrion (t_Handle h_FmMac, uint32_t *macVresion) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetVersion) + return p_FmMacControllerDriver->f_FM_MAC_GetVersion(h_FmMac, macVresion); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + +} + +/* ........................................................................... */ + +t_Error FM_MAC_GetId (t_Handle h_FmMac, uint32_t *macId) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetId) + return p_FmMacControllerDriver->f_FM_MAC_GetId(h_FmMac, macId); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_SetPromiscuous (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous) + return p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AdjustLink) + return p_FmMacControllerDriver->f_FM_MAC_AdjustLink(h_FmMac, speed, fullDuplex); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_MII_WritePhyReg (t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg) + return p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg(h_FmMac, phyAddr, reg, data); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg) + return p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg(h_FmMac, phyAddr, reg, p_Data); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ........................................................................... */ + +uint16_t FM_MAC_GetMaxFrameLength(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_VALUE(p_FmMacControllerDriver, E_INVALID_HANDLE, 0); + + if (p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength) + return p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength(h_FmMac); + + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + return 0; +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/*****************************************************************************/ +t_Error FM_MAC_DumpRegs(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_DumpRegs) + return p_FmMacControllerDriver->f_FM_MAC_DumpRegs(h_FmMac); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} +#endif /* (defined(DEBUG_ERRORS) && ... */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec_mii_acc.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/tgec_mii_acc.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TGEC_MII_ACC_H +#define __TGEC_MII_ACC_H + +#include "std_ext.h" + + +/* MII Management Command Register */ +#define MIIMCOM_READ_POST_INCREMENT 0x00004000 +#define MIIMCOM_READ_CYCLE 0x00008000 +#define MIIMCOM_SCAN_CYCLE 0x00000800 +#define MIIMCOM_PREAMBLE_DISABLE 0x00000400 + +#define MIIMCOM_MDIO_HOLD_1_REG_CLK 0 +#define MIIMCOM_MDIO_HOLD_2_REG_CLK 1 +#define MIIMCOM_MDIO_HOLD_3_REG_CLK 2 +#define MIIMCOM_MDIO_HOLD_4_REG_CLK 3 + +#define MIIMCOM_DIV_MASK 0x0000ff00 +#define MIIMCOM_DIV_SHIFT 8 + +/* MII Management Indicator Register */ +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_READ_ERROR 0x00000002 + +#define MIIDATA_BUSY 0x80000000 + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/*----------------------------------------------------*/ +/* MII Configuration Control Memory Map Registers */ +/*----------------------------------------------------*/ +typedef _Packed struct t_TgecMiiAccessMemMap +{ + volatile uint32_t mdio_cfg_status; /* 0x030 */ + volatile uint32_t mdio_command; /* 0x034 */ + volatile uint32_t mdio_data; /* 0x038 */ + volatile uint32_t mdio_regaddr; /* 0x03c */ +} _PackedType t_TgecMiiAccessMemMap ; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +#endif /* __TGEC_MII_ACC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/fm_mac.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/MAC/fm_mac.h @@ -0,0 +1,197 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_mac.h + + @Description FM MAC ... +*//***************************************************************************/ +#ifndef __FM_MAC_H +#define __FM_MAC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "fm_mac_ext.h" + + +#define __ERR_MODULE__ MODULE_FM_MAC + + +#define DEFAULT_resetOnInit FALSE + + +typedef struct { + uint64_t addr; /* Ethernet Address */ + t_List node; +} t_EthHashEntry; +#define ETH_HASH_ENTRY_OBJ(ptr) LIST_OBJECT(ptr, t_EthHashEntry, node) + +typedef struct { + uint16_t size; + t_List *p_Lsts; +} t_EthHash; + +typedef struct { + t_Error (*f_FM_MAC_Init) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Free) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_SetStatistics) (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel); + t_Error (*f_FM_MAC_ConfigLoopback) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigMaxFrameLength) (t_Handle h_FmMac, uint16_t newVal); + t_Error (*f_FM_MAC_ConfigWan) (t_Handle h_FmMac, bool flag); + t_Error (*f_FM_MAC_ConfigPadAndCrc) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigHalfDuplex) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigLengthCheck) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigException) (t_Handle h_FmMac, e_FmMacExceptions, bool enable); +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + t_Error (*f_FM_MAC_ConfigSkipFman11Workaround) (t_Handle h_FmMac); +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + t_Error (*f_FM_MAC_SetException) (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); + + t_Error (*f_FM_MAC_Enable) (t_Handle h_FmMac, e_CommMode mode); + t_Error (*f_FM_MAC_Disable) (t_Handle h_FmMac, e_CommMode mode); + t_Error (*f_FM_MAC_Enable1588TimeStamp) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Disable1588TimeStamp) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Reset) (t_Handle h_FmMac, bool wait); + + t_Error (*f_FM_MAC_SetTxAutoPauseFrames) (t_Handle h_FmMac, uint16_t pauseTime); + t_Error (*f_FM_MAC_SetRxIgnorePauseFrames) (t_Handle h_FmMac, bool en); + + t_Error (*f_FM_MAC_ResetCounters) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_GetStatistics) (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics); + + t_Error (*f_FM_MAC_ModifyMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_AddHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_RemoveHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_AddExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_RemovelExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + + t_Error (*f_FM_MAC_SetPromiscuous) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_AdjustLink) (t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex); + + t_Error (*f_FM_MAC_GetId) (t_Handle h_FmMac, uint32_t *macId); + + t_Error (*f_FM_MAC_GetVersion) (t_Handle h_FmMac, uint32_t *macVersion); + + uint16_t (*f_FM_MAC_GetMaxFrameLength) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_MII_WritePhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data); + t_Error (*f_FM_MAC_MII_ReadPhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_Error (*f_FM_MAC_DumpRegs) (t_Handle h_FmMac); +#endif /* (defined(DEBUG_ERRORS) && ... */ + + t_Handle h_Fm; + e_EnetMode enetMode; + uint8_t macId; + bool resetOnInit; + uint16_t clkFreq; +} t_FmMacControllerDriver; + + +t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam); +t_Handle TGEC_Config(t_FmMacParams *p_FmMacParams); +uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac); + + +/* ........................................................................... */ + +static __inline__ t_EthHashEntry *DequeueAddrFromHashEntry(t_List *p_AddrLst) +{ + t_EthHashEntry *p_HashEntry = NULL; + if (!LIST_IsEmpty(p_AddrLst)) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_AddrLst->p_Next); + LIST_DelAndInit(&p_HashEntry->node); + } + return p_HashEntry; +} + +/* ........................................................................... */ + +static __inline__ void FreeHashTable(t_EthHash *p_Hash) +{ + t_EthHashEntry *p_HashEntry; + int i = 0; + + if (!p_Hash || !p_Hash->p_Lsts) + return; + + for(i=0; isize; i++) + { + p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); + while (p_HashEntry) + { + XX_Free(p_HashEntry); + p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); + } + } + + XX_Free(p_Hash->p_Lsts); + XX_Free(p_Hash); +} + +/* ........................................................................... */ + +static __inline__ t_EthHash * AllocHashTable(uint16_t size) +{ + uint32_t i; + t_EthHash *p_Hash; + + /* Allocate address hash table */ + p_Hash = (t_EthHash *)XX_Malloc(size*sizeof(t_EthHash *)); + if (!p_Hash) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); + return NULL; + } + p_Hash->size = size; + + p_Hash->p_Lsts = (t_List *)XX_Malloc(p_Hash->size*sizeof(t_List)); + if (!p_Hash->p_Lsts) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); + XX_Free(p_Hash); + return NULL; + } + + for(i=0 ; isize; i++) + INIT_LIST(&p_Hash->p_Lsts[i]); + + return p_Hash; +} + + +#endif /* __FM_MAC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/inc/fm_hc.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/inc/fm_hc.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FM_HC_H +#define __FM_HC_H + +#include "std_ext.h" +#include "error_ext.h" + + +#define __ERR_MODULE__ MODULE_FM_PCD + + +typedef struct t_FmHcParams { + t_Handle h_Fm; + t_Handle h_FmPcd; + t_FmPcdHcParams params; +} t_FmHcParams; + + +t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams); +void FmHcFree(t_Handle h_FmHc); +t_Error FmHcDumpRegs(t_Handle h_FmHc); + +void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd); + +t_Handle FmHcPcdKgSetScheme(t_Handle h_FmHc, t_FmPcdKgSchemeParams *p_Scheme); +t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme); +t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams ); +t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set); +t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t clsPlanGrpId); + +t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value); +uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme); + +t_Error FmHcPcdCcModifyTreeNextEngine(t_Handle h_FmHc, t_Handle h_CcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); +t_Error FmHcPcdCcModifyNodeNextEngine(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); +t_Error FmHcPcdCcModifyNodeMissNextEngine(t_Handle h_FmHc, t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); +t_Error FmHcPcdCcRemoveKey(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex); +t_Error FmHcPcdCcAddKey(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams); +t_Error FmHcPcdCcModifyKeyAndNextEngine(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams); +t_Error FmHcPcdCcModifyKey(t_Handle h_FmHc, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask); + +t_Handle FmHcPcdPlcrSetProfile(t_Handle h_FmHc,t_FmPcdPlcrProfileParams *p_Profile); +t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile); + +t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value); +uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter); + +t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add); +t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg); + +t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction); +t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction); + + +#endif /* __FM_HC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/inc/fm_common.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/inc/fm_common.h @@ -0,0 +1,1173 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_common.h + + @Description FM internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_COMMON_H +#define __FM_COMMON_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_pcd_ext.h" +#include "fm_port_ext.h" + +#define CLS_PLAN_NUM_PER_GRP 8 + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/**************************************************************************//** + @Description PCD KG scheme registers +*//***************************************************************************/ +typedef _Packed struct t_FmPcdPlcrInterModuleProfileRegs { + volatile uint32_t fmpl_pemode; /* 0x090 FMPL_PEMODE - FM Policer Profile Entry Mode*/ + volatile uint32_t fmpl_pegnia; /* 0x094 FMPL_PEGNIA - FM Policer Profile Entry GREEN Next Invoked Action*/ + volatile uint32_t fmpl_peynia; /* 0x098 FMPL_PEYNIA - FM Policer Profile Entry YELLOW Next Invoked Action*/ + volatile uint32_t fmpl_pernia; /* 0x09C FMPL_PERNIA - FM Policer Profile Entry RED Next Invoked Action*/ + volatile uint32_t fmpl_pecir; /* 0x0A0 FMPL_PECIR - FM Policer Profile Entry Committed Information Rate*/ + volatile uint32_t fmpl_pecbs; /* 0x0A4 FMPL_PECBS - FM Policer Profile Entry Committed Burst Size*/ + volatile uint32_t fmpl_pepepir_eir; /* 0x0A8 FMPL_PEPIR_EIR - FM Policer Profile Entry Peak/Excess Information Rate*/ + volatile uint32_t fmpl_pepbs_ebs; /* 0x0AC FMPL_PEPBS_EBS - FM Policer Profile Entry Peak/Excess Information Rate*/ + volatile uint32_t fmpl_pelts; /* 0x0B0 FMPL_PELTS - FM Policer Profile Entry Last TimeStamp*/ + volatile uint32_t fmpl_pects; /* 0x0B4 FMPL_PECTS - FM Policer Profile Entry Committed Token Status*/ + volatile uint32_t fmpl_pepts_ets; /* 0x0B8 FMPL_PEPTS_ETS - FM Policer Profile Entry Peak/Excess Token Status*/ + volatile uint32_t fmpl_pegpc; /* 0x0BC FMPL_PEGPC - FM Policer Profile Entry GREEN Packet Counter*/ + volatile uint32_t fmpl_peypc; /* 0x0C0 FMPL_PEYPC - FM Policer Profile Entry YELLOW Packet Counter*/ + volatile uint32_t fmpl_perpc; /* 0x0C4 FMPL_PERPC - FM Policer Profile Entry RED Packet Counter */ + volatile uint32_t fmpl_perypc; /* 0x0C8 FMPL_PERYPC - FM Policer Profile Entry Recolored YELLOW Packet Counter*/ + volatile uint32_t fmpl_perrpc; /* 0x0CC FMPL_PERRPC - FM Policer Profile Entry Recolored RED Packet Counter*/ + volatile uint32_t fmpl_res1[12]; /* 0x0D0-0x0FF Reserved */ +} _PackedType t_FmPcdPlcrInterModuleProfileRegs; + +/**************************************************************************//** + @Description PCD KG scheme registers +*//***************************************************************************/ +typedef _Packed struct t_FmPcdKgInterModuleSchemeRegs { + volatile uint32_t kgse_mode; /**< MODE */ + volatile uint32_t kgse_ekfc; /**< Extract Known Fields Command */ + volatile uint32_t kgse_ekdv; /**< Extract Known Default Value */ + volatile uint32_t kgse_bmch; /**< Bit Mask Command High */ + volatile uint32_t kgse_bmcl; /**< Bit Mask Command Low */ + volatile uint32_t kgse_fqb; /**< Frame Queue Base */ + volatile uint32_t kgse_hc; /**< Hash Command */ + volatile uint32_t kgse_ppc; /**< Policer Profile Command */ + volatile uint32_t kgse_gec[FM_PCD_KG_NUM_OF_GENERIC_REGS]; + /**< Generic Extract Command */ + volatile uint32_t kgse_spc; /**< KeyGen Scheme Entry Statistic Packet Counter */ + volatile uint32_t kgse_dv0; /**< KeyGen Scheme Entry Default Value 0 */ + volatile uint32_t kgse_dv1; /**< KeyGen Scheme Entry Default Value 1 */ + volatile uint32_t kgse_ccbs; /**< KeyGen Scheme Entry Coarse Classification Bit*/ + volatile uint32_t kgse_mv; /**< KeyGen Scheme Entry Match vector */ +} _PackedType t_FmPcdKgInterModuleSchemeRegs; + +typedef _Packed struct t_FmPcdCcCapwapReassmTimeoutParams { + volatile uint32_t portIdAndCapwapReassmTbl; + volatile uint32_t fqidForTimeOutFrames; + volatile uint32_t timeoutRequestTime; +}_PackedType t_FmPcdCcCapwapReassmTimeoutParams; + + + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +typedef struct { + uint8_t baseEntry; + uint16_t numOfClsPlanEntries; + uint32_t vectors[FM_PCD_MAX_NUM_OF_CLS_PLANS]; +} t_FmPcdKgInterModuleClsPlanSet; + +/**************************************************************************//** + @Description Structure for binding a port to keygen schemes. +*//***************************************************************************/ +typedef struct t_FmPcdKgInterModuleBindPortToSchemes { + uint8_t hardwarePortId; + uint8_t netEnvId; + bool useClsPlan; /**< TRUE if this port uses the clsPlan mechanism */ + uint8_t numOfSchemes; + uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; +} t_FmPcdKgInterModuleBindPortToSchemes; + +typedef struct { + uint32_t nextCcNodeInfo; + t_List node; +} t_CcNodeInfo; + +typedef struct +{ + t_Handle h_CcNode; + uint16_t index; + t_List node; +}t_CcNodeInformation; +#define CC_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInformation, node) + +typedef struct +{ + t_Handle h_Manip; + t_List node; +}t_ManipInfo; +#define CC_NEXT_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInfo, node) + +typedef struct { + uint32_t type; + uint8_t prOffset; + + uint16_t dataOffset; + uint8_t poolIndex; + + uint8_t poolIdForManip; + uint8_t numOfTasks; + + uint8_t hardwarePortId; + +} t_GetCcParams; + +typedef struct { + uint32_t type; + int psoSize; + uint32_t nia; + +} t_SetCcParams; + +typedef struct { + t_GetCcParams getCcParams; + t_SetCcParams setCcParams; +} t_FmPortGetSetCcParams; + + +static __inline__ bool TRY_LOCK(t_Handle h_Spinlock, volatile bool *p_Flag) +{ + uint32_t intFlags; + if (h_Spinlock) + intFlags = XX_LockIntrSpinlock(h_Spinlock); + else + intFlags = XX_DisableAllIntr(); + if (*p_Flag) + { + if (h_Spinlock) + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); + else + XX_RestoreAllIntr(intFlags); + return FALSE; + } + *p_Flag = TRUE; + if (h_Spinlock) + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); + else + XX_RestoreAllIntr(intFlags); + return TRUE; +} + +#define RELEASE_LOCK(_flag) _flag = FALSE; + +/**************************************************************************//** + @Collection Defines used for manipulation CC and BMI + @{ +*//***************************************************************************/ +#define INTERNAL_CONTEXT_OFFSET 0x80000000 +#define OFFSET_OF_PR 0x40000000 +#define BUFFER_POOL_ID_FOR_MANIP 0x20000000 +#define NUM_OF_TASKS 0x10000000 +#define OFFSET_OF_DATA 0x08000000 +#define HW_PORT_ID 0x04000000 + + +#define UPDATE_NIA_PNEN 0x80000000 +#define UPDATE_PSO 0x40000000 +#define UPDATE_NIA_PNDN 0x20000000 +#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY 0x10000000 +/* @} */ + +/**************************************************************************//** + @Collection Defines used for manipulation CC and CC + @{ +*//***************************************************************************/ +#define UPDATE_NIA_ENQ_WITHOUT_DMA 0x80000000 +#define UPDATE_CC_WITH_TREE 0x40000000 +#define UPDATE_CC_WITH_DELETE_TREE 0x20000000 +/* @} */ + +/**************************************************************************//** + @Collection Defines used for enabling/disabling FM interrupts + @{ +*//***************************************************************************/ +typedef uint32_t t_FmBlockErrIntrEnable; + +#define ERR_INTR_EN_DMA 0x00010000 +#define ERR_INTR_EN_FPM 0x80000000 +#define ERR_INTR_EN_BMI 0x00800000 +#define ERR_INTR_EN_QMI 0x00400000 +#define ERR_INTR_EN_PRS 0x00200000 +#define ERR_INTR_EN_KG 0x00100000 +#define ERR_INTR_EN_PLCR 0x00080000 +#define ERR_INTR_EN_MURAM 0x00040000 +#define ERR_INTR_EN_IRAM 0x00020000 +#define ERR_INTR_EN_10G_MAC0 0x00008000 +#define ERR_INTR_EN_1G_MAC0 0x00004000 +#define ERR_INTR_EN_1G_MAC1 0x00002000 +#define ERR_INTR_EN_1G_MAC2 0x00001000 +#define ERR_INTR_EN_1G_MAC3 0x00000800 +#define ERR_INTR_EN_1G_MAC4 0x00000400 +#define ERR_INTR_EN_MACSEC_MAC0 0x00000200 + + +typedef uint32_t t_FmBlockIntrEnable; + +#define INTR_EN_BMI 0x80000000 +#define INTR_EN_QMI 0x40000000 +#define INTR_EN_PRS 0x20000000 +#define INTR_EN_KG 0x10000000 +#define INTR_EN_PLCR 0x08000000 +#define INTR_EN_1G_MAC0_TMR 0x00080000 +#define INTR_EN_1G_MAC1_TMR 0x00040000 +#define INTR_EN_1G_MAC2_TMR 0x00020000 +#define INTR_EN_1G_MAC3_TMR 0x00010000 +#define INTR_EN_1G_MAC4_TMR 0x00000040 +#define INTR_EN_REV0 0x00008000 +#define INTR_EN_REV1 0x00004000 +#define INTR_EN_REV2 0x00002000 +#define INTR_EN_REV3 0x00001000 +#define INTR_EN_BRK 0x00000080 +#define INTR_EN_TMR 0x01000000 +#define INTR_EN_MACSEC_MAC0 0x00000001 +/* @} */ + +#define FM_MAX_NUM_OF_PORTS (FM_MAX_NUM_OF_OH_PORTS + \ + FM_MAX_NUM_OF_1G_RX_PORTS + \ + FM_MAX_NUM_OF_10G_RX_PORTS + \ + FM_MAX_NUM_OF_1G_TX_PORTS + \ + FM_MAX_NUM_OF_10G_TX_PORTS) + +#define MODULE_NAME_SIZE 30 +#define DUMMY_PORT_ID 0 + +#define FM_LIODN_OFFSET_MASK 0x3FF + +/**************************************************************************//** + @Description NIA Description +*//***************************************************************************/ +#define NIA_ORDER_RESTOR 0x00800000 +#define NIA_ENG_FM_CTL 0x00000000 +#define NIA_ENG_PRS 0x00440000 +#define NIA_ENG_KG 0x00480000 +#define NIA_ENG_PLCR 0x004C0000 +#define NIA_ENG_BMI 0x00500000 +#define NIA_ENG_QMI_ENQ 0x00540000 +#define NIA_ENG_QMI_DEQ 0x00580000 +#define NIA_ENG_MASK 0x007C0000 + +#define NIA_FM_CTL_AC_CC 0x00000006 +#define NIA_FM_CTL_AC_HC 0x0000000C +#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008 +#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A +#define NIA_FM_CTL_AC_FRAG 0x0000000e +#define NIA_FM_CTL_AC_PRE_FETCH 0x00000010 +#define NIA_FM_CTL_AC_POST_FETCH_PCD 0x00000012 +#define NIA_FM_CTL_AC_POST_FETCH_PCD_UDP_LEN 0x00000018 +#define NIA_FM_CTL_AC_POST_FETCH_NO_PCD 0x00000012 +#define NIA_FM_CTL_AC_FRAG_CHECK 0x00000014 +#define NIA_FM_CTL_AC_MASK 0x0000001f + +#define NIA_BMI_AC_ENQ_FRAME 0x00000002 +#define NIA_BMI_AC_TX_RELEASE 0x000002C0 +#define NIA_BMI_AC_RELEASE 0x000000C0 +#define NIA_BMI_AC_DISCARD 0x000000C1 +#define NIA_BMI_AC_TX 0x00000274 +#define NIA_BMI_AC_FETCH 0x00000208 +#define NIA_BMI_AC_MASK 0x000003FF + +#define NIA_KG_DIRECT 0x00000100 +#define NIA_KG_CC_EN 0x00000200 +#define NIA_PLCR_ABSOLUTE 0x00008000 + +#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202 + +/**************************************************************************//** + @Description Port Id defines +*//***************************************************************************/ +#define BASE_OH_PORTID 1 +#define BASE_1G_RX_PORTID 8 +#define BASE_10G_RX_PORTID 0x10 +#define BASE_1G_TX_PORTID 0x28 +#define BASE_10G_TX_PORTID 0x30 + +#define FM_PCD_PORT_OH_BASE_INDX 0 +#define FM_PCD_PORT_1G_RX_BASE_INDX (FM_PCD_PORT_OH_BASE_INDX+FM_MAX_NUM_OF_OH_PORTS) +#define FM_PCD_PORT_10G_RX_BASE_INDX (FM_PCD_PORT_1G_RX_BASE_INDX+FM_MAX_NUM_OF_1G_RX_PORTS) +#define FM_PCD_PORT_1G_TX_BASE_INDX (FM_PCD_PORT_10G_RX_BASE_INDX+FM_MAX_NUM_OF_10G_RX_PORTS) +#define FM_PCD_PORT_10G_TX_BASE_INDX (FM_PCD_PORT_1G_TX_BASE_INDX+FM_MAX_NUM_OF_1G_TX_PORTS) + +#if (FM_MAX_NUM_OF_OH_PORTS > 0) +#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_OH_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id")) +#else +#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_1G_RX_PORTS > 0) +#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_1G_RX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id")) +#else +#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_10G_RX_PORTS > 0) +#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_10G_RX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id")) +#else +#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_1G_TX_PORTS > 0) +#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_1G_TX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id")) +#else +#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_10G_TX_PORTS > 0) +#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_10G_TX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id")) +#else +#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id")) +#endif + + +#define SW_PORT_ID_TO_HW_PORT_ID(_port, _type, _relativePortId) \ +switch(_type) { \ + case(e_FM_PORT_TYPE_OH_OFFLINE_PARSING): \ + case(e_FM_PORT_TYPE_OH_HOST_COMMAND): \ + CHECK_PORT_ID_OH_PORTS(_relativePortId); \ + _port = (uint8_t)(BASE_OH_PORTID + (_relativePortId)); \ + break; \ + case(e_FM_PORT_TYPE_RX): \ + CHECK_PORT_ID_1G_RX_PORTS(_relativePortId); \ + _port = (uint8_t)(BASE_1G_RX_PORTID + (_relativePortId)); \ + break; \ + case(e_FM_PORT_TYPE_RX_10G): \ + CHECK_PORT_ID_10G_RX_PORTS(_relativePortId); \ + _port = (uint8_t)(BASE_10G_RX_PORTID + (_relativePortId)); \ + break; \ + case(e_FM_PORT_TYPE_TX): \ + CHECK_PORT_ID_1G_TX_PORTS(_relativePortId); \ + _port = (uint8_t)(BASE_1G_TX_PORTID + (_relativePortId)); \ + break; \ + case(e_FM_PORT_TYPE_TX_10G): \ + CHECK_PORT_ID_10G_TX_PORTS(_relativePortId); \ + _port = (uint8_t)(BASE_10G_TX_PORTID + (_relativePortId)); \ + break; \ + default: \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type")); \ + _port = 0; \ + break; \ +} + +#define HW_PORT_ID_TO_SW_PORT_ID(_relativePortId, hardwarePortId) \ +{ if (((hardwarePortId) >= BASE_OH_PORTID) && \ + ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_OH_PORTID); \ + else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \ + ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID); \ + else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \ + ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID); \ + else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \ + ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID); \ + else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \ + ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID); \ + else { \ + _relativePortId = (uint8_t)DUMMY_PORT_ID; \ + ASSERT_COND(TRUE); \ + } \ +} + +#define HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId) \ +do { \ + if (((hardwarePortId) >= BASE_OH_PORTID) && ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_OH_PORTID+FM_PCD_PORT_OH_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \ + ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID+FM_PCD_PORT_1G_RX_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \ + ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID+FM_PCD_PORT_10G_RX_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \ + ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID+FM_PCD_PORT_1G_TX_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \ + ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID+FM_PCD_PORT_10G_TX_BASE_INDX); \ + else ASSERT_COND(FALSE); \ +} while (0) + +#define SW_PORT_INDX_TO_HW_PORT_ID(hardwarePortId, swPortIndex) \ +do { \ + if (((swPortIndex) >= FM_PCD_PORT_OH_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_1G_RX_BASE_INDX)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_OH_BASE_INDX+BASE_OH_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_1G_RX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_RX_BASE_INDX)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_RX_BASE_INDX+BASE_1G_RX_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_10G_RX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_RX_BASE_INDX+BASE_10G_RX_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_1G_TX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_TX_BASE_INDX)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_TX_BASE_INDX+BASE_1G_TX_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_10G_TX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_TX_BASE_INDX+BASE_10G_TX_PORTID); \ + else ASSERT_COND(FALSE); \ +} while (0) + +#define BMI_FIFO_UNITS 0x100 + +typedef struct { + void (*f_Isr) (t_Handle h_Arg); + t_Handle h_SrcHandle; + uint8_t guestId; +} t_FmIntrSrc; + +#define ILLEGAL_HDR_NUM 0xFF +#define NO_HDR_NUM FM_PCD_PRS_NUM_OF_HDRS + +#define IS_PRIVATE_HEADER(hdr) (((hdr) == HEADER_TYPE_USER_DEFINED_SHIM1) || \ + ((hdr) == HEADER_TYPE_USER_DEFINED_SHIM2)) +#define IS_SPECIAL_HEADER(hdr) ((hdr) == HEADER_TYPE_MACSEC) + +#define GET_PRS_HDR_NUM(num, hdr) \ +switch(hdr) \ +{ case(HEADER_TYPE_ETH): num = 0; break; \ + case(HEADER_TYPE_LLC_SNAP): num = 1; break; \ + case(HEADER_TYPE_VLAN): num = 2; break; \ + case(HEADER_TYPE_PPPoE): num = 3; break; \ + case(HEADER_TYPE_MPLS): num = 4; break; \ + case(HEADER_TYPE_IPv4): num = 5; break; \ + case(HEADER_TYPE_IPv6): num = 6; break; \ + case(HEADER_TYPE_GRE): num = 7; break; \ + case(HEADER_TYPE_MINENCAP): num = 8; break; \ + case(HEADER_TYPE_USER_DEFINED_L3): num = 9; break; \ + case(HEADER_TYPE_TCP): num = 10; break; \ + case(HEADER_TYPE_UDP): num = 11; break; \ + case(HEADER_TYPE_IPSEC_AH): \ + case(HEADER_TYPE_IPSEC_ESP): num = 12; break; \ + case(HEADER_TYPE_SCTP): num = 13; break; \ + case(HEADER_TYPE_DCCP): num = 14; break; \ + case(HEADER_TYPE_USER_DEFINED_L4): num = 15; break; \ + case(HEADER_TYPE_USER_DEFINED_SHIM1): \ + case(HEADER_TYPE_USER_DEFINED_SHIM2): \ + case(HEADER_TYPE_MACSEC): \ + num = NO_HDR_NUM; break; \ + default: \ + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header for parser"));\ + num = ILLEGAL_HDR_NUM; break; \ +} + +/***********************************************************************/ +/* Policer defines */ +/***********************************************************************/ +#define FM_PCD_PLCR_PAR_GO 0x80000000 +#define FM_PCD_PLCR_PAR_PWSEL_MASK 0x0000FFFF +#define FM_PCD_PLCR_PAR_R 0x40000000 + +/* shifts */ +#define FM_PCD_PLCR_PAR_PNUM_SHIFT 16 + + +/***********************************************************************/ +/* Keygen defines */ +/***********************************************************************/ +/* maskes */ +#define KG_SCH_PP_SHIFT_HIGH 0x80000000 +#define KG_SCH_PP_NO_GEN 0x10000000 +#define KG_SCH_PP_SHIFT_LOW 0x0000F000 +#define KG_SCH_MODE_NIA_PLCR 0x40000000 +#define KG_SCH_GEN_EXTRACT_TYPE 0x00008000 +#define KG_SCH_BITMASK_MASK 0x000000FF +#define KG_SCH_GEN_VALID 0x80000000 +#define KG_SCH_GEN_MASK 0x00FF0000 +#define FM_PCD_KG_KGAR_ERR 0x20000000 +#define FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY 0x01000000 +#define FM_PCD_KG_KGAR_SEL_PORT_ENTRY 0x02000000 +#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP 0x00008000 +#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP 0x00004000 +#define FM_PCD_KG_KGAR_WSEL_MASK 0x0000FF00 +#define KG_SCH_HASH_CONFIG_NO_FQID 0x80000000 +#define KG_SCH_HASH_CONFIG_SYM 0x40000000 + +#define FM_PCD_KG_KGAR_GO 0x80000000 +#define FM_PCD_KG_KGAR_READ 0x40000000 +#define FM_PCD_KG_KGAR_WRITE 0x00000000 +#define FM_PCD_KG_KGAR_SEL_SCHEME_ENTRY 0x00000000 +#define FM_PCD_KG_KGAR_SCHEME_WSEL_UPDATE_CNT 0x00008000 + + +typedef uint32_t t_KnownFieldsMasks; + +#define KG_SCH_KN_PORT_ID 0x80000000 +#define KG_SCH_KN_MACDST 0x40000000 +#define KG_SCH_KN_MACSRC 0x20000000 +#define KG_SCH_KN_TCI1 0x10000000 +#define KG_SCH_KN_TCI2 0x08000000 +#define KG_SCH_KN_ETYPE 0x04000000 +#define KG_SCH_KN_PPPSID 0x02000000 +#define KG_SCH_KN_PPPID 0x01000000 +#define KG_SCH_KN_MPLS1 0x00800000 +#define KG_SCH_KN_MPLS2 0x00400000 +#define KG_SCH_KN_MPLS_LAST 0x00200000 +#define KG_SCH_KN_IPSRC1 0x00100000 +#define KG_SCH_KN_IPDST1 0x00080000 +#define KG_SCH_KN_PTYPE1 0x00040000 +#define KG_SCH_KN_IPTOS_TC1 0x00020000 +#define KG_SCH_KN_IPV6FL1 0x00010000 +#define KG_SCH_KN_IPSRC2 0x00008000 +#define KG_SCH_KN_IPDST2 0x00004000 +#define KG_SCH_KN_PTYPE2 0x00002000 +#define KG_SCH_KN_IPTOS_TC2 0x00001000 +#define KG_SCH_KN_IPV6FL2 0x00000800 +#define KG_SCH_KN_GREPTYPE 0x00000400 +#define KG_SCH_KN_IPSEC_SPI 0x00000200 +#define KG_SCH_KN_IPSEC_NH 0x00000100 +#define KG_SCH_KN_L4PSRC 0x00000004 +#define KG_SCH_KN_L4PDST 0x00000002 +#define KG_SCH_KN_TFLG 0x00000001 + +typedef uint8_t t_GenericCodes; + +#define KG_SCH_GEN_SHIM1 0x70 +#define KG_SCH_GEN_DEFAULT 0x10 +#define KG_SCH_GEN_PARSE_RESULT_N_FQID 0x20 +#define KG_SCH_GEN_START_OF_FRM 0x40 +#define KG_SCH_GEN_SHIM2 0x71 +#define KG_SCH_GEN_IP_PID_NO_V 0x72 +#define KG_SCH_GEN_ETH 0x03 +#define KG_SCH_GEN_ETH_NO_V 0x73 +#define KG_SCH_GEN_SNAP 0x04 +#define KG_SCH_GEN_SNAP_NO_V 0x74 +#define KG_SCH_GEN_VLAN1 0x05 +#define KG_SCH_GEN_VLAN1_NO_V 0x75 +#define KG_SCH_GEN_VLAN2 0x06 +#define KG_SCH_GEN_VLAN2_NO_V 0x76 +#define KG_SCH_GEN_ETH_TYPE 0x07 +#define KG_SCH_GEN_ETH_TYPE_NO_V 0x77 +#define KG_SCH_GEN_PPP 0x08 +#define KG_SCH_GEN_PPP_NO_V 0x78 +#define KG_SCH_GEN_MPLS1 0x09 +#define KG_SCH_GEN_MPLS2 0x19 +#define KG_SCH_GEN_MPLS3 0x29 +#define KG_SCH_GEN_MPLS1_NO_V 0x79 +#define KG_SCH_GEN_MPLS_LAST 0x0a +#define KG_SCH_GEN_MPLS_LAST_NO_V 0x7a +#define KG_SCH_GEN_IPV4 0x0b +#define KG_SCH_GEN_IPV6 0x1b +#define KG_SCH_GEN_L3_NO_V 0x7b +#define KG_SCH_GEN_IPV4_TUNNELED 0x0c +#define KG_SCH_GEN_IPV6_TUNNELED 0x1c +#define KG_SCH_GEN_MIN_ENCAP 0x2c +#define KG_SCH_GEN_IP2_NO_V 0x7c +#define KG_SCH_GEN_GRE 0x0d +#define KG_SCH_GEN_GRE_NO_V 0x7d +#define KG_SCH_GEN_TCP 0x0e +#define KG_SCH_GEN_UDP 0x1e +#define KG_SCH_GEN_IPSEC_AH 0x2e +#define KG_SCH_GEN_SCTP 0x3e +#define KG_SCH_GEN_DCCP 0x4e +#define KG_SCH_GEN_IPSEC_ESP 0x6e +#define KG_SCH_GEN_L4_NO_V 0x7e +#define KG_SCH_GEN_NEXTHDR 0x7f + +/* shifts */ +#define KG_SCH_PP_SHIFT_HIGH_SHIFT 27 +#define KG_SCH_PP_SHIFT_LOW_SHIFT 12 +#define KG_SCH_PP_MASK_SHIFT 16 +#define KG_SCH_MODE_CCOBASE_SHIFT 24 +#define KG_SCH_DEF_MAC_ADDR_SHIFT 30 +#define KG_SCH_DEF_TCI_SHIFT 28 +#define KG_SCH_DEF_ENET_TYPE_SHIFT 26 +#define KG_SCH_DEF_PPP_SESSION_ID_SHIFT 24 +#define KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT 22 +#define KG_SCH_DEF_MPLS_LABEL_SHIFT 20 +#define KG_SCH_DEF_IP_ADDR_SHIFT 18 +#define KG_SCH_DEF_PROTOCOL_TYPE_SHIFT 16 +#define KG_SCH_DEF_IP_TOS_TC_SHIFT 14 +#define KG_SCH_DEF_IPV6_FLOW_LABEL_SHIFT 12 +#define KG_SCH_DEF_IPSEC_SPI_SHIFT 10 +#define KG_SCH_DEF_L4_PORT_SHIFT 8 +#define KG_SCH_DEF_TCP_FLAG_SHIFT 6 +#define KG_SCH_HASH_CONFIG_SHIFT_SHIFT 24 +#define KG_SCH_GEN_MASK_SHIFT 16 +#define KG_SCH_GEN_HT_SHIFT 8 +#define KG_SCH_GEN_SIZE_SHIFT 24 +#define KG_SCH_GEN_DEF_SHIFT 29 +#define FM_PCD_KG_KGAR_NUM_SHIFT 16 + + +/* others */ +#define NUM_OF_SW_DEFAULTS 3 +#define MAX_PP_SHIFT 15 +#define MAX_KG_SCH_SIZE 16 +#define MASK_FOR_GENERIC_BASE_ID 0x20 +#define MAX_HASH_SHIFT 40 +#define MAX_KG_SCH_FQID_BIT_OFFSET 31 +#define MAX_KG_SCH_PP_BIT_OFFSET 15 +#define MAX_DIST_FQID_SHIFT 23 + +#define GET_MASK_SEL_SHIFT(shift,i) \ +switch(i) { \ + case(0):shift = 26;break; \ + case(1):shift = 20;break; \ + case(2):shift = 10;break; \ + case(3):shift = 4;break; \ + default: \ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);\ +} + +#define GET_MASK_OFFSET_SHIFT(shift,i) \ +switch(i) { \ + case(0):shift = 16;break; \ + case(1):shift = 0;break; \ + case(2):shift = 28;break; \ + case(3):shift = 24;break; \ + default: \ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);\ +} + +#define GET_MASK_SHIFT(shift,i) \ +switch(i) { \ + case(0):shift = 24;break; \ + case(1):shift = 16;break; \ + case(2):shift = 8;break; \ + case(3):shift = 0;break; \ + default: \ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);\ +} + +#define FM_PCD_MAX_NUM_OF_OPTIONS(clsPlanEntries) ((clsPlanEntries==256)? 8:((clsPlanEntries==128)? 7: ((clsPlanEntries==64)? 6: ((clsPlanEntries==32)? 5:0)))) + +typedef struct { + uint16_t num; + uint8_t hardwarePortId; + uint16_t plcrProfilesBase; +} t_FmPortPcdInterModulePlcrParams; + +/**************************************************************************//** + @Description A structure for initializing a keygen classification plan group +*//***************************************************************************/ +typedef struct t_FmPcdKgInterModuleClsPlanGrpParams { + uint8_t netEnvId; /* IN */ + bool grpExists; /* OUT (unused in FmPcdKgBuildClsPlanGrp)*/ + uint8_t clsPlanGrpId; /* OUT */ + bool emptyClsPlanGrp; /* OUT */ + uint8_t numOfOptions; /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ + protocolOpt_t options[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; + /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ + uint32_t optVectors[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; + /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ +} t_FmPcdKgInterModuleClsPlanGrpParams; + +typedef struct t_FmInterModulePortRxPoolsParams +{ + uint8_t numOfPools; + uint16_t secondLargestBufSize; + uint16_t largestBufSize; +} t_FmInterModulePortRxPoolsParams; + + +typedef t_Error (t_FmPortGetSetCcParamsCallback) (t_Handle h_FmPort, + t_FmPortGetSetCcParams *p_FmPortGetSetCcParams); + + +t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd); +uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr); +uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum); +uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId); +void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId); +void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId); +void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId); +uint32_t FmPcdLock(t_Handle h_FmPcd); +void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags); +bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); +bool FmPcdIsIpFrag(t_Handle h_FmPcd, uint8_t netEnvId); + +t_Error FmPcdCcReleaseModifiedDataStructure(t_Handle h_FmPcd, t_List *h_FmPcdOldPointersLst, t_List *h_FmPcdNewPointersLst, uint16_t numOfGoodChanges, t_Handle *h_Params); +uint32_t FmPcdCcGetNodeAddrOffset(t_Handle h_FmPcd, t_Handle h_Pointer); +t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint8_t keyIndex, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams); +t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPCdCcKeyParams, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_Params); +t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams); +t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPcdCcKeyParams, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams); +t_Error FmPcdCcModifyMissNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,t_List *h_OldPointer, t_List *h_NewPointer,t_Handle *h_AdditionalParams); +t_Error FmPcdCcModifyNextEngineParamTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams); +t_Error FmPcdCcModiyNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, uint8_t keyIndex,t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,t_List *h_OldPointer, t_List *h_NewPointer,t_Handle *h_AdditionalParams); +uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, t_Handle h_Pointer); +t_Error FmPcdCcTreeTryLock(t_Handle h_FmPcdCcTree); +t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_List *p_List); +void FmPcdCcTreeReleaseLock(t_Handle h_FmPcdCcTree); +void FmPcdCcNodeTreeReleaseLock(t_List *p_List); +t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree, uint8_t manipIndx); +void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, t_Handle h_SavedManipParams, uint8_t manipIndx); + +bool FmPcdKgIsSchemeValidSw(t_Handle h_FmPcd, uint8_t schemeId); +uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp); +uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp); + +t_Error FmPcdKgBuildScheme(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_Scheme, t_FmPcdKgInterModuleSchemeRegs *p_SchemeRegs); +t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet); +uint8_t FmPcdKgGetNumOfPartitionSchemes(t_Handle h_FmPcd); +uint8_t FmPcdKgGetPhysicalSchemeId(t_Handle h_FmPcd, uint8_t schemeId); +uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId); +void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId); +void FmPcdKgValidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId); +void FmPcdKgInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId); +t_Error FmPcdKgCheckInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId); +t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPortToSchemes, uint32_t *p_SpReg, bool add); +void FmPcdKgIncSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort); +void FmPcdKgDecSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort); +bool FmPcdKgIsDriverClsPlan(t_Handle h_FmPcd); +bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg); +uint32_t FmPcdKgBuildCppReg(t_Handle h_FmPcd, uint8_t clsPlanGrpId); +uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter); +uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId); +uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId); +uint32_t FmPcdKgBuildReadClsPlanBlockActionReg(uint8_t grpId); +uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId); +uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId); +uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId); +uint8_t FmPcdKgGetSchemeSwId(t_Handle h_FmPcd, uint8_t schemeHwId); +t_Error FmPcdKgSchemeTryLock(t_Handle h_FmPcd, uint8_t schemeId, bool intr); +void FmPcdKgReleaseSchemeLock(t_Handle h_FmPcd, uint8_t schemeId); +void FmPcdKgUpatePointedOwner(t_Handle h_FmPcd, uint8_t schemeId, bool add); + +t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind); +t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind); +uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId); +uint32_t FmPcdKgGetPointedOwners(t_Handle h_FmPcd, uint8_t schemeId); +e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId); +e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId); +void FmPcdKgUpdateRequiredAction(t_Handle h_FmPcd, uint8_t schemeId, uint32_t requiredAction); +bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId); +bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId); +uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId); + +/* FM-PCD parser API routines */ +t_Error FmPcdPrsIncludePortInStatistics(t_Handle p_FmPcd, uint8_t hardwarePortId, bool include); + +/* FM-PCD policer API routines */ +t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles); +t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId); +bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId); +uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId); +uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId); +uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId); +uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter); +uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId); +uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId); +t_Error FmPcdPlcrBuildProfile(t_Handle h_FmPcd, t_FmPcdPlcrProfileParams *p_Profile, t_FmPcdPlcrInterModuleProfileRegs *p_PlcrRegs); +t_Error FmPcdPlcrGetAbsoluteProfileId(t_Handle h_FmPcd, + e_FmPcdProfileTypeSelection profileType, + t_Handle h_FmPort, + uint16_t relativeProfile, + uint16_t *p_AbsoluteId); +void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); +void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); +bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg); +t_Error FmPcdPlcrProfileTryLock(t_Handle h_FmPcd, uint16_t profileId, bool intr); +void FmPcdPlcrReleaseProfileLock(t_Handle h_FmPcd, uint16_t profileId); +uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId); +uint32_t FmPcdPlcrGetPointedOwners(t_Handle h_FmPcd, uint16_t absoluteProfileId); +void FmPcdPlcrUpatePointedOwner(t_Handle h_FmPcd, uint16_t absoluteProfileId, bool add); +uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red); +void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction); + +/* FM-PCD Coarse-Classification API routines */ +uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode); +uint8_t FmPcdCcGetOffset(t_Handle h_CcNode); + +t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad, bool validate, int level, t_Handle h_FmTree, bool modify); +t_Error FmPortGetSetCcParams(t_Handle h_FmPort, t_FmPortGetSetCcParams *p_FmPortGetSetCcParams); +uint32_t FmPcdManipGetRequiredAction (t_Handle h_Manip); +t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_CcTree, uint32_t *p_Offset,t_Handle h_FmPort); +t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_CcTree); + +t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx,uint32_t requiredAction); +t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction); + +uint8_t FmPortGetNetEnvId(t_Handle h_FmPort); +uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort); +uint32_t FmPortGetPcdEngines(t_Handle h_FmPort); +void FmPortPcdKgSwUnbindClsPlanGrp (t_Handle h_FmPort); +t_Error FmPortAttachPCD(t_Handle h_FmPort); +t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp); +t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId); + + +/**************************************************************************//** + @Function FmRegisterIntr + + @Description Used to register an inter-module event handler to be processed by FM + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] mod The module that causes the event + @Param[in] modId Module id - if more than 1 instansiation of this + mode exists,0 otherwise. + @Param[in] intrType Interrupt type (error/normal) selection. + @Param[in] f_Isr The interrupt service routine. + @Param[in] h_Arg Argument to be passed to f_Isr. + + @Return None. +*//***************************************************************************/ +void FmRegisterIntr(t_Handle h_Fm, + e_FmEventModules mod, + uint8_t modId, + e_FmIntrType intrType, + void (*f_Isr) (t_Handle h_Arg), + t_Handle h_Arg); + +/**************************************************************************//** + @Function FmUnregisterIntr + + @Description Used to un-register an inter-module event handler that was processed by FM + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] mod The module that causes the event + @Param[in] modId Module id - if more than 1 instansiation of this + mode exists,0 otherwise. + @Param[in] intrType Interrupt type (error/normal) selection. + + @Return None. +*//***************************************************************************/ +void FmUnregisterIntr(t_Handle h_Fm, + e_FmEventModules mod, + uint8_t modId, + e_FmIntrType intrType); + +/**************************************************************************//** + @Function FmRegisterFmCtlIntr + + @Description Used to register to one of the fmCtl events in the FM module + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] eventRegId FmCtl event id (0-7). + @Param[in] f_Isr The interrupt service routine. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +void FmRegisterFmCtlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event)); + + +/**************************************************************************//** + @Description enum for defining MAC types +*//***************************************************************************/ +typedef enum e_FmMacType { + e_FM_MAC_10G = 0, /**< 10G MAC */ + e_FM_MAC_1G /**< 1G MAC */ +} e_FmMacType; + +/**************************************************************************//** + @Description Structure for port-FM communication during FM_PORT_Init. + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. + Some fields are optional (depending on configuration) and + will be analized by the port and FM modules accordingly. +*//***************************************************************************/ +typedef struct t_FmInterModulePortInitParams { + uint8_t hardwarePortId; /**< IN. port Id */ + e_FmPortType portType; /**< IN. Port type */ + bool independentMode; /**< IN. TRUE if FM Port operates in independent mode */ + uint16_t liodnOffset; /**< IN. Port's requested resource */ + uint8_t numOfTasks; /**< IN. Port's requested resource */ + uint8_t numOfExtraTasks; /**< IN. Port's requested resource */ + uint8_t numOfOpenDmas; /**< IN. Port's requested resource */ + uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */ + uint32_t sizeOfFifo; /**< IN. Port's requested resource */ + uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */ + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ + uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1. + LIODN base for this port, to be + used together with LIODN offset. */ + t_FmPhysAddr fmMuramPhysBaseAddr;/**< OUT. FM-MURAM physical address*/ +} t_FmInterModulePortInitParams; + +/**************************************************************************//** + @Description Structure for port-FM communication during FM_PORT_Free. +*//***************************************************************************/ +typedef struct t_FmInterModulePortFreeParams { + uint8_t hardwarePortId; /**< IN. port Id */ + e_FmPortType portType; /**< IN. Port type */ +#ifdef FM_QMI_DEQ_OPTIONS_SUPPORT + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ +#endif /* FM_QMI_DEQ_OPTIONS_SUPPORT */ +} t_FmInterModulePortFreeParams; + +/**************************************************************************//** + @Function FmGetPcdPrsBaseAddr + + @Description Get the base address of the Parser from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return Base address. +*//***************************************************************************/ +uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetPcdKgBaseAddr + + @Description Get the base address of the Keygen from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return Base address. +*//***************************************************************************/ +uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetPcdPlcrBaseAddr + + @Description Get the base address of the Policer from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return Base address. +*//***************************************************************************/ +uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetMuramHandle + + @Description Get the handle of the MURAM from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return MURAM module handle. +*//***************************************************************************/ +t_Handle FmGetMuramHandle(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetPhysicalMuramBase + + @Description Get the physical base address of the MURAM from the FM module + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] fmPhysAddr Physical MURAM base + + @Return Physical base address. +*//***************************************************************************/ +void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *fmPhysAddr); + +/**************************************************************************//** + @Function FmGetTimeStampScale + + @Description Used internally by other modules in order to get the timeStamp + period as requested by the application. + + @Param[in] h_Fm A handle to an FM Module. + + @Return TimeStamp period in nanoseconds. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +uint32_t FmGetTimeStampScale(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmResumeStalledPort + + @Description Used internally by FM port to release a stalled port. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] hardwarePortId HW port id. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId); + +/**************************************************************************//** + @Function FmIsPortStalled + + @Description Used internally by FM port to read the port's status. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] hardwarePortId HW port id. + @Param[in] p_IsStalled A pointer to the boolean port stalled state + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled); + +/**************************************************************************//** + @Function FmResetMac + + @Description Used by MAC driver to reset the MAC registers + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] type MAC type. + @Param[in] macId MAC id - according to type. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId); + +/**************************************************************************//** + @Function FmGetClockFreq + + @Description Used by MAC driver to get the FM clock frequency + + @Param[in] h_Fm A handle to an FM Module. + + @Return clock-freq on success; 0 otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +uint16_t FmGetClockFreq(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetId + + @Description Used by PCD driver to read rhe FM id + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +uint8_t FmGetId(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetSetPortParams + + @Description Used by FM-PORT driver to pass and receive parameters between + PORT and FM modules. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in,out] p_PortParams A structure of FM Port parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmGetSetPortParams(t_Handle h_Fm,t_FmInterModulePortInitParams *p_PortParams); + +/**************************************************************************//** + @Function FmFreePortParams + + @Description Used by FM-PORT driver to free port's resources within the FM. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in,out] p_PortParams A structure of FM Port parameters. + + @Return None. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams); + +/**************************************************************************//** + @Function FmSetPortToWorkWithOneRiscOnly + + @Description Used by FM-PORT driver to pass parameter between + PORT and FM modules for working with number of RISC.. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in,out] p_PortParams A structure of FM Port parameters. + + @Return None. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, uint8_t hardwarePortId, uint8_t numOfFmanCtrls); + + +void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd); +void FmUnregisterPcd(t_Handle h_Fm); +t_Handle FmGetPcdHandle(t_Handle h_Fm); +bool FmRamsEccIsExternalCtl(t_Handle h_Fm); +t_Error FmEnableRamsEcc(t_Handle h_Fm); +t_Error FmDisableRamsEcc(t_Handle h_Fm); +void FmGetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo); +t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId); +void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId); +void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents); +uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId); +void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event), t_Handle h_Arg); +void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId); +t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu); +bool FmIsMaster(t_Handle h_Fm); +uint8_t FmGetGuestId(t_Handle h_Fm); +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId); +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +void FmMuramClear(t_Handle h_FmMuram); +t_Error FmSetNumOfOpenDmas(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t numOfOpenDmas, + uint8_t numOfExtraOpenDmas, + bool initialConfig); +t_Error FmSetNumOfTasks(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t numOfTasks, + uint8_t numOfExtraTasks, + bool initialConfig); +t_Error FmSetSizeOfFifo(t_Handle h_Fm, + uint8_t hardwarePortId, + e_FmPortType portType, + bool independentMode, + uint32_t *p_SizeOfFifo, + uint32_t extraSizeOfFifo, + uint8_t deqPipelineDepth, + t_FmInterModulePortRxPoolsParams *p_RxPoolsParams, + bool initialConfig); + + +#endif /* __FM_COMMON_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_pcd_ipc.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_pcd_ipc.h @@ -0,0 +1,326 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_pcd_ipc.h + + @Description FM PCD Inter-Partition prototypes, structures and definitions. +*//***************************************************************************/ +#ifndef __FM_PCD_IPC_H +#define __FM_PCD_IPC_H + +#include "std_ext.h" + + +/**************************************************************************//** + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/**************************************************************************//** + @Description Structure for getting a sw parser address according to a label + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. +*//***************************************************************************/ +typedef _Packed struct t_FmPcdIpcSwPrsLable +{ + uint32_t enumHdr; /**< IN. The existance of this header will envoke + the sw parser code. */ + uint8_t indexPerHdr; /**< IN. Normally 0, if more than one sw parser + attachments for the same header, use this + + index to distinguish between them. */ +} _PackedType t_FmPcdIpcSwPrsLable; + +/**************************************************************************//** + @Description Structure for port-PCD communication. + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. + Some fields are optional (depending on configuration) and + will be analized by the port and FM modules accordingly. +*//***************************************************************************/ +typedef struct t_FmPcdIpcKgSchemesParams +{ + uint8_t guestId; /**< IN */ + uint8_t numOfSchemes; /**< IN */ + uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; /**< OUT */ +} _PackedType t_FmPcdIpcKgSchemesParams; + +typedef struct t_FmPcdIpcKgClsPlanParams +{ + uint8_t guestId; /**< IN */ + uint16_t numOfClsPlanEntries; /**< IN */ + uint8_t clsPlanBase; /**< IN in alloc only */ +} _PackedType t_FmPcdIpcKgClsPlanParams; + +typedef _Packed struct t_FmPcdIpcPlcrAllocParams +{ + uint16_t num; + uint8_t hardwarePortId; + uint16_t plcrProfilesBase; +} _PackedType t_FmPcdIpcPlcrAllocParams; + +typedef _Packed struct t_FmPcdIpcSharedPlcrAllocParams +{ + uint16_t num; /**< IN */ + //uint16_t profilesIds[FM_PCD_PLCR_NUM_ENTRIES]; /**< OUT */ + uint32_t sharedProfilesMask[8]; +} _PackedType t_FmPcdIpcSharedPlcrAllocParams; + +typedef _Packed struct t_FmPcdIpcPrsIncludePort +{ + uint8_t hardwarePortId; /* IN */ + bool include; /* IN */ +} _PackedType t_FmPcdIpcPrsIncludePort; + + +#define FM_PCD_MAX_REPLY_SIZE 16 +#define FM_PCD_MAX_MSG_SIZE 36 +#define FM_PCD_MAX_REPLY_BODY_SIZE 36 + +typedef _Packed struct +{ + uint32_t msgId; + uint8_t msgBody[FM_PCD_MAX_MSG_SIZE]; +} _PackedType t_FmPcdIpcMsg; + +typedef _Packed struct t_FmPcdIpcReply +{ + uint32_t error; + uint8_t replyBody[FM_PCD_MAX_REPLY_BODY_SIZE]; +} _PackedType t_FmPcdIpcReply; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + + +/**************************************************************************//** + @Function FM_PCD_ALLOC_KG_SCHEMES + + @Description Used by FM PCD front-end in order to allocate KG resources + + @Param[in/out] t_FmPcdIpcKgAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_ALLOC_KG_SCHEMES 3 + +/**************************************************************************//** + @Function FM_PCD_FREE_KG_SCHEMES + + @Description Used by FM PCD front-end in order to Free KG resources + + @Param[in/out] t_FmPcdIpcKgSchemesParams Pointer +*//***************************************************************************/ +#define FM_PCD_FREE_KG_SCHEMES 4 + +/**************************************************************************//** + @Function FM_PCD_ALLOC_PROFILES + + @Description Used by FM PCD front-end in order to allocate Policer profiles + + @Param[in/out] t_FmPcdIpcKgSchemesParams Pointer +*//***************************************************************************/ +#define FM_PCD_ALLOC_PROFILES 5 + +/**************************************************************************//** + @Function FM_PCD_FREE_PROFILES + + @Description Used by FM PCD front-end in order to Free Policer profiles + + @Param[in/out] t_FmPcdIpcPlcrAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_FREE_PROFILES 6 + +/**************************************************************************//** + @Function FM_PCD_GET_PHYS_MURAM_BASE + + @Description Used by FM PCD front-end in order to get MURAM base address + + @Param[in/out] t_FmPcdIcPhysAddr Pointer +*//***************************************************************************/ +#define FM_PCD_GET_PHYS_MURAM_BASE 7 + +/**************************************************************************//** + @Function FM_PCD_GET_SW_PRS_OFFSET + + @Description Used by FM front-end to get the SW parser offset of the start of + code relevant to a given label. + + @Param[in/out] t_FmPcdIpcSwPrsLable Pointer +*//***************************************************************************/ +#define FM_PCD_GET_SW_PRS_OFFSET 8 + +/**************************************************************************//** + @Function FM_PCD_ALLOC_SHARED_PROFILES + + @Description Used by FM PCD front-end in order to allocate shared profiles + + @Param[in/out] t_FmPcdIpcSharedPlcrAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_ALLOC_SHARED_PROFILES 9 + +/**************************************************************************//** + @Function FM_PCD_FREE_SHARED_PROFILES + + @Description Used by FM PCD front-end in order to free shared profiles + + @Param[in/out] t_FmPcdIpcSharedPlcrAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_FREE_SHARED_PROFILES 10 + +/**************************************************************************//** + @Function FM_PCD_MASTER_IS_ENABLED + + @Description Used by FM front-end in order to verify + PCD enablement. + + @Param[in] bool Pointer +*//***************************************************************************/ +#define FM_PCD_MASTER_IS_ENABLED 15 + +/**************************************************************************//** + @Function FM_PCD_GUEST_DISABLE + + @Description Used by FM front-end to inform back-end when + front-end PCD is disabled + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_GUEST_DISABLE 16 + +/**************************************************************************//** + @Function FM_PCD_DUMP_REGS + + @Description Used by FM front-end to dump all PCD registers + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_DUMP_REGS 17 + +/**************************************************************************//** + @Function FM_PCD_KG_DUMP_REGS + + @Description Used by FM front-end to dump KG registers + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_KG_DUMP_REGS 18 + +/**************************************************************************//** + @Function FM_PCD_PLCR_DUMP_REGS + + @Description Used by FM front-end to dump PLCR registers + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_PLCR_DUMP_REGS 19 + +/**************************************************************************//** + @Function FM_PCD_PLCR_PROFILE_DUMP_REGS + + @Description Used by FM front-end to dump PLCR specified profile registers + + @Param[in] t_Handle Pointer +*//***************************************************************************/ +#define FM_PCD_PLCR_PROFILE_DUMP_REGS 20 + +/**************************************************************************//** + @Function FM_PCD_PRS_DUMP_REGS + + @Description Used by FM front-end to dump PRS registers + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_PRS_DUMP_REGS 21 + +/**************************************************************************//** + @Function FM_PCD_FREE_KG_CLSPLAN + + @Description Used by FM PCD front-end in order to Free KG classification plan entries + + @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer +*//***************************************************************************/ +#define FM_PCD_FREE_KG_CLSPLAN 22 + +/**************************************************************************//** + @Function FM_PCD_ALLOC_KG_CLSPLAN + + @Description Used by FM PCD front-end in order to allocate KG classification plan entries + + @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer +*//***************************************************************************/ +#define FM_PCD_ALLOC_KG_CLSPLAN 23 + +/**************************************************************************//** + @Function FM_PCD_MASTER_IS_ALIVE + + @Description Used by FM front-end to check that back-end exists + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_MASTER_IS_ALIVE 24 + +/**************************************************************************//** + @Function FM_PCD_GET_COUNTER + + @Description Used by FM front-end to read PCD counters + + @Param[in/out] t_FmPcdIpcGetCounter Pointer +*//***************************************************************************/ +#define FM_PCD_GET_COUNTER 25 + +/**************************************************************************//** + @Function FM_PCD_PRS_INC_PORT_STATS + + @Description Used by FM front-end to set/clear statistics for port + + @Param[in/out] t_FmPcdIpcPrsIncludePort Pointer +*//***************************************************************************/ +#define FM_PCD_PRS_INC_PORT_STATS 26 +/** @} */ /* end of FM_PCD_IPC_grp group */ +/** @} */ /* end of FM_grp group */ + + +#endif /* __FM_PCD_IPC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_kg.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_kg.c @@ -0,0 +1,3189 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_kg.c + + @Description FM PCD ... +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "net_ext.h" +#include "fm_port_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_hc.h" + +#include "fm_pcd_ipc.h" + + +static t_Error WriteKgarWait(t_FmPcd *p_FmPcd, uint32_t kgar) +{ + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgar, kgar); + /* Wait for GO to be idle and read error */ + while ((kgar = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgar)) & FM_PCD_KG_KGAR_GO) ; + if (kgar & FM_PCD_KG_KGAR_ERR) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Keygen scheme access violation")); + return E_OK; +} + +static e_FmPcdKgExtractDfltSelect GetGenericSwDefault(t_FmPcdKgExtractDflt swDefaults[], uint8_t numOfSwDefaults, uint8_t code) +{ + int i; + + switch(code) + { + case( KG_SCH_GEN_PARSE_RESULT_N_FQID): + case( KG_SCH_GEN_DEFAULT): + case( KG_SCH_GEN_NEXTHDR): + for(i=0 ; i mask 0x1-0x7F */ + if(bitOffset<8) + { + mask = 0; + for(i = 0 ; i < bitOffset ; i++, walking1Mask <<= 1) + mask |= walking1Mask; + } + else + { + mask = 0xFF; + numOfOnesToClear = 0; + if(fqid && bitOffset>24) + /* bitOffset 25-31 --> mask 0xFE-0x80 */ + numOfOnesToClear = (uint8_t)(bitOffset-24); + else + /* bitOffset 9-15 --> mask 0xFE-0x80 */ + if(!fqid && bitOffset>8) + numOfOnesToClear = (uint8_t)(bitOffset-8); + for(i = 0 ; i < numOfOnesToClear ; i++, walking1Mask <<= 1) + mask &= ~walking1Mask; + /* bitOffset 8-24 for FQID, 8 for PP --> no mask (0xFF)*/ + } + return mask; +} + + +t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdKgClsPlanGrp *p_ClsPlanGrp; + t_FmPcdIpcKgClsPlanParams kgAlloc; + t_Error err = E_OK; + uint32_t oredVectors = 0; + uint32_t intFlags; + int i, j; + + if (p_Grp->numOfOptions >= FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Too many classification plan basic options selected.")); + + intFlags = FmPcdLock(p_FmPcd); + + /* find a new clsPlan group */ + for(i = 0;ip_FmPcdKg->clsPlanGrps[i].used) + break; + if(i== FM_MAX_NUM_OF_PORTS) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_FULL,("No classification plan groups available.")); + } + p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used = TRUE; + p_Grp->clsPlanGrpId = (uint8_t)i; + + if(p_Grp->numOfOptions == 0) + p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = (uint8_t)i; + + if (!TRY_LOCK(NULL, &p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock)) + { + FmPcdUnlock(p_FmPcd, intFlags); + return ERROR_CODE(E_BUSY); + } + FmPcdUnlock(p_FmPcd, intFlags); + + p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[i]; + p_ClsPlanGrp->netEnvId = p_Grp->netEnvId; + p_ClsPlanGrp->owners = 0; + FmPcdSetClsPlanGrpId(p_FmPcd, p_Grp->netEnvId, p_Grp->clsPlanGrpId); + FmPcdIncNetEnvOwners(p_FmPcd, p_Grp->netEnvId); + + p_ClsPlanGrp->sizeOfGrp = (uint16_t)(1<numOfOptions); + /* a minimal group of 8 is required */ + if(p_ClsPlanGrp->sizeOfGrp < CLS_PLAN_NUM_PER_GRP) + p_ClsPlanGrp->sizeOfGrp = CLS_PLAN_NUM_PER_GRP; + if(p_FmPcd->guestId == NCSW_MASTER_ID) + { + err = KgAllocClsPlanEntries(h_FmPcd, p_ClsPlanGrp->sizeOfGrp, p_FmPcd->guestId, &p_ClsPlanGrp->baseEntry); + + if(err) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); + RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); + } + + } + else + { + t_FmPcdIpcMsg msg; + uint32_t replyLength; + t_FmPcdIpcReply reply; + + /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */ + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + memset(&kgAlloc, 0, sizeof(kgAlloc)); + kgAlloc.guestId = p_FmPcd->guestId; + kgAlloc.numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp; + msg.msgId = FM_PCD_ALLOC_KG_CLSPLAN; + memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); + replyLength = (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry)); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(kgAlloc), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (replyLength != (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry))) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + } + if ((t_Error)reply.error != E_OK) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); + RETURN_ERROR(MINOR, (t_Error)reply.error, NO_MSG); + } + + p_ClsPlanGrp->baseEntry = *(uint8_t*)(reply.replyBody); + } + + /* build classification plan entries parameters */ + p_ClsPlanSet->baseEntry = p_ClsPlanGrp->baseEntry; + p_ClsPlanSet->numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp; + + oredVectors = 0; + for(i = 0; inumOfOptions; i++) + { + oredVectors |= p_Grp->optVectors[i]; + /* save an array of used options - the indexes represent the power of 2 index */ + p_ClsPlanGrp->optArray[i] = p_Grp->options[i]; + } + /* set the classification plan relevant entries so that all bits + * relevant to the list of options is cleared + */ + for(j = 0; jsizeOfGrp; j++) + p_ClsPlanSet->vectors[j] = ~oredVectors; + + for(i = 0; inumOfOptions; i++) + { + /* option i got the place 2^i in the clsPlan array. all entries that + * have bit i set, should have the vector bit cleared. So each option + * has one location that it is exclusive (1,2,4,8...) and represent the + * presence of that option only, and other locations that represent a + * combination of options. + * e.g: + * If ethernet-BC is option 1 it gets entry 2 in the table. Entry 2 + * now represents a frame with ethernet-BC header - so the bit + * representing ethernet-BC should be set and all other option bits + * should be cleared. + * Entries 2,3,6,7,10... also have ethernet-BC and therefore have bit + * vector[1] set, but they also have other bits set: + * 3=1+2, options 0 and 1 + * 6=2+4, options 1 and 2 + * 7=1+2+4, options 0,1,and 2 + * 10=2+8, options 1 and 3 + * etc. + * */ + + /* now for each option (i), we set their bits in all entries (j) + * that contain bit 2^i. + */ + for(j = 0; jsizeOfGrp; j++) + { + if(j & (1<vectors[j] |= p_Grp->optVectors[i]; + } + } + + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); + + return E_OK; +} + +void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdIpcKgClsPlanParams kgAlloc; + t_Error err; + t_FmPcdIpcMsg msg; + uint32_t replyLength; + t_FmPcdIpcReply reply; + + /* check that no port is bound to this clsPlan */ + if(p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].owners) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a clsPlan grp that has ports bound to")); + return; + } + + FmPcdDecNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId); + + /* free blocks */ + if(p_FmPcd->guestId == NCSW_MASTER_ID) + { + KgFreeClsPlanEntries(h_FmPcd, + p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp, + p_FmPcd->guestId, + p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry); + } + else /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */ + { + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + kgAlloc.guestId = p_FmPcd->guestId; + kgAlloc.numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp; + kgAlloc.clsPlanBase = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry; + msg.msgId = FM_PCD_FREE_KG_CLSPLAN; + memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(kgAlloc), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + if (replyLength != sizeof(uint32_t)) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return; + } + if((t_Error)reply.error != E_OK) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Free KG clsPlan failed")); + return; + } + } + + if(grpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId) + p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN; + /* clear clsPlan driver structure */ + memset(&p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId], 0, sizeof(t_FmPcdKgClsPlanGrp)); +} + +t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort, uint32_t *p_SpReg, bool add) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t j, schemesPerPortVector = 0; + t_FmPcdKgScheme *p_Scheme; + uint8_t i, relativeSchemeId; + uint32_t tmp, walking1Mask; + uint8_t swPortIndex = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + /* for each scheme */ + for(i = 0; inumOfSchemes; i++) + { + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]); + if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if(add) + { + if (!FmPcdKgIsSchemeValidSw(h_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid.")); + + p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; + /* check netEnvId of the port against the scheme netEnvId */ + if((p_Scheme->netEnvId != p_BindPort->netEnvId) && (p_Scheme->netEnvId != ILLEGAL_NETENV)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port may not be bound to requested scheme - differ in netEnvId")); + + /* if next engine is private port policer profile, we need to check that it is valid */ + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, p_BindPort->hardwarePortId); + if(p_Scheme->nextRelativePlcrProfile) + { + for(j = 0;jnumOfProfiles;j++) + { + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort); + if(p_Scheme->relativeProfileId+j >= p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Relative profile not in range")); + if(!FmPcdPlcrIsProfileValid(p_FmPcd, (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + p_Scheme->relativeProfileId + j))) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Relative profile not valid.")); + } + } + if(!p_BindPort->useClsPlan) + { + /* if this port does not use clsPlan, it may not be bound to schemes with units that contain + cls plan options. Schemes that are used only directly, should not be checked. + it also may not be bound to schemes that go to CC with units that are options - so we OR + the match vector and the grpBits (= ccUnits) */ + if ((p_Scheme->matchVector != SCHEME_ALWAYS_DIRECT) || p_Scheme->ccUnits) + { + walking1Mask = 0x80000000; + tmp = (p_Scheme->matchVector == SCHEME_ALWAYS_DIRECT)? 0:p_Scheme->matchVector; + tmp |= p_Scheme->ccUnits; + while (tmp) + { + if(tmp & walking1Mask) + { + tmp &= ~walking1Mask; + if(!PcdNetEnvIsUnitWithoutOpts(p_FmPcd, p_Scheme->netEnvId, walking1Mask)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port (without clsPlan) may not be bound to requested scheme - uses clsPlan options")); + } + walking1Mask >>= 1; + } + } + } + } + /* build vector */ + schemesPerPortVector |= 1 << (31 - p_BindPort->schemesIds[i]); + } + + *p_SpReg = schemesPerPortVector; + + return E_OK; +} + +void FmPcdKgIncSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + int i; + t_FmPcdKgScheme *p_Scheme; + + /* for each scheme - update owners counters */ + for(i = 0; inumOfSchemes; i++) + { + p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[p_BindPort->schemesIds[i]]; + + /* increment owners number */ + p_Scheme->owners++; + } +} + +void FmPcdKgDecSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + int i; + t_FmPcdKgScheme *p_Scheme; + + /* for each scheme - update owners counters */ + for(i = 0; inumOfSchemes; i++) + { + p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[p_BindPort->schemesIds[i]]; + + /* increment owners number */ + ASSERT_COND(p_Scheme->owners); + p_Scheme->owners--; + } +} + +static t_Error KgWriteSp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t spReg, bool add) +{ + t_FmPcdKgPortConfigRegs *p_FmPcdKgPortRegs; + uint32_t tmpKgarReg = 0, tmpKgpeSp, intFlags; + t_Error err = E_OK; + + if (p_FmPcd->h_Hc) + return FmHcKgWriteSp(p_FmPcd->h_Hc, hardwarePortId, spReg, add); + + p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs; + + tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId); + intFlags = FmPcdLock(p_FmPcd); + err = WriteKgarWait(p_FmPcd, tmpKgarReg); + if(err) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + tmpKgpeSp = GET_UINT32(p_FmPcdKgPortRegs->kgoe_sp); + + if(add) + tmpKgpeSp |= spReg; + else /* clear */ + tmpKgpeSp &= ~spReg; + + WRITE_UINT32(p_FmPcdKgPortRegs->kgoe_sp, tmpKgpeSp); + + tmpKgarReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId); + + err = WriteKgarWait(p_FmPcd, tmpKgarReg); + FmPcdUnlock(p_FmPcd, intFlags); + return err; +} + +static t_Error KgWriteCpp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t cppReg) +{ + t_FmPcdKgPortConfigRegs *p_FmPcdKgPortRegs; + uint32_t tmpKgarReg, intFlags; + t_Error err; + + if (p_FmPcd->h_Hc) + return FmHcKgWriteCpp(p_FmPcd->h_Hc, hardwarePortId, cppReg); + + p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs; + intFlags = FmPcdLock(p_FmPcd); + WRITE_UINT32(p_FmPcdKgPortRegs->kgoe_cpp, cppReg); + + tmpKgarReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId); + err = WriteKgarWait(p_FmPcd, tmpKgarReg); + FmPcdUnlock(p_FmPcd, intFlags); + + return err; +} + +static void FmPcdKgUnbindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId) +{ + KgWriteCpp(p_FmPcd, hardwarePortId, 0); +} + +static t_Error KgBindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId) +{ + uint32_t tmpKgpeCpp = 0; + + tmpKgpeCpp = FmPcdKgBuildCppReg(p_FmPcd, clsPlanGrpId); + return KgWriteCpp(p_FmPcd, hardwarePortId, tmpKgpeCpp); +} + +t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t spReg; + t_Error err = E_OK; + + err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, TRUE); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, TRUE); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + FmPcdKgIncSchemeOwners(h_FmPcd, p_SchemeBind); + + return E_OK; +} + +t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t spReg; + t_Error err = E_OK; + + err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, FALSE); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, FALSE); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + FmPcdKgDecSchemeOwners(h_FmPcd, p_SchemeBind); + + return E_OK; +} + +bool FmPcdKgIsSchemeValidSw(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + return p_FmPcd->p_FmPcdKg->schemes[schemeId].valid; +} + +bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + if(p_FmPcd->p_FmPcdKg->schemes[schemeId].matchVector == SCHEME_ALWAYS_DIRECT) + return TRUE; + else + return FALSE; +} + +t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags; + uint8_t i,j; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + + intFlags = FmPcdLock(p_FmPcd); + for(j=0,i=0;ip_FmPcdKg->schemesMng[i].allocated) + { + p_FmPcd->p_FmPcdKg->schemesMng[i].allocated = TRUE; + p_FmPcd->p_FmPcdKg->schemesMng[i].ownerId = guestId; + p_SchemesIds[j] = i; + j++; + } + } + + if (j != numOfSchemes) + { + /* roll back */ + for(j--; j; j--) + { + p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].allocated = FALSE; + p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].ownerId = 0; + p_SchemesIds[j] = 0; + } + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("No schemes found")); + } + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; +} + +t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags; + uint8_t i; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + + intFlags = FmPcdLock(p_FmPcd); + + for(i=0;ip_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme was not previously allocated")); + } + if(p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId != guestId) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme is not owned by caller. ")); + } + p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated = FALSE; + p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId = 0; + } + + FmPcdUnlock(p_FmPcd, intFlags); + return E_OK; +} + +t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags; + uint8_t numOfBlocks, blocksFound=0, first=0; + uint8_t i, j; + + intFlags = FmPcdLock(p_FmPcd); + + if(!numOfClsPlanEntries) + { + FmPcdUnlock(p_FmPcd, intFlags); + return E_OK; + } + + if ((numOfClsPlanEntries % CLS_PLAN_NUM_PER_GRP) || (!POWER_OF_2(numOfClsPlanEntries))) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfClsPlanEntries must be a power of 2 and divisible by 8")); + } + + numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP); + + /* try to find consequent blocks */ + first = 0; + for(i=0;ip_FmPcdKg->clsPlanBlocksMng[i].allocated) + { + blocksFound++; + i++; + if(blocksFound == numOfBlocks) + break; + } + else + { + blocksFound = 0; + /* advance i to the next aligned address */ + first = i = (uint8_t)(first + numOfBlocks); + } + } + + if(blocksFound == numOfBlocks) + { + *p_First = (uint8_t)(first*CLS_PLAN_NUM_PER_GRP); + for(j = first; jp_FmPcdKg->clsPlanBlocksMng[j].allocated = TRUE; + p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].ownerId = guestId; + } + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; + } + else + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MINOR, E_FULL, ("No recources for clsPlan")); + } +} + +void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags; + uint8_t numOfBlocks; + uint8_t i, baseBlock; + + UNUSED( guestId); + + intFlags = FmPcdLock(p_FmPcd); + + numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP); + ASSERT_COND(!(base%CLS_PLAN_NUM_PER_GRP)); + + baseBlock = (uint8_t)(base/CLS_PLAN_NUM_PER_GRP); + for(i=baseBlock;ip_FmPcdKg->clsPlanBlocksMng[i].allocated); + ASSERT_COND(guestId == p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId); + p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated = FALSE; + p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId = 0; + } + FmPcdUnlock(p_FmPcd, intFlags); +} + +void KgEnable(t_FmPcd *p_FmPcd) +{ + t_FmPcdKgRegs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + WRITE_UINT32(p_Regs->kggcr,GET_UINT32(p_Regs->kggcr) | FM_PCD_KG_KGGCR_EN); +} + +void KgDisable(t_FmPcd *p_FmPcd) +{ + t_FmPcdKgRegs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + WRITE_UINT32(p_Regs->kggcr,GET_UINT32(p_Regs->kggcr) & ~FM_PCD_KG_KGGCR_EN); +} + +void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdKgClsPlanRegs *p_FmPcdKgPortRegs; + uint32_t tmpKgarReg=0, intFlags; + uint16_t i, j; + + SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs; + + intFlags = FmPcdLock(p_FmPcd); + for(i=p_Set->baseEntry;ibaseEntry+p_Set->numOfClsPlanEntries;i+=8) + { + tmpKgarReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP)); + + for (j = i; j < i+8; j++) + { + ASSERT_COND(IN_RANGE(0, (j - p_Set->baseEntry), FM_PCD_MAX_NUM_OF_CLS_PLANS-1)); + WRITE_UINT32(p_FmPcdKgPortRegs->kgcpe[j % CLS_PLAN_NUM_PER_GRP],p_Set->vectors[j - p_Set->baseEntry]); + } + + if(WriteKgarWait(p_FmPcd, tmpKgarReg) != E_OK) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("WriteKgarWait FAILED")); + return; + } + } + FmPcdUnlock(p_FmPcd, intFlags); +} + +static void PcdKgErrorException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, force, schemeIndexes = 0,index = 0, mask = 0; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + event = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeer); + mask = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeeer); + + schemeIndexes = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseer); + schemeIndexes &= GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseeer); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer); + if(force & event) + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer, force & ~event); + + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeer, event); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseer, schemeIndexes); + + if(event & FM_PCD_KG_DOUBLE_ECC) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC); + if(event & FM_PCD_KG_KEYSIZE_OVERFLOW) + { + if(schemeIndexes) + { + while(schemeIndexes) + { + if(schemeIndexes & 0x1) + p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, (uint16_t)(31 - index)); + schemeIndexes >>= 1; + index+=1; + } + } + else /* this should happen only when interrupt is forced. */ + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW); + } +} + +static t_Error KgInitGuest(t_FmPcd *p_FmPcd) +{ + t_Error err = E_OK; + t_FmPcdIpcKgSchemesParams kgAlloc; + uint32_t replyLength; + t_FmPcdIpcReply reply; + t_FmPcdIpcMsg msg; + + ASSERT_COND(p_FmPcd->guestId != NCSW_MASTER_ID); + + /* in GUEST_PARTITION, we use the IPC */ + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + memset(&kgAlloc, 0, sizeof(t_FmPcdIpcKgSchemesParams)); + kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes; + kgAlloc.guestId = p_FmPcd->guestId; + msg.msgId = FM_PCD_ALLOC_KG_SCHEMES; + memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); + replyLength = sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(kgAlloc), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if(replyLength != (sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy(p_FmPcd->p_FmPcdKg->schemesIds, (uint8_t*)(reply.replyBody),p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t)); + + return (t_Error)reply.error; +} + +static t_Error KgInitMaster(t_FmPcd *p_FmPcd) +{ + t_Error err = E_OK; + t_FmPcdKgRegs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + int i; + uint8_t hardwarePortId = 0; + uint32_t tmpReg; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + + /**********************KGEER******************/ + WRITE_UINT32(p_Regs->kgeer, (FM_PCD_KG_DOUBLE_ECC | FM_PCD_KG_KEYSIZE_OVERFLOW)); + /**********************KGEER******************/ + + /**********************KGEEER******************/ + tmpReg = 0; + if(p_FmPcd->exceptions & FM_PCD_EX_KG_DOUBLE_ECC) + { + FmEnableRamsEcc(p_FmPcd->h_Fm); + tmpReg |= FM_PCD_KG_DOUBLE_ECC; + } + if(p_FmPcd->exceptions & FM_PCD_EX_KG_KEYSIZE_OVERFLOW) + tmpReg |= FM_PCD_KG_KEYSIZE_OVERFLOW; + WRITE_UINT32(p_Regs->kgeeer,tmpReg); + /**********************KGEEER******************/ + + /**********************KGFDOR******************/ + WRITE_UINT32(p_Regs->kgfdor,0); + /**********************KGFDOR******************/ + + /**********************KGGDV0R******************/ + WRITE_UINT32(p_Regs->kggdv0r,0); + /**********************KGGDV0R******************/ + + /**********************KGGDV1R******************/ + WRITE_UINT32(p_Regs->kggdv1r,0); + /**********************KGGDV1R******************/ + + /**********************KGGCR******************/ + WRITE_UINT32(p_Regs->kggcr, NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); + /**********************KGGCR******************/ + + /* register even if no interrupts enabled, to allow future enablement */ + FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR, PcdKgErrorException, p_FmPcd); + + /* clear binding between ports to schemes so that all ports are not bound to any schemes */ + for (i=0;ikgseer, 0xFFFFFFFF); + WRITE_UINT32(p_Regs->kgseeer, 0xFFFFFFFF); + + if(p_FmPcd->p_FmPcdKg->numOfSchemes) + { + err = FmPcdKgAllocSchemes(p_FmPcd, + p_FmPcd->p_FmPcdKg->numOfSchemes, + p_FmPcd->guestId, + p_FmPcd->p_FmPcdKg->schemesIds); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + } + + return E_OK; +} + + +/****************************************/ +/* API routines */ +/****************************************/ +t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdKgRegs *p_Regs; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER); + + p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + if(!FmIsMaster(p_FmPcd->h_Fm)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetAdditionalDataAfterParsing - guest mode!")); + +/* not needed + if(payloadOffset > 256) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("data exatraction offset from parseing end can not be more than 256")); +*/ + + WRITE_UINT32(p_Regs->kgfdor,payloadOffset); + + return E_OK; +} + +t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdKgRegs *p_Regs; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((valueId == 0) || (valueId == 1)), E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER); + + p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + if(!FmIsMaster(p_FmPcd->h_Fm)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetDfltValue - guest mode!")); + + if(valueId == 0) + WRITE_UINT32(p_Regs->kggdv0r,value); + else + WRITE_UINT32(p_Regs->kggdv1r,value); + return E_OK; +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FM_PCD_KgDumpRegs(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + int i = 0, j = 0; + uint8_t hardwarePortId = 0; + uint32_t tmpKgarReg, intFlags; + t_Error err = E_OK; + t_FmPcdIpcMsg msg; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_KG_DUMP_REGS; + return XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL); + } + DUMP_SUBTITLE(("\n")); + DUMP_TITLE(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, ("FmPcdKgRegs Regs")); + + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggcr); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgeer); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgeeer); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgseer); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgseeer); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggsr); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgtpc); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgserc); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfdor); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggdv0r); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggdv1r); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfer); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfeer); + DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgar); + + DUMP_SUBTITLE(("\n")); + intFlags = FmPcdLock(p_FmPcd); + for(j = 0;jp_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs, ("FmPcdKgIndirectAccessSchemeRegs Scheme %d Regs", j)); + + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_mode); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ekfc); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ekdv); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_bmch); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_bmcl); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_fqb); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_hc); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ppc); + + DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_gec, ("kgse_gec")); + DUMP_SUBSTRUCT_ARRAY(i, FM_PCD_KG_NUM_OF_GENERIC_REGS) + { + DUMP_MEMORY(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_gec[i], sizeof(uint32_t)); + } + + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_spc); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_dv0); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_dv1); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ccbs); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_mv); + } + DUMP_SUBTITLE(("\n")); + + for (i=0;ip_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, ("FmPcdKgIndirectAccessPortRegs PCD Port %d regs", hardwarePortId)); + + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, kgoe_sp); + DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, kgoe_cpp); + } + + DUMP_SUBTITLE(("\n")); + for(j=0;jp_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs, ("FmPcdKgIndirectAccessClsPlanRegs Regs group %d", j)); + DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs.kgcpe, ("kgcpe")); + + tmpKgarReg = FmPcdKgBuildReadClsPlanBlockActionReg((uint8_t)j); + err = WriteKgarWait(p_FmPcd, tmpKgarReg); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + DUMP_SUBSTRUCT_ARRAY(i, 8) + DUMP_MEMORY(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs.kgcpe[i], sizeof(uint32_t)); + } + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + +t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams) +{ + t_FmPcdKg *p_FmPcdKg; + + UNUSED(p_FmPcd); + + if (p_FmPcdParams->numOfSchemes > FM_PCD_KG_NUM_OF_SCHEMES) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("numOfSchemes should not exceed %d", FM_PCD_KG_NUM_OF_SCHEMES)); + return NULL; + } + + p_FmPcdKg = (t_FmPcdKg *)XX_Malloc(sizeof(t_FmPcdKg)); + if (!p_FmPcdKg) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Keygen allocation FAILED")); + return NULL; + } + memset(p_FmPcdKg, 0, sizeof(t_FmPcdKg)); + + if(FmIsMaster(p_FmPcd->h_Fm)) + { + p_FmPcdKg->p_FmPcdKgRegs = (t_FmPcdKgRegs *)UINT_TO_PTR(FmGetPcdKgBaseAddr(p_FmPcdParams->h_Fm)); + p_FmPcd->exceptions |= DEFAULT_fmPcdKgErrorExceptions; + } + + p_FmPcdKg->numOfSchemes = p_FmPcdParams->numOfSchemes; + if((p_FmPcd->guestId == NCSW_MASTER_ID) && !p_FmPcdKg->numOfSchemes) + { + p_FmPcdKg->numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES; + DBG(WARNING, ("numOfSchemes was defined 0 by user, re-defined by driver to FM_PCD_KG_NUM_OF_SCHEMES")); + } + + p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN; + + return p_FmPcdKg; +} + +t_Error KgInit(t_FmPcd *p_FmPcd) +{ + if (p_FmPcd->guestId == NCSW_MASTER_ID) + return KgInitMaster(p_FmPcd); + else + return KgInitGuest(p_FmPcd); +} + +t_Error KgFree(t_FmPcd *p_FmPcd) +{ + t_FmPcdIpcKgSchemesParams kgAlloc; + t_Error err = E_OK; + t_FmPcdIpcMsg msg; + uint32_t replyLength; + t_FmPcdIpcReply reply; + + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR); + + if(p_FmPcd->guestId == NCSW_MASTER_ID) + return FmPcdKgFreeSchemes(p_FmPcd, + p_FmPcd->p_FmPcdKg->numOfSchemes, + p_FmPcd->guestId, + p_FmPcd->p_FmPcdKg->schemesIds); + + /* guest */ + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes; + kgAlloc.guestId = p_FmPcd->guestId; + ASSERT_COND(kgAlloc.numOfSchemes < FM_PCD_KG_NUM_OF_SCHEMES); + memcpy(kgAlloc.schemesIds, p_FmPcd->p_FmPcdKg->schemesIds , (sizeof(uint8_t))*kgAlloc.numOfSchemes); + msg.msgId = FM_PCD_FREE_KG_SCHEMES; + memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(kgAlloc), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + return (t_Error)reply.error; +} + +t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdKgInterModuleClsPlanGrpParams grpParams, *p_GrpParams; + t_FmPcdKgClsPlanGrp *p_ClsPlanGrp; + t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; + t_Error err; + + memset(&grpParams, 0, sizeof(grpParams)); + grpParams.clsPlanGrpId = ILLEGAL_CLS_PLAN; + p_GrpParams = &grpParams; + + p_GrpParams->netEnvId = netEnvId; + err = PcdGetClsPlanGrpParams(h_FmPcd, p_GrpParams); + if(err) + RETURN_ERROR(MINOR,err,NO_MSG); + if(p_GrpParams->grpExists) + *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId; + else + { + p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); + if (!p_ClsPlanSet) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("memory allocation failed for p_ClsPlanSet")); + memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); + err = FmPcdKgBuildClsPlanGrp(h_FmPcd, p_GrpParams, p_ClsPlanSet); + if (err) + { + XX_Free(p_ClsPlanSet); + RETURN_ERROR(MINOR,err,NO_MSG); + } + *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId; + + if (p_FmPcd->h_Hc) + { + /* write clsPlan entries to memory */ + err = FmHcPcdKgSetClsPlan(p_FmPcd->h_Hc, p_ClsPlanSet); + if (err) + { + XX_Free(p_ClsPlanSet); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + else + /* write clsPlan entries to memory */ + KgSetClsPlan(p_FmPcd, p_ClsPlanSet); + + XX_Free(p_ClsPlanSet); + } + + /* mark if this is an empty classification group */ + if(*p_ClsPlanGrpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId) + *p_IsEmptyClsPlanGrp = TRUE; + else + *p_IsEmptyClsPlanGrp = FALSE; + + p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId]; + + /* increment owners number */ + p_ClsPlanGrp->owners++; + + /* copy options array for port */ + memcpy(p_OptArray, &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId].optArray, FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)*sizeof(protocolOpt_t)); + + /* bind port to the new or existing group */ + err = KgBindPortToClsPlanGrp(p_FmPcd, hardwarePortId, p_GrpParams->clsPlanGrpId); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdKgClsPlanGrp *p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId]; + t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; + + FmPcdKgUnbindPortToClsPlanGrp(p_FmPcd, hardwarePortId); + + /* decrement owners number */ + ASSERT_COND(p_ClsPlanGrp->owners); + p_ClsPlanGrp->owners--; + + if(!p_ClsPlanGrp->owners) + { + if (p_FmPcd->h_Hc) + return FmHcPcdKgDeleteClsPlan(p_FmPcd->h_Hc, clsPlanGrpId); + else + { + /* clear clsPlan entries in memory */ + p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); + if (!p_ClsPlanSet) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("memory allocation failed for p_ClsPlanSet")); + memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); + p_ClsPlanSet->baseEntry = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry; + p_ClsPlanSet->numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp; + KgSetClsPlan(p_FmPcd, p_ClsPlanSet); + XX_Free(p_ClsPlanSet); + FmPcdKgDestroyClsPlanGrp(h_FmPcd, clsPlanGrpId); + } + } + return E_OK; +} + +t_Error FmPcdKgBuildScheme(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_Scheme, t_FmPcdKgInterModuleSchemeRegs *p_SchemeRegs) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t grpBits = 0; + uint8_t grpBase; + bool direct=TRUE, absolute=FALSE; + uint16_t profileId=0, numOfProfiles=0, relativeProfileId; + t_Error err = E_OK; + int i = 0; + t_NetEnvParams netEnvParams; + uint32_t tmpReg, fqbTmp = 0, ppcTmp = 0, selectTmp, maskTmp, knownTmp, genTmp; + t_FmPcdKgKeyExtractAndHashParams *p_KeyAndHash = NULL; + uint8_t j, curr, idx; + uint8_t id, shift=0, code=0, offset=0, size=0; + t_FmPcdExtractEntry *p_Extract = NULL; + t_FmPcdKgExtractedOrParams *p_ExtractOr; + bool generic = FALSE; + t_KnownFieldsMasks bitMask; + e_FmPcdKgExtractDfltSelect swDefault = (e_FmPcdKgExtractDfltSelect)0; + t_FmPcdKgSchemesExtracts *p_LocalExtractsArray; + uint8_t numOfSwDefaults = 0; + t_FmPcdKgExtractDflt swDefaults[NUM_OF_SW_DEFAULTS]; + uint8_t currGenId = 0, relativeSchemeId; + + if(!p_Scheme->modify) + relativeSchemeId = p_Scheme->id.relativeSchemeId; + else + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, (uint8_t)(PTR_TO_UINT(p_Scheme->id.h_Scheme)-1)); + + memset(&p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId], 0, sizeof(t_FmPcdKgScheme)); + memset(swDefaults, 0, NUM_OF_SW_DEFAULTS*sizeof(t_FmPcdKgExtractDflt)); + memset(p_SchemeRegs, 0, sizeof(t_FmPcdKgInterModuleSchemeRegs)); + + if (p_Scheme->netEnvParams.numOfDistinctionUnits > FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("numOfDistinctionUnits should not exceed %d", FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)); + + /* by netEnv parameters, get match vector */ + if(!p_Scheme->alwaysDirect) + { + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId = + (uint8_t)(PTR_TO_UINT(p_Scheme->netEnvParams.h_NetEnv)-1); + netEnvParams.netEnvId = p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId; + netEnvParams.numOfDistinctionUnits = p_Scheme->netEnvParams.numOfDistinctionUnits; + memcpy(netEnvParams.unitIds, p_Scheme->netEnvParams.unitIds, (sizeof(uint8_t))*p_Scheme->netEnvParams.numOfDistinctionUnits); + err = PcdGetUnitsVector(p_FmPcd, &netEnvParams); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector = netEnvParams.vector; + } + else + { + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector = SCHEME_ALWAYS_DIRECT; + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId = ILLEGAL_NETENV; + } + + if(p_Scheme->nextEngine == e_FM_PCD_INVALID) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next Engine of the scheme is not Valid")); + + if(p_Scheme->bypassFqidGeneration) + { +#ifdef FM_KG_NO_BYPASS_FQID_GEN + { + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPcd->h_Fm, &revInfo); + if (revInfo.majorRev != 4) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassFqidGeneration.")); + } +#endif /* FM_KG_NO_BYPASS_FQID_GEN */ + if(p_Scheme->baseFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid set for a scheme that does not generate an FQID")); + } + else + if(!p_Scheme->baseFqid) + DBG(WARNING, ("baseFqid is 0.")); + + if(p_Scheme->nextEngine == e_FM_PCD_PLCR) + { + direct = p_Scheme->kgNextEngineParams.plcrProfile.direct; + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr = direct; + absolute = (bool)(p_Scheme->kgNextEngineParams.plcrProfile.sharedProfile ? TRUE : FALSE); + if(!direct && absolute) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Indirect policing is not available when profile is shared.")); + + if(direct) + { + profileId = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.directRelativeProfileId; + numOfProfiles = 1; + } + else + { + profileId = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; + shift = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; + numOfProfiles = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.numOfProfiles; + } + } + + if(p_Scheme->nextEngine == e_FM_PCD_CC) + { +#ifdef FM_KG_NO_BYPASS_PLCR_PROFILE_GEN + if((p_Scheme->kgNextEngineParams.cc.plcrNext) && (p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) + { + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPcd->h_Fm, &revInfo); + if (revInfo.majorRev != 4) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassPlcrProfileGeneration.")); + } +#endif /* FM_KG_NO_BYPASS_PLCR_PROFILE_GEN */ + + err = FmPcdCcGetGrpParams(p_Scheme->kgNextEngineParams.cc.h_CcTree, + p_Scheme->kgNextEngineParams.cc.grpId, + &grpBits, + &grpBase); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].ccUnits = grpBits; + + if((p_Scheme->kgNextEngineParams.cc.plcrNext) && + (!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) + { + if(p_Scheme->kgNextEngineParams.cc.plcrProfile.sharedProfile) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Shared profile may not be used after Coarse classification.")); + absolute = FALSE; + direct = p_Scheme->kgNextEngineParams.cc.plcrProfile.direct; + if(direct) + { + profileId = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.directRelativeProfileId; + numOfProfiles = 1; + } + else + { + profileId = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; + shift = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; + numOfProfiles = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.numOfProfiles; + } + } + } + + /* if policer is used directly after KG, or after CC */ + if((p_Scheme->nextEngine == e_FM_PCD_PLCR) || + ((p_Scheme->nextEngine == e_FM_PCD_CC) && + (p_Scheme->kgNextEngineParams.cc.plcrNext) && + (!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration))) + { + /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */ + if(absolute) + { + /* for absolute direct policy only, */ + relativeProfileId = profileId; + err = FmPcdPlcrGetAbsoluteProfileId(h_FmPcd,e_FM_PCD_PLCR_SHARED,NULL, relativeProfileId, &profileId); + if(err) + RETURN_ERROR(MAJOR, err, ("Shared profile not valid offset")); + if(!FmPcdPlcrIsProfileValid(p_FmPcd, profileId)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Shared profile not valid.")); + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId = profileId; + } + else + { + /* save relative profile id's for later check */ + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile = TRUE; + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId = profileId; + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].numOfProfiles = numOfProfiles; + } + } + else + { + /* if policer is NOT going to be used after KG at all than if bypassFqidGeneration + is set, we do not need numOfUsedExtractedOrs and hashDistributionNumOfFqids */ + if(p_Scheme->bypassFqidGeneration && p_Scheme->numOfUsedExtractedOrs) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("numOfUsedExtractedOrs is set in a scheme that does not generate FQID or policer profile ID")); + if(p_Scheme->bypassFqidGeneration && + p_Scheme->useHash && + p_Scheme->keyExtractAndHashParams.hashDistributionNumOfFqids) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("hashDistributionNumOfFqids is set in a scheme that does not generate FQID or policer profile ID")); + } + + /* configure all 21 scheme registers */ + tmpReg = KG_SCH_MODE_EN; + switch(p_Scheme->nextEngine) + { + case(e_FM_PCD_PLCR): + /* add to mode register - NIA */ + tmpReg |= KG_SCH_MODE_NIA_PLCR; + tmpReg |= NIA_ENG_PLCR; + tmpReg |= (uint32_t)(p_Scheme->kgNextEngineParams.plcrProfile.sharedProfile ? NIA_PLCR_ABSOLUTE:0); + /* initialize policer profile command - */ + /* configure kgse_ppc */ + if(direct) + /* use profileId as base, other fields are 0 */ + p_SchemeRegs->kgse_ppc = (uint32_t)profileId; + else + { + if(shift > MAX_PP_SHIFT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT)); + + if(!numOfProfiles || !POWER_OF_2(numOfProfiles)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2")); + + ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH; + ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW; + ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT); + ppcTmp |= (uint32_t)profileId; + + p_SchemeRegs->kgse_ppc = ppcTmp; + } + break; + case(e_FM_PCD_CC): + /* mode reg - define NIA */ + tmpReg |= (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC); + + p_SchemeRegs->kgse_ccbs = grpBits; + tmpReg |= (uint32_t)(grpBase << KG_SCH_MODE_CCOBASE_SHIFT); + + if(p_Scheme->kgNextEngineParams.cc.plcrNext) + { + if(!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration) + { + /* find out if absolute or relative */ + if(absolute) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("It is illegal to request a shared profile in a scheme that is in a KG->CC->PLCR flow")); + if(direct) + { + /* mask = 0, base = directProfileId */ + p_SchemeRegs->kgse_ppc = (uint32_t)profileId; + } + else + { + if(shift > MAX_PP_SHIFT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT)); + if(!numOfProfiles || !POWER_OF_2(numOfProfiles)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2")); + + ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH; + ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW; + ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT); + ppcTmp |= (uint32_t)profileId; + + p_SchemeRegs->kgse_ppc = ppcTmp; + } + } + else + ppcTmp = KG_SCH_PP_NO_GEN; + } + break; + case(e_FM_PCD_DONE): + if(p_Scheme->kgNextEngineParams.doneAction == e_FM_PCD_DROP_FRAME) + tmpReg |= (NIA_ENG_BMI | NIA_BMI_AC_DISCARD); + else + tmpReg |= (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); + break; + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine not supported")); + } + p_SchemeRegs->kgse_mode = tmpReg; + + p_SchemeRegs->kgse_mv = p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector; + + if(p_Scheme->useHash) + { + p_KeyAndHash = &p_Scheme->keyExtractAndHashParams; + + if (p_KeyAndHash->numOfUsedExtracts >= FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfUsedExtracts out of range")); + + /* configure kgse_dv0 */ + p_SchemeRegs->kgse_dv0 = p_KeyAndHash->privateDflt0; + + /* configure kgse_dv1 */ + p_SchemeRegs->kgse_dv1 = p_KeyAndHash->privateDflt1; + + if(!p_Scheme->bypassFqidGeneration) + { + if(!p_KeyAndHash->hashDistributionNumOfFqids || !POWER_OF_2(p_KeyAndHash->hashDistributionNumOfFqids)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionNumOfFqids must not be 0 and must be a power of 2")); + if((p_KeyAndHash->hashDistributionNumOfFqids-1) & p_Scheme->baseFqid) + DBG(WARNING, ("baseFqid unaligned. Distribution may result in less than hashDistributionNumOfFqids queues.")); + } + + /* configure kgse_ekdv */ + tmpReg = 0; + for( i=0 ;inumOfUsedDflts ; i++) + { + switch(p_KeyAndHash->dflts[i].type) + { + case(e_FM_PCD_KG_MAC_ADDR): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MAC_ADDR_SHIFT); + break; + case(e_FM_PCD_KG_TCI): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCI_SHIFT); + break; + case(e_FM_PCD_KG_ENET_TYPE): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_ENET_TYPE_SHIFT); + break; + case(e_FM_PCD_KG_PPP_SESSION_ID): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_SESSION_ID_SHIFT); + break; + case(e_FM_PCD_KG_PPP_PROTOCOL_ID): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT); + break; + case(e_FM_PCD_KG_MPLS_LABEL): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MPLS_LABEL_SHIFT); + break; + case(e_FM_PCD_KG_IP_ADDR): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_ADDR_SHIFT); + break; + case(e_FM_PCD_KG_PROTOCOL_TYPE): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PROTOCOL_TYPE_SHIFT); + break; + case(e_FM_PCD_KG_IP_TOS_TC): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_TOS_TC_SHIFT); + break; + case(e_FM_PCD_KG_IPV6_FLOW_LABEL): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT); + break; + case(e_FM_PCD_KG_IPSEC_SPI): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IPSEC_SPI_SHIFT); + break; + case(e_FM_PCD_KG_L4_PORT): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT); + break; + case(e_FM_PCD_KG_TCP_FLAG): + tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCP_FLAG_SHIFT); + break; + case(e_FM_PCD_KG_GENERIC_FROM_DATA): + swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA; + swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; + numOfSwDefaults ++; + break; + case(e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V): + swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V; + swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; + numOfSwDefaults ++; + break; + case(e_FM_PCD_KG_GENERIC_NOT_FROM_DATA): + swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA; + swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; + numOfSwDefaults ++; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + } + p_SchemeRegs->kgse_ekdv = tmpReg; + + p_LocalExtractsArray = (t_FmPcdKgSchemesExtracts *)XX_Malloc(sizeof(t_FmPcdKgSchemesExtracts)); + if(!p_LocalExtractsArray) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + + /* configure kgse_ekfc and kgse_gec */ + knownTmp = 0; + for( i=0 ;inumOfUsedExtracts ; i++) + { + p_Extract = &p_KeyAndHash->extractArray[i]; + switch(p_Extract->type) + { + case(e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO): + knownTmp |= KG_SCH_KN_PORT_ID; + /* save in driver structure */ + p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(KG_SCH_KN_PORT_ID); + p_LocalExtractsArray->extractsArray[i].known = TRUE; + break; + case(e_FM_PCD_EXTRACT_BY_HDR): + switch(p_Extract->extractByHdr.hdr) + { + case(HEADER_TYPE_UDP_ENCAP_ESP): + switch(p_Extract->extractByHdr.type) + { + case(e_FM_PCD_EXTRACT_FROM_HDR): + /* case where extraction from ESP only */ + if (p_Extract->extractByHdr.extractByHdrType.fromHdr.offset >= UDP_HEADER_SIZE) + { + p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); + p_Extract->extractByHdr.extractByHdrType.fromHdr.offset -= UDP_HEADER_SIZE; + p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; + } + else + { + p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; + p_Extract->extractByHdr.ignoreProtocolValidation = FALSE; + } + break; + case(e_FM_PCD_EXTRACT_FROM_FIELD): + switch(p_Extract->extractByHdr.extractByHdrType.fromField.field.udpEncapEsp) + { + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC): + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST): + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN): + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM): + p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; + break; + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI): + p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; + p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); + p_Extract->extractByHdr.extractByHdrType.fromField.size = p_Extract->extractByHdr.extractByHdrType.fromField.size; + /*p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SPI_OFFSET;*/ + p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; + break; + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM): + p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; + p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); + p_Extract->extractByHdr.extractByHdrType.fromField.size = p_Extract->extractByHdr.extractByHdrType.fromField.size; + p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SEQ_NUM_OFFSET; + p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; + break; + } + break; + case(e_FM_PCD_EXTRACT_FULL_FIELD): + switch(p_Extract->extractByHdr.extractByHdrType.fullField.udpEncapEsp) + { + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC): + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST): + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN): + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM): + p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; + break; + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI): + p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; + p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); + p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SPI_SIZE; + p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SPI_OFFSET; + p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; + break; + case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM): + p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; + p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); + p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SEQ_NUM_SIZE; + p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SEQ_NUM_OFFSET; + p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; + break; + } + break; + } + break; + default: + break; + } + switch(p_Extract->extractByHdr.type) + { + case(e_FM_PCD_EXTRACT_FROM_HDR): + generic = TRUE; + /* get the header code for the generic extract */ + code = GetGenHdrCode(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, p_Extract->extractByHdr.ignoreProtocolValidation); + /* set generic register fields */ + offset = p_Extract->extractByHdr.extractByHdrType.fromHdr.offset; + size = p_Extract->extractByHdr.extractByHdrType.fromHdr.size; + break; + case(e_FM_PCD_EXTRACT_FROM_FIELD): + generic = TRUE; + /* get the field code for the generic extract */ + code = GetGenFieldCode(p_Extract->extractByHdr.hdr, + p_Extract->extractByHdr.extractByHdrType.fromField.field, p_Extract->extractByHdr.ignoreProtocolValidation,p_Extract->extractByHdr.hdrIndex); + offset = p_Extract->extractByHdr.extractByHdrType.fromField.offset; + size = p_Extract->extractByHdr.extractByHdrType.fromField.size; + break; + case(e_FM_PCD_EXTRACT_FULL_FIELD): + if(!p_Extract->extractByHdr.ignoreProtocolValidation) + { + /* if we have a known field for it - use it, otherwise use generic */ + bitMask = GetKnownProtMask(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, + p_Extract->extractByHdr.extractByHdrType.fullField); + if(bitMask) + { + knownTmp |= bitMask; + /* save in driver structure */ + p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(bitMask); + p_LocalExtractsArray->extractsArray[i].known = TRUE; + } + else + generic = TRUE; + + } + else + generic = TRUE; + if(generic) + { + /* tmp - till we cover more headers under generic */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Full header selection not supported")); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + case(e_FM_PCD_EXTRACT_NON_HDR): + /* use generic */ + generic = TRUE; + offset = 0; + /* get the field code for the generic extract */ + code = GetGenCode(p_Extract->extractNonHdr.src, &offset); + offset += p_Extract->extractNonHdr.offset; + size = p_Extract->extractNonHdr.size; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + if(generic) + { + /* set generic register fields */ + if(currGenId >= FM_PCD_KG_NUM_OF_GENERIC_REGS) + RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); + if(!code) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); + + genTmp = KG_SCH_GEN_VALID; + genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT); + genTmp |= offset; + if((size > MAX_KG_SCH_SIZE) || (size < 1)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal extraction (size out of range)")); + genTmp |= (uint32_t)((size - 1) << KG_SCH_GEN_SIZE_SHIFT); + swDefault = GetGenericSwDefault(swDefaults, numOfSwDefaults, code); + if(swDefault == e_FM_PCD_KG_DFLT_ILLEGAL) + DBG(WARNING, ("No sw default configured")); + + genTmp |= swDefault << KG_SCH_GEN_DEF_SHIFT; + genTmp |= KG_SCH_GEN_MASK; + p_SchemeRegs->kgse_gec[currGenId] = genTmp; + /* save in driver structure */ + p_LocalExtractsArray->extractsArray[i].id = currGenId++; + p_LocalExtractsArray->extractsArray[i].known = FALSE; + generic = FALSE; + } + } + p_SchemeRegs->kgse_ekfc = knownTmp; + + selectTmp = 0; + maskTmp = 0xFFFFFFFF; + /* configure kgse_bmch, kgse_bmcl and kgse_fqb */ + + if(p_KeyAndHash->numOfUsedMasks >= FM_PCD_KG_NUM_OF_EXTRACT_MASKS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Only %d masks supported", FM_PCD_KG_NUM_OF_EXTRACT_MASKS)); + for( i=0 ;inumOfUsedMasks ; i++) + { + /* Get the relative id of the extract (for known 0-0x1f, for generic 0-7) */ + id = p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].id; + /* Get the shift of the select field (depending on i) */ + GET_MASK_SEL_SHIFT(shift,i); + if (p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].known) + selectTmp |= id << shift; + else + selectTmp |= (id + MASK_FOR_GENERIC_BASE_ID) << shift; + + /* Get the shift of the offset field (depending on i) - may + be in kgse_bmch or in kgse_fqb (depending on i) */ + GET_MASK_OFFSET_SHIFT(shift,i); + if (i<=1) + selectTmp |= p_KeyAndHash->masks[i].offset << shift; + else + fqbTmp |= p_KeyAndHash->masks[i].offset << shift; + + /* Get the shift of the mask field (depending on i) */ + GET_MASK_SHIFT(shift,i); + /* pass all bits */ + maskTmp |= KG_SCH_BITMASK_MASK << shift; + /* clear bits that need masking */ + maskTmp &= ~(0xFF << shift) ; + /* set mask bits */ + maskTmp |= (p_KeyAndHash->masks[i].mask << shift) ; + } + p_SchemeRegs->kgse_bmch = selectTmp; + p_SchemeRegs->kgse_bmcl = maskTmp; + /* kgse_fqb will be written t the end of the routine */ + + /* configure kgse_hc */ + if(p_KeyAndHash->hashShift > MAX_HASH_SHIFT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashShift must not be larger than %d", MAX_HASH_SHIFT)); + if(p_KeyAndHash->hashDistributionFqidsShift > MAX_DIST_FQID_SHIFT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionFqidsShift must not be larger than %d", MAX_DIST_FQID_SHIFT)); + + tmpReg = 0; + + tmpReg |= ((p_KeyAndHash->hashDistributionNumOfFqids - 1) << p_KeyAndHash->hashDistributionFqidsShift); + tmpReg |= p_KeyAndHash->hashShift << KG_SCH_HASH_CONFIG_SHIFT_SHIFT; + + if(p_KeyAndHash->symmetricHash) + { + if((!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACDST)) || + (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC1) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST1)) || + (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC2) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST2)) || + (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PDST))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("symmetricHash set but src/dest extractions missing")); + tmpReg |= KG_SCH_HASH_CONFIG_SYM; + } + p_SchemeRegs->kgse_hc = tmpReg; + + /* build the return array describing the order of the extractions */ + + /* the last currGenId places of the array + are for generic extracts that are always last. + We now sort for the calculation of the order of the known + extractions we sort the known extracts between orderedArray[0] and + orderedArray[p_KeyAndHash->numOfUsedExtracts - currGenId - 1]. + for the calculation of the order of the generic extractions we use: + num_of_generic - currGenId + num_of_known - p_KeyAndHash->numOfUsedExtracts - currGenId + first_generic_index = num_of_known */ + curr = 0; + for (i=0;inumOfUsedExtracts ; i++) + { + if(p_LocalExtractsArray->extractsArray[i].known) + { + ASSERT_COND(curr<(p_KeyAndHash->numOfUsedExtracts - currGenId)); + j = curr; + /* id is the extract id (port id = 0, mac src = 1 etc.). the value in the array is the original + index in the user's extractions array */ + /* we compare the id of the current extract with the id of the extract in the orderedArray[j-1] + location */ + while((j > 0) && (p_LocalExtractsArray->extractsArray[i].id < + p_LocalExtractsArray->extractsArray[p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j-1]].id)) + { + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j] = + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j-1]; + j--; + } + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j] = (uint8_t)i; + curr++; + } + else + { + /* index is first_generic_index + generic index (id) */ + idx = (uint8_t)(p_KeyAndHash->numOfUsedExtracts - currGenId + p_LocalExtractsArray->extractsArray[i].id); + ASSERT_COND(idx < FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY); + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[idx]= (uint8_t)i; + } + } + XX_Free(p_LocalExtractsArray); + p_LocalExtractsArray = NULL; + + } + else + { + /* clear all unused registers: */ + p_SchemeRegs->kgse_ekfc = 0; + p_SchemeRegs->kgse_ekdv = 0; + p_SchemeRegs->kgse_bmch = 0; + p_SchemeRegs->kgse_bmcl = 0; + p_SchemeRegs->kgse_hc = 0; + p_SchemeRegs->kgse_dv0 = 0; + p_SchemeRegs->kgse_dv1 = 0; + } + + if(p_Scheme->bypassFqidGeneration) + p_SchemeRegs->kgse_hc |= KG_SCH_HASH_CONFIG_NO_FQID; + + /* configure kgse_spc */ + if( p_Scheme->schemeCounter.update) + p_SchemeRegs->kgse_spc = p_Scheme->schemeCounter.value; + + + /* check that are enough generic registers */ + if(p_Scheme->numOfUsedExtractedOrs + currGenId > FM_PCD_KG_NUM_OF_GENERIC_REGS) + RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); + + /* extracted OR mask on Qid */ + for( i=0 ;inumOfUsedExtractedOrs ; i++) + { + + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs = TRUE; + /* configure kgse_gec[i] */ + p_ExtractOr = &p_Scheme->extractedOrs[i]; + switch(p_ExtractOr->type) + { + case(e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO): + code = KG_SCH_GEN_PARSE_RESULT_N_FQID; + offset = 0; + break; + case(e_FM_PCD_EXTRACT_BY_HDR): + /* get the header code for the generic extract */ + code = GetGenHdrCode(p_ExtractOr->extractByHdr.hdr, p_ExtractOr->extractByHdr.hdrIndex, p_ExtractOr->extractByHdr.ignoreProtocolValidation); + /* set generic register fields */ + offset = p_ExtractOr->extractionOffset; + break; + case(e_FM_PCD_EXTRACT_NON_HDR): + /* get the field code for the generic extract */ + offset = 0; + code = GetGenCode(p_ExtractOr->src, &offset); + offset += p_ExtractOr->extractionOffset; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + /* set generic register fields */ + if(!code) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); + genTmp = KG_SCH_GEN_EXTRACT_TYPE | KG_SCH_GEN_VALID; + genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT); + genTmp |= offset; + if(!!p_ExtractOr->bitOffsetInFqid == !!p_ExtractOr->bitOffsetInPlcrProfile) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" extracted byte must effect either FQID or Policer profile")); + + /************************************************************************************ + bitOffsetInFqid and bitOffsetInPolicerProfile are translated to rotate parameter + in the following way: + + Driver API and implementation: + ============================== + FQID: extracted OR byte may be shifted right 1-31 bits to effect parts of the FQID. + if shifted less than 8 bits, or more than 24 bits a mask is set on the bits that + are not overlapping FQID. + ------------------------ + | FQID (24) | + ------------------------ + -------- + | | extracted OR byte + -------- + + Policer Profile: extracted OR byte may be shifted right 1-15 bits to effect parts of the + PP id. Unless shifted exactly 8 bits to overlap the PP id, a mask is set on the bits that + are not overlapping PP id. + + -------- + | PP (8) | + -------- + -------- + | | extracted OR byte + -------- + + HW implementation + ================= + FQID and PP construct a 32 bit word in the way describe below. Extracted byte is located + as the highest byte of that word and may be rotated to effect any part os the FQID or + the PP. + ------------------------ -------- + | FQID (24) || PP (8) | + ------------------------ -------- + -------- + | | extracted OR byte + -------- + + ************************************************************************************/ + + if(p_ExtractOr->bitOffsetInFqid) + { + if(p_ExtractOr->bitOffsetInFqid > MAX_KG_SCH_FQID_BIT_OFFSET ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInFqid out of range)")); + if(p_ExtractOr->bitOffsetInFqid<8) + genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid+24) << KG_SCH_GEN_SIZE_SHIFT); + else + genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid-8) << KG_SCH_GEN_SIZE_SHIFT); + p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInFqid, TRUE); + } + else /* effect policer profile */ + { + if(p_ExtractOr->bitOffsetInPlcrProfile > MAX_KG_SCH_PP_BIT_OFFSET ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInPlcrProfile out of range)")); + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile = p_ExtractOr->bitOffsetInPlcrProfile; + genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInPlcrProfile+16) << KG_SCH_GEN_SIZE_SHIFT); + p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInPlcrProfile, FALSE); + } + + genTmp |= (uint32_t)(p_ExtractOr->extractionOffset << KG_SCH_GEN_DEF_SHIFT); + /* clear bits that need masking */ + genTmp &= ~KG_SCH_GEN_MASK ; + /* set mask bits */ + genTmp |= (uint32_t)(p_ExtractOr->mask << KG_SCH_GEN_MASK_SHIFT); + p_SchemeRegs->kgse_gec[currGenId++] = genTmp; + + } + /* clear all unused GEC registers */ + for( i=currGenId ;ikgse_gec[i] = 0; + + /* add base Qid for this scheme */ + /* add configuration for kgse_fqb */ + if(p_Scheme->baseFqid & ~0x00FFFFFF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid must be between 1 and 2^24-1")); + + fqbTmp |= p_Scheme->baseFqid; + p_SchemeRegs->kgse_fqb = fqbTmp; + + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine = p_Scheme->nextEngine; + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction = p_Scheme->kgNextEngineParams.doneAction; + return E_OK; +} + +void FmPcdKgValidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(!p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + if(p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId != ILLEGAL_NETENV) + FmPcdIncNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId); + p_FmPcd->p_FmPcdKg->schemes[schemeId].valid = TRUE; +} + +void FmPcdKgInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId) +{ + + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + if(p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId != ILLEGAL_NETENV) + FmPcdDecNetEnvOwners(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId); + p_FmPcd->p_FmPcdKg->schemes[schemeId].valid = FALSE; +} + +uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction; +} + +uint32_t FmPcdKgGetPointedOwners(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + return p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners; +} + +bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + return p_FmPcd->p_FmPcdKg->schemes[schemeId].directPlcr; +} + + +uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + return p_FmPcd->p_FmPcdKg->schemes[schemeId].relativeProfileId; +} + + +bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + if((p_FmPcd->p_FmPcdKg->schemes[schemeId].extractedOrs && + p_FmPcd->p_FmPcdKg->schemes[schemeId].bitOffsetInPlcrProfile) || + p_FmPcd->p_FmPcdKg->schemes[schemeId].nextRelativePlcrProfile) + return TRUE; + else + return FALSE; + +} +void FmPcdKgUpatePointedOwner(t_Handle h_FmPcd, uint8_t schemeId, bool add) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + if(add) + p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners++; + else + p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners--; +} + +e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + return p_FmPcd->p_FmPcdKg->schemes[schemeId].nextEngine; +} + +e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + return p_FmPcd->p_FmPcdKg->schemes[schemeId].doneAction; +} + +void FmPcdKgUpdateRequiredAction(t_Handle h_FmPcd, uint8_t schemeId, uint32_t requiredAction) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); + + p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction = requiredAction; +} + +t_Error FmPcdKgCheckInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + if(schemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + /* check that no port is bound to this scheme */ + if(p_FmPcd->p_FmPcdKg->schemes[schemeId].owners) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a scheme that has ports bound to")); + if(!p_FmPcd->p_FmPcdKg->schemes[schemeId].valid) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete an invalid scheme")); + return E_OK; +} + +uint32_t FmPcdKgBuildCppReg(t_Handle h_FmPcd, uint8_t clsPlanGrpId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpKgpeCpp; + + tmpKgpeCpp = (uint32_t)(p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry / 8); + tmpKgpeCpp |= (uint32_t)(((p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp / 8) - 1) << FM_PCD_KG_PE_CPP_MASK_SHIFT); + return tmpKgpeCpp; +} + +bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg) +{ + + if(schemeModeReg & KG_SCH_MODE_EN) + return TRUE; + else + return FALSE; +} + +uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter) +{ + return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT)| + FM_PCD_KG_KGAR_GO | + FM_PCD_KG_KGAR_WRITE | + FM_PCD_KG_KGAR_SEL_SCHEME_ENTRY | + DUMMY_PORT_ID | + (updateCounter ? FM_PCD_KG_KGAR_SCHEME_WSEL_UPDATE_CNT:0)); + +} + +uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId) +{ + return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT)| + FM_PCD_KG_KGAR_GO | + FM_PCD_KG_KGAR_READ | + FM_PCD_KG_KGAR_SEL_SCHEME_ENTRY | + DUMMY_PORT_ID | + FM_PCD_KG_KGAR_SCHEME_WSEL_UPDATE_CNT); + +} + + +uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId) +{ + return (uint32_t)(FM_PCD_KG_KGAR_GO | + FM_PCD_KG_KGAR_WRITE | + FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | + DUMMY_PORT_ID | + ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) | + FM_PCD_KG_KGAR_WSEL_MASK); + + + /* if we ever want to write 1 by 1, use: + sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));*/ +} + +uint32_t FmPcdKgBuildReadClsPlanBlockActionReg(uint8_t grpId) +{ + return (uint32_t)(FM_PCD_KG_KGAR_GO | + FM_PCD_KG_KGAR_READ | + FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | + DUMMY_PORT_ID | + ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) | + FM_PCD_KG_KGAR_WSEL_MASK); + + + /* if we ever want to write 1 by 1, use: + sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));*/ +} + +uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId) +{ + + return (uint32_t)(FM_PCD_KG_KGAR_GO | + FM_PCD_KG_KGAR_WRITE | + FM_PCD_KG_KGAR_SEL_PORT_ENTRY | + hardwarePortId | + FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); +} + +uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId) +{ + + return (uint32_t)(FM_PCD_KG_KGAR_GO | + FM_PCD_KG_KGAR_READ | + FM_PCD_KG_KGAR_SEL_PORT_ENTRY | + hardwarePortId | + FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); +} +uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId) +{ + + return (uint32_t)(FM_PCD_KG_KGAR_GO | + FM_PCD_KG_KGAR_WRITE | + FM_PCD_KG_KGAR_SEL_PORT_ENTRY | + hardwarePortId | + FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP); +} + +uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].baseEntry; +} + +uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].sizeOfGrp; +} + +uint8_t FmPcdKgGetSchemeSwId(t_Handle h_FmPcd, uint8_t schemeHwId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint8_t i; + + for(i=0;ip_FmPcdKg->numOfSchemes;i++) + if(p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeHwId) + return i; + ASSERT_COND(i!=p_FmPcd->p_FmPcdKg->numOfSchemes); + return FM_PCD_KG_NUM_OF_SCHEMES; +} + +uint8_t FmPcdKgGetNumOfPartitionSchemes(t_Handle h_FmPcd) +{ + return ((t_FmPcd*)h_FmPcd)->p_FmPcdKg->numOfSchemes; +} + +uint8_t FmPcdKgGetPhysicalSchemeId(t_Handle h_FmPcd, uint8_t relativeSchemeId) +{ + return ((t_FmPcd*)h_FmPcd)->p_FmPcdKg->schemesIds[relativeSchemeId]; +} + +uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint8_t i; + + for(i = 0;ip_FmPcdKg->numOfSchemes;i++) + if(p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeId) + return i; + + if(i == p_FmPcd->p_FmPcdKg->numOfSchemes) + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of partition range")); + + return FM_PCD_KG_NUM_OF_SCHEMES; +} + +t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint8_t relativeSchemeId, physicalSchemeId; + uint32_t tmpKgarReg, tmpReg32 = 0, intFlags; + t_Error err; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); + + if (p_FmPcd->h_Hc) + return FmHcPcdKgCcGetSetParams(p_FmPcd->h_Hc, h_Scheme, requiredAction); + + physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); + if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if (FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Lock of the scheme FAILED")); + + if(!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].pointedOwners || + !(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction & requiredAction)) + { + if(requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + { + switch(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine) + { + case(e_FM_PCD_DONE): + if(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction == e_FM_PCD_ENQ_FRAME) + { + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = FmPcdLock(p_FmPcd); + WriteKgarWait(p_FmPcd, tmpKgarReg); + if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); + } + tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode); + ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode, tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA); + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + WriteKgarWait(p_FmPcd, tmpKgarReg); + FmPcdUnlock(p_FmPcd, intFlags); + } + break; + case(e_FM_PCD_PLCR): + if(!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr || + (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs && + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile) || + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared")); + } + err = FmPcdPlcrCcGetSetParams(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId, requiredAction); + if(err) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("in this situation the next engine after scheme can be or PLCR or ENQ_FRAME")); + } + } + } + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].pointedOwners += 1; + p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction |= requiredAction; + + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + return E_OK; +} + +t_Error FmPcdKgSchemeTryLock(t_Handle h_FmPcd, uint8_t schemeId, bool intr) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + bool ans; + + if (intr) + ans = TRY_LOCK(NULL, &p_FmPcd->p_FmPcdKg->schemes[schemeId].lock); + else + ans = TRY_LOCK(p_FmPcd->h_Spinlock, &p_FmPcd->p_FmPcdKg->schemes[schemeId].lock); + if (ans) + return E_OK; + return ERROR_CODE(E_BUSY); +} + +void FmPcdKgReleaseSchemeLock(t_Handle h_FmPcd, uint8_t schemeId) +{ + RELEASE_LOCK(((t_FmPcd*)h_FmPcd)->p_FmPcdKg->schemes[schemeId].lock); +} + +t_Handle FM_PCD_KgSetScheme(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_Scheme) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpReg; + t_FmPcdKgInterModuleSchemeRegs schemeRegs; + t_FmPcdKgInterModuleSchemeRegs *p_MemRegs; + uint8_t i; + t_Error err = E_OK; + uint32_t tmpKgarReg; + uint32_t intFlags; + uint8_t physicalSchemeId, relativeSchemeId; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); + + if (p_FmPcd->h_Hc) + return FmHcPcdKgSetScheme(p_FmPcd->h_Hc, p_Scheme); + + /* if not called for modification, check first that this scheme is unused */ + if(!p_Scheme->modify) + { + /* check that schemeId is in range */ + if(p_Scheme->id.relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes) + { + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of range")); + return NULL; + } + relativeSchemeId = p_Scheme->id.relativeSchemeId; + + if (FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE)) + return NULL; + + physicalSchemeId = p_FmPcd->p_FmPcdKg->schemesIds[relativeSchemeId]; + + /* read specified scheme into scheme registers */ + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = FmPcdLock(p_FmPcd); + WriteKgarWait(p_FmPcd, tmpKgarReg); + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode); + FmPcdUnlock(p_FmPcd, intFlags); + + if (tmpReg & KG_SCH_MODE_EN) + { + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, + ("Scheme %d(phys %d) is already used", relativeSchemeId, physicalSchemeId)); + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + return NULL; + } + } + else + { + SANITY_CHECK_RETURN_VALUE(p_Scheme->id.h_Scheme, E_INVALID_HANDLE, NULL); + + intFlags = FmPcdLock(p_FmPcd); + physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_Scheme->id.h_Scheme)-1); + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); + + /* check that schemeId is in range */ + if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + { + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + FmPcdUnlock(p_FmPcd, intFlags); + return NULL; + } + + err = FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, TRUE); + FmPcdUnlock(p_FmPcd, intFlags); + if (err) + return NULL; + } + + err = FmPcdKgBuildScheme(h_FmPcd, p_Scheme, &schemeRegs); + if(err) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + FmPcdKgInvalidateSchemeSw(h_FmPcd, relativeSchemeId); + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + return NULL; + } + + /* configure all 21 scheme registers */ + p_MemRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs; + intFlags = FmPcdLock(p_FmPcd); + WRITE_UINT32(p_MemRegs->kgse_ppc, schemeRegs.kgse_ppc); + WRITE_UINT32(p_MemRegs->kgse_ccbs, schemeRegs.kgse_ccbs); + WRITE_UINT32(p_MemRegs->kgse_mode, schemeRegs.kgse_mode); + WRITE_UINT32(p_MemRegs->kgse_mv, schemeRegs.kgse_mv); + WRITE_UINT32(p_MemRegs->kgse_dv0, schemeRegs.kgse_dv0); + WRITE_UINT32(p_MemRegs->kgse_dv1, schemeRegs.kgse_dv1); + WRITE_UINT32(p_MemRegs->kgse_ekdv, schemeRegs.kgse_ekdv); + WRITE_UINT32(p_MemRegs->kgse_ekfc, schemeRegs.kgse_ekfc); + WRITE_UINT32(p_MemRegs->kgse_bmch, schemeRegs.kgse_bmch); + WRITE_UINT32(p_MemRegs->kgse_bmcl, schemeRegs.kgse_bmcl); + WRITE_UINT32(p_MemRegs->kgse_hc, schemeRegs.kgse_hc); + WRITE_UINT32(p_MemRegs->kgse_spc, schemeRegs.kgse_spc); + WRITE_UINT32(p_MemRegs->kgse_fqb, schemeRegs.kgse_fqb); + for(i=0 ; ikgse_gec[i], schemeRegs.kgse_gec[i]); + + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_Scheme->schemeCounter.update); + + WriteKgarWait(p_FmPcd, tmpKgarReg); + FmPcdUnlock(p_FmPcd, intFlags); + + FmPcdKgValidateSchemeSw(h_FmPcd, relativeSchemeId); + + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + + return UINT_TO_PTR((uint64_t)physicalSchemeId+1); +} + +t_Error FM_PCD_KgDeleteScheme(t_Handle h_FmPcd, t_Handle h_Scheme) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint8_t physicalSchemeId; + uint32_t tmpKgarReg, intFlags; + t_Error err = E_OK; + uint8_t relativeSchemeId; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if (p_FmPcd->h_Hc) + return FmHcPcdKgDeleteScheme(p_FmPcd->h_Hc, h_Scheme); + + physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); + + if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if ((err = FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* check that no port is bound to this scheme */ + err = FmPcdKgCheckInvalidateSchemeSw(h_FmPcd, relativeSchemeId); + if(err) + RETURN_ERROR(MINOR, err, NO_MSG); + + intFlags = FmPcdLock(p_FmPcd); + /* clear mode register, including enable bit */ + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode, 0); + + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + + WriteKgarWait(p_FmPcd, tmpKgarReg); + FmPcdUnlock(p_FmPcd, intFlags); + + FmPcdKgInvalidateSchemeSw(h_FmPcd, relativeSchemeId); + + RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); + + return E_OK; +} + +uint32_t FM_PCD_KgGetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpKgarReg, spc, intFlags; + uint8_t physicalSchemeId; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); + + if (p_FmPcd->h_Hc) + return FmHcPcdKgGetSchemeCounter(p_FmPcd->h_Hc, h_Scheme); + + physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + + if(FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES) + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = FmPcdLock(p_FmPcd); + WriteKgarWait(p_FmPcd, tmpKgarReg); + if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); + spc = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_spc); + FmPcdUnlock(p_FmPcd, intFlags); + + return spc; +} + +t_Error FM_PCD_KgSetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpKgarReg, intFlags; + uint8_t physicalSchemeId; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); + + if (p_FmPcd->h_Hc) + return FmHcPcdKgSetSchemeCounter(p_FmPcd->h_Hc, h_Scheme, value); + + physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); + /* check that schemeId is in range */ + if(FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES) + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + /* read specified scheme into scheme registers */ + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = FmPcdLock(p_FmPcd); + WriteKgarWait(p_FmPcd, tmpKgarReg); + if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); + } + + /* change counter value */ + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_spc, value); + + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); + + WriteKgarWait(p_FmPcd, tmpKgarReg); + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; +} + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_plcr.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_plcr.c @@ -0,0 +1,1702 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_plcr.c + + @Description FM PCD POLICER... +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "net_ext.h" +#include "fm_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_hc.h" +#include "fm_pcd_ipc.h" + + +static bool FmPcdPlcrIsProfileShared(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint16_t i; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, FALSE); + + for(i=0;ip_FmPcdPlcr->numOfSharedProfiles;i++) + if(p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] == absoluteProfileId) + return TRUE; + return FALSE; +} + +static t_Error SetProfileNia(t_FmPcd *p_FmPcd, e_FmPcdEngine nextEngine, u_FmPcdPlcrNextEngineParams *p_NextEngineParams, uint32_t *nextAction) +{ + uint32_t nia; + uint16_t absoluteProfileId = (uint16_t)(PTR_TO_UINT(p_NextEngineParams->h_Profile)-1); + uint8_t relativeSchemeId, physicatSchemeId; + + nia = FM_PCD_PLCR_NIA_VALID; + + switch (nextEngine) + { + case e_FM_PCD_DONE : + switch (p_NextEngineParams->action) + { + case e_FM_PCD_DROP_FRAME : + nia |= (NIA_ENG_BMI | NIA_BMI_AC_DISCARD); + break; + case e_FM_PCD_ENQ_FRAME: + nia |= (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + case e_FM_PCD_KG: + physicatSchemeId = (uint8_t)(PTR_TO_UINT(p_NextEngineParams->h_DirectScheme)-1); + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicatSchemeId); + if(relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + if (!FmPcdKgIsSchemeValidSw(p_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid direct scheme.")); + if(!KgIsSchemeAlwaysDirect(p_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Policer Profile may point only to a scheme that is always direct.")); + nia |= NIA_ENG_KG | NIA_KG_DIRECT | physicatSchemeId; + break; + case e_FM_PCD_PLCR: + if(!FmPcdPlcrIsProfileShared(p_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next profile must be a shared profile")); + if(!FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid profile ")); + nia |= NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + *nextAction = nia; + + return E_OK; +} + +static uint32_t FPP_Function(uint32_t fpp) +{ + if(fpp > 15) + return 15 - (0x1f - fpp); + else + return 16 + fpp; +} + +static void GetInfoRateReg(e_FmPcdPlcrRateMode rateMode, + uint32_t rate, + uint64_t tsuInTenthNano, + uint32_t fppShift, + uint64_t *p_Integer, + uint64_t *p_Fraction) +{ + uint64_t tmp, div; + + if(rateMode == e_FM_PCD_PLCR_BYTE_MODE) + { + /* now we calculate the initial integer for the bigger rate */ + /* from Kbps to Bytes/TSU */ + tmp = (uint64_t)rate; + tmp *= 1000; /* kb --> b */ + tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */ + + div = 1000000000; /* nano */ + div *= 10; /* 10 nano */ + div *= 8; /* bit to byte */ + } + else + { + /* now we calculate the initial integer for the bigger rate */ + /* from Kbps to Bytes/TSU */ + tmp = (uint64_t)rate; + tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */ + + div = 1000000000; /* nano */ + div *= 10; /* 10 nano */ + } + *p_Integer = (tmp<h_Fm); /* TimeStamp per nano seconds units */ + /* we want the tsu to count 10 nano for better precision normally tsu is 3.9 nano, now we will get 39 */ + tsuInTenthNanos = (uint32_t)(1000*10/(1<comittedInfoRate > p_NonPassthroughAlgParam->peakOrAccessiveInfoRate) + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->comittedInfoRate, tsuInTenthNanos, 0, &integer, &fraction); + else + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrAccessiveInfoRate, tsuInTenthNanos, 0, &integer, &fraction); + + + /* we shift integer, as in cir/pir it is represented by the MSB 16 bits, and + * the LSB bits are for the fraction */ + temp = (uint32_t)((integer<<16) & 0x00000000FFFFFFFF); + /* temp is effected by the rate. For low rates it may be as low as 0, and then we'll + * take max fpp=31. + * For high rates it will never exceed the 32 bit reg (after the 16 shift), as it is + * limited by the 10G physical port. + */ + if(temp != 0) + { + /* count zeroes left of the higher used bit (in order to shift the value such that + * unused bits may be used for fraction). + */ + while ((temp & 0x80000000) == 0) + { + temp = temp << 1; + fppShift++; + } + if(fppShift > 15) + { + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, ("timeStampPeriod to Information rate ratio is too small")); + return; + } + } + else + { + temp = (uint32_t)fraction; /* fraction will alyas be smaller than 2^16 */ + if(!temp) + /* integer and fraction are 0, we set fpp to its max val */ + fppShift = 31; + else + { + /* integer was 0 but fraction is not. fpp is 16 for the integer, + * + all left zeroes of the fraction. */ + fppShift=16; + /* count zeroes left of the higher used bit (in order to shift the value such that + * unused bits may be used for fraction). + */ + while ((temp & 0x8000) == 0) + { + temp = temp << 1; + fppShift++; + } + } + } + + /* + * This means that the FM TS register will now be used so that 'count' bits are for + * fraction and the rest for integer */ + /* now we re-calculate cir */ + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->comittedInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction); + *cir = (uint32_t)(integer << 16 | (fraction & 0xFFFF)); + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrAccessiveInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction); + *pir_eir = (uint32_t)(integer << 16 | (fraction & 0xFFFF)); + + *cbs = p_NonPassthroughAlgParam->comittedBurstSize; + *pbs_ebs = p_NonPassthroughAlgParam->peakOrAccessiveBurstSize; + + /* get fpp as it should be written to reg.*/ + *fpp = FPP_Function(fppShift); + +} + +static void WritePar(t_FmPcd *p_FmPcd, uint32_t par) +{ + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + WRITE_UINT32(p_FmPcdPlcrRegs->fmpl_par, par); + + while(GET_UINT32(p_FmPcdPlcrRegs->fmpl_par) & FM_PCD_PLCR_PAR_GO) ; + +} + +/*********************************************/ +/*............Policer Exception..............*/ +/*********************************************/ +static void PcdPlcrException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, mask, force; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr); + mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr); + if(force & event) + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, force & ~event); + + + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr, event); + + if(event & FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE); + if(event & FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE); + +} + +/* ..... */ + +static void PcdPlcrErrorException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, force, captureReg, mask; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr); + mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr); + if(force & event) + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, force & ~event); + + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr, event); + + if(event & FM_PCD_PLCR_DOUBLE_ECC) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC); + if(event & FM_PCD_PLCR_INIT_ENTRY_ERROR) + { + captureReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr); + /*ASSERT_COND(captureReg & PLCR_ERR_UNINIT_CAP); + p_UnInitCapt->profileNum = (uint8_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK); + p_UnInitCapt->portId = (uint8_t)((captureReg & PLCR_ERR_UNINIT_PID_MASK) >>PLCR_ERR_UNINIT_PID_SHIFT) ; + p_UnInitCapt->absolute = (bool)(captureReg & PLCR_ERR_UNINIT_ABSOLUTE_MASK);*/ + p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,(uint16_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK)); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr, PLCR_ERR_UNINIT_CAP); + } +} + +void FmPcdPlcrUpatePointedOwner(t_Handle h_FmPcd, uint16_t absoluteProfileId, bool add) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + if(add) + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].pointedOwners++; + else + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].pointedOwners--; +} + +uint32_t FmPcdPlcrGetPointedOwners(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].pointedOwners; +} +uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction; +} + +t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdIpcPlcrAllocParams ipcPlcrParams; + t_Error err = E_OK; + uint16_t base; + uint16_t swPortIndex = 0; + t_FmPcdIpcMsg msg; + uint32_t replyLength; + t_FmPcdIpcReply reply; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + if(!numOfProfiles) + return E_OK; + + memset(&ipcPlcrParams, 0, sizeof(ipcPlcrParams)); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + /* Alloc resources using IPC messaging */ + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + ipcPlcrParams.num = numOfProfiles; + ipcPlcrParams.hardwarePortId = hardwarePortId; + msg.msgId = FM_PCD_ALLOC_PROFILES; + memcpy(msg.msgBody, &ipcPlcrParams, sizeof(ipcPlcrParams)); + replyLength = sizeof(uint32_t) + sizeof(uint16_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(ipcPlcrParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err,NO_MSG); + if (replyLength != sizeof(uint32_t) + sizeof(uint16_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + if((t_Error)reply.error != E_OK) + RETURN_ERROR(MAJOR, (t_Error)reply.error, ("PLCR profiles allocation failed")); + + memcpy((uint8_t*)&base, reply.replyBody, sizeof(uint16_t)); + } + else /* master */ + { + err = PlcrAllocProfiles(p_FmPcd, hardwarePortId, numOfProfiles, &base); + if(err) + RETURN_ERROR(MAJOR, err,NO_MSG); + } + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = numOfProfiles; + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = base; + + return E_OK; +} + +t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdIpcPlcrAllocParams ipcPlcrParams; + t_Error err = E_OK; + uint16_t swPortIndex = 0; + t_FmPcdIpcMsg msg; + uint32_t replyLength; + t_FmPcdIpcReply reply; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + /* Alloc resources using IPC messaging */ + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + ipcPlcrParams.num = p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles; + ipcPlcrParams.hardwarePortId = hardwarePortId; + ipcPlcrParams.plcrProfilesBase = p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase; + msg.msgId = FM_PCD_FREE_PROFILES; + memcpy(msg.msgBody, &ipcPlcrParams, sizeof(ipcPlcrParams)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(ipcPlcrParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err,NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + if ((t_Error)reply.error != E_OK) + RETURN_ERROR(MINOR, (t_Error)reply.error, ("PLCR Free Profiles failed")); + } + else /* master */ + { + err = PlcrFreeProfiles(p_FmPcd, hardwarePortId, p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles, p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase); + if(err) + RETURN_ERROR(MAJOR, err,NO_MSG); + } + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = 0; + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = 0; + + return E_OK; +} + +bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + + return p_FmPcdPlcr->profiles[absoluteProfileId].valid; +} + +t_Error PlcrAllocProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles, uint16_t *p_Base) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + uint32_t profilesFound, log2Num, tmpReg32; + uint32_t intFlags; + uint16_t first, i; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + if(!numOfProfiles) + return E_OK; + + ASSERT_COND(hardwarePortId); + + if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big.")); + + if (!POWER_OF_2(numOfProfiles)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2.")); + + intFlags = FmPcdLock(p_FmPcd); + + if(GET_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1]) & FM_PCD_PLCR_PMR_V) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("The requesting port has already an allocated profiles window.")); + } + + first = 0; + profilesFound = 0; + for(i=0;ip_FmPcdPlcr->profiles[i].profilesMng.allocated) + { + profilesFound++; + i++; + if(profilesFound == numOfProfiles) + break; + } + else + { + profilesFound = 0; + /* advance i to the next aligned address */ + first = i = (uint8_t)(first + numOfProfiles); + } + } + if(profilesFound == numOfProfiles) + { + for(i = first; ip_FmPcdPlcr->profiles[i].profilesMng.allocated = TRUE; + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = hardwarePortId; + } + } + else + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MINOR, E_FULL, ("No profiles.")); + } + + /**********************FMPL_PMRx******************/ + LOG2((uint64_t)numOfProfiles, log2Num); + tmpReg32 = first; + tmpReg32 |= log2Num << 16; + tmpReg32 |= FM_PCD_PLCR_PMR_V; + WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], tmpReg32); + + *p_Base = first; + + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; +} + +t_Error PlcrAllocSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds) +{ + uint32_t profilesFound; + uint16_t i, k=0; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + if(!numOfProfiles) + return E_OK; + + if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big.")); + + profilesFound = 0; + for(i=0;ip_FmPcdPlcr->profiles[i].profilesMng.allocated) + { + profilesFound++; + profilesIds[k] = i; + k++; + if(profilesFound == numOfProfiles) + break; + } + } + if(profilesFound != numOfProfiles) + RETURN_ERROR(MAJOR, E_INVALID_STATE,NO_MSG); + for(i = 0;ip_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = TRUE; + p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = 0; + } + + return E_OK; +} + +t_Error PlcrFreeProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles, uint16_t base) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + uint16_t i; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], 0); + + for(i = base; ip_FmPcdPlcr->profiles[i].profilesMng.ownerId == hardwarePortId); + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated); + + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = FALSE; + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = 0; + } + + return E_OK; +} + +void PlcrFreeSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds) +{ + uint16_t i; + + SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + for(i=0;ip_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated); + p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = FALSE; + } +} + +void PlcrEnable(t_FmPcd *p_FmPcd) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + + WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) | FM_PCD_PLCR_GCR_EN); +} + +void PlcrDisable(t_FmPcd *p_FmPcd) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + + WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) & ~FM_PCD_PLCR_GCR_EN); +} + +t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + + if(!FmIsMaster(p_FmPcd->h_Fm)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPlcrStatistics - guest mode!")); + + tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr); + if(enable) + tmpReg32 |= FM_PCD_PLCR_GCR_STEN; + else + tmpReg32 &= ~FM_PCD_PLCR_GCR_STEN; + + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr, tmpReg32); + return E_OK; +} + +t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + + if(!FmIsMaster(p_FmPcd->h_Fm)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPlcrAutoRefreshMode - guest mode!")); + + p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = enable; + + return E_OK; +} + + +t_Error FmPcdPlcrBuildProfile(t_Handle h_FmPcd, t_FmPcdPlcrProfileParams *p_Profile, t_FmPcdPlcrInterModuleProfileRegs *p_PlcrRegs) +{ + + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + uint32_t pemode, gnia, ynia, rnia; + +/* Set G, Y, R Nia */ + err = SetProfileNia(p_FmPcd, p_Profile->nextEngineOnGreen, &(p_Profile->paramsOnGreen), &gnia); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + err = SetProfileNia(p_FmPcd, p_Profile->nextEngineOnYellow, &(p_Profile->paramsOnYellow), &ynia); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + err = SetProfileNia(p_FmPcd, p_Profile->nextEngineOnRed, &(p_Profile->paramsOnRed), &rnia); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + +/* Mode fmpl_pemode */ + pemode = FM_PCD_PLCR_PEMODE_PI; + + switch (p_Profile->algSelection) + { + case e_FM_PCD_PLCR_PASS_THROUGH: + p_PlcrRegs->fmpl_pecir = 0; + p_PlcrRegs->fmpl_pecbs = 0; + p_PlcrRegs->fmpl_pepepir_eir = 0; + p_PlcrRegs->fmpl_pepbs_ebs = 0; + p_PlcrRegs->fmpl_pelts = 0; + p_PlcrRegs->fmpl_pects = 0; + p_PlcrRegs->fmpl_pepts_ets = 0; + pemode &= ~FM_PCD_PLCR_PEMODE_ALG_MASK; + switch (p_Profile->colorMode) + { + case e_FM_PCD_PLCR_COLOR_BLIND: + pemode |= FM_PCD_PLCR_PEMODE_CBLND; + switch (p_Profile->color.dfltColor) + { + case e_FM_PCD_PLCR_GREEN: + pemode &= ~FM_PCD_PLCR_PEMODE_DEFC_MASK; + break; + case e_FM_PCD_PLCR_YELLOW: + pemode |= FM_PCD_PLCR_PEMODE_DEFC_Y; + break; + case e_FM_PCD_PLCR_RED: + pemode |= FM_PCD_PLCR_PEMODE_DEFC_R; + break; + case e_FM_PCD_PLCR_OVERRIDE: + pemode |= FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + break; + case e_FM_PCD_PLCR_COLOR_AWARE: + pemode &= ~FM_PCD_PLCR_PEMODE_CBLND; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + + case e_FM_PCD_PLCR_RFC_2698: + /* Select algorithm MODE[ALG] = "01" */ + pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC2698; + if (p_Profile->nonPassthroughAlgParams.comittedInfoRate > p_Profile->nonPassthroughAlgParams.peakOrAccessiveInfoRate) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("in RFC2698 Peak rate must be equal or larger than comittedInfoRate.")); + goto cont_rfc; + case e_FM_PCD_PLCR_RFC_4115: + /* Select algorithm MODE[ALG] = "10" */ + pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC4115; +cont_rfc: + /* Select Color-Blind / Color-Aware operation (MODE[CBLND]) */ + switch (p_Profile->colorMode) + { + case e_FM_PCD_PLCR_COLOR_BLIND: + pemode |= FM_PCD_PLCR_PEMODE_CBLND; + break; + case e_FM_PCD_PLCR_COLOR_AWARE: + pemode &= ~FM_PCD_PLCR_PEMODE_CBLND; + /*In color aware more select override color interpretation (MODE[OVCLR]) */ + switch (p_Profile->color.override) + { + case e_FM_PCD_PLCR_GREEN: + pemode &= ~FM_PCD_PLCR_PEMODE_OVCLR_MASK; + break; + case e_FM_PCD_PLCR_YELLOW: + pemode |= FM_PCD_PLCR_PEMODE_OVCLR_Y; + break; + case e_FM_PCD_PLCR_RED: + pemode |= FM_PCD_PLCR_PEMODE_OVCLR_R; + break; + case e_FM_PCD_PLCR_OVERRIDE: + pemode |= FM_PCD_PLCR_PEMODE_OVCLR_G_NC; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + /* Select Measurement Unit Mode to BYTE or PACKET (MODE[PKT]) */ + switch (p_Profile->nonPassthroughAlgParams.rateMode) + { + case e_FM_PCD_PLCR_BYTE_MODE : + pemode &= ~FM_PCD_PLCR_PEMODE_PKT; + switch (p_Profile->nonPassthroughAlgParams.byteModeParams.frameLengthSelection) + { + case e_FM_PCD_PLCR_L2_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_L2; + break; + case e_FM_PCD_PLCR_L3_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_L3; + break; + case e_FM_PCD_PLCR_L4_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_L4; + break; + case e_FM_PCD_PLCR_FULL_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_FULL; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + switch (p_Profile->nonPassthroughAlgParams.byteModeParams.rollBackFrameSelection) + { + case e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN: + pemode &= ~FM_PCD_PLCR_PEMODE_RBFLS; + break; + case e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_RBFLS; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + case e_FM_PCD_PLCR_PACKET_MODE : + pemode |= FM_PCD_PLCR_PEMODE_PKT; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + /* Select timeStamp floating point position (MODE[FPP]) to fit the actual traffic rates. For PACKET + mode with low traffic rates move the fixed point to the left to increase fraction accuracy. For BYTE + mode with high traffic rates move the fixed point to the right to increase integer accuracy. */ + + /* Configure Traffic Parameters*/ + { + uint32_t cir=0, cbs=0, pir_eir=0, pbs_ebs=0, fpp=0; + + calcRates(h_FmPcd, &p_Profile->nonPassthroughAlgParams, &cir, &cbs, &pir_eir, &pbs_ebs, &fpp); + + /* Set Committed Information Rate (CIR) */ + p_PlcrRegs->fmpl_pecir = cir; + /* Set Committed Burst Size (CBS). */ + p_PlcrRegs->fmpl_pecbs = cbs; + /* Set Peak Information Rate (PIR_EIR used as PIR) */ + p_PlcrRegs->fmpl_pepepir_eir = pir_eir; + /* Set Peak Burst Size (PBS_EBS used as PBS) */ + p_PlcrRegs->fmpl_pepbs_ebs = pbs_ebs; + + /* Initialize the Metering Buckets to be full (write them with 0xFFFFFFFF. */ + /* Peak Rate Token Bucket Size (PTS_ETS used as PTS) */ + p_PlcrRegs->fmpl_pepts_ets = 0xFFFFFFFF; + /* Committed Rate Token Bucket Size (CTS) */ + p_PlcrRegs->fmpl_pects = 0xFFFFFFFF; + + /* Set the FPP based on calculation */ + pemode |= (fpp << FM_PCD_PLCR_PEMODE_FPP_SHIFT); + } + break; /* FM_PCD_PLCR_PEMODE_ALG_RFC2698 , FM_PCD_PLCR_PEMODE_ALG_RFC4115 */ + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + p_PlcrRegs->fmpl_pemode = pemode; + + p_PlcrRegs->fmpl_pegnia = gnia; + p_PlcrRegs->fmpl_peynia = ynia; + p_PlcrRegs->fmpl_pernia = rnia; + + /* Zero Counters */ + p_PlcrRegs->fmpl_pegpc = 0; + p_PlcrRegs->fmpl_peypc = 0; + p_PlcrRegs->fmpl_perpc = 0; + p_PlcrRegs->fmpl_perypc = 0; + p_PlcrRegs->fmpl_perrpc = 0; + + return E_OK; +} + +void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(!p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = TRUE; +} + +void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = FALSE; +} + +t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams) +{ + t_FmPcdPlcr *p_FmPcdPlcr; + /*uint8_t i=0;*/ + + UNUSED(p_FmPcd); + UNUSED(p_FmPcdParams); + + p_FmPcdPlcr = (t_FmPcdPlcr *) XX_Malloc(sizeof(t_FmPcdPlcr)); + if (!p_FmPcdPlcr) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer structure allocation FAILED")); + return NULL; + } + memset(p_FmPcdPlcr, 0, sizeof(t_FmPcdPlcr)); + if(p_FmPcd->guestId == NCSW_MASTER_ID) + { + p_FmPcdPlcr->p_FmPcdPlcrRegs = (t_FmPcdPlcrRegs *)UINT_TO_PTR(FmGetPcdPlcrBaseAddr(p_FmPcdParams->h_Fm)); + p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = DEFAULT_plcrAutoRefresh; + p_FmPcd->exceptions |= (DEFAULT_fmPcdPlcrExceptions | DEFAULT_fmPcdPlcrErrorExceptions); + } + + p_FmPcdPlcr->numOfSharedProfiles = DEFAULT_numOfSharedPlcrProfiles; + + return p_FmPcdPlcr; +} + +t_Error PlcrInit(t_FmPcd *p_FmPcd) +{ + t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + uint32_t tmpReg32 = 0; + t_Error err = E_OK; + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + t_FmPcdIpcMsg msg; + uint32_t replyLength; + t_FmPcdIpcReply reply; + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + (p_FmPcdPlcr->numOfSharedProfiles)) + { + int i, j, index = 0; + uint32_t walking1Mask = 0x80000000; + uint32_t sharedProfilesMask[FM_PCD_PLCR_NUM_ENTRIES/32]; + + memset(sharedProfilesMask, 0, FM_PCD_PLCR_NUM_ENTRIES/32 * sizeof(uint32_t)); + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_ALLOC_SHARED_PROFILES; + memcpy(msg.msgBody, (uint8_t *)&p_FmPcdPlcr->numOfSharedProfiles, sizeof(uint16_t)); + replyLength = sizeof(uint32_t) + sizeof(sharedProfilesMask); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId)+ sizeof(p_FmPcdPlcr->numOfSharedProfiles), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err,NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(sharedProfilesMask))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + memcpy(sharedProfilesMask, reply.replyBody, sizeof(sharedProfilesMask)); + /* translate 8 regs of 32 bits masks into an array of up to 256 indexes. */ + for(i = 0; ip_FmPcdPlcr->sharedProfilesIds[index++] = (uint16_t)(i*32+j); + walking1Mask >>= 1; + } + walking1Mask = 0x80000000; + } + } + return (t_Error)reply.error; + } + + if(p_FmPcdPlcr->numOfSharedProfiles) + { + err = PlcrAllocSharedProfiles(p_FmPcd, p_FmPcdPlcr->numOfSharedProfiles, p_FmPcd->p_FmPcdPlcr->sharedProfilesIds); + if(err) + RETURN_ERROR(MAJOR, err,NO_MSG); + } + + /**********************FMPL_GCR******************/ + tmpReg32 = 0; + tmpReg32 |= FM_PCD_PLCR_GCR_STEN; + if(p_Param->plcrAutoRefresh) + tmpReg32 |= FM_PCD_PLCR_GCR_DAR; + tmpReg32 |= NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME; + + WRITE_UINT32(p_Regs->fmpl_gcr, tmpReg32); + /**********************FMPL_GCR******************/ + + /**********************FMPL_EEVR******************/ + WRITE_UINT32(p_Regs->fmpl_eevr, (FM_PCD_PLCR_DOUBLE_ECC | FM_PCD_PLCR_INIT_ENTRY_ERROR)); + /**********************FMPL_EEVR******************/ + /**********************FMPL_EIER******************/ + tmpReg32 = 0; + if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC) + { + FmEnableRamsEcc(p_FmPcd->h_Fm); + tmpReg32 |= FM_PCD_PLCR_DOUBLE_ECC; + } + if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR) + tmpReg32 |= FM_PCD_PLCR_INIT_ENTRY_ERROR; + WRITE_UINT32(p_Regs->fmpl_eier, tmpReg32); + /**********************FMPL_EIER******************/ + + /**********************FMPL_EVR******************/ + WRITE_UINT32(p_Regs->fmpl_evr, (FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE | FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE)); + /**********************FMPL_EVR******************/ + /**********************FMPL_IER******************/ + tmpReg32 = 0; + if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE) + tmpReg32 |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; + if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE ) + tmpReg32 |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; + WRITE_UINT32(p_Regs->fmpl_ier, tmpReg32); + /**********************FMPL_IER******************/ + + /* register even if no interrupts enabled, to allow future enablement */ + FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR, PcdPlcrErrorException, p_FmPcd); + FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL, PcdPlcrException, p_FmPcd); + + /* driver initializes one DFLT profile at the last entry*/ + /**********************FMPL_DPMR******************/ + tmpReg32 = 0; + WRITE_UINT32(p_Regs->fmpl_dpmr, tmpReg32); + p_FmPcd->p_FmPcdPlcr->profiles[0].profilesMng.allocated = TRUE; + + return E_OK; +} + +t_Error PlcrFree(t_FmPcd *p_FmPcd) +{ + t_Error err; + t_FmPcdIpcSharedPlcrAllocParams ipcSharedPlcrParams; + t_FmPcdIpcMsg msg; + + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR); + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL); + + if(p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles) + { + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + int i; + memset(ipcSharedPlcrParams.sharedProfilesMask, 0, sizeof(ipcSharedPlcrParams.sharedProfilesMask)); + /* Free resources using IPC messaging */ + ipcSharedPlcrParams.num = p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles; + + /* translate the allocated profile id's to a 32bit * 8regs mask */ + for(i = 0;ip_FmPcdPlcr->numOfSharedProfiles;i++) + ipcSharedPlcrParams.sharedProfilesMask[p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i]/32] |= (0x80000000 >> (p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] % 32)); + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_FREE_SHARED_PROFILES; + memcpy(msg.msgBody, &ipcSharedPlcrParams, sizeof(ipcSharedPlcrParams)); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(ipcSharedPlcrParams), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err,NO_MSG); + } + /* else + PlcrFreeSharedProfiles(p_FmPcd, p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles, p_FmPcd->p_FmPcdPlcr->sharedProfilesIds);*/ + } + return E_OK; +} + +t_Error FmPcdPlcrGetAbsoluteProfileId(t_Handle h_FmPcd, + e_FmPcdProfileTypeSelection profileType, + t_Handle h_FmPort, + uint16_t relativeProfile, + uint16_t *p_AbsoluteId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + uint8_t i; + + switch (profileType) + { + case e_FM_PCD_PLCR_PORT_PRIVATE: + /* get port PCD id from port handle */ + for(i=0;ip_FmPcdPlcr->portsMapping[i].h_FmPort == h_FmPort) + break; + if (i == FM_MAX_NUM_OF_PORTS) + RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Invalid port handle.")); + + if(!p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Port has no allocated profiles")); + if(relativeProfile >= p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range")); + *p_AbsoluteId = (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[i].profilesBase + relativeProfile); + break; + case e_FM_PCD_PLCR_SHARED: + if(relativeProfile >= p_FmPcdPlcr->numOfSharedProfiles) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range")); + *p_AbsoluteId = (uint16_t)(p_FmPcdPlcr->sharedProfilesIds[relativeProfile]); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Invalid policer profile type")); + } + return E_OK; +} + +uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint16_t swPortIndex = 0; + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase; +} + +uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint16_t swPortIndex = 0; + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles; + +} +uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId) +{ + return (uint32_t)(FM_PCD_PLCR_PAR_GO | + ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT)); +} + +uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId) +{ + return (uint32_t)(FM_PCD_PLCR_PAR_GO | + ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) | + FM_PCD_PLCR_PAR_PWSEL_MASK); +} + +bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg) +{ + + if(profileModeReg & FM_PCD_PLCR_PEMODE_PI) + return TRUE; + else + return FALSE; +} + +uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId) +{ + return (uint32_t)(FM_PCD_PLCR_PAR_GO | + FM_PCD_PLCR_PAR_R | + ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) | + FM_PCD_PLCR_PAR_PWSEL_MASK); +} + +uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter) +{ + switch(counter) + { + case(e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER): + return FM_PCD_PLCR_PAR_PWSEL_PEGPC; + case(e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER): + return FM_PCD_PLCR_PAR_PWSEL_PEYPC; + case(e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER) : + return FM_PCD_PLCR_PAR_PWSEL_PERPC; + case(e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER) : + return FM_PCD_PLCR_PAR_PWSEL_PERYPC; + case(e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER) : + return FM_PCD_PLCR_PAR_PWSEL_PERRPC; + default: + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + return 0; + } +} + +uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red) +{ + + uint32_t tmpReg32 = 0; + + if(green) + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA; + if(yellow) + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA; + if(red) + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA; + + return tmpReg32; +} + +void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction = requiredAction; +} + +t_Error FmPcdPlcrProfileTryLock(t_Handle h_FmPcd, uint16_t profileId, bool intr) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + bool ans; + if (intr) + ans = TRY_LOCK(NULL, &p_FmPcd->p_FmPcdPlcr->profiles[profileId].lock); + else + ans = TRY_LOCK(p_FmPcd->h_Spinlock, &p_FmPcd->p_FmPcdPlcr->profiles[profileId].lock); + if (ans) + return E_OK; + return ERROR_CODE(E_BUSY); +} + +void FmPcdPlcrReleaseProfileLock(t_Handle h_FmPcd, uint16_t profileId) +{ + RELEASE_LOCK(((t_FmPcd*)h_FmPcd)->p_FmPcdPlcr->profiles[profileId].lock); +} + +/**************************************************/ +/*............Policer API.........................*/ +/**************************************************/ + +t_Handle FM_PCD_PlcrSetProfile(t_Handle h_FmPcd, + t_FmPcdPlcrProfileParams *p_Profile) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + t_FmPcdPlcrInterModuleProfileRegs plcrProfileReg; + uint32_t intFlags; + uint16_t absoluteProfileId; + t_Error err = E_OK; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL); + + if (p_FmPcd->h_Hc) + return FmHcPcdPlcrSetProfile(p_FmPcd->h_Hc, p_Profile); + + p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, NULL); + + if (p_Profile->modify) + { + absoluteProfileId = (uint16_t)(PTR_TO_UINT(p_Profile->id.h_Profile)-1); + if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); + return NULL; + } + if (FmPcdPlcrProfileTryLock(p_FmPcd, absoluteProfileId, FALSE)) + return NULL; + } + else + { + intFlags = FmPcdLock(p_FmPcd); + err = FmPcdPlcrGetAbsoluteProfileId(h_FmPcd, + p_Profile->id.newParams.profileType, + p_Profile->id.newParams.h_FmPort, + p_Profile->id.newParams.relativeProfileId, + &absoluteProfileId); + if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); + return NULL; + } + if(err) + { + FmPcdUnlock(p_FmPcd, intFlags); + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + err = FmPcdPlcrProfileTryLock(p_FmPcd, absoluteProfileId, TRUE); + FmPcdUnlock(p_FmPcd, intFlags); + if (err) + return NULL; + } + + /* if no override, check first that this profile is unused */ + if(!p_Profile->modify) + { + /* read specified profile into profile registers */ + tmpReg32 = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); + intFlags = FmPcdLock(p_FmPcd); + WritePar(p_FmPcd, tmpReg32); + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode); + FmPcdUnlock(p_FmPcd, intFlags); + if (tmpReg32 & FM_PCD_PLCR_PEMODE_PI) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].lock); + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer Profile is already used")); + return NULL; + } + } + + memset(&plcrProfileReg, 0, sizeof(t_FmPcdPlcrInterModuleProfileRegs)); + + err = FmPcdPlcrBuildProfile(h_FmPcd, p_Profile, &plcrProfileReg); + if(err) + { + RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].lock); + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].nextEngineOnGreen = p_Profile->nextEngineOnGreen; + memcpy(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].paramsOnGreen, &(p_Profile->paramsOnGreen), sizeof(u_FmPcdPlcrNextEngineParams)); + + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].nextEngineOnYellow = p_Profile->nextEngineOnYellow; + memcpy(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].paramsOnYellow, &(p_Profile->paramsOnYellow), sizeof(u_FmPcdPlcrNextEngineParams)); + + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].nextEngineOnRed = p_Profile->nextEngineOnRed; + memcpy(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].paramsOnRed, &(p_Profile->paramsOnRed), sizeof(u_FmPcdPlcrNextEngineParams)); + + intFlags = FmPcdLock(p_FmPcd); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode , plcrProfileReg.fmpl_pemode); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia , plcrProfileReg.fmpl_pegnia); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia , plcrProfileReg.fmpl_peynia); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia , plcrProfileReg.fmpl_pernia); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecir , plcrProfileReg.fmpl_pecir); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecbs , plcrProfileReg.fmpl_pecbs); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepepir_eir,plcrProfileReg.fmpl_pepepir_eir); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepbs_ebs,plcrProfileReg.fmpl_pepbs_ebs); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pelts , plcrProfileReg.fmpl_pelts); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pects , plcrProfileReg.fmpl_pects); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepts_ets,plcrProfileReg.fmpl_pepts_ets); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc , plcrProfileReg.fmpl_pegpc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc , plcrProfileReg.fmpl_peypc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc , plcrProfileReg.fmpl_perpc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc , plcrProfileReg.fmpl_perypc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc , plcrProfileReg.fmpl_perrpc); + + tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(absoluteProfileId); + WritePar(p_FmPcd, tmpReg32); + + FmPcdUnlock(p_FmPcd, intFlags); + + if (!p_Profile->modify) + FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId); + + RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].lock); + + return UINT_TO_PTR((uint64_t)absoluteProfileId+1); +} + +t_Error FM_PCD_PlcrDeleteProfile(t_Handle h_FmPcd, t_Handle h_Profile) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint16_t profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + uint32_t tmpReg32, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((profileIndx < FM_PCD_PLCR_NUM_ENTRIES), E_INVALID_SELECTION); + + if (p_FmPcd->h_Hc) + return FmHcPcdPlcrDeleteProfile(p_FmPcd->h_Hc, h_Profile); + + FmPcdPlcrInvalidateProfileSw(p_FmPcd,profileIndx); + + intFlags = FmPcdLock(p_FmPcd); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs.fmpl_pemode, ~FM_PCD_PLCR_PEMODE_PI); + + tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx); + WritePar(p_FmPcd, tmpReg32); + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; +} + +/* ......... */ +/***************************************************/ +/*............Policer Profile Counter..............*/ +/***************************************************/ +uint32_t FM_PCD_PlcrGetProfileCounter(t_Handle h_FmPcd, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint16_t profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + uint32_t intFlags, counterVal = 0; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, 0); + + if (p_FmPcd->h_Hc) + return FmHcPcdPlcrGetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter); + + p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, 0); + + if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); + return 0; + } + intFlags = FmPcdLock(p_FmPcd); + WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx)); + + if(!FmPcdPlcrHwProfileIsValid(GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode))) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized profile")); + FmPcdUnlock(p_FmPcd, intFlags); + return 0; + } + + switch (counter) + { + case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: + counterVal = (GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc)); + break; + case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc); + break; + case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc); + break; + default: + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + break; + } + FmPcdUnlock(p_FmPcd, intFlags); + + return counterVal; +} + + +t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx ,uint32_t requiredAction) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcdPlcr->p_FmPcdPlcrRegs; + uint32_t tmpReg32, intFlags; + + if (p_FmPcd->h_Hc) + return FmHcPcdPlcrCcGetSetParams(p_FmPcd->h_Hc, profileIndx, requiredAction); + + if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile out of range")); + + if (FmPcdPlcrProfileTryLock(p_FmPcd, profileIndx, FALSE)) + RETURN_ERROR(MAJOR, E_INVALID_STATE,("Lock on PP FAILED")); + + intFlags = FmPcdLock(p_FmPcd); + WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx)); + + if(!FmPcdPlcrHwProfileIsValid(GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode))) + { + FmPcdUnlock(p_FmPcd, intFlags); + RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].lock); + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile is not valid")); + } + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].valid); + + if(!p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].pointedOwners || + !(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction & requiredAction)) + { + if(requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + { + if((p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnGreen!= e_FM_PCD_DONE) || + (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnYellow!= e_FM_PCD_DONE) || + (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnRed!= e_FM_PCD_DONE)) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR (MAJOR, E_OK, ("In this case the next engine can be e_FM_PCD_DONE")); + } + + if(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnGreen.action == e_FM_PCD_ENQ_FRAME) + { + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia); + if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia, tmpReg32); + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA; + WritePar(p_FmPcd, tmpReg32); + } + + if(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnYellow.action == e_FM_PCD_ENQ_FRAME) + { + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia); + if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia, tmpReg32); + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA; + WritePar(p_FmPcd, tmpReg32); + } + + if(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnRed.action == e_FM_PCD_ENQ_FRAME) + { + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia); + if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + FmPcdUnlock(p_FmPcd, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia, tmpReg32); + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA; + WritePar(p_FmPcd, tmpReg32); + } + } + } + FmPcdUnlock(p_FmPcd, intFlags); + + p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].pointedOwners += 1; + p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction |= requiredAction; + + RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].lock); + + return E_OK; +} + +t_Error FM_PCD_PlcrSetProfileCounter(t_Handle h_FmPcd, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint16_t profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + uint32_t tmpReg32, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + + if (p_FmPcd->h_Hc) + return FmHcPcdPlcrSetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter, value); + + p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + SANITY_CHECK_RETURN_ERROR(p_FmPcdPlcrRegs, E_INVALID_HANDLE); + + intFlags = FmPcdLock(p_FmPcd); + switch (counter) + { + case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc, value); + break; + case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc, value); + break; + case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc, value); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc ,value); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc ,value); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + /* Activate the atomic write action by writing FMPL_PAR with: GO=1, RW=1, PSI=0, PNUM = + * Profile Number, PWSEL=0xFFFF (select all words). + */ + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FmPcdPlcrBuildCounterProfileReg(counter); + WritePar(p_FmPcd, tmpReg32); + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; +} + +t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + + p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles = numOfSharedPlcrProfiles; + + return E_OK; +} + + +/* ... */ + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FM_PCD_PlcrDumpRegs(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + int i = 0; + t_FmPcdIpcMsg msg; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_PLCR_DUMP_REGS; + return XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL); + } + else + { + DUMP_SUBTITLE(("\n")); + DUMP_TITLE(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, ("FmPcdPlcrRegs Regs")); + + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_gcr); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_gsr); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_evr); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_ier); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_ifr); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_eevr); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_eier); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_eifr); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_rpcnt); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_ypcnt); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_rrpcnt); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_rypcnt); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_tpcnt); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_flmcnt); + + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_serc); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_upcr); + DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_dpmr); + + + DUMP_TITLE(&p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr, ("fmpl_pmr")); + DUMP_SUBSTRUCT_ARRAY(i, 63) + { + DUMP_MEMORY(&p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr[i], sizeof(uint32_t)); + } + + return E_OK; + } +} + +t_Error FM_PCD_PlcrProfileDumpRegs(t_Handle h_FmPcd, t_Handle h_Profile) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdPlcrInterModuleProfileRegs *p_ProfilesRegs; + uint32_t tmpReg, intFlags; + uint16_t profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1); + t_FmPcdIpcMsg msg; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_PLCR_PROFILE_DUMP_REGS; + memcpy(msg.msgBody, (uint8_t *)&h_Profile, sizeof(uint32_t)); + return XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(uint32_t), + NULL, + NULL, + NULL, + NULL); + } + else + { + DUMP_SUBTITLE(("\n")); + DUMP_TITLE(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, ("FmPcdPlcrRegs Profile Regs")); + + p_ProfilesRegs = &p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs; + + tmpReg = FmPcdPlcrBuildReadPlcrActionReg((uint16_t)profileIndx); + intFlags = FmPcdLock(p_FmPcd); + WritePar(p_FmPcd, tmpReg); + + DUMP_TITLE(p_ProfilesRegs, ("Profile %d regs", profileIndx)); + + DUMP_VAR(p_ProfilesRegs, fmpl_pemode); + DUMP_VAR(p_ProfilesRegs, fmpl_pegnia); + DUMP_VAR(p_ProfilesRegs, fmpl_peynia); + DUMP_VAR(p_ProfilesRegs, fmpl_pernia); + DUMP_VAR(p_ProfilesRegs, fmpl_pecir); + DUMP_VAR(p_ProfilesRegs, fmpl_pecbs); + DUMP_VAR(p_ProfilesRegs, fmpl_pepepir_eir); + DUMP_VAR(p_ProfilesRegs, fmpl_pepbs_ebs); + DUMP_VAR(p_ProfilesRegs, fmpl_pelts); + DUMP_VAR(p_ProfilesRegs, fmpl_pects); + DUMP_VAR(p_ProfilesRegs, fmpl_pepts_ets); + DUMP_VAR(p_ProfilesRegs, fmpl_pegpc); + DUMP_VAR(p_ProfilesRegs, fmpl_peypc); + DUMP_VAR(p_ProfilesRegs, fmpl_perpc); + DUMP_VAR(p_ProfilesRegs, fmpl_perypc); + DUMP_VAR(p_ProfilesRegs, fmpl_perrpc); + FmPcdUnlock(p_FmPcd, intFlags); + + return E_OK; + } +} +#endif /* (defined(DEBUG_ERRORS) && ... */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_cc.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_cc.h @@ -0,0 +1,312 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_cc.h + + @Description FM PCD CC ... +*//***************************************************************************/ +#ifndef __FM_CC_H +#define __FM_CC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "fm_pcd.h" + + +/***********************************************************************/ +/* Coarse classification defines */ +/***********************************************************************/ + +#define CC_PC_FF_MACDST 0x00 +#define CC_PC_FF_MACSRC 0x01 +#define CC_PC_FF_ETYPE 0x02 + +#define CC_PC_FF_TCI1 0x03 +#define CC_PC_FF_TCI2 0x04 + +#define CC_PC_FF_MPLS1 0x06 +#define CC_PC_FF_MPLS_LAST 0x07 + +#define CC_PC_FF_IPV4DST1 0x08 +#define CC_PC_FF_IPV4DST2 0x16 +#define CC_PC_FF_IPV4IPTOS_TC1 0x09 +#define CC_PC_FF_IPV4IPTOS_TC2 0x17 +#define CC_PC_FF_IPV4PTYPE1 0x0A +#define CC_PC_FF_IPV4PTYPE2 0x18 +#define CC_PC_FF_IPV4SRC1 0x0b +#define CC_PC_FF_IPV4SRC2 0x19 +#define CC_PC_FF_IPV4SRC1_IPV4DST1 0x0c +#define CC_PC_FF_IPV4SRC2_IPV4DST2 0x1a +#define CC_PC_FF_IPV4TTL 0x29 + + +#define CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1 0x0d /*TODO - CLASS - what is it? TOS*/ +#define CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2 0x1b +#define CC_PC_FF_IPV6PTYPE1 0x0e +#define CC_PC_FF_IPV6PTYPE2 0x1c +#define CC_PC_FF_IPV6DST1 0x0f +#define CC_PC_FF_IPV6DST2 0x1d +#define CC_PC_FF_IPV6SRC1 0x10 +#define CC_PC_FF_IPV6SRC2 0x1e +#define CC_PC_FF_IPV6HOP_LIMIT 0x2a +#define CC_PC_FF_GREPTYPE 0x11 + +#define CC_PC_FF_MINENCAP_PTYPE 0x12 +#define CC_PC_FF_MINENCAP_IPDST 0x13 +#define CC_PC_FF_MINENCAP_IPSRC 0x14 +#define CC_PC_FF_MINENCAP_IPSRC_IPDST 0x15 + +#define CC_PC_FF_L4PSRC 0x1f +#define CC_PC_FF_L4PDST 0x20 +#define CC_PC_FF_L4PSRC_L4PDST 0x21 + +#define CC_PC_FF_PPPPID 0x05 + +#define CC_PC_PR_SHIM1 0x22 +#define CC_PC_PR_SHIM2 0x23 + +#define CC_PC_GENERIC_WITHOUT_MASK 0x27 +#define CC_PC_GENERIC_WITH_MASK 0x28 +#define CC_PC_GENERIC_IC_GMASK 0x2B +#define CC_PC_GENERIC_IC_HASH_INDEXED 0x2C + +#define CC_PR_OFFSET 0x25 +#define CC_PR_WITHOUT_OFFSET 0x26 + +#define CC_PC_PR_ETH_OFFSET 19 +#define CC_PC_PR_USER_DEFINED_SHIM1_OFFSET 16 +#define CC_PC_PR_USER_DEFINED_SHIM2_OFFSET 17 +#define CC_PC_PR_USER_LLC_SNAP_OFFSET 20 +#define CC_PC_PR_VLAN1_OFFSET 21 +#define CC_PC_PR_VLAN2_OFFSET 22 +#define CC_PC_PR_PPPOE_OFFSET 24 +#define CC_PC_PR_MPLS1_OFFSET 25 +#define CC_PC_PR_MPLS_LAST_OFFSET 26 +#define CC_PC_PR_IP1_OFFSET 27 +#define CC_PC_PR_IP_LAST_OFFSET 28 +#define CC_PC_PR_MINENC_OFFSET 28 +#define CC_PC_PR_L4_OFFSET 30 +#define CC_PC_PR_GRE_OFFSET 29 +#define CC_PC_PR_ETYPE_LAST_OFFSET 23 +#define CC_PC_PR_NEXT_HEADER_OFFSET 31 + +#define CC_PC_ILLEGAL 0xff +#define CC_SIZE_ILLEGAL 0 + +#define FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN 16 +#define FM_PCD_CC_AD_TABLE_ALIGN 256 +#define FM_PCD_CC_AD_ENTRY_SIZE 16 +#define FM_PCD_CC_NUM_OF_KEYS 255 + +#define FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE 0x00000000 +#define FM_PCD_AD_RESULT_DATA_FLOW_TYPE 0x80000000 +#define FM_PCD_AD_RESULT_PLCR_DIS 0x20000000 +#define FM_PCD_AD_RESULT_EXTENDED_MODE 0x80000000 +#define FM_PCD_AD_RESULT_NADEN 0x20000000 +#define FM_PCD_AD_RESULT_STATISTICS_EN 0x40000000 + + +#define FM_PCD_AD_CONT_LOOKUP_TYPE 0x40000000 +#define FM_PCD_AD_CONT_LOOKUP_LCL_MASK 0x00800000 + +#define FM_PCD_AD_TYPE_MASK 0xc0000000 +#define FM_PCD_AD_OPCODE_MASK 0x0000000f + +#define FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT 16 + +#define GLBL_MASK_FOR_HASH_INDEXED 0xfff00000 +#define CC_GLBL_MASK_SIZE 4 + +typedef uint32_t ccPrivateInfo_t; /**< private info of CC: */ + +#define CC_PRIVATE_INFO_NONE 0 +#define CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP 0x80000000 +#define CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH 0x40000000 +#define CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH 0x20000000 +#define CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP 0x10000000 + +/***********************************************************************/ +/* Memory map */ +/***********************************************************************/ +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +typedef _Packed struct { + volatile uint32_t fqid; + volatile uint32_t plcrProfile; + volatile uint32_t nia; + volatile uint32_t res; +} _PackedType t_AdOfTypeResult; + +typedef _Packed struct { + volatile uint32_t ccAdBase; + volatile uint32_t matchTblPtr; + volatile uint32_t pcAndOffsets; + volatile uint32_t gmask; +} _PackedType t_AdOfTypeContLookup; + +typedef _Packed union { + volatile t_AdOfTypeResult adResult; + volatile t_AdOfTypeContLookup adContLookup; +} _PackedType t_Ad; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/***********************************************************************/ +/* Driver's internal structures */ +/***********************************************************************/ + +typedef enum e_ModifyState { + e_MODIFY_STATE_ADD = 0, + e_MODIFY_STATE_REMOVE, + e_MODIFY_STATE_CHANGE +} e_ModifyState; + +typedef struct { + t_FmPcdCcNextEngineParams nextEngineParams; + uint32_t requiredAction; + uint32_t shadowAction; +} t_FmPcdCcNextEngineAndRequiredActionParams; + +typedef struct { + t_Handle p_Ad; + e_FmPcdEngine fmPcdEngine; + bool adAllocated; + bool isTree; + + uint32_t myInfo; + t_List *h_CcNextNodesLst; + t_Handle h_AdditionalInfo; + t_Handle h_Node; +} t_FmPcdModifyCcAdditionalParams; + +typedef struct { + t_Handle p_AdTableNew; + t_Handle p_KeysMatchTableNew; + t_Handle p_AdTableOld; + t_Handle p_KeysMatchTableOld; + uint16_t numOfKeys; + t_Handle h_CurrentNode; + uint16_t keyIndex; + t_Handle h_NodeForAdd; + t_Handle h_NodeForRmv; + t_Handle h_ManipForRmv; + bool tree; + + t_FmPcdCcNextEngineAndRequiredActionParams nextEngineAndRequiredAction[256]; +} t_FmPcdModifyCcKeyAdditionalParams; + +typedef struct { + t_Handle h_Manip; + t_Handle h_CcNode; +} t_CcNextEngineInfo; + +typedef struct { + uint16_t numOfKeys; + bool glblMaskUpdated; + t_Handle p_GlblMask; + bool lclMask; + uint8_t parseCode; + uint8_t offset; + uint8_t prsArrayOffset; + bool ctrlFlow; + uint8_t owners; + + uint8_t ccKeySizeAccExtraction; + uint8_t sizeOfExtraction; + uint8_t glblMaskSize; + + t_Handle h_KeysMatchTable; + t_Handle h_AdTable; + + t_List ccPrevNodesLst; + + t_List ccTreeIdLst; + t_List ccTreesLst; + + t_Handle h_FmPcd; + uint32_t shadowAction; + bool modifiedState; + uint8_t userSizeOfExtraction; + + t_FmPcdCcNextEngineAndRequiredActionParams nextEngineAndRequiredAction[256]; +} t_FmPcdCcNode; + +typedef struct { + t_FmPcdCcNode *p_FmPcdCcNode; + bool occupied; + uint8_t owners; + volatile bool lock; +} t_FmPcdCcNodeArray; + +typedef struct { + uint8_t numOfEntriesInGroup; + uint32_t totalBitsMask; + uint8_t baseGroupEntry; +} t_FmPcdCcGroupParam; + +typedef struct { + uint8_t netEnvId; + uintptr_t ccTreeBaseAddr; + uint8_t numOfGrps; + t_FmPcdCcGroupParam fmPcdGroupParam[FM_PCD_MAX_NUM_OF_CC_GROUPS]; + t_List fmPortsLst; + volatile bool lock; + uint8_t numOfEntries; + uint8_t owners; + t_Handle *fmPcdCcSavedManipParams[256]; + bool modifiedState; + uint32_t requiredAction; + t_FmPcdCcNextEngineAndRequiredActionParams nextEngineAndRequiredAction[FM_PCD_MAX_NUM_OF_KEYS]; +} t_FmPcdCcTree; + +typedef struct { + t_FmPcdCcTree *p_FmPcdCcTree; + bool occupied; + uint8_t owners; + volatile bool lock; +} t_FmPcdCcTreeArray; + + +bool FmPcdManipIsManipNode(t_Handle h_Ad); + + +#endif /* __FM_CC_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/dpa/NetCommSw/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-Pcd.o + +fsl-ncsw-Pcd-objs := fm_cc.o fm_kg.o fm_pcd.o fm_plcr.o fm_prs.o + + + + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_pcd.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_pcd.c @@ -0,0 +1,1693 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_pcd.c + + @Description FM PCD ... +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "xx_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "net_ext.h" +#include "fm_ext.h" +#include "fm_pcd_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_pcd_ipc.h" +#include "fm_hc.h" + + +static t_Error CheckFmPcdParameters(t_FmPcd *p_FmPcd) +{ + if(!p_FmPcd->h_Fm) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("h_Fm has to be initialized")); + + if(p_FmPcd->guestId == NCSW_MASTER_ID) + { + if(p_FmPcd->p_FmPcdKg && !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG")); + + if(p_FmPcd->p_FmPcdPlcr && !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG")); + + if(!p_FmPcd->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdExceptions has to be initialized")); + + if((!p_FmPcd->f_FmPcdIndexedException) && (p_FmPcd->p_FmPcdPlcr || p_FmPcd->p_FmPcdKg)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdIndexedException has to be initialized")); + + if(p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit > PRS_MAX_CYCLE_LIMIT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("prsMaxParseCycleLimit has to be less than 8191")); + } + + return E_OK; +} + +static volatile bool blockingFlag = FALSE; +static void FmPcdIpcMsgCompletionCB(t_Handle h_FmPcd, + uint8_t *p_Msg, + uint8_t *p_Reply, + uint32_t replyLength, + t_Error status) +{ + UNUSED(h_FmPcd);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status); + blockingFlag = FALSE; +} + +static t_Error FmPcdHandleIpcMsgCB(t_Handle h_FmPcd, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + t_FmPcdIpcMsg *p_IpcMsg = (t_FmPcdIpcMsg*)p_Msg; + t_FmPcdIpcReply *p_IpcReply = (t_FmPcdIpcReply*)p_Reply; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE); + +#ifdef DISABLE_SANITY_CHECKS + UNUSED(msgLength); +#endif /* DISABLE_SANITY_CHECKS */ + + ASSERT_COND(p_Msg); + + memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_PCD_MAX_REPLY_SIZE)); + *p_ReplyLength = 0; + + switch(p_IpcMsg->msgId) + { + case (FM_PCD_MASTER_IS_ALIVE): + *(uint8_t*)(p_IpcReply->replyBody) = 1; + p_IpcReply->error = E_OK; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + case (FM_PCD_MASTER_IS_ENABLED): + /* count partitions registrations */ + if(p_FmPcd->enabled) + p_FmPcd->numOfEnabledGuestPartitionsPcds++; + *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)p_FmPcd->enabled; + p_IpcReply->error = E_OK; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + case (FM_PCD_GUEST_DISABLE): + if(p_FmPcd->numOfEnabledGuestPartitionsPcds) + { + p_FmPcd->numOfEnabledGuestPartitionsPcds--; + p_IpcReply->error = E_OK; + } + else + { + REPORT_ERROR(MINOR, E_INVALID_STATE,("Trying to disable an unregistered partition")); + p_IpcReply->error = E_INVALID_STATE; + } + *p_ReplyLength = sizeof(uint32_t); + break; + case(FM_PCD_GET_COUNTER): + { + e_FmPcdCounters inCounter; + uint32_t outCounter; + + memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t)); + outCounter = FM_PCD_GetCounter(h_FmPcd, inCounter); + memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t)); + p_IpcReply->error = E_OK; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_PCD_ALLOC_KG_SCHEMES): + { + t_FmPcdIpcKgSchemesParams ipcSchemesParams; + + memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams)); + err = FmPcdKgAllocSchemes(h_FmPcd, + ipcSchemesParams.numOfSchemes, + ipcSchemesParams.guestId, + p_IpcReply->replyBody); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t) + ipcSchemesParams.numOfSchemes*sizeof(uint8_t); + break; + } + case (FM_PCD_FREE_KG_SCHEMES): + { + t_FmPcdIpcKgSchemesParams ipcSchemesParams; + + memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams)); + err = FmPcdKgFreeSchemes(h_FmPcd, + ipcSchemesParams.numOfSchemes, + ipcSchemesParams.guestId, + ipcSchemesParams.schemesIds); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_PCD_ALLOC_KG_CLSPLAN): + { + t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams; + + memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams)); + err = KgAllocClsPlanEntries(h_FmPcd, + ipcKgClsPlanParams.numOfClsPlanEntries, + ipcKgClsPlanParams.guestId, + p_IpcReply->replyBody); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + } + case (FM_PCD_FREE_KG_CLSPLAN): + { + t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams; + + memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams)); + KgFreeClsPlanEntries(h_FmPcd, + ipcKgClsPlanParams.numOfClsPlanEntries, + ipcKgClsPlanParams.guestId, + ipcKgClsPlanParams.clsPlanBase); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_PCD_ALLOC_PROFILES): + { + t_FmPcdIpcPlcrAllocParams ipcPlcrAllocParams; + uint16_t profilesBase; + + memcpy((uint8_t*)&ipcPlcrAllocParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcPlcrAllocParams)); + err = PlcrAllocProfiles(h_FmPcd, + ipcPlcrAllocParams.hardwarePortId, + ipcPlcrAllocParams.num, + &profilesBase); + memcpy(p_IpcReply->replyBody, (uint8_t*)&profilesBase, sizeof(uint16_t)); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint16_t); + break; + } + case (FM_PCD_FREE_PROFILES): + { + t_FmPcdIpcPlcrAllocParams ipcPlcrAllocParams; + + memcpy((uint8_t*)&ipcPlcrAllocParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcPlcrAllocParams)); + err = PlcrFreeProfiles(h_FmPcd, + ipcPlcrAllocParams.hardwarePortId, + ipcPlcrAllocParams.num, + ipcPlcrAllocParams.plcrProfilesBase); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_PCD_ALLOC_SHARED_PROFILES): + { + uint16_t numOfProfiles; + uint16_t profilesIds[FM_PCD_PLCR_NUM_ENTRIES]; + uint32_t profilesMask[FM_PCD_PLCR_NUM_ENTRIES/32]; + int i; + + memset(profilesMask, 0, FM_PCD_PLCR_NUM_ENTRIES/32 * sizeof(uint32_t)); + memcpy((uint8_t*)&numOfProfiles, p_IpcMsg->msgBody, sizeof(uint16_t)); + err = PlcrAllocSharedProfiles(h_FmPcd, + numOfProfiles, + profilesIds); + p_IpcReply->error = err; + + /* translate the allocated profile id's to a 32bit * 8regs mask */ + for(i = 0;i> (profilesIds[i] % 32)); + + memcpy(p_IpcReply->replyBody, (uint8_t*)&profilesMask, sizeof(profilesMask)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(profilesMask); /* num-of-shared-profiles */ + break; + } + case (FM_PCD_FREE_SHARED_PROFILES): + { + t_FmPcdIpcSharedPlcrAllocParams ipcSharedPlcrAllocParams; + uint16_t profilesIds[FM_PCD_PLCR_NUM_ENTRIES]; + int i,j, index = 0; + uint32_t walking1Mask = 0x80000000; + + memset(profilesIds, 0, FM_PCD_PLCR_NUM_ENTRIES*sizeof(uint16_t)); + memcpy((uint8_t*)&ipcSharedPlcrAllocParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcSharedPlcrAllocParams)); + for(i = 0; i>= 1; + } + walking1Mask = 0x80000000; + } + } + + PlcrFreeSharedProfiles(h_FmPcd, + ipcSharedPlcrAllocParams.num, + profilesIds); + break; + } + case(FM_PCD_GET_SW_PRS_OFFSET): + { + t_FmPcdIpcSwPrsLable ipcSwPrsLable; + uint32_t swPrsOffset; + + memcpy((uint8_t*)&ipcSwPrsLable, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcSwPrsLable)); + swPrsOffset = + FmPcdGetSwPrsOffset(h_FmPcd, + (e_NetHeaderType)ipcSwPrsLable.enumHdr, + ipcSwPrsLable.indexPerHdr); + memcpy(p_IpcReply->replyBody, (uint8_t*)&swPrsOffset, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case(FM_PCD_PRS_INC_PORT_STATS): + { + t_FmPcdIpcPrsIncludePort ipcPrsIncludePort; + + memcpy((uint8_t*)&ipcPrsIncludePort, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcPrsIncludePort)); + PrsIncludePortInStatistics(h_FmPcd, + ipcPrsIncludePort.hardwarePortId, + ipcPrsIncludePort.include); + break; + } +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + case(FM_PCD_DUMP_REGS): + if((err = FM_PCD_DumpRegs(h_FmPcd)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + case(FM_PCD_KG_DUMP_REGS): + if((err = FM_PCD_KgDumpRegs(h_FmPcd)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + case(FM_PCD_PLCR_DUMP_REGS): + if((err = FM_PCD_PlcrDumpRegs(h_FmPcd)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + case(FM_PCD_PLCR_PROFILE_DUMP_REGS): + { + t_Handle h_Profile; + memcpy((uint8_t*)&h_Profile, p_IpcMsg->msgBody, sizeof(t_Handle)); + if((err = FM_PCD_PlcrProfileDumpRegs(h_FmPcd, h_Profile)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + + } + case(FM_PCD_PRS_DUMP_REGS): + if((err = FM_PCD_PrsDumpRegs(h_FmPcd)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; +#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ + default: + *p_ReplyLength = 0; + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); + } + return E_OK; +} + +void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId) +{ + p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = clsPlanGrpId; +} + +t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams) +{ + uint8_t netEnvId = p_GrpParams->netEnvId; + int i, k, j; + + if(p_FmPcd->netEnvs[netEnvId].clsPlanGrpId != ILLEGAL_CLS_PLAN) + { + p_GrpParams->grpExists = TRUE; + p_GrpParams->clsPlanGrpId = p_FmPcd->netEnvs[netEnvId].clsPlanGrpId; + return E_OK; + } + + for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++) + { + for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) + { + /* if an option exists, add it to the opts list */ + if(p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) + { + /* check if this option already exists, add if it doesn't */ + for(j = 0;jnumOfOptions;j++) + { + if(p_GrpParams->options[j] == p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) + break; + } + p_GrpParams->optVectors[j] |= p_FmPcd->netEnvs[netEnvId].unitsVectors[i]; + if(j == p_GrpParams->numOfOptions) + { + p_GrpParams->options[p_GrpParams->numOfOptions] = p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt; + p_GrpParams->numOfOptions++; + } + } + } + } + + if(p_GrpParams->numOfOptions == 0) + { + if(p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId != ILLEGAL_CLS_PLAN) + { + p_GrpParams->grpExists = TRUE; + p_GrpParams->clsPlanGrpId = p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId; + } + } + + return E_OK; + +} + +t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector) +{ + uint8_t j,k; + + *p_Vector = 0; + + for (j=0; ((j < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[0].hdr != HEADER_TYPE_NONE)); j++) + { + for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) + { + if (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].opt == opt) + *p_Vector |= p_FmPcd->netEnvs[netEnvId].unitsVectors[j]; + } + } + + if (!*p_Vector) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested option was not defined for this Network Environment Characteristics module")); + else + return E_OK; +} + +t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params) +{ + int i; + + p_Params->vector = 0; + for(i=0; inumOfDistinctionUnits ;i++) + { + if(p_FmPcd->netEnvs[p_Params->netEnvId].units[p_Params->unitIds[i]].hdrs[0].hdr == HEADER_TYPE_NONE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested unit was not defined for this Network Environment Characteristics module")); + ASSERT_COND(p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]); + p_Params->vector |= p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]; + } + + return E_OK; +} + +bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector) +{ + int i=0, k; + /* check whether a given unit may be used by non-clsPlan users. */ + /* first, recognize the unit by its vector */ + while (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE) + { + if (p_FmPcd->netEnvs[netEnvId].unitsVectors[i] == unitVector) + { + for (k=0; + ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); + k++) + /* check that no option exists */ + if((protocolOpt_t)p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) + return FALSE; + break; + } + i++; + } + /* assert that a unit was found to mach the vector */ + ASSERT_COND(p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); + + return TRUE; +} +bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + int i, k; + + ASSERT_COND(p_FmPcd); + + for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++) + { + for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) + if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr) + return TRUE; + } + for (i=0; ((i < FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE)); i++) + { + if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) + return TRUE; + } + + return FALSE; +} + +e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr) +{ + int i; + + ASSERT_COND(p_FmPcd); + + for (i=0; (i < FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) + && (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++) + { + if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) + return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr; + } + + return HEADER_TYPE_NONE; +} + +void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint16_t swPortIndex = 0; + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort = h_FmPort; +} + +uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + return p_FmPcd->netEnvs[netEnvId].lcvs[hdrNum]; +} + +uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + return p_FmPcd->netEnvs[netEnvId].macsecVector; +} + +void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId) +{ + ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners++; +} + +void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId) +{ + ASSERT_COND(((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners); + ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners--; +} + +uint32_t FmPcdLock(t_Handle h_FmPcd) +{ + return XX_LockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock); +} + +void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags) +{ + XX_UnlockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock, intFlags); +} + +t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd) +{ + ASSERT_COND(h_FmPcd); + SANITY_CHECK_RETURN_VALUE(((t_FmPcd*)h_FmPcd)->h_Hc, E_INVALID_HANDLE, NULL); + return ((t_FmPcd*)h_FmPcd)->h_Hc; +} + +/**********************************************************************************************************/ +/* API */ +/**********************************************************************************************************/ + +t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams) +{ + t_FmPcd *p_FmPcd = NULL; + t_FmPhysAddr physicalMuramBase; + uint8_t i; + + SANITY_CHECK_RETURN_VALUE(p_FmPcdParams, E_INVALID_HANDLE,NULL); + + p_FmPcd = (t_FmPcd *) XX_Malloc(sizeof(t_FmPcd)); + if (!p_FmPcd) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd")); + return NULL; + } + memset(p_FmPcd, 0, sizeof(t_FmPcd)); + + p_FmPcd->p_FmPcdDriverParam = (t_FmPcdDriverParam *) XX_Malloc(sizeof(t_FmPcdDriverParam)); + if (!p_FmPcd->p_FmPcdDriverParam) + { + XX_Free(p_FmPcd); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd Driver Param")); + return NULL; + } + memset(p_FmPcd->p_FmPcdDriverParam, 0, sizeof(t_FmPcdDriverParam)); + + p_FmPcd->h_Fm = p_FmPcdParams->h_Fm; + p_FmPcd->guestId = FmGetGuestId(p_FmPcd->h_Fm); + p_FmPcd->h_FmMuram = FmGetMuramHandle(p_FmPcd->h_Fm); + FmGetPhysicalMuramBase(p_FmPcdParams->h_Fm, &physicalMuramBase); + p_FmPcd->physicalMuramBase = (uint64_t)((uint64_t)(&physicalMuramBase)->low | ((uint64_t)(&physicalMuramBase)->high << 32)); + + for(i = 0; inetEnvs[i].clsPlanGrpId = ILLEGAL_CLS_PLAN; + + if (p_FmPcdParams->useHostCommand) + { + t_FmHcParams hcParams; + + memset(&hcParams, 0, sizeof(hcParams)); + hcParams.h_Fm = p_FmPcd->h_Fm; + hcParams.h_FmPcd = (t_Handle)p_FmPcd; + memcpy((uint8_t*)&hcParams.params, (uint8_t*)&p_FmPcdParams->hc, sizeof(t_FmPcdHcParams)); + p_FmPcd->h_Hc = FmHcConfigAndInit(&hcParams); + if (!p_FmPcd->h_Hc) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd HC")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + else if(p_FmPcd->guestId != NCSW_MASTER_ID) + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("No Host Command defined for a guest partition.")); + + if(p_FmPcdParams->kgSupport) + { + p_FmPcd->p_FmPcdKg = (t_FmPcdKg *)KgConfig(p_FmPcd, p_FmPcdParams); + if(!p_FmPcd->p_FmPcdKg) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd Keygen")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + + if(p_FmPcdParams->plcrSupport) + { + p_FmPcd->p_FmPcdPlcr = (t_FmPcdPlcr *)PlcrConfig(p_FmPcd, p_FmPcdParams); + if(!p_FmPcd->p_FmPcdPlcr) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd Policer")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + + if(p_FmPcdParams->prsSupport) + { + p_FmPcd->p_FmPcdPrs = (t_FmPcdPrs *)PrsConfig(p_FmPcd, p_FmPcdParams); + if(!p_FmPcd->p_FmPcdPrs) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd Parser")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + + p_FmPcd->h_Spinlock = XX_InitSpinlock(); + if (!p_FmPcd->h_Spinlock) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd spinlock")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + + p_FmPcd->numOfEnabledGuestPartitionsPcds = 0; + + p_FmPcd->f_Exception = p_FmPcdParams->f_Exception; + p_FmPcd->f_FmPcdIndexedException = p_FmPcdParams->f_ExceptionId; + p_FmPcd->h_App = p_FmPcdParams->h_App; + + return p_FmPcd; +} + +t_Error FM_PCD_Init(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + t_FmPcdIpcMsg msg; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + uint8_t isMasterAlive = 0; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + memset(p_FmPcd->fmPcdIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if(Sprint (p_FmPcd->fmPcdIpcHandlerModuleName, "FM_PCD_%d_%d", FmGetId(p_FmPcd->h_Fm), NCSW_MASTER_ID) != 10) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if(Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm), p_FmPcd->guestId) != (p_FmPcd->guestId<10 ? 10:11)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + + p_FmPcd->h_IpcSession = XX_IpcInitSession(p_FmPcd->fmPcdIpcHandlerModuleName, p_FmPcd->fmPcdModuleName); + if (p_FmPcd->h_IpcSession == NULL) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM PCD Guest %d IPC session", p_FmPcd->guestId)); + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_PCD_MASTER_IS_ALIVE; + msg.msgBody[0] = p_FmPcd->guestId; + blockingFlag = TRUE; + + do + { + replyLength = sizeof(uint32_t) + sizeof(isMasterAlive); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(p_FmPcd->guestId), + (uint8_t*)&reply, + &replyLength, + FmPcdIpcMsgCompletionCB, + h_FmPcd)) != E_OK) + REPORT_ERROR(MAJOR, err, NO_MSG); + while(blockingFlag) ; + if(replyLength != (sizeof(uint32_t) + sizeof(isMasterAlive))) + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + isMasterAlive = *(uint8_t*)(reply.replyBody); + } while (!isMasterAlive); + } + + CHECK_INIT_PARAMETERS(p_FmPcd, CheckFmPcdParameters); + + if(p_FmPcd->p_FmPcdKg) + { + err = KgInit(p_FmPcd); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if(p_FmPcd->p_FmPcdPlcr) + { + err = PlcrInit(p_FmPcd); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if(p_FmPcd->p_FmPcdPrs) + { + err = PrsInit(p_FmPcd); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if(p_FmPcd->guestId == NCSW_MASTER_ID) + { + /* register to inter-core messaging mechanism */ + memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if(Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm),NCSW_MASTER_ID) != 10) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + err = XX_IpcRegisterMsgHandler(p_FmPcd->fmPcdModuleName, FmPcdHandleIpcMsgCB, p_FmPcd, FM_PCD_MAX_REPLY_SIZE); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + XX_Free(p_FmPcd->p_FmPcdDriverParam); + p_FmPcd->p_FmPcdDriverParam = NULL; + + FmRegisterPcd(p_FmPcd->h_Fm, p_FmPcd); + + return E_OK; +} + +t_Error FM_PCD_Free(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd =(t_FmPcd *)h_FmPcd; + t_Error err = E_OK; + + if(p_FmPcd->enabled) + FM_PCD_Disable(p_FmPcd); + + if (p_FmPcd->h_Spinlock) + XX_FreeSpinlock(p_FmPcd->h_Spinlock); + + if(p_FmPcd->p_FmPcdDriverParam) + { + XX_Free(p_FmPcd->p_FmPcdDriverParam); + p_FmPcd->p_FmPcdDriverParam = NULL; + } + if(p_FmPcd->p_FmPcdKg) + { + if((err = KgFree(p_FmPcd)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + XX_Free(p_FmPcd->p_FmPcdKg); + p_FmPcd->p_FmPcdKg = NULL; + } + + if(p_FmPcd->p_FmPcdPlcr) + { + if((err = PlcrFree(p_FmPcd)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + XX_Free(p_FmPcd->p_FmPcdPlcr); + p_FmPcd->p_FmPcdPlcr = NULL; + } + + if(p_FmPcd->p_FmPcdPrs) + { + if(p_FmPcd->guestId == NCSW_MASTER_ID) + PrsFree(p_FmPcd); + XX_Free(p_FmPcd->p_FmPcdPrs); + p_FmPcd->p_FmPcdPrs = NULL; + } + + if (p_FmPcd->h_Hc) + { + FmHcFree(p_FmPcd->h_Hc); + p_FmPcd->h_Hc = NULL; + } + + XX_IpcUnregisterMsgHandler(p_FmPcd->fmPcdModuleName); + + FmUnregisterPcd(p_FmPcd->h_Fm); + + XX_Free(p_FmPcd); + return E_OK; +} + +t_Error FM_PCD_Enable(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + + if(p_FmPcd->guestId == NCSW_MASTER_ID) + { + if(p_FmPcd->p_FmPcdKg) + KgEnable(p_FmPcd); + + if(p_FmPcd->p_FmPcdPlcr) + PlcrEnable(p_FmPcd); + + if(p_FmPcd->p_FmPcdPrs) + PrsEnable(p_FmPcd); + + p_FmPcd->enabled = TRUE; + } + else + { + uint8_t enabled; + t_FmPcdIpcMsg msg; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_PCD_MASTER_IS_ENABLED; + replyLength = sizeof(uint32_t) + sizeof(enabled); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t) + sizeof(enabled)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + p_FmPcd->enabled = (bool)!!(*(uint8_t*)(reply.replyBody)); + if (!p_FmPcd->enabled) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-PCD master should be enabled first!")); + } + + return E_OK; +} + +t_Error FM_PCD_Disable(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + t_FmPcdIpcMsg msg; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + + if(p_FmPcd->guestId == NCSW_MASTER_ID) + { + if(p_FmPcd->numOfEnabledGuestPartitionsPcds != 0) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Trying to disable a master partition PCD while guest partitions are still enabled.")); + + if(p_FmPcd->p_FmPcdKg) + KgDisable(p_FmPcd); + + if(p_FmPcd->p_FmPcdPlcr) + PlcrDisable(p_FmPcd); + + if(p_FmPcd->p_FmPcdPrs) + PrsDisable(p_FmPcd); + + p_FmPcd->enabled = FALSE; + + return E_OK; + } + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_GUEST_DISABLE; + memset(&reply, 0, sizeof(reply)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + return (t_Error)(reply.error); +} + +t_Handle FM_PCD_SetNetEnvCharacteristics(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags, specialUnits = 0; + uint8_t bitId = 0; + uint8_t i, j, k; + uint8_t netEnvCurrId; + uint8_t ipsecAhUnit = 0,ipsecEspUnit = 0; + bool ipsecAhExists = FALSE, ipsecEspExists = FALSE, shim1Selected = FALSE; + uint8_t hdrNum; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_STATE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); + + intFlags = FmPcdLock(p_FmPcd); + + /* find a new netEnv */ + for(i = 0;inetEnvs[i].used) + break; + + if(i== FM_MAX_NUM_OF_PORTS) + { + REPORT_ERROR(MAJOR, E_FULL,("No more than %d netEnv's allowed.", FM_MAX_NUM_OF_PORTS)); + FmPcdUnlock(p_FmPcd, intFlags); + return NULL; + } + + p_FmPcd->netEnvs[i].used = TRUE; + + if (!TRY_LOCK(NULL, &p_FmPcd->netEnvs[i].lock)) + { + FmPcdUnlock(p_FmPcd, intFlags); + return NULL; + } + FmPcdUnlock(p_FmPcd, intFlags); + + netEnvCurrId = (uint8_t)i; + + /* clear from previous use */ + memset(&p_FmPcd->netEnvs[netEnvCurrId].units, 0, FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS * sizeof(t_FmPcdIntDistinctionUnit)); + memset(&p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs, 0, FM_PCD_MAX_NUM_OF_PRIVATE_HDRS * sizeof(t_FmPcdNetEnvAliases)); + memcpy(&p_FmPcd->netEnvs[netEnvCurrId].units, p_NetEnvParams->units, p_NetEnvParams->numOfDistinctionUnits*sizeof(t_FmPcdIntDistinctionUnit)); + p_FmPcd->netEnvs[netEnvCurrId].clsPlanGrpId = ILLEGAL_CLS_PLAN; + + /* check that header with opt is not interchanged with the same header */ + for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + for (k=0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) + { + /* if an option exists, check that other headers are not the same header + without option */ + if(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt) + { + for (j=0; (j < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr != HEADER_TYPE_NONE); j++) + if((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr == p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr) && + !p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].opt) + { + REPORT_ERROR(MINOR, E_FULL, ("Illegal unit - header with opt may not be interchangeable with the same header without opt")); + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvCurrId].lock); + return NULL; + } + } + } + } + + /* IPSEC_AH and IPSEC_SPI can't be 2 units, */ + /* check that header with opt is not interchanged with the same header */ + for(i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + for(k=0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) + { + /* Some headers pairs may not be defined on different units as the parser + doesn't distinguish */ + if(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_AH) + { + if (ipsecEspExists && (ipsecEspUnit != i)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units")); + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvCurrId].lock); + return NULL; + } + else + { + ipsecAhUnit = i; + ipsecAhExists = TRUE; + } + } + if(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_ESP) + { + if (ipsecAhExists && (ipsecAhUnit != i)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units")); + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvCurrId].lock); + return NULL; + } + else + { + ipsecEspUnit = i; + ipsecEspExists = TRUE; + } + } + if(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_ENCAP_ESP) + { + /* TODO - general coding. choose the free shim header */ + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_ENCAP_ESP; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM1; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM1; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; + } + } + } + + /* if private header (shim), check that no other headers specified */ + for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + if(IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + if(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[1].hdr != HEADER_TYPE_NONE) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header may not be interchanged with other headers")); + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvCurrId].lock); + return NULL; + } + } + + for(i=0; inumOfDistinctionUnits;i++) + { + if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + switch(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr) + { + case(HEADER_TYPE_USER_DEFINED_SHIM1): + if (shim1Selected) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header cannot be selected with UDP_IPSEC_ESP")); + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvCurrId].lock); + return NULL; + } + shim1Selected = TRUE; + p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000001; + break; + case(HEADER_TYPE_USER_DEFINED_SHIM2): + p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000002; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested SHIM not supported")); + } + else + { + p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = (uint32_t)(0x80000000 >> bitId++); + + if(IS_SPECIAL_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + p_FmPcd->netEnvs[netEnvCurrId].macsecVector = p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i]; + } + } + + /* define a set of hardware parser LCV's according to the defined netenv */ + + /* set an array of LCV's for each header in the netEnv */ + for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + /* private headers have no LCV in the hard parser */ + if (!IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + { + for (k=0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) + { + GET_PRS_HDR_NUM(hdrNum, p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr); + if ((hdrNum == ILLEGAL_HDR_NUM) || (hdrNum == NO_HDR_NUM)) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvCurrId].lock); + return NULL; + } + p_FmPcd->netEnvs[netEnvCurrId].lcvs[hdrNum] |= p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i]; + } + } + } + + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvCurrId].lock); + + return UINT_TO_PTR((uint64_t)netEnvCurrId+1); +} + +t_Error FM_PCD_DeleteNetEnvCharacteristics(t_Handle h_FmPcd, t_Handle h_NetEnv) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint8_t netEnvId = (uint8_t)(PTR_TO_UINT(h_NetEnv)-1); + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if (!TRY_LOCK(p_FmPcd->h_Spinlock, &p_FmPcd->netEnvs[netEnvId].lock)) + return ERROR_CODE(E_BUSY); + /* check that no port is bound to this netEnv */ + if(p_FmPcd->netEnvs[netEnvId].owners) + { + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvId].lock); + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a netEnv that has ports/schemes/trees/clsPlanGrps bound to")); + } + p_FmPcd->netEnvs[netEnvId].used= FALSE; + p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = ILLEGAL_CLS_PLAN; + + memset(p_FmPcd->netEnvs[netEnvId].units, 0, sizeof(t_FmPcdIntDistinctionUnit)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + memset(p_FmPcd->netEnvs[netEnvId].unitsVectors, 0, sizeof(uint32_t)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + memset(p_FmPcd->netEnvs[netEnvId].lcvs, 0, sizeof(uint32_t)*FM_PCD_PRS_NUM_OF_HDRS); + + RELEASE_LOCK(p_FmPcd->netEnvs[netEnvId].lock); + + return E_OK; +} + +void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN(h_FmPcd, E_INVALID_STATE); + + FmHcTxConf(p_FmPcd->h_Hc, p_Fd); +} + +uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t replyLength, outCounter = 0; + t_FmPcdIpcMsg msg; + t_Error err; + t_FmPcdIpcReply reply; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_PCD_GET_COUNTER; + memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t)); + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(uint32_t), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t) + sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t)); + return outCounter; + } + + switch(counter) + { + case(e_FM_PCD_KG_COUNTERS_TOTAL): + if(!p_FmPcd->p_FmPcdKg) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this counters")); + return 0; + } + break; + case(e_FM_PCD_PLCR_COUNTERS_YELLOW): + case(e_FM_PCD_PLCR_COUNTERS_RED): + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + case(e_FM_PCD_PLCR_COUNTERS_TOTAL): + case(e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + if(!p_FmPcd->p_FmPcdPlcr) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this counters")); + return 0; + } + /* check that counters are enabled */ + if(!(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + return 0; + } + break; + case(e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + if(!p_FmPcd->p_FmPcdPrs) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this counters")); + return 0; + } + break; + default: + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); + return 0; + } + switch(counter) + { + case(e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pds); + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l2rrs); + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l3rrs); + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l4rrs); + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->srrs); + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l2rres); + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l3rres); + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l4rres); + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->srres); + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->spcs); + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->spscs); + case(e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->hxscs); + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mrcs); + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mrscs); + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mwcs); + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mwscs); + case(e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fcscs); + case(e_FM_PCD_KG_COUNTERS_TOTAL): + return GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgtpc); + + /*Policer statictics*/ + case(e_FM_PCD_PLCR_COUNTERS_YELLOW): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt); + case(e_FM_PCD_PLCR_COUNTERS_RED): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt); + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt); + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt); + case(e_FM_PCD_PLCR_COUNTERS_TOTAL): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt); + case(e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt); + + default: + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); + return 0; + } +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FM_PCD_DumpRegs(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdIpcMsg msg; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_DUMP_REGS; + return XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL); + } + if (p_FmPcd->p_FmPcdKg) + return FM_PCD_KgDumpRegs(h_FmPcd); + if (p_FmPcd->p_FmPcdPlcr) + return FM_PCD_PlcrDumpRegs(h_FmPcd); + if (p_FmPcd->p_FmPcdPrs) + return FM_PCD_PrsDumpRegs(h_FmPcd); + return E_OK; +} + +t_Error FM_PCD_HcDumpRegs(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_STATE); + + return FmHcDumpRegs(p_FmPcd->h_Hc); +} + +#endif /* (defined(DEBUG_ERRORS) && ... */ + +t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigException - guest mode!")); + + GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception); + if(bitMask) + { + if (enable) + p_FmPcd->exceptions |= bitMask; + else + p_FmPcd->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t bitMask = 0, tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetException - guest mode!")); + + GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception); + + if(bitMask) + { + if (enable) + p_FmPcd->exceptions |= bitMask; + else + p_FmPcd->exceptions &= ~bitMask; + + switch(exception) + { + case(e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): + case(e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): + if(!p_FmPcd->p_FmPcdKg) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working")); + break; + case(e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): + case(e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): + case(e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): + case(e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): + if(!p_FmPcd->p_FmPcdPlcr) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working")); + break; + case(e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): + case(e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): + if(!p_FmPcd->p_FmPcdPrs) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - parser is not working")); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported exception")); + + } + + switch(exception) + { + case(e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeeer); + if(enable) + tmpReg |= FM_PCD_KG_DOUBLE_ECC; + else + tmpReg &= ~FM_PCD_KG_DOUBLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeeer, tmpReg); + break; + case(e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeeer); + if(enable) + tmpReg |= FM_PCD_KG_KEYSIZE_OVERFLOW; + else + tmpReg &= ~FM_PCD_KG_KEYSIZE_OVERFLOW; + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeeer, tmpReg); + break; + case(e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perer); + if(enable) + tmpReg |= FM_PCD_PRS_DOUBLE_ECC; + else + tmpReg &= ~FM_PCD_PRS_DOUBLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perer, tmpReg); + break; + case(e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pever); + if(enable) + tmpReg |= FM_PCD_PRS_SINGLE_ECC; + else + tmpReg &= ~FM_PCD_PRS_SINGLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pever, tmpReg); + break; + case(e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); + if(enable) + tmpReg |= FM_PCD_PLCR_DOUBLE_ECC; + else + tmpReg &= ~FM_PCD_PLCR_DOUBLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg); + break; + case(e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); + if(enable) + tmpReg |= FM_PCD_PLCR_INIT_ENTRY_ERROR; + else + tmpReg &= ~FM_PCD_PLCR_INIT_ENTRY_ERROR; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg); + break; + case(e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); + if(enable) + tmpReg |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; + else + tmpReg &= ~FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg); + break; + case(e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); + if(enable) + tmpReg |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; + else + tmpReg &= ~FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported exception")); + } + /* for ECC exceptions driver automatically enables ECC mechanism, if disabled. + Driver may disable them automatically, depending on driver's status */ + if(enable && ( (exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC))) + FmEnableRamsEcc(p_FmPcd->h_Fm); + if(!enable && ( (exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC))) + FmDisableRamsEcc(p_FmPcd->h_Fm); + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ForceIntr - guest mode!")); + + switch(exception) + { + case(e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): + case(e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): + if(!p_FmPcd->p_FmPcdKg) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working")); + break; + case(e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): + case(e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): + case(e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): + case(e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): + if(!p_FmPcd->p_FmPcdPlcr) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working")); + break; + case(e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): + case(e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): + if(!p_FmPcd->p_FmPcdPrs) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt -parsrer is not working")); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid interrupt requested")); + + } + switch(exception) + { + case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perfr, FM_PCD_PRS_DOUBLE_ECC); + break; + case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pevfr, FM_PCD_PRS_SINGLE_ECC); + break; + case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC: + if (!(p_FmPcd->exceptions & FM_PCD_EX_KG_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer, FM_PCD_KG_DOUBLE_ECC); + break; + case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW: + if (!(p_FmPcd->exceptions & FM_PCD_EX_KG_KEYSIZE_OVERFLOW)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer, FM_PCD_KG_KEYSIZE_OVERFLOW); + break; + case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_DOUBLE_ECC); + break; + case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_INIT_ENTRY_ERROR); + break; + case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE); + break; + case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE); + break; + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception may not be forced")); + } + + return E_OK; +} + + +t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ModifyCounter - guest mode!")); + + switch(counter) + { + case(e_FM_PCD_KG_COUNTERS_TOTAL): + if(!p_FmPcd->p_FmPcdKg) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this counters - keygen is not working")); + break; + case(e_FM_PCD_PLCR_COUNTERS_YELLOW): + case(e_FM_PCD_PLCR_COUNTERS_RED): + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + case(e_FM_PCD_PLCR_COUNTERS_TOTAL): + case(e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + if(!p_FmPcd->p_FmPcdPlcr) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this counters - Policer is not working")); + if(!(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + break; + case(e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + case(e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + if(!p_FmPcd->p_FmPcdPrs) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); + } + switch(counter) + { + case(e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pds, value); + break; + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l2rrs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l3rrs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l4rrs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->srrs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l2rres, value); + break; + case(e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l3rres, value); + break; + case(e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->l4rres, value); + break; + case(e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->srres, value); + break; + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->spcs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->spscs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->hxscs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mrcs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mrscs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mwcs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->mwscs, value); + break; + case(e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fcscs, value); + break; + case(e_FM_PCD_KG_COUNTERS_TOTAL): + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgtpc,value); + break; + + /*Policer counters*/ + case(e_FM_PCD_PLCR_COUNTERS_YELLOW): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt, value); + break; + case(e_FM_PCD_PLCR_COUNTERS_RED): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt, value); + break; + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt, value); + break; + case(e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt, value); + break; + case(e_FM_PCD_PLCR_COUNTERS_TOTAL): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt, value); + break; + case(e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt, value); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported type of counter")); + } + +return E_OK; +} + --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_cc.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_cc.c @@ -0,0 +1,3467 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_cc.c + + @Description FM CC ... +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "fm_pcd_ext.h" +#include "fm_muram_ext.h" + +#include "fm_common.h" +#include "fm_hc.h" +#include "fm_cc.h" + + +#if defined(FM_CAPWAP_SUPPORT) +#define FM_PCD_CC_MANIP +#endif /* defined(FM_CAPWAP_SUPPORT) || ... */ + + +t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree, uint8_t manipIndx) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; + + ASSERT_COND(p_FmPcdCcTree); + + return p_FmPcdCcTree->fmPcdCcSavedManipParams[manipIndx]; +} + +void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, t_Handle h_SavedManipParams, uint8_t manipIndx) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; + + ASSERT_COND(p_FmPcdCcTree); + + p_FmPcdCcTree->fmPcdCcSavedManipParams[manipIndx] = h_SavedManipParams; +} + +uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_FmPcdCcNode); + return p_FmPcdCcNode->parseCode; +} + +uint8_t FmPcdCcGetOffset(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_FmPcdCcNode); + return p_FmPcdCcNode->offset; +} + +uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_FmPcdCcNode); + return p_FmPcdCcNode->numOfKeys; +} +static void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo) +{ + t_CcNodeInformation *p_CcInformation; + uint32_t intFlags; + + p_CcInformation = (t_CcNodeInformation *)XX_Malloc(sizeof(t_CcNodeInformation)); + if (p_CcInformation) + { + memset(p_CcInformation, 0, sizeof(t_CcNodeInformation)); + memcpy(p_CcInformation, p_CcInfo, sizeof(t_CcNodeInformation)); + INIT_LIST(&p_CcInformation->node); + + intFlags = XX_DisableAllIntr(); + LIST_AddToTail(&p_CcInformation->node, p_List); + XX_RestoreAllIntr(intFlags); + } + else + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Node Information")); +} + + +static t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info) +{ + t_CcNodeInformation *p_CcInformation; + t_List *p_Pos; + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List); p_Pos = LIST_NEXT(p_Pos)) + { + p_CcInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcInformation->h_CcNode); + if(p_CcInformation->h_CcNode == h_Info) + { + XX_RestoreAllIntr(intFlags); + return p_CcInformation; + } + } + XX_RestoreAllIntr(intFlags); + return NULL; +} + +static void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info) +{ + t_CcNodeInformation *p_CcInformation = NULL; + uint32_t intFlags; + t_List *p_Pos; + + intFlags = XX_DisableAllIntr(); + if (LIST_IsEmpty(p_List)) + { + XX_RestoreAllIntr(intFlags); + return; + } + + for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List); p_Pos = LIST_NEXT(p_Pos)) + { + p_CcInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcInformation->h_CcNode); + if (p_CcInformation->h_CcNode == h_Info) + break; + } + if (p_CcInformation) + LIST_DelAndInit(&p_CcInformation->node); + XX_RestoreAllIntr(intFlags); +} + +static t_Error FmPcdCcSetRequiredAction(t_Handle h_FmPcd, uint32_t requiredAction, t_FmPcdCcNextEngineAndRequiredActionParams *p_CcNextEngineParamsTmp, + t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree) +{ + + t_AdOfTypeResult *p_AdTmp = (t_AdOfTypeResult *)h_AdTmp; + uint32_t tmpReg32; + t_Error err; + t_FmPcdCcNode *p_FmPcdCcNode; + int i = 0; + uint16_t tmp = 0; + uint16_t profileId; + uint8_t relativeSchemeId, physicalSchemeId; + t_CcNodeInformation ccNodeInfo; + + for(i = 0; i < numOfEntries; i++) + { + if(i == 0) + h_AdTmp = PTR_MOVE(h_AdTmp, i*FM_PCD_CC_AD_ENTRY_SIZE); + else + h_AdTmp = PTR_MOVE(h_AdTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + if(p_CcNextEngineParamsTmp[i].shadowAction & requiredAction) + continue; + switch(p_CcNextEngineParamsTmp[i].nextEngineParams.nextEngine) + { + case(e_FM_PCD_CC): + if(requiredAction) + { + p_FmPcdCcNode = p_CcNextEngineParamsTmp[i].nextEngineParams.params.ccParams.h_CcNode; + ASSERT_COND(p_FmPcdCcNode); + if(p_FmPcdCcNode->shadowAction == requiredAction) + break; + if((requiredAction & UPDATE_CC_WITH_TREE) && !(p_FmPcdCcNode->shadowAction & UPDATE_CC_WITH_TREE)) + { + + ASSERT_COND(LIST_NumOfObjs(&p_FmPcdCcNode->ccTreesLst) == 0); + if(p_FmPcdCcNode->shadowAction & UPDATE_CC_WITH_DELETE_TREE) + p_FmPcdCcNode->shadowAction &= ~UPDATE_CC_WITH_DELETE_TREE; + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = h_Tree; + EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNode->ccTreesLst, &ccNodeInfo); + p_CcNextEngineParamsTmp[i].shadowAction |= UPDATE_CC_WITH_TREE; + } + if((requiredAction & UPDATE_CC_WITH_DELETE_TREE) && !(p_FmPcdCcNode->shadowAction & UPDATE_CC_WITH_DELETE_TREE)) + { + ASSERT_COND(LIST_NumOfObjs(&p_FmPcdCcNode->ccTreesLst) == 1); + if(p_FmPcdCcNode->shadowAction & UPDATE_CC_WITH_TREE) + p_FmPcdCcNode->shadowAction &= ~UPDATE_CC_WITH_TREE; + DequeueNodeInfoFromRelevantLst(&p_FmPcdCcNode->ccTreesLst, h_Tree); + p_CcNextEngineParamsTmp[i].shadowAction |= UPDATE_CC_WITH_DELETE_TREE; + } + if(p_FmPcdCcNode->nextEngineAndRequiredAction[p_FmPcdCcNode->numOfKeys].nextEngineParams.nextEngine != e_FM_PCD_INVALID) + tmp = (uint8_t)(p_FmPcdCcNode->numOfKeys + 1); + else + tmp = p_FmPcdCcNode->numOfKeys; + err = FmPcdCcSetRequiredAction(h_FmPcd, requiredAction, p_FmPcdCcNode->nextEngineAndRequiredAction, p_FmPcdCcNode->h_AdTable, tmp, h_Tree); + if(err != E_OK) + return err; + p_FmPcdCcNode->shadowAction |= requiredAction; + } + break; + + case(e_FM_PCD_KG): + if((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) && !(p_CcNextEngineParamsTmp[i].shadowAction & UPDATE_NIA_ENQ_WITHOUT_DMA)) + { + physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_CcNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme)-1); + relativeSchemeId = FmPcdKgGetRelativeSchemeId(h_FmPcd, physicalSchemeId); + if(relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + if (!FmPcdKgIsSchemeValidSw(h_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid direct scheme.")); + if(!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this action scheme has to be direct.")); + err = FmPcdKgCcGetSetParams(h_FmPcd, p_CcNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme, requiredAction); + if(err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_CcNextEngineParamsTmp[i].shadowAction |= requiredAction; + } + break; + + case(e_FM_PCD_PLCR): + if((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) && !(p_CcNextEngineParamsTmp[i].shadowAction & UPDATE_NIA_ENQ_WITHOUT_DMA)) + { + if(!p_CcNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.overrideParams) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this intialization only overrideFqid can be intiizliaes")); + if(!p_CcNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.sharedProfile) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this intialization only overrideFqid can be intiizliaes")); + err = FmPcdPlcrGetAbsoluteProfileId(h_FmPcd, e_FM_PCD_PLCR_SHARED, NULL, p_CcNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.newRelativeProfileId, &profileId); + if(err!= E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + err = FmPcdPlcrCcGetSetParams(h_FmPcd, profileId, requiredAction); + if(err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_CcNextEngineParamsTmp[i].shadowAction |= requiredAction; + } + break; + + case(e_FM_PCD_DONE): + if((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) && !(p_CcNextEngineParamsTmp[i].shadowAction & UPDATE_NIA_ENQ_WITHOUT_DMA)) + { + tmpReg32 = GET_UINT32(p_AdTmp->nia); + if((tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) != (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine was previosely assigned not as PCD_DONE")); + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_AdTmp->nia, tmpReg32); + p_CcNextEngineParamsTmp[i].shadowAction |= requiredAction; + } + break; + + default: + break; + } + } + + return E_OK; +} + +static t_Error CcUpdateParam(t_Handle h_FmPcd, + t_Handle h_FmPort, + t_FmPcdCcNextEngineAndRequiredActionParams *p_CcNextEngineParams, + uint16_t numOfEntries, + t_Handle h_Ad, + bool validate, + uint16_t level, + t_Handle h_FmTree, + bool modify) +{ + t_CcNodeInformation *p_CcNodeInfo; + t_FmPcdCcNode *p_FmPcdCcNode; + t_Error err; + uint16_t tmp = 0; + int i = 0; + + level++; + + if(numOfEntries) + { + for(i = 0; i < numOfEntries; i++) + { + if(i == 0) + h_Ad = PTR_MOVE(h_Ad, i*FM_PCD_CC_AD_ENTRY_SIZE); + else + h_Ad = PTR_MOVE(h_Ad, FM_PCD_CC_AD_ENTRY_SIZE); + + if(p_CcNextEngineParams[i].nextEngineParams.nextEngine == e_FM_PCD_CC) + { + p_FmPcdCcNode = p_CcNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; + ASSERT_COND(p_FmPcdCcNode); + p_CcNodeInfo = FindNodeInfoInReleventLst(&p_FmPcdCcNode->ccTreesLst,h_FmTree); + ASSERT_COND(p_CcNodeInfo); + p_CcNodeInfo->index = level; +#ifdef FM_PCD_CC_MANIP + if(p_CcNextEngineParams[i].nextEngineParams.h_Manip) + { + err = FmPcdManipUpdate(h_FmPcd, h_FmPort, p_CcNextEngineParams[i].nextEngineParams.h_Manip, h_Ad, validate, p_CcNodeInfo->index, h_FmTree, modify); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } +#endif /* FM_PCD_CC_MANIP */ + + if(p_FmPcdCcNode->nextEngineAndRequiredAction[p_FmPcdCcNode->numOfKeys].nextEngineParams.nextEngine != e_FM_PCD_INVALID) + tmp = (uint8_t)(p_FmPcdCcNode->numOfKeys + 1); + else + tmp = p_FmPcdCcNode->numOfKeys; + + err = CcUpdateParam(h_FmPcd, h_FmPort, p_FmPcdCcNode->nextEngineAndRequiredAction, tmp, p_FmPcdCcNode->h_AdTable, validate,level, h_FmTree, modify); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } +#ifdef FM_PCD_CC_MANIP + else + { + if(p_CcNextEngineParams[i].nextEngineParams.h_Manip) + { + err = FmPcdManipUpdate(h_FmPcd, h_FmPort, p_CcNextEngineParams[i].nextEngineParams.h_Manip, h_Ad, validate, level,h_FmTree, modify); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } +#endif /* FM_PCD_CC_MANIP */ + } + } + + return E_OK; +} +static bool IsNodeInModifiedState(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_CcNode); + + return p_CcNode->modifiedState; +} + +static void UpdateNodeWithModifiedState(t_Handle h_CcNode, bool modifiedState) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_FmPcdCcNode); + + p_FmPcdCcNode->modifiedState = modifiedState; +} + +static ccPrivateInfo_t IcDefineCode(t_FmPcdCcNodeParams *p_CcNodeParam) +{ + switch (p_CcNodeParam->extractCcParams.extractNonHdr.action) + { + case(e_FM_PCD_ACTION_EXACT_MATCH): + switch(p_CcNodeParam->extractCcParams.extractNonHdr.src) + { + case(e_FM_PCD_EXTRACT_FROM_KEY): + return CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH; + case(e_FM_PCD_EXTRACT_FROM_HASH): + return CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH; + default: + return CC_PRIVATE_INFO_NONE; + } + case(e_FM_PCD_ACTION_INDEXED_LOOKUP): + switch(p_CcNodeParam->extractCcParams.extractNonHdr.src) + { + case(e_FM_PCD_EXTRACT_FROM_HASH): + return CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP; + case(e_FM_PCD_EXTRACT_FROM_FLOW_ID): + return CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP; + default: + return CC_PRIVATE_INFO_NONE; + } + default: + break; + } + return CC_PRIVATE_INFO_NONE; +} + +static t_CcNodeInformation * DequeueAdditionalInfoFromRelevantLst(t_List *p_List) +{ + t_CcNodeInformation *p_CcNodeInfo = NULL; + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + if (!LIST_IsEmpty(p_List)) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_List->p_Next); + LIST_DelAndInit(&p_CcNodeInfo->node); + } + XX_RestoreAllIntr(intFlags); + return p_CcNodeInfo; +} + +static void ReleaseLst(t_List *p_List) +{ + t_CcNodeInformation *p_CcNodeInfo = NULL; + + if(!LIST_IsEmpty(p_List)) + { + p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List); + while (p_CcNodeInfo) + { + XX_Free(p_CcNodeInfo); + p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List); + } + } + LIST_DelAndInit(p_List); +} + +void FmPcdCcTreeReleaseLock(t_Handle h_FmPcdCcTree) +{ + RELEASE_LOCK(((t_FmPcdCcTree *)h_FmPcdCcTree)->lock); +} + +void FmPcdCcNodeTreeReleaseLock(t_List *p_List) +{ + t_List *p_Pos; + t_CcNodeInformation *p_CcNodeInfo; + t_Handle h_FmPcdCcTree; + + LIST_FOR_EACH(p_Pos, p_List) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); + h_FmPcdCcTree = p_CcNodeInfo->h_CcNode; + FmPcdCcTreeReleaseLock(h_FmPcdCcTree); + } + ReleaseLst(p_List); +} + +static void DeleteNode(t_FmPcdCcNode *p_FmPcdCcNode) +{ + if(p_FmPcdCcNode) + { + if(p_FmPcdCcNode->p_GlblMask) + { + XX_Free(p_FmPcdCcNode->p_GlblMask); + p_FmPcdCcNode->p_GlblMask = NULL; + } + if(p_FmPcdCcNode->h_KeysMatchTable) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcdCcNode->h_FmPcd), p_FmPcdCcNode->h_KeysMatchTable); + p_FmPcdCcNode->h_KeysMatchTable = NULL; + } + if(p_FmPcdCcNode->h_AdTable) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcdCcNode->h_FmPcd), p_FmPcdCcNode->h_AdTable); + p_FmPcdCcNode->h_AdTable = NULL; + } + + ReleaseLst(&p_FmPcdCcNode->ccPrevNodesLst); + ReleaseLst(&p_FmPcdCcNode->ccTreeIdLst); + ReleaseLst(&p_FmPcdCcNode->ccTreesLst); + + XX_Free(p_FmPcdCcNode); + } +} + +static void DeleteTree(t_FmPcdCcTree *p_FmPcdTree, t_FmPcd *p_FmPcd) +{ + if(p_FmPcdTree) + { + if(p_FmPcdTree->ccTreeBaseAddr) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd), UINT_TO_PTR(p_FmPcdTree->ccTreeBaseAddr)); + p_FmPcdTree->ccTreeBaseAddr = 0; + } + + ReleaseLst(&p_FmPcdTree->fmPortsLst); + + XX_Free(p_FmPcdTree); + } +} + +static void UpdateNodeOwner(t_FmPcdCcNode *p_FmPcdCcNode, bool add) +{ + ASSERT_COND(p_FmPcdCcNode); + + if(add) + p_FmPcdCcNode->owners++; + else + { + ASSERT_COND(p_FmPcdCcNode->owners); + p_FmPcdCcNode->owners--; + } +} + +static void GetCcExtractKeySize(uint8_t parseCodeRealSize, uint8_t *parseCodeCcSize) +{ + if((parseCodeRealSize > 0) && (parseCodeRealSize < 2)) + *parseCodeCcSize = 1; + else if(parseCodeRealSize == 2) + *parseCodeCcSize = 2; + else if((parseCodeRealSize > 2) && (parseCodeRealSize <= 4)) + *parseCodeCcSize = 4; + else if((parseCodeRealSize > 4) && (parseCodeRealSize <= 8)) + *parseCodeCcSize = 8; + else if((parseCodeRealSize > 8) && (parseCodeRealSize <= 16)) + *parseCodeCcSize = 16; + else if((parseCodeRealSize > 16) && (parseCodeRealSize <= 24)) + *parseCodeCcSize = 24; + else if((parseCodeRealSize > 24) && (parseCodeRealSize <= 32)) + *parseCodeCcSize = 32; + else if((parseCodeRealSize > 32) && (parseCodeRealSize <= 40)) + *parseCodeCcSize = 40; + else if((parseCodeRealSize > 40) && (parseCodeRealSize <= 48)) + *parseCodeCcSize = 48; + else if((parseCodeRealSize > 48) && (parseCodeRealSize <= 56)) + *parseCodeCcSize = 56; + else + *parseCodeCcSize = 0; +} + +static void GetSizeHeaderField(e_NetHeaderType hdr,t_FmPcdFields field,uint8_t *parseCodeRealSize) +{ + switch(hdr) + { + case (HEADER_TYPE_ETH): + switch(field.eth) + { + case(NET_HEADER_FIELD_ETH_DA): + *parseCodeRealSize = 6; + break; + case(NET_HEADER_FIELD_ETH_SA): + *parseCodeRealSize = 6; + break; + case(NET_HEADER_FIELD_ETH_TYPE): + *parseCodeRealSize = 2; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case(HEADER_TYPE_PPPoE): + switch(field.pppoe) + { + case(NET_HEADER_FIELD_PPPoE_PID): + *parseCodeRealSize = 2; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_VLAN): + switch(field.vlan) + { + case(NET_HEADER_FIELD_VLAN_TCI): + *parseCodeRealSize = 2; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported2")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_MPLS): + switch(field.mpls) + { + case(NET_HEADER_FIELD_MPLS_LABEL_STACK): + *parseCodeRealSize = 4; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported3")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_IPv4): + switch(field.ipv4) + { + case(NET_HEADER_FIELD_IPv4_DST_IP): + case(NET_HEADER_FIELD_IPv4_SRC_IP): + *parseCodeRealSize = 4; + break; + case(NET_HEADER_FIELD_IPv4_TOS): + case(NET_HEADER_FIELD_IPv4_PROTO): + *parseCodeRealSize = 1; + break; + case(NET_HEADER_FIELD_IPv4_DST_IP | NET_HEADER_FIELD_IPv4_SRC_IP): + *parseCodeRealSize = 8; + break; + case(NET_HEADER_FIELD_IPv4_TTL): + *parseCodeRealSize = 1; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported4")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_IPv6): + switch(field.ipv6) + { + case(NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC): + *parseCodeRealSize = 4; + break; + case(NET_HEADER_FIELD_IPv6_NEXT_HDR): + case(NET_HEADER_FIELD_IPv6_HOP_LIMIT): + *parseCodeRealSize = 1; + break; + case(NET_HEADER_FIELD_IPv6_DST_IP): + case(NET_HEADER_FIELD_IPv6_SRC_IP): + *parseCodeRealSize = 16; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_GRE): + switch(field.gre) + { + case(NET_HEADER_FIELD_GRE_TYPE): + *parseCodeRealSize = 2; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported6")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_MINENCAP): + switch(field.minencap) + { + case(NET_HEADER_FIELD_MINENCAP_TYPE): + *parseCodeRealSize = 1; + break; + case(NET_HEADER_FIELD_MINENCAP_DST_IP): + case(NET_HEADER_FIELD_MINENCAP_SRC_IP): + *parseCodeRealSize = 4; + break; + case(NET_HEADER_FIELD_MINENCAP_SRC_IP | NET_HEADER_FIELD_MINENCAP_DST_IP): + *parseCodeRealSize = 8; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported7")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_TCP): + switch(field.tcp) + { + case(NET_HEADER_FIELD_TCP_PORT_SRC): + case(NET_HEADER_FIELD_TCP_PORT_DST): + *parseCodeRealSize = 2; + break; + case(NET_HEADER_FIELD_TCP_PORT_SRC | NET_HEADER_FIELD_TCP_PORT_DST): + *parseCodeRealSize = 4; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported8")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + case (HEADER_TYPE_UDP): + switch(field.udp) + { + case(NET_HEADER_FIELD_UDP_PORT_SRC): + case(NET_HEADER_FIELD_UDP_PORT_DST): + *parseCodeRealSize = 2; + break; + case(NET_HEADER_FIELD_UDP_PORT_SRC | NET_HEADER_FIELD_UDP_PORT_DST): + *parseCodeRealSize = 4; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported9")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported10")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } +} + +static t_Error ValidateNextEngineParams(t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + uint16_t absoluteProfileId; + t_Error err = E_OK; + uint8_t relativeSchemeId; + + switch(p_FmPcdCcNextEngineParams->nextEngine) + { + case(e_FM_PCD_INVALID): + err = E_NOT_SUPPORTED; + break; + case(e_FM_PCD_DONE): + if(p_FmPcdCcNextEngineParams->params.enqueueParams.action == e_FM_PCD_ENQ_FRAME) + { + if(p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid && + !p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("not defined fqid for control flow for BMI next engine ")); + if(p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid & ~0x00FFFFFF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidForCtrlFlow must be between 1 and 2^24-1")); + } + break; + case(e_FM_PCD_KG): + relativeSchemeId = FmPcdKgGetRelativeSchemeId(h_FmPcd, (uint8_t)(PTR_TO_UINT(p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme)-1)); + if(relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if(!FmPcdKgIsSchemeValidSw(h_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("not valid schemeIndex in KG next engine param")); + if(!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("CC Node may point only to a scheme that is always direct.")); + break; + case(e_FM_PCD_PLCR): + if(p_FmPcdCcNextEngineParams->params.plcrParams.overrideParams) + { + /* if private policer profile, it may be uninitialized yet, therefor no checks are done at this stage */ + if(p_FmPcdCcNextEngineParams->params.plcrParams.sharedProfile) + { + err = FmPcdPlcrGetAbsoluteProfileId(h_FmPcd,e_FM_PCD_PLCR_SHARED,NULL,p_FmPcdCcNextEngineParams->params.plcrParams.newRelativeProfileId, &absoluteProfileId); + if(err) + RETURN_ERROR(MAJOR, err, ("Shared profile offset is out of range")); + if(!FmPcdPlcrIsProfileValid(h_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid profile")); + } + else + { + } + /* TODO - add check according to the revision of the chip. + if(!p_FmPcdCcNextEngineParams->params.plcrParams.newFqid || + (p_FmPcdCcNextEngineParams->params.plcrParams.newFqid & ~0x00FFFFFF)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("newFqid must be between 1 and 2^24-1")); + */ + } + break; + case(e_FM_PCD_CC): + if(!p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode) + RETURN_ERROR(MAJOR, E_NULL_POINTER, ("handler to next Node is NULL")); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine is not correct")); + } + return err; +} + +static uint8_t GetGenParseCode(e_FmPcdExtractFrom src, uint32_t offset, bool glblMask, uint8_t *parseArrayOffset, bool fromIc, ccPrivateInfo_t icCode) +{ + if(!fromIc) + { + switch(src) + { + case(e_FM_PCD_EXTRACT_FROM_FRAME_START): + if(glblMask) + return CC_PC_GENERIC_WITH_MASK ; + else + return CC_PC_GENERIC_WITHOUT_MASK; + case(e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE): + *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET; + if(offset) + return CC_PR_OFFSET; + else + return CC_PR_WITHOUT_OFFSET; + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src")); + return CC_PC_ILLEGAL; + } + } + else + { + switch (icCode) + { + case(CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH): + *parseArrayOffset = 0x50; + return CC_PC_GENERIC_IC_GMASK; + case(CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH): + *parseArrayOffset = 0x48; + return CC_PC_GENERIC_IC_GMASK; + case(CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP): + *parseArrayOffset = 0x48; + return CC_PC_GENERIC_IC_HASH_INDEXED; + case(CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP): + *parseArrayOffset = 0x16; + return CC_PC_GENERIC_IC_HASH_INDEXED; + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src")); + break; + } + } + return CC_PC_ILLEGAL; +} + +static uint8_t GetFullFieldParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex index, t_FmPcdFields field) +{ + + switch(hdr) + { + case(HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + return CC_PC_ILLEGAL; + + case(HEADER_TYPE_ETH): + switch(field.eth) + { + case(NET_HEADER_FIELD_ETH_DA): + return CC_PC_FF_MACDST; + case(NET_HEADER_FIELD_ETH_SA): + return CC_PC_FF_MACSRC; + case(NET_HEADER_FIELD_ETH_TYPE): + return CC_PC_FF_ETYPE; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_VLAN): + switch(field.vlan) + { + case(NET_HEADER_FIELD_VLAN_TCI): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_TCI1; + if(index == e_FM_PCD_HDR_INDEX_LAST) + return CC_PC_FF_TCI2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_MPLS): + switch(field.mpls) + { + case(NET_HEADER_FIELD_MPLS_LABEL_STACK): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_MPLS1; + if(index == e_FM_PCD_HDR_INDEX_LAST) + return CC_PC_FF_MPLS_LAST; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index")); + return CC_PC_ILLEGAL; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_IPv4): + switch(field.ipv4) + { + case(NET_HEADER_FIELD_IPv4_DST_IP): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4DST1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4DST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv4_TOS): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4IPTOS_TC1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4IPTOS_TC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv4_PROTO): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4PTYPE1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4PTYPE2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv4_SRC_IP): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4SRC1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4SRC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv4_SRC_IP | NET_HEADER_FIELD_IPv4_DST_IP): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4SRC1_IPV4DST1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4SRC2_IPV4DST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv4_TTL): + return CC_PC_FF_IPV4TTL; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_IPv6): + switch(field.ipv6) + { + case(NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv6_NEXT_HDR): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV6PTYPE1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV6PTYPE2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv6_DST_IP): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV6DST1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV6DST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv6_SRC_IP): + if((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV6SRC1; + if(index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV6SRC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + case(NET_HEADER_FIELD_IPv6_HOP_LIMIT): + return CC_PC_FF_IPV6HOP_LIMIT; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_GRE): + switch(field.gre) + { + case(NET_HEADER_FIELD_GRE_TYPE): + return CC_PC_FF_GREPTYPE; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + case(HEADER_TYPE_MINENCAP): + switch(field.minencap) + { + case(NET_HEADER_FIELD_MINENCAP_TYPE): + return CC_PC_FF_MINENCAP_PTYPE; + case(NET_HEADER_FIELD_MINENCAP_DST_IP): + return CC_PC_FF_MINENCAP_IPDST; + case(NET_HEADER_FIELD_MINENCAP_SRC_IP): + return CC_PC_FF_MINENCAP_IPSRC; + case(NET_HEADER_FIELD_MINENCAP_SRC_IP | NET_HEADER_FIELD_MINENCAP_DST_IP): + return CC_PC_FF_MINENCAP_IPSRC_IPDST; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_TCP): + switch(field.tcp) + { + case(NET_HEADER_FIELD_TCP_PORT_SRC): + return CC_PC_FF_L4PSRC; + case(NET_HEADER_FIELD_TCP_PORT_DST): + return CC_PC_FF_L4PDST; + case(NET_HEADER_FIELD_TCP_PORT_DST | NET_HEADER_FIELD_TCP_PORT_SRC): + return CC_PC_FF_L4PSRC_L4PDST; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_PPPoE): + switch(field.pppoe) + { + case(NET_HEADER_FIELD_PPPoE_PID): + return CC_PC_FF_PPPPID; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case(HEADER_TYPE_UDP): + switch(field.udp) + { + case(NET_HEADER_FIELD_UDP_PORT_SRC): + return CC_PC_FF_L4PSRC; + case(NET_HEADER_FIELD_UDP_PORT_DST): + return CC_PC_FF_L4PDST; + case(NET_HEADER_FIELD_UDP_PORT_DST | NET_HEADER_FIELD_UDP_PORT_SRC): + return CC_PC_FF_L4PSRC_L4PDST; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } +} + +static uint8_t GetPrParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex, uint32_t offset, bool glblMask, uint8_t *parseArrayOffset) +{ + bool offsetRelevant = FALSE; + + if(offset) + offsetRelevant = TRUE; + + switch(hdr){ + case(HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + return CC_PC_ILLEGAL; + case(HEADER_TYPE_ETH): + *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET; + break; + case(HEADER_TYPE_USER_DEFINED_SHIM1): + if(offset || glblMask) + *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET; + else + return CC_PC_PR_SHIM1; + break; + case(HEADER_TYPE_USER_DEFINED_SHIM2): + if(offset || glblMask) + *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET; + else + return CC_PC_PR_SHIM2; + break; + case(HEADER_TYPE_LLC_SNAP): + *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET; + break; + case(HEADER_TYPE_PPPoE): + *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET; + break; + case(HEADER_TYPE_MPLS): + if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET; + else if(hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET; + else + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index")); + return CC_PC_ILLEGAL; + } + break; + case(HEADER_TYPE_IPv4): + case(HEADER_TYPE_IPv6): + if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_IP1_OFFSET; + else if(hdrIndex == e_FM_PCD_HDR_INDEX_2) + *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET; + else + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index")); + return CC_PC_ILLEGAL; + + } + break; + case(HEADER_TYPE_MINENCAP): + *parseArrayOffset = CC_PC_PR_MINENC_OFFSET; + break; + case(HEADER_TYPE_GRE): + *parseArrayOffset = CC_PC_PR_GRE_OFFSET; + break; + case(HEADER_TYPE_TCP): + case(HEADER_TYPE_UDP): + case(HEADER_TYPE_IPSEC_AH): + case(HEADER_TYPE_IPSEC_ESP): + case(HEADER_TYPE_DCCP): + case(HEADER_TYPE_SCTP): + *parseArrayOffset = CC_PC_PR_L4_OFFSET; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header for this type of operation")); + return CC_PC_ILLEGAL; + } + + if(offsetRelevant) + return CC_PR_OFFSET; + else + return CC_PR_WITHOUT_OFFSET; +} + +static uint8_t GetFieldParseCode(e_NetHeaderType hdr, t_FmPcdFields field, uint32_t offset, uint8_t *parseArrayOffset, e_FmPcdHdrIndex hdrIndex) +{ + bool offsetRelevant = FALSE; + + if(offset) + offsetRelevant = TRUE; + + switch(hdr) + { + case(HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + case(HEADER_TYPE_ETH): + switch(field.eth) + { + case(NET_HEADER_FIELD_ETH_TYPE): + *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + break; + case(HEADER_TYPE_VLAN): + switch(field.vlan) + { + case(NET_HEADER_FIELD_VLAN_TCI): + if((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET; + else if(hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal header ")); + return CC_PC_ILLEGAL; + } + if(offsetRelevant) + return CC_PR_OFFSET; + else + return CC_PR_WITHOUT_OFFSET; +} + +static void FillAdOfTypeResult(t_Handle p_Ad, t_FmPcd *p_FmPcd, t_FmPcdCcNextEngineParams *p_CcNextEngineParams) +{ + t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult*)p_Ad; + uint32_t tmp = 0, tmpNia = 0; + uint16_t profileId; + t_Handle p_AdNewPtr = NULL; + + p_AdNewPtr = p_AdResult; + +#ifdef FM_PCD_CC_MANIP + if (p_CcNextEngineParams->h_Manip) + FmPcdManipUpdateAdResultForCc(p_CcNextEngineParams->h_Manip, p_Ad, &p_AdNewPtr); +#endif /* FM_PCD_CC_MANIP */ + + if(p_AdNewPtr) + { + switch(p_CcNextEngineParams->nextEngine) + { + case(e_FM_PCD_DONE): + if(p_CcNextEngineParams->params.enqueueParams.action == e_FM_PCD_ENQ_FRAME) + { + if(p_CcNextEngineParams->params.enqueueParams.overrideFqid) + { + tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; + tmp |= p_CcNextEngineParams->params.enqueueParams.newFqid; + } + else + { + tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; + tmp |= FM_PCD_AD_RESULT_PLCR_DIS; + } + } + if(p_CcNextEngineParams->params.enqueueParams.action == e_FM_PCD_DROP_FRAME) + tmpNia |= (NIA_ENG_BMI |NIA_BMI_AC_DISCARD); + else + tmpNia |= (NIA_ENG_BMI |NIA_BMI_AC_ENQ_FRAME); + if(p_CcNextEngineParams->params.enqueueParams.statisticsEn) + tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE | FM_PCD_AD_RESULT_STATISTICS_EN; + break; + case(e_FM_PCD_KG): + if(p_CcNextEngineParams->params.kgParams.overrideFqid) + { + tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; + tmp |= p_CcNextEngineParams->params.kgParams.newFqid; + } + else + { + tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; + tmp |= FM_PCD_AD_RESULT_PLCR_DIS; + } + tmpNia = NIA_KG_DIRECT; + tmpNia |= NIA_ENG_KG; + tmpNia |= (uint8_t)(PTR_TO_UINT(p_CcNextEngineParams->params.kgParams.h_DirectScheme)-1); + if(p_CcNextEngineParams->params.kgParams.statisticsEn) + tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE | FM_PCD_AD_RESULT_STATISTICS_EN; + break; + case(e_FM_PCD_PLCR): + tmp = 0; + if(p_CcNextEngineParams->params.plcrParams.overrideParams) + { + tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; + + /* if private policer profile, it may be uninitialized yet, therefor no checks are done at this stage */ + if(p_CcNextEngineParams->params.plcrParams.sharedProfile) + { + tmpNia |= NIA_PLCR_ABSOLUTE; + FmPcdPlcrGetAbsoluteProfileId((t_Handle)p_FmPcd,e_FM_PCD_PLCR_SHARED,NULL,p_CcNextEngineParams->params.plcrParams.newRelativeProfileId, &profileId); + } + else + profileId = p_CcNextEngineParams->params.plcrParams.newRelativeProfileId; + + tmp |= p_CcNextEngineParams->params.plcrParams.newFqid; + WRITE_UINT32(p_AdResult->plcrProfile,(uint32_t)((uint32_t)profileId << FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT)); + } + else + tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; + tmpNia |= NIA_ENG_PLCR | p_CcNextEngineParams->params.plcrParams.newRelativeProfileId; + if(p_CcNextEngineParams->params.kgParams.statisticsEn) + tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE | FM_PCD_AD_RESULT_STATISTICS_EN; + break; + default: + return; + } + WRITE_UINT32(p_AdResult->fqid, tmp); + +#ifdef FM_PCD_CC_MANIP + if(p_CcNextEngineParams->h_Manip) + { + tmp = GET_UINT32(p_AdResult->plcrProfile); + tmp |= (uint32_t)(XX_VirtToPhys(p_AdNewPtr) - (p_FmPcd->physicalMuramBase)) >> 4; + WRITE_UINT32(p_AdResult->plcrProfile, tmp); + + tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE; + tmpNia |= FM_PCD_AD_RESULT_NADEN; + } +#endif /* FM_PCD_CC_MANIP */ + + WRITE_UINT32(p_AdResult->nia, tmpNia); + } +} + +static void FillAdOfTypeContLookup(t_Handle p_Ad, t_Handle h_FmPcd, t_Handle p_FmPcdCcNode, t_Handle h_Manip) +{ + t_FmPcdCcNode *p_Node = (t_FmPcdCcNode *)p_FmPcdCcNode; + t_AdOfTypeContLookup *p_AdContLookup = (t_AdOfTypeContLookup *)p_Ad; + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpReg32; + t_Handle p_AdNewPtr = NULL; + + p_AdNewPtr = p_AdContLookup; + +#ifdef FM_PCD_CC_MANIP + if (h_Manip) + FmPcdManipUpdateAdContLookupForCc(h_Manip, p_Ad, &p_AdNewPtr, (uint32_t)((XX_VirtToPhys(p_Node->h_AdTable) - p_FmPcd->physicalMuramBase))); +#else + UNUSED(h_Manip); +#endif /* FM_PCD_CC_MANIP */ + + if(p_AdNewPtr) + { + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + tmpReg32 |= p_Node->sizeOfExtraction ? ((p_Node->sizeOfExtraction - 1) << 24) : 0; + tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Node->h_AdTable) - p_FmPcd->physicalMuramBase); + WRITE_UINT32(p_AdContLookup->ccAdBase, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= p_Node->numOfKeys << 24; + tmpReg32 |= (p_Node->lclMask ? FM_PCD_AD_CONT_LOOKUP_LCL_MASK : 0); + tmpReg32 |= p_Node->h_KeysMatchTable ? + (uint32_t)(XX_VirtToPhys(p_Node->h_KeysMatchTable) - p_FmPcd->physicalMuramBase) : 0; + WRITE_UINT32(p_AdContLookup->matchTblPtr, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= p_Node->prsArrayOffset << 24; + tmpReg32 |= p_Node->offset << 16; + tmpReg32 |= p_Node->parseCode; + WRITE_UINT32(p_AdContLookup->pcAndOffsets, tmpReg32); + + Mem2IOCpy32((void*)&p_AdContLookup->gmask, p_Node->p_GlblMask, CC_GLBL_MASK_SIZE); + } +} + +static void NextStepAd(t_Handle p_Ad, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, t_FmPcd *p_FmPcd) +{ + switch(p_FmPcdCcNextEngineParams->nextEngine) + { + case(e_FM_PCD_KG): + case(e_FM_PCD_PLCR): + case(e_FM_PCD_DONE): + FillAdOfTypeResult(p_Ad, p_FmPcd, p_FmPcdCcNextEngineParams); + break; + case(e_FM_PCD_CC): + FillAdOfTypeContLookup(p_Ad, + p_FmPcd, + p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, +#ifdef FM_PCD_CC_MANIP + p_FmPcdCcNextEngineParams->h_Manip +#else + NULL +#endif /* FM_PCD_CC_MANIP */ + ); + UpdateNodeOwner (p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, + TRUE); + break; + default: + return; + } +} + + +static void ReleaseNewNodeCommonPart(t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + if(p_AdditionalInfo->p_AdTableNew) + FM_MURAM_FreeMem(FmPcdGetMuramHandle(((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd), p_AdditionalInfo->p_AdTableNew); + if(p_AdditionalInfo->p_KeysMatchTableNew) + FM_MURAM_FreeMem(FmPcdGetMuramHandle(((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd), p_AdditionalInfo->p_KeysMatchTableNew); +} + +static t_Error UpdateGblMask(t_FmPcdCcNode *p_FmPcdCcNode, uint8_t keySize, uint8_t *p_Mask) +{ + if (p_Mask && + !p_FmPcdCcNode->glblMaskUpdated && + (keySize <= 4) && + !p_FmPcdCcNode->lclMask ) + { + memcpy(p_FmPcdCcNode->p_GlblMask, p_Mask, (sizeof(uint8_t))*keySize); + p_FmPcdCcNode->glblMaskUpdated = TRUE; + p_FmPcdCcNode->glblMaskSize = 4; + } + else if (p_Mask && + (keySize <= 4) && + !p_FmPcdCcNode->lclMask) + { + if (memcmp(p_FmPcdCcNode->p_GlblMask, p_Mask, keySize) != 0) + { + p_FmPcdCcNode->lclMask = TRUE; + p_FmPcdCcNode->glblMaskSize = 0; + } + } + else if (!p_Mask && (p_FmPcdCcNode->glblMaskUpdated) && (keySize <= 4)) + { + uint32_t tmpMask = 0xffffffff; + if (memcmp(p_FmPcdCcNode->p_GlblMask, &tmpMask, 4) != 0) + { + p_FmPcdCcNode->lclMask = TRUE; + p_FmPcdCcNode->glblMaskSize = 0; + } + } + else if (p_Mask) + { + p_FmPcdCcNode->lclMask = TRUE; + p_FmPcdCcNode->glblMaskSize = 0; + } + + return E_OK; +} + +static t_Error BuildNewNodeCommonPart(t_FmPcdCcNode *p_FmPcdCcNode, + int *size, + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + + p_AdditionalInfo->p_AdTableNew = (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcdCcNode->h_FmPcd), + (uint32_t)( (p_AdditionalInfo->numOfKeys+1) * FM_PCD_CC_AD_ENTRY_SIZE), + FM_PCD_CC_AD_TABLE_ALIGN); + if(!p_AdditionalInfo->p_AdTableNew) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory in MURAM for AD table ")); + + IOMemSet32((uint8_t*)p_AdditionalInfo->p_AdTableNew, 0, (uint32_t)((p_AdditionalInfo->numOfKeys+1) * FM_PCD_CC_AD_ENTRY_SIZE)); + + if(p_FmPcdCcNode->lclMask) + *size = 2 * p_FmPcdCcNode->ccKeySizeAccExtraction; + else + *size = p_FmPcdCcNode->ccKeySizeAccExtraction; + + p_AdditionalInfo->p_KeysMatchTableNew = + (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcdCcNode->h_FmPcd), + (uint32_t)(*size * sizeof(uint8_t) * (p_AdditionalInfo->numOfKeys + 1)), + FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN); + if(!p_AdditionalInfo->p_KeysMatchTableNew) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcdCcNode->h_FmPcd), p_AdditionalInfo->p_AdTableNew); + p_AdditionalInfo->p_AdTableNew = NULL; + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory in MURAM for KEY MATCH table")); + } + IOMemSet32((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0, *size * sizeof(uint8_t) * (p_AdditionalInfo->numOfKeys + 1)); + + p_AdditionalInfo->p_AdTableOld = p_FmPcdCcNode->h_AdTable; + p_AdditionalInfo->p_KeysMatchTableOld = p_FmPcdCcNode->h_KeysMatchTable; + + return E_OK; +} + +static t_Error BuildNewNodeAddOrMdfyKeyAndNextEngine(t_Handle h_FmPcd ,t_FmPcdCcNode *p_FmPcdCcNode, uint8_t keyIndex, t_FmPcdCcKeyParams *p_KeyParams,t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo, bool add) +{ + t_Error err = E_OK; + t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; + t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; + int size; + int i = 0, j = 0; + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t requiredAction = 0; + bool prvLclMask; + t_CcNodeInformation *p_CcNodeInformation; + t_List *p_Pos; + + /*check that new NIA is legal*/ + err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + prvLclMask = p_FmPcdCcNode->lclMask; + + /*check that new key is not require update of localMask*/ + err = UpdateGblMask(p_FmPcdCcNode, + p_FmPcdCcNode->ccKeySizeAccExtraction, + p_KeyParams->p_Mask); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*update internal data structure for next engine per index (index - key)*/ + memcpy(&p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].nextEngineParams,&p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); + + /*update numOfKeys*/ + if(add) + p_AdditionalInfo->numOfKeys = (uint8_t)(p_FmPcdCcNode->numOfKeys + 1); + else + p_AdditionalInfo->numOfKeys = (uint8_t)p_FmPcdCcNode->numOfKeys; + /*function which build in the memory new KeyTbl, AdTbl*/ + err = BuildNewNodeCommonPart(p_FmPcdCcNode, &size, p_AdditionalInfo); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + +#ifdef FM_PCD_CC_MANIP + /*check that manip is legal and what requiredAction is necessary for this manip*/ + if(p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(&p_KeyParams->ccNextEngineParams,&requiredAction); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + } +#endif /* FM_PCD_CC_MANIP */ + + p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].requiredAction = requiredAction; + + p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].requiredAction |= UPDATE_CC_WITH_TREE; + + + /*update new Ad and new Key Table according to new requirement*/ + i = 0; + for(j = 0; j < p_AdditionalInfo->numOfKeys; j++) + { + p_AdTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); + if(j == keyIndex) + { + NextStepAd(p_AdTableNewTmp,&p_KeyParams->ccNextEngineParams, p_FmPcd); + p_KeysMatchTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size * sizeof(uint8_t)); + Mem2IOCpy32((void*)p_KeysMatchTableNewTmp, p_KeyParams->p_Key, p_FmPcdCcNode->userSizeOfExtraction); + if(p_FmPcdCcNode->lclMask) + { + if(p_KeyParams->p_Mask) + Mem2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), p_KeyParams->p_Mask, p_FmPcdCcNode->userSizeOfExtraction); + else if (p_FmPcdCcNode->ccKeySizeAccExtraction > 4) + IOMemSet32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), 0xff, p_FmPcdCcNode->userSizeOfExtraction); + else + Mem2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction),p_FmPcdCcNode->p_GlblMask, p_FmPcdCcNode->userSizeOfExtraction); + } + if(!add) + i++; + } + else + { + p_AdTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE); + IO2IOCpy32(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + p_KeysMatchTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size * sizeof(uint8_t)); + p_KeysMatchTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, i*size * sizeof(uint8_t)); + + if(p_FmPcdCcNode->lclMask) + { + if(prvLclMask) + IO2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), + PTR_MOVE(p_KeysMatchTableOldTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), + p_FmPcdCcNode->ccKeySizeAccExtraction); + else + { + p_KeysMatchTableOldTmp = PTR_MOVE(p_FmPcdCcNode->h_KeysMatchTable, i*p_FmPcdCcNode->ccKeySizeAccExtraction*sizeof(uint8_t)); + + if (p_FmPcdCcNode->ccKeySizeAccExtraction > 4) + IOMemSet32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), 0xff, p_FmPcdCcNode->userSizeOfExtraction); + else + IO2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), p_FmPcdCcNode->p_GlblMask, p_FmPcdCcNode->userSizeOfExtraction); + } + } + IO2IOCpy32(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, p_FmPcdCcNode->ccKeySizeAccExtraction); + i++; + } + } + + p_AdTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE); + IO2IOCpy32(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + + if(!LIST_IsEmpty(&p_FmPcdCcNode->ccTreesLst)) + { + LIST_FOR_EACH(p_Pos, &p_FmPcdCcNode->ccTreesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInformation->h_CcNode); + /*update the manipulation which has to be updated from parameters of the port*/ + /*it's has to be updated with restrictions defined in the function*/ + err = FmPcdCcSetRequiredAction(p_FmPcdCcNode->h_FmPcd, + p_FmPcdCcNode->shadowAction | p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].requiredAction, + &p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex], + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + 1, + p_CcNodeInformation->h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + err = CcUpdateParam(p_FmPcdCcNode->h_FmPcd, + NULL, + &p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex], + 1, + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + TRUE, + p_CcNodeInformation->index, + p_CcNodeInformation->h_CcNode, + TRUE); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + } + + if(p_FmPcdCcNode->lclMask) + memset(p_FmPcdCcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + + + if(p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForAdd = p_KeyParams->ccNextEngineParams.params.ccParams.h_CcNode; + + if(!add) + { + if(p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.params.ccParams.h_CcNode; +#ifdef FM_PCD_CC_MANIP + if(p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip; +#endif /* FM_PCD_CC_MANIP */ + } + + return E_OK; +} + +static t_Error BuildNewNodeRemoveKey(t_FmPcdCcNode *p_FmPcdCcNode, uint8_t keyIndex, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + int i = 0, j = 0; + t_Handle p_AdTableNewTmp,p_KeysMatchTableNewTmp; + t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; + int size; + t_Error err = E_OK; + + /*save new numOfKeys*/ + p_AdditionalInfo->numOfKeys = (uint16_t)(p_FmPcdCcNode->numOfKeys - 1); + + /*function which allocates in the memory new KeyTbl, AdTbl*/ + err = BuildNewNodeCommonPart(p_FmPcdCcNode, &size, p_AdditionalInfo); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*update new Ad and new Key Table according to new requirement*/ + for(i = 0, j = 0; j < p_FmPcdCcNode->numOfKeys; i++, j++) + { + if(j == keyIndex) + { + p_AdTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j*FM_PCD_CC_AD_ENTRY_SIZE); + j++; + } + if(j == p_FmPcdCcNode->numOfKeys) + break; + p_AdTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i*FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j*FM_PCD_CC_AD_ENTRY_SIZE); + IO2IOCpy32(p_AdTableNewTmp,p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + p_KeysMatchTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, j*size * sizeof(uint8_t)); + p_KeysMatchTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, i*size * sizeof(uint8_t)); + IO2IOCpy32(p_KeysMatchTableNewTmp,p_KeysMatchTableOldTmp, size * sizeof(uint8_t)); + } + + p_AdTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i*FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j*FM_PCD_CC_AD_ENTRY_SIZE); + IO2IOCpy32(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + if(p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.params.ccParams.h_CcNode; +#ifdef FM_PCD_CC_MANIP + if(p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip; +#endif /* FM_PCD_CC_MANIP */ + + return E_OK; +} + +static t_Error BuildNewNodeModifyKey(t_FmPcdCcNode *p_FmPcdCcNode, uint8_t keyIndex, uint8_t *p_Key, uint8_t *p_Mask,t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + t_Error err = E_OK; + t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; + t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; + int size; + int i = 0, j = 0; + bool prvLclMask; + + p_AdditionalInfo->numOfKeys = p_FmPcdCcNode->numOfKeys; + + prvLclMask = p_FmPcdCcNode->lclMask; + + /*check that new key is not require update of localMask*/ + err = UpdateGblMask(p_FmPcdCcNode, + p_FmPcdCcNode->sizeOfExtraction, + p_Mask); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*function which build in the memory new KeyTbl, AdTbl*/ + err = BuildNewNodeCommonPart(p_FmPcdCcNode, &size, p_AdditionalInfo); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*fill the New AdTable and New KeyTable*/ + for(j = 0, i = 0; j < p_AdditionalInfo->numOfKeys; j++, i++) + { + p_AdTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE); + IO2IOCpy32(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + if(j == keyIndex) + { + p_KeysMatchTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size * sizeof(uint8_t)); + Mem2IOCpy32(p_KeysMatchTableNewTmp, p_Key, p_FmPcdCcNode->userSizeOfExtraction); + if(p_FmPcdCcNode->lclMask) + { + if(p_Mask) + Mem2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), p_Mask, p_FmPcdCcNode->userSizeOfExtraction); + else if (p_FmPcdCcNode->ccKeySizeAccExtraction > 4) + IOMemSet32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), 0xff, p_FmPcdCcNode->userSizeOfExtraction); + else + Mem2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction),p_FmPcdCcNode->p_GlblMask, p_FmPcdCcNode->userSizeOfExtraction); + } + } + else + { + p_KeysMatchTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size * sizeof(uint8_t)); + p_KeysMatchTableOldTmp = PTR_MOVE(p_FmPcdCcNode->h_KeysMatchTable, i*size * sizeof(uint8_t)); + if (p_FmPcdCcNode->lclMask) + { + if(prvLclMask) + IO2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), + PTR_MOVE(p_KeysMatchTableOldTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), + p_FmPcdCcNode->userSizeOfExtraction); + else + { + p_KeysMatchTableOldTmp = PTR_MOVE(p_FmPcdCcNode->h_KeysMatchTable, i*p_FmPcdCcNode->ccKeySizeAccExtraction * sizeof(uint8_t)); + + if (p_FmPcdCcNode->ccKeySizeAccExtraction > 4) + IOMemSet32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), 0xff, p_FmPcdCcNode->userSizeOfExtraction); + else + IO2IOCpy32(PTR_MOVE(p_KeysMatchTableNewTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), p_FmPcdCcNode->p_GlblMask, p_FmPcdCcNode->userSizeOfExtraction); + } + } + IO2IOCpy32((void*)p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, p_FmPcdCcNode->ccKeySizeAccExtraction); + } + } + + p_AdTableNewTmp = PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = PTR_MOVE(p_FmPcdCcNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); + IO2IOCpy32(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + return E_OK; +} + +static t_Error BuildNewNodeModifyNextEngine(t_Handle h_FmPcd ,t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex,t_FmPcdCcNextEngineParams *p_CcNextEngineParams, t_List *h_OldLst, t_List *h_NewLst,t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + + t_Error err = E_OK; + uint32_t requiredAction = 0; + t_List *p_Pos; + t_CcNodeInformation *p_CcNodeInformation, ccNodeInfo; + t_Handle p_Ad; + t_FmPcdCcNode *p_FmPcdCcNode1 = NULL; + t_FmPcdCcTree *p_FmPcdCcTree = NULL; + + ASSERT_COND(p_CcNextEngineParams); + /*check that new NIA is legal*/ + err = ValidateNextEngineParams(h_FmPcd, p_CcNextEngineParams); + if(err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*update internal data structure for next engine per index (index - key)*/ + memcpy(&p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].nextEngineParams,p_CcNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); + +#ifdef FM_PCD_CC_MANIP + /*check that manip is legal and what requiredAction is necessary for this manip*/ + if(p_CcNextEngineParams->h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(p_CcNextEngineParams,&requiredAction); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + } +#endif /* FM_PCD_CC_MANIP */ + + if(!p_AdditionalInfo->tree) + { + p_FmPcdCcNode1 = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree; + p_Ad = p_FmPcdCcNode1->h_AdTable; + if(p_FmPcdCcNode1->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = p_FmPcdCcNode1->nextEngineAndRequiredAction[keyIndex].nextEngineParams.params.ccParams.h_CcNode; +#ifdef FM_PCD_CC_MANIP + if(p_FmPcdCcNode1->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = p_FmPcdCcNode1->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip; +#endif /* FM_PCD_CC_MANIP */ + } + else + { + p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree; + p_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + if(p_FmPcdCcTree->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = p_FmPcdCcTree->nextEngineAndRequiredAction[keyIndex].nextEngineParams.params.ccParams.h_CcNode; +#ifdef FM_PCD_CC_MANIP + if(p_FmPcdCcTree->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = p_FmPcdCcTree->nextEngineAndRequiredAction[keyIndex].nextEngineParams.h_Manip; +#endif /* FM_PCD_CC_MANIP */ + } + ASSERT_COND(p_Ad); + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = PTR_MOVE(p_Ad, keyIndex * FM_PCD_CC_AD_ENTRY_SIZE); + EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo); + + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + p_Ad = (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(h_FmPcd), + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + + if(!p_Ad) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation in MURAM FAILED")); + + IOMemSet32((uint8_t *)p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + if(p_CcNextEngineParams) + NextStepAd(p_Ad,p_CcNextEngineParams, h_FmPcd); + ccNodeInfo.h_CcNode = p_Ad; + EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo); + + p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].requiredAction = requiredAction; + + p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].requiredAction |= UPDATE_CC_WITH_TREE; + + if(!p_AdditionalInfo->tree) + { + ASSERT_COND(p_FmPcdCcNode1); + if(!LIST_IsEmpty(&p_FmPcdCcNode1->ccTreesLst)) + { + LIST_FOR_EACH(p_Pos, &p_FmPcdCcNode1->ccTreesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInformation->h_CcNode); + /*update the manipulation which has to be updated from parameters of the port*/ + /*it's has to be updated with restrictions defined in the function*/ + err = FmPcdCcSetRequiredAction(p_FmPcdCcNode1->h_FmPcd, p_FmPcdCcNode1->shadowAction | p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].requiredAction, &p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex], + p_Ad, 1, p_CcNodeInformation->h_CcNode); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + err = CcUpdateParam(p_FmPcdCcNode1->h_FmPcd, NULL, &p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex],1, p_Ad, TRUE, p_CcNodeInformation->index, p_CcNodeInformation->h_CcNode, TRUE); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + } + } + else + { + ASSERT_COND(p_FmPcdCcTree); + err = FmPcdCcSetRequiredAction(h_FmPcd, p_FmPcdCcTree->requiredAction | p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex].requiredAction, &p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex], + p_Ad, 1, (t_Handle)p_FmPcdCcTree); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + err = CcUpdateParam(h_FmPcd, NULL, &p_AdditionalInfo->nextEngineAndRequiredAction[keyIndex],1, p_Ad, TRUE, 0, (t_Handle)p_FmPcdCcTree, TRUE); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + if(p_CcNextEngineParams->nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForAdd = p_CcNextEngineParams->params.ccParams.h_CcNode; + return E_OK; +} + +static t_Handle BuildNewAd(t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams, + t_FmPcdCcNode *p_FmPcdCcNode, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + + t_Handle p_Ad; + t_FmPcdCcNode *p_FmPcdCcNodeTmp; + + p_Ad = (t_Handle)FM_MURAM_AllocMem(((t_FmPcd *)(p_FmPcdCcNode->h_FmPcd))->h_FmMuram, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if(!p_Ad) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM for AD")); + return NULL; + } + IOMemSet32(p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + p_FmPcdCcNodeTmp = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode)); + if(!p_FmPcdCcNodeTmp) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcNodeTmp")); + return NULL; + } + memset(p_FmPcdCcNodeTmp, 0, sizeof(t_FmPcdCcNode)); + + p_FmPcdCcNodeTmp->numOfKeys = p_FmPcdModifyCcKeyAdditionalParams->numOfKeys; + p_FmPcdCcNodeTmp->h_KeysMatchTable = p_FmPcdModifyCcKeyAdditionalParams->p_KeysMatchTableNew; + p_FmPcdCcNodeTmp->h_AdTable = p_FmPcdModifyCcKeyAdditionalParams->p_AdTableNew; + + p_FmPcdCcNodeTmp->lclMask = p_FmPcdCcNode->lclMask; + p_FmPcdCcNodeTmp->parseCode = p_FmPcdCcNode->parseCode; + p_FmPcdCcNodeTmp->offset = p_FmPcdCcNode->offset; + p_FmPcdCcNodeTmp->prsArrayOffset = p_FmPcdCcNode->prsArrayOffset; + p_FmPcdCcNodeTmp->ctrlFlow = p_FmPcdCcNode->ctrlFlow; + p_FmPcdCcNodeTmp->ccKeySizeAccExtraction = p_FmPcdCcNode->ccKeySizeAccExtraction; + p_FmPcdCcNodeTmp->sizeOfExtraction = p_FmPcdCcNode->sizeOfExtraction; + p_FmPcdCcNodeTmp->glblMaskSize = p_FmPcdCcNode->glblMaskSize; + p_FmPcdCcNodeTmp->p_GlblMask = p_FmPcdCcNode->p_GlblMask; + + if (p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC) + FillAdOfTypeContLookup(p_Ad, + p_FmPcdCcNode->h_FmPcd, + p_FmPcdCcNodeTmp, +#ifdef FM_PCD_CC_MANIP + p_FmPcdCcNextEngineParams->h_Manip +#else + NULL +#endif /* FM_PCD_CC_MANIP */ + ); + + XX_Free(p_FmPcdCcNodeTmp); + + return p_Ad; +} + +static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(t_FmPcdCcNode *p_CrntMdfNode ,t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams, t_List *h_OldLst, t_List *h_NewLst) +{ + t_CcNodeInformation *p_CcNodeInformation; + t_FmPcdCcNode *p_NodePtrOnCurrentMdfNode = NULL; + t_List *p_Pos; + int i = 0; + t_Handle p_AdTablePtOnCrntCurrentMdfNode, p_AdTableNewModified; + t_CcNodeInformation ccNodeInfo; + + LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccPrevNodesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + p_NodePtrOnCurrentMdfNode = (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode; + ASSERT_COND(p_NodePtrOnCurrentMdfNode); + /*search in the prev node which exact index points on this current modified node for getting AD */ + for(i = 0; i < p_NodePtrOnCurrentMdfNode->numOfKeys + 1; i++) + { + if(p_NodePtrOnCurrentMdfNode->nextEngineAndRequiredAction[i].nextEngineParams.nextEngine == e_FM_PCD_CC) + { + if(p_NodePtrOnCurrentMdfNode->nextEngineAndRequiredAction[i].nextEngineParams.params.ccParams.h_CcNode == (t_Handle)p_CrntMdfNode) + { + p_AdTablePtOnCrntCurrentMdfNode = PTR_MOVE(p_NodePtrOnCurrentMdfNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode; + EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo); + + p_AdTableNewModified = BuildNewAd(p_FmPcdModifyCcKeyAdditionalParams, p_CrntMdfNode, &p_NodePtrOnCurrentMdfNode->nextEngineAndRequiredAction[i].nextEngineParams); + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTableNewModified; + EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo); + } + } + } + ASSERT_COND(i != p_NodePtrOnCurrentMdfNode->numOfKeys); + } +} + +static void UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(t_FmPcdCcNode *p_CrntMdfNode ,t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams, t_List *h_OldLst, t_List *h_NewLst) +{ + t_CcNodeInformation *p_CcNodeInformation; + t_FmPcdCcTree *p_TreePtrOnCurrentMdfNode = NULL; + t_List *p_Pos; + int i = 0; + t_Handle p_AdTableTmp, p_AdTableTmp1; + t_CcNodeInformation ccNodeInfo; + + LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccTreeIdLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + p_TreePtrOnCurrentMdfNode = (t_FmPcdCcTree *)p_CcNodeInformation->h_CcNode; + + ASSERT_COND(p_TreePtrOnCurrentMdfNode); + /*search in the trees which exact index points on this current modified node for getting AD + */ + for(i = 0; i < p_TreePtrOnCurrentMdfNode->numOfEntries; i++) + { + if(p_TreePtrOnCurrentMdfNode->nextEngineAndRequiredAction[i].nextEngineParams.nextEngine == e_FM_PCD_CC) + { + if(p_TreePtrOnCurrentMdfNode->nextEngineAndRequiredAction[i].nextEngineParams.params.ccParams.h_CcNode == (t_Handle)p_CrntMdfNode) + { + p_AdTableTmp = UINT_TO_PTR(p_TreePtrOnCurrentMdfNode->ccTreeBaseAddr + i*FM_PCD_CC_AD_ENTRY_SIZE); + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTableTmp; + EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo); + + p_AdTableTmp1 = BuildNewAd(p_FmPcdModifyCcKeyAdditionalParams, p_CrntMdfNode, &p_TreePtrOnCurrentMdfNode->nextEngineAndRequiredAction[i].nextEngineParams); + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTableTmp1; + EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo); + } + } + } + ASSERT_COND(i == p_TreePtrOnCurrentMdfNode->numOfEntries); + } +} + +static t_Error ModifyKeyCommonPart1(t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex, t_Handle *h_Params, e_ModifyState modifyState, bool check, bool tree) +{ + t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams; + int i = 0, j = 0; + bool wasUpdate = FALSE; + t_FmPcdCcNode *p_FmPcdCcNode = NULL; + t_FmPcdCcTree *p_FmPcdCcTree; + uint16_t numOfKeys; + t_FmPcdCcNextEngineAndRequiredActionParams *p_nextEngineAndRequiredAction = NULL; + + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcNodeOrTree,E_INVALID_HANDLE); + + p_nextEngineAndRequiredAction = XX_Malloc(FM_PCD_MAX_NUM_OF_KEYS * sizeof(*p_nextEngineAndRequiredAction)); + if(!p_nextEngineAndRequiredAction) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("failed to allocate memory for p_nextEngineAndRequiredAction")); + + memset(p_nextEngineAndRequiredAction, 0, FM_PCD_MAX_NUM_OF_KEYS * sizeof(*p_nextEngineAndRequiredAction)); + + if(!tree) + { + p_FmPcdCcNode = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree; + numOfKeys = p_FmPcdCcNode->numOfKeys; + + /*node has to be pointed by another node or tree*/ + if (!LIST_NumOfObjs(&p_FmPcdCcNode->ccPrevNodesLst) && + !LIST_NumOfObjs(&p_FmPcdCcNode->ccTreeIdLst)) + { + XX_Free(p_nextEngineAndRequiredAction); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("node has to be pointed by node or tree")); + } + + if(!LIST_NumOfObjs(&p_FmPcdCcNode->ccTreesLst) || + (LIST_NumOfObjs(&p_FmPcdCcNode->ccTreesLst) != 1)) + { + XX_Free(p_nextEngineAndRequiredAction); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("node has to be belonging to some tree and only to one tree")); + } + + memcpy(p_nextEngineAndRequiredAction, + p_FmPcdCcNode->nextEngineAndRequiredAction, + FM_PCD_MAX_NUM_OF_KEYS * sizeof(t_FmPcdCcNextEngineAndRequiredActionParams)); + + if(check) + { + if((p_FmPcdCcNode->parseCode == CC_PC_FF_IPV4TTL) || + (p_FmPcdCcNode->parseCode == CC_PC_FF_IPV6HOP_LIMIT) || + (p_FmPcdCcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)) + { + XX_Free(p_nextEngineAndRequiredAction); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_FF_IPV4TTL or CC_PC_FF_IPV6HOP_LIMIT can not be used for addKey, removeKey, modifyKey")); + } + } + } + else + { + p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree; + numOfKeys = p_FmPcdCcTree->numOfEntries; + memcpy(p_nextEngineAndRequiredAction, + p_FmPcdCcTree->nextEngineAndRequiredAction, + FM_PCD_MAX_NUM_OF_KEYS * sizeof(t_FmPcdCcNextEngineAndRequiredActionParams)); + } + + p_FmPcdModifyCcKeyAdditionalParams = + (t_FmPcdModifyCcKeyAdditionalParams *)XX_Malloc(sizeof(t_FmPcdModifyCcKeyAdditionalParams)); + if(!p_FmPcdModifyCcKeyAdditionalParams) + { + XX_Free(p_nextEngineAndRequiredAction); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of internal data structure FAILED")); + } + memset(p_FmPcdModifyCcKeyAdditionalParams, 0, sizeof(t_FmPcdModifyCcKeyAdditionalParams)); + + p_FmPcdModifyCcKeyAdditionalParams->h_CurrentNode = h_FmPcdCcNodeOrTree; + p_FmPcdModifyCcKeyAdditionalParams->keyIndex = keyIndex; + + while(i < numOfKeys) + { + if((j == keyIndex) && !wasUpdate) + { + if(modifyState == e_MODIFY_STATE_ADD) + j++; + else if(modifyState == e_MODIFY_STATE_REMOVE) + i++; + wasUpdate = TRUE; + } + else + { + memcpy(&p_FmPcdModifyCcKeyAdditionalParams->nextEngineAndRequiredAction[j], &p_nextEngineAndRequiredAction[i], sizeof(t_FmPcdCcNextEngineAndRequiredActionParams)); + i++; + j++; + } + } + + if (keyIndex == numOfKeys) + { + if (modifyState == e_MODIFY_STATE_ADD) + j++; + else if(modifyState == e_MODIFY_STATE_REMOVE) + i++; + } + + memcpy(&p_FmPcdModifyCcKeyAdditionalParams->nextEngineAndRequiredAction[j], &p_nextEngineAndRequiredAction[numOfKeys], sizeof(t_FmPcdCcNextEngineAndRequiredActionParams)); + + XX_Free(p_nextEngineAndRequiredAction); + *h_Params = p_FmPcdModifyCcKeyAdditionalParams; + + return E_OK; +} + +static t_Error UpdatePtrWhichPointOnCrntMdfNode(t_FmPcdCcNode *p_FmPcdCcNode, t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams ,t_List *h_OldLst, t_List *h_NewLst) +{ + if(!LIST_IsEmpty(&p_FmPcdCcNode->ccPrevNodesLst)) + UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(p_FmPcdCcNode, p_FmPcdModifyCcKeyAdditionalParams, h_OldLst, h_NewLst); + + if(!LIST_IsEmpty(&p_FmPcdCcNode->ccTreeIdLst)) + UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(p_FmPcdCcNode, p_FmPcdModifyCcKeyAdditionalParams, h_OldLst, h_NewLst); + + return E_OK; +} + +static void FmPcdCcUpdateTreeOwner(t_FmPcdCcTree *p_FmPcdCcTree, bool add) +{ + ASSERT_COND(p_FmPcdCcTree); + + if(add) + p_FmPcdCcTree->owners++; + else + { + ASSERT_COND(p_FmPcdCcTree->owners); + p_FmPcdCcTree->owners--; + } +} + +#ifdef FM_PCD_CC_MANIP +static t_Error CheckAndSetManipParamsWithCcNodeParams(t_FmPcdCcNode *p_FmPcdCcNode) +{ + t_Error err = E_OK; + int i = 0; + + for(i = 0; i < p_FmPcdCcNode->numOfKeys; i++) + { + if(p_FmPcdCcNode->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsWithCcNodeParams(p_FmPcdCcNode->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip, (t_Handle)p_FmPcdCcNode); + if(err) + return err; + } + } + + return err; +} +#endif /* FM_PCD_CC_MANIP */ + +static t_Error CcUpdateParams(t_Handle h_FmPcd, + t_Handle h_FmPort, + t_Handle h_FmTree, + bool validate) +{ + t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *) h_FmTree; + + return CcUpdateParam(h_FmPcd, + h_FmPort, + p_CcTree->nextEngineAndRequiredAction, + p_CcTree->numOfEntries, + UINT_TO_PTR(p_CcTree->ccTreeBaseAddr), + validate, + 0, + h_FmTree, + FALSE); +} + +static t_Error CheckParams(t_Handle h_FmPcd, + t_FmPcdCcNodeParams *p_CcNodeParam, + t_FmPcdCcNode *p_FmPcdCcNode, + bool *isKeyTblAlloc) +{ + int tmp = 0; + t_FmPcdCcKeyParams *p_KeyParams; + t_Error err; + uint32_t requiredAction = 0; + + err = ValidateNextEngineParams(h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss); + if(err) + RETURN_ERROR(MAJOR, err, ("For this node MissNextEngineParams are not valid")); + +#ifdef FM_PCD_CC_MANIP + if(p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(&p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, &requiredAction); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } +#endif /* FM_PCD_CC_MANIP */ + + memcpy(&p_FmPcdCcNode->nextEngineAndRequiredAction[p_FmPcdCcNode->numOfKeys].nextEngineParams,&p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, sizeof(t_FmPcdCcNextEngineParams)); + p_FmPcdCcNode->nextEngineAndRequiredAction[p_FmPcdCcNode->numOfKeys].requiredAction = requiredAction; + + for(tmp = 0 ; tmp < p_FmPcdCcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + + if(!p_KeyParams->p_Key) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_Key is not initialized")); + + + err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + err = UpdateGblMask(p_FmPcdCcNode, + p_CcNodeParam->keysParams.keySize, + p_KeyParams->p_Mask); + +#ifdef FM_PCD_CC_MANIP + if(p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(&p_KeyParams->ccNextEngineParams, &requiredAction); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } +#endif /* FM_PCD_CC_MANIP */ + + memcpy(&p_FmPcdCcNode->nextEngineAndRequiredAction[tmp],&p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); + p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].requiredAction = requiredAction; + } + + *isKeyTblAlloc = TRUE; + return E_OK; +} + +static t_Error Ipv4TtlOrIpv6HopLimiCheckParams( t_Handle h_FmPcd, + t_FmPcdCcNodeParams *p_CcNodeParam, t_FmPcdCcNode *p_FmPcdCcNode, + bool *isKeyTblAlloc) +{ + int tmp = 0; + t_FmPcdCcKeyParams *p_KeyParams; + t_Error err; + uint8_t key = 0x01; + uint32_t requiredAction = 0; + + if(p_FmPcdCcNode->numOfKeys != 1 ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for IPV4TTL and IPV6_HOP_LIMIT has to be only 1 key - TTL = 1, otherwise it's Miss")); + + err = ValidateNextEngineParams(h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss); + if(err) + RETURN_ERROR(MAJOR, err, ("For this node MissNextEngineParams are not valid")); + +#ifdef FM_PCD_CC_MANIP + if(p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(&p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, &requiredAction); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } +#endif /* FM_PCD_CC_MANIP */ + + memcpy(&p_FmPcdCcNode->nextEngineAndRequiredAction[p_FmPcdCcNode->numOfKeys].nextEngineParams, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, sizeof(t_FmPcdCcNextEngineParams)); + p_FmPcdCcNode->nextEngineAndRequiredAction[p_FmPcdCcNode->numOfKeys].requiredAction = requiredAction; + + for(tmp = 0 ; tmp < p_FmPcdCcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + if(p_KeyParams->p_Mask) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("If node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Mask can not be initialized")); + if(memcmp(p_KeyParams->p_Key, &key, 1) != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("If node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Key has to be 1")); + err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + +#ifdef FM_PCD_CC_MANIP + if(p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(&p_KeyParams->ccNextEngineParams, &requiredAction); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } +#endif /* FM_PCD_CC_MANIP */ + + memcpy(&p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].nextEngineParams, &p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); + p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].requiredAction = requiredAction; + } + + *isKeyTblAlloc = FALSE; + return E_OK; +} + +static t_Error IcHashIndexedCheckParams(t_Handle h_FmPcd, + t_FmPcdCcNodeParams *p_CcNodeParam, + t_FmPcdCcNode *p_FmPcdCcNode, + /*uint16_t *ccInfo,*/ + /*t_List *ccNextDifferentNodesLst,*/ + bool *isKeyTblAlloc) +{ + int tmp = 0, countOnes = 0; + t_FmPcdCcKeyParams *p_KeyParams; + t_Error err; + uint16_t glblMask = p_CcNodeParam->extractCcParams.extractNonHdr.icIndxMask; + uint16_t countMask = (uint16_t)(glblMask >> 4); +#ifdef FM_PCD_CC_MANIP + uint32_t requiredAction; +#endif /* FM_PCD_CC_MANIP */ + + if (glblMask & 0x000f) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("icIndxMask has to be with last nibble 0")); + + while (countMask) + { + countOnes++; + countMask=(uint16_t)(countMask>>1); + } + + if (!POWER_OF_2(p_FmPcdCcNode->numOfKeys)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("For Node of the type INDEXED numOfKeys has to be powerOfTwo")); + if (p_FmPcdCcNode->numOfKeys != ((uint32_t)1<keysParams.ccNextEngineParamsForMiss); + if(GET_ERROR_TYPE(err)!= E_NOT_SUPPORTED) + RETURN_ERROR(MAJOR, err, ("MissNextEngineParams for the node of the type IC_INDEX_HASH has to be UnInitialized")); + + for(tmp = 0 ; tmp < p_FmPcdCcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + if(p_KeyParams->p_Mask || p_KeyParams->p_Key) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("For Node of the type IC_HASH_INDEXED p_Key or p_Mask has to be NULL")); + + if((glblMask & (tmp * 16)) == (tmp * 16)) + { + err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams); + if(err) + RETURN_ERROR(MAJOR, err, ("This index has to be initialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask ")); + +#ifdef FM_PCD_CC_MANIP + if(p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(&p_KeyParams->ccNextEngineParams, &requiredAction); + if(err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].requiredAction = requiredAction; +#endif /* FM_PCD_CC_MANIP */ + + memcpy(&p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].nextEngineParams,&p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); + } + else + { + err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams); + if(GET_ERROR_TYPE(err)!= E_NOT_SUPPORTED) + RETURN_ERROR(MAJOR, err, ("This index has to be UnInitialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask")); + } + } + *isKeyTblAlloc = FALSE; + memcpy(PTR_MOVE(p_FmPcdCcNode->p_GlblMask, 2), &glblMask, 2); + + return E_OK; +} + +t_Error FmPcdCcModifyNextEngineParamTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + t_Error err = E_OK; + uint16_t keyIndex; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + + SANITY_CHECK_RETURN_ERROR((grpId <= 7),E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree,E_INVALID_VALUE); + + if(grpId >= p_FmPcdCcTree->numOfGrps) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("grpId you asked > numOfGroup of relevant tree")); + + if(index >= p_FmPcdCcTree->fmPcdGroupParam[grpId].numOfEntriesInGroup) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("index > numOfEntriesInGroup")); + + keyIndex = (uint16_t)(p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry + index); + + err = ModifyKeyCommonPart1(h_FmPcdCcTree, keyIndex, h_AdditionalParams, e_MODIFY_STATE_CHANGE, TRUE, TRUE); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_AdditionalParams; + p_ModifyKeyParams->tree = TRUE; + + err = BuildNewNodeModifyNextEngine (h_FmPcd, h_FmPcdCcTree, keyIndex,p_FmPcdCcNextEngineParams, h_OldLst, h_NewLst, p_ModifyKeyParams); + if(err) + { + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + return E_OK; + +} + +t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint8_t keyIndex, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams) +{ + + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *) h_FmPcdCcNode; + t_Error err = E_OK; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + + if(keyIndex >= p_FmPcdCcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("impossible to remove key when numOfKeys <= keyIndex")); + + if(!p_FmPcdCcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("keyIndex you asked > numOfKeys of relevant node that was initialized")); + + if(p_FmPcdCcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("handler to FmPcd is diferent from one which was assigned to the node in the Init time")); + + err = ModifyKeyCommonPart1(p_FmPcdCcNode, keyIndex, h_AdditionalParams, e_MODIFY_STATE_REMOVE, TRUE, FALSE); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_AdditionalParams; + err = BuildNewNodeRemoveKey (p_FmPcdCcNode, keyIndex, p_ModifyKeyParams); + if(err) + { + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_FmPcdCcNode, p_ModifyKeyParams, h_OldLst, h_NewLst); + if(err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; + +} + +t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint8_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, t_List *h_OldLst, t_List *h_NewLst,t_Handle *h_AdditionalParams) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_Error err = E_OK; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + + if(keyIndex >= p_FmPcdCcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("keyIndex > previousely cleared last index + 1")); + + if((p_FmPcdCcNode->numOfKeys + 1) > FM_PCD_MAX_NUM_OF_CC_NODES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfKeys with new key can not be larger than 255")); + + if(keySize != p_FmPcdCcNode->userSizeOfExtraction) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("size for ModifyKey has to be the same as defined in SetNode")); + + if(p_FmPcdCcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("handler to FmPcd is diferent from one which was assigned to the node in the Init time")); + + err = ModifyKeyCommonPart1(p_FmPcdCcNode, keyIndex, h_AdditionalParams, e_MODIFY_STATE_CHANGE, TRUE, FALSE); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_AdditionalParams; + + err = BuildNewNodeModifyKey (p_FmPcdCcNode, keyIndex, p_Key, p_Mask, p_ModifyKeyParams); + if(err) + { + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_FmPcdCcNode, p_ModifyKeyParams, h_OldLst, h_NewLst); + if(err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + return E_OK; +} + + +t_Error FmPcdCcModiyNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, uint8_t keyIndex,t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,t_List *h_OldPointer, t_List *h_NewPointer,t_Handle *h_AdditionalParams) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_Error err = E_OK; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd,E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNode,E_INVALID_HANDLE); + + if(keyIndex >= p_FmPcdCcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("keyIndex > previousely cleared last index + 1")); + + if((p_FmPcdCcNode->numOfKeys + 1) > FM_PCD_MAX_NUM_OF_CC_NODES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfKeys with new key can not be larger than 255")); + + err = ModifyKeyCommonPart1(p_FmPcdCcNode, keyIndex, h_AdditionalParams, e_MODIFY_STATE_CHANGE, FALSE, FALSE); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_AdditionalParams; + + err = BuildNewNodeModifyNextEngine (h_FmPcd, p_FmPcdCcNode, keyIndex,p_FmPcdCcNextEngineParams, h_OldPointer, h_NewPointer, p_ModifyKeyParams); + if(err) + { + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + return E_OK; +} + +t_Error FmPcdCcModifyMissNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,t_List *h_OldPointer, t_List *h_NewPointer,t_Handle *h_AdditionalParams) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_Error err = E_OK; + uint16_t keyIndex; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNode,E_INVALID_VALUE); + + keyIndex = p_FmPcdCcNode->numOfKeys; + + err = ModifyKeyCommonPart1(p_FmPcdCcNode, keyIndex, h_AdditionalParams, e_MODIFY_STATE_CHANGE, TRUE, FALSE); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_AdditionalParams; + + err = BuildNewNodeModifyNextEngine (h_FmPcd, p_FmPcdCcNode, keyIndex,p_FmPcdCcNextEngineParams, h_OldPointer, h_NewPointer, p_ModifyKeyParams); + if(err) + { + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; +} + +t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPcdCcKeyParams, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + t_Error err = E_OK; + + if(keyIndex > p_FmPcdCcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("keyIndex > previousely cleared last index + 1")); + + if((p_FmPcdCcNode->numOfKeys + 1) > FM_PCD_MAX_NUM_OF_CC_NODES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfKeys with new key can not be larger than 255")); + + if(keySize != p_FmPcdCcNode->userSizeOfExtraction) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("keySize has to be defined as it was defined in initialization step.")); + + if(p_FmPcdCcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("handler to FmPcd is diferent from one which was assigned to the node in the Init time")); + + err = ModifyKeyCommonPart1(p_FmPcdCcNode, keyIndex, h_AdditionalParams, e_MODIFY_STATE_ADD, TRUE, FALSE); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_AdditionalParams; + err = BuildNewNodeAddOrMdfyKeyAndNextEngine (h_FmPcd, p_FmPcdCcNode, keyIndex, p_FmPcdCcKeyParams, p_ModifyKeyParams, TRUE); + if(err) + { + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_FmPcdCcNode, p_ModifyKeyParams, h_OldLst, h_NewLst); + if(err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; +} + +t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPcdCcKeyParams, t_List *h_OldLst, t_List *h_NewLst, t_Handle *h_AdditionalParams) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + t_Error err = E_OK; + + if(keyIndex > p_FmPcdCcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("keyIndex > previousely cleared last index + 1")); + + if((p_FmPcdCcNode->numOfKeys + 1) > FM_PCD_MAX_NUM_OF_CC_NODES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfKeys with new key can not be larger than 255")); + + if(keySize != p_FmPcdCcNode->userSizeOfExtraction) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("keySize has to be defined as it was defined in initialization step")); + + if(p_FmPcdCcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("handler to FmPcd is diferent from one which was assigned to the node in the Init time")); + + err = ModifyKeyCommonPart1(p_FmPcdCcNode, keyIndex, h_AdditionalParams, e_MODIFY_STATE_CHANGE, TRUE, FALSE); + if(err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_AdditionalParams; + + err = BuildNewNodeAddOrMdfyKeyAndNextEngine (h_FmPcd, p_FmPcdCcNode, keyIndex, p_FmPcdCcKeyParams, p_ModifyKeyParams, FALSE); + if(err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_FmPcdCcNode, p_ModifyKeyParams, h_OldLst, h_NewLst); + if(err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; +} + +t_Error FmPcdCcReleaseModifiedDataStructure(t_Handle h_FmPcd, t_List *h_FmPcdOldPointersLst, t_List *h_FmPcdNewPointersLst, uint16_t numOfGoodChanges, t_Handle *h_Params) +{ + t_FmPcdModifyCcKeyAdditionalParams *p_CcNewModifyAdditionalParams = (t_FmPcdModifyCcKeyAdditionalParams *)*h_Params; + t_List *p_Pos; + t_Error err = E_OK; + t_CcNodeInformation ccNodeInfo, *p_CcNodeInformation; + t_Handle h_Muram; + t_FmPcdCcNode *p_FmPcdCcNextNode; + t_List *p_UpdateLst; + + UNUSED(numOfGoodChanges); + + SANITY_CHECK_RETURN_ERROR(h_FmPcd,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_CcNewModifyAdditionalParams->h_CurrentNode,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdOldPointersLst,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdNewPointersLst,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((numOfGoodChanges == LIST_NumOfObjs(h_FmPcdOldPointersLst)),E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR((numOfGoodChanges == LIST_NumOfObjs(h_FmPcdNewPointersLst)),E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR((LIST_NumOfObjs(h_FmPcdOldPointersLst) == LIST_NumOfObjs(h_FmPcdNewPointersLst)),E_INVALID_STATE); + + /*we don't update subtree of the new node with new tree because it was done in the previose stage*/ + if(p_CcNewModifyAdditionalParams->h_NodeForAdd) + { + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_CcNewModifyAdditionalParams->h_NodeForAdd; + if(!p_CcNewModifyAdditionalParams->tree) + p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst; + else + p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst; + p_CcNodeInformation = FindNodeInfoInReleventLst(p_UpdateLst, p_CcNewModifyAdditionalParams->h_CurrentNode); + if(p_CcNodeInformation) + p_CcNodeInformation->index++; + else + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = (t_Handle)p_CcNewModifyAdditionalParams->h_CurrentNode; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst(p_UpdateLst, &ccNodeInfo); + } + } + + if(p_CcNewModifyAdditionalParams->h_NodeForRmv) + { + + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_CcNewModifyAdditionalParams->h_NodeForRmv; + if(!p_CcNewModifyAdditionalParams->tree) + { + p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst; + LIST_FOR_EACH(p_Pos, &p_FmPcdCcNextNode->ccTreesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInformation->h_CcNode); + err = FmPcdCcSetRequiredAction(h_FmPcd, + UPDATE_CC_WITH_DELETE_TREE, + &((t_FmPcdCcNode *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->nextEngineAndRequiredAction[p_CcNewModifyAdditionalParams->keyIndex], + PTR_MOVE(((t_FmPcdCcNode *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->h_AdTable, p_CcNewModifyAdditionalParams->keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + 1, + p_CcNodeInformation->h_CcNode); + } + } + else + { + p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst; + err = FmPcdCcSetRequiredAction(h_FmPcd, + UPDATE_CC_WITH_DELETE_TREE, + &((t_FmPcdCcTree *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->nextEngineAndRequiredAction[p_CcNewModifyAdditionalParams->keyIndex], + UINT_TO_PTR(((t_FmPcdCcTree *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->ccTreeBaseAddr + p_CcNewModifyAdditionalParams->keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + 1, + p_CcNewModifyAdditionalParams->h_CurrentNode); + } + if(err) + return err; + + /*we remove from the subtree of the removed node tree because it wasn't done in the previose stage*/ + /*update ccPrevNodesLst or ccTreeIdLst of the removed node*/ + /*update of the nodeOwner*/ + p_CcNodeInformation = FindNodeInfoInReleventLst(p_UpdateLst, p_CcNewModifyAdditionalParams->h_CurrentNode); + ASSERT_COND(p_CcNodeInformation); + ASSERT_COND(p_CcNodeInformation->index); + p_CcNodeInformation->index--; + if(p_CcNodeInformation->index == 0) + DequeueNodeInfoFromRelevantLst(p_UpdateLst,p_CcNewModifyAdditionalParams->h_CurrentNode); + ASSERT_COND(LIST_NumOfObjs(&p_FmPcdCcNextNode->ccTreesLst) == 1); + UpdateNodeOwner(p_FmPcdCcNextNode, FALSE); + } + +#ifdef FM_PCD_CC_MANIP + if(p_CcNewModifyAdditionalParams->h_ManipForRmv) + FmPcdManipUpdateOwner(p_CcNewModifyAdditionalParams->h_ManipForRmv, FALSE); +#endif /* FM_PCD_CC_MANIP */ + + h_Muram = FmPcdGetMuramHandle(h_FmPcd); + ASSERT_COND(h_Muram); + + /*we release new AD which was allocated and updated for copy from to actual AD*/ + LIST_FOR_EACH(p_Pos, h_FmPcdNewPointersLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInformation->h_CcNode); + FM_MURAM_FreeMem(h_Muram, p_CcNodeInformation->h_CcNode); + + } + + /*free Old data structure if it has to be freed - new data structure was allocated*/ + if(p_CcNewModifyAdditionalParams->p_AdTableOld) + FM_MURAM_FreeMem(h_Muram,p_CcNewModifyAdditionalParams->p_AdTableOld); + if(p_CcNewModifyAdditionalParams->p_KeysMatchTableOld) + FM_MURAM_FreeMem(h_Muram,p_CcNewModifyAdditionalParams->p_KeysMatchTableOld); + + /*update current modified node with changed fields if it's required*/ + if(!p_CcNewModifyAdditionalParams->tree) + { + if(p_CcNewModifyAdditionalParams->p_AdTableNew) + ((t_FmPcdCcNode *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->h_AdTable = p_CcNewModifyAdditionalParams->p_AdTableNew; + if(p_CcNewModifyAdditionalParams->numOfKeys) + ((t_FmPcdCcNode *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->numOfKeys = p_CcNewModifyAdditionalParams->numOfKeys; + if(p_CcNewModifyAdditionalParams->p_KeysMatchTableNew) + ((t_FmPcdCcNode *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->h_KeysMatchTable = p_CcNewModifyAdditionalParams->p_KeysMatchTableNew; + memcpy(((t_FmPcdCcNode *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->nextEngineAndRequiredAction, &p_CcNewModifyAdditionalParams->nextEngineAndRequiredAction, sizeof(t_FmPcdCcNextEngineAndRequiredActionParams) * (FM_PCD_MAX_NUM_OF_KEYS)); + } + else + memcpy(&((t_FmPcdCcTree *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->nextEngineAndRequiredAction, &p_CcNewModifyAdditionalParams->nextEngineAndRequiredAction, sizeof(t_FmPcdCcNextEngineAndRequiredActionParams) * (((t_FmPcdCcTree *)(p_CcNewModifyAdditionalParams->h_CurrentNode))->numOfEntries)); + + ReleaseLst(h_FmPcdOldPointersLst); + ReleaseLst(h_FmPcdNewPointersLst); + XX_Free(p_CcNewModifyAdditionalParams); + + return E_OK; +} + +uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, t_Handle h_Pointer) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_CcNodeInformation *p_CcNodeInfo; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd,E_INVALID_HANDLE, (uint32_t)ILLEGAL_BASE); + + p_CcNodeInfo = CC_NODE_F_OBJECT(h_Pointer); + return (uint32_t)(XX_VirtToPhys(p_CcNodeInfo->h_CcNode) - p_FmPcd->physicalMuramBase); +} + +t_Error FmPcdCcGetGrpParams(t_Handle h_FmPcdCcTree, uint8_t grpId, uint32_t *p_GrpBits, uint8_t *p_GrpBase) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *) h_FmPcdCcTree; + + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); + + if(grpId >= p_FmPcdCcTree->numOfGrps) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("grpId you asked > numOfGroup of relevant tree")); + *p_GrpBits = p_FmPcdCcTree->fmPcdGroupParam[grpId].totalBitsMask; + *p_GrpBase = p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry; + return E_OK; +} + +t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint32_t *p_Offset, t_Handle h_FmPort) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcTree,E_INVALID_STATE); + + FmPcdCcUpdateTreeOwner(p_FmPcdCcTree, TRUE); + + *p_Offset = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr)) - + p_FmPcd->physicalMuramBase); + + err = CcUpdateParams(h_FmPcd, h_FmPort, h_FmPcdCcTree, TRUE); + + return err; +} + +t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + + UNUSED(h_FmPcd); + + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcTree,E_INVALID_HANDLE); + + FmPcdCcUpdateTreeOwner(p_FmPcdCcTree, FALSE); + + return E_OK; +} + +t_Error FmPcdCcTreeTryLock(t_Handle h_FmPcdCcTree) +{ + if (TRY_LOCK(NULL, &((t_FmPcdCcTree *)h_FmPcdCcTree)->lock)) + return E_OK; + return ERROR_CODE(E_BUSY); +} + +t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_List *p_List) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_List *p_Pos; + t_CcNodeInformation *p_CcNodeInfo, nodeInfo; + t_Error err = E_OK; + + UNUSED(h_FmPcd); + + if(LIST_IsEmpty(&p_FmPcdCcNode->ccTreesLst)) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("asked for more nodes in CC than MAX")) ; + LIST_FOR_EACH(p_Pos, &p_FmPcdCcNode->ccTreesLst) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInfo->h_CcNode); + err = FmPcdCcTreeTryLock(p_CcNodeInfo->h_CcNode); + if(err == E_OK) + { + memset(&nodeInfo, 0, sizeof(t_CcNodeInformation)); + nodeInfo.h_CcNode = p_CcNodeInfo->h_CcNode; + EnqueueNodeInfoToRelevantLst(p_List, &nodeInfo); + } + else + FmPcdCcNodeTreeReleaseLock(p_List); + } + + return err; +} + +t_Handle FM_PCD_CcBuildTree(t_Handle h_FmPcd, t_FmPcdCcTreeParams *p_PcdGroupsParam) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_Error err = E_OK; + int i = 0, j = 0, k = 0; + t_FmPcdCcTree *p_FmPcdCcTree; + uint8_t numOfEntries; + t_Handle p_CcTreeTmp; + t_FmPcdCcGrpParams *p_FmPcdCcGroupParams; + t_FmPcdCcNextEngineAndRequiredActionParams params[16]; + t_NetEnvParams netEnvParams; + uint8_t lastOne = 0; + uint32_t requiredAction = 0; + t_FmPcdCcNode *p_FmPcdCcNextNode; + t_CcNodeInformation ccNodeInfo, *p_CcInformation; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd,E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_PcdGroupsParam,E_INVALID_HANDLE, NULL); + + if (p_PcdGroupsParam->numOfGrps > FM_PCD_MAX_NUM_OF_CC_GROUPS) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfGrps should not exceed %d", FM_PCD_MAX_NUM_OF_CC_GROUPS)); + return NULL; + } + + p_FmPcdCcTree = (t_FmPcdCcTree*)XX_Malloc(sizeof(t_FmPcdCcTree)); + if(!p_FmPcdCcTree) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("PCD tree structure")); + return NULL; + } + memset(p_FmPcdCcTree, 0, sizeof(t_FmPcdCcTree)) ; + memset(params, 0, 16 * sizeof(t_FmPcdCcNextEngineParams)); + + INIT_LIST(&p_FmPcdCcTree->fmPortsLst); + + numOfEntries = 0; + p_FmPcdCcTree->netEnvId = (uint8_t)(PTR_TO_UINT(p_PcdGroupsParam->h_NetEnv)-1); + for(i = 0; i < p_PcdGroupsParam->numOfGrps; i++) + { + p_FmPcdCcGroupParams = &p_PcdGroupsParam->ccGrpParams[i]; + + if (p_FmPcdCcGroupParams->numOfDistinctionUnits > FM_PCD_MAX_NUM_OF_CC_UNITS) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("numOfDistinctionUnits (group %d) should not exceed %d", i, FM_PCD_MAX_NUM_OF_CC_UNITS)); + return NULL; + } + + p_FmPcdCcTree->fmPcdGroupParam[i].baseGroupEntry = numOfEntries; + p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup =(uint8_t)( 0x01 << p_FmPcdCcGroupParams->numOfDistinctionUnits); + numOfEntries += p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; + if(numOfEntries > 16) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfEntries can not be larger than 16")); + return NULL; + } + if(lastOne) + { + if(p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup > lastOne) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, E_CONFLICT, ("numOfEntries per group must be set in descending order")); + return NULL; + } + } + + lastOne = p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; + + netEnvParams.netEnvId = p_FmPcdCcTree->netEnvId; + netEnvParams.numOfDistinctionUnits = p_FmPcdCcGroupParams->numOfDistinctionUnits; + memcpy(netEnvParams.unitIds, &p_FmPcdCcGroupParams->unitIds, (sizeof(uint8_t)) * p_FmPcdCcGroupParams->numOfDistinctionUnits); + err = PcdGetUnitsVector(p_FmPcd, &netEnvParams); + if(err) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + + p_FmPcdCcTree->fmPcdGroupParam[i].totalBitsMask = netEnvParams.vector; + for(j = 0; j < p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; j++) + { + err = ValidateNextEngineParams(h_FmPcd,&p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j]); + if(err) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, err, (NO_MSG)); + return NULL; + } + +#ifdef FM_PCD_CC_MANIP + if(p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j].h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEgine(&p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], &requiredAction); + if(err) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + return NULL; + } + } +#endif /* FM_PCD_CC_MANIP */ + + memcpy(¶ms[k].nextEngineParams, &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], sizeof(t_FmPcdCcNextEngineParams)); + requiredAction |= UPDATE_CC_WITH_TREE; + params[k].requiredAction = requiredAction; + k++; + } + } + + p_FmPcdCcTree->numOfEntries = (uint8_t)k; + p_FmPcdCcTree->numOfGrps = p_PcdGroupsParam->numOfGrps; + p_FmPcdCcTree->ccTreeBaseAddr = + PTR_TO_UINT(FM_MURAM_AllocMem(FmPcdGetMuramHandle(h_FmPcd), + (uint32_t)( k * FM_PCD_CC_AD_ENTRY_SIZE), + FM_PCD_CC_AD_TABLE_ALIGN)); + + if(!p_FmPcdCcTree->ccTreeBaseAddr) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + IOMemSet32(UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr), 0, (uint32_t)(k * FM_PCD_CC_AD_ENTRY_SIZE)); + + p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + + j = 0; + for(i = 0; i < numOfEntries; i++) + { + NextStepAd(p_CcTreeTmp,¶ms[i].nextEngineParams,p_FmPcd); + p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE); + memcpy(&p_FmPcdCcTree->nextEngineAndRequiredAction[i], ¶ms[i], sizeof(t_FmPcdCcNextEngineAndRequiredActionParams)); + if(p_FmPcdCcTree->nextEngineAndRequiredAction[i].nextEngineParams.nextEngine== e_FM_PCD_CC) + { + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_FmPcdCcTree->nextEngineAndRequiredAction[i].nextEngineParams.params.ccParams.h_CcNode; + if(!IsNodeInModifiedState((t_Handle)p_FmPcdCcNextNode)) + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = (t_Handle)p_FmPcdCcTree; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccTreeIdLst, &ccNodeInfo); + UpdateNodeWithModifiedState((t_Handle)p_FmPcdCcNextNode, TRUE); + } + else + { + p_CcInformation = FindNodeInfoInReleventLst(&p_FmPcdCcNextNode->ccTreeIdLst,(t_Handle)p_FmPcdCcTree); + ASSERT_COND(p_CcInformation); + p_CcInformation->index++; + } + } + } + + FmPcdIncNetEnvOwners(h_FmPcd, p_FmPcdCcTree->netEnvId); + p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + + for(i = 0; i < p_FmPcdCcTree->numOfEntries ; i++) + { + if(p_FmPcdCcTree->nextEngineAndRequiredAction[i].nextEngineParams.nextEngine == e_FM_PCD_CC) + { + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_FmPcdCcTree->nextEngineAndRequiredAction[i].nextEngineParams.params.ccParams.h_CcNode; + + if(IsNodeInModifiedState((t_Handle)p_FmPcdCcNextNode)) + UpdateNodeWithModifiedState((t_Handle)p_FmPcdCcNextNode, FALSE); + } + } + + for(i = 0; i < numOfEntries; i++) + { + if(p_FmPcdCcTree->nextEngineAndRequiredAction[i].requiredAction) + { + err = FmPcdCcSetRequiredAction(h_FmPcd, p_FmPcdCcTree->nextEngineAndRequiredAction[i].requiredAction, &p_FmPcdCcTree->nextEngineAndRequiredAction[i], p_CcTreeTmp,1, p_FmPcdCcTree); + if(err) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE); + } + } + + return p_FmPcdCcTree; +} + +t_Error FM_PCD_CcDeleteTree(t_Handle h_FmPcd, t_Handle h_CcTree) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree; + int i= 0; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_CcTree,E_INVALID_STATE); + + FmPcdDecNetEnvOwners(h_FmPcd, p_CcTree->netEnvId); + + if(p_CcTree->owners) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("the tree with this ID can not be removed because this tree is occupied, first - unbind this tree")); + + for(i = 0; i numOfEntries; i++) + { + if(p_CcTree->nextEngineAndRequiredAction[i].nextEngineParams.nextEngine == e_FM_PCD_CC) + UpdateNodeOwner(p_CcTree->nextEngineAndRequiredAction[i].nextEngineParams.params.ccParams.h_CcNode, FALSE); + } + +#ifdef FM_PCD_CC_MANIP + for(i = 0; i < p_CcTree->numOfEntries; i++) + { + if(p_CcTree->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip) + FmPcdManipUpdateOwner(p_CcTree->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip, FALSE); + } +#endif /* FM_PCD_CC_MANIP */ + + DeleteTree(p_CcTree, p_FmPcd); + return E_OK; +} + +t_Handle FM_PCD_CcSetNode(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *) h_FmPcd; + t_FmPcdCcNode *p_FmPcdCcNode, *p_FmPcdCcNextNode; + t_Error err = E_OK; + int tmp, size; + bool glblMask = FALSE; + t_FmPcdCcKeyParams *p_KeyParams; + t_Handle p_KeysMatchTblTmp; + t_Handle p_AdTableTmp; + bool fullField = FALSE; + ccPrivateInfo_t icCode = CC_PRIVATE_INFO_NONE; + bool isKeyTblAlloc, fromIc = FALSE; + t_CcNodeInformation ccNodeInfo, *p_CcInformation; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd,E_INVALID_HANDLE,NULL); + + /* + if (!p_CcNodeParam->keysParams.keySize || + !p_CcNodeParam->keysParams.numOfKeys) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("At least one key of keySize > 0 must be defined.")); + return NULL; + } + */ + p_FmPcdCcNode = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode)); + if(!p_FmPcdCcNode) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + memset(p_FmPcdCcNode, 0, sizeof(t_FmPcdCcNode)); + + p_FmPcdCcNode->p_GlblMask = (t_Handle)XX_Malloc(CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + memset(p_FmPcdCcNode->p_GlblMask, 0, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + + p_FmPcdCcNode->numOfKeys = p_CcNodeParam->keysParams.numOfKeys; + + p_FmPcdCcNode->h_FmPcd = h_FmPcd; + + INIT_LIST(&p_FmPcdCcNode->ccPrevNodesLst); + INIT_LIST(&p_FmPcdCcNode->ccTreeIdLst); + INIT_LIST(&p_FmPcdCcNode->ccTreesLst); + + if((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_BY_HDR) && + ((p_CcNodeParam->extractCcParams.extractByHdr.hdr == HEADER_TYPE_IPv4) || + (p_CcNodeParam->extractCcParams.extractByHdr.hdr == HEADER_TYPE_IPv6)) && + (p_CcNodeParam->extractCcParams.extractByHdr.type == e_FM_PCD_EXTRACT_FULL_FIELD) && + ((p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv6 == NET_HEADER_FIELD_IPv6_HOP_LIMIT) || + (p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv4 == NET_HEADER_FIELD_IPv4_TTL))) + { + err = Ipv4TtlOrIpv6HopLimiCheckParams(h_FmPcd, p_CcNodeParam, p_FmPcdCcNode, &isKeyTblAlloc); + glblMask = FALSE; + + } + else if((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_NON_HDR) && + ((p_CcNodeParam->extractCcParams.extractNonHdr.src == e_FM_PCD_EXTRACT_FROM_KEY) || + (p_CcNodeParam->extractCcParams.extractNonHdr.src == e_FM_PCD_EXTRACT_FROM_HASH) || + (p_CcNodeParam->extractCcParams.extractNonHdr.src == e_FM_PCD_EXTRACT_FROM_FLOW_ID))) + { + if((p_CcNodeParam->extractCcParams.extractNonHdr.src == e_FM_PCD_EXTRACT_FROM_FLOW_ID) && + (p_CcNodeParam->extractCcParams.extractNonHdr.offset != 0)) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("In the case of the extraction from e_FM_PCD_EXTRACT_FROM_FLOW_ID offset has to be 0")); + return NULL; + } + + icCode = IcDefineCode(p_CcNodeParam); + fromIc = TRUE; + if(icCode == CC_PRIVATE_INFO_NONE) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("user asked extraction from IC and field in internal context or action wasn't initialized in the right way")); + return NULL; + } + + if((icCode == CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP) || (icCode == CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP)) + { + err = IcHashIndexedCheckParams(h_FmPcd, p_CcNodeParam, p_FmPcdCcNode, &isKeyTblAlloc); + + glblMask = TRUE; + } + else + { + err = CheckParams(h_FmPcd, p_CcNodeParam,p_FmPcdCcNode, &isKeyTblAlloc); + if(p_FmPcdCcNode->glblMaskSize) + glblMask = TRUE; + } + } + else + { + err = CheckParams(h_FmPcd, p_CcNodeParam,p_FmPcdCcNode, &isKeyTblAlloc); + if(p_FmPcdCcNode->glblMaskSize) + glblMask = TRUE; + } + + if(err) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + + switch(p_CcNodeParam->extractCcParams.type) + { + case(e_FM_PCD_EXTRACT_BY_HDR): + switch(p_CcNodeParam->extractCcParams.extractByHdr.type) + { + case(e_FM_PCD_EXTRACT_FULL_FIELD): + p_FmPcdCcNode->parseCode = GetFullFieldParseCode(p_CcNodeParam->extractCcParams.extractByHdr.hdr, p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex, + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField); + GetSizeHeaderField(p_CcNodeParam->extractCcParams.extractByHdr.hdr, p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField, &p_FmPcdCcNode->sizeOfExtraction); + fullField = TRUE; + if((p_FmPcdCcNode->parseCode != CC_PC_FF_TCI1) && (p_FmPcdCcNode->parseCode != CC_PC_FF_TCI2) && + (p_FmPcdCcNode->parseCode != CC_PC_FF_MPLS1) && (p_FmPcdCcNode->parseCode != CC_PC_FF_MPLS1) && + (p_FmPcdCcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1) && (p_FmPcdCcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2) && + (p_FmPcdCcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1) && (p_FmPcdCcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2) && + glblMask) + { + glblMask = FALSE; + p_FmPcdCcNode->glblMaskSize = 4; + p_FmPcdCcNode->lclMask = TRUE; + } + break; + case(e_FM_PCD_EXTRACT_FROM_HDR): + p_FmPcdCcNode->sizeOfExtraction = p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.size; + p_FmPcdCcNode->offset = p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset; + p_FmPcdCcNode->parseCode = GetPrParseCode(p_CcNodeParam->extractCcParams.extractByHdr.hdr, p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex, + p_FmPcdCcNode->offset,glblMask, &p_FmPcdCcNode->prsArrayOffset); + break; + case(e_FM_PCD_EXTRACT_FROM_FIELD): + p_FmPcdCcNode->offset = p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset; + p_FmPcdCcNode->sizeOfExtraction = p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.size; + p_FmPcdCcNode->parseCode = GetFieldParseCode(p_CcNodeParam->extractCcParams.extractByHdr.hdr, p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.field, + p_FmPcdCcNode->offset,&p_FmPcdCcNode->prsArrayOffset, + p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex); + break; + default: + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + return NULL; + } + break; + case(e_FM_PCD_EXTRACT_NON_HDR): + /* get the field code for the generic extract */ + p_FmPcdCcNode->sizeOfExtraction = p_CcNodeParam->extractCcParams.extractNonHdr.size; + p_FmPcdCcNode->offset = p_CcNodeParam->extractCcParams.extractNonHdr.offset; + p_FmPcdCcNode->parseCode = GetGenParseCode(p_CcNodeParam->extractCcParams.extractNonHdr.src, p_FmPcdCcNode->offset, glblMask, &p_FmPcdCcNode->prsArrayOffset, fromIc,icCode); + + if(p_FmPcdCcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED) + { + if((p_FmPcdCcNode->offset + p_FmPcdCcNode->sizeOfExtraction) > 64) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_INVALID_SELECTION,("when node of the type CC_PC_GENERIC_IC_HASH_INDEXED offset + size can not be bigger then size of HASH 64 bits (8 bytes)")); + return NULL; + } + } + if((p_FmPcdCcNode->parseCode == CC_PC_GENERIC_IC_GMASK) || (p_FmPcdCcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)) + { + p_FmPcdCcNode->offset += p_FmPcdCcNode->prsArrayOffset; + p_FmPcdCcNode->prsArrayOffset = 0; + } + break; + + default: + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + return NULL; + } + + if(p_FmPcdCcNode->parseCode == CC_PC_ILLEGAL) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("illeagl extraction type")); + return NULL; + } + + if((p_FmPcdCcNode->sizeOfExtraction > FM_PCD_MAX_SIZE_OF_KEY) || !p_FmPcdCcNode->sizeOfExtraction) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("sizeOfExatrction can not be greater than 56 and not 0")); + return NULL; + } + + if(p_CcNodeParam->keysParams.keySize != p_FmPcdCcNode->sizeOfExtraction) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("keySize has to be equal to sizeOfExtraction")); + return NULL; + } + + + p_FmPcdCcNode->userSizeOfExtraction = p_FmPcdCcNode->sizeOfExtraction; + + if(!glblMask) + memset(p_FmPcdCcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + +#ifdef FM_PCD_CC_MANIP + err = CheckAndSetManipParamsWithCcNodeParams(p_FmPcdCcNode); + if(err != E_OK) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("keySize has to be equal to sizeOfExtraction")); + return NULL; + } +#endif /* FM_PCD_CC_MANIP */ + + GetCcExtractKeySize(p_FmPcdCcNode->sizeOfExtraction, &p_FmPcdCcNode->ccKeySizeAccExtraction); + + if(p_FmPcdCcNode->lclMask) + size = 2 * p_FmPcdCcNode->ccKeySizeAccExtraction; + else + size = p_FmPcdCcNode->ccKeySizeAccExtraction; + + if(isKeyTblAlloc) + { + p_FmPcdCcNode->h_KeysMatchTable =(t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcdCcNode->h_FmPcd), + (uint32_t)(size * sizeof(uint8_t) * (p_FmPcdCcNode->numOfKeys + 1)), + FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN); + if(!p_FmPcdCcNode->h_KeysMatchTable) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory in MURAM for KEY MATCH table")); + return NULL; + } + IOMemSet32((uint8_t *)p_FmPcdCcNode->h_KeysMatchTable, 0, size * sizeof(uint8_t) * (p_FmPcdCcNode->numOfKeys + 1)); + } + + p_FmPcdCcNode->h_AdTable = (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcdCcNode->h_FmPcd), + (uint32_t)( (p_FmPcdCcNode->numOfKeys+1) * FM_PCD_CC_AD_ENTRY_SIZE), + FM_PCD_CC_AD_TABLE_ALIGN); + if(!p_FmPcdCcNode->h_AdTable) + { + DeleteNode(p_FmPcdCcNode); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory in MURAM for AD table ")); + return NULL; + } + IOMemSet32((uint8_t *)p_FmPcdCcNode->h_AdTable, 0, (uint32_t)((p_FmPcdCcNode->numOfKeys+1) * FM_PCD_CC_AD_ENTRY_SIZE)); + + p_KeysMatchTblTmp = p_FmPcdCcNode->h_KeysMatchTable; + p_AdTableTmp = p_FmPcdCcNode->h_AdTable; + for(tmp = 0 ; tmp < p_FmPcdCcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + + if(p_KeysMatchTblTmp) + { + Mem2IOCpy32((void*)p_KeysMatchTblTmp, p_KeyParams->p_Key, p_FmPcdCcNode->sizeOfExtraction); + + if(p_FmPcdCcNode->lclMask && p_KeyParams->p_Mask) + Mem2IOCpy32(PTR_MOVE(p_KeysMatchTblTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), p_KeyParams->p_Mask, p_FmPcdCcNode->sizeOfExtraction); + else if(p_FmPcdCcNode->lclMask) + IOMemSet32(PTR_MOVE(p_KeysMatchTblTmp, p_FmPcdCcNode->ccKeySizeAccExtraction), 0xff, p_FmPcdCcNode->sizeOfExtraction); + p_KeysMatchTblTmp = PTR_MOVE(p_KeysMatchTblTmp, size * sizeof(uint8_t)); + } + NextStepAd(p_AdTableTmp,&p_KeyParams->ccNextEngineParams, p_FmPcd); + + p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + } + NextStepAd(p_AdTableTmp,&p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, p_FmPcd); + + if(fullField == TRUE) + p_FmPcdCcNode->sizeOfExtraction = 0; + + + for(tmp = 0; tmp < p_FmPcdCcNode->numOfKeys + 1; tmp++) + { + if(p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].nextEngineParams.nextEngine == e_FM_PCD_CC) + { + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].nextEngineParams.params.ccParams.h_CcNode; + + if(!IsNodeInModifiedState((t_Handle)p_FmPcdCcNextNode)) + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = (t_Handle)p_FmPcdCcNode; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccPrevNodesLst, &ccNodeInfo); + UpdateNodeWithModifiedState((t_Handle)p_FmPcdCcNextNode, TRUE); + } + else + { + p_CcInformation = FindNodeInfoInReleventLst(&p_FmPcdCcNextNode->ccPrevNodesLst,(t_Handle)p_FmPcdCcNode); + ASSERT_COND(p_CcInformation); + p_CcInformation->index++; + } + } + + } + + for(tmp = 0; tmp < p_FmPcdCcNode->numOfKeys + 1; tmp++) + { + if(p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].nextEngineParams.nextEngine == e_FM_PCD_CC) + { + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].nextEngineParams.params.ccParams.h_CcNode; + + if(IsNodeInModifiedState((t_Handle)p_FmPcdCcNextNode)) + UpdateNodeWithModifiedState((t_Handle)p_FmPcdCcNextNode, FALSE); + } + } + + p_AdTableTmp = p_FmPcdCcNode->h_AdTable; + for(tmp = 0; tmp < p_FmPcdCcNode->numOfKeys; tmp++) + { + if(p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].requiredAction) + { + + err = FmPcdCcSetRequiredAction(h_FmPcd, p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].requiredAction, &p_FmPcdCcNode->nextEngineAndRequiredAction[tmp], p_AdTableTmp,1, NULL); + if(err) + { + FM_PCD_CcDeleteNode(h_FmPcd, (t_Handle)p_FmPcdCcNode); + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE); + } + } + if(p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].requiredAction) + { + err = FmPcdCcSetRequiredAction(h_FmPcd, p_FmPcdCcNode->nextEngineAndRequiredAction[tmp].requiredAction, &p_FmPcdCcNode->nextEngineAndRequiredAction[tmp], p_AdTableTmp,1, NULL); + if(err) + { + FM_PCD_CcDeleteNode(h_FmPcd, (t_Handle)p_FmPcdCcNode); + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + + } + + + return p_FmPcdCcNode; +} + +t_Error FM_PCD_CcDeleteNode(t_Handle h_FmPcd, t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + int i = 0; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + + UNUSED(h_FmPcd); + if(!p_CcNode) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("the node with this ID is not initialized")); + + if(p_CcNode->owners) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("the node with this ID can not be removed because this node is occupied, first - unbind this node")); + + for(i = 0; i < p_CcNode->numOfKeys; i++) + { + if(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.nextEngine == e_FM_PCD_CC) + UpdateNodeOwner(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.params.ccParams.h_CcNode, FALSE); + + } + if(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.nextEngine == e_FM_PCD_CC) + UpdateNodeOwner(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.params.ccParams.h_CcNode, FALSE); + +#ifdef FM_PCD_CC_MANIP + for(i = 0; i < p_CcNode->numOfKeys; i++) + { + if(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip) + FmPcdManipUpdateOwner(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip, FALSE); + } + if(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip) + FmPcdManipUpdateOwner(p_CcNode->nextEngineAndRequiredAction[i].nextEngineParams.h_Manip, FALSE); +#endif /* FM_PCD_CC_MANIP */ + + DeleteNode(p_CcNode); + + return E_OK; +} + +t_Error FM_PCD_CcNodeAddKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcPcdCcAddKey(p_FmPcd->h_Hc, h_CcNode, keyIndex, keySize, p_KeyParams); +} + +t_Error FM_PCD_CcNodeRemoveKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcPcdCcRemoveKey(p_FmPcd->h_Hc, h_CcNode, keyIndex); +} + +t_Error FM_PCD_CcNodeModifyKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcPcdCcModifyKey(p_FmPcd->h_Hc, h_CcNode, keyIndex, keySize, p_Key, p_Mask); +} + +t_Error FM_PCD_CcNodeModifyNextEngine(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcPcdCcModifyNodeNextEngine(p_FmPcd->h_Hc, h_CcNode, keyIndex, p_FmPcdCcNextEngineParams); +} + +t_Error FM_PCD_CcNodeModifyMissNextEngine(t_Handle h_FmPcd, t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcPcdCcModifyNodeMissNextEngine(p_FmPcd->h_Hc, h_CcNode, p_FmPcdCcNextEngineParams); +} + +t_Error FM_PCD_CcTreeModifyNextEngine(t_Handle h_FmPcd, t_Handle h_CcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcPcdCcModifyTreeNextEngine(p_FmPcd->h_Hc, h_CcTree, grpId, index, p_FmPcdCcNextEngineParams); +} + +t_Error FM_PCD_CcNodeModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcPcdCcModifyKeyAndNextEngine(p_FmPcd->h_Hc, h_CcNode, keyIndex, keySize, p_KeyParams); +} + +uint32_t FM_PCD_CcNodeGetKeyCounter(t_Handle h_FmPcd, t_Handle h_CcNode, uint8_t keyIndex) +{ + t_FmPcdCcNode *p_FmPcdCcNode = (t_FmPcdCcNode *)h_CcNode; + t_AdOfTypeResult *p_AdResult = NULL; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_VALUE(h_CcNode, E_INVALID_HANDLE, 0); +#ifdef DISABLE_SANITY_CHECKS +UNUSED(h_FmPcd); +#endif /* DISABLE_SANITY_CHECKS */ + + if (keyIndex >= p_FmPcdCcNode->numOfKeys) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, + ("keyIndex > numOfKeys defined for this node")); + return 0; + } + + p_AdResult = PTR_MOVE(p_FmPcdCcNode->h_AdTable, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE); + ASSERT_COND(p_AdResult); + + if (p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_CC) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, + ("statistics updated only for entries where next engine not CC")); + return 0; + } + + if(((p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_DONE) && + !p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.params.enqueueParams.statisticsEn) || + ((p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_KG) && + !p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.params.kgParams.statisticsEn) || + ((p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.nextEngine == e_FM_PCD_PLCR) && + !p_FmPcdCcNode->nextEngineAndRequiredAction[keyIndex].nextEngineParams.params.plcrParams.statisticsEn)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, + ("statistics wasn't enable")); + return 0; + } + + return GET_UINT32(p_AdResult->res); +} --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_pcd.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_pcd.h @@ -0,0 +1,715 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_pcd.h + + @Description FM PCD ... +*//***************************************************************************/ +#ifndef __FM_PCD_H +#define __FM_PCD_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "fm_pcd_ext.h" + + +#define __ERR_MODULE__ MODULE_FM_PCD + + +/**************************************************************************//** + @Group FM_PCD_Runtime_grp FM PCD Runtime Unit + @{ +*//***************************************************************************/ + +/****************************/ +/* Network defines */ +/****************************/ +#define UDP_HEADER_SIZE 8 + +#define ESP_SPI_OFFSET 0 +#define ESP_SPI_SIZE 4 +#define ESP_SEQ_NUM_OFFSET ESP_SPI_SIZE +#define ESP_SEQ_NUM_SIZE 4 + +/****************************/ +/* General defines */ +/****************************/ +#define ILLEGAL_CLS_PLAN 0xff +#define ILLEGAL_NETENV 0xff +/****************************/ +/* Error defines */ +/****************************/ +#define FM_PCD_EX_KG_DOUBLE_ECC 0x80000000 +#define FM_PCD_EX_KG_KEYSIZE_OVERFLOW 0x40000000 + +#define FM_PCD_EX_PLCR_DOUBLE_ECC 0x20000000 +#define FM_PCD_EX_PLCR_INIT_ENTRY_ERROR 0x10000000 +#define FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE 0x08000000 +#define FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE 0x04000000 + +#define FM_PCD_EX_PRS_DOUBLE_ECC 0x02000000 +#define FM_PCD_EX_PRS_SINGLE_ECC 0x01000000 + +#define GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception) \ +switch(exception){ \ + case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC: \ + bitMask = FM_PCD_EX_KG_DOUBLE_ECC; break; \ + case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC: \ + bitMask = FM_PCD_EX_PLCR_DOUBLE_ECC; break; \ + case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW: \ + bitMask = FM_PCD_EX_KG_KEYSIZE_OVERFLOW; break; \ + case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR: \ + bitMask = FM_PCD_EX_PLCR_INIT_ENTRY_ERROR; break; \ + case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE: \ + bitMask = FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE; break; \ + case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE: \ + bitMask = FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE; break; \ + case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC: \ + bitMask = FM_PCD_EX_PRS_DOUBLE_ECC; break; \ + case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC: \ + bitMask = FM_PCD_EX_PRS_SINGLE_ECC; break; \ + default: bitMask = 0;break;} + +/***********************************************************************/ +/* SW parser L4 shells patch */ +/***********************************************************************/ +#ifdef FM_PRS_L4_SHELL_ERRATA_FMANb +#define SW_PRS_L4_PATCH \ +{ 0x31,0x92,0x02,0x1f,0x00,0x32,0x00,0x78, \ + 0x00,0x34,0x32,0xf0,0x00,0x50,0x00,0x0c, \ + 0x28,0x5e,0x83,0x8e,0x29,0x32,0xaf,0x8e, \ + 0x31,0xb2,0x9f,0xff,0x00,0x06,0xaf,0xbf, \ + 0x00,0x06,0x29,0x36,0x00,0x01,0x1b,0xff, \ + 0x32,0xf0,0x00,0x50,0x00,0x08,0x28,0x5e, \ + 0x08,0x99,0x00,0x00,0x9f,0x8e,0x31,0xb2, \ + 0x9f,0xff,0x00,0x06,0x29,0x36,0x00,0x01, \ + 0x1b,0xff,0x32,0xf0,0x00,0x50,0x00,0x04, \ + 0x28,0x5e,0x8f,0x9e,0x29,0x32,0x31,0xb2, \ + 0x8f,0xbf,0x00,0x06,0x29,0x36,0x00,0x01, \ + 0x1b,0xff,0x32,0xf0,0x00,0x50,0x00,0x04, \ + 0x28,0x5e,0x8f,0x9e,0x29,0x32,0x31,0xb2, \ + 0x8f,0xbf,0x00,0x06,0x29,0x36,0x00,0x01, \ + 0x1b,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; + +#define SW_PRS_L4_PATCH_SIZE 120 +#endif /* FM_PRS_L4_SHELL_ERRATA_FMANb */ + +/****************************/ +/* Parser defines */ +/****************************/ +/* masks */ +#define PRS_ERR_CAP 0x80000000 +#define PRS_ERR_TYPE_DOUBLE 0x40000000 +#define PRS_ERR_SINGLE_ECC_CNT_MASK 0x00FF0000 +#define PRS_ERR_ADDR_MASK 0x000001FF +#define FM_PCD_PRS_RPIMAC_EN 0x00000001 +#define FM_PCD_PRS_SINGLE_ECC 0x00004000 +#define FM_PCD_PRS_PORT_IDLE_STS 0xffff0000 +#define FM_PCD_PRS_DOUBLE_ECC 0x00004000 +#define FM_PCD_PRS_PPSC_ALL_PORTS 0xffff0000 + +/* others */ +#define PRS_MAX_CYCLE_LIMIT 8191 +#define PRS_SW_DATA 0x00000800 +#define PRS_REGS_OFFSET 0x00000840 + +#define GET_FM_PCD_PRS_PORT_ID(prsPortId,hardwarePortId) \ + prsPortId = (uint8_t)(hardwarePortId & 0x0f) + +#define GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId) \ + bitMask = 0x80000000>>prsPortId + +/***********************************************************************/ +/* Keygen defines */ +/***********************************************************************/ +/* Masks */ +#define FM_PCD_KG_KGGCR_EN 0x80000000 +#define KG_SCH_GEN_VALID 0x80000000 +#define KG_SCH_GEN_EXTRACT_TYPE 0x00008000 +#define KG_ERR_CAP 0x80000000 +#define KG_ERR_TYPE_DOUBLE 0x40000000 +#define KG_ERR_ADDR_MASK 0x00000FFF +#define FM_PCD_KG_DOUBLE_ECC 0x80000000 +#define FM_PCD_KG_KEYSIZE_OVERFLOW 0x40000000 +#define KG_SCH_MODE_EN 0x80000000 + +/* shifts */ +#define FM_PCD_KG_PE_CPP_MASK_SHIFT 16 +#define FM_PCD_KG_KGAR_WSEL_SHIFT 8 + +/* others */ +#define KG_DOUBLE_MEANING_REGS_OFFSET 0x100 +#define NO_VALIDATION 0x70 +#define KG_ACTION_REG_TO 1024 +#define KG_MAX_PROFILE 255 +#define SCHEME_ALWAYS_DIRECT 0xFFFFFFFF + +typedef struct { + bool known; + uint8_t id; +} t_FmPcdKgSchemesExtractsEntry; + +typedef struct { + t_FmPcdKgSchemesExtractsEntry extractsArray[FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; +} t_FmPcdKgSchemesExtracts; + +/***********************************************************************/ +/* Policer defines */ +/***********************************************************************/ + +/* masks */ +#define FM_PCD_PLCR_PEMODE_PI 0x80000000 +#define FM_PCD_PLCR_PEMODE_CBLND 0x40000000 +#define FM_PCD_PLCR_PEMODE_ALG_MASK 0x30000000 +#define FM_PCD_PLCR_PEMODE_ALG_RFC2698 0x10000000 +#define FM_PCD_PLCR_PEMODE_ALG_RFC4115 0x20000000 +#define FM_PCD_PLCR_PEMODE_DEFC_MASK 0x0C000000 +#define FM_PCD_PLCR_PEMODE_DEFC_Y 0x04000000 +#define FM_PCD_PLCR_PEMODE_DEFC_R 0x08000000 +#define FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE 0x0C000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_MASK 0x03000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_Y 0x01000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_R 0x02000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_G_NC 0x03000000 +#define FM_PCD_PLCR_PEMODE_PKT 0x00800000 +#define FM_PCD_PLCR_PEMODE_FPP_MASK 0x001F0000 +#define FM_PCD_PLCR_PEMODE_FPP_SHIFT 16 +#define FM_PCD_PLCR_PEMODE_FLS_MASK 0x0000F000 +#define FM_PCD_PLCR_PEMODE_FLS_L2 0x00003000 +#define FM_PCD_PLCR_PEMODE_FLS_L3 0x0000B000 +#define FM_PCD_PLCR_PEMODE_FLS_L4 0x0000E000 +#define FM_PCD_PLCR_PEMODE_FLS_FULL 0x0000F000 +#define FM_PCD_PLCR_PEMODE_RBFLS 0x00000800 +#define FM_PCD_PLCR_PEMODE_TRA 0x00000004 +#define FM_PCD_PLCR_PEMODE_TRB 0x00000002 +#define FM_PCD_PLCR_PEMODE_TRC 0x00000001 +#define FM_PCD_PLCR_DOUBLE_ECC 0x80000000 +#define FM_PCD_PLCR_INIT_ENTRY_ERROR 0x40000000 +#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE 0x80000000 +#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE 0x40000000 + +#define FM_PCD_PLCR_NIA_VALID 0x80000000 + +#define FM_PCD_PLCR_GCR_EN 0x80000000 +#define FM_PCD_PLCR_GCR_STEN 0x40000000 +#define FM_PCD_PLCR_GCR_DAR 0x20000000 +#define FM_PCD_PLCR_GCR_DEFNIA 0x00FFFFFF +#define FM_PCD_PLCR_NIA_ABS 0x00000100 + +#define FM_PCD_PLCR_GSR_BSY 0x80000000 +#define FM_PCD_PLCR_GSR_DQS 0x60000000 +#define FM_PCD_PLCR_GSR_RPB 0x20000000 +#define FM_PCD_PLCR_GSR_FQS 0x0C000000 +#define FM_PCD_PLCR_GSR_LPALG 0x0000C000 +#define FM_PCD_PLCR_GSR_LPCA 0x00003000 +#define FM_PCD_PLCR_GSR_LPNUM 0x000000FF + +#define FM_PCD_PLCR_EVR_PSIC 0x80000000 +#define FM_PCD_PLCR_EVR_AAC 0x40000000 + +#define FM_PCD_PLCR_PAR_PSI 0x20000000 +#define FM_PCD_PLCR_PAR_PNUM 0x00FF0000 +/* PWSEL Selctive select options */ +#define FM_PCD_PLCR_PAR_PWSEL_PEMODE 0x00008000 /* 0 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEGNIA 0x00004000 /* 1 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEYNIA 0x00002000 /* 2 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERNIA 0x00001000 /* 3 */ +#define FM_PCD_PLCR_PAR_PWSEL_PECIR 0x00000800 /* 4 */ +#define FM_PCD_PLCR_PAR_PWSEL_PECBS 0x00000400 /* 5 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEPIR_EIR 0x00000200 /* 6 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEPBS_EBS 0x00000100 /* 7 */ +#define FM_PCD_PLCR_PAR_PWSEL_PELTS 0x00000080 /* 8 */ +#define FM_PCD_PLCR_PAR_PWSEL_PECTS 0x00000040 /* 9 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEPTS_ETS 0x00000020 /* 10 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEGPC 0x00000010 /* 11 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEYPC 0x00000008 /* 12 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERPC 0x00000004 /* 13 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERYPC 0x00000002 /* 14 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERRPC 0x00000001 /* 15 */ + +#define FM_PCD_PLCR_PAR_PMR_BRN_1TO1 0x0000 /* - Full bit replacement. {PBNUM[0:N-1] + 1-> 2^N specific locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_2TO2 0x1 /* - {PBNUM[0:N-2],PNUM[N-1]}. + 2-> 2^(N-1) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_4TO4 0x2 /* - {PBNUM[0:N-3],PNUM[N-2:N-1]}. + 4-> 2^(N-2) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_8TO8 0x3 /* - {PBNUM[0:N-4],PNUM[N-3:N-1]}. + 8->2^(N-3) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_16TO16 0x4 /* - {PBNUM[0:N-5],PNUM[N-4:N-1]}. + 16-> 2^(N-4) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_32TO32 0x5 /* {PBNUM[0:N-6],PNUM[N-5:N-1]}. + 32-> 2^(N-5) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_64TO64 0x6 /* {PBNUM[0:N-7],PNUM[N-6:N-1]}. + 64-> 2^(N-6) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_128TO128 0x7 /* {PBNUM[0:N-8],PNUM[N-7:N-1]}. + 128-> 2^(N-7) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_256TO256 0x8 /* - No bit replacement for N=8. {PNUM[N-8:N-1]}. + When N=8 this option maps all 256 profiles by the DISPATCH bus into one group. */ + +#define FM_PCD_PLCR_PMR_V 0x80000000 +#define PLCR_ERR_ECC_CAP 0x80000000 +#define PLCR_ERR_ECC_TYPE_DOUBLE 0x40000000 +#define PLCR_ERR_ECC_PNUM_MASK 0x00000FF0 +#define PLCR_ERR_ECC_OFFSET_MASK 0x0000000F + +#define PLCR_ERR_UNINIT_CAP 0x80000000 +#define PLCR_ERR_UNINIT_NUM_MASK 0x000000FF +#define PLCR_ERR_UNINIT_PID_MASK 0x003f0000 +#define PLCR_ERR_UNINIT_ABSOLUTE_MASK 0x00008000 + +/* shifts */ +#define PLCR_ERR_ECC_PNUM_SHIFT 4 +#define PLCR_ERR_UNINIT_PID_SHIFT 16 + +#define FM_PCD_PLCR_PMR_BRN_SHIFT 16 + +/* others */ +#define WAIT_FOR_PLCR_EVR_AAC \ +{\ + uint32_t count = 0; \ + uint32_t tmpReg32; \ + while (count < FM_PCD_PLCR_POLL) \ + { \ + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->fmpl_evr);\ + if (!( tmpReg32 & FM_PCD_PLCR_EVR_AAC)) break;\ + count++;\ + }\ +} + +#define WAIT_FOR_PLCR_PAR_GO \ +{\ + uint32_t count = 0; \ + uint32_t tmpReg32; \ + while (count < FM_PCD_PLCR_POLL) \ + { \ + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->fmpl_par);\ + if (!( tmpReg32 & FM_PCD_PLCR_PAR_GO)) break;\ + count++; \ + }\ +} + +#define PLCR_PORT_WINDOW_SIZE(hardwarePortId) + +/****************************/ +/* Defaults */ +/****************************/ +#define DEFAULT_plcrAutoRefresh FALSE +#define DEFAULT_prsMaxParseCycleLimit 0 +#define DEFAULT_fmPcdKgErrorExceptions (FM_PCD_EX_KG_DOUBLE_ECC | FM_PCD_EX_KG_KEYSIZE_OVERFLOW) +#define DEFAULT_fmPcdPlcrErrorExceptions (FM_PCD_EX_PLCR_DOUBLE_ECC | FM_PCD_EX_PLCR_INIT_ENTRY_ERROR) +#define DEFAULT_fmPcdPlcrExceptions 0 +#define DEFAULT_fmPcdPrsErrorExceptions (FM_PCD_EX_PRS_DOUBLE_ECC) + +#define DEFAULT_fmPcdPrsExceptions FM_PCD_EX_PRS_SINGLE_ECC +#define DEFAULT_numOfUsedProfilesPerWindow 16 +#define DEFAULT_numOfSharedPlcrProfiles 4 + +/***********************************************************************/ +/* Memory map */ +/***********************************************************************/ +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +typedef _Packed struct { + volatile uint32_t kgoe_sp; + volatile uint32_t kgoe_cpp; +} _PackedType t_FmPcdKgPortConfigRegs; + +typedef _Packed struct { + volatile uint32_t kgcpe[8]; +} _PackedType t_FmPcdKgClsPlanRegs; + +typedef _Packed union { + t_FmPcdKgInterModuleSchemeRegs schemeRegs; + t_FmPcdKgPortConfigRegs portRegs; + t_FmPcdKgClsPlanRegs clsPlanRegs; +} _PackedType u_FmPcdKgIndirectAccessRegs; + +typedef _Packed struct { + volatile uint32_t kggcr; + volatile uint32_t res0; + volatile uint32_t res1; + volatile uint32_t kgeer; + volatile uint32_t kgeeer; + volatile uint32_t res2; + volatile uint32_t res3; + volatile uint32_t kgseer; + volatile uint32_t kgseeer; + volatile uint32_t kggsr; + volatile uint32_t kgtpc; + volatile uint32_t kgserc; + volatile uint32_t res4[4]; + volatile uint32_t kgfdor; + volatile uint32_t kggdv0r; + volatile uint32_t kggdv1r; + volatile uint32_t res5[5]; + volatile uint32_t kgfer; + volatile uint32_t kgfeer; + volatile uint32_t res6[38]; + u_FmPcdKgIndirectAccessRegs indirectAccessRegs; + volatile uint32_t res[42]; /*(0xfc-sizeof(u_FmPcdKgIndirectAccessRegs))/4 */ + volatile uint32_t kgar; +} _PackedType t_FmPcdKgRegs; + +typedef _Packed struct { +/* General Configuration and Status Registers */ + volatile uint32_t fmpl_gcr; /* 0x000 FMPL_GCR - FM Policer General Configuration */ + volatile uint32_t fmpl_gsr; /* 0x004 FMPL_GSR - FM Policer Global Status Register */ + volatile uint32_t fmpl_evr; /* 0x008 FMPL_EVR - FM Policer Event Register */ + volatile uint32_t fmpl_ier; /* 0x00C FMPL_IER - FM Policer Interrupt Enable Register */ + volatile uint32_t fmpl_ifr; /* 0x010 FMPL_IFR - FM Policer Interrupt Force Register */ + volatile uint32_t fmpl_eevr; /* 0x014 FMPL_EEVR - FM Policer Error Event Register */ + volatile uint32_t fmpl_eier; /* 0x018 FMPL_EIER - FM Policer Error Interrupt Enable Register */ + volatile uint32_t fmpl_eifr; /* 0x01C FMPL_EIFR - FM Policer Error Interrupt Force Register */ +/* Global Statistic Counters */ + volatile uint32_t fmpl_rpcnt; /* 0x020 FMPL_RPC - FM Policer RED Packets Counter */ + volatile uint32_t fmpl_ypcnt; /* 0x024 FMPL_YPC - FM Policer YELLOW Packets Counter */ + volatile uint32_t fmpl_rrpcnt; /* 0x028 FMPL_RRPC - FM Policer Recolored RED Packet Counter */ + volatile uint32_t fmpl_rypcnt; /* 0x02C FMPL_RYPC - FM Policer Recolored YELLOW Packet Counter */ + volatile uint32_t fmpl_tpcnt; /* 0x030 FMPL_TPC - FM Policer Total Packet Counter */ + volatile uint32_t fmpl_flmcnt; /* 0x034 FMPL_FLMC - FM Policer Frame Length Mismatch Counter */ + volatile uint32_t fmpl_res0[21]; /* 0x038 - 0x08B Reserved */ +/* Profile RAM Access Registers */ + volatile uint32_t fmpl_par; /* 0x08C FMPL_PAR - FM Policer Profile Action Register*/ + t_FmPcdPlcrInterModuleProfileRegs profileRegs; +/* Error Capture Registers */ + volatile uint32_t fmpl_serc; /* 0x100 FMPL_SERC - FM Policer Soft Error Capture */ + volatile uint32_t fmpl_upcr; /* 0x104 FMPL_UPCR - FM Policer Uninitialized Profile Capture Register */ + volatile uint32_t fmpl_res2; /* 0x108 Reserved */ +/* Debug Registers */ + volatile uint32_t fmpl_res3[61]; /* 0x10C-0x200 Reserved Debug*/ +/* Profile Selection Mapping Registers Per Port-ID (n=1-11, 16) */ + volatile uint32_t fmpl_dpmr; /* 0x200 FMPL_DPMR - FM Policer Default Mapping Register */ + volatile uint32_t fmpl_pmr[63]; /*+default 0x204-0x2FF FMPL_PMR1 - FMPL_PMR63, - FM Policer Profile Mapping Registers. + (for port-ID 1-11, only for supported Port-ID registers) */ +} _PackedType t_FmPcdPlcrRegs; + +typedef _Packed struct { + volatile uint32_t rpclim; + volatile uint32_t rpimac; + volatile uint32_t pmeec; + volatile uint32_t res1[5]; + volatile uint32_t pevr; + volatile uint32_t pever; + volatile uint32_t pevfr; + volatile uint32_t perr; + volatile uint32_t perer; + volatile uint32_t perfr; + volatile uint32_t res2[0xA]; + volatile uint32_t ppsc; + volatile uint32_t res3; + volatile uint32_t pds; + volatile uint32_t l2rrs; + volatile uint32_t l3rrs; + volatile uint32_t l4rrs; + volatile uint32_t srrs; + volatile uint32_t l2rres; + volatile uint32_t l3rres; + volatile uint32_t l4rres; + volatile uint32_t srres; + volatile uint32_t spcs; + volatile uint32_t spscs; + volatile uint32_t hxscs; + volatile uint32_t mrcs; + volatile uint32_t mwcs; + volatile uint32_t mrscs; + volatile uint32_t mwscs; + volatile uint32_t fcscs; +} _PackedType t_FmPcdPrsRegs; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/***********************************************************************/ +/* Driver's internal structures */ +/***********************************************************************/ + +typedef struct { + t_Handle h_Manip; + bool keepRes; + e_FmPcdEngine nextEngine; + uint8_t parseCode; +} t_FmPcdInfoForManip; + +/**************************************************************************//** + @Description A structure of parameters to communicate + between the port and PCD regarding the KG scheme. +*//***************************************************************************/ +typedef struct { + uint8_t netEnvId; /* in */ + uint8_t numOfDistinctionUnits; /* in */ + uint8_t unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* in */ + uint32_t vector; /* out */ +} t_NetEnvParams; + +typedef struct { + volatile bool lock; + bool used; + uint8_t owners; + uint8_t netEnvId; + uint8_t guestId; + uint8_t baseEntry; + uint16_t sizeOfGrp; + protocolOpt_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; +} t_FmPcdKgClsPlanGrp; + +typedef struct { + volatile bool lock; + bool valid; + uint8_t netEnvId; + uint8_t owners; + uint32_t matchVector; + uint32_t ccUnits; + bool nextRelativePlcrProfile; + uint16_t relativeProfileId; + uint16_t numOfProfiles; + t_FmPcdKgKeyOrder orderedArray; + e_FmPcdEngine nextEngine; + e_FmPcdDoneAction doneAction; + uint8_t pointedOwners; + uint32_t requiredAction; + bool extractedOrs; + uint8_t bitOffsetInPlcrProfile; + bool directPlcr; +} t_FmPcdKgScheme; + +typedef struct { + bool allocated; + uint8_t ownerId; /* guestId for KG in multi-partition only, + portId for PLCR in any environment */ +} t_FmPcdAllocMng; + +typedef struct { + t_FmPcdKgRegs *p_FmPcdKgRegs; + uint32_t schemeExceptionsBitMask; + uint8_t numOfSchemes; + uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; + t_FmPcdKgScheme schemes[FM_PCD_KG_NUM_OF_SCHEMES]; + t_FmPcdKgClsPlanGrp clsPlanGrps[FM_MAX_NUM_OF_PORTS]; + uint8_t emptyClsPlanGrpId; + t_FmPcdAllocMng schemesMng[FM_PCD_KG_NUM_OF_SCHEMES]; /* only for MASTER ! */ + t_FmPcdAllocMng clsPlanBlocksMng[FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP]; +} t_FmPcdKg; + +typedef struct { + uint16_t profilesBase; + uint16_t numOfProfiles; + t_Handle h_FmPort; +} t_FmPcdPlcrMapParam; + +typedef struct { + bool valid; + volatile bool lock; + t_FmPcdAllocMng profilesMng; + uint8_t pointedOwners; + uint32_t requiredAction; + e_FmPcdEngine nextEngineOnGreen; /**< Green next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnGreen; /**< Green next engine params */ + + e_FmPcdEngine nextEngineOnYellow; /**< Yellow next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnYellow; /**< Yellow next engine params */ + + e_FmPcdEngine nextEngineOnRed; /**< Red next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnRed; /**< Red next engine params */ +} t_FmPcdPlcrProfile; + +typedef struct { + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + t_FmPcdPlcrProfile profiles[FM_PCD_PLCR_NUM_ENTRIES]; + uint16_t numOfSharedProfiles; + uint16_t sharedProfilesIds[FM_PCD_PLCR_NUM_ENTRIES]; + t_FmPcdPlcrMapParam portsMapping[FM_MAX_NUM_OF_PORTS]; +} t_FmPcdPlcr; + +typedef struct { + uint32_t *p_SwPrsCode; + uint32_t *p_CurrSwPrs; + uint8_t currLabel; + t_FmPcdPrsRegs *p_FmPcdPrsRegs; + t_FmPcdPrsLabelParams labelsTable[FM_PCD_PRS_NUM_OF_LABELS]; + uint32_t fmPcdPrsPortIdStatistics; +} t_FmPcdPrs; + +typedef struct { + struct { + e_NetHeaderType hdr; + protocolOpt_t opt; /* only one option !! */ + } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS]; +} t_FmPcdIntDistinctionUnit; + +typedef struct { + e_NetHeaderType hdr; + e_NetHeaderType aliasHdr; +} t_FmPcdNetEnvAliases; + +typedef struct { + volatile bool lock; + bool used; + uint8_t owners; + uint8_t clsPlanGrpId; + t_FmPcdIntDistinctionUnit units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + uint32_t unitsVectors[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS]; + uint32_t macsecVector; + t_FmPcdNetEnvAliases aliasHdrs[FM_PCD_MAX_NUM_OF_PRIVATE_HDRS]; +} t_FmPcdNetEnv; + +typedef struct { + bool plcrAutoRefresh; + + uint16_t prsMaxParseCycleLimit; +} t_FmPcdDriverParam; + +typedef struct { + t_Handle h_Fm; + t_Handle h_FmMuram; + uint64_t physicalMuramBase; + volatile bool lock; + t_Handle h_Spinlock; + t_Handle h_IpcSession; /* relevant for guest only */ + bool enabled; + uint8_t guestId; /**< Guest Partition Id */ + uint8_t numOfEnabledGuestPartitionsPcds; + char fmPcdModuleName[MODULE_NAME_SIZE]; + char fmPcdIpcHandlerModuleName[MODULE_NAME_SIZE]; /* relevant for guest only - this is the master's name */ + t_FmPcdNetEnv netEnvs[FM_MAX_NUM_OF_PORTS]; + t_FmPcdKg *p_FmPcdKg; + t_FmPcdPlcr *p_FmPcdPlcr; + t_FmPcdPrs *p_FmPcdPrs; + + t_Handle h_Hc; + + uint32_t exceptions; + t_FmPcdExceptionCallback *f_Exception; + t_FmPcdIdExceptionCallback *f_FmPcdIndexedException; + t_Handle h_App; + + t_FmPcdDriverParam *p_FmPcdDriverParam; +} t_FmPcd; + + +/***********************************************************************/ +/* PCD internal routines */ +/***********************************************************************/ + +/**************************************************************************//** + + @Group FM_PCD_InterModule_grp FM PCD Inter-Module Unit + + @Description FM PCD Inter Module functions - + These are not User API routines but routines that may be called + from other modules. This will be the case in a single core environment, + where instead of useing the XX messeging mechanism, the routines may be + called from other modules. In a multicore environment, the other modules may + be run by other cores and therefor these routines may not be called directly. + + @{ +*//***************************************************************************/ + +t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector); +t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params); +bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector); +t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams); +void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId); +e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); +uint8_t FmPcdNetEnvGetUnitIdForSingleHdr(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); + +t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams); +t_Error KgInit(t_FmPcd *p_FmPcd); +t_Error KgFree(t_FmPcd *p_FmPcd); +void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set); +bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId); +void KgEnable(t_FmPcd *p_FmPcd); +void KgDisable(t_FmPcd *p_FmPcd); +t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First); +void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base); + +/* only for MULTI partittion */ +t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds); +t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds); +/* only for SINGLE partittion */ +t_Error KgBindPortToSchemes(t_Handle h_FmPcd , uint8_t hardwarePortId, uint32_t spReg); + +t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams); +t_Error PlcrInit(t_FmPcd *p_FmPcd); +t_Error PlcrFree(t_FmPcd *p_FmPcd); +void PlcrEnable(t_FmPcd *p_FmPcd); +void PlcrDisable(t_FmPcd *p_FmPcd); +t_Error PlcrFreeProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint16_t num, uint16_t base); +t_Error PlcrAllocProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles, uint16_t *p_Base); +t_Error PlcrAllocSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds); +void PlcrFreeSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds); + +t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams); +t_Error PrsInit(t_FmPcd *p_FmPcd); +void PrsEnable(t_FmPcd *p_FmPcd); +void PrsDisable(t_FmPcd *p_FmPcd); +void PrsFree(t_FmPcd *p_FmPcd ); +t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include); + +t_Handle FmPcdCcConfig(t_Handle h_FmPcd, t_FmPcdParams *p_FmPcdParams); +t_Error FmPcdCcGetGrpParams(t_Handle treeId, uint8_t grpId, uint32_t *p_GrpBits, uint8_t *p_GrpBase); +uint8_t FmPcdCcGetOffset(t_Handle h_CcNode); +uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode); +uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode); + +void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add); +t_Error FmPcdManipCheckParamsForCcNextEgine(t_FmPcdCcNextEngineParams *p_InfoForManip, uint32_t *requiredAction); +void FmPcdManipUpdateAdResultForCc(t_Handle h_Manip, t_Handle p_Ad, t_Handle *p_AdNew); +void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad, t_Handle *p_AdNew, uint32_t adTableOffset); +uint32_t FmPcdManipCheckNia(t_Handle h_FmPcd, t_Handle h_Ad); +void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add); +t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip, t_Handle h_FmPcdCcNode); + +static __inline__ t_Handle FmPcdGetMuramHandle(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + ASSERT_COND(p_FmPcd); + return p_FmPcd->h_FmMuram; +} + +static __inline__ uint64_t FmPcdGetMuramPhysBase(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + ASSERT_COND(p_FmPcd); + return p_FmPcd->physicalMuramBase; +} + + +#endif /* __FM_PCD_H */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_prs.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Pcd/fm_prs.c @@ -0,0 +1,517 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_pcd.c + + @Description FM PCD ... +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "net_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_pcd_ipc.h" + + +t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams) +{ + t_FmPcdPrs *p_FmPcdPrs; + uintptr_t baseAddr; + + UNUSED(p_FmPcd); + UNUSED(p_FmPcdParams); + + p_FmPcdPrs = (t_FmPcdPrs *) XX_Malloc(sizeof(t_FmPcdPrs)); + if (!p_FmPcdPrs) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Parser structure allocation FAILED")); + return NULL; + } + memset(p_FmPcdPrs, 0, sizeof(t_FmPcdPrs)); + + if (p_FmPcd->guestId == NCSW_MASTER_ID) + { + baseAddr = FmGetPcdPrsBaseAddr(p_FmPcdParams->h_Fm); + p_FmPcdPrs->p_SwPrsCode = (uint32_t *)UINT_TO_PTR(baseAddr); + p_FmPcdPrs->p_FmPcdPrsRegs = (t_FmPcdPrsRegs *)UINT_TO_PTR(baseAddr + PRS_REGS_OFFSET); + } + + p_FmPcdPrs->fmPcdPrsPortIdStatistics = 0; + p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = DEFAULT_prsMaxParseCycleLimit; + p_FmPcd->exceptions |= (DEFAULT_fmPcdPrsErrorExceptions | DEFAULT_fmPcdPrsExceptions); + + return p_FmPcdPrs; +} + +static void PcdPrsErrorException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, mask, force; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + event = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perr); + mask = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perer); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perfr); + if(force & event) + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perfr, force & ~event); + + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->perr, event); + + DBG(TRACE, ("parser error - 0x%08x\n",event)); + + if(event & FM_PCD_PRS_DOUBLE_ECC) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC); +} + +static void PcdPrsException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, force; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + event = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pevr); + event &= GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pever); + + ASSERT_COND(event & FM_PCD_PRS_SINGLE_ECC); + + DBG(TRACE, ("parser event - 0x%08x\n",event)); + + /* clear the forced events */ + force = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pevfr); + if(force & event) + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pevfr, force & ~event); + + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->pevr, event); + + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC); +} + +static uint32_t GetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + int i; + t_FmPcdPrsLabelParams *p_Label; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE, 0); + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + ASSERT_COND(p_FmPcd->p_FmPcdPrs->currLabel < FM_PCD_PRS_NUM_OF_LABELS); + + for (i=0; i < p_FmPcd->p_FmPcdPrs->currLabel; i++) + { + p_Label = &p_FmPcd->p_FmPcdPrs->labelsTable[i]; + + if ((hdr == p_Label->hdr) && (indexPerHdr == p_Label->indexPerHdr)) + return p_Label->instructionOffset; + } + + REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Sw Parser attachment Not found")); + return (uint32_t)ILLEGAL_BASE; +} + +t_Error PrsInit(t_FmPcd *p_FmPcd) +{ + t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam; + t_FmPcdPrsRegs *p_Regs = p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + uint32_t tmpReg; + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + return E_OK; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + +#ifdef FM_PRS_MEM_ERRATA_FMAN_SW003 + { + uint32_t i; + uint32_t regsToGlobalOffset = 0x840; + uint32_t firstPortToGlobalOffset = 0x45800; + uint64_t globalAddr = PTR_TO_UINT(p_Regs) - regsToGlobalOffset; + uint32_t firstPortAddr = (uint32_t)(globalAddr - (uint64_t)firstPortToGlobalOffset); + uint32_t portSize = 0x1000; + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPcd->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + /* clear all parser memory */ + IOMemSet32(UINT_TO_PTR(globalAddr), 0x00000000, 0x800); + for(i = 0;i<16;i++) + IOMemSet32(UINT_TO_PTR(firstPortAddr+i*portSize), (uint8_t)0x00000000, (uint32_t)0x80); + } + } +#endif /* FM_PRS_MEM_ERRATA_FMAN_SW003 */ + + /**********************RPCLIM******************/ + WRITE_UINT32(p_Regs->rpclim, (uint32_t)p_Param->prsMaxParseCycleLimit); + /**********************FMPL_RPCLIM******************/ + + /* register even if no interrupts enabled, to allow future enablement */ + FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR, PcdPrsErrorException, p_FmPcd); + + /* register even if no interrupts enabled, to allow future enablement */ + FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL, PcdPrsException, p_FmPcd); + + /**********************PEVR******************/ + WRITE_UINT32(p_Regs->pevr, (FM_PCD_PRS_SINGLE_ECC | FM_PCD_PRS_PORT_IDLE_STS) ); + /**********************PEVR******************/ + + /**********************PEVER******************/ + if(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC) + { + FmEnableRamsEcc(p_FmPcd->h_Fm); + WRITE_UINT32(p_Regs->pever, FM_PCD_PRS_SINGLE_ECC); + } + else + WRITE_UINT32(p_Regs->pever, 0); + /**********************PEVER******************/ + + /**********************PERR******************/ + WRITE_UINT32(p_Regs->perr, FM_PCD_PRS_DOUBLE_ECC); + + /**********************PERR******************/ + + /**********************PERER******************/ + tmpReg = 0; + if(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC) + { + FmEnableRamsEcc(p_FmPcd->h_Fm); + tmpReg |= FM_PCD_PRS_DOUBLE_ECC; + } + WRITE_UINT32(p_Regs->perer, tmpReg); + /**********************PERER******************/ + + /**********************PPCS******************/ + WRITE_UINT32(p_Regs->ppsc, p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics); + /**********************PPCS******************/ + +#ifdef FM_PRS_L4_SHELL_ERRATA_FMANb + { + uint32_t i, j; + t_FmRevisionInfo revInfo; + uint8_t swPrsL4Patch[] = SW_PRS_L4_PATCH; + + FM_GetRevision(p_FmPcd->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)) + { + /* load sw parser L4 patch */ + for(i=0;ip_FmPcdPrs->p_SwPrsCode+ FM_PCD_PRS_SW_OFFSET/4 + i), tmpReg); + } + p_FmPcd->p_FmPcdPrs->p_CurrSwPrs = FM_PCD_PRS_SW_OFFSET/4 + p_FmPcd->p_FmPcdPrs->p_SwPrsCode+sizeof(swPrsL4Patch)/4; + } + } +#endif /* FM_PRS_L4_SHELL_ERRATA_FMANb */ + + return E_OK; +} + +void PrsFree(t_FmPcd *p_FmPcd ) +{ + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR); + /* register even if no interrupts enabled, to allow future enablement */ + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL); +} + +void PrsEnable(t_FmPcd *p_FmPcd ) +{ + t_FmPcdPrsRegs *p_Regs = p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + WRITE_UINT32(p_Regs->rpimac, GET_UINT32(p_Regs->rpimac) | FM_PCD_PRS_RPIMAC_EN); +} + +void PrsDisable(t_FmPcd *p_FmPcd ) +{ + t_FmPcdPrsRegs *p_Regs = p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + WRITE_UINT32(p_Regs->rpimac, GET_UINT32(p_Regs->rpimac) & ~FM_PCD_PRS_RPIMAC_EN); +} + +t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include) +{ + uint32_t bitMask = 0; + uint8_t prsPortId; + + SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); + + GET_FM_PCD_PRS_PORT_ID(prsPortId, hardwarePortId); + GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId); + + if(include) + p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics |= bitMask; + else + p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics &= ~bitMask; + + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->ppsc, p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics); + + return E_OK; +} + +t_Error FmPcdPrsIncludePortInStatistics(t_Handle h_FmPcd, uint8_t hardwarePortId, bool include) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdIpcPrsIncludePort prsIncludePortParams; + t_FmPcdIpcMsg msg; + t_Error err; + + SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + prsIncludePortParams.hardwarePortId = hardwarePortId; + prsIncludePortParams.include = include; + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_PRS_INC_PORT_STATS; + memcpy(msg.msgBody, &prsIncludePortParams, sizeof(prsIncludePortParams)); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(prsIncludePortParams), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + return E_OK; + } + return PrsIncludePortInStatistics(p_FmPcd, hardwarePortId, include); +} + +uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_Error err = E_OK; + t_FmPcdIpcSwPrsLable labelParams; + t_FmPcdIpcMsg msg; + uint32_t prsOffset = 0; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + labelParams.enumHdr = (uint32_t)hdr; + labelParams.indexPerHdr = indexPerHdr; + msg.msgId = FM_PCD_GET_SW_PRS_OFFSET; + memcpy(msg.msgBody, &labelParams, sizeof(labelParams)); + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(labelParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if(replyLength != sizeof(uint32_t) + sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + memcpy((uint8_t*)&prsOffset, reply.replyBody, sizeof(uint32_t)); + return prsOffset; + } + + return GetSwPrsOffset(h_FmPcd, hdr, indexPerHdr); +} + +void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPrsStatistics - guest mode!")); + return; + } + if(enable) + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->ppsc, FM_PCD_PRS_PPSC_ALL_PORTS); + else + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->ppsc, 0); + +} + +t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t *p_LoadTarget, tmpReg; + int i, j; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_SwPrs, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_HANDLE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_PrsLoadSw - guest mode!")); + + if(!p_SwPrs->override) + { + if(p_FmPcd->p_FmPcdPrs->p_CurrSwPrs > p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SW parser base must be larger than current loaded code")); + } + if(p_SwPrs->size > FM_PCD_SW_PRS_SIZE - FM_PCD_PRS_SW_TAIL_SIZE - p_SwPrs->base*2) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_SwPrs->size may not be larger than MAX_SW_PRS_CODE_SIZE")); + if(p_SwPrs->size % 4) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_SwPrs->size must be divisible by 4")); + + /* save sw parser labels */ + if(p_SwPrs->override) + p_FmPcd->p_FmPcdPrs->currLabel = 0; + if(p_FmPcd->p_FmPcdPrs->currLabel+ p_SwPrs->numOfLabels > FM_PCD_PRS_NUM_OF_LABELS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceeded number of labels allowed ")); + memcpy(&p_FmPcd->p_FmPcdPrs->labelsTable[p_FmPcd->p_FmPcdPrs->currLabel], p_SwPrs->labelsTable, p_SwPrs->numOfLabels*sizeof(t_FmPcdPrsLabelParams)); + p_FmPcd->p_FmPcdPrs->currLabel += p_SwPrs->numOfLabels; + /* load sw parser code */ + p_LoadTarget = p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4; + for(i=0;isize/4;i++) + { + tmpReg = 0; + for(j =0;j<4;j++) + { + tmpReg <<= 8; + tmpReg |= *(p_SwPrs->p_Code+i*4+j); + } + WRITE_UINT32(*(p_LoadTarget + i), tmpReg); + } + p_FmPcd->p_FmPcdPrs->p_CurrSwPrs = p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4 + p_SwPrs->size/4; + + /* copy data parameters */ + for(i=0;ip_FmPcdPrs->p_SwPrsCode+PRS_SW_DATA/4+i), p_SwPrs->swPrsDataParams[i]); + + + /* Clear last 4 bytes */ + WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+(PRS_SW_DATA-FM_PCD_PRS_SW_TAIL_SIZE)/4), 0); + + return E_OK; +} + +t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPrsMaxCycleLimit - guest mode!")); + + p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = value; + + return E_OK; +} + + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FM_PCD_PrsDumpRegs(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdIpcMsg msg; + + DECLARE_DUMP; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_PRS_DUMP_REGS; + return XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL); + } + DUMP_SUBTITLE(("\n")); + DUMP_TITLE(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs, ("FmPcdPrsRegs Regs")); + + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,rpclim); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,rpimac); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,pmeec); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,pevr); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,pever); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,pevfr); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,perr); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,perer); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,perfr); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,ppsc); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,pds); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,l2rrs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,l3rrs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,l4rrs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,srrs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,l2rres); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,l3rres); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,l4rres); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,srres); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,spcs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,spscs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,hxscs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,mrcs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,mwcs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,mrscs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,mwscs); + DUMP_VAR(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs,fcscs); + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Rtc/fm_rtc.c +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Rtc/fm_rtc.c @@ -0,0 +1,891 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_rtc.c + + @Description FM RTC driver implementation. + + @Cautions None +*//***************************************************************************/ + +#include "error_ext.h" +#include "debug_ext.h" +#include "string_ext.h" +#include "part_ext.h" +#include "xx_ext.h" +#include "ncsw_ext.h" + +#include "fm_rtc.h" +#include "fm_common.h" + + +/*****************************************************************************/ +static void SetDefaultParam(t_FmRtc *p_Rtc) +{ + t_FmRtcDriverParam *p_RtcDriverParam = p_Rtc->p_RtcDriverParam; + int i; + + p_Rtc->outputClockDivisor = DEFAULT_outputClockDivisor; + p_Rtc->p_RtcDriverParam->bypass = DEFAULT_bypass; + p_RtcDriverParam->srcClk = DEFAULT_srcClock; + p_RtcDriverParam->invertInputClkPhase = DEFAULT_invertInputClkPhase; + p_RtcDriverParam->invertOutputClkPhase = DEFAULT_invertOutputClkPhase; + p_RtcDriverParam->pulseRealign = DEFAULT_pulseRealign; + for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++) + { + p_RtcDriverParam->alarmPolarity[i] = DEFAULT_alarmPolarity; + } + for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++) + { + p_RtcDriverParam->triggerPolarity[i] = DEFAULT_triggerPolarity; + } + p_Rtc->clockPeriodNanoSec = DEFAULT_clockPeriod; /* 1 usec */ +} + +/*****************************************************************************/ +static t_Error CheckInitParameters(t_FmRtc *p_Rtc) +{ + t_FmRtcDriverParam *p_RtcDriverParam = p_Rtc->p_RtcDriverParam; + int i; + + if ((p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_EXTERNAL) && + (p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM) && + (p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_OSCILATOR)) + RETURN_ERROR(MAJOR, E_INVALID_CLOCK, ("Source clock undefined")); + + if (p_Rtc->outputClockDivisor == 0) + { + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Divisor for output clock (should be positive)")); + } + + for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++) + { + if ((p_RtcDriverParam->alarmPolarity[i] != e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW) && + (p_RtcDriverParam->alarmPolarity[i] != e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH)) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm %d signal polarity", i)); + } + } + for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++) + { + if ((p_RtcDriverParam->triggerPolarity[i] != e_FM_RTC_TRIGGER_ON_FALLING_EDGE) && + (p_RtcDriverParam->triggerPolarity[i] != e_FM_RTC_TRIGGER_ON_RISING_EDGE)) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Trigger %d signal polarity", i)); + } + } + +#ifdef FM_1588_SRC_CLK_ERRATA_FMAN1 + { + t_FmRevisionInfo revInfo; + FM_GetRevision(p_Rtc->h_Fm, &revInfo); + if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0)&& + ((p_RtcDriverParam->srcClk==e_FM_RTC_SOURCE_CLOCK_SYSTEM) && p_RtcDriverParam->invertInputClkPhase)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Can not use invertInputClkPhase when source clock is e_FM_RTC_SOURCE_CLOCK_SYSTEM")); + } +#endif /* FM_1588_SRC_CLK_ERRATA_FMAN1 */ + + return E_OK; +} + +/*****************************************************************************/ +static void RtcExceptions(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + t_FmRtcMemMap *p_MemMap; + register uint32_t events; + + ASSERT_COND(p_Rtc); + p_MemMap = p_Rtc->p_MemMap; + + /* Get valid events */ + events = GET_UINT32(p_MemMap->tmr_tevent); + events &= GET_UINT32(p_MemMap->tmr_temask); + + /* Clear event bits */ + WRITE_UINT32(p_MemMap->tmr_tevent, events); + + if (events & TMR_TEVENT_ALM1) + { + if(p_Rtc->alarmParams[0].clearOnExpiration) + { + WRITE_UINT32(p_MemMap->tmr_alarm[0].tmr_alarm_l, 0); + WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) & ~TMR_TEVENT_ALM1); + } + ASSERT_COND(p_Rtc->alarmParams[0].f_AlarmCallback); + p_Rtc->alarmParams[0].f_AlarmCallback(p_Rtc->h_App, 0); + } + if (events & TMR_TEVENT_ALM2) + { + if(p_Rtc->alarmParams[1].clearOnExpiration) + { + WRITE_UINT32(p_MemMap->tmr_alarm[1].tmr_alarm_l, 0); + WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) & ~TMR_TEVENT_ALM2); + } + ASSERT_COND(p_Rtc->alarmParams[1].f_AlarmCallback); + p_Rtc->alarmParams[1].f_AlarmCallback(p_Rtc->h_App, 1); + } + if (events & TMR_TEVENT_PP1) + { + ASSERT_COND(p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback); + p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback(p_Rtc->h_App, 0); + } + if (events & TMR_TEVENT_PP2) + { + ASSERT_COND(p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback); + p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback(p_Rtc->h_App, 1); + } + if (events & TMR_TEVENT_ETS1) + { + ASSERT_COND(p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback); + p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback(p_Rtc->h_App, 0); + } + if (events & TMR_TEVENT_ETS2) + { + ASSERT_COND(p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback); + p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback(p_Rtc->h_App, 1); + } +} + + +/*****************************************************************************/ +t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam) +{ + t_FmRtc *p_Rtc; + + SANITY_CHECK_RETURN_VALUE(p_FmRtcParam, E_NULL_POINTER, NULL); + + /* Allocate memory for the FM RTC driver parameters */ + p_Rtc = (t_FmRtc *)XX_Malloc(sizeof(t_FmRtc)); + if (!p_Rtc) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver structure")); + return NULL; + } + + memset(p_Rtc, 0, sizeof(t_FmRtc)); + + /* Allocate memory for the FM RTC driver parameters */ + p_Rtc->p_RtcDriverParam = (t_FmRtcDriverParam *)XX_Malloc(sizeof(t_FmRtcDriverParam)); + if (!p_Rtc->p_RtcDriverParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver parameters")); + XX_Free(p_Rtc); + return NULL; + } + + memset(p_Rtc->p_RtcDriverParam, 0, sizeof(t_FmRtcDriverParam)); + + /* Store RTC configuration parameters */ + p_Rtc->h_Fm = p_FmRtcParam->h_Fm; + + /* Set default RTC configuration parameters */ + SetDefaultParam(p_Rtc); + + /* Store RTC parameters in the RTC control structure */ + p_Rtc->p_MemMap = (t_FmRtcMemMap *)UINT_TO_PTR(p_FmRtcParam->baseAddress); + p_Rtc->h_App = p_FmRtcParam->h_App; + + return p_Rtc; +} + +/*****************************************************************************/ +t_Error FM_RTC_Init(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + t_FmRtcDriverParam *p_RtcDriverParam; + t_FmRtcMemMap *p_MemMap; + uint32_t freqCompensation; + uint32_t tmrCtrl; + int i; + uint64_t tmpDouble; + + p_RtcDriverParam = p_Rtc->p_RtcDriverParam; + p_MemMap = p_Rtc->p_MemMap; + + if(CheckInitParameters(p_Rtc)!=E_OK) + RETURN_ERROR(MAJOR, E_CONFLICT, + ("Init Parameters are not Valid")); + + /* TODO A check must be added here, that no timestamping MAC's + * are working in this stage. */ + WRITE_UINT32(p_MemMap->tmr_ctrl, TMR_CTRL_TMSR); + XX_UDelay(10); + WRITE_UINT32(p_MemMap->tmr_ctrl, 0); + + /* Set the source clock */ + switch (p_RtcDriverParam->srcClk) + { + case e_FM_RTC_SOURCE_CLOCK_SYSTEM: + tmrCtrl = TMR_CTRL_CKSEL_MAC_CLK; + break; + case e_FM_RTC_SOURCE_CLOCK_OSCILATOR: + tmrCtrl = TMR_CTRL_CKSEL_OSC_CLK; + break; + default: + /* Use a clock from the External TMR reference clock.*/ + tmrCtrl = TMR_CTRL_CKSEL_EXT_CLK; + break; + } + + /* whatever period the user picked, the timestamp will advance in '1' every time + * the period passed. */ + tmrCtrl |= ((1 << TMR_CTRL_TCLK_PERIOD_SHIFT) & TMR_CTRL_TCLK_PERIOD_MASK); + + if (p_RtcDriverParam->invertInputClkPhase) + tmrCtrl |= TMR_CTRL_CIPH; + if (p_RtcDriverParam->invertOutputClkPhase) + tmrCtrl |= TMR_CTRL_COPH; + + for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++) + { + if (p_RtcDriverParam->alarmPolarity[i] == e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW) + tmrCtrl |= (TMR_CTRL_ALMP1 >> i); + } + + for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++) + if (p_RtcDriverParam->triggerPolarity[i] == e_FM_RTC_TRIGGER_ON_FALLING_EDGE) + tmrCtrl |= (TMR_CTRL_ETEP1 << i); + + if (!p_RtcDriverParam->timerSlaveMode && p_Rtc->p_RtcDriverParam->bypass) + tmrCtrl |= TMR_CTRL_BYP; + + WRITE_UINT32(p_MemMap->tmr_ctrl, tmrCtrl); + + for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++) + { + /* Clear TMR_ALARM registers */ + WRITE_UINT32(p_MemMap->tmr_alarm[i].tmr_alarm_l, 0xFFFFFFFF); + WRITE_UINT32(p_MemMap->tmr_alarm[i].tmr_alarm_h, 0xFFFFFFFF); + } + + /* Clear TMR_TEVENT */ + WRITE_UINT32(p_MemMap->tmr_tevent, TMR_TEVENT_ALL); + + /* Initialize TMR_TEMASK */ + WRITE_UINT32(p_MemMap->tmr_temask, 0); + + + /* find source clock frequency in Mhz */ + if (p_Rtc->p_RtcDriverParam->srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM) + p_Rtc->srcClkFreqMhz = p_Rtc->p_RtcDriverParam->extSrcClkFreq; + else + p_Rtc->srcClkFreqMhz = (uint32_t)(FmGetClockFreq(p_Rtc->h_Fm)/2); + + /* if timer in Master mode Initialize TMR_CTRL */ + /* We want the counter (TMR_CNT) to count in nano-seconds */ + if (!p_RtcDriverParam->timerSlaveMode && p_Rtc->p_RtcDriverParam->bypass) + { + p_Rtc->clockPeriodNanoSec = (1000 / p_Rtc->srcClkFreqMhz); + } + else + { + /* Initialize TMR_ADD with the initial frequency compensation value: + freqCompensation = (2^32 / frequency ratio) */ + /* frequency ratio = sorce clock/rtc clock = + * (p_Rtc->srcClkFreqMhz*1000000))/ 1/(p_Rtc->clockPeriodNanoSec * 1000000000) */ + freqCompensation = (uint32_t)DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000, + p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz); + WRITE_UINT32(p_MemMap->tmr_add, freqCompensation); + } + /* check the legality of the relation between source and destination clocks */ + /* should be larger than 1.0001 */ + tmpDouble = 10000 * (uint64_t)p_Rtc->clockPeriodNanoSec * (uint64_t)p_Rtc->srcClkFreqMhz; + if((tmpDouble) <= 10001) + RETURN_ERROR(MAJOR, E_CONFLICT, + ("Invalid relation between source and destination clocks. Should be larger than 1.0001")); + + + for (i=0; i < 2; i++) + /* Clear TMR_FIPER registers */ + WRITE_UINT32(p_MemMap->tmr_fiper[i], 0xFFFFFFFF); + + /* Initialize TMR_PRSC */ + WRITE_UINT32(p_MemMap->tmr_prsc, p_Rtc->outputClockDivisor); + + /* Clear TMR_OFF */ + WRITE_UINT32(p_MemMap->tmr_off_l, 0); + WRITE_UINT32(p_MemMap->tmr_off_h, 0); + + /* Register the FM RTC interrupt */ + FmRegisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL, RtcExceptions , p_Rtc); + + /* Free parameters structures */ + XX_Free(p_Rtc->p_RtcDriverParam); + p_Rtc->p_RtcDriverParam = NULL; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_Free(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + + if (p_Rtc->p_RtcDriverParam) + { + XX_Free(p_Rtc->p_RtcDriverParam); + } + else + { + FM_RTC_Disable(h_FmRtc); + } + + /* Unregister FM RTC interrupt */ + FmUnregisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL); + XX_Free(p_Rtc); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc, + e_FmSrcClk srcClk, + uint32_t freqInMhz) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->srcClk = srcClk; + if(srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM) + p_Rtc->p_RtcDriverParam->extSrcClkFreq = freqInMhz; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->clockPeriodNanoSec = period; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->bypass = enabled; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->invertInputClkPhase = inverted; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->invertOutputClkPhase = inverted; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->outputClockDivisor = divisor; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->pulseRealign = enable; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc, + uint8_t alarmId, + e_FmRtcAlarmPolarity alarmPolarity) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (alarmId >= FM_RTC_NUM_OF_ALARMS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID")); + } + + p_Rtc->p_RtcDriverParam->alarmPolarity[alarmId] = alarmPolarity; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc, + uint8_t triggerId, + e_FmRtcTriggerPolarity triggerPolarity) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID")); + } + + p_Rtc->p_RtcDriverParam->triggerPolarity[triggerId] = triggerPolarity; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint32_t tmrCtrl; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + tmrCtrl = GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl); + + /* TODO A check must be added here, that no timestamping MAC's + * are working in this stage. */ + if (resetClock) + { + WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, (tmrCtrl | TMR_CTRL_TMSR)); + + XX_UDelay(10); + /* Clear TMR_OFF */ + WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_l, 0); + WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_h, 0); + } + + WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, (tmrCtrl | TMR_CTRL_TE)); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_Disable(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint32_t tmrCtrl; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* TODO A check must be added here, that no timestamping MAC's + * are working in this stage. */ + tmrCtrl = GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl); + WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, (tmrCtrl & ~(TMR_CTRL_TE))); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* TMR_OFF_L must be written first */ + WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_l, (uint32_t)offset); + WRITE_UINT32(p_Rtc->p_MemMap->tmr_off_h, (uint32_t)(offset >> 32)); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + t_FmRtcMemMap *p_MemMap; + uint32_t tmpReg; + uint64_t tmpAlarm; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_MemMap = p_Rtc->p_MemMap; + + if (p_FmRtcAlarmParams->alarmId >= FM_RTC_NUM_OF_ALARMS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID")); + } + + if(p_FmRtcAlarmParams->alarmTime < p_Rtc->clockPeriodNanoSec) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm time must be equal or larger than RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec)); + if(p_FmRtcAlarmParams->alarmTime % (uint64_t)p_Rtc->clockPeriodNanoSec) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm time must be a multiple of RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec)); + tmpAlarm = p_FmRtcAlarmParams->alarmTime/(uint64_t)p_Rtc->clockPeriodNanoSec; + + /* TMR_ALARM_L must be written first */ + WRITE_UINT32(p_MemMap->tmr_alarm[p_FmRtcAlarmParams->alarmId].tmr_alarm_l, (uint32_t)tmpAlarm); + WRITE_UINT32(p_MemMap->tmr_alarm[p_FmRtcAlarmParams->alarmId].tmr_alarm_h, + (uint32_t)(tmpAlarm >> 32)); + + if (p_FmRtcAlarmParams->f_AlarmCallback) + { + p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].f_AlarmCallback = p_FmRtcAlarmParams->f_AlarmCallback; + p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].clearOnExpiration = p_FmRtcAlarmParams->clearOnExpiration; + + if(p_FmRtcAlarmParams->alarmId == 0) + tmpReg = TMR_TEVENT_ALM1; + else + tmpReg = TMR_TEVENT_ALM2; + WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) | tmpReg); + } + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + t_FmRtcMemMap *p_MemMap; + uint32_t tmpReg; + uint64_t tmpFiper; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_MemMap = p_Rtc->p_MemMap; + + if (p_FmRtcPeriodicPulseParams->periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID")); + } + if(GET_UINT32(p_MemMap->tmr_ctrl) & TMR_CTRL_TE) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Can't set Periodic pulse when RTC is enabled.")); + if(p_FmRtcPeriodicPulseParams->periodicPulsePeriod < p_Rtc->clockPeriodNanoSec) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse must be equal or larger than RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec)); + if(p_FmRtcPeriodicPulseParams->periodicPulsePeriod % (uint64_t)p_Rtc->clockPeriodNanoSec) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse must be a multiple of RTC period - %d nanoseconds", p_Rtc->clockPeriodNanoSec)); + tmpFiper = p_FmRtcPeriodicPulseParams->periodicPulsePeriod/(uint64_t)p_Rtc->clockPeriodNanoSec; + if(tmpFiper & 0xffffffff00000000LL) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse/RTC Period must be smaller than 4294967296", p_Rtc->clockPeriodNanoSec)); + + WRITE_UINT32(p_MemMap->tmr_fiper[p_FmRtcPeriodicPulseParams->periodicPulseId], (uint32_t)tmpFiper); + + if (p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback) + { + p_Rtc->periodicPulseParams[p_FmRtcPeriodicPulseParams->periodicPulseId].f_PeriodicPulseCallback = + p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback; + + if(p_FmRtcPeriodicPulseParams->periodicPulseId == 0) + tmpReg = TMR_TEVENT_PP1; + else + tmpReg = TMR_TEVENT_PP2; + WRITE_UINT32(p_MemMap->tmr_temask, GET_UINT32(p_MemMap->tmr_temask) | tmpReg); + } + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID")); + } + + p_Rtc->periodicPulseParams[periodicPulseId].f_PeriodicPulseCallback = NULL; + + if(periodicPulseId == 0) + tmpReg = TMR_TEVENT_PP1; + else + tmpReg = TMR_TEVENT_PP2; + WRITE_UINT32(p_Rtc->p_MemMap->tmr_temask, GET_UINT32(p_Rtc->p_MemMap->tmr_temask) & ~tmpReg); + + if (GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & TMR_CTRL_FS) + WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & ~TMR_CTRL_FS); + + WRITE_UINT32(p_Rtc->p_MemMap->tmr_fiper[periodicPulseId], 0xFFFFFFFF); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (p_FmRtcExternalTriggerParams->externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID")); + } + + if (p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback) + { + p_Rtc->externalTriggerParams[p_FmRtcExternalTriggerParams->externalTriggerId].f_ExternalTriggerCallback = p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback; + if(p_FmRtcExternalTriggerParams->externalTriggerId == 0) + tmpReg = TMR_TEVENT_ETS1; + else + tmpReg = TMR_TEVENT_ETS2; + WRITE_UINT32(p_Rtc->p_MemMap->tmr_temask, GET_UINT32(p_Rtc->p_MemMap->tmr_temask) | tmpReg); + } + + if(p_FmRtcExternalTriggerParams->usePulseAsInput) + { + if(p_FmRtcExternalTriggerParams->externalTriggerId == 0) + tmpReg = TMR_CTRL_PP1L; + else + tmpReg = TMR_CTRL_PP2L; + WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) | tmpReg); + } + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t externalTriggerId) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID")); + + p_Rtc->externalTriggerParams[externalTriggerId].f_ExternalTriggerCallback = NULL; + + if(externalTriggerId == 0) + tmpReg = TMR_TEVENT_ETS1; + else + tmpReg = TMR_TEVENT_ETS2; + WRITE_UINT32(p_Rtc->p_MemMap->tmr_temask, GET_UINT32(p_Rtc->p_MemMap->tmr_temask) & ~tmpReg); + + if(externalTriggerId == 0) + tmpReg = TMR_CTRL_PP1L; + else + tmpReg = TMR_CTRL_PP2L; + + if (GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & tmpReg) + WRITE_UINT32(p_Rtc->p_MemMap->tmr_ctrl, GET_UINT32(p_Rtc->p_MemMap->tmr_ctrl) & ~tmpReg); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc, + uint8_t triggerId, + uint64_t *p_TimeStamp) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint64_t timeStamp; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID")); + } + + timeStamp = (uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_etts[triggerId].tmr_etts_l); + timeStamp |= ((uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_etts[triggerId].tmr_etts_h) << 32); + + timeStamp = timeStamp*p_Rtc->clockPeriodNanoSec; + *p_TimeStamp = timeStamp; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint64_t time; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* TMR_CNT_L must be read first to get an accurate value */ + time = (uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_cnt_l); + time |= ((uint64_t)GET_UINT32(p_Rtc->p_MemMap->tmr_cnt_h) << 32); + + time = time*p_Rtc->clockPeriodNanoSec; + + *p_Ts = time; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + ts = ts/p_Rtc->clockPeriodNanoSec; + /* TMR_CNT_L must be written first to get an accurate value */ + WRITE_UINT32(p_Rtc->p_MemMap->tmr_cnt_l, (uint32_t)ts); + WRITE_UINT32(p_Rtc->p_MemMap->tmr_cnt_h, (uint32_t)(ts >> 32)); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + *p_Compensation = (uint32_t) + DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000, + p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* set the new freqCompensation */ + WRITE_UINT32(p_Rtc->p_MemMap->tmr_add, freqCompensation); + + return E_OK; +} + +/*****************************************************************************/ +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FM_RTC_DumpRegs(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + t_FmRtcMemMap *p_MemMap = p_Rtc->p_MemMap; + int i = 0; + + DECLARE_DUMP; + + if (p_MemMap) + { + + DUMP_TITLE(p_MemMap, ("RTC:")); + DUMP_VAR(p_MemMap, tmr_id); + DUMP_VAR(p_MemMap, tmr_id2); + DUMP_VAR(p_MemMap, tmr_ctrl); + DUMP_VAR(p_MemMap, tmr_tevent); + DUMP_VAR(p_MemMap, tmr_temask); + DUMP_VAR(p_MemMap, tmr_cnt_h); + DUMP_VAR(p_MemMap, tmr_cnt_l); + DUMP_VAR(p_MemMap, tmr_ctrl); + DUMP_VAR(p_MemMap, tmr_add); + DUMP_VAR(p_MemMap, tmr_acc); + DUMP_VAR(p_MemMap, tmr_prsc); + DUMP_VAR(p_MemMap, tmr_off_h); + DUMP_VAR(p_MemMap, tmr_off_l); + + DUMP_SUBSTRUCT_ARRAY(i, 2) + { + DUMP_VAR(p_MemMap, tmr_alarm[i].tmr_alarm_h); + DUMP_VAR(p_MemMap, tmr_alarm[i].tmr_alarm_l); + } + DUMP_SUBSTRUCT_ARRAY(i, 2) + { + DUMP_VAR(p_MemMap, tmr_fiper[i]); + DUMP_VAR(p_MemMap, tmr_fiper[i]); + } + DUMP_SUBSTRUCT_ARRAY(i, 2) + { + DUMP_VAR(p_MemMap, tmr_etts[i].tmr_etts_l); + DUMP_VAR(p_MemMap, tmr_etts[i].tmr_etts_l); + } + } + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Rtc/fm_rtc.h +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Rtc/fm_rtc.h @@ -0,0 +1,217 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_rtc.h + + @Description Memory map and internal definitions for FM RTC IEEE1588 Timer driver. + + @Cautions None +*//***************************************************************************/ + +#ifndef __FM_RTC_H__ +#define __FM_RTC_H__ + +#include "std_ext.h" +#include "fm_rtc_ext.h" + + +#define __ERR_MODULE__ MODULE_FM_RTC + +/* General definitions */ + +#define NANOSEC_PER_ONE_HZ_TICK 1000000000 +#define MIN_RTC_CLK_FREQ_HZ 1000 +#define MHz 1000000 + +#define ACCUMULATOR_OVERFLOW ((uint64_t)(1LL << 32)) + +/* RTC default values */ +#define DEFAULT_srcClock e_FM_RTC_SOURCE_CLOCK_SYSTEM +#define DEFAULT_bypass FALSE +#define DEFAULT_invertInputClkPhase FALSE +#define DEFAULT_invertOutputClkPhase FALSE +#define DEFAULT_outputClockDivisor 0x00000002 +#define DEFAULT_alarmPolarity e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH +#define DEFAULT_triggerPolarity e_FM_RTC_TRIGGER_ON_FALLING_EDGE +#define DEFAULT_pulseRealign FALSE +#define DEFAULT_clockPeriod 1000 + +/* FM RTC Registers definitions */ +#define TMR_CTRL_ALMP1 0x80000000 +#define TMR_CTRL_ALMP2 0x40000000 +#define TMR_CTRL_FS 0x10000000 +#define TMR_CTRL_PP1L 0x08000000 +#define TMR_CTRL_PP2L 0x04000000 +#define TMR_CTRL_TCLK_PERIOD_MASK 0x03FF0000 +#define TMR_CTRL_FRD 0x00004000 +#define TMR_CTRL_SLV 0x00002000 +#define TMR_CTRL_ETEP1 0x00000100 +#define TMR_CTRL_COPH 0x00000080 +#define TMR_CTRL_CIPH 0x00000040 +#define TMR_CTRL_TMSR 0x00000020 +#define TMR_CTRL_DBG 0x00000010 +#define TMR_CTRL_BYP 0x00000008 +#define TMR_CTRL_TE 0x00000004 +#define TMR_CTRL_CKSEL_OSC_CLK 0x00000003 +#define TMR_CTRL_CKSEL_MAC_CLK 0x00000001 +#define TMR_CTRL_CKSEL_EXT_CLK 0x00000000 +#define TMR_CTRL_TCLK_PERIOD_SHIFT 16 + +#define TMR_TEVENT_ETS2 0x02000000 +#define TMR_TEVENT_ETS1 0x01000000 +#define TMR_TEVENT_ALM2 0x00020000 +#define TMR_TEVENT_ALM1 0x00010000 +#define TMR_TEVENT_PP1 0x00000080 +#define TMR_TEVENT_PP2 0x00000040 +#define TMR_TEVENT_PP3 0x00000020 +#define TMR_TEVENT_ALL (TMR_TEVENT_ETS2 | TMR_TEVENT_ETS1 | \ + TMR_TEVENT_ALM2 | TMR_TEVENT_ALM1 | \ + TMR_TEVENT_PP1 | TMR_TEVENT_PP2 | TMR_TEVENT_PP3) + +#define TMR_PRSC_OCK_MASK 0x0000FFFF + + +/**************************************************************************//** + @Description Memory Mapped Registers +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ +#define MEM_MAP_START + +/**************************************************************************//** + @Description FM RTC timer alarm +*//***************************************************************************/ +typedef _Packed struct t_TmrAlaram +{ + volatile uint32_t tmr_alarm_h; /**< */ + volatile uint32_t tmr_alarm_l; /**< */ +} _PackedType t_TmrAlaram; + +/**************************************************************************//** + @Description FM RTC timer Ex trigger +*//***************************************************************************/ +typedef _Packed struct t_TmrExtTrigger +{ + volatile uint32_t tmr_etts_h; /**< */ + volatile uint32_t tmr_etts_l; /**< */ +} _PackedType t_TmrExtTrigger; + +typedef _Packed struct +{ + volatile uint32_t tmr_id; /* Module ID and version register */ + volatile uint32_t tmr_id2; /* Module ID and configuration register */ + volatile uint32_t PTP_RESERVED1[30]; + volatile uint32_t tmr_ctrl; /* timer control register */ + volatile uint32_t tmr_tevent; /* timer event register */ + volatile uint32_t tmr_temask; /* timer event mask register */ + volatile uint32_t PTP_RESERVED2[3]; + volatile uint32_t tmr_cnt_h; /* timer counter high register */ + volatile uint32_t tmr_cnt_l; /* timer counter low register */ + volatile uint32_t tmr_add; /* timer drift compensation addend register */ + volatile uint32_t tmr_acc; /* timer accumulator register */ + volatile uint32_t tmr_prsc; /* timer prescale */ + volatile uint32_t PTP_RESERVED3; + volatile uint32_t tmr_off_h; /* timer offset high */ + volatile uint32_t tmr_off_l; /* timer offset low */ + volatile t_TmrAlaram tmr_alarm[FM_RTC_NUM_OF_ALARMS]; /* timer alarm */ + volatile uint32_t PTP_RESERVED4[2]; + volatile uint32_t tmr_fiper[FM_RTC_NUM_OF_PERIODIC_PULSES]; /* timer fixed period interval */ + volatile uint32_t PTP_RESERVED5[2]; + volatile t_TmrExtTrigger tmr_etts[FM_RTC_NUM_OF_EXT_TRIGGERS]; /*time stamp general purpose external */ + volatile uint32_t PTP_RESERVED6[3]; +} _PackedType t_FmRtcMemMap; + +#define MEM_MAP_END +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/**************************************************************************//** + @Description RTC FM driver parameters structure. +*//***************************************************************************/ +typedef struct t_FmRtcDriverParam +{ + t_Handle h_Fm; /**< */ + e_FmSrcClk srcClk; /**< */ + uint32_t extSrcClkFreq; /**< */ + uint32_t rtcFreqHz; /**< */ + bool timerSlaveMode; /*Slave/Master Mode*/ + bool invertInputClkPhase; + bool invertOutputClkPhase; + uint32_t eventsMask; + bool bypass; /**< Indicates if frequency compensation is bypassed */ + bool pulseRealign; + e_FmRtcAlarmPolarity alarmPolarity[FM_RTC_NUM_OF_ALARMS]; + e_FmRtcTriggerPolarity triggerPolarity[FM_RTC_NUM_OF_EXT_TRIGGERS]; +} t_FmRtcDriverParam; + +typedef struct t_FmRtcAlarm +{ + t_FmRtcExceptionsCallback *f_AlarmCallback; + bool clearOnExpiration; +} t_FmRtcAlarm; + +typedef struct t_FmRtcPeriodicPulse +{ + t_FmRtcExceptionsCallback *f_PeriodicPulseCallback; +} t_FmRtcPeriodicPulse; + +typedef struct t_FmRtcExternalTrigger +{ + t_FmRtcExceptionsCallback *f_ExternalTriggerCallback; +} t_FmRtcExternalTrigger; + + +/**************************************************************************//** + @Description RTC FM driver control structure. +*//***************************************************************************/ +typedef struct t_FmRtc +{ + t_Part *p_Part; /**< Pointer to the integration device */ + t_Handle h_Fm; + t_Handle h_App; /**< Application handle */ + t_FmRtcMemMap *p_MemMap; /**< Pointer to RTC memory map */ + uint32_t clockPeriodNanoSec; /**< RTC clock period in nano-seconds (for FS mode) */ + uint32_t srcClkFreqMhz; + uint16_t outputClockDivisor; /**< Output clock divisor (for FS mode) */ + t_FmRtcAlarm alarmParams[FM_RTC_NUM_OF_ALARMS]; + t_FmRtcPeriodicPulse periodicPulseParams[FM_RTC_NUM_OF_PERIODIC_PULSES]; + t_FmRtcExternalTrigger externalTriggerParams[FM_RTC_NUM_OF_EXT_TRIGGERS]; + t_FmRtcDriverParam *p_RtcDriverParam; /**< RTC Driver parameters (for Init phase) */ +} t_FmRtc; + + +#endif /* __FM_RTC_H__ */ --- linux-3.13.0.orig/drivers/net/dpa/NetCommSw/Peripherals/FM/Rtc/Makefile +++ linux-3.13.0/drivers/net/dpa/NetCommSw/Peripherals/FM/Rtc/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/dpa/NetCommSw/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/dpa/NetCommSw/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-RTC.o + +fsl-ncsw-RTC-objs := fm_rtc.o --- linux-3.13.0.orig/drivers/net/ethernet/Makefile +++ linux-3.13.0/drivers/net/ethernet/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/ obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/ obj-$(CONFIG_NET_VENDOR_AMD) += amd/ +obj-$(CONFIG_NET_XGENE) += apm/ obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ obj-$(CONFIG_NET_VENDOR_ARC) += arc/ obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ --- linux-3.13.0.orig/drivers/net/ethernet/Kconfig +++ linux-3.13.0/drivers/net/ethernet/Kconfig @@ -17,6 +17,7 @@ config SUNGEM_PHY tristate +source "drivers/net/ethernet/apm/Kconfig" source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/adaptec/Kconfig" source "drivers/net/ethernet/aeroflex/Kconfig" --- linux-3.13.0.orig/drivers/net/ethernet/sfc/efx.h +++ linux-3.13.0/drivers/net/ethernet/sfc/efx.h @@ -66,6 +66,9 @@ #define EFX_RXQ_MIN_ENT 128U #define EFX_TXQ_MIN_ENT(efx) (2 * efx_tx_max_skb_descs(efx)) +#define EFX_TXQ_MAX_ENT(efx) (EFX_WORKAROUND_35388(efx) ? \ + EFX_MAX_DMAQ_SIZE / 2 : EFX_MAX_DMAQ_SIZE) + /* Filters */ /** --- linux-3.13.0.orig/drivers/net/ethernet/sfc/ethtool.c +++ linux-3.13.0/drivers/net/ethernet/sfc/ethtool.c @@ -583,7 +583,7 @@ struct efx_nic *efx = netdev_priv(net_dev); ring->rx_max_pending = EFX_MAX_DMAQ_SIZE; - ring->tx_max_pending = EFX_MAX_DMAQ_SIZE; + ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx); ring->rx_pending = efx->rxq_entries; ring->tx_pending = efx->txq_entries; } @@ -596,7 +596,7 @@ if (ring->rx_mini_pending || ring->rx_jumbo_pending || ring->rx_pending > EFX_MAX_DMAQ_SIZE || - ring->tx_pending > EFX_MAX_DMAQ_SIZE) + ring->tx_pending > EFX_TXQ_MAX_ENT(efx)) return -EINVAL; if (ring->rx_pending < EFX_RXQ_MIN_ENT) { --- linux-3.13.0.orig/drivers/net/ethernet/sfc/ptp.c +++ linux-3.13.0/drivers/net/ethernet/sfc/ptp.c @@ -1360,6 +1360,13 @@ struct efx_ptp_data *ptp = efx->ptp_data; int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE); + if (!ptp) { + if (net_ratelimit()) + netif_warn(efx, drv, efx->net_dev, + "Received PTP event but PTP not set up\n"); + return; + } + if (!ptp->enabled) return; --- linux-3.13.0.orig/drivers/net/ethernet/broadcom/tg3.h +++ linux-3.13.0/drivers/net/ethernet/broadcom/tg3.h @@ -2601,7 +2601,11 @@ #define RXD_ERR_TOO_SMALL 0x00400000 #define RXD_ERR_NO_RESOURCES 0x00800000 #define RXD_ERR_HUGE_FRAME 0x01000000 -#define RXD_ERR_MASK 0xffff0000 + +#define RXD_ERR_MASK (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION | \ + RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE | \ + RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL | \ + RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME) u32 reserved; u32 opaque; --- linux-3.13.0.orig/drivers/net/ethernet/broadcom/tg3.c +++ linux-3.13.0/drivers/net/ethernet/broadcom/tg3.c @@ -326,6 +326,7 @@ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57786)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791), .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795), @@ -6827,8 +6828,7 @@ work_mask |= opaque_key; - if ((desc->err_vlan & RXD_ERR_MASK) != 0 && - (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) { + if (desc->err_vlan & RXD_ERR_MASK) { drop_it: tg3_recycle_rx(tnapi, tpr, opaque_key, desc_idx, *post_ptr); @@ -13965,12 +13965,12 @@ tg3_netif_stop(tp); + tg3_set_mtu(dev, tp, new_mtu); + tg3_full_lock(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - tg3_set_mtu(dev, tp, new_mtu); - /* Reset PHY, otherwise the read DMA engine will be in a mode that * breaks all requests to 256 bytes. */ --- linux-3.13.0.orig/drivers/net/ethernet/ibm/ibmveth.c +++ linux-3.13.0/drivers/net/ethernet/ibm/ibmveth.c @@ -523,10 +523,21 @@ return rc; } +static u64 ibmveth_encode_mac_addr(u8 *mac) +{ + int i; + u64 encoded = 0; + + for (i = 0; i < ETH_ALEN; i++) + encoded = (encoded << 8) | mac[i]; + + return encoded; +} + static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev_priv(netdev); - u64 mac_address = 0; + u64 mac_address; int rxq_entries = 1; unsigned long lpar_rc; int rc; @@ -580,8 +591,7 @@ adapter->rx_queue.num_slots = rxq_entries; adapter->rx_queue.toggle = 1; - memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); - mac_address = mac_address >> 16; + mac_address = ibmveth_encode_mac_addr(netdev->dev_addr); rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len; @@ -1184,8 +1194,8 @@ /* add the addresses to the filter table */ netdev_for_each_mc_addr(ha, netdev) { /* add the multicast address to the filter table */ - unsigned long mcast_addr = 0; - memcpy(((char *)&mcast_addr)+2, ha->addr, ETH_ALEN); + u64 mcast_addr; + mcast_addr = ibmveth_encode_mac_addr(ha->addr); lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address, IbmVethMcastAddFilter, mcast_addr); @@ -1369,9 +1379,6 @@ netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16); - adapter->mac_addr = 0; - memcpy(&adapter->mac_addr, mac_addr_p, ETH_ALEN); - netdev->irq = dev->irq; netdev->netdev_ops = &ibmveth_netdev_ops; netdev->ethtool_ops = &netdev_ethtool_ops; @@ -1380,7 +1387,7 @@ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; netdev->features |= netdev->hw_features; - memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); + memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN); for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) { struct kobject *kobj = &adapter->rx_buff_pool[i].kobj; --- linux-3.13.0.orig/drivers/net/ethernet/ibm/ibmveth.h +++ linux-3.13.0/drivers/net/ethernet/ibm/ibmveth.h @@ -139,7 +139,6 @@ struct napi_struct napi; struct net_device_stats stats; unsigned int mcastFilterSize; - unsigned long mac_addr; void * buffer_list_addr; void * filter_list_addr; dma_addr_t buffer_list_dma; --- linux-3.13.0.orig/drivers/net/ethernet/freescale/xgmac_mdio.c +++ linux-3.13.0/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -32,6 +32,10 @@ __be32 mdio_addr; /* MDIO address */ } __packed; +/* Taken from memac_mdio.c */ +#define MDIO_STAT_ENC (1 << 6) +#define MDIO_STAT_HOLD_15_CLK (7 << 2) + #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) #define MDIO_STAT_BSY (1 << 0) #define MDIO_STAT_RD_ER (1 << 1) @@ -91,26 +95,39 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) { struct tgec_mdio_controller __iomem *regs = bus->priv; - uint16_t dev_addr = regnum >> 16; + uint16_t dev_addr; + u32 mdio_ctl, mdio_stat; int ret; - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); + mdio_stat = in_be32(®s->mdio_stat); + if (regnum & MII_ADDR_C45) { + /* Clause 45 (ie 10G) */ + dev_addr = (regnum >> 16) & 0x1f; + mdio_stat |= MDIO_STAT_ENC | MDIO_STAT_HOLD_15_CLK; + } else { + /* Clause 22 (ie 1G) */ + dev_addr = regnum & 0x1f; + mdio_stat &= ~MDIO_STAT_ENC; + } + + out_be32(®s->mdio_stat, mdio_stat); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) return ret; /* Set the port and dev addr */ - out_be32(®s->mdio_ctl, - MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr)); + mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); + out_be32(®s->mdio_ctl, mdio_ctl); /* Set the register address */ - out_be32(®s->mdio_addr, regnum & 0xffff); + if (regnum & MII_ADDR_C45) { + out_be32(®s->mdio_addr, regnum & 0xffff); - ret = xgmac_wait_until_free(&bus->dev, regs); - if (ret) - return ret; + ret = xgmac_wait_until_free(&bus->dev, regs); + if (ret) + return ret; + } /* Write the value to the register */ out_be32(®s->mdio_data, MDIO_DATA(value)); @@ -130,13 +147,22 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) { struct tgec_mdio_controller __iomem *regs = bus->priv; - uint16_t dev_addr = regnum >> 16; + uint16_t dev_addr; + uint32_t mdio_stat; uint32_t mdio_ctl; uint16_t value; int ret; - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); + mdio_stat = in_be32(®s->mdio_stat); + if (regnum & MII_ADDR_C45) { + dev_addr = (regnum >> 16) & 0x1f; + mdio_stat |= MDIO_STAT_ENC | MDIO_STAT_HOLD_15_CLK; + } else { + dev_addr = regnum & 0x1f; + mdio_stat = ~MDIO_STAT_ENC; + } + + out_be32(®s->mdio_stat, mdio_stat); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) @@ -147,11 +173,13 @@ out_be32(®s->mdio_ctl, mdio_ctl); /* Set the register address */ - out_be32(®s->mdio_addr, regnum & 0xffff); + if (regnum & MII_ADDR_C45) { + out_be32(®s->mdio_addr, regnum & 0xffff); - ret = xgmac_wait_until_free(&bus->dev, regs); - if (ret) - return ret; + ret = xgmac_wait_until_free(&bus->dev, regs); + if (ret) + return ret; + } /* Initiate the read */ out_be32(®s->mdio_ctl, mdio_ctl | MDIO_CTL_READ); @@ -162,7 +190,7 @@ /* Return all Fs if nothing was there */ if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) { - dev_err(&bus->dev, "MDIO read error\n"); + dev_dbg(&bus->dev, "MDIO read error\n"); return 0xffff; } @@ -181,7 +209,7 @@ mutex_lock(&bus->mdio_lock); /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); + clrbits32(®s->mdio_stat, MDIO_STAT_ENC); ret = xgmac_wait_until_free(&bus->dev, regs); @@ -256,6 +284,9 @@ { .compatible = "fsl,fman-xmdio", }, + { + .compatible = "fsl,fman-memac-mdio", + }, {}, }; MODULE_DEVICE_TABLE(of, xgmac_mdio_match); --- linux-3.13.0.orig/drivers/net/ethernet/marvell/mvneta.c +++ linux-3.13.0/drivers/net/ethernet/marvell/mvneta.c @@ -101,16 +101,56 @@ #define MVNETA_CPU_RXQ_ACCESS_ALL_MASK 0x000000ff #define MVNETA_CPU_TXQ_ACCESS_ALL_MASK 0x0000ff00 #define MVNETA_RXQ_TIME_COAL_REG(q) (0x2580 + ((q) << 2)) + +/* Exception Interrupt Port/Queue Cause register */ + #define MVNETA_INTR_NEW_CAUSE 0x25a0 -#define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) #define MVNETA_INTR_NEW_MASK 0x25a4 + +/* bits 0..7 = TXQ SENT, one bit per queue. + * bits 8..15 = RXQ OCCUP, one bit per queue. + * bits 16..23 = RXQ FREE, one bit per queue. + * bit 29 = OLD_REG_SUM, see old reg ? + * bit 30 = TX_ERR_SUM, one bit for 4 ports + * bit 31 = MISC_SUM, one bit for 4 ports + */ +#define MVNETA_TX_INTR_MASK(nr_txqs) (((1 << nr_txqs) - 1) << 0) +#define MVNETA_TX_INTR_MASK_ALL (0xff << 0) +#define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) +#define MVNETA_RX_INTR_MASK_ALL (0xff << 8) + #define MVNETA_INTR_OLD_CAUSE 0x25a8 #define MVNETA_INTR_OLD_MASK 0x25ac + +/* Data Path Port/Queue Cause Register */ #define MVNETA_INTR_MISC_CAUSE 0x25b0 #define MVNETA_INTR_MISC_MASK 0x25b4 + +#define MVNETA_CAUSE_PHY_STATUS_CHANGE BIT(0) +#define MVNETA_CAUSE_LINK_CHANGE BIT(1) +#define MVNETA_CAUSE_PTP BIT(4) + +#define MVNETA_CAUSE_INTERNAL_ADDR_ERR BIT(7) +#define MVNETA_CAUSE_RX_OVERRUN BIT(8) +#define MVNETA_CAUSE_RX_CRC_ERROR BIT(9) +#define MVNETA_CAUSE_RX_LARGE_PKT BIT(10) +#define MVNETA_CAUSE_TX_UNDERUN BIT(11) +#define MVNETA_CAUSE_PRBS_ERR BIT(12) +#define MVNETA_CAUSE_PSC_SYNC_CHANGE BIT(13) +#define MVNETA_CAUSE_SERDES_SYNC_ERR BIT(14) + +#define MVNETA_CAUSE_BMU_ALLOC_ERR_SHIFT 16 +#define MVNETA_CAUSE_BMU_ALLOC_ERR_ALL_MASK (0xF << MVNETA_CAUSE_BMU_ALLOC_ERR_SHIFT) +#define MVNETA_CAUSE_BMU_ALLOC_ERR_MASK(pool) (1 << (MVNETA_CAUSE_BMU_ALLOC_ERR_SHIFT + (pool))) + +#define MVNETA_CAUSE_TXQ_ERROR_SHIFT 24 +#define MVNETA_CAUSE_TXQ_ERROR_ALL_MASK (0xFF << MVNETA_CAUSE_TXQ_ERROR_SHIFT) +#define MVNETA_CAUSE_TXQ_ERROR_MASK(q) (1 << (MVNETA_CAUSE_TXQ_ERROR_SHIFT + (q))) + #define MVNETA_INTR_ENABLE 0x25b8 #define MVNETA_TXQ_INTR_ENABLE_ALL_MASK 0x0000ff00 -#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0xff000000 +#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0xff000000 // note: neta says it's 0x000000FF + #define MVNETA_RXQ_CMD 0x2680 #define MVNETA_RXQ_DISABLE_SHIFT 8 #define MVNETA_RXQ_ENABLE_MASK 0x000000ff @@ -176,9 +216,6 @@ #define MVNETA_RX_COAL_PKTS 32 #define MVNETA_RX_COAL_USEC 100 -/* Timer */ -#define MVNETA_TX_DONE_TIMER_PERIOD 10 - /* Napi polling weight */ #define MVNETA_RX_POLL_WEIGHT 64 @@ -221,10 +258,12 @@ #define MVNETA_RX_BUF_SIZE(pkt_size) ((pkt_size) + NET_SKB_PAD) -struct mvneta_stats { +struct mvneta_pcpu_stats { struct u64_stats_sync syncp; - u64 packets; - u64 bytes; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; }; struct mvneta_port { @@ -232,16 +271,11 @@ void __iomem *base; struct mvneta_rx_queue *rxqs; struct mvneta_tx_queue *txqs; - struct timer_list tx_done_timer; struct net_device *dev; u32 cause_rx_tx; struct napi_struct napi; - /* Flags */ - unsigned long flags; -#define MVNETA_F_TX_DONE_TIMER_BIT 0 - /* Napi weight */ int weight; @@ -250,8 +284,7 @@ u8 mcast_count[256]; u16 tx_ring_size; u16 rx_ring_size; - struct mvneta_stats tx_stats; - struct mvneta_stats rx_stats; + struct mvneta_pcpu_stats *stats; struct mii_bus *mii_bus; struct phy_device *phy_dev; @@ -461,21 +494,29 @@ { struct mvneta_port *pp = netdev_priv(dev); unsigned int start; + int cpu; - memset(stats, 0, sizeof(struct rtnl_link_stats64)); - - do { - start = u64_stats_fetch_begin_bh(&pp->rx_stats.syncp); - stats->rx_packets = pp->rx_stats.packets; - stats->rx_bytes = pp->rx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&pp->rx_stats.syncp, start)); - - - do { - start = u64_stats_fetch_begin_bh(&pp->tx_stats.syncp); - stats->tx_packets = pp->tx_stats.packets; - stats->tx_bytes = pp->tx_stats.bytes; - } while (u64_stats_fetch_retry_bh(&pp->tx_stats.syncp, start)); + for_each_possible_cpu(cpu) { + struct mvneta_pcpu_stats *cpu_stats; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + + cpu_stats = per_cpu_ptr(pp->stats, cpu); + do { + start = u64_stats_fetch_begin_bh(&cpu_stats->syncp); + rx_packets = cpu_stats->rx_packets; + rx_bytes = cpu_stats->rx_bytes; + tx_packets = cpu_stats->tx_packets; + tx_bytes = cpu_stats->tx_bytes; + } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } stats->rx_errors = dev->stats.rx_errors; stats->rx_dropped = dev->stats.rx_dropped; @@ -1100,17 +1141,6 @@ txq->done_pkts_coal = value; } -/* Trigger tx done timer in MVNETA_TX_DONE_TIMER_PERIOD msecs */ -static void mvneta_add_tx_done_timer(struct mvneta_port *pp) -{ - if (test_and_set_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags) == 0) { - pp->tx_done_timer.expires = jiffies + - msecs_to_jiffies(MVNETA_TX_DONE_TIMER_PERIOD); - add_timer(&pp->tx_done_timer); - } -} - - /* Handle rx descriptor fill by setting buf_cookie and buf_phys_addr */ static void mvneta_rx_desc_fill(struct mvneta_rx_desc *rx_desc, u32 phys_addr, u32 cookie) @@ -1391,6 +1421,8 @@ { struct net_device *dev = pp->dev; int rx_done, rx_filled; + u32 rcvd_pkts = 0; + u32 rcvd_bytes = 0; /* Get number of received packets */ rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq); @@ -1428,10 +1460,8 @@ rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE); - u64_stats_update_begin(&pp->rx_stats.syncp); - pp->rx_stats.packets++; - pp->rx_stats.bytes += rx_bytes; - u64_stats_update_end(&pp->rx_stats.syncp); + rcvd_pkts++; + rcvd_bytes += rx_bytes; /* Linux processing */ skb_reserve(skb, MVNETA_MH_SIZE); @@ -1452,6 +1482,15 @@ } } + if (rcvd_pkts) { + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + + u64_stats_update_begin(&stats->syncp); + stats->rx_packets += rcvd_pkts; + stats->rx_bytes += rcvd_bytes; + u64_stats_update_end(&stats->syncp); + } + /* Update rxq management counters */ mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_filled); @@ -1582,25 +1621,17 @@ out: if (frags > 0) { - u64_stats_update_begin(&pp->tx_stats.syncp); - pp->tx_stats.packets++; - pp->tx_stats.bytes += skb->len; - u64_stats_update_end(&pp->tx_stats.syncp); + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + u64_stats_update_begin(&stats->syncp); + stats->tx_packets++; + stats->tx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); } else { dev->stats.tx_dropped++; dev_kfree_skb_any(skb); } - if (txq->count >= MVNETA_TXDONE_COAL_PKTS) - mvneta_txq_done(pp, txq); - - /* If after calling mvneta_txq_done, count equals - * frags, we need to set the timer - */ - if (txq->count == frags && frags > 0) - mvneta_add_tx_done_timer(pp); - return NETDEV_TX_OK; } @@ -1876,14 +1907,22 @@ /* Read cause register */ cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE) & - MVNETA_RX_INTR_MASK(rxq_number); + (MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); + + /* Release Tx descriptors */ + if (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL) { + int tx_todo = 0; + + mvneta_tx_done_gbe(pp, (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL), &tx_todo); + cause_rx_tx &= ~MVNETA_TX_INTR_MASK_ALL; + } /* For the case where the last mvneta_poll did not process all * RX packets */ cause_rx_tx |= pp->cause_rx_tx; if (rxq_number > 1) { - while ((cause_rx_tx != 0) && (budget > 0)) { + while ((cause_rx_tx & MVNETA_RX_INTR_MASK_ALL) && (budget > 0)) { int count; struct mvneta_rx_queue *rxq; /* get rx queue number from cause_rx_tx */ @@ -1915,7 +1954,7 @@ napi_complete(napi); local_irq_save(flags); mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number)); + MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); local_irq_restore(flags); } @@ -1923,26 +1962,6 @@ return rx_done; } -/* tx done timer callback */ -static void mvneta_tx_done_timer_callback(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct mvneta_port *pp = netdev_priv(dev); - int tx_done = 0, tx_todo = 0; - - if (!netif_running(dev)) - return ; - - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); - - tx_done = mvneta_tx_done_gbe(pp, - (((1 << txq_number) - 1) & - MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK), - &tx_todo); - if (tx_todo > 0) - mvneta_add_tx_done_timer(pp); -} - /* Handle rxq fill: allocates rxq skbs; called when initializing a port */ static int mvneta_rxq_fill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int num) @@ -2192,7 +2211,7 @@ /* Unmask interrupts */ mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number)); + MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); phy_start(pp->phy_dev); netif_tx_start_all_queues(pp->dev); @@ -2225,16 +2244,6 @@ mvneta_rx_reset(pp); } -/* tx timeout callback - display a message and stop/start the network device */ -static void mvneta_tx_timeout(struct net_device *dev) -{ - struct mvneta_port *pp = netdev_priv(dev); - - netdev_info(dev, "tx timeout\n"); - mvneta_stop_dev(pp); - mvneta_start_dev(pp); -} - /* Return positive if MTU is valid */ static int mvneta_check_mtu_valid(struct net_device *dev, int mtu) { @@ -2478,8 +2487,6 @@ free_irq(dev->irq, pp); mvneta_cleanup_rxqs(pp); mvneta_cleanup_txqs(pp); - del_timer(&pp->tx_done_timer); - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); return 0; } @@ -2615,7 +2622,6 @@ .ndo_set_rx_mode = mvneta_set_rx_mode, .ndo_set_mac_address = mvneta_set_mac_addr, .ndo_change_mtu = mvneta_change_mtu, - .ndo_tx_timeout = mvneta_tx_timeout, .ndo_get_stats64 = mvneta_get_stats64, .ndo_do_ioctl = mvneta_ioctl, }; @@ -2751,6 +2757,7 @@ const char *mac_from; int phy_mode; int err; + int cpu; /* Our multiqueue support is not complete, so for now, only * allow the usage of the first RX queue @@ -2792,9 +2799,6 @@ pp = netdev_priv(dev); - u64_stats_init(&pp->tx_stats.syncp); - u64_stats_init(&pp->rx_stats.syncp); - pp->weight = MVNETA_RX_POLL_WEIGHT; pp->phy_node = phy_node; pp->phy_interface = phy_mode; @@ -2813,6 +2817,19 @@ goto err_clk; } + /* Alloc per-cpu stats */ + pp->stats = alloc_percpu(struct mvneta_pcpu_stats); + if (!pp->stats) { + err = -ENOMEM; + goto err_unmap; + } + + for_each_possible_cpu(cpu) { + struct mvneta_pcpu_stats *stats; + stats = per_cpu_ptr(pp->stats, cpu); + u64_stats_init(&stats->syncp); + } + dt_mac_addr = of_get_mac_address(dn); if (dt_mac_addr) { mac_from = "device tree"; @@ -2828,11 +2845,6 @@ } } - pp->tx_done_timer.data = (unsigned long)dev; - pp->tx_done_timer.function = mvneta_tx_done_timer_callback; - init_timer(&pp->tx_done_timer); - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); - pp->tx_ring_size = MVNETA_MAX_TXD; pp->rx_ring_size = MVNETA_MAX_RXD; @@ -2842,7 +2854,7 @@ err = mvneta_init(pp, phy_addr); if (err < 0) { dev_err(&pdev->dev, "can't init eth hal\n"); - goto err_unmap; + goto err_free_stats; } mvneta_port_power_up(pp, phy_mode); @@ -2872,6 +2884,8 @@ err_deinit: mvneta_deinit(pp); +err_free_stats: + free_percpu(pp->stats); err_unmap: iounmap(pp->base); err_clk: @@ -2892,6 +2906,7 @@ unregister_netdev(dev); mvneta_deinit(pp); clk_disable_unprepare(pp->clk); + free_percpu(pp->stats); iounmap(pp->base); irq_dispose_mapping(dev->irq); free_netdev(dev); --- linux-3.13.0.orig/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ linux-3.13.0/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -4206,6 +4206,9 @@ return ret; } +#define VXGE_PXE_FIRMWARE "vxge/X3fw-pxe.ncf" +#define VXGE_FIRMWARE "vxge/X3fw.ncf" + static int vxge_probe_fw_update(struct vxgedev *vdev) { u32 maj, min, bld; @@ -4248,9 +4251,9 @@ } } if (gpxe) - fw_name = "vxge/X3fw-pxe.ncf"; + fw_name = VXGE_PXE_FIRMWARE; else - fw_name = "vxge/X3fw.ncf"; + fw_name = VXGE_FIRMWARE; ret = vxge_fw_upgrade(vdev, fw_name, 0); /* -EINVAL and -ENOENT are not fatal errors for flashing firmware on @@ -4855,3 +4858,5 @@ } module_init(vxge_starter); module_exit(vxge_closer); +MODULE_FIRMWARE(VXGE_PXE_FIRMWARE); +MODULE_FIRMWARE(VXGE_FIRMWARE); --- linux-3.13.0.orig/drivers/net/ethernet/ti/davinci_emac.c +++ linux-3.13.0/drivers/net/ethernet/ti/davinci_emac.c @@ -1532,7 +1532,7 @@ struct device *emac_dev = &ndev->dev; u32 cnt; struct resource *res; - int ret; + int q, m, ret; int i = 0; int k = 0; struct emac_priv *priv = netdev_priv(ndev); @@ -1567,8 +1567,7 @@ while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { - if (devm_request_irq(&priv->pdev->dev, i, emac_irq, - 0, ndev->name, ndev)) + if (request_irq(i, emac_irq, 0, ndev->name, ndev)) goto rollback; } k++; @@ -1641,7 +1640,15 @@ rollback: - dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed"); + dev_err(emac_dev, "DaVinci EMAC: request_irq() failed"); + + for (q = k; k >= 0; k--) { + for (m = i; m >= res->start; m--) + free_irq(m, ndev); + res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k-1); + m = res->end; + } + ret = -EBUSY; err: pm_runtime_put(&priv->pdev->dev); @@ -1659,6 +1666,9 @@ */ static int emac_dev_stop(struct net_device *ndev) { + struct resource *res; + int i = 0; + int irq_num; struct emac_priv *priv = netdev_priv(ndev); struct device *emac_dev = &ndev->dev; @@ -1674,6 +1684,13 @@ if (priv->phydev) phy_disconnect(priv->phydev); + /* Free IRQ */ + while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, priv->ndev); + i++; + } + if (netif_msg_drv(priv)) dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name); --- linux-3.13.0.orig/drivers/net/ethernet/emulex/benet/be_cmds.c +++ linux-3.13.0/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1101,23 +1101,22 @@ OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req), wrb, NULL); req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); - if (lancer_chip(adapter)) { - req->hdr.version = 1; - req->cq_id = cpu_to_le16(cq->id); - - AMAP_SET_BITS(struct amap_mcc_context_lancer, ring_size, ctxt, - be_encoded_q_len(mccq->len)); - AMAP_SET_BITS(struct amap_mcc_context_lancer, valid, ctxt, 1); - AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_id, - ctxt, cq->id); - AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_valid, - ctxt, 1); - - } else { + if (BEx_chip(adapter)) { AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, be_encoded_q_len(mccq->len)); AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); + } else { + req->hdr.version = 1; + req->cq_id = cpu_to_le16(cq->id); + + AMAP_SET_BITS(struct amap_mcc_context_v1, ring_size, ctxt, + be_encoded_q_len(mccq->len)); + AMAP_SET_BITS(struct amap_mcc_context_v1, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_id, + ctxt, cq->id); + AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_valid, + ctxt, 1); } /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ @@ -1187,7 +1186,7 @@ int status; status = be_cmd_mccq_ext_create(adapter, mccq, cq); - if (status && !lancer_chip(adapter)) { + if (status && BEx_chip(adapter)) { dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " "or newer to avoid conflicting priorities between NIC " "and FCoE traffic"); @@ -2692,6 +2691,13 @@ struct be_cmd_resp_get_fn_privileges *resp = embedded_payload(wrb); *privilege = le32_to_cpu(resp->privilege_mask); + + /* In UMC mode FW does not return right privileges. + * Override with correct privilege equivalent to PF. + */ + if (BEx_chip(adapter) && be_is_mc(adapter) && + be_physfn(adapter)) + *privilege = MAX_PRIVILEGES; } err: @@ -2736,7 +2742,8 @@ * If pmac_id is returned, pmac_id_valid is returned as true */ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, - bool *pmac_id_valid, u32 *pmac_id, u8 domain) + bool *pmac_id_valid, u32 *pmac_id, u32 if_handle, + u8 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_get_mac_list *req; @@ -2774,7 +2781,7 @@ req->mac_type = MAC_ADDRESS_TYPE_NETWORK; if (*pmac_id_valid) { req->mac_id = cpu_to_le32(*pmac_id); - req->iface_id = cpu_to_le16(adapter->if_handle); + req->iface_id = cpu_to_le16(if_handle); req->perm_override = 0; } else { req->perm_override = 1; @@ -2827,17 +2834,21 @@ return status; } -int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, u8 *mac) +int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, u8 *mac, + u32 if_handle, bool active, u32 domain) { - bool active = true; + if (!active) + be_cmd_get_mac_from_list(adapter, mac, &active, &curr_pmac_id, + if_handle, domain); if (BEx_chip(adapter)) return be_cmd_mac_addr_query(adapter, mac, false, - adapter->if_handle, curr_pmac_id); + if_handle, curr_pmac_id); else /* Fetch the MAC address using pmac_id */ return be_cmd_get_mac_from_list(adapter, mac, &active, - &curr_pmac_id, 0); + &curr_pmac_id, + if_handle, domain); } int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac) @@ -2856,7 +2867,7 @@ adapter->if_handle, 0); } else { status = be_cmd_get_mac_from_list(adapter, mac, &pmac_valid, - NULL, 0); + NULL, adapter->if_handle, 0); } return status; @@ -2917,7 +2928,8 @@ int status; status = be_cmd_get_mac_from_list(adapter, old_mac, &active_mac, - &pmac_id, dom); + &pmac_id, if_id, dom); + if (!status && active_mac) be_cmd_pmac_del(adapter, if_id, pmac_id, dom); @@ -2997,7 +3009,7 @@ ctxt, intf_id); AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1); - if (!BEx_chip(adapter)) { + if (!BEx_chip(adapter) && mode) { AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, ctxt, adapter->hba_port_num); AMAP_SET_BITS(struct amap_get_hsw_req_context, pport, ctxt, 1); @@ -3028,14 +3040,16 @@ { struct be_mcc_wrb *wrb; struct be_cmd_req_acpi_wol_magic_config_v1 *req; - int status; - int payload_len = sizeof(*req); + int status = 0; struct be_dma_mem cmd; if (!be_cmd_allowed(adapter, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, CMD_SUBSYSTEM_ETH)) return -EPERM; + if (be_is_wol_excluded(adapter)) + return status; + if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1; @@ -3060,7 +3074,7 @@ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, - payload_len, wrb, &cmd); + sizeof(*req), wrb, &cmd); req->hdr.version = 1; req->query_options = BE_GET_WOL_CAP; @@ -3070,13 +3084,9 @@ struct be_cmd_resp_acpi_wol_magic_config_v1 *resp; resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *) cmd.va; - /* the command could succeed misleadingly on old f/w - * which is not aware of the V1 version. fake an error. */ - if (resp->hdr.response_length < payload_len) { - status = -1; - goto err; - } adapter->wol_cap = resp->wol_settings; + if (adapter->wol_cap & BE_WOL_CAP) + adapter->wol_en = true; } err: mutex_unlock(&adapter->mbox_lock); @@ -3085,6 +3095,76 @@ return status; } + +int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level) +{ + struct be_dma_mem extfat_cmd; + struct be_fat_conf_params *cfgs; + int status; + int i, j; + + memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); + extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); + extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, + &extfat_cmd.dma); + if (!extfat_cmd.va) + return -ENOMEM; + + status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); + if (status) + goto err; + + cfgs = (struct be_fat_conf_params *) + (extfat_cmd.va + sizeof(struct be_cmd_resp_hdr)); + for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) { + u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes); + for (j = 0; j < num_modes; j++) { + if (cfgs->module[i].trace_lvl[j].mode == MODE_UART) + cfgs->module[i].trace_lvl[j].dbg_lvl = + cpu_to_le32(level); + } + } + + status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, cfgs); +err: + pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, + extfat_cmd.dma); + return status; +} + +int be_cmd_get_fw_log_level(struct be_adapter *adapter) +{ + struct be_dma_mem extfat_cmd; + struct be_fat_conf_params *cfgs; + int status, j; + int level = 0; + + memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); + extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); + extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, + &extfat_cmd.dma); + + if (!extfat_cmd.va) { + dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", + __func__); + goto err; + } + + status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); + if (!status) { + cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + + sizeof(struct be_cmd_resp_hdr)); + for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) { + if (cfgs->module[0].trace_lvl[j].mode == MODE_UART) + level = cfgs->module[0].trace_lvl[j].dbg_lvl; + } + } + pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, + extfat_cmd.dma); +err: + return level; +} + int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, struct be_dma_mem *cmd) { @@ -3608,6 +3688,40 @@ mutex_unlock(&adapter->mbox_lock); return status; } + +/* Uses MBOX */ +int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile_id) +{ + struct be_cmd_req_get_active_profile *req; + struct be_mcc_wrb *wrb; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_ACTIVE_PROFILE, sizeof(*req), + wrb, NULL); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_active_profile *resp = + embedded_payload(wrb); + *profile_id = le16_to_cpu(resp->active_profile_id); + } + +err: + mutex_unlock(&adapter->mbox_lock); + return status; +} int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, int wrb_payload_size, u16 *cmd_status, u16 *ext_status) --- linux-3.13.0.orig/drivers/net/ethernet/emulex/benet/be.h +++ linux-3.13.0/drivers/net/ethernet/emulex/benet/be.h @@ -34,7 +34,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "4.9.224.0u" +#define DRV_VER "10.0.600.0u" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" @@ -42,7 +42,7 @@ #define OC_NAME_BE OC_NAME "(be3)" #define OC_NAME_LANCER OC_NAME "(Lancer)" #define OC_NAME_SH OC_NAME "(Skyhawk)" -#define DRV_DESC "Emulex OneConnect 10Gbps NIC Driver" +#define DRV_DESC "Emulex OneConnect NIC Driver" #define BE_VENDOR_ID 0x19a2 #define EMULEX_VENDOR_ID 0x10df @@ -283,7 +283,6 @@ u32 rss_hash; u16 vlan_tag; u16 pkt_size; - u16 rxq_idx; u16 port; u8 vlanf; u8 num_rcvd; @@ -493,7 +492,7 @@ u16 pvid; struct phy_info phy; u8 wol_cap; - bool wol; + bool wol_en; u32 uc_macs; /* Count of secondary UC MAC programmed */ u16 asic_rev; u16 qnq_vid; --- linux-3.13.0.orig/drivers/net/ethernet/emulex/benet/be_main.c +++ linux-3.13.0/drivers/net/ethernet/emulex/benet/be_main.c @@ -121,12 +121,6 @@ "Unknown" }; -/* Is BE in a multi-channel mode */ -static inline bool be_is_mc(struct be_adapter *adapter) { - return (adapter->function_mode & FLEX10_MODE || - adapter->function_mode & VNIC_MODE || - adapter->function_mode & UMC_ENABLED); -} static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) { @@ -258,6 +252,12 @@ if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + /* Proceed further only if, User provided MAC is different + * from active MAC + */ + if (ether_addr_equal(addr->sa_data, netdev->dev_addr)) + return 0; + /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT * privilege or if PF did not provision the new MAC address. * On BE3, this cmd will always fail if the VF doesn't have the @@ -280,7 +280,8 @@ /* Decide if the new MAC is successfully activated only after * querying the FW */ - status = be_cmd_get_active_mac(adapter, curr_pmac_id, mac); + status = be_cmd_get_active_mac(adapter, curr_pmac_id, mac, + adapter->if_handle, true, 0); if (status) goto err; @@ -1096,8 +1097,6 @@ dev_info(&adapter->pdev->dev, "Disabling VLAN Promiscuous mode.\n"); adapter->flags &= ~BE_FLAGS_VLAN_PROMISC; - dev_info(&adapter->pdev->dev, - "Re-Enabling HW VLAN filtering\n"); } } } @@ -1105,12 +1104,12 @@ return status; set_vlan_promisc: - dev_warn(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n"); + if (adapter->flags & BE_FLAGS_VLAN_PROMISC) + return 0; status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON); if (!status) { dev_info(&adapter->pdev->dev, "Enable VLAN Promiscuous mode\n"); - dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering\n"); adapter->flags |= BE_FLAGS_VLAN_PROMISC; } else dev_err(&adapter->pdev->dev, @@ -1123,19 +1122,18 @@ struct be_adapter *adapter = netdev_priv(netdev); int status = 0; - /* Packets with VID 0 are always received by Lancer by default */ if (lancer_chip(adapter) && vid == 0) goto ret; adapter->vlan_tag[vid] = 1; - if (adapter->vlans_added <= (be_max_vlans(adapter) + 1)) - status = be_vid_config(adapter); + adapter->vlans_added++; - if (!status) - adapter->vlans_added++; - else + status = be_vid_config(adapter); + if (status) { + adapter->vlans_added--; adapter->vlan_tag[vid] = 0; + } ret: return status; } @@ -1150,9 +1148,7 @@ goto ret; adapter->vlan_tag[vid] = 0; - if (adapter->vlans_added <= be_max_vlans(adapter)) - status = be_vid_config(adapter); - + status = be_vid_config(adapter); if (!status) adapter->vlans_added--; else @@ -1442,12 +1438,12 @@ (rxcp->ip_csum || rxcp->ipv6); } -static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo, - u16 frag_idx) +static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo) { struct be_adapter *adapter = rxo->adapter; struct be_rx_page_info *rx_page_info; struct be_queue_info *rxq = &rxo->q; + u16 frag_idx = rxq->tail; rx_page_info = &rxo->page_info_tbl[frag_idx]; BUG_ON(!rx_page_info->page); @@ -1459,6 +1455,7 @@ rx_page_info->last_page_user = false; } + queue_tail_inc(rxq); atomic_dec(&rxq->used); return rx_page_info; } @@ -1467,15 +1464,13 @@ static void be_rx_compl_discard(struct be_rx_obj *rxo, struct be_rx_compl_info *rxcp) { - struct be_queue_info *rxq = &rxo->q; struct be_rx_page_info *page_info; u16 i, num_rcvd = rxcp->num_rcvd; for (i = 0; i < num_rcvd; i++) { - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); - index_inc(&rxcp->rxq_idx, rxq->len); } } @@ -1486,13 +1481,12 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb, struct be_rx_compl_info *rxcp) { - struct be_queue_info *rxq = &rxo->q; struct be_rx_page_info *page_info; u16 i, j; u16 hdr_len, curr_frag_len, remaining; u8 *start; - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); start = page_address(page_info->page) + page_info->page_offset; prefetch(start); @@ -1526,10 +1520,9 @@ } /* More frags present for this completion */ - index_inc(&rxcp->rxq_idx, rxq->len); remaining = rxcp->pkt_size - curr_frag_len; for (i = 1, j = 0; i < rxcp->num_rcvd; i++) { - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); curr_frag_len = min(remaining, rx_frag_size); /* Coalesce all frags from the same physical page in one slot */ @@ -1550,7 +1543,6 @@ skb->data_len += curr_frag_len; skb->truesize += rx_frag_size; remaining -= curr_frag_len; - index_inc(&rxcp->rxq_idx, rxq->len); page_info->page = NULL; } BUG_ON(j > MAX_SKB_FRAGS); @@ -1598,7 +1590,6 @@ struct be_adapter *adapter = rxo->adapter; struct be_rx_page_info *page_info; struct sk_buff *skb = NULL; - struct be_queue_info *rxq = &rxo->q; u16 remaining, curr_frag_len; u16 i, j; @@ -1610,7 +1601,7 @@ remaining = rxcp->pkt_size; for (i = 0, j = -1; i < rxcp->num_rcvd; i++) { - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); curr_frag_len = min(remaining, rx_frag_size); @@ -1628,7 +1619,6 @@ skb_frag_size_add(&skb_shinfo(skb)->frags[j], curr_frag_len); skb->truesize += rx_frag_size; remaining -= curr_frag_len; - index_inc(&rxcp->rxq_idx, rxq->len); memset(page_info, 0, sizeof(*page_info)); } BUG_ON(j > MAX_SKB_FRAGS); @@ -1663,8 +1653,6 @@ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl); rxcp->ipv6 = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl); - rxcp->rxq_idx = - AMAP_GET_BITS(struct amap_eth_rx_compl_v1, fragndx, compl); rxcp->num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); rxcp->pkt_type = @@ -1695,8 +1683,6 @@ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl); rxcp->ipv6 = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl); - rxcp->rxq_idx = - AMAP_GET_BITS(struct amap_eth_rx_compl_v0, fragndx, compl); rxcp->num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); rxcp->pkt_type = @@ -1921,7 +1907,6 @@ struct be_rx_compl_info *rxcp; struct be_adapter *adapter = rxo->adapter; int flush_wait = 0; - u16 tail; /* Consume pending rx completions. * Wait for the flush completion (identified by zero num_rcvd) @@ -1954,9 +1939,8 @@ be_cq_notify(adapter, rx_cq->id, false, 0); /* Then free posted rx buffers that were not used */ - tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; - for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { - page_info = get_rx_page_info(rxo, tail); + while (atomic_read(&rxq->used) > 0) { + page_info = get_rx_page_info(rxo); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); } @@ -2891,14 +2875,11 @@ int status, vf; u8 mac[ETH_ALEN]; struct be_vf_cfg *vf_cfg; - bool active = false; for_all_vfs(adapter, vf_cfg, vf) { - be_cmd_get_mac_from_list(adapter, mac, &active, - &vf_cfg->pmac_id, 0); - - status = be_cmd_mac_addr_query(adapter, mac, false, - vf_cfg->if_handle, 0); + status = be_cmd_get_active_mac(adapter, vf_cfg->pmac_id, + mac, vf_cfg->if_handle, + false, vf+1); if (status) return status; memcpy(vf_cfg->mac_addr, mac, ETH_ALEN); @@ -3240,6 +3221,7 @@ /* Routine to query per function resource limits */ static int be_get_config(struct be_adapter *adapter) { + u16 profile_id; int status; status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, @@ -3249,6 +3231,13 @@ if (status) return status; + if (be_physfn(adapter)) { + status = be_cmd_get_active_profile(adapter, &profile_id); + if (!status) + dev_info(&adapter->pdev->dev, + "Using profile 0x%x\n", profile_id); + } + status = be_get_resources(adapter); if (status) return status; @@ -3403,11 +3392,6 @@ goto err; be_cmd_get_fn_privileges(adapter, &adapter->cmd_privileges, 0); - /* In UMC mode FW does not return right privileges. - * Override with correct privilege equivalent to PF. - */ - if (be_is_mc(adapter)) - adapter->cmd_privileges = MAX_PRIVILEGES; status = be_mac_setup(adapter); if (status) @@ -3426,6 +3410,8 @@ be_set_rx_mode(adapter->netdev); + be_cmd_get_acpi_wol_cap(adapter); + be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) @@ -4295,74 +4281,22 @@ free_netdev(adapter->netdev); } -bool be_is_wol_supported(struct be_adapter *adapter) -{ - return ((adapter->wol_cap & BE_WOL_CAP) && - !be_is_wol_excluded(adapter)) ? true : false; -} - -u32 be_get_fw_log_level(struct be_adapter *adapter) -{ - struct be_dma_mem extfat_cmd; - struct be_fat_conf_params *cfgs; - int status; - u32 level = 0; - int j; - - if (lancer_chip(adapter)) - return 0; - - memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); - extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); - extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, - &extfat_cmd.dma); - - if (!extfat_cmd.va) { - dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", - __func__); - goto err; - } - - status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); - if (!status) { - cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + - sizeof(struct be_cmd_resp_hdr)); - for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) { - if (cfgs->module[0].trace_lvl[j].mode == MODE_UART) - level = cfgs->module[0].trace_lvl[j].dbg_lvl; - } - } - pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, - extfat_cmd.dma); -err: - return level; -} - static int be_get_initial_config(struct be_adapter *adapter) { - int status; - u32 level; + int status, level; status = be_cmd_get_cntl_attributes(adapter); if (status) return status; - status = be_cmd_get_acpi_wol_cap(adapter); - if (status) { - /* in case of a failure to get wol capabillities - * check the exclusion list to determine WOL capability */ - if (!be_is_wol_excluded(adapter)) - adapter->wol_cap |= BE_WOL_CAP; - } - - if (be_is_wol_supported(adapter)) - adapter->wol = true; - /* Must be a power of 2 or else MODULO will BUG_ON */ adapter->be_get_temp_freq = 64; - level = be_get_fw_log_level(adapter); - adapter->msg_enable = level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0; + if (BEx_chip(adapter)) { + level = be_cmd_get_fw_log_level(adapter); + adapter->msg_enable = + level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0; + } adapter->cfg_num_qs = netif_get_num_default_rss_queues(); return 0; @@ -4625,7 +4559,7 @@ struct be_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; - if (adapter->wol) + if (adapter->wol_en) be_setup_wol(adapter, true); be_intr_set(adapter, false); @@ -4681,7 +4615,7 @@ msecs_to_jiffies(1000)); netif_device_attach(netdev); - if (adapter->wol) + if (adapter->wol_en) be_setup_wol(adapter, false); return 0; --- linux-3.13.0.orig/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ linux-3.13.0/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -713,12 +713,13 @@ { struct be_adapter *adapter = netdev_priv(netdev); - if (be_is_wol_supported(adapter)) { + if (adapter->wol_cap & BE_WOL_CAP) { wol->supported |= WAKE_MAGIC; - if (adapter->wol) + if (adapter->wol_en) wol->wolopts |= WAKE_MAGIC; - } else + } else { wol->wolopts = 0; + } memset(&wol->sopass, 0, sizeof(wol->sopass)); } @@ -730,15 +731,15 @@ if (wol->wolopts & ~WAKE_MAGIC) return -EOPNOTSUPP; - if (!be_is_wol_supported(adapter)) { + if (!(adapter->wol_cap & BE_WOL_CAP)) { dev_warn(&adapter->pdev->dev, "WOL not supported\n"); return -EOPNOTSUPP; } if (wol->wolopts & WAKE_MAGIC) - adapter->wol = true; + adapter->wol_en = true; else - adapter->wol = false; + adapter->wol_en = false; return 0; } @@ -904,73 +905,21 @@ { struct be_adapter *adapter = netdev_priv(netdev); - if (lancer_chip(adapter)) { - dev_err(&adapter->pdev->dev, "Operation not supported\n"); - return -EOPNOTSUPP; - } - return adapter->msg_enable; } -static void be_set_fw_log_level(struct be_adapter *adapter, u32 level) -{ - struct be_dma_mem extfat_cmd; - struct be_fat_conf_params *cfgs; - int status; - int i, j; - - memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); - extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); - extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, - &extfat_cmd.dma); - if (!extfat_cmd.va) { - dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", - __func__); - goto err; - } - status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); - if (!status) { - cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + - sizeof(struct be_cmd_resp_hdr)); - for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) { - u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes); - for (j = 0; j < num_modes; j++) { - if (cfgs->module[i].trace_lvl[j].mode == - MODE_UART) - cfgs->module[i].trace_lvl[j].dbg_lvl = - cpu_to_le32(level); - } - } - status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, - cfgs); - if (status) - dev_err(&adapter->pdev->dev, - "Message level set failed\n"); - } else { - dev_err(&adapter->pdev->dev, "Message level get failed\n"); - } - - pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, - extfat_cmd.dma); -err: - return; -} - static void be_set_msg_level(struct net_device *netdev, u32 level) { struct be_adapter *adapter = netdev_priv(netdev); - if (lancer_chip(adapter)) { - dev_err(&adapter->pdev->dev, "Operation not supported\n"); - return; - } - if (adapter->msg_enable == level) return; if ((level & NETIF_MSG_HW) != (adapter->msg_enable & NETIF_MSG_HW)) - be_set_fw_log_level(adapter, level & NETIF_MSG_HW ? - FW_LOG_LEVEL_DEFAULT : FW_LOG_LEVEL_FATAL); + if (BEx_chip(adapter)) + be_cmd_set_fw_log_level(adapter, level & NETIF_MSG_HW ? + FW_LOG_LEVEL_DEFAULT : + FW_LOG_LEVEL_FATAL); adapter->msg_enable = level; return; --- linux-3.13.0.orig/drivers/net/ethernet/emulex/benet/be_cmds.h +++ linux-3.13.0/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -216,6 +216,7 @@ #define OPCODE_COMMON_GET_FUNC_CONFIG 160 #define OPCODE_COMMON_GET_PROFILE_CONFIG 164 #define OPCODE_COMMON_SET_PROFILE_CONFIG 165 +#define OPCODE_COMMON_GET_ACTIVE_PROFILE 167 #define OPCODE_COMMON_SET_HSW_CONFIG 153 #define OPCODE_COMMON_GET_FN_PRIVILEGES 170 #define OPCODE_COMMON_READ_OBJECT 171 @@ -452,7 +453,7 @@ u8 rsvd2[32]; } __packed; -struct amap_mcc_context_lancer { +struct amap_mcc_context_v1 { u8 async_cq_id[16]; u8 ring_size[4]; u8 rsvd0[12]; @@ -476,7 +477,7 @@ u16 num_pages; u16 cq_id; u32 async_event_bitmap[1]; - u8 context[sizeof(struct amap_mcc_context_be) / 8]; + u8 context[sizeof(struct amap_mcc_context_v1) / 8]; struct phys_addr pages[8]; } __packed; @@ -1097,6 +1098,14 @@ u32 function_caps; }; +/* Is BE in a multi-channel mode */ +static inline bool be_is_mc(struct be_adapter *adapter) +{ + return adapter->function_mode & FLEX10_MODE || + adapter->function_mode & VNIC_MODE || + adapter->function_mode & UMC_ENABLED; +} + /******************** RSS Config ****************************************/ /* RSS type Input parameters used to compute RX hash * RSS_ENABLE_IPV4 SRC IPv4, DST IPv4 @@ -1917,6 +1926,17 @@ struct be_cmd_resp_hdr hdr; }; +struct be_cmd_req_get_active_profile { + struct be_cmd_req_hdr hdr; + u32 rsvd; +} __packed; + +struct be_cmd_resp_get_active_profile { + struct be_cmd_resp_hdr hdr; + u16 active_profile_id; + u16 next_profile_id; +} __packed; + struct be_cmd_enable_disable_vf { struct be_cmd_req_hdr hdr; u8 enable; @@ -2037,8 +2057,10 @@ int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges, u32 vf_num); int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, - bool *pmac_id_active, u32 *pmac_id, u8 domain); -int be_cmd_get_active_mac(struct be_adapter *adapter, u32 pmac_id, u8 *mac); + bool *pmac_id_active, u32 *pmac_id, + u32 if_handle, u8 domain); +int be_cmd_get_active_mac(struct be_adapter *adapter, u32 pmac_id, u8 *mac, + u32 if_handle, bool active, u32 domain); int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac); int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, u8 mac_count, u32 domain); @@ -2048,6 +2070,8 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, u32 domain, u16 intf_id, u8 *mode); int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter); +int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level); +int be_cmd_get_fw_log_level(struct be_adapter *adapter); int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, struct be_dma_mem *cmd); int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter, @@ -2063,6 +2087,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, struct be_resources *res, u8 domain); int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps, u8 domain); +int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile); int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg, int vf_num); int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain); --- linux-3.13.0.orig/drivers/net/ethernet/apm/Makefile +++ linux-3.13.0/drivers/net/ethernet/apm/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for APM X-GENE Ethernet driver. +# + +obj-$(CONFIG_NET_XGENE) += xgene/ --- linux-3.13.0.orig/drivers/net/ethernet/apm/Kconfig +++ linux-3.13.0/drivers/net/ethernet/apm/Kconfig @@ -0,0 +1 @@ +source "drivers/net/ethernet/apm/xgene/Kconfig" --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_csr.h +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_csr.h @@ -0,0 +1,427 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Ravi Patel + * Iyappan Subramanian + * Fushen Chen + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __XGENE_ENET_CSR_H__ +#define __XGENE_ENET_CSR_H__ + +#define RSIF_INT_REG0_ADDR 0x00000054 +#define RSIF_FINT_REG0_ADDR 0x0000005c +#define TSIF_INT_REG0_ADDR 0x0000012c +#define TSIF_FINT_REG0_ADDR 0x00000134 +#define TSO_INT_REG0_ADDR 0x00000324 +#define SPI2SAP_INT_REG0_ADDR 0x00000448 +#define RX_TX_BUF_CHKSM_INT_REG0_ADDR 0x0000052c +#define ENET_SPARE_CFG_REG_ADDR 0x00000750 +#define RSIF_CONFIG_REG_ADDR 0x00000010 +#define RSIF_RAM_DBG_REG0_ADDR 0x00000048 +#define RGMII_REG_0_ADDR 0x000007e0 +#define CFG_LINK_AGGR_RESUME_0_ADDR 0x000007c8 +#define DEBUG_REG_ADDR 0x00000700 +#define CFG_BYPASS_ADDR 0x00000294 +#define CLE_BYPASS_REG0_0_ADDR 0x00000490 +#define CLE_BYPASS_REG1_0_ADDR 0x00000494 +#define CLE_BYPASS_REG8_0_ADDR 0x000004b0 +#define TSIF_MSS_REG0_0_ADDR 0x00000108 +#define TSIF_MSS_REG1_0_ADDR 0x00000110 +#define TSO_CFG_0_ADDR 0x00000314 +#define TSO_CFG_INSERT_VLAN_0_ADDR 0x0000031c +#define CFG_RSIF_FPBUFF_TIMEOUT_EN_WR(src) \ + (((u32)(src)<<31) & 0x80000000) +#define RSIF_LCL_RXBUF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x20000000 +#define RSIF_LCL_RXBUF_FIFO_OVERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x20000000)>>29) +#define RSIF_LCL_RXBUF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x10000000 +#define RSIF_LCL_RXBUF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x10000000)>>28) +#define RSIF_CHKSUM_BUFF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x08000000 +#define RSIF_CHKSUM_BUFF_FIFO_OVERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x08000000)>>27) +#define RSIF_CHKSUM_BUFF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x04000000 +#define RSIF_CHKSUM_BUFF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x04000000)>>26) +#define RSIF_TIMESTAMP_BUFF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x02000000 +#define RSIF_TIMESTAMP_BUFF_FIFO_OVERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x02000000)>>25) +#define RSIF_TIMESTAMP_BUFF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x01000000 +#define RSIF_TIMESTAMP_BUFF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x01000000)>>24) +#define RSIF_ERR_BUFF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x00800000 +#define RSIF_ERR_BUFF_FIFO_OVERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00800000)>>23) +#define RSIF_ERR_BUFF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x00400000 +#define RSIF_ERR_BUFF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00400000)>>22) +#define RSIF_CLEBUFF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x00200000 +#define RSIF_CLEBUFF_FIFO_OVERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00200000)>>21) +#define RSIF_CLEBUFF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x00100000 +#define RSIF_CLEBUFF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00100000)>>20) +#define RSIF_CTRLBUFF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x00080000 +#define RSIF_CTRLBUFF_FIFO_OVERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00080000)>>19) +#define RSIF_CTRLBUFF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x00040000 +#define RSIF_CTRLBUFF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00040000)>>18) +#define RSIF_BUF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x00020000 +#define RSIF_BUF_FIFO_OVERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00020000)>>17) +#define RSIF_BUF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x00010000 +#define RSIF_BUF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) \ + (((src) & 0x00010000)>>16) +#define ENET_RSIF_PLC_CLEBUFF_FIFO_OVERFL_INTR0_MASK 0x00008000 +#define ENET_RSIF_PLC_CLEBUFF_FIFO_OVERFL_INTR0_RD(src) \ + (((src) & 0x00008000)>>15) +#define ENET_RSIF_PLC_CLEBUFF_FIFO_UNDERFL_INTR0_RD(src) \ + (((src) & 0x00004000)>>14) +#define RSIF_LCL_RXBUF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00001000 +#define RSIF_LCL_RXBUF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00001000)>>12) +#define RSIF_LCL_RXBUF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00002000 +#define RSIF_LCL_RXBUF_FIFO_OVERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00002000)>>13) +#define RSIF_CHKSUM_BUFF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00000800 +#define RSIF_CHKSUM_BUFF_FIFO_OVERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00000800)>>11) +#define RSIF_CHKSUM_BUFF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00000400 +#define RSIF_CHKSUM_BUFF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00000400)>>10) +#define RSIF_TIMESTAMP_BUFF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00000200 +#define RSIF_TIMESTAMP_BUFF_FIFO_OVERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00000200)>>9) +#define RSIF_TIMESTAMP_BUFF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00000100 +#define RSIF_TIMESTAMP_BUFF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00000100)>>8) +#define RSIF_ERR_BUFF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00000080 +#define RSIF_ERR_BUFF_FIFO_OVERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000080)>>7) +#define RSIF_ERR_BUFF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00000040 +#define RSIF_ERR_BUFF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00000040)>>6) +#define RSIF_CLEBUFF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00000020 +#define RSIF_CLEBUFF_FIFO_OVERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000020)>>5) +#define RSIF_CLEBUFF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00000010 +#define RSIF_CLEBUFF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000010)>>4) +#define RSIF_CTRLBUFF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00000008 +#define RSIF_CTRLBUFF_FIFO_OVERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000008)>>3) +#define RSIF_CTRLBUFF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00000004 +#define RSIF_CTRLBUFF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) \ + (((src) & 0x00000004)>>2) +#define RSIF_BUF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00000002 +#define RSIF_BUF_FIFO_OVERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000002)>>1) +#define RSIF_BUF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00000001 +#define RSIF_BUF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000001)) +#define RSIF_SS_MIRRORERR_INTR_RXPRT10_MASK 0x00080000 +#define RSIF_SS_MIRRORERR_INTR_RXPRT10_RD(src) (((src) & 0x00080000)>>19) +#define RSIF_SS_SPLIT_BOUNDARY_INTR_RXPRT10_RD(src) (((src) & 0x00040000)>>18) +#define RSIF_SS_FPBUFF_TIMEOUT_INTR_RXPRT10_MASK 0x00020000 +#define RSIF_SS_FPBUFF_TIMEOUT_INTR_RXPRT10_RD(src) (((src) & 0x00020000)>>17) +#define RSIF_SS_AXI_WRERR_INTR_RXPRT10_MASK 0x00010000 +#define RSIF_SS_AXI_WRERR_INTR_RXPRT10_RD(src) (((src) & 0x00010000)>>16) +#define RSIF_SS_MIRRORERR_INTR_RXPRT00_MASK 0x00000010 +#define RSIF_SS_MIRRORERR_INTR_RXPRT00_RD(src) (((src) & 0x00000010)>>4) +#define RSIF_SS_SPLIT_BOUNDARY_INTR_RXPRT00_MASK 0x00000008 +#define RSIF_SS_SPLIT_BOUNDARY_INTR_RXPRT00_RD(src) (((src) & 0x00000008)>>3) +#define RSIF_SS_FPBUFF_TIMEOUT_INTR_RXPRT00_MASK 0x00000004 +#define RSIF_SS_FPBUFF_TIMEOUT_INTR_RXPRT00_RD(src) (((src) & 0x00000004)>>2) +#define RSIF_SS_AXI_WRERR_INTR_RXPRT00_MASK 0x00000002 +#define RSIF_SS_AXI_WRERR_INTR_RXPRT00_RD(src) (((src) & 0x00000002)>>1) +#define STS_RSIF_PLC_DROP0_MASK 0x00000001 +#define STS_RSIF_PLC_DROP0_RD(src) (((src) & 0x00000001)) +#define CFG_TSIF_MSS_SZ10_SET(dst, src) \ + (((dst) & ~0x3fff0000) | (((u32)(src)<<16) & 0x3fff0000)) +#define CFG_TSIF_MSS_SZ00_SET(dst, src) \ + (((dst) & ~0x00003fff) | (((u32)(src)) & 0x00003fff)) +#define CFG_TSIF_MSS_SZ20_SET(dst, src) \ + (((dst) & ~0x00003fff) | (((u32)(src)) & 0x00003fff)) +#define CFG_TSIF_MSS_SZ30_SET(dst, src) \ + (((dst) & ~0x3fff0000) | (((u32)(src)<<16) & 0x3fff0000)) +#define TSIF_RDMBUFF_FIFO_OVERFL_INTR_PRT10_MASK 0x00200000 +#define TSIF_RDMBUFF_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00200000)>>21) +#define TSIF_RDMBUFF_FIFO_UNDERFL_INTR_PRT10_MASK 0x00100000 +#define TSIF_RDMBUFF_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00100000)>>20) +#define TSIF_RRM_FIFO_OVERFL_INTR_PRT10_MASK 0x00080000 +#define TSIF_RRM_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00080000)>>19) +#define TSIF_RRM_FIFO_UNDERFL_INTR_PRT10_MASK 0x00040000 +#define TSIF_RRM_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00040000)>>18) +#define TSIF_AMABUF_FIFO_OVERFL_INTR_PRT10_MASK 0x00020000 +#define TSIF_AMABUF_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00020000)>>17) +#define TSIF_AMABUF_FIFO_UNDERFL_INTR_PRT10_MASK 0x00010000 +#define TSIF_AMABUF_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00010000)>>16) +#define TSIF_RDMBUFF_FIFO_OVERFL_INTR_PRT00_MASK 0x00000020 +#define TSIF_RDMBUFF_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000020)>>5) +#define TSIF_RDMBUFF_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000010 +#define TSIF_RDMBUFF_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000010)>>4) +#define TSIF_RRM_FIFO_OVERFL_INTR_PRT00_MASK 0x00000008 +#define TSIF_RRM_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000008)>>3) +#define TSIF_RRM_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000004 +#define TSIF_RRM_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000004)>>2) +#define TSIF_AMABUF_FIFO_OVERFL_INTR_PRT00_MASK 0x00000002 +#define TSIF_AMABUF_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000002)>>1) +#define TSIF_AMABUF_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000001 +#define TSIF_AMABUF_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000001)) +#define TSIF_SS_AXI_LLRDERR_INTR_PRT10_MASK 0x00040000 +#define TSIF_SS_AXI_LLRDERR_INTR_PRT10_RD(src) (((src) & 0x00040000)>>18) +#define TSIF_SS_AXI_RDERR_INTR_PRT10_MASK 0x00020000 +#define TSIF_SS_AXI_RDERR_INTR_PRT10_RD(src) (((src) & 0x00020000)>>17) +#define TSIF_SS_BAD_MSG_INTR_PRT10_MASK 0x00010000 +#define TSIF_SS_BAD_MSG_INTR_PRT10_RD(src) (((src) & 0x00010000)>>16) +#define TSIF_SS_AXI_LLRDERR_INTR_PRT00_MASK 0x00000004 +#define TSIF_SS_AXI_LLRDERR_INTR_PRT00_RD(src) (((src) & 0x00000004)>>2) +#define TSIF_SS_AXI_RDERR_INTR_PRT00_MASK 0x00000002 +#define TSIF_SS_AXI_RDERR_INTR_PRT00_RD(src) (((src) & 0x00000002)>>1) +#define TSIF_SS_BAD_MSG_INTR_PRT00_MASK 0x00000001 +#define TSIF_SS_BAD_MSG_INTR_PRT00_RD(src) (((src) & 0x00000001)) +#define RESUME_TX_WR(src) (((u32)(src)) & 0x00000001) +#define MB_TTF_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00200000)>>21) +#define MB_TTF_FIFO_OVERFL_INTR_PRT10_MASK 0x00200000 +#define MB_TTF_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00100000)>>20) +#define MB_TTF_FIFO_UNDERFL_INTR_PRT10_MASK 0x00100000 +#define MH_DEALLOC_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00080000)>>19) +#define MH_DEALLOC_FIFO_OVERFL_INTR_PRT10_MASK 0x00080000 +#define MH_DEALLOC_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00040000)>>18) +#define MH_DEALLOC_FIFO_UNDERFL_INTR_PRT10_MASK 0x00040000 +#define MH_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00020000)>>17) +#define MH_FIFO_OVERFL_INTR_PRT10_MASK 0x00020000 +#define MH_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00010000)>>16) +#define MH_FIFO_UNDERFL_INTR_PRT10_MASK 0x00010000 +#define MB_TTF_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000020)>>5) +#define MB_TTF_FIFO_OVERFL_INTR_PRT00_MASK 0x00000020 +#define MB_TTF_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000010)>>4) +#define MB_TTF_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000010 +#define MH_DEALLOC_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000008)>>3) +#define MH_DEALLOC_FIFO_OVERFL_INTR_PRT00_MASK 0x00000008 +#define MH_DEALLOC_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000004)>>2) +#define MH_DEALLOC_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000004 +#define MH_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000002)>>1) +#define MH_FIFO_OVERFL_INTR_PRT00_MASK 0x00000002 +#define MH_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000001)) +#define MH_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000001 +#define MACIF_FIFO_OVERFL_INTR_RXPRT10_RD(src) (((src) & 0x00020000)>>17) +#define MACIF_FIFO_OVERFL_INTR_RXPRT10_MASK 0x00020000 +#define MACIF_FIFO_OVERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000002)>>1) +#define MACIF_FIFO_OVERFL_INTR_RXPRT00_MASK 0x00000002 +#define MACIF_FIFO_UNDERFL_INTR_RXPRT10_RD(src) (((src) & 0x00010000)>>16) +#define MACIF_FIFO_UNDERFL_INTR_RXPRT10_MASK 0x00010000 +#define MACIF_FIFO_UNDERFL_INTR_RXPRT00_RD(src) (((src) & 0x00000001)) +#define MACIF_FIFO_UNDERFL_INTR_RXPRT00_MASK 0x00000001 +#define RXBUF_PAUSE_INTR_PORT10_RD(src) (((src) & 0x00400000)>>22) +#define RXBUF_PAUSE_INTR_PORT10_MASK 0x00400000 +#define RX_CHKSUM_INTR_PORT10_RD(src) (((src) & 0x00200000)>>21) +#define RX_CHKSUM_INTR_PORT10_MASK 0x00200000 +#define TX_CHKSUM_INTR_PORT10_RD(src) (((src) & 0x00100000)>>20) +#define TX_CHKSUM_INTR_PORT10_MASK 0x00100000 +#define RXBUF_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00080000)>>19) +#define RXBUF_FIFO_OVERFL_INTR_PRT10_MASK 0x00080000 +#define RXBUF_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00040000)>>18) +#define RXBUF_FIFO_UNDERFL_INTR_PRT10_MASK 0x00040000 +#define TXBUF_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00020000)>>17) +#define TXBUF_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00010000)>>16) +#define RXBUF_PAUSE_INTR_PORT00_RD(src) (((src) & 0x00000040)>>6) +#define RX_CHKSUM_INTR_PORT00_RD(src) (((src) & 0x00000020)>>5) +#define RX_CHKSUM_INTR_PORT00_MASK 0x00000020 +#define RXBUF_PAUSE_INTR_PORT00_MASK 0x00000040 +#define TX_CHKSUM_INTR_PORT00_RD(src) (((src) & 0x00000010)>>4) +#define TX_CHKSUM_INTR_PORT00_MASK 0x00000010 +#define RXBUF_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000008)>>3) +#define RXBUF_FIFO_OVERFL_INTR_PRT00_MASK 0x00000008 +#define RXBUF_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000004)>>2) +#define RXBUF_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000004 +#define TXBUF_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000002)>>1) +#define TXBUF_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000001)) +#define CFG_SPEED_1250_WR(src) (((u32)(src)<<24) & 0x01000000) +#define CFG_TXCLK_MUXSEL0_WR(src) (((u32)(src)<<29) & 0xe0000000) +#define TX_PORT0_WR(src) (((u32)(src)) & 0x00000001) +#define CFG_BYPASS_UNISEC_TX_WR(src) (((u32)(src)<<2) & 0x00000004) +#define CFG_BYPASS_UNISEC_RX_WR(src) (((u32)(src)<<1) & 0x00000002) +#define CFG_CLE_BYPASS_EN0_SET(dst, src) \ + (((dst) & ~0x80000000) | (((u32)(src)<<31) & 0x80000000)) +#define CFG_CLE_IP_PROTOCOL0_SET(dst, src) \ + (((dst) & ~0x00030000) | (((u32)(src)<<16) & 0x00030000)) +#define CFG_CLE_DSTQID0_SET(dst, src) \ + (((dst) & ~0x00000fff) | (((u32)(src)) & 0x00000fff)) +#define CFG_CLE_FPSEL0_SET(dst, src) \ + (((dst) & ~0x000f0000) | (((u32)(src)<<16) & 0x000f0000)) +#define CFG_CLE_HENQNUM0_SET(dst, src) \ + (((dst) & ~0x0fff0000) | (((u32)(src)<<16) & 0x0fff0000)) +#define MAC_INT_REG0_ADDR 0x00000514 +#define MAC_INT_REG1_ADDR 0x0000051c +#define ICM_CONFIG0_REG_0_ADDR 0x00000400 +#define ICM_CONFIG2_REG_0_ADDR 0x00000410 +#define ECM_CONFIG0_REG_0_ADDR 0x00000500 +#define RX_DV_GATE_REG_0_ADDR 0x000005fc +#define TX_DV_GATE_EN0_SET(dst, src) \ + (((dst) & ~0x00000004) | (((u32)(src)<<2) & 0x00000004)) +#define RX_DV_GATE_EN0_SET(dst, src) \ + (((dst) & ~0x00000002) | (((u32)(src)<<1) & 0x00000002)) +#define RESUME_RX0_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32)(src)) & 0x00000001)) +#define ICM_DATA_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x01000000)>>24) +#define ICM_DATA_FIFO_UNDERFL_INTR_PRT10_MASK 0x01000000 +#define ICM_DATA_FIFO_OVERFL_INTR_PRT10_MASK 0x00800000 +#define ICM_CTRL_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000020)>>5) +#define ICM_CTRL_FIFO_OVERFL_INTR_PRT00_MASK 0x00000020 +#define ICM_CTRL_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00200000)>>21) +#define ICM_CTRL_FIFO_OVERFL_INTR_PRT10_MASK 0x00200000 +#define ICM_CTRL_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00400000)>>22) +#define ICM_CTRL_FIFO_UNDERFL_INTR_PRT10_MASK 0x00400000 +#define ICM_CTRL_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000040)>>6) +#define ICM_CTRL_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000040 +#define ICM_DATA_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000080)>>7) +#define ICM_DATA_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00800000)>>23) +#define ICM_DATA_FIFO_OVERFL_INTR_PRT00_MASK 0x00000080 +#define ICM_DATA_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000100)>>8) +#define ICM_DATA_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000100 +#define ECM_DATA_FIFO_UNDERN_INTR_PRT00_RD(src) (((src) & 0x00000010)>>4) +#define ECM_DATA_FIFO_UNDERN_INTR_PRT00_MASK 0x00000010 +#define ECM_DATA_FIFO_UNDERN_INTR_PRT10_RD(src) (((src) & 0x00100000)>>20) +#define ECM_DATA_FIFO_UNDERN_INTR_PRT10_MASK 0x00100000 +#define ECM_DATA_FIFO_UNDERFL_INTR_PRT10_RD(src) (((src) & 0x00080000)>>19) +#define ECM_DATA_FIFO_UNDERFL_INTR_PRT10_MASK 0x00080000 +#define ECM_DATA_FIFO_OVERFL_INTR_PRT10_RD(src) (((src) & 0x00040000)>>18) +#define ECM_DATA_FIFO_OVERFL_INTR_PRT10_MASK 0x00040000 +#define CARRY_PORT01_RD(src) (((src) & 0x00000001)) +#define CARRY_PORT01_MASK 0x00000001 +#define LINKDOWN_PORT11_RD(src) (((src) & 0x00000008)>>3) +#define LINKDOWN_PORT11_MASK 0x00000008 +#define CARRY_PORT11_RD(src) (((src) & 0x00000004)>>2) +#define CARRY_PORT11_MASK 0x00000004 +#define LINKDOWN_PORT01_RD(src) (((src) & 0x00000002)>>1) +#define LINKDOWN_PORT01_MASK 0x00000002 +#define MACIF_FIFO_UNDERFL_INTR_RXPRT00_F2_RD(src) (((src) & 0x00000002)>>1) +#define MACIF_FIFO_UNDERFL_INTR_RXPRT00_F2_MASK 0x00000002 +#define MACIF_FIFO_UNDERFL_INTR_RXPRT10_F2_RD(src) (((src) & 0x00020000)>>17) +#define MACIF_FIFO_UNDERFL_INTR_RXPRT10_F2_MASK 0x00020000 +#define MACIF_FIFO_OVERFL_INTR_RXPRT00_F2_RD(src) (((src) & 0x00000001)) +#define MACIF_FIFO_OVERFL_INTR_RXPRT00_F2_MASK 0x00000001 +#define MACIF_FIFO_OVERFL_INTR_RXPRT10_F2_RD(src) (((src) & 0x00010000)>>16) +#define MACIF_FIFO_OVERFL_INTR_RXPRT10_F2_MASK 0x00010000 +#define ECM_DATA_FIFO_UNDERFL_INTR_PRT00_RD(src) (((src) & 0x00000008)>>3) +#define ECM_DATA_FIFO_UNDERFL_INTR_PRT00_MASK 0x00000008 +#define ECM_DATA_FIFO_OVERFL_INTR_PRT00_RD(src) (((src) & 0x00000004)>>2) +#define ECM_DATA_FIFO_OVERFL_INTR_PRT00_MASK 0x00000004 +#define ENET_STSSSQMIINT0_ADDR 0x0000009c +#define ENET_STSSSQMIINT1_ADDR 0x000000a4 +#define ENET_STSSSQMIINT2_ADDR 0x000000ac +#define ENET_STSSSQMIINT3_ADDR 0x000000b4 +#define ENET_STSSSQMIINT4_ADDR 0x000000bc +#define ENET_CFGSSQMIWQASSOC_ADDR 0x000000e0 +#define ENET_CFGSSQMIFPQASSOC_ADDR 0x000000dc +#define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0x000000f0 +#define ENET_CFGSSQMIQMLITEWQASSOC_ADDR 0x000000f4 +#define ENET_FPOVERFLOW0_RD(src) (((src) & 0xffffffff)) +#define ENET_WQOVERFLOW1_RD(src) (((src) & 0xffffffff)) +#define ENET_FPUNDERRUN2_RD(src) (((src) & 0xffffffff)) +#define ENET_WQUNDERRUN3_RD(src) (((src) & 0xffffffff)) +#define ENET_AXIWCMR_SLVERR4_RD(src) (((src) & 0x00000002)>>1) +#define ENET_AXIWCMR_SLVERR4_MASK 0x00000002 +#define ENET_FPOVERFLOW0_MASK 0xffffffff +#define ENET_WQOVERFLOW1_MASK 0xffffffff +#define ENET_FPUNDERRUN2_MASK 0xffffffff +#define ENET_WQUNDERRUN3_MASK 0xffffffff +#define ENET_CLKEN_ADDR 0x00000008 +#define ENET_SRST_ADDR 0x00000000 +#define CSR0_RESET_WR(src) (((u32)(src)) & 0x00000001) +#define ENET0_RESET_WR(src) (((u32)(src)<<1) & 0x00000002) +#define CSR1_RESET_WR(src) (((u32)(src)<<2) & 0x00000004) +#define ENET1_RESET_WR(src) (((u32)(src)<<3) & 0x00000008) +#define CSR0_CLKEN_WR(src) (((u32)(src)) & 0x00000001) +#define ENET0_CLKEN_WR(src) (((u32)(src)<<1) & 0x00000002) +#define CSR1_CLKEN_WR(src) (((u32)(src)<<2) & 0x00000004) +#define ENET1_CLKEN_WR(src) (((u32)(src)<<3) & 0x00000008) +#define ENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x00000070 +#define ENET_BLOCK_MEM_RDY_ADDR 0x00000074 +#define MAC_CONFIG_1_ADDR 0x00000000 +#define MAC_CONFIG_2_ADDR 0x00000004 +#define MAX_FRAME_LEN_ADDR 0x00000010 +#define MII_MGMT_CONFIG_ADDR 0x00000020 +#define MII_MGMT_COMMAND_ADDR 0x00000024 +#define MII_MGMT_ADDRESS_ADDR 0x00000028 +#define MII_MGMT_CONTROL_ADDR 0x0000002c +#define MII_MGMT_STATUS_ADDR 0x00000030 +#define MII_MGMT_INDICATORS_ADDR 0x00000034 +#define INTERFACE_CONTROL_ADDR 0x00000038 +#define STATION_ADDR0_ADDR 0x00000040 +#define STATION_ADDR1_ADDR 0x00000044 +#define RX_FLOW_EN1_MASK 0x00000020 +#define TX_FLOW_EN1_MASK 0x00000010 +#define RX_FLOW_EN1_RD(src) (((src) & 0x00000020)>>5) +#define TX_FLOW_EN1_RD(src) (((src) & 0x00000010)>>4) +#define SCAN_CYCLE_MASK 0x00000002 +#define SOFT_RESET1_MASK 0x80000000 +#define MAX_FRAME_LEN_SET(dst, src) \ + (((dst) & ~0x0000ffff) | (((u32)(src)) & 0x0000ffff)) +#define PHY_ADDR_SET(dst, src) \ + (((dst) & ~0x00001f00) | (((u32)(src)<<8) & 0x00001f00)) +#define REG_ADDR_SET(dst, src) \ + (((dst) & ~0x0000001f) | (((u32)(src)) & 0x0000001f)) +#define RESET_TX_FUN1_WR(src) (((u32)(src)<<16) & 0x00010000) +#define RESET_RX_FUN1_WR(src) (((u32)(src)<<17) & 0x00020000) +#define RESET_TX_MC1_WR(src) (((u32)(src)<<18) & 0x00040000) +#define RESET_RX_MC1_WR(src) (((u32)(src)<<19) & 0x00080000) +#define SIM_RESET1_WR(src) (((u32)(src)<<30) & 0x40000000) +#define SOFT_RESET1_WR(src) (((u32)(src)<<31) & 0x80000000) +#define TX_EN1_WR(src) (((u32)(src)) & 0x00000001) +#define RX_EN1_WR(src) (((u32)(src)<<2) & 0x00000004) +#define TX_FLOW_EN1_WR(src) (((u32)(src)<<4) & 0x00000010) +#define LOOP_BACK1_WR(src) (((u32)(src)<<8) & 0x00000100) +#define RX_FLOW_EN1_WR(src) (((u32)(src)<<5) & 0x00000020) +#define ENET_LHD_MODE_WR(src) (((u32)(src)<<25) & 0x02000000) +#define ENET_GHD_MODE_WR(src) (((u32)(src)<<26) & 0x04000000) +#define FULL_DUPLEX2_WR(src) (((u32)(src)) & 0x00000001) +#define LENGTH_CHECK2_WR(src) (((u32)(src)<<4) & 0x00000010) +#define HUGE_FRAME_EN2_WR(src) (((u32)(src)<<5) & 0x00000020) +#define ENET_INTERFACE_MODE2_WR(src) (((u32)(src)<<8) & 0x00000300) +#define PAD_CRC2_WR(src) (((u32)(src)<<2) & 0x00000004) +#define CRC_EN2_WR(src) (((u32)(src)<<1) & 0x00000002) +#define PREAMBLE_LENGTH2_WR(src) (((u32)(src)<<12) & 0x0000f000) +#define MAX_FRAME_LEN_WR(src) (((u32)(src)) & 0x0000ffff) +#define MGMT_CLOCK_SEL_SET(dst, src) \ + (((dst) & ~0x00000007) | (((u32)(src)) & 0x00000007)) +#define RX_EN1_SET(dst, src) \ + (((dst) & ~0x00000004) | (((u32)(src)<<2) & 0x00000004)) +#define TX_EN1_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32)(src)) & 0x00000001)) +#define SCAN_AUTO_INCR_MASK 0x00000020 +#define RBYT_ADDR 0x00000027 +#define RPKT_ADDR 0x00000028 +#define RFCS_ADDR 0x00000029 +#define RALN_ADDR 0x0000002f +#define RFLR_ADDR 0x00000030 +#define RUND_ADDR 0x00000033 +#define ROVR_ADDR 0x00000034 +#define RDRP_ADDR 0x00000037 +#define TBYT_ADDR 0x00000038 +#define TPKT_ADDR 0x00000039 +#define TDRP_ADDR 0x00000045 +#define TFCS_ADDR 0x00000047 +#define TUND_ADDR 0x0000004a +#define RX_BYTE_CNTR_MASK 0x7fffffff +#define RX_PKT_CNTR_MASK 0x7fffffff +#define RX_FCS_ERROR_CNTR_MASK 0x0000ffff +#define RX_ALIGN_ERR_CNTR_MASK 0x0000ffff +#define RX_LEN_ERR_CNTR_MASK 0x0000ffff +#define RX_UNDRSIZE_PKT_CNTR_MASK 0x0000ffff +#define RX_OVRSIZE_PKT_CNTR_MASK 0x0000ffff +#define RX_DROPPED_PKT_CNTR_MASK 0x0000ffff +#define TX_BYTE_CNTR_MASK 0x7fffffff +#define TX_PKT_CNTR_MASK 0x7fffffff +#define TX_DROP_FRAME_CNTR_MASK 0x0000ffff +#define TX_FCS_ERROR_CNTR_MASK 0x00000fff +#define TX_UNDSIZE_FRAME_CNTR_MASK 0x00000fff + +#endif /* __XGENE_ENET_CSR_H__ */ --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_err.c +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_err.c @@ -0,0 +1,511 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Ravi Patel + * Iyappan Subramanian + * Fushen Chen + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "xgene_enet_main.h" +#include "xgene_enet_csr.h" + +int xgene_enet_parse_error(u8 LErr, int qid) +{ + /* QM Error */ + switch (LErr) { + case 1: + pr_err("LErr[%d] QID %d: QM msg size error\n", LErr, qid); + return 0; + case 2: + pr_err("LErr[%d] QID %d: QM msg hop count error\n", LErr, qid); + return 0; + case 3: + pr_err("LErr[%d] QID %d: enqueue to virtual queue error\n", + LErr, qid); + return 0; + case 4: + pr_err("LErr[%d] QID %d: enqueue to disable queue error\n", + LErr, qid); + return 0; + case 5: + pr_err("LErr[%d] QID %d: queue overfill error\n", LErr, qid); + return 1; + case 6: + pr_err("LErr[%d] QID %d: QM enqueue error\n", LErr, qid); + return 0; + case 7: + pr_err("LErr[%d] QID %d: QM dequeue error\n", LErr, qid); + return 0; + } + return 0; +} + +static irqreturn_t xgene_enet_qmi_err_irq(int irq, void *dev_instance) +{ + struct xgene_enet_pdev *pdev; + struct xgene_enet_priv *priv; + int rc; + u32 data; + u32 int_mask = 0; + + pdev = netdev_priv(dev_instance); + priv = &pdev->priv; + pr_err("Received Ethernet QMI Error Interrupt\n"); + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, ENET_STSSSQMIINT0_ADDR, &data); + if (data) { + pr_err("Received STSSSQMIINT0 Error intr\n"); + if (ENET_FPOVERFLOW0_RD(data)) { + pr_err("FP PB overflow indication:0x%08X\n", data); + int_mask |= ENET_FPOVERFLOW0_MASK; + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + ENET_STSSSQMIINT0_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, ENET_STSSSQMIINT1_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received STSSSQMIINT1 Error Interrupt\n"); + if (ENET_WQOVERFLOW1_RD(data)) { + pr_err("WQ PB overflow indication:0x%08X\n", data); + int_mask |= ENET_WQOVERFLOW1_MASK; + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + ENET_STSSSQMIINT1_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, ENET_STSSSQMIINT2_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received STSSSQMIINT2 Error Interrupt\n"); + if (ENET_FPUNDERRUN2_RD(data)) { + pr_err("FP PB underrun indication:0x%08X\n", data); + int_mask |= ENET_FPUNDERRUN2_MASK; + } + + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + ENET_STSSSQMIINT2_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, ENET_STSSSQMIINT3_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received STSSSQMIINT3 Error Interrupt\n"); + if (ENET_WQUNDERRUN3_RD(data)) { + pr_err("WQ PB underrun indication:0x%08X\n", data); + int_mask |= ENET_WQUNDERRUN3_MASK; + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + ENET_STSSSQMIINT3_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, ENET_STSSSQMIINT4_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received STSSSQMIINT4 Error Interrupt\n"); + if (ENET_AXIWCMR_SLVERR4_RD(data)) { + pr_err("AXI slave error on write master channel\n"); + int_mask |= ENET_AXIWCMR_SLVERR4_MASK; + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + ENET_STSSSQMIINT4_ADDR, int_mask); + } + + return IRQ_HANDLED; +} + +static irqreturn_t xgene_enet_mac_err_irq(int irq, void *dev_instance) +{ + struct xgene_enet_pdev *pdev; + struct xgene_enet_priv *priv; + u8 bit; + int rc; + u32 data; + u32 int_mask = 0; + + static const char *mac_int_reg0_msgs[32] = { + "RxPort0 Mac i/f fifo overflow", /* bit 0 */ + "RxPort0 Mac i/f fifo underflow", + "TxPort0 ECM Data fifo overflow", + "TxPort0 ECM Data fifo underflow", + "RxPort0 ECM Data fifo underrun", + "RxPort0 ICM Ctrl fifo overflow", /* bit 5 */ + "RxPort0 ICM Ctrl fifo underflow", + "RxPort0 ICM Data fifo overflow", + "RxPort0 ICM Data fifo underflow", + "TxPort0 ECM EOF control fifo overflow", + "TxPort0 ECM EOF control fifo underflow", /* bit 10 */ + "TxPort0 ECM SOF control fifo overflow", + "TxPort0 ECM SOF control fifo underflow", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 15 */ + "RxPort1 Mac i/f fifo overflow", + "RxPort1 Mac i/f fifo underflow", + "TxPort1 ECM Data fifo overflow", + "TxPort1 ECM Data fifo underflow", + "RxPort1 ECM Data fifo underrun", /* bit 20 */ + "RxPort1 ICM Ctrl fifo overflow", + "RxPort1 ICM Ctrl fifo underflow", + "RxPort1 ICM Data fifo overflow", + "RxPort1 ICM Data fifo underflow", + "TxPort1 ECM EOF control fifo overflow", /* bit 25 */ + "TxPort1 ECM EOF control fifo underflow", + "TxPort1 ECM SOF control fifo overflow", + "TxPort1 ECM SOF control fifo underflow", + "Rsvd", + "Rsvd", + "Rsvd" + }; + + pdev = netdev_priv(dev_instance); + priv = &pdev->priv; + pr_err("Received Ethernet MAC Error Interrupt\n"); + + rc = xgene_enet_rd(priv, BLOCK_MCX_MAC_CSR, MAC_INT_REG0_ADDR, &data); + if (data) { + pr_err("Received MAC Error Interrupt\n"); + for_each_set_bit(bit, (unsigned long *)&data, 32) { + int_mask |= bit; + pr_err("%s interrupt\n", mac_int_reg0_msgs[bit]); + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_MCX_MAC_CSR, + MAC_INT_REG0_ADDR, int_mask); + } + + return IRQ_HANDLED; +} + +static irqreturn_t xgene_enet_err_irq(int irq, void *dev_instance) +{ + struct xgene_enet_pdev *pdev; + struct xgene_enet_priv *priv; + u8 bit; + int rc; + u32 data; + u32 int_mask = 0; + + static const char *rsif_int_reg0_msgs[32] = { + "Rx port0 buffer FIFO underflow", /* bit 0 */ + "Rx port0 buffer FIFO overflow", + "Rx port0 ctrl buffer FIFO underflow", + "Rx port0 ctrl buffer FIFO overflow", + "Rx port0 classifier buffer FIFO underflow", + "Rx port0 classifier buffer FIFO overflow", /* bit 5 */ + "Rx port0 err buffer FIFO underflow", + "Rx port0 err buffer FIFO overflow", + "Rx port0 timestamp FIFO underflow", + "Rx port0 timestamp buffer FIFO overflow", + "Rx port0 chksum buffer FIFO underflow", /* bit 10 */ + "Rx port0 chksum buffer FIFO overflow", + "Rx port0 Local Rx buffer FIFO underflow", + "Rx port0 Local Rx buffer FIFO overflow", + "Policer CLE FIFO underflow", + "Policer CLE FIFO overflow", /* bit 15 */ + "Rx port1 buffer FIFO underflow", + "Rx port1 buffer FIFO overflow", + "Rx port1 ctrl buffer FIFO underflow", + "Rx port1 ctrl buffer FIFO overflow", + "Rx port1 classifier buffer FIFO underflow", /* bit 20 */ + "Rx port1 classifier buffer FIFO overflow", + "Rx port1 err buffer FIFO underflow", + "Rx port1 err buffer FIFO overflow", + "Rx port1 timestamp FIFO underflow", + "Rx port1 timestamp buffer FIFO overflow", /* bit 25 */ + "Rx port1 chksum buffer FIFO underflow", + "Rx port1 chksum buff FIFO overflow", + "Rx port1 Local Rxbuff FIFO underflow", + "Rx port1 Local Rxbuff FIFO overflow", + "Rx policer EOF FIFO underflow", + "Rx policer EOF FIFO overflow" + }; + + static const char *rsif_fint_reg0_msgs[32] = { + "Packet dropped by policer", /* bit 0 */ + "AXI write error on port0", + "Freepool buffer was NOT available from QMI on port0", + "Split boundary can't be accomodated in the 1st buf in port0", + "Mirror buf addr offset/len do not match with normal xfr port0", + "Received FP buf w/ invalid len encoding on port0", /* bit 5 */ + "Number of LL buffers for a packet on port 0 exceeded 256", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 10 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 15 */ + "AXI write error on port1", + "Freepool buffer was NOT available from QMI on port1", + "Split boundary can't be accomodated in 1st buffer in port1", + "Mirror buf addr offset/len do not match with normal xfr port1", + "Received FP buf w/ invalid len encoding on port1", /* bit 20 */ + "Number of LL buffers for a packet on port 0 exceeded 256", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 25 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd" + }; + + static const char *tsif_int_reg0_msgs[32] = { + "Tx port0 AMA buffer FIFO underflow", /* bit 0 */ + "Tx port0 AMA buffer FIFO overflow", + "Tx port0 RRM buffer FIFO underflow", + "Tx port0 RRM buffer FIFO overflow", + "Tx port0 RDM buffer FIFO underflow", + "Tx port0 RDM buffer FIFO overflow", /* bit 5 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 10 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 15 */ + "Tx port1 AMA buffer FIFO underflow", + "Tx port1 AMA buffer FIFO overflow", + "Tx port1 RRM buffer FIFO underflow", + "Tx port1 RRM buffer FIFO overflow", + "Tx port1 RDM buffer FIFO underflow", /* bit 20 */ + "Tx port1 RDM buffer FIFO overflow", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 25 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd" + }; + + static const char *tsif_fint_reg0_msgs[32] = { + "Bad message received by TSIF on port0", /* bit 0 */ + "AXI error when reading data from port0", + "AXI error when reading data from port0", + "TSO error: header length > pkt length on port 0", + "Msg received with LL=1, NV=0 on port 0", + /* bit 5 */ + "TSO error: header len did not fit in the inline buffers port0", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 10 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 15 */ + "Bad message received by TSIF on port1", + "AXI error when reading data from port1", + "AXI error when reading data from port1", + "TSO error: header length > pkt length on port 1", + "Msg received with LL=1, NV=0 on port 1", /* bit 20 */ + "TSO error: header len did not fit in the inline buffers port1", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 25 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd" + }; + + static const char *tso_int_reg0_msgs[32] = { + "Tx port0 Message Hold FIFO underflow", /* bit 0 */ + "Tx port0 Message Hold FIFO overflow", + "Tx port0 Dealloc FIFO underflow", + "Tx port0 Dealloc FIFO overflow", + "Tx port0 tso_txbuff FIFO underflow", + "Tx port0 tso_txbuff FIFO overflow", /* bit 5 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 10 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 15 */ + "Tx port1 Message Hold FIFO underflow", + "Tx port1 Message Hold FIFO overflow", + "Tx port1 Dealloc FIFO underflow", + "Tx port1 Dealloc FIFO overflow", + "Tx port1 tso_txbuff FIFO underflow", /* bit 20 */ + "Tx port1 tso_txbuff FIFO overflow", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 25 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd" + }; + + static const char *rx_tx_buf_chksm_int_reg0[32] = { + "Tx port0 rx buffer FIFO underflow", /* bit 0 */ + "Tx port0 rx buffer FIFO overflow", + "Rx port0 rx buffer FIFO underflow", + "Rx port0 rx buffer FIFO overflow", + "Tx port0 Chksum Error", + "Rx port0 Chksum Error", /* bit 5 */ + "Rx port0 Pause", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 10 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 15 */ + "Tx port1 rx buffer FIFO underflow", + "Tx port1 rx buffer FIFO overflow", + "Rx port1 rx buffer FIFO underflow", + "Rx port1 rx buffer FIFO overflow", + "Tx port1 Chksum Error", /* bit 20 */ + "Rx port1 Chksum Error", + "Rx port1 Pause", + "Rsvd", + "Rsvd", + "Rsvd", /* bit 25 */ + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd", + "Rsvd" + }; + + pdev = netdev_priv(dev_instance); + priv = &pdev->priv; + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, RSIF_INT_REG0_ADDR, &data); + if (data) { + pr_err("Received RSIF Error Interrupt\n"); + for_each_set_bit(bit, (unsigned long *)&data, 32) { + int_mask |= bit; + pr_err("%s interrupt\n", rsif_int_reg0_msgs[bit]); + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + RSIF_INT_REG0_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, RSIF_FINT_REG0_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received RSIF Error2 Interrupt\n"); + for_each_set_bit(bit, (unsigned long *)&data, 32) { + int_mask |= bit; + pr_err("%s\n", rsif_fint_reg0_msgs[bit]); + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + RSIF_FINT_REG0_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, TSIF_INT_REG0_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received TSIF Error Interrupt\n"); + for_each_set_bit(bit, (unsigned long *)&data, 32) { + int_mask |= bit; + pr_err("%s interrupt\n", tsif_int_reg0_msgs[bit]); + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSIF_INT_REG0_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, TSIF_FINT_REG0_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received TSIF Error Interrupt\n"); + for_each_set_bit(bit, (unsigned long *)&data, 32) { + int_mask |= bit; + pr_err("%s\n", tsif_fint_reg0_msgs[bit]); + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSIF_FINT_REG0_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, TSO_INT_REG0_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received TSO Error Interrupt\n"); + for_each_set_bit(bit, (unsigned long *)&data, 32) { + int_mask |= bit; + pr_err("%s interrupt\n", tso_int_reg0_msgs[bit]); + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSO_INT_REG0_ADDR, int_mask); + } + rc = xgene_enet_rd(priv, BLOCK_ETH_CSR, + RX_TX_BUF_CHKSM_INT_REG0_ADDR, &data); + int_mask = 0; + if (data) { + pr_err("Received RX/TX Buffer Checksum Error Interrupt\n"); + for_each_set_bit(bit, (unsigned long *)&data, 32) { + int_mask |= bit; + pr_err("%s interrupt\n", rx_tx_buf_chksm_int_reg0[bit]); + } + /* Clear intrstatus bits, its COW */ + rc = xgene_enet_wr(priv, BLOCK_ETH_CSR, + RX_TX_BUF_CHKSM_INT_REG0_ADDR, int_mask); + } + + return IRQ_HANDLED; +} + +void xgene_enet_register_err_irqs(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev; + struct device *dev; + + pdev = (struct xgene_enet_pdev *)netdev_priv(ndev); + dev = &pdev->plat_dev->dev; + + if ((devm_request_irq(dev, pdev->enet_err_irq, xgene_enet_err_irq, + IRQF_SHARED, ndev->name, ndev)) != 0) + netdev_err(ndev, "Failed to reg Enet Error IRQ %d\n", + pdev->enet_err_irq); + if ((devm_request_irq(dev, pdev->enet_mac_err_irq, + xgene_enet_mac_err_irq, IRQF_SHARED, + ndev->name, ndev)) != 0) + netdev_err(ndev, "Failed to reg Enet MAC Error IRQ %d\n", + pdev->enet_mac_err_irq); + if ((devm_request_irq(dev, pdev->enet_qmi_err_irq, + xgene_enet_qmi_err_irq, + IRQF_SHARED, ndev->name, ndev)) != 0) + netdev_err(ndev, "Failed to reg Enet QMI Error IRQ %d\n", + pdev->enet_qmi_err_irq); +} --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_mac.c +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_mac.c @@ -0,0 +1,514 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Ravi Patel + * Iyappan Subramanian + * Fushen Chen + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "xgene_enet_main.h" +#include "xgene_enet_csr.h" + +static void xgene_gmac_set_mac_addr(struct xgene_enet_priv *priv, + unsigned char *dev_addr) +{ + u32 a_hi = *(u32 *)&dev_addr[0]; + u32 a_lo = (u32) *(u16 *)&dev_addr[4]; + xgene_enet_wr(priv, BLOCK_MCX_MAC, STATION_ADDR0_ADDR, a_hi); + + a_lo <<= 16; + a_lo |= (priv->phy_addr & 0xFFFF); + xgene_enet_wr(priv, BLOCK_MCX_MAC, STATION_ADDR1_ADDR, a_lo); +} + +static int xgene_enet_ecc_init(struct xgene_enet_priv *priv) +{ + u32 data; + int wait; + + xgene_enet_wr(priv, BLOCK_ETH_DIAG_CSR, + ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); + /* check for at leaset 1 ms */ + wait = 1000; + do { + xgene_enet_rd(priv, BLOCK_ETH_DIAG_CSR, + ENET_BLOCK_MEM_RDY_ADDR, &data); + usleep_range(1, 100); + } while (--wait && data != 0xffffffff); + if (!wait) { + pr_err("Failed to release memory from shutdown\n"); + return -ENODEV; + } + + return 0; +} + +static void xgene_gmac_change_mtu(struct xgene_enet_priv *priv, u32 new_mtu) +{ + u32 data; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAX_FRAME_LEN_ADDR, &data); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAX_FRAME_LEN_ADDR, + MAX_FRAME_LEN_SET(data, new_mtu)); +} + +static void xgene_gmac_phy_enable_scan_cycle(struct xgene_enet_priv *priv, + int enable) +{ + u32 val; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MII_MGMT_COMMAND_ADDR, &val); + if (enable) + val |= SCAN_CYCLE_MASK; + else + val &= ~SCAN_CYCLE_MASK; + xgene_enet_wr(priv, BLOCK_MCX_MAC, MII_MGMT_COMMAND_ADDR, val); + + /* Program phy address start scan from 0 and register at address 0x1 */ + xgene_enet_rd(priv, BLOCK_MCX_MAC, MII_MGMT_ADDRESS_ADDR, &val); + val = PHY_ADDR_SET(val, 0); + val = REG_ADDR_SET(val, 1); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MII_MGMT_ADDRESS_ADDR, val); +} + +static void xgene_gmac_reset(struct xgene_enet_priv *priv) +{ + u32 value; + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &value); + if (!(value & SOFT_RESET1_MASK)) + return; + + value = RESET_TX_FUN1_WR(1) + | RESET_RX_FUN1_WR(1) + | RESET_TX_MC1_WR(1) + | RESET_RX_MC1_WR(1) + | SIM_RESET1_WR(1) + | SOFT_RESET1_WR(1); + + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, value); + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &value); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, 0); +} + +int xgene_gmac_init(struct xgene_enet_priv *priv, unsigned char *dev_addr, + int speed, int mtu, int crc) +{ + u32 value, temp; + u32 addr_hi, addr_lo; + + u32 interface_control; + u32 mac_config_2; + u32 rgmii; + u32 icm_config0 = 0x0008503f; + u32 icm_config2 = 0x0010000f; + u32 ecm_config0 = 0x00000032; + u32 enet_spare_cfg = 0x00006040; + + /* Reset subsystem */ + value = RESET_TX_FUN1_WR(1) + | RESET_RX_FUN1_WR(1) + | RESET_TX_MC1_WR(1) + | RESET_RX_MC1_WR(1) + | SIM_RESET1_WR(1) + | SOFT_RESET1_WR(1); + + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, value); + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &temp); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, 0); + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &temp); + + value = TX_EN1_WR(1) + | RX_EN1_WR(1) + | TX_FLOW_EN1_WR(0) + | LOOP_BACK1_WR(0) + | RX_FLOW_EN1_WR(0); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, value); + xgene_enet_rd(priv, BLOCK_ETH_CSR, + ENET_SPARE_CFG_REG_ADDR, &enet_spare_cfg); + + if (speed == XGENE_ENET_SPEED_10) { + interface_control = ENET_LHD_MODE_WR(0) + | ENET_GHD_MODE_WR(0); + mac_config_2 = FULL_DUPLEX2_WR(1) + | LENGTH_CHECK2_WR(0) + | HUGE_FRAME_EN2_WR(0) + | ENET_INTERFACE_MODE2_WR(1) /* 10Mbps */ + |PAD_CRC2_WR(crc) + | CRC_EN2_WR(crc) + | PREAMBLE_LENGTH2_WR(7); + rgmii = 0; + icm_config0 = 0x0000503f; + icm_config2 = 0x000101f4; + ecm_config0 = 0x600032; + enet_spare_cfg = enet_spare_cfg | (0x0000c040); + } else if (speed == XGENE_ENET_SPEED_100) { + interface_control = ENET_LHD_MODE_WR(1); + mac_config_2 = FULL_DUPLEX2_WR(1) + | LENGTH_CHECK2_WR(0) + | HUGE_FRAME_EN2_WR(0) + | ENET_INTERFACE_MODE2_WR(1) /* 100Mbps */ + |PAD_CRC2_WR(crc) + | CRC_EN2_WR(crc) + | PREAMBLE_LENGTH2_WR(7); + rgmii = 0; + icm_config0 = 0x0004503f; + icm_config2 = 0x00010050; + ecm_config0 = 0x600032; + enet_spare_cfg = enet_spare_cfg | (0x0000c040); + } else { + interface_control = ENET_GHD_MODE_WR(1); + mac_config_2 = FULL_DUPLEX2_WR(1) + | LENGTH_CHECK2_WR(0) + | HUGE_FRAME_EN2_WR(0) + | ENET_INTERFACE_MODE2_WR(2) /* 1Gbps */ + |PAD_CRC2_WR(crc) + | CRC_EN2_WR(crc) + | PREAMBLE_LENGTH2_WR(7); + rgmii = CFG_SPEED_1250_WR(1) | CFG_TXCLK_MUXSEL0_WR(4); + icm_config0 = 0x0008503f; + icm_config2 = 0x0001000f; + ecm_config0 = 0x32; + enet_spare_cfg = (enet_spare_cfg & ~0x0000c000) + | (0x00000040); + } + + enet_spare_cfg |= 0x00006040; + + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_2_ADDR, mac_config_2); + + xgene_enet_wr(priv, BLOCK_MCX_MAC, INTERFACE_CONTROL_ADDR, + interface_control); + + value = MAX_FRAME_LEN_WR(0x0600); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAX_FRAME_LEN_ADDR, value); + + /* Program the station MAC address */ + addr_hi = *(u32 *) &dev_addr[0]; + addr_lo = *(u16 *) &dev_addr[4]; + addr_lo <<= 16; + addr_lo |= (priv->phy_addr & 0xFFFF); + + xgene_enet_wr(priv, BLOCK_MCX_MAC, STATION_ADDR0_ADDR, addr_hi); + xgene_enet_wr(priv, BLOCK_MCX_MAC, STATION_ADDR1_ADDR, addr_lo); + + /* Adjust MDC clock frequency */ + xgene_enet_rd(priv, BLOCK_MCX_MAC, MII_MGMT_CONFIG_ADDR, &value); + value = MGMT_CLOCK_SEL_SET(value, 7); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MII_MGMT_CONFIG_ADDR, value); + + /* Enable drop if FP not available */ + xgene_enet_rd(priv, BLOCK_ETH_CSR, RSIF_CONFIG_REG_ADDR, &value); + value |= CFG_RSIF_FPBUFF_TIMEOUT_EN_WR(1); + xgene_enet_wr(priv, BLOCK_ETH_CSR, RSIF_CONFIG_REG_ADDR, value); + + /* Rtype should be copied from FP */ + value = 0; + xgene_enet_wr(priv, BLOCK_ETH_CSR, RSIF_RAM_DBG_REG0_ADDR, value); + /* Initialize RGMII PHY */ + if (priv->phy_mode == PHY_MODE_RGMII) + xgene_enet_wr(priv, BLOCK_ETH_CSR, RGMII_REG_0_ADDR, rgmii); + + xgene_enet_wr(priv, BLOCK_MCX_MAC_CSR, ICM_CONFIG0_REG_0_ADDR, + icm_config0); + xgene_enet_wr(priv, BLOCK_MCX_MAC_CSR, ICM_CONFIG2_REG_0_ADDR, + icm_config2); + xgene_enet_wr(priv, BLOCK_MCX_MAC_CSR, ECM_CONFIG0_REG_0_ADDR, + ecm_config0); + xgene_enet_wr(priv, BLOCK_ETH_CSR, ENET_SPARE_CFG_REG_ADDR, + enet_spare_cfg); + + /* Rx-Tx traffic resume */ + xgene_enet_wr(priv, BLOCK_ETH_CSR, + CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0_WR(0x1)); + + if (speed != XGENE_ENET_SPEED_10 && speed != XGENE_ENET_SPEED_100) { + xgene_enet_rd(priv, BLOCK_ETH_CSR, DEBUG_REG_ADDR, &value); + value |= CFG_BYPASS_UNISEC_TX_WR(1) + | CFG_BYPASS_UNISEC_RX_WR(1); + xgene_enet_wr(priv, BLOCK_ETH_CSR, DEBUG_REG_ADDR, value); + } + + xgene_enet_rd(priv, BLOCK_MCX_MAC_CSR, RX_DV_GATE_REG_0_ADDR, &value); + value = TX_DV_GATE_EN0_SET(value, 0); + value = RX_DV_GATE_EN0_SET(value, 0); + value = RESUME_RX0_SET(value, 1); + xgene_enet_wr(priv, BLOCK_MCX_MAC_CSR, RX_DV_GATE_REG_0_ADDR, value); + + xgene_enet_wr(priv, BLOCK_ETH_CSR, CFG_BYPASS_ADDR, RESUME_TX_WR(1)); + return 0; +} + +/* Start Statistics related functions */ +static void xgene_gmac_get_rx_stats(struct xgene_enet_priv *priv, + struct xgene_enet_rx_stats *rx_stat) +{ + xgene_enet_rd(priv, BLOCK_MCX_STATS, RBYT_ADDR, + &rx_stat->rx_byte_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, RPKT_ADDR, + &rx_stat->rx_packet_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, RDRP_ADDR, + &rx_stat->rx_drop_pkt_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, RFCS_ADDR, + &rx_stat->rx_fcs_err_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, RFLR_ADDR, + &rx_stat->rx_frm_len_err_pkt_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, RALN_ADDR, + &rx_stat->rx_alignment_err_pkt_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, ROVR_ADDR, + &rx_stat->rx_oversize_pkt_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, RUND_ADDR, + &rx_stat->rx_undersize_pkt_count); + + rx_stat->rx_byte_count &= RX_BYTE_CNTR_MASK; + rx_stat->rx_packet_count &= RX_PKT_CNTR_MASK; + rx_stat->rx_drop_pkt_count &= RX_DROPPED_PKT_CNTR_MASK; + rx_stat->rx_fcs_err_count &= RX_FCS_ERROR_CNTR_MASK; + rx_stat->rx_frm_len_err_pkt_count &= RX_LEN_ERR_CNTR_MASK; + rx_stat->rx_alignment_err_pkt_count &= RX_ALIGN_ERR_CNTR_MASK; + rx_stat->rx_oversize_pkt_count &= RX_OVRSIZE_PKT_CNTR_MASK; + rx_stat->rx_undersize_pkt_count &= RX_UNDRSIZE_PKT_CNTR_MASK; +} + +static void xgene_gmac_get_tx_stats(struct xgene_enet_priv *priv, + struct xgene_enet_tx_stats *tx_stats) +{ + xgene_enet_rd(priv, BLOCK_MCX_STATS, TBYT_ADDR, + &tx_stats->tx_byte_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, TPKT_ADDR, + &tx_stats->tx_pkt_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, TDRP_ADDR, + &tx_stats->tx_drop_frm_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, TFCS_ADDR, + &tx_stats->tx_fcs_err_frm_count); + xgene_enet_rd(priv, BLOCK_MCX_STATS, TUND_ADDR, + &tx_stats->tx_undersize_frm_count); + + tx_stats->tx_byte_count &= TX_BYTE_CNTR_MASK; + tx_stats->tx_pkt_count &= TX_PKT_CNTR_MASK; + tx_stats->tx_drop_frm_count &= TX_DROP_FRAME_CNTR_MASK; + tx_stats->tx_fcs_err_frm_count &= TX_FCS_ERROR_CNTR_MASK; + tx_stats->tx_undersize_frm_count &= TX_UNDSIZE_FRAME_CNTR_MASK; +} + +static void xgene_gmac_get_detailed_stats(struct xgene_enet_priv *priv, + struct xgene_enet_detailed_stats *stats) +{ + xgene_gmac_get_rx_stats(priv, &(stats->rx_stats)); + xgene_gmac_get_tx_stats(priv, &(stats->tx_stats)); +} + +/* Configure Ethernet QMI: WQ and FPQ association to QML */ +static void xgene_enet_config_qmi_assoc(struct xgene_enet_priv *priv) +{ + xgene_enet_wr(priv, BLOCK_ETH_QMI, ENET_CFGSSQMIWQASSOC_ADDR, + 0xffffffff); + xgene_enet_wr(priv, BLOCK_ETH_QMI, ENET_CFGSSQMIFPQASSOC_ADDR, + 0xffffffff); + xgene_enet_wr(priv, BLOCK_ETH_QMI, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, + 0xffffffff); + xgene_enet_wr(priv, BLOCK_ETH_QMI, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, + 0xffffffff); +} + +static void xgene_enet_cle_bypass_mode_cfg(struct xgene_enet_priv *priv, + u32 cle_dstqid, u32 cle_fpsel) +{ + u32 reg; + + xgene_enet_rd(priv, BLOCK_ETH_CSR, CLE_BYPASS_REG0_0_ADDR, ®); + reg = CFG_CLE_BYPASS_EN0_SET(reg, 1); + reg = CFG_CLE_IP_PROTOCOL0_SET(reg, 3); + xgene_enet_wr(priv, BLOCK_ETH_CSR, CLE_BYPASS_REG0_0_ADDR, reg); + + xgene_enet_rd(priv, BLOCK_ETH_CSR, CLE_BYPASS_REG1_0_ADDR, ®); + reg = CFG_CLE_DSTQID0_SET(reg, cle_dstqid); + reg = CFG_CLE_FPSEL0_SET(reg, cle_fpsel); + xgene_enet_wr(priv, BLOCK_ETH_CSR, CLE_BYPASS_REG1_0_ADDR, reg); + + xgene_enet_rd(priv, BLOCK_ETH_CSR, CLE_BYPASS_REG8_0_ADDR, ®); + reg = CFG_CLE_HENQNUM0_SET(reg, cle_dstqid); + xgene_enet_wr(priv, BLOCK_ETH_CSR, CLE_BYPASS_REG8_0_ADDR, reg); +} + +static void xgene_gmac_rx_state(struct xgene_enet_priv *priv, u32 enable) +{ + u32 data, rx_en; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + rx_en = (enable) ? RX_EN1_SET(data, 1) : RX_EN1_SET(data, 0); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, rx_en); +} + +static void xgene_gmac_tx_state(struct xgene_enet_priv *priv, u32 enable) +{ + u32 data, tx_en; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + tx_en = (enable) ? TX_EN1_SET(data, 1) : TX_EN1_SET(data, 0); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, tx_en); +} + +static void xgene_gmac_tx_offload(struct xgene_enet_priv *priv, + u32 command, u32 value) +{ + u32 data; + + switch (command) { + /* TCP MSS 0 */ + case XGENE_ENET_MSS0: + xgene_enet_rd(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG0_0_ADDR, &data); + xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG0_0_ADDR, + CFG_TSIF_MSS_SZ00_SET(data, value)); + break; + /* TCP MSS 1 */ + case XGENE_ENET_MSS1: + xgene_enet_rd(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG0_0_ADDR, &data); + xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG0_0_ADDR, + CFG_TSIF_MSS_SZ10_SET(data, value)); + break; + /* TCP MSS 2 */ + case XGENE_ENET_MSS2: + xgene_enet_rd(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG1_0_ADDR, &data); + xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG1_0_ADDR, + CFG_TSIF_MSS_SZ20_SET(data, value)); + break; + /* TCP MSS 3 */ + case XGENE_ENET_MSS3: + xgene_enet_rd(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG1_0_ADDR, &data); + xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSIF_MSS_REG1_0_ADDR, + CFG_TSIF_MSS_SZ30_SET(data, value)); + break; + /* Program TSO config */ + case XGENE_ENET_TSO_CFG: + xgene_enet_wr(priv, BLOCK_ETH_CSR, TSO_CFG_0_ADDR, + value); + break; + /* Insert Inser tVLAN TAG */ + case XGENE_ENET_INSERT_VLAN: + xgene_enet_wr(priv, BLOCK_ETH_CSR, + TSO_CFG_INSERT_VLAN_0_ADDR, value); + break; + } +} + +static void xgene_enet_clkrst_cfg(struct xgene_enet_priv *priv) +{ + u32 data; + + /* disable all clocks */ + data = CSR0_CLKEN_WR(0) | ENET0_CLKEN_WR(0) | + CSR1_CLKEN_WR(0) | ENET1_CLKEN_WR(0); + xgene_enet_wr(priv, BLOCK_ETH_CLKRST_CSR, ENET_CLKEN_ADDR, data); + + /* enable all clocks */ + data = CSR0_CLKEN_WR(1) | ENET0_CLKEN_WR(1) | + CSR1_CLKEN_WR(1) | ENET1_CLKEN_WR(1); + xgene_enet_wr(priv, BLOCK_ETH_CLKRST_CSR, ENET_CLKEN_ADDR, data); + + /* put csr and core reset */ + data = CSR0_RESET_WR(1) | ENET0_RESET_WR(1) | + CSR1_RESET_WR(1) | ENET1_RESET_WR(1); + xgene_enet_wr(priv, BLOCK_ETH_CLKRST_CSR, ENET_SRST_ADDR, data); + + /* release csr and core reset */ + data = CSR0_RESET_WR(0) | ENET0_RESET_WR(0) | + CSR1_RESET_WR(0) | ENET1_RESET_WR(0); + xgene_enet_wr(priv, BLOCK_ETH_CLKRST_CSR, ENET_SRST_ADDR, data); + + xgene_enet_ecc_init(priv); +} + +static void xgene_gport_reset(struct xgene_enet_priv *priv) +{ + u32 val; + + xgene_enet_clkrst_cfg(priv); + xgene_enet_config_qmi_assoc(priv); + + /* Enable auto-incr for scanning */ + xgene_enet_rd(priv, BLOCK_MCX_MAC, MII_MGMT_CONFIG_ADDR, &val); + val |= SCAN_AUTO_INCR_MASK; + val = MGMT_CLOCK_SEL_SET(val, 1); + xgene_enet_wr(priv, BLOCK_MCX_MAC, MII_MGMT_CONFIG_ADDR, val); + xgene_gmac_phy_enable_scan_cycle(priv, 1); +} + +static void xgene_gport_shutdown(struct xgene_enet_priv *priv) +{ + u32 clk, rst; + + rst = CSR0_RESET_WR(1) | ENET0_RESET_WR(1); + clk = CSR0_CLKEN_WR(0) | ENET0_CLKEN_WR(0); + + /* reset ethernet csr, core and disable clock */ + xgene_enet_wr(priv, BLOCK_ETH_CLKRST_CSR, ENET_SRST_ADDR, rst); + xgene_enet_wr(priv, BLOCK_ETH_CLKRST_CSR, ENET_CLKEN_ADDR, clk); +} + +void xgene_enet_init_priv(struct xgene_enet_priv *priv) +{ + void *gbl_vaddr = priv->vaddr_base; + void *port_vaddr = priv->vpaddr_base; + + /* Initialize base addresses for direct access */ + priv->eth_csr_addr_v = gbl_vaddr + BLOCK_ETH_CSR_OFFSET; + priv->eth_cle_addr_v = gbl_vaddr + BLOCK_ETH_CLE_OFFSET; + priv->eth_qmi_addr_v = gbl_vaddr + BLOCK_ETH_QMI_OFFSET; + priv->eth_sds_csr_addr_v = gbl_vaddr + BLOCK_ETH_SDS_CSR_OFFSET; + priv->eth_clkrst_csr_addr_v = gbl_vaddr + BLOCK_ETH_CLKRST_CSR_OFFSET; + priv->eth_diag_csr_addr_v = gbl_vaddr + BLOCK_ETH_DIAG_CSR_OFFSET; + + /* Initialize per port base addr for indirect & direct MCX MAC access */ + priv->mcx_mac_addr_v = port_vaddr + BLOCK_ETH_MAC_OFFSET; + priv->mcx_stats_addr_v = port_vaddr + BLOCK_ETH_STATS_OFFSET; + priv->mcx_mac_csr_addr_v = gbl_vaddr + BLOCK_ETH_MAC_CSR_OFFSET; + priv->sata_enet_csr_addr_v = gbl_vaddr + BLOCK_SATA_ENET_CSR_OFFSET; + + /* Enable autonegotiation by default */ + priv->autoneg_set = 1; + + pr_debug(" ETH PORT VADDR: 0x%p\n", priv->vpaddr_base); + pr_debug(" ETH VADDR: 0x%p\n", priv->vaddr_base); + pr_debug(" ETH CSR VADDR: 0x%p\n", priv->eth_csr_addr_v); + pr_debug(" ETH CLE VADDR: 0x%p\n", priv->eth_cle_addr_v); + pr_debug(" ETH QMI VADDR: 0x%p\n", priv->eth_qmi_addr_v); + pr_debug(" ETH SDS CSR VADDR: 0x%p\n", priv->eth_sds_csr_addr_v); + pr_debug("ETH CLKRST CSR VADDR: 0x%p\n", priv->eth_clkrst_csr_addr_v); + pr_debug(" ETH DIAG VADDR: 0x%p\n", priv->eth_diag_csr_addr_v); + pr_debug(" MAC MII VADDR: 0x%p\n", priv->vmii_base); + pr_debug(" MCX MAC VADDR: 0x%p\n", priv->mcx_mac_addr_v); + pr_debug(" MCX STAT VADDR: 0x%p\n", priv->mcx_stats_addr_v); + pr_debug(" MCX MAC CSR VADDR: 0x%p\n", priv->mcx_mac_csr_addr_v); + pr_debug(" SATA ENET CSR VADDR: 0x%p\n", priv->sata_enet_csr_addr_v); + + /* Initialize priv handlers */ + priv->port_reset = xgene_gport_reset; + priv->mac_reset = xgene_gmac_reset; + priv->mac_init = xgene_gmac_init; + priv->mac_rx_state = xgene_gmac_rx_state; + priv->mac_tx_state = xgene_gmac_tx_state; + priv->mac_change_mtu = xgene_gmac_change_mtu; + priv->set_mac_addr = xgene_gmac_set_mac_addr; + priv->cle_bypass = xgene_enet_cle_bypass_mode_cfg; + priv->tx_offload = xgene_gmac_tx_offload; + priv->port_shutdown = xgene_gport_shutdown; + priv->get_stats = xgene_gmac_get_detailed_stats; +} --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_common.h +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_common.h @@ -0,0 +1,449 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Ravi Patel rapatel@apm.com> + * Iyappan Subramanian isubramanian@apm.com> + * Fushen Chen fchen@apm.com> + * Keyur Chudgar kchudgar@apm.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __XGENE_ENET_COMMON_H__ +#define __XGENE_ENET_COMMON_H__ + +#include +#define MAX_LOOP_POLL_CNT 10 + +#ifndef UDP_HDR_SIZE +#define UDP_HDR_SIZE 2 +#endif + +/* Ethernet & XGENET port ids */ +enum eth_port_ids { + ENET_0 = 0, + ENET_1, + ENET_2, + ENET_3, + XGENET_0, + XGENET_1, + XGENET_2, + XGENET_3, + MENET, + MAX_ENET_PORTS +}; + +/* TSO Parameters */ +#define TSO_ENABLE 1 +#define TSO_ENABLE_MASK 1 +#define TSO_CHKSUM_ENABLE 1 +#define TSO_INS_CRC_ENABLE 1 +#define TSO_IPPROTO_TCP 1 +#define TSO_IPPROTO_UDP 0 +#define TSO_IP_HLEN_MASK 0X3F +#define TSO_TCP_HLEN_MASK 0X3F +#define TSO_ETH_HLEN_MASK 0XFF +#define TSO_MSS_MASK 0X3 /* 2b */ +#define DEFAULT_TCP_MSS 1448 + +enum { + XGENE_ENET_MSS0 = 0, + XGENE_ENET_MSS1, + XGENE_ENET_MSS2, + XGENE_ENET_MSS3, + XGENE_ENET_TSO_CFG, + XGENE_ENET_INSERT_VLAN +}; + +/* TYPE_SEL for Ethernt egress message */ +#define TYPE_SEL_WORK_MSG 1U + +/* Blocks for defined regions */ +enum { + BLOCK_ETH_CSR = 1, + BLOCK_ETH_CLE, + BLOCK_ETH_QMI, + BLOCK_ETH_SDS_CSR, + BLOCK_ETH_CLKRST_CSR, + BLOCK_ETH_DIAG_CSR, + BLOCK_ETH_MDIO_CSR, + BLOCK_ETH_INTPHY, + BLOCK_ETH_EXTPHY, + BLOCK_MCX_MAC, + BLOCK_MCX_STATS, + BLOCK_MCX_MAC_CSR, + BLOCK_SATA_ENET_CSR, + BLOCK_AXG_MAC, + BLOCK_AXG_STATS, + BLOCK_AXG_MAC_CSR, + BLOCK_XGENET_PCS, + BLOCK_XGENET_MDIO_CSR, + BLOCK_ETH_MAX +}; + +/* Direct Address mode */ +#define BLOCK_ETH_CSR_OFFSET 0x2000 +#define BLOCK_ETH_CLE_OFFSET 0x6000 +#define BLOCK_ETH_QMI_OFFSET 0x9000 +#define BLOCK_ETH_SDS_CSR_OFFSET 0xA000 +#define BLOCK_ETH_CLKRST_CSR_OFFSET 0xC000 +#define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 + +/* Indirect & Direct Address mode for MCX_MAC and AXG_MAC */ +#define BLOCK_ETH_MAC_OFFSET 0x0000 +#define BLOCK_ETH_STATS_OFFSET 0x0014 +#define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 + +#define BLOCK_SATA_ENET_CSR_OFFSET 0x7000 + +/* Constants for indirect registers */ +#define MAC_ADDR_REG_OFFSET 0 +#define MAC_COMMAND_REG_OFFSET 4 +#define MAC_WRITE_REG_OFFSET 8 +#define MAC_READ_REG_OFFSET 12 +#define MAC_COMMAND_DONE_REG_OFFSET 16 + +#define STAT_ADDR_REG_OFFSET 0 +#define STAT_COMMAND_REG_OFFSET 4 +#define STAT_WRITE_REG_OFFSET 8 +#define STAT_READ_REG_OFFSET 12 +#define STAT_COMMAND_DONE_REG_OFFSET 16 + +/* Address PE_MCXMAC Registers */ +#define MII_MGMT_COMMAND_ADDR 0x00000024 +#define MII_MGMT_ADDRESS_ADDR 0x00000028 +#define MII_MGMT_CONTROL_ADDR 0x0000002c +#define MII_MGMT_STATUS_ADDR 0x00000030 +#define MII_MGMT_INDICATORS_ADDR 0x00000034 + +#define INT_PHY_ADDR 0x1E + +#define BUSY_MASK 0x00000001 +#define READ_CYCLE_MASK 0x00000001 +#define PHY_CONTROL_WR(src) (((u32)(src)) & 0x0000ffff) + +#define HW_MTU(m) ((m) + 12 + 2 + 4 /* MAC + CRC */) + +enum xgene_enum_speed { + XGENE_ENET_SPEED_0 = 0xffff, + XGENE_ENET_SPEED_10 = 10, + XGENE_ENET_SPEED_100 = 100, + XGENE_ENET_SPEED_1000 = 1000, + XGENE_ENET_SPEED_10000 = 10000 +}; + +enum xgene_enet_mode { + HALF_DUPLEX = 1, + FULL_DUPLEX = 2 +}; + +enum xgene_enet_phy_mode { + PHY_MODE_NONE, + PHY_MODE_RGMII, + PHY_MODE_SGMII, + PHY_MODE_XGMII +}; + +enum xgene_enet_cmd { + XGENE_ENET_WR_CMD = 0x80000000, + XGENE_ENET_RD_CMD = 0x40000000 +}; + +#define CMU 0 + +/* ===== MII definitions ===== */ + +#define MII_CRC_LEN 0x4 /* CRC length in bytes */ +#define MII_ETH_MAX_PCK_SZ (ETHERMTU + SIZEOF_ETHERHEADER \ + + MII_CRC_LEN) +#define MII_MAX_PHY_NUM 0x20 /* max number of attached PHYs */ +#define MII_MAX_REG_NUM 0x20 /* max number of registers */ + +#define MII_CTRL_REG 0x0 /* Control Register */ +#define MII_STAT_REG 0x1 /* Status Register */ +#define MII_PHY_ID1_REG 0x2 /* PHY identifier 1 Register */ +#define MII_PHY_ID2_REG 0x3 /* PHY identifier 2 Register */ +#define MII_AN_ADS_REG 0x4 /* Auto-Negotiation */ + /* Advertisement Register */ +#define MII_AN_PRTN_REG 0x5 /* Auto-Negotiation */ + /* partner ability Register */ +#define MII_AN_EXP_REG 0x6 /* Auto-Negotiation */ + /* Expansion Register */ +#define MII_AN_NEXT_REG 0x7 /* Auto-Negotiation */ + /* next-page transmit Register */ + +#define MII_AN_PRTN_NEXT_REG 0x8 /* Link partner received next page */ +#define MII_MASSLA_CTRL_REG 0x9 /* MATER-SLAVE control register */ +#define MII_MASSLA_STAT_REG 0xa /* MATER-SLAVE status register */ +#define MII_EXT_STAT_REG 0xf /* Extented status register */ + +/* MII control register bit */ +#define MII_CR_1000 0x0040 /* 1 = 1000mb when + * MII_CR_100 is also 1 + */ +#define MII_CR_COLL_TEST 0x0080 /* collision test */ +#define MII_CR_FDX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART 0x0200 /* restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* power down */ +#define MII_CR_AUTO_EN 0x1000 /* auto-negotiation enable */ +#define MII_CR_100 0x2000 /* 0 = 10mb, 1 = 100mb */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_NORM_EN 0x0000 /* just enable the PHY */ +#define MII_CR_DEF_0_MASK 0xca7f /* they must return zero */ +#define MII_CR_RES_MASK 0x003f /* reserved bits,return zero */ + +/* MII Status register bit definitions */ +#define MII_SR_LINK_STATUS 0x0004 /* link Status -- 1 = link */ +#define MII_SR_AUTO_SEL 0x0008 /* auto speed select capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote fault detect */ +#define MII_SR_AUTO_NEG 0x0020 /* auto negotiation complete */ +#define MII_SR_EXT_STS 0x0100 /* extended sts in reg 15 */ +#define MII_SR_T2_HALF_DPX 0x0200 /* 100baseT2 HD capable */ +#define MII_SR_T2_FULL_DPX 0x0400 /* 100baseT2 FD capable */ +#define MII_SR_10T_HALF_DPX 0x0800 /* 10BaseT HD capable */ +#define MII_SR_10T_FULL_DPX 0x1000 /* 10BaseT FD capable */ +#define MII_SR_TX_HALF_DPX 0x2000 /* TX HD capable */ +#define MII_SR_TX_FULL_DPX 0x4000 /* TX FD capable */ +#define MII_SR_T4 0x8000 /* T4 capable */ +#define MII_SR_ABIL_MASK 0xff80 /* abilities mask */ +#define MII_SR_EXT_CAP 0x0001 /* extended capabilities */ +#define MII_SR_SPEED_SEL_MASK 0xf800 /* Mask to extract just speed + * capabilities from status + * register. + */ + +/* MII AN advertisement Register bit definition */ +#define MII_ANAR_10TX_HD 0x0020 +#define MII_ANAR_10TX_FD 0x0040 +#define MII_ANAR_100TX_HD 0x0080 +#define MII_ANAR_100TX_FD 0x0100 +#define MII_ANAR_100T_4 0x0200 +#define MII_ANAR_PAUSE 0x0400 +#define MII_ANAR_ASM_PAUSE 0x0800 +#define MII_ANAR_REMORT_FAULT 0x2000 +#define MII_ANAR_NEXT_PAGE 0x8000 +#define MII_ANAR_PAUSE_MASK 0x0c00 + +/* MII Link Code word bit definitions */ +#define MII_BP_FAULT 0x2000 /* remote fault */ +#define MII_BP_ACK 0x4000 /* acknowledge */ +#define MII_BP_NP 0x8000 /* nexp page is supported */ + +/* MII Next Page bit definitions */ +#define MII_NP_TOGGLE 0x0800 /* toggle bit */ +#define MII_NP_ACK2 0x1000 /* acknowledge two */ +#define MII_NP_MSG 0x2000 /* message page */ +#define MII_NP_ACK1 0x4000 /* acknowledge one */ +#define MII_NP_NP 0x8000 /* nexp page will follow */ + +/* MII Master-Slave Control register bit definition */ +#define MII_MASSLA_CTRL_1000T_HD 0x100 +#define MII_MASSLA_CTRL_1000T_FD 0x200 +#define MII_MASSLA_CTRL_PORT_TYPE 0x400 +#define MII_MASSLA_CTRL_CONFIG_VAL 0x800 +#define MII_MASSLA_CTRL_CONFIG_EN 0x1000 + +/* MII Master-Slave Status register bit definition */ +#define MII_MASSLA_STAT_LP1000T_HD 0x400 +#define MII_MASSLA_STAT_LP1000T_FD 0x800 +#define MII_MASSLA_STAT_REMOTE_RCV 0x1000 +#define MII_MASSLA_STAT_LOCAL_RCV 0x2000 +#define MII_MASSLA_STAT_CONF_RES 0x4000 +#define MII_MASSLA_STAT_CONF_FAULT 0x8000 + +/* these values may be used in the default phy mode field of the load + * string, since that is used to force the operating mode of the PHY + * in case any attempt to establish the link failed. + */ + +#define PHY_10BASE_T 0x00 /* 10 Base-T */ +#define PHY_10BASE_T_FDX 0x01 /* 10 Base Tx, full duplex */ +#define PHY_100BASE_TX 0x02 /* 100 Base Tx */ +#define PHY_100BASE_TX_FDX 0x03 /* 100 Base TX, full duplex */ +#define PHY_100BASE_T4 0x04 /* 100 Base T4 */ +#define PHY_AN_ENABLE 0x05 /* re-enable auto-negotiation */ + +#define MII_AN_TBL_MAX 20 /* max number of entries in the table */ + +/* Realtek PHY definitions */ +#define PHY_SPEED_RES 3 +#define PHY_SPEED_1000 2 +#define PHY_SPEED_100 1 +#define PHY_SPEED_10 0 +#define RTL_PHYSR_ADR 0X11 +#define RTL_PHYSR_SPEED_RD(src) (((src) & 0x0000C000) >> 14) +#define RTL_PHYSR_LINK_RD(src) (((src) & 0x00000400) >> 10) + +#define RTL_PHYSR_ADR 0X11 + +/* LErr(3b) Decoding */ +enum xgene_enet_lerr { + ENET_NO_ERR = 0, /* No Error */ + ENET_AXI_WR_ERR = 1, /* AXI write data error due to RSIF */ + ENET_ING_CRC_ERR = 2, /* Rx packet had CRC */ + ENET_AXI_RD_ERR = 3, /* AXI read data error when processing + * a work message in TSIF + */ + ENET_LL_RD_ERR = 4, /* AXI Link List read error when + * processing a work message in TSIF + */ + ENET_ING_ERR = 5, /* Rx packet had ingress processing error */ + ENET_CHKSUM_ERR = 5, /* Checksum error */ + ENET_BAD_MSG_ERR = 6, /* Bad message to subsytem */ + ENET_MISC_ERR = 7, /* Other ingress processing error */ + ENET_MAC_TRUNC_ERR = 7, /* MAX truncated */ + ENET_MAC_LEN_ERR = 8, /* Packet length error */ + ENET_PKT_LESS64_ERR = 9, /* MAC length lesser than 64B */ + ENET_MAC_OVERRUN_ERR = 10, /* FIFO overrun on ingress */ + ENET_UNISEC_CHKSUM_ERR = 11, /* Rx pacekt checksum error */ + ENET_UNISEC_LEN_ERR = 12, /* Rx pkt length mismatch QM message */ + ENET_UNISEC_ICV_ERR = 13, /* Rx pkt ICV error */ + ENET_UNISEC_PROTO_ERR = 14, /* Rx pkt protocol field mismatch */ + ENET_FP_TIMEOUT_ERR = 15 /* Free pool buffer timeout */ +}; + +/* Error TX/RX Statistics - maintained by software */ +struct xgene_mac_error_stats { + u64 rx_hw_errors; + u64 rx_hw_overrun; + u64 tx_dropped; +}; + +struct xgene_enet_rx_stats { + u32 rx_byte_count; /* Receive Byte Counter */ + u32 rx_packet_count; /* Receive Packet Counter */ + u32 rx_fcs_err_count; /* Receive FCS Error Counter */ + u32 rx_alignment_err_pkt_count; /* Rx Alignment Err Packet Counter */ + u32 rx_frm_len_err_pkt_count; /* Rx Frame Len Err Packet Counter */ + u32 rx_undersize_pkt_count; /* Receive Undersize Packet Counter */ + u32 rx_oversize_pkt_count; /* Receive Oversize Packet Counter */ + u32 rx_drop_pkt_count; /* Receive Drop Packet Counter */ +}; + +struct xgene_enet_tx_stats { + u32 tx_byte_count; /* Tx Byte cnt */ + u32 tx_pkt_count; /* Tx pkt cnt */ + u32 tx_drop_frm_count; /* Tx Drop Frame cnt */ + u32 tx_fcs_err_frm_count; /* Tx FCS Error Frame cnt */ + u32 tx_undersize_frm_count; /* Tx Undersize Frame cnt */ +}; + +struct xgene_enet_detailed_stats { + struct xgene_enet_rx_stats rx_stats; + struct xgene_enet_tx_stats tx_stats; + struct xgene_mac_error_stats estats; +}; + +/* Ethernet private structure */ +struct xgene_enet_priv { + void *eth_csr_addr_v; + void *eth_cle_addr_v; + void *eth_qmi_addr_v; + void *eth_sds_csr_addr_v; + void *eth_clkrst_csr_addr_v; + void *eth_diag_csr_addr_v; + void *mcx_mac_addr_v; + void *mcx_stats_addr_v; + void *mcx_mac_csr_addr_v; + void *sata_enet_csr_addr_v; + void *axg_mac_addr_v; + void *axg_stats_addr_v; + void *axg_mac_csr_addr_v; + void *xgenet_pcs_addr_v; + void *xgenet_mdio_csr_addr_v; + + u64 paddr_base; /* Base physical address of device */ + void *vaddr_base; /* Base Virtual address for the device */ + u64 ppaddr_base; /* Per port physical address of device */ + void *vpaddr_base; /* Per port Virtual address of device */ + void *vmii_base; /* Base MII Virtual address of device */ + + u32 phy_addr; /* Virtual address for PHY */ + u32 phy_mode; + u32 speed; /* Forced Link Speed */ + u32 link_status; + u32 crc; + u32 autoneg_set; + u32 mac_to_mac; /* Tell traffic is MAC-to-MAC */ + u32 desired_speed; /* In case of MAC-to-MAC, no autoneg, + * tell the desired speed to setup + */ + u32 phyless; /* PHY stays away from board on + * common server board design + */ + u32 force_serdes_reset; /* Force analog reset till stable state */ + + /* Function pointers */ + void (*port_reset) (struct xgene_enet_priv *priv); + int (*phy_autoneg_done) (struct xgene_enet_priv *priv); + void (*phy_link_mode) (struct xgene_enet_priv *priv, + u32 *speed, u32 *state); + void (*mac_reset) (struct xgene_enet_priv *priv); + int (*mac_init) (struct xgene_enet_priv *priv, + unsigned char *dev_addr, int speed, int mtu, int crc); + void (*mac_rx_state) (struct xgene_enet_priv *priv, u32 enable); + void (*mac_tx_state) (struct xgene_enet_priv *priv, u32 enable); + void (*mac_change_mtu) (struct xgene_enet_priv *priv, u32 new_mtu); + void (*mac_set_ipg) (struct xgene_enet_priv *priv, u16 new_ipg); + void (*get_stats) (struct xgene_enet_priv *priv, + struct xgene_enet_detailed_stats *stats); + void (*set_mac_addr) (struct xgene_enet_priv *priv, + unsigned char *dev_addr); + void (*cle_bypass) (struct xgene_enet_priv *priv, u32 dstqid, + u32 fpsel); + void (*tx_offload) (struct xgene_enet_priv *priv, u32 command, + u32 value); + void (*qmi_assoc) (struct xgene_enet_priv *priv); + void (*port_shutdown) (struct xgene_enet_priv *priv); +}; + +int xgene_enet_wr(struct xgene_enet_priv *priv, u8 block_id, + u32 reg_offset, u32 value); + +int xgene_enet_rd(struct xgene_enet_priv *priv, u8 block_id, + u32 reg_offset, u32 *value); + +void xgene_enet_port_reset(struct xgene_enet_priv *priv); + +/* This function resets the entire part of MAC and minimal init for phy access + * It will put both Transmit and Receive MAC Control block in reset + * and then init. + */ +void xgene_enet_mac_reset(struct xgene_enet_priv *priv); + +int xgene_enet_mac_init(struct xgene_enet_priv *priv, unsigned char *dev_addr, + int speed, int mtu, int crc); + +void xgene_enet_mac_rx_state(struct xgene_enet_priv *priv, u32 enable); +void xgene_enet_mac_tx_state(struct xgene_enet_priv *priv, u32 enable); + +void xgene_enet_mac_change_mtu(struct xgene_enet_priv *priv, u32 new_mtu); +void xgene_enet_mac_set_ipg(struct xgene_enet_priv *priv, u16 ipg); + +void xgene_enet_set_mac_addr(struct xgene_enet_priv *priv, + unsigned char *dev_addr); + +void xgene_enet_cle_bypass(struct xgene_enet_priv *priv, u32 dstqid, u32 fpsel); + +void xgene_enet_tx_offload(struct xgene_enet_priv *priv, + u32 command, u32 value); + +void xgene_enet_port_shutdown(struct xgene_enet_priv *priv); +enum xgene_qmtm_qaccess xgene_enet_get_qacess(void); +void xgene_genericmiiphy_read(struct xgene_enet_priv *priv, u8 phy_id, + unsigned char reg, u32 *data); +void xgene_genericmiiphy_write(struct xgene_enet_priv *priv, u8 phy_id, + unsigned char reg, u32 data); + +void xgene_enet_get_stats(struct xgene_enet_priv *priv, + struct xgene_enet_detailed_stats *detailed_stats); +#endif /* __XGENE_ENET_COMMON_H__ */ --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -0,0 +1,177 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Ravi Patel + * Iyappan Subramanian + * Fushen Chen + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __XGENE_ENET_MAIN_H__ +#define __XGENE_ENET_MAIN_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xgene_enet_common.h" + +#define XGENE_ENET_DRIVER_NAME "xgene-enet" +#define XGENE_ENET_DRIVER_VERSION "1.0" +#define XGENE_ENET_DRIVER_DESC "APM X-Gene SoC Ethernet driver" + +#define XGENE_ENET_MIN_MTU 64 +#define XGENE_ENET_MAX_MTU 10000 + +/* Note: PKT_BUF_SIZE & PKT_NXTBUF_SIZE has to be one of the following: + * 256, 1K, 2K, 4K, 16K for ethernet to work with optimum performance. + */ +#define XGENE_ENET_PKT_BUF_SIZE 2048 +#define XGENE_NUM_PKT_BUF 256 + +/* define Enet system struct */ +struct xgene_enet_dev { + int refcnt; + struct timer_list link_poll_timer; + int ipp_loaded; + int ipp_hw_mtu; +}; + +enum xgene_enet_phy_poll_interval { + PHY_POLL_LINK_ON = HZ, + PHY_POLL_LINK_OFF = (HZ / 5) +}; + +enum xgene_enet_debug_cmd { + XGENE_ENET_READ_CMD, + XGENE_ENET_WRITE_CMD, + XGENE_ENET_MAX_CMD +}; + +#define MAX_TX_QUEUES 1 +#define MAX_RX_QUEUES 1 + +/* This is soft flow context of queue */ +struct xgene_enet_qcontext { + struct xgene_enet_pdev *pdev; + struct xgene_qmtm_qdesc *qdesc; + struct xgene_qmtm_msg_ext8 *msg8; + u32 *nummsgs; + unsigned int queue_index; + unsigned int eqnum; + u32 buf_size; + unsigned int c2e_count; + struct sk_buff * (*skb); + struct xgene_enet_qcontext *c2e_skb; + struct xgene_enet_qcontext *c2e_page; + struct napi_struct napi; + char irq_name[16]; +}; + +/* Queues related parameters per Enet port */ +#define ENET_MAX_PBN 8 +#define ENET_MAX_QSEL 8 + +struct eth_wqids { + u16 qtype; + u16 qid; + u16 arb; + u16 qcount; + u16 qsel[ENET_MAX_QSEL]; +}; + +struct eth_fqids { + u16 qid; + u16 pbn; +}; + +struct eth_queue_ids { + u16 default_tx_qid; + u16 tx_count; + u16 tx_idx; + struct eth_wqids tx[ENET_MAX_PBN]; + u16 default_rx_qid; + u16 rx_count; + u16 rx_idx; + struct eth_wqids rx[ENET_MAX_PBN]; + u16 default_rx_fp_qid; + u16 default_rx_fp_pbn; + struct eth_fqids rx_fp[ENET_MAX_PBN]; + u16 default_rx_nxtfp_qid; + u16 default_rx_nxtfp_pbn; + struct eth_fqids rx_nxtfp[ENET_MAX_PBN]; + struct eth_fqids hw_fp; + u16 default_hw_tx_qid; + struct eth_fqids hw_tx[ENET_MAX_PBN]; + struct eth_wqids comp[ENET_MAX_PBN]; + u16 default_comp_qid; + u32 qm_ip; +}; + +struct xgene_enet_platform_data { + const char *sname; + int irq; + u32 phy_id; + u8 ethaddr[6]; +}; + +/* APM ethernet per port data */ +struct xgene_enet_pdev { + struct net_device *ndev; + struct mii_bus *mdio_bus; + struct phy_device *phy_dev; + int phy_link; + int phy_speed; + struct clk *clk; + struct device_node *node; + struct platform_device *plat_dev; + struct xgene_qmtm_sdev *sdev; + struct xgene_enet_qcontext *tx[MAX_TX_QUEUES]; + struct xgene_enet_qcontext *rx_skb_pool[MAX_RX_QUEUES]; + u32 num_tx_queues; + struct xgene_enet_qcontext *rx[MAX_RX_QUEUES]; + struct xgene_enet_qcontext *tx_completion[MAX_TX_QUEUES]; + u32 num_rx_queues; + struct net_device_stats nstats; + struct xgene_enet_detailed_stats stats; + char *dev_name; + int uc_count; + struct eth_queue_ids qm_queues; + u32 rx_buff_cnt, tx_cqt_low, tx_cqt_hi; + int mss; + unsigned int enet_err_irq; + unsigned int enet_mac_err_irq; + unsigned int enet_qmi_err_irq; + struct xgene_enet_priv priv; +}; + +/* Ethernet raw register write, read routines */ +void xgene_enet_wr32(void *addr, u32 data); +void xgene_enet_rd32(void *addr, u32 *data); + +u32 xgene_enet_get_port(struct xgene_enet_pdev *pdev); + +void xgene_enet_init_priv(struct xgene_enet_priv *priv); + +int xgene_enet_parse_error(u8 LErr, int qid); +void xgene_enet_register_err_irqs(struct net_device *ndev); + +extern const struct ethtool_ops xgene_ethtool_ops; +#endif /* __XGENE_ENET_MAIN_H__ */ --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_tools.c +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_tools.c @@ -0,0 +1,296 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Hrishikesh Karanjikar + * Ravi Patel + * Iyappan Subramanian + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "xgene_enet_csr.h" +#include "xgene_enet_main.h" + +struct xgene_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +static const struct xgene_stats xgene_gstrings_stats[] = { + { "rx_bytes", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_byte_count), + offsetof(struct xgene_enet_pdev, stats.rx_stats.rx_byte_count) + }, + { "rx_packets", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_packet_count), + offsetof(struct xgene_enet_pdev, stats.rx_stats.rx_packet_count) + }, + { "rx_fcs_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_fcs_err_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_fcs_err_count) + }, + { "rx_alignment_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_alignment_err_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_alignment_err_pkt_count) + }, + { "rx_frm_len_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_frm_len_err_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_frm_len_err_pkt_count) + }, + { "rx_undersize", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_undersize_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_undersize_pkt_count) + }, + { "rx_oversize", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_oversize_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_oversize_pkt_count) + }, + { "rx_drop", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_drop_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_drop_pkt_count) + }, + { "tx_bytes", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_byte_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_byte_count) + }, + { "tx_packets", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_pkt_count) + }, + { "tx_drop", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_drop_frm_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_drop_frm_count) + }, + { "tx_fcs_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_fcs_err_frm_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_fcs_err_frm_count) + }, + { "tx_undersize", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_undersize_frm_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_undersize_frm_count) + }, +}; + +#define XGENE_GLOBAL_STATS_LEN ARRAY_SIZE(xgene_gstrings_stats) + +/* Ethtool APIs */ +static int xgene_ethtool_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct phy_device *phydev = pdev->phy_dev; + struct xgene_enet_priv *priv = &pdev->priv; + + if (priv->phy_mode == PHY_MODE_RGMII) { + if (!phydev) + return -ENODEV; + return phy_ethtool_gset(phydev, cmd); + } + return 0; +} + +static int xgene_ethtool_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct phy_device *phydev = pdev->phy_dev; + struct xgene_enet_priv *priv = &pdev->priv; + + if (priv->phy_mode == PHY_MODE_RGMII) { + if (!phydev) + return -ENODEV; + return phy_ethtool_sset(phydev, cmd); + } + return 0; +} + +static int xgene_ethtool_set_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + u32 data; + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + + /* Modify value to set or reset rx flow control */ + if (pp->rx_pause) + data |= RX_FLOW_EN1_MASK; + else + data &= ~RX_FLOW_EN1_MASK; + + /* Modify value to set or reset tx flow control */ + if (pp->tx_pause) + data |= TX_FLOW_EN1_MASK; + else + data &= ~TX_FLOW_EN1_MASK; + + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, data); + + return 0; +} + +static void xgene_ethtool_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + u32 data; + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + pp->rx_pause = RX_FLOW_EN1_RD(data); + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + pp->tx_pause = TX_FLOW_EN1_RD(data); +} + +static int xgene_ethtool_nway_reset(struct net_device *ndev) +{ + u32 data = 0, retry = 0; + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + + if (priv->phy_mode == PHY_MODE_RGMII) + mutex_lock(&pdev->mdio_bus->mdio_lock); + + /* Power-down PHY */ + data = MII_CR_POWER_DOWN; + xgene_genericmiiphy_write(priv, priv->phy_addr, + MII_CTRL_REG, data); + + /* Power-up PHY */ + data = 0x0; + xgene_genericmiiphy_write(priv, priv->phy_addr, + MII_CTRL_REG, data); + + /* Reset PHY */ + data = MII_CR_RESET; + xgene_genericmiiphy_write(priv, priv->phy_addr, + MII_CTRL_REG, data); + + /* PHY reset may take 100 ms */ + retry = 100; + do { + xgene_genericmiiphy_read(priv, priv->phy_addr, + MII_CTRL_REG, &data); + usleep_range(1000, 2000); + } while (--retry && (data & MII_CR_RESET)); + + xgene_genericmiiphy_write(priv, priv->phy_addr, MII_CTRL_REG, + MII_CR_AUTO_EN|MII_CR_RESTART|MII_CR_FDX); + + priv->autoneg_set = 1; + priv->speed = XGENE_ENET_SPEED_1000; + priv->mac_init(priv, ndev->dev_addr, priv->speed, + HW_MTU(ndev->mtu), priv->crc); + + if (priv->phy_mode == PHY_MODE_RGMII) + mutex_unlock(&pdev->mdio_bus->mdio_lock); + + return 0; +} + +static void xgene_get_strings(struct net_device *ndev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_TEST: + case ETH_SS_STATS: + for (i = 0; i < XGENE_GLOBAL_STATS_LEN; i++) { + memcpy(p, xgene_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int xgene_get_sset_count(struct net_device *ndev, int sset) +{ + switch (sset) { + case ETH_SS_TEST: + return XGENE_GLOBAL_STATS_LEN; + case ETH_SS_STATS: + return XGENE_GLOBAL_STATS_LEN; + default: + return -EOPNOTSUPP; + } + +} + +static void xgene_ethtool_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *ethtool_stats, + u64 *data) +{ + + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + struct xgene_enet_detailed_stats *stats = &pdev->stats; + int i; + + xgene_enet_get_stats(priv, stats); + for (i = 0; i < XGENE_GLOBAL_STATS_LEN; i++) { + char *p = (char *)pdev + xgene_gstrings_stats[i].stat_offset; + data[i] = (xgene_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } +} + +static void xgene_ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, ndev->name); + strcpy(info->version, XGENE_ENET_DRIVER_VERSION); + strcpy(info->fw_version, "N/A"); +} + +const struct ethtool_ops xgene_ethtool_ops = { + .get_settings = xgene_ethtool_get_settings, + .set_settings = xgene_ethtool_set_settings, + .get_drvinfo = xgene_ethtool_get_drvinfo, + .nway_reset = xgene_ethtool_nway_reset, + .get_pauseparam = xgene_ethtool_get_pauseparam, + .set_pauseparam = xgene_ethtool_set_pauseparam, + .get_ethtool_stats = xgene_ethtool_get_ethtool_stats, + .get_sset_count = xgene_get_sset_count, + .get_strings = xgene_get_strings, + .get_link = ethtool_op_get_link, +}; --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/Makefile +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for APM X-GENE Ethernet driver. +# + +xgene-enet-objs := \ + xgene_enet_common.o \ + xgene_enet_mac.o \ + xgene_enet_main.o \ + xgene_enet_err.o \ + xgene_enet_tools.o + +obj-$(CONFIG_NET_XGENE) += xgene-enet.o --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/Kconfig +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/Kconfig @@ -0,0 +1,10 @@ +config NET_XGENE + tristate "APM X-Gene Ethernet Driver" + depends on XGENE_QMTM + select PHYLIB + default y + help + This is the Ethernet driver for APM X-Gene SoC. + + To compile this driver as a module, choose M here. This module will + be called xgene_enet. --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_common.c +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_common.c @@ -0,0 +1,491 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Ravi Patel + * Iyappan Subramanian + * Fushen Chen + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "xgene_enet_main.h" +#include "xgene_enet_common.h" +#include "xgene_enet_csr.h" + +/* Indirect Address - read/write commands */ +#define PHY_ADDR_WR(src) (((u32)(src) < 8) & 0x00001f00) +#define REG_ADDR_WR(src) (((u32)(src)) & 0x0000001f) + +int xgene_enet_wr(struct xgene_enet_priv *priv, u8 block_id, + u32 reg_offset, u32 value) +{ + u32 cmd_done; + u32 indirect = 0; + int wait; + void *addr_reg_offst, *cmd_reg_offst, *wr_reg_offst; + void *cmd_done_reg_offst; + + switch (block_id) { + case BLOCK_ETH_CSR: + addr_reg_offst = priv->eth_csr_addr_v + reg_offset; + pr_debug("ETH CSR write\n"); + break; + + case BLOCK_ETH_MDIO_CSR: + addr_reg_offst = priv->vmii_base + reg_offset + + BLOCK_ETH_CSR_OFFSET; + pr_debug("BLOCK_ETH_MDIO_CSR write 0x%p\n", addr_reg_offst); + break; + + case BLOCK_ETH_CLE: + addr_reg_offst = priv->eth_cle_addr_v + reg_offset; + pr_debug("ETH CLE write\n"); + break; + + case BLOCK_ETH_QMI: + addr_reg_offst = priv->eth_qmi_addr_v + reg_offset; + pr_debug("ETH QMI write\n"); + break; + + case BLOCK_ETH_SDS_CSR: + addr_reg_offst = priv->eth_sds_csr_addr_v + reg_offset; + pr_debug("ETH SDS CSR write\n"); + break; + + case BLOCK_ETH_CLKRST_CSR: + addr_reg_offst = priv->eth_clkrst_csr_addr_v + reg_offset; + pr_debug("ETH CLKRST CSR write\n"); + break; + + case BLOCK_ETH_DIAG_CSR: + addr_reg_offst = priv->eth_diag_csr_addr_v + reg_offset; + pr_debug("ETH DIAG CSR write\n"); + break; + + case BLOCK_MCX_MAC: + case BLOCK_ETH_INTPHY: + addr_reg_offst = priv->mcx_mac_addr_v + MAC_ADDR_REG_OFFSET; + cmd_reg_offst = priv->mcx_mac_addr_v + MAC_COMMAND_REG_OFFSET; + wr_reg_offst = priv->mcx_mac_addr_v + MAC_WRITE_REG_OFFSET; + cmd_done_reg_offst = priv->mcx_mac_addr_v + + MAC_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("MCX MAC/Internal PHY write\n"); + break; + + case BLOCK_ETH_EXTPHY: + addr_reg_offst = priv->vmii_base + MAC_ADDR_REG_OFFSET; + cmd_reg_offst = priv->vmii_base + MAC_COMMAND_REG_OFFSET; + wr_reg_offst = priv->vmii_base + MAC_WRITE_REG_OFFSET; + cmd_done_reg_offst = priv->vmii_base + + MAC_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("MCX MAC/External PHY write\n"); + break; + + case BLOCK_MCX_STATS: + addr_reg_offst = priv->mcx_stats_addr_v + STAT_ADDR_REG_OFFSET; + cmd_reg_offst = + priv->mcx_stats_addr_v + STAT_COMMAND_REG_OFFSET; + wr_reg_offst = priv->mcx_stats_addr_v + STAT_WRITE_REG_OFFSET; + cmd_done_reg_offst = priv->mcx_stats_addr_v + + STAT_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("MCX STATS write\n"); + break; + + case BLOCK_MCX_MAC_CSR: + addr_reg_offst = priv->mcx_mac_csr_addr_v + reg_offset; + pr_debug("MCX MAC CSR write\n"); + break; + + case BLOCK_SATA_ENET_CSR: + addr_reg_offst = priv->sata_enet_csr_addr_v + reg_offset; + pr_debug("SATA ENET CSR write\n"); + break; + + case BLOCK_AXG_MAC: + addr_reg_offst = priv->axg_mac_addr_v + MAC_ADDR_REG_OFFSET; + cmd_reg_offst = priv->axg_mac_addr_v + MAC_COMMAND_REG_OFFSET; + wr_reg_offst = priv->axg_mac_addr_v + MAC_WRITE_REG_OFFSET; + cmd_done_reg_offst = priv->axg_mac_addr_v + + MAC_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("AXG MAC write\n"); + break; + + case BLOCK_AXG_STATS: + addr_reg_offst = priv->axg_stats_addr_v + STAT_ADDR_REG_OFFSET; + cmd_reg_offst = + priv->axg_stats_addr_v + STAT_COMMAND_REG_OFFSET; + wr_reg_offst = priv->axg_stats_addr_v + STAT_WRITE_REG_OFFSET; + cmd_done_reg_offst = priv->axg_stats_addr_v + + STAT_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("AXG STATS write\n"); + break; + + case BLOCK_AXG_MAC_CSR: + addr_reg_offst = priv->axg_mac_csr_addr_v + reg_offset; + pr_debug("AXG MAC CSR write\n"); + break; + + case BLOCK_XGENET_PCS: + addr_reg_offst = priv->xgenet_pcs_addr_v + reg_offset; + pr_debug("XGENET PCS write\n"); + break; + + case BLOCK_XGENET_MDIO_CSR: + addr_reg_offst = priv->xgenet_mdio_csr_addr_v + reg_offset; + pr_debug("XGENET MDIO CSR write\n"); + break; + + default: + pr_err("Invalid blockid in write reg: %d\n", block_id); + return -1; + } + + if (indirect) { + xgene_enet_wr32(addr_reg_offst, reg_offset); + xgene_enet_wr32(wr_reg_offst, value); + xgene_enet_wr32(cmd_reg_offst, XGENE_ENET_WR_CMD); + pr_debug("Indirect write: addr: 0x%X, value: 0x%X\n", + reg_offset, value); + + /* wait upto 5 us for completion */ + wait = 5; + do { + xgene_enet_rd32(cmd_done_reg_offst, &cmd_done); + usleep_range(1, 2); + } while (--wait && !cmd_done); + if (!wait) { + pr_err("Write failed for blk: %d\n", block_id); + BUG(); + } + + xgene_enet_wr32(cmd_reg_offst, 0); + } else { + xgene_enet_wr32(addr_reg_offst, value); + pr_debug("Direct write addr: 0x%p, value: 0x%X\n", + addr_reg_offst, value); + } + + return 0; +} + +int xgene_enet_rd(struct xgene_enet_priv *priv, u8 block_id, + u32 reg_offset, u32 *value) +{ + u32 cmd_done; + u32 indirect = 0; + int wait; + void *addr_reg_offst, *cmd_reg_offst, *rd_reg_offst; + void *cmd_done_reg_offst; + + switch (block_id) { + case BLOCK_ETH_CSR: + addr_reg_offst = priv->eth_csr_addr_v + reg_offset; + pr_debug("ETH CSR read\n"); + break; + + case BLOCK_ETH_MDIO_CSR: + addr_reg_offst = priv->vmii_base + reg_offset + + BLOCK_ETH_CSR_OFFSET; + pr_debug("BLOCK_ETH_MDIO_CSR read 0x%p\n", addr_reg_offst); + break; + + case BLOCK_ETH_CLE: + addr_reg_offst = priv->eth_cle_addr_v + reg_offset; + pr_debug("ETH CLE read\n"); + break; + + case BLOCK_ETH_QMI: + addr_reg_offst = priv->eth_qmi_addr_v + reg_offset; + pr_debug("ETH QMI read\n"); + break; + + case BLOCK_ETH_SDS_CSR: + addr_reg_offst = priv->eth_sds_csr_addr_v + reg_offset; + pr_debug("ETH SDS CSR read\n"); + break; + + case BLOCK_ETH_CLKRST_CSR: + addr_reg_offst = priv->eth_clkrst_csr_addr_v + reg_offset; + pr_debug("ETH CLKRST CSR read\n"); + break; + + case BLOCK_ETH_DIAG_CSR: + addr_reg_offst = priv->eth_diag_csr_addr_v + reg_offset; + pr_debug("ETH DIAG CSR read\n"); + break; + + case BLOCK_MCX_MAC: + case BLOCK_ETH_INTPHY: + addr_reg_offst = priv->mcx_mac_addr_v + MAC_ADDR_REG_OFFSET; + cmd_reg_offst = priv->mcx_mac_addr_v + MAC_COMMAND_REG_OFFSET; + rd_reg_offst = priv->mcx_mac_addr_v + MAC_READ_REG_OFFSET; + cmd_done_reg_offst = priv->mcx_mac_addr_v + + MAC_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("MCX MAC/Internal PHY read\n"); + break; + + case BLOCK_ETH_EXTPHY: + addr_reg_offst = priv->vmii_base + MAC_ADDR_REG_OFFSET; + cmd_reg_offst = priv->vmii_base + MAC_COMMAND_REG_OFFSET; + rd_reg_offst = priv->vmii_base + MAC_READ_REG_OFFSET; + cmd_done_reg_offst = priv->vmii_base + + MAC_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("MCX MAC/External PHY read\n"); + break; + + case BLOCK_MCX_STATS: + addr_reg_offst = priv->mcx_stats_addr_v + STAT_ADDR_REG_OFFSET; + cmd_reg_offst = + priv->mcx_stats_addr_v + STAT_COMMAND_REG_OFFSET; + rd_reg_offst = priv->mcx_stats_addr_v + STAT_READ_REG_OFFSET; + cmd_done_reg_offst = priv->mcx_stats_addr_v + + STAT_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("MCX STATS read\n"); + break; + + case BLOCK_MCX_MAC_CSR: + addr_reg_offst = priv->mcx_mac_csr_addr_v + reg_offset; + pr_debug("MCX MAC CSR read\n"); + break; + + case BLOCK_SATA_ENET_CSR: + addr_reg_offst = priv->sata_enet_csr_addr_v + reg_offset; + pr_debug("SATA ENET CSR read\n"); + break; + + case BLOCK_AXG_MAC: + addr_reg_offst = priv->axg_mac_addr_v + MAC_ADDR_REG_OFFSET; + cmd_reg_offst = priv->axg_mac_addr_v + MAC_COMMAND_REG_OFFSET; + rd_reg_offst = priv->axg_mac_addr_v + MAC_READ_REG_OFFSET; + cmd_done_reg_offst = priv->axg_mac_addr_v + + MAC_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("AXG MAC read\n"); + break; + + case BLOCK_AXG_STATS: + addr_reg_offst = priv->axg_stats_addr_v + STAT_ADDR_REG_OFFSET; + cmd_reg_offst = + priv->axg_stats_addr_v + STAT_COMMAND_REG_OFFSET; + rd_reg_offst = priv->axg_stats_addr_v + STAT_READ_REG_OFFSET; + cmd_done_reg_offst = priv->axg_stats_addr_v + + STAT_COMMAND_DONE_REG_OFFSET; + indirect = 1; + pr_debug("AXG STATS read\n"); + break; + + case BLOCK_AXG_MAC_CSR: + addr_reg_offst = priv->axg_mac_csr_addr_v + reg_offset; + pr_debug("AXG MAC CSR read\n"); + break; + + case BLOCK_XGENET_PCS: + addr_reg_offst = priv->xgenet_pcs_addr_v + reg_offset; + pr_debug("XGENET PCS read\n"); + break; + + case BLOCK_XGENET_MDIO_CSR: + addr_reg_offst = priv->xgenet_mdio_csr_addr_v + reg_offset; + pr_debug("XGENET MDIO CSR read\n"); + break; + + default: + pr_err("Invalid blockid in read reg: %d\n", block_id); + return -1; + } + + if (indirect) { + xgene_enet_wr32(addr_reg_offst, reg_offset); + xgene_enet_wr32(cmd_reg_offst, XGENE_ENET_RD_CMD); + pr_debug("Indirect read: addr: 0x%X\n", reg_offset); + + /* wait upto 5 us for completion */ + wait = 5; + do { + xgene_enet_rd32(cmd_done_reg_offst, &cmd_done); + } while (--wait && !cmd_done); + if (!wait) { + pr_err("Read failed for blk: %d\n", block_id); + BUG(); + } + + xgene_enet_rd32(rd_reg_offst, value); + pr_debug("Indirect read value: 0x%X\n", *value); + + xgene_enet_wr32(cmd_reg_offst, 0); + } else { + xgene_enet_rd32(addr_reg_offst, value); + pr_debug("Direct read addr: 0x%p, value: 0x%X\n", + addr_reg_offst, *value); + } + + return 0; +} + +void xgene_genericmiiphy_write(struct xgene_enet_priv *priv, u8 phy_id, + unsigned char reg, u32 data) +{ + u32 value; + int wait; + u32 blockid = BLOCK_ETH_EXTPHY; + + /* All PHYs lie on MII bus of Port0 MAC due to this + * each port should access its PHY through Port0 MAC. + * Hence we allow access to PHY_ID associated with this + * port only. + */ + + /* Write PHY number and address in MII Mgmt Address */ + value = PHY_ADDR_WR(phy_id) | REG_ADDR_WR(reg); + pr_debug("Write MII_MGMT_ADDRESS phy_id=0x%x, reg=0x%x, value=0x%x\n", + phy_id, reg << 2, value); + xgene_enet_wr(priv, blockid, MII_MGMT_ADDRESS_ADDR, value); + + /* Write 16 bit data to MII MGMT CONTROL */ + value = PHY_CONTROL_WR(data); + pr_debug("Write MII_MGMT_CONTROL phy_id=0x%x, reg=0x%x, value=0x%x\n", + phy_id, reg << 2, value); + xgene_enet_wr(priv, blockid, MII_MGMT_CONTROL_ADDR, value); + + /* wait upto 20 us for completion */ + wait = 20; + do { + xgene_enet_rd(priv, blockid, MII_MGMT_INDICATORS_ADDR, &value); + usleep_range(1, 2); + } while (--wait && (value & BUSY_MASK)); + if (!wait) + pr_err("MII_MGMT write failed\n"); +} + +void xgene_genericmiiphy_read(struct xgene_enet_priv *priv, u8 phy_id, + unsigned char reg, u32 *data) +{ + u32 value; + u32 blockid = BLOCK_ETH_EXTPHY; + int wait; + + /* All PHYs lie on MII bus of Port0 MAC due to this + * each port should access its PHY through Port0 MAC. + * Hence we allow access to PHY_ID associated with this + * port only. + */ + + /* Write PHY number and address in MII Mgmt Address */ + value = PHY_ADDR_WR(phy_id) | REG_ADDR_WR(reg); + pr_debug("Write MII_MGMT_ADDR phy_id=0x%x, reg=0x%x, value=0x%x\n", + phy_id, reg << 2, value); + xgene_enet_wr(priv, blockid, MII_MGMT_ADDRESS_ADDR, value); + + /* Write read command */ + xgene_enet_wr(priv, blockid, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); + + /* wait upto 20 us for completion */ + wait = 20; + do { + xgene_enet_rd(priv, blockid, MII_MGMT_INDICATORS_ADDR, &value); + if (!(value & BUSY_MASK)) + break; + usleep_range(1, 2); + } while (--wait && (value & BUSY_MASK)); + + xgene_enet_rd(priv, blockid, MII_MGMT_STATUS_ADDR, data); + + /* reset mii_mgmt_command register */ + xgene_enet_wr(priv, blockid, MII_MGMT_COMMAND_ADDR, 0); +} + +inline void xgene_enet_port_reset(struct xgene_enet_priv *priv) +{ + if (priv->port_reset) + priv->port_reset(priv); +} + +inline void xgene_enet_mac_reset(struct xgene_enet_priv *priv) +{ + if (priv->mac_reset) + priv->mac_reset(priv); +} + +inline int xgene_enet_mac_init(struct xgene_enet_priv *priv, + unsigned char *dev_addr, int speed, int mtu, + int crc) +{ + int rc = 0; + if (priv->mac_init) + rc = priv->mac_init(priv, dev_addr, speed, mtu, crc); + return rc; +} + +inline void xgene_enet_mac_tx_state(struct xgene_enet_priv *priv, u32 enable) +{ + if (priv->mac_tx_state) + priv->mac_tx_state(priv, enable); +} + +inline void xgene_enet_mac_rx_state(struct xgene_enet_priv *priv, u32 enable) +{ + if (priv->mac_rx_state) + priv->mac_rx_state(priv, enable); +} + +inline void xgene_enet_mac_change_mtu(struct xgene_enet_priv *priv, u32 new_mtu) +{ + if (priv->mac_change_mtu) + priv->mac_change_mtu(priv, new_mtu); +} + +inline void xgene_enet_mac_set_ipg(struct xgene_enet_priv *priv, u16 ipg) +{ + if (priv->mac_set_ipg) + priv->mac_set_ipg(priv, ipg); +} + +inline void xgene_enet_get_stats(struct xgene_enet_priv *priv, + struct xgene_enet_detailed_stats *stats) +{ + if (priv->get_stats) + priv->get_stats(priv, stats); +} + +inline void xgene_enet_set_mac_addr(struct xgene_enet_priv *priv, + unsigned char *dev_addr) +{ + if (priv->set_mac_addr) + priv->set_mac_addr(priv, dev_addr); +} + +inline void xgene_enet_cle_bypass(struct xgene_enet_priv *priv, + u32 dstqid, u32 fpsel) +{ + if (priv->cle_bypass) + priv->cle_bypass(priv, dstqid, fpsel); +} + +inline void xgene_enet_tx_offload(struct xgene_enet_priv *priv, + u32 command, u32 value) +{ + if (priv->tx_offload) + priv->tx_offload(priv, command, value); +} + +inline void xgene_enet_port_shutdown(struct xgene_enet_priv *priv) +{ + if (priv->port_shutdown) + priv->port_shutdown(priv); +} --- linux-3.13.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ linux-3.13.0/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -0,0 +1,1599 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Ravi Patel + * Iyappan Subramanian + * Fushen Chen + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "xgene_enet_main.h" +#include "xgene_enet_csr.h" + +inline void xgene_enet_wr32(void *addr, u32 data) +{ + pr_debug("Write addr 0x%p data 0x%08X\n", addr, data); + writel(data, (void __iomem *)addr); +} + +inline void xgene_enet_rd32(void *addr, u32 *data) +{ + *data = readl((void __iomem *)addr); + pr_debug("data 0x%08X\n", *data); +} + +inline phys_addr_t xgene_enet_enc_addr(void *vaddr) +{ + return __pa(vaddr); +} + +inline void *xgene_enet_dec_addr(phys_addr_t paddr) +{ + return __va(paddr); +} + +inline void xgene_enet_set_skb_data(struct xgene_qmtm_msg16 *msg16, + struct sk_buff *skb) +{ + u64 pa = xgene_enet_enc_addr(skb->data); + u32 *word = &msg16->DataAddrL; + + *word++ = cpu_to_le32((u32)pa); + *word = (*word & ~cpu_to_le32(0x3FF)) | cpu_to_le32((u32)(pa >> 32)); +} + +static int xgene_enet_init_fp(struct xgene_enet_qcontext *c2e, u32 nbuf) +{ + struct xgene_enet_pdev *pdev = c2e->pdev; + struct sk_buff *skb; + struct xgene_qmtm_msg16 *msg16; + u32 i; + + /* Initializing common fields */ + for (i = 0; i < c2e->qdesc->count; i++) { + msg16 = &c2e->qdesc->msg16[i]; + memset(msg16, 0, sizeof(struct xgene_qmtm_msg16)); + msg16->UserInfo = i; + msg16->C = 1; + msg16->BufDataLen = xgene_qmtm_encode_bufdatalen(c2e->buf_size); + msg16->FPQNum = c2e->eqnum; + msg16->PB = 0; + msg16->HB = 1; + xgene_qmtm_msg_le32(&(((u32 *)msg16)[1]), 3); + } + + if (nbuf > c2e->qdesc->count) { + netdev_warn(pdev->ndev, + "Limiting number of skb alloc to queue size\n"); + nbuf = c2e->qdesc->count; + } + + for (i = 0; i < nbuf; i++) { + msg16 = &c2e->qdesc->msg16[i]; + skb = dev_alloc_skb(c2e->buf_size); + if (unlikely(!skb)) { + netdev_err(pdev->ndev, + "Failed to allocate new skb size %d", + c2e->buf_size); + return -ENOMEM; + } + skb_reserve(skb, NET_IP_ALIGN); + c2e->skb[i] = skb; + xgene_enet_set_skb_data(msg16, skb); + } + + writel(nbuf, c2e->qdesc->command); + + if (nbuf == c2e->qdesc->count) + nbuf = 0; + c2e->qdesc->qtail = nbuf; + + return 0; +} + +static int xgene_enet_refill_fp(struct xgene_enet_qcontext *c2e, u32 nbuf) +{ + register u32 qtail = c2e->qdesc->qtail; + struct xgene_enet_pdev *pdev = c2e->pdev; + u32 i; + + for (i = 0; i < nbuf; i++) { + struct sk_buff *skb; + struct xgene_qmtm_msg16 *msg16 = &c2e->qdesc->msg16[qtail]; + + msg16->BufDataLen = xgene_qmtm_encode_bufdatalen(c2e->buf_size); + skb = dev_alloc_skb(c2e->buf_size); + if (unlikely(!skb)) { + netdev_err(pdev->ndev, + "Failed to allocate new skb size %d", + c2e->buf_size); + return -ENOMEM; + } + skb_reserve(skb, NET_IP_ALIGN); + c2e->skb[qtail] = skb; + xgene_enet_set_skb_data(msg16, skb); + if (++qtail == c2e->qdesc->count) + qtail = 0; + } + + writel(nbuf, c2e->qdesc->command); + c2e->qdesc->qtail = qtail; + + return 0; +} + +static void xgene_enet_deinit_fp(struct xgene_enet_qcontext *c2e, int qid) +{ + u32 qtail = c2e->qdesc->qtail; + u32 count = c2e->qdesc->count; + u32 command = 0; + struct xgene_enet_pdev *pdev = c2e->pdev; + struct xgene_qmtm_msg16 *msg16; + struct xgene_qmtm_qinfo qinfo; + int i; + + memset(&qinfo, 0, sizeof(qinfo)); + qinfo.qmtm = pdev->sdev->qmtm; + qinfo.queue_id = qid; + xgene_qmtm_read_qstate(&qinfo); + + for (i = 0; i < qinfo.nummsgs; i++) { + if (qtail == 0) + qtail = count; + + qtail--; + msg16 = &c2e->qdesc->msg16[qtail]; + kfree_skb(c2e->skb[msg16->UserInfo]); + command--; + } + + writel(command, c2e->qdesc->command); + c2e->qdesc->qtail = qtail; +} + +static int xgene_enet_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + int eth_running; + + if (HW_MTU(new_mtu) < XGENE_ENET_MIN_MTU + || HW_MTU(new_mtu) > XGENE_ENET_MAX_MTU) { + netdev_err(ndev, "Invalid MTU: %d\n", new_mtu); + return -EINVAL; + } + + netdev_info(ndev, "changing MTU from %d to %d\n", ndev->mtu, new_mtu); + eth_running = netif_running(ndev); + if (eth_running) { + netif_stop_queue(ndev); + xgene_enet_mac_rx_state(priv, 0); + xgene_enet_mac_tx_state(priv, 0); + } + ndev->mtu = new_mtu; + xgene_enet_mac_change_mtu(priv, HW_MTU(new_mtu)); + if (eth_running) { + xgene_enet_mac_rx_state(priv, 1); + xgene_enet_mac_tx_state(priv, 1); + netif_start_queue(ndev); + } + return 0; +} + +static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct xgene_enet_pdev *pdev = bus->priv; + struct xgene_enet_priv *priv = &pdev->priv; + u32 regval1; + + xgene_genericmiiphy_read(priv, mii_id, regnum, ®val1); + pr_debug("%s: bus=%d reg=%d val=%x\n", __func__, mii_id, + regnum, regval1); + return (int)regval1; +} + +static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, + u16 regval) +{ + struct xgene_enet_pdev *pdev = bus->priv; + struct xgene_enet_priv *priv = &pdev->priv; + + pr_debug("%s: bus=%d reg=%d val=%x\n", __func__, mii_id, + regnum, regval); + xgene_genericmiiphy_write(priv, mii_id, regnum, regval); + + return 0; +} + +static void xgene_enet_mdio_link_change(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + struct phy_device *phydev = pdev->phy_dev; + int status_change = 0; + + if (phydev->link) { + if (pdev->phy_speed != phydev->speed) { + xgene_enet_mac_init(priv, ndev->dev_addr, phydev->speed, + HW_MTU(ndev->mtu), priv->crc); + pdev->phy_speed = phydev->speed; + status_change = 1; + } + } + + if (phydev->link != pdev->phy_link) { + if (!phydev->link) + pdev->phy_speed = 0; + pdev->phy_link = phydev->link; + status_change = 1; + } + + if (status_change) { + xgene_enet_mac_rx_state(priv, phydev->link); + xgene_enet_mac_tx_state(priv, phydev->link); + if (phydev->link) + netdev_info(ndev, "%s: link up %d Mbps\n", + ndev->name, phydev->speed); + else + netdev_info(ndev, "%s: link down\n", ndev->name); + } +} + +static int xgene_enet_mdio_probe(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct phy_device *phydev = NULL; + int phy_addr; + + /* find the first phy */ + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (pdev->mdio_bus->phy_map[phy_addr]) { + phydev = pdev->mdio_bus->phy_map[phy_addr]; + break; + } + } + + if (!phydev) { + netdev_info(ndev, "%s: no PHY found\n", ndev->name); + return -1; + } + + /* attach the mac to the phy */ + phydev = phy_connect(ndev, dev_name(&phydev->dev), + &xgene_enet_mdio_link_change, + PHY_INTERFACE_MODE_RGMII); + + pdev->phy_link = 0; + pdev->phy_speed = 0; + + if (IS_ERR(phydev)) { + pdev->phy_dev = NULL; + netdev_err(ndev, "%s: Could not attach to PHY\n", ndev->name); + return PTR_ERR(phydev); + } + pdev->phy_dev = phydev; + + netdev_info(ndev, "%s: phy_id=0x%08x phy_drv=\"%s\"", + ndev->name, phydev->phy_id, phydev->drv->name); + + return 0; +} + +static int xgene_enet_mdio_remove(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = + (struct xgene_enet_pdev *)netdev_priv(ndev); + struct mii_bus *mdio_bus; + + mdio_bus = pdev->mdio_bus; + mdiobus_unregister(mdio_bus); + mdiobus_free(mdio_bus); + pdev->mdio_bus = NULL; + + return 0; +} + +static inline u32 xgene_enet_hdr_len(const void *data) +{ + const struct ethhdr *eth = data; + return (eth->h_proto == htons(ETH_P_8021Q)) ? VLAN_ETH_HLEN : ETH_HLEN; +} + +irqreturn_t xgene_enet_e2c_irq(const int irq, void *data) +{ + struct xgene_enet_qcontext *e2c = (struct xgene_enet_qcontext *)data; + + if (napi_schedule_prep(&e2c->napi)) { + disable_irq_nosync(irq); + __napi_schedule(&e2c->napi); + } + + return IRQ_HANDLED; +} + +static int xgene_enet_tx_completion(struct xgene_enet_qcontext *e2c, + struct xgene_qmtm_msg32 *msg32_1) +{ + struct sk_buff *skb; + int rc = 0; + + skb = (struct sk_buff *)xgene_enet_dec_addr( + ((u64)msg32_1->msgup16.H0Info_msbH << 32) | + msg32_1->msgup16.H0Info_msbL); + + if (likely(skb)) { + dev_kfree_skb_any(skb); + } else { + netdev_info(e2c->pdev->ndev, "completion skb is NULL\n"); + rc = -1; + } + + return rc; +} + +static inline u16 xgene_enet_select_queue(struct net_device *ndev, + struct sk_buff *skb, + void *accel_priv) +{ + return skb_tx_hash(ndev, skb); +} + +/* Checksum offload processing */ +static int xgene_enet_checksum_offload(struct net_device *ndev, + struct sk_buff *skb, + struct xgene_qmtm_msg_up16 *msg_up16) +{ + u32 maclen, nr_frags, ihl; + struct iphdr *iph; + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + int rc = 0; + + if (unlikely(!(ndev->features & NETIF_F_IP_CSUM))) + goto out; + + if (unlikely(skb->protocol != htons(ETH_P_IP)) && + unlikely(skb->protocol != htons(ETH_P_8021Q))) + goto out; + + nr_frags = skb_shinfo(skb)->nr_frags; + maclen = xgene_enet_hdr_len(skb->data); + iph = ip_hdr(skb); + ihl = ip_hdrlen(skb) >> 2; + + if (unlikely(iph->frag_off & htons(IP_MF | IP_OFFSET))) + goto out; + + if (likely(iph->protocol == IPPROTO_TCP)) { + int xhlen, mss_len; + u32 mss, all_hdr_len; + + xhlen = tcp_hdrlen(skb) / 4; + msg_up16->H0Info_lsbL |= + (xhlen & TSO_TCP_HLEN_MASK) | + ((ihl & TSO_IP_HLEN_MASK) << 6) | + (TSO_CHKSUM_ENABLE << 22) | (TSO_IPPROTO_TCP << 24); + + netdev_dbg(ndev, + "Checksum Offload H0Info 0x%04X%08X H1Info 0x%04X%08X\n", + msg_up16->H0Info_lsbH, msg_up16->H0Info_lsbL, + msg_up16->H0Info_msbH, msg_up16->H0Info_msbL); + + if (unlikely(!(ndev->features & NETIF_F_TSO))) + goto out; + + /* TCP Segmentation offload processing */ + mss = skb_shinfo(skb)->gso_size; + all_hdr_len = maclen + ip_hdrlen(skb) + tcp_hdrlen(skb); + mss_len = skb->len - all_hdr_len; + + /* HW requires all header resides in the first buffer */ + if (nr_frags && (skb_headlen(skb) < all_hdr_len)) { + netdev_err(ndev, + "Unsupported header len location by Eth HW\n"); + pdev->stats.estats.tx_dropped++; + dev_kfree_skb(skb); + rc = -1; + goto out; + } + + if (!mss || mss_len <= mss) + goto out; + + if (mss != pdev->mss) { + xgene_enet_tx_offload(&pdev->priv, XGENE_ENET_MSS0, + mss); + pdev->mss = mss; + } + + msg_up16->H0Info_lsbL |= ((0 & TSO_MSS_MASK) << 20) | + ((TSO_ENABLE & TSO_ENABLE_MASK) << 23); + netdev_dbg(ndev, + "TSO H0Info 0x%04X%08X H1Info 0x%04X%08X mss %d\n", + msg_up16->H0Info_lsbH, msg_up16->H0Info_lsbL, + msg_up16->H0Info_msbH, msg_up16->H0Info_msbL, mss); + } else if (iph->protocol == IPPROTO_UDP) { + msg_up16->H0Info_lsbL |= (UDP_HDR_SIZE & TSO_TCP_HLEN_MASK) + | ((ihl & TSO_IP_HLEN_MASK) << 6) + | (TSO_CHKSUM_ENABLE << 22) + | (TSO_IPPROTO_UDP << 24); + netdev_dbg(ndev, + "Csum Offload H0Info 0x%04X%08X H1Info 0x%04X%08X\n", + msg_up16->H0Info_lsbH, msg_up16->H0Info_lsbL, + msg_up16->H0Info_msbH, msg_up16->H0Info_msbL); + } else { + msg_up16->H0Info_lsbL |= ((ihl & TSO_IP_HLEN_MASK) << 6); + } +out: + return rc; +} + +static void xgene_enet_process_frags(struct net_device *ndev, + struct xgene_qmtm_msg16 *msg16, + struct xgene_enet_qcontext *c2e, + struct sk_buff *skb) +{ + struct xgene_qmtm_msg_up16 *msg_up16; + struct xgene_qmtm_msg_ext32 *msg32_2; + struct xgene_qmtm_msg_ext8 *ext_msg; + struct xgene_qmtm_msg_ll8 *ext_msg_ll8; + u32 qtail = c2e->qdesc->qtail; + phys_addr_t paddr = virt_to_phys(skb->data); + u32 nr_frags = skb_shinfo(skb)->nr_frags; + skb_frag_t *frag = NULL; + u8 *vaddr = NULL; + int frag_no = 0, len = 0, offset = 0; + int ell_bcnt = 0, ell_cnt = 0, i; + + msg_up16 = (struct xgene_qmtm_msg_up16 *)&msg16[1]; + msg32_2 = (struct xgene_qmtm_msg_ext32 *)&c2e->qdesc->msg32[qtail]; + + if (++qtail == c2e->qdesc->count) + qtail = 0; + + memset(msg32_2, 0, sizeof(struct xgene_qmtm_msg_ext32)); + + /* First Fragment, 64B message */ + msg16->BufDataLen = xgene_qmtm_encode_datalen(skb_headlen(skb)); + msg16->DataAddrL = (u32)paddr; + msg16->DataAddrH = (u32)(paddr >> 32); + msg16->NV = 1; + + /* 2nd, 3rd, and 4th fragments */ + ext_msg = &msg32_2->msg8_1; + + /* Terminate next pointers, will be updated later as required */ + msg32_2->msg8_2.NxtBufDataLength = 0x7800; + msg32_2->msg8_3.NxtBufDataLength = 0x7800; + msg32_2->msg8_4.NxtBufDataLength = 0x7800; + + for (i = 0; i < 3 && frag_no < nr_frags; i++) { + if (!vaddr) { + frag = &skb_shinfo(skb)->frags[frag_no]; + len = frag->size; + vaddr = skb_frag_address(frag); + offset = 0; + netdev_dbg(ndev, "SKB Frag[%d] 0x%p len %d\n", + frag_no, vaddr, len); + } + paddr = virt_to_phys(vaddr + offset); + ext_msg->NxtDataAddrL = (u32)paddr; + ext_msg->NxtDataAddrH = (u32)(paddr >> 32); + + if (len <= 16 * 1024) { + /* Encode using 16K buffer size format */ + ext_msg->NxtBufDataLength = + xgene_qmtm_encode_datalen(len); + vaddr = NULL; + frag_no++; + } else { + len -= 16 * 1024; + offset += 16 * 1024; + /* Encode using 16K buffer size format */ + ext_msg->NxtBufDataLength = 0; + } + + netdev_dbg(ndev, "Frag[%d] PADDR 0x%04X%08X len %d\n", i, + ext_msg->NxtDataAddrH, ext_msg->NxtDataAddrL, + ext_msg->NxtBufDataLength); + ext_msg = (struct xgene_qmtm_msg_ext8 *) + (((u8 *) msg32_2) + (8 * ((i + 1) ^ 1))); + } + + /* Determine no more fragment, last one, or more than one */ + if (!vaddr) { + /* Check next fragment */ + if (frag_no >= nr_frags) { + goto out; + } else { + frag = &skb_shinfo(skb)->frags[frag_no]; + if (frag->size <= 16 * 1024 + && (frag_no + 1) >= nr_frags) + goto one_more_frag; + else + goto more_than_one_frag; + } + } else if (len <= 16 * 1024) { + /* Current fragment <= 16K, check if last fragment */ + if ((frag_no + 1) >= nr_frags) + goto one_more_frag; + else + goto more_than_one_frag; + } else { + /* Current fragment requires two pointers */ + goto more_than_one_frag; + } + +one_more_frag: + if (!vaddr) { + frag = &skb_shinfo(skb)->frags[frag_no]; + len = frag->size; + vaddr = skb_frag_address(frag); + offset = 0; + netdev_dbg(ndev, "SKB Frag[%d] 0x%p len %d\n", + frag_no, vaddr, len); + } + + paddr = virt_to_phys(vaddr + offset); + ext_msg->NxtDataAddrL = (u32)paddr; + ext_msg->NxtDataAddrH = (u32)(paddr >> 32); + /* Encode using 16K buffer size format */ + ext_msg->NxtBufDataLength = xgene_qmtm_encode_datalen(len); + netdev_dbg(ndev, "Frag[%d] PADDR 0x%04X%08X len %d\n", i, + ext_msg->NxtDataAddrH, ext_msg->NxtDataAddrL, + ext_msg->NxtBufDataLength); + goto out; + +more_than_one_frag: + msg16->LL = 1; /* Extended link list */ + ext_msg_ll8 = &msg32_2->msg8_ll; + ext_msg = &c2e->msg8[qtail * 256]; + memset(ext_msg, 0, 255 * sizeof(struct xgene_qmtm_msg_ext8)); + paddr = virt_to_phys(ext_msg); + ext_msg_ll8->NxtDataPtrL = (u32)paddr; + ext_msg_ll8->NxtDataPtrH = (u32)(paddr >> 32); + + for (i = 0; i < 255 && frag_no < nr_frags;) { + if (vaddr == NULL) { + frag = &skb_shinfo(skb)->frags[frag_no]; + len = frag->size; + vaddr = skb_frag_address(frag); + offset = 0; + netdev_dbg(ndev, "SKB Frag[%d] 0x%p len %d\n", + frag_no, vaddr, len); + } + paddr = virt_to_phys(vaddr + offset); + ext_msg[i ^ 1].NxtDataAddrL = (u32)paddr; + ext_msg[i ^ 1].NxtDataAddrH = (u32)(paddr >> 32); + + if (len <= 16 * 1024) { + /* Encode using 16K buffer size format */ + ext_msg[i ^ 1].NxtBufDataLength = + xgene_qmtm_encode_datalen(len); + ell_bcnt += len; + vaddr = NULL; + frag_no++; + } else { + len -= 16 * 1024; + offset += 16 * 1024; + ell_bcnt += 16 * 1024; + } + + ell_cnt++; + netdev_dbg(ndev, "Frag ELL[%d] PADDR 0x%04X%08X len %d\n", i, + ext_msg[i ^ 1].NxtDataAddrH, + ext_msg[i ^ 1].NxtDataAddrL, + ext_msg[i ^ 1].NxtBufDataLength); + i++; + xgene_qmtm_msg_le32((u32 *)&ext_msg[i ^ 1], 2); + } + + /* Encode the extended link list byte count and link count */ + ext_msg_ll8->NxtLinkListength = ell_cnt; + msg_up16->TotDataLengthLinkListLSBs = (ell_bcnt & 0xFFF); + ext_msg_ll8->TotDataLengthLinkListMSBs = ((ell_bcnt & 0xFF000) >> 12); + +out: + xgene_qmtm_msg_le32((u32 *)msg32_2, 8); + c2e->qdesc->qtail = qtail; +} + +/* Packet transmit function */ +static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_qcontext *c2e = pdev->tx[skb->queue_mapping]; + struct xgene_qmtm_msg16 *msg16; + struct xgene_qmtm_msg_up16 *msg_up16; + u64 pa = xgene_enet_enc_addr((void *)skb); + u32 nr_frags = skb_shinfo(skb)->nr_frags; + u32 nummsgs = (readl(c2e->nummsgs) & 0x1fffe) >> 1; + u32 cmd = 1; + + msg16 = + (struct xgene_qmtm_msg16 *)&c2e->qdesc->msg32[c2e->qdesc->qtail]; + msg_up16 = (struct xgene_qmtm_msg_up16 *)&msg16[1]; + + if (nummsgs > pdev->tx_cqt_hi) { + do { + nummsgs = (readl(c2e->nummsgs) & 0x1fffe) >> 1; + } while (nummsgs < pdev->tx_cqt_low); + } + + if (++c2e->qdesc->qtail == c2e->qdesc->count) + c2e->qdesc->qtail = 0; + + memset(msg16, 0, sizeof(struct xgene_qmtm_msg32)); + + if (likely(nr_frags == 0)) { + skb->len = (skb->len < 60) ? 60 : skb->len; + msg16->BufDataLen = xgene_qmtm_encode_datalen(skb->len); + msg16->DataAddrL = (u32)virt_to_phys(skb->data); + msg16->DataAddrH = (u32)(virt_to_phys(skb->data) >> 32); + } else { + xgene_enet_process_frags(ndev, msg16, c2e, skb); + cmd = 2; + } + + msg_up16->H0Info_msbL = (u32)pa; + msg_up16->H0Info_msbH = (u32)(pa >> 32); + msg_up16->H0Enq_Num = c2e->eqnum; + msg16->C = 1; + + /* Set TYPE_SEL for egress work message */ + msg_up16->H0Info_lsbH = TYPE_SEL_WORK_MSG << 12; + + /* Enable CRC insertion */ + if (!pdev->priv.crc) + msg_up16->H0Info_lsbH |= (TSO_INS_CRC_ENABLE << 3); + + /* Setup mac header length H0Info */ + msg_up16->H0Info_lsbL |= + ((xgene_enet_hdr_len(skb->data) & TSO_ETH_HLEN_MASK) << 12); + + if (unlikely(xgene_enet_checksum_offload(ndev, skb, msg_up16))) + return NETDEV_TX_OK; + + /* xmit: Push the work message to ENET HW */ + netdev_dbg(ndev, "TX CQID %d Addr 0x%04x%08x len %d\n", + msg_up16->H0Enq_Num, msg16->DataAddrH, + msg16->DataAddrL, msg16->BufDataLen); + xgene_qmtm_msg_le32(&(((u32 *)msg16)[1]), 7); + writel(cmd, c2e->qdesc->command); + + ndev->trans_start = jiffies; + return NETDEV_TX_OK; +} + +int xgene_enet_check_skb(struct net_device *ndev, + struct sk_buff *skb, + struct xgene_qmtm_msg32 *msg32_1, u32 qid) +{ + struct xgene_qmtm_msg16 *msg16 = &msg32_1->msg16; + u32 UserInfo = msg16->UserInfo; + u8 NV = msg16->NV; + int rc = 0; + + if (unlikely(!skb)) { + netdev_err(ndev, "ENET skb NULL UserInfo %d QID %d FP 0x%x\n", + UserInfo, qid, msg16->FPQNum); + print_hex_dump(KERN_INFO, "QM msg:", + DUMP_PREFIX_ADDRESS, 16, 4, msg32_1, + NV ? 64 : 32, 1); + rc = -1; + goto out; + } + + if (unlikely(!skb->head) || unlikely(!skb->data)) { + netdev_err(ndev, "ENET skb 0x%p head 0x%p data 0x%p FP 0x%x\n", + skb, skb->head, skb->data, msg16->FPQNum); + print_hex_dump(KERN_INFO, "QM msg:", + DUMP_PREFIX_ADDRESS, 16, 4, msg32_1, + NV ? 64 : 32, 1); + rc = -1; + goto out; + } + + if (unlikely(skb->len)) { + netdev_err(ndev, "ENET skb 0x%p len %d FP 0x%x\n", skb, + skb->len, msg16->FPQNum); + print_hex_dump(KERN_INFO, "QM msg:", + DUMP_PREFIX_ADDRESS, 16, 4, msg32_1, + NV ? 64 : 32, 1); + rc = -1; + goto out; + } + +out: + return rc; +} + +inline void xgene_enet_skip_csum(struct sk_buff *skb) +{ + struct iphdr *iph = (struct iphdr *)skb->data; + if (likely(!(iph->frag_off & htons(IP_MF | IP_OFFSET))) + || likely(iph->protocol != IPPROTO_TCP + && iph->protocol != IPPROTO_UDP)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } +} + +/* Process received frame */ +static int xgene_enet_rx_frame(struct xgene_enet_qcontext *e2c, + struct xgene_qmtm_msg32 *msg32_1) +{ + struct xgene_enet_qcontext *c2e = e2c->c2e_skb; + struct xgene_enet_pdev *pdev = e2c->pdev; + struct net_device *ndev = pdev->ndev; + struct xgene_qmtm_msg16 *msg16 = &msg32_1->msg16; + struct sk_buff *skb = NULL; + u32 data_len = xgene_qmtm_decode_datalen(msg16->BufDataLen); + u8 NV = msg16->NV; + u8 LErr = ((u8) msg16->ELErr << 3) | msg16->LErr; + u32 UserInfo = msg16->UserInfo; + u32 qid = pdev->qm_queues.rx[e2c->queue_index].qid; + + if (unlikely(UserInfo >= c2e->qdesc->count)) { + netdev_err(ndev, "ENET: invalid UserInfo %d QID %d FP 0x%x\n", + UserInfo, qid, msg16->FPQNum); + print_hex_dump(KERN_INFO, "QM msg:", + DUMP_PREFIX_ADDRESS, 16, 4, msg32_1, + NV ? 64 : 32, 1); + goto err_refill; + } + + skb = c2e->skb[UserInfo]; + if (unlikely(xgene_enet_check_skb(ndev, skb, msg32_1, qid))) + goto err_refill; + + /* Check for error, if packet received with error */ + if (unlikely(LErr)) { + if (LErr == 0x15) /* ignore rx queue full error */ + goto process_pkt; + if (LErr == 0x10 || LErr == 0x11) { + LErr = 0; + goto process_pkt; + } + if (LErr == 0x10 || LErr == 5) { + LErr = 0; + goto process_pkt; + } + + xgene_enet_parse_error(LErr, qid); + netdev_dbg(ndev, "ENET LErr 0x%x skb 0x%p FP 0x%x\n", + LErr, skb, msg16->FPQNum); + print_hex_dump(KERN_ERR, "QM Msg: ", + DUMP_PREFIX_ADDRESS, 16, 4, msg32_1, + NV ? 64 : 32, 1); + goto err_refill; + } + +process_pkt: + prefetch(skb->data - NET_IP_ALIGN); + + if (likely(!NV)) { + /* Strip off CRC as HW isn't doing this */ + data_len -= 4; + skb_put(skb, data_len); + netdev_dbg(ndev, "RX SKB len %d\n", data_len); + } + + if (--e2c->c2e_count == 0) { + xgene_enet_refill_fp(c2e, 32); + e2c->c2e_count = 32; + } + + if (pdev->num_rx_queues > 1) + skb_record_rx_queue(skb, e2c->queue_index); + + skb->protocol = eth_type_trans(skb, ndev); + if (likely(ndev->features & NETIF_F_IP_CSUM) + && likely(LErr == 0) + && likely(skb->protocol == htons(ETH_P_IP))) { + xgene_enet_skip_csum(skb); + } + + napi_gro_receive(&e2c->napi, skb); + return 0; + +err_refill: + if (skb != NULL) + dev_kfree_skb_any(skb); + + xgene_enet_refill_fp(e2c->c2e_skb, 1); + + if (LErr != 0x15) + pdev->stats.estats.rx_hw_errors++; + else + pdev->stats.estats.rx_hw_overrun++; + + return -1; +} + +static int xgene_enet_dequeue_msg(struct xgene_enet_qcontext *e2c, int budget) +{ + u32 processed = 0; + u32 command = 0; + u32 qhead = e2c->qdesc->qhead; + u32 count = e2c->qdesc->count; + u16 nummsgs; + + while (budget--) { + struct xgene_qmtm_msg32 *msg32_1 = &e2c->qdesc->msg32[qhead]; + struct xgene_qmtm_msg_ext32 *msg32_2 = NULL; + + if (unlikely(((u32 *) msg32_1)[EMPTY_SLOT_INDEX] == EMPTY_SLOT)) + break; + + command--; + if (++qhead == count) + qhead = 0; + + xgene_qmtm_msg_le32(&(((u32 *)msg32_1)[1]), 7); + + if (msg32_1->msg16.NV) { + msg32_2 = (struct xgene_qmtm_msg_ext32 *) + &e2c->qdesc->msg32[qhead]; + if (unlikely(((u32 *) msg32_2)[EMPTY_SLOT_INDEX] + == EMPTY_SLOT)) { + command++; + if (!qhead) + qhead = count; + qhead--; + xgene_qmtm_msg_le32(&(((u32 *)msg32_1)[1]), 7); + break; + } + command--; + if (++qhead == count) + qhead = 0; + xgene_qmtm_msg_le32((u32 *)msg32_2, 8) + } + + if (msg32_1->msg16.FPQNum) + xgene_enet_rx_frame(e2c, msg32_1); + else + xgene_enet_tx_completion(e2c, msg32_1); + + ((u32 *) msg32_1)[EMPTY_SLOT_INDEX] = EMPTY_SLOT; + if (msg32_2) + ((u32 *) msg32_2)[EMPTY_SLOT_INDEX] = EMPTY_SLOT; + processed++; + } + + do { + nummsgs = (readl(e2c->nummsgs) & 0x1fffe) >> 1; + } while (nummsgs < (1 + ~command)); + writel(command, e2c->qdesc->command); + e2c->qdesc->qhead = qhead; + + return processed; +} + +static int xgene_enet_napi(struct napi_struct *napi, const int budget) +{ + struct xgene_enet_qcontext *e2c = + container_of(napi, struct xgene_enet_qcontext, napi); + int processed = xgene_enet_dequeue_msg(e2c, budget); + + if (processed != budget) { + napi_complete(napi); + enable_irq(e2c->qdesc->irq); + } + + return processed; +} + +static void xgene_enet_timeout(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + xgene_enet_mac_reset(&pdev->priv); +} + +static void xgene_enet_napi_add(struct xgene_enet_pdev *pdev) +{ + u32 qindex; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) + netif_napi_add(pdev->ndev, &pdev->rx[qindex]->napi, + xgene_enet_napi, 64); +} + +static void xgene_enet_napi_del(struct xgene_enet_pdev *pdev) +{ + u32 qindex; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) + netif_napi_del(&pdev->rx[qindex]->napi); +} + +static void xgene_enet_napi_enable(struct xgene_enet_pdev *pdev) +{ + u32 qindex; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) + napi_enable(&pdev->rx[qindex]->napi); +} + +static void xgene_enet_napi_disable(struct xgene_enet_pdev *pdev) +{ + u32 qindex; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) + napi_disable(&pdev->rx[qindex]->napi); +} + +static void xgene_enet_irq_enable(struct xgene_enet_pdev *pdev) +{ + u32 qindex; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) + enable_irq(pdev->rx[qindex]->qdesc->irq); +} + +static void xgene_enet_irq_disable_all(struct xgene_enet_pdev *pdev) +{ + u32 qindex; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) + disable_irq_nosync(pdev->rx[qindex]->qdesc->irq); +} + +static int xgene_enet_open(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + + xgene_enet_napi_enable(pdev); + xgene_enet_irq_enable(pdev); + + netif_tx_start_all_queues(ndev); + netif_carrier_on(ndev); + + if (pdev->phy_dev) + phy_start(pdev->phy_dev); + + xgene_enet_mac_tx_state(priv, 1); + xgene_enet_mac_rx_state(priv, 1); + + return 0; +} + +static int xgene_enet_close(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + u32 qindex; + + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + netif_tx_disable(ndev); + + if (pdev->phy_dev) + phy_stop(pdev->phy_dev); + + xgene_enet_mac_tx_state(priv, 0); + xgene_enet_mac_rx_state(priv, 0); + + xgene_enet_irq_disable_all(pdev); + xgene_enet_napi_disable(pdev); + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) + xgene_enet_dequeue_msg(pdev->rx[qindex], -1); + + return 0; +} + +static struct xgene_enet_qcontext *xgene_enet_allocq(struct xgene_enet_pdev + *pdev, + struct xgene_qmtm_qinfo + *qinfo, + struct xgene_qmtm_sdev + *sdev, u8 qtype, u8 qsize) +{ + struct xgene_enet_qcontext *qc; + + memset(qinfo, 0, sizeof(struct xgene_qmtm_qinfo)); + qinfo->sdev = sdev; + qinfo->qaccess = QACCESS_ALT; + qinfo->qtype = qtype; + qinfo->qsize = qsize; + qinfo->flags = XGENE_SLAVE_DEFAULT_FLAGS; + + if (xgene_qmtm_set_qinfo(qinfo)) { + netdev_err(pdev->ndev, "Could not allocate queue\n"); + return NULL; + } + + qc = (struct xgene_enet_qcontext *) + kmalloc(sizeof(struct xgene_enet_qcontext), + GFP_KERNEL | __GFP_ZERO); + qc->nummsgs = &(((u32 *) qinfo->qfabric)[1]); + qc->qdesc = qinfo->qdesc; + qc->pdev = pdev; + + return qc; +} + +static int xgene_enet_qconfig(struct xgene_enet_pdev *pdev) +{ + struct xgene_qmtm_qinfo qinfo; + struct xgene_qmtm_sdev *sdev = pdev->sdev; + struct xgene_qmtm_sdev *idev = pdev->sdev->idev; + int qmtm_ip = sdev->qmtm_ip; + int rc = 0; + u32 qindex; + struct xgene_enet_qcontext *e2c; + struct xgene_enet_qcontext *c2e; + + memset(&pdev->qm_queues, 0, sizeof(struct eth_queue_ids)); + pdev->qm_queues.qm_ip = qmtm_ip; + + for (qindex = 0; qindex < pdev->num_tx_queues; qindex++) { + /* Allocate EGRESS work queues from CPUx to ETHx */ + c2e = xgene_enet_allocq(pdev, &qinfo, sdev, + QTYPE_PQ, QSIZE_64KB); + if (!c2e) + goto out; + + pdev->qm_queues.tx[qindex].qid = qinfo.queue_id; + + /* Setup TX Frame cpu_to_enet info */ + c2e->msg8 = + (struct xgene_qmtm_msg_ext8 *) + kmalloc(sizeof(struct xgene_qmtm_msg_ext8) * 256 * + c2e->qdesc->count, GFP_KERNEL); + c2e->queue_index = qindex; + pdev->tx[qindex] = c2e; + /* Assign TX completn queue threshold based on rx queue size */ + pdev->tx_cqt_hi = c2e->qdesc->count / 4; + pdev->tx_cqt_low = pdev->tx_cqt_low / 16; + } + + pdev->qm_queues.default_tx_qid = pdev->qm_queues.tx[0].qid; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) { + /* Allocate INGRESS work queue from ETHx to CPUx */ + u8 qsize = QSIZE_512KB; + e2c = xgene_enet_allocq(pdev, &qinfo, idev, + QTYPE_PQ, qsize); + if (!e2c) + goto out; + + pdev->qm_queues.rx[qindex].qid = qinfo.queue_id; + e2c->queue_index = qindex; + snprintf(e2c->irq_name, sizeof(e2c->irq_name), "%s-rx%d", + pdev->ndev->name, qindex); + e2c->c2e_count = 1; + pdev->rx[qindex] = e2c; + + /* Allocate free pool for ETHx from CPUx */ + c2e = xgene_enet_allocq(pdev, &qinfo, sdev, + QTYPE_FP, QSIZE_16KB); + if (!c2e) + goto out; + + c2e->skb = kmalloc(sizeof (struct sk_buff *) * + qinfo.qdesc->count, GFP_KERNEL | __GFP_ZERO); + pdev->qm_queues.rx_fp[qindex].qid = qinfo.queue_id; + pdev->qm_queues.rx_fp[qindex].pbn = qinfo.pbn; + + c2e->eqnum = QMTM_QUEUE_ID(qmtm_ip, qinfo.queue_id); + c2e->buf_size = XGENE_ENET_PKT_BUF_SIZE; + pdev->rx_skb_pool[qindex] = c2e; + pdev->rx[qindex]->c2e_skb = pdev->rx_skb_pool[qindex]; + + /* Configure free pool */ + xgene_enet_init_fp(pdev->rx_skb_pool[qindex], + pdev->rx_buff_cnt); + } + + for (qindex = 0; qindex < pdev->num_tx_queues; qindex++) { + u32 cqindex = pdev->num_tx_queues - qindex - 1; + u32 rqindex = qindex % pdev->num_rx_queues; + + pdev->tx[cqindex]->nummsgs = pdev->rx[rqindex]->nummsgs; + pdev->tx[cqindex]->eqnum = QMTM_QUEUE_ID(qmtm_ip, + pdev->qm_queues. + rx[rqindex].qid); + } + + pdev->qm_queues.default_hw_tx_qid = pdev->qm_queues.hw_tx[0].qid; + pdev->qm_queues.default_rx_qid = pdev->qm_queues.rx[0].qid; + pdev->qm_queues.default_rx_fp_qid = pdev->qm_queues.rx_fp[0].qid; + pdev->qm_queues.default_rx_fp_pbn = pdev->qm_queues.rx_fp[0].pbn; + pdev->qm_queues.default_rx_nxtfp_qid = pdev->qm_queues.rx_nxtfp[0].qid; + pdev->qm_queues.default_rx_nxtfp_pbn = pdev->qm_queues.rx_nxtfp[0].pbn; + + netdev_dbg(pdev->ndev, "CQID %d FP %d FP PBN %d\n", + pdev->qm_queues.default_comp_qid, + pdev->qm_queues.default_rx_fp_qid, + pdev->qm_queues.default_rx_fp_pbn); + +out: + return rc; +} + +static void xgene_enet_delete_queue(struct xgene_enet_pdev *pdev) +{ + struct xgene_qmtm_qinfo qinfo; + u32 qindex; + u8 qmtm_ip = pdev->sdev->qmtm_ip; + u16 queue_id; + + qinfo.qmtm_ip = qmtm_ip; + + for (qindex = 0; qindex < pdev->num_tx_queues; qindex++) { + queue_id = pdev->qm_queues.tx[qindex].qid; + + if (queue_id) { + qinfo.queue_id = queue_id; + xgene_qmtm_clr_qinfo(&qinfo); + } + } + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) { + queue_id = pdev->qm_queues.rx[qindex].qid; + + if (queue_id) { + qinfo.queue_id = queue_id; + xgene_qmtm_clr_qinfo(&qinfo); + } + + queue_id = pdev->qm_queues.rx_fp[qindex].qid; + + if (queue_id) { + qinfo.queue_id = queue_id; + xgene_qmtm_clr_qinfo(&qinfo); + } + } +} + +static struct net_device_stats *xgene_enet_stats(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &(pdev->priv); + struct net_device_stats *nst = &pdev->nstats; + struct xgene_enet_detailed_stats detailed_stats; + struct xgene_enet_rx_stats *rx_stats; + struct xgene_enet_tx_stats *tx_stats; + u32 pkt_bytes, crc_bytes = 4; + + memset(&detailed_stats, 0, sizeof(struct xgene_enet_detailed_stats)); + + rx_stats = &detailed_stats.rx_stats; + tx_stats = &detailed_stats.tx_stats; + + local_irq_disable(); + xgene_enet_get_stats(priv, &detailed_stats); + + pkt_bytes = rx_stats->rx_byte_count; + pkt_bytes -= (rx_stats->rx_packet_count * crc_bytes); + nst->rx_packets += rx_stats->rx_packet_count; + nst->rx_bytes += pkt_bytes; + + pkt_bytes = tx_stats->tx_byte_count; + pkt_bytes -= (tx_stats->tx_pkt_count * crc_bytes); + nst->tx_packets += tx_stats->tx_pkt_count; + nst->tx_bytes += pkt_bytes; + + nst->rx_dropped += rx_stats->rx_drop_pkt_count; + nst->tx_dropped += tx_stats->tx_drop_frm_count; + + nst->rx_crc_errors += rx_stats->rx_fcs_err_count; + nst->rx_length_errors += rx_stats->rx_frm_len_err_pkt_count; + nst->rx_frame_errors += rx_stats->rx_alignment_err_pkt_count; + nst->rx_over_errors += (rx_stats->rx_oversize_pkt_count + + pdev->stats.estats.rx_hw_overrun); + + nst->rx_errors += (rx_stats->rx_fcs_err_count + + rx_stats->rx_frm_len_err_pkt_count + + rx_stats->rx_oversize_pkt_count + + rx_stats->rx_undersize_pkt_count + + pdev->stats.estats.rx_hw_overrun + + pdev->stats.estats.rx_hw_errors); + + nst->tx_errors += tx_stats->tx_fcs_err_frm_count + + tx_stats->tx_undersize_frm_count; + + local_irq_enable(); + + pdev->stats.estats.rx_hw_errors = 0; + pdev->stats.estats.rx_hw_overrun = 0; + + return nst; +} + +static int xgene_enet_set_mac_address(struct net_device *ndev, void *p) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &(pdev->priv); + struct sockaddr *addr = p; + + if (netif_running(ndev)) + return -EBUSY; + + memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + xgene_enet_set_mac_addr(priv, (unsigned char *)(ndev->dev_addr)); + return 0; +} + +/* net_device_ops structure for data path ethernet */ +static const struct net_device_ops apm_dnetdev_ops = { + .ndo_open = xgene_enet_open, + .ndo_stop = xgene_enet_close, + .ndo_select_queue = xgene_enet_select_queue, + .ndo_start_xmit = xgene_enet_start_xmit, + .ndo_tx_timeout = xgene_enet_timeout, + .ndo_get_stats = xgene_enet_stats, + .ndo_change_mtu = xgene_enet_change_mtu, + .ndo_set_mac_address = xgene_enet_set_mac_address, +}; + +static void xgene_enet_register_irq(struct net_device *ndev) +{ + struct xgene_enet_pdev *pdev; + struct device *dev; + u32 qindex; + + pdev = (struct xgene_enet_pdev *)netdev_priv(ndev); + dev = &pdev->plat_dev->dev; + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) { + if (devm_request_irq(dev, pdev->rx[qindex]->qdesc->irq, + xgene_enet_e2c_irq, 0, + pdev->rx[qindex]->irq_name, + (void *)pdev->rx[qindex]) != 0) { + netdev_err(ndev, "request_irq failed %d for RX Frame\n", + pdev->rx[qindex]->qdesc->irq); + return; + } + + /* Disable interrupts for RX queue mailboxes */ + disable_irq_nosync(pdev->rx[qindex]->qdesc->irq); + } + + xgene_enet_register_err_irqs(ndev); +} + +static int xgene_enet_get_resources(struct xgene_enet_pdev *pdev) +{ + struct platform_device *plat_dev; + struct net_device *ndev; + struct device *dev; + struct xgene_enet_priv *priv; + struct xgene_qmtm_sdev *sdev; + struct xgene_enet_platform_data pdata; + struct resource *res; + u64 csr_paddr; + void *csr_addr; + int i, rc = 0; + + plat_dev = pdev->plat_dev; + dev = &plat_dev->dev; + ndev = pdev->ndev; + priv = &pdev->priv; + + res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); + rc = -ENODEV; + goto out; + } + csr_paddr = res->start; + csr_addr = devm_ioremap(&plat_dev->dev, csr_paddr, resource_size(res)); + priv->ppaddr_base = csr_paddr; + priv->vpaddr_base = csr_addr; + + res = platform_get_resource(plat_dev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(dev, "Unable to retrieve ENET Global CSR region\n"); + rc = -ENODEV; + goto out; + } + csr_paddr = res->start; + csr_addr = devm_ioremap(&plat_dev->dev, csr_paddr, resource_size(res)); + priv->paddr_base = csr_paddr; + priv->vaddr_base = csr_addr; + + res = platform_get_resource(plat_dev, IORESOURCE_MEM, 2); + if (!res) { + dev_err(dev, "Unable to retrieve ENET MII access region\n"); + rc = -ENODEV; + goto out; + } + csr_paddr = res->start; + csr_addr = devm_ioremap(&plat_dev->dev, csr_paddr, resource_size(res)); + priv->vmii_base = csr_addr; + + rc = of_property_read_string(plat_dev->dev.of_node, "slave-name", + &pdata.sname); + + sdev = xgene_qmtm_get_sdev((char *)pdata.sname); + if (!sdev) { + dev_err(dev, "QMTM Slave %s error\n", pdata.sname); + rc = -ENODEV; + goto out; + } + pdev->sdev = sdev; + + pdata.irq = platform_get_irq(plat_dev, 0); + if (pdata.irq <= 0) { + dev_err(dev, "Unable to get ENET Error IRQ\n"); + rc = pdata.irq; + goto out; + } + pdev->enet_err_irq = pdata.irq; + + pdata.irq = platform_get_irq(plat_dev, 1); + if (pdata.irq <= 0) { + dev_err(dev, "Unable to get ENET MAC Error IRQ\n"); + rc = pdata.irq; + goto out; + } + pdev->enet_mac_err_irq = pdata.irq; + + pdata.irq = platform_get_irq(plat_dev, 2); + if (pdata.irq <= 0) { + dev_err(dev, "Unable to get ENET QMI Error IRQ\n"); + rc = pdata.irq; + goto out; + } + pdev->enet_qmi_err_irq = pdata.irq; + + rc = of_property_read_u32(plat_dev->dev.of_node, "phyid", + &pdata.phy_id); + if (rc || pdata.phy_id > 0x1F) { + dev_err(dev, "No phy ID or invalid value in DTS\n"); + rc = -EINVAL; + goto out; + } + priv->phy_addr = pdata.phy_id; + + rc = of_property_read_u8_array(plat_dev->dev.of_node, + "local-mac-address", pdata.ethaddr, + ARRAY_SIZE(pdata.ethaddr)); + if (rc) { + dev_err(dev, "Can't get Device MAC address\n"); + } else { + for (i = 0; i < ETH_ALEN; i++) + ndev->dev_addr[i] = pdata.ethaddr[i] & 0xff; + } + + pdev->clk = clk_get(&plat_dev->dev, NULL); + + if (IS_ERR(pdev->clk)) + dev_err(&plat_dev->dev, "can't get clock\n"); + else if (clk_prepare_enable(pdev->clk)) + dev_err(&plat_dev->dev, "clock prepare enable failed"); + + priv->phy_mode = PHY_MODE_RGMII; + pdev->rx_buff_cnt = XGENE_NUM_PKT_BUF; + +out: + return rc; +} + +static int xgene_enet_init_hw(struct xgene_enet_pdev *pdev) +{ + struct net_device *ndev; + struct xgene_enet_priv *priv; + struct mii_bus *mdio_bus; + int rc = 0; + + ndev = pdev->ndev; + priv = &pdev->priv; + + xgene_enet_port_reset(priv); + + /* To ensure no packet enters the system, disable Rx/Tx */ + xgene_enet_mac_tx_state(priv, 0); + xgene_enet_mac_rx_state(priv, 0); + + ndev->netdev_ops = &apm_dnetdev_ops; + + ndev->features |= NETIF_F_IP_CSUM; + ndev->features |= NETIF_F_TSO | NETIF_F_SG; + pdev->mss = DEFAULT_TCP_MSS; + xgene_enet_tx_offload(priv, XGENE_ENET_MSS0, pdev->mss); + ndev->features |= NETIF_F_GRO; + + /* Ethtool checks the capabilities/features in hw_features flag */ + ndev->hw_features = ndev->features; + SET_ETHTOOL_OPS(ndev, &xgene_ethtool_ops); + + rc = register_netdev(ndev); + if (rc) { + netdev_err(ndev, "Failed to register net dev(%d)!\n", rc); + goto out; + } + + rc = xgene_enet_qconfig(pdev); + if (rc) { + netdev_err(ndev, "Error in QM configuration\n"); + goto out; + } + + xgene_enet_napi_add(pdev); + + xgene_enet_cle_bypass(priv, QMTM_QUEUE_ID(pdev->sdev->qmtm_ip, + pdev->qm_queues. + default_rx_qid), + pdev->qm_queues.default_rx_fp_pbn - 0x20); + + /* Default MAC initialization */ + xgene_enet_mac_init(priv, ndev->dev_addr, SPEED_1000, + HW_MTU(ndev->mtu), priv->crc); + + /* Setup MDIO bus */ + mdio_bus = mdiobus_alloc(); + if (!mdio_bus) { + netdev_err(ndev, "Not able to allocate memory for MDIO bus\n"); + rc = -ENOMEM; + goto out; + } + + pdev->mdio_bus = mdio_bus; + mdio_bus->name = "APM Ethernet MII Bus"; + mdio_bus->read = xgene_enet_mdio_read; + mdio_bus->write = xgene_enet_mdio_write; + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x", priv->phy_addr); + mdio_bus->priv = pdev; + mdio_bus->parent = &ndev->dev; + mdio_bus->phy_mask = ~(1 << priv->phy_addr); + rc = mdiobus_register(mdio_bus); + if (rc) { + netdev_err(ndev, "Failed to register MDIO bus(%d)!\n", rc); + return rc; + } + + rc = xgene_enet_mdio_probe(ndev); + xgene_enet_register_irq(ndev); + +out: + return rc; +} + +static int xgene_enet_probe(struct platform_device *plat_dev) +{ + struct net_device *ndev; + struct xgene_enet_pdev *pdev; + struct device *dev; + struct xgene_enet_priv *priv; + u32 num_tx_queues, num_rx_queues; + int rc; + + dev = &plat_dev->dev; + num_tx_queues = MAX_TX_QUEUES; + num_rx_queues = MAX_RX_QUEUES; + + ndev = alloc_etherdev_mqs(sizeof(struct xgene_enet_pdev), + num_tx_queues, num_rx_queues); + + if (!ndev) { + dev_err(dev, "Not able to allocate memory for netdev\n"); + rc = -ENOMEM; + goto out; + } + + pdev = (struct xgene_enet_pdev *)netdev_priv(ndev); + priv = &pdev->priv; + pdev->ndev = ndev; + pdev->num_tx_queues = num_tx_queues; + pdev->num_rx_queues = num_rx_queues; + pdev->plat_dev = plat_dev; + pdev->node = plat_dev->dev.of_node; + SET_NETDEV_DEV(ndev, &plat_dev->dev); + dev_set_drvdata(&plat_dev->dev, pdev); + + xgene_enet_get_resources(pdev); + + xgene_enet_init_priv(priv); + rc = xgene_enet_init_hw(pdev); + +out: + return rc; +} + +static int xgene_enet_remove(struct platform_device *plat_dev) +{ + struct xgene_enet_pdev *pdev; + struct xgene_enet_priv *priv; + struct net_device *ndev; + u32 qindex; + u8 qmtm_ip; + + pdev = platform_get_drvdata(plat_dev); + qmtm_ip = pdev->sdev->qmtm_ip; + ndev = pdev->ndev; + priv = &pdev->priv; + + /* Stop any traffic and disable MAC */ + xgene_enet_mac_rx_state(priv, 0); + xgene_enet_mac_tx_state(priv, 0); + + if (netif_running(ndev)) { + netif_device_detach(ndev); + netif_stop_queue(ndev); + xgene_enet_napi_disable(pdev); + } + + xgene_enet_napi_del(pdev); + xgene_enet_mdio_remove(ndev); + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) { + if (pdev->qm_queues.rx_fp[qindex].qid > 0) + xgene_enet_deinit_fp(pdev->rx_skb_pool[qindex], + pdev->qm_queues.rx_fp[qindex].qid); + } + + xgene_enet_delete_queue(pdev); + + for (qindex = 0; qindex < pdev->num_rx_queues; qindex++) { + kfree(pdev->rx_skb_pool[qindex]->skb); + kfree(pdev->rx_skb_pool[qindex]); + kfree(pdev->rx[qindex]); + } + for (qindex = 0; qindex < pdev->num_tx_queues; qindex++) { + kfree(pdev->tx[qindex]->msg8); + kfree(pdev->tx[qindex]); + } + + unregister_netdev(ndev); + xgene_enet_port_shutdown(priv); + + free_netdev(ndev); + + return 0; +} + +static struct of_device_id xgene_enet_match[] = { + { + .compatible = "apm,xgene-enet", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, xgene_enet_match); + +static struct platform_driver xgene_enet_driver = { + .driver = { + .name = XGENE_ENET_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = xgene_enet_match, + }, + .probe = xgene_enet_probe, + .remove = xgene_enet_remove, +}; + +static int __init xgene_enet_init(void) +{ + if (!platform_driver_register(&xgene_enet_driver)) + pr_info("%s v%s loaded\n", XGENE_ENET_DRIVER_DESC, + XGENE_ENET_DRIVER_VERSION); + + return 0; +} + +static void __exit xgene_enet_exit(void) +{ + platform_driver_unregister(&xgene_enet_driver); + pr_info("%s v%s unloaded\n", XGENE_ENET_DRIVER_DESC, + XGENE_ENET_DRIVER_VERSION); +} + +module_init(xgene_enet_init); +module_exit(xgene_enet_exit); + +MODULE_DESCRIPTION(XGENE_ENET_DRIVER_DESC); +MODULE_VERSION(XGENE_ENET_DRIVER_VERSION); +MODULE_AUTHOR("Keyur Chudgar "); +MODULE_LICENSE("GPL"); --- linux-3.13.0.orig/drivers/net/ethernet/intel/e100.c +++ linux-3.13.0/drivers/net/ethernet/intel/e100.c @@ -3034,7 +3034,7 @@ *enable_wake = false; } - pci_disable_device(pdev); + pci_clear_master(pdev); } static int __e100_power_off(struct pci_dev *pdev, bool wake) --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/core.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/core.c @@ -46,10 +46,20 @@ "Firmware callback routine entered!\n"); complete(&rtlpriv->firmware_loading_complete); if (!firmware) { + if (rtlpriv->cfg->alt_fw_name) { + err = request_firmware(&firmware, + rtlpriv->cfg->alt_fw_name, + rtlpriv->io.dev); + pr_info("Loading alternative firmware %s\n", + rtlpriv->cfg->alt_fw_name); + if (!err) + goto found_alt; + } pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name); rtlpriv->max_fw_size = 0; return; } +found_alt: if (firmware->size > rtlpriv->max_fw_size) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Firmware is too big!\n"); @@ -184,6 +194,7 @@ rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS]); } + mac->link_state = MAC80211_LINKED; break; case NL80211_IFTYPE_ADHOC: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/stats.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/stats.c @@ -176,6 +176,7 @@ struct rtl_sta_info *drv_priv = NULL; struct ieee80211_sta *sta = NULL; long undec_sm_pwdb; + long undec_sm_cck; rcu_read_lock(); if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) @@ -185,12 +186,16 @@ if (sta) { drv_priv = (struct rtl_sta_info *) sta->drv_priv; undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb; + undec_sm_cck = drv_priv->rssi_stat.undec_sm_cck; } else { undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; + undec_sm_cck = rtlpriv->dm.undec_sm_cck; } if (undec_sm_pwdb < 0) undec_sm_pwdb = pstatus->rx_pwdb_all; + if (undec_sm_cck < 0) + undec_sm_cck = pstatus->rx_pwdb_all; if (pstatus->rx_pwdb_all > (u32) undec_sm_pwdb) { undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) + @@ -200,6 +205,15 @@ undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); } + if (pstatus->rx_pwdb_all > (u32) undec_sm_cck) { + undec_sm_cck = (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undec_sm_cck = undec_sm_cck + 1; + } else { + undec_sm_pwdb = (((undec_sm_cck) * (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } if (sta) { drv_priv->rssi_stat.undec_sm_pwdb = undec_sm_pwdb; --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/usb.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/usb.c @@ -483,6 +483,8 @@ if (unicast) rtlpriv->link_info.num_rx_inperiod++; } + /* static bcn for roaming */ + rtl_beacon_statistic(hw, skb); } } @@ -553,7 +555,7 @@ } } -#define __RX_SKB_MAX_QUEUED 32 +#define __RX_SKB_MAX_QUEUED 64 static void _rtl_rx_work(unsigned long param) { --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/wifi.h +++ linux-3.13.0/drivers/net/wireless/rtlwifi/wifi.h @@ -1033,6 +1033,7 @@ struct rssi_sta { long undec_sm_pwdb; + long undec_sm_cck; }; struct rtl_tid_data { @@ -1323,8 +1324,10 @@ struct rtl_dm { /*PHY status for Dynamic Management */ long entry_min_undec_sm_pwdb; + long undec_sm_cck; long undec_sm_pwdb; /*out dm */ long entry_max_undec_sm_pwdb; + s32 ofdm_pkt_cnt; bool dm_initialgain_enable; bool dynamic_txpower_enable; bool current_turbo_edca; @@ -1339,6 +1342,7 @@ bool inform_fw_driverctrldm; bool current_mrc_switch; u8 txpowercount; + u8 powerindex_backup[6]; u8 thermalvalue_rxgain; u8 thermalvalue_iqk; @@ -1350,7 +1354,9 @@ bool done_txpower; u8 dynamic_txhighpower_lvl; /*Tx high power level */ u8 dm_flag; /*Indicate each dynamic mechanism's status. */ + u8 dm_flag_tmp; u8 dm_type; + u8 dm_rssi_sel; u8 txpower_track_control; bool interrupt_migration; bool disable_tx_int; @@ -1804,6 +1810,7 @@ bool write_readback; char *name; char *fw_name; + char *alt_fw_name; struct rtl_hal_ops *ops; struct rtl_mod_params *mod_params; struct rtl_hal_usbint_cfg *usb_interface_cfg; @@ -1948,6 +1955,7 @@ u8 pre_ccastate; u8 cur_ccasate; u8 large_fa_hit; + u8 dig_dynamic_min; u8 forbidden_igi; u8 dig_state; u8 dig_highpwrstate; @@ -2028,22 +2036,15 @@ struct dig_t dm_digtable; struct ps_t dm_pstable; - /* section shared by individual drivers */ - union { - struct { /* data buffer pointer for USB reads */ - __le32 *usb_data; - int usb_data_index; - bool initialized; - }; - struct { /* section for 8723ae */ - bool reg_init; /* true if regs saved */ - u32 reg_874; - u32 reg_c70; - u32 reg_85c; - u32 reg_a74; - bool bt_operation_on; - }; - }; + u32 reg_874; + u32 reg_c70; + u32 reg_85c; + u32 reg_a74; + bool reg_init; /* true if regs saved */ + bool bt_operation_on; + __le32 *usb_data; + int usb_data_index; + bool initialized; bool enter_ps; /* true when entering PS */ u8 rate_mask[5]; --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/base.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/base.c @@ -1437,7 +1437,8 @@ /* if we can't recv beacon for 6s, we should * reconnect this AP */ - if (rtlpriv->link_info.roam_times >= 3) { + if ((rtlpriv->link_info.roam_times >= 3) && + !is_zero_ether_addr(rtlpriv->mac80211.bssid)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AP off, try to reconnect now\n"); rtlpriv->link_info.roam_times = 0; --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/ps.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/ps.c @@ -48,7 +48,7 @@ /*<2> Enable Adapter */ if (rtlpriv->cfg->ops->hw_init(hw)) - return 1; + return false; RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); /*<3> Enable Interrupt */ --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -91,6 +91,17 @@ #define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 #define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 +#define DYNAMIC_FUNC_DISABLE 0x0 +#define DYNAMIC_FUNC_DIG BIT(0) +#define DYNAMIC_FUNC_HP BIT(1) +#define DYNAMIC_FUNC_SS BIT(2) /*Tx Power Tracking*/ +#define DYNAMIC_FUNC_BT BIT(3) +#define DYNAMIC_FUNC_ANT_DIV BIT(4) + +#define RSSI_CCK 0 +#define RSSI_OFDM 1 +#define RSSI_DEFAULT 2 + struct swat_t { u8 failure_cnt; u8 try_flag; @@ -167,5 +178,8 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); +void dm_savepowerindex(struct ieee80211_hw *hw); +void dm_writepowerindex(struct ieee80211_hw *hw, u8 value); +void dm_restorepowerindex(struct ieee80211_hw *hw); #endif --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -158,6 +158,42 @@ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} }; +static u32 power_index_reg[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + +void dm_restorepowerindex(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index; + + for (index = 0; index < 6; index++) + rtl_write_byte(rtlpriv, power_index_reg[index], + rtlpriv->dm.powerindex_backup[index]); +} +EXPORT_SYMBOL_GPL(dm_restorepowerindex); + +void dm_writepowerindex(struct ieee80211_hw *hw, u8 value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index; + + for (index = 0; index < 6; index++) + rtl_write_byte(rtlpriv, power_index_reg[index], value); +} +EXPORT_SYMBOL_GPL(dm_writepowerindex); + +void dm_savepowerindex(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index; + u8 tmp; + + for (index = 0; index < 6; index++) { + tmp = rtl_read_byte(rtlpriv, power_index_reg[index]); + rtlpriv->dm.powerindex_backup[index] = tmp; + } +} +EXPORT_SYMBOL_GPL(dm_savepowerindex); + static void rtl92c_dm_diginit(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -180,7 +216,12 @@ dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; - dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi; + + dm_digtable->forbidden_igi = DM_DIG_MIN; + dm_digtable->large_fa_hit = 0; + dm_digtable->recover_cnt = 0; + dm_digtable->dig_dynamic_min = 0x25; } static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) @@ -206,7 +247,9 @@ rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb; } - return (u8) rssi_val_min; + if (rssi_val_min > 100) + rssi_val_min = 100; + return (u8)rssi_val_min; } static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) @@ -224,9 +267,17 @@ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); + + ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD); + falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff); + falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16); + falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + - falsealm_cnt->cnt_rate_illegal + - falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail; + falsealm_cnt->cnt_rate_illegal + + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail + + falsealm_cnt->cnt_fast_fsync_fail + + falsealm_cnt->cnt_sb_search_fail; rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1); ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0); @@ -271,12 +322,14 @@ value_igi++; else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2) value_igi += 2; + if (value_igi > DM_DIG_FA_UPPER) value_igi = DM_DIG_FA_UPPER; else if (value_igi < DM_DIG_FA_LOWER) value_igi = DM_DIG_FA_LOWER; + if (rtlpriv->falsealm_cnt.cnt_all > 10000) - value_igi = 0x32; + value_igi = DM_DIG_FA_UPPER; dm_digtable->cur_igvalue = value_igi; rtl92c_dm_write_dig(hw); @@ -286,32 +339,80 @@ { struct rtl_priv *rtlpriv = rtl_priv(hw); struct dig_t *digtable = &rtlpriv->dm_digtable; + u32 isbt; - if (rtlpriv->falsealm_cnt.cnt_all > digtable->fa_highthresh) { - if ((digtable->back_val - 2) < digtable->back_range_min) - digtable->back_val = digtable->back_range_min; - else - digtable->back_val -= 2; - } else if (rtlpriv->falsealm_cnt.cnt_all < digtable->fa_lowthresh) { - if ((digtable->back_val + 2) > digtable->back_range_max) - digtable->back_val = digtable->back_range_max; - else - digtable->back_val += 2; + /* modify DIG lower bound, deal with abnorally large false alarm */ + if (rtlpriv->falsealm_cnt.cnt_all > 10000) { + digtable->large_fa_hit++; + if (digtable->forbidden_igi < digtable->cur_igvalue) { + digtable->forbidden_igi = digtable->cur_igvalue; + digtable->large_fa_hit = 1; + } + + if (digtable->large_fa_hit >= 3) { + if ((digtable->forbidden_igi + 1) > + digtable->rx_gain_max) + digtable->rx_gain_min = digtable->rx_gain_max; + else + digtable->rx_gain_min = (digtable->forbidden_igi + 1); + digtable->recover_cnt = 3600; /* 3600=2hr */ + } + } else { + /* Recovery mechanism for IGI lower bound */ + if (digtable->recover_cnt != 0) { + digtable->recover_cnt--; + } else { + if (digtable->large_fa_hit == 0) { + if ((digtable->forbidden_igi-1) < DM_DIG_MIN) { + digtable->forbidden_igi = DM_DIG_MIN; + digtable->rx_gain_min = DM_DIG_MIN; + } else { + digtable->forbidden_igi--; + digtable->rx_gain_min = digtable->forbidden_igi + 1; + } + } else if (digtable->large_fa_hit == 3) { + digtable->large_fa_hit = 0; + } + } } + if (rtlpriv->falsealm_cnt.cnt_all < 250) { + isbt = rtl_read_byte(rtlpriv, 0x4fd) & 0x01; - if ((digtable->rssi_val_min + 10 - digtable->back_val) > - digtable->rx_gain_max) + if (!isbt) { + if (rtlpriv->falsealm_cnt.cnt_all > + digtable->fa_lowthresh) { + if ((digtable->back_val - 2) < + digtable->back_range_min) + digtable->back_val = digtable->back_range_min; + else + digtable->back_val -= 2; + } else if (rtlpriv->falsealm_cnt.cnt_all < + digtable->fa_lowthresh) { + if ((digtable->back_val + 2) > + digtable->back_range_max) + digtable->back_val = digtable->back_range_max; + else + digtable->back_val += 2; + } + } else { + digtable->back_val = DM_DIG_BACKOFF_DEFAULT; + } + } else { + /* Adjust initial gain by false alarm */ + if (rtlpriv->falsealm_cnt.cnt_all > 1000) + digtable->cur_igvalue = digtable->pre_igvalue + 2; + else if (rtlpriv->falsealm_cnt.cnt_all > 750) + digtable->cur_igvalue = digtable->pre_igvalue + 1; + else if (rtlpriv->falsealm_cnt.cnt_all < 500) + digtable->cur_igvalue = digtable->pre_igvalue - 1; + } + + /* Check initial gain by upper/lower bound */ + if (digtable->cur_igvalue > digtable->rx_gain_max) digtable->cur_igvalue = digtable->rx_gain_max; - else if ((digtable->rssi_val_min + 10 - - digtable->back_val) < digtable->rx_gain_min) - digtable->cur_igvalue = digtable->rx_gain_min; - else - digtable->cur_igvalue = digtable->rssi_val_min + 10 - - digtable->back_val; - RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, - "rssi_val_min = %x back_val %x\n", - digtable->rssi_val_min, digtable->back_val); + if (digtable->cur_igvalue < digtable->rx_gain_min) + digtable->cur_igvalue = digtable->rx_gain_min; rtl92c_dm_write_dig(hw); } @@ -329,7 +430,7 @@ multi_sta = true; if (!multi_sta || - dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) { + dm_digtable->cursta_cstate == DIG_STA_DISCONNECT) { initialized = false; dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; return; @@ -375,7 +476,6 @@ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "presta_cstate = %x, cursta_cstate = %x\n", dm_digtable->presta_cstate, dm_digtable->cursta_cstate); - if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate || dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT || dm_digtable->cursta_cstate == DIG_STA_CONNECT) { @@ -383,6 +483,8 @@ if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) { dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); + if (dm_digtable->rssi_val_min > 100) + dm_digtable->rssi_val_min = 100; rtl92c_dm_ctrl_initgain_by_rssi(hw); } } else { @@ -398,11 +500,12 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct dig_t *dm_digtable = &rtlpriv->dm_digtable; if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) { dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); + if (dm_digtable->rssi_val_min > 100) + dm_digtable->rssi_val_min = 100; if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { if (dm_digtable->rssi_val_min <= 25) @@ -424,48 +527,14 @@ } if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { - if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { - if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) - dm_digtable->cur_cck_fa_state = - CCK_FA_STAGE_High; - else - dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_Low; - - if (dm_digtable->pre_cck_fa_state != - dm_digtable->cur_cck_fa_state) { - if (dm_digtable->cur_cck_fa_state == - CCK_FA_STAGE_Low) - rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, - 0x83); - else - rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, - 0xcd); - - dm_digtable->pre_cck_fa_state = - dm_digtable->cur_cck_fa_state; - } - - rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40); - - if (IS_92C_SERIAL(rtlhal->version)) - rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, - MASKBYTE2, 0xd7); - } else { + if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) || + (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_MAX)) + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83); + else rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); - rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47); - if (IS_92C_SERIAL(rtlhal->version)) - rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, - MASKBYTE2, 0xd3); - } dm_digtable->pre_cck_pd_state = dm_digtable->cur_cck_pd_state; } - - RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "CCKPDStage=%x\n", - dm_digtable->cur_cck_pd_state); - - RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "is92C=%x\n", - IS_92C_SERIAL(rtlhal->version)); } static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) @@ -482,6 +551,8 @@ else dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; + dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; + rtl92c_dm_initial_gain_sta(hw); rtl92c_dm_initial_gain_multi_sta(hw); rtl92c_dm_cck_packet_detection_thresh(hw); @@ -493,23 +564,26 @@ static void rtl92c_dm_dig(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; if (rtlpriv->dm.dm_initialgain_enable == false) return; - if (dm_digtable->dig_enable_flag == false) + if (!rtlpriv->dm.dm_flag & DYNAMIC_FUNC_DIG) return; rtl92c_dm_ctrl_initgain_by_twoport(hw); - } static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - rtlpriv->dm.dynamic_txpower_enable = false; - + if (rtlpriv->rtlhal.interface == INTF_USB && + rtlpriv->rtlhal.board_type & 0x1) { + dm_savepowerindex(hw); + rtlpriv->dm.dynamic_txpower_enable = true; + } else { + rtlpriv->dm.dynamic_txpower_enable = false; + } rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; } @@ -524,9 +598,14 @@ dm_digtable->cur_igvalue, dm_digtable->pre_igvalue, dm_digtable->back_val); - dm_digtable->cur_igvalue += 2; - if (dm_digtable->cur_igvalue > 0x3f) - dm_digtable->cur_igvalue = 0x3f; + if (rtlpriv->rtlhal.interface == INTF_USB && + !dm_digtable->dig_enable_flag) { + dm_digtable->pre_igvalue = 0x17; + return; + } + dm_digtable->cur_igvalue -= 1; + if (dm_digtable->cur_igvalue < DM_DIG_MIN) + dm_digtable->cur_igvalue = DM_DIG_MIN; if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) { rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, @@ -536,11 +615,47 @@ dm_digtable->pre_igvalue = dm_digtable->cur_igvalue; } + RT_TRACE(rtlpriv, COMP_DIG, DBG_WARNING, + "dig values 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + dm_digtable->cur_igvalue, dm_digtable->pre_igvalue, + dm_digtable->rssi_val_min, dm_digtable->back_val, + dm_digtable->rx_gain_max, dm_digtable->rx_gain_min, + dm_digtable->large_fa_hit, dm_digtable->forbidden_igi); } EXPORT_SYMBOL(rtl92c_dm_write_dig); static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff; + + if (mac->link_state != MAC80211_LINKED) + return; + + if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_AP) { + /* TODO: Handle ADHOC and AP Mode */ + } + + if (tmpentry_max_pwdb != 0) + rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb; + else + rtlpriv->dm.entry_max_undec_sm_pwdb = 0; + + if (tmpentry_min_pwdb != 0xff) + rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb; + else + rtlpriv->dm.entry_min_undec_sm_pwdb = 0; + +/* TODO: + * if (mac->opmode == NL80211_IFTYPE_STATION) { + * if (rtlpriv->rtlhal.fw_ready) { + * u32 param = (u32)(rtlpriv->dm.undec_sm_pwdb << 16); + * rtl8192c_set_rssi_cmd(hw, param); + * } + * } + */ } void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw) @@ -750,6 +865,7 @@ rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; rtlpriv->dm.cck_index = cck_index_old; } + /* Handle USB High PA boards */ delta = (thermalvalue > rtlpriv->dm.thermalvalue) ? (thermalvalue - rtlpriv->dm.thermalvalue) : @@ -1140,22 +1256,22 @@ { struct rtl_priv *rtlpriv = rtl_priv(hw); struct ps_t *dm_pstable = &rtlpriv->dm_pstable; - static u8 initialize; - static u32 reg_874, reg_c70, reg_85c, reg_a74; - if (initialize == 0) { - reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, - MASKDWORD) & 0x1CC000) >> 14; + if (!rtlpriv->reg_init) { + rtlpriv->reg_874 = (rtl_get_bbreg(hw, + RFPGA0_XCD_RFINTERFACESW, + MASKDWORD) & 0x1CC000) >> 14; - reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1, - MASKDWORD) & BIT(3)) >> 3; + rtlpriv->reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1, + MASKDWORD) & BIT(3)) >> 3; - reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, - MASKDWORD) & 0xFF000000) >> 24; + rtlpriv->reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, + MASKDWORD) & 0xFF000000) >> 24; - reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12; + rtlpriv->reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & + 0xF000) >> 12; - initialize = 1; + rtlpriv->reg_init = true; } if (!bforce_in_normal) { @@ -1192,12 +1308,12 @@ rtl_set_bbreg(hw, 0x818, BIT(28), 0x1); } else { rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, - 0x1CC000, reg_874); + 0x1CC000, rtlpriv->reg_874); rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), - reg_c70); + rtlpriv->reg_c70); rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000, - reg_85c); - rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74); + rtlpriv->reg_85c); + rtl_set_bbreg(hw, 0xa74, 0xF000, rtlpriv->reg_a74); rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); } @@ -1213,6 +1329,7 @@ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + /* Determine the minimum RSSI */ if (((mac->link_state == MAC80211_NOLINK)) && (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) { dm_pstable->rssi_val_min = 0; @@ -1241,6 +1358,7 @@ dm_pstable->rssi_val_min); } + /* Power Saving for 92C */ if (IS_92C_SERIAL(rtlhal->version)) ;/* rtl92c_dm_1r_cca(hw); */ else @@ -1252,12 +1370,23 @@ struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtlpriv->dm.dm_flag = DYNAMIC_FUNC_DISABLE | DYNAMIC_FUNC_DIG; + rtlpriv->dm.undec_sm_pwdb = -1; + rtlpriv->dm.undec_sm_cck = -1; + rtlpriv->dm.dm_initialgain_enable = true; rtl92c_dm_diginit(hw); + + rtlpriv->dm.dm_flag |= HAL_DM_HIPWR_DISABLE; rtl92c_dm_init_dynamic_txpower(hw); + rtl92c_dm_init_edca_turbo(hw); rtl92c_dm_init_rate_adaptive_mask(hw); + rtlpriv->dm.dm_flag |= DYNAMIC_FUNC_SS; rtl92c_dm_initialize_txpower_tracking(hw); rtl92c_dm_init_dynamic_bb_powersaving(hw); + + rtlpriv->dm.ofdm_pkt_cnt = 0; + rtlpriv->dm.dm_rssi_sel = RSSI_DEFAULT; } EXPORT_SYMBOL(rtl92c_dm_init); @@ -1308,7 +1437,7 @@ } if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { - rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL2; RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); } else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && @@ -1328,8 +1457,16 @@ "PHY_SetTxPowerLevel8192S() Channel = %d\n", rtlphy->current_channel); rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_NORMAL) + dm_restorepowerindex(hw); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL1) + dm_writepowerindex(hw, 0x14); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL2) + dm_writepowerindex(hw, 0x10); } - rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; } @@ -1400,12 +1537,6 @@ else curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW); - /* Set Tx Power according to BT status. */ - if (undec_sm_pwdb >= 30) - curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW; - else if (undec_sm_pwdb < 25) - curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW); - /* Check BT state related to BT_Idle in B/G mode. */ if (undec_sm_pwdb < 15) curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW; --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -937,14 +937,26 @@ bool is92c; int err; u8 tmp_u1b; + unsigned long flags; rtlpci->being_init_adapter = true; + + /* Since this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); + rtlpriv->intf_ops->disable_aspm(hw); rtstatus = _rtl92ce_init_mac(hw); if (!rtstatus) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); err = 1; - return err; + goto exit; } err = rtl92c_download_fw(hw); @@ -952,7 +964,7 @@ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); err = 1; - return err; + goto exit; } rtlhal->last_hmeboxnum = 0; @@ -1032,6 +1044,8 @@ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); } rtl92c_dm_init(hw); +exit: + local_irq_restore(flags); rtlpci->being_init_adapter = false; return err; } --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c @@ -1078,7 +1078,7 @@ rtldm->swing_flag_ofdm = true; } - if (rtldm->swing_idx_cck != rtldm->swing_idx_cck) { + if (rtldm->swing_idx_cck_cur != rtldm->swing_idx_cck) { rtldm->swing_idx_cck_cur = rtldm->swing_idx_cck; rtldm->swing_flag_cck = true; } --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c @@ -101,6 +101,15 @@ "PHY_SetTxPowerLevel8192S() Channel = %d\n", rtlphy->current_channel); rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_NORMAL) + dm_restorepowerindex(hw); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL1) + dm_writepowerindex(hw, 0x14); + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL2) + dm_writepowerindex(hw, 0x10); } rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -50,6 +50,9 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n USB wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) { @@ -69,14 +72,21 @@ "Can't alloc buffer for fw\n"); return 1; } - + if (IS_VENDOR_UMC_A_CUT(rtlpriv->rtlhal.version) && + !IS_92C_SERIAL(rtlpriv->rtlhal.version)) { + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_A.bin"; + } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlpriv->rtlhal.version)) { + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_B.bin"; + } else { + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_TMSC.bin"; + } + /* provide name of alternative file */ + rtlpriv->cfg->alt_fw_name = "rtlwifi/rtl8192cufw.bin"; pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name); rtlpriv->max_fw_size = 0x4000; err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); - - return err; } @@ -307,6 +317,7 @@ {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ + {RTL_USB_DEVICE(0x0df6, 0x0077, rtl92cu_hal_cfg)}, /*Sitecom-WLA2100V2*/ {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/ /* HP - Lite-On ,8188CUS Slim Combo */ --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -85,17 +85,15 @@ if (mac->act_scanning) { tx_agc[RF90_PATH_A] = 0x3f3f3f3f; tx_agc[RF90_PATH_B] = 0x3f3f3f3f; - if (turbo_scanoff) { - for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { - tx_agc[idx1] = ppowerlevel[idx1] | - (ppowerlevel[idx1] << 8) | - (ppowerlevel[idx1] << 16) | - (ppowerlevel[idx1] << 24); - if (rtlhal->interface == INTF_USB) { - if (tx_agc[idx1] > 0x20 && - rtlefuse->external_pa) - tx_agc[idx1] = 0x20; - } + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + if (rtlhal->interface == INTF_USB) { + if (tx_agc[idx1] > 0x20 && + rtlefuse->external_pa) + tx_agc[idx1] = 0x20; } } } else { @@ -107,7 +105,7 @@ TXHIGHPWRLEVEL_LEVEL2) { tx_agc[RF90_PATH_A] = 0x00000000; tx_agc[RF90_PATH_B] = 0x00000000; - } else{ + } else { for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { tx_agc[idx1] = ppowerlevel[idx1] | (ppowerlevel[idx1] << 8) | @@ -373,7 +371,12 @@ regoffset == RTXAGC_B_MCS07_MCS04) regoffset = 0xc98; for (i = 0; i < 3; i++) { - writeVal = (writeVal > 6) ? (writeVal - 6) : 0; + if (i != 2) + writeVal = (writeVal > 8) ? + (writeVal - 8) : 0; + else + writeVal = (writeVal > 6) ? + (writeVal - 6) : 0; rtl_write_byte(rtlpriv, (u32)(regoffset + i), (u8)writeVal); } --- linux-3.13.0.orig/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h +++ linux-3.13.0/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h @@ -30,3 +30,6 @@ #include "../rtl8192ce/dm.h" void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw); +void dm_savepowerindex(struct ieee80211_hw *hw); +void dm_writepowerindex(struct ieee80211_hw *hw, u8 value); +void dm_restorepowerindex(struct ieee80211_hw *hw); --- linux-3.13.0.orig/drivers/net/wireless/b43/b43.h +++ linux-3.13.0/drivers/net/wireless/b43/b43.h @@ -731,8 +731,6 @@ struct b43_request_fw_context { /* The device we are requesting the fw for. */ struct b43_wldev *dev; - /* a completion event structure needed if this call is asynchronous */ - struct completion fw_load_complete; /* a pointer to the firmware object */ const struct firmware *blob; /* The type of firmware to request. */ @@ -809,6 +807,8 @@ struct b43_wldev { struct b43_bus_dev *dev; struct b43_wl *wl; + /* a completion event structure needed if this call is asynchronous */ + struct completion fw_load_complete; /* The device initialization status. * Use b43_status() to query. */ --- linux-3.13.0.orig/drivers/net/wireless/b43/main.c +++ linux-3.13.0/drivers/net/wireless/b43/main.c @@ -2070,6 +2070,7 @@ static void b43_release_firmware(struct b43_wldev *dev) { + complete(&dev->fw_load_complete); b43_do_release_fw(&dev->fw.ucode); b43_do_release_fw(&dev->fw.pcm); b43_do_release_fw(&dev->fw.initvals); @@ -2095,7 +2096,7 @@ struct b43_request_fw_context *ctx = context; ctx->blob = firmware; - complete(&ctx->fw_load_complete); + complete(&ctx->dev->fw_load_complete); } int b43_do_request_fw(struct b43_request_fw_context *ctx, @@ -2142,7 +2143,7 @@ } if (async) { /* do this part asynchronously */ - init_completion(&ctx->fw_load_complete); + init_completion(&ctx->dev->fw_load_complete); err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, ctx->dev->dev->dev, GFP_KERNEL, ctx, b43_fw_cb); @@ -2150,12 +2151,11 @@ pr_err("Unable to load firmware\n"); return err; } - /* stall here until fw ready */ - wait_for_completion(&ctx->fw_load_complete); + wait_for_completion(&ctx->dev->fw_load_complete); if (ctx->blob) goto fw_ready; /* On some ARM systems, the async request will fail, but the next sync - * request works. For this reason, we dall through here + * request works. For this reason, we fall through here */ } err = request_firmware(&ctx->blob, ctx->fwname, @@ -2424,6 +2424,7 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl); static void b43_one_core_detach(struct b43_bus_dev *dev); +static int b43_rng_init(struct b43_wl *wl); static void b43_request_firmware(struct work_struct *work) { @@ -2475,6 +2476,10 @@ goto err_one_core_detach; wl->hw_registred = true; b43_leds_register(wl->current_dev); + + /* Register HW RNG driver */ + b43_rng_init(wl); + goto out; err_one_core_detach: @@ -4636,9 +4641,6 @@ if (!dev || b43_status(dev) != B43_STAT_INITIALIZED) return; - /* Unregister HW RNG driver */ - b43_rng_exit(dev->wl); - b43_set_status(dev, B43_STAT_UNINIT); /* Stop the microcode PSM. */ @@ -4795,9 +4797,6 @@ b43_set_status(dev, B43_STAT_INITIALIZED); - /* Register HW RNG driver */ - b43_rng_init(dev->wl); - out: return err; @@ -5464,6 +5463,9 @@ b43_one_core_detach(wldev->dev); + /* Unregister HW RNG driver */ + b43_rng_exit(wl); + b43_leds_unregister(wl); ieee80211_free_hw(wl->hw); @@ -5541,6 +5543,9 @@ b43_one_core_detach(dev); + /* Unregister HW RNG driver */ + b43_rng_exit(wl); + if (list_empty(&wl->devlist)) { b43_leds_unregister(wl); /* Last core on the chip unregistered. --- linux-3.13.0.orig/drivers/net/wireless/b43/xmit.c +++ linux-3.13.0/drivers/net/wireless/b43/xmit.c @@ -821,10 +821,10 @@ * channel number in b43. */ if (chanstat & B43_RX_CHAN_5GHZ) { status.band = IEEE80211_BAND_5GHZ; - status.freq = b43_freq_to_channel_5ghz(chanid); + status.freq = b43_channel_to_freq_5ghz(chanid); } else { status.band = IEEE80211_BAND_2GHZ; - status.freq = b43_freq_to_channel_2ghz(chanid); + status.freq = b43_channel_to_freq_2ghz(chanid); } break; default: --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/iwl-prph.h +++ linux-3.13.0/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -274,4 +274,8 @@ /*********************** END TX SCHEDULER *************************************/ +/* Oscillator clock */ +#define OSC_CLK (0xa04068) +#define OSC_CLK_FORCE_CONTROL (0x8) + #endif /* __iwl_prph_h__ */ --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/iwl-drv.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1247,7 +1247,7 @@ MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); MODULE_PARM_DESC(11n_disable, - "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); + "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX"); module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)"); --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -182,6 +182,11 @@ for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) { ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); + + if (ch_idx >= NUM_2GHZ_CHANNELS && + !data->sku_cap_band_52GHz_enable) + ch_flags &= ~NVM_CHANNEL_VALID; + if (!(ch_flags & NVM_CHANNEL_VALID)) { IWL_DEBUG_EEPROM(dev, "Ch. %d Flags %x [%sGHz] - No traffic\n", --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ linux-3.13.0/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -79,9 +79,12 @@ IWL_POWER_NUM }; -#define IWL_DISABLE_HT_ALL BIT(0) -#define IWL_DISABLE_HT_TXAGG BIT(1) -#define IWL_DISABLE_HT_RXAGG BIT(2) +enum iwl_disable_11n { + IWL_DISABLE_HT_ALL = BIT(0), + IWL_DISABLE_HT_TXAGG = BIT(1), + IWL_DISABLE_HT_RXAGG = BIT(2), + IWL_ENABLE_HT_TXAGG = BIT(3), +}; /** * struct iwl_mod_params @@ -90,7 +93,7 @@ * * @sw_crypto: using hardware encryption, default = 0 * @disable_11n: disable 11n capabilities, default = 0, - * use IWL_DISABLE_HT_* constants + * use IWL_[DIS,EN]ABLE_HT_* constants * @amsdu_size_8K: enable 8K amsdu size, default = 0 * @restart_fw: restart firmware, default = 1 * @wd_disable: enable stuck queue check, default = 0 --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -68,6 +68,7 @@ #include #include #include +#include #include "iwl-op-mode.h" #include "iwl-trans.h" @@ -151,7 +152,7 @@ IWL_POWER_SCHEME_LP }; -#define IWL_CONN_MAX_LISTEN_INTERVAL 70 +#define IWL_CONN_MAX_LISTEN_INTERVAL 10 #define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ @@ -517,6 +518,9 @@ /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; + void *fw_error_dump; + void *fw_error_sram; + u32 fw_error_sram_len; struct led_classdev led; @@ -600,7 +604,10 @@ struct ieee80211_tx_rate *r); u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); -void iwl_mvm_dump_sram(struct iwl_mvm *mvm); +#ifdef CONFIG_IWLWIFI_DEBUGFS +bool iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm); +#endif u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/scan.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -325,7 +325,8 @@ iwl_mvm_scan_fill_ssids(cmd, req, basic_ssid ? 1 : 0); - cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL); + cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | + TX_CMD_FLG_BT_DIS); cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); cmd->tx_cmd.rate_n_flags = --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/ops.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -61,6 +61,7 @@ * *****************************************************************************/ #include +#include #include #include "iwl-notif-wait.h" @@ -78,6 +79,7 @@ #include "iwl-prph.h" #include "rs.h" #include "fw-api-scan.h" +#include "fw-error-dump.h" #include "time-event.h" /* @@ -470,6 +472,7 @@ out_unregister: ieee80211_unregister_hw(mvm->hw); + iwl_mvm_leds_exit(mvm); out_free: iwl_phy_db_free(mvm->phy_db); kfree(mvm->scan_cmd); @@ -491,6 +494,8 @@ ieee80211_unregister_hw(mvm->hw); kfree(mvm->scan_cmd); + vfree(mvm->fw_error_dump); + kfree(mvm->fw_error_sram); #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) kfree(mvm->d3_resume_sram); @@ -751,13 +756,66 @@ } } +#ifdef CONFIG_IWLWIFI_DEBUGFS +/* Returns true if a dump was created */ +bool iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +{ + struct iwl_fw_error_dump_file *dump_file; + struct iwl_fw_error_dump_data *dump_data; + u32 file_len; + + lockdep_assert_held(&mvm->mutex); + + /* + * Don't create an error dump if we'v already got one, but return + * true to trigger a (re-?)notification to userspace that there's + * something there to read. + */ + if (mvm->fw_error_dump) + return true; + + if (!mvm->fw_error_sram) + return false; + + file_len = mvm->fw_error_sram_len + + sizeof(*dump_file) + + sizeof(*dump_data); + + dump_file = vmalloc(file_len); + if (!dump_file) + return false; + + mvm->fw_error_dump = dump_file; + + dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); + dump_file->file_len = cpu_to_le32(file_len); + dump_data = (void *)dump_file->data; + dump_data->type = IWL_FW_ERROR_DUMP_SRAM; + dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); + + /* + * No need for lock since at the stage the FW isn't loaded. So it + * can't assert - we are the only one who can possibly be accessing + * mvm->fw_error_sram right now. + */ + memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len); + kfree(mvm->fw_error_sram); + mvm->fw_error_sram = NULL; + mvm->fw_error_sram_len = 0; + + return true; +} +#endif + static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); iwl_mvm_dump_nic_error_log(mvm); - if (!mvm->restart_fw) - iwl_mvm_dump_sram(mvm); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + iwl_mvm_fw_error_sram_dump(mvm); +#endif iwl_mvm_nic_restart(mvm); } --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -179,7 +179,7 @@ !iwlwifi_mod_params.sw_crypto) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) { + if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) { hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; hw->uapsd_queues = IWL_UAPSD_AC_INFO; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; @@ -246,7 +246,7 @@ else hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { + if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; @@ -321,6 +321,24 @@ ieee80211_free_txskb(hw, skb); } +static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) +{ + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) + return false; + return true; +} + +static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) +{ + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) + return false; + if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) + return true; + + /* enabled by default */ + return true; +} + static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, @@ -340,7 +358,7 @@ switch (action) { case IEEE80211_AMPDU_RX_START: - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) { + if (!iwl_enable_rx_ampdu(mvm->cfg)) { ret = -EINVAL; break; } @@ -350,7 +368,7 @@ ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); break; case IEEE80211_AMPDU_TX_START: - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) { + if (!iwl_enable_tx_ampdu(mvm->cfg)) { ret = -EINVAL; break; } @@ -397,6 +415,14 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { +#ifdef CONFIG_IWLWIFI_DEBUGFS + static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; + + /* notify the userspace about the error we had */ + if (iwl_mvm_fw_error_dump(mvm)) + kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); +#endif + iwl_trans_stop_device(mvm->trans); iwl_trans_stop_hw(mvm->trans, false); --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/utils.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -411,6 +411,8 @@ mvm->status, table.valid); } + IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); + trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, table.data1, table.data2, table.data3, table.blink1, table.blink2, table.ilink1, @@ -453,27 +455,26 @@ IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); } -void iwl_mvm_dump_sram(struct iwl_mvm *mvm) +void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) { const struct fw_img *img; - int ofs, len = 0; - u8 *buf; + u32 ofs, sram_len; + void *sram; - if (!mvm->ucode_loaded) + if (!mvm->ucode_loaded || mvm->fw_error_sram) return; img = &mvm->fw->img[mvm->cur_ucode]; ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - len = img->sec[IWL_UCODE_SECTION_DATA].len; + sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; - buf = kzalloc(len, GFP_ATOMIC); - if (!buf) + sram = kzalloc(sram_len, GFP_ATOMIC); + if (!sram) return; - iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len); - iwl_print_hex_error(mvm->trans, buf, len); - - kfree(buf); + iwl_trans_read_mem_bytes(mvm->trans, ofs, sram, sram_len); + mvm->fw_error_sram = sram; + mvm->fw_error_sram_len = sram_len; } /** --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __fw_error_dump_h__ +#define __fw_error_dump_h__ + +#include + +#define IWL_FW_ERROR_DUMP_BARKER 0x14789632 + +/** + * enum iwl_fw_error_dump_type - types of data in the dump file + * @IWL_FW_ERROR_DUMP_SRAM: + * @IWL_FW_ERROR_DUMP_REG: + */ +enum iwl_fw_error_dump_type { + IWL_FW_ERROR_DUMP_SRAM = 0, + IWL_FW_ERROR_DUMP_REG = 1, + + IWL_FW_ERROR_DUMP_MAX, +}; + +/** + * struct iwl_fw_error_dump_data - data for one type + * @type: %enum iwl_fw_error_dump_type + * @len: the length starting from %data - must be a multiplier of 4. + * @data: the data itself padded to be a multiplier of 4. + */ +struct iwl_fw_error_dump_data { + __le32 type; + __le32 len; + __u8 data[]; +} __packed __aligned(4); + +/** + * struct iwl_fw_error_dump_file - the layout of the header of the file + * @barker: must be %IWL_FW_ERROR_DUMP_BARKER + * @file_len: the length of all the file starting from %barker + * @data: array of %struct iwl_fw_error_dump_data + */ +struct iwl_fw_error_dump_file { + __le32 barker; + __le32 file_len; + u8 data[0]; +} __packed __aligned(4); + +#endif /* __fw_error_dump_h__ */ --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -871,8 +871,11 @@ lockdep_assert_held(&mvm->mutex); - /* Rssi update while not associated ?! */ - if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)) + /* + * Rssi update while not associated - can happen since the statistics + * are handled asynchronously + */ + if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) return; /* No BT - reports should be disabled */ --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/tx.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -822,16 +822,12 @@ struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; struct sk_buff_head reclaimed_skbs; struct iwl_mvm_tid_data *tid_data; - struct ieee80211_tx_info *info; struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; - struct ieee80211_hdr *hdr; struct sk_buff *skb; int sta_id, tid, freed; - /* "flow" corresponds to Tx queue */ u16 scd_flow = le16_to_cpu(ba_notif->scd_flow); - /* "ssn" is start of block-ack Tx window, corresponds to index * (in Tx queue's circular buffer) of first TFD/frame in window */ u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn); @@ -888,22 +884,26 @@ freed = 0; skb_queue_walk(&reclaimed_skbs, skb) { - hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = (void *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (ieee80211_is_data_qos(hdr->frame_control)) freed++; else WARN_ON_ONCE(1); - info = IEEE80211_SKB_CB(skb); iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); + memset(&info->status, 0, sizeof(info->status)); + /* Packet was transmitted successfully, failures come as single + * frames because before failing a frame the firmware transmits + * it without aggregation at least once. + */ + info->flags |= IEEE80211_TX_STAT_ACK; + if (freed == 1) { /* this is the first skb we deliver in this batch */ /* put the rate scaling data there */ - info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); - info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; info->status.ampdu_ack_len = ba_notif->txed_2_done; info->status.ampdu_len = ba_notif->txed; --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -63,6 +63,7 @@ #include "mvm.h" #include "sta.h" #include "iwl-io.h" +#include "fw-error-dump.h" struct iwl_dbgfs_mvm_ctx { struct iwl_mvm *mvm; @@ -139,6 +140,48 @@ return ret; } +static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) +{ + struct iwl_mvm *mvm = inode->i_private; + int ret; + + if (!mvm) + return -EINVAL; + + mutex_lock(&mvm->mutex); + if (!mvm->fw_error_dump) { + ret = -ENODATA; + goto out; + } + + file->private_data = mvm->fw_error_dump; + mvm->fw_error_dump = NULL; + ret = 0; + +out: + mutex_unlock(&mvm->mutex); + return ret; +} + +static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_fw_error_dump_file *dump_file = file->private_data; + + return simple_read_from_buffer(user_buf, count, ppos, + dump_file, + le32_to_cpu(dump_file->file_len)); +} + +static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, + struct file *file) +{ + vfree(file->private_data); + + return 0; +} + static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1170,6 +1213,12 @@ MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain); +static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { + .open = iwl_dbgfs_fw_error_dump_open, + .read = iwl_dbgfs_fw_error_dump_read, + .release = iwl_dbgfs_fw_error_dump_release, +}; + #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); #endif @@ -1189,6 +1238,7 @@ MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/pcie/drv.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -354,20 +354,25 @@ /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5112, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5100, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x510A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)}, - {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5400, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x1010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5000, iwl7265_2n_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5200, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5002, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9012, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)}, --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/pcie/trans.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -206,6 +206,28 @@ goto out; } + if (trans->cfg->host_interrupt_operation_mode) { + /* + * This is a bit of an abuse - This is needed for 7260 / 3160 + * only check host_interrupt_operation_mode even if this is + * not related to host_interrupt_operation_mode. + * + * Enable the oscillator to count wake up time for L1 exit. This + * consumes slightly more power (100uA) - but allows to be sure + * that we wake up from L1 on time. + * + * This looks weird: read twice the same register, discard the + * value, set a bit, and yet again, read that same register + * just to discard the value. But that's the way the hardware + * seems to like it. + */ + iwl_read_prph(trans, OSC_CLK); + iwl_read_prph(trans, OSC_CLK); + iwl_set_bits_prph(trans, OSC_CLK, OSC_CLK_FORCE_CONTROL); + iwl_read_prph(trans, OSC_CLK); + iwl_read_prph(trans, OSC_CLK); + } + /* * Enable DMA clock and wait for it to stabilize. * --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -704,6 +704,24 @@ return ret; } +static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) +{ + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) + return false; + return true; +} + +static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) +{ + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) + return false; + if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) + return true; + + /* disabled by default */ + return false; +} + static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, @@ -725,7 +743,7 @@ switch (action) { case IEEE80211_AMPDU_RX_START: - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) + if (!iwl_enable_rx_ampdu(priv->cfg)) break; IWL_DEBUG_HT(priv, "start Rx\n"); ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); @@ -737,7 +755,7 @@ case IEEE80211_AMPDU_TX_START: if (!priv->trans->ops->txq_enable) break; - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) + if (!iwl_enable_tx_ampdu(priv->cfg)) break; IWL_DEBUG_HT(priv, "start Tx\n"); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/dvm/sta.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -590,6 +590,7 @@ sizeof(priv->tid_data[sta_id][tid])); priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; priv->num_stations--; --- linux-3.13.0.orig/drivers/net/wireless/iwlwifi/dvm/tx.c +++ linux-3.13.0/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1291,8 +1291,6 @@ struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data; struct iwl_ht_agg *agg; struct sk_buff_head reclaimed_skbs; - struct ieee80211_tx_info *info; - struct ieee80211_hdr *hdr; struct sk_buff *skb; int sta_id; int tid; @@ -1379,22 +1377,28 @@ freed = 0; skb_queue_walk(&reclaimed_skbs, skb) { - hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = (void *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (ieee80211_is_data_qos(hdr->frame_control)) freed++; else WARN_ON_ONCE(1); - info = IEEE80211_SKB_CB(skb); iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]); + memset(&info->status, 0, sizeof(info->status)); + /* Packet was transmitted successfully, failures come as single + * frames because before failing a frame the firmware transmits + * it without aggregation at least once. + */ + info->flags |= IEEE80211_TX_STAT_ACK; + if (freed == 1) { /* this is the first skb we deliver in this batch */ /* put the rate scaling data there */ info = IEEE80211_SKB_CB(skb); memset(&info->status, 0, sizeof(info->status)); - info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; info->status.ampdu_ack_len = ba_resp->txed_2_done; info->status.ampdu_len = ba_resp->txed; --- linux-3.13.0.orig/drivers/net/wireless/mwifiex/scan.c +++ linux-3.13.0/drivers/net/wireless/mwifiex/scan.c @@ -1681,7 +1681,7 @@ const u8 *ie_buf; size_t ie_len; u16 channel = 0; - u64 fw_tsf = 0; + __le64 fw_tsf = 0; u16 beacon_size = 0; u32 curr_bcn_bytes; u32 freq; @@ -1815,7 +1815,7 @@ ie_buf, ie_len, rssi, GFP_KERNEL); bss_priv = (struct mwifiex_bss_priv *)bss->priv; bss_priv->band = band; - bss_priv->fw_tsf = fw_tsf; + bss_priv->fw_tsf = le64_to_cpu(fw_tsf); if (priv->media_connected && !memcmp(bssid, priv->curr_bss_params.bss_descriptor @@ -2101,12 +2101,12 @@ curr_bss->ht_info_offset); if (curr_bss->bcn_vht_cap) - curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf + - curr_bss->vht_cap_offset); + curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf + + curr_bss->vht_cap_offset); if (curr_bss->bcn_vht_oper) - curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf + - curr_bss->vht_info_offset); + curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf + + curr_bss->vht_info_offset); if (curr_bss->bcn_bss_co_2040) curr_bss->bcn_bss_co_2040 = --- linux-3.13.0.orig/drivers/net/wireless/mwifiex/11n.c +++ linux-3.13.0/drivers/net/wireless/mwifiex/11n.c @@ -308,8 +308,7 @@ ht_cap->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_cap)); memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), - (u8 *) bss_desc->bcn_ht_cap + - sizeof(struct ieee_types_header), + (u8 *)bss_desc->bcn_ht_cap, le16_to_cpu(ht_cap->header.len)); mwifiex_fill_cap_info(priv, radio_type, ht_cap); --- linux-3.13.0.orig/drivers/net/wireless/mwifiex/usb.c +++ linux-3.13.0/drivers/net/wireless/mwifiex/usb.c @@ -511,13 +511,6 @@ MWIFIEX_BSS_ROLE_ANY), MWIFIEX_ASYNC_CMD); -#ifdef CONFIG_PM - /* Resume handler may be called due to remote wakeup, - * force to exit suspend anyway - */ - usb_disable_autosuspend(card->udev); -#endif /* CONFIG_PM */ - return 0; } @@ -557,7 +550,6 @@ .id_table = mwifiex_usb_table, .suspend = mwifiex_usb_suspend, .resume = mwifiex_usb_resume, - .supports_autosuspend = 1, }; static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) --- linux-3.13.0.orig/drivers/net/wireless/mwifiex/pcie.c +++ linux-3.13.0/drivers/net/wireless/mwifiex/pcie.c @@ -1211,6 +1211,12 @@ rd_index = card->rxbd_rdptr & reg->rx_mask; skb_data = card->rx_buf_list[rd_index]; + /* If skb allocation was failed earlier for Rx packet, + * rx_buf_list[rd_index] would have been left with a NULL. + */ + if (!skb_data) + return -ENOMEM; + MWIFIEX_SKB_PACB(skb_data, &buf_pa); pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE, PCI_DMA_FROMDEVICE); @@ -1525,6 +1531,14 @@ if (adapter->ps_state == PS_STATE_SLEEP_CFM) { mwifiex_process_sleep_confirm_resp(adapter, skb->data, skb->len); + mwifiex_pcie_enable_host_int(adapter); + if (mwifiex_write_reg(adapter, + PCIE_CPU_INT_EVENT, + CPU_INTR_SLEEP_CFM_DONE)) { + dev_warn(adapter->dev, + "Write register failed\n"); + return -1; + } while (reg->sleep_cookie && (count++ < 10) && mwifiex_pcie_ok_to_access_hw(adapter)) usleep_range(50, 60); @@ -1993,23 +2007,9 @@ adapter->int_status |= pcie_ireg; spin_unlock_irqrestore(&adapter->int_lock, flags); - if (pcie_ireg & HOST_INTR_CMD_DONE) { - if ((adapter->ps_state == PS_STATE_SLEEP_CFM) || - (adapter->ps_state == PS_STATE_SLEEP)) { - mwifiex_pcie_enable_host_int(adapter); - if (mwifiex_write_reg(adapter, - PCIE_CPU_INT_EVENT, - CPU_INTR_SLEEP_CFM_DONE) - ) { - dev_warn(adapter->dev, - "Write register failed\n"); - return; - - } - } - } else if (!adapter->pps_uapsd_mode && - adapter->ps_state == PS_STATE_SLEEP && - mwifiex_pcie_ok_to_access_hw(adapter)) { + if (!adapter->pps_uapsd_mode && + adapter->ps_state == PS_STATE_SLEEP && + mwifiex_pcie_ok_to_access_hw(adapter)) { /* Potentially for PCIe we could get other * interrupts like shared. Don't change power * state until cookie is set */ --- linux-3.13.0.orig/drivers/net/wireless/mwifiex/fw.h +++ linux-3.13.0/drivers/net/wireless/mwifiex/fw.h @@ -226,7 +226,7 @@ /* HW_SPEC fw_cap_info */ -#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(13)|BIT(14))) +#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(12)|BIT(13))) #define GET_VHTCAP_CHWDSET(vht_cap_info) ((vht_cap_info >> 2) & 0x3) #define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3) --- linux-3.13.0.orig/drivers/net/wireless/mwifiex/wmm.c +++ linux-3.13.0/drivers/net/wireless/mwifiex/wmm.c @@ -559,7 +559,8 @@ mwifiex_wmm_delete_all_ralist(priv); memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); - if (priv->adapter->if_ops.clean_pcie_ring) + if (priv->adapter->if_ops.clean_pcie_ring && + !priv->adapter->surprise_removed) priv->adapter->if_ops.clean_pcie_ring(priv->adapter); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } --- linux-3.13.0.orig/drivers/net/wireless/mwifiex/11ac.c +++ linux-3.13.0/drivers/net/wireless/mwifiex/11ac.c @@ -189,8 +189,7 @@ vht_cap->header.len = cpu_to_le16(sizeof(struct ieee80211_vht_cap)); memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header), - (u8 *)bss_desc->bcn_vht_cap + - sizeof(struct ieee_types_header), + (u8 *)bss_desc->bcn_vht_cap, le16_to_cpu(vht_cap->header.len)); mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band); --- linux-3.13.0.orig/drivers/net/wireless/p54/txrx.c +++ linux-3.13.0/drivers/net/wireless/p54/txrx.c @@ -587,7 +587,7 @@ chan = priv->curchan; if (chan) { struct survey_info *survey = &priv->survey[chan->hw_value]; - survey->noise = clamp_t(s8, priv->noise, -128, 127); + survey->noise = clamp(priv->noise, -128, 127); survey->channel_time = priv->survey_raw.active; survey->channel_time_tx = priv->survey_raw.tx; survey->channel_time_busy = priv->survey_raw.tx + --- linux-3.13.0.orig/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ linux-3.13.0/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -56,7 +56,7 @@ {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, @@ -95,7 +95,7 @@ {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa}, {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; --- linux-3.13.0.orig/drivers/net/wireless/ath/ath9k/recv.c +++ linux-3.13.0/drivers/net/wireless/ath/ath9k/recv.c @@ -733,11 +733,18 @@ return NULL; /* - * mark descriptor as zero-length and set the 'more' - * flag to ensure that both buffers get discarded + * Re-check previous descriptor, in case it has been filled + * in the mean time. */ - rs->rs_datalen = 0; - rs->rs_more = true; + ret = ath9k_hw_rxprocdesc(ah, ds, rs); + if (ret == -EINPROGRESS) { + /* + * mark descriptor as zero-length and set the 'more' + * flag to ensure that both buffers get discarded + */ + rs->rs_datalen = 0; + rs->rs_more = true; + } } list_del(&bf->list); @@ -851,20 +858,15 @@ enum ieee80211_band band; unsigned int i = 0; struct ath_softc __maybe_unused *sc = common->priv; + struct ath_hw *ah = sc->sc_ah; - band = hw->conf.chandef.chan->band; + band = ah->curchan->chan->band; sband = hw->wiphy->bands[band]; - switch (hw->conf.chandef.width) { - case NL80211_CHAN_WIDTH_5: + if (IS_CHAN_QUARTER_RATE(ah->curchan)) rxs->flag |= RX_FLAG_5MHZ; - break; - case NL80211_CHAN_WIDTH_10: + else if (IS_CHAN_HALF_RATE(ah->curchan)) rxs->flag |= RX_FLAG_10MHZ; - break; - default: - break; - } if (rx_stats->rs_rate & 0x80) { /* HT rate */ @@ -1171,32 +1173,32 @@ struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hdr *hdr; bool discard_current = sc->rx.discard_next; - int ret = 0; /* * Discard corrupt descriptors which are marked in * ath_get_next_rx_buf(). */ - sc->rx.discard_next = rx_stats->rs_more; if (discard_current) - return -EINVAL; + goto corrupt; + + sc->rx.discard_next = false; /* * Discard zero-length packets. */ if (!rx_stats->rs_datalen) { RX_STAT_INC(rx_len_err); - return -EINVAL; + goto corrupt; } - /* - * rs_status follows rs_datalen so if rs_datalen is too large - * we can take a hint that hardware corrupted it, so ignore - * those frames. - */ + /* + * rs_status follows rs_datalen so if rs_datalen is too large + * we can take a hint that hardware corrupted it, so ignore + * those frames. + */ if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { RX_STAT_INC(rx_len_err); - return -EINVAL; + goto corrupt; } /* Only use status info from the last fragment */ @@ -1210,10 +1212,8 @@ * This is different from the other corrupt descriptor * condition handled above. */ - if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) { - ret = -EINVAL; - goto exit; - } + if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) + goto corrupt; hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); @@ -1229,18 +1229,15 @@ if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) RX_STAT_INC(rx_spectral); - ret = -EINVAL; - goto exit; + return -EINVAL; } /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. */ - if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) { - ret = -EINVAL; - goto exit; - } + if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) + return -EINVAL; rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr); if (rx_stats->is_mybeacon) { @@ -1248,15 +1245,19 @@ ath_start_rx_poll(sc, 3); } - if (ath9k_process_rate(common, hw, rx_stats, rx_status)) { - ret =-EINVAL; - goto exit; - } + /* + * This shouldn't happen, but have a safety check anyway. + */ + if (WARN_ON(!ah->curchan)) + return -EINVAL; + + if (ath9k_process_rate(common, hw, rx_stats, rx_status)) + return -EINVAL; ath9k_process_rssi(common, hw, rx_stats, rx_status); - rx_status->band = hw->conf.chandef.chan->band; - rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = ah->curchan->chan->band; + rx_status->freq = ah->curchan->chan->center_freq; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; @@ -1266,9 +1267,11 @@ sc->rx.num_pkts++; #endif -exit: - sc->rx.discard_next = false; - return ret; + return 0; + +corrupt: + sc->rx.discard_next = rx_stats->rs_more; + return -EINVAL; } static void ath9k_rx_skb_postprocess(struct ath_common *common, --- linux-3.13.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ linux-3.13.0/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -34,6 +34,10 @@ module_param_named(btcoex_enable, ath9k_htc_btcoex_enable, int, 0444); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); + #define CHAN2G(_freq, _idx) { \ .center_freq = (_freq), \ .hw_value = (_idx), \ @@ -725,12 +729,14 @@ IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + if (ath9k_ps_enable) + hw->flags |= IEEE80211_HW_SUPPORTS_PS; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | --- linux-3.13.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ linux-3.13.0/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1315,21 +1315,22 @@ struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_target_rate trate; + if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED)) + return; + mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); - ath9k_htc_setup_rate(priv, sta, &trate); - if (!ath9k_htc_send_rate_cmd(priv, &trate)) - ath_dbg(common, CONFIG, - "Supported rates for sta: %pM updated, rate caps: 0x%X\n", - sta->addr, be32_to_cpu(trate.capflags)); - else - ath_dbg(common, CONFIG, - "Unable to update supported rates for sta: %pM\n", - sta->addr); - } + memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); + ath9k_htc_setup_rate(priv, sta, &trate); + if (!ath9k_htc_send_rate_cmd(priv, &trate)) + ath_dbg(common, CONFIG, + "Supported rates for sta: %pM updated, rate caps: 0x%X\n", + sta->addr, be32_to_cpu(trate.capflags)); + else + ath_dbg(common, CONFIG, + "Unable to update supported rates for sta: %pM\n", + sta->addr); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); --- linux-3.13.0.orig/drivers/net/wireless/ath/ath9k/hw.c +++ linux-3.13.0/drivers/net/wireless/ath/ath9k/hw.c @@ -2608,13 +2608,6 @@ ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; - /* - * Fast channel change across bands is available - * only for AR9462 and AR9565. - */ - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH; - return 0; } --- linux-3.13.0.orig/drivers/net/wireless/ath/ath9k/init.c +++ linux-3.13.0/drivers/net/wireless/ath/ath9k/init.c @@ -57,6 +57,10 @@ module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444); MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity"); +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); + bool is_ath9k_unloaded; /* We use the hw_value as an index into our private channel structure */ @@ -890,13 +894,15 @@ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_RC_TABLE | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; + if (ath9k_ps_enable) + hw->flags |= IEEE80211_HW_SUPPORTS_PS; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; --- linux-3.13.0.orig/drivers/net/wireless/ath/ath9k/xmit.c +++ linux-3.13.0/drivers/net/wireless/ath/ath9k/xmit.c @@ -1458,14 +1458,16 @@ for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - if (!tid->sched) - continue; - ac = tid->ac; txq = ac->txq; ath_txq_lock(sc, txq); + if (!tid->sched) { + ath_txq_unlock(sc, txq); + continue; + } + buffered = ath_tid_has_buffered(tid); tid->sched = false; @@ -2195,14 +2197,15 @@ txq->stopped = true; } + if (txctl->an) + tid = ath_get_skb_tid(sc, txctl->an, skb); + if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { ath_txq_unlock(sc, txq); txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); } else if (txctl->an && ieee80211_is_data_present(hdr->frame_control)) { - tid = ath_get_skb_tid(sc, txctl->an, skb); - WARN_ON(tid->ac->txq != txctl->txq); if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) --- linux-3.13.0.orig/drivers/net/wireless/ath/ar5523/ar5523.c +++ linux-3.13.0/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1765,7 +1765,7 @@ AR5523_DEVICE_UG(0x07d1, 0x3a07), /* D-Link / WUA-2340 rev A1 */ AR5523_DEVICE_UG(0x1690, 0x0712), /* Gigaset / AR5523 */ AR5523_DEVICE_UG(0x1690, 0x0710), /* Gigaset / SMCWUSBTG */ - AR5523_DEVICE_UG(0x129b, 0x160c), /* Gigaset / USB stick 108 + AR5523_DEVICE_UG(0x129b, 0x160b), /* Gigaset / USB stick 108 (CyberTAN Technology) */ AR5523_DEVICE_UG(0x16ab, 0x7801), /* Globalsun / AR5523_1 */ AR5523_DEVICE_UX(0x16ab, 0x7811), /* Globalsun / AR5523_2 */ --- linux-3.13.0.orig/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h +++ linux-3.13.0/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h @@ -15,6 +15,8 @@ #ifndef RTL8187_H #define RTL8187_H +#include + #include "rtl818x.h" #include "leds.h" @@ -139,7 +141,10 @@ u8 aifsn[4]; u8 rfkill_mask; struct { - __le64 buf; + union { + __le64 buf; + u8 dummy1[L1_CACHE_BYTES]; + } ____cacheline_aligned; struct sk_buff_head queue; } b_tx_status; /* This queue is used by both -b and non-b devices */ struct mutex io_mutex; @@ -147,7 +152,8 @@ u8 bits8; __le16 bits16; __le32 bits32; - } *io_dmabuf; + u8 dummy2[L1_CACHE_BYTES]; + } *io_dmabuf ____cacheline_aligned; bool rfkill_off; u16 seqno; }; --- linux-3.13.0.orig/drivers/net/wireless/b43legacy/main.c +++ linux-3.13.0/drivers/net/wireless/b43legacy/main.c @@ -3919,6 +3919,7 @@ * as the ieee80211 unreg will destroy the workqueue. */ cancel_work_sync(&wldev->restart_work); cancel_work_sync(&wl->firmware_load); + complete(&wldev->fw_load_complete); B43legacy_WARN_ON(!wl); if (!wldev->fw.ucode) --- linux-3.13.0.orig/drivers/net/wireless/hostap/hostap_hw.c +++ linux-3.13.0/drivers/net/wireless/hostap/hostap_hw.c @@ -69,7 +69,7 @@ module_param_string(essid, essid, sizeof(essid), 0444); MODULE_PARM_DESC(essid, "Host AP's ESSID"); -static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; +static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_INFRA, DEF_INTS }; module_param_array(iw_mode, int, NULL, 0444); MODULE_PARM_DESC(iw_mode, "Initial operation mode"); --- linux-3.13.0.orig/drivers/net/can/vcan.c +++ linux-3.13.0/drivers/net/can/vcan.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -109,25 +110,23 @@ stats->rx_packets++; stats->rx_bytes += cfd->len; } - kfree_skb(skb); + consume_skb(skb); return NETDEV_TX_OK; } /* perform standard echo handling for CAN network interfaces */ if (loop) { - struct sock *srcsk = skb->sk; - skb = skb_share_check(skb, GFP_ATOMIC); + skb = can_create_echo_skb(skb); if (!skb) return NETDEV_TX_OK; /* receive with packet counting */ - skb->sk = srcsk; vcan_rx(skb, dev); } else { /* no looped packets => no counting */ - kfree_skb(skb); + consume_skb(skb); } return NETDEV_TX_OK; } --- linux-3.13.0.orig/drivers/net/can/janz-ican3.c +++ linux-3.13.0/drivers/net/can/janz-ican3.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1134,20 +1135,9 @@ */ static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb) { - struct sock *srcsk = skb->sk; - - if (atomic_read(&skb->users) != 1) { - struct sk_buff *old_skb = skb; - - skb = skb_clone(old_skb, GFP_ATOMIC); - kfree_skb(old_skb); - if (!skb) - return; - } else { - skb_orphan(skb); - } - - skb->sk = srcsk; + skb = can_create_echo_skb(skb); + if (!skb) + return; /* save this skb for tx interrupt echo handling */ skb_queue_tail(&mod->echoq, skb); --- linux-3.13.0.orig/drivers/net/can/flexcan.c +++ linux-3.13.0/drivers/net/can/flexcan.c @@ -144,6 +144,8 @@ #define FLEXCAN_MB_CODE_MASK (0xf0ffffff) +#define FLEXCAN_TIMEOUT_US (50) + /* * FLEXCAN hardware feature flags * @@ -259,6 +261,22 @@ } #endif +static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) +{ + if (!priv->reg_xceiver) + return 0; + + return regulator_enable(priv->reg_xceiver); +} + +static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv) +{ + if (!priv->reg_xceiver) + return 0; + + return regulator_disable(priv->reg_xceiver); +} + static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, u32 reg_esr) { @@ -266,26 +284,42 @@ (reg_esr & FLEXCAN_ESR_ERR_BUS); } -static inline void flexcan_chip_enable(struct flexcan_priv *priv) +static int flexcan_chip_enable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = flexcan_read(®s->mcr); reg &= ~FLEXCAN_MCR_MDIS; flexcan_write(reg, ®s->mcr); - udelay(10); + while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK) + return -ETIMEDOUT; + + return 0; } -static inline void flexcan_chip_disable(struct flexcan_priv *priv) +static int flexcan_chip_disable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = flexcan_read(®s->mcr); reg |= FLEXCAN_MCR_MDIS; flexcan_write(reg, ®s->mcr); + + while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + return -ETIMEDOUT; + + return 0; } static int flexcan_get_berr_counter(const struct net_device *dev, @@ -706,7 +740,9 @@ u32 reg_mcr, reg_ctrl; /* enable module */ - flexcan_chip_enable(priv); + err = flexcan_chip_enable(priv); + if (err) + return err; /* soft reset */ flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); @@ -785,11 +821,9 @@ if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) flexcan_write(0x0, ®s->rxfgmask); - if (priv->reg_xceiver) { - err = regulator_enable(priv->reg_xceiver); - if (err) - goto out; - } + err = flexcan_transceiver_enable(priv); + if (err) + goto out; /* synchronize with the can bus */ reg_mcr = flexcan_read(®s->mcr); @@ -824,16 +858,17 @@ struct flexcan_regs __iomem *regs = priv->base; u32 reg; - /* Disable all interrupts */ - flexcan_write(0, ®s->imask1); - /* Disable + halt module */ reg = flexcan_read(®s->mcr); reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT; flexcan_write(reg, ®s->mcr); - if (priv->reg_xceiver) - regulator_disable(priv->reg_xceiver); + /* Disable all interrupts */ + flexcan_write(0, ®s->imask1); + flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, + ®s->ctrl); + + flexcan_transceiver_disable(priv); priv->can.state = CAN_STATE_STOPPED; return; @@ -863,7 +898,7 @@ /* start chip and queuing */ err = flexcan_chip_start(dev); if (err) - goto out_close; + goto out_free_irq; can_led_event(dev, CAN_LED_EVENT_OPEN); @@ -872,6 +907,8 @@ return 0; + out_free_irq: + free_irq(dev->irq, dev); out_close: close_candev(dev); out_disable_per: @@ -942,12 +979,16 @@ goto out_disable_ipg; /* select "bus clock", chip must be disabled */ - flexcan_chip_disable(priv); + err = flexcan_chip_disable(priv); + if (err) + goto out_disable_per; reg = flexcan_read(®s->ctrl); reg |= FLEXCAN_CTRL_CLK_SRC; flexcan_write(reg, ®s->ctrl); - flexcan_chip_enable(priv); + err = flexcan_chip_enable(priv); + if (err) + goto out_chip_disable; /* set freeze, halt and activate FIFO, restrict register access */ reg = flexcan_read(®s->mcr); @@ -964,14 +1005,15 @@ if (!(reg & FLEXCAN_MCR_FEN)) { netdev_err(dev, "Could not enable RX FIFO, unsupported core\n"); err = -ENODEV; - goto out_disable_per; + goto out_chip_disable; } err = register_candev(dev); - out_disable_per: /* disable core and turn off clocks */ + out_chip_disable: flexcan_chip_disable(priv); + out_disable_per: clk_disable_unprepare(priv->clk_per); out_disable_ipg: clk_disable_unprepare(priv->clk_ipg); @@ -1101,9 +1143,10 @@ static int flexcan_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); + struct flexcan_priv *priv = netdev_priv(dev); unregister_flexcandev(dev); - + netif_napi_del(&priv->napi); free_candev(dev); return 0; @@ -1114,8 +1157,11 @@ { struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); + int err; - flexcan_chip_disable(priv); + err = flexcan_chip_disable(priv); + if (err) + return err; if (netif_running(dev)) { netif_stop_queue(dev); @@ -1136,9 +1182,7 @@ netif_device_attach(dev); netif_start_queue(dev); } - flexcan_chip_enable(priv); - - return 0; + return flexcan_chip_enable(priv); } #endif /* CONFIG_PM_SLEEP */ --- linux-3.13.0.orig/drivers/net/can/dev.c +++ linux-3.13.0/drivers/net/can/dev.c @@ -324,19 +324,10 @@ } if (!priv->echo_skb[idx]) { - struct sock *srcsk = skb->sk; - if (atomic_read(&skb->users) != 1) { - struct sk_buff *old_skb = skb; - - skb = skb_clone(old_skb, GFP_ATOMIC); - kfree_skb(old_skb); - if (!skb) - return; - } else - skb_orphan(skb); - - skb->sk = srcsk; + skb = can_create_echo_skb(skb); + if (!skb) + return; /* make settings for echo to reduce code in irq context */ skb->protocol = htons(ETH_P_CAN); --- linux-3.13.0.orig/drivers/net/can/usb/kvaser_usb.c +++ linux-3.13.0/drivers/net/can/usb/kvaser_usb.c @@ -474,6 +474,8 @@ return err; dev->nchannels = msg.u.cardinfo.nchannels; + if (dev->nchannels > MAX_NET_DEVICES) + return -EINVAL; return 0; } --- linux-3.13.0.orig/drivers/net/bonding/bond_3ad.h +++ linux-3.13.0/drivers/net/bonding/bond_3ad.h @@ -253,6 +253,7 @@ struct ad_bond_info { struct ad_system system; /* 802.3ad system structure */ u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes + u16 aggregator_identifier; }; struct ad_slave_info { --- linux-3.13.0.orig/drivers/net/bonding/bond_3ad.c +++ linux-3.13.0/drivers/net/bonding/bond_3ad.c @@ -1806,8 +1806,6 @@ BOND_AD_INFO(bond).agg_select_timer = timeout; } -static u16 aggregator_identifier; - /** * bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures * @bond: bonding struct to work on @@ -1821,7 +1819,7 @@ if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), bond->dev->dev_addr)) { - aggregator_identifier = 0; + BOND_AD_INFO(bond).aggregator_identifier = 0; BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); @@ -1892,7 +1890,7 @@ ad_initialize_agg(aggregator); aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr); - aggregator->aggregator_identifier = (++aggregator_identifier); + aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier; aggregator->slave = slave; aggregator->is_active = 0; aggregator->num_of_ports = 0; --- linux-3.13.0.orig/drivers/net/hyperv/netvsc_drv.c +++ linux-3.13.0/drivers/net/hyperv/netvsc_drv.c @@ -89,8 +89,12 @@ { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_device *device_obj = net_device_ctx->device_ctx; + struct netvsc_device *nvdev; + struct rndis_device *rdev; int ret = 0; + netif_carrier_off(net); + /* Open up the device */ ret = rndis_filter_open(device_obj); if (ret != 0) { @@ -100,6 +104,11 @@ netif_start_queue(net); + nvdev = hv_get_drvdata(device_obj); + rdev = nvdev->extension; + if (!rdev->link_state) + netif_carrier_on(net); + return ret; } @@ -230,23 +239,24 @@ struct net_device *net; struct net_device_context *ndev_ctx; struct netvsc_device *net_device; + struct rndis_device *rdev; net_device = hv_get_drvdata(device_obj); + rdev = net_device->extension; + + rdev->link_state = status != 1; + net = net_device->ndev; - if (!net) { - netdev_err(net, "got link status but net device " - "not initialized yet\n"); + if (!net || net->reg_state != NETREG_REGISTERED) return; - } + ndev_ctx = netdev_priv(net); if (status == 1) { - netif_carrier_on(net); - ndev_ctx = netdev_priv(net); schedule_delayed_work(&ndev_ctx->dwork, 0); schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); } else { - netif_carrier_off(net); + schedule_delayed_work(&ndev_ctx->dwork, 0); } } @@ -389,17 +399,35 @@ * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add * another netif_notify_peers() into a delayed work, otherwise GARP packet * will not be sent after quick migration, and cause network disconnection. + * Also, we update the carrier status here. */ -static void netvsc_send_garp(struct work_struct *w) +static void netvsc_link_change(struct work_struct *w) { struct net_device_context *ndev_ctx; struct net_device *net; struct netvsc_device *net_device; + struct rndis_device *rdev; + bool notify; + + rtnl_lock(); ndev_ctx = container_of(w, struct net_device_context, dwork.work); net_device = hv_get_drvdata(ndev_ctx->device_ctx); + rdev = net_device->extension; net = net_device->ndev; - netdev_notify_peers(net); + + if (rdev->link_state) { + netif_carrier_off(net); + notify = false; + } else { + netif_carrier_on(net); + notify = true; + } + + rtnl_unlock(); + + if (notify) + netdev_notify_peers(net); } @@ -415,13 +443,10 @@ if (!net) return -ENOMEM; - /* Set initial state */ - netif_carrier_off(net); - net_device_ctx = netdev_priv(net); net_device_ctx->device_ctx = dev; hv_set_drvdata(dev, net); - INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp); + INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change); INIT_WORK(&net_device_ctx->work, do_set_multicast); net->netdev_ops = &device_ops; @@ -444,8 +469,6 @@ } memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); - netif_carrier_on(net); - ret = register_netdev(net); if (ret != 0) { pr_err("Unable to register netdev.\n"); --- linux-3.13.0.orig/drivers/net/hyperv/netvsc.c +++ linux-3.13.0/drivers/net/hyperv/netvsc.c @@ -137,8 +137,7 @@ if (net_device->recv_buf) { /* Free up the receive buffer */ - free_pages((unsigned long)net_device->recv_buf, - get_order(net_device->recv_buf_size)); + vfree(net_device->recv_buf); net_device->recv_buf = NULL; } @@ -164,9 +163,7 @@ return -ENODEV; ndev = net_device->ndev; - net_device->recv_buf = - (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, - get_order(net_device->recv_buf_size)); + net_device->recv_buf = vzalloc(net_device->recv_buf_size); if (!net_device->recv_buf) { netdev_err(ndev, "unable to allocate receive " "buffer of size %d\n", net_device->recv_buf_size); @@ -362,6 +359,11 @@ goto cleanup; /* Post the big receive buffer to NetVSP */ + if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2) + net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; + else + net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; + ret = netvsc_init_recv_buf(device); cleanup: @@ -911,7 +913,6 @@ ndev = net_device->ndev; /* Initialize the NetVSC channel extension */ - net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; spin_lock_init(&net_device->recv_pkt_list_lock); INIT_LIST_HEAD(&net_device->recv_pkt_list); --- linux-3.13.0.orig/drivers/net/hyperv/hyperv_net.h +++ linux-3.13.0/drivers/net/hyperv/hyperv_net.h @@ -463,7 +463,8 @@ #define NETVSC_MTU 65536 -#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*2) /* 2MB */ +#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ +#define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ #define NETVSC_RECEIVE_BUFFER_ID 0xcafe --- linux-3.13.0.orig/drivers/net/vmxnet3/vmxnet3_drv.c +++ linux-3.13.0/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1760,11 +1760,20 @@ { struct vmxnet3_adapter *adapter = netdev_priv(netdev); - if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE) - vmxnet3_disable_all_intrs(adapter); - - vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size); - vmxnet3_enable_all_intrs(adapter); + switch (adapter->intr.type) { +#ifdef CONFIG_PCI_MSI + case VMXNET3_IT_MSIX: { + int i; + for (i = 0; i < adapter->num_rx_queues; i++) + vmxnet3_msix_rx(0, &adapter->rx_queue[i]); + break; + } +#endif + case VMXNET3_IT_MSI: + default: + vmxnet3_intr(0, adapter->netdev); + break; + } } #endif /* CONFIG_NET_POLL_CONTROLLER */ --- linux-3.13.0.orig/drivers/clocksource/vf_pit_timer.c +++ linux-3.13.0/drivers/clocksource/vf_pit_timer.c @@ -54,7 +54,7 @@ static u64 pit_read_sched_clock(void) { - return __raw_readl(clksrc_base + PITCVAL); + return ~__raw_readl(clksrc_base + PITCVAL); } static int __init pit_clocksource_init(unsigned long rate) --- linux-3.13.0.orig/drivers/input/tablet/wacom_sys.c +++ linux-3.13.0/drivers/input/tablet/wacom_sys.c @@ -304,7 +304,7 @@ struct usb_device *dev = interface_to_usbdev(intf); char limit = 0; /* result has to be defined as int for some devices */ - int result = 0; + int result = 0, touch_max = 0; int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; unsigned char *report; @@ -351,7 +351,8 @@ if (usage == WCM_DESKTOP) { if (finger) { features->device_type = BTN_TOOL_FINGER; - + /* touch device at least supports one touch point */ + touch_max = 1; switch (features->type) { case TABLETPC2FG: features->pktlen = WACOM_PKGLEN_TPC2FG; @@ -504,6 +505,8 @@ } out: + if (!features->touch_max && touch_max) + features->touch_max = touch_max; result = 0; kfree(report); return result; @@ -1194,12 +1197,15 @@ wacom_wac1->features.device_type = BTN_TOOL_PEN; snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen", wacom_wac1->features.name); + wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max; + wacom_wac1->shared->type = wacom_wac1->features.type; error = wacom_register_input(wacom1); if (error) goto fail; /* Touch interface */ - if (wacom_wac1->features.touch_max) { + if (wacom_wac1->features.touch_max || + wacom_wac1->features.type == INTUOSHT) { wacom_wac2->features = *((struct wacom_features *)id->driver_info); wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; @@ -1214,6 +1220,10 @@ error = wacom_register_input(wacom2); if (error) goto fail; + + if (wacom_wac1->features.type == INTUOSHT && + wacom_wac1->features.touch_max) + wacom_wac->shared->touch_input = wacom_wac2->input; } error = wacom_initialize_battery(wacom); @@ -1322,7 +1332,7 @@ * HID descriptor. If this is the touch interface (wMaxPacketSize * of WACOM_PKGLEN_BBTOUCH3), override the table values. */ - if (features->type >= INTUOS5S && features->type <= INTUOSPL) { + if (features->type >= INTUOS5S && features->type <= INTUOSHT) { if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) { features->device_type = BTN_TOOL_FINGER; features->pktlen = WACOM_PKGLEN_BBTOUCH3; @@ -1393,6 +1403,11 @@ } } + if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) { + if (wacom_wac->features.device_type == BTN_TOOL_FINGER) + wacom_wac->shared->touch_input = wacom_wac->input; + } + return 0; fail5: wacom_destroy_leds(wacom); --- linux-3.13.0.orig/drivers/input/tablet/wacom_wac.c +++ linux-3.13.0/drivers/input/tablet/wacom_wac.c @@ -210,6 +210,62 @@ return 1; } +static int wacom_dtus_irq(struct wacom_wac *wacom) +{ + char *data = wacom->data; + struct input_dev *input = wacom->input; + unsigned short prox, pressure = 0; + + if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) { + dev_dbg(input->dev.parent, + "%s: received unknown report #%d", __func__, data[0]); + return 0; + } else if (data[0] == WACOM_REPORT_DTUSPAD) { + input_report_key(input, BTN_0, (data[1] & 0x01)); + input_report_key(input, BTN_1, (data[1] & 0x02)); + input_report_key(input, BTN_2, (data[1] & 0x04)); + input_report_key(input, BTN_3, (data[1] & 0x08)); + input_report_abs(input, ABS_MISC, + data[1] & 0x0f ? PAD_DEVICE_ID : 0); + /* + * Serial number is required when expresskeys are + * reported through pen interface. + */ + input_event(input, EV_MSC, MSC_SERIAL, 0xf0); + return 1; + } else { + prox = data[1] & 0x80; + if (prox) { + switch ((data[1] >> 3) & 3) { + case 1: /* Rubber */ + wacom->tool[0] = BTN_TOOL_RUBBER; + wacom->id[0] = ERASER_DEVICE_ID; + break; + + case 2: /* Pen */ + wacom->tool[0] = BTN_TOOL_PEN; + wacom->id[0] = STYLUS_DEVICE_ID; + break; + } + } + + input_report_key(input, BTN_STYLUS, data[1] & 0x20); + input_report_key(input, BTN_STYLUS2, data[1] & 0x40); + input_report_abs(input, ABS_X, get_unaligned_be16(&data[3])); + input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5])); + pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff); + input_report_abs(input, ABS_PRESSURE, pressure); + input_report_key(input, BTN_TOUCH, pressure > 10); + + if (!prox) /* out-prox */ + wacom->id[0] = 0; + input_report_key(input, wacom->tool[0], prox); + input_report_abs(input, ABS_MISC, wacom->id[0]); + input_event(input, EV_MSC, MSC_SERIAL, 1); + return 1; + } +} + static int wacom_graphire_irq(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; @@ -331,7 +387,7 @@ /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { - if (features->quirks == WACOM_QUIRK_MULTI_INPUT) + if (features->quirks & WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = true; /* serial number of the tool */ @@ -436,7 +492,7 @@ /* Exit report */ if ((data[1] & 0xfe) == 0x80) { - if (features->quirks == WACOM_QUIRK_MULTI_INPUT) + if (features->quirks & WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = false; /* @@ -1151,8 +1207,8 @@ int width, height; if (features->type >= INTUOSPS && features->type <= INTUOSPL) { - width = data[5]; - height = data[6]; + width = data[5] * 100; + height = data[6] * 100; } else { /* * "a" is a scaled-down area which we assume is @@ -1176,10 +1232,16 @@ static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data) { struct input_dev *input = wacom->input; + struct wacom_features *features = &wacom->features; - input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); + if (features->type == INTUOSHT) { + input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0); + input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0); + } else { + input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0); + input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); + } input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0); - input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0); input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0); } @@ -1213,13 +1275,23 @@ static int wacom_bpt_pen(struct wacom_wac *wacom) { + struct wacom_features *features = &wacom->features; struct input_dev *input = wacom->input; unsigned char *data = wacom->data; int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0; - if (data[0] != 0x02) + if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_USB) return 0; + if (data[0] == WACOM_REPORT_USB) { + if (features->type == INTUOSHT && features->touch_max) { + input_report_switch(wacom->shared->touch_input, + SW_MUTE_DEVICE, data[8] & 0x40); + input_sync(wacom->shared->touch_input); + } + return 0; + } + prox = (data[1] & 0x20) == 0x20; /* @@ -1252,8 +1324,8 @@ * touching and applying pressure; do not report negative * distance. */ - if (data[8] <= wacom->features.distance_max) - d = wacom->features.distance_max - data[8]; + if (data[8] <= features->distance_max) + d = features->distance_max - data[8]; pen = data[1] & 0x01; btn1 = data[1] & 0x02; @@ -1297,13 +1369,20 @@ unsigned char *data = wacom->data; int connected; - if (len != WACOM_PKGLEN_WIRELESS || data[0] != 0x80) + if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL) return 0; connected = data[1] & 0x01; if (connected) { int pid, battery; + if ((wacom->shared->type == INTUOSHT) && + wacom->shared->touch_max) { + input_report_switch(wacom->shared->touch_input, + SW_MUTE_DEVICE, data[5] & 0x40); + input_sync(wacom->shared->touch_input); + } + pid = get_unaligned_be16(&data[6]); battery = data[5] & 0x3f; if (wacom->pid != pid) { @@ -1348,6 +1427,10 @@ sync = wacom_dtu_irq(wacom_wac); break; + case DTUS: + sync = wacom_dtus_irq(wacom_wac); + break; + case INTUOS: case INTUOS3S: case INTUOS3: @@ -1391,6 +1474,7 @@ break; case BAMBOO_PT: + case INTUOSHT: sync = wacom_bpt_irq(wacom_wac, len); break; @@ -1459,7 +1543,7 @@ /* these device have multiple inputs */ if (features->type >= WIRELESS || - (features->type >= INTUOS5S && features->type <= INTUOSPL) || + (features->type >= INTUOS5S && features->type <= INTUOSHT) || (features->oVid && features->oPid)) features->quirks |= WACOM_QUIRK_MULTI_INPUT; @@ -1538,7 +1622,7 @@ wacom_abs_set_axis(input_dev, wacom_wac); - switch (wacom_wac->features.type) { + switch (features->type) { case WACOM_MO: input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); /* fall through */ @@ -1749,8 +1833,14 @@ /* fall through */ + case DTUS: case PL: case DTU: + if (features->type == DTUS) { + input_set_capability(input_dev, EV_MSC, MSC_SERIAL); + for (i = 0; i < 3; i++) + __set_bit(BTN_0 + i, input_dev->keybit); + } __set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_STYLUS, input_dev->keybit); @@ -1771,33 +1861,50 @@ __set_bit(INPUT_PROP_POINTER, input_dev->propbit); break; + case INTUOSHT: + if (features->touch_max && + features->device_type == BTN_TOOL_FINGER) { + input_dev->evbit[0] |= BIT_MASK(EV_SW); + __set_bit(SW_MUTE_DEVICE, input_dev->swbit); + } + /* fall through */ + case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - if (features->device_type == BTN_TOOL_FINGER) { - unsigned int flags = INPUT_MT_POINTER; __set_bit(BTN_LEFT, input_dev->keybit); __set_bit(BTN_FORWARD, input_dev->keybit); __set_bit(BTN_BACK, input_dev->keybit); __set_bit(BTN_RIGHT, input_dev->keybit); - if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - input_set_abs_params(input_dev, + if (features->touch_max) { + /* touch interface */ + unsigned int flags = INPUT_MT_POINTER; + + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, + input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, features->y_max, 0, 0); + } else { + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); + __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); + flags = 0; + } + input_mt_init_slots(input_dev, features->touch_max, flags); } else { - __set_bit(BTN_TOOL_FINGER, input_dev->keybit); - __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); - flags = 0; + /* buttons/keys only interface */ + __clear_bit(ABS_X, input_dev->absbit); + __clear_bit(ABS_Y, input_dev->absbit); + __clear_bit(BTN_TOUCH, input_dev->keybit); } - input_mt_init_slots(input_dev, features->touch_max, flags); } else if (features->device_type == BTN_TOOL_PEN) { + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_STYLUS, input_dev->keybit); @@ -2055,6 +2162,9 @@ static const struct wacom_features wacom_features_0xF0 = { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, 0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0xFB = + { "Wacom DTU1031", WACOM_PKGLEN_DTUS, 22096, 13960, 511, + 0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x57 = { "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES}; @@ -2200,6 +2310,17 @@ static const struct wacom_features wacom_features_0x301 = { "Wacom Bamboo One M", WACOM_PKGLEN_BBPEN, 21648, 13530, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x302 = + { "Wacom Intuos PT S", WACOM_PKGLEN_BBPEN, 15200, 9500, 1023, + 31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 16 }; +static const struct wacom_features wacom_features_0x303 = + { "Wacom Intuos PT M", WACOM_PKGLEN_BBPEN, 21600, 13500, 1023, + 31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 16 }; +static const struct wacom_features wacom_features_0x30E = + { "Wacom Intuos S", WACOM_PKGLEN_BBPEN, 15200, 9500, 1023, + 31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x6004 = { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -2337,6 +2458,9 @@ { USB_DEVICE_WACOM(0x10F) }, { USB_DEVICE_WACOM(0x300) }, { USB_DEVICE_WACOM(0x301) }, + { USB_DEVICE_DETAILED(0x302, USB_CLASS_HID, 0, 0) }, + { USB_DEVICE_DETAILED(0x303, USB_CLASS_HID, 0, 0) }, + { USB_DEVICE_DETAILED(0x30E, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0x304) }, { USB_DEVICE_DETAILED(0x314, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) }, @@ -2347,6 +2471,7 @@ { USB_DEVICE_WACOM(0xF8) }, { USB_DEVICE_DETAILED(0xF6, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0xFA) }, + { USB_DEVICE_WACOM(0xFB) }, { USB_DEVICE_WACOM(0x0307) }, { USB_DEVICE_DETAILED(0x0309, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_LENOVO(0x6004) }, --- linux-3.13.0.orig/drivers/input/tablet/wacom_wac.h +++ linux-3.13.0/drivers/input/tablet/wacom_wac.h @@ -12,7 +12,7 @@ #include /* maximum packet length for USB devices */ -#define WACOM_PKGLEN_MAX 64 +#define WACOM_PKGLEN_MAX 68 #define WACOM_NAME_MAX 64 @@ -29,6 +29,7 @@ #define WACOM_PKGLEN_WIRELESS 32 #define WACOM_PKGLEN_MTOUCH 62 #define WACOM_PKGLEN_MTTPC 40 +#define WACOM_PKGLEN_DTUS 68 /* wacom data size per MT contact */ #define WACOM_BYTES_PER_MT_PACKET 11 @@ -47,13 +48,17 @@ #define WACOM_REPORT_INTUOSWRITE 6 #define WACOM_REPORT_INTUOSPAD 12 #define WACOM_REPORT_INTUOS5PAD 3 +#define WACOM_REPORT_DTUSPAD 21 #define WACOM_REPORT_TPC1FG 6 #define WACOM_REPORT_TPC2FG 13 #define WACOM_REPORT_TPCMT 13 #define WACOM_REPORT_TPCHID 15 #define WACOM_REPORT_TPCST 16 +#define WACOM_REPORT_DTUS 17 #define WACOM_REPORT_TPC1FGE 18 #define WACOM_REPORT_24HDT 1 +#define WACOM_REPORT_WL 128 +#define WACOM_REPORT_USB 192 /* device quirks */ #define WACOM_QUIRK_MULTI_INPUT 0x0001 @@ -68,6 +73,7 @@ PTU, PL, DTU, + DTUS, INTUOS, INTUOS3S, INTUOS3, @@ -81,6 +87,7 @@ INTUOSPS, INTUOSPM, INTUOSPL, + INTUOSHT, WACOM_21UX2, WACOM_22HD, DTK, @@ -129,6 +136,10 @@ struct wacom_shared { bool stylus_in_proximity; bool touch_down; + /* for wireless device to access USB interfaces */ + unsigned touch_max; + int type; + struct input_dev *touch_input; }; struct wacom_wac { --- linux-3.13.0.orig/drivers/input/serio/hyperv-keyboard.c +++ linux-3.13.0/drivers/input/serio/hyperv-keyboard.c @@ -160,7 +160,9 @@ if (info & IS_E0) serio_interrupt(kbd_dev->hv_serio, XTKBD_EMUL0, 0); - + if (info & IS_E1) + serio_interrupt(kbd_dev->hv_serio, + XTKBD_EMUL1, 0); scan_code = __le16_to_cpu(ks_msg->make_code); if (info & IS_BREAK) scan_code |= XTKBD_RELEASE; --- linux-3.13.0.orig/drivers/input/misc/arizona-haptics.c +++ linux-3.13.0/drivers/input/misc/arizona-haptics.c @@ -77,16 +77,14 @@ return; } + mutex_unlock(dapm_mutex); + ret = snd_soc_dapm_sync(arizona->dapm); if (ret != 0) { dev_err(arizona->dev, "Failed to sync DAPM: %d\n", ret); - mutex_unlock(dapm_mutex); return; } - - mutex_unlock(dapm_mutex); - } else { /* This disable sequence will be a noop if already enabled */ mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); @@ -99,16 +97,15 @@ return; } + mutex_unlock(dapm_mutex); + ret = snd_soc_dapm_sync(arizona->dapm); if (ret != 0) { dev_err(arizona->dev, "Failed to sync DAPM: %d\n", ret); - mutex_unlock(dapm_mutex); return; } - mutex_unlock(dapm_mutex); - ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1, ARIZONA_HAP_CTRL_MASK, --- linux-3.13.0.orig/drivers/input/misc/xen-kbdfront.c +++ linux-3.13.0/drivers/input/misc/xen-kbdfront.c @@ -29,6 +29,7 @@ #include #include #include +#include struct xenkbd_info { struct input_dev *kbd; @@ -380,6 +381,9 @@ if (xen_initial_domain()) return -ENODEV; + if (!xen_has_pv_devices()) + return -ENODEV; + return xenbus_register_frontend(&xenkbd_driver); } --- linux-3.13.0.orig/drivers/input/mouse/synaptics.c +++ linux-3.13.0/drivers/input/mouse/synaptics.c @@ -1317,7 +1317,9 @@ /* Clickpads report only left button */ __clear_bit(BTN_RIGHT, dev->keybit); __clear_bit(BTN_MIDDLE, dev->keybit); - } + } else if (SYN_CAP_CLICKPAD2BTN(priv->ext_cap_0c) || + SYN_CAP_CLICKPAD2BTN2(priv->ext_cap_0c)) + __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); } static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse, --- linux-3.13.0.orig/drivers/input/mouse/alps.h +++ linux-3.13.0/drivers/input/mouse/alps.h @@ -19,6 +19,10 @@ #define ALPS_PROTO_V5 5 #define ALPS_PROTO_V6 6 +#define DOLPHIN_COUNT_PER_ELECTRODE 64 +#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ +#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ + /** * struct alps_model_info - touchpad ID table * @signature: E7 response string to match. @@ -146,7 +150,8 @@ int (*hw_init)(struct psmouse *psmouse); void (*process_packet)(struct psmouse *psmouse); - void (*decode_fields)(struct alps_fields *f, unsigned char *p); + void (*decode_fields)(struct alps_fields *f, unsigned char *p, + struct psmouse *psmouse); void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1); int prev_fin; --- linux-3.13.0.orig/drivers/input/mouse/cypress_ps2.h +++ linux-3.13.0/drivers/input/mouse/cypress_ps2.h @@ -130,7 +130,18 @@ #define RESP_REMOTE_BIT 0x40 #define RESP_SMBUS_BIT 0x80 -#define CYTP_MAX_MT_SLOTS 2 +/* + * CYPRESS_SIMULATED_MT + * set to 1 for simulated multitouch (up to 5 contact points) + * set to 0 for SEMI_MT (only 2 corner points, and count of fingers) + */ +#define CYPRESS_SIMULATED_MT 1 + +#if ( CYPRESS_SIMULATED_MT == 1 ) +# define CYTP_MAX_MT_SLOTS 5 +#else +# define CYTP_MAX_MT_SLOTS 2 +#endif struct cytp_contact { int x; --- linux-3.13.0.orig/drivers/input/mouse/synaptics.h +++ linux-3.13.0/drivers/input/mouse/synaptics.h @@ -81,6 +81,7 @@ */ #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ #define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ +#define SYN_CAP_CLICKPAD2BTN2(ex0c) ((ex0c) & 0x200000) /* 2-button ClickPad */ #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) #define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) --- linux-3.13.0.orig/drivers/input/mouse/elantech.c +++ linux-3.13.0/drivers/input/mouse/elantech.c @@ -486,6 +486,7 @@ unsigned char *packet = psmouse->packet; input_report_key(dev, BTN_LEFT, packet[0] & 0x01); + input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); input_mt_report_pointer_emulation(dev, true); input_sync(dev); } @@ -984,6 +985,44 @@ } /* + * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in + * fw_version for this is based on the following fw_version & caps table: + * + * Laptop-model: fw_version: caps: buttons: + * Acer S3 0x461f00 10, 13, 0e clickpad + * Acer S7-392 0x581f01 50, 17, 0d clickpad + * Acer V5-131 0x461f02 01, 16, 0c clickpad + * Acer V5-551 0x461f00 ? clickpad + * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons + * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons + * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons + * Asus UX31 0x361f00 20, 15, 0e clickpad + * Asus UX32VD 0x361f02 00, 15, 0e clickpad + * Avatar AVIU-145A2 0x361f00 ? clickpad + * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons + * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) + * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons + * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad + * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad + * Samsung NP900X3E-A02 0x575f03 ? clickpad + * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad + * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons + * Samsung RF710 0x450f00 ? 2 hw buttons + * System76 Pangolin 0x250f01 ? 2 hw buttons + * (*) + 3 trackpoint buttons + */ +static void elantech_set_buttonpad_prop(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + + if (etd->fw_version & 0x001000) { + __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); + __clear_bit(BTN_RIGHT, dev->keybit); + } +} + +/* * Set the appropriate event bits for the input subsystem */ static int elantech_set_input_params(struct psmouse *psmouse) @@ -1026,6 +1065,8 @@ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); /* fall through */ case 3: + if (etd->hw_version == 3) + elantech_set_buttonpad_prop(psmouse); input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); if (etd->reports_pressure) { @@ -1047,9 +1088,7 @@ */ psmouse_warn(psmouse, "couldn't query resolution data.\n"); } - /* v4 is clickpad, with only one button. */ - __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); - __clear_bit(BTN_RIGHT, dev->keybit); + elantech_set_buttonpad_prop(psmouse); __set_bit(BTN_TOOL_QUADTAP, dev->keybit); /* For X to recognize me as touchpad. */ input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); --- linux-3.13.0.orig/drivers/input/mouse/cypress_ps2.c +++ linux-3.13.0/drivers/input/mouse/cypress_ps2.c @@ -391,7 +391,9 @@ if (ret < 0) return ret; +#if ( CYPRESS_SIMULATED_MT != 1 ) __set_bit(INPUT_PROP_SEMI_MT, input->propbit); +#endif input_abs_set_res(input, ABS_X, cytp->tp_res_x); input_abs_set_res(input, ABS_Y, cytp->tp_res_y); @@ -480,6 +482,22 @@ ((packet[5] & 0x0f) << 8) | packet[7]; if (cytp->mode & CYTP_BIT_ABS_PRESSURE) report_data->contacts[1].z = report_data->contacts[0].z; +#if ( CYPRESS_SIMULATED_MT == 1 ) + /* simulate contact positions for >2 fingers */ + if ( report_data->contact_cnt >= 3 ) { + int i; + for ( i=1; icontact_cnt; i++ ) { + report_data->contacts[i].x = + report_data->contacts[0].x + + 100*(i)*((i%2)?-1:1); + report_data->contacts[i].y = + report_data->contacts[0].y; + if (cytp->mode & CYTP_BIT_ABS_PRESSURE) + report_data->contacts[i].z = + report_data->contacts[0].z; + } + } +#endif } report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0; --- linux-3.13.0.orig/drivers/input/mouse/alps.c +++ linux-3.13.0/drivers/input/mouse/alps.c @@ -277,6 +277,57 @@ } /* + * Process bitmap data for V5 protocols. Return value is null. + * + * The bitmaps don't have enough data to track fingers, so this function + * only generates points representing a bounding box of at most two contacts. + * These two points are returned in x1, y1, x2, and y2. + */ +static void alps_process_bitmap_dolphin(struct alps_data *priv, + struct alps_fields *fields, + int *x1, int *y1, int *x2, int *y2) +{ + int box_middle_x, box_middle_y; + unsigned int x_map, y_map; + unsigned char start_bit, end_bit; + unsigned char x_msb, x_lsb, y_msb, y_lsb; + + x_map = fields->x_map; + y_map = fields->y_map; + + if (!x_map || !y_map) + return; + + /* Get Most-significant and Least-significant bit */ + x_msb = fls(x_map); + x_lsb = ffs(x_map); + y_msb = fls(y_map); + y_lsb = ffs(y_map); + + /* Most-significant bit should never exceed max sensor line number */ + if (x_msb > priv->x_bits || y_msb > priv->y_bits) + return; + + *x1 = *y1 = *x2 = *y2 = 0; + + if (fields->fingers > 1) { + start_bit = priv->x_bits - x_msb; + end_bit = priv->x_bits - x_lsb; + box_middle_x = (priv->x_max * (start_bit + end_bit)) / + (2 * (priv->x_bits - 1)); + + start_bit = y_lsb - 1; + end_bit = y_msb - 1; + box_middle_y = (priv->y_max * (start_bit + end_bit)) / + (2 * (priv->y_bits - 1)); + *x1 = fields->x; + *y1 = fields->y; + *x2 = 2 * box_middle_x - *x1; + *y2 = 2 * box_middle_y - *y1; + } +} + +/* * Process bitmap data from v3 and v4 protocols. Returns the number of * fingers detected. A return value of 0 means at least one of the * bitmaps was empty. @@ -481,7 +532,8 @@ f->ts_middle = !!(p[3] & 0x40); } -static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) +static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, + struct psmouse *psmouse) { f->first_mp = !!(p[4] & 0x40); f->is_mp = !!(p[0] & 0x40); @@ -502,48 +554,61 @@ alps_decode_buttons_v3(f, p); } -static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p) +static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, + struct psmouse *psmouse) { - alps_decode_pinnacle(f, p); + alps_decode_pinnacle(f, p, psmouse); f->x_map |= (p[5] & 0x10) << 11; f->y_map |= (p[5] & 0x20) << 6; } -static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p) +static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, + struct psmouse *psmouse) { + u64 palm_data = 0; + struct alps_data *priv = psmouse->private; + f->first_mp = !!(p[0] & 0x02); f->is_mp = !!(p[0] & 0x20); - f->fingers = ((p[0] & 0x6) >> 1 | + if (!f->is_mp) { + f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); + f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); + f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; + alps_decode_buttons_v3(f, p); + } else { + f->fingers = ((p[0] & 0x6) >> 1 | (p[0] & 0x10) >> 2); - f->x_map = ((p[2] & 0x60) >> 5) | - ((p[4] & 0x7f) << 2) | - ((p[5] & 0x7f) << 9) | - ((p[3] & 0x07) << 16) | - ((p[3] & 0x70) << 15) | - ((p[0] & 0x01) << 22); - f->y_map = (p[1] & 0x7f) | - ((p[2] & 0x1f) << 7); - - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; - alps_decode_buttons_v3(f, p); + palm_data = (p[1] & 0x7f) | + ((p[2] & 0x7f) << 7) | + ((p[4] & 0x7f) << 14) | + ((p[5] & 0x7f) << 21) | + ((p[3] & 0x07) << 28) | + (((u64)p[3] & 0x70) << 27) | + (((u64)p[0] & 0x01) << 34); + + /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ + f->y_map = palm_data & (BIT(priv->y_bits) - 1); + + /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ + f->x_map = (palm_data >> priv->y_bits) & + (BIT(priv->x_bits) - 1); + } } -static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) +static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; struct input_dev *dev2 = priv->dev2; int x1 = 0, y1 = 0, x2 = 0, y2 = 0; - int fingers = 0, bmap_fingers; - struct alps_fields f; + int fingers = 0, bmap_fn; + struct alps_fields f = {0}; - priv->decode_fields(&f, packet); + priv->decode_fields(&f, packet, psmouse); /* * There's no single feature of touchpad position and bitmap packets @@ -560,19 +625,38 @@ */ if (f.is_mp) { fingers = f.fingers; - bmap_fingers = alps_process_bitmap(priv, - f.x_map, f.y_map, - &x1, &y1, &x2, &y2); - - /* - * We shouldn't report more than one finger if - * we don't have two coordinates. - */ - if (fingers > 1 && bmap_fingers < 2) - fingers = bmap_fingers; - - /* Now process position packet */ - priv->decode_fields(&f, priv->multi_data); + if (priv->proto_version == ALPS_PROTO_V3) { + bmap_fn = alps_process_bitmap(priv, f.x_map, + f.y_map, &x1, &y1, + &x2, &y2); + + /* + * We shouldn't report more than one finger if + * we don't have two coordinates. + */ + if (fingers > 1 && bmap_fn < 2) + fingers = bmap_fn; + + /* Now process position packet */ + priv->decode_fields(&f, priv->multi_data, + psmouse); + } else { + /* + * Because Dolphin uses position packet's + * coordinate data as Pt1 and uses it to + * calculate Pt2, so we need to do position + * packet decode first. + */ + priv->decode_fields(&f, priv->multi_data, + psmouse); + + /* + * Since Dolphin's finger number is reliable, + * there is no need to compare with bmap_fn. + */ + alps_process_bitmap_dolphin(priv, &f, &x1, &y1, + &x2, &y2); + } } else { priv->multi_packet = 0; } @@ -662,7 +746,7 @@ return; } - alps_process_touchpad_packet_v3(psmouse); + alps_process_touchpad_packet_v3_v5(psmouse); } static void alps_process_packet_v6(struct psmouse *psmouse) @@ -1709,6 +1793,52 @@ return -1; } +static int alps_dolphin_get_device_area(struct psmouse *psmouse, + struct alps_data *priv) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[4] = {0}; + int num_x_electrode, num_y_electrode; + + if (alps_enter_command_mode(psmouse)) + return -1; + + param[0] = 0x0a; + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || + ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || + ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE)) + return -1; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + return -1; + + /* + * Dolphin's sensor line number is not fixed. It can be calculated + * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. + * Further more, we can get device's x_max and y_max by multiplying + * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. + * + * e.g. When we get register's sensor_x = 11 & sensor_y = 8, + * real sensor line number X = 11 + 8 = 19, and + * real sensor line number Y = 8 + 1 = 9. + * So, x_max = (19 - 1) * 64 = 1152, and + * y_max = (9 - 1) * 64 = 512. + */ + num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F); + num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F); + priv->x_bits = num_x_electrode; + priv->y_bits = num_y_electrode; + priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; + priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; + + if (alps_exit_command_mode(psmouse)) + return -1; + + return 0; +} + static int alps_hw_init_dolphin_v1(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; @@ -1763,13 +1893,13 @@ break; case ALPS_PROTO_V5: priv->hw_init = alps_hw_init_dolphin_v1; - priv->process_packet = alps_process_packet_v3; + priv->process_packet = alps_process_touchpad_packet_v3_v5; priv->decode_fields = alps_decode_dolphin; priv->set_abs_params = alps_set_abs_params_mt; priv->nibble_commands = alps_v3_nibble_commands; priv->addr_command = PSMOUSE_CMD_RESET_WRAP; priv->byte0 = 0xc8; - priv->mask0 = 0xc8; + priv->mask0 = 0xd8; priv->flags = 0; priv->x_max = 1360; priv->y_max = 660; @@ -1845,11 +1975,13 @@ if (alps_match_table(psmouse, priv, e7, ec) == 0) { return 0; } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && - ec[0] == 0x73 && ec[1] == 0x01) { + ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { priv->proto_version = ALPS_PROTO_V5; alps_set_defaults(priv); - - return 0; + if (alps_dolphin_get_device_area(psmouse, priv)) + return -EIO; + else + return 0; } else if (ec[0] == 0x88 && ec[1] == 0x08) { priv->proto_version = ALPS_PROTO_V3; alps_set_defaults(priv); --- linux-3.13.0.orig/drivers/tty/n_tty.c +++ linux-3.13.0/drivers/tty/n_tty.c @@ -813,8 +813,7 @@ struct n_tty_data *ldata = tty->disc_data; size_t echoed; - if ((!L_ECHO(tty) && !L_ECHONL(tty)) || - ldata->echo_mark == ldata->echo_tail) + if (ldata->echo_mark == ldata->echo_tail) return; mutex_lock(&ldata->output_lock); @@ -1238,7 +1237,8 @@ if (L_ECHO(tty)) { echo_char(c, tty); commit_echoes(tty); - } + } else + process_echoes(tty); isig(signal, tty); return; } @@ -1269,7 +1269,7 @@ if (I_IXON(tty)) { if (c == START_CHAR(tty)) { start_tty(tty); - commit_echoes(tty); + process_echoes(tty); return 0; } if (c == STOP_CHAR(tty)) { @@ -1821,8 +1821,10 @@ * Fix tty hang when I_IXON(tty) is cleared, but the tty * been stopped by STOP_CHAR(tty) before it. */ - if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) + if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) { start_tty(tty); + process_echoes(tty); + } /* The termios change make the tty ready for I/O */ wake_up_interruptible(&tty->write_wait); --- linux-3.13.0.orig/drivers/tty/Kconfig +++ linux-3.13.0/drivers/tty/Kconfig @@ -366,7 +366,7 @@ "Trace data router for MIPI P1149.7 cJTAG standard". config PPC_EPAPR_HV_BYTECHAN - tristate "ePAPR hypervisor byte channel driver" + bool "ePAPR hypervisor byte channel driver" depends on PPC select EPAPR_PARAVIRT help --- linux-3.13.0.orig/drivers/tty/n_gsm.c +++ linux-3.13.0/drivers/tty/n_gsm.c @@ -1089,6 +1089,7 @@ { unsigned int addr = 0; unsigned int modem = 0; + unsigned int brk = 0; struct gsm_dlci *dlci; int len = clen; u8 *dp = data; @@ -1115,6 +1116,16 @@ if (len == 0) return; } + len--; + if (len > 0) { + while (gsm_read_ea(&brk, *dp++) == 0) { + len--; + if (len == 0) + return; + } + modem <<= 7; + modem |= (brk & 0x7f); + } tty = tty_port_tty_get(&dlci->port); gsm_process_modem(tty, dlci, modem, clen); if (tty) { --- linux-3.13.0.orig/drivers/tty/vt/vt.c +++ linux-3.13.0/drivers/tty/vt/vt.c @@ -1164,6 +1164,8 @@ scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, vc->vc_screenbuf_size >> 1); set_origin(vc); + if (CON_IS_VISIBLE(vc)) + update_screen(vc); /* fall through */ case 2: /* erase whole display */ count = vc->vc_cols * vc->vc_rows; --- linux-3.13.0.orig/drivers/tty/serial/omap-serial.c +++ linux-3.13.0/drivers/tty/serial/omap-serial.c @@ -738,9 +738,6 @@ return retval; } disable_irq(up->wakeirq); - } else { - dev_info(up->port.dev, "no wakeirq for uart%d\n", - up->port.line); } dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); @@ -1687,6 +1684,9 @@ up->port.iotype = UPIO_MEM; up->port.irq = uartirq; up->wakeirq = wakeirq; + if (!up->wakeirq) + dev_info(up->port.dev, "no wakeirq for uart%d\n", + up->port.line); up->port.regshift = 2; up->port.fifosize = 64; --- linux-3.13.0.orig/drivers/tty/serial/sirfsoc_uart.c +++ linux-3.13.0/drivers/tty/serial/sirfsoc_uart.c @@ -540,8 +540,10 @@ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | SIRFUART_IO_MODE); - sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); spin_unlock_irqrestore(&sirfport->rx_lock, flags); + spin_lock(&port->lock); + sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); + spin_unlock(&port->lock); if (sirfport->rx_io_count == 4) { spin_lock_irqsave(&sirfport->rx_lock, flags); sirfport->rx_io_count = 0; --- linux-3.13.0.orig/drivers/tty/serial/amba-pl011.c +++ linux-3.13.0/drivers/tty/serial/amba-pl011.c @@ -1537,6 +1537,8 @@ /* * Provoke TX FIFO interrupt into asserting. */ + spin_lock_irq(&uap->port.lock); + cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; writew(cr, uap->port.membase + UART011_CR); writew(0, uap->port.membase + UART011_FBRD); @@ -1561,6 +1563,8 @@ cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; writew(cr, uap->port.membase + UART011_CR); + spin_unlock_irq(&uap->port.lock); + /* * initialise the old status of the modem signals */ @@ -1629,11 +1633,13 @@ * it during startup(). */ uap->autorts = false; + spin_lock_irq(&uap->port.lock); cr = readw(uap->port.membase + UART011_CR); uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; writew(cr, uap->port.membase + UART011_CR); + spin_unlock_irq(&uap->port.lock); /* * disable break condition and fifos --- linux-3.13.0.orig/drivers/tty/serial/atmel_serial.c +++ linux-3.13.0/drivers/tty/serial/atmel_serial.c @@ -825,9 +825,6 @@ atmel_port->desc_rx = NULL; atmel_port->chan_rx = NULL; atmel_port->cookie_rx = -EINVAL; - - if (!atmel_port->is_usart) - del_timer_sync(&atmel_port->uart_timer); } static void atmel_rx_from_dma(struct uart_port *port) @@ -1229,9 +1226,6 @@ DMA_FROM_DEVICE); kfree(pdc->buf); } - - if (!atmel_port->is_usart) - del_timer_sync(&atmel_port->uart_timer); } static void atmel_rx_from_pdc(struct uart_port *port) @@ -1604,12 +1598,13 @@ /* enable xmit & rcvr */ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + setup_timer(&atmel_port->uart_timer, + atmel_uart_timer_callback, + (unsigned long)port); + if (atmel_use_pdc_rx(port)) { /* set UART timeout */ if (!atmel_port->is_usart) { - setup_timer(&atmel_port->uart_timer, - atmel_uart_timer_callback, - (unsigned long)port); mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); /* set USART timeout */ @@ -1624,9 +1619,6 @@ } else if (atmel_use_dma_rx(port)) { /* set UART timeout */ if (!atmel_port->is_usart) { - setup_timer(&atmel_port->uart_timer, - atmel_uart_timer_callback, - (unsigned long)port); mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); /* set USART timeout */ @@ -1650,12 +1642,30 @@ static void atmel_shutdown(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* - * Ensure everything is stopped. + * Prevent any tasklets being scheduled during + * cleanup + */ + del_timer_sync(&atmel_port->uart_timer); + + /* + * Clear out any scheduled tasklets before + * we destroy the buffers + */ + tasklet_kill(&atmel_port->tasklet); + + /* + * Ensure everything is stopped and + * disable all interrupts, port and break condition. */ atmel_stop_rx(port); atmel_stop_tx(port); + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, -1); + + /* * Shut-down the DMA. */ @@ -1665,10 +1675,10 @@ atmel_port->release_tx(port); /* - * Disable all interrupts, port and break condition. + * Reset ring buffer pointers */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, -1); + atmel_port->rx_ring.head = 0; + atmel_port->rx_ring.tail = 0; /* * Free the interrupt @@ -2441,11 +2451,12 @@ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int ret = 0; + tasklet_kill(&atmel_port->tasklet); + device_init_wakeup(&pdev->dev, 0); ret = uart_remove_one_port(&atmel_uart, port); - tasklet_kill(&atmel_port->tasklet); kfree(atmel_port->rx_ring.buf); /* "port" is allocated statically, so we shouldn't free it */ --- linux-3.13.0.orig/drivers/tty/serial/8250/8250_core.c +++ linux-3.13.0/drivers/tty/serial/8250/8250_core.c @@ -2670,6 +2670,10 @@ if (port->type == PORT_16550A && port->iotype == UPIO_AU) up->bugs |= UART_BUG_NOMSR; + /* HW bugs may trigger IRQ while IIR == NO_INT */ + if (port->type == PORT_TEGRA) + up->bugs |= UART_BUG_NOMSR; + if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); --- linux-3.13.0.orig/drivers/tty/serial/8250/8250_pci.c +++ linux-3.13.0/drivers/tty/serial/8250/8250_pci.c @@ -1259,10 +1259,10 @@ unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; - outl(inl(base + 0x38), base + 0x38); + outl(inl(base + 0x38) | 0x00002000, base + 0x38); tmp = inl(base + 0x3c); outl(tmp | 0x01000000, base + 0x3c); - outl(tmp, base + 0x3c); + outl(tmp &= ~0x01000000, base + 0x3c); } } return 0; @@ -1744,6 +1744,7 @@ #define PCI_DEVICE_ID_TITAN_800E 0xA014 #define PCI_DEVICE_ID_TITAN_200EI 0xA016 #define PCI_DEVICE_ID_TITAN_200EISI 0xA017 +#define PCI_DEVICE_ID_TITAN_200V3 0xA306 #define PCI_DEVICE_ID_TITAN_400V3 0xA310 #define PCI_DEVICE_ID_TITAN_410V3 0xA312 #define PCI_DEVICE_ID_TITAN_800V3 0xA314 @@ -4427,6 +4428,9 @@ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_921600 }, --- linux-3.13.0.orig/drivers/media/dvb-core/dvb-usb-ids.h +++ linux-3.13.0/drivers/media/dvb-core/dvb-usb-ids.h @@ -239,6 +239,7 @@ #define USB_PID_AVERMEDIA_A835B_4835 0x4835 #define USB_PID_AVERMEDIA_1867 0x1867 #define USB_PID_AVERMEDIA_A867 0xa867 +#define USB_PID_AVERMEDIA_H335 0x0335 #define USB_PID_AVERMEDIA_TWINSTAR 0x0825 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 --- linux-3.13.0.orig/drivers/media/usb/uvc/uvc_driver.c +++ linux-3.13.0/drivers/media/usb/uvc/uvc_driver.c @@ -2210,6 +2210,15 @@ .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_DEF }, + /* Alienware X51*/ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x05a9, + .idProduct = 0x2643, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_DEF }, /* Apple Built-In iSight */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, --- linux-3.13.0.orig/drivers/media/usb/dvb-usb/cxusb.c +++ linux-3.13.0/drivers/media/usb/dvb-usb/cxusb.c @@ -149,6 +149,7 @@ int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; int i; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) @@ -173,7 +174,8 @@ if (1 + msg[i].len > sizeof(ibuf)) { warn("i2c rd: len=%d is too big!\n", msg[i].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = 0; obuf[1] = msg[i].len; @@ -193,12 +195,14 @@ if (3 + msg[i].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[i].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } if (1 + msg[i + 1].len > sizeof(ibuf)) { warn("i2c rd: len=%d is too big!\n", msg[i + 1].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[i].len; obuf[1] = msg[i+1].len; @@ -223,7 +227,8 @@ if (2 + msg[i].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[i].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[i].addr; obuf[1] = msg[i].len; @@ -237,8 +242,14 @@ } } + if (i == num) + ret = num; + else + ret = -EREMOTEIO; + +unlock: mutex_unlock(&d->i2c_mutex); - return i == num ? num : -EREMOTEIO; + return ret; } static u32 cxusb_i2c_func(struct i2c_adapter *adapter) --- linux-3.13.0.orig/drivers/media/usb/dvb-usb/dw2102.c +++ linux-3.13.0/drivers/media/usb/dvb-usb/dw2102.c @@ -301,6 +301,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; if (!d) return -ENODEV; @@ -316,7 +317,8 @@ if (2 + msg[1].len > sizeof(ibuf)) { warn("i2c rd: len=%d is too big!\n", msg[1].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[0].addr << 1; @@ -340,7 +342,8 @@ if (2 + msg[0].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[1].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[0].addr << 1; @@ -357,7 +360,8 @@ if (2 + msg[0].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[1].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[0].addr << 1; @@ -386,15 +390,17 @@ break; } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int len, i, j; + int len, i, j, ret; if (!d) return -ENODEV; @@ -430,7 +436,8 @@ if (2 + msg[j].len > sizeof(ibuf)) { warn("i2c rd: len=%d is too big!\n", msg[j].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } dw210x_op_rw(d->udev, 0xc3, @@ -466,7 +473,8 @@ if (2 + msg[j].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[j].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[j].addr << 1; @@ -481,15 +489,18 @@ } } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; int i; if (!d) @@ -506,7 +517,8 @@ if (2 + msg[1].len > sizeof(ibuf)) { warn("i2c rd: len=%d is too big!\n", msg[1].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; @@ -530,7 +542,8 @@ if (2 + msg[0].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[0].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; @@ -556,9 +569,11 @@ msg[i].flags == 0 ? ">>>" : "<<<"); debug_dump(msg[i].buf, msg[i].len, deb_xfer); } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], @@ -566,7 +581,7 @@ { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct usb_device *udev; - int len, i, j; + int len, i, j, ret; if (!d) return -ENODEV; @@ -618,7 +633,8 @@ if (msg[j].len > sizeof(ibuf)) { warn("i2c rd: len=%d is too big!\n", msg[j].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } dw210x_op_rw(d->udev, 0x91, 0, 0, @@ -652,7 +668,8 @@ if (2 + msg[j].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[j].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[j + 1].len; @@ -671,7 +688,8 @@ if (2 + msg[j].len > sizeof(obuf)) { warn("i2c wr: len=%d is too big!\n", msg[j].len); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto unlock; } obuf[0] = msg[j].len + 1; obuf[1] = (msg[j].addr << 1); @@ -685,9 +703,11 @@ } } } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], --- linux-3.13.0.orig/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ linux-3.13.0/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -105,7 +105,7 @@ ret = -EINVAL; } - pr_debug("R: (0x%02x, 0x%02x)\n", addr, *data); + pr_debug("R: (0x%02x, 0x%02x)\n", addr, buf[1]); fail: return ret; } --- linux-3.13.0.orig/drivers/media/usb/dvb-usb-v2/it913x.c +++ linux-3.13.0/drivers/media/usb/dvb-usb-v2/it913x.c @@ -799,6 +799,9 @@ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2", RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335, + &it913x_properties, "Avermedia H335", + RC_MAP_IT913X_V2) }, {} /* Terminating entry */ }; --- linux-3.13.0.orig/drivers/media/usb/dvb-usb-v2/af9035.c +++ linux-3.13.0/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1539,6 +1539,8 @@ &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05, &af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900, + &af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); --- linux-3.13.0.orig/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h +++ linux-3.13.0/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h @@ -68,7 +68,7 @@ #else static inline struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state + struct mxl111sf_state *mxl_state, struct mxl111sf_tuner_config *cfg) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); --- linux-3.13.0.orig/drivers/media/usb/dvb-usb-v2/anysee.c +++ linux-3.13.0/drivers/media/usb/dvb-usb-v2/anysee.c @@ -442,6 +442,7 @@ * IOD[0] ZL10353 1=enabled * IOE[0] tuner 0=enabled * tuner is behind ZL10353 I2C-gate + * tuner is behind TDA10023 I2C-gate * * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" * PCB: 508TC (rev0.6) @@ -956,7 +957,7 @@ if (fe && adap->fe[1]) { /* attach tuner for 2nd FE */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], + fe = dvb_attach(dvb_pll_attach, adap->fe[1], (0xc0 >> 1), &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); } --- linux-3.13.0.orig/drivers/media/pci/cx18/cx18-driver.c +++ linux-3.13.0/drivers/media/pci/cx18/cx18-driver.c @@ -327,13 +327,16 @@ struct i2c_client *c; u8 eedata[256]; + memset(tv, 0, sizeof(*tv)); + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return; strlcpy(c->name, "cx18 tveeprom tmp", sizeof(c->name)); c->adapter = &cx->i2c_adap[0]; c->addr = 0xa0 >> 1; - memset(tv, 0, sizeof(*tv)); if (tveeprom_read(c, eedata, sizeof(eedata))) goto ret; --- linux-3.13.0.orig/drivers/media/dvb-frontends/m88rs2000.c +++ linux-3.13.0/drivers/media/dvb-frontends/m88rs2000.c @@ -110,28 +110,94 @@ return b1[0]; } +static u32 m88rs2000_get_mclk(struct dvb_frontend *fe) +{ + struct m88rs2000_state *state = fe->demodulator_priv; + u32 mclk; + u8 reg; + /* Must not be 0x00 or 0xff */ + reg = m88rs2000_readreg(state, 0x86); + if (!reg || reg == 0xff) + return 0; + + reg /= 2; + reg += 1; + + mclk = (u32)(reg * RS2000_FE_CRYSTAL_KHZ + 28 / 2) / 28; + + return mclk; +} + +static int m88rs2000_set_carrieroffset(struct dvb_frontend *fe, s16 offset) +{ + struct m88rs2000_state *state = fe->demodulator_priv; + u32 mclk; + s32 tmp; + u8 reg; + int ret; + + mclk = m88rs2000_get_mclk(fe); + if (!mclk) + return -EINVAL; + + tmp = (offset * 4096 + (s32)mclk / 2) / (s32)mclk; + if (tmp < 0) + tmp += 4096; + + /* Carrier Offset */ + ret = m88rs2000_writereg(state, 0x9c, (u8)(tmp >> 4)); + + reg = m88rs2000_readreg(state, 0x9d); + reg &= 0xf; + reg |= (u8)(tmp & 0xf) << 4; + + ret |= m88rs2000_writereg(state, 0x9d, reg); + + return ret; +} + static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate) { struct m88rs2000_state *state = fe->demodulator_priv; int ret; - u32 temp; + u64 temp; + u32 mclk; u8 b[3]; if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; + mclk = m88rs2000_get_mclk(fe); + if (!mclk) + return -EINVAL; + temp = srate / 1000; - temp *= 11831; - temp /= 68; - temp -= 3; + temp *= 1 << 24; + + do_div(temp, mclk); b[0] = (u8) (temp >> 16) & 0xff; b[1] = (u8) (temp >> 8) & 0xff; b[2] = (u8) temp & 0xff; + ret = m88rs2000_writereg(state, 0x93, b[2]); ret |= m88rs2000_writereg(state, 0x94, b[1]); ret |= m88rs2000_writereg(state, 0x95, b[0]); + if (srate > 10000000) + ret |= m88rs2000_writereg(state, 0xa0, 0x20); + else + ret |= m88rs2000_writereg(state, 0xa0, 0x60); + + ret |= m88rs2000_writereg(state, 0xa1, 0xe0); + + if (srate > 12000000) + ret |= m88rs2000_writereg(state, 0xa3, 0x20); + else if (srate > 2800000) + ret |= m88rs2000_writereg(state, 0xa3, 0x98); + else + ret |= m88rs2000_writereg(state, 0xa3, 0x90); + deb_info("m88rs2000: m88rs2000_set_symbolrate\n"); return ret; } @@ -261,8 +327,6 @@ struct inittab fe_reset[] = { {DEMOD_WRITE, 0x00, 0x01}, - {DEMOD_WRITE, 0xf1, 0xbf}, - {DEMOD_WRITE, 0x00, 0x01}, {DEMOD_WRITE, 0x20, 0x81}, {DEMOD_WRITE, 0x21, 0x80}, {DEMOD_WRITE, 0x10, 0x33}, @@ -305,9 +369,6 @@ {DEMOD_WRITE, 0x9b, 0x64}, {DEMOD_WRITE, 0x9e, 0x00}, {DEMOD_WRITE, 0x9f, 0xf8}, - {DEMOD_WRITE, 0xa0, 0x20}, - {DEMOD_WRITE, 0xa1, 0xe0}, - {DEMOD_WRITE, 0xa3, 0x38}, {DEMOD_WRITE, 0x98, 0xff}, {DEMOD_WRITE, 0xc0, 0x0f}, {DEMOD_WRITE, 0x89, 0x01}, @@ -540,9 +601,8 @@ struct dtv_frontend_properties *c = &fe->dtv_property_cache; fe_status_t status; int i, ret = 0; - s32 tmp; u32 tuner_freq; - u16 offset = 0; + s16 offset = 0; u8 reg; state->no_lock_count = 0; @@ -567,29 +627,26 @@ if (ret < 0) return -ENODEV; - offset = tuner_freq - c->frequency; - - /* calculate offset assuming 96000kHz*/ - tmp = offset; - tmp *= 65536; - - tmp = (2 * tmp + 96000) / (2 * 96000); - if (tmp < 0) - tmp += 65536; + offset = (s16)((s32)tuner_freq - c->frequency); - offset = tmp & 0xffff; + /* default mclk value 96.4285 * 2 * 1000 = 192857 */ + if (((c->frequency % 192857) >= (192857 - 3000)) || + (c->frequency % 192857) <= 3000) + ret = m88rs2000_writereg(state, 0x86, 0xc2); + else + ret = m88rs2000_writereg(state, 0x86, 0xc6); - ret = m88rs2000_writereg(state, 0x9a, 0x30); - /* Unknown usually 0xc6 sometimes 0xc1 */ - reg = m88rs2000_readreg(state, 0x86); - ret |= m88rs2000_writereg(state, 0x86, reg); - /* Offset lower nibble always 0 */ - ret |= m88rs2000_writereg(state, 0x9c, (offset >> 8)); - ret |= m88rs2000_writereg(state, 0x9d, offset & 0xf0); + ret |= m88rs2000_set_carrieroffset(fe, offset); + if (ret < 0) + return -ENODEV; + /* Reset demod by symbol rate */ + if (c->symbol_rate > 27500000) + ret = m88rs2000_writereg(state, 0xf1, 0xa4); + else + ret = m88rs2000_writereg(state, 0xf1, 0xbf); - /* Reset Demod */ - ret = m88rs2000_tab_set(state, fe_reset); + ret |= m88rs2000_tab_set(state, fe_reset); if (ret < 0) return -ENODEV; --- linux-3.13.0.orig/drivers/media/dvb-frontends/m88rs2000.h +++ linux-3.13.0/drivers/media/dvb-frontends/m88rs2000.h @@ -53,6 +53,8 @@ } #endif /* CONFIG_DVB_M88RS2000 */ +#define RS2000_FE_CRYSTAL_KHZ 27000 + enum { DEMOD_WRITE = 0x1, WRITE_DELAY = 0x10, --- linux-3.13.0.orig/drivers/media/dvb-frontends/cx24117.c +++ linux-3.13.0/drivers/media/dvb-frontends/cx24117.c @@ -1166,7 +1166,7 @@ switch (demod) { case 0: - dev_err(&state->priv->i2c->dev, + dev_err(&i2c->dev, "%s: Error attaching frontend %d\n", KBUILD_MODNAME, demod); goto error1; --- linux-3.13.0.orig/drivers/media/dvb-frontends/nxt200x.c +++ linux-3.13.0/drivers/media/dvb-frontends/nxt200x.c @@ -40,7 +40,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 +#define MAX_XFER_SIZE 256 #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" #define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" --- linux-3.13.0.orig/drivers/media/dvb-frontends/dib8000.c +++ linux-3.13.0/drivers/media/dvb-frontends/dib8000.c @@ -157,15 +157,10 @@ return ret; } -static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) +static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg) { u16 ret; - if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); - return 0; - } - state->i2c_write_buffer[0] = reg >> 8; state->i2c_write_buffer[1] = reg & 0xff; @@ -183,6 +178,21 @@ dprintk("i2c read error on %d", reg); ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + + return ret; +} + +static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) +{ + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + + ret = __dib8000_read_word(state, reg); + mutex_unlock(&state->i2c_buffer_lock); return ret; @@ -192,8 +202,15 @@ { u16 rw[2]; - rw[0] = dib8000_read_word(state, reg + 0); - rw[1] = dib8000_read_word(state, reg + 1); + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + + rw[0] = __dib8000_read_word(state, reg + 0); + rw[1] = __dib8000_read_word(state, reg + 1); + + mutex_unlock(&state->i2c_buffer_lock); return ((rw[0] << 16) | (rw[1])); } @@ -2445,7 +2462,8 @@ if (state->revision == 0x8090) internal = dib8000_read32(state, 23) / 1000; - if (state->autosearch_state == AS_SEARCHING_FFT) { + if ((state->revision >= 0x8002) && + (state->autosearch_state == AS_SEARCHING_FFT)) { dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ @@ -2481,7 +2499,8 @@ dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ - } else if (state->autosearch_state == AS_SEARCHING_GUARD) { + } else if ((state->revision >= 0x8002) && + (state->autosearch_state == AS_SEARCHING_GUARD)) { c->transmission_mode = TRANSMISSION_MODE_8K; c->guard_interval = GUARD_INTERVAL_1_8; c->inversion = 0; @@ -2583,7 +2602,8 @@ struct dib8000_state *state = fe->demodulator_priv; u16 irq_pending = dib8000_read_word(state, 1284); - if (state->autosearch_state == AS_SEARCHING_FFT) { + if ((state->revision >= 0x8002) && + (state->autosearch_state == AS_SEARCHING_FFT)) { if (irq_pending & 0x1) { dprintk("dib8000_autosearch_irq: max correlation result available"); return 3; --- linux-3.13.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ linux-3.13.0/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -177,21 +177,6 @@ mutex_unlock(&dev->mfc_mutex); } -static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - - if (!vdev) { - mfc_err("failed to get video_device"); - return MFCNODE_INVALID; - } - if (vdev->index == 0) - return MFCNODE_DECODER; - else if (vdev->index == 1) - return MFCNODE_ENCODER; - return MFCNODE_INVALID; -} - static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) { mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); @@ -705,6 +690,7 @@ /* Open an MFC node */ static int s5p_mfc_open(struct file *file) { + struct video_device *vdev = video_devdata(file); struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = NULL; struct vb2_queue *q; @@ -742,7 +728,7 @@ /* Mark context as idle */ clear_work_bit_irqsave(ctx); dev->ctx[ctx->num] = ctx; - if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { + if (vdev == dev->vfd_dec) { ctx->type = MFCINST_DECODER; ctx->c_ops = get_dec_codec_ops(); s5p_mfc_dec_init(ctx); @@ -752,7 +738,7 @@ mfc_err("Failed to setup mfc controls\n"); goto err_ctrls_setup; } - } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { + } else if (vdev == dev->vfd_enc) { ctx->type = MFCINST_ENCODER; ctx->c_ops = get_enc_codec_ops(); /* only for encoder */ @@ -797,10 +783,10 @@ q = &ctx->vq_dst; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; q->drv_priv = &ctx->fh; - if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { + if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; q->ops = get_dec_queue_ops(); - } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { + } else if (vdev == dev->vfd_enc) { q->io_modes = VB2_MMAP | VB2_USERPTR; q->ops = get_enc_queue_ops(); } else { @@ -819,10 +805,10 @@ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; q->io_modes = VB2_MMAP; q->drv_priv = &ctx->fh; - if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { + if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; q->ops = get_dec_queue_ops(); - } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { + } else if (vdev == dev->vfd_enc) { q->io_modes = VB2_MMAP | VB2_USERPTR; q->ops = get_enc_queue_ops(); } else { --- linux-3.13.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ linux-3.13.0/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -115,15 +115,6 @@ }; /** - * enum s5p_mfc_node_type - The type of an MFC device node. - */ -enum s5p_mfc_node_type { - MFCNODE_INVALID = -1, - MFCNODE_DECODER = 0, - MFCNODE_ENCODER = 1, -}; - -/** * enum s5p_mfc_inst_type - The type of an MFC instance. */ enum s5p_mfc_inst_type { --- linux-3.13.0.orig/drivers/media/v4l2-core/v4l2-dev.c +++ linux-3.13.0/drivers/media/v4l2-core/v4l2-dev.c @@ -872,8 +872,8 @@ /* Should not happen since we thought this minor was free */ WARN_ON(video_device[vdev->minor] != NULL); - video_device[vdev->minor] = vdev; vdev->index = get_index(vdev); + video_device[vdev->minor] = vdev; mutex_unlock(&videodev_lock); if (vdev->ioctl_ops) --- linux-3.13.0.orig/drivers/media/v4l2-core/videobuf-dma-sg.c +++ linux-3.13.0/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -338,14 +338,11 @@ static void videobuf_vm_open(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); - videobuf_queue_lock(q); map->count++; - videobuf_queue_unlock(q); } static void videobuf_vm_close(struct vm_area_struct *vma) @@ -358,9 +355,10 @@ dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); - videobuf_queue_lock(q); - if (!--map->count) { + map->count--; + if (0 == map->count) { dprintk(1, "munmap %p q=%p\n", map, q); + videobuf_queue_lock(q); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; @@ -376,9 +374,9 @@ q->bufs[i]->baddr = 0; q->ops->buf_release(q, q->bufs[i]); } + videobuf_queue_unlock(q); kfree(map); } - videobuf_queue_unlock(q); return; } --- linux-3.13.0.orig/drivers/media/v4l2-core/videobuf-vmalloc.c +++ linux-3.13.0/drivers/media/v4l2-core/videobuf-vmalloc.c @@ -54,14 +54,11 @@ static void videobuf_vm_open(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); - videobuf_queue_lock(q); map->count++; - videobuf_queue_unlock(q); } static void videobuf_vm_close(struct vm_area_struct *vma) @@ -73,11 +70,12 @@ dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); - videobuf_queue_lock(q); - if (!--map->count) { + map->count--; + if (0 == map->count) { struct videobuf_vmalloc_memory *mem; dprintk(1, "munmap %p q=%p\n", map, q); + videobuf_queue_lock(q); /* We need first to cancel streams, before unmapping */ if (q->streaming) @@ -116,8 +114,8 @@ kfree(map); + videobuf_queue_unlock(q); } - videobuf_queue_unlock(q); return; } --- linux-3.13.0.orig/drivers/media/v4l2-core/videobuf-dma-contig.c +++ linux-3.13.0/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -66,14 +66,11 @@ static void videobuf_vm_open(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - dev_dbg(q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", + dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); - videobuf_queue_lock(q); map->count++; - videobuf_queue_unlock(q); } static void videobuf_vm_close(struct vm_area_struct *vma) @@ -85,11 +82,12 @@ dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); - videobuf_queue_lock(q); - if (!--map->count) { + map->count--; + if (0 == map->count) { struct videobuf_dma_contig_memory *mem; dev_dbg(q->dev, "munmap %p q=%p\n", map, q); + videobuf_queue_lock(q); /* We need first to cancel streams, before unmapping */ if (q->streaming) @@ -128,8 +126,8 @@ kfree(map); + videobuf_queue_unlock(q); } - videobuf_queue_unlock(q); } static const struct vm_operations_struct videobuf_vm_ops = { --- linux-3.13.0.orig/drivers/uio/uio.c +++ linux-3.13.0/drivers/uio/uio.c @@ -847,7 +847,7 @@ info->uio_dev = idev; if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { - ret = devm_request_irq(parent, info->irq, uio_interrupt, + ret = devm_request_irq(idev->dev, info->irq, uio_interrupt, info->irq_flags, info->name, idev); if (ret) goto err_request_irq; --- linux-3.13.0.orig/drivers/hv/vmbus_drv.c +++ linux-3.13.0/drivers/hv/vmbus_drv.c @@ -46,6 +46,12 @@ static struct completion probe_event; static int irq; +struct resource hyperv_mmio = { + .name = "hyperv mmio", + .flags = IORESOURCE_MEM, +}; +EXPORT_SYMBOL_GPL(hyperv_mmio); + static int vmbus_exists(void) { if (hv_acpi_dev == NULL) @@ -888,18 +894,21 @@ /* - * VMBUS is an acpi enumerated device. Get the the IRQ information - * from DSDT. + * VMBUS is an acpi enumerated device. Get the the information we + * need from DSDT. */ -static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq) +static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) { + switch (res->type) { + case ACPI_RESOURCE_TYPE_IRQ: + irq = res->data.irq.interrupts[0]; + break; - if (res->type == ACPI_RESOURCE_TYPE_IRQ) { - struct acpi_resource_irq *irqp; - irqp = &res->data.irq; - - *((unsigned int *)irq) = irqp->interrupts[0]; + case ACPI_RESOURCE_TYPE_ADDRESS64: + hyperv_mmio.start = res->data.address64.minimum; + hyperv_mmio.end = res->data.address64.maximum; + break; } return AE_OK; @@ -908,18 +917,34 @@ static int vmbus_acpi_add(struct acpi_device *device) { acpi_status result; + int ret_val = -ENODEV; hv_acpi_dev = device; result = acpi_walk_resources(device->handle, METHOD_NAME__CRS, - vmbus_walk_resources, &irq); + vmbus_walk_resources, NULL); - if (ACPI_FAILURE(result)) { - complete(&probe_event); - return -ENODEV; + if (ACPI_FAILURE(result)) + goto acpi_walk_err; + /* + * The parent of the vmbus acpi device (Gen2 firmware) is the VMOD that + * has the mmio ranges. Get that. + */ + if (device->parent) { + result = acpi_walk_resources(device->parent->handle, + METHOD_NAME__CRS, + vmbus_walk_resources, NULL); + + if (ACPI_FAILURE(result)) + goto acpi_walk_err; + if (hyperv_mmio.start && hyperv_mmio.end) + request_resource(&iomem_resource, &hyperv_mmio); } + ret_val = 0; + +acpi_walk_err: complete(&probe_event); - return 0; + return ret_val; } static const struct acpi_device_id vmbus_acpi_device_ids[] = { --- linux-3.13.0.orig/drivers/hv/hyperv_vmbus.h +++ linux-3.13.0/drivers/hv/hyperv_vmbus.h @@ -669,5 +669,9 @@ void vmbus_on_event(unsigned long data); +int hv_fcopy_init(struct hv_util_service *); +void hv_fcopy_deinit(void); +void hv_fcopy_onchannelcallback(void *); + #endif /* _HYPERV_VMBUS_H */ --- linux-3.13.0.orig/drivers/hv/hv_util.c +++ linux-3.13.0/drivers/hv/hv_util.c @@ -28,6 +28,7 @@ #include #include +#include "hyperv_vmbus.h" #define SD_MAJOR 3 #define SD_MINOR 0 @@ -82,6 +83,12 @@ .util_deinit = hv_vss_deinit, }; +static struct hv_util_service util_fcopy = { + .util_cb = hv_fcopy_onchannelcallback, + .util_init = hv_fcopy_init, + .util_deinit = hv_fcopy_deinit, +}; + static void perform_shutdown(struct work_struct *dummy) { orderly_poweroff(true); @@ -401,6 +408,10 @@ { HV_VSS_GUID, .driver_data = (unsigned long)&util_vss }, + /* File copy GUID */ + { HV_FCOPY_GUID, + .driver_data = (unsigned long)&util_fcopy + }, { }, }; --- linux-3.13.0.orig/drivers/hv/connection.c +++ linux-3.13.0/drivers/hv/connection.c @@ -67,7 +67,6 @@ int ret = 0; struct vmbus_channel_initiate_contact *msg; unsigned long flags; - int t; init_completion(&msginfo->waitevent); @@ -78,6 +77,8 @@ msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); + if (version == VERSION_WIN8) + msg->target_vcpu = hv_context.vp_index[smp_processor_id()]; /* * Add to list before we send the request since we may @@ -100,15 +101,7 @@ } /* Wait for the connection response */ - t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); - if (t == 0) { - spin_lock_irqsave(&vmbus_connection.channelmsg_lock, - flags); - list_del(&msginfo->msglistentry); - spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, - flags); - return -ETIMEDOUT; - } + wait_for_completion(&msginfo->waitevent); spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&msginfo->msglistentry); --- linux-3.13.0.orig/drivers/hv/Makefile +++ linux-3.13.0/drivers/hv/Makefile @@ -5,4 +5,4 @@ hv_vmbus-y := vmbus_drv.o \ hv.o connection.o channel.o \ channel_mgmt.o ring_buffer.o -hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o +hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o --- linux-3.13.0.orig/drivers/hv/hv.c +++ linux-3.13.0/drivers/hv/hv.c @@ -31,6 +31,14 @@ #include #include "hyperv_vmbus.h" +#ifndef PKG_ABI +/* + * Preserve the ability to 'make deb-pkg' since PKG_ABI is provided + * by the Ubuntu build rules. + */ +#define PKG_ABI 0 +#endif + /* The one and only */ struct hv_context hv_context = { .synic_initialized = false, @@ -148,7 +156,7 @@ /* * Write our OS ID. */ - hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0); + hv_context.guestid = generate_guest_id(0x80 /*Canonical*/, LINUX_VERSION_CODE, PKG_ABI); wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid); /* See if the hypercall page is already set */ --- linux-3.13.0.orig/drivers/hv/hv_fcopy.c +++ linux-3.13.0/drivers/hv/hv_fcopy.c @@ -0,0 +1,414 @@ +/* + * An implementation of file copy service. + * + * Copyright (C) 2014, Microsoft, Inc. + * + * Author : K. Y. Srinivasan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hyperv_vmbus.h" + +#define WIN8_SRV_MAJOR 1 +#define WIN8_SRV_MINOR 1 +#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) + +/* + * Global state maintained for transaction that is being processed. + * For a class of integration services, including the "file copy service", + * the specified protocol is a "request/response" protocol which means that + * there can only be single outstanding transaction from the host at any + * given point in time. We use this to simplify memory management in this + * driver - we cache and process only one message at a time. + * + * While the request/response protocol is guaranteed by the host, we further + * ensure this by serializing packet processing in this driver - we do not + * read additional packets from the VMBUs until the current packet is fully + * handled. + * + * The transaction "active" state is set when we receive a request from the + * host and we cleanup this state when the transaction is completed - when we + * respond to the host with our response. When the transaction active state is + * set, we defer handling incoming packets. + */ + +static struct { + bool active; /* transaction status - active or not */ + int recv_len; /* number of bytes received. */ + struct hv_fcopy_hdr *fcopy_msg; /* current message */ + struct hv_start_fcopy message; /* sent to daemon */ + struct vmbus_channel *recv_channel; /* chn we got the request */ + u64 recv_req_id; /* request ID. */ + void *fcopy_context; /* for the channel callback */ + struct semaphore read_sema; +} fcopy_transaction; + +static bool opened; /* currently device opened */ + +/* + * Before we can accept copy messages from the host, we need + * to handshake with the user level daemon. This state tracks + * if we are in the handshake phase. + */ +static bool in_hand_shake = true; +static void fcopy_send_data(void); +static void fcopy_respond_to_host(int error); +static void fcopy_work_func(struct work_struct *dummy); +static DECLARE_DELAYED_WORK(fcopy_work, fcopy_work_func); +static u8 *recv_buffer; + +static void fcopy_work_func(struct work_struct *dummy) +{ + /* + * If the timer fires, the user-mode component has not responded; + * process the pending transaction. + */ + fcopy_respond_to_host(HV_E_FAIL); +} + +static int fcopy_handle_handshake(u32 version) +{ + switch (version) { + case FCOPY_CURRENT_VERSION: + break; + default: + /* + * For now we will fail the registration. + * If and when we have multiple versions to + * deal with, we will be backward compatible. + * We will add this code when needed. + */ + return -EINVAL; + } + pr_info("FCP: user-mode registering done. Daemon version: %d\n", + version); + fcopy_transaction.active = false; + if (fcopy_transaction.fcopy_context) + hv_fcopy_onchannelcallback(fcopy_transaction.fcopy_context); + in_hand_shake = false; + return 0; +} + +static void fcopy_send_data(void) +{ + struct hv_start_fcopy *smsg_out = &fcopy_transaction.message; + int operation = fcopy_transaction.fcopy_msg->operation; + struct hv_start_fcopy *smsg_in; + + /* + * The strings sent from the host are encoded in + * in utf16; convert it to utf8 strings. + * The host assures us that the utf16 strings will not exceed + * the max lengths specified. We will however, reserve room + * for the string terminating character - in the utf16s_utf8s() + * function we limit the size of the buffer where the converted + * string is placed to W_MAX_PATH -1 to guarantee + * that the strings can be properly terminated! + */ + + switch (operation) { + case START_FILE_COPY: + memset(smsg_out, 0, sizeof(struct hv_start_fcopy)); + smsg_out->hdr.operation = operation; + smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg; + + utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH, + UTF16_LITTLE_ENDIAN, + (__u8 *)smsg_out->file_name, W_MAX_PATH - 1); + + utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH, + UTF16_LITTLE_ENDIAN, + (__u8 *)smsg_out->path_name, W_MAX_PATH - 1); + + smsg_out->copy_flags = smsg_in->copy_flags; + smsg_out->file_size = smsg_in->file_size; + break; + + default: + break; + } + up(&fcopy_transaction.read_sema); + return; +} + +/* + * Send a response back to the host. + */ + +static void +fcopy_respond_to_host(int error) +{ + struct icmsg_hdr *icmsghdr; + u32 buf_len; + struct vmbus_channel *channel; + u64 req_id; + + /* + * Copy the global state for completing the transaction. Note that + * only one transaction can be active at a time. This is guaranteed + * by the file copy protocol implemented by the host. Furthermore, + * the "transaction active" state we maintain ensures that there can + * only be one active transaction at a time. + */ + + buf_len = fcopy_transaction.recv_len; + channel = fcopy_transaction.recv_channel; + req_id = fcopy_transaction.recv_req_id; + + fcopy_transaction.active = false; + + icmsghdr = (struct icmsg_hdr *) + &recv_buffer[sizeof(struct vmbuspipe_hdr)]; + + if (channel->onchannel_callback == NULL) + /* + * We have raced with util driver being unloaded; + * silently return. + */ + return; + + icmsghdr->status = error; + icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; + vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, + VM_PKT_DATA_INBAND, 0); +} + +void hv_fcopy_onchannelcallback(void *context) +{ + struct vmbus_channel *channel = context; + u32 recvlen; + u64 requestid; + struct hv_fcopy_hdr *fcopy_msg; + struct icmsg_hdr *icmsghdr; + struct icmsg_negotiate *negop = NULL; + int util_fw_version; + int fcopy_srv_version; + + if (fcopy_transaction.active) { + /* + * We will defer processing this callback once + * the current transaction is complete. + */ + fcopy_transaction.fcopy_context = context; + return; + } + + vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, + &requestid); + if (recvlen <= 0) + return; + + icmsghdr = (struct icmsg_hdr *)&recv_buffer[ + sizeof(struct vmbuspipe_hdr)]; + if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) { + util_fw_version = UTIL_FW_VERSION; + fcopy_srv_version = WIN8_SRV_VERSION; + vmbus_prep_negotiate_resp(icmsghdr, negop, recv_buffer, + util_fw_version, fcopy_srv_version); + } else { + fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ + sizeof(struct vmbuspipe_hdr) + + sizeof(struct icmsg_hdr)]; + + /* + * Stash away this global state for completing the + * transaction; note transactions are serialized. + */ + + fcopy_transaction.active = true; + fcopy_transaction.recv_len = recvlen; + fcopy_transaction.recv_channel = channel; + fcopy_transaction.recv_req_id = requestid; + fcopy_transaction.fcopy_msg = fcopy_msg; + + /* + * Send the information to the user-level daemon. + */ + fcopy_send_data(); + schedule_delayed_work(&fcopy_work, 5*HZ); + return; + } + icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; + vmbus_sendpacket(channel, recv_buffer, recvlen, requestid, + VM_PKT_DATA_INBAND, 0); +} + +/* + * Create a char device that can support read/write for passing + * the payload. + */ + +static ssize_t fcopy_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + void *src; + size_t copy_size; + int operation; + + /* + * Wait until there is something to be read. + */ + if (down_interruptible(&fcopy_transaction.read_sema)) + return -EINTR; + + /* + * The channel may be rescinded and in this case, we will wakeup the + * the thread blocked on the semaphore and we will use the opened + * state to correctly handle this case. + */ + if (!opened) + return -ENODEV; + + operation = fcopy_transaction.fcopy_msg->operation; + + if (operation == START_FILE_COPY) { + src = &fcopy_transaction.message; + copy_size = sizeof(struct hv_start_fcopy); + if (count < copy_size) + return 0; + } else { + src = fcopy_transaction.fcopy_msg; + copy_size = sizeof(struct hv_do_fcopy); + if (count < copy_size) + return 0; + } + if (copy_to_user(buf, src, copy_size)) + return -EFAULT; + + return copy_size; +} + +static ssize_t fcopy_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + int response = 0; + + if (count != sizeof(int)) + return -EINVAL; + + if (copy_from_user(&response, buf, sizeof(int))) + return -EFAULT; + + if (in_hand_shake) { + if (fcopy_handle_handshake(response)) + return -EINVAL; + return sizeof(int); + } + + /* + * Complete the transaction by forwarding the result + * to the host. But first, cancel the timeout. + */ + if (cancel_delayed_work_sync(&fcopy_work)) + fcopy_respond_to_host(response); + + return sizeof(int); +} + +static int fcopy_open(struct inode *inode, struct file *f) +{ + /* + * The user level daemon that will open this device is + * really an extension of this driver. We can have only + * active open at a time. + */ + if (opened) + return -EBUSY; + + /* + * The daemon is alive; setup the state. + */ + opened = true; + return 0; +} + +static int fcopy_release(struct inode *inode, struct file *f) +{ + /* + * The daemon has exited; reset the state. + */ + in_hand_shake = true; + opened = false; + return 0; +} + + +static const struct file_operations fcopy_fops = { + .read = fcopy_read, + .write = fcopy_write, + .release = fcopy_release, + .open = fcopy_open, +}; + +static struct miscdevice fcopy_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "vmbus/hv_fcopy", + .fops = &fcopy_fops, +}; + +static int fcopy_dev_init(void) +{ + return misc_register(&fcopy_misc); +} + +static void fcopy_dev_deinit(void) +{ + + /* + * The device is going away - perhaps because the + * host has rescinded the channel. Setup state so that + * user level daemon can gracefully exit if it is blocked + * on the read semaphore. + */ + opened = false; + /* + * Signal the semaphore as the device is + * going away. + */ + up(&fcopy_transaction.read_sema); + misc_deregister(&fcopy_misc); +} + +int hv_fcopy_init(struct hv_util_service *srv) +{ + recv_buffer = srv->recv_buffer; + + /* + * When this driver loads, the user level daemon that + * processes the host requests may not yet be running. + * Defer processing channel callbacks until the daemon + * has registered. + */ + fcopy_transaction.active = true; + sema_init(&fcopy_transaction.read_sema, 0); + + return fcopy_dev_init(); +} + +void hv_fcopy_deinit(void) +{ + cancel_delayed_work_sync(&fcopy_work); + fcopy_dev_deinit(); +} --- linux-3.13.0.orig/drivers/hv/channel.c +++ linux-3.13.0/drivers/hv/channel.c @@ -209,7 +209,6 @@ { int i; int pagecount; - unsigned long long pfn; struct vmbus_channel_gpadl_header *gpadl_header; struct vmbus_channel_gpadl_body *gpadl_body; struct vmbus_channel_msginfo *msgheader; @@ -219,7 +218,6 @@ int pfnsum, pfncount, pfnleft, pfncurr, pfnsize; pagecount = size >> PAGE_SHIFT; - pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT; /* do we need a gpadl body msg */ pfnsize = MAX_SIZE_CHANNEL_MESSAGE - @@ -248,7 +246,8 @@ gpadl_header->range[0].byte_offset = 0; gpadl_header->range[0].byte_count = size; for (i = 0; i < pfncount; i++) - gpadl_header->range[0].pfn_array[i] = pfn+i; + gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys( + kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; *msginfo = msgheader; *messagecount = 1; @@ -301,7 +300,9 @@ * so the hypervisor gurantees that this is ok. */ for (i = 0; i < pfncurr; i++) - gpadl_body->pfn[i] = pfn + pfnsum + i; + gpadl_body->pfn[i] = slow_virt_to_phys( + kbuffer + PAGE_SIZE * (pfnsum + i)) >> + PAGE_SHIFT; /* add to msg header */ list_add_tail(&msgbody->msglistentry, @@ -327,7 +328,8 @@ gpadl_header->range[0].byte_offset = 0; gpadl_header->range[0].byte_count = size; for (i = 0; i < pagecount; i++) - gpadl_header->range[0].pfn_array[i] = pfn+i; + gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys( + kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; *msginfo = msgheader; *messagecount = 1; @@ -344,7 +346,7 @@ * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer * * @channel: a channel - * @kbuffer: from kmalloc + * @kbuffer: from kmalloc or vmalloc * @size: page-size multiple * @gpadl_handle: some funky thing */ --- linux-3.13.0.orig/drivers/hv/hv_balloon.c +++ linux-3.13.0/drivers/hv/hv_balloon.c @@ -1171,7 +1171,8 @@ int t; while (!kthread_should_stop()) { - t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ); + t = wait_for_completion_interruptible_timeout( + &dm_device.config_event, 1*HZ); /* * The host expects us to post information on the memory * pressure every second. --- linux-3.13.0.orig/drivers/hid/Kconfig +++ linux-3.13.0/drivers/hid/Kconfig @@ -27,7 +27,7 @@ config HID_BATTERY_STRENGTH bool "Battery level reporting for HID devices" - depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY + depends on HID && POWER_SUPPLY default n ---help--- This option adds support of reporting battery strength (for HID devices --- linux-3.13.0.orig/drivers/hid/hidraw.c +++ linux-3.13.0/drivers/hid/hidraw.c @@ -313,13 +313,13 @@ hid_hw_close(hidraw->hid); wake_up_interruptible(&hidraw->wait); } + device_destroy(hidraw_class, + MKDEV(hidraw_major, hidraw->minor)); } else { --hidraw->open; } if (!hidraw->open) { if (!hidraw->exist) { - device_destroy(hidraw_class, - MKDEV(hidraw_major, hidraw->minor)); hidraw_table[hidraw->minor] = NULL; kfree(hidraw); } else { --- linux-3.13.0.orig/drivers/staging/Makefile +++ linux-3.13.0/drivers/staging/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_R8188EU) += rtl8188eu/ +obj-$(CONFIG_R8821AE) += rtl8821ae/ obj-$(CONFIG_RTS5139) += rts5139/ obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_IDE_PHISON) += phison/ @@ -67,3 +68,5 @@ obj-$(CONFIG_DGNC) += dgnc/ obj-$(CONFIG_DGAP) += dgap/ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ +obj-$(CONFIG_FSL_DPA) += fsl_qbman/ +obj-$(CONFIG_FSL_PME2) += fsl_pme2/ --- linux-3.13.0.orig/drivers/staging/Kconfig +++ linux-3.13.0/drivers/staging/Kconfig @@ -52,6 +52,8 @@ source "drivers/staging/rtl8188eu/Kconfig" +source "drivers/staging/rtl8821ae/Kconfig" + source "drivers/staging/rts5139/Kconfig" source "drivers/staging/frontier/Kconfig" @@ -150,4 +152,8 @@ source "drivers/staging/dgap/Kconfig" +source "drivers/staging/fsl_qbman/Kconfig" + +source "drivers/staging/fsl_pme2/Kconfig" + endif # STAGING --- linux-3.13.0.orig/drivers/staging/vt6656/card.c +++ linux-3.13.0/drivers/staging/vt6656/card.c @@ -731,7 +731,7 @@ uBeaconInterval = wBeaconInterval * 1024; // Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval - uLowNextTBTT = ((qwTSF & 0xffffffffU) >> 10) << 10; + uLowNextTBTT = ((qwTSF & 0xffffffffULL) >> 10) << 10; uLowRemain = (uLowNextTBTT) % uBeaconInterval; uHighRemain = ((0x80000000 % uBeaconInterval) * 2 * (u32)(qwTSF >> 32)) % uBeaconInterval; --- linux-3.13.0.orig/drivers/staging/vt6656/baseband.c +++ linux-3.13.0/drivers/staging/vt6656/baseband.c @@ -1464,7 +1464,6 @@ if( bScanning ) { // need Max sensitivity //RSSI -69, -70,.... - if(pDevice->byBBPreEDIndex == 0) break; pDevice->byBBPreEDIndex = 0; ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, 0x00); //CR201(0xC9) ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xCE, 0x30); //CR206(0xCE) @@ -1607,7 +1606,6 @@ if( bScanning ) { // need Max sensitivity //RSSI -69, -70, ... - if(pDevice->byBBPreEDIndex == 0) break; pDevice->byBBPreEDIndex = 0; ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, 0x00); //CR201(0xC9) ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xCE, 0x24); //CR206(0xCE) @@ -1759,7 +1757,6 @@ case RF_VT3342A0: //RobertYu:20060627, testing table if( bScanning ) { // need Max sensitivity //RSSI -67, -68, ... - if(pDevice->byBBPreEDIndex == 0) break; pDevice->byBBPreEDIndex = 0; ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, 0x00); //CR201(0xC9) ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xCE, 0x38); //CR206(0xCE) --- linux-3.13.0.orig/drivers/staging/rtl8821ae/core.h +++ linux-3.13.0/drivers/staging/rtl8821ae/core.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * Tmis program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Tme full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_CORE_H__ +#define __RTL_CORE_H__ + +#define RTL_SUPPORTED_FILTERS \ + (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | FIF_CONTROL | \ + FIF_OTHER_BSS | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC) + +#define RTL_SUPPORTED_CTRL_FILTER 0xFF + +extern const struct ieee80211_ops rtl_ops; +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/core.c +++ linux-3.13.0/drivers/staging/rtl8821ae/core.c @@ -0,0 +1,1464 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "wifi.h" +#include "core.h" +#include "cam.h" +#include "base.h" +#include "ps.h" + +#include "btcoexist/rtl_btc.h" + +/*mutex for start & stop is must here. */ +static int rtl_op_start(struct ieee80211_hw *hw) +{ + int err = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (!is_hal_stop(rtlhal)) + return 0; + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + return 0; + mutex_lock(&rtlpriv->locks.conf_mutex); + err = rtlpriv->intf_ops->adapter_start(hw); + if (err) + goto out; + rtl_watch_dog_timer_callback((unsigned long)hw); + +out: + mutex_unlock(&rtlpriv->locks.conf_mutex); + return err; +} + +static void rtl_op_stop(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if (is_hal_stop(rtlhal)) + return; + + /* here is must, because adhoc do stop and start, + * but stop with RFOFF may cause something wrong, + * like adhoc TP */ + if (unlikely(ppsc->rfpwr_state == ERFOFF)) + rtl_ips_nic_on(hw); + + mutex_lock(&rtlpriv->locks.conf_mutex); + + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; + + /*reset sec info */ + rtl_cam_reset_sec_info(hw); + + rtl_deinit_deferred_work(hw); + rtlpriv->intf_ops->adapter_stop(hw); + + mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) +static int rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + + if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + + return NETDEV_TX_OK; + +err_free: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} +#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) +static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +#else +/**/ +static void rtl_op_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +/**/ +#endif +/**/ +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); +#else +/**/ + if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb)) + rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc); +/**/ +#endif +/**/ + return; + +err_free: + dev_kfree_skb_any(skb); + return; +} +/**/ +#endif +/**/ + +static int rtl_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + int err = 0; + + if (mac->vif) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("vif has been set!! mac->vif = 0x%p\n", mac->vif)); + return -EOPNOTSUPP; + } + +/*This flag is not defined before kernel 3.4*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; +#endif + + rtl_ips_nic_on(hw); + + mutex_lock(&rtlpriv->locks.conf_mutex); +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_CLIENT: + mac->p2p = P2P_ROLE_CLIENT; + /*fall through*/ +#else +/**/ + switch (vif->type) { +/**/ +#endif +/**/ + case NL80211_IFTYPE_STATION: + if (mac->beacon_enabled == 1) { + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("NL80211_IFTYPE_STATION \n")); + mac->beacon_enabled = 0; + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); + } + break; + case NL80211_IFTYPE_ADHOC: + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("NL80211_IFTYPE_ADHOC \n")); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); + + break; +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) + case NL80211_IFTYPE_P2P_GO: + mac->p2p = P2P_ROLE_GO; + /*fall through*/ +#endif +/**/ + case NL80211_IFTYPE_AP: + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("NL80211_IFTYPE_AP \n")); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); + break; + case NL80211_IFTYPE_MESH_POINT: + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("NL80211_IFTYPE_MESH_POINT \n")); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("operation mode %d is not support!\n", vif->type)); + err = -EOPNOTSUPP; + goto out; + } + +#ifdef VIF_TODO + if (!rtl_set_vif_info(hw, vif)) + goto out; +#endif + + if (mac->p2p) { + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("p2p role %x \n",vif->type)); + mac->basic_rates = 0xff0;/*disable cck rate for p2p*/ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); + } + mac->vif = vif; + mac->opmode = vif->type; + rtlpriv->cfg->ops->set_network_type(hw, vif->type); + memcpy(mac->mac_addr, vif->addr, ETH_ALEN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + +out: + mutex_unlock(&rtlpriv->locks.conf_mutex); + return err; +} + +static void rtl_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + mutex_lock(&rtlpriv->locks.conf_mutex); + + /* Free beacon resources */ + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if (mac->beacon_enabled == 1) { + mac->beacon_enabled = 0; + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); + } + } + + /* + *Note: We assume NL80211_IFTYPE_UNSPECIFIED as + *NO LINK for our hardware. + */ + mac->p2p = 0; + mac->vif = NULL; + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; + mac->opmode = NL80211_IFTYPE_UNSPECIFIED; + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + + mutex_unlock(&rtlpriv->locks.conf_mutex); +} +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) +/**/ +static int rtl_op_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype new_type, bool p2p) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int ret; + rtl_op_remove_interface(hw, vif); + + vif->type = new_type; + vif->p2p = p2p; + ret = rtl_op_add_interface(hw, vif); + RT_TRACE(COMP_MAC80211, DBG_LOUD, + (" p2p %x\n",p2p)); + return ret; +} +/**/ +#endif +/**/ +static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct ieee80211_conf *conf = &hw->conf; + + if (mac->skip_scan) + return 1; + + + mutex_lock(&rtlpriv->locks.conf_mutex); + if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* BIT(2) */ + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n")); + } + + /*For IPS */ + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + if (hw->conf.flags & IEEE80211_CONF_IDLE) + rtl_ips_nic_off(hw); + else + rtl_ips_nic_on(hw); + } else { + /* + *although rfoff may not cause by ips, but we will + *check the reason in set_rf_power_state function + */ + if (unlikely(ppsc->rfpwr_state == ERFOFF)) + rtl_ips_nic_on(hw); + } + + /*For LPS */ + if (changed & IEEE80211_CONF_CHANGE_PS) { + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + if (conf->flags & IEEE80211_CONF_PS) { + rtlpriv->psc.sw_ps_enabled = true; + /* sleep here is must, or we may recv the beacon and + * cause mac80211 into wrong ps state, this will cause + * power save nullfunc send fail, and further cause + * pkt loss, So sleep must quickly but not immediatly + * because that will cause nullfunc send by mac80211 + * fail, and cause pkt loss, we have tested that 5mA + * is worked very well */ + if (!rtlpriv->psc.multi_buffered) + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, + MSECS(5)); + } else { + rtl_swlps_rf_awake(hw); + rtlpriv->psc.sw_ps_enabled = false; + } + } + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n", + hw->conf.long_frame_max_tx_count)); + mac->retry_long = hw->conf.long_frame_max_tx_count; + mac->retry_short = hw->conf.long_frame_max_tx_count; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + (u8 *) (&hw->conf.long_frame_max_tx_count)); + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + struct ieee80211_channel *channel = hw->conf.chandef.chan; + enum nl80211_channel_type channel_type = + cfg80211_get_chandef_type(&(hw->conf.chandef)); +#else + struct ieee80211_channel *channel = hw->conf.channel; + enum nl80211_channel_type channel_type = hw->conf.channel_type; +#endif + u8 wide_chan = (u8) channel->hw_value; + + if (mac->act_scanning) + mac->n_channels++; + + if (rtlpriv->dm.supp_phymode_switch && + mac->link_state < MAC80211_LINKED && + !mac->act_scanning) { + if (rtlpriv->cfg->ops->check_switch_to_dmdp) + rtlpriv->cfg->ops->check_switch_to_dmdp(hw); + } + + /* + *because we should back channel to + *current_network.chan in in scanning, + *So if set_chan == current_network.chan + *we should set it. + *because mac80211 tell us wrong bw40 + *info for cisco1253 bw20, so we modify + *it here based on UPPER & LOWER + */ + switch (channel_type) { + case NL80211_CHAN_HT20: + case NL80211_CHAN_NO_HT: + /* SC */ + mac->cur_40_prime_sc = + PRIME_CHNL_OFFSET_DONT_CARE; + rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; + mac->bw_40 = false; + break; + case NL80211_CHAN_HT40MINUS: + /* SC */ + mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; + rtlphy->current_chan_bw = + HT_CHANNEL_WIDTH_20_40; + mac->bw_40 = true; + + /*wide channel */ + wide_chan -= 2; + + break; + case NL80211_CHAN_HT40PLUS: + /* SC */ + mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; + rtlphy->current_chan_bw = + HT_CHANNEL_WIDTH_20_40; + mac->bw_40 = true; + + /*wide channel */ + wide_chan += 2; + + break; + default: + mac->bw_40 = false; + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not processed \n")); + break; + } + + if (wide_chan <= 0) + wide_chan = 1; + + /* in scanning, when before we offchannel we may send a ps=1 + * null to AP, and then we may send a ps = 0 null to AP quickly, + * but first null have cause AP's put lots of packet to hw tx + * buffer, these packet must be tx before off channel so we must + * delay more time to let AP flush these packets before + * offchannel, or dis-association or delete BA will happen by AP + */ + if (rtlpriv->mac80211.offchan_deley) { + rtlpriv->mac80211.offchan_deley = false; + mdelay(50); + } + + rtlphy->current_channel = wide_chan; + + rtlpriv->cfg->ops->switch_channel(hw); + rtlpriv->cfg->ops->set_channel_access(hw); + rtlpriv->cfg->ops->set_bw_mode(hw, + channel_type); + } + + mutex_unlock(&rtlpriv->locks.conf_mutex); + + return 0; +} + +static void rtl_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, u64 multicast) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + *new_flags &= RTL_SUPPORTED_FILTERS; + if (0 == changed_flags) + return; + + /*TODO: we disable broadcase now, so enable here */ + if (changed_flags & FIF_ALLMULTI) { + if (*new_flags & FIF_ALLMULTI) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] | + rtlpriv->cfg->maps[MAC_RCR_AB]; + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Enable receive multicast frame.\n")); + } else { + mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] | + rtlpriv->cfg->maps[MAC_RCR_AB]); + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Disable receive multicast frame.\n")); + } + } + + if (changed_flags & FIF_FCSFAIL) { + if (*new_flags & FIF_FCSFAIL) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32]; + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Enable receive FCS error frame.\n")); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Disable receive FCS error frame.\n")); + } + } + + /* if ssid not set to hw don't check bssid + * here just used for linked scanning, & linked + * and nolink check bssid is set in set network_type */ + if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && + (mac->link_state >= MAC80211_LINKED)) { + if (mac->opmode != NL80211_IFTYPE_AP && + mac->opmode != NL80211_IFTYPE_MESH_POINT) { + if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { + rtlpriv->cfg->ops->set_chk_bssid(hw, false); + } else { + rtlpriv->cfg->ops->set_chk_bssid(hw, true); + } + } + } + + if (changed_flags & FIF_CONTROL) { + if (*new_flags & FIF_CONTROL) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; + + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Enable receive control frame.\n")); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Disable receive control frame.\n")); + } + } + + if (changed_flags & FIF_OTHER_BSS) { + if (*new_flags & FIF_OTHER_BSS) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP]; + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Enable receive other BSS's frame.\n")); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("Disable receive other BSS's frame.\n")); + } + } +} +static int rtl_op_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal= rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry; + + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_add_tail(&sta_entry->list, &rtlpriv->entry_list); + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + sta_entry->wireless_mode = WIRELESS_MODE_G; + if (sta->supp_rates[0] <= 0xf) + sta_entry->wireless_mode = WIRELESS_MODE_B; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + + if (vif->type == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_G; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + sta_entry->wireless_mode = WIRELESS_MODE_A; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + + if (vif->type == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_A; + } + /*disable cck rate for p2p*/ + if (mac->p2p) + sta->supp_rates[0] &= 0xfffffff0; + + memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN); + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("Add sta addr is %pM\n",sta->addr)); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + } + + return 0; +} + +static int rtl_op_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry; + if (sta) { + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("Remove sta addr is %pM\n",sta->addr)); + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = 0; + sta_entry->ratr_index = 0; + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_del(&sta_entry->list); + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + } + return 0; +} +static int _rtl_get_hal_qnum(u16 queue) +{ + int qnum; + + switch (queue) { + case 0: + qnum = AC3_VO; + break; + case 1: + qnum = AC2_VI; + break; + case 2: + qnum = AC0_BE; + break; + case 3: + qnum = AC1_BK; + break; + default: + qnum = AC0_BE; + break; + } + return qnum; +} + +/* + *for mac80211 VO=0, VI=1, BE=2, BK=3 + *for rtl819x BE=0, BK=1, VI=2, VO=3 + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +static int rtl_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *param) +#else +static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *param) +#endif +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + int aci; + + if (queue >= AC_MAX) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("queue number %d is incorrect!\n", queue)); + return -EINVAL; + } + + aci = _rtl_get_hal_qnum(queue); + mac->ac[aci].aifs = param->aifs; + mac->ac[aci].cw_min = param->cw_min; + mac->ac[aci].cw_max = param->cw_max; + mac->ac[aci].tx_op = param->txop; + memcpy(&mac->edca_param[aci], param, sizeof(*param)); + rtlpriv->cfg->ops->set_qos(hw, aci); + return 0; +} + +static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + mutex_lock(&rtlpriv->locks.conf_mutex); + if ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((changed & BSS_CHANGED_BEACON) || + (changed & BSS_CHANGED_BEACON_ENABLED && + bss_conf->enable_beacon)) { + if (mac->beacon_enabled == 0) { + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("BSS_CHANGED_BEACON_ENABLED \n")); + + /*start hw beacon interrupt. */ + /*rtlpriv->cfg->ops->set_bcn_reg(hw); */ + mac->beacon_enabled = 1; + rtlpriv->cfg->ops->update_interrupt_mask(hw, + rtlpriv->cfg->maps + [RTL_IBSS_INT_MASKS], 0); + + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); + } + } + if ((changed & BSS_CHANGED_BEACON_ENABLED && + !bss_conf->enable_beacon)){ + if (mac->beacon_enabled == 1) { + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("ADHOC DISABLE BEACON\n")); + + mac->beacon_enabled = 0; + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + rtlpriv->cfg->maps + [RTL_IBSS_INT_MASKS]); + } + } + if (changed & BSS_CHANGED_BEACON_INT) { + RT_TRACE(COMP_BEACON, DBG_TRACE, + ("BSS_CHANGED_BEACON_INT\n")); + mac->beacon_interval = bss_conf->beacon_int; + rtlpriv->cfg->ops->set_bcn_intv(hw); + } + } + + /*TODO: reference to enum ieee80211_bss_change */ + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + struct ieee80211_sta *sta = NULL; + /* we should reset all sec info & cam + * before set cam after linked, we should not + * reset in disassoc, that will cause tkip->wep + * fail because some flag will be wrong */ + /* reset sec info */ + rtl_cam_reset_sec_info(hw); + /* reset cam to fix wep fail issue + * when change from wpa to wep */ + rtl_cam_reset_all_entry(hw); + + mac->link_state = MAC80211_LINKED; + mac->cnt_after_linked = 0; + mac->assoc_id = bss_conf->aid; + memcpy(mac->bssid, bss_conf->bssid, 6); + + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, (u8*)bss_conf->bssid); + + if (vif->type == NL80211_IFTYPE_STATION && sta) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + RT_TRACE(COMP_EASY_CONCURRENT, DBG_LOUD, + ("send PS STATIC frame \n")); + if (rtlpriv->dm.supp_phymode_switch) { + if (sta->ht_cap.ht_supported) + rtl_send_smps_action(hw, sta, + IEEE80211_SMPS_STATIC); + } + rcu_read_unlock(); + + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("BSS_CHANGED_ASSOC\n")); + } else { + if (mac->link_state == MAC80211_LINKED) + rtl_lps_leave(hw); + if (ppsc->p2p_ps_info.p2p_ps_mode> P2P_PS_NONE) + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; + + if (rtlpriv->dm.supp_phymode_switch) { + if (rtlpriv->cfg->ops->check_switch_to_dmdp) + rtlpriv->cfg->ops->check_switch_to_dmdp(hw); + } + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("BSS_CHANGED_UN_ASSOC\n")); + } + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("BSS_CHANGED_ERP_CTS_PROT\n")); + mac->use_cts_protect = bss_conf->use_cts_prot; + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + RT_TRACE(COMP_MAC80211, DBG_LOUD, + ("BSS_CHANGED_ERP_PREAMBLE use short preamble:%x \n", + bss_conf->use_short_preamble)); + + mac->short_preamble = bss_conf->use_short_preamble; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE, + (u8 *) (&mac->short_preamble)); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("BSS_CHANGED_ERP_SLOT\n")); + + if (bss_conf->use_short_slot) + mac->slot_time = RTL_SLOT_TIME_9; + else + mac->slot_time = RTL_SLOT_TIME_20; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *) (&mac->slot_time)); + } + + if (changed & BSS_CHANGED_HT) { + struct ieee80211_sta *sta = NULL; + + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("BSS_CHANGED_HT\n")); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, (u8*)bss_conf->bssid); + if (sta) { + if (sta->ht_cap.ampdu_density > + mac->current_ampdu_density) + mac->current_ampdu_density = + sta->ht_cap.ampdu_density; + if (sta->ht_cap.ampdu_factor < + mac->current_ampdu_factor) + mac->current_ampdu_factor = + sta->ht_cap.ampdu_factor; + } + rcu_read_unlock(); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY, + (u8 *) (&mac->max_mss_density)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR, + &mac->current_ampdu_factor); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE, + &mac->current_ampdu_density); + } + + if (changed & BSS_CHANGED_BSSID) { + u32 basic_rates; + struct ieee80211_sta *sta = NULL; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, + (u8 *) bss_conf->bssid); + + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("bssid: %pM\n", bss_conf->bssid)); + + mac->vendor = PEER_UNKNOWN; + memcpy(mac->bssid, bss_conf->bssid, 6); + rtlpriv->cfg->ops->set_network_type(hw, vif->type); + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, (u8*)bss_conf->bssid); + if (!sta) { + rcu_read_unlock(); + goto out; + } + + if (rtlhal->current_bandtype == BAND_ON_5G) { + mac->mode = WIRELESS_MODE_A; + } else { + if (sta->supp_rates[0] <= 0xf) + mac->mode = WIRELESS_MODE_B; + else + mac->mode = WIRELESS_MODE_G; + } + + if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) + mac->mode = WIRELESS_MODE_N_24G; + else + mac->mode = WIRELESS_MODE_N_5G; + } + + /* just station need it, because ibss & ap mode will + * set in sta_add, and will be NULL here */ + if (vif->type == NL80211_IFTYPE_STATION) { + struct rtl_sta_info *sta_entry; + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = mac->mode; + } + + if (sta->ht_cap.ht_supported) { + mac->ht_enable = true; + + /* + * for cisco 1252 bw20 it's wrong + * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + * mac->bw_40 = true; + * } + * */ + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + /* for 5G must << RATE_6M_INDEX=4, + * because 5G have no cck rate*/ + if (rtlhal->current_bandtype == BAND_ON_5G) + basic_rates = sta->supp_rates[1] << 4; + else + basic_rates = sta->supp_rates[0]; + + mac->basic_rates = basic_rates; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&basic_rates)); + } + rcu_read_unlock(); + } + + /* + * For FW LPS and Keep Alive: + * To tell firmware we have connected + * to an AP. For 92SE/CE power save v2. + */ + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + u8 keep_alive = 10; + u8 mstatus = RT_MEDIA_CONNECT; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_KEEP_ALIVE, + (u8 *) (&keep_alive)); + + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *) (&mstatus)); + ppsc->report_linked = true; + + } else { + + u8 mstatus = RT_MEDIA_DISCONNECT; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *) (&mstatus)); + ppsc->report_linked = false; + + } + + if (rtlpriv->cfg->ops->get_btc_status()){ + rtlpriv->btcoexist.btc_ops->btc_mediastatus_notify( + rtlpriv, ppsc->report_linked); + } + } + +out: + mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +#else +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) +#endif +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u64 tsf; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&tsf)); + return tsf; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +static void rtl_op_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) +#else +static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) +#endif +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + + mac->tsf = tsf; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss)); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +static void rtl_op_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +#else +static void rtl_op_reset_tsf(struct ieee80211_hw *hw) +#endif +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp = 0; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, (u8 *) (&tmp)); +} + +static void rtl_op_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + switch (cmd) { + case STA_NOTIFY_SLEEP: + break; + case STA_NOTIFY_AWAKE: + break; + default: + break; + } +} + +static int rtl_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 * ssn +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) +/**/ + ,u8 buf_size +/**/ +#endif +/**/ + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (action) { + case IEEE80211_AMPDU_TX_START: + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid)); + return rtl_tx_agg_start(hw, vif, sta, tid, ssn); + break; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: +#else + case IEEE80211_AMPDU_TX_STOP: +#endif + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid)); + return rtl_tx_agg_stop(hw, vif, sta, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid)); + rtl_tx_agg_oper(hw, sta, tid); + break; + case IEEE80211_AMPDU_RX_START: + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_RX_START:TID:%d\n", tid)); + return rtl_rx_agg_start(hw, sta, tid); + break; + case IEEE80211_AMPDU_RX_STOP: + RT_TRACE(COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid)); + return rtl_rx_agg_stop(hw, sta, tid); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("IEEE80211_AMPDU_ERR!!!!:\n")); + return -EOPNOTSUPP; + } + return 0; +} + +static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("\n")); + mac->act_scanning = true; + /*rtlpriv->btcops->btc_scan_notify(rtlpriv, 0); */ + if (rtlpriv->link_info.b_higher_busytraffic) { + mac->skip_scan = true; + return; + } + + if (rtlpriv->dm.supp_phymode_switch) { + if (rtlpriv->cfg->ops->check_switch_to_dmdp) + rtlpriv->cfg->ops->check_switch_to_dmdp(hw); + } + + if (mac->link_state == MAC80211_LINKED) { + rtl_lps_leave(hw); + mac->link_state = MAC80211_LINKED_SCANNING; + } else { + rtl_ips_nic_on(hw); + } + + /* Dul mac */ + rtlpriv->rtlhal.b_load_imrandiqk_setting_for2g = false; + + rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); + + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0); + +} + +static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("\n")); + mac->act_scanning = false; + mac->skip_scan = false; + if (rtlpriv->link_info.b_higher_busytraffic) { + return; + } + + /* p2p will use 1/6/11 to scan */ + if (mac->n_channels == 3) + mac->p2p_in_use = true; + else + mac->p2p_in_use = false; + mac->n_channels = 0; + /* Dul mac */ + rtlpriv->rtlhal.b_load_imrandiqk_setting_for2g = false; + + if (mac->link_state == MAC80211_LINKED_SCANNING) { + mac->link_state = MAC80211_LINKED; + if (mac->opmode == NL80211_IFTYPE_STATION) { + /* fix fwlps issue */ + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + } + } + + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); + /* rtlpriv->btcops->btc_scan_notify(rtlpriv, 1); */ +} + +static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 key_type = NO_ENCRYPTION; + u8 key_idx; + bool group_key = false; + bool wep_only = false; + int err = 0; + u8 mac_addr[ETH_ALEN]; + u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + u8 zero_addr[ETH_ALEN] = { 0 }; + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("not open hw encryption\n")); + return -ENOSPC; /*User disabled HW-crypto */ + } + /* To support IBSS, use sw-crypto for GTK */ + if(((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -ENOSPC; + RT_TRACE(COMP_SEC, DBG_DMESG, + ("%s hardware based encryption for keyidx: %d, mac: %pM\n", + cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, + sta ? sta->addr : bcast_addr)); + rtlpriv->sec.being_setkey = true; + rtl_ips_nic_on(hw); + mutex_lock(&rtlpriv->locks.conf_mutex); + /* <1> get encryption alg */ + +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) +/**/ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key_type = WEP40_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:WEP104\n")); + key_type = WEP104_ENCRYPTION; + break; + case WLAN_CIPHER_SUITE_TKIP: + key_type = TKIP_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key_type = AESCCMP_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + /* HW don't support CMAC encryption, + * use software CMAC encryption */ + key_type = AESCMAC_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n")); + RT_TRACE(COMP_SEC, DBG_DMESG, + ("HW don't support CMAC encrypiton, " + "use software CMAC encrypiton\n")); + err = -EOPNOTSUPP; + goto out_unlock; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("alg_err:%x!!!!:\n", key->cipher)); + goto out_unlock; + } +/**/ +#else + switch (key->alg) { + case ALG_WEP: + if (key->keylen == WLAN_KEY_LEN_WEP40) { + key_type = WEP40_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); + } else { + RT_TRACE(COMP_SEC, DBG_DMESG, + ("alg:WEP104\n")); + key_type = WEP104_ENCRYPTION; + } + break; + case ALG_TKIP: + key_type = TKIP_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); + break; + case ALG_CCMP: + key_type = AESCCMP_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); + break; + case ALG_AES_CMAC: + /*HW don't support CMAC encryption, use software CMAC encryption */ + key_type = AESCMAC_ENCRYPTION; + RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n")); + RT_TRACE(COMP_SEC, DBG_DMESG, + ("HW don't support CMAC encrypiton, " + "use software CMAC encrypiton\n")); + err = -EOPNOTSUPP; + goto out_unlock; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("alg_err:%x!!!!:\n", key->alg)); + goto out_unlock; + } +#endif +/**/ + if(key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION || + vif->type == NL80211_IFTYPE_ADHOC) + rtlpriv->sec.use_defaultkey = true; + + /* <2> get key_idx */ + key_idx = (u8) (key->keyidx); + if (key_idx > 3) + goto out_unlock; + /* <3> if pairwise key enable_hw_sec */ + group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); + + /* wep always be group key, but there are two conditions: + * 1) wep only: is just for wep enc, in this condition + * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION + * will be true & enable_hw_sec will be set when wep + * ke setting. + * 2) wep(group) + AES(pairwise): some AP like cisco + * may use it, in this condition enable_hw_sec will not + * be set when wep key setting */ + /* we must reset sec_info after lingked before set key, + * or some flag will be wrong*/ + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT) { + if (!group_key || key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION) { + if (group_key) { + wep_only = true; + } + rtlpriv->cfg->ops->enable_hw_sec(hw); + } + } else { + if ((!group_key) || (vif->type == NL80211_IFTYPE_ADHOC) || + rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION && + (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION)) + wep_only = true; + rtlpriv->sec.pairwise_enc_algorithm = key_type; + RT_TRACE(COMP_SEC, DBG_DMESG, + ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:" + "1 TKIP:2 AES:4 WEP104:5)\n", key_type)); + rtlpriv->cfg->ops->enable_hw_sec(hw); + } + } + /* <4> set key based on cmd */ + switch (cmd) { + case SET_KEY: + if (wep_only) { + RT_TRACE(COMP_SEC, DBG_DMESG, + ("set WEP(group/pairwise) key\n")); + /* Pairwise key with an assigned MAC address. */ + rtlpriv->sec.pairwise_enc_algorithm = key_type; + rtlpriv->sec.group_enc_algorithm = key_type; + /*set local buf about wep key. */ + memcpy(rtlpriv->sec.key_buf[key_idx], + key->key, key->keylen); + rtlpriv->sec.key_len[key_idx] = key->keylen; + memcpy(mac_addr, zero_addr, ETH_ALEN); + } else if (group_key) { /* group key */ + RT_TRACE(COMP_SEC, DBG_DMESG, + ("set group key\n")); + /* group key */ + rtlpriv->sec.group_enc_algorithm = key_type; + /*set local buf about group key. */ + memcpy(rtlpriv->sec.key_buf[key_idx], + key->key, key->keylen); + rtlpriv->sec.key_len[key_idx] = key->keylen; + memcpy(mac_addr, bcast_addr, ETH_ALEN); + } else { /* pairwise key */ + RT_TRACE(COMP_SEC, DBG_DMESG, + ("set pairwise key\n")); + if (!sta) { + RT_ASSERT(false, ("pairwise key withnot" + "mac_addr\n")); + + err = -EOPNOTSUPP; + goto out_unlock; + } + /* Pairwise key with an assigned MAC address. */ + rtlpriv->sec.pairwise_enc_algorithm = key_type; + /*set local buf about pairwise key. */ + memcpy(rtlpriv->sec.key_buf[PAIRWISE_KEYIDX], + key->key, key->keylen); + rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen; + rtlpriv->sec.pairwise_key = + rtlpriv->sec.key_buf[PAIRWISE_KEYIDX]; + memcpy(mac_addr, sta->addr, ETH_ALEN); + } + rtlpriv->cfg->ops->set_key(hw, key_idx, mac_addr, + group_key, key_type, wep_only, + false); + /* <5> tell mac80211 do something: */ + /*must use sw generate IV, or can not work !!!!. */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + key->hw_key_idx = key_idx; + if (key_type == TKIP_ENCRYPTION) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + /*use software CCMP encryption for management frames (MFP) */ + if (key_type == AESCCMP_ENCRYPTION) + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; + break; + case DISABLE_KEY: + RT_TRACE(COMP_SEC, DBG_DMESG, + ("disable key delete one entry\n")); + /*set local buf about wep key. */ + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT) { + if (sta) + rtl_cam_del_entry(hw, sta->addr); + } + memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); + rtlpriv->sec.key_len[key_idx] = 0; + memcpy(mac_addr, zero_addr, ETH_ALEN); + /* + *mac80211 will delete entrys one by one, + *so don't use rtl_cam_reset_all_entry + *or clear all entry here. + */ + rtl_cam_delete_one_entry(hw, mac_addr, key_idx); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("cmd_err:%x!!!!:\n", cmd)); + } +out_unlock: + mutex_unlock(&rtlpriv->locks.conf_mutex); + rtlpriv->sec.being_setkey = false; + return err; +} + +static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + bool radio_state; + bool blocked; + u8 valid = 0; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + return; + + mutex_lock(&rtlpriv->locks.conf_mutex); + + /*if Radio On return true here */ + radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + + if (valid) { + if (unlikely(radio_state != rtlpriv->rfkill.rfkill_state)) { + rtlpriv->rfkill.rfkill_state = radio_state; + + RT_TRACE(COMP_RF, DBG_DMESG, + (KERN_INFO "wireless radio switch turned %s\n", + radio_state ? "on" : "off")); + + blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); + } + } + + mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +/* this function is called by mac80211 to flush tx buffer + * before switch channle or power save, or tx buffer packet + * maybe send after offchannel or rf sleep, this may cause + * dis-association by AP */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->intf_ops->flush) + rtlpriv->intf_ops->flush(hw, queues, drop); +} +#else +static void rtl_op_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->intf_ops->flush) + rtlpriv->intf_ops->flush(hw, drop); +} +#endif + +const struct ieee80211_ops rtl_ops = { + .start = rtl_op_start, + .stop = rtl_op_stop, + .tx = rtl_op_tx, + .add_interface = rtl_op_add_interface, + .remove_interface = rtl_op_remove_interface, +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) +/**/ + .change_interface = rtl_op_change_interface, +/**/ +#endif +/**/ + .config = rtl_op_config, + .configure_filter = rtl_op_configure_filter, + .set_key = rtl_op_set_key, + .conf_tx = rtl_op_conf_tx, + .bss_info_changed = rtl_op_bss_info_changed, + .get_tsf = rtl_op_get_tsf, + .set_tsf = rtl_op_set_tsf, + .reset_tsf = rtl_op_reset_tsf, + .sta_notify = rtl_op_sta_notify, + .ampdu_action = rtl_op_ampdu_action, + .sw_scan_start = rtl_op_sw_scan_start, + .sw_scan_complete = rtl_op_sw_scan_complete, + .rfkill_poll = rtl_op_rfkill_poll, + .sta_add = rtl_op_sta_add, + .sta_remove = rtl_op_sta_remove, + .flush = rtl_op_flush, +}; --- linux-3.13.0.orig/drivers/staging/rtl8821ae/cam.h +++ linux-3.13.0/drivers/staging/rtl8821ae/cam.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_CAM_H_ +#define __RTL_CAM_H_ + +#define CAM_CONTENT_COUNT 8 + +#define CFG_DEFAULT_KEY BIT(5) +#define CFG_VALID BIT(15) + +#define PAIRWISE_KEYIDX 0 +#define CAM_PAIRWISE_KEY_POSITION 4 + +#define CAM_CONFIG_USEDK 1 +#define CAM_CONFIG_NO_USEDK 0 + +extern void rtl_cam_reset_all_entry(struct ieee80211_hw *hw); +extern u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, + u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg, + u32 ul_default_key, u8 *key_content); +int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, + u32 ul_key_id); +void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/stats.c +++ linux-3.13.0/drivers/staging/rtl8821ae/stats.c @@ -0,0 +1,283 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#include "wifi.h" +#include "stats.h" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +#include +#endif + +u8 rtl_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return (100 + antpower); +} +//EXPORT_SYMBOL(rtl_query_rxpwrpercentage); + +u8 rtl_evm_db_to_percentage(char value) +{ + char ret_val; + ret_val = value; + + if (ret_val >= 0) + ret_val = 0; + if (ret_val <= -33) + ret_val = -33; + ret_val = 0 - ret_val; + ret_val *= 3; + if (ret_val == 99) + ret_val = 100; + + return ret_val; +} +//EXPORT_SYMBOL(rtl_evm_db_to_percentage); + +long rtl_translate_todbm(struct ieee80211_hw *hw, + u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + return signal_power; +} + +long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig) +{ + long retsig; + + if (currsig >= 61 && currsig <= 100) + retsig = 90 + ((currsig - 60) / 4); + else if (currsig >= 41 && currsig <= 60) + retsig = 78 + ((currsig - 40) / 2); + else if (currsig >= 31 && currsig <= 40) + retsig = 66 + (currsig - 30); + else if (currsig >= 21 && currsig <= 30) + retsig = 54 + (currsig - 20); + else if (currsig >= 5 && currsig <= 20) + retsig = 42 + (((currsig - 5) * 2) / 3); + else if (currsig == 4) + retsig = 36; + else if (currsig == 3) + retsig = 27; + else if (currsig == 2) + retsig = 18; + else if (currsig == 1) + retsig = 9; + else + retsig = currsig; + + return retsig; +} +//EXPORT_SYMBOL(rtl_signal_scale_mapping); + +void rtl_process_ui_rssi(struct ieee80211_hw *hw, struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + u32 last_rssi, tmpval; + + if (!pstatus->b_packet_toself && !pstatus->b_packet_beacon) + return; + + rtlpriv->stats.pwdb_all_cnt += pstatus->rx_pwdb_all; + rtlpriv->stats.rssi_calculate_cnt++; + + if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; + last_rssi = rtlpriv->stats.ui_rssi.elements[ + rtlpriv->stats.ui_rssi.index]; + rtlpriv->stats.ui_rssi.total_val -= last_rssi; + } + rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] = + pstatus->signalstrength; + if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) + rtlpriv->stats.ui_rssi.index = 0; + tmpval = rtlpriv->stats.ui_rssi.total_val / + rtlpriv->stats.ui_rssi.total_num; + rtlpriv->stats.signal_strength = rtl_translate_todbm(hw, + (u8) tmpval); + pstatus->rssi = rtlpriv->stats.signal_strength; + + if (pstatus->b_is_cck) + return; + + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstatus->rx_mimo_signalstrength[rfpath]; + + } + if (pstatus->rx_mimo_signalstrength[rfpath] > + rtlpriv->stats.rx_rssi_percentage[rfpath]) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + rtlpriv->stats.rx_rssi_percentage[rfpath] = + rtlpriv->stats.rx_rssi_percentage[rfpath] + 1; + } else { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + rtlpriv->stats.rx_snr_db[rfpath] = pstatus->rx_snr[rfpath]; + rtlpriv->stats.rx_evm_dbm[rfpath] = + pstatus->rx_mimo_evm_dbm[rfpath]; + rtlpriv->stats.rx_cfo_short[rfpath] = + pstatus->cfo_short[rfpath]; + rtlpriv->stats.rx_cfo_tail[rfpath] = pstatus->cfo_tail[rfpath]; + } +} + +static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower; + if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * + 5 + pstatus->recvsignalpower + weighting) / 6; +} + +static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *drv_priv = NULL; + struct ieee80211_sta *sta = NULL; + long undecorated_smoothed_pwdb; + + rcu_read_lock(); + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + sta = rtl_find_sta(hw, pstatus->psaddr); + + /* adhoc or ap mode */ + if (sta) { + drv_priv = (struct rtl_sta_info *) sta->drv_priv; + undecorated_smoothed_pwdb = + drv_priv->rssi_stat.undecorated_smoothed_pwdb; + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + } + + if (undecorated_smoothed_pwdb < 0) + undecorated_smoothed_pwdb = pstatus->rx_pwdb_all; + if (pstatus->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { + undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undecorated_smoothed_pwdb = undecorated_smoothed_pwdb + 1; + } else { + undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } + + if(sta) { + drv_priv->rssi_stat.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + } else { + rtlpriv->dm.undecorated_smoothed_pwdb = undecorated_smoothed_pwdb; + } + rcu_read_unlock(); + + rtl_update_rxsignalstatistics(hw, pstatus); +} + +static void rtl_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm, n_stream, tmpval; + + if (pstatus->signalquality == 0) + return; + + if (rtlpriv->stats.ui_link_quality.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + rtlpriv->stats.ui_link_quality.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index]; + rtlpriv->stats.ui_link_quality.total_val -= last_evm; + } + rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality; + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index++] = + pstatus->signalquality; + if (rtlpriv->stats.ui_link_quality.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + rtlpriv->stats.ui_link_quality.index = 0; + tmpval = rtlpriv->stats.ui_link_quality.total_val / + rtlpriv->stats.ui_link_quality.total_num; + rtlpriv->stats.signal_quality = tmpval; + rtlpriv->stats.last_sigstrength_inpercent = tmpval; + for (n_stream = 0; n_stream < 2; n_stream++) { + if (pstatus->rx_mimo_signalquality[n_stream] != -1) { + if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) { + rtlpriv->stats.rx_evm_percentage[n_stream] = + pstatus->rx_mimo_signalquality[n_stream]; + } + rtlpriv->stats.rx_evm_percentage[n_stream] = + ((rtlpriv->stats.rx_evm_percentage[n_stream] + * (RX_SMOOTH_FACTOR - 1)) + + (pstatus->rx_mimo_signalquality[n_stream] * 1)) / + (RX_SMOOTH_FACTOR); + } + } +} + +void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, + struct rtl_stats *pstatus) +{ + + if (!pstatus->b_packet_matchbssid) + return; + + rtl_process_ui_rssi(hw, pstatus); + rtl_process_pwdb(hw, pstatus); + rtl_process_ui_link_quality(hw, pstatus); +} +//EXPORT_SYMBOL(rtl_process_phyinfo); --- linux-3.13.0.orig/drivers/staging/rtl8821ae/regd.c +++ linux-3.13.0/drivers/staging/rtl8821ae/regd.c @@ -0,0 +1,503 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "wifi.h" +#include "regd.h" + +static struct country_code_to_enum_rd allCountries[] = { + {COUNTRY_CODE_FCC, "US"}, + {COUNTRY_CODE_IC, "US"}, + {COUNTRY_CODE_ETSI, "EC"}, + {COUNTRY_CODE_SPAIN, "EC"}, + {COUNTRY_CODE_FRANCE, "EC"}, + {COUNTRY_CODE_MKK, "JP"}, + {COUNTRY_CODE_MKK1, "JP"}, + {COUNTRY_CODE_ISRAEL, "EC"}, + {COUNTRY_CODE_TELEC, "JP"}, + {COUNTRY_CODE_MIC, "JP"}, + {COUNTRY_CODE_GLOBAL_DOMAIN, "JP"}, + {COUNTRY_CODE_WORLD_WIDE_13, "EC"}, + {COUNTRY_CODE_TELEC_NETGEAR, "EC"}, +}; + +/* + *Only these channels all allow active + *scan on all world regulatory domains + */ +#define RTL819x_2GHZ_CH01_11 \ + REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) + +/* + *We enable active scan on these a case + *by case basis by regulatory domain + */ +#define RTL819x_2GHZ_CH12_13 \ + REG_RULE(2467-10, 2472+10, 40, 0, 20,\ + NL80211_RRF_PASSIVE_SCAN) + +#define RTL819x_2GHZ_CH14 \ + REG_RULE(2484-10, 2484+10, 40, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_OFDM) + +/* 5G chan 36 - chan 64*/ +#define RTL819x_5GHZ_5150_5350 \ + REG_RULE(5150-10, 5350+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 100 - chan 165*/ +#define RTL819x_5GHZ_5470_5850 \ + REG_RULE(5470-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 149 - chan 165*/ +#define RTL819x_5GHZ_5725_5850 \ + REG_RULE(5725-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +#define RTL819x_5GHZ_ALL \ + RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850 + +static const struct ieee80211_regdomain rtl_regdom_11 = { + .n_reg_rules = 1, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_12_13 = { + .n_reg_rules = 2, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_no_midband = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_5GHZ_5150_5350, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_60_64 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + } +}; + +static bool _rtl_is_radar_freq(u16 center_freq) +{ + return (center_freq >= 5260 && center_freq <= 5700); +} + +static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + const struct ieee80211_reg_rule *reg_rule; + struct ieee80211_channel *ch; + unsigned int i; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)) + u32 bandwidth = 0; + int r; +#endif + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + + if (!wiphy->bands[band]) + continue; + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (_rtl_is_radar_freq(ch->center_freq) || + (ch->flags & IEEE80211_CHAN_RADAR)) + continue; + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (IS_ERR(reg_rule)) + continue; +#else + r = freq_reg_info(wiphy, ch->center_freq, + bandwidth, ®_rule); + if (r) + continue; +#endif + + /* + *If 11d had a rule for this channel ensure + *we enable adhoc/beaconing if it allows us to + *use it. Note that we would have disabled it + *by applying our static world regdomain by + *default during init, prior to calling our + *regulatory_hint(). + */ + + if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) + ch->flags &= ~IEEE80211_CHAN_NO_IBSS; + if (!(reg_rule->flags & + NL80211_RRF_PASSIVE_SCAN)) + ch->flags &= + ~IEEE80211_CHAN_PASSIVE_SCAN; + } else { + if (ch->beacon_found) + ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN); + } + } + } +} + +/* Allows active scan scan on Ch 12 and 13 */ +static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator + initiator) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + const struct ieee80211_reg_rule *reg_rule; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)) + u32 bandwidth = 0; + int r; +#endif + + if (!wiphy->bands[IEEE80211_BAND_2GHZ]) + return; + sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + + /* + *If no country IE has been received always enable active scan + *on these channels. This is only done for specific regulatory SKUs + */ + if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + ch = &sband->channels[11]; /* CH 12 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + ch = &sband->channels[12]; /* CH 13 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + return; + } + + /* + *If a country IE has been recieved check its rule for this + *channel first before enabling active scan. The passive scan + *would have been enforced by the initial processing of our + *custom regulatory domain. + */ + + ch = &sband->channels[11]; /* CH 12 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { +#else + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); + if (!r) { +#endif + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } + + ch = &sband->channels[12]; /* CH 13 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) + reg_rule = freq_reg_info(wiphy, ch->center_freq); + if (!IS_ERR(reg_rule)) { +#else + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); + if (!r) { +#endif + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } +} + +/* + *Always apply Radar/DFS rules on + *freq range 5260 MHz - 5700 MHz + */ +static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + unsigned int i; + + if (!wiphy->bands[IEEE80211_BAND_5GHZ]) + return; + + sband = wiphy->bands[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (!_rtl_is_radar_freq(ch->center_freq)) + continue; + + /* + *We always enable radar detection/DFS on this + *frequency range. Additionally we also apply on + *this frequency range: + *- If STA mode does not yet have DFS supports disable + * active scanning + *- If adhoc mode does not support DFS yet then disable + * adhoc in the frequency. + *- If AP mode does not yet support radar detection/DFS + *do not allow AP mode + */ + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) + ch->flags |= IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN; + } +} + +static void _rtl_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + struct rtl_regulatory *reg) +{ + _rtl_reg_apply_beaconing_flags(wiphy, initiator); + _rtl_reg_apply_active_scan_flags(wiphy, initiator); + return; +} + +static void _rtl_dump_channel_map(struct wiphy *wiphy) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + unsigned int i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + sband = wiphy->bands[band]; + for (i = 0; i < sband->n_channels; i++) + ch = &sband->channels[i]; + } +} + +static int _rtl_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct rtl_regulatory *reg) +{ + /* We always apply this */ + _rtl_reg_apply_radar_flags(wiphy); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + break; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + _rtl_reg_apply_world_flags(wiphy, request->initiator, reg); + break; + } + + _rtl_dump_channel_map(wiphy); + + return 0; +} + +static const struct ieee80211_regdomain *_rtl_regdomain_select( + struct rtl_regulatory *reg) +{ + switch (reg->country_code) { + case COUNTRY_CODE_FCC: + return &rtl_regdom_no_midband; + case COUNTRY_CODE_IC: + return &rtl_regdom_11; + case COUNTRY_CODE_ETSI: + case COUNTRY_CODE_TELEC_NETGEAR: + return &rtl_regdom_60_64; + case COUNTRY_CODE_SPAIN: + case COUNTRY_CODE_FRANCE: + case COUNTRY_CODE_ISRAEL: + case COUNTRY_CODE_WORLD_WIDE_13: + return &rtl_regdom_12_13; + case COUNTRY_CODE_MKK: + case COUNTRY_CODE_MKK1: + case COUNTRY_CODE_TELEC: + case COUNTRY_CODE_MIC: + return &rtl_regdom_14_60_64; + case COUNTRY_CODE_GLOBAL_DOMAIN: + return &rtl_regdom_14; + default: + return &rtl_regdom_no_midband; + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) +static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, + struct wiphy *wiphy, + void (*reg_notifier) (struct wiphy * wiphy, + struct regulatory_request * + request)) +#else +static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, + struct wiphy *wiphy, + int (*reg_notifier) (struct wiphy * wiphy, + struct regulatory_request * + request)) +#endif +{ + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; + + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; + wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; + + regd = _rtl_regdomain_select(reg); + wiphy_apply_custom_regulatory(wiphy, regd); + _rtl_reg_apply_radar_flags(wiphy); + _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); + return 0; +} + +static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].countrycode == countrycode) + return &allCountries[i]; + } + return NULL; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) +int rtl_regd_init(struct ieee80211_hw *hw, + void (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request *request)) +#else +int rtl_regd_init(struct ieee80211_hw *hw, + int (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request *request)) +#endif +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct wiphy *wiphy = hw->wiphy; + struct country_code_to_enum_rd *country = NULL; + + if (wiphy == NULL || &rtlpriv->regd == NULL) + return -EINVAL; + + /* init country_code from efuse channel plan */ + rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan; + + RT_TRACE(COMP_REGD, DBG_TRACE, + (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", + rtlpriv->regd.country_code)); + + if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) { + RT_TRACE(COMP_REGD, DBG_DMESG, + (KERN_DEBUG "rtl: EEPROM indicates invalid contry code" + "world wide 13 should be used\n")); + + rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; + } + + country = _rtl_regd_find_country(rtlpriv->regd.country_code); + + if (country) { + rtlpriv->regd.alpha2[0] = country->iso_name[0]; + rtlpriv->regd.alpha2[1] = country->iso_name[1]; + } else { + rtlpriv->regd.alpha2[0] = '0'; + rtlpriv->regd.alpha2[1] = '0'; + } + + RT_TRACE(COMP_REGD, DBG_TRACE, + (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n", + rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1])); + + _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier); + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) +void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_REGD, DBG_LOUD, ("\n")); + + _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); +} +#else +int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_REGD, DBG_LOUD, ("\n")); + + return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); +} +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/efuse.h +++ linux-3.13.0/drivers/staging/rtl8821ae/efuse.h @@ -0,0 +1,130 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_EFUSE_H_ +#define __RTL_EFUSE_H_ + +#define EFUSE_IC_ID_OFFSET 506 + +/* +#define EFUSE_REAL_CONTENT_LEN 512 +#define EFUSE_MAP_LEN 128 +#define EFUSE_MAX_SECTION 16 +#define EFUSE_MAX_WORD_UNIT 4 +#define EFUSE_IC_ID_OFFSET 506 +*/ + +#define EFUSE_MAX_WORD_UNIT 4 + +#define EFUSE_INIT_MAP 0 +#define EFUSE_MODIFY_MAP 1 + +#define PG_STATE_HEADER 0x01 +#define PG_STATE_WORD_0 0x02 +#define PG_STATE_WORD_1 0x04 +#define PG_STATE_WORD_2 0x08 +#define PG_STATE_WORD_3 0x10 +#define PG_STATE_DATA 0x20 + +#define PG_SWBYTE_H 0x01 +#define PG_SWBYTE_L 0x02 + +#define _POWERON_DELAY_ +#define _PRE_EXECUTE_READ_CMD_ + +#define EFUSE_REPEAT_THRESHOLD_ 3 +#define EFUSE_ERROE_HANDLE 1 + +struct efuse_map { + u8 offset; + u8 word_start; + u8 byte_start; + u8 byte_cnts; +}; + +struct pgpkt_struct { + u8 offset; + u8 word_en; + u8 data[8]; +}; + +enum efuse_data_item { + EFUSE_CHIP_ID = 0, + EFUSE_LDO_SETTING, + EFUSE_CLK_SETTING, + EFUSE_SDIO_SETTING, + EFUSE_CCCR, + EFUSE_SDIO_MODE, + EFUSE_OCR, + EFUSE_F0CIS, + EFUSE_F1CIS, + EFUSE_MAC_ADDR, + EFUSE_EEPROM_VER, + EFUSE_CHAN_PLAN, + EFUSE_TXPW_TAB +}; + +enum { + VOLTAGE_V25 = 0x03, + LDOE25_SHIFT = 28, +}; + +struct efuse_priv { + u8 id[2]; + u8 ldo_setting[2]; + u8 clk_setting[2]; + u8 cccr; + u8 sdio_mode; + u8 ocr[3]; + u8 cis0[17]; + u8 cis1[48]; + u8 mac_addr[6]; + u8 eeprom_verno; + u8 channel_plan; + u8 tx_power_b[14]; + u8 tx_power_g[14]; +}; + +extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); +extern void efuse_initialize(struct ieee80211_hw *hw); +extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); +extern int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data); +extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); +extern void read_efuse(struct ieee80211_hw *hw, u16 _offset, + u16 _size_byte, u8 * pbuf); +extern void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 * value); +extern void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 value); +extern bool efuse_shadow_update(struct ieee80211_hw *hw); +extern bool efuse_shadow_update_chk(struct ieee80211_hw *hw); +extern void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw); +extern void efuse_force_write_vendor_Id(struct ieee80211_hw *hw); +extern void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rc.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rc.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_RC_H__ +#define __RTL_RC_H__ + +#define B_MODE_MAX_RIX 3 +#define G_MODE_MAX_RIX 11 +#define A_MODE_MAX_RIX 7 + +/* in mac80211 mcs0-mcs15 is idx0-idx15*/ +#define N_MODE_MCS7_RIX 7 +#define N_MODE_MCS15_RIX 15 + +struct rtl_rate_priv { + u8 ht_cap; +}; + +int rtl_rate_control_register(void); +void rtl_rate_control_unregister(void); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/regd.h +++ linux-3.13.0/drivers/staging/rtl8821ae/regd.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_REGD_H__ +#define __RTL_REGD_H__ + +#define IEEE80211_CHAN_NO_IBSS 1<<2 +#define IEEE80211_CHAN_PASSIVE_SCAN 1<<1 +#define WIPHY_FLAG_CUSTOM_REGULATORY BIT(0) +#define WIPHY_FLAG_STRICT_REGULATORY BIT(1) +#define WIPHY_FLAG_DISABLE_BEACON_HINTS BIT(2) + +struct country_code_to_enum_rd { + u16 countrycode; + const char *iso_name; +}; + +enum country_code_type_t { + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC = 8, + COUNTRY_CODE_MIC = 9, + COUNTRY_CODE_GLOBAL_DOMAIN = 10, + COUNTRY_CODE_WORLD_WIDE_13 = 11, + COUNTRY_CODE_TELEC_NETGEAR = 12, + + /*add new channel plan above this line */ + COUNTRY_CODE_MAX +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) +int rtl_regd_init(struct ieee80211_hw *hw, + void (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request *request)); +void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); +#else +int rtl_regd_init(struct ieee80211_hw *hw, + int (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request *request)); +int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); +#endif + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/ps.h +++ linux-3.13.0/drivers/staging/rtl8821ae/ps.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __REALTEK_RTL_PCI_PS_H__ +#define __REALTEK_RTL_PCI_PS_H__ + +#define MAX_SW_LPS_SLEEP_INTV 5 + +bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, + enum rf_pwrstate state_toset, u32 changesource, + bool protect_or_not); +bool rtl_ps_enable_nic(struct ieee80211_hw *hw); +bool rtl_ps_disable_nic(struct ieee80211_hw *hw); +void rtl_ips_nic_off(struct ieee80211_hw *hw); +void rtl_ips_nic_on(struct ieee80211_hw *hw); +void rtl_ips_nic_off_wq_callback(void *data); +void rtl_lps_enter(struct ieee80211_hw *hw); +void rtl_lps_leave(struct ieee80211_hw *hw); + +void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode); + +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_swlps_wq_callback(void *data); +void rtl_swlps_rfon_wq_callback(void *data); +void rtl_swlps_rf_awake(struct ieee80211_hw *hw); +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); +void rtl_p2p_ps_cmd(struct ieee80211_hw *hw,u8 p2p_ps_state); +void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/efuse.c +++ linux-3.13.0/drivers/staging/rtl8821ae/efuse.c @@ -0,0 +1,1285 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * Tmis program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Tme full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#include "wifi.h" +#include "efuse.h" +#include "btcoexist/halbt_precomp.h" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +#include +#endif + +static const u8 MAX_PGPKT_SIZE = 9; +static const u8 PGPKT_DATA_SIZE = 8; +static const int EFUSE_MAX_SIZE = 512; + +static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = { + {0, 0, 0, 2}, + {0, 1, 0, 2}, + {0, 2, 0, 2}, + {1, 0, 0, 1}, + {1, 0, 1, 1}, + {1, 1, 0, 1}, + {1, 1, 1, 3}, + {1, 3, 0, 17}, + {3, 3, 1, 48}, + {10, 0, 0, 6}, + {10, 3, 0, 1}, + {10, 3, 1, 1}, + {11, 0, 0, 28} +}; + +static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, + u8 * value); +static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, + u16 * value); +static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset, + u32 * value); +static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset, + u8 value); +static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset, + u16 value); +static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset, + u32 value); +static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, + u8 data); +static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse); +static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, + u8 *data); +static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset, + u8 word_en, u8 * data); +static void efuse_word_enable_data_read(u8 word_en, u8 * sourdata, + u8 * targetdata); +static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, + u16 efuse_addr, u8 word_en, u8 * data); +static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, + u8 pwrstate); +static u16 efuse_get_current_size(struct ieee80211_hw *hw); +static u8 efuse_calculate_word_cnts(u8 word_en); + +void efuse_initialize(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bytetemp; + u8 temp; + + bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1); + temp = bytetemp | 0x20; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, temp); + + bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1); + temp = bytetemp & 0xFE; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, temp); + + bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); + temp = bytetemp | 0x80; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, temp); + + rtl_write_byte(rtlpriv, 0x2F8, 0x3); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); + +} + +u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 data; + u8 bytetemp; + u8 temp; + u32 k = 0; + const u32 efuse_real_content_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + + if (address < efuse_real_content_len) { + temp = address & 0xFF; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + temp); + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2); + temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + temp = bytetemp & 0x7F; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, + temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + while (!(bytetemp & 0x80)) { + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg-> + maps[EFUSE_CTRL] + 3); + k++; + if (k == 1000) { + k = 0; + break; + } + } + data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + return data; + } else + return 0xFF; + +} +//EXPORT_SYMBOL(efuse_read_1byte); + +void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bytetemp; + u8 temp; + u32 k = 0; + const u32 efuse_real_content_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + + RT_TRACE(COMP_EFUSE, DBG_LOUD, + ("Addr=%x Data =%x\n", address, value)); + + if (address < efuse_real_content_len) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); + + temp = address & 0xFF; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + temp); + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2); + + temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2, temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + temp = bytetemp | 0x80; + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3, temp); + + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + + while (bytetemp & 0x80) { + bytetemp = rtl_read_byte(rtlpriv, + rtlpriv->cfg-> + maps[EFUSE_CTRL] + 3); + k++; + if (k == 100) { + k = 0; + break; + } + } + } + +} + +void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 value32; + u8 readbyte; + u16 retry; + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + (_offset & 0xff)); + readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); + + readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, + (readbyte & 0x7f)); + + retry = 0; + value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { + value32 = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL]); + retry++; + } + + udelay(50); + value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + + *pbuf = (u8) (value32 & 0xff); +} + +void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 efuse_tbl[rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]]; + u8 rtemp8[1]; + u16 efuse_addr = 0; + u8 offset, wren; + u8 u1temp = 0; + u16 i; + u16 j; + const u16 efuse_max_section = + rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; + const u32 efuse_real_content_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + u16 efuse_word[efuse_max_section][EFUSE_MAX_WORD_UNIT]; + u16 efuse_utilized = 0; + u8 efuse_usage; + + if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { + RT_TRACE(COMP_EFUSE, DBG_LOUD, + ("read_efuse(): Invalid offset(%#x) with read " + "bytes(%#x)!!\n", _offset, _size_byte)); + return; + } + + for (i = 0; i < efuse_max_section; i++) + for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) + efuse_word[i][j] = 0xFFFF; + + read_efuse_byte(hw, efuse_addr, rtemp8); + if (*rtemp8 != 0xFF) { + efuse_utilized++; + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + ("Addr=%d\n", efuse_addr)); + efuse_addr++; + } + + while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_real_content_len)) { + /* Check PG header for section num. */ + if((*rtemp8 & 0x1F ) == 0x0F) {/* extended header */ + u1temp =( (*rtemp8 & 0xE0) >> 5); + read_efuse_byte(hw, efuse_addr, rtemp8); + + if((*rtemp8 & 0x0F) == 0x0F) { + efuse_addr++; + read_efuse_byte(hw, efuse_addr, rtemp8); + + if (*rtemp8 != 0xFF && + (efuse_addr < efuse_real_content_len)) { + efuse_addr++; + } + continue; + } else { + offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; + wren = (*rtemp8 & 0x0F); + efuse_addr++; + } + } else { + offset = ((*rtemp8 >> 4) & 0x0f); + wren = (*rtemp8 & 0x0f); + } + + if (offset < efuse_max_section) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + ("offset-%d Worden=%x\n", offset, wren)); + + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + if (!(wren & 0x01)) { + RTPRINT(rtlpriv, FEEPROM, + EFUSE_READ_ALL, ("Addr=%d\n", + efuse_addr)); + + read_efuse_byte(hw, efuse_addr, rtemp8); + efuse_addr++; + efuse_utilized++; + efuse_word[offset][i] = (*rtemp8 & + 0xff); + + if (efuse_addr >= + efuse_real_content_len) + break; + + RTPRINT(rtlpriv, FEEPROM, + EFUSE_READ_ALL, ("Addr=%d\n", + efuse_addr)); + + read_efuse_byte(hw, efuse_addr, rtemp8); + efuse_addr++; + efuse_utilized++; + efuse_word[offset][i] |= + (((u16) * rtemp8 << 8) & 0xff00); + + if (efuse_addr >= efuse_real_content_len) + break; + } + + wren >>= 1; + } + } + + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + ("Addr=%d\n", efuse_addr)); + read_efuse_byte(hw, efuse_addr, rtemp8); + if (*rtemp8 != 0xFF && (efuse_addr < efuse_real_content_len)) { + efuse_utilized++; + efuse_addr++; + } + } + + for (i = 0; i < efuse_max_section; i++) { + for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { + efuse_tbl[(i * 8) + (j * 2)] = + (efuse_word[i][j] & 0xff); + efuse_tbl[(i * 8) + ((j * 2) + 1)] = + ((efuse_word[i][j] >> 8) & 0xff); + } + } + + for (i = 0; i < _size_byte; i++) + pbuf[i] = efuse_tbl[_offset + i]; + + rtlefuse->efuse_usedbytes = efuse_utilized; + efuse_usage = (u8) ((efuse_utilized * 100) / efuse_real_content_len); + rtlefuse->efuse_usedpercentage = efuse_usage; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, + (u8 *) & efuse_utilized); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE, + (u8 *) & efuse_usage); +} + +bool efuse_shadow_update_chk(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 section_idx, i, Base; + u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; + bool bwordchanged, bresult = true; + + for (section_idx = 0; section_idx < 16; section_idx++) { + Base = section_idx * 8; + bwordchanged = false; + + for (i = 0; i < 8; i = i + 2) { + if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i]) || + (rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i + 1] != + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + + 1])) { + words_need++; + bwordchanged = true; + } + } + + if (bwordchanged == true) + hdr_num++; + } + + totalbytes = hdr_num + words_need * 2; + efuse_used = rtlefuse->efuse_usedbytes; + + if ((totalbytes + efuse_used) >= (EFUSE_MAX_SIZE - + rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) + bresult = false; + + RT_TRACE(COMP_EFUSE, DBG_LOUD, + ("efuse_shadow_update_chk(): totalbytes(%#x), " + "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", + totalbytes, hdr_num, words_need, efuse_used)); + + return bresult; +} + +void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 *value) +{ + if (type == 1) + efuse_shadow_read_1byte(hw, offset, (u8 *) value); + else if (type == 2) + efuse_shadow_read_2byte(hw, offset, (u16 *) value); + else if (type == 4) + efuse_shadow_read_4byte(hw, offset, (u32 *) value); + +} + +void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, + u32 value) +{ + if (type == 1) + efuse_shadow_write_1byte(hw, offset, (u8) value); + else if (type == 2) + efuse_shadow_write_2byte(hw, offset, (u16) value); + else if (type == 4) + efuse_shadow_write_4byte(hw, offset, (u32) value); + +} + +bool efuse_shadow_update(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u16 i, offset, base; + u8 word_en = 0x0F; + u8 first_pg = false; + + RT_TRACE(COMP_EFUSE, DBG_LOUD, ("\n")); + + if (!efuse_shadow_update_chk(hw)) { + efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + + RT_TRACE(COMP_EFUSE, DBG_LOUD, + ("efuse out of capacity!!\n")); + return false; + } + efuse_power_switch(hw, true, true); + + for (offset = 0; offset < 16; offset++) { + + word_en = 0x0F; + base = offset * 8; + + for (i = 0; i < 8; i++) { + if (first_pg == true) { + + word_en &= ~(BIT(i / 2)); + + rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; + } else { + + if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) { + word_en &= ~(BIT(i / 2)); + + rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; + } + } + } + + if (word_en != 0x0F) { + u8 tmpdata[8]; + memcpy(tmpdata, (&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base]), 8); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, + ("U-efuse\n"), tmpdata, 8); + + if (!efuse_pg_packet_write(hw, (u8) offset, word_en, + tmpdata)) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("PG section(%#x) fail!!\n", offset)); + break; + } + } + + } + + efuse_power_switch(hw, true, false); + efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + + RT_TRACE(COMP_EFUSE, DBG_LOUD, ("\n")); + return true; +} + +void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + if (rtlefuse->autoload_failflag == true) { + memset((&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), + 0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + } else { + efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + } + + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + +} +//EXPORT_SYMBOL(rtl_efuse_shadow_map_update); + +void efuse_force_write_vendor_Id(struct ieee80211_hw *hw) +{ + u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF }; + + efuse_power_switch(hw, true, true); + + efuse_pg_packet_write(hw, 1, 0xD, tmpdata); + + efuse_power_switch(hw, true, false); + +} + +void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx) +{ +} + +static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, + u16 offset, u8 *value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; +} + +static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, + u16 offset, u16 *value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; + +} + +static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, + u16 offset, u32 *value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16; + *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24; +} + +static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, + u16 offset, u8 value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value; +} + +static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, + u16 offset, u16 value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF; + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8; + +} + +static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, + u16 offset, u32 value) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = + (u8) (value & 0x000000FF); + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = + (u8) ((value >> 8) & 0x0000FF); + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] = + (u8) ((value >> 16) & 0x00FF); + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] = + (u8) ((value >> 24) & 0xFF); + +} + +int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; + int bresult; + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + (u8) (addr & 0xff)); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + ((u8) ((addr >> 8) & 0x03)) | + (rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 2) & + 0xFC)); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); + + while (!(0x80 & rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) + && (tmpidx < 100)) { + tmpidx++; + } + + if (tmpidx < 100) { + *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + bresult = true; + } else { + *data = 0xff; + bresult = false; + } + return bresult; +} +//EXPORT_SYMBOL(efuse_one_byte_read); + +static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; + bool bresult; + + RT_TRACE(COMP_EFUSE, DBG_LOUD, + ("Addr = %x Data=%x\n", addr, data)); + + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff)); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, + (rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + + 2) & 0xFC) | (u8) ((addr >> 8) & 0x03)); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], data); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0xF2); + + while ((0x80 & rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) + && (tmpidx < 100)) { + tmpidx++; + } + + if (tmpidx < 100) + bresult = true; + else + bresult = false; + + return bresult; +} + +static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + efuse_power_switch(hw, false, true); + read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); + efuse_power_switch(hw, false, false); +} + +static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, + u8 efuse_data, u8 offset, u8 *tmpdata, + u8 *readstate) +{ + bool bdataempty = true; + u8 hoffset; + u8 tmpidx; + u8 hworden; + u8 word_cnts; + + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + word_cnts = efuse_calculate_word_cnts(hworden); + + if (hoffset == offset) { + for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) { + if (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx, + &efuse_data)) { + tmpdata[tmpidx] = efuse_data; + if (efuse_data != 0xff) + bdataempty = true; + } + } + + if (bdataempty == true) { + *readstate = PG_STATE_DATA; + } else { + *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; + *readstate = PG_STATE_HEADER; + } + + } else { + *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; + *readstate = PG_STATE_HEADER; + } +} + +static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) +{ + u8 readstate = PG_STATE_HEADER; + + bool bcontinual = true; + + u8 efuse_data, word_cnts = 0; + u16 efuse_addr = 0; + u8 hworden = 0; + u8 tmpdata[8]; + + if (data == NULL) + return false; + if (offset > 15) + return false; + + memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + + while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { + if (readstate & PG_STATE_HEADER) { + if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) + && (efuse_data != 0xFF)) + efuse_read_data_case1(hw, &efuse_addr, efuse_data, offset, + tmpdata, &readstate); + else + bcontinual = false; + } else if (readstate & PG_STATE_DATA) { + efuse_word_enable_data_read(hworden, tmpdata, data); + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + readstate = PG_STATE_HEADER; + } + + } + + if ((data[0] == 0xff) && (data[1] == 0xff) && + (data[2] == 0xff) && (data[3] == 0xff) && + (data[4] == 0xff) && (data[5] == 0xff) && + (data[6] == 0xff) && (data[7] == 0xff)) + return false; + else + return true; + +} + +static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, + u8 efuse_data, u8 offset, int *bcontinual, + u8 *write_state, struct pgpkt_struct *target_pkt, + int *repeat_times, int *bresult, u8 word_en) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct tmp_pkt; + int bdataempty = true; + u8 originaldata[8 * sizeof(u8)]; + u8 badworden = 0x0F; + u8 match_word_en, tmp_word_en; + u8 tmpindex; + u8 tmp_header = efuse_data; + u8 tmp_word_cnts; + + tmp_pkt.offset = (tmp_header >> 4) & 0x0F; + tmp_pkt.word_en = tmp_header & 0x0F; + tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); + + if (tmp_pkt.offset != target_pkt->offset) { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + *write_state = PG_STATE_HEADER; + } else { + for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) { + if (efuse_one_byte_read(hw, + (*efuse_addr + 1 + tmpindex), + &efuse_data) && (efuse_data != 0xFF)) + bdataempty = false; + } + + if (bdataempty == false) { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + *write_state = PG_STATE_HEADER; + } else { + match_word_en = 0x0F; + if (!((target_pkt->word_en & BIT(0)) | + (tmp_pkt.word_en & BIT(0)))) + match_word_en &= (~BIT(0)); + + if (!((target_pkt->word_en & BIT(1)) | + (tmp_pkt.word_en & BIT(1)))) + match_word_en &= (~BIT(1)); + + if (!((target_pkt->word_en & BIT(2)) | + (tmp_pkt.word_en & BIT(2)))) + match_word_en &= (~BIT(2)); + + if (!((target_pkt->word_en & BIT(3)) | + (tmp_pkt.word_en & BIT(3)))) + match_word_en &= (~BIT(3)); + + if ((match_word_en & 0x0F) != 0x0F) { + badworden = efuse_word_enable_data_write(hw, + *efuse_addr + 1, + tmp_pkt.word_en, + target_pkt->data); + + if (0x0F != (badworden & 0x0F)) { + u8 reorg_offset = offset; + u8 reorg_worden = badworden; + efuse_pg_packet_write(hw, reorg_offset, + reorg_worden, + originaldata); + } + + tmp_word_en = 0x0F; + if ((target_pkt->word_en & BIT(0)) ^ + (match_word_en & BIT(0))) + tmp_word_en &= (~BIT(0)); + + if ((target_pkt->word_en & BIT(1)) ^ + (match_word_en & BIT(1))) + tmp_word_en &= (~BIT(1)); + + if ((target_pkt->word_en & BIT(2)) ^ + (match_word_en & BIT(2))) + tmp_word_en &= (~BIT(2)); + + if ((target_pkt->word_en & BIT(3)) ^ + (match_word_en & BIT(3))) + tmp_word_en &= (~BIT(3)); + + if ((tmp_word_en & 0x0F) != 0x0F) { + *efuse_addr = efuse_get_current_size(hw); + target_pkt->offset = offset; + target_pkt->word_en = tmp_word_en; + } else { + *bcontinual = false; + } + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { + *bcontinual = false; + *bresult = false; + } + } else { + *efuse_addr += (2 * tmp_word_cnts) + 1; + target_pkt->offset = offset; + target_pkt->word_en = word_en; + *write_state = PG_STATE_HEADER; + } + } + } + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER-1\n")); +} + +static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, + int *bcontinual, u8 *write_state, + struct pgpkt_struct target_pkt, + int *repeat_times, int *bresult) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct tmp_pkt; + u8 pg_header; + u8 tmp_header; + u8 originaldata[8 * sizeof(u8)]; + u8 tmp_word_cnts; + u8 badworden = 0x0F; + + pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en; + efuse_one_byte_write(hw, *efuse_addr, pg_header); + efuse_one_byte_read(hw, *efuse_addr, &tmp_header); + + if (tmp_header == pg_header) { + *write_state = PG_STATE_DATA; + } else if (tmp_header == 0xFF) { + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { + *bcontinual = false; + *bresult = false; + } + } else { + tmp_pkt.offset = (tmp_header >> 4) & 0x0F; + tmp_pkt.word_en = tmp_header & 0x0F; + + tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); + + memset(originaldata, 0xff, 8 * sizeof(u8)); + + if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { + badworden = efuse_word_enable_data_write(hw, + *efuse_addr + 1, + tmp_pkt.word_en, + originaldata); + + if (0x0F != (badworden & 0x0F)) { + u8 reorg_offset = tmp_pkt.offset; + u8 reorg_worden = badworden; + efuse_pg_packet_write(hw, reorg_offset, + reorg_worden, + originaldata); + *efuse_addr = efuse_get_current_size(hw); + } else { + *efuse_addr = *efuse_addr + + (tmp_word_cnts * 2) + 1; + } + } else { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + } + + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { + *bcontinual = false; + *bresult = false; + } + + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse PG_STATE_HEADER-2\n")); + } +} + +static int efuse_pg_packet_write(struct ieee80211_hw *hw, + u8 offset, u8 word_en, u8 *data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct target_pkt; + u8 write_state = PG_STATE_HEADER; + int bcontinual = true, bdataempty = true, bresult = true; + u16 efuse_addr = 0; + u8 efuse_data; + u8 target_word_cnts = 0; + u8 badworden = 0x0F; + static int repeat_times = 0; + + if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE - + rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse_pg_packet_write error \n")); + return false; + } + + target_pkt.offset = offset; + target_pkt.word_en = word_en; + + memset(target_pkt.data, 0xFF, 8 * sizeof(u8)); + + efuse_word_enable_data_read(word_en, data, target_pkt.data); + target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); + + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n")); + + while (bcontinual && (efuse_addr < (EFUSE_MAX_SIZE - + rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) { + + if (write_state == PG_STATE_HEADER) { + bdataempty = true; + badworden = 0x0F; + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse PG_STATE_HEADER\n")); + + if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && + (efuse_data != 0xFF)) + efuse_write_data_case1(hw, &efuse_addr, + efuse_data, offset, + &bcontinual, + &write_state, + &target_pkt, + &repeat_times, &bresult, + word_en); + else + efuse_write_data_case2(hw, &efuse_addr, + &bcontinual, + &write_state, + target_pkt, + &repeat_times, + &bresult); + + } else if (write_state == PG_STATE_DATA) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse PG_STATE_DATA\n")); + badworden = 0x0f; + badworden = + efuse_word_enable_data_write(hw, efuse_addr + 1, + target_pkt.word_en, + target_pkt.data); + + if ((badworden & 0x0F) == 0x0F) { + bcontinual = false; + } else { + efuse_addr = + efuse_addr + (2 * target_word_cnts) + 1; + + target_pkt.offset = offset; + target_pkt.word_en = badworden; + target_word_cnts = + efuse_calculate_word_cnts(target_pkt. + word_en); + write_state = PG_STATE_HEADER; + repeat_times++; + if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { + bcontinual = false; + bresult = false; + } + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse PG_STATE_HEADER-3\n")); + } + } + } + + if (efuse_addr >= (EFUSE_MAX_SIZE - + rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { + RT_TRACE(COMP_EFUSE, DBG_LOUD, + ("efuse_addr(%#x) Out of size!!\n", efuse_addr)); + } + + return true; +} + +static void efuse_word_enable_data_read(u8 word_en, u8 * sourdata, + u8 *targetdata) +{ + if (!(word_en & BIT(0))) { + targetdata[0] = sourdata[0]; + targetdata[1] = sourdata[1]; + } + + if (!(word_en & BIT(1))) { + targetdata[2] = sourdata[2]; + targetdata[3] = sourdata[3]; + } + + if (!(word_en & BIT(2))) { + targetdata[4] = sourdata[4]; + targetdata[5] = sourdata[5]; + } + + if (!(word_en & BIT(3))) { + targetdata[6] = sourdata[6]; + targetdata[7] = sourdata[7]; + } +} + +static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, + u16 efuse_addr, u8 word_en, u8 *data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 tmpaddr; + u16 start_addr = efuse_addr; + u8 badworden = 0x0F; + u8 tmpdata[8]; + + memset(tmpdata, 0xff, PGPKT_DATA_SIZE); + RT_TRACE(COMP_EFUSE, DBG_LOUD, + ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr)); + + if (!(word_en & BIT(0))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[0]); + efuse_one_byte_write(hw, start_addr++, data[1]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]); + if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) + badworden &= (~BIT(0)); + } + + if (!(word_en & BIT(1))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[2]); + efuse_one_byte_write(hw, start_addr++, data[3]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]); + if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) + badworden &= (~BIT(1)); + } + + if (!(word_en & BIT(2))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[4]); + efuse_one_byte_write(hw, start_addr++, data[5]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]); + if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) + badworden &= (~BIT(2)); + } + + if (!(word_en & BIT(3))) { + tmpaddr = start_addr; + efuse_one_byte_write(hw, start_addr++, data[6]); + efuse_one_byte_write(hw, start_addr++, data[7]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]); + efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]); + if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) + badworden &= (~BIT(3)); + } + + return badworden; +} + +static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tempval; + u16 tmpV16; + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + if (pwrstate == true) + { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69); + + // 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid + tmpV16 = rtl_read_word(rtlpriv, + rtlpriv->cfg->maps[SYS_ISO_CTRL]); + + printk("SYS_ISO_CTRL=%04x.\n",tmpV16); + if( ! (tmpV16 & PWC_EV12V ) ){ + tmpV16 |= PWC_EV12V ; + //PlatformEFIOWrite2Byte(pAdapter,REG_SYS_ISO_CTRL,tmpV16); + } + // Reset: 0x0000h[28], default valid + tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN]); + printk("SYS_FUNC_EN=%04x.\n",tmpV16); + if( !(tmpV16 & FEN_ELDR) ){ + tmpV16 |= FEN_ELDR ; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN], tmpV16); + } + + // Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid + tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK] ); + printk("SYS_CLK=%04x.\n",tmpV16); + if( (!(tmpV16 & LOADER_CLK_EN) ) ||(!(tmpV16 & ANA8M) ) ) + { + tmpV16 |= (LOADER_CLK_EN |ANA8M ) ; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_CLK], tmpV16); + } + + if(bwrite == true) + { + // Enable LDO 2.5V before read/write action + tempval = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); + printk("EFUSE_TEST=%04x.\n",tmpV16); + tempval &= ~(BIT(3) | BIT(4) |BIT(5) | BIT(6)); + tempval |= (VOLTAGE_V25 << 3); + tempval |= BIT(7); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, tempval); + } + } + else + { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], 0x00); + if(bwrite == true){ + // Disable LDO 2.5V after read/write action + tempval = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, (tempval & 0x7F)); + } + } + } + else + { + if (pwrstate == true && (rtlhal->hw_type != + HARDWARE_TYPE_RTL8192SE)) { + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE) + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], + 0x69); + + tmpV16 = rtl_read_word(rtlpriv, + rtlpriv->cfg->maps[SYS_ISO_CTRL]); + if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { + tmpV16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V]; + rtl_write_word(rtlpriv, + rtlpriv->cfg->maps[SYS_ISO_CTRL], + tmpV16); + } + + tmpV16 = rtl_read_word(rtlpriv, + rtlpriv->cfg->maps[SYS_FUNC_EN]); + if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) { + tmpV16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR]; + rtl_write_word(rtlpriv, + rtlpriv->cfg->maps[SYS_FUNC_EN], tmpV16); + } + + tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK]); + if ((!(tmpV16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) || + (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) { + tmpV16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] | + rtlpriv->cfg->maps[EFUSE_ANA8M]); + rtl_write_word(rtlpriv, + rtlpriv->cfg->maps[SYS_CLK], tmpV16); + } + } + + if (pwrstate == true) { + if (bwrite == true) { + tempval = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + + 3); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { + tempval &= 0x0F; + tempval |= (VOLTAGE_V25 << 4); + } + + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + 3, + (tempval | 0x80)); + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x03); + } + + } else { + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE) + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], 0); + + if (bwrite == true) { + tempval = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + + 3); + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + 3, + (tempval & 0x7F)); + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x02); + } + + } + } + +} + +static u16 efuse_get_current_size(struct ieee80211_hw *hw) +{ + int bcontinual = true; + u16 efuse_addr = 0; + u8 hoffset, hworden; + u8 efuse_data, word_cnts; + + while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) + && (efuse_addr < EFUSE_MAX_SIZE)) { + if (efuse_data != 0xFF) { + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + word_cnts = efuse_calculate_word_cnts(hworden); + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + } else { + bcontinual = false; + } + } + + return efuse_addr; +} + +static u8 efuse_calculate_word_cnts(u8 word_en) +{ + u8 word_cnts = 0; + if (!(word_en & BIT(0))) + word_cnts++; + if (!(word_en & BIT(1))) + word_cnts++; + if (!(word_en & BIT(2))) + word_cnts++; + if (!(word_en & BIT(3))) + word_cnts++; + return word_cnts; +} + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/wifi.h +++ linux-3.13.0/drivers/staging/rtl8821ae/wifi.h @@ -0,0 +1,2532 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_WIFI_H__ +#define __RTL_WIFI_H__ + +#include +#include +#include +#include +#include +#include +#include "debug.h" + + +#define RF_CHANGE_BY_INIT 0 +#define RF_CHANGE_BY_IPS BIT(28) +#define RF_CHANGE_BY_PS BIT(29) +#define RF_CHANGE_BY_HW BIT(30) +#define RF_CHANGE_BY_SW BIT(31) + +#define IQK_ADDA_REG_NUM 16 +#define IQK_MAC_REG_NUM 4 +#define IQK_THRESHOLD 8 + +#define MAX_KEY_LEN 61 +#define KEY_BUF_SIZE 5 + +/* QoS related. */ +/*aci: 0x00 Best Effort*/ +/*aci: 0x01 Background*/ +/*aci: 0x10 Video*/ +/*aci: 0x11 Voice*/ +/*Max: define total number.*/ +#define AC0_BE 0 +#define AC1_BK 1 +#define AC2_VI 2 +#define AC3_VO 3 +#define AC_MAX 4 +#define QOS_QUEUE_NUM 4 +#define RTL_MAC80211_NUM_QUEUE 5 + +#define QBSS_LOAD_SIZE 5 +#define MAX_WMMELE_LENGTH 64 + +#define TOTAL_CAM_ENTRY 32 + +/*slot time for 11g. */ +#define RTL_SLOT_TIME_9 9 +#define RTL_SLOT_TIME_20 20 + +/*related with tcp/ip. */ +/*if_ehther.h*/ +#define ETH_P_PAE 0x888E /*Port Access Entity + *(IEEE 802.1X) */ +#define ETH_P_IP 0x0800 /*Internet Protocol packet */ +#define ETH_P_ARP 0x0806 /*Address Resolution packet */ +#define SNAP_SIZE 6 +#define PROTOC_TYPE_SIZE 2 + +/*related with 802.11 frame*/ +#define MAC80211_3ADDR_LEN 24 +#define MAC80211_4ADDR_LEN 30 + +#define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max + * channel number */ +#define CHANNEL_MAX_NUMBER_2G 14 +#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to + *"phy_GetChnlGroup8812A" and + * "Hal_ReadTxPowerInfo8812A"*/ +#define CHANNEL_MAX_NUMBER_5G_80M 7 +#define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, ch4~9, ch10~14 + * total three groups */ +#define MAX_PG_GROUP 13 +#define CHANNEL_GROUP_MAX_2G 3 +#define CHANNEL_GROUP_IDX_5GL 3 +#define CHANNEL_GROUP_IDX_5GM 6 +#define CHANNEL_GROUP_IDX_5GH 9 +#define CHANNEL_GROUP_MAX_5G 9 +#define CHANNEL_MAX_NUMBER_2G 14 +#define AVG_THERMAL_NUM 8 +#define AVG_THERMAL_NUM_92E 4 +#define AVG_THERMAL_NUM_88E 4 +#define AVG_THERMAL_NUM_8723BE 4 +#define MAX_TID_COUNT 9 +#define MAX_NUM_RATES 264 + +/*for 88E use*/ +/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/ +#define MAX_TX_COUNT 4 +#define MAX_RF_PATH 4 +#define MAX_CHNL_GROUP_24G 6 +#define MAX_CHNL_GROUP_5G 14 + +/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */ +#define MAX_TX_QUEUE 9 + +#define TX_PWR_BY_RATE_NUM_BAND 2 +#define TX_PWR_BY_RATE_NUM_RF 4 +#define TX_PWR_BY_RATE_NUM_SECTION 12 +#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 +#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 + +#define DELTA_SWINGIDX_SIZE 30 +#define BAND_NUM 3 +/*Now, it's just for 8192ee + *not OK yet, keep it 0*/ +#define DMA_IS_64BIT 0 +#define RTL8192EE_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */ + +struct txpower_info_2g { + u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; + u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; + /*If only one tx, only BW20 and OFDM are used.*/ + u8 cck_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; +}; + +struct txpower_info_5g { + u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_5G]; + /*If only one tx, only BW20, OFDM, BW80 and BW160 are used.*/ + u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT]; +}; + + +/* for early mode */ +#define EM_HDR_LEN 8 +#define FCS_LEN 4 + +#define MAX_VIRTUAL_MAC 1 + +enum rf_tx_num { + RF_1TX = 0, + RF_2TX, + RF_MAX_TX_NUM, + RF_TX_NUM_NONIMPLEMENT, +}; + +enum rate_section { + CCK = 0, + OFDM, + HT_MCS0_MCS7, + HT_MCS8_MCS15, + VHT_1SSMCS0_1SSMCS9, + VHT_2SSMCS0_2SSMCS9, +}; + +enum intf_type { + INTF_PCI = 0, + INTF_USB = 1, +}; + +enum radio_path { + RF90_PATH_A = 0, + RF90_PATH_B = 1, + RF90_PATH_C = 2, + RF90_PATH_D = 3, +}; + +enum rt_eeprom_type { + EEPROM_93C46, + EEPROM_93C56, + EEPROM_BOOT_EFUSE, +}; + +enum rtl_status { + RTL_STATUS_INTERFACE_START = 0, +}; + +enum hardware_type { + HARDWARE_TYPE_RTL8192E, + HARDWARE_TYPE_RTL8192U, + HARDWARE_TYPE_RTL8192SE, + HARDWARE_TYPE_RTL8192SU, + HARDWARE_TYPE_RTL8192CE, + HARDWARE_TYPE_RTL8192CU, + HARDWARE_TYPE_RTL8192DE, + HARDWARE_TYPE_RTL8192DU, + HARDWARE_TYPE_RTL8723AE, + HARDWARE_TYPE_RTL8188EE, + HARDWARE_TYPE_RTL8723BE, + HARDWARE_TYPE_RTL8192EE, + HARDWARE_TYPE_RTL8821AE, + HARDWARE_TYPE_RTL8812AE, + /* keep it last */ + HARDWARE_TYPE_NUM +}; + +enum scan_operation_backup_opt { + SCAN_OPT_BACKUP_BAND0=0, + SCAN_OPT_BACKUP_BAND1, + SCAN_OPT_RESTORE, + SCAN_OPT_MAX +}; + +/*RF state.*/ +enum rf_pwrstate { + ERFON, + ERFSLEEP, + ERFOFF +}; + +struct bb_reg_def { + u32 rfintfs; + u32 rfintfi; + u32 rfintfo; + u32 rfintfe; + u32 rf3wire_offset; + u32 rflssi_select; + u32 rftxgain_stage; + u32 rfhssi_para1; + u32 rfhssi_para2; + u32 rfswitch_control; + u32 rfagc_control1; + u32 rfagc_control2; + u32 rfrxiq_imbalance; + u32 rfrx_afe; + u32 rftxiq_imbalance; + u32 rftx_afe; + u32 rflssi_readback; + u32 rflssi_readbackpi; +}; + +enum io_type { + IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0, + IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1, + IO_CMD_RESUME_DM_BY_SCAN = 2, +}; + +enum hw_variables { + HW_VAR_ETHER_ADDR, + HW_VAR_MULTICAST_REG, + HW_VAR_BASIC_RATE, + HW_VAR_BSSID, + HW_VAR_MEDIA_STATUS, + HW_VAR_SECURITY_CONF, + HW_VAR_BEACON_INTERVAL, + HW_VAR_ATIM_WINDOW, + HW_VAR_LISTEN_INTERVAL, + HW_VAR_CS_COUNTER, + HW_VAR_DEFAULTKEY0, + HW_VAR_DEFAULTKEY1, + HW_VAR_DEFAULTKEY2, + HW_VAR_DEFAULTKEY3, + HW_VAR_SIFS, + HW_VAR_DIFS, + HW_VAR_EIFS, + HW_VAR_SLOT_TIME, + HW_VAR_ACK_PREAMBLE, + HW_VAR_CW_CONFIG, + HW_VAR_CW_VALUES, + HW_VAR_RATE_FALLBACK_CONTROL, + HW_VAR_CONTENTION_WINDOW, + HW_VAR_RETRY_COUNT, + HW_VAR_TR_SWITCH, + HW_VAR_COMMAND, + HW_VAR_WPA_CONFIG, + HW_VAR_AMPDU_MIN_SPACE, + HW_VAR_SHORTGI_DENSITY, + HW_VAR_AMPDU_FACTOR, + HW_VAR_MCS_RATE_AVAILABLE, + HW_VAR_AC_PARAM, + HW_VAR_ACM_CTRL, + HW_VAR_DIS_Req_Qsize, + HW_VAR_CCX_CHNL_LOAD, + HW_VAR_CCX_NOISE_HISTOGRAM, + HW_VAR_CCX_CLM_NHM, + HW_VAR_TxOPLimit, + HW_VAR_TURBO_MODE, + HW_VAR_RF_STATE, + HW_VAR_RF_OFF_BY_HW, + HW_VAR_BUS_SPEED, + HW_VAR_SET_DEV_POWER, + + HW_VAR_RCR, + HW_VAR_RATR_0, + HW_VAR_RRSR, + HW_VAR_CPU_RST, + HW_VAR_CECHK_BSSID, + HW_VAR_LBK_MODE, + HW_VAR_AES_11N_FIX, + HW_VAR_USB_RX_AGGR, + HW_VAR_USER_CONTROL_TURBO_MODE, + HW_VAR_RETRY_LIMIT, + HW_VAR_INIT_TX_RATE, + HW_VAR_TX_RATE_REG, + HW_VAR_EFUSE_USAGE, + HW_VAR_EFUSE_BYTES, + HW_VAR_AUTOLOAD_STATUS, + HW_VAR_RF_2R_DISABLE, + HW_VAR_SET_RPWM, + HW_VAR_H2C_FW_PWRMODE, + HW_VAR_H2C_FW_JOINBSSRPT, + HW_VAR_H2C_FW_MEDIASTATUSRPT, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + HW_VAR_FW_PSMODE_STATUS, + HW_VAR_RESUME_CLK_ON, + HW_VAR_FW_LPS_ACTION, + HW_VAR_1X1_RECV_COMBINE, + HW_VAR_STOP_SEND_BEACON, + HW_VAR_TSF_TIMER, + HW_VAR_IO_CMD, + + HW_VAR_RF_RECOVERY, + HW_VAR_H2C_FW_UPDATE_GTK, + HW_VAR_WF_MASK, + HW_VAR_WF_CRC, + HW_VAR_WF_IS_MAC_ADDR, + HW_VAR_H2C_FW_OFFLOAD, + HW_VAR_RESET_WFCRC, + + HW_VAR_HANDLE_FW_C2H, + HW_VAR_DL_FW_RSVD_PAGE, + HW_VAR_AID, + HW_VAR_HW_SEQ_ENABLE, + HW_VAR_CORRECT_TSF, + HW_VAR_BCN_VALID, + HW_VAR_FWLPS_RF_ON, + HW_VAR_DUAL_TSF_RST, + HW_VAR_SWITCH_EPHY_WoWLAN, + HW_VAR_INT_MIGRATION, + HW_VAR_INT_AC, + HW_VAR_RF_TIMING, + + HAL_DEF_WOWLAN, + HW_VAR_MRC, + HW_VAR_KEEP_ALIVE, + HW_VAR_NAV_UPPER, +}; + +enum rt_media_status { + RT_MEDIA_DISCONNECT = 0, + RT_MEDIA_CONNECT = 1 +}; + +enum rt_oem_id { + RT_CID_DEFAULT = 0, + RT_CID_8187_ALPHA0 = 1, + RT_CID_8187_SERCOMM_PS = 2, + RT_CID_8187_HW_LED = 3, + RT_CID_8187_NETGEAR = 4, + RT_CID_WHQL = 5, + RT_CID_819x_CAMEO = 6, + RT_CID_819x_RUNTOP = 7, + RT_CID_819x_Senao = 8, + RT_CID_TOSHIBA = 9, + RT_CID_819x_Netcore = 10, + RT_CID_Nettronix = 11, + RT_CID_DLINK = 12, + RT_CID_PRONET = 13, + RT_CID_COREGA = 14, + RT_CID_819x_ALPHA = 15, + RT_CID_819x_Sitecom = 16, + RT_CID_CCX = 17, + RT_CID_819x_Lenovo = 18, + RT_CID_819x_QMI = 19, + RT_CID_819x_Edimax_Belkin = 20, + RT_CID_819x_Sercomm_Belkin = 21, + RT_CID_819x_CAMEO1 = 22, + RT_CID_819x_MSI = 23, + RT_CID_819x_Acer = 24, + RT_CID_819x_HP = 27, + RT_CID_819x_CLEVO = 28, + RT_CID_819x_Arcadyan_Belkin = 29, + RT_CID_819x_SAMSUNG = 30, + RT_CID_819x_WNC_COREGA = 31, + RT_CID_819x_Foxcoon = 32, + RT_CID_819x_DELL = 33, + RT_CID_819x_PRONETS = 34, + RT_CID_819x_Edimax_ASUS = 35, + RT_CID_NETGEAR = 36, + RT_CID_PLANEX = 37, + RT_CID_CC_C = 38, +}; + +enum hw_descs { + HW_DESC_OWN, + HW_DESC_RXOWN, + HW_DESC_TX_NEXTDESC_ADDR, + HW_DESC_TXBUFF_ADDR, + HW_DESC_RXBUFF_ADDR, + HW_DESC_RXPKT_LEN, + HW_DESC_RXERO, + HW_DESC_RX_PREPARE, +}; + +enum prime_sc { + PRIME_CHNL_OFFSET_DONT_CARE = 0, + PRIME_CHNL_OFFSET_LOWER = 1, + PRIME_CHNL_OFFSET_UPPER = 2, +}; + +enum rf_type { + RF_1T1R = 0, + RF_1T2R = 1, + RF_2T2R = 2, + RF_2T2R_GREEN = 3, +}; + +enum ht_channel_width { + HT_CHANNEL_WIDTH_20 = 0, + HT_CHANNEL_WIDTH_20_40 = 1, + HT_CHANNEL_WIDTH_80 = 2, +}; + +/* Ref: 802.11i sepc D10.0 7.3.2.25.1 +Cipher Suites Encryption Algorithms */ +enum rt_enc_alg { + NO_ENCRYPTION = 0, + WEP40_ENCRYPTION = 1, + TKIP_ENCRYPTION = 2, + RSERVED_ENCRYPTION = 3, + AESCCMP_ENCRYPTION = 4, + WEP104_ENCRYPTION = 5, + AESCMAC_ENCRYPTION = 6, /*IEEE802.11w */ +}; + +enum rtl_hal_state { + _HAL_STATE_STOP = 0, + _HAL_STATE_START = 1, +}; + +enum rtl_var_map { + /*reg map */ + SYS_ISO_CTRL = 0, + SYS_FUNC_EN, + SYS_CLK, + MAC_RCR_AM, + MAC_RCR_AB, + MAC_RCR_ACRC32, + MAC_RCR_ACF, + MAC_RCR_AAP, + MAC_HIMR, + MAC_HIMRE, + MAC_HSISR, + + /*efuse map */ + EFUSE_TEST, + EFUSE_CTRL, + EFUSE_CLK, + EFUSE_CLK_CTRL, + EFUSE_PWC_EV12V, + EFUSE_FEN_ELDR, + EFUSE_LOADER_CLK_EN, + EFUSE_ANA8M, + EFUSE_HWSET_MAX_SIZE, + EFUSE_MAX_SECTION_MAP, + EFUSE_REAL_CONTENT_SIZE, + EFUSE_OOB_PROTECT_BYTES_LEN, + EFUSE_ACCESS, + /*CAM map */ + RWCAM, + WCAMI, + RCAMO, + CAMDBG, + SECR, + SEC_CAM_NONE, + SEC_CAM_WEP40, + SEC_CAM_TKIP, + SEC_CAM_AES, + SEC_CAM_WEP104, + + /*IMR map */ + RTL_IMR_BCNDMAINT6, /*Beacon DMA Interrupt 6 */ + RTL_IMR_BCNDMAINT5, /*Beacon DMA Interrupt 5 */ + RTL_IMR_BCNDMAINT4, /*Beacon DMA Interrupt 4 */ + RTL_IMR_BCNDMAINT3, /*Beacon DMA Interrupt 3 */ + RTL_IMR_BCNDMAINT2, /*Beacon DMA Interrupt 2 */ + RTL_IMR_BCNDMAINT1, /*Beacon DMA Interrupt 1 */ + RTL_IMR_BCNDOK8, /*Beacon Queue DMA OK Interrup 8 */ + RTL_IMR_BCNDOK7, /*Beacon Queue DMA OK Interrup 7 */ + RTL_IMR_BCNDOK6, /*Beacon Queue DMA OK Interrup 6 */ + RTL_IMR_BCNDOK5, /*Beacon Queue DMA OK Interrup 5 */ + RTL_IMR_BCNDOK4, /*Beacon Queue DMA OK Interrup 4 */ + RTL_IMR_BCNDOK3, /*Beacon Queue DMA OK Interrup 3 */ + RTL_IMR_BCNDOK2, /*Beacon Queue DMA OK Interrup 2 */ + RTL_IMR_BCNDOK1, /*Beacon Queue DMA OK Interrup 1 */ + RTL_IMR_TIMEOUT2, /*Timeout interrupt 2 */ + RTL_IMR_TIMEOUT1, /*Timeout interrupt 1 */ + RTL_IMR_TXFOVW, /*Transmit FIFO Overflow */ + RTL_IMR_PSTIMEOUT, /*Power save time out interrupt */ + RTL_IMR_BcnInt, /*Beacon DMA Interrupt 0 */ + RTL_IMR_RXFOVW, /*Receive FIFO Overflow */ + RTL_IMR_RDU, /*Receive Descriptor Unavailable */ + RTL_IMR_ATIMEND, /*For 92C,ATIM Window End Interrupt */ + RTL_IMR_BDOK, /*Beacon Queue DMA OK Interrup */ + RTL_IMR_HIGHDOK, /*High Queue DMA OK Interrupt */ + RTL_IMR_COMDOK, /*Command Queue DMA OK Interrupt*/ + RTL_IMR_TBDOK, /*Transmit Beacon OK interrup */ + RTL_IMR_MGNTDOK, /*Management Queue DMA OK Interrupt */ + RTL_IMR_TBDER, /*For 92C,Transmit Beacon Error Interrupt */ + RTL_IMR_BKDOK, /*AC_BK DMA OK Interrupt */ + RTL_IMR_BEDOK, /*AC_BE DMA OK Interrupt */ + RTL_IMR_VIDOK, /*AC_VI DMA OK Interrupt */ + RTL_IMR_VODOK, /*AC_VO DMA Interrupt */ + RTL_IMR_ROK, /*Receive DMA OK Interrupt */ + RTL_IMR_HSISR_IND, /*HSISR Interrupt*/ + RTL_IBSS_INT_MASKS, /*(RTL_IMR_BcnInt | RTL_IMR_TBDOK | + * RTL_IMR_TBDER) */ + RTL_IMR_C2HCMD, /*fw interrupt*/ + + /*CCK Rates, TxHT = 0 */ + RTL_RC_CCK_RATE1M, + RTL_RC_CCK_RATE2M, + RTL_RC_CCK_RATE5_5M, + RTL_RC_CCK_RATE11M, + + /*OFDM Rates, TxHT = 0 */ + RTL_RC_OFDM_RATE6M, + RTL_RC_OFDM_RATE9M, + RTL_RC_OFDM_RATE12M, + RTL_RC_OFDM_RATE18M, + RTL_RC_OFDM_RATE24M, + RTL_RC_OFDM_RATE36M, + RTL_RC_OFDM_RATE48M, + RTL_RC_OFDM_RATE54M, + + RTL_RC_HT_RATEMCS7, + RTL_RC_HT_RATEMCS15, + + /*keep it last */ + RTL_VAR_MAP_MAX, +}; + +/*Firmware PS mode for control LPS.*/ +enum _fw_ps_mode { + FW_PS_ACTIVE_MODE = 0, + FW_PS_MIN_MODE = 1, + FW_PS_MAX_MODE = 2, + FW_PS_DTIM_MODE = 3, + FW_PS_VOIP_MODE = 4, + FW_PS_UAPSD_WMM_MODE = 5, + FW_PS_UAPSD_MODE = 6, + FW_PS_IBSS_MODE = 7, + FW_PS_WWLAN_MODE = 8, + FW_PS_PM_Radio_Off = 9, + FW_PS_PM_Card_Disable = 10, +}; + +enum rt_psmode { + EACTIVE, /*Active/Continuous access. */ + EMAXPS, /*Max power save mode. */ + EFASTPS, /*Fast power save mode. */ + EAUTOPS, /*Auto power save mode. */ +}; + +/*LED related.*/ +enum led_ctl_mode { + LED_CTL_POWER_ON = 1, + LED_CTL_LINK = 2, + LED_CTL_NO_LINK = 3, + LED_CTL_TX = 4, + LED_CTL_RX = 5, + LED_CTL_SITE_SURVEY = 6, + LED_CTL_POWER_OFF = 7, + LED_CTL_START_TO_LINK = 8, + LED_CTL_START_WPS = 9, + LED_CTL_STOP_WPS = 10, +}; + +enum rtl_led_pin { + LED_PIN_GPIO0, + LED_PIN_LED0, + LED_PIN_LED1, + LED_PIN_LED2 +}; + +/*QoS related.*/ +/*acm implementation method.*/ +enum acm_method { + eAcmWay0_SwAndHw = 0, + eAcmWay1_HW = 1, + eAcmWay2_SW = 2, +}; + +enum macphy_mode { + SINGLEMAC_SINGLEPHY = 0, + DUALMAC_DUALPHY, + DUALMAC_SINGLEPHY, +}; + +enum band_type { + BAND_ON_2_4G = 0, + BAND_ON_5G, + BAND_ON_BOTH, + BANDMAX +}; + +/*aci/aifsn Field. +Ref: WMM spec 2.2.2: WME Parameter Element, p.12.*/ +union aci_aifsn { + u8 char_data; + + struct { + u8 aifsn:4; + u8 acm:1; + u8 aci:2; + u8 reserved:1; + } f; /* Field */ +}; + +/*mlme related.*/ +enum wireless_mode { + WIRELESS_MODE_UNKNOWN = 0x00, + WIRELESS_MODE_A = 0x01, + WIRELESS_MODE_B = 0x02, + WIRELESS_MODE_G = 0x04, + WIRELESS_MODE_AUTO = 0x08, + WIRELESS_MODE_N_24G = 0x10, + WIRELESS_MODE_N_5G = 0x20, + WIRELESS_MODE_AC_5G = 0x40, + WIRELESS_MODE_AC_24G = 0x80 +}; + +enum ratr_table_mode { + RATR_INX_WIRELESS_NGB = 0, // BGN 40 Mhz 2SS 1SS + RATR_INX_WIRELESS_NG = 1, // GN or N + RATR_INX_WIRELESS_NB = 2, // BGN 20 Mhz 2SS 1SS or BN + RATR_INX_WIRELESS_N = 3, + RATR_INX_WIRELESS_GB = 4, + RATR_INX_WIRELESS_G = 5, + RATR_INX_WIRELESS_B = 6, + RATR_INX_WIRELESS_MC = 7, + RATR_INX_WIRELESS_AC_5N = 8, + RATR_INX_WIRELESS_AC_24N = 9, +}; + +enum rtl_link_state { + MAC80211_NOLINK = 0, + MAC80211_LINKING = 1, + MAC80211_LINKED = 2, + MAC80211_LINKED_SCANNING = 3, +}; + +enum act_category { + ACT_CAT_QOS = 1, + ACT_CAT_DLS = 2, + ACT_CAT_BA = 3, + ACT_CAT_HT = 7, + ACT_CAT_WMM = 17, +}; + +enum ba_action { + ACT_ADDBAREQ = 0, + ACT_ADDBARSP = 1, + ACT_DELBA = 2, +}; + +enum rt_polarity_ctl { + RT_POLARITY_LOW_ACT = 0, + RT_POLARITY_HIGH_ACT = 1, +}; + + +struct octet_string { + u8 *octet; + u16 length; +}; + +struct rtl_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __packed; + +struct rtl_info_element { + u8 id; + u8 len; + u8 data[0]; +} __packed; + +struct rtl_probe_rsp { + struct rtl_hdr_3addr header; + u32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + /*SSID, supported rates, FH params, DS params, + CF params, IBSS params, TIM (if beacon), RSN */ + struct rtl_info_element info_element[0]; +} __packed; + +/*LED related.*/ +/*ledpin Identify how to implement this SW led.*/ +struct rtl_led { + void *hw; + enum rtl_led_pin ledpin; + bool b_ledon; +}; + +struct rtl_led_ctl { + bool bled_opendrain; + struct rtl_led sw_led0; + struct rtl_led sw_led1; +}; + +struct rtl_qos_parameters { + __le16 cw_min; + __le16 cw_max; + u8 aifs; + u8 flag; + __le16 tx_op; +} __packed; + +struct rt_smooth_data { + u32 elements[100]; /*array to store values */ + u32 index; /*index to current array to store */ + u32 total_num; /*num of valid elements */ + u32 total_val; /*sum of valid elements */ +}; + +struct rtl_ht_agg { + u16 txq_id; + u16 wait_for_ba; + u16 start_idx; + u64 bitmap; + u32 rate_n_flags; + u8 agg_state; + u8 rx_agg_state; +}; + +struct rtl_tid_data { + u16 seq_number; + struct rtl_ht_agg agg; +}; + +struct rssi_sta{ + long undecorated_smoothed_pwdb; +}; + +struct rtl_sta_info { + struct list_head list; + u8 ratr_index; + u8 wireless_mode; + u8 mimo_ps; + u8 mac_addr[6]; + struct rtl_tid_data tids[MAX_TID_COUNT]; + + /* just used for ap adhoc or mesh*/ + struct rssi_sta rssi_stat; +} __packed; + +#ifdef VIF_TODO +struct rtl_vif { + unsigned int id; + /* struct ieee80211_vif __rcu *vif; */ + struct ieee80211_vif *vif; +}; + +struct rtl_vif_info { + struct list_head list; + bool active; + unsigned int id; + struct sk_buff *beacon; + bool enable_beacon; +}; + +struct vif_priv { + struct list_head vif_list; + + /* interface mode settings */ + unsigned long vif_bitmap; + unsigned int vifs; + struct rtl_vif vif[MAX_VIRTUAL_MAC]; + + /* beaconing */ + spinlock_t beacon_lock; + unsigned int global_pretbtt; + unsigned int global_beacon_int; + /* struct rtl_vif_info __rcu *beacon_iter; */ + struct rtl_vif_info *beacon_iter; + unsigned int beacon_enabled; +}; +#endif + +struct false_alarm_statistics { + u32 cnt_parity_fail; + u32 cnt_rate_illegal; + u32 cnt_crc8_fail; + u32 cnt_mcs_fail; + u32 cnt_fast_fsync_fail; + u32 cnt_sb_search_fail; + u32 cnt_ofdm_fail; + u32 cnt_cck_fail; + u32 cnt_all; + u32 cnt_ofdm_cca; + u32 cnt_cck_cca; + u32 cnt_cca_all; + u32 cnt_bw_usc; + u32 cnt_bw_lsc; +}; + +struct init_gain { + u8 xaagccore1; + u8 xbagccore1; + u8 xcagccore1; + u8 xdagccore1; + u8 cca; + +}; + +struct wireless_stats { + unsigned long txbytesunicast; + unsigned long txbytesmulticast; + unsigned long txbytesbroadcast; + unsigned long rxbytesunicast; + + long rx_snr_db[4]; + /*Correct smoothed ss in Dbm, only used + in driver to report real power now. */ + long recv_signal_power; + long signal_quality; + long last_sigstrength_inpercent; + + u32 rssi_calculate_cnt; + u32 pwdb_all_cnt; + + /*Transformed, in dbm. Beautified signal + strength for UI, not correct. */ + long signal_strength; + + u8 rx_rssi_percentage[4]; + u8 rx_evm_dbm[4]; + u8 rx_evm_percentage[2]; + + u16 rx_cfo_short[4]; + u16 rx_cfo_tail[4]; + + struct rt_smooth_data ui_rssi; + struct rt_smooth_data ui_link_quality; +}; + +struct rate_adaptive { + u8 rate_adaptive_disabled; + u8 ratr_state; + u16 reserve; + + u32 high_rssi_thresh_for_ra; + u32 high2low_rssi_thresh_for_ra; + u8 low2high_rssi_thresh_for_ra; + u32 low_rssi_thresh_for_ra; + u32 upper_rssi_threshold_ratr; + u32 middleupper_rssi_threshold_ratr; + u32 middle_rssi_threshold_ratr; + u32 middlelow_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr; + u32 ultralow_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr_40m; + u32 low_rssi_threshold_ratr_20m; + u8 ping_rssi_enable; + u32 ping_rssi_ratr; + u32 ping_rssi_thresh_for_ra; + u32 last_ratr; + u8 pre_ratr_state; + u8 ldpc_thres; + bool use_ldpc; + bool lower_rts_rate; + bool is_special_data; +}; + +struct regd_pair_mapping { + u16 reg_dmnenum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +struct dynamic_primary_cca{ + u8 pricca_flag; + u8 intf_flag; + u8 intf_type; + u8 dup_rts_flag; + u8 monitor_flag; + u8 ch_offset; + u8 mf_state; +}; + +struct rtl_regulatory { + char alpha2[2]; + u16 country_code; + u16 max_power_level; + u32 tp_scale; + u16 current_rd; + u16 current_rd_ext; + int16_t power_limit; + struct regd_pair_mapping *regpair; +}; + +struct rtl_rfkill { + bool rfkill_state; /*0 is off, 1 is on */ +}; + +/*for P2P PS**/ +#define P2P_MAX_NOA_NUM 2 + +enum p2p_role { + P2P_ROLE_DISABLE = 0, + P2P_ROLE_DEVICE = 1, + P2P_ROLE_CLIENT = 2, + P2P_ROLE_GO = 3 +}; + +enum p2p_ps_state { + P2P_PS_DISABLE = 0, + P2P_PS_ENABLE = 1, + P2P_PS_SCAN = 2, + P2P_PS_SCAN_DONE = 3, + P2P_PS_ALLSTASLEEP = 4, // for P2P GO +}; + +enum p2p_ps_mode { + P2P_PS_NONE = 0, + P2P_PS_CTWINDOW = 1, + P2P_PS_NOA = 2, + P2P_PS_MIX = 3, // CTWindow and NoA +}; + +struct rtl_p2p_ps_info { + enum p2p_ps_mode p2p_ps_mode; /* indicate p2p ps mode */ + enum p2p_ps_state p2p_ps_state; /* indicate p2p ps state */ + u8 noa_index; /* Identifies and instance of Notice of Absence timing. */ + /* Client traffic window. A period of time in TU after TBTT. */ + u8 ctwindow; + u8 opp_ps; /* opportunistic power save. */ + u8 noa_num; /* number of NoA descriptor in P2P IE. */ + /* Count for owner, Type of client. */ + u8 noa_count_type[P2P_MAX_NOA_NUM]; + /* Max duration for owner, preferred or + * min acceptable duration for client. */ + u32 noa_duration[P2P_MAX_NOA_NUM]; + /* Length of interval for owner, preferred or + * max acceptable interval of client. */ + u32 noa_interval[P2P_MAX_NOA_NUM]; + /* schedule expressed in terms of the lower 4 bytes of the TSF timer. */ + u32 noa_start_time[P2P_MAX_NOA_NUM]; +}; + + struct p2p_ps_offload_t { + u8 Offload_En:1; + u8 role:1; /* 1: Owner, 0: Client */ + u8 CTWindow_En:1; + u8 NoA0_En:1; + u8 NoA1_En:1; + u8 AllStaSleep:1; + u8 discovery:1; + u8 reserved:1; +}; + +#define IQK_MATRIX_REG_NUM 8 +#define IQK_MATRIX_SETTINGS_NUM (14+24+21) // Channels_2_4G_NUM + Channels_5G_20M_NUM + Channels_5G +struct iqk_matrix_regs { + bool b_iqk_done; + long value[1][IQK_MATRIX_REG_NUM]; +}; + +struct rtl_phy { + struct bb_reg_def phyreg_def[4]; /*Radio A/B/C/D */ + struct init_gain initgain_backup; + enum io_type current_io_type; + + u8 rf_mode; + u8 rf_type; + u8 current_chan_bw; + u8 set_bwmode_inprogress; + u8 sw_chnl_inprogress; + u8 sw_chnl_stage; + u8 sw_chnl_step; + u8 current_channel; + u8 h2c_box_num; + u8 set_io_inprogress; + u8 lck_inprogress; + + /* record for power tracking */ + s32 reg_e94; + s32 reg_e9c; + s32 reg_ea4; + s32 reg_eac; + s32 reg_eb4; + s32 reg_ebc; + s32 reg_ec4; + s32 reg_ecc; + u8 rfpienable; + u8 reserve_0; + u16 reserve_1; + u32 reg_c04, reg_c08, reg_874; + u32 adda_backup[16]; + u32 iqk_mac_backup[IQK_MAC_REG_NUM]; + u32 iqk_bb_backup[10]; + bool iqk_initialized; + + bool rfpath_rx_enable[MAX_RF_PATH]; + /*Jaguar*/ + u8 reg_837; + /* Dul mac */ + bool b_need_iqk; + struct iqk_matrix_regs iqk_matrix_regsetting[IQK_MATRIX_SETTINGS_NUM]; + + bool b_rfpi_enable; + + bool b_iqk_in_progress; + + u8 pwrgroup_cnt; + u8 bcck_high_power; + /* this is for 88E & 8723A */ + u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16]; + /* this is for 92EE */ + u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND] + [TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_SECTION]; + u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [MAX_BASE_NUM_IN_PHY_REG_PG_24G]; + + u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [MAX_BASE_NUM_IN_PHY_REG_PG_5G]; + u8 default_initialgain[4]; + + /* the current Tx power level */ + u8 cur_cck_txpwridx; + u8 cur_ofdm24g_txpwridx; + u8 cur_bw20_txpwridx; + u8 cur_bw40_txpwridx; + + u32 rfreg_chnlval[2]; + bool b_apk_done; + u32 reg_rf3c[2]; /* pathA / pathB */ + + u32 backup_rf_0x1a;/*92ee*/ + /* bfsync */ + u8 framesync; + u32 framesync_c34; + + u8 num_total_rfpath; + u16 rf_pathmap; + + u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ + + enum rt_polarity_ctl polarity_ctl; +}; + +#define RTL_AGG_STOP 0 +#define RTL_AGG_PROGRESS 1 +#define RTL_AGG_START 2 +#define RTL_AGG_OPERATIONAL 3 +#define RTL_RX_AGG_START 1 +#define RTL_RX_AGG_STOP 0 + +struct rtl_priv; +struct rtl_io { + struct device *dev; + + /*PCI MEM map */ + unsigned long pci_mem_end; /*shared mem end */ + unsigned long pci_mem_start; /*shared mem start */ + + /*PCI IO map */ + unsigned long pci_base_addr; /*device I/O address */ + + void (*write8_async) (struct rtl_priv * rtlpriv, u32 addr, u8 val); + void (*write16_async) (struct rtl_priv * rtlpriv, u32 addr, u16 val); + void (*write32_async) (struct rtl_priv * rtlpriv, u32 addr, u32 val); + + u8(*read8_sync) (struct rtl_priv * rtlpriv, u32 addr); + u16(*read16_sync) (struct rtl_priv * rtlpriv, u32 addr); + u32(*read32_sync) (struct rtl_priv * rtlpriv, u32 addr); + +}; + +struct rtl_mac { + u8 mac_addr[ETH_ALEN]; + u8 mac80211_registered; + u8 beacon_enabled; + + u32 tx_ss_num; + u32 rx_ss_num; + + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif; + enum nl80211_iftype opmode; + + /*Probe Beacon management */ + enum rtl_link_state link_state; + + int n_channels; + int n_bitrates; + + bool offchan_deley; + u8 p2p; /*using p2p role*/ + bool p2p_in_use; + + /*filters */ + u32 rx_conf; + + bool act_scanning; + u8 cnt_after_linked; + bool skip_scan; + + /* early mode */ + /* skb wait queue */ + struct sk_buff_head skb_waitq[MAX_TID_COUNT]; + + /*RDG*/ + bool rdg_en; + + /*AP*/ + u8 bssid[6]; + u32 vendor; + u32 basic_rates; /* b/g rates */ + u8 ht_enable; + u8 bw_40; + u8 mode; /* wireless mode */ + u8 slot_time; + u8 short_preamble; + u8 use_cts_protect; + u8 cur_40_prime_sc; + u8 cur_40_prime_sc_bk; + u8 cur_80_prime_sc; + u64 tsf; + u8 retry_short; + u8 retry_long; + u16 assoc_id; + bool bhiddenssid; + + /*IBSS*/ + int beacon_interval; + + /*AMPDU*/ + u8 min_space_cfg; /*For Min spacing configurations */ + u8 max_mss_density; + u8 current_ampdu_factor; + u8 current_ampdu_density; + + /*QOS & EDCA */ + struct ieee80211_tx_queue_params edca_param[RTL_MAC80211_NUM_QUEUE]; + struct rtl_qos_parameters ac[AC_MAX]; +}; + +struct rtl_hal { + struct ieee80211_hw *hw; + + bool driver_is_goingto_unload; + bool up_first_time; + bool bfirst_init; + bool being_init_adapter; + bool b_bbrf_ready; + bool b_mac_func_enable; + bool b_pre_edcca_enable; + + enum intf_type interface; + u16 hw_type; /*92c or 92d or 92s and so on */ + u8 ic_class; + u8 oem_id; + u32 version; /*version of chip */ + u8 state; /*stop 0, start 1 */ + u8 boad_type; + + /*firmware */ + u32 fwsize; + u8 *pfirmware; + u16 fw_version; + u16 fw_subversion; + bool b_h2c_setinprogress; + u8 last_hmeboxnum; + bool bfw_ready; + + /*Reserve page start offset except beacon in TxQ. */ + u8 fw_rsvdpage_startoffset; + u8 h2c_txcmd_seq; + u8 current_ra_rate; + + /* FW Cmd IO related */ + u16 fwcmd_iomap; + u32 fwcmd_ioparam; + bool set_fwcmd_inprogress; + u8 current_fwcmd_io; + + bool bfw_clk_change_in_progress; + bool ballow_sw_to_change_hwclc; + u8 fw_ps_state; + struct p2p_ps_offload_t p2p_ps_offload; + /**/ + bool driver_going2unload; + + /*AMPDU init min space*/ + u8 minspace_cfg; /*For Min spacing configurations */ + + /* Dul mac */ + enum macphy_mode macphymode; + enum band_type current_bandtype; /* 0:2.4G, 1:5G */ + enum band_type current_bandtypebackup; + enum band_type bandset; + /* dual MAC 0--Mac0 1--Mac1 */ + u32 interfaceindex; + /* just for DulMac S3S4 */ + u8 macphyctl_reg; + bool b_earlymode_enable; + u8 max_earlymode_num; + /* Dul mac*/ + bool during_mac0init_radiob; + bool during_mac1init_radioa; + bool reloadtxpowerindex; + /* True if IMR or IQK have done + for 2.4G in scan progress */ + bool b_load_imrandiqk_setting_for2g; + + bool disable_amsdu_8k; + bool bmaster_of_dmsp; + bool bslave_of_dmsp; + + u16 rx_tag;/*for 92ee*/ + u8 rts_en; +}; + +struct rtl_security { + /*default 0 */ + bool use_sw_sec; + + bool being_setkey; + bool use_defaultkey; + /*Encryption Algorithm for Unicast Packet */ + enum rt_enc_alg pairwise_enc_algorithm; + /*Encryption Algorithm for Brocast/Multicast */ + enum rt_enc_alg group_enc_algorithm; + /*Cam Entry Bitmap */ + u32 hwsec_cam_bitmap; + u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN]; + /*local Key buffer, indx 0 is for + pairwise key 1-4 is for agoup key. */ + u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN]; + u8 key_len[KEY_BUF_SIZE]; + + /*The pointer of Pairwise Key, + it always points to KeyBuf[4] */ + u8 *pairwise_key; +}; + +struct rtl_dig { + u8 dig_enable_flag; + u8 dig_ext_port_stage; + + u32 rssi_lowthresh; + u32 rssi_highthresh; + + u32 fa_lowthresh; + u32 fa_highthresh; + + u8 cursta_connectstate; + u8 presta_connectstate; + u8 curmultista_connectstate; + + u8 pre_igvalue; + u8 cur_igvalue; + + char backoff_val; + char backoff_val_range_max; + char backoff_val_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + u8 rssi_val_min; + u8 min_undecorated_pwdb_for_dm; + long last_min_undecorated_pwdb_for_dm; + + u8 pre_cck_pd_state; + u8 cur_cck_pd_state; + + u8 large_fa_hit; + u8 forbidden_igi; + u32 recover_cnt; + +}; + +struct rtl_pstbl { + u8 pre_ccastate; + u8 cur_ccasate; + + u8 pre_rfstate; + u8 cur_rfstate; + + long rssi_val_min; + +}; + +#define ASSOCIATE_ENTRY_NUM 32+1 + +struct fast_ant_trainning{ + u8 bssid[6]; + u8 antsel_rx_keep_0; + u8 antsel_rx_keep_1; + u8 antsel_rx_keep_2; + u32 ant_sum_rssi[7]; + u32 ant_rssi_cnt[7]; + u32 ant_ave_rssi[7]; + u8 fat_state; + u32 train_idx; + u8 antsel_a[ASSOCIATE_ENTRY_NUM]; + u8 antsel_b[ASSOCIATE_ENTRY_NUM]; + u8 antsel_c[ASSOCIATE_ENTRY_NUM]; + u32 main_ant_sum[ASSOCIATE_ENTRY_NUM]; + u32 aux_ant_sum[ASSOCIATE_ENTRY_NUM]; + u32 main_ant_cnt[ASSOCIATE_ENTRY_NUM]; + u32 aux_ant_cnt[ASSOCIATE_ENTRY_NUM]; + u8 rx_idle_ant; + bool b_becomelinked; +}; + +struct dm_phy_dbg_info { + char rx_snrdb[4]; + u64 num_qry_phy_status; + u64 num_qry_phy_status_cck; + u64 num_qry_phy_status_ofdm; + u16 num_qry_beacon_pkt; + u16 num_non_be_pkt; + s32 rx_evm[4]; +}; + +struct rtl_dm { + /*PHY status for DM */ + long entry_min_undecoratedsmoothed_pwdb; + long undecorated_smoothed_pwdb; /*out dm */ + long entry_max_undecoratedsmoothed_pwdb; + bool b_dm_initialgain_enable; + bool bdynamic_txpower_enable; + bool bcurrent_turbo_edca; + bool bis_any_nonbepkts; /*out dm */ + bool bis_cur_rdlstate; + bool btxpower_trackinginit; + bool b_disable_framebursting; + bool b_cck_inch14; + bool btxpower_tracking; + bool b_useramask; + bool brfpath_rxenable[4]; + bool binform_fw_driverctrldm; + bool bcurrent_mrc_switch; + u8 txpowercount; + + u8 thermalvalue_rxgain; + u8 thermalvalue_iqk; + u8 thermalvalue_lck; + u8 thermalvalue; + u8 thermalvalue_avg[AVG_THERMAL_NUM]; + u8 thermalvalue_avg_index; + bool bdone_txpower; + u8 last_dtp_lvl; + u8 dynamic_txhighpower_lvl; /*Tx high power level */ + u8 dm_flag; /*Indicate if each dynamic mechanism's status. */ + u8 dm_type; + u8 txpower_track_control; + bool binterrupt_migration; + bool bdisable_tx_int; + char ofdm_index[MAX_RF_PATH]; + u8 default_ofdm_index; + u8 default_cck_index; + char cck_index; + char delta_power_index[MAX_RF_PATH]; + char delta_power_index_last[MAX_RF_PATH]; + char power_index_offset[MAX_RF_PATH]; + char aboslute_ofdm_swing_idx[MAX_RF_PATH]; + char remnant_ofdm_swing_idx[MAX_RF_PATH]; + char remnant_cck_idx; + bool modify_txagc_flag_path_a; + bool modify_txagc_flag_path_b; + + bool b_one_entry_only; + struct dm_phy_dbg_info dbginfo; + /* Dynamic ATC switch */ + + bool atc_status; + bool large_cfo_hit; + bool is_freeze; + int cfo_tail[2]; + int cfo_ave_pre; + int crystal_cap; + u8 cfo_threshold; + u32 packet_count; + u32 packet_count_pre; + u8 tx_rate; + + + /*88e tx power tracking*/ + u8 bb_swing_idx_ofdm[MAX_RF_PATH]; + u8 bb_swing_idx_ofdm_current; + u8 bb_swing_idx_ofdm_base[MAX_RF_PATH]; + bool bb_swing_flag_Ofdm; + u8 bb_swing_idx_cck; + u8 bb_swing_idx_cck_current; + u8 bb_swing_idx_cck_base; + bool bb_swing_flag_cck; + + char bb_swing_diff_2g; + char bb_swing_diff_5g; + + u8 delta_swing_table_idx_24gccka_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24gccka_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24gcckb_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24gcckb_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24ga_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24ga_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24gb_p[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24gb_n[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5ga_p[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5ga_n[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gb_p[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_5gb_n[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24ga_p_8188e[DELTA_SWINGIDX_SIZE]; + u8 delta_swing_table_idx_24ga_n_8188e[DELTA_SWINGIDX_SIZE]; + + + /* DMSP */ + bool supp_phymode_switch; + + /* DulMac */ + struct rtl_dig dm_digtable; + struct rtl_pstbl dm_pstable; + struct fast_ant_trainning fat_table; + + u8 resp_tx_path; + u8 path_sel; + u32 patha_sum; + u32 pathb_sum; + u32 patha_cnt; + u32 pathb_cnt; + + u8 pre_channel; + u8 *p_channel; + u8 linked_interval; + + u64 last_tx_ok_cnt; + u64 last_rx_ok_cnt; +}; + +#define EFUSE_MAX_LOGICAL_SIZE 256 + +struct rtl_efuse { + bool bautoLoad_ok; + bool bootfromefuse; + u16 max_physical_size; + + u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE]; + u16 efuse_usedbytes; + u8 efuse_usedpercentage; +#ifdef EFUSE_REPG_WORKAROUND + bool efuse_re_pg_sec1flag; + u8 efuse_re_pg_data[8]; +#endif + + u8 autoload_failflag; + u8 autoload_status; + + short epromtype; + u16 eeprom_vid; + u16 eeprom_did; + u16 eeprom_svid; + u16 eeprom_smid; + u8 eeprom_oemid; + u16 eeprom_channelplan; + u8 eeprom_version; + + u8 dev_addr[6]; + u8 board_type; + u8 wowlan_enable; + u8 antenna_div_cfg; + u8 antenna_div_type; + + bool b_txpwr_fromeprom; + u8 eeprom_crystalcap; + u8 eeprom_tssi[2]; + u8 eeprom_tssi_5g[3][2]; /* for 5GL/5GM/5GH band. */ + u8 eeprom_pwrlimit_ht20[CHANNEL_GROUP_MAX]; + u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX]; + u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G]; + u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX]; + u8 eeprom_chnlarea_txpwr_ht40_2sdiif[2][CHANNEL_GROUP_MAX]; + + + u8 internal_pa_5g[2]; /* pathA / pathB */ + u8 eeprom_c9; + u8 eeprom_cc; + + /*For power group */ + u8 eeprom_pwrgroup[2][3]; + u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER]; + u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER]; + + u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + char txpwr_cckdiff[MAX_RF_PATH][MAX_TX_COUNT]; /*CCK_24G_Diff*/ + /*HT 20<->40 Pwr diff */ + char txpwr_ht20diff[MAX_RF_PATH][MAX_TX_COUNT]; /*BW20_24G_Diff*/ + char txpwr_ht40diff[MAX_RF_PATH][MAX_TX_COUNT];/*BW40_24G_Diff*/ + /*For HT<->legacy pwr diff */ + char txpwr_legacyhtdiff[MAX_RF_PATH][MAX_TX_COUNT];/*OFDM_24G_Diff*/ + + u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M]; + char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT]; + + u8 txpwr_safetyflag; /* Band edge enable flag */ + u16 eeprom_txpowerdiff; + u8 legacy_httxpowerdiff; /* Legacy to HT rate power diff */ + u8 antenna_txpwdiff[3]; + + u8 eeprom_regulatory; + u8 eeprom_thermalmeter; + u8 thermalmeter[2];/*ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */ + u16 tssi_13dbm; + u8 crystalcap; /* CrystalCap. */ + u8 delta_iqk; + u8 delta_lck; + + u8 legacy_ht_txpowerdiff; /*Legacy to HT rate power diff */ + bool b_apk_thermalmeterignore; + + bool b1x1_recvcombine; + bool b1ss_support; + + /*channel plan */ + u8 channel_plan; +}; + +struct rtl_ps_ctl { + bool pwrdomain_protect; + bool b_in_powersavemode; + bool rfchange_inprogress; + bool b_swrf_processing; + bool b_hwradiooff; + /* + * just for PCIE ASPM + * If it supports ASPM, Offset[560h] = 0x40, + * otherwise Offset[560h] = 0x00. + * */ + bool b_support_aspm; + bool b_support_backdoor; + + /*for LPS */ + enum rt_psmode dot11_psmode; /*Power save mode configured. */ + bool b_swctrl_lps; + bool b_fwctrl_lps; + u8 fwctrl_psmode; + /*For Fw control LPS mode */ + u8 b_reg_fwctrl_lps; + /*Record Fw PS mode status. */ + bool b_fw_current_inpsmode; + u8 reg_max_lps_awakeintvl; + bool report_linked; + bool b_low_power_enable;/*for 32k*/ + + /*for IPS */ + bool b_inactiveps; + + u32 rfoff_reason; + + /*RF OFF Level */ + u32 cur_ps_level; + u32 reg_rfps_level; + + /*just for PCIE ASPM */ + u8 const_amdpci_aspm; + + enum rf_pwrstate inactive_pwrstate; + enum rf_pwrstate rfpwr_state; /*cur power state */ + + /* for SW LPS*/ + bool sw_ps_enabled; + bool state; + bool state_inap; + bool multi_buffered; + u16 nullfunc_seq; + unsigned int dtim_counter; + unsigned int sleep_ms; + unsigned long last_sleep_jiffies; + unsigned long last_awake_jiffies; + unsigned long last_delaylps_stamp_jiffies; + unsigned long last_dtim; + unsigned long last_beacon; + unsigned long last_action; + unsigned long last_slept; + + /*For P2P PS */ + struct rtl_p2p_ps_info p2p_ps_info; + u8 pwr_mode; + u8 smart_ps; +}; + +struct rtl_stats { + u8 psaddr[ETH_ALEN]; + u32 mac_time[2]; + s8 rssi; + u8 signal; + u8 noise; + u8 rate; /* hw desc rate */ + u8 rawdata; + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u64 tsf; + u32 beacon_time; + u8 nic_type; + u16 length; + u8 signalquality; /*in 0-100 index. */ + /* + * Real power in dBm for this packet, + * no beautification and aggregation. + * */ + s32 recvsignalpower; + s8 rxpower; /*in dBm Translate from PWdB */ + u8 signalstrength; /*in 0-100 index. */ + u16 b_hwerror:1; + u16 b_crc:1; + u16 b_icv:1; + u16 b_shortpreamble:1; + u16 antenna:1; + u16 decrypted:1; + u16 wakeup:1; + u32 timestamp_low; + u32 timestamp_high; + bool b_shift; + + u8 rx_drvinfo_size; + u8 rx_bufshift; + bool b_isampdu; + bool b_isfirst_ampdu; + bool rx_is40Mhzpacket; + u32 rx_pwdb_all; + u8 rx_mimo_signalstrength[4]; /*in 0~100 index */ + s8 rx_mimo_signalquality[4]; + u8 rx_mimo_evm_dbm[4]; + u16 cfo_short[4]; /* per-path's Cfo_short */ + u16 cfo_tail[4]; + + u8 rx_pwr[4]; /* per-path's pwdb */ + u8 rx_snr[4]; /* per-path's SNR */ + u8 bandwidth; + u8 bt_coex_pwr_adjust; + bool b_packet_matchbssid; + bool b_is_cck; + bool b_is_ht; + bool b_packet_toself; + bool b_packet_beacon; /*for rssi */ + char cck_adc_pwdb[4]; /*for rx path selection */ + + u8 packet_report_type; + + u32 macid; + u8 wake_match; + u32 bt_rx_rssi_percentage; + u32 macid_valid_entry[2]; +}; + +struct rt_link_detect { + /* count for raoming */ + u32 bcn_rx_inperiod; + u32 roam_times; + + u32 num_tx_in4period[4]; + u32 num_rx_in4period[4]; + + u32 num_tx_inperiod; + u32 num_rx_inperiod; + + bool b_busytraffic; + bool b_tx_busy_traffic; + bool b_rx_busy_traffic; + bool b_higher_busytraffic; + bool b_higher_busyrxtraffic; + + u32 tidtx_in4period[MAX_TID_COUNT][4]; + u32 tidtx_inperiod[MAX_TID_COUNT]; + bool higher_busytxtraffic[MAX_TID_COUNT]; +}; + +struct rtl_tcb_desc { + u8 b_packet_bw:1; + u8 b_multicast:1; + u8 b_broadcast:1; + + u8 b_rts_stbc:1; + u8 b_rts_enable:1; + u8 b_cts_enable:1; + u8 b_rts_use_shortpreamble:1; + u8 b_rts_use_shortgi:1; + u8 rts_sc:1; + u8 b_rts_bw:1; + u8 rts_rate; + + u8 use_shortgi:1; + u8 use_shortpreamble:1; + u8 use_driver_rate:1; + u8 disable_ratefallback:1; + + u8 ratr_index; + u8 mac_id; + u8 hw_rate; + + u8 b_last_inipkt:1; + u8 b_cmd_or_init:1; + u8 queue_index; + + /* early mode */ + u8 empkt_num; + /* The max value by HW */ + u32 empkt_len[10]; + bool btx_enable_sw_calc_duration; + /* used for hal construct pkt, + * we may set desc when tx */ + u8 self_desc; +}; + +struct proxim { + bool proxim_on; + + void *proximity_priv; + int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status, + struct sk_buff *skb); + u8 (*proxim_get_var)(struct ieee80211_hw *hw, u8 type); +}; + +struct rtl_hal_ops { + int (*init_sw_vars) (struct ieee80211_hw * hw); + void (*deinit_sw_vars) (struct ieee80211_hw * hw); + void (*read_eeprom_info) (struct ieee80211_hw * hw); + void (*interrupt_recognized) (struct ieee80211_hw * hw, + u32 * p_inta, u32 * p_intb); + int (*hw_init) (struct ieee80211_hw * hw); + void (*hw_disable) (struct ieee80211_hw * hw); + void (*hw_suspend) (struct ieee80211_hw * hw); + void (*hw_resume) (struct ieee80211_hw * hw); + void (*enable_interrupt) (struct ieee80211_hw * hw); + void (*disable_interrupt) (struct ieee80211_hw * hw); + int (*set_network_type) (struct ieee80211_hw * hw, + enum nl80211_iftype type); + void (*set_chk_bssid)(struct ieee80211_hw *hw, + bool check_bssid); + void (*set_bw_mode) (struct ieee80211_hw * hw, + enum nl80211_channel_type ch_type); + u8(*switch_channel) (struct ieee80211_hw * hw); + void (*set_qos) (struct ieee80211_hw * hw, int aci); + void (*set_bcn_reg) (struct ieee80211_hw * hw); + void (*set_bcn_intv) (struct ieee80211_hw * hw); + void (*update_interrupt_mask) (struct ieee80211_hw * hw, + u32 add_msr, u32 rm_msr); + void (*get_hw_reg) (struct ieee80211_hw * hw, u8 variable, u8 * val); + void (*set_hw_reg) (struct ieee80211_hw * hw, u8 variable, u8 * val); + void (*update_rate_tbl) (struct ieee80211_hw * hw, + struct ieee80211_sta *sta, u8 rssi_level); + void (*pre_fill_tx_bd_desc) (struct ieee80211_hw *hw, u8 *tx_bd_desc, + u8 *desc, u8 queue_index, + struct sk_buff *skb, dma_addr_t addr); + u16 (*rx_desc_buff_remained_cnt) (struct ieee80211_hw *hw, + u8 queue_index); + void (*rx_check_dma_ok) (struct ieee80211_hw *hw, u8 *header_desc, + u8 queue_index); + void (*fill_tx_desc) (struct ieee80211_hw * hw, + struct ieee80211_hdr * hdr, + u8 * pdesc_tx, u8 * pbd_desc, + struct ieee80211_tx_info * info, +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)) +/**/ + struct ieee80211_sta *sta, +/**/ +#endif +/**/ + struct sk_buff * skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); + void (*fill_tx_cmddesc) (struct ieee80211_hw * hw, u8 * pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff * skb); + bool(*query_rx_desc) (struct ieee80211_hw * hw, + struct rtl_stats * status, + struct ieee80211_rx_status * rx_status, + u8 * pdesc, struct sk_buff * skb); + void (*set_channel_access) (struct ieee80211_hw * hw); + bool(*radio_onoff_checking) (struct ieee80211_hw * hw, u8 * valid); + void (*dm_watchdog) (struct ieee80211_hw * hw); + void (*scan_operation_backup) (struct ieee80211_hw * hw, u8 operation); + bool(*set_rf_power_state) (struct ieee80211_hw * hw, + enum rf_pwrstate rfpwr_state); + void (*led_control) (struct ieee80211_hw * hw, + enum led_ctl_mode ledaction); + void (*set_desc) (struct ieee80211_hw *hw, u8 * pdesc, bool istx, + u8 desc_name, u8 * val); + u32(*get_desc) (u8 * pdesc, bool istx, u8 desc_name); + bool (*is_tx_desc_closed) (struct ieee80211_hw *hw, + u8 hw_queue, u16 index); + void (*tx_polling) (struct ieee80211_hw * hw, u8 hw_queue); + void (*enable_hw_sec) (struct ieee80211_hw * hw); + void (*set_key) (struct ieee80211_hw * hw, u32 key_index, + u8 * p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); + void (*init_sw_leds) (struct ieee80211_hw * hw); + u32(*get_bbreg) (struct ieee80211_hw * hw, u32 regaddr, u32 bitmask); + void (*set_bbreg) (struct ieee80211_hw * hw, u32 regaddr, u32 bitmask, + u32 data); + u32(*get_rfreg) (struct ieee80211_hw * hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask); + void (*set_rfreg) (struct ieee80211_hw * hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); + void (*allow_all_destaddr)(struct ieee80211_hw *hw, + bool allow_all_da, bool write_into_reg); + void (*linked_set_reg) (struct ieee80211_hw * hw); + void (*check_switch_to_dmdp) (struct ieee80211_hw * hw); + void (*dualmac_easy_concurrent) (struct ieee80211_hw *hw); + void (*dualmac_switch_to_dmdp) (struct ieee80211_hw *hw); + void (*c2h_command_handle) (struct ieee80211_hw *hw); + void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw, bool mstate); + void (*bt_turn_off_bt_coexist_before_enter_lps) (struct ieee80211_hw *hw); + void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); + bool (*get_btc_status) (void); + u32 (*rx_command_packet_handler)(struct ieee80211_hw *hw, struct rtl_stats status, struct sk_buff *skb); +}; + +struct rtl_intf_ops { + /*com */ + void (*read_efuse_byte)(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); + int (*adapter_start) (struct ieee80211_hw * hw); + void (*adapter_stop) (struct ieee80211_hw * hw); + bool (*check_buddy_priv)(struct ieee80211_hw *hw, + struct rtl_priv **buddy_priv); + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + int (*adapter_tx) (struct ieee80211_hw * hw, struct sk_buff * skb, + struct rtl_tcb_desc *ptcb_desc); +#else +/**/ + int (*adapter_tx) (struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc); +/**/ +#endif +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop); +#else + void (*flush)(struct ieee80211_hw *hw, bool drop); +#endif + int (*reset_trx_ring) (struct ieee80211_hw * hw); +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb); +#else +/**/ + bool (*waitq_insert) (struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb); +/**/ +#endif +/**/ + + /*pci */ + void (*disable_aspm) (struct ieee80211_hw * hw); + void (*enable_aspm) (struct ieee80211_hw * hw); + + /*usb */ +}; + +struct rtl_mod_params { + /* default: 0 = using hardware encryption */ + bool sw_crypto; + + /* default: 1 = using no linked power save */ + bool b_inactiveps; + + /* default: 1 = using linked sw power save */ + bool b_swctrl_lps; + + /* default: 1 = using linked fw power save */ + bool b_fwctrl_lps; +}; + +struct rtl_hal_cfg { + u8 bar_id; + bool write_readback; + char *name; + char *fw_name; + struct rtl_hal_ops *ops; + struct rtl_mod_params *mod_params; + + /*this map used for some registers or vars + defined int HAL but used in MAIN */ + u32 maps[RTL_VAR_MAP_MAX]; + +}; + +struct rtl_locks { + /* mutex */ + struct mutex conf_mutex; + + /*spin lock */ + spinlock_t ips_lock; + spinlock_t irq_th_lock; + spinlock_t h2c_lock; + spinlock_t rf_ps_lock; + spinlock_t rf_lock; + spinlock_t lps_lock; + spinlock_t waitq_lock; + spinlock_t entry_list_lock; + + /*FW clock change */ + spinlock_t fw_ps_lock; + + /*Dul mac*/ + spinlock_t cck_and_rw_pagea_lock; + + /*Easy concurrent*/ + spinlock_t check_sendpkt_lock; + + spinlock_t iqk_lock; +}; + +struct rtl_works { + struct ieee80211_hw *hw; + + /*timer */ + struct timer_list watchdog_timer; + struct timer_list dualmac_easyconcurrent_retrytimer; + struct timer_list fw_clockoff_timer; + struct timer_list fast_antenna_trainning_timer; + /*task */ + struct tasklet_struct irq_tasklet; + struct tasklet_struct irq_prepare_bcn_tasklet; + + /*work queue */ + struct workqueue_struct *rtl_wq; + struct delayed_work watchdog_wq; + struct delayed_work ips_nic_off_wq; + + /* For SW LPS */ + struct delayed_work ps_work; + struct delayed_work ps_rfon_wq; + struct delayed_work fwevt_wq; +}; + +struct rtl_debug { + u32 dbgp_type[DBGP_TYPE_MAX]; + u32 global_debuglevel; + u64 global_debugcomponents; + + /* add for proc debug */ + struct proc_dir_entry *proc_dir; + char proc_name[20]; +}; + +#define MIMO_PS_STATIC 0 +#define MIMO_PS_DYNAMIC 1 +#define MIMO_PS_NOLIMIT 3 + +struct rtl_dualmac_easy_concurrent_ctl { + enum band_type currentbandtype_backfordmdp; + bool bclose_bbandrf_for_dmsp; + bool bchange_to_dmdp; + bool bchange_to_dmsp; + bool bswitch_in_process; +}; + +struct rtl_dmsp_ctl { + bool bactivescan_for_slaveofdmsp; + bool bscan_for_anothermac_fordmsp; + bool bscan_for_itself_fordmsp; + bool bwritedig_for_anothermacofdmsp; + u32 curdigvalue_for_anothermacofdmsp; + bool bchangecckpdstate_for_anothermacofdmsp; + u8 curcckpdstate_for_anothermacofdmsp; + bool bchangetxhighpowerlvl_for_anothermacofdmsp; + u8 curtxhighlvl_for_anothermacofdmsp; + long rssivalmin_for_anothermacofdmsp; +}; + +struct rtl_global_var { + /* from this list we can get + * other adapter's rtl_priv */ + struct list_head glb_priv_list; + spinlock_t glb_list_lock; +}; + +struct rtl_btc_info { + u8 bt_type; + u8 btcoexist; + u8 ant_num; +}; + +struct rtl_btc_ops { + void (*btc_init_variables) (struct rtl_priv *rtlpriv); + void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv); + void (*btc_init_hw_config) (struct rtl_priv *rtlpriv); + void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type); + void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype); + void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action); + void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv, + enum rt_media_status mstatus); + void (*btc_periodical) (struct rtl_priv *rtlpriv); + void (*btc_halt_notify) (void); + void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv, + u8 * tmp_buf, u8 length); + bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv); + bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv); + bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv); +}; + +struct rtl_bt_coexist { + struct rtl_btc_ops *btc_ops; + struct rtl_btc_info btc_info; +}; + + +struct rtl_priv { + struct list_head list; +#ifdef VIF_TODO + struct vif_priv vif_priv; +#endif + struct rtl_priv *buddy_priv; + struct rtl_global_var *glb_var; + struct rtl_dualmac_easy_concurrent_ctl easy_concurrent_ctl; + struct rtl_dmsp_ctl dmsp_ctl; + struct rtl_locks locks; + struct rtl_works works; + struct rtl_mac mac80211; + struct rtl_hal rtlhal; + struct rtl_regulatory regd; + struct rtl_rfkill rfkill; + struct rtl_io io; + struct rtl_phy phy; + struct rtl_dm dm; + struct rtl_security sec; + struct rtl_efuse efuse; + + struct rtl_ps_ctl psc; + struct rate_adaptive ra; + struct dynamic_primary_cca primarycca; + struct wireless_stats stats; + struct rt_link_detect link_info; + struct false_alarm_statistics falsealm_cnt; + + struct rtl_rate_priv *rate_priv; + + struct rtl_debug dbg; + + /* sta entry list for ap adhoc or mesh */ + struct list_head entry_list; + + /* + *hal_cfg : for diff cards + *intf_ops : for diff interrface usb/pcie + */ + struct rtl_hal_cfg *cfg; + struct rtl_intf_ops *intf_ops; + + /*this var will be set by set_bit, + and was used to indicate status of + interface or hardware */ + unsigned long status; + + /* intel Proximity, should be alloc mem + * in intel Proximity module and can only + * be used in intel Proximity mode */ + struct proxim proximity; + + /*for bt coexist use*/ + struct rtl_bt_coexist btcoexist; + + /* seperate 92ee from other ICs, + * 92ee use new trx flow. */ + bool use_new_trx_flow; + /*This must be the last item so + that it points to the data allocated + beyond this structure like: + rtl_pci_priv or rtl_usb_priv */ + u8 priv[0]; +}; + +#define rtl_priv(hw) (((struct rtl_priv *)(hw)->priv)) +#define rtl_mac(rtlpriv) (&((rtlpriv)->mac80211)) +#define rtl_hal(rtlpriv) (&((rtlpriv)->rtlhal)) +#define rtl_efuse(rtlpriv) (&((rtlpriv)->efuse)) +#define rtl_psc(rtlpriv) (&((rtlpriv)->psc)) +#define rtl_sec(rtlpriv) (&((rtlpriv)->sec)) +#define rtl_dm(rtlpriv) (&((rtlpriv)->dm)) +/*************************************** + Bluetooth Co-existance Related +****************************************/ + +enum bt_ant_num { + ANT_X2 = 0, + ANT_X1 = 1, +}; + +enum bt_co_type { + BT_2WIRE = 0, + BT_ISSC_3WIRE = 1, + BT_ACCEL = 2, + BT_CSR_BC4 = 3, + BT_CSR_BC8 = 4, + BT_RTL8756 = 5, + BT_RTL8723A = 6, + BT_RTL8821A = 7, + BT_RTL8723B = 8, + BT_RTL8192E = 9, + BT_RTL8812A = 11, +}; + +enum bt_total_ant_num{ + ANT_TOTAL_X2 = 0, + ANT_TOTAL_X1 = 1 +}; + +enum bt_cur_state { + BT_OFF = 0, + BT_ON = 1, +}; + +enum bt_service_type { + BT_SCO = 0, + BT_A2DP = 1, + BT_HID = 2, + BT_HID_IDLE = 3, + BT_SCAN = 4, + BT_IDLE = 5, + BT_OTHER_ACTION = 6, + BT_BUSY = 7, + BT_OTHERBUSY = 8, + BT_PAN = 9, +}; + +enum bt_radio_shared { + BT_RADIO_SHARED = 0, + BT_RADIO_INDIVIDUAL = 1, +}; + +struct bt_coexist_info { + + /* EEPROM BT info. */ + u8 eeprom_bt_coexist; + u8 eeprom_bt_type; + u8 eeprom_bt_ant_num; + u8 eeprom_bt_ant_isolation; + u8 eeprom_bt_radio_shared; + + u8 bt_coexistence; + u8 bt_ant_num; + u8 bt_coexist_type; + u8 bt_state; + u8 bt_cur_state; /* 0:on, 1:off */ + u8 bt_ant_isolation; /* 0:good, 1:bad */ + u8 bt_pape_ctrl; /* 0:SW, 1:SW/HW dynamic */ + u8 bt_service; + u8 bt_radio_shared_type; + u8 bt_rfreg_origin_1e; + u8 bt_rfreg_origin_1f; + u8 bt_rssi_state; + u32 ratio_tx; + u32 ratio_pri; + u32 bt_edca_ul; + u32 bt_edca_dl; + + bool b_init_set; + bool b_bt_busy_traffic; + bool b_bt_traffic_mode_set; + bool b_bt_non_traffic_mode_set; + + bool b_fw_coexist_all_off; + bool b_sw_coexist_all_off; + bool b_hw_coexist_all_off; + u32 current_state; + u32 previous_state; + u32 current_state_h; + u32 previous_state_h; + + u8 bt_pre_rssi_state; + u8 bt_pre_rssi_state1; + + u8 b_reg_bt_iso; + u8 b_reg_bt_sco; + bool b_balance_on; + u8 bt_active_zero_cnt; + bool b_cur_bt_disabled; + bool b_pre_bt_disabled; + + u8 bt_profile_case; + u8 bt_profile_action; + bool b_bt_busy; + bool b_hold_for_bt_operation; + u8 lps_counter; +}; + + +/**************************************** + mem access macro define start + Call endian free function when + 1. Read/write packet content. + 2. Before write integer to IO. + 3. After read integer from IO. +****************************************/ +/* Convert little data endian to host */ +#define EF1BYTE(_val) \ + ((u8)(_val)) +#define EF2BYTE(_val) \ + (le16_to_cpu(_val)) +#define EF4BYTE(_val) \ + (le32_to_cpu(_val)) + +/* Read data from memory */ +#define READEF1BYTE(_ptr) \ + EF1BYTE(*((u8 *)(_ptr))) +#define READEF2BYTE(_ptr) \ + EF2BYTE(*((u16 *)(_ptr))) +#define READEF4BYTE(_ptr) \ + EF4BYTE(*((u32 *)(_ptr))) + +/* Write data to memory */ +#define WRITEEF1BYTE(_ptr, _val) \ + (*((u8 *)(_ptr)))=EF1BYTE(_val) +#define WRITEEF2BYTE(_ptr, _val) \ + (*((u16 *)(_ptr)))=EF2BYTE(_val) +#define WRITEEF4BYTE(_ptr, _val) \ + (*((u32 *)(_ptr)))=EF4BYTE(_val) + +/*Example: +BIT_LEN_MASK_32(0) => 0x00000000 +BIT_LEN_MASK_32(1) => 0x00000001 +BIT_LEN_MASK_32(2) => 0x00000003 +BIT_LEN_MASK_32(32) => 0xFFFFFFFF*/ +#define BIT_LEN_MASK_32(__bitlen) \ + (0xFFFFFFFF >> (32 - (__bitlen))) +#define BIT_LEN_MASK_16(__bitlen) \ + (0xFFFF >> (16 - (__bitlen))) +#define BIT_LEN_MASK_8(__bitlen) \ + (0xFF >> (8 - (__bitlen))) + +/*Example: +BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 +BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000*/ +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \ + (BIT_LEN_MASK_32(__bitlen) << (__bitoffset)) +#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \ + (BIT_LEN_MASK_16(__bitlen) << (__bitoffset)) +#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \ + (BIT_LEN_MASK_8(__bitlen) << (__bitoffset)) + +/*Description: +Return 4-byte value in host byte ordering from +4-byte pointer in little-endian system.*/ +#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \ + (EF4BYTE(*((u32 *)(__pstart)))) +#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \ + (EF2BYTE(*((u16 *)(__pstart)))) +#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ + (EF1BYTE(*((u8 *)(__pstart)))) + +/*Description: +Translate subfield (continuous bits in little-endian) of 4-byte +value to host byte ordering.*/ +#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + ( LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset) ) & \ + BIT_LEN_MASK_32(__bitlen) \ + ) +#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + ( LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset) ) & \ + BIT_LEN_MASK_16(__bitlen) \ + ) +#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + ( LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset) ) & \ + BIT_LEN_MASK_8(__bitlen) \ + ) + +/*Description: +Mask subfield (continuous bits in little-endian) of 4-byte value +and return the result in 4-byte value in host byte ordering.*/ +#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + LE_P4BYTE_TO_HOST_4BYTE(__pstart) & \ + ( ~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) ) \ + ) +#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \ + ( ~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) ) \ + ) +#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \ + ( ~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) ) \ + ) + +/*Description: +Set subfield of little-endian 4-byte value to specified value. */ +#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u32 *)(__pstart)) = EF4BYTE \ + ( \ + LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \ + ( (((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset) )\ + ); +#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u16 *)(__pstart)) = EF2BYTE \ + ( \ + LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ + ( (((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset) )\ + ); +#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u8 *)(__pstart)) = EF1BYTE \ + ( \ + LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \ + ( (((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset) ) \ + ); + +#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ + (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) + +/**************************************** + mem access macro define end +****************************************/ + +#define byte(x,n) ((x >> (8 * n)) & 0xff) + +#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC) +#define RTL_WATCH_DOG_TIME 2000 +#define MSECS(t) msecs_to_jiffies(t) +#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) +#define WLAN_FC_MORE_DATA(fc) ((fc) & IEEE80211_FCTL_MOREDATA) +#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) + +#define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */ +#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */ +#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) /*PCI D3 mode */ +/*NIC halt, re-initialize hw parameters*/ +#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) +#define RT_RF_OFF_LEVL_FREE_FW BIT(4) /*FW free, re-download the FW */ +#define RT_RF_OFF_LEVL_FW_32K BIT(5) /*FW in 32k */ +/*Always enable ASPM and Clock Req in initialization.*/ +#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) +/* no matter RFOFF or SLEEP we set PS_ASPM_LEVL*/ +#define RT_PS_LEVEL_ASPM BIT(7) +/*When LPS is on, disable 2R if no packet is received or transmittd.*/ +#define RT_RF_LPS_DISALBE_2R BIT(30) +#define RT_RF_LPS_LEVEL_ASPM BIT(31) /*LPS with ASPM */ +#define RT_IN_PS_LEVEL(ppsc, _ps_flg) \ + ((ppsc->cur_ps_level & _ps_flg) ? true : false) +#define RT_CLEAR_PS_LEVEL(ppsc, _ps_flg) \ + (ppsc->cur_ps_level &= (~(_ps_flg))) +#define RT_SET_PS_LEVEL(ppsc, _ps_flg) \ + (ppsc->cur_ps_level |= _ps_flg) + +#define container_of_dwork_rtl(x,y,z) \ + container_of(container_of(x, struct delayed_work, work), y, z) + +#define FILL_OCTET_STRING(_os,_octet,_len) \ + (_os).octet=(u8*)(_octet); \ + (_os).length=(_len); + +#define CP_MACADDR(des,src) \ + ((des)[0]=(src)[0],(des)[1]=(src)[1],\ + (des)[2]=(src)[2],(des)[3]=(src)[3],\ + (des)[4]=(src)[4],(des)[5]=(src)[5]) + +static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) +{ + return rtlpriv->io.read8_sync(rtlpriv, addr); +} + +static inline u16 rtl_read_word(struct rtl_priv *rtlpriv, u32 addr) +{ + return rtlpriv->io.read16_sync(rtlpriv, addr); +} + +static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) +{ + return rtlpriv->io.read32_sync(rtlpriv, addr); +} + +static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) +{ + rtlpriv->io.write8_async(rtlpriv, addr, val8); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read8_sync(rtlpriv, addr); +} + +static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) +{ + rtlpriv->io.write16_async(rtlpriv, addr, val16); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read16_sync(rtlpriv, addr); +} + +static inline void rtl_write_dword(struct rtl_priv *rtlpriv, + u32 addr, u32 val32) +{ + rtlpriv->io.write32_async(rtlpriv, addr, val32); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read32_sync(rtlpriv, addr); +} + +static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask) +{ + return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_bbreg(hw, + regaddr, + bitmask); +} + +static inline void rtl_set_bbreg(struct ieee80211_hw *hw, u32 regaddr, + u32 bitmask, u32 data) +{ + ((struct rtl_priv *)(hw)->priv)->cfg->ops->set_bbreg(hw, + regaddr, bitmask, + data); + +} + +static inline u32 rtl_get_rfreg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask) +{ + return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_rfreg(hw, + rfpath, + regaddr, + bitmask); +} + +static inline void rtl_set_rfreg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data) +{ + ((struct rtl_priv *)(hw)->priv)->cfg->ops->set_rfreg(hw, + rfpath, regaddr, + bitmask, data); +} + +static inline bool is_hal_stop(struct rtl_hal *rtlhal) +{ + return (_HAL_STATE_STOP == rtlhal->state); +} + +static inline void set_hal_start(struct rtl_hal *rtlhal) +{ + rtlhal->state = _HAL_STATE_START; +} + +static inline void set_hal_stop(struct rtl_hal *rtlhal) +{ + rtlhal->state = _HAL_STATE_STOP; +} + +static inline u8 get_rf_type(struct rtl_phy *rtlphy) +{ + return rtlphy->rf_type; +} + +static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) +{ + return (struct ieee80211_hdr *)(skb->data); +} + +static inline u16 rtl_get_fc(struct sk_buff *skb) +{ + return le16_to_cpu(rtl_get_hdr(skb)->frame_control); +} + +static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) +{ + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +static inline u16 rtl_get_tid(struct sk_buff *skb) +{ + return rtl_get_tid_h(rtl_get_hdr(skb)); +} + +static inline struct ieee80211_sta *rtl_find_sta(struct ieee80211_hw *hw, + u8 *mac_addr) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + return ieee80211_find_sta(mac->vif, mac_addr); +} + +struct ieee80211_hw *rtl_pci_get_hw_pointer(void); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/pci.h +++ linux-3.13.0/drivers/staging/rtl8821ae/pci.h @@ -0,0 +1,353 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_PCI_H__ +#define __RTL_PCI_H__ + +#include +/* +1: MSDU packet queue, +2: Rx Command Queue +*/ +#define RTL_PCI_RX_MPDU_QUEUE 0 +#define RTL_PCI_RX_CMD_QUEUE 1 +#define RTL_PCI_MAX_RX_QUEUE 2 + +#define RTL_PCI_MAX_RX_COUNT 512//64 +#define RTL_PCI_MAX_TX_QUEUE_COUNT 9 + +#define RT_TXDESC_NUM 128 +#define TX_DESC_NUM_92E 512 +#define RT_TXDESC_NUM_BE_QUEUE 256 + +#define BK_QUEUE 0 +#define BE_QUEUE 1 +#define VI_QUEUE 2 +#define VO_QUEUE 3 +#define BEACON_QUEUE 4 +#define TXCMD_QUEUE 5 +#define MGNT_QUEUE 6 +#define HIGH_QUEUE 7 +#define HCCA_QUEUE 8 + +#define RTL_PCI_DEVICE(vend, dev, cfg) \ + .vendor = (vend), \ + .device = (dev), \ + .subvendor = PCI_ANY_ID, \ + .subdevice = PCI_ANY_ID,\ + .driver_data = (kernel_ulong_t)&(cfg) + +#define INTEL_VENDOR_ID 0x8086 +#define SIS_VENDOR_ID 0x1039 +#define ATI_VENDOR_ID 0x1002 +#define ATI_DEVICE_ID 0x7914 +#define AMD_VENDOR_ID 0x1022 + +#define PCI_MAX_BRIDGE_NUMBER 255 +#define PCI_MAX_DEVICES 32 +#define PCI_MAX_FUNCTION 8 + +#define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */ +#define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */ + +#define PCI_CLASS_BRIDGE_DEV 0x06 +#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04 +#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 +#define PCI_CAP_ID_EXP 0x10 + +#define U1DONTCARE 0xFF +#define U2DONTCARE 0xFFFF +#define U4DONTCARE 0xFFFFFFFF + +#define RTL_PCI_8192_DID 0x8192 /*8192 PCI-E */ +#define RTL_PCI_8192SE_DID 0x8192 /*8192 SE */ +#define RTL_PCI_8174_DID 0x8174 /*8192 SE */ +#define RTL_PCI_8173_DID 0x8173 /*8191 SE Crab */ +#define RTL_PCI_8172_DID 0x8172 /*8191 SE RE */ +#define RTL_PCI_8171_DID 0x8171 /*8191 SE Unicron */ +#define RTL_PCI_0045_DID 0x0045 /*8190 PCI for Ceraga */ +#define RTL_PCI_0046_DID 0x0046 /*8190 Cardbus for Ceraga */ +#define RTL_PCI_0044_DID 0x0044 /*8192e PCIE for Ceraga */ +#define RTL_PCI_0047_DID 0x0047 /*8192e Express Card for Ceraga */ +#define RTL_PCI_700F_DID 0x700F +#define RTL_PCI_701F_DID 0x701F +#define RTL_PCI_DLINK_DID 0x3304 +#define RTL_PCI_8723AE_DID 0x8723 /*8723e */ +#define RTL_PCI_8192CET_DID 0x8191 /*8192ce */ +#define RTL_PCI_8192CE_DID 0x8178 /*8192ce */ +#define RTL_PCI_8191CE_DID 0x8177 /*8192ce */ +#define RTL_PCI_8188CE_DID 0x8176 /*8192ce */ +#define RTL_PCI_8192CU_DID 0x8191 /*8192ce */ +#define RTL_PCI_8192DE_DID 0x8193 /*8192de */ +#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/ +#define RTL_PCI_8188EE_DID 0x8179 /*8188ee*/ +#define RTL_PCI_8723BE_DID 0xB723 /*8723be*/ +#define RTL_PCI_8192EE_DID 0x818B /*8192ee*/ +#define RTL_PCI_8821AE_DID 0x8821 /*8821ae*/ +#define RTL_PCI_8812AE_DID 0x8812 /*8812ae*/ + +/*8192 support 16 pages of IO registers*/ +#define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000 +#define RTL_MEM_MAPPED_IO_RANGE_8192PCIE 0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192SE 0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192CE 0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192DE 0x4000 + +#define RTL_PCI_REVISION_ID_8190PCI 0x00 +#define RTL_PCI_REVISION_ID_8192PCIE 0x01 +#define RTL_PCI_REVISION_ID_8192SE 0x10 +#define RTL_PCI_REVISION_ID_8192CE 0x1 +#define RTL_PCI_REVISION_ID_8192DE 0x0 + +#define PCI_VENDOR_ID_REALTEK 0x10ec + +#define RTL_DEFAULT_HARDWARE_TYPE HARDWARE_TYPE_RTL8192CE + +enum pci_bridge_vendor { + PCI_BRIDGE_VENDOR_INTEL = 0x0, /*0b'0000,0001 */ + PCI_BRIDGE_VENDOR_ATI, /*0b'0000,0010*/ + PCI_BRIDGE_VENDOR_AMD, /*0b'0000,0100*/ + PCI_BRIDGE_VENDOR_SIS, /*0b'0000,1000*/ + PCI_BRIDGE_VENDOR_UNKNOWN, /*0b'0100,0000*/ + PCI_BRIDGE_VENDOR_MAX, +}; + +struct rtl_pci_capabilities_header { + u8 capability_id; + u8 next; +}; + +/* In new TRX flow, Buffer_desc is new concept + * But TX wifi info == TX descriptor in old flow + * RX wifi info == RX descriptor in old flow */ +struct rtl_tx_buffer_desc { +#if (RTL8192EE_SEG_NUM == 2) + u32 dword[2*(DMA_IS_64BIT + 1)*8]; //seg = 8 +#elif (RTL8192EE_SEG_NUM == 1) + u32 dword[2*(DMA_IS_64BIT + 1)*4]; //seg = 4 +#elif (RTL8192EE_SEG_NUM == 0) + u32 dword[2*(DMA_IS_64BIT + 1)*2]; //seg = 2 +#endif +} __packed; + +struct rtl_tx_desc {/*old: tx desc*//*new: tx wifi info*/ + u32 dword[16]; +} __packed; + +struct rtl_rx_buffer_desc { /*rx buffer desc*/ + u32 dword[2]; +} __packed; + +struct rtl_rx_desc { /*old: rx desc*//*new: rx wifi info*/ + u32 dword[8]; +} __packed; + +struct rtl_tx_cmd_desc { + u32 dword[16]; +} __packed; + +struct rtl8192_tx_ring { + struct rtl_tx_desc *desc; /*tx desc / tx wifi info*/ + dma_addr_t dma; /*tx desc dma memory / tx wifi info dma memory*/ + unsigned int idx; + unsigned int entries; + struct sk_buff_head queue; + /*add for new trx flow*/ + struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/ + dma_addr_t buffer_desc_dma; /*tx bufferd desc dma memory*/ + u16 avl_desc; /* available_desc_to_write */ + u16 cur_tx_wp; /* current_tx_write_point */ + u16 cur_tx_rp; /* current_tx_read_point */ +}; + +struct rtl8192_rx_ring { + struct rtl_rx_desc *desc;/*for old trx flow, not uesd in new trx*/ + /*dma matches either 'desc' or 'buffer_desc'*/ + dma_addr_t dma; + unsigned int idx; + struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT]; + /*add for new trx flow*/ + struct rtl_rx_buffer_desc *buffer_desc; /*rx buffer descriptor*/ + u16 next_rx_rp; /* next_rx_read_point */ +}; + +struct rtl_pci { + struct pci_dev *pdev; + bool irq_enabled; + + /*Tx */ + struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT]; + int txringcount[RTL_PCI_MAX_TX_QUEUE_COUNT]; + u32 transmit_config; + + /*Rx */ + struct rtl8192_rx_ring rx_ring[RTL_PCI_MAX_RX_QUEUE]; + int rxringcount; + u16 rxbuffersize; + u32 receive_config; + + /*irq */ + u8 irq_alloc; + u32 irq_mask[2]; + u32 sys_irq_mask; + + /*Bcn control register setting */ + u32 reg_bcn_ctrl_val; + + /*ASPM*/ u8 const_pci_aspm; + u8 const_amdpci_aspm; + u8 const_hwsw_rfoff_d3; + u8 const_support_pciaspm; + /*pci-e bridge */ + u8 const_hostpci_aspm_setting; + /*pci-e device */ + u8 const_devicepci_aspm_setting; + /*If it supports ASPM, Offset[560h] = 0x40, + otherwise Offset[560h] = 0x00. */ + bool b_support_aspm; + bool b_support_backdoor; + + /*QOS & EDCA */ + enum acm_method acm_method; + + u16 shortretry_limit; + u16 longretry_limit; + + /* MSI support */ + bool msi_support; + bool using_msi; +}; + +struct mp_adapter { + u8 linkctrl_reg; + + u8 busnumber; + u8 devnumber; + u8 funcnumber; + + u8 pcibridge_busnum; + u8 pcibridge_devnum; + u8 pcibridge_funcnum; + + u8 pcibridge_vendor; + u16 pcibridge_vendorid; + u16 pcibridge_deviceid; + + u32 pcicfg_addrport; + u8 num4bytes; + + u8 pcibridge_pciehdr_offset; + u8 pcibridge_linkctrlreg; + + bool amd_l1_patch; +}; + +struct rtl_pci_priv { + struct rtl_pci dev; + struct mp_adapter ndis_adapter; + struct rtl_led_ctl ledctl; + struct bt_coexist_info btcoexist; +}; + +#define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) +#define rtl_pcidev(pcipriv) (&((pcipriv)->dev)) + +int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw); + +extern struct rtl_intf_ops rtl_pci_ops; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) +int rtl_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +#else +int __devinit rtl_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +#endif +void rtl_pci_disconnect(struct pci_dev *pdev); +int rtl_pci_suspend(struct device *dev); +int rtl_pci_resume(struct device *dev); + +static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return 0xff & readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr); +} + +static inline u16 pci_read16_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return readw((u8 __iomem *) rtlpriv->io.pci_mem_start + addr); +} + +static inline u32 pci_read32_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return readl((u8 __iomem *) rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) +{ + writeb(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write16_async(struct rtl_priv *rtlpriv, + u32 addr, u16 val) +{ + writew(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write32_async(struct rtl_priv *rtlpriv, + u32 addr, u32 val) +{ + writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); +} + +static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val) +{ + outl(val, port); +} + +static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val) +{ + outb(val, port); +} + +static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 * pval) +{ + *pval = inb(port); +} + +static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 * pval) +{ + *pval = inw(port); +} + +static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 * pval) +{ + *pval = inl(port); +} + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/TODO +++ linux-3.13.0/drivers/staging/rtl8821ae/TODO @@ -0,0 +1,10 @@ +Realtek 8821AE PCI wifi driver TODO: + - remove built-in btcoexist module when the "real" one gets upstream + - remove built-in rtlwifi code by porting driver to use the "real" one + in the drivers/net/ directory. + - fix up coding style issues + +Please send any patches for this driver to: + Greg Kroah-Hartman +and the mailing list. + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/pci.c +++ linux-3.13.0/drivers/staging/rtl8821ae/pci.c @@ -0,0 +1,2549 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "core.h" +#include "wifi.h" +#include "pci.h" +#include "base.h" +#include "ps.h" +#include "efuse.h" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +#include +#endif + +static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { + INTEL_VENDOR_ID, + ATI_VENDOR_ID, + AMD_VENDOR_ID, + SIS_VENDOR_ID +}; + +static const u8 ac_to_hwq[] = { + VO_QUEUE, + VI_QUEUE, + BE_QUEUE, + BK_QUEUE +}; + +u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 fc = rtl_get_fc(skb); + u8 queue_index = skb_get_queue_mapping(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return BEACON_QUEUE; + if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) + return MGNT_QUEUE; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + if (ieee80211_is_nullfunc(fc)) + return HIGH_QUEUE; + + return ac_to_hwq[queue_index]; +} + +/* Update PCI dependent default settings*/ +static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 init_aspm; + + ppsc->reg_rfps_level = 0; + ppsc->b_support_aspm = 0; + + /*Update PCI ASPM setting */ + ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm; + switch (rtlpci->const_pci_aspm) { + case 0: + /*No ASPM */ + break; + + case 1: + /*ASPM dynamically enabled/disable. */ + ppsc->reg_rfps_level |= RT_RF_LPS_LEVEL_ASPM; + break; + + case 2: + /*ASPM with Clock Req dynamically enabled/disable. */ + ppsc->reg_rfps_level |= (RT_RF_LPS_LEVEL_ASPM | + RT_RF_OFF_LEVL_CLK_REQ); + break; + + case 3: + /* + * Always enable ASPM and Clock Req + * from initialization to halt. + * */ + ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM); + ppsc->reg_rfps_level |= (RT_RF_PS_LEVEL_ALWAYS_ASPM | + RT_RF_OFF_LEVL_CLK_REQ); + break; + + case 4: + /* + * Always enable ASPM without Clock Req + * from initialization to halt. + * */ + ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM | + RT_RF_OFF_LEVL_CLK_REQ); + ppsc->reg_rfps_level |= RT_RF_PS_LEVEL_ALWAYS_ASPM; + break; + } + + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; + + /*Update Radio OFF setting */ + switch (rtlpci->const_hwsw_rfoff_d3) { + case 1: + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; + break; + + case 2: + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; + break; + + case 3: + ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_PCI_D3; + break; + } + + /*Set HW definition to determine if it supports ASPM. */ + switch (rtlpci->const_support_pciaspm) { + case 0:{ + /*Not support ASPM. */ + bool b_support_aspm = false; + ppsc->b_support_aspm = b_support_aspm; + break; + } + case 1:{ + /*Support ASPM. */ + bool b_support_aspm = true; + bool b_support_backdoor = true; + ppsc->b_support_aspm = b_support_aspm; + + /*if(priv->oem_id == RT_CID_TOSHIBA && + !priv->ndis_adapter.amd_l1_patch) + b_support_backdoor = false; */ + + ppsc->b_support_backdoor = b_support_backdoor; + + break; + } + case 2: + /*ASPM value set by chipset. */ + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { + bool b_support_aspm = true; + ppsc->b_support_aspm = b_support_aspm; + } + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + + /* toshiba aspm issue, toshiba will set aspm selfly + * so we should not set aspm in driver */ + pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); + if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && + init_aspm == 0x43) + ppsc->b_support_aspm = false; +} + +static bool _rtl_pci_platform_switch_device_pci_aspm(struct ieee80211_hw *hw, + u8 value) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool bresult = false; + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) + value |= 0x40; + + pci_write_config_byte(rtlpci->pdev, 0x80, value); + + return bresult; +} + +/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ +static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool bresult = false; + + pci_write_config_byte(rtlpci->pdev, 0x81, value); + bresult = true; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + udelay(100); + + return bresult; +} + +/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ +static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + u8 num4bytes = pcipriv->ndis_adapter.num4bytes; + /*Retrieve original configuration settings. */ + u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; + u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. + pcibridge_linkctrlreg; + u16 aspmlevel = 0; + + if (!ppsc->b_support_aspm) + return; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(COMP_POWER, DBG_TRACE, + ("PCI(Bridge) UNKNOWN.\n")); + + return; + } + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); + _rtl_pci_switch_clk_req(hw, 0x0); + } + + if (1) { + /*for promising device will in L0 state after an I/O. */ + u8 tmp_u1b; + pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); + } + + /*Set corresponding value. */ + aspmlevel |= BIT(0) | BIT(1); + linkctrl_reg &= ~aspmlevel; + pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1)); + + _rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg); + udelay(50); + + /*4 Disable Pci Bridge ASPM */ + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + (num4bytes << 2)); + rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); + + udelay(50); + +} + +/* + *Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for + *power saving We should follow the sequence to enable + *RTL8192SE first then enable Pci Bridge ASPM + *or the system will show bluescreen. + */ +static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + u8 num4bytes = pcipriv->ndis_adapter.num4bytes; + u16 aspmlevel; + u8 u_pcibridge_aspmsetting; + u8 u_device_aspmsetting; + + if (!ppsc->b_support_aspm) + return; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(COMP_POWER, DBG_TRACE, + ("PCI(Bridge) UNKNOWN.\n")); + return; + } + + /*4 Enable Pci Bridge ASPM */ + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + (num4bytes << 2)); + + u_pcibridge_aspmsetting = + pcipriv->ndis_adapter.pcibridge_linkctrlreg | + rtlpci->const_hostpci_aspm_setting; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) + u_pcibridge_aspmsetting &= ~BIT(0); + + rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("PlatformEnableASPM(): Write reg[%x] = %x\n", + (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10), + u_pcibridge_aspmsetting)); + + udelay(50); + + /*Get ASPM level (with/without Clock Req) */ + aspmlevel = rtlpci->const_devicepci_aspm_setting; + u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg; + + /*_rtl_pci_platform_switch_device_pci_aspm(dev,*/ + /*(priv->ndis_adapter.linkctrl_reg | ASPMLevel)); */ + + u_device_aspmsetting |= aspmlevel; + + _rtl_pci_platform_switch_device_pci_aspm(hw, u_device_aspmsetting); + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { + _rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level & + RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); + } + udelay(100); +} + +static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + + bool status = false; + u8 offset_e0; + unsigned offset_e4; + + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + 0xE0); + rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0); + + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + 0xE0); + rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0); + + if (offset_e0 == 0xA0) { + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + 0xE4); + rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4); + if (offset_e4 & BIT(23)) + status = true; + } + + return status; +} + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) +static u8 _rtl_pci_get_pciehdr_offset(struct ieee80211_hw *hw) +{ + u8 capability_offset; + u8 num4bytes = 0x34/4; + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u32 pcicfg_addr_port = (pcipriv->ndis_adapter.pcibridge_busnum << 16)| + (pcipriv->ndis_adapter.pcibridge_devnum << 11)| + (pcipriv->ndis_adapter.pcibridge_funcnum << 8)| + (1 << 31); + + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS , pcicfg_addr_port + + (num4bytes << 2)); + rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &capability_offset); + while (capability_offset != 0) { + struct rtl_pci_capabilities_header capability_hdr; + + num4bytes = capability_offset / 4; + /* Read the header of the capability at this offset. + * If the retrieved capability is not the power management + * capability that we are looking for, follow the link to + * the next capability and continue looping. + */ + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS , + pcicfg_addr_port + + (num4bytes << 2)); + rtl_pci_raw_read_port_ushort(PCI_CONF_DATA, + (u16*)&capability_hdr); + /* Found the PCI express capability. */ + if (capability_hdr.capability_id == + PCI_CAPABILITY_ID_PCI_EXPRESS) + break; + else + capability_offset = capability_hdr.next; + } + return capability_offset; +} +#endif +/**/ + +bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw, + struct rtl_priv **buddy_priv) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + bool b_find_buddy_priv = false; + struct rtl_priv *temp_priv = NULL; + struct rtl_pci_priv *temp_pcipriv = NULL; + + if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) { + list_for_each_entry(temp_priv, &rtlpriv->glb_var->glb_priv_list, + list) { + if (temp_priv) { + temp_pcipriv = + (struct rtl_pci_priv *)temp_priv->priv; + RT_TRACE(COMP_INIT, DBG_LOUD, + (("pcipriv->ndis_adapter.funcnumber %x \n"), + pcipriv->ndis_adapter.funcnumber)); + RT_TRACE(COMP_INIT, DBG_LOUD, + (("temp_pcipriv->ndis_adapter.funcnumber %x \n"), + temp_pcipriv->ndis_adapter.funcnumber)); + + if ((pcipriv->ndis_adapter.busnumber == + temp_pcipriv->ndis_adapter.busnumber) && + (pcipriv->ndis_adapter.devnumber == + temp_pcipriv->ndis_adapter.devnumber) && + (pcipriv->ndis_adapter.funcnumber != + temp_pcipriv->ndis_adapter.funcnumber)) { + b_find_buddy_priv = true; + break; + } + } + } + } + + RT_TRACE(COMP_INIT, DBG_LOUD, + (("b_find_buddy_priv %d \n"), b_find_buddy_priv)); + + if (b_find_buddy_priv) + *buddy_priv = temp_priv; + + return b_find_buddy_priv; +} + +void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; + u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + u8 linkctrl_reg; + u8 num4bbytes; + + num4bbytes = (capabilityoffset + 0x10) / 4; + + /*Read Link Control Register */ + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + (num4bbytes << 2)); + rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); + + pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; +} + +static void rtl_pci_parse_configuration(struct pci_dev *pdev, + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + + u8 tmp; + int pos; + u8 linkctrl_reg; + + /*Link Control Register */ + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg); + pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg; + + RT_TRACE(COMP_INIT, DBG_TRACE, + ("Link Control Register =%x\n", + pcipriv->ndis_adapter.linkctrl_reg)); + + pci_read_config_byte(pdev, 0x98, &tmp); + tmp |= BIT(4); + pci_write_config_byte(pdev, 0x98, tmp); + + tmp = 0x17; + pci_write_config_byte(pdev, 0x70f, tmp); +} + +static void rtl_pci_init_aspm(struct ieee80211_hw *hw) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + _rtl_pci_update_default_setting(hw); + + if (ppsc->reg_rfps_level & RT_RF_PS_LEVEL_ALWAYS_ASPM) { + /*Always enable ASPM & Clock Req. */ + rtl_pci_enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_PS_LEVEL_ALWAYS_ASPM); + } + +} + +static void _rtl_pci_io_handler_init(struct device *dev, + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->io.dev = dev; + + rtlpriv->io.write8_async = pci_write8_async; + rtlpriv->io.write16_async = pci_write16_async; + rtlpriv->io.write32_async = pci_write32_async; + + rtlpriv->io.read8_sync = pci_read8_sync; + rtlpriv->io.read16_sync = pci_read16_sync; + rtlpriv->io.read32_sync = pci_read32_sync; + +} + +static bool _rtl_pci_update_earlymode_info(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_tcb_desc *tcb_desc, + u8 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 additionlen = FCS_LEN; + struct sk_buff *next_skb; + + /* here open is 4, wep/tkip is 8, aes is 12*/ + if (info->control.hw_key) + additionlen += info->control.hw_key->icv_len; + + /* The most skb num is 6 */ + tcb_desc->empkt_num = 0; + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) { + struct ieee80211_tx_info *next_info = + IEEE80211_SKB_CB(next_skb); + if (next_info->flags & IEEE80211_TX_CTL_AMPDU) { + tcb_desc->empkt_len[tcb_desc->empkt_num] = + next_skb->len + additionlen; + tcb_desc->empkt_num++; + } else { + break; + } + + if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid], + next_skb)) + break; + + if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num) + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + return true; +} + +/* just for early mode now */ +static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct sk_buff *skb = NULL; + struct ieee80211_tx_info *info = NULL; + int tid; /* should be int */ + + if (!rtlpriv->rtlhal.b_earlymode_enable) + return; + if (rtlpriv->dm.supp_phymode_switch && + (rtlpriv->easy_concurrent_ctl.bswitch_in_process || + (rtlpriv->buddy_priv && + rtlpriv->buddy_priv->easy_concurrent_ctl.bswitch_in_process))) + return; + /* we juse use em for BE/BK/VI/VO */ + for (tid = 7; tid >= 0; tid--) { + u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)]; + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + while (!mac->act_scanning && + rtlpriv->psc.rfpwr_state == ERFON) { + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + if (!skb_queue_empty(&mac->skb_waitq[tid]) && + (ring->entries - skb_queue_len(&ring->queue) > + rtlhal->max_earlymode_num)) { + skb = skb_dequeue(&mac->skb_waitq[tid]); + } else { + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + /* Some macaddr can't do early mode. like + * multicast/broadcast/no_qos data */ + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + _rtl_pci_update_earlymode_info(hw, skb, + &tcb_desc, tid); + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); +#else +/**/ + rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); +#endif +/**/ + } + } +} + +static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct sk_buff *skb; + struct ieee80211_tx_info *info; + u16 fc; + u8 tid; + u8 *entry; + + + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc[ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + + if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx)) + return; + + ring->idx = (ring->idx + 1) % ring->entries; + + skb = __skb_dequeue(&ring->queue); + + pci_unmap_single(rtlpci->pdev, + le32_to_cpu(rtlpriv->cfg->ops-> + get_desc((u8 *) entry, true, + HW_DESC_TXBUFF_ADDR)), + skb->len, PCI_DMA_TODEVICE); + + /* remove early mode header */ + if(rtlpriv->rtlhal.b_earlymode_enable) + skb_pull(skb, EM_HDR_LEN); + + RT_TRACE((COMP_INTR | COMP_SEND), DBG_TRACE, + ("new ring->idx:%d, " + "free: skb_queue_len:%d, free: seq:%d\n", + ring->idx, + skb_queue_len(&ring->queue), + *(u16 *) (skb->data + 22))); + + if(prio == TXCMD_QUEUE) { + dev_kfree_skb(skb); + goto tx_status_ok; + + } + + /* for sw LPS, just after NULL skb send out, we can + * sure AP kown we are sleeped, our we should not let + * rf to sleep*/ + fc = rtl_get_fc(skb); + if (ieee80211_is_nullfunc(fc)) { + if(ieee80211_has_pm(fc)) { + rtlpriv->mac80211.offchan_deley = true; + rtlpriv->psc.state_inap = 1; + } else { + rtlpriv->psc.state_inap = 0; + } + } + if (ieee80211_is_action(fc)) { + struct ieee80211_mgmt_compat *action_frame = + (struct ieee80211_mgmt_compat *)skb->data; + if (action_frame->u.action.u.ht_smps.action == + WLAN_HT_ACTION_SMPS) { + dev_kfree_skb(skb); + goto tx_status_ok; + } + } + + /* update tid tx pkt num */ + tid = rtl_get_tid(skb); + if (tid <= 7) + rtlpriv->link_info.tidtx_inperiod[tid]++; + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + info->flags |= IEEE80211_TX_STAT_ACK; + /*info->status.rates[0].count = 1; */ + + ieee80211_tx_status_irqsafe(hw, skb); + + if ((ring->entries - skb_queue_len(&ring->queue)) + == 2) { + + RT_TRACE(COMP_ERR, DBG_LOUD, + ("more desc left, wake" + "skb_queue@%d,ring->idx = %d," + "skb_queue_len = 0x%d\n", + prio, ring->idx, + skb_queue_len(&ring->queue))); + + ieee80211_wake_queue(hw, + skb_get_queue_mapping + (skb)); + } +tx_status_ok: + skb = NULL; + } + + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) { + rtl_lps_leave(hw); + } +} + +static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, + u8 *entry, int rxring_idx, int desc_idx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 bufferaddress; + u8 tmp_one = 1; + struct sk_buff *skb; + + skb = dev_alloc_skb(rtlpci->rxbuffersize); + if (!skb) + return 0; + rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb; + + /* just set skb->cb to mapping addr + * for pci_unmap_single use */ + *((dma_addr_t *) skb->cb) = pci_map_single(rtlpci->pdev, + skb_tail_pointer(skb), rtlpci->rxbuffersize, + PCI_DMA_FROMDEVICE); + bufferaddress = cpu_to_le32(*((dma_addr_t *) skb->cb)); + if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) + return 0; + if (rtlpriv->use_new_trx_flow) { + rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false, + HW_DESC_RX_PREPARE, + (u8 *) & bufferaddress); + } else { + rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false, + HW_DESC_RXBUFF_ADDR, + (u8 *) & bufferaddress); + rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false, + HW_DESC_RXPKT_LEN, + (u8 *) & rtlpci->rxbuffersize); + rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false, + HW_DESC_RXOWN, + (u8 *) & tmp_one); + } + + return 1; +} + +/* inorder to receive 8K AMSDU we have set skb to + * 9100bytes in init rx ring, but if this packet is + * not a AMSDU, this so big packet will be sent to + * TCP/IP directly, this cause big packet ping fail + * like: "ping -s 65507", so here we will realloc skb + * based on the true size of packet, I think mac80211 + * do it will be better, but now mac80211 haven't */ + +/* but some platform will fail when alloc skb sometimes. + * in this condition, we will send the old skb to + * mac80211 directly, this will not cause any other + * issues, but only be losted by TCP/IP */ +static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw, + struct sk_buff *skb, struct ieee80211_rx_status rx_status) +{ + if (unlikely(!rtl_action_proc(hw, skb, false))) { + dev_kfree_skb_any(skb); + } else { + struct sk_buff *uskb = NULL; + u8 *pdata; + + uskb = dev_alloc_skb(skb->len + 128); + if (likely(uskb)) { + memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, + sizeof(rx_status)); + pdata = (u8 *)skb_put(uskb, skb->len); + memcpy(pdata, skb->data, skb->len); + dev_kfree_skb_any(skb); + + ieee80211_rx_irqsafe(hw, uskb); + } else { + ieee80211_rx_irqsafe(hw, skb); + } + } +} + +/*hsisr interrupt handler*/ +static void _rtl_pci_hs_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR], + rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR]) | + rtlpci->sys_irq_mask); + + +} +static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int rxring_idx = RTL_PCI_RX_MPDU_QUEUE; + + struct ieee80211_rx_status rx_status = { 0 }; + unsigned int count = rtlpci->rxringcount; + bool unicast = false; + u8 hw_queue = 0; + unsigned int rx_remained_cnt; + u8 own; + u8 tmp_one; + + struct rtl_stats status = { + .signal = 0, + .noise = -98, + .rate = 0, + }; + + /*RX NORMAL PKT */ + while (count--) { + struct ieee80211_hdr *hdr; + u16 fc; + u16 len; + /*rx buffer descriptor */ + struct rtl_rx_buffer_desc *buffer_desc = NULL; + /*if use new trx flow, it means wifi info */ + struct rtl_rx_desc *pdesc = NULL; + /*rx pkt */ + struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[ + rtlpci->rx_ring[rxring_idx].idx]; + + if (rtlpriv->use_new_trx_flow) { + rx_remained_cnt = + rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw, + hw_queue); + if (rx_remained_cnt < 1) + return; + + } else { /* rx descriptor */ + pdesc = &rtlpci->rx_ring[rxring_idx].desc[ + rtlpci->rx_ring[rxring_idx].idx]; + + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, + false, + HW_DESC_OWN); + if (own) /* wait data to be filled by hardware */ + return; + } + + /* Get here means: data is filled already*/ + /* AAAAAAttention !!! + * We can NOT access 'skb' before 'pci_unmap_single' */ + pci_unmap_single(rtlpci->pdev, *((dma_addr_t *) skb->cb), + rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); + + if (rtlpriv->use_new_trx_flow) { + buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[ + rtlpci->rx_ring[rxring_idx].idx]; + /*means rx wifi info*/ + pdesc = (struct rtl_rx_desc *)skb->data; + } + + rtlpriv->cfg->ops->query_rx_desc(hw, &status, + &rx_status, (u8 *) pdesc, skb); + + if (rtlpriv->use_new_trx_flow) + rtlpriv->cfg->ops->rx_check_dma_ok(hw, + (u8 *)buffer_desc, + hw_queue); + + + len = rtlpriv->cfg->ops->get_desc((u8 *)pdesc, false, + HW_DESC_RXPKT_LEN); + + if (skb->end - skb->tail > len) { + skb_put(skb, len); + if (rtlpriv->use_new_trx_flow) + skb_reserve(skb, status.rx_drvinfo_size + + status.rx_bufshift + 24); + else + skb_reserve(skb, status.rx_drvinfo_size + + status.rx_bufshift); + + } else { + printk("skb->end - skb->tail = %d, len is %d\n", + skb->end - skb->tail, len); + break; + } + + rtlpriv->cfg->ops->rx_command_packet_handler(hw, status, skb); + + /* + *NOTICE This can not be use for mac80211, + *this is done in mac80211 code, + *if you done here sec DHCP will fail + *skb_trim(skb, skb->len - 4); + */ + + hdr = rtl_get_hdr(skb); + fc = rtl_get_fc(skb); + + if (!status.b_crc && !status.b_hwerror) { + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, + sizeof(rx_status)); + + if (is_broadcast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else if (is_multicast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else { + unicast = true; + rtlpriv->stats.rxbytesunicast += skb->len; + } + + rtl_is_special_data(hw, skb, false); + + if (ieee80211_is_data(fc)) { + rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); + + if (unicast) + rtlpriv->link_info.num_rx_inperiod++; + } + + /* static bcn for roaming */ + rtl_beacon_statistic(hw, skb); + rtl_p2p_info(hw, (void*)skb->data, skb->len); + /* for sw lps */ + rtl_swlps_beacon(hw, (void*)skb->data, skb->len); + rtl_recognize_peer(hw, (void*)skb->data, skb->len); + if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) && + (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)&& + (ieee80211_is_beacon(fc) || + ieee80211_is_probe_resp(fc))) { + dev_kfree_skb_any(skb); + } else { + _rtl_pci_rx_to_mac80211(hw, skb, rx_status); + } + } else { + dev_kfree_skb_any(skb); + } + if (rtlpriv->use_new_trx_flow) { + rtlpci->rx_ring[hw_queue].next_rx_rp += 1; + rtlpci->rx_ring[hw_queue].next_rx_rp %= + RTL_PCI_MAX_RX_COUNT; + + + rx_remained_cnt--; + if (1/*rx_remained_cnt == 0*/) { + rtl_write_word(rtlpriv, 0x3B4, + rtlpci->rx_ring[hw_queue].next_rx_rp); + } + } + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) { + rtl_lps_leave(hw); + } + + if (rtlpriv->use_new_trx_flow) { + _rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc, + rxring_idx, + rtlpci->rx_ring[rxring_idx].idx); + } else { + _rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx, + rtlpci->rx_ring[rxring_idx].idx); + + if (rtlpci->rx_ring[rxring_idx].idx == + rtlpci->rxringcount - 1) + rtlpriv->cfg->ops->set_desc(hw, (u8 *) pdesc, + false, + HW_DESC_RXERO, + (u8 *) & tmp_one); + } + rtlpci->rx_ring[rxring_idx].idx = + (rtlpci->rx_ring[rxring_idx].idx + 1) % + rtlpci->rxringcount; + } +} + +static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) +{ + struct ieee80211_hw *hw = dev_id; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u32 inta = 0; + u32 intb = 0; + + + + if (rtlpci->irq_enabled == 0) + return IRQ_HANDLED; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock,flags); + + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMR], 0x0); + + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE], 0x0); + + + /*read ISR: 4/8bytes */ + rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb); + + + /*Shared IRQ or HW disappared */ + if (!inta || inta == 0xffff) + goto done; + /*<1> beacon related */ + if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) { + RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon ok interrupt!\n")); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) { + RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon err interrupt!\n")); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) { + RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon interrupt!\n")); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) { + RT_TRACE(COMP_INTR, DBG_TRACE, + ("prepare beacon for interrupt!\n")); + tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet); + } + + + /*<2> tx related */ + if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_TXFOVW])) + RT_TRACE(COMP_ERR, DBG_TRACE, ("IMR_TXFOVW!\n")); + + if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) { + RT_TRACE(COMP_INTR, DBG_TRACE, ("Manage ok interrupt!\n")); + _rtl_pci_tx_isr(hw, MGNT_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) { + RT_TRACE(COMP_INTR, DBG_TRACE, ("HIGH_QUEUE ok interrupt!\n")); + _rtl_pci_tx_isr(hw, HIGH_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BKDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(COMP_INTR, DBG_TRACE, ("BK Tx OK interrupt!\n")); + _rtl_pci_tx_isr(hw, BK_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BEDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(COMP_INTR, DBG_TRACE, ("BE TX OK interrupt!\n")); + _rtl_pci_tx_isr(hw, BE_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_VIDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(COMP_INTR, DBG_TRACE, ("VI TX OK interrupt!\n")); + _rtl_pci_tx_isr(hw, VI_QUEUE); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_VODOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(COMP_INTR, DBG_TRACE, ("Vo TX OK interrupt!\n")); + _rtl_pci_tx_isr(hw, VO_QUEUE); + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(COMP_INTR, DBG_TRACE, + ("CMD TX OK interrupt!\n")); + _rtl_pci_tx_isr(hw, TXCMD_QUEUE); + } + } + + /*<3> rx related */ + if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { + RT_TRACE(COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); + + _rtl_pci_rx_interrupt(hw); + + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("rx descriptor unavailable!\n")); + rtl_write_byte(rtlpriv, 0xb4, BIT(1) ); + _rtl_pci_rx_interrupt(hw); + } + + if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { + RT_TRACE(COMP_ERR, DBG_WARNING, ("rx overflow !\n")); + _rtl_pci_rx_interrupt(hw); + } + + /*<4> fw related*/ + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) { + if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) { + RT_TRACE(COMP_INTR, DBG_TRACE, + ("firmware interrupt!\n")); + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.fwevt_wq, 0); + } + } + + /*<5> hsisr related*/ + /* Only 8188EE & 8723BE Supported. + * If Other ICs Come in, System will corrupt, + * because maps[RTL_IMR_HSISR_IND] & maps[MAC_HSISR] + * are not initialized*/ + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE || + rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_HSISR_IND])) { + RT_TRACE(COMP_INTR, DBG_TRACE, + ("hsisr interrupt!\n")); + _rtl_pci_hs_interrupt(hw); + } + } + + + if(rtlpriv->rtlhal.b_earlymode_enable) + tasklet_schedule(&rtlpriv->works.irq_tasklet); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMR], + rtlpci->irq_mask[0]); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE], + rtlpci->irq_mask[1]); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + return IRQ_HANDLED; + +done: + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + return IRQ_HANDLED; +} + +static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) +{ + _rtl_pci_tx_chk_waitq(hw); +} + +static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl8192_tx_ring *ring = NULL; + struct ieee80211_hdr *hdr = NULL; + struct ieee80211_tx_info *info = NULL; + struct sk_buff *pskb = NULL; + struct rtl_tx_desc *pdesc = NULL; + struct rtl_tcb_desc tcb_desc; + /*This is for new trx flow*/ + struct rtl_tx_buffer_desc *pbuffer_desc = NULL; + u8 temp_one = 1; + + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + + /*NB: the beacon data buffer must be 32-bit aligned. */ + pskb = ieee80211_beacon_get(hw, mac->vif); + if (pskb == NULL) + return; + hdr = rtl_get_hdr(pskb); + info = IEEE80211_SKB_CB(pskb); + pdesc = &ring->desc[0]; + if (rtlpriv->use_new_trx_flow) + pbuffer_desc = &ring->buffer_desc[0]; + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, + (u8 *)pbuffer_desc, info, pskb, + BEACON_QUEUE, &tcb_desc); +#else +/**/ + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, + (u8 *)pbuffer_desc, info, NULL, pskb, + BEACON_QUEUE, &tcb_desc); +/**/ +#endif +/**/ + + __skb_queue_tail(&ring->queue, pskb); + + rtlpriv->cfg->ops->set_desc(hw, (u8 *) pdesc, true, HW_DESC_OWN, + (u8 *) & temp_one); + + return; +} + +static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 i; + u16 desc_num; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) + desc_num = TX_DESC_NUM_92E; + else + desc_num = RT_TXDESC_NUM; + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { + rtlpci->txringcount[i] = desc_num; + } + /* + *we just alloc 2 desc for beacon queue, + *because we just need first desc in hw beacon. + */ + rtlpci->txringcount[BEACON_QUEUE] = 2; + + /* + *BE queue need more descriptor for performance + *consideration or, No more tx desc will happen, + *and may cause mac80211 mem leakage. + */ + if (rtl_priv(hw)->use_new_trx_flow == false) + rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE; + + rtlpci->rxbuffersize = 9100; /*2048/1024; */ + rtlpci->rxringcount = RTL_PCI_MAX_RX_COUNT; /*64; */ +} + +static void _rtl_pci_init_struct(struct ieee80211_hw *hw, + struct pci_dev *pdev) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + rtlpriv->rtlhal.up_first_time = true; + rtlpriv->rtlhal.being_init_adapter = false; + + rtlhal->hw = hw; + rtlpci->pdev = pdev; + + /*Tx/Rx related var */ + _rtl_pci_init_trx_var(hw); + + /*IBSS*/ mac->beacon_interval = 100; + + /*AMPDU*/ + mac->min_space_cfg = 0; + mac->max_mss_density = 0; + /*set sane AMPDU defaults */ + mac->current_ampdu_density = 7; + mac->current_ampdu_factor = 3; + + /*QOS*/ + rtlpci->acm_method = eAcmWay2_SW; + + /*task */ + tasklet_init(&rtlpriv->works.irq_tasklet, + (void (*)(unsigned long))_rtl_pci_irq_tasklet, + (unsigned long)hw); + tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, + (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, + (unsigned long)hw); +} + +static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, + unsigned int prio, unsigned int entries) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_buffer_desc *buffer_desc; + struct rtl_tx_desc *desc; + dma_addr_t buffer_desc_dma, desc_dma; + u32 nextdescaddress; + int i; + + /* alloc tx buffer desc for new trx flow*/ + if (rtlpriv->use_new_trx_flow) { + buffer_desc = pci_alloc_consistent(rtlpci->pdev, + sizeof(*buffer_desc) * entries, + &buffer_desc_dma); + + if (!buffer_desc || (unsigned long)buffer_desc & 0xFF) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Cannot allocate TX ring (prio = %d)\n", + prio)); + return -ENOMEM; + } + + memset(buffer_desc, 0, sizeof(*buffer_desc) * entries); + rtlpci->tx_ring[prio].buffer_desc = buffer_desc; + rtlpci->tx_ring[prio].buffer_desc_dma = buffer_desc_dma; + + rtlpci->tx_ring[prio].cur_tx_rp = 0; + rtlpci->tx_ring[prio].cur_tx_wp = 0; + rtlpci->tx_ring[prio].avl_desc = entries; + + } + + /* alloc dma for this ring */ + desc = pci_alloc_consistent(rtlpci->pdev, + sizeof(*desc) * entries, &desc_dma); + + if (!desc || (unsigned long)desc & 0xFF) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Cannot allocate TX ring (prio = %d)\n", prio)); + return -ENOMEM; + } + + memset(desc, 0, sizeof(*desc) * entries); + rtlpci->tx_ring[prio].desc = desc; + rtlpci->tx_ring[prio].dma = desc_dma; + + rtlpci->tx_ring[prio].idx = 0; + rtlpci->tx_ring[prio].entries = entries; + skb_queue_head_init(&rtlpci->tx_ring[prio].queue); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("queue:%d, ring_addr:%p\n", prio, desc)); + + /* init every desc in this ring */ + if (rtlpriv->use_new_trx_flow == false) { + for (i = 0; i < entries; i++) { + nextdescaddress = cpu_to_le32((u32) desc_dma + + ((i + 1) % entries) * + sizeof(*desc)); + + rtlpriv->cfg->ops->set_desc(hw, (u8 *) & (desc[i]), + true, + HW_DESC_TX_NEXTDESC_ADDR, + (u8 *) & nextdescaddress); + } + } + return 0; +} + +static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + int i; + + if (rtlpriv->use_new_trx_flow) { + struct rtl_rx_buffer_desc *entry = NULL; + /* alloc dma for this ring */ + rtlpci->rx_ring[rxring_idx].buffer_desc = + pci_alloc_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx]. + buffer_desc) * + rtlpci->rxringcount, + &rtlpci->rx_ring[rxring_idx].dma); + if (!rtlpci->rx_ring[rxring_idx].buffer_desc || + (unsigned long)rtlpci->rx_ring[rxring_idx].buffer_desc & 0xFF) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("Cannot allocate RX ring\n")); + return -ENOMEM; + } + + memset(rtlpci->rx_ring[rxring_idx].buffer_desc, 0, + sizeof(*rtlpci->rx_ring[rxring_idx].buffer_desc) * + rtlpci->rxringcount); + + /* init every desc in this ring */ + rtlpci->rx_ring[rxring_idx].idx = 0; + for (i = 0; i < rtlpci->rxringcount; i++) { + entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i]; + if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry, + rxring_idx, i)) + return -ENOMEM; + } + } else { + struct rtl_rx_desc *entry = NULL; + u8 tmp_one = 1; + /* alloc dma for this ring */ + rtlpci->rx_ring[rxring_idx].desc = + pci_alloc_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx]. + desc) * rtlpci->rxringcount, + &rtlpci->rx_ring[rxring_idx].dma); + if (!rtlpci->rx_ring[rxring_idx].desc || + (unsigned long)rtlpci->rx_ring[rxring_idx].desc & 0xFF) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Cannot allocate RX ring\n")); + return -ENOMEM; + } + + memset(rtlpci->rx_ring[rxring_idx].desc, 0, + sizeof(*rtlpci->rx_ring[rxring_idx].desc) * + rtlpci->rxringcount); + + /* init every desc in this ring */ + rtlpci->rx_ring[rxring_idx].idx = 0; + for (i = 0; i < rtlpci->rxringcount; i++) { + entry = &rtlpci->rx_ring[rxring_idx].desc[i]; + if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry, + rxring_idx, i)) + return -ENOMEM; + } + rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false, + HW_DESC_RXERO, (u8 *) & tmp_one); + } + return 0; +} + +static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw, + unsigned int prio) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + + /* free every desc in this ring */ + while (skb_queue_len(&ring->queue)) { + u8 *entry; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc[ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + + pci_unmap_single(rtlpci->pdev, + le32_to_cpu(rtlpriv->cfg->ops->get_desc( + (u8 *) entry, true, HW_DESC_TXBUFF_ADDR)), + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + + /* free dma of this ring */ + pci_free_consistent(rtlpci->pdev, + sizeof(*ring->desc) * ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; + if (rtlpriv->use_new_trx_flow) { + pci_free_consistent(rtlpci->pdev, + sizeof(*ring->buffer_desc) * ring->entries, + ring->buffer_desc, ring->buffer_desc_dma); + ring->buffer_desc = NULL; + } +} + +static void _rtl_pci_free_rx_ring(struct ieee80211_hw *hw, int rxring_idx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int i; + + /* free every desc in this ring */ + for (i = 0; i < rtlpci->rxringcount; i++) { + struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[i]; + if (!skb) + continue; + + pci_unmap_single(rtlpci->pdev, *((dma_addr_t *) skb->cb), + rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); + kfree_skb(skb); + } + + /* free dma of this ring */ + if (rtlpriv->use_new_trx_flow) { + pci_free_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx]. + buffer_desc) * rtlpci->rxringcount, + rtlpci->rx_ring[rxring_idx].buffer_desc, + rtlpci->rx_ring[rxring_idx].dma); + rtlpci->rx_ring[rxring_idx].buffer_desc = NULL; + } else { + pci_free_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rxring_idx].desc) * + rtlpci->rxringcount, + rtlpci->rx_ring[rxring_idx].desc, + rtlpci->rx_ring[rxring_idx].dma); + rtlpci->rx_ring[rxring_idx].desc = NULL; + } +} + +static int _rtl_pci_init_trx_ring(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int ret; + int i, rxring_idx; + + /* rxring_idx 0:RX_MPDU_QUEUE + * rxring_idx 1:RX_CMD_QUEUE */ + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) { + ret = _rtl_pci_init_rx_ring(hw, rxring_idx); + if (ret) + return ret; + } + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { + ret = _rtl_pci_init_tx_ring(hw, i, rtlpci->txringcount[i]); + if (ret) + goto err_free_rings; + } + + return 0; + +err_free_rings: + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) + _rtl_pci_free_rx_ring(hw, rxring_idx); + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + if (rtlpci->tx_ring[i].desc || + rtlpci->tx_ring[i].buffer_desc) + _rtl_pci_free_tx_ring(hw, i); + + return 1; +} + +static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw) +{ + u32 i, rxring_idx; + + /*free rx rings */ + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) + _rtl_pci_free_rx_ring(hw, rxring_idx); + + /*free tx rings */ + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + _rtl_pci_free_tx_ring(hw, i); + + return 0; +} + +int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int i, rxring_idx; + unsigned long flags; + u8 tmp_one = 1; + /* rxring_idx 0:RX_MPDU_QUEUE */ + /* rxring_idx 1:RX_CMD_QUEUE */ + for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) { + /* force the rx_ring[RX_MPDU_QUEUE/ + * RX_CMD_QUEUE].idx to the first one */ + /*new trx flow, do nothing*/ + if ((rtlpriv->use_new_trx_flow == false) && + rtlpci->rx_ring[rxring_idx].desc) { + struct rtl_rx_desc *entry = NULL; + + for (i = 0; i < rtlpci->rxringcount; i++) { + entry = &rtlpci->rx_ring[rxring_idx].desc[i]; + rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, + false, + HW_DESC_RXOWN, + (u8 *) & tmp_one); + } + } + rtlpci->rx_ring[rxring_idx].idx = 0; } + + /* after reset, release previous pending packet, + * and force the tx idx to the first one */ + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { + if (rtlpci->tx_ring[i].desc || + rtlpci->tx_ring[i].buffer_desc) { + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i]; + + while (skb_queue_len(&ring->queue)) { + u8 *entry; + struct sk_buff *skb = + __skb_dequeue(&ring->queue); + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc + [ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + + pci_unmap_single(rtlpci->pdev, + le32_to_cpu(rtlpriv->cfg->ops->get_desc( + (u8 *)entry, true, + HW_DESC_TXBUFF_ADDR)), + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + ring->idx = 0; + } + } + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + return 0; +} + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) +static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, + struct sk_buff *skb) +#else +/**/ +static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb) +/**/ +#endif +/**/ +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; +#endif +/**/ + struct rtl_sta_info *sta_entry = NULL; + u8 tid = rtl_get_tid(skb); + u16 fc = rtl_get_fc(skb); + + if(!sta) + return false; + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + + if (!rtlpriv->rtlhal.b_earlymode_enable) + return false; + if (ieee80211_is_nullfunc(fc)) + return false; + if (ieee80211_is_qos_nullfunc(fc)) + return false; + if (ieee80211_is_pspoll(fc)) { + return false; + } + + if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL) + return false; + if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) + return false; + if (tid > 7) + return false; + /* maybe every tid should be checked */ + if (!rtlpriv->link_info.higher_busytxtraffic[tid]) + return false; + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb); + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + return true; +} + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) +int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc) +#else +/**/ +static int rtl_pci_tx(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc) +/**/ +#endif +/**/ +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry = NULL; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + struct ieee80211_sta *sta = info->control.sta; +#endif +/**/ + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + struct rtl_tx_buffer_desc *ptx_bd_desc = NULL; + u16 idx; + u8 own; + u8 temp_one = 1; + u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); + unsigned long flags; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + u16 fc = rtl_get_fc(skb); + u8 *pda_addr = hdr->addr1; + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + /*ssn */ + u8 tid = 0; + u16 seq_number = 0; + + + if (ieee80211_is_mgmt(fc)) + rtl_tx_mgmt_proc(hw, skb); + + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + + rtl_action_proc(hw, skb, true); + + if (is_multicast_ether_addr(pda_addr)) + rtlpriv->stats.txbytesmulticast += skb->len; + else if (is_broadcast_ether_addr(pda_addr)) + rtlpriv->stats.txbytesbroadcast += skb->len; + else + rtlpriv->stats.txbytesunicast += skb->len; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + ring = &rtlpci->tx_ring[hw_queue]; + if (hw_queue != BEACON_QUEUE) { + if (rtlpriv->use_new_trx_flow) + idx = ring->cur_tx_wp; + else + idx = (ring->idx + skb_queue_len(&ring->queue)) % + ring->entries; + } else { + idx = 0; + } + + pdesc = &ring->desc[idx]; + + if (rtlpriv->use_new_trx_flow) { + ptx_bd_desc = &ring->buffer_desc[idx]; + } else { + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, + true, HW_DESC_OWN); + + if ((own == 1) && (hw_queue != BEACON_QUEUE)) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("No more TX desc@%d, ring->idx = %d," + "idx = %d, skb_queue_len = 0x%d\n", + hw_queue, ring->idx, idx, + skb_queue_len(&ring->queue))); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + return skb->len; + } + } + + if (ieee80211_is_data_qos(fc)) { + tid = rtl_get_tid(skb); + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + seq_number = (le16_to_cpu(hdr->seq_ctrl) & + IEEE80211_SCTL_SEQ) >> 4; + seq_number += 1; + + if (!ieee80211_has_morefrags(hdr->frame_control)) + sta_entry->tids[tid].seq_number = seq_number; + } + } + + if (ieee80211_is_data(fc)) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, + (u8 *)ptx_bd_desc, info, skb, + hw_queue, ptcb_desc); +#else +/**/ + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, + (u8 *)ptx_bd_desc, info, sta, skb, + hw_queue, ptcb_desc); +/**/ +#endif +/**/ + + __skb_queue_tail(&ring->queue, skb); + if (rtlpriv->use_new_trx_flow) { + rtlpriv->cfg->ops->set_desc(hw, (u8 *) pdesc, true, + HW_DESC_OWN, (u8 *) & hw_queue); + } else { + rtlpriv->cfg->ops->set_desc(hw, (u8 *) pdesc, true, + HW_DESC_OWN, (u8 *) & temp_one); + } + + if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && + hw_queue != BEACON_QUEUE) { + + RT_TRACE(COMP_ERR, DBG_LOUD, + ("less desc left, stop skb_queue@%d, " + "ring->idx = %d," + "idx = %d, skb_queue_len = 0x%d\n", + hw_queue, ring->idx, idx, + skb_queue_len(&ring->queue))); + + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); + } + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, hw_queue); + + return 0; +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +static void rtl_pci_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +#else +static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop) +#endif +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 i = 0; + int queue_id; + struct rtl8192_tx_ring *ring; + + if (mac->skip_scan) + return; + + for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { + u32 queue_len; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + if (((queues >> queue_id) & 0x1) == 0) { + queue_id--; + continue; + } +#endif + ring = &pcipriv->dev.tx_ring[queue_id]; + queue_len = skb_queue_len(&ring->queue); + if (queue_len == 0 || queue_id == BEACON_QUEUE || + queue_id == TXCMD_QUEUE) { + queue_id--; + continue; + } else { + msleep(5); + i++; + } + + /* we just wait 1s for all queues */ + if (rtlpriv->psc.rfpwr_state == ERFOFF || + is_hal_stop(rtlhal) || i >= 200) + return; + } +} + +void rtl_pci_deinit(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + _rtl_pci_deinit_trx_ring(hw); + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); + + flush_workqueue(rtlpriv->works.rtl_wq); + destroy_workqueue(rtlpriv->works.rtl_wq); + +} + +int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err; + + _rtl_pci_init_struct(hw, pdev); + + err = _rtl_pci_init_trx_ring(hw); + if (err) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("tx ring initialization failed")); + return err; + } + + return 1; +} + +int rtl_pci_start(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + int err = 0; + RT_TRACE(COMP_INIT, DBG_DMESG, (" rtl_pci_start \n")); + rtl_pci_reset_trx_ring(hw); + + rtlpriv->rtlhal.driver_is_goingto_unload = false; + err = rtlpriv->cfg->ops->hw_init(hw); + if (err) { + RT_TRACE(COMP_INIT, DBG_DMESG, + ("Failed to config hardware err %x!\n",err)); + return err; + } + + rtlpriv->cfg->ops->enable_interrupt(hw); + RT_TRACE(COMP_INIT, DBG_LOUD, ("enable_interrupt OK\n")); + + rtl_init_rx_config(hw); + + /*should after adapter start and interrupt enable. */ + set_hal_start(rtlhal); + + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + rtlpriv->rtlhal.up_first_time = false; + + RT_TRACE(COMP_INIT, DBG_DMESG, ("rtl_pci_start OK\n")); + return 0; +} + +void rtl_pci_stop(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 RFInProgressTimeOut = 0; + + /* + *should before disable interrrupt&adapter + *and will do it immediately. + */ + set_hal_stop(rtlhal); + + rtlpriv->cfg->ops->disable_interrupt(hw); + + spin_lock(&rtlpriv->locks.rf_ps_lock); + while (ppsc->rfchange_inprogress) { + spin_unlock(&rtlpriv->locks.rf_ps_lock); + if (RFInProgressTimeOut > 100) { + spin_lock(&rtlpriv->locks.rf_ps_lock); + break; + } + mdelay(1); + RFInProgressTimeOut++; + spin_lock(&rtlpriv->locks.rf_ps_lock); + } + ppsc->rfchange_inprogress = true; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + + rtlpriv->rtlhal.driver_is_goingto_unload = true; + rtlpriv->cfg->ops->hw_disable(hw); + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + + rtl_pci_enable_aspm(hw); +} + +static bool _rtl_pci_find_adapter(struct pci_dev *pdev, + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct pci_dev *bridge_pdev = pdev->bus->self; + u16 venderid; + u16 deviceid; + u8 revisionid; + u16 irqline; + u8 tmp; + + venderid = pdev->vendor; + deviceid = pdev->device; + pci_read_config_byte(pdev, 0x8, &revisionid); + pci_read_config_word(pdev, 0x3C, &irqline); + + if (deviceid == RTL_PCI_8192_DID || + deviceid == RTL_PCI_0044_DID || + deviceid == RTL_PCI_0047_DID || + deviceid == RTL_PCI_8192SE_DID || + deviceid == RTL_PCI_8174_DID || + deviceid == RTL_PCI_8173_DID || + deviceid == RTL_PCI_8172_DID || + deviceid == RTL_PCI_8171_DID) { + switch (revisionid) { + case RTL_PCI_REVISION_ID_8192PCIE: + RT_TRACE(COMP_INIT, DBG_DMESG, + ("8192E is found but not supported now-" + "vid/did=%x/%x\n", venderid, deviceid)); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192E; + return false; + break; + case RTL_PCI_REVISION_ID_8192SE: + RT_TRACE(COMP_INIT, DBG_DMESG, + ("8192SE is found - " + "vid/did=%x/%x\n", venderid, deviceid)); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; + break; + default: + RT_TRACE(COMP_ERR, DBG_WARNING, + ("Err: Unknown device - " + "vid/did=%x/%x\n", venderid, deviceid)); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; + break; + + } + }else if(deviceid == RTL_PCI_8723AE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8723AE; + RT_TRACE(COMP_INIT, DBG_DMESG, + ("8723AE PCI-E is found - " + "vid/did=%x/%x\n", venderid, deviceid)); + } else if (deviceid == RTL_PCI_8192CET_DID || + deviceid == RTL_PCI_8192CE_DID || + deviceid == RTL_PCI_8191CE_DID || + deviceid == RTL_PCI_8188CE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192CE; + RT_TRACE(COMP_INIT, DBG_DMESG, + ("8192C PCI-E is found - " + "vid/did=%x/%x\n", venderid, deviceid)); + } else if (deviceid == RTL_PCI_8192DE_DID || + deviceid == RTL_PCI_8192DE_DID2) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE; + RT_TRACE(COMP_INIT, DBG_DMESG, + ("8192D PCI-E is found - " + "vid/did=%x/%x\n", venderid, deviceid)); + }else if(deviceid == RTL_PCI_8188EE_DID){ + rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE; + RT_TRACE(COMP_INIT,DBG_LOUD, + ("Find adapter, Hardware type is 8188EE\n")); + }else if (deviceid == RTL_PCI_8723BE_DID){ + rtlhal->hw_type = HARDWARE_TYPE_RTL8723BE; + RT_TRACE(COMP_INIT,DBG_LOUD, + ("Find adapter, Hardware type is 8723BE\n")); + }else if (deviceid == RTL_PCI_8192EE_DID){ + rtlhal->hw_type = HARDWARE_TYPE_RTL8192EE; + RT_TRACE(COMP_INIT,DBG_LOUD, + ("Find adapter, Hardware type is 8192EE\n")); + }else if (deviceid == RTL_PCI_8821AE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8821AE; + RT_TRACE(COMP_INIT,DBG_LOUD, + ("Find adapter, Hardware type is 8821AE\n")); + }else if (deviceid == RTL_PCI_8812AE_DID) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8812AE; + RT_TRACE(COMP_INIT,DBG_LOUD, + ("Find adapter, Hardware type is 8812AE\n")); + }else { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("Err: Unknown device -" + " vid/did=%x/%x\n", venderid, deviceid)); + + rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) { + if (revisionid == 0 || revisionid == 1) { + if (revisionid == 0) { + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Find 92DE MAC0.\n")); + rtlhal->interfaceindex = 0; + } else if (revisionid == 1) { + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Find 92DE MAC1.\n")); + rtlhal->interfaceindex = 1; + } + } else { + RT_TRACE(COMP_INIT, DBG_LOUD, ("Unknown device - " + "VendorID/DeviceID=%x/%x, Revision=%x\n", + venderid, deviceid, revisionid)); + rtlhal->interfaceindex = 0; + } + } + + /* 92ee use new trx flow */ + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) + rtlpriv->use_new_trx_flow = true; + else + rtlpriv->use_new_trx_flow = false; + + /*find bus info */ + pcipriv->ndis_adapter.busnumber = pdev->bus->number; + pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); + pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn); + + /*find bridge info */ + pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; + /* some ARM have no bridge_pdev and will crash here + * so we should check if bridge_pdev is NULL */ + if (bridge_pdev) { + pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; + for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { + if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { + pcipriv->ndis_adapter.pcibridge_vendor = tmp; + RT_TRACE(COMP_INIT, DBG_DMESG, + ("Pci Bridge Vendor is found index: %d\n", + tmp)); + break; + } + } + } + + if (pcipriv->ndis_adapter.pcibridge_vendor != + PCI_BRIDGE_VENDOR_UNKNOWN) { + pcipriv->ndis_adapter.pcibridge_busnum = + bridge_pdev->bus->number; + pcipriv->ndis_adapter.pcibridge_devnum = + PCI_SLOT(bridge_pdev->devfn); + pcipriv->ndis_adapter.pcibridge_funcnum = + PCI_FUNC(bridge_pdev->devfn); + pcipriv->ndis_adapter.pcicfg_addrport = + (pcipriv->ndis_adapter.pcibridge_busnum << 16) | + (pcipriv->ndis_adapter.pcibridge_devnum << 11) | + (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) +/**/ + pcipriv->ndis_adapter.pcibridge_pciehdr_offset = + pci_pcie_cap(bridge_pdev); +/**/ +#else + pcipriv->ndis_adapter.pcibridge_pciehdr_offset = + _rtl_pci_get_pciehdr_offset(hw); +#endif +/**/ + pcipriv->ndis_adapter.num4bytes = + (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; + + rtl_pci_get_linkcontrol_field(hw); + + if (pcipriv->ndis_adapter.pcibridge_vendor == + PCI_BRIDGE_VENDOR_AMD) { + pcipriv->ndis_adapter.amd_l1_patch = + rtl_pci_get_amd_l1_patch(hw); + } + } + + RT_TRACE(COMP_INIT, DBG_DMESG, + ("pcidev busnumber:devnumber:funcnumber:" + "vendor:link_ctl %d:%d:%d:%x:%x\n", + pcipriv->ndis_adapter.busnumber, + pcipriv->ndis_adapter.devnumber, + pcipriv->ndis_adapter.funcnumber, + pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg)); + + RT_TRACE(COMP_INIT, DBG_DMESG, + ("pci_bridge busnumber:devnumber:funcnumber:vendor:" + "pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n", + pcipriv->ndis_adapter.pcibridge_busnum, + pcipriv->ndis_adapter.pcibridge_devnum, + pcipriv->ndis_adapter.pcibridge_funcnum, + pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor], + pcipriv->ndis_adapter.pcibridge_pciehdr_offset, + pcipriv->ndis_adapter.pcibridge_linkctrlreg, + pcipriv->ndis_adapter.amd_l1_patch)); + + rtl_pci_parse_configuration(pdev, hw); + list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list); + return true; +} + +static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + int ret; + ret = pci_enable_msi(rtlpci->pdev); + if (ret < 0) + return ret; + + ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, + IRQF_SHARED, KBUILD_MODNAME, hw); + if (ret < 0) { + pci_disable_msi(rtlpci->pdev); + return ret; + } + + rtlpci->using_msi = true; + + RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG, ("MSI Interrupt Mode!\n")); + return 0; +} + +static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + int ret; + + ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, + IRQF_SHARED, KBUILD_MODNAME, hw); + if (ret < 0) { + return ret; + } + + rtlpci->using_msi = false; + RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG, + ("Pin-based Interrupt Mode!\n")); + return 0; +} + +static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + int ret; + if (rtlpci->msi_support == true) { + ret = rtl_pci_intr_mode_msi(hw); + if (ret < 0) + ret = rtl_pci_intr_mode_legacy(hw); + } else { + ret = rtl_pci_intr_mode_legacy(hw); + } + return ret; +} + +/* this is used for other modules get + * hw pointer in rtl_pci_get_hw_pointer */ +struct ieee80211_hw *hw_export = NULL; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) +int rtl_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + +#else +int __devinit rtl_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +#endif +{ + struct ieee80211_hw *hw = NULL; + + struct rtl_priv *rtlpriv = NULL; + struct rtl_pci_priv *pcipriv = NULL; + struct rtl_pci *rtlpci; + unsigned long pmem_start, pmem_len, pmem_flags; + int err; + + + err = pci_enable_device(pdev); + if (err) { + RT_ASSERT(false, + ("%s : Cannot enable new PCI device\n", + pci_name(pdev))); + return err; + } + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { + RT_ASSERT(false, ("Unable to obtain 32bit DMA " + "for consistent allocations\n")); + pci_disable_device(pdev); + return -ENOMEM; + } + } + + pci_set_master(pdev); + + hw = ieee80211_alloc_hw(sizeof(struct rtl_pci_priv) + + sizeof(struct rtl_priv), &rtl_ops); + if (!hw) { + RT_ASSERT(false, + ("%s : ieee80211 alloc failed\n", pci_name(pdev))); + err = -ENOMEM; + goto fail1; + } + hw_export = hw; + + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); + + rtlpriv = hw->priv; + pcipriv = (void *)rtlpriv->priv; + pcipriv->dev.pdev = pdev; + + /* init cfg & intf_ops */ + rtlpriv->rtlhal.interface = INTF_PCI; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); + rtlpriv->intf_ops = &rtl_pci_ops; + rtlpriv->glb_var = &global_var; + + /* + *init dbgp flags before all + *other functions, because we will + *use it in other funtions like + *RT_TRACE/RT_PRINT/RTL_PRINT_DATA + *you can not use these macro + *before this + */ + rtl_dbgp_flag_init(hw); + + /* MEM map */ + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + RT_ASSERT(false, ("Can't obtain PCI resources\n")); + return err; + } + + pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); + pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id); + pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id); + + /*shared mem start */ + rtlpriv->io.pci_mem_start = + (unsigned long)pci_iomap(pdev, + rtlpriv->cfg->bar_id, pmem_len); + if (rtlpriv->io.pci_mem_start == 0) { + RT_ASSERT(false, ("Can't map PCI mem\n")); + goto fail2; + } + + RT_TRACE(COMP_INIT, DBG_DMESG, + ("mem mapped space: start: 0x%08lx len:%08lx " + "flags:%08lx, after map:0x%08lx\n", + pmem_start, pmem_len, pmem_flags, + rtlpriv->io.pci_mem_start)); + + /* Disable Clk Request */ + pci_write_config_byte(pdev, 0x81, 0); + /* leave D3 mode */ + pci_write_config_byte(pdev, 0x44, 0); + pci_write_config_byte(pdev, 0x04, 0x06); + pci_write_config_byte(pdev, 0x04, 0x07); + + /* find adapter */ + /* if chip not support, will return false */ + if(!_rtl_pci_find_adapter(pdev, hw)) + goto fail3; + + /* Init IO handler */ + _rtl_pci_io_handler_init(&pdev->dev, hw); + + /*like read eeprom and so on */ + rtlpriv->cfg->ops->read_eeprom_info(hw); + + if (rtlpriv->cfg->ops->init_sw_vars(hw)) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("Can't init_sw_vars.\n")); + goto fail3; + } + + rtlpriv->cfg->ops->init_sw_leds(hw); + + /*aspm */ + rtl_pci_init_aspm(hw); + + /* Init mac80211 sw */ + err = rtl_init_core(hw); + if (err) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Can't allocate sw for mac80211.\n")); + goto fail3; + } + + /* Init PCI sw */ + err = !rtl_pci_init(hw, pdev); + if (err) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("Failed to init PCI.\n")); + goto fail3; + } + + err = ieee80211_register_hw(hw); + if (err) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Can't register mac80211 hw.\n")); + goto fail3; + } else { + rtlpriv->mac80211.mac80211_registered = 1; + } + /* the wiphy must have been registed to + * cfg80211 prior to regulatory_hint */ + if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) { + RT_TRACE(COMP_ERR, DBG_WARNING, ("regulatory_hint fail\n")); + } + + err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group); + if (err) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("failed to create sysfs device attributes\n")); + goto fail3; + } + /* add for prov */ + rtl_proc_add_one(hw); + + /*init rfkill */ + rtl_init_rfkill(hw); + + rtlpci = rtl_pcidev(pcipriv); + + err = rtl_pci_intr_mode_decide(hw); + if (err) { + RT_TRACE(COMP_INIT, DBG_DMESG, + ("%s: failed to register IRQ handler\n", + wiphy_name(hw->wiphy))); + goto fail3; + } else { + rtlpci->irq_alloc = 1; + } + + set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + return 0; + +fail3: + pci_set_drvdata(pdev, NULL); + rtl_deinit_core(hw); + ieee80211_free_hw(hw); + + if (rtlpriv->io.pci_mem_start != 0) + pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start); + +fail2: + pci_release_regions(pdev); + +fail1: + + pci_disable_device(pdev); + + return -ENODEV; + +} +//EXPORT_SYMBOL(rtl_pci_probe); + +struct ieee80211_hw *rtl_pci_get_hw_pointer(void) +{ + return hw_export; +} +//EXPORT_SYMBOL(rtl_pci_get_hw_pointer); + +void rtl_pci_disconnect(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + struct rtl_mac *rtlmac = rtl_mac(rtlpriv); + + clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + + sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group); + + /* add for prov */ + rtl_proc_remove_one(hw); + + + /*ieee80211_unregister_hw will call ops_stop */ + if (rtlmac->mac80211_registered == 1) { + ieee80211_unregister_hw(hw); + rtlmac->mac80211_registered = 0; + } else { + rtl_deinit_deferred_work(hw); + rtlpriv->intf_ops->adapter_stop(hw); + } + + /*deinit rfkill */ + rtl_deinit_rfkill(hw); + + rtl_pci_deinit(hw); + rtl_deinit_core(hw); + rtlpriv->cfg->ops->deinit_sw_vars(hw); + + if (rtlpci->irq_alloc) { + synchronize_irq(rtlpci->pdev->irq); + free_irq(rtlpci->pdev->irq, hw); + rtlpci->irq_alloc = 0; + } + + if (rtlpci->using_msi == true) + pci_disable_msi(rtlpci->pdev); + + list_del(&rtlpriv->list); + if (rtlpriv->io.pci_mem_start != 0) { + pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start); + pci_release_regions(pdev); + } + + pci_disable_device(pdev); + + rtl_pci_disable_aspm(hw); + + pci_set_drvdata(pdev, NULL); + + ieee80211_free_hw(hw); +} +//EXPORT_SYMBOL(rtl_pci_disconnect); + +/*************************************** +kernel pci power state define: +PCI_D0 ((pci_power_t __force) 0) +PCI_D1 ((pci_power_t __force) 1) +PCI_D2 ((pci_power_t __force) 2) +PCI_D3hot ((pci_power_t __force) 3) +PCI_D3cold ((pci_power_t __force) 4) +PCI_UNKNOWN ((pci_power_t __force) 5) + +This function is called when system +goes into suspend state mac80211 will +call rtl_mac_stop() from the mac80211 +suspend function first, So there is +no need to call hw_disable here. +****************************************/ +int rtl_pci_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->hw_suspend(hw); + rtl_deinit_rfkill(hw); + + return 0; +} +//EXPORT_SYMBOL(rtl_pci_suspend); + +int rtl_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->hw_resume(hw); + rtl_init_rfkill(hw); + + return 0; +} +//EXPORT_SYMBOL(rtl_pci_resume); + +struct rtl_intf_ops rtl_pci_ops = { + .read_efuse_byte = read_efuse_byte, + .adapter_start = rtl_pci_start, + .adapter_stop = rtl_pci_stop, + .check_buddy_priv = rtl_pci_check_buddy_priv, + .adapter_tx = rtl_pci_tx, + .flush = rtl_pci_flush, + .reset_trx_ring = rtl_pci_reset_trx_ring, + .waitq_insert = rtl_pci_tx_chk_waitq_insert, + + .disable_aspm = rtl_pci_disable_aspm, + .enable_aspm = rtl_pci_enable_aspm, +}; --- linux-3.13.0.orig/drivers/staging/rtl8821ae/Makefile +++ linux-3.13.0/drivers/staging/rtl8821ae/Makefile @@ -0,0 +1,35 @@ +PCI_MAIN_OBJS := base.o \ + rc.o \ + debug.o \ + regd.o \ + efuse.o \ + cam.o \ + ps.o \ + core.o \ + stats.o \ + pci.o \ + +BT_COEXIST_OBJS:= btcoexist/halbtc8192e2ant.o\ + btcoexist/halbtc8723b1ant.o\ + btcoexist/halbtc8723b2ant.o\ + btcoexist/halbtcoutsrc.o\ + btcoexist/rtl_btc.o \ + +PCI_8821AE_HAL_OBJS:= \ + rtl8821ae/hw.o \ + rtl8821ae/table.o \ + rtl8821ae/sw.o \ + rtl8821ae/trx.o \ + rtl8821ae/led.o \ + rtl8821ae/fw.o \ + rtl8821ae/phy.o \ + rtl8821ae/rf.o \ + rtl8821ae/dm.o \ + rtl8821ae/pwrseq.o \ + rtl8821ae/pwrseqcmd.o \ + rtl8821ae/hal_btc.o \ + rtl8821ae/hal_bt_coexist.o \ + +rtl8821ae-objs += $(BT_COEXIST_OBJS) $(PCI_MAIN_OBJS) $(PCI_8821AE_HAL_OBJS) + +obj-$(CONFIG_R8821AE) += rtl8821ae.o --- linux-3.13.0.orig/drivers/staging/rtl8821ae/stats.h +++ linux-3.13.0/drivers/staging/rtl8821ae/stats.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_STATS_H__ +#define __RTL_STATS_H__ + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +/* Rx smooth factor */ +#define RX_SMOOTH_FACTOR 20 + +u8 rtl_query_rxpwrpercentage(char antpower); +u8 rtl_evm_db_to_percentage(char value); +long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig); +void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, + struct rtl_stats *pstatus); + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/base.h +++ linux-3.13.0/drivers/staging/rtl8821ae/base.h @@ -0,0 +1,159 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_BASE_H__ +#define __RTL_BASE_H__ + +#include "compat.h" + +enum ap_peer { + PEER_UNKNOWN = 0, + PEER_RTL = 1, + PEER_RTL_92SE = 2, + PEER_BROAD = 3, + PEER_RAL = 4, + PEER_ATH = 5, + PEER_CISCO = 6, + PEER_MARV = 7, + PEER_AIRGO = 9, + PEER_MAX = 10, +} ; + +#define RTL_DUMMY_OFFSET 0 +#define RTL_DUMMY_UNIT 8 +#define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT) +#define RTL_TX_DESC_SIZE 32 +#define RTL_TX_HEADER_SIZE (RTL_TX_DESC_SIZE + RTL_TX_DUMMY_SIZE) + +#define HT_AMSDU_SIZE_4K 3839 +#define HT_AMSDU_SIZE_8K 7935 + +#define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */ +#define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */ + +#define RTL_RATE_COUNT_LEGACY 12 +#define RTL_CHANNEL_COUNT 14 + +#define FRAME_OFFSET_FRAME_CONTROL 0 +#define FRAME_OFFSET_DURATION 2 +#define FRAME_OFFSET_ADDRESS1 4 +#define FRAME_OFFSET_ADDRESS2 10 +#define FRAME_OFFSET_ADDRESS3 16 +#define FRAME_OFFSET_SEQUENCE 22 +#define FRAME_OFFSET_ADDRESS4 24 + +#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \ + WRITEEF2BYTE(_hdr, _val) +#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \ + WRITEEF1BYTE(_hdr, _val) +#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val) +#define SET_80211_HDR_TO_DS(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val) + +#define SET_80211_PS_POLL_AID(_hdr, _val) \ + WRITEEF2BYTE(((u8*)(_hdr))+2, _val) +#define SET_80211_PS_POLL_BSSID(_hdr, _val) \ + CP_MACADDR(((u8*)(_hdr))+4, (u8*)(_val)) +#define SET_80211_PS_POLL_TA(_hdr, _val) \ + CP_MACADDR(((u8*)(_hdr))+10, (u8*)(_val)) + +#define SET_80211_HDR_DURATION(_hdr, _val) \ + WRITEEF2BYTE((u8*)(_hdr)+FRAME_OFFSET_DURATION, _val) +#define SET_80211_HDR_ADDRESS1(_hdr, _val) \ + CP_MACADDR((u8*)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val)) +#define SET_80211_HDR_ADDRESS2(_hdr, _val) \ + CP_MACADDR((u8*)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8*)(_val)) +#define SET_80211_HDR_ADDRESS3(_hdr, _val) \ + CP_MACADDR((u8*)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8*)(_val)) +#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \ + WRITEEF2BYTE((u8*)(_hdr)+FRAME_OFFSET_SEQUENCE, _val) + +#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \ + WRITEEF4BYTE(((u8*)(__phdr)) + 24, __val) +#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \ + WRITEEF4BYTE(((u8*)(__phdr)) + 28, __val) +#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \ + WRITEEF2BYTE(((u8*)(__phdr)) + 32, __val) +#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \ + READEF2BYTE(((u8*)(__phdr)) + 34) +#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + WRITEEF2BYTE(((u8*)(__phdr)) + 34, __val) +#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ + (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) + +int rtl_init_core(struct ieee80211_hw *hw); +void rtl_deinit_core(struct ieee80211_hw *hw); +void rtl_init_rx_config(struct ieee80211_hw *hw); +void rtl_init_rfkill(struct ieee80211_hw *hw); +void rtl_deinit_rfkill(struct ieee80211_hw *hw); + +void rtl_watch_dog_timer_callback(unsigned long data); +void rtl_deinit_deferred_work(struct ieee80211_hw *hw); + +bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); + +void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_watch_dog_timer_callback(unsigned long data); +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid, u16 * ssn); +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid); +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid); +int rtl_rx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid); +int rtl_rx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid); +void rtl_watchdog_wq_callback(void *data); +void rtl_fwevt_wq_callback(void *data); + +void rtl_get_tcb_desc(struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); + +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + enum ieee80211_smps_mode smps); +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); +extern struct attribute_group rtl_attribute_group; +void rtl_easy_concurrent_retrytimer_callback(unsigned long data); +extern struct rtl_global_var global_var; + +#ifdef VIF_TODO +struct ieee80211_vif *rtl_get_main_vif(struct ieee80211_hw *hw); +bool rtl_set_vif_info(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +#endif +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/Kconfig +++ linux-3.13.0/drivers/staging/rtl8821ae/Kconfig @@ -0,0 +1,11 @@ +config R8821AE + tristate "RealTek RTL8821AE Wireless LAN NIC driver" + depends on PCI && WLAN && MAC80211 + depends on m + select WIRELESS_EXT + select WEXT_PRIV + select EEPROM_93CX6 + select CRYPTO + default N + ---help--- + If built as a module, it will be called r8821ae.ko. --- linux-3.13.0.orig/drivers/staging/rtl8821ae/base.c +++ linux-3.13.0/drivers/staging/rtl8821ae/base.c @@ -0,0 +1,1873 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include +#include +#include "wifi.h" +#include "rc.h" +#include "base.h" +#include "efuse.h" +#include "cam.h" +#include "ps.h" +#include "regd.h" +#include "pci.h" + +/* + *NOTICE!!!: This file will be very big, we hsould + *keep it clear under follwing roles: + * + *This file include follwing part, so, if you add new + *functions into this file, please check which part it + *should includes. or check if you should add new part + *for this file: + * + *1) mac80211 init functions + *2) tx information functions + *3) functions called by core.c + *4) wq & timer callback functions + *5) frame process functions + *6) IOT functions + *7) sysfs functions + *8) vif functions + *9) ... + */ + +/********************************************************* + * + * mac80211 init functions + * + *********************************************************/ +static struct ieee80211_channel rtl_channeltable_2g[] = { + {.center_freq = 2412,.hw_value = 1,}, + {.center_freq = 2417,.hw_value = 2,}, + {.center_freq = 2422,.hw_value = 3,}, + {.center_freq = 2427,.hw_value = 4,}, + {.center_freq = 2432,.hw_value = 5,}, + {.center_freq = 2437,.hw_value = 6,}, + {.center_freq = 2442,.hw_value = 7,}, + {.center_freq = 2447,.hw_value = 8,}, + {.center_freq = 2452,.hw_value = 9,}, + {.center_freq = 2457,.hw_value = 10,}, + {.center_freq = 2462,.hw_value = 11,}, + {.center_freq = 2467,.hw_value = 12,}, + {.center_freq = 2472,.hw_value = 13,}, + {.center_freq = 2484,.hw_value = 14,}, +}; + +static struct ieee80211_channel rtl_channeltable_5g[] = { + {.center_freq = 5180,.hw_value = 36,}, + {.center_freq = 5200,.hw_value = 40,}, + {.center_freq = 5220,.hw_value = 44,}, + {.center_freq = 5240,.hw_value = 48,}, + {.center_freq = 5260,.hw_value = 52,}, + {.center_freq = 5280,.hw_value = 56,}, + {.center_freq = 5300,.hw_value = 60,}, + {.center_freq = 5320,.hw_value = 64,}, + {.center_freq = 5500,.hw_value = 100,}, + {.center_freq = 5520,.hw_value = 104,}, + {.center_freq = 5540,.hw_value = 108,}, + {.center_freq = 5560,.hw_value = 112,}, + {.center_freq = 5580,.hw_value = 116,}, + {.center_freq = 5600,.hw_value = 120,}, + {.center_freq = 5620,.hw_value = 124,}, + {.center_freq = 5640,.hw_value = 128,}, + {.center_freq = 5660,.hw_value = 132,}, + {.center_freq = 5680,.hw_value = 136,}, + {.center_freq = 5700,.hw_value = 140,}, + {.center_freq = 5745,.hw_value = 149,}, + {.center_freq = 5765,.hw_value = 153,}, + {.center_freq = 5785,.hw_value = 157,}, + {.center_freq = 5805,.hw_value = 161,}, + {.center_freq = 5825,.hw_value = 165,}, +}; + +static struct ieee80211_rate rtl_ratetable_2g[] = { + {.bitrate = 10,.hw_value = 0x00,}, + {.bitrate = 20,.hw_value = 0x01,}, + {.bitrate = 55,.hw_value = 0x02,}, + {.bitrate = 110,.hw_value = 0x03,}, + {.bitrate = 60,.hw_value = 0x04,}, + {.bitrate = 90,.hw_value = 0x05,}, + {.bitrate = 120,.hw_value = 0x06,}, + {.bitrate = 180,.hw_value = 0x07,}, + {.bitrate = 240,.hw_value = 0x08,}, + {.bitrate = 360,.hw_value = 0x09,}, + {.bitrate = 480,.hw_value = 0x0a,}, + {.bitrate = 540,.hw_value = 0x0b,}, +}; + +static struct ieee80211_rate rtl_ratetable_5g[] = { + {.bitrate = 60,.hw_value = 0x04,}, + {.bitrate = 90,.hw_value = 0x05,}, + {.bitrate = 120,.hw_value = 0x06,}, + {.bitrate = 180,.hw_value = 0x07,}, + {.bitrate = 240,.hw_value = 0x08,}, + {.bitrate = 360,.hw_value = 0x09,}, + {.bitrate = 480,.hw_value = 0x0a,}, + {.bitrate = 540,.hw_value = 0x0b,}, +}; + +static const struct ieee80211_supported_band rtl_band_2ghz = { + .band = IEEE80211_BAND_2GHZ, + + .channels = rtl_channeltable_2g, + .n_channels = ARRAY_SIZE(rtl_channeltable_2g), + + .bitrates = rtl_ratetable_2g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g), + + .ht_cap = {0}, +}; + +static struct ieee80211_supported_band rtl_band_5ghz = { + .band = IEEE80211_BAND_5GHZ, + + .channels = rtl_channeltable_5g, + .n_channels = ARRAY_SIZE(rtl_channeltable_5g), + + .bitrates = rtl_ratetable_5g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g), + + .ht_cap = {0}, +}; + +static const u8 tid_to_ac[] = { + 2, /* IEEE80211_AC_BE */ + 3, /* IEEE80211_AC_BK */ + 3, /* IEEE80211_AC_BK */ + 2, /* IEEE80211_AC_BE */ + 1, /* IEEE80211_AC_VI */ + 1, /* IEEE80211_AC_VI */ + 0, /* IEEE80211_AC_VO */ + 0, /* IEEE80211_AC_VO */ +}; + +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid) +{ + return tid_to_ac[tid]; +} + +static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_sta_ht_cap *ht_cap) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + ht_cap->ht_supported = true; + ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + + if (rtlpriv->rtlhal.disable_amsdu_8k) + ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + + /* + *Maximum length of AMPDU that the STA can receive. + *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) + */ + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + + /*Minimum MPDU start spacing , */ + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + /* + *hw->wiphy->bands[IEEE80211_BAND_2GHZ] + *base on ant_num + *rx_mask: RX mask + *if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7 + *if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15 + *if rx_ant >=3 rx_mask[2]=0xff; + *if BW_40 rx_mask[4]=0x01; + *highest supported RX rate + */ + if (rtlpriv->dm.supp_phymode_switch) { + RT_TRACE(COMP_INIT, DBG_EMERG, ("Support phy mode switch\n")); + + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0xFF; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15; + } else { + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_2T2R) { + + RT_TRACE(COMP_INIT, DBG_DMESG, ("1T2R or 2T2R\n")); + + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0xFF; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15; + } else if (get_rf_type(rtlphy) == RF_1T1R) { + + RT_TRACE(COMP_INIT, DBG_DMESG, ("1T1R\n")); + + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0x00; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS7; + } + } +} + +static void _rtl_init_mac80211(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct ieee80211_supported_band *sband; + + + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && + rtlhal->bandset == BAND_ON_BOTH) { + /* 1: 2.4 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + + /* 2: 5 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), + &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), + &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + RT_TRACE(COMP_INIT, DBG_EMERG, ("Err BAND %d\n", + rtlhal->current_bandtype)); + } + } + /* <5> set hw caps */ + hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_RX_INCLUDES_FCS | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) + IEEE80211_HW_BEACON_FILTER | +#endif + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_CONNECTION_MONITOR | + /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */ + IEEE80211_HW_MFP_CAPABLE | 0; + + /* swlps or hwlps has been set in diff chip in init_sw_vars */ + if (rtlpriv->psc.b_swctrl_lps) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + 0; +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); +#else +/**/ + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT) ; +/**/ +#endif +/**/ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,39)) + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) + hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; +#endif + + hw->wiphy->rts_threshold = 2347; + + hw->queues = AC_MAX; + hw->extra_tx_headroom = RTL_TX_HEADER_SIZE; + + /* TODO: Correct this value for our hw */ + /* TODO: define these hard code value */ + hw->max_listen_interval = 10; + hw->max_rate_tries = 4; + /* hw->max_rates = 1; */ + hw->sta_data_size = sizeof(struct rtl_sta_info); +#ifdef VIF_TODO + hw->vif_data_size = sizeof(struct rtl_vif_info); +#endif + + /* <6> mac address */ + if (is_valid_ether_addr(rtlefuse->dev_addr)) { + SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr); + } else { + u8 rtlmac[] = { 0x00, 0xe0, 0x4c, 0x81, 0x92, 0x00 }; + get_random_bytes((rtlmac + (ETH_ALEN - 1)), 1); + SET_IEEE80211_PERM_ADDR(hw, rtlmac); + } + +} + +static void _rtl_init_deferred_work(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* <1> timer */ + init_timer(&rtlpriv->works.watchdog_timer); + setup_timer(&rtlpriv->works.watchdog_timer, + rtl_watch_dog_timer_callback, (unsigned long)hw); + init_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer); + setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer, + rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw); + /* <2> work queue */ + rtlpriv->works.hw = hw; +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) +/**/ + rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0); +/**/ +#else + rtlpriv->works.rtl_wq = create_workqueue(rtlpriv->cfg->name); +#endif +/**/ + INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, + (void *)rtl_watchdog_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, + (void *)rtl_ips_nic_off_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_work, + (void *)rtl_swlps_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, + (void *)rtl_swlps_rfon_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq, + (void *)rtl_fwevt_wq_callback); + +} + +void rtl_deinit_deferred_work(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + del_timer_sync(&rtlpriv->works.watchdog_timer); + + cancel_delayed_work(&rtlpriv->works.watchdog_wq); + cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + cancel_delayed_work(&rtlpriv->works.fwevt_wq); +} + +void rtl_init_rfkill(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + bool radio_state; + bool blocked; + u8 valid = 0; + + /*set init state to on */ + rtlpriv->rfkill.rfkill_state = 1; + wiphy_rfkill_set_hw_state(hw->wiphy, 0); + + radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + + if (valid) { + printk(KERN_INFO "rtlwifi: wireless switch is %s\n", + rtlpriv->rfkill.rfkill_state ? "on" : "off"); + + rtlpriv->rfkill.rfkill_state = radio_state; + + blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); + } + + wiphy_rfkill_start_polling(hw->wiphy); +} + +void rtl_deinit_rfkill(struct ieee80211_hw *hw) +{ + wiphy_rfkill_stop_polling(hw->wiphy); +} + +#ifdef VIF_TODO +static void rtl_init_vif(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + INIT_LIST_HEAD(&rtlpriv->vif_priv.vif_list); + + rtlpriv->vif_priv.vifs = 0; +} +#endif + +int rtl_init_core(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + + /* <1> init mac80211 */ + _rtl_init_mac80211(hw); + rtlmac->hw = hw; + rtlmac->link_state = MAC80211_NOLINK; + + /* <2> rate control register */ + hw->rate_control_algorithm = "rtl_rc"; + + /* + * <3> init CRDA must come after init + * mac80211 hw in _rtl_init_mac80211. + */ + if (rtl_regd_init(hw, rtl_reg_notifier)) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("REGD init failed\n")); + return 1; + } + + /* <4> locks */ + mutex_init(&rtlpriv->locks.conf_mutex); + spin_lock_init(&rtlpriv->locks.ips_lock); + spin_lock_init(&rtlpriv->locks.irq_th_lock); + spin_lock_init(&rtlpriv->locks.h2c_lock); + spin_lock_init(&rtlpriv->locks.rf_ps_lock); + spin_lock_init(&rtlpriv->locks.rf_lock); + spin_lock_init(&rtlpriv->locks.lps_lock); + spin_lock_init(&rtlpriv->locks.waitq_lock); + spin_lock_init(&rtlpriv->locks.entry_list_lock); + spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); + spin_lock_init(&rtlpriv->locks.check_sendpkt_lock); + spin_lock_init(&rtlpriv->locks.fw_ps_lock); + spin_lock_init(&rtlpriv->locks.iqk_lock); + /* <5> init list */ + INIT_LIST_HEAD(&rtlpriv->entry_list); + + /* <6> init deferred work */ + _rtl_init_deferred_work(hw); + + /* <7> */ +#ifdef VIF_TODO + rtl_init_vif(hw); +#endif + + return 0; +} + +void rtl_deinit_core(struct ieee80211_hw *hw) +{ +} + +void rtl_init_rx_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); +} + +/********************************************************* + * + * tx information functions + * + *********************************************************/ +static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw, + struct rtl_tcb_desc *tcb_desc, + struct ieee80211_tx_info *info) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 rate_flag = info->control.rates[0].flags; + + tcb_desc->use_shortpreamble = false; + + /* 1M can only use Long Preamble. 11B spec */ + if (tcb_desc->hw_rate == rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]) + return; + else if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + tcb_desc->use_shortpreamble = true; + + return; +} + +static void _rtl_query_shortgi(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc, + struct ieee80211_tx_info *info) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 rate_flag = info->control.rates[0].flags; + u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; + tcb_desc->use_shortgi = false; + + if (sta == NULL) + return; + + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + + if (!(sta->ht_cap.ht_supported)) + return; + + if (!sgi_40 && !sgi_20) + return; + + if (mac->opmode == NL80211_IFTYPE_STATION) + bw_40 = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if ((bw_40 == true) && sgi_40) + tcb_desc->use_shortgi = true; + else if ((bw_40 == false) && sgi_20) + tcb_desc->use_shortgi = true; + + if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) + tcb_desc->use_shortgi = false; +} + +static void _rtl_query_protection_mode(struct ieee80211_hw *hw, + struct rtl_tcb_desc *tcb_desc, + struct ieee80211_tx_info *info) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 rate_flag = info->control.rates[0].flags; + + /* Common Settings */ + tcb_desc->b_rts_stbc = false; + tcb_desc->b_cts_enable = false; + tcb_desc->rts_sc = 0; + tcb_desc->b_rts_bw = false; + tcb_desc->b_rts_use_shortpreamble = false; + tcb_desc->b_rts_use_shortgi = false; + + if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) { + /* Use CTS-to-SELF in protection mode. */ + tcb_desc->b_rts_enable = true; + tcb_desc->b_cts_enable = true; + tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; + } else if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { + /* Use RTS-CTS in protection mode. */ + tcb_desc->b_rts_enable = true; + tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; + } +} + +static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u8 ratr_index = 7; + + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + ratr_index = sta_entry->ratr_index; + } + if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) { + if (mac->opmode == NL80211_IFTYPE_STATION) { + tcb_desc->ratr_index = 0; + } else if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + if (tcb_desc->b_multicast || tcb_desc->b_broadcast) { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; + tcb_desc->use_driver_rate = 1; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; + } else { + tcb_desc->ratr_index = ratr_index; + } + } else if (mac->opmode == NL80211_IFTYPE_AP) { + tcb_desc->ratr_index = ratr_index; + } + } + + if (rtlpriv->dm.b_useramask) { + tcb_desc->ratr_index = ratr_index; + /* TODO we will differentiate adhoc and station futrue */ + if (mac->opmode == NL80211_IFTYPE_STATION || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + tcb_desc->mac_id = 0; + + if (mac->mode == WIRELESS_MODE_N_24G) { + tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; + } else if (mac->mode == WIRELESS_MODE_N_5G) { + tcb_desc->ratr_index = RATR_INX_WIRELESS_NG; + } else if (mac->mode & WIRELESS_MODE_G) { + tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; + } else if (mac->mode & WIRELESS_MODE_B) { + tcb_desc->ratr_index = RATR_INX_WIRELESS_B; + } else if (mac->mode & WIRELESS_MODE_A) { + tcb_desc->ratr_index = RATR_INX_WIRELESS_G; + } + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (NULL != sta) { + if (sta->aid > 0) { + tcb_desc->mac_id = sta->aid + 1; + } else { + tcb_desc->mac_id = 1; + } + } else { + tcb_desc->mac_id = 0; + } + } + } +} + +static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + tcb_desc->b_packet_bw = false; + if (!sta) + return; + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + if (!(sta->ht_cap.ht_supported) || + !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + return; + } else if (mac->opmode == NL80211_IFTYPE_STATION) { + if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) + return; + } + if (tcb_desc->b_multicast || tcb_desc->b_broadcast) + return; + + /*use legency rate, shall use 20MHz */ + if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]) + return; + + tcb_desc->b_packet_bw = true; +} + +static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 hw_rate; + + if ((get_rf_type(rtlphy) == RF_2T2R) && (sta->ht_cap.mcs.rx_mask[1]!=0)) + hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]; + else + hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7]; + + return hw_rate; +} + +void rtl_get_tcb_desc(struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + struct ieee80211_rate *txrate; + u16 fc = rtl_get_fc(skb); + + txrate = ieee80211_get_tx_rate(hw, info); + if (txrate != NULL) + tcb_desc->hw_rate = txrate->hw_value; + + if (ieee80211_is_data(fc)) { + /* + *we set data rate INX 0 + *in rtl_rc.c if skb is special data or + *mgt which need low data rate. + */ + + /* + *So tcb_desc->hw_rate is just used for + *special data and mgt frames + */ + if (info->control.rates[0].idx == 0 || + ieee80211_is_nullfunc(fc)) { + tcb_desc->use_driver_rate = true; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; + + tcb_desc->disable_ratefallback = 1; + } else { + /* + *because hw will nerver use hw_rate + *when tcb_desc->use_driver_rate = false + *so we never set highest N rate here, + *and N rate will all be controled by FW + *when tcb_desc->use_driver_rate = false + */ + if (sta && (sta->ht_cap.ht_supported)) { + tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw, sta); + } else { + if(rtlmac->mode == WIRELESS_MODE_B) { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; + } else { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; + } + } + } + + if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) + tcb_desc->b_multicast = 1; + else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + tcb_desc->b_broadcast = 1; + + _rtl_txrate_selectmode(hw, sta, tcb_desc); + _rtl_query_bandwidth_mode(hw, sta, tcb_desc); + _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); + _rtl_query_shortgi(hw, sta, tcb_desc, info); + _rtl_query_protection_mode(hw, tcb_desc, info); + } else { + tcb_desc->use_driver_rate = true; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; + tcb_desc->disable_ratefallback = 1; + tcb_desc->mac_id = 0; + tcb_desc->b_packet_bw = false; + } +} +//EXPORT_SYMBOL(rtl_get_tcb_desc); + +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 fc = rtl_get_fc(skb); + + if (rtlpriv->dm.supp_phymode_switch && + mac->link_state < MAC80211_LINKED && + (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) { + if (rtlpriv->cfg->ops->check_switch_to_dmdp) + rtlpriv->cfg->ops->check_switch_to_dmdp(hw); + } + if (ieee80211_is_auth(fc)) { + RT_TRACE(COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); + rtl_ips_nic_on(hw); + + mac->link_state = MAC80211_LINKING; + /* Dul mac */ + rtlpriv->phy.b_need_iqk = true; + + } + + return true; +} + +struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, u8 *sa, + u8 *bssid, u16 tid); +bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 fc = rtl_get_fc(skb); + u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN)); + u8 category; + + if (!ieee80211_is_action(fc)) + return true; + + category = *act; + act++; + switch (category) { + case ACT_CAT_BA: + switch (*act) { + case ACT_ADDBAREQ: + if (mac->act_scanning) + return false; + + RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, + ("%s ACT_ADDBAREQ From :%pM\n", + is_tx ? "Tx" : "Rx", hdr->addr2)); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("req \n"), + skb->data, skb->len); + if (!is_tx) { + struct ieee80211_sta *sta = NULL; + struct rtl_sta_info *sta_entry = NULL; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u16 capab = 0, tid = 0; + struct rtl_tid_data *tid_data; + struct sk_buff *skb_delba = NULL; + struct ieee80211_rx_status rx_status = { 0 }; + + rcu_read_lock(); + sta = rtl_find_sta(hw, hdr->addr3); + if (sta == NULL) { + RT_TRACE((COMP_SEND | COMP_RECV), + DBG_EMERG, ("sta is NULL\n")); + rcu_read_unlock(); + return true; + } + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) { + rcu_read_unlock(); + return true; + } + capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + tid_data = &sta_entry->tids[tid]; + if (tid_data->agg.rx_agg_state == + RTL_RX_AGG_START) { + skb_delba = rtl_make_del_ba(hw, + hdr->addr2, + hdr->addr3, + tid); + if (skb_delba) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + rx_status.freq = hw->conf.chandef.chan->center_freq; + rx_status.band = hw->conf.chandef.chan->band; +#else + rx_status.freq = hw->conf.channel->center_freq; + rx_status.band = hw->conf.channel->band; +#endif + rx_status.flag |= RX_FLAG_DECRYPTED; + rx_status.flag |= RX_FLAG_MACTIME_MPDU; + rx_status.rate_idx = 0; + rx_status.signal = 50 + 10; + memcpy(IEEE80211_SKB_RXCB(skb_delba), &rx_status, + sizeof(rx_status)); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, + ("fake del\n"), skb_delba->data, + skb_delba->len); + ieee80211_rx_irqsafe(hw, skb_delba); + } + } + rcu_read_unlock(); + } + break; + case ACT_ADDBARSP: + RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, + ("%s ACT_ADDBARSP From :%pM\n", + is_tx ? "Tx" : "Rx", hdr->addr2)); + break; + case ACT_DELBA: + RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, + ("ACT_ADDBADEL From :%pM\n", hdr->addr2)); + break; + } + break; + default: + break; + } + + return true; +} + +/*should call before software enc*/ +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u16 fc = rtl_get_fc(skb); + u16 ether_type; + u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); + const struct iphdr *ip; + + if (!ieee80211_is_data(fc)) + goto end; + + + ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + + SNAP_SIZE + PROTOC_TYPE_SIZE); + ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); + ether_type = ntohs(ether_type); + + if (ETH_P_IP == ether_type) { + if (IPPROTO_UDP == ip->protocol) { + struct udphdr *udp = (struct udphdr *)((u8 *) ip + + (ip->ihl << 2)); + if (((((u8 *) udp)[1] == 68) && + (((u8 *) udp)[3] == 67)) || + ((((u8 *) udp)[1] == 67) && + (((u8 *) udp)[3] == 68))) { + /* + * 68 : UDP BOOTP client + * 67 : UDP BOOTP server + */ + RT_TRACE((COMP_SEND | COMP_RECV), + DBG_DMESG, ("dhcp %s !!\n", + (is_tx) ? "Tx" : "Rx")); + + if (is_tx) { + rtlpriv->ra.is_special_data = true; + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = + jiffies; + } + + return true; + } + } + } else if (ETH_P_ARP == ether_type) { + if (is_tx) { + rtlpriv->ra.is_special_data = true; + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + + return true; + } else if (ETH_P_PAE == ether_type) { + RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, + ("802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx")); + + if (is_tx) { + rtlpriv->ra.is_special_data = true; + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + + return true; + } else if (0x86DD == ether_type) { + return true; + } + +end: + rtlpriv->ra.is_special_data = false; + return false; +} + +/********************************************************* + * + * functions called by core.c + * + *********************************************************/ +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) + return -ENXIO; + tid_data = &sta_entry->tids[tid]; + + RT_TRACE(COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number)); + + *ssn = tid_data->seq_number; + tid_data->agg.agg_state = RTL_AGG_START; + + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + return 0; +} + +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n")); + return -EINVAL; + } + + RT_TRACE(COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; + + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + return 0; +} + +int rtl_rx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) + return -ENXIO; + tid_data = &sta_entry->tids[tid]; + + RT_TRACE(COMP_RECV, DBG_DMESG, + ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number)); + + tid_data->agg.rx_agg_state = RTL_RX_AGG_START; + return 0; +} + +int rtl_rx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n")); + return -EINVAL; + } + + RT_TRACE(COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP; + + return 0; +} +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n")); + return -EINVAL; + } + + RT_TRACE(COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; + + return 0; +} + +/********************************************************* + * + * wq & timer callback functions + * + *********************************************************/ +/* this function is used for roaming */ +void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + return; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control) && + !ieee80211_is_probe_resp(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (skb->len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->link_info.bcn_rx_inperiod ++; +} + +void rtl_watchdog_wq_callback(void *data) +{ + struct rtl_works *rtlworks = container_of_dwork_rtl(data, + struct rtl_works, + watchdog_wq); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + bool b_busytraffic = false; + bool b_tx_busy_traffic = false; + bool b_rx_busy_traffic = false; + bool b_higher_busytraffic = false; + bool b_higher_busyrxtraffic = false; + u8 idx, tid; + u32 rx_cnt_inp4eriod = 0; + u32 tx_cnt_inp4eriod = 0; + u32 aver_rx_cnt_inperiod = 0; + u32 aver_tx_cnt_inperiod = 0; + u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; + u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; + bool benter_ps = false; + + if (is_hal_stop(rtlhal)) + return; + + /* <1> Determine if action frame is allowed */ + if (mac->link_state > MAC80211_NOLINK) { + if (mac->cnt_after_linked < 20) + mac->cnt_after_linked++; + } else { + mac->cnt_after_linked = 0; + } + + /* <2> to check if traffic busy, if + * busytraffic we don't change channel */ + if (mac->link_state >= MAC80211_LINKED) { + + /* (1) get aver_rx_cnt_inperiod & aver_tx_cnt_inperiod */ + for (idx = 0; idx <= 2; idx++) { + rtlpriv->link_info.num_rx_in4period[idx] = + rtlpriv->link_info.num_rx_in4period[idx + 1]; + rtlpriv->link_info.num_tx_in4period[idx] = + rtlpriv->link_info.num_tx_in4period[idx + 1]; + } + rtlpriv->link_info.num_rx_in4period[3] = + rtlpriv->link_info.num_rx_inperiod; + rtlpriv->link_info.num_tx_in4period[3] = + rtlpriv->link_info.num_tx_inperiod; + for (idx = 0; idx <= 3; idx++) { + rx_cnt_inp4eriod += + rtlpriv->link_info.num_rx_in4period[idx]; + tx_cnt_inp4eriod += + rtlpriv->link_info.num_tx_in4period[idx]; + } + aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4; + aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4; + + /* (2) check traffic busy */ + if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) { + b_busytraffic = true; + if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod) + b_rx_busy_traffic = true; + else + b_tx_busy_traffic = false; + } + + /* Higher Tx/Rx data. */ + if (aver_rx_cnt_inperiod > 4000 || + aver_tx_cnt_inperiod > 4000) { + b_higher_busytraffic = true; + + /* Extremely high Rx data. */ + if (aver_rx_cnt_inperiod > 5000) + b_higher_busyrxtraffic = true; + } + + /* check every tid's tx traffic */ + for (tid = 0; tid <= 7; tid++) { + for (idx = 0; idx <= 2; idx++) + rtlpriv->link_info.tidtx_in4period[tid][idx] = + rtlpriv->link_info.tidtx_in4period[tid] + [idx + 1]; + rtlpriv->link_info.tidtx_in4period[tid][3] = + rtlpriv->link_info.tidtx_inperiod[tid]; + + for (idx = 0; idx <= 3; idx++) + tidtx_inp4eriod[tid] += + rtlpriv->link_info.tidtx_in4period[tid][idx]; + aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; + if (aver_tidtx_inperiod[tid] > 5000) + rtlpriv->link_info.higher_busytxtraffic[tid] = + true; + else + rtlpriv->link_info.higher_busytxtraffic[tid] = + false; + } + + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) + benter_ps = false; + else + benter_ps = true; + + /* LeisurePS only work in infra mode. */ + if (benter_ps) + rtl_lps_enter(hw); + else + rtl_lps_leave(hw); + } + + rtlpriv->link_info.num_rx_inperiod = 0; + rtlpriv->link_info.num_tx_inperiod = 0; + for (tid = 0; tid <= 7; tid++) + rtlpriv->link_info.tidtx_inperiod[tid] = 0; + + rtlpriv->link_info.b_busytraffic = b_busytraffic; + rtlpriv->link_info.b_rx_busy_traffic = b_rx_busy_traffic; + rtlpriv->link_info.b_tx_busy_traffic = b_tx_busy_traffic; + rtlpriv->link_info.b_higher_busytraffic = b_higher_busytraffic; + rtlpriv->link_info.b_higher_busyrxtraffic = b_higher_busyrxtraffic; + + /* <3> DM */ + rtlpriv->cfg->ops->dm_watchdog(hw); + + /* <4> roaming */ + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { + if ((rtlpriv->link_info.bcn_rx_inperiod + + rtlpriv->link_info.num_rx_inperiod) == 0) { + rtlpriv->link_info.roam_times++; + RT_TRACE(COMP_ERR, DBG_DMESG, ("AP off for %d s\n", + (rtlpriv->link_info.roam_times * 2))); + + /* if we can't recv beacon for 10s, + * we should reconnect this AP */ + if (rtlpriv->link_info.roam_times >= 5) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("AP off, try to reconnect now\n")); + rtlpriv->link_info.roam_times = 0; + ieee80211_connection_loss(rtlpriv->mac80211.vif); + } + } else { + rtlpriv->link_info.roam_times = 0; + } + } + rtlpriv->link_info.bcn_rx_inperiod = 0; +} + +void rtl_watch_dog_timer_callback(unsigned long data) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.watchdog_wq, 0); + + mod_timer(&rtlpriv->works.watchdog_timer, + jiffies + MSECS(RTL_WATCH_DOG_TIME)); +} +void rtl_fwevt_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, fwevt_wq); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->c2h_command_handle(hw); +} +void rtl_easy_concurrent_retrytimer_callback(unsigned long data) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_priv *buddy_priv = rtlpriv->buddy_priv; + + if(buddy_priv == NULL) + return; + + rtlpriv->cfg->ops->dualmac_easy_concurrent(hw); +} +/********************************************************* + * + * frame process functions + * + *********************************************************/ +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + return NULL; +} + +/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ +/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ +struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, + enum ieee80211_smps_mode smps, + u8 *da, u8 *bssid) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct sk_buff *skb; + struct ieee80211_mgmt_compat *action_frame; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(27 + hw->extra_tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, hw->extra_tx_headroom); + action_frame = (void *)skb_put(skb, 27); + memset(action_frame, 0, 27); + memcpy(action_frame->da, da, ETH_ALEN); + memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_HT; + action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC:/* 0 */ + case IEEE80211_SMPS_NUM_MODES:/* 4 */ + WARN_ON(1); + case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */ + break; + case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */ + break; + case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */ + break; + } + + return skb; +} + +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + enum ieee80211_smps_mode smps) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct sk_buff *skb = NULL; + struct rtl_tcb_desc tcb_desc; + u8 bssid[ETH_ALEN] = {0}; + + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (rtlpriv->mac80211.act_scanning) + goto err_free; + + if (!sta) + goto err_free; + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) + memcpy(bssid, rtlpriv->efuse.dev_addr, ETH_ALEN); + else + memcpy(bssid, rtlpriv->mac80211.bssid, ETH_ALEN); + + skb = rtl_make_smps_action(hw, smps, sta->addr, bssid); + /* this is a type = mgmt * stype = action frame */ + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_sta_info *sta_entry = + (struct rtl_sta_info *) sta->drv_priv; + sta_entry->mimo_ps = smps; + /* rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); */ + + info->control.rates[0].idx = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + info->band = hw->conf.chandef.chan->band; +#else + info->band = hw->conf.channel->band; +#endif +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + info->control.sta = sta; + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); +#else +/**/ + rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc); +/**/ +#endif +/**/ + } + return 1; + +err_free: + return 0; +} +//EXPORT_SYMBOL(rtl_send_smps_action); + +/* because mac80211 have issues when can receive del ba + * so here we just make a fake del_ba if we receive a ba_req + * but rx_agg was opened to let mac80211 release some ba + * related resources, so please this del_ba for tx */ +struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, + u8 *sa, u8 *bssid, u16 tid) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct sk_buff *skb; + struct ieee80211_mgmt *action_frame; + u16 params; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(34 + hw->extra_tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, hw->extra_tx_headroom); + action_frame = (void *)skb_put(skb, 34); + memset(action_frame, 0, 34); + memcpy(action_frame->sa, sa, ETH_ALEN); + memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_BACK; + action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA; + params = (u16)(1 << 11); /* bit 11 initiator */ + params |= (u16)(tid << 12); /* bit 15:12 TID number */ + + action_frame->u.action.u.delba.params = cpu_to_le16(params); + action_frame->u.action.u.delba.reason_code = + cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); + + return skb; +} + +/********************************************************* + * + * IOT functions + * + *********************************************************/ +static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, + struct octet_string vendor_ie) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool matched = false; + static u8 athcap_1[] = { 0x00, 0x03, 0x7F }; + static u8 athcap_2[] = { 0x00, 0x13, 0x74 }; + static u8 broadcap_1[] = { 0x00, 0x10, 0x18 }; + static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 }; + static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 }; + static u8 racap[] = { 0x00, 0x0c, 0x43 }; + static u8 ciscocap[] = { 0x00, 0x40, 0x96 }; + static u8 marvcap[] = { 0x00, 0x50, 0x43 }; + + if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 || + memcmp(vendor_ie.octet, athcap_2, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_ATH; + matched = true; + } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_2, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_3, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_BROAD; + matched = true; + } else if (memcmp(vendor_ie.octet, racap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_RAL; + matched = true; + } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_CISCO; + matched = true; + } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_MARV; + matched = true; + } + + return matched; +} + +bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, + unsigned int len) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + struct octet_string vendor_ie; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos[0] == 221) { + vendor_ie.length = pos[1]; + vendor_ie.octet = &pos[2]; + if (rtl_chk_vendor_ouisub(hw, vendor_ie)) + return true; + } + + if (pos + 2 + pos[1] > end) + return false; + + pos += 2 + pos[1]; + } + return false; +} + +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *)data; + u32 vendor = PEER_UNKNOWN; + + static u8 ap3_1[3] = { 0x00, 0x14, 0xbf }; + static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 }; + static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e }; + static u8 ap4_1[3] = { 0x00, 0x90, 0xcc }; + static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e }; + static u8 ap4_3[3] = { 0x00, 0x18, 0x02 }; + static u8 ap4_4[3] = { 0x00, 0x17, 0x3f }; + static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf }; + static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 }; + static u8 ap5_2[3] = { 0x00, 0x21, 0x91 }; + static u8 ap5_3[3] = { 0x00, 0x24, 0x01 }; + static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 }; + static u8 ap5_5[3] = { 0x00, 0x17, 0x9A }; + static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 }; + static u8 ap6_1[3] = { 0x00, 0x17, 0x94 }; + static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 }; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (mac->link_state == MAC80211_NOLINK) { + mac->vendor = PEER_UNKNOWN; + return; + } + + if (mac->cnt_after_linked > 2) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + if (rtl_find_221_ie(hw, data, len)) { + vendor = mac->vendor; + } + + if ((memcmp(mac->bssid, ap5_1, 3) == 0) || + (memcmp(mac->bssid, ap5_2, 3) == 0) || + (memcmp(mac->bssid, ap5_3, 3) == 0) || + (memcmp(mac->bssid, ap5_4, 3) == 0) || + (memcmp(mac->bssid, ap5_5, 3) == 0) || + (memcmp(mac->bssid, ap5_6, 3) == 0) || + vendor == PEER_ATH) { + vendor = PEER_ATH; + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ath find\n")); + } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) || + (memcmp(mac->bssid, ap4_5, 3) == 0) || + (memcmp(mac->bssid, ap4_1, 3) == 0) || + (memcmp(mac->bssid, ap4_2, 3) == 0) || + (memcmp(mac->bssid, ap4_3, 3) == 0) || + vendor == PEER_RAL) { + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ral findn\n")); + vendor = PEER_RAL; + } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || + vendor == PEER_CISCO) { + vendor = PEER_CISCO; + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>cisco find\n")); + } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) || + (memcmp(mac->bssid, ap3_2, 3) == 0) || + (memcmp(mac->bssid, ap3_3, 3) == 0) || + vendor == PEER_BROAD) { + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>broad find\n")); + vendor = PEER_BROAD; + } else if (memcmp(mac->bssid, ap7_1, 3) == 0 || + vendor == PEER_MARV) { + vendor = PEER_MARV; + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>marv find\n")); + } + + mac->vendor = vendor; +} + +/********************************************************* + * + * sysfs functions + * + *********************************************************/ +static ssize_t rtl_show_debug_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ieee80211_hw *hw = dev_get_drvdata(d); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return sprintf(buf, "0x%08X\n", rtlpriv->dbg.global_debuglevel); +} + +static ssize_t rtl_store_debug_level(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ieee80211_hw *hw = dev_get_drvdata(d); + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 0, &val); + if (ret) { + printk(KERN_DEBUG "%s is not in hex or decimal form.\n", buf); + } else { + rtlpriv->dbg.global_debuglevel = val; + printk(KERN_DEBUG "debuglevel:%x\n", + rtlpriv->dbg.global_debuglevel); + } + + return strnlen(buf, count); +} + +static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, + rtl_show_debug_level, rtl_store_debug_level); + +static struct attribute *rtl_sysfs_entries[] = { + + &dev_attr_debug_level.attr, + + NULL +}; + +/* + * "name" is folder name witch will be + * put in device directory like : + * sys/devices/pci0000:00/0000:00:1c.4/ + * 0000:06:00.0/rtl_sysfs + */ +struct attribute_group rtl_attribute_group = { + .name = "rtlsysfs", + .attrs = rtl_sysfs_entries, +}; + +#ifdef VIF_TODO +/********************************************************* + * + * vif functions + * + *********************************************************/ +static inline struct ieee80211_vif * +rtl_get_vif(struct rtl_vif_info *vif_priv) +{ + return container_of((void *)vif_priv, struct ieee80211_vif, drv_priv); +} + +/* Protected by ar->mutex or RCU */ +struct ieee80211_vif *rtl_get_main_vif(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_vif_info *cvif; + + list_for_each_entry_rcu(cvif, &rtlpriv->vif_priv.vif_list, list) { + if (cvif->active) + return rtl_get_vif(cvif); + } + + return NULL; +} + +static inline bool is_main_vif(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + bool ret; + + rcu_read_lock(); + ret = (rtl_get_main_vif(hw) == vif); + rcu_read_unlock(); + return ret; +} + +bool rtl_set_vif_info(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct rtl_vif_info *vif_info = (void *) vif->drv_priv; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int vif_id = -1; + + if (rtlpriv->vif_priv.vifs >= MAX_VIRTUAL_MAC) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("vif number can not bigger than %d, now vifs is:%d\n", + MAX_VIRTUAL_MAC, rtlpriv->vif_priv.vifs)); + return false; + } + + rcu_read_lock(); + vif_id = bitmap_find_free_region(&rtlpriv->vif_priv.vif_bitmap, + MAX_VIRTUAL_MAC, 0); + RT_TRACE(COMP_MAC80211, DBG_DMESG, + ("%s vid_id:%d\n", __func__, vif_id)); + + if (vif_id < 0) { + rcu_read_unlock(); + return false; + } + + BUG_ON(rtlpriv->vif_priv.vif[vif_id].id != vif_id); + vif_info->active = true; + vif_info->id = vif_id; + vif_info->enable_beacon = false; + rtlpriv->vif_priv.vifs++; + if (rtlpriv->vif_priv.vifs > 1) { + rtlpriv->psc.b_inactiveps = false; + rtlpriv->psc.b_swctrl_lps = false; + rtlpriv->psc.b_fwctrl_lps = false; + } + + list_add_tail_rcu(&vif_info->list, &rtlpriv->vif_priv.vif_list); + rcu_assign_pointer(rtlpriv->vif_priv.vif[vif_id].vif, vif); + + RT_TRACE(COMP_MAC80211, DBG_DMESG, ("vifaddress:%p %p %p\n", + rtlpriv->vif_priv.vif[vif_id].vif, vif, rtl_get_main_vif(hw))); + + rcu_read_unlock(); + + return true; +} +#endif + + +#if 0 +MODULE_AUTHOR("lizhaoming "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_AUTHOR("Larry Finger "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); +#endif +struct rtl_global_var global_var = {}; + +int rtl_core_module_init(void) +{ + if (rtl_rate_control_register()) + printk(KERN_DEBUG "rtl: Unable to register rtl_rc," + "use default RC !!\n"); + + /* add proc for debug */ + rtl_proc_add_topdir(); + + /* init some global vars */ + INIT_LIST_HEAD(&global_var.glb_priv_list); + spin_lock_init(&global_var.glb_list_lock); + + return 0; +} + +void rtl_core_module_exit(void) +{ + /*RC*/ + rtl_rate_control_unregister(); + + /* add proc for debug */ + rtl_proc_remove_topdir(); +} + +#if 0 +module_init(rtl_core_module_init); +module_exit(rtl_core_module_exit); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/ps.c +++ linux-3.13.0/drivers/staging/rtl8821ae/ps.c @@ -0,0 +1,1025 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "wifi.h" +#include "base.h" +#include "ps.h" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +#include +#endif +#include "btcoexist/rtl_btc.h" + +bool rtl_ps_enable_nic(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool init_status = true; + + /*<1> reset trx ring */ + if (rtlhal->interface == INTF_PCI) + rtlpriv->intf_ops->reset_trx_ring(hw); + + if (is_hal_stop(rtlhal)) + RT_TRACE(COMP_ERR, DBG_WARNING, ("Driver is already down!\n")); + + /*<2> Enable Adapter */ + rtlpriv->cfg->ops->hw_init(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + /*init_status = false; */ + + /*<3> Enable Interrupt */ + rtlpriv->cfg->ops->enable_interrupt(hw); + + /* */ + rtl_watch_dog_timer_callback((unsigned long)hw); + + return init_status; +} +//EXPORT_SYMBOL(rtl_ps_enable_nic); + +bool rtl_ps_disable_nic(struct ieee80211_hw *hw) +{ + bool status = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /*<1> Stop all timer */ + rtl_deinit_deferred_work(hw); + + /*<2> Disable Interrupt */ + rtlpriv->cfg->ops->disable_interrupt(hw); + + /*<3> Disable Adapter */ + rtlpriv->cfg->ops->hw_disable(hw); + + return status; +} +//EXPORT_SYMBOL(rtl_ps_disable_nic); + +bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, + enum rf_pwrstate state_toset, + u32 changesource, bool protect_or_not) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum rf_pwrstate rtstate; + bool b_actionallowed = false; + u16 rfwait_cnt = 0; + + /*protect_or_not = true; */ + + if (protect_or_not) + goto no_protect; + + /* + *Only one thread can change + *the RF state at one time, and others + *should wait to be executed. + */ + while (true) { + spin_lock(&rtlpriv->locks.rf_ps_lock); + if (ppsc->rfchange_inprogress) { + spin_unlock(&rtlpriv->locks.rf_ps_lock); + + RT_TRACE(COMP_ERR, DBG_WARNING, + ("RF Change in progress!" + "Wait to set..state_toset(%d).\n", + state_toset)); + + /* Set RF after the previous action is done. */ + while (ppsc->rfchange_inprogress) { + rfwait_cnt++; + mdelay(1); + /* + *Wait too long, return false to avoid + *to be stuck here. + */ + if (rfwait_cnt > 100) + return false; + } + } else { + ppsc->rfchange_inprogress = true; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + break; + } + } + +no_protect: + rtstate = ppsc->rfpwr_state; + + switch (state_toset) { + case ERFON: + ppsc->rfoff_reason &= (~changesource); + + if ((changesource == RF_CHANGE_BY_HW) && + (ppsc->b_hwradiooff == true)) { + ppsc->b_hwradiooff = false; + } + + if (!ppsc->rfoff_reason) { + ppsc->rfoff_reason = 0; + b_actionallowed = true; + } + + break; + + case ERFOFF: + + if ((changesource == RF_CHANGE_BY_HW) && + (ppsc->b_hwradiooff == false)) { + ppsc->b_hwradiooff = true; + } + + ppsc->rfoff_reason |= changesource; + b_actionallowed = true; + break; + + case ERFSLEEP: + ppsc->rfoff_reason |= changesource; + b_actionallowed = true; + break; + + default: + RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not process \n")); + break; + } + + if (b_actionallowed) + rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); + + if (!protect_or_not) { + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + } + + return b_actionallowed; +} +//EXPORT_SYMBOL(rtl_ps_set_rf_state); + +static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + ppsc->b_swrf_processing = true; + + if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { + if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && + rtlhal->interface == INTF_PCI) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + } + + if (rtlpriv->cfg->ops->get_btc_status()){ + rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv, + ppsc->inactive_pwrstate); + } + rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, + RF_CHANGE_BY_IPS, false); + + if (ppsc->inactive_pwrstate == ERFOFF && + rtlhal->interface == INTF_PCI) { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + } + + ppsc->b_swrf_processing = false; +} + +void rtl_ips_nic_off_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum rf_pwrstate rtstate; + + if (mac->opmode != NL80211_IFTYPE_STATION) { + RT_TRACE(COMP_ERR, DBG_WARNING, ("not station return\n")); + return; + } + + if (mac->p2p_in_use) + return; + + if (mac->link_state > MAC80211_NOLINK) + return; + + if (is_hal_stop(rtlhal)) + return; + + if (rtlpriv->sec.being_setkey) + return; + + if(rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps) + rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps(hw); + + if (ppsc->b_inactiveps) { + rtstate = ppsc->rfpwr_state; + + /* + *Do not enter IPS in the following conditions: + *(1) RF is already OFF or Sleep + *(2) b_swrf_processing (indicates the IPS is still under going) + *(3) Connectted (only disconnected can trigger IPS) + *(4) IBSS (send Beacon) + *(5) AP mode (send Beacon) + *(6) monitor mode (rcv packet) + */ + + if (rtstate == ERFON && + !ppsc->b_swrf_processing && + (mac->link_state == MAC80211_NOLINK) && + !mac->act_scanning) { + RT_TRACE(COMP_RF, DBG_LOUD, + ("IPSEnter(): Turn off RF.\n")); + + ppsc->inactive_pwrstate = ERFOFF; + ppsc->b_in_powersavemode = true; + + /*rtl_pci_reset_trx_ring(hw); */ + _rtl_ps_inactive_ps(hw); + } + } +} + +void rtl_ips_nic_off(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* + *because when link with ap, mac80211 will ask us + *to disable nic quickly after scan before linking, + *this will cause link failed, so we delay 100ms here + */ + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ips_nic_off_wq, MSECS(100)); +} + +/* NOTICE: any opmode should exc nic_on, or disable without + * nic_on may something wrong, like adhoc TP*/ +void rtl_ips_nic_on(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum rf_pwrstate rtstate; + + cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + + spin_lock(&rtlpriv->locks.ips_lock); + if (ppsc->b_inactiveps) { + rtstate = ppsc->rfpwr_state; + + if (rtstate != ERFON && + !ppsc->b_swrf_processing && + ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { + + ppsc->inactive_pwrstate = ERFON; + ppsc->b_in_powersavemode = false; + _rtl_ps_inactive_ps(hw); + } + } + spin_unlock(&rtlpriv->locks.ips_lock); +} + +/*for FW LPS*/ + +/* + *Determine if we can set Fw into PS mode + *in current condition.Return true if it + *can enter PS mode. + */ +static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u32 ps_timediff; + + ps_timediff = jiffies_to_msecs(jiffies - + ppsc->last_delaylps_stamp_jiffies); + + if (ps_timediff < 2000) { + RT_TRACE(COMP_POWER, DBG_LOUD, + ("Delay enter Fw LPS for DHCP, ARP," + " or EAPOL exchanging state.\n")); + return false; + } + + if (mac->link_state != MAC80211_LINKED) + return false; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + return false; + + return true; +} + +/* Change current and default preamble mode.*/ +void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool enter_fwlps; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + return; + + if (mac->link_state != MAC80211_LINKED) + return; + + if (ppsc->dot11_psmode == rt_psmode) + return; + + /* Update power save mode configured. */ + ppsc->dot11_psmode = rt_psmode; + + /* + * + *1. Enter PS mode + * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode + * cmd to set Fw into PS mode. + *2. Leave PS mode + * Send H2C fw_pwrmode cmd to Fw to set Fw into Active + * mode and set RPWM to turn RF on. + */ + + if ((ppsc->b_fwctrl_lps) && ppsc->report_linked) { + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(COMP_RF, DBG_DMESG, + ("FW LPS leave ps_mode:%x\n", + FW_PS_ACTIVE_MODE)); + enter_fwlps = false; + ppsc->pwr_mode = FW_PS_ACTIVE_MODE; + ppsc->smart_ps = 0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION, + (u8 *)(&enter_fwlps)); + if (ppsc->p2p_ps_info.opp_ps) + rtl_p2p_ps_cmd(hw,P2P_PS_ENABLE); + + } else { + if (rtl_get_fwlps_doze(hw)) { + RT_TRACE(COMP_RF, DBG_DMESG, + ("FW LPS enter ps_mode:%x\n", + ppsc->fwctrl_psmode)); + enter_fwlps = true; + ppsc->pwr_mode = ppsc->fwctrl_psmode; + ppsc->smart_ps = 2; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_FW_LPS_ACTION, + (u8 *)(&enter_fwlps)); + + } else { + /* Reset the power save related parameters. */ + ppsc->dot11_psmode = EACTIVE; + } + } + } +} + +/*Enter the leisure power save mode.*/ +void rtl_lps_enter(struct ieee80211_hw *hw) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long flag; + + if (!ppsc->b_fwctrl_lps) + return; + + if (rtlpriv->sec.being_setkey) + return; + + if (rtlpriv->link_info.b_busytraffic) + return; + + /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ + if (mac->cnt_after_linked < 5) + return; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + return; + + if (mac->link_state != MAC80211_LINKED) + return; + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + + /* Idle for a while if we connect to AP a while ago. */ + if (mac->cnt_after_linked >= 2) { + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(COMP_POWER, DBG_LOUD, + ("Enter 802.11 power save mode...\n")); + + rtl_lps_set_psmode(hw, EAUTOPS); + } + } + + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} + +/*Leave the leisure power save mode.*/ +void rtl_lps_leave(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flag; + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + + if (ppsc->b_fwctrl_lps) { + if (ppsc->dot11_psmode != EACTIVE) { + + /*FIX ME */ + rtlpriv->cfg->ops->enable_interrupt(hw); + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && + rtlhal->interface == INTF_PCI) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + RT_TRACE(COMP_POWER, DBG_LOUD, + ("Busy Traffic,Leave 802.11 power save..\n")); + + rtl_lps_set_psmode(hw, EACTIVE); + } + } + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} + +/* For sw LPS*/ +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *) data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool u_buffed; + bool m_buffed; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (!rtlpriv->psc.b_swctrl_lps) + return; + + if (rtlpriv->mac80211.link_state != MAC80211_LINKED) + return; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if (rtlpriv->psc.b_fwctrl_lps) + return; + + if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->psc.last_beacon = jiffies; + + tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) +/**/ + if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) + rtlpriv->psc.dtim_counter = tim_ie->dtim_count; +/**/ +#else + if (!WARN_ON_ONCE(!mac->vif->bss_conf.dtim_period)) + rtlpriv->psc.dtim_counter = tim_ie->dtim_count; +#endif +/**/ + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + u_buffed = ieee80211_check_tim(tim_ie, tim_len, + rtlpriv->mac80211.assoc_id); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + m_buffed = tim_ie->bitmap_ctrl & 0x01; + rtlpriv->psc.multi_buffered = m_buffed; + + /* unicast will process by mac80211 through + * set ~IEEE80211_CONF_PS, So we just check + * multicast frames here */ + if (!m_buffed ) {//&&) {// !rtlpriv->psc.tx_doing) { + /* back to low-power land. and delay is + * prevent null power save frame tx fail */ + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, MSECS(5)); + } else { + RT_TRACE(COMP_POWER, DBG_DMESG, + ("u_bufferd: %x, m_buffered: %x\n", + u_buffed, m_buffed)); + } +} + +void rtl_swlps_rf_awake(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flag; + + if (!rtlpriv->psc.b_swctrl_lps) + return; + if (mac->link_state != MAC80211_LINKED) + return; + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} + +void rtl_swlps_rfon_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_swlps_rf_awake(hw); +} + +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + unsigned long flag; + u8 sleep_intv; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if ((rtlpriv->sec.being_setkey) || + (mac->opmode == NL80211_IFTYPE_ADHOC)) + return; + + /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ + if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) + return; + + if (rtlpriv->link_info.b_busytraffic) + return; + + spin_lock(&rtlpriv->locks.rf_ps_lock); + if (rtlpriv->psc.rfchange_inprogress) { + spin_unlock(&rtlpriv->locks.rf_ps_lock); + return; + } + spin_unlock(&rtlpriv->locks.rf_ps_lock); + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS,false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + /* here is power save alg, when this beacon is DTIM + * we will set sleep time to dtim_period * n; + * when this beacon is not DTIM, we will set sleep + * time to sleep_intv = rtlpriv->psc.dtim_counter or + * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ + +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) +/**/ + if (rtlpriv->psc.dtim_counter == 0) { + if (hw->conf.ps_dtim_period == 1) + sleep_intv = hw->conf.ps_dtim_period * 2; + else + sleep_intv = hw->conf.ps_dtim_period; + } else { + sleep_intv = rtlpriv->psc.dtim_counter; + } +/**/ +#else + if (rtlpriv->psc.dtim_counter == 0) { + if (mac->vif->bss_conf.dtim_period == 1) + sleep_intv = mac->vif->bss_conf.dtim_period * 2; + else + sleep_intv = mac->vif->bss_conf.dtim_period; + } else { + sleep_intv = rtlpriv->psc.dtim_counter; + } +#endif +/**/ + + if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) + sleep_intv = MAX_SW_LPS_SLEEP_INTV; + + /* this print should always be dtim_conter = 0 & + * sleep = dtim_period, that meaons, we should + * awake before every dtim */ + RT_TRACE(COMP_POWER, DBG_DMESG, + ("dtim_counter:%x will sleep :%d beacon_intv\n", + rtlpriv->psc.dtim_counter, sleep_intv)); + + /* we tested that 40ms is enough for sw & hw sw delay */ + queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, + MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); +} + + +void rtl_swlps_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ps_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool ps = false; + + ps = (hw->conf.flags & IEEE80211_CONF_PS); + + /* we can sleep after ps null send ok */ + if (rtlpriv->psc.state_inap) { + rtl_swlps_rf_sleep(hw); + + if (rtlpriv->psc.state && !ps) { + rtlpriv->psc.sleep_ms = + jiffies_to_msecs(jiffies - + rtlpriv->psc.last_action); + } + + if (ps) + rtlpriv->psc.last_slept = jiffies; + + rtlpriv->psc.last_action = jiffies; + rtlpriv->psc.state = ps; + } +} + + +void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_mgmt *mgmt = (void *)data; + struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); + u8 *pos, *end, *ie; + u16 noa_len; + static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; + u8 noa_num, index,i, noa_index = 0; + bool find_p2p_ie = false , find_p2p_ps_ie = false; + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + ie = NULL; + + while (pos + 1 < end) { + + if (pos + 2 + pos[1] > end) + return; + + if (pos[0] == 221 && pos[1] > 4) { + if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) { + ie = pos + 2+4; + break; + } + } + pos += 2 + pos[1]; + } + + if (ie == NULL) + return; + find_p2p_ie = true; + /*to find noa ie*/ + while (ie + 1 < end) { + noa_len = READEF2BYTE(&ie[1]); + if (ie + 3 + ie[1] > end) + return; + + if (ie[0] == 12) { + find_p2p_ps_ie = true; + if ( (noa_len - 2) % 13 != 0){ + RT_TRACE(COMP_INIT, DBG_LOUD, + ("P2P notice of absence: " + "invalid length.%d\n",noa_len)); + return; + } else { + noa_num = (noa_len - 2) / 13; + } + noa_index = ie[3]; + if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == P2P_PS_NONE + || noa_index != p2pinfo->noa_index) { + RT_TRACE(COMP_FW, DBG_LOUD, + ("update NOA ie.\n")); + p2pinfo->noa_index = noa_index; + p2pinfo->opp_ps= (ie[4] >> 7); + p2pinfo->ctwindow = ie[4] & 0x7F; + p2pinfo->noa_num = noa_num; + index = 5; + for (i = 0; i< noa_num; i++){ + p2pinfo->noa_count_type[i] = + READEF1BYTE(ie+index); + index += 1; + p2pinfo->noa_duration[i] = + READEF4BYTE(ie+index); + index += 4; + p2pinfo->noa_interval[i] = + READEF4BYTE(ie+index); + index += 4; + p2pinfo->noa_start_time[i] = + READEF4BYTE(ie+index); + index += 4; + } + + if (p2pinfo->opp_ps == 1) { + p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; + /* Driver should wait LPS + * entering CTWindow*/ + if (rtlpriv->psc.b_fw_current_inpsmode){ + rtl_p2p_ps_cmd(hw, + P2P_PS_ENABLE); + } + } else if (p2pinfo->noa_num > 0) { + p2pinfo->p2p_ps_mode = P2P_PS_NOA; + rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); + } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + } + } + + break; + } + ie += 3 + noa_len; + } + + if (find_p2p_ie == true) { + if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) && + (find_p2p_ps_ie == false)) + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + } +} + +void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_mgmt *mgmt = (void *)data; + struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); + bool find_p2p_ie = false , find_p2p_ps_ie = false; + u8 noa_num, index,i, noa_index = 0; + u8 *pos, *end, *ie; + u16 noa_len; + static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; + + pos = (u8 *) &mgmt->u.action.category; + end = data + len; + ie = NULL; + + if (pos[0] == 0x7f ) { + if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0) { + ie = pos + 3+4; + } + } + + if (ie == NULL) + return; + find_p2p_ie = true; + + RT_TRACE(COMP_FW, DBG_LOUD, ("action frame find P2P IE.\n")); + /*to find noa ie*/ + while (ie + 1 < end) { + noa_len = READEF2BYTE(&ie[1]); + if (ie + 3 + ie[1] > end) + return; + + if (ie[0] == 12) { + RT_TRACE(COMP_FW, DBG_LOUD, ("find NOA IE.\n")); + RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, ("noa ie "), + ie, noa_len); + find_p2p_ps_ie = true; + if ( (noa_len - 2) % 13 != 0){ + RT_TRACE(COMP_FW, DBG_LOUD, + ("P2P notice of absence: " + "invalid length.%d\n",noa_len)); + return; + } else { + noa_num = (noa_len - 2) / 13; + } + noa_index = ie[3]; + if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == P2P_PS_NONE + || noa_index != p2pinfo->noa_index) { + p2pinfo->noa_index = noa_index; + p2pinfo->opp_ps= (ie[4] >> 7); + p2pinfo->ctwindow = ie[4] & 0x7F; + p2pinfo->noa_num = noa_num; + index = 5; + for (i = 0; i< noa_num; i++){ + p2pinfo->noa_count_type[i] = + READEF1BYTE(ie+index); + index += 1; + p2pinfo->noa_duration[i] = + READEF4BYTE(ie+index); + index += 4; + p2pinfo->noa_interval[i] = + READEF4BYTE(ie+index); + index += 4; + p2pinfo->noa_start_time[i] = + READEF4BYTE(ie+index); + index += 4; + } + + if (p2pinfo->opp_ps == 1) { + p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; + /* Driver should wait LPS + * entering CTWindow */ + if (rtlpriv->psc.b_fw_current_inpsmode){ + rtl_p2p_ps_cmd(hw, + P2P_PS_ENABLE); + } + } else if (p2pinfo->noa_num > 0) { + p2pinfo->p2p_ps_mode = P2P_PS_NOA; + rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); + } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + } + } + + break; + } + ie += 3 + noa_len; + } + + +} + + +void rtl_p2p_ps_cmd(struct ieee80211_hw *hw,u8 p2p_ps_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); + struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); + + RT_TRACE(COMP_FW, DBG_LOUD, (" p2p state %x\n",p2p_ps_state)); + switch (p2p_ps_state) { + case P2P_PS_DISABLE: + p2pinfo->p2p_ps_state = p2p_ps_state; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + (u8 *)(&p2p_ps_state)); + + p2pinfo->noa_index = 0; + p2pinfo->ctwindow = 0; + p2pinfo->opp_ps = 0; + p2pinfo->noa_num = 0; + p2pinfo->p2p_ps_mode = P2P_PS_NONE; + if (rtlps->b_fw_current_inpsmode == true) { + if (rtlps->smart_ps == 0) { + rtlps->smart_ps = 2; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&rtlps->pwr_mode)); + } + + } + break; + case P2P_PS_ENABLE: + if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + p2pinfo->p2p_ps_state = p2p_ps_state; + + if (p2pinfo->ctwindow > 0) { + if (rtlps->smart_ps != 0){ + rtlps->smart_ps = 0; + rtlpriv->cfg->ops->set_hw_reg( + hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&rtlps->pwr_mode)); + } + } + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + (u8 *)(&p2p_ps_state)); + + } + break; + case P2P_PS_SCAN: + case P2P_PS_SCAN_DONE: + case P2P_PS_ALLSTASLEEP: + if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { + p2pinfo->p2p_ps_state = p2p_ps_state; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + (u8 *)(&p2p_ps_state)); + } + break; + default: + break; + + } + RT_TRACE(COMP_FW, DBG_LOUD, (" ctwindow %x oppps %x \n", + p2pinfo->ctwindow,p2pinfo->opp_ps)); + RT_TRACE(COMP_FW, DBG_LOUD, ("count %x duration %x index %x interval %x" + " start time %x noa num %x\n", + p2pinfo->noa_count_type[0], + p2pinfo->noa_duration[0], + p2pinfo->noa_index, + p2pinfo->noa_interval[0], + p2pinfo->noa_start_time[0], + p2pinfo->noa_num)); + RT_TRACE(COMP_FW, DBG_LOUD, ("end\n")); +} + +void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *) data; + + if (!mac->p2p) + return; + if (mac->link_state != MAC80211_LINKED) + return; + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + /* check if this really is a beacon */ + if (!(ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_action(hdr->frame_control))) + return; + + if (ieee80211_is_action(hdr->frame_control)) { + rtl_p2p_action_ie(hw,data,len - FCS_LEN); + } else { + rtl_p2p_noa_ie(hw,data,len - FCS_LEN); + } + +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rc.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rc.c @@ -0,0 +1,309 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "wifi.h" +#include "base.h" +#include "rc.h" + +/* + *Finds the highest rate index we can use + *if skb is special data like DHCP/EAPOL, we set should + *it to lowest rate CCK_1M, otherwise we set rate to + *highest rate based on wireless mode used for iwconfig + *show Tx rate. + */ +static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, + struct sk_buff *skb, bool not_data) +{ + struct rtl_mac *rtlmac = rtl_mac(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_sta_info *sta_entry = NULL; + u8 wireless_mode = 0; + + /* + *this rate is no use for true rate, firmware + *will control rate at all it just used for + *1.show in iwconfig in B/G mode + *2.in rtl_get_tcb_desc when we check rate is + * 1M we will not use FW rate but user rate. + */ + if (rtlmac->opmode == NL80211_IFTYPE_AP || + rtlmac->opmode == NL80211_IFTYPE_ADHOC || + rtlmac->opmode == NL80211_IFTYPE_MESH_POINT) { + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wireless_mode = sta_entry->wireless_mode; + } else { + return 0; + } + } else { + wireless_mode = rtlmac->mode; + } + + if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || not_data) { + return 0; + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (wireless_mode == WIRELESS_MODE_B) { + return B_MODE_MAX_RIX; + } else if (wireless_mode == WIRELESS_MODE_G) { + return G_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } else { + if (wireless_mode == WIRELESS_MODE_A) { + return A_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } + } +} + +static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, + struct ieee80211_tx_rate *rate, + struct ieee80211_tx_rate_control *txrc, + u8 tries, char rix, int rtsctsenable, + bool not_data) +{ + struct rtl_mac *mac = rtl_mac(rtlpriv); + u8 sgi_20 = 0, sgi_40 = 0; + + if (sta) { + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + } + rate->count = tries; + rate->idx = rix >= 0x00 ? rix : 0x00; + + if (!not_data) { + if (txrc->short_preamble) + rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta && (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } else { + if (mac->bw_40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } + if (sgi_20 || sgi_40) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + if (sta && sta->ht_cap.ht_supported) + rate->flags |= IEEE80211_TX_RC_MCS; + } +} + +static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc) +{ + struct rtl_priv *rtlpriv = ppriv; + struct sk_buff *skb = txrc->skb; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->control.rates; + __le16 fc = rtl_get_fc(skb); + u8 try_per_rate, i, rix; + bool not_data = !ieee80211_is_data(fc); + + if (rate_control_send_low(sta, priv_sta, txrc)) + return; + + rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); + try_per_rate = 1; + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, + try_per_rate, rix, 1, not_data); + + if (!not_data) { + for (i = 1; i < 4; i++) + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], + txrc, i, (rix - i), 1, + not_data); + } +} + +static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, + struct rtl_sta_info *sta_entry, u16 tid) +{ + struct rtl_mac *mac = rtl_mac(rtlpriv); + + if (mac->act_scanning) + return false; + + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->cnt_after_linked < 3) + return false; + + if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) + return true; + + return false; +} + +/*mac80211 Rate Control callbacks*/ +static void rtl_tx_status(void *ppriv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = ppriv; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); + struct rtl_sta_info *sta_entry; + + if (!priv_sta || !ieee80211_is_data(fc)) + return; + + if (rtl_is_special_data(mac->hw, skb, true)) + return; + + if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + return; + + if (sta) { + /* Check if aggregation has to be enabled for this tid */ + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + if ((sta->ht_cap.ht_supported == true) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 tid = rtl_get_tid(skb); + if (_rtl_tx_aggr_check(rtlpriv, sta_entry, + tid)) { + sta_entry->tids[tid].agg.agg_state = + RTL_AGG_PROGRESS; + /**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) + /**/ + ieee80211_start_tx_ba_session(sta, tid, + 5000); + /**/ +#else + ieee80211_start_tx_ba_session(sta, tid); +#endif + /**/ + } + } + } + } +} + +static void rtl_rate_init(void *ppriv, + struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *priv_sta) +{ +} +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)) +static void rtl_rate_update(void *ppriv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed, + enum nl80211_channel_type oper_chan_type) +{ +} +#else +static void rtl_rate_update(void *ppriv, + struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed) +{ +} +#endif +static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + return rtlpriv; +} + +static void rtl_rate_free(void *rtlpriv) +{ + return; +} + +static void *rtl_rate_alloc_sta(void *ppriv, + struct ieee80211_sta *sta, gfp_t gfp) +{ + struct rtl_priv *rtlpriv = ppriv; + struct rtl_rate_priv *rate_priv; + + rate_priv = kzalloc(sizeof(struct rtl_rate_priv), gfp); + if (!rate_priv) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Unable to allocate private rc structure\n")); + return NULL; + } + + rtlpriv->rate_priv = rate_priv; + + return rate_priv; +} + +static void rtl_rate_free_sta(void *rtlpriv, + struct ieee80211_sta *sta, void *priv_sta) +{ + struct rtl_rate_priv *rate_priv = priv_sta; + kfree(rate_priv); +} + +static struct rate_control_ops rtl_rate_ops = { + .module = NULL, + .name = "rtl_rc", + .alloc = rtl_rate_alloc, + .free = rtl_rate_free, + .alloc_sta = rtl_rate_alloc_sta, + .free_sta = rtl_rate_free_sta, + .rate_init = rtl_rate_init, + .rate_update = rtl_rate_update, + .tx_status = rtl_tx_status, + .get_rate = rtl_get_rate, +}; + +int rtl_rate_control_register(void) +{ + return ieee80211_rate_control_register(&rtl_rate_ops); +} + +void rtl_rate_control_unregister(void) +{ + ieee80211_rate_control_unregister(&rtl_rate_ops); +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/compat.h +++ linux-3.13.0/drivers/staging/rtl8821ae/compat.h @@ -0,0 +1,125 @@ +#ifndef __RTL_COMPAT_H__ +#define __RTL_COMPAT_H__ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) +/* + * Use this if you want to use the same suspend and resume callbacks for suspend + * to RAM and hibernation. + */ +#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ +struct dev_pm_ops name = { \ + .suspend = suspend_fn, \ + .resume = resume_fn, \ + .freeze = suspend_fn, \ + .thaw = resume_fn, \ + .poweroff = suspend_fn, \ + .restore = resume_fn, \ +} + +#define compat_pci_suspend(fn) \ + int fn##_compat(struct pci_dev *pdev, pm_message_t state) \ + { \ + int r; \ + \ + r = fn(&pdev->dev); \ + if (r) \ + return r; \ + \ + pci_save_state(pdev); \ + pci_disable_device(pdev); \ + pci_set_power_state(pdev, PCI_D3hot); \ + \ + return 0; \ + } + +#define compat_pci_resume(fn) \ + int fn##_compat(struct pci_dev *pdev) \ + { \ + int r; \ + \ + pci_set_power_state(pdev, PCI_D0); \ + r = pci_enable_device(pdev); \ + if (r) \ + return r; \ + pci_restore_state(pdev); \ + \ + return fn(&pdev->dev); \ + } +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) +#define RX_FLAG_MACTIME_MPDU RX_FLAG_TSFT +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) +#define RX_FLAG_MACTIME_MPDU RX_FLAG_MACTIME_START +#else +#endif +//#define NETDEV_TX_OK +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)) +#define IEEE80211_KEY_FLAG_SW_MGMT IEEE80211_KEY_FLAG_SW_MGMT_TX +#endif + +struct ieee80211_mgmt_compat { + __le16 frame_control; + __le16 duration; + u8 da[6]; + u8 sa[6]; + u8 bssid[6]; + __le16 seq_ctrl; + union { + struct { + u8 category; + union { + struct { + u8 action_code; + u8 dialog_token; + u8 status_code; + u8 variable[0]; + } __attribute__ ((packed)) wme_action; + struct{ + u8 action_code; + u8 dialog_token; + __le16 capab; + __le16 timeout; + __le16 start_seq_num; + } __attribute__((packed)) addba_req; + struct{ + u8 action_code; + u8 dialog_token; + __le16 status; + __le16 capab; + __le16 timeout; + } __attribute__((packed)) addba_resp; + struct{ + u8 action_code; + __le16 params; + __le16 reason_code; + } __attribute__((packed)) delba; + struct{ + u8 action_code; + /* capab_info for open and confirm, + * reason for close + */ + __le16 aux; + /* Followed in plink_confirm by status + * code, AID and supported rates, + * and directly by supported rates in + * plink_open and plink_close + */ + u8 variable[0]; + } __attribute__((packed)) plink_action; + struct{ + u8 action_code; + u8 variable[0]; + } __attribute__((packed)) mesh_action; + struct { + u8 action; + u8 smps_control; + } __attribute__ ((packed)) ht_smps; + } u; + } __attribute__ ((packed)) action; + } u; +} __attribute__ ((packed)); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/debug.h +++ linux-3.13.0/drivers/staging/rtl8821ae/debug.h @@ -0,0 +1,227 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * Tmis program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Tme full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_DEBUG_H__ +#define __RTL_DEBUG_H__ + +/*-------------------------------------------------------------- + Debug level +--------------------------------------------------------------*/ +/* + *Fatal bug. + *For example, Tx/Rx/IO locked up, + *memory access violation, + *resource allocation failed, + *unexpected HW behavior, HW BUG + *and so on. + */ +#define DBG_EMERG 0 + +/* + *Abnormal, rare, or unexpeted cases. + *For example, Packet/IO Ctl canceled, + *device suprisely unremoved and so on. + */ +#define DBG_WARNING 2 + +/* + *Normal case driver developer should + *open, we can see link status like + *assoc/AddBA/DHCP/adapter start and + *so on basic and useful infromations. + */ +#define DBG_DMESG 3 + +/* + *Normal case with useful information + *about current SW or HW state. + *For example, Tx/Rx descriptor to fill, + *Tx/Rx descriptor completed status, + *SW protocol state change, dynamic + *mechanism state change and so on. + */ +#define DBG_LOUD 4 + +/* + *Normal case with detail execution + *flow or information. + */ +#define DBG_TRACE 5 + +/*-------------------------------------------------------------- + Define the rt_trace components +--------------------------------------------------------------*/ +#define COMP_ERR BIT(0) +#define COMP_FW BIT(1) +#define COMP_INIT BIT(2) /*For init/deinit */ +#define COMP_RECV BIT(3) /*For Rx. */ +#define COMP_SEND BIT(4) /*For Tx. */ +#define COMP_MLME BIT(5) /*For MLME. */ +#define COMP_SCAN BIT(6) /*For Scan. */ +#define COMP_INTR BIT(7) /*For interrupt Related. */ +#define COMP_LED BIT(8) /*For LED. */ +#define COMP_SEC BIT(9) /*For sec. */ +#define COMP_BEACON BIT(10) /*For beacon. */ +#define COMP_RATE BIT(11) /*For rate. */ +#define COMP_RXDESC BIT(12) /*For rx desc. */ +#define COMP_DIG BIT(13) /*For DIG */ +#define COMP_TXAGC BIT(14) /*For Tx power */ +#define COMP_HIPWR BIT(15) /*For High Power Mechanism */ +#define COMP_POWER BIT(16) /*For lps/ips/aspm. */ +#define COMP_POWER_TRACKING BIT(17) /*For TX POWER TRACKING */ +#define COMP_BB_POWERSAVING BIT(18) +#define COMP_SWAS BIT(19) /*For SW Antenna Switch */ +#define COMP_RF BIT(20) /*For RF. */ +#define COMP_TURBO BIT(21) /*For EDCA TURBO. */ +#define COMP_RATR BIT(22) +#define COMP_CMD BIT(23) +#define COMP_EFUSE BIT(24) +#define COMP_QOS BIT(25) +#define COMP_MAC80211 BIT(26) +#define COMP_REGD BIT(27) +#define COMP_CHAN BIT(28) +#define COMP_EASY_CONCURRENT BIT(29) +#define COMP_BT_COEXIST BIT(30) +#define COMP_IQK BIT(31) + +/*-------------------------------------------------------------- + Define the rt_print components +--------------------------------------------------------------*/ +/* Define EEPROM and EFUSE check module bit*/ +#define EEPROM_W BIT(0) +#define EFUSE_PG BIT(1) +#define EFUSE_READ_ALL BIT(2) + +/* Define init check for module bit*/ +#define INIT_EEPROM BIT(0) +#define INIT_TxPower BIT(1) +#define INIT_IQK BIT(2) +#define INIT_RF BIT(3) + +/* Define PHY-BB/RF/MAC check module bit */ +#define PHY_BBR BIT(0) +#define PHY_BBW BIT(1) +#define PHY_RFR BIT(2) +#define PHY_RFW BIT(3) +#define PHY_MACR BIT(4) +#define PHY_MACW BIT(5) +#define PHY_ALLR BIT(6) +#define PHY_ALLW BIT(7) +#define PHY_TXPWR BIT(8) +#define PHY_PWRDIFF BIT(9) + +/* Define Dynamic Mechanism check module bit --> FDM */ +#define WA_IOT BIT(0) +#define DM_PWDB BIT(1) +#define DM_MONITOR BIT(2) +#define DM_DIG BIT(3) +#define DM_EDCA_TURBO BIT(4) + +enum dbgp_flag_e { + FQOS = 0, + FTX = 1, + FRX = 2, + FSEC = 3, + FMGNT = 4, + FMLME = 5, + FRESOURCE = 6, + FBEACON = 7, + FISR = 8, + FPHY = 9, + FMP = 10, + FEEPROM = 11, + FPWR = 12, + FDM = 13, + FDBGCtrl = 14, + FC2H = 15, + FBT = 16, + FINIT = 17, + FIOCTL = 18, + DBGP_TYPE_MAX +}; + +#define RT_ASSERT(_exp,fmt) \ + do { \ + if(!(_exp)) { \ + printk(KERN_DEBUG "%s:%s(): ", KBUILD_MODNAME, \ + __func__); \ + printk fmt; \ + } \ + } while(0); + +#define RT_DISP(dbgtype, dbgflag, printstr) + +#define RT_TRACE(comp, level, fmt)\ + do { \ + if(unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \ + ((level) <= rtlpriv->dbg.global_debuglevel))) {\ + printk(KERN_DEBUG "%s-%d:%s():<%lx-%x> ", \ + KBUILD_MODNAME, \ + rtlpriv->rtlhal.interfaceindex, __func__, \ + in_interrupt(), in_atomic()); \ + printk fmt; \ + }\ + } while(0); + +#define RTPRINT(rtlpriv, dbgtype, dbgflag, printstr) \ + do { \ + if (unlikely(rtlpriv->dbg.dbgp_type[dbgtype] & dbgflag)) { \ + printk(KERN_DEBUG "%s: ", KBUILD_MODNAME); \ + printk printstr; \ + } \ + } while(0); + +#define RT_PRINT_DATA(rtlpriv, _comp, _level, _titlestring, _hexdata, \ + _hexdatalen) \ + do {\ + if(unlikely(((_comp) & rtlpriv->dbg.global_debugcomponents ) &&\ + (_level <= rtlpriv->dbg.global_debuglevel ))) { \ + int __i; \ + u8* ptr = (u8*)_hexdata; \ + printk(KERN_DEBUG "%s: ", KBUILD_MODNAME); \ + printk(KERN_DEBUG "In process \"%s\" (pid %i):", \ + current->comm, \ + current->pid); \ + printk(_titlestring); \ + for( __i=0; __i<(int)_hexdatalen; __i++ ) { \ + printk("%02X%s", ptr[__i], (((__i + 1) % 4) \ + == 0)?" ":" ");\ + if (((__i + 1) % 16) == 0) \ + printk("\n"); \ + } \ + printk(KERN_DEBUG "\n"); \ + } \ + } while(0); + +void rtl_dbgp_flag_init(struct ieee80211_hw *hw); +void rtl_proc_add_one(struct ieee80211_hw *hw); +void rtl_proc_remove_one(struct ieee80211_hw *hw); +void rtl_proc_add_topdir(void); +void rtl_proc_remove_topdir(void); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/cam.c +++ linux-3.13.0/drivers/staging/rtl8821ae/cam.c @@ -0,0 +1,354 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#include "wifi.h" +#include "cam.h" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +#include +#endif + +void rtl_cam_reset_sec_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->sec.use_defaultkey = false; + rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION; + rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION; + memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN); + memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE); + rtlpriv->sec.pairwise_key = NULL; +} + +static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, + u8 *mac_addr, u8 *key_cont_128, u16 us_config) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + u32 target_command; + u32 target_content = 0; + u8 entry_i; + + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content :", + key_cont_128, 16); + + for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { + target_command = entry_i + CAM_CONTENT_COUNT * entry_no; + target_command = target_command | BIT(31) | BIT(16); + + if (entry_i == 0) { + target_content = (u32) (*(mac_addr + 0)) << 16 | + (u32) (*(mac_addr + 1)) << 24 | (u32) us_config; + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], + target_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + + RT_TRACE(COMP_SEC, DBG_LOUD, + ("WRITE %x: %x \n", + rtlpriv->cfg->maps[WCAMI], target_content)); + RT_TRACE(COMP_SEC, DBG_LOUD, + ("The Key ID is %d\n", entry_no)); + RT_TRACE(COMP_SEC, DBG_LOUD, + ("WRITE %x: %x \n", + rtlpriv->cfg->maps[RWCAM], target_command)); + + } else if (entry_i == 1) { + + target_content = (u32) (*(mac_addr + 5)) << 24 | + (u32) (*(mac_addr + 4)) << 16 | + (u32) (*(mac_addr + 3)) << 8 | + (u32) (*(mac_addr + 2)); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], + target_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + + RT_TRACE(COMP_SEC, DBG_LOUD, + ("WRITE A4: %x \n", target_content)); + RT_TRACE(COMP_SEC, DBG_LOUD, + ("WRITE A0: %x \n", target_command)); + + } else { + + target_content = + (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) << + 24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2)) + << 16 | + (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8 + | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0)); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], + target_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + udelay(100); + + RT_TRACE(COMP_SEC, DBG_LOUD, + ("WRITE A4: %x \n", target_content)); + RT_TRACE(COMP_SEC, DBG_LOUD, + ("WRITE A0: %x \n", target_command)); + } + } + + RT_TRACE(COMP_SEC, DBG_LOUD, + ("after set key, usconfig:%x\n", us_config)); +} + +u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, + u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg, + u32 ul_default_key, u8 *key_content) +{ + u32 us_config; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_SEC, DBG_DMESG, + ("EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, " + "ulUseDK=%x MacAddr %pM\n", + ul_entry_idx, ul_key_id, ul_enc_alg, + ul_default_key, mac_addr)); + + if (ul_key_id == TOTAL_CAM_ENTRY) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("ulKeyId exceed!\n")); + return 0; + } + + if (ul_default_key == 1) { + us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2); + } else { + us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id; + } + + rtl_cam_program_entry(hw, ul_entry_idx, mac_addr, + (u8 *) key_content, us_config); + + RT_TRACE(COMP_SEC, DBG_DMESG, ("end \n")); + + return 1; + +} +//EXPORT_SYMBOL(rtl_cam_add_one_entry); + +int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, + u8 *mac_addr, u32 ul_key_id) +{ + u32 ul_command; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_SEC, DBG_DMESG, ("key_idx:%d\n", ul_key_id)); + + ul_command = ul_key_id * CAM_CONTENT_COUNT; + ul_command = ul_command | BIT(31) | BIT(16); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + + RT_TRACE(COMP_SEC, DBG_DMESG, + ("rtl_cam_delete_one_entry(): WRITE A4: %x \n", 0)); + RT_TRACE(COMP_SEC, DBG_DMESG, + ("rtl_cam_delete_one_entry(): WRITE A0: %x \n", ul_command)); + + return 0; + +} +//EXPORT_SYMBOL(rtl_cam_delete_one_entry); + +void rtl_cam_reset_all_entry(struct ieee80211_hw *hw) +{ + u32 ul_command; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + ul_command = BIT(31) | BIT(30); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); +} +//EXPORT_SYMBOL(rtl_cam_reset_all_entry); + +void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + u32 ul_command; + u32 ul_content; + u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + + switch (rtlpriv->sec.pairwise_enc_algorithm) { + case WEP40_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; + break; + case WEP104_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; + break; + case TKIP_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; + break; + case AESCCMP_ENCRYPTION: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + break; + default: + ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + } + + ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2); + + ul_content |= BIT(15); + ul_command = CAM_CONTENT_COUNT * uc_index; + ul_command = ul_command | BIT(31) | BIT(16); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + + RT_TRACE(COMP_SEC, DBG_DMESG, + ("rtl_cam_mark_invalid(): WRITE A4: %x \n", ul_content)); + RT_TRACE(COMP_SEC, DBG_DMESG, + ("rtl_cam_mark_invalid(): WRITE A0: %x \n", ul_command)); +} +//EXPORT_SYMBOL(rtl_cam_mark_invalid); + +void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + u32 ul_command; + u32 ul_content; + u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; + u8 entry_i; + + switch (rtlpriv->sec.pairwise_enc_algorithm) { + case WEP40_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; + break; + case WEP104_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; + break; + case TKIP_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; + break; + case AESCCMP_ENCRYPTION: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; + break; + default: + ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; + } + + for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { + + if (entry_i == 0) { + ul_content = + (uc_index & 0x03) | ((u16) (ul_encalgo) << 2); + ul_content |= BIT(15); + + } else { + ul_content = 0; + } + + ul_command = CAM_CONTENT_COUNT * uc_index + entry_i; + ul_command = ul_command | BIT(31) | BIT(16); + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + + RT_TRACE(COMP_SEC, DBG_LOUD, + ("rtl_cam_empty_entry(): WRITE A4: %x \n", + ul_content)); + RT_TRACE(COMP_SEC, DBG_LOUD, + ("rtl_cam_empty_entry(): WRITE A0: %x \n", + ul_command)); + } + +} +//EXPORT_SYMBOL(rtl_cam_empty_entry); + +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; + u8 entry_idx = 0; + u8 i, *addr; + + if (NULL == sta_addr) { + RT_TRACE(COMP_SEC, DBG_EMERG, + ("sta_addr is NULL.\n")); + return TOTAL_CAM_ENTRY; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + if(memcmp(addr, sta_addr, ETH_ALEN) == 0) + return i; + } + /* Get a free CAM entry. */ + for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { + if ((bitmap & BIT(0)) == 0) { + RT_TRACE(COMP_SEC, DBG_EMERG, + ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", + rtlpriv->sec.hwsec_cam_bitmap, entry_idx)); + rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; + memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], + sta_addr, ETH_ALEN); + return entry_idx; + } + bitmap = bitmap >>1; + } + return TOTAL_CAM_ENTRY; +} +//EXPORT_SYMBOL(rtl_cam_get_free_entry); + +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap; + u8 i, *addr; + + if (NULL == sta_addr) { + RT_TRACE(COMP_SEC, DBG_EMERG, + ("sta_addr is NULL.\n")); + } + + if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\ + sta_addr[4]|sta_addr[5]) == 0) { + RT_TRACE(COMP_SEC, DBG_EMERG, + ("sta_addr is 00:00:00:00:00:00.\n")); + return; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; + if (((bitmap & BIT(0)) == BIT(0)) && + (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { + /* Remove from HW Security CAM */ + memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); + rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); + printk("&&&&&&&&&del entry %d\n",i); + } + } + return; +} +//EXPORT_SYMBOL(rtl_cam_del_entry); --- linux-3.13.0.orig/drivers/staging/rtl8821ae/debug.c +++ linux-3.13.0/drivers/staging/rtl8821ae/debug.c @@ -0,0 +1,988 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * Tmis program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Tme full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "wifi.h" +#include "cam.h" + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +#define GET_INODE_DATA(__node) PDE_DATA(__node) +#else +#define GET_INODE_DATA(__node) PDE(__node)->data +#endif + + +void rtl_dbgp_flag_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 i; + + rtlpriv->dbg.global_debuglevel = DBG_DMESG; + + rtlpriv->dbg.global_debugcomponents = + COMP_ERR | + COMP_FW | + COMP_INIT | + COMP_RECV | + COMP_SEND | + COMP_MLME | + COMP_SCAN | + COMP_INTR | + COMP_LED | + COMP_SEC | + COMP_BEACON | + COMP_RATE | + COMP_RXDESC | + COMP_DIG | + COMP_TXAGC | + COMP_POWER | + COMP_POWER_TRACKING | + COMP_BB_POWERSAVING | + COMP_SWAS | + COMP_RF | + COMP_TURBO | + COMP_RATR | + COMP_CMD | + COMP_EASY_CONCURRENT | + COMP_EFUSE | + COMP_QOS | COMP_MAC80211 | COMP_REGD | + COMP_CHAN | + COMP_BT_COEXIST | + COMP_IQK | + 0; + + for (i = 0; i < DBGP_TYPE_MAX; i++) + rtlpriv->dbg.dbgp_type[i] = 0; + + /*Init Debug flag enable condition */ +} + +struct proc_dir_entry *proc_topdir; +static int rtl_proc_get_mac_0(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x000; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_0(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_0, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_0 = { + .open = dl_proc_open_mac_0, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_mac_1(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x100; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_1(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_1, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_1 = { + .open = dl_proc_open_mac_1, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_mac_2(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x200; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_2(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_2, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_2 = { + .open = dl_proc_open_mac_2, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_mac_3(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x300; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_3(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_3, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_3 = { + .open = dl_proc_open_mac_3, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_mac_4(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x400; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_4(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_4, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_4 = { + .open = dl_proc_open_mac_4, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_mac_5(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x500; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_5(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_5, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_5 = { + .open = dl_proc_open_mac_5, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_mac_6(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x600; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_6(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_6, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_6 = { + .open = dl_proc_open_mac_6, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_mac_7(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i, n, page; + int max = 0xff; + page = 0x700; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_read_dword(rtlpriv, (page | n))); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_mac_7(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_mac_7, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_7 = { + .open = dl_proc_open_mac_7, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_8(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0x800; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_8(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_8, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_8 = { + .open = dl_proc_open_bb_8, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_9(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0x900; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_9(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_9, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_9 = { + .open = dl_proc_open_bb_9, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_a(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0xa00; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_a(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_a, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_a = { + .open = dl_proc_open_bb_a, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_b(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0xb00; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_b(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_b, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_b = { + .open = dl_proc_open_bb_b, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_c(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0xc00; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_c(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_c, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_c = { + .open = dl_proc_open_bb_c, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_d(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0xd00; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_d(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_d, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_d = { + .open = dl_proc_open_bb_d, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_e(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0xe00; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_e(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_e, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_e = { + .open = dl_proc_open_bb_e, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_bb_f(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n, page; + int max = 0xff; + page = 0xf00; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n + page); + for (i = 0; i < 4 && n <= max; i++, n += 4) + seq_printf(m, "%8.8x ", + rtl_get_bbreg(hw, (page | n), 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_bb_f(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_bb_f, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_f = { + .open = dl_proc_open_bb_f, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_reg_rf_a(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n; + int max = 0x40; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n); + for (i = 0; i < 4 && n <= max; n += 1, i++) + seq_printf(m, "%8.8x ", + rtl_get_rfreg(hw, RF90_PATH_A, n, 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_rf_a(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_reg_rf_a, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_rf_a = { + .open = dl_proc_open_rf_a, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_reg_rf_b(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + int i, n; + int max = 0x40; + + for (n = 0; n <= max; ) { + seq_printf(m, "\n%8.8x ", n); + for (i = 0; i < 4 && n <= max; n += 1, i++) + seq_printf(m, "%8.8x ", + rtl_get_rfreg(hw, RF90_PATH_B, n, + 0xffffffff)); + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_rf_b(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_reg_rf_b, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_rf_b = { + .open = dl_proc_open_rf_b, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_cam_register_1(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 target_cmd = 0; + u32 target_val=0; + u8 entry_i=0; + u32 ulstatus; + int i = 100, j = 0; + + /* This dump the current register page */ + seq_puts(m, + "\n#################### SECURITY CAM (0-10) ##################\n "); + + for (j = 0; j < 11; j++) { + seq_printf(m, "\nD: %2x > ", j); + for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { + /* polling bit, and No Write enable, and address */ + target_cmd = entry_i + CAM_CONTENT_COUNT * j; + target_cmd = target_cmd | BIT(31); + + /* Check polling bit is clear */ + while ((i--) >= 0) { + ulstatus = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[RWCAM]); + if (ulstatus & BIT(31)) { + continue; + } else { + break; + } + } + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_cmd); + target_val = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[RCAMO]); + seq_printf(m, "%8.8x ", target_val); + } + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_cam_1(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_cam_register_1, + GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_cam_1 = { + .open = dl_proc_open_cam_1, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_cam_register_2(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 target_cmd = 0; + u32 target_val = 0; + u8 entry_i = 0; + u32 ulstatus; + int i = 100, j = 0; + + /* This dump the current register page */ + seq_puts(m, + "\n################### SECURITY CAM (11-21) ##################\n "); + + for (j = 11; j < 22; j++) { + seq_printf(m, "\nD: %2x > ", j); + for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { + target_cmd = entry_i + CAM_CONTENT_COUNT * j; + target_cmd = target_cmd | BIT(31); + + while ((i--) >= 0) { + ulstatus = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[RWCAM]); + if (ulstatus & BIT(31)) { + continue; + } else { + break; + } + } + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_cmd); + target_val = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[RCAMO]); + seq_printf(m, "%8.8x ", target_val); + } + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_cam_2(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_cam_register_2, + GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_cam_2 = { + .open = dl_proc_open_cam_2, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int rtl_proc_get_cam_register_3(struct seq_file *m, void *v) +{ + struct ieee80211_hw *hw = m->private; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 target_cmd = 0; + u32 target_val = 0; + u8 entry_i = 0; + u32 ulstatus; + int i = 100, j = 0; + + /* This dump the current register page */ + seq_puts(m, + "\n################### SECURITY CAM (22-31) ##################\n "); + + for (j = 22; j < TOTAL_CAM_ENTRY; j++) { + seq_printf(m, "\nD: %2x > ", j); + for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { + target_cmd = entry_i+CAM_CONTENT_COUNT*j; + target_cmd = target_cmd | BIT(31); + + while ((i--) >= 0) { + ulstatus = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[RWCAM]); + if (ulstatus & BIT(31)) { + continue; + } else { + break; + } + } + + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_cmd); + target_val = rtl_read_dword(rtlpriv, + rtlpriv->cfg->maps[RCAMO]); + seq_printf(m, "%8.8x ", target_val); + } + } + seq_puts(m, "\n"); + return 0; +} + +static int dl_proc_open_cam_3(struct inode *inode, struct file *file) +{ + return single_open(file, rtl_proc_get_cam_register_3, + GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_cam_3 = { + .open = dl_proc_open_cam_3, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +void rtl_proc_add_one(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct proc_dir_entry *entry; + + snprintf(rtlpriv->dbg.proc_name, 18, "%x-%x-%x-%x-%x-%x", + rtlefuse->dev_addr[0], rtlefuse->dev_addr[1], + rtlefuse->dev_addr[2], rtlefuse->dev_addr[3], + rtlefuse->dev_addr[4], rtlefuse->dev_addr[5]); + + rtlpriv->dbg.proc_dir = proc_mkdir(rtlpriv->dbg.proc_name, proc_topdir); + if (!rtlpriv->dbg.proc_dir) { + RT_TRACE(COMP_INIT, DBG_EMERG, ("Unable to init " + "/proc/net/%s/%s\n", rtlpriv->cfg->name, + rtlpriv->dbg.proc_name)); + return; + } + + entry = proc_create_data("mac-0", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_0, hw); + if (!entry) + RT_TRACE(COMP_INIT, DBG_EMERG, + ("Unable to initialize /proc/net/%s/%s/mac-0\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("mac-1", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_1, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/mac-1\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("mac-2", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_2, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/mac-2\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("mac-3", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_3, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/mac-3\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("mac-4", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_4, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/mac-4\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("mac-5", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_5, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/mac-5\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("mac-6", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_6, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/mac-6\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("mac-7", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_mac_7, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/mac-7\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-8", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_8, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-8\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-9", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_9, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-9\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-a", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_a, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-a\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-b", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_b, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-b\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-c", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_c, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-c\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-d", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_d, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-d\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-e", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_e, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-e\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("bb-f", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_bb_f, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/bb-f\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("rf-a", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_rf_a, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/rf-a\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("rf-b", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_rf_b, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/rf-b\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("cam-1", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_cam_1, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/cam-1\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("cam-2", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_cam_2, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/cam-2\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + + entry = proc_create_data("cam-3", S_IFREG | S_IRUGO, + rtlpriv->dbg.proc_dir, &file_ops_cam_3, hw); + if (!entry) + RT_TRACE(COMP_INIT, COMP_ERR, + ("Unable to initialize /proc/net/%s/%s/cam-3\n", + rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); +} + +void rtl_proc_remove_one(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dbg.proc_dir) { + remove_proc_entry("mac-0", rtlpriv->dbg.proc_dir); + remove_proc_entry("mac-1", rtlpriv->dbg.proc_dir); + remove_proc_entry("mac-2", rtlpriv->dbg.proc_dir); + remove_proc_entry("mac-3", rtlpriv->dbg.proc_dir); + remove_proc_entry("mac-4", rtlpriv->dbg.proc_dir); + remove_proc_entry("mac-5", rtlpriv->dbg.proc_dir); + remove_proc_entry("mac-6", rtlpriv->dbg.proc_dir); + remove_proc_entry("mac-7", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-8", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-9", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-a", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-b", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-c", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-d", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-e", rtlpriv->dbg.proc_dir); + remove_proc_entry("bb-f", rtlpriv->dbg.proc_dir); + remove_proc_entry("rf-a", rtlpriv->dbg.proc_dir); + remove_proc_entry("rf-b", rtlpriv->dbg.proc_dir); + remove_proc_entry("cam-1", rtlpriv->dbg.proc_dir); + remove_proc_entry("cam-2", rtlpriv->dbg.proc_dir); + remove_proc_entry("cam-3", rtlpriv->dbg.proc_dir); + + remove_proc_entry(rtlpriv->dbg.proc_name, proc_topdir); + + rtlpriv->dbg.proc_dir = NULL; + } +} + +void rtl_proc_add_topdir(void) +{ + proc_topdir = proc_mkdir("rtlwifi", init_net.proc_net); +} + +void rtl_proc_remove_topdir(void) +{ + if (proc_topdir) + remove_proc_entry("rtlwifi", init_net.proc_net); +} \ No newline at end of file --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/reg.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/reg.h @@ -0,0 +1,2427 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_REG_H__ +#define __RTL8821AE_REG_H__ + +#define TXPKT_BUF_SELECT 0x69 +#define RXPKT_BUF_SELECT 0xA5 +#define DISABLE_TRXPKT_BUF_ACCESS 0x0 + +#define REG_SYS_ISO_CTRL 0x0000 +#define REG_SYS_FUNC_EN 0x0002 +#define REG_APS_FSMCO 0x0004 +#define REG_SYS_CLKR 0x0008 +#define REG_9346CR 0x000A +#define REG_EE_VPD 0x000C +#define REG_AFE_MISC 0x0010 +#define REG_SPS0_CTRL 0x0011 +#define REG_SPS_OCP_CFG 0x0018 +#define REG_RSV_CTRL 0x001C +#define REG_RF_CTRL 0x001F +#define REG_LDOA15_CTRL 0x0020 +#define REG_LDOV12D_CTRL 0x0021 +#define REG_LDOHCI12_CTRL 0x0022 +#define REG_LPLDO_CTRL 0x0023 +#define REG_AFE_XTAL_CTRL 0x0024 +#define REG_AFE_LDO_CTRL 0x0027 /* 1.5v for 8188EE test chip, 1.4v for MP chip */ +#define REG_AFE_PLL_CTRL 0x0028 +#define REG_MAC_PHY_CTRL 0x002c +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define REG_PWR_DATA 0x0038 +#define REG_CAL_TIMER 0x003C +#define REG_ACLK_MON 0x003E +#define REG_GPIO_MUXCFG 0x0040 +#define REG_GPIO_IO_SEL 0x0042 +#define REG_MAC_PINMUX_CFG 0x0043 +#define REG_GPIO_PIN_CTRL 0x0044 +#define REG_GPIO_INTM 0x0048 +#define REG_LEDCFG0 0x004C +#define REG_LEDCFG1 0x004D +#define REG_LEDCFG2 0x004E +#define REG_LEDCFG3 0x004F +#define REG_FSIMR 0x0050 +#define REG_FSISR 0x0054 +#define REG_HSIMR 0x0058 +#define REG_HSISR 0x005c +#define REG_GPIO_PIN_CTRL_2 0x0060 +#define REG_GPIO_IO_SEL_2 0x0062 +#define REG_MULTI_FUNC_CTRL 0x0068 +#define REG_GPIO_OUTPUT 0x006c +#define REG_OPT_CTRL 0x0074 +#define REG_AFE_XTAL_CTRL_EXT 0x0078 +#define REG_XCK_OUT_CTRL 0x007c +#define REG_MCUFWDL 0x0080 +#define REG_WOL_EVENT 0x0081 +#define REG_MCUTSTCFG 0x0084 + + +#define REG_HIMR 0x00B0 +#define REG_HISR 0x00B4 +#define REG_HIMRE 0x00B8 +#define REG_HISRE 0x00BC + +#define REG_PMC_DBG_CTRL2 0x00CC + +#define REG_EFUSE_ACCESS 0x00CF + +#define REG_BIST_SCAN 0x00D0 +#define REG_BIST_RPT 0x00D4 +#define REG_BIST_ROM_RPT 0x00D8 +#define REG_USB_SIE_INTF 0x00E0 +#define REG_PCIE_MIO_INTF 0x00E4 +#define REG_PCIE_MIO_INTD 0x00E8 +#define REG_HPON_FSM 0x00EC +#define REG_SYS_CFG 0x00F0 +#define REG_GPIO_OUTSTS 0x00F4 +#define REG_SYS_CFG1 0x00FC +#define REG_ROM_VERSION 0x00FD + +#define REG_CR 0x0100 +#define REG_PBP 0x0104 +#define REG_PKT_BUFF_ACCESS_CTRL 0x0106 +#define REG_TRXDMA_CTRL 0x010C +#define REG_TRXFF_BNDY 0x0114 +#define REG_TRXFF_STATUS 0x0118 +#define REG_RXFF_PTR 0x011C + +#define REG_CPWM 0x012F +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_PKTBUF_DBG_CTRL 0x0140 +#define REG_PKTBUF_DBG_DATA_L 0x0144 +#define REG_PKTBUF_DBG_DATA_H 0x0148 +#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL+2) + +#define REG_TC0_CTRL 0x0150 +#define REG_TC1_CTRL 0x0154 +#define REG_TC2_CTRL 0x0158 +#define REG_TC3_CTRL 0x015C +#define REG_TC4_CTRL 0x0160 +#define REG_TCUNIT_BASE 0x0164 +#define REG_MBIST_START 0x0174 +#define REG_MBIST_DONE 0x0178 +#define REG_MBIST_FAIL 0x017C +#define REG_32K_CTRL 0x0194 +#define REG_C2HEVT_MSG_NORMAL 0x01A0 +#define REG_C2HEVT_CLEAR 0x01AF +#define REG_C2HEVT_MSG_TEST 0x01B8 +#define REG_MCUTST_1 0x01c0 +#define REG_FMETHR 0x01C8 +#define REG_HMETFR 0x01CC +#define REG_HMEBOX_0 0x01D0 +#define REG_HMEBOX_1 0x01D4 +#define REG_HMEBOX_2 0x01D8 +#define REG_HMEBOX_3 0x01DC + +#define REG_LLT_INIT 0x01E0 +#define REG_BB_ACCEESS_CTRL 0x01E8 +#define REG_BB_ACCESS_DATA 0x01EC + +#define REG_HMEBOX_EXT_0 0x01F0 +#define REG_HMEBOX_EXT_1 0x01F4 +#define REG_HMEBOX_EXT_2 0x01F8 +#define REG_HMEBOX_EXT_3 0x01FC + +#define REG_RQPN 0x0200 +#define REG_FIFOPAGE 0x0204 +#define REG_TDECTRL 0x0208 +#define REG_TXDMA_OFFSET_CHK 0x020C +#define REG_TXDMA_STATUS 0x0210 +#define REG_RQPN_NPQ 0x0214 + +#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_FW_UPD_RDPTR 0x0284 /* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */ +#define REG_RXDMA_CONTROL 0x0286 /* Control the RX DMA.*/ +#define REG_RXPKT_NUM 0x0287 /* The number of packets in RXPKTBUF. */ + +#define REG_PCIE_CTRL_REG 0x0300 +#define REG_INT_MIG 0x0304 +#define REG_BCNQ_DESA 0x0308 +#define REG_HQ_DESA 0x0310 +#define REG_MGQ_DESA 0x0318 +#define REG_VOQ_DESA 0x0320 +#define REG_VIQ_DESA 0x0328 +#define REG_BEQ_DESA 0x0330 +#define REG_BKQ_DESA 0x0338 +#define REG_RX_DESA 0x0340 + +#define REG_DBI_WDATA 0x0348 +#define REG_DBI_RDATA 0x034C +#define REG_DBI_ADDR 0x0350 +#define REG_DBI_FLAG 0x0352 +#define REG_MDIO_WDATA 0x0354 +#define REG_MDIO_RDATA 0x0356 +#define REG_MDIO_CTL 0x0358 +#define REG_DBG_SEL 0x0360 +#define REG_PCIE_HRPWM 0x0361 +#define REG_PCIE_HCPWM 0x0363 +#define REG_UART_CTRL 0x0364 +#define REG_WATCH_DOG 0x0368 +#define REG_UART_TX_DESA 0x0370 +#define REG_UART_RX_DESA 0x0378 + + +#define REG_HDAQ_DESA_NODEF 0x0000 +#define REG_CMDQ_DESA_NODEF 0x0000 + +#define REG_VOQ_INFORMATION 0x0400 +#define REG_VIQ_INFORMATION 0x0404 +#define REG_BEQ_INFORMATION 0x0408 +#define REG_BKQ_INFORMATION 0x040C +#define REG_MGQ_INFORMATION 0x0410 +#define REG_HGQ_INFORMATION 0x0414 +#define REG_BCNQ_INFORMATION 0x0418 +#define REG_TXPKT_EMPTY 0x041A + + +#define REG_CPU_MGQ_INFORMATION 0x041C +#define REG_FWHW_TXQ_CTRL 0x0420 +#define REG_HWSEQ_CTRL 0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define REG_MULTI_BCNQ_EN 0x0426 +#define REG_MULTI_BCNQ_OFFSET 0x0427 +#define REG_SPEC_SIFS 0x0428 +#define REG_RL 0x042A +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RRSR 0x0440 +#define REG_ARFR0 0x0444 +#define REG_ARFR1 0x044C +#define REG_CCK_CHECK 0x0454 +#define REG_AMPDU_MAX_TIME 0x0456 +#define REG_AGGLEN_LMT 0x0458 +#define REG_AMPDU_MIN_SPACE 0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D +#define REG_FAST_EDCA_CTRL 0x0460 +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_INIDATA_RATE_SEL 0x0484 +#define REG_ARFR2 0x048C +#define REG_ARFR3 0x0494 +#define REG_POWER_STATUS 0x04A4 +#define REG_POWER_STAGE1 0x04B4 +#define REG_POWER_STAGE2 0x04B8 +#define REG_PKT_LIFE_TIME 0x04C0 +#define REG_STBC_SETTING 0x04C4 +#define REG_HT_SINGLE_AMPDU 0x04C7 +#define REG_PROT_MODE_CTRL 0x04C8 +#define REG_MAX_AGGR_NUM 0x04CA +#define REG_BAR_MODE_CTRL 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT 0x04CF +#define REG_EARLY_MODE_CONTROL 0x04D0 +#define REG_NQOS_SEQ 0x04DC +#define REG_QOS_SEQ 0x04DE +#define REG_NEED_CPU_HANDLE 0x04E0 +#define REG_PKT_LOSE_RPT 0x04E1 +#define REG_PTCL_ERR_STATUS 0x04E2 +#define REG_TX_RPT_CTRL 0x04EC +#define REG_TX_RPT_TIME 0x04F0 +#define REG_DUMMY 0x04FC + +#define REG_EDCA_VO_PARAM 0x0500 +#define REG_EDCA_VI_PARAM 0x0504 +#define REG_EDCA_BE_PARAM 0x0508 +#define REG_EDCA_BK_PARAM 0x050C +#define REG_BCNTCFG 0x0510 +#define REG_PIFS 0x0512 +#define REG_RDG_PIFS 0x0513 +#define REG_SIFS_CTX 0x0514 +#define REG_SIFS_TRX 0x0516 +#define REG_AGGR_BREAK_TIME 0x051A +#define REG_SLOT 0x051B +#define REG_TX_PTCL_CTRL 0x0520 +#define REG_TXPAUSE 0x0522 +#define REG_DIS_TXREQ_CLR 0x0523 +#define REG_RD_CTRL 0x0524 +#define REG_TBTT_PROHIBIT 0x0540 +#define REG_RD_NAV_NXT 0x0544 +#define REG_NAV_PROT_LEN 0x0546 +#define REG_BCN_CTRL 0x0550 +#define REG_USTIME_TSF 0x0551 +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 +#define REG_BCN_INTERVAL 0x0554 +#define REG_MBSSID_BCN_SPACE 0x0554 +#define REG_DRVERLYINT 0x0558 +#define REG_BCNDMATIM 0x0559 +#define REG_ATIMWND 0x055A +#define REG_BCN_MAX_ERR 0x055D +#define REG_RXTSF_OFFSET_CCK 0x055E +#define REG_RXTSF_OFFSET_OFDM 0x055F +#define REG_TSFTR 0x0560 +#define REG_INIT_TSFTR 0x0564 +#define REG_SECONDARY_CCA_CTRL 0x0577 +#define REG_PSTIMER 0x0580 +#define REG_TIMER0 0x0584 +#define REG_TIMER1 0x0588 +#define REG_ACMHWCTRL 0x05C0 +#define REG_ACMRSTCTRL 0x05C1 +#define REG_ACMAVG 0x05C2 +#define REG_VO_ADMTIME 0x05C4 +#define REG_VI_ADMTIME 0x05C6 +#define REG_BE_ADMTIME 0x05C8 +#define REG_EDCA_RANDOM_GEN 0x05CC +#define REG_NOA_DESC_SEL 0x05CF +#define REG_NOA_DESC_DURATION 0x05E0 +#define REG_NOA_DESC_INTERVAL 0x05E4 +#define REG_NOA_DESC_START 0x05E8 +#define REG_NOA_DESC_COUNT 0x05EC +#define REG_SCH_TX_CMD 0x05F8 + +#define REG_APSD_CTRL 0x0600 +#define REG_BWOPMODE 0x0603 +#define REG_TCR 0x0604 +#define REG_RCR 0x0608 +#define REG_RX_PKT_LIMIT 0x060C +#define REG_RX_DLK_TIME 0x060D +#define REG_RX_DRVINFO_SZ 0x060F + +#define REG_MACID 0x0610 +#define REG_BSSID 0x0618 +#define REG_MAR 0x0620 +#define REG_MBIDCAMCFG 0x0628 + +#define REG_USTIME_EDCA 0x0638 +#define REG_MAC_SPEC_SIFS 0x063A +#define REG_RESP_SIFS_CCK 0x063C +#define REG_RESP_SIFS_OFDM 0x063E +#define REG_ACKTO 0x0640 +#define REG_CTS2TO 0x0641 +#define REG_EIFS 0x0642 + +#define REG_NAV_CTRL 0x0650 +#define REG_NAV_UPPER 0x0652 +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 +#define REG_FWDLY 0x0661 +#define REG_RXERR_RPT 0x0664 +#define REG_TRXPTCL_CTL 0x0668 + +#define REG_CAMCMD 0x0670 +#define REG_CAMWRITE 0x0674 +#define REG_CAMREAD 0x0678 +#define REG_CAMDBG 0x067C +#define REG_SECCFG 0x0680 + +#define REG_WOW_CTRL 0x0690 +#define REG_PSSTATUS 0x0691 +#define REG_PS_RX_INFO 0x0692 +#define REG_UAPSD_TID 0x0693 +#define REG_LPNAV_CTRL 0x0694 +#define REG_WKFMCAM_NUM 0x0698 +#define REG_WKFMCAM_RWD 0x069C +#define REG_RXFLTMAP0 0x06A0 +#define REG_RXFLTMAP1 0x06A2 +#define REG_RXFLTMAP2 0x06A4 +#define REG_BCN_PSR_RPT 0x06A8 +#define REG_CALB32K_CTRL 0x06AC +#define REG_PKT_MON_CTRL 0x06B4 +#define REG_BT_COEX_TABLE 0x06C0 +#define REG_WMAC_RESP_TXINFO 0x06D8 + +#define REG_USB_INFO 0xFE17 +#define REG_USB_SPECIAL_OPTION 0xFE55 +#define REG_USB_DMA_AGG_TO 0xFE5B +#define REG_USB_AGG_TO 0xFE5C +#define REG_USB_AGG_TH 0xFE5D + +#define REG_TEST_USB_TXQS 0xFE48 +#define REG_TEST_SIE_VID 0xFE60 +#define REG_TEST_SIE_PID 0xFE62 +#define REG_TEST_SIE_OPTIONAL 0xFE64 +#define REG_TEST_SIE_CHIRP_K 0xFE65 +#define REG_TEST_SIE_PHY 0xFE66 +#define REG_TEST_SIE_MAC_ADDR 0xFE70 +#define REG_TEST_SIE_STRING 0xFE80 + +#define REG_NORMAL_SIE_VID 0xFE60 +#define REG_NORMAL_SIE_PID 0xFE62 +#define REG_NORMAL_SIE_OPTIONAL 0xFE64 +#define REG_NORMAL_SIE_EP 0xFE65 +#define REG_NORMAL_SIE_PHY 0xFE68 +#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 +#define REG_NORMAL_SIE_STRING 0xFE80 + +#define CR9346 REG_9346CR +#define MSR (REG_CR + 2) +#define ISR REG_HISR +#define TSFR REG_TSFTR + +#define MACIDR0 REG_MACID +#define MACIDR4 (REG_MACID + 4) + +#define PBP REG_PBP + +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + +#define UNUSED_REGISTER 0x1BF +#define DCAM UNUSED_REGISTER +#define PSR UNUSED_REGISTER +#define BBADDR UNUSED_REGISTER +#define PHYDATAR UNUSED_REGISTER + +#define INVALID_BBRF_VALUE 0x12345678 + +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +#define CMDEEPROM_EN BIT(5) +#define CMDEEPROM_SEL BIT(4) +#define CMD9346CR_9356SEL BIT(4) +#define AUTOLOAD_EEPROM (CMDEEPROM_EN|CMDEEPROM_SEL) +#define AUTOLOAD_EFUSE CMDEEPROM_EN + +#define GPIOSEL_GPIO 0 +#define GPIOSEL_ENBT BIT(5) + +#define GPIO_IN REG_GPIO_PIN_CTRL +#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) +#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) +#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) + +/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */ +#define HSIMR_GPIO12_0_INT_EN BIT(0) +#define HSIMR_SPS_OCP_INT_EN BIT(5) +#define HSIMR_RON_INT_EN BIT(6) +#define HSIMR_PDN_INT_EN BIT(7) +#define HSIMR_GPIO9_INT_EN BIT(25) + + +/* +* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) +*/ +#define HSISR_GPIO12_0_INT BIT(0) +#define HSISR_SPS_OCP_INT BIT(5) +#define HSISR_RON_INT_EN BIT(6) +#define HSISR_PDNINT BIT(7) +#define HSISR_GPIO9_INT BIT(25) + +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT(0) +#define RRSR_2M BIT(1) +#define RRSR_5_5M BIT(2) +#define RRSR_11M BIT(3) +#define RRSR_6M BIT(4) +#define RRSR_9M BIT(5) +#define RRSR_12M BIT(6) +#define RRSR_18M BIT(7) +#define RRSR_24M BIT(8) +#define RRSR_36M BIT(9) +#define RRSR_48M BIT(10) +#define RRSR_54M BIT(11) +#define RRSR_MCS0 BIT(12) +#define RRSR_MCS1 BIT(13) +#define RRSR_MCS2 BIT(14) +#define RRSR_MCS3 BIT(15) +#define RRSR_MCS4 BIT(16) +#define RRSR_MCS5 BIT(17) +#define RRSR_MCS6 BIT(18) +#define RRSR_MCS7 BIT(19) +#define BRSR_ACKSHORTPMB BIT(23) + +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 + +#define RATE_1M BIT(0) +#define RATE_2M BIT(1) +#define RATE_5_5M BIT(2) +#define RATE_11M BIT(3) +#define RATE_6M BIT(4) +#define RATE_9M BIT(5) +#define RATE_12M BIT(6) +#define RATE_18M BIT(7) +#define RATE_24M BIT(8) +#define RATE_36M BIT(9) +#define RATE_48M BIT(10) +#define RATE_54M BIT(11) +#define RATE_MCS0 BIT(12) +#define RATE_MCS1 BIT(13) +#define RATE_MCS2 BIT(14) +#define RATE_MCS3 BIT(15) +#define RATE_MCS4 BIT(16) +#define RATE_MCS5 BIT(17) +#define RATE_MCS6 BIT(18) +#define RATE_MCS7 BIT(19) +#define RATE_MCS8 BIT(20) +#define RATE_MCS9 BIT(21) +#define RATE_MCS10 BIT(22) +#define RATE_MCS11 BIT(23) +#define RATE_MCS12 BIT(24) +#define RATE_MCS13 BIT(25) +#define RATE_MCS14 BIT(26) +#define RATE_MCS15 BIT(27) + +#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M) +#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M |\ + RATR_24M| RATR_36M | RATR_48M | RATR_54M) +#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\ + RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\ + RATR_MCS6 | RATR_MCS7) +#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\ + RATR_MCS11| RATR_MCS12 | RATR_MCS13 |\ + RATR_MCS14 | RATR_MCS15) + +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + +#define CAM_VALID BIT(15) +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT(5) + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +#define TOTAL_CAM_ENTRY 32 +#define HALF_CAM_ENTRY 16 + +#define CAM_WRITE BIT(16) +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT(31) + +#define SCR_USEDK 0x01 +#define SCR_TXSEC_ENABLE 0x02 +#define SCR_RXSEC_ENABLE 0x04 + +#define WOW_PMEN BIT(0) +#define WOW_WOMEN BIT(1) +#define WOW_MAGIC BIT(2) +#define WOW_UWF BIT(3) + +/********************************************* +* 8188 IMR/ISR bits +**********************************************/ +#define IMR_DISABLED 0x0 +/* IMR DW0(0x0060-0063) Bit 0-31 */ +#define IMR_TXCCK BIT(30) /* TXRPT interrupt when CCX bit of the packet is set */ +#define IMR_PSTIMEOUT BIT(29) /* Power Save Time Out Interrupt */ +#define IMR_GTINT4 BIT(28) /* When GTIMER4 expires, this bit is set to 1 */ +#define IMR_GTINT3 BIT(27) /* When GTIMER3 expires, this bit is set to 1 */ +#define IMR_TBDER BIT(26) /* Transmit Beacon0 Error */ +#define IMR_TBDOK BIT(25) /* Transmit Beacon0 OK */ +#define IMR_TSF_BIT32_TOGGLE BIT(24) /* TSF Timer BIT32 toggle indication interrupt */ +#define IMR_BCNDMAINT0 BIT(20) /* Beacon DMA Interrupt 0 */ +#define IMR_BCNDOK0 BIT(16) /* Beacon Queue DMA OK0 */ +#define IMR_HSISR_IND_ON_INT BIT(15) /* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */ +#define IMR_BCNDMAINT_E BIT(14) /* Beacon DMA Interrupt Extension for Win7 */ +#define IMR_ATIMEND BIT(12) /* CTWidnow End or ATIM Window End */ +#define IMR_HISR1_IND_INT BIT(11) /* HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1)*/ +#define IMR_C2HCMD BIT(10) /* CPU to Host Command INT Status, Write 1 clear */ +#define IMR_CPWM2 BIT(9) /* CPU power Mode exchange INT Status, Write 1 clear */ +#define IMR_CPWM BIT(8) /* CPU power Mode exchange INT Status, Write 1 clear */ +#define IMR_HIGHDOK BIT(7) /* High Queue DMA OK */ +#define IMR_MGNTDOK BIT(6) /* Management Queue DMA OK */ +#define IMR_BKDOK BIT(5) /* AC_BK DMA OK */ +#define IMR_BEDOK BIT(4) /* AC_BE DMA OK */ +#define IMR_VIDOK BIT(3) /* AC_VI DMA OK */ +#define IMR_VODOK BIT(2) /* AC_VO DMA OK */ +#define IMR_RDU BIT(1) /* Rx Descriptor Unavailable */ +#define IMR_ROK BIT(0) /* Receive DMA OK */ + +/* IMR DW1(0x00B4-00B7) Bit 0-31 */ +#define IMR_BCNDMAINT7 BIT(27) /* Beacon DMA Interrupt 7 */ +#define IMR_BCNDMAINT6 BIT(26) /* Beacon DMA Interrupt 6 */ +#define IMR_BCNDMAINT5 BIT(25) /* Beacon DMA Interrupt 5 */ +#define IMR_BCNDMAINT4 BIT(24) /* Beacon DMA Interrupt 4 */ +#define IMR_BCNDMAINT3 BIT(23) /* Beacon DMA Interrupt 3 */ +#define IMR_BCNDMAINT2 BIT(22) /* Beacon DMA Interrupt 2 */ +#define IMR_BCNDMAINT1 BIT(21) /* Beacon DMA Interrupt 1 */ +#define IMR_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrup 7 */ +#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrup 6 */ +#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrup 5 */ +#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrup 4 */ +#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrup 3 */ +#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrup 2 */ +#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrup 1 */ +#define IMR_ATIMEND_E BIT(13) /* ATIM Window End Extension for Win7 */ +#define IMR_TXERR BIT(11) /* Tx Error Flag Interrupt Status, write 1 clear. */ +#define IMR_RXERR BIT(10) /* Rx Error Flag INT Status, Write 1 clear */ +#define IMR_TXFOVW BIT(9) /* Transmit FIFO Overflow */ +#define IMR_RXFOVW BIT(8) /* Receive FIFO Overflow */ + + +#define HWSET_MAX_SIZE 512 +#define EFUSE_MAX_SECTION 64 +#define EFUSE_REAL_CONTENT_LEN 256 +#define EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte.*/ + + +#define EEPROM_DEFAULT_TSSI 0x0 +#define EEPROM_DEFAULT_TXPOWERDIFF 0x0 +#define EEPROM_DEFAULT_CRYSTALCAP 0x5 +#define EEPROM_DEFAULT_BOARDTYPE 0x02 +#define EEPROM_DEFAULT_TXPOWER 0x1010 +#define EEPROM_DEFAULT_HT2T_TXPWR 0x10 + +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 +#define EEPROM_DEFAULT_THERMALMETER 0x18 +#define EEPROM_DEFAULT_ANTTXPOWERDIFF 0x0 +#define EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP 0x5 +#define EEPROM_DEFAULT_TXPOWERLEVEL 0x22 +#define EEPROM_DEFAULT_HT40_2SDIFF 0x0 +#define EEPROM_DEFAULT_HT20_DIFF 2 +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 +#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0 +#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 0 + +#define RF_OPTION1 0x79 +#define RF_OPTION2 0x7A +#define RF_OPTION3 0x7B +#define RF_OPTION4 0xC3 + +#define EEPROM_DEFAULT_PID 0x1234 +#define EEPROM_DEFAULT_VID 0x5678 +#define EEPROM_DEFAULT_CUSTOMERID 0xAB +#define EEPROM_DEFAULT_SUBCUSTOMERID 0xCD +#define EEPROM_DEFAULT_VERSION 0 + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_NCC 0xB +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_TOSHIBA 0x4 +#define EEPROM_CID_CCX 0x10 +#define EEPROM_CID_QMI 0x0D +#define EEPROM_CID_WHQL 0xFE + +#define RTL_EEPROM_ID 0x8129 + +#define EEPROM_HPON 0x02 +#define EEPROM_CLK 0x06 +#define EEPROM_TESTR 0x08 + + +#define EEPROM_TXPOWERCCK 0x10 +#define EEPROM_TXPOWERHT40_1S 0x16 +#define EEPROM_TXPOWERHT20DIFF 0x1B +#define EEPROM_TXPOWER_OFDMDIFF 0x1B + + + +#define EEPROM_TX_PWR_INX 0x10 + +#define EEPROM_CHANNELPLAN 0xB8 +#define EEPROM_XTAL_8821AE 0xB9 +#define EEPROM_THERMAL_METER 0xBA +#define EEPROM_IQK_LCK_88E 0xBB + +#define EEPROM_RF_BOARD_OPTION 0xC1 +#define EEPROM_RF_FEATURE_OPTION_88E 0xC2 +#define EEPROM_RF_BT_SETTING 0xC3 +#define EEPROM_VERSION 0xC4 +#define EEPROM_CUSTOMER_ID 0xC5 +#define EEPROM_RF_ANTENNA_OPT_88E 0xC9 + +#define EEPROM_MAC_ADDR 0xD0 +#define EEPROM_VID 0xD6 +#define EEPROM_DID 0xD8 +#define EEPROM_SVID 0xDA +#define EEPROM_SMID 0xDC + +#define STOPBECON BIT(6) +#define STOPHIGHT BIT(5) +#define STOPMGT BIT(4) +#define STOPVO BIT(3) +#define STOPVI BIT(2) +#define STOPBE BIT(1) +#define STOPBK BIT(0) + +#define RCR_APPFCS BIT(31) +#define RCR_APP_MIC BIT(30) +#define RCR_APP_ICV BIT(29) +#define RCR_APP_PHYST_RXFF BIT(28) +#define RCR_APP_BA_SSN BIT(27) +#define RCR_NONQOS_VHT BIT(26) +#define RCR_ENMBID BIT(24) +#define RCR_LSIGEN BIT(23) +#define RCR_MFBEN BIT(22) +#define RCR_HTC_LOC_CTRL BIT(14) +#define RCR_AMF BIT(13) +#define RCR_ACF BIT(12) +#define RCR_ADF BIT(11) +#define RCR_AICV BIT(9) +#define RCR_ACRC32 BIT(8) +#define RCR_CBSSID_BCN BIT(7) +#define RCR_CBSSID_DATA BIT(6) +#define RCR_CBSSID RCR_CBSSID_DATA +#define RCR_APWRMGT BIT(5) +#define RCR_ADD3 BIT(4) +#define RCR_AB BIT(3) +#define RCR_AM BIT(2) +#define RCR_APM BIT(1) +#define RCR_AAP BIT(0) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + +#define RSV_CTRL 0x001C +#define RD_CTRL 0x0524 + +#define REG_USB_INFO 0xFE17 +#define REG_USB_SPECIAL_OPTION 0xFE55 +#define REG_USB_DMA_AGG_TO 0xFE5B +#define REG_USB_AGG_TO 0xFE5C +#define REG_USB_AGG_TH 0xFE5D + +#define REG_USB_VID 0xFE60 +#define REG_USB_PID 0xFE62 +#define REG_USB_OPTIONAL 0xFE64 +#define REG_USB_CHIRP_K 0xFE65 +#define REG_USB_PHY 0xFE66 +#define REG_USB_MAC_ADDR 0xFE70 +#define REG_USB_HRPWM 0xFE58 +#define REG_USB_HCPWM 0xFE57 + +#define SW18_FPWM BIT(3) + +#define ISO_MD2PP BIT(0) +#define ISO_UA2USB BIT(1) +#define ISO_UD2CORE BIT(2) +#define ISO_PA2PCIE BIT(3) +#define ISO_PD2CORE BIT(4) +#define ISO_IP2MAC BIT(5) +#define ISO_DIOP BIT(6) +#define ISO_DIOE BIT(7) +#define ISO_EB2CORE BIT(8) +#define ISO_DIOR BIT(9) + +#define PWC_EV25V BIT(14) +#define PWC_EV12V BIT(15) + +#define FEN_BBRSTB BIT(0) +#define FEN_BB_GLB_RSTN BIT(1) +#define FEN_USBA BIT(2) +#define FEN_UPLL BIT(3) +#define FEN_USBD BIT(4) +#define FEN_DIO_PCIE BIT(5) +#define FEN_PCIEA BIT(6) +#define FEN_PPLL BIT(7) +#define FEN_PCIED BIT(8) +#define FEN_DIOE BIT(9) +#define FEN_CPUEN BIT(10) +#define FEN_DCORE BIT(11) +#define FEN_ELDR BIT(12) +#define FEN_DIO_RF BIT(13) +#define FEN_HWPDN BIT(14) +#define FEN_MREGEN BIT(15) + +#define PFM_LDALL BIT(0) +#define PFM_ALDN BIT(1) +#define PFM_LDKP BIT(2) +#define PFM_WOWL BIT(3) +#define EnPDN BIT(4) +#define PDN_PL BIT(5) +#define APFM_ONMAC BIT(8) +#define APFM_OFF BIT(9) +#define APFM_RSM BIT(10) +#define AFSM_HSUS BIT(11) +#define AFSM_PCIE BIT(12) +#define APDM_MAC BIT(13) +#define APDM_HOST BIT(14) +#define APDM_HPDN BIT(15) +#define RDY_MACON BIT(16) +#define SUS_HOST BIT(17) +#define ROP_ALD BIT(20) +#define ROP_PWR BIT(21) +#define ROP_SPS BIT(22) +#define SOP_MRST BIT(25) +#define SOP_FUSE BIT(26) +#define SOP_ABG BIT(27) +#define SOP_AMB BIT(28) +#define SOP_RCK BIT(29) +#define SOP_A8M BIT(30) +#define XOP_BTCK BIT(31) + +#define ANAD16V_EN BIT(0) +#define ANA8M BIT(1) +#define MACSLP BIT(4) +#define LOADER_CLK_EN BIT(5) +#define _80M_SSC_DIS BIT(7) +#define _80M_SSC_EN_HO BIT(8) +#define PHY_SSC_RSTB BIT(9) +#define SEC_CLK_EN BIT(10) +#define MAC_CLK_EN BIT(11) +#define SYS_CLK_EN BIT(12) +#define RING_CLK_EN BIT(13) + +#define BOOT_FROM_EEPROM BIT(4) +#define EEPROM_EN BIT(5) + +#define AFE_BGEN BIT(0) +#define AFE_MBEN BIT(1) +#define MAC_ID_EN BIT(7) + +#define WLOCK_ALL BIT(0) +#define WLOCK_00 BIT(1) +#define WLOCK_04 BIT(2) +#define WLOCK_08 BIT(3) +#define WLOCK_40 BIT(4) +#define R_DIS_PRST_0 BIT(5) +#define R_DIS_PRST_1 BIT(6) +#define LOCK_ALL_EN BIT(7) + +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + +#define LDA15_EN BIT(0) +#define LDA15_STBY BIT(1) +#define LDA15_OBUF BIT(2) +#define LDA15_REG_VOS BIT(3) +#define _LDA15_VOADJ(x) (((x) & 0x7) << 4) + +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) +#define LPLDO_HSM BIT(2) +#define LPLDO_LSM_DIS BIT(3) +#define _LDV12_VADJ(x) (((x) & 0xF) << 4) + +#define XTAL_EN BIT(0) +#define XTAL_BSEL BIT(1) +#define _XTAL_BOSC(x) (((x) & 0x3) << 2) +#define _XTAL_CADJ(x) (((x) & 0xF) << 4) +#define XTAL_GATE_USB BIT(8) +#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9) +#define XTAL_GATE_AFE BIT(11) +#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12) +#define XTAL_RF_GATE BIT(14) +#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15) +#define XTAL_GATE_DIG BIT(17) +#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18) +#define XTAL_BT_GATE BIT(20) +#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21) +#define _XTAL_GPIO(x) (((x) & 0x7) << 23) + +#define CKDLY_AFE BIT(26) +#define CKDLY_USB BIT(27) +#define CKDLY_DIG BIT(28) +#define CKDLY_BT BIT(29) + +#define APLL_EN BIT(0) +#define APLL_320_EN BIT(1) +#define APLL_FREF_SEL BIT(2) +#define APLL_EDGE_SEL BIT(3) +#define APLL_WDOGB BIT(4) +#define APLL_LPFEN BIT(5) + +#define APLL_REF_CLK_13MHZ 0x1 +#define APLL_REF_CLK_19_2MHZ 0x2 +#define APLL_REF_CLK_20MHZ 0x3 +#define APLL_REF_CLK_25MHZ 0x4 +#define APLL_REF_CLK_26MHZ 0x5 +#define APLL_REF_CLK_38_4MHZ 0x6 +#define APLL_REF_CLK_40MHZ 0x7 + +#define APLL_320EN BIT(14) +#define APLL_80EN BIT(15) +#define APLL_1MEN BIT(24) + +#define ALD_EN BIT(18) +#define EF_PD BIT(19) +#define EF_FLAG BIT(31) + +#define EF_TRPT BIT(7) +#define LDOE25_EN BIT(31) + +#define RSM_EN BIT(0) +#define Timer_EN BIT(4) + +#define TRSW0EN BIT(2) +#define TRSW1EN BIT(3) +#define EROM_EN BIT(4) +#define EnBT BIT(5) +#define EnUart BIT(8) +#define Uart_910 BIT(9) +#define EnPMAC BIT(10) +#define SIC_SWRST BIT(11) +#define EnSIC BIT(12) +#define SIC_23 BIT(13) +#define EnHDP BIT(14) +#define SIC_LBK BIT(15) + +#define LED0PL BIT(4) +#define LED1PL BIT(12) +#define LED0DIS BIT(7) + +#define MCUFWDL_EN BIT(0) +#define MCUFWDL_RDY BIT(1) +#define FWDL_CHKSUM_RPT BIT(2) +#define MACINI_RDY BIT(3) +#define BBINI_RDY BIT(4) +#define RFINI_RDY BIT(5) +#define WINTINI_RDY BIT(6) +#define CPRST BIT(23) + +#define XCLK_VLD BIT(0) +#define ACLK_VLD BIT(1) +#define UCLK_VLD BIT(2) +#define PCLK_VLD BIT(3) +#define PCIRSTB BIT(4) +#define V15_VLD BIT(5) +#define TRP_B15V_EN BIT(7) +#define SIC_IDLE BIT(8) +#define BD_MAC2 BIT(9) +#define BD_MAC1 BIT(10) +#define IC_MACPHY_MODE BIT(11) +#define VENDOR_ID BIT(19) +#define PAD_HWPD_IDN BIT(22) +#define TRP_VAUX_EN BIT(23) +#define TRP_BT_EN BIT(24) +#define BD_PKG_SEL BIT(25) +#define BD_HCI_SEL BIT(26) +#define TYPE_ID BIT(27) + +#define CHIP_VER_RTL_MASK 0xF000 +#define CHIP_VER_RTL_SHIFT 12 + +#define REG_LBMODE (REG_CR + 3) + +#define HCI_TXDMA_EN BIT(0) +#define HCI_RXDMA_EN BIT(1) +#define TXDMA_EN BIT(2) +#define RXDMA_EN BIT(3) +#define PROTOCOL_EN BIT(4) +#define SCHEDULE_EN BIT(5) +#define MACTXEN BIT(6) +#define MACRXEN BIT(7) +#define ENSWBCN BIT(8) +#define ENSEC BIT(9) + +#define _NETTYPE(x) (((x) & 0x3) << 16) +#define MASK_NETTYPE 0x30000 +#define NT_NO_LINK 0x0 +#define NT_LINK_AD_HOC 0x1 +#define NT_LINK_AP 0x2 +#define NT_AS_AP 0x3 + +#define _LBMODE(x) (((x) & 0xF) << 24) +#define MASK_LBMODE 0xF000000 +#define LOOPBACK_NORMAL 0x0 +#define LOOPBACK_IMMEDIATELY 0xB +#define LOOPBACK_MAC_DELAY 0x3 +#define LOOPBACK_PHY 0x1 +#define LOOPBACK_DMA 0x7 + +#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) +#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) +#define _PSRX_MASK 0xF +#define _PSTX_MASK 0xF0 +#define _PSRX(x) (x) +#define _PSTX(x) ((x) << 4) + +#define PBP_64 0x0 +#define PBP_128 0x1 +#define PBP_256 0x2 +#define PBP_512 0x3 +#define PBP_1024 0x4 + +#define RXDMA_ARBBW_EN BIT(0) +#define RXSHFT_EN BIT(1) +#define RXDMA_AGG_EN BIT(2) +#define QS_VO_QUEUE BIT(8) +#define QS_VI_QUEUE BIT(9) +#define QS_BE_QUEUE BIT(10) +#define QS_BK_QUEUE BIT(11) +#define QS_MANAGER_QUEUE BIT(12) +#define QS_HIGH_QUEUE BIT(13) + +#define HQSEL_VOQ BIT(0) +#define HQSEL_VIQ BIT(1) +#define HQSEL_BEQ BIT(2) +#define HQSEL_BKQ BIT(3) +#define HQSEL_MGTQ BIT(4) +#define HQSEL_HIQ BIT(5) + +#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) +#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) +#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) +#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8 ) +#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6 ) +#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4 ) + +#define QUEUE_LOW 1 +#define QUEUE_NORMAL 2 +#define QUEUE_HIGH 3 + +#define _LLT_NO_ACTIVE 0x0 +#define _LLT_WRITE_ACCESS 0x1 +#define _LLT_READ_ACCESS 0x2 + +#define _LLT_INIT_DATA(x) ((x) & 0xFF) +#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) +#define _LLT_OP(x) (((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) + +#define BB_WRITE_READ_MASK (BIT(31) | BIT(30)) +#define BB_WRITE_EN BIT(30) +#define BB_READ_EN BIT(31) + +#define _HPQ(x) ((x) & 0xFF) +#define _LPQ(x) (((x) & 0xFF) << 8) +#define _PUBQ(x) (((x) & 0xFF) << 16) +#define _NPQ(x) ((x) & 0xFF) + +#define HPQ_PUBLIC_DIS BIT(24) +#define LPQ_PUBLIC_DIS BIT(25) +#define LD_RQPN BIT(31) + +#define BCN_VALID BIT(16) +#define BCN_HEAD(x) (((x) & 0xFF) << 8) +#define BCN_HEAD_MASK 0xFF00 + +#define BLK_DESC_NUM_SHIFT 4 +#define BLK_DESC_NUM_MASK 0xF + +#define DROP_DATA_EN BIT(9) + +#define EN_AMPDU_RTY_NEW BIT(7) + +#define _INIRTSMCS_SEL(x) ((x) & 0x3F) + +#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) +#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) + +#define RATE_REG_BITMAP_ALL 0xFFFFF + +#define _RRSC_BITMAP(x) ((x) & 0xFFFFF) + +#define _RRSR_RSC(x) (((x) & 0x3) << 21) +#define RRSR_RSC_RESERVED 0x0 +#define RRSR_RSC_UPPER_SUBCHANNEL 0x1 +#define RRSR_RSC_LOWER_SUBCHANNEL 0x2 +#define RRSR_RSC_DUPLICATE_MODE 0x3 + +#define USE_SHORT_G1 BIT(20) + +#define _AGGLMT_MCS0(x) ((x) & 0xF) +#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4) +#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8) +#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12) +#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16) +#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20) +#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24) +#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28) + +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + +#define _DARF_RC1(x) ((x) & 0x1F) +#define _DARF_RC2(x) (((x) & 0x1F) << 8) +#define _DARF_RC3(x) (((x) & 0x1F) << 16) +#define _DARF_RC4(x) (((x) & 0x1F) << 24) +#define _DARF_RC5(x) ((x) & 0x1F) +#define _DARF_RC6(x) (((x) & 0x1F) << 8) +#define _DARF_RC7(x) (((x) & 0x1F) << 16) +#define _DARF_RC8(x) (((x) & 0x1F) << 24) + +#define _RARF_RC1(x) ((x) & 0x1F) +#define _RARF_RC2(x) (((x) & 0x1F) << 8) +#define _RARF_RC3(x) (((x) & 0x1F) << 16) +#define _RARF_RC4(x) (((x) & 0x1F) << 24) +#define _RARF_RC5(x) ((x) & 0x1F) +#define _RARF_RC6(x) (((x) & 0x1F) << 8) +#define _RARF_RC7(x) (((x) & 0x1F) << 16) +#define _RARF_RC8(x) (((x) & 0x1F) << 24) + +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +#define _AIFS(x) (x) +#define _ECW_MAX_MIN(x) ((x) << 8) +#define _TXOP_LIMIT(x) ((x) << 16) + +#define _BCNIFS(x) ((x) & 0xFF) +#define _BCNECW(x) ((((x) & 0xF))<< 8) + +#define _LRL(x) ((x) & 0x3F) +#define _SRL(x) (((x) & 0x3F) << 8) + +#define _SIFS_CCK_CTX(x) ((x) & 0xFF) +#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8); + +#define _SIFS_OFDM_CTX(x) ((x) & 0xFF) +#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8); + +#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8) + +#define DIS_EDCA_CNT_DWN BIT(11) + +#define EN_MBSSID BIT(1) +#define EN_TXBCN_RPT BIT(2) +#define EN_BCN_FUNCTION BIT(3) + +#define TSFTR_RST BIT(0) +#define TSFTR1_RST BIT(1) + +#define STOP_BCNQ BIT(6) + +#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) +#define DIS_TSF_UDT0_TEST_CHIP BIT(5) + +#define AcmHw_HwEn BIT(0) +#define AcmHw_BeqEn BIT(1) +#define AcmHw_ViqEn BIT(2) +#define AcmHw_VoqEn BIT(3) +#define AcmHw_BeqStatus BIT(4) +#define AcmHw_ViqStatus BIT(5) +#define AcmHw_VoqStatus BIT(6) + +#define APSDOFF BIT(6) +#define APSDOFF_STATUS BIT(7) + +#define BW_20MHZ BIT(2) + +#define RATE_BITMAP_ALL 0xFFFFF + +#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 + +#define TSFRST BIT(0) +#define DIS_GCLK BIT(1) +#define PAD_SEL BIT(2) +#define PWR_ST BIT(6) +#define PWRBIT_OW_EN BIT(7) +#define ACRC BIT(8) +#define CFENDFORM BIT(9) +#define ICV BIT(10) + +#define AAP BIT(0) +#define APM BIT(1) +#define AM BIT(2) +#define AB BIT(3) +#define ADD3 BIT(4) +#define APWRMGT BIT(5) +#define CBSSID BIT(6) +#define CBSSID_DATA BIT(6) +#define CBSSID_BCN BIT(7) +#define ACRC32 BIT(8) +#define AICV BIT(9) +#define ADF BIT(11) +#define ACF BIT(12) +#define AMF BIT(13) +#define HTC_LOC_CTRL BIT(14) +#define UC_DATA_EN BIT(16) +#define BM_DATA_EN BIT(17) +#define MFBEN BIT(22) +#define LSIGEN BIT(23) +#define EnMBID BIT(24) +#define APP_BASSN BIT(27) +#define APP_PHYSTS BIT(28) +#define APP_ICV BIT(29) +#define APP_MIC BIT(30) +#define APP_FCS BIT(31) + +#define _MIN_SPACE(x) ((x) & 0x7) +#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3) + +#define RXERR_TYPE_OFDM_PPDU 0 +#define RXERR_TYPE_OFDM_FALSE_ALARM 1 +#define RXERR_TYPE_OFDM_MPDU_OK 2 +#define RXERR_TYPE_OFDM_MPDU_FAIL 3 +#define RXERR_TYPE_CCK_PPDU 4 +#define RXERR_TYPE_CCK_FALSE_ALARM 5 +#define RXERR_TYPE_CCK_MPDU_OK 6 +#define RXERR_TYPE_CCK_MPDU_FAIL 7 +#define RXERR_TYPE_HT_PPDU 8 +#define RXERR_TYPE_HT_FALSE_ALARM 9 +#define RXERR_TYPE_HT_MPDU_TOTAL 10 +#define RXERR_TYPE_HT_MPDU_OK 11 +#define RXERR_TYPE_HT_MPDU_FAIL 12 +#define RXERR_TYPE_RX_FULL_DROP 15 + +#define RXERR_COUNTER_MASK 0xFFFFF +#define RXERR_RPT_RST BIT(27) +#define _RXERR_RPT_SEL(type) ((type) << 28) + +#define SCR_TxUseDK BIT(0) +#define SCR_RxUseDK BIT(1) +#define SCR_TxEncEnable BIT(2) +#define SCR_RxDecEnable BIT(3) +#define SCR_SKByA2 BIT(4) +#define SCR_NoSKMC BIT(5) +#define SCR_TXBCUSEDK BIT(6) +#define SCR_RXBCUSEDK BIT(7) + +#define XCLK_VLD BIT(0) +#define ACLK_VLD BIT(1) +#define UCLK_VLD BIT(2) +#define PCLK_VLD BIT(3) +#define PCIRSTB BIT(4) +#define V15_VLD BIT(5) +#define TRP_B15V_EN BIT(7) +#define SIC_IDLE BIT(8) +#define BD_MAC2 BIT(9) +#define BD_MAC1 BIT(10) +#define IC_MACPHY_MODE BIT(11) +#define BT_FUNC BIT(16) +#define VENDOR_ID BIT(19) +#define PAD_HWPD_IDN BIT(22) +#define TRP_VAUX_EN BIT(23) +#define TRP_BT_EN BIT(24) +#define BD_PKG_SEL BIT(25) +#define BD_HCI_SEL BIT(26) +#define TYPE_ID BIT(27) + +#define USB_IS_HIGH_SPEED 0 +#define USB_IS_FULL_SPEED 1 +#define USB_SPEED_MASK BIT(5) + +#define USB_NORMAL_SIE_EP_MASK 0xF +#define USB_NORMAL_SIE_EP_SHIFT 4 + +#define USB_TEST_EP_MASK 0x30 +#define USB_TEST_EP_SHIFT 4 + +#define USB_AGG_EN BIT(3) + +#define MAC_ADDR_LEN 6 +#define LAST_ENTRY_OF_TX_PKT_BUFFER 175/*255 88e*/ + +#define POLLING_LLT_THRESHOLD 20 +#define POLLING_READY_TIMEOUT_COUNT 3000 + +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_LOAD 1 + +#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE + +#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) + +#define RA_LSSIWRITE_8821A 0xc90 +#define RB_LSSIWRITE_8821A 0xe90 + +#define RA_PIREAD_8821A 0xd04 +#define RB_PIREAD_8821A 0xd44 +#define RA_SIREAD_8821A 0xd08 +#define RB_SIREAD_8821A 0xd48 + +#define RPMAC_RESET 0x100 +#define RPMAC_TXSTART 0x104 +#define RPMAC_TXLEGACYSIG 0x108 +#define RPMAC_TXHTSIG1 0x10c +#define RPMAC_TXHTSIG2 0x110 +#define RPMAC_PHYDEBUG 0x114 +#define RPMAC_TXPACKETNUM 0x118 +#define RPMAC_TXIDLE 0x11c +#define RPMAC_TXMACHEADER0 0x120 +#define RPMAC_TXMACHEADER1 0x124 +#define RPMAC_TXMACHEADER2 0x128 +#define RPMAC_TXMACHEADER3 0x12c +#define RPMAC_TXMACHEADER4 0x130 +#define RPMAC_TXMACHEADER5 0x134 +#define RPMAC_TXDADATYPE 0x138 +#define RPMAC_TXRANDOMSEED 0x13c +#define RPMAC_CCKPLCPPREAMBLE 0x140 +#define RPMAC_CCKPLCPHEADER 0x144 +#define RPMAC_CCKCRC16 0x148 +#define RPMAC_OFDMRXCRC32OK 0x170 +#define RPMAC_OFDMRXCRC32Er 0x174 +#define RPMAC_OFDMRXPARITYER 0x178 +#define RPMAC_OFDMRXCRC8ER 0x17c +#define RPMAC_CCKCRXRC16ER 0x180 +#define RPMAC_CCKCRXRC32ER 0x184 +#define RPMAC_CCKCRXRC32OK 0x188 +#define RPMAC_TXSTATUS 0x18c + +#define RFPGA0_RFMOD 0x800 + +#define RFPGA0_TXINFO 0x804 +#define RFPGA0_PSDFUNCTION 0x808 + +#define RFPGA0_TXGAINSTAGE 0x80c + +#define RFPGA0_RFTIMING1 0x810 +#define RFPGA0_RFTIMING2 0x814 + +#define RFPGA0_XA_HSSIPARAMETER1 0x820 +#define RFPGA0_XA_HSSIPARAMETER2 0x824 +#define RFPGA0_XB_HSSIPARAMETER1 0x828 +#define RFPGA0_XB_HSSIPARAMETER2 0x82c +#define RCCAONSEC 0x838 + +#define RFPGA0_XA_LSSIPARAMETER 0x840 +#define RFPGA0_XB_LSSIPARAMETER 0x844 +#define RL1PEAKTH 0x848 + +#define RFPGA0_RFWAKEUPPARAMETER 0x850 +#define RFPGA0_RFSLEEPUPPARAMETER 0x854 + +#define RFPGA0_XAB_SWITCHCONTROL 0x858 +#define RFPGA0_XCD_SWITCHCONTROL 0x85c + +#define RFPGA0_XA_RFINTERFACEOE 0x860 +#define RFC_AREA 0x860 +#define RFPGA0_XB_RFINTERFACEOE 0x864 + +#define RFPGA0_XAB_RFINTERFACESW 0x870 +#define RFPGA0_XCD_RFINTERFACESW 0x874 + +#define rFPGA0_XAB_RFPARAMETER 0x878 +#define rFPGA0_XCD_RFPARAMETER 0x87c + +#define RFPGA0_ANALOGPARAMETER1 0x880 +#define RFPGA0_ANALOGPARAMETER2 0x884 +#define RFPGA0_ANALOGPARAMETER3 0x888 +#define RFPGA0_ANALOGPARAMETER4 0x88c + +#define RFPGA0_XA_LSSIREADBACK 0x8a0 +#define RFPGA0_XB_LSSIREADBACK 0x8a4 +#define RFPGA0_XC_LSSIREADBACK 0x8a8 +//#define RFPGA0_XD_LSSIREADBACK 0x8ac +#define RRFMOD 0x8ac +#define RHSSIREAD_8821AE 0x8b0 + +#define RFPGA0_PSDREPORT 0x8b4 +#define TRANSCEIVEA_HSPI_READBACK 0x8b8 +#define TRANSCEIVEB_HSPI_READBACK 0x8bc +//#define REG_SC_CNT 0x8c4 +#define RADC_BUF_CLK 0x8c4 +#define RFPGA0_XAB_RFINTERFACERB 0x8e0 +#define RFPGA0_XCD_RFINTERFACERB 0x8e4 + +#define RFPGA1_RFMOD 0x900 + +#define RFPGA1_TXBLOCK 0x904 +#define RFPGA1_DEBUGSELECT 0x908 +#define RFPGA1_TXINFO 0x90c + +#define RCCK_SYSTEM 0xa00 +#define BCCK_SYSTEM 0x10 + + +#define RCCK0_AFESETTING 0xa04 +#define RCCK0_CCA 0xa08 + +#define RCCK0_RXAGC1 0xa0c +#define RCCK0_RXAGC2 0xa10 + +#define RCCK0_RXHP 0xa14 + +#define RCCK0_DSPPARAMETER1 0xa18 +#define RCCK0_DSPPARAMETER2 0xa1c + +#define RCCK0_TXFILTER1 0xa20 +#define RCCK0_TXFILTER2 0xa24 +#define RCCK0_DEBUGPORT 0xa28 +#define RCCK0_FALSEALARMREPORT 0xa2c +#define RCCK0_TRSSIREPORT 0xa50 +#define RCCK0_RXREPORT 0xa54 +#define RCCK0_FACOUNTERLOWER 0xa5c +#define RCCK0_FACOUNTERUPPER 0xa58 +#define RCCK0_CCA_CNT 0xa60 + + +/* PageB(0xB00) */ +#define rPdp_AntA 0xb00 +#define rPdp_AntA_4 0xb04 +#define rPdp_AntA_8 0xb08 +#define rPdp_AntA_C 0xb0c +#define rPdp_AntA_10 0xb10 +#define rPdp_AntA_14 0xb14 +#define rPdp_AntA_18 0xb18 +#define rPdp_AntA_1C 0xb1c +#define rPdp_AntA_20 0xb20 +#define rPdp_AntA_24 0xb24 + +#define rConfig_Pmpd_AntA 0xb28 +#define rConfig_ram64x16 0xb2c + +#define rBndA 0xb30 +#define rHssiPar 0xb34 + +#define rConfig_AntA 0xb68 +#define rConfig_AntB 0xb6c + +#define rPdp_AntB 0xb70 +#define rPdp_AntB_4 0xb74 +#define rPdp_AntB_8 0xb78 +#define rPdp_AntB_C 0xb7c +#define rPdp_AntB_10 0xb80 +#define rPdp_AntB_14 0xb84 +#define rPdp_AntB_18 0xb88 +#define rPdp_AntB_1C 0xb8c +#define rPdp_AntB_20 0xb90 +#define rPdp_AntB_24 0xb94 + +#define rConfig_Pmpd_AntB 0xb98 + +#define rBndB 0xba0 + +#define rAPK 0xbd8 +#define rPm_Rx0_AntA 0xbdc +#define rPm_Rx1_AntA 0xbe0 +#define rPm_Rx2_AntA 0xbe4 +#define rPm_Rx3_AntA 0xbe8 +#define rPm_Rx0_AntB 0xbec +#define rPm_Rx1_AntB 0xbf0 +#define rPm_Rx2_AntB 0xbf4 +#define rPm_Rx3_AntB 0xbf8 + +/*RSSI Dump*/ +#define RA_RSSI_DUMP 0xBF0 +#define RB_RSSI_DUMP 0xBF1 +#define RS1_RX_EVM_DUMP 0xBF4 +#define RS2_RX_EVM_DUMP 0xBF5 +#define RA_RX_SNR_DUMP 0xBF6 +#define RB_RX_SNR_DUMP 0xBF7 +#define RA_CFO_SHORT_DUMP 0xBF8 +#define RB_CFO_SHORT_DUMP 0xBFA +#define RA_CFO_LONG_DUMP 0xBEC +#define RB_CFO_LONG_DUMP 0xBEE + +/*Page C*/ +#define ROFDM0_LSTF 0xc00 + +#define ROFDM0_TRXPATHENABLE 0xc04 +#define ROFDM0_TRMUXPAR 0xc08 +#define ROFDM0_TRSWISOLATION 0xc0c + +#define ROFDM0_XARXAFE 0xc10 +#define ROFDM0_XARXIQIMBALANCE 0xc14 +#define ROFDM0_XBRXAFE 0xc18 +#define ROFDM0_XBRXIQIMBALANCE 0xc1c +#define ROFDM0_XCRXAFE 0xc20 +#define ROFDM0_XCRXIQIMBANLANCE 0xc24 +#define ROFDM0_XDRXAFE 0xc28 +#define ROFDM0_XDRXIQIMBALANCE 0xc2c + +#define ROFDM0_RXDETECTOR1 0xc30 +#define ROFDM0_RXDETECTOR2 0xc34 +#define ROFDM0_RXDETECTOR3 0xc38 +#define ROFDM0_RXDETECTOR4 0xc3c + +#define ROFDM0_RXDSP 0xc40 +#define ROFDM0_CFOANDDAGC 0xc44 +#define ROFDM0_CCADROPTHRESHOLD 0xc48 +#define ROFDM0_ECCATHRESHOLD 0xc4c + +#define ROFDM0_XAAGCCORE1 0xc50 +#define ROFDM0_XAAGCCORE2 0xc54 +#define ROFDM0_XBAGCCORE1 0xc58 +#define ROFDM0_XBAGCCORE2 0xc5c +#define ROFDM0_XCAGCCORE1 0xc60 +#define ROFDM0_XCAGCCORE2 0xc64 +#define ROFDM0_XDAGCCORE1 0xc68 +#define ROFDM0_XDAGCCORE2 0xc6c + +#define ROFDM0_AGCPARAMETER1 0xc70 +#define ROFDM0_AGCPARAMETER2 0xc74 +#define ROFDM0_AGCRSSITABLE 0xc78 +#define ROFDM0_HTSTFAGC 0xc7c + +#define ROFDM0_XATXIQIMBALANCE 0xc80 +#define ROFDM0_XATXAFE 0xc84 +#define ROFDM0_XBTXIQIMBALANCE 0xc88 +#define ROFDM0_XBTXAFE 0xc8c +#define ROFDM0_XCTXIQIMBALANCE 0xc90 +#define ROFDM0_XCTXAFE 0xc94 +#define ROFDM0_XDTXIQIMBALANCE 0xc98 +#define ROFDM0_XDTXAFE 0xc9c + +#define ROFDM0_RXIQEXTANTA 0xca0 +#define ROFDM0_TXCOEFF1 0xca4 +#define ROFDM0_TXCOEFF2 0xca8 +#define ROFDM0_TXCOEFF3 0xcac +#define ROFDM0_TXCOEFF4 0xcb0 +#define ROFDM0_TXCOEFF5 0xcb4 +#define ROFDM0_TXCOEFF6 0xcb8 + +/*Path_A RFE cotrol */ +#define RA_RFE_CTRL_8812 0xcb8 +/*Path_B RFE control*/ +#define RB_RFE_CTRL_8812 0xeb8 + +#define ROFDM0_RXHPPARAMETER 0xce0 +#define ROFDM0_TXPSEUDONOISEWGT 0xce4 +#define ROFDM0_FRAMESYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 + + +#define ROFDM1_LSTF 0xd00 +#define ROFDM1_TRXPATHENABLE 0xd04 + +#define ROFDM1_CF0 0xd08 +#define ROFDM1_CSI1 0xd10 +#define ROFDM1_SBD 0xd14 +#define ROFDM1_CSI2 0xd18 +#define ROFDM1_CFOTRACKING 0xd2c +#define ROFDM1_TRXMESAURE1 0xd34 +#define ROFDM1_INTFDET 0xd3c +#define ROFDM1_PSEUDONOISESTATEAB 0xd50 +#define ROFDM1_PSEUDONOISESTATECD 0xd54 +#define ROFDM1_RXPSEUDONOISEWGT 0xd58 + +#define ROFDM_PHYCOUNTER1 0xda0 +#define ROFDM_PHYCOUNTER2 0xda4 +#define ROFDM_PHYCOUNTER3 0xda8 + +#define ROFDM_SHORTCFOAB 0xdac +#define ROFDM_SHORTCFOCD 0xdb0 +#define ROFDM_LONGCFOAB 0xdb4 +#define ROFDM_LONGCFOCD 0xdb8 +#define ROFDM_TAILCF0AB 0xdbc +#define ROFDM_TAILCF0CD 0xdc0 +#define ROFDM_PWMEASURE1 0xdc4 +#define ROFDM_PWMEASURE2 0xdc8 +#define ROFDM_BWREPORT 0xdcc +#define ROFDM_AGCREPORT 0xdd0 +#define ROFDM_RXSNR 0xdd4 +#define ROFDM_RXEVMCSI 0xdd8 +#define ROFDM_SIGREPORT 0xddc + +#define RTXAGC_A_CCK11_CCK1 0xc20 +#define RTXAGC_A_OFDM18_OFDM6 0xc24 +#define RTXAGC_A_OFDM54_OFDM24 0xc28 +#define RTXAGC_A_MCS03_MCS00 0xc2c +#define RTXAGC_A_MCS07_MCS04 0xc30 +#define RTXAGC_A_MCS11_MCS08 0xc34 +#define RTXAGC_A_MCS15_MCS12 0xc38 +#define RTXAGC_A_NSS1INDEX3_NSS1INDEX0 0xc3c +#define RTXAGC_A_NSS1INDEX7_NSS1INDEX4 0xc40 +#define RTXAGC_A_NSS2INDEX1_NSS1INDEX8 0xc44 +#define RTXAGC_A_NSS2INDEX5_NSS2INDEX2 0xc48 +#define RTXAGC_A_NSS2INDEX9_NSS2INDEX6 0xc4c +#define RTXAGC_B_CCK11_CCK1 0xe20 +#define RTXAGC_B_OFDM18_OFDM6 0xe24 +#define RTXAGC_B_OFDM54_OFDM24 0xe28 +#define RTXAGC_B_MCS03_MCS00 0xe2c +#define RTXAGC_B_MCS07_MCS04 0xe30 +#define RTXAGC_B_MCS11_MCS08 0xe34 +#define RTXAGC_B_MCS15_MCS12 0xe38 +#define RTXAGC_B_NSS1INDEX3_NSS1INDEX0 0xe3c +#define RTXAGC_B_NSS1INDEX7_NSS1INDEX4 0xe40 +#define RTXAGC_B_NSS2INDEX1_NSS1INDEX8 0xe44 +#define RTXAGC_B_NSS2INDEX5_NSS2INDEX2 0xe48 +#define RTXAGC_B_NSS2INDEX9_NSS2INDEX6 0xe4c + +#define RA_TXPWRTRAING 0xc54 +#define RB_TXPWRTRAING 0xe54 + + +#define RFPGA0_IQK 0xe28 +#define RTx_IQK_Tone_A 0xe30 +#define RRx_IQK_Tone_A 0xe34 +#define RTx_IQK_PI_A 0xe38 +#define RRx_IQK_PI_A 0xe3c + +#define RTx_IQK 0xe40 +#define RRx_IQK 0xe44 +#define RIQK_AGC_Pts 0xe48 +#define RIQK_AGC_Rsp 0xe4c +#define RTx_IQK_Tone_B 0xe50 +#define RRx_IQK_Tone_B 0xe54 +#define RTx_IQK_PI_B 0xe58 +#define RRx_IQK_PI_B 0xe5c +#define RIQK_AGC_Cont 0xe60 + +#define RBlue_Tooth 0xe6c +#define RRx_Wait_CCA 0xe70 +#define RTx_CCK_RFON 0xe74 +#define RTx_CCK_BBON 0xe78 +#define RTx_OFDM_RFON 0xe7c +#define RTx_OFDM_BBON 0xe80 +#define RTx_To_Rx 0xe84 +#define RTx_To_Tx 0xe88 +#define RRx_CCK 0xe8c + +#define RTx_Power_Before_IQK_A 0xe94 +#define RTx_Power_After_IQK_A 0xe9c + +#define RRx_Power_Before_IQK_A 0xea0 +#define RRx_Power_Before_IQK_A_2 0xea4 +#define RRx_Power_After_IQK_A 0xea8 +#define RRx_Power_After_IQK_A_2 0xeac + +#define RTx_Power_Before_IQK_B 0xeb4 +#define RTx_Power_After_IQK_B 0xebc + +#define RRx_Power_Before_IQK_B 0xec0 +#define RRx_Power_Before_IQK_B_2 0xec4 +#define RRx_Power_After_IQK_B 0xec8 +#define RRx_Power_After_IQK_B_2 0xecc + +#define RRx_OFDM 0xed0 +#define RRx_Wait_RIFS 0xed4 +#define RRx_TO_Rx 0xed8 +#define RStandby 0xedc +#define RSleep 0xee0 +#define RPMPD_ANAEN 0xeec + +#define RZEBRA1_HSSIENABLE 0x0 +#define RZEBRA1_TRXENABLE1 0x1 +#define RZEBRA1_TRXENABLE2 0x2 +#define RZEBRA1_AGC 0x4 +#define RZEBRA1_CHARGEPUMP 0x5 +#define RZEBRA1_CHANNEL 0x7 + +#define RZEBRA1_TXGAIN 0x8 +#define RZEBRA1_TXLPF 0x9 +#define RZEBRA1_RXLPF 0xb +#define RZEBRA1_RXHPFCORNER 0xc + +#define RGLOBALCTRL 0 +#define RRTL8256_TXLPF 19 +#define RRTL8256_RXLPF 11 +#define RRTL8258_TXLPF 0x11 +#define RRTL8258_RXLPF 0x13 +#define RRTL8258_RSSILPF 0xa + +#define RF_AC 0x00 + +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_POW_TRSW 0x05 + +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 + +#define RF_TXM_IDAC 0x08 +#define RF_BS_IQGEN 0x0F + +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 + +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define RRFCHANNEL 0x18 +#define RF_CHNLBW 0x18 +#define RF_TOP 0x19 + +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B + +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D + +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F + +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 + +#define RF_TX_BB1 0x23 +#define RF_T_METER 0x24 +#define RF_T_METER_88E 0x42 +#define RF_T_METER_8812A 0x42 + +#define RF_SYN_G1 0x25 +#define RF_SYN_G2 0x26 +#define RF_SYN_G3 0x27 +#define RF_SYN_G4 0x28 +#define RF_SYN_G5 0x29 +#define RF_SYN_G6 0x2A +#define RF_SYN_G7 0x2B +#define RF_SYN_G8 0x2C + +#define RF_RCK_OS 0x30 +#define RF_TXPA_G1 0x31 +#define RF_TXPA_G2 0x32 +#define RF_TXPA_G3 0x33 + +#define RF_TX_BIAS_A 0x35 +#define RF_TX_BIAS_D 0x36 +#define RF_LOBF_9 0x38 +#define RF_RXRF_A3 0x3C +#define RF_TRSW 0x3F + +#define RF_TXRF_A2 0x41 +#define RF_TXPA_G4 0x46 +#define RF_TXPA_A4 0x4B + +#define RF_APK 0x63 + +#define RF_WE_LUT 0xEF + +#define BBBRESETB 0x100 +#define BGLOBALRESETB 0x200 +#define BOFDMTXSTART 0x4 +#define BCCKTXSTART 0x8 +#define BCRC32DEBUG 0x100 +#define BPMACLOOPBACK 0x10 +#define BTXLSIG 0xffffff +#define BOFDMTXRATE 0xf +#define BOFDMTXRESERVED 0x10 +#define BOFDMTXLENGTH 0x1ffe0 +#define BOFDMTXPARITY 0x20000 +#define BTXHTSIG1 0xffffff +#define BTXHTMCSRATE 0x7f +#define BTXHTBW 0x80 +#define BTXHTLENGTH 0xffff00 +#define BTXHTSIG2 0xffffff +#define BTXHTSMOOTHING 0x1 +#define BTXHTSOUNDING 0x2 +#define BTXHTRESERVED 0x4 +#define BTXHTAGGREATION 0x8 +#define BTXHTSTBC 0x30 +#define BTXHTADVANCECODING 0x40 +#define BTXHTSHORTGI 0x80 +#define BTXHTNUMBERHT_LTF 0x300 +#define BTXHTCRC8 0x3fc00 +#define BCOUNTERRESET 0x10000 +#define BNUMOFOFDMTX 0xffff +#define BNUMOFCCKTX 0xffff0000 +#define BTXIDLEINTERVAL 0xffff +#define BOFDMSERVICE 0xffff0000 +#define BTXMACHEADER 0xffffffff +#define BTXDATAINIT 0xff +#define BTXHTMODE 0x100 +#define BTXDATATYPE 0x30000 +#define BTXRANDOMSEED 0xffffffff +#define BCCKTXPREAMBLE 0x1 +#define BCCKTXSFD 0xffff0000 +#define BCCKTXSIG 0xff +#define BCCKTXSERVICE 0xff00 +#define BCCKLENGTHEXT 0x8000 +#define BCCKTXLENGHT 0xffff0000 +#define BCCKTXCRC16 0xffff +#define BCCKTXSTATUS 0x1 +#define BOFDMTXSTATUS 0x2 +#define IS_BB_REG_OFFSET_92S(_Offset) \ + ((_Offset >= 0x800) && (_Offset <= 0xfff)) + +#define BRFMOD 0x1 +#define BJAPANMODE 0x2 +#define BCCKTXSC 0x30 +/* Block & Path enable*/ +#define ROFDMCCKEN 0x808 +#define BCCKEN 0x10000000 +#define BOFDMEN 0x20000000 +#define RRXPATH 0x808 /* Rx antenna*/ +#define BRXPATH 0xff +#define RTXPATH 0x80c /* Tx antenna*/ +#define BTXPATH 0x0fffffff +#define RCCK_RX 0xa04 /* for cck rx path selection*/ +#define BCCK_RX 0x0c000000 +#define RVHTLEN_USE_LSIG 0x8c3 /* Use LSIG for VHT length*/ + + +#define BOFDMRXADCPHASE 0x10000 +#define BOFDMTXDACPHASE 0x40000 +#define BXATXAGC 0x3f + +#define BXBTXAGC 0xf00 +#define BXCTXAGC 0xf000 +#define BXDTXAGC 0xf0000 + +#define BPASTART 0xf0000000 +#define BTRSTART 0x00f00000 +#define BRFSTART 0x0000f000 +#define BBBSTART 0x000000f0 +#define BBBCCKSTART 0x0000000f +#define BPAEND 0xf +#define BTREND 0x0f000000 +#define BRFEND 0x000f0000 +#define BCCAMASK 0x000000f0 +#define BR2RCCAMASK 0x00000f00 +#define BHSSI_R2TDELAY 0xf8000000 +#define BHSSI_T2RDELAY 0xf80000 +#define BCONTXHSSI 0x400 +#define BIGFROMCCK 0x200 +#define BAGCADDRESS 0x3f +#define BRXHPTX 0x7000 +#define BRXHP2RX 0x38000 +#define BRXHPCCKINI 0xc0000 +#define BAGCTXCODE 0xc00000 +#define BAGCRXCODE 0x300000 + +#define B3WIREDATALENGTH 0x800 +#define B3WIREADDREAALENGTH 0x400 + +#define B3WIRERFPOWERDOWN 0x1 +#define B5GPAPEPOLARITY 0x40000000 +#define B2GPAPEPOLARITY 0x80000000 +#define BRFSW_TXDEFAULTANT 0x3 +#define BRFSW_TXOPTIONANT 0x30 +#define BRFSW_RXDEFAULTANT 0x300 +#define BRFSW_RXOPTIONANT 0x3000 +#define BRFSI_3WIREDATA 0x1 +#define BRFSI_3WIRECLOCK 0x2 +#define BRFSI_3WIRELOAD 0x4 +#define BRFSI_3WIRERW 0x8 +#define BRFSI_3WIRE 0xf + +#define BRFSI_RFENV 0x10 + +#define BRFSI_TRSW 0x20 +#define BRFSI_TRSWB 0x40 +#define BRFSI_ANTSW 0x100 +#define BRFSI_ANTSWB 0x200 +#define BRFSI_PAPE 0x400 +#define BRFSI_PAPE5G 0x800 +#define BBANDSELECT 0x1 +#define BHTSIG2_GI 0x80 +#define BHTSIG2_SMOOTHING 0x01 +#define BHTSIG2_SOUNDING 0x02 +#define BHTSIG2_AGGREATON 0x08 +#define BHTSIG2_STBC 0x30 +#define BHTSIG2_ADVCODING 0x40 +#define BHTSIG2_NUMOFHTLTF 0x300 +#define BHTSIG2_CRC8 0x3fc +#define BHTSIG1_MCS 0x7f +#define BHTSIG1_BANDWIDTH 0x80 +#define BHTSIG1_HTLENGTH 0xffff +#define BLSIG_RATE 0xf +#define BLSIG_RESERVED 0x10 +#define BLSIG_LENGTH 0x1fffe +#define BLSIG_PARITY 0x20 +#define BCCKRXPHASE 0x4 + +#define BLSSIREADADDRESS 0x7f800000 +#define BLSSIREADEDGE 0x80000000 + +#define BLSSIREADBACKDATA 0xfffff + +#define BLSSIREADOKFLAG 0x1000 +#define BCCKSAMPLERATE 0x8 +#define BREGULATOR0STANDBY 0x1 +#define BREGULATORPLLSTANDBY 0x2 +#define BREGULATOR1STANDBY 0x4 +#define BPLLPOWERUP 0x8 +#define BDPLLPOWERUP 0x10 +#define BDA10POWERUP 0x20 +#define BAD7POWERUP 0x200 +#define BDA6POWERUP 0x2000 +#define BXTALPOWERUP 0x4000 +#define B40MDCLKPOWERUP 0x8000 +#define BDA6DEBUGMODE 0x20000 +#define BDA6SWING 0x380000 + +#define BADCLKPHASE 0x4000000 +#define B80MCLKDELAY 0x18000000 +#define BAFEWATCHDOGENABLE 0x20000000 + +#define BXTALCAP01 0xc0000000 +#define BXTALCAP23 0x3 +#define BXTALCAP92X 0x0f000000 +#define BXTALCAP 0x0f000000 + +#define BINTDIFCLKENABLE 0x400 +#define BEXTSIGCLKENABLE 0x800 +#define BBANDGAP_MBIAS_POWERUP 0x10000 +#define BAD11SH_GAIN 0xc0000 +#define BAD11NPUT_RANGE 0x700000 +#define BAD110P_CURRENT 0x3800000 +#define BLPATH_LOOPBACK 0x4000000 +#define BQPATH_LOOPBACK 0x8000000 +#define BAFE_LOOPBACK 0x10000000 +#define BDA10_SWING 0x7e0 +#define BDA10_REVERSE 0x800 +#define BDA_CLK_SOURCE 0x1000 +#define BDA7INPUT_RANGE 0x6000 +#define BDA7_GAIN 0x38000 +#define BDA7OUTPUT_CM_MODE 0x40000 +#define BDA7INPUT_CM_MODE 0x380000 +#define BDA7CURRENT 0xc00000 +#define BREGULATOR_ADJUST 0x7000000 +#define BAD11POWERUP_ATTX 0x1 +#define BDA10PS_ATTX 0x10 +#define BAD11POWERUP_ATRX 0x100 +#define BDA10PS_ATRX 0x1000 +#define BCCKRX_AGC_FORMAT 0x200 +#define BPSDFFT_SAMPLE_POINT 0xc000 +#define BPSD_AVERAGE_NUM 0x3000 +#define BIQPATH_CONTROL 0xc00 +#define BPSD_FREQ 0x3ff +#define BPSD_ANTENNA_PATH 0x30 +#define BPSD_IQ_SWITCH 0x40 +#define BPSD_RX_TRIGGER 0x400000 +#define BPSD_TX_TRIGGER 0x80000000 +#define BPSD_SINE_TONE_SCALE 0x7f000000 +#define BPSD_REPORT 0xffff + +#define BOFDM_TXSC 0x30000000 +#define BCCK_TXON 0x1 +#define BOFDM_TXON 0x2 +#define BDEBUG_PAGE 0xfff +#define BDEBUG_ITEM 0xff +#define BANTL 0x10 +#define BANT_NONHT 0x100 +#define BANT_HT1 0x1000 +#define BANT_HT2 0x10000 +#define BANT_HT1S1 0x100000 +#define BANT_NONHTS1 0x1000000 + +#define BCCK_BBMODE 0x3 +#define BCCK_TXPOWERSAVING 0x80 +#define BCCK_RXPOWERSAVING 0x40 + +#define BCCK_SIDEBAND 0x10 + +#define BCCK_SCRAMBLE 0x8 +#define BCCK_ANTDIVERSITY 0x8000 +#define BCCK_CARRIER_RECOVERY 0x4000 +#define BCCK_TXRATE 0x3000 +#define BCCK_DCCANCEL 0x0800 +#define BCCK_ISICANCEL 0x0400 +#define BCCK_MATCH_FILTER 0x0200 +#define BCCK_EQUALIZER 0x0100 +#define BCCK_PREAMBLE_DETECT 0x800000 +#define BCCK_FAST_FALSECCA 0x400000 +#define BCCK_CH_ESTSTART 0x300000 +#define BCCK_CCA_COUNT 0x080000 +#define BCCK_CS_LIM 0x070000 +#define BCCK_BIST_MODE 0x80000000 +#define BCCK_CCAMASK 0x40000000 +#define BCCK_TX_DAC_PHASE 0x4 +#define BCCK_RX_ADC_PHASE 0x20000000 +#define BCCKR_CP_MODE 0x0100 +#define BCCK_TXDC_OFFSET 0xf0 +#define BCCK_RXDC_OFFSET 0xf +#define BCCK_CCA_MODE 0xc000 +#define BCCK_FALSECS_LIM 0x3f00 +#define BCCK_CS_RATIO 0xc00000 +#define BCCK_CORGBIT_SEL 0x300000 +#define BCCK_PD_LIM 0x0f0000 +#define BCCK_NEWCCA 0x80000000 +#define BCCK_RXHP_OF_IG 0x8000 +#define BCCK_RXIG 0x7f00 +#define BCCK_LNA_POLARITY 0x800000 +#define BCCK_RX1ST_BAIN 0x7f0000 +#define BCCK_RF_EXTEND 0x20000000 +#define BCCK_RXAGC_SATLEVEL 0x1f000000 +#define BCCK_RXAGC_SATCOUNT 0xe0 +#define bCCKRxRFSettle 0x1f +#define BCCK_FIXED_RXAGC 0x8000 +#define BCCK_ANTENNA_POLARITY 0x2000 +#define BCCK_TXFILTER_TYPE 0x0c00 +#define BCCK_RXAGC_REPORTTYPE 0x0300 +#define BCCK_RXDAGC_EN 0x80000000 +#define BCCK_RXDAGC_PERIOD 0x20000000 +#define BCCK_RXDAGC_SATLEVEL 0x1f000000 +#define BCCK_TIMING_RECOVERY 0x800000 +#define BCCK_TXC0 0x3f0000 +#define BCCK_TXC1 0x3f000000 +#define BCCK_TXC2 0x3f +#define BCCK_TXC3 0x3f00 +#define BCCK_TXC4 0x3f0000 +#define BCCK_TXC5 0x3f000000 +#define BCCK_TXC6 0x3f +#define BCCK_TXC7 0x3f00 +#define BCCK_DEBUGPORT 0xff0000 +#define BCCK_DAC_DEBUG 0x0f000000 +#define BCCK_FALSEALARM_ENABLE 0x8000 +#define BCCK_FALSEALARM_READ 0x4000 +#define BCCK_TRSSI 0x7f +#define BCCK_RXAGC_REPORT 0xfe +#define BCCK_RXREPORT_ANTSEL 0x80000000 +#define BCCK_RXREPORT_MFOFF 0x40000000 +#define BCCK_RXREPORT_SQLOSS 0x20000000 +#define BCCK_RXREPORT_PKTLOSS 0x10000000 +#define BCCK_RXREPORT_LOCKEDBIT 0x08000000 +#define BCCK_RXREPORT_RATEERROR 0x04000000 +#define BCCK_RXREPORT_RXRATE 0x03000000 +#define BCCK_RXFA_COUNTER_LOWER 0xff +#define BCCK_RXFA_COUNTER_UPPER 0xff000000 +#define BCCK_RXHPAGC_START 0xe000 +#define BCCK_RXHPAGC_FINAL 0x1c00 +#define BCCK_RXFALSEALARM_ENABLE 0x8000 +#define BCCK_FACOUNTER_FREEZE 0x4000 +#define BCCK_TXPATH_SEL 0x10000000 +#define BCCK_DEFAULT_RXPATH 0xc000000 +#define BCCK_OPTION_RXPATH 0x3000000 + +#define BNUM_OFSTF 0x3 +#define BSHIFT_L 0xc0 +#define BGI_TH 0xc +#define BRXPATH_A 0x1 +#define BRXPATH_B 0x2 +#define BRXPATH_C 0x4 +#define BRXPATH_D 0x8 +#define BTXPATH_A 0x1 +#define BTXPATH_B 0x2 +#define BTXPATH_C 0x4 +#define BTXPATH_D 0x8 +#define BTRSSI_FREQ 0x200 +#define BADC_BACKOFF 0x3000 +#define BDFIR_BACKOFF 0xc000 +#define BTRSSI_LATCH_PHASE 0x10000 +#define BRX_LDC_OFFSET 0xff +#define BRX_QDC_OFFSET 0xff00 +#define BRX_DFIR_MODE 0x1800000 +#define BRX_DCNF_TYPE 0xe000000 +#define BRXIQIMB_A 0x3ff +#define BRXIQIMB_B 0xfc00 +#define BRXIQIMB_C 0x3f0000 +#define BRXIQIMB_D 0xffc00000 +#define BDC_DC_NOTCH 0x60000 +#define BRXNB_NOTCH 0x1f000000 +#define BPD_TH 0xf +#define BPD_TH_OPT2 0xc000 +#define BPWED_TH 0x700 +#define BIFMF_WIN_L 0x800 +#define BPD_OPTION 0x1000 +#define BMF_WIN_L 0xe000 +#define BBW_SEARCH_L 0x30000 +#define BWIN_ENH_L 0xc0000 +#define BBW_TH 0x700000 +#define BED_TH2 0x3800000 +#define BBW_OPTION 0x4000000 +#define BRADIO_TH 0x18000000 +#define BWINDOW_L 0xe0000000 +#define BSBD_OPTION 0x1 +#define BFRAME_TH 0x1c +#define BFS_OPTION 0x60 +#define BDC_SLOPE_CHECK 0x80 +#define BFGUARD_COUNTER_DC_L 0xe00 +#define BFRAME_WEIGHT_SHORT 0x7000 +#define BSUB_TUNE 0xe00000 +#define BFRAME_DC_LENGTH 0xe000000 +#define BSBD_START_OFFSET 0x30000000 +#define BFRAME_TH_2 0x7 +#define BFRAME_GI2_TH 0x38 +#define BGI2_SYNC_EN 0x40 +#define BSARCH_SHORT_EARLY 0x300 +#define BSARCH_SHORT_LATE 0xc00 +#define BSARCH_GI2_LATE 0x70000 +#define BCFOANTSUM 0x1 +#define BCFOACC 0x2 +#define BCFOSTARTOFFSET 0xc +#define BCFOLOOPBACK 0x70 +#define BCFOSUMWEIGHT 0x80 +#define BDAGCENABLE 0x10000 +#define BTXIQIMB_A 0x3ff +#define BTXIQIMB_b 0xfc00 +#define BTXIQIMB_C 0x3f0000 +#define BTXIQIMB_D 0xffc00000 +#define BTXIDCOFFSET 0xff +#define BTXIQDCOFFSET 0xff00 +#define BTXDFIRMODE 0x10000 +#define BTXPESUDO_NOISEON 0x4000000 +#define BTXPESUDO_NOISE_A 0xff +#define BTXPESUDO_NOISE_B 0xff00 +#define BTXPESUDO_NOISE_C 0xff0000 +#define BTXPESUDO_NOISE_D 0xff000000 +#define BCCA_DROPOPTION 0x20000 +#define BCCA_DROPTHRES 0xfff00000 +#define BEDCCA_H 0xf +#define BEDCCA_L 0xf0 +#define BLAMBDA_ED 0x300 +#define BRX_INITIALGAIN 0x7f +#define BRX_ANTDIV_EN 0x80 +#define BRX_AGC_ADDRESS_FOR_LNA 0x7f00 +#define BRX_HIGHPOWER_FLOW 0x8000 +#define BRX_AGC_FREEZE_THRES 0xc0000 +#define BRX_FREEZESTEP_AGC1 0x300000 +#define BRX_FREEZESTEP_AGC2 0xc00000 +#define BRX_FREEZESTEP_AGC3 0x3000000 +#define BRX_FREEZESTEP_AGC0 0xc000000 +#define BRXRSSI_CMP_EN 0x10000000 +#define BRXQUICK_AGCEN 0x20000000 +#define BRXAGC_FREEZE_THRES_MODE 0x40000000 +#define BRX_OVERFLOW_CHECKTYPE 0x80000000 +#define BRX_AGCSHIFT 0x7f +#define BTRSW_TRI_ONLY 0x80 +#define BPOWER_THRES 0x300 +#define BRXAGC_EN 0x1 +#define BRXAGC_TOGETHER_EN 0x2 +#define BRXAGC_MIN 0x4 +#define BRXHP_INI 0x7 +#define BRXHP_TRLNA 0x70 +#define BRXHP_RSSI 0x700 +#define BRXHP_BBP1 0x7000 +#define BRXHP_BBP2 0x70000 +#define BRXHP_BBP3 0x700000 +#define BRSSI_H 0x7f0000 +#define BRSSI_GEN 0x7f000000 +#define BRXSETTLE_TRSW 0x7 +#define BRXSETTLE_LNA 0x38 +#define BRXSETTLE_RSSI 0x1c0 +#define BRXSETTLE_BBP 0xe00 +#define BRXSETTLE_RXHP 0x7000 +#define BRXSETTLE_ANTSW_RSSI 0x38000 +#define BRXSETTLE_ANTSW 0xc0000 +#define BRXPROCESS_TIME_DAGC 0x300000 +#define BRXSETTLE_HSSI 0x400000 +#define BRXPROCESS_TIME_BBPPW 0x800000 +#define BRXANTENNA_POWER_SHIFT 0x3000000 +#define BRSSI_TABLE_SELECT 0xc000000 +#define BRXHP_FINAL 0x7000000 +#define BRXHPSETTLE_BBP 0x7 +#define BRXHTSETTLE_HSSI 0x8 +#define BRXHTSETTLE_RXHP 0x70 +#define BRXHTSETTLE_BBPPW 0x80 +#define BRXHTSETTLE_IDLE 0x300 +#define BRXHTSETTLE_RESERVED 0x1c00 +#define BRXHT_RXHP_EN 0x8000 +#define BRXAGC_FREEZE_THRES 0x30000 +#define BRXAGC_TOGETHEREN 0x40000 +#define BRXHTAGC_MIN 0x80000 +#define BRXHTAGC_EN 0x100000 +#define BRXHTDAGC_EN 0x200000 +#define BRXHT_RXHP_BBP 0x1c00000 +#define BRXHT_RXHP_FINAL 0xe0000000 +#define BRXPW_RADIO_TH 0x3 +#define BRXPW_RADIO_EN 0x4 +#define BRXMF_HOLD 0x3800 +#define BRXPD_DELAY_TH1 0x38 +#define BRXPD_DELAY_TH2 0x1c0 +#define BRXPD_DC_COUNT_MAX 0x600 +#define BRXPD_DELAY_TH 0x8000 +#define BRXPROCESS_DELAY 0xf0000 +#define BRXSEARCHRANGE_GI2_EARLY 0x700000 +#define BRXFRAME_FUARD_COUNTER_L 0x3800000 +#define BRXSGI_GUARD_L 0xc000000 +#define BRXSGI_SEARCH_L 0x30000000 +#define BRXSGI_TH 0xc0000000 +#define BDFSCNT0 0xff +#define BDFSCNT1 0xff00 +#define BDFSFLAG 0xf0000 +#define BMF_WEIGHT_SUM 0x300000 +#define BMINIDX_TH 0x7f000000 +#define BDAFORMAT 0x40000 +#define BTXCH_EMU_ENABLE 0x01000000 +#define BTRSW_ISOLATION_A 0x7f +#define BTRSW_ISOLATION_B 0x7f00 +#define BTRSW_ISOLATION_C 0x7f0000 +#define BTRSW_ISOLATION_D 0x7f000000 +#define BEXT_LNA_GAIN 0x7c00 + +#define BSTBC_EN 0x4 +#define BANTENNA_MAPPING 0x10 +#define BNSS 0x20 +#define BCFO_ANTSUM_ID 0x200 +#define BPHY_COUNTER_RESET 0x8000000 +#define BCFO_REPORT_GET 0x4000000 +#define BOFDM_CONTINUE_TX 0x10000000 +#define BOFDM_SINGLE_CARRIER 0x20000000 +#define BOFDM_SINGLE_TONE 0x40000000 +#define BHT_DETECT 0x100 +#define BCFOEN 0x10000 +#define BCFOVALUE 0xfff00000 +#define BSIGTONE_RE 0x3f +#define BSIGTONE_IM 0x7f00 +#define BCOUNTER_CCA 0xffff +#define BCOUNTER_PARITYFAIL 0xffff0000 +#define BCOUNTER_RATEILLEGAL 0xffff +#define BCOUNTER_CRC8FAIL 0xffff0000 +#define BCOUNTER_MCSNOSUPPORT 0xffff +#define BCOUNTER_FASTSYNC 0xffff +#define BSHORTCFO 0xfff +#define BSHORTCFOT_LENGTH 12 +#define BSHORTCFOF_LENGTH 11 +#define BLONGCFO 0x7ff +#define BLONGCFOT_LENGTH 11 +#define BLONGCFOF_LENGTH 11 +#define BTAILCFO 0x1fff +#define BTAILCFOT_LENGTH 13 +#define BTAILCFOF_LENGTH 12 +#define BNOISE_EN_PWDB 0xffff +#define BCC_POWER_DB 0xffff0000 +#define BMOISE_PWDB 0xffff +#define BPOWERMEAST_LENGTH 10 +#define BPOWERMEASF_LENGTH 3 +#define BRX_HT_BW 0x1 +#define BRXSC 0x6 +#define BRX_HT 0x8 +#define BNB_INTF_DET_ON 0x1 +#define BINTF_WIN_LEN_CFG 0x30 +#define BNB_INTF_TH_CFG 0x1c0 +#define BRFGAIN 0x3f +#define BTABLESEL 0x40 +#define BTRSW 0x80 +#define BRXSNR_A 0xff +#define BRXSNR_B 0xff00 +#define BRXSNR_C 0xff0000 +#define BRXSNR_D 0xff000000 +#define BSNR_EVMT_LENGTH 8 +#define BSNR_EVMF_LENGTH 1 +#define BCSI1ST 0xff +#define BCSI2ND 0xff00 +#define BRXEVM1ST 0xff0000 +#define BRXEVM2ND 0xff000000 +#define BSIGEVM 0xff +#define BPWDB 0xff00 +#define BSGIEN 0x10000 + +#define BSFACTOR_QMA1 0xf +#define BSFACTOR_QMA2 0xf0 +#define BSFACTOR_QMA3 0xf00 +#define BSFACTOR_QMA4 0xf000 +#define BSFACTOR_QMA5 0xf0000 +#define BSFACTOR_QMA6 0xf0000 +#define BSFACTOR_QMA7 0xf00000 +#define BSFACTOR_QMA8 0xf000000 +#define BSFACTOR_QMA9 0xf0000000 +#define BCSI_SCHEME 0x100000 + +#define BNOISE_LVL_TOP_SET 0x3 +#define BCHSMOOTH 0x4 +#define BCHSMOOTH_CFG1 0x38 +#define BCHSMOOTH_CFG2 0x1c0 +#define BCHSMOOTH_CFG3 0xe00 +#define BCHSMOOTH_CFG4 0x7000 +#define BMRCMODE 0x800000 +#define BTHEVMCFG 0x7000000 + +#define BLOOP_FIT_TYPE 0x1 +#define BUPD_CFO 0x40 +#define BUPD_CFO_OFFDATA 0x80 +#define BADV_UPD_CFO 0x100 +#define BADV_TIME_CTRL 0x800 +#define BUPD_CLKO 0x1000 +#define BFC 0x6000 +#define BTRACKING_MODE 0x8000 +#define BPHCMP_ENABLE 0x10000 +#define BUPD_CLKO_LTF 0x20000 +#define BCOM_CH_CFO 0x40000 +#define BCSI_ESTI_MODE 0x80000 +#define BADV_UPD_EQZ 0x100000 +#define BUCHCFG 0x7000000 +#define BUPDEQZ 0x8000000 + +#define BRX_PESUDO_NOISE_ON 0x20000000 +#define BRX_PESUDO_NOISE_A 0xff +#define BRX_PESUDO_NOISE_B 0xff00 +#define BRX_PESUDO_NOISE_C 0xff0000 +#define BRX_PESUDO_NOISE_D 0xff000000 +#define BRX_PESUDO_NOISESTATE_A 0xffff +#define BRX_PESUDO_NOISESTATE_B 0xffff0000 +#define BRX_PESUDO_NOISESTATE_C 0xffff +#define BRX_PESUDO_NOISESTATE_D 0xffff0000 + +#define BZEBRA1_HSSIENABLE 0x8 +#define BZEBRA1_TRXCONTROL 0xc00 +#define BZEBRA1_TRXGAINSETTING 0x07f +#define BZEBRA1_RXCOUNTER 0xc00 +#define BZEBRA1_TXCHANGEPUMP 0x38 +#define BZEBRA1_RXCHANGEPUMP 0x7 +#define BZEBRA1_CHANNEL_NUM 0xf80 +#define BZEBRA1_TXLPFBW 0x400 +#define BZEBRA1_RXLPFBW 0x600 + +#define BRTL8256REG_MODE_CTRL1 0x100 +#define BRTL8256REG_MODE_CTRL0 0x40 +#define BRTL8256REG_TXLPFBW 0x18 +#define BRTL8256REG_RXLPFBW 0x600 + +#define BRTL8258_TXLPFBW 0xc +#define BRTL8258_RXLPFBW 0xc00 +#define BRTL8258_RSSILPFBW 0xc0 + +#define BBYTE0 0x1 +#define BBYTE1 0x2 +#define BBYTE2 0x4 +#define BBYTE3 0x8 +#define BWORD0 0x3 +#define BWORD1 0xc +#define BWORD 0xf + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#define BENABLE 0x1 +#define BDISABLE 0x0 + +#define LEFT_ANTENNA 0x0 +#define RIGHT_ANTENNA 0x1 + +#define TCHECK_TXSTATUS 500 +#define TUPDATE_RXCOUNTER 100 + +#define REG_UN_used_register 0x01bf + +/* WOL bit information */ +#define HAL92C_WOL_PTK_UPDATE_EVENT BIT(0) +#define HAL92C_WOL_GTK_UPDATE_EVENT BIT(1) +#define HAL92C_WOL_DISASSOC_EVENT BIT(2) +#define HAL92C_WOL_DEAUTH_EVENT BIT(3) +#define HAL92C_WOL_FW_DISCONNECT_EVENT BIT(4) + +#define WOL_REASON_PTK_UPDATE BIT(0) +#define WOL_REASON_GTK_UPDATE BIT(1) +#define WOL_REASON_DISASSOC BIT(2) +#define WOL_REASON_DEAUTH BIT(3) +#define WOL_REASON_FW_DISCONNECT BIT(4) + +#define RA_RFE_PINMUX 0xcb0 /* Path_A RFE cotrol pinmux*/ +#define RB_RFE_PINMUX 0xeb0 /* Path_B RFE control pinmux*/ + +#define RA_RFE_INV 0xcb4 +#define RB_RFE_INV 0xeb4 + +/* RXIQC */ +#define RA_RXIQC_AB 0xc10 /*RxIQ imblance matrix coeff. A & B*/ +#define RA_RXIQC_CD 0xc14 /*RxIQ imblance matrix coeff. C & D*/ +#define RA_TXSCALE 0xc1c /* Pah_A TX scaling factor*/ +#define RB_TXSCALE 0xe1c /* Path_B TX scaling factor*/ +#define RB_RXIQC_AB 0xe10 /*RxIQ imblance matrix coeff. A & B*/ +#define RB_RXIQC_CD 0xe14 /*RxIQ imblance matrix coeff. C & D*/ +#define RXIQC_AC 0x02ff /*bit mask for IQC matrix element A & C*/ +#define RXIQC_BD 0x02ff0000 /*bit mask for IQC matrix element A & C*/ + +/* 2 EFUSE_TEST (For RTL8723 partially) */ +#define EFUSE_SEL(x) (((x) & 0x3) << 8) +#define EFUSE_SEL_MASK 0x300 +#define EFUSE_WIFI_SEL_0 0x0 + +/*REG_MULTI_FUNC_CTRL(For RTL8723 Only)*/ +#define WL_HWPDN_EN BIT(0) /* Enable GPIO[9] as WiFi HW PDn source*/ +#define WL_HWPDN_SL BIT(1) /* WiFi HW PDn polarity control*/ +#define WL_FUNC_EN BIT(2) // WiFi function enable +#define WL_HWROF_EN BIT(3) // Enable GPIO[9] as WiFi RF HW PDn source +#define BT_HWPDN_EN BIT(16) // Enable GPIO[11] as BT HW PDn source +#define BT_HWPDN_SL BIT(17) // BT HW PDn polarity control +#define BT_FUNC_EN BIT(18) // BT function enable +#define BT_HWROF_EN BIT(19) // Enable GPIO[11] as BT/GPS RF HW PDn source +#define GPS_HWPDN_EN BIT(20) // Enable GPIO[10] as GPS HW PDn source +#define GPS_HWPDN_SL BIT(21) // GPS HW PDn polarity control +#define GPS_FUNC_EN BIT(22) // GPS function enable + + +#define BMASKBYTE0 0xff +#define BMASKBYTE1 0xff00 +#define BMASKBYTE2 0xff0000 +#define BMASKBYTE3 0xff000000 +#define BMASKHWORD 0xffff0000 +#define BMASKLWORD 0x0000ffff +#define BMASKDWORD 0xffffffff +#define BMASK12BITS 0xfff +#define BMASKH4BITS 0xf0000000 +#define BMASKOFDM_D 0xffc00000 +#define BMASKCCK 0x3f3f3f3f + +#define BRFREGOFFSETMASK 0xfffff + +#define ODM_REG_CCK_RPT_FORMAT_11AC 0x804 +#define ODM_REG_BB_RX_PATH_11AC 0x808 +/*PAGE 9*/ +#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 +/*PAGE A*/ +#define ODM_REG_CCK_CCA_11AC 0xA0A +#define ODM_REG_CCK_FA_RST_11AC 0xA2C +#define ODM_REG_CCK_FA_11AC 0xA5C +/*PAGE C*/ +#define ODM_REG_IGI_A_11AC 0xC50 +/*PAGE E*/ +#define ODM_REG_IGI_B_11AC 0xE50 +/*PAGE F*/ +#define ODM_REG_OFDM_FA_11AC 0xF48 + + +//2 MAC REG LIST + + + + +//DIG Related +#define ODM_BIT_IGI_11AC 0xFFFFFFFF +#define ODM_BIT_CCK_RPT_FORMAT_11AC BIT16 +#define ODM_BIT_BB_RX_PATH_11AC 0xF + +typedef enum AGGRE_SIZE{ + HT_AGG_SIZE_8K = 0, + HT_AGG_SIZE_16K = 1, + HT_AGG_SIZE_32K = 2, + HT_AGG_SIZE_64K = 3, + VHT_AGG_SIZE_128K = 4, + VHT_AGG_SIZE_256K = 5, + VHT_AGG_SIZE_512K = 6, + VHT_AGG_SIZE_1024K = 7, +}AGGRE_SIZE_E, *PAGGRE_SIZE_E; + +#define REG_AMPDU_MAX_LENGTH_8812 0x0458 + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/dm.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/dm.c @@ -0,0 +1,3045 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "trx.h" +#include "../btcoexist/rtl_btc.h" + +struct dig_t dm_digtable; +static struct ps_t dm_pstable; + +static const u32 rtl8812ae_txscaling_table[TXSCALE_TABLE_SIZE] = +{ + 0x081, // 0, -12.0dB + 0x088, // 1, -11.5dB + 0x090, // 2, -11.0dB + 0x099, // 3, -10.5dB + 0x0A2, // 4, -10.0dB + 0x0AC, // 5, -9.5dB + 0x0B6, // 6, -9.0dB + 0x0C0, // 7, -8.5dB + 0x0CC, // 8, -8.0dB + 0x0D8, // 9, -7.5dB + 0x0E5, // 10, -7.0dB + 0x0F2, // 11, -6.5dB + 0x101, // 12, -6.0dB + 0x110, // 13, -5.5dB + 0x120, // 14, -5.0dB + 0x131, // 15, -4.5dB + 0x143, // 16, -4.0dB + 0x156, // 17, -3.5dB + 0x16A, // 18, -3.0dB + 0x180, // 19, -2.5dB + 0x197, // 20, -2.0dB + 0x1AF, // 21, -1.5dB + 0x1C8, // 22, -1.0dB + 0x1E3, // 23, -0.5dB + 0x200, // 24, +0 dB + 0x21E, // 25, +0.5dB + 0x23E, // 26, +1.0dB + 0x261, // 27, +1.5dB + 0x285, // 28, +2.0dB + 0x2AB, // 29, +2.5dB + 0x2D3, // 30, +3.0dB + 0x2FE, // 31, +3.5dB + 0x32B, // 32, +4.0dB + 0x35C, // 33, +4.5dB + 0x38E, // 34, +5.0dB + 0x3C4, // 35, +5.5dB + 0x3FE // 36, +6.0dB +}; + +static const u32 rtl8821ae_txscaling_table[TXSCALE_TABLE_SIZE] = { + 0x081, // 0, -12.0dB + 0x088, // 1, -11.5dB + 0x090, // 2, -11.0dB + 0x099, // 3, -10.5dB + 0x0A2, // 4, -10.0dB + 0x0AC, // 5, -9.5dB + 0x0B6, // 6, -9.0dB + 0x0C0, // 7, -8.5dB + 0x0CC, // 8, -8.0dB + 0x0D8, // 9, -7.5dB + 0x0E5, // 10, -7.0dB + 0x0F2, // 11, -6.5dB + 0x101, // 12, -6.0dB + 0x110, // 13, -5.5dB + 0x120, // 14, -5.0dB + 0x131, // 15, -4.5dB + 0x143, // 16, -4.0dB + 0x156, // 17, -3.5dB + 0x16A, // 18, -3.0dB + 0x180, // 19, -2.5dB + 0x197, // 20, -2.0dB + 0x1AF, // 21, -1.5dB + 0x1C8, // 22, -1.0dB + 0x1E3, // 23, -0.5dB + 0x200, // 24, +0 dB + 0x21E, // 25, +0.5dB + 0x23E, // 26, +1.0dB + 0x261, // 27, +1.5dB + 0x285, // 28, +2.0dB + 0x2AB, // 29, +2.5dB + 0x2D3, // 30, +3.0dB + 0x2FE, // 31, +3.5dB + 0x32B, // 32, +4.0dB + 0x35C, // 33, +4.5dB + 0x38E, // 34, +5.0dB + 0x3C4, // 35, +5.5dB + 0x3FE // 36, +6.0dB +}; + +static const u32 ofdmswing_table[] = { + 0x0b40002d, // 0, -15.0dB + 0x0c000030, // 1, -14.5dB + 0x0cc00033, // 2, -14.0dB + 0x0d800036, // 3, -13.5dB + 0x0e400039, // 4, -13.0dB + 0x0f00003c, // 5, -12.5dB + 0x10000040, // 6, -12.0dB + 0x11000044, // 7, -11.5dB + 0x12000048, // 8, -11.0dB + 0x1300004c, // 9, -10.5dB + 0x14400051, // 10, -10.0dB + 0x15800056, // 11, -9.5dB + 0x16c0005b, // 12, -9.0dB + 0x18000060, // 13, -8.5dB + 0x19800066, // 14, -8.0dB + 0x1b00006c, // 15, -7.5dB + 0x1c800072, // 16, -7.0dB + 0x1e400079, // 17, -6.5dB + 0x20000080, // 18, -6.0dB + 0x22000088, // 19, -5.5dB + 0x24000090, // 20, -5.0dB + 0x26000098, // 21, -4.5dB + 0x288000a2, // 22, -4.0dB + 0x2ac000ab, // 23, -3.5dB + 0x2d4000b5, // 24, -3.0dB + 0x300000c0, // 25, -2.5dB + 0x32c000cb, // 26, -2.0dB + 0x35c000d7, // 27, -1.5dB + 0x390000e4, // 28, -1.0dB + 0x3c8000f2, // 29, -0.5dB + 0x40000100, // 30, +0dB + 0x43c0010f, // 31, +0.5dB + 0x47c0011f, // 32, +1.0dB + 0x4c000130, // 33, +1.5dB + 0x50800142, // 34, +2.0dB + 0x55400155, // 35, +2.5dB + 0x5a400169, // 36, +3.0dB + 0x5fc0017f, // 37, +3.5dB + 0x65400195, // 38, +4.0dB + 0x6b8001ae, // 39, +4.5dB + 0x71c001c7, // 40, +5.0dB + 0x788001e2, // 41, +5.5dB + 0x7f8001fe // 42, +6.0dB +}; + +static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = { + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, // 0, -16.0dB + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, // 1, -15.5dB + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, // 2, -15.0dB + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, // 3, -14.5dB + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, // 4, -14.0dB + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, // 5, -13.5dB + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, // 6, -13.0dB + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, // 7, -12.5dB + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, // 8, -12.0dB + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, // 9, -11.5dB + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 10, -11.0dB + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 11, -10.5dB + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 12, -10.0dB + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 13, -9.5dB + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 14, -9.0dB + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, // 15, -8.5dB + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 16, -8.0dB + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, // 17, -7.5dB + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 18, -7.0dB + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, // 19, -6.5dB + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 20, -6.0dB + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, // 21, -5.5dB + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 22, -5.0dB + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, // 23, -4.5dB + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 24, -4.0dB + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, // 25, -3.5dB + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 26, -3.0dB + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, // 27, -2.5dB + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 28, -2.0dB + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, // 29, -1.5dB + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 30, -1.0dB + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, // 31, -0.5dB + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04} // 32, +0dB +}; + +static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8]= { + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, // 0, -16.0dB + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 1, -15.5dB + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 2, -15.0dB + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 3, -14.5dB + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 4, -14.0dB + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 5, -13.5dB + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 6, -13.0dB + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, // 7, -12.5dB + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 8, -12.0dB + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 9, -11.5dB + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, // 10, -11.0dB + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, // 11, -10.5dB + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 12, -10.0dB + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 13, -9.5dB + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 14, -9.0dB + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 15, -8.5dB + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 16, -8.0dB + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 17, -7.5dB + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 18, -7.0dB + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, // 19, -6.5dB + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 20, -6.0dB + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 21, -5.5dB + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 22, -5.0dB + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, // 23, -4.5dB + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 24, -4.0dB + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, // 25, -3.5dB + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 26, -3.0dB + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, // 27, -2.5dB + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 28, -2.0dB + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, // 29, -1.5dB + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 30, -1.0dB + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, // 31, -0.5dB + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} // 32, +0dB +}; + +static const u32 edca_setting_dl[PEER_MAX] = { + 0xa44f, /* 0 UNKNOWN */ + 0x5ea44f, /* 1 REALTEK_90 */ + 0x5e4322, /* 2 REALTEK_92SE */ + 0x5ea42b, /* 3 BROAD */ + 0xa44f, /* 4 RAL */ + 0xa630, /* 5 ATH */ + 0x5ea630, /* 6 CISCO */ + 0x5ea42b, /* 7 MARVELL */ +}; + +static const u32 edca_setting_ul[PEER_MAX] = { + 0x5e4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0x5ea32b, /* 3 BROAD */ + 0x5ea422, /* 4 RAL */ + 0x5ea322, /* 5 ATH */ + 0x3ea430, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +static u8 rtl8818e_delta_swing_table_idx_24gb_p_txpwrtrack[] = + {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +static u8 rtl8818e_delta_swing_table_idx_24gb_n_txpwrtrack[] = + {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; + + +u8 rtl8812ae_delta_swing_table_idx_24gb_n_txpwrtrack[] = + {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u8 rtl8812ae_delta_swing_table_idx_24gb_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; +u8 rtl8812ae_delta_swing_table_idx_24ga_n_txpwrtrack[] = + {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u8 rtl8812ae_delta_swing_table_idx_24ga_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; +u8 rtl8812ae_delta_swing_table_idx_24gcckb_n_txpwrtrack[] = + {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u8 rtl8812ae_delta_swing_table_idx_24gcckb_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; +u8 rtl8812ae_delta_swing_table_idx_24gccka_n_txpwrtrack[] = + {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u8 rtl8812ae_delta_swing_table_idx_24gccka_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; + +u8 rtl8812ae_delta_swing_table_idx_5gb_n_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13}, + {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13}, + {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 14, 15, 16, 17, 17, 17, 18, 18, 18}, +}; +u8 rtl8812ae_delta_swing_table_idx_5gb_p_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; +u8 rtl8812ae_delta_swing_table_idx_5ga_n_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13}, + {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13}, + {0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18}, +}; +u8 rtl8812ae_delta_swing_table_idx_5ga_p_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +u8 rtl8821ae_delta_swing_table_idx_24gb_n_txpwrtrack[] = + {0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; +u8 rtl8821ae_delta_swing_table_idx_24gb_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; +u8 rtl8821ae_delta_swing_table_idx_24ga_n_txpwrtrack[] = + {0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; +u8 rtl8821ae_delta_swing_table_idx_24ga_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; +u8 rtl8821ae_delta_swing_table_idx_24gcckb_n_txpwrtrack[] = + {0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; +u8 rtl8821ae_delta_swing_table_idx_24gcckb_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; +u8 rtl8821ae_delta_swing_table_idx_24gccka_n_txpwrtrack[] = + {0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; +u8 rtl8821ae_delta_swing_table_idx_24gccka_p_txpwrtrack[] = + {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; + +u8 rtl8821ae_delta_swing_table_idx_5gb_n_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +u8 rtl8821ae_delta_swing_table_idx_5gb_p_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +u8 rtl8821ae_delta_swing_table_idx_5ga_n_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +u8 rtl8821ae_delta_swing_table_idx_5ga_p_txpwrtrack[][DELTA_SWINGIDX_SIZE] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +void rtl8812ae_dm_read_and_config_txpower_track( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===> rtl8821ae_dm_read_and_config_txpower_track\n")); + + + memcpy(rtldm->delta_swing_table_idx_24ga_p, + rtl8812ae_delta_swing_table_idx_24ga_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24ga_n, + rtl8812ae_delta_swing_table_idx_24ga_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gb_p, + rtl8812ae_delta_swing_table_idx_24gb_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gb_n, + rtl8812ae_delta_swing_table_idx_24gb_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + + memcpy(rtldm->delta_swing_table_idx_24gccka_p, + rtl8812ae_delta_swing_table_idx_24gccka_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gccka_n, + rtl8812ae_delta_swing_table_idx_24gccka_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gcckb_p, + rtl8812ae_delta_swing_table_idx_24gcckb_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gcckb_n, + rtl8812ae_delta_swing_table_idx_24gcckb_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + + memcpy(rtldm->delta_swing_table_idx_5ga_p, + rtl8812ae_delta_swing_table_idx_5ga_p_txpwrtrack, DELTA_SWINGIDX_SIZE*3); + memcpy(rtldm->delta_swing_table_idx_5ga_n, + rtl8812ae_delta_swing_table_idx_5ga_n_txpwrtrack, DELTA_SWINGIDX_SIZE*3); + memcpy(rtldm->delta_swing_table_idx_5gb_p, + rtl8812ae_delta_swing_table_idx_5gb_p_txpwrtrack, DELTA_SWINGIDX_SIZE*3); + memcpy(rtldm->delta_swing_table_idx_5gb_n, + rtl8812ae_delta_swing_table_idx_5gb_n_txpwrtrack, DELTA_SWINGIDX_SIZE*3); +} + +void rtl8821ae_dm_read_and_config_txpower_track( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===> rtl8821ae_dm_read_and_config_txpower_track\n")); + + + memcpy(rtldm->delta_swing_table_idx_24ga_p, + rtl8821ae_delta_swing_table_idx_24ga_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24ga_n, + rtl8821ae_delta_swing_table_idx_24ga_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gb_p, + rtl8821ae_delta_swing_table_idx_24gb_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gb_n, + rtl8821ae_delta_swing_table_idx_24gb_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + + memcpy(rtldm->delta_swing_table_idx_24gccka_p, + rtl8821ae_delta_swing_table_idx_24gccka_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gccka_n, + rtl8821ae_delta_swing_table_idx_24gccka_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gcckb_p, + rtl8821ae_delta_swing_table_idx_24gcckb_p_txpwrtrack, DELTA_SWINGIDX_SIZE); + memcpy(rtldm->delta_swing_table_idx_24gcckb_n, + rtl8821ae_delta_swing_table_idx_24gcckb_n_txpwrtrack, DELTA_SWINGIDX_SIZE); + + memcpy(rtldm->delta_swing_table_idx_5ga_p, + rtl8821ae_delta_swing_table_idx_5ga_p_txpwrtrack, DELTA_SWINGIDX_SIZE*3); + memcpy(rtldm->delta_swing_table_idx_5ga_n, + rtl8821ae_delta_swing_table_idx_5ga_n_txpwrtrack, DELTA_SWINGIDX_SIZE*3); + memcpy(rtldm->delta_swing_table_idx_5gb_p, + rtl8821ae_delta_swing_table_idx_5gb_p_txpwrtrack, DELTA_SWINGIDX_SIZE*3); + memcpy(rtldm->delta_swing_table_idx_5gb_n, + rtl8821ae_delta_swing_table_idx_5gb_n_txpwrtrack, DELTA_SWINGIDX_SIZE*3); +} + + + +#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _deltaThermal) \ + do {\ + for(_offset = 0; _offset < _size; _offset++)\ + {\ + if(_deltaThermal < thermal_threshold[_direction][_offset])\ + {\ + if(_offset != 0)\ + _offset--;\ + break;\ + }\ + } \ + if(_offset >= _size)\ + _offset = _size-1;\ + } while(0) + + +void rtl8821ae_dm_txpower_track_adjust(struct ieee80211_hw *hw, + u8 type,u8 *pdirection, + u32 *poutwrite_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 pwr_val = 0; + + if (type == 0){ + if (rtlpriv->dm.bb_swing_idx_ofdm[RF90_PATH_A] <= + rtlpriv->dm.bb_swing_idx_ofdm_base[RF90_PATH_A]) { + *pdirection = 1; + pwr_val = rtldm->bb_swing_idx_ofdm_base[RF90_PATH_A] - rtldm->bb_swing_idx_ofdm[RF90_PATH_A]; + } else { + *pdirection = 2; + pwr_val = rtldm->bb_swing_idx_ofdm[RF90_PATH_A] - rtldm->bb_swing_idx_ofdm_base[RF90_PATH_A]; + } + } else if (type ==1) { + if (rtldm->bb_swing_idx_cck <= rtldm->bb_swing_idx_cck_base) { + *pdirection = 1; + pwr_val = rtldm->bb_swing_idx_cck_base - rtldm->bb_swing_idx_cck; + } else { + *pdirection = 2; + pwr_val = rtldm->bb_swing_idx_cck - rtldm->bb_swing_idx_cck_base; + } + } + + if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1)) + pwr_val = TXPWRTRACK_MAX_IDX; + + *poutwrite_val = pwr_val |(pwr_val << 8)|(pwr_val << 16) | (pwr_val << 24); +} + +void rtl8821ae_dm_clear_txpower_tracking_state(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtlpriv); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + u8 p = 0; + rtldm->bb_swing_idx_cck_base = rtldm->default_cck_index; + rtldm->bb_swing_idx_cck = rtldm->default_cck_index; + rtldm->cck_index = 0; + + for (p = RF90_PATH_A; p < MAX_RF_PATH; ++p) { + rtldm->bb_swing_idx_ofdm_base[p] = rtldm->default_ofdm_index; + rtldm->bb_swing_idx_ofdm[p] = rtldm->default_ofdm_index; + rtldm->ofdm_index[p] = rtldm->default_ofdm_index; + + rtldm->power_index_offset[p] = 0; + rtldm->delta_power_index[p] = 0; + rtldm->delta_power_index_last[p] = 0; + + rtldm->aboslute_ofdm_swing_idx[p] = 0; /*Initial Mix mode power tracking*/ + rtldm->remnant_ofdm_swing_idx[p] = 0; + } + + rtldm->modify_txagc_flag_path_a = false; /*Initial at Modify Tx Scaling Mode*/ + rtldm->modify_txagc_flag_path_b = false; /*Initial at Modify Tx Scaling Mode*/ + rtldm->remnant_cck_idx = 0; + rtldm->thermalvalue = rtlefuse->eeprom_thermalmeter; + rtldm->thermalvalue_iqk = rtlefuse->eeprom_thermalmeter; + rtldm->thermalvalue_lck = rtlefuse->eeprom_thermalmeter; +} + +u8 rtl8821ae_dm_get_swing_index(struct ieee80211_hw *hw) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 i = 0; + u32 bb_swing; + + bb_swing =rtl8821ae_phy_query_bb_reg(hw, rtlhal->current_bandtype, RF90_PATH_A); + + for (i = 0; i < TXSCALE_TABLE_SIZE; ++i) + if ( bb_swing == rtl8821ae_txscaling_table[i]) + break; + + return i; +} + +void rtl8821ae_dm_initialize_txpower_tracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtlpriv); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 default_swing_index = 0; + u8 p = 0; + + rtlpriv->dm.txpower_track_control = true; + rtldm->thermalvalue = rtlefuse->eeprom_thermalmeter; + rtldm->thermalvalue_iqk = rtlefuse->eeprom_thermalmeter; + rtldm->thermalvalue_lck = rtlefuse->eeprom_thermalmeter; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_dm_read_and_config_txpower_track(hw); + else + rtl8821ae_dm_read_and_config_txpower_track(hw); + + default_swing_index = rtl8821ae_dm_get_swing_index(hw); + + rtldm->default_ofdm_index = (default_swing_index == TXSCALE_TABLE_SIZE) ? 24 : default_swing_index; + rtldm->default_cck_index = 24; + + rtldm->bb_swing_idx_cck_base = rtldm->default_cck_index; + rtldm->cck_index = rtldm->default_cck_index; + + for (p = RF90_PATH_A; p < MAX_RF_PATH; ++p) + { + rtldm->bb_swing_idx_ofdm_base[p] = rtldm->default_ofdm_index; + rtldm->ofdm_index[p] = rtldm->default_ofdm_index; + rtldm->delta_power_index[p] = 0; + rtldm->power_index_offset[p] = 0; + rtldm->delta_power_index_last[p] = 0; + } +} + +static void rtl8821ae_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) +{ + dm_pstable.pre_ccastate = CCA_MAX; + dm_pstable.cur_ccasate = CCA_MAX; + dm_pstable.pre_rfstate = RF_MAX; + dm_pstable.cur_rfstate = RF_MAX; + dm_pstable.rssi_val_min = 0; + dm_pstable.initialize = 0; +} + + +static void rtl8821ae_dm_diginit(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + //dm_digtable.dig_enable_flag = true; + dm_digtable.cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); + /*dm_digtable.pre_igvalue = 0; + dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + dm_digtable.presta_connectstate = DIG_STA_DISCONNECT; + dm_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT;*/ + dm_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; + dm_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; + dm_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + dm_digtable.rx_gain_range_max = DM_DIG_MAX; + dm_digtable.rx_gain_range_min = DM_DIG_MIN; + dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN; + dm_digtable.pre_cck_cca_thres = 0xff; + dm_digtable.cur_cck_cca_thres = 0x83; + dm_digtable.forbidden_igi = DM_DIG_MIN; + dm_digtable.large_fa_hit = 0; + dm_digtable.recover_cnt = 0; + dm_digtable.dig_dynamic_min_0 = DM_DIG_MIN; + dm_digtable.dig_dynamic_min_1 = DM_DIG_MIN; + dm_digtable.b_media_connect_0 = false; + dm_digtable.b_media_connect_1 = false; + rtlpriv->dm.b_dm_initialgain_enable = true; + dm_digtable.bt30_cur_igi = 0x32; +} + +static void rtl8821ae_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.bdynamic_txpower_enable = false; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +} + + +void rtl8821ae_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtlpriv->dm.bcurrent_turbo_edca = false; + rtlpriv->dm.bis_any_nonbepkts = false; + rtlpriv->dm.bis_cur_rdlstate = false; +} + + +void rtl8821ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rate_adaptive *p_ra = &(rtlpriv->ra); + + p_ra->ratr_state = DM_RATR_STA_INIT; + p_ra->pre_ratr_state = DM_RATR_STA_INIT; + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) + rtlpriv->dm.b_useramask = true; + else + rtlpriv->dm.b_useramask = false; + + p_ra->high_rssi_thresh_for_ra = 50; + p_ra->low_rssi_thresh_for_ra = 20; +} + + +static void rtl8821ae_dm_init_txpower_tracking(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.btxpower_tracking = true; + rtlpriv->dm.btxpower_trackinginit = false; + rtlpriv->dm.txpowercount = 0; + rtlpriv->dm.txpower_track_control = true; + rtlpriv->dm.thermalvalue = 0; + + rtlpriv->dm.ofdm_index[0] = 30; + rtlpriv->dm.cck_index = 20; + + rtlpriv->dm.bb_swing_idx_cck_base = rtlpriv->dm.cck_index; + + + rtlpriv->dm.bb_swing_idx_ofdm[RF90_PATH_A] = rtlpriv->dm.ofdm_index[0]; + rtlpriv->dm.bb_swing_idx_ofdm[RF90_PATH_B] = rtlpriv->dm.ofdm_index[0]; + rtlpriv->dm.delta_power_index[0] = 0; + rtlpriv->dm.delta_power_index_last[0] = 0; + rtlpriv->dm.power_index_offset[0] = 0; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + (" rtlpriv->dm.btxpower_tracking = %d\n", + rtlpriv->dm.btxpower_tracking)); +} + + +void rtl8821ae_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap; + + rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11)); + rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL; +} + + +void rtl8821ae_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = false; + spin_unlock(&rtlpriv->locks.iqk_lock); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtl8821ae_dm_diginit(hw); + rtl8821ae_dm_init_rate_adaptive_mask(hw); + rtl8812ae_dm_path_diversity_init(hw); + rtl8821ae_dm_init_edca_turbo(hw); + rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(hw); +#if 1 + rtl8821ae_dm_init_dynamic_bb_powersaving(hw); + rtl8821ae_dm_init_dynamic_txpower(hw); + rtl8821ae_dm_init_txpower_tracking(hw); +#endif + rtl8821ae_dm_init_dynamic_atc_switch(hw); +} + +void rtl8821ae_dm_find_minimum_rssi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dig *rtl_dm_dig = &(rtlpriv->dm.dm_digtable); + struct rtl_mac *mac = rtl_mac(rtlpriv); + + /* Determine the minimum RSSI */ + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + rtl_dm_dig->min_undecorated_pwdb_for_dm = 0; + RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, + ("Not connected to any \n")); + } + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_dm_dig->min_undecorated_pwdb_for_dm = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, + ("AP Client PWDB = 0x%lx \n", + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb)); + } else { + rtl_dm_dig->min_undecorated_pwdb_for_dm = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, + ("STA Default Port PWDB = 0x%x \n", + rtl_dm_dig->min_undecorated_pwdb_for_dm)); + } + } else { + rtl_dm_dig->min_undecorated_pwdb_for_dm = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, + ("AP Ext Port or disconnet PWDB = 0x%x \n", + rtl_dm_dig->min_undecorated_pwdb_for_dm)); + } + RT_TRACE(COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", + rtl_dm_dig->min_undecorated_pwdb_for_dm)); +} + +#if 0 +void rtl8812ae_dm_rssi_dump_to_register( + struct ieee80211_hw *hw + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, RA_RSSI_DUMP, Adapter->RxStats.RxRSSIPercentage[0]); + rtl_write_byte(rtlpriv, RB_RSSI_DUMP, Adapter->RxStats.RxRSSIPercentage[1]); + + /* Rx EVM*/ + rtl_write_byte(rtlpriv, RS1_RX_EVM_DUMP, Adapter->RxStats.RxEVMdbm[0]); + rtl_write_byte(rtlpriv, RS2_RX_EVM_DUMP, Adapter->RxStats.RxEVMdbm[1]); + + /*Rx SNR*/ + rtl_write_byte(rtlpriv, RA_RX_SNR_DUMP, (u1Byte)(Adapter->RxStats.RxSNRdB[0])); + rtl_write_byte(rtlpriv, RB_RX_SNR_DUMP, (u1Byte)(Adapter->RxStats.RxSNRdB[1])); + + /*Rx Cfo_Short*/ + rtl_write_word(rtlpriv, RA_CFO_SHORT_DUMP, Adapter->RxStats.RxCfoShort[0]); + rtl_write_word(rtlpriv, RB_CFO_SHORT_DUMP, Adapter->RxStats.RxCfoShort[1]); + + /*Rx Cfo_Tail*/ + rtl_write_word(rtlpriv, RA_CFO_LONG_DUMP, Adapter->RxStats.RxCfoTail[0]); + rtl_write_word(rtlpriv, RB_CFO_LONG_DUMP, Adapter->RxStats.RxCfoTail[1]); + +} +#endif + +static void rtl8821ae_dm_check_rssi_monitor(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *drv_priv; + u8 h2c_parameter[3] = { 0 }; + long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff; + + + /* AP & ADHOC & MESH */ + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) { + if(drv_priv->rssi_stat.undecorated_smoothed_pwdb < tmp_entry_min_pwdb) + tmp_entry_min_pwdb = drv_priv->rssi_stat.undecorated_smoothed_pwdb; + if(drv_priv->rssi_stat.undecorated_smoothed_pwdb > tmp_entry_max_pwdb) + tmp_entry_max_pwdb = drv_priv->rssi_stat.undecorated_smoothed_pwdb; + + /*h2c_parameter[2] = (u8) (rtlpriv->dm.undecorated_smoothed_pwdb & 0xFF); + h2c_parameter[1] = 0x20; + h2c_parameter[0] = drv_priv->rssi_stat; + rtl8821ae_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);*/ + } + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + + /* If associated entry is found */ + if (tmp_entry_max_pwdb != 0) { + rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = tmp_entry_max_pwdb; + RTPRINT(rtlpriv, FDM, DM_PWDB, ("EntryMaxPWDB = 0x%lx(%ld)\n", + tmp_entry_max_pwdb, tmp_entry_max_pwdb)); + } else { + rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = 0; + } + /* If associated entry is found */ + if (tmp_entry_min_pwdb != 0xff) { + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = tmp_entry_min_pwdb; + RTPRINT(rtlpriv, FDM, DM_PWDB, ("EntryMinPWDB = 0x%lx(%ld)\n", + tmp_entry_min_pwdb, tmp_entry_min_pwdb)); + } else { + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = 0; + } + /* Indicate Rx signal strength to FW. */ + if (rtlpriv->dm.b_useramask) { + h2c_parameter[2] = (u8) (rtlpriv->dm.undecorated_smoothed_pwdb & 0xFF); + h2c_parameter[1] = 0x20; + h2c_parameter[0] = 0; + rtl8821ae_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter); + } else { + rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undecorated_smoothed_pwdb); + } + rtl8821ae_dm_find_minimum_rssi(hw); + dm_digtable.rssi_val_min = rtlpriv->dm.dm_digtable.min_undecorated_pwdb_for_dm; +} + +void rtl8821ae_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 current_cca) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (dm_digtable.cur_cck_cca_thres != current_cca) + rtl_write_byte(rtlpriv, DM_REG_CCK_CCA_11AC, current_cca); + + dm_digtable.pre_cck_cca_thres = dm_digtable.cur_cck_cca_thres; + dm_digtable.cur_cck_cca_thres = current_cca; +} + +void rtl8821ae_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if(dm_digtable.stop_dig) + return; + + if (dm_digtable.cur_igvalue != current_igi){ + rtl_set_bbreg(hw, DM_REG_IGI_A_11AC, DM_BIT_IGI_11AC, current_igi); + if (rtlpriv->phy.rf_type != RF_1T1R) + rtl_set_bbreg(hw, DM_REG_IGI_B_11AC, DM_BIT_IGI_11AC, current_igi); + } + //dm_digtable.pre_igvalue = dm_digtable.cur_igvalue; + dm_digtable.cur_igvalue = current_igi; +} + +static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 dig_dynamic_min; + u8 dig_max_of_min; + bool first_connect, first_disconnect; + u8 dm_dig_max, dm_dig_min, offset; + u8 current_igi =dm_digtable.cur_igvalue; + + + RT_TRACE(COMP_DIG, DBG_LOUD,("rtl8821ae_dm_dig()==>\n")); + + + if (mac->act_scanning == true) { + RT_TRACE(COMP_DIG, DBG_LOUD,("rtl8821ae_dm_dig() Return: In Scan Progress \n")); + return; + } + + /*add by Neil Chen to avoid PSD is processing*/ + dig_dynamic_min = dm_digtable.dig_dynamic_min_0; + first_connect = (mac->link_state >= MAC80211_LINKED) && + (dm_digtable.b_media_connect_0 == false); + first_disconnect = (mac->link_state < MAC80211_LINKED) && + (dm_digtable.b_media_connect_0 == true); + + /*1 Boundary Decision*/ + + + dm_dig_max = 0x5A; + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8821AE) + dm_dig_min = DM_DIG_MIN; + else + dm_dig_min = 0x1C; + + dig_max_of_min = DM_DIG_MAX_AP; + + if (mac->link_state >= MAC80211_LINKED) { + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8821AE) + offset = 20; + else + offset = 10; + + if ((dm_digtable.rssi_val_min + offset) > dm_dig_max) + dm_digtable.rx_gain_range_max = dm_dig_max; + else if ((dm_digtable.rssi_val_min + offset) < dm_dig_min) + dm_digtable.rx_gain_range_max = dm_dig_min; + else + dm_digtable.rx_gain_range_max = dm_digtable.rssi_val_min + offset; + + if(rtlpriv->dm.b_one_entry_only){ + offset = 0; + + if (dm_digtable.rssi_val_min - offset < dm_dig_min) + dig_dynamic_min = dm_dig_min; + else if (dm_digtable.rssi_val_min - offset > dig_max_of_min) + dig_dynamic_min = dig_max_of_min; + else + dig_dynamic_min = dm_digtable.rssi_val_min - offset; + + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig() : bOneEntryOnly=TRUE, dig_dynamic_min=0x%x\n", + dig_dynamic_min)); + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig() : dm_digtable.rssi_val_min=%d",dm_digtable. + rssi_val_min)); + } else { + dig_dynamic_min = dm_dig_min; + } + } else { + dm_digtable.rx_gain_range_max = dm_dig_max; + dig_dynamic_min = dm_dig_min; + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig() : No Link\n")); + } + + if (rtlpriv->falsealm_cnt.cnt_all > 10000) { + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): Abnornally false alarm case. \n")); + + if (dm_digtable.large_fa_hit != 3) + dm_digtable.large_fa_hit++; + if (dm_digtable.forbidden_igi < current_igi) { + dm_digtable.forbidden_igi = current_igi; + dm_digtable.large_fa_hit = 1; + } + + if (dm_digtable.large_fa_hit >= 3) { + if((dm_digtable.forbidden_igi + 1) > dm_digtable.rx_gain_range_max) + dm_digtable.rx_gain_range_min = dm_digtable.rx_gain_range_max; + else + dm_digtable.rx_gain_range_min = (dm_digtable.forbidden_igi + 1); + dm_digtable.recover_cnt = 3600; + } + + } else { + /*Recovery mechanism for IGI lower bound*/ + if (dm_digtable.recover_cnt != 0) + dm_digtable.recover_cnt --; + else { + if (dm_digtable.large_fa_hit < 3) { + if ((dm_digtable.forbidden_igi -1) < dig_dynamic_min) { + dm_digtable.forbidden_igi = dig_dynamic_min; + dm_digtable.rx_gain_range_min = dig_dynamic_min; + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): Normal Case: At Lower Bound\n")); + } else { + dm_digtable.forbidden_igi --; + dm_digtable.rx_gain_range_min = (dm_digtable.forbidden_igi + 1); + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): Normal Case: Approach Lower Bound\n")); + } + } else { + dm_digtable.large_fa_hit = 0; + } + } + } + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): pDM_DigTable->LargeFAHit=%d\n", + dm_digtable.large_fa_hit)); + + if (rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 10) + dm_digtable.rx_gain_range_min = dm_dig_min; + + if (dm_digtable.rx_gain_range_min > dm_digtable.rx_gain_range_max) + dm_digtable.rx_gain_range_min = dm_digtable.rx_gain_range_max; + + /*Adjust initial gain by false alarm*/ + if (mac->link_state >= MAC80211_LINKED) { + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): DIG AfterLink\n")); + if (first_connect) { + if (dm_digtable.rssi_val_min <= dig_max_of_min) + current_igi = dm_digtable.rssi_val_min; + else + current_igi = dig_max_of_min; + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig: First Connect\n")); + } else { + if(rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2) + current_igi = current_igi + 4; + else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1) + current_igi = current_igi + 2; + else if(rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0) + current_igi = current_igi - 2; + + if((rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 10) + &&(rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1)) { + current_igi = dm_digtable.rx_gain_range_min; + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): Beacon is less than 10 and FA is less than 768, IGI GOES TO 0x1E!!!!!!!!!!!!\n")); + } + } + } else{ + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): DIG BeforeLink\n")); + if (first_disconnect){ + current_igi = dm_digtable.rx_gain_range_min; + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): First DisConnect \n")); + } else { + /*2012.03.30 LukeLee: enable DIG before link but with very high thresholds*/ + if (rtlpriv->falsealm_cnt.cnt_all > 2000) + current_igi = current_igi + 4; + else if (rtlpriv->falsealm_cnt.cnt_all > 600) + current_igi = current_igi + 2; + else if(rtlpriv->falsealm_cnt.cnt_all < 300) + current_igi = current_igi - 2; + if (current_igi >= 0x3e) + current_igi = 0x3e; + RT_TRACE(COMP_DIG, DBG_LOUD,("rtl8821ae_dm_dig(): England DIG \n")); + } + } + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): DIG End Adjust IGI\n")); + /* Check initial gain by upper/lower bound*/ + + if (current_igi > dm_digtable.rx_gain_range_max) + current_igi = dm_digtable.rx_gain_range_max; + if (current_igi < dm_digtable.rx_gain_range_min) + current_igi = dm_digtable.rx_gain_range_min; + + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n", + dm_digtable.rx_gain_range_max, dm_digtable.rx_gain_range_min)); + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): TotalFA=%d\n", rtlpriv->falsealm_cnt.cnt_all)); + RT_TRACE(COMP_DIG, DBG_LOUD, + ("rtl8821ae_dm_dig(): CurIGValue=0x%x\n", current_igi)); + + rtl8821ae_dm_write_dig(hw, current_igi); + dm_digtable.b_media_connect_0= ((mac->link_state >= MAC80211_LINKED) ? true :false); + dm_digtable.dig_dynamic_min_0 = dig_dynamic_min; +} + +static void rtl8821ae_dm_common_info_self_update(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 cnt = 0; + struct rtl_sta_info *drv_priv; + + rtlpriv->dm.b_one_entry_only = false; + + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && + rtlpriv->mac80211.link_state >= MAC80211_LINKED) { + rtlpriv->dm.b_one_entry_only = true; + return; + } + + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP || + rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC || + rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) { + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) { + cnt ++; + } + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + + if (cnt == 1) + rtlpriv->dm.b_one_entry_only = true; + } +} + + +static void rtl8821ae_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + u32 cck_enable =0; + + /*read OFDM FA counter*/ + falsealm_cnt->cnt_ofdm_fail = rtl_get_bbreg(hw, ODM_REG_OFDM_FA_11AC, BMASKLWORD); + falsealm_cnt->cnt_cck_fail = rtl_get_bbreg(hw, ODM_REG_CCK_FA_11AC, BMASKLWORD); + + cck_enable = rtl_get_bbreg(hw, ODM_REG_BB_RX_PATH_11AC, BIT(28)); + if (cck_enable) /*if(pDM_Odm->pBandType == ODM_BAND_2_4G)*/ + falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail + falsealm_cnt->cnt_cck_fail; + else + falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail; + + /*reset OFDM FA coutner*/ + rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 1); + rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 0); + /* reset CCK FA counter*/ + rtl_set_bbreg(hw, ODM_REG_CCK_FA_RST_11AC, BIT(15), 0); + rtl_set_bbreg(hw, ODM_REG_CCK_FA_RST_11AC, BIT(15), 1); + + RT_TRACE(COMP_DIG, DBG_LOUD, ("Cnt_Cck_fail=%d\n", + falsealm_cnt->cnt_cck_fail)); + RT_TRACE(COMP_DIG, DBG_LOUD, ("cnt_ofdm_fail=%d\n", + falsealm_cnt->cnt_ofdm_fail)); + RT_TRACE(COMP_DIG, DBG_LOUD, ("Total False Alarm=%d\n", + falsealm_cnt->cnt_all)); +} + +void rtl8812ae_dm_check_txpower_tracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static u8 tm_trigger = 0; + + if (!rtlpriv->dm.btxpower_tracking) + return; + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E, BIT(17)|BIT(16), 0x03); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Trigger 8812 Thermal Meter!!\n")); + tm_trigger = 1; + return; + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Schedule TxPowerTracking direct call!!\n")); + rtl8812ae_dm_txpower_tracking_callback_thermalmeter(hw); + tm_trigger = 0; + } +} + +static void rtl8821ae_dm_iq_calibrate(struct ieee80211_hw *hw) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (mac->link_state >= MAC80211_LINKED) { + /*if ((*rtldm->p_channel != rtldm->pre_channel ) + && (!mac->act_scanning)) { + rtldm->pre_channel = *rtldm->p_channel; + rtldm->linked_interval = 0; + }*/ + + if(rtldm->linked_interval < 3) + rtldm->linked_interval ++; + + if(rtldm->linked_interval == 2) + { + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_phy_iq_calibrate(hw, false); + else + rtl8821ae_phy_iq_calibrate(hw, false); + } + } else { + rtldm->linked_interval = 0; + } +} + + +void rtl8812ae_get_delta_swing_table( + struct ieee80211_hw *hw, + u8 **temperature_up_a, + u8 **temperature_down_a, + u8 **temperature_up_b, + u8 **temperature_down_b + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 channel = rtlphy->current_channel; + u8 rate = rtldm->tx_rate; + + + if ( 1 <= channel && channel <= 14) { + if (RX_HAL_IS_CCK_RATE(rate)) { + *temperature_up_a = rtldm->delta_swing_table_idx_24gccka_p; + *temperature_down_a = rtldm->delta_swing_table_idx_24gccka_n; + *temperature_up_b = rtldm->delta_swing_table_idx_24gcckb_p; + *temperature_down_b = rtldm->delta_swing_table_idx_24gcckb_n; + } else { + *temperature_up_a = rtldm->delta_swing_table_idx_24ga_p; + *temperature_down_a = rtldm->delta_swing_table_idx_24ga_n; + *temperature_up_b = rtldm->delta_swing_table_idx_24gb_p; + *temperature_down_b = rtldm->delta_swing_table_idx_24gb_n; + } + } else if ( 36 <= channel && channel <= 64) { + *temperature_up_a = rtldm->delta_swing_table_idx_5ga_p[0]; + *temperature_down_a = rtldm->delta_swing_table_idx_5ga_n[0]; + *temperature_up_b = rtldm->delta_swing_table_idx_5gb_p[0]; + *temperature_down_b = rtldm->delta_swing_table_idx_5gb_n[0]; + } else if ( 100 <= channel && channel <= 140) { + *temperature_up_a = rtldm->delta_swing_table_idx_5ga_p[1]; + *temperature_down_a = rtldm->delta_swing_table_idx_5ga_n[1]; + *temperature_up_b = rtldm->delta_swing_table_idx_5gb_p[1]; + *temperature_down_b = rtldm->delta_swing_table_idx_5gb_n[1]; + } else if ( 149 <= channel && channel <= 173) { + *temperature_up_a = rtldm->delta_swing_table_idx_5ga_p[2]; + *temperature_down_a = rtldm->delta_swing_table_idx_5ga_n[2]; + *temperature_up_b = rtldm->delta_swing_table_idx_5gb_p[2]; + *temperature_down_b = rtldm->delta_swing_table_idx_5gb_n[2]; + } else { + *temperature_up_a = (u8*)rtl8818e_delta_swing_table_idx_24gb_p_txpwrtrack; + *temperature_down_a =(u8*)rtl8818e_delta_swing_table_idx_24gb_n_txpwrtrack; + *temperature_up_b = (u8*)rtl8818e_delta_swing_table_idx_24gb_p_txpwrtrack; + *temperature_down_b = (u8*)rtl8818e_delta_swing_table_idx_24gb_n_txpwrtrack; + } + + return; +} + +void rtl8812ae_phy_lccalibrate( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("===> rtl8812ae_phy_lccalibrate\n")); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("<=== rtl8812ae_phy_lccalibrate\n")); + +} + +void rtl8812ae_dm_update_init_rate( + struct ieee80211_hw *hw, + u8 rate + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 p = 0; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Get C2H Command! Rate=0x%x\n", rate)); + + rtldm->tx_rate = rate; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE){ + rtl8821ae_dm_txpwr_track_set_pwr(hw, MIX_MODE, RF90_PATH_A, 0); + } + else + { + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) + { + rtl8812ae_dm_txpwr_track_set_pwr(hw, BBSWING, p, 0); + } + } + +} + +u8 rtl8812ae_hw_rate_to_mrate( + struct ieee80211_hw *hw, + u8 rate + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 ret_rate = MGN_1M; + + + switch(rate) + { + case DESC_RATE1M: ret_rate = MGN_1M; break; + case DESC_RATE2M: ret_rate = MGN_2M; break; + case DESC_RATE5_5M: ret_rate = MGN_5_5M; break; + case DESC_RATE11M: ret_rate = MGN_11M; break; + case DESC_RATE6M: ret_rate = MGN_6M; break; + case DESC_RATE9M: ret_rate = MGN_9M; break; + case DESC_RATE12M: ret_rate = MGN_12M; break; + case DESC_RATE18M: ret_rate = MGN_18M; break; + case DESC_RATE24M: ret_rate = MGN_24M; break; + case DESC_RATE36M: ret_rate = MGN_36M; break; + case DESC_RATE48M: ret_rate = MGN_48M; break; + case DESC_RATE54M: ret_rate = MGN_54M; break; + case DESC_RATEMCS0: ret_rate = MGN_MCS0; break; + case DESC_RATEMCS1: ret_rate = MGN_MCS1; break; + case DESC_RATEMCS2: ret_rate = MGN_MCS2; break; + case DESC_RATEMCS3: ret_rate = MGN_MCS3; break; + case DESC_RATEMCS4: ret_rate = MGN_MCS4; break; + case DESC_RATEMCS5: ret_rate = MGN_MCS5; break; + case DESC_RATEMCS6: ret_rate = MGN_MCS6; break; + case DESC_RATEMCS7: ret_rate = MGN_MCS7; break; + case DESC_RATEMCS8: ret_rate = MGN_MCS8; break; + case DESC_RATEMCS9: ret_rate = MGN_MCS9; break; + case DESC_RATEMCS10: ret_rate = MGN_MCS10; break; + case DESC_RATEMCS11: ret_rate = MGN_MCS11; break; + case DESC_RATEMCS12: ret_rate = MGN_MCS12; break; + case DESC_RATEMCS13: ret_rate = MGN_MCS13; break; + case DESC_RATEMCS14: ret_rate = MGN_MCS14; break; + case DESC_RATEMCS15: ret_rate = MGN_MCS15; break; + case DESC_RATEVHT1SS_MCS0: ret_rate = MGN_VHT1SS_MCS0; break; + case DESC_RATEVHT1SS_MCS1: ret_rate = MGN_VHT1SS_MCS1; break; + case DESC_RATEVHT1SS_MCS2: ret_rate = MGN_VHT1SS_MCS2; break; + case DESC_RATEVHT1SS_MCS3: ret_rate = MGN_VHT1SS_MCS3; break; + case DESC_RATEVHT1SS_MCS4: ret_rate = MGN_VHT1SS_MCS4; break; + case DESC_RATEVHT1SS_MCS5: ret_rate = MGN_VHT1SS_MCS5; break; + case DESC_RATEVHT1SS_MCS6: ret_rate = MGN_VHT1SS_MCS6; break; + case DESC_RATEVHT1SS_MCS7: ret_rate = MGN_VHT1SS_MCS7; break; + case DESC_RATEVHT1SS_MCS8: ret_rate = MGN_VHT1SS_MCS8; break; + case DESC_RATEVHT1SS_MCS9: ret_rate = MGN_VHT1SS_MCS9; break; + case DESC_RATEVHT2SS_MCS0: ret_rate = MGN_VHT2SS_MCS0; break; + case DESC_RATEVHT2SS_MCS1: ret_rate = MGN_VHT2SS_MCS1; break; + case DESC_RATEVHT2SS_MCS2: ret_rate = MGN_VHT2SS_MCS2; break; + case DESC_RATEVHT2SS_MCS3: ret_rate = MGN_VHT2SS_MCS3; break; + case DESC_RATEVHT2SS_MCS4: ret_rate = MGN_VHT2SS_MCS4; break; + case DESC_RATEVHT2SS_MCS5: ret_rate = MGN_VHT2SS_MCS5; break; + case DESC_RATEVHT2SS_MCS6: ret_rate = MGN_VHT2SS_MCS6; break; + case DESC_RATEVHT2SS_MCS7: ret_rate = MGN_VHT2SS_MCS7; break; + case DESC_RATEVHT2SS_MCS8: ret_rate = MGN_VHT2SS_MCS8; break; + case DESC_RATEVHT2SS_MCS9: ret_rate = MGN_VHT2SS_MCS9; break; + + default: + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("HwRateToMRate8812(): Non supported Rate [%x]!!!\n",rate )); + break; + } + return ret_rate; +} + +/*----------------------------------------------------------------------------- + * Function: odm_TxPwrTrackSetPwr88E() + * + * Overview: 88E change all channel tx power accordign to flag. + * OFDM & CCK are all different. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 04/23/2012 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, + enum pwr_track_control_method method, u8 rf_path, u8 channel_mapped_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 final_bb_swing_idx[2]; + u8 pwr_tracking_limit = 26; /*+1.0dB*/ + u8 tx_rate = 0xFF; + s8 final_ofdm_swing_index = 0; + + if(rtldm->tx_rate != 0xFF) + tx_rate = rtl8812ae_hw_rate_to_mrate(hw, rtldm->tx_rate); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===>rtl8812ae_dm_txpwr_track_set_pwr\n")); + + if(tx_rate != 0xFF) { /*20130429 Mimic Modify High Rate BBSwing Limit.*/ + /*CCK*/ + if((tx_rate >= MGN_1M) && (tx_rate <= MGN_11M)) + pwr_tracking_limit = 32; /*+4dB*/ + /*OFDM*/ + else if((tx_rate >= MGN_6M) && (tx_rate <= MGN_48M)) + pwr_tracking_limit = 30; /*+3dB*/ + else if(tx_rate == MGN_54M) + pwr_tracking_limit = 28; /*+2dB*/ + /*HT*/ + else if((tx_rate >= MGN_MCS0) && (tx_rate <= MGN_MCS2)) /*QPSK/BPSK*/ + pwr_tracking_limit = 34; /*+5dB*/ + else if((tx_rate >= MGN_MCS3) && (tx_rate <= MGN_MCS4)) /*16QAM*/ + pwr_tracking_limit = 30; /*+3dB*/ + else if((tx_rate >= MGN_MCS5) && (tx_rate <= MGN_MCS7)) /*64QAM*/ + pwr_tracking_limit = 28; /*+2dB*/ + + else if((tx_rate >= MGN_MCS8) && (tx_rate <= MGN_MCS10)) /*QPSK/BPSK*/ + pwr_tracking_limit = 34; /*+5dB*/ + else if((tx_rate >= MGN_MCS11) && (tx_rate <= MGN_MCS12)) /*16QAM*/ + pwr_tracking_limit = 30; /*+3dB*/ + else if((tx_rate >= MGN_MCS13) && (tx_rate <= MGN_MCS15)) /*64QAM*/ + pwr_tracking_limit = 28; /*+2dB*/ + + /*2 VHT*/ + else if((tx_rate >= MGN_VHT1SS_MCS0) && (tx_rate <= MGN_VHT1SS_MCS2)) /*QPSK/BPSK*/ + pwr_tracking_limit = 34; /*+5dB*/ + else if((tx_rate >= MGN_VHT1SS_MCS3) && (tx_rate <= MGN_VHT1SS_MCS4)) /*16QAM*/ + pwr_tracking_limit = 30; /*+3dB*/ + else if((tx_rate >= MGN_VHT1SS_MCS5)&&(tx_rate <= MGN_VHT1SS_MCS6)) /*64QAM*/ + pwr_tracking_limit = 28; /*+2dB*/ + else if(tx_rate == MGN_VHT1SS_MCS7) /*64QAM*/ + pwr_tracking_limit = 26; /*+1dB*/ + else if(tx_rate == MGN_VHT1SS_MCS8) /*256QAM*/ + pwr_tracking_limit = 24; /*+0dB*/ + else if(tx_rate == MGN_VHT1SS_MCS9) /*256QAM*/ + pwr_tracking_limit = 22; /*-1dB*/ + + else if((tx_rate >= MGN_VHT2SS_MCS0)&&(tx_rate <= MGN_VHT2SS_MCS2)) /*QPSK/BPSK*/ + pwr_tracking_limit = 34; /*+5dB*/ + else if((tx_rate >= MGN_VHT2SS_MCS3)&&(tx_rate <= MGN_VHT2SS_MCS4)) /*16QAM*/ + pwr_tracking_limit = 30; /*+3dB*/ + else if((tx_rate >= MGN_VHT2SS_MCS5)&&(tx_rate <= MGN_VHT2SS_MCS6)) /*64QAM*/ + pwr_tracking_limit = 28; /*+2dB*/ + else if(tx_rate == MGN_VHT2SS_MCS7) /*64QAM*/ + pwr_tracking_limit = 26; /*+1dB*/ + else if(tx_rate == MGN_VHT2SS_MCS8) /*256QAM*/ + pwr_tracking_limit = 24; /*+0dB*/ + else if(tx_rate == MGN_VHT2SS_MCS9) /*256QAM*/ + pwr_tracking_limit = 22; /*-1dB*/ + else + pwr_tracking_limit = 24; + } + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("TxRate=0x%x, PwrTrackingLimit=%d\n", tx_rate, pwr_tracking_limit)); + + + if (method == BBSWING) { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===>rtl8812ae_dm_txpwr_track_set_pwr\n")); + + if (rf_path == RF90_PATH_A) { + final_bb_swing_idx[RF90_PATH_A] = + (rtldm->ofdm_index[RF90_PATH_A] > pwr_tracking_limit) ? + pwr_tracking_limit : rtldm->ofdm_index[RF90_PATH_A]; + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("pDM_Odm->RFCalibrateInfo.OFDM_index[ODM_RF_PATH_A]=%d, \ + pDM_Odm->RealBbSwingIdx[ODM_RF_PATH_A]=%d\n", + rtldm->ofdm_index[RF90_PATH_A], final_bb_swing_idx[RF90_PATH_A])); + + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[final_bb_swing_idx[RF90_PATH_A]]); + } else { + final_bb_swing_idx[RF90_PATH_B] = + rtldm->ofdm_index[RF90_PATH_B] > pwr_tracking_limit ? \ + pwr_tracking_limit : rtldm->ofdm_index[RF90_PATH_B]; + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("pDM_Odm->RFCalibrateInfo.OFDM_index[ODM_RF_PATH_B]=%d, \ + pDM_Odm->RealBbSwingIdx[ODM_RF_PATH_B]=%d\n", + rtldm->ofdm_index[RF90_PATH_B], final_bb_swing_idx[RF90_PATH_B])); + + rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[final_bb_swing_idx[RF90_PATH_B]]); + } + } else if (method == MIX_MODE) { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("pDM_Odm->DefaultOfdmIndex=%d, \ + pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", + rtldm->default_ofdm_index, rtldm->aboslute_ofdm_swing_idx[rf_path], + rf_path )); + + + final_ofdm_swing_index = rtldm->default_ofdm_index + rtldm->aboslute_ofdm_swing_idx[rf_path]; + + if (rf_path == RF90_PATH_A) { + if(final_ofdm_swing_index > pwr_tracking_limit) { /*BBSwing higher then Limit*/ + + rtldm->remnant_cck_idx = final_ofdm_swing_index - pwr_tracking_limit; + /* CCK Follow the same compensate value as Path A*/ + rtldm->remnant_ofdm_swing_idx[rf_path] = final_ofdm_swing_index - pwr_tracking_limit; + + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[pwr_tracking_limit]); + + rtldm->modify_txagc_flag_path_a = true; + + /*Set TxAGC Page C{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_A); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d \n", + pwr_tracking_limit, rtldm->remnant_ofdm_swing_idx[rf_path])); + } else if (final_ofdm_swing_index < 0) { + rtldm->remnant_cck_idx = final_ofdm_swing_index; + /* CCK Follow the same compensate value as Path A*/ + rtldm->remnant_ofdm_swing_idx[rf_path] = final_ofdm_swing_index; + + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[0]); + + rtldm->modify_txagc_flag_path_a = true; + + /*Set TxAGC Page C{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_A); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A Lower then BBSwing lower bound 0 , Remnant TxAGC Value = %d \n", + rtldm->remnant_ofdm_swing_idx[rf_path])); + } else { + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[final_ofdm_swing_index]); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A Compensate with BBSwing , Final_OFDM_Swing_Index = %d \n", + final_ofdm_swing_index)); + + if(rtldm->modify_txagc_flag_path_a) { /*If TxAGC has changed, reset TxAGC again*/ + rtldm->remnant_cck_idx = 0; + rtldm->remnant_ofdm_swing_idx[rf_path] = 0; + + /*Set TxAGC Page C{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_A); + + rtldm->modify_txagc_flag_path_a = false; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A pDM_Odm->Modify_TxAGC_Flag = FALSE \n")); + } + } + } + + if (rf_path == RF90_PATH_B) { + if(final_ofdm_swing_index > pwr_tracking_limit) { /*BBSwing higher then Limit*/ + rtldm->remnant_ofdm_swing_idx[rf_path] = final_ofdm_swing_index - pwr_tracking_limit; + + rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[pwr_tracking_limit]); + + rtldm->modify_txagc_flag_path_b = true; + + /*Set TxAGC Page E{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_B); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_B Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d \n", + pwr_tracking_limit, rtldm->remnant_ofdm_swing_idx[rf_path])); + } else if (final_ofdm_swing_index < 0) { + rtldm->remnant_ofdm_swing_idx[rf_path] = final_ofdm_swing_index; + + rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[0]); + + rtldm->modify_txagc_flag_path_b = true; + + /*Set TxAGC Page E{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_B); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_B Lower then BBSwing lower bound 0 , Remnant TxAGC Value = %d \n", + rtldm->remnant_ofdm_swing_idx[rf_path] )); + } else { + rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[final_ofdm_swing_index]); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_B Compensate with BBSwing , Final_OFDM_Swing_Index = %d \n", + final_ofdm_swing_index)); + + if(rtldm->modify_txagc_flag_path_b) { /*If TxAGC has changed, reset TxAGC again*/ + rtldm->remnant_ofdm_swing_idx[rf_path] = 0; + + /*Set TxAGC Page E{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_B); + + rtldm->modify_txagc_flag_path_b = false; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_B pDM_Odm->Modify_TxAGC_Flag = FALSE \n")); + } + } + } + + } else { + return; + } +} + +void rtl8812ae_dm_txpower_tracking_callback_thermalmeter + (struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + u8 thermal_value = 0, delta, delta_lck, delta_iqk, p = 0, i = 0; + u8 thermal_value_avg_count = 0; + u32 thermal_value_avg = 0; + + u8 ofdm_min_index = 6; /*OFDM BB Swing should be less than +3.0dB, which is required by Arthur*/ + u8 index_for_channel = 0; /* GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/ + + /* 1. The following TWO tables decide the final index of OFDM/CCK swing table.*/ + u8 *delta_swing_table_idx_tup_a; + u8 *delta_swing_table_idx_tdown_a; + u8 *delta_swing_table_idx_tup_b; + u8 *delta_swing_table_idx_tdown_b; + + /*2. Initilization ( 7 steps in total )*/ + rtl8812ae_get_delta_swing_table(hw, (u8**)&delta_swing_table_idx_tup_a, + (u8**)&delta_swing_table_idx_tdown_a, + (u8**)&delta_swing_table_idx_tup_b, + (u8**)&delta_swing_table_idx_tdown_b); + + rtldm->btxpower_trackinginit = true; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===>rtl8812ae_dm_txpower_tracking_callback_thermalmeter, \ + \n pDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase[A]:\ + %d, pDM_Odm->DefaultOfdmIndex: %d\n", + rtldm->bb_swing_idx_cck_base, + rtldm->bb_swing_idx_ofdm_base[RF90_PATH_A], + rtldm->default_ofdm_index)); + + thermal_value = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER_8812A, 0xfc00); /*0x42: RF Reg[15:10] 88E*/ + if( ! rtldm->txpower_track_control || rtlefuse->eeprom_thermalmeter == 0 || + rtlefuse->eeprom_thermalmeter == 0xFF) + return; + + + /* 3. Initialize ThermalValues of RFCalibrateInfo*/ + + if(rtlhal->reloadtxpowerindex) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("reload ofdm index for band switch\n")); + } + + /*4. Calculate average thermal meter*/ + rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermal_value; + rtldm->thermalvalue_avg_index++; + if(rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8812A) + /*Average times = c.AverageThermalNum*/ + rtldm->thermalvalue_avg_index = 0; + + for(i = 0; i < AVG_THERMAL_NUM_8812A; i++) + { + if(rtldm->thermalvalue_avg[i]) + { + thermal_value_avg += rtldm->thermalvalue_avg[i]; + thermal_value_avg_count++; + } + } + + if(thermal_value_avg_count) /*Calculate Average ThermalValue after average enough times*/ + { + thermal_value = (u8)(thermal_value_avg / thermal_value_avg_count); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n", + thermal_value, rtlefuse->eeprom_thermalmeter)); + } + + /*5. Calculate delta, delta_LCK, delta_IQK.*/ + /*"delta" here is used to determine whether thermal value changes or not.*/ + delta = (thermal_value > rtldm->thermalvalue) ? \ + (thermal_value - rtldm->thermalvalue): \ + (rtldm->thermalvalue - thermal_value); + delta_lck = (thermal_value > rtldm->thermalvalue_lck) ? \ + (thermal_value - rtldm->thermalvalue_lck) : \ + (rtldm->thermalvalue_lck - thermal_value); + delta_iqk = (thermal_value > rtldm->thermalvalue_iqk) ? \ + (thermal_value - rtldm->thermalvalue_iqk) : \ + (rtldm->thermalvalue_iqk - thermal_value); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n", + delta, delta_lck, delta_iqk)); + + /* 6. If necessary, do LCK. */ + + if (delta_lck >= IQK_THRESHOLD) /*Delta temperature is equal to or larger than 20 centigrade.*/ + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("delta_LCK(%d) >= Threshold_IQK(%d)\n", + delta_lck, IQK_THRESHOLD)); + rtldm->thermalvalue_lck = thermal_value; + rtl8812ae_phy_lccalibrate(hw); + } + + /*7. If necessary, move the index of swing table to adjust Tx power.*/ + + if (delta > 0 && rtldm->txpower_track_control) + { + /*"delta" here is used to record the absolute value of differrence.*/ + delta = thermal_value > rtlefuse->eeprom_thermalmeter ? \ + (thermal_value - rtlefuse->eeprom_thermalmeter) : \ + (rtlefuse->eeprom_thermalmeter - thermal_value); + + if (delta >= TXPWR_TRACK_TABLE_SIZE) + delta = TXPWR_TRACK_TABLE_SIZE - 1; + + /*7.1 The Final Power Index = BaseIndex + PowerIndexOffset*/ + + if(thermal_value > rtlefuse->eeprom_thermalmeter) { + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("delta_swing_table_idx_tup_a[%d] = %d\n", + delta, delta_swing_table_idx_tup_a[delta])); + rtldm->delta_power_index_last[RF90_PATH_A] = rtldm->delta_power_index[RF90_PATH_A]; + rtldm->delta_power_index[RF90_PATH_A] = delta_swing_table_idx_tup_a[delta]; + + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A] = delta_swing_table_idx_tup_a[delta]; + /*Record delta swing for mix mode power tracking*/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A])); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("delta_swing_table_idx_tup_b[%d] = %d\n", + delta, delta_swing_table_idx_tup_b[delta])); + rtldm->delta_power_index_last[RF90_PATH_B] = rtldm->delta_power_index[RF90_PATH_B]; + rtldm->delta_power_index[RF90_PATH_B] = delta_swing_table_idx_tup_b[delta]; + + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_B] = delta_swing_table_idx_tup_b[delta]; + /*Record delta swing for mix mode power tracking*/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_B])); + + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("delta_swing_table_idx_tdown_a[%d] = %d\n", + delta, delta_swing_table_idx_tdown_a[delta])); + + rtldm->delta_power_index_last[RF90_PATH_A] = rtldm->delta_power_index[RF90_PATH_A]; + rtldm->delta_power_index[RF90_PATH_A] = -1 * delta_swing_table_idx_tdown_a[delta]; + + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A] = -1 * delta_swing_table_idx_tdown_a[delta]; + /* Record delta swing for mix mode power tracking*/ + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A])); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("deltaSwingTableIdx_TDOWN_B[%d] = %d\n", + delta, delta_swing_table_idx_tdown_b[delta])); + + rtldm->delta_power_index_last[RF90_PATH_B] = rtldm->delta_power_index[RF90_PATH_B]; + rtldm->delta_power_index[RF90_PATH_B] = -1 * delta_swing_table_idx_tdown_b[delta]; + + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_B] = -1 * delta_swing_table_idx_tdown_b[delta]; + /*Record delta swing for mix mode power tracking*/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_B])); + } + + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("\n\n================================ [Path-%c] \ + Calculating PowerIndexOffset ================================\n", + (p == RF90_PATH_A ? 'A' : 'B'))); + + if (rtldm->delta_power_index[p] == rtldm->delta_power_index_last[p]) + /*If Thermal value changes but lookup table value still the same*/ + rtldm->power_index_offset[p] = 0; + else + rtldm->power_index_offset[p] = + rtldm->delta_power_index[p] - rtldm->delta_power_index_last[p]; + /*Power Index Diff between 2 times Power Tracking*/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("[Path-%c] PowerIndexOffset(%d) = DeltaPowerIndex(%d) - DeltaPowerIndexLast(%d)\n", + (p == RF90_PATH_A ? 'A' : 'B'), + rtldm->power_index_offset[p], + rtldm->delta_power_index[p] , + rtldm->delta_power_index_last[p])); + + rtldm->ofdm_index[p] = + rtldm->bb_swing_idx_ofdm_base[p] + rtldm->power_index_offset[p]; + rtldm->cck_index = + rtldm->bb_swing_idx_cck_base + rtldm->power_index_offset[p]; + + rtldm->bb_swing_idx_cck = rtldm->cck_index; + rtldm->bb_swing_idx_ofdm[p] = rtldm->ofdm_index[p]; + + /*************Print BB Swing Base and Index Offset*************/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n", + rtldm->bb_swing_idx_cck, + rtldm->bb_swing_idx_cck_base, + rtldm->power_index_offset[p])); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n", + rtldm->bb_swing_idx_ofdm[p], + (p == RF90_PATH_A ? 'A' : 'B'), + rtldm->bb_swing_idx_ofdm_base[p], + rtldm->power_index_offset[p])); + + /*7.1 Handle boundary conditions of index.*/ + + + if(rtldm->ofdm_index[p] > TXSCALE_TABLE_SIZE -1) + { + rtldm->ofdm_index[p] = TXSCALE_TABLE_SIZE -1; + } + else if (rtldm->ofdm_index[p] < ofdm_min_index) + { + rtldm->ofdm_index[p] = ofdm_min_index; + } + } + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("\n\n======================================================\ + ==================================================\n")); + if(rtldm->cck_index > TXSCALE_TABLE_SIZE -1) + rtldm->cck_index = TXSCALE_TABLE_SIZE -1; + else if (rtldm->cck_index < 0) + rtldm->cck_index = 0; + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("The thermal meter is unchanged or TxPowerTracking OFF(%d): \ + ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n", + rtldm->txpower_track_control, + thermal_value, + rtldm->thermalvalue)); + + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) + rtldm->power_index_offset[p] = 0; + } + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n", + rtldm->cck_index, rtldm->bb_swing_idx_cck_base)); /*Print Swing base & current*/ + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index[%c]: %d\n", + rtldm->ofdm_index[p], + (p == RF90_PATH_A ? 'A' : 'B'), + rtldm->bb_swing_idx_ofdm_base[p])); + } + + if ((rtldm->power_index_offset[RF90_PATH_A] != 0 || + rtldm->power_index_offset[RF90_PATH_B] != 0 ) && + rtldm->txpower_track_control) + { + /*7.2 Configure the Swing Table to adjust Tx Power.*/ + /*Always TRUE after Tx Power is adjusted by power tracking.*/ + /* + 2012/04/23 MH According to Luke's suggestion, we can not write BB digital + to increase TX power. Otherwise, EVM will be bad. + + 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. + */ + if (thermal_value > rtldm->thermalvalue) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature Increasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + rtldm->power_index_offset[RF90_PATH_A], + delta, thermal_value, + rtlefuse->eeprom_thermalmeter, + rtldm->thermalvalue)); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature Increasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + rtldm->power_index_offset[RF90_PATH_B], + delta, thermal_value, + rtlefuse->eeprom_thermalmeter, + rtldm->thermalvalue)); + + } else if (thermal_value < rtldm->thermalvalue) { /*Low temperature*/ + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + rtldm->power_index_offset[RF90_PATH_A], + delta, thermal_value, + rtlefuse->eeprom_thermalmeter, + rtldm->thermalvalue)); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature Decreasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + rtldm->power_index_offset[RF90_PATH_B], + delta, thermal_value, + rtlefuse->eeprom_thermalmeter, + rtldm->thermalvalue)); + } + + if (thermal_value > rtlefuse->eeprom_thermalmeter) { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature(%d) higher than PG value(%d)\n", + thermal_value, rtlefuse->eeprom_thermalmeter)); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) + rtl8812ae_dm_txpwr_track_set_pwr(hw, MIX_MODE, p, 0); + + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature(%d) lower than PG value(%d)\n", + thermal_value, rtlefuse->eeprom_thermalmeter)); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) + rtl8812ae_dm_txpwr_track_set_pwr(hw, MIX_MODE, p, index_for_channel); + + } + + rtldm->bb_swing_idx_cck_base = rtldm->bb_swing_idx_cck; /*Record last time Power Tracking result as base.*/ + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) + rtldm->bb_swing_idx_ofdm_base[p] = rtldm->bb_swing_idx_ofdm[p]; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n", + rtldm->thermalvalue, thermal_value)); + + rtldm->thermalvalue = thermal_value; /*Record last Power Tracking Thermal Value*/ + + } + /*Delta temperature is equal to or larger than 20 centigrade (When threshold is 8).*/ + if ((delta_iqk >= IQK_THRESHOLD)) { + + if ( !rtlphy->b_iqk_in_progress) { + + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = true; + spin_unlock(&rtlpriv->locks.iqk_lock); + + rtl8812ae_do_iqk(hw, delta_iqk, thermal_value, 8); + + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = false; + spin_unlock(&rtlpriv->locks.iqk_lock); + } + } + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("<===rtl8812ae_dm_txpower_tracking_callback_thermalmeter\n")); +} + + +void rtl8821ae_get_delta_swing_table( + struct ieee80211_hw *hw, + u8 **temperature_up_a, + u8 **temperature_down_a, + u8 **temperature_up_b, + u8 **temperature_down_b + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 channel = rtlphy->current_channel; + u8 rate = rtldm->tx_rate; + + + if ( 1 <= channel && channel <= 14) { + if (RX_HAL_IS_CCK_RATE(rate)) { + *temperature_up_a = rtldm->delta_swing_table_idx_24gccka_p; + *temperature_down_a = rtldm->delta_swing_table_idx_24gccka_n; + *temperature_up_b = rtldm->delta_swing_table_idx_24gcckb_p; + *temperature_down_b = rtldm->delta_swing_table_idx_24gcckb_n; + } else { + *temperature_up_a = rtldm->delta_swing_table_idx_24ga_p; + *temperature_down_a = rtldm->delta_swing_table_idx_24ga_n; + *temperature_up_b = rtldm->delta_swing_table_idx_24gb_p; + *temperature_down_b = rtldm->delta_swing_table_idx_24gb_n; + } + } else if ( 36 <= channel && channel <= 64) { + *temperature_up_a = rtldm->delta_swing_table_idx_5ga_p[0]; + *temperature_down_a = rtldm->delta_swing_table_idx_5ga_n[0]; + *temperature_up_b = rtldm->delta_swing_table_idx_5gb_p[0]; + *temperature_down_b = rtldm->delta_swing_table_idx_5gb_n[0]; + } else if ( 100 <= channel && channel <= 140) { + *temperature_up_a = rtldm->delta_swing_table_idx_5ga_p[1]; + *temperature_down_a = rtldm->delta_swing_table_idx_5ga_n[1]; + *temperature_up_b = rtldm->delta_swing_table_idx_5gb_p[1]; + *temperature_down_b = rtldm->delta_swing_table_idx_5gb_n[1]; + } else if ( 149 <= channel && channel <= 173) { + *temperature_up_a = rtldm->delta_swing_table_idx_5ga_p[2]; + *temperature_down_a = rtldm->delta_swing_table_idx_5ga_n[2]; + *temperature_up_b = rtldm->delta_swing_table_idx_5gb_p[2]; + *temperature_down_b = rtldm->delta_swing_table_idx_5gb_n[2]; + } else { + *temperature_up_a = (u8*)rtl8818e_delta_swing_table_idx_24gb_p_txpwrtrack; + *temperature_down_a =(u8*)rtl8818e_delta_swing_table_idx_24gb_n_txpwrtrack; + *temperature_up_b = (u8*)rtl8818e_delta_swing_table_idx_24gb_p_txpwrtrack; + *temperature_down_b = (u8*)rtl8818e_delta_swing_table_idx_24gb_n_txpwrtrack; + } + + return; +} + +void rtl8821ae_phy_lccalibrate( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("===> rtl8812ae_phy_lccalibrate\n")); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("<=== rtl8812ae_phy_lccalibrate\n")); + +} + +/*----------------------------------------------------------------------------- + * Function: odm_TxPwrTrackSetPwr88E() + * + * Overview: 88E change all channel tx power accordign to flag. + * OFDM & CCK are all different. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 04/23/2012 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void rtl8821ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, + enum pwr_track_control_method method, u8 rf_path, u8 channel_mapped_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 final_bb_swing_idx[1]; + u8 pwr_tracking_limit = 26; /*+1.0dB*/ + u8 tx_rate = 0xFF; + s8 final_ofdm_swing_index = 0; + + if(rtldm->tx_rate != 0xFF) + tx_rate = rtl8812ae_hw_rate_to_mrate(hw, rtldm->tx_rate); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===>rtl8812ae_dm_txpwr_track_set_pwr\n")); + + if(tx_rate != 0xFF) { /*20130429 Mimic Modify High Rate BBSwing Limit.*/ + /*CCK*/ + if((tx_rate >= MGN_1M) && (tx_rate <= MGN_11M)) + pwr_tracking_limit = 32; /*+4dB*/ + /*OFDM*/ + else if((tx_rate >= MGN_6M) && (tx_rate <= MGN_48M)) + pwr_tracking_limit = 30; /*+3dB*/ + else if(tx_rate == MGN_54M) + pwr_tracking_limit = 28; /*+2dB*/ + /*HT*/ + else if((tx_rate >= MGN_MCS0) && (tx_rate <= MGN_MCS2)) /*QPSK/BPSK*/ + pwr_tracking_limit = 34; /*+5dB*/ + else if((tx_rate >= MGN_MCS3) && (tx_rate <= MGN_MCS4)) /*16QAM*/ + pwr_tracking_limit = 30; /*+3dB*/ + else if((tx_rate >= MGN_MCS5) && (tx_rate <= MGN_MCS7)) /*64QAM*/ + pwr_tracking_limit = 28; /*+2dB*/ +#if 0 + else if((tx_rate >= MGN_MCS8) && (tx_rate <= MGN_MCS10)) /*QPSK/BPSK*/ + pwr_tracking_limit = 34; /*+5dB*/ + else if((tx_rate >= MGN_MCS11) && (tx_rate <= MGN_MCS12)) /*16QAM*/ + pwr_tracking_limit = 30; /*+3dB*/ + else if((tx_rate >= MGN_MCS13) && (tx_rate <= MGN_MCS15)) /*64QAM*/ + pwr_tracking_limit = 28; /*+2dB*/ +#endif + /*2 VHT*/ + else if((tx_rate >= MGN_VHT1SS_MCS0) && (tx_rate <= MGN_VHT1SS_MCS2)) /*QPSK/BPSK*/ + pwr_tracking_limit = 34; /*+5dB*/ + else if((tx_rate >= MGN_VHT1SS_MCS3) && (tx_rate <= MGN_VHT1SS_MCS4)) /*16QAM*/ + pwr_tracking_limit = 30; /*+3dB*/ + else if((tx_rate >= MGN_VHT1SS_MCS5)&&(tx_rate <= MGN_VHT1SS_MCS6)) /*64QAM*/ + pwr_tracking_limit = 28; /*+2dB*/ + else if(tx_rate == MGN_VHT1SS_MCS7) /*64QAM*/ + pwr_tracking_limit = 26; /*+1dB*/ + else if(tx_rate == MGN_VHT1SS_MCS8) /*256QAM*/ + pwr_tracking_limit = 24; /*+0dB*/ + else if(tx_rate == MGN_VHT1SS_MCS9) /*256QAM*/ + pwr_tracking_limit = 22; /*-1dB*/ + else + pwr_tracking_limit = 24; + } + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("TxRate=0x%x, PwrTrackingLimit=%d\n", tx_rate, pwr_tracking_limit)); + + + if (method == BBSWING) { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===>rtl8812ae_dm_txpwr_track_set_pwr\n")); + + if (rf_path == RF90_PATH_A) { + final_bb_swing_idx[RF90_PATH_A] = + (rtldm->ofdm_index[RF90_PATH_A] > pwr_tracking_limit) ? + pwr_tracking_limit : rtldm->ofdm_index[RF90_PATH_A]; + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("pDM_Odm->RFCalibrateInfo.OFDM_index[ODM_RF_PATH_A]=%d, \ + pDM_Odm->RealBbSwingIdx[ODM_RF_PATH_A]=%d\n", + rtldm->ofdm_index[RF90_PATH_A], final_bb_swing_idx[RF90_PATH_A])); + + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[final_bb_swing_idx[RF90_PATH_A]]); + } + } else if (method == MIX_MODE) { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("pDM_Odm->DefaultOfdmIndex=%d, \ + pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", + rtldm->default_ofdm_index, rtldm->aboslute_ofdm_swing_idx[rf_path], + rf_path )); + + + final_ofdm_swing_index = rtldm->default_ofdm_index + rtldm->aboslute_ofdm_swing_idx[rf_path]; + + if (rf_path == RF90_PATH_A) { + if(final_ofdm_swing_index > pwr_tracking_limit) { /*BBSwing higher then Limit*/ + + rtldm->remnant_cck_idx = final_ofdm_swing_index - pwr_tracking_limit; + /* CCK Follow the same compensate value as Path A*/ + rtldm->remnant_ofdm_swing_idx[rf_path] = final_ofdm_swing_index - pwr_tracking_limit; + + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[pwr_tracking_limit]); + + rtldm->modify_txagc_flag_path_a = true; + + /*Set TxAGC Page C{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_A); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d \n", + pwr_tracking_limit, rtldm->remnant_ofdm_swing_idx[rf_path])); + } else if (final_ofdm_swing_index < 0) { + rtldm->remnant_cck_idx = final_ofdm_swing_index; + /* CCK Follow the same compensate value as Path A*/ + rtldm->remnant_ofdm_swing_idx[rf_path] = final_ofdm_swing_index; + + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[0]); + + rtldm->modify_txagc_flag_path_a = true; + + /*Set TxAGC Page C{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_A); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A Lower then BBSwing lower bound 0 , Remnant TxAGC Value = %d \n", + rtldm->remnant_ofdm_swing_idx[rf_path])); + } else { + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, rtl8812ae_txscaling_table[final_ofdm_swing_index]); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A Compensate with BBSwing , Final_OFDM_Swing_Index = %d \n", + final_ofdm_swing_index)); + + if(rtldm->modify_txagc_flag_path_a) { /*If TxAGC has changed, reset TxAGC again*/ + rtldm->remnant_cck_idx = 0; + rtldm->remnant_ofdm_swing_idx[rf_path] = 0; + + /*Set TxAGC Page C{};*/ + rtl8821ae_phy_set_txpower_level_by_path(hw, rtlphy->current_channel, RF90_PATH_A); + + rtldm->modify_txagc_flag_path_a = false; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Path_A pDM_Odm->Modify_TxAGC_Flag = FALSE \n")); + } + } + } + + } else { + return; + } +} + + +void rtl8821ae_dm_txpower_tracking_callback_thermalmeter + (struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + u8 thermal_value = 0, delta, delta_lck, delta_iqk, p = 0, i = 0; + u8 thermal_value_avg_count = 0; + u32 thermal_value_avg = 0; + + u8 ofdm_min_index = 6; /*OFDM BB Swing should be less than +3.0dB, which is required by Arthur*/ + u8 index_for_channel = 0; /* GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/ + + /* 1. The following TWO tables decide the final index of OFDM/CCK swing table.*/ + u8 *delta_swing_table_idx_tup_a; + u8 *delta_swing_table_idx_tdown_a; + u8 *delta_swing_table_idx_tup_b; + u8 *delta_swing_table_idx_tdown_b; + + /*2. Initilization ( 7 steps in total )*/ + rtl8821ae_get_delta_swing_table(hw, (u8**)&delta_swing_table_idx_tup_a, + (u8**)&delta_swing_table_idx_tdown_a, + (u8**)&delta_swing_table_idx_tup_b, + (u8**)&delta_swing_table_idx_tdown_b); + + rtldm->btxpower_trackinginit = true; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===>rtl8812ae_dm_txpower_tracking_callback_thermalmeter, \ + \n pDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase[A]:\ + %d, pDM_Odm->DefaultOfdmIndex: %d\n", + rtldm->bb_swing_idx_cck_base, + rtldm->bb_swing_idx_ofdm_base[RF90_PATH_A], + rtldm->default_ofdm_index)); + + thermal_value = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER_8812A, 0xfc00); /*0x42: RF Reg[15:10] 88E*/ + if( ! rtldm->txpower_track_control || rtlefuse->eeprom_thermalmeter == 0 || + rtlefuse->eeprom_thermalmeter == 0xFF) + return; + + + /* 3. Initialize ThermalValues of RFCalibrateInfo*/ + + if(rtlhal->reloadtxpowerindex) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("reload ofdm index for band switch\n")); + } + + /*4. Calculate average thermal meter*/ + rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermal_value; + rtldm->thermalvalue_avg_index++; + if(rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8812A) + /*Average times = c.AverageThermalNum*/ + rtldm->thermalvalue_avg_index = 0; + + for(i = 0; i < AVG_THERMAL_NUM_8812A; i++) + { + if(rtldm->thermalvalue_avg[i]) + { + thermal_value_avg += rtldm->thermalvalue_avg[i]; + thermal_value_avg_count++; + } + } + + if(thermal_value_avg_count) /*Calculate Average ThermalValue after average enough times*/ + { + thermal_value = (u8)(thermal_value_avg / thermal_value_avg_count); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n", + thermal_value, rtlefuse->eeprom_thermalmeter)); + } + + /*5. Calculate delta, delta_LCK, delta_IQK.*/ + /*"delta" here is used to determine whether thermal value changes or not.*/ + delta = (thermal_value > rtldm->thermalvalue) ? \ + (thermal_value - rtldm->thermalvalue): \ + (rtldm->thermalvalue - thermal_value); + delta_lck = (thermal_value > rtldm->thermalvalue_lck) ? \ + (thermal_value - rtldm->thermalvalue_lck) : \ + (rtldm->thermalvalue_lck - thermal_value); + delta_iqk = (thermal_value > rtldm->thermalvalue_iqk) ? \ + (thermal_value - rtldm->thermalvalue_iqk) : \ + (rtldm->thermalvalue_iqk - thermal_value); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n", + delta, delta_lck, delta_iqk)); + + /* 6. If necessary, do LCK. */ + + if (delta_lck >= IQK_THRESHOLD) /*Delta temperature is equal to or larger than 20 centigrade.*/ + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("delta_LCK(%d) >= Threshold_IQK(%d)\n", + delta_lck, IQK_THRESHOLD)); + rtldm->thermalvalue_lck = thermal_value; + rtl8821ae_phy_lccalibrate(hw); + } + + /*7. If necessary, move the index of swing table to adjust Tx power.*/ + + if (delta > 0 && rtldm->txpower_track_control) + { + /*"delta" here is used to record the absolute value of differrence.*/ + delta = thermal_value > rtlefuse->eeprom_thermalmeter ? \ + (thermal_value - rtlefuse->eeprom_thermalmeter) : \ + (rtlefuse->eeprom_thermalmeter - thermal_value); + + if (delta >= TXSCALE_TABLE_SIZE) + delta = TXSCALE_TABLE_SIZE - 1; + + /*7.1 The Final Power Index = BaseIndex + PowerIndexOffset*/ + + if(thermal_value > rtlefuse->eeprom_thermalmeter) { + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("delta_swing_table_idx_tup_a[%d] = %d\n", + delta, delta_swing_table_idx_tup_a[delta])); + rtldm->delta_power_index_last[RF90_PATH_A] = rtldm->delta_power_index[RF90_PATH_A]; + rtldm->delta_power_index[RF90_PATH_A] = delta_swing_table_idx_tup_a[delta]; + + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A] = delta_swing_table_idx_tup_a[delta]; + /*Record delta swing for mix mode power tracking*/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A])); + + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("delta_swing_table_idx_tdown_a[%d] = %d\n", + delta, delta_swing_table_idx_tdown_a[delta])); + + rtldm->delta_power_index_last[RF90_PATH_A] = rtldm->delta_power_index[RF90_PATH_A]; + rtldm->delta_power_index[RF90_PATH_A] = -1 * delta_swing_table_idx_tdown_a[delta]; + + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A] = -1 * delta_swing_table_idx_tdown_a[delta]; + /* Record delta swing for mix mode power tracking*/ + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + rtldm->aboslute_ofdm_swing_idx[RF90_PATH_A])); + } + + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("\n\n================================ [Path-%c] \ + Calculating PowerIndexOffset ================================\n", + (p == RF90_PATH_A ? 'A' : 'B'))); + + if (rtldm->delta_power_index[p] == rtldm->delta_power_index_last[p]) + /*If Thermal value changes but lookup table value still the same*/ + rtldm->power_index_offset[p] = 0; + else + rtldm->power_index_offset[p] = + rtldm->delta_power_index[p] - rtldm->delta_power_index_last[p]; + /*Power Index Diff between 2 times Power Tracking*/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("[Path-%c] PowerIndexOffset(%d) = DeltaPowerIndex(%d) - DeltaPowerIndexLast(%d)\n", + (p == RF90_PATH_A ? 'A' : 'B'), + rtldm->power_index_offset[p], + rtldm->delta_power_index[p] , + rtldm->delta_power_index_last[p])); + + rtldm->ofdm_index[p] = + rtldm->bb_swing_idx_ofdm_base[p] + rtldm->power_index_offset[p]; + rtldm->cck_index = + rtldm->bb_swing_idx_cck_base + rtldm->power_index_offset[p]; + + rtldm->bb_swing_idx_cck = rtldm->cck_index; + rtldm->bb_swing_idx_ofdm[p] = rtldm->ofdm_index[p]; + + /*************Print BB Swing Base and Index Offset*************/ + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n", + rtldm->bb_swing_idx_cck, + rtldm->bb_swing_idx_cck_base, + rtldm->power_index_offset[p])); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n", + rtldm->bb_swing_idx_ofdm[p], + (p == RF90_PATH_A ? 'A' : 'B'), + rtldm->bb_swing_idx_ofdm_base[p], + rtldm->power_index_offset[p])); + + /*7.1 Handle boundary conditions of index.*/ + + + if(rtldm->ofdm_index[p] > TXSCALE_TABLE_SIZE -1) + { + rtldm->ofdm_index[p] = TXSCALE_TABLE_SIZE -1; + } + else if (rtldm->ofdm_index[p] < ofdm_min_index) + { + rtldm->ofdm_index[p] = ofdm_min_index; + } + } + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("\n\n======================================================\ + ==================================================\n")); + if(rtldm->cck_index > TXSCALE_TABLE_SIZE -1) + rtldm->cck_index = TXSCALE_TABLE_SIZE -1; + else if (rtldm->cck_index < 0) + rtldm->cck_index = 0; + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("The thermal meter is unchanged or TxPowerTracking OFF(%d): \ + ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n", + rtldm->txpower_track_control, + thermal_value, + rtldm->thermalvalue)); + + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) + rtldm->power_index_offset[p] = 0; + } + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n", + rtldm->cck_index, rtldm->bb_swing_idx_cck_base)); /*Print Swing base & current*/ + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index[%c]: %d\n", + rtldm->ofdm_index[p], + (p == RF90_PATH_A ? 'A' : 'B'), + rtldm->bb_swing_idx_ofdm_base[p])); + } + + if ((rtldm->power_index_offset[RF90_PATH_A] != 0 || + rtldm->power_index_offset[RF90_PATH_B] != 0 ) && + rtldm->txpower_track_control) + { + /*7.2 Configure the Swing Table to adjust Tx Power.*/ + /*Always TRUE after Tx Power is adjusted by power tracking.*/ + /* + 2012/04/23 MH According to Luke's suggestion, we can not write BB digital + to increase TX power. Otherwise, EVM will be bad. + + 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. + */ + if (thermal_value > rtldm->thermalvalue) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature Increasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + rtldm->power_index_offset[RF90_PATH_A], + delta, thermal_value, + rtlefuse->eeprom_thermalmeter, + rtldm->thermalvalue)); + } else if (thermal_value < rtldm->thermalvalue) { /*Low temperature*/ + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + rtldm->power_index_offset[RF90_PATH_A], + delta, thermal_value, + rtlefuse->eeprom_thermalmeter, + rtldm->thermalvalue)); + } + + if (thermal_value > rtlefuse->eeprom_thermalmeter) { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature(%d) higher than PG value(%d)\n", + thermal_value, rtlefuse->eeprom_thermalmeter)); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) + rtl8821ae_dm_txpwr_track_set_pwr(hw, MIX_MODE, p, index_for_channel); + + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Temperature(%d) lower than PG value(%d)\n", + thermal_value, rtlefuse->eeprom_thermalmeter)); + + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) + rtl8812ae_dm_txpwr_track_set_pwr(hw, MIX_MODE, p, index_for_channel); + + } + + rtldm->bb_swing_idx_cck_base = rtldm->bb_swing_idx_cck; /*Record last time Power Tracking result as base.*/ + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) + rtldm->bb_swing_idx_ofdm_base[p] = rtldm->bb_swing_idx_ofdm[p]; + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n", + rtldm->thermalvalue, thermal_value)); + + rtldm->thermalvalue = thermal_value; /*Record last Power Tracking Thermal Value*/ + + } + /*Delta temperature is equal to or larger than 20 centigrade (When threshold is 8).*/ + if ((delta_iqk >= IQK_THRESHOLD)) { + + if ( !rtlphy->b_iqk_in_progress) { + + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = true; + spin_unlock(&rtlpriv->locks.iqk_lock); + + rtl8821ae_do_iqk(hw, delta_iqk, thermal_value, 8); + + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = false; + spin_unlock(&rtlpriv->locks.iqk_lock); + } + } + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("<===rtl8812ae_dm_txpower_tracking_callback_thermalmeter\n")); +} + + +void rtl8821ae_dm_check_txpower_tracking_thermalmeter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static u8 tm_trigger = 0; + + //if (!rtlpriv->dm.btxpower_tracking) + // return; + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E, BIT(17)|BIT(16), + 0x03); + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Trigger 8821ae Thermal Meter!!\n")); + tm_trigger = 1; + return; + } else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("Schedule TxPowerTracking !!\n")); + + rtl8821ae_dm_txpower_tracking_callback_thermalmeter(hw); + tm_trigger = 0; + } +} + + +void rtl8821ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rate_adaptive *p_ra = &(rtlpriv->ra); + u32 low_rssithresh_for_ra = p_ra->low2high_rssi_thresh_for_ra; + u32 high_rssithresh_for_ra = p_ra->high_rssi_thresh_for_ra; + u8 go_up_gap = 5; + struct ieee80211_sta *sta = NULL; + + if (is_hal_stop(rtlhal)) { + RT_TRACE(COMP_RATE, DBG_LOUD, + ("driver is going to unload\n")); + return; + } + + if (!rtlpriv->dm.b_useramask) { + RT_TRACE(COMP_RATE, DBG_LOUD, + ("driver does not control rate adaptive mask\n")); + return; + } + + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { + + switch (p_ra->pre_ratr_state) { + case DM_RATR_STA_MIDDLE: + high_rssithresh_for_ra += go_up_gap; + break; + case DM_RATR_STA_LOW: + high_rssithresh_for_ra += go_up_gap; + low_rssithresh_for_ra += go_up_gap; + break; + default: + break; + } + + if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)high_rssithresh_for_ra) + p_ra->ratr_state = DM_RATR_STA_HIGH; + else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)low_rssithresh_for_ra) + p_ra->ratr_state = DM_RATR_STA_MIDDLE; + else + p_ra->ratr_state = DM_RATR_STA_LOW; + + if (p_ra->pre_ratr_state != p_ra->ratr_state ) { + RT_TRACE(COMP_RATE, DBG_LOUD, + ("RSSI = %ld\n", + rtlpriv->dm.undecorated_smoothed_pwdb)); + RT_TRACE(COMP_RATE, DBG_LOUD, + ("RSSI_LEVEL = %d\n", p_ra->ratr_state)); + RT_TRACE(COMP_RATE, DBG_LOUD, + ("PreState = %d, CurState = %d\n", + p_ra->pre_ratr_state, p_ra->ratr_state)); + + rcu_read_lock(); + sta = rtl_find_sta(hw, mac->bssid); + if (sta) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, p_ra->ratr_state); + rcu_read_unlock(); + + p_ra->pre_ratr_state = p_ra->ratr_state; + } + } +} + +bool rtl8821ae_dm_is_edca_turbo_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->btcoexist.btc_ops->btc_is_disable_edca_turbo(rtlpriv)) + return true; + if (rtlpriv->mac80211.mode == WIRELESS_MODE_B) + return true; + + return false; +} + +void rtl8821ae_dm_edca_choose_traffic_idx( + struct ieee80211_hw *hw, u64 cur_tx_bytes, u64 cur_rx_bytes, bool b_bias_on_rx, + bool *pb_is_cur_rdl_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if(b_bias_on_rx) + { + if (cur_tx_bytes > (cur_rx_bytes*4)) { + *pb_is_cur_rdl_state = false; + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("Uplink Traffic\n ")); + } else { + *pb_is_cur_rdl_state = true; + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("Balance Traffic\n")); + } + } else { + if (cur_rx_bytes > (cur_tx_bytes*4)) { + *pb_is_cur_rdl_state = true; + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("Downlink Traffic\n")); + } else { + *pb_is_cur_rdl_state = false; + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("Balance Traffic\n")); + } + } + return ; +} + +static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + + /*Keep past Tx/Rx packet count for RT-to-RT EDCA turbo.*/ + unsigned long cur_tx_ok_cnt = 0; + unsigned long cur_rx_ok_cnt = 0; + u32 edca_be_ul = 0x5ea42b; + u32 edca_be_dl = 0x5ea42b; + u32 edca_be = 0x5ea42b; + u8 iot_peer = 0; + bool *pb_is_cur_rdl_state = NULL; + bool b_last_is_cur_rdl_state = false; + bool b_bias_on_rx = false; + bool b_edca_turbo_on = false; + + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("rtl8821ae_dm_check_edca_turbo=====>")); + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("Orginial BE PARAM: 0x%x\n", + rtl_read_dword(rtlpriv, DM_REG_EDCA_BE_11N))); + + /*=============================== + list paramter for different platform + ===============================*/ + b_last_is_cur_rdl_state = rtlpriv->dm.bis_cur_rdlstate; + pb_is_cur_rdl_state = &( rtlpriv->dm.bis_cur_rdlstate); + + cur_tx_ok_cnt = rtlpriv->stats.txbytesunicast - rtldm->last_tx_ok_cnt; + cur_rx_ok_cnt = rtlpriv->stats.rxbytesunicast - rtldm->last_rx_ok_cnt; + + rtldm->last_tx_ok_cnt = rtlpriv->stats.txbytesunicast; + rtldm->last_rx_ok_cnt = rtlpriv->stats.rxbytesunicast; + + iot_peer = rtlpriv->mac80211.vendor; + b_bias_on_rx = (iot_peer == PEER_RAL || iot_peer == PEER_ATH) ? + true : false; + b_edca_turbo_on = ((!rtlpriv->dm.bis_any_nonbepkts) && + (!rtlpriv->dm.b_disable_framebursting)) ? + true : false; + + /*if (rtl8821ae_dm_is_edca_turbo_disable(hw)) + goto dm_CheckEdcaTurbo_EXIT;*/ + + if ((iot_peer == PEER_CISCO) && (mac->mode == WIRELESS_MODE_N_24G)) + { + edca_be_dl = edca_setting_dl[iot_peer]; + edca_be_ul = edca_setting_ul[iot_peer]; + } + + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("bIsAnyNonBEPkts : 0x%x bDisableFrameBursting : 0x%x \n", + rtlpriv->dm.bis_any_nonbepkts, rtlpriv->dm.b_disable_framebursting)); + + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("bEdcaTurboOn : 0x%x bBiasOnRx : 0x%x\n", + b_edca_turbo_on, b_bias_on_rx)); + + if (b_edca_turbo_on) { + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("curTxOkCnt : 0x%lx \n",cur_tx_ok_cnt)); + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("curRxOkCnt : 0x%lx \n",cur_rx_ok_cnt)); + if(b_bias_on_rx) + rtl8821ae_dm_edca_choose_traffic_idx(hw, cur_tx_ok_cnt, + cur_rx_ok_cnt, true, pb_is_cur_rdl_state); + else + rtl8821ae_dm_edca_choose_traffic_idx(hw, cur_tx_ok_cnt, + cur_rx_ok_cnt, false, pb_is_cur_rdl_state); + + edca_be = ((*pb_is_cur_rdl_state) == true) ? edca_be_dl : edca_be_ul; + + rtl_write_dword(rtlpriv, DM_REG_EDCA_BE_11N, edca_be); + + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("EDCA Turbo on: EDCA_BE:0x%x\n", edca_be)); + + rtlpriv->dm.bcurrent_turbo_edca = true; + + RT_TRACE(COMP_TURBO, DBG_LOUD, + ("EDCA_BE_DL : 0x%x EDCA_BE_UL : 0x%x EDCA_BE : 0x%x \n", + edca_be_dl, edca_be_ul, edca_be)); + } else { + if (rtlpriv->dm.bcurrent_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *) (&tmp)); + } + rtlpriv->dm.bcurrent_turbo_edca = false; + } + +/* dm_CheckEdcaTurbo_EXIT: */ + rtlpriv->dm.bis_any_nonbepkts = false; + rtldm->last_tx_ok_cnt = rtlpriv->stats.txbytesunicast; + rtldm->last_rx_ok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl8821ae_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 cur_cck_cca_thresh; + + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) { + /*dm_digtable.rssi_val_min = rtl8821ae_dm_initial_gain_min_pwdb(hw);*/ + if (dm_digtable.rssi_val_min > 25) + cur_cck_cca_thresh = 0xcd; + else if ((dm_digtable.rssi_val_min <= 25) && (dm_digtable.rssi_val_min > 10)) + cur_cck_cca_thresh = 0x83; + else { + if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000) + cur_cck_cca_thresh = 0x83; + else + cur_cck_cca_thresh = 0x40; + } + + } else { + if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000) + cur_cck_cca_thresh = 0x83; + else + cur_cck_cca_thresh = 0x40; + } + + if (dm_digtable.cur_cck_cca_thres != cur_cck_cca_thresh) { + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh); + } + + dm_digtable.pre_cck_cca_thres = dm_digtable.cur_cck_cca_thres; + dm_digtable.cur_cck_cca_thres = cur_cck_cca_thresh; + RT_TRACE(COMP_DIG, DBG_TRACE, + ("CCK cca thresh hold =%x\n", dm_digtable.cur_cck_cca_thres)); + +} + +void rtl8821ae_dm_dynamic_edcca(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool b_fw_current_in_ps_mode = false; + + rtlpriv->cfg->ops->get_hw_reg(hw,HW_VAR_FW_PSMODE_STATUS, \ + (u8*)(&b_fw_current_in_ps_mode)); + if (b_fw_current_in_ps_mode) + return; +} + +void rtl8812ae_dm_update_txpath(struct ieee80211_hw *hw, u8 path) +{ + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtldm->resp_tx_path != path) { + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("Need to Update Tx Path\n")); + if (path == RF90_PATH_A) { + /*Tx by Reg*/ + rtl_set_bbreg(hw, 0x80c, 0xFFF0, 0x111); + /*Resp Tx by Txinfo*/ + rtl_set_bbreg(hw, 0x6d8, BIT(7) | BIT(6), 1); + } else { + /*Tx by Reg*/ + rtl_set_bbreg(hw, 0x80c, 0xFFF0, 0x222); + /*Resp Tx by Txinfo*/ + rtl_set_bbreg(hw, 0x6d8, BIT(7) |BIT(6), 2); + } + } + rtldm->resp_tx_path = path; + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("Path=%s\n",(path == RF90_PATH_A) ? \ + "RF90_PATH_A":"RF90_PATH_A")); +} + +void rtl8812ae_dm_path_diversity_init(struct ieee80211_hw *hw) +{ + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + + //rtl_set_bbreg(hw, 0x80c , BIT(29), 1); /*Tx path from Reg*/ + rtl_set_bbreg(hw, 0x80c , 0xFFF0, 0x111); /*Tx by Reg*/ + rtl_set_bbreg(hw, 0x6d8 , BIT(7) | BIT(6), 1); /*Resp Tx by Txinfo*/ + rtl8812ae_dm_update_txpath(hw, RF90_PATH_A); + + rtldm->path_sel = 1; /* TxInfo default at path-A*/ +} + +void rtl812ae_dm_set_txpath_by_txinfo(struct ieee80211_hw *hw, + u8 *pdesc) +{ + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + + SET_TX_DESC_TX_ANT(pdesc, rtldm->path_sel); +} + +void rtl8812ae_dm_path_statistics(struct ieee80211_hw *hw, + u32 rssi_a, u32 rssi_b) +{ + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + + rtldm->patha_sum += rssi_a; + rtldm->patha_cnt ++; + + rtldm->pathb_sum += rssi_b; + rtldm->pathb_cnt ++; +} + +void rtl8812ae_dm_path_diversity(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u32 rssi_avg_a = 0; + u32 rssi_avg_b = 0; + u32 local_min_rssi = 0; + u32 min_rssi = 0xFF; + u8 tx_resp_path=0, target_path; + struct ieee80211_sta *sta = NULL; + + sta = rtl_find_sta(hw, mac->bssid); + if (sta) { + /*Caculate RSSI per Path*/ + rssi_avg_a = (rtldm->patha_cnt != 0) ? \ + (rtldm->patha_sum / rtldm->patha_cnt) : 0; + rssi_avg_b = (rtldm->pathb_cnt != 0) ? \ + (rtldm->pathb_sum / rtldm->pathb_cnt) : 0; + + target_path = (rssi_avg_a == rssi_avg_b) ? rtldm->resp_tx_path : \ + ((rssi_avg_a>=rssi_avg_b) ? RF90_PATH_A : RF90_PATH_B); + + RT_TRACE(COMP_DIG, DBG_TRACE, \ + ("assoc_id=%d, PathA_Sum=%d, PathA_Cnt=%d\n", \ + mac->assoc_id, rtldm->patha_sum, rtldm->patha_cnt)); + RT_TRACE(COMP_DIG, DBG_TRACE, \ + ("assoc_id=%d, PathB_Sum=%d, PathB_Cnt=%d\n", \ + mac->assoc_id, rtldm->pathb_sum, rtldm->pathb_cnt)); + RT_TRACE(COMP_DIG, DBG_TRACE, \ + ("assoc_id=%d, RssiAvgA= %d, RssiAvgB= %d\n", \ + mac->assoc_id, rssi_avg_a, rssi_avg_b)); + + /*Select Resp Tx Path*/ + local_min_rssi = (rssi_avg_a > rssi_avg_b) ? rssi_avg_b : rssi_avg_a; + if(local_min_rssi < min_rssi) + { + min_rssi = local_min_rssi; + tx_resp_path = target_path; + } + + /*Select Tx DESC*/ + if(target_path == RF90_PATH_A) + rtldm->path_sel = 1; + else + rtldm->path_sel = 2; + + RT_TRACE(COMP_DIG, DBG_TRACE, \ + ("Tx from TxInfo, TargetPath=%s\n", \ + (target_path==RF90_PATH_A) ? \ + "ODM_RF_PATH_A":"ODM_RF_PATH_B")); + RT_TRACE(COMP_DIG, DBG_TRACE, \ + ("pDM_PathDiv->PathSel= %d\n", \ + rtldm->path_sel)); + } + rtldm->patha_cnt = 0; + rtldm->patha_sum = 0; + rtldm->pathb_cnt = 0; + rtldm->pathb_sum = 0; +} + +void rtl8821ae_dm_dynamic_atc_switch(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 crystal_cap; + u32 packet_count; + int cfo_khz_a,cfo_khz_b,cfo_ave = 0, adjust_xtal = 0; + int cfo_ave_diff; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED){ + /*1.Enable ATC*/ + if (rtldm->atc_status == ATC_STATUS_OFF) + { + rtl_set_bbreg(hw, RFC_AREA, BIT(14), ATC_STATUS_ON); + rtldm->atc_status = ATC_STATUS_ON; + } + + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): No link!!\n")); + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): atc_status = %d\n", \ + rtldm->atc_status)); + + if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) + { + rtldm->crystal_cap = rtlpriv->efuse.crystalcap; + crystal_cap = rtldm->crystal_cap & 0x3f; + crystal_cap = crystal_cap & 0x3f; + rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, \ + 0x7ff80000, (crystal_cap | (crystal_cap << 6))); + } + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): crystal_cap = 0x%x\n", \ + rtldm->crystal_cap)); + }else{ + /*1. Calculate CFO for path-A & path-B*/ + cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280; + cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280; + packet_count = rtldm->packet_count; + + /*2.No new packet*/ + if (packet_count == rtldm->packet_count_pre) { + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): packet counter doesn't change\n")); + return; + } + + rtldm->packet_count_pre = packet_count; + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): packet counter = %d\n", \ + rtldm->packet_count)); + + /*3.Average CFO*/ + if (rtlpriv->phy.rf_type == RF_1T1R) + cfo_ave = cfo_khz_a; + else + cfo_ave = (cfo_khz_a + cfo_khz_b) >> 1; + + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch():" + "cfo_khz_a = %dkHz, cfo_khz_b = %dkHz, cfo_ave = %dkHz\n", + cfo_khz_a, cfo_khz_b, cfo_ave)); + + /*4.Avoid abnormal large CFO*/ + cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave)? + (rtldm->cfo_ave_pre - cfo_ave): + (cfo_ave - rtldm->cfo_ave_pre); + + if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0){ + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): first large CFO hit\n")); + rtldm->large_cfo_hit = 1; + return; + } + else + rtldm->large_cfo_hit = 0; + + rtldm->cfo_ave_pre = cfo_ave; + + /*CFO tracking by adjusting Xtal cap.*/ + + /*1.Dynamic Xtal threshold*/ + if (cfo_ave >= -rtldm->cfo_threshold && + cfo_ave <= rtldm->cfo_threshold && + rtldm->is_freeze == 0){ + if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL){ + rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10; + rtldm->is_freeze = 1; + } + else + rtldm->cfo_threshold = CFO_THRESHOLD_XTAL; + } + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): Dynamic threshold = %d\n", \ + rtldm->cfo_threshold)); + + /* 2.Calculate Xtal offset*/ + if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f) + adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 2) + 1; + else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) && rtlpriv->dm.crystal_cap > 0) + adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 2) - 1; + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): " + "Crystal cap = 0x%x, Crystal cap offset = %d\n", + rtldm->crystal_cap, adjust_xtal)); + + /*3.Adjudt Crystal Cap.*/ + if (adjust_xtal != 0){ + rtldm->is_freeze = 0; + rtldm->crystal_cap += adjust_xtal; + + if (rtldm->crystal_cap > 0x3f) + rtldm->crystal_cap = 0x3f; + else if (rtldm->crystal_cap < 0) + rtldm->crystal_cap = 0; + + crystal_cap = rtldm->crystal_cap & 0x3f; + crystal_cap = crystal_cap & 0x3f; + rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, \ + 0x7ff80000, (crystal_cap | (crystal_cap << 6))); + RT_TRACE(COMP_DIG, DBG_LOUD, \ + ("rtl8821ae_dm_dynamic_atc_switch(): New crystal cap = 0x%x \n", \ + rtldm->crystal_cap)); + } + } + +} + +void rtl8821ae_dm_watchdog(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool b_fw_current_inpsmode = false; + bool b_fw_ps_awake = true; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&b_fw_current_inpsmode)); + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, + (u8 *) (&b_fw_ps_awake)); + + if(ppsc->p2p_ps_info.p2p_ps_mode) + b_fw_ps_awake = false; + + if((ppsc->rfpwr_state == ERFON) && + ((!b_fw_current_inpsmode) && b_fw_ps_awake) && + (!ppsc->rfchange_inprogress)) { + rtl8821ae_dm_common_info_self_update(hw); + rtl8821ae_dm_false_alarm_counter_statistics(hw); + rtl8821ae_dm_check_rssi_monitor(hw); + rtl8821ae_dm_dig(hw); + rtl8821ae_dm_dynamic_edcca(hw); + rtl8821ae_dm_cck_packet_detection_thresh(hw); + rtl8821ae_dm_refresh_rate_adaptive_mask(hw); + rtl8821ae_dm_check_edca_turbo(hw); + rtl8821ae_dm_dynamic_atc_switch(hw); + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_dm_check_txpower_tracking_thermalmeter(hw); + else + rtl8821ae_dm_check_txpower_tracking_thermalmeter(hw); + rtl8821ae_dm_iq_calibrate(hw); + if (rtlpriv->cfg->ops->get_btc_status()){ + rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); + } + } + + rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0; +} + +void rtl8821ae_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw, + u8 *pdesc, u32 mac_id) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + struct fast_ant_trainning *pfat_table= &(rtldm->fat_table); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8812AE) + return; + + if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) || + (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)){ + SET_TX_DESC_TX_ANT(pdesc, pfat_table->antsel_a[mac_id]); + } +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/sw.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/sw.c @@ -0,0 +1,499 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include +#include + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "hw.h" +#include "sw.h" +#include "trx.h" +#include "led.h" +#include "table.h" +#include "hal_btc.h" +#include "../btcoexist/rtl_btc.h" + +void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + * */ + rtlpci->const_pci_aspm = 3; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 0; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 1; +} + +/*InitializeVariables8812E*/ +int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) +{ + int err = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const struct firmware *firmware; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + char *fw_name = NULL; + + rtl8821ae_bt_reg_init(hw); + rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); + + rtlpriv->dm.b_dm_initialgain_enable = 1; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.b_disable_framebursting = 0;; + rtlpriv->dm.thermalvalue = 0; + rtlpci->transmit_config = CFENDFORM | BIT(15) | BIT(24) | BIT(25); + + mac->ht_enable = true; + + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + /*following 2 is for register 5G band, refer to _rtl_init_mac80211()*/ + rtlpriv->rtlhal.bandset = BAND_ON_BOTH; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->receive_config = (RCR_APPFCS | + RCR_APP_MIC | + RCR_APP_ICV | + RCR_APP_PHYST_RXFF | + RCR_NONQOS_VHT | + RCR_HTC_LOC_CTRL | + RCR_AMF | + RCR_ACF | + RCR_ADF | /*This bit controls the PS-Poll packet filter.*/ + RCR_AICV | + RCR_ACRC32 | + RCR_AB | + RCR_AM | + RCR_APM | + 0); + + + rtlpci->irq_mask[0] = + (u32) (IMR_PSTIMEOUT | + IMR_GTINT3 | + /*IMR_TBDER | + IMR_TBDOK | + IMR_BCNDMAINT0 |*/ + IMR_HSISR_IND_ON_INT | + IMR_C2HCMD | + IMR_HIGHDOK | + IMR_MGNTDOK | + IMR_BKDOK | + IMR_BEDOK | + IMR_VIDOK | + IMR_VODOK | + IMR_RDU | + IMR_ROK | + 0); + + rtlpci->irq_mask[1] = + (u32)( IMR_RXFOVW | + IMR_TXFOVW | + 0); + + /* for LPS & IPS */ + rtlpriv->psc.b_inactiveps = rtlpriv->cfg->mod_params->b_inactiveps; + rtlpriv->psc.b_swctrl_lps = rtlpriv->cfg->mod_params->b_swctrl_lps; + rtlpriv->psc.b_fwctrl_lps = rtlpriv->cfg->mod_params->b_fwctrl_lps; + rtlpriv->psc.b_reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl8821ae_init_aspm_vars(hw); + + if (rtlpriv->psc.b_reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.b_reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.b_reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x8000); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Can't alloc buffer for fw.\n")); + return 1; + } + + fw_name = "rtlwifi/rtl8821aefw.bin"; + err = request_firmware(&firmware, fw_name, rtlpriv->io.dev); + if (err) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + + if (firmware->size > 0x8000) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + + if (rtlpriv->cfg->ops->get_btc_status()){ + rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); + rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv); + } + + RT_TRACE(COMP_INIT, DBG_LOUD, (" FirmwareDownload OK\n")); + return err; +} + +void rtl8821ae_deinit_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + //printk("=========>rtl8821ae_deinit_sw_vars().\n"); + if (rtlpriv->cfg->ops->get_btc_status()){ + //printk("=========>rtl8821ae_deinit_sw_vars().get_btc_status\n"); + rtlpriv->btcoexist.btc_ops->btc_halt_notify(); + } + if (rtlpriv->rtlhal.pfirmware) { + //printk("=========>rtl8821ae_deinit_sw_vars().rtlpriv->rtlhal.pfirmware\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } + //printk("<=========rtl8821ae_deinit_sw_vars().\n"); +} + +u32 rtl8812ae_rx_command_packet_handler( + struct ieee80211_hw *hw, + struct rtl_stats status, + struct sk_buff *skb + ) +{ + u32 result = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (status.packet_report_type) { + case NORMAL_RX: + result = 0; + break; + case C2H_PACKET: + rtl8812ae_c2h_packet_handler(hw, skb->data, (u8) skb->len); + result = 1; + RT_TRACE(COMP_RECV, DBG_LOUD, + ("===>rtl8821ae_rx_command_packet_handler(): (u8) skb->len=%d\n\n", skb->len)); + break; + default: + RT_TRACE(COMP_RECV, DBG_LOUD, + ("===>rtl8821ae_rx_command_packet_handler(): No this packet type!!\n")); + break; + } + + return result; +} + + +/* get bt coexist status */ +bool rtl8821ae_get_btc_status(void) +{ + return true; +} + +struct rtl_hal_ops rtl8821ae_hal_ops = { + .init_sw_vars = rtl8821ae_init_sw_vars, + .deinit_sw_vars = rtl8821ae_deinit_sw_vars, + .read_eeprom_info = rtl8821ae_read_eeprom_info, + .interrupt_recognized = rtl8821ae_interrupt_recognized, + .hw_init = rtl8821ae_hw_init, + .hw_disable = rtl8821ae_card_disable, + .hw_suspend = rtl8821ae_suspend, + .hw_resume = rtl8821ae_resume, + .enable_interrupt = rtl8821ae_enable_interrupt, + .disable_interrupt = rtl8821ae_disable_interrupt, + .set_network_type = rtl8821ae_set_network_type, + .set_chk_bssid = rtl8821ae_set_check_bssid, + .set_qos = rtl8821ae_set_qos, + .set_bcn_reg = rtl8821ae_set_beacon_related_registers, + .set_bcn_intv = rtl8821ae_set_beacon_interval, + .update_interrupt_mask = rtl8821ae_update_interrupt_mask, + .get_hw_reg = rtl8821ae_get_hw_reg, + .set_hw_reg = rtl8821ae_set_hw_reg, + .update_rate_tbl = rtl8821ae_update_hal_rate_tbl, + .fill_tx_desc = rtl8821ae_tx_fill_desc, + .fill_tx_cmddesc = rtl8821ae_tx_fill_cmddesc, + .query_rx_desc = rtl8821ae_rx_query_desc, + .set_channel_access = rtl8821ae_update_channel_access_setting, + .radio_onoff_checking = rtl8821ae_gpio_radio_on_off_checking, + .set_bw_mode = rtl8821ae_phy_set_bw_mode, + .switch_channel = rtl8821ae_phy_sw_chnl, + .dm_watchdog = rtl8821ae_dm_watchdog, + .scan_operation_backup = rtl8821ae_phy_scan_operation_backup, + .set_rf_power_state = rtl8821ae_phy_set_rf_power_state, + .led_control = rtl8821ae_led_control, + .set_desc = rtl8821ae_set_desc, + .get_desc = rtl8821ae_get_desc, + .is_tx_desc_closed = rtl8821ae_is_tx_desc_closed, + .tx_polling = rtl8821ae_tx_polling, + .enable_hw_sec = rtl8821ae_enable_hw_security_config, + .set_key = rtl8821ae_set_key, + .init_sw_leds = rtl8821ae_init_sw_leds, + .allow_all_destaddr = rtl8821ae_allow_all_destaddr, + .get_bbreg = rtl8821ae_phy_query_bb_reg, + .set_bbreg = rtl8821ae_phy_set_bb_reg, + .get_rfreg = rtl8821ae_phy_query_rf_reg, + .set_rfreg = rtl8821ae_phy_set_rf_reg, + .c2h_command_handle = rtl_8821ae_c2h_command_handle, + .bt_wifi_media_status_notify = rtl_8821ae_bt_wifi_media_status_notify, + .bt_turn_off_bt_coexist_before_enter_lps = rtl8821ae_dm_bt_turn_off_bt_coexist_before_enter_lps, + .fill_h2c_cmd = rtl8821ae_fill_h2c_cmd, + .get_btc_status = rtl8821ae_get_btc_status, + .rx_command_packet_handler = rtl8812ae_rx_command_packet_handler, +}; + +struct rtl_mod_params rtl8821ae_mod_params = { + .sw_crypto = false, + .b_inactiveps = false,//true, + .b_swctrl_lps = false, + .b_fwctrl_lps = false, //true, +}; + +struct rtl_hal_cfg rtl8821ae_hal_cfg = { + .bar_id = 2, + .write_readback = true, + .name = "rtl8821ae_pci", + .fw_name = "rtlwifi/rtl8821aefw.bin", + .ops = &rtl8821ae_hal_ops, + .mod_params = &rtl8821ae_mod_params, + .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, + .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, + .maps[SYS_CLK] = REG_SYS_CLKR, + .maps[MAC_RCR_AM] = AM, + .maps[MAC_RCR_AB] = AB, + .maps[MAC_RCR_ACRC32] = ACRC32, + .maps[MAC_RCR_ACF] = ACF, + .maps[MAC_RCR_AAP] = AAP, + .maps[MAC_HIMR] = REG_HIMR, + .maps[MAC_HIMRE] = REG_HIMRE, + + + .maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS, + + .maps[EFUSE_TEST] = REG_EFUSE_TEST, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_CLK] = 0, + .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_PWC_EV12V] = PWC_EV12V, + .maps[EFUSE_FEN_ELDR] = FEN_ELDR, + .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, + .maps[EFUSE_ANA8M] = ANA8M, + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES, + + .maps[RWCAM] = REG_CAMCMD, + .maps[WCAMI] = REG_CAMWRITE, + .maps[RCAMO] = REG_CAMREAD, + .maps[CAMDBG] = REG_CAMDBG, + .maps[SECR] = REG_SECCFG, + .maps[SEC_CAM_NONE] = CAM_NONE, + .maps[SEC_CAM_WEP40] = CAM_WEP40, + .maps[SEC_CAM_TKIP] = CAM_TKIP, + .maps[SEC_CAM_AES] = CAM_AES, + .maps[SEC_CAM_WEP104] = CAM_WEP104, + + .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, + .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, + .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, + .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, + .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, + .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, +/* .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, */ /*need check*/ + .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, + .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, + .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, + .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, + .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, + .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, + .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, +/* .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,*/ +/* .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,*/ + + .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, + .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, + .maps[RTL_IMR_BcnInt] = IMR_BCNDMAINT0, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BCNDOK0, + .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, + .maps[RTL_IMR_TBDER] = IMR_TBDER, + .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, + .maps[RTL_IMR_TBDOK] = IMR_TBDOK, + .maps[RTL_IMR_BKDOK] = IMR_BKDOK, + .maps[RTL_IMR_BEDOK] = IMR_BEDOK, + .maps[RTL_IMR_VIDOK] = IMR_VIDOK, + .maps[RTL_IMR_VODOK] = IMR_VODOK, + .maps[RTL_IMR_ROK] = IMR_ROK, + .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) +static struct pci_device_id rtl8821ae_pci_ids[] = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8812, rtl8821ae_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8821, rtl8821ae_hal_cfg)}, + {}, +}; +#else +static struct pci_device_id rtl8821ae_pci_ids[] __devinitdata = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8812, rtl8821ae_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8821, rtl8821ae_hal_cfg)}, + {}, +}; +#endif + +MODULE_DEVICE_TABLE(pci, rtl8821ae_pci_ids); + +MODULE_AUTHOR("Ping Yan"); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8821ae 802.11ac PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin"); + +module_param_named(swenc, rtl8821ae_mod_params.sw_crypto, bool, 0444); +module_param_named(ips, rtl8821ae_mod_params.b_inactiveps, bool, 0444); +module_param_named(swlps, rtl8821ae_mod_params.b_swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl8821ae_mod_params.b_fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n"); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static const SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) +compat_pci_suspend(rtl_pci_suspend) +compat_pci_resume(rtl_pci_resume) +#endif + +static struct pci_driver rtl8821ae_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8821ae_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) + .driver.pm = &rtlwifi_pm_ops, +#elif defined(CONFIG_PM) + .suspend = rtl_pci_suspend_compat, + .resume = rtl_pci_resume_compat, +#endif + +}; + + +extern int rtl_core_module_init(void); +extern void rtl_core_module_exit(void); + +static int __init rtl8821ae_module_init(void) +{ + int ret; + + ret = rtl_core_module_init(); + if (ret) + return ret; + + //printk("==========>rtl8821ae_module_init().\n"); + ret = pci_register_driver(&rtl8821ae_driver); + if (ret) + RT_ASSERT(false, (": No device found\n")); + + return ret; +} + +static void __exit rtl8821ae_module_exit(void) +{ + pci_unregister_driver(&rtl8821ae_driver); + rtl_core_module_exit(); +} + +module_init(rtl8821ae_module_init); +module_exit(rtl8821ae_module_exit); --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/hw.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/hw.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_HW_H__ +#define __RTL8821AE_HW_H__ + +void rtl8821ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8821ae_read_eeprom_info(struct ieee80211_hw *hw); + +void rtl8821ae_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb); +int rtl8821ae_hw_init(struct ieee80211_hw *hw); +void rtl8821ae_card_disable(struct ieee80211_hw *hw); +void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw); +void rtl8821ae_disable_interrupt(struct ieee80211_hw *hw); +int rtl8821ae_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl8821ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl8821ae_set_qos(struct ieee80211_hw *hw, int aci); +void rtl8821ae_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl8821ae_set_beacon_interval(struct ieee80211_hw *hw); +void rtl8821ae_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl8821ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8821ae_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); +void rtl8821ae_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl8821ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl8821ae_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl8821ae_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); + +void rtl8821ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8* hwinfo); +void rtl8812ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8* hwinfo); +void rtl8821ae_bt_reg_init(struct ieee80211_hw* hw); +void rtl8821ae_bt_hw_init(struct ieee80211_hw* hw); +void rtl8821ae_suspend(struct ieee80211_hw *hw); +void rtl8821ae_resume(struct ieee80211_hw *hw); +void rtl8821ae_allow_all_destaddr(struct ieee80211_hw *hw, + bool allow_all_da, + bool write_into_reg); +void _rtl8821ae_stop_tx_beacon(struct ieee80211_hw *hw); +void _rtl8821ae_resume_tx_beacon(struct ieee80211_hw *hw); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/btc.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/btc.h @@ -0,0 +1,87 @@ + +/****************************************************************************** + ** + ** Copyright(c) 2009-2010 Realtek Corporation. + ** + ** This program is free software; you can redistribute it and/or modify it + ** under the terms of version 2 of the GNU General Public License as + ** published by the Free Software Foundation. + ** + ** This program is distributed in the hope that it will be useful, but WITHOUT + ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + ** more details. + ** + ** You should have received a copy of the GNU General Public License along with + ** this program; if not, write to the Free Software Foundation, Inc., + ** 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + ** + ** The full GNU General Public License is included in this distribution in the + ** file called LICENSE. + ** + ** Contact Information: + ** wlanfae + ** Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + ** Hsinchu 300, Taiwan. + ** Larry Finger + ** + ******************************************************************************/ + +#ifndef __RTL8821AE_BTC_H__ +#define __RTL8821AE_BTC_H__ + +#include "../wifi.h" +#include "hal_bt_coexist.h" + +struct bt_coexist_c2h_info { + u8 no_parse_c2h; + u8 has_c2h; +}; + +struct btdm_8821ae { + bool b_all_off; + bool b_agc_table_en; + bool b_adc_back_off_on; + bool b2_ant_hid_en; + bool b_low_penalty_rate_adaptive; + bool b_rf_rx_lpf_shrink; + bool b_reject_aggre_pkt; + bool b_tra_tdma_on; + u8 tra_tdma_nav; + u8 tra_tdma_ant; + bool b_tdma_on; + u8 tdma_ant; + u8 tdma_nav; + u8 tdma_dac_swing; + u8 fw_dac_swing_lvl; + bool b_ps_tdma_on; + u8 ps_tdma_byte[5]; + bool b_pta_on; + u32 val_0x6c0; + u32 val_0x6c8; + u32 val_0x6cc; + bool b_sw_dac_swing_on; + u32 sw_dac_swing_lvl; + u32 wlan_act_hi; + u32 wlan_act_lo; + u32 bt_retry_index; + bool b_dec_bt_pwr; + bool b_ignore_wlan_act; +}; + +struct bt_coexist_8821ae { + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 c2h_bt_info; + bool b_c2h_bt_info_req_sent; + bool b_c2h_bt_inquiry_page; + u32 bt_inq_page_start_time; + u8 bt_retry_cnt; + u8 c2h_bt_info_original; + u8 bt_inquiry_page_cnt; + struct btdm_8821ae btdm; +}; + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/table.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/table.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on 2010/ 5/18, 1:41 + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_TABLE__H_ +#define __RTL8821AE_TABLE__H_ + +#include +#define RTL8821AEPHY_REG_1TARRAYLEN 344 +extern u32 RTL8821AE_PHY_REG_ARRAY[]; +#define RTL8812AEPHY_REG_1TARRAYLEN 490 +extern u32 RTL8812AE_PHY_REG_ARRAY[]; +#define RTL8821AEPHY_REG_ARRAY_PGLEN 90 +extern u32 RTL8821AE_PHY_REG_ARRAY_PG[]; +#define RTL8812AEPHY_REG_ARRAY_PGLEN 276 +extern u32 RTL8812AE_PHY_REG_ARRAY_PG[]; +//#define RTL8723BE_RADIOA_1TARRAYLEN 206 +//extern u8 *RTL8821AE_TXPWR_LMT_ARRAY[]; +#define RTL8812AE_RADIOA_1TARRAYLEN 1264 +extern u32 RTL8812AE_RADIOA_ARRAY[]; +#define RTL8812AE_RADIOB_1TARRAYLEN 1240 +extern u32 RTL8812AE_RADIOB_ARRAY[]; +#define RTL8821AE_RADIOA_1TARRAYLEN 1176 +extern u32 RTL8821AE_RADIOA_ARRAY[]; +#define RTL8821AEMAC_1T_ARRAYLEN 194 +extern u32 RTL8821AE_MAC_REG_ARRAY[]; +#define RTL8812AEMAC_1T_ARRAYLEN 214 +extern u32 RTL8812AE_MAC_REG_ARRAY[]; +#define RTL8821AEAGCTAB_1TARRAYLEN 382 +extern u32 RTL8821AE_AGC_TAB_ARRAY[]; +#define RTL8812AEAGCTAB_1TARRAYLEN 1312 +extern u32 RTL8812AE_AGC_TAB_ARRAY[]; + + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.c @@ -0,0 +1,199 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "pwrseqcmd.h" +#include "pwrseq.h" + +/* + drivers should parse below arrays and do the corresponding actions +*/ +//3 Power on Array +struct wlan_pwr_cfg rtl8812_power_on_flow[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS+RTL8812_TRANS_END_STEPS]= +{ + RTL8812_TRANS_CARDEMU_TO_ACT + RTL8812_TRANS_END +}; + +//3Radio off GPIO Array +struct wlan_pwr_cfg rtl8812_radio_off_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_END_STEPS]= +{ + RTL8812_TRANS_ACT_TO_CARDEMU + RTL8812_TRANS_END +}; + +//3Card Disable Array +struct wlan_pwr_cfg rtl8812_card_disable_flow[ RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8812_TRANS_END_STEPS ] = +{ + RTL8812_TRANS_ACT_TO_CARDEMU + RTL8812_TRANS_CARDEMU_TO_CARDDIS + RTL8812_TRANS_END +}; + +//3 Card Enable Array +struct wlan_pwr_cfg rtl8812_card_enable_flow[ RTL8812_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8812_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8812_TRANS_END_STEPS ] = +{ + RTL8812_TRANS_CARDDIS_TO_CARDEMU + RTL8812_TRANS_CARDEMU_TO_ACT + RTL8812_TRANS_END +}; + +//3Suspend Array +struct wlan_pwr_cfg rtl8812_suspend_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_SUS_STEPS+RTL8812_TRANS_END_STEPS]= +{ + RTL8812_TRANS_ACT_TO_CARDEMU + RTL8812_TRANS_CARDEMU_TO_SUS + RTL8812_TRANS_END +}; + +//3 Resume Array +struct wlan_pwr_cfg rtl8812_resume_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_SUS_STEPS+RTL8812_TRANS_END_STEPS]= +{ + RTL8812_TRANS_SUS_TO_CARDEMU + RTL8812_TRANS_CARDEMU_TO_ACT + RTL8812_TRANS_END +}; + + + +//3HWPDN Array +struct wlan_pwr_cfg rtl8812_hwpdn_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_PDN_STEPS+RTL8812_TRANS_END_STEPS]= +{ + RTL8812_TRANS_ACT_TO_CARDEMU + RTL8812_TRANS_CARDEMU_TO_PDN + RTL8812_TRANS_END +}; + +//3 Enter LPS +struct wlan_pwr_cfg rtl8812_enter_lps_flow[RTL8812_TRANS_ACT_TO_LPS_STEPS+RTL8812_TRANS_END_STEPS]= +{ + //FW behavior + RTL8812_TRANS_ACT_TO_LPS + RTL8812_TRANS_END +}; + +//3 Leave LPS +struct wlan_pwr_cfg rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEPS+RTL8812_TRANS_END_STEPS]= +{ + //FW behavior + RTL8812_TRANS_LPS_TO_ACT + RTL8812_TRANS_END +}; + + +/* + drivers should parse below arrays and do the corresponding actions +*/ +/*3 Power on Array*/ +struct wlan_pwr_cfg rtl8821A_power_on_flow[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + RTL8821A_TRANS_CARDEMU_TO_ACT + RTL8821A_TRANS_END +}; + +/*3Radio off GPIO Array */ +struct wlan_pwr_cfg rtl8821A_radio_off_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + RTL8821A_TRANS_ACT_TO_CARDEMU + RTL8821A_TRANS_END +}; + +/*3Card Disable Array*/ +struct wlan_pwr_cfg rtl8821A_card_disable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + RTL8821A_TRANS_ACT_TO_CARDEMU + RTL8821A_TRANS_CARDEMU_TO_CARDDIS + RTL8821A_TRANS_END +}; + +/*3 Card Enable Array*/ +struct wlan_pwr_cfg rtl8821A_card_enable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS /*RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS*/ + + RTL8821A_TRANS_END_STEPS] = +{ + RTL8821A_TRANS_CARDDIS_TO_CARDEMU + RTL8821A_TRANS_CARDEMU_TO_ACT + RTL8821A_TRANS_END +}; + +/*3Suspend Array*/ +struct wlan_pwr_cfg rtl8821A_suspend_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + RTL8821A_TRANS_ACT_TO_CARDEMU + RTL8821A_TRANS_CARDEMU_TO_SUS + RTL8821A_TRANS_END +}; + +/*3 Resume Array*/ +struct wlan_pwr_cfg rtl8821A_resume_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + RTL8821A_TRANS_SUS_TO_CARDEMU + RTL8821A_TRANS_CARDEMU_TO_ACT + RTL8821A_TRANS_END +}; + +/*3HWPDN Array*/ +struct wlan_pwr_cfg rtl8821A_hwpdn_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + RTL8821A_TRANS_ACT_TO_CARDEMU + RTL8821A_TRANS_CARDEMU_TO_PDN + RTL8821A_TRANS_END +}; + +/*3 Enter LPS */ +struct wlan_pwr_cfg rtl8821A_enter_lps_flow[RTL8821A_TRANS_ACT_TO_LPS_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + /*FW behavior*/ + RTL8821A_TRANS_ACT_TO_LPS + RTL8821A_TRANS_END +}; + +/*3 Leave LPS */ +struct wlan_pwr_cfg rtl8821A_leave_lps_flow[RTL8821A_TRANS_LPS_TO_ACT_STEPS + + RTL8821A_TRANS_END_STEPS] = +{ + /*FW behavior*/ + RTL8821A_TRANS_LPS_TO_ACT + RTL8821A_TRANS_END +}; + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/trx.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/trx.c @@ -0,0 +1,1050 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "../stats.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" +#include "dm.h" +#include "phy.h" +u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) +{ + u16 fc = rtl_get_fc(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) + return QSLT_MGNT; + + return skb->priority; +} + +/* mac80211's rate_idx is like this: + * + * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ + * + * B/G rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 + * + * 5G band:rx_status->band == IEEE80211_BAND_5GHZ + * A rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 + */ +static int _rtl8821ae_rate_mapping(struct ieee80211_hw *hw, + bool isht, u8 desc_rate) +{ + int rate_idx; + + if (false == isht) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { +#else + if (IEEE80211_BAND_2GHZ == hw->conf.channel->band) { +#endif + switch (desc_rate) { + case DESC_RATE1M: + rate_idx = 0; + break; + case DESC_RATE2M: + rate_idx = 1; + break; + case DESC_RATE5_5M: + rate_idx = 2; + break; + case DESC_RATE11M: + rate_idx = 3; + break; + case DESC_RATE6M: + rate_idx = 4; + break; + case DESC_RATE9M: + rate_idx = 5; + break; + case DESC_RATE12M: + rate_idx = 6; + break; + case DESC_RATE18M: + rate_idx = 7; + break; + case DESC_RATE24M: + rate_idx = 8; + break; + case DESC_RATE36M: + rate_idx = 9; + break; + case DESC_RATE48M: + rate_idx = 10; + break; + case DESC_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + } else { + switch (desc_rate) { + case DESC_RATE6M: + rate_idx = 0; + break; + case DESC_RATE9M: + rate_idx = 1; + break; + case DESC_RATE12M: + rate_idx = 2; + break; + case DESC_RATE18M: + rate_idx = 3; + break; + case DESC_RATE24M: + rate_idx = 4; + break; + case DESC_RATE36M: + rate_idx = 5; + break; + case DESC_RATE48M: + rate_idx = 6; + break; + case DESC_RATE54M: + rate_idx = 7; + break; + default: + rate_idx = 0; + break; + } + } + } else { + switch(desc_rate) { + case DESC_RATEMCS0: + rate_idx = 0; + break; + case DESC_RATEMCS1: + rate_idx = 1; + break; + case DESC_RATEMCS2: + rate_idx = 2; + break; + case DESC_RATEMCS3: + rate_idx = 3; + break; + case DESC_RATEMCS4: + rate_idx = 4; + break; + case DESC_RATEMCS5: + rate_idx = 5; + break; + case DESC_RATEMCS6: + rate_idx = 6; + break; + case DESC_RATEMCS7: + rate_idx = 7; + break; + case DESC_RATEMCS8: + rate_idx = 8; + break; + case DESC_RATEMCS9: + rate_idx = 9; + break; + case DESC_RATEMCS10: + rate_idx = 10; + break; + case DESC_RATEMCS11: + rate_idx = 11; + break; + case DESC_RATEMCS12: + rate_idx = 12; + break; + case DESC_RATEMCS13: + rate_idx = 13; + break; + case DESC_RATEMCS14: + rate_idx = 14; + break; + case DESC_RATEMCS15: + rate_idx = 15; + break; + default: + rate_idx = 0; + break; + } + } + return rate_idx; +} + +static void _rtl8821ae_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstatus, u8 *pdesc, + struct rx_fwinfo_8821ae *p_drvinfo, bool bpacket_match_bssid, + bool bpacket_toself, bool b_packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + struct phy_sts_cck_8821ae_t *cck_buf; + struct phy_status_rpt *p_phystRpt = (struct phy_status_rpt *)p_drvinfo; + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + char rx_pwr_all = 0, rx_pwr[4]; + u8 rf_rx_num = 0, evm, pwdb_all; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool b_is_cck = pstatus->b_is_cck; + u8 lan_idx,vga_idx; + + /* Record it for next packet processing */ + pstatus->b_packet_matchbssid = bpacket_match_bssid; + pstatus->b_packet_toself = bpacket_toself; + pstatus->b_packet_beacon = b_packet_beacon; + pstatus->rx_mimo_signalquality[0] = -1; + pstatus->rx_mimo_signalquality[1] = -1; + + if (b_is_cck) { + u8 cck_highpwr; + u8 cck_agc_rpt; + /* CCK Driver info Structure is not the same as OFDM packet. */ + cck_buf = (struct phy_sts_cck_8821ae_t *)p_drvinfo; + cck_agc_rpt = cck_buf->cck_agc_rpt; + + /* (1)Hardware does not provide RSSI for CCK */ + /* (2)PWDB, Average PWDB cacluated by + * hardware (for rate adaptive) */ + if (ppsc->rfpwr_state == ERFON) + cck_highpwr = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + + lan_idx = ((cck_agc_rpt & 0xE0) >> 5); + vga_idx = (cck_agc_rpt & 0x1f); + switch (lan_idx) { + case 7: + if(vga_idx <= 27) + rx_pwr_all = -100 + 2*(27-vga_idx); /*VGA_idx = 27~2*/ + else + rx_pwr_all = -100; + break; + case 6: + rx_pwr_all = -48 + 2*(2-vga_idx); /*VGA_idx = 2~0*/ + break; + case 5: + rx_pwr_all = -42 + 2*(7-vga_idx); /*VGA_idx = 7~5*/ + break; + case 4: + rx_pwr_all = -36 + 2*(7-vga_idx); /*VGA_idx = 7~4*/ + break; + case 3: + rx_pwr_all = -24 + 2*(7-vga_idx); /*VGA_idx = 7~0*/ + break; + case 2: + if(cck_highpwr) + rx_pwr_all = -12 + 2*(5-vga_idx); /*VGA_idx = 5~0*/ + else + rx_pwr_all = -6+ 2*(5-vga_idx); + break; + case 1: + rx_pwr_all = 8-2*vga_idx; + break; + case 0: + rx_pwr_all = 14-2*vga_idx; + break; + default: + break; + } + rx_pwr_all += 6; + pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); + /* CCK gain is smaller than OFDM/MCS gain, */ + /* so we add gain diff by experiences, + * the val is 6 */ + pwdb_all += 6; + if(pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same + * gain index with OFDM. */ + if(pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if(pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if(pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if(pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + if (cck_highpwr == false){ + if (pwdb_all >= 80) + pwdb_all =((pwdb_all-80)<<1)+((pwdb_all-80)>>1)+80; + else if((pwdb_all <= 78) && (pwdb_all >= 20)) + pwdb_all += 3; + if(pwdb_all>100) + pwdb_all = 100; + } + + pstatus->rx_pwdb_all = pwdb_all; + pstatus->recvsignalpower = rx_pwr_all; + + /* (3) Get Signal Quality (EVM) */ + if (bpacket_match_bssid) { + u8 sq; + + if (pstatus->rx_pwdb_all > 40) + sq = 100; + else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + + pstatus->signalquality = sq; + pstatus->rx_mimo_signalquality[0] = sq; + pstatus->rx_mimo_signalquality[1] = -1; + } + } else { + rtlpriv->dm.brfpath_rxenable[0] = + rtlpriv->dm.brfpath_rxenable[1] = true; + + /* (1)Get RSSI for HT rate */ + for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) { + + /* we will judge RF RX path now. */ + if (rtlpriv->dm.brfpath_rxenable[i]) + rf_rx_num++; + + rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110; + + /* Translate DBM to percentage. */ + rssi = rtl_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + + /* Get Rx snr value in DB */ + rtlpriv->stats.rx_snr_db[i] = (long)(p_drvinfo->rxsnr[i] / 2); + + /* Record Signal Strength for next packet */ + if (bpacket_match_bssid) + pstatus->rx_mimo_signalstrength[i] = (u8) rssi; + } + + /* (2)PWDB, Average PWDB cacluated by + * hardware (for rate adaptive) */ + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + + pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); + pstatus->rx_pwdb_all = pwdb_all; + pstatus->rxpower = rx_pwr_all; + pstatus->recvsignalpower = rx_pwr_all; + + /* (3)EVM of HT rate */ + if (pstatus->b_is_ht && pstatus->rate >= DESC_RATEMCS8 && + pstatus->rate <= DESC_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]); + + if (bpacket_match_bssid) { + /* Fill value in RFD, Get the first + * spatial stream only */ + if (i == 0) + pstatus->signalquality = (u8) (evm & 0xff); + pstatus->rx_mimo_signalquality[i] = (u8) (evm & 0xff); + } + } + } + + /* UI BSS List signal strength(in percentage), + * make it good looking, from 0~100. */ + if (b_is_cck) + pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw, + pwdb_all)); + else if (rf_rx_num != 0) + pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw, + total_rssi /= rf_rx_num)); + /*HW antenna diversity*/ + rtldm->fat_table.antsel_rx_keep_0 = p_phystRpt->ant_sel; + rtldm->fat_table.antsel_rx_keep_1 = p_phystRpt->ant_sel_b; + rtldm->fat_table.antsel_rx_keep_2 = p_phystRpt->antsel_rx_keep_2; + +} +#if 0 +static void _rtl8821ae_smart_antenna(struct ieee80211_hw *hw, + struct rtl_stats *pstatus) +{ + struct rtl_dm *rtldm= rtl_dm(rtl_priv(hw)); + struct rtl_efuse *rtlefuse =rtl_efuse(rtl_priv(hw)); + u8 antsel_tr_mux; + struct fast_ant_trainning *pfat_table = &(rtldm->fat_table); + + if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV) { + if (pfat_table->fat_state == FAT_TRAINING_STATE) { + if (pstatus->b_packet_toself) { + antsel_tr_mux = (pfat_table->antsel_rx_keep_2 << 2) | + (pfat_table->antsel_rx_keep_1 << 1) | pfat_table->antsel_rx_keep_0; + pfat_table->ant_sum_rssi[antsel_tr_mux] += pstatus->rx_pwdb_all; + pfat_table->ant_rssi_cnt[antsel_tr_mux]++; + } + } + } else if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) || + (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)) { + if (pstatus->b_packet_toself || pstatus->b_packet_matchbssid) { + antsel_tr_mux = (pfat_table->antsel_rx_keep_2 << 2) | + (pfat_table->antsel_rx_keep_1 << 1) | pfat_table->antsel_rx_keep_0; + rtl8821ae_dm_ant_sel_statistics(hw, antsel_tr_mux, 0, pstatus->rx_pwdb_all); + } + + } +} +#endif +static void _rtl8821ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, struct rtl_stats *pstatus, + u8 *pdesc, struct rx_fwinfo_8821ae *p_drvinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct ieee80211_hdr *hdr; + u8 *tmp_buf; + u8 *praddr; + u8 *psaddr; + u16 fc, type; + bool b_packet_matchbssid, b_packet_toself, b_packet_beacon; + + tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift; + + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = le16_to_cpu(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + psaddr = ieee80211_get_SA(hdr); + memcpy(pstatus->psaddr, psaddr, ETH_ALEN); + + b_packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && + (!ether_addr_equal(mac->bssid, (fc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && (!pstatus->b_hwerror) && + (!pstatus->b_crc) && (!pstatus->b_icv)); + + b_packet_toself = b_packet_matchbssid && + (!ether_addr_equal(praddr, rtlefuse->dev_addr)); + + if (ieee80211_is_beacon(fc)) + b_packet_beacon = true; + else + b_packet_beacon = false; + + if (b_packet_beacon && b_packet_matchbssid) + rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++; + + _rtl8821ae_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo, + b_packet_matchbssid, b_packet_toself, + b_packet_beacon); + /*_rtl8821ae_smart_antenna(hw, pstatus); */ + rtl_process_phyinfo(hw, tmp_buf, pstatus); +} + +static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, + u8 *virtualaddress) +{ + u32 dwtmp = 0; + memset(virtualaddress, 0, 8); + + SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num); + if (ptcb_desc->empkt_num == 1) + dwtmp = ptcb_desc->empkt_len[0]; + else { + dwtmp = ptcb_desc->empkt_len[0]; + dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; + dwtmp += ptcb_desc->empkt_len[1]; + } + SET_EARLYMODE_LEN0(virtualaddress, dwtmp); + + if (ptcb_desc->empkt_num <= 3) + dwtmp = ptcb_desc->empkt_len[2]; + else { + dwtmp = ptcb_desc->empkt_len[2]; + dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; + dwtmp += ptcb_desc->empkt_len[3]; + } + SET_EARLYMODE_LEN1(virtualaddress, dwtmp); + if (ptcb_desc->empkt_num <= 5) + dwtmp = ptcb_desc->empkt_len[4]; + else { + dwtmp = ptcb_desc->empkt_len[4]; + dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; + dwtmp += ptcb_desc->empkt_len[5]; + } + SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF); + SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4); + if (ptcb_desc->empkt_num <= 7) + dwtmp = ptcb_desc->empkt_len[6]; + else { + dwtmp = ptcb_desc->empkt_len[6]; + dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; + dwtmp += ptcb_desc->empkt_len[7]; + } + SET_EARLYMODE_LEN3(virtualaddress, dwtmp); + if (ptcb_desc->empkt_num <= 9) + dwtmp = ptcb_desc->empkt_len[8]; + else { + dwtmp = ptcb_desc->empkt_len[8]; + dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; + dwtmp += ptcb_desc->empkt_len[9]; + } + SET_EARLYMODE_LEN4(virtualaddress, dwtmp); +} + +bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *status, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rx_fwinfo_8821ae *p_drvinfo; + struct ieee80211_hdr *hdr; + + u32 phystatus = GET_RX_DESC_PHYST(pdesc); + + status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); + status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * + RX_DRV_INFO_SIZE_UNIT; + status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); + status->b_icv = (u16) GET_RX_DESC_ICV(pdesc); + status->b_crc = (u16) GET_RX_DESC_CRC32(pdesc); + status->b_hwerror = (status->b_crc | status->b_icv); + status->decrypted = !GET_RX_DESC_SWDEC(pdesc); + status->rate = (u8) GET_RX_DESC_RXMCS(pdesc); + status->b_shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); + status->b_isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + status->b_isfirst_ampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + status->timestamp_low = GET_RX_DESC_TSFL(pdesc); + status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + status->macid = GET_RX_DESC_MACID(pdesc); + status->b_is_ht = (bool)GET_RX_DESC_RXHT(pdesc); + + status->b_is_cck = RX_HAL_IS_CCK_RATE(status->rate); + + if (GET_RX_STATUS_DESC_RPT_SEL(pdesc)) + status->packet_report_type = C2H_PACKET; + else + status->packet_report_type = NORMAL_RX; + + if (GET_RX_STATUS_DESC_PATTERN_MATCH(pdesc)) + status->wake_match = BIT(2); + else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc)) + status->wake_match = BIT(1); + else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc)) + status->wake_match = BIT(0); + else + status->wake_match = 0; + + if (status->wake_match) + RT_TRACE(COMP_RXDESC,DBG_LOUD, + ("GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",status->wake_match )); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; +#else + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; +#endif + + hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size + + status->rx_bufshift); + + if (status->b_crc) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (status->rx_is40Mhzpacket) + rx_status->flag |= RX_FLAG_40MHZ; + + if (status->b_is_ht) + rx_status->flag |= RX_FLAG_HT; + + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + + /* hw will set status->decrypted true, if it finds the + * frame is open data frame or mgmt frame. */ + /* So hw will not decryption robust managment frame + * for IEEE80211w but still set status->decrypted + * true, so here we should set it back to undecrypted + * for IEEE80211w frame, and mac80211 sw will help + * to decrypt it */ + if (status->decrypted) { + if (!hdr) { + WARN_ON_ONCE(true); + pr_err("decrypted is true but hdr NULL, from skb %p\n", + rtl_get_hdr(skb)); + return false; + } + + if ((ieee80211_is_robust_mgmt_frame(hdr)) && + (ieee80211_has_protected(hdr->frame_control))) + rx_status->flag &= ~RX_FLAG_DECRYPTED; + else + rx_status->flag |= RX_FLAG_DECRYPTED; + } + + /* rate_idx: index of data rate into band's + * supported rates or MCS index if HT rates + * are use (RX_FLAG_HT)*/ + /* Notice: this is diff with windows define */ + rx_status->rate_idx = _rtl8821ae_rate_mapping(hw, + status->b_is_ht, status->rate); + + rx_status->mactime = status->timestamp_low; + if (phystatus == true) { + p_drvinfo = (struct rx_fwinfo_8821ae *)(skb->data + + status->rx_bufshift); + + _rtl8821ae_translate_rx_signal_stuff(hw, + skb, status, pdesc, + p_drvinfo); + } + + /*rx_status->qual = status->signal; */ + rx_status->signal = status->recvsignalpower + 10; + /*rx_status->noise = -status->noise; */ + if (status->packet_report_type == TX_REPORT2){ + status->macid_valid_entry[0] = GET_RX_RPT2_DESC_MACID_VALID_1(pdesc); + status->macid_valid_entry[1] = GET_RX_RPT2_DESC_MACID_VALID_2(pdesc); + } + return true; +} + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) +void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, u8 *txbd, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +#else +/**/ +void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, u8 *txbd, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, + struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +/**/ +#endif +/**/ +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + struct ieee80211_sta *sta = info->control.sta; +#endif +/**/ + u8 *pdesc = (u8 *) pdesc_tx; + u16 seq_number; + u16 fc = le16_to_cpu(hdr->frame_control); + unsigned int buf_len = 0; + unsigned int skb_len = skb->len; + u8 fw_qsel = _rtl8821ae_map_hwqueue_to_fwqueue(skb, hw_queue); + bool b_firstseg = ((hdr->seq_ctrl & + cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + bool b_lastseg = ((hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); + dma_addr_t mapping; + u8 bw_40 = 0; + u8 short_gi = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + /* reserve 8 byte for AMPDU early mode */ + if (rtlhal->b_earlymode_enable) { + skb_push(skb, EM_HDR_LEN); + memset(skb->data, 0, EM_HDR_LEN); + } + buf_len = skb->len; + mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { + RT_TRACE(COMP_SEND, DBG_TRACE, + ("DMA mapping error")); + return; + } + CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8821ae)); + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + b_firstseg = true; + b_lastseg = true; + } + if (b_firstseg) { + if (rtlhal->b_earlymode_enable) { + SET_TX_DESC_PKT_OFFSET(pdesc, 1); + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN + EM_HDR_LEN); + if (ptcb_desc->empkt_num) { + RT_TRACE(COMP_SEND, DBG_TRACE, + ("Insert 8 byte.pTcb->EMPktNum:%d\n", + ptcb_desc->empkt_num)); + _rtl8821ae_insert_emcontent(ptcb_desc, (u8 *)(skb->data)); + } + } else { + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + } + + /* ptcb_desc->use_driver_rate = true; */ + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + if (ptcb_desc->hw_rate > DESC_RATEMCS0) { + short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; + } else { + short_gi = (ptcb_desc->use_shortpreamble) ? 1 :0; + } + SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + SET_TX_DESC_AGG_ENABLE(pdesc, 1); + SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); + } + SET_TX_DESC_SEQ(pdesc, seq_number); + SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->b_rts_enable && + !ptcb_desc->b_cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(pdesc,0); + SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->b_cts_enable) ? 1 : 0)); + /* SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->b_rts_stbc) ? 1 : 0));*/ + + SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); + /* SET_TX_DESC_RTS_BW(pdesc, 0);*/ + SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= DESC_RATE54M) ? + (ptcb_desc->b_rts_use_shortpreamble ? 1 : 0) : + (ptcb_desc->b_rts_use_shortgi ? 1 : 0))); + + if(ptcb_desc->btx_enable_sw_calc_duration) + SET_TX_DESC_NAV_USE_HDR(pdesc, 1); + + if (bw_40) { + if (ptcb_desc->b_packet_bw) { + SET_TX_DESC_DATA_BW(pdesc, 1); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, mac->cur_40_prime_sc); + } + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } + + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len); + if (sta) { + u8 ampdu_density = sta->ht_cap.ampdu_density; + SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); + } + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf = info->control.hw_key; +/**/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) +/**/ + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + + } +/**/ +#else + switch (keyconf->alg) { + case ALG_WEP: + case ALG_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case ALG_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + + } +#endif +/**/ + } + + SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); + SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ? 1 : 0); + SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0); + +#if 0 + SET_TX_DESC_USE_RATE(pdesc, 1); + SET_TX_DESC_TX_RATE(pdesc, 0x04); + + SET_TX_DESC_RETRY_LIMIT_ENABLE(pdesc, 1); + SET_TX_DESC_DATA_RETRY_LIMIT(pdesc, 0x3f); +#endif + + /*SET_TX_DESC_PWR_STATUS(pdesc, pwr_status);*/ + /* Set TxRate and RTSRate in TxDesc */ + /* This prevent Tx initial rate of new-coming packets */ + /* from being overwritten by retried packet rate.*/ + if (!ptcb_desc->use_driver_rate) { + /*SET_TX_DESC_RTS_RATE(pdesc, 0x08); */ + /* SET_TX_DESC_TX_RATE(pdesc, 0x0b); */ + } + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { + RT_TRACE(COMP_SEND, DBG_TRACE, + ("Enable RDG function.\n")); + SET_TX_DESC_RDG_ENABLE(pdesc, 1); + SET_TX_DESC_HTC(pdesc, 1); + } + } + } + + SET_TX_DESC_FIRST_SEG(pdesc, (b_firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (b_lastseg ? 1 : 0)); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + //if (rtlpriv->dm.b_useramask) { + if(1){ + SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + } else { + SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + } +/* if (ieee80211_is_data_qos(fc)) + SET_TX_DESC_QOS(pdesc, 1); +*/ + if (!ieee80211_is_data_qos(fc)) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_HWSEQ_SEL(pdesc, 0); + } + SET_TX_DESC_MORE_FRAG(pdesc, (b_lastseg ? 0 : 1)); + if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) { + SET_TX_DESC_BMC(pdesc, 1); + } + + rtl8821ae_dm_set_tx_ant_by_tx_info(hw,pdesc,ptcb_desc->mac_id); + RT_TRACE(COMP_SEND, DBG_TRACE, ("\n")); +} + +void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw, + u8 *pdesc, bool b_firstseg, + bool b_lastseg, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 fw_queue = QSLT_BEACON; + + dma_addr_t mapping = pci_map_single(rtlpci->pdev, + skb->data, skb->len, + PCI_DMA_TODEVICE); + + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { + RT_TRACE(COMP_SEND, DBG_TRACE, + ("DMA mapping error")); + return; + } + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); + + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len)); + + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + + SET_TX_DESC_USE_RATE(pdesc, 1); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); + SET_TX_DESC_DISABLE_FB(pdesc, 1); + + SET_TX_DESC_DATA_BW(pdesc, 0); + + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + + SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); +/* + if(IsCtrlNDPA(VirtualAddress) || IsMgntNDPA(VirtualAddress)) + { + SET_TX_DESC_DATA_RETRY_LIMIT_8812(pDesc, 5); + SET_TX_DESC_RETRY_LIMIT_ENABLE_8812(pDesc, 1); + + if(IsMgntNDPA(VirtualAddress)) + { + SET_TX_DESC_NDPA_8812(pDesc, 1); + SET_TX_DESC_RTS_SC_8812(pDesc, SCMapping_8812(Adapter, pTcb)); + } + else + { + SET_TX_DESC_NDPA_8812(pDesc, 2); + SET_TX_DESC_RTS_SC_8812(pDesc, SCMapping_8812(Adapter, pTcb)); + } + }*/ + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); + + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + SET_TX_DESC_MACID(pdesc, 0); + + SET_TX_DESC_OWN(pdesc, 1); + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C Tx Cmd Content\n", + pdesc, TX_DESC_SIZE); +} + +void rtl8821ae_set_desc(struct ieee80211_hw * hw, u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx == true) { + switch (desc_name) { + case HW_DESC_OWN: + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d" + " not process\n", desc_name)); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + SET_RX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_DESC_PKT_LEN(pdesc, *(u32 *) val); + break; + case HW_DESC_RXERO: + SET_RX_DESC_EOR(pdesc, 1); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d " + "not process\n", desc_name)); + break; + } + } +} + +u32 rtl8821ae_get_desc(u8 *pdesc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx == true) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(pdesc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d " + "not process\n", desc_name)); + break; + } + } else { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_RX_DESC_OWN(pdesc); + break; + case HW_DESC_RXPKT_LEN: + ret = GET_RX_DESC_PKT_LEN(pdesc); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d " + "not process\n", desc_name)); + break; + } + } + return ret; +} + +bool rtl8821ae_is_tx_desc_closed(struct ieee80211_hw *hw, + u8 hw_queue, u16 index) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + u8 *entry = (u8 *)(&ring->desc[ring->idx]); + u8 own = (u8) rtl8821ae_get_desc(entry, true, HW_DESC_OWN); + + /* + *beacon packet will only use the first + *descriptor defautly,and the own may not + *be cleared by the hardware + */ + if (own) + return false; + else + return true; +} + + +void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (hw_queue == BEACON_QUEUE) { + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4)); + } else { + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, + BIT(0) << (hw_queue)); + } +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/rf.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/rf.c @@ -0,0 +1,464 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + +static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw); + +void rtl8821ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (bandwidth) { + case HT_CHANNEL_WIDTH_20: + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 3); + rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 3); + break; + case HT_CHANNEL_WIDTH_20_40: + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 1); + rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 1); + break; + case HT_CHANNEL_WIDTH_80: + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 0); + rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 0); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", bandwidth)); + break; + } +} + +void rtl8821ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 tx_agc[2] = {0, 0}, tmpval; + bool turbo_scanoff = false; + u8 idx1, idx2; + u8 *ptr; + u8 direction; + u32 pwrtrac_value; + + if (rtlefuse->eeprom_regulatory != 0) + turbo_scanoff = true; + + if (mac->act_scanning == true) { + tx_agc[RF90_PATH_A] = 0x3f3f3f3f; + tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + + if (turbo_scanoff) { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + } + } else { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + + if (rtlefuse->eeprom_regulatory == 0) { + tmpval = + (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][7] << + 8); + tx_agc[RF90_PATH_A] += tmpval; + + tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][15] << + 24); + tx_agc[RF90_PATH_B] += tmpval; + } + } + + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + ptr = (u8 *) (&(tx_agc[idx1])); + for (idx2 = 0; idx2 < 4; idx2++) { + if (*ptr > RF6052_MAX_TX_PWR) + *ptr = RF6052_MAX_TX_PWR; + ptr++; + } + } + rtl8821ae_dm_txpower_track_adjust(hw,1,&direction,&pwrtrac_value); + if (direction ==1){ + tx_agc[0] += pwrtrac_value; + tx_agc[1] += pwrtrac_value; + } else if (direction == 2){ + tx_agc[0] -= pwrtrac_value; + tx_agc[1] -= pwrtrac_value; + } + tmpval = tx_agc[RF90_PATH_A] ; + rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKDWORD, tmpval); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("CCK PWR 1~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_A_CCK11_CCK1)); + + tmpval = tx_agc[RF90_PATH_B] ; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKDWORD, tmpval); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_B_CCK11_CCK1)); +} + +static void rtl8821ae_phy_get_power_base(struct ieee80211_hw *hw, + u8 *ppowerlevel_ofdm, u8 *ppowerlevel_bw20, u8 *ppowerlevel_bw40, u8 channel, + u32 *ofdmbase, u32 *mcsbase) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 powerBase0, powerBase1; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerBase0 = ppowerlevel_ofdm[i]; + + powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | + (powerBase0 << 8) | powerBase0; + *(ofdmbase + i) = powerBase0; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + (" [OFDM power base index rf(%c) = 0x%x]\n", + ((i == 0) ? 'A' : 'B'), *(ofdmbase + i))); + } + + for (i = 0; i < 2; i++) { + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + powerlevel[i] = ppowerlevel_bw20[i]; + }else{ + powerlevel[i] = ppowerlevel_bw40[i]; + } + powerBase1 = powerlevel[i]; + powerBase1 = (powerBase1 << 24) | + (powerBase1 << 16) | (powerBase1 << 8) | powerBase1; + + *(mcsbase + i) = powerBase1; + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + (" [MCS power base index rf(%c) = 0x%x]\n", + ((i == 0) ? 'A' : 'B'), *(mcsbase + i))); + } +} + +static void _rtl8821ae_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, + u8 channel, u8 index, + u32 *powerBase0, + u32 *powerBase1, + u32 *p_outwriteval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup = 0, pwr_diff_limit[4],pwr_diff = 0,customer_pwr_diff; + u32 writeVal, customer_limit, rf; + + for (rf = 0; rf < 2; rf++) { + switch (rtlefuse->eeprom_regulatory) { + case 0: + chnlgroup = 0; + + writeVal = + rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index + + (rf ? 8 : 0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("RTK better performance, " + "writeVal(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeVal)); + break; + case 1: + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + else { + if(channel<3) + chnlgroup = 0; + else if (channel <6) + chnlgroup = 1; + else if (channel <9) + chnlgroup = 2; + else if (channel <12) + chnlgroup = 3; + else if (channel < 14) + chnlgroup = 4; + else if (channel == 14) + chnlgroup = 5; + } + + writeVal = + rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] + [index + (rf ? 8 : 0)] + ((index < 2) ? + powerBase0[rf] : + powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Realtek regulatory, 20MHz, " + "writeVal(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeVal)); + + break; + case 2: + writeVal = + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Better regulatory, " + "writeVal(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeVal)); + break; + case 3: + chnlgroup = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("customer's limit, 40MHz " + "rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), + rtlefuse->pwrgroup_ht40[rf][channel - + 1])); + } else { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("customer's limit, 20MHz " + "rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), + rtlefuse->pwrgroup_ht20[rf][channel - + 1])); + } + + if (index < 2) + pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][channel-1]; + else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) + pwr_diff = rtlefuse->txpwr_ht20diff[rf][channel-1]; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) + customer_pwr_diff = rtlefuse->pwrgroup_ht40[rf][channel-1]; + else + customer_pwr_diff = rtlefuse->pwrgroup_ht20[rf][channel-1]; + + if (pwr_diff > customer_pwr_diff) + pwr_diff = 0; + else + pwr_diff = customer_pwr_diff - pwr_diff; + + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = + (u8) ((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + (rf ? 8 : 0)] & (0x7f << + (i * 8))) >> (i * 8)); + + if(pwr_diff_limit[i] > pwr_diff) + pwr_diff_limit[i] = pwr_diff; + } + + customer_limit = (pwr_diff_limit[3] << 24) | + (pwr_diff_limit[2] << 16) | + (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Customer's limit rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), customer_limit)); + + writeVal = customer_limit + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Customer, writeVal rf(%c)= 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeVal)); + break; + default: + chnlgroup = 0; + writeVal = + rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] + [index + (rf ? 8 : 0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("RTK better performance, writeVal " + "rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeVal)); + break; + } + + if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) + writeVal = writeVal - 0x06060606; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_BT2) + writeVal = writeVal - 0x0c0c0c0c; + *(p_outwriteval + rf) = writeVal; + } +} + +static void _rtl8821ae_write_ofdm_power_reg(struct ieee80211_hw *hw, + u8 index, u32 *pValue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regoffset_a[6] = { + RTXAGC_A_OFDM18_OFDM6, RTXAGC_A_OFDM54_OFDM24, + RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, + RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 + }; + u16 regoffset_b[6] = { + RTXAGC_B_OFDM18_OFDM6, RTXAGC_B_OFDM54_OFDM24, + RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, + RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 + }; + u8 i, rf, pwr_val[4]; + u32 writeVal; + u16 regoffset; + + for (rf = 0; rf < 2; rf++) { + writeVal = pValue[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8) ((writeVal & (0x7f << + (i * 8))) >> (i * 8)); + + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | + (pwr_val[1] << 8) | pwr_val[0]; + + if (rf == 0) + regoffset = regoffset_a[index]; + else + regoffset = regoffset_b[index]; + rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Set 0x%x = %08x\n", regoffset, writeVal)); + } +} + +void rtl8821ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel_ofdm, u8 *ppowerlevel_bw20, u8 *ppowerlevel_bw40, u8 channel) +{ + u32 writeVal[2], powerBase0[2], powerBase1[2]; + u8 index; + u8 direction; + u32 pwrtrac_value; + + rtl8821ae_phy_get_power_base(hw, ppowerlevel_ofdm, ppowerlevel_bw20, ppowerlevel_bw40, + channel, &powerBase0[0], &powerBase1[0]); + + rtl8821ae_dm_txpower_track_adjust(hw,1,&direction,&pwrtrac_value); + + for (index = 0; index < 6; index++) { + _rtl8821ae_get_txpower_writeval_by_regulatory(hw, + channel, index, + &powerBase0[0], + &powerBase1[0], + &writeVal[0]); + if (direction ==1){ + writeVal[0] += pwrtrac_value; + writeVal[1] += pwrtrac_value; + } else if (direction == 2){ + writeVal[0] -= pwrtrac_value; + writeVal[1] -= pwrtrac_value; + } + _rtl8821ae_write_ofdm_power_reg(hw, index, &writeVal[0]); + } +} + +bool rtl8821ae_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + return _rtl8821ae_phy_rf6052_config_parafile(hw); + +} + +static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + //u32 u4_regvalue = 0; + u8 rfpath; + bool rtstatus = true; + //struct bb_reg_def *pphyreg; + + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + switch (rfpath) { + case RF90_PATH_A: { + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtstatus = rtl8812ae_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); + else + rtstatus = rtl8821ae_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); + break; + } + case RF90_PATH_B: { + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtstatus = rtl8812ae_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); + else + rtstatus = rtl8821ae_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); + break; + } + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + + if (rtstatus != true) { + RT_TRACE(COMP_INIT, DBG_TRACE, + ("Radio[%d] Fail!!", rfpath)); + return false; + } + + } + + /*put arrays in dm.c*/ + /*_rtl8821ae_config_rf_txpwr_track_headerfile(hw);*/ + RT_TRACE(COMP_INIT, DBG_TRACE, ("\n")); + return rtstatus; +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/fw.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/fw.c @@ -0,0 +1,1349 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" +#include "dm.h" + +static void _rtl8821ae_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + + if (enable) { + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05); + + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); + rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); + + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + //printk("0x80=%02x.\n",tmp); + } else { + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + //printk("0x80=%02x.\n",tmp); + } + +} + +static void _rtl8821ae_fw_block_write(struct ieee80211_hw *hw, + const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 blockSize = sizeof(u32); + u8 *bufferPtr = (u8 *) buffer; + u32 *pu4BytePtr = (u32 *) buffer; + u32 i, offset, blockCount, remainSize; + + blockCount = size / blockSize; + remainSize = size % blockSize; + + for (i = 0; i < blockCount; i++) { + offset = i * blockSize; + rtl_write_dword(rtlpriv, (FW_8821AE_START_ADDRESS + offset), + *(pu4BytePtr + i)); + } + + if (remainSize) { + offset = blockCount * blockSize; + bufferPtr += offset; + for (i = 0; i < remainSize; i++) { + rtl_write_byte(rtlpriv, (FW_8821AE_START_ADDRESS + + offset + i), *(bufferPtr + i)); + } + } +} + +static void _rtl8821ae_fw_page_write(struct ieee80211_hw *hw, + u32 page, const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value8; + u8 u8page = (u8) (page & 0x07); + + value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; + + rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); + _rtl8821ae_fw_block_write(hw, buffer, size); +} + +static void _rtl8821ae_fill_dummy(u8 *pfwbuf, u32 *pfwlen) +{ + u32 fwlen = *pfwlen; + u8 remain = (u8) (fwlen % 4); + + remain = (remain == 0) ? 0 : (4 - remain); + + while (remain > 0) { + pfwbuf[fwlen] = 0; + fwlen++; + remain--; + } + + *pfwlen = fwlen; +} + +static void _rtl8821ae_write_fw(struct ieee80211_hw *hw, + enum version_8821ae version, + u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 *bufferPtr = (u8 *) buffer; + u32 pageNums, remainSize; + u32 page, offset; + + RT_TRACE(COMP_FW, DBG_LOUD, ("FW size is %d bytes,\n", size)); + + _rtl8821ae_fill_dummy(bufferPtr, &size); + + pageNums = size / FW_8821AE_PAGE_SIZE; + remainSize = size % FW_8821AE_PAGE_SIZE; + + if (pageNums > 8) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Page numbers should not greater then 8\n")); + } + + for (page = 0; page < pageNums; page++) { + offset = page * FW_8821AE_PAGE_SIZE; + _rtl8821ae_fw_page_write(hw, page, (bufferPtr + offset), + FW_8821AE_PAGE_SIZE); + } + + if (remainSize) { + offset = pageNums * FW_8821AE_PAGE_SIZE; + page = pageNums; + _rtl8821ae_fw_page_write(hw, page, (bufferPtr + offset), + remainSize); + } + +} + +static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err = -EIO; + u32 counter = 0; + u32 value32; + + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + } while ((counter++ < FW_8821AE_POLLING_TIMEOUT_COUNT) && + (!(value32 & FWDL_CHKSUM_RPT))); + + if (counter >= FW_8821AE_POLLING_TIMEOUT_COUNT) { + RT_TRACE(COMP_ERR, DBG_LOUD, + ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", + value32)); + goto exit; + } + + RT_TRACE(COMP_FW, DBG_EMERG, + ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32)); + + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + value32 |= MCUFWDL_RDY; + value32 &= ~WINTINI_RDY; + rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + + rtl8821ae_firmware_selfreset(hw); + + counter = 0; + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + if (value32 & WINTINI_RDY) { + RT_TRACE(COMP_FW, DBG_LOUD, + ("Polling FW ready success!! REG_MCUFWDL:0x%08x .\n", + value32)); + err = 0; + goto exit; + } + + udelay(FW_8821AE_POLLING_DELAY); + + } while (counter++ < FW_8821AE_POLLING_TIMEOUT_COUNT); + + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); + +exit: + return err; +} + +int rtl8821ae_download_fw(struct ieee80211_hw *hw, + bool buse_wake_on_wlan_fw + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl8821a_firmware_header *pfwheader; + u8 *pfwdata; + u32 fwsize; + int err; + enum version_8821ae version = rtlhal->version; + + if(!rtlhal->pfirmware) + return 1; + + pfwheader = (struct rtl8821a_firmware_header *)rtlhal->pfirmware; + pfwdata = (u8 *) rtlhal->pfirmware; + fwsize = rtlhal->fwsize; + RT_TRACE(COMP_FW, DBG_DMESG, + ("normal Firmware SIZE %d \n",fwsize)); + + if (IS_FW_HEADER_EXIST_8812(pfwheader) || IS_FW_HEADER_EXIST_8821(pfwheader)) { + RT_TRACE(COMP_FW, DBG_DMESG, + ("Firmware Version(%d), Signature(%#x),Size(%d)\n", + pfwheader->version, pfwheader->signature, + (int)sizeof(struct rtl8821a_firmware_header))); + + pfwdata = pfwdata + sizeof(struct rtl8821a_firmware_header); + fwsize = fwsize - sizeof(struct rtl8821a_firmware_header); + } + + if(rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)){ + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + rtl8821ae_firmware_selfreset(hw); + } + _rtl8821ae_enable_fw_download(hw, true); + _rtl8821ae_write_fw(hw, version, pfwdata, fwsize); + _rtl8821ae_enable_fw_download(hw, false); + + err = _rtl8821ae_fw_free_to_go(hw); + if (err) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Firmware is not ready to run!\n")); + } else { + RT_TRACE(COMP_FW, DBG_LOUD, + ("Firmware is ready to run!\n")); + } + + return 0; +} + +static bool _rtl8821ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 val_hmetfr; + bool result = false; + + val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); + if (((val_hmetfr >> boxnum) & BIT(0)) == 0) + result = true; + return result; +} + +static void _rtl8821ae_fill_h2c_command(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 boxnum =0; + u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp = 0; + bool isfw_read = false; + u8 buf_index = 0; + bool bwrite_sucess = false; + u8 wait_h2c_limmit = 100; + /*u8 wait_writeh2c_limmit = 100;*/ + u8 boxcontent[4], boxextcontent[4]; + u32 h2c_waitcounter = 0; + unsigned long flag =0; + u8 idx =0; + + RT_TRACE(COMP_CMD, DBG_LOUD, ("come in\n")); + + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->b_h2c_setinprogress) { + RT_TRACE(COMP_CMD, DBG_LOUD, + ("H2C set in progress! Wait to set.." + "element_id(%d).\n", element_id)); + + while (rtlhal->b_h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(COMP_CMD, DBG_LOUD, + ("Wait 100 us (%d times)...\n", + h2c_waitcounter)); + udelay(100); + + if (h2c_waitcounter > 1000) + return; + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, + flag); + } + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + } else { + rtlhal->b_h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + + while (!bwrite_sucess) { + /*cosa remove this because never reach this.*/ +#if 0 + wait_writeh2c_limmit--; + if (wait_writeh2c_limmit == 0) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Write H2C fail because no trigger " + "for FW INT!\n")); + break; + } +#endif + + boxnum = rtlhal->last_hmeboxnum; + switch (boxnum) { + case 0: + box_reg = REG_HMEBOX_0; + box_extreg = REG_HMEBOX_EXT_0; + break; + case 1: + box_reg = REG_HMEBOX_1; + box_extreg = REG_HMEBOX_EXT_1; + break; + case 2: + box_reg = REG_HMEBOX_2; + box_extreg = REG_HMEBOX_EXT_2; + break; + case 3: + box_reg = REG_HMEBOX_3; + box_extreg = REG_HMEBOX_EXT_3; + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + + isfw_read = false; + u1b_tmp = rtl_read_byte(rtlpriv, REG_CR); + + if (u1b_tmp != 0xEA) + isfw_read = true; + else { + if( rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xEA || + rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xEA) + rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xFF); + } + + if (isfw_read == true) { + wait_h2c_limmit = 100; + isfw_read = _rtl8821ae_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + /*wait until Fw read*/ + wait_h2c_limmit--; + if (wait_h2c_limmit == 0) { + RT_TRACE(COMP_CMD, DBG_LOUD, + ("Wating too long for FW read " + "clear HMEBox(%d)!\n", boxnum)); + break; + } + + udelay(10); + + isfw_read = _rtl8821ae_check_fw_read_last_h2c(hw, boxnum); + u1b_tmp = rtl_read_byte(rtlpriv, 0x130); + RT_TRACE(COMP_CMD, DBG_LOUD, + ("Wating for FW read clear HMEBox(%d)!!! " + "0x130 = %2x\n", boxnum, u1b_tmp)); + } + } + + if (!isfw_read) { + RT_TRACE(COMP_CMD, DBG_LOUD, + ("Write H2C register BOX[%d] fail!!!!! " + "Fw do not read. \n", boxnum)); + break; + } + + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(COMP_CMD, DBG_LOUD, + ("Write element_id box_reg(%4x) = %2x \n", + box_reg, element_id)); + + switch (cmd_len) { + case 1: + case 2: + case 3: + /*boxcontent[0] &= ~(BIT(7));*/ + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + buf_index, cmd_len); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 4: + case 5: + case 6: + case 7: + /*boxcontent[0] |= (BIT(7));*/ + memcpy((u8 *) (boxextcontent), + p_cmdbuffer + buf_index+3, cmd_len-3); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + buf_index, 3); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + } + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + + bwrite_sucess = true; + + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + + RT_TRACE(COMP_CMD, DBG_LOUD, + ("pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum)); + } + + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->b_h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + + RT_TRACE(COMP_CMD, DBG_LOUD, ("go out\n")); +} + +void rtl8821ae_fill_h2c_cmd(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 tmp_cmdbuf[2]; + + if (rtlhal->bfw_ready == false) { + RT_ASSERT(false, ("return H2C cmd because of Fw " + "download fail!!!\n")); + return; + } + + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); + _rtl8821ae_fill_h2c_command(hw, element_id, cmd_len, (u8 *) & tmp_cmdbuf); + + return; +} + +void rtl8821ae_firmware_selfreset(struct ieee80211_hw *hw) +{ + u8 u1b_tmp; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3)))); + }else { + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(0)))); + } + + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2)))); + udelay(50); + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp | BIT(3))); + }else { + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp | BIT(0))); + } + + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2))); + + RT_TRACE(COMP_INIT, DBG_LOUD, (" _8051Reset8812ae(): 8051 reset success .\n")); + +} + +void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[H2C_8821AE_PWEMODE_LENGTH] = { 0 }; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 rlbm,power_state = 0; + RT_TRACE(COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode)); + + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); + rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/ + SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); + SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1); + SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, ppsc->reg_max_lps_awakeintvl); + SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); + if(mode == FW_PS_ACTIVE_MODE) + { + power_state |= FW_PWR_STATE_ACTIVE; + } + else + { + power_state |= FW_PWR_STATE_RF_OFF; + } + SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode \n", + u1_h2c_set_pwrmode, H2C_8821AE_PWEMODE_LENGTH); + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_SETPWRMODE, H2C_8821AE_PWEMODE_LENGTH, u1_h2c_set_pwrmode); + +} + +void rtl8821ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 u1_joinbssrpt_parm[1] = { 0 }; + + SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} + +void rtl8821ae_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, u8 ap_offload_enable) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 u1_apoffload_parm[H2C_8821AE_AP_OFFLOAD_LENGTH] = { 0 }; + + SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable); + SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->bhiddenssid); + SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0); + + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_AP_OFFLOAD, H2C_8821AE_AP_OFFLOAD_LENGTH, u1_apoffload_parm); + +} + +static bool _rtl8821ae_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + u8 own; + unsigned long flags; + struct sk_buff *pskb = NULL; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + pdesc = &ring->desc[0]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + return true; +} + +#define BEACON_PG 0 /* ->1 */ +#define PSPOLL_PG 2 +#define NULL_PG 3 +#define PROBERSP_PG 4 /* ->5 */ + +#define BEACON_PG_8812 0 +#define PSPOLL_PG_8812 1 +#define NULL_PG_8812 2 +#define PROBERSP_PG_8812 3 + +#define BEACON_PG_8821 0 +#define PSPOLL_PG_8821 1 +#define NULL_PG_8821 2 +#define PROBERSP_PG_8821 3 + +#define TOTAL_RESERVED_PKT_LEN_8812 2048 +#define TOTAL_RESERVED_PKT_LEN_8821 1024 + + +static u8 reserved_page_packet_8821[TOTAL_RESERVED_PKT_LEN_8821] = { + /* page 0 */ + 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xe0, 0x4c, 0x02, 0xe2, 0x64, + 0x40, 0x16, 0x9f, 0x23, 0xd4, 0x46, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x20, 0x04, 0x00, 0x06, 0x64, 0x6c, + 0x69, 0x6e, 0x6b, 0x31, 0x01, 0x08, 0x82, 0x84, + 0x8b, 0x96, 0x0c, 0x18, 0x30, 0x48, 0x03, 0x01, + 0x0b, 0x06, 0x02, 0x00, 0x00, 0x2a, 0x01, 0x8b, + 0x32, 0x04, 0x12, 0x24, 0x60, 0x6c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x28, 0x8c, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* page 1 */ + 0xa4, 0x10, 0x01, 0xc0, 0x40, 0x16, 0x9f, 0x23, + 0xd4, 0x46, 0x00, 0xe0, 0x4c, 0x02, 0xe2, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x28, 0x8c, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* page 2 */ + 0x48, 0x01, 0x00, 0x00, 0x40, 0x16, 0x9f, 0x23, + 0xd4, 0x46, 0x00, 0xe0, 0x4c, 0x02, 0xe2, 0x64, + 0x40, 0x16, 0x9f, 0x23, 0xd4, 0x46, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x28, 0x8c, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* page 3 */ + 0xc8, 0x01, 0x00, 0x00, 0x40, 0x16, 0x9f, 0x23, + 0xd4, 0x46, 0x00, 0xe0, 0x4c, 0x02, 0xe2, 0x64, + 0x40, 0x16, 0x9f, 0x23, 0xd4, 0x46, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +static u8 reserved_page_packet_8812[TOTAL_RESERVED_PKT_LEN_8812] = { + 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0x53, 0xE5, + 0xE0, 0x46, 0x9A, 0x57, 0x71, 0x30, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x30, 0x04, 0x00, 0x0C, 0x4E, 0x45, + 0x54, 0x47, 0x45, 0x41, 0x52, 0x5F, 0x31, 0x35, + 0x30, 0x4E, 0x01, 0x08, 0x82, 0x84, 0x8B, 0x96, + 0x0C, 0x12, 0x18, 0x24, 0x03, 0x01, 0x03, 0x06, + 0x02, 0x00, 0x00, 0x2A, 0x01, 0x8A, 0x32, 0x04, + 0x30, 0x48, 0x60, 0x6C, 0xDD, 0x18, 0x00, 0x50, + 0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x02, + 0x01, 0x00, 0x00, 0x50, 0xF2, 0x02, 0x01, 0x00, + 0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xA4, 0x10, 0x02, 0xC0, 0xE0, 0x46, 0x9A, 0x57, + 0x71, 0x30, 0x00, 0xE0, 0x4C, 0x02, 0x53, 0xE5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x48, 0x01, 0x00, 0x00, 0xE0, 0x46, 0x9A, 0x57, + 0x71, 0x30, 0x00, 0xE0, 0x4C, 0x02, 0x53, 0xE5, + 0xE0, 0x46, 0x9A, 0x57, 0x71, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1A, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xC8, 0x01, 0x00, 0x00, 0xE0, 0x46, 0x9A, 0x57, + 0x71, 0x30, 0x00, 0xE0, 0x4C, 0x02, 0x53, 0xE5, + 0xE0, 0x46, 0x9A, 0x57, 0x71, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void rtl8812ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; + + u32 totalpacketlen; + bool rtstatus; + u8 u1RsvdPageLoc[5] = { 0 }; + bool b_dlok = false; + + u8* beacon; + u8* p_pspoll; + u8* nullfunc; + u8* p_probersp; + /*--------------------------------------------------------- + (1) beacon + ---------------------------------------------------------*/ + beacon = &reserved_page_packet_8812[BEACON_PG_8812 * 512]; + SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); + SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + + /*------------------------------------------------------- + (2) ps-poll + --------------------------------------------------------*/ + p_pspoll = &reserved_page_packet_8812[PSPOLL_PG_8812 * 512]; + SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); + SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG_8812); + + /*-------------------------------------------------------- + (3) null data + ---------------------------------------------------------*/ + nullfunc = &reserved_page_packet_8812[NULL_PG_8812* 512]; + SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); + SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); + SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG_8812); + + /*--------------------------------------------------------- + (4) probe response + ----------------------------------------------------------*/ + p_probersp = &reserved_page_packet_8812[PROBERSP_PG_8812 * 512]; + SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG_8812); + + totalpacketlen = TOTAL_RESERVED_PKT_LEN_8812; + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl8821ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL \n", + &reserved_page_packet_8812[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl8821ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL \n", + u1RsvdPageLoc, 3); + + + skb = dev_alloc_skb(totalpacketlen); + memcpy((u8 *) skb_put(skb, totalpacketlen), + &reserved_page_packet_8812, totalpacketlen); + + rtstatus = _rtl8821ae_cmd_send_packet(hw, skb); + + if (rtstatus) + b_dlok = true; + + if (b_dlok) { + RT_TRACE(COMP_POWER, DBG_LOUD, + ("Set RSVD page location to Fw.\n")); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "H2C_RSVDPAGE:\n", + u1RsvdPageLoc, 3); + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_RSVDPAGE, + sizeof(u1RsvdPageLoc), u1RsvdPageLoc); + } else + RT_TRACE(COMP_ERR, DBG_WARNING, + ("Set RSVD page location to Fw FAIL!!!!!!.\n")); +} + +void rtl8821ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; + + u32 totalpacketlen; + bool rtstatus; + u8 u1RsvdPageLoc[5] = { 0 }; + bool b_dlok = false; + + u8* beacon; + u8* p_pspoll; + u8* nullfunc; + u8* p_probersp; + /*--------------------------------------------------------- + (1) beacon + ---------------------------------------------------------*/ + beacon = &reserved_page_packet_8821[BEACON_PG_8821 * 256]; + SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); + SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + + /*------------------------------------------------------- + (2) ps-poll + --------------------------------------------------------*/ + p_pspoll = &reserved_page_packet_8821[PSPOLL_PG_8821 * 256]; + SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); + SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG_8821); + + /*-------------------------------------------------------- + (3) null data + ---------------------------------------------------------*/ + nullfunc = &reserved_page_packet_8821[NULL_PG_8821 * 256]; + SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); + SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); + SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG_8821); + + /*--------------------------------------------------------- + (4) probe response + ----------------------------------------------------------*/ + p_probersp = &reserved_page_packet_8821[PROBERSP_PG_8821 * 256]; + SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG_8821); + + totalpacketlen = TOTAL_RESERVED_PKT_LEN_8821; + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl8821ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL \n", + &reserved_page_packet_8821[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl8821ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL \n", + u1RsvdPageLoc, 3); + + + skb = dev_alloc_skb(totalpacketlen); + memcpy((u8 *) skb_put(skb, totalpacketlen), + &reserved_page_packet_8821, totalpacketlen); + + rtstatus = _rtl8821ae_cmd_send_packet(hw, skb); + + if (rtstatus) + b_dlok = true; + + if (b_dlok) { + RT_TRACE(COMP_POWER, DBG_LOUD, + ("Set RSVD page location to Fw.\n")); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "H2C_RSVDPAGE:\n", + u1RsvdPageLoc, 3); + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_RSVDPAGE, + sizeof(u1RsvdPageLoc), u1RsvdPageLoc); + } else + RT_TRACE(COMP_ERR, DBG_WARNING, + ("Set RSVD page location to Fw FAIL!!!!!!.\n")); +} + +/*Shoud check FW support p2p or not.*/ +void rtl8821ae_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) +{ + u8 u1_ctwindow_period[1] ={ ctwindow}; + + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_P2P_PS_CTW_CMD, 1, u1_ctwindow_period); + +} + +void rtl8821ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); + struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; + u8 i; + u16 ctwindow; + u32 start_time, tsf_low; + + switch(p2p_ps_state) + { + case P2P_PS_DISABLE: + RT_TRACE(COMP_FW, DBG_LOUD,("P2P_PS_DISABLE \n")); + memset(p2p_ps_offload, 0, 1); + break; + case P2P_PS_ENABLE: + RT_TRACE(COMP_FW, DBG_LOUD,("P2P_PS_ENABLE \n")); + /* update CTWindow value. */ + if( p2pinfo->ctwindow > 0 ) + { + p2p_ps_offload->CTWindow_En = 1; + ctwindow = p2pinfo->ctwindow; + rtl8821ae_set_p2p_ctw_period_cmd(hw, ctwindow); + } + + /* hw only support 2 set of NoA */ + for( i=0 ; inoa_num ; i++) + { + /* To control the register setting for which NOA*/ + rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); + if(i == 0) + p2p_ps_offload->NoA0_En = 1; + else + p2p_ps_offload->NoA1_En = 1; + + /* config P2P NoA Descriptor Register */ + rtl_write_dword(rtlpriv, 0x5E0, p2pinfo->noa_duration[i]); + rtl_write_dword(rtlpriv, 0x5E4, p2pinfo->noa_interval[i]); + + /*Get Current TSF value */ + tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + + start_time = p2pinfo->noa_start_time[i]; + if(p2pinfo->noa_count_type[i] != 1) + { + while( start_time <= (tsf_low+(50*1024) ) ) { + start_time += p2pinfo->noa_interval[i]; + if(p2pinfo->noa_count_type[i] != 255) + p2pinfo->noa_count_type[i]--; + } + } + rtl_write_dword(rtlpriv, 0x5E8, start_time); + rtl_write_dword(rtlpriv, 0x5EC, p2pinfo->noa_count_type[i] ); + + } + + if( (p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0) ) + { + /* rst p2p circuit */ + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); + + p2p_ps_offload->Offload_En = 1; + + if(P2P_ROLE_GO == rtlpriv->mac80211.p2p) + { + p2p_ps_offload->role= 1; + p2p_ps_offload->AllStaSleep = 0; + } + else + { + p2p_ps_offload->role= 0; + } + + p2p_ps_offload->discovery = 0; + } + break; + case P2P_PS_SCAN: + RT_TRACE(COMP_FW, DBG_LOUD,("P2P_PS_SCAN \n")); + p2p_ps_offload->discovery = 1; + break; + case P2P_PS_SCAN_DONE: + RT_TRACE(COMP_FW, DBG_LOUD,("P2P_PS_SCAN_DONE \n")); + p2p_ps_offload->discovery = 0; + p2pinfo->p2p_ps_state = P2P_PS_ENABLE; + break; + default: + break; + } + + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload); + +} + +void rtl8812ae_c2h_ra_report_handler( + struct ieee80211_hw *hw, + u8 *cmd_buf, + u8 cmd_len +) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 rate = cmd_buf[0] & 0x3F; + + rtlhal->current_ra_rate= rtl8812ae_hw_rate_to_mrate(hw, rate); + + rtl8812ae_dm_update_init_rate(hw, rate); +} + + +void _rtl8812ae_c2h_content_parsing( + struct ieee80211_hw *hw, + u8 c2h_cmd_id, + u8 c2h_cmd_len, + u8 *tmp_buf +) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (c2h_cmd_id) { + case C2H_8812_DBG: + RT_TRACE(COMP_FW, DBG_LOUD,("[C2H], C2H_8812_DBG!!\n")); + break; + + case C2H_8812_RA_RPT: + rtl8812ae_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); + break; + + default: + break; + } + +} + +void rtl8812ae_c2h_packet_handler( + struct ieee80211_hw *hw, + u8 *buffer, + u8 length + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 c2h_cmd_id=0, c2h_cmd_seq=0, c2h_cmd_len=0; + u8 *tmp_buf=NULL; + + c2h_cmd_id = buffer[0]; + c2h_cmd_seq = buffer[1]; + c2h_cmd_len = length -2; + tmp_buf = buffer + 2; + + RT_TRACE(COMP_FW, DBG_LOUD, + ("[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n", + c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len)); + + RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, + "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); + _rtl8812ae_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); +} + + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.h @@ -0,0 +1,160 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_HAL_BTC_H__ +#define __RTL8821AE_HAL_BTC_H__ + +#include "../wifi.h" +#include "btc.h" +#include "hal_bt_coexist.h" + +#define BT_TXRX_CNT_THRES_1 1200 +#define BT_TXRX_CNT_THRES_2 1400 +#define BT_TXRX_CNT_THRES_3 3000 +#define BT_TXRX_CNT_LEVEL_0 0 // < 1200 +#define BT_TXRX_CNT_LEVEL_1 1 // >= 1200 && < 1400 +#define BT_TXRX_CNT_LEVEL_2 2 // >= 1400 +#define BT_TXRX_CNT_LEVEL_3 3 + + + +#define BT_COEX_DISABLE 0 +#define BT_Q_PKT_OFF 0 +#define BT_Q_PKT_ON 1 + +#define BT_TX_PWR_OFF 0 +#define BT_TX_PWR_ON 1 + +/* TDMA mode definition */ +#define TDMA_2ANT 0 +#define TDMA_1ANT 1 +#define TDMA_NAV_OFF 0 +#define TDMA_NAV_ON 1 +#define TDMA_DAC_SWING_OFF 0 +#define TDMA_DAC_SWING_ON 1 + +/* PTA mode related definition */ +#define BT_PTA_MODE_OFF 0 +#define BT_PTA_MODE_ON 1 + +/* Penalty Tx Rate Adaptive */ +#define BT_TX_RATE_ADAPTIVE_NORMAL 0 +#define BT_TX_RATE_ADAPTIVE_LOW_PENALTY 1 + +/* RF Corner */ +#define BT_RF_RX_LPF_CORNER_RESUME 0 +#define BT_RF_RX_LPF_CORNER_SHRINK 1 + +#define C2H_EVT_HOST_CLOSE 0x00 +#define C2H_EVT_FW_CLOSE 0xFF + +enum bt_traffic_mode { + BT_MOTOR_EXT_BE = 0x00, + BT_MOTOR_EXT_GUL = 0x01, + BT_MOTOR_EXT_GUB = 0x02, + BT_MOTOR_EXT_GULB = 0x03 +}; + +enum bt_traffic_mode_profile { + BT_PROFILE_NONE, + BT_PROFILE_A2DP, + BT_PROFILE_PAN, + BT_PROFILE_HID, + BT_PROFILE_SCO +}; + +enum hci_ext_bt_operation { + HCI_BT_OP_NONE = 0x0, + HCI_BT_OP_INQUIRE_START = 0x1, + HCI_BT_OP_INQUIRE_FINISH = 0x2, + HCI_BT_OP_PAGING_START = 0x3, + HCI_BT_OP_PAGING_SUCCESS = 0x4, + HCI_BT_OP_PAGING_UNSUCCESS = 0x5, + HCI_BT_OP_PAIRING_START = 0x6, + HCI_BT_OP_PAIRING_FINISH = 0x7, + HCI_BT_OP_BT_DEV_ENABLE = 0x8, + HCI_BT_OP_BT_DEV_DISABLE = 0x9, + HCI_BT_OP_MAX, +}; + +enum bt_spec { + BT_SPEC_1_0_b = 0x00, + BT_SPEC_1_1 = 0x01, + BT_SPEC_1_2 = 0x02, + BT_SPEC_2_0_EDR = 0x03, + BT_SPEC_2_1_EDR = 0x04, + BT_SPEC_3_0_HS = 0x05, + BT_SPEC_4_0 = 0x06 +}; + +struct c2h_evt_hdr { + u8 cmd_id; + u8 cmd_len; + u8 cmd_seq; +}; + +enum bt_state{ + BT_INFO_STATE_DISABLED = 0, + BT_INFO_STATE_NO_CONNECTION = 1, + BT_INFO_STATE_CONNECT_IDLE = 2, + BT_INFO_STATE_INQ_OR_PAG = 3, + BT_INFO_STATE_ACL_ONLY_BUSY = 4, + BT_INFO_STATE_SCO_ONLY_BUSY = 5, + BT_INFO_STATE_ACL_SCO_BUSY = 6, + BT_INFO_STATE_HID_BUSY = 7, + BT_INFO_STATE_HID_SCO_BUSY = 8, + BT_INFO_STATE_MAX = 7 +}; + +enum rtl8723be_c2h_evt { + C2H_DBG = 0, + C2H_TSF = 1, + C2H_AP_RPT_RSP = 2, + C2H_CCX_TX_RPT = 3, // The FW notify the report of the specific tx packet. + C2H_BT_RSSI = 4, + C2H_BT_OP_MODE = 5, + C2H_HW_INFO_EXCH = 10, + C2H_C2H_H2C_TEST = 11, + BT_INFO = 9, + MAX_C2HEVENT +}; + + + +void rtl8821ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_coexist(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, struct btdm_8821ae *p_btdm); +void rtl_8821ae_c2h_command_handle(struct ieee80211_hw * hw); +void rtl_8821ae_bt_wifi_media_status_notify(struct ieee80211_hw * hw, bool mstatus); +void rtl8821ae_dm_bt_turn_off_bt_coexist_before_enter_lps(struct ieee80211_hw *hw); + + + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.h @@ -0,0 +1,71 @@ +#ifndef __RTL8821AE_PWRSEQCMD_H__ +#define __RTL8821AE_PWRSEQCMD_H__ + +#include "../wifi.h" +/*---------------------------------------------*/ +/*The value of cmd: 4 bits */ +/*---------------------------------------------*/ +#define PWR_CMD_READ 0x00 +#define PWR_CMD_WRITE 0x01 +#define PWR_CMD_POLLING 0x02 +#define PWR_CMD_DELAY 0x03 +#define PWR_CMD_END 0x04 + +/* define the base address of each block */ +#define PWR_BASEADDR_MAC 0x00 +#define PWR_BASEADDR_USB 0x01 +#define PWR_BASEADDR_PCIE 0x02 +#define PWR_BASEADDR_SDIO 0x03 + +#define PWR_INTF_SDIO_MSK BIT(0) +#define PWR_INTF_USB_MSK BIT(1) +#define PWR_INTF_PCI_MSK BIT(2) +#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +#define PWR_FAB_TSMC_MSK BIT(0) +#define PWR_FAB_UMC_MSK BIT(1) +#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +#define PWR_CUT_TESTCHIP_MSK BIT(0) +#define PWR_CUT_A_MSK BIT(1) +#define PWR_CUT_B_MSK BIT(2) +#define PWR_CUT_C_MSK BIT(3) +#define PWR_CUT_D_MSK BIT(4) +#define PWR_CUT_E_MSK BIT(5) +#define PWR_CUT_F_MSK BIT(6) +#define PWR_CUT_G_MSK BIT(7) +#define PWR_CUT_ALL_MSK 0xFF + + +enum pwrseq_delay_unit { + PWRSEQ_DELAY_US, + PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { + u16 offset; + u8 cut_msk; + u8 fab_msk:4; + u8 interface_msk:4; + u8 base:4; + u8 cmd:4; + u8 msk; + u8 value; + +}; + +#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset +#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) __PWR_CMD.cut_msk +#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) __PWR_CMD.fab_msk +#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) __PWR_CMD.interface_msk +#define GET_PWR_CFG_BASE(__PWR_CMD) __PWR_CMD.base +#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd +#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk +#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value + +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv * rtlpriv, u8 cut_version, + u8 fab_version, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]); + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h @@ -0,0 +1,413 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_PWRSEQ_H__ +#define __RTL8821AE_PWRSEQ_H__ + +#include "pwrseqcmd.h" +#include "../btcoexist/halbt_precomp.h" + +#define RTL8812_TRANS_CARDEMU_TO_ACT_STEPS 15 +#define RTL8812_TRANS_ACT_TO_CARDEMU_STEPS 15 +#define RTL8812_TRANS_CARDEMU_TO_SUS_STEPS 15 +#define RTL8812_TRANS_SUS_TO_CARDEMU_STEPS 15 +#define RTL8812_TRANS_CARDEMU_TO_PDN_STEPS 25 +#define RTL8812_TRANS_PDN_TO_CARDEMU_STEPS 15 +#define RTL8812_TRANS_ACT_TO_LPS_STEPS 15 +#define RTL8812_TRANS_LPS_TO_ACT_STEPS 15 +#define RTL8812_TRANS_END_STEPS 1 + + +#define RTL8812_TRANS_CARDEMU_TO_ACT \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]=0*/ \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]=0*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, 0},/* disable WL suspend*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT0, 0},/**/ + +#define RTL8812_TRANS_ACT_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ + {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0}, /* 0x2[0] = 0 RESET BB, CLOSE RF */ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ + /*{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},//0x1F[7:0] = 0 turn off RF*/ \ + /*{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},//0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x2A}, /* 0x07[7:0] = 0x28 sps pwm mode 0x2a for BT coex*/ \ + {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk =500k */ \ + /*{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0|BIT1, 0}, // 0x02[1:0] = 0 reset BB */ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ + +#define RTL8812_TRANS_CARDEMU_TO_SUS \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xF0, 0xcc},\ + {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xF0, 0xEC},\ + {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ + {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ + {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ + {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* suspend option all off */ \ + {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ + {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk =500k */ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'11 enable WL suspend for PCIe*/ + +#define RTL8812_TRANS_SUS_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO sleep mode leave */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ + {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ + {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ + {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ + +#define RTL8812_TRANS_CARDEMU_TO_CARDDIS \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + /**{0x0194, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0}, //0x194[0]=0 , disable 32K clock*/ \ + /**{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x94}, //0x93=0x94 , 90[30] =0 enable 500k ANA clock .switch clock from 12M to 500K , 90 [26] =0 disable EEprom loader clock*/ \ + {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT2, 0}, /*0x03[2] = 0, reset 8051*/ \ + {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x05}, /*0x80=05h if reload fw, fill the default value of host_CPU handshake field*/ \ + {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xF0, 0xcc},\ + {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xF0, 0xEC},\ + {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x07},/* gpio11 input mode, gpio10~8 output mode */ \ + {0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio 0~7 output same value as input ?? */ \ + {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ + {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ + {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ + {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/*0x12[0] = 0 force PFM mode */ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ + {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk =500k */ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07=0x20 , SOP option to disable BG/MB*/ \ + {0x001f, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0}, /*0x01f[1]=0 , disable RFC_0 control REG_RF_CTRL_8812 */ \ + {0x0076, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0}, /*0x076[1]=0 , disable RFC_1 control REG_OPT_CTRL_8812 +2 */ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'01 enable WL suspend*/ + +#define RTL8812_TRANS_CARDDIS_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/*0x12[0] = 1 force PWM mode */ \ + {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO leave sleep mode */ \ + {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ + {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT2, 0}, /*0x04[10] = 0, enable SW LPS PCIE only*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \ + {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT2, BIT2}, /*0x03[2] = 1, enable 8051*/ \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ + + +#define RTL8812_TRANS_CARDEMU_TO_PDN \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ + +#define RTL8812_TRANS_PDN_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ + +#define RTL8812_TRANS_ACT_TO_LPS \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \ + {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xc00[7:0] = 4 turn off 3-wire */ \ + {0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x04}, /* 0xe00[7:0] = 4 turn off 3-wire */ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled,and clock are gated,and RF closed*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0}, /* Whole BB is reset*/ \ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ + {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ + + +#define RTL8812_TRANS_LPS_TO_ACT \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/ \ + {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/ \ + {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/ \ + {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/ \ + {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/ \ + {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT6|BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/ \ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/ \ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/ \ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ + +#define RTL8812_TRANS_END \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,0,PWR_CMD_END, 0, 0}, // + + +extern struct wlan_pwr_cfg rtl8812_power_on_flow[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_radio_off_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_card_disable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_PDN_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_card_enable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_PDN_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_suspend_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_SUS_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_resume_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_SUS_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_hwpdn_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS+RTL8812_TRANS_CARDEMU_TO_PDN_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_enter_lps_flow[RTL8812_TRANS_ACT_TO_LPS_STEPS+RTL8812_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEPS+RTL8812_TRANS_END_STEPS]; + +/* + Check document WM-20130516-JackieLau-RTL8821A_Power_Architecture-R10.vsd + There are 6 HW Power States: + 0: POFF--Power Off + 1: PDN--Power Down + 2: CARDEMU--Card Emulation + 3: ACT--Active Mode + 4: LPS--Low Power State + 5: SUS--Suspend + + The transision from different states are defined below + TRANS_CARDEMU_TO_ACT + TRANS_ACT_TO_CARDEMU + TRANS_CARDEMU_TO_SUS + TRANS_SUS_TO_CARDEMU + TRANS_CARDEMU_TO_PDN + TRANS_ACT_TO_LPS + TRANS_LPS_TO_ACT + + TRANS_END +*/ +#define RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS 25 +#define RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS 15 +#define RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS 15 +#define RTL8821A_TRANS_SUS_TO_CARDEMU_STEPS 15 +#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS 15 +#define RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS 15 +#define RTL8821A_TRANS_PDN_TO_CARDEMU_STEPS 15 +#define RTL8821A_TRANS_ACT_TO_LPS_STEPS 15 +#define RTL8821A_TRANS_LPS_TO_ACT_STEPS 15 +#define RTL8821A_TRANS_END_STEPS 1 + + +#define RTL8821A_TRANS_CARDEMU_TO_ACT \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \ + {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \ + {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \ + {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital ,1:isolation*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, (BIT4|BIT3|BIT2), 0},/* disable SW LPS 0x04[10]=0 and WLSUS_EN 0x04[12:11]=0*/ \ + {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0 , BIT0},/* Disable USB suspend */ \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ + {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0 , 0},/* Enable USB suspend */ \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]=1*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]=0*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, (BIT4|BIT3), 0},/* disable WL suspend*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT0, 0},/**/ \ + {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/*0x4C[24] = 0x4F[0] = 1, switch DPDT_SEL_P output from WL BB */\ + {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, (BIT5|BIT4), (BIT5|BIT4)},/*0x66[13] = 0x67[5] = 1, switch for PAPE_G/PAPE_A from WL BB ; 0x66[12] = 0x67[4] = 1, switch LNAON from WL BB */\ + {0x0025, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT6, 0},/*anapar_mac<118> , 0x25[6]=0 by wlan single function*/\ + {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1},/*Enable falling edge triggering interrupt*/\ + {0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1},/*Enable GPIO9 interrupt mode*/\ + {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*Enable GPIO9 input mode*/\ + {0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/*Enable HSISR GPIO[C:0] interrupt*/\ + {0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1},/*Enable HSISR GPIO9 interrupt*/\ + {0x007A, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x3A},/*0x7A = 0x3A start BT*/\ + {0x002E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF , 0x82 },/* 0x2C[23:12]=0x820 ; XTAL trim */ \ + {0x0010, PWR_CUT_A_MSK , PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT6 , BIT6 },/* 0x10[6]=1 ; MP·s¼W¹ï©ó0x2Cªº±±¨îÅv¡A¶·§â0x10[6]³]¬°1¤~¯àÅýWLAN±±¨î */ \ + + +#define RTL8821A_TRANS_ACT_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \ + {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/*0x4C[24] = 0x4F[0] = 0, switch DPDT_SEL_P output from register 0x65[2] */\ + {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*Enable rising edge triggering interrupt*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ + {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, BIT5}, /*0x00[5] = 1b'1 analog Ips to digital ,1:isolation*/ \ + {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/ \ + + +#define RTL8821A_TRANS_CARDEMU_TO_SUS \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4|BIT3, (BIT4|BIT3)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ + +#define RTL8821A_TRANS_SUS_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ + +#define RTL8821A_TRANS_CARDEMU_TO_CARDDIS \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07=0x20 , SOP option to disable BG/MB*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT2, BIT2}, /*0x04[10] = 1, enable SW LPS*/ \ + {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ + +#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ + {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ + + +#define RTL8821A_TRANS_CARDEMU_TO_PDN \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ + +#define RTL8821A_TRANS_PDN_TO_CARDEMU \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ + +#define RTL8821A_TRANS_ACT_TO_LPS \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/ \ + {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled,and clock are gated*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*Whole BB is reset*/ \ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ + {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/ \ + {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ \ + + +#define RTL8821A_TRANS_LPS_TO_ACT \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\ + {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\ + {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\ + {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\ + {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/\ + {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT6|BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ + +#define RTL8821A_TRANS_END \ + /* format */ \ + /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ + {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,0,PWR_CMD_END, 0, 0}, // + +extern struct wlan_pwr_cfg rtl8821A_power_on_flow[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_radio_off_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_card_disable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_card_enable_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS/*RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS*/ + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_suspend_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_resume_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_hwpdn_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_enter_lps_flow[RTL8821A_TRANS_ACT_TO_LPS_STEPS + + RTL8821A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8821A_leave_lps_flow[RTL8821A_TRANS_LPS_TO_ACT_STEPS + + RTL8821A_TRANS_END_STEPS]; + +/*RTL8812 Power Configuration CMDs for PCIe interface*/ +#define RTL8812_NIC_PWR_ON_FLOW rtl8812_power_on_flow +#define RTL8812_NIC_RF_OFF_FLOW rtl8812_radio_off_flow +#define RTL8812_NIC_DISABLE_FLOW rtl8812_card_disable_flow +#define RTL8812_NIC_ENABLE_FLOW rtl8812_card_enable_flow +#define RTL8812_NIC_SUSPEND_FLOW rtl8812_suspend_flow +#define RTL8812_NIC_RESUME_FLOW rtl8812_resume_flow +#define RTL8812_NIC_PDN_FLOW rtl8812_hwpdn_flow +#define RTL8812_NIC_LPS_ENTER_FLOW rtl8812_enter_lps_flow +#define RTL8812_NIC_LPS_LEAVE_FLOW rtl8812_leave_lps_flow + +/* RTL8821 Power Configuration CMDs for PCIe interface */ +#define RTL8821A_NIC_PWR_ON_FLOW rtl8821A_power_on_flow +#define RTL8821A_NIC_RF_OFF_FLOW rtl8821A_radio_off_flow +#define RTL8821A_NIC_DISABLE_FLOW rtl8821A_card_disable_flow +#define RTL8821A_NIC_ENABLE_FLOW rtl8821A_card_enable_flow +#define RTL8821A_NIC_SUSPEND_FLOW rtl8821A_suspend_flow +#define RTL8821A_NIC_RESUME_FLOW rtl8821A_resume_flow +#define RTL8821A_NIC_PDN_FLOW rtl8821A_hwpdn_flow +#define RTL8821A_NIC_LPS_ENTER_FLOW rtl8821A_enter_lps_flow +#define RTL8821A_NIC_LPS_LEAVE_FLOW rtl8821A_leave_lps_flow + + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/def.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/def.h @@ -0,0 +1,442 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_DEF_H__ +#define __RTL8821AE_DEF_H__ + +/*--------------------------Define -------------------------------------------*/ +/* BIT 7 HT Rate*/ +/*TxHT = 0*/ +#define MGN_1M 0x02 +#define MGN_2M 0x04 +#define MGN_5_5M 0x0b +#define MGN_11M 0x16 + +#define MGN_6M 0x0c +#define MGN_9M 0x12 +#define MGN_12M 0x18 +#define MGN_18M 0x24 +#define MGN_24M 0x30 +#define MGN_36M 0x48 +#define MGN_48M 0x60 +#define MGN_54M 0x6c + +// TxHT = 1 +#define MGN_MCS0 0x80 +#define MGN_MCS1 0x81 +#define MGN_MCS2 0x82 +#define MGN_MCS3 0x83 +#define MGN_MCS4 0x84 +#define MGN_MCS5 0x85 +#define MGN_MCS6 0x86 +#define MGN_MCS7 0x87 +#define MGN_MCS8 0x88 +#define MGN_MCS9 0x89 +#define MGN_MCS10 0x8a +#define MGN_MCS11 0x8b +#define MGN_MCS12 0x8c +#define MGN_MCS13 0x8d +#define MGN_MCS14 0x8e +#define MGN_MCS15 0x8f +//VHT rate +#define MGN_VHT1SS_MCS0 0x90 +#define MGN_VHT1SS_MCS1 0x91 +#define MGN_VHT1SS_MCS2 0x92 +#define MGN_VHT1SS_MCS3 0x93 +#define MGN_VHT1SS_MCS4 0x94 +#define MGN_VHT1SS_MCS5 0x95 +#define MGN_VHT1SS_MCS6 0x96 +#define MGN_VHT1SS_MCS7 0x97 +#define MGN_VHT1SS_MCS8 0x98 +#define MGN_VHT1SS_MCS9 0x99 +#define MGN_VHT2SS_MCS0 0x9a +#define MGN_VHT2SS_MCS1 0x9b +#define MGN_VHT2SS_MCS2 0x9c +#define MGN_VHT2SS_MCS3 0x9d +#define MGN_VHT2SS_MCS4 0x9e +#define MGN_VHT2SS_MCS5 0x9f +#define MGN_VHT2SS_MCS6 0xa0 +#define MGN_VHT2SS_MCS7 0xa1 +#define MGN_VHT2SS_MCS8 0xa2 +#define MGN_VHT2SS_MCS9 0xa3 + +#define MGN_VHT3SS_MCS0 0xa4 +#define MGN_VHT3SS_MCS1 0xa5 +#define MGN_VHT3SS_MCS2 0xa6 +#define MGN_VHT3SS_MCS3 0xa7 +#define MGN_VHT3SS_MCS4 0xa8 +#define MGN_VHT3SS_MCS5 0xa9 +#define MGN_VHT3SS_MCS6 0xaa +#define MGN_VHT3SS_MCS7 0xab +#define MGN_VHT3SS_MCS8 0xac +#define MGN_VHT3SS_MCS9 0xad + +#define MGN_MCS0_SG 0xc0 +#define MGN_MCS1_SG 0xc1 +#define MGN_MCS2_SG 0xc2 +#define MGN_MCS3_SG 0xc3 +#define MGN_MCS4_SG 0xc4 +#define MGN_MCS5_SG 0xc5 +#define MGN_MCS6_SG 0xc6 +#define MGN_MCS7_SG 0xc7 +#define MGN_MCS8_SG 0xc8 +#define MGN_MCS9_SG 0xc9 +#define MGN_MCS10_SG 0xca +#define MGN_MCS11_SG 0xcb +#define MGN_MCS12_SG 0xcc +#define MGN_MCS13_SG 0xcd +#define MGN_MCS14_SG 0xce +#define MGN_MCS15_SG 0xcf + +#define MGN_UNKNOWN 0xff + + +/* 30 ms */ +#define WIFI_NAV_UPPER_US 30000 +#define HAL_92C_NAV_UPPER_UNIT 128 + +#define HAL_RETRY_LIMIT_INFRA 48 +#define HAL_RETRY_LIMIT_AP_ADHOC 7 + +#define RESET_DELAY_8185 20 + +#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER) +#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) + +#define NUM_OF_FIRMWARE_QUEUE 10 +#define NUM_OF_PAGES_IN_FW 0x100 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1 + +#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00 + +#define MAX_RX_DMA_BUFFER_SIZE 0x3E80 + + +#define MAX_LINES_HWCONFIG_TXT 1000 +#define MAX_BYTES_LINE_HWCONFIG_TXT 256 + +#define SW_THREE_WIRE 0 +#define HW_THREE_WIRE 2 + +#define BT_DEMO_BOARD 0 +#define BT_QA_BOARD 1 +#define BT_FPGA 2 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +#define MAX_H2C_QUEUE_NUM 10 + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 +#define AC2QUEUEID(_AC) (_AC) + +#define C2H_RX_CMD_HDR_LEN 8 +#define GET_C2H_CMD_CMD_LEN(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 0, 16) +#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 16, 8) +#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 24, 7) +#define GET_C2H_CMD_CONTINUE(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 31, 1) +#define GET_C2H_CMD_CONTENT(__prxhdr) \ + ((u8*)(__prxhdr) + C2H_RX_CMD_HDR_LEN) + +#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16) +#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) +#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) + +#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) + +#define CHIP_8812 BIT(2) +#define CHIP_8821 (BIT(0)|BIT(2)) + +#define CHIP_8821A (BIT(0)|BIT(2)) +#define NORMAL_CHIP BIT(3) +#define RF_TYPE_1T1R (~(BIT(4)|BIT(5)|BIT(6))) +#define RF_TYPE_1T2R BIT(4) +#define RF_TYPE_2T2R BIT(5) +#define CHIP_VENDOR_UMC BIT(7) +#define B_CUT_VERSION BIT(12) +#define C_CUT_VERSION BIT(13) +#define D_CUT_VERSION ((BIT(12)|BIT(13))) +#define E_CUT_VERSION BIT(14) +#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28)) + + + +enum version_8821ae { + VERSION_TEST_CHIP_1T1R_8812 = 0x0004, + VERSION_TEST_CHIP_2T2R_8812 = 0x0024, + VERSION_NORMAL_TSMC_CHIP_1T1R_8812 = 0x100c, + VERSION_NORMAL_TSMC_CHIP_2T2R_8812 = 0x102c, + VERSION_NORMAL_TSMC_CHIP_1T1R_8812_C_CUT = 0x200c, + VERSION_NORMAL_TSMC_CHIP_2T2R_8812_C_CUT = 0x202c, + VERSION_TEST_CHIP_8821 = 0x0005, + VERSION_NORMAL_TSMC_CHIP_8821 = 0x000d, + VERSION_NORMAL_TSMC_CHIP_8821_B_CUT = 0x100d, + VERSION_UNKNOWN = 0xFF, +}; + +enum vht_data_sc{ + VHT_DATA_SC_DONOT_CARE = 0, + VHT_DATA_SC_20_UPPER_OF_80MHZ = 1, + VHT_DATA_SC_20_LOWER_OF_80MHZ = 2, + VHT_DATA_SC_20_UPPERST_OF_80MHZ = 3, + VHT_DATA_SC_20_LOWEST_OF_80MHZ = 4, + VHT_DATA_SC_20_RECV1 = 5, + VHT_DATA_SC_20_RECV2 = 6, + VHT_DATA_SC_20_RECV3 = 7, + VHT_DATA_SC_20_RECV4 = 8, + VHT_DATA_SC_40_UPPER_OF_80MHZ = 9, + VHT_DATA_SC_40_LOWER_OF_80MHZ = 10, +}; + + +/* MASK */ +#define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2)) +#define CHIP_TYPE_MASK BIT(3) +#define RF_TYPE_MASK (BIT(4)|BIT(5)|BIT(6)) +#define MANUFACTUER_MASK BIT(7) +#define ROM_VERSION_MASK (BIT(11)|BIT(10)|BIT(9)|BIT(8)) +#define CUT_VERSION_MASK (BIT(15)|BIT(14)|BIT(13)|BIT(12)) + +/* Get element */ +#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK) +#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK) +#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK) +#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK) +#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK) +#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK) + +#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version))? false : true) +#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)\ + ? true : false) +#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)\ + ? true : false) + +#define IS_8812_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8812)? \ + true : false) +#define IS_8821_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8821)? \ + true : false) + +#define IS_VENDOR_8812A_TEST_CHIP(version) ((IS_8812_SERIES(version)) ? \ + ((IS_NORMAL_CHIP(version)) ? \ + false : true) : false) +#define IS_VENDOR_8812A_MP_CHIP(version) ((IS_8812_SERIES(version)) ? \ + ((IS_NORMAL_CHIP(version)) ? \ + true : false) : false) +#define IS_VENDOR_8812A_C_CUT(version) ((IS_8812_SERIES(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? \ + true : false) : false) + +#define IS_VENDOR_8821A_TEST_CHIP(version) ((IS_8821_SERIES(version)) ? \ + ((IS_NORMAL_CHIP(version)) ? \ + false : true) : false) +#define IS_VENDOR_8821A_MP_CHIP(version) ((IS_8821_SERIES(version)) ? \ + ((IS_NORMAL_CHIP(version)) ? \ + true : false) : false) +#define IS_VENDOR_8821A_B_CUT(version) ((IS_8821_SERIES(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? \ + true : false) : false) + + +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +enum rf_power_state { + RF_ON, + RF_OFF, + RF_SLEEP, + RF_SHUT_DOWN, +}; + +enum power_save_mode { + POWER_SAVE_MODE_ACTIVE, + POWER_SAVE_MODE_SAVE, +}; + +enum power_polocy_config { + POWERCFG_MAX_POWER_SAVINGS, + POWERCFG_GLOBAL_POWER_SAVINGS, + POWERCFG_LOCAL_POWER_SAVINGS, + POWERCFG_LENOVO, +}; + +enum interface_select_pci { + INTF_SEL1_MINICARD = 0, + INTF_SEL0_PCIE = 1, + INTF_SEL2_RSV = 2, + INTF_SEL3_RSV = 3, +}; + +enum hal_fw_c2h_cmd_id { + HAL_FW_C2H_CMD_Read_MACREG = 0, + HAL_FW_C2H_CMD_Read_BBREG = 1, + HAL_FW_C2H_CMD_Read_RFREG = 2, + HAL_FW_C2H_CMD_Read_EEPROM = 3, + HAL_FW_C2H_CMD_Read_EFUSE = 4, + HAL_FW_C2H_CMD_Read_CAM = 5, + HAL_FW_C2H_CMD_Get_BasicRate = 6, + HAL_FW_C2H_CMD_Get_DataRate = 7, + HAL_FW_C2H_CMD_Survey = 8, + HAL_FW_C2H_CMD_SurveyDone = 9, + HAL_FW_C2H_CMD_JoinBss = 10, + HAL_FW_C2H_CMD_AddSTA = 11, + HAL_FW_C2H_CMD_DelSTA = 12, + HAL_FW_C2H_CMD_AtimDone = 13, + HAL_FW_C2H_CMD_TX_Report = 14, + HAL_FW_C2H_CMD_CCX_Report = 15, + HAL_FW_C2H_CMD_DTM_Report = 16, + HAL_FW_C2H_CMD_TX_Rate_Statistics = 17, + HAL_FW_C2H_CMD_C2HLBK = 18, + HAL_FW_C2H_CMD_C2HDBG = 19, + HAL_FW_C2H_CMD_C2HFEEDBACK = 20, + HAL_FW_C2H_CMD_MAX +}; + +enum rtl_desc_qsel { + QSLT_BK = 0x2, + QSLT_BE = 0x0, + QSLT_VI = 0x5, + QSLT_VO = 0x7, + QSLT_BEACON = 0x10, + QSLT_HIGH = 0x11, + QSLT_MGNT = 0x12, + QSLT_CMD = 0x13, +}; + +enum rtl_desc8821ae_rate { + DESC_RATE1M = 0x00, + DESC_RATE2M = 0x01, + DESC_RATE5_5M = 0x02, + DESC_RATE11M = 0x03, + + DESC_RATE6M = 0x04, + DESC_RATE9M = 0x05, + DESC_RATE12M = 0x06, + DESC_RATE18M = 0x07, + DESC_RATE24M = 0x08, + DESC_RATE36M = 0x09, + DESC_RATE48M = 0x0a, + DESC_RATE54M = 0x0b, + + DESC_RATEMCS0 = 0x0c, + DESC_RATEMCS1 = 0x0d, + DESC_RATEMCS2 = 0x0e, + DESC_RATEMCS3 = 0x0f, + DESC_RATEMCS4 = 0x10, + DESC_RATEMCS5 = 0x11, + DESC_RATEMCS6 = 0x12, + DESC_RATEMCS7 = 0x13, + DESC_RATEMCS8 = 0x14, + DESC_RATEMCS9 = 0x15, + DESC_RATEMCS10 = 0x16, + DESC_RATEMCS11 = 0x17, + DESC_RATEMCS12 = 0x18, + DESC_RATEMCS13 = 0x19, + DESC_RATEMCS14 = 0x1a, + DESC_RATEMCS15 = 0x1b, + DESC_RATEVHT1SS_MCS0 = 0x1c, + DESC_RATEVHT1SS_MCS1 = 0x1d, + DESC_RATEVHT1SS_MCS2 = 0x1e, + DESC_RATEVHT1SS_MCS3 = 0x1f, + DESC_RATEVHT1SS_MCS4 = 0x20, + DESC_RATEVHT1SS_MCS5 = 0x21, + DESC_RATEVHT1SS_MCS6 = 0x22, + DESC_RATEVHT1SS_MCS7 = 0x23, + DESC_RATEVHT1SS_MCS8 = 0x24, + DESC_RATEVHT1SS_MCS9 = 0x25, + DESC_RATEVHT2SS_MCS0 = 0x26, + DESC_RATEVHT2SS_MCS1 = 0x27, + DESC_RATEVHT2SS_MCS2 = 0x28, + DESC_RATEVHT2SS_MCS3 = 0x29, + DESC_RATEVHT2SS_MCS4 = 0x2a, + DESC_RATEVHT2SS_MCS5 = 0x2b, + DESC_RATEVHT2SS_MCS6 = 0x2c, + DESC_RATEVHT2SS_MCS7 = 0x2d, + DESC_RATEVHT2SS_MCS8 = 0x2e, + DESC_RATEVHT2SS_MCS9 = 0x2f, +}; + +enum rx_packet_type{ + NORMAL_RX, + TX_REPORT1, + TX_REPORT2, + HIS_REPORT, + C2H_PACKET, +}; + +struct phy_sts_cck_8821ae_t { + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +struct h2c_cmd_8821ae { + u8 element_id; + u32 cmd_len; + u8 *p_cmdbuffer; +}; + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/table.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/table.c @@ -0,0 +1,4002 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on 2010/ 5/18, 1:41 + * + * Larry Finger + * + *****************************************************************************/ + +#include "table.h" +u32 RTL8812AE_PHY_REG_ARRAY[] = { + 0x800, 0x8020D010, + 0x804, 0x080112E0, + 0x808, 0x0E028233, + 0x80C, 0x12131113, + 0x810, 0x20101263, + 0x814, 0x020C3D10, + 0x818, 0x03A00385, + 0x820, 0x00000000, + 0x824, 0x00030FE0, + 0x828, 0x00000000, + 0x82C, 0x002083DD, + 0x830, 0x2AAA6C86, + 0x834, 0x0037A706, + 0x838, 0x06C89B44, + 0x83C, 0x0000095B, + 0x840, 0xC0000001, + 0x844, 0x40003CDE, + 0x848, 0x6210FF8B, + 0x84C, 0x6CFDFFB8, + 0x850, 0x28874706, + 0x854, 0x0001520C, + 0x858, 0x8060E000, + 0x85C, 0x74210168, + 0x860, 0x6929C321, + 0x864, 0x79727432, + 0x868, 0x8CA7A314, + 0x86C, 0x338C2878, + 0x870, 0x03333333, + 0x874, 0x31602C2E, + 0x878, 0x00003152, + 0x87C, 0x000FC000, + 0x8A0, 0x00000013, + 0x8A4, 0x7F7F7F7F, + 0x8A8, 0xA202033E, + 0x8AC, 0x0FF0FA0A, + 0x8B0, 0x00000600, + 0x8B4, 0x000FC080, + 0x8B8, 0x6C0057FF, + 0x8BC, 0x4CA520A3, + 0x8C0, 0x27F00020, + 0x8C4, 0x00000000, + 0x8C8, 0x00013169, + 0x8CC, 0x08248492, + 0x8D0, 0x0000B800, + 0x8DC, 0x00000000, + 0x8D4, 0x940008A0, + 0x8D8, 0x290B5612, + 0x8F8, 0x400002C0, + 0x8FC, 0x00000000, + 0xFF0F07D8, 0xABCD, + 0x900, 0x00000700, + 0xFF0F07D0, 0xCDEF, + 0x900, 0x00000700, + 0xCDCDCDCD, 0xCDCD, + 0x900, 0x00000700, + 0xFF0F07D8, 0xDEAD, + 0x90C, 0x00000000, + 0x910, 0x0000FC00, + 0x914, 0x00000404, + 0x918, 0x1C1028C0, + 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, + 0x924, 0x055AA500, + 0x928, 0x00000004, + 0x92C, 0xFFFE0000, + 0x930, 0xFFFFFFFE, + 0x934, 0x001FFFFF, + 0x960, 0x00000000, + 0x964, 0x00000000, + 0x968, 0x00000000, + 0x96C, 0x00000000, + 0x970, 0x801FFFFF, + 0x978, 0x00000000, + 0x97C, 0x00000000, + 0x980, 0x00000000, + 0x984, 0x00000000, + 0x988, 0x00000000, + 0x990, 0x27100000, + 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, + 0x99C, 0xFFFFFFFF, + 0x9A0, 0x000000FF, + 0x9A4, 0x00080080, + 0x9A8, 0x00000000, + 0x9AC, 0x00000000, + 0x9B0, 0x81081008, + 0x9B4, 0x00000000, + 0x9B8, 0x01081008, + 0x9BC, 0x01081008, + 0x9D0, 0x00000000, + 0x9D4, 0x00000000, + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E4, 0x00000002, + 0x9E8, 0x000002D5, + 0xA00, 0x00D047C8, + 0xA04, 0x01FF000C, + 0xA08, 0x8C838300, + 0xA0C, 0x2E7F000F, + 0xA10, 0x9500BB78, + 0xA14, 0x11144028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xA2C, 0x00900000, + 0xA70, 0x101FFF00, + 0xA74, 0x00000008, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x218075B2, + 0xA84, 0x001F8C80, + 0xB00, 0x03100000, + 0xB04, 0x0000B000, + 0xB08, 0xAE0201EB, + 0xB0C, 0x01003207, + 0xB10, 0x00009807, + 0xB14, 0x01000000, + 0xB18, 0x00000002, + 0xB1C, 0x00000002, + 0xB20, 0x0000001F, + 0xB24, 0x03020100, + 0xB28, 0x07060504, + 0xB2C, 0x0B0A0908, + 0xB30, 0x0F0E0D0C, + 0xB34, 0x13121110, + 0xB38, 0x17161514, + 0xB3C, 0x0000003A, + 0xB40, 0x00000000, + 0xB44, 0x00000000, + 0xB48, 0x13000032, + 0xB4C, 0x48080000, + 0xB50, 0x00000000, + 0xB54, 0x00000000, + 0xB58, 0x00000000, + 0xB5C, 0x00000000, + 0xC00, 0x00000007, + 0xC04, 0x00042020, + 0xC08, 0x80410231, + 0xC0C, 0x00000000, + 0xC10, 0x00000100, + 0xC14, 0x01000000, + 0xC1C, 0x40000003, + 0xC20, 0x12121212, + 0xC24, 0x12121212, + 0xC28, 0x12121212, + 0xC2C, 0x12121212, + 0xC30, 0x12121212, + 0xC34, 0x12121212, + 0xC38, 0x12121212, + 0xC3C, 0x12121212, + 0xC40, 0x12121212, + 0xC44, 0x12121212, + 0xC48, 0x12121212, + 0xC4C, 0x12121212, + 0xC50, 0x00000020, + 0xC54, 0x0008121C, + 0xC58, 0x30000C1C, + 0xC5C, 0x00000058, + 0xC60, 0x34344443, + 0xC64, 0x07003333, + 0xC68, 0x59791979, + 0xC6C, 0x59795979, + 0xC70, 0x19795979, + 0xC74, 0x19795979, + 0xC78, 0x19791979, + 0xC7C, 0x19791979, + 0xC80, 0x19791979, + 0xC84, 0x19791979, + 0xC94, 0x0100005C, + 0xC98, 0x00000000, + 0xC9C, 0x00000000, + 0xCA0, 0x00000029, + 0xCA4, 0x08040201, + 0xCA8, 0x80402010, + 0xFF0F0740, 0xABCD, + 0xCB0, 0x77547717, + 0xFF0F01C0, 0xCDEF, + 0xCB0, 0x77547717, + 0xFF0F02C0, 0xCDEF, + 0xCB0, 0x77547717, + 0xFF0F07D8, 0xCDEF, + 0xCB0, 0x54547710, + 0xFF0F07D0, 0xCDEF, + 0xCB0, 0x54547710, + 0xCDCDCDCD, 0xCDCD, + 0xCB0, 0x77547777, + 0xFF0F0740, 0xDEAD, + 0xCB4, 0x00000077, + 0xCB8, 0x00508242, + 0xE00, 0x00000007, + 0xE04, 0x00042020, + 0xE08, 0x80410231, + 0xE0C, 0x00000000, + 0xE10, 0x00000100, + 0xE14, 0x01000000, + 0xE1C, 0x40000003, + 0xE20, 0x12121212, + 0xE24, 0x12121212, + 0xE28, 0x12121212, + 0xE2C, 0x12121212, + 0xE30, 0x12121212, + 0xE34, 0x12121212, + 0xE38, 0x12121212, + 0xE3C, 0x12121212, + 0xE40, 0x12121212, + 0xE44, 0x12121212, + 0xE48, 0x12121212, + 0xE4C, 0x12121212, + 0xE50, 0x00000020, + 0xE54, 0x0008121C, + 0xE58, 0x30000C1C, + 0xE5C, 0x00000058, + 0xE60, 0x34344443, + 0xE64, 0x07003333, + 0xE68, 0x59791979, + 0xE6C, 0x59795979, + 0xE70, 0x19795979, + 0xE74, 0x19795979, + 0xE78, 0x19791979, + 0xE7C, 0x19791979, + 0xE80, 0x19791979, + 0xE84, 0x19791979, + 0xE94, 0x0100005C, + 0xE98, 0x00000000, + 0xE9C, 0x00000000, + 0xEA0, 0x00000029, + 0xEA4, 0x08040201, + 0xEA8, 0x80402010, + 0xFF0F0740, 0xABCD, + 0xEB0, 0x77547717, + 0xFF0F01C0, 0xCDEF, + 0xEB0, 0x77547717, + 0xFF0F02C0, 0xCDEF, + 0xEB0, 0x77547717, + 0xFF0F07D8, 0xCDEF, + 0xEB0, 0x54547710, + 0xFF0F07D0, 0xCDEF, + 0xEB0, 0x54547710, + 0xCDCDCDCD, 0xCDCD, + 0xEB0, 0x77547777, + 0xFF0F0740, 0xDEAD, + 0xEB4, 0x00000077, + 0xEB8, 0x00508242, +}; + +u32 RTL8821AE_PHY_REG_ARRAY[] = { + 0x800, 0x0020D090, + 0x804, 0x080112E0, + 0x808, 0x0E028211, + 0x80C, 0x92131111, + 0x810, 0x20101261, + 0x814, 0x020C3D10, + 0x818, 0x03A00385, + 0x820, 0x00000000, + 0x824, 0x00030FE0, + 0x828, 0x00000000, + 0x82C, 0x002081DD, + 0x830, 0x2AAA8E24, + 0x834, 0x0037A706, + 0x838, 0x06489B44, + 0x83C, 0x0000095B, + 0x840, 0xC0000001, + 0x844, 0x40003CDE, + 0x848, 0x62103F8B, + 0x84C, 0x6CFDFFB8, + 0x850, 0x28874706, + 0x854, 0x0001520C, + 0x858, 0x8060E000, + 0x85C, 0x74210168, + 0x860, 0x6929C321, + 0x864, 0x79727432, + 0x868, 0x8CA7A314, + 0x86C, 0x888C2878, + 0x870, 0x08888888, + 0x874, 0x31612C2E, + 0x878, 0x00000152, + 0x87C, 0x000FD000, + 0x8A0, 0x00000013, + 0x8A4, 0x7F7F7F7F, + 0x8A8, 0xA2000338, + 0x8AC, 0x0FF0FA0A, + 0x8B4, 0x000FC080, + 0x8B8, 0x6C10D7FF, + 0x8BC, 0x0CA52090, + 0x8C0, 0x1BF00020, + 0x8C4, 0x00000000, + 0x8C8, 0x00013169, + 0x8CC, 0x08248492, + 0x8D4, 0x940008A0, + 0x8D8, 0x290B5612, + 0x8F8, 0x400002C0, + 0x8FC, 0x00000000, + 0x900, 0x00000700, + 0x90C, 0x00000000, + 0x910, 0x0000FC00, + 0x914, 0x00000404, + 0x918, 0x1C1028C0, + 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, + 0x924, 0x055AA500, + 0x928, 0x00000004, + 0x92C, 0xFFFE0000, + 0x930, 0xFFFFFFFE, + 0x934, 0x001FFFFF, + 0x960, 0x00000000, + 0x964, 0x00000000, + 0x968, 0x00000000, + 0x96C, 0x00000000, + 0x970, 0x801FFFFF, + 0x974, 0x000003FF, + 0x978, 0x00000000, + 0x97C, 0x00000000, + 0x980, 0x00000000, + 0x984, 0x00000000, + 0x988, 0x00000000, + 0x990, 0x27100000, + 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, + 0x99C, 0xFFFFFFFF, + 0x9A0, 0x000000FF, + 0x9A4, 0x00480080, + 0x9A8, 0x00000000, + 0x9AC, 0x00000000, + 0x9B0, 0x81081008, + 0x9B4, 0x01081008, + 0x9B8, 0x01081008, + 0x9BC, 0x01081008, + 0x9D0, 0x00000000, + 0x9D4, 0x00000000, + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E0, 0x00005D00, + 0x9E4, 0x00000002, + 0x9E8, 0x00000001, + 0xA00, 0x00D047C8, + 0xA04, 0x01FF000C, + 0xA08, 0x8C8A8300, + 0xA0C, 0x2E68000F, + 0xA10, 0x9500BB78, + 0xA14, 0x11144028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xA2C, 0x00900000, + 0xA70, 0x101FFF00, + 0xA74, 0x00000008, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x21805490, + 0xA84, 0x001F0000, + 0xB00, 0x03100040, + 0xB04, 0x0000B000, + 0xB08, 0xAE0201EB, + 0xB0C, 0x01003207, + 0xB10, 0x00009807, + 0xB14, 0x01000000, + 0xB18, 0x00000002, + 0xB1C, 0x00000002, + 0xB20, 0x0000001F, + 0xB24, 0x03020100, + 0xB28, 0x07060504, + 0xB2C, 0x0B0A0908, + 0xB30, 0x0F0E0D0C, + 0xB34, 0x13121110, + 0xB38, 0x17161514, + 0xB3C, 0x0000003A, + 0xB40, 0x00000000, + 0xB44, 0x00000000, + 0xB48, 0x13000032, + 0xB4C, 0x48080000, + 0xB50, 0x00000000, + 0xB54, 0x00000000, + 0xB58, 0x00000000, + 0xB5C, 0x00000000, + 0xC00, 0x00000007, + 0xC04, 0x00042020, + 0xC08, 0x80410231, + 0xC0C, 0x00000000, + 0xC10, 0x00000100, + 0xC14, 0x01000000, + 0xC1C, 0x40000003, + 0xC20, 0x2C2C2C2C, + 0xC24, 0x30303030, + 0xC28, 0x30303030, + 0xC2C, 0x2C2C2C2C, + 0xC30, 0x2C2C2C2C, + 0xC34, 0x2C2C2C2C, + 0xC38, 0x2C2C2C2C, + 0xC3C, 0x2A2A2A2A, + 0xC40, 0x2A2A2A2A, + 0xC44, 0x2A2A2A2A, + 0xC48, 0x2A2A2A2A, + 0xC4C, 0x2A2A2A2A, + 0xC50, 0x00000020, + 0xC54, 0x001C1208, + 0xC58, 0x30000C1C, + 0xC5C, 0x00000058, + 0xC60, 0x34344443, + 0xC64, 0x07003333, + 0xC68, 0x19791979, + 0xC6C, 0x19791979, + 0xC70, 0x19791979, + 0xC74, 0x19791979, + 0xC78, 0x19791979, + 0xC7C, 0x19791979, + 0xC80, 0x19791979, + 0xC84, 0x19791979, + 0xC94, 0x0100005C, + 0xC98, 0x00000000, + 0xC9C, 0x00000000, + 0xCA0, 0x00000029, + 0xCA4, 0x08040201, + 0xCA8, 0x80402010, + 0xCB0, 0x77775747, + 0xCB4, 0x10000077, + 0xCB8, 0x00508240, +}; + +u32 RTL8812AE_PHY_REG_ARRAY_PG[] = { + 0, 0, 0, 0x00000c20, 0xffffffff, 0x34363840, + 0, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, + 0, 0, 0, 0x00000c28, 0xffffffff, 0x30323638, + 0, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, + 0, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, + 0, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, + 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, + 0, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, + 0, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, + 0, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, + 0, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, + 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, + 0, 1, 0, 0x00000e20, 0xffffffff, 0x34363840, + 0, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, + 0, 1, 0, 0x00000e28, 0xffffffff, 0x30323638, + 0, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, + 0, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, + 0, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, + 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, + 0, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, + 0, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, + 0, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, + 0, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, + 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, + 1, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, + 1, 0, 0, 0x00000c28, 0xffffffff, 0x30323640, + 1, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, + 1, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, + 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, + 1, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, + 1, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, + 1, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, + 1, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, + 1, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, + 1, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, + 1, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, + 1, 1, 0, 0x00000e28, 0xffffffff, 0x30323640, + 1, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, + 1, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, + 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, + 1, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, + 1, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, + 1, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, + 1, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, + 1, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, + 1, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628 +}; + +u32 RTL8821AE_PHY_REG_ARRAY_PG[] = { + 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, + 0, 0, 0, 0x00000c24, 0xffffffff, 0x36363838, + 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, + 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363838, + 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, + 0, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, + 0, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, + 0, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022, + 1, 0, 0, 0x00000c24, 0xffffffff, 0x34343636, + 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, + 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343636, + 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, + 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, + 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, + 1, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022 +}; + +/* it seems not used +u8 *RTL8821AE_TXPWR_LMT_ARRAY[] = { + "FCC", "2.4G", "20M", "CCK", "1T", "01", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "01", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "01", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "02", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "02", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "02", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "03", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "03", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "03", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "04", "34", + "ETSI", "2.4G", "20M", "CCK", "1T", "04", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "04", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "05", "34", + "ETSI", "2.4G", "20M", "CCK", "1T", "05", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "05", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "06", "34", + "ETSI", "2.4G", "20M", "CCK", "1T", "06", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "06", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "07", "34", + "ETSI", "2.4G", "20M", "CCK", "1T", "07", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "07", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "08", "34", + "ETSI", "2.4G", "20M", "CCK", "1T", "08", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "08", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "09", "34", + "ETSI", "2.4G", "20M", "CCK", "1T", "09", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "09", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "10", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "10", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "10", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "11", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "11", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "11", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "12", "63", + "ETSI", "2.4G", "20M", "CCK", "1T", "12", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "12", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "13", "63", + "ETSI", "2.4G", "20M", "CCK", "1T", "13", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "13", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "14", "63", + "ETSI", "2.4G", "20M", "CCK", "1T", "14", "63", + "MKK", "2.4G", "20M", "CCK", "1T", "14", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "01", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "01", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "01", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "02", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "02", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "02", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "03", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "03", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "03", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "04", "32", + "ETSI", "2.4G", "20M", "OFDM", "1T", "04", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "04", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "05", "32", + "ETSI", "2.4G", "20M", "OFDM", "1T", "05", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "05", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "06", "32", + "ETSI", "2.4G", "20M", "OFDM", "1T", "06", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "06", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "07", "32", + "ETSI", "2.4G", "20M", "OFDM", "1T", "07", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "07", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "08", "32", + "ETSI", "2.4G", "20M", "OFDM", "1T", "08", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "08", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "09", "32", + "ETSI", "2.4G", "20M", "OFDM", "1T", "09", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "09", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "10", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "10", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "10", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "11", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "11", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "11", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "12", "63", + "ETSI", "2.4G", "20M", "OFDM", "1T", "12", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "12", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "13", "63", + "ETSI", "2.4G", "20M", "OFDM", "1T", "13", "32", + "MKK", "2.4G", "20M", "OFDM", "1T", "13", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "14", "63", + "ETSI", "2.4G", "20M", "OFDM", "1T", "14", "63", + "MKK", "2.4G", "20M", "OFDM", "1T", "14", "63", + "FCC", "2.4G", "20M", "HT", "1T", "01", "26", + "ETSI", "2.4G", "20M", "HT", "1T", "01", "32", + "MKK", "2.4G", "20M", "HT", "1T", "01", "32", + "FCC", "2.4G", "20M", "HT", "1T", "02", "26", + "ETSI", "2.4G", "20M", "HT", "1T", "02", "32", + "MKK", "2.4G", "20M", "HT", "1T", "02", "32", + "FCC", "2.4G", "20M", "HT", "1T", "03", "26", + "ETSI", "2.4G", "20M", "HT", "1T", "03", "32", + "MKK", "2.4G", "20M", "HT", "1T", "03", "32", + "FCC", "2.4G", "20M", "HT", "1T", "04", "32", + "ETSI", "2.4G", "20M", "HT", "1T", "04", "32", + "MKK", "2.4G", "20M", "HT", "1T", "04", "32", + "FCC", "2.4G", "20M", "HT", "1T", "05", "32", + "ETSI", "2.4G", "20M", "HT", "1T", "05", "32", + "MKK", "2.4G", "20M", "HT", "1T", "05", "32", + "FCC", "2.4G", "20M", "HT", "1T", "06", "32", + "ETSI", "2.4G", "20M", "HT", "1T", "06", "32", + "MKK", "2.4G", "20M", "HT", "1T", "06", "32", + "FCC", "2.4G", "20M", "HT", "1T", "07", "32", + "ETSI", "2.4G", "20M", "HT", "1T", "07", "32", + "MKK", "2.4G", "20M", "HT", "1T", "07", "32", + "FCC", "2.4G", "20M", "HT", "1T", "08", "32", + "ETSI", "2.4G", "20M", "HT", "1T", "08", "32", + "MKK", "2.4G", "20M", "HT", "1T", "08", "32", + "FCC", "2.4G", "20M", "HT", "1T", "09", "32", + "ETSI", "2.4G", "20M", "HT", "1T", "09", "32", + "MKK", "2.4G", "20M", "HT", "1T", "09", "32", + "FCC", "2.4G", "20M", "HT", "1T", "10", "26", + "ETSI", "2.4G", "20M", "HT", "1T", "10", "32", + "MKK", "2.4G", "20M", "HT", "1T", "10", "32", + "FCC", "2.4G", "20M", "HT", "1T", "11", "26", + "ETSI", "2.4G", "20M", "HT", "1T", "11", "32", + "MKK", "2.4G", "20M", "HT", "1T", "11", "32", + "FCC", "2.4G", "20M", "HT", "1T", "12", "63", + "ETSI", "2.4G", "20M", "HT", "1T", "12", "32", + "MKK", "2.4G", "20M", "HT", "1T", "12", "32", + "FCC", "2.4G", "20M", "HT", "1T", "13", "63", + "ETSI", "2.4G", "20M", "HT", "1T", "13", "32", + "MKK", "2.4G", "20M", "HT", "1T", "13", "32", + "FCC", "2.4G", "20M", "HT", "1T", "14", "63", + "ETSI", "2.4G", "20M", "HT", "1T", "14", "63", + "MKK", "2.4G", "20M", "HT", "1T", "14", "63", + "FCC", "2.4G", "20M", "HT", "2T", "01", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "01", "32", + "MKK", "2.4G", "20M", "HT", "2T", "01", "32", + "FCC", "2.4G", "20M", "HT", "2T", "02", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "02", "32", + "MKK", "2.4G", "20M", "HT", "2T", "02", "32", + "FCC", "2.4G", "20M", "HT", "2T", "03", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "03", "32", + "MKK", "2.4G", "20M", "HT", "2T", "03", "32", + "FCC", "2.4G", "20M", "HT", "2T", "04", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "04", "32", + "MKK", "2.4G", "20M", "HT", "2T", "04", "32", + "FCC", "2.4G", "20M", "HT", "2T", "05", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "05", "32", + "MKK", "2.4G", "20M", "HT", "2T", "05", "32", + "FCC", "2.4G", "20M", "HT", "2T", "06", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "06", "32", + "MKK", "2.4G", "20M", "HT", "2T", "06", "32", + "FCC", "2.4G", "20M", "HT", "2T", "07", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "07", "32", + "MKK", "2.4G", "20M", "HT", "2T", "07", "32", + "FCC", "2.4G", "20M", "HT", "2T", "08", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "08", "32", + "MKK", "2.4G", "20M", "HT", "2T", "08", "32", + "FCC", "2.4G", "20M", "HT", "2T", "09", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "09", "32", + "MKK", "2.4G", "20M", "HT", "2T", "09", "32", + "FCC", "2.4G", "20M", "HT", "2T", "10", "32", + "ETSI", "2.4G", "20M", "HT", "2T", "10", "32", + "MKK", "2.4G", "20M", "HT", "2T", "10", "32", + "FCC", "2.4G", "20M", "HT", "2T", "11", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "11", "32", + "MKK", "2.4G", "20M", "HT", "2T", "11", "32", + "FCC", "2.4G", "20M", "HT", "2T", "12", "63", + "ETSI", "2.4G", "20M", "HT", "2T", "12", "32", + "MKK", "2.4G", "20M", "HT", "2T", "12", "32", + "FCC", "2.4G", "20M", "HT", "2T", "13", "63", + "ETSI", "2.4G", "20M", "HT", "2T", "13", "32", + "MKK", "2.4G", "20M", "HT", "2T", "13", "32", + "FCC", "2.4G", "20M", "HT", "2T", "14", "63", + "ETSI", "2.4G", "20M", "HT", "2T", "14", "63", + "MKK", "2.4G", "20M", "HT", "2T", "14", "63", + "FCC", "2.4G", "40M", "HT", "1T", "01", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "01", "63", + "MKK", "2.4G", "40M", "HT", "1T", "01", "63", + "FCC", "2.4G", "40M", "HT", "1T", "02", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "02", "63", + "MKK", "2.4G", "40M", "HT", "1T", "02", "63", + "FCC", "2.4G", "40M", "HT", "1T", "03", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "03", "32", + "MKK", "2.4G", "40M", "HT", "1T", "03", "32", + "FCC", "2.4G", "40M", "HT", "1T", "04", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "04", "32", + "MKK", "2.4G", "40M", "HT", "1T", "04", "32", + "FCC", "2.4G", "40M", "HT", "1T", "05", "32", + "ETSI", "2.4G", "40M", "HT", "1T", "05", "32", + "MKK", "2.4G", "40M", "HT", "1T", "05", "32", + "FCC", "2.4G", "40M", "HT", "1T", "06", "32", + "ETSI", "2.4G", "40M", "HT", "1T", "06", "32", + "MKK", "2.4G", "40M", "HT", "1T", "06", "32", + "FCC", "2.4G", "40M", "HT", "1T", "07", "32", + "ETSI", "2.4G", "40M", "HT", "1T", "07", "32", + "MKK", "2.4G", "40M", "HT", "1T", "07", "32", + "FCC", "2.4G", "40M", "HT", "1T", "08", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "08", "32", + "MKK", "2.4G", "40M", "HT", "1T", "08", "32", + "FCC", "2.4G", "40M", "HT", "1T", "09", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "09", "32", + "MKK", "2.4G", "40M", "HT", "1T", "09", "32", + "FCC", "2.4G", "40M", "HT", "1T", "10", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "10", "32", + "MKK", "2.4G", "40M", "HT", "1T", "10", "32", + "FCC", "2.4G", "40M", "HT", "1T", "11", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "11", "32", + "MKK", "2.4G", "40M", "HT", "1T", "11", "32", + "FCC", "2.4G", "40M", "HT", "1T", "12", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "12", "32", + "MKK", "2.4G", "40M", "HT", "1T", "12", "32", + "FCC", "2.4G", "40M", "HT", "1T", "13", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "13", "32", + "MKK", "2.4G", "40M", "HT", "1T", "13", "32", + "FCC", "2.4G", "40M", "HT", "1T", "14", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "14", "63", + "MKK", "2.4G", "40M", "HT", "1T", "14", "63", + "FCC", "2.4G", "40M", "HT", "2T", "01", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "01", "63", + "MKK", "2.4G", "40M", "HT", "2T", "01", "63", + "FCC", "2.4G", "40M", "HT", "2T", "02", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "02", "63", + "MKK", "2.4G", "40M", "HT", "2T", "02", "63", + "FCC", "2.4G", "40M", "HT", "2T", "03", "30", + "ETSI", "2.4G", "40M", "HT", "2T", "03", "30", + "MKK", "2.4G", "40M", "HT", "2T", "03", "30", + "FCC", "2.4G", "40M", "HT", "2T", "04", "32", + "ETSI", "2.4G", "40M", "HT", "2T", "04", "30", + "MKK", "2.4G", "40M", "HT", "2T", "04", "30", + "FCC", "2.4G", "40M", "HT", "2T", "05", "32", + "ETSI", "2.4G", "40M", "HT", "2T", "05", "30", + "MKK", "2.4G", "40M", "HT", "2T", "05", "30", + "FCC", "2.4G", "40M", "HT", "2T", "06", "32", + "ETSI", "2.4G", "40M", "HT", "2T", "06", "30", + "MKK", "2.4G", "40M", "HT", "2T", "06", "30", + "FCC", "2.4G", "40M", "HT", "2T", "07", "32", + "ETSI", "2.4G", "40M", "HT", "2T", "07", "30", + "MKK", "2.4G", "40M", "HT", "2T", "07", "30", + "FCC", "2.4G", "40M", "HT", "2T", "08", "32", + "ETSI", "2.4G", "40M", "HT", "2T", "08", "30", + "MKK", "2.4G", "40M", "HT", "2T", "08", "30", + "FCC", "2.4G", "40M", "HT", "2T", "09", "32", + "ETSI", "2.4G", "40M", "HT", "2T", "09", "30", + "MKK", "2.4G", "40M", "HT", "2T", "09", "30", + "FCC", "2.4G", "40M", "HT", "2T", "10", "32", + "ETSI", "2.4G", "40M", "HT", "2T", "10", "30", + "MKK", "2.4G", "40M", "HT", "2T", "10", "30", + "FCC", "2.4G", "40M", "HT", "2T", "11", "30", + "ETSI", "2.4G", "40M", "HT", "2T", "11", "30", + "MKK", "2.4G", "40M", "HT", "2T", "11", "30", + "FCC", "2.4G", "40M", "HT", "2T", "12", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "12", "32", + "MKK", "2.4G", "40M", "HT", "2T", "12", "32", + "FCC", "2.4G", "40M", "HT", "2T", "13", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "13", "32", + "MKK", "2.4G", "40M", "HT", "2T", "13", "32", + "FCC", "2.4G", "40M", "HT", "2T", "14", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "14", "63", + "MKK", "2.4G", "40M", "HT", "2T", "14", "63", + "FCC", "5G", "20M", "OFDM", "1T", "36", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "36", "30", + "MKK", "5G", "20M", "OFDM", "1T", "36", "30", + "FCC", "5G", "20M", "OFDM", "1T", "40", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "40", "30", + "MKK", "5G", "20M", "OFDM", "1T", "40", "30", + "FCC", "5G", "20M", "OFDM", "1T", "44", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "44", "30", + "MKK", "5G", "20M", "OFDM", "1T", "44", "30", + "FCC", "5G", "20M", "OFDM", "1T", "48", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "48", "30", + "MKK", "5G", "20M", "OFDM", "1T", "48", "30", + "FCC", "5G", "20M", "OFDM", "1T", "52", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "52", "30", + "MKK", "5G", "20M", "OFDM", "1T", "52", "30", + "FCC", "5G", "20M", "OFDM", "1T", "56", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "56", "30", + "MKK", "5G", "20M", "OFDM", "1T", "56", "30", + "FCC", "5G", "20M", "OFDM", "1T", "60", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "60", "30", + "MKK", "5G", "20M", "OFDM", "1T", "60", "30", + "FCC", "5G", "20M", "OFDM", "1T", "64", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "64", "30", + "MKK", "5G", "20M", "OFDM", "1T", "64", "30", + "FCC", "5G", "20M", "OFDM", "1T", "100", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "100", "30", + "MKK", "5G", "20M", "OFDM", "1T", "100", "30", + "FCC", "5G", "20M", "OFDM", "1T", "114", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "114", "30", + "MKK", "5G", "20M", "OFDM", "1T", "114", "30", + "FCC", "5G", "20M", "OFDM", "1T", "108", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "108", "30", + "MKK", "5G", "20M", "OFDM", "1T", "108", "30", + "FCC", "5G", "20M", "OFDM", "1T", "112", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "112", "30", + "MKK", "5G", "20M", "OFDM", "1T", "112", "30", + "FCC", "5G", "20M", "OFDM", "1T", "116", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "116", "30", + "MKK", "5G", "20M", "OFDM", "1T", "116", "30", + "FCC", "5G", "20M", "OFDM", "1T", "120", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "120", "30", + "MKK", "5G", "20M", "OFDM", "1T", "120", "30", + "FCC", "5G", "20M", "OFDM", "1T", "124", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "124", "30", + "MKK", "5G", "20M", "OFDM", "1T", "124", "30", + "FCC", "5G", "20M", "OFDM", "1T", "128", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "128", "30", + "MKK", "5G", "20M", "OFDM", "1T", "128", "30", + "FCC", "5G", "20M", "OFDM", "1T", "132", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "132", "30", + "MKK", "5G", "20M", "OFDM", "1T", "132", "30", + "FCC", "5G", "20M", "OFDM", "1T", "136", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "136", "30", + "MKK", "5G", "20M", "OFDM", "1T", "136", "30", + "FCC", "5G", "20M", "OFDM", "1T", "140", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "140", "30", + "MKK", "5G", "20M", "OFDM", "1T", "140", "30", + "FCC", "5G", "20M", "OFDM", "1T", "149", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "149", "30", + "MKK", "5G", "20M", "OFDM", "1T", "149", "63", + "FCC", "5G", "20M", "OFDM", "1T", "153", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "153", "30", + "MKK", "5G", "20M", "OFDM", "1T", "153", "63", + "FCC", "5G", "20M", "OFDM", "1T", "157", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "157", "30", + "MKK", "5G", "20M", "OFDM", "1T", "157", "63", + "FCC", "5G", "20M", "OFDM", "1T", "161", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "161", "30", + "MKK", "5G", "20M", "OFDM", "1T", "161", "63", + "FCC", "5G", "20M", "OFDM", "1T", "165", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "165", "30", + "MKK", "5G", "20M", "OFDM", "1T", "165", "63", + "FCC", "5G", "20M", "HT", "1T", "36", "30", + "ETSI", "5G", "20M", "HT", "1T", "36", "30", + "MKK", "5G", "20M", "HT", "1T", "36", "30", + "FCC", "5G", "20M", "HT", "1T", "40", "30", + "ETSI", "5G", "20M", "HT", "1T", "40", "30", + "MKK", "5G", "20M", "HT", "1T", "40", "30", + "FCC", "5G", "20M", "HT", "1T", "44", "30", + "ETSI", "5G", "20M", "HT", "1T", "44", "30", + "MKK", "5G", "20M", "HT", "1T", "44", "30", + "FCC", "5G", "20M", "HT", "1T", "48", "30", + "ETSI", "5G", "20M", "HT", "1T", "48", "30", + "MKK", "5G", "20M", "HT", "1T", "48", "30", + "FCC", "5G", "20M", "HT", "1T", "52", "30", + "ETSI", "5G", "20M", "HT", "1T", "52", "30", + "MKK", "5G", "20M", "HT", "1T", "52", "30", + "FCC", "5G", "20M", "HT", "1T", "56", "30", + "ETSI", "5G", "20M", "HT", "1T", "56", "30", + "MKK", "5G", "20M", "HT", "1T", "56", "30", + "FCC", "5G", "20M", "HT", "1T", "60", "30", + "ETSI", "5G", "20M", "HT", "1T", "60", "30", + "MKK", "5G", "20M", "HT", "1T", "60", "30", + "FCC", "5G", "20M", "HT", "1T", "64", "30", + "ETSI", "5G", "20M", "HT", "1T", "64", "30", + "MKK", "5G", "20M", "HT", "1T", "64", "30", + "FCC", "5G", "20M", "HT", "1T", "100", "30", + "ETSI", "5G", "20M", "HT", "1T", "100", "30", + "MKK", "5G", "20M", "HT", "1T", "100", "30", + "FCC", "5G", "20M", "HT", "1T", "114", "30", + "ETSI", "5G", "20M", "HT", "1T", "114", "30", + "MKK", "5G", "20M", "HT", "1T", "114", "30", + "FCC", "5G", "20M", "HT", "1T", "108", "30", + "ETSI", "5G", "20M", "HT", "1T", "108", "30", + "MKK", "5G", "20M", "HT", "1T", "108", "30", + "FCC", "5G", "20M", "HT", "1T", "112", "30", + "ETSI", "5G", "20M", "HT", "1T", "112", "30", + "MKK", "5G", "20M", "HT", "1T", "112", "30", + "FCC", "5G", "20M", "HT", "1T", "116", "30", + "ETSI", "5G", "20M", "HT", "1T", "116", "30", + "MKK", "5G", "20M", "HT", "1T", "116", "30", + "FCC", "5G", "20M", "HT", "1T", "120", "30", + "ETSI", "5G", "20M", "HT", "1T", "120", "30", + "MKK", "5G", "20M", "HT", "1T", "120", "30", + "FCC", "5G", "20M", "HT", "1T", "124", "30", + "ETSI", "5G", "20M", "HT", "1T", "124", "30", + "MKK", "5G", "20M", "HT", "1T", "124", "30", + "FCC", "5G", "20M", "HT", "1T", "128", "30", + "ETSI", "5G", "20M", "HT", "1T", "128", "30", + "MKK", "5G", "20M", "HT", "1T", "128", "30", + "FCC", "5G", "20M", "HT", "1T", "132", "30", + "ETSI", "5G", "20M", "HT", "1T", "132", "30", + "MKK", "5G", "20M", "HT", "1T", "132", "30", + "FCC", "5G", "20M", "HT", "1T", "136", "30", + "ETSI", "5G", "20M", "HT", "1T", "136", "30", + "MKK", "5G", "20M", "HT", "1T", "136", "30", + "FCC", "5G", "20M", "HT", "1T", "140", "30", + "ETSI", "5G", "20M", "HT", "1T", "140", "30", + "MKK", "5G", "20M", "HT", "1T", "140", "30", + "FCC", "5G", "20M", "HT", "1T", "149", "30", + "ETSI", "5G", "20M", "HT", "1T", "149", "30", + "MKK", "5G", "20M", "HT", "1T", "149", "63", + "FCC", "5G", "20M", "HT", "1T", "153", "30", + "ETSI", "5G", "20M", "HT", "1T", "153", "30", + "MKK", "5G", "20M", "HT", "1T", "153", "63", + "FCC", "5G", "20M", "HT", "1T", "157", "30", + "ETSI", "5G", "20M", "HT", "1T", "157", "30", + "MKK", "5G", "20M", "HT", "1T", "157", "63", + "FCC", "5G", "20M", "HT", "1T", "161", "30", + "ETSI", "5G", "20M", "HT", "1T", "161", "30", + "MKK", "5G", "20M", "HT", "1T", "161", "63", + "FCC", "5G", "20M", "HT", "1T", "165", "30", + "ETSI", "5G", "20M", "HT", "1T", "165", "30", + "MKK", "5G", "20M", "HT", "1T", "165", "63", + "FCC", "5G", "20M", "HT", "2T", "36", "28", + "ETSI", "5G", "20M", "HT", "2T", "36", "30", + "MKK", "5G", "20M", "HT", "2T", "36", "30", + "FCC", "5G", "20M", "HT", "2T", "40", "28", + "ETSI", "5G", "20M", "HT", "2T", "40", "30", + "MKK", "5G", "20M", "HT", "2T", "40", "30", + "FCC", "5G", "20M", "HT", "2T", "44", "28", + "ETSI", "5G", "20M", "HT", "2T", "44", "30", + "MKK", "5G", "20M", "HT", "2T", "44", "30", + "FCC", "5G", "20M", "HT", "2T", "48", "28", + "ETSI", "5G", "20M", "HT", "2T", "48", "30", + "MKK", "5G", "20M", "HT", "2T", "48", "30", + "FCC", "5G", "20M", "HT", "2T", "52", "34", + "ETSI", "5G", "20M", "HT", "2T", "52", "30", + "MKK", "5G", "20M", "HT", "2T", "52", "30", + "FCC", "5G", "20M", "HT", "2T", "56", "32", + "ETSI", "5G", "20M", "HT", "2T", "56", "30", + "MKK", "5G", "20M", "HT", "2T", "56", "30", + "FCC", "5G", "20M", "HT", "2T", "60", "30", + "ETSI", "5G", "20M", "HT", "2T", "60", "30", + "MKK", "5G", "20M", "HT", "2T", "60", "30", + "FCC", "5G", "20M", "HT", "2T", "64", "26", + "ETSI", "5G", "20M", "HT", "2T", "64", "30", + "MKK", "5G", "20M", "HT", "2T", "64", "30", + "FCC", "5G", "20M", "HT", "2T", "100", "28", + "ETSI", "5G", "20M", "HT", "2T", "100", "30", + "MKK", "5G", "20M", "HT", "2T", "100", "30", + "FCC", "5G", "20M", "HT", "2T", "114", "28", + "ETSI", "5G", "20M", "HT", "2T", "114", "30", + "MKK", "5G", "20M", "HT", "2T", "114", "30", + "FCC", "5G", "20M", "HT", "2T", "108", "30", + "ETSI", "5G", "20M", "HT", "2T", "108", "30", + "MKK", "5G", "20M", "HT", "2T", "108", "30", + "FCC", "5G", "20M", "HT", "2T", "112", "32", + "ETSI", "5G", "20M", "HT", "2T", "112", "30", + "MKK", "5G", "20M", "HT", "2T", "112", "30", + "FCC", "5G", "20M", "HT", "2T", "116", "32", + "ETSI", "5G", "20M", "HT", "2T", "116", "30", + "MKK", "5G", "20M", "HT", "2T", "116", "30", + "FCC", "5G", "20M", "HT", "2T", "120", "34", + "ETSI", "5G", "20M", "HT", "2T", "120", "30", + "MKK", "5G", "20M", "HT", "2T", "120", "30", + "FCC", "5G", "20M", "HT", "2T", "124", "32", + "ETSI", "5G", "20M", "HT", "2T", "124", "30", + "MKK", "5G", "20M", "HT", "2T", "124", "30", + "FCC", "5G", "20M", "HT", "2T", "128", "30", + "ETSI", "5G", "20M", "HT", "2T", "128", "30", + "MKK", "5G", "20M", "HT", "2T", "128", "30", + "FCC", "5G", "20M", "HT", "2T", "132", "28", + "ETSI", "5G", "20M", "HT", "2T", "132", "30", + "MKK", "5G", "20M", "HT", "2T", "132", "30", + "FCC", "5G", "20M", "HT", "2T", "136", "28", + "ETSI", "5G", "20M", "HT", "2T", "136", "30", + "MKK", "5G", "20M", "HT", "2T", "136", "30", + "FCC", "5G", "20M", "HT", "2T", "140", "26", + "ETSI", "5G", "20M", "HT", "2T", "140", "30", + "MKK", "5G", "20M", "HT", "2T", "140", "30", + "FCC", "5G", "20M", "HT", "2T", "149", "34", + "ETSI", "5G", "20M", "HT", "2T", "149", "30", + "MKK", "5G", "20M", "HT", "2T", "149", "63", + "FCC", "5G", "20M", "HT", "2T", "153", "34", + "ETSI", "5G", "20M", "HT", "2T", "153", "30", + "MKK", "5G", "20M", "HT", "2T", "153", "63", + "FCC", "5G", "20M", "HT", "2T", "157", "34", + "ETSI", "5G", "20M", "HT", "2T", "157", "30", + "MKK", "5G", "20M", "HT", "2T", "157", "63", + "FCC", "5G", "20M", "HT", "2T", "161", "34", + "ETSI", "5G", "20M", "HT", "2T", "161", "30", + "MKK", "5G", "20M", "HT", "2T", "161", "63", + "FCC", "5G", "20M", "HT", "2T", "165", "34", + "ETSI", "5G", "20M", "HT", "2T", "165", "30", + "MKK", "5G", "20M", "HT", "2T", "165", "63", + "FCC", "5G", "40M", "HT", "1T", "38", "26", + "ETSI", "5G", "40M", "HT", "1T", "38", "30", + "MKK", "5G", "40M", "HT", "1T", "38", "30", + "FCC", "5G", "40M", "HT", "1T", "46", "30", + "ETSI", "5G", "40M", "HT", "1T", "46", "30", + "MKK", "5G", "40M", "HT", "1T", "46", "30", + "FCC", "5G", "40M", "HT", "1T", "54", "30", + "ETSI", "5G", "40M", "HT", "1T", "54", "30", + "MKK", "5G", "40M", "HT", "1T", "54", "30", + "FCC", "5G", "40M", "HT", "1T", "62", "26", + "ETSI", "5G", "40M", "HT", "1T", "62", "30", + "MKK", "5G", "40M", "HT", "1T", "62", "30", + "FCC", "5G", "40M", "HT", "1T", "102", "24", + "ETSI", "5G", "40M", "HT", "1T", "102", "30", + "MKK", "5G", "40M", "HT", "1T", "102", "30", + "FCC", "5G", "40M", "HT", "1T", "110", "30", + "ETSI", "5G", "40M", "HT", "1T", "110", "30", + "MKK", "5G", "40M", "HT", "1T", "110", "30", + "FCC", "5G", "40M", "HT", "1T", "118", "30", + "ETSI", "5G", "40M", "HT", "1T", "118", "30", + "MKK", "5G", "40M", "HT", "1T", "118", "30", + "FCC", "5G", "40M", "HT", "1T", "126", "30", + "ETSI", "5G", "40M", "HT", "1T", "126", "30", + "MKK", "5G", "40M", "HT", "1T", "126", "30", + "FCC", "5G", "40M", "HT", "1T", "134", "30", + "ETSI", "5G", "40M", "HT", "1T", "134", "30", + "MKK", "5G", "40M", "HT", "1T", "134", "30", + "FCC", "5G", "40M", "HT", "1T", "151", "30", + "ETSI", "5G", "40M", "HT", "1T", "151", "30", + "MKK", "5G", "40M", "HT", "1T", "151", "63", + "FCC", "5G", "40M", "HT", "1T", "159", "30", + "ETSI", "5G", "40M", "HT", "1T", "159", "30", + "MKK", "5G", "40M", "HT", "1T", "159", "63", + "FCC", "5G", "40M", "HT", "2T", "38", "28", + "ETSI", "5G", "40M", "HT", "2T", "38", "30", + "MKK", "5G", "40M", "HT", "2T", "38", "30", + "FCC", "5G", "40M", "HT", "2T", "46", "28", + "ETSI", "5G", "40M", "HT", "2T", "46", "30", + "MKK", "5G", "40M", "HT", "2T", "46", "30", + "FCC", "5G", "40M", "HT", "2T", "54", "30", + "ETSI", "5G", "40M", "HT", "2T", "54", "30", + "MKK", "5G", "40M", "HT", "2T", "54", "30", + "FCC", "5G", "40M", "HT", "2T", "62", "30", + "ETSI", "5G", "40M", "HT", "2T", "62", "30", + "MKK", "5G", "40M", "HT", "2T", "62", "30", + "FCC", "5G", "40M", "HT", "2T", "102", "26", + "ETSI", "5G", "40M", "HT", "2T", "102", "30", + "MKK", "5G", "40M", "HT", "2T", "102", "30", + "FCC", "5G", "40M", "HT", "2T", "110", "30", + "ETSI", "5G", "40M", "HT", "2T", "110", "30", + "MKK", "5G", "40M", "HT", "2T", "110", "30", + "FCC", "5G", "40M", "HT", "2T", "118", "34", + "ETSI", "5G", "40M", "HT", "2T", "118", "30", + "MKK", "5G", "40M", "HT", "2T", "118", "30", + "FCC", "5G", "40M", "HT", "2T", "126", "32", + "ETSI", "5G", "40M", "HT", "2T", "126", "30", + "MKK", "5G", "40M", "HT", "2T", "126", "30", + "FCC", "5G", "40M", "HT", "2T", "134", "30", + "ETSI", "5G", "40M", "HT", "2T", "134", "30", + "MKK", "5G", "40M", "HT", "2T", "134", "30", + "FCC", "5G", "40M", "HT", "2T", "151", "34", + "ETSI", "5G", "40M", "HT", "2T", "151", "30", + "MKK", "5G", "40M", "HT", "2T", "151", "63", + "FCC", "5G", "40M", "HT", "2T", "159", "34", + "ETSI", "5G", "40M", "HT", "2T", "159", "30", + "MKK", "5G", "40M", "HT", "2T", "159", "63", + "FCC", "5G", "80M", "VHT", "1T", "42", "22", + "ETSI", "5G", "80M", "VHT", "1T", "42", "30", + "MKK", "5G", "80M", "VHT", "1T", "42", "30", + "FCC", "5G", "80M", "VHT", "1T", "58", "20", + "ETSI", "5G", "80M", "VHT", "1T", "58", "30", + "MKK", "5G", "80M", "VHT", "1T", "58", "30", + "FCC", "5G", "80M", "VHT", "1T", "106", "20", + "ETSI", "5G", "80M", "VHT", "1T", "106", "30", + "MKK", "5G", "80M", "VHT", "1T", "106", "30", + "FCC", "5G", "80M", "VHT", "1T", "122", "28", + "ETSI", "5G", "80M", "VHT", "1T", "122", "30", + "MKK", "5G", "80M", "VHT", "1T", "122", "30", + "FCC", "5G", "80M", "VHT", "1T", "155", "30", + "ETSI", "5G", "80M", "VHT", "1T", "155", "30", + "MKK", "5G", "80M", "VHT", "1T", "155", "63", + "FCC", "5G", "80M", "VHT", "2T", "42", "28", + "ETSI", "5G", "80M", "VHT", "2T", "42", "30", + "MKK", "5G", "80M", "VHT", "2T", "42", "30", + "FCC", "5G", "80M", "VHT", "2T", "58", "26", + "ETSI", "5G", "80M", "VHT", "2T", "58", "30", + "MKK", "5G", "80M", "VHT", "2T", "58", "30", + "FCC", "5G", "80M", "VHT", "2T", "106", "28", + "ETSI", "5G", "80M", "VHT", "2T", "106", "30", + "MKK", "5G", "80M", "VHT", "2T", "106", "30", + "FCC", "5G", "80M", "VHT", "2T", "122", "32", + "ETSI", "5G", "80M", "VHT", "2T", "122", "30", + "MKK", "5G", "80M", "VHT", "2T", "122", "30", + "FCC", "5G", "80M", "VHT", "2T", "155", "34", + "ETSI", "5G", "80M", "VHT", "2T", "155", "30", + "MKK", "5G", "80M", "VHT", "2T", "155", "63" +};*/ + +u32 RTL8812AE_RADIOA_ARRAY[] = { + 0x000, 0x00010000, + 0x018, 0x0001712A, + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x01E, 0x00080000, + 0x089, 0x00000080, + 0xFF0F0740, 0xABCD, + 0x086, 0x00014B38, + 0xFF0F02C0, 0xCDEF, + 0x086, 0x00014B38, + 0xFF0F01C0, 0xCDEF, + 0x086, 0x00014B38, + 0xFF0F07D8, 0xCDEF, + 0x086, 0x00014B3A, + 0xFF0F07D0, 0xCDEF, + 0x086, 0x00014B3A, + 0xCDCDCDCD, 0xCDCD, + 0x086, 0x00014B38, + 0xFF0F0740, 0xDEAD, + 0x0B1, 0x0001FC1A, + 0x0B3, 0x000F0810, + 0x0B4, 0x0001A78D, + 0x0BA, 0x00086180, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0xFF0F07D8, 0xABCD, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xFF0F07D0, 0xCDEF, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xCDCDCDCD, 0xCDCD, + 0x03B, 0x00038A58, + 0x03B, 0x00037A58, + 0x03B, 0x0002A590, + 0x03B, 0x00027A50, + 0x03B, 0x00018248, + 0x03B, 0x00010240, + 0x03B, 0x00008240, + 0xFF0F07D8, 0xDEAD, + 0x0EF, 0x00000100, + 0xFF0F07D8, 0xABCD, + 0x034, 0x0000A4EE, + 0x034, 0x00009076, + 0x034, 0x00008073, + 0x034, 0x00007070, + 0x034, 0x0000606D, + 0x034, 0x0000506A, + 0x034, 0x00004049, + 0x034, 0x00003046, + 0x034, 0x00002028, + 0x034, 0x00001025, + 0x034, 0x00000022, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0000ADF4, + 0x034, 0x00009DF1, + 0x034, 0x00008DEE, + 0x034, 0x00007DEB, + 0x034, 0x00006DE8, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000034EA, + 0x034, 0x000024E7, + 0x034, 0x0000146B, + 0x034, 0x0000006D, + 0xFF0F07D8, 0xDEAD, + 0x0EF, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000192, + 0x035, 0x00008192, + 0x035, 0x00010192, + 0x036, 0x00000024, + 0x036, 0x00008024, + 0x036, 0x00010024, + 0x036, 0x00018024, + 0x0EF, 0x00000000, + 0x051, 0x00000C21, + 0x052, 0x000006D9, + 0x053, 0x000FC649, + 0x054, 0x0000017E, + 0x0EF, 0x00000002, + 0x008, 0x00008400, + 0x018, 0x0001712A, + 0x0EF, 0x00001000, + 0x03A, 0x00000080, + 0x03B, 0x0003A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0003202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0002B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00023070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0001B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00012085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0000A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00002080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x0007A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0007202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0006B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00023070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0005B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00052085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0004A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00042080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x000BA02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x000B202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x000AB064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x000A3070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0009B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00092085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0008A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00082080, + 0x03C, 0x00010000, + 0x0EF, 0x00001100, + 0xFF0F0740, 0xABCD, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F01C0, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F07D8, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F07D0, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045DC9, + 0x034, 0x00044CE8, + 0x034, 0x000438CA, + 0x034, 0x00042889, + 0x034, 0x0004184A, + 0x034, 0x0004044A, + 0xFF0F0740, 0xDEAD, + 0xFF0F0740, 0xABCD, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F01C0, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F07D8, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F07D0, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0002ADF5, + 0x034, 0x00029DF2, + 0x034, 0x00028DEF, + 0x034, 0x00027DEC, + 0x034, 0x00026DE9, + 0x034, 0x00025DC9, + 0x034, 0x00024CE8, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x0002184A, + 0x034, 0x0002044A, + 0xFF0F0740, 0xDEAD, + 0xFF0F0740, 0xABCD, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F01C0, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F07D8, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F07D0, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0000AFF7, + 0x034, 0x00009DF7, + 0x034, 0x00008DF4, + 0x034, 0x00007DF1, + 0x034, 0x00006DEE, + 0x034, 0x00005DCD, + 0x034, 0x00004CEB, + 0x034, 0x000038CC, + 0x034, 0x0000288B, + 0x034, 0x0000184C, + 0x034, 0x0000044C, + 0xFF0F0740, 0xDEAD, + 0x0EF, 0x00000000, + 0xFF0F0740, 0xABCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0xFF0F02C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0xFF0F01C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0xFF0F07D8, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0xFF0F07D0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0xCDCDCDCD, 0xCDCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x00000188, + 0x035, 0x00008147, + 0x035, 0x00010147, + 0x035, 0x000201D7, + 0x035, 0x000281D7, + 0x035, 0x000301D7, + 0x035, 0x000401D8, + 0x035, 0x000481D8, + 0x035, 0x000501D8, + 0xFF0F0740, 0xDEAD, + 0x0EF, 0x00000000, + 0xFF0F0740, 0xABCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0xFF0F02C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0xFF0F01C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0xFF0F07D8, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0xFF0F07D0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0xCDCDCDCD, 0xCDCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00084EB4, + 0x036, 0x0008CC35, + 0x036, 0x00094C35, + 0x036, 0x0009CC35, + 0x036, 0x000A4935, + 0x036, 0x000ACC35, + 0x036, 0x000B4C35, + 0x036, 0x000BCC35, + 0x036, 0x000C4EB4, + 0x036, 0x000CCEB5, + 0x036, 0x000D4EB5, + 0x036, 0x000DCEB5, + 0xFF0F0740, 0xDEAD, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0xFF0F0740, 0xABCD, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0xFF0F02C0, 0xCDEF, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0xFF0F01C0, 0xCDEF, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0xFF0F07D8, 0xCDEF, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0xFF0F07D0, 0xCDEF, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0xCDCDCDCD, 0xCDCD, + 0x03C, 0x000002A8, + 0x03C, 0x000005A2, + 0x03C, 0x00000880, + 0xFF0F0740, 0xDEAD, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x0DF, 0x00000080, + 0x01F, 0x00040064, + 0xFF0F0740, 0xABCD, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D1, + 0xFF0F02C0, 0xCDEF, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D1, + 0xFF0F01C0, 0xCDEF, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D1, + 0xFF0F07D8, 0xCDEF, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D1, + 0xFF0F07D0, 0xCDEF, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D1, + 0xCDCDCDCD, 0xCDCD, + 0x061, 0x000E5D53, + 0x062, 0x00038FCD, + 0x063, 0x000314EB, + 0x064, 0x000196AC, + 0x065, 0x000911D7, + 0xFF0F0740, 0xDEAD, + 0x008, 0x00008400, + 0x01C, 0x000739D2, + 0x0B4, 0x0001E78D, + 0x018, 0x0001F12A, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x0B4, 0x0001A78D, + 0x018, 0x0001712A, +}; + +u32 RTL8812AE_RADIOB_ARRAY[] = { + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x089, 0x00000080, + 0xFF0F0740, 0xABCD, + 0x086, 0x00014B38, + 0xFF0F01C0, 0xCDEF, + 0x086, 0x00014B38, + 0xFF0F02C0, 0xCDEF, + 0x086, 0x00014B38, + 0xFF0F07D8, 0xCDEF, + 0x086, 0x00014B3A, + 0xFF0F07D0, 0xCDEF, + 0x086, 0x00014B3A, + 0xCDCDCDCD, 0xCDCD, + 0x086, 0x00014B38, + 0xFF0F0740, 0xDEAD, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0xFF0F07D8, 0xABCD, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xFF0F07D0, 0xCDEF, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xCDCDCDCD, 0xCDCD, + 0x03B, 0x00038A58, + 0x03B, 0x00037A58, + 0x03B, 0x0002A590, + 0x03B, 0x00027A50, + 0x03B, 0x00018248, + 0x03B, 0x00010240, + 0x03B, 0x00008240, + 0xFF0F07D8, 0xDEAD, + 0x0EF, 0x00000100, + 0xFF0F07D8, 0xABCD, + 0x034, 0x0000A4EE, + 0x034, 0x00009076, + 0x034, 0x00008073, + 0x034, 0x00007070, + 0x034, 0x0000606D, + 0x034, 0x0000506A, + 0x034, 0x00004049, + 0x034, 0x00003046, + 0x034, 0x00002028, + 0x034, 0x00001025, + 0x034, 0x00000022, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0000ADF4, + 0x034, 0x00009DF1, + 0x034, 0x00008DEE, + 0x034, 0x00007DEB, + 0x034, 0x00006DE8, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000034EA, + 0x034, 0x000024E7, + 0x034, 0x0000146B, + 0x034, 0x0000006D, + 0xFF0F07D8, 0xDEAD, + 0x0EF, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000192, + 0x035, 0x00008192, + 0x035, 0x00010192, + 0x036, 0x00000024, + 0x036, 0x00008024, + 0x036, 0x00010024, + 0x036, 0x00018024, + 0x0EF, 0x00000000, + 0x051, 0x00000C21, + 0x052, 0x000006D9, + 0x053, 0x000FC649, + 0x054, 0x0000017E, + 0x0EF, 0x00000002, + 0x008, 0x00008400, + 0x018, 0x0001712A, + 0x0EF, 0x00001000, + 0x03A, 0x00000080, + 0x03B, 0x0003A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0003202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0002B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00023070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0001B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00012085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0000A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00002080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x0007A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0007202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0006B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00063070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0005B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00052085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0004A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00042080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x000BA02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x000B202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x000AB064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x000A3070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0009B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00092085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0008A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00082080, + 0x03C, 0x00010000, + 0x0EF, 0x00001100, + 0xFF0F0740, 0xABCD, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F01C0, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F07D8, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xFF0F07D0, 0xCDEF, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045DC9, + 0x034, 0x00044CE8, + 0x034, 0x000438CA, + 0x034, 0x00042889, + 0x034, 0x0004184A, + 0x034, 0x0004044A, + 0xFF0F0740, 0xDEAD, + 0xFF0F0740, 0xABCD, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F01C0, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F07D8, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xFF0F07D0, 0xCDEF, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0002ADF5, + 0x034, 0x00029DF2, + 0x034, 0x00028DEF, + 0x034, 0x00027DEC, + 0x034, 0x00026DE9, + 0x034, 0x00025DC9, + 0x034, 0x00024CE8, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x0002184A, + 0x034, 0x0002044A, + 0xFF0F0740, 0xDEAD, + 0xFF0F0740, 0xABCD, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F01C0, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F07D8, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xFF0F07D0, 0xCDEF, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0000AFF7, + 0x034, 0x00009DF7, + 0x034, 0x00008DF4, + 0x034, 0x00007DF1, + 0x034, 0x00006DEE, + 0x034, 0x00005DCD, + 0x034, 0x00004CEB, + 0x034, 0x000038CC, + 0x034, 0x0000288B, + 0x034, 0x0000184C, + 0x034, 0x0000044C, + 0xFF0F0740, 0xDEAD, + 0x0EF, 0x00000000, + 0xFF0F0740, 0xABCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0xFF0F01C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0xFF0F02C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0xFF0F07D8, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0xFF0F07D0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0xCDCDCDCD, 0xCDCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x00000186, + 0x035, 0x00008186, + 0x035, 0x00010185, + 0x035, 0x000201D5, + 0x035, 0x000281D5, + 0x035, 0x000301D5, + 0x035, 0x000401D5, + 0x035, 0x000481D5, + 0x035, 0x000501D5, + 0x0EF, 0x00000000, + 0xFF0F0740, 0xDEAD, + 0xFF0F0740, 0xABCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0xFF0F01C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0xFF0F02C0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0xFF0F07D8, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0xFF0F07D0, 0xCDEF, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0xCDCDCDCD, 0xCDCD, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00084EB4, + 0x036, 0x0008C9B4, + 0x036, 0x000949B4, + 0x036, 0x0009C9B4, + 0x036, 0x000A4935, + 0x036, 0x000AC935, + 0x036, 0x000B4935, + 0x036, 0x000BC935, + 0x036, 0x000C4EB4, + 0x036, 0x000CCEB4, + 0x036, 0x000D4EB4, + 0x036, 0x000DCEB4, + 0xFF0F0740, 0xDEAD, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0xFF0F0740, 0xABCD, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0xFF0F01C0, 0xCDEF, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0xFF0F02C0, 0xCDEF, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0xFF0F07D8, 0xCDEF, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0xFF0F07D0, 0xCDEF, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0xCDCDCDCD, 0xCDCD, + 0x03C, 0x000002AA, + 0x03C, 0x000005A2, + 0x03C, 0x00000880, + 0xFF0F0740, 0xDEAD, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x0DF, 0x00000080, + 0xFF0F0740, 0xABCD, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0xFF0F01C0, 0xCDEF, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0xFF0F02C0, 0xCDEF, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0xFF0F07D8, 0xCDEF, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0xFF0F07D0, 0xCDEF, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0xCDCDCDCD, 0xCDCD, + 0x061, 0x000E5D53, + 0x062, 0x00038FCD, + 0x063, 0x000314EB, + 0x064, 0x000196AC, + 0x065, 0x000931D7, + 0xFF0F0740, 0xDEAD, + 0x008, 0x00008400, +}; + +u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x018, 0x0001712A, + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x000, 0x00010000, + 0x01E, 0x00080000, + 0x082, 0x00000830, + 0x083, 0x00021800, + 0x084, 0x00028000, + 0x085, 0x00048000, + 0x086, 0x00094838, + 0x087, 0x00044980, + 0x088, 0x00048000, + 0x089, 0x0000D480, + 0x08A, 0x00042240, + 0x08B, 0x000F0380, + 0x08C, 0x00090000, + 0x08D, 0x00022852, + 0x08E, 0x00065540, + 0x08F, 0x00088001, + 0x0EF, 0x00020000, + 0x03E, 0x00000380, + 0x03F, 0x00090018, + 0x03E, 0x00020380, + 0x03F, 0x000A0018, + 0x03E, 0x00040308, + 0x03F, 0x000A0018, + 0x03E, 0x00060018, + 0x03F, 0x000A0018, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x089, 0x00000080, + 0x08B, 0x00080180, + 0x0EF, 0x00001000, + 0x03A, 0x00000244, + 0x03B, 0x00038027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x00030113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x00028027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x00027027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0001F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00017F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00008027, + 0x03C, 0x000CA000, + 0x03A, 0x00000244, + 0x03B, 0x00078027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x00070113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x00068027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x00067027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0005F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00057F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00048027, + 0x03C, 0x000CA000, + 0x03A, 0x00000244, + 0x03B, 0x000B8027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x000B0113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x000A8027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x000A7027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0009F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00097F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00088027, + 0x03C, 0x000CA000, + 0x0EF, 0x00000000, + 0x0EF, 0x00001100, + 0xFF0F0104, 0xABCD, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0xFF0F0204, 0xCDEF, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0xFF0F0404, 0xCDEF, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0xFF0F0200, 0xCDEF, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0004A0F3, + 0x034, 0x000490B1, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0004ADF7, + 0x034, 0x00049DF3, + 0xFF0F0104, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0xFF0F0204, 0xCDEF, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0xFF0F0404, 0xCDEF, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x000480AE, + 0x034, 0x000470AB, + 0x034, 0x0004608B, + 0x034, 0x00045069, + 0x034, 0x00044048, + 0x034, 0x00043045, + 0x034, 0x00042026, + 0x034, 0x00041023, + 0x034, 0x00040002, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045CCB, + 0x034, 0x0004488D, + 0x034, 0x0004348D, + 0x034, 0x0004248A, + 0x034, 0x0004108D, + 0x034, 0x0004008A, + 0xFF0F0104, 0xDEAD, + 0xFF0F0200, 0xABCD, + 0x034, 0x0002ADF4, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0002A0F3, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0002ADF7, + 0xFF0F0200, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x034, 0x00029DF4, + 0xFF0F0204, 0xCDEF, + 0x034, 0x00029DF4, + 0xFF0F0404, 0xCDEF, + 0x034, 0x00029DF4, + 0xFF0F0200, 0xCDEF, + 0x034, 0x00029DF1, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x000290F0, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x00029DF2, + 0xFF0F0104, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0xFF0F0204, 0xCDEF, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0xFF0F0404, 0xCDEF, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x000280AF, + 0x034, 0x000270AC, + 0x034, 0x0002608B, + 0x034, 0x00025069, + 0x034, 0x00024048, + 0x034, 0x00023045, + 0x034, 0x00022026, + 0x034, 0x00021023, + 0x034, 0x00020002, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x00028DEE, + 0x034, 0x00027DEB, + 0x034, 0x00026CCD, + 0x034, 0x00025CCA, + 0x034, 0x0002488C, + 0x034, 0x0002384C, + 0x034, 0x00022849, + 0x034, 0x00021449, + 0x034, 0x0002004D, + 0xFF0F0104, 0xDEAD, + 0xFF0F02C0, 0xABCD, + 0x034, 0x0000A0D7, + 0x034, 0x000090D3, + 0x034, 0x000080B1, + 0x034, 0x000070AE, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0000ADF7, + 0x034, 0x00009DF4, + 0x034, 0x00008DF1, + 0x034, 0x00007DEE, + 0xFF0F02C0, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0xFF0F0204, 0xCDEF, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0xFF0F0404, 0xCDEF, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0xFF0F02C0, 0xCDEF, + 0x034, 0x0000608D, + 0x034, 0x0000506B, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x00002044, + 0x034, 0x00001025, + 0x034, 0x00000004, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x00006DCD, + 0x034, 0x00005CCD, + 0x034, 0x00004CCA, + 0x034, 0x0000388C, + 0x034, 0x00002888, + 0x034, 0x00001488, + 0x034, 0x00000486, + 0xFF0F0104, 0xDEAD, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0xFF0F0104, 0xABCD, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0xFF0F0204, 0xCDEF, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0xFF0F0404, 0xCDEF, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0xCDCDCDCD, 0xCDCD, + 0x035, 0x00000145, + 0x035, 0x00008145, + 0x035, 0x00010145, + 0x035, 0x00020196, + 0x035, 0x00028196, + 0x035, 0x00030196, + 0x035, 0x000401C7, + 0x035, 0x000481C7, + 0x035, 0x000501C7, + 0xFF0F0104, 0xDEAD, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0xFF0F0104, 0xABCD, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0xFF0F0204, 0xCDEF, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0xFF0F0404, 0xCDEF, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0xCDCDCDCD, 0xCDCD, + 0x036, 0x000056B3, + 0x036, 0x0000D6B3, + 0x036, 0x000156B3, + 0x036, 0x0001D6B3, + 0x036, 0x00026634, + 0x036, 0x0002E634, + 0x036, 0x00036634, + 0x036, 0x0003E634, + 0x036, 0x000467B4, + 0x036, 0x0004E7B4, + 0x036, 0x000567B4, + 0x036, 0x0005E7B4, + 0xFF0F0104, 0xDEAD, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0xFF0F0104, 0xABCD, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0xFF0F0204, 0xCDEF, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0xFF0F0404, 0xCDEF, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0xCDCDCDCD, 0xCDCD, + 0x03C, 0x0000022A, + 0x03C, 0x00000594, + 0xFF0F0104, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x03C, 0x00000800, + 0xFF0F0204, 0xCDEF, + 0x03C, 0x00000800, + 0xFF0F0404, 0xCDEF, + 0x03C, 0x00000800, + 0xFF0F02C0, 0xCDEF, + 0x03C, 0x00000820, + 0xCDCDCDCD, 0xCDCD, + 0x03C, 0x00000900, + 0xFF0F0104, 0xDEAD, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0xFF0F0104, 0xABCD, + 0x008, 0x0004E400, + 0xFF0F0204, 0xCDEF, + 0x008, 0x0004E400, + 0xFF0F0404, 0xCDEF, + 0x008, 0x0004E400, + 0xCDCDCDCD, 0xCDCD, + 0x008, 0x00002000, + 0xFF0F0104, 0xDEAD, + 0x0EF, 0x00000000, + 0x0DF, 0x000000C0, + 0x01F, 0x00040064, + 0xFF0F0104, 0xABCD, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0xFF0F0204, 0xCDEF, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0xFF0F0404, 0xCDEF, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0xCDCDCDCD, 0xCDCD, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0xFF0F0104, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0xFF0F0204, 0xCDEF, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0xFF0F0404, 0xCDEF, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0xCDCDCDCD, 0xCDCD, + 0x061, 0x000EAD53, + 0x062, 0x00093BC4, + 0xFF0F0104, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x063, 0x000110E9, + 0xFF0F0204, 0xCDEF, + 0x063, 0x000110E9, + 0xFF0F0404, 0xCDEF, + 0x063, 0x000110E9, + 0xFF0F0200, 0xCDEF, + 0x063, 0x000710E9, + 0xFF0F02C0, 0xCDEF, + 0x063, 0x000110E9, + 0xCDCDCDCD, 0xCDCD, + 0x063, 0x000714E9, + 0xFF0F0104, 0xDEAD, + 0xFF0F0104, 0xABCD, + 0x064, 0x0001C27C, + 0xFF0F0204, 0xCDEF, + 0x064, 0x0001C27C, + 0xFF0F0404, 0xCDEF, + 0x064, 0x0001C27C, + 0xCDCDCDCD, 0xCDCD, + 0x064, 0x0001C67C, + 0xFF0F0104, 0xDEAD, + 0xFF0F0200, 0xABCD, + 0x065, 0x00093016, + 0xFF0F02C0, 0xCDEF, + 0x065, 0x00093015, + 0xCDCDCDCD, 0xCDCD, + 0x065, 0x00091016, + 0xFF0F0200, 0xDEAD, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x03B, 0x0003824B, + 0x03B, 0x0003024B, + 0x03B, 0x0002844B, + 0x03B, 0x00020F4B, + 0x03B, 0x00018F4B, + 0x03B, 0x000104B2, + 0x03B, 0x00008049, + 0x03B, 0x00000148, + 0x03B, 0x0007824B, + 0x03B, 0x0007024B, + 0x03B, 0x0006824B, + 0x03B, 0x00060F4B, + 0x03B, 0x00058F4B, + 0x03B, 0x000504B2, + 0x03B, 0x00048049, + 0x03B, 0x00040148, + 0x0EF, 0x00000000, + 0x0EF, 0x00000100, + 0x034, 0x0000ADF3, + 0x034, 0x00009DEF, + 0x034, 0x00008DEC, + 0x034, 0x00007DE9, + 0x034, 0x00006CED, + 0x034, 0x00005CE9, + 0x034, 0x000044E9, + 0x034, 0x000034E6, + 0x034, 0x0000246A, + 0x034, 0x00001467, + 0x034, 0x00000068, + 0x0EF, 0x00000000, + 0x0ED, 0x00000010, + 0x044, 0x0000ADF2, + 0x044, 0x00009DEF, + 0x044, 0x00008DEC, + 0x044, 0x00007DE9, + 0x044, 0x00006CEC, + 0x044, 0x00005CE9, + 0x044, 0x000044EC, + 0x044, 0x000034E9, + 0x044, 0x0000246C, + 0x044, 0x00001469, + 0x044, 0x0000006C, + 0x0ED, 0x00000000, + 0x0ED, 0x00000001, + 0x040, 0x00038DA7, + 0x040, 0x000300C2, + 0x040, 0x000288E2, + 0x040, 0x000200B8, + 0x040, 0x000188A5, + 0x040, 0x00010FBC, + 0x040, 0x00008F71, + 0x040, 0x00000240, + 0x0ED, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000120, + 0x035, 0x00008120, + 0x035, 0x00010120, + 0x036, 0x00000085, + 0x036, 0x00008085, + 0x036, 0x00010085, + 0x036, 0x00018085, + 0x0EF, 0x00000000, + 0x051, 0x00000C31, + 0x052, 0x00000622, + 0x053, 0x000FC70B, + 0x054, 0x0000017E, + 0x056, 0x00051DF3, + 0x051, 0x00000C01, + 0x052, 0x000006D6, + 0x053, 0x000FC649, + 0x070, 0x00049661, + 0x071, 0x0007843E, + 0x072, 0x00000382, + 0x074, 0x00051400, + 0x035, 0x00000160, + 0x035, 0x00008160, + 0x035, 0x00010160, + 0x036, 0x00000124, + 0x036, 0x00008124, + 0x036, 0x00010124, + 0x036, 0x00018124, + 0x0ED, 0x0000000C, + 0x045, 0x00000140, + 0x045, 0x00008140, + 0x045, 0x00010140, + 0x046, 0x00000124, + 0x046, 0x00008124, + 0x046, 0x00010124, + 0x046, 0x00018124, + 0x0DF, 0x00000088, + 0x0B3, 0x000F0E18, + 0x0B4, 0x0001214C, + 0x0B7, 0x0003000C, + 0x01C, 0x000539D2, + 0x018, 0x0001F12A, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x018, 0x0001712A, +}; + +u32 RTL8812AE_MAC_REG_ARRAY[] = { + 0x010, 0x0000000C, + 0xFF0F0180, 0xABCD, + 0x025, 0x0000000F, + 0xFF0F01C0, 0xCDEF, + 0x025, 0x0000000F, + 0xCDCDCDCD, 0xCDCD, + 0x025, 0x0000006F, + 0xFF0F0180, 0xDEAD, + 0x072, 0x00000000, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000007, + 0x43F, 0x00000008, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x00000000, + 0x446, 0x00000000, + 0x447, 0x00000000, + 0x448, 0x00000000, + 0x449, 0x000000F0, + 0x44A, 0x0000000F, + 0x44B, 0x0000003E, + 0x44C, 0x00000010, + 0x44D, 0x00000000, + 0x44E, 0x00000000, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x000000F0, + 0x452, 0x0000000F, + 0x453, 0x00000000, + 0x45B, 0x00000080, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x604, 0x00000001, + 0x605, 0x00000030, + 0x607, 0x00000003, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000080, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + 0x718, 0x00000040, +}; + +u32 RTL8821AE_MAC_REG_ARRAY[] = { + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000007, + 0x43F, 0x00000008, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x00000000, + 0x446, 0x00000000, + 0x447, 0x00000000, + 0x448, 0x00000000, + 0x449, 0x000000F0, + 0x44A, 0x0000000F, + 0x44B, 0x0000003E, + 0x44C, 0x00000010, + 0x44D, 0x00000000, + 0x44E, 0x00000000, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x000000F0, + 0x452, 0x0000000F, + 0x453, 0x00000000, + 0x456, 0x0000005E, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x4C8, 0x0000003F, + 0x4C9, 0x000000FF, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x605, 0x00000030, + 0x607, 0x00000007, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000040, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + 0x718, 0x00000040, +}; + +u32 RTL8812AE_AGC_TAB_ARRAY[] = { + 0xFF0F07D8, 0xABCD, + 0x81C, 0xFC000001, + 0x81C, 0xFB020001, + 0x81C, 0xFA040001, + 0x81C, 0xF9060001, + 0x81C, 0xF8080001, + 0x81C, 0xF70A0001, + 0x81C, 0xF60C0001, + 0x81C, 0xF50E0001, + 0x81C, 0xF4100001, + 0x81C, 0xF3120001, + 0x81C, 0xF2140001, + 0x81C, 0xF1160001, + 0x81C, 0xF0180001, + 0x81C, 0xEF1A0001, + 0x81C, 0xEE1C0001, + 0x81C, 0xED1E0001, + 0x81C, 0xEC200001, + 0x81C, 0xEB220001, + 0x81C, 0xEA240001, + 0x81C, 0xCD260001, + 0x81C, 0xCC280001, + 0x81C, 0xCB2A0001, + 0x81C, 0xCA2C0001, + 0x81C, 0xC92E0001, + 0x81C, 0xC8300001, + 0x81C, 0xA6320001, + 0x81C, 0xA5340001, + 0x81C, 0xA4360001, + 0x81C, 0xA3380001, + 0x81C, 0xA23A0001, + 0x81C, 0x883C0001, + 0x81C, 0x873E0001, + 0x81C, 0x86400001, + 0x81C, 0x85420001, + 0x81C, 0x84440001, + 0x81C, 0x83460001, + 0x81C, 0x82480001, + 0x81C, 0x814A0001, + 0x81C, 0x484C0001, + 0x81C, 0x474E0001, + 0x81C, 0x46500001, + 0x81C, 0x45520001, + 0x81C, 0x44540001, + 0x81C, 0x43560001, + 0x81C, 0x42580001, + 0x81C, 0x415A0001, + 0x81C, 0x255C0001, + 0x81C, 0x245E0001, + 0x81C, 0x23600001, + 0x81C, 0x22620001, + 0x81C, 0x21640001, + 0x81C, 0x21660001, + 0x81C, 0x21680001, + 0x81C, 0x216A0001, + 0x81C, 0x216C0001, + 0x81C, 0x216E0001, + 0x81C, 0x21700001, + 0x81C, 0x21720001, + 0x81C, 0x21740001, + 0x81C, 0x21760001, + 0x81C, 0x21780001, + 0x81C, 0x217A0001, + 0x81C, 0x217C0001, + 0x81C, 0x217E0001, + 0xFF0F07D0, 0xCDEF, + 0x81C, 0xF9000001, + 0x81C, 0xF8020001, + 0x81C, 0xF7040001, + 0x81C, 0xF6060001, + 0x81C, 0xF5080001, + 0x81C, 0xF40A0001, + 0x81C, 0xF30C0001, + 0x81C, 0xF20E0001, + 0x81C, 0xF1100001, + 0x81C, 0xF0120001, + 0x81C, 0xEF140001, + 0x81C, 0xEE160001, + 0x81C, 0xED180001, + 0x81C, 0xEC1A0001, + 0x81C, 0xEB1C0001, + 0x81C, 0xEA1E0001, + 0x81C, 0xCD200001, + 0x81C, 0xCC220001, + 0x81C, 0xCB240001, + 0x81C, 0xCA260001, + 0x81C, 0xC9280001, + 0x81C, 0xC82A0001, + 0x81C, 0xC72C0001, + 0x81C, 0xC62E0001, + 0x81C, 0xA5300001, + 0x81C, 0xA4320001, + 0x81C, 0xA3340001, + 0x81C, 0xA2360001, + 0x81C, 0x88380001, + 0x81C, 0x873A0001, + 0x81C, 0x863C0001, + 0x81C, 0x853E0001, + 0x81C, 0x84400001, + 0x81C, 0x83420001, + 0x81C, 0x82440001, + 0x81C, 0x81460001, + 0x81C, 0x48480001, + 0x81C, 0x474A0001, + 0x81C, 0x464C0001, + 0x81C, 0x454E0001, + 0x81C, 0x44500001, + 0x81C, 0x43520001, + 0x81C, 0x42540001, + 0x81C, 0x41560001, + 0x81C, 0x25580001, + 0x81C, 0x245A0001, + 0x81C, 0x235C0001, + 0x81C, 0x225E0001, + 0x81C, 0x21600001, + 0x81C, 0x21620001, + 0x81C, 0x21640001, + 0x81C, 0x21660001, + 0x81C, 0x21680001, + 0x81C, 0x216A0001, + 0x81C, 0x236C0001, + 0x81C, 0x226E0001, + 0x81C, 0x21700001, + 0x81C, 0x21720001, + 0x81C, 0x21740001, + 0x81C, 0x21760001, + 0x81C, 0x21780001, + 0x81C, 0x217A0001, + 0x81C, 0x217C0001, + 0x81C, 0x217E0001, + 0xCDCDCDCD, 0xCDCD, + 0x81C, 0xFF000001, + 0x81C, 0xFF020001, + 0x81C, 0xFF040001, + 0x81C, 0xFF060001, + 0x81C, 0xFF080001, + 0x81C, 0xFE0A0001, + 0x81C, 0xFD0C0001, + 0x81C, 0xFC0E0001, + 0x81C, 0xFB100001, + 0x81C, 0xFA120001, + 0x81C, 0xF9140001, + 0x81C, 0xF8160001, + 0x81C, 0xF7180001, + 0x81C, 0xF61A0001, + 0x81C, 0xF51C0001, + 0x81C, 0xF41E0001, + 0x81C, 0xF3200001, + 0x81C, 0xF2220001, + 0x81C, 0xF1240001, + 0x81C, 0xF0260001, + 0x81C, 0xEF280001, + 0x81C, 0xEE2A0001, + 0x81C, 0xED2C0001, + 0x81C, 0xEC2E0001, + 0x81C, 0xEB300001, + 0x81C, 0xEA320001, + 0x81C, 0xE9340001, + 0x81C, 0xE8360001, + 0x81C, 0xE7380001, + 0x81C, 0xE63A0001, + 0x81C, 0xE53C0001, + 0x81C, 0xC73E0001, + 0x81C, 0xC6400001, + 0x81C, 0xC5420001, + 0x81C, 0xC4440001, + 0x81C, 0xC3460001, + 0x81C, 0xC2480001, + 0x81C, 0xC14A0001, + 0x81C, 0xA74C0001, + 0x81C, 0xA64E0001, + 0x81C, 0xA5500001, + 0x81C, 0xA4520001, + 0x81C, 0xA3540001, + 0x81C, 0xA2560001, + 0x81C, 0xA1580001, + 0x81C, 0x675A0001, + 0x81C, 0x665C0001, + 0x81C, 0x655E0001, + 0x81C, 0x64600001, + 0x81C, 0x63620001, + 0x81C, 0x48640001, + 0x81C, 0x47660001, + 0x81C, 0x46680001, + 0x81C, 0x456A0001, + 0x81C, 0x446C0001, + 0x81C, 0x436E0001, + 0x81C, 0x42700001, + 0x81C, 0x41720001, + 0x81C, 0x41740001, + 0x81C, 0x41760001, + 0x81C, 0x41780001, + 0x81C, 0x417A0001, + 0x81C, 0x417C0001, + 0x81C, 0x417E0001, + 0xFF0F07D8, 0xDEAD, + 0xFF0F0180, 0xABCD, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xFF0F0280, 0xCDEF, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xFF0F01C0, 0xCDEF, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xFF0F02C0, 0xCDEF, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xFF0F07D8, 0xCDEF, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xFF0F07D0, 0xCDEF, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xCDCDCDCD, 0xCDCD, + 0x81C, 0xFF800001, + 0x81C, 0xFF820001, + 0x81C, 0xFF840001, + 0x81C, 0xFE860001, + 0x81C, 0xFD880001, + 0x81C, 0xFC8A0001, + 0x81C, 0xFB8C0001, + 0x81C, 0xFA8E0001, + 0x81C, 0xF9900001, + 0x81C, 0xF8920001, + 0x81C, 0xF7940001, + 0x81C, 0xF6960001, + 0x81C, 0xF5980001, + 0x81C, 0xF49A0001, + 0x81C, 0xF39C0001, + 0x81C, 0xF29E0001, + 0x81C, 0xF1A00001, + 0x81C, 0xF0A20001, + 0x81C, 0xEFA40001, + 0x81C, 0xEEA60001, + 0x81C, 0xEDA80001, + 0x81C, 0xECAA0001, + 0x81C, 0xEBAC0001, + 0x81C, 0xEAAE0001, + 0x81C, 0xE9B00001, + 0x81C, 0xE8B20001, + 0x81C, 0xE7B40001, + 0x81C, 0xE6B60001, + 0x81C, 0xE5B80001, + 0x81C, 0xE4BA0001, + 0x81C, 0xE3BC0001, + 0x81C, 0xA8BE0001, + 0x81C, 0xA7C00001, + 0x81C, 0xA6C20001, + 0x81C, 0xA5C40001, + 0x81C, 0xA4C60001, + 0x81C, 0xA3C80001, + 0x81C, 0xA2CA0001, + 0x81C, 0xA1CC0001, + 0x81C, 0x68CE0001, + 0x81C, 0x67D00001, + 0x81C, 0x66D20001, + 0x81C, 0x65D40001, + 0x81C, 0x64D60001, + 0x81C, 0x47D80001, + 0x81C, 0x46DA0001, + 0x81C, 0x45DC0001, + 0x81C, 0x44DE0001, + 0x81C, 0x43E00001, + 0x81C, 0x42E20001, + 0x81C, 0x08E40001, + 0x81C, 0x07E60001, + 0x81C, 0x06E80001, + 0x81C, 0x05EA0001, + 0x81C, 0x04EC0001, + 0x81C, 0x03EE0001, + 0x81C, 0x02F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xFF0F0180, 0xDEAD, + 0xC50, 0x00000022, + 0xC50, 0x00000020, + 0xE50, 0x00000022, + 0xE50, 0x00000020, +}; + +u32 RTL8821AE_AGC_TAB_ARRAY[] = { + 0x81C, 0xBF000001, + 0x81C, 0xBF020001, + 0x81C, 0xBF040001, + 0x81C, 0xBF060001, + 0x81C, 0xBE080001, + 0x81C, 0xBD0A0001, + 0x81C, 0xBC0C0001, + 0x81C, 0xBA0E0001, + 0x81C, 0xB9100001, + 0x81C, 0xB8120001, + 0x81C, 0xB7140001, + 0x81C, 0xB6160001, + 0x81C, 0xB5180001, + 0x81C, 0xB41A0001, + 0x81C, 0xB31C0001, + 0x81C, 0xB21E0001, + 0x81C, 0xB1200001, + 0x81C, 0xB0220001, + 0x81C, 0xAF240001, + 0x81C, 0xAE260001, + 0x81C, 0xAD280001, + 0x81C, 0xAC2A0001, + 0x81C, 0xAB2C0001, + 0x81C, 0xAA2E0001, + 0x81C, 0xA9300001, + 0x81C, 0xA8320001, + 0x81C, 0xA7340001, + 0x81C, 0xA6360001, + 0x81C, 0xA5380001, + 0x81C, 0xA43A0001, + 0x81C, 0xA33C0001, + 0x81C, 0x673E0001, + 0x81C, 0x66400001, + 0x81C, 0x65420001, + 0x81C, 0x64440001, + 0x81C, 0x63460001, + 0x81C, 0x62480001, + 0x81C, 0x614A0001, + 0x81C, 0x474C0001, + 0x81C, 0x464E0001, + 0x81C, 0x45500001, + 0x81C, 0x44520001, + 0x81C, 0x43540001, + 0x81C, 0x42560001, + 0x81C, 0x41580001, + 0x81C, 0x285A0001, + 0x81C, 0x275C0001, + 0x81C, 0x265E0001, + 0x81C, 0x25600001, + 0x81C, 0x24620001, + 0x81C, 0x0A640001, + 0x81C, 0x09660001, + 0x81C, 0x08680001, + 0x81C, 0x076A0001, + 0x81C, 0x066C0001, + 0x81C, 0x056E0001, + 0x81C, 0x04700001, + 0x81C, 0x03720001, + 0x81C, 0x02740001, + 0x81C, 0x01760001, + 0x81C, 0x01780001, + 0x81C, 0x017A0001, + 0x81C, 0x017C0001, + 0x81C, 0x017E0001, + 0xFF0F02C0, 0xABCD, + 0x81C, 0xFB000101, + 0x81C, 0xFA020101, + 0x81C, 0xF9040101, + 0x81C, 0xF8060101, + 0x81C, 0xF7080101, + 0x81C, 0xF60A0101, + 0x81C, 0xF50C0101, + 0x81C, 0xF40E0101, + 0x81C, 0xF3100101, + 0x81C, 0xF2120101, + 0x81C, 0xF1140101, + 0x81C, 0xF0160101, + 0x81C, 0xEF180101, + 0x81C, 0xEE1A0101, + 0x81C, 0xED1C0101, + 0x81C, 0xEC1E0101, + 0x81C, 0xEB200101, + 0x81C, 0xEA220101, + 0x81C, 0xE9240101, + 0x81C, 0xE8260101, + 0x81C, 0xE7280101, + 0x81C, 0xE62A0101, + 0x81C, 0xE52C0101, + 0x81C, 0xE42E0101, + 0x81C, 0xE3300101, + 0x81C, 0xA5320101, + 0x81C, 0xA4340101, + 0x81C, 0xA3360101, + 0x81C, 0x87380101, + 0x81C, 0x863A0101, + 0x81C, 0x853C0101, + 0x81C, 0x843E0101, + 0x81C, 0x69400101, + 0x81C, 0x68420101, + 0x81C, 0x67440101, + 0x81C, 0x66460101, + 0x81C, 0x49480101, + 0x81C, 0x484A0101, + 0x81C, 0x474C0101, + 0x81C, 0x2A4E0101, + 0x81C, 0x29500101, + 0x81C, 0x28520101, + 0x81C, 0x27540101, + 0x81C, 0x26560101, + 0x81C, 0x25580101, + 0x81C, 0x245A0101, + 0x81C, 0x235C0101, + 0x81C, 0x055E0101, + 0x81C, 0x04600101, + 0x81C, 0x03620101, + 0x81C, 0x02640101, + 0x81C, 0x01660101, + 0x81C, 0x01680101, + 0x81C, 0x016A0101, + 0x81C, 0x016C0101, + 0x81C, 0x016E0101, + 0x81C, 0x01700101, + 0x81C, 0x01720101, + 0xCDCDCDCD, 0xCDCD, + 0x81C, 0xFF000101, + 0x81C, 0xFF020101, + 0x81C, 0xFE040101, + 0x81C, 0xFD060101, + 0x81C, 0xFC080101, + 0x81C, 0xFD0A0101, + 0x81C, 0xFC0C0101, + 0x81C, 0xFB0E0101, + 0x81C, 0xFA100101, + 0x81C, 0xF9120101, + 0x81C, 0xF8140101, + 0x81C, 0xF7160101, + 0x81C, 0xF6180101, + 0x81C, 0xF51A0101, + 0x81C, 0xF41C0101, + 0x81C, 0xF31E0101, + 0x81C, 0xF2200101, + 0x81C, 0xF1220101, + 0x81C, 0xF0240101, + 0x81C, 0xEF260101, + 0x81C, 0xEE280101, + 0x81C, 0xED2A0101, + 0x81C, 0xEC2C0101, + 0x81C, 0xEB2E0101, + 0x81C, 0xEA300101, + 0x81C, 0xE9320101, + 0x81C, 0xE8340101, + 0x81C, 0xE7360101, + 0x81C, 0xE6380101, + 0x81C, 0xE53A0101, + 0x81C, 0xE43C0101, + 0x81C, 0xE33E0101, + 0x81C, 0xA5400101, + 0x81C, 0xA4420101, + 0x81C, 0xA3440101, + 0x81C, 0x87460101, + 0x81C, 0x86480101, + 0x81C, 0x854A0101, + 0x81C, 0x844C0101, + 0x81C, 0x694E0101, + 0x81C, 0x68500101, + 0x81C, 0x67520101, + 0x81C, 0x66540101, + 0x81C, 0x49560101, + 0x81C, 0x48580101, + 0x81C, 0x475A0101, + 0x81C, 0x2A5C0101, + 0x81C, 0x295E0101, + 0x81C, 0x28600101, + 0x81C, 0x27620101, + 0x81C, 0x26640101, + 0x81C, 0x25660101, + 0x81C, 0x24680101, + 0x81C, 0x236A0101, + 0x81C, 0x056C0101, + 0x81C, 0x046E0101, + 0x81C, 0x03700101, + 0x81C, 0x02720101, + 0xFF0F02C0, 0xDEAD, + 0x81C, 0x01740101, + 0x81C, 0x01760101, + 0x81C, 0x01780101, + 0x81C, 0x017A0101, + 0x81C, 0x017C0101, + 0x81C, 0x017E0101, + 0xC50, 0x00000022, + 0xC50, 0x00000020, + +}; --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/dm.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/dm.h @@ -0,0 +1,426 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_DM_H__ +#define __RTL8821AE_DM_H__ + +#define MAIN_ANT 0 +#define AUX_ANT 1 +#define MAIN_ANT_CG_TRX 1 +#define AUX_ANT_CG_TRX 0 +#define MAIN_ANT_CGCS_RX 0 +#define AUX_ANT_CGCS_RX 1 + +#define TXSCALE_TABLE_SIZE 37 + +/*RF REG LIST*/ +#define DM_REG_RF_MODE_11N 0x00 +#define DM_REG_RF_0B_11N 0x0B +#define DM_REG_CHNBW_11N 0x18 +#define DM_REG_T_METER_11N 0x24 +#define DM_REG_RF_25_11N 0x25 +#define DM_REG_RF_26_11N 0x26 +#define DM_REG_RF_27_11N 0x27 +#define DM_REG_RF_2B_11N 0x2B +#define DM_REG_RF_2C_11N 0x2C +#define DM_REG_RXRF_A3_11N 0x3C +#define DM_REG_T_METER_92D_11N 0x42 +#define DM_REG_T_METER_88E_11N 0x42 + + + +/*BB REG LIST*/ +/*PAGE 8 */ +#define DM_REG_BB_CTRL_11N 0x800 +#define DM_REG_RF_PIN_11N 0x804 +#define DM_REG_PSD_CTRL_11N 0x808 +#define DM_REG_TX_ANT_CTRL_11N 0x80C +#define DM_REG_BB_PWR_SAV5_11N 0x818 +#define DM_REG_CCK_RPT_FORMAT_11N 0x824 +#define DM_REG_RX_DEFUALT_A_11N 0x858 +#define DM_REG_RX_DEFUALT_B_11N 0x85A +#define DM_REG_BB_PWR_SAV3_11N 0x85C +#define DM_REG_ANTSEL_CTRL_11N 0x860 +#define DM_REG_RX_ANT_CTRL_11N 0x864 +#define DM_REG_PIN_CTRL_11N 0x870 +#define DM_REG_BB_PWR_SAV1_11N 0x874 +#define DM_REG_ANTSEL_PATH_11N 0x878 +#define DM_REG_BB_3WIRE_11N 0x88C +#define DM_REG_SC_CNT_11N 0x8C4 +#define DM_REG_PSD_DATA_11N 0x8B4 +/*PAGE 9*/ +#define DM_REG_ANT_MAPPING1_11N 0x914 +#define DM_REG_ANT_MAPPING2_11N 0x918 +/*PAGE A*/ +#define DM_REG_CCK_ANTDIV_PARA1_11N 0xA00 +#define DM_REG_CCK_CCA_11N 0xA0A +#define DM_REG_CCK_CCA_11AC 0xA0A +#define DM_REG_CCK_ANTDIV_PARA2_11N 0xA0C +#define DM_REG_CCK_ANTDIV_PARA3_11N 0xA10 +#define DM_REG_CCK_ANTDIV_PARA4_11N 0xA14 +#define DM_REG_CCK_FILTER_PARA1_11N 0xA22 +#define DM_REG_CCK_FILTER_PARA2_11N 0xA23 +#define DM_REG_CCK_FILTER_PARA3_11N 0xA24 +#define DM_REG_CCK_FILTER_PARA4_11N 0xA25 +#define DM_REG_CCK_FILTER_PARA5_11N 0xA26 +#define DM_REG_CCK_FILTER_PARA6_11N 0xA27 +#define DM_REG_CCK_FILTER_PARA7_11N 0xA28 +#define DM_REG_CCK_FILTER_PARA8_11N 0xA29 +#define DM_REG_CCK_FA_RST_11N 0xA2C +#define DM_REG_CCK_FA_MSB_11N 0xA58 +#define DM_REG_CCK_FA_LSB_11N 0xA5C +#define DM_REG_CCK_CCA_CNT_11N 0xA60 +#define DM_REG_BB_PWR_SAV4_11N 0xA74 +/*PAGE B */ +#define DM_REG_LNA_SWITCH_11N 0xB2C +#define DM_REG_PATH_SWITCH_11N 0xB30 +#define DM_REG_RSSI_CTRL_11N 0xB38 +#define DM_REG_CONFIG_ANTA_11N 0xB68 +#define DM_REG_RSSI_BT_11N 0xB9C +/*PAGE C */ +#define DM_REG_OFDM_FA_HOLDC_11N 0xC00 +#define DM_REG_RX_PATH_11N 0xC04 +#define DM_REG_TRMUX_11N 0xC08 +#define DM_REG_OFDM_FA_RSTC_11N 0xC0C +#define DM_REG_RXIQI_MATRIX_11N 0xC14 +#define DM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C +#define DM_REG_IGI_A_11N 0xC50 +#define DM_REG_IGI_A_11AC 0xC50 +#define DM_REG_ANTDIV_PARA2_11N 0xC54 +#define DM_REG_IGI_B_11N 0xC58 +#define DM_REG_IGI_B_11AC 0xE50 +#define DM_REG_ANTDIV_PARA3_11N 0xC5C +#define DM_REG_BB_PWR_SAV2_11N 0xC70 +#define DM_REG_RX_OFF_11N 0xC7C +#define DM_REG_TXIQK_MATRIXA_11N 0xC80 +#define DM_REG_TXIQK_MATRIXB_11N 0xC88 +#define DM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 +#define DM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C +#define DM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 +#define DM_REG_ANTDIV_PARA1_11N 0xCA4 +#define DM_REG_OFDM_FA_TYPE1_11N 0xCF0 +/*PAGE D */ +#define DM_REG_OFDM_FA_RSTD_11N 0xD00 +#define DM_REG_OFDM_FA_TYPE2_11N 0xDA0 +#define DM_REG_OFDM_FA_TYPE3_11N 0xDA4 +#define DM_REG_OFDM_FA_TYPE4_11N 0xDA8 +/*PAGE E */ +#define DM_REG_TXAGC_A_6_18_11N 0xE00 +#define DM_REG_TXAGC_A_24_54_11N 0xE04 +#define DM_REG_TXAGC_A_1_MCS32_11N 0xE08 +#define DM_REG_TXAGC_A_MCS0_3_11N 0xE10 +#define DM_REG_TXAGC_A_MCS4_7_11N 0xE14 +#define DM_REG_TXAGC_A_MCS8_11_11N 0xE18 +#define DM_REG_TXAGC_A_MCS12_15_11N 0xE1C +#define DM_REG_FPGA0_IQK_11N 0xE28 +#define DM_REG_TXIQK_TONE_A_11N 0xE30 +#define DM_REG_RXIQK_TONE_A_11N 0xE34 +#define DM_REG_TXIQK_PI_A_11N 0xE38 +#define DM_REG_RXIQK_PI_A_11N 0xE3C +#define DM_REG_TXIQK_11N 0xE40 +#define DM_REG_RXIQK_11N 0xE44 +#define DM_REG_IQK_AGC_PTS_11N 0xE48 +#define DM_REG_IQK_AGC_RSP_11N 0xE4C +#define DM_REG_BLUETOOTH_11N 0xE6C +#define DM_REG_RX_WAIT_CCA_11N 0xE70 +#define DM_REG_TX_CCK_RFON_11N 0xE74 +#define DM_REG_TX_CCK_BBON_11N 0xE78 +#define DM_REG_OFDM_RFON_11N 0xE7C +#define DM_REG_OFDM_BBON_11N 0xE80 +#define DM_REG_TX2RX_11N 0xE84 +#define DM_REG_TX2TX_11N 0xE88 +#define DM_REG_RX_CCK_11N 0xE8C +#define DM_REG_RX_OFDM_11N 0xED0 +#define DM_REG_RX_WAIT_RIFS_11N 0xED4 +#define DM_REG_RX2RX_11N 0xED8 +#define DM_REG_STANDBY_11N 0xEDC +#define DM_REG_SLEEP_11N 0xEE0 +#define DM_REG_PMPD_ANAEN_11N 0xEEC + + +/*MAC REG LIST*/ +#define DM_REG_BB_RST_11N 0x02 +#define DM_REG_ANTSEL_PIN_11N 0x4C +#define DM_REG_EARLY_MODE_11N 0x4D0 +#define DM_REG_RSSI_MONITOR_11N 0x4FE +#define DM_REG_EDCA_VO_11N 0x500 +#define DM_REG_EDCA_VI_11N 0x504 +#define DM_REG_EDCA_BE_11N 0x508 +#define DM_REG_EDCA_BK_11N 0x50C +#define DM_REG_TXPAUSE_11N 0x522 +#define DM_REG_RESP_TX_11N 0x6D8 +#define DM_REG_ANT_TRAIN_PARA1_11N 0x7b0 +#define DM_REG_ANT_TRAIN_PARA2_11N 0x7b4 + + +/*DIG Related*/ +#define DM_BIT_IGI_11N 0x0000007F +#define DM_BIT_IGI_11AC 0xFFFFFFFF + + + +#define HAL_DM_DIG_DISABLE BIT(0) +#define HAL_DM_HIPWR_DISABLE BIT(1) + +#define OFDM_TABLE_LENGTH 43 +#define CCK_TABLE_LENGTH 33 + +#define OFDM_TABLE_SIZE 37 +#define CCK_TABLE_SIZE 33 + +#define BW_AUTO_SWITCH_HIGH_LOW 25 +#define BW_AUTO_SWITCH_LOW_HIGH 30 + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1e + +#define DM_DIG_MAX_AP 0x32 +#define DM_DIG_MIN_AP 0x20 + +#define DM_DIG_FA_UPPER 0x3e +#define DM_DIG_FA_LOWER 0x1e +#define DM_DIG_FA_TH0 0x200 +#define DM_DIG_FA_TH1 0x300 +#define DM_DIG_FA_TH2 0x400 + +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +#define RXPATHSELECTION_SS_TH_lOW 30 +#define RXPATHSELECTION_DIFF_TH 18 + +#define DM_RATR_STA_INIT 0 +#define DM_RATR_STA_HIGH 1 +#define DM_RATR_STA_MIDDLE 2 +#define DM_RATR_STA_LOW 3 + +#define CTS2SELF_THVAL 30 +#define REGC38_TH 20 + +#define WAIOTTHVal 25 + +#define TXHIGHPWRLEVEL_NORMAL 0 +#define TXHIGHPWRLEVEL_LEVEL1 1 +#define TXHIGHPWRLEVEL_LEVEL2 2 +#define TXHIGHPWRLEVEL_BT1 3 +#define TXHIGHPWRLEVEL_BT2 4 + +#define DM_TYPE_BYFW 0 +#define DM_TYPE_BYDRIVER 1 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 +#define TXPWRTRACK_MAX_IDX 6 + +/* Dynamic ATC switch */ +#define ATC_STATUS_OFF 0x0 /* enable */ +#define ATC_STATUS_ON 0x1 /* disable */ +#define CFO_THRESHOLD_XTAL 10 /* kHz */ +#define CFO_THRESHOLD_ATC 80 /* kHz */ + +#define AVG_THERMAL_NUM_8812A 4 +#define TXPWR_TRACK_TABLE_SIZE 30 +#define MAX_PATH_NUM_8812A 2 +#define MAX_PATH_NUM_8821A 1 + + +struct ps_t { + u8 pre_ccastate; + u8 cur_ccasate; + u8 pre_rfstate; + u8 cur_rfstate; + u8 initialize; + long rssi_val_min; + +}; + +struct dig_t { + u8 dig_enable_flag; + u8 dig_ext_port_stage; + u32 rssi_lowthresh; + u32 rssi_highthresh; + + u32 fa_lowthresh; + u32 fa_highthresh; + + u8 cursta_connectctate; + u8 presta_connectstate; + u8 curmultista_connectstate; + + u8 pre_igvalue; + u8 cur_igvalue; + u8 bt30_cur_igi; + u8 backup_igvalue; + u8 stop_dig; + + char backoff_val; + char backoff_val_range_max; + char backoff_val_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + u8 rssi_val_min; + + u8 pre_cck_cca_thres; + u8 cur_cck_cca_thres; + u8 pre_cck_pd_state; + u8 cur_cck_pd_state; + + u8 large_fa_hit; + u8 forbidden_igi; + u32 recover_cnt; + + u8 dig_dynamic_min_0; + u8 dig_dynamic_min_1; + bool b_media_connect_0; + bool b_media_connect_1; + + u32 antdiv_rssi_max; + u32 rssi_max; +}; + + +enum FAT_STATE { + FAT_NORMAL_STATE = 0, + FAT_TRAINING_STATE = 1, +}; + +enum tag_dynamic_init_gain_operation_type_definition { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +enum tag_cck_packet_detection_threshold_type_definition { + CCK_PD_STAGE_LowRssi = 0, + CCK_PD_STAGE_HighRssi = 1, + CCK_FA_STAGE_Low = 2, + CCK_FA_STAGE_High = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_1r_cca_e { + CCA_1R = 0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf_e { + RF_SAVE = 0, + RF_NORMAL = 1, + RF_MAX = 2, +}; + +enum dm_sw_ant_switch_e { + ANS_ANTENNA_B = 1, + ANS_ANTENNA_A = 2, + ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg_e { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect_e { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MULTISTA_DISCONNECT = 3, + DIG_MULTISTA_CONNECT = 4, + DIG_CONNECT_MAX +}; + +enum pwr_track_control_method { + BBSWING, + TXAGC, + MIX_MODE +}; + +#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) +#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) +#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) +#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) +#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) +#define GET_UNDECORATED_AVERAGE_RSSI(_priv) \ + (((struct rtl_priv *)(_priv))->mac80211.opmode == NL80211_IFTYPE_ADHOC)? \ + (((struct rtl_priv *)(_priv))->dm.entry_min_undecoratedsmoothed_pwdb): \ + (((struct rtl_priv *)(_priv))->dm.undecorated_smoothed_pwdb) + +extern struct dig_t dm_digtable; +void rtl8821ae_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw, + u8 *pdesc, u32 mac_id); +void rtl8821ae_dm_ant_sel_statistics(struct ieee80211_hw *hw, + u8 antsel_tr_mux, u32 mac_id, + u32 rx_pwdb_all); +void rtl8821ae_dm_fast_antenna_trainning_callback(unsigned long data); +void rtl8821ae_dm_init(struct ieee80211_hw *hw); +void rtl8821ae_dm_watchdog(struct ieee80211_hw *hw); +void rtl8821ae_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi); +void rtl8821ae_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl8821ae_dm_check_txpower_tracking_thermalmeter(struct ieee80211_hw *hw); +void rtl8821ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); +void rtl8821ae_dm_txpower_track_adjust(struct ieee80211_hw *hw, + u8 type,u8 *pdirection, + u32 *poutwrite_val); +void rtl8821ae_dm_clear_txpower_tracking_state(struct ieee80211_hw *hw); +void rtl8821ae_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 current_cca); +void rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(struct ieee80211_hw *hw); +void rtl8812ae_dm_path_diversity(struct ieee80211_hw *hw); +void rtl8812ae_dm_path_diversity_init(struct ieee80211_hw *hw); +void rtl8812ae_dm_path_statistics(struct ieee80211_hw *hw, + u32 rssi_a, u32 rssi_b); +void rtl812ae_dm_set_txpath_by_txinfo(struct ieee80211_hw *hw, + u8 *pdesc); +void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, + enum pwr_track_control_method method, + u8 rf_path, + u8 channel_mapped_index); +void rtl8821ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, + enum pwr_track_control_method method, u8 rf_path, u8 channel_mapped_index); + +void rtl8812ae_dm_update_init_rate(struct ieee80211_hw *hw, u8 rate); +u8 rtl8812ae_hw_rate_to_mrate(struct ieee80211_hw *hw, u8 rate); +void rtl8812ae_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw *hw); +void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw *hw); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/hw.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/hw.c @@ -0,0 +1,3346 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "led.h" +#include "hw.h" +#include "pwrseqcmd.h" +#include "pwrseq.h" +#include "btc.h" +#include "../btcoexist/rtl_btc.h" + +#define LLT_CONFIG 5 + +static void _rtl8821ae_return_beacon_queue_skb(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + while (skb_queue_len(&ring->queue)) { + struct rtl_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + + pci_unmap_single(rtlpci->pdev, + le32_to_cpu(rtlpriv->cfg->ops->get_desc( + (u8 *) entry, true, HW_DESC_TXBUFF_ADDR)), + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + +} + +static void _rtl8821ae_set_bcn_ctrl_reg(struct ieee80211_hw *hw, + u8 set_bits, u8 clear_bits) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpci->reg_bcn_ctrl_val |= set_bits; + rtlpci->reg_bcn_ctrl_val &= ~clear_bits; + + rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); +} + +void _rtl8821ae_stop_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6))); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +void _rtl8821ae_resume_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte |= BIT(0); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl8821ae_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl8821ae_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl8821ae_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +static void _rtl8821ae_set_fw_clock_on(struct ieee80211_hw *hw, + u8 rpwm_val, bool b_need_turn_off_ckk) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool b_support_remote_wake_up; + u32 count = 0,isr_regaddr,content; + bool b_schedule_timer = b_need_turn_off_ckk; + rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN, + (u8 *) (&b_support_remote_wake_up)); + + if (!rtlhal->bfw_ready) + return; + if (!rtlpriv->psc.b_fw_current_inpsmode) + return; + + while (1) { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + if (rtlhal->bfw_clk_change_in_progress) { + while (rtlhal->bfw_clk_change_in_progress) { + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + count++; + udelay(100); + if (count > 1000) + return; + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + } + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } else { + rtlhal->bfw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } + } + + if (IS_IN_LOW_POWER_STATE_8821AE(rtlhal->fw_ps_state)) { + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *) (&rpwm_val)); + if (FW_PS_IS_ACK(rpwm_val)) { + isr_regaddr = REG_HISR; + content = rtl_read_dword(rtlpriv, isr_regaddr); + while (!(content & IMR_CPWM) && (count < 500)) { + udelay(50); + count++; + content = rtl_read_dword(rtlpriv, isr_regaddr); + } + + if (content & IMR_CPWM) { + rtl_write_word(rtlpriv,isr_regaddr, 0x0100); + rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_8821AE; + RT_TRACE(COMP_POWER, DBG_LOUD, ("Receive CPWM INT!!! Set pHalData->FwPSState = %X\n", rtlhal->fw_ps_state)); + } + } + + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->bfw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + if (b_schedule_timer) { + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + } + + } else { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->bfw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } + + +} + +static void _rtl8821ae_set_fw_clock_off(struct ieee80211_hw *hw, + u8 rpwm_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + enum rf_pwrstate rtstate; + bool b_schedule_timer = false; + u8 queue; + + if (!rtlhal->bfw_ready) + return; + if (!rtlpriv->psc.b_fw_current_inpsmode) + return; + if (!rtlhal->ballow_sw_to_change_hwclc) + return; + rtlpriv->cfg->ops->get_hw_reg(hw,HW_VAR_RF_STATE,(u8 *)(&rtstate)); + if (rtstate == ERFOFF ||rtlpriv->psc.inactive_pwrstate ==ERFOFF) + return; + + for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) { + ring = &rtlpci->tx_ring[queue]; + if (skb_queue_len(&ring->queue)) { + b_schedule_timer = true; + break; + } + } + + if (b_schedule_timer) { + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + return; + } + + if (FW_PS_STATE(rtlhal->fw_ps_state) != FW_PS_STATE_RF_OFF_LOW_PWR_8821AE) { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + if (!rtlhal->bfw_clk_change_in_progress) { + rtlhal->bfw_clk_change_in_progress = true; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val); + rtl_write_word(rtlpriv, REG_HISR, 0x0100); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *) (&rpwm_val)); + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->bfw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } else { + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + } + } + +} + +static void _rtl8821ae_set_fw_ps_rf_on(struct ieee80211_hw *hw) +{ + u8 rpwm_val = 0; + rpwm_val |= (FW_PS_STATE_RF_OFF_8821AE | FW_PS_ACK); + _rtl8821ae_set_fw_clock_on(hw, rpwm_val, true); +} + +static void _rtl8821ae_fwlps_leave(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool b_fw_current_inps = false; + u8 rpwm_val = 0,fw_pwrmode = FW_PS_ACTIVE_MODE; + + if (ppsc->b_low_power_enable){ + rpwm_val = (FW_PS_STATE_ALL_ON_8821AE|FW_PS_ACK);/* RF on */ + _rtl8821ae_set_fw_clock_on(hw, rpwm_val, false); + rtlhal->ballow_sw_to_change_hwclc = false; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *) (&fw_pwrmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&b_fw_current_inps)); + } else { + rpwm_val = FW_PS_STATE_ALL_ON_8821AE; /* RF on */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *) (&rpwm_val)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *) (&fw_pwrmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&b_fw_current_inps)); + } + +} + +static void _rtl8821ae_fwlps_enter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool b_fw_current_inps = true; + u8 rpwm_val; + + if (ppsc->b_low_power_enable){ + rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_8821AE; /* RF off */ + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&b_fw_current_inps)); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_PWRMODE, + (u8 *) (&ppsc->fwctrl_psmode)); + rtlhal->ballow_sw_to_change_hwclc = true; + _rtl8821ae_set_fw_clock_off(hw, rpwm_val); + + + } else { + rpwm_val = FW_PS_STATE_RF_OFF_8821AE; /* RF off */ + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&b_fw_current_inps)); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_PWRMODE, + (u8 *) (&ppsc->fwctrl_psmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_SET_RPWM, + (u8 *) (&rpwm_val)); + } + +} + +void rtl8821ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + switch (variable) { + case HW_VAR_ETHER_ADDR: + *((u32 *)(val)) = rtl_read_dword(rtlpriv, REG_MACID); + *((u16 *)(val+4)) = rtl_read_word(rtlpriv, REG_MACID + 4); + break; + case HW_VAR_BSSID: + *((u32 *)(val)) = rtl_read_dword(rtlpriv, REG_BSSID); + *((u16 *)(val+4)) = rtl_read_word(rtlpriv, REG_BSSID+4); + break; + case HW_VAR_MEDIA_STATUS: + val[0] = rtl_read_byte(rtlpriv, REG_CR+2) & 0x3; + break; + case HW_VAR_SLOT_TIME: + *((u8 *)(val)) = mac->slot_time; + break; + case HW_VAR_BEACON_INTERVAL: + *((u16 *)(val)) = rtl_read_word(rtlpriv, REG_BCN_INTERVAL); + break; + case HW_VAR_ATIM_WINDOW: + *((u16 *)(val)) = rtl_read_word(rtlpriv, REG_ATIMWND); + break; + case HW_VAR_RCR: + *((u32 *) (val)) = rtlpci->receive_config; + break; + case HW_VAR_RF_STATE: + *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; + break; + case HW_VAR_FWLPS_RF_ON:{ + enum rf_pwrstate rfState; + u32 val_rcr; + + rtlpriv->cfg->ops->get_hw_reg(hw, + HW_VAR_RF_STATE, + (u8 *) (&rfState)); + if (rfState == ERFOFF) { + *((bool *) (val)) = true; + } else { + val_rcr = rtl_read_dword(rtlpriv, REG_RCR); + val_rcr &= 0x00070000; + if (val_rcr) + *((bool *) (val)) = false; + else + *((bool *) (val)) = true; + } + break; + } + case HW_VAR_FW_PSMODE_STATUS: + *((bool *) (val)) = ppsc->b_fw_current_inpsmode; + break; + case HW_VAR_CORRECT_TSF:{ + u64 tsf; + u32 *ptsf_low = (u32 *) & tsf; + u32 *ptsf_high = ((u32 *) & tsf) + 1; + + *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4)); + *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + + *((u64 *) (val)) = tsf; + + break; + } + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process %x\n",variable)); + break; + } +} + + +void rtl8821ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 idx; + + switch (variable) { + case HW_VAR_ETHER_ADDR:{ + for (idx = 0; idx < ETH_ALEN; idx++) { + rtl_write_byte(rtlpriv, (REG_MACID + idx), + val[idx]); + } + break; + } + case HW_VAR_BASIC_RATE:{ + u16 b_rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + b_rate_cfg = b_rate_cfg & 0x15f; + b_rate_cfg |= 0x01; + rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR + 1, + (b_rate_cfg >> 8) & 0xff); + while (b_rate_cfg > 0x1) { + b_rate_cfg = (b_rate_cfg >> 1); + rate_index++; + } + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, + rate_index); + break; + } + case HW_VAR_BSSID:{ + for (idx = 0; idx < ETH_ALEN; idx++) { + rtl_write_byte(rtlpriv, (REG_BSSID + idx), + val[idx]); + } + break; + } + case HW_VAR_SIFS:{ + rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]); + rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]); + + rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]); + rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]); + + if (!mac->ht_enable) + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, + 0x0e0e); + else + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, + *((u16 *) val)); + break; + } + case HW_VAR_SLOT_TIME:{ + u8 e_aci; + + RT_TRACE(COMP_MLME, DBG_LOUD, + ("HW_VAR_SLOT_TIME %x\n", val[0])); + + rtl_write_byte(rtlpriv, REG_SLOT, val[0]); + + for (e_aci = 0; e_aci < AC_MAX; e_aci++) { + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AC_PARAM, + (u8 *) (&e_aci)); + } + break; + } + case HW_VAR_ACK_PREAMBLE:{ + u8 reg_tmp; + u8 short_preamble = (bool) (*(u8 *) val); + reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL+2); + if (short_preamble){ + reg_tmp |= BIT(1); + rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp); + } else { + reg_tmp &= (~BIT(1)); + rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp); + } + break; + } + case HW_VAR_WPA_CONFIG: + rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val)); + break; + case HW_VAR_AMPDU_MIN_SPACE:{ + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *) val); + if (min_spacing_to_set <= 7) { + sec_min_space = 0; + + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + + mac->min_space_cfg = ((mac->min_space_cfg & + 0xf8) | + min_spacing_to_set); + + *val = min_spacing_to_set; + + RT_TRACE(COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg)); + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY:{ + u8 density_to_set; + + density_to_set = *((u8 *) val); + mac->min_space_cfg |= (density_to_set << 3); + + RT_TRACE(COMP_MLME, DBG_LOUD, + ("Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg)); + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + + break; + } + case HW_VAR_AMPDU_FACTOR:{ + u32 ampdu_len = (*((u8 *)val)); + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + if(ampdu_len < VHT_AGG_SIZE_128K) + ampdu_len = (0x2000 << (*((u8 *)val))) -1; + else + ampdu_len = 0x1ffff; + } else if(rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + if(ampdu_len < HT_AGG_SIZE_64K) + ampdu_len = (0x2000 << (*((u8 *)val))) -1; + else + ampdu_len = 0xffff; + } + ampdu_len |= BIT(31); + + rtl_write_dword(rtlpriv, + REG_AMPDU_MAX_LENGTH_8812, ampdu_len); + break; + } + case HW_VAR_AC_PARAM:{ + u8 e_aci = *((u8 *) val); + rtl8821ae_dm_init_edca_turbo(hw); + + if (rtlpci->acm_method != eAcmWay2_SW) + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_ACM_CTRL, + (u8 *) (&e_aci)); + break; + } + case HW_VAR_ACM_CTRL:{ + u8 e_aci = *((u8 *) val); + union aci_aifsn *p_aci_aifsn = + (union aci_aifsn *)(&(mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); + + acm_ctrl = + acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1); + + if (acm) { + switch (e_aci) { + case AC0_BE: + acm_ctrl |= AcmHw_BeqEn; + break; + case AC2_VI: + acm_ctrl |= AcmHw_ViqEn; + break; + case AC3_VO: + acm_ctrl |= AcmHw_VoqEn; + break; + default: + RT_TRACE(COMP_ERR, DBG_WARNING, + ("HW_VAR_ACM_CTRL acm set " + "failed: eACI is %d\n", acm)); + break; + } + } else { + switch (e_aci) { + case AC0_BE: + acm_ctrl &= (~AcmHw_BeqEn); + break; + case AC2_VI: + acm_ctrl &= (~AcmHw_ViqEn); + break; + case AC3_VO: + acm_ctrl &= (~AcmHw_BeqEn); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + } + + RT_TRACE(COMP_QOS, DBG_TRACE, + ("SetHwReg8190pci(): [HW_VAR_ACM_CTRL] " + "Write 0x%X\n", acm_ctrl)); + rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); + break; + } + case HW_VAR_RCR:{ + rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]); + rtlpci->receive_config = ((u32 *) (val))[0]; + break; + } + case HW_VAR_RETRY_LIMIT:{ + u8 retry_limit = ((u8 *) (val))[0]; + + rtl_write_word(rtlpriv, REG_RL, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + break; + } + case HW_VAR_DUAL_TSF_RST: + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); + break; + case HW_VAR_EFUSE_BYTES: + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + case HW_VAR_EFUSE_USAGE: + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + case HW_VAR_IO_CMD: + rtl8821ae_phy_set_io_cmd(hw, (*(enum io_type *)val)); + break; + case HW_VAR_SET_RPWM:{ + u8 rpwm_val; + + rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM); + udelay(1); + + if (rpwm_val & BIT(7)) { + rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, + (*(u8 *) val)); + } else { + rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, + ((*(u8 *) val) | BIT(7))); + } + + break; + } + case HW_VAR_H2C_FW_PWRMODE:{ + rtl8821ae_set_fw_pwrmode_cmd(hw, (*(u8 *) val)); + break; + } + case HW_VAR_FW_PSMODE_STATUS: + ppsc->b_fw_current_inpsmode = *((bool *) val); + break; + + case HW_VAR_RESUME_CLK_ON: + _rtl8821ae_set_fw_ps_rf_on(hw); + break; + + case HW_VAR_FW_LPS_ACTION:{ + bool b_enter_fwlps = *((bool *) val); + + if (b_enter_fwlps) + _rtl8821ae_fwlps_enter(hw); + else + _rtl8821ae_fwlps_leave(hw); + + break; + } + + case HW_VAR_H2C_FW_JOINBSSRPT:{ + u8 mstatus = (*(u8 *) val); + u8 tmp_regcr, tmp_reg422,bcnvalid_reg; + u8 count = 0, dlbcn_count = 0; + bool b_recover = false; + + if (mstatus == RT_MEDIA_CONNECT) { + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, + NULL); + + tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr | BIT(0))); + + _rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(3)); + _rtl8821ae_set_bcn_ctrl_reg(hw, BIT(4), 0); + + tmp_reg422 = + rtl_read_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp_reg422 & (~BIT(6))); + if (tmp_reg422 & BIT(6)) + b_recover = true; + + do { + bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL+2); + rtl_write_byte(rtlpriv, REG_TDECTRL+2,(bcnvalid_reg | BIT(0))); + _rtl8821ae_return_beacon_queue_skb(hw); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_set_fw_rsvdpagepkt(hw, 0); + else + rtl8821ae_set_fw_rsvdpagepkt(hw, 0); + bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL+2); + count = 0; + while (!(bcnvalid_reg & BIT(0)) && count <20){ + count++; + udelay(10); + bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL+2); + } + dlbcn_count++; + } while (!(bcnvalid_reg & BIT(0)) && dlbcn_count <5); + + if (bcnvalid_reg & BIT(0)) + rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0)); + + _rtl8821ae_set_bcn_ctrl_reg(hw, BIT(3), 0); + _rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(4)); + + if (b_recover) { + rtl_write_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2, + tmp_reg422); + } + + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr & ~(BIT(0)))); + } + rtl8821ae_set_fw_joinbss_report_cmd(hw, (*(u8 *) val)); + + break; + } + case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:{ + rtl8821ae_set_p2p_ps_offload_cmd(hw, (*(u8 *) val)); + break; + } + + case HW_VAR_AID:{ + u16 u2btmp; + u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT); + u2btmp &= 0xC000; + rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp | + mac->assoc_id)); + + break; + } + case HW_VAR_CORRECT_TSF:{ + u8 btype_ibss = ((u8 *) (val))[0]; + + if (btype_ibss == true) + _rtl8821ae_stop_tx_beacon(hw); + + _rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(3)); + + rtl_write_dword(rtlpriv, REG_TSFTR, + (u32) (mac->tsf & 0xffffffff)); + rtl_write_dword(rtlpriv, REG_TSFTR + 4, + (u32) ((mac->tsf >> 32) & 0xffffffff)); + + _rtl8821ae_set_bcn_ctrl_reg(hw, BIT(3), 0); + + if (btype_ibss == true) + _rtl8821ae_resume_tx_beacon(hw); + + break; + + } + case HW_VAR_NAV_UPPER: { + u32 us_nav_upper = ((u32)*val); + + if(us_nav_upper > HAL_92C_NAV_UPPER_UNIT * 0xFF) + { + RT_TRACE(COMP_INIT , DBG_WARNING, + ("The setting value (0x%08X us) of NAV_UPPER" + " is larger than (%d * 0xFF)!!!\n", + us_nav_upper, HAL_92C_NAV_UPPER_UNIT)); + break; + } + rtl_write_byte(rtlpriv, REG_NAV_UPPER, + ((u8)((us_nav_upper + HAL_92C_NAV_UPPER_UNIT - 1) / HAL_92C_NAV_UPPER_UNIT))); + break; + } + case HW_VAR_KEEP_ALIVE: { + u8 array[2]; + array[0] = 0xff; + array[1] = *((u8 *)val); + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_KEEP_ALIVE_CTRL, 2, array); + } + default: + RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case " + "not process %x\n",variable)); + break; + } +} + +static bool _rtl8821ae_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool status = true; + long count = 0; + u32 value = _LLT_INIT_ADDR(address) | + _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + + rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + + do { + value = rtl_read_dword(rtlpriv, REG_LLT_INIT); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) + break; + + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Failed to polling write LLT done at " + "address %d!\n", address)); + status = false; + break; + } + } while (++count); + + return status; +} + +static bool _rtl8821ae_llt_table_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned short i; + u8 txpktbuf_bndy; + u8 maxPage; + bool status; + + maxPage = 255; + txpktbuf_bndy = 0xF8; + + + rtl_write_byte(rtlpriv, REG_TRXFF_BNDY, txpktbuf_bndy); + rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, MAX_RX_DMA_BUFFER_SIZE - 1); + + rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); + + rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + + rtl_write_byte(rtlpriv, REG_PBP, 0x31); + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + + for (i = 0; i < (txpktbuf_bndy - 1); i++) { + status = _rtl8821ae_llt_write(hw, i, i + 1); + if (true != status) + return status; + } + + status = _rtl8821ae_llt_write(hw, (txpktbuf_bndy - 1), 0xFF); + if (true != status) + return status; + + for (i = txpktbuf_bndy; i < maxPage; i++) { + status = _rtl8821ae_llt_write(hw, i, (i + 1)); + if (true != status) + return status; + } + + status = _rtl8821ae_llt_write(hw, maxPage, txpktbuf_bndy); + if (true != status) + return status; + + rtl_write_dword(rtlpriv, REG_RQPN, 0x80e70808); + rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x00); + + return true; +} + +static void _rtl8821ae_gen_refresh_led_state(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlpriv->rtlhal.up_first_time) + return; + + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_sw_led_on(hw, pLed0); + else + rtl8821ae_sw_led_on(hw, pLed0); + else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_sw_led_on(hw, pLed0); + else + rtl8821ae_sw_led_on(hw, pLed0); + else + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_sw_led_off(hw, pLed0); + else + rtl8821ae_sw_led_off(hw, pLed0); +} + +static bool _rtl8821ae_init_mac(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 bytetmp = 0; + u16 wordtmp = 0; + bool b_mac_func_enable = rtlhal->b_mac_func_enable; + + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + + /*Auto Power Down to CHIP-off State*/ + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7)); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + /* HW Power on sequence*/ + if(!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8812_NIC_ENABLE_FLOW)) { + RT_TRACE(COMP_INIT,DBG_LOUD,("init 8812 MAC Fail as power on failure\n")); + return false; + } + } else { + /* HW Power on sequence */ + if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_A_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8821A_NIC_ENABLE_FLOW)){ + RT_TRACE(COMP_INIT,DBG_LOUD,("init 8821 MAC Fail as power on failure\n")); + return false; + } + } + + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4); + rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp); + + bytetmp = rtl_read_byte(rtlpriv, REG_CR); + bytetmp = 0xff; + rtl_write_byte(rtlpriv, REG_CR, bytetmp); + mdelay(2); + + bytetmp |= 0x7f; + rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, bytetmp); + mdelay(2); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CFG + 3); + if (bytetmp & BIT(0)) { + bytetmp = rtl_read_byte(rtlpriv, 0x7c); + bytetmp |= BIT(6); + rtl_write_byte(rtlpriv, 0x7c, bytetmp); + } + } + + bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1); + bytetmp &= ~BIT(4); + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp); + + rtl_write_word(rtlpriv, REG_CR, 0x2ff); + + if (!b_mac_func_enable) { + if (!_rtl8821ae_llt_table_init(hw)) + return false; + } + + rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); + rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff); + + /* Enable FW Beamformer Interrupt */ + bytetmp = rtl_read_byte(rtlpriv, REG_FWIMR + 3); + rtl_write_byte(rtlpriv, REG_FWIMR + 3, bytetmp | BIT(6)); + + wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL); + wordtmp &= 0xf; + wordtmp |= 0xF5B1; + rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); + + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF); + /*low address*/ + rtl_write_dword(rtlpriv, REG_BCNQ_DESA, + rtlpci->tx_ring[BEACON_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_MGQ_DESA, + rtlpci->tx_ring[MGNT_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VOQ_DESA, + rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VIQ_DESA, + rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BEQ_DESA, + rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BKQ_DESA, + rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_HQ_DESA, + rtlpci->tx_ring[HIGH_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_RX_DESA, + rtlpci->rx_ring[RX_MPDU_QUEUE].dma & DMA_BIT_MASK(32)); + + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x77); + + rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + + rtl_write_byte(rtlpriv, REG_SECONDARY_CCA_CTRL, 0x3); + _rtl8821ae_gen_refresh_led_state(hw); + + return true; +} + +static void _rtl8821ae_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 reg_rrsr; + + reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + + rtl_write_dword(rtlpriv, REG_RRSR, reg_rrsr); + /* ARFB table 9 for 11ac 5G 2SS */ + rtl_write_dword(rtlpriv, REG_ARFR0 + 4, 0xfffff000); + /* ARFB table 10 for 11ac 5G 1SS */ + rtl_write_dword(rtlpriv, REG_ARFR1 + 4, 0x003ff000); + /* ARFB table 11 for 11ac 24G 1SS */ + rtl_write_dword(rtlpriv, REG_ARFR2, 0x00000015); + rtl_write_dword(rtlpriv, REG_ARFR2 + 4, 0x003ff000); + /* ARFB table 12 for 11ac 24G 1SS */ + rtl_write_dword(rtlpriv, REG_ARFR3, 0x00000015); + rtl_write_dword(rtlpriv, REG_ARFR3 + 4, 0xffcff000); + /* 0x420[7] = 0 , enable retry AMPDU in new AMPD not singal MPDU. */ + rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F00); + rtl_write_byte(rtlpriv, REG_AMPDU_MAX_TIME, 0x70); + + /*Set retry limit*/ + rtl_write_word(rtlpriv, REG_RL, 0x0707); + + + /* Set Data / Response auto rate fallack retry count*/ + rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000); + rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504); + rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); + rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); + + rtlpci->reg_bcn_ctrl_val = 0x1d; + rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val); + + /* TBTT prohibit hold time. Suggested by designer TimChen. */ + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1,0xff); // 8 ms + + /* AGGR_BK_TIME Reg51A 0x16 */ + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040); + + /*For Rx TP. Suggested by SD1 Richard. Added by tynli. 2010.04.12.*/ + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); + + rtl_write_byte(rtlpriv, REG_HT_SINGLE_AMPDU, 0x80); + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20); + rtl_write_word(rtlpriv, REG_MAX_AGGR_NUM, 0x1F1F); +} + +static u16 _rtl8821ae_mdio_read(struct rtl_priv *rtlpriv, u8 addr) +{ + u16 ret = 0; + u8 tmp = 0, count = 0; + + rtl_write_byte(rtlpriv, REG_MDIO_CTL, addr | BIT(6)); + tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(6) ; + count = 0; + while (tmp && count < 20) { + udelay(10); + tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(6); + count++; + } + if (0 == tmp) + ret = rtl_read_word(rtlpriv, REG_MDIO_RDATA); + + return ret; +} + +void _rtl8821ae_mdio_write(struct rtl_priv *rtlpriv, u8 addr, u16 data) +{ + u8 tmp = 0, count = 0; + + rtl_write_word(rtlpriv, REG_MDIO_WDATA, data); + rtl_write_byte(rtlpriv, REG_MDIO_CTL, addr | BIT(5)); + tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(5) ; + count = 0; + while (tmp && count < 20) { + udelay(10); + tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(5); + count++; + } +} + +static u8 _rtl8821ae_dbi_read(struct rtl_priv *rtlpriv, u16 addr) +{ + u16 read_addr = addr & 0xfffc; + u8 tmp = 0, count = 0, ret = 0; + + rtl_write_word(rtlpriv, REG_DBI_ADDR, read_addr); + rtl_write_byte(rtlpriv, REG_DBI_FLAG, 0x2); + tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG); + count = 0; + while (tmp && count < 20) { + udelay(10); + tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG); + count++; + } + if (0 == tmp) { + read_addr = REG_DBI_RDATA + addr % 4; + ret = rtl_read_word(rtlpriv, read_addr); + } + return ret; +} + +void _rtl8821ae_dbi_write(struct rtl_priv *rtlpriv, u16 addr, u8 data) +{ + u8 tmp = 0, count = 0; + u16 wrtie_addr, remainder = addr % 4; + + wrtie_addr = REG_DBI_WDATA + remainder; + rtl_write_byte(rtlpriv, wrtie_addr, data); + + wrtie_addr = (addr & 0xfffc) | (BIT(0) << (remainder + 12)); + rtl_write_word(rtlpriv, REG_DBI_ADDR, wrtie_addr); + + rtl_write_byte(rtlpriv, REG_DBI_FLAG, 0x1); + + tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG); + count = 0; + while (tmp && count < 20) { + udelay(10); + tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG); + count++; + } + +} + +static void _rtl8821ae_enable_aspm_back_door(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + if (_rtl8821ae_mdio_read(rtlpriv, 0x04) != 0x8544) + _rtl8821ae_mdio_write(rtlpriv, 0x04, 0x8544); + + if (_rtl8821ae_mdio_read(rtlpriv, 0x0b) != 0x0070) + _rtl8821ae_mdio_write(rtlpriv, 0x0b, 0x0070); + } + + tmp = _rtl8821ae_dbi_read(rtlpriv, 0x70f); + _rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7)); + + tmp = _rtl8821ae_dbi_read(rtlpriv, 0x719); + _rtl8821ae_dbi_write(rtlpriv, 0x719, tmp | BIT(3) | BIT(4)); + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + tmp = _rtl8821ae_dbi_read(rtlpriv, 0x718); + _rtl8821ae_dbi_write(rtlpriv, 0x718, tmp|BIT(4)); + } +} + +void rtl8821ae_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value; + u8 tmp; + + RT_TRACE(COMP_INIT, DBG_DMESG, + ("PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n", + rtlpriv->sec.pairwise_enc_algorithm, + rtlpriv->sec.group_enc_algorithm)); + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(COMP_SEC, DBG_DMESG, ("not open hw encryption\n")); + return; + } + + sec_reg_value = SCR_TxEncEnable | SCR_RxDecEnable; + + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TxUseDK; + sec_reg_value |= SCR_RxUseDK; + } + + sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + + tmp = rtl_read_byte(rtlpriv, REG_CR + 1); + rtl_write_byte(rtlpriv, REG_CR + 1, tmp | BIT(1)); + + RT_TRACE(COMP_SEC, DBG_DMESG, + ("The SECR-value %x \n", sec_reg_value)); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +#if 0 +bool _rtl8821ae_check_pcie_dma_hang(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + tmp = rtl_read_byte(rtlpriv, REG_DBI_CTRL+3); + if (!(tmp&BIT(2))) { + rtl_write_byte(rtlpriv, REG_DBI_CTRL+3, tmp|BIT(2)); + mdelay(100); + } + + tmp = rtl_read_byte(rtlpriv, REG_DBI_CTRL+3); + if (tmp&BIT(0) || tmp&BIT(1)) { + RT_TRACE(COMP_INIT, DBG_LOUD, + ("rtl8821ae_check_pcie_dma_hang(): TRUE! Reset PCIE DMA!\n")); + return true; + } else { + return false; + } +} + +void _rtl8821ae_reset_pcie_interface_dma(struct ieee80211_hw *hw, + bool mac_power_on, bool watch_dog) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + bool release_mac_rx_pause; + u8 backup_pcie_dma_pause; + + RT_TRACE(COMP_INIT, DBG_LOUD, ("_rtl8821ae_reset_pcie_interface_dma()\n")); + + tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL); + tmp &= ~BIT(1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp); + tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2); + tmp |= BIT2; + rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp); + + tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); + if (tmp & BIT(2)) { + release_mac_rx_pause = false; + } else { + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, tmp | BIT(2)); + release_mac_rx_pause = true; + } + backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+1); + if (backup_pcie_dma_pause != 0xFF) + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0xFF); + + if (mac_power_on) + rtl_write_byte(rtlpriv, REG_CR, 0); + + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); + tmp &= ~BIT(0); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, tmp); + + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); + tmp |= ~BIT(0); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, tmp); + + if (mac_power_on) + rtl_write_byte(rtlpriv, REG_CR, 0xFF); + + tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL+2); + tmp |= BIT1; + rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL+2, tmp); + + if (watch_dog) { + u32 rqpn = 0; + u32 rqpn_npq = 0; + u8 tx_page_boundary = _RQPN_Init_8812E(Adapter, &rqpn_npq, &rqpn); + + if(LLT_table_init_8812(Adapter, TX_PAGE_BOUNDARY, RQPN, RQPN_NPQ) == RT_STATUS_FAILURE) + return false; + + PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); + PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); + + // <1> Reset Tx descriptor + Adapter->HalFunc.ResetTxDescHandler(Adapter,Adapter->NumTxDesc); + + // <2> Reset Rx descriptor + Adapter->HalFunc.ResetRxDescHandler(Adapter,Adapter->NumRxDesc); + + // <3> Reset RFDs + FreeRFDs( Adapter, TRUE); + + // <4> Reset TCBs + FreeTCBs( Adapter, TRUE); + + // We should set all Rx desc own bit to 1 to prevent from RDU after enable Rx DMA. 2013.02.18, by tynli. + PrepareAllRxDescBuffer(Adapter); + + PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); + PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); + + // + // Initialize TRx DMA address. + // + // Because set 0x100 to 0x0 will cause the Rx descriptor address 0x340 be cleared to zero on 88EE, + // we should re-initialize Rx desc. address before enable DMA. 2012.11.07. by tynli. + InitTRxDescHwAddress8812AE(Adapter); + } + + // In MAC power on state, BB and RF maybe in ON state, if we release TRx DMA here + // it will cause packets to be started to Tx/Rx, so we release Tx/Rx DMA later. + if(!bInMACPowerOn || bInWatchDog) + { + // 8. release TRX DMA + //write 0x284 bit[18] = 1'b0 + //write 0x301 = 0x00 + if(bReleaseMACRxPause) + { + u1Tmp = PlatformEFIORead1Byte(Adapter, REG_RXDMA_CONTROL); + PlatformEFIOWrite1Byte(Adapter, REG_RXDMA_CONTROL, (u1Tmp&~BIT2)); + } + PlatformEFIOWrite1Byte(Adapter, REG_PCIE_CTRL_REG+1, BackUpPcieDMAPause); + } + + if(IS_HARDWARE_TYPE_8821E(Adapter)) + { + //9. lock system register + // write 0xCC bit[2] = 1'b0 + u1Tmp = PlatformEFIORead1Byte(Adapter, REG_PMC_DBG_CTRL2_8723B); + u1Tmp &= ~(BIT2); + PlatformEFIOWrite1Byte(Adapter, REG_PMC_DBG_CTRL2_8723B, u1Tmp); + } + + return RT_STATUS_SUCCESS; +} +#endif + +// Static MacID Mapping (cf. Used in MacIdDoStaticMapping) ---------- +#define MAC_ID_STATIC_FOR_DEFAULT_PORT 0 +#define MAC_ID_STATIC_FOR_BROADCAST_MULTICAST 1 +#define MAC_ID_STATIC_FOR_BT_CLIENT_START 2 +#define MAC_ID_STATIC_FOR_BT_CLIENT_END 3 +// ----------------------------------------------------------- + +void rtl8821ae_macid_initialize_mediastatus(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 media_rpt[4] = {RT_MEDIA_CONNECT, 1, \ + MAC_ID_STATIC_FOR_BROADCAST_MULTICAST, \ + MAC_ID_STATIC_FOR_BT_CLIENT_END}; + + rtlpriv->cfg->ops->set_hw_reg(hw, \ + HW_VAR_H2C_FW_MEDIASTATUSRPT, media_rpt); + + RT_TRACE(COMP_INIT,DBG_LOUD, \ + ("Initialize MacId media status: from %d to %d\n", \ + MAC_ID_STATIC_FOR_BROADCAST_MULTICAST, \ + MAC_ID_STATIC_FOR_BT_CLIENT_END)); +} + +int rtl8821ae_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool rtstatus = true; + int err; + u8 tmp_u1b; + u32 nav_upper = WIFI_NAV_UPPER_US; + + rtlpriv->rtlhal.being_init_adapter = true; + rtlpriv->intf_ops->disable_aspm(hw); + + /*YP wowlan not considered*/ + + tmp_u1b = rtl_read_byte(rtlpriv, REG_CR); + if (tmp_u1b!=0 && tmp_u1b != 0xEA) { + rtlhal->b_mac_func_enable = true; + RT_TRACE(COMP_INIT,DBG_LOUD,(" MAC has already power on.\n")); + } else { + rtlhal->b_mac_func_enable = false; + rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_8821AE; + } + +/* if (_rtl8821ae_check_pcie_dma_hang(hw)) { + _rtl8821ae_reset_pcie_interface_dma(hw,rtlhal->b_mac_func_enable,false); + rtlhal->b_mac_func_enable = false; + } */ + + rtstatus = _rtl8821ae_init_mac(hw); + if (rtstatus != true) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("Init MAC failed\n")); + err = 1; + return err; + } + + tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CFG); + tmp_u1b &= 0x7F; + rtl_write_byte(rtlpriv, REG_SYS_CFG, tmp_u1b); + + err = rtl8821ae_download_fw(hw, false); + if (err) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("Failed to download FW. Init HW " + "without FW now..\n")); + err = 1; + rtlhal->bfw_ready = false; + return err; + } else { + rtlhal->bfw_ready = true; + } + rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_8821AE; + rtlhal->bfw_clk_change_in_progress = false; + rtlhal->ballow_sw_to_change_hwclc = false; + rtlhal->last_hmeboxnum = 0; + + /*SIC_Init(Adapter); + if(pHalData->AMPDUBurstMode) + PlatformEFIOWrite1Byte(Adapter,REG_AMPDU_BURST_MODE_8812, 0x7F);*/ + + rtl8821ae_phy_mac_config(hw); + /* because last function modify RCR, so we update + * rcr var here, or TP will unstable for receive_config + * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx + * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252 + rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); + rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);*/ + rtl8821ae_phy_bb_config(hw); + + rtl8821ae_phy_rf_config(hw); + + _rtl8821ae_hw_configure(hw); + + rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_2_4G); + + /*set wireless mode*/ + + rtlhal->b_mac_func_enable = true; + + rtl_cam_reset_all_entry(hw); + + rtl8821ae_enable_hw_security_config(hw); + + ppsc->rfpwr_state = ERFON; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + _rtl8821ae_enable_aspm_back_door(hw); + rtlpriv->intf_ops->enable_aspm(hw); + + //rtl8821ae_bt_hw_init(hw); + rtlpriv->rtlhal.being_init_adapter = false; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_NAV_UPPER, (u8 *)&nav_upper); + + //rtl8821ae_dm_check_txpower_tracking(hw); + //rtl8821ae_phy_lc_calibrate(hw); + + /* Release Rx DMA*/ + tmp_u1b = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); + if (tmp_u1b & BIT(2)) { + /* Release Rx DMA if needed*/ + tmp_u1b &= ~BIT(2); + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, tmp_u1b); + } + + /* Release Tx/Rx PCIE DMA if*/ + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0); + + rtl8821ae_dm_init(hw); + rtl8821ae_macid_initialize_mediastatus(hw); + + RT_TRACE(COMP_INIT, DBG_LOUD, ("rtl8821ae_hw_init() <====\n")); + return err; +} + +static enum version_8821ae _rtl8821ae_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + enum version_8821ae version = VERSION_UNKNOWN; + u32 value32; + + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1); + RT_TRACE(COMP_INIT, DBG_LOUD, ("ReadChipVersion8812A 0xF0 = 0x%x \n", value32)); + + + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtlphy->rf_type = RF_2T2R; + else if(rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + rtlphy->rf_type = RF_1T1R; + + RT_TRACE(COMP_INIT, DBG_LOUD, ("RF_Type is %x!!\n", rtlphy->rf_type)); + + + if (value32 & TRP_VAUX_EN) + { + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + if(rtlphy->rf_type == RF_2T2R) + version = VERSION_TEST_CHIP_2T2R_8812; + else + version = VERSION_TEST_CHIP_1T1R_8812; + } + else + version = VERSION_TEST_CHIP_8821; + } else { + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + u32 rtl_id = ((value32 & CHIP_VER_RTL_MASK) >> 12) +1 ; + + if(rtlphy->rf_type == RF_2T2R) + version = (enum version_8821ae)(CHIP_8812 | NORMAL_CHIP | RF_TYPE_2T2R); + else + version = (enum version_8821ae)(CHIP_8812 | NORMAL_CHIP); + + version = (enum version_8821ae)(version| (rtl_id << 12)); + } + else if(rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + { + u32 rtl_id = value32 & CHIP_VER_RTL_MASK; + + version = (enum version_8821ae)(CHIP_8821 | NORMAL_CHIP | rtl_id); + } + } + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ? + "RF_2T2R" : "RF_1T1R")); + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + { + /*WL_HWROF_EN.*/ + value32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL); + rtlphy->hw_rof_enable= ((value32 & WL_HWROF_EN) ? 1 : 0); + } + + switch(version) + { + case VERSION_TEST_CHIP_1T1R_8812: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_TEST_CHIP_1T1R_8812.\n")); + break; + case VERSION_TEST_CHIP_2T2R_8812: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_TEST_CHIP_2T2R_8812.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_1T1R_8812: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_1T1R_8812.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_2T2R_8812: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_2T2R_8812.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_1T1R_8812_C_CUT: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_1T1R_8812 C CUT.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_2T2R_8812_C_CUT: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_2T2R_8812 C CUT.\n")); + break; + case VERSION_TEST_CHIP_8821: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_TEST_CHIP_8821.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_8821: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_8821 A CUT.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_8821_B_CUT: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_8821 B CUT.\n")); + break; + default: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Chip Version ID: Unknow (0x%X).\n", version)); + break; + } + + return version; +} + +static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bt_msr = rtl_read_byte(rtlpriv, MSR); + enum led_ctl_mode ledaction = LED_CTL_NO_LINK; + bt_msr &= 0xfc; + + rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0); + RT_TRACE(COMP_BEACON, DBG_LOUD, + ("clear 0x550 when set HW_VAR_MEDIA_STATUS\n")); + + if (type == NL80211_IFTYPE_UNSPECIFIED || + type == NL80211_IFTYPE_STATION) { + _rtl8821ae_stop_tx_beacon(hw); + _rtl8821ae_enable_bcn_sub_func(hw); + } else if (type == NL80211_IFTYPE_ADHOC || + type == NL80211_IFTYPE_AP) { + _rtl8821ae_resume_tx_beacon(hw); + _rtl8821ae_disable_bcn_sub_func(hw); + } else { + RT_TRACE(COMP_ERR, DBG_WARNING,("Set HW_VAR_MEDIA_STATUS: " + "No such media status(%x).\n", type)); + } + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= MSR_NOLINK; + ledaction = LED_CTL_LINK; + RT_TRACE(COMP_INIT, DBG_TRACE, ("Set Network type to NO LINK!\n")); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= MSR_ADHOC; + RT_TRACE(COMP_INIT, DBG_TRACE, ("Set Network type to Ad Hoc!\n")); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= MSR_INFRA; + ledaction = LED_CTL_LINK; + RT_TRACE(COMP_INIT, DBG_TRACE, ("Set Network type to STA!\n")); + break; + case NL80211_IFTYPE_AP: + bt_msr |= MSR_AP; + RT_TRACE(COMP_INIT, DBG_TRACE, ("Set Network type to AP!\n")); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, ("Network type %d not support!\n", type)); + return 1; + break; + + } + + rtl_write_byte(rtlpriv, (MSR), bt_msr); + rtlpriv->cfg->ops->led_control(hw, ledaction); + if ((bt_msr & 0xfc) == MSR_AP) + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); + else + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); + + return 0; +} + +void rtl8821ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 reg_rcr = rtlpci->receive_config; + + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (check_bssid == true) { + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *) (®_rcr)); + _rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(4)); + } else if (check_bssid == false) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + _rtl8821ae_set_bcn_ctrl_reg(hw, BIT(4), 0); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_RCR, (u8 *) (®_rcr)); + } + +} + +int rtl8821ae_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_INIT, DBG_LOUD, ("rtl8821ae_set_network_type!\n")); + + if (_rtl8821ae_set_media_status(hw, type)) + return -EOPNOTSUPP; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl8821ae_set_check_bssid(hw, true); + } else { + rtl8821ae_set_check_bssid(hw, false); + } + + return 0; +} + +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ +void rtl8821ae_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl8821ae_dm_init_edca_turbo(hw); + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); + break; + case AC0_BE: + /* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */ + break; + case AC2_VI: + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); + break; + default: + RT_ASSERT(false, ("invalid aci: %d !\n", aci)); + break; + } +} + +void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); + rtlpci->irq_enabled = true; + /* there are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. + *So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. + */ + //rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0); + /*enable system interrupt*/ + rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF); +} + +void rtl8821ae_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED); + rtlpci->irq_enabled = false; + synchronize_irq(rtlpci->pdev->irq); +} + +static void _rtl8821ae_poweroff_adapter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 u1b_tmp; + + rtlhal->b_mac_func_enable = false; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + /* Combo (PCIe + USB) Card and PCIe-MF Card */ + /* 1. Run LPS WL RFOFF flow */ + //RT_TRACE(COMP_INIT, DBG_LOUD, ("=====>CardDisableRTL8812E,RTL8821A_NIC_LPS_ENTER_FLOW\n")); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8821A_NIC_LPS_ENTER_FLOW); + } + /* 2. 0x1F[7:0] = 0 */ + /* turn off RF */ + //rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); + if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && + rtlhal->bfw_ready ) { + rtl8821ae_firmware_selfreset(hw); + } + + /* Reset MCU. Suggested by Filen. */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2)))); + + /* g. MCUFWDL 0x80[1:0]=0 */ + /* reset MCU ready status */ + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + /* HW card disable configuration. */ + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8821A_NIC_DISABLE_FLOW); + } else { + /* HW card disable configuration. */ + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8812_NIC_DISABLE_FLOW); + } + + /* Reset MCU IO Wrapper */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0)))); + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0)); + + /* 7. RSV_CTRL 0x1C[7:0] = 0x0E */ + /* lock ISO/CLK/Power control register */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); +} + +void rtl8821ae_card_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum nl80211_iftype opmode; + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("rtl8821ae_card_disable.\n")); + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl8821ae_set_media_status(hw, opmode); + if (rtlpriv->rtlhal.driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + _rtl8821ae_poweroff_adapter(hw); + + /* after power off we should do iqk again */ + rtlpriv->phy.iqk_initialized = false; +} + +void rtl8821ae_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; + rtl_write_dword(rtlpriv, ISR, *p_inta); + + + *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1]; + rtl_write_dword(rtlpriv, REG_HISRE, *p_intb); + +} + + +void rtl8821ae_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u16 bcn_interval, atim_window; + + bcn_interval = mac->beacon_interval; + atim_window = 2; /*FIX MERGE */ + rtl8821ae_disable_interrupt(hw); + rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18); + rtl_write_byte(rtlpriv, 0x606, 0x30); + rtlpci->reg_bcn_ctrl_val |= BIT(3); + rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); + rtl8821ae_enable_interrupt(hw); +} + +void rtl8821ae_set_beacon_interval(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval = mac->beacon_interval; + + RT_TRACE(COMP_BEACON, DBG_DMESG, + ("beacon_interval:%d\n", bcn_interval)); + rtl8821ae_disable_interrupt(hw); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + rtl8821ae_enable_interrupt(hw); +} + +void rtl8821ae_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + RT_TRACE(COMP_INTR, DBG_LOUD, + ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + + if (add_msr) + rtlpci->irq_mask[0] |= add_msr; + if (rm_msr) + rtlpci->irq_mask[0] &= (~rm_msr); + rtl8821ae_disable_interrupt(hw); + rtl8821ae_enable_interrupt(hw); +} + +static u8 _rtl8821ae_get_chnl_group(u8 chnl) +{ + u8 group = 0; + + if (chnl <= 14) { + if (1 <= chnl && chnl <= 2 ) + group = 0; + else if (3 <= chnl && chnl <= 5 ) + group = 1; + else if (6 <= chnl && chnl <= 8 ) + group = 2; + else if (9 <= chnl && chnl <= 11) + group = 3; + else /*if (12 <= chnl && chnl <= 14)*/ + group = 4; + } else { + if (36 <= chnl && chnl <= 42) + group = 0; + else if (44 <= chnl && chnl <= 48) + group = 1; + else if (50 <= chnl && chnl <= 58) + group = 2; + else if (60 <= chnl && chnl <= 64) + group = 3; + else if (100 <= chnl && chnl <= 106) + group = 4; + else if (108 <= chnl && chnl <= 114) + group = 5; + else if (116 <= chnl && chnl <= 122) + group = 6; + else if (124 <= chnl && chnl <= 130) + group = 7; + else if (132 <= chnl && chnl <= 138) + group = 8; + else if (140 <= chnl && chnl <= 144) + group = 9; + else if (149 <= chnl && chnl <= 155) + group = 10; + else if (157 <= chnl && chnl <= 161) + group = 11; + else if (165 <= chnl && chnl <= 171) + group = 12; + else if (173 <= chnl && chnl <= 177) + group = 13; + else + /*RT_TRACE(COMP_EFUSE,DBG_LOUD, + ("5G, Channel %d in Group not found \n",chnl));*/ + RT_ASSERT(!COMP_EFUSE, + ("5G, Channel %d in Group not found \n",chnl)); + } + return group; +} + +static void _rtl8821ae_read_power_value_fromprom(struct ieee80211_hw *hw, + struct txpower_info_2g *pwrinfo24g, + struct txpower_info_5g *pwrinfo5g, + bool autoload_fail, + u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 rfPath, eeAddr=EEPROM_TX_PWR_INX, group,TxCount=0; + + RT_TRACE(COMP_INIT, DBG_LOUD, ("hal_ReadPowerValueFromPROM8821ae(): PROMContent[0x%x]=0x%x\n", (eeAddr+1), hwinfo[eeAddr+1])); + if (0xFF == hwinfo[eeAddr+1]) /*YJ,add,120316*/ + autoload_fail = true; + + if (autoload_fail) + { + RT_TRACE(COMP_INIT, DBG_LOUD, ("auto load fail : Use Default value!\n")); + for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) { + /*2.4G default value*/ + for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) { + pwrinfo24g->index_cck_base[rfPath][group] = 0x2D; + pwrinfo24g->index_bw40_base[rfPath][group] = 0x2D; + } + for (TxCount = 0;TxCount < MAX_TX_COUNT;TxCount++) { + if (TxCount == 0) { + pwrinfo24g->bw20_diff[rfPath][0] = 0x02; + pwrinfo24g->ofdm_diff[rfPath][0] = 0x04; + } else { + pwrinfo24g->bw20_diff[rfPath][TxCount] = 0xFE; + pwrinfo24g->bw40_diff[rfPath][TxCount] = 0xFE; + pwrinfo24g->cck_diff[rfPath][TxCount] = 0xFE; + pwrinfo24g->ofdm_diff[rfPath][TxCount] = 0xFE; + } + } + /*5G default value*/ + for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++) + pwrinfo5g->index_bw40_base[rfPath][group] = 0x2A; + + for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { + if (TxCount == 0) { + pwrinfo5g->ofdm_diff[rfPath][0] = 0x04; + pwrinfo5g->bw20_diff[rfPath][0] = 0x00; + pwrinfo5g->bw80_diff[rfPath][0] = 0xFE; + pwrinfo5g->bw160_diff[rfPath][0] = 0xFE; + } else { + pwrinfo5g->ofdm_diff[rfPath][0] = 0xFE; + pwrinfo5g->bw20_diff[rfPath][0] = 0xFE; + pwrinfo5g->bw40_diff[rfPath][0] = 0xFE; + pwrinfo5g->bw80_diff[rfPath][0] = 0xFE; + pwrinfo5g->bw160_diff[rfPath][0] = 0xFE; + } + } + } + return; + } + + rtl_priv(hw)->efuse.b_txpwr_fromeprom = true; + + for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) { + /*2.4G default value*/ + for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) { + pwrinfo24g->index_cck_base[rfPath][group] = hwinfo[eeAddr++]; + if (pwrinfo24g->index_cck_base[rfPath][group] == 0xFF) + pwrinfo24g->index_cck_base[rfPath][group] = 0x2D; + } + for (group = 0 ; group < MAX_CHNL_GROUP_24G - 1; group++) { + pwrinfo24g->index_bw40_base[rfPath][group] = hwinfo[eeAddr++]; + if (pwrinfo24g->index_bw40_base[rfPath][group] == 0xFF) + pwrinfo24g->index_bw40_base[rfPath][group] = 0x2D; + } + for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount ++) { + if (TxCount == 0) { + pwrinfo24g->bw40_diff[rfPath][TxCount] = 0; + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo24g->bw20_diff[rfPath][TxCount] = 0x02; + } else { + pwrinfo24g->bw20_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0xf0) >> 4; + if (pwrinfo24g->bw20_diff[rfPath][TxCount] & BIT(3)) /*bit sign number to 8 bit sign number*/ + pwrinfo24g->bw20_diff[rfPath][TxCount] |= 0xF0; + } + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo24g->ofdm_diff[rfPath][TxCount] = 0x04; + } else { + pwrinfo24g->ofdm_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f); + if(pwrinfo24g->ofdm_diff[rfPath][TxCount] & BIT(3)) /*bit sign number to 8 bit sign number*/ + pwrinfo24g->ofdm_diff[rfPath][TxCount] |= 0xF0; + } + pwrinfo24g->cck_diff[rfPath][TxCount] = 0; + eeAddr++; + } else { + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo24g->bw40_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo24g->bw40_diff[rfPath][TxCount] = (hwinfo[eeAddr]&0xf0) >> 4; + if (pwrinfo24g->bw40_diff[rfPath][TxCount] & BIT(3)) + pwrinfo24g->bw40_diff[rfPath][TxCount] |= 0xF0; + } + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo24g->bw20_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo24g->bw20_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f); + if (pwrinfo24g->bw20_diff[rfPath][TxCount] & BIT(3)) + pwrinfo24g->bw20_diff[rfPath][TxCount] |= 0xF0; + } + + eeAddr++; + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo24g->ofdm_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo24g->ofdm_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0xf0) >> 4; + if(pwrinfo24g->ofdm_diff[rfPath][TxCount] & BIT(3)) + pwrinfo24g->ofdm_diff[rfPath][TxCount] |= 0xF0; + } + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo24g->cck_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo24g->cck_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f); + if(pwrinfo24g->cck_diff[rfPath][TxCount] & BIT(3)) + pwrinfo24g->cck_diff[rfPath][TxCount] |= 0xF0; + } + eeAddr++; + } + } + + /*5G default value*/ + for (group = 0 ; group < MAX_CHNL_GROUP_5G; group ++) { + pwrinfo5g->index_bw40_base[rfPath][group] = hwinfo[eeAddr++]; + if (pwrinfo5g->index_bw40_base[rfPath][group] == 0xFF) + pwrinfo5g->index_bw40_base[rfPath][group] = 0xFE; + } + + for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { + if (TxCount == 0) { + pwrinfo5g->bw40_diff[rfPath][TxCount] = 0; + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo5g->bw20_diff[rfPath][TxCount] = 0x0; + } else { + pwrinfo5g->bw20_diff[rfPath][0] = (hwinfo[eeAddr] & 0xf0) >> 4; + if(pwrinfo5g->bw20_diff[rfPath][TxCount] & BIT(3)) + pwrinfo5g->bw20_diff[rfPath][TxCount] |= 0xF0; + } + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo5g->ofdm_diff[rfPath][TxCount] = 0x4; + } else { + pwrinfo5g->ofdm_diff[rfPath][0] = (hwinfo[eeAddr] & 0x0f); + if(pwrinfo5g->ofdm_diff[rfPath][TxCount] & BIT(3)) + pwrinfo5g->ofdm_diff[rfPath][TxCount] |= 0xF0; + } + eeAddr++; + } else { + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo5g->bw40_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo5g->bw40_diff[rfPath][TxCount]= (hwinfo[eeAddr] & 0xf0) >> 4; + if(pwrinfo5g->bw40_diff[rfPath][TxCount] & BIT(3)) + pwrinfo5g->bw40_diff[rfPath][TxCount] |= 0xF0; + } + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo5g->bw20_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo5g->bw20_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f); + if(pwrinfo5g->bw20_diff[rfPath][TxCount] & BIT(3)) + pwrinfo5g->bw20_diff[rfPath][TxCount] |= 0xF0; + } + eeAddr++; + } + } + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo5g->ofdm_diff[rfPath][1] = 0xFE; + pwrinfo5g->ofdm_diff[rfPath][2] = 0xFE; + } else { + pwrinfo5g->ofdm_diff[rfPath][1] = (hwinfo[eeAddr] & 0xf0) >> 4; + pwrinfo5g->ofdm_diff[rfPath][2] = (hwinfo[eeAddr] & 0x0f); + } + eeAddr++; + if (hwinfo[eeAddr] == 0xFF) + pwrinfo5g->ofdm_diff[rfPath][3] = 0xFE; + else + pwrinfo5g->ofdm_diff[rfPath][3] = (hwinfo[eeAddr] & 0x0f); + + eeAddr++; + + for (TxCount = 1; TxCount < MAX_TX_COUNT; TxCount++) { + if (pwrinfo5g->ofdm_diff[rfPath][TxCount] == 0xFF) + pwrinfo5g->ofdm_diff[rfPath][TxCount] = 0xFE; + else if(pwrinfo5g->ofdm_diff[rfPath][TxCount] & BIT(3)) + pwrinfo5g->ofdm_diff[rfPath][TxCount] |= 0xF0; + } + for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo5g->bw80_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo5g->bw80_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0xf0) >> 4; + if(pwrinfo5g->bw80_diff[rfPath][TxCount] & BIT(3)) //4bit sign number to 8 bit sign number + pwrinfo5g->bw80_diff[rfPath][TxCount] |= 0xF0; + } + + if (hwinfo[eeAddr] == 0xFF) { + pwrinfo5g->bw160_diff[rfPath][TxCount] = 0xFE; + } else { + pwrinfo5g->bw160_diff[rfPath][TxCount]= (hwinfo[eeAddr] & 0x0f); + if(pwrinfo5g->bw160_diff[rfPath][TxCount] & BIT(3)) //4bit sign number to 8 bit sign number + pwrinfo5g->bw160_diff[rfPath][TxCount] |= 0xF0; + } + eeAddr++; + } + } +} + +static void _rtl8812ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct txpower_info_2g pwrinfo24g; + struct txpower_info_5g pwrinfo5g; + u8 channel5g[CHANNEL_MAX_NUMBER_5G] = + {36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,100,102,104,106,108,110,112, + 114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,149,151, + 153,155,157,159,161,163,165,167,168,169,171,173,175,177}; + u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171}; + u8 rf_path, index; + u8 i; + + _rtl8821ae_read_power_value_fromprom(hw, &pwrinfo24g, &pwrinfo5g, autoload_fail, hwinfo); + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < CHANNEL_MAX_NUMBER_2G; i++) { + index = _rtl8821ae_get_chnl_group(i + 1); + + if (i == CHANNEL_MAX_NUMBER_2G - 1) { + rtlefuse->txpwrlevel_cck[rf_path][i] = + pwrinfo24g.index_cck_base[rf_path][5]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + pwrinfo24g.index_bw40_base[rf_path][index]; + } else { + rtlefuse->txpwrlevel_cck[rf_path][i] = + pwrinfo24g.index_cck_base[rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + pwrinfo24g.index_bw40_base[rf_path][index]; + } + } + + for (i = 0; i < CHANNEL_MAX_NUMBER_5G; i++) { + index = _rtl8821ae_get_chnl_group(channel5g[i]); + rtlefuse->txpwr_5g_bw40base[rf_path][i] = pwrinfo5g.index_bw40_base[rf_path][index]; + } + for (i = 0; i < CHANNEL_MAX_NUMBER_5G_80M; i++) { + u8 upper, lower; + index = _rtl8821ae_get_chnl_group(channel5g_80m[i]); + upper = pwrinfo5g.index_bw40_base[rf_path][index]; + lower = pwrinfo5g.index_bw40_base[rf_path][index + 1]; + + rtlefuse->txpwr_5g_bw80base[rf_path][i] = (upper + lower) / 2; + } + for (i = 0; i < MAX_TX_COUNT; i++) { + rtlefuse->txpwr_cckdiff[rf_path][i] = pwrinfo24g.cck_diff[rf_path][i]; + rtlefuse->txpwr_legacyhtdiff[rf_path][i] = pwrinfo24g.ofdm_diff[rf_path][i]; + rtlefuse->txpwr_ht20diff[rf_path][i] = pwrinfo24g.bw20_diff[rf_path][i]; + rtlefuse->txpwr_ht40diff[rf_path][i] = pwrinfo24g.bw40_diff[rf_path][i]; + + rtlefuse->txpwr_5g_ofdmdiff[rf_path][i] = pwrinfo5g.ofdm_diff[rf_path][i]; + rtlefuse->txpwr_5g_bw20diff[rf_path][i] = pwrinfo5g.bw20_diff[rf_path][i]; + rtlefuse->txpwr_5g_bw40diff[rf_path][i] = pwrinfo5g.bw40_diff[rf_path][i]; + rtlefuse->txpwr_5g_bw80diff[rf_path][i] = pwrinfo5g.bw80_diff[rf_path][i]; + } + } + + if (!autoload_fail){ + rtlefuse->eeprom_regulatory = + hwinfo[EEPROM_RF_BOARD_OPTION] & 0x07;/*bit0~2*/ + if (hwinfo[EEPROM_RF_BOARD_OPTION] == 0xFF) + rtlefuse->eeprom_regulatory = 0; + } else { + rtlefuse->eeprom_regulatory = 0; + } + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory )); +} + +static void _rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct txpower_info_2g pwrinfo24g; + struct txpower_info_5g pwrinfo5g; + u8 channel5g[CHANNEL_MAX_NUMBER_5G] = + {36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,100,102,104,106,108,110,112, + 114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,149,151, + 153,155,157,159,161,163,165,167,168,169,171,173,175,177}; + u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171}; + u8 rf_path, index; + u8 i; + + _rtl8821ae_read_power_value_fromprom(hw, &pwrinfo24g, &pwrinfo5g, autoload_fail, hwinfo); + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < CHANNEL_MAX_NUMBER_2G; i++) { + index = _rtl8821ae_get_chnl_group(i + 1); + + if (i == CHANNEL_MAX_NUMBER_2G - 1) { + rtlefuse->txpwrlevel_cck[rf_path][i] = pwrinfo24g.index_cck_base[rf_path][5]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = pwrinfo24g.index_bw40_base[rf_path][index]; + } else { + rtlefuse->txpwrlevel_cck[rf_path][i] = pwrinfo24g.index_cck_base[rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = pwrinfo24g.index_bw40_base[rf_path][index]; + } + } + + for (i = 0; i < CHANNEL_MAX_NUMBER_5G; i++) { + index = _rtl8821ae_get_chnl_group(channel5g[i]); + rtlefuse->txpwr_5g_bw40base[rf_path][i] = pwrinfo5g.index_bw40_base[rf_path][index]; + } + for (i = 0; i < CHANNEL_MAX_NUMBER_5G_80M; i++) { + u8 upper, lower; + index = _rtl8821ae_get_chnl_group(channel5g_80m[i]); + upper = pwrinfo5g.index_bw40_base[rf_path][index]; + lower = pwrinfo5g.index_bw40_base[rf_path][index + 1]; + + rtlefuse->txpwr_5g_bw80base[rf_path][i] = (upper + lower) / 2; + } + for (i = 0; i < MAX_TX_COUNT; i++) { + rtlefuse->txpwr_cckdiff[rf_path][i] = pwrinfo24g.cck_diff[rf_path][i]; + rtlefuse->txpwr_legacyhtdiff[rf_path][i] = pwrinfo24g.ofdm_diff[rf_path][i]; + rtlefuse->txpwr_ht20diff[rf_path][i] = pwrinfo24g.bw20_diff[rf_path][i]; + rtlefuse->txpwr_ht40diff[rf_path][i] = pwrinfo24g.bw40_diff[rf_path][i]; + + rtlefuse->txpwr_5g_ofdmdiff[rf_path][i] = pwrinfo5g.ofdm_diff[rf_path][i]; + rtlefuse->txpwr_5g_bw20diff[rf_path][i] = pwrinfo5g.bw20_diff[rf_path][i]; + rtlefuse->txpwr_5g_bw40diff[rf_path][i] = pwrinfo5g.bw40_diff[rf_path][i]; + rtlefuse->txpwr_5g_bw80diff[rf_path][i] = pwrinfo5g.bw80_diff[rf_path][i]; + } + } + + if (!autoload_fail){ + rtlefuse->eeprom_regulatory = hwinfo[EEPROM_RF_BOARD_OPTION] & 0x07;/*bit0~2*/ + if (hwinfo[EEPROM_RF_BOARD_OPTION] == 0xFF) + rtlefuse->eeprom_regulatory = 0; + } else { + rtlefuse->eeprom_regulatory = 0; + } + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory )); +} + +static void _rtl8812ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_test ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u16 i, usvalue; + u8 hwinfo[HWSET_MAX_SIZE]; + u16 eeprom_id; + + if (b_pseudo_test) { + /* need add */ + } + + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + rtl_efuse_shadow_map_update(hw); + memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE); + } else if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("RTL819X Not boot from eeprom, check it !!")); + } + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP \n"), + hwinfo, HWSET_MAX_SIZE); + + eeprom_id = *((u16 *) & hwinfo[0]); + if (eeprom_id != RTL_EEPROM_ID) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag == true) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("RTL8812AE autoload_failflag, check it !!")); + return; + } + + rtlefuse->eeprom_version = *(u8 *) & hwinfo[EEPROM_VERSION]; + if (rtlefuse->eeprom_version == 0xff) + rtlefuse->eeprom_version = 0; + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM version: 0x%2x\n", rtlefuse->eeprom_version)); + + rtlefuse->eeprom_vid = *(u16 *) &hwinfo[EEPROM_VID]; + rtlefuse->eeprom_did = *(u16 *) &hwinfo[EEPROM_DID]; + rtlefuse->eeprom_svid = *(u16 *) &hwinfo[EEPROM_SVID]; + rtlefuse->eeprom_smid = *(u16 *) &hwinfo[EEPROM_SMID]; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROMId = 0x%4x\n", eeprom_id)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid)); + + /*customer ID*/ + rtlefuse->eeprom_oemid = *(u8 *) & hwinfo[EEPROM_CUSTOMER_ID]; + if (rtlefuse->eeprom_oemid == 0xFF) + rtlefuse->eeprom_oemid = 0; + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *) & hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + + RT_TRACE(COMP_INIT, DBG_DMESG, + ("dev_addr: %pM\n", rtlefuse->dev_addr)); + + _rtl8812ae_read_txpower_info_from_hwpg(hw, + rtlefuse->autoload_failflag, hwinfo); + + /*board type*/ + rtlefuse->board_type = (((*(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION]) & 0xE0 ) >> 5); + if ((*(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION]) == 0xff ) + rtlefuse->board_type = 0; + rtlhal->boad_type = rtlefuse->board_type; + + rtl8812ae_read_bt_coexist_info_from_hwpg(hw, + rtlefuse->autoload_failflag, hwinfo); + + rtlefuse->eeprom_channelplan = *(u8 *) & hwinfo[EEPROM_CHANNELPLAN]; + if (rtlefuse->eeprom_channelplan == 0xff) + rtlefuse->eeprom_channelplan = 0x7F; + + /* set channel paln to world wide 13 */ + //rtlefuse->channel_plan = (u8) rtlefuse->eeprom_channelplan; + + /*parse xtal*/ + rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8821AE]; + if ( rtlefuse->crystalcap == 0xFF ) + rtlefuse->crystalcap = 0x20; + + rtlefuse->eeprom_thermalmeter = *(u8 *) & hwinfo[EEPROM_THERMAL_METER]; + if ((rtlefuse->eeprom_thermalmeter == 0xff) ||rtlefuse->autoload_failflag ) + { + rtlefuse->b_apk_thermalmeterignore = true; + rtlefuse->eeprom_thermalmeter = 0xff; + } + + rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter)); + + if (rtlefuse->autoload_failflag == false) { + rtlefuse->antenna_div_cfg = *(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION] & 0x18 >> 3; + if (*(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION] == 0xff) + rtlefuse->antenna_div_cfg = 0x00; + /*if (BT_1ant()) + rtlefuse->antenna_div_cfg = 0;*/ + rtlefuse->antenna_div_type = *(u8 *) & hwinfo[EEPROM_RF_ANTENNA_OPT_88E]; + if (rtlefuse->antenna_div_type == 0xFF) + { + rtlefuse->antenna_div_type = FIXED_HW_ANTDIV; + } + } else { + rtlefuse->antenna_div_cfg = 0; + rtlefuse->antenna_div_type = 0; + } + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("SWAS: bHwAntDiv = %x, TRxAntDivType = %x\n", + rtlefuse->antenna_div_cfg, rtlefuse->antenna_div_type)); + + /*Hal_ReadPAType_8821A()*/ + /*Hal_EfuseParseRateIndicationOption8821A()*/ + /*Hal_ReadEfusePCIeCap8821AE()*/ + + pcipriv->ledctl.bled_opendrain = true; + + if (rtlhal->oem_id == RT_CID_DEFAULT) { + switch (rtlefuse->eeprom_oemid) { + case RT_CID_DEFAULT: + break; + case EEPROM_CID_TOSHIBA: + rtlhal->oem_id = RT_CID_TOSHIBA; + break; + case EEPROM_CID_CCX: + rtlhal->oem_id = RT_CID_CCX; + break; + case EEPROM_CID_QMI: + rtlhal->oem_id = RT_CID_819x_QMI; + break; + case EEPROM_CID_WHQL: + break; + default: + break; + + } + } +} + +static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_test ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u16 i, usvalue; + u8 hwinfo[HWSET_MAX_SIZE]; + u16 eeprom_id; + + if (b_pseudo_test) { + /* need add */ + } + + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + rtl_efuse_shadow_map_update(hw); + memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE); + } else if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("RTL819X Not boot from eeprom, check it !!")); + } + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP \n"), + hwinfo, HWSET_MAX_SIZE); + + eeprom_id = *((u16 *) & hwinfo[0]); + if (eeprom_id != RTL_EEPROM_ID) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag == true) { + RT_TRACE(COMP_ERR, DBG_EMERG, + ("RTL8812AE autoload_failflag, check it !!")); + return; + } + + rtlefuse->eeprom_version = *(u8 *) & hwinfo[EEPROM_VERSION]; + if (rtlefuse->eeprom_version == 0xff) + rtlefuse->eeprom_version = 0; + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM version: 0x%2x\n", rtlefuse->eeprom_version)); + + rtlefuse->eeprom_vid = *(u16 *) &hwinfo[EEPROM_VID]; + rtlefuse->eeprom_did = *(u16 *) &hwinfo[EEPROM_DID]; + rtlefuse->eeprom_svid = *(u16 *) &hwinfo[EEPROM_SVID]; + rtlefuse->eeprom_smid = *(u16 *) &hwinfo[EEPROM_SMID]; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROMId = 0x%4x\n", eeprom_id)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid)); + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid)); + + /*customer ID*/ + rtlefuse->eeprom_oemid = *(u8 *) & hwinfo[EEPROM_CUSTOMER_ID]; + if (rtlefuse->eeprom_oemid == 0xFF) + rtlefuse->eeprom_oemid = 0; + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *) & hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + + RT_TRACE(COMP_INIT, DBG_DMESG, + ("dev_addr: %pM\n", rtlefuse->dev_addr)); + + _rtl8821ae_read_txpower_info_from_hwpg(hw, + rtlefuse->autoload_failflag, hwinfo); + + /*board type*/ + rtlefuse->board_type = (((*(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION]) & 0xE0 ) >> 5); + if ((*(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION]) == 0xff ) + rtlefuse->board_type = 0; + rtlhal->boad_type = rtlefuse->board_type; + + rtl8821ae_read_bt_coexist_info_from_hwpg(hw, + rtlefuse->autoload_failflag, hwinfo); + + rtlefuse->eeprom_channelplan = *(u8 *) & hwinfo[EEPROM_CHANNELPLAN]; + if (rtlefuse->eeprom_channelplan == 0xff) + rtlefuse->eeprom_channelplan = 0x7F; + + /* set channel paln to world wide 13 */ + //rtlefuse->channel_plan = (u8) rtlefuse->eeprom_channelplan; + + /*parse xtal*/ + rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8821AE]; + if ( rtlefuse->crystalcap == 0xFF ) + rtlefuse->crystalcap = 0x20; + + rtlefuse->eeprom_thermalmeter = *(u8 *) & hwinfo[EEPROM_THERMAL_METER]; + if ((rtlefuse->eeprom_thermalmeter == 0xff) ||rtlefuse->autoload_failflag ) + { + rtlefuse->b_apk_thermalmeterignore = true; + rtlefuse->eeprom_thermalmeter = 0x18; + } + + rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter)); + + if (rtlefuse->autoload_failflag == false) { + rtlefuse->antenna_div_cfg = (*(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION] & BIT(3))?true:false; + /*if (BT_1ant()) + rtlefuse->antenna_div_cfg = 0;*/ + + rtlefuse->antenna_div_type = CG_TRX_HW_ANTDIV; + } else { + rtlefuse->antenna_div_cfg = 0; + rtlefuse->antenna_div_type = 0; + } + + RT_TRACE(COMP_INIT, DBG_LOUD, + ("SWAS: bHwAntDiv = %x, TRxAntDivType = %x\n", + rtlefuse->antenna_div_cfg, rtlefuse->antenna_div_type)); + + pcipriv->ledctl.bled_opendrain = true; + + if (rtlhal->oem_id == RT_CID_DEFAULT) { + switch (rtlefuse->eeprom_oemid) { + case RT_CID_DEFAULT: + break; + case EEPROM_CID_TOSHIBA: + rtlhal->oem_id = RT_CID_TOSHIBA; + break; + case EEPROM_CID_CCX: + rtlhal->oem_id = RT_CID_CCX; + break; + case EEPROM_CID_QMI: + rtlhal->oem_id = RT_CID_819x_QMI; + break; + case EEPROM_CID_WHQL: + break; + default: + break; + } + } +} + + +/*static void _rtl8821ae_hal_customized_behavior(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + pcipriv->ledctl.bled_opendrain = true; + switch (rtlhal->oem_id) { + case RT_CID_819x_HP: + pcipriv->ledctl.bled_opendrain = true; + break; + case RT_CID_819x_Lenovo: + case RT_CID_DEFAULT: + case RT_CID_TOSHIBA: + case RT_CID_CCX: + case RT_CID_819x_Acer: + case RT_CID_WHQL: + default: + break; + } + RT_TRACE(COMP_INIT, DBG_DMESG, + ("RT Customized ID: 0x%02X\n", rtlhal->oem_id)); +}*/ + +void rtl8821ae_read_eeprom_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_u1b; + + rtlhal->version = _rtl8821ae_read_chip_version(hw); + + if (get_rf_type(rtlphy) == RF_1T1R) + rtlpriv->dm.brfpath_rxenable[0] = true; + else + rtlpriv->dm.brfpath_rxenable[0] = + rtlpriv->dm.brfpath_rxenable[1] = true; + RT_TRACE(COMP_INIT, DBG_LOUD, ("VersionID = 0x%4x\n", + rtlhal->version)); + + tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); + if (tmp_u1b & BIT(4)) { + RT_TRACE(COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n")); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n")); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + + if (tmp_u1b & BIT(5)) { + RT_TRACE(COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + _rtl8812ae_read_adapter_info(hw, false); + else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + _rtl8821ae_read_adapter_info(hw, false); + } else { + RT_TRACE(COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); + } + /*hal_ReadRFType_8812A()*/ + //_rtl8821ae_hal_customized_behavior(hw); +} + +static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 b_nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate; + u32 tmp_ratr_value; + u8 b_curtxbw_40mhz = mac->bw_40; + u8 b_curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 b_curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + if (mac->opmode == NL80211_IFTYPE_ADHOC) + ratr_value = 0xfff; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + if (ratr_value & 0x0000000c) + ratr_value &= 0x0000000d; + else + ratr_value &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + b_nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) + ratr_mask = 0x000ff005; + else + ratr_mask = 0x0f0ff005; + + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + + break; + } + + if ( (rtlpcipriv->btcoexist.bt_coexistence) && + (rtlpcipriv->btcoexist.bt_coexist_type == BT_CSR_BC4) && + (rtlpcipriv->btcoexist.bt_cur_state) && + (rtlpcipriv->btcoexist.bt_ant_isolation) && + ((rtlpcipriv->btcoexist.bt_service == BT_SCO)|| + (rtlpcipriv->btcoexist.bt_service == BT_BUSY)) ) + ratr_value &= 0x0fffcfc0; + else + ratr_value &= 0x0FFFFFFF; + + if (b_nmode && ((b_curtxbw_40mhz && + b_curshortgi_40mhz) || (!b_curtxbw_40mhz && + b_curshortgi_20mhz))) { + + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + } + + rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + + RT_TRACE(COMP_RATR, DBG_DMESG, + ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0))); +} + + +static u8 _rtl8821ae_mrate_idx_to_arfr_id( + struct ieee80211_hw *hw, u8 rate_index, + enum wireless_mode wirelessmode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 ret = 0; + switch(rate_index){ + case RATR_INX_WIRELESS_NGB: + if(rtlphy->rf_type == RF_1T1R) + ret = 1; + else + ret = 0; + ;break; + case RATR_INX_WIRELESS_N: + case RATR_INX_WIRELESS_NG: + if(rtlphy->rf_type == RF_1T1R) + ret = 5; + else + ret = 4; + ;break; + case RATR_INX_WIRELESS_NB: + if(rtlphy->rf_type == RF_1T1R) + ret = 3; + else + ret = 2; + ;break; + case RATR_INX_WIRELESS_GB: + ret = 6; + break; + case RATR_INX_WIRELESS_G: + ret = 7; + break; + case RATR_INX_WIRELESS_B: + ret = 8; + break; + case RATR_INX_WIRELESS_MC: + if ((wirelessmode == WIRELESS_MODE_B) + || (wirelessmode == WIRELESS_MODE_G) + || (wirelessmode == WIRELESS_MODE_N_24G) + || (wirelessmode == WIRELESS_MODE_AC_24G)) + ret = 6; + else + ret = 7; + case RATR_INX_WIRELESS_AC_5N: + if(rtlphy->rf_type == RF_1T1R) + ret = 10; + else + ret = 9; + break; + case RATR_INX_WIRELESS_AC_24N: + if(rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) + { + if(rtlphy->rf_type == RF_1T1R) + ret = 10; + else + ret = 9; + } else { + if(rtlphy->rf_type == RF_1T1R) + ret = 11; + else + ret = 12; + } + break; + default: + ret = 0;break; + } + return ret; +} + +static void rtl8821ae_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info * sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index; + u8 b_curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 b_curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 b_curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool b_shortgi = false; + u8 rate_mask[7]; + u8 macid = 0; + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION || + mac->opmode == NL80211_IFTYPE_MESH_POINT) + b_curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + ratr_bitmap = sta->supp_rates[0]; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + ratr_bitmap = 0xfff; + + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); +/*mac id owner*/ + switch (wirelessmode) { + case WIRELESS_MODE_B: + ratr_index = RATR_INX_WIRELESS_B; + if (ratr_bitmap & 0x0000000c) + ratr_bitmap &= 0x0000000d; + else + ratr_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_index = RATR_INX_WIRELESS_GB; + + if (rssi_level == 1) + ratr_bitmap &= 0x00000f00; + else if (rssi_level == 2) + ratr_bitmap &= 0x00000ff0; + else + ratr_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_A: + ratr_index = RATR_INX_WIRELESS_G; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + if (wirelessmode == WIRELESS_MODE_N_24G) + ratr_index = RATR_INX_WIRELESS_NGB; + else + ratr_index = RATR_INX_WIRELESS_NG; + + if (mimo_ps == IEEE80211_SMPS_STATIC || mimo_ps == IEEE80211_SMPS_DYNAMIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if ( rtlphy->rf_type == RF_1T1R) { + if (b_curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff005; + } + } else { + if (b_curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0fff0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0ffff000; + else + ratr_bitmap &= 0x0ffff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x0fff0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0ffff000; + else + ratr_bitmap &= 0x0ffff005; + } + } + } + if ((b_curtxbw_40mhz && b_curshortgi_40mhz) || + (!b_curtxbw_40mhz && b_curshortgi_20mhz)) { + + if (macid == 0) + b_shortgi = true; + else if (macid == 1) + b_shortgi = false; + } + break; + + case WIRELESS_MODE_AC_24G: + ratr_index = RATR_INX_WIRELESS_AC_24N; + if(rssi_level == 1) + ratr_bitmap &= 0xfc3f0000; + else if(rssi_level == 2) + ratr_bitmap &= 0xfffff000; + else + ratr_bitmap &= 0xffffffff; + break; + + case WIRELESS_MODE_AC_5G: + ratr_index = RATR_INX_WIRELESS_AC_5N; + + if (rtlphy->rf_type == RF_1T1R) + { + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + if(rssi_level == 1) /*add by Gary for ac-series*/ + ratr_bitmap &= 0x003f8000; + else if (rssi_level == 2) + ratr_bitmap &= 0x003ff000; + else + ratr_bitmap &= 0x003ff010; + } + else + ratr_bitmap &= 0x000ff010; + } + else + { + if(rssi_level == 1) /* add by Gary for ac-series*/ + ratr_bitmap &= 0xfe3f8000; /*VHT 2SS MCS3~9*/ + else if (rssi_level == 2) + ratr_bitmap &= 0xfffff000; /*VHT 2SS MCS0~9*/ + else + ratr_bitmap &= 0xfffff010; /*All*/ + } + break; + + default: + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f0ff0ff; + break; + + } + + sta_entry->ratr_index = ratr_index; + + RT_TRACE(COMP_RATR, DBG_DMESG, + ("ratr_bitmap :%x\n", ratr_bitmap)); + *(u32 *) & rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | + (ratr_index << 28)); + rate_mask[0] = macid; + rate_mask[1] = _rtl8821ae_mrate_idx_to_arfr_id(hw, ratr_index, wirelessmode) | (b_shortgi ? 0x80 : 0x00); + rate_mask[2] = b_curtxbw_40mhz; + /* if (prox_priv->proxim_modeinfo->power_output > 0) + rate_mask[2] |= BIT(6); */ + + rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff); + rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >>8); + rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16); + rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24); + + RT_TRACE(COMP_RATR, DBG_DMESG, ("Rate_index:%x, " + "ratr_val:%x, %x:%x:%x:%x:%x:%x:%x\n", + ratr_index, ratr_bitmap, + rate_mask[0], rate_mask[1], + rate_mask[2], rate_mask[3], + rate_mask[4], rate_mask[5], + rate_mask[6])); + rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_RA_MASK, 7, rate_mask); + _rtl8821ae_set_bcn_ctrl_reg(hw, BIT(3), 0); +} + +void rtl8821ae_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (rtlpriv->dm.b_useramask) + rtl8821ae_update_hal_rate_mask(hw, sta, rssi_level); + else + /*RT_TRACE(COMP_RATR,DBG_LOUD,("rtl8821ae_update_hal_rate_tbl(): Error! 8821ae FW RA Only"));*/ + rtl8821ae_update_hal_rate_table(hw, sta); +} + +void rtl8821ae_update_channel_access_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 sifs_timer; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *) & mac->slot_time); + if (!mac->ht_enable) + sifs_timer = 0x0a0a; + else + sifs_timer = 0x0e0e; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *) & sifs_timer); +} + +bool rtl8821ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; + u8 u1tmp = 0; + bool b_actuallyset = false; + + if (rtlpriv->rtlhal.being_init_adapter) + return false; + + if (ppsc->b_swrf_processing) + return false; + + spin_lock(&rtlpriv->locks.rf_ps_lock); + if (ppsc->rfchange_inprogress) { + spin_unlock(&rtlpriv->locks.rf_ps_lock); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + } + + cur_rfstate = ppsc->rfpwr_state; + + rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2, + rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2) & ~(BIT(1))); + + u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL_2); + + if (rtlphy->polarity_ctl) { + e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFOFF : ERFON; + } else { + e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF; + } + + if ((ppsc->b_hwradiooff == true) && (e_rfpowerstate_toset == ERFON)) { + RT_TRACE(COMP_RF, DBG_DMESG, + ("GPIOChangeRF - HW Radio ON, RF ON\n")); + + e_rfpowerstate_toset = ERFON; + ppsc->b_hwradiooff = false; + b_actuallyset = true; + } else if ((ppsc->b_hwradiooff == false) + && (e_rfpowerstate_toset == ERFOFF)) { + RT_TRACE(COMP_RF, DBG_DMESG, + ("GPIOChangeRF - HW Radio OFF, RF OFF\n")); + + e_rfpowerstate_toset = ERFOFF; + ppsc->b_hwradiooff = true; + b_actuallyset = true; + } + + if (b_actuallyset) { + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + } else { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + } + + *valid = 1; + return !ppsc->b_hwradiooff; + +} + +void rtl8821ae_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *macaddr = p_macaddr; + u32 entry_id = 0; + bool is_pairwise = false; + + static u8 cam_const_addr[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} + }; + static u8 cam_const_broad[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + if (clear_all) { + u8 idx = 0; + u8 cam_offset = 0; + u8 clear_number = 5; + + RT_TRACE(COMP_SEC, DBG_DMESG, ("clear_all\n")); + + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + rtl_cam_empty_entry(hw, cam_offset + idx); + + if (idx < 5) { + memset(rtlpriv->sec.key_buf[idx], 0, + MAX_KEY_LEN); + rtlpriv->sec.key_len[idx] = 0; + } + } + + } else { + switch (enc_algo) { + case WEP40_ENCRYPTION: + enc_algo = CAM_WEP40; + break; + case WEP104_ENCRYPTION: + enc_algo = CAM_WEP104; + break; + case TKIP_ENCRYPTION: + enc_algo = CAM_TKIP; + break; + case AESCCMP_ENCRYPTION: + enc_algo = CAM_AES; + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case " + "not process \n")); + enc_algo = CAM_TKIP; + break; + } + + if (is_wepkey || rtlpriv->sec.use_defaultkey) { + macaddr = cam_const_addr[key_index]; + entry_id = key_index; + } else { + if (is_group) { + macaddr = cam_const_broad; + entry_id = key_index; + } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(COMP_SEC, DBG_EMERG, + ("Can not find free hw security cam entry\n")); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + + key_index = PAIRWISE_KEYIDX; + is_pairwise = true; + } + } + + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(COMP_SEC, DBG_DMESG, + ("delete one entry, entry_id is %d\n",entry_id)); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(COMP_SEC, DBG_DMESG, ("add one entry\n")); + if (is_pairwise) { + RT_TRACE(COMP_SEC, DBG_DMESG, ("set Pairwiase key\n")); + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[key_index]); + } else { + RT_TRACE(COMP_SEC, DBG_DMESG, ("set group key\n")); + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_cam_add_one_entry(hw, + rtlefuse->dev_addr, + PAIRWISE_KEYIDX, + CAM_PAIRWISE_KEY_POSITION, + enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf + [entry_id]); + } + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + } + } +} + + +void rtl8812ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value; + + if (!auto_load_fail) { + value = *(u8 *) & hwinfo[EEPROM_RF_BOARD_OPTION]; + if (((value & 0xe0) >> 5) == 0x1) + rtlpriv->btcoexist.btc_info.btcoexist = 1; + else + rtlpriv->btcoexist.btc_info.btcoexist = 0; + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8812A; + + value = hwinfo[EEPROM_RF_BT_SETTING]; + rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1); + } else { + rtlpriv->btcoexist.btc_info.btcoexist = 0; + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8812A; + rtlpriv->btcoexist.btc_info.ant_num = ANT_X2; + } + /*move BT_InitHalVars() to init_sw_vars*/ +} + +void rtl8821ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value; + u32 tmpu_32; + + if (!auto_load_fail) { + tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL); + if(tmpu_32 & BIT(18)) + rtlpriv->btcoexist.btc_info.btcoexist = 1; + else + rtlpriv->btcoexist.btc_info.btcoexist = 0; + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8821A; + + value = hwinfo[EEPROM_RF_BT_SETTING]; + rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1); + } else { + rtlpriv->btcoexist.btc_info.btcoexist = 0; + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8821A; + rtlpriv->btcoexist.btc_info.ant_num = ANT_X2; + } + /*move BT_InitHalVars() to init_sw_vars*/ +} + +void rtl8821ae_bt_reg_init(struct ieee80211_hw* hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + /* 0:Low, 1:High, 2:From Efuse. */ + rtlpcipriv->btcoexist.b_reg_bt_iso = 2; + /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ + rtlpcipriv->btcoexist.b_reg_bt_sco= 3; + /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ + rtlpcipriv->btcoexist.b_reg_bt_sco= 0; +} + + +void rtl8821ae_bt_hw_init(struct ieee80211_hw* hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->cfg->ops->get_btc_status()){ + rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv); + } +} + +void rtl8821ae_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl8821ae_resume(struct ieee80211_hw *hw) +{ +} + +/* Turn on AAP (RCR:bit 0) for promicuous mode. */ +void rtl8821ae_allow_all_destaddr(struct ieee80211_hw *hw, + bool allow_all_da, bool write_into_reg) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + if (allow_all_da) /* Set BIT0 */ + rtlpci->receive_config |= RCR_AAP; + else /* Clear BIT0 */ + rtlpci->receive_config &= ~RCR_AAP; + + if(write_into_reg) + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + + + RT_TRACE(COMP_TURBO | COMP_INIT, DBG_LOUD, + ("receive_config=0x%08X, write_into_reg=%d\n", + rtlpci->receive_config, write_into_reg )); +} + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/phy.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/phy.c @@ -0,0 +1,5525 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "table.h" +#include "trx.h" +#include "../btcoexist/halbt_precomp.h" +#include "hw.h" + +#define READ_NEXT_PAIR(array_table,v1, v2, i) do { i += 2; v1 = array_table[i]; v2 = array_table[i+1]; } while(0) + +static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask); +static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw); +static bool _rtl8812ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); +static bool _rtl8821ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); +static bool _rtl8821ae_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +static bool _rtl8812ae_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +static bool _rtl8812ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +static void _rtl8821ae_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); + +static long _rtl8821ae_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u8 txpwridx); +static void rtl8821ae_phy_set_rf_on(struct ieee80211_hw *hw); +static void rtl8821ae_phy_set_io(struct ieee80211_hw *hw); + +void rtl8812ae_fixspur( + struct ieee80211_hw *hw, + enum ht_channel_width band_width, + u8 channel +) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + /*C cut Item12 ADC FIFO CLOCK*/ + if(IS_VENDOR_8812A_C_CUT(rtlhal->version)) + { + if(band_width == HT_CHANNEL_WIDTH_20_40 && channel == 11) + rtl_set_bbreg(hw, RRFMOD, 0xC00, 0x3) ; + /* 0x8AC[11:10] = 2'b11*/ + else + rtl_set_bbreg(hw, RRFMOD, 0xC00, 0x2); + /* 0x8AC[11:10] = 2'b10*/ + + + /* <20120914, Kordan> A workarould to resolve + 2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)*/ + if (band_width == HT_CHANNEL_WIDTH_20 && + (channel == 13 || channel == 14)) { + rtl_set_bbreg(hw, RRFMOD, 0x300, 0x3); + /*0x8AC[9:8] = 2'b11*/ + rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 1); + /* 0x8C4[30] = 1*/ + } else if (band_width == HT_CHANNEL_WIDTH_20_40 && + channel == 11) { + rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 1); + /*0x8C4[30] = 1*/ + } else if (band_width != HT_CHANNEL_WIDTH_80) { + rtl_set_bbreg(hw, RRFMOD, 0x300, 0x2); + /*0x8AC[9:8] = 2'b10*/ + rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 0); + /*0x8C4[30] = 0*/ + } + } + else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + /* <20120914, Kordan> A workarould to resolve + 2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)*/ + if (band_width == HT_CHANNEL_WIDTH_20 && + (channel == 13 || channel == 14)) + rtl_set_bbreg(hw, RRFMOD, 0x300, 0x3); + /*0x8AC[9:8] = 11*/ + else if (channel <= 14) /*2.4G only*/ + rtl_set_bbreg(hw, RRFMOD, 0x300, 0x2); + /*0x8AC[9:8] = 10*/ + } + +} + +u32 rtl8821ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 returnvalue, originalvalue, bitshift; + + RT_TRACE(COMP_RF, DBG_TRACE, ("regaddr(%#x), " + "bitmask(%#x)\n", regaddr, + bitmask)); + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + + RT_TRACE(COMP_RF, DBG_TRACE, ("BBR MASK=0x%x " + "Addr[0x%x]=0x%x\n", bitmask, + regaddr, originalvalue)); + + return returnvalue; + +} + +void rtl8821ae_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 originalvalue, bitshift; + + RT_TRACE(COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, + data)); + + if (bitmask != MASKDWORD) { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | ((data << bitshift) & bitmask)); + } + + rtl_write_dword(rtlpriv, regaddr, data); + + RT_TRACE(COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, + data)); + +} + +u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, readback_value, bitshift; + unsigned long flags; + + RT_TRACE(COMP_RF, DBG_TRACE, ("regaddr(%#x), " + "rfpath(%#x), bitmask(%#x)\n", + regaddr, rfpath, bitmask)); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + + original_value = _rtl8821ae_phy_rf_serial_read(hw,rfpath, regaddr); + bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(COMP_RF, DBG_TRACE, + ("regaddr(%#x), rfpath(%#x), " + "bitmask(%#x), original_value(%#x)\n", + regaddr, rfpath, bitmask, original_value)); + + return readback_value; +} + +void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, bitshift; + unsigned long flags; + + RT_TRACE(COMP_RF, DBG_TRACE, + ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath)); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl8821ae_phy_rf_serial_read(hw, + rfpath, + regaddr); + bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); + data = + ((original_value & (~bitmask)) | + (data << bitshift)); + } + + _rtl8821ae_phy_rf_serial_write(hw, rfpath, regaddr, data); + + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(COMP_RF, DBG_TRACE, ("regaddr(%#x), " + "bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath)); + +} + +static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool b_is_pi_mode =false; + u32 retvalue = 0; + + /* 2009/06/17 MH We can not execute IO for power save or other accident mode.*/ + if (RT_CANNOT_IO(hw)) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("return all one\n")); + return 0xFFFFFFFF; + } + + /* <20120809, Kordan> CCA OFF(when entering), asked by James to avoid reading the wrong value. + <20120828, Kordan> Toggling CCA would affect RF 0x0, skip it!*/ + if (offset != 0x0 && + !((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + || (IS_VENDOR_8812A_C_CUT(rtlhal->version)))) + rtl_set_bbreg(hw, RCCAONSEC, 0x8, 1); + + offset &= 0xff; + + if (rfpath == RF90_PATH_A) + b_is_pi_mode = (bool) rtl_get_bbreg(hw, 0xC00, 0x4); + else if (rfpath == RF90_PATH_B) + b_is_pi_mode = (bool) rtl_get_bbreg(hw, 0xE00, 0x4); + + rtl_set_bbreg(hw, RHSSIREAD_8821AE, 0xff, offset); + + if ((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + || (IS_VENDOR_8812A_C_CUT(rtlhal->version))) + udelay(20); + + if (b_is_pi_mode) + { + if (rfpath == RF90_PATH_A) { + retvalue = rtl_get_bbreg(hw, RA_PIREAD_8821A, BLSSIREADBACKDATA); + } + else if (rfpath == RF90_PATH_B){ + retvalue = rtl_get_bbreg(hw, RB_PIREAD_8821A, BLSSIREADBACKDATA); + } + } + else + { + if (rfpath == RF90_PATH_A) { + retvalue = rtl_get_bbreg(hw, RA_SIREAD_8821A, BLSSIREADBACKDATA); + } + else if (rfpath == RF90_PATH_B){ + retvalue = rtl_get_bbreg(hw, RB_SIREAD_8821A, BLSSIREADBACKDATA); + } + } + + /*<20120809, Kordan> CCA ON(when exiting), asked by James to avoid reading the wrong value. + <20120828, Kordan> Toggling CCA would affect RF 0x0, skip it!*/ + if (offset != 0x0 && ! ((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + || (IS_VENDOR_8812A_C_CUT(rtlhal->version)))) + rtl_set_bbreg(hw, RCCAONSEC, 0x8, 0); + return retvalue; +} + +#if 0 +static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 newoffset; + u32 tmplong, tmplong2; + u8 rfpi_enable = 0; + u32 retvalue; + + offset &= 0xff; + newoffset = offset; + if (RT_CANNOT_IO(hw)) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("return all one\n")); + return 0xFFFFFFFF; + } + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); + if (rfpath == RF90_PATH_A) + tmplong2 = tmplong; + else + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); + tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | + (newoffset << 23) | BLSSIREADEDGE; + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, + tmplong & (~BLSSIREADEDGE)); + mdelay(1); + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); + mdelay(1); + /*rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, + tmplong | BLSSIREADEDGE);*/ + mdelay(1); + if (rfpath == RF90_PATH_A) + rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + else if (rfpath == RF90_PATH_B) + rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, + BIT(8)); + if (rfpi_enable) + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, + BLSSIREADBACKDATA); + else + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSIREADBACKDATA); + RT_TRACE(COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rflssi_readback, + retvalue)); + return retvalue; +} +#endif + +static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data) +{ + u32 data_and_addr; + u32 newoffset; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + + if (RT_CANNOT_IO(hw)) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("stop\n")); + return; + } + offset &= 0xff; + newoffset = offset; + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); + RT_TRACE(COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rf3wire_offset, + data_and_addr)); +} + +static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + return i; +} + +bool rtl8821ae_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool rtstatus = 0; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtstatus = _rtl8812ae_phy_config_mac_with_headerfile(hw); + else + rtstatus = _rtl8821ae_phy_config_mac_with_headerfile(hw); + + return rtstatus; +} + +bool rtl8821ae_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 regval; + u8 crystal_cap; + //u32 tmp; + + _rtl8821ae_phy_init_bb_rf_register_definition(hw); + + regval = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN); + regval |= regval | FEN_PCIEA; + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, regval); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, + regval | FEN_BB_GLB_RSTN | FEN_BBRSTB); + + rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x7);/*RF_EN | RF_RSTB | RF_SDMRSTB*/ + rtl_write_byte(rtlpriv, REG_OPT_CTRL + 2, 0x7);/*RF_EN | RF_RSTB | RF_SDMRSTB*/ + + rtstatus = _rtl8821ae_phy_bb8821a_config_parafile(hw); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + { + crystal_cap = rtlefuse->crystalcap & 0x3F; + rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0x7FF80000, (crystal_cap | (crystal_cap << 6))); + }else{ + crystal_cap = rtlefuse->crystalcap & 0x3F; + rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000, (crystal_cap | (crystal_cap << 6))); + } + rtlphy->reg_837 = rtl_read_byte(rtlpriv, 0x837); + + return rtstatus; +} + +bool rtl8821ae_phy_rf_config(struct ieee80211_hw *hw) +{ + return rtl8821ae_phy_rf6052_config(hw); +} + + +u32 phy_get_tx_bb_swing_8812A( + struct ieee80211_hw *hw, + u8 band, + u8 rf_path + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtlpriv); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + char bb_swing_2g = (char) (-1 * 0xFF); + char bb_swing_5g = (char) (-1 * 0xFF); + u32 out = 0x200; + const char auto_temp = -1; + + RT_TRACE(COMP_SCAN, DBG_LOUD, + ("===> PHY_GetTxBBSwing_8812A, bbSwing_2G: %d, bbSwing_5G: %d\n", + (int)bb_swing_2g, (int)bb_swing_5g)); + + if ( rtlefuse->autoload_failflag) { + if ( band == BAND_ON_2_4G ) { + rtldm->bb_swing_diff_2g = bb_swing_2g; + if (bb_swing_2g == 0) out = 0x200; // 0 dB + else if (bb_swing_2g == -3) out = 0x16A; // -3 dB + else if (bb_swing_2g == -6) out = 0x101; // -6 dB + else if (bb_swing_2g == -9) out = 0x0B6; // -9 dB + else { + rtldm->bb_swing_diff_2g = 0; + out = 0x200; + } + + } else if ( band == BAND_ON_5G ) { + rtldm->bb_swing_diff_5g = bb_swing_5g; + if (bb_swing_5g == 0) out = 0x200; // 0 dB + else if (bb_swing_5g == -3) out = 0x16A; // -3 dB + else if (bb_swing_5g == -6) out = 0x101; // -6 dB + else if (bb_swing_5g == -9) out = 0x0B6; // -9 dB + else { + if ( rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + rtldm->bb_swing_diff_5g = -3; + out = 0x16A; + } else { + rtldm->bb_swing_diff_5g = 0; + out = 0x200; + } + } + } else { + rtldm->bb_swing_diff_2g = -3; + rtldm->bb_swing_diff_5g = -3; + out = 0x16A; // -3 dB + } + } + else + { + u32 swing = 0, swing_a = 0, swing_b = 0; + + if (band == BAND_ON_2_4G) + { + if (0xFF == auto_temp) + { + efuse_shadow_read(hw, 1, 0xC6, (u32 *)&swing); + swing = (swing == 0xFF) ? 0x00 : swing; + } + else if (bb_swing_2g == 0) swing = 0x00; // 0 dB + else if (bb_swing_2g == -3) swing = 0x05; // -3 dB + else if (bb_swing_2g == -6) swing = 0x0A; // -6 dB + else if (bb_swing_2g == -9) swing = 0xFF; // -9 dB + else swing = 0x00; + } + else + { + if (0xFF == auto_temp) + { + efuse_shadow_read(hw, 1, 0xC7, (u32 *)&swing); + swing = (swing == 0xFF) ? 0x00 : swing; + } + else if (bb_swing_5g == 0) swing = 0x00; // 0 dB + else if (bb_swing_5g == -3) swing = 0x05; // -3 dB + else if (bb_swing_5g == -6) swing = 0x0A; // -6 dB + else if (bb_swing_5g == -9) swing = 0xFF; // -9 dB + else swing = 0x00; + } + + swing_a = (swing & 0x3) >> 0; // 0xC6/C7[1:0] + swing_b = (swing & 0xC) >> 2; // 0xC6/C7[3:2] + RT_TRACE(COMP_SCAN, DBG_LOUD, + ("===> PHY_GetTxBBSwing_8812A, swingA: 0x%X, swingB: 0x%X\n", + swing_a, swing_b)); + + //3 Path-A + if (swing_a == 0x0) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = 0; + else + rtldm->bb_swing_diff_5g = 0; + out = 0x200; // 0 dB + } else if (swing_a == 0x1) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = -3; + else + rtldm->bb_swing_diff_5g = -3; + out = 0x16A; // -3 dB + } else if (swing_a == 0x2) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = -6; + else + rtldm->bb_swing_diff_5g = -6; + out = 0x101; // -6 dB + } else if (swing_a == 0x3) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = -9; + else + rtldm->bb_swing_diff_5g = -9; + out = 0x0B6; // -9 dB + } + + //3 Path-B + if (swing_b == 0x0) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = 0; + else + rtldm->bb_swing_diff_5g = 0; + out = 0x200; // 0 dB + } else if (swing_b == 0x1) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = -3; + else + rtldm->bb_swing_diff_5g = -3; + out = 0x16A; // -3 dB + } else if (swing_b == 0x2) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = -6; + else + rtldm->bb_swing_diff_5g = -6; + out = 0x101; // -6 dB + } else if (swing_b == 0x3) { + if (band == BAND_ON_2_4G) + rtldm->bb_swing_diff_2g = -9; + else + rtldm->bb_swing_diff_5g = -9; + out = 0x0B6; // -9 dB + } + } + + RT_TRACE(COMP_SCAN, DBG_LOUD, + ("<=== PHY_GetTxBBSwing_8812A, out = 0x%X\n", out)); + return out; +} +void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtlpriv); + u8 current_band = rtlhal->current_bandtype; + u32 txpath, rxpath; + //u8 i, value8; + char bb_diff_between_band; + + RT_TRACE(COMP_INIT, DBG_LOUD, ("\n")); + txpath = rtl8821ae_phy_query_bb_reg(hw, RTXPATH, 0xf0); + rxpath = rtl8821ae_phy_query_bb_reg(hw, RCCK_RX, 0x0f000000); + rtlhal->current_bandtype = (enum band_type) band; + /* reconfig BB/RF according to wireless mode */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* BB & RF Config */ + RT_TRACE(COMP_CMD, DBG_DMESG, ("2.4G\n")); + rtl_set_bbreg(hw, ROFDMCCKEN, BOFDMEN|BCCKEN, 0x03); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + /* 0xCB0[15:12] = 0x7 (LNA_On)*/ + rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF000, 0x7); + /* 0xCB0[7:4] = 0x7 (PAPE_A)*/ + rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF0, 0x7); + } + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + rtl_set_bbreg(hw, 0x830, 0xE, 0x4); /*0x830[3:1] = 0x4*/ + rtl_set_bbreg(hw, 0x834, 0x3, 0x1); /*0x834[1:0] = 0x1*/ + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) + rtl_set_bbreg(hw, RA_TXSCALE, 0xF00, 0); // 0xC1C[11:8] = 0 + else + rtl_set_bbreg(hw, 0x82c, 0x3, 0); // 0x82C[1:0] = 2b'00 + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77777777); + rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77777777); + rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x000); + rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x000); + } + + rtl_set_bbreg(hw, RTXPATH, 0xf0, txpath); + rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, rxpath); + + rtl_write_byte(rtlpriv, REG_CCK_CHECK, 0x0); + } else {/* 5G band */ + u16 count, reg_41a; + RT_TRACE(COMP_CMD, DBG_DMESG, ("5G\n")); + + if(rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + /*0xCB0[15:12] = 0x5 (LNA_On)*/ + rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF000, 0x5); + /*0xCB0[7:4] = 0x4 (PAPE_A)*/ + rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF0, 0x4); + } + /*CCK_CHECK_en*/ + rtl_write_byte(rtlpriv, REG_CCK_CHECK, 0x80); + + count = 0; + reg_41a = rtl_read_word(rtlpriv, REG_TXPKT_EMPTY); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Reg41A value %d", reg_41a)); + reg_41a &= 0x30; + while ((reg_41a!= 0x30) && (count < 50)) { + udelay(50); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Delay 50us \n")); + + reg_41a = rtl_read_word(rtlpriv, REG_TXPKT_EMPTY); + reg_41a &= 0x30; + count++; + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Reg41A value %d", reg_41a)); + } + if (count != 0) + RT_TRACE(COMP_MLME, DBG_LOUD, + ("PHY_SwitchWirelessBand8812(): Switch to 5G Band. " + "Count = %d reg41A=0x%x\n", count, reg_41a)); + + // 2012/02/01, Sinda add registry to switch workaround without long-run verification for scan issue. + rtl_set_bbreg(hw, ROFDMCCKEN, BOFDMEN|BCCKEN, 0x03); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + rtl_set_bbreg(hw, 0x830, 0xE, 0x3); /*0x830[3:1] = 0x3*/ + rtl_set_bbreg(hw, 0x834, 0x3, 0x2); /*0x834[1:0] = 0x2*/ + } + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + /* AGC table select */ + rtl_set_bbreg(hw, RA_TXSCALE, 0xF00, 1); /* 0xC1C[11:8] = 1*/ + } else + rtl_set_bbreg(hw, 0x82c, 0x3, 1); // 0x82C[1:0] = 2'b00 + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77337777); + rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77337777); + rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x010); + rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x010); + } + + rtl_set_bbreg(hw, RTXPATH, 0xf0, txpath); + rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, rxpath); + + RT_TRACE(COMP_SCAN, DBG_LOUD, + ("==>PHY_SwitchWirelessBand8812() BAND_ON_5G settings OFDM index 0x%x\n", + rtlpriv->dm.ofdm_index[RF90_PATH_A])); + } + + if ((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) || + (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)) { + rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000, + phy_get_tx_bb_swing_8812A(hw, band, RF90_PATH_A)); // 0xC1C[31:21] + rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000, + phy_get_tx_bb_swing_8812A(hw, band, RF90_PATH_B)); // 0xE1C[31:21] + + /* <20121005, Kordan> When TxPowerTrack is ON, we should take care of the change of BB swing. + That is, reset all info to trigger Tx power tracking.*/ + if (band != current_band) { + bb_diff_between_band = (rtldm->bb_swing_diff_2g - rtldm->bb_swing_diff_5g); + bb_diff_between_band = (band == BAND_ON_2_4G) ? bb_diff_between_band : (-1 * bb_diff_between_band); + rtldm->default_ofdm_index += bb_diff_between_band * 2; + } + rtl8821ae_dm_clear_txpower_tracking_state(hw); + } + + RT_TRACE(COMP_SCAN, DBG_TRACE, + ("<==rtl8821ae_phy_switch_wirelessband():Switch Band OK.\n")); + return; +} + +static bool _rtl8821ae_check_condition(struct ieee80211_hw *hw, + const u32 Condition + ) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 _board = rtlefuse->board_type; /*need efuse define*/ + u32 _interface = rtlhal->interface; + u32 _platform = 0x08;/*SupportPlatform */ + u32 cond = Condition; + + if ( Condition == 0xCDCDCDCD ) + return true; + + cond = Condition & 0xFF; + if ( (_board != cond) == 0 && cond != 0xFF) + return false; + + cond = Condition & 0xFF00; + cond = cond >> 8; + if ( (_interface & cond) == 0 && cond != 0x07) + return false; + + cond = Condition & 0xFF0000; + cond = cond >> 16; + if ( (_platform & cond) == 0 && cond != 0x0F) + return false; + return true; +} + +static void _rtl8821ae_config_rf_reg(struct ieee80211_hw *hw, + u32 addr, + u32 data, + enum radio_path rfpath, + u32 regaddr + ) +{ + if ( addr == 0xfe || addr == 0xffe) { + mdelay(50); + } else { + rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data); + udelay(1); + } +} + +static void _rtl8821ae_config_rf_radio_a(struct ieee80211_hw *hw, + u32 addr, u32 data) +{ + u32 content = 0x1000; /*RF Content: radio_a_txt*/ + u32 maskforphyset = (u32)(content & 0xE000); + + _rtl8821ae_config_rf_reg(hw, addr, data, RF90_PATH_A, addr | maskforphyset); + +} + +static void _rtl8821ae_config_rf_radio_b(struct ieee80211_hw *hw, + u32 addr, u32 data) +{ + u32 content = 0x1001; /*RF Content: radio_b_txt*/ + u32 maskforphyset = (u32)(content & 0xE000); + + _rtl8821ae_config_rf_reg(hw, addr, data, RF90_PATH_B, addr | maskforphyset); + +} + +static void _rtl8812ae_config_bb_reg(struct ieee80211_hw *hw, + u32 addr, u32 data) +{ + if ( addr == 0xfe) { + mdelay(50); + } else if ( addr == 0xfd) + mdelay(5); + else if ( addr == 0xfc) + mdelay(1); + else if ( addr == 0xfb) + udelay(50); + else if ( addr == 0xfa) + udelay(5); + else if ( addr == 0xf9) + udelay(1); + else { + rtl_set_bbreg(hw, addr, MASKDWORD,data); + } + udelay(1); +} + +static void _rtl8821ae_config_bb_reg(struct ieee80211_hw *hw, + u32 addr, u32 data) +{ + if ( addr == 0xfe) { + mdelay(50); + } else if ( addr == 0xfd) + mdelay(5); + else if ( addr == 0xfc) + mdelay(1); + else if ( addr == 0xfb) + udelay(50); + else if ( addr == 0xfa) + udelay(5); + else if ( addr == 0xf9) + udelay(1); + + rtl_set_bbreg(hw, addr, MASKDWORD,data); + udelay(1); +} + +static void _rtl8821ae_phy_init_tx_power_by_rate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + u8 band, rfpath, txnum, rate_section; + + for ( band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band ) + for ( rfpath = 0; rfpath < TX_PWR_BY_RATE_NUM_RF; ++rfpath ) + for ( txnum = 0; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum ) + for ( rate_section = 0; rate_section < TX_PWR_BY_RATE_NUM_SECTION; ++rate_section ) + rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = 0; +} + +void _rtl8821ae_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw, + u8 band, u8 path, + u8 rate_section, + u8 txnum, u8 value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (path > RF90_PATH_D) { + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n", path)); + return; + } + + if (band == BAND_ON_2_4G) { + switch (rate_section) { + case CCK: + rtlphy->txpwr_by_rate_base_24g[path][txnum][0] = value; + break; + case OFDM: + rtlphy->txpwr_by_rate_base_24g[path][txnum][1] = value; + break; + case HT_MCS0_MCS7: + rtlphy->txpwr_by_rate_base_24g[path][txnum][2] = value; + break; + case HT_MCS8_MCS15: + rtlphy->txpwr_by_rate_base_24g[path][txnum][3] = value; + break; + case VHT_1SSMCS0_1SSMCS9: + rtlphy->txpwr_by_rate_base_24g[path][txnum][4] = value; + break; + case VHT_2SSMCS0_2SSMCS9: + rtlphy->txpwr_by_rate_base_24g[path][txnum][5] = value; + break; + default: + RT_TRACE(COMP_INIT, DBG_LOUD, ( "Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n", + rate_section, path, txnum ) ); + break; + }; + } else if (band == BAND_ON_5G) { + switch (rate_section) { + case OFDM: + rtlphy->txpwr_by_rate_base_5g[path][txnum][0] = value; + break; + case HT_MCS0_MCS7: + rtlphy->txpwr_by_rate_base_5g[path][txnum][1] = value; + break; + case HT_MCS8_MCS15: + rtlphy->txpwr_by_rate_base_5g[path][txnum][2] = value; + break; + case VHT_1SSMCS0_1SSMCS9: + rtlphy->txpwr_by_rate_base_5g[path][txnum][3] = value; + break; + case VHT_2SSMCS0_2SSMCS9: + rtlphy->txpwr_by_rate_base_5g[path][txnum][4] = value; + break; + default: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Invalid RateSection %d in Band 5G, Rf Path %d, " + "%dTx in PHY_SetTxPowerByRateBase()\n", + rate_section, path, txnum)); + break; + }; + } else { + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Invalid Band %d in PHY_SetTxPowerByRateBase()\n", band)); + } + +} + +u8 _rtl8821ae_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw, + u8 band, u8 path, + u8 txnum, u8 rate_section) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 value = 0; + + if (path > RF90_PATH_D) { + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Invalid Rf Path %d in PHY_GetTxPowerByRateBase()\n", path)); + return 0; + } + + if (band == BAND_ON_2_4G) { + switch (rate_section) { + case CCK: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][0]; + break; + case OFDM: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][1]; + break; + case HT_MCS0_MCS7: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][2]; + break; + case HT_MCS8_MCS15: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][3]; + break; + case VHT_1SSMCS0_1SSMCS9: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][4]; + break; + case VHT_2SSMCS0_2SSMCS9: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][5]; + break; + default: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Invalid RateSection %d in Band 2.4G, Rf Path %d," + " %dTx in PHY_GetTxPowerByRateBase()\n", + rate_section, path, txnum)); + break; + }; + } else if (band == BAND_ON_5G) { + switch (rate_section) { + case OFDM: + value = rtlphy->txpwr_by_rate_base_5g[path][txnum][0]; + break; + case HT_MCS0_MCS7: + value = rtlphy->txpwr_by_rate_base_5g[path][txnum][1]; + break; + case HT_MCS8_MCS15: + value = rtlphy->txpwr_by_rate_base_5g[path][txnum][2]; + break; + case VHT_1SSMCS0_1SSMCS9: + value = rtlphy->txpwr_by_rate_base_5g[path][txnum][3]; + break; + case VHT_2SSMCS0_2SSMCS9: + value = rtlphy->txpwr_by_rate_base_5g[path][txnum][4]; + break; + default: + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Invalid RateSection %d in Band 5G, Rf Path %d," + " %dTx in PHY_GetTxPowerByRateBase()\n", + rate_section, path, txnum)); + break; + }; + } else { + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Invalid Band %d in PHY_GetTxPowerByRateBase()\n", band)); + } + + return value; + +} +void _rtl8821ae_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u16 rawValue = 0; + u8 base = 0, path = 0; + + for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) { + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][0] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, CCK, RF_1TX, base); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][2] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, OFDM, RF_1TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][4] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS0_MCS7, RF_1TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_2TX][6] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS8_MCS15, RF_2TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][8] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_2TX][11] >> 8) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_1TX][2] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, OFDM, RF_1TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_1TX][4] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, HT_MCS0_MCS7, RF_1TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_2TX][6] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, HT_MCS8_MCS15, RF_2TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_1TX][8] >> 24) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base ); + + rawValue = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_2TX][11] >> 8) & 0xFF; + base = (rawValue >> 4) * 10 + (rawValue & 0xF); + _rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base ); + } +} + +void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start, + u8 end, u8 base_val) +{ + char i = 0; + u8 temp_value = 0; + u32 temp_data = 0; + + for (i = 3; i >= 0; --i) + { + if (i >= start && i <= end) { + // Get the exact value + temp_value = (u8) (*data >> (i * 8)) & 0xF; + temp_value += ((u8) ((*data >> (i * 8 + 4)) & 0xF)) * 10; + + // Change the value to a relative value + temp_value = (temp_value > base_val) ? temp_value - base_val : base_val - temp_value; + } else { + temp_value = (u8) (*data >> (i * 8)) & 0xFF; + } + temp_data <<= 8; + temp_data |= temp_value; + } + *data = temp_data; +} + +void _rtl8821ae_phy_convert_txpower_dbm_to_relative_value(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 base = 0, rfPath = 0; + + for (rfPath = RF90_PATH_A; rfPath <= RF90_PATH_B; ++rfPath) { + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, CCK); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 2.4G CCK 1TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][0] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, OFDM ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 2.4G OFDM 1TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][1] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][2] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, HT_MCS0_MCS7 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 2.4G HTMCS0-7 1TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][3] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][4] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_2TX, HT_MCS8_MCS15 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 2.4G HTMCS8-15 2TX: %d\n", base ) ); + + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][5] ), + 0, 3, base ); + + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][6] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, VHT_1SSMCS0_1SSMCS9 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 2.4G VHT1SSMCS0-9 1TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][7] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][8] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][9] ), + 0, 1, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_2TX, VHT_2SSMCS0_2SSMCS9 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 2.4G VHT2SSMCS0-9 2TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][9] ), + 2, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][10] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][11] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_1TX, OFDM ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 5G OFDM 1TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][1] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][2] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_1TX, HT_MCS0_MCS7 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 5G HTMCS0-7 1TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][3] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][4] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_2TX, HT_MCS8_MCS15 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 5G HTMCS8-15 2TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][5] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][6] ), + 0, 3, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_1TX, VHT_1SSMCS0_1SSMCS9 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 5G VHT1SSMCS0-9 1TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][7] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][8] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][9] ), + 0, 1, base ); + + base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_2TX, VHT_2SSMCS0_2SSMCS9 ); + RT_DISP( FPHY, PHY_TXPWR, ( "base of 5G VHT2SSMCS0-9 2TX: %d\n", base ) ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][9] ), + 2, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][10] ), + 0, 3, base ); + _phy_convert_txpower_dbm_to_relative_value( + &(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][11] ), + 0, 3, base ); + } + + RT_TRACE(COMP_POWER, DBG_TRACE, + ("<===_rtl8821ae_phy_convert_txpower_dbm_to_relative_value()\n")); + +} + +void _rtl8821ae_phy_txpower_by_rate_configuration(struct ieee80211_hw *hw) +{ + _rtl8821ae_phy_store_txpower_by_rate_base(hw); + _rtl8821ae_phy_convert_txpower_dbm_to_relative_value(hw); +} + +static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool rtstatus; + + /*TX POWER LIMIT + PHY_InitTxPowerLimit + PHY_ConfigRFWithCustomPowerLimitTableParaFile*/ + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtstatus = _rtl8812ae_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_PHY_REG); + else{ + rtstatus = _rtl8821ae_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_PHY_REG); + } + if (rtstatus != true) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("Write BB Reg Fail!!")); + return false; + } + _rtl8821ae_phy_init_tx_power_by_rate(hw); + if (rtlefuse->autoload_failflag == false) { + //rtlphy->pwrgroup_cnt = 0; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtstatus = _rtl8812ae_phy_config_bb_with_pgheaderfile(hw, + BASEBAND_CONFIG_PHY_REG); + else{ + rtstatus = _rtl8821ae_phy_config_bb_with_pgheaderfile(hw, + BASEBAND_CONFIG_PHY_REG); + } + } + if (rtstatus != true) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("BB_PG Reg Fail!!")); + return false; + } + + _rtl8821ae_phy_txpower_by_rate_configuration(hw); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtstatus = _rtl8812ae_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + else + rtstatus = _rtl8821ae_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + + if (rtstatus != true) { + RT_TRACE(COMP_ERR, DBG_EMERG, ("AGC Table Fail\n")); + return false; + } + rtlphy->bcck_high_power = (bool) (rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + 0x200)); + return true; +} + +static bool _rtl8812ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i, v1, v2; + u32 arraylength; + u32 *ptrarray; + + RT_TRACE(COMP_INIT, DBG_TRACE, ("Read rtl8812AE_MAC_REG_Array\n")); + arraylength = RTL8812AEMAC_1T_ARRAYLEN; + ptrarray = RTL8812AE_MAC_REG_ARRAY; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Img:RTL8812AE_MAC_REG_ARRAY LEN %d\n",arraylength)); + for (i = 0; i < arraylength; i += 2) { + v1 = ptrarray[i]; + v2 = (u8) ptrarray[i + 1]; + if (v1<0xCDCDCDCD) { + rtl_write_byte(rtlpriv, v1, (u8) v2); + } else { + if (!_rtl8821ae_check_condition(hw,v1)) { + /*Discard the following (offset, data) pairs*/ + READ_NEXT_PAIR(ptrarray, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylength -2) + READ_NEXT_PAIR(ptrarray, v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + } else {/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_PAIR(ptrarray, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylength -2) { + rtl_write_byte(rtlpriv,v1,v2); + READ_NEXT_PAIR(ptrarray, v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylength -2) + READ_NEXT_PAIR(ptrarray, v1, v2, i); + } + } + } + return true; +} + +static bool _rtl8821ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i, v1, v2; + u32 arraylength; + u32 *ptrarray; + + RT_TRACE(COMP_INIT, DBG_TRACE, ("Read rtl8821AE_MAC_REG_Array\n")); + arraylength = RTL8821AEMAC_1T_ARRAYLEN; + ptrarray = RTL8821AE_MAC_REG_ARRAY; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Img:RTL8821AE_MAC_REG_ARRAY LEN %d\n",arraylength)); + for (i = 0; i < arraylength; i += 2) { + v1 = ptrarray[i]; + v2 = (u8) ptrarray[i + 1]; + if (v1<0xCDCDCDCD) { + rtl_write_byte(rtlpriv, v1, (u8) v2); + continue; + } else { + if (!_rtl8821ae_check_condition(hw,v1)) { + /*Discard the following (offset, data) pairs*/ + READ_NEXT_PAIR(ptrarray, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylength -2) + READ_NEXT_PAIR(ptrarray, v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + } else {/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_PAIR(ptrarray, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylength -2) { + rtl_write_byte(rtlpriv,v1,v2); + READ_NEXT_PAIR(ptrarray, v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylength -2) + READ_NEXT_PAIR(ptrarray, v1, v2, i); + } + } + } + return true; +} + +static bool _rtl8812ae_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *array_table; + u16 arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 v1 = 0, v2 = 0; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + arraylen = RTL8812AEPHY_REG_1TARRAYLEN; + array_table = RTL8812AE_PHY_REG_ARRAY; + + for (i = 0; i < arraylen; i += 2) { + v1 = array_table[i]; + v2 = array_table[i+1]; + if (v1<0xCDCDCDCD) { + _rtl8812ae_config_bb_reg(hw, v1, v2); + continue; + } else {/*This line is the start line of branch.*/ + if (!_rtl8821ae_check_condition(hw,v1)) { + /*Discard the following (offset, data) pairs*/ + READ_NEXT_PAIR(array_table,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) + READ_NEXT_PAIR(array_table,v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + } else {/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_PAIR(array_table,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) { + _rtl8812ae_config_bb_reg(hw,v1,v2); + READ_NEXT_PAIR(array_table,v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylen -2) + READ_NEXT_PAIR(array_table,v1, v2, i); + } + } + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + arraylen = RTL8812AEAGCTAB_1TARRAYLEN; + array_table = RTL8812AE_AGC_TAB_ARRAY; + + for (i = 0; i < arraylen; i = i + 2) { + v1 = array_table[i]; + v2 = array_table[i+1]; + if (v1 < 0xCDCDCDCD) { + rtl_set_bbreg(hw, v1, MASKDWORD, v2); + udelay(1); + continue; + } else {/*This line is the start line of branch.*/ + if (!_rtl8821ae_check_condition(hw,v1)) { + /*Discard the following (offset, data) pairs*/ + READ_NEXT_PAIR(array_table,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) + READ_NEXT_PAIR(array_table,v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + }else{/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_PAIR(array_table,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) + { + rtl_set_bbreg(hw, v1, MASKDWORD, v2); + udelay(1); + READ_NEXT_PAIR(array_table,v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylen -2) + READ_NEXT_PAIR(array_table,v1, v2, i); + } + } + RT_TRACE(COMP_INIT, DBG_TRACE, + ("The agctab_array_table[0] is " + "%x Rtl818EEPHY_REGArray[1] is %x \n", + array_table[i], + array_table[i + 1])); + } + } + return true; +} + +static bool _rtl8821ae_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *array_table; + u16 arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 v1 = 0, v2 = 0; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + arraylen = RTL8821AEPHY_REG_1TARRAYLEN; + array_table = RTL8821AE_PHY_REG_ARRAY; + + for (i = 0; i < arraylen; i += 2) { + v1 = array_table[i]; + v2 = array_table[i+1]; + if (v1<0xCDCDCDCD) { + _rtl8821ae_config_bb_reg(hw, v1, v2); + continue; + } else {/*This line is the start line of branch.*/ + if (!_rtl8821ae_check_condition(hw,v1)) { + /*Discard the following (offset, data) pairs*/ + READ_NEXT_PAIR(array_table, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) + READ_NEXT_PAIR(array_table, v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + } else {/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_PAIR(array_table, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) { + _rtl8821ae_config_bb_reg(hw,v1,v2); + READ_NEXT_PAIR(array_table, v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylen -2) + READ_NEXT_PAIR(array_table, v1, v2, i); + } + } + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + arraylen = RTL8821AEAGCTAB_1TARRAYLEN; + array_table = RTL8821AE_AGC_TAB_ARRAY; + + for (i = 0; i < arraylen; i = i + 2) { + v1 = array_table[i]; + v2 = array_table[i+1]; + if (v1 < 0xCDCDCDCD) { + rtl_set_bbreg(hw, v1, MASKDWORD, v2); + udelay(1); + continue; + } else {/*This line is the start line of branch.*/ + if (!_rtl8821ae_check_condition(hw,v1)) { + /*Discard the following (offset, data) pairs*/ + READ_NEXT_PAIR(array_table, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) + READ_NEXT_PAIR(array_table, v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + }else{/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_PAIR(array_table, v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < arraylen -2) + { + rtl_set_bbreg(hw, v1, MASKDWORD, v2); + udelay(1); + READ_NEXT_PAIR(array_table, v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylen -2) + READ_NEXT_PAIR(array_table, v1, v2, i); + } + } + RT_TRACE(COMP_INIT, DBG_TRACE, + ("The agctab_array_table[0] is " + "%x Rtl818EEPHY_REGArray[1] is %x \n", + array_table[i], + array_table[i + 1])); + } + } + return true; +} + +static u8 _rtl8821ae_get_rate_selection_index(u32 regaddr) +{ + u8 index = 0; + + regaddr &= 0xFFF; + if (regaddr >= 0xC20 && regaddr <= 0xC4C) + index = (u8) ((regaddr - 0xC20) / 4); + else if (regaddr >= 0xE20 && regaddr <= 0xE4C) + index = (u8) ((regaddr - 0xE20) / 4); + else + RT_ASSERT(!COMP_INIT, + ("Invalid RegAddr 0x%x in" + "PHY_GetRateSectionIndexOfTxPowerByRate()\n",regaddr)); + + return index; +} + +static void _rtl8821ae_store_tx_power_by_rate(struct ieee80211_hw *hw, + u32 band, u32 rfpath, + u32 txnum, u32 regaddr, + u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rate_section = _rtl8821ae_get_rate_selection_index(regaddr); + + if (band != BAND_ON_2_4G && band != BAND_ON_5G) + RT_TRACE(COMP_INIT, DBG_WARNING, ("Invalid Band %d\n", band)); + + if (rfpath > MAX_RF_PATH) + RT_TRACE(COMP_INIT, DBG_WARNING, ("Invalid RfPath %d\n", rfpath)); + + if (txnum > MAX_RF_PATH) + RT_TRACE(COMP_INIT, DBG_WARNING, ("Invalid TxNum %d\n", txnum ) ); + + rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = data; + RT_TRACE(COMP_INIT, DBG_WARNING,( "pHalData->TxPwrByRateOffset[Band %d][RfPath %d][TxNum %d][RateSection %d] = 0x%x\n", + band, rfpath, txnum, rate_section, rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section])); + +} + +static bool _rtl8812ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + u32 *phy_regarray_table_pg; + u16 phy_regarray_pg_len; + u32 v1, v2, v3, v4, v5, v6; + + phy_regarray_pg_len = RTL8812AEPHY_REG_ARRAY_PGLEN; + phy_regarray_table_pg = RTL8812AE_PHY_REG_ARRAY_PG; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray_pg_len; i += 6) { + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + v4 = phy_regarray_table_pg[i+3]; + v5 = phy_regarray_table_pg[i+4]; + v6 = phy_regarray_table_pg[i+5]; + + if (v1<0xCDCDCDCD) { + if ( (v4 == 0xfe) || (v4 == 0xffe)) + mdelay(50); + else + /*_rtl8821ae_store_pwrIndex_diffrate_offset*/ + _rtl8821ae_store_tx_power_by_rate(hw, v1, v2, v3, v4, v5, v6); + continue; + } else { + if (!_rtl8821ae_check_condition(hw,v1)) { /*don't need the hw_body*/ + i += 2; /* skip the pair of expression*/ + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + while (v2 != 0xDEAD) { + i += 3; + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + } + } + } + } + } else { + + RT_TRACE(COMP_SEND, DBG_TRACE, + ("configtype != BaseBand_Config_PHY_REG\n")); + } + return true; +} + +static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + u32 *phy_regarray_table_pg; + u16 phy_regarray_pg_len; + u32 v1, v2, v3, v4, v5, v6; + + phy_regarray_pg_len = RTL8821AEPHY_REG_ARRAY_PGLEN; + phy_regarray_table_pg = RTL8821AE_PHY_REG_ARRAY_PG; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray_pg_len; i += 6) { + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + v4 = phy_regarray_table_pg[i+3]; + v5 = phy_regarray_table_pg[i+4]; + v6 = phy_regarray_table_pg[i+5]; + + if (v1<0xCDCDCDCD) { + if (v4 == 0xfe) + mdelay(50); + else if (v4 == 0xfd) + mdelay(5); + else if (v4 == 0xfc) + mdelay(1); + else if (v4 == 0xfb) + udelay(50); + else if (v4 == 0xfa) + udelay(5); + else if (v4 == 0xf9) + udelay(1); + + /*_rtl8821ae_store_pwrIndex_diffrate_offset*/ + _rtl8821ae_store_tx_power_by_rate(hw, v1, v2, v3, v4, v5, v6); + continue; + } else { + if (!_rtl8821ae_check_condition(hw,v1)) { /*don't need the hw_body*/ + i += 2; /* skip the pair of expression*/ + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + while (v2 != 0xDEAD) { + i += 3; + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + } + } + } + } + } else { + + RT_TRACE(COMP_SEND, DBG_TRACE, + ("configtype != BaseBand_Config_PHY_REG\n")); + } + return true; +} + +bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw * hw, + enum radio_path rfpath) +{ + #define READ_NEXT_RF_PAIR_8812(radioa_array_table,v1, v2, i) do { i += 2; v1 = radioa_array_table[i]; v2 = radioa_array_table[i+1]; } while(0) + + int i; + bool rtstatus = true; + u32 *radioa_array_table_a, *radioa_array_table_b; + u16 radioa_arraylen_a, radioa_arraylen_b; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 v1 = 0, v2 = 0; + + radioa_arraylen_a = RTL8812AE_RADIOA_1TARRAYLEN; + radioa_array_table_a= RTL8812AE_RADIOA_ARRAY; + radioa_arraylen_b= RTL8812AE_RADIOB_1TARRAYLEN; + radioa_array_table_b = RTL8812AE_RADIOB_ARRAY; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Radio_A:RTL8821AE_RADIOA_ARRAY %d\n",radioa_arraylen_a)); + RT_TRACE(COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath)); + rtstatus = true; + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radioa_arraylen_a; i = i + 2) { + v1 = radioa_array_table_a[i]; + v2 = radioa_array_table_a[i+1]; + if (v1<0xcdcdcdcd) { + _rtl8821ae_config_rf_radio_a(hw,v1,v2); + continue; + }else{/*This line is the start line of branch.*/ + if(!_rtl8821ae_check_condition(hw,v1)){ + /*Discard the following (offset, data) pairs*/ + READ_NEXT_RF_PAIR_8812(radioa_array_table_a,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < radioa_arraylen_a-2) + READ_NEXT_RF_PAIR_8812(radioa_array_table_a,v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + } else {/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_RF_PAIR_8812(radioa_array_table_a,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < radioa_arraylen_a -2) { + _rtl8821ae_config_rf_radio_a(hw,v1,v2); + READ_NEXT_RF_PAIR_8812(radioa_array_table_a,v1, v2, i); + } + + while (v2 != 0xDEAD && i < radioa_arraylen_a-2) + READ_NEXT_RF_PAIR_8812(radioa_array_table_a,v1, v2, i); + } + } + } + break; + case RF90_PATH_B: + for (i = 0; i < radioa_arraylen_b; i = i + 2) { + v1 = radioa_array_table_b[i]; + v2 = radioa_array_table_b[i+1]; + if (v1<0xcdcdcdcd) { + _rtl8821ae_config_rf_radio_b(hw,v1,v2); + continue; + }else{/*This line is the start line of branch.*/ + if(!_rtl8821ae_check_condition(hw,v1)){ + /*Discard the following (offset, data) pairs*/ + READ_NEXT_RF_PAIR_8812(radioa_array_table_b,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < radioa_arraylen_b-2) + READ_NEXT_RF_PAIR_8812(radioa_array_table_b,v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + } else {/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_RF_PAIR_8812(radioa_array_table_b,v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < radioa_arraylen_b-2) { + _rtl8821ae_config_rf_radio_b(hw,v1,v2); + READ_NEXT_RF_PAIR_8812(radioa_array_table_b,v1, v2, i); + } + + while (v2 != 0xDEAD && i < radioa_arraylen_b-2) + READ_NEXT_RF_PAIR_8812(radioa_array_table_b,v1, v2, i); + } + } + } + break; + case RF90_PATH_C: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + case RF90_PATH_D: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + return true; +} + + +bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw * hw, + enum radio_path rfpath) +{ + #define READ_NEXT_RF_PAIR(v1, v2, i) do { i += 2; v1 = radioa_array_table[i]; v2 = radioa_array_table[i+1]; } while(0) + + int i; + bool rtstatus = true; + u32 *radioa_array_table; + u16 radioa_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + //struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 v1 = 0, v2 = 0; + + radioa_arraylen = RTL8821AE_RADIOA_1TARRAYLEN; + radioa_array_table = RTL8821AE_RADIOA_ARRAY; + RT_TRACE(COMP_INIT, DBG_LOUD, + ("Radio_A:RTL8821AE_RADIOA_ARRAY %d\n",radioa_arraylen)); + RT_TRACE(COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath)); + rtstatus = true; + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radioa_arraylen; i = i + 2) { + v1 = radioa_array_table[i]; + v2 = radioa_array_table[i+1]; + if (v1<0xcdcdcdcd) { + _rtl8821ae_config_rf_radio_a(hw,v1,v2); + }else{/*This line is the start line of branch.*/ + if(!_rtl8821ae_check_condition(hw,v1)){ + /*Discard the following (offset, data) pairs*/ + READ_NEXT_RF_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < radioa_arraylen -2) + READ_NEXT_RF_PAIR(v1, v2, i); + + i -= 2; /* prevent from for-loop += 2*/ + } else {/*Configure matched pairs and skip to end of if-else.*/ + READ_NEXT_RF_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < radioa_arraylen -2) { + _rtl8821ae_config_rf_radio_a(hw,v1,v2); + READ_NEXT_RF_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < radioa_arraylen -2) + READ_NEXT_RF_PAIR(v1, v2, i); + } + } + } + break; + + case RF90_PATH_B: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + case RF90_PATH_C: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + case RF90_PATH_D: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + return true; +} + +void rtl8821ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->default_initialgain[0] = + (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[1] = + (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[2] = + (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[3] = + (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0); + + RT_TRACE(COMP_INIT, DBG_TRACE, + ("Default initial gain (c50=0x%x, " + "c58=0x%x, c60=0x%x, c68=0x%x \n", + rtlphy->default_initialgain[0], + rtlphy->default_initialgain[1], + rtlphy->default_initialgain[2], + rtlphy->default_initialgain[3])); + + rtlphy->framesync = (u8) rtl_get_bbreg(hw, + ROFDM0_RXDETECTOR3, MASKBYTE0); + rtlphy->framesync_c34 = rtl_get_bbreg(hw, + ROFDM0_RXDETECTOR2, MASKDWORD); + + RT_TRACE(COMP_INIT, DBG_TRACE, + ("Default framesync (0x%x) = 0x%x \n", + ROFDM0_RXDETECTOR3, rtlphy->framesync)); +} + +static void _rtl8821ae_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + + rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = RA_LSSIWRITE_8821A; + rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = RB_LSSIWRITE_8821A; + + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RHSSIREAD_8821AE; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RHSSIREAD_8821AE; + + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = RA_SIREAD_8821A; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = RB_SIREAD_8821A; + + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = RA_PIREAD_8821A; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = RB_PIREAD_8821A; +} + +void rtl8821ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 txpwr_level; + long txpwr_dbm; + + txpwr_level = rtlphy->cur_cck_txpwridx; + txpwr_dbm = _rtl8821ae_phy_txpwr_idx_to_dbm(hw, + WIRELESS_MODE_B, txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx; + if (_rtl8821ae_phy_txpwr_idx_to_dbm(hw, + WIRELESS_MODE_G, + txpwr_level) > txpwr_dbm) + txpwr_dbm = + _rtl8821ae_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, + txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx; + if (_rtl8821ae_phy_txpwr_idx_to_dbm(hw, + WIRELESS_MODE_N_24G, + txpwr_level) > txpwr_dbm) + txpwr_dbm = + _rtl8821ae_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, + txpwr_level); + *powerlevel = txpwr_dbm; +} + +static bool _rtl8821ae_phy_get_chnl_index(u8 channel, u8 *chnl_index) +{ + u8 channel_5g[CHANNEL_MAX_NUMBER_5G] = + {36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,100,102,104,106,108,110,112, + 114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,149,151, + 153,155,157,159,161,163,165,167,168,169,171,173,175,177}; + u8 i = 0; + bool in_24g = true; + + if (channel <= 14) { + in_24g = true; + *chnl_index = channel - 1; + } else { + in_24g = false; + + for (i = 0; i < sizeof(channel_5g) / sizeof(u8); ++i) { + if (channel_5g[i] == channel) { + *chnl_index = i; + return in_24g; + } + } + } + return in_24g; +} + +static char _rtl8821ae_phy_get_ratesection_intxpower_byrate(u8 path, u8 rate) +{ + char rate_section = 0; + switch (rate) { + case DESC_RATE1M: + case DESC_RATE2M: + case DESC_RATE5_5M: + case DESC_RATE11M: + rate_section = 0; + break; + + case DESC_RATE6M: + case DESC_RATE9M: + case DESC_RATE12M: + case DESC_RATE18M: + rate_section = 1; + break; + + case DESC_RATE24M: + case DESC_RATE36M: + case DESC_RATE48M: + case DESC_RATE54M: + rate_section = 2; + break; + + case DESC_RATEMCS0: + case DESC_RATEMCS1: + case DESC_RATEMCS2: + case DESC_RATEMCS3: + rate_section = 3; + break; + + case DESC_RATEMCS4: + case DESC_RATEMCS5: + case DESC_RATEMCS6: + case DESC_RATEMCS7: + rate_section = 4; + break; + + case DESC_RATEMCS8: + case DESC_RATEMCS9: + case DESC_RATEMCS10: + case DESC_RATEMCS11: + rate_section = 5; + break; + + case DESC_RATEMCS12: + case DESC_RATEMCS13: + case DESC_RATEMCS14: + case DESC_RATEMCS15: + rate_section = 6; + break; + + case DESC_RATEVHT1SS_MCS0: + case DESC_RATEVHT1SS_MCS1: + case DESC_RATEVHT1SS_MCS2: + case DESC_RATEVHT1SS_MCS3: + rate_section = 7; + break; + + case DESC_RATEVHT1SS_MCS4: + case DESC_RATEVHT1SS_MCS5: + case DESC_RATEVHT1SS_MCS6: + case DESC_RATEVHT1SS_MCS7: + rate_section = 8; + break; + + case DESC_RATEVHT1SS_MCS8: + case DESC_RATEVHT1SS_MCS9: + case DESC_RATEVHT2SS_MCS0: + case DESC_RATEVHT2SS_MCS1: + rate_section = 9; + break; + + case DESC_RATEVHT2SS_MCS2: + case DESC_RATEVHT2SS_MCS3: + case DESC_RATEVHT2SS_MCS4: + case DESC_RATEVHT2SS_MCS5: + rate_section = 10; + break; + + case DESC_RATEVHT2SS_MCS6: + case DESC_RATEVHT2SS_MCS7: + case DESC_RATEVHT2SS_MCS8: + case DESC_RATEVHT2SS_MCS9: + rate_section = 11; + break; + + default: + RT_ASSERT(true, ("Rate_Section is Illegal\n")); + break; + } + + return rate_section; +} + +static char _rtl8821ae_phy_get_txpower_by_rate(struct ieee80211_hw *hw, + u8 band, u8 path, u8 rate) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 shift = 0, rate_section, tx_num; + char tx_pwr_diff = 0; + + rate_section = _rtl8821ae_phy_get_ratesection_intxpower_byrate(path, rate); + tx_num = RF_TX_NUM_NONIMPLEMENT; + + if (tx_num == RF_TX_NUM_NONIMPLEMENT) { + if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15 ) || + (rate >= DESC_RATEVHT2SS_MCS2 && rate <= DESC_RATEVHT2SS_MCS9)) + tx_num = RF_2TX; + else + tx_num = RF_1TX; + } + + switch (rate) { + case DESC_RATE1M: shift = 0; break; + case DESC_RATE2M: shift = 8; break; + case DESC_RATE5_5M: shift = 16; break; + case DESC_RATE11M: shift = 24; break; + + case DESC_RATE6M: shift = 0; break; + case DESC_RATE9M: shift = 8; break; + case DESC_RATE12M: shift = 16; break; + case DESC_RATE18M: shift = 24; break; + + case DESC_RATE24M: shift = 0; break; + case DESC_RATE36M: shift = 8; break; + case DESC_RATE48M: shift = 16; break; + case DESC_RATE54M: shift = 24; break; + + case DESC_RATEMCS0: shift = 0; break; + case DESC_RATEMCS1: shift = 8; break; + case DESC_RATEMCS2: shift = 16; break; + case DESC_RATEMCS3: shift = 24; break; + + case DESC_RATEMCS4: shift = 0; break; + case DESC_RATEMCS5: shift = 8; break; + case DESC_RATEMCS6: shift = 16; break; + case DESC_RATEMCS7: shift = 24; break; + + case DESC_RATEMCS8: shift = 0; break; + case DESC_RATEMCS9: shift = 8; break; + case DESC_RATEMCS10: shift = 16; break; + case DESC_RATEMCS11: shift = 24; break; + + case DESC_RATEMCS12: shift = 0; break; + case DESC_RATEMCS13: shift = 8; break; + case DESC_RATEMCS14: shift = 16; break; + case DESC_RATEMCS15: shift = 24; break; + + case DESC_RATEVHT1SS_MCS0: shift = 0; break; + case DESC_RATEVHT1SS_MCS1: shift = 8; break; + case DESC_RATEVHT1SS_MCS2: shift = 16; break; + case DESC_RATEVHT1SS_MCS3: shift = 24; break; + + case DESC_RATEVHT1SS_MCS4: shift = 0; break; + case DESC_RATEVHT1SS_MCS5: shift = 8; break; + case DESC_RATEVHT1SS_MCS6: shift = 16; break; + case DESC_RATEVHT1SS_MCS7: shift = 24; break; + + case DESC_RATEVHT1SS_MCS8: shift = 0; break; + case DESC_RATEVHT1SS_MCS9: shift = 8; break; + case DESC_RATEVHT2SS_MCS0: shift = 16; break; + case DESC_RATEVHT2SS_MCS1: shift = 24; break; + + case DESC_RATEVHT2SS_MCS2: shift = 0; break; + case DESC_RATEVHT2SS_MCS3: shift = 8; break; + case DESC_RATEVHT2SS_MCS4: shift = 16; break; + case DESC_RATEVHT2SS_MCS5: shift = 24; break; + + case DESC_RATEVHT2SS_MCS6: shift = 0; break; + case DESC_RATEVHT2SS_MCS7: shift = 8; break; + case DESC_RATEVHT2SS_MCS8: shift = 16; break; + case DESC_RATEVHT2SS_MCS9: shift = 24; break; + + default: + RT_ASSERT(true, ("Rate_Section is Illegal\n")); + break; + } + + tx_pwr_diff = (u8) (rtlphy->tx_power_by_rate_offset[band][path][tx_num][rate_section] >> shift) & 0xff; + + return tx_pwr_diff; +} + +static u8 _rtl8821ae_get_txpower_index(struct ieee80211_hw *hw, u8 path, + u8 rate, u8 bandwidth, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + u8 txpower = 0; + bool in_24g = false; + char powerdiff_byrate = 0; + + if (((rtlhal->current_bandtype == BAND_ON_2_4G) && (channel > 14 || channel < 1)) || + ((rtlhal->current_bandtype == BAND_ON_5G) && (channel <= 14))) { + index = 0; + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("Illegal channel!!\n")); + } + + in_24g = _rtl8821ae_phy_get_chnl_index(channel, &index); + if (in_24g) { + if (RX_HAL_IS_CCK_RATE(rate)) + txpower = rtlefuse->txpwrlevel_cck[path][index]; + else if ( DESC_RATE6M <= rate ) + txpower = rtlefuse->txpwrlevel_ht40_1s[path][index]; + else + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("invalid rate\n")); + + if (DESC_RATE6M <= rate && rate <= DESC_RATE54M && !RX_HAL_IS_CCK_RATE(rate)) + txpower += rtlefuse->txpwr_legacyhtdiff[path][TX_1S]; + + if (bandwidth == HT_CHANNEL_WIDTH_20) { + if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_ht20diff[path][TX_1S]; + if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_ht20diff[path][TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_20_40) { + if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_ht40diff[path][TX_1S]; + if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_ht40diff[path][TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_80) { + if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_ht40diff[path][TX_1S]; + if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_ht40diff[path][TX_2S]; + } + + } else { + if (DESC_RATE6M <= rate) + txpower = rtlefuse->txpwr_5g_bw40base[path][index]; + else + RT_TRACE(COMP_POWER_TRACKING, DBG_WARNING,("INVALID Rate.\n")); + + if (DESC_RATE6M <= rate && rate <= DESC_RATE54M && !RX_HAL_IS_CCK_RATE(rate)) + txpower += rtlefuse->txpwr_5g_ofdmdiff[path][TX_1S]; + + if (bandwidth == HT_CHANNEL_WIDTH_20) { + if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw20diff[path][TX_1S]; + if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw20diff[path][TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_20_40) { + if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw40diff[path][TX_1S]; + if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower += rtlefuse->txpwr_5g_bw40diff[path][TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_80) { + u8 channel_5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171}; + u8 i = 0; + for (i = 0; i < sizeof(channel_5g_80m) / sizeof(u8); ++i) + if (channel_5g_80m[i] == channel) + index = i; + + if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower = rtlefuse->txpwr_5g_bw80base[path][index] + + rtlefuse->txpwr_5g_bw80diff[path][TX_1S]; + if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) || + (DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9)) + txpower = rtlefuse->txpwr_5g_bw80base[path][index] + + rtlefuse->txpwr_5g_bw80diff[path][TX_1S] + + rtlefuse->txpwr_5g_bw80diff[path][TX_2S]; + } + } + if (rtlefuse->eeprom_regulatory != 2) + powerdiff_byrate = _rtl8821ae_phy_get_txpower_by_rate(hw, + (u8)(!in_24g), path, rate); + + if (rate == DESC_RATEVHT1SS_MCS8 || rate == DESC_RATEVHT1SS_MCS9 || + rate == DESC_RATEVHT2SS_MCS8 || rate == DESC_RATEVHT2SS_MCS9) + txpower -= powerdiff_byrate; + else + txpower += powerdiff_byrate; + + if (rate > DESC_RATE11M) + txpower += rtlpriv->dm.remnant_ofdm_swing_idx[path]; + else + txpower += rtlpriv->dm.remnant_cck_idx; + + if (txpower > MAX_POWER_INDEX) + txpower = MAX_POWER_INDEX; + + return txpower; +} + +static void _rtl8821ae_phy_set_txpower_index(struct ieee80211_hw *hw, + u8 power_index, u8 path, u8 rate) +{ + struct rtl_priv* rtlpriv = rtl_priv(hw); + + if (path == RF90_PATH_A) { + switch (rate) { + case DESC_RATE1M: + rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKBYTE0, power_index); + break; + case DESC_RATE2M: + rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKBYTE1, power_index); + break; + case DESC_RATE5_5M: + rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKBYTE2, power_index); + break; + case DESC_RATE11M: + rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKBYTE3, power_index); + break; + + case DESC_RATE6M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6, MASKBYTE0, power_index); + break; + case DESC_RATE9M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6, MASKBYTE1, power_index); + break; + case DESC_RATE12M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6, MASKBYTE2, power_index); + break; + case DESC_RATE18M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6, MASKBYTE3, power_index); + break; + + case DESC_RATE24M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24, MASKBYTE0, power_index); + break; + case DESC_RATE36M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24, MASKBYTE1, power_index); + break; + case DESC_RATE48M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24, MASKBYTE2, power_index); + break; + case DESC_RATE54M: + rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS0: + rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE0, power_index); + break; + case DESC_RATEMCS1: + rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE1, power_index); + break; + case DESC_RATEMCS2: + rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE2, power_index); + break; + case DESC_RATEMCS3: + rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS4: + rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE0, power_index); + break; + case DESC_RATEMCS5: + rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE1, power_index); + break; + case DESC_RATEMCS6: + rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE2, power_index); + break; + case DESC_RATEMCS7: + rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS8: + rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE0, power_index); + break; + case DESC_RATEMCS9: + rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE1, power_index); + break; + case DESC_RATEMCS10: + rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE2, power_index); + break; + case DESC_RATEMCS11: + rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS12: + rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE0, power_index); + break; + case DESC_RATEMCS13: + rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE1, power_index); + break; + case DESC_RATEMCS14: + rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE2, power_index); + break; + case DESC_RATEMCS15: + rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT1SS_MCS0: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0, MASKBYTE0, power_index); + break; + case DESC_RATEVHT1SS_MCS1: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0, MASKBYTE1, power_index); + break; + case DESC_RATEVHT1SS_MCS2: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0, MASKBYTE2, power_index); + break; + case DESC_RATEVHT1SS_MCS3: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT1SS_MCS4: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4, MASKBYTE0, power_index); + break; + case DESC_RATEVHT1SS_MCS5: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4, MASKBYTE1, power_index); + break; + case DESC_RATEVHT1SS_MCS6: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4, MASKBYTE2, power_index); + break; + case DESC_RATEVHT1SS_MCS7: + rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT1SS_MCS8: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8, MASKBYTE0, power_index); + break; + case DESC_RATEVHT1SS_MCS9: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8, MASKBYTE1, power_index); + break; + case DESC_RATEVHT2SS_MCS0: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8, MASKBYTE2, power_index); + break; + case DESC_RATEVHT2SS_MCS1: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT2SS_MCS2: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2, MASKBYTE0, power_index); + break; + case DESC_RATEVHT2SS_MCS3: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2, MASKBYTE1, power_index); + break; + case DESC_RATEVHT2SS_MCS4: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2, MASKBYTE2, power_index); + break; + case DESC_RATEVHT2SS_MCS5: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT2SS_MCS6: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6, MASKBYTE0, power_index); + break; + case DESC_RATEVHT2SS_MCS7: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6, MASKBYTE1, power_index); + break; + case DESC_RATEVHT2SS_MCS8: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6, MASKBYTE2, power_index); + break; + case DESC_RATEVHT2SS_MCS9: + rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6, MASKBYTE3, power_index); + break; + + default: + RT_TRACE(COMP_POWER, DBG_LOUD, ("Invalid Rate!!\n")); + break; + } + } else if (path == RF90_PATH_B) { + switch (rate) { + case DESC_RATE1M: + rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKBYTE0, power_index); + break; + case DESC_RATE2M: + rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKBYTE1, power_index); + break; + case DESC_RATE5_5M: + rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKBYTE2, power_index); + break; + case DESC_RATE11M: + rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKBYTE3, power_index); + break; + + case DESC_RATE6M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6, MASKBYTE0, power_index); + break; + case DESC_RATE9M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6, MASKBYTE1, power_index); + break; + case DESC_RATE12M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6, MASKBYTE2, power_index); + break; + case DESC_RATE18M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6, MASKBYTE3, power_index); + break; + + case DESC_RATE24M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24, MASKBYTE0, power_index); + break; + case DESC_RATE36M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24, MASKBYTE1, power_index); + break; + case DESC_RATE48M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24, MASKBYTE2, power_index); + break; + case DESC_RATE54M: + rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS0: + rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE0, power_index); + break; + case DESC_RATEMCS1: + rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE1, power_index); + break; + case DESC_RATEMCS2: + rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE2, power_index); + break; + case DESC_RATEMCS3: + rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS4: + rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE0, power_index); + break; + case DESC_RATEMCS5: + rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE1, power_index); + break; + case DESC_RATEMCS6: + rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE2, power_index); + break; + case DESC_RATEMCS7: + rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS8: + rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE0, power_index); + break; + case DESC_RATEMCS9: + rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE1, power_index); + break; + case DESC_RATEMCS10: + rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE2, power_index); + break; + case DESC_RATEMCS11: + rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE3, power_index); + break; + + case DESC_RATEMCS12: + rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE0, power_index); + break; + case DESC_RATEMCS13: + rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE1, power_index); + break; + case DESC_RATEMCS14: + rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE2, power_index); + break; + case DESC_RATEMCS15: + rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT1SS_MCS0: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0, MASKBYTE0, power_index); + break; + case DESC_RATEVHT1SS_MCS1: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0, MASKBYTE1, power_index); + break; + case DESC_RATEVHT1SS_MCS2: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0, MASKBYTE2, power_index); + break; + case DESC_RATEVHT1SS_MCS3: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT1SS_MCS4: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4, MASKBYTE0, power_index); + break; + case DESC_RATEVHT1SS_MCS5: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4, MASKBYTE1, power_index); + break; + case DESC_RATEVHT1SS_MCS6: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4, MASKBYTE2, power_index); + break; + case DESC_RATEVHT1SS_MCS7: + rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT1SS_MCS8: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8, MASKBYTE0, power_index); + break; + case DESC_RATEVHT1SS_MCS9: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8, MASKBYTE1, power_index); + break; + case DESC_RATEVHT2SS_MCS0: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8, MASKBYTE2, power_index); + break; + case DESC_RATEVHT2SS_MCS1: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT2SS_MCS2: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2, MASKBYTE0, power_index); + break; + case DESC_RATEVHT2SS_MCS3: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2, MASKBYTE1, power_index); + break; + case DESC_RATEVHT2SS_MCS4: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2, MASKBYTE2, power_index); + break; + case DESC_RATEVHT2SS_MCS5: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2, MASKBYTE3, power_index); + break; + + case DESC_RATEVHT2SS_MCS6: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6, MASKBYTE0, power_index); + break; + case DESC_RATEVHT2SS_MCS7: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6, MASKBYTE1, power_index); + break; + case DESC_RATEVHT2SS_MCS8: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6, MASKBYTE2, power_index); + break; + case DESC_RATEVHT2SS_MCS9: + rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6, MASKBYTE3, power_index); + break; + + default: + RT_TRACE(COMP_POWER, DBG_LOUD, ("Invalid Rate!!\n")); + break; + } + } else { + RT_TRACE(COMP_POWER, DBG_LOUD, ("Invalid RFPath!!\n")); + } +} + +void _rtl8821ae_phy_set_txpower_level_by_path(struct ieee80211_hw *hw, + u8 *array, u8 path, u8 channel, + u8 size) +{ + struct rtl_phy *rtlphy = &(rtl_priv(hw)->phy); + u8 i; + u8 power_index; + for (i = 0; i < size; i ++) { + power_index = _rtl8821ae_get_txpower_index(hw, path, array[i], + rtlphy->current_chan_bw, channel); + _rtl8821ae_phy_set_txpower_index(hw, power_index, path, array[i]); + } +} + +static void _rtl8821ae_phy_txpower_training_by_path(struct ieee80211_hw *hw, + u8 bw, u8 channel, u8 path) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + u8 i; + u32 power_level, data, offset; + + if(path >= rtlphy->num_total_rfpath) + return; + + data = 0; + if (path == RF90_PATH_A) { + power_level = + _rtl8821ae_get_txpower_index(hw, RF90_PATH_A, + DESC_RATEMCS7, bw, channel); + offset = RA_TXPWRTRAING; + } else { + power_level = + _rtl8821ae_get_txpower_index(hw, RF90_PATH_A, + DESC_RATEMCS7, bw, channel); + offset = RB_TXPWRTRAING; + } + + for (i = 0; i < 3; i++) { + if (i == 0) + power_level = power_level - 10; + else if (i == 1) + power_level = power_level - 8; + else + power_level = power_level - 6; + + data |= (((power_level > 2) ? (power_level) : 2) << (i * 8)); + } + rtl_set_bbreg(hw, offset, 0xffffff, data); +} + +void rtl8821ae_phy_set_txpower_level_by_path(struct ieee80211_hw *hw, u8 channel, u8 path) +{ + //struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtl_priv(hw)->phy); + u8 cck_rates[] = {DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M}; + u8 ofdm_rates[] = {DESC_RATE6M, DESC_RATE9M, DESC_RATE12M, DESC_RATE18M, + DESC_RATE24M, DESC_RATE36M, DESC_RATE48M, DESC_RATE54M}; + u8 ht_rates_1t[] = {DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2, DESC_RATEMCS3, + DESC_RATEMCS4, DESC_RATEMCS5, DESC_RATEMCS6, DESC_RATEMCS7}; + u8 ht_rates_2t[] = {DESC_RATEMCS8, DESC_RATEMCS9, DESC_RATEMCS10, DESC_RATEMCS11, + DESC_RATEMCS12, DESC_RATEMCS13, DESC_RATEMCS14, DESC_RATEMCS15}; + u8 vht_rates_1t[] = {DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1, DESC_RATEVHT1SS_MCS2, + DESC_RATEVHT1SS_MCS3, DESC_RATEVHT1SS_MCS4, + DESC_RATEVHT1SS_MCS5, DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7, + DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9}; + u8 vht_rates_2t[] = {DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1, DESC_RATEVHT2SS_MCS2, + DESC_RATEVHT2SS_MCS3, DESC_RATEVHT2SS_MCS4, + DESC_RATEVHT2SS_MCS5, DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7, + DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9}; + //u8 i,size; + //u8 power_index; + + if (rtlhal->current_bandtype == BAND_ON_2_4G) + _rtl8821ae_phy_set_txpower_level_by_path(hw,cck_rates,path,channel, + sizeof(cck_rates) / sizeof(u8)); + + _rtl8821ae_phy_set_txpower_level_by_path(hw,ofdm_rates,path,channel, + sizeof(ofdm_rates) / sizeof(u8)); + _rtl8821ae_phy_set_txpower_level_by_path(hw,ht_rates_1t,path,channel, + sizeof(ht_rates_1t) / sizeof(u8)); + _rtl8821ae_phy_set_txpower_level_by_path(hw,vht_rates_1t,path,channel, + sizeof(vht_rates_1t) / sizeof(u8)); + + if (rtlphy->num_total_rfpath >= 2) { + _rtl8821ae_phy_set_txpower_level_by_path(hw,ht_rates_2t,path,channel, + sizeof(ht_rates_2t) / sizeof(u8)); + _rtl8821ae_phy_set_txpower_level_by_path(hw,vht_rates_2t,path,channel, + sizeof(vht_rates_2t) / sizeof(u8)); + } + + _rtl8821ae_phy_txpower_training_by_path(hw, rtlphy->current_chan_bw, channel, path); +} +/*just in case, write txpower in DW, to reduce time*/ +#if 0 +void _rtl8821ae_phy_get_txpower_index_by_rate_array(struct ieee80211_hw *hw, u8 channel, + u8 *rate, u8 path, u8 bw, u8 *power_index, u8 size) +{ + u8 i; + for (i = 0; i < size; i++) + power_index[i] = _rtl8821ae_get_txpower_index(hw, path, rate[i], bw, channel); +} + +void rtl8821ae_phy_set_txpower_level_by_path2(struct ieee80211_hw *hw, u8 channel, u8 path) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtl_priv(hw)->phy); + u8 cck_rates[] = {DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M}; + u8 ofdm_rates[] = {DESC_RATE6M, DESC_RATE9M, DESC_RATE12M, DESC_RATE18M, + DESC_RATE24M, DESC_RATE36M, DESC_RATE48M, DESC_RATE54M}; + u8 ht_rates_1t[] = {DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2, DESC_RATEMCS3, + DESC_RATEMCS4, DESC_RATEMCS5, DESC_RATEMCS6, DESC_RATEMCS7}; + u8 ht_rates_2t[] = {DESC_RATEMCS8, DESC_RATEMCS9, DESC_RATEMCS10, DESC_RATEMCS11, + DESC_RATEMCS12, DESC_RATEMCS13, DESC_RATEMCS14, DESC_RATEMCS15}; + u8 vht_rates_1t[] = {DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1, DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3, DESC_RATEVHT1SS_MCS4, + DESC_RATEVHT1SS_MCS5, DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7, DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9}; + u8 vht_rates_2t[] = {DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1, DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3, DESC_RATEVHT2SS_MCS4, + DESC_RATEVHT2SS_MCS5, DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7, DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9}; + u8 i, j; + u8 pwridx[48] = {0}; + u8 cs = sizeof(cck_rates) / sizeof(u8); + u8 os = sizeof(ofdm_rates) / sizeof(u8); + u8 h1s = sizeof(ht_rates_1t) / sizeof(u8); + u8 h2s = sizeof(ht_rates_2t) / sizeof(u8); + u8 v1s = sizeof(vht_rates_1t) / sizeof(u8); + u8 v2s = sizeof(vht_rates_2t) / sizeof(u8); + + u8 len, start; + u32 reg_addr, power_index; + u8 bw = rtlphy->current_chan_bw; + + _rtl8821ae_phy_get_txpower_index_by_rate_array(hw, channel, + ofdm_rates, path, bw, &pwridx[cs], os); + + _rtl8821ae_phy_get_txpower_index_by_rate_array(hw, channel, + ht_rates_1t, path, bw, &pwridx[cs+os], h1s); + + _rtl8821ae_phy_get_txpower_index_by_rate_array(hw, channel, + vht_rates_1t, path, bw, &pwridx[cs+os+h1s+h2s], v1s); + + + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + _rtl8821ae_phy_get_txpower_index_by_rate_array(hw, channel, + cck_rates, path, bw, pwridx, cs); + + start = 0; + } else { + start = cs; + } + + reg_addr = (path == 0) ? RTXAGC_A_CCK11_CCK1 : RTXAGC_B_CCK11_CCK1; + reg_addr += start; + + len = cs + os + h1s + h2s + v1s; + if (rtlphy->num_total_rfpath >= 2) { + _rtl8821ae_phy_get_txpower_index_by_rate_array(hw, channel, + ht_rates_2t, path, bw, &pwridx[cs+os+h1s], h2s); + + _rtl8821ae_phy_get_txpower_index_by_rate_array(hw, channel, + vht_rates_2t, path, bw, &pwridx[cs+os+h1s+h2s+v1s], v2s); + + len += v2s; + } + for (i = start; i < len; i += 4) { + power_index = 0; + for (j = 0; j < 4; j++) + power_index |= (pwridx[i+j] << (j*8)); + rtl_set_bbreg(hw, reg_addr + i, MASKDWORD, power_index); + } + + _rtl8821ae_phy_txpower_training_by_path(hw, rtlphy->current_chan_bw, channel, path); +} +#endif + +void rtl8821ae_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 path = 0; + + for (path = RF90_PATH_A; path < rtlphy->num_total_rfpath; ++path ) + rtl8821ae_phy_set_txpower_level_by_path(hw, channel, path); +} + +static long _rtl8821ae_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u8 txpwridx) +{ + long offset; + long pwrout_dbm; + + switch (wirelessmode) { + case WIRELESS_MODE_B: + offset = -7; + break; + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + offset = -8; + break; + default: + offset = -8; + break; + } + pwrout_dbm = txpwridx / 2 + offset; + return pwrout_dbm; +} + +void rtl8821ae_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + enum io_type iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN; + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP_BAND0: + iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_IO_CMD, + (u8 *) & iotype); + + break; + case SCAN_OPT_BACKUP_BAND1: + iotype = IO_CMD_PAUSE_BAND1_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_IO_CMD, + (u8 *) & iotype); + + break; + case SCAN_OPT_RESTORE: + iotype = IO_CMD_RESUME_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_IO_CMD, + (u8 *) & iotype); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("Unknown Scan Backup operation.\n")); + break; + } + } +} + +static void _rtl8821ae_phy_set_reg_bw(struct rtl_priv * rtlpriv, u8 bw) +{ + u16 reg_rf_mode_bw, tmp = 0; + reg_rf_mode_bw = rtl_read_word(rtlpriv, REG_TRXPTCL_CTL); + switch (bw) { + case HT_CHANNEL_WIDTH_20: + rtl_write_word(rtlpriv, REG_TRXPTCL_CTL, reg_rf_mode_bw & 0xFE7F); + break; + case HT_CHANNEL_WIDTH_20_40: + tmp = reg_rf_mode_bw | BIT(7); + rtl_write_word(rtlpriv, REG_TRXPTCL_CTL, tmp & 0xFEFF); + break; + case HT_CHANNEL_WIDTH_80: + tmp = reg_rf_mode_bw | BIT(8); + rtl_write_word(rtlpriv, REG_TRXPTCL_CTL, tmp & 0xFF7F); + break; + default: + RT_TRACE(COMP_ERR, DBG_WARNING,("unknown Bandwidth: 0x%x\n",bw)); + break; + } +} + +static u8 _rtl8821ae_phy_get_secondary_chnl(struct rtl_priv * rtlpriv) +{ + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtlpriv); + u8 sc_set_40 = 0, sc_set_20 =0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) { + if(mac->cur_80_prime_sc == PRIME_CHNL_OFFSET_LOWER) + sc_set_40 = VHT_DATA_SC_40_LOWER_OF_80MHZ; + else if(mac->cur_80_prime_sc == PRIME_CHNL_OFFSET_UPPER) + sc_set_40 = VHT_DATA_SC_40_UPPER_OF_80MHZ; + else + RT_TRACE(COMP_ERR, DBG_EMERG, + ("SCMapping: Not Correct Primary40MHz Setting \n")); + + if((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_LOWER) && + (mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER)) + sc_set_20 = VHT_DATA_SC_20_LOWEST_OF_80MHZ; + else if((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_UPPER) && + (mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER)) + sc_set_20 = VHT_DATA_SC_20_LOWER_OF_80MHZ; + else if((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_LOWER) && + (mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_UPPER)) + sc_set_20 = VHT_DATA_SC_20_UPPER_OF_80MHZ; + else if((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_UPPER) && + (mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_UPPER)) + sc_set_20 = VHT_DATA_SC_20_UPPERST_OF_80MHZ; + else + RT_TRACE(COMP_ERR, DBG_EMERG, + ("SCMapping: Not Correct Primary40MHz Setting \n")); + } else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + if (mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_UPPER) + sc_set_20 = VHT_DATA_SC_20_UPPER_OF_80MHZ; + else if (mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_LOWER) + sc_set_20 = VHT_DATA_SC_20_LOWER_OF_80MHZ; + else + RT_TRACE(COMP_ERR, DBG_EMERG, + ("SCMapping: Not Correct Primary40MHz Setting \n")); + } + return ((sc_set_40 << 4) | sc_set_20); +} + +void rtl8821ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 sub_chnl = 0; + u8 l1pk_val = 0; + + RT_TRACE(COMP_SCAN, DBG_TRACE, + ("Switch to %s bandwidth\n", + (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? + "20MHz" : + (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40 ? + "40MHz" : "80MHz")))) + + + + _rtl8821ae_phy_set_reg_bw(rtlpriv, rtlphy->current_chan_bw); + sub_chnl = _rtl8821ae_phy_get_secondary_chnl(rtlpriv); + rtl_write_byte(rtlpriv, 0x0483, sub_chnl); + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + rtl_set_bbreg(hw, RRFMOD, 0x003003C3, 0x00300200); + rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 0); + + if(rtlphy->rf_type == RF_2T2R) + rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, 7); + else + rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, 8); + break; + case HT_CHANNEL_WIDTH_20_40: + rtl_set_bbreg(hw, RRFMOD, 0x003003C3, 0x00300201); + rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 0); + rtl_set_bbreg(hw, RRFMOD, 0x3C, sub_chnl); + rtl_set_bbreg(hw, RCCAONSEC, 0xf0000000, sub_chnl); + + if(rtlphy->reg_837 & BIT(2)) + l1pk_val = 6; + else + { + if(rtlphy->rf_type == RF_2T2R) + l1pk_val = 7; + else + l1pk_val = 8; + } + rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, l1pk_val); // 0x848[25:22] = 0x6 + + if(sub_chnl == VHT_DATA_SC_20_UPPER_OF_80MHZ) + rtl_set_bbreg(hw, RCCK_SYSTEM, BCCK_SYSTEM, 1); + else + rtl_set_bbreg(hw, RCCK_SYSTEM, BCCK_SYSTEM, 0); + break; + + case HT_CHANNEL_WIDTH_80: + rtl_set_bbreg(hw, RRFMOD, 0x003003C3, 0x00300202); // 0x8ac[21,20,9:6,1,0]=8'b11100010 + rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 1); // 0x8c4[30] = 1 + rtl_set_bbreg(hw, RRFMOD, 0x3C, sub_chnl); + rtl_set_bbreg(hw, RCCAONSEC, 0xf0000000, sub_chnl); + + if(rtlphy->reg_837 & BIT(2)) + l1pk_val = 5; + else + { + if(rtlphy->rf_type == RF_2T2R) + l1pk_val = 6; + else + l1pk_val = 7; + } + rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, l1pk_val); + + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); + break; + } + + rtl8812ae_fixspur(hw, rtlphy->current_chan_bw, rtlphy->current_channel); + + rtl8821ae_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + + RT_TRACE(COMP_SCAN, DBG_LOUD, (" \n")); +} + +void rtl8821ae_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_bw = rtlphy->current_chan_bw; + + if (rtlphy->set_bwmode_inprogress) + return; + rtlphy->set_bwmode_inprogress = true; + if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtl8821ae_phy_set_bw_mode_callback(hw); + } else { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("FALSE driver sleep or unload\n")); + rtlphy->set_bwmode_inprogress = false; + rtlphy->current_chan_bw = tmp_bw; + } +} + +void rtl8821ae_phy_sw_chnl_callback(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 channel = rtlphy->current_channel; + u8 path; + u32 data; + + RT_TRACE(COMP_SCAN, DBG_TRACE, + ("switch to channel%d\n", rtlphy->current_channel)); + if (is_hal_stop(rtlhal)) + return; + + if (36 <= channel && channel <= 48) + data = 0x494; + else if (50 <= channel && channel <= 64) + data = 0x453; + else if (100 <= channel && channel <= 116) + data = 0x452; + else if (118 <= channel) + data = 0x412; + else + data = 0x96a; + rtl_set_bbreg(hw, RFC_AREA, 0x1ffe0000, data); + + + for(path = RF90_PATH_A; path < rtlphy->num_total_rfpath; path++) + { + if (36 <= channel && channel <= 64) + data = 0x101; + else if (100 <= channel && channel <= 140) + data = 0x301; + else if (140 < channel) + data = 0x501; + else + data = 0x000; + rtl8821ae_phy_set_rf_reg(hw, path, RF_CHNLBW, + BIT(18)|BIT(17)|BIT(16)|BIT(9)|BIT(8), data); + + rtl8821ae_phy_set_rf_reg(hw, path, RF_CHNLBW, + BMASKBYTE0, channel); + + if (channel > 14) { + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + if (36 <= channel && channel <= 64) + data = 0x114E9; + else if (100 <= channel && channel <= 140) + data = 0x110E9; + else + data = 0x110E9; + rtl8821ae_phy_set_rf_reg(hw, path, RF_APK, + BRFREGOFFSETMASK, data); + } + } + } + RT_TRACE(COMP_SCAN, DBG_TRACE, ("\n")); +} + +u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 timeout = 1000, timecount = 0; + u8 channel = rtlphy->current_channel; + + if (rtlphy->sw_chnl_inprogress) + return 0; + if (rtlphy->set_bwmode_inprogress) + return 0; + + if ((is_hal_stop(rtlhal)) || (RT_CANNOT_IO(hw))) { + RT_TRACE(COMP_CHAN, DBG_LOUD, + ("sw_chnl_inprogress false driver sleep or unload\n")); + return 0; + } + while (rtlphy->lck_inprogress && timecount < timeout) { + mdelay(50); + timecount += 50; + } + + if (rtlphy->current_channel > 14 && rtlhal->current_bandtype != BAND_ON_5G) + rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_5G); + else if (rtlphy->current_channel <= 14 && rtlhal->current_bandtype != BAND_ON_2_4G) + rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_2_4G); + + rtlphy->sw_chnl_inprogress = true; + if (channel == 0) + channel = 1; + + RT_TRACE(COMP_SCAN, DBG_TRACE, + ("switch to channel%d, band type is %d\n", rtlphy->current_channel, rtlhal->current_bandtype)); + + rtl8821ae_phy_sw_chnl_callback(hw); + + rtl8821ae_dm_clear_txpower_tracking_state(hw); + rtl8821ae_phy_set_txpower_level(hw, rtlphy->current_channel); + + RT_TRACE(COMP_SCAN, DBG_TRACE, ("\n")); + rtlphy->sw_chnl_inprogress = false; + return 1; +} + +#if 0 +static u8 _rtl8821ae_phy_path_b_iqk(struct ieee80211_hw *hw) +{ + u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc; + u8 result = 0x00; + + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002); + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000); + mdelay(IQK_DELAY_TIME); + reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); + reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); + reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); + reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); + reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); + + if (!(reg_eac & BIT(31)) && + (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && + (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; + if (!(reg_eac & BIT(30)) && + (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && + (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + return result; +} + +static u8 _rtl8821ae_phy_path_a_rx_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ + u32 reg_eac, reg_e94, reg_e9c, reg_ea4,u32temp; + u8 result = 0x00; + + /*Get TXIMR Setting*/ + /*Modify RX IQK mode table*/ + rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); + rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0); + rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000); + rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f); + rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b); + rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + + /*IQK Setting*/ + rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, 0x01007c00); + rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x81004800); + + /*path a IQK setting*/ + rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x10008c1c); + rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x30008c1c); + rtl_set_bbreg(hw, RTx_IQK_PI_A, MASKDWORD, 0x82160804); + rtl_set_bbreg(hw, RRx_IQK_PI_A, MASKDWORD, 0x28160000); + + /*LO calibration Setting*/ + rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x0046a911); + /*one shot,path A LOK & iqk*/ + rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + + mdelay(IQK_DELAY_TIME); + + reg_eac = rtl_get_bbreg(hw, RRx_Power_After_IQK_A_2, MASKDWORD); + reg_e94 = rtl_get_bbreg(hw, RTx_Power_Before_IQK_A, MASKDWORD); + reg_e9c = rtl_get_bbreg(hw, RTx_Power_After_IQK_A, MASKDWORD); + + + if (!(reg_eac & BIT(28)) && + (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && + (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; + + u32temp = 0x80007C00 | (reg_e94&0x3FF0000) | ((reg_e9c&0x3FF0000) >> 16); + rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, u32temp); + /*RX IQK*/ + /*Modify RX IQK mode table*/ + rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); + rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0); + rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000); + rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f); + rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa); + rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + + /*IQK Setting*/ + rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x01004800); + + /*path a IQK setting*/ + rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x30008c1c); + rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x10008c1c); + rtl_set_bbreg(hw, RTx_IQK_PI_A, MASKDWORD, 0x82160c05); + rtl_set_bbreg(hw, RRx_IQK_PI_A, MASKDWORD, 0x28160c05); + + /*LO calibration Setting*/ + rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x0046a911); + /*one shot,path A LOK & iqk*/ + rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + + mdelay(IQK_DELAY_TIME); + + reg_eac = rtl_get_bbreg(hw, RRx_Power_After_IQK_A_2, MASKDWORD); + reg_e94 = rtl_get_bbreg(hw, RTx_Power_Before_IQK_A, MASKDWORD); + reg_e9c = rtl_get_bbreg(hw, RTx_Power_After_IQK_A, MASKDWORD); + reg_ea4 = rtl_get_bbreg(hw, RRx_Power_Before_IQK_A_2, MASKDWORD); + + if (!(reg_eac & BIT(27)) && + (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) && + (((reg_eac & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + return result; +} +#endif + +u8 _rtl8812ae_get_right_chnl_place_for_iqk(u8 chnl) +{ + u8 channel_all[TARGET_CHNL_NUM_2G_5G_8812] = + {1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,38,40,42,\ + 44,46,48,50,52,54,56,58,60,62,64,100,\ + 102,104,106,108,110,112,114,116,118,\ + 120,122,124,126,128,130,132,134,136,\ + 138,140,149,151,153,155,157,159,161,\ + 163,165}; + u8 place = chnl; + + if(chnl > 14) + { + for(place = 14; place Page C*/ + if (rx_x >> 1 ==0x112 || rx_y >> 1 == 0x3ee){ + rtl_set_bbreg(hw, 0xc10, 0x000003ff, 0x100); + rtl_set_bbreg(hw, 0xc10, 0x03ff0000, 0); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX_X = %x;;RX_Y = %x ====>fill to IQC\n", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff)); + } + else{ + rtl_set_bbreg(hw, 0xc10, 0x000003ff, rx_x >> 1); + rtl_set_bbreg(hw, 0xc10, 0x03ff0000, rx_y >> 1); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX_X = %x;;RX_Y = %x ====>fill to IQC\n", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("0xc10 = %x ====>fill to IQC\n", + rtl_read_dword(rtlpriv, 0xc10))); + } + } + break; + case RF90_PATH_B: + { + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + if (rx_x >> 1 ==0x112 || rx_y >> 1 == 0x3ee){ + rtl_set_bbreg(hw, 0xe10, 0x000003ff, 0x100); + rtl_set_bbreg(hw, 0xe10, 0x03ff0000, 0); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX_X = %x;;RX_Y = %x ====>fill to IQC\n", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff)); + } + else{ + rtl_set_bbreg(hw, 0xe10, 0x000003ff, rx_x >> 1); + rtl_set_bbreg(hw, 0xe10, 0x03ff0000, rx_y >> 1); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX_X = %x;;RX_Y = %x====>fill to IQC\n ", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("0xe10 = %x====>fill to IQC\n", + rtl_read_dword(rtlpriv, 0xe10))); + } + } + break; + default: + break; + }; +} + +void _rtl8812ae_iqk_tx_fill_iqc( + struct ieee80211_hw *hw, + enum radio_path path, + u32 tx_x, + u32 tx_y + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (path) { + case RF90_PATH_A: + { + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /*[31] = 1 --> Page C1*/ + rtl_write_dword(rtlpriv, 0xc90, 0x00000080); + rtl_write_dword(rtlpriv, 0xcc4, 0x20040000); + rtl_write_dword(rtlpriv, 0xcc8, 0x20000000); + rtl_set_bbreg(hw, 0xccc, 0x000007ff, tx_y); + rtl_set_bbreg(hw, 0xcd4, 0x000007ff, tx_x); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX_X = %x;;TX_Y = %x =====> fill to IQC\n", + tx_x & 0x000007ff, tx_y & 0x000007ff)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("0xcd4 = %x;;0xccc = %x ====>fill to IQC\n", + rtl_get_bbreg(hw, 0xcd4, 0x000007ff), + rtl_get_bbreg(hw, 0xccc, 0x000007ff))); + } + break; + case RF90_PATH_B: + { + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /*[31] = 1 --> Page C1*/ + rtl_write_dword(rtlpriv, 0xe90, 0x00000080); + rtl_write_dword(rtlpriv, 0xec4, 0x20040000); + rtl_write_dword(rtlpriv, 0xec8, 0x20000000); + rtl_set_bbreg(hw, 0xecc, 0x000007ff, tx_y); + rtl_set_bbreg(hw, 0xed4, 0x000007ff, tx_x); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX_X = %x;;TX_Y = %x =====> fill to IQC\n", + tx_x&0x000007ff, tx_y&0x000007ff)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("0xed4 = %x;;0xecc = %x ====>fill to IQC\n", + rtl_get_bbreg(hw, 0xed4, 0x000007ff), + rtl_get_bbreg(hw, 0xecc, 0x000007ff))); + } + break; + default: + break; + }; +} + +void _rtl8812ae_iqk_backup_macbb( + struct ieee80211_hw *hw, + u32 *macbb_backup, + u32 *backup_macbb_reg, + u32 mac_bb_num + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*save MACBB default value*/ + for (i = 0; i < mac_bb_num; i++) { + macbb_backup[i] =rtl_read_dword(rtlpriv,backup_macbb_reg[i]); + } + + RT_TRACE(COMP_IQK, DBG_LOUD, ("BackupMacBB Success!!!!\n")); +} + +void _rtl8812ae_iqk_backup_afe( + struct ieee80211_hw *hw, + u32 *afe_backup, + u32 *backup_afe_REG, + u32 afe_num + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*Save AFE Parameters */ + for (i = 0; i < afe_num; i++){ + afe_backup[i] = rtl_read_dword(rtlpriv, backup_afe_REG[i]); + } + RT_TRACE(COMP_IQK, DBG_LOUD, ("BackupAFE Success!!!!\n")); +} + +void _rtl8812ae_iqk_backup_rf( + struct ieee80211_hw *hw, + u32 *rfa_backup, + u32 *rfb_backup, + u32 *backup_rf_reg, + u32 rf_num + ) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*Save RF Parameters*/ + for (i = 0; i < rf_num; i++){ + rfa_backup[i] = rtl_get_rfreg(hw, RF90_PATH_A, backup_rf_reg[i], BMASKDWORD); + rfb_backup[i] = rtl_get_rfreg(hw, RF90_PATH_B, backup_rf_reg[i], BMASKDWORD); + } + RT_TRACE(COMP_IQK, DBG_LOUD, ("BackupRF Success!!!!\n")); +} + +void _rtl8812ae_iqk_configure_mac( + struct ieee80211_hw *hw + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + /* ========MAC register setting========*/ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + rtl_write_byte(rtlpriv, 0x522, 0x3f); + rtl_set_bbreg(hw, 0x550, BIT(11) | BIT(3), 0x0); + rtl_write_byte(rtlpriv, 0x808, 0x00); /*RX ante off*/ + rtl_set_bbreg(hw, 0x838, 0xf, 0xc); /*CCA off*/ +} + +#define cal_num 10 + +void _rtl8812ae_iqk_tx( + struct ieee80211_hw *hw, + u8 chnl_idx + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 delay_count; + u8 cal0_retry, cal1_retry; + u8 tx0_average = 0, tx1_average = 0, rx0_average = 0, rx1_average = 0; + int tx0_x = 0, tx0_y = 0, rx0_x = 0, rx0_y = 0; + int tx_x0[cal_num], tx_y0[cal_num], rx_x0[cal_num], rx_y0[cal_num]; + int tx1_x = 0, tx1_y = 0, rx1_x = 0, rx1_y = 0; + int tx_x1[cal_num], tx_y1[cal_num], rx_x1[cal_num], rx_y1[cal_num]; + bool tx0iqkok= false, rx0iqkok = false, tx0_fail = true, rx0_fail; + bool iqk0_ready = false, tx0_finish = false, rx0_finish = false; + bool tx1iqkok = false, rx1iqkok = false, tx1_fail = true, rx1_fail; + bool iqk1_ready = false, tx1_finish = false, rx1_finish = false, vdf_enable = false; + int i, tx_dt[3] = {0}, rx_dt[3] = {0}, ii, dx = 0, dy = 0; + + RT_TRACE(COMP_IQK, DBG_LOUD, + ("BandWidth = %d.\n", + rtlphy->current_chan_bw)); + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80){ + vdf_enable = true; + } + vdf_enable = false; + + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*========Path-A AFE all on========*/ + /*Port 0 DAC/ADC on*/ + rtl_write_dword(rtlpriv, 0xc60, 0x77777777); + rtl_write_dword(rtlpriv, 0xc64, 0x77777777); + + /* Port 1 DAC/ADC off*/ + rtl_write_dword(rtlpriv, 0xe60, 0x77777777); + rtl_write_dword(rtlpriv, 0xe64, 0x77777777); + + rtl_write_dword(rtlpriv, 0xc68, 0x19791979); + rtl_write_dword(rtlpriv, 0xe68, 0x19791979); + rtl_set_bbreg(hw,0xc00, 0xf, 0x4);/*hardware 3-wire off*/ + rtl_set_bbreg(hw,0xe00, 0xf, 0x4);/*hardware 3-wire off*/ + + /*DAC/ADC sampling rate (160 MHz)*/ + rtl_set_bbreg(hw, 0xc5c, BIT(26) | BIT(25) | BIT(24), 0x7); + rtl_set_bbreg(hw, 0xe5c, BIT(26) | BIT(25) | BIT(24), 0x7); + rtl_set_bbreg(hw, 0x8c4, BIT(30), 0x1); + + /*====== Path A TX IQK RF Setting ======*/ + rtl_set_bbreg(hw,0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + rtl_set_rfreg(hw,RF90_PATH_A, 0xef, BRFREGOFFSETMASK, 0x80002); + rtl_set_rfreg(hw,RF90_PATH_A, 0x30, BRFREGOFFSETMASK, 0x20000); + rtl_set_rfreg(hw,RF90_PATH_A, 0x31, BRFREGOFFSETMASK, 0x3fffd); + rtl_set_rfreg(hw,RF90_PATH_A, 0x32, BRFREGOFFSETMASK, 0xfe83f); + rtl_set_rfreg(hw,RF90_PATH_A, 0x65, BRFREGOFFSETMASK, 0x931d5); + rtl_set_rfreg(hw,RF90_PATH_A, 0x8f, BRFREGOFFSETMASK, 0x8a001); + /*====== Path A TX IQK RF Setting ======*/ + rtl_set_rfreg(hw,RF90_PATH_B, 0xef, BRFREGOFFSETMASK, 0x80002); + rtl_set_rfreg(hw,RF90_PATH_B, 0x30, BRFREGOFFSETMASK, 0x20000); + rtl_set_rfreg(hw,RF90_PATH_B, 0x31, BRFREGOFFSETMASK, 0x3fffd); + rtl_set_rfreg(hw,RF90_PATH_B, 0x32, BRFREGOFFSETMASK, 0xfe83f); + rtl_set_rfreg(hw,RF90_PATH_B, 0x65, BRFREGOFFSETMASK, 0x931d5); + rtl_set_rfreg(hw,RF90_PATH_B, 0x8f, BRFREGOFFSETMASK, 0x8a001); + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0xb00, 0x03000100); + rtl_set_bbreg(hw, 0xc94, BIT(0), 0x1); + rtl_set_bbreg(hw, 0xe94, BIT(0), 0x1); + rtl_write_dword(rtlpriv, 0x978, 0x29002000);/* TX (X,Y)*/ + rtl_write_dword(rtlpriv, 0x97c, 0xa9002000);/* RX (X,Y)*/ + rtl_write_dword(rtlpriv, 0x984, 0x00462910);/*[0]:AGC_en, [15]:idac_K_Mask*/ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1*/ + + /*ExternalPA_5G == 0*/ + rtl_write_dword(rtlpriv, 0xc88, 0x821403f1); + rtl_write_dword(rtlpriv, 0xe88, 0x821403f1); + + if (rtlhal->current_bandtype){ + rtl_write_dword(rtlpriv, 0xc8c, 0x68163e96); + rtl_write_dword(rtlpriv, 0xe8c, 0x68163e96); + } + else{ + rtl_write_dword(rtlpriv, 0xc8c, 0x28163e96); + rtl_write_dword(rtlpriv, 0xe8c, 0x28163e96); + } + + if (vdf_enable){} + else{ + rtl_write_dword(rtlpriv, 0xc80, 0x18008c10);/*TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16*/ + rtl_write_dword(rtlpriv, 0xc84, 0x38008c10);/*RX_Tone_idx[9:0], RxK_Mask[29]*/ + rtl_write_dword(rtlpriv, 0xce8, 0x00000000); + rtl_write_dword(rtlpriv, 0xe80, 0x18008c10);/*TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16*/ + rtl_write_dword(rtlpriv, 0xe84, 0x38008c10);/*RX_Tone_idx[9:0], RxK_Mask[29]*/ + rtl_write_dword(rtlpriv, 0xee8, 0x00000000); + + cal0_retry = 0; + cal1_retry = 0; + while(1){ + /*one shot*/ + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module*/ + rtl_write_dword(rtlpriv, 0xeb8, 0x00100000);/* cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module*/ + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); /*Delay 25ms*/ + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + rtl_write_dword(rtlpriv, 0xeb8, 0x00000000); + delay_count = 0; + while (1){ + if (!tx0_finish) + iqk0_ready = (bool) rtl_get_bbreg(hw, 0xd00, BIT(10)); + if (!tx1_finish) + iqk1_ready = (bool) rtl_get_bbreg(hw, 0xd40, BIT(10)); + if ((iqk0_ready && iqk1_ready) || (delay_count>20)) + break; + else{ + mdelay(1); + delay_count++; + } + } + RT_TRACE(COMP_IQK, DBG_LOUD, ("TX delay_count = %d\n", delay_count)); + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + /* ============TXIQK Check==============*/ + tx0_fail = (bool) rtl_get_bbreg(hw, 0xd00, BIT(12)); + tx1_fail = (bool) rtl_get_bbreg(hw, 0xd40, BIT(12)); + if (!(tx0_fail || tx0_finish)){ + rtl_write_dword(rtlpriv, 0xcb8, 0x02000000); + tx_x0[tx0_average] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000) << 21; + rtl_write_dword(rtlpriv, 0xcb8, 0x04000000); + tx_y0[tx0_average] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000) << 21; + tx0iqkok = true; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX_X0[%d] = %x ;; TX_Y0[%d] = %x\n", + tx0_average, (tx_x0[tx0_average]) >> 21 & 0x000007ff, + tx0_average, (tx_y0[tx0_average]) >> 21 & 0x000007ff)); + + tx0_average++; + } + else{ + tx0iqkok = false; + cal0_retry++; + if (cal0_retry == 10) + break; + } + if (!(tx1_fail || tx1_finish)){ + rtl_write_dword(rtlpriv, 0xeb8, 0x02000000); + tx_x1[tx1_average] = rtl_get_bbreg(hw, 0xd40, 0x07ff0000) << 21; + rtl_write_dword(rtlpriv, 0xeb8, 0x04000000); + tx_y1[tx1_average] = rtl_get_bbreg(hw, 0xd40, 0x07ff0000) << 21; + tx1iqkok= true; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX_X1[%d] = %x ;; TX_Y1[%d] = %x\n", + tx1_average, (tx_x1[tx1_average]) >> 21 & 0x000007ff, + tx1_average, (tx_y1[tx1_average]) >> 21 & 0x000007ff)); + + tx1_average++; + } + else{ + tx1iqkok = false; + cal1_retry++; + if (cal1_retry == 10) + break; + } + } + else{ + tx0iqkok = false; + tx1iqkok = false; + cal0_retry++; + cal1_retry++; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("Delay 20ms TX IQK Not Ready!!!!!\n")); + if (cal0_retry == 10) + break; + } + if (tx0_average >= 2){ + for (i = 0; i < tx0_average; i++){ + for (ii = i+1; ii > 21) - (tx_x0[ii] >> 21); + if (dx < 4 && dx > -4){ + dy = (tx_y0[i]>>21) - (tx_y0[ii]>>21); + if (dy < 4 && dy > -4){ + tx0_x = ((tx_x0[i] >> 21) + (tx_x0[ii] >> 21)) / 2; + tx0_y = ((tx_y0[i] >> 21) + (tx_y0[ii] >> 21)) / 2; + tx_x0[0] = tx_x0[i]; + tx_y0[1] = tx_y0[ii]; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX0_X = %x;;TX0_Y = %x\n", + tx0_x & 0x000007ff, tx0_y & 0x000007ff)); + if ((rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) + && vdf_enable) { + tx_dt[0] = (tx_dt[i] + tx_dt[ii]) / 2; + } + tx0_finish = true; + } + } + } + } + } + if (tx1_average >= 2){ + for (i = 0; i < tx1_average; i++){ + for (ii = i+1; ii < tx1_average; ii++){ + dx = (tx_x1[i] >> 21) - (tx_x1[ii] >> 21); + if (dx < 4 && dx > -4){ + dy = (tx_y1[i] >> 21) - (tx_y1[ii] >> 21); + if (dy < 4 && dy > -4){ + tx1_x = ((tx_x1[i] >> 21) + (tx_x1[ii] >> 21)) / 2; + tx1_y = ((tx_y1[i] >> 21) + (tx_y1[ii] >> 21)) / 2; + tx_x1[0] = tx_x1[i]; + tx_y1[1] = tx_y1[ii]; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX1_X = %x;;TX1_Y = %x\n", + tx1_x & 0x000007ff, tx1_y & 0x000007ff)); + if ((rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) + && vdf_enable) { + tx_dt[0] = (tx_dt[i] + tx_dt[ii]) / 2; + } + tx1_finish = true; + } + } + } + } + } + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX0_Average = %d, TX1_Average = %d\n", + tx0_average, tx1_average)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TX0_finish = %d, TX1_finish = %d\n", + tx0_finish, tx1_finish)); + if (tx0_finish && tx1_finish) + break; + if ((cal0_retry + tx0_average) >= 10 + || (cal1_retry + tx1_average) >= 10 ) + break; + } + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TXA_cal_retry = %d\n", cal0_retry)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("TXB_cal_retry = %d\n", cal1_retry)); + + } + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C*/ + rtl_set_rfreg(hw, RF90_PATH_A, 0x58, 0x7fe00, + rtl_get_rfreg(hw, RF90_PATH_A, 0x8, 0xffc00)); /*Load LOK*/ + rtl_set_rfreg(hw, RF90_PATH_B, 0x58, 0x7fe00, + rtl_get_rfreg(hw, RF90_PATH_B, 0x8, 0xffc00)); /* Load LOK*/ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /*[31] = 1 --> Page C1*/ + + + if (vdf_enable) {} + else{ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + if (tx0_finish) { + /*====== Path A RX IQK RF Setting======*/ + rtl_set_rfreg(hw, RF90_PATH_A, 0xef, BRFREGOFFSETMASK, 0x80000); + rtl_set_rfreg(hw, RF90_PATH_A, 0x18, 0x00c00, 0x3); /* BW 20M*/ + rtl_set_rfreg(hw, RF90_PATH_A, 0x30, BRFREGOFFSETMASK, 0x30000); + rtl_set_rfreg(hw, RF90_PATH_A, 0x31, BRFREGOFFSETMASK, 0x3f7ff); + rtl_set_rfreg(hw, RF90_PATH_A, 0x32, BRFREGOFFSETMASK, 0xfe7bf); + rtl_set_rfreg(hw, RF90_PATH_A, 0x8f, BRFREGOFFSETMASK, 0x88001); + rtl_set_rfreg(hw, RF90_PATH_A, 0x65, BRFREGOFFSETMASK, 0x931d6); + rtl_set_rfreg(hw, RF90_PATH_A, 0xef, BRFREGOFFSETMASK, 0x00000); + } + if (tx1_finish){ + /*====== Path B RX IQK RF Setting======*/ + rtl_set_rfreg(hw, RF90_PATH_B, 0xef, BRFREGOFFSETMASK, 0x80000); + rtl_set_rfreg(hw, RF90_PATH_B, 0x30, BRFREGOFFSETMASK, 0x30000); + rtl_set_rfreg(hw, RF90_PATH_B, 0x31, BRFREGOFFSETMASK, 0x3f7ff); + rtl_set_rfreg(hw, RF90_PATH_B, 0x32, BRFREGOFFSETMASK, 0xfe7bf); + rtl_set_rfreg(hw, RF90_PATH_B, 0x8f, BRFREGOFFSETMASK, 0x88001); + rtl_set_rfreg(hw, RF90_PATH_B, 0x65, BRFREGOFFSETMASK, 0x931d1); + rtl_set_rfreg(hw, RF90_PATH_B, 0xef, BRFREGOFFSETMASK, 0x00000); + } + rtl_set_bbreg(hw, 0x978, BIT(31), 0x1); + rtl_set_bbreg(hw, 0x97c, BIT(31), 0x0); + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0x984, 0x0046a890); + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /*[31] = 1 --> Page C1*/ + if (tx0_finish) { + rtl_write_dword(rtlpriv, 0xc80, 0x38008c10);/*TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16*/ + rtl_write_dword(rtlpriv, 0xc84, 0x18008c10);/*RX_Tone_idx[9:0], RxK_Mask[29]*/ + rtl_write_dword(rtlpriv, 0xc88, 0x02140119); + rtl_write_dword(rtlpriv, 0xc8c, 0x28160cc0); + } + if (tx1_finish){ + rtl_write_dword(rtlpriv, 0xe80, 0x38008c10);/*TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16*/ + rtl_write_dword(rtlpriv, 0xe84, 0x18008c10);/*RX_Tone_idx[9:0], RxK_Mask[29]*/ + rtl_write_dword(rtlpriv, 0xe88, 0x02140119); + rtl_write_dword(rtlpriv, 0xe8c, 0x28160ca0); + } + cal0_retry = 0; + cal1_retry = 0; + while(1){ + /* one shot*/ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + if (tx0_finish){ + rtl_set_bbreg(hw, 0x978, 0x03FF8000, (tx_x0[rx0_average % 2]) >> 21 & 0x000007ff); + rtl_set_bbreg(hw, 0x978, 0x000007FF, (tx_y0[rx0_average % 2]) >> 21 & 0x000007ff); + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1*/ + rtl_write_dword(rtlpriv, 0xcb8, 0x00300000);/*cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module*/ + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000); + mdelay(5); /*Delay 10ms*/ + } + if (tx1_finish){ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + rtl_set_bbreg(hw, 0x978, 0x03FF8000, (tx_x1[rx1_average % 2]) >> 21 & 0x000007ff); + rtl_set_bbreg(hw, 0x978, 0x000007FF, (tx_y1[rx1_average % 2]) >> 21 & 0x000007ff); + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /*[31] = 1 --> Page C1*/ + rtl_write_dword(rtlpriv, 0xeb8, 0x00300000);/*cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module*/ + rtl_write_dword(rtlpriv, 0xeb8, 0x00100000);/* cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module*/ + } + mdelay(10); /*Delay 10ms*/ + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + rtl_write_dword(rtlpriv, 0xeb8, 0x00000000); + delay_count = 0; + while (1){ + if (!rx0_finish && tx0_finish) + iqk0_ready = (bool) rtl_get_bbreg(hw, 0xd00, BIT(10)); + if (!rx1_finish && tx1_finish) + iqk1_ready = (bool) rtl_get_bbreg(hw, 0xd40, BIT(10)); + if ((iqk0_ready && iqk1_ready)||(delay_count>20)) + break; + else{ + mdelay(1); + delay_count++; + } + } + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX delay_count = %d\n", delay_count)); + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + // ============RXIQK Check============== + rx0_fail = (bool) rtl_get_bbreg(hw, 0xd00, BIT(11)); + rx1_fail = (bool) rtl_get_bbreg(hw, 0xd40, BIT(11)); + if (!(rx0_fail || rx0_finish) && tx0_finish){ + rtl_write_dword(rtlpriv, 0xcb8, 0x06000000); + rx_x0[rx0_average] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000) << 21; + rtl_write_dword(rtlpriv, 0xcb8, 0x08000000); + rx_y0[rx0_average] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000) << 21; + rx0iqkok= true; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX_X0[%d] = %x ;; RX_Y0[%d] = %x\n", + rx0_average, (rx_x0[rx0_average]) >> 21 & 0x000007ff, + rx0_average, (rx_y0[rx0_average]) >> 21 & 0x000007ff)); + + rx0_average++; + } + else{ + RT_TRACE(COMP_IQK, DBG_LOUD, + ("1. RXA_cal_retry = %d\n", cal0_retry)); + rx0iqkok = false; + cal0_retry++; + if (cal0_retry == 10) + break; + } + if (!(rx1_fail || rx1_finish) && tx1_finish){ + rtl_write_dword(rtlpriv, 0xeb8, 0x06000000); + rx_x1[rx1_average] = rtl_get_bbreg(hw, 0xd40, 0x07ff0000) << 21; + rtl_write_dword(rtlpriv, 0xeb8, 0x08000000); + rx_y1[rx1_average] = rtl_get_bbreg(hw, 0xd40, 0x07ff0000) << 21; + rx1iqkok = true; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX_X1[%d] = %x ;; RX_Y1[%d] = %x\n", + rx1_average, (rx_x1[rx1_average]) >> 21 & 0x000007ff, + rx1_average, (rx_y1[rx1_average]) >> 21 & 0x000007ff)); + + rx1_average++; + } + else{ + rx1iqkok= false; + cal1_retry++; + if (cal1_retry == 10) + break; + } + + } + else{ + RT_TRACE(COMP_IQK, DBG_LOUD, + ("2. RXA_cal_retry = %d\n", cal0_retry)); + rx0iqkok = false; + rx1iqkok = false; + cal0_retry++; + cal1_retry++; + RT_TRACE(COMP_IQK, DBG_LOUD, + ("Delay 20ms RX IQK Not Ready!!!!!\n")); + if (cal0_retry == 10) + break; + } + RT_TRACE(COMP_IQK, DBG_LOUD, + ("3. RXA_cal_retry = %d\n", cal0_retry)); + if (rx0_average >= 2){ + for (i = 0; i < rx0_average; i++){ + for (ii = i+1; ii < rx0_average; ii++){ + dx = (rx_x0[i] >> 21) - (rx_x0[ii] >> 21); + if (dx < 4 && dx > -4){ + dy = (rx_y0[i] >> 21) - (rx_y0[ii] >> 21); + if (dy < 4 && dy > -4){ + rx0_x = ((rx_x0[i]>>21) + (rx_x0[ii] >> 21)) / 2; + rx0_y = ((rx_y0[i]>>21) + (rx_y0[ii] >> 21)) / 2; + if ((rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) + && vdf_enable) { + rx_dt[0] = (rx_dt[i] + rx_dt[ii]) / 2; + } + rx0_finish = true; + break; + } + } + } + } + } + if (rx1_average >= 2){ + for (i = 0; i < rx1_average; i++){ + for (ii = i+1; ii < rx1_average; ii++){ + dx = (rx_x1[i] >> 21) - (rx_x1[ii] >> 21); + if (dx < 4 && dx > -4){ + dy = (rx_y1[i] >> 21) - (rx_y1[ii] >> 21); + if (dy < 4 && dy > -4){ + rx1_x = ((rx_x1[i] >> 21) + (rx_x1[ii] >> 21)) / 2; + rx1_y = ((rx_y1[i] >> 21) + (rx_y1[ii] >> 21)) / 2; + if ((rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) + && vdf_enable) { + rx_dt[0] = (rx_dt[i] + rx_dt[ii]) / 2; + } + rx1_finish = true; + break; + } + } + } + } + } + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX0_Average = %d, RX1_Average = %d\n", + rx0_average, rx1_average)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RX0_finish = %d, RX1_finish = %d\n", + rx0_finish, rx1_finish)); + if ((rx0_finish|| !tx0_finish) && (rx1_finish || !tx1_finish) ) + break; + if ((cal0_retry + rx0_average) >= 10 + || (cal1_retry + rx1_average) >= 10 + || rx0_average == 3 + || rx1_average == 3) + break; + } + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RXA_cal_retry = %d\n", cal0_retry)); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RXB_cal_retry = %d\n", cal1_retry)); + } + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C*/ + switch (rtlphy->current_chan_bw) + { + case HT_CHANNEL_WIDTH_20_40: + { + rtl_set_rfreg(hw, RF90_PATH_A, 0x18, 0x00c00, 0x1); + } + break; + case HT_CHANNEL_WIDTH_80: + { + rtl_set_rfreg(hw, RF90_PATH_A, 0x18, 0x00c00, 0x0); + } + break; + default: + break; + + } + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 0 --> Page C*/ + /*FillIQK Result*/ + RT_TRACE(COMP_IQK, DBG_LOUD, + ("========Path_A =======\n")); + + if (tx0_finish){ + _rtl8812ae_iqk_tx_fill_iqc(hw, RF90_PATH_A, tx0_x, tx0_y); + } + else{ + _rtl8812ae_iqk_tx_fill_iqc(hw, RF90_PATH_A, 0x200, 0x0); + } + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80 + || vdf_enable){ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /*[31] = 0 --> Page C*/ + rtl_set_bbreg(hw, 0xce8, 0x3fff0000, tx_dt[0] & 0x00003fff); + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + } + + if (rx0_finish == 1){ + _rtl8812ae_iqk_rx_fill_iqc(hw, RF90_PATH_A, rx0_x, rx0_y); + } + else{ + _rtl8812ae_iqk_rx_fill_iqc(hw, RF90_PATH_A, 0x200, 0x0); + } + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80 + || vdf_enable){ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /*[31] = 0 --> Page C*/ + rtl_set_bbreg(hw, 0xce8, 0x00003fff, rx_dt[0] & 0x00003fff); + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C*/ + } + + RT_TRACE(COMP_IQK, DBG_LOUD, + ("========Path_B =======\n")); + + if (tx1_finish){ + _rtl8812ae_iqk_tx_fill_iqc(hw, RF90_PATH_B, tx1_x, tx1_y); + } + else{ + _rtl8812ae_iqk_tx_fill_iqc(hw, RF90_PATH_B, 0x200, 0x0); + } + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80 + || vdf_enable){ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 0 --> Page C*/ + rtl_set_bbreg(hw, 0xee8, 0x3fff0000, tx_dt[0] & 0x00003fff); + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C*/ + } + + if (rx1_finish == 1){ + _rtl8812ae_iqk_rx_fill_iqc(hw, RF90_PATH_B, rx1_x, rx1_y); + } + else{ + _rtl8812ae_iqk_rx_fill_iqc(hw, RF90_PATH_B, 0x200, 0x0); + } + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80 + || vdf_enable){ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 0 --> Page C*/ + rtl_set_bbreg(hw, 0xee8, 0x00003fff, rx_dt[0] & 0x00003fff); + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C*/ + } +} + +void _rtl8812ae_iqk_restore_rf( + struct ieee80211_hw *hw, + enum radio_path path, + u32 *backup_rf_reg, + u32 *rf_backup, + u32 rf_reg_num + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + for (i = 0; i < rf_reg_num; i++) + rtl_set_rfreg(hw, path, backup_rf_reg[i], BRFREGOFFSETMASK, rf_backup[i]); + + rtl_set_rfreg(hw, path, 0xef, BRFREGOFFSETMASK, 0x0); + + switch(path){ + case RF90_PATH_A: + { + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RestoreRF Path A Success!!!!\n")); + } + break; + case RF90_PATH_B: + { + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RestoreRF Path B Success!!!!\n")); + } + break; + default: + break; + } +} + +void _rtl8812ae_iqk_restore_afe( + struct ieee80211_hw *hw, + u32 *afe_backup, + u32 *backup_afe_reg, + u32 afe_num + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*Reload AFE Parameters */ + for (i = 0; i < afe_num; i++){ + rtl_write_dword(rtlpriv, backup_afe_reg[i], afe_backup[i]); + } + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1*/ + rtl_write_dword(rtlpriv, 0xc80, 0x0); + rtl_write_dword(rtlpriv, 0xc84, 0x0); + rtl_write_dword(rtlpriv, 0xc88, 0x0); + rtl_write_dword(rtlpriv, 0xc8c, 0x3c000000); + rtl_write_dword(rtlpriv, 0xc90, 0x00000080); + rtl_write_dword(rtlpriv, 0xc94, 0x00000000); + rtl_write_dword(rtlpriv, 0xcc4, 0x20040000); + rtl_write_dword(rtlpriv, 0xcc8, 0x20000000); + rtl_write_dword(rtlpriv, 0xcb8, 0x0); + rtl_write_dword(rtlpriv, 0xe80, 0x0); + rtl_write_dword(rtlpriv, 0xe84, 0x0); + rtl_write_dword(rtlpriv, 0xe88, 0x0); + rtl_write_dword(rtlpriv, 0xe8c, 0x3c000000); + rtl_write_dword(rtlpriv, 0xe90, 0x00000080); + rtl_write_dword(rtlpriv, 0xe94, 0x00000000); + rtl_write_dword(rtlpriv, 0xec4, 0x20040000); + rtl_write_dword(rtlpriv, 0xec8, 0x20000000); + rtl_write_dword(rtlpriv, 0xeb8, 0x0); + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RestoreAFE Success!!!!\n")); +} + +void _rtl8812ae_iqk_restore_macbb( + struct ieee80211_hw *hw, + u32 *macbb_backup, + u32 *backup_macbb_reg, + u32 macbb_num + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C*/ + //Reload MacBB Parameters + for (i = 0; i < macbb_num; i++){ + rtl_write_dword(rtlpriv, backup_macbb_reg[i], macbb_backup[i]); + } + RT_TRACE(COMP_IQK, DBG_LOUD, + ("RestoreMacBB Success!!!!\n")); +} + +#define MACBB_REG_NUM 10 +#define AFE_REG_NUM 14 +#define RF_REG_NUM 3 + +static void _rtl8812ae_phy_iq_calibrate( + struct ieee80211_hw *hw, + u8 channel) +{ + u32 macbb_backup[MACBB_REG_NUM]; + u32 afe_backup[AFE_REG_NUM]; + u32 rfa_backup[RF_REG_NUM]; + u32 rfb_backup[RF_REG_NUM]; + u32 backup_macbb_reg[MACBB_REG_NUM] = {0xb00, 0x520, 0x550, + 0x808, 0x90c, 0xc00, 0xe00, + 0x8c4,0x838, 0x82c}; + u32 backup_afe_reg[AFE_REG_NUM] = {0xc5c, 0xc60, 0xc64, 0xc68, + 0xcb8, 0xcb0, 0xcb4,0xe5c, + 0xe60, 0xe64, 0xe68, 0xeb8, + 0xeb0, 0xeb4}; + u32 backup_rf_reg[RF_REG_NUM] = {0x65, 0x8f, 0x0}; + u8 chnl_idx = _rtl8812ae_get_right_chnl_place_for_iqk(channel); + + _rtl8812ae_iqk_backup_macbb(hw, macbb_backup, backup_macbb_reg, MACBB_REG_NUM); + _rtl8812ae_iqk_backup_afe(hw, afe_backup, backup_afe_reg, AFE_REG_NUM); + _rtl8812ae_iqk_backup_rf(hw, rfa_backup, rfb_backup, backup_rf_reg, RF_REG_NUM); + + _rtl8812ae_iqk_configure_mac(hw); + _rtl8812ae_iqk_tx(hw, chnl_idx); + _rtl8812ae_iqk_restore_rf(hw, RF90_PATH_A, backup_rf_reg, rfa_backup, RF_REG_NUM); + _rtl8812ae_iqk_restore_rf(hw, RF90_PATH_A, backup_rf_reg, rfb_backup, RF_REG_NUM); // PATH_A ? + + _rtl8812ae_iqk_restore_afe(hw, afe_backup, backup_afe_reg, AFE_REG_NUM); + _rtl8812ae_iqk_restore_macbb(hw, macbb_backup, backup_macbb_reg, MACBB_REG_NUM); +} + + +void _rtl8821ae_iqk_backup_macbb( + struct ieee80211_hw *hw, + u32 *macbb_backup, + u32 *backup_macbb_reg, + u32 mac_bb_num + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*save MACBB default value*/ + for (i = 0; i < mac_bb_num; i++) { + macbb_backup[i] =rtl_read_dword(rtlpriv,backup_macbb_reg[i]); + } + + RT_TRACE(COMP_IQK, DBG_LOUD, ("BackupMacBB Success!!!!\n")); +} + +void _rtl8821ae_iqk_backup_afe( + struct ieee80211_hw *hw, + u32 *afe_backup, + u32 *backup_afe_REG, + u32 afe_num + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*Save AFE Parameters */ + for (i = 0; i < afe_num; i++){ + afe_backup[i] = rtl_read_dword(rtlpriv, backup_afe_REG[i]); + } + RT_TRACE(COMP_IQK, DBG_LOUD, ("BackupAFE Success!!!!\n")); +} + +void _rtl8821ae_iqk_backup_rf( + struct ieee80211_hw *hw, + u32 *rfa_backup, + u32 *rfb_backup, + u32 *backup_rf_reg, + u32 rf_num + ) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*Save RF Parameters*/ + for (i = 0; i < rf_num; i++){ + rfa_backup[i] = rtl_get_rfreg(hw, RF90_PATH_A, backup_rf_reg[i], BMASKDWORD); + rfb_backup[i] = rtl_get_rfreg(hw, RF90_PATH_B, backup_rf_reg[i], BMASKDWORD); + } + RT_TRACE(COMP_IQK, DBG_LOUD, ("BackupRF Success!!!!\n")); +} + +void _rtl8821ae_iqk_configure_mac( + struct ieee80211_hw *hw + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + /* ========MAC register setting========*/ + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + rtl_write_byte(rtlpriv, 0x522, 0x3f); + rtl_set_bbreg(hw, 0x550, BIT(11) | BIT(3), 0x0); + rtl_write_byte(rtlpriv, 0x808, 0x00); /*RX ante off*/ + rtl_set_bbreg(hw, 0x838, 0xf, 0xc); /*CCA off*/ +} + + +void _rtl8821ae_iqk_tx_fill_iqc( + struct ieee80211_hw *hw, + enum radio_path path, + u32 tx_x, + u32 tx_y + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + switch (path) { + case RF90_PATH_A: + { + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + rtl_write_dword(rtlpriv, 0xc90, 0x00000080); + rtl_write_dword(rtlpriv, 0xcc4, 0x20040000); + rtl_write_dword(rtlpriv, 0xcc8, 0x20000000); + rtl_set_bbreg(hw, 0xccc, 0x000007ff, tx_y); + rtl_set_bbreg(hw, 0xcd4, 0x000007ff, tx_x); + RT_TRACE(COMP_IQK, DBG_LOUD, ("TX_X = %x;;TX_Y = %x =====> fill to IQC\n", tx_x, tx_y)); + RT_TRACE(COMP_IQK, DBG_LOUD, ("0xcd4 = %x;;0xccc = %x ====>fill to IQC\n", rtl_get_bbreg(hw, 0xcd4, 0x000007ff), rtl_get_bbreg(hw, 0xccc, 0x000007ff))); + } + break; + default: + break; + }; +} + + +void _rtl8821ae_iqk_rx_fill_iqc( + struct ieee80211_hw *hw, + enum radio_path path, + u32 rx_x, + u32 rx_y + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + switch (path) { + case RF90_PATH_A: + { + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + rtl_set_bbreg(hw, 0xc10, 0x000003ff, rx_x>>1); + rtl_set_bbreg(hw, 0xc10, 0x03ff0000, rx_y>>1); + RT_TRACE(COMP_IQK, DBG_LOUD, ("rx_x = %x;;rx_y = %x ====>fill to IQC\n", rx_x>>1, rx_y>>1)); + RT_TRACE(COMP_IQK, DBG_LOUD, ("0xc10 = %x ====>fill to IQC\n", rtl_read_dword(rtlpriv, 0xc10))); + } + break; + default: + break; + }; +} + + + +#define cal_num 10 + +void _rtl8821ae_iqk_tx( + struct ieee80211_hw *hw, + enum radio_path path + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u32 tx_fail, rx_fail, delay_count, iqk_ready, cal_retry, cal = 0, temp_reg65; + int tx_x = 0, tx_y = 0, rx_x = 0, rx_y = 0, tx_average = 0, rx_average = 0; + int tx_x0[cal_num], tx_y0[cal_num], tx_x0_rxk[cal_num], tx_y0_rxk[cal_num], rx_x0[cal_num], rx_y0[cal_num]; + bool tx0iqkok = false, rx0iqkok = false; + bool vdf_enable = false; + int i, k, vdf_y[3], vdf_x[3], tx_dt[3], rx_dt[3], ii, dx = 0, dy = 0, tx_finish = 0, rx_finish = 0; + + + RT_TRACE(COMP_IQK, DBG_LOUD, + ("BandWidth = %d.\n", + rtlphy->current_chan_bw)); + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80){ + vdf_enable = true; + } + + while (cal < cal_num) { + switch (path) { + case RF90_PATH_A: + { + temp_reg65 = rtl_get_rfreg(hw, path, 0x65, 0xffffffff); + //Path-A LOK + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/ + /*========Path-A AFE all on========*/ + /*Port 0 DAC/ADC on*/ + rtl_write_dword(rtlpriv, 0xc60, 0x77777777); + rtl_write_dword(rtlpriv, 0xc64, 0x77777777); + rtl_write_dword(rtlpriv, 0xc68, 0x19791979); + rtl_write_dword(rtlpriv, 0xc6c, 0x19791979); + rtl_write_dword(rtlpriv, 0xc70, 0x19791979); + rtl_write_dword(rtlpriv, 0xc74, 0x19791979); + rtl_write_dword(rtlpriv, 0xc78, 0x19791979); + rtl_write_dword(rtlpriv, 0xc7c, 0x19791979); + rtl_write_dword(rtlpriv, 0xc80, 0x19791979); + rtl_write_dword(rtlpriv, 0xc84, 0x19791979); + + rtl_set_bbreg(hw, 0xc00, 0xf, 0x4); /*hardware 3-wire off*/ + + // LOK Setting + //====== LOK ====== + /*DAC/ADC sampling rate (160 MHz)*/ + rtl_set_bbreg(hw, 0xc5c, BIT(26) | BIT(25) | BIT(24), 0x7); + + // 2. LoK RF Setting (at BW = 20M) + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80002); + rtl_set_rfreg(hw, path, 0x18, 0x00c00, 0x3); // BW 20M + rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x20000); + rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0003f); + rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xf3fc3); + rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d5); + rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001); + rtl_set_bbreg(hw, 0xcb8, 0xf, 0xd); + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0xb00, 0x03000100); + rtl_set_bbreg(hw, 0xc94, BIT(0), 0x1); + rtl_write_dword(rtlpriv, 0x978, 0x29002000);// TX (X,Y) + rtl_write_dword(rtlpriv, 0x97c, 0xa9002000);// RX (X,Y) + rtl_write_dword(rtlpriv, 0x984, 0x00462910);// [0]:AGC_en, [15]:idac_K_Mask + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + rtl_write_dword(rtlpriv, 0xc88, 0x821403f4); + + if (rtlhal->current_bandtype) + rtl_write_dword(rtlpriv, 0xc8c, 0x68163e96); + else + rtl_write_dword(rtlpriv, 0xc8c, 0x28163e96); + + rtl_write_dword(rtlpriv, 0xc80, 0x18008c10);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x38008c10);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);// cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); //Delay 10ms + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + rtl_set_rfreg(hw, path, 0x58, 0x7fe00, rtl_get_rfreg(hw, path, 0x8, 0xffc00)); // Load LOK + + switch (rtlphy->current_chan_bw) + { + case 1: + { + rtl_set_rfreg(hw, path, 0x18, 0x00c00, 0x1); + } + break; + case 2: + { + rtl_set_rfreg(hw, path, 0x18, 0x00c00, 0x0); + } + break; + default: + break; + + } + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + + // 3. TX RF Setting + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000); + rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x20000); + rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0003f); + rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xf3fc3); + rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d5); + rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001); + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000); + //ODM_SetBBReg(pDM_Odm, 0xcb8, 0xf, 0xd); + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0xb00, 0x03000100); + rtl_set_bbreg(hw, 0xc94, BIT(0), 0x1); + rtl_write_dword(rtlpriv, 0x978, 0x29002000);// TX (X,Y) + rtl_write_dword(rtlpriv, 0x97c, 0xa9002000);// RX (X,Y) + rtl_write_dword(rtlpriv, 0x984, 0x0046a910);// [0]:AGC_en, [15]:idac_K_Mask + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + rtl_write_dword(rtlpriv, 0xc88, 0x821403f1); + if (rtlhal->current_bandtype) + rtl_write_dword(rtlpriv, 0xc8c, 0x40163e96); + else + rtl_write_dword(rtlpriv, 0xc8c, 0x00163e96); + + if (vdf_enable == 1){ + RT_TRACE(COMP_IQK, DBG_LOUD, ("VDF_enable\n")); + for (k = 0;k <= 2; k++){ + switch (k){ + case 0: + { + rtl_write_dword(rtlpriv, 0xc80, 0x18008c38);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x38008c38);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_set_bbreg(hw, 0xce8, BIT(31), 0x0); + } + break; + case 1: + { + rtl_set_bbreg(hw, 0xc80, BIT(28), 0x0); + rtl_set_bbreg(hw, 0xc84, BIT(28), 0x0); + rtl_set_bbreg(hw, 0xce8, BIT(31), 0x0); + } + break; + case 2: + { + RT_TRACE(COMP_IQK, DBG_LOUD, ("vdf_y[1] = %x;;;vdf_y[0] = %x\n", vdf_y[1]>>21 & 0x00007ff, vdf_y[0]>>21 & 0x00007ff)); + RT_TRACE(COMP_IQK, DBG_LOUD, ("vdf_x[1] = %x;;;vdf_x[0] = %x\n", vdf_x[1]>>21 & 0x00007ff, vdf_x[0]>>21 & 0x00007ff)); + tx_dt[cal] = (vdf_y[1]>>20)-(vdf_y[0]>>20); + tx_dt[cal] = ((16*tx_dt[cal])*10000/15708); + tx_dt[cal] = (tx_dt[cal] >> 1 )+(tx_dt[cal] & BIT(0)); + rtl_write_dword(rtlpriv, 0xc80, 0x18008c20);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x38008c20);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_set_bbreg(hw, 0xce8, BIT(31), 0x1); + rtl_set_bbreg(hw, 0xce8, 0x3fff0000, tx_dt[cal] & 0x00003fff); + } + break; + default: + break; + } + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);// cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module + cal_retry = 0; + while(1){ + // one shot + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); //Delay 10ms + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + delay_count = 0; + while (1){ + iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10)); + if ((~iqk_ready) || (delay_count>20)){ + break; + } + else{ + mdelay(1); + delay_count++; + } + } + + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + // ============TXIQK Check============== + tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12)); + + if (~tx_fail){ + rtl_write_dword(rtlpriv, 0xcb8, 0x02000000); + vdf_x[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rtl_write_dword(rtlpriv, 0xcb8, 0x04000000); + vdf_y[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + tx0iqkok = true; + break; + } + else{ + rtl_set_bbreg(hw, 0xccc, 0x000007ff, 0x0); + rtl_set_bbreg(hw, 0xcd4, 0x000007ff, 0x200); + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10) { + break; + } + } + } + else{ + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10){ + break; + } + } + } + } + if (k == 3){ + tx_x0[cal] = vdf_x[k-1] ; + tx_y0[cal] = vdf_y[k-1]; + } + } + + else { + rtl_write_dword(rtlpriv, 0xc80, 0x18008c10);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x38008c10);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);// cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module + cal_retry = 0; + while(1){ + // one shot + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); //Delay 10ms + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + delay_count = 0; + while (1){ + iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10)); + if ((~iqk_ready) || (delay_count>20)) { + break; + } + else{ + mdelay(1); + delay_count++; + } + } + + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + // ============TXIQK Check============== + tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12)); + + if (~tx_fail){ + rtl_write_dword(rtlpriv, 0xcb8, 0x02000000); + tx_x0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rtl_write_dword(rtlpriv, 0xcb8, 0x04000000); + tx_y0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + tx0iqkok = true; + break; + } + else{ + rtl_set_bbreg(hw, 0xccc, 0x000007ff, 0x0); + rtl_set_bbreg(hw, 0xcd4, 0x000007ff, 0x200); + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10) { + break; + } + } + } + else{ + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + } + } + } + + + if (tx0iqkok == false) + break; // TXK fail, Don't do RXK + + if (vdf_enable == 1){ + rtl_set_bbreg(hw, 0xce8, BIT(31), 0x0); // TX VDF Disable + RT_TRACE(COMP_IQK, DBG_LOUD, ("RXVDF Start\n")); + for (k = 0;k <= 2; k++){ + //====== RX mode TXK (RXK Step 1) ====== + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + // 1. TX RF Setting + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000); + rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000); + rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x00029); + rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xd7ffb); + rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, temp_reg65); + rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001); + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000); + + rtl_set_bbreg(hw, 0xcb8, 0xf, 0xd); + rtl_write_dword(rtlpriv, 0x978, 0x29002000);// TX (X,Y) + rtl_write_dword(rtlpriv, 0x97c, 0xa9002000);// RX (X,Y) + rtl_write_dword(rtlpriv, 0x984, 0x0046a910);// [0]:AGC_en, [15]:idac_K_Mask + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0xb00, 0x03000100); + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + switch (k){ + case 0: + { + rtl_write_dword(rtlpriv, 0xc80, 0x18008c38);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x38008c38);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_set_bbreg(hw, 0xce8, BIT(30), 0x0); + } + break; + case 1: + { + rtl_write_dword(rtlpriv, 0xc80, 0x08008c38);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x28008c38);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_set_bbreg(hw, 0xce8, BIT(30), 0x0); + } + break; + case 2: + { + RT_TRACE(COMP_IQK, DBG_LOUD, ("VDF_Y[1] = %x;;;VDF_Y[0] = %x\n", vdf_y[1]>>21 & 0x00007ff, vdf_y[0]>>21 & 0x00007ff)); + RT_TRACE(COMP_IQK, DBG_LOUD, ("VDF_X[1] = %x;;;VDF_X[0] = %x\n", vdf_x[1]>>21 & 0x00007ff, vdf_x[0]>>21 & 0x00007ff)); + rx_dt[cal] = (vdf_y[1]>>20)-(vdf_y[0]>>20); + RT_TRACE(COMP_IQK, DBG_LOUD, ("Rx_dt = %d\n", rx_dt[cal])); + rx_dt[cal] = ((16*rx_dt[cal])*10000/13823); + rx_dt[cal] = (rx_dt[cal] >> 1 )+(rx_dt[cal] & BIT(0)); + rtl_write_dword(rtlpriv, 0xc80, 0x18008c20);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x38008c20);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_set_bbreg(hw, 0xce8, 0x00003fff, rx_dt[cal] & 0x00003fff); + } + break; + default: + break; + } + rtl_write_dword(rtlpriv, 0xc88, 0x821603e0); + rtl_write_dword(rtlpriv, 0xc8c, 0x68163e96); + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);// cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module + cal_retry = 0; + while(1){ + // one shot + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); //Delay 10ms + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + delay_count = 0; + while (1){ + iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10)); + if ((~iqk_ready)||(delay_count>20)){ + break; + } + else{ + mdelay(1); + delay_count++; + } + } + + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + // ============TXIQK Check============== + tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12)); + + if (~tx_fail){ + rtl_write_dword(rtlpriv, 0xcb8, 0x02000000); + tx_x0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rtl_write_dword(rtlpriv, 0xcb8, 0x04000000); + tx_y0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + tx0iqkok = true; + break; + } + else{ + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + } + } + else{ + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + } + } + + if (tx0iqkok == false){ //If RX mode TXK fail, then take TXK Result + tx_x0_rxk[cal] = tx_x0[cal]; + tx_y0_rxk[cal] = tx_y0[cal]; + tx0iqkok = true; + RT_TRACE(COMP_IQK, DBG_LOUD, ("RXK Step 1 fail\n")); + } + + + //====== RX IQK ====== + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + // 1. RX RF Setting + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000); + rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000); + rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0002f); + rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xfffbb); + rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x88001); + rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d8); + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000); + + rtl_set_bbreg(hw, 0x978, 0x03FF8000, (tx_x0_rxk[cal])>>21&0x000007ff); + rtl_set_bbreg(hw, 0x978, 0x000007FF, (tx_y0_rxk[cal])>>21&0x000007ff); + rtl_set_bbreg(hw, 0x978, BIT(31), 0x1); + rtl_set_bbreg(hw, 0x97c, BIT(31), 0x0); + rtl_set_bbreg(hw, 0xcb8, 0xF, 0xe); + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0x984, 0x0046a911); + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + rtl_set_bbreg(hw, 0xc80, BIT(29), 0x1); + rtl_set_bbreg(hw, 0xc84, BIT(29), 0x0); + rtl_write_dword(rtlpriv, 0xc88, 0x02140119); + + rtl_write_dword(rtlpriv, 0xc8c, 0x28160d00); /* pDM_Odm->SupportInterface == 1 */ + + if (k==2){ + rtl_set_bbreg(hw, 0xce8, BIT(30), 0x1); //RX VDF Enable + } + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);// cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module + + cal_retry = 0; + while(1){ + // one shot + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); //Delay 10ms + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + delay_count = 0; + while (1){ + iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10)); + if ((~iqk_ready)||(delay_count>20)){ + break; + } + else{ + mdelay(1); + delay_count++; + } + } + + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + // ============RXIQK Check============== + rx_fail = rtl_get_bbreg(hw, 0xd00, BIT(11)); + if (rx_fail == 0){ + rtl_write_dword(rtlpriv, 0xcb8, 0x06000000); + vdf_x[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rtl_write_dword(rtlpriv, 0xcb8, 0x08000000); + vdf_y[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rx0iqkok = true; + break; + } + else{ + rtl_set_bbreg(hw, 0xc10, 0x000003ff, 0x200>>1); + rtl_set_bbreg(hw, 0xc10, 0x03ff0000, 0x0>>1); + rx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + + } + } + else{ + rx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + } + } + + } + if (k == 3){ + rx_x0[cal] = vdf_x[k-1] ; + rx_y0[cal] = vdf_y[k-1]; + } + rtl_set_bbreg(hw, 0xce8, BIT(31), 0x1); // TX VDF Enable + } + + else{ + //====== RX mode TXK (RXK Step 1) ====== + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + // 1. TX RF Setting + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000); + rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000); + rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x00029); + rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xd7ffb); + rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, temp_reg65); + rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001); + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000); + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0xb00, 0x03000100); + rtl_write_dword(rtlpriv, 0x984, 0x0046a910);// [0]:AGC_en, [15]:idac_K_Mask + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + rtl_write_dword(rtlpriv, 0xc80, 0x18008c10);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x38008c10);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_write_dword(rtlpriv, 0xc88, 0x821603e0); + //ODM_Write4Byte(pDM_Odm, 0xc8c, 0x68163e96); + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);// cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module + cal_retry = 0; + while(1){ + // one shot + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); //Delay 10ms + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + delay_count = 0; + while (1){ + iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10)); + if ((~iqk_ready)||(delay_count>20)){ + break; + } + else{ + mdelay(1); + delay_count++; + } + } + + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + // ============TXIQK Check============== + tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12)); + + if (~tx_fail){ + rtl_write_dword(rtlpriv, 0xcb8, 0x02000000); + tx_x0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rtl_write_dword(rtlpriv, 0xcb8, 0x04000000); + tx_y0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + tx0iqkok = true; + break; + } + else{ + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + } + } + else{ + tx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + } + } + + + if (tx0iqkok == false){ //If RX mode TXK fail, then take TXK Result + tx_x0_rxk[cal] = tx_x0[cal]; + tx_y0_rxk[cal] = tx_y0[cal]; + tx0iqkok = true; + RT_TRACE(COMP_IQK, DBG_LOUD, ("1")); + } + + + //====== RX IQK ====== + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + // 1. RX RF Setting + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000); + rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000); + rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0002f); + rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xfffbb); + rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x88001); + rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d8); + rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000); + + rtl_set_bbreg(hw, 0x978, 0x03FF8000, (tx_x0_rxk[cal])>>21&0x000007ff); + rtl_set_bbreg(hw, 0x978, 0x000007FF, (tx_y0_rxk[cal])>>21&0x000007ff); + rtl_set_bbreg(hw, 0x978, BIT(31), 0x1); + rtl_set_bbreg(hw, 0x97c, BIT(31), 0x0); + //ODM_SetBBReg(pDM_Odm, 0xcb8, 0xF, 0xe); + rtl_write_dword(rtlpriv, 0x90c, 0x00008000); + rtl_write_dword(rtlpriv, 0x984, 0x0046a911); + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + rtl_write_dword(rtlpriv, 0xc80, 0x38008c10);// TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 + rtl_write_dword(rtlpriv, 0xc84, 0x18008c10);// RX_Tone_idx[9:0], RxK_Mask[29] + rtl_write_dword(rtlpriv, 0xc88, 0x02140119); + + rtl_write_dword(rtlpriv, 0xc8c, 0x28160d00); /*pDM_Odm->SupportInterface == 1*/ + + rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);// cb8[20] ±N SI/PI ¨Ï¥ÎÅv¤Áµ¹ iqk_dpk module + + cal_retry = 0; + while(1){ + // one shot + rtl_write_dword(rtlpriv, 0x980, 0xfa000000); + rtl_write_dword(rtlpriv, 0x980, 0xf8000000); + + mdelay(10); //Delay 10ms + rtl_write_dword(rtlpriv, 0xcb8, 0x00000000); + delay_count = 0; + while (1){ + iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10)); + if ((~iqk_ready)||(delay_count>20)){ + break; + } + else{ + mdelay(1); + delay_count++; + } + } + + if (delay_count < 20){ // If 20ms No Result, then cal_retry++ + // ============RXIQK Check============== + rx_fail = rtl_get_bbreg(hw, 0xd00, BIT(11)); + if (rx_fail == 0){ + /* + ODM_Write4Byte(pDM_Odm, 0xcb8, 0x05000000); + reg1 = ODM_GetBBReg(pDM_Odm, 0xd00, 0xffffffff); + ODM_Write4Byte(pDM_Odm, 0xcb8, 0x06000000); + reg2 = ODM_GetBBReg(pDM_Odm, 0xd00, 0x0000001f); + DbgPrint("reg1 = %d, reg2 = %d", reg1, reg2); + Image_Power = (reg2<<32)+reg1; + DbgPrint("Before PW = %d\n", Image_Power); + ODM_Write4Byte(pDM_Odm, 0xcb8, 0x07000000); + reg1 = ODM_GetBBReg(pDM_Odm, 0xd00, 0xffffffff); + ODM_Write4Byte(pDM_Odm, 0xcb8, 0x08000000); + reg2 = ODM_GetBBReg(pDM_Odm, 0xd00, 0x0000001f); + Image_Power = (reg2<<32)+reg1; + DbgPrint("After PW = %d\n", Image_Power); + */ + + rtl_write_dword(rtlpriv, 0xcb8, 0x06000000); + rx_x0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rtl_write_dword(rtlpriv, 0xcb8, 0x08000000); + rx_y0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21; + rx0iqkok = true; + break; + } + else{ + rtl_set_bbreg(hw, 0xc10, 0x000003ff, 0x200>>1); + rtl_set_bbreg(hw, 0xc10, 0x03ff0000, 0x0>>1); + rx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + + } + } + else{ + rx0iqkok = false; + cal_retry++; + if (cal_retry == 10) + break; + } + } + } + + if (tx0iqkok) + tx_average++; + if (rx0iqkok) + rx_average++; + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, temp_reg65); + } + break; + default: + break; + } + cal++; + } + + // FillIQK Result + switch (path){ + case RF90_PATH_A: + { + RT_TRACE(COMP_IQK, DBG_LOUD, ("========Path_A =======\n")); + if (tx_average == 0) + break; + + for (i = 0; i < tx_average; i++){ + RT_TRACE(COMP_IQK, DBG_LOUD, (" TX_X0_RXK[%d] = %x ;; TX_Y0_RXK[%d] = %x\n", i, (tx_x0_rxk[i])>>21&0x000007ff, i, (tx_y0_rxk[i])>>21&0x000007ff)); + RT_TRACE(COMP_IQK, DBG_LOUD, ("TX_X0[%d] = %x ;; TX_Y0[%d] = %x\n", i, (tx_x0[i])>>21&0x000007ff, i, (tx_y0[i])>>21&0x000007ff)); + } + for (i = 0; i < tx_average; i++){ + for (ii = i+1; ii >21) - (tx_x0[ii]>>21); + if (dx < 3 && dx > -3){ + dy = (tx_y0[i]>>21) - (tx_y0[ii]>>21); + if (dy < 3 && dy > -3){ + tx_x = ((tx_x0[i]>>21) + (tx_x0[ii]>>21))/2; + tx_y = ((tx_y0[i]>>21) + (tx_y0[ii]>>21))/2; + tx_finish = 1; + break; + } + } + } + if (tx_finish == 1) + break; + } + + if (tx_finish == 1){ + _rtl8821ae_iqk_tx_fill_iqc(hw, path, tx_x, tx_y); // ? + } + else{ + _rtl8821ae_iqk_tx_fill_iqc(hw, path, 0x200, 0x0); + } + + if (rx_average == 0) + break; + + for (i = 0; i < rx_average; i++){ + RT_TRACE(COMP_IQK, DBG_LOUD, ("RX_X0[%d] = %x ;; RX_Y0[%d] = %x\n", i, (rx_x0[i])>>21&0x000007ff, i, (rx_y0[i])>>21&0x000007ff)); + } + for (i = 0; i < rx_average; i++){ + for (ii = i+1; ii >21) - (rx_x0[ii]>>21); + if (dx < 4 && dx > -4){ + dy = (rx_y0[i]>>21) - (rx_y0[ii]>>21); + if (dy < 4 && dy > -4){ + rx_x = ((rx_x0[i]>>21) + (rx_x0[ii]>>21))/2; + rx_y = ((rx_y0[i]>>21) + (rx_y0[ii]>>21))/2; + rx_finish = 1; + break; + } + } + } + if (rx_finish == 1) + break; + } + + if (rx_finish == 1){ + _rtl8821ae_iqk_rx_fill_iqc(hw, path, rx_x, rx_y); + } + else{ + _rtl8821ae_iqk_rx_fill_iqc(hw, path, 0x200, 0x0); + } + } + break; + default: + break; + } +} + +void _rtl8821ae_iqk_restore_rf( + struct ieee80211_hw *hw, + enum radio_path path, + u32* backup_rf_reg, + u32* rf_backup, + u32 rf_reg_num + ) +{ + u32 i; + struct rtl_priv* rtlpriv = rtl_priv(hw); + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + for (i = 0; i < RF_REG_NUM; i++) + rtl_set_rfreg(hw, path, backup_rf_reg[i], RFREG_OFFSET_MASK, rf_backup[i]); + + switch(path){ + case RF90_PATH_A: + { + RT_TRACE(COMP_IQK, DBG_LOUD, ("RestoreRF Path A Success!!!!\n")); + } + break; + default: + break; + } +} + +void _rtl8821ae_iqk_restore_afe( + struct ieee80211_hw *hw, + u32* afe_backup, + u32* backup_afe_reg, + u32 afe_num + ) +{ + u32 i; + struct rtl_priv* rtlpriv = rtl_priv(hw); + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + //Reload AFE Parameters + for (i = 0; i < afe_num; i++){ + rtl_write_dword(rtlpriv, backup_afe_reg[i], afe_backup[i]); + } + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); // [31] = 1 --> Page C1 + rtl_write_dword(rtlpriv, 0xc80, 0x0); + rtl_write_dword(rtlpriv, 0xc84, 0x0); + rtl_write_dword(rtlpriv, 0xc88, 0x0); + rtl_write_dword(rtlpriv, 0xc8c, 0x3c000000); + rtl_write_dword(rtlpriv, 0xc90, 0x00000080); + rtl_write_dword(rtlpriv, 0xc94, 0x00000000); + rtl_write_dword(rtlpriv, 0xcc4, 0x20040000); + rtl_write_dword(rtlpriv, 0xcc8, 0x20000000); + rtl_write_dword(rtlpriv, 0xcb8, 0x0); + RT_TRACE(COMP_IQK, DBG_LOUD, ("RestoreAFE Success!!!!\n")); +} + +void _rtl8821ae_iqk_restore_macbb( + struct ieee80211_hw *hw, + u32* macbb_backup, + u32* backup_macbb_reg, + u32 macbb_num + ) +{ + u32 i; + struct rtl_priv* rtlpriv = rtl_priv(hw); + + rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); // [31] = 0 --> Page C + //Reload MacBB Parameters + for (i = 0; i < macbb_num; i++){ + rtl_write_dword(rtlpriv, backup_macbb_reg[i], macbb_backup[i]); + } + RT_TRACE(COMP_IQK, DBG_LOUD, ("RestoreMacBB Success!!!!\n")); +} + + +#undef MACBB_REG_NUM +#undef AFE_REG_NUM +#undef RF_REG_NUM + +#define MACBB_REG_NUM 11 +#define AFE_REG_NUM 12 +#define RF_REG_NUM 3 + +static void _rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw) +{ + u32 macbb_backup[MACBB_REG_NUM]; + u32 afe_backup[AFE_REG_NUM]; + u32 rfa_backup[RF_REG_NUM]; + u32 rfb_backup[RF_REG_NUM]; + u32 backup_macbb_reg[MACBB_REG_NUM] = {0xb00, 0x520, 0x550, 0x808, 0x90c, 0xc00, 0xc50, + 0xe00, 0xe50, 0x838, 0x82c}; + u32 backup_afe_reg[AFE_REG_NUM] = {0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, + 0xc78, 0xc7c, 0xc80, 0xc84, 0xcb8}; + u32 backup_rf_reg[RF_REG_NUM] = {0x65, 0x8f, 0x0}; + + _rtl8821ae_iqk_backup_macbb(hw, macbb_backup, backup_macbb_reg, MACBB_REG_NUM); + _rtl8821ae_iqk_backup_afe(hw, afe_backup, backup_afe_reg, AFE_REG_NUM); + _rtl8821ae_iqk_backup_rf(hw, rfa_backup, rfb_backup, backup_rf_reg, RF_REG_NUM); + + _rtl8821ae_iqk_configure_mac(hw); + _rtl8821ae_iqk_tx(hw, RF90_PATH_A); + _rtl8821ae_iqk_restore_rf(hw, RF90_PATH_A, backup_rf_reg, rfa_backup, RF_REG_NUM); + + _rtl8821ae_iqk_restore_afe(hw, afe_backup, backup_afe_reg, AFE_REG_NUM); + _rtl8821ae_iqk_restore_macbb(hw, macbb_backup, backup_macbb_reg, MACBB_REG_NUM); +} + +static void _rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) +{ + u8 tmpreg; + u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + tmpreg = rtl_read_byte(rtlpriv, 0xd03); + + if ((tmpreg & 0x70) != 0) + rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F); + else + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + + if ((tmpreg & 0x70) != 0) { + rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS); + + if (is2t) + rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00, + MASK12BITS); + + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, + (rf_a_mode & 0x8FFFF) | 0x10000); + + if (is2t) + rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, + (rf_b_mode & 0x8FFFF) | 0x10000); + } + lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS); + + rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdfbe0); + /* rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000); */ + rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, 0x8c0a); + + mdelay(100); + + rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdffe0); + + if ((tmpreg & 0x70) != 0) { + rtl_write_byte(rtlpriv, 0xd03, tmpreg); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode); + + if (is2t) + rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, rf_b_mode); + } else { + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + } +RT_TRACE(COMP_INIT,DBG_LOUD,("\n")); + +} + +static void _rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool main) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + //struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + //struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + RT_TRACE(COMP_INIT,DBG_LOUD,("\n")); + + if (main) + rtl_set_bbreg(hw, RA_RFE_PINMUX + 4, BIT(29) | BIT(28), 0x1); + else + rtl_set_bbreg(hw, RA_RFE_PINMUX + 4, BIT(29) | BIT(28), 0x2); +} + +#undef IQK_ADDA_REG_NUM +#undef IQK_DELAY_TIME + +void rtl8812ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (!rtlphy->b_iqk_in_progress) + { + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = true; + spin_unlock(&rtlpriv->locks.iqk_lock); + + _rtl8812ae_phy_iq_calibrate(hw, rtlphy->current_channel); + + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = false; + spin_unlock(&rtlpriv->locks.iqk_lock); + } +} + +void rtl8812ae_reset_iqk_result(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 i; + + RT_TRACE(COMP_IQK, DBG_LOUD, + ("rtl8812ae_dm_reset_iqk_result:: settings regs %d default regs %d\n", + (int)(sizeof(rtlphy->iqk_matrix_regsetting) / + sizeof(struct iqk_matrix_regs)), + IQK_MATRIX_SETTINGS_NUM)); + + for(i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) { + { + rtlphy->iqk_matrix_regsetting[i].value[0][0] = + rtlphy->iqk_matrix_regsetting[i].value[0][2] = + rtlphy->iqk_matrix_regsetting[i].value[0][4] = + rtlphy->iqk_matrix_regsetting[i].value[0][6] = 0x100; + + rtlphy->iqk_matrix_regsetting[i].value[0][1] = + rtlphy->iqk_matrix_regsetting[i].value[0][3] = + rtlphy->iqk_matrix_regsetting[i].value[0][5] = + rtlphy->iqk_matrix_regsetting[i].value[0][7] = 0x0; + + rtlphy->iqk_matrix_regsetting[i].b_iqk_done = false; + + } + } +} + +void rtl8812ae_do_iqk(struct ieee80211_hw *hw,u8 delta_thermal_index, + u8 thermal_value, u8 threshold) +{ + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + + rtl8812ae_reset_iqk_result(hw); + + rtldm->thermalvalue_iqk= thermal_value; + rtl8812ae_phy_iq_calibrate(hw, false); +} + +void rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (!rtlphy->b_iqk_in_progress) + { + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = true; + spin_unlock(&rtlpriv->locks.iqk_lock); + + _rtl8821ae_phy_iq_calibrate(hw); + + spin_lock(&rtlpriv->locks.iqk_lock); + rtlphy->b_iqk_in_progress = false; + spin_unlock(&rtlpriv->locks.iqk_lock); + } +} + +void rtl8821ae_reset_iqk_result(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 i; + + RT_TRACE(COMP_IQK, DBG_LOUD, + ("rtl8812ae_dm_reset_iqk_result:: settings regs %d default regs %d\n", + (int)(sizeof(rtlphy->iqk_matrix_regsetting) / + sizeof(struct iqk_matrix_regs)), + IQK_MATRIX_SETTINGS_NUM)); + + for(i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) { + { + rtlphy->iqk_matrix_regsetting[i].value[0][0] = + rtlphy->iqk_matrix_regsetting[i].value[0][2] = + rtlphy->iqk_matrix_regsetting[i].value[0][4] = + rtlphy->iqk_matrix_regsetting[i].value[0][6] = 0x100; + + rtlphy->iqk_matrix_regsetting[i].value[0][1] = + rtlphy->iqk_matrix_regsetting[i].value[0][3] = + rtlphy->iqk_matrix_regsetting[i].value[0][5] = + rtlphy->iqk_matrix_regsetting[i].value[0][7] = 0x0; + + rtlphy->iqk_matrix_regsetting[i].b_iqk_done = false; + + } + } +} + +void rtl8821ae_do_iqk(struct ieee80211_hw *hw,u8 delta_thermal_index, + u8 thermal_value, u8 threshold) +{ + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + + rtl8821ae_reset_iqk_result(hw); + + rtldm->thermalvalue_iqk= thermal_value; + rtl8821ae_phy_iq_calibrate(hw, false); +} + +void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 timeout = 2000, timecount = 0; + + + while (rtlpriv->mac80211.act_scanning && timecount < timeout) { + udelay(50); + timecount += 50; + } + + rtlphy->lck_inprogress = true; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("LCK:Start!!! currentband %x delay %d ms\n", + rtlhal->current_bandtype, timecount)); + + _rtl8821ae_phy_lc_calibrate(hw, false); + + rtlphy->lck_inprogress = false; +} + +void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (rtlphy->b_apk_done) + return; + + return; +} + +void rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain) +{ + _rtl8821ae_phy_set_rfpath_switch(hw, bmain); +} + +bool rtl8821ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool b_postprocessing = false; + + RT_TRACE(COMP_CMD, DBG_TRACE, + ("-->IO Cmd(%#x), set_io_inprogress(%d)\n", + iotype, rtlphy->set_io_inprogress)); + do { + switch (iotype) { + case IO_CMD_RESUME_DM_BY_SCAN: + RT_TRACE(COMP_CMD, DBG_TRACE, + ("[IO CMD] Resume DM after scan.\n")); + b_postprocessing = true; + break; + case IO_CMD_PAUSE_BAND0_DM_BY_SCAN: + case IO_CMD_PAUSE_BAND1_DM_BY_SCAN: + RT_TRACE(COMP_CMD, DBG_TRACE, + ("[IO CMD] Pause DM before scan.\n")); + b_postprocessing = true; + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + } while (false); + if (b_postprocessing && !rtlphy->set_io_inprogress) { + rtlphy->set_io_inprogress = true; + rtlphy->current_io_type = iotype; + } else { + return false; + } + rtl8821ae_phy_set_io(hw); + RT_TRACE(COMP_CMD, DBG_TRACE, ("IO Type(%#x)\n", iotype)); + return true; +} + +static void rtl8821ae_phy_set_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + RT_TRACE(COMP_CMD, DBG_TRACE, + ("--->Cmd(%#x), set_io_inprogress(%d)\n", + rtlphy->current_io_type, rtlphy->set_io_inprogress)); + switch (rtlphy->current_io_type) { + case IO_CMD_RESUME_DM_BY_SCAN: + if (rtlpriv->mac80211.opmode== NL80211_IFTYPE_ADHOC) + _rtl8821ae_resume_tx_beacon(hw); + rtl8821ae_dm_write_dig(hw, rtlphy->initgain_backup.xaagccore1); + rtl8821ae_dm_write_cck_cca_thres(hw, rtlphy->initgain_backup.cca); + break; + case IO_CMD_PAUSE_BAND0_DM_BY_SCAN: + if (rtlpriv->mac80211.opmode== NL80211_IFTYPE_ADHOC) + _rtl8821ae_stop_tx_beacon(hw); + rtlphy->initgain_backup.xaagccore1 = dm_digtable.cur_igvalue; + rtl8821ae_dm_write_dig(hw, 0x17); + rtlphy->initgain_backup.cca = dm_digtable.cur_cck_cca_thres; + rtl8821ae_dm_write_cck_cca_thres(hw, 0x40); + break; + case IO_CMD_PAUSE_BAND1_DM_BY_SCAN: + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + rtlphy->set_io_inprogress = false; + RT_TRACE(COMP_CMD, DBG_TRACE, + ("(%#x)\n", rtlphy->current_io_type)); +} + +static void rtl8821ae_phy_set_rf_on(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +} + +#if 0 +static void _rtl8821ae_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + /*rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + while (u4b_tmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + delay--; + } + if (delay == 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + RT_TRACE(COMP_POWER, DBG_TRACE, + ("Switch RF timeout !!!.\n")); + return; + }*/ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} +#endif + +static bool _rtl8821ae_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = true; + u8 i, queue_id; + struct rtl8192_tx_ring *ring = NULL; + + switch (rfpwr_state) { + case ERFON:{ + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + bool rtstatus = false; + u32 InitializeCount = 0; + do { + InitializeCount++; + RT_TRACE(COMP_RF, DBG_DMESG, + ("IPS Set eRf nic enable\n")); + rtstatus = rtl_ps_enable_nic(hw); + } while ((rtstatus != true) + && (InitializeCount < 10)); + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(COMP_RF, DBG_DMESG, + ("Set ERFON sleeped:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc-> + last_sleep_jiffies))); + ppsc->last_awake_jiffies = jiffies; + rtl8821ae_phy_set_rf_on(hw); + } + if (mac->link_state == MAC80211_LINKED) { + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_LINK); + } else { + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + } + break; + } + case ERFOFF:{ + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (skb_queue_len(&ring->queue) == 0) { + queue_id++; + continue; + } else { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("eRf Off/Sleep: %d times " + "TcbBusyQueue[%d] =%d before " + "doze!\n", (i + 1), queue_id, + skb_queue_len(&ring->queue))); + + udelay(10); + i++; + } + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("\n ERFSLEEP: %d times " + "TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue))); + break; + } + } + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(COMP_RF, DBG_DMESG, + ("IPS Set eRf nic disable\n")); + rtl_ps_disable_nic(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } else { + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + } else { + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_POWER_OFF); + } + } + break; + } + /*case ERFSLEEP:{ + if (ppsc->rfpwr_state == ERFOFF) + break; + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (skb_queue_len(&ring->queue) == 0) { + queue_id++; + continue; + } else { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("eRf Off/Sleep: %d times " + "TcbBusyQueue[%d] =%d before " + "doze!\n", (i + 1), queue_id, + skb_queue_len(&ring->queue))); + + udelay(10); + i++; + } + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(COMP_ERR, DBG_WARNING, + ("\n ERFSLEEP: %d times " + "TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue))); + break; + } + } + RT_TRACE(COMP_RF, DBG_DMESG, + ("Set ERFSLEEP awaked:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies))); + ppsc->last_sleep_jiffies = jiffies; + _rtl8821ae_phy_set_rf_sleep(hw); + break; + }*/ + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + bresult = false; + break; + } + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + return bresult; +} + +bool rtl8821ae_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + bool bresult = false; + + if (rfpwr_state == ppsc->rfpwr_state) + return bresult; + bresult = _rtl8821ae_phy_set_rf_power_state(hw, rfpwr_state); + return bresult; +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.c @@ -0,0 +1,519 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "hal_bt_coexist.h" +#include "../pci.h" +#include "dm.h" +#include "fw.h" +#include "phy.h" +#include "reg.h" +#include "hal_btc.h" + +static bool bt_operation_on = false; + +void rtl8821ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw, bool b_reject) +{ +#if 0 + struct rtl_priv rtlpriv = rtl_priv(hw); + PRX_TS_RECORD pRxTs = NULL; + + if(b_reject){ + // Do not allow receiving A-MPDU aggregation. + if (rtlpriv->mac80211.vendor == PEER_CISCO) { + if (pHTInfo->bAcceptAddbaReq) { + RTPRINT(FBT, BT_TRACE, ("BT_Disallow AMPDU \n")); + pHTInfo->bAcceptAddbaReq = FALSE; + if(GetTs(Adapter, (PTS_COMMON_INFO*)(&pRxTs), pMgntInfo->Bssid, 0, RX_DIR, FALSE)) + TsInitDelBA(Adapter, (PTS_COMMON_INFO)pRxTs, RX_DIR); + } + } else { + if (!pHTInfo->bAcceptAddbaReq) { + RTPRINT(FBT, BT_TRACE, ("BT_Allow AMPDU BT Idle\n")); + pHTInfo->bAcceptAddbaReq = TRUE; + } + } + } else { + if(rtlpriv->mac80211.vendor == PEER_CISCO) { + if (!pHTInfo->bAcceptAddbaReq) { + RTPRINT(FBT, BT_TRACE, ("BT_Allow AMPDU \n")); + pHTInfo->bAcceptAddbaReq = TRUE; + } + } + } +#endif +} + +void _rtl8821ae_dm_bt_check_wifi_state(struct ieee80211_hw *hw) +{ +struct rtl_priv *rtlpriv = rtl_priv(hw); +struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +struct rtl_phy *rtlphy = &(rtlpriv->phy); + +if (rtlpriv->link_info.b_busytraffic) { + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_IDLE; + + if(rtlpriv->link_info.b_tx_busy_traffic) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_UPLINK; + } else { + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_UPLINK; + } + + if(rtlpriv->link_info.b_rx_busy_traffic) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_DOWNLINK; + } else { + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_DOWNLINK; + } +} else { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_IDLE; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_UPLINK; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_DOWNLINK; +} + +if (rtlpriv->mac80211.mode == WIRELESS_MODE_G + || rtlpriv->mac80211.mode == WIRELESS_MODE_B) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_LEGACY; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_HT20; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_HT40; +} else { + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_LEGACY; + if(rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_HT40; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_HT20; + } else { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_HT20; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_HT40; + } +} + +if (bt_operation_on) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BT30; +} else { + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_BT30; +} +} + + +u8 rtl8821ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw, + u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) + +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + long undecoratedsmoothed_pwdb = 0; + u8 bt_rssi_state = 0; + + undecoratedsmoothed_pwdb = rtl8821ae_dm_bt_get_rx_ss(hw); + + if(level_num == 2) { + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + + if( (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_LOW) || + (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_STAY_LOW)) { + if(undecoratedsmoothed_pwdb >= (rssi_thresh + BT_FW_COEX_THRESH_TOL)) { + bt_rssi_state = BT_RSSI_STATE_HIGH; + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_RSSI_1_HIGH; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state switch to High\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state stay at Low\n")); + } + } else { + if(undecoratedsmoothed_pwdb < rssi_thresh) { + bt_rssi_state = BT_RSSI_STATE_LOW; + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_RSSI_1_LOW; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state switch to Low\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state stay at High\n")); + } + } + } else if(level_num == 3) { + if(rssi_thresh > rssi_thresh1) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 thresh error!!\n")); + return rtlpcipriv->btcoexist.bt_pre_rssi_state; + } + + if( (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_LOW) || + (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_STAY_LOW)) { + if(undecoratedsmoothed_pwdb >= (rssi_thresh+BT_FW_COEX_THRESH_TOL)) { + bt_rssi_state = BT_RSSI_STATE_MEDIUM; + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state switch to Medium\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state stay at Low\n")); + } + } else if( (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_MEDIUM) || + (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_STAY_MEDIUM)) { + if(undecoratedsmoothed_pwdb >= (rssi_thresh1 + BT_FW_COEX_THRESH_TOL)) { + bt_rssi_state = BT_RSSI_STATE_HIGH; + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_RSSI_1_HIGH; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state switch to High\n")); + } else if(undecoratedsmoothed_pwdb < rssi_thresh) { + bt_rssi_state = BT_RSSI_STATE_LOW; + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_RSSI_1_LOW; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state switch to Low\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_MEDIUM; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state stay at Medium\n")); + } + } else { + if(undecoratedsmoothed_pwdb < rssi_thresh1) { + bt_rssi_state = BT_RSSI_STATE_MEDIUM; + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE,("[DM][BT], RSSI_1 state switch to Medium\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[DM][BT], RSSI_1 state stay at High\n")); + } + } + } + + rtlpcipriv->btcoexist.bt_pre_rssi_state1 = bt_rssi_state; + + return bt_rssi_state; +} + +u8 rtl8821ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw, + u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + long undecoratedsmoothed_pwdb = 0; + u8 bt_rssi_state = 0; + + undecoratedsmoothed_pwdb = rtl8821ae_dm_bt_get_rx_ss(hw); + + if (level_num == 2) { + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; + + if ((rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_LOW) || + (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_STAY_LOW)){ + if (undecoratedsmoothed_pwdb + >= (rssi_thresh + BT_FW_COEX_THRESH_TOL)) { + bt_rssi_state = BT_RSSI_STATE_HIGH; + rtlpcipriv->btcoexist.current_state + |= BT_COEX_STATE_WIFI_RSSI_HIGH; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state switch to High\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state stay at Low\n")); + } + } else { + if (undecoratedsmoothed_pwdb < rssi_thresh) { + bt_rssi_state = BT_RSSI_STATE_LOW; + rtlpcipriv->btcoexist.current_state + |= BT_COEX_STATE_WIFI_RSSI_LOW; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state switch to Low\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state stay at High\n")); + } + } + } + else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI thresh error!!\n")); + return rtlpcipriv->btcoexist.bt_pre_rssi_state; + } + if ((rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_LOW) || + (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_STAY_LOW)) { + if(undecoratedsmoothed_pwdb + >= (rssi_thresh + BT_FW_COEX_THRESH_TOL)) { + bt_rssi_state = BT_RSSI_STATE_MEDIUM; + rtlpcipriv->btcoexist.current_state + |= BT_COEX_STATE_WIFI_RSSI_MEDIUM; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state switch to Medium\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state stay at Low\n")); + } + } else if ((rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_MEDIUM) || + (rtlpcipriv->btcoexist.bt_pre_rssi_state == BT_RSSI_STATE_STAY_MEDIUM)) { + if (undecoratedsmoothed_pwdb + >= (rssi_thresh1 + BT_FW_COEX_THRESH_TOL)) { + bt_rssi_state = BT_RSSI_STATE_HIGH; + rtlpcipriv->btcoexist.current_state + |= BT_COEX_STATE_WIFI_RSSI_HIGH; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state switch to High\n")); + } else if(undecoratedsmoothed_pwdb < rssi_thresh) + { + bt_rssi_state = BT_RSSI_STATE_LOW; + rtlpcipriv->btcoexist.current_state + |= BT_COEX_STATE_WIFI_RSSI_LOW; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state switch to Low\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_MEDIUM; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state stay at Medium\n")); + } + } else { + if(undecoratedsmoothed_pwdb < rssi_thresh1) { + bt_rssi_state = BT_RSSI_STATE_MEDIUM; + rtlpcipriv->btcoexist.current_state + |= BT_COEX_STATE_WIFI_RSSI_MEDIUM; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + rtlpcipriv->btcoexist.current_state + &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state switch to Medium\n")); + } else { + bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], RSSI state stay at High\n")); + } + } + } + + rtlpcipriv->btcoexist.bt_pre_rssi_state = bt_rssi_state; + return bt_rssi_state; +} +long rtl8821ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + long undecoratedsmoothed_pwdb = 0; + + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) { + undecoratedsmoothed_pwdb = GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); + } else { + undecoratedsmoothed_pwdb + = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + } + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("rtl8821ae_dm_bt_get_rx_ss() = %ld\n", undecoratedsmoothed_pwdb)); + + return undecoratedsmoothed_pwdb; +} + +void rtl8821ae_dm_bt_balance(struct ieee80211_hw *hw, + bool b_balance_on, u8 ms0, u8 ms1) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[3] ={0}; + + if (b_balance_on) { + h2c_parameter[2] = 1; + h2c_parameter[1] = ms1; + h2c_parameter[0] = ms0; + rtlpcipriv->btcoexist.b_fw_coexist_all_off = false; + } else { + h2c_parameter[2] = 0; + h2c_parameter[1] = 0; + h2c_parameter[0] = 0; + } + rtlpcipriv->btcoexist.b_balance_on = b_balance_on; + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[DM][BT], Balance=[%s:%dms:%dms], write 0xc=0x%x\n", + b_balance_on?"ON":"OFF", ms0, ms1, + h2c_parameter[0]<<16 | h2c_parameter[1]<<8 | h2c_parameter[2])); + + rtl8821ae_fill_h2c_cmd(hw, 0xc, 3, h2c_parameter); +} + + +void rtl8821ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if (type == BT_AGCTABLE_OFF) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BT]AGCTable Off!\n")); + rtl_write_dword(rtlpriv, 0xc78,0x641c0001); + rtl_write_dword(rtlpriv, 0xc78,0x631d0001); + rtl_write_dword(rtlpriv, 0xc78,0x621e0001); + rtl_write_dword(rtlpriv, 0xc78,0x611f0001); + rtl_write_dword(rtlpriv, 0xc78,0x60200001); + + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0x32000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0x71000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0xb0000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0xfc000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_G1, 0xfffff, 0x30355); + } else if (type == BT_AGCTABLE_ON) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BT]AGCTable On!\n")); + rtl_write_dword(rtlpriv, 0xc78,0x4e1c0001); + rtl_write_dword(rtlpriv, 0xc78,0x4d1d0001); + rtl_write_dword(rtlpriv, 0xc78,0x4c1e0001); + rtl_write_dword(rtlpriv, 0xc78,0x4b1f0001); + rtl_write_dword(rtlpriv, 0xc78,0x4a200001); + + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0xdc000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0x90000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0x51000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_AGC_HP, 0xfffff, 0x12000); + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, + RF_RX_G1, 0xfffff, 0x00355); + + rtlpcipriv->btcoexist.b_sw_coexist_all_off = false; + } +} + +void rtl8821ae_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if (type == BT_BB_BACKOFF_OFF) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BT]BBBackOffLevel Off!\n")); + rtl_write_dword(rtlpriv, 0xc04,0x3a05611); + } else if (type == BT_BB_BACKOFF_ON) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BT]BBBackOffLevel On!\n")); + rtl_write_dword(rtlpriv, 0xc04,0x3a07611); + rtlpcipriv->btcoexist.b_sw_coexist_all_off = false; + } +} + +void rtl8821ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("rtl8821ae_dm_bt_fw_coex_all_off()\n")); + + if(rtlpcipriv->btcoexist.b_fw_coexist_all_off) + return; + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("rtl8821ae_dm_bt_fw_coex_all_off(), real Do\n")); + rtl8821ae_dm_bt_fw_coex_all_off_8723a(hw); + rtlpcipriv->btcoexist.b_fw_coexist_all_off = true; +} + +void rtl8821ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("rtl8821ae_dm_bt_sw_coex_all_off()\n")); + + if(rtlpcipriv->btcoexist.b_sw_coexist_all_off) + return; + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("rtl8821ae_dm_bt_sw_coex_all_off(), real Do\n")); + rtl8821ae_dm_bt_sw_coex_all_off_8723a(hw); + rtlpcipriv->btcoexist.b_sw_coexist_all_off = true; +} + +void rtl8821ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("rtl8821ae_dm_bt_hw_coex_all_off()\n")); + + if(rtlpcipriv->btcoexist.b_hw_coexist_all_off) + return; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("rtl8821ae_dm_bt_hw_coex_all_off(), real Do\n")); + + rtl8821ae_dm_bt_hw_coex_all_off_8723a(hw); + + rtlpcipriv->btcoexist.b_hw_coexist_all_off = true; +} + +void rtl8821ae_btdm_coex_all_off(struct ieee80211_hw *hw) +{ + rtl8821ae_dm_bt_fw_coex_all_off(hw); + rtl8821ae_dm_bt_sw_coex_all_off(hw); + rtl8821ae_dm_bt_hw_coex_all_off(hw); +} + +bool rtl8821ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if((rtlpcipriv->btcoexist.previous_state + == rtlpcipriv->btcoexist.current_state) + && (rtlpcipriv->btcoexist.previous_state_h + == rtlpcipriv->btcoexist.current_state_h)) + return false; + else + return true; +} + +bool rtl8821ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->link_info.b_tx_busy_traffic) + return true; + else + return false; +} + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c @@ -0,0 +1,140 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "pwrseq.h" + + +/* +* Description: +* This routine deal with the Power Configuration CMDs +* parsing for RTL8723/RTL8188E Series IC. +* Assumption: +* We should follow specific format which was released from HW SD. +* +* 2011.07.07, added by Roger. +*/ +bool rtl_hal_pwrseqcmdparsing (struct rtl_priv* rtlpriv, u8 cut_version, + u8 fab_version, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]) + +{ + struct wlan_pwr_cfg pwr_cfg_cmd = {0}; + bool polling_bit = false; + u32 ary_idx=0; + u8 value = 0; + u32 offset = 0; + u32 polling_count = 0; + u32 max_polling_cnt = 5000; + + do { + pwr_cfg_cmd = pwrcfgcmd[ary_idx]; + RT_TRACE(COMP_INIT, DBG_TRACE, + ("rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), fab_msk(%#x)," + "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n", + GET_PWR_CFG_OFFSET(pwr_cfg_cmd), GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd), + GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd), GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd), + GET_PWR_CFG_BASE(pwr_cfg_cmd), GET_PWR_CFG_CMD(pwr_cfg_cmd), + GET_PWR_CFG_MASK(pwr_cfg_cmd), GET_PWR_CFG_VALUE(pwr_cfg_cmd))); + + if ((GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd)&fab_version) && + (GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd)&cut_version) && + (GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd)&interface_type)) { + switch (GET_PWR_CFG_CMD(pwr_cfg_cmd)) { + case PWR_CMD_READ: + RT_TRACE(COMP_INIT, DBG_TRACE, + ("rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n")); + break; + + case PWR_CMD_WRITE: { + RT_TRACE(COMP_INIT, DBG_TRACE, + ("rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n")); + offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd); + + /*Read the value from system register*/ + value = rtl_read_byte(rtlpriv, offset); + value = value & (~(GET_PWR_CFG_MASK(pwr_cfg_cmd))); + value = value | (GET_PWR_CFG_VALUE(pwr_cfg_cmd) + & GET_PWR_CFG_MASK(pwr_cfg_cmd)); + + /*Write the value back to sytem register*/ + rtl_write_byte(rtlpriv, offset, value); + } + break; + + case PWR_CMD_POLLING: + RT_TRACE(COMP_INIT, DBG_TRACE, + ("rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n")); + polling_bit = false; + offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd); + + do { + value = rtl_read_byte(rtlpriv, offset); + + value = value & GET_PWR_CFG_MASK(pwr_cfg_cmd); + if (value == (GET_PWR_CFG_VALUE(pwr_cfg_cmd) + & GET_PWR_CFG_MASK(pwr_cfg_cmd))) + polling_bit=true; + else + udelay(10); + + if (polling_count++ > max_polling_cnt) { + return false; + } + } while (!polling_bit); + + break; + + case PWR_CMD_DELAY: + RT_TRACE(COMP_INIT, DBG_TRACE, + ("rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n")); + if (GET_PWR_CFG_VALUE(pwr_cfg_cmd) == PWRSEQ_DELAY_US) + udelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd)); + else + mdelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd)); + break; + + case PWR_CMD_END: + RT_TRACE(COMP_INIT, DBG_TRACE, + ("rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n")); + return true; + break; + + default: + RT_ASSERT(false, + ("rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n")); + break; + } + + } + + ary_idx++; + } while (1); + + return true; +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/fw.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/fw.h @@ -0,0 +1,321 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE__FW__H__ +#define __RTL8821AE__FW__H__ + +#define FW_8821AE_SIZE 0x8000 +#define FW_8821AE_START_ADDRESS 0x1000 +#define FW_8821AE_END_ADDRESS 0x5FFF +#define FW_8821AE_PAGE_SIZE 4096 +#define FW_8821AE_POLLING_DELAY 5 +#define FW_8821AE_POLLING_TIMEOUT_COUNT 6000 + +#define IS_FW_HEADER_EXIST_8812(_pfwhdr) \ + ((_pfwhdr->signature&0xFFF0) == 0x9500 ) + +#define IS_FW_HEADER_EXIST_8821(_pfwhdr) \ + ((_pfwhdr->signature&0xFFF0) == 0x2100 ) + +#define USE_OLD_WOWLAN_DEBUG_FW 0 + +#define H2C_8821AE_RSVDPAGE_LOC_LEN 5 +#define H2C_8821AE_PWEMODE_LENGTH 5 +#define H2C_8821AE_JOINBSSRPT_LENGTH 1 +#define H2C_8821AE_AP_OFFLOAD_LENGTH 3 +#define H2C_8821AE_WOWLAN_LENGTH 3 +#define H2C_8821AE_KEEP_ALIVE_CTRL_LENGTH 3 +#if(USE_OLD_WOWLAN_DEBUG_FW == 0) +#define H2C_8821AE_REMOTE_WAKE_CTRL_LEN 1 +#else +#define H2C_8821AE_REMOTE_WAKE_CTRL_LEN 3 +#endif +#define H2C_8821AE_AOAC_GLOBAL_INFO_LEN 2 +#define H2C_8821AE_AOAC_RSVDPAGE_LOC_LEN 7 + + +/* Fw PS state for RPWM. +*BIT[2:0] = HW state +*BIT[3] = Protocol PS state, 1: register active state , 0: register sleep state +*BIT[4] = sub-state +*/ +#define FW_PS_GO_ON BIT(0) +#define FW_PS_TX_NULL BIT(1) +#define FW_PS_RF_ON BIT(2) +#define FW_PS_REGISTER_ACTIVE BIT(3) + +#define FW_PS_DPS BIT(0) +#define FW_PS_LCLK (FW_PS_DPS) +#define FW_PS_RF_OFF BIT(1) +#define FW_PS_ALL_ON BIT(2) +#define FW_PS_ST_ACTIVE BIT(3) +#define FW_PS_ISR_ENABLE BIT(4) +#define FW_PS_IMR_ENABLE BIT(5) + + +#define FW_PS_ACK BIT(6) +#define FW_PS_TOGGLE BIT(7) + + /* 8821AE RPWM value*/ + /* BIT[0] = 1: 32k, 0: 40M*/ +#define FW_PS_CLOCK_OFF BIT(0) /* 32k*/ +#define FW_PS_CLOCK_ON 0 /*40M*/ + +#define FW_PS_STATE_MASK (0x0F) +#define FW_PS_STATE_HW_MASK (0x07) +#define FW_PS_STATE_INT_MASK (0x3F) /*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/ + +#define FW_PS_STATE(x) (FW_PS_STATE_MASK & (x)) +#define FW_PS_STATE_HW(x) (FW_PS_STATE_HW_MASK & (x)) +#define FW_PS_STATE_INT(x) (FW_PS_STATE_INT_MASK & (x)) +#define FW_PS_ISR_VAL(x) ((x) & 0x70) +#define FW_PS_IMR_MASK(x) ((x) & 0xDF) +#define FW_PS_KEEP_IMR(x) ((x) & 0x20) + + +#define FW_PS_STATE_S0 (FW_PS_DPS) +#define FW_PS_STATE_S1 (FW_PS_LCLK) +#define FW_PS_STATE_S2 (FW_PS_RF_OFF) +#define FW_PS_STATE_S3 (FW_PS_ALL_ON) +#define FW_PS_STATE_S4 ((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON)) + +#define FW_PS_STATE_ALL_ON_8821AE (FW_PS_CLOCK_ON) /* ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))*/ +#define FW_PS_STATE_RF_ON_8821AE (FW_PS_CLOCK_ON) /* (FW_PS_RF_ON)*/ +#define FW_PS_STATE_RF_OFF_8821AE (FW_PS_CLOCK_ON) /* 0x0*/ +#define FW_PS_STATE_RF_OFF_LOW_PWR_8821AE (FW_PS_CLOCK_OFF) /* (FW_PS_STATE_RF_OFF)*/ + +#define FW_PS_STATE_ALL_ON_92C (FW_PS_STATE_S4) +#define FW_PS_STATE_RF_ON_92C (FW_PS_STATE_S3) +#define FW_PS_STATE_RF_OFF_92C (FW_PS_STATE_S2) +#define FW_PS_STATE_RF_OFF_LOW_PWR_92C (FW_PS_STATE_S1) + + +/* For 8821AE H2C PwrMode Cmd ID 5.*/ +#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define FW_PWR_STATE_RF_OFF 0 + +#define FW_PS_IS_ACK(x) ((x) & FW_PS_ACK ) +#define FW_PS_IS_CLK_ON(x) ((x) & (FW_PS_RF_OFF |FW_PS_ALL_ON )) +#define FW_PS_IS_RF_ON(x) ((x) & (FW_PS_ALL_ON)) +#define FW_PS_IS_ACTIVE(x) ((x) & (FW_PS_ST_ACTIVE)) +#define FW_PS_IS_CPWM_INT(x) ((x) & 0x40) + +#define FW_CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) + +#define IS_IN_LOW_POWER_STATE_8821AE(FwPSState) \ + (FW_PS_STATE(FwPSState) == FW_PS_CLOCK_OFF) + +#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define FW_PWR_STATE_RF_OFF 0 + +struct rtl8821a_firmware_header { + u16 signature; + u8 category; + u8 function; + u16 version; + u8 subversion; + u8 rsvd1; + u8 month; + u8 date; + u8 hour; + u8 minute; + u16 ramcodeSize; + u16 rsvd2; + u32 svnindex; + u32 rsvd3; + u32 rsvd4; + u32 rsvd5; +}; + +enum rtl8812_c2h_evt{ + C2H_8812_DBG = 0, + C2H_8812_LB = 1, + C2H_8812_TXBF = 2, + C2H_8812_TX_REPORT = 3, + C2H_8812_BT_INFO = 9, + C2H_8812_BT_MP = 11, + C2H_8812_RA_RPT=12, + + C2H_8812_FW_SWCHNL = 0x10, + C2H_8812_IQK_FINISH = 0x11, + MAX_8812_C2HEVENT +}; + +enum rtl8821a_h2c_cmd { + H2C_8821AE_RSVDPAGE = 0, + H2C_8821AE_JOINBSSRPT = 1, + H2C_8821AE_SCAN = 2, + H2C_8821AE_KEEP_ALIVE_CTRL = 3, + H2C_8821AE_DISCONNECT_DECISION = 4, +#if(USE_OLD_WOWLAN_DEBUG_FW == 1) + H2C_8821AE_WO_WLAN = 5, +#endif + H2C_8821AE_INIT_OFFLOAD = 6, +#if(USE_OLD_WOWLAN_DEBUG_FW == 1) + H2C_8821AE_REMOTE_WAKE_CTRL = 7, +#endif + H2C_8821AE_AP_OFFLOAD = 8, + H2C_8821AE_BCN_RSVDPAGE = 9, + H2C_8821AE_PROBERSP_RSVDPAGE = 10, + + H2C_8821AE_SETPWRMODE = 0x20, + H2C_8821AE_PS_TUNING_PARA = 0x21, + H2C_8821AE_PS_TUNING_PARA2 = 0x22, + H2C_8821AE_PS_LPS_PARA = 0x23, + H2C_8821AE_P2P_PS_OFFLOAD = 024, + +#if(USE_OLD_WOWLAN_DEBUG_FW == 0) + H2C_8821AE_WO_WLAN = 0x80, + H2C_8821AE_REMOTE_WAKE_CTRL = 0x81, + H2C_8821AE_AOAC_GLOBAL_INFO = 0x82, + H2C_8821AE_AOAC_RSVDPAGE = 0x83, +#endif + H2C_RSSI_REPORT = 0x42, + H2C_8821AE_RA_MASK = 0x40, + H2C_8821AE_SELECTIVE_SUSPEND_ROF_CMD, + H2C_8821AE_P2P_PS_MODE, + H2C_8821AE_PSD_RESULT, + /*Not defined CTW CMD for P2P yet*/ + H2C_8821AE_P2P_PS_CTW_CMD, + MAX_8821AE_H2CCMD +}; + +#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1:0)) + +#define SET_8821AE_H2CCMD_WOWLAN_FUNC_ENABLE(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 3, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_ALL_PKT_DROP(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_GPIO_ACTIVE(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 5, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_REKEY_WAKE_UP(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 6, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 7, 1, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_GPIONUM(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) +#define SET_8821AE_H2CCMD_WOWLAN_GPIO_DURATION(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) + + +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_RLBM(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 4, __Value) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 4, 4, __Value) +#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) +#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+3, 0, 8, __Value) +#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+4, 0, 8, __Value) +#define GET_8821AE_H2CCMD_PWRMODE_PARM_MODE(__pH2CCmd) \ + LE_BITS_TO_1BYTE(__pH2CCmd, 0, 8) + +#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) + +/* AP_OFFLOAD */ +#define SET_H2CCMD_AP_OFFLOAD_ON(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) +#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) +#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) +#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+3, 0, 8, __Value) + +/* Keep Alive Control*/ +#define SET_8821AE_H2CCMD_KEEP_ALIVE_ENABLE(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) +#define SET_8821AE_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) +#define SET_8821AE_H2CCMD_KEEP_ALIVE_PERIOD(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) + +/*REMOTE_WAKE_CTRL */ +#define SET_8821AE_H2CCMD_REMOTE_WAKE_CTRL_EN(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) +#if(USE_OLD_WOWLAN_DEBUG_FW == 0) +#define SET_8821AE_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) +#define SET_8821AE_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) +#define SET_8821AE_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 3, 1, __Value) +#else +#define SET_8821AE_H2CCMD_REMOTE_WAKE_CTRL_PAIRWISE_ENC_ALG(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) +#define SET_8821AE_H2CCMD_REMOTE_WAKE_CTRL_GROUP_ENC_ALG(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) +#endif + +/* GTK_OFFLOAD */ +#define SET_8821AE_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) +#define SET_8821AE_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) + +/* AOAC_RSVDPAGE_LOC */ +#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd), 0, 8, __Value) +#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) +#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) +#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+3, 0, 8, __Value) +#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__pH2CCmd, __Value) \ + SET_BITS_TO_LE_1BYTE((__pH2CCmd)+4, 0, 8, __Value) + +int rtl8821ae_download_fw(struct ieee80211_hw *hw, + bool buse_wake_on_wlan_fw); +void rtl8821ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl8821ae_firmware_selfreset(struct ieee80211_hw *hw); +void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl8821ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); +void rtl8821ae_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, u8 ap_offload_enable); +void rtl8821ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl8812ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl8821ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); +void rtl8812ae_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 length); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/trx.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/trx.h @@ -0,0 +1,641 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_TRX_H__ +#define __RTL8821AE_TRX_H__ + +#define TX_DESC_SIZE 40 +#define TX_DESC_AGGR_SUBFRAME_SIZE 32 + +#define RX_DESC_SIZE 32 +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define TX_DESC_NEXT_DESC_OFFSET 40 +#define USB_HWDESC_HEADER_LEN 40 +#define CRCLENGTH 4 + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val) + + +#define SET_TX_DESC_PAID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val) +#define SET_TX_DESC_CCA_RTS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_BT_INT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val) +#define SET_TX_DESC_GID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val) + + +#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val) +#define SET_TX_DESC_CHK_EN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val) +#define SET_TX_DESC_EARLY_MODE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val) +#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val) +#define SET_TX_DESC_NDPA(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val) +#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val) +#define SET_TX_DESC_TX_ANT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 4, __val) + +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val) +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val) + + +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \ + SET_BITS_TO_LE_1BYTE(__pdesc+20, 6, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val) +#define SET_TX_DESC_DATA_LDPC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_STBC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val) +#define SET_TX_DESC_CTROL_STBC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) + + +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) + +#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+28, 0, 16) + +#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+32, 15, 1, __val) + +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+36, 12, 12, __val) + +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val) + +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+40, 0, 32) + + +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 32, __val) + +#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+48, 0, 32) + +#define GET_RX_DESC_PKT_LEN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 0, 7) +#define GET_RX_DESC_TID(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 8, 4) +#define GET_RX_DESC_AMSDU(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 13, 1) +#define GET_RX_STATUS_DESC_RXID_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_RX_DESC_PAGGR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_RX_DESC_CHKERR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 20, 1) +#define GET_RX_DESC_IPVER(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 21, 1) +#define GET_RX_STATUS_DESC_IS_TCPUDP(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 22, 1) +#define GET_RX_STATUS_DESC_CHK_VLD(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 23, 1) +#define GET_RX_DESC_PAM(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 31, 1) + + +#define GET_RX_DESC_SEQ(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 12, 4) +#define GET_RX_STATUS_DESC_RX_IS_QOS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 16, 1) +#define GET_RX_STATUS_DESC_WLANHD_IV_LEN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 18, 6) +#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 28, 1) + + +#define GET_RX_DESC_RXMCS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 0, 7) +#define GET_RX_DESC_RXHT(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 6, 1) +#define GET_RX_STATUS_DESC_RX_GF(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 7, 1) +#define GET_RX_DESC_HTC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 10, 1) +#define GET_RX_STATUS_DESC_EOSP(__pdesc) \ + LE_BITS_TO_4BYTE( __pdesc+12, 11, 1) +#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc) \ + LE_BITS_TO_4BYTE( __pdesc+12, 12, 2) + +#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE( __pdesc+12, 29, 1) +#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE( __pdesc+12, 30, 1) +#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE( __pdesc+12, 31, 1) + +#define GET_RX_DESC_SPLCP(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 0, 1) +#define GET_RX_STATUS_DESC_LDPC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 1, 1) +#define GET_RX_STATUS_DESC_STBC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 2, 1) +#define GET_RX_DESC_BW(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 4, 2) + +#define GET_RX_DESC_TSFL(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val) + + +/* TX report 2 format in Rx desc*/ + +#define GET_RX_RPT2_DESC_PKT_LEN(__pRxStatusDesc) \ + LE_BITS_TO_4BYTE( __pRxStatusDesc, 0, 9) +#define GET_RX_RPT2_DESC_MACID_VALID_1(__pRxStatusDesc) \ + LE_BITS_TO_4BYTE( __pRxStatusDesc+16, 0, 32) +#define GET_RX_RPT2_DESC_MACID_VALID_2(__pRxStatusDesc) \ + LE_BITS_TO_4BYTE( __pRxStatusDesc+20, 0, 32) + +#define SET_EARLYMODE_PKTNUM(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __value) +#define SET_EARLYMODE_LEN0(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 4, 12, __value) +#define SET_EARLYMODE_LEN1(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 16, 12, __value) +#define SET_EARLYMODE_LEN2_1(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 28, 4, __value) +#define SET_EARLYMODE_LEN2_2(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8, __value) +#define SET_EARLYMODE_LEN3(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr+4, 8, 12, __value) +#define SET_EARLYMODE_LEN4(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __value) + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ +do { \ + if(_size > TX_DESC_NEXT_DESC_OFFSET) \ + memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + else \ + memset(__pdesc, 0, _size); \ +} while (0); + +#define RX_HAL_IS_CCK_RATE(rxmcs)\ + (rxmcs == DESC_RATE1M ||\ + rxmcs == DESC_RATE2M ||\ + rxmcs == DESC_RATE5_5M ||\ + rxmcs == DESC_RATE11M) + +#define IS_LITTLE_ENDIAN 1 + +struct phy_rx_agc_info_t { + #if IS_LITTLE_ENDIAN + u8 gain:7,trsw:1; + #else + u8 trsw:1,gain:7; + #endif +}; +struct phy_status_rpt{ + struct phy_rx_agc_info_t path_agc[2]; + u8 ch_corr[2]; + u8 cck_sig_qual_ofdm_pwdb_all; + u8 cck_agc_rpt_ofdm_cfosho_a; + u8 cck_rpt_b_ofdm_cfosho_b; + u8 rsvd_1;//ch_corr_msb; + u8 noise_power_db_msb; + u8 path_cfotail[2]; + u8 pcts_mask[2]; + u8 stream_rxevm[2]; + u8 path_rxsnr[2]; + u8 noise_power_db_lsb; + u8 rsvd_2[3]; + u8 stream_csi[2]; + u8 stream_target_csi[2]; + u8 sig_evm; + u8 rsvd_3; +#if IS_LITTLE_ENDIAN + u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/ + u8 sgi_en:1; + u8 rxsc:2; + u8 idle_long:1; + u8 r_ant_train_en:1; + u8 ant_sel_b:1; + u8 ant_sel:1; +#else /* _BIG_ENDIAN_ */ + u8 ant_sel:1; + u8 ant_sel_b:1; + u8 r_ant_train_en:1; + u8 idle_long:1; + u8 rxsc:2; + u8 sgi_en:1; + u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/ +#endif +}__packed; + +struct rx_fwinfo_8821ae { + u8 gain_trsw[4]; + u8 pwdb_all; + u8 cfosho[4]; + u8 cfotail[4]; + char rxevm[2]; + char rxsnr[4]; + u8 pdsnr[2]; + u8 csi_current[2]; + u8 csi_target[2]; + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +} __packed; + +struct tx_desc_8821ae { + u32 pktsize:16; + u32 offset:8; + u32 bmc:1; + u32 htc:1; + u32 lastseg:1; + u32 firstseg:1; + u32 linip:1; + u32 noacm:1; + u32 gf:1; + u32 own:1; + + u32 macid:6; + u32 rsvd0:2; + u32 queuesel:5; + u32 rd_nav_ext:1; + u32 lsig_txop_en:1; + u32 pifs:1; + u32 rateid:4; + u32 nav_usehdr:1; + u32 en_descid:1; + u32 sectype:2; + u32 pktoffset:8; + + u32 rts_rc:6; + u32 data_rc:6; + u32 agg_en:1; + u32 rdg_en:1; + u32 bar_retryht:2; + u32 agg_break:1; + u32 morefrag:1; + u32 raw:1; + u32 ccx:1; + u32 ampdudensity:3; + u32 bt_int:1; + u32 ant_sela:1; + u32 ant_selb:1; + u32 txant_cck:2; + u32 txant_l:2; + u32 txant_ht:2; + + u32 nextheadpage:8; + u32 tailpage:8; + u32 seq:12; + u32 cpu_handle:1; + u32 tag1:1; + u32 trigger_int:1; + u32 hwseq_en:1; + + u32 rtsrate:5; + u32 apdcfe:1; + u32 qos:1; + u32 hwseq_ssn:1; + u32 userrate:1; + u32 dis_rtsfb:1; + u32 dis_datafb:1; + u32 cts2self:1; + u32 rts_en:1; + u32 hwrts_en:1; + u32 portid:1; + u32 pwr_status:3; + u32 waitdcts:1; + u32 cts2ap_en:1; + u32 txsc:2; + u32 stbc:2; + u32 txshort:1; + u32 txbw:1; + u32 rtsshort:1; + u32 rtsbw:1; + u32 rtssc:2; + u32 rtsstbc:2; + + u32 txrate:6; + u32 shortgi:1; + u32 ccxt:1; + u32 txrate_fb_lmt:5; + u32 rtsrate_fb_lmt:4; + u32 retrylmt_en:1; + u32 txretrylmt:6; + u32 usb_txaggnum:8; + + u32 txagca:5; + u32 txagcb:5; + u32 usemaxlen:1; + u32 maxaggnum:5; + u32 mcsg1maxlen:4; + u32 mcsg2maxlen:4; + u32 mcsg3maxlen:4; + u32 mcs7sgimaxlen:4; + + u32 txbuffersize:16; + u32 sw_offset30:8; + u32 sw_offset31:4; + u32 rsvd1:1; + u32 antsel_c:1; + u32 null_0:1; + u32 null_1:1; + + u32 txbuffaddr; + u32 txbufferaddr64; + u32 nextdescaddress; + u32 nextdescaddress64; + + u32 reserve_pass_pcie_mm_limit[4]; +} __packed; + +struct rx_desc_8821ae { + u32 length:14; + u32 crc32:1; + u32 icverror:1; + u32 drv_infosize:4; + u32 security:3; + u32 qos:1; + u32 shift:2; + u32 phystatus:1; + u32 swdec:1; + u32 lastseg:1; + u32 firstseg:1; + u32 eor:1; + u32 own:1; + + u32 macid:6; + u32 tid:4; + u32 hwrsvd:5; + u32 paggr:1; + u32 faggr:1; + u32 a1_fit:4; + u32 a2_fit:4; + u32 pam:1; + u32 pwr:1; + u32 moredata:1; + u32 morefrag:1; + u32 type:2; + u32 mc:1; + u32 bc:1; + + u32 seq:12; + u32 frag:4; + u32 nextpktlen:14; + u32 nextind:1; + u32 rsvd:1; + + u32 rxmcs:6; + u32 rxht:1; + u32 amsdu:1; + u32 splcp:1; + u32 bandwidth:1; + u32 htc:1; + u32 tcpchk_rpt:1; + u32 ipcchk_rpt:1; + u32 tcpchk_valid:1; + u32 hwpcerr:1; + u32 hwpcind:1; + u32 iv0:16; + + u32 iv1; + + u32 tsfl; + + u32 bufferaddress; + u32 bufferaddress64; + +} __packed; + +/**/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) +void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, u8 *txbd, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); +#else +/**/ +void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, u8 *txbd, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, + struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); +/**/ +#endif +/**/ +bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *status, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb); +void rtl8821ae_set_desc(struct ieee80211_hw * hw, u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl8821ae_get_desc(u8 *pdesc, bool istx, u8 desc_name); +bool rtl8821ae_is_tx_desc_closed(struct ieee80211_hw *hw, + u8 hw_queue, u16 index); +void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); +void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff *skb); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/led.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/led.c @@ -0,0 +1,239 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" + +static void _rtl8821ae_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, + enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->b_ledon = false; +} + +void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + ledcfg &= ~BIT(6); + rtl_write_byte(rtlpriv, + REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5)); + break; + case LED_PIN_LED1: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1); + rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10); + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + pled->b_ledon = true; +} + +void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u16 ledreg = REG_LEDCFG1; + u8 ledcfg = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (pled->ledpin) { + case LED_PIN_LED0: + ledreg = REG_LEDCFG1; + break; + + case LED_PIN_LED1: + ledreg = REG_LEDCFG2; + break; + + case LED_PIN_GPIO0: + default: + break; + } + + RT_TRACE(COMP_LED, DBG_LOUD, ("In SwLedOn, LedAddr:%X LEDPIN=%d \n", ledreg, pled->ledpin)); + + ledcfg = rtl_read_byte(rtlpriv, ledreg); + ledcfg |= BIT(5); /*Set 0x4c[21]*/ + ledcfg &= ~(BIT(7) | BIT(6) | BIT(3) |BIT(2) | BIT(1) |BIT(0)); + /*Clear 0x4c[23:22] and 0x4c[19:16]*/ + rtl_write_byte(rtlpriv, ledreg, ledcfg); /*SW control led0 on.*/ + pled->b_ledon = true; +} + +void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + RT_TRACE(COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.bled_opendrain == true) { + ledcfg &= 0x90; /* Set to software control. */ + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3))); + ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG); + ledcfg &= 0xFE; + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg); + } + else { + ledcfg &= ~BIT(6); + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(3) | BIT(5))); + } + break; + case LED_PIN_LED1: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1); + ledcfg &= 0x10; /* Set to software control. */ + rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3)); + + break; + default: + RT_TRACE(COMP_ERR, DBG_EMERG, + ("switch case not process \n")); + break; + } + pled->b_ledon = false; +} + +void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled){ + u16 ledreg = REG_LEDCFG1; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + + switch(pled->ledpin) + { + case LED_PIN_LED0: + ledreg = REG_LEDCFG1; + break; + + case LED_PIN_LED1: + ledreg = REG_LEDCFG2; + break; + + case LED_PIN_GPIO0: + default: + break; + } + + RT_TRACE(COMP_LED,DBG_LOUD,("In SwLedOff,LedAddr:%X LEDPIN=%d\n", ledreg, pled->ledpin)); + + if(pcipriv->ledctl.bled_opendrain == true) /*Open-drain arrangement for controlling the LED*/ + { + u8 ledcfg = rtl_read_byte(rtlpriv, ledreg); + + ledreg &= 0xd0; /* Set to software control.*/ + rtl_write_byte(rtlpriv, ledreg, (ledcfg | BIT(3))); + + /*Open-drain arrangement*/ + ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG); + ledcfg &= 0xFE;/*Set GPIO[8] to input mode*/ + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg); + } + else + { + rtl_write_byte(rtlpriv, ledreg, 0x28); + } + + pled->b_ledon = false; +} + +void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl8821ae_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl8821ae_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +static void _rtl8821ae_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + switch (ledaction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + rtl8812ae_sw_led_on(hw, pLed0); + else + rtl8821ae_sw_led_on(hw, pLed0); + break; + case LED_CTL_POWER_OFF: + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)\ + rtl8812ae_sw_led_off(hw, pLed0); + else + rtl8821ae_sw_led_off(hw, pLed0); + break; + default: + break; + } +} + +void rtl8821ae_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && + (ledaction == LED_CTL_TX || + ledaction == LED_CTL_RX || + ledaction == LED_CTL_SITE_SURVEY || + ledaction == LED_CTL_LINK || + ledaction == LED_CTL_NO_LINK || + ledaction == LED_CTL_START_TO_LINK || + ledaction == LED_CTL_POWER_ON)) { + return; + } + RT_TRACE(COMP_LED, DBG_LOUD, ("ledaction %d, \n", + ledaction)); + _rtl8821ae_sw_led_control(hw, ledaction); +} --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h @@ -0,0 +1,169 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_HAL_BT_COEXIST_H__ +#define __RTL8821AE_HAL_BT_COEXIST_H__ + +#include "../wifi.h" + +/* The reg define is for 8723 */ +#define REG_HIGH_PRIORITY_TXRX 0x770 +#define REG_LOW_PRIORITY_TXRX 0x774 + +#define BT_FW_COEX_THRESH_TOL 6 +#define BT_FW_COEX_THRESH_20 20 +#define BT_FW_COEX_THRESH_23 23 +#define BT_FW_COEX_THRESH_25 25 +#define BT_FW_COEX_THRESH_30 30 +#define BT_FW_COEX_THRESH_35 35 +#define BT_FW_COEX_THRESH_40 40 +#define BT_FW_COEX_THRESH_45 45 +#define BT_FW_COEX_THRESH_47 47 +#define BT_FW_COEX_THRESH_50 50 +#define BT_FW_COEX_THRESH_55 55 + +#define BT_COEX_STATE_BT30 BIT(0) +#define BT_COEX_STATE_WIFI_HT20 BIT(1) +#define BT_COEX_STATE_WIFI_HT40 BIT(2) +#define BT_COEX_STATE_WIFI_LEGACY BIT(3) + +#define BT_COEX_STATE_WIFI_RSSI_LOW BIT(4) +#define BT_COEX_STATE_WIFI_RSSI_MEDIUM BIT(5) +#define BT_COEX_STATE_WIFI_RSSI_HIGH BIT(6) +#define BT_COEX_STATE_DEC_BT_POWER BIT(7) + +#define BT_COEX_STATE_WIFI_IDLE BIT(8) +#define BT_COEX_STATE_WIFI_UPLINK BIT(9) +#define BT_COEX_STATE_WIFI_DOWNLINK BIT(10) + +#define BT_COEX_STATE_BT_INQ_PAGE BIT(11) +#define BT_COEX_STATE_BT_IDLE BIT(12) +#define BT_COEX_STATE_BT_UPLINK BIT(13) +#define BT_COEX_STATE_BT_DOWNLINK BIT(14) + +#define BT_COEX_STATE_HOLD_FOR_BT_OPERATION BIT(15) +#define BT_COEX_STATE_BT_RSSI_LOW BIT(19) + +#define BT_COEX_STATE_PROFILE_HID BIT(20) +#define BT_COEX_STATE_PROFILE_A2DP BIT(21) +#define BT_COEX_STATE_PROFILE_PAN BIT(22) +#define BT_COEX_STATE_PROFILE_SCO BIT(23) + +#define BT_COEX_STATE_WIFI_RSSI_1_LOW BIT(24) +#define BT_COEX_STATE_WIFI_RSSI_1_MEDIUM BIT(25) +#define BT_COEX_STATE_WIFI_RSSI_1_HIGH BIT(26) + +#define BT_COEX_STATE_BTINFO_COMMON BIT(30) +#define BT_COEX_STATE_BTINFO_B_HID_SCOESCO BIT(31) +#define BT_COEX_STATE_BTINFO_B_FTP_A2DP BIT(29) + +#define BT_COEX_STATE_BT_CNT_LEVEL_0 BIT(0) +#define BT_COEX_STATE_BT_CNT_LEVEL_1 BIT(1) +#define BT_COEX_STATE_BT_CNT_LEVEL_2 BIT(2) +#define BT_COEX_STATE_BT_CNT_LEVEL_3 BIT(3) + +#define BT_RSSI_STATE_HIGH 0 +#define BT_RSSI_STATE_MEDIUM 1 +#define BT_RSSI_STATE_LOW 2 +#define BT_RSSI_STATE_STAY_HIGH 3 +#define BT_RSSI_STATE_STAY_MEDIUM 4 +#define BT_RSSI_STATE_STAY_LOW 5 + +#define BT_AGCTABLE_OFF 0 +#define BT_AGCTABLE_ON 1 +#define BT_BB_BACKOFF_OFF 0 +#define BT_BB_BACKOFF_ON 1 +#define BT_FW_NAV_OFF 0 +#define BT_FW_NAV_ON 1 + +#define BT_COEX_MECH_NONE 0 +#define BT_COEX_MECH_SCO 1 +#define BT_COEX_MECH_HID 2 +#define BT_COEX_MECH_A2DP 3 +#define BT_COEX_MECH_PAN 4 +#define BT_COEX_MECH_HID_A2DP 5 +#define BT_COEX_MECH_HID_PAN 6 +#define BT_COEX_MECH_PAN_A2DP 7 +#define BT_COEX_MECH_HID_SCO_ESCO 8 +#define BT_COEX_MECH_FTP_A2DP 9 +#define BT_COEX_MECH_COMMON 10 +#define BT_COEX_MECH_MAX 11 + +#define BT_DBG_PROFILE_NONE 0 +#define BT_DBG_PROFILE_SCO 1 +#define BT_DBG_PROFILE_HID 2 +#define BT_DBG_PROFILE_A2DP 3 +#define BT_DBG_PROFILE_PAN 4 +#define BT_DBG_PROFILE_HID_A2DP 5 +#define BT_DBG_PROFILE_HID_PAN 6 +#define BT_DBG_PROFILE_PAN_A2DP 7 +#define BT_DBG_PROFILE_MAX 9 + +#define BTINFO_B_FTP BIT(7) +#define BTINFO_B_A2DP BIT(6) +#define BTINFO_B_HID BIT(5) +#define BTINFO_B_SCO_BUSY BIT(4) +#define BTINFO_B_ACL_BUSY BIT(3) +#define BTINFO_B_INQ_PAGE BIT(2) +#define BTINFO_B_SCO_ESCO BIT(1) +#define BTINFO_B_CONNECTION BIT(0) + + +void rtl8821ae_btdm_coex_all_off(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw); + +void rtl8821ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw); +long rtl8821ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_balance(struct ieee80211_hw *hw, + bool b_balance_on, u8 ms0, u8 ms1); +void rtl8821ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 tyep); +void rtl8821ae_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type); +u8 rtl8821ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw, + u8 level_num, u8 rssi_thresh, u8 rssi_thresh1); +u8 rtl8821ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw, + u8 level_num, u8 rssi_thresh, u8 rssi_thresh1); +void _rtl8821ae_dm_bt_check_wifi_state(struct ieee80211_hw *hw); +void rtl8821ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw, + bool b_reject); + +#if 0 +VOID +BTDM_PWDBMonitor( + PADAPTER Adapter + ); + +BOOLEAN +BTDM_DIGByBTRSSI( + PADAPTER Adapter + ); +#endif +bool rtl8821ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw); +bool rtl8821ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw); +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/rf.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/rf.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_RF_H__ +#define __RTL8821AE_RF_H__ + +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F + +extern void rtl8821ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl8821ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl8821ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel_ofdm, + u8 *ppowerlevel_bw20, + u8 *ppowerlevel_bw40, + u8 channel); +extern bool rtl8821ae_phy_rf6052_config(struct ieee80211_hw *hw); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/sw.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/sw.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_SW_H__ +#define __RTL8821AE_SW_H__ + +int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw); +void rtl8821ae_deinit_sw_vars(struct ieee80211_hw *hw); +void rtl8821ae_init_var_map(struct ieee80211_hw *hw); +bool rtl8821ae_get_btc_status(void); + + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c @@ -0,0 +1,2069 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#include "hal_btc.h" +#include "../pci.h" +#include "phy.h" +#include "fw.h" +#include "reg.h" +#include "def.h" +#include "../btcoexist/rtl_btc.h" + +static struct bt_coexist_8821ae hal_coex_8821ae; + +void rtl8821ae_dm_bt_turn_off_bt_coexist_before_enter_lps(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if(!rtlpcipriv->btcoexist.bt_coexistence) + return; + + if(ppsc->b_inactiveps) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG,("[BT][DM], Before enter IPS, turn off all Coexist DM\n")); + rtlpcipriv->btcoexist.current_state = 0; + rtlpcipriv->btcoexist.previous_state = 0; + rtlpcipriv->btcoexist.current_state_h = 0; + rtlpcipriv->btcoexist.previous_state_h = 0; + rtl8821ae_btdm_coex_all_off(hw); + } +} + + +enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum rt_media_status m_status = RT_MEDIA_DISCONNECT; + + u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + + if(bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED) { + m_status = RT_MEDIA_CONNECT; + } + + return m_status; +} + +void rtl_8821ae_bt_wifi_media_status_notify(struct ieee80211_hw *hw, bool mstatus) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 h2c_parameter[3] ={0}; + u8 chnl; + + if(!rtlpcipriv->btcoexist.bt_coexistence) + return; + + if(RT_MEDIA_CONNECT == mstatus) + h2c_parameter[0] = 0x1; // 0: disconnected, 1:connected + else + h2c_parameter[0] = 0x0; + + if(mgnt_link_status_query(hw)) { + chnl = rtlphy->current_channel; + h2c_parameter[1] = chnl; + } + + if(rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40){ + h2c_parameter[2] = 0x30; + } else { + h2c_parameter[2] = 0x20; + } + + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG,("[BTCoex], FW write 0x19=0x%x\n", + h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2])); + + rtl8821ae_fill_h2c_cmd(hw, 0x19, 3, h2c_parameter); + +} + + +bool rtl8821ae_dm_bt_is_wifi_busy(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if(rtlpriv->link_info.b_busytraffic || + rtlpriv->link_info.b_rx_busy_traffic || + rtlpriv->link_info.b_tx_busy_traffic) + return true; + else + return false; +} +void rtl8821ae_dm_bt_set_fw_3a(struct ieee80211_hw *hw, + u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[5] ={0}; + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], FW write 0x3a(4bytes)=0x%x%8x\n", + h2c_parameter[0], h2c_parameter[1]<<24 | h2c_parameter[2]<<16 | h2c_parameter[3]<<8 | h2c_parameter[4])); + rtl8821ae_fill_h2c_cmd(hw, 0x3a, 5, h2c_parameter); +} + +bool rtl8821ae_dm_bt_need_to_dec_bt_pwr(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (mgnt_link_status_query(hw) == RT_MEDIA_CONNECT) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Need to decrease bt power\n")); + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_DEC_BT_POWER; + return true; + } + + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_DEC_BT_POWER; + return false; +} + + +bool rtl8821ae_dm_bt_is_same_coexist_state(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if ((rtlpcipriv->btcoexist.previous_state + == rtlpcipriv->btcoexist.current_state) + &&(rtlpcipriv->btcoexist.previous_state_h + == rtlpcipriv->btcoexist.current_state_h)) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[DM][BT], Coexist state do not chang!!\n")); + return true; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[DM][BT], Coexist state changed!!\n")); + return false; + } +} + +void rtl8821ae_dm_bt_set_coex_table(struct ieee80211_hw *hw, + u32 val_0x6c0, u32 val_0x6c8, u32 val_0x6cc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("set coex table, set 0x6c0=0x%x\n", val_0x6c0)); + rtl_write_dword(rtlpriv, 0x6c0, val_0x6c0); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("set coex table, set 0x6c8=0x%x\n", val_0x6c8)); + rtl_write_dword(rtlpriv, 0x6c8, val_0x6c8); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("set coex table, set 0x6cc=0x%x\n", val_0x6cc)); + rtl_write_byte(rtlpriv, 0x6cc, val_0x6cc); +} + +void rtl8821ae_dm_bt_set_hw_pta_mode(struct ieee80211_hw *hw, bool b_mode) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (BT_PTA_MODE_ON == b_mode) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("PTA mode on, ")); + /* Enable GPIO 0/1/2/3/8 pins for bt */ + rtl_write_byte(rtlpriv, 0x40, 0x20); + rtlpcipriv->btcoexist.b_hw_coexist_all_off = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("PTA mode off\n")); + rtl_write_byte(rtlpriv, 0x40, 0x0); + } +} + +void rtl8821ae_dm_bt_set_sw_rf_rx_lpf_corner(struct ieee80211_hw *hw, u8 type) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (BT_RF_RX_LPF_CORNER_SHRINK == type) { + /* Shrink RF Rx LPF corner, 0x1e[7:4]=1111 ==> [11:4] by Jenyu */ + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Shrink RF Rx LPF corner!!\n")); + /* PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)PathA, 0x1e, 0xf0, 0xf); */ + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff, 0xf0ff7); + rtlpcipriv->btcoexist.b_sw_coexist_all_off = false; + } else if(BT_RF_RX_LPF_CORNER_RESUME == type) { + /*Resume RF Rx LPF corner*/ + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Resume RF Rx LPF corner!!\n")); + /* PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)PathA, 0x1e, 0xf0, + * pHalData->btcoexist.BtRfRegOrigin1E); */ + rtl8821ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff, + rtlpcipriv->btcoexist.bt_rfreg_origin_1e); + } +} + +void rtl8821ae_dm_bt_set_sw_penalty_tx_rate_adaptive(struct ieee80211_hw *hw, + u8 ra_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 tmp_u1; + + tmp_u1 = rtl_read_byte(rtlpriv, 0x4fd); + tmp_u1 |= BIT(0); + if (BT_TX_RATE_ADAPTIVE_LOW_PENALTY == ra_type) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Tx rate adaptive, set low penalty!!\n")); + tmp_u1 &= ~BIT(2); + rtlpcipriv->btcoexist.b_sw_coexist_all_off = false; + } else if(BT_TX_RATE_ADAPTIVE_NORMAL == ra_type) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Tx rate adaptive, set normal!!\n")); + tmp_u1 |= BIT(2); + } + + rtl_write_byte(rtlpriv, 0x4fd, tmp_u1); +} + +void rtl8821ae_dm_bt_btdm_structure_reload(struct ieee80211_hw *hw, + struct btdm_8821ae *p_btdm) +{ + p_btdm->b_all_off = false; + p_btdm->b_agc_table_en = false; + p_btdm->b_adc_back_off_on = false; + p_btdm->b2_ant_hid_en = false; + p_btdm->b_low_penalty_rate_adaptive = false; + p_btdm->b_rf_rx_lpf_shrink = false; + p_btdm->b_reject_aggre_pkt= false; + + p_btdm->b_tdma_on = false; + p_btdm->tdma_ant = TDMA_2ANT; + p_btdm->tdma_nav = TDMA_NAV_OFF; + p_btdm->tdma_dac_swing = TDMA_DAC_SWING_OFF; + p_btdm->fw_dac_swing_lvl = 0x20; + + p_btdm->b_tra_tdma_on = false; + p_btdm->tra_tdma_ant = TDMA_2ANT; + p_btdm->tra_tdma_nav = TDMA_NAV_OFF; + p_btdm->b_ignore_wlan_act = false; + + p_btdm->b_ps_tdma_on = false; + p_btdm->ps_tdma_byte[0] = 0x0; + p_btdm->ps_tdma_byte[1] = 0x0; + p_btdm->ps_tdma_byte[2] = 0x0; + p_btdm->ps_tdma_byte[3] = 0x8; + p_btdm->ps_tdma_byte[4] = 0x0; + + p_btdm->b_pta_on = true; + p_btdm->val_0x6c0 = 0x5a5aaaaa; + p_btdm->val_0x6c8 = 0xcc; + p_btdm->val_0x6cc = 0x3; + + p_btdm->b_sw_dac_swing_on = false; + p_btdm->sw_dac_swing_lvl = 0xc0; + p_btdm->wlan_act_hi = 0x20; + p_btdm->wlan_act_lo = 0x10; + p_btdm->bt_retry_index = 2; + + p_btdm->b_dec_bt_pwr = false; +} + +void rtl8821ae_dm_bt_btdm_structure_reload_all_off(struct ieee80211_hw *hw, + struct btdm_8821ae *p_btdm) +{ + rtl8821ae_dm_bt_btdm_structure_reload(hw, p_btdm); + p_btdm->b_all_off = true; + p_btdm->b_pta_on = false; + p_btdm->wlan_act_hi = 0x10; +} + +bool rtl8821ae_dm_bt_is_2_ant_common_action(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct btdm_8821ae btdm8821ae; + bool b_common = false; + + rtl8821ae_dm_bt_btdm_structure_reload(hw, &btdm8821ae); + + if(!rtl8821ae_dm_bt_is_wifi_busy(hw) + && !rtlpcipriv->btcoexist.b_bt_busy) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("Wifi idle + Bt idle, bt coex mechanism always off!!\n")); + rtl8821ae_dm_bt_btdm_structure_reload_all_off(hw, &btdm8821ae); + b_common = true; + } else if (rtl8821ae_dm_bt_is_wifi_busy(hw) + && !rtlpcipriv->btcoexist.b_bt_busy) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("Wifi non-idle + Bt disabled/idle!!\n")); + btdm8821ae.b_low_penalty_rate_adaptive = true; + btdm8821ae.b_rf_rx_lpf_shrink = false; + btdm8821ae.b_reject_aggre_pkt = false; + + /* sw mechanism */ + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + + btdm8821ae.b_pta_on = true; + btdm8821ae.val_0x6c0 = 0x5a5aaaaa; + btdm8821ae.val_0x6c8 = 0xcccc; + btdm8821ae.val_0x6cc = 0x3; + + btdm8821ae.b_tdma_on = false; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_OFF; + btdm8821ae.b2_ant_hid_en = false; + + b_common = true; + }else if (rtlpcipriv->btcoexist.b_bt_busy) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("Bt non-idle!\n")); + if(mgnt_link_status_query(hw) == RT_MEDIA_CONNECT){ + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi connection exist\n")) + b_common = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("No Wifi connection!\n")); + btdm8821ae.b_rf_rx_lpf_shrink = true; + btdm8821ae.b_low_penalty_rate_adaptive = false; + btdm8821ae.b_reject_aggre_pkt = false; + + /* sw mechanism */ + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + + btdm8821ae.b_pta_on = true; + btdm8821ae.val_0x6c0 = 0x55555555; + btdm8821ae.val_0x6c8 = 0x0000ffff; + btdm8821ae.val_0x6cc = 0x3; + + btdm8821ae.b_tdma_on = false; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_OFF; + btdm8821ae.b2_ant_hid_en = false; + + b_common = true; + } + } + + if (rtl8821ae_dm_bt_need_to_dec_bt_pwr(hw)) { + btdm8821ae.b_dec_bt_pwr = true; + } + + if(b_common) + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BTINFO_COMMON; + + if (b_common && rtl8821ae_dm_bt_is_coexist_state_changed(hw)) + rtl8821ae_dm_bt_set_bt_dm(hw, &btdm8821ae); + + return b_common; +} + +void rtl8821ae_dm_bt_set_sw_full_time_dac_swing( + struct ieee80211_hw * hw, bool b_sw_dac_swing_on, u32 sw_dac_swing_lvl) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (b_sw_dac_swing_on) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], SwDacSwing = 0x%x\n", sw_dac_swing_lvl)); + rtl8821ae_phy_set_bb_reg(hw, 0x880, 0xff000000, sw_dac_swing_lvl); + rtlpcipriv->btcoexist.b_sw_coexist_all_off = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], SwDacSwing Off!\n")); + rtl8821ae_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0); + } +} + +void rtl8821ae_dm_bt_set_fw_dec_bt_pwr( + struct ieee80211_hw *hw, bool b_dec_bt_pwr) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[1] ={0}; + + h2c_parameter[0] = 0; + + if (b_dec_bt_pwr) { + h2c_parameter[0] |= BIT(1); + rtlpcipriv->btcoexist.b_fw_coexist_all_off = false; + } + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], decrease Bt Power : %s, write 0x21=0x%x\n", + (b_dec_bt_pwr? "Yes!!":"No!!"), h2c_parameter[0])); + + rtl8821ae_fill_h2c_cmd(hw, 0x21, 1, h2c_parameter); +} + + +void rtl8821ae_dm_bt_set_fw_2_ant_hid(struct ieee80211_hw *hw, + bool b_enable, bool b_dac_swing_on) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[1] ={0}; + + if (b_enable) { + h2c_parameter[0] |= BIT(0); + rtlpcipriv->btcoexist.b_fw_coexist_all_off = false; + } + if (b_dac_swing_on) { + h2c_parameter[0] |= BIT(1); /* Dac Swing default enable */ + } + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], turn 2-Ant+HID mode %s, DACSwing:%s, write 0x15=0x%x\n", + (b_enable ? "ON!!":"OFF!!"), (b_dac_swing_on ? "ON":"OFF"), + h2c_parameter[0])); + + rtl8821ae_fill_h2c_cmd(hw, 0x15, 1, h2c_parameter); +} + +void rtl8821ae_dm_bt_set_fw_tdma_ctrl(struct ieee80211_hw *hw, + bool b_enable, u8 ant_num, u8 nav_en, u8 dac_swing_en) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 h2c_parameter[1] ={0}; + u8 h2c_parameter1[1] = {0}; + + h2c_parameter[0] = 0; + h2c_parameter1[0] = 0; + + if(b_enable) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], set BT PTA update manager to trigger update!!\n")); + h2c_parameter1[0] |= BIT(0); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], turn TDMA mode ON!!\n")); + h2c_parameter[0] |= BIT(0); /* function enable */ + if (TDMA_1ANT == ant_num) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TDMA_1ANT\n")); + h2c_parameter[0] |= BIT(1); + } else if(TDMA_2ANT == ant_num) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TDMA_2ANT\n")); + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], Unknown Ant\n")); + } + + if (TDMA_NAV_OFF == nav_en) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TDMA_NAV_OFF\n")); + } else if (TDMA_NAV_ON == nav_en) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TDMA_NAV_ON\n")); + h2c_parameter[0] |= BIT(2); + } + + if (TDMA_DAC_SWING_OFF == dac_swing_en) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], TDMA_DAC_SWING_OFF\n")); + } else if(TDMA_DAC_SWING_ON == dac_swing_en) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], TDMA_DAC_SWING_ON\n")); + h2c_parameter[0] |= BIT(4); + } + rtlpcipriv->btcoexist.b_fw_coexist_all_off = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], set BT PTA update manager to no update!!\n")); + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], turn TDMA mode OFF!!\n")); + } + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], FW2AntTDMA, write 0x26=0x%x\n", h2c_parameter1[0])); + rtl8821ae_fill_h2c_cmd(hw, 0x26, 1, h2c_parameter1); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], FW2AntTDMA, write 0x14=0x%x\n", h2c_parameter[0])); + rtl8821ae_fill_h2c_cmd(hw, 0x14, 1, h2c_parameter); + + if (!b_enable) { + /* delay_ms(2); + * PlatformEFIOWrite1Byte(Adapter, 0x778, 0x1); */ + } +} + + +void rtl8821ae_dm_bt_set_fw_ignore_wlan_act( struct ieee80211_hw *hw, bool b_enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 h2c_parameter[1] ={0}; + + if (b_enable) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], BT Ignore Wlan_Act !!\n")); + h2c_parameter[0] |= BIT(0); // function enable + rtlpcipriv->btcoexist.b_fw_coexist_all_off = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], BT don't ignore Wlan_Act !!\n")); + } + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], set FW for BT Ignore Wlan_Act, write 0x25=0x%x\n", + h2c_parameter[0])); + + rtl8821ae_fill_h2c_cmd(hw, 0x25, 1, h2c_parameter); +} + + +void rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(struct ieee80211_hw *hw, + bool b_enable, u8 ant_num, u8 nav_en + ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + //struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 h2c_parameter[2] ={0}; + + + if (b_enable) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], turn TTDMA mode ON!!\n")); + h2c_parameter[0] |= BIT(0); // function enable + if (TDMA_1ANT == ant_num) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TTDMA_1ANT\n")); + h2c_parameter[0] |= BIT(1); + } else if (TDMA_2ANT == ant_num) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TTDMA_2ANT\n")); + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], Unknown Ant\n")); + } + + if (TDMA_NAV_OFF == nav_en) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TTDMA_NAV_OFF\n")); + } else if (TDMA_NAV_ON == nav_en) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], TTDMA_NAV_ON\n")); + h2c_parameter[1] |= BIT(0); + } + + rtlpcipriv->btcoexist.b_fw_coexist_all_off = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], turn TTDMA mode OFF!!\n")); + } + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], FW Traditional TDMA, write 0x33=0x%x\n", + h2c_parameter[0] << 8| h2c_parameter[1])); + + rtl8821ae_fill_h2c_cmd(hw, 0x33, 2, h2c_parameter); +} + + +void rtl8821ae_dm_bt_set_fw_dac_swing_level(struct ieee80211_hw *hw, + u8 dac_swing_lvl) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[1] ={0}; + h2c_parameter[0] = dac_swing_lvl; + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl)); + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], write 0x29=0x%x\n", h2c_parameter[0])); + + rtl8821ae_fill_h2c_cmd(hw, 0x29, 1, h2c_parameter); +} + +void rtl8821ae_dm_bt_set_fw_bt_hid_info(struct ieee80211_hw *hw, bool b_enable) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[1] ={0}; + h2c_parameter[0] = 0; + + if(b_enable){ + h2c_parameter[0] |= BIT(0); + rtlpcipriv->btcoexist.b_fw_coexist_all_off = false; + } + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], Set BT HID information=0x%x\n", b_enable)); + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], write 0x24=0x%x\n", h2c_parameter[0])); + + rtl8821ae_fill_h2c_cmd(hw, 0x24, 1, h2c_parameter); +} + +void rtl8821ae_dm_bt_set_fw_bt_retry_index(struct ieee80211_hw *hw, + u8 retry_index) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[1] ={0}; + h2c_parameter[0] = retry_index; + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], Set BT Retry Index=%d\n", retry_index)); + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], write 0x23=0x%x\n", h2c_parameter[0])); + + rtl8821ae_fill_h2c_cmd(hw, 0x23, 1, h2c_parameter); +} + +void rtl8821ae_dm_bt_set_fw_wlan_act(struct ieee80211_hw *hw, + u8 wlan_act_hi, u8 wlan_act_lo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter_hi[1] ={0}; + u8 h2c_parameter_lo[1] ={0}; + h2c_parameter_hi[0] = wlan_act_hi; + h2c_parameter_lo[0] = wlan_act_lo; + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], Set WLAN_ACT Hi:Lo=0x%x/0x%x\n", wlan_act_hi, wlan_act_lo)); + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], write 0x22=0x%x\n", h2c_parameter_hi[0])); + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], write 0x11=0x%x\n", h2c_parameter_lo[0])); + + /* WLAN_ACT = High duration, unit:ms */ + rtl8821ae_fill_h2c_cmd(hw, 0x22, 1, h2c_parameter_hi); + /* WLAN_ACT = Low duration, unit:3*625us */ + rtl8821ae_fill_h2c_cmd(hw, 0x11, 1, h2c_parameter_lo); +} + +void rtl8821ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, struct btdm_8821ae *p_btdm) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct btdm_8821ae *p_btdm_8821ae = &hal_coex_8821ae.btdm; + u8 i; + + bool b_fw_current_inpsmode = false; + bool b_fw_ps_awake = true; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&b_fw_current_inpsmode)); + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, + (u8 *) (&b_fw_ps_awake)); + + // check new setting is different with the old one, + // if all the same, don't do the setting again. + if (memcmp(p_btdm_8821ae, p_btdm, sizeof(struct btdm_8821ae)) == 0) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], the same coexist setting, return!!\n")); + return; + } else { //save the new coexist setting + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], UPDATE TO NEW COEX SETTING!!\n")); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bAllOff=0x%x/ 0x%x \n", + p_btdm_8821ae->b_all_off, p_btdm->b_all_off)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new b_agc_table_en=0x%x/ 0x%x \n", + p_btdm_8821ae->b_agc_table_en, p_btdm->b_agc_table_en)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new b_adc_back_off_on=0x%x/ 0x%x \n", + p_btdm_8821ae->b_adc_back_off_on, p_btdm->b_adc_back_off_on)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new b2_ant_hid_en=0x%x/ 0x%x \n", + p_btdm_8821ae->b2_ant_hid_en, p_btdm->b2_ant_hid_en)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bLowPenaltyRateAdaptive=0x%x/ 0x%x \n", + p_btdm_8821ae->b_low_penalty_rate_adaptive, + p_btdm->b_low_penalty_rate_adaptive)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bRfRxLpfShrink=0x%x/ 0x%x \n", + p_btdm_8821ae->b_rf_rx_lpf_shrink, p_btdm->b_rf_rx_lpf_shrink)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bRejectAggrePkt=0x%x/ 0x%x \n", + p_btdm_8821ae->b_reject_aggre_pkt, p_btdm->b_reject_aggre_pkt)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new b_tdma_on=0x%x/ 0x%x \n", + p_btdm_8821ae->b_tdma_on, p_btdm->b_tdma_on)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new tdmaAnt=0x%x/ 0x%x \n", + p_btdm_8821ae->tdma_ant, p_btdm->tdma_ant)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new tdmaNav=0x%x/ 0x%x \n", + p_btdm_8821ae->tdma_nav, p_btdm->tdma_nav)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new tdma_dac_swing=0x%x/ 0x%x \n", + p_btdm_8821ae->tdma_dac_swing, p_btdm->tdma_dac_swing)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new fw_dac_swing_lvl=0x%x/ 0x%x \n", + p_btdm_8821ae->fw_dac_swing_lvl, p_btdm->fw_dac_swing_lvl)); + + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bTraTdmaOn=0x%x/ 0x%x \n", + p_btdm_8821ae->b_tra_tdma_on, p_btdm->b_tra_tdma_on)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new traTdmaAnt=0x%x/ 0x%x \n", + p_btdm_8821ae->tra_tdma_ant, p_btdm->tra_tdma_ant)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new traTdmaNav=0x%x/ 0x%x \n", + p_btdm_8821ae->tra_tdma_nav, p_btdm->tra_tdma_nav)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bPsTdmaOn=0x%x/ 0x%x \n", + p_btdm_8821ae->b_ps_tdma_on, p_btdm->b_ps_tdma_on)); + for(i=0; i<5; i++) + { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new psTdmaByte[i]=0x%x/ 0x%x \n", + p_btdm_8821ae->ps_tdma_byte[i], p_btdm->ps_tdma_byte[i])); + } + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bIgnoreWlanAct=0x%x/ 0x%x \n", + p_btdm_8821ae->b_ignore_wlan_act, p_btdm->b_ignore_wlan_act)); + + + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new bPtaOn=0x%x/ 0x%x \n", + p_btdm_8821ae->b_pta_on, p_btdm->b_pta_on)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new val_0x6c0=0x%x/ 0x%x \n", + p_btdm_8821ae->val_0x6c0, p_btdm->val_0x6c0)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new val_0x6c8=0x%x/ 0x%x \n", + p_btdm_8821ae->val_0x6c8, p_btdm->val_0x6c8)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new val_0x6cc=0x%x/ 0x%x \n", + p_btdm_8821ae->val_0x6cc, p_btdm->val_0x6cc)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new b_sw_dac_swing_on=0x%x/ 0x%x \n", + p_btdm_8821ae->b_sw_dac_swing_on, p_btdm->b_sw_dac_swing_on)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new sw_dac_swing_lvl=0x%x/ 0x%x \n", + p_btdm_8821ae->sw_dac_swing_lvl, p_btdm->sw_dac_swing_lvl)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new wlanActHi=0x%x/ 0x%x \n", + p_btdm_8821ae->wlan_act_hi, p_btdm->wlan_act_hi)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new wlanActLo=0x%x/ 0x%x \n", + p_btdm_8821ae->wlan_act_lo, p_btdm->wlan_act_lo)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], original/new btRetryIndex=0x%x/ 0x%x \n", + p_btdm_8821ae->bt_retry_index, p_btdm->bt_retry_index)); + + memcpy(p_btdm_8821ae, p_btdm, sizeof(struct btdm_8821ae)); + } + /* + * Here we only consider when Bt Operation + * inquiry/paging/pairing is ON + * we only need to turn off TDMA */ + + if (rtlpcipriv->btcoexist.b_hold_for_bt_operation) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], set to ignore wlanAct for BT OP!!\n")); + rtl8821ae_dm_bt_set_fw_ignore_wlan_act(hw, true); + return; + } + + if (p_btdm->b_all_off) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex], disable all coexist mechanism !!\n")); + rtl8821ae_btdm_coex_all_off(hw); + return; + } + + rtl8821ae_dm_bt_reject_ap_aggregated_packet(hw, p_btdm->b_reject_aggre_pkt); + + if(p_btdm->b_low_penalty_rate_adaptive) + rtl8821ae_dm_bt_set_sw_penalty_tx_rate_adaptive(hw, + BT_TX_RATE_ADAPTIVE_LOW_PENALTY); + else + rtl8821ae_dm_bt_set_sw_penalty_tx_rate_adaptive(hw, + BT_TX_RATE_ADAPTIVE_NORMAL); + + if(p_btdm->b_rf_rx_lpf_shrink) + rtl8821ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, BT_RF_RX_LPF_CORNER_SHRINK); + else + rtl8821ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, BT_RF_RX_LPF_CORNER_RESUME); + + if(p_btdm->b_agc_table_en) + rtl8821ae_dm_bt_agc_table(hw, BT_AGCTABLE_ON); + else + rtl8821ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF); + + if(p_btdm->b_adc_back_off_on) + rtl8821ae_dm_bt_bb_back_off_level(hw, BT_BB_BACKOFF_ON); + else + rtl8821ae_dm_bt_bb_back_off_level(hw, BT_BB_BACKOFF_OFF); + + rtl8821ae_dm_bt_set_fw_bt_retry_index(hw, p_btdm->bt_retry_index); + + rtl8821ae_dm_bt_set_fw_dac_swing_level(hw, p_btdm->fw_dac_swing_lvl); + rtl8821ae_dm_bt_set_fw_wlan_act(hw, p_btdm->wlan_act_hi, p_btdm->wlan_act_lo); + + rtl8821ae_dm_bt_set_coex_table(hw, p_btdm->val_0x6c0, + p_btdm->val_0x6c8, p_btdm->val_0x6cc); + rtl8821ae_dm_bt_set_hw_pta_mode(hw, p_btdm->b_pta_on); + + /* + * Note: There is a constraint between TDMA and 2AntHID + * Only one of 2AntHid and tdma can be turn on + * We should turn off those mechanisms should be turned off first + * and then turn on those mechanisms should be turned on. + */ +#if 1 + if(p_btdm->b2_ant_hid_en) { + // turn off tdma + rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(hw, p_btdm->b_tra_tdma_on, + p_btdm->tra_tdma_ant, p_btdm->tra_tdma_nav); + rtl8821ae_dm_bt_set_fw_tdma_ctrl(hw, false, p_btdm->tdma_ant, + p_btdm->tdma_nav, p_btdm->tdma_dac_swing); + + // turn off Pstdma + rtl8821ae_dm_bt_set_fw_ignore_wlan_act(hw, p_btdm->b_ignore_wlan_act); + rtl8821ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); // Antenna control by PTA, 0x870 = 0x300. + + // turn on 2AntHid + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, true); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, true, true); + } else if(p_btdm->b_tdma_on) { + // turn off 2AntHid + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, false); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + + // turn off pstdma + rtl8821ae_dm_bt_set_fw_ignore_wlan_act(hw, p_btdm->b_ignore_wlan_act); + rtl8821ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); // Antenna control by PTA, 0x870 = 0x300. + + // turn on tdma + rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(hw, p_btdm->b_tra_tdma_on, p_btdm->tra_tdma_ant, p_btdm->tra_tdma_nav); + rtl8821ae_dm_bt_set_fw_tdma_ctrl(hw, true, p_btdm->tdma_ant, p_btdm->tdma_nav, p_btdm->tdma_dac_swing); + } else if(p_btdm->b_ps_tdma_on) { + // turn off 2AntHid + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, false); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + + // turn off tdma + rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(hw, p_btdm->b_tra_tdma_on, p_btdm->tra_tdma_ant, p_btdm->tra_tdma_nav); + rtl8821ae_dm_bt_set_fw_tdma_ctrl(hw, false, p_btdm->tdma_ant, p_btdm->tdma_nav, p_btdm->tdma_dac_swing); + + // turn on pstdma + rtl8821ae_dm_bt_set_fw_ignore_wlan_act(hw, p_btdm->b_ignore_wlan_act); + rtl8821ae_dm_bt_set_fw_3a(hw, + p_btdm->ps_tdma_byte[0], + p_btdm->ps_tdma_byte[1], + p_btdm->ps_tdma_byte[2], + p_btdm->ps_tdma_byte[3], + p_btdm->ps_tdma_byte[4]); + } else { + // turn off 2AntHid + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, false); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + + // turn off tdma + rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(hw, p_btdm->b_tra_tdma_on, p_btdm->tra_tdma_ant, p_btdm->tra_tdma_nav); + rtl8821ae_dm_bt_set_fw_tdma_ctrl(hw, false, p_btdm->tdma_ant, p_btdm->tdma_nav, p_btdm->tdma_dac_swing); + + // turn off pstdma + rtl8821ae_dm_bt_set_fw_ignore_wlan_act(hw, p_btdm->b_ignore_wlan_act); + rtl8821ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); // Antenna control by PTA, 0x870 = 0x300. + } +#else + if (p_btdm->b_tdma_on) { + if(p_btdm->b_ps_tdma_on) { + } else { + rtl8821ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); + } + /* Turn off 2AntHID first then turn tdma ON */ + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, false); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(hw, p_btdm->b_tra_tdma_on, p_btdm->tra_tdma_ant, p_btdm->tra_tdma_nav); + rtl8821ae_dm_bt_set_fw_tdma_ctrl(hw, true, + p_btdm->tdma_ant, p_btdm->tdma_nav, p_btdm->tdma_dac_swing); + } else { + /* Turn off tdma first then turn 2AntHID ON if need */ + rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(hw, p_btdm->b_tra_tdma_on, p_btdm->tra_tdma_ant, p_btdm->tra_tdma_nav); + rtl8821ae_dm_bt_set_fw_tdma_ctrl(hw, false, p_btdm->tdma_ant, + p_btdm->tdma_nav, p_btdm->tdma_dac_swing); + if (p_btdm->b2_ant_hid_en) { + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, true); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, true, true); + } else { + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, false); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + } + if(p_btdm->b_ps_tdma_on) { + rtl8821ae_dm_bt_set_fw_3a(hw, p_btdm->ps_tdma_byte[0], p_btdm->ps_tdma_byte[1], + p_btdm->ps_tdma_byte[2], p_btdm->ps_tdma_byte[3], p_btdm->ps_tdma_byte[4]); + } else { + rtl8821ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); + } + } +#endif + + /* + * Note: + * We should add delay for making sure sw DacSwing can be set sucessfully. + * because of that rtl8821ae_dm_bt_set_fw_2_ant_hid() and rtl8821ae_dm_bt_set_fw_tdma_ctrl() + * will overwrite the reg 0x880. + */ + mdelay(30); + rtl8821ae_dm_bt_set_sw_full_time_dac_swing(hw, + p_btdm->b_sw_dac_swing_on, p_btdm->sw_dac_swing_lvl); + rtl8821ae_dm_bt_set_fw_dec_bt_pwr(hw, p_btdm->b_dec_bt_pwr); +} + +void rtl8821ae_dm_bt_bt_state_update_2_ant_hid(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], HID busy!!\n")); + rtlpcipriv->btcoexist.b_bt_busy = true; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_BT_IDLE; +} + +void rtl8821ae_dm_bt_bt_state_update_2_ant_pan(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + bool b_idle = false; + + if (hal_coex_8821ae.low_priority_tx >= + hal_coex_8821ae.low_priority_rx) { + if((hal_coex_8821ae.low_priority_tx/ + hal_coex_8821ae.low_priority_rx) > 10) { + b_idle = true; + } + } else { + if((hal_coex_8821ae.low_priority_rx/ + hal_coex_8821ae.low_priority_tx) > 10) { + b_idle = true; + } + } + + if(!b_idle) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], PAN busy!!\n")); + rtlpcipriv->btcoexist.b_bt_busy = true; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_BT_IDLE; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], PAN idle!!\n")); + } +} + +void rtl8821ae_dm_bt_2_ant_sco_action(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct btdm_8821ae btdm8821ae; + u8 bt_rssi_state; + + rtl8821ae_dm_bt_btdm_structure_reload(hw, &btdm8821ae); + btdm8821ae.b_rf_rx_lpf_shrink = true; + btdm8821ae.b_low_penalty_rate_adaptive = true; + btdm8821ae.b_reject_aggre_pkt = false; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT40\n")); + /* coex table */ + btdm8821ae.val_0x6c0 = 0x5a5aaaaa; + btdm8821ae.val_0x6c8 = 0xcc; + btdm8821ae.val_0x6cc = 0x3; + /* sw mechanism */ + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + /* fw mechanism */ + btdm8821ae.b_tdma_on = false; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_OFF; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT20 or Legacy\n")); + bt_rssi_state + = rtl8821ae_dm_bt_check_coex_rssi_state(hw, 2, BT_FW_COEX_THRESH_47, 0); + + /* coex table */ + btdm8821ae.val_0x6c0 = 0x5a5aaaaa; + btdm8821ae.val_0x6c8 = 0xcc; + btdm8821ae.val_0x6cc = 0x3; + /* sw mechanism */ + if ((bt_rssi_state == BT_RSSI_STATE_HIGH) || + (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH) ) { + btdm8821ae.b_agc_table_en = true; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + } else { + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + } + /* fw mechanism */ + btdm8821ae.b_tdma_on = false; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_OFF; + } + + if (rtl8821ae_dm_bt_need_to_dec_bt_pwr(hw)) { + btdm8821ae.b_dec_bt_pwr = true; + } + + if(rtl8821ae_dm_bt_is_coexist_state_changed(hw)) + rtl8821ae_dm_bt_set_bt_dm(hw, &btdm8821ae); +} + +void rtl8821ae_dm_bt_2_ant_hid_action(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct btdm_8821ae btdm8821ae; + u8 bt_rssi_state; + + rtl8821ae_dm_bt_btdm_structure_reload(hw, &btdm8821ae); + + btdm8821ae.b_rf_rx_lpf_shrink = true; + btdm8821ae.b_low_penalty_rate_adaptive = true; + btdm8821ae.b_reject_aggre_pkt = false; + + // coex table + btdm8821ae.val_0x6c0 = 0x55555555; + btdm8821ae.val_0x6c8 = 0xffff; + btdm8821ae.val_0x6cc = 0x3; + btdm8821ae.b_ignore_wlan_act = true; + + if(rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT40\n")); + // sw mechanism + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + + // fw mechanism + btdm8821ae.b_ps_tdma_on = true; + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x0; + btdm8821ae.ps_tdma_byte[4] = 0x80; + + btdm8821ae.b_tra_tdma_on = false; + btdm8821ae.b_tdma_on = false; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_OFF; + btdm8821ae.b2_ant_hid_en = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT20 or Legacy\n")); + bt_rssi_state = + rtl8821ae_dm_bt_check_coex_rssi_state(hw, 2, 47, 0); + + if( (bt_rssi_state == BT_RSSI_STATE_HIGH) || + (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH) ) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi high \n")); + // sw mechanism + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = true; + btdm8821ae.sw_dac_swing_lvl = 0x20; + + // fw mechanism + btdm8821ae.b_ps_tdma_on = false; + btdm8821ae.b_tdma_on = false; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_OFF; + btdm8821ae.b2_ant_hid_en = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi low \n")); + // sw mechanism + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + + // fw mechanism + btdm8821ae.b_ps_tdma_on = false; + btdm8821ae.b_tdma_on = false; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_OFF; + btdm8821ae.b2_ant_hid_en = true; + btdm8821ae.fw_dac_swing_lvl = 0x20; + } + } + + if (rtl8821ae_dm_bt_need_to_dec_bt_pwr(hw)) { + btdm8821ae.b_dec_bt_pwr = true; + } + + if (rtl8821ae_dm_bt_is_coexist_state_changed(hw)) { + rtl8821ae_dm_bt_set_bt_dm(hw, &btdm8821ae); + } +} + + +void rtl8821ae_dm_bt_2_ant_2_dp_action_no_profile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct btdm_8821ae btdm8821ae; + u8 bt_rssi_state; + + rtl8821ae_dm_bt_btdm_structure_reload(hw, &btdm8821ae); + + btdm8821ae.b_rf_rx_lpf_shrink = true; + btdm8821ae.b_low_penalty_rate_adaptive = true; + btdm8821ae.b_reject_aggre_pkt = false; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("HT40\n")); + if (rtl8821ae_dm_bt_is_wifi_up_link(hw)) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi Uplink\n")); + /* coex table */ + btdm8821ae.val_0x6c0 = 0x5a5a5a5a; + btdm8821ae.val_0x6c8 = 0xcccc; + btdm8821ae.val_0x6cc = 0x3; + // sw mechanism + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + // fw mechanism + btdm8821ae.b_tra_tdma_on = true; + btdm8821ae.b_tdma_on = true; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_ON; + btdm8821ae.b2_ant_hid_en = false; + //btSpec = BTHCI_GetBTCoreSpecByProf(Adapter, BT_PROFILE_A2DP); + //if(btSpec >= BT_SPEC_2_1_EDR) + { + btdm8821ae.wlan_act_hi = 0x10; + btdm8821ae.wlan_act_lo = 0x10; + } + //else + //{ + //btdm8821ae.wlanActHi = 0x20; + //btdm8821ae.wlanActLo = 0x20; + //} + btdm8821ae.bt_retry_index = 2; + btdm8821ae.fw_dac_swing_lvl = 0x18; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi Downlink\n")); + // coex table + btdm8821ae.val_0x6c0 = 0x5a5a5a5a; + btdm8821ae.val_0x6c8 = 0xcc; + btdm8821ae.val_0x6cc = 0x3; + // sw mechanism + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + // fw mechanism + btdm8821ae.b_tra_tdma_on = true; + btdm8821ae.b_tdma_on = true; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_ON; + btdm8821ae.b2_ant_hid_en = false; + //btSpec = BTHCI_GetBTCoreSpecByProf(Adapter, BT_PROFILE_A2DP); + //if(btSpec >= BT_SPEC_2_1_EDR) + { + btdm8821ae.wlan_act_hi = 0x10; + btdm8821ae.wlan_act_lo = 0x10; + } + //else + //{ + // btdm8821ae.wlanActHi = 0x20; + // btdm8821ae.wlanActLo = 0x20; + //} + btdm8821ae.bt_retry_index = 2; + btdm8821ae.fw_dac_swing_lvl = 0x40; + } + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("HT20 or Legacy\n")); + bt_rssi_state = rtl8821ae_dm_bt_check_coex_rssi_state(hw, 2, BT_FW_COEX_THRESH_47, 0); + + if(rtl8821ae_dm_bt_is_wifi_up_link(hw)) + { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi Uplink\n")); + // coex table + btdm8821ae.val_0x6c0 = 0x5a5a5a5a; + btdm8821ae.val_0x6c8 = 0xcccc; + btdm8821ae.val_0x6cc = 0x3; + // sw mechanism + if( (bt_rssi_state == BT_RSSI_STATE_HIGH) || + (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH) ) + { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi rssi high \n")); + btdm8821ae.b_agc_table_en = true; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi rssi low \n")); + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + } + // fw mechanism + btdm8821ae.b_tra_tdma_on = true; + btdm8821ae.b_tdma_on = true; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_ON; + btdm8821ae.b2_ant_hid_en = false; + //btSpec = BTHCI_GetBTCoreSpecByProf(Adapter, BT_PROFILE_A2DP); + //if(btSpec >= BT_SPEC_2_1_EDR) + { + btdm8821ae.wlan_act_hi = 0x10; + btdm8821ae.wlan_act_lo = 0x10; + } + //else + //{ + //btdm8821ae.wlanActHi = 0x20; + //btdm8821ae.wlanActLo = 0x20; + //} + btdm8821ae.bt_retry_index = 2; + btdm8821ae.fw_dac_swing_lvl = 0x18; + } + else + { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi Downlink\n")); + // coex table + btdm8821ae.val_0x6c0 = 0x5a5a5a5a; + btdm8821ae.val_0x6c8 = 0xcc; + btdm8821ae.val_0x6cc = 0x3; + // sw mechanism + if( (bt_rssi_state == BT_RSSI_STATE_HIGH) || + (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH) ) + { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi rssi high \n")); + btdm8821ae.b_agc_table_en = true; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + } + else + { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("Wifi rssi low \n")); + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + } + // fw mechanism + btdm8821ae.b_tra_tdma_on = true; + btdm8821ae.b_tdma_on = true; + btdm8821ae.tdma_dac_swing = TDMA_DAC_SWING_ON; + btdm8821ae.b2_ant_hid_en = false; + //btSpec = BTHCI_GetBTCoreSpecByProf(Adapter, BT_PROFILE_A2DP); + //if(btSpec >= BT_SPEC_2_1_EDR) + { + btdm8821ae.wlan_act_hi = 0x10; + btdm8821ae.wlan_act_lo = 0x10; + } + //else + //{ + //btdm8821ae.wlanActHi = 0x20; + //btdm8821ae.wlanActLo = 0x20; + //} + btdm8821ae.bt_retry_index = 2; + btdm8821ae.fw_dac_swing_lvl = 0x40; + } + } + + if (rtl8821ae_dm_bt_need_to_dec_bt_pwr(hw)) { + btdm8821ae.b_dec_bt_pwr = true; + } + + if (rtl8821ae_dm_bt_is_coexist_state_changed(hw)) { + rtl8821ae_dm_bt_set_bt_dm(hw, &btdm8821ae); + } +} + + +//============================================================ +// extern function start with BTDM_ +//============================================================ +u32 rtl8821ae_dm_bt_tx_rx_couter_h(struct ieee80211_hw *hw) +{ + u32 counters=0; + + counters = hal_coex_8821ae.high_priority_tx + hal_coex_8821ae.high_priority_rx ; + return counters; +} + +u32 rtl8821ae_dm_bt_tx_rx_couter_l(struct ieee80211_hw *hw) +{ + u32 counters=0; + + counters = hal_coex_8821ae.low_priority_tx + hal_coex_8821ae.low_priority_rx ; + return counters; +} + +u8 rtl8821ae_dm_bt_bt_tx_rx_counter_level(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u32 bt_tx_rx_cnt = 0; + u8 bt_tx_rx_cnt_lvl = 0; + + bt_tx_rx_cnt = rtl8821ae_dm_bt_tx_rx_couter_h(hw) + + rtl8821ae_dm_bt_tx_rx_couter_l(hw); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt)); + + rtlpcipriv->btcoexist.current_state_h &= ~\ + (BT_COEX_STATE_BT_CNT_LEVEL_0 | BT_COEX_STATE_BT_CNT_LEVEL_1| + BT_COEX_STATE_BT_CNT_LEVEL_2); + + if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_3) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT TxRx Counters at level 3\n")); + bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_3; + rtlpcipriv->btcoexist.current_state_h |= BT_COEX_STATE_BT_CNT_LEVEL_3; + } else if(bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT TxRx Counters at level 2\n")); + bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_2; + rtlpcipriv->btcoexist.current_state_h |= BT_COEX_STATE_BT_CNT_LEVEL_2; + } else if(bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT TxRx Counters at level 1\n")); + bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_1; + rtlpcipriv->btcoexist.current_state_h |= BT_COEX_STATE_BT_CNT_LEVEL_1; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT TxRx Counters at level 0\n")); + bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_0; + rtlpcipriv->btcoexist.current_state_h |= BT_COEX_STATE_BT_CNT_LEVEL_0; + } + return bt_tx_rx_cnt_lvl; +} + + +void rtl8821ae_dm_bt_2_ant_hid_sco_esco(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct btdm_8821ae btdm8821ae; + + u8 bt_rssi_state, bt_rssi_state1; + u8 bt_tx_rx_cnt_lvl = 0; + + rtl8821ae_dm_bt_btdm_structure_reload(hw, &btdm8821ae); + + + btdm8821ae.b_rf_rx_lpf_shrink = true; + btdm8821ae.b_low_penalty_rate_adaptive = true; + btdm8821ae.b_reject_aggre_pkt = false; + + bt_tx_rx_cnt_lvl = rtl8821ae_dm_bt_bt_tx_rx_counter_level(hw); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl)); + + if(rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) + { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT40\n")); + // coex table + btdm8821ae.val_0x6c0 = 0x55555555; + btdm8821ae.val_0x6c8 = 0xffff; + btdm8821ae.val_0x6cc = 0x3; + + // sw mechanism + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + + // fw mechanism + btdm8821ae.b_ps_tdma_on = true; + if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x2; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1200 && < 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xa; + btdm8821ae.ps_tdma_byte[2] = 0xa; + btdm8821ae.ps_tdma_byte[3] = 0x2; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters < 1200\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x2; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT20 or Legacy\n")); + bt_rssi_state = rtl8821ae_dm_bt_check_coex_rssi_state(hw, 2, 47, 0); + bt_rssi_state1 = rtl8821ae_dm_bt_check_coex_rssi_state1(hw, 2, 27, 0); + + // coex table + btdm8821ae.val_0x6c0 = 0x55555555; + btdm8821ae.val_0x6c8 = 0xffff; + btdm8821ae.val_0x6cc = 0x3; + + // sw mechanism + if( (bt_rssi_state == BT_RSSI_STATE_HIGH) || + (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH) ) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi high \n")); + btdm8821ae.b_agc_table_en = true; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi low \n")); + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + } + + // fw mechanism + btdm8821ae.b_ps_tdma_on = true; + if( (bt_rssi_state1 == BT_RSSI_STATE_HIGH) || + (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH) ) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG,("Wifi rssi-1 high \n")); + // only rssi high we need to do this, + // when rssi low, the value will modified by fw + rtl_write_byte(rtlpriv, 0x883, 0x40); + if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x83; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1200 && < 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xa; + btdm8821ae.ps_tdma_byte[2] = 0xa; + btdm8821ae.ps_tdma_byte[3] = 0x83; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters < 1200\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x83; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi-1 low \n")); + if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) + { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x2; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1200 && < 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xa; + btdm8821ae.ps_tdma_byte[2] = 0xa; + btdm8821ae.ps_tdma_byte[3] = 0x2; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters < 1200\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x2; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + } + } + + if (rtl8821ae_dm_bt_need_to_dec_bt_pwr(hw)) { + btdm8821ae.b_dec_bt_pwr = true; + } + + // Always ignore WlanAct if bHid|bSCOBusy|bSCOeSCO + + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n", + hal_coex_8821ae.bt_inq_page_start_time, bt_tx_rx_cnt_lvl)); + if( (hal_coex_8821ae.bt_inq_page_start_time) || + (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl) ) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], Set BT inquiry / page scan 0x3a setting\n")); + btdm8821ae.b_ps_tdma_on = true; + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x2; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + + if(rtl8821ae_dm_bt_is_coexist_state_changed(hw)) { + rtl8821ae_dm_bt_set_bt_dm(hw, &btdm8821ae); + } +} + +void rtl8821ae_dm_bt_2_ant_ftp_a2dp(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct btdm_8821ae btdm8821ae; + + u8 bt_rssi_state, bt_rssi_state1; + u32 bt_tx_rx_cnt_lvl = 0; + + rtl8821ae_dm_bt_btdm_structure_reload(hw, &btdm8821ae); + + btdm8821ae.b_rf_rx_lpf_shrink = true; + btdm8821ae.b_low_penalty_rate_adaptive = true; + btdm8821ae.b_reject_aggre_pkt = false; + + bt_tx_rx_cnt_lvl = rtl8821ae_dm_bt_bt_tx_rx_counter_level(hw); + + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl)); + + if(rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) + { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT40\n")); + bt_rssi_state = rtl8821ae_dm_bt_check_coex_rssi_state(hw, 2, 37, 0); + + // coex table + btdm8821ae.val_0x6c0 = 0x55555555; + btdm8821ae.val_0x6c8 = 0xffff; + btdm8821ae.val_0x6cc = 0x3; + + // sw mechanism + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + + // fw mechanism + btdm8821ae.b_ps_tdma_on = true; + if ((bt_rssi_state == BT_RSSI_STATE_HIGH) || + (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH) ) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi high \n")); + if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x81; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1200 && < 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xa; + btdm8821ae.ps_tdma_byte[2] = 0xa; + btdm8821ae.ps_tdma_byte[3] = 0x81; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters < 1200\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x81; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi low \n")); + if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x0; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1200 && < 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xa; + btdm8821ae.ps_tdma_byte[2] = 0xa; + btdm8821ae.ps_tdma_byte[3] = 0x0; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters < 1200\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x0; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + } + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("HT20 or Legacy\n")); + bt_rssi_state = rtl8821ae_dm_bt_check_coex_rssi_state(hw, 2, 47, 0); + bt_rssi_state1 = rtl8821ae_dm_bt_check_coex_rssi_state1(hw, 2, 27, 0); + + // coex table + btdm8821ae.val_0x6c0 = 0x55555555; + btdm8821ae.val_0x6c8 = 0xffff; + btdm8821ae.val_0x6cc = 0x3; + + // sw mechanism + if( (bt_rssi_state == BT_RSSI_STATE_HIGH) || + (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH) ) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi high \n")); + btdm8821ae.b_agc_table_en = true; + btdm8821ae.b_adc_back_off_on = true; + btdm8821ae.b_sw_dac_swing_on = false; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi low \n")); + btdm8821ae.b_agc_table_en = false; + btdm8821ae.b_adc_back_off_on = false; + btdm8821ae.b_sw_dac_swing_on = false; + } + + // fw mechanism + btdm8821ae.b_ps_tdma_on = true; + if( (bt_rssi_state1 == BT_RSSI_STATE_HIGH) || + (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH) ) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi-1 high \n")); + // only rssi high we need to do this, + // when rssi low, the value will modified by fw + rtl_write_byte(rtlpriv, 0x883, 0x40); + if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x81; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1200 && < 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xa; + btdm8821ae.ps_tdma_byte[2] = 0xa; + btdm8821ae.ps_tdma_byte[3] = 0x81; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters < 1200\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x81; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Wifi rssi-1 low \n")); + if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x0; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else if(bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters >= 1200 && < 1400\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xa; + btdm8821ae.ps_tdma_byte[2] = 0xa; + btdm8821ae.ps_tdma_byte[3] = 0x0; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT TxRx Counters < 1200\n")); + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0xf; + btdm8821ae.ps_tdma_byte[2] = 0xf; + btdm8821ae.ps_tdma_byte[3] = 0x0; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + } + } + + if(rtl8821ae_dm_bt_need_to_dec_bt_pwr(hw)) { + btdm8821ae.b_dec_bt_pwr = true; + } + + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n", + hal_coex_8821ae.bt_inq_page_start_time, bt_tx_rx_cnt_lvl)); + + if( (hal_coex_8821ae.bt_inq_page_start_time) || + (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl) ) + { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], Set BT inquiry / page scan 0x3a setting\n")); + btdm8821ae.b_ps_tdma_on = true; + btdm8821ae.ps_tdma_byte[0] = 0xa3; + btdm8821ae.ps_tdma_byte[1] = 0x5; + btdm8821ae.ps_tdma_byte[2] = 0x5; + btdm8821ae.ps_tdma_byte[3] = 0x83; + btdm8821ae.ps_tdma_byte[4] = 0x80; + } + + if(rtl8821ae_dm_bt_is_coexist_state_changed(hw)){ + rtl8821ae_dm_bt_set_bt_dm(hw, &btdm8821ae); + } +} + +void rtl8821ae_dm_bt_inq_page_monitor(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 cur_time; + cur_time = jiffies; + if (hal_coex_8821ae.b_c2h_bt_inquiry_page) { + //pHalData->btcoexist.halCoex8821ae.btInquiryPageCnt++; + // bt inquiry or page is started. + if(hal_coex_8821ae.bt_inq_page_start_time == 0){ + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BT_INQ_PAGE; + hal_coex_8821ae.bt_inq_page_start_time = cur_time; + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT Inquiry/page is started at time : 0x%x \n", + hal_coex_8821ae.bt_inq_page_start_time)); + } + } + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], BT Inquiry/page started time : 0x%x, cur_time : 0x%x \n", + hal_coex_8821ae.bt_inq_page_start_time, cur_time)); + + if (hal_coex_8821ae.bt_inq_page_start_time) { + if ((((long)cur_time - (long)hal_coex_8821ae.bt_inq_page_start_time) / HZ) >= 10) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BT Inquiry/page >= 10sec!!!")); + hal_coex_8821ae.bt_inq_page_start_time = 0; + rtlpcipriv->btcoexist.current_state &=~ BT_COEX_STATE_BT_INQ_PAGE; + } + } + +#if 0 + if (hal_coex_8821ae.b_c2h_bt_inquiry_page) { + hal_coex_8821ae.b_c2h_bt_inquiry_page++; + // bt inquiry or page is started. + } if(hal_coex_8821ae.b_c2h_bt_inquiry_page) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BT_INQ_PAGE; + if(hal_coex_8821ae.bt_inquiry_page_cnt >= 4) + hal_coex_8821ae.bt_inquiry_page_cnt = 0; + hal_coex_8821ae.bt_inquiry_page_cnt++; + } else { + rtlpcipriv->btcoexist.current_state &=~ BT_COEX_STATE_BT_INQ_PAGE; + } +#endif +} + +void rtl8821ae_dm_bt_reset_action_profile_state(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + rtlpcipriv->btcoexist.current_state &= ~\ + (BT_COEX_STATE_PROFILE_HID | BT_COEX_STATE_PROFILE_A2DP| + BT_COEX_STATE_PROFILE_PAN | BT_COEX_STATE_PROFILE_SCO); + + rtlpcipriv->btcoexist.current_state &= ~\ + (BT_COEX_STATE_BTINFO_COMMON | BT_COEX_STATE_BTINFO_B_HID_SCOESCO| + BT_COEX_STATE_BTINFO_B_FTP_A2DP); +} + +void _rtl8821ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 bt_retry_cnt; + u8 bt_info_original; + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex] Get bt info by fw!!\n")); + + _rtl8821ae_dm_bt_check_wifi_state(hw); + + if (hal_coex_8821ae.b_c2h_bt_info_req_sent) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("[BTCoex] c2h for bt_info not rcvd yet!!\n")); + } + + bt_retry_cnt = hal_coex_8821ae.bt_retry_cnt; + bt_info_original = hal_coex_8821ae.c2h_bt_info_original; + + // when bt inquiry or page scan, we have to set h2c 0x25 + // ignore wlanact for continuous 4x2secs + rtl8821ae_dm_bt_inq_page_monitor(hw); + rtl8821ae_dm_bt_reset_action_profile_state(hw); + + if(rtl8821ae_dm_bt_is_2_ant_common_action(hw)) { + rtlpcipriv->btcoexist.bt_profile_case = BT_COEX_MECH_COMMON; + rtlpcipriv->btcoexist.bt_profile_action= BT_COEX_MECH_COMMON; + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("Action 2-Ant common.\n")); + } else { + if( (bt_info_original & BTINFO_B_HID) || + (bt_info_original & BTINFO_B_SCO_BUSY) || + (bt_info_original & BTINFO_B_SCO_ESCO) ) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BTINFO_B_HID_SCOESCO; + rtlpcipriv->btcoexist.bt_profile_case = BT_COEX_MECH_HID_SCO_ESCO; + rtlpcipriv->btcoexist.bt_profile_action = BT_COEX_MECH_HID_SCO_ESCO; + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BTInfo: bHid|bSCOBusy|bSCOeSCO\n")); + rtl8821ae_dm_bt_2_ant_hid_sco_esco(hw); + } else if( (bt_info_original & BTINFO_B_FTP) || + (bt_info_original & BTINFO_B_A2DP) ) { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BTINFO_B_FTP_A2DP; + rtlpcipriv->btcoexist.bt_profile_case = BT_COEX_MECH_FTP_A2DP; + rtlpcipriv->btcoexist.bt_profile_action = BT_COEX_MECH_FTP_A2DP; + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("BTInfo: bFTP|bA2DP\n")); + rtl8821ae_dm_bt_2_ant_ftp_a2dp(hw); + } else { + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BTINFO_B_HID_SCOESCO; + rtlpcipriv->btcoexist.bt_profile_case = BT_COEX_MECH_NONE; + rtlpcipriv->btcoexist.bt_profile_action= BT_COEX_MECH_NONE; + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], BTInfo: undefined case!!!!\n")); + rtl8821ae_dm_bt_2_ant_hid_sco_esco(hw); + } + } +} + +void _rtl8821ae_dm_bt_coexist_1_ant(struct ieee80211_hw *hw) +{ + return; +} + +void rtl8821ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw) +{ + rtl8821ae_dm_bt_set_coex_table(hw, 0x5a5aaaaa, 0xcc, 0x3); + rtl8821ae_dm_bt_set_hw_pta_mode(hw, true); +} + +void rtl8821ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw) +{ + rtl8821ae_dm_bt_set_fw_ignore_wlan_act(hw, false); + rtl8821ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); + rtl8821ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + rtl8821ae_dm_bt_set_fw_tra_tdma_ctrl(hw, false, TDMA_2ANT, TDMA_NAV_OFF); + rtl8821ae_dm_bt_set_fw_tdma_ctrl(hw, false, TDMA_2ANT, + TDMA_NAV_OFF, TDMA_DAC_SWING_OFF); + rtl8821ae_dm_bt_set_fw_dac_swing_level(hw, 0); + rtl8821ae_dm_bt_set_fw_bt_hid_info(hw, false); + rtl8821ae_dm_bt_set_fw_bt_retry_index(hw, 2); + rtl8821ae_dm_bt_set_fw_wlan_act(hw, 0x10, 0x10); + rtl8821ae_dm_bt_set_fw_dec_bt_pwr(hw, false); +} + +void rtl8821ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw) +{ + rtl8821ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF); + rtl8821ae_dm_bt_bb_back_off_level(hw, BT_BB_BACKOFF_OFF); + rtl8821ae_dm_bt_reject_ap_aggregated_packet(hw, false); + + rtl8821ae_dm_bt_set_sw_penalty_tx_rate_adaptive(hw, + BT_TX_RATE_ADAPTIVE_NORMAL); + rtl8821ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, BT_RF_RX_LPF_CORNER_RESUME); + rtl8821ae_dm_bt_set_sw_full_time_dac_swing(hw, false, 0xc0); +} + +void rtl8821ae_dm_bt_query_bt_information(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 h2c_parameter[1] = {0}; + + hal_coex_8821ae.b_c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); + + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("Query Bt information, write 0x38=0x%x\n", h2c_parameter[0])); + + rtl8821ae_fill_h2c_cmd(hw, 0x38, 1, h2c_parameter); +} + +void rtl8821ae_dm_bt_bt_hw_counters_monitor(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u32 reg_hp_tx_rx, reg_lp_tx_rx, u32_tmp; + u32 reg_hp_tx=0, reg_hp_rx=0, reg_lp_tx=0, reg_lp_rx=0; + + reg_hp_tx_rx = REG_HIGH_PRIORITY_TXRX; + reg_lp_tx_rx = REG_LOW_PRIORITY_TXRX; + + u32_tmp = rtl_read_dword(rtlpriv, reg_hp_tx_rx); + reg_hp_tx = u32_tmp & MASKLWORD; + reg_hp_rx = (u32_tmp & MASKHWORD)>>16; + + u32_tmp = rtl_read_dword(rtlpriv, reg_lp_tx_rx); + reg_lp_tx = u32_tmp & MASKLWORD; + reg_lp_rx = (u32_tmp & MASKHWORD)>>16; + + if(rtlpcipriv->btcoexist.lps_counter > 1) { + reg_hp_tx %= rtlpcipriv->btcoexist.lps_counter; + reg_hp_rx %= rtlpcipriv->btcoexist.lps_counter; + reg_lp_tx %= rtlpcipriv->btcoexist.lps_counter; + reg_lp_rx %= rtlpcipriv->btcoexist.lps_counter; + } + + hal_coex_8821ae.high_priority_tx = reg_hp_tx; + hal_coex_8821ae.high_priority_rx = reg_hp_rx; + hal_coex_8821ae.low_priority_tx = reg_lp_tx; + hal_coex_8821ae.low_priority_rx = reg_lp_rx; + + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("High Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n", + reg_hp_tx_rx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx)); + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("Low Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n", + reg_lp_tx_rx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx)); + rtlpcipriv->btcoexist.lps_counter = 0; + //rtl_write_byte(rtlpriv, 0x76e, 0xc); +} + +void rtl8821ae_dm_bt_bt_enable_disable_check(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + bool bt_alife = true; + + if (hal_coex_8821ae.high_priority_tx == 0 && + hal_coex_8821ae.high_priority_rx == 0 && + hal_coex_8821ae.low_priority_tx == 0 && + hal_coex_8821ae.low_priority_rx == 0) { + bt_alife = false; + } + if (hal_coex_8821ae.high_priority_tx == 0xeaea && + hal_coex_8821ae.high_priority_rx == 0xeaea && + hal_coex_8821ae.low_priority_tx == 0xeaea && + hal_coex_8821ae.low_priority_rx == 0xeaea) { + bt_alife = false; + } + if (hal_coex_8821ae.high_priority_tx == 0xffff && + hal_coex_8821ae.high_priority_rx == 0xffff && + hal_coex_8821ae.low_priority_tx == 0xffff && + hal_coex_8821ae.low_priority_rx == 0xffff) { + bt_alife = false; + } + if (bt_alife) { + rtlpcipriv->btcoexist.bt_active_zero_cnt = 0; + rtlpcipriv->btcoexist.b_cur_bt_disabled = false; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("8821AE BT is enabled !!\n")); + } else { + rtlpcipriv->btcoexist.bt_active_zero_cnt++; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, + ("8821AE bt all counters=0, %d times!!\n", + rtlpcipriv->btcoexist.bt_active_zero_cnt)); + if (rtlpcipriv->btcoexist.bt_active_zero_cnt >= 2) { + rtlpcipriv->btcoexist.b_cur_bt_disabled = true; + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("8821AE BT is disabled !!\n")); + } + } + if (rtlpcipriv->btcoexist.b_pre_bt_disabled != + rtlpcipriv->btcoexist.b_cur_bt_disabled) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("8821AE BT is from %s to %s!!\n", + (rtlpcipriv->btcoexist.b_pre_bt_disabled ? "disabled":"enabled"), + (rtlpcipriv->btcoexist.b_cur_bt_disabled ? "disabled":"enabled"))); + rtlpcipriv->btcoexist.b_pre_bt_disabled + = rtlpcipriv->btcoexist.b_cur_bt_disabled; + } +} + + +void rtl8821ae_dm_bt_coexist(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + rtl8821ae_dm_bt_query_bt_information(hw); + rtl8821ae_dm_bt_bt_hw_counters_monitor(hw); + rtl8821ae_dm_bt_bt_enable_disable_check(hw); + + if (rtlpcipriv->btcoexist.bt_ant_num == ANT_X2) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTCoex], 2 Ant mechanism\n")); + _rtl8821ae_dm_bt_coexist_2_ant(hw); + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("[BTCoex], 1 Ant mechanism\n")); + _rtl8821ae_dm_bt_coexist_1_ant(hw); + } + + if (!rtl8821ae_dm_bt_is_same_coexist_state(hw)) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("[BTCoex], Coexist State[bitMap] change from 0x%x%8x to 0x%x%8x\n", + rtlpcipriv->btcoexist.previous_state_h, + rtlpcipriv->btcoexist.previous_state, + rtlpcipriv->btcoexist.current_state_h, + rtlpcipriv->btcoexist.current_state)); + rtlpcipriv->btcoexist.previous_state + = rtlpcipriv->btcoexist.current_state; + rtlpcipriv->btcoexist.previous_state_h + = rtlpcipriv->btcoexist.current_state_h; + } +} + +void rtl8821ae_dm_bt_parse_bt_info(struct ieee80211_hw *hw, u8 * tmp_buf, u8 len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 bt_info; + u8 i; + + hal_coex_8821ae.b_c2h_bt_info_req_sent = false; + hal_coex_8821ae.bt_retry_cnt = 0; + for (i = 0; i < len; i++) { + if (i == 0) { + hal_coex_8821ae.c2h_bt_info_original = tmp_buf[i]; + } else if (i == 1) { + hal_coex_8821ae.bt_retry_cnt = tmp_buf[i]; + } + if(i == len-1) { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("0x%2x]", tmp_buf[i])); + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_TRACE, ("0x%2x, ", tmp_buf[i])); + } + } + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, + ("BT info bt_info (Data)= 0x%x\n",hal_coex_8821ae.c2h_bt_info_original)); + bt_info = hal_coex_8821ae.c2h_bt_info_original; + + if(bt_info & BIT(2)){ + hal_coex_8821ae.b_c2h_bt_inquiry_page = true; + } else { + hal_coex_8821ae.b_c2h_bt_inquiry_page = false; + } + + if (bt_info & BTINFO_B_CONNECTION) { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTC2H], BTInfo: bConnect=true\n")); + rtlpcipriv->btcoexist.b_bt_busy = true; + rtlpcipriv->btcoexist.current_state &= ~BT_COEX_STATE_BT_IDLE; + } else { + RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, ("[BTC2H], BTInfo: bConnect=false\n")); + rtlpcipriv->btcoexist.b_bt_busy = false; + rtlpcipriv->btcoexist.current_state |= BT_COEX_STATE_BT_IDLE; + } +} +void rtl_8821ae_c2h_command_handle(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct c2h_evt_hdr c2h_event; + u8 * ptmp_buf = NULL; + u8 index = 0; + u8 u1b_tmp = 0; + memset(&c2h_event, 0, sizeof(c2h_event)); + u1b_tmp = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL); + RT_TRACE(COMP_FW, DBG_DMESG, + ("&&&&&&: REG_C2HEVT_MSG_NORMAL is 0x%x\n", u1b_tmp)); + c2h_event.cmd_id = u1b_tmp & 0xF; + c2h_event.cmd_len = (u1b_tmp & 0xF0) >> 4; + c2h_event.cmd_seq = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL + 1); + RT_TRACE(COMP_FW, DBG_DMESG, ("cmd_id: %d, cmd_len: %d, cmd_seq: %d\n", + c2h_event.cmd_id , c2h_event.cmd_len, c2h_event.cmd_seq)); + u1b_tmp = rtl_read_byte(rtlpriv, 0x01AF); + if (u1b_tmp == C2H_EVT_HOST_CLOSE) { + return; + } else if (u1b_tmp != C2H_EVT_FW_CLOSE) { + rtl_write_byte(rtlpriv, 0x1AF, 0x00); + return; + } + ptmp_buf = (u8 *) kmalloc(c2h_event.cmd_len, GFP_KERNEL); + if(ptmp_buf == NULL) { + RT_TRACE(COMP_FW, DBG_TRACE, ("malloc cmd buf failed\n")); + return; + } + + /* Read the content */ + for (index = 0; index < c2h_event.cmd_len; index ++) { + ptmp_buf[index] = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL + 2+ index); + } + + switch(c2h_event.cmd_id) { + case C2H_BT_RSSI: + break; + + case C2H_BT_OP_MODE: + break; + + case BT_INFO: + RT_TRACE(COMP_FW, DBG_TRACE, + ("BT info Byte[0] (ID) is 0x%x\n", c2h_event.cmd_id)); + RT_TRACE(COMP_FW, DBG_TRACE, + ("BT info Byte[1] (Seq) is 0x%x\n", c2h_event.cmd_seq)); + RT_TRACE(COMP_FW, DBG_TRACE, + ("BT info Byte[2] (Data)= 0x%x\n", ptmp_buf[0])); + + if (rtlpriv->cfg->ops->get_btc_status()){ + rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, ptmp_buf, c2h_event.cmd_len); + } + break; + default: + break; + } + + if(ptmp_buf) + kfree(ptmp_buf); + + rtl_write_byte(rtlpriv, 0x01AF, C2H_EVT_HOST_CLOSE); +} + + + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/led.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/led.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_LED_H__ +#define __RTL8821AE_LED_H__ + +void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw); +void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8821ae_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/rtl8821ae/phy.h +++ linux-3.13.0/drivers/staging/rtl8821ae/rtl8821ae/phy.h @@ -0,0 +1,258 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8821AE_PHY_H__ +#define __RTL8821AE_PHY_H__ + +/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/ +#define MAX_TX_COUNT 4 +#define TX_1S 0 +#define TX_2S 1 +#define TX_3S 2 +#define TX_4S 3 + +#define MAX_POWER_INDEX 0x3F + +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define MAX_DOZE_WAITING_TIMES_9x 64 + +#define RT_CANNOT_IO(hw) false +#define HIGHPOWER_RADIOA_ARRAYLEN 22 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM 9 +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 10 +#define index_mapping_NUM 15 + +#define APK_BB_REG_NUM 5 +#define APK_AFE_REG_NUM 16 +#define APK_CURVE_REG_NUM 4 +#define PATH_NUM 2 + +#define LOOP_LIMIT 5 +#define MAX_STALL_TIME 50 +#define AntennaDiversityValue 0x80 +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define Reset_Cnt_Limit 3 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_MAC_REG_NUM 4 + +#define RF6052_MAX_PATH 2 + +#define CT_OFFSET_MAC_ADDR 0X16 + +#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A +#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60 +#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF 0x66 +#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69 +#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C + +#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F +#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72 + +#define CT_OFFSET_CHANNEL_PLAH 0x75 +#define CT_OFFSET_THERMAL_METER 0x78 +#define CT_OFFSET_RF_OPTION 0x79 +#define CT_OFFSET_VERSION 0x7E +#define CT_OFFSET_CUSTOMER_ID 0x7F + +#define RTL8821AE_MAX_PATH_NUM 2 + +#define TARGET_CHNL_NUM_2G_5G_8812 59 + +enum swchnlcmd_id { + CMDID_END, + CMDID_SET_TXPOWEROWER_LEVEL, + CMDID_BBREGWRITE10, + CMDID_WRITEPORT_ULONG, + CMDID_WRITEPORT_USHORT, + CMDID_WRITEPORT_UCHAR, + CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { + enum swchnlcmd_id cmdid; + u32 para1; + u32 para2; + u32 msdelay; +}; + +enum hw90_block_e { + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, +}; + +enum baseband_config_type { + BASEBAND_CONFIG_PHY_REG = 0, + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum ra_offset_area { + RA_OFFSET_LEGACY_OFDM1, + RA_OFFSET_LEGACY_OFDM2, + RA_OFFSET_HT_OFDM1, + RA_OFFSET_HT_OFDM2, + RA_OFFSET_HT_OFDM3, + RA_OFFSET_HT_OFDM4, + RA_OFFSET_HT_CCK, +}; + +enum antenna_path { + ANTENNA_NONE, + ANTENNA_D, + ANTENNA_C, + ANTENNA_CD, + ANTENNA_B, + ANTENNA_BD, + ANTENNA_BC, + ANTENNA_BCD, + ANTENNA_A, + ANTENNA_AD, + ANTENNA_AC, + ANTENNA_ACD, + ANTENNA_AB, + ANTENNA_ABD, + ANTENNA_ABC, + ANTENNA_ABCD +}; + +struct r_antenna_select_ofdm { + u32 r_tx_antenna:4; + u32 r_ant_l:4; + u32 r_ant_non_ht:4; + u32 r_ant_ht1:4; + u32 r_ant_ht2:4; + u32 r_ant_ht_s1:4; + u32 r_ant_non_ht_s1:4; + u32 ofdm_txsc:2; + u32 reserved:2; +}; + +struct r_antenna_select_cck { + u8 r_cckrx_enable_2:2; + u8 r_cckrx_enable:2; + u8 r_ccktx_enable:4; +}; + + +struct efuse_contents { + u8 mac_addr[ETH_ALEN]; + u8 cck_tx_power_idx[6]; + u8 ht40_1s_tx_power_idx[6]; + u8 ht40_2s_tx_power_idx_diff[3]; + u8 ht20_tx_power_idx_diff[3]; + u8 ofdm_tx_power_idx_diff[3]; + u8 ht40_max_power_offset[3]; + u8 ht20_max_power_offset[3]; + u8 channel_plan; + u8 thermal_meter; + u8 rf_option[5]; + u8 version; + u8 oem_id; + u8 regulatory; +}; + +struct tx_power_struct { + u8 cck[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_1s[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_2s[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht20_diff[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_diff[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_txpowerdiff; + u8 groupht20[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 groupht40[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 pwrgroup_cnt; + u32 mcs_original_offset[4][16]; +}; +enum _ANT_DIV_TYPE +{ + NO_ANTDIV = 0xFF, + CG_TRX_HW_ANTDIV = 0x01, + CGCS_RX_HW_ANTDIV = 0x02, + FIXED_HW_ANTDIV = 0x03, + CG_TRX_SMART_ANTDIV = 0x04, + CGCS_RX_SW_ANTDIV = 0x05, + +}; + +extern u32 rtl8821ae_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +extern void rtl8821ae_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data); +extern u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask); +extern void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data); +extern bool rtl8821ae_phy_mac_config(struct ieee80211_hw *hw); +extern bool rtl8821ae_phy_bb_config(struct ieee80211_hw *hw); +extern bool rtl8821ae_phy_rf_config(struct ieee80211_hw *hw); +extern void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band); +extern void rtl8821ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +extern void rtl8821ae_phy_get_txpower_level(struct ieee80211_hw *hw, + long *powerlevel); +extern void rtl8821ae_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +extern void rtl8821ae_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +extern void rtl8821ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +extern void rtl8821ae_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +extern void rtl8821ae_phy_sw_chnl_callback(struct ieee80211_hw *hw); +extern u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw); +extern void rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +extern void rtl8812ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +bool rtl8821ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +extern bool rtl8821ae_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +u8 _rtl8812ae_get_right_chnl_place_for_iqk(u8 chnl); +void rtl8821ae_phy_set_txpower_level_by_path(struct ieee80211_hw *hw, u8 channel, u8 path); +void rtl8812ae_do_iqk(struct ieee80211_hw *hw,u8 delta_thermal_index, + u8 thermal_value, u8 threshold); +void rtl8821ae_do_iqk(struct ieee80211_hw *hw,u8 delta_thermal_index, + u8 thermal_value, u8 threshold); +void rtl8821ae_reset_iqk_result(struct ieee80211_hw *hw); + + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.h @@ -0,0 +1,226 @@ +//=========================================== +// The following is for 8192E_1ANT BT Co-exist definition +//=========================================== +#define BT_AUTO_REPORT_ONLY_8192E_1ANT 0 + +#define BT_INFO_8192E_1ANT_B_FTP BIT7 +#define BT_INFO_8192E_1ANT_B_A2DP BIT6 +#define BT_INFO_8192E_1ANT_B_HID BIT5 +#define BT_INFO_8192E_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8192E_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8192E_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8192E_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8192E_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? true:FALSE) + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT 2 + +typedef enum _BT_INFO_SRC_8192E_1ANT{ + BT_INFO_SRC_8192E_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192E_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192E_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192E_1ANT_MAX +}BT_INFO_SRC_8192E_1ANT,*PBT_INFO_SRC_8192E_1ANT; + +typedef enum _BT_8192E_1ANT_BT_STATUS{ + BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192E_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8192E_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8192E_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8192E_1ANT_BT_STATUS_MAX +}BT_8192E_1ANT_BT_STATUS,*PBT_8192E_1ANT_BT_STATUS; + +typedef enum _BT_8192E_1ANT_WIFI_STATUS{ + BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8192E_1ANT_WIFI_STATUS_MAX +}BT_8192E_1ANT_WIFI_STATUS,*PBT_8192E_1ANT_WIFI_STATUS; + +typedef enum _BT_8192E_1ANT_COEX_ALGO{ + BT_8192E_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192E_1ANT_COEX_ALGO_SCO = 0x1, + BT_8192E_1ANT_COEX_ALGO_HID = 0x2, + BT_8192E_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8192E_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8192E_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8192E_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8192E_1ANT_COEX_ALGO_MAX = 0xb, +}BT_8192E_1ANT_COEX_ALGO,*PBT_8192E_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8192E_1ANT{ + // fw mechanism + u1Byte preBtDecPwrLvl; + u1Byte curBtDecPwrLvl; + BOOLEAN bPreBtLnaConstrain; + BOOLEAN bCurBtLnaConstrain; + u1Byte bPreBtPsdMode; + u1Byte bCurBtPsdMode; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bAutoTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + u1Byte preLps; + u1Byte curLps; + u1Byte preRpwm; + u1Byte curRpwm; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN limited_dig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + u1Byte preSsType; + u1Byte curSsType; + + u4Byte prera_mask; + u4Byte curra_mask; + + u1Byte errorCondition; +} COEX_DM_8192E_1ANT, *PCOEX_DM_8192E_1ANT; + +typedef struct _COEX_STA_8192E_1ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8192E_1ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8192E_1ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8192E_1ANT, *PCOEX_STA_8192E_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8192e1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8192e1ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ); +VOID +EXhalbtc8192e1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ); --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c @@ -0,0 +1,4242 @@ +/************************************************************** + * Description: + * + * This file is for RTL8192E Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + **************************************************************/ + +/************************************************************** + * include files + **************************************************************/ +#include "halbt_precomp.h" +#if 1 +/************************************************************** + * Global variables, these are static variables + **************************************************************/ +static struct coex_dm_8192e_2ant glcoex_dm_8192e_2ant; +static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant; +static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant; +static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant; + +const char *const GLBtInfoSrc8192e2Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8192e_2ant = 20130902; +u32 glcoex_ver_8192e_2ant = 0x34; + +/************************************************************** + * local function proto type if needed + **************************************************************/ +/************************************************************** + * local function start with halbtc8192e2ant_ + **************************************************************/ +u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + int btrssi=0; + u8 btrssi_state = coex_sta->pre_bt_rssi_state; + + btrssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state=LOW\n"); + if (btrssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + btrssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to High\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at Low\n"); + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state=HIGH\n"); + if (btrssi < rssi_thresh) { + btrssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Low\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state=LOW\n"); + if(btrssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + btrssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Medium\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi pre state=MEDIUM\n"); + if (btrssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + btrssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to High\n"); + } else if (btrssi < rssi_thresh) { + btrssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Low\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at Medium\n"); + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state=HIGH\n"); + if (btrssi < rssi_thresh1) { + btrssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Medium\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at High\n"); + } + } + } + + coex_sta->pre_bt_rssi_state = btrssi_state; + + return btrssi_state; +} + +u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist * btcoexist, u8 index, + u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + int wifirssi = 0; + u8 wifirssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifirssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + wifirssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to High\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at Low\n"); + } + } else { + if (wifirssi < rssi_thresh) { + wifirssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Low\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifirssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + wifirssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Medium\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifirssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + wifirssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to High\n"); + } else if (wifirssi < rssi_thresh) { + wifirssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Low\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at Medium\n"); + } + } else { + if (wifirssi < rssi_thresh1) { + wifirssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Medium\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at High\n"); + } + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifirssi_state; + + return wifirssi_state; +} + +void halbtc8192e2ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) +{ + static bool pre_bt_disabled = false; + static u32 bt_disable_cnt = 0; + bool bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is enabled !!\n"); + } else { + bt_disable_cnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is disabled !!\n"); + } + } + if (pre_bt_disabled != bt_disabled) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is from %s to %s!!\n", + (pre_bt_disabled ? "disabled":"enabled"), + (bt_disabled ? "disabled":"enabled")); + pre_bt_disabled = bt_disabled; + } +} + +u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist, + u8 sstype, u32 ra_masktype) +{ + u32 disra_mask = 0x0; + + switch (ra_masktype) { + case 0: /* normal mode */ + if (sstype == 2) + disra_mask = 0x0; /* enable 2ss */ + else + disra_mask = 0xfff00000;/* disable 2ss */ + break; + case 1: /* disable cck 1/2 */ + if(sstype == 2) + disra_mask = 0x00000003;/* enable 2ss */ + else + disra_mask = 0xfff00003;/* disable 2ss */ + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + if(sstype == 2) + disra_mask = 0x0001f1f7;/* enable 2ss */ + else + disra_mask = 0xfff1f1f7;/* disable 2ss */ + break; + default: + break; + } + + return disra_mask; +} + +void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist, + bool force_exec, u32 dis_ratemask) +{ + coex_dm->curra_mask = dis_ratemask; + + if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, + &coex_dm->curra_mask); + coex_dm->prera_mask = coex_dm->curra_mask; +} + +void halbtc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + bool wifi_under_bmode = false; + + coex_dm->cur_arfrtype = type; + + if (force_exec || (coex_dm->pre_arfrtype != coex_dm->cur_arfrtype)) { + switch (coex_dm->cur_arfrtype) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_bmode); + if (wifi_under_bmode) { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfrtype = coex_dm->cur_arfrtype; +} + +void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_retrylimit_type = type; + + if (force_exec || (coex_dm->pre_retrylimit_type != + coex_dm->cur_retrylimit_type)) { + switch (coex_dm->cur_retrylimit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retrylimit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retrylimit_type = coex_dm->cur_retrylimit_type; +} + +void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_ampdutime_type = type; + + if (force_exec || (coex_dm->pre_ampdutime_type != + coex_dm->cur_ampdutime_type)) { + switch (coex_dm->cur_ampdutime_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_maxtime); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdutime_type = coex_dm->cur_ampdutime_type; +} + +void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist, + bool force_exec, u8 ra_masktype, u8 arfr_type, + u8 retrylimit_type, u8 ampdutime_type) +{ + u32 disra_mask = 0x0; + + coex_dm->curra_masktype = ra_masktype; + disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, + coex_dm->cur_sstype, + ra_masktype); + halbtc8192e2ant_Updatera_mask(btcoexist, force_exec, disra_mask); + + halbtc8192e2ant_autorate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8192e2ant_retrylimit(btcoexist, force_exec, retrylimit_type); + halbtc8192e2ant_ampdu_maxtime(btcoexist, force_exec, ampdutime_type); +} + +void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist, + bool force_exec, bool rej_ap_agg_pkt, + bool b_bt_ctrl_agg_buf_size, + u8 agg_buf_size) +{ + bool reject_rx_agg = rej_ap_agg_pkt; + bool bt_ctrl_rx_agg_size = b_bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /********************************************* + * Rx Aggregation related setting + *********************************************/ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work + * when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD)>>16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD)>>16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex] High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex] Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] ={0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +bool halbtc8192e2ant_iswifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy = false; + static bool pre_under_4way = false, pre_bt_hson = false; + bool wifi_busy = false, under_4way = false, bt_hson = false; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hson != pre_bt_hson) { + pre_bt_hson = bt_hson; + return true; + } + } + + return false; +} + +void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hson = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hson) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + bool bt_hson=false; + u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED; + u8 numOfDiffProfile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + + if (!bt_link_info->bt_link_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + numOfDiffProfile++; + if (bt_link_info->hid_exist) + numOfDiffProfile++; + if (bt_link_info->pan_exist) + numOfDiffProfile++; + if (bt_link_info->a2dp_exist) + numOfDiffProfile++; + + if (numOfDiffProfile == 1) { + if (bt_link_info->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO only\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID only\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "A2DP only\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "PAN(HS) only\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "PAN(EDR) only\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (numOfDiffProfile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + A2DP ==> SCO\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + if (stack_info->num_of_hid >= 2) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID*2 + A2DP\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + A2DP\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "A2DP + PAN(HS)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "A2DP + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (numOfDiffProfile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID + A2DP ==> HID\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + A2DP + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + A2DP + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + A2DP + PAN(HS)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + A2DP + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (numOfDiffProfile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "ErrorSCO+HID+A2DP+PAN(HS)\n"); + + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO+HID+A2DP+PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist, + u8 dac_swinglvl) +{ + u8 h2c_parameter[1] ={0}; + + /* There are several type of dacswing + * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swinglvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Set Dac Swing Level=0x%x\n", dac_swinglvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x64=0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist, + u8 dec_btpwr_lvl) +{ + u8 h2c_parameter[1] ={0}; + + h2c_parameter[0] = dec_btpwr_lvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex] decrease Bt Power level = %d, FW write 0x62=0x%x\n", + dec_btpwr_lvl, h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist, + bool force_exec, u8 dec_btpwr_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s Dec BT power level = %d\n", + (force_exec? "force to":""), dec_btpwr_lvl); + coex_dm->cur_dec_bt_pwr = dec_btpwr_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], preBtDecPwrLvl=%d, curBtDecPwrLvl=%d\n", + coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + } + halbtc8192e2ant_set_fwdec_btpwr(btcoexist, coex_dm->cur_dec_bt_pwr); + + coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist, + bool enable_autoreport) +{ + u8 h2c_parameter[1] ={0}; + + h2c_parameter[0] = 0; + + if (enable_autoreport) + h2c_parameter[0] |= BIT0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (enable_autoreport? "Enabled!!":"Disabled!!"), + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist, + bool force_exec, bool enable_autoreport) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s BT Auto report = %s\n", + (force_exec? "force to":""), + ((enable_autoreport)? "Enabled":"Disabled")); + coex_dm->cur_bt_auto_report = enable_autoreport; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex] bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + coex_dm->pre_bt_auto_report, + coex_dm->cur_bt_auto_report); + + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8192e2ant_set_bt_autoreport(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist, + bool force_exec, u8 fw_dac_swinglvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec? "force to":""), fw_dac_swinglvl); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swinglvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex] preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + coex_dm->pre_fw_dac_swing_lvl, + coex_dm->cur_fw_dac_swing_lvl); + + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8192e2ant_setfw_dac_swinglevel(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, + bool rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0xffffc); + } else { + /* Resume RF Rx LPF corner + * After initialized, we can use coex_dm->btRf0x1eBackup */ + if (btcoexist->initilized) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, + coex_dm->bt_rf0x1e_backup); + } + } +} + +void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist, + bool force_exec, bool rx_rf_shrink_on) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec? "force to":""), ((rx_rf_shrink_on)? "ON":"OFF")); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex]bPreRfRxLpfShrink=%d,bCurRfRxLpfShrink=%d\n", + coex_dm->pre_rf_rx_lpf_shrink, + coex_dm->cur_rf_rx_lpf_shrink); + + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8192e2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void halbtc8192e2ant_set_sw_penalty_tx_rateadaptive( + struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + u8 h2c_parameter[6] ={0}; + + h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT0; + /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[2] = 0x00; + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set WiFi Low-Penalty Retry: %s", + (low_penalty_ra? "ON!!":"OFF!!")); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8192e2ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn LowPenaltyRA = %s\n", + (force_exec? "force to":""), ((low_penalty_ra)? "ON":"OFF")); + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex] bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + coex_dm->pre_low_penalty_ra, + coex_dm->cur_low_penalty_ra); + + if (coex_dm->pre_low_penalty_ra == + coex_dm->cur_low_penalty_ra) + return; + } + halbtc8192e2ant_set_sw_penalty_tx_rateadaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist, + u32 level) +{ + u8 val = (u8)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +void halbtc8192e2ant_setsw_fulltime_dacswing(struct btc_coexist *btcoexist, + bool sw_dac_swingon, + u32 sw_dac_swinglvl) +{ + if (sw_dac_swingon) + halbtc8192e2ant_set_dac_swingreg(btcoexist, sw_dac_swinglvl); + else + halbtc8192e2ant_set_dac_swingreg(btcoexist, 0x18); +} + + +void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist, + bool force_exec, bool dac_swingon, + u32 dac_swinglvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn DacSwing=%s, dac_swinglvl=0x%x\n", + (force_exec? "force to":""), + ((dac_swingon)? "ON":"OFF"), dac_swinglvl); + coex_dm->cur_dac_swing_on = dac_swingon; + coex_dm->cur_dac_swing_lvl = dac_swinglvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, ", + coex_dm->pre_dac_swing_on, + coex_dm->pre_dac_swing_lvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + coex_dm->cur_dac_swing_on, + coex_dm->cur_dac_swing_lvl); + + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) + return; + } + mdelay(30); + halbtc8192e2ant_setsw_fulltime_dacswing(btcoexist, dac_swingon, + dac_swinglvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void halbtc8192e2ant_set_adc_backoff(struct btc_coexist *btcoexist, + bool adc_backoff) +{ + if(adc_backoff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level On!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x3); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level Off!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x1); + } +} + +void halbtc8192e2ant_adc_backoff(struct btc_coexist *btcoexist, + bool force_exec, bool adc_backoff) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn AdcBackOff = %s\n", + (force_exec? "force to":""), ((adc_backoff)? "ON":"OFF")); + coex_dm->cur_adc_back_off = adc_backoff; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off); + + if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8192e2ant_set_adc_backoff(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist, + bool agc_table_en) +{ + + /* BB AGC Gain Table */ + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table On!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x0a1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x091B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x081C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x071D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x061E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x051F0001); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table Off!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); + } +} + +void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist, + bool force_exec, bool agc_table_en) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s %s Agc Table\n", + (force_exec? "force to":""), + ((agc_table_en)? "Enable":"Disable")); + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en); + + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8192e2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist, bool force_exec, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0=0x%x, ", + (force_exec? "force to":""), val0x6c0); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + val0x6c4, val0x6c8, val0x6cc); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, ", + coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, \n", + coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc); + + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8192e2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8192e2ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + switch (type) { + case 0: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 1: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5ffb5ffb, 0xffffff, 0x3); + break; + case 3: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff, + 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 4: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff, + 0x5ffb5ffb, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] ={0}; + + if (enable) + h2c_parameter[0] |= BIT0; /* function enable */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex]set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec? "force to":""), (enable? "ON":"OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreIgnoreWlanAct = %d ", + coex_dm->pre_ignore_wlan_act); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "bCurIgnoreWlanAct = %d!!\n", + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8192e2ant_set_fw_ignore_wlanact(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1, + u8 byte2, u8 byte3, u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5] ={0}; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | + h2c_parameter[3] << 8 | h2c_parameter[4]); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8192e2ant_sw_mechanism1(struct btc_coexist *btcoexist, + bool shrink_rx_lpf, bool low_penalty_ra, + bool limited_dig, bool btlan_constrain) +{ + halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); +} + +void halbtc8192e2ant_sw_mechanism2(struct btc_coexist *btcoexist, + bool agc_table_shift, bool adc_backoff, + bool sw_dac_swing, u32 dac_swinglvl) +{ + halbtc8192e2ant_AgcTable(btcoexist, NORMAL_EXEC, agc_table_shift); + halbtc8192e2ant_DacSwing(btcoexist, NORMAL_EXEC, sw_dac_swing, + dac_swinglvl); +} + +void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) +{ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn %s PS TDMA, type=%d\n", + (force_exec? "force to":""), (turn_on? "ON":"OFF"), type); + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + case 1: + default: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 2: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 3: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10, + 0x3, 0xf1, 0x90); + break; + case 5: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 6: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0x60, 0x90); + break; + case 7: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0x70, 0x90); + break; + case 8: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xa3, 0x10, + 0x3, 0x70, 0x90); + break; + case 9: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x10); + break; + case 10: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x10); + break; + case 11: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x10); + break; + case 12: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10, + 0x3, 0xf1, 0x10); + break; + case 13: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe0, 0x10); + break; + case 14: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe0, 0x10); + break; + case 15: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf0, 0x10); + break; + case 16: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x3, 0xf0, 0x10); + break; + case 17: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0x61, 0x20, + 0x03, 0x10, 0x10); + break; + case 18: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25, + 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25, + 0x25, 0x60, 0x90); + break; + case 21: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x15, + 0x03, 0x70, 0x90); + break; + case 71: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + default: + case 0: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0x8, 0x0, 0x0, + 0x0, 0x0); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + case 1: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0, + 0x8, 0x0); + mdelay(5); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist, u8 sstype) +{ + u8 mimops = BTC_MIMO_PS_DYNAMIC; + u32 disra_mask = 0x0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], REAL set SS Type = %d\n", sstype); + + disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, sstype, + coex_dm->curra_masktype); + halbtc8192e2ant_Updatera_mask(btcoexist, FORCE_EXEC, disra_mask); + + if (sstype == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + /* switch ofdm path */ + btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x11); + btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x1); + btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81111111); + /* switch cck patch */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1); + btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81); + mimops=BTC_MIMO_PS_STATIC; + } else if (sstype == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33); + btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x3); + btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0); + btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41); + mimops=BTC_MIMO_PS_DYNAMIC; + } + /* set rx 1ss or 2ss */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimops); +} + +void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist, + bool force_exec, u8 new_sstype) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], %s Switch SS Type = %d\n", + (force_exec? "force to":""), new_sstype); + coex_dm->cur_sstype = new_sstype; + + if (!force_exec) { + if (coex_dm->pre_sstype == coex_dm->cur_sstype) + return; + } + halbtc8192e2ant_set_switch_sstype(btcoexist, coex_dm->cur_sstype); + + coex_dm->pre_sstype = coex_dm->cur_sstype; +} + +void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, FORCE_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, FORCE_EXEC, 0); + + halbtc8192e2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8192e2ant_switch_sstype(btcoexist, FORCE_EXEC, 2); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + bool low_pwr_disable = true; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool common = false, wifi_connected = false, wifi_busy = false; + bool bt_hson = false, low_pwr_disable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (bt_link_info->sco_exist || bt_link_info->hid_exist) + halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0); + else + halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + if (!wifi_connected) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non-connected idle!!\n"); + + if ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, + 2); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, + 1); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + } + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + common = true; + } else { + if (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi connected + BT non connected-idle!!\n"); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, + 2); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, + 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (bt_hson) + return false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi connected + BT connected-idle!!\n"); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, + 2); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, + 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (wifi_busy) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi Connected-Busy + BT Busy!!\n"); + common = false; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi Connected-Idle + BT Busy!!\n"); + + halbtc8192e2ant_switch_sstype(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, + 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 21); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, + NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, + NORMAL_EXEC, 0); + halbtc8192e2ant_sw_mechanism1(btcoexist, false, + false, false, + false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, + false, false, + 0x18); + common = true; + } + } + } + return common; +} + +void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, + bool sco_hid, bool tx_pause, + u8 max_interval) +{ + static int up, dn, m, n, wait_cnt; + /* 0: no change, +1: increase WiFi duration, + * -1: decrease WiFi duration */ + int result; + u8 retry_cnt = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjust()\n"); + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } + } else { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } + } else { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } + } + } + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + wait_cnt = 0; + } else { + /* accquire the BT TRx retry count from BT_Info byte2 */ + retry_cnt = coex_sta->bt_retry_cnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], retry_cnt = %d\n", retry_cnt); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_cnt=%d\n", + up, dn, m, n, wait_cnt); + result = 0; + wait_cnt++; + /* no retry in the last 2-second duration */ + if (retry_cnt == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + wait_cnt = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex]Increase wifi duration!!\n"); + } + } else if (retry_cnt <= 3) { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + if (wait_cnt <= 2) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_cnt = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "Reduce wifi duration for retry<3\n"); + } + } else { + if (wait_cnt == 1) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3*m; + up = 0; + dn = 0; + wait_cnt = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "Decrease wifi duration for retryCounter>3!!\n"); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], max Interval = %d\n", max_interval); + if (max_interval == 1) { + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + + if (coex_dm->cur_ps_tdma == 71) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = + 71; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if (max_interval == 2) { + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if(coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if(coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if(coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } + } + + /* if current PsTdma not match with + * the recorded one (when scan, dhcp...), + * then we have to adjust it back to the previous record one. */ + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { + bool scan = false, link = false, roam = false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], PsTdma type dismatch!!!, " ); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "curPsTdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if ( !scan && !link && !roam) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, + coex_dm->ps_tdma_du_adj_type); + else + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); + } +} + +/* SCO only or SCO+PAN(HS) */ +void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x6); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x6); + } + } +} + +void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x6); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x6); + } + } +} + +void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state=BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + bool long_dist = false; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + if ((btrssi_state == BTC_RSSI_STATE_LOW || + btrssi_state == BTC_RSSI_STATE_STAY_LOW) && + (wifirssi_state == BTC_RSSI_STATE_LOW || + wifirssi_state == BTC_RSSI_STATE_STAY_LOW)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2dp, wifi/bt rssi both LOW!!\n"); + long_dist = true; + } + if (long_dist) { + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, + 0x4); + } else { + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + } + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + if (long_dist) + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + else + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + + if (long_dist) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17); + coex_dm->auto_tdma_adjust = false; + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else { + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + true, 1); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 1); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 1); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + } + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 2); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, + 2); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, + 2); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } +} + +void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(HS) only */ +void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + } + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(EDR)+A2DP */ +void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state=BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 3); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, + 3); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, + 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 3); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], return for Manual CTRL <===\n"); + return; + } + + if (coex_sta->under_ips) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + algorithm = halbtc8192e2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8192E_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + halbtc8192e2ant_action_bt_inquiry(btcoexist); + return; + } + + coex_dm->cur_algorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Algorithm = %d \n", coex_dm->cur_algorithm); + + if (halbtc8192e2ant_is_common_action(btcoexist)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant common.\n"); + coex_dm->auto_tdma_adjust = false; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex] preAlgorithm=%d, curAlgorithm=%d\n", + coex_dm->pre_algorithm, + coex_dm->cur_algorithm); + coex_dm->auto_tdma_adjust = false; + } + switch (coex_dm->cur_algorithm) { + case BT_8192E_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = SCO.\n"); + halbtc8192e2ant_action_sco(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_SCO_PAN: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = SCO+PAN(EDR).\n"); + halbtc8192e2ant_action_sco_pan(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HID.\n"); + halbtc8192e2ant_action_hid(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = A2DP.\n"); + halbtc8192e2ant_action_a2dp(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + halbtc8192e2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = PAN(EDR).\n"); + halbtc8192e2ant_action_pan_edr(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HS mode.\n"); + halbtc8192e2ant_action_pan_hs(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = PAN+A2DP.\n"); + halbtc8192e2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + halbtc8192e2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + halbtc8192e2ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HID+A2DP.\n"); + halbtc8192e2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = unknown!!\n"); + /* halbtc8192e2ant_coex_alloff(btcoexist); */ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist, bool backup) +{ + u16 u16tmp = 0; + u8 u8tmp = 0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 2Ant Init HW Config!!\n"); + + if (backup) { + /* backup rf 0x1e value */ + coex_dm->bt_rf0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, + 0x1e, 0xfffff); + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retrylimit = btcoexist->btc_read_2byte( + btcoexist, + 0x42a); + coex_dm->backup_ampdu_maxtime = btcoexist->btc_read_1byte( + btcoexist, + 0x456); + } + + /* antenna sw ctrl to bt */ + btcoexist->btc_write_1byte(btcoexist, 0x4f, 0x6); + btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24); + btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004); + else + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004); + + halbtc8192e2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + /* antenna switch control parameter */ + btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555); + + /* coex parameters */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* enable PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); + /* enable mailbox interface */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40); + u16tmp |= BIT9; + btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp); + + /* enable PTA I2C mailbox */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101); + u8tmp |= BIT4; + btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp); + + /* enable bt clock when wifi is disabled. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93); + u8tmp |= BIT0; + btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp); + /* enable bt clock when suspend. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); + u8tmp |= BIT0; + btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp); +} + +/************************************************************* + * work around function start with wa_halbtc8192e2ant_ + *************************************************************/ + +/************************************************************ + * extern function start with EXhalbtc8192e2ant_ + ************************************************************/ + +void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + halbtc8192e2ant_init_hwconfig(btcoexist, true); +} + +void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + halbtc8192e2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info*stack_info = &btcoexist->stack_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + bool roam = false, scan = false, link = false, wifi_under_5g = false; + bool bt_hson = false, wifi_busy = false; + int wifirssi = 0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir; + u8 wifi_dot11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ===========[Under Manual Control]==========="); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, + &wifi_dot11_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsMode(HsChnl)", + wifi_dot11_chnl, bt_hson, wifi_hs_chnl); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], + coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), + ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : + (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), + ((!wifi_busy) ? "idle" : + ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? + "uplink" : "downlink"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((btcoexist->bt_info.bt_disabled) ? ("disabled") : + ((coex_sta->c2h_bt_inquiry_page) ? + ("inquiry/page scan") : + ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", stack_info->sco_exist, + stack_info->hid_exist, stack_info->pan_exist, + stack_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i=0; ibt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x ", + GLBtInfoSrc8192e2Ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3]); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "%02x %02x %02x(%d)", + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + "PS state, IPS/LPS", + ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), + ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", + coex_dm->cur_sstype); + CL_PRINTF(cli_buf); + + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, + coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", + btcoexist->bt_info.ra_mask); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", coex_dm->ps_tdma_para[0], + coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], + coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], + ps_tdma_case, coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", + coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, + coex_dm->backup_arfr_cnt2, coex_dm->backup_retrylimit, + coex_dm->backup_ampdu_maxtime); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", + u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x40/ 0x4f", u8tmp[0], u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", + u32tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(hp rx[31:16]/tx[15:0])", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(lp rx[31:16]/tx[15:0])", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) + halbtc8192e2ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + halbtc8192e2ant_coex_alloff(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + } +} + +void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_SCAN_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + else if(BTC_SCAN_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); +} + +void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_ASSOCIATE_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + else if(BTC_ASSOCIATE_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); +} + +void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] ={0}; + u32 wifi_bw; + u8 wifi_center_chnl; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_center_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_center_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_center_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66=0x%x\n", + h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | + h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + if (type == BTC_PACKET_DHCP) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], DHCP Packet notify\n"); + } + +void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length ) +{ + u8 bt_info = 0; + u8 i, rspSource = 0; + bool bt_busy = false, limited_dig = false; + bool wifi_connected = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rspSource = tmp_buf[0] & 0xf; + if (rspSource >= BT_INFO_SRC_8192E_2ANT_MAX) + rspSource = BT_INFO_SRC_8192E_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length=%d, hex data=[", + rspSource, length); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rspSource][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length-1) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmp_buf[i]); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmp_buf[i]); + } + + if (BT_INFO_SRC_8192E_2ANT_WIFI_FW != rspSource) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rspSource][2] & 0xf; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rspSource][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rspSource][4]; + + /* Here we need to resend some wifi info to BT + * because bt is reset and loss of the info. */ + if ((coex_sta->bt_info_ext & BIT1)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "bit1, send wifi BW&Chnl to BT!!\n"); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8192e2ant_media_status_notify( + btcoexist, + BTC_MEDIA_CONNECT); + else + ex_halbtc8192e2ant_media_status_notify( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT3)) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "bit3, BT NOT ignore Wlan active!\n"); + halbtc8192e2ant_IgnoreWlanAct(btcoexist, + FORCE_EXEC, + false); + } + } else { + /* BT already NOT ignore Wlan active, + * do nothing here. */ + } + +#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + if ((coex_sta->bt_info_ext & BIT4)) { + /* BT auto report already enabled, do nothing */ + } else { + halbtc8192e2ant_bt_autoreport(btcoexist, FORCE_EXEC, + true); + } +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if(bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else {/* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8192E_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8192e2ant_update_btlink_info(btcoexist); + + if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Non-Connected idle!!!\n"); + } else if (bt_info == BT_INFO_8192E_2ANT_B_CONNECTION) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], bt_infoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info&BT_INFO_8192E_2ANT_B_SCO_ESCO) || + (bt_info&BT_INFO_8192E_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], bt_infoNotify(), BT SCO busy!!!\n"); + } else if (bt_info&BT_INFO_8192E_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], bt_infoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex]bt_infoNotify(), BT Non-Defined state!!!\n"); + } + + if ((BT_8192E_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8192e2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, + u8 type) +{ + if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex] StackOP Inquiry/page/pair start notify\n"); + else if(BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex] StackOP Inquiry/page/pair finish notify\n"); +} + +void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + + halbtc8192e2ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, true); + ex_halbtc8192e2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist) +{ + static u8 dis_ver_info_cnt = 0; + u32 fw_ver = 0, bt_patch_ver = 0; + struct btc_board_info *board_info=&btcoexist->board_info; + struct btc_stack_info *stack_info=&btcoexist->stack_info; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "=======================Periodical=======================\n"); + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "************************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "BT stack/ hci ext ver = %s / %d\n", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "************************************************\n"); + } + +#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + halbtc8192e2ant_querybt_info(btcoexist); + halbtc8192e2ant_monitor_bt_ctr(btcoexist); + halbtc8192e2ant_monitor_bt_enable_disable(btcoexist); +#else + if (halbtc8192e2ant_iswifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + halbtc8192e2ant_run_coexist_mechanism(btcoexist); +#endif +} + + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.h @@ -0,0 +1,205 @@ +//=========================================== +// The following is for 8812A_1ANT BT Co-exist definition +//=========================================== +#define BT_INFO_8812A_1ANT_B_FTP BIT7 +#define BT_INFO_8812A_1ANT_B_A2DP BIT6 +#define BT_INFO_8812A_1ANT_B_HID BIT5 +#define BT_INFO_8812A_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8812A_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8812A_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8812A_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8812A_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? true:false) + +#define BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT 2 + +#define +#define OUT + +typedef enum _BT_INFO_SRC_8812A_1ANT{ + BT_INFO_SRC_8812A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8812A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8812A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8812A_1ANT_MAX +}BT_INFO_SRC_8812A_1ANT,*PBT_INFO_SRC_8812A_1ANT; + +typedef enum _BT_8812A_1ANT_BT_STATUS{ + BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8812A_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8812A_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8812A_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8812A_1ANT_BT_STATUS_MAX +}BT_8812A_1ANT_BT_STATUS,*PBT_8812A_1ANT_BT_STATUS; + +typedef enum _BT_8812A_1ANT_COEX_ALGO{ + BT_8812A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8812A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8812A_1ANT_COEX_ALGO_HID = 0x2, + BT_8812A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8812A_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8812A_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8812A_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8812A_1ANT_COEX_ALGO_MAX = 0xb, +}BT_8812A_1ANT_COEX_ALGO,*PBT_8812A_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8812A_1ANT{ + // fw mechanism + bool pre_dec_bt_pwr; + bool cur_dec_bt_pwr; + bool bPreBtLnaConstrain; + bool bCurBtLnaConstrain; + u8 bPreBtPsdMode; + u8 bCurBtPsdMode; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + bool reset_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + // sw mechanism + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_back_off; + bool cur_adc_back_off; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + // algorithm related + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u8 error_condition; +} COEX_DM_8812A_1ANT, *PCOEX_DM_8812A_1ANT; + +typedef struct _COEX_STA_8812A_1ANT{ + bool under_lps; + bool under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8812A_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8812A_1ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}COEX_STA_8812A_1ANT, *PCOEX_STA_8812A_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +void +EXhalbtc8812a1ant_InitHwConfig( + PBTC_COEXIST btcoexist + ); +void +EXhalbtc8812a1ant_InitCoexDm( + PBTC_COEXIST btcoexist + ); +void +EXhalbtc8812a1ant_IpsNotify( + PBTC_COEXIST btcoexist, + u8 type + ); +void +EXhalbtc8812a1ant_LpsNotify( + PBTC_COEXIST btcoexist, + u8 type + ); +void +EXhalbtc8812a1ant_ScanNotify( + PBTC_COEXIST btcoexist, + u8 type + ); +void +EXhalbtc8812a1ant_ConnectNotify( + PBTC_COEXIST btcoexist, + u8 type + ); +void +EXhalbtc8812a1ant_MediaStatusNotify( + PBTC_COEXIST btcoexist, + u8 type + ); +void +EXhalbtc8812a1ant_SpecialPacketNotify( + PBTC_COEXIST btcoexist, + u8 type + ); +void +EXhalbtc8812a1ant_BtInfoNotify( + PBTC_COEXIST btcoexist, + u8 *tmp_buf, + u8 length + ); +void +EXhalbtc8812a1ant_StackOperationNotify( + PBTC_COEXIST btcoexist, + u8 type + ); +void +EXhalbtc8812a1ant_HaltNotify( + PBTC_COEXIST btcoexist + ); +void +EXhalbtc8812a1ant_PnpNotify( + PBTC_COEXIST btcoexist, + u8 pnpState + ); +void +EXhalbtc8812a1ant_Periodical( + PBTC_COEXIST btcoexist + ); +void +EXhalbtc8812a1ant_DisplayCoexInfo( + PBTC_COEXIST btcoexist + ); +void +EXhalbtc8812a1ant_DbgControl( + PBTC_COEXIST btcoexist, + u8 opCode, + u8 opLen, + u8 *pData + ); --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbt_precomp.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbt_precomp.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __HALBT_PRECOMP_H__ +#define __HALBT_PRECOMP_H__ +/************************************************************* + * include files + *************************************************************/ +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "../rtl8821ae/reg.h" +#include "../rtl8821ae/def.h" +#include "../rtl8821ae/phy.h" +#include "../rtl8821ae/dm.h" +#include "../rtl8821ae/fw.h" +#include "../rtl8821ae/led.h" +#include "../rtl8821ae/hw.h" +#include "../rtl8821ae/pwrseqcmd.h" +#include "../rtl8821ae/pwrseq.h" + +#include "halbtcoutsrc.h" + + +#include "halbtc8192e2ant.h" +#include "halbtc8723b1ant.h" +#include "halbtc8723b2ant.h" + + + +#define GetDefaultAdapter(padapter) padapter + + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#endif /* __HALBT_PRECOMP_H__ */ --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.h @@ -0,0 +1,549 @@ +#ifndef __HALBTC_OUT_SRC_H__ +#define __HALBTC_OUT_SRC_H__ + +#include "../wifi.h" + +#define NORMAL_EXEC false +#define FORCE_EXEC true + +#define BTC_RF_A RF90_PATH_A +#define BTC_RF_B RF90_PATH_B +#define BTC_RF_C RF90_PATH_C +#define BTC_RF_D RF90_PATH_D + +#define BTC_SMSP SINGLEMAC_SINGLEPHY +#define BTC_DMDP DUALMAC_DUALPHY +#define BTC_DMSP DUALMAC_SINGLEPHY +#define BTC_MP_UNKNOWN 0xff + +#define IN +#define OUT + +#define BT_TMP_BUF_SIZE 100 + +#define BT_COEX_ANT_TYPE_PG 0 +#define BT_COEX_ANT_TYPE_ANTDIV 1 +#define BT_COEX_ANT_TYPE_DETECTED 2 + +#define BTC_MIMO_PS_STATIC 0 +#define BTC_MIMO_PS_DYNAMIC 1 + +#define BTC_RATE_DISABLE 0 +#define BTC_RATE_ENABLE 1 + +/* single Antenna definition */ +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 +/* dual Antenna definition */ +#define BTC_ANT_WIFI_AT_MAIN 0 +#define BTC_ANT_WIFI_AT_AUX 1 +/* coupler Antenna definition */ +#define BTC_ANT_WIFI_AT_CPL_MAIN 0 +#define BTC_ANT_WIFI_AT_CPL_AUX 1 + +enum btc_chip_interface{ + BTC_INTF_UNKNOWN = 0, + BTC_INTF_PCI = 1, + BTC_INTF_USB = 2, + BTC_INTF_SDIO = 3, + BTC_INTF_GSPI = 4, + BTC_INTF_MAX +}; + +enum btc_chip_type{ + BTC_CHIP_UNDEF = 0, + BTC_CHIP_CSR_BC4 = 1, + BTC_CHIP_CSR_BC8 = 2, + BTC_CHIP_RTL8723A = 3, + BTC_CHIP_RTL8821 = 4, + BTC_CHIP_RTL8723B = 5, + BTC_CHIP_MAX +}; + +enum btc_msg_type{ + BTC_MSG_INTERFACE = 0x0, + BTC_MSG_ALGORITHM = 0x1, + BTC_MSG_MAX +}; + +extern u32 btc_dbg_type[]; + +/* following is for BTC_MSG_INTERFACE */ +#define INTF_INIT BIT0 +#define INTF_NOTIFY BIT2 + +/* following is for BTC_ALGORITHM */ +#define ALGO_BT_RSSI_STATE BIT0 +#define ALGO_WIFI_RSSI_STATE BIT1 +#define ALGO_BT_MONITOR BIT2 +#define ALGO_TRACE BIT3 +#define ALGO_TRACE_FW BIT4 +#define ALGO_TRACE_FW_DETAIL BIT5 +#define ALGO_TRACE_FW_EXEC BIT6 +#define ALGO_TRACE_SW BIT7 +#define ALGO_TRACE_SW_DETAIL BIT8 +#define ALGO_TRACE_SW_EXEC BIT9 + + + +#define CL_SPRINTF snprintf +#define CL_PRINTF printk + +#define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \ + do { \ + if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\ + printk(printstr, ##__VA_ARGS__); \ + } \ + } while(0) + +#define BTC_PRINT_F(dbgtype, dbgflag, printstr, ...) \ + do { \ + if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\ + printk(KERN_DEBUG "%s: ", __func__); \ + printk(printstr, ##__VA_ARGS__); \ + } \ + } while(0) + +#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr) \ + do { \ + if(unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \ + int __i; \ + u8* __ptr = (u8*)_Ptr; \ + printk printstr; \ + for( __i = 0; __i < 6; __i++ ) \ + printk("%02X%s", __ptr[__i], (__i==5)?"":"-");\ + printk(KERN_DEBUG "\n"); \ + }\ + } while(0) + +#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \ + do { \ + if(unlikely(btc_dbg_type[dbgtype] & dbgflag) ) { \ + int __i; \ + u8 *__ptr = (u8*)_hexdata; \ + printk(_titlestring); \ + for( __i = 0; __i < (int)_hexdatalen; __i++ ) { \ + printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \ + == 0)?" ":" ");\ + if (((__i + 1) % 16) == 0) \ + printk("\n"); \ + } \ + printk(KERN_DEBUG "\n"); \ + } \ + } while(0) + + +#define BTC_RSSI_HIGH(_rssi_) \ + ((_rssi_==BTC_RSSI_STATE_HIGH || _rssi_==BTC_RSSI_STATE_STAY_HIGH) ? \ + true : false) + +#define BTC_RSSI_MEDIUM(_rssi_) \ + ((_rssi_==BTC_RSSI_STATE_MEDIUM || _rssi_==BTC_RSSI_STATE_STAY_MEDIUM) \ + ? true : false) + +#define BTC_RSSI_LOW(_rssi_) \ + ((_rssi_==BTC_RSSI_STATE_LOW || _rssi_==BTC_RSSI_STATE_STAY_LOW) ? \ + true : false) + + +enum btc_power_save_type { + BTC_PS_WIFI_NATIVE = 0, + BTC_PS_LPS_ON = 1, + BTC_PS_LPS_OFF = 2, + BTC_PS_LPS_MAX +}; + +struct btc_board_info { + /* The following is some board information */ + u8 bt_chip_type; + u8 pg_ant_num; /* pg ant number */ + u8 btdm_ant_num; /* ant number for btdm */ + u8 btdm_ant_pos; + bool bt_exist; +}; + +enum btc_dbg_opcode{ + BTC_DBG_SET_COEX_NORMAL = 0x0, + BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, + BTC_DBG_SET_COEX_BT_ONLY = 0x2, + BTC_DBG_MAX +}; + +enum btc_rssi_state{ + BTC_RSSI_STATE_HIGH = 0x0, + BTC_RSSI_STATE_MEDIUM = 0x1, + BTC_RSSI_STATE_LOW = 0x2, + BTC_RSSI_STATE_STAY_HIGH = 0x3, + BTC_RSSI_STATE_STAY_MEDIUM = 0x4, + BTC_RSSI_STATE_STAY_LOW = 0x5, + BTC_RSSI_MAX +}; + +enum btc_wifi_role{ + BTC_ROLE_STATION = 0x0, + BTC_ROLE_AP = 0x1, + BTC_ROLE_IBSS = 0x2, + BTC_ROLE_HS_MODE = 0x3, + BTC_ROLE_MAX +}; + +enum btc_wifi_bw_mode{ + BTC_WIFI_BW_LEGACY = 0x0, + BTC_WIFI_BW_HT20 = 0x1, + BTC_WIFI_BW_HT40 = 0x2, + BTC_WIFI_BW_MAX +}; + +enum btc_wifi_traffic_dir{ + BTC_WIFI_TRAFFIC_TX = 0x0, + BTC_WIFI_TRAFFIC_RX = 0x1, + BTC_WIFI_TRAFFIC_MAX +}; + +enum btc_wifi_pnp{ + BTC_WIFI_PNP_WAKE_UP = 0x0, + BTC_WIFI_PNP_SLEEP = 0x1, + BTC_WIFI_PNP_MAX +}; + + +enum btc_get_type{ + /* type bool */ + BTC_GET_BL_HS_OPERATION, + BTC_GET_BL_HS_CONNECTING, + BTC_GET_BL_WIFI_CONNECTED, + BTC_GET_BL_WIFI_BUSY, + BTC_GET_BL_WIFI_SCAN, + BTC_GET_BL_WIFI_LINK, + BTC_GET_BL_WIFI_DHCP, + BTC_GET_BL_WIFI_SOFTAP_IDLE, + BTC_GET_BL_WIFI_SOFTAP_LINKING, + BTC_GET_BL_WIFI_IN_EARLY_SUSPEND, + BTC_GET_BL_WIFI_ROAM, + BTC_GET_BL_WIFI_4_WAY_PROGRESS, + BTC_GET_BL_WIFI_UNDER_5G, + BTC_GET_BL_WIFI_AP_MODE_ENABLE, + BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, + BTC_GET_BL_WIFI_UNDER_B_MODE, + BTC_GET_BL_EXT_SWITCH, + + /* type s4Byte */ + BTC_GET_S4_WIFI_RSSI, + BTC_GET_S4_HS_RSSI, + + /* type u32 */ + BTC_GET_U4_WIFI_BW, + BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + BTC_GET_U4_WIFI_FW_VER, + BTC_GET_U4_BT_PATCH_VER, + + /* type u1Byte */ + BTC_GET_U1_WIFI_DOT11_CHNL, + BTC_GET_U1_WIFI_CENTRAL_CHNL, + BTC_GET_U1_WIFI_HS_CHNL, + BTC_GET_U1_MAC_PHY_MODE, + BTC_GET_U1_AP_NUM, + + /* for 1Ant */ + BTC_GET_U1_LPS_MODE, + BTC_GET_BL_BT_SCO_BUSY, + + /* for test mode */ + BTC_GET_DRIVER_TEST_CFG, +#if 0 + BTC_GET_U1_LPS, + BTC_GET_U1_RPWM, +#endif + BTC_GET_MAX +}; + + +enum btc_set_type{ + /* type bool */ + BTC_SET_BL_BT_DISABLE, + BTC_SET_BL_BT_TRAFFIC_BUSY, + BTC_SET_BL_BT_LIMITED_DIG, + BTC_SET_BL_FORCE_TO_ROAM, + BTC_SET_BL_TO_REJ_AP_AGG_PKT, + BTC_SET_BL_BT_CTRL_AGG_SIZE, + BTC_SET_BL_INC_SCAN_DEV_NUM, + + /* type u1Byte */ + BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + BTC_SET_UI_SCAN_SIG_COMPENSATION, + BTC_SET_U1_AGG_BUF_SIZE, + + /* type trigger some action */ + BTC_SET_ACT_GET_BT_RSSI, + BTC_SET_ACT_AGGREGATE_CTRL, + + /********* for 1Ant **********/ + /* type bool */ + BTC_SET_BL_BT_SCO_BUSY, + /* type u1Byte */ + BTC_SET_U1_1ANT_LPS, + BTC_SET_U1_1ANT_RPWM, + /* type trigger some action */ + BTC_SET_ACT_LEAVE_LPS, + BTC_SET_ACT_ENTER_LPS, + BTC_SET_ACT_NORMAL_LPS, + BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT, + BTC_SET_ACT_DISABLE_LOW_POWER, + BTC_SET_ACT_UPDATE_ra_mask, + BTC_SET_ACT_SEND_MIMO_PS, + /* BT Coex related */ + BTC_SET_ACT_CTRL_BT_INFO, + BTC_SET_ACT_CTRL_BT_COEX, + /***************************/ + BTC_SET_MAX +}; + +enum btc_dbg_disp_type{ + BTC_DBG_DISP_COEX_STATISTICS = 0x0, + BTC_DBG_DISP_BT_LINK_INFO = 0x1, + BTC_DBG_DISP_BT_FW_VER = 0x2, + BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x3, + BTC_DBG_DISP_MAX +}; + +enum btc_notify_type_ips{ + BTC_IPS_LEAVE = 0x0, + BTC_IPS_ENTER = 0x1, + BTC_IPS_MAX +}; + +enum btc_notify_type_lps{ + BTC_LPS_DISABLE = 0x0, + BTC_LPS_ENABLE = 0x1, + BTC_LPS_MAX +}; + +enum btc_notify_type_scan{ + BTC_SCAN_FINISH = 0x0, + BTC_SCAN_START = 0x1, + BTC_SCAN_MAX +}; + +enum btc_notify_type_associate{ + BTC_ASSOCIATE_FINISH = 0x0, + BTC_ASSOCIATE_START = 0x1, + BTC_ASSOCIATE_MAX +}; + +enum btc_notify_type_media_status{ + BTC_MEDIA_DISCONNECT = 0x0, + BTC_MEDIA_CONNECT = 0x1, + BTC_MEDIA_MAX +}; + +enum btc_notify_type_special_packet{ + BTC_PACKET_UNKNOWN = 0x0, + BTC_PACKET_DHCP = 0x1, + BTC_PACKET_ARP = 0x2, + BTC_PACKET_EAPOL = 0x3, + BTC_PACKET_MAX +}; + +enum btc_notify_type_stack_operation{ + BTC_STACK_OP_NONE = 0x0, + BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, + BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, + BTC_STACK_OP_MAX +}; + + +typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr); + +typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr); + +typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr); + +typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data); + +typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr, + u8 bit_mask, u8 data1b); + +typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data); + +typedef void (*bfp_btc_w4)(void *btc_context, u32 reg_addr, u32 data); + +typedef void (*bfp_btc_wr_1byte_bit_mask)(void *btc_context, u32 reg_addr, + u8 bit_mask, u8 data); + +typedef void (*bfp_btc_set_bb_reg)(void *btc_context, u32 reg_addr, + u32 bit_mask, u32 data); + +typedef u32 (*bfp_btc_get_bb_reg)(void *btc_context, u32 reg_addr, + u32 bit_mask); + +typedef void (*bfp_btc_set_rf_reg)(void *btc_context, u8 rf_path, u32 reg_addr, + u32 bit_mask, u32 data); + +typedef u32 (*bfp_btc_get_rf_reg)(void *btc_context, u8 rf_path, + u32 reg_addr, u32 bit_mask); + +typedef void (*bfp_btc_fill_h2c)(void *btc_context, u8 element_id, + u32 cmd_len, u8 *cmd_buffer); + +typedef bool (*bfp_btc_get)(void *btcoexist, u8 get_type, void *out_buf); + +typedef bool (*bfp_btc_set)(void *btcoexist, u8 set_type, void *in_buf); + +typedef void (*bfp_btc_disp_dbg_msg)(void *btcoexist, u8 disp_type); + +struct btc_bt_info { + bool bt_disabled; + u8 rssi_adjust_for_agc_table_on; + u8 rssi_adjust_for_1ant_coex_type; + bool bt_busy; + u8 agg_buf_size; + bool limited_dig; + bool reject_agg_pkt; + bool b_bt_ctrl_buf_size; + bool increase_scan_dev_num; + u16 bt_hci_ver; + u16 bt_real_fw_ver; + u8 bt_fw_ver; + + /* the following is for 1Ant solution */ + bool bt_ctrl_lps; + bool bt_pwr_save_mode; + bool bt_lps_on; + bool force_to_roam; + u8 force_exec_pwr_cmd_cnt; + u8 lps_1ant; + u8 rpwm_1ant; + u32 ra_mask; +}; + +struct btc_stack_info { + bool profile_notified; + u16 hci_version; /* stack hci version */ + u8 num_of_link; + bool bt_link_exist; + bool sco_exist; + bool acl_exist; + bool a2dp_exist; + bool hid_exist; + u8 num_of_hid; + bool pan_exist; + bool unknown_acl_exist; + char min_bt_rssi; +}; + +struct btc_statistics { + u32 cnt_bind; + u32 cnt_init_hw_config; + u32 cnt_init_coex_dm; + u32 cnt_ips_notify; + u32 cnt_lps_notify; + u32 cnt_scan_notify; + u32 cnt_connect_notify; + u32 cnt_media_status_notify; + u32 cnt_special_packet_notify; + u32 cnt_bt_info_notify; + u32 cnt_periodical; + u32 cnt_stack_operation_notify; + u32 cnt_dbg_ctrl; +}; + +struct btc_bt_link_info { + bool bt_link_exist; + bool sco_exist; + bool sco_only; + bool a2dp_exist; + bool a2dp_only; + bool hid_exist; + bool hid_only; + bool pan_exist; + bool pan_only; +}; + +enum btc_antenna_pos { + BTC_ANTENNA_AT_MAIN_PORT = 0x1, + BTC_ANTENNA_AT_AUX_PORT = 0x2, +}; + +struct btc_coexist { + /* make sure only one adapter can bind the data context */ + bool binded; + /* default adapter */ + void *adapter; + struct btc_board_info board_info; + /* some bt info referenced by non-bt module */ + struct btc_bt_info bt_info; + struct btc_stack_info stack_info; + enum btc_chip_interface chip_interface; + struct btc_bt_link_info bt_link_info; + + bool initilized; + bool stop_coex_dm; + bool manual_control; + u8 *cli_buf; + struct btc_statistics statistics; + u8 pwr_mode_val[10]; + + /* function pointers + * io related */ + bfp_btc_r1 btc_read_1byte; + bfp_btc_w1 btc_write_1byte; + bfp_btc_w1_bit_mak btc_write_1byte_bitmask; + bfp_btc_r2 btc_read_2byte; + bfp_btc_w2 btc_write_2byte; + bfp_btc_r4 btc_read_4byte; + bfp_btc_w4 btc_write_4byte; + + bfp_btc_set_bb_reg btc_set_bb_reg; + bfp_btc_get_bb_reg btc_get_bb_reg; + + + bfp_btc_set_rf_reg btc_set_rf_reg; + bfp_btc_get_rf_reg btc_get_rf_reg; + + + bfp_btc_fill_h2c btc_fill_h2c; + + bfp_btc_disp_dbg_msg btc_disp_dbg_msg; + + bfp_btc_get btc_get; + bfp_btc_set btc_set; +}; + +bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); + + +extern struct btc_coexist gl_bt_coexist; + +bool exhalbtc_initlize_variables(struct rtl_priv* adapter); +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist); +void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist); +void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action); +void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, + enum rt_media_status media_status); +void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type); +void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, + u8 length); +void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_halt_notify(struct btc_coexist *btcoexist); +void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void exhalbtc_periodical(struct btc_coexist *btcoexist); +void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, + u8 *data); +void exhalbtc_stack_update_profile_info(void); +void exhalbtc_set_hci_version(u16 hci_version); +void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version); +void exhalbtc_update_min_bt_rssi(char bt_rssi); +void exhalbtc_set_bt_exist(bool bt_exist); +void exhalbtc_set_chip_type(u8 chip_type); +void exhalbtc_set_ant_num(u8 type, u8 ant_num); +void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist); +void exhalbtc_signal_compensation(struct btc_coexist *btcoexist, + u8 *rssi_wifi, u8 *rssi_bt); +void exhalbtc_lps_leave(struct btc_coexist *btcoexist); +void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist); +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c @@ -0,0 +1,4104 @@ +/*************************************************************** + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + ***************************************************************/ + + +/*************************************************************** + * include files + ***************************************************************/ +#include "halbt_precomp.h" +#if 1 +/*************************************************************** + * Global variables, these are static variables + ***************************************************************/ +static struct coex_dm_8723b_1ant glcoex_dm_8723b_1ant; +static struct coex_dm_8723b_1ant *coex_dm = &glcoex_dm_8723b_1ant; +static struct coex_sta_8723b_1ant glcoex_sta_8723b_1ant; +static struct coex_sta_8723b_1ant *coex_sta = &glcoex_sta_8723b_1ant; + +const char *const GLBtInfoSrc8723b1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8723b_1ant = 20130906; +u32 glcoex_ver_8723b_1ant = 0x45; + +/*************************************************************** + * local function proto type if needed + ***************************************************************/ +/*************************************************************** + * local function start with halbtc8723b1ant_ + ***************************************************************/ +u8 halbtc8723b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi=0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2){ + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to High\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Low\n"); + } + } else { + if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to High\n"); + } else if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Medium\n"); + } + } else { + if (bt_rssi < rssi_thresh1) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at High\n"); + } + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8723b1ant_wifi_rssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 wifi_rssi=0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, + BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to High\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Low\n"); + } + } else { + if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to High\n"); + } else if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Medium\n"); + } + } else { + if (wifi_rssi < rssi_thresh1) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at High\n"); + } + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8723b1ant_updatera_mask(struct btc_coexist *btcoexist, + bool force_exec, u32 dis_rate_mask) +{ + coex_dm->curra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, + &coex_dm->curra_mask); + + coex_dm->prera_mask = coex_dm->curra_mask; +} + +void halbtc8723b1ant_auto_rate_fallback_retry(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + bool wifi_under_bmode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_bmode); + if (wifi_under_bmode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8723b1ant_retry_limit(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8723b1ant_ampdu_maxtime(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || (coex_dm->pre_ampdu_time_type != + coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, + 0x456, 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8723b1ant_limited_tx(struct btc_coexist *btcoexist, + bool force_exec, u8 ra_maskType, u8 arfr_type, + u8 retry_limit_type, u8 ampdu_time_type) +{ + switch (ra_maskType) { + case 0: /* normal mode */ + halbtc8723b1ant_updatera_mask(btcoexist, force_exec, 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8723b1ant_updatera_mask(btcoexist, force_exec, + 0x00000003); + break; + /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/ + case 2: + halbtc8723b1ant_updatera_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8723b1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8723b1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8723b1ant_ampdu_maxtime(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8723b1ant_limited_rx(struct btc_coexist *btcoexist, + bool force_exec, bool rej_ap_agg_pkt, + bool b_bt_ctrl_agg_buf_size, u8 agg_buf_size) +{ + bool reject_rx_agg = rej_ap_agg_pkt; + bool bt_ctrl_rx_agg_size = b_bt_ctrl_agg_buf_size; + u8 rxAggSize = agg_buf_size; + + /********************************************** + * Rx Aggregation related setting + **********************************************/ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work + *when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxAggSize); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0; + u32 reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger*/ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +bool halbtc8723b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy = false; + static bool pre_under_4way = false, pre_bt_hs_on = false; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && bt_link_info->hid_exist ) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8723b1ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u8 algorithm = BT_8723B_1ANT_COEX_ALGO_UNDEFINED; + u8 numOfDiffProfile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + numOfDiffProfile++; + if (bt_link_info->hid_exist) + numOfDiffProfile++; + if (bt_link_info->pan_exist) + numOfDiffProfile++; + if (bt_link_info->a2dp_exist) + numOfDiffProfile++; + + if (numOfDiffProfile == 1) { + if (bt_link_info->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO only\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID only\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = A2DP only\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "PAN(HS) only\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "PAN(EDR) only\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (numOfDiffProfile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "SCO + A2DP ==> SCO\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile " + "= SCO + PAN(HS)\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile " + "= SCO + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "HID + A2DP\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "HID + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "HID + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "A2DP + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "A2DP + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (numOfDiffProfile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "SCO + HID + A2DP ==> HID\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "SCO + HID + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "SCO + HID + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "SCO + A2DP + PAN(HS)\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + " + "A2DP + PAN(EDR) ==> HID\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "HID + A2DP + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "HID + A2DP + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (numOfDiffProfile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Error!!! " + "BT Profile = SCO + " + "HID + A2DP + PAN(HS)\n"); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = " + "SCO + HID + A2DP + PAN(EDR)" + "==>PAN(EDR)+HID\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +bool halbtc8723b1ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist) +{ + bool ret = false; + bool bt_hs_on = false, wifi_connected = false; + s32 bt_hs_rssi = 0; + u8 bt_rssi_state; + + if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on)) + return false; + if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected)) + return false; + if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi)) + return false; + + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 35, 0); + + if (wifi_connected) { + if (bt_hs_on) { + if (bt_hs_rssi > 37) + ret = true; + } else { + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + ret = true; + } + } + + return ret; +} + +void halbtc8723b1ant_set_fw_dac_swing_level(struct btc_coexist *btcoexist, + u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing + * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x64=0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8723b1ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, + bool dec_bt_pwr) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (dec_bt_pwr) + h2c_parameter[0] |= BIT1; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], decrease Bt Power : %s, FW write 0x62=0x%x\n", + (dec_bt_pwr? "Yes!!":"No!!"),h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8723b1ant_dec_bt_pwr(struct btc_coexist *btcoexist, + bool force_exec, bool dec_bt_pwr) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s Dec BT power = %s\n", + (force_exec ? "force to" : ""), (dec_bt_pwr ? "ON" : "OFF")); + coex_dm->cur_dec_bt_pwr = dec_bt_pwr; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n", + coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + + if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) + return; + } + halbtc8723b1ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr); + + coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +void halbtc8723b1ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (enable_auto_report? "Enabled!!":"Disabled!!"), + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8723b1ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, bool enable_auto_report) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s BT Auto report = %s\n", + (force_exec? "force to":""), + ((enable_auto_report)? "Enabled":"Disabled")); + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreBtAutoReport=%d, " + "bCurBtAutoReport=%d\n", + coex_dm->pre_bt_auto_report, + coex_dm->cur_bt_auto_report); + + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8723b1ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, + bool force_exec, u8 fw_dac_swing_lvl) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec? "force to":""), fw_dac_swing_lvl); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], preFwDacSwingLvl=%d, " + "curFwDacSwingLvl=%d\n", + coex_dm->pre_fw_dac_swing_lvl, + coex_dm->cur_fw_dac_swing_lvl); + + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8723b1ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8723b1ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, + bool rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /*Shrink RF Rx LPF corner */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0xffff7); + } else { + /*Resume RF Rx LPF corner + * After initialized, we can use coex_dm->btRf0x1eBackup */ + if (btcoexist->initilized) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x1e, 0xfffff, + coex_dm->bt_rf0x1e_backup); + } + } +} + +void halbtc8723b1ant_rf_shrink(struct btc_coexist *btcoexist, + bool force_exec, bool rx_rf_shrink_on) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec? "force to":""), + ((rx_rf_shrink_on)? "ON":"OFF")); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreRfRxLpfShrink=%d, " + "bCurRfRxLpfShrink=%d\n", + coex_dm->pre_rf_rx_lpf_shrink, + coex_dm->cur_rf_rx_lpf_shrink); + + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8723b1ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void halbtc8723b1ant_set_sw_penalty_tx_rate_adaptive( + struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT0; + /*normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[2] = 0x00; + h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36 */ + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set WiFi Low-Penalty Retry: %s", + (low_penalty_ra ? "ON!!" : "OFF!!")); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8723b1ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8723b1ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8723b1ant_set_dac_swing_reg(struct btc_coexist *btcoexist, u32 level) +{ + u8 val = (u8) level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +void halbtc8723b1ant_set_sw_full_time_dac_swing(struct btc_coexist *btcoexist, + bool sw_dac_swing_on, + u32 sw_dac_swing_lvl) +{ + if (sw_dac_swing_on) + halbtc8723b1ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); + else + halbtc8723b1ant_set_dac_swing_reg(btcoexist, 0x18); +} + + +void halbtc8723b1ant_dac_swing(struct btc_coexist *btcoexist, bool force_exec, + bool dac_swing_on, u32 dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn DacSwing=%s, dac_swing_lvl=0x%x\n", + (force_exec ? "force to" : ""), (dac_swing_on ? "ON" : "OFF"), + dac_swing_lvl); + + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, " + "bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + coex_dm->pre_dac_swing_on, coex_dm->pre_dac_swing_lvl, + coex_dm->cur_dac_swing_on, + coex_dm->cur_dac_swing_lvl); + + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) + return; + } + mdelay(30); + halbtc8723b1ant_set_sw_full_time_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void halbtc8723b1ant_set_adc_backoff(struct btc_coexist *btcoexist, + bool adc_backoff) +{ + if (adc_backoff) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level On!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level Off!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1); + } +} + +void halbtc8723b1ant_adc_backoff(struct btc_coexist *btcoexist, + bool force_exec, bool adc_backoff) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn AdcBackOff = %s\n", + (force_exec ? "force to" : ""), (adc_backoff ? "ON" : "OFF")); + coex_dm->cur_adc_backoff = adc_backoff; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + coex_dm->pre_adc_backoff, coex_dm->cur_adc_backoff); + + if(coex_dm->pre_adc_backoff == coex_dm->cur_adc_backoff) + return; + } + halbtc8723b1ant_set_adc_backoff(btcoexist, coex_dm->cur_adc_backoff); + + coex_dm->pre_adc_backoff = + coex_dm->cur_adc_backoff; +} + +void halbtc8723b1ant_set_agc_table(struct btc_coexist *btcoexist, + bool adc_table_en) +{ + u8 rssi_adjust_val = 0; + + btcoexist->btc_set_rf_reg(btcoexist, + BTC_RF_A, 0xef, 0xfffff, 0x02000); + if (adc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table On!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x3fa58); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x37a58); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x2fa58); + rssi_adjust_val = 8; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table Off!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x39258); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x31258); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x29258); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + /* set rssi_adjust_val for wifi module. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + &rssi_adjust_val); +} + + +void halbtc8723b1ant_agc_table(struct btc_coexist *btcoexist, + bool force_exec, bool adc_table_en) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s %s Agc Table\n", + (force_exec ? "force to" : ""), + (adc_table_en ? "Enable" : "Disable")); + coex_dm->cur_agc_table_en = adc_table_en; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + coex_dm->pre_agc_table_en, + coex_dm->cur_agc_table_en); + + if(coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8723b1ant_set_agc_table(btcoexist, adc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void halbtc8723b1ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, + u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0=0x%x," + " 0x6c4=0x%x, 0x6cc=0x%x\n", (force_exec ? "force to" : ""), + val0x6c0, val0x6c4, val0x6cc); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8723b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + switch (type) { + case 0: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5aaa5aaa, 0xffffff, 0x3); + break; + case 5: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 6: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5afa5afa, + 0x5afa5afa, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8723b1ant_SetFwIgnoreWlanAct(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT0; /* function enable */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set FW for BT Ignore Wlan_Act," + " FW write 0x63=0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8723b1ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreIgnoreWlanAct = %d, " + "bCurIgnoreWlanAct = %d!!\n", + coex_dm->pre_ignore_wlan_act, + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8723b1ant_SetFwIgnoreWlanAct(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8723b1ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, + u8 byte1, u8 byte2, u8 byte3, + u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + bool ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if ((byte1 & BIT4) && !(byte1 & BIT5)) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], FW for 1Ant AP mode\n"); + real_byte1 &= ~BIT4; + real_byte1 |= BIT5; + + real_byte5 |= BIT5; + real_byte5 &= ~BIT6; + } + } + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1] << 24 | + h2c_parameter[2] << 16 | + h2c_parameter[3] << 8 | + h2c_parameter[4]); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8723b1ant_SetLpsRpwm(struct btc_coexist *btcoexist, + u8 lps_val, u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_1ANT_LPS, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_1ANT_RPWM, &rpwm); +} + +void halbtc8723b1ant_LpsRpwm(struct btc_coexist *btcoexist, bool force_exec, + u8 lps_val, u8 rpwm_val) +{ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (force_exec ? "force to" : ""), lps_val, rpwm_val); + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], LPS-RxBeaconMode=0x%x , LPS-RPWM=0x%x!!\n", + coex_dm->cur_lps, coex_dm->cur_rpwm); + + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], LPS-RPWM_Last=0x%x" + " , LPS-RPWM_Now=0x%x!!\n", + coex_dm->pre_rpwm, coex_dm->cur_rpwm); + + return; + } + } + halbtc8723b1ant_SetLpsRpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8723b1ant_sw_mechanism1(struct btc_coexist *btcoexist, + bool shrink_rx_lpf, bool low_penalty_ra, + bool limited_dig, bool bt_lna_constrain) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], SM1[ShRf/ LpRA/ LimDig/ btLna] = %d %d %d %d\n", + shrink_rx_lpf, low_penalty_ra, limited_dig, bt_lna_constrain); + + halbtc8723b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +void halbtc8723b1ant_sw_mechanism2(struct btc_coexist *btcoexist, + bool agc_table_shift, bool adc_backoff, + bool sw_dac_swing, u32 dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], SM2[AgcT/ AdcB/ SwDacSwing(lvl)] = %d %d %d\n", + agc_table_shift, adc_backoff, sw_dac_swing); +} + +void halbtc8723b1ant_SetAntPath(struct btc_coexist *btcoexist, + u8 ant_pos_type, bool init_hw_cfg, + bool wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 fw_ver = 0, u32tmp = 0; + bool pg_ext_switch = false; + bool use_ext_switch = false; + u8 h2c_parameter[2] = {0}; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); + /* [31:16]=fw ver, [15:0]=fw sub ver */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + + + if ((fw_ver < 0xc0000) || pg_ext_switch) + use_ext_switch = true; + + if (init_hw_cfg){ + /*BT select s0/s1 is controlled by WiFi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + + /*Force GNT_BT to Normal */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); + } else if (wifi_off) { + /*Force GNT_BT to High */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); + /*BT select s0/s1 is controlled by BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); + + /* 0x4c[24:23]=00, Set Antenna control by BT_RFE_CTRL + * BT Vendor 0xac=0xf002 */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT23; + u32tmp &= ~BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + + if (use_ext_switch) { + if (init_hw_cfg) { + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT23; + u32tmp |= BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + /* Main Ant to BT for IPS case 0x4c[23]=1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x1); + + /*tell firmware "no antenna inverse"*/ + h2c_parameter[0] = 0; + h2c_parameter[1] = 1; /*ext switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /*Aux Ant to BT for IPS case 0x4c[23]=1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x0); + + /*tell firmware "antenna inverse"*/ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; /*ext switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* fixed internal switch first*/ + /* fixed internal switch S1->WiFi, S0->BT*/ + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + else/* fixed internal switch S0->WiFi, S1->BT*/ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x2); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x2); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x2); + break; + } + + } else { + if (init_hw_cfg) { + /* 0x4c[23]=1, 0x4c[24]=0 Antenna control by 0x64*/ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp |= BIT23; + u32tmp &= ~BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + /*Main Ant to WiFi for IPS case 0x4c[23]=1*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x0); + + /*tell firmware "no antenna inverse"*/ + h2c_parameter[0] = 0; + h2c_parameter[1] = 0; /*internal switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /*Aux Ant to BT for IPS case 0x4c[23]=1*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x1); + + /*tell firmware "antenna inverse"*/ + h2c_parameter[0] = 1; + h2c_parameter[1] = 0; /*internal switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* fixed external switch first*/ + /*Main->WiFi, Aux->BT*/ + if(board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x1); + else/*Main->BT, Aux->WiFi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x2); + + /* internal switch setting*/ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if(board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x0); + else + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x280); + break; + case BTC_ANT_PATH_BT: + if(board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x280); + else + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x0); + break; + default: + case BTC_ANT_PATH_PTA: + if(board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x200); + else + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x80); + break; + } + } +} + +void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, + bool turn_on, u8 type) +{ + bool wifi_busy = false; + u8 rssi_adjust_val = 0; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!force_exec) { + if (coex_dm->cur_ps_tdma_on) + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], ******** TDMA(on, %d) *********\n", + coex_dm->cur_ps_tdma); + else + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], ******** TDMA(off, %d) ********\n", + coex_dm->cur_ps_tdma); + + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + default: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a, + 0x1a, 0x0, 0x50); + break; + case 1: + if (wifi_busy) + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, + 0x3a, 0x03, + 0x10, 0x50); + else + halbtc8723b1ant_set_fw_ps_tdma(btcoexist,0x51, + 0x3a, 0x03, + 0x10, 0x51); + + rssi_adjust_val = 11; + break; + case 2: + if (wifi_busy) + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, + 0x2b, 0x03, + 0x10, 0x50); + else + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, + 0x2b, 0x03, + 0x10, 0x51); + rssi_adjust_val = 14; + break; + case 3: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d, + 0x1d, 0x0, 0x52); + break; + case 4: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, + 0x3, 0x14, 0x0); + rssi_adjust_val = 17; + break; + case 5: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, + 0x3, 0x11, 0x10); + break; + case 6: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20, + 0x3, 0x11, 0x13); + break; + case 7: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc, + 0x5, 0x0, 0x0); + break; + case 8: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, + 0x3, 0x10, 0x0); + break; + case 9: + if(wifi_busy) + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, + 0x21, 0x3, + 0x10, 0x50); + else + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, + 0x21, 0x3, + 0x10, 0x50); + rssi_adjust_val = 18; + break; + case 10: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, + 0xa, 0x0, 0x40); + break; + case 11: + if (wifi_busy) + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, + 0x15, 0x03, + 0x10, 0x50); + else + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, + 0x15, 0x03, + 0x10, 0x50); + rssi_adjust_val = 20; + break; + case 12: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a, + 0x0a, 0x0, 0x50); + break; + case 13: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, + 0x15, 0x0, 0x50); + break; + case 14: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, + 0x3, 0x10, 0x52); + break; + case 15: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, + 0x3, 0x8, 0x0); + break; + case 16: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, + 0x3, 0x10, 0x0); + rssi_adjust_val = 18; + break; + case 18: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, + 0x3, 0x10, 0x0); + rssi_adjust_val = 14; + break; + case 20: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35, + 0x03, 0x11, 0x10); + break; + case 21: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, + 0x03, 0x11, 0x10); + break; + case 22: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x10); + break; + case 23: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 24: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 25: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 26: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 27: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x3, 0x31, 0x98); + rssi_adjust_val = 22; + break; + case 28: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25, + 0x3, 0x31, 0x0); + break; + case 29: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a, + 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, + 0x3, 0x10, 0x50); + break; + case 31: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a, + 0x1a, 0, 0x58); + break; + case 32: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa, + 0x3, 0x10, 0x0); + break; + case 33: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25, + 0x3, 0x30, 0x90); + break; + case 34: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a, + 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a, + 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, + 0x3, 0x14, 0x50); + break; + /* SoftAP only with no sta associated,BT disable , + * TDMA mode for power saving + * here softap mode screen off will cost 70-80mA for phone */ + case 40: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18, + 0x00, 0x10, 0x24); + break; + } + } else { + switch (type) { + case 8: /*PTA Control */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0, + 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA, + false, false); + break; + case 0: + default: /*Software control, Antenna at BT side */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, + 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, + false, false); + break; + case 9: /*Software control, Antenna at WiFi side */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, + 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_WIFI, + false, false); + break; + } + } + rssi_adjust_val = 0; + btcoexist->btc_set(btcoexist, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + &rssi_adjust_val); + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8723b1ant_coex_alloff(struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + /* sw all off */ + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + + /* hw all off */ + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +bool halbtc8723b1ant_is_common_action(struct btc_coexist *btcoexist) +{ + bool commom = false, wifi_connected = false; + bool wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non connected-idle + " + "BT non connected-idle!!\n"); + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + commom = true; + } else if (wifi_connected && + (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + " + "BT non connected-idle!!\n"); + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + commom = true; + } else if (!wifi_connected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non connected-idle + " + "BT connected-idle!!\n"); + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + commom = true; + } else if (wifi_connected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + commom = true; + } else if (!wifi_connected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + commom = true; + } else { + if (wifi_busy) + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Busy" + " + BT Busy!!\n"); + else + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Idle" + " + BT Busy!!\n"); + + commom = false; + } + + return commom; +} + + +void halbtc8723b1ant_tdma_duration_adjust_for_acl(struct btc_coexist *btcoexist, + u8 wifi_status) +{ + static s32 up, dn, m, n, wait_count; + /* 0: no change, +1: increase WiFi duration, + * -1: decrease WiFi duration */ + s32 result; + u8 retry_count = 0, bt_info_ext; + static bool pre_wifi_busy = false; + bool wifi_busy = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjustForAcl()\n"); + + if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status) + wifi_busy = true; + else + wifi_busy = false; + + if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifi_status)) { + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /*accquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + result = 0; + wait_count++; + /* no retry in the last 2-second duration */ + if (retry_count == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Increase wifi " + "duration!!\n"); + } + } else if (retry_count <= 3) { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + if (wait_count <= 2) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration" + " for retryCounter<3!!\n"); + } + } else { + if (wait_count == 1) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration" + " for retryCounter>3!!\n"); + } + + if (result == -1) { + if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } else if(result == 1) { + if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } + } else { /*no change */ + /*if busy / idle change */ + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, + true, + coex_dm->cur_ps_tdma); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex],********* TDMA(on, %d) ********\n", + coex_dm->cur_ps_tdma); + } + + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + } + } +} + +u8 halbtc8723b1ant_ps_tdma_type_by_wifi_rssi(s32 wifi_rssi, s32 pre_wifi_rssi, + u8 wifi_rssi_thresh) +{ + u8 ps_tdma_type=0; + + if (wifi_rssi > pre_wifi_rssi) { + if (wifi_rssi > (wifi_rssi_thresh + 5)) + ps_tdma_type = 26; + else + ps_tdma_type = 25; + } else { + if (wifi_rssi > wifi_rssi_thresh) + ps_tdma_type = 26; + else + ps_tdma_type = 25; + } + + return ps_tdma_type; +} + +void halbtc8723b1ant_PsTdmaCheckForPowerSaveState(struct btc_coexist *btcoexist, + bool new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist, + u8 ps_type, u8 lps_val, + u8 rpwm_val) +{ + bool low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + halbtc8723b1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8723b1ant_LpsRpwm(btcoexist, NORMAL_EXEC, lps_val, + rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + case BTC_PS_LPS_OFF: + halbtc8723b1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + +void halbtc8723b1ant_action_wifi_only(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); +} + +void halbtc8723b1ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) +{ + static bool pre_bt_disabled = false; + static u32 bt_disable_cnt = 0; + bool bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is enabled !!\n"); + } else { + bt_disable_cnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is disabled !!\n"); + halbtc8723b1ant_action_wifi_only(btcoexist); + } + } + if (pre_bt_disabled != bt_disabled) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is from %s to %s!!\n", + (pre_bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + pre_bt_disabled = bt_disabled; + if (!bt_disabled) { + } else { + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + +/*************************************************** + * + * Software Coex Mechanism start + * + ***************************************************/ +/* SCO only or SCO+PAN(HS) */ +void halbtc8723b1ant_action_sco(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = + halbtc8723b1ant_wifi_rssi_state(btcoexist, 0, 2, 25, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + + +void halbtc8723b1ant_action_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8723b1ant_action_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b1ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + + +/* PAN(HS) only */ +void halbtc8723b1ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* fw mechanism */ + if((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* fw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/*PAN(EDR)+A2DP */ +void halbtc8723b1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b1ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8723b1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b1ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8723b1ant_wifi_rssi_state(btcoexist, + 0, 2, 25, 0); + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 50, 0); + + if (halbtc8723b1ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + else + halbtc8723b1ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } else { + halbtc8723b1ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/***************************************************** + * + * Non-Software Coex Mechanism start + * + *****************************************************/ +void halbtc8723b1ant_action_hs(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); +} + +void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!wifi_connected) { + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if (bt_link_info->sco_exist || bt_link_info->hid_only) { + /* SCO/HID-only busy */ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else { + if (ap_enable) + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, + 0x50, 0x4); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +void halbtc8723b1ant_action_bt_sco_hid_only_busy(struct btc_coexist * btcoexist, + u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* tdma and coex table */ + + if (bt_link_info->sco_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } else { /* HID */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } +} + +void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + struct btc_coexist *btcoexist, + u8 wifi_status) +{ + u8 bt_rssi_state; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 28, 0); + + if (bt_link_info->hid_only) { /*HID */ + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + wifi_status); + coex_dm->auto_tdma_adjust = false; + return; + } else if (bt_link_info->a2dp_only) { /*A2DP */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_tdma_duration_adjust_for_acl(btcoexist, + wifi_status); + } else { /*for low BT RSSI */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->auto_tdma_adjust = false; + } + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /*HID+A2DP */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->auto_tdma_adjust = false; + } else { /*for low BT RSSI*/ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->auto_tdma_adjust = false; + } + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + /*PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + } else if (bt_link_info->pan_only || + (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + coex_dm->auto_tdma_adjust = false; + /*A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP)*/ + } else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } +} + +void halbtc8723b1ant_action_wifi_not_connected(struct btc_coexist *btcoexist) +{ + /* power save state */ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723b1ant_action_wifi_not_connected_asso_auth_scan( + struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +} + +void halbtc8723b1ant_ActionWifiConnectedScan(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 22); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +void halbtc8723b1ant_action_wifi_connected_special_packet( + struct btc_coexist *btcoexist) +{ + bool hs_connecting = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 22); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) +{ + bool wifi_busy = false; + bool scan = false, link = false, roam = false; + bool under_4way = false, ap_enable = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect()===>\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (under_4way) { + halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect(), " + "return for wifi is under 4way<===\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + halbtc8723b1ant_ActionWifiConnectedScan(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect(), " + "return for wifi is under scan<===\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + /* power save state */ + if (!ap_enable && + BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && + !btcoexist->bt_link_info.hid_only) + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, + 0x50, 0x4); + else + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_BUSY, &wifi_busy); + if (!wifi_busy) { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } else { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } +} + +void halbtc8723b1ant_run_sw_coexist_mechanism(struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8723b1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8723b1ant_is_common_action(btcoexist)) { + } else { + switch (coex_dm->cur_algorithm) { + case BT_8723B_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = SCO.\n"); + halbtc8723b1ant_action_sco(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID.\n"); + halbtc8723b1ant_action_hid(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = A2DP.\n"); + halbtc8723b1ant_action_a2dp(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = " + "A2DP+PAN(HS).\n"); + halbtc8723b1ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + halbtc8723b1ant_action_pan_edr(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HS mode.\n"); + halbtc8723b1ant_action_pan_hs(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + halbtc8723b1ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = " + "PAN(EDR)+HID.\n"); + halbtc8723b1ant_action_pan_edr_hid(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = " + "HID+A2DP+PAN.\n"); + halbtc8723b1ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + halbtc8723b1ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = " + "coexist All Off!!\n"); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, bt_hs_on = false; + bool limited_dig = false, bIncreaseScanDevNum = false; + bool b_bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), " + "return for Manual CTRL <===\n"); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), " + "return for Stop Coex DM <===\n"); + return; + } + + if (coex_sta->under_ips) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + limited_dig = true; + bIncreaseScanDevNum = true; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &bIncreaseScanDevNum); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + } else { + if (wifi_connected) { + wifi_rssi_state = + halbtc8723b1ant_wifi_rssi_state(btcoexist, + 1, 2, 30, 0); + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_limited_tx(btcoexist, + NORMAL_EXEC, + 1, 1, 1, 1); + } else { + halbtc8723b1ant_limited_tx(btcoexist, + NORMAL_EXEC, + 1, 1, 1, 1); + } + } else { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, + 0, 0, 0, 0); + } + } + + if (bt_link_info->sco_exist) { + b_bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x3; + } else if (bt_link_info->hid_exist) { + b_bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x5; + } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { + b_bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x8; + } + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + b_bt_ctrl_agg_buf_size, agg_buf_size); + + halbtc8723b1ant_run_sw_coexist_mechanism(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + + if (!wifi_connected) { + bool scan = false, link = false, roam = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is non connected-idle !!!\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) + halbtc8723b1ant_action_wifi_not_connected_asso_auth_scan(btcoexist); + else + halbtc8723b1ant_action_wifi_not_connected(btcoexist); + } else { /* wifi LPS/Busy */ + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8723b1ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8723b1ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false); + + /* sw all off */ + halbtc8723b1ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b1ant_sw_mechanism2(btcoexist,false, false, false, 0x18); + + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, bool backup) +{ + u32 u32tmp = 0; + u8 u8tmp = 0; + u32 cnt_bt_cal_chk = 0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 1Ant Init HW Config!!\n"); + + if (backup) {/* backup rf 0x1e value */ + coex_dm->bt_rf0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, + BTC_RF_A, 0x1e, 0xfffff); + + coex_dm->backup_arfr_cnt1 = + btcoexist->btc_read_4byte(btcoexist, 0x430); + coex_dm->backup_arfr_cnt2 = + btcoexist->btc_read_4byte(btcoexist, 0x434); + coex_dm->backup_retry_limit = + btcoexist->btc_read_2byte(btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = + btcoexist->btc_read_1byte(btcoexist, 0x456); + } + + /* WiFi goto standby while GNT_BT 0-->1 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); + /* BT goto standby while GNT_BT 1-->0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500); + + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + + + /* BT calibration check */ + while (cnt_bt_cal_chk <= 20) { + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d); + cnt_bt_cal_chk++; + if (u32tmp & BIT0) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ########### BT " + "calibration(cnt=%d) ###########\n", + cnt_bt_cal_chk); + mdelay(50); + } else { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ********** BT NOT " + "calibration (cnt=%d)**********\n", + cnt_bt_cal_chk); + break; + } + } + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* Enable counter statistics */ + /*0x76e[3] =1, WLAN_Act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + + /*Antenna config */ + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA, true, false); + /* PTA parameter */ + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + +} + +void halbtc8723b1ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist) +{ + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0); +} + +/************************************************************** + * work around function start with wa_halbtc8723b1ant_ + **************************************************************/ +/************************************************************** + * extern function start with EXhalbtc8723b1ant_ + **************************************************************/ + +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_init_hw_config(btcoexist, true); +} + +void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + + btcoexist->stop_coex_dm = false; + + halbtc8723b1ant_init_coex_dm(btcoexist); + + halbtc8723b1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, psTdmaCase=0; + u16 u16tmp[4]; + u32 u32tmp[4]; + bool roam = false, scan = false; + bool link = false, wifi_under_5g = false; + bool bt_hs_on = false, wifi_busy = false; + s32 wifi_rssi =0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck; + u8 wifi_dot11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]=========="); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "Ant PG Num/ Ant Mech/ Ant Pos:", \ + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", \ + ((stack_info->profile_notified)? "Yes":"No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", \ + glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant, + fw_ver, bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, + &wifi_dot11_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(HsMode)", \ + wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", \ + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist,BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + "Wifi status", (wifi_under_5g? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifi_bw)? "Legacy": + (((BTC_WIFI_BW_HT40==wifi_bw)? "HT40":"HT20"))), + ((!wifi_busy)? "idle": + ((BTC_WIFI_TRAFFIC_TX==wifi_traffic_dir)? + "uplink":"downlink"))); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((btcoexist->bt_info.bt_disabled)? ("disabled"): + ((coex_sta->c2h_bt_inquiry_page)?("inquiry/page scan"): + ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status)? + "non-connected idle": + ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)? + "connected-idle":"busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", bt_link_info->sco_exist, + bt_link_info->hid_exist, bt_link_info->pan_exist, + bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT0) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x " + "%02x %02x %02x %02x(%d)", + GLBtInfoSrc8723b1Ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s/%s, (0x%x/0x%x)", + "PS state, IPS/LPS, (lps/rpwm)", \ + ((coex_sta->under_ips? "IPS ON":"IPS OFF")), + ((coex_sta->under_lps? "LPS ON":"LPS OFF")), + btcoexist->bt_info.lps_1ant, + btcoexist->bt_info.rpwm_1ant); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if (!btcoexist->manual_control) { + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", \ + coex_dm->cur_rf_rx_lpf_shrink, + coex_dm->cur_low_penalty_ra, + btcoexist->bt_info.limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + coex_dm->cur_agc_table_en, + coex_dm->cur_adc_backoff, + coex_dm->cur_dac_swing_on, + coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + "Rate Mask", btcoexist->bt_info.ra_mask); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + psTdmaCase = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x " + "case-%d (auto:%d)", + "PS TDMA", coex_dm->ps_tdma_para[0], + coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], + coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], + psTdmaCase, coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", \ + coex_dm->error_condition); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr, + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, + coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit, + coex_dm->backup_ampdu_max_time); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0], + (u32tmp[1] & 0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x948/ 0x67[5] / 0x765", + u32tmp[0], ((u8tmp[0] & 0x20)>> 5), u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", + u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x38[11]/0x40/0x4c[24:23]/0x64[0]", + ((u8tmp[0] & 0x8)>>3), u8tmp[1], + ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8); + u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + + fa_ofdm = ((u32tmp[0] & 0xffff0000) >> 16) + + ((u32tmp[1] & 0xffff0000) >> 16) + + (u32tmp[1] & 0xffff) + + (u32tmp[2] & 0xffff) + \ + ((u32tmp[3] & 0xffff0000) >> 16) + + (u32tmp[3] & 0xffff) ; + fa_cck = (u8tmp[0] << 8) + u8tmp[1]; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "OFDM-CCA/OFDM-FA/CCK-FA", + u32tmp[0] & 0xffff, fa_ofdm, fa_cck); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", coex_sta->high_priority_rx, + coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, + coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if(BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) + halbtc8723b1ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, + false, true); + /* set PTA control */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + + halbtc8723b1ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + bool wifi_connected = false, bt_hs_on = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8723b1ant_query_bt_info(btcoexist); + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + if (!wifi_connected) /* non-connected scan */ + halbtc8723b1ant_action_wifi_not_connected_asso_auth_scan(btcoexist); + else /* wifi is connected */ + halbtc8723b1ant_ActionWifiConnectedScan(btcoexist); + } else if (BTC_SCAN_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); + if (!wifi_connected) /* non-connected scan */ + halbtc8723b1ant_action_wifi_not_connected(btcoexist); + else + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + bool wifi_connected = false, bt_hs_on = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + halbtc8723b1ant_action_wifi_not_connected_asso_auth_scan(btcoexist); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (!wifi_connected) /* non-connected scan */ + halbtc8723b1ant_action_wifi_not_connected(btcoexist); + else + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] ={0}; + u32 wifi_bw; + u8 wifiCentralChnl; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled ) + return; + + if (BTC_MEDIA_CONNECT == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifiCentralChnl); + + if ((BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14)) { + h2c_parameter[0] = 0x0; + h2c_parameter[1] = wifiCentralChnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66=0x%x\n", + h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | + h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + bool bt_hs_on = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + coex_sta->special_pkt_period_cnt = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], special Packet(%d) notify\n", type); + halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist); + } +} + +void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + bool wifi_connected = false; + bool bt_busy = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8723B_1ANT_MAX) + rsp_source = BT_INFO_SRC_8723B_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length=%d, hex data=[", + rsp_source, length); + for (i=0; ibt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmp_buf[i]); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmp_buf[i]); + } + + if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + /* Here we need to resend some wifi info to BT + * because bt is reset and loss of the info.*/ + if(coex_sta->bt_info_ext & BIT1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit1 check, " + "send wifi BW&Chnl to BT!!\n"); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if(wifi_connected) + ex_halbtc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_CONNECT); + else + ex_halbtc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); + } + + if (coex_sta->bt_info_ext & BIT3) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit3 check, " + "set BT NOT ignore Wlan active!!\n"); + halbtc8723b1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, + false); + } + } else { + /* BT already NOT ignore Wlan active, do nothing here.*/ + } +#if(BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + if (coex_sta->bt_info_ext & BIT4) { + /* BT auto report already enabled, do nothing */ + } else { + halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); + } +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8723b1ant_update_bt_link_info(btcoexist); + + if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "BT Non-Connected idle!!!\n"); + /* connection exists but no busy */ + } else if (bt_info == BT_INFO_8723B_1ANT_B_CONNECTION) { + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "BT SCO busy!!!\n"); + } else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->auto_tdma_adjust = false; + + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = + BT_8723B_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n"); + } + + if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8723b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + + btcoexist->stop_coex_dm = true; + + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false, true); + + halbtc8723b1ant_wifi_off_hw_cfg(btcoexist); + halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Pnp notify\n"); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Pnp notify to SLEEP\n"); + btcoexist->stop_coex_dm = true; + halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Pnp notify to WAKE UP\n"); + btcoexist->stop_coex_dm = false; + halbtc8723b1ant_init_hw_config(btcoexist, false); + halbtc8723b1ant_init_coex_dm(btcoexist); + halbtc8723b1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + static u8 dis_ver_info_cnt = 0; + u32 fw_ver = 0, bt_patch_ver = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], ==========================" + "Periodical===========================\n"); + + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], *************************" + "***************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Ant PG Num/ Ant Mech/ " + "Ant Pos = %d/ %d/ %d\n", \ + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((stack_info->profile_notified)? "Yes":"No"), + stack_info->hci_version); + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], CoexVer/ FwVer/ PatchVer " + "= %d_%x/ 0x%x/ 0x%x(%d)\n", \ + glcoex_ver_date_8723b_1ant, + glcoex_ver_8723b_1ant, fw_ver, + bt_patch_ver, bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], *****************************" + "***********************************\n"); + } + +#if(BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + halbtc8723b1ant_query_bt_info(btcoexist); + halbtc8723b1ant_monitor_bt_ctr(btcoexist); + halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); +#else + if (halbtc8723b1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) { + if (coex_sta->special_pkt_period_cnt > 2) + halbtc8723b1ant_run_coexist_mechanism(btcoexist); + } + + coex_sta->special_pkt_period_cnt++; +#endif +} + + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/rtl_btc.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/rtl_btc.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_BTC_H__ +#define __RTL_BTC_H__ + +#include "halbt_precomp.h" + + + +void rtl_btc_init_variables(struct rtl_priv *rtlpriv); +void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv); +void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv); +void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type); +void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype); +void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action); +void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, enum rt_media_status mstatus); +void rtl_btc_periodical(struct rtl_priv *rtlpriv); +void rtl_btc_halt_notify(void); +void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 * tmpBuf, u8 length); +bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); +bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); + + +//extern struct rtl_btc_ops rtl_btc_operation; +extern struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); + +u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv); +//enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw); + + + + + + + + +#endif --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.h @@ -0,0 +1,145 @@ +/************************************************************************ + * The following is for 8723B 2Ant BT Co-exist definition + ************************************************************************/ +#define BT_AUTO_REPORT_ONLY_8723B_2ANT 1 + + +#define BT_INFO_8723B_2ANT_B_FTP BIT7 +#define BT_INFO_8723B_2ANT_B_A2DP BIT6 +#define BT_INFO_8723B_2ANT_B_HID BIT5 +#define BT_INFO_8723B_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723B_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723B_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723B_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723B_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2 + +typedef enum _BT_INFO_SRC_8723B_2ANT{ + BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_2ANT_MAX +}BT_INFO_SRC_8723B_2ANT,*PBT_INFO_SRC_8723B_2ANT; + +typedef enum _BT_8723B_2ANT_BT_STATUS{ + BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_2ANT_BT_STATUS_MAX +}BT_8723B_2ANT_BT_STATUS,*PBT_8723B_2ANT_BT_STATUS; + +typedef enum _BT_8723B_2ANT_COEX_ALGO{ + BT_8723B_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_2ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_2ANT_COEX_ALGO_HID = 0x2, + BT_8723B_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_2ANT_COEX_ALGO_MAX = 0xb, +}BT_8723B_2ANT_COEX_ALGO,*PBT_8723B_2ANT_COEX_ALGO; + +struct coex_dm_8723b_2ant{ + /* fw mechanism */ + bool pre_dec_bt_pwr; + bool cur_dec_bt_pwr; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + bool reset_tdma_adjust; + bool auto_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + + /* sw mechanism */ + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_back_off; + bool cur_adc_back_off; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + bool need_recover_0x948; + u16 backup_0x948; +}; + +struct coex_sta_8723b_2ant{ + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_lps; + bool under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8723B_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_2ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/********************************************************************* + * The following is interface which will notify coex module. + *********************************************************************/ +void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_periodical(struct btc_coexist * btcoexist); +void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c @@ -0,0 +1,1614 @@ +//============================================================ +// Description: +// +// This file is for RTL8723A Co-exist mechanism +// +// History +// 2012/08/22 Cosa first check in. +// 2012/11/14 Cosa Revise for 8723A 1Ant out sourcing. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8723A_1ANT GLCoexDm8723a1Ant; +static PCOEX_DM_8723A_1ANT pCoexDm=&GLCoexDm8723a1Ant; +static COEX_STA_8723A_1ANT GLCoexSta8723a1Ant; +static PCOEX_STA_8723A_1ANT pCoexSta=&GLCoexSta8723a1Ant; + +const char *const GLBtInfoSrc8723a1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8723a1ant_ +//============================================================ +VOID +halbtc8723a1ant_Reg0x550Bit3( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSet + ) +{ + u1Byte u1tmp=0; + + u1tmp = pBtCoexist->btc_read_1byte(pBtCoexist, 0x550); + if(bSet) + { + u1tmp |= BIT3; + } + else + { + u1tmp &= ~BIT3; + } + pBtCoexist->btc_write_1byte(pBtCoexist, 0x550, u1tmp); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], set 0x550[3]=%d\n", (bSet? 1:0))); +} + +VOID +halbtc8723a1ant_NotifyFwScan( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte scanType + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(BTC_SCAN_START == scanType) + H2C_Parameter[0] = 0x1; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Notify FW for wifi scan, write 0x3b=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x3b, 1, H2C_Parameter); +} + +VOID +halbtc8723a1ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = true; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x38=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x38, 1, H2C_Parameter); +} + +VOID +halbtc8723a1ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xf0ff7); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->initilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8723a1ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8723a1ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8723a1ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->btc_read_1byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->btc_write_1byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8723a1ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8723a1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8723a1ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8723a1ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8723a1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8723a1ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x25=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x25, 1, H2C_Parameter); +} + +VOID +halbtc8723a1ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8723a1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8723a1ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + u1Byte realByte1=byte1, realByte5=byte5; + BOOLEAN bApEnable=FALSE; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); + + // byte1[1:0] != 0 means enable pstdma + // for 2Ant bt coexist, if byte1 != 0 means enable pstdma + if(byte1) + { + if(bApEnable) + { + if(type != 5 && type != 12) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], FW for 1Ant AP mode\n")); + realByte1 &= ~BIT4; + realByte1 |= BIT5; + + realByte5 |= BIT5; + realByte5 &= ~BIT6; + } + } + } + H2C_Parameter[0] = realByte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = realByte5; + + pCoexDm->psTdmaPara[0] = realByte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = realByte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x3a(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x3a, 5, H2C_Parameter); +} + +VOID +halbtc8723a1ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(pCoexDm->bCurPsTdmaOn) + { + switch(pCoexDm->curPsTdma) + { + case 1: + default: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x1a, 0x1a, 0x0, 0x40); + break; + case 2: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x12, 0x12, 0x0, 0x40); + break; + case 3: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x3f, 0x3, 0x10, 0x40); + break; + case 4: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x15, 0x3, 0x10, 0x0); + break; + case 5: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0xa9, 0x15, 0x3, 0x35, 0xc0); + break; + + case 8: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 10: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x5, 0x5, 0x0, 0x40); + break; + case 12: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0xa9, 0xa, 0x3, 0x15, 0xc0); + break; + + case 18: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + + case 20: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x2a, 0x2a, 0x0, 0x0); + break; + case 21: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x20, 0x3, 0x10, 0x40); + break; + case 22: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x1a, 0x1a, 0x2, 0x40); + break; + case 23: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x12, 0x12, 0x2, 0x40); + break; + case 24: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0xa, 0xa, 0x2, 0x40); + break; + case 25: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x5, 0x5, 0x2, 0x40); + break; + case 26: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 27: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x5, 0x5, 0x2, 0x40); + break; + case 28: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x3, 0x2f, 0x2f, 0x0, 0x0); + break; + + } + } + else + { + // disable PS tdma + switch(pCoexDm->curPsTdma) + { + case 8: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x8, 0x0, 0x0, 0x0, 0x0); + break; + case 0: + default: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x0, 0x0, 0x0, 0x0, 0x0); + pBtCoexist->btc_write_2byte(pBtCoexist, 0x860, 0x210); + break; + case 9: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x0, 0x0, 0x0, 0x0, 0x0); + pBtCoexist->btc_write_2byte(pBtCoexist, 0x860, 0x110); + break; + + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + + +VOID +halbtc8723a1ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + // sw all off + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + + // hw all off + halbtc8723a1ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); +} + +VOID +halbtc8723a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); +} + +VOID +halbtc8723a1ant_BtEnableAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); +} + +VOID +halbtc8723a1ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->btc_read_4byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & MASKLWORD; + regHPRx = (u4Tmp & MASKHWORD)>>16; + + u4Tmp = pBtCoexist->btc_read_4byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & MASKLWORD; + regLPRx = (u4Tmp & MASKHWORD)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->btc_write_1byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8723a1ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=true, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = true; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + halbtc8723a1ant_BtEnableAction(pBtCoexist); + } + else + { + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + } + } +} + +VOID +halbtc8723a1ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + u1Byte btState; + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + u4Byte wifiBw; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + btState = pCoexDm->btStatus; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], TdmaDurationAdjust()\n")); + if(pCoexDm->psTdmaGlobalCnt != pCoexDm->psTdmaMonitorCnt) + { + pCoexDm->psTdmaMonitorCnt = 0; + pCoexDm->psTdmaGlobalCnt = 0; + } + if(pCoexDm->psTdmaMonitorCnt == 0) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], first run BT A2DP + WiFi busy state!!\n")); + if(btState == BT_STATE_8723A_1ANT_ACL_ONLY_BUSY) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 22); + pCoexDm->psTdmaDuAdjType = 22; + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], retryCount = %d\n", retryCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if ³sÄò n ­Ó2¬í retry count¬°0, «h½Õ¼eWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if ³sÄò 2 ­Ó2¬í retry count< 3, «h½Õ¯¶WiFi duration + { + if (WaitCount <= 2) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, ¥u­n1¦¸ retry count > 3, «h½Õ¯¶WiFi duration + { + if (WaitCount == 1) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT TxRx counter H+L <= 1200\n")); + if(btState != BT_STATE_8723A_1ANT_ACL_ONLY_BUSY) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], NOT ACL only busy!\n")); + if(BTC_WIFI_BW_HT40 != wifiBw) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], 20MHz\n")); + if(result == -1) + { + if(pCoexDm->curPsTdma == 22) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + else if(pCoexDm->curPsTdma == 23) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 25); + pCoexDm->psTdmaDuAdjType = 25; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 25) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + else if(pCoexDm->curPsTdma == 23) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 22); + pCoexDm->psTdmaDuAdjType = 22; + } + } + // error handle, if not in the following state, + // set psTdma again. + if( (pCoexDm->psTdmaDuAdjType != 22) && + (pCoexDm->psTdmaDuAdjType != 23) && + (pCoexDm->psTdmaDuAdjType != 24) && + (pCoexDm->psTdmaDuAdjType != 25) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], duration case out of handle!!\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], 40MHz\n")); + if(result == -1) + { + if(pCoexDm->curPsTdma == 23) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 25); + pCoexDm->psTdmaDuAdjType = 25; + } + else if(pCoexDm->curPsTdma == 25) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 27); + pCoexDm->psTdmaDuAdjType = 27; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 27) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 25); + pCoexDm->psTdmaDuAdjType = 25; + } + else if(pCoexDm->curPsTdma == 25) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + } + // error handle, if not in the following state, + // set psTdma again. + if( (pCoexDm->psTdmaDuAdjType != 23) && + (pCoexDm->psTdmaDuAdjType != 24) && + (pCoexDm->psTdmaDuAdjType != 25) && + (pCoexDm->psTdmaDuAdjType != 27) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], duration case out of handle!!\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ACL only busy\n")); + if (result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 11) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + } + + // error handle, if not in the following state, + // set psTdma again. + if( (pCoexDm->psTdmaDuAdjType != 1) && + (pCoexDm->psTdmaDuAdjType != 2) && + (pCoexDm->psTdmaDuAdjType != 9) && + (pCoexDm->psTdmaDuAdjType != 11) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], duration case out of handle!!\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } + pCoexDm->psTdmaMonitorCnt++; +} + + +VOID +halbtc8723a1ant_CoexForWifiConnect( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE, bWifiBusy=FALSE; + u1Byte btState, btInfoOriginal=0; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + btState = pCoexDm->btStatus; + btInfoOriginal = pCoexSta->btInfoC2h[BT_INFO_SRC_8723A_1ANT_BT_RSP][0]; + + if(bWifiConnected) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi connected!!\n")); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if( !bWifiBusy && + ((BT_STATE_8723A_1ANT_NO_CONNECTION == btState) || + (BT_STATE_8723A_1ANT_CONNECT_IDLE == btState)) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], [Wifi is idle] or [Bt is non connected idle or Bt is connected idle]!!\n")); + + if(BT_STATE_8723A_1ANT_NO_CONNECTION == btState) + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + else if(BT_STATE_8723A_1ANT_CONNECT_IDLE == btState) + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + pBtCoexist->btc_setBbReg(pBtCoexist, 0x880, 0xff000000, 0xc0); + } + else + { + if( (BT_STATE_8723A_1ANT_SCO_ONLY_BUSY == btState) || + (BT_STATE_8723A_1ANT_ACL_SCO_BUSY == btState) || + (BT_STATE_8723A_1ANT_HID_BUSY == btState) || + (BT_STATE_8723A_1ANT_HID_SCO_BUSY == btState) ) + { + pBtCoexist->btc_setBbReg(pBtCoexist, 0x880, 0xff000000, 0x60); + } + else + { + pBtCoexist->btc_setBbReg(pBtCoexist, 0x880, 0xff000000, 0xc0); + } + switch(btState) + { + case BT_STATE_8723A_1ANT_NO_CONNECTION: + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); + break; + case BT_STATE_8723A_1ANT_CONNECT_IDLE: + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + break; + case BT_STATE_8723A_1ANT_INQ_OR_PAG: + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + break; + case BT_STATE_8723A_1ANT_SCO_ONLY_BUSY: + case BT_STATE_8723A_1ANT_ACL_SCO_BUSY: + case BT_STATE_8723A_1ANT_HID_BUSY: + case BT_STATE_8723A_1ANT_HID_SCO_BUSY: + halbtc8723a1ant_TdmaDurationAdjust(pBtCoexist); + break; + case BT_STATE_8723A_1ANT_ACL_ONLY_BUSY: + if (btInfoOriginal&BT_INFO_8723A_1ANT_B_A2DP) + { + halbtc8723a1ant_TdmaDurationAdjust(pBtCoexist); + } + else if(btInfoOriginal&BT_INFO_8723A_1ANT_B_FTP) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + } + else if( (btInfoOriginal&BT_INFO_8723A_1ANT_B_A2DP) && + (btInfoOriginal&BT_INFO_8723A_1ANT_B_FTP) ) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + } + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], error!!!, undefined case in halbtc8723a1ant_CoexForWifiConnect()!!\n")); + break; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is disconnected!!\n")); + } + + pCoexDm->psTdmaGlobalCnt++; +} + +//============================================================ +// work around function start with wa_halbtc8723a1ant_ +//============================================================ +VOID +wa_halbtc8723a1ant_MonitorC2h( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte tmp1b=0x0; + u4Byte curC2hTotalCnt=0x0; + static u4Byte preC2hTotalCnt=0x0, sameCntPollingTime=0x0; + + curC2hTotalCnt+=pCoexSta->btInfoC2hCnt[BT_INFO_SRC_8723A_1ANT_BT_RSP]; + + if(curC2hTotalCnt == preC2hTotalCnt) + { + sameCntPollingTime++; + } + else + { + preC2hTotalCnt = curC2hTotalCnt; + sameCntPollingTime = 0; + } + + if(sameCntPollingTime >= 2) + { + tmp1b = pBtCoexist->btc_read_1byte(pBtCoexist, 0x1af); + if(tmp1b != 0x0) + { + pCoexSta->c2hHangDetectCnt++; + pBtCoexist->btc_write_1byte(pBtCoexist, 0x1af, 0x0); + } + } +} + +//============================================================ +// extern function start with EXhalbtc8723a1ant_ +//============================================================ +VOID +EXhalbtc8723a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->btc_get_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + pBtCoexist->btc_write_1byte(pBtCoexist, 0x40, 0x20); + + // enable counter statistics + pBtCoexist->btc_write_1byte(pBtCoexist, 0x76e, 0x4); + + // coex table + pBtCoexist->btc_write_1byte(pBtCoexist, 0x6cc, 0x0); // 1-Ant coex + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c8, 0xffff); // wifi break table + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c4, 0x55555555); //coex table + + // antenna switch control parameter + pBtCoexist->btc_write_4byte(pBtCoexist, 0x858, 0xaaaaaaaa); + + pBtCoexist->btc_write_2byte(pBtCoexist, 0x860, 0x210); //set antenna at wifi side if ANTSW is software control + pBtCoexist->btc_write_4byte(pBtCoexist, 0x870, 0x300); //SPDT(connected with TRSW) control by hardware PTA + pBtCoexist->btc_write_4byte(pBtCoexist, 0x874, 0x22804000); //ANTSW keep by GNT_BT + + // coexistence parameters + pBtCoexist->btc_write_1byte(pBtCoexist, 0x778, 0x1); // enable RTK mode PTA +} + +VOID +EXhalbtc8723a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8723a1ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8723a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + struct btc_board_info * pBoardInfo=&pBtCoexist->board_info; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stack_info; + pu1Byte cliBuf=pBtCoexist->cli_buf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(!pBoardInfo->bt_exist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pg_ant_num, pBoardInfo->btdm_ant_num); + CL_PRINTF(cliBuf); + + if(pBtCoexist->manual_control) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cliBuf); + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723A_1ANT_BT_STATUS_IDLE == pCoexDm->btStatus)? "idle":( (BT_8723A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy"))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + if(pStackInfo->bProfileNotified) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_disp_dbg_msg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; ibtInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723a1Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "write 0x1af=0x0 num", \ + pCoexSta->c2hHangDetectCnt); + CL_PRINTF(cliBuf); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "SM1[ShRf/ LpRA/ LimDig]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->limited_dig); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + if(!pBtCoexist->manual_control) + { + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "IgnWlanAct", \ + pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x778); + u1Tmp[1] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x783); + u1Tmp[2] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x796); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/ 0x783/ 0x796", \ + u1Tmp[0], u1Tmp[1], u1Tmp[2]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x880); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x880", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x40); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x484); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x484(rate adaptive)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xda0); + u4Tmp[1] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xda4); + u4Tmp[2] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xda8); + u4Tmp[3] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xdac); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0xda0/0xda4/0xda8/0xdac(FA cnt)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u4Tmp[3]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770 (hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); + + // Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x41b); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x41b (mgntQ hang chk == 0xf)", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_disp_dbg_msg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8723a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + halbtc8723a1ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + //halbtc8723a1ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8723a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + } +} + +VOID +EXhalbtc8723a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE; + + halbtc8723a1ant_NotifyFwScan(pBtCoexist, type); + + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else + { + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!bWifiConnected) // non-connected scan + { + //set 0x550[3]=1 before PsTdma + halbtc8723a1ant_Reg0x550Bit3(pBtCoexist, true); + } + + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8723a1ant_CoexForWifiConnect(pBtCoexist); + } + } + } +} + +VOID +EXhalbtc8723a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE; + + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else + { + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + //set 0x550[3]=1 before PsTdma + halbtc8723a1ant_Reg0x550Bit3(pBtCoexist, true); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); // extend wifi slot + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) // non-connected scan + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8723a1ant_CoexForWifiConnect(pBtCoexist); + } + } + } +} + +VOID +EXhalbtc8723a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } +} + +VOID +EXhalbtc8723a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 18); + } + } +} + +VOID +EXhalbtc8723a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bBtHsOn=FALSE, bBtBusy=FALSE, bForceLps=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = BT_INFO_SRC_8723A_1ANT_BT_RSP; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; ibtInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 0) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8723A_1ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = + pCoexSta->btInfoC2h[rspSource][1]; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][2]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][3]; + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8723A_1ANT_B_INQ_PAGE) + { + pCoexSta->bC2hBtInquiryPage = true; + } + else + { + pCoexSta->bC2hBtInquiryPage = FALSE; + } + btInfo &= ~BIT2; + if(!(btInfo & BIT0)) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_NO_CONNECTION; + bForceLps = FALSE; + } + else + { + bForceLps = true; + if(btInfo == 0x1) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_CONNECT_IDLE; + } + else if(btInfo == 0x9) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_ACL_ONLY_BUSY; + bBtBusy = true; + } + else if(btInfo == 0x13) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_SCO_ONLY_BUSY; + bBtBusy = true; + } + else if(btInfo == 0x1b) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_ACL_SCO_BUSY; + bBtBusy = true; + } + else if(btInfo == 0x29) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_HID_BUSY; + bBtBusy = true; + } + else if(btInfo == 0x3b) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_HID_SCO_BUSY; + bBtBusy = true; + } + } + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bBtBusy); + if(bForceLps) + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + else + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + + if( (BT_STATE_8723A_1ANT_NO_CONNECTION == pCoexDm->btStatus) || + (BT_STATE_8723A_1ANT_CONNECT_IDLE == pCoexDm->btStatus) ) + { + if(pCoexSta->bC2hBtInquiryPage) + pCoexDm->btStatus = BT_STATE_8723A_1ANT_INQ_OR_PAG; + } +} + +VOID +EXhalbtc8723a1ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_STACK_OP_INQ_PAGE_PAIR_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair start notify\n")); + } + else if(BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair finish notify\n")); + } +} + +VOID +EXhalbtc8723a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723a1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, FORCE_EXEC, FALSE); + + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); + EXhalbtc8723a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8723a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE, bWifiConnected=FALSE; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 1Ant Periodical!!\n")); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + // work around for c2h hang + wa_halbtc8723a1ant_MonitorC2h(pBtCoexist); + + halbtc8723a1ant_QueryBtInfo(pBtCoexist); + halbtc8723a1ant_MonitorBtCtr(pBtCoexist); + halbtc8723a1ant_MonitorBtEnableDisable(pBtCoexist); + + + if(bScan) + return; + if(bLink) + return; + + if(bWifiConnected) + { + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + } + else + { + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_CoexForWifiConnect(pBtCoexist); + } + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + } +} + + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c @@ -0,0 +1,4185 @@ +/*************************************************************** + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + **************************************************************/ +/************************************************************** + * include files + **************************************************************/ +#include "halbt_precomp.h" +#if 1 +/************************************************************** + * Global variables, these are static variables + **************************************************************/ +static struct coex_dm_8723b_2ant glcoex_dm_8723b_2ant; +static struct coex_dm_8723b_2ant *coex_dm = &glcoex_dm_8723b_2ant; +static struct coex_sta_8723b_2ant glcoex_sta_8723b_2ant; +static struct coex_sta_8723b_2ant *coex_sta = &glcoex_sta_8723b_2ant; + +const char *const glbt_info_src_8723b_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8723b_2ant = 20131113; +u32 glcoex_ver_8723b_2ant = 0x3f; + +/************************************************************** + * local function proto type if needed + **************************************************************/ +/************************************************************** + * local function start with halbtc8723b2ant_ + **************************************************************/ +u8 halbtc8723b2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to High\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Low\n"); + } + } else { + if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to High\n"); + } else if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Medium\n"); + } + } else { + if (bt_rssi < rssi_thresh1) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at High\n"); + } + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8723b2ant_wifi_rssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 wifi_rssi=0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to High\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Low\n"); + } + } else { + if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if(wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to High\n"); + } else if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Medium\n"); + } + } else { + if (wifi_rssi < rssi_thresh1) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at High\n"); + } + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8723b2ant_monitor_bt_enable_disable(struct btc_coexist *btcoexist) +{ + static bool pre_bt_disabled = false; + static u32 bt_disable_cnt = 0; + bool bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = true; + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is enabled !!\n"); + } else { + bt_disable_cnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is disabled !!\n"); + } + } + + if (pre_bt_disabled != bt_disabled) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is from %s to %s!!\n", + (pre_bt_disabled ? "disabled":"enabled"), + (bt_disabled ? "disabled":"enabled")); + + pre_bt_disabled = bt_disabled; + if (!bt_disabled) { + } else { + } + } +} + +void halbtc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0; + u32 reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], High Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], Low Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +void halbtc8723b2ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] ={0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +bool halbtc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy = false; + static bool pre_under_4way = false; + static bool pre_bt_hs_on = false; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +void halbtc8723b2ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ + /*struct btc_stack_info *stack_info = &btcoexist->stack_info;*/ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) /* profile from bt patch */ + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } +#else /* profile from bt stack */ + bt_link_info->bt_link_exist = stack_info->bt_link_exist; + bt_link_info->sco_exist = stack_info->sco_exist; + bt_link_info->a2dp_exist = stack_info->a2dp_exist; + bt_link_info->pan_exist = stack_info->pan_exist; + bt_link_info->hid_exist = stack_info->hid_exist; + + /*for win-8 stack HID report error*/ + if (!stack_info->hid_exist) + stack_info->hid_exist = coex_sta->hid_exist; + /*sync BTInfo with BT firmware and stack*/ + /* when stack HID report error, here we use the info from bt fw.*/ + if (!stack_info->bt_link_exist) + stack_info->bt_link_exist = coex_sta->bt_link_exist; +#endif + /* check if Sco only */ + if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8723b2ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info=&btcoexist->bt_link_info; + bool bt_hs_on = false; + u8 algorithm = BT_8723B_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO only\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID only\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2DP only\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], PAN(HS) only\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], PAN(EDR) only\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP ==> SCO\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + PAN(HS)\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + PAN(HS)\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2DP + PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex],A2DP + PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + A2DP" + " ==> HID\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + " + "PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + " + "PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP + " + "PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP + " + "PAN(EDR) ==> HID\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP + " + "PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP + " + "PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Error!!! SCO + HID" + " + A2DP + PAN(HS)\n"); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + A2DP +" + " PAN(EDR)==>PAN(EDR)+HID\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +bool halbtc8723b2ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist) +{ + bool bRet = false; + bool bt_hs_on = false, wifi_connected = false; + s32 bt_hs_rssi=0; + u8 bt_rssi_state; + + if (!btcoexist->btc_get(btcoexist, + BTC_GET_BL_HS_OPERATION, &bt_hs_on)) + return false; + if (!btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, &wifi_connected)) + return false; + if (!btcoexist->btc_get(btcoexist, + BTC_GET_S4_HS_RSSI, &bt_hs_rssi)) + return false; + + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + + if (wifi_connected) { + if (bt_hs_on) { + if (bt_hs_rssi > 37) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], Need to decrease bt " + "power for HS mode!!\n"); + bRet = true; + } + } else { + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], Need to decrease bt " + "power for Wifi is connected!!\n"); + bRet = true; + } + } + } + + return bRet; +} + +void halbtc8723b2ant_set_fw_dac_swing_level(struct btc_coexist *btcoexist, + u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] ={0}; + + /* There are several type of dacswing + * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x64=0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8723b2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, + bool dec_bt_pwr) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (dec_bt_pwr) + h2c_parameter[0] |= BIT1; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], decrease Bt Power : %s, FW write 0x62=0x%x\n", + (dec_bt_pwr? "Yes!!":"No!!"), h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8723b2ant_dec_bt_pwr(struct btc_coexist *btcoexist, + bool force_exec, bool dec_bt_pwr) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s Dec BT power = %s\n", + (force_exec? "force to":""), (dec_bt_pwr? "ON":"OFF")); + coex_dm->cur_dec_bt_pwr = dec_bt_pwr; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n", + coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + + if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) + return; + } + halbtc8723b2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr); + + coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +void halbtc8723b2ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (enable_auto_report? "Enabled!!":"Disabled!!"), + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8723b2ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, bool enable_auto_report) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s BT Auto report = %s\n", + (force_exec? "force to":""), + ((enable_auto_report)? "Enabled":"Disabled")); + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreBtAutoReport=%d, " + "bCurBtAutoReport=%d\n", + coex_dm->pre_bt_auto_report, + coex_dm->cur_bt_auto_report); + + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8723b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, + bool force_exec, u8 fw_dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec? "force to":""), fw_dac_swing_lvl); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], preFwDacSwingLvl=%d, " + "curFwDacSwingLvl=%d\n", + coex_dm->pre_fw_dac_swing_lvl, + coex_dm->cur_fw_dac_swing_lvl); + + if(coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8723b2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8723b2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, + bool rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0xffffc); + } else { + /* Resume RF Rx LPF corner */ + /* After initialized, we can use coex_dm->btRf0x1eBackup */ + if (btcoexist->initilized) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, + coex_dm->bt_rf0x1e_backup); + } + } +} + +void halbtc8723b2ant_rf_shrink(struct btc_coexist *btcoexist, + bool force_exec, bool rx_rf_shrink_on) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec? "force to":""), (rx_rf_shrink_on? "ON":"OFF")); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreRfRxLpfShrink=%d, " + "bCurRfRxLpfShrink=%d\n", + coex_dm->pre_rf_rx_lpf_shrink, + coex_dm->cur_rf_rx_lpf_shrink); + + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8723b2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void halbtc8723b2ant_set_sw_penalty_txrate_adaptive( + struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + u8 h2c_parameter[6] ={0}; + + h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty*/ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT0; + /*normal rate except MCS7/6/5, OFDM54/48/36*/ + h2c_parameter[2] = 0x00; + h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54*/ + h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48*/ + h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36*/ + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set WiFi Low-Penalty Retry: %s", + (low_penalty_ra? "ON!!":"OFF!!")); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8723b2ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + /*return; */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn LowPenaltyRA = %s\n", + (force_exec? "force to":""), (low_penalty_ra? "ON":"OFF")); + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreLowPenaltyRa=%d, " + "bCurLowPenaltyRa=%d\n", + coex_dm->pre_low_penalty_ra, + coex_dm->cur_low_penalty_ra); + + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8723b2ant_set_sw_penalty_txrate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8723b2ant_set_dac_swing_reg(struct btc_coexist * btcoexist, + u32 level) +{ + u8 val = (u8) level; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +void halbtc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoexist, + bool sw_dac_swing_on, + u32 sw_dac_swing_lvl) +{ + if(sw_dac_swing_on) + halbtc8723b2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); + else + halbtc8723b2ant_set_dac_swing_reg(btcoexist, 0x18); +} + + +void halbtc8723b2ant_dac_swing(struct btc_coexist *btcoexist, + bool force_exec, bool dac_swing_on, + u32 dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn DacSwing=%s, dac_swing_lvl=0x%x\n", + (force_exec? "force to":""), + (dac_swing_on? "ON":"OFF"), dac_swing_lvl); + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x," + " bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + coex_dm->pre_dac_swing_on, coex_dm->pre_dac_swing_lvl, + coex_dm->cur_dac_swing_on, + coex_dm->cur_dac_swing_lvl); + + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) + return; + } + mdelay(30); + halbtc8723b2ant_set_sw_fulltime_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void halbtc8723b2ant_set_adc_backoff(struct btc_coexist *btcoexist, + bool adc_backoff) +{ + if (adc_backoff) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level On!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x3); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level Off!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x1); + } +} + +void halbtc8723b2ant_adc_backoff(struct btc_coexist *btcoexist, + bool force_exec, bool adc_backoff) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn AdcBackOff = %s\n", + (force_exec? "force to":""), (adc_backoff? "ON":"OFF")); + coex_dm->cur_adc_back_off = adc_backoff; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + coex_dm->pre_adc_back_off, + coex_dm->cur_adc_back_off); + + if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8723b2ant_set_adc_backoff(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +void halbtc8723b2ant_set_agc_table(struct btc_coexist *btcoexist, + bool agc_table_en) +{ + u8 rssi_adjust_val = 0; + + /* BB AGC Gain Table */ + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table On!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6e1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6d1B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6c1C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6b1D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6a1E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x691F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x68200001); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table Off!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001); + } + + + /* RF Gain */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table On!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x38ffe); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table Off!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); + + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table On!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x38ffe); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table Off!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); + + /* set rssiAdjustVal for wifi module. */ + if (agc_table_en) + rssi_adjust_val = 8; + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + &rssi_adjust_val); +} + +void halbtc8723b2ant_agc_table(struct btc_coexist *btcoexist, + bool force_exec, bool agc_table_en) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s %s Agc Table\n", + (force_exec? "force to":""), + (agc_table_en? "Enable":"Disable")); + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en); + + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8723b2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void halbtc8723b2ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8723b2ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, + u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0=0x%x," + " 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (force_exec? "force to":""), val0x6c0, + val0x6c4, val0x6c8, val0x6cc); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], preVal0x6c0=0x%x, " + "preVal0x6c4=0x%x, preVal0x6c8=0x%x, " + "preVal0x6cc=0x%x !!\n", + coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4, + coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], curVal0x6c0=0x%x, " + "curVal0x6c4=0x%x, curVal0x6c8=0x%x, " + "curVal0x6cc=0x%x !!\n", + coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4, + coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc); + + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8723b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8723b2ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + switch (type) { + case 0: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, 0xffff, 0x3); + break; + case 1: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5afa5afa, 0xffff, 0x3); + break; + case 2: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffff, 0x3); + break; + case 3: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, + 0xaaaaaaaa, 0xffff, 0x3); + break; + case 4: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0xffffffff, + 0xffffffff, 0xffff, 0x3); + break; + case 5: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5fff5fff, 0xffff, 0x3); + break; + case 6: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5a5a5a5a, 0xffff, 0x3); + break; + case 7: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5afa5afa, 0xffff, 0x3); + break; + case 8: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x5aea5aea, + 0x5aea5aea, 0xffff, 0x3); + break; + case 9: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5aea5aea, 0xffff, 0x3); + break; + case 10: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5aff5aff, 0xffff, 0x3); + break; + case 11: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5a5f5a5f, 0xffff, 0x3); + break; + case 12: + halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5f5f5f5f, 0xffff, 0x3); + break; + default: + break; + } +} + +void halbtc8723b2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] ={0}; + + if (enable) + h2c_parameter[0] |= BIT0;/* function enable*/ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set FW for BT Ignore Wlan_Act, " + "FW write 0x63=0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8723b2ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec? "force to":""), (enable? "ON":"OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreIgnoreWlanAct = %d, " + "bCurIgnoreWlanAct = %d!!\n", + coex_dm->pre_ignore_wlan_act, + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8723b2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8723b2ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, u8 byte1, + u8 byte2, u8 byte3, u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5] ={0}; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | + h2c_parameter[3] << 8 | h2c_parameter[4]); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8723b2ant_sw_mechanism1(struct btc_coexist *btcoexist, + bool shrink_rx_lpf, bool low_penalty_ra, + bool limited_dig, bool bt_lna_constrain) +{ + /* + u32 wifi_bw; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 != wifi_bw) //only shrink RF Rx LPF for HT40 + { + if (shrink_rx_lpf) + shrink_rx_lpf = false; + } + */ + + halbtc8723b2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); + halbtc8723b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +void halbtc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist, + bool agc_table_shift, bool adc_backoff, + bool sw_dac_swing, u32 dac_swing_lvl) +{ + halbtc8723b2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift); + /*halbtc8723b2ant_adc_backoff(btcoexist, NORMAL_EXEC, adc_backoff);*/ + halbtc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, + dac_swing_lvl); +} + +void halbtc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, + u8 antpos_type, bool init_hwcfg, + bool wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 fw_ver = 0, u32tmp=0; + bool pg_ext_switch = false; + bool use_ext_switch = false; + u8 h2c_parameter[2] ={0}; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + + if ((fw_ver<0xc0000) || pg_ext_switch) + use_ext_switch = true; + + if (init_hwcfg) { + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT23; + u32tmp |= BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + + /* Force GNT_BT to low */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + /* tell firmware "no antenna inverse" */ + h2c_parameter[0] = 0; + h2c_parameter[1] = 1; /* ext switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /* tell firmware "antenna inverse" */ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; /* ext switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* ext switch setting */ + if (use_ext_switch) { + /* fixed internal switch S1->WiFi, S0->BT */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + switch (antpos_type) { + case BTC_ANT_WIFI_AT_MAIN: + /* ext switch main at wifi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x1); + break; + case BTC_ANT_WIFI_AT_AUX: + /* ext switch aux at wifi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, 0x2); + break; + } + } else { /* internal switch */ + /* fixed ext switch */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1); + switch (antpos_type) { + case BTC_ANT_WIFI_AT_MAIN: + /* fixed internal switch S1->WiFi, S0->BT */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + break; + case BTC_ANT_WIFI_AT_AUX: + /* fixed internal switch S0->WiFi, S1->BT */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + break; + } + } +} + + +void halbtc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, + bool turn_on, u8 type) +{ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn %s PS TDMA, type=%d\n", + (force_exec? "force to":""), (turn_on? "ON":"OFF"), type); + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + case 1: + default: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 2: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 3: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10, + 0x03, 0xf1, 0x90); + break; + case 5: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 6: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0x60, 0x90); + break; + case 7: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, + 0x3, 0x70, 0x90); + break; + case 8: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x10, + 0x3, 0x70, 0x90); + break; + case 9: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 10: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 11: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0xa, 0xe1, 0x90); + break; + case 12: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 13: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 14: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0x60, 0x90); + break; + case 15: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0xa, 0x60, 0x90); + break; + case 16: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, + 0x5, 0x60, 0x90); + break; + case 17: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x2f, + 0x2f, 0x60, 0x90); + break; + case 18: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x25, 0x60, 0x90); + break; + case 21: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, + 0x03, 0x70, 0x90); + break; + case 71: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + case 1: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x48, 0x0); + break; + default: + halbtc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8723b2ant_coex_alloff(struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + /* sw all off */ + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism*/ + + halbtc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +void halbtc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + bool wifi_connected = false; + bool low_pwr_disable = true; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (wifi_connected) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + coex_dm->need_recover_0x948 = true; + coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948); + + halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_AUX, + false, false); +} + +bool halbtc8723b2ant_is_common_action(struct btc_coexist *btcoexist) +{ + bool bCommon = false, wifi_connected = false; + bool wifi_busy = false; + bool bt_hs_on = false, low_pwr_disable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non-connected idle!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + bCommon = true; + } else { + if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + " + "BT non connected-idle!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + bCommon = true; + } else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if(bt_hs_on) + return false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + " + "BT connected-idle!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + bCommon = true; + } else { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (wifi_busy) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Busy + " + "BT Busy!!\n"); + bCommon = false; + } else { + if(bt_hs_on) + return false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Idle + " + "BT Busy!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x1, 0xfffff, 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, + 7); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 21); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, + NORMAL_EXEC, + 0xb); + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, + true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, + false); + halbtc8723b2ant_sw_mechanism1(btcoexist, false, + false, false, + false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, + false, false, + 0x18); + bCommon = true; + } + } + } + + return bCommon; +} +void halbtc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, + bool sco_hid, bool tx_pause, + u8 max_interval) +{ + static s32 up, dn, m, n, wait_count; + /*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/ + s32 result; + u8 retryCount=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjust()\n"); + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + }else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } + } else { + if(max_interval == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } + } else { + if (max_interval == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } + } + } + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + wait_count = 0; + } else { + /*accquire the BT TRx retry count from BT_Info byte2*/ + retryCount = coex_sta->bt_retry_cnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], retryCount = %d\n", retryCount); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_count=%d\n", + up, dn, m, n, wait_count); + result = 0; + wait_count++; + /* no retry in the last 2-second duration*/ + if (retryCount == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Increase wifi " + "duration!!\n"); + }/* <=3 retry in the last 2-second duration*/ + } else if (retryCount <= 3) { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + if (wait_count <= 2) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration " + "for retryCounter<3!!\n"); + } + } else { + if (wait_count == 1) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration " + "for retryCounter>3!!\n"); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], max Interval = %d\n", max_interval); + if (max_interval == 1) { + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + + if (coex_dm->cur_ps_tdma == 71) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + + if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if(coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if(coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if(coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if(coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if(coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if(coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + + if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if(coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if(coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if(coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = + 71; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if(max_interval == 2) { + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14){ + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } + } + + /*if current PsTdma not match with the recorded one (when scan, dhcp..), + *then we have to adjust it back to the previous record one.*/ + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { + bool scan = false, link = false, roam = false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], PsTdma type dismatch!!!, " + "curPsTdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (!scan && !link && !roam) + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + else + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], roaming/link/scan is under" + " progress, will adjust next time!!!\n"); + } +} + +/* SCO only or SCO+PAN(HS) */ +void halbtc8723b2ant_action_sco(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + /*for SCO quality at 11b/g mode*/ + if (BTC_WIFI_BW_LEGACY == wifi_bw) + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else /*for SCO quality & wifi performance balance at 11n mode*/ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + /*for voice quality */ + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x4); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + true, 0x4); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x4); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + true, 0x4); + } + } +} + + +void halbtc8723b2ant_action_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_LEGACY == wifi_bw) /*/for HID at 11b/g mode*/ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + else /*for HID quality & wifi performance balance at 11n mode*/ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 9); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + else + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/ +void halbtc8723b2ant_action_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + u8 ap_num = 0; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 1, 2, 40, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + + /* define the office environment */ + /* driver don't know AP num in Linux, so we will never enter this if */ + if (ap_num >= 10 && BTC_RSSI_HIGH(wifi_rssi_state1)) { + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } + return; + } + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b2ant_tdma_duration_adjust(btcoexist,false, false, 1); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist,false, true, 1); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 2); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false,0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 10); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + else + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + + +/*PAN(HS) only*/ +void halbtc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/*PAN(EDR)+A2DP*/ +void halbtc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_coex_table_with_type(btcoexist,NORMAL_EXEC, 12); + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, + true, 3); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, + false, 3); + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) { + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 3); + halbtc8723b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 11); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x780); + } else { + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + halbtc8723b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + } + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } else { + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_coex_table_with_type(btcoexist,NORMAL_EXEC, 11); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)){ + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 2); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 3); + } else { + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), " + "return for Manual CTRL <===\n"); + return; + } + + if (coex_sta->under_ips) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + algorithm = halbtc8723b2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8723B_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + halbtc8723b2ant_action_bt_inquiry(btcoexist); + return; + } else { + if (coex_dm->need_recover_0x948) { + coex_dm->need_recover_0x948 = false; + btcoexist->btc_write_2byte(btcoexist, 0x948, + coex_dm->backup_0x948); + } + } + + coex_dm->cur_algorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Algorithm = %d \n", + coex_dm->cur_algorithm); + + if (halbtc8723b2ant_is_common_action(btcoexist)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant common.\n"); + coex_dm->auto_tdma_adjust = false; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], preAlgorithm=%d, " + "curAlgorithm=%d\n", coex_dm->pre_algorithm, + coex_dm->cur_algorithm); + coex_dm->auto_tdma_adjust = false; + } + switch (coex_dm->cur_algorithm) { + case BT_8723B_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + halbtc8723b2ant_action_sco(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + halbtc8723b2ant_action_hid(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = A2DP.\n"); + halbtc8723b2ant_action_a2dp(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = A2DP+PAN(HS).\n"); + halbtc8723b2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = PAN(EDR).\n"); + halbtc8723b2ant_action_pan_edr(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = HS mode.\n"); + halbtc8723b2ant_action_pan_hs(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = PAN+A2DP.\n"); + halbtc8723b2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = PAN(EDR)+HID.\n"); + halbtc8723b2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = HID+A2DP+PAN.\n"); + halbtc8723b2ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = HID+A2DP.\n"); + halbtc8723b2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = coexist All Off!!\n"); + halbtc8723b2ant_coex_alloff(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist) +{ + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + /* Force GNT_BT to High */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); + /* BT select s0/s1 is controlled by BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); +} + +/********************************************************************* + * work around function start with wa_halbtc8723b2ant_ + *********************************************************************/ +/********************************************************************* + * extern function start with EXhalbtc8723b2ant_ + *********************************************************************/ +void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + u8 u8tmp = 0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 2Ant Init HW Config!!\n"); + coex_dm->bt_rf0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + + /*Antenna config */ + halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, + true, false); + + + + + /* PTA parameter */ + halbtc8723b2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + /* Enable counter statistics */ + /*0x76e[3] =1, WLAN_Act control by PTA*/ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + halbtc8723b2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info* bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case=0; + u32 u32tmp[4]; + bool roam = false, scan = false; + bool link = false, wifi_under_5g = false; + bool bt_hs_on = false, wifi_busy = false; + s32 wifi_rssi = 0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck; + u8 wifi_dot11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + u8 ap_num = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ==========[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((stack_info->profile_notified)? "Yes":"No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", + "CoexVer/ fw_ver/ PatchVer", + glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, + &wifi_dot11_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(HsMode)", + wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], + coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + "Wifi status", (wifi_under_5g? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY == wifi_bw)? "Legacy": + (((BTC_WIFI_BW_HT40 == wifi_bw)? "HT40":"HT20"))), + ((!wifi_busy)? "idle": + ((BTC_WIFI_TRAFFIC_TX ==wifi_traffic_dir)?\ + "uplink":"downlink"))); + CL_PRINTF(cli_buf); + + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cli_buf); + + for (i=0; ibt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x " + "%02x %02x %02x %02x(%d)", + glbt_info_src_8723b_2ant[i], \ + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + "PS state, IPS/LPS", + ((coex_sta->under_ips? "IPS ON":"IPS OFF")), + ((coex_sta->under_lps? "LPS ON":"LPS OFF"))); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, + coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", coex_dm->ps_tdma_para[0], + coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], + coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], + ps_tdma_case, coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr, + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x880[29:25]", u8tmp[0], + (u32tmp[0]&0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x948/ 0x67[5] / 0x765", + u32tmp[0], ((u8tmp[0]&0x20)>> 5), u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", + u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x38[11]/0x40/0x4c[24:23]/0x64[0]", + ((u8tmp[0] & 0x8)>>3), u8tmp[1], + ((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8); + u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + + fa_ofdm = ((u32tmp[0]&0xffff0000) >> 16) + + ((u32tmp[1]&0xffff0000) >> 16) + + (u32tmp[1] & 0xffff) + + (u32tmp[2] & 0xffff) + + ((u32tmp[3]&0xffff0000) >> 16) + + (u32tmp[3] & 0xffff) ; + fa_cck = (u8tmp[0] << 8) + u8tmp[1]; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "OFDM-CCA/OFDM-FA/CCK-FA", \ + u32tmp[0]&0xffff, fa_ofdm, fa_cck); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, + coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) + halbtc8723b2ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, + BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + halbtc8723b2ant_wifioff_hwcfg(btcoexist); + halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + halbtc8723b2ant_coex_alloff(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + ex_halbtc8723b2ant_init_hwconfig(btcoexist); + halbtc8723b2ant_init_coex_dm(btcoexist); + halbtc8723b2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_SCAN_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + else if (BTC_SCAN_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); +} + +void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_ASSOCIATE_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + else if (BTC_ASSOCIATE_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); +} + +void ex_halbtc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] ={0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + if (BTC_MEDIA_CONNECT == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, + BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66=0x%x\n", + h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | + h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + if (type == BTC_PACKET_DHCP) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], DHCP Packet notify\n"); +} + +void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length) +{ + u8 btInfo = 0; + u8 i, rsp_source = 0; + bool bt_busy = false, limited_dig = false; + bool wifi_connected = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmpbuf[0]&0xf; + if(rsp_source >= BT_INFO_SRC_8723B_2ANT_MAX) + rsp_source = BT_INFO_SRC_8723B_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length=%d, hex data=[", + rsp_source, length); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmpbuf[i]; + if (i == 1) + btInfo = tmpbuf[i]; + if (i == length-1) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmpbuf[i]); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmpbuf[i]); + } + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "return for Manual CTRL<===\n"); + return; + } + + if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0]*/ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + /* Here we need to resend some wifi info to BT + because bt is reset and loss of the info.*/ + if ((coex_sta->bt_info_ext & BIT1)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit1 check," + " send wifi BW&Chnl to BT!!\n"); + btcoexist->btc_get(btcoexist,BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8723b2ant_media_status_notify( + btcoexist, + BTC_MEDIA_CONNECT); + else + ex_halbtc8723b2ant_media_status_notify( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT3)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit3 check, " + "set BT NOT to ignore Wlan active!!\n"); + halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, + false); + } else { + /* BT already NOT ignore Wlan active, do nothing here.*/ + } +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + if ((coex_sta->bt_info_ext & BIT4)) { + /* BT auto report already enabled, do nothing*/ + } else { + halbtc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); + } +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan*/ + if (btInfo & BT_INFO_8723B_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status*/ + if (!(btInfo & BT_INFO_8723B_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else {// connection exists + coex_sta->bt_link_exist = true; + if (btInfo & BT_INFO_8723B_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (btInfo & BT_INFO_8723B_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (btInfo & BT_INFO_8723B_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8723b2ant_update_bt_link_info(btcoexist); + + if (!(btInfo & BT_INFO_8723B_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "BT Non-Connected idle!!!\n"); + /* connection exists but no busy */ + } else if (btInfo == BT_INFO_8723B_2ANT_B_CONNECTION) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if ((btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) || + (btInfo & BT_INFO_8723B_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = + BT_8723B_2ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (btInfo&BT_INFO_8723B_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = + BT_8723B_2ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "BT Non-Defined state!!!\n"); + } + + if ((BT_8723B_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8723b2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + + halbtc8723b2ant_wifioff_hwcfg(btcoexist); + halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + ex_halbtc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + static u8 dis_ver_info_cnt = 0; + u32 fw_ver = 0, bt_patch_ver = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], ==========================" + "Periodical===========================\n"); + + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************" + "************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Ant PG Num/ Ant Mech/ " + "Ant Pos = %d/ %d/ %d\n", board_info->pg_ant_num, + board_info->btdm_ant_num, board_info->btdm_ant_pos); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], BT stack/ hci ext ver = %s / %d\n", + ((stack_info->profile_notified)? "Yes":"No"), + stack_info->hci_version); + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], CoexVer/ fw_ver/ PatchVer = " + "%d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], *****************************" + "***********************************\n"); + } + +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + halbtc8723b2ant_query_bt_info(btcoexist); + halbtc8723b2ant_monitor_bt_ctr(btcoexist); + halbtc8723b2ant_monitor_bt_enable_disable(btcoexist); +#else + if (halbtc8723b2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + halbtc8723b2ant_run_coexist_mechanism(btcoexist); +#endif +} + + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.h @@ -0,0 +1,162 @@ +/***************************************************************** + * The following is for 8192E 2Ant BT Co-exist definition + *****************************************************************/ +#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0 + +#define BT_INFO_8192E_2ANT_B_FTP BIT7 +#define BT_INFO_8192E_2ANT_B_A2DP BIT6 +#define BT_INFO_8192E_2ANT_B_HID BIT5 +#define BT_INFO_8192E_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8192E_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8192E_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8192E_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8192E_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT 2 + +enum bt_info_src_8192e_2ant{ + BT_INFO_SRC_8192E_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192E_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192E_2ANT_MAX +}; + +enum bt_8192e_2ant_bt_status{ + BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192E_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8192E_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8192E_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8192E_2ANT_BT_STATUS_MAX +}; + +enum bt_8192e_2ant_coex_algo{ + BT_8192E_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192E_2ANT_COEX_ALGO_SCO = 0x1, + BT_8192E_2ANT_COEX_ALGO_SCO_PAN = 0x2, + BT_8192E_2ANT_COEX_ALGO_HID = 0x3, + BT_8192E_2ANT_COEX_ALGO_A2DP = 0x4, + BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS = 0x5, + BT_8192E_2ANT_COEX_ALGO_PANEDR = 0x6, + BT_8192E_2ANT_COEX_ALGO_PANHS = 0x7, + BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8, + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID = 0x9, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP = 0xb, + BT_8192E_2ANT_COEX_ALGO_MAX = 0xc +}; + +struct coex_dm_8192e_2ant{ + /* fw mechanism */ + u8 pre_dec_bt_pwr; + u8 cur_dec_bt_pwr; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + bool reset_tdma_adjust; + bool auto_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + + /* sw mechanism */ + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_back_off; + bool cur_adc_back_off; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retrylimit; + u8 backup_ampdu_maxtime; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u8 pre_sstype; + u8 cur_sstype; + + u32 prera_mask; + u32 curra_mask; + u8 curra_masktype; + u8 pre_arfrtype; + u8 cur_arfrtype; + u8 pre_retrylimit_type; + u8 cur_retrylimit_type; + u8 pre_ampdutime_type; + u8 cur_ampdutime_type; +}; + +struct coex_sta_8192e_2ant{ + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_lps; + bool under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8192E_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_2ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/**************************************************************** + * The following is interface which will notify coex module. + ****************************************************************/ +void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpBuf,u8 length); +void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist); + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.h @@ -0,0 +1,176 @@ +//=========================================== +// The following is for 8723A 1Ant BT Co-exist definition +//=========================================== +#define BT_INFO_8723A_1ANT_B_FTP BIT7 +#define BT_INFO_8723A_1ANT_B_A2DP BIT6 +#define BT_INFO_8723A_1ANT_B_HID BIT5 +#define BT_INFO_8723A_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723A_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723A_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723A_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723A_1ANT_B_CONNECTION BIT0 + +typedef enum _BT_STATE_8723A_1ANT{ + BT_STATE_8723A_1ANT_DISABLED = 0, + BT_STATE_8723A_1ANT_NO_CONNECTION = 1, + BT_STATE_8723A_1ANT_CONNECT_IDLE = 2, + BT_STATE_8723A_1ANT_INQ_OR_PAG = 3, + BT_STATE_8723A_1ANT_ACL_ONLY_BUSY = 4, + BT_STATE_8723A_1ANT_SCO_ONLY_BUSY = 5, + BT_STATE_8723A_1ANT_ACL_SCO_BUSY = 6, + BT_STATE_8723A_1ANT_HID_BUSY = 7, + BT_STATE_8723A_1ANT_HID_SCO_BUSY = 8, + BT_STATE_8723A_1ANT_MAX +}BT_STATE_8723A_1ANT, *PBT_STATE_8723A_1ANT; + +#define BTC_RSSI_COEX_THRESH_TOL_8723A_1ANT 2 + +typedef enum _BT_INFO_SRC_8723A_1ANT{ + BT_INFO_SRC_8723A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723A_1ANT_MAX +}BT_INFO_SRC_8723A_1ANT,*PBT_INFO_SRC_8723A_1ANT; + +typedef enum _BT_8723A_1ANT_BT_STATUS{ + BT_8723A_1ANT_BT_STATUS_IDLE = 0x0, + BT_8723A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723A_1ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8723A_1ANT_BT_STATUS_MAX +}BT_8723A_1ANT_BT_STATUS,*PBT_8723A_1ANT_BT_STATUS; + +typedef enum _BT_8723A_1ANT_COEX_ALGO{ + BT_8723A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8723A_1ANT_COEX_ALGO_HID = 0x2, + BT_8723A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8723A_1ANT_COEX_ALGO_PANEDR = 0x4, + BT_8723A_1ANT_COEX_ALGO_PANHS = 0x5, + BT_8723A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x6, + BT_8723A_1ANT_COEX_ALGO_PANEDR_HID = 0x7, + BT_8723A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x8, + BT_8723A_1ANT_COEX_ALGO_HID_A2DP = 0x9, + BT_8723A_1ANT_COEX_ALGO_MAX +}BT_8723A_1ANT_COEX_ALGO,*PBT_8723A_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8723A_1ANT{ + // fw mechanism + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + u4Byte psTdmaMonitorCnt; + u4Byte psTdmaGlobalCnt; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN limited_dig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; +} COEX_DM_8723A_1ANT, *PCOEX_DM_8723A_1ANT; + +typedef struct _COEX_STA_8723A_1ANT{ + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preBtRssiState1; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8723A_1ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8723A_1ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; + //BOOLEAN bHoldForStackOperation; + //u1Byte bHoldPeriodCnt; + // this is for c2h hang work-around + u4Byte c2hHangDetectCnt; +}COEX_STA_8723A_1ANT, *PCOEX_STA_8723A_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8723a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8723a1ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/rtl_btc.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/rtl_btc.c @@ -0,0 +1,236 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#include +#include + +#include "rtl_btc.h" +#include "halbt_precomp.h" + +struct rtl_btc_ops rtl_btc_operation ={ + .btc_init_variables = rtl_btc_init_variables, + .btc_init_hal_vars = rtl_btc_init_hal_vars, + .btc_init_hw_config = rtl_btc_init_hw_config, + .btc_ips_notify = rtl_btc_ips_notify, + .btc_scan_notify = rtl_btc_scan_notify, + .btc_connect_notify = rtl_btc_connect_notify, + .btc_mediastatus_notify = rtl_btc_mediastatus_notify, + .btc_periodical = rtl_btc_periodical, + .btc_halt_notify = rtl_btc_halt_notify, + .btc_btinfo_notify = rtl_btc_btinfo_notify, + .btc_is_limited_dig = rtl_btc_is_limited_dig, + .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo, + .btc_is_bt_disabled = rtl_btc_is_bt_disabled, +}; + + +void rtl_btc_init_variables(struct rtl_priv *rtlpriv) +{ + + exhalbtc_initlize_variables(rtlpriv); +} + +void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) +{ + u8 ant_num; + u8 bt_exist; + u8 bt_type; + ant_num = rtl_get_hwpg_ant_num(rtlpriv); + RT_TRACE(COMP_INIT, DBG_DMESG, ("%s, antNum is %d\n", __func__, ant_num)); + + bt_exist = rtl_get_hwpg_bt_exist(rtlpriv); + RT_TRACE(COMP_INIT, DBG_DMESG, ("%s, bt_exist is %d\n", __func__, bt_exist)); + exhalbtc_set_bt_exist(bt_exist); + + bt_type = rtl_get_hwpg_bt_type(rtlpriv); + RT_TRACE(COMP_INIT, DBG_DMESG, ("%s, bt_type is %d\n", __func__, bt_type)); + exhalbtc_set_chip_type(bt_type); + + exhalbtc_set_ant_num(BT_COEX_ANT_TYPE_PG, ant_num); + +} + + +void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) +{ + exhalbtc_init_hw_config(&gl_bt_coexist); + exhalbtc_init_coex_dm(&gl_bt_coexist); +} + + +void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type) +{ + exhalbtc_ips_notify(&gl_bt_coexist, type); +} + + +void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype) +{ + exhalbtc_scan_notify(&gl_bt_coexist, scantype); +} + + +void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action) +{ + exhalbtc_connect_notify(&gl_bt_coexist, action); +} + + +void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, enum rt_media_status mstatus) +{ + exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus); +} + +void rtl_btc_periodical(struct rtl_priv *rtlpriv) +{ +// rtl_bt_dm_monitor(); + exhalbtc_periodical(&gl_bt_coexist); +} + +void rtl_btc_halt_notify(void) +{ + exhalbtc_halt_notify(&gl_bt_coexist); +} + +void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 * tmp_buf, u8 length) +{ + exhalbtc_bt_info_notify(&gl_bt_coexist, tmp_buf, length); +} + +bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.limited_dig; +} + +bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv) +{ + bool bt_change_edca = false; + u32 cur_edca_val; + u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b; + u32 edca_hs; + u32 edca_addr = 0x504; + + cur_edca_val = rtl_read_dword(rtlpriv, edca_addr); + if (halbtc_is_wifi_uplink(rtlpriv)){ + if (cur_edca_val != edca_bt_hs_uplink){ + edca_hs = edca_bt_hs_uplink; + bt_change_edca = true; + } + }else{ + if (cur_edca_val != edca_bt_hs_downlink){ + edca_hs = edca_bt_hs_downlink; + bt_change_edca = true; + } + } + + if(bt_change_edca) + rtl_write_dword(rtlpriv, edca_addr, edca_hs); + + return true; +} + +bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv) +{ + if (gl_bt_coexist.bt_info.bt_disabled) + return true; + else + return false; +} + +struct rtl_btc_ops *rtl_btc_get_ops_pointer(void) +{ + return &rtl_btc_operation; +} +//EXPORT_SYMBOL(rtl_btc_get_ops_pointer); + +u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv) +{ + u8 num; + + if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2) + num = 2; + else + num = 1; + + return num; +} + +#if 0 +enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum rt_media_status m_status = RT_MEDIA_DISCONNECT; + + u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + + if(bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED) { + m_status = RT_MEDIA_CONNECT; + } + + return m_status; +} +#endif + +u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv) +{ + return rtlpriv->btcoexist.btc_info.btcoexist; +} + +u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv) +{ + return rtlpriv->btcoexist.btc_info.bt_type; +} + + +#if 0 + +MODULE_AUTHOR("Page He "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_AUTHOR("Larry Finger "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); + +static int __init rtl_btcoexist_module_init(void) +{ + + //printk("%s, rtlpriv->btc_ops.btc_init_variables addr is %p\n", __func__, rtlpriv->btc_ops.btc_init_variables); + + return 0; +} + +static void __exit rtl_btcoexist_module_exit(void) +{ + return; +} + +module_init(rtl_btcoexist_module_init); +module_exit(rtl_btcoexist_module_exit); + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c @@ -0,0 +1,3891 @@ +//============================================================ +// Description: +// +// This file is for 8192e1ant Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8192E_1ANT GLCoexDm8192e1Ant; +static PCOEX_DM_8192E_1ANT pCoexDm=&GLCoexDm8192e1Ant; +static COEX_STA_8192E_1ANT GLCoexSta8192e1Ant; +static PCOEX_STA_8192E_1ANT pCoexSta=&GLCoexSta8192e1Ant; + +const char *const GLBtInfoSrc8192e1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8192e1Ant=20130729; +u4Byte GLCoexVer8192e1Ant=0x10; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8192e1ant_ +//============================================================ +u1Byte +halbtc8192e1ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8192e1ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8192e1ant_Updatera_mask( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type, + IN u4Byte rateMask + ) +{ + if(BTC_RATE_DISABLE == type) + { + pCoexDm->curra_mask |= rateMask; // disable rate + } + else if(BTC_RATE_ENABLE == type) + { + pCoexDm->curra_mask &= ~rateMask; // enable rate + } + + if( bForceExec || (pCoexDm->prera_mask != pCoexDm->curra_mask)) + { + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_UPDATE_ra_mask, &pCoexDm->curra_mask); + } + pCoexDm->prera_mask = pCoexDm->curra_mask; +} + +VOID +halbtc8192e1ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->btc_read_4byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & MASKLWORD; + regHPRx = (u4Tmp & MASKHWORD)>>16; + + u4Tmp = pBtCoexist->btc_read_4byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & MASKLWORD; + regLPRx = (u4Tmp & MASKHWORD)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->btc_write_1byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8192e1ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = true; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x61, 1, H2C_Parameter); +} + +BOOLEAN +halbtc8192e1ant_IsWifiStatusChanged( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreWifiBusy=FALSE, bPreUnder4way=FALSE, bPreBtHsOn=FALSE; + BOOLEAN bWifiBusy=FALSE, bUnder4way=FALSE, bBtHsOn=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + + if(bWifiConnected) + { + if(bWifiBusy != bPreWifiBusy) + { + bPreWifiBusy = bWifiBusy; + return true; + } + if(bUnder4way != bPreUnder4way) + { + bPreUnder4way = bUnder4way; + return true; + } + if(bBtHsOn != bPreBtHsOn) + { + bPreBtHsOn = bBtHsOn; + return true; + } + } + + return FALSE; +} + +VOID +halbtc8192e1ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = true; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = true; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = true; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = true; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8192e1ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8192E_1ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +VOID +halbtc8192e1ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x64, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte decBtPwrLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = decBtPwrLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power level = %d, FW write 0x62=0x%x\n", + decBtPwrLvl, H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x62, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte decBtPwrLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power level = %d\n", + (bForceExec? "force to":""), decBtPwrLvl)); + pCoexDm->curBtDecPwrLvl = decBtPwrLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], BtDecPwrLvl=%d, curBtDecPwrLvl=%d\n", + pCoexDm->preBtDecPwrLvl, pCoexDm->curBtDecPwrLvl)); + + if(pCoexDm->preBtDecPwrLvl == pCoexDm->curBtDecPwrLvl) + return; + } + halbtc8192e1ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->curBtDecPwrLvl); + + pCoexDm->preBtDecPwrLvl = pCoexDm->curBtDecPwrLvl; +} + +VOID +halbtc8192e1ant_SetFwBtLnaConstrain( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBtLnaConsOn + ) +{ + u1Byte H2C_Parameter[2] ={0}; + + H2C_Parameter[0] = 0x3; // opCode, 0x3=BT_SET_LNA_CONSTRAIN + + if(bBtLnaConsOn) + { + H2C_Parameter[1] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set BT LNA Constrain: %s, FW write 0x69=0x%x\n", + (bBtLnaConsOn? "ON!!":"OFF!!"), + H2C_Parameter[0]<<8|H2C_Parameter[1])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x69, 2, H2C_Parameter); +} + +VOID +halbtc8192e1ant_SetBtLnaConstrain( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bBtLnaConsOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Constrain = %s\n", + (bForceExec? "force":""), ((bBtLnaConsOn)? "ON":"OFF"))); + pCoexDm->bCurBtLnaConstrain = bBtLnaConsOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtLnaConstrain=%d, bCurBtLnaConstrain=%d\n", + pCoexDm->bPreBtLnaConstrain, pCoexDm->bCurBtLnaConstrain)); + + if(pCoexDm->bPreBtLnaConstrain == pCoexDm->bCurBtLnaConstrain) + return; + } + halbtc8192e1ant_SetFwBtLnaConstrain(pBtCoexist, pCoexDm->bCurBtLnaConstrain); + + pCoexDm->bPreBtLnaConstrain = pCoexDm->bCurBtLnaConstrain; +} + +VOID +halbtc8192e1ant_SetFwBtPsdMode( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte btPsdMode + ) +{ + u1Byte H2C_Parameter[2] ={0}; + + H2C_Parameter[0] = 0x2; // opCode, 0x2=BT_SET_PSD_MODE + + H2C_Parameter[1] = btPsdMode; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set BT PSD mode=0x%x, FW write 0x69=0x%x\n", + H2C_Parameter[1], + H2C_Parameter[0]<<8|H2C_Parameter[1])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x69, 2, H2C_Parameter); +} + + +VOID +halbtc8192e1ant_SetBtPsdMode( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte btPsdMode + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT PSD mode = 0x%x\n", + (bForceExec? "force":""), btPsdMode)); + pCoexDm->bCurBtPsdMode = btPsdMode; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtPsdMode=0x%x, bCurBtPsdMode=0x%x\n", + pCoexDm->bPreBtPsdMode, pCoexDm->bCurBtPsdMode)); + + if(pCoexDm->bPreBtPsdMode == pCoexDm->bCurBtPsdMode) + return; + } + halbtc8192e1ant_SetFwBtPsdMode(pBtCoexist, pCoexDm->bCurBtPsdMode); + + pCoexDm->bPreBtPsdMode = pCoexDm->bCurBtPsdMode; +} + + +VOID +halbtc8192e1ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bEnableAutoReport) + { + H2C_Parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (bEnableAutoReport? "Enabled!!":"Disabled!!"), H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x68, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8192e1ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8192e1ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8192e1ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8192e1ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xf0ff7); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->initilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8192e1ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8192e1ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8192e1ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->btc_read_1byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->btc_write_1byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8192e1ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8192e1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8192e1ant_SetDacSwingReg( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte level + ) +{ + u1Byte val=(u1Byte)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); + pBtCoexist->btc_write_1byte_bitmask(pBtCoexist, 0x883, 0x3e, val); +} + +VOID +halbtc8192e1ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + halbtc8192e1ant_SetDacSwingReg(pBtCoexist, swDacSwingLvl); + } + else + { + halbtc8192e1ant_SetDacSwingReg(pBtCoexist, 0x18); + } +} + + +VOID +halbtc8192e1ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + mdelay(30); + halbtc8192e1ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8192e1ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->btc_write_1byte_bitmask(pBtCoexist, 0x8db, 0x60, 0x3); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->btc_write_1byte_bitmask(pBtCoexist, 0x8db, 0x60, 0x1); + } +} + +VOID +halbtc8192e1ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8192e1ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8192e1ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x3fa58); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x37a58); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x2fa58); + rssiAdjustVal = 8; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x39258); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x31258); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x29258); + } + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + // set rssiAdjustVal for wifi module. + pBtCoexist->btc_set(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + + +VOID +halbtc8192e1ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8192e1ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8192e1ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8192e1ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8192e1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8192e1ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + switch(type) + { + case 0: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0xffffffff, 0xffffffff, 0xffffff, 0x3); + break; + case 5: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x5fff5fff, 0x5fff5fff, 0xffffff, 0x3); + break; + case 6: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0xddffddff, 0xddffddff, 0xffffff, 0x3); + break; + case 8: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5afa5afa, 0xffffff, 0x3); + break; + case 9: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x5f5f5f5f, 0x5f5f5f5f, 0xffffff, 0x3); + break; + default: + break; + } +} + +VOID +halbtc8192e1ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x63, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8192e1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8192e1ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8192e1ant_SetLpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + u1Byte lps=lpsVal; + u1Byte rpwm=rpwmVal; + + pBtCoexist->btc_set(pBtCoexist, BTC_SET_U1_1ANT_LPS, &lps); + pBtCoexist->btc_set(pBtCoexist, BTC_SET_U1_1ANT_RPWM, &rpwm); +} + +VOID +halbtc8192e1ant_LpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bForceExecPwrCmd=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (bForceExec? "force to":""), lpsVal, rpwmVal)); + pCoexDm->curLps = lpsVal; + pCoexDm->curRpwm = rpwmVal; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preLps/curLps=0x%x/0x%x, preRpwm/curRpwm=0x%x/0x%x!!\n", + pCoexDm->preLps, pCoexDm->curLps, pCoexDm->preRpwm, pCoexDm->curRpwm)); + + if( (pCoexDm->preLps == pCoexDm->curLps) && + (pCoexDm->preRpwm == pCoexDm->curRpwm) ) + { + return; + } + } + halbtc8192e1ant_SetLpsRpwm(pBtCoexist, lpsVal, rpwmVal); + + pCoexDm->preLps = pCoexDm->curLps; + pCoexDm->preRpwm = pCoexDm->curRpwm; +} + +VOID +halbtc8192e1ant_SwMechanism1( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bShrinkRxLPF, + IN BOOLEAN bLowPenaltyRA, + IN BOOLEAN limited_dig, + IN BOOLEAN bBTLNAConstrain + ) +{ + //halbtc8192e1ant_RfShrink(pBtCoexist, NORMAL_EXEC, bShrinkRxLPF); + //halbtc8192e1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); + + //no limited DIG + //halbtc8192e1ant_SetBtLnaConstrain(pBtCoexist, NORMAL_EXEC, bBTLNAConstrain); +} + +VOID +halbtc8192e1ant_SwMechanism2( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAGCTableShift, + IN BOOLEAN bADCBackOff, + IN BOOLEAN bSWDACSwing, + IN u4Byte dacSwingLvl + ) +{ + //halbtc8192e1ant_AgcTable(pBtCoexist, NORMAL_EXEC, bAGCTableShift); + //halbtc8192e1ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, bADCBackOff); + //halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, bSWDACSwing, dacSwingLvl); +} + +VOID +halbtc8192e1ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0, rssiAdjustVal=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + default: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x2c, 0x03, 0x10, 0x50); + break; + case 1: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x2c, 0x03, 0x10, 0x50); + rssiAdjustVal = 11; + break; + case 2: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x25, 0x03, 0x10, 0x50); + rssiAdjustVal = 14; + break; + case 3: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x40); + break; + case 4: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + rssiAdjustVal = 17; + break; + case 5: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x61, 0x15, 0x3, 0x31, 0x0); + break; + case 6: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x0, 0x0); + break; + case 7: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x1e, 0x03, 0x10, 0x50); + rssiAdjustVal = 18; + break; + case 10: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x12, 0x03, 0x10, 0x50); + rssiAdjustVal = 20; + break; + case 12: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xeb, 0xa, 0x3, 0x31, 0x18); + break; + + case 15: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x10, 0x0); + rssiAdjustVal = 18; + break; + + case 18: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + rssiAdjustVal = 14; + break; + + case 20: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0x25, 0x25, 0x0, 0x0); + break; + case 21: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x20, 0x3, 0x10, 0x40); + break; + case 22: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0x8, 0x8, 0x0, 0x40); + break; + case 23: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 24: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 25: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 26: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 27: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); + rssiAdjustVal = 22; + break; + case 28: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x69, 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xab, 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + break; + case 31: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xab, 0xa, 0x3, 0x31, 0x90); + break; + case 33: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xa3, 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); + break; + case 37: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x25, 0x3, 0x10, 0x50); + break; + case 38: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 8: //0x778 = 1, ant2PTA + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x92c, 0x4); + break; + case 0: //0x778 = 1, ant2BT + default: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + mdelay(5); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x92c, 0x20); + break; + case 9: //0x778 = 1, ant2WIFI + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x92c, 0x4); + break; + case 10: //0x778 = 3, ant2BT + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + mdelay(5); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x92c, 0x20); + break; + } + } + rssiAdjustVal =0; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssiAdjustVal); + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8192e1ant_SetSwitchSsType( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte ssType + ) +{ + u1Byte mimoPs=BTC_MIMO_PS_DYNAMIC; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], REAL set SS Type = %d\n", ssType)); + + if(ssType == 1) + { + halbtc8192e1ant_Updatera_mask(pBtCoexist, FORCE_EXEC, BTC_RATE_DISABLE, 0xfff00000); // disable 2ss + halbtc8192e1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + // switch ofdm path + pBtCoexist->btc_write_1byte(pBtCoexist, 0xc04, 0x11); + pBtCoexist->btc_write_1byte(pBtCoexist, 0xd04, 0x1); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x90c, 0x81111111); + // switch cck patch + pBtCoexist->btc_write_1byte_bitmask(pBtCoexist, 0xe77, 0x4, 0x1); + pBtCoexist->btc_write_1byte(pBtCoexist, 0xa07, 0x81); + mimoPs=BTC_MIMO_PS_STATIC; + } + else if(ssType == 2) + { + halbtc8192e1ant_Updatera_mask(pBtCoexist, FORCE_EXEC, BTC_RATE_ENABLE, 0xfff00000); // enable 2ss + halbtc8192e1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + pBtCoexist->btc_write_1byte(pBtCoexist, 0xc04, 0x33); + pBtCoexist->btc_write_1byte(pBtCoexist, 0xd04, 0x3); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x90c, 0x81121313); + pBtCoexist->btc_write_1byte_bitmask(pBtCoexist, 0xe77, 0x4, 0x0); + pBtCoexist->btc_write_1byte(pBtCoexist, 0xa07, 0x41); + mimoPs=BTC_MIMO_PS_DYNAMIC; + } + + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimoPs); // set rx 1ss or 2ss +} + +VOID +halbtc8192e1ant_SwitchSsType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte newSsType + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], %s Switch SS Type = %d\n", + (bForceExec? "force to":""), newSsType)); + pCoexDm->curSsType = newSsType; + + if(!bForceExec) + { + if(pCoexDm->preSsType == pCoexDm->curSsType) + return; + } + halbtc8192e1ant_SetSwitchSsType(pBtCoexist, pCoexDm->curSsType); + + pCoexDm->preSsType = pCoexDm->curSsType; +} + +VOID +halbtc8192e1ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + // sw all off + halbtc8192e1ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + + // hw all off + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +BOOLEAN +halbtc8192e1ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(!bWifiConnected && + BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")); + halbtc8192e1ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = true; + } + else if(bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + halbtc8192e1ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = true; + } + else if(!bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")); + halbtc8192e1ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = true; + } + else if(bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + halbtc8192e1ant_SwMechanism1(pBtCoexist,true,true,true,true); + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = true; + } + else if(!bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + halbtc8192e1ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = true; + } + else + { + halbtc8192e1ant_SwMechanism1(pBtCoexist,true,true,true,true); + + bCommon = FALSE; + } + + return bCommon; +} + + +VOID +halbtc8192e1ant_TdmaDurationAdjustForAcl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0, btInfoExt; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjustForAcl()\n")); + + if( (BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + { + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 3 && + pCoexDm->curPsTdma != 9 ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + return; + } + + if(!pCoexDm->bAutoTdmaAdjust) + { + pCoexDm->bAutoTdmaAdjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + btInfoExt = pCoexSta->btInfoExt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if ³sÄò n ­Ó2¬í retry count¬°0, «h½Õ¼eWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if ³sÄò 2 ­Ó2¬í retry count< 3, «h½Õ¯¶WiFi duration + { + if (WaitCount <= 2) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, ¥u­n1¦¸ retry count > 3, «h½Õ¯¶WiFi duration + { + if (WaitCount == 1) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + if(result == -1) + { + if( (BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + else if(result == 1) + { + if( (BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + } + + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 9 && + pCoexDm->curPsTdma != 11 ) + { + // recover to previous adjust type + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, pCoexDm->psTdmaDuAdjType); + } + } +} + +u1Byte +halbtc8192e1ant_PsTdmaTypeByWifiRssi( + IN s4Byte wifiRssi, + IN s4Byte preWifiRssi, + IN u1Byte wifiRssiThresh + ) +{ + u1Byte psTdmaType=0; + + if(wifiRssi > preWifiRssi) + { + if(wifiRssi > (wifiRssiThresh+5)) + { + psTdmaType = 26; + } + else + { + psTdmaType = 25; + } + } + else + { + if(wifiRssi > wifiRssiThresh) + { + psTdmaType = 26; + } + else + { + psTdmaType = 25; + } + } + + return psTdmaType; +} + +VOID +halbtc8192e1ant_PsTdmaCheckForPowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bNewPsState + ) +{ + u1Byte lpsMode=0x0; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_LPS_MODE, &lpsMode); + + if(lpsMode) // already under LPS state + { + if(bNewPsState) + { + // keep state under LPS, do nothing. + } + else + { + // will leave LPS state, turn off psTdma first + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + } + else // NO PS state + { + if(bNewPsState) + { + // will enter LPS state, turn off psTdma first + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + // keep state under NO PS state, do nothing. + } + } +} + +VOID +halbtc8192e1ant_PowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte psType, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bLowPwrDisable=FALSE; + + switch(psType) + { + case BTC_PS_WIFI_NATIVE: + // recover to original 32k low power setting + bLowPwrDisable = FALSE; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + halbtc8192e1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, true); + halbtc8192e1ant_LpsRpwm(pBtCoexist, NORMAL_EXEC, lpsVal, rpwmVal); + // when coex force to enter LPS, do not enter 32k low power. + bLowPwrDisable = true; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + // power save must executed before psTdma. + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + case BTC_PS_LPS_OFF: + halbtc8192e1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, FALSE); + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + + +VOID +halbtc8192e1ant_ActionWifiOnly( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); +} + +VOID +halbtc8192e1ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=true, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = true; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + halbtc8192e1ant_ActionWifiOnly(pBtCoexist); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + } + } +} + +//============================================= +// +// Software Coex Mechanism start +// +//============================================= + +// SCO only or SCO+PAN(HS) +VOID +halbtc8192e1ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + + +VOID +halbtc8192e1ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,FALSE,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8192e1ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e1ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e1ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + + +//PAN(HS) only +VOID +halbtc8192e1ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//PAN(EDR)+A2DP +VOID +halbtc8192e1ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e1ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8192e1ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e1ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8192e1ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,true,FALSE,0x18); + } + } + else + { + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,true,true,FALSE,0x18); + } + else + { + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//============================================= +// +// Non-Software Coex Mechanism start +// +//============================================= +VOID +halbtc8192e1ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + // Note: + // Do not do DacSwing here, use original setting. + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(bBtHsOn) + return; + + if(!bWifiConnected) + { + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (pBtLinkInfo->bScoExist) || + (pBtLinkInfo->bHidOnly) ) + { + // SCO/HID-only busy + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else + { + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 30); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } +} + +VOID +halbtc8192e1ant_ActionBtScoHidOnlyBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + u1Byte btRssiState=BTC_RSSI_STATE_HIGH; + + if(BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else + { + if(pBtLinkInfo->bHidOnly) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else + { + // dec bt power for diff level + btRssiState = halbtc8192e1ant_BtRssiState(3, 34, 42); + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 6); + } + + // sw dacSwing + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, true, 0xc); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + } + } +} + +VOID +halbtc8192e1ant_ActionHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action for HS!!!\n")); + + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if(BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + // error, should not be here + pCoexDm->errorCondition = 1; + } + else if(BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, true, 6); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 10); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && + !pBtCoexist->bt_link_info.bHidOnly) + { + if(pCoexDm->curSsType == 1) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, true, 6); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 10); + //halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 38); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + } + else + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } +} + +VOID +halbtc8192e1ant_ActionWifiConnectedBtAclBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + + if(pBtLinkInfo->bHidOnly) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, wifiStatus); + pCoexDm->bAutoTdmaAdjust = FALSE; + return; + } + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + if( (pBtLinkInfo->bA2dpOnly) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist) ) + { + halbtc8192e1ant_TdmaDurationAdjustForAcl(pBtCoexist, wifiStatus); + } + else if( (pBtLinkInfo->bPanOnly) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bPanExist) ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else + { + if( (BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + else + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); +} + + +VOID +halbtc8192e1ant_ActionWifiNotConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8192e1ant_ActionWifiConnectedScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->bt_link_info.bHidOnly) + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else if( (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + + +VOID +halbtc8192e1ant_ActionWifiConnectedSpecialPacket( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->bt_link_info.bHidOnly) + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + +VOID +halbtc8192e1ant_ActionWifiConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE, bWifiBusy=FALSE; + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BOOLEAN bUnder4way=FALSE; + u4Byte wifiBw; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect()===>\n")); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi not connected<===\n")); + return; + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + if(bUnder4way) + { + halbtc8192e1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")); + return; + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + if(bScan || bLink || bRoam) + { + halbtc8192e1ant_ActionWifiConnectedScan(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")); + return; + } + + // power save state + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->bt_link_info.bHidOnly) + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + if(!bWifiBusy) + { + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else if( (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } + else + { + if(BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else if(BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else if( (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } +} + +VOID +halbtc8192e1ant_RunSwCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE, bWifiBusy=FALSE, bWifiConnected=FALSE; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + return; + + algorithm = halbtc8192e1ant_ActionAlgorithm(pBtCoexist); + pCoexDm->curAlgorithm = algorithm; + + if(halbtc8192e1ant_IsCommonAction(pBtCoexist)) + { + } + else + { + switch(pCoexDm->curAlgorithm) + { + case BT_8192E_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n")); + halbtc8192e1ant_ActionSco(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n")); + halbtc8192e1ant_ActionHid(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n")); + halbtc8192e1ant_ActionA2dp(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n")); + halbtc8192e1ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n")); + halbtc8192e1ant_ActionPanEdr(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n")); + halbtc8192e1ant_ActionPanHs(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n")); + halbtc8192e1ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n")); + halbtc8192e1ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n")); + halbtc8192e1ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n")); + halbtc8192e1ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n")); + halbtc8192e1ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8192e1ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->manual_control) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + halbtc8192e1ant_RunSwCoexistMechanism(pBtCoexist); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + + // 1ss or 2ss + if(pBtLinkInfo->bScoExist) + { + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + } + else if(bBtHsOn) + { + if(pBtLinkInfo->bHidOnly) + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + } + else + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + + if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n")); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if(bScan || bLink || bRoam) + halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + else + halbtc8192e1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8192e1ant_ActionWifiConnected(pBtCoexist); + } +} + +VOID +halbtc8192e1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8192e1ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); + halbtc8192e1ant_DecBtPwr(pBtCoexist, FORCE_EXEC, 0); + + // sw all off + halbtc8192e1ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e1ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + halbtc8192e1ant_SwitchSsType(pBtCoexist, FORCE_EXEC, 2); + + halbtc8192e1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); +} + +//============================================================ +// work around function start with wa_halbtc8192e1ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8192e1ant_ +//============================================================ +VOID +EXhalbtc8192e1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte u4Tmp=0; + u16 u2Tmp=0; + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->btc_get_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + // antenna sw ctrl to bt + pBtCoexist->btc_write_1byte(pBtCoexist, 0x4f, 0x6); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x944, 0x24); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x930, 0x700700); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x92c, 0x20); + if(pBtCoexist->chipInterface == BTC_INTF_USB) + pBtCoexist->btc_write_4byte(pBtCoexist, 0x64, 0x30430004); + else + pBtCoexist->btc_write_4byte(pBtCoexist, 0x64, 0x30030004); + + halbtc8192e1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); + + // antenna switch control parameter + pBtCoexist->btc_write_4byte(pBtCoexist, 0x858, 0x55555555); + + // coex parameters + pBtCoexist->btc_write_1byte(pBtCoexist, 0x778, 0x1); + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->btc_read_1byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->btc_write_1byte(pBtCoexist, 0x790, u1Tmp); + + // enable counter statistics + pBtCoexist->btc_write_1byte(pBtCoexist, 0x76e, 0x4); + + // enable PTA + pBtCoexist->btc_write_1byte(pBtCoexist, 0x40, 0x20); + // enable mailbox interface + u2Tmp = pBtCoexist->btc_read_2byte(pBtCoexist, 0x40); + u2Tmp |= BIT9; + pBtCoexist->btc_write_2byte(pBtCoexist, 0x40, u2Tmp); + + // enable PTA I2C mailbox + u1Tmp = pBtCoexist->btc_read_1byte(pBtCoexist, 0x101); + u1Tmp |= BIT4; + pBtCoexist->btc_write_1byte(pBtCoexist, 0x101, u1Tmp); + + // enable bt clock when wifi is disabled. + u1Tmp = pBtCoexist->btc_read_1byte(pBtCoexist, 0x93); + u1Tmp |= BIT0; + pBtCoexist->btc_write_1byte(pBtCoexist, 0x93, u1Tmp); + // enable bt clock when suspend. + u1Tmp = pBtCoexist->btc_read_1byte(pBtCoexist, 0x7); + u1Tmp |= BIT0; + pBtCoexist->btc_write_1byte(pBtCoexist, 0x7, u1Tmp); +} + +VOID +EXhalbtc8192e1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + pBtCoexist->bStopCoexDm = FALSE; + + halbtc8192e1ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8192e1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + struct btc_board_info * pBoardInfo=&pBtCoexist->board_info; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stack_info; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + pu1Byte cliBuf=pBtCoexist->cli_buf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->manual_control) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + if(pBtCoexist->bStopCoexDm) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bt_exist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pg_ant_num, pBoardInfo->btdm_ant_num); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8192e1Ant, GLCoexVer8192e1Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->btc_disp_dbg_msg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; ibtInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8192e1Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF")), + pBtCoexist->btInfo.lps1Ant, + pBtCoexist->btInfo.rpwm_1ant); + CL_PRINTF(cliBuf); + pBtCoexist->btc_disp_dbg_msg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", \ + pCoexDm->curSsType); + CL_PRINTF(cliBuf); + + if(!pBtCoexist->manual_control) + { + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig/ btLna]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->limited_dig, pCoexDm->bCurBtLnaConstrain); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", \ + (pBtCoexist->btInfo.reject_agg_pkt? "Yes":"No"), (pBtCoexist->btInfo.b_bt_ctrl_agg_buf_size? "Yes":"No"), + pBtCoexist->btInfo.aggBufSize); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ + pBtCoexist->btInfo.ra_mask); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \ + pCoexDm->errorCondition); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwrLvl/ IgnWlanAct", \ + pCoexDm->curBtDecPwrLvl, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xc04); + u4Tmp[1] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xd04); + u4Tmp[2] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x90c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0xc04/ 0xd04/ 0x90c", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x778); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x92c); + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x930); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x92c/ 0x930", \ + (u1Tmp[0]), u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x40); + u1Tmp[1] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x4f); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x40/ 0x4f", \ + u1Tmp[0], u1Tmp[1]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); +#if(BT_AUTO_REPORT_ONLY_8192E_1ANT == 1) + halbtc8192e1ant_MonitorBtCtr(pBtCoexist); +#endif + + pBtCoexist->btc_disp_dbg_msg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8192e1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u4Byte u4Tmp=0; + + if(pBtCoexist->manual_control || pBtCoexist->bStopCoexDm) + return; + + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = true; + halbtc8192e1ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + } +} + +VOID +EXhalbtc8192e1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(pBtCoexist->manual_control || pBtCoexist->bStopCoexDm) + return; + + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = true; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8192e1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->manual_control || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else // wifi is connected + { + halbtc8192e1ant_ActionWifiConnectedScan(pBtCoexist); + } + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8192e1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8192e1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8192e1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->manual_control || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) // non-connected scan + { + halbtc8192e1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8192e1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8192e1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(pBtCoexist->manual_control || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x66, 3, H2C_Parameter); +} + +VOID +EXhalbtc8192e1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bBtHsOn=FALSE; + + if(pBtCoexist->manual_control || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + if( BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type ) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet(%d) notify\n", type)); + halbtc8192e1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + } +} + +VOID +EXhalbtc8192e1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->bt_link_info; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + static u4Byte setBtPsdMode=0; + BOOLEAN bBtBusy=FALSE, limited_dig=FALSE; + BOOLEAN bWifiConnected=FALSE; + BOOLEAN b_bt_ctrl_agg_buf_size=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8192E_1ANT_MAX) + rspSource = BT_INFO_SRC_8192E_1ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; ibtInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(pBtCoexist->btInfo.bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for BT is disabled <===\n")); + return; + } + + if(pBtCoexist->manual_control) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n")); + return; + } + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Coex STOPPED!!<===\n")); + return; + } + + if(BT_INFO_SRC_8192E_1ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (pCoexSta->btInfoExt & BIT1) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8192e1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8192e1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + + setBtPsdMode = 0; + } + + // test-chip bt patch only rsp the status for BT_RSP, + // so temporary we consider the following only under BT_RSP + if(BT_INFO_SRC_8192E_1ANT_BT_RSP == rspSource) + { + if( (pCoexSta->btInfoExt & BIT3) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8192e1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } +#if(BT_AUTO_REPORT_ONLY_8192E_1ANT == 0) + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n")); + halbtc8192e1ant_BtAutoReport(pBtCoexist, FORCE_EXEC, true); + } +#endif + } + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8192E_1ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = true; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8192E_1ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = true; + if(btInfo & BT_INFO_8192E_1ANT_B_FTP) + pCoexSta->bPanExist = true; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8192E_1ANT_B_A2DP) + pCoexSta->bA2dpExist = true; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8192E_1ANT_B_HID) + pCoexSta->bHidExist = true; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8192E_1ANT_B_SCO_ESCO) + pCoexSta->bScoExist = true; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8192e1ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8192E_1ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8192E_1ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8192E_1ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8192E_1ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt sco busy!!!\n")); + } + else if( (btInfo&BT_INFO_8192E_1ANT_B_ACL_BUSY) || + (btInfo&BT_INFO_8192E_1ANT_B_A2DP) || + (btInfo&BT_INFO_8192E_1ANT_B_FTP) ) + { + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus) + pCoexDm->bAutoTdmaAdjust = FALSE; + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt acl busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-defined state!!!\n")); + } + + // ra mask check + if(pBtLinkInfo->bScoExist || pBtLinkInfo->bHidExist) + { + halbtc8192e1ant_Updatera_mask(pBtCoexist, NORMAL_EXEC, BTC_RATE_DISABLE, 0x00000003); // disable tx cck 1M/2M + } + else + { + halbtc8192e1ant_Updatera_mask(pBtCoexist, NORMAL_EXEC, BTC_RATE_ENABLE, 0x00000003); // enable tx cck 1M/2M + } + + if( (BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bBtBusy = true; + limited_dig = true; + if(pBtLinkInfo->bHidExist) + b_bt_ctrl_agg_buf_size = true; + } + else + { + bBtBusy = FALSE; + limited_dig = FALSE; + } + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + //============================================ + // Aggregation related setting + //============================================ + // if sco, reject AddBA + //pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejApAggPkt); + + // decide BT control aggregation buf size or not + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &b_bt_ctrl_agg_buf_size); + // real update aggregation setting + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + //============================================ + + pCoexDm->limited_dig = limited_dig; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8192e1ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8192e1ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_STACK_OP_INQ_PAGE_PAIR_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair start notify\n")); + } + else if(BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair finish notify\n")); + } +} + +VOID +EXhalbtc8192e1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + pBtCoexist->bStopCoexDm = true; + halbtc8192e1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); + + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x4f, 0xf); + + EXhalbtc8192e1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8192e1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); + + if(BTC_WIFI_PNP_SLEEP == pnpState) + { + pBtCoexist->bStopCoexDm = true; + halbtc8192e1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else if(BTC_WIFI_PNP_WAKE_UP == pnpState) + { + + } +} + +VOID +EXhalbtc8192e1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + struct btc_board_info * pBoardInfo=&pBtCoexist->board_info; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stack_info; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pg_ant_num, pBoardInfo->btdm_ant_num, pBoardInfo->btdm_ant_pos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8192e1Ant, GLCoexVer8192e1Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } +#if(BT_AUTO_REPORT_ONLY_8192E_1ANT == 0) + halbtc8192e1ant_QueryBtInfo(pBtCoexist); + halbtc8192e1ant_MonitorBtCtr(pBtCoexist); + halbtc8192e1ant_MonitorBtEnableDisable(pBtCoexist); +#else + if( halbtc8192e1ant_IsWifiStatusChanged(pBtCoexist) || + pCoexDm->bAutoTdmaAdjust) + { + halbtc8192e1ant_RunCoexistMechanism(pBtCoexist); + } +#endif +} + +VOID +EXhalbtc8192e1ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ) +{ + switch(opCode) + { + case BTC_DBG_SET_COEX_NORMAL: + pBtCoexist->manual_control = FALSE; + halbtc8192e1ant_InitCoexDm(pBtCoexist); + break; + case BTC_DBG_SET_COEX_WIFI_ONLY: + pBtCoexist->manual_control = true; + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + break; + case BTC_DBG_SET_COEX_BT_ONLY: + // todo + break; + default: + break; + } +} +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c @@ -0,0 +1,1181 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include "halbt_precomp.h" + +/*#if(BT_30_SUPPORT == 1)*/ +#if 1 +/*********************************************** + * Global variables + ***********************************************/ +const char *const bt_profile_string[]={ + "NONE", + "A2DP", + "PAN", + "HID", + "SCO", +}; + +const char *const bt_spec_string[]={ + "1.0b", + "1.1", + "1.2", + "2.0+EDR", + "2.1+EDR", + "3.0+HS", + "4.0", +}; + +const char *const bt_link_role_string[]={ + "Master", + "Slave", +}; + +const char *const h2c_state_string[]={ + "successful", + "h2c busy", + "rf off", + "fw not read", +}; + +const char *const io_state_string[]={ + "IO_STATUS_SUCCESS", + "IO_STATUS_FAIL_CANNOT_IO", + "IO_STATUS_FAIL_RF_OFF", + "IO_STATUS_FAIL_FW_READ_CLEAR_TIMEOUT", + "IO_STATUS_FAIL_WAIT_IO_EVENT_TIMEOUT", + "IO_STATUS_INVALID_LEN", + "IO_STATUS_IO_IDLE_QUEUE_EMPTY", + "IO_STATUS_IO_INSERT_WAIT_QUEUE_FAIL", + "IO_STATUS_UNKNOWN_FAIL", + "IO_STATUS_WRONG_LEVEL", + "IO_STATUS_H2C_STOPPED", +}; + +struct btc_coexist gl_bt_coexist; + +u32 btc_dbg_type[BTC_MSG_MAX]; +u8 btc_dbg_buf[100]; + +/*************************************************** + * Debug related function + ***************************************************/ +bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist) +{ + if (!btcoexist->binded || NULL == btcoexist->adapter) + return false; + + return true; +} + +bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv) +{ + + if (rtlpriv->link_info.b_busytraffic) + return true; + else + return false; +} + + +void halbtc_dbg_init(void) +{ + u8 i; + + for (i = 0; i < BTC_MSG_MAX; i++) + btc_dbg_type[i] = 0; + + btc_dbg_type[BTC_MSG_INTERFACE] = \ +// INTF_INIT | +// INTF_NOTIFY | + 0; + + btc_dbg_type[BTC_MSG_ALGORITHM] = \ +// ALGO_BT_RSSI_STATE | +// ALGO_WIFI_RSSI_STATE | +// ALGO_BT_MONITOR | +// ALGO_TRACE | +// ALGO_TRACE_FW | +// ALGO_TRACE_FW_DETAIL | +// ALGO_TRACE_FW_EXEC | +// ALGO_TRACE_SW | +// ALGO_TRACE_SW_DETAIL | +// ALGO_TRACE_SW_EXEC | + 0; +} + +bool halbtc_is_hw_mailbox_exist(struct btc_coexist *btcoexist) +{ + return true; +} + +bool halbtc_is_bt40(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool is_ht40 = true; + enum ht_channel_width bw = rtlphy->current_chan_bw; + + + if (bw == HT_CHANNEL_WIDTH_20) + is_ht40 = false; + else if (bw == HT_CHANNEL_WIDTH_20_40) + is_ht40 = true; + + return is_ht40; +} + +bool halbtc_legacy(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + + bool is_legacy = false; + + if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_B)) + is_legacy = true; + + return is_legacy; +} + +bool halbtc_is_wifi_uplink(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + + if (rtlpriv->link_info.b_tx_busy_traffic) + return true; + else + return false; +} + +u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = + (struct rtl_priv *)btcoexist->adapter; + u32 wifi_bw = BTC_WIFI_BW_HT20; + + if (halbtc_is_bt40(rtlpriv)){ + wifi_bw = BTC_WIFI_BW_HT40; + } else { + if(halbtc_legacy(rtlpriv)) + wifi_bw = BTC_WIFI_BW_LEGACY; + else + wifi_bw = BTC_WIFI_BW_HT20; + } + return wifi_bw; +} + +u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 chnl = 1; + + + if (rtlphy->current_channel != 0) + chnl = rtlphy->current_channel; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "halbtc_get_wifi_central_chnl:%d\n",chnl); + return chnl; +} + +void halbtc_leave_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv; + struct rtl_ps_ctl *ppsc; + bool ap_enable = false; + + rtlpriv = btcoexist->adapter; + ppsc = rtl_psc(rtlpriv); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + printk("halbtc_leave_lps()<--dont leave lps under AP mode\n"); + return; + } + + btcoexist->bt_info.bt_ctrl_lps = true; + btcoexist->bt_info.bt_lps_on = false; +} + +void halbtc_enter_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv; + struct rtl_ps_ctl *ppsc; + bool ap_enable = false; + + rtlpriv = btcoexist->adapter; + ppsc = rtl_psc(rtlpriv); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + printk("halbtc_enter_lps()<--dont enter lps under AP mode\n"); + return; + } + + btcoexist->bt_info.bt_ctrl_lps = true; + btcoexist->bt_info.bt_lps_on = false; +} + +void halbtc_normal_lps(struct btc_coexist *btcoexist) +{ + if (btcoexist->bt_info.bt_ctrl_lps) { + btcoexist->bt_info.bt_lps_on = false; + btcoexist->bt_info.bt_ctrl_lps = false; + } + +} + +void halbtc_leave_low_power(void) +{ +} + +void halbtc_nomal_low_power(void) +{ +} + +void halbtc_disable_low_power(void) +{ +} + +void halbtc_aggregation_check(void) +{ +} + + +u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) +{ + return 0; +} + +s32 halbtc_get_wifi_rssi(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + s32 undecorated_smoothed_pwdb = 0; + + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + else /* associated entry pwdb */ + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + return undecorated_smoothed_pwdb; +} + +bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + bool *bool_tmp = (bool*)out_buf; + int *s32_tmp = (int*)out_buf; + u32 *u32_tmp = (u32*)out_buf; + u8 *u8_tmp = (u8*)out_buf; + bool tmp = false; + + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return false; + + + switch (get_type){ + case BTC_GET_BL_HS_OPERATION: + *bool_tmp = false; + break; + case BTC_GET_BL_HS_CONNECTING: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_CONNECTED: + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + tmp = true; + + *bool_tmp = tmp; + break; + case BTC_GET_BL_WIFI_BUSY: + if(halbtc_is_wifi_busy(rtlpriv)) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_SCAN: + if (mac->act_scanning == true) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_LINK: + if (mac->link_state == MAC80211_LINKING) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_ROAM: /*TODO*/ + if (mac->link_state == MAC80211_LINKING) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_4_WAY_PROGRESS: /*TODO*/ + *bool_tmp = false; + + break; + case BTC_GET_BL_WIFI_UNDER_5G: + *bool_tmp = false; /*TODO*/ + + case BTC_GET_BL_WIFI_DHCP: /*TODO*/ + break; + case BTC_GET_BL_WIFI_SOFTAP_IDLE: + *bool_tmp = true; + break; + case BTC_GET_BL_WIFI_SOFTAP_LINKING: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_IN_EARLY_SUSPEND: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_AP_MODE_ENABLE: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: + if (NO_ENCRYPTION == rtlpriv->sec.pairwise_enc_algorithm) + *bool_tmp = false; + else + *bool_tmp = true; + break; + case BTC_GET_BL_WIFI_UNDER_B_MODE: + *bool_tmp = false; /*TODO*/ + break; + case BTC_GET_BL_EXT_SWITCH: + *bool_tmp = false; + break; + case BTC_GET_S4_WIFI_RSSI: + *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); + break; + case BTC_GET_S4_HS_RSSI: /*TODO*/ + *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); + break; + case BTC_GET_U4_WIFI_BW: + *u32_tmp = halbtc_get_wifi_bw(btcoexist); + break; + case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION: + if (halbtc_is_wifi_uplink(rtlpriv)) + *u32_tmp = BTC_WIFI_TRAFFIC_TX; + else + *u32_tmp = BTC_WIFI_TRAFFIC_RX; + break; + case BTC_GET_U4_WIFI_FW_VER: + *u32_tmp = rtlhal->fw_version; + break; + case BTC_GET_U4_BT_PATCH_VER: + *u32_tmp = halbtc_get_bt_patch_version(btcoexist); + break; + case BTC_GET_U1_WIFI_DOT11_CHNL: + *u8_tmp = rtlphy->current_channel; + break; + case BTC_GET_U1_WIFI_CENTRAL_CHNL: + *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist); + break; + case BTC_GET_U1_WIFI_HS_CHNL: + *u8_tmp = 1;/* BT_OperateChnl(rtlpriv); */ + break; + case BTC_GET_U1_MAC_PHY_MODE: + *u8_tmp = BTC_MP_UNKNOWN; + break; + case BTC_GET_U1_AP_NUM: + /* driver don't know AP num in Linux, + * So, the return value here is not right */ + *u8_tmp = 1;/* pDefMgntInfo->NumBssDesc4Query; */ + break; + + /************* 1Ant **************/ + case BTC_GET_U1_LPS_MODE: + *u8_tmp = btcoexist->pwr_mode_val[0]; + break; + + default: + break; + } + + return true; +} + +bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; + bool *bool_tmp = (bool *)in_buf; + u8 *u8_tmp = (u8 *)in_buf; + u32 *u32_tmp = (u32 *)in_buf; + + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return false; + + switch (set_type) { + /* set some bool type variables. */ + case BTC_SET_BL_BT_DISABLE: + btcoexist->bt_info.bt_disabled = *bool_tmp; + break; + case BTC_SET_BL_BT_TRAFFIC_BUSY: + btcoexist->bt_info.bt_busy = *bool_tmp; + break; + case BTC_SET_BL_BT_LIMITED_DIG: + btcoexist->bt_info.limited_dig = *bool_tmp; + break; + case BTC_SET_BL_FORCE_TO_ROAM: + btcoexist->bt_info.force_to_roam = *bool_tmp; + break; + case BTC_SET_BL_TO_REJ_AP_AGG_PKT: + btcoexist->bt_info.reject_agg_pkt = *bool_tmp; + break; + case BTC_SET_BL_BT_CTRL_AGG_SIZE: + btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp; + break; + case BTC_SET_BL_INC_SCAN_DEV_NUM: + btcoexist->bt_info.increase_scan_dev_num = *bool_tmp; + break; + /* set some u1Byte type variables. */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: + btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp; + break; + case BTC_SET_U1_AGG_BUF_SIZE: + btcoexist->bt_info.agg_buf_size = *u8_tmp; + break; + /* the following are some action which will be triggered */ + case BTC_SET_ACT_GET_BT_RSSI: + /*BTHCI_SendGetBtRssiEvent(rtlpriv);*/ + break; + case BTC_SET_ACT_AGGREGATE_CTRL: + halbtc_aggregation_check(); + break; + + /* 1Ant */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: + btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp; + break; + case BTC_SET_UI_SCAN_SIG_COMPENSATION: + /* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */ + break; + case BTC_SET_U1_1ANT_LPS: + btcoexist->bt_info.lps_1ant = *u8_tmp; + break; + case BTC_SET_U1_1ANT_RPWM: + btcoexist->bt_info.rpwm_1ant = *u8_tmp; + break; + /* the following are some action which will be triggered */ + case BTC_SET_ACT_LEAVE_LPS: + halbtc_leave_lps(btcoexist); + break; + case BTC_SET_ACT_ENTER_LPS: + halbtc_enter_lps(btcoexist); + break; + case BTC_SET_ACT_NORMAL_LPS: + halbtc_normal_lps(btcoexist); + break; + case BTC_SET_ACT_DISABLE_LOW_POWER: + halbtc_disable_low_power(); + break; + case BTC_SET_ACT_UPDATE_ra_mask: + btcoexist->bt_info.ra_mask = *u32_tmp; + break; + case BTC_SET_ACT_SEND_MIMO_PS: + break; + case BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT: + btcoexist->bt_info.force_exec_pwr_cmd_cnt++; + break; + case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/ + break; + case BTC_SET_ACT_CTRL_BT_COEX: + break; + default: + break; + } + + return true; +} + +void halbtc_display_coex_statistics(struct btc_coexist *btcoexist) +{ +} + +void halbtc_display_bt_link_info(struct btc_coexist *btcoexist) +{ +} + +void halbtc_display_bt_fw_info(struct btc_coexist *btcoexist) +{ +} + +void halbtc_display_fw_pwr_mode_cmd(struct btc_coexist *btcoexist) +{ +} + +/************************************************************ + * IO related function + ************************************************************/ +u8 halbtc_read_1byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_byte(rtlpriv, reg_addr); +} + + +u16 halbtc_read_2byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_word(rtlpriv, reg_addr); +} + + +u32 halbtc_read_4byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_dword(rtlpriv, reg_addr); +} + + +void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_byte(rtlpriv, reg_addr, data); +} + +void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr, + u8 bit_mask, u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 original_value, bit_shift = 0; + u8 i; + + if (bit_mask != MASKDWORD) {/*if not "double word" write*/ + original_value = rtl_read_byte(rtlpriv, reg_addr); + for (i=0; i<=7; i++) { + if((bit_mask>>i)&0x1) + break; + } + bit_shift = i; + data = (original_value & (~bit_mask)) | + ((data << bit_shift) & bit_mask); + } + rtl_write_byte(rtlpriv, reg_addr, data); +} + + +void halbtc_write_2byte(void *bt_context, u32 reg_addr, u16 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_word(rtlpriv, reg_addr, data); +} + + +void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data) +{ + struct btc_coexist *btcoexist = + (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_dword(rtlpriv, reg_addr, data); +} + + +void halbtc_set_macreg(void *bt_context, u32 reg_addr, u32 bit_mask, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data); +} + + +u32 halbtc_get_macreg(void *bt_context, u32 reg_addr, u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask); +} + + +void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data); +} + + +u32 halbtc_get_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_bbreg(rtlpriv->mac80211.hw,reg_addr, bit_mask); +} + + +void halbtc_set_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, + u32 bit_mask, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask, data); +} + + +u32 halbtc_get_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask); +} + + +void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, + u32 cmd_len, u8 *cmd_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, element_id, + cmd_len, cmd_buf); +} + +void halbtc_display_dbg_msg(void *bt_context, u8 disp_type) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + switch (disp_type) { + case BTC_DBG_DISP_COEX_STATISTICS: + halbtc_display_coex_statistics(btcoexist); + break; + case BTC_DBG_DISP_BT_LINK_INFO: + halbtc_display_bt_link_info(btcoexist); + break; + case BTC_DBG_DISP_BT_FW_VER: + halbtc_display_bt_fw_info(btcoexist); + break; + case BTC_DBG_DISP_FW_PWR_MODE_CMD: + halbtc_display_fw_pwr_mode_cmd(btcoexist); + break; + default: + break; + } +} + +bool halbtc_under_ips(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + enum rf_pwrstate rtstate; + + if (ppsc->b_inactiveps) { + rtstate = ppsc->rfpwr_state; + + if (rtstate != ERFON && + ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { + + return true; + } + } + + return false; +} + +/***************************************************************** + * Extern functions called by other module + *****************************************************************/ +bool exhalbtc_initlize_variables(struct rtl_priv *adapter) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + btcoexist->statistics.cnt_bind++; + + halbtc_dbg_init(); + + if (btcoexist->binded) + return false; + else + btcoexist->binded = true; + +#if ( defined(CONFIG_PCI_HCI)) + btcoexist->chip_interface = BTC_INTF_PCI; +#elif ( defined(CONFIG_USB_HCI)) + btcoexist->chip_interface = BTC_INTF_USB; +#elif ( defined(CONFIG_SDIO_HCI)) + btcoexist->chip_interface = BTC_INTF_SDIO; +#elif ( defined(CONFIG_GSPI_HCI)) + btcoexist->chip_interface = BTC_INTF_GSPI; +#else + btcoexist->chip_interface = BTC_INTF_UNKNOWN; +#endif + + if (NULL == btcoexist->adapter) + btcoexist->adapter = adapter; + + btcoexist->stack_info.profile_notified = false; + + btcoexist->btc_read_1byte = halbtc_read_1byte; + btcoexist->btc_write_1byte = halbtc_write_1byte; + btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte; + btcoexist->btc_read_2byte = halbtc_read_2byte; + btcoexist->btc_write_2byte = halbtc_write_2byte; + btcoexist->btc_read_4byte = halbtc_read_4byte; + btcoexist->btc_write_4byte = halbtc_write_4byte; + + btcoexist->btc_set_bb_reg = halbtc_set_bbreg; + btcoexist->btc_get_bb_reg = halbtc_get_bbreg; + + btcoexist->btc_set_rf_reg = halbtc_set_rfreg; + btcoexist->btc_get_rf_reg = halbtc_get_rfreg; + + btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd; + btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg; + + btcoexist->btc_get = halbtc_get; + btcoexist->btc_set = halbtc_set; + + btcoexist->cli_buf = &btc_dbg_buf[0]; + + btcoexist->bt_info.b_bt_ctrl_buf_size = false; + btcoexist->bt_info.agg_buf_size = 5; + + btcoexist->bt_info.increase_scan_dev_num = false; + return true; +} + +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_init_hw_config++; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_init_hwconfig(btcoexist); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_init_hwconfig(btcoexist); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_init_hwconfig(btcoexist); + } + +} + +void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_init_coex_dm++; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_init_coex_dm(btcoexist); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_init_coex_dm(btcoexist); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_init_coex_dm(btcoexist); + } + + btcoexist->initilized = true; +} + +void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 ips_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_ips_notify++; + if (btcoexist->manual_control) + return; + + if (ERFOFF == type) + ips_type = BTC_IPS_ENTER; + else + ips_type = BTC_IPS_LEAVE; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_ips_notify(btcoexist, ips_type); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_ips_notify(btcoexist, ips_type); + } + + halbtc_nomal_low_power(); +} + +void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 lps_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_lps_notify++; + if (btcoexist->manual_control) + return; + + if (EACTIVE == type) + lps_type = BTC_LPS_DISABLE; + else + lps_type = BTC_LPS_ENABLE; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_lps_notify(btcoexist, lps_type); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_lps_notify(btcoexist, lps_type); + } +} + +void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 scan_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_scan_notify++; + if (btcoexist->manual_control) + return; + + if (type) + scan_type = BTC_SCAN_START; + else + scan_type = BTC_SCAN_FINISH; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_scan_notify(btcoexist, scan_type); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_scan_notify(btcoexist, scan_type); + } + + halbtc_nomal_low_power(); +} + +void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 asso_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_connect_notify++; + if (btcoexist->manual_control) + return; + + if (action) + asso_type = BTC_ASSOCIATE_START; + else + asso_type = BTC_ASSOCIATE_FINISH; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_connect_notify(btcoexist, asso_type); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_connect_notify(btcoexist, asso_type); + } + + halbtc_nomal_low_power(); +} + +void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, + enum rt_media_status media_status) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 status; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_media_status_notify++; + if (btcoexist->manual_control) + return; + + if (RT_MEDIA_CONNECT == media_status) + status = BTC_MEDIA_CONNECT; + else + status = BTC_MEDIA_DISCONNECT; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_media_status_notify(btcoexist, status); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_media_status_notify(btcoexist, status); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_media_status_notify(btcoexist, status); + } + + halbtc_nomal_low_power(); +} + +void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) +{ + u8 packet_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_special_packet_notify++; + if (btcoexist->manual_control) + return; + + /*if(PACKET_DHCP == pkt_type)*/ + packet_type = BTC_PACKET_DHCP; + /*else if(PACKET_EAPOL == pkt_type) + packet_type = BTC_PACKET_EAPOL; + else + packet_type = BTC_PACKET_UNKNOWN;*/ + + halbtc_leave_low_power(); + + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_special_packet_notify(btcoexist, + packet_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_special_packet_notify(btcoexist, + packet_type); + + halbtc_nomal_low_power(); +} + +void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_bt_info_notify++; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_bt_info_notify(btcoexist, tmp_buf, length); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + // ex_halbtc8192e2ant_bt_info_notify(btcoexist, tmp_buf, length); + } +} + +void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) +{ + u8 stack_op_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_stack_operation_notify++; + if (btcoexist->manual_control) + return; + + stack_op_type = BTC_STACK_OP_NONE; +} + +void exhalbtc_halt_notify(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_halt_notify(btcoexist); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_halt_notify(btcoexist); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_halt_notify(btcoexist); + } +} + +void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; +} + +void exhalbtc_periodical(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_periodical++; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_periodical(btcoexist); + else if(btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_periodical(btcoexist); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { + ex_halbtc8192e2ant_periodical(btcoexist); + } + + halbtc_nomal_low_power(); +} + +void exhalbtc_dbg_control(struct btc_coexist *btcoexist, + u8 code, u8 len, u8 *data) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_dbg_ctrl++; +} + +void exhalbtc_stack_update_profile_info() +{ +} + +void exhalbtc_update_min_bt_rssi(char bt_rssi) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->stack_info.min_bt_rssi = bt_rssi; +} + + +void exhalbtc_set_hci_version(u16 hci_version) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->stack_info.hci_version = hci_version; +} + +void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->bt_info.bt_real_fw_ver = bt_patch_version; + btcoexist->bt_info.bt_hci_ver = bt_hci_version; +} + +void exhalbtc_set_bt_exist(bool bt_exist) +{ + gl_bt_coexist.board_info.bt_exist = bt_exist; +} + +void exhalbtc_set_chip_type(u8 chip_type) +{ + switch (chip_type) { + default: + case BT_2WIRE: + case BT_ISSC_3WIRE: + case BT_ACCEL: + case BT_RTL8756: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_UNDEF; + break; + case BT_CSR_BC4: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC4; + break; + case BT_CSR_BC8: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC8; + break; + case BT_RTL8723A: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A; + break; + case BT_RTL8821A: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8821; + break; + case BT_RTL8723B: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723B; + break; + } +} + +void exhalbtc_set_ant_num(u8 type, u8 ant_num) +{ + if (BT_COEX_ANT_TYPE_PG == type) { + gl_bt_coexist.board_info.pg_ant_num = ant_num; + gl_bt_coexist.board_info.btdm_ant_num = ant_num; + } else if (BT_COEX_ANT_TYPE_ANTDIV == type) { + gl_bt_coexist.board_info.btdm_ant_num = ant_num; + } +} + +void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (btcoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_display_coex_info(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_display_coex_info(btcoexist); +} + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.h @@ -0,0 +1,175 @@ +/********************************************************************** + * The following is for 8723B 1ANT BT Co-exist definition + **********************************************************************/ +#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1 + +#define BT_INFO_8723B_1ANT_B_FTP BIT7 +#define BT_INFO_8723B_1ANT_B_A2DP BIT6 +#define BT_INFO_8723B_1ANT_B_HID BIT5 +#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723B_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? true:false) + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 + +typedef enum _BT_INFO_SRC_8723B_1ANT{ + BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_1ANT_MAX +}BT_INFO_SRC_8723B_1ANT,*PBT_INFO_SRC_8723B_1ANT; + +typedef enum _BT_8723B_1ANT_BT_STATUS{ + BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_1ANT_BT_STATUS_MAX +}BT_8723B_1ANT_BT_STATUS,*PBT_8723B_1ANT_BT_STATUS; + +typedef enum _BT_8723B_1ANT_WIFI_STATUS{ + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8723B_1ANT_WIFI_STATUS_MAX +}BT_8723B_1ANT_WIFI_STATUS,*PBT_8723B_1ANT_WIFI_STATUS; + +typedef enum _BT_8723B_1ANT_COEX_ALGO{ + BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_1ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_1ANT_COEX_ALGO_HID = 0x2, + BT_8723B_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_1ANT_COEX_ALGO_MAX = 0xb, +}BT_8723B_1ANT_COEX_ALGO,*PBT_8723B_1ANT_COEX_ALGO; + +struct coex_dm_8723b_1ant{ + /* fw mechanism */ + bool pre_dec_bt_pwr; + bool cur_dec_bt_pwr; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + bool auto_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_backoff; + bool cur_adc_backoff; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 prera_mask; + u32 curra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + + u8 error_condition; +}; + +struct coex_sta_8723b_1ant{ + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_lps; + bool under_ips; + u32 special_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/************************************************************************* + * The following is interface which will notify coex module. + *************************************************************************/ +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpState); +void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist); + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c @@ -0,0 +1,3976 @@ +//============================================================ +// Description: +// +// This file is for 8812a1ant Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "halbt_precomp.h" +#if 1 +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8812A_1ANT GLCoexDm8812a1Ant; +static PCOEX_DM_8812A_1ANT coex_dm=&GLCoexDm8812a1Ant; +static COEX_STA_8812A_1ANT GLCoexSta8812a1Ant; +static PCOEX_STA_8812A_1ANT coex_sta=&GLCoexSta8812a1Ant; + +const char *const GLBtInfoSrc8812a1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8812a1ant_ +//============================================================ +#if 0 +void +halbtc8812a1ant_Reg0x550Bit3( + PBTC_COEXIST btcoexist, + BOOLEAN bSet + ) +{ + u1Byte u1tmp=0; + + u1tmp = btcoexist->btc_read_1byte(btcoexist, 0x550); + if(bSet) + { + u1tmp |= BIT3; + } + else + { + u1tmp &= ~BIT3; + } + btcoexist->btc_write_1byte(btcoexist, 0x550, u1tmp); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], set 0x550[3]=%d\n", (bSet? 1:0))); +} +#endif +u1Byte +halbtc8812a1ant_BtRssiState( + u1Byte level_num, + u1Byte rssi_thresh, + u1Byte rssi_thresh1 + ) +{ + s4Byte bt_rssi=0; + u1Byte bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if(level_num == 2) + { + if( (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) + { + if(bt_rssi >= (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(bt_rssi < rssi_thresh) + { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(level_num == 3) + { + if(rssi_thresh > rssi_thresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return coex_sta->pre_bt_rssi_state; + } + + if( (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) + { + if(bt_rssi >= (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(bt_rssi >= (rssi_thresh1+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(bt_rssi < rssi_thresh) + { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(bt_rssi < rssi_thresh1) + { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u1Byte +halbtc8812a1ant_WifiRssiState( + PBTC_COEXIST btcoexist, + u1Byte index, + u1Byte level_num, + u1Byte rssi_thresh, + u1Byte rssi_thresh1 + ) +{ + s4Byte wifi_rssi=0; + u1Byte wifi_rssi_state; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if(level_num == 2) + { + if( (coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifi_rssi >= (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifi_rssi < rssi_thresh) + { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(level_num == 3) + { + if(rssi_thresh > rssi_thresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if( (coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifi_rssi >= (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifi_rssi >= (rssi_thresh1+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifi_rssi < rssi_thresh) + { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifi_rssi < rssi_thresh1) + { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void +halbtc8812a1ant_MonitorBtEnableDisable( + PBTC_COEXIST btcoexist + ) +{ + static BOOLEAN pre_bt_disabled=false; + static u4Byte bt_disable_cnt=0; + BOOLEAN bt_active=true, bt_disable_by68=false, bt_disabled=false; + u4Byte u4_tmp=0; + + // This function check if bt is disabled + + if( coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + { + bt_active = false; + } + if( coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + { + bt_active = false; + } + if(bt_active) + { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + bt_disable_cnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt)); + if(bt_disable_cnt >= 2 ||bt_disable_by68) + { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(pre_bt_disabled != bt_disabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (pre_bt_disabled ? "disabled":"enabled"), + (bt_disabled ? "disabled":"enabled"))); + pre_bt_disabled = bt_disabled; + if(!bt_disabled) + { + } + else + { + } + } +} + +void +halbtc8812a1ant_MonitorBtCtr( + PBTC_COEXIST btcoexist + ) +{ + u4Byte reg_hp_tx_rx, reg_lp_tx_rx, u4_tmp; + u4Byte reg_hp_tx=0, reg_hp_rx=0, reg_lp_tx=0, reg_lp_rx=0; + u1Byte u1_tmp; + + reg_hp_tx_rx = 0x770; + reg_lp_tx_rx = 0x774; + + u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_tx_rx); + reg_hp_tx = u4_tmp & bMaskLWord; + reg_hp_rx = (u4_tmp & bMaskHWord)>>16; + + u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_tx_rx); + reg_lp_tx = u4_tmp & bMaskLWord; + reg_lp_rx = (u4_tmp & bMaskHWord)>>16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n", + reg_hp_tx_rx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n", + reg_lp_tx_rx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx)); + + // reset counter + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +void +halbtc8812a1ant_QueryBtInfo( + PBTC_COEXIST btcoexist + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + static u4Byte btInfoCnt=0; + + if(!btInfoCnt || + (coex_sta->bt_info_c2h_cnt[BT_INFO_SRC_8812A_1ANT_BT_RSP]-btInfoCnt)>2) + { + buf[0] = dataLen; + buf[1] = 0x1; // polling enable, 1=enable, 0=disable + buf[2] = 0x2; // polling time in seconds + buf[3] = 0x1; // auto report enable, 1=enable, 0=disable + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_INFO, (PVOID)&buf[0]); + } + btInfoCnt = coex_sta->bt_info_c2h_cnt[BT_INFO_SRC_8812A_1ANT_BT_RSP]; +} +u1Byte +halbtc8812a1ant_ActionAlgorithm( + PBTC_COEXIST btcoexist + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + BOOLEAN bt_hs_on=false; + u1Byte algorithm=BT_8812A_1ANT_COEX_ALGO_UNDEFINED; + u1Byte num_of_diff_profile=0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if(!stack_info->bt_link_exist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if(stack_info->sco_exist) + num_of_diff_profile++; + if(stack_info->hid_exist) + num_of_diff_profile++; + if(stack_info->pan_exist) + num_of_diff_profile++; + if(stack_info->a2dp_exist) + num_of_diff_profile++; + + if(num_of_diff_profile == 1) + { + if(stack_info->sco_exist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else + { + if(stack_info->hid_exist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } + else if(stack_info->a2dp_exist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_A2DP; + } + else if(stack_info->pan_exist) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(num_of_diff_profile == 2) + { + if(stack_info->sco_exist) + { + if(stack_info->hid_exist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } + else if(stack_info->a2dp_exist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else if(stack_info->pan_exist) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( stack_info->hid_exist && + stack_info->a2dp_exist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else if( stack_info->hid_exist && + stack_info->pan_exist ) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( stack_info->pan_exist && + stack_info->a2dp_exist ) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(num_of_diff_profile == 3) + { + if(stack_info->sco_exist) + { + if( stack_info->hid_exist && + stack_info->a2dp_exist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } + else if( stack_info->hid_exist && + stack_info->pan_exist ) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( stack_info->pan_exist && + stack_info->a2dp_exist ) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( stack_info->hid_exist && + stack_info->pan_exist && + stack_info->a2dp_exist ) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(num_of_diff_profile >= 3) + { + if(stack_info->sco_exist) + { + if( stack_info->hid_exist && + stack_info->pan_exist && + stack_info->a2dp_exist ) + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +BOOLEAN +halbtc8812a1ant_NeedToDecBtPwr( + PBTC_COEXIST btcoexist + ) +{ + BOOLEAN ret=false; + BOOLEAN bt_hs_on=false, wifi_connected=false; + s4Byte bt_hs_rssi=0; + + if(!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on)) + return false; + if(!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected)) + return false; + if(!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi)) + return false; + + if(wifi_connected) + { + if(bt_hs_on) + { + if(bt_hs_rssi > 37) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for HS mode!!\n")); + ret = true; + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for Wifi is connected!!\n")); + ret = true; + } + } + + return ret; +} + +void +halbtc8812a1ant_SetFwDacSwingLevel( + PBTC_COEXIST btcoexist, + u1Byte dac_swing_lvl + ) +{ + u1Byte h2c_parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + h2c_parameter[0] = dac_swing_lvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64=0x%x\n", h2c_parameter[0])); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void +halbtc8812a1ant_SetFwDecBtPwr( + PBTC_COEXIST btcoexist, + BOOLEAN dec_bt_pwr + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power : %s\n", + (dec_bt_pwr? "Yes!!":"No!!"))); + + buf[0] = dataLen; + buf[1] = 0x3; // OP_Code + buf[2] = 0x1; // OP_Code_Length + if(dec_bt_pwr) + buf[3] = 0x1; // OP_Code_Content + else + buf[3] = 0x0; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +void +halbtc8812a1ant_DecBtPwr( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN dec_bt_pwr + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power = %s\n", + (force_exec? "force to":""), ((dec_bt_pwr)? "ON":"OFF"))); + coex_dm->cur_dec_bt_pwr = dec_bt_pwr; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], pre_dec_bt_pwr=%d, cur_dec_bt_pwr=%d\n", + coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr)); + + if(coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) + return; + } + halbtc8812a1ant_SetFwDecBtPwr(btcoexist, coex_dm->cur_dec_bt_pwr); + + coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +void +halbtc8812a1ant_SetFwBtLnaConstrain( + PBTC_COEXIST btcoexist, + BOOLEAN bt_lna_cons_on + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set BT LNA Constrain: %s\n", + (bt_lna_cons_on? "ON!!":"OFF!!"))); + + buf[0] = dataLen; + buf[1] = 0x2; // OP_Code + buf[2] = 0x1; // OP_Code_Length + if(bt_lna_cons_on) + buf[3] = 0x1; // OP_Code_Content + else + buf[3] = 0x0; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +void +halbtc8812a1ant_SetBtLnaConstrain( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN bt_lna_cons_on + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Constrain = %s\n", + (force_exec? "force":""), ((bt_lna_cons_on)? "ON":"OFF"))); + coex_dm->bCurBtLnaConstrain = bt_lna_cons_on; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtLnaConstrain=%d, bCurBtLnaConstrain=%d\n", + coex_dm->bPreBtLnaConstrain, coex_dm->bCurBtLnaConstrain)); + + if(coex_dm->bPreBtLnaConstrain == coex_dm->bCurBtLnaConstrain) + return; + } + halbtc8812a1ant_SetFwBtLnaConstrain(btcoexist, coex_dm->bCurBtLnaConstrain); + + coex_dm->bPreBtLnaConstrain = coex_dm->bCurBtLnaConstrain; +} + +void +halbtc8812a1ant_SetFwBtPsdMode( + PBTC_COEXIST btcoexist, + u1Byte bt_psd_mode + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set BT PSD mode=0x%x\n", + bt_psd_mode)); + + buf[0] = dataLen; + buf[1] = 0x4; // OP_Code + buf[2] = 0x1; // OP_Code_Length + buf[3] = bt_psd_mode; // OP_Code_Content + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + + +void +halbtc8812a1ant_SetBtPsdMode( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + u1Byte bt_psd_mode + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT PSD mode = 0x%x\n", + (force_exec? "force":""), bt_psd_mode)); + coex_dm->bCurBtPsdMode = bt_psd_mode; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtPsdMode=0x%x, bCurBtPsdMode=0x%x\n", + coex_dm->bPreBtPsdMode, coex_dm->bCurBtPsdMode)); + + if(coex_dm->bPreBtPsdMode == coex_dm->bCurBtPsdMode) + return; + } + halbtc8812a1ant_SetFwBtPsdMode(btcoexist, coex_dm->bCurBtPsdMode); + + coex_dm->bPreBtPsdMode = coex_dm->bCurBtPsdMode; +} + + +void +halbtc8812a1ant_SetBtAutoReport( + PBTC_COEXIST btcoexist, + BOOLEAN enable_auto_report + ) +{ +#if 0 + u1Byte h2c_parameter[1] ={0}; + + h2c_parameter[0] = 0; + + if(enable_auto_report) + { + h2c_parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (enable_auto_report? "Enabled!!":"Disabled!!"), h2c_parameter[0])); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +#else + +#endif +} + +void +halbtc8812a1ant_BtAutoReport( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN enable_auto_report + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (force_exec? "force to":""), ((enable_auto_report)? "Enabled":"Disabled"))); + coex_dm->cur_bt_auto_report = enable_auto_report; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], pre_bt_auto_report=%d, cur_bt_auto_report=%d\n", + coex_dm->pre_bt_auto_report, coex_dm->cur_bt_auto_report)); + + if(coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8812a1ant_SetBtAutoReport(btcoexist, coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void +halbtc8812a1ant_FwDacSwingLvl( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + u1Byte fw_dac_swing_lvl + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec? "force to":""), fw_dac_swing_lvl)); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], pre_fw_dac_swing_lvl=%d, cur_fw_dac_swing_lvl=%d\n", + coex_dm->pre_fw_dac_swing_lvl, coex_dm->cur_fw_dac_swing_lvl)); + + if(coex_dm->pre_fw_dac_swing_lvl == coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8812a1ant_SetFwDacSwingLevel(btcoexist, coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void +halbtc8812a1ant_SetSwRfRxLpfCorner( + PBTC_COEXIST btcoexist, + BOOLEAN rx_rf_shrink_on + ) +{ + if(rx_rf_shrink_on) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff, 0xf0ff7); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use coex_dm->bt_rf0x1e_backup + if(btcoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff, coex_dm->bt_rf0x1e_backup); + } + } +} + +void +halbtc8812a1ant_RfShrink( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN rx_rf_shrink_on + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec? "force to":""), ((rx_rf_shrink_on)? "ON":"OFF"))); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], pre_rf_rx_lpf_shrink=%d, cur_rf_rx_lpf_shrink=%d\n", + coex_dm->pre_rf_rx_lpf_shrink, coex_dm->cur_rf_rx_lpf_shrink)); + + if(coex_dm->pre_rf_rx_lpf_shrink == coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8812a1ant_SetSwRfRxLpfCorner(btcoexist, coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void +halbtc8812a1ant_SetSwPenaltyTxRateAdaptive( + PBTC_COEXIST btcoexist, + BOOLEAN low_penalty_ra + ) +{ + u1Byte u1_tmp; + + u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x4fd); + u1_tmp |= BIT0; + if(low_penalty_ra) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + u1_tmp &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + u1_tmp |= BIT2; + } + + btcoexist->btc_write_1byte(btcoexist, 0x4fd, u1_tmp); +} + +void +halbtc8812a1ant_LowPenaltyRa( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN low_penalty_ra + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (force_exec? "force to":""), ((low_penalty_ra)? "ON":"OFF"))); + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], pre_low_penalty_ra=%d, cur_low_penalty_ra=%d\n", + coex_dm->pre_low_penalty_ra, coex_dm->cur_low_penalty_ra)); + + if(coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8812a1ant_SetSwPenaltyTxRateAdaptive(btcoexist, coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void +halbtc8812a1ant_SetDacSwingReg( + PBTC_COEXIST btcoexist, + u4Byte level + ) +{ + u1Byte val=(u1Byte)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val); +} + +void +halbtc8812a1ant_SetSwFullTimeDacSwing( + PBTC_COEXIST btcoexist, + BOOLEAN sw_dac_swing_on, + u4Byte sw_dac_swing_lvl + ) +{ + if(sw_dac_swing_on) + { + halbtc8812a1ant_SetDacSwingReg(btcoexist, sw_dac_swing_lvl); + } + else + { + halbtc8812a1ant_SetDacSwingReg(btcoexist, 0x18); + } +} + + +void +halbtc8812a1ant_DacSwing( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN dac_swing_on, + u4Byte dac_swing_lvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dac_swing_lvl=0x%x\n", + (force_exec? "force to":""), ((dac_swing_on)? "ON":"OFF"), dac_swing_lvl)); + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], pre_dac_swing_on=%d, pre_dac_swing_lvl=0x%x, cur_dac_swing_on=%d, cur_dac_swing_lvl=0x%x\n", + coex_dm->pre_dac_swing_on, coex_dm->pre_dac_swing_lvl, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl)); + + if( (coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl) ) + return; + } + delay_ms(30); + halbtc8812a1ant_SetSwFullTimeDacSwing(btcoexist, dac_swing_on, dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void +halbtc8812a1ant_SetAdcBackOff( + PBTC_COEXIST btcoexist, + BOOLEAN adc_back_off + ) +{ + if(adc_back_off) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1); + } +} + +void +halbtc8812a1ant_AdcBackOff( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN adc_back_off + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (force_exec? "force to":""), ((adc_back_off)? "ON":"OFF"))); + coex_dm->cur_adc_back_off = adc_back_off; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], pre_adc_back_off=%d, cur_adc_back_off=%d\n", + coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off)); + + if(coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8812a1ant_SetAdcBackOff(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +void +halbtc8812a1ant_SetAgcTable( + PBTC_COEXIST btcoexist, + BOOLEAN agc_table_en + ) +{ + u1Byte rssi_adjust_val=0; + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if(agc_table_en) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, 0x3fa58); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, 0x37a58); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, 0x2fa58); + rssi_adjust_val = 8; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, 0x39258); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, 0x31258); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, 0x29258); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + // set rssi_adjust_val for wifi module. + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssi_adjust_val); +} + + +void +halbtc8812a1ant_AgcTable( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN agc_table_en + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (force_exec? "force to":""), ((agc_table_en)? "Enable":"Disable"))); + coex_dm->cur_agc_table_en = agc_table_en; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], pre_agc_table_en=%d, cur_agc_table_en=%d\n", + coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en)); + + if(coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8812a1ant_SetAgcTable(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void +halbtc8812a1ant_SetCoexTable( + PBTC_COEXIST btcoexist, + u4Byte val0x6c0, + u4Byte val0x6c4, + u4Byte val0x6c8, + u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void +halbtc8812a1ant_CoexTable( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + u4Byte val0x6c0, + u4Byte val0x6c4, + u4Byte val0x6c8, + u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (force_exec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], pre_val0x6c0=0x%x, pre_val0x6c4=0x%x, pre_val0x6c8=0x%x, pre_val0x6cc=0x%x !!\n", + coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4, coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], cur_val0x6c0=0x%x, cur_val0x6c4=0x%x, cur_val0x6c8=0x%x, cur_val0x6cc=0x%x !!\n", + coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4, coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc)); + + if( (coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc) ) + return; + } + halbtc8812a1ant_SetCoexTable(btcoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void +halbtc8812a1ant_SetFwIgnoreWlanAct( + PBTC_COEXIST btcoexist, + BOOLEAN enable + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], %s BT Ignore Wlan_Act\n", + (enable? "Enable":"Disable"))); + + buf[0] = dataLen; + buf[1] = 0x1; // OP_Code + buf[2] = 0x1; // OP_Code_Length + if(enable) + buf[3] = 0x1; // OP_Code_Content + else + buf[3] = 0x0; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +void +halbtc8812a1ant_IgnoreWlanAct( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN enable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec? "force to":""), (enable? "ON":"OFF"))); + coex_dm->cur_ignore_wlan_act = enable; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n", + coex_dm->pre_ignore_wlan_act, coex_dm->cur_ignore_wlan_act)); + + if(coex_dm->pre_ignore_wlan_act == coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8812a1ant_SetFwIgnoreWlanAct(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void +halbtc8812a1ant_SetFwPstdma( + PBTC_COEXIST btcoexist, + u1Byte byte1, + u1Byte byte2, + u1Byte byte3, + u1Byte byte4, + u1Byte byte5 + ) +{ + u1Byte h2c_parameter[5] ={0}; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1]<<24|h2c_parameter[2]<<16|h2c_parameter[3]<<8|h2c_parameter[4])); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void +halbtc8812a1ant_SetLpsRpwm( + PBTC_COEXIST btcoexist, + u1Byte lps_val, + u1Byte rpwm_val + ) +{ + u1Byte lps=lps_val; + u1Byte rpwm=rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_1ANT_LPS, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_1ANT_RPWM, &rpwm); + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT, NULL); +} + +void +halbtc8812a1ant_LpsRpwm( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + u1Byte lps_val, + u1Byte rpwm_val + ) +{ + BOOLEAN bForceExecPwrCmd=false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (force_exec? "force to":""), lps_val, rpwm_val)); + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], pre_lps/cur_lps=0x%x/0x%x, pre_rpwm/cur_rpwm=0x%x/0x%x!!\n", + coex_dm->pre_lps, coex_dm->cur_lps, coex_dm->pre_rpwm, coex_dm->cur_rpwm)); + + if( (coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm) ) + { + return; + } + } + halbtc8812a1ant_SetLpsRpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void +halbtc8812a1ant_SwMechanism1( + PBTC_COEXIST btcoexist, + BOOLEAN shrink_rx_lpf, + BOOLEAN low_penalty_ra, + BOOLEAN limited_dig, + BOOLEAN bt_lna_constrain + ) +{ + //halbtc8812a1ant_RfShrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); + //halbtc8812a1ant_LowPenaltyRa(btcoexist, NORMAL_EXEC, low_penalty_ra); + + //no limited DIG + //halbtc8812a1ant_SetBtLnaConstrain(btcoexist, NORMAL_EXEC, bt_lna_constrain); +} + +void +halbtc8812a1ant_SwMechanism2( + PBTC_COEXIST btcoexist, + BOOLEAN agc_table_shift, + BOOLEAN adc_back_off, + BOOLEAN sw_dac_swing, + u4Byte dac_swing_lvl + ) +{ + //halbtc8812a1ant_AgcTable(btcoexist, NORMAL_EXEC, agc_table_shift); + //halbtc8812a1ant_AdcBackOff(btcoexist, NORMAL_EXEC, adc_back_off); + //halbtc8812a1ant_DacSwing(btcoexist, NORMAL_EXEC, sw_dac_swing, dac_swing_lvl); +} + +void +halbtc8812a1ant_PsTdma( + PBTC_COEXIST btcoexist, + BOOLEAN force_exec, + BOOLEAN turn_on, + u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=false; + u1Byte psTdmaTypeByCnt=0, rssi_adjust_val=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (force_exec? "force to":""), (turn_on? "ON":"OFF"), type)); + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if(!force_exec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], pre_ps_tdma_on = %d, cur_ps_tdma_on = %d!!\n", + coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], pre_ps_tdma = %d, cur_ps_tdma = %d!!\n", + coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma)); + + if( (coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma) ) + return; + } + if(turn_on) + { + switch(type) + { + default: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x58); + break; + case 1: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x48); + rssi_adjust_val = 11; + break; + case 2: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0x12, 0x12, 0x0, 0x48); + rssi_adjust_val = 14; + break; + case 3: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x93, 0x25, 0x3, 0x10, 0x40); + break; + case 4: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + rssi_adjust_val = 17; + break; + case 5: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x61, 0x15, 0x3, 0x31, 0x0); + break; + case 6: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x13, 0xa, 0x3, 0x0, 0x0); + break; + case 7: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x13, 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0xa, 0xa, 0x0, 0x48); + rssi_adjust_val = 18; + break; + case 10: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0x5, 0x5, 0x0, 0x48); + rssi_adjust_val = 20; + break; + case 12: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xeb, 0xa, 0x3, 0x31, 0x18); + break; + + case 15: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x13, 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x93, 0x15, 0x3, 0x10, 0x0); + rssi_adjust_val = 18; + break; + + case 18: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + rssi_adjust_val = 14; + break; + + case 20: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x13, 0x25, 0x25, 0x0, 0x0); + break; + case 21: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x93, 0x20, 0x3, 0x10, 0x40); + break; + case 22: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x13, 0x8, 0x8, 0x0, 0x40); + break; + case 23: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 24: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 25: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 26: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 27: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); + rssi_adjust_val = 22; + break; + case 28: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x69, 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xab, 0x1a, 0x1a, 0x1, 0x8); + break; + case 30: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + break; + case 31: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xab, 0xa, 0x3, 0x31, 0x88); + break; + case 33: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xa3, 0x25, 0x3, 0x30, 0x88); + break; + case 34: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x8); + break; + case 35: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, 0x1a, 0x0, 0x8); + break; + case 36: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0xd3, 0x12, 0x3, 0x14, 0x58); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 8: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + case 0: + default: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + delay_ms(5); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + break; + case 9: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + case 10: + halbtc8812a1ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + delay_ms(5); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + break; + } + } + rssi_adjust_val =0; + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val); + + // update pre state + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void +halbtc8812a1ant_CoexAllOff( + PBTC_COEXIST btcoexist + ) +{ + // fw all off + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + // sw all off + halbtc8812a1ant_SwMechanism1(btcoexist,false,false,false,false); + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + + + // hw all off + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); +} + +void +halbtc8812a1ant_WifiParaAdjust( + PBTC_COEXIST btcoexist, + BOOLEAN enable + ) +{ + if(enable) + { + halbtc8812a1ant_LowPenaltyRa(btcoexist, NORMAL_EXEC, true); + } + else + { + halbtc8812a1ant_LowPenaltyRa(btcoexist, NORMAL_EXEC, false); + } +} + +BOOLEAN +halbtc8812a1ant_IsCommonAction( + PBTC_COEXIST btcoexist + ) +{ + BOOLEAN common=false, wifi_connected=false, wifi_busy=false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + //halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + + if(!wifi_connected && + BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")); + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + halbtc8812a1ant_SwMechanism1(btcoexist,false,false,false,false); + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + + common = true; + } + else if(wifi_connected && + (BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + + halbtc8812a1ant_SwMechanism1(btcoexist,false,false,false,false); + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + + common = true; + } + else if(!wifi_connected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")); + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + halbtc8812a1ant_SwMechanism1(btcoexist,false,false,false,false); + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + + common = true; + } + else if(wifi_connected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + halbtc8812a1ant_SwMechanism1(btcoexist,true,true,true,true); + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + + common = true; + } + else if(!wifi_connected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE != coex_dm->bt_status) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + halbtc8812a1ant_SwMechanism1(btcoexist,false,false,false,false); + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + + common = true; + } + else + { + halbtc8812a1ant_SwMechanism1(btcoexist,true,true,true,true); + + common = false; + } + + return common; +} + + +void +halbtc8812a1ant_TdmaDurationAdjustForAcl( + PBTC_COEXIST btcoexist + ) +{ + static s4Byte up,dn,m,n,wait_count; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retry_count=0, bt_info_ext; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], halbtc8812a1ant_TdmaDurationAdjustForAcl()\n")); + if(coex_dm->reset_tdma_adjust) + { + coex_dm->reset_tdma_adjust = false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + wait_count = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retry_count = %d\n", retry_count)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_count=%d\n", + up, dn, m, n, wait_count)); + result = 0; + wait_count++; + + if(retry_count == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if ³sÄò n ­Ó2¬í retry count¬°0, «h½Õ¼eWiFi duration + { + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retry_count <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if ³sÄò 2 ­Ó2¬í retry count< 3, «h½Õ¯¶WiFi duration + { + if (wait_count <= 2) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, ¥u­n1¦¸ retry count > 3, «h½Õ¯¶WiFi duration + { + if (wait_count == 1) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + if(result == -1) + { + if( (BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) ||(coex_dm->cur_ps_tdma == 2)) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } + else if(coex_dm->cur_ps_tdma == 1) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } + else if(coex_dm->cur_ps_tdma == 2) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } + else if(coex_dm->cur_ps_tdma == 9) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } + else if(result == 1) + { + if( (BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) ||(coex_dm->cur_ps_tdma == 2)) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } + else if(coex_dm->cur_ps_tdma == 11) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } + else if(coex_dm->cur_ps_tdma == 9) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } + else if(coex_dm->cur_ps_tdma == 2) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } + } + + if( coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && + coex_dm->cur_ps_tdma != 11 ) + { + // recover to previous adjust type + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, coex_dm->ps_tdma_du_adj_type); + } + } +} + +u1Byte +halbtc8812a1ant_PsTdmaTypeByWifiRssi( + s4Byte wifi_rssi, + s4Byte pre_wifi_rssi, + u1Byte wifi_rssi_thresh + ) +{ + u1Byte ps_tdma_type=0; + + if(wifi_rssi > pre_wifi_rssi) + { + if(wifi_rssi > (wifi_rssi_thresh+5)) + { + ps_tdma_type = 26; + } + else + { + ps_tdma_type = 25; + } + } + else + { + if(wifi_rssi > wifi_rssi_thresh) + { + ps_tdma_type = 26; + } + else + { + ps_tdma_type = 25; + } + } + + return ps_tdma_type; +} + +void +halbtc8812a1ant_PsTdmaCheckForPowerSaveState( + PBTC_COEXIST btcoexist, + BOOLEAN new_ps_state + ) +{ + u1Byte lps_mode=0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if(lps_mode) // already under LPS state + { + if(new_ps_state) + { + // keep state under LPS, do nothing. + } + else + { + // will leave LPS state, turn off psTdma first + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 0); + } + } + else // NO PS state + { + if(new_ps_state) + { + // will enter LPS state, turn off psTdma first + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 0); + } + else + { + // keep state under NO PS state, do nothing. + } + } +} + +// SCO only or SCO+PAN(HS) +void +halbtc8812a1ant_ActionSco( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state; + u4Byte wifi_bw; + + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 4); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + + +void +halbtc8812a1ant_ActionHid( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state; + u4Byte wifi_bw; + + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,false,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +void +halbtc8812a1ant_ActionA2dp( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state; + u4Byte wifi_bw; + + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +void +halbtc8812a1ant_ActionA2dpPanHs( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state, bt_info_ext; + u4Byte wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +void +halbtc8812a1ant_ActionPanEdr( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state; + u4Byte wifi_bw; + + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + + +//PAN(HS) only +void +halbtc8812a1ant_ActionPanHs( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state; + u4Byte wifi_bw; + + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // fw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + } + else + { + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + } + + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // fw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + } + else + { + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + } + + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +//PAN(EDR)+A2DP +void +halbtc8812a1ant_ActionPanEdrA2dp( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state, bt_info_ext; + u4Byte wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +void +halbtc8812a1ant_ActionPanEdrHid( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state; + u4Byte wifi_bw; + + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +// HID+A2DP+PAN(EDR) +void +halbtc8812a1ant_ActionHidA2dpPanEdr( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state, bt_info_ext; + u4Byte wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, NORMAL_EXEC, 6); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +void +halbtc8812a1ant_ActionHidA2dp( + PBTC_COEXIST btcoexist + ) +{ + u1Byte wifi_rssi_state, bt_rssi_state, bt_info_ext; + u4Byte wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8812a1ant_WifiRssiState(btcoexist, 0, 2, 25, 0); + bt_rssi_state = halbtc8812a1ant_BtRssiState(2, 50, 0); + + if(halbtc8812a1ant_NeedToDecBtPwr(btcoexist)) + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8812a1ant_DecBtPwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 == wifi_bw) + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,true,false,0x18); + } + } + else + { + // sw mechanism + if( (wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8812a1ant_SwMechanism2(btcoexist,true,true,false,0x18); + } + else + { + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + } + } +} + +void +halbtc8812a1ant_ActionHs( + PBTC_COEXIST btcoexist, + BOOLEAN hs_connecting + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action for HS, hs_connecting=%d!!!\n", hs_connecting)); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + + if(hs_connecting) + { + halbtc8812a1ant_CoexTable(btcoexist, FORCE_EXEC, 0xaaaaaaaa, 0xaaaaaaaa, 0xffff, 0x3); + } + else + { + if((coex_sta->high_priority_tx+coex_sta->high_priority_rx+ + coex_sta->low_priority_tx+coex_sta->low_priority_rx)<=1200) + halbtc8812a1ant_CoexTable(btcoexist, FORCE_EXEC, 0xaaaaaaaa, 0xaaaaaaaa, 0xffff, 0x3); + else + halbtc8812a1ant_CoexTable(btcoexist, FORCE_EXEC, 0xffffffff, 0xffffffff, 0xffff, 0x3); + } +} + + +void +halbtc8812a1ant_ActionWifiNotConnected( + PBTC_COEXIST btcoexist + ) +{ + BOOLEAN hs_connecting=false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + + if(hs_connecting) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HS is connecting!!!\n")); + halbtc8812a1ant_ActionHs(btcoexist, hs_connecting); + } + else + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } +} + +void +halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan( + PBTC_COEXIST btcoexist + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + BOOLEAN hs_connecting=false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + + if(hs_connecting) + { + halbtc8812a1ant_ActionHs(btcoexist, hs_connecting); + } + else if(btcoexist->bt_info.bt_disabled) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if(BT_8812A_1ANT_BT_STATUS_INQ_PAGE == coex_dm->bt_status) +{ + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if( (BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 28); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) + { + if(stack_info->hid_exist) + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 35); + else + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 29); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); + } + else + { + //error condition, should not reach here, record error number for debugging. + coex_dm->error_condition = 1; + } +} + +void +halbtc8812a1ant_ActionWifiConnectedScan( + PBTC_COEXIST btcoexist + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ActionConnectedScan()===>\n")); + + if(btcoexist->bt_info.bt_disabled) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x0, 0x4); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + + // psTdma + if(BT_8812A_1ANT_BT_STATUS_INQ_PAGE == coex_dm->bt_status) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ActionConnectedScan(), bt is under inquiry/page scan\n")); + if(stack_info->sco_exist) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + } + else if( (BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) + { + if(stack_info->hid_exist) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 34); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 4); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + //error condition, should not reach here + coex_dm->error_condition = 2; + } + } + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ActionConnectedScan()<===\n")); +} + +void +halbtc8812a1ant_ActionWifiConnectedSpecialPacket( + PBTC_COEXIST btcoexist + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + + if(btcoexist->bt_info.bt_disabled) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else + { + if(BT_8812A_1ANT_BT_STATUS_INQ_PAGE == coex_dm->bt_status) + { + if(stack_info->sco_exist) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + } + else if( (BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 28); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) + { + if(stack_info->hid_exist) + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 35); + else + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 29); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); + } + else + { + //error condition, should not reach here + coex_dm->error_condition = 3; + } + } +} + +void +halbtc8812a1ant_ActionWifiConnected( + PBTC_COEXIST btcoexist + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + BOOLEAN wifi_connected=false, wifi_busy=false, bt_hs_on=false; + BOOLEAN scan=false, link=false, roam=false; + BOOLEAN hs_connecting=false, under4way=false; + u4Byte wifi_bw; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect()===>\n")); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if(!wifi_connected) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi not connected<===\n")); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &under4way); + if(under4way) + { + halbtc8812a1ant_ActionWifiConnectedSpecialPacket(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if(scan || link || roam) + { + halbtc8812a1ant_ActionWifiConnectedScan(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + if(!wifi_busy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi associated-idle!!!\n")); + if(btcoexist->bt_info.bt_disabled) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x0, 0x4); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else + { + if(BT_8812A_1ANT_BT_STATUS_INQ_PAGE == coex_dm->bt_status) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], bt is under inquiry/page scan!!!\n")); + if(stack_info->sco_exist) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x0, 0x4); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + } + else if(BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x26, 0x0); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if(BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x26, 0x0); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) + { + if(stack_info->hid_exist && stack_info->numOfLink==1) + { + // hid only + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5fff5fff, 0x5fff5fff, 0xffff, 0x3); + coex_dm->reset_tdma_adjust = true; + } + else + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x0, 0x4); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + + if(stack_info->hid_exist) + { + if(stack_info->a2dp_exist) + { + // hid+a2dp + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else if(stack_info->pan_exist) + { + if(bt_hs_on) + { + // hid+hs + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + } + else + { + // hid+pan + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + } + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + coex_dm->error_condition = 4; + } + coex_dm->reset_tdma_adjust = true; + } + else if(stack_info->a2dp_exist) + { + if(stack_info->pan_exist) + { + if(bt_hs_on) + { + // a2dp+hs + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + } + else + { + // a2dp+pan + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 36); + } + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + coex_dm->reset_tdma_adjust = true; + } + else + { + // a2dp only + halbtc8812a1ant_TdmaDurationAdjustForAcl(btcoexist); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + } + else if(stack_info->pan_exist) + { + // pan only + if(bt_hs_on) + { + coex_dm->error_condition = 5; + } + else + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + coex_dm->reset_tdma_adjust = true; + } + else + { + // temp state, do nothing!!! + //DbgPrint("error 6, coex_dm->bt_status=%d\n", coex_dm->bt_status); + //DbgPrint("error 6, stack_info->numOfLink=%d, stack_info->hid_exist=%d, stack_info->a2dp_exist=%d, stack_info->pan_exist=%d, stack_info->sco_exist=%d\n", + //stack_info->numOfLink, stack_info->hid_exist, stack_info->a2dp_exist, stack_info->pan_exist, stack_info->sco_exist); + //coex_dm->error_condition = 6; + } + } + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); + } + else + { + //error condition, should not reach here + coex_dm->error_condition = 7; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi busy!!!\n")); + if(btcoexist->bt_info.bt_disabled) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else + { + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HS is under progress!!!\n")); + //DbgPrint("coex_dm->bt_status = 0x%x\n", coex_dm->bt_status); + halbtc8812a1ant_ActionHs(btcoexist, hs_connecting); + } + else if(BT_8812A_1ANT_BT_STATUS_INQ_PAGE == coex_dm->bt_status) + { + if(stack_info->sco_exist) + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x0, 0x4); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + } + else if(BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); + } + else if(BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + if(bt_hs_on) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HS is under progress!!!\n")); + halbtc8812a1ant_ActionHs(btcoexist, hs_connecting); + } + else + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); + } + } + else if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) + { + if(stack_info->hid_exist && stack_info->numOfLink==1) + { + // hid only + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5fff5fff, 0x5fff5fff, 0xffff, 0x3); + coex_dm->reset_tdma_adjust = true; + } + else + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x0, 0x4); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + + if(stack_info->hid_exist) + { + if(stack_info->a2dp_exist) + { + // hid+a2dp + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else if(stack_info->pan_exist) + { + if(bt_hs_on) + { + // hid+hs + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + } + else + { + // hid+pan + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + } + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + else + { + coex_dm->error_condition = 8; + } + coex_dm->reset_tdma_adjust = true; + } + else if(stack_info->a2dp_exist) + { + if(stack_info->pan_exist) + { + if(bt_hs_on) + { + // a2dp+hs + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + } + else + { + // a2dp+pan + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 36); + } + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + coex_dm->reset_tdma_adjust = true; + } + else + { + // a2dp only + halbtc8812a1ant_TdmaDurationAdjustForAcl(btcoexist); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + } + else if(stack_info->pan_exist) + { + // pan only + if(bt_hs_on) + { + coex_dm->error_condition = 9; + } + else + { + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, true, 2); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + } + coex_dm->reset_tdma_adjust = true; + } + else + { + //DbgPrint("error 10, stack_info->numOfLink=%d, stack_info->hid_exist=%d, stack_info->a2dp_exist=%d, stack_info->pan_exist=%d, stack_info->sco_exist=%d\n", + //stack_info->numOfLink, stack_info->hid_exist, stack_info->a2dp_exist, stack_info->pan_exist, stack_info->sco_exist); + coex_dm->error_condition = 10; + } + } + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status) ) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); + } + else + { + //DbgPrint("error 11, coex_dm->bt_status=%d\n", coex_dm->bt_status); + //DbgPrint("error 11, stack_info->numOfLink=%d, stack_info->hid_exist=%d, stack_info->a2dp_exist=%d, stack_info->pan_exist=%d, stack_info->sco_exist=%d\n", + //stack_info->numOfLink, stack_info->hid_exist, stack_info->a2dp_exist, stack_info->pan_exist, stack_info->sco_exist); + //error condition, should not reach here + coex_dm->error_condition = 11; + } + } + } + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect()<===\n")); +} + +void +halbtc8812a1ant_RunSwCoexistMechanism( + PBTC_COEXIST btcoexist + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + BOOLEAN wifi_under5g=false, wifi_busy=false, wifi_connected=false; + u1Byte bt_info_original=0, bt_retry_cnt=0; + u1Byte algorithm=0; + + return; + if(stack_info->bProfileNotified) + { + algorithm = halbtc8812a1ant_ActionAlgorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d \n", coex_dm->cur_algorithm)); + + if(halbtc8812a1ant_IsCommonAction(btcoexist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action common.\n")); + } + else + { + switch(coex_dm->cur_algorithm) + { + case BT_8812A_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n")); + halbtc8812a1ant_ActionSco(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n")); + halbtc8812a1ant_ActionHid(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n")); + halbtc8812a1ant_ActionA2dp(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n")); + halbtc8812a1ant_ActionA2dpPanHs(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n")); + halbtc8812a1ant_ActionPanEdr(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n")); + halbtc8812a1ant_ActionPanHs(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n")); + halbtc8812a1ant_ActionPanEdrA2dp(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n")); + halbtc8812a1ant_ActionPanEdrHid(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n")); + halbtc8812a1ant_ActionHidA2dpPanEdr(btcoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n")); + halbtc8812a1ant_ActionHidA2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n")); + halbtc8812a1ant_CoexAllOff(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } + } +} + +void +halbtc8812a1ant_RunCoexistMechanism( + PBTC_COEXIST btcoexist + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + BOOLEAN wifi_under5g=false, wifi_busy=false, wifi_connected=false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under5g); + + if(wifi_under5g) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for 5G <===\n")); + return; + } + + if(btcoexist->manual_control) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(btcoexist->stop_coex_dm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n")); + return; + } + + halbtc8812a1ant_RunSwCoexistMechanism(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if(btcoexist->bt_info.bt_disabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], bt is disabled!!!\n")); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + if(wifi_busy) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + } + else + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, true); + halbtc8812a1ant_LpsRpwm(btcoexist, NORMAL_EXEC, 0x0, 0x4); + // power save must executed before psTdma. + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + } + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + } + else if(coex_sta->under_ips) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8812a1ant_CoexTable(btcoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + halbtc8812a1ant_WifiParaAdjust(btcoexist, false); + } + else if(!wifi_connected) + { + BOOLEAN scan=false, link=false, roam=false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n")); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if(scan || link || roam) + halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan(btcoexist); + else + halbtc8812a1ant_ActionWifiNotConnected(btcoexist); + } + else // wifi LPS/Busy + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is NOT under IPS!!!\n")); + halbtc8812a1ant_WifiParaAdjust(btcoexist, true); + halbtc8812a1ant_ActionWifiConnected(btcoexist); + } + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()<===\n")); +} + +void +halbtc8812a1ant_InitCoexDm( + PBTC_COEXIST btcoexist + ) +{ + BOOLEAN wifi_connected=false; + // force to reset coex mechanism + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if(!wifi_connected) // non-connected scan + { + halbtc8812a1ant_ActionWifiNotConnected(btcoexist); + } + else // wifi is connected + { + halbtc8812a1ant_ActionWifiConnected(btcoexist); + } + + halbtc8812a1ant_FwDacSwingLvl(btcoexist, FORCE_EXEC, 6); + halbtc8812a1ant_DecBtPwr(btcoexist, FORCE_EXEC, false); + + // sw all off + halbtc8812a1ant_SwMechanism1(btcoexist,false,false,false,false); + halbtc8812a1ant_SwMechanism2(btcoexist,false,false,false,0x18); + + halbtc8812a1ant_CoexTable(btcoexist, FORCE_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); +} + +//============================================================ +// work around function start with wa_halbtc8812a1ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8812a1ant_ +//============================================================ +void +EXhalbtc8812a1ant_InitHwConfig( + PBTC_COEXIST btcoexist + ) +{ + u4Byte u4_tmp=0; + u2Byte u2Tmp=0; + u1Byte u1_tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + // backup rf 0x1e value + coex_dm->bt_rf0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); + + //ant sw control to BT + btcoexist->btc_write_4byte(btcoexist, 0x900, 0x00000400); + btcoexist->btc_write_1byte(btcoexist, 0x76d, 0x1); + btcoexist->btc_write_1byte(btcoexist, 0xcb3, 0x77); + btcoexist->btc_write_1byte(btcoexist, 0xcb7, 0x40); + + // 0x790[5:0]=0x5 + u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u1_tmp &= 0xc0; + u1_tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u1_tmp); + + // PTA parameter + btcoexist->btc_write_1byte(btcoexist, 0x6cc, 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, 0xffff); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, 0x55555555); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, 0x55555555); + + // coex parameters + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + // enable counter statistics + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + // enable PTA + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); + + // bt clock related + u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x4); + u1_tmp |= BIT7; + btcoexist->btc_write_1byte(btcoexist, 0x4, u1_tmp); + + // bt clock related + u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); + u1_tmp |= BIT1; + btcoexist->btc_write_1byte(btcoexist, 0x7, u1_tmp); +} + +void +EXhalbtc8812a1ant_InitCoexDm( + PBTC_COEXIST btcoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + btcoexist->stop_coex_dm = false; + + halbtc8812a1ant_InitCoexDm(btcoexist); +} + +void +EXhalbtc8812a1ant_DisplayCoexInfo( + PBTC_COEXIST btcoexist + ) +{ + PBTC_BOARD_INFO board_info=&btcoexist->boardInfo; + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + pu1Byte cli_buf=btcoexist->cli_buf; + u1Byte u1_tmp[4], i, bt_info_ext, psTdmaCase=0; + u4Byte u4_tmp[4]; + BOOLEAN roam=false, scan=false, link=false, wifi_under5g=false; + BOOLEAN bt_hs_on=false, wifi_busy=false; + s4Byte wifi_rssi=0, bt_hs_rssi=0; + u4Byte wifi_bw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if(btcoexist->manual_control) + { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if(btcoexist->stop_coex_dm) + { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if(!board_info->bBtExist) + { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + board_info->pgAntNum, board_info->btdmAntNum); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((stack_info->bProfileNotified)? "Yes":"No"), stack_info->hciVersion); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_FW_VER); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bt_hs_on); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifi_rssi, bt_hs_rssi); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", \ + link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (wifi_under5g? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifi_bw)? "Legacy": (((BTC_WIFI_BW_HT40==wifi_bw)? "HT40":"HT20"))), + ((!wifi_busy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((coex_sta->c2h_bt_inquiry_page)?("inquiry/page scan"):((BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status)? "non-connected idle": + ( (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)? "connected-idle":"busy"))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + if(stack_info->bProfileNotified) + { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + stack_info->sco_exist, stack_info->hid_exist, stack_info->pan_exist, stack_info->a2dp_exist); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (bt_info_ext&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cli_buf); + + for(i=0; ibt_info_c2h_cnt[i]) + { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8812a1Ant[i], \ + coex_sta->bt_info_c2h[i][0], coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ + ((coex_sta->under_ips? "IPS ON":"IPS OFF")), + ((coex_sta->under_lps? "LPS ON":"LPS OFF")), + btcoexist->bt_info.lps1Ant, + btcoexist->bt_info.rpwm1Ant); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if(!btcoexist->manual_control) + { + // Sw mechanism + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig/ btLna]", \ + coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, coex_dm->limited_dig, coex_dm->bCurBtLnaConstrain); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + // Fw mechanism + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + psTdmaCase = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", \ + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], psTdmaCase); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \ + coex_dm->error_condition); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ + coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + } + + // Hw setting + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + coex_dm->bt_rf0x1e_backup); + CL_PRINTF(cli_buf); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", \ + u1_tmp[0]); + CL_PRINTF(cli_buf); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x92c/ 0x930", \ + (u1_tmp[0]), u4_tmp[0]); + CL_PRINTF(cli_buf); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x40/ 0x4f", \ + u1_tmp[0], u1_tmp[1]); + CL_PRINTF(cli_buf); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4_tmp[0], u1_tmp[0]); + CL_PRINTF(cli_buf); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4_tmp[0]); + CL_PRINTF(cli_buf); + +#if 0 + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); + u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xf4c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xf48/ 0xf4c (FA cnt)", \ + u4_tmp[0], u4_tmp[1]); + CL_PRINTF(cli_buf); +#endif + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u4_tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4_tmp[0], u4_tmp[1], u4_tmp[2], u1_tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(hp rx[31:16]/tx[15:0])", \ + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void +EXhalbtc8812a1ant_IpsNotify( + PBTC_COEXIST btcoexist, + u1Byte type + ) +{ + u4Byte u4_tmp=0; + + if(btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + coex_sta->under_ips = true; + + // 0x4c[23]=1 + u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u4_tmp |= BIT23; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp); + + halbtc8812a1ant_CoexAllOff(btcoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + coex_sta->under_ips = false; + //halbtc8812a1ant_InitCoexDm(btcoexist); + } +} + +void +EXhalbtc8812a1ant_LpsNotify( + PBTC_COEXIST btcoexist, + u1Byte type + ) +{ + if(btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + coex_sta->under_lps = true; + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + coex_sta->under_lps = false; + } +} + +void +EXhalbtc8812a1ant_ScanNotify( + PBTC_COEXIST btcoexist, + u1Byte type + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + BOOLEAN wifi_connected=false; + + if(btcoexist->manual_control ||btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!wifi_connected) // non-connected scan + { + //set 0x550[3]=1 before PsTdma + //halbtc8812a1ant_Reg0x550Bit3(btcoexist, true); + halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan(btcoexist); + } + else // wifi is connected + { + halbtc8812a1ant_ActionWifiConnectedScan(btcoexist); + } + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!wifi_connected) // non-connected scan + { + //halbtc8812a1ant_Reg0x550Bit3(btcoexist, false); + halbtc8812a1ant_ActionWifiNotConnected(btcoexist); + } + else + { + halbtc8812a1ant_ActionWifiConnected(btcoexist); + } + } +} + +void +EXhalbtc8812a1ant_ConnectNotify( + PBTC_COEXIST btcoexist, + u1Byte type + ) +{ + PBTC_STACK_INFO stack_info=&btcoexist->stack_info; + BOOLEAN wifi_connected=false; + + if(btcoexist->manual_control ||btcoexist->stop_coex_dm) + return; + + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + if(btcoexist->bt_info.bt_disabled) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + } + else + { + halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan(btcoexist); + } + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if(!wifi_connected) // non-connected scan + { + //halbtc8812a1ant_Reg0x550Bit3(btcoexist, false); + halbtc8812a1ant_ActionWifiNotConnected(btcoexist); + } + else + { + halbtc8812a1ant_ActionWifiConnected(btcoexist); + } + } +} + +void +EXhalbtc8812a1ant_MediaStatusNotify( + PBTC_COEXIST btcoexist, + u1Byte type + ) +{ + u1Byte dataLen=5; + u1Byte buf[6] = {0}; + u1Byte h2c_parameter[3] ={0}; + BOOLEAN wifi_under5g=false; + u4Byte wifi_bw; + u1Byte wifi_central_chnl; + + if(btcoexist->manual_control ||btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under5g); + + // only 2.4G we need to inform bt the chnl mask + if(!wifi_under5g) + { + if(BTC_MEDIA_CONNECT == type) + { + h2c_parameter[0] = 0x1; + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl); + h2c_parameter[1] = wifi_central_chnl; + if(BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + buf[0] = dataLen; + buf[1] = 0x5; // OP_Code + buf[2] = 0x3; // OP_Code_Length + buf[3] = h2c_parameter[0]; // OP_Code_Content + buf[4] = h2c_parameter[1]; + buf[5] = h2c_parameter[2]; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +void +EXhalbtc8812a1ant_SpecialPacketNotify( + PBTC_COEXIST btcoexist, + u1Byte type + ) +{ + BOOLEAN bSecurityLink=false; + + if(btcoexist->manual_control ||btcoexist->stop_coex_dm) + return; + + //if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet(%d) notify\n", type)); + if(btcoexist->bt_info.bt_disabled) + { + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + } + else + { + halbtc8812a1ant_ActionWifiConnectedSpecialPacket(btcoexist); + } + } +} + +void +EXhalbtc8812a1ant_BtInfoNotify( + PBTC_COEXIST btcoexist, + pu1Byte tmp_buf, + u1Byte length + ) +{ + u1Byte bt_info=0; + u1Byte i, rsp_source=0; + static u4Byte set_bt_lna_cnt=0, set_bt_psd_mode=0; + BOOLEAN bt_busy=false, limited_dig=false; + BOOLEAN wifi_connected=false; + BOOLEAN bRejApAggPkt=false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify()===>\n")); + + + rsp_source = tmp_buf[0]&0xf; + if(rsp_source >= BT_INFO_SRC_8812A_1ANT_MAX) + rsp_source = BT_INFO_SRC_8812A_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, length)); + for(i=0; ibt_info_c2h[rsp_source][i] = tmp_buf[i]; + if(i == 1) + bt_info = tmp_buf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%2x]\n", tmp_buf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%2x, ", tmp_buf[i])); + } + } + + if(btcoexist->manual_control) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n")); + return; + } + if(btcoexist->stop_coex_dm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Coex STOPPED!!<===\n")); + return; + } + + if(BT_INFO_SRC_8812A_1ANT_WIFI_FW != rsp_source) + { + coex_sta->bt_retry_cnt = + coex_sta->bt_info_c2h[rsp_source][2]; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3]*2+10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (coex_sta->bt_info_ext & BIT1) ) + { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if(wifi_connected) + { + EXhalbtc8812a1ant_MediaStatusNotify(btcoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8812a1ant_MediaStatusNotify(btcoexist, BTC_MEDIA_DISCONNECT); + } + + set_bt_psd_mode = 0; + } + + // test-chip bt patch doesn't support, temporary remove. + // need to add back when mp-chip. 12/20/2012 +#if 0 + if(set_bt_psd_mode <= 3) + { + halbtc8812a1ant_SetBtPsdMode(btcoexist, FORCE_EXEC, 0xd); + set_bt_psd_mode++; + } + + if(coex_dm->bCurBtLnaConstrain) + { + if( (coex_sta->bt_info_ext & BIT2) ) + { + } + else + { + if(set_bt_lna_cnt <= 3) + { + halbtc8812a1ant_SetBtLnaConstrain(btcoexist, FORCE_EXEC, true); + set_bt_lna_cnt++; + } + } + } + else + { + set_bt_lna_cnt = 0; + } +#endif + // test-chip bt patch only rsp the status for BT_RSP, + // so temporary we consider the following only under BT_RSP + if(BT_INFO_SRC_8812A_1ANT_BT_RSP == rsp_source) + { + if( (coex_sta->bt_info_ext & BIT3) ) + { + #if 0// temp disable because bt patch report the wrong value. + halbtc8812a1ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, false); + #endif + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } + + if( (coex_sta->bt_info_ext & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + halbtc8812a1ant_BtAutoReport(btcoexist, FORCE_EXEC, true); + } + } + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(bt_info & BT_INFO_8812A_1ANT_B_INQ_PAGE) + { + coex_sta->c2h_bt_inquiry_page = true; + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_INQ_PAGE; + } + else + { + coex_sta->c2h_bt_inquiry_page = false; + if(!(bt_info&BT_INFO_8812A_1ANT_B_CONNECTION)) + { + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-connected idle!!!\n")); + } + else if(bt_info == BT_INFO_8812A_1ANT_B_CONNECTION) // connection exists but no busy + { + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt connected-idle!!!\n")); + } + else if((bt_info&BT_INFO_8812A_1ANT_B_SCO_ESCO) || + (bt_info&BT_INFO_8812A_1ANT_B_SCO_BUSY)) + { + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_SCO_BUSY; + bRejApAggPkt = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt sco busy!!!\n")); + } + else if(bt_info&BT_INFO_8812A_1ANT_B_ACL_BUSY) + { + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->reset_tdma_adjust = true; + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt acl busy!!!\n")); + } +#if 0 + else if(bt_info&BT_INFO_8812A_1ANT_B_SCO_ESCO) + { + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt acl/sco busy!!!\n")); + } +#endif + else + { + //DbgPrint("error, undefined bt_info=0x%x\n", bt_info); + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-defined state!!!\n")); + } + + // send delete BA to disable aggregation + //btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejApAggPkt); + } + + if( (BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status) ) + { + bt_busy = true; + } + else + { + bt_busy = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + if(bt_busy) + { + limited_dig = true; + } + else + { + limited_dig = false; + } + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8812a1ant_RunCoexistMechanism(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify()<===\n")); +} + +void +EXhalbtc8812a1ant_StackOperationNotify( + PBTC_COEXIST btcoexist, + u1Byte type + ) +{ + if(BTC_STACK_OP_INQ_PAGE_PAIR_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair start notify\n")); + } + else if(BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair finish notify\n")); + } +} + +void +EXhalbtc8812a1ant_HaltNotify( + PBTC_COEXIST btcoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8812a1ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, true); + halbtc8812a1ant_PsTdma(btcoexist, FORCE_EXEC, false, 0); + btcoexist->btc_write_1byte(btcoexist, 0x4f, 0xf); + halbtc8812a1ant_WifiParaAdjust(btcoexist, false); +} + +void +EXhalbtc8812a1ant_PnpNotify( + PBTC_COEXIST btcoexist, + u1Byte pnpState + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); + + if(BTC_WIFI_PNP_SLEEP == pnpState) + { + btcoexist->stop_coex_dm = true; + halbtc8812a1ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, true); + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + } + else if(BTC_WIFI_PNP_WAKE_UP == pnpState) + { + + } +} + +void +EXhalbtc8812a1ant_Periodical( + PBTC_COEXIST btcoexist + ) +{ + BOOLEAN wifi_under5g=false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Periodical()===>\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 1Ant Periodical!!\n")); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under5g); + + if(wifi_under5g) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Periodical(), return for 5G<===\n")); + halbtc8812a1ant_CoexAllOff(btcoexist); + return; + } + + halbtc8812a1ant_QueryBtInfo(btcoexist); + halbtc8812a1ant_MonitorBtCtr(btcoexist); + halbtc8812a1ant_MonitorBtEnableDisable(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Periodical()<===\n")); +} + +void +EXhalbtc8812a1ant_DbgControl( + PBTC_COEXIST btcoexist, + u1Byte opCode, + u1Byte opLen, + pu1Byte pData + ) +{ + switch(opCode) + { + case BTC_DBG_SET_COEX_NORMAL: + btcoexist->manual_control = false; + halbtc8812a1ant_InitCoexDm(btcoexist); + break; + case BTC_DBG_SET_COEX_WIFI_ONLY: + btcoexist->manual_control = true; + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + halbtc8812a1ant_PsTdma(btcoexist, NORMAL_EXEC, false, 9); + break; + case BTC_DBG_SET_COEX_BT_ONLY: + // todo + break; + default: + break; + } +} +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.h +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.h @@ -0,0 +1,179 @@ +//=========================================== +// The following is for 8723A 2Ant BT Co-exist definition +//=========================================== +#define BT_INFO_8723A_2ANT_B_FTP BIT7 +#define BT_INFO_8723A_2ANT_B_A2DP BIT6 +#define BT_INFO_8723A_2ANT_B_HID BIT5 +#define BT_INFO_8723A_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723A_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723A_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723A_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723A_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT 2 + +typedef enum _BT_INFO_SRC_8723A_2ANT{ + BT_INFO_SRC_8723A_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723A_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723A_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723A_2ANT_MAX +}BT_INFO_SRC_8723A_2ANT,*PBT_INFO_SRC_8723A_2ANT; + +typedef enum _BT_8723A_2ANT_BT_STATUS{ + BT_8723A_2ANT_BT_STATUS_IDLE = 0x0, + BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723A_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8723A_2ANT_BT_STATUS_MAX +}BT_8723A_2ANT_BT_STATUS,*PBT_8723A_2ANT_BT_STATUS; + +typedef enum _BT_8723A_2ANT_COEX_ALGO{ + BT_8723A_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723A_2ANT_COEX_ALGO_SCO = 0x1, + BT_8723A_2ANT_COEX_ALGO_HID = 0x2, + BT_8723A_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8723A_2ANT_COEX_ALGO_PANEDR = 0x4, + BT_8723A_2ANT_COEX_ALGO_PANHS = 0x5, + BT_8723A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x6, + BT_8723A_2ANT_COEX_ALGO_PANEDR_HID = 0x7, + BT_8723A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x8, + BT_8723A_2ANT_COEX_ALGO_HID_A2DP = 0x9, + BT_8723A_2ANT_COEX_ALGO_MAX +}BT_8723A_2ANT_COEX_ALGO,*PBT_8723A_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8723A_2ANT{ + // fw mechanism + BOOLEAN bPreDecBtPwr; + BOOLEAN bCurDecBtPwr; + //BOOLEAN bPreBtLnaConstrain; + //BOOLEAN bCurBtLnaConstrain; + //u1Byte bPreBtPsdMode; + //u1Byte bCurBtPsdMode; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + //BOOLEAN bPreBtAutoReport; + //BOOLEAN bCurBtAutoReport; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN limited_dig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; +} COEX_DM_8723A_2ANT, *PCOEX_DM_8723A_2ANT; + +typedef struct _COEX_STA_8723A_2ANT{ + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preBtRssiState1; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8723A_2ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8723A_2ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; + BOOLEAN bHoldForStackOperation; + u1Byte bHoldPeriodCnt; + // this is for c2h hang work-around + u4Byte c2hHangDetectCnt; +}COEX_STA_8723A_2ANT, *PCOEX_STA_8723A_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8723a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8723a2ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + --- linux-3.13.0.orig/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c +++ linux-3.13.0/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c @@ -0,0 +1,3780 @@ +//============================================================ +// Description: +// +// This file is for RTL8723A Co-exist mechanism +// +// History +// 2012/08/22 Cosa first check in. +// 2012/11/14 Cosa Revise for 8723A 2Ant out sourcing. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8723A_2ANT GLCoexDm8723a2Ant; +static PCOEX_DM_8723A_2ANT pCoexDm=&GLCoexDm8723a2Ant; +static COEX_STA_8723A_2ANT GLCoexSta8723a2Ant; +static PCOEX_STA_8723A_2ANT pCoexSta=&GLCoexSta8723a2Ant; + +const char *const GLBtInfoSrc8723a2Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8723a2ant_ +//============================================================ +BOOLEAN +halbtc8723a2ant_IsWifiIdle( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE, bScan=FALSE, bLink=FALSE, bRoam=FALSE; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if(bWifiConnected) + return FALSE; + if(bScan) + return FALSE; + if(bLink) + return FALSE; + if(bRoam) + return FALSE; + + return true; +} + +u1Byte +halbtc8723a2ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8723a2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8723a2ant_IndicateWifiChnlBwInfo( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x19=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x19, 3, H2C_Parameter); +} + +VOID +halbtc8723a2ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = true; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x38=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x38, 1, H2C_Parameter); +} +u1Byte +halbtc8723a2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stack_info; + BOOLEAN bBtHsOn=FALSE, bBtBusy=FALSE, limited_dig=FALSE; + u1Byte algorithm=BT_8723A_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + //====================== + // here we get BT status first + //====================== + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_IDLE; + + if((pStackInfo->bScoExist) ||(bBtHsOn) ||(pStackInfo->bHidExist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO or HID or HS exists, set BT non-idle !!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + else + { + // A2dp profile + if( (pBtCoexist->stack_info.numOfLink == 1) && + (pStackInfo->bA2dpExist) ) + { + if( (pCoexSta->lowPriorityTx+ pCoexSta->lowPriorityRx) < 100) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP, low priority tx+rx < 100, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP, low priority tx+rx >= 100, set BT non-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + } + // Pan profile + if( (pBtCoexist->stack_info.numOfLink == 1) && + (pStackInfo->bPanExist) ) + { + if((pCoexSta->lowPriorityTx+ pCoexSta->lowPriorityRx) < 600) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN, low priority tx+rx < 600, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + else + { + if(pCoexSta->lowPriorityTx) + { + if((pCoexSta->lowPriorityRx /pCoexSta->lowPriorityTx)>9 ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN, low priority rx/tx > 9, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + } + } + if(BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN, set BT non-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + } + // Pan+A2dp profile + if( (pBtCoexist->stack_info.numOfLink == 2) && + (pStackInfo->bA2dpExist) && + (pStackInfo->bPanExist) ) + { + if((pCoexSta->lowPriorityTx+ pCoexSta->lowPriorityRx) < 600) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN+A2DP, low priority tx+rx < 600, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + else + { + if(pCoexSta->lowPriorityTx) + { + if((pCoexSta->lowPriorityRx /pCoexSta->lowPriorityTx)>9 ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN+A2DP, low priority rx/tx > 9, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + } + } + if(BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN+A2DP, set BT non-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + } + } + if(BT_8723A_2ANT_BT_STATUS_IDLE != pCoexDm->btStatus) + { + bBtBusy = true; + limited_dig = true; + } + else + { + bBtBusy = FALSE; + limited_dig = FALSE; + } + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + //====================== + + if(!pStackInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if(pStackInfo->bScoExist) + numOfDiffProfile++; + if(pStackInfo->bHidExist) + numOfDiffProfile++; + if(pStackInfo->bPanExist) + numOfDiffProfile++; + if(pStackInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pStackInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_A2DP; + } + else if(pStackInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pStackInfo->bScoExist) + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else if(pStackInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pStackInfo->bScoExist) + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID; + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pStackInfo->bScoExist) + { + if( pStackInfo->bHidExist && + pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +BOOLEAN +halbtc8723a2ant_NeedToDecBtPwr( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bRet=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiConnected=FALSE; + s4Byte btHsRssi=0; + + if(!pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn)) + return FALSE; + if(!pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected)) + return FALSE; + if(!pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi)) + return FALSE; + + if(bWifiConnected) + { + if(bBtHsOn) + { + if(btHsRssi > 37) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for HS mode!!\n")); + bRet = true; + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for Wifi is connected!!\n")); + bRet = true; + } + } + + return bRet; +} + +VOID +halbtc8723a2ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x29=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x29, 1, H2C_Parameter); +} + +VOID +halbtc8723a2ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bDecBtPwr + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bDecBtPwr) + { + H2C_Parameter[0] |= BIT1; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power : %s, FW write 0x21=0x%x\n", + (bDecBtPwr? "Yes!!":"No!!"), H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x21, 1, H2C_Parameter); +} + +VOID +halbtc8723a2ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDecBtPwr + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power = %s\n", + (bForceExec? "force to":""), ((bDecBtPwr)? "ON":"OFF"))); + pCoexDm->bCurDecBtPwr = bDecBtPwr; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n", + pCoexDm->bPreDecBtPwr, pCoexDm->bCurDecBtPwr)); + + if(pCoexDm->bPreDecBtPwr == pCoexDm->bCurDecBtPwr) + return; + } + halbtc8723a2ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->bCurDecBtPwr); + + pCoexDm->bPreDecBtPwr = pCoexDm->bCurDecBtPwr; +} + +VOID +halbtc8723a2ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8723a2ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8723a2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xf0ff7); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->initilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8723a2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8723a2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8723a2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->btc_read_1byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->btc_write_1byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8723a2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8723a2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8723a2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + pBtCoexist->btc_setBbReg(pBtCoexist, 0x880, 0xff000000, swDacSwingLvl); + } + else + { + pBtCoexist->btc_setBbReg(pBtCoexist, 0x880, 0xff000000, 0xc0); + } +} + + +VOID +halbtc8723a2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + mdelay(30); + halbtc8723a2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8723a2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc04,0x3a07611); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc04,0x3a05611); + } +} + +VOID +halbtc8723a2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8723a2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8723a2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x4e1c0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x4d1d0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x4c1e0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x4b1f0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x4a200001); + + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xdc000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x90000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x51000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x12000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0x00355); + + rssiAdjustVal = 6; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x641c0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x631d0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x621e0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x611f0001); + pBtCoexist->btc_write_4byte(pBtCoexist, 0xc78,0x60200001); + + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x32000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x71000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xb0000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xfc000); + pBtCoexist->btc_set_rf_reg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0x30355); + } + + // set rssiAdjustVal for wifi module. + pBtCoexist->btc_set(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + + +VOID +halbtc8723a2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8723a2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8723a2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->btc_write_4byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8723a2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8723a2ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8723a2ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x25=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x25, 1, H2C_Parameter); +} + +VOID +halbtc8723a2ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8723a2ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8723a2ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x3a(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->btc_fill_h2c(pBtCoexist, 0x3a, 5, H2C_Parameter); +} + +VOID +halbtc8723a2ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + u4Byte btTxRxCnt=0; + + btTxRxCnt = pCoexSta->highPriorityTx+pCoexSta->highPriorityRx+ + pCoexSta->lowPriorityTx+pCoexSta->lowPriorityRx; + + if(btTxRxCnt > 3000) + { + pCoexDm->bCurPsTdmaOn = true; + pCoexDm->curPsTdma = 8; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], turn ON PS TDMA, type=%d for BT tx/rx counters=%d(>3000)\n", + pCoexDm->curPsTdma, btTxRxCnt)); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + } + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(pCoexDm->bCurPsTdmaOn) + { + switch(pCoexDm->curPsTdma) + { + case 1: + default: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x98); + break; + case 2: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x98); + break; + case 3: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0xe1, 0x98); + break; + case 4: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x5, 0x5, 0xe1, 0x80); + break; + case 5: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x98); + break; + case 6: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x98); + break; + case 7: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0x60, 0x98); + break; + case 8: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x5, 0x5, 0x60, 0x80); + break; + case 9: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x98); + break; + case 10: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x98); + break; + case 11: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0xe1, 0x98); + break; + case 12: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x98); + break; + case 13: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x98); + break; + case 14: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x98); + break; + case 15: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0x60, 0x98); + break; + case 16: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0x60, 0x98); + break; + case 17: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x2f, 0x2f, 0x60, 0x80); + break; + case 18: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x98); + break; + case 19: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0xe1, 0x98); + break; + case 20: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0x60, 0x98); + break; + } + } + else + { + // disable PS tdma + switch(pCoexDm->curPsTdma) + { + case 0: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + break; + case 1: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + break; + default: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + break; + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + + +VOID +halbtc8723a2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + // sw all off + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + // hw all off + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); +} + +VOID +halbtc8723a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8723a2ant_CoexTable(pBtCoexist, FORCE_EXEC, 0x55555555, 0xffff, 0x3); + halbtc8723a2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_RfShrink(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, FORCE_EXEC, FALSE, 0xc0); +} + +VOID +halbtc8723a2ant_BtInquiryPage( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bLowPwrDisable=true; + + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); +} + +VOID +halbtc8723a2ant_BtEnableAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + halbtc8723a2ant_IndicateWifiChnlBwInfo(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + halbtc8723a2ant_IndicateWifiChnlBwInfo(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); +} + +VOID +halbtc8723a2ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->btc_read_4byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & MASKLWORD; + regHPRx = (u4Tmp & MASKHWORD)>>16; + + u4Tmp = pBtCoexist->btc_read_4byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & MASKLWORD; + regLPRx = (u4Tmp & MASKHWORD)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->btc_write_1byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8723a2ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=true, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = true; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + halbtc8723a2ant_BtEnableAction(pBtCoexist); + } + } +} + +BOOLEAN +halbtc8723a2ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stack_info; + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE; + BOOLEAN bLowPwrDisable=FALSE; + + if(!pStackInfo->bBtLinkExist) + { + bLowPwrDisable = FALSE; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + } + else + { + bLowPwrDisable = true; + pBtCoexist->btc_set(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + if(halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + BT_8723A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi idle + Bt idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = true; + } + else if(!halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-idle + BT idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = true; + } + else if(halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi idle + Bt connected idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = true; + } + else if(!halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-idle + Bt connected idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = true; + } + else if(halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_NON_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi idle + BT non-idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = true; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-idle + BT non-idle!!\n")); + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + + bCommon = FALSE; + } + + return bCommon; +} +VOID +halbtc8723a2ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bScoHid, + IN BOOLEAN bTxPause, + IN u1Byte maxInterval + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n")); + + if(pCoexDm->bResetTdmaAdjust) + { + pCoexDm->bResetTdmaAdjust = FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + { + if(bScoHid) + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + else + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + else + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + } + else + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + } + } + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if ³sÄò n ­Ó2¬í retry count¬°0, «h½Õ¼eWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if ³sÄò 2 ­Ó2¬í retry count< 3, «h½Õ¯¶WiFi duration + { + if (WaitCount <= 2) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, ¥u­n1¦¸ retry count > 3, «h½Õ¯¶WiFi duration + { + if (WaitCount == 1) + m++; // ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ + else + m = 1; + + if ( m >= 20) //m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval)); + if(maxInterval == 1) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + } + } + } + else if(maxInterval == 2) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + } + } + } + else if(maxInterval == 3) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } +} + +// SCO only or SCO+PAN(HS) +VOID +halbtc8723a2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + + +VOID +halbtc8723a2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8723a2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, true, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, true, 1); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, true, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, true, 1); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + + +//PAN(HS) only +VOID +halbtc8723a2ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + } + else + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + } + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +//PAN(EDR)+A2DP +VOID +halbtc8723a2ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8723a2ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, true); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, FALSE, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, true, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, true, 1); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, FALSE, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, true, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, true, true, 1); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, true); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stack_info; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + if(pBtCoexist->manual_control) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Manual control!!!\n")); + return; + } + + if(pStackInfo->bProfileNotified) + { + if(pCoexSta->bHoldForStackOperation) + { + // if bt inquiry/page/pair, do not execute. + return; + } + + algorithm = halbtc8723a2ant_ActionAlgorithm(pBtCoexist); + if(pCoexSta->bHoldPeriodCnt && (BT_8723A_2ANT_COEX_ALGO_PANHS!=algorithm)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex],Hold BT inquiry/page scan setting (cnt = %d)!!\n", + pCoexSta->bHoldPeriodCnt)); + if(pCoexSta->bHoldPeriodCnt >= 6) + { + pCoexSta->bHoldPeriodCnt = 0; + // next time the coexist parameters should be reset again. + } + else + pCoexSta->bHoldPeriodCnt++; + return; + } + + pCoexDm->curAlgorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d \n", pCoexDm->curAlgorithm)); + if(halbtc8723a2ant_IsCommonAction(pBtCoexist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n")); + pCoexDm->bResetTdmaAdjust = true; + } + else + { + if(pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], preAlgorithm=%d, curAlgorithm=%d\n", + pCoexDm->preAlgorithm, pCoexDm->curAlgorithm)); + pCoexDm->bResetTdmaAdjust = true; + } + switch(pCoexDm->curAlgorithm) + { + case BT_8723A_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n")); + halbtc8723a2ant_ActionSco(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n")); + halbtc8723a2ant_ActionHid(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n")); + halbtc8723a2ant_ActionA2dp(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n")); + halbtc8723a2ant_ActionPanEdr(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n")); + halbtc8723a2ant_ActionPanHs(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n")); + halbtc8723a2ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + halbtc8723a2ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + halbtc8723a2ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n")); + halbtc8723a2ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n")); + halbtc8723a2ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } + } +} + +//============================================================ +// work around function start with wa_halbtc8723a2ant_ +//============================================================ +VOID +wa_halbtc8723a2ant_MonitorC2h( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte tmp1b=0x0; + u4Byte curC2hTotalCnt=0x0; + static u4Byte preC2hTotalCnt=0x0, sameCntPollingTime=0x0; + + curC2hTotalCnt+=pCoexSta->btInfoC2hCnt[BT_INFO_SRC_8723A_2ANT_BT_RSP]; + + if(curC2hTotalCnt == preC2hTotalCnt) + { + sameCntPollingTime++; + } + else + { + preC2hTotalCnt = curC2hTotalCnt; + sameCntPollingTime = 0; + } + + if(sameCntPollingTime >= 2) + { + tmp1b = pBtCoexist->btc_read_1byte(pBtCoexist, 0x1af); + if(tmp1b != 0x0) + { + pCoexSta->c2hHangDetectCnt++; + pBtCoexist->btc_write_1byte(pBtCoexist, 0x1af, 0x0); + } + } +} + +//============================================================ +// extern function start with EXhalbtc8723a2ant_ +//============================================================ +VOID +EXhalbtc8723a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte u4Tmp=0; + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->btc_get_rf_reg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + // Enable counter statistics + pBtCoexist->btc_write_1byte(pBtCoexist, 0x76e, 0x4); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x778, 0x3); + pBtCoexist->btc_write_1byte(pBtCoexist, 0x40, 0x20); +} + +VOID +EXhalbtc8723a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8723a2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8723a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + struct btc_board_info * pBoardInfo=&pBtCoexist->board_info; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stack_info; + pu1Byte cliBuf=pBtCoexist->cli_buf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(!pBoardInfo->bt_exist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pg_ant_num, pBoardInfo->btdm_ant_num); + CL_PRINTF(cliBuf); + + if(pBtCoexist->manual_control) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cliBuf); + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus)? "idle":( (BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy"))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + if(pStackInfo->bProfileNotified) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_disp_dbg_msg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; ibtInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723a2Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "write 0x1af=0x0 num", \ + pCoexSta->c2hHangDetectCnt); + CL_PRINTF(cliBuf); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "SM1[ShRf/ LpRA/ LimDig]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->limited_dig); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + if(!pBtCoexist->manual_control) + { + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ + pCoexDm->bCurDecBtPwr, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x778); + u1Tmp[1] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x783); + u1Tmp[2] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x796); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/ 0x783/ 0x796", \ + u1Tmp[0], u1Tmp[1], u1Tmp[2]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x880); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x880", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x40); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x484); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x484(rate adaptive)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xda0); + u4Tmp[1] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xda4); + u4Tmp[2] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xda8); + u4Tmp[3] = pBtCoexist->btc_read_4byte(pBtCoexist, 0xdac); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0xda0/0xda4/0xda8/0xdac(FA cnt)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u4Tmp[3]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->btc_read_4byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770 (hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); + + // Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang + u1Tmp[0] = pBtCoexist->btc_read_1byte(pBtCoexist, 0x41b); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x41b (mgntQ hang chk == 0xf)", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_disp_dbg_msg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8723a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + halbtc8723a2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + //halbtc8723a2ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8723a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + halbtc8723a2ant_IndicateWifiChnlBwInfo(pBtCoexist, type); +} + +VOID +EXhalbtc8723a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bBtBusy=FALSE, limited_dig=FALSE; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = BT_INFO_SRC_8723A_2ANT_BT_RSP; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; ibtInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 0) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8723A_2ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = + pCoexSta->btInfoC2h[rspSource][1]; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][2]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][3]; + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8723A_2ANT_B_INQ_PAGE) + { + pCoexSta->bC2hBtInquiryPage = true; + } + else + { + pCoexSta->bC2hBtInquiryPage = FALSE; + } +} + +VOID +EXhalbtc8723a2ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_STACK_OP_INQ_PAGE_PAIR_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair start notify\n")); + pCoexSta->bHoldForStackOperation = true; + pCoexSta->bHoldPeriodCnt = 1; + halbtc8723a2ant_BtInquiryPage(pBtCoexist); + } + else if(BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair finish notify\n")); + pCoexSta->bHoldForStackOperation = FALSE; + } +} + +VOID +EXhalbtc8723a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); + EXhalbtc8723a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8723a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 2Ant Periodical!!\n")); + + // work around for c2h hang + wa_halbtc8723a2ant_MonitorC2h(pBtCoexist); + + halbtc8723a2ant_QueryBtInfo(pBtCoexist); + halbtc8723a2ant_MonitorBtCtr(pBtCoexist); + halbtc8723a2ant_MonitorBtEnableDisable(pBtCoexist); + + halbtc8723a2ant_RunCoexistMechanism(pBtCoexist); +} + + +#endif + --- linux-3.13.0.orig/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ linux-3.13.0/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -53,8 +53,9 @@ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */ /*=== Customer ID ===*/ /****** 8188EUS ********/ - {USB_DEVICE(0x8179, 0x07B8)}, /* Abocom - Abocom */ + {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ + {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ {} /* Terminating entry */ }; --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_test_thresh.c +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_test_thresh.c @@ -0,0 +1,197 @@ +/* Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_test.h" + +/* Test constants */ +#define TEST_NUMBUFS 129728 +#define TEST_EXIT 129536 +#define TEST_ENTRY 129024 + +struct affine_test_data { + struct task_struct *t; + int cpu; + int expect_affinity; + int drain; + int num_enter; + int num_exit; + struct list_head node; + struct completion wakethread; + struct completion wakeparent; +}; + +static void cb_depletion(struct bman_portal *portal, + struct bman_pool *pool, + void *opaque, + int depleted) +{ + struct affine_test_data *data = opaque; + int c = smp_processor_id(); + pr_info("cb_depletion: bpid=%d, depleted=%d, cpu=%d, original=%d\n", + bman_get_params(pool)->bpid, depleted, c, data->cpu); + /* We should be executing on the CPU of the thread that owns the pool if + * and that CPU has an affine portal (ie. it isn't slaved). */ + BUG_ON((c != data->cpu) && data->expect_affinity); + BUG_ON((c == data->cpu) && !data->expect_affinity); + if (depleted) + data->num_enter++; + else + data->num_exit++; +} + +/* Params used to set up a pool, this also dynamically allocates a BPID */ +struct bman_pool_params params_nocb = { + .flags = BMAN_POOL_FLAG_DYNAMIC_BPID | BMAN_POOL_FLAG_THRESH, + .thresholds = { TEST_ENTRY, TEST_EXIT, 0, 0 } +}; + +/* Params used to set up each cpu's pool with callbacks enabled */ +struct bman_pool_params params_cb = { + .bpid = 0, /* will be replaced to match pool_nocb */ + .flags = BMAN_POOL_FLAG_DEPLETION, + .cb = cb_depletion +}; + +static struct bman_pool *pool_nocb; +static LIST_HEAD(threads); + +static int affine_test(void *__data) +{ + struct bman_pool *pool; + struct affine_test_data *data = __data; + struct bman_pool_params my_params = params_cb; + + pr_info("thread %d: starting\n", data->cpu); + /* create the pool */ + my_params.cb_ctx = data; + pool = bman_new_pool(&my_params); + BUG_ON(!pool); + complete(&data->wakeparent); + wait_for_completion(&data->wakethread); + init_completion(&data->wakethread); + + /* if we're the drainer, we get signalled for that */ + if (data->drain) { + struct bm_buffer buf; + int ret; + pr_info("thread %d: draining...\n", data->cpu); + do { + ret = bman_acquire(pool, &buf, 1, 0); + } while (ret > 0); + pr_info("thread %d: draining done.\n", data->cpu); + complete(&data->wakeparent); + wait_for_completion(&data->wakethread); + init_completion(&data->wakethread); + } + + /* cleanup */ + bman_free_pool(pool); + while (!kthread_should_stop()) + cpu_relax(); + pr_info("thread %d: exiting\n", data->cpu); + return 0; +} + +static struct affine_test_data *start_affine_test(int cpu, int drain) +{ + struct affine_test_data *data = kmalloc(sizeof(*data), GFP_KERNEL); + + if (!data) + return NULL; + data->cpu = cpu; + data->expect_affinity = cpumask_test_cpu(cpu, bman_affine_cpus()); + data->drain = drain; + data->num_enter = 0; + data->num_exit = 0; + init_completion(&data->wakethread); + init_completion(&data->wakeparent); + list_add_tail(&data->node, &threads); + data->t = kthread_create(affine_test, data, "threshtest%d", cpu); + BUG_ON(IS_ERR(data->t)); + kthread_bind(data->t, cpu); + wake_up_process(data->t); + return data; +} + +void bman_test_thresh(void) +{ + int loop = TEST_NUMBUFS; + int ret, num_cpus = 0; + struct affine_test_data *data, *drainer = NULL; + + pr_info("bman_test_thresh: start\n"); + + /* allocate a BPID and seed it */ + pool_nocb = bman_new_pool(¶ms_nocb); + BUG_ON(!pool_nocb); + while (loop--) { + struct bm_buffer buf; + bm_buffer_set64(&buf, 0x0badbeef + loop); + ret = bman_release(pool_nocb, &buf, 1, + BMAN_RELEASE_FLAG_WAIT); + BUG_ON(ret); + } + while (!bman_rcr_is_empty()) + cpu_relax(); + pr_info("bman_test_thresh: buffers are in\n"); + + /* create threads and wait for them to create pools */ + params_cb.bpid = bman_get_params(pool_nocb)->bpid; + for_each_cpu(loop, cpu_online_mask) { + data = start_affine_test(loop, drainer ? 0 : 1); + BUG_ON(!data); + if (!drainer) + drainer = data; + num_cpus++; + wait_for_completion(&data->wakeparent); + } + + /* signal the drainer to start draining */ + complete(&drainer->wakethread); + wait_for_completion(&drainer->wakeparent); + init_completion(&drainer->wakeparent); + + /* tear down */ + list_for_each_entry_safe(data, drainer, &threads, node) { + complete(&data->wakethread); + ret = kthread_stop(data->t); + BUG_ON(ret); + list_del(&data->node); + /* check that we get the expected callbacks (and no others) */ + BUG_ON(data->num_enter != 1); + BUG_ON(data->num_exit != 0); + kfree(data); + } + bman_free_pool(pool_nocb); + + pr_info("bman_test_thresh: done\n"); +} + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_debugfs.c +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_debugfs.c @@ -0,0 +1,121 @@ +/* Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +static struct dentry *dfs_root; /* debugfs root directory */ + +/******************************************************************************* + * Query Buffer Pool State + ******************************************************************************/ +static int query_bp_state_show(struct seq_file *file, void *offset) +{ + int ret; + struct bm_pool_state state; + int i, j; + u32 mask; + + memset(&state, 0, sizeof(struct bm_pool_state)); + ret = bman_query_pools(&state); + if (ret) { + seq_printf(file, "Error %d\n", ret); + return 0; + } + seq_printf(file, "bp_id free_buffers_avail bp_depleted\n"); + for (i = 0; i < 2; i++) { + mask = 0x80000000; + for (j = 0; j < 32; j++) { + seq_printf(file, + " %-2u %-3s %-3s\n", + (i*32)+j, + (state.as.state.__state[i] & mask) ? "no" : "yes", + (state.ds.state.__state[i] & mask) ? "yes" : "no"); + mask >>= 1; + } + } + return 0; +} + +static int query_bp_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, query_bp_state_show, NULL); +} + +static const struct file_operations query_bp_state_fops = { + .owner = THIS_MODULE, + .open = query_bp_state_open, + .read = seq_read, + .release = single_release, +}; + +static int __init bman_debugfs_module_init(void) +{ + int ret = 0; + struct dentry *d; + + dfs_root = debugfs_create_dir("bman", NULL); + + if (dfs_root == NULL) { + ret = -ENOMEM; + pr_err("Cannot create bman debugfs dir\n"); + goto _return; + } + d = debugfs_create_file("query_bp_state", + S_IRUGO, + dfs_root, + NULL, + &query_bp_state_fops); + if (d == NULL) { + ret = -ENOMEM; + pr_err("Cannot create query_bp_state\n"); + goto _return; + } + return 0; + +_return: + if (dfs_root) + debugfs_remove_recursive(dfs_root); + return ret; +} + +static void __exit bman_debugfs_module_exit(void) +{ + debugfs_remove_recursive(dfs_root); +} + + +module_init(bman_debugfs_module_init); +module_exit(bman_debugfs_module_exit); +MODULE_LICENSE("Dual BSD/GPL"); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_config.c +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_config.c @@ -0,0 +1,690 @@ +/* Copyright (c) 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CONFIG_SMP +#include /* get_hard_smp_processor_id() */ +#endif +#include +#include + +#include "bman_private.h" + +/* Last updated for v00.79 of the BG */ + +struct bman; + +/* Register offsets */ +#define REG_POOL_SWDET(n) (0x0000 + ((n) * 0x04)) +#define REG_POOL_HWDET(n) (0x0100 + ((n) * 0x04)) +#define REG_POOL_SWDXT(n) (0x0200 + ((n) * 0x04)) +#define REG_POOL_HWDXT(n) (0x0300 + ((n) * 0x04)) +#define REG_POOL_CONTENT(n) (0x0600 + ((n) * 0x04)) +#define REG_FBPR_FPC 0x0800 +#define REG_ECSR 0x0a00 +#define REG_ECIR 0x0a04 +#define REG_EADR 0x0a08 +#define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) +#define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) +#define REG_IP_REV_1 0x0bf8 +#define REG_IP_REV_2 0x0bfc +#define REG_FBPR_BARE 0x0c00 +#define REG_FBPR_BAR 0x0c04 +#define REG_FBPR_AR 0x0c10 +#define REG_SRCIDR 0x0d04 +#define REG_LIODNR 0x0d08 +#define REG_ERR_ISR 0x0e00 /* + "enum bm_isr_reg" */ + +/* Used by all error interrupt registers except 'inhibit' */ +#define BM_EIRQ_IVCI 0x00000010 /* Invalid Command Verb */ +#define BM_EIRQ_FLWI 0x00000008 /* FBPR Low Watermark */ +#define BM_EIRQ_MBEI 0x00000004 /* Multi-bit ECC Error */ +#define BM_EIRQ_SBEI 0x00000002 /* Single-bit ECC Error */ +#define BM_EIRQ_BSCN 0x00000001 /* pool State Change Notification */ + +/* BMAN_ECIR valid error bit */ +#define PORTAL_ECSR_ERR (BM_EIRQ_IVCI) + +union bman_ecir { + u32 ecir_raw; + struct { + u32 __reserved1:4; + u32 portal_num:4; + u32 __reserved2:12; + u32 numb:4; + u32 __reserved3:2; + u32 pid:6; + } __packed info; +}; + +union bman_eadr { + u32 eadr_raw; + struct { + u32 __reserved1:5; + u32 memid:3; + u32 __reserved2:14; + u32 eadr:10; + } __packed info; +}; + +struct bman_hwerr_txt { + u32 mask; + const char *txt; +}; + +#define BMAN_HWE_TXT(a, b) { .mask = BM_EIRQ_##a, .txt = b } + +static const struct bman_hwerr_txt bman_hwerr_txts[] = { + BMAN_HWE_TXT(IVCI, "Invalid Command Verb"), + BMAN_HWE_TXT(FLWI, "FBPR Low Watermark"), + BMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"), + BMAN_HWE_TXT(SBEI, "Single-bit ECC Error"), + BMAN_HWE_TXT(BSCN, "Pool State Change Notification"), +}; +#define BMAN_HWE_COUNT (sizeof(bman_hwerr_txts)/sizeof(struct bman_hwerr_txt)) + +struct bman_error_info_mdata { + u16 addr_mask; + u16 bits; + const char *txt; +}; + +#define BMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c} +static const struct bman_error_info_mdata error_mdata[] = { + BMAN_ERR_MDATA(0x03FF, 192, "Stockpile memory"), + BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 1"), + BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 2"), +}; +#define BMAN_ERR_MDATA_COUNT \ + (sizeof(error_mdata)/sizeof(struct bman_error_info_mdata)) + +/* Add this in Kconfig */ +#define BMAN_ERRS_TO_UNENABLE (BM_EIRQ_FLWI) + +/** + * bm_err_isr__ - Manipulate global interrupt registers + * @v: for accessors that write values, this is the 32-bit value + * + * Manipulates BMAN_ERR_ISR, BMAN_ERR_IER, BMAN_ERR_ISDR, BMAN_ERR_IIR. All + * manipulations except bm_err_isr_[un]inhibit() use 32-bit masks composed of + * the BM_EIRQ_*** definitions. Note that "bm_err_isr_enable_write" means + * "write the enable register" rather than "enable the write register"! + */ +#define bm_err_isr_status_read(bm) __bm_err_isr_read(bm, bm_isr_status) +#define bm_err_isr_status_clear(bm, m) __bm_err_isr_write(bm, bm_isr_status,m) +#define bm_err_isr_enable_read(bm) __bm_err_isr_read(bm, bm_isr_enable) +#define bm_err_isr_enable_write(bm, v) __bm_err_isr_write(bm, bm_isr_enable,v) +#define bm_err_isr_disable_read(bm) __bm_err_isr_read(bm, bm_isr_disable) +#define bm_err_isr_disable_write(bm, v) __bm_err_isr_write(bm, bm_isr_disable,v) +#define bm_err_isr_inhibit(bm) __bm_err_isr_write(bm, bm_isr_inhibit,1) +#define bm_err_isr_uninhibit(bm) __bm_err_isr_write(bm, bm_isr_inhibit,0) + +/* + * TODO: unimplemented registers + * + * BMAN_POOLk_SDCNT, BMAN_POOLk_HDCNT, BMAN_FULT, + * BMAN_VLDPL, BMAN_EECC, BMAN_SBET, BMAN_EINJ + */ + +/* Encapsulate "struct bman *" as a cast of the register space address. */ + +static struct bman *bm_create(void *regs) +{ + return (struct bman *)regs; +} + +static inline u32 __bm_in(struct bman *bm, u32 offset) +{ + return in_be32((void *)bm + offset); +} +static inline void __bm_out(struct bman *bm, u32 offset, u32 val) +{ + out_be32((void *)bm + offset, val); +} +#define bm_in(reg) __bm_in(bm, REG_##reg) +#define bm_out(reg, val) __bm_out(bm, REG_##reg, val) + +static u32 __bm_err_isr_read(struct bman *bm, enum bm_isr_reg n) +{ + return __bm_in(bm, REG_ERR_ISR + (n << 2)); +} + +static void __bm_err_isr_write(struct bman *bm, enum bm_isr_reg n, u32 val) +{ + __bm_out(bm, REG_ERR_ISR + (n << 2), val); +} + +#if 0 +static void bm_get_details(struct bman *bm, u8 *int_options, u8 *errata, + u8 *conf_options) +{ + u32 v = bm_in(IP_REV_1); + *int_options = (v >> 16) & 0xff; + *errata = (v >> 8) & 0xff; + *conf_options = v & 0xff; +} + +static u8 bm_get_corenet_sourceid(struct bman *bm) +{ + return bm_in(SRCIDR); +} + +static void bm_set_liodn(struct bman *bm, u16 liodn) +{ + bm_out(LIODNR, liodn & 0xfff); +} + +#endif + +static void bm_get_version(struct bman *bm, u16 *id, u8 *major, u8 *minor) +{ + u32 v = bm_in(IP_REV_1); + *id = (v >> 16); + *major = (v >> 8) & 0xff; + *minor = v & 0xff; +} + +static u32 __generate_thresh(u32 val, int roundup) +{ + u32 e = 0; /* co-efficient, exponent */ + int oddbit = 0; + while(val > 0xff) { + oddbit = val & 1; + val >>= 1; + e++; + if(roundup && oddbit) + val++; + } + DPA_ASSERT(e < 0x10); + return (val | (e << 8)); +} + +static void bm_set_pool(struct bman *bm, u8 pool, u32 swdet, u32 swdxt, + u32 hwdet, u32 hwdxt) +{ + DPA_ASSERT(pool < bman_pool_max); + bm_out(POOL_SWDET(pool), __generate_thresh(swdet, 0)); + bm_out(POOL_SWDXT(pool), __generate_thresh(swdxt, 1)); + bm_out(POOL_HWDET(pool), __generate_thresh(hwdet, 0)); + bm_out(POOL_HWDXT(pool), __generate_thresh(hwdxt, 1)); +} + +static void bm_set_memory(struct bman *bm, u64 ba, int prio, u32 size) +{ + u32 exp = ilog2(size); + /* choke if size isn't within range */ + DPA_ASSERT((size >= 4096) && (size <= 1073741824) && + is_power_of_2(size)); + /* choke if '[e]ba' has lower-alignment than 'size' */ + DPA_ASSERT(!(ba & (size - 1))); + bm_out(FBPR_BARE, upper_32_bits(ba)); + bm_out(FBPR_BAR, lower_32_bits(ba)); + bm_out(FBPR_AR, (prio ? 0x40000000 : 0) | (exp - 1)); +} + +/*****************/ +/* Config driver */ +/*****************/ + +/* We support only one of these. */ +static struct bman *bm; +static struct device_node *bm_node; + +/* TODO: Kconfig these? */ +#define DEFAULT_FBPR_SZ (PAGE_SIZE << 12) + +/* Parse the property to extract the memory location and size and + * memblock_reserve() it. If it isn't supplied, memblock_alloc() the default size. */ +static __init int parse_mem_property(struct device_node *node, const char *name, + dma_addr_t *addr, size_t *sz, int zero) +{ + const u32 *pint; + int ret; + + pint = of_get_property(node, name, &ret); + if (!pint || (ret != 16)) { + pr_info("No %s property '%s', using memblock_alloc(%016zx)\n", + node->full_name, name, *sz); + *addr = memblock_alloc(*sz, *sz); + if (zero) + memset(phys_to_virt(*addr), 0, *sz); + return 0; + } + pr_info("Using %s property '%s'\n", node->full_name, name); + /* If using a "zero-pma", don't try to zero it, even if you asked */ + if (zero && of_find_property(node, "zero-pma", &ret)) { + pr_info(" it's a 'zero-pma', not zeroing from s/w\n"); + zero = 0; + } + *addr = ((u64)pint[0] << 32) | (u64)pint[1]; + *sz = ((u64)pint[2] << 32) | (u64)pint[3]; + /* Keep things simple, it's either all in the DRAM range or it's all + * outside. */ + if (*addr < memblock_end_of_DRAM()) { + BUG_ON((u64)*addr + (u64)*sz > memblock_end_of_DRAM()); + if (memblock_reserve(*addr, *sz) < 0) { + pr_err("Failed to reserve %s\n", name); + return -ENOMEM; + } + if (zero) + memset(phys_to_virt(*addr), 0, *sz); + } else if (zero) { + /* map as cacheable, non-guarded */ + void *tmpp = ioremap_prot(*addr, *sz, 0); + memset(tmpp, 0, *sz); + iounmap(tmpp); + } + return 0; +} + +static int __init fsl_bman_init(struct device_node *node) +{ + struct resource res; + u32 __iomem *regs; + const char *s; + dma_addr_t fbpr_a = 0; /* gcc doesn't know this is unnecessary */ + size_t fbpr_sz = DEFAULT_FBPR_SZ; + int ret, standby = 0; + u16 id; + u8 major, minor; + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + pr_err("Can't get %s property 'reg'\n", + node->full_name); + return ret; + } + s = of_get_property(node, "fsl,hv-claimable", &ret); + if (s && !strcmp(s, "standby")) + standby = 1; + if (!standby) { + ret = parse_mem_property(node, "fsl,bman-fbpr", + &fbpr_a, &fbpr_sz, 0); + BUG_ON(ret); + } + /* Global configuration */ + regs = ioremap(res.start, res.end - res.start + 1); + bm = bm_create(regs); + BUG_ON(!bm); + bm_node = node; + bm_get_version(bm, &id, &major, &minor); + pr_info("Bman ver:%04x,%02x,%02x\n", id, major, minor); + if ((major == 1) && (minor == 0)) { + bman_ip_rev = BMAN_REV10; + bman_pool_max = 64; + } else if ((major == 2) && (minor == 0)) { + bman_ip_rev = BMAN_REV20; + bman_pool_max = 8; + } else { + pr_warning("unknown Bman version, default to rev1.0\n"); + } + + if (standby) { + pr_info(" -> in standby mode\n"); + return 0; + } + /* FBPR memory */ + bm_set_memory(bm, fbpr_a, 0, fbpr_sz); + return 0; +} + +int bman_have_ccsr(void) +{ + return (bm ? 1 : 0); +} + +int bm_pool_set(u32 bpid, const u32 *thresholds) +{ + if (!bm) + return -ENODEV; + bm_set_pool(bm, bpid, thresholds[0], thresholds[1], + thresholds[2], thresholds[3]); + return 0; +} +EXPORT_SYMBOL(bm_pool_set); + +__init void bman_init_early(void) +{ + struct device_node *dn; + for_each_compatible_node(dn, NULL, "fsl,bman") { + if (bm) + pr_err("%s: only one 'fsl,bman' allowed\n", + dn->full_name); + else { + int ret = fsl_bman_init(dn); + BUG_ON(ret); + } + } +} + +static void log_edata_bits(u32 bit_count) +{ + u32 i, j, mask = 0xffffffff; + + pr_warning("Bman ErrInt, EDATA:\n"); + i = bit_count/32; + if (bit_count%32) { + i++; + mask = ~(mask << bit_count%32); + } + j = 16-i; + pr_warning(" 0x%08x\n", bm_in(EDATA(j)) & mask); + j++; + for (; j < 16; j++) + pr_warning(" 0x%08x\n", bm_in(EDATA(j))); +} + +static void log_additional_error_info(u32 isr_val, u32 ecsr_val) +{ + union bman_ecir ecir_val; + union bman_eadr eadr_val; + + ecir_val.ecir_raw = bm_in(ECIR); + /* Is portal info valid */ + if (ecsr_val & PORTAL_ECSR_ERR) { + pr_warning("Bman ErrInt: SWP id %d, numb %d, pid %d\n", + ecir_val.info.portal_num, ecir_val.info.numb, + ecir_val.info.pid); + } + if (ecsr_val & (BM_EIRQ_SBEI|BM_EIRQ_MBEI)) { + eadr_val.eadr_raw = bm_in(EADR); + pr_warning("Bman ErrInt: EADR Memory: %s, 0x%x\n", + error_mdata[eadr_val.info.memid].txt, + error_mdata[eadr_val.info.memid].addr_mask + & eadr_val.info.eadr); + log_edata_bits(error_mdata[eadr_val.info.memid].bits); + } +} + +/* Bman interrupt handler */ +static irqreturn_t bman_isr(int irq, void *ptr) +{ + u32 isr_val, ier_val, ecsr_val, isr_mask, i; + + ier_val = bm_err_isr_enable_read(bm); + isr_val = bm_err_isr_status_read(bm); + ecsr_val = bm_in(ECSR); + isr_mask = isr_val & ier_val; + + if (!isr_mask) + return IRQ_NONE; + for (i = 0; i < BMAN_HWE_COUNT; i++) { + if (bman_hwerr_txts[i].mask & isr_mask) { + pr_warning("Bman ErrInt: %s\n", bman_hwerr_txts[i].txt); + if (bman_hwerr_txts[i].mask & ecsr_val) { + log_additional_error_info(isr_mask, ecsr_val); + /* Re-arm error capture registers */ + bm_out(ECSR, ecsr_val); + } + if (bman_hwerr_txts[i].mask & BMAN_ERRS_TO_UNENABLE) { + pr_devel("Bman un-enabling error 0x%x\n", + bman_hwerr_txts[i].mask); + ier_val &= ~bman_hwerr_txts[i].mask; + bm_err_isr_enable_write(bm, ier_val); + } + } + } + bm_err_isr_status_clear(bm, isr_val); + return IRQ_HANDLED; +} + +static int __bind_irq(void) +{ + int ret, err_irq; + + err_irq = of_irq_to_resource(bm_node, 0, NULL); + if (err_irq == NO_IRQ) { + pr_info("Can't get %s property '%s'\n", bm_node->full_name, + "interrupts"); + return -ENODEV; + } + ret = request_irq(err_irq, bman_isr, IRQF_SHARED, "bman-err", bm_node); + if (ret) { + pr_err("request_irq() failed %d for '%s'\n", ret, + bm_node->full_name); + return -ENODEV; + } + /* Disable Buffer Pool State Change */ + bm_err_isr_disable_write(bm, BM_EIRQ_BSCN); + /* Write-to-clear any stale bits, (eg. starvation being asserted prior + * to resource allocation during driver init). */ + bm_err_isr_status_clear(bm, 0xffffffff); + /* Enable Error Interrupts */ + bm_err_isr_enable_write(bm, 0xffffffff); + return 0; +} + +/* Initialise Error Interrupt Handler */ +int bman_init_error_int(struct device_node *node) +{ + if (!bman_have_ccsr()) + return 0; + if (node != bm_node) + return -EINVAL; + return __bind_irq(); +} + +#ifdef CONFIG_SYSFS + +#define DRV_NAME "fsl-bman" + +static ssize_t show_fbpr_fpc(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(FBPR_FPC)); +}; + +static ssize_t show_pool_count(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + u32 data; + int i; + + if (!sscanf(dev_attr->attr.name, "%d", &i)) + return -EINVAL; + data = bm_in(POOL_CONTENT(i)); + return snprintf(buf, PAGE_SIZE, "%d\n", data); +}; + +static ssize_t show_err_isr(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%08x\n", bm_in(ERR_ISR)); +}; + +static ssize_t show_sbec(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + int i; + + if (!sscanf(dev_attr->attr.name, "sbec_%d", &i)) + return -EINVAL; + return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(SBEC(i))); +}; + +static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL); +static DEVICE_ATTR(fbpr_fpc, S_IRUSR, show_fbpr_fpc, NULL); + +/* Didn't use DEVICE_ATTR as 64 of this would be required. + * Initialize them when needed. */ +static char *name_attrs_pool_count; /* "xx" + null-terminator */ +static struct device_attribute *dev_attr_buffer_pool_count; + +static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL); +static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL); + +static struct attribute *bman_dev_attributes[] = { + &dev_attr_fbpr_fpc.attr, + &dev_attr_err_isr.attr, + NULL +}; + +static struct attribute *bman_dev_ecr_attributes[] = { + &dev_attr_sbec_0.attr, + &dev_attr_sbec_1.attr, + NULL +}; + +static struct attribute **bman_dev_pool_count_attributes; + + +/* root level */ +static const struct attribute_group bman_dev_attr_grp = { + .name = NULL, + .attrs = bman_dev_attributes +}; +static const struct attribute_group bman_dev_ecr_grp = { + .name = "error_capture", + .attrs = bman_dev_ecr_attributes +}; +static struct attribute_group bman_dev_pool_countent_grp = { + .name = "pool_count", +}; + +static int of_fsl_bman_remove(struct platform_device *ofdev) +{ + sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp); + return 0; +}; + +static int of_fsl_bman_probe(struct platform_device *ofdev) +{ + int ret, i; + + ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_attr_grp); + if (ret) + goto done; + ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_ecr_grp); + if (ret) + goto del_group_0; + + name_attrs_pool_count = kmalloc(sizeof(char) * bman_pool_max * 3, + GFP_KERNEL); + if (!name_attrs_pool_count) { + pr_err("Can't alloc name_attrs_pool_count\n"); + goto del_group_1; + } + + dev_attr_buffer_pool_count = kmalloc(sizeof(struct device_attribute) * + bman_pool_max, GFP_KERNEL); + if (!dev_attr_buffer_pool_count) { + pr_err("Can't alloc dev_attr-buffer_pool_count\n"); + goto del_group_2; + } + + bman_dev_pool_count_attributes = kmalloc(sizeof(struct attribute *) * + (bman_pool_max + 1), GFP_KERNEL); + if (!bman_dev_pool_count_attributes) { + pr_err("can't alloc bman_dev_pool_count_attributes\n"); + goto del_group_3; + } + + for (i = 0; i < (bman_pool_max + 1); i++) { + bman_dev_pool_count_attributes[i] = + kmalloc(sizeof(struct attribute), GFP_KERNEL); + if (!bman_dev_pool_count_attributes[i]) { + pr_err("cannot alloc for each" + " bman_dev_pool_count_attributes\n"); + goto del_group_3; + } + } + + for (i = 0; i < bman_pool_max; i++) { + ret = scnprintf((name_attrs_pool_count + i * 3), 3, "%d", i); + if (!ret) + goto del_group_4; + dev_attr_buffer_pool_count[i].attr.name = + (name_attrs_pool_count + i * 3); + dev_attr_buffer_pool_count[i].attr.mode = S_IRUSR; + dev_attr_buffer_pool_count[i].show = show_pool_count; + bman_dev_pool_count_attributes[i] = + &dev_attr_buffer_pool_count[i].attr; + } + bman_dev_pool_count_attributes[bman_pool_max] = NULL; + + bman_dev_pool_countent_grp.attrs = bman_dev_pool_count_attributes; + + ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_pool_countent_grp); + if (ret) + goto del_group_4; + + goto done; + +del_group_4: + for (i = 0; i < (bman_pool_max + 1); i++) + kfree(bman_dev_pool_count_attributes[i]); + kfree(bman_dev_pool_count_attributes); +del_group_3: + kfree(dev_attr_buffer_pool_count); +del_group_2: + kfree(name_attrs_pool_count); +del_group_1: + sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_ecr_grp); +del_group_0: + sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp); +done: + if (ret) + dev_err(&ofdev->dev, + "Cannot create dev attributes ret=%d\n", ret); + return ret; +}; + +static struct of_device_id of_fsl_bman_ids[] = { + { + .compatible = "fsl,bman", + }, + {} +}; +MODULE_DEVICE_TABLE(of, of_fsl_bman_ids); + +static struct platform_driver of_fsl_bman_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = of_fsl_bman_ids, + }, + .probe = of_fsl_bman_probe, + .remove = of_fsl_bman_remove, +}; + +static int bman_ctrl_init(void) +{ + return platform_driver_register(&of_fsl_bman_driver); +} + +static void bman_ctrl_exit(void) +{ + platform_driver_unregister(&of_fsl_bman_driver); +} + +module_init(bman_ctrl_init); +module_exit(bman_ctrl_exit); + +#endif /* CONFIG_SYSFS */ --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_test_hotpotato.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_test_hotpotato.c @@ -0,0 +1,497 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "qman_test.h" + +/* Algorithm: + * + * Each cpu will have HP_PER_CPU "handlers" set up, each of which incorporates + * an rx/tx pair of FQ objects (both of which are stashed on dequeue). The + * organisation of FQIDs is such that the HP_PER_CPU*NUM_CPUS handlers will + * shuttle a "hot potato" frame around them such that every forwarding action + * moves it from one cpu to another. (The use of more than one handler per cpu + * is to allow enough handlers/FQs to truly test the significance of caching - + * ie. when cache-expiries are occuring.) + * + * The "hot potato" frame content will be HP_NUM_WORDS*4 bytes in size, and the + * first and last words of the frame data will undergo a transformation step on + * each forwarding action. To achieve this, each handler will be assigned a + * 32-bit "mixer", that is produced using a 32-bit LFSR. When a frame is + * received by a handler, the mixer of the expected sender is XOR'd into all + * words of the entire frame, which is then validated against the original + * values. Then, before forwarding, the entire frame is XOR'd with the mixer of + * the current handler. Apart from validating that the frame is taking the + * expected path, this also provides some quasi-realistic overheads to each + * forwarding action - dereferencing *all* the frame data, computation, and + * conditional branching. There is a "special" handler designated to act as the + * instigator of the test by creating an enqueuing the "hot potato" frame, and + * to determine when the test has completed by counting HP_LOOPS iterations. + * + * Init phases: + * + * 1. prepare each cpu's 'hp_cpu' struct using on_each_cpu(,,1) and link them + * into 'hp_cpu_list'. Specifically, set processor_id, allocate HP_PER_CPU + * handlers and link-list them (but do no other handler setup). + * + * 2. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each + * hp_cpu's 'iterator' to point to its first handler. With each loop, + * allocate rx/tx FQIDs and mixer values to the hp_cpu's iterator handler + * and advance the iterator for the next loop. This includes a final fixup, + * which connects the last handler to the first (and which is why phase 2 + * and 3 are separate). + * + * 3. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each + * hp_cpu's 'iterator' to point to its first handler. With each loop, + * initialise FQ objects and advance the iterator for the next loop. + * Moreover, do this initialisation on the cpu it applies to so that Rx FQ + * initialisation targets the correct cpu. + */ + +/* helper to run something on all cpus (can't use on_each_cpu(), as that invokes + * the fn from irq context, which is too restrictive). */ +struct bstrap { + void (*fn)(void); + atomic_t started; +}; +static int bstrap_fn(void *__bstrap) +{ + struct bstrap *bstrap = __bstrap; + atomic_inc(&bstrap->started); + bstrap->fn(); + while (!kthread_should_stop()) + msleep(1); + return 0; +} +static int on_all_cpus(void (*fn)(void)) +{ + int cpu; + for_each_cpu(cpu, cpu_online_mask) { + struct bstrap bstrap = { + .fn = fn, + .started = ATOMIC_INIT(0) + }; + struct task_struct *k = kthread_create(bstrap_fn, &bstrap, + "hotpotato%d", cpu); + int ret; + if (IS_ERR(k)) + return -ENOMEM; + kthread_bind(k, cpu); + wake_up_process(k); + /* If we call kthread_stop() before the "wake up" has had an + * effect, then the thread may exit with -EINTR without ever + * running the function. So poll until it's started before + * requesting it to stop. */ + while (!atomic_read(&bstrap.started)) + msleep(10); + ret = kthread_stop(k); + if (ret) + return ret; + } + return 0; +} + +struct hp_handler { + + /* The following data is stashed when 'rx' is dequeued; */ + /* -------------- */ + /* The Rx FQ, dequeues of which will stash the entire hp_handler */ + struct qman_fq rx; + /* The Tx FQ we should forward to */ + struct qman_fq tx; + /* The value we XOR post-dequeue, prior to validating */ + u32 rx_mixer; + /* The value we XOR pre-enqueue, after validating */ + u32 tx_mixer; + /* what the hotpotato address should be on dequeue */ + dma_addr_t addr; + u32 *frame_ptr; + + /* The following data isn't (necessarily) stashed on dequeue; */ + /* -------------- */ + u32 fqid_rx, fqid_tx; + /* list node for linking us into 'hp_cpu' */ + struct list_head node; + /* Just to check ... */ + unsigned int processor_id; +} ____cacheline_aligned; + +struct hp_cpu { + /* identify the cpu we run on; */ + unsigned int processor_id; + /* root node for the per-cpu list of handlers */ + struct list_head handlers; + /* list node for linking us into 'hp_cpu_list' */ + struct list_head node; + /* when repeatedly scanning 'hp_list', each time linking the n'th + * handlers together, this is used as per-cpu iterator state */ + struct hp_handler *iterator; +}; + +/* Each cpu has one of these */ +static DEFINE_PER_CPU(struct hp_cpu, hp_cpus); + +/* links together the hp_cpu structs, in first-come first-serve order. */ +static LIST_HEAD(hp_cpu_list); +static spinlock_t hp_lock = __SPIN_LOCK_UNLOCKED(hp_lock); + +static unsigned int hp_cpu_list_length; + +/* the "special" handler, that starts and terminates the test. */ +static struct hp_handler *special_handler; +static int loop_counter; + +/* handlers are allocated out of this, so they're properly aligned. */ +static struct kmem_cache *hp_handler_slab; + +/* this is the frame data */ +static void *__frame_ptr; +static u32 *frame_ptr; +static dma_addr_t frame_dma; + +/* the main function waits on this */ +static DECLARE_WAIT_QUEUE_HEAD(queue); + +#define HP_PER_CPU 2 +#define HP_LOOPS 8 +/* 80 bytes, like a small ethernet frame, and bleeds into a second cacheline */ +#define HP_NUM_WORDS 80 +/* First word of the LFSR-based frame data */ +#define HP_FIRST_WORD 0xabbaf00d + +static inline u32 do_lfsr(u32 prev) +{ + return (prev >> 1) ^ (-(prev & 1u) & 0xd0000001u); +} + +static void allocate_frame_data(void) +{ + u32 lfsr = HP_FIRST_WORD; + int loop; + struct platform_device *pdev = platform_device_alloc("foobar", -1); + if (!pdev) + panic("platform_device_alloc() failed"); + if (platform_device_add(pdev)) + panic("platform_device_add() failed"); + __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL); + if (!__frame_ptr) + panic("kmalloc() failed"); + frame_ptr = (void *)(((unsigned long)__frame_ptr + 63) & + ~(unsigned long)63); + for (loop = 0; loop < HP_NUM_WORDS; loop++) { + frame_ptr[loop] = lfsr; + lfsr = do_lfsr(lfsr); + } + frame_dma = dma_map_single(&pdev->dev, frame_ptr, 4 * HP_NUM_WORDS, + DMA_BIDIRECTIONAL); + platform_device_del(pdev); + platform_device_put(pdev); +} + +static void deallocate_frame_data(void) +{ + kfree(__frame_ptr); +} + +static inline void process_frame_data(struct hp_handler *handler, + const struct qm_fd *fd) +{ + u32 *p = handler->frame_ptr; + u32 lfsr = HP_FIRST_WORD; + int loop; + if (qm_fd_addr_get64(fd) != handler->addr) + panic("bad frame address"); + for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { + *p ^= handler->rx_mixer; + if (*p != lfsr) + panic("corrupt frame data"); + *p ^= handler->tx_mixer; + lfsr = do_lfsr(lfsr); + } +} + +static enum qman_cb_dqrr_result normal_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr) +{ + struct hp_handler *handler = (struct hp_handler *)fq; + + process_frame_data(handler, &dqrr->fd); + if (qman_enqueue(&handler->tx, &dqrr->fd, 0)) + panic("qman_enqueue() failed"); + return qman_cb_dqrr_consume; +} + +static enum qman_cb_dqrr_result special_dqrr(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr) +{ + struct hp_handler *handler = (struct hp_handler *)fq; + + process_frame_data(handler, &dqrr->fd); + if (++loop_counter < HP_LOOPS) { + if (qman_enqueue(&handler->tx, &dqrr->fd, 0)) + panic("qman_enqueue() failed"); + } else { + pr_info("Received final (%dth) frame\n", loop_counter); + wake_up(&queue); + } + return qman_cb_dqrr_consume; +} + +static void create_per_cpu_handlers(void) +{ + struct hp_handler *handler; + int loop; + struct hp_cpu *hp_cpu = &__get_cpu_var(hp_cpus); + + hp_cpu->processor_id = smp_processor_id(); + spin_lock(&hp_lock); + list_add_tail(&hp_cpu->node, &hp_cpu_list); + hp_cpu_list_length++; + spin_unlock(&hp_lock); + INIT_LIST_HEAD(&hp_cpu->handlers); + for (loop = 0; loop < HP_PER_CPU; loop++) { + handler = kmem_cache_alloc(hp_handler_slab, GFP_KERNEL); + if (!handler) + panic("kmem_cache_alloc() failed"); + handler->processor_id = hp_cpu->processor_id; + handler->addr = frame_dma; + handler->frame_ptr = frame_ptr; + list_add_tail(&handler->node, &hp_cpu->handlers); + } +} + +static void destroy_per_cpu_handlers(void) +{ + struct list_head *loop, *tmp; + struct hp_cpu *hp_cpu = &__get_cpu_var(hp_cpus); + + spin_lock(&hp_lock); + list_del(&hp_cpu->node); + spin_unlock(&hp_lock); + list_for_each_safe(loop, tmp, &hp_cpu->handlers) { + u32 flags; + struct hp_handler *handler = list_entry(loop, struct hp_handler, + node); + if (qman_retire_fq(&handler->rx, &flags)) + panic("qman_retire_fq(rx) failed"); + BUG_ON(flags & QMAN_FQ_STATE_BLOCKOOS); + if (qman_oos_fq(&handler->rx)) + panic("qman_oos_fq(rx) failed"); + qman_destroy_fq(&handler->rx, 0); + qman_destroy_fq(&handler->tx, 0); + qm_fq_free(handler->fqid_rx); + list_del(&handler->node); + kmem_cache_free(hp_handler_slab, handler); + } +} + +static inline u8 num_cachelines(u32 offset) +{ + u8 res = (offset + (L1_CACHE_BYTES - 1)) + / (L1_CACHE_BYTES); + if (res > 3) + return 3; + return res; +} +#define STASH_DATA_CL \ + num_cachelines(HP_NUM_WORDS * 4) +#define STASH_CTX_CL \ + num_cachelines(offsetof(struct hp_handler,fqid_rx)) + +static void init_handler(void *__handler) +{ + struct qm_mcc_initfq opts; + struct hp_handler *handler = __handler; + BUG_ON(handler->processor_id != smp_processor_id()); + /* Set up rx */ + memset(&handler->rx, 0, sizeof(handler->rx)); + if (handler == special_handler) + handler->rx.cb.dqrr = special_dqrr; + else + handler->rx.cb.dqrr = normal_dqrr; + if (qman_create_fq(handler->fqid_rx, 0, &handler->rx)) + panic("qman_create_fq(rx) failed"); + memset(&opts, 0, sizeof(opts)); + opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_CONTEXTA; + opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING; + opts.fqd.context_a.stashing.data_cl = STASH_DATA_CL; + opts.fqd.context_a.stashing.context_cl = STASH_CTX_CL; + if (qman_init_fq(&handler->rx, QMAN_INITFQ_FLAG_SCHED | + QMAN_INITFQ_FLAG_LOCAL, &opts)) + panic("qman_init_fq(rx) failed"); + /* Set up tx */ + memset(&handler->tx, 0, sizeof(handler->tx)); + if (qman_create_fq(handler->fqid_tx, QMAN_FQ_FLAG_NO_MODIFY, + &handler->tx)) + panic("qman_create_fq(tx) failed"); +} + +static void init_phase2(void) +{ + int loop; + u32 fqid = 0; + u32 lfsr = 0xdeadbeef; + struct hp_cpu *hp_cpu; + struct hp_handler *handler; + + for (loop = 0; loop < HP_PER_CPU; loop++) { + list_for_each_entry(hp_cpu, &hp_cpu_list, node) { + if (!loop) + hp_cpu->iterator = list_first_entry( + &hp_cpu->handlers, + struct hp_handler, node); + else + hp_cpu->iterator = list_entry( + hp_cpu->iterator->node.next, + struct hp_handler, node); + /* Rx FQID is the previous handler's Tx FQID */ + hp_cpu->iterator->fqid_rx = fqid; + /* Allocate new FQID for Tx */ + fqid = qm_fq_new(); + if (!fqid) + panic("qm_fq_new() failed"); + hp_cpu->iterator->fqid_tx = fqid; + /* Rx mixer is the previous handler's Tx mixer */ + hp_cpu->iterator->rx_mixer = lfsr; + /* Get new mixer for Tx */ + lfsr = do_lfsr(lfsr); + hp_cpu->iterator->tx_mixer = lfsr; + } + } + /* Fix up the first handler (fqid_rx==0, rx_mixer=0xdeadbeef) */ + hp_cpu = list_first_entry(&hp_cpu_list, struct hp_cpu, node); + handler = list_first_entry(&hp_cpu->handlers, struct hp_handler, node); + BUG_ON((handler->fqid_rx != 0) || (handler->rx_mixer != 0xdeadbeef)); + handler->fqid_rx = fqid; + handler->rx_mixer = lfsr; + /* and tag it as our "special" handler */ + special_handler = handler; +} + +static void init_phase3(void) +{ + int loop; + struct hp_cpu *hp_cpu; + + for (loop = 0; loop < HP_PER_CPU; loop++) { + list_for_each_entry(hp_cpu, &hp_cpu_list, node) { + if (!loop) + hp_cpu->iterator = list_first_entry( + &hp_cpu->handlers, + struct hp_handler, node); + else + hp_cpu->iterator = list_entry( + hp_cpu->iterator->node.next, + struct hp_handler, node); + preempt_disable(); + if (hp_cpu->processor_id == smp_processor_id()) + init_handler(hp_cpu->iterator); + else + smp_call_function_single(hp_cpu->processor_id, + init_handler, hp_cpu->iterator, 1); + preempt_enable(); + } + } +} + +static void send_first_frame(void *ignore) +{ + u32 *p = special_handler->frame_ptr; + u32 lfsr = HP_FIRST_WORD; + int loop; + struct qm_fd fd; + + BUG_ON(special_handler->processor_id != smp_processor_id()); + memset(&fd, 0, sizeof(fd)); + qm_fd_addr_set64(&fd, special_handler->addr); + fd.format = qm_fd_contig_big; + fd.length29 = HP_NUM_WORDS * 4; + for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { + if (*p != lfsr) + panic("corrupt frame data"); + *p ^= special_handler->tx_mixer; + lfsr = do_lfsr(lfsr); + } + pr_info("Sending first frame\n"); + if (qman_enqueue(&special_handler->tx, &fd, 0)) + panic("qman_enqueue() failed"); +} + +void qman_test_hotpotato(void) +{ + if (cpumask_weight(cpu_online_mask) < 2) { + pr_info("qman_test_hotpotato, skip - only 1 CPU\n"); + return; + } + + pr_info("qman_test_hotpotato starting\n"); + + hp_cpu_list_length = 0; + loop_counter = 0; + hp_handler_slab = kmem_cache_create("hp_handler_slab", + sizeof(struct hp_handler), L1_CACHE_BYTES, + SLAB_HWCACHE_ALIGN, NULL); + if (!hp_handler_slab) + panic("kmem_cache_create() failed"); + + allocate_frame_data(); + + /* Init phase 1 */ + pr_info("Creating %d handlers per cpu...\n", HP_PER_CPU); + if (on_all_cpus(create_per_cpu_handlers)) + panic("on_each_cpu() failed"); + pr_info("Number of cpus: %d, total of %d handlers\n", + hp_cpu_list_length, hp_cpu_list_length * HP_PER_CPU); + + init_phase2(); + + init_phase3(); + + preempt_disable(); + if (special_handler->processor_id == smp_processor_id()) + send_first_frame(NULL); + else + smp_call_function_single(special_handler->processor_id, + send_first_frame, NULL, 1); + preempt_enable(); + + wait_event(queue, loop_counter == HP_LOOPS); + deallocate_frame_data(); + if (on_all_cpus(destroy_per_cpu_handlers)) + panic("on_each_cpu() failed"); + kmem_cache_destroy(hp_handler_slab); + pr_info("qman_test_hotpotato finished\n"); +} + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_fqalloc.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_fqalloc.c @@ -0,0 +1,264 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_private.h" + +#include + +/****************/ +/* FQ allocator */ +/****************/ + +/* Global flag: use BPID==0 (fq_pool), or use the range-allocator? */ +static int use_bman; + +#ifdef CONFIG_FSL_BMAN_PORTAL +static struct bman_pool *fq_pool; +static const struct bman_pool_params fq_pool_params; +#endif + +__init int fqalloc_init(int __use_bman) +{ + use_bman = __use_bman; +#ifdef CONFIG_FSL_BMAN_PORTAL + if (use_bman) { + fq_pool = bman_new_pool(&fq_pool_params); + if (!fq_pool) + return -ENOMEM; + } +#else + BUG_ON(use_bman); +#endif + return 0; +} + +u32 qm_fq_new(void) +{ +#ifdef CONFIG_FSL_BMAN_PORTAL + struct bm_buffer buf; + int ret; +#endif + + if (!use_bman) { + u32 result; + if (qman_alloc_fqid(&result) < 0) + return 0; + return result; + } +#ifdef CONFIG_FSL_BMAN_PORTAL + BUG_ON(!fq_pool); + ret = bman_acquire(fq_pool, &buf, 1, 0); + if (ret != 1) + return 0; + return (u32)bm_buffer_get64(&buf); +#else + BUG(); +#endif +} +EXPORT_SYMBOL(qm_fq_new); + +int qm_fq_free_flags(u32 fqid, __maybe_unused u32 flags) +{ +#ifdef CONFIG_FSL_BMAN_PORTAL + struct bm_buffer buf; + u32 bflags = 0; + int ret; + bm_buffer_set64(&buf, fqid); +#endif + + if (!use_bman) { + qman_release_fqid(fqid); + return 0; + } +#ifdef CONFIG_FSL_BMAN_PORTAL +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & QM_FQ_FREE_WAIT) { + bflags |= BMAN_RELEASE_FLAG_WAIT; + if (flags & BMAN_RELEASE_FLAG_WAIT_INT) + bflags |= BMAN_RELEASE_FLAG_WAIT_INT; + if (flags & BMAN_RELEASE_FLAG_WAIT_SYNC) + bflags |= BMAN_RELEASE_FLAG_WAIT_SYNC; + } +#endif + ret = bman_release(fq_pool, &buf, 1, bflags); + return ret; +#else + BUG(); +#endif +} +EXPORT_SYMBOL(qm_fq_free_flags); + +/* Global state for the allocator */ +static DEFINE_SPINLOCK(alloc_lock); +static LIST_HEAD(alloc_list); + +/* The allocator is a (possibly-empty) list of these; */ +struct alloc_node { + struct list_head list; + u32 base; + u32 num; +}; + +/* #define FQRANGE_DEBUG */ + +#ifdef FQRANGE_DEBUG +#define DPRINT pr_info +static void DUMP(void) +{ + int off = 0; + char buf[256]; + struct alloc_node *p; + list_for_each_entry(p, &alloc_list, list) { + if (off < 255) + off += snprintf(buf + off, 255-off, "{%d,%d}", + p->base, p->base + p->num - 1); + } + pr_info("%s\n", buf); +} +#else +#define DPRINT(x...) do { ; } while(0) +#define DUMP() do { ; } while(0) +#endif + +int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial) +{ + struct alloc_node *i = NULL, *next_best = NULL; + u32 base, next_best_base = 0, num = 0, next_best_num = 0; + struct alloc_node *margin_left, *margin_right; + + *result = (u32)-1; + DPRINT("alloc_range(%d,%d,%d)\n", count, align, partial); + DUMP(); + /* If 'align' is 0, it should behave as though it was 1 */ + if (!align) + align = 1; + margin_left = kmalloc(sizeof(*margin_left), GFP_KERNEL); + if (!margin_left) + goto err; + margin_right = kmalloc(sizeof(*margin_right), GFP_KERNEL); + if (!margin_right) { + kfree(margin_left); + goto err; + } + spin_lock_irq(&alloc_lock); + list_for_each_entry(i, &alloc_list, list) { + base = (i->base + align - 1) / align; + base *= align; + if ((base - i->base) >= i->num) + /* alignment is impossible, regardless of count */ + continue; + num = i->num - (base - i->base); + if (num >= count) { + /* this one will do nicely */ + num = count; + goto done; + } + if (num > next_best_num) { + next_best = i; + next_best_base = base; + next_best_num = num; + } + } + if (partial && next_best) { + i = next_best; + base = next_best_base; + num = next_best_num; + } else + i = NULL; +done: + if (i) { + if (base != i->base) { + margin_left->base = i->base; + margin_left->num = base - i->base; + list_add_tail(&margin_left->list, &i->list); + } else + kfree(margin_left); + if ((base + num) < (i->base + i->num)) { + margin_right->base = base + num; + margin_right->num = (i->base + i->num) - + (base + num); + list_add(&margin_right->list, &i->list); + } else + kfree(margin_right); + list_del(&i->list); + kfree(i); + *result = base; + } + spin_unlock_irq(&alloc_lock); +err: + DPRINT("returning %d\n", i ? num : -ENOMEM); + DUMP(); + return i ? (int)num : -ENOMEM; +} +EXPORT_SYMBOL(qman_alloc_fqid_range); + +void qman_release_fqid_range(u32 fqid, u32 count) +{ + struct alloc_node *i, *node = kmalloc(sizeof(*node), GFP_KERNEL); + DPRINT("release_range(%d,%d)\n", fqid, count); + DUMP(); + spin_lock_irq(&alloc_lock); + node->base = fqid; + node->num = count; + list_for_each_entry(i, &alloc_list, list) { + if (i->base >= node->base) { + list_add_tail(&node->list, &i->list); + goto done; + } + } + list_add_tail(&node->list, &alloc_list); +done: + /* Merge to the left */ + i = list_entry(node->list.prev, struct alloc_node, list); + if (node->list.prev != &alloc_list) { + BUG_ON((i->base + i->num) > node->base); + if ((i->base + i->num) == node->base) { + node->base = i->base; + node->num += i->num; + list_del(&i->list); + kfree(i); + } + } + /* Merge to the right */ + i = list_entry(node->list.next, struct alloc_node, list); + if (node->list.next != &alloc_list) { + BUG_ON((node->base + node->num) > i->base); + if ((node->base + node->num) == i->base) { + node->num += i->num; + list_del(&i->list); + kfree(i); + } + } + spin_unlock_irq(&alloc_lock); + DUMP(); +} +EXPORT_SYMBOL(qman_release_fqid_range); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_low.h +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_low.h @@ -0,0 +1,1186 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_private.h" + +/***************************/ +/* Portal register assists */ +/***************************/ + +/* Cache-inhibited register offsets */ +#define REG_EQCR_PI_CINH 0x0000 +#define REG_EQCR_CI_CINH 0x0004 +#define REG_EQCR_ITR 0x0008 +#define REG_DQRR_PI_CINH 0x0040 +#define REG_DQRR_CI_CINH 0x0044 +#define REG_DQRR_ITR 0x0048 +#define REG_DQRR_DCAP 0x0050 +#define REG_DQRR_SDQCR 0x0054 +#define REG_DQRR_VDQCR 0x0058 +#define REG_DQRR_PDQCR 0x005c +#define REG_MR_PI_CINH 0x0080 +#define REG_MR_CI_CINH 0x0084 +#define REG_MR_ITR 0x0088 +#define REG_CFG 0x0100 +#define REG_ISR 0x0e00 +#define REG_ITPR 0x0e14 + +/* Cache-enabled register offsets */ +#define CL_EQCR 0x0000 +#define CL_DQRR 0x1000 +#define CL_MR 0x2000 +#define CL_EQCR_PI_CENA 0x3000 +#define CL_EQCR_CI_CENA 0x3100 +#define CL_DQRR_PI_CENA 0x3200 +#define CL_DQRR_CI_CENA 0x3300 +#define CL_MR_PI_CENA 0x3400 +#define CL_MR_CI_CENA 0x3500 +#define CL_CR 0x3800 +#define CL_RR0 0x3900 +#define CL_RR1 0x3940 + +/* BTW, the drivers (and h/w programming model) already obtain the required + * synchronisation for portal accesses via lwsync(), hwsync(), and + * data-dependencies. Use of barrier()s or other order-preserving primitives + * simply degrade performance. Hence the use of the __raw_*() interfaces, which + * simply ensure that the compiler treats the portal registers as volatile (ie. + * non-coherent). */ + +/* Cache-inhibited register access. */ +#define __qm_in(qm, o) __raw_readl((qm)->addr_ci + (o)) +#define __qm_out(qm, o, val) __raw_writel((val), (qm)->addr_ci + (o)) +#define qm_in(reg) __qm_in(&portal->addr, REG_##reg) +#define qm_out(reg, val) __qm_out(&portal->addr, REG_##reg, val) + +/* Cache-enabled (index) register access */ +#define __qm_cl_touch_ro(qm, o) dcbt_ro((qm)->addr_ce + (o)) +#define __qm_cl_touch_rw(qm, o) dcbt_rw((qm)->addr_ce + (o)) +#define __qm_cl_in(qm, o) __raw_readl((qm)->addr_ce + (o)) +#define __qm_cl_out(qm, o, val) \ + do { \ + u32 *__tmpclout = (qm)->addr_ce + (o); \ + __raw_writel((val), __tmpclout); \ + dcbf(__tmpclout); \ + } while (0) +#define __qm_cl_invalidate(qm, o) dcbi((qm)->addr_ce + (o)) +#define qm_cl_touch_ro(reg) __qm_cl_touch_ro(&portal->addr, CL_##reg##_CENA) +#define qm_cl_touch_rw(reg) __qm_cl_touch_rw(&portal->addr, CL_##reg##_CENA) +#define qm_cl_in(reg) __qm_cl_in(&portal->addr, CL_##reg##_CENA) +#define qm_cl_out(reg, val) __qm_cl_out(&portal->addr, CL_##reg##_CENA, val) +#define qm_cl_invalidate(reg) __qm_cl_invalidate(&portal->addr, CL_##reg##_CENA) + +/* Cache-enabled ring access */ +#define qm_cl(base, idx) ((void *)base + ((idx) << 6)) + +/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf + * analysis, look at using the "extra" bit in the ring index registers to avoid + * cyclic issues. */ +static inline u8 cyc_diff(u8 ringsize, u8 first, u8 last) +{ + /* 'first' is included, 'last' is excluded */ + if (first <= last) + return last - first; + return ringsize + last - first; +} + +/* Portal modes. + * Enum types; + * pmode == production mode + * cmode == consumption mode, + * dmode == h/w dequeue mode. + * Enum values use 3 letter codes. First letter matches the portal mode, + * remaining two letters indicate; + * ci == cache-inhibited portal register + * ce == cache-enabled portal register + * vb == in-band valid-bit (cache-enabled) + * dc == DCA (Discrete Consumption Acknowledgement), DQRR-only + * As for "enum qm_dqrr_dmode", it should be self-explanatory. + */ +enum qm_eqcr_pmode { /* matches QCSP_CFG::EPM */ + qm_eqcr_pci = 0, /* PI index, cache-inhibited */ + qm_eqcr_pce = 1, /* PI index, cache-enabled */ + qm_eqcr_pvb = 2 /* valid-bit */ +}; +enum qm_eqcr_cmode { /* s/w-only */ + qm_eqcr_cci, /* CI index, cache-inhibited */ + qm_eqcr_cce /* CI index, cache-enabled */ +}; +enum qm_dqrr_dmode { /* matches QCSP_CFG::DP */ + qm_dqrr_dpush = 0, /* SDQCR + VDQCR */ + qm_dqrr_dpull = 1 /* PDQCR */ +}; +enum qm_dqrr_pmode { /* s/w-only */ + qm_dqrr_pci, /* reads DQRR_PI_CINH */ + qm_dqrr_pce, /* reads DQRR_PI_CENA */ + qm_dqrr_pvb /* reads valid-bit */ +}; +enum qm_dqrr_cmode { /* matches QCSP_CFG::DCM */ + qm_dqrr_cci = 0, /* CI index, cache-inhibited */ + qm_dqrr_cce = 1, /* CI index, cache-enabled */ + qm_dqrr_cdc = 2 /* Discrete Consumption Acknowledgement */ +}; +enum qm_mr_pmode { /* s/w-only */ + qm_mr_pci, /* reads MR_PI_CINH */ + qm_mr_pce, /* reads MR_PI_CENA */ + qm_mr_pvb /* reads valid-bit */ +}; +enum qm_mr_cmode { /* matches QCSP_CFG::MM */ + qm_mr_cci = 0, /* CI index, cache-inhibited */ + qm_mr_cce = 1 /* CI index, cache-enabled */ +}; + + +/* ------------------------- */ +/* --- Portal structures --- */ + +#define QM_EQCR_SIZE 8 +#define QM_DQRR_SIZE 16 +#define QM_MR_SIZE 8 + +struct qm_eqcr { + struct qm_eqcr_entry *ring, *cursor; + u8 ci, available, ithresh, vbit; +#ifdef CONFIG_FSL_DPA_CHECKING + u32 busy; + enum qm_eqcr_pmode pmode; + enum qm_eqcr_cmode cmode; +#endif +}; + +struct qm_dqrr { + const struct qm_dqrr_entry *ring, *cursor; + u8 pi, ci, fill, ithresh, vbit; +#ifdef CONFIG_FSL_DPA_CHECKING +#define QM_DQRR_FLAG_RE 0x01 /* Stash ring entries */ +#define QM_DQRR_FLAG_SE 0x02 /* Stash data */ + u8 flags; + enum qm_dqrr_dmode dmode; + enum qm_dqrr_pmode pmode; + enum qm_dqrr_cmode cmode; +#endif +}; + +struct qm_mr { + const struct qm_mr_entry *ring, *cursor; + u8 pi, ci, fill, ithresh, vbit; +#ifdef CONFIG_FSL_DPA_CHECKING + enum qm_mr_pmode pmode; + enum qm_mr_cmode cmode; +#endif +}; + +struct qm_mc { + struct qm_mc_command *cr; + struct qm_mc_result *rr; + u8 rridx, vbit; +#ifdef CONFIG_FSL_DPA_CHECKING + enum { + /* Can be _mc_start()ed */ + mc_idle, + /* Can be _mc_commit()ed or _mc_abort()ed */ + mc_user, + /* Can only be _mc_retry()ed */ + mc_hw + } state; +#endif +}; + +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 +/* For workarounds that require storage. The struct alignment is required for + * cases where operations on "shadow" structs need the same alignment as is + * present on the corresponding h/w data structs (specifically, there is a + * zero-bit present above the range required to address the ring, so that + * iteration can be achieved by incrementing a ring pointer and clearing the + * carry-bit). The "portal" struct needs the same alignment because this type + * goes at its head, so it has a more radical alignment requirement if this + * structure is used. (NB: "64" instead of "L1_CACHE_BYTES", because this + * alignment relates to the h/w interface, not the CPU cache granularity!)*/ +#define QM_PORTAL_ALIGNMENT __attribute__((aligned(32 * 64))) +struct qm_portal_bugs { + /* shadow MR ring, for QMAN9 workaround, 8-CL-aligned */ + struct qm_mr_entry mr[QM_MR_SIZE]; + /* shadow MC result, for QMAN6 and QMAN7 workarounds, CL-aligned */ + struct qm_mc_result result; + /* boolean switch for QMAN7 workaround */ + int initfq_and_sched; +} QM_PORTAL_ALIGNMENT; +#else +#define QM_PORTAL_ALIGNMENT ____cacheline_aligned +#endif + +struct qm_addr { + void __iomem *addr_ce; /* cache-enabled */ + void __iomem *addr_ci; /* cache-inhibited */ +}; + +struct qm_portal { +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 + struct qm_portal_bugs bugs; +#endif + /* In the non-CONFIG_FSL_DPA_CHECKING case, the following stuff up to + * and including 'mc' fits within a cacheline (yay!). The 'config' part + * is setup-only, so isn't a cause for a concern. In other words, don't + * rearrange this structure on a whim, there be dragons ... */ + struct qm_addr addr; + struct qm_eqcr eqcr; + struct qm_dqrr dqrr; + struct qm_mr mr; + struct qm_mc mc; +} QM_PORTAL_ALIGNMENT; + + +/* ---------------- */ +/* --- EQCR API --- */ + +/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ +#define EQCR_CARRYCLEAR(p) \ + (void *)((unsigned long)(p) & (~(unsigned long)(QM_EQCR_SIZE << 6))) + +/* Bit-wise logic to convert a ring pointer to a ring index */ +static inline u8 EQCR_PTR2IDX(struct qm_eqcr_entry *e) +{ + return ((uintptr_t)e >> 6) & (QM_EQCR_SIZE - 1); +} + +/* Increment the 'cursor' ring pointer, taking 'vbit' into account */ +static inline void EQCR_INC(struct qm_eqcr *eqcr) +{ + /* NB: this is odd-looking, but experiments show that it generates fast + * code with essentially no branching overheads. We increment to the + * next EQCR pointer and handle overflow and 'vbit'. */ + struct qm_eqcr_entry *partial = eqcr->cursor + 1; + eqcr->cursor = EQCR_CARRYCLEAR(partial); + if (partial != eqcr->cursor) + eqcr->vbit ^= QM_EQCR_VERB_VBIT; +} + +static inline int qm_eqcr_init(struct qm_portal *portal, + enum qm_eqcr_pmode pmode, + __maybe_unused enum qm_eqcr_cmode cmode) +{ + /* This use of 'register', as well as all other occurances, is because + * it has been observed to generate much faster code with gcc than is + * otherwise the case. */ + register struct qm_eqcr *eqcr = &portal->eqcr; + u32 cfg; + u8 pi; + + eqcr->ring = portal->addr.addr_ce + CL_EQCR; + eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); + qm_cl_invalidate(EQCR_CI); + pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1); + eqcr->cursor = eqcr->ring + pi; + eqcr->vbit = (qm_in(EQCR_PI_CINH) & QM_EQCR_SIZE) ? + QM_EQCR_VERB_VBIT : 0; + eqcr->available = QM_EQCR_SIZE - 1 - + cyc_diff(QM_EQCR_SIZE, eqcr->ci, pi); + eqcr->ithresh = qm_in(EQCR_ITR); +#ifdef CONFIG_FSL_DPA_CHECKING + eqcr->busy = 0; + eqcr->pmode = pmode; + eqcr->cmode = cmode; +#endif + cfg = (qm_in(CFG) & 0x00ffffff) | + ((pmode & 0x3) << 24); /* QCSP_CFG::EPM */ + qm_out(CFG, cfg); + return 0; +} + +static inline void qm_eqcr_finish(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + u8 pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1); + u8 ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); + + DPA_ASSERT(!eqcr->busy); + if (pi != EQCR_PTR2IDX(eqcr->cursor)) + pr_crit("losing uncommited EQCR entries\n"); + if (ci != eqcr->ci) + pr_crit("missing existing EQCR completions\n"); + if (eqcr->ci != EQCR_PTR2IDX(eqcr->cursor)) + pr_crit("EQCR destroyed unquiesced\n"); +} + +static inline struct qm_eqcr_entry *qm_eqcr_start(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + DPA_ASSERT(!eqcr->busy); + if (!eqcr->available) + return NULL; +#ifdef CONFIG_FSL_DPA_CHECKING + eqcr->busy = 1; +#endif + dcbz_64(eqcr->cursor); + return eqcr->cursor; +} + +static inline void qm_eqcr_abort(struct qm_portal *portal) +{ + __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr; + DPA_ASSERT(eqcr->busy); +#ifdef CONFIG_FSL_DPA_CHECKING + eqcr->busy = 0; +#endif +} + +static inline struct qm_eqcr_entry *qm_eqcr_pend_and_next( + struct qm_portal *portal, u8 myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + DPA_ASSERT(eqcr->busy); + DPA_ASSERT(eqcr->pmode != qm_eqcr_pvb); + if (eqcr->available == 1) + return NULL; + eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit; + dcbf(eqcr->cursor); + EQCR_INC(eqcr); + eqcr->available--; + dcbz_64(eqcr->cursor); + return eqcr->cursor; +} + +#define EQCR_COMMIT_CHECKS(eqcr) \ +do { \ + DPA_ASSERT(eqcr->busy); \ + DPA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); \ + DPA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0x00ffffff)); \ +} while(0) + +static inline void qm_eqcr_pci_commit(struct qm_portal *portal, u8 myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + EQCR_COMMIT_CHECKS(eqcr); + DPA_ASSERT(eqcr->pmode == qm_eqcr_pci); + eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit; + EQCR_INC(eqcr); + eqcr->available--; + dcbf(eqcr->cursor); + hwsync(); + qm_out(EQCR_PI_CINH, EQCR_PTR2IDX(eqcr->cursor)); +#ifdef CONFIG_FSL_DPA_CHECKING + eqcr->busy = 0; +#endif +} + +static inline void qm_eqcr_pce_prefetch(struct qm_portal *portal) +{ + __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr; + DPA_ASSERT(eqcr->pmode == qm_eqcr_pce); + qm_cl_invalidate(EQCR_PI); + qm_cl_touch_rw(EQCR_PI); +} + +static inline void qm_eqcr_pce_commit(struct qm_portal *portal, u8 myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + EQCR_COMMIT_CHECKS(eqcr); + DPA_ASSERT(eqcr->pmode == qm_eqcr_pce); + eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit; + EQCR_INC(eqcr); + eqcr->available--; + dcbf(eqcr->cursor); + lwsync(); + qm_cl_out(EQCR_PI, EQCR_PTR2IDX(eqcr->cursor)); +#ifdef CONFIG_FSL_DPA_CHECKING + eqcr->busy = 0; +#endif +} + +static inline void qm_eqcr_pvb_commit(struct qm_portal *portal, u8 myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + struct qm_eqcr_entry *eqcursor; + EQCR_COMMIT_CHECKS(eqcr); + DPA_ASSERT(eqcr->pmode == qm_eqcr_pvb); + lwsync(); + eqcursor = eqcr->cursor; + eqcursor->__dont_write_directly__verb = myverb | eqcr->vbit; + dcbf(eqcursor); + EQCR_INC(eqcr); + eqcr->available--; +#ifdef CONFIG_FSL_DPA_CHECKING + eqcr->busy = 0; +#endif +} + +static inline u8 qm_eqcr_cci_update(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + u8 diff, old_ci = eqcr->ci; + DPA_ASSERT(eqcr->cmode == qm_eqcr_cci); + eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); + diff = cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); + eqcr->available += diff; + return diff; +} + +static inline void qm_eqcr_cce_prefetch(struct qm_portal *portal) +{ + __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr; + DPA_ASSERT(eqcr->cmode == qm_eqcr_cce); + qm_cl_touch_ro(EQCR_CI); +} + +static inline u8 qm_eqcr_cce_update(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + u8 diff, old_ci = eqcr->ci; + DPA_ASSERT(eqcr->cmode == qm_eqcr_cce); + eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1); + qm_cl_invalidate(EQCR_CI); + diff = cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); + eqcr->available += diff; + return diff; +} + +static inline u8 qm_eqcr_get_ithresh(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + return eqcr->ithresh; +} + +static inline void qm_eqcr_set_ithresh(struct qm_portal *portal, u8 ithresh) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + eqcr->ithresh = ithresh; + qm_out(EQCR_ITR, ithresh); +} + +static inline u8 qm_eqcr_get_avail(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + return eqcr->available; +} + +static inline u8 qm_eqcr_get_fill(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + return QM_EQCR_SIZE - 1 - eqcr->available; +} + + +/* ---------------- */ +/* --- DQRR API --- */ + +/* FIXME: many possible improvements; + * - look at changing the API to use pointer rather than index parameters now + * that 'cursor' is a pointer, + * - consider moving other parameters to pointer if it could help (ci) + */ + +#define DQRR_CARRYCLEAR(p) \ + (void *)((unsigned long)(p) & (~(unsigned long)(QM_DQRR_SIZE << 6))) + +static inline u8 DQRR_PTR2IDX(const struct qm_dqrr_entry *e) +{ + return ((uintptr_t)e >> 6) & (QM_DQRR_SIZE - 1); +} + +static inline const struct qm_dqrr_entry *DQRR_INC( + const struct qm_dqrr_entry *e) +{ + return DQRR_CARRYCLEAR(e + 1); +} + +static inline void qm_dqrr_set_maxfill(struct qm_portal *portal, u8 mf) +{ + qm_out(CFG, (qm_in(CFG) & 0xff0fffff) | + ((mf & (QM_DQRR_SIZE - 1)) << 20)); +} + +static inline int qm_dqrr_init(struct qm_portal *portal, + const struct qm_portal_config *config, + enum qm_dqrr_dmode dmode, + __maybe_unused enum qm_dqrr_pmode pmode, + enum qm_dqrr_cmode cmode, u8 max_fill, + int disable_stash) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + u32 cfg; + + if ((config->public_cfg.has_stashing) && (config->public_cfg.cpu == -1)) + return -EINVAL; + /* Make sure the DQRR will be idle when we enable */ + qm_out(DQRR_SDQCR, 0); + qm_out(DQRR_VDQCR, 0); + qm_out(DQRR_PDQCR, 0); + dqrr->ring = portal->addr.addr_ce + CL_DQRR; + dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1); + dqrr->ci = qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1); + dqrr->cursor = dqrr->ring + dqrr->ci; + dqrr->fill = cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi); + dqrr->vbit = (qm_in(DQRR_PI_CINH) & QM_DQRR_SIZE) ? + QM_DQRR_VERB_VBIT : 0; + dqrr->ithresh = qm_in(DQRR_ITR); +#ifdef CONFIG_FSL_DPA_CHECKING + dqrr->dmode = dmode; + dqrr->pmode = pmode; + dqrr->cmode = cmode; + dqrr->flags = 0; + if (!disable_stash) + dqrr->flags |= QM_DQRR_FLAG_RE | QM_DQRR_FLAG_SE; +#endif + cfg = (qm_in(CFG) & 0xff000f00) | + ((max_fill & (QM_DQRR_SIZE - 1)) << 20) | /* DQRR_MF */ + ((dmode & 1) << 18) | /* DP */ + ((cmode & 3) << 16) | /* DCM */ + (disable_stash ? 0 : /* RE+SE */ + config->public_cfg.has_stashing ? 0xa0 : 0) | + (0 ? 0x40 : 0) | /* Ignore RP */ + (0 ? 0x10 : 0); /* Ignore SP */ + qm_out(CFG, cfg); + qm_dqrr_set_maxfill(portal, max_fill); + return 0; +} + +static inline void qm_dqrr_finish(struct qm_portal *portal) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef CONFIG_FSL_DPA_CHECKING + if ((dqrr->cmode != qm_dqrr_cdc) && + (dqrr->ci != DQRR_PTR2IDX(dqrr->cursor))) + pr_crit("Ignoring completed DQRR entries\n"); +#endif +} + +static inline const struct qm_dqrr_entry *qm_dqrr_current( + struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + if (!dqrr->fill) + return NULL; + return dqrr->cursor; +} + +static inline u8 qm_dqrr_cursor(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + return DQRR_PTR2IDX(dqrr->cursor); +} + +static inline u8 qm_dqrr_next(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->fill); + dqrr->cursor = DQRR_INC(dqrr->cursor); + return --dqrr->fill; +} + +static inline u8 qm_dqrr_pci_update(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + u8 diff, old_pi = dqrr->pi; + DPA_ASSERT(dqrr->pmode == qm_dqrr_pci); + dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1); + diff = cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi); + dqrr->fill += diff; + return diff; +} + +static inline void qm_dqrr_pce_prefetch(struct qm_portal *portal) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->pmode == qm_dqrr_pce); + qm_cl_invalidate(DQRR_PI); + qm_cl_touch_ro(DQRR_PI); +} + +static inline u8 qm_dqrr_pce_update(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + u8 diff, old_pi = dqrr->pi; + DPA_ASSERT(dqrr->pmode == qm_dqrr_pce); + dqrr->pi = qm_cl_in(DQRR_PI) & (QM_DQRR_SIZE - 1); + diff = cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi); + dqrr->fill += diff; + return diff; +} + +static inline void qm_dqrr_pvb_update(struct qm_portal *portal, int coherent) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + const struct qm_dqrr_entry *res = qm_cl(dqrr->ring, dqrr->pi); + DPA_ASSERT(dqrr->pmode == qm_dqrr_pvb); + /* when accessing 'verb', use __raw_readb() to ensure that compiler + * inlining doesn't try to optimise out "excess reads". */ + if ((__raw_readb(&res->verb) & QM_DQRR_VERB_VBIT) == dqrr->vbit) { + dqrr->pi = (dqrr->pi + 1) & (QM_DQRR_SIZE - 1); + if (!dqrr->pi) + dqrr->vbit ^= QM_DQRR_VERB_VBIT; + dqrr->fill++; + if (!coherent) { + DPA_ASSERT(!(dqrr->flags & QM_DQRR_FLAG_RE)); + dcbit_ro(DQRR_INC(res)); + } + } else if (!coherent) { + DPA_ASSERT(!(dqrr->flags & QM_DQRR_FLAG_RE)); + dcbit_ro(res); + } +} + +static inline void qm_dqrr_cci_consume(struct qm_portal *portal, u8 num) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cci); + dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1); + qm_out(DQRR_CI_CINH, dqrr->ci); +} + +static inline void qm_dqrr_cci_consume_to_current(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cci); + dqrr->ci = DQRR_PTR2IDX(dqrr->cursor); + qm_out(DQRR_CI_CINH, dqrr->ci); +} + +static inline void qm_dqrr_cce_prefetch(struct qm_portal *portal) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cce); + qm_cl_invalidate(DQRR_CI); + qm_cl_touch_rw(DQRR_CI); +} + +static inline void qm_dqrr_cce_consume(struct qm_portal *portal, u8 num) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cce); + dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1); + qm_cl_out(DQRR_CI, dqrr->ci); +} + +static inline void qm_dqrr_cce_consume_to_current(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cce); + dqrr->ci = DQRR_PTR2IDX(dqrr->cursor); + qm_cl_out(DQRR_CI, dqrr->ci); +} + +static inline void qm_dqrr_cdc_consume_1(struct qm_portal *portal, u8 idx, + int park) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + DPA_ASSERT(idx < QM_DQRR_SIZE); + qm_out(DQRR_DCAP, (0 << 8) | /* S */ + ((park ? 1 : 0) << 6) | /* PK */ + idx); /* DCAP_CI */ +} + +static inline void qm_dqrr_cdc_consume_1ptr(struct qm_portal *portal, + const struct qm_dqrr_entry *dq, + int park) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + u8 idx = DQRR_PTR2IDX(dq); + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + DPA_ASSERT((dqrr->ring + idx) == dq); + DPA_ASSERT(idx < QM_DQRR_SIZE); + qm_out(DQRR_DCAP, (0 << 8) | /* DQRR_DCAP::S */ + ((park ? 1 : 0) << 6) | /* DQRR_DCAP::PK */ + idx); /* DQRR_DCAP::DCAP_CI */ +} + +static inline void qm_dqrr_cdc_consume_n(struct qm_portal *portal, u16 bitmask) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + qm_out(DQRR_DCAP, (1 << 8) | /* DQRR_DCAP::S */ + ((u32)bitmask << 16)); /* DQRR_DCAP::DCAP_CI */ +} + +static inline u8 qm_dqrr_cdc_cci(struct qm_portal *portal) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + return qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1); +} + +static inline void qm_dqrr_cdc_cce_prefetch(struct qm_portal *portal) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + qm_cl_invalidate(DQRR_CI); + qm_cl_touch_ro(DQRR_CI); +} + +static inline u8 qm_dqrr_cdc_cce(struct qm_portal *portal) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); + return qm_cl_in(DQRR_CI) & (QM_DQRR_SIZE - 1); +} + +static inline u8 qm_dqrr_get_ci(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc); + return dqrr->ci; +} + +static inline void qm_dqrr_park(struct qm_portal *portal, u8 idx) +{ + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc); + qm_out(DQRR_DCAP, (0 << 8) | /* S */ + (1 << 6) | /* PK */ + (idx & (QM_DQRR_SIZE - 1))); /* DCAP_CI */ +} + +static inline void qm_dqrr_park_current(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc); + qm_out(DQRR_DCAP, (0 << 8) | /* S */ + (1 << 6) | /* PK */ + DQRR_PTR2IDX(dqrr->cursor)); /* DCAP_CI */ +} + +static inline void qm_dqrr_sdqcr_set(struct qm_portal *portal, u32 sdqcr) +{ + qm_out(DQRR_SDQCR, sdqcr); +} + +static inline u32 qm_dqrr_sdqcr_get(struct qm_portal *portal) +{ + return qm_in(DQRR_SDQCR); +} + +static inline void qm_dqrr_vdqcr_set(struct qm_portal *portal, u32 vdqcr) +{ + qm_out(DQRR_VDQCR, vdqcr); +} + +static inline u32 qm_dqrr_vdqcr_get(struct qm_portal *portal) +{ + return qm_in(DQRR_VDQCR); +} + +static inline void qm_dqrr_pdqcr_set(struct qm_portal *portal, u32 pdqcr) +{ + qm_out(DQRR_PDQCR, pdqcr); +} + +static inline u32 qm_dqrr_pdqcr_get(struct qm_portal *portal) +{ + return qm_in(DQRR_PDQCR); +} + +static inline u8 qm_dqrr_get_ithresh(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + return dqrr->ithresh; +} + +static inline void qm_dqrr_set_ithresh(struct qm_portal *portal, u8 ithresh) +{ + qm_out(DQRR_ITR, ithresh); +} + +static inline u8 qm_dqrr_get_maxfill(struct qm_portal *portal) +{ + return (qm_in(CFG) & 0x00f00000) >> 20; +} + + +/* -------------- */ +/* --- MR API --- */ + +#define MR_CARRYCLEAR(p) \ + (void *)((unsigned long)(p) & (~(unsigned long)(QM_MR_SIZE << 6))) + +static inline u8 MR_PTR2IDX(const struct qm_mr_entry *e) +{ + return ((uintptr_t)e >> 6) & (QM_MR_SIZE - 1); +} + +static inline const struct qm_mr_entry *MR_INC(const struct qm_mr_entry *e) +{ + return MR_CARRYCLEAR(e + 1); +} + +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 +static inline void __mr_copy_and_fixup(struct qm_portal *p, u8 idx) +{ + if (qman_ip_rev == QMAN_REV10) { + struct qm_mr_entry *shadow = qm_cl(p->bugs.mr, idx); + struct qm_mr_entry *res = qm_cl(p->mr.ring, idx); + copy_words(shadow, res, sizeof(*res)); + /* Bypass the QM_MR_RC_*** definitions, and check the byte value + * directly to handle the erratum. */ + if (shadow->ern.rc == 0x06) + shadow->ern.rc = 0x60; + } +} +#else +#define __mr_copy_and_fixup(p, idx) do { ; } while (0) +#endif + +static inline int qm_mr_init(struct qm_portal *portal, enum qm_mr_pmode pmode, + enum qm_mr_cmode cmode) +{ + register struct qm_mr *mr = &portal->mr; + u32 cfg; + int loop; + +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 + if ((qman_ip_rev == QMAN_REV10) && (pmode != qm_mr_pvb)) { + pr_err("Qman is rev1, so QMAN9 workaround requires 'pvb'\n"); + return -EINVAL; + } +#endif + mr->ring = portal->addr.addr_ce + CL_MR; + mr->pi = qm_in(MR_PI_CINH) & (QM_MR_SIZE - 1); + mr->ci = qm_in(MR_CI_CINH) & (QM_MR_SIZE - 1); +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 + if (qman_ip_rev == QMAN_REV10) + /* Situate the cursor in the shadow ring */ + mr->cursor = portal->bugs.mr + mr->ci; + else +#endif + mr->cursor = mr->ring + mr->ci; + mr->fill = cyc_diff(QM_MR_SIZE, mr->ci, mr->pi); + mr->vbit = (qm_in(MR_PI_CINH) & QM_MR_SIZE) ? QM_MR_VERB_VBIT : 0; + mr->ithresh = qm_in(MR_ITR); +#ifdef CONFIG_FSL_DPA_CHECKING + mr->pmode = pmode; + mr->cmode = cmode; +#endif + /* Only new entries get the copy-and-fixup treatment from + * qm_mr_pvb_update(), so perform it here for any stale entries. */ + for (loop = 0; loop < mr->fill; loop++) + __mr_copy_and_fixup(portal, (mr->ci + loop) & (QM_MR_SIZE - 1)); + cfg = (qm_in(CFG) & 0xfffff0ff) | + ((cmode & 1) << 8); /* QCSP_CFG:MM */ + qm_out(CFG, cfg); + return 0; +} + +static inline void qm_mr_finish(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + if (mr->ci != MR_PTR2IDX(mr->cursor)) + pr_crit("Ignoring completed MR entries\n"); +} + +static inline const struct qm_mr_entry *qm_mr_current(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + if (!mr->fill) + return NULL; + return mr->cursor; +} + +static inline u8 qm_mr_cursor(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + return MR_PTR2IDX(mr->cursor); +} + +static inline u8 qm_mr_next(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + DPA_ASSERT(mr->fill); + mr->cursor = MR_INC(mr->cursor); + return --mr->fill; +} + +static inline u8 qm_mr_pci_update(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + u8 diff, old_pi = mr->pi; + DPA_ASSERT(mr->pmode == qm_mr_pci); + mr->pi = qm_in(MR_PI_CINH); + diff = cyc_diff(QM_MR_SIZE, old_pi, mr->pi); + mr->fill += diff; + return diff; +} + +static inline void qm_mr_pce_prefetch(struct qm_portal *portal) +{ + __maybe_unused register struct qm_mr *mr = &portal->mr; + DPA_ASSERT(mr->pmode == qm_mr_pce); + qm_cl_invalidate(MR_PI); + qm_cl_touch_ro(MR_PI); +} + +static inline u8 qm_mr_pce_update(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + u8 diff, old_pi = mr->pi; + DPA_ASSERT(mr->pmode == qm_mr_pce); + mr->pi = qm_cl_in(MR_PI) & (QM_MR_SIZE - 1); + diff = cyc_diff(QM_MR_SIZE, old_pi, mr->pi); + mr->fill += diff; + return diff; +} + +static inline void qm_mr_pvb_update(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + const struct qm_mr_entry *res = qm_cl(mr->ring, mr->pi); + DPA_ASSERT(mr->pmode == qm_mr_pvb); + /* when accessing 'verb', use __raw_readb() to ensure that compiler + * inlining doesn't try to optimise out "excess reads". */ + if ((__raw_readb(&res->verb) & QM_MR_VERB_VBIT) == mr->vbit) { + __mr_copy_and_fixup(portal, mr->pi); + mr->pi = (mr->pi + 1) & (QM_MR_SIZE - 1); + if (!mr->pi) + mr->vbit ^= QM_MR_VERB_VBIT; + mr->fill++; + res = MR_INC(res); + } + dcbit_ro(res); +} + +static inline void qm_mr_cci_consume(struct qm_portal *portal, u8 num) +{ + register struct qm_mr *mr = &portal->mr; + DPA_ASSERT(mr->cmode == qm_mr_cci); + mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1); + qm_out(MR_CI_CINH, mr->ci); +} + +static inline void qm_mr_cci_consume_to_current(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + DPA_ASSERT(mr->cmode == qm_mr_cci); + mr->ci = MR_PTR2IDX(mr->cursor); + qm_out(MR_CI_CINH, mr->ci); +} + +static inline void qm_mr_cce_prefetch(struct qm_portal *portal) +{ + __maybe_unused register struct qm_mr *mr = &portal->mr; + DPA_ASSERT(mr->cmode == qm_mr_cce); + qm_cl_invalidate(MR_CI); + qm_cl_touch_rw(MR_CI); +} + +static inline void qm_mr_cce_consume(struct qm_portal *portal, u8 num) +{ + register struct qm_mr *mr = &portal->mr; + DPA_ASSERT(mr->cmode == qm_mr_cce); + mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1); + qm_cl_out(MR_CI, mr->ci); +} + +static inline void qm_mr_cce_consume_to_current(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + DPA_ASSERT(mr->cmode == qm_mr_cce); + mr->ci = MR_PTR2IDX(mr->cursor); + qm_cl_out(MR_CI, mr->ci); +} + +static inline u8 qm_mr_get_ci(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + return mr->ci; +} + +static inline u8 qm_mr_get_ithresh(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + return mr->ithresh; +} + +static inline void qm_mr_set_ithresh(struct qm_portal *portal, u8 ithresh) +{ + qm_out(MR_ITR, ithresh); +} + + +/* ------------------------------ */ +/* --- Management command API --- */ + +static inline int qm_mc_init(struct qm_portal *portal) +{ + register struct qm_mc *mc = &portal->mc; + mc->cr = portal->addr.addr_ce + CL_CR; + mc->rr = portal->addr.addr_ce + CL_RR0; + mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) & + QM_MCC_VERB_VBIT) ? 0 : 1; + mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0; +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_idle; +#endif + return 0; +} + +static inline void qm_mc_finish(struct qm_portal *portal) +{ + __maybe_unused register struct qm_mc *mc = &portal->mc; + DPA_ASSERT(mc->state == mc_idle); +#ifdef CONFIG_FSL_DPA_CHECKING + if (mc->state != mc_idle) + pr_crit("Losing incomplete MC command\n"); +#endif +} + +static inline struct qm_mc_command *qm_mc_start(struct qm_portal *portal) +{ + register struct qm_mc *mc = &portal->mc; + DPA_ASSERT(mc->state == mc_idle); +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_user; +#endif + dcbz_64(mc->cr); + return mc->cr; +} + +static inline void qm_mc_abort(struct qm_portal *portal) +{ + __maybe_unused register struct qm_mc *mc = &portal->mc; + DPA_ASSERT(mc->state == mc_user); +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_idle; +#endif +} + +static inline void qm_mc_commit(struct qm_portal *portal, u8 myverb) +{ + register struct qm_mc *mc = &portal->mc; + struct qm_mc_result *rr = mc->rr + mc->rridx; + DPA_ASSERT(mc->state == mc_user); + lwsync(); +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 + if ((qman_ip_rev == QMAN_REV10) && ((myverb & QM_MCC_VERB_MASK) == + QM_MCC_VERB_INITFQ_SCHED)) { + u32 fqid = mc->cr->initfq.fqid; + /* Do two commands to avoid the hw bug. Note, we poll locally + * rather than using qm_mc_result() because from a DPA_CHECKING + * perspective, we don't want to appear to have "finished" until + * both commands are done. */ + mc->cr->__dont_write_directly__verb = mc->vbit | + QM_MCC_VERB_INITFQ_PARKED; + dcbf(mc->cr); + portal->bugs.initfq_and_sched = 1; + do { + dcbit_ro(rr); + } while (!__raw_readb(&rr->verb)); +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_idle; +#endif + if (rr->result != QM_MCR_RESULT_OK) { +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_hw; +#endif + return; + } + mc->rridx ^= 1; + mc->vbit ^= QM_MCC_VERB_VBIT; + rr = mc->rr + mc->rridx; + dcbz_64(mc->cr); + mc->cr->alterfq.fqid = fqid; + lwsync(); + myverb = QM_MCC_VERB_ALTER_SCHED; + } else + portal->bugs.initfq_and_sched = 0; +#endif + mc->cr->__dont_write_directly__verb = myverb | mc->vbit; + dcbf(mc->cr); + dcbit_ro(rr); +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_hw; +#endif +} + +static inline struct qm_mc_result *qm_mc_result(struct qm_portal *portal) +{ + register struct qm_mc *mc = &portal->mc; + struct qm_mc_result *rr = mc->rr + mc->rridx; + DPA_ASSERT(mc->state == mc_hw); + /* The inactive response register's verb byte always returns zero until + * its command is submitted and completed. This includes the valid-bit, + * in case you were wondering... */ + if (!__raw_readb(&rr->verb)) { + dcbit_ro(rr); + return NULL; + } +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 + if (qman_ip_rev == QMAN_REV10) { + if ((__raw_readb(&rr->verb) & QM_MCR_VERB_MASK) == + QM_MCR_VERB_QUERYFQ) { + void *misplaced = (void *)rr + 50; + copy_words(&portal->bugs.result, rr, sizeof(*rr)); + rr = &portal->bugs.result; + copy_shorts(&rr->queryfq.fqd.td, misplaced, + sizeof(rr->queryfq.fqd.td)); + } else if (portal->bugs.initfq_and_sched) { + /* We split the user-requested command, make the final + * result match the requested type. */ + copy_words(&portal->bugs.result, rr, sizeof(*rr)); + rr = &portal->bugs.result; + rr->verb = (rr->verb & QM_MCR_VERB_RRID) | + QM_MCR_VERB_INITFQ_SCHED; + } + } +#endif + mc->rridx ^= 1; + mc->vbit ^= QM_MCC_VERB_VBIT; +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_idle; +#endif + return rr; +} + + +/* ------------------------------------- */ +/* --- Portal interrupt register API --- */ + +static inline int qm_isr_init(__always_unused struct qm_portal *portal) +{ + return 0; +} + +static inline void qm_isr_finish(__always_unused struct qm_portal *portal) +{ +} + +static inline void qm_isr_set_iperiod(struct qm_portal *portal, u16 iperiod) +{ + qm_out(ITPR, iperiod); +} + +static inline u32 __qm_isr_read(struct qm_portal *portal, enum qm_isr_reg n) +{ + return __qm_in(&portal->addr, REG_ISR + (n << 2)); +} + +static inline void __qm_isr_write(struct qm_portal *portal, enum qm_isr_reg n, + u32 val) +{ + __qm_out(&portal->addr, REG_ISR + (n << 2), val); +} + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_driver.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_driver.c @@ -0,0 +1,544 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "qman_private.h" + +/* Global variable containing revision id (even on non-control plane systems + * where CCSR isn't available) */ +u16 qman_ip_rev; +EXPORT_SYMBOL(qman_ip_rev); + +/* size of the fqd region in bytes */ +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP +static u32 fqd_size = (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ); +#endif + +/*****************/ +/* Portal driver */ +/*****************/ + +static struct dpa_uio_class qman_uio = { + .list = LIST_HEAD_INIT(qman_uio.list), + .dev_prefix = "qman-uio-" +}; +const struct dpa_uio_class *dpa_uio_qman(void) +{ + return &qman_uio; +} +EXPORT_SYMBOL(dpa_uio_qman); + +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX +/* Handlers for NULL portal callbacks (ie. where the contextB field, normally + * pointing to the corresponding FQ object, is NULL). */ +static enum qman_cb_dqrr_result null_cb_dqrr(struct qman_portal *qm, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr) +{ + pr_warning("Ignoring unowned DQRR frame on portal %p.\n", qm); + return qman_cb_dqrr_consume; +} +static void null_cb_mr(struct qman_portal *qm, struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + pr_warning("Ignoring unowned MR msg on portal %p, verb 0x%02x.\n", + qm, msg->verb); +} +static const struct qman_fq_cb null_cb = { + .dqrr = null_cb_dqrr, + .ern = null_cb_mr, + .dc_ern = null_cb_mr, + .fqs = null_cb_mr +}; +#endif + +#ifdef CONFIG_FSL_QMAN_PORTAL +/* This structure carries parameters from the device-tree handling code that + * wants to set up a portal for use on 1 or more CPUs, and each temporary thread + * created to run on those CPUs. The 'portal' member is the return value. */ +struct affine_portal_data { + struct completion done; + const struct qm_portal_config *pconfig; + struct qman_portal *redirect; + int recovery_mode; + struct qman_portal *portal; +}; + +/* This function is called in a temporary thread for each CPU, to initialise the + * "affine" portal that the CPU should use. The thread is created and run from + * the init_affine_portal() bootstrapper. If the CPU has not been assigned its + * own portal, "redirect" will be non-NULL indicating it should share another + * CPU's portal (it becomes a "slave"). */ +static __init int thread_init_affine_portal(void *__data) +{ + struct affine_portal_data *data = __data; + const struct qm_portal_config *pconfig = data->pconfig; + if (data->redirect) + data->portal = qman_create_affine_slave(data->redirect); + else { + /* TODO: cgrs ?? */ + data->portal = qman_create_affine_portal(pconfig, NULL, +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX + &null_cb, +#endif + data->recovery_mode); + if (data->portal) { + u32 irq_sources = 0; + /* default: enable all (available) pool channels */ + qman_static_dequeue_add(~0); + /* Determine what should be interrupt-vs-poll driven */ +#ifdef CONFIG_FSL_DPA_PIRQ_SLOW + irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | + QM_PIRQ_MRI | QM_PIRQ_CSCI; +#endif +#ifdef CONFIG_FSL_DPA_PIRQ_FAST + irq_sources |= QM_PIRQ_DQRI; +#endif + qman_irqsource_add(irq_sources); + } + } + complete(&data->done); + return 0; +} + +/* This function is just a bootstrap for running thread_init_affine_portal() on + * a given CPU. The parameters are passed in via the (void*) thread-arg (and + * results are received back) using the affine_portal_data struct. */ +static __init struct qman_portal *init_affine_portal( + const struct qm_portal_config *pconfig, + int cpu, struct qman_portal *redirect, + int recovery_mode) +{ + struct affine_portal_data data = { + .done = COMPLETION_INITIALIZER_ONSTACK(data.done), + .pconfig = pconfig, + .redirect = redirect, + .recovery_mode = recovery_mode, + .portal = NULL + }; + struct task_struct *k = kthread_create(thread_init_affine_portal, &data, + "qman_affine%d", cpu); + int ret; + if (IS_ERR(k)) { + pr_err("Failed to init %sQman affine portal for cpu %d\n", + redirect ? "(slave) " : "", cpu); + return NULL; + } + kthread_bind(k, cpu); + wake_up_process(k); + wait_for_completion(&data.done); + ret = kthread_stop(k); + if (ret) { + pr_err("Qman portal initialisation failed, cpu %d, code %d\n", + cpu, ret); + return NULL; + } + if (data.portal) + pr_info("Qman portal %sinitialised, cpu %d\n", + redirect ? "(slave) " : + pconfig->public_cfg.is_shared ? "(shared) " : "", cpu); + return data.portal; +} +#endif + +/* Parses the device-tree node, extracts the configuration, and if appropriate + * initialises the portal for use on one or more CPUs. */ +static __init struct qm_portal_config *fsl_qman_portal_init( + struct device_node *node) +{ + struct qm_portal_config *pcfg; + const u32 *index, *channel; + const phandle *ph; + struct device_node *tmp_node; + int irq, ret, numpools; + u16 ip_rev = 0; + + pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL); + if (!pcfg) { + pr_err("can't allocate portal config"); + return NULL; + } + + if (of_device_is_compatible(node, "fsl,qman-portal-1.0")) + ip_rev = QMAN_REV10; + else if (of_device_is_compatible(node, "fsl,qman-portal-1.1")) + ip_rev = QMAN_REV11; + else if (of_device_is_compatible(node, "fsl,qman-portal-1.2")) + ip_rev = QMAN_REV12; + else if (of_device_is_compatible(node, "fsl,qman-portal-2.0")) + ip_rev = QMAN_REV20; + + if (!qman_ip_rev) { + if (ip_rev) + qman_ip_rev = ip_rev; + else { + pr_warning("unknown Qman version, default to rev1.1\n"); + qman_ip_rev = QMAN_REV11; + } + } else if (ip_rev && (qman_ip_rev != ip_rev)) + pr_warning("Revision=0x%04x, but portal '%s' has 0x%04x\n", + qman_ip_rev, node->full_name, ip_rev); + + ret = of_address_to_resource(node, QM_ADDR_CE, + &pcfg->addr_phys[QM_ADDR_CE]); + if (ret) { + pr_err("Can't get %s property '%s'\n", node->full_name, + "reg::CE"); + goto err; + } + ret = of_address_to_resource(node, QM_ADDR_CI, + &pcfg->addr_phys[QM_ADDR_CI]); + if (ret) { + pr_err("Can't get %s property '%s'\n", node->full_name, + "reg::CI"); + goto err; + } + index = of_get_property(node, "cell-index", &ret); + if (!index || (ret != 4)) { + pr_err("Can't get %s property '%s'\n", node->full_name, + "cell-index"); + goto err; + } + channel = of_get_property(node, "fsl,qman-channel-id", &ret); + if (!channel || (ret != 4)) { + pr_err("Can't get %s property '%s'\n", node->full_name, + "fsl,qman-channel-id"); + goto err; + } + if (*channel != (*index + qm_channel_swportal0)) + pr_err("Warning: node %s has mismatched %s and %s\n", + node->full_name, "cell-index", "fsl,qman-channel-id"); + pcfg->public_cfg.channel = *channel; + /* Parse cpu associations for this portal. This involves dereferencing + * to the cpu device-tree nodes, but it also ensures we only try to work + * with CPUs that exist. (Eg. under a hypervisor.) */ + ph = of_get_property(node, "cpu-handle", &ret); + if (ph) { + if (ret != sizeof(phandle)) { + pr_err("Malformed %s property '%s'\n", node->full_name, + "cpu-handle"); + return NULL; + } + ret = check_cpu_phandle(*ph); + if (ret < 0) + return NULL; + pcfg->public_cfg.cpu = ret; + } else + pcfg->public_cfg.cpu = -1; + + ph = of_get_property(node, "fsl,qman-pool-channels", &ret); + if (ph && (ret % sizeof(phandle))) { + pr_err("Malformed %s property '%s'\n", node->full_name, + "fsl,qman-pool-channels"); + goto err; + } + numpools = ph ? (ret / sizeof(phandle)) : 0; + irq = irq_of_parse_and_map(node, 0); + if (irq == NO_IRQ) { + pr_err("Can't get %s property '%s'\n", node->full_name, + "interrupts"); + goto err; + } + pcfg->public_cfg.irq = irq; + pcfg->public_cfg.index = *index; + if (of_get_property(node, "fsl,hv-dma-handle", &ret)) + pcfg->public_cfg.has_stashing = 1; + else if (qman_ip_rev == QMAN_REV20) + pcfg->public_cfg.has_stashing = 1; + else +#ifdef CONFIG_FSL_PAMU + pcfg->public_cfg.has_stashing = 1; +#else + pcfg->public_cfg.has_stashing = 0; +#endif + pcfg->public_cfg.pools = 0; + pcfg->node = node; +#ifdef CONFIG_FSL_QMAN_CONFIG + /* We need the same LIODN offset for all portals */ + qman_liodn_fixup(pcfg->public_cfg.channel); +#endif + + if (of_get_property(node, "fsl,usdpaa-portal", &ret)) { + struct dpa_uio_portal *u = kmalloc(sizeof(*u), GFP_KERNEL); + if (!u) + goto err; + u->type = dpa_uio_portal_qman; + u->qm_cfg = pcfg; + list_add_tail(&u->node, &qman_uio.list); + /* Return NULL, otherwise the kernel may share it on CPUs that + * don't have their own portals, which would be ... *bad*. */ + return NULL; + } + + /* Map the portals now we know they aren't for UIO (the UIO code doesn't + * need the CE mapping, and so will do its own CI-only mapping). */ + pcfg->addr_virt[QM_ADDR_CE] = ioremap_prot( + pcfg->addr_phys[QM_ADDR_CE].start, + resource_size(&pcfg->addr_phys[QM_ADDR_CE]), + 0); + pcfg->addr_virt[QM_ADDR_CI] = ioremap_prot( + pcfg->addr_phys[QM_ADDR_CI].start, + resource_size(&pcfg->addr_phys[QM_ADDR_CI]), + _PAGE_GUARDED | _PAGE_NO_CACHE); + + while (numpools--) { + for_each_compatible_node(tmp_node, NULL, + "fsl,qman-pool-channel") { + phandle *lph = (phandle *)of_get_property(tmp_node, + "linux,phandle", &ret); + if (*lph == *ph) { + u32 *index = (u32 *)of_get_property(tmp_node, + "cell-index", &ret); + pcfg->public_cfg.pools |= + QM_SDQCR_CHANNELS_POOL(*index); + } + } + ph++; + } + if (pcfg->public_cfg.pools == 0) + panic("Unrecoverable error linking pool channels"); + + return pcfg; +err: + kfree(pcfg); + return NULL; +} + +static void __init fsl_qman_portal_destroy(struct qm_portal_config *pcfg) +{ + iounmap(pcfg->addr_virt[QM_ADDR_CE]); + iounmap(pcfg->addr_virt[QM_ADDR_CI]); + kfree(pcfg); +} + +static __init int fsl_fqid_range_init(struct device_node *node, + int recovery_mode) +{ + int ret; + u32 *range = (u32 *)of_get_property(node, "fsl,fqid-range", &ret); + if (!range) { + pr_err("No 'fsl,fqid-range' property in node %s\n", + node->full_name); + return -EINVAL; + } + if (ret != 8) { + pr_err("'fsl,fqid-range' is not a 2-cell range in node %s\n", + node->full_name); + return -EINVAL; + } + qman_release_fqid_range(range[0], range[1]); +#ifdef CONFIG_FSL_QMAN_PORTAL + /* If in recovery mode *and* we are using a private FQ allocation range, + * then automatically clean up all FQs in that range so we can + * automatically exit recovery mode too. */ + if (recovery_mode) { + u32 fqid; + for (fqid = range[0]; fqid < (range[0] + range[1]); fqid++) { + ret = qman_recovery_cleanup_fq(fqid); + if (ret) { + pr_err("Failed to recovery FQID %d\n", fqid); + return ret; + } + } + } +#else + BUG_ON(recovery_mode); +#endif + pr_info("Qman: FQID allocator includes range %d:%d%s\n", + range[0], range[1], recovery_mode ? " (recovered)" : ""); + return 0; +} + +#ifdef CONFIG_FSL_QMAN_PORTAL +static __init int __leave_recovery(void *__data) +{ + struct completion *done = __data; + qman_recovery_exit_local(); + complete(done); + return 0; +} + +int qman_recovery_exit(void) +{ + struct completion done = COMPLETION_INITIALIZER_ONSTACK(done); + unsigned int cpu; + + for_each_cpu(cpu, qman_affine_cpus()) { + struct task_struct *k = kthread_create(__leave_recovery, &done, + "qman_recovery"); + int ret; + if (IS_ERR(k)) { + pr_err("Thread failure (recovery) on cpu %d\n", cpu); + return -ENOMEM; + } + kthread_bind(k, cpu); + wake_up_process(k); + wait_for_completion(&done); + ret = kthread_stop(k); + if (ret) { + pr_err("Failed to exit recovery on cpu %d\n", cpu); + return ret; + } + pr_info("Qman portal exited recovery, cpu %d\n", cpu); + } + return 0; +} +EXPORT_SYMBOL(qman_recovery_exit); +#endif + +/***************/ +/* Driver load */ +/***************/ + +static __init int qman_init(void) +{ +#ifdef CONFIG_FSL_QMAN_PORTAL + struct qman_cgr cgr; + struct cpumask primary_cpus = *cpu_none_mask; + struct cpumask slave_cpus = *cpu_online_mask; + struct qman_portal *sharing_portal = NULL; + int sharing_cpu = -1; +#endif + struct device_node *dn; + struct qm_portal_config *pcfg; + int ret, use_bpid0 = 1, recovery_mode = 0; + LIST_HEAD(cfg_list); + + for_each_compatible_node(dn, NULL, "fsl,qman") { + if (!qman_init_error_int(dn)) + pr_info("Qman err interrupt handler present\n"); + else + pr_err("Qman err interrupt handler missing\n"); + } +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + ret = qman_setup_fq_lookup_table(fqd_size/64); + if (ret) + return ret; +#endif +#ifdef CONFIG_FSL_QMAN_PORTAL + if (fsl_dpa_should_recover()) + recovery_mode = 1; + for_each_compatible_node(dn, NULL, "fsl,qman-portal") { + pcfg = fsl_qman_portal_init(dn); + if (pcfg) { + if (pcfg->public_cfg.cpu >= 0) { + cpumask_set_cpu(pcfg->public_cfg.cpu, + &primary_cpus); + list_add(&pcfg->list, &cfg_list); + } else + fsl_qman_portal_destroy(pcfg); + } + } + /* only consider "online" CPUs */ + cpumask_and(&primary_cpus, &primary_cpus, cpu_online_mask); + if (cpumask_empty(&primary_cpus)) + /* No portals, we're done */ + return 0; + if (!cpumask_subset(cpu_online_mask, &primary_cpus)) { + /* Need to do some sharing. In lieu of anything more scientific + * (or configurable), we pick the last-most CPU that has a + * portal and share that one. */ + int next = cpumask_first(&primary_cpus); + while (next < nr_cpu_ids) { + sharing_cpu = next; + next = cpumask_next(next, &primary_cpus); + } + } + /* Parsing is done and sharing decisions are made, now initialise the + * portals and determine which "slave" CPUs are left over. */ + list_for_each_entry(pcfg, &cfg_list, list) { + struct qman_portal *p; + int is_shared = (!sharing_portal && (sharing_cpu >= 0) && + (pcfg->public_cfg.cpu == sharing_cpu)); + pcfg->public_cfg.is_shared = is_shared; + /* If it's not mapped to a CPU, or another portal is already + * initialised to the same CPU, skip this portal. */ + if (pcfg->public_cfg.cpu < 0 || !cpumask_test_cpu( + pcfg->public_cfg.cpu, &slave_cpus)) + continue; + p = init_affine_portal(pcfg, pcfg->public_cfg.cpu, NULL, + recovery_mode); + if (p) { + if (is_shared) + sharing_portal = p; + cpumask_clear_cpu(pcfg->public_cfg.cpu, &slave_cpus); + } + } + if (sharing_portal) { + int loop; + for_each_cpu(loop, &slave_cpus) { + struct qman_portal *p = init_affine_portal(NULL, loop, + sharing_portal, recovery_mode); + if (!p) + pr_err("Failed slave Qman portal for cpu %d\n", + loop); + } + } +#else + for_each_compatible_node(dn, NULL, "fsl,qman-portal") { + pcfg = fsl_qman_portal_init(dn); + if (pcfg) + /* No kernel portal support, so if USDPAA didn't consume + * the portal, we've no other use for it. */ + fsl_qman_portal_destroy(pcfg); + } +#endif + for_each_compatible_node(dn, NULL, "fsl,fqid-range") { + use_bpid0 = 0; + ret = fsl_fqid_range_init(dn, recovery_mode); + if (ret) + return ret; + } +#ifdef CONFIG_FSL_QMAN_PORTAL + /* If using private FQ allocation, exit recovery mode automatically (ie. + * after automatic recovery) */ + if (recovery_mode && !use_bpid0) { + ret = qman_recovery_exit(); + if (ret) + return ret; + } + for (cgr.cgrid = 0; cgr.cgrid < __CGR_NUM; cgr.cgrid++) { + /* This is to ensure h/w-internal CGR memory is zeroed out. Note + * that we do this for all conceivable CGRIDs, not all of which + * are necessarily available on the underlying hardware version. + * We ignore any errors for this reason. */ + qman_modify_cgr(&cgr, QMAN_CGR_FLAG_USE_INIT, NULL); + } +#endif + ret = fqalloc_init(use_bpid0); + if (ret) + return ret; + pr_info("Qman portals initialised\n"); + return 0; +} +subsys_initcall(qman_init); --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_private.h +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_private.h @@ -0,0 +1,292 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dpa_sys.h" +#include + +#if !defined(CONFIG_FSL_QMAN_FQ_LOOKUP) && defined(CONFIG_PPC64) +#error "_PPC64 requires _FSL_QMAN_FQ_LOOKUP" +#endif + + /* ----------------- */ + /* Congestion Groups */ + /* ----------------- */ +/* This wrapper represents a bit-array for the state of the 256 Qman congestion + * groups. Is also used as a *mask* for congestion groups, eg. so we ignore + * those that don't concern us. We harness the structure and accessor details + * already used in the management command to query congestion groups. */ +struct qman_cgrs { + struct __qm_mcr_querycongestion q; +}; +static inline void qman_cgrs_init(struct qman_cgrs *c) +{ + memset(c, 0, sizeof(*c)); +} +static inline void qman_cgrs_fill(struct qman_cgrs *c) +{ + memset(c, 0xff, sizeof(*c)); +} +static inline int qman_cgrs_get(struct qman_cgrs *c, int num) +{ + return QM_MCR_QUERYCONGESTION(&c->q, num); +} +static inline void qman_cgrs_set(struct qman_cgrs *c, int num) +{ + c->q.__state[__CGR_WORD(num)] |= (0x80000000 >> __CGR_SHIFT(num)); +} +static inline void qman_cgrs_unset(struct qman_cgrs *c, int num) +{ + c->q.__state[__CGR_WORD(num)] &= ~(0x80000000 >> __CGR_SHIFT(num)); +} +static inline int qman_cgrs_next(struct qman_cgrs *c, int num) +{ + while ((++num < __CGR_NUM) && !qman_cgrs_get(c, num)) + ; + return num; +} +static inline void qman_cgrs_cp(struct qman_cgrs *dest, + const struct qman_cgrs *src) +{ + memcpy(dest, src, sizeof(*dest)); +} +static inline void qman_cgrs_and(struct qman_cgrs *dest, + const struct qman_cgrs *a, const struct qman_cgrs *b) +{ + int ret; + u32 *_d = dest->q.__state; + const u32 *_a = a->q.__state; + const u32 *_b = b->q.__state; + for (ret = 0; ret < 8; ret++) + *(_d++) = *(_a++) & *(_b++); +} +static inline void qman_cgrs_xor(struct qman_cgrs *dest, + const struct qman_cgrs *a, const struct qman_cgrs *b) +{ + int ret; + u32 *_d = dest->q.__state; + const u32 *_a = a->q.__state; + const u32 *_b = b->q.__state; + for (ret = 0; ret < 8; ret++) + *(_d++) = *(_a++) ^ *(_b++); +} + +#define qman_cgrs_for_each_1(cgr, cgrs) \ + for ((cgr) = -1; (cgr) = qman_cgrs_next((cgrs), (cgr)),\ + (cgr) < __CGR_NUM;) + +/* used by CCSR and portal interrupt code */ +enum qm_isr_reg { + qm_isr_status = 0, + qm_isr_enable = 1, + qm_isr_disable = 2, + qm_isr_inhibit = 3 +}; + +#define QM_ADDR_CE 0 +#define QM_ADDR_CI 1 +struct qm_portal_config { + /* Corenet portal addresses; + * [0]==cache-enabled, [1]==cache-inhibited. */ + __iomem void *addr_virt[2]; + struct resource addr_phys[2]; + struct device_node *node; + /* Allow these to be joined in lists */ + struct list_head list; + /* User-visible portal configuration settings */ + struct qman_portal_config public_cfg; +}; + +/* Hooks for driver initialisation */ +__init int fqalloc_init(int use_bman); + +/* Revision info (for errata and feature handling) */ +#define QMAN_REV10 0x0100 +#define QMAN_REV11 0x0101 +#define QMAN_REV12 0x0102 +#define QMAN_REV20 0x0200 +extern u16 qman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */ + +#ifdef CONFIG_FSL_QMAN_CONFIG +/* Hooks from qman_driver.c to qman_config.c */ +int qman_init_error_int(struct device_node *node); +void qman_liodn_fixup(enum qm_channel channel); +#endif + +/* Hooks from qman_driver.c in to qman_high.c */ +struct qman_portal *qman_create_affine_portal( + const struct qm_portal_config *config, + const struct qman_cgrs *cgrs, + const struct qman_fq_cb *null_cb, + int recovery_mode); +struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect); +const struct qm_portal_config *qman_destroy_affine_portal(void); +void qman_recovery_exit_local(void); + +/* This CGR feature is supported by h/w and required by unit-tests and the + * debugfs hooks, so is implemented in the driver. However it allows an explicit + * corruption of h/w fields by s/w that are usually incorruptible (because the + * counters are usually maintained entirely within h/w). As such, we declare + * this API internally. */ +int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt, + struct qm_mcr_cgrtestwrite *result); + +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP +/* If the fq object pointer is greater than the size of context_b field, + * than a lookup table is required. */ +int qman_setup_fq_lookup_table(size_t num_entries); +#endif + +/*************************************************/ +/* QMan s/w corenet portal, low-level i/face */ +/*************************************************/ + +/* Note: most functions are only used by the high-level interface, so are + * inlined from qman_low.h. The stuff below is for use by other parts of the + * driver. */ + +/* For qm_dqrr_sdqcr_set(); Choose one SOURCE. Choose one COUNT. Choose one + * dequeue TYPE. Choose TOKEN (8-bit). + * If SOURCE == CHANNELS, + * Choose CHANNELS_DEDICATED and/or CHANNELS_POOL(n). + * You can choose DEDICATED_PRECEDENCE if the portal channel should have + * priority. + * If SOURCE == SPECIFICWQ, + * Either select the work-queue ID with SPECIFICWQ_WQ(), or select the + * channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the + * work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the + * same value. + */ +#define QM_SDQCR_SOURCE_CHANNELS 0x0 +#define QM_SDQCR_SOURCE_SPECIFICWQ 0x40000000 +#define QM_SDQCR_COUNT_EXACT1 0x0 +#define QM_SDQCR_COUNT_UPTO3 0x20000000 +#define QM_SDQCR_DEDICATED_PRECEDENCE 0x10000000 +#define QM_SDQCR_TYPE_MASK 0x03000000 +#define QM_SDQCR_TYPE_NULL 0x0 +#define QM_SDQCR_TYPE_PRIO_QOS 0x01000000 +#define QM_SDQCR_TYPE_ACTIVE_QOS 0x02000000 +#define QM_SDQCR_TYPE_ACTIVE 0x03000000 +#define QM_SDQCR_TOKEN_MASK 0x00ff0000 +#define QM_SDQCR_TOKEN_SET(v) (((v) & 0xff) << 16) +#define QM_SDQCR_TOKEN_GET(v) (((v) >> 16) & 0xff) +#define QM_SDQCR_CHANNELS_DEDICATED 0x00008000 +#if 0 /* These are defined in the external fsl_qman.h API */ +#define QM_SDQCR_CHANNELS_POOL_MASK 0x00007fff +#define QM_SDQCR_CHANNELS_POOL(n) (0x00008000 >> (n)) +#endif +#define QM_SDQCR_SPECIFICWQ_MASK 0x000000f7 +#define QM_SDQCR_SPECIFICWQ_DEDICATED 0x00000000 +#define QM_SDQCR_SPECIFICWQ_POOL(n) ((n) << 4) +#define QM_SDQCR_SPECIFICWQ_WQ(n) (n) + +/* For qm_dqrr_vdqcr_set(); Choose one PRECEDENCE. EXACT is optional. Use + * NUMFRAMES(n) (6-bit) or NUMFRAMES_TILLEMPTY to fill in the frame-count. Use + * FQID(n) to fill in the frame queue ID. */ +#if 0 /* These are defined in the external fsl_qman.h API */ +#define QM_VDQCR_PRECEDENCE_VDQCR 0x0 +#define QM_VDQCR_PRECEDENCE_SDQCR 0x80000000 +#define QM_VDQCR_EXACT 0x40000000 +#define QM_VDQCR_NUMFRAMES_MASK 0x3f000000 +#define QM_VDQCR_NUMFRAMES_SET(n) (((n) & 0x3f) << 24) +#define QM_VDQCR_NUMFRAMES_GET(n) (((n) >> 24) & 0x3f) +#define QM_VDQCR_NUMFRAMES_TILLEMPTY QM_VDQCR_NUMFRAMES_SET(0) +#endif +#define QM_VDQCR_FQID_MASK 0x00ffffff +#define QM_VDQCR_FQID(n) ((n) & QM_VDQCR_FQID_MASK) + +/* For qm_dqrr_pdqcr_set(); Choose one MODE. Choose one COUNT. + * If MODE==SCHEDULED + * Choose SCHEDULED_CHANNELS or SCHEDULED_SPECIFICWQ. Choose one dequeue TYPE. + * If CHANNELS, + * Choose CHANNELS_DEDICATED and/or CHANNELS_POOL() channels. + * You can choose DEDICATED_PRECEDENCE if the portal channel should have + * priority. + * If SPECIFICWQ, + * Either select the work-queue ID with SPECIFICWQ_WQ(), or select the + * channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the + * work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the + * same value. + * If MODE==UNSCHEDULED + * Choose FQID(). + */ +#define QM_PDQCR_MODE_SCHEDULED 0x0 +#define QM_PDQCR_MODE_UNSCHEDULED 0x80000000 +#define QM_PDQCR_SCHEDULED_CHANNELS 0x0 +#define QM_PDQCR_SCHEDULED_SPECIFICWQ 0x40000000 +#define QM_PDQCR_COUNT_EXACT1 0x0 +#define QM_PDQCR_COUNT_UPTO3 0x20000000 +#define QM_PDQCR_DEDICATED_PRECEDENCE 0x10000000 +#define QM_PDQCR_TYPE_MASK 0x03000000 +#define QM_PDQCR_TYPE_NULL 0x0 +#define QM_PDQCR_TYPE_PRIO_QOS 0x01000000 +#define QM_PDQCR_TYPE_ACTIVE_QOS 0x02000000 +#define QM_PDQCR_TYPE_ACTIVE 0x03000000 +#define QM_PDQCR_CHANNELS_DEDICATED 0x00008000 +#define QM_PDQCR_CHANNELS_POOL(n) (0x00008000 >> (n)) +#define QM_PDQCR_SPECIFICWQ_MASK 0x000000f7 +#define QM_PDQCR_SPECIFICWQ_DEDICATED 0x00000000 +#define QM_PDQCR_SPECIFICWQ_POOL(n) ((n) << 4) +#define QM_PDQCR_SPECIFICWQ_WQ(n) (n) +#define QM_PDQCR_FQID(n) ((n) & 0xffffff) + +/* Used by all portal interrupt registers except 'inhibit'. NB, some of these + * definitions are exported for use by the qman_irqsource_***() APIs, so are + * commented-out here. */ +#define QM_PIRQ_DQAVAIL 0x0000ffff /* Channels with frame availability */ +#if 0 +#define QM_PIRQ_CSCI 0x00100000 /* Congestion State Change */ +#define QM_PIRQ_EQCI 0x00080000 /* Enqueue Command Committed */ +#define QM_PIRQ_EQRI 0x00040000 /* EQCR Ring (below threshold) */ +#define QM_PIRQ_DQRI 0x00020000 /* DQRR Ring (non-empty) */ +#define QM_PIRQ_MRI 0x00010000 /* MR Ring (non-empty) */ +/* This mask contains all the interrupt sources that need handling except DQRI, + * ie. that if present should trigger slow-path processing. */ +#define QM_PIRQ_SLOW (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | \ + QM_PIRQ_MRI) +#endif +/* The DQAVAIL interrupt fields break down into these bits; */ +#define QM_DQAVAIL_PORTAL 0x8000 /* Portal channel */ +#define QM_DQAVAIL_POOL(n) (0x8000 >> (n)) /* Pool channel, n==[1..15] */ +#define QM_DQAVAIL_MASK 0xffff +/* This mask contains all the "irqsource" bits visible to API users */ +#define QM_PIRQ_VISIBLE (QM_PIRQ_SLOW | QM_PIRQ_DQRI) + +/* These are qm__(). So for example, qm_disable_write() means "write + * the disable register" rather than "disable the ability to write". */ +#define qm_isr_status_read(qm) __qm_isr_read(qm, qm_isr_status) +#define qm_isr_status_clear(qm, m) __qm_isr_write(qm, qm_isr_status, m) +#define qm_isr_enable_read(qm) __qm_isr_read(qm, qm_isr_enable) +#define qm_isr_enable_write(qm, v) __qm_isr_write(qm, qm_isr_enable, v) +#define qm_isr_disable_read(qm) __qm_isr_read(qm, qm_isr_disable) +#define qm_isr_disable_write(qm, v) __qm_isr_write(qm, qm_isr_disable, v) +/* TODO: unfortunate name-clash here, reword? */ +#define qm_isr_inhibit(qm) __qm_isr_write(qm, qm_isr_inhibit, 1) +#define qm_isr_uninhibit(qm) __qm_isr_write(qm, qm_isr_inhibit, 0) --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_test_errata.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_test_errata.c @@ -0,0 +1,248 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_test.h" + +/* Waiting on a model fix from virtutech */ +#if 0 +/*********************/ +/* generic utilities */ +/*********************/ + +static int do_enqueues(struct qman_fq *fq, const struct qm_fd *fds, int num) +{ + int ret = 0; + u32 flags = QMAN_ENQUEUE_FLAG_WAIT; + while (num-- && !ret) { + if (!num) + flags |= QMAN_ENQUEUE_FLAG_WAIT_SYNC; + pr_info("about to enqueue\n"); + ret = qman_enqueue(fq, fds++, flags); + } + return ret; +} + +/***************************/ +/* "tdthresh" test (QMAN6) */ +/***************************/ + +/* First thresh == 201 * (2^21) == 421527552 (0x19200000) */ +#define THRESH_MANT 201 +#define THRESH_EXP 21 + +/* first three equal thresh, fourth takes us over */ +static const struct qm_fd td_eq[] = { + QM_FD_FMT_20(0, 0x34, 0x87654321, QM_FD_SG, 0, 79321), + QM_FD_FMT_29(0, 0x34, 0x87654321, QM_FD_COMPOUND, 29923679), + QM_FD_FMT_29(0, 0x0d, 0xacadabba, QM_FD_CONTIG_BIG, 391524552), + QM_FD_FMT_20(0, 0x0b, 0x0fa10ada, QM_FD_CONTIG, 0, 1), + QM_FD_FMT_20(0, 0x0b, 0x0fa10ada, QM_FD_CONTIG, 0, 1), +}; + +struct tdthresh_fq { + struct qman_fq fq; + int got_ern; + int num_dqrr; +}; + +static enum qman_cb_dqrr_result cb_dqrr_tdthresh(struct qman_portal *p, + struct qman_fq *__fq, + const struct qm_dqrr_entry *dqrr) +{ + struct tdthresh_fq *t = (void *)__fq; + t->num_dqrr++; + return qman_cb_dqrr_consume; +} + +static void cb_ern_tdthresh(struct qman_portal *p, struct qman_fq *__fq, + const struct qm_mr_entry *mr) +{ + struct tdthresh_fq *t = (void *)__fq; + t->got_ern = 1; +} + +static void test_tdthresh(void) +{ + struct tdthresh_fq tdfq = { + .fq = { + .cb = { + .dqrr = cb_dqrr_tdthresh, + .ern = cb_ern_tdthresh + } + }, + .got_ern = 0, + .num_dqrr = 0 + }; + struct qman_fq *fq = &tdfq.fq; + struct qm_mcc_initfq opts = { + .we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_TDTHRESH, + .fqd = { + .fq_ctrl = QM_FQCTRL_TDE, + .td = { + .exp = THRESH_EXP, + .mant = THRESH_MANT, + } + } + }; + struct qm_fqd fqd; + u32 flags; + int ret = qman_create_fq(0, QMAN_FQ_FLAG_DYNAMIC_FQID, fq); + BUG_ON(ret); + /* leave it parked, and set it for local dequeue (loopback) */ + ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, &opts); + BUG_ON(ret); + /* query it back and confirm everything is ok */ + ret = qman_query_fq(fq, &fqd); + BUG_ON(ret); + if (fqd.fq_ctrl != opts.fqd.fq_ctrl) { + pr_err("queried fq_ctrl=%x, should be=%x\n", fqd.fq_ctrl, + opts.fqd.fq_ctrl); + panic("fail"); + } + if (memcmp(&fqd.td, &opts.fqd.td, sizeof(fqd.td))) { + pr_err("queried td_thresh=%x:%x, should be=%x:%x\n", + fqd.td.exp, fqd.td.mant, + opts.fqd.td.exp, opts.fqd.td.mant); + panic("fail"); + } + ret = do_enqueues(fq, td_eq, 3); + BUG_ON(ret); + pr_info(" tdthresh: eq[0..2] complete\n"); + /* enqueues are flushed, so if Qman is going to throw an ERN, the irq + * assertion will already be on its way. */ + msleep(500); + BUG_ON(tdfq.got_ern); + pr_info(" tdthresh: eq <= thresh OK\n"); + ret = do_enqueues(fq, td_eq + 3, 1); + BUG_ON(ret); + pr_info(" tdthresh: eq[3] complete\n"); + /* enqueues are flushed, so if Qman is going to throw an ERN, the irq + * assertion will already be on its way. */ + msleep(500); + BUG_ON(tdfq.got_ern); + pr_info(" tdthresh: eq <= thresh OK\n"); + ret = do_enqueues(fq, td_eq + 4, 1); + BUG_ON(ret); + pr_info(" tdthresh: eq[4] complete\n"); + /* enqueues are flushed, so if Qman is going to throw an ERN, the irq + * assertion will already be on its way. */ + msleep(500); + BUG_ON(!tdfq.got_ern); + pr_info(" tdthresh: eq > thresh OK\n"); + ret = qman_volatile_dequeue(fq, + QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH, + QM_VDQCR_NUMFRAMES_TILLEMPTY); + BUG_ON(ret); + BUG_ON(tdfq.num_dqrr != 4); + ret = qman_retire_fq(fq, &flags); + BUG_ON(ret); + BUG_ON(flags); + ret = qman_oos_fq(fq); + BUG_ON(ret); +} + +/****************************/ +/* "ern code6" test (QMAN9) */ +/****************************/ + +/* Dummy FD to enqueue out-of-sequence and generate an ERN */ +static const struct qm_fd c6_eq = + QM_FD_FMT_29(0, 0xba, 0xdeadbeef, QM_FD_CONTIG_BIG, 1234); + +struct code6_fq { + struct qman_fq fq; + struct qm_mr_entry mr; + struct completion got_ern; +}; + +static void cb_ern_code6(struct qman_portal *p, struct qman_fq *__fq, + const struct qm_mr_entry *mr) +{ + struct code6_fq *c = (void *)__fq; + memcpy(&c->mr, mr, sizeof(*mr)); + complete(&c->got_ern); +} + +static void test_ern_code6(void) +{ + struct code6_fq c6fq = { + .fq = { + .cb = { + .ern = cb_ern_code6 + } + }, + .got_ern = COMPLETION_INITIALIZER(c6fq.got_ern) + }; + struct qman_fq *fq = &c6fq.fq; + struct qm_mcc_initfq opts = { + .we_mask = QM_INITFQ_WE_FQCTRL, + .fqd = { + .fq_ctrl = QM_FQCTRL_ORP + } + }; + u32 flags; + int ret = qman_create_fq(0, QMAN_FQ_FLAG_DYNAMIC_FQID, fq); + BUG_ON(ret); + /* leave it parked, and set it for local dequeue (loopback) */ + ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, &opts); + BUG_ON(ret); + /* enqueue with ORP using a "too early" sequence number */ + ret = qman_enqueue_orp(fq, &c6_eq, + QMAN_ENQUEUE_FLAG_WAIT | QMAN_ENQUEUE_FLAG_WAIT_SYNC, fq, 5); + BUG_ON(ret); + pr_info(" code6: eq complete\n"); + ret = qman_retire_fq(fq, &flags); + BUG_ON(ret); + pr_info(" code6: retire complete, flags=%08x\n", flags); + BUG_ON(flags != QMAN_FQ_STATE_ORL); + wait_for_completion(&c6fq.got_ern); + pr_info(" code6: ERN, VERB=0x%02x, RC==0x%02x\n", + c6fq.mr.verb, c6fq.mr.ern.rc); + BUG_ON(c6fq.mr.verb & 0x20); + BUG_ON((c6fq.mr.ern.rc & QM_MR_RC_MASK) != QM_MR_RC_ORPWINDOW_RETIRED); + ret = qman_oos_fq(fq); + BUG_ON(ret); +} + +void qman_test_errata(void) +{ + pr_info("Testing Qman errata handling ...\n"); + test_tdthresh(); + test_ern_code6(); + pr_info(" ... SUCCESS!\n"); +} +#else +void qman_test_errata(void) +{ + pr_info("Qman errata-handling test disabled, waiting on model fix\n"); +} +#endif + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_utility.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_utility.c @@ -0,0 +1,131 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_private.h" + +/* ----------------- */ +/* --- FQID Pool --- */ + +struct qman_fqid_pool { + /* Base and size of the FQID range */ + u32 fqid_base; + u32 total; + /* Number of FQIDs currently "allocated" */ + u32 used; + /* Allocation optimisation. When 'usedfqid_base = fqid_start; + pool->total = num; + pool->used = 0; + pool->next = 0; + pool->bits = kmalloc(QNUM_BYTES(num), GFP_KERNEL); + if (!pool->bits) { + kfree(pool); + return NULL; + } + memset(pool->bits, 0, QNUM_BYTES(num)); + /* If num is not an even multiple of QLONG_BITS (or even 8, for + * byte-oriented searching) then we fill the trailing bits with 1, to + * make them look allocated (permanently). */ + for (i = num + 1; i < QNUM_BITS(num); i++) + set_bit(i, pool->bits); + return pool; +} +EXPORT_SYMBOL(qman_fqid_pool_create); + +int qman_fqid_pool_destroy(struct qman_fqid_pool *pool) +{ + int ret = pool->used; + kfree(pool->bits); + kfree(pool); + return ret; +} +EXPORT_SYMBOL(qman_fqid_pool_destroy); + +int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid) +{ + int ret; + if (pool->used == pool->total) + return -ENOMEM; + *fqid = pool->fqid_base + pool->next; + ret = test_and_set_bit(pool->next, pool->bits); + BUG_ON(ret); + if (++pool->used == pool->total) + return 0; + pool->next = find_next_zero_bit(pool->bits, pool->total, pool->next); + if (pool->next >= pool->total) + pool->next = find_first_zero_bit(pool->bits, pool->total); + BUG_ON(pool->next >= pool->total); + return 0; +} +EXPORT_SYMBOL(qman_fqid_pool_alloc); + +void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid) +{ + int ret; + + fqid -= pool->fqid_base; + ret = test_and_clear_bit(fqid, pool->bits); + BUG_ON(!ret); + if (pool->used-- == pool->total) + pool->next = fqid; +} +EXPORT_SYMBOL(qman_fqid_pool_free); + +u32 qman_fqid_pool_used(struct qman_fqid_pool *pool) +{ + return pool->used; +} +EXPORT_SYMBOL(qman_fqid_pool_used); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/dpa_uio.c +++ linux-3.13.0/drivers/staging/fsl_qbman/dpa_uio.c @@ -0,0 +1,231 @@ +/* Copyright 2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_private.h" +#include "qman_private.h" + +static const char dpa_uio_version[] = "USDPAA UIO portal driver v0.2"; + +static LIST_HEAD(uio_portal_list); + +struct dpa_uio_info { + atomic_t ref; /* exclusive, only one open() at a time */ + struct uio_info uio; + void *addr_ci; + char name[16]; /* big enough for "qman-uio-xx" */ + struct platform_device *pdev; + struct list_head node; +}; + +static int dpa_uio_open(struct uio_info *info, struct inode *inode) +{ + struct dpa_uio_info *i = container_of(info, struct dpa_uio_info, uio); + if (!atomic_dec_and_test(&i->ref)) { + atomic_inc(&i->ref); + return -EBUSY; + } + return 0; +} + +static int dpa_uio_release(struct uio_info *info, struct inode *inode) +{ + struct dpa_uio_info *i = container_of(info, struct dpa_uio_info, uio); + atomic_inc(&i->ref); + return 0; +} + +static int dpa_uio_mmap(struct uio_info *info, struct vm_area_struct *vma) +{ + struct uio_mem *mem; + struct dpa_uio_info *i = container_of(info, struct dpa_uio_info, uio); + + if (vma->vm_pgoff == 0) { + /* CENA */ + mem = &i->uio.mem[0]; + vma->vm_page_prot &= + ~(_PAGE_GUARDED | _PAGE_NO_CACHE | _PAGE_COHERENT); + } else if (vma->vm_pgoff == 1) { + /* CINH */ + mem = &i->uio.mem[1]; + vma->vm_page_prot |= _PAGE_GUARDED | _PAGE_NO_CACHE; + } else { + pr_err("%s: unknown mmap offset %d, rejecting\n", + i->name, (int)vma->vm_pgoff); + return -EINVAL; + } + if ((vma->vm_end - vma->vm_start) != mem->size) { + pr_err("%s: invalid mmap() size %d, expect %d\n", + i->name, (int)(vma->vm_end - vma->vm_start), + (int)mem->size); + return -EINVAL; + } + /* FIXME: UIO appears not to support sizeof(phys_addr_t) > sizeof(void*) + * as mem->addr is 32-bit. Also, it would have been more natural (and in + * keeping with UIO's design intent) to have used the UIO_MEM_PHYS type + * for our two memory regions, and to rely on UIO's own mmap() handler + * (by not declaring our own). Unfortunately UIO does not allow any + * specification of pgprots and assumes cache-inhibited mappings for + * anything physical (see drivers/uio/uio.c, eg. uio_mmap_physical()). + * So UIO could use a couple of improvements as it is not saving us much + * on the kernel nor the user side. The first would be to use PFN + * instead of a raw base address in the uio_mem structs (same reason as + * everywhere else, this covers 4096 times as much address space, and + * why waste lower bits given it has to be page-aligned anyway?). The + * second is to add a pgprot field to uio_mem to be used with _PHYS + * mappings. (Or use a new _PHYS_PGPROT type, for backwards + * compatibility?) */ + /* Normally, we'd ">>PAGE_SHIFT" the mem->addr value here, but due to + * the 36-bit issue, it is already stored as a PFN. */ + return io_remap_pfn_range(vma, vma->vm_start, mem->addr, mem->size, + vma->vm_page_prot); +} + +static irqreturn_t dpa_uio_irq_handler(int irq, struct uio_info *info) +{ + struct dpa_uio_info *i = container_of(info, struct dpa_uio_info, uio); + /* This is the only code outside the regular portal driver that + * manipulates any portal register, so rather than breaking that + * encapsulation I am simply hard-coding the offset to the inhibit + * register here. */ + out_be32(i->addr_ci + 0xe0c, ~(u32)0); + return IRQ_HANDLED; +} + +static void __init dpa_uio_portal_init(struct dpa_uio_portal *p, + const struct dpa_uio_class *c) +{ + struct dpa_uio_info *info; + const struct resource *res; + u32 index; + int irq, ret; + + /* allocate 'info' */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return; + atomic_set(&info->ref, 1); + if (p->type == dpa_uio_portal_bman) { + res = &p->bm_cfg->addr_phys[0]; + index = p->bm_cfg->public_cfg.index; + irq = p->bm_cfg->public_cfg.irq; + } else { + res = &p->qm_cfg->addr_phys[0]; + index = p->qm_cfg->public_cfg.index; + irq = p->qm_cfg->public_cfg.irq; + } + /* We need to map the cache-inhibited region in the kernel for + * interrupt-handling purposes. */ + info->addr_ci = ioremap_prot(res[BM_ADDR_CI].start, + resource_size(&res[BM_ADDR_CI]), + _PAGE_GUARDED | _PAGE_NO_CACHE); + /* Name the UIO device according to the cell-index. It's supposed to be + * unique for each device class (Qman/Bman), and is also a convenient + * way for user-space to find the UIO device that corresponds to a given + * portal device-tree node. */ + sprintf(info->name, "%s%x", c->dev_prefix, index); + info->pdev = platform_device_alloc(info->name, -1); + if (!info->pdev) { + iounmap(info->addr_ci); + kfree(info); + pr_err("dpa_uio_portal: platform_device_alloc() failed\n"); + return; + } + ret = platform_device_add(info->pdev); + if (ret) { + platform_device_put(info->pdev); + iounmap(info->addr_ci); + kfree(info); + pr_err("dpa_uio_portal: platform_device_add() failed\n"); + return; + } + info->uio.name = info->name; + info->uio.version = dpa_uio_version; + /* Work around the 36-bit UIO issue by bit-shifting the addresses */ + info->uio.mem[BM_ADDR_CE].name = "cena"; + info->uio.mem[BM_ADDR_CE].addr = res[BM_ADDR_CE].start >> PAGE_SHIFT; + info->uio.mem[BM_ADDR_CE].size = resource_size(&res[BM_ADDR_CE]); + info->uio.mem[BM_ADDR_CI].name = "cinh"; + info->uio.mem[BM_ADDR_CI].addr = res[BM_ADDR_CI].start >> PAGE_SHIFT; + info->uio.mem[BM_ADDR_CI].size = resource_size(&res[BM_ADDR_CI]); + info->uio.irq = irq; + info->uio.handler = dpa_uio_irq_handler; + info->uio.mmap = dpa_uio_mmap; + info->uio.open = dpa_uio_open; + info->uio.release = dpa_uio_release; + ret = uio_register_device(&info->pdev->dev, &info->uio); + if (ret) { + platform_device_del(info->pdev); + platform_device_put(info->pdev); + iounmap(info->addr_ci); + kfree(info); + pr_err("dpa_uio_portal: UIO registration failed\n"); + return; + } + list_add_tail(&info->node, &uio_portal_list); + pr_info("USDPAA portal initialised, %s\n", info->name); +} + +static int __init dpa_uio_init(void) +{ + const struct dpa_uio_class *classes[3], **c = classes; + classes[0] = dpa_uio_bman(); + classes[1] = dpa_uio_qman(); + classes[2] = NULL; + while (*c) { + struct dpa_uio_portal *p; + list_for_each_entry(p, &(*c)->list, node) + dpa_uio_portal_init(p, *c); + c++; + } + pr_info("USDPAA portal layer loaded\n"); + return 0; +} + +static void __exit dpa_uio_exit(void) +{ + struct dpa_uio_info *info, *tmp; + list_for_each_entry_safe(info, tmp, &uio_portal_list, node) { + list_del(&info->node); + uio_unregister_device(&info->uio); + platform_device_del(info->pdev); + platform_device_put(info->pdev); + iounmap(info->addr_ci); + pr_info("USDPAA portal removed, %s\n", info->name); + kfree(info); + } + pr_info("USDPAA portal layer unloaded\n"); +} + + +module_init(dpa_uio_init) +module_exit(dpa_uio_exit) +MODULE_LICENSE("GPL"); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_test.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_test.c @@ -0,0 +1,61 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_test.h" + +MODULE_AUTHOR("Geoff Thorpe"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Qman testing"); + +static int test_init(void) +{ + int loop = 1; + while(loop--) { +#ifdef CONFIG_FSL_QMAN_TEST_STASH_POTATO + qman_test_hotpotato(); +#endif +#ifdef CONFIG_FSL_QMAN_TEST_HIGH + qman_test_high(); +#endif +#ifdef CONFIG_FSL_QMAN_TEST_ERRATA + qman_test_errata(); +#endif + } + return 0; +} + +static void test_exit(void) +{ +} + +module_init(test_init); +module_exit(test_exit); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_debugfs.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_debugfs.c @@ -0,0 +1,1314 @@ +/* Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "qman_private.h" + +#define MAX_FQID (0x00ffffff) +#define QM_FQD_BLOCK_SIZE 64 +#define QM_FQD_AR (0xC10) + +static u32 fqid_max; +static u64 qman_ccsr_start; +static u64 qman_ccsr_size; + +static const char *state_txt[] = { + "Out of Service", + "Retired", + "Tentatively Scheduled", + "Truly Scheduled", + "Parked", + "Active, Active Held or Held Suspended", + "Unknown State 6", + "Unknown State 7", + NULL, +}; + +static const u8 fqd_states[] = { + QM_MCR_NP_STATE_OOS, QM_MCR_NP_STATE_RETIRED, QM_MCR_NP_STATE_TEN_SCHED, + QM_MCR_NP_STATE_TRU_SCHED, QM_MCR_NP_STATE_PARKED, + QM_MCR_NP_STATE_ACTIVE}; +static const u32 fqd_states_count = sizeof(fqd_states)/sizeof(u8); + +struct mask_to_text { + u16 mask; + const char *txt; +}; + +struct mask_filter_s { + u16 mask; + u8 filter; +}; + +static const struct mask_filter_s mask_filter[] = { + {QM_FQCTRL_PREFERINCACHE, 0}, + {QM_FQCTRL_PREFERINCACHE, 1}, + {QM_FQCTRL_HOLDACTIVE, 0}, + {QM_FQCTRL_HOLDACTIVE, 1}, + {QM_FQCTRL_AVOIDBLOCK, 0}, + {QM_FQCTRL_AVOIDBLOCK, 1}, + {QM_FQCTRL_FORCESFDR, 0}, + {QM_FQCTRL_FORCESFDR, 1}, + {QM_FQCTRL_CPCSTASH, 0}, + {QM_FQCTRL_CPCSTASH, 1}, + {QM_FQCTRL_CTXASTASHING, 0}, + {QM_FQCTRL_CTXASTASHING, 1}, + {QM_FQCTRL_ORP, 0}, + {QM_FQCTRL_ORP, 1}, + {QM_FQCTRL_TDE, 0}, + {QM_FQCTRL_TDE, 1}, + {QM_FQCTRL_CGE, 0}, + {QM_FQCTRL_CGE, 1} +}; +static const u32 mask_filter_count = + sizeof(mask_filter)/sizeof(struct mask_filter_s); + +static const struct mask_to_text fq_ctrl_text_list[] = { + { + .mask = QM_FQCTRL_PREFERINCACHE, + .txt = "Prefer in cache", + }, + { + .mask = QM_FQCTRL_HOLDACTIVE, + .txt = "Hold active in portal", + }, + { + .mask = QM_FQCTRL_AVOIDBLOCK, + .txt = "Avoid Blocking", + }, + { + .mask = QM_FQCTRL_FORCESFDR, + .txt = "High-priority SFDRs", + }, + { + .mask = QM_FQCTRL_CPCSTASH, + .txt = "CPC Stash Enable", + }, + { + .mask = QM_FQCTRL_CTXASTASHING, + .txt = "Context-A stashing", + }, + { + .mask = QM_FQCTRL_ORP, + .txt = "ORP Enable", + }, + { + .mask = QM_FQCTRL_TDE, + .txt = "Tail-Drop Enable", + }, + { + .mask = QM_FQCTRL_CGE, + .txt = "Congestion Group Enable", + }, + { + .mask = 0, + .txt = NULL, + } +}; + +static const char *get_fqd_ctrl_text(u16 mask) +{ + int i = 0; + + while (fq_ctrl_text_list[i].txt != NULL) { + if (fq_ctrl_text_list[i].mask == mask) + return fq_ctrl_text_list[i].txt; + i++; + } + return NULL; +} + +static const struct mask_to_text stashing_text_list[] = { + { + .mask = QM_STASHING_EXCL_CTX, + .txt = "FQ Ctx Stash" + }, + { + .mask = QM_STASHING_EXCL_DATA, + .txt = "Frame Data Stash", + }, + { + .mask = QM_STASHING_EXCL_ANNOTATION, + .txt = "Frame Annotation Stash", + }, + { + .mask = 0, + .txt = NULL, + }, +}; + +static int user_input_convert(const char __user *user_buf, size_t count, + unsigned long *val) +{ + char buf[12]; + + if (count > sizeof(buf) - 1) + return -EINVAL; + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + buf[count] = '\0'; + if (strict_strtoul(buf, 0, val)) + return -EINVAL; + return 0; +} + +struct line_buffer_fq { + u32 buf[8]; + u32 buf_cnt; + int line_cnt; +}; + +static void add_to_line_buffer(struct line_buffer_fq *line_buf, u32 fqid, + struct seq_file *file) +{ + line_buf->buf[line_buf->buf_cnt] = fqid; + line_buf->buf_cnt++; + if (line_buf->buf_cnt == 8) { + /* Buffer is full, flush it */ + if (line_buf->line_cnt != 0) + seq_printf(file, ",\n"); + seq_printf(file, "0x%06x,0x%06x,0x%06x,0x%06x,0x%06x," + "0x%06x,0x%06x,0x%06x", + line_buf->buf[0], line_buf->buf[1], line_buf->buf[2], + line_buf->buf[3], line_buf->buf[4], line_buf->buf[5], + line_buf->buf[6], line_buf->buf[7]); + line_buf->buf_cnt = 0; + line_buf->line_cnt++; + } +} + +static void flush_line_buffer(struct line_buffer_fq *line_buf, + struct seq_file *file) +{ + if (line_buf->buf_cnt) { + int y = 0; + if (line_buf->line_cnt != 0) + seq_printf(file, ",\n"); + while (y != line_buf->buf_cnt) { + if (y+1 == line_buf->buf_cnt) + seq_printf(file, "0x%06x", line_buf->buf[y]); + else + seq_printf(file, "0x%06x,", line_buf->buf[y]); + y++; + } + line_buf->line_cnt++; + } + if (line_buf->line_cnt) + seq_printf(file, "\n"); +} + +static struct dentry *dfs_root; /* debugfs root directory */ + +/******************************************************************************* + * Query Frame Queue Non Programmable Fields + ******************************************************************************/ +struct query_fq_np_fields_data_s { + u32 fqid; +}; +static struct query_fq_np_fields_data_s query_fq_np_fields_data = { + .fqid = 1, +}; + +static int query_fq_np_fields_show(struct seq_file *file, void *offset) +{ + int ret; + struct qm_mcr_queryfq_np np; + struct qman_fq fq; + + fq.fqid = query_fq_np_fields_data.fqid; + ret = qman_query_fq_np(&fq, &np); + if (ret) + return ret; + /* Print state */ + seq_printf(file, "Query FQ Non Programmable Fields Result fqid 0x%x\n", + fq.fqid); + seq_printf(file, " force eligible pending: %s\n", + (np.state & QM_MCR_NP_STATE_FE) ? "yes" : "no"); + seq_printf(file, " retirement pending: %s\n", + (np.state & QM_MCR_NP_STATE_R) ? "yes" : "no"); + seq_printf(file, " state: %s\n", + state_txt[np.state & QM_MCR_NP_STATE_MASK]); + seq_printf(file, " fq_link: 0x%x\n", np.fqd_link); + seq_printf(file, " odp_seq: %u\n", np.odp_seq); + seq_printf(file, " orp_nesn: %u\n", np.orp_nesn); + seq_printf(file, " orp_ea_hseq: %u\n", np.orp_ea_hseq); + seq_printf(file, " orp_ea_tseq: %u\n", np.orp_ea_tseq); + seq_printf(file, " orp_ea_hptr: 0x%x\n", np.orp_ea_hptr); + seq_printf(file, " orp_ea_tptr: 0x%x\n", np.orp_ea_tptr); + seq_printf(file, " pfdr_hptr: 0x%x\n", np.pfdr_hptr); + seq_printf(file, " pfdr_tptr: 0x%x\n", np.pfdr_tptr); + seq_printf(file, " is: ics_surp contains a %s\n", + (np.is) ? "deficit" : "surplus"); + seq_printf(file, " ics_surp: %u\n", np.ics_surp); + seq_printf(file, " byte_cnt: %u\n", np.byte_cnt); + seq_printf(file, " frm_cnt: %u\n", np.frm_cnt); + seq_printf(file, " ra1_sfdr: 0x%x\n", np.ra1_sfdr); + seq_printf(file, " ra2_sfdr: 0x%x\n", np.ra2_sfdr); + seq_printf(file, " od1_sfdr: 0x%x\n", np.od1_sfdr); + seq_printf(file, " od2_sfdr: 0x%x\n", np.od2_sfdr); + seq_printf(file, " od3_sfdr: 0x%x\n", np.od3_sfdr); + return 0; +} + +static int query_fq_np_fields_open(struct inode *inode, + struct file *file) +{ + return single_open(file, query_fq_np_fields_show, NULL); +} + +static ssize_t query_fq_np_fields_write(struct file *f, + const char __user *buf, size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + if (val > MAX_FQID) + return -EINVAL; + query_fq_np_fields_data.fqid = (u32)val; + return count; +} + +static const struct file_operations query_fq_np_fields_fops = { + .owner = THIS_MODULE, + .open = query_fq_np_fields_open, + .read = seq_read, + .write = query_fq_np_fields_write, + .release = single_release, +}; + +/******************************************************************************* + * Frame Queue Programmable Fields + ******************************************************************************/ +struct query_fq_fields_data_s { + u32 fqid; +}; + +static struct query_fq_fields_data_s query_fq_fields_data = { + .fqid = 1, +}; + +static int query_fq_fields_show(struct seq_file *file, void *offset) +{ + int ret; + struct qm_fqd fqd; + struct qman_fq fq; + int i = 0; + + memset(&fqd, 0, sizeof(struct qm_fqd)); + fq.fqid = query_fq_fields_data.fqid; + ret = qman_query_fq(&fq, &fqd); + if (ret) + return ret; + seq_printf(file, "Query FQ Programmable Fields Result fqid 0x%x\n", + fq.fqid); + seq_printf(file, " orprws: %u\n", fqd.orprws); + seq_printf(file, " oa: %u\n", fqd.oa); + seq_printf(file, " olws: %u\n", fqd.olws); + + seq_printf(file, " cgid: %u\n", fqd.cgid); + + if ((fqd.fq_ctrl & QM_FQCTRL_MASK) == 0) + seq_printf(file, " fq_ctrl: None\n"); + else { + i = 0; + seq_printf(file, " fq_ctrl:\n"); + while (fq_ctrl_text_list[i].txt != NULL) { + if ((fqd.fq_ctrl & QM_FQCTRL_MASK) & + fq_ctrl_text_list[i].mask) + seq_printf(file, " %s\n", + fq_ctrl_text_list[i].txt); + i++; + } + } + seq_printf(file, " dest_channel: %u\n", fqd.dest.channel); + seq_printf(file, " dest_wq: %u\n", fqd.dest.wq); + seq_printf(file, " ics_cred: %u\n", fqd.ics_cred); + seq_printf(file, " td_mant: %u\n", fqd.td.mant); + seq_printf(file, " td_exp: %u\n", fqd.td.exp); + + seq_printf(file, " ctx_b: 0x%x\n", fqd.context_b); + + seq_printf(file, " ctx_a: 0x%llx\n", qm_fqd_stashing_get64(&fqd)); + /* Any stashing configured */ + if ((fqd.context_a.stashing.exclusive & 0x7) == 0) + seq_printf(file, " ctx_a_stash_exclusive: None\n"); + else { + seq_printf(file, " ctx_a_stash_exclusive:\n"); + i = 0; + while (stashing_text_list[i].txt != NULL) { + if ((fqd.fq_ctrl & 0x7) & stashing_text_list[i].mask) + seq_printf(file, " %s\n", + stashing_text_list[i].txt); + i++; + } + } + seq_printf(file, " ctx_a_stash_annotation_cl: %u\n", + fqd.context_a.stashing.annotation_cl); + seq_printf(file, " ctx_a_stash_data_cl: %u\n", + fqd.context_a.stashing.data_cl); + seq_printf(file, " ctx_a_stash_context_cl: %u\n", + fqd.context_a.stashing.context_cl); + return 0; +} + +static int query_fq_fields_open(struct inode *inode, + struct file *file) +{ + return single_open(file, query_fq_fields_show, NULL); +} + +static ssize_t query_fq_fields_write(struct file *f, + const char __user *buf, size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + if (val > MAX_FQID) + return -EINVAL; + query_fq_fields_data.fqid = (u32)val; + return count; +} + +static const struct file_operations query_fq_fields_fops = { + .owner = THIS_MODULE, + .open = query_fq_fields_open, + .read = seq_read, + .write = query_fq_fields_write, + .release = single_release, +}; + +/******************************************************************************* + * Query WQ lengths + ******************************************************************************/ +struct query_wq_lengths_data_s { + union { + u16 channel_wq; /* ignores wq (3 lsbits) */ + struct { + u16 id:13; /* enum qm_channel */ + u16 __reserved:3; + } __packed channel; + }; +}; +static struct query_wq_lengths_data_s query_wq_lengths_data; +static int query_wq_lengths_show(struct seq_file *file, void *offset) +{ + int ret; + struct qm_mcr_querywq wq; + int i; + + memset(&wq, 0, sizeof(struct qm_mcr_querywq)); + wq.channel.id = query_wq_lengths_data.channel.id; + ret = qman_query_wq(0, &wq); + if (ret) + return ret; + seq_printf(file, "Query Result For Channel: 0x%x\n", wq.channel.id); + for (i = 0; i < 8; i++) + /* mask out upper 4 bits since they are not part of length */ + seq_printf(file, " wq%d_len : %u\n", i, wq.wq_len[i] & 0x0fff); + return 0; +} + +static int query_wq_lengths_open(struct inode *inode, + struct file *file) +{ + return single_open(file, query_wq_lengths_show, NULL); +} + +static ssize_t query_wq_lengths_write(struct file *f, + const char __user *buf, size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + if (val > 0xfff8) + return -EINVAL; + query_wq_lengths_data.channel.id = (u16)val; + return count; +} + +static const struct file_operations query_wq_lengths_fops = { + .owner = THIS_MODULE, + .open = query_wq_lengths_open, + .read = seq_read, + .write = query_wq_lengths_write, + .release = single_release, +}; + +/******************************************************************************* + * Query CGR + ******************************************************************************/ +struct query_cgr_s { + u8 cgid; +}; +static struct query_cgr_s query_cgr_data; + +static int query_cgr_show(struct seq_file *file, void *offset) +{ + int ret; + struct qm_mcr_querycgr cgrd; + struct qman_cgr cgr; + + memset(&cgr, 0, sizeof(struct qm_mcr_querycgr)); + cgr.cgrid = query_cgr_data.cgid; + ret = qman_query_cgr(&cgr, &cgrd); + if (ret) + return ret; + seq_printf(file, "Query CGR id 0x%x\n", cgr.cgrid); + seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", + cgrd.cgr.wr_parm_g.MA, cgrd.cgr.wr_parm_g.Mn, + cgrd.cgr.wr_parm_g.SA, cgrd.cgr.wr_parm_g.Sn, + cgrd.cgr.wr_parm_g.Pn); + + seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", + cgrd.cgr.wr_parm_y.MA, cgrd.cgr.wr_parm_y.Mn, + cgrd.cgr.wr_parm_y.SA, cgrd.cgr.wr_parm_y.Sn, + cgrd.cgr.wr_parm_y.Pn); + + seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", + cgrd.cgr.wr_parm_r.MA, cgrd.cgr.wr_parm_r.Mn, + cgrd.cgr.wr_parm_r.SA, cgrd.cgr.wr_parm_r.Sn, + cgrd.cgr.wr_parm_r.Pn); + + seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n", + cgrd.cgr.wr_en_g, cgrd.cgr.wr_en_y, cgrd.cgr.wr_en_r); + + seq_printf(file, " cscn_en: %u\n", cgrd.cgr.cscn_en); + seq_printf(file, " cscn_targ: %u\n", cgrd.cgr.cscn_targ); + seq_printf(file, " cstd_en: %u\n", cgrd.cgr.cstd_en); + seq_printf(file, " cs: %u\n", cgrd.cgr.cs); + + seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n", + cgrd.cgr.cs_thres.TA, cgrd.cgr.cs_thres.Tn); + + if (qman_ip_rev != QMAN_REV10) { + seq_printf(file, " mode: %s\n", + (cgrd.cgr.mode & QMAN_CGR_MODE_FRAME) ? + "frame count" : "byte count"); + } + seq_printf(file, " i_bcnt: %llu\n", qm_mcr_querycgr_i_get64(&cgrd)); + seq_printf(file, " a_bcnt: %llu\n", qm_mcr_querycgr_a_get64(&cgrd)); + + return 0; +} + +static int query_cgr_open(struct inode *inode, struct file *file) +{ + return single_open(file, query_cgr_show, NULL); +} + +static ssize_t query_cgr_write(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + if (val > 0xff) + return -EINVAL; + query_cgr_data.cgid = (u8)val; + return count; +} + +static const struct file_operations query_cgr_fops = { + .owner = THIS_MODULE, + .open = query_cgr_open, + .read = seq_read, + .write = query_cgr_write, + .release = single_release, +}; + +/******************************************************************************* + * Test Write CGR + ******************************************************************************/ +struct test_write_cgr_s { + u64 i_bcnt; + u8 cgid; +}; +static struct test_write_cgr_s test_write_cgr_data; + +static int testwrite_cgr_show(struct seq_file *file, void *offset) +{ + int ret; + struct qm_mcr_cgrtestwrite result; + struct qman_cgr cgr; + u64 i_bcnt; + + memset(&cgr, 0, sizeof(struct qman_cgr)); + memset(&result, 0, sizeof(struct qm_mcr_cgrtestwrite)); + cgr.cgrid = test_write_cgr_data.cgid; + i_bcnt = test_write_cgr_data.i_bcnt; + ret = qman_testwrite_cgr(&cgr, i_bcnt, &result); + if (ret) + return ret; + seq_printf(file, "CGR Test Write CGR id 0x%x\n", cgr.cgrid); + seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", + result.cgr.wr_parm_g.MA, result.cgr.wr_parm_g.Mn, + result.cgr.wr_parm_g.SA, result.cgr.wr_parm_g.Sn, + result.cgr.wr_parm_g.Pn); + seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", + result.cgr.wr_parm_y.MA, result.cgr.wr_parm_y.Mn, + result.cgr.wr_parm_y.SA, result.cgr.wr_parm_y.Sn, + result.cgr.wr_parm_y.Pn); + seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", + result.cgr.wr_parm_r.MA, result.cgr.wr_parm_r.Mn, + result.cgr.wr_parm_r.SA, result.cgr.wr_parm_r.Sn, + result.cgr.wr_parm_r.Pn); + seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n", + result.cgr.wr_en_g, result.cgr.wr_en_y, result.cgr.wr_en_r); + seq_printf(file, " cscn_en: %u\n", result.cgr.cscn_en); + seq_printf(file, " cscn_targ: %u\n", result.cgr.cscn_targ); + seq_printf(file, " cstd_en: %u\n", result.cgr.cstd_en); + seq_printf(file, " cs: %u\n", result.cgr.cs); + seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n", + result.cgr.cs_thres.TA, result.cgr.cs_thres.Tn); + + /* Add Mode for Si 2 */ + if (qman_ip_rev != QMAN_REV10) { + seq_printf(file, " mode: %s\n", + (result.cgr.mode & QMAN_CGR_MODE_FRAME) ? + "frame count" : "byte count"); + } + + seq_printf(file, " i_bcnt: %llu\n", + qm_mcr_cgrtestwrite_i_get64(&result)); + seq_printf(file, " a_bcnt: %llu\n", + qm_mcr_cgrtestwrite_a_get64(&result)); + seq_printf(file, " wr_prob_g: %u\n", result.wr_prob_g); + seq_printf(file, " wr_prob_y: %u\n", result.wr_prob_y); + seq_printf(file, " wr_prob_r: %u\n", result.wr_prob_r); + return 0; +} + +static int testwrite_cgr_open(struct inode *inode, struct file *file) +{ + return single_open(file, testwrite_cgr_show, NULL); +} + +static const struct file_operations testwrite_cgr_fops = { + .owner = THIS_MODULE, + .open = testwrite_cgr_open, + .read = seq_read, + .release = single_release, +}; + + +static int testwrite_cgr_ibcnt_show(struct seq_file *file, void *offset) +{ + seq_printf(file, "i_bcnt: %llu\n", test_write_cgr_data.i_bcnt); + return 0; +} +static int testwrite_cgr_ibcnt_open(struct inode *inode, struct file *file) +{ + return single_open(file, testwrite_cgr_ibcnt_show, NULL); +} + +static ssize_t testwrite_cgr_ibcnt_write(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + test_write_cgr_data.i_bcnt = val; + return count; +} + +static const struct file_operations teswrite_cgr_ibcnt_fops = { + .owner = THIS_MODULE, + .open = testwrite_cgr_ibcnt_open, + .read = seq_read, + .write = testwrite_cgr_ibcnt_write, + .release = single_release, +}; + +static int testwrite_cgr_cgrid_show(struct seq_file *file, void *offset) +{ + seq_printf(file, "cgrid: %u\n", (u32)test_write_cgr_data.cgid); + return 0; +} +static int testwrite_cgr_cgrid_open(struct inode *inode, struct file *file) +{ + return single_open(file, testwrite_cgr_cgrid_show, NULL); +} + +static ssize_t testwrite_cgr_cgrid_write(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + if (val > 0xff) + return -EINVAL; + test_write_cgr_data.cgid = (u8)val; + return count; +} + +static const struct file_operations teswrite_cgr_cgrid_fops = { + .owner = THIS_MODULE, + .open = testwrite_cgr_cgrid_open, + .read = seq_read, + .write = testwrite_cgr_cgrid_write, + .release = single_release, +}; + +/******************************************************************************* + * Query Congestion State + ******************************************************************************/ +static int query_congestion_show(struct seq_file *file, void *offset) +{ + int ret; + struct qm_mcr_querycongestion cs; + int i, j, in_cong = 0; + u32 mask; + + memset(&cs, 0, sizeof(struct qm_mcr_querycongestion)); + ret = qman_query_congestion(&cs); + if (ret) + return ret; + seq_printf(file, "Query Congestion Result\n"); + for (i = 0; i < 8; i++) { + mask = 0x80000000; + for (j = 0; j < 32; j++) { + if (cs.state.__state[i] & mask) { + in_cong = 1; + seq_printf(file, " cg %u: %s\n", (i*32)+j, + "in congestion"); + } + mask >>= 1; + } + } + if (!in_cong) + seq_printf(file, " All congestion groups not congested.\n"); + return 0; +} + +static int query_congestion_open(struct inode *inode, struct file *file) +{ + return single_open(file, query_congestion_show, NULL); +} + +static const struct file_operations query_congestion_fops = { + .owner = THIS_MODULE, + .open = query_congestion_open, + .read = seq_read, + .release = single_release, +}; + +/******************************************************************************* + * QMan register + ******************************************************************************/ +struct qman_register_s { + u32 val; +}; +static struct qman_register_s qman_register_data; + +static void init_ccsrmempeek(void) +{ + struct device_node *dn; + const u32 *regaddr_p; + + dn = of_find_compatible_node(NULL, NULL, "fsl,qman"); + if (!dn) { + pr_info("No fsl,qman node\n"); + return; + } + regaddr_p = of_get_address(dn, 0, &qman_ccsr_size, NULL); + if (!regaddr_p) { + of_node_put(dn); + return; + } + qman_ccsr_start = of_translate_address(dn, regaddr_p); + of_node_put(dn); +} +/* This function provides access to QMan ccsr memory map */ +static int qman_ccsrmempeek(u32 *val, u32 offset) +{ + void __iomem *addr; + u64 phys_addr; + + if (!qman_ccsr_start) + return -EINVAL; + + if (offset > (qman_ccsr_size - sizeof(u32))) + return -EINVAL; + + phys_addr = qman_ccsr_start + offset; + addr = ioremap(phys_addr, sizeof(u32)); + if (!addr) { + pr_err("ccsrmempeek, ioremap failed\n"); + return -EINVAL; + } + *val = in_be32(addr); + iounmap(addr); + return 0; +} + +static int qman_ccsrmempeek_show(struct seq_file *file, void *offset) +{ + u32 b; + + qman_ccsrmempeek(&b, qman_register_data.val); + seq_printf(file, "QMan register offset = 0x%x\n", + qman_register_data.val); + seq_printf(file, "value = 0x%08x\n", b); + + return 0; +} + +static int qman_ccsrmempeek_open(struct inode *inode, struct file *file) +{ + return single_open(file, qman_ccsrmempeek_show, NULL); +} + +static ssize_t qman_ccsrmempeek_write(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + /* multiple of 4 */ + if (val > (qman_ccsr_size - sizeof(u32))) { + pr_info("Input 0x%lx > 0x%llx\n", + val, (qman_ccsr_size - sizeof(u32))); + return -EINVAL; + } + if (val & 0x3) { + pr_info("Input 0x%lx not multiple of 4\n", val); + return -EINVAL; + } + qman_register_data.val = val; + return count; +} + +static const struct file_operations qman_ccsrmempeek_fops = { + .owner = THIS_MODULE, + .open = qman_ccsrmempeek_open, + .read = seq_read, + .write = qman_ccsrmempeek_write, +}; + +/******************************************************************************* + * QMan state + ******************************************************************************/ +static int qman_fqd_state_show(struct seq_file *file, void *offset) +{ + struct qm_mcr_queryfq_np np; + struct qman_fq fq; + struct line_buffer_fq line_buf; + int ret, i; + u8 *state = file->private; + u32 qm_fq_state_cnt[fqd_states_count]; + + memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt)); + memset(&line_buf, 0, sizeof(line_buf)); + + seq_printf(file, "List of fq ids in state: %s\n", state_txt[*state]); + + for (i = 1; i < fqid_max; i++) { + fq.fqid = i; + ret = qman_query_fq_np(&fq, &np); + if (ret) + return ret; + if (*state == (np.state & QM_MCR_NP_STATE_MASK)) + add_to_line_buffer(&line_buf, fq.fqid, file); + /* Keep a summary count of all states */ + if ((np.state & QM_MCR_NP_STATE_MASK) < fqd_states_count) + qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++; + } + flush_line_buffer(&line_buf, file); + + for (i = 0; i < fqd_states_count; i++) { + seq_printf(file, "%s count = %u\n", state_txt[i], + qm_fq_state_cnt[i]); + } + return 0; +} + +static int qman_fqd_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, qman_fqd_state_show, inode->i_private); +} + +static const struct file_operations qman_fqd_state_fops = { + .owner = THIS_MODULE, + .open = qman_fqd_state_open, + .read = seq_read, +}; + +static int qman_fqd_ctrl_show(struct seq_file *file, void *offset) +{ + struct qm_fqd fqd; + struct qman_fq fq; + u32 fq_en_cnt = 0, fq_di_cnt = 0; + int ret, i; + struct mask_filter_s *data = file->private; + const char *ctrl_txt = get_fqd_ctrl_text(data->mask); + struct line_buffer_fq line_buf; + + memset(&line_buf, 0, sizeof(line_buf)); + seq_printf(file, "List of fq ids with: %s :%s\n", + ctrl_txt, (data->filter) ? "enabled" : "disabled"); + for (i = 1; i < fqid_max; i++) { + fq.fqid = i; + memset(&fqd, 0, sizeof(struct qm_fqd)); + ret = qman_query_fq(&fq, &fqd); + if (ret) + return ret; + if (data->filter) { + if (fqd.fq_ctrl & data->mask) + add_to_line_buffer(&line_buf, fq.fqid, file); + } else { + if (!(fqd.fq_ctrl & data->mask)) + add_to_line_buffer(&line_buf, fq.fqid, file); + } + if (fqd.fq_ctrl & data->mask) + fq_en_cnt++; + else + fq_di_cnt++; + } + flush_line_buffer(&line_buf, file); + + seq_printf(file, "Total FQD with: %s : enabled = %u\n", + ctrl_txt, fq_en_cnt); + seq_printf(file, "Total FQD with: %s : disabled = %u\n", + ctrl_txt, fq_di_cnt); + return 0; +} + +/******************************************************************************* + * QMan ctrl CGE, TDE, ORP, CTX, CPC, SFDR, BLOCK, HOLD, CACHE + ******************************************************************************/ +static int qman_fqd_ctrl_open(struct inode *inode, struct file *file) +{ + return single_open(file, qman_fqd_ctrl_show, inode->i_private); +} + +static const struct file_operations qman_fqd_ctrl_fops = { + .owner = THIS_MODULE, + .open = qman_fqd_ctrl_open, + .read = seq_read, +}; + +/******************************************************************************* + * QMan ctrl summary + ******************************************************************************/ +/******************************************************************************* + * QMan summary state + ******************************************************************************/ +static int qman_fqd_non_prog_summary_show(struct seq_file *file, void *offset) +{ + struct qm_mcr_queryfq_np np; + struct qman_fq fq; + int ret, i; + u32 qm_fq_state_cnt[fqd_states_count]; + + memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt)); + + for (i = 1; i < fqid_max; i++) { + fq.fqid = i; + ret = qman_query_fq_np(&fq, &np); + if (ret) + return ret; + /* Keep a summary count of all states */ + if ((np.state & QM_MCR_NP_STATE_MASK) < fqd_states_count) + qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++; + } + + for (i = 0; i < fqd_states_count; i++) { + seq_printf(file, "%s count = %u\n", state_txt[i], + qm_fq_state_cnt[i]); + } + return 0; +} + +static int qman_fqd_prog_summary_show(struct seq_file *file, void *offset) +{ + struct qm_fqd fqd; + struct qman_fq fq; + int ret, i , j; + u32 qm_prog_cnt[mask_filter_count/2]; + + memset(qm_prog_cnt, 0, sizeof(qm_prog_cnt)); + + for (i = 1; i < fqid_max; i++) { + memset(&fqd, 0, sizeof(struct qm_fqd)); + fq.fqid = i; + ret = qman_query_fq(&fq, &fqd); + if (ret) + return ret; + /* Keep a summary count of all states */ + for (j = 0; j < mask_filter_count; j += 2) + if ((fqd.fq_ctrl & QM_FQCTRL_MASK) & + mask_filter[j].mask) + qm_prog_cnt[j/2]++; + } + for (i = 0; i < mask_filter_count/2; i++) { + seq_printf(file, "%s count = %u\n", + get_fqd_ctrl_text(mask_filter[i*2].mask), + qm_prog_cnt[i]); + } + return 0; +} + +static int qman_fqd_summary_show(struct seq_file *file, void *offset) +{ + int ret; + + /* Display summary of non programmable fields */ + ret = qman_fqd_non_prog_summary_show(file, offset); + if (ret) + return ret; + seq_printf(file, "-----------------------------------------\n"); + /* Display programmable fields */ + ret = qman_fqd_prog_summary_show(file, offset); + if (ret) + return ret; + return 0; +} + +static int qman_fqd_summary_open(struct inode *inode, struct file *file) +{ + return single_open(file, qman_fqd_summary_show, NULL); +} + +static const struct file_operations qman_fqd_summary_fops = { + .owner = THIS_MODULE, + .open = qman_fqd_summary_open, + .read = seq_read, +}; + +/******************************************************************************* + * QMan destination work queue + ******************************************************************************/ +struct qman_dest_wq_s { + u16 wq_id; +}; +static struct qman_dest_wq_s qman_dest_wq_data = { + .wq_id = 0, +}; + +static int qman_fqd_dest_wq_show(struct seq_file *file, void *offset) +{ + struct qm_fqd fqd; + struct qman_fq fq; + int ret, i; + u16 *wq, wq_id = qman_dest_wq_data.wq_id; + struct line_buffer_fq line_buf; + + memset(&line_buf, 0, sizeof(line_buf)); + /* use vmalloc : need to allocate large memory region and don't + * require the memory to be physically contiguous. */ + wq = vmalloc(sizeof(u16) * (0xFFFF+1)); + if (!wq) + return -ENOMEM; + memset(wq, 0, sizeof(u16) * (0xFFFF+1)); + + seq_printf(file, "List of fq ids with destination work queue id" + " = 0x%x\n", wq_id); + + for (i = 1; i < fqid_max; i++) { + fq.fqid = i; + memset(&fqd, 0, sizeof(struct qm_fqd)); + ret = qman_query_fq(&fq, &fqd); + if (ret) { + vfree(wq); + return ret; + } + if (wq_id == fqd.dest_wq) + add_to_line_buffer(&line_buf, fq.fqid, file); + wq[fqd.dest_wq]++; + } + flush_line_buffer(&line_buf, file); + + seq_printf(file, "Summary of all FQD destination work queue values\n"); + for (i = 0; i < 0xFFFF; i++) { + if (wq[i]) + seq_printf(file, "Channel: 0x%x WQ: 0x%x WQ_ID: 0x%x, " + "count = %u\n", i >> 3, i & 0x3, i, wq[i]); + } + vfree(wq); + return 0; +} + +static ssize_t qman_fqd_dest_wq_write(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + int ret; + unsigned long val; + + ret = user_input_convert(buf, count, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + qman_dest_wq_data.wq_id = val; + return count; +} + +static int qman_fqd_dest_wq_open(struct inode *inode, struct file *file) +{ + return single_open(file, qman_fqd_dest_wq_show, NULL); +} + +static const struct file_operations qman_fqd_dest_wq_fops = { + .owner = THIS_MODULE, + .open = qman_fqd_dest_wq_open, + .read = seq_read, + .write = qman_fqd_dest_wq_write, +}; + +/******************************************************************************* + * QMan Intra-Class Scheduling Credit + ******************************************************************************/ +static int qman_fqd_cred_show(struct seq_file *file, void *offset) +{ + struct qm_fqd fqd; + struct qman_fq fq; + int ret, i; + u32 fq_cnt = 0; + struct line_buffer_fq line_buf; + + memset(&line_buf, 0, sizeof(line_buf)); + seq_printf(file, "List of fq ids with Intra-Class Scheduling Credit > 0" + "\n"); + + for (i = 1; i < fqid_max; i++) { + fq.fqid = i; + memset(&fqd, 0, sizeof(struct qm_fqd)); + ret = qman_query_fq(&fq, &fqd); + if (ret) + return ret; + if (fqd.ics_cred > 0) { + add_to_line_buffer(&line_buf, fq.fqid, file); + fq_cnt++; + } + } + flush_line_buffer(&line_buf, file); + + seq_printf(file, "Total FQD with ics_cred > 0 = %d\n", fq_cnt); + return 0; +} + +static int qman_fqd_cred_open(struct inode *inode, struct file *file) +{ + return single_open(file, qman_fqd_cred_show, NULL); +} + +static const struct file_operations qman_fqd_cred_fops = { + .owner = THIS_MODULE, + .open = qman_fqd_cred_open, + .read = seq_read, +}; + +/* helper macros used in qman_debugfs_module_init */ +#define QMAN_DBGFS_ENTRY(name, mode, parent, data, fops) \ + do { \ + d = debugfs_create_file(name, \ + mode, parent, \ + data, \ + fops); \ + if (d == NULL) { \ + ret = -ENOMEM; \ + goto _return; \ + } \ + } while (0) + +/* dfs_root as parent */ +#define QMAN_DBGFS_ENTRY_ROOT(name, mode, data, fops) \ + QMAN_DBGFS_ENTRY(name, mode, dfs_root, data, fops) + +/* fqd_root as parent */ +#define QMAN_DBGFS_ENTRY_FQDROOT(name, mode, data, fops) \ + QMAN_DBGFS_ENTRY(name, mode, fqd_root, data, fops) + +/* fqd state */ +#define QMAN_DBGFS_ENTRY_FQDSTATE(name, index) \ + QMAN_DBGFS_ENTRY_FQDROOT(name, S_IRUGO, \ + (void *)&mask_filter[index], &qman_fqd_ctrl_fops) + +static int __init qman_debugfs_module_init(void) +{ + int ret = 0; + struct dentry *d, *fqd_root; + u32 reg; + + fqid_max = 0; + init_ccsrmempeek(); + if (qman_ccsr_start) { + if (!qman_ccsrmempeek(®, QM_FQD_AR)) { + /* extract the size of the FQD window */ + reg = reg & 0x3f; + /* calculate valid frame queue descriptor range */ + fqid_max = (1 << (reg + 1)) / QM_FQD_BLOCK_SIZE; + } + } + dfs_root = debugfs_create_dir("qman", NULL); + fqd_root = debugfs_create_dir("fqd", dfs_root); + if (dfs_root == NULL || fqd_root == NULL) { + ret = -ENOMEM; + pr_err("Cannot create qman/fqd debugfs dir\n"); + goto _return; + } + if (fqid_max) { + QMAN_DBGFS_ENTRY_ROOT("ccsrmempeek", S_IRUGO | S_IWUGO, + NULL, &qman_ccsrmempeek_fops); + } + QMAN_DBGFS_ENTRY_ROOT("query_fq_np_fields", S_IRUGO | S_IWUGO, + &query_fq_np_fields_data, &query_fq_np_fields_fops); + + QMAN_DBGFS_ENTRY_ROOT("query_fq_fields", S_IRUGO | S_IWUGO, + &query_fq_fields_data, &query_fq_fields_fops); + + QMAN_DBGFS_ENTRY_ROOT("query_wq_lengths", S_IRUGO | S_IWUGO, + &query_wq_lengths_data, &query_wq_lengths_fops); + + QMAN_DBGFS_ENTRY_ROOT("query_cgr", S_IRUGO | S_IWUGO, + &query_cgr_data, &query_cgr_fops); + + QMAN_DBGFS_ENTRY_ROOT("query_congestion", S_IRUGO, + NULL, &query_congestion_fops); + + QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr", S_IRUGO, + NULL, &testwrite_cgr_fops); + + QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_cgrid", S_IRUGO | S_IWUGO, + NULL, &teswrite_cgr_cgrid_fops); + + QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_ibcnt", S_IRUGO | S_IWUGO, + NULL, &teswrite_cgr_ibcnt_fops); + + /* Create files with fqd_root as parent */ + + QMAN_DBGFS_ENTRY_FQDROOT("stateoos", S_IRUGO, + (void *)&fqd_states[QM_MCR_NP_STATE_OOS], &qman_fqd_state_fops); + + QMAN_DBGFS_ENTRY_FQDROOT("state_retired", S_IRUGO, + (void *)&fqd_states[QM_MCR_NP_STATE_RETIRED], + &qman_fqd_state_fops); + + QMAN_DBGFS_ENTRY_FQDROOT("state_tentatively_sched", S_IRUGO, + (void *)&fqd_states[QM_MCR_NP_STATE_TEN_SCHED], + &qman_fqd_state_fops); + + QMAN_DBGFS_ENTRY_FQDROOT("state_truly_sched", S_IRUGO, + (void *)&fqd_states[QM_MCR_NP_STATE_TRU_SCHED], + &qman_fqd_state_fops); + + QMAN_DBGFS_ENTRY_FQDROOT("state_parked", S_IRUGO, + (void *)&fqd_states[QM_MCR_NP_STATE_PARKED], + &qman_fqd_state_fops); + + QMAN_DBGFS_ENTRY_FQDROOT("state_active", S_IRUGO, + (void *)&fqd_states[QM_MCR_NP_STATE_ACTIVE], + &qman_fqd_state_fops); + + QMAN_DBGFS_ENTRY_FQDSTATE("cge_enable", 17); + + QMAN_DBGFS_ENTRY_FQDSTATE("cge_disable", 16); + + QMAN_DBGFS_ENTRY_FQDSTATE("tde_enable", 15); + + QMAN_DBGFS_ENTRY_FQDSTATE("tde_disable", 14); + + QMAN_DBGFS_ENTRY_FQDSTATE("orp_enable", 13); + + QMAN_DBGFS_ENTRY_FQDSTATE("orp_disable", 12); + + QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_enable", 11); + + QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_disable", 10); + + QMAN_DBGFS_ENTRY_FQDSTATE("cpc_enable", 9); + + QMAN_DBGFS_ENTRY_FQDSTATE("cpc_disable", 8); + + QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_enable", 7); + + QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_disable", 6); + + QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_enable", 5); + + QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_disable", 4); + + QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_enable", 3); + + QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_disable", 2); + + QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_enable", 1); + + QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_disable", 0); + + QMAN_DBGFS_ENTRY_FQDROOT("summary", S_IRUGO, + NULL, &qman_fqd_summary_fops); + + QMAN_DBGFS_ENTRY_FQDROOT("wq", S_IRUGO | S_IWUGO, + NULL, &qman_fqd_dest_wq_fops); + + QMAN_DBGFS_ENTRY_FQDROOT("cred", S_IRUGO, + NULL, &qman_fqd_cred_fops); + + return 0; + +_return: + if (dfs_root) + debugfs_remove_recursive(dfs_root); + return ret; +} + +static void __exit qman_debugfs_module_exit(void) +{ + debugfs_remove_recursive(dfs_root); +} + +module_init(qman_debugfs_module_init); +module_exit(qman_debugfs_module_exit); +MODULE_LICENSE("Dual BSD/GPL"); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_high.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_high.c @@ -0,0 +1,2360 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_low.h" + +/* Compilation constants */ +#define DQRR_MAXFILL 15 +#define EQCR_ITHRESH 4 /* if EQCR congests, interrupt threshold */ +#define IRQNAME "QMan portal %d" +#define MAX_IRQNAME 16 /* big enough for "QMan portal %d" */ + +/* Lock/unlock frame queues, subject to the "LOCKED" flag. This is about + * inter-processor locking only. Note, FQLOCK() is always called either under a + * local_irq_save() or from interrupt context - hence there's no need for irq + * protection (and indeed, attempting to nest irq-protection doesn't work, as + * the "irq en/disable" machinery isn't recursive...). */ +#define FQLOCK(fq) \ + do { \ + struct qman_fq *__fq478 = (fq); \ + if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \ + spin_lock(&__fq478->fqlock); \ + } while(0) +#define FQUNLOCK(fq) \ + do { \ + struct qman_fq *__fq478 = (fq); \ + if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \ + spin_unlock(&__fq478->fqlock); \ + } while(0) + +static inline void fq_set(struct qman_fq *fq, u32 mask) +{ + set_bits(mask, &fq->flags); +} +static inline void fq_clear(struct qman_fq *fq, u32 mask) +{ + clear_bits(mask, &fq->flags); +} +static inline int fq_isset(struct qman_fq *fq, u32 mask) +{ + return fq->flags & mask; +} +static inline int fq_isclear(struct qman_fq *fq, u32 mask) +{ + return !(fq->flags & mask); +} + +#define PORTAL_BITS_CI_PREFETCH 0x00020000 /* EQCR::CI prefetched */ +#define PORTAL_BITS_RECOVERY 0x00040000 /* recovery mode */ + +struct qman_portal { + struct qm_portal p; + unsigned long bits; /* PORTAL_BITS_*** - dynamic, strictly internal */ + unsigned long irq_sources; + u32 slowpoll; /* only used when interrupts are off */ + struct qman_fq *vdqcr_owned; /* only 1 volatile dequeue at a time */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + struct qman_fq *eqci_owned; /* only 1 enqueue WAIT_SYNC at a time */ +#endif +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + spinlock_t sharing_lock; /* only used if is_shared */ + int is_shared; + struct qman_portal *sharing_redirect; +#endif + u32 sdqcr; + int dqrr_disable_ref; +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX + /* If we receive a DQRR or MR ring entry for a "null" FQ, ie. for which + * FQD::contextB is NULL rather than pointing to a FQ object, we use + * these handlers. (This is not considered a fast-path mechanism.) */ + struct qman_fq_cb null_cb; +#endif + /* When the cpu-affine portal is activated, this is non-NULL */ + const struct qm_portal_config *config; + /* This is needed for providing a non-NULL device to dma_map_***() */ + struct platform_device *pdev; + struct dpa_rbtree retire_table; + char irqname[MAX_IRQNAME]; + /* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */ + struct qman_cgrs *cgrs; + /* 256-element array, each is a linked-list of CSCN handlers. */ + struct list_head cgr_cbs[256]; + /* list lock */ + spinlock_t cgr_lock; +}; + +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE +#define PORTAL_IRQ_LOCK(p, irqflags) \ + do { \ + if ((p)->is_shared) \ + spin_lock_irqsave(&(p)->sharing_lock, irqflags); \ + else \ + local_irq_save(irqflags); \ + } while (0) +#define PORTAL_IRQ_UNLOCK(p, irqflags) \ + do { \ + if ((p)->is_shared) \ + spin_unlock_irqrestore(&(p)->sharing_lock, irqflags); \ + else \ + local_irq_restore(irqflags); \ + } while (0) +#else +#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags) +#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags) +#endif + +static cpumask_t affine_mask; +static DEFINE_SPINLOCK(affine_mask_lock); +static DEFINE_PER_CPU(struct qman_portal, qman_affine_portal); +/* "raw" gets the cpu-local struct whether it's a redirect or not. */ +static inline struct qman_portal *get_raw_affine_portal(void) +{ + return &get_cpu_var(qman_affine_portal); +} +/* For ops that can redirect, this obtains the portal to use */ +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE +static inline struct qman_portal *get_affine_portal(void) +{ + struct qman_portal *p = get_raw_affine_portal(); + if (p->sharing_redirect) + return p->sharing_redirect; + return p; +} +#else +#define get_affine_portal() get_raw_affine_portal() +#endif +/* For every "get", there must be a "put" */ +static inline void put_affine_portal(void) +{ + put_cpu_var(qman_affine_portal); +} + +/* This gives a FQID->FQ lookup to cover the fact that we can't directly demux + * retirement notifications (the fact they are sometimes h/w-consumed means that + * contextB isn't always a s/w demux - and as we can't know which case it is + * when looking at the notification, we have to use the slow lookup for all of + * them). NB, it's possible to have multiple FQ objects refer to the same FQID + * (though at most one of them should be the consumer), so this table isn't for + * all FQs - FQs are added when retirement commands are issued, and removed when + * they complete, which also massively reduces the size of this table. */ +IMPLEMENT_DPA_RBTREE(fqtree, struct qman_fq, node, fqid); + +/* This is what everything can wait on, even if it migrates to a different cpu + * to the one whose affine portal it is waiting on. */ +static DECLARE_WAIT_QUEUE_HEAD(affine_queue); + +static inline int table_push_fq(struct qman_portal *p, struct qman_fq *fq) +{ + int ret = fqtree_push(&p->retire_table, fq); + if (ret) + pr_err("ERROR: double FQ-retirement %d\n", fq->fqid); + return ret; +} + +static inline void table_del_fq(struct qman_portal *p, struct qman_fq *fq) +{ + fqtree_del(&p->retire_table, fq); +} + +static inline struct qman_fq *table_find_fq(struct qman_portal *p, u32 fqid) +{ + return fqtree_find(&p->retire_table, fqid); +} + +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP +static void **qman_fq_lookup_table; +static size_t qman_fq_lookup_table_size; + +int qman_setup_fq_lookup_table(size_t num_entries) +{ + num_entries++; + /* Allocate 1 more entry since the first entry is not used */ + qman_fq_lookup_table = vmalloc((num_entries * sizeof(void *))); + if (!qman_fq_lookup_table) { + pr_err("QMan: Could not allocate fq lookup table\n"); + return -ENOMEM; + } + memset(qman_fq_lookup_table, 0, num_entries * sizeof(void *)); + qman_fq_lookup_table_size = num_entries; + pr_info("QMan: Allocated lookup table at %p, entry count %lu\n", + qman_fq_lookup_table, + (unsigned long)qman_fq_lookup_table_size); + return 0; +} + +/* global structure that maintains fq object mapping */ +static DEFINE_SPINLOCK(fq_hash_table_lock); + +static int find_empty_fq_table_entry(u32 *entry, struct qman_fq *fq) +{ + u32 i; + + spin_lock(&fq_hash_table_lock); + /* Can't use index zero because this has special meaning + * in context_b field. */ + for (i = 1; i < qman_fq_lookup_table_size; i++) { + if (qman_fq_lookup_table[i] == NULL) { + *entry = i; + qman_fq_lookup_table[i] = fq; + spin_unlock(&fq_hash_table_lock); + return 0; + } + } + spin_unlock(&fq_hash_table_lock); + return -ENOMEM; +} + +static void clear_fq_table_entry(u32 entry) +{ + spin_lock(&fq_hash_table_lock); + BUG_ON(entry >= qman_fq_lookup_table_size); + qman_fq_lookup_table[entry] = NULL; + spin_unlock(&fq_hash_table_lock); +} + +static inline struct qman_fq *get_fq_table_entry(u32 entry) +{ + BUG_ON(entry >= qman_fq_lookup_table_size); + return qman_fq_lookup_table[entry]; +} +#endif + +/* In the case that slow- and fast-path handling are both done by qman_poll() + * (ie. because there is no interrupt handling), we ought to balance how often + * we do the fast-path poll versus the slow-path poll. We'll use two decrementer + * sources, so we call the fast poll 'n' times before calling the slow poll + * once. The idle decrementer constant is used when the last slow-poll detected + * no work to do, and the busy decrementer constant when the last slow-poll had + * work to do. */ +#define SLOW_POLL_IDLE 1000 +#define SLOW_POLL_BUSY 10 +static u32 __poll_portal_slow(struct qman_portal *p, u32 is); +static inline unsigned int __poll_portal_fast(struct qman_portal *p, + unsigned int poll_limit); + +#ifdef CONFIG_FSL_DPA_HAVE_IRQ +/* Portal interrupt handler */ +static irqreturn_t portal_isr(__always_unused int irq, void *ptr) +{ + struct qman_portal *p = ptr; + u32 clear = QM_DQAVAIL_MASK | p->irq_sources; + u32 is = qm_isr_status_read(&p->p) & p->irq_sources; + /* DQRR-handling if it's interrupt-driven */ + if (is & QM_PIRQ_DQRI) + __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT); + /* Handling of anything else that's interrupt-driven */ + clear |= __poll_portal_slow(p, is); + qm_isr_status_clear(&p->p, clear); + return IRQ_HANDLED; +} +#endif + +/* This inner version is used privately by qman_create_affine_portal(), as well + * as by the exported qman_stop_dequeues(). */ +static inline void qman_stop_dequeues_ex(struct qman_portal *p) +{ + unsigned long irqflags __maybe_unused; + PORTAL_IRQ_LOCK(p, irqflags); + if (!(p->dqrr_disable_ref++)) + qm_dqrr_set_maxfill(&p->p, 0); + PORTAL_IRQ_UNLOCK(p, irqflags); +} + +static int drain_mr_fqrni(struct qm_portal *p) +{ + const struct qm_mr_entry *msg; +loop: + msg = qm_mr_current(p); + if (!msg) { + /* if MR was full and h/w had other FQRNI entries to produce, we + * need to allow it time to produce those entries once the + * existing entries are consumed. A worst-case situation + * (fully-loaded system) means h/w sequencers may have to do 3-4 + * other things before servicing the portal's MR pump, each of + * which (if slow) may take ~50 qman cycles (which is ~200 + * processor cycles). So rounding up and then multiplying this + * worst-case estimate by a factor of 10, just to be + * ultra-paranoid, goes as high as 10,000 cycles. NB, we consume + * one entry at a time, so h/w has an opportunity to produce new + * entries well before the ring has been fully consumed, so + * we're being *really* paranoid here. */ + u64 now, then = mfatb(); + do { + now = mfatb(); + } while ((then + 10000) > now); + msg = qm_mr_current(p); + if (!msg) + return 0; + } + if ((msg->verb & QM_MR_VERB_TYPE_MASK) != QM_MR_VERB_FQRNI) + /* We aren't draining anything but FQRNIs */ + return -1; + qm_mr_next(p); + qm_mr_cci_consume(p, 1); + goto loop; +} + +/* this is called from qman_create_affine_portal() if not initialising in + * recovery mode, otherwise from qman_recovery_exit_local() after recovery is + * done. */ +static void post_recovery(struct qman_portal *p __always_unused, + const struct qm_portal_config *config) +{ + struct device_node *tmp_node, *node = config->node; + /* Enable DMA on portal LIODNs (stashing) and those of its sub-nodes + * (Fman TX and SEC/PME accelerators, where available). */ + if (pamu_enable_liodn(node, -1)) + /* If there's a PAMU problem, best to continue anyway and let + * the corresponding traffic hit whatever problems it will hit, + * than to fail portal initialisation and trigger a crash in + * dependent code that has no relationship to the PAMU issue. */ + pr_err("Failed to enable portal LIODN %s\n", + node->full_name); + for_each_child_of_node(node, tmp_node) + if (pamu_enable_liodn(tmp_node, -1)) + pr_err("Failed to enable portal LIODN %s\n", + tmp_node->full_name); +} + +struct qman_portal *qman_create_affine_portal( + const struct qm_portal_config *config, + const struct qman_cgrs *cgrs, + const struct qman_fq_cb *null_cb, + int recovery_mode) +{ + struct qman_portal *portal = get_raw_affine_portal(); + struct qm_portal *__p = &portal->p; + char buf[16]; + int ret; + u32 isdr; + + /* A criteria for calling this function (from qman_driver.c) is that + * we're already affine to the cpu and won't schedule onto another cpu. + * This means we can put_affine_portal() and yet continue to use + * "portal", which in turn means aspects of this routine can sleep. */ + put_affine_portal(); +#ifndef CONFIG_FSL_QMAN_NULL_FQ_DEMUX + if (null_cb) { + pr_err("Driver does not support 'NULL FQ' callbacks\n"); + return NULL; + } +#endif + /* prep the low-level portal struct with the mapped addresses from the + * config, everything that follows depends on it and "config" is more + * for (de)reference... */ + __p->addr.addr_ce = config->addr_virt[QM_ADDR_CE]; + __p->addr.addr_ci = config->addr_virt[QM_ADDR_CI]; + if (qm_eqcr_init(__p, qm_eqcr_pvb, qm_eqcr_cce)) { + pr_err("Qman EQCR initialisation failed\n"); + goto fail_eqcr; + } +#ifdef CONFIG_FSL_QMAN_PORTAL_DISABLEAUTO_DCA +#define QM_DQRR_CMODE qm_dqrr_cci +#else +#define QM_DQRR_CMODE qm_dqrr_cdc +#endif + /* for recovery mode, don't enable stashing yet */ + if (qm_dqrr_init(__p, config, qm_dqrr_dpush, qm_dqrr_pvb, + recovery_mode ? qm_dqrr_cci : QM_DQRR_CMODE, + DQRR_MAXFILL, recovery_mode)) { + pr_err("Qman DQRR initialisation failed\n"); + goto fail_dqrr; + } + if (qm_mr_init(__p, qm_mr_pvb, qm_mr_cci)) { + pr_err("Qman MR initialisation failed\n"); + goto fail_mr; + } + /* for recovery mode, quiesce SDQCR/VDQCR and drain DQRR+MR until h/w + * wraps up anything it was doing (5ms is ample idle time). */ + if (recovery_mode) { + const struct qm_dqrr_entry *dq; + const struct qm_mr_entry *msg; + int idle = 0; + /* quiesce SDQCR/VDQCR, then drain till h/w wraps up anything it + * was doing (5ms is more than enough to ensure it's done). */ + qm_dqrr_sdqcr_set(__p, 0); + qm_dqrr_vdqcr_set(__p, 0); +drain_loop: + qm_dqrr_pvb_update(__p, 0); + dq = qm_dqrr_current(__p); + qm_mr_pvb_update(__p); + msg = qm_mr_current(__p); + if (dq) { + pr_warning("DQRR recovery: dumping dqrr %02x:%02x for " + "FQID %d\n", dq->verb & QM_DQRR_VERB_MASK, + dq->stat, dq->fqid); + qm_dqrr_next(__p); + qm_dqrr_cci_consume(__p, 1); + } + if (msg) { + pr_warning("MR recovery: dumping msg 0x%02x for " + "FQID %d\n", msg->verb & QM_MR_VERB_TYPE_MASK, + msg->fq.fqid); + qm_mr_next(__p); + qm_mr_cci_consume(__p, 1); + } + if (!dq && !msg) { + if (++idle < 5) { + msleep(1); + goto drain_loop; + } + } else { + idle = 0; + goto drain_loop; + } + } + if (qm_mc_init(__p)) { + pr_err("Qman MC initialisation failed\n"); + goto fail_mc; + } + if (qm_isr_init(__p)) { + pr_err("Qman ISR initialisation failed\n"); + goto fail_isr; + } + /* static interrupt-gating controls */ + qm_dqrr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_DQRR_ITHRESH); + qm_mr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_MR_ITHRESH); + qm_isr_set_iperiod(__p, CONFIG_FSL_QMAN_PIRQ_IPERIOD); + portal->cgrs = kmalloc(2 * sizeof(*cgrs), GFP_KERNEL); + if (!portal->cgrs) + goto fail_cgrs; + /* initial snapshot is no-depletion */ + qman_cgrs_init(&portal->cgrs[1]); + if (cgrs) + portal->cgrs[0] = *cgrs; + else + /* if the given mask is NULL, assume all CGRs can be seen */ + qman_cgrs_fill(&portal->cgrs[0]); + for (ret = 0; ret < __CGR_NUM; ret++) + INIT_LIST_HEAD(&portal->cgr_cbs[ret]); + spin_lock_init(&portal->cgr_lock); + portal->bits = recovery_mode ? PORTAL_BITS_RECOVERY : 0; + portal->slowpoll = 0; +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + portal->eqci_owned = NULL; +#endif +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + spin_lock_init(&portal->sharing_lock); + portal->is_shared = config->public_cfg.is_shared; + portal->sharing_redirect = NULL; +#endif + portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 | + QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS | + QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED; + portal->dqrr_disable_ref = 0; +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX + if (null_cb) + portal->null_cb = *null_cb; + else + memset(&portal->null_cb, 0, sizeof(*null_cb)); +#endif + sprintf(buf, "qportal-%d", config->public_cfg.channel); + portal->pdev = platform_device_alloc(buf, -1); + if (!portal->pdev) + goto fail_devalloc; + if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) + goto fail_devadd; + ret = platform_device_add(portal->pdev); + if (ret) + goto fail_devadd; + dpa_rbtree_init(&portal->retire_table); + isdr = 0xffffffff; + qm_isr_disable_write(__p, isdr); + portal->irq_sources = 0; + qm_isr_enable_write(__p, portal->irq_sources); + qm_isr_status_clear(__p, 0xffffffff); +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu); + if (request_irq(config->public_cfg.irq, portal_isr, + IRQF_NOBALANCING | IRQF_DISABLED, portal->irqname, + portal)) { + pr_err("request_irq() failed\n"); + goto fail_irq; + } + if (config->public_cfg.cpu != -1) { + disable_irq(config->public_cfg.irq); + irq_set_affinity(config->public_cfg.irq, + cpumask_of(config->public_cfg.cpu)); + } + enable_irq(config->public_cfg.irq); + + if (recovery_mode) { + qm_isr_inhibit(__p); + } else { + post_recovery(portal, config); + qm_isr_uninhibit(__p); + } +#endif + /* Need EQCR to be empty before continuing */ + isdr ^= QM_PIRQ_EQCI; + qm_isr_disable_write(__p, isdr); + ret = qm_eqcr_get_fill(__p); + if (ret) { + pr_err("Qman EQCR unclean, need recovery\n"); + goto fail_eqcr_empty; + } + isdr ^= (QM_PIRQ_DQRI | QM_PIRQ_MRI); + qm_isr_disable_write(__p, isdr); + if (qm_dqrr_current(__p) != NULL) { + pr_err("Qman DQRR unclean, need recovery\n"); + goto fail_dqrr_mr_empty; + } + if (qm_mr_current(__p) != NULL) { + /* special handling, drain just in case it's a few FQRNIs */ + if (drain_mr_fqrni(__p)) { + pr_err("Qman MR unclean, need recovery\n"); + goto fail_dqrr_mr_empty; + } + } + /* Success */ + portal->config = config; + spin_lock(&affine_mask_lock); + cpumask_set_cpu(config->public_cfg.cpu, &affine_mask); + spin_unlock(&affine_mask_lock); + qm_isr_disable_write(__p, 0); + /* Write a sane SDQCR */ + qm_dqrr_sdqcr_set(__p, recovery_mode ? 0 : portal->sdqcr); + return portal; +fail_dqrr_mr_empty: +fail_eqcr_empty: +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + free_irq(config->public_cfg.irq, portal); +fail_irq: +#endif + platform_device_del(portal->pdev); +fail_devadd: + platform_device_put(portal->pdev); +fail_devalloc: + if (portal->cgrs) + kfree(portal->cgrs); +fail_cgrs: + qm_isr_finish(__p); +fail_isr: + qm_mc_finish(__p); +fail_mc: + qm_mr_finish(__p); +fail_mr: + qm_dqrr_finish(__p); +fail_dqrr: + qm_eqcr_finish(__p); +fail_eqcr: + put_affine_portal(); + return NULL; +} + +/* These checks are BUG_ON()s because the driver is already supposed to avoid + * these cases. */ +struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect) +{ +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + struct qman_portal *p = get_raw_affine_portal(); + /* Check that we don't already have our own portal */ + BUG_ON(p->config); + /* Check that we aren't already slaving to another portal */ + BUG_ON(p->is_shared); + /* Check that 'redirect' is prepared to have us */ + BUG_ON(!redirect->config->public_cfg.is_shared); + /* These are the only elements to initialise when redirecting */ + p->irq_sources = 0; + p->sharing_redirect = redirect; + put_affine_portal(); + return p; +#else + BUG(); + return NULL; +#endif +} + +const struct qm_portal_config *qman_destroy_affine_portal(void) +{ + /* We don't want to redirect if we're a slave, use "raw" */ + struct qman_portal *qm = get_raw_affine_portal(); + const struct qm_portal_config *pcfg; + int cpu; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (qm->sharing_redirect) { + qm->sharing_redirect = NULL; + put_affine_portal(); + return NULL; + } + qm->is_shared = 0; +#endif + pcfg = qm->config; + cpu = pcfg->public_cfg.cpu; + /* NB we do this to "quiesce" EQCR. If we add enqueue-completions or + * something related to QM_PIRQ_EQCI, this may need fixing. + * Also, due to the prefetching model used for CI updates in the enqueue + * path, this update will only invalidate the CI cacheline *after* + * working on it, so we need to call this twice to ensure a full update + * irrespective of where the enqueue processing was at when the teardown + * began. */ + qm_eqcr_cce_update(&qm->p); + qm_eqcr_cce_update(&qm->p); +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + free_irq(pcfg->public_cfg.irq, qm); +#endif + kfree(qm->cgrs); + qm_isr_finish(&qm->p); + qm_mc_finish(&qm->p); + qm_mr_finish(&qm->p); + qm_dqrr_finish(&qm->p); + qm_eqcr_finish(&qm->p); + qm->config = NULL; + spin_lock(&affine_mask_lock); + cpumask_clear_cpu(cpu, &affine_mask); + spin_unlock(&affine_mask_lock); + put_affine_portal(); + return pcfg; +} + +const struct qman_portal_config *qman_get_portal_config(void) +{ + struct qman_portal *p = get_affine_portal(); + const struct qman_portal_config *ret = &p->config->public_cfg; + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_get_portal_config); + +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX +void qman_get_null_cb(struct qman_fq_cb *null_cb) +{ + struct qman_portal *p = get_affine_portal(); + *null_cb = p->null_cb; + put_affine_portal(); +} +EXPORT_SYMBOL(qman_get_null_cb); + +void qman_set_null_cb(const struct qman_fq_cb *null_cb) +{ + struct qman_portal *p = get_affine_portal(); + p->null_cb = *null_cb; + put_affine_portal(); +} +EXPORT_SYMBOL(qman_set_null_cb); +#endif + +/* Inline helper to reduce nesting in __poll_portal_slow() */ +static inline void fq_state_change(struct qman_portal *p, struct qman_fq *fq, + const struct qm_mr_entry *msg, u8 verb) +{ + FQLOCK(fq); + switch(verb) { + case QM_MR_VERB_FQRL: + DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_ORL)); + fq_clear(fq, QMAN_FQ_STATE_ORL); + table_del_fq(p, fq); + break; + case QM_MR_VERB_FQRN: + DPA_ASSERT((fq->state == qman_fq_state_parked) || + (fq->state == qman_fq_state_sched)); + DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_CHANGING)); + fq_clear(fq, QMAN_FQ_STATE_CHANGING); + if (msg->fq.fqs & QM_MR_FQS_NOTEMPTY) + fq_set(fq, QMAN_FQ_STATE_NE); + if (msg->fq.fqs & QM_MR_FQS_ORLPRESENT) + fq_set(fq, QMAN_FQ_STATE_ORL); + else + table_del_fq(p, fq); + fq->state = qman_fq_state_retired; + break; + case QM_MR_VERB_FQPN: + DPA_ASSERT(fq->state == qman_fq_state_sched); + DPA_ASSERT(fq_isclear(fq, QMAN_FQ_STATE_CHANGING)); + fq->state = qman_fq_state_parked; + } + FQUNLOCK(fq); +} + +static u32 __poll_portal_slow(struct qman_portal *p, u32 is) +{ + const struct qm_mr_entry *msg; + + BUG_ON(p->bits & PORTAL_BITS_RECOVERY); + + if (is & QM_PIRQ_CSCI) { + struct qman_cgrs rr, c; + struct qm_mc_result *mcr; + struct qman_cgr *cgr; + int i; + unsigned long irqflags __maybe_unused; + + spin_lock_irqsave(&p->cgr_lock, irqflags); + qm_mc_start(&p->p); + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + /* mask out the ones I'm not interested in */ + qman_cgrs_and(&rr, (const struct qman_cgrs *) + &mcr->querycongestion.state, &p->cgrs[0]); + /* check previous snapshot for delta, enter/exit congestion */ + qman_cgrs_xor(&c, &rr, &p->cgrs[1]); + /* update snapshot */ + qman_cgrs_cp(&p->cgrs[1], &rr); + /* Invoke callback */ + qman_cgrs_for_each_1(i, &c) + list_for_each_entry(cgr, &p->cgr_cbs[i], node) { + if (cgr->cb) + cgr->cb(p, cgr, qman_cgrs_get(&rr, i)); + } + spin_unlock_irqrestore(&p->cgr_lock, irqflags); + } + +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (is & QM_PIRQ_EQCI) { + unsigned long irqflags; + PORTAL_IRQ_LOCK(p, irqflags); + p->eqci_owned = NULL; + PORTAL_IRQ_UNLOCK(p, irqflags); + wake_up(&affine_queue); + } +#endif + + if (is & QM_PIRQ_EQRI) { + unsigned long irqflags __maybe_unused; + PORTAL_IRQ_LOCK(p, irqflags); + qm_eqcr_cce_update(&p->p); + qm_eqcr_set_ithresh(&p->p, 0); + PORTAL_IRQ_UNLOCK(p, irqflags); + wake_up(&affine_queue); + } + + if (is & QM_PIRQ_MRI) { + u8 num = 0; +mr_loop: + qm_mr_pvb_update(&p->p); + msg = qm_mr_current(&p->p); + if (msg) { + u8 verb = msg->verb & QM_MR_VERB_TYPE_MASK; +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + struct qman_fq *fq; +#else + struct qman_fq *fq = (void *)(uintptr_t)msg->ern.tag; +#endif + if (verb == QM_MR_VERB_FQRNI) { + ; /* nada, we drop FQRNIs on the floor */ + } else if ((verb == QM_MR_VERB_FQRN) || + (verb == QM_MR_VERB_FQRL)) { + /* It's retirement related - need a lookup */ + fq = table_find_fq(p, msg->fq.fqid); + if (!fq) + panic("unexpected FQ retirement"); + fq_state_change(p, fq, msg, verb); + if (fq->cb.fqs) + fq->cb.fqs(p, fq, msg); +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + } else if (likely(msg->ern.tag)) { + fq = get_fq_table_entry(msg->ern.tag); +#else + } else if (likely(fq)) { +#endif + /* As per the header note, this is the way to + * determine if it's a s/w ERN or not. */ + if (likely(!(verb & QM_MR_VERB_DC_ERN))) + fq->cb.ern(p, fq, msg); + else + fq->cb.dc_ern(p, fq, msg); + } +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX + else { + /* use portal default handlers for 'null's */ + if (likely(!(verb & QM_MR_VERB_DC_ERN))) + p->null_cb.ern(p, NULL, msg); + else if (verb == QM_MR_VERB_DC_ERN) + p->null_cb.dc_ern(p, NULL, msg); + else if (p->null_cb.fqs) + p->null_cb.fqs(p, NULL, msg); + } +#endif + num++; + qm_mr_next(&p->p); + goto mr_loop; + } + qm_mr_cci_consume(&p->p, num); + } + + return is & (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI); +} + +/* remove some slowish-path stuff from the "fast path" and make sure it isn't + * inlined. */ +static noinline void clear_vdqcr(struct qman_portal *p, struct qman_fq *fq) +{ + p->vdqcr_owned = NULL; + FQLOCK(fq); + fq_clear(fq, QMAN_FQ_STATE_VDQCR); + FQUNLOCK(fq); + wake_up(&affine_queue); +} + +/* Look: no locks, no irq_save()s, no preempt_disable()s! :-) The only states + * that would conflict with other things if they ran at the same time on the + * same cpu are; + * + * (i) setting/clearing vdqcr_owned, and + * (ii) clearing the NE (Not Empty) flag. + * + * Both are safe. Because; + * + * (i) this clearing can only occur after qman_volatile_dequeue() has set the + * vdqcr_owned field (which it does before setting VDQCR), and + * qman_volatile_dequeue() blocks interrupts and preemption while this is + * done so that we can't interfere. + * (ii) the NE flag is only cleared after qman_retire_fq() has set it, and as + * with (i) that API prevents us from interfering until it's safe. + * + * The good thing is that qman_volatile_dequeue() and qman_retire_fq() run far + * less frequently (ie. per-FQ) than __poll_portal_fast() does, so the nett + * advantage comes from this function not having to "lock" anything at all. + * + * Note also that the callbacks are invoked at points which are safe against the + * above potential conflicts, but that this function itself is not re-entrant + * (this is because the function tracks one end of each FIFO in the portal and + * we do *not* want to lock that). So the consequence is that it is safe for + * user callbacks to call into any Qman API *except* qman_poll() (as that's the + * sole API that could be invoking the callback through this function). + */ +static inline unsigned int __poll_portal_fast(struct qman_portal *p, + unsigned int poll_limit) +{ + const struct qm_dqrr_entry *dq; + struct qman_fq *fq; + enum qman_cb_dqrr_result res; +#ifdef CONFIG_FSL_QMAN_DQRR_PREFETCHING + int coherent = (p->config->public_cfg.has_stashing); +#endif + unsigned int limit = 0; + + BUG_ON(p->bits & PORTAL_BITS_RECOVERY); +loop: +#ifdef CONFIG_FSL_QMAN_DQRR_PREFETCHING + qm_dqrr_pvb_update(&p->p, coherent); +#else + qm_dqrr_pvb_update(&p->p, 1); +#endif + dq = qm_dqrr_current(&p->p); + if (!dq) + goto done; + if (dq->stat & QM_DQRR_STAT_UNSCHEDULED) { + /* VDQCR: don't trust contextB as the FQ may have been + * configured for h/w consumption and we're draining it + * post-retirement. */ + fq = p->vdqcr_owned; + /* We only set QMAN_FQ_STATE_NE when retiring, so we only need + * to check for clearing it when doing volatile dequeues. It's + * one less thing to check in the critical path (SDQCR). */ + if (dq->stat & QM_DQRR_STAT_FQ_EMPTY) + fq_clear(fq, QMAN_FQ_STATE_NE); + /* this is duplicated from the SDQCR code, but we have stuff to + * do before *and* after this callback, and we don't want + * multiple if()s in the critical path (SDQCR). */ + res = fq->cb.dqrr(p, fq, dq); + if (res == qman_cb_dqrr_stop) + goto done; + /* Check for VDQCR completion */ + if (dq->stat & QM_DQRR_STAT_DQCR_EXPIRED) + clear_vdqcr(p, fq); + } else { + /* SDQCR: contextB points to the FQ */ +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + fq = get_fq_table_entry(dq->contextB); +#else + fq = (void *)(uintptr_t)dq->contextB; +#endif +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX + if (unlikely(!fq)) { + /* use portal default handlers */ + res = p->null_cb.dqrr(p, NULL, dq); + DPA_ASSERT(res == qman_cb_dqrr_consume); + res = qman_cb_dqrr_consume; + } else +#endif + { + /* Now let the callback do its stuff */ + res = fq->cb.dqrr(p, fq, dq); + /* The callback can request that we exit without + * consuming this entry nor advancing; */ + if (res == qman_cb_dqrr_stop) + goto done; + } + } + /* Interpret 'dq' from a driver perspective. */ + /* Parking isn't possible unless HELDACTIVE was set. NB, + * FORCEELIGIBLE implies HELDACTIVE, so we only need to + * check for HELDACTIVE to cover both. */ + DPA_ASSERT((dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) || + (res != qman_cb_dqrr_park)); +#ifdef CONFIG_FSL_QMAN_PORTAL_DISABLEAUTO_DCA + if (res == qman_cb_dqrr_park) + /* The only thing to do for non-DCA is the park-request */ + qm_dqrr_park_current(&p->p); + /* Move forward */ + qm_dqrr_next(&p->p); + qm_dqrr_cci_consume(&p->p, 1); +#else + /* Defer just means "skip it, I'll consume it myself later on" */ + if (res != qman_cb_dqrr_defer) + qm_dqrr_cdc_consume_1ptr(&p->p, dq, (res == qman_cb_dqrr_park)); + /* Move forward */ + qm_dqrr_next(&p->p); +#endif + /* Entry processed and consumed, increment our counter. The callback can + * request that we exit after consuming the entry, and we also exit if + * we reach our processing limit, so loop back only if neither of these + * conditions is met. */ + if ((++limit < poll_limit) && (res != qman_cb_dqrr_consume_stop)) + goto loop; +done: + return limit; +} + +u32 qman_irqsource_get(void) +{ + /* "irqsource" and "poll" APIs mustn't redirect when sharing, they + * should shut the user out if they are not the primary CPU hosting the + * portal. That's why we use the "raw" interface. */ + struct qman_portal *p = get_raw_affine_portal(); + u32 ret = p->irq_sources & QM_PIRQ_VISIBLE; + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_irqsource_get); + +int qman_irqsource_add(u32 bits __maybe_unused) +{ +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + struct qman_portal *p = get_raw_affine_portal(); + int ret = 0; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (p->sharing_redirect) + ret = -EINVAL; + else +#endif + { + __maybe_unused unsigned long irqflags; + PORTAL_IRQ_LOCK(p, irqflags); + set_bits(bits & QM_PIRQ_VISIBLE, &p->irq_sources); + qm_isr_enable_write(&p->p, p->irq_sources); + PORTAL_IRQ_UNLOCK(p, irqflags); + } + put_affine_portal(); + return ret; +#else + pr_err("No Qman portal IRQ support, mustn't specify IRQ flags!"); + return -EINVAL; +#endif +} +EXPORT_SYMBOL(qman_irqsource_add); + +int qman_irqsource_remove(u32 bits) +{ +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + struct qman_portal *p = get_raw_affine_portal(); + __maybe_unused unsigned long irqflags; + u32 ier; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (p->sharing_redirect) { + put_affine_portal(); + return -EINVAL; + } +#endif + /* Our interrupt handler only processes+clears status register bits that + * are in p->irq_sources. As we're trimming that mask, if one of them + * were to assert in the status register just before we remove it from + * the enable register, there would be an interrupt-storm when we + * release the IRQ lock. So we wait for the enable register update to + * take effect in h/w (by reading it back) and then clear all other bits + * in the status register. Ie. we clear them from ISR once it's certain + * IER won't allow them to reassert. */ + PORTAL_IRQ_LOCK(p, irqflags); + bits &= QM_PIRQ_VISIBLE; + clear_bits(bits, &p->irq_sources); + qm_isr_enable_write(&p->p, p->irq_sources); + ier = qm_isr_enable_read(&p->p); + /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a + * data-dependency, ie. to protect against re-ordering. */ + qm_isr_status_clear(&p->p, ~ier); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return 0; +#else + pr_err("No Qman portal IRQ support, mustn't specify IRQ flags!"); + return -EINVAL; +#endif +} +EXPORT_SYMBOL(qman_irqsource_remove); + +const cpumask_t *qman_affine_cpus(void) +{ + return &affine_mask; +} +EXPORT_SYMBOL(qman_affine_cpus); + +int qman_poll_dqrr(unsigned int limit) +{ + /* We need to fail when called for a "slave", so use "raw" */ + struct qman_portal *p = get_raw_affine_portal(); + int ret; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (unlikely(p->sharing_redirect)) + ret = -EINVAL; + else +#endif + { + BUG_ON(p->irq_sources & QM_PIRQ_DQRI); + ret = __poll_portal_fast(p, limit); + } + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_poll_dqrr); + +u32 qman_poll_slow(void) +{ + /* We need to fail when called for a "slave", so use "raw" */ + struct qman_portal *p = get_raw_affine_portal(); + u32 ret; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (unlikely(p->sharing_redirect)) + ret = (u32)-1; + else +#endif + { + u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources; + ret = __poll_portal_slow(p, is); + qm_isr_status_clear(&p->p, ret); + } + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_poll_slow); + +/* Legacy wrapper */ +void qman_poll(void) +{ + struct qman_portal *p = get_raw_affine_portal(); +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (unlikely(p->sharing_redirect)) + goto done; +#endif + if ((~p->irq_sources) & QM_PIRQ_SLOW) { + if (!(p->slowpoll--)) { + u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources; + u32 active = __poll_portal_slow(p, is); + if (active) { + qm_isr_status_clear(&p->p, active); + p->slowpoll = SLOW_POLL_BUSY; + } else + p->slowpoll = SLOW_POLL_IDLE; + } + } + if ((~p->irq_sources) & QM_PIRQ_DQRI) + __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT); +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE +done: +#endif + put_affine_portal(); +} +EXPORT_SYMBOL(qman_poll); + +/* Recovery processing. */ +static int recovery_poll_mr(struct qman_portal *p, u32 fqid) +{ + const struct qm_mr_entry *msg; + enum { + wait_for_fqrn, + wait_for_fqrl, + done + } state = wait_for_fqrn; + u8 v, fqs = 0; + +loop: + qm_mr_pvb_update(&p->p); + msg = qm_mr_current(&p->p); + if (!msg) { + cpu_relax(); + goto loop; + } + v = msg->verb & QM_MR_VERB_TYPE_MASK; + /* all MR messages have "fqid" in the same place */ + if (msg->fq.fqid != fqid) { +ignore_msg: + pr_warning("recovery_poll_mr(), ignoring msg 0x%02x for " + "FQID %d\n", v, msg->fq.fqid); + goto next_msg; + } + if (state == wait_for_fqrn) { + if ((v != QM_MR_VERB_FQRN) && (v != QM_MR_VERB_FQRNI)) + goto ignore_msg; + fqs = msg->fq.fqs; + if (!(fqs & QM_MR_FQS_ORLPRESENT)) + state = done; + else + state = wait_for_fqrl; + } else { + if (v != QM_MR_VERB_FQRL) + goto ignore_msg; + state = done; + } +next_msg: + qm_mr_next(&p->p); + qm_mr_cci_consume(&p->p, 1); + if (state != done) + goto loop; + return (fqs & QM_MR_FQS_NOTEMPTY) ? 1 : 0; +} +static unsigned int recovery_poll_dqrr(struct qman_portal *p, u32 fqid) +{ + const struct qm_dqrr_entry *dq; + u8 empty = 0, num_fds = 0; + +loop: + qm_dqrr_pvb_update(&p->p, 0); + dq = qm_dqrr_current(&p->p); + if (!dq) { + cpu_relax(); + goto loop; + } + if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED)) { +ignore_dqrr: + pr_warning("recovery_poll_dqrr(), ignoring dqrr %02x:%02x " + "for FQID %d\n", + dq->verb & QM_DQRR_VERB_MASK, dq->stat, dq->fqid); + goto next_dqrr; + } + if (dq->fqid != fqid) + goto ignore_dqrr; + if (dq->stat & QM_DQRR_STAT_FD_VALID) + num_fds++; + if (dq->stat & QM_DQRR_STAT_FQ_EMPTY) + empty = 1; +next_dqrr: + qm_dqrr_next(&p->p); + qm_dqrr_cci_consume(&p->p, 1); + if (!empty) + goto loop; + return num_fds; +} +int qman_recovery_cleanup_fq(u32 fqid) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + int ret = 0; + unsigned int num_fds = 0; + const char *s; + u8 state; + + /* Lock this whole flow down via the portal's "vdqcr" */ + PORTAL_IRQ_LOCK(p, irqflags); + BUG_ON(!(p->bits & PORTAL_BITS_RECOVERY)); + if (p->vdqcr_owned) + ret = -EBUSY; + else + p->vdqcr_owned = (void *)1; + PORTAL_IRQ_UNLOCK(p, irqflags); + if (ret) + goto out; + + /* Query the FQ's state */ + mcc = qm_mc_start(&p->p); + mcc->queryfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP); + if (mcr->result != QM_MCR_RESULT_OK) { + ret = -EIO; + goto out; + } + state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK; + + /* OOS: nothing to do */ + if (state == QM_MCR_NP_STATE_OOS) + goto out; + /* Otherwise: must be retired */ + if (state != QM_MCR_NP_STATE_RETIRED) { + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == + QM_MCR_VERB_ALTER_RETIRE); + if ((mcr->result != QM_MCR_RESULT_OK) && + (mcr->result != QM_MCR_RESULT_PENDING)) { + ret = -EIO; + goto out; + } + ret = recovery_poll_mr(p, fqid); + if (!ret) + /* FQ empty */ + goto oos; + } + /* Drain till empty */ + qm_dqrr_vdqcr_set(&p->p, fqid & 0x00ffffff); + num_fds = recovery_poll_dqrr(p, fqid); + +oos: + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS); + if (mcr->result != QM_MCR_RESULT_OK) + ret = -EIO; + /* done */ + s = (state == QM_MCR_NP_STATE_RETIRED) ? "retired" : + (state == QM_MCR_NP_STATE_PARKED) ? "parked" : "scheduled"; + pr_info("Qman: %s FQID %d recovered (%d frames)\n", s, fqid, num_fds); +out: + PORTAL_IRQ_LOCK(p, irqflags); + p->vdqcr_owned = NULL; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_recovery_cleanup_fq); + +/* called from qman_driver.c::qman_recovery_exit() only (if exporting, use + * get_raw_affine_portal() and check for the "SLAVE" bit). */ +void qman_recovery_exit_local(void) +{ + struct qman_portal *p = get_affine_portal(); + BUG_ON(!(p->bits & PORTAL_BITS_RECOVERY)); + /* Reinitialise DQRR using expected settings */ + qm_dqrr_finish(&p->p); + post_recovery(p, p->config); + clear_bits(PORTAL_BITS_RECOVERY, &p->bits); + if (qm_dqrr_init(&p->p, p->config, qm_dqrr_dpush, qm_dqrr_pvb, + QM_DQRR_CMODE, DQRR_MAXFILL, 0)) + panic("Qman DQRR initialisation failed, recovery broken"); + qm_dqrr_sdqcr_set(&p->p, p->sdqcr); + qm_isr_status_clear(&p->p, 0xffffffff); + qm_isr_uninhibit(&p->p); + put_affine_portal(); +} + +void qman_stop_dequeues(void) +{ + struct qman_portal *p = get_affine_portal(); + qman_stop_dequeues_ex(p); + put_affine_portal(); +} +EXPORT_SYMBOL(qman_stop_dequeues); + +void qman_start_dequeues(void) +{ + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + PORTAL_IRQ_LOCK(p, irqflags); + DPA_ASSERT(p->dqrr_disable_ref > 0); + if (!(--p->dqrr_disable_ref)) + qm_dqrr_set_maxfill(&p->p, DQRR_MAXFILL); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); +} +EXPORT_SYMBOL(qman_start_dequeues); + +void qman_static_dequeue_add(u32 pools) +{ + unsigned long irqflags __maybe_unused; + struct qman_portal *p = get_affine_portal(); + PORTAL_IRQ_LOCK(p, irqflags); + pools &= p->config->public_cfg.pools; + p->sdqcr |= pools; + qm_dqrr_sdqcr_set(&p->p, p->sdqcr); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); +} +EXPORT_SYMBOL(qman_static_dequeue_add); + +void qman_static_dequeue_del(u32 pools) +{ + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + PORTAL_IRQ_LOCK(p, irqflags); + pools &= p->config->public_cfg.pools; + p->sdqcr &= ~pools; + qm_dqrr_sdqcr_set(&p->p, p->sdqcr); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); +} +EXPORT_SYMBOL(qman_static_dequeue_del); + +u32 qman_static_dequeue_get(void) +{ + struct qman_portal *p = get_affine_portal(); + u32 ret = p->sdqcr; + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_static_dequeue_get); + +void qman_dca(struct qm_dqrr_entry *dq, int park_request) +{ + struct qman_portal *p = get_affine_portal(); + qm_dqrr_cdc_consume_1ptr(&p->p, dq, park_request); + put_affine_portal(); +} +EXPORT_SYMBOL(qman_dca); + +/*******************/ +/* Frame queue API */ +/*******************/ + +static const char *mcr_result_str(u8 result) +{ + switch (result) { + case QM_MCR_RESULT_NULL: + return "QM_MCR_RESULT_NULL"; + case QM_MCR_RESULT_OK: + return "QM_MCR_RESULT_OK"; + case QM_MCR_RESULT_ERR_FQID: + return "QM_MCR_RESULT_ERR_FQID"; + case QM_MCR_RESULT_ERR_FQSTATE: + return "QM_MCR_RESULT_ERR_FQSTATE"; + case QM_MCR_RESULT_ERR_NOTEMPTY: + return "QM_MCR_RESULT_ERR_NOTEMPTY"; + case QM_MCR_RESULT_PENDING: + return "QM_MCR_RESULT_PENDING"; + case QM_MCR_RESULT_ERR_BADCOMMAND: + return "QM_MCR_RESULT_ERR_BADCOMMAND"; + } + return ""; +} + +int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq) +{ + struct qm_fqd fqd; + struct qm_mcr_queryfq_np np; + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p; + unsigned long irqflags __maybe_unused; + + if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID) { + fqid = qm_fq_new(); + if (!fqid) + return -ENOMEM; + } + spin_lock_init(&fq->fqlock); + fq->fqid = fqid; + fq->flags = flags; + fq->state = qman_fq_state_oos; + fq->cgr_groupid = 0; +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + if (unlikely(find_empty_fq_table_entry(&fq->key, fq))) + return -ENOMEM; +#endif + if (!(flags & QMAN_FQ_FLAG_AS_IS) || (flags & QMAN_FQ_FLAG_NO_MODIFY)) + return 0; + /* Everything else is AS_IS support */ + p = get_affine_portal(); + PORTAL_IRQ_LOCK(p, irqflags); + mcc = qm_mc_start(&p->p); + mcc->queryfq.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ); + if (mcr->result != QM_MCR_RESULT_OK) { + pr_err("QUERYFQ failed: %s\n", mcr_result_str(mcr->result)); + goto err; + } + fqd = mcr->queryfq.fqd; + mcc = qm_mc_start(&p->p); + mcc->queryfq_np.fqid = fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ_NP); + if (mcr->result != QM_MCR_RESULT_OK) { + pr_err("QUERYFQ_NP failed: %s\n", mcr_result_str(mcr->result)); + goto err; + } + np = mcr->queryfq_np; + /* Phew, have queryfq and queryfq_np results, stitch together + * the FQ object from those. */ + fq->cgr_groupid = fqd.cgid; + switch (np.state & QM_MCR_NP_STATE_MASK) { + case QM_MCR_NP_STATE_OOS: + break; + case QM_MCR_NP_STATE_RETIRED: + fq->state = qman_fq_state_retired; + if (np.frm_cnt) + fq_set(fq, QMAN_FQ_STATE_NE); + break; + case QM_MCR_NP_STATE_TEN_SCHED: + case QM_MCR_NP_STATE_TRU_SCHED: + case QM_MCR_NP_STATE_ACTIVE: + fq->state = qman_fq_state_sched; + if (np.state & QM_MCR_NP_STATE_R) + fq_set(fq, QMAN_FQ_STATE_CHANGING); + break; + case QM_MCR_NP_STATE_PARKED: + fq->state = qman_fq_state_parked; + break; + default: + DPA_ASSERT(NULL == "invalid FQ state"); + } + if (fqd.fq_ctrl & QM_FQCTRL_CGE) + fq->state |= QMAN_FQ_STATE_CGR_EN; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return 0; +err: + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID) + qm_fq_free(fqid); + return -EIO; +} +EXPORT_SYMBOL(qman_create_fq); + +void qman_destroy_fq(struct qman_fq *fq, u32 flags __maybe_unused) +{ + /* We don't need to lock the FQ as it is a pre-condition that the FQ be + * quiesced. Instead, run some checks. */ + switch (fq->state) { + case qman_fq_state_parked: + DPA_ASSERT(flags & QMAN_FQ_DESTROY_PARKED); + case qman_fq_state_oos: + if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) + qm_fq_free(fq->fqid); +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + clear_fq_table_entry(fq->key); +#endif + return; + default: + break; + } + DPA_ASSERT(NULL == "qman_free_fq() on unquiesced FQ!"); +} +EXPORT_SYMBOL(qman_destroy_fq); + +u32 qman_fq_fqid(struct qman_fq *fq) +{ + return fq->fqid; +} +EXPORT_SYMBOL(qman_fq_fqid); + +void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags) +{ + if (state) + *state = fq->state; + if (flags) + *flags = fq->flags; +} +EXPORT_SYMBOL(qman_fq_state); + +int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p; + unsigned long irqflags __maybe_unused; + u8 res, myverb = (flags & QMAN_INITFQ_FLAG_SCHED) ? + QM_MCC_VERB_INITFQ_SCHED : QM_MCC_VERB_INITFQ_PARKED; + + DPA_ASSERT((fq->state == qman_fq_state_oos) || + (fq->state == qman_fq_state_parked)); +#ifdef CONFIG_FSL_DPA_CHECKING + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) + return -EINVAL; +#endif + if (opts && (opts->we_mask & QM_INITFQ_WE_OAC)) { + /* OAC not supported on rev1.0 */ + if (unlikely(qman_ip_rev == QMAN_REV10)) + return -EINVAL; + /* And can't be set at the same time as TDTHRESH */ + if (opts->we_mask & QM_INITFQ_WE_TDTHRESH) + return -EINVAL; + } + /* Issue an INITFQ_[PARKED|SCHED] management command */ + p = get_affine_portal(); + PORTAL_IRQ_LOCK(p, irqflags); + FQLOCK(fq); + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) || + ((fq->state != qman_fq_state_oos) && + (fq->state != qman_fq_state_parked)))) { + FQUNLOCK(fq); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return -EBUSY; + } + mcc = qm_mc_start(&p->p); + if (opts) + mcc->initfq = *opts; + mcc->initfq.fqid = fq->fqid; + mcc->initfq.count = 0; + /* If INITFQ_FLAG_NULL is passed, contextB is set to zero. Otherwise, + * if the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a + * demux pointer. Otherwise, TO_DCPORTAL is set, so the caller-provided + * value is allowed to stand, don't overwrite it. */ + if ((flags & QMAN_INITFQ_FLAG_NULL) || + fq_isclear(fq, QMAN_FQ_FLAG_TO_DCPORTAL)) { + dma_addr_t phys_fq; + mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTB; +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + mcc->initfq.fqd.context_b = (flags & QMAN_INITFQ_FLAG_NULL) ? + 0 : fq->key; +#else + mcc->initfq.fqd.context_b = (flags & QMAN_INITFQ_FLAG_NULL) ? + 0 : (u32)(uintptr_t)fq; +#endif + /* and the physical address - NB, if the user wasn't trying to + * set CONTEXTA, clear the stashing settings. */ + if (!(mcc->initfq.we_mask & QM_INITFQ_WE_CONTEXTA)) { + mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; + memset(&mcc->initfq.fqd.context_a, 0, + sizeof(mcc->initfq.fqd.context_a)); + } else { + phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq), + DMA_TO_DEVICE); + qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq); + } + } + if (flags & QMAN_INITFQ_FLAG_LOCAL) { + mcc->initfq.fqd.dest.channel = p->config->public_cfg.channel; + if (!(mcc->initfq.we_mask & QM_INITFQ_WE_DESTWQ)) { + mcc->initfq.we_mask |= QM_INITFQ_WE_DESTWQ; + mcc->initfq.fqd.dest.wq = 4; + } + } + qm_mc_commit(&p->p, myverb); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb); + res = mcr->result; + if (res != QM_MCR_RESULT_OK) { + FQUNLOCK(fq); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return -EIO; + } + if (opts) { + if (opts->we_mask & QM_INITFQ_WE_FQCTRL) { + if (opts->fqd.fq_ctrl & QM_FQCTRL_CGE) + fq_set(fq, QMAN_FQ_STATE_CGR_EN); + else + fq_clear(fq, QMAN_FQ_STATE_CGR_EN); + } + if (opts->we_mask & QM_INITFQ_WE_CGID) + fq->cgr_groupid = opts->fqd.cgid; + } + fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ? + qman_fq_state_sched : qman_fq_state_parked; + FQUNLOCK(fq); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return 0; +} +EXPORT_SYMBOL(qman_init_fq); + +int qman_schedule_fq(struct qman_fq *fq) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p; + unsigned long irqflags __maybe_unused; + int ret = 0; + u8 res; + + DPA_ASSERT(fq->state == qman_fq_state_parked); +#ifdef CONFIG_FSL_DPA_CHECKING + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) + return -EINVAL; +#endif + /* Issue a ALTERFQ_SCHED management command */ + p = get_affine_portal(); + PORTAL_IRQ_LOCK(p, irqflags); + FQLOCK(fq); + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) || + (fq->state != qman_fq_state_parked))) { + ret = -EBUSY; + goto out; + } + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_SCHED); + res = mcr->result; + if (res != QM_MCR_RESULT_OK) { + ret = -EIO; + goto out; + } + fq->state = qman_fq_state_sched; +out: + FQUNLOCK(fq); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_schedule_fq); + +int qman_retire_fq(struct qman_fq *fq, u32 *flags) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p; + unsigned long irqflags __maybe_unused; + int rval; + u8 res; + + DPA_ASSERT((fq->state == qman_fq_state_parked) || + (fq->state == qman_fq_state_sched)); +#ifdef CONFIG_FSL_DPA_CHECKING + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) + return -EINVAL; +#endif + p = get_affine_portal(); + PORTAL_IRQ_LOCK(p, irqflags); + FQLOCK(fq); + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) || + (fq->state == qman_fq_state_retired) || + (fq->state == qman_fq_state_oos))) { + rval = -EBUSY; + goto out; + } + rval = table_push_fq(p, fq); + if (rval) + goto out; + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_RETIRE); + res = mcr->result; + /* "Elegant" would be to treat OK/PENDING the same way; set CHANGING, + * and defer the flags until FQRNI or FQRN (respectively) show up. But + * "Friendly" is to process OK immediately, and not set CHANGING. We do + * friendly, otherwise the caller doesn't necessarily have a fully + * "retired" FQ on return even if the retirement was immediate. However + * this does mean some code duplication between here and + * fq_state_change(). */ + if (likely(res == QM_MCR_RESULT_OK)) { + rval = 0; + /* Process 'fq' right away, we'll ignore FQRNI */ + if (mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY) + fq_set(fq, QMAN_FQ_STATE_NE); + if (mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT) + fq_set(fq, QMAN_FQ_STATE_ORL); + else + table_del_fq(p, fq); + if (flags) + *flags = fq->flags; + fq->state = qman_fq_state_retired; + if (fq->cb.fqs) { + /* Another issue with supporting "immediate" retirement + * is that we're forced to drop FQRNIs, because by the + * time they're seen it may already be "too late" (the + * fq may have been OOS'd and free()'d already). But if + * the upper layer wants a callback whether it's + * immediate or not, we have to fake a "MR" entry to + * look like an FQRNI... */ + struct qm_mr_entry msg; + msg.verb = QM_MR_VERB_FQRNI; + msg.fq.fqs = mcr->alterfq.fqs; + msg.fq.fqid = fq->fqid; +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + msg.fq.contextB = fq->key; +#else + msg.fq.contextB = (u32)(uintptr_t)fq; +#endif + fq->cb.fqs(p, fq, &msg); + } + } else if (res == QM_MCR_RESULT_PENDING) { + rval = 1; + fq_set(fq, QMAN_FQ_STATE_CHANGING); + } else { + rval = -EIO; + table_del_fq(p, fq); + } +out: + FQUNLOCK(fq); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return rval; +} +EXPORT_SYMBOL(qman_retire_fq); + +int qman_oos_fq(struct qman_fq *fq) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p; + unsigned long irqflags __maybe_unused; + int ret = 0; + u8 res; + + DPA_ASSERT(fq->state == qman_fq_state_retired); +#ifdef CONFIG_FSL_DPA_CHECKING + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) + return -EINVAL; +#endif + p = get_affine_portal(); + PORTAL_IRQ_LOCK(p, irqflags); + FQLOCK(fq); + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_BLOCKOOS)) || + (fq->state != qman_fq_state_retired))) { + ret = -EBUSY; + goto out; + } + mcc = qm_mc_start(&p->p); + mcc->alterfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS); + res = mcr->result; + if (res != QM_MCR_RESULT_OK) { + ret = -EIO; + goto out; + } + fq->state = qman_fq_state_oos; +out: + FQUNLOCK(fq); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_oos_fq); + +int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + u8 res; + + PORTAL_IRQ_LOCK(p, irqflags); + mcc = qm_mc_start(&p->p); + mcc->queryfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ); + res = mcr->result; + if (res == QM_MCR_RESULT_OK) + *fqd = mcr->queryfq.fqd; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (res != QM_MCR_RESULT_OK) + return -EIO; + return 0; +} +EXPORT_SYMBOL(qman_query_fq); + +int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + u8 res; + + PORTAL_IRQ_LOCK(p, irqflags); + mcc = qm_mc_start(&p->p); + mcc->queryfq.fqid = fq->fqid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP); + res = mcr->result; + if (res == QM_MCR_RESULT_OK) + *np = mcr->queryfq_np; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (res != QM_MCR_RESULT_OK) + return -EIO; + return 0; +} +EXPORT_SYMBOL(qman_query_fq_np); + +int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + u8 res, myverb; + + PORTAL_IRQ_LOCK(p, irqflags); + myverb = (query_dedicated) ? QM_MCR_VERB_QUERYWQ_DEDICATED : + QM_MCR_VERB_QUERYWQ; + mcc = qm_mc_start(&p->p); + mcc->querywq.channel.id = wq->channel.id; + qm_mc_commit(&p->p, myverb); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb); + res = mcr->result; + if (res == QM_MCR_RESULT_OK) + *wq = mcr->querywq; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (res != QM_MCR_RESULT_OK) { + pr_err("QUERYWQ failed: %s\n", mcr_result_str(res)); + return -EIO; + } + return 0; +} +EXPORT_SYMBOL(qman_query_wq); + +int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt, + struct qm_mcr_cgrtestwrite *result) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + u8 res; + + PORTAL_IRQ_LOCK(p, irqflags); + mcc = qm_mc_start(&p->p); + mcc->cgrtestwrite.cgid = cgr->cgrid; + mcc->cgrtestwrite.i_bcnt_hi = (u8)(i_bcnt >> 32); + mcc->cgrtestwrite.i_bcnt_lo = (u32)i_bcnt; + qm_mc_commit(&p->p, QM_MCC_VERB_CGRTESTWRITE); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_CGRTESTWRITE); + res = mcr->result; + if (res == QM_MCR_RESULT_OK) + *result = mcr->cgrtestwrite; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (res != QM_MCR_RESULT_OK) { + pr_err("CGR TEST WRITE failed: %s\n", mcr_result_str(res)); + return -EIO; + } + return 0; +} +EXPORT_SYMBOL(qman_testwrite_cgr); + +int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *cgrd) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + u8 res; + + PORTAL_IRQ_LOCK(p, irqflags); + mcc = qm_mc_start(&p->p); + mcc->querycgr.cgid = cgr->cgrid; + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCGR); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR); + res = mcr->result; + if (res == QM_MCR_RESULT_OK) + *cgrd = mcr->querycgr; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (res != QM_MCR_RESULT_OK) { + pr_err("QUERY_CGR failed: %s\n", mcr_result_str(res)); + return -EIO; + } + return 0; +} +EXPORT_SYMBOL(qman_query_cgr); + +int qman_query_congestion(struct qm_mcr_querycongestion *congestion) +{ + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + u8 res; + + PORTAL_IRQ_LOCK(p, irqflags); + qm_mc_start(&p->p); + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == + QM_MCC_VERB_QUERYCONGESTION); + res = mcr->result; + if (res == QM_MCR_RESULT_OK) + *congestion = mcr->querycongestion; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (res != QM_MCR_RESULT_OK) { + pr_err("QUERY_CONGESTION failed: %s\n", mcr_result_str(res)); + return -EIO; + } + return 0; +} +EXPORT_SYMBOL(qman_query_congestion); + +/* internal function used as a wait_event() expression */ +static int set_vdqcr(struct qman_portal **p, struct qman_fq *fq, u32 vdqcr) +{ + unsigned long irqflags __maybe_unused; + int ret = -EBUSY; + *p = get_affine_portal(); + PORTAL_IRQ_LOCK(*p, irqflags); + if (!(*p)->vdqcr_owned) { + FQLOCK(fq); + if (fq_isset(fq, QMAN_FQ_STATE_VDQCR)) + goto escape; + fq_set(fq, QMAN_FQ_STATE_VDQCR); + FQUNLOCK(fq); + (*p)->vdqcr_owned = fq; + ret = 0; + } +escape: + PORTAL_IRQ_UNLOCK(*p, irqflags); + if (!ret) + qm_dqrr_vdqcr_set(&(*p)->p, vdqcr); + put_affine_portal(); + return ret; +} + +#ifdef CONFIG_FSL_DPA_CAN_WAIT +static int wait_vdqcr_start(struct qman_portal **p, struct qman_fq *fq, + u32 vdqcr, u32 flags) +{ + int ret = 0; + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) + ret = wait_event_interruptible(affine_queue, + !(ret = set_vdqcr(p, fq, vdqcr))); + else + wait_event(affine_queue, !(ret = set_vdqcr(p, fq, vdqcr))); + return ret; +} +#endif + +int qman_volatile_dequeue(struct qman_fq *fq, u32 flags __maybe_unused, + u32 vdqcr) +{ + struct qman_portal *p; + int ret; + + DPA_ASSERT(!fq || (fq->state == qman_fq_state_parked) || + (fq->state == qman_fq_state_retired)); + DPA_ASSERT(!fq || !(vdqcr & QM_VDQCR_FQID_MASK)); + DPA_ASSERT(!fq || !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); + if (fq) + vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid; +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & QMAN_VOLATILE_FLAG_WAIT) + ret = wait_vdqcr_start(&p, fq, vdqcr, flags); + else +#endif + ret = set_vdqcr(&p, fq, vdqcr); + if (ret) + return ret; + /* VDQCR is set */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & QMAN_VOLATILE_FLAG_FINISH) { + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) + /* NB: don't propagate any error - the caller wouldn't + * know whether the VDQCR was issued or not. A signal + * could arrive after returning anyway, so the caller + * can check signal_pending() if that's an issue. */ + wait_event_interruptible(affine_queue, + !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); + else + wait_event(affine_queue, + !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); + } +#endif + return 0; +} +EXPORT_SYMBOL(qman_volatile_dequeue); + +static noinline void update_eqcr_ci(struct qman_portal *p, u8 avail) +{ + if (avail) + qm_eqcr_cce_prefetch(&p->p); + else + qm_eqcr_cce_update(&p->p); +} + +int qman_eqcr_is_empty(void) +{ + unsigned long irqflags __maybe_unused; + struct qman_portal *p = get_affine_portal(); + u8 avail; + + PORTAL_IRQ_LOCK(p, irqflags); + update_eqcr_ci(p, 0); + avail = qm_eqcr_get_fill(&p->p); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return (avail == 0); +} +EXPORT_SYMBOL(qman_eqcr_is_empty); + +static inline struct qm_eqcr_entry *try_eq_start(struct qman_portal **p, + unsigned long *irqflags __maybe_unused, + struct qman_fq *fq, + const struct qm_fd *fd, + u32 flags) +{ + struct qm_eqcr_entry *eq; + u8 avail; + + *p = get_affine_portal(); + PORTAL_IRQ_LOCK(*p, (*irqflags)); +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { + if ((*p)->eqci_owned) { + PORTAL_IRQ_UNLOCK(*p, (*irqflags)); + put_affine_portal(); + return NULL; + } + (*p)->eqci_owned = fq; + } +#endif + avail = qm_eqcr_get_avail(&(*p)->p); + if (avail < 2) + update_eqcr_ci(*p, avail); + eq = qm_eqcr_start(&(*p)->p); + if (unlikely(!eq)) { +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) + (*p)->eqci_owned = NULL; +#endif + PORTAL_IRQ_UNLOCK(*p, (*irqflags)); + put_affine_portal(); + return NULL; + } + if (flags & QMAN_ENQUEUE_FLAG_DCA) + eq->dca = QM_EQCR_DCA_ENABLE | + ((flags & QMAN_ENQUEUE_FLAG_DCA_PARK) ? + QM_EQCR_DCA_PARK : 0) | + ((flags >> 8) & QM_EQCR_DCA_IDXMASK); + eq->fqid = fq->fqid; +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + eq->tag = fq->key; +#else + eq->tag = (u32)(uintptr_t)fq; +#endif + /* From p4080 rev1 -> rev2, the FD struct's address went from 48-bit to + * 40-bit but rev1 chips will still interpret it as 48-bit, meaning we + * have to scrub the upper 8-bits, just in case the user left noise in + * there. Doing this selectively via a run-time check of the h/w + * revision (as we do for most errata, for example) is too slow in this + * critical path code. The most inexpensive way to handle this is just + * to reinterpret the FD as 4 32-bit words and to mask the first word + * appropriately, irrespecitive of the h/w revision. The struct fields + * corresponding to this word are; + * u8 dd:2; + * u8 liodn_offset:6; + * u8 bpid; + * u8 eliodn_offset:4; + * u8 __reserved:4; + * u8 addr_hi; + * So we mask this word with 0xc0ff00ff, which implicitly scrubs out + * liodn_offset, eliodn_offset, and __reserved - the latter two fields + * are interpreted as the 8 msbits of the 48-bit address in the case of + * rev1. + */ + { + const u32 *src = (const u32 *)fd; + u32 *dest = (u32 *)&eq->fd; + dest[0] = src[0] & 0xc0ff00ff; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + } + return eq; +} + +#ifdef CONFIG_FSL_DPA_CAN_WAIT +static noinline struct qm_eqcr_entry *__wait_eq_start(struct qman_portal **p, + unsigned long *irqflags __maybe_unused, + struct qman_fq *fq, + const struct qm_fd *fd, + u32 flags) +{ + struct qm_eqcr_entry *eq = try_eq_start(p, irqflags, fq, fd, flags); + if (!eq) + qm_eqcr_set_ithresh(&(*p)->p, EQCR_ITHRESH); + return eq; +} +static noinline struct qm_eqcr_entry *wait_eq_start(struct qman_portal **p, + unsigned long *irqflags __maybe_unused, + struct qman_fq *fq, + const struct qm_fd *fd, + u32 flags) +{ + struct qm_eqcr_entry *eq; + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) + wait_event_interruptible(affine_queue, + (eq = __wait_eq_start(p, irqflags, fq, fd, flags))); + else + wait_event(affine_queue, + (eq = __wait_eq_start(p, irqflags, fq, fd, flags))); + return eq; +} +#endif + +int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags) +{ + struct qman_portal *p; + struct qm_eqcr_entry *eq; + unsigned long irqflags __maybe_unused; + +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & QMAN_ENQUEUE_FLAG_WAIT) + eq = wait_eq_start(&p, &irqflags, fq, fd, flags); + else +#endif + eq = try_eq_start(&p, &irqflags, fq, fd, flags); + if (!eq) + return -EBUSY; + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE | + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); + /* Factor the below out, it's used from qman_enqueue_orp() too */ + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) + wait_event_interruptible(affine_queue, + (p->eqci_owned != fq)); + else + wait_event(affine_queue, (p->eqci_owned != fq)); + } +#endif + return 0; +} +EXPORT_SYMBOL(qman_enqueue); + +int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags, + struct qman_fq *orp, u16 orp_seqnum) +{ + struct qman_portal *p; + struct qm_eqcr_entry *eq; + unsigned long irqflags __maybe_unused; + +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & QMAN_ENQUEUE_FLAG_WAIT) + eq = wait_eq_start(&p, &irqflags, fq, fd, flags); + else +#endif + eq = try_eq_start(&p, &irqflags, fq, fd, flags); + if (!eq) + return -EBUSY; + /* Process ORP-specifics here */ + if (flags & QMAN_ENQUEUE_FLAG_NLIS) + orp_seqnum |= QM_EQCR_SEQNUM_NLIS; + else { + orp_seqnum &= ~QM_EQCR_SEQNUM_NLIS; + if (flags & QMAN_ENQUEUE_FLAG_NESN) + orp_seqnum |= QM_EQCR_SEQNUM_NESN; + else + /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */ + orp_seqnum &= ~QM_EQCR_SEQNUM_NESN; + } + eq->seqnum = orp_seqnum; + eq->orp = orp->fqid; + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_ORP | + ((flags & (QMAN_ENQUEUE_FLAG_HOLE | QMAN_ENQUEUE_FLAG_NESN)) ? + 0 : QM_EQCR_VERB_CMD_ENQUEUE) | + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) + wait_event_interruptible(affine_queue, + (p->eqci_owned != fq)); + else + wait_event(affine_queue, (p->eqci_owned != fq)); + } +#endif + return 0; +} +EXPORT_SYMBOL(qman_enqueue_orp); + +int qman_modify_cgr(struct qman_cgr *cgr, u32 flags, + struct qm_mcc_initcgr *opts) +{ + struct qm_mc_command *mcc; + struct qm_mc_result *mcr; + struct qman_portal *p = get_affine_portal(); + unsigned long irqflags __maybe_unused; + u8 res; + u8 verb = QM_MCC_VERB_MODIFYCGR; + + /* frame mode not supported on rev1.0 */ + if (unlikely(qman_ip_rev == QMAN_REV10)) { + if (opts && (opts->we_mask & QM_CGR_WE_MODE) && + opts->cgr.mode == QMAN_CGR_MODE_FRAME) { + put_affine_portal(); + return -EIO; + } + } + PORTAL_IRQ_LOCK(p, irqflags); + mcc = qm_mc_start(&p->p); + if (opts) + mcc->initcgr = *opts; + mcc->initcgr.cgid = cgr->cgrid; + if (flags & QMAN_CGR_FLAG_USE_INIT) + verb = QM_MCC_VERB_INITCGR; + qm_mc_commit(&p->p, verb); + while (!(mcr = qm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == verb); + res = mcr->result; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return (res == QM_MCR_RESULT_OK) ? 0 : -EIO; +} +EXPORT_SYMBOL(qman_modify_cgr); + +#define TARG_MASK(n) (0x80000000 >> (n->config->public_cfg.channel - \ + qm_channel_swportal0)) + +int qman_create_cgr(struct qman_cgr *cgr, u32 flags, + struct qm_mcc_initcgr *opts) +{ + unsigned long irqflags __maybe_unused; + struct qm_mcr_querycgr cgr_state; + struct qm_mcc_initcgr local_opts; + int ret; + struct qman_portal *p; + + /* We have to check that the provided CGRID is within the limits of the + * data-structures, for obvious reasons. However we'll let h/w take + * care of determining whether it's within the limits of what exists on + * the SoC. */ + if (cgr->cgrid >= __CGR_NUM) + return -EINVAL; + + p = get_affine_portal(); + + memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr)); + cgr->chan = p->config->public_cfg.channel; + spin_lock_irqsave(&p->cgr_lock, irqflags); + + /* if no opts specified and I'm not the first for this portal, just add + * to the list */ + if ((opts == NULL) && !list_empty(&p->cgr_cbs[cgr->cgrid])) + goto add_list; + + ret = qman_query_cgr(cgr, &cgr_state); + if (ret) + goto release_lock; + if (opts) + local_opts = *opts; + /* Overwrite TARG */ + local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ | TARG_MASK(p); + local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; + + /* send init if flags indicate so */ + if (opts && (flags & QMAN_CGR_FLAG_USE_INIT)) + ret = qman_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, &local_opts); + else + ret = qman_modify_cgr(cgr, 0, &local_opts); + if (ret) + goto release_lock; +add_list: + list_add(&cgr->node, &p->cgr_cbs[cgr->cgrid]); + + /* Determine if newly added object requires its callback to be called */ + ret = qman_query_cgr(cgr, &cgr_state); + if (ret) { + /* we can't go back, so proceed and return success, but screen + * and wail to the log file */ + pr_crit("CGR HW state partially modified\n"); + ret = 0; + goto release_lock; + } + if (cgr->cb && cgr_state.cgr.cscn_en && qman_cgrs_get(&p->cgrs[1], + cgr->cgrid)) + cgr->cb(p, cgr, 1); +release_lock: + spin_unlock_irqrestore(&p->cgr_lock, irqflags); + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_create_cgr); + +int qman_delete_cgr(struct qman_cgr *cgr) +{ + unsigned long irqflags __maybe_unused; + struct qm_mcr_querycgr cgr_state; + struct qm_mcc_initcgr local_opts; + int ret = 0; + struct qman_portal *p = get_affine_portal(); + + if (cgr->chan != p->config->public_cfg.channel) { + pr_crit("Attempting to delete cgr from different portal " + "than it was create: create 0x%x, delete 0x%x\n", + cgr->chan, p->config->public_cfg.channel); + ret = -EINVAL; + goto put_portal; + } + memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr)); + spin_lock_irqsave(&p->cgr_lock, irqflags); + list_del(&cgr->node); + /* If last in list, CSCN_TARG must be set accordingly */ + if (!list_empty(&p->cgr_cbs[cgr->cgrid])) + goto release_lock; + ret = qman_query_cgr(cgr, &cgr_state); + if (ret) { + /* add back to the list */ + list_add(&cgr->node, &p->cgr_cbs[cgr->cgrid]); + goto release_lock; + } + /* Overwrite TARG */ + local_opts.we_mask = QM_CGR_WE_CSCN_TARG; + local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ & ~(TARG_MASK(p)); + ret = qman_modify_cgr(cgr, 0, &local_opts); + if (ret) + /* add back to the list */ + list_add(&cgr->node, &p->cgr_cbs[cgr->cgrid]); +release_lock: + spin_unlock_irqrestore(&p->cgr_lock, irqflags); +put_portal: + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(qman_delete_cgr); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_private.h +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_private.h @@ -0,0 +1,149 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dpa_sys.h" +#include + +/* Revision info (for errata and feature handling) */ +#define BMAN_REV10 0x0100 +#define BMAN_REV20 0x0200 +extern u16 bman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */ + +/* + * Global variables of the max portal/pool number this bman version supported + */ +extern u16 bman_pool_max; + +/* used by CCSR and portal interrupt code */ +enum bm_isr_reg { + bm_isr_status = 0, + bm_isr_enable = 1, + bm_isr_disable = 2, + bm_isr_inhibit = 3 +}; + +#define BM_ADDR_CE 0 +#define BM_ADDR_CI 1 +struct bm_portal_config { + /* Corenet portal addresses; + * [0]==cache-enabled, [1]==cache-inhibited. */ + __iomem void *addr_virt[2]; + struct resource addr_phys[2]; + /* Allow these to be joined in lists */ + struct list_head list; + /* User-visible portal configuration settings */ + struct bman_portal_config public_cfg; +}; + +#ifdef CONFIG_FSL_BMAN_CONFIG +/* Hooks from bman_driver.c to bman_config.c */ +int bman_init_error_int(struct device_node *node); +#endif + +/* Hooks from bman_driver.c in to bman_high.c */ +struct bman_portal *bman_create_affine_portal( + const struct bm_portal_config *config, + int recovery_mode); +struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect); +const struct bm_portal_config *bman_destroy_affine_portal(void); +void bman_recovery_exit_local(void); + +/* Pool logic in the portal driver, during initialisation, needs to know if + * there's access to CCSR or not (if not, it'll cripple the pool allocator). */ +#ifdef CONFIG_FSL_BMAN_CONFIG +int bman_have_ccsr(void); +#else +#define bman_have_ccsr() 0 +#endif + +/* Stockpile build constants. The _LOW value: when bman_acquire() is called and + * the stockpile fill-level is <= _LOW, an acquire is attempted from h/w but it + * might fail (if the buffer pool is depleted). So this value provides some + * "stagger" in that the bman_acquire() function will only fail if lots of bufs + * are requested at once or if h/w has been tested a couple of times without + * luck. The _HIGH value: when bman_release() is called and the stockpile + * fill-level is >= _HIGH, a release is attempted to h/w but it might fail (if + * the release ring is full). So this value provides some "stagger" so that + * ring-access is retried a couple of times prior to the API returning a + * failure. The following *must* be true; + * BMAN_STOCKPILE_HIGH-BMAN_STOCKPILE_LOW > 8 + * (to avoid thrashing) + * BMAN_STOCKPILE_SZ >= 16 + * (as the release logic expects to either send 8 buffers to hw prior to + * adding the given buffers to the stockpile or add the buffers to the + * stockpile before sending 8 to hw, as the API must be an all-or-nothing + * success/fail.) + */ +#define BMAN_STOCKPILE_SZ 16u /* number of bufs in per-pool cache */ +#define BMAN_STOCKPILE_LOW 2u /* when fill is <= this, acquire from hw */ +#define BMAN_STOCKPILE_HIGH 14u /* when fill is >= this, release to hw */ + +/*************************************************/ +/* BMan s/w corenet portal, low-level i/face */ +/*************************************************/ + +/* Used by all portal interrupt registers except 'inhibit'. NB, some of these + * definitions are exported for use by the bman_irqsource_***() APIs, so are + * commented-out here. */ +#if 0 +#define BM_PIRQ_RCRI 0x00000002 /* RCR Ring (below threshold) */ +#define BM_PIRQ_BSCN 0x00000001 /* Buffer depletion State Change */ +#endif +/* This mask contains all the "irqsource" bits visible to API users */ +#define BM_PIRQ_VISIBLE (BM_PIRQ_RCRI | BM_PIRQ_BSCN) + +/* These are bm__(). So for example, bm_disable_write() means "write + * the disable register" rather than "disable the ability to write". */ +#define bm_isr_status_read(bm) __bm_isr_read(bm, bm_isr_status) +#define bm_isr_status_clear(bm, m) __bm_isr_write(bm, bm_isr_status, m) +#define bm_isr_enable_read(bm) __bm_isr_read(bm, bm_isr_enable) +#define bm_isr_enable_write(bm, v) __bm_isr_write(bm, bm_isr_enable, v) +#define bm_isr_disable_read(bm) __bm_isr_read(bm, bm_isr_disable) +#define bm_isr_disable_write(bm, v) __bm_isr_write(bm, bm_isr_disable, v) +#define bm_isr_inhibit(bm) __bm_isr_write(bm, bm_isr_inhibit, 1) +#define bm_isr_uninhibit(bm) __bm_isr_write(bm, bm_isr_inhibit, 0) + +/* Allocate/release an unreserved buffer pool id */ +int bm_pool_new(u32 *bpid); +void bm_pool_free(u32 bpid); + +#ifdef CONFIG_FSL_BMAN_CONFIG +/* Set depletion thresholds associated with a buffer pool. Requires that the + * operating system have access to Bman CCSR (ie. compiled in support and + * run-time access courtesy of the device-tree). */ +int bm_pool_set(u32 bpid, const u32 *thresholds); +#define BM_POOL_THRESH_SW_ENTER 0 +#define BM_POOL_THRESH_SW_EXIT 1 +#define BM_POOL_THRESH_HW_ENTER 2 +#define BM_POOL_THRESH_HW_EXIT 3 + +#endif /* CONFIG_FSL_BMAN_CONFIG */ + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_test.c +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_test.c @@ -0,0 +1,57 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_test.h" + +MODULE_AUTHOR("Geoff Thorpe"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Bman testing"); + +static int test_init(void) +{ +#ifdef CONFIG_FSL_BMAN_TEST_HIGH + int loop = 1; + while (loop--) + bman_test_high(); +#endif +#ifdef CONFIG_FSL_BMAN_TEST_THRESH + bman_test_thresh(); +#endif + return 0; +} + +static void test_exit(void) +{ +} + +module_init(test_init); +module_exit(test_exit); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_test_high.c +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_test_high.c @@ -0,0 +1,181 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_test.h" +#include "bman_private.h" + +/*************/ +/* constants */ +/*************/ + +#define PORTAL_OPAQUE (void *)0xf00dbeef +#define POOL_OPAQUE (void *)0xdeadabba +#define NUM_BUFS 93 +#define LOOPS 3 +#define BMAN_TOKEN_MASK 0x00FFFFFFFFFFLLU + +/***************/ +/* global vars */ +/***************/ + +static struct bman_pool *pool; +static int depleted; +static struct bm_buffer bufs_in[NUM_BUFS] ____cacheline_aligned; +static struct bm_buffer bufs_out[NUM_BUFS] ____cacheline_aligned; +static int bufs_received; + +/* Predeclare the callback so we can instantiate pool parameters */ +static void depletion_cb(struct bman_portal *, struct bman_pool *, void *, int); + +/**********************/ +/* internal functions */ +/**********************/ + +static void bufs_init(void) +{ + int i; + for (i = 0; i < NUM_BUFS; i++) + bm_buffer_set64(&bufs_in[i], 0xfedc01234567LLU * i); + bufs_received = 0; +} + +static inline int bufs_cmp(const struct bm_buffer *a, const struct bm_buffer *b) +{ + if (bman_ip_rev == BMAN_REV20) { + /* On SoCs with Bman revison 2.0, Bman only respects the 40 + * LS-bits of buffer addresses, masking off the upper 8-bits on + * release commands. The API provides for 48-bit addresses + * because some SoCs support all 48-bits. When generating + * garbage addresses for testing, we either need to zero the + * upper 8-bits when releasing to Bman (otherwise we'll be + * disappointed when the buffers we acquire back from Bman + * don't match), or we need to mask the upper 8-bits off when + * comparing. We do the latter. + */ + if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK) + < (bm_buffer_get64(b) & BMAN_TOKEN_MASK)) + return -1; + if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK) + > (bm_buffer_get64(b) & BMAN_TOKEN_MASK)) + return 1; + } else { + if (bm_buffer_get64(a) < bm_buffer_get64(b)) + return -1; + if (bm_buffer_get64(a) > bm_buffer_get64(b)) + return 1; + } + + return 0; +} + +static void bufs_confirm(void) +{ + int i, j; + for (i = 0; i < NUM_BUFS; i++) { + int matches = 0; + for (j = 0; j < NUM_BUFS; j++) + if (!bufs_cmp(&bufs_in[i], &bufs_out[j])) + matches++; + BUG_ON(matches != 1); + } +} + +/********/ +/* test */ +/********/ + +static void depletion_cb(struct bman_portal *__portal, struct bman_pool *__pool, + void *pool_ctx, int __depleted) +{ + BUG_ON(__pool != pool); + BUG_ON(pool_ctx != POOL_OPAQUE); + depleted = __depleted; +} + +void bman_test_high(void) +{ + struct bman_pool_params pparams = { + .flags = BMAN_POOL_FLAG_DEPLETION | BMAN_POOL_FLAG_DYNAMIC_BPID, + .cb = depletion_cb, + .cb_ctx = POOL_OPAQUE, + }; + int i, loops = LOOPS; + + bufs_init(); + + pr_info("BMAN: --- starting high-level test ---\n"); + + pool = bman_new_pool(&pparams); + BUG_ON(!pool); + + /*******************/ + /* Release buffers */ + /*******************/ +do_loop: + i = 0; + while (i < NUM_BUFS) { + u32 flags = BMAN_RELEASE_FLAG_WAIT; + int num = 8; + if ((i + num) > NUM_BUFS) + num = NUM_BUFS - i; + if ((i + num) == NUM_BUFS) + flags |= BMAN_RELEASE_FLAG_WAIT_SYNC; + if (bman_release(pool, bufs_in + i, num, flags)) + panic("bman_release() failed\n"); + i += num; + } + + /*******************/ + /* Acquire buffers */ + /*******************/ + while (i > 0) { + int tmp, num = 8; + if (num > i) + num = i; + tmp = bman_acquire(pool, bufs_out + i - num, num, 0); + BUG_ON(tmp != num); + i -= num; + } + i = bman_acquire(pool, NULL, 1, 0); + BUG_ON(i > 0); + + bufs_confirm(); + + if (--loops) + goto do_loop; + + /************/ + /* Clean up */ + /************/ + bman_free_pool(pool); + pr_info("BMAN: --- finished high-level test ---\n"); +} + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/Makefile +++ linux-3.13.0/drivers/staging/fsl_qbman/Makefile @@ -0,0 +1,23 @@ +# Bman +obj-$(CONFIG_FSL_BMAN_CONFIG) += bman_config.o bman_driver.o +obj-$(CONFIG_FSL_BMAN_PORTAL) += bman_high.o +obj-$(CONFIG_FSL_BMAN_TEST) += bman_tester.o +obj-$(CONFIG_FSL_BMAN_DEBUGFS) += bman_debugfs_interface.o +bman_tester-y = bman_test.o +bman_tester-$(CONFIG_FSL_BMAN_TEST_HIGH) += bman_test_high.o +bman_tester-$(CONFIG_FSL_BMAN_TEST_THRESH) += bman_test_thresh.o +bman_debugfs_interface-y = bman_debugfs.o + +# Qman +obj-$(CONFIG_FSL_QMAN) += qman_utility.o qman_fqalloc.o +obj-$(CONFIG_FSL_QMAN_CONFIG) += qman_config.o qman_driver.o +obj-$(CONFIG_FSL_QMAN_PORTAL) += qman_high.o +obj-$(CONFIG_FSL_QMAN_TEST) += qman_tester.o +qman_tester-y = qman_test.o qman_test_hotpotato.o \ + qman_test_high.o +qman_tester-$(CONFIG_FSL_QMAN_TEST_ERRATA) += qman_test_errata.o +obj-$(CONFIG_FSL_QMAN_DEBUGFS) += qman_debugfs_interface.o +qman_debugfs_interface-y = qman_debugfs.o + +# USDPAA +obj-$(CONFIG_FSL_DPA_UIO) += dpa_uio.o --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_driver.c +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_driver.c @@ -0,0 +1,588 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "bman_private.h" + +/* + * Global variables of the max portal/pool number this bman version supported + */ +u16 bman_ip_rev; +EXPORT_SYMBOL(bman_ip_rev); +u16 bman_pool_max; +EXPORT_SYMBOL(bman_pool_max); + +/*****************/ +/* Portal driver */ +/*****************/ + +/* Compatibility behaviour (when no bpool-range is present) is that; + * (a) on a control plane, all pools that aren't explicitly mentioned in the dtb + * are available for allocation, + * (b) on a non-control plane, there is never any allocation possible at all. + * + * New behaviour is that if any "fsl,bpool-range" nodes are declared, they + * declare what is available for allocation, and this is independent of which + * pools are/aren't mentioned in the dtb. Eg. to stipulate that no allocation is + * possible, a fsl,bpool-range should be specified with zero items in it. + * + * This "pools" struct contains the allocator, and "explicit allocator" + * indicates whether the range is seeded explicitly (via at least one range) or + * implicitly (by being the set of pools that aren't declared). + */ +static struct bman_depletion pools; +static u8 num_pools; +static DEFINE_SPINLOCK(pools_lock); +static int explicit_allocator; + +static struct dpa_uio_class bman_uio = { + .list = LIST_HEAD_INIT(bman_uio.list), + .dev_prefix = "bman-uio-" +}; +const struct dpa_uio_class *dpa_uio_bman(void) +{ + return &bman_uio; +} +EXPORT_SYMBOL(dpa_uio_bman); + +static int __bm_pool_add(u32 bpid, u32 *cfg, int triplets) +{ + u64 total = 0; + BUG_ON(bpid >= bman_pool_max); +#ifdef CONFIG_FSL_BMAN_PORTAL + while (triplets--) { + struct bman_pool_params params = { + .bpid = bpid, + .flags = BMAN_POOL_FLAG_ONLY_RELEASE + }; + u64 c = ((u64)cfg[0] << 32) | cfg[1]; + u64 d = ((u64)cfg[2] << 32) | cfg[3]; + u64 b = ((u64)cfg[4] << 32) | cfg[5]; + struct bman_pool *pobj = bman_new_pool(¶ms); + if (!pobj) + return -ENOMEM; + while (c) { + struct bm_buffer bufs[8]; + int ret, num_bufs = 0; + do { + BUG_ON(b > 0xffffffffffffull); + bufs[num_bufs].bpid = bpid; + bm_buffer_set64(&bufs[num_bufs++], b); + b += d; + } while (--c && (num_bufs < 8)); + ret = bman_release(pobj, bufs, num_bufs, + BMAN_RELEASE_FLAG_WAIT); + if (ret) + panic("Seeding reserved buffer pool failed\n"); + total += num_bufs; + } + bman_free_pool(pobj); + cfg += 6; + } +#endif + /* Remove this pool from the allocator (by treating its declaration as + * an implicit "reservation") iff the allocator is *not* being set up + * explicitly defined via "bpool-range" nodes. */ + if (!explicit_allocator && !bman_depletion_get(&pools, bpid)) { + bman_depletion_set(&pools, bpid); + num_pools++; + } + if (total) + pr_info("Bman: reserved bpid %d, seeded %lld items\n", bpid, + total); + else + pr_info("Bman: reserved bpid %d\n", bpid); + return 0; +} + +int bm_pool_new(u32 *bpid) +{ + int ret = 0, b = bman_pool_max; + spin_lock(&pools_lock); + if (num_pools >= bman_pool_max) + ret = -ENOMEM; + else { + while (b-- && bman_depletion_get(&pools, b)) + ; + BUG_ON(b < 0); + bman_depletion_set(&pools, b); + *bpid = b; + num_pools++; + } + spin_unlock(&pools_lock); + return ret; +} +EXPORT_SYMBOL(bm_pool_new); + +void bm_pool_free(u32 bpid) +{ + spin_lock(&pools_lock); + BUG_ON(bpid >= bman_pool_max); + BUG_ON(!bman_depletion_get(&pools, bpid)); + bman_depletion_unset(&pools, bpid); + num_pools--; + spin_unlock(&pools_lock); +} +EXPORT_SYMBOL(bm_pool_free); + +#ifdef CONFIG_FSL_BMAN_PORTAL +/* To understand the use of this structure and the flow of operation for all + * this portal-setup code, please see qman_driver.c. The Bman case is much the + * same, but simpler (no Qman-specific fiddly bits). */ +struct affine_portal_data { + struct completion done; + const struct bm_portal_config *pconfig; + struct bman_portal *redirect; + int recovery_mode; + struct bman_portal *portal; +}; + +static __init int thread_init_affine_portal(void *__data) +{ + struct affine_portal_data *data = __data; + const struct bm_portal_config *pconfig = data->pconfig; + if (data->redirect) + data->portal = bman_create_affine_slave(data->redirect); + else { + data->portal = bman_create_affine_portal(pconfig, + data->recovery_mode); +#ifdef CONFIG_FSL_DPA_PIRQ_SLOW + if (data->portal) + bman_irqsource_add(BM_PIRQ_RCRI | BM_PIRQ_BSCN); +#endif + } + complete(&data->done); + return 0; +} + +static __init struct bman_portal *init_affine_portal( + struct bm_portal_config *pconfig, + int cpu, struct bman_portal *redirect, + int recovery_mode) +{ + struct affine_portal_data data = { + .done = COMPLETION_INITIALIZER_ONSTACK(data.done), + .pconfig = pconfig, + .redirect = redirect, + .recovery_mode = recovery_mode, + .portal = NULL + }; + struct task_struct *k = kthread_create(thread_init_affine_portal, &data, + "bman_affine%d", cpu); + int ret; + if (IS_ERR(k)) { + pr_err("Failed to init %sBman affine portal for cpu %d\n", + redirect ? "(slave) " : "", cpu); + return NULL; + } + kthread_bind(k, cpu); + wake_up_process(k); + wait_for_completion(&data.done); + ret = kthread_stop(k); + if (ret) { + pr_err("Bman portal initialisation failed, cpu %d, code %d\n", + cpu, ret); + return NULL; + } + if (data.portal) + pr_info("Bman portal %sinitialised, cpu %d\n", + redirect ? "(slave) " : + pconfig->public_cfg.is_shared ? "(shared) " : "", cpu); + return data.portal; +} +#endif + +static struct bm_portal_config * __init fsl_bman_portal_init( + struct device_node *node) +{ + struct bm_portal_config *pcfg; + const u32 *index; + const phandle *ph = NULL; + int irq, ret; + + pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL); + if (!pcfg) { + pr_err("can't allocate portal config"); + return NULL; + } + + if (of_device_is_compatible(node, "fsl,bman-portal-1.0")) { + bman_ip_rev = BMAN_REV10; + bman_pool_max = 64; + } else if (of_device_is_compatible(node, "fsl,bman-portal-2.0")) { + bman_ip_rev = BMAN_REV20; + bman_pool_max = 8; + } + + ret = of_address_to_resource(node, BM_ADDR_CE, + &pcfg->addr_phys[BM_ADDR_CE]); + if (ret) { + pr_err("Can't get %s property 'reg::CE'\n", node->full_name); + goto err; + } + ret = of_address_to_resource(node, BM_ADDR_CI, + &pcfg->addr_phys[BM_ADDR_CI]); + if (ret) { + pr_err("Can't get %s property 'reg::CI'\n", node->full_name); + goto err; + } + index = of_get_property(node, "cell-index", &ret); + if (!index || (ret != 4)) { + pr_err("Can't get %s property '%s'\n", node->full_name, + "cell-index"); + goto err; + } + ph = of_get_property(node, "cpu-handle", &ret); + if (ph) { + if (ret != sizeof(phandle)) { + pr_err("Malformed %s property '%s'\n", node->full_name, + "cpu-handle"); + goto err; + } + ret = check_cpu_phandle(*ph); + if (ret < 0) + goto err; + pcfg->public_cfg.cpu = ret; + } else + pcfg->public_cfg.cpu = -1; + + irq = irq_of_parse_and_map(node, 0); + if (irq == NO_IRQ) { + pr_err("Can't get %s property 'interrupts'\n", node->full_name); + goto err; + } + pcfg->public_cfg.irq = irq; + pcfg->public_cfg.index = *index; + bman_depletion_fill(&pcfg->public_cfg.mask); + + if (of_get_property(node, "fsl,usdpaa-portal", &ret)) { + struct dpa_uio_portal *u = kmalloc(sizeof(*u), GFP_KERNEL); + if (!u) + goto err; + u->type = dpa_uio_portal_bman; + u->bm_cfg = pcfg; + list_add_tail(&u->node, &bman_uio.list); + /* Return NULL, otherwise the kernel may share it on CPUs that + * don't have their own portals, which would be ... *bad*. */ + return NULL; + } + + /* Map the portals now we know they aren't for UIO (the UIO code doesn't + * need the CE mapping, and so will do its own CI-only mapping). */ + pcfg->addr_virt[BM_ADDR_CE] = ioremap_prot( + pcfg->addr_phys[BM_ADDR_CE].start, + resource_size(&pcfg->addr_phys[BM_ADDR_CE]), + 0); + pcfg->addr_virt[BM_ADDR_CI] = ioremap_prot( + pcfg->addr_phys[BM_ADDR_CI].start, + resource_size(&pcfg->addr_phys[BM_ADDR_CI]), + _PAGE_GUARDED | _PAGE_NO_CACHE); + return pcfg; +err: + kfree(pcfg); + return NULL; +} + +static void __init fsl_bman_portal_destroy(struct bm_portal_config *pcfg) +{ + iounmap(pcfg->addr_virt[BM_ADDR_CE]); + iounmap(pcfg->addr_virt[BM_ADDR_CI]); + kfree(pcfg); +} + +static int __init fsl_bpool_init(struct device_node *node) +{ + int ret; + u32 *cfg = NULL, *thresh; + struct device_node *tmp_node; + u32 *bpid = (u32 *)of_get_property(node, "fsl,bpid", &ret); + if (!bpid || (ret!= 4)) { + pr_err("Can't get %s property 'fsl,bpid'\n", node->full_name); + return -ENODEV; + } + thresh = (u32 *)of_get_property(node, "fsl,bpool-thresholds", &ret); + if (thresh) { + if (ret != 16) { + pr_err("Invalid %s property '%s'\n", + node->full_name, "fsl,bpool-thresholds"); + return -ENODEV; + } +#ifndef CONFIG_FSL_BMAN_CONFIG + pr_err("Ignoring %s property '%s', no CCSR support\n", + node->full_name, "fsl,bpool-thresholds"); +#endif + } + /* If rebooted, we should not re-seed any pools via bpool-cfg. */ + /* TODO: parsing hypervisor fields to determine qualitative things like + * "was I rebooted" should probably be wrapped in fsl_hypervisor.h. */ + tmp_node = of_find_node_by_name(NULL, "hypervisor"); + if (!tmp_node || !of_find_property(tmp_node, "fsl,hv-stopped-by", + &ret)) + cfg = (u32 *)of_get_property(node, "fsl,bpool-cfg", &ret); + if (cfg && (!ret || (ret % 24))) { + pr_err("Invalid %s property '%s'\n", node->full_name, + "fsl,bpool-cfg"); + return -ENODEV; + } + if (cfg) + ret = __bm_pool_add(*bpid, cfg, ret / 24); + else + ret = __bm_pool_add(*bpid, NULL, 0); + if (ret) { + pr_err("Can't reserve bpid %d from node %s\n", *bpid, + node->full_name); + return ret; + } +#ifdef CONFIG_FSL_BMAN_CONFIG + if (thresh) { + ret = bm_pool_set(*bpid, thresh); + if (ret) + pr_err("No CCSR node for %s property '%s'\n", + node->full_name, "fsl,bpool-thresholds"); + } +#endif + return ret; +} + +static int __init fsl_bpool_range_init(struct device_node *node, + int recovery_mode) +{ + int ret, warned = 0; + u32 bpid; + u32 *range = (u32 *)of_get_property(node, "fsl,bpool-range", &ret); + if (!range) { + pr_err("No 'fsl,bpool-range' property in node %s\n", + node->full_name); + return -EINVAL; + } + if (ret != 8) { + pr_err("'fsl,bpool-range' is not a 2-cell range in node %s\n", + node->full_name); + return -EINVAL; + } + for (bpid = range[0]; bpid < (range[0] + range[1]); bpid++) { + if (bpid >= bman_pool_max) { + pr_err("BPIDs out of range in node %s\n", + node->full_name); + return -EINVAL; + } + if (!bman_depletion_get(&pools, bpid)) { + if (!warned) { + warned = 1; + pr_err("BPID overlap in node %s, ignoring\n", + node->full_name); + } + } else { + bman_depletion_unset(&pools, bpid); + num_pools--; + } + } +#ifdef CONFIG_FSL_BMAN_PORTAL + /* If in recovery mode *and* we are using a private BPID allocation + * range, then automatically clean up all BPIDs in that range so we can + * automatically exit recovery mode too. */ + if (recovery_mode) { + for (bpid = range[0]; bpid < (range[0] + range[1]); bpid++) { + ret = bman_recovery_cleanup_bpid(bpid); + if (ret) { + pr_err("Failed to recovery BPID %d\n", bpid); + return ret; + } + } + } +#else + BUG_ON(recovery_mode); +#endif + pr_info("Bman: BPID allocator includes range %d:%d%s\n", + range[0], range[1], recovery_mode ? " (recovered)" : ""); + return 0; +} + +#ifdef CONFIG_FSL_BMAN_PORTAL +static __init int __leave_recovery(void *__data) +{ + struct completion *done = __data; + bman_recovery_exit_local(); + complete(done); + return 0; +} + +int bman_recovery_exit(void) +{ + struct completion done = COMPLETION_INITIALIZER_ONSTACK(done); + unsigned int cpu; + + for_each_cpu(cpu, bman_affine_cpus()) { + struct task_struct *k = kthread_create(__leave_recovery, &done, + "bman_recovery"); + int ret; + if (IS_ERR(k)) { + pr_err("Thread failure (recovery) on cpu %d\n", cpu); + return -ENOMEM; + } + kthread_bind(k, cpu); + wake_up_process(k); + wait_for_completion(&done); + ret = kthread_stop(k); + if (ret) { + pr_err("Failed to exit recovery on cpu %d\n", cpu); + return ret; + } + pr_info("Bman portal exited recovery, cpu %d\n", cpu); + } + return 0; +} +EXPORT_SYMBOL(bman_recovery_exit); +#endif + +static __init int bman_init(void) +{ +#ifdef CONFIG_FSL_BMAN_PORTAL + struct cpumask primary_cpus = *cpu_none_mask; + struct cpumask slave_cpus = *cpu_online_mask; + struct bman_portal *sharing_portal = NULL; + int sharing_cpu = -1; +#endif + struct device_node *dn; + struct bm_portal_config *pcfg; + int ret, recovery_mode = 0; + LIST_HEAD(cfg_list); + + for_each_compatible_node(dn, NULL, "fsl,bman") { + if (!bman_init_error_int(dn)) + pr_info("Bman err interrupt handler present\n"); + else + pr_err("Bman err interrupt handler missing\n"); + } + if (!bman_have_ccsr()) { + /* If there's no CCSR, our bpid allocator is empty unless + * fsl,bpool-range nodes are used. */ + bman_depletion_fill(&pools); + num_pools = bman_pool_max; + } +#ifdef CONFIG_FSL_BMAN_PORTAL + if (fsl_dpa_should_recover()) + recovery_mode = 1; + for_each_compatible_node(dn, NULL, "fsl,bman-portal") { + pcfg = fsl_bman_portal_init(dn); + if (pcfg) { + if (pcfg->public_cfg.cpu >= 0) { + cpumask_set_cpu(pcfg->public_cfg.cpu, + &primary_cpus); + list_add(&pcfg->list, &cfg_list); + } else + fsl_bman_portal_destroy(pcfg); + } + } + /* only consider "online" CPUs */ + cpumask_and(&primary_cpus, &primary_cpus, cpu_online_mask); + if (cpumask_empty(&primary_cpus)) + /* No portals, we're done */ + return 0; + if (!cpumask_subset(cpu_online_mask, &primary_cpus)) { + /* Need to do some sharing. In lieu of anything more scientific + * (or configurable), we pick the last-most CPU that has a + * portal and share that one. */ + int next = cpumask_first(&primary_cpus); + while (next < nr_cpu_ids) { + sharing_cpu = next; + next = cpumask_next(next, &primary_cpus); + } + } + /* Parsing is done and sharing decisions are made, now initialise the + * portals and determine which "slave" CPUs are left over. */ + list_for_each_entry(pcfg, &cfg_list, list) { + struct bman_portal *p; + int is_shared = (!sharing_portal && (sharing_cpu >= 0) && + (pcfg->public_cfg.cpu == sharing_cpu)); + pcfg->public_cfg.is_shared = is_shared; + /* If it's not mapped to a CPU, or another portal is already + * initialised to the same CPU, skip this portal. */ + if (pcfg->public_cfg.cpu < 0 || !cpumask_test_cpu( + pcfg->public_cfg.cpu, &slave_cpus)) + continue; + p = init_affine_portal(pcfg, pcfg->public_cfg.cpu, NULL, + recovery_mode); + if (p) { + if (is_shared) + sharing_portal = p; + cpumask_clear_cpu(pcfg->public_cfg.cpu, &slave_cpus); + } + } + + if (sharing_portal) { + int loop; + for_each_cpu(loop, &slave_cpus) { + struct bman_portal *p = init_affine_portal(NULL, loop, + sharing_portal, recovery_mode); + if (!p) + pr_err("Failed slave Bman portal for cpu %d\n", + loop); + } + } +#else + for_each_compatible_node(dn, NULL, "fsl,bman-portal") { + pcfg = fsl_bman_portal_init(dn); + if (pcfg) + /* No kernel portal support, so if USDPAA didn't consume + * the portal, we've no other use for it. */ + fsl_bman_portal_destroy(pcfg); + } +#endif + for_each_compatible_node(dn, NULL, "fsl,bpool-range") { + if (!explicit_allocator) { + explicit_allocator = 1; + bman_depletion_fill(&pools); + num_pools = 64; + } + ret = fsl_bpool_range_init(dn, recovery_mode); + if (ret) + return ret; + } +#ifdef CONFIG_FSL_BMAN_PORTAL + /* If using private BPID allocation, exit recovery mode automatically + * (ie. after automatic recovery) */ + if (recovery_mode && explicit_allocator) { + ret = bman_recovery_exit(); + if (ret) + return ret; + } +#endif + for_each_compatible_node(dn, NULL, "fsl,bpool") { + ret = fsl_bpool_init(dn); + if (ret) + return ret; + } + pr_info("Bman portals initialised\n"); + return 0; +} +subsys_initcall(bman_init); --- linux-3.13.0.orig/drivers/staging/fsl_qbman/Kconfig +++ linux-3.13.0/drivers/staging/fsl_qbman/Kconfig @@ -0,0 +1,278 @@ +config FSL_DPA + bool "Freescale Datapath Queue and Buffer management" + depends on HAS_FSL_QBMAN + default y + select FSL_QMAN_FQ_LOOKUP if PPC64 + +menu "Freescale Datapath QMan/BMan options" + depends on FSL_DPA + +config FSL_DPA_CHECKING + bool "additional driver checking" + default n + ---help--- + Compiles in additional checks to sanity-check the drivers and any + use of it by other code. Not recommended for performance. + +config FSL_DPA_HAVE_IRQ + bool + default y + +config FSL_DPA_CAN_WAIT + bool + default y + +config FSL_DPA_CAN_WAIT_SYNC + bool + default y + +config FSL_DPA_PIRQ_FAST + bool "fast-path processing via IRQ" + depends on FSL_DPA_HAVE_IRQ + default y + ---help--- + By default, configure fast-path handling to be triggered by IRQ. + Drivers can modify this at run-time, but for linux it makes sense + for all handling to be triggered by IRQ, unless a special + run-to-completion application is being built. + +config FSL_DPA_PIRQ_SLOW + bool "slow-path processing via IRQ" + depends on FSL_DPA_HAVE_IRQ + default y + ---help--- + By default, configure slow-path handling to be triggered by IRQ. + Drivers can modify this at run-time, but for linux it makes sense + for all handling to be triggered by IRQ, unless a special + run-to-completion application is being built. + +config FSL_DPA_PORTAL_SHARE + bool "allow portals to be affine to multiple CPUs" + default y + ---help--- + If the kernel, via its device-tree, will be required to use a + single Qman or Bman portal for multiple CPUs, then select this + option. Note however that compiling with this option will result + in a very slight (but non-zero) overhead even when the feature + is not being used. + +config FSL_DPA_UIO + tristate "Export USDPAA portals via UIO" + depends on UIO + default y + ---help--- + Portals are exported as UIO devices for use by USDPAA (User + Space DataPath Acceleration Architecture) applications. + +config FSL_BMAN + bool "Freescale Buffer Manager support" + default y + +if FSL_BMAN + +config FSL_BMAN_PORTAL + bool "Bman portal support" + default y + ---help--- + Compiles support to detect and support Bman software corenet portals + (as provided by the device-tree). + +config FSL_BMAN_CONFIG + bool "Bman device management" + default y + ---help--- + If this linux image is running natively, you need this option. If this + linux image is running as a guest OS under the hypervisor, only one + guest OS ("the control plane") needs this option. + +config FSL_BMAN_TEST + tristate "Bman self-tests" + depends on FSL_BMAN_PORTAL + default n + ---help--- + This option compiles self-test code for Bman. + +config FSL_BMAN_TEST_HIGH + bool "Bman high-level self-test" + depends on FSL_BMAN_TEST + default y + ---help--- + This requires the presence of cpu-affine portals, and performs + high-level API testing with them (whichever portal(s) are affine to + the cpu(s) the test executes on). + +config FSL_BMAN_TEST_THRESH + bool "Bman threshold test" + depends on FSL_BMAN_TEST + default y + ---help--- + Multi-threaded (SMP) test of Bman pool depletion. A pool is seeded + before multiple threads (one per cpu) create pool objects to track + depletion state changes. The pool is then drained to empty by a + "drainer" thread, and the other threads that they observe exactly + the depletion state changes that are expected. + +config FSL_BMAN_DEBUGFS + tristate "Bman debugfs interface" + depends on FSL_BMAN_PORTAL && DEBUG_FS + default y + ---help--- + This option compiles bman debugfs code for Bman. + +endif # FSL_BMAN + +config FSL_QMAN + bool "Freescale Queue Manager support" + default y + +if FSL_QMAN + +config FSL_QMAN_PORTAL + bool "Qman portal support" + default y + ---help--- + Compiles support to detect and support Qman software corenet portals + (as provided by the device-tree). + +config FSL_QMAN_BUG_AND_FEATURE_REV1 + bool "workarounds for errata and missing features in p4080 rev1" + depends on FSL_QMAN_PORTAL + default y + ---help--- + If this option is selected, the driver will be compiled with + workarounds for errata as well as feature limitations (relative to + more recent parts) of p4080 rev1. On unaffected revisions, this + support incurs only a negligable overhead, typically only a couple of + instructions per non-fast-path operation (the fast-path operations are + unaffected). + + If in doubt, say Y. + +config FSL_QMAN_POLL_LIMIT + int + default 32 + +config FSL_QMAN_PORTAL_DISABLEAUTO_DCA + bool "disable discrete-consumption support on cpu-affine portals" + default n + ---help--- + By default, auto-initialised cpu-affine portals support + discrete-consumption acknowledgements, but this may be unimplemented + in the simulation model. + +config FSL_QMAN_NULL_FQ_DEMUX + bool "support NULL demux handlers" + default y + ---help--- + Normally, incoming frame dequeues and messages from Qman to a software + portal provide a direct demux to the owner of the corresponding FQ. + However, exotic "zero-conf" possibilities can be supported if other + cpus (or operating systems) can schedule "NULL" FQs to a receiver's + portal. If this option is selected, the driver will support this + feature, but it adds a small overhead to the hottest-path in the + driver, so it should be disabled unless needed. + +config FSL_QMAN_DQRR_PREFETCHING + bool "support prefetching or DQRR (if stashing disabled)" + default y + ---help--- + Normally, portals are configured to stash DQRR entries, but if this is + not the case, then s/w needs to invalidate and prefetch ring entries. + Selecting this option supports both cases and chooses the best one at + run-time, but introduces a small overhead in some hot paths of the + driver, so disable it if you know stashing will be configured. + +config FSL_QMAN_CONFIG + bool "Qman device management" + default y + ---help--- + If this linux image is running natively, you need this option. If this + linux image is running as a guest OS under the hypervisor, only one + guest OS ("the control plane") needs this option. + +config FSL_QMAN_TEST + tristate "Qman self-tests" + depends on FSL_QMAN_PORTAL + default n + ---help--- + This option compiles self-test code for Qman. + +config FSL_QMAN_TEST_STASH_POTATO + bool "Qman 'hot potato' data-stashing self-test" + depends on FSL_QMAN_TEST + default y + ---help--- + This performs a "hot potato" style test enqueuing/dequeuing a frame + across a series of FQs scheduled to different portals (and cpus), with + DQRR, data and context stashing always on. + +config FSL_QMAN_TEST_HIGH + bool "Qman high-level self-test" + depends on FSL_QMAN_TEST + default y + ---help--- + This requires the presence of cpu-affine portals, and performs + high-level API testing with them (whichever portal(s) are affine to + the cpu(s) the test executes on). + +config FSL_QMAN_TEST_ERRATA + bool "Qman errata-handling self-test" + depends on FSL_QMAN_TEST + default y + ---help--- + This requires the presence of cpu-affine portals, and performs + testing that handling for known hardware-errata is correct. + +config FSL_QMAN_DEBUGFS + tristate "Qman debugfs interface" + depends on FSL_QMAN_PORTAL + default y + ---help--- + This option compiles qman debugfs code for Qman. + +# H/w settings that can be hard-coded for now. +config FSL_QMAN_FQD_SZ + int "Size of Frame Queue Descriptor region" + default 9 + ---help--- + This is the size of the FQD region defined as: PAGE_SIZE * (2^value) + ex: 9 => PAGE_SIZE * (2^9) + +# Corenet initiator settings. Stash request queues are 4-deep to match cores' +# ability to snart. Stash priority is 3, other priorities are 2. +config FSL_QMAN_CI_SCHED_CFG_SRCCIV + int + depends on FSL_QMAN_CONFIG + default 4 +config FSL_QMAN_CI_SCHED_CFG_SRQ_W + int + depends on FSL_QMAN_CONFIG + default 3 +config FSL_QMAN_CI_SCHED_CFG_RW_W + int + depends on FSL_QMAN_CONFIG + default 2 +config FSL_QMAN_CI_SCHED_CFG_BMAN_W + int + depends on FSL_QMAN_CONFIG + default 2 + +# portal interrupt settings +config FSL_QMAN_PIRQ_DQRR_ITHRESH + int + default 12 +config FSL_QMAN_PIRQ_MR_ITHRESH + int + default 4 +config FSL_QMAN_PIRQ_IPERIOD + int + default 100 + +# 64 bit kernel support +config FSL_QMAN_FQ_LOOKUP + bool + default n + +endif # FSL_QMAN + +endmenu --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_test_high.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_test_high.c @@ -0,0 +1,222 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qman_test.h" + +/*************/ +/* constants */ +/*************/ + +#define CGR_ID 27 +#define POOL_ID 2 +#define FQ_FLAGS QMAN_FQ_FLAG_DYNAMIC_FQID +#define NUM_ENQUEUES 10 +#define NUM_PARTIAL 4 +#define PORTAL_SDQCR (QM_SDQCR_SOURCE_CHANNELS | \ + QM_SDQCR_TYPE_PRIO_QOS | \ + QM_SDQCR_TOKEN_SET(0x98) | \ + QM_SDQCR_CHANNELS_DEDICATED | \ + QM_SDQCR_CHANNELS_POOL(POOL_ID)) +#define PORTAL_OPAQUE (void *)0xf00dbeef +#define VDQCR_FLAGS (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH) + +/*************************************/ +/* Predeclarations (eg. for fq_base) */ +/*************************************/ + +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *, + struct qman_fq *, + const struct qm_dqrr_entry *); +static void cb_ern(struct qman_portal *, struct qman_fq *, + const struct qm_mr_entry *); +static void cb_dc_ern(struct qman_portal *, struct qman_fq *, + const struct qm_mr_entry *); +static void cb_fqs(struct qman_portal *, struct qman_fq *, + const struct qm_mr_entry *); + +/***************/ +/* global vars */ +/***************/ + +static struct qm_fd fd, fd_dq; +static struct qman_fq fq_base = { + .cb.dqrr = cb_dqrr, + .cb.ern = cb_ern, + .cb.dc_ern = cb_dc_ern, + .cb.fqs = cb_fqs +}; +static DECLARE_WAIT_QUEUE_HEAD(waitqueue); +static int retire_complete, sdqcr_complete; + +/**********************/ +/* internal functions */ +/**********************/ + +/* Helpers for initialising and "incrementing" a frame descriptor */ +static void fd_init(struct qm_fd *__fd) +{ + qm_fd_addr_set64(__fd, 0xabdeadbeefLLU); + __fd->format = qm_fd_contig_big; + __fd->length29 = 0x0000ffff; + __fd->cmd = 0xfeedf00d; +} + +static void fd_inc(struct qm_fd *__fd) +{ + u64 t = qm_fd_addr_get64(__fd); + int z = t >> 40; + t <<= 1; + if (z) + t |= 1; + qm_fd_addr_set64(__fd, t); + __fd->length29--; + __fd->cmd++; +} + +/* The only part of the 'fd' we can't memcmp() is the ppid */ +static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b) +{ + int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1; + if (!r) + r = a->format - b->format; + if (!r) + r = a->opaque - b->opaque; + if (!r) + r = a->cmd - b->cmd; + return r; +} + +/********/ +/* test */ +/********/ + +static void do_enqueues(struct qman_fq *fq) +{ + unsigned int loop; + for (loop = 0; loop < NUM_ENQUEUES; loop++) { + if (qman_enqueue(fq, &fd, QMAN_ENQUEUE_FLAG_WAIT | + (((loop + 1) == NUM_ENQUEUES) ? + QMAN_ENQUEUE_FLAG_WAIT_SYNC : 0))) + panic("qman_enqueue() failed\n"); + fd_inc(&fd); + } +} + +void qman_test_high(void) +{ + int flags, res; + struct qman_fq *fq = &fq_base; + + pr_info("qman_test_high starting\n"); + fd_init(&fd); + fd_init(&fd_dq); + + /* Initialise (parked) FQ */ + if (qman_create_fq(0, FQ_FLAGS, fq)) + panic("qman_create_fq() failed\n"); + if (qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL)) + panic("qman_init_fq() failed\n"); + + /* Do enqueues + VDQCR, twice. (Parked FQ) */ + do_enqueues(fq); + pr_info("VDQCR (till-empty);\n"); + if (qman_volatile_dequeue(fq, VDQCR_FLAGS, + QM_VDQCR_NUMFRAMES_TILLEMPTY)) + panic("qman_volatile_dequeue() failed\n"); + do_enqueues(fq); + pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES); + if (qman_volatile_dequeue(fq, VDQCR_FLAGS, + QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL))) + panic("qman_volatile_dequeue() failed\n"); + pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL, + NUM_ENQUEUES); + if (qman_volatile_dequeue(fq, VDQCR_FLAGS, + QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL))) + panic("qman_volatile_dequeue() failed\n"); + + do_enqueues(fq); + pr_info("scheduled dequeue (till-empty)\n"); + if (qman_schedule_fq(fq)) + panic("qman_schedule_fq() failed\n"); + wait_event(waitqueue, sdqcr_complete); + + /* Retire and OOS the FQ */ + res = qman_retire_fq(fq, &flags); + if (res < 0) + panic("qman_retire_fq() failed\n"); + wait_event(waitqueue, retire_complete); + if (flags & QMAN_FQ_STATE_BLOCKOOS) + panic("leaking frames\n"); + if (qman_oos_fq(fq)) + panic("qman_oos_fq() failed\n"); + qman_destroy_fq(fq, 0); + pr_info("qman_test_high finished\n"); +} + +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + if (fd_cmp(&fd_dq, &dq->fd)) { + pr_err("BADNESS: dequeued frame doesn't match;\n"); + BUG(); + } + fd_inc(&fd_dq); + if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) { + sdqcr_complete = 1; + wake_up(&waitqueue); + } + return qman_cb_dqrr_consume; +} + +static void cb_ern(struct qman_portal *p, struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + panic("cb_ern() unimplemented"); +} + +static void cb_dc_ern(struct qman_portal *p, struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + panic("cb_dc_ern() unimplemented"); +} + +static void cb_fqs(struct qman_portal *p, struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK); + if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) + panic("unexpected FQS message"); + pr_info("Retirement message received\n"); + retire_complete = 1; + wake_up(&waitqueue); +} + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_config.c +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_config.c @@ -0,0 +1,1013 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CONFIG_SMP +#include /* get_hard_smp_processor_id() */ +#endif + +#include +#include + +#include "qman_private.h" + +/* Last updated for v00.800 of the BG */ + +/* Register offsets */ +#define REG_QCSP_PID_CFG(n) (0x0000 + ((n) * 0x10)) +#define REG_QCSP_IO_CFG(n) (0x0004 + ((n) * 0x10)) +#define REG_QCSP_DD_CFG(n) (0x000c + ((n) * 0x10)) +#define REG_DD_CFG 0x0200 +#define REG_DCP_CFG(n) (0x0300 + ((n) * 0x10)) +#define REG_DCP_DD_CFG(n) (0x0304 + ((n) * 0x10)) +#define REG_DCP_DLM_AVG(n) (0x030c + ((n) * 0x10)) +#define REG_PFDR_FPC 0x0400 +#define REG_PFDR_FP_HEAD 0x0404 +#define REG_PFDR_FP_TAIL 0x0408 +#define REG_PFDR_FP_LWIT 0x0410 +#define REG_PFDR_CFG 0x0414 +#define REG_SFDR_CFG 0x0500 +#define REG_SFDR_IN_USE 0x0504 +#define REG_WQ_CS_CFG(n) (0x0600 + ((n) * 0x04)) +#define REG_WQ_DEF_ENC_WQID 0x0630 +#define REG_WQ_SC_DD_CFG(n) (0x640 + ((n) * 0x04)) +#define REG_WQ_PC_DD_CFG(n) (0x680 + ((n) * 0x04)) +#define REG_WQ_DC0_DD_CFG(n) (0x6c0 + ((n) * 0x04)) +#define REG_WQ_DC1_DD_CFG(n) (0x700 + ((n) * 0x04)) +#define REG_WQ_DCn_DD_CFG(n) (0x6c0 + ((n) * 0x40)) /* n=2,3 */ +#define REG_CM_CFG 0x0800 +#define REG_ECSR 0x0a00 +#define REG_ECIR 0x0a04 +#define REG_EADR 0x0a08 +#define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) +#define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) +#define REG_MCR 0x0b00 +#define REG_MCP(n) (0x0b04 + ((n) * 0x04)) +#define REG_HID_CFG 0x0bf0 +#define REG_IDLE_STAT 0x0bf4 +#define REG_IP_REV_1 0x0bf8 +#define REG_IP_REV_2 0x0bfc +#define REG_FQD_BARE 0x0c00 +#define REG_PFDR_BARE 0x0c20 +#define REG_offset_BAR 0x0004 /* relative to REG_[FQD|PFDR]_BARE */ +#define REG_offset_AR 0x0010 /* relative to REG_[FQD|PFDR]_BARE */ +#define REG_QCSP_BARE 0x0c80 +#define REG_QCSP_BAR 0x0c84 +#define REG_CI_SCHED_CFG 0x0d00 +#define REG_SRCIDR 0x0d04 +#define REG_LIODNR 0x0d08 +#define REG_CI_RLM_AVG 0x0d14 +#define REG_ERR_ISR 0x0e00 /* + "enum qm_isr_reg" */ + +/* Assists for QMAN_MCR */ +#define MCR_INIT_PFDR 0x01000000 +#define MCR_get_rslt(v) (u8)((v) >> 24) +#define MCR_rslt_idle(r) (!rslt || (rslt >= 0xf0)) +#define MCR_rslt_ok(r) (rslt == 0xf0) +#define MCR_rslt_eaccess(r) (rslt == 0xf8) +#define MCR_rslt_inval(r) (rslt == 0xff) + +struct qman; + +/* Follows WQ_CS_CFG0-5 */ +enum qm_wq_class { + qm_wq_portal = 0, + qm_wq_pool = 1, + qm_wq_fman0 = 2, + qm_wq_fman1 = 3, + qm_wq_caam = 4, + qm_wq_pme = 5, + qm_wq_first = qm_wq_portal, + qm_wq_last = qm_wq_pme +}; + +/* Follows FQD_[BARE|BAR|AR] and PFDR_[BARE|BAR|AR] */ +enum qm_memory { + qm_memory_fqd, + qm_memory_pfdr +}; + +/* Used by all error interrupt registers except 'inhibit' */ +#define QM_EIRQ_CIDE 0x20000000 /* Corenet Initiator Data Error */ +#define QM_EIRQ_CTDE 0x10000000 /* Corenet Target Data Error */ +#define QM_EIRQ_CITT 0x08000000 /* Corenet Invalid Target Transaction */ +#define QM_EIRQ_PLWI 0x04000000 /* PFDR Low Watermark */ +#define QM_EIRQ_MBEI 0x02000000 /* Multi-bit ECC Error */ +#define QM_EIRQ_SBEI 0x01000000 /* Single-bit ECC Error */ +#define QM_EIRQ_PEBI 0x00800000 /* PFDR Enqueues Blocked Interrupt */ +#define QM_EIRQ_ICVI 0x00010000 /* Invalid Command Verb */ +#define QM_EIRQ_IDDI 0x00000800 /* Invalid Dequeue (Direct-connect) */ +#define QM_EIRQ_IDFI 0x00000400 /* Invalid Dequeue FQ */ +#define QM_EIRQ_IDSI 0x00000200 /* Invalid Dequeue Source */ +#define QM_EIRQ_IDQI 0x00000100 /* Invalid Dequeue Queue */ +#define QM_EIRQ_IEOI 0x00000008 /* Invalid Enqueue Overflow */ +#define QM_EIRQ_IESI 0x00000004 /* Invalid Enqueue State */ +#define QM_EIRQ_IECI 0x00000002 /* Invalid Enqueue Channel */ +#define QM_EIRQ_IEQI 0x00000001 /* Invalid Enqueue Queue */ + +/* QMAN_ECIR valid error bit */ +#define PORTAL_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IESI | QM_EIRQ_IEOI | \ + QM_EIRQ_IDQI | QM_EIRQ_IDSI | QM_EIRQ_IDFI | \ + QM_EIRQ_IDDI | QM_EIRQ_ICVI) +#define FQID_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IECI | QM_EIRQ_IESI | \ + QM_EIRQ_IEOI | QM_EIRQ_IDQI | QM_EIRQ_IDFI) + +union qman_ecir { + u32 ecir_raw; + struct { + u32 __reserved:2; + u32 portal_type:1; + u32 portal_num:5; + u32 fqid:24; + } __packed info; +}; + +union qman_eadr { + u32 eadr_raw; + struct { + u32 __reserved1:4; + u32 memid:4; + u32 __reserved2:12; + u32 eadr:12; + } __packed info; +}; + +struct qman_hwerr_txt { + u32 mask; + const char *txt; +}; + +#define QMAN_HWE_TXT(a, b) { .mask = QM_EIRQ_##a, .txt = b } + +static const struct qman_hwerr_txt qman_hwerr_txts[] = { + QMAN_HWE_TXT(CIDE, "Corenet Initiator Data Error"), + QMAN_HWE_TXT(CTDE, "Corenet Target Data Error"), + QMAN_HWE_TXT(CITT, "Corenet Invalid Target Transaction"), + QMAN_HWE_TXT(PLWI, "PFDR Low Watermark"), + QMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"), + QMAN_HWE_TXT(SBEI, "Single-bit ECC Error"), + QMAN_HWE_TXT(PEBI, "PFDR Enqueues Blocked Interrupt"), + QMAN_HWE_TXT(ICVI, "Invalid Command Verb"), + QMAN_HWE_TXT(IDDI, "Invalid Dequeue (Direct-connect)"), + QMAN_HWE_TXT(IDFI, "Invalid Dequeue FQ"), + QMAN_HWE_TXT(IDSI, "Invalid Dequeue Source"), + QMAN_HWE_TXT(IDQI, "Invalid Dequeue Queue"), + QMAN_HWE_TXT(IEOI, "Invalid Enqueue Overflow"), + QMAN_HWE_TXT(IESI, "Invalid Enqueue State"), + QMAN_HWE_TXT(IECI, "Invalid Enqueue Channel"), + QMAN_HWE_TXT(IEQI, "Invalid Enqueue Queue") +}; +#define QMAN_HWE_COUNT (sizeof(qman_hwerr_txts)/sizeof(struct qman_hwerr_txt)) + +struct qman_error_info_mdata { + u16 addr_mask; + u16 bits; + const char *txt; +}; + +#define QMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c} +static const struct qman_error_info_mdata error_mdata[] = { + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 0"), + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 1"), + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 2"), + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 3"), + QMAN_ERR_MDATA(0x0FFF, 512, "FQD cache memory"), + QMAN_ERR_MDATA(0x07FF, 128, "SFDR memory"), + QMAN_ERR_MDATA(0x01FF, 72, "WQ context memory"), + QMAN_ERR_MDATA(0x00FF, 240, "CGR memory"), + QMAN_ERR_MDATA(0x00FF, 302, "Internal Order Restoration List memory"), + QMAN_ERR_MDATA(0x01FF, 256, "SW portal ring memory"), +}; +#define QMAN_ERR_MDATA_COUNT \ + (sizeof(error_mdata)/sizeof(struct qman_error_info_mdata)) + +/* Add this in Kconfig */ +#define QMAN_ERRS_TO_UNENABLE (QM_EIRQ_PLWI | QM_EIRQ_PEBI) + +/** + * qm_err_isr__ - Manipulate global interrupt registers + * @v: for accessors that write values, this is the 32-bit value + * + * Manipulates QMAN_ERR_ISR, QMAN_ERR_IER, QMAN_ERR_ISDR, QMAN_ERR_IIR. All + * manipulations except qm_err_isr_[un]inhibit() use 32-bit masks composed of + * the QM_EIRQ_*** definitions. Note that "qm_err_isr_enable_write" means + * "write the enable register" rather than "enable the write register"! + */ +#define qm_err_isr_status_read(qm) __qm_err_isr_read(qm, qm_isr_status) +#define qm_err_isr_status_clear(qm, m) __qm_err_isr_write(qm, qm_isr_status,m) +#define qm_err_isr_enable_read(qm) __qm_err_isr_read(qm, qm_isr_enable) +#define qm_err_isr_enable_write(qm, v) __qm_err_isr_write(qm, qm_isr_enable,v) +#define qm_err_isr_disable_read(qm) __qm_err_isr_read(qm, qm_isr_disable) +#define qm_err_isr_disable_write(qm, v) __qm_err_isr_write(qm, qm_isr_disable,v) +#define qm_err_isr_inhibit(qm) __qm_err_isr_write(qm, qm_isr_inhibit,1) +#define qm_err_isr_uninhibit(qm) __qm_err_isr_write(qm, qm_isr_inhibit,0) + +/* + * TODO: unimplemented registers + * + * Keeping a list here of Qman registers I have not yet covered; + * QCSP_DD_IHRSR, QCSP_DD_IHRFR, QCSP_DD_HASR, + * DCP_DD_IHRSR, DCP_DD_IHRFR, DCP_DD_HASR, CM_CFG, + * QMAN_EECC, QMAN_SBET, QMAN_EINJ, QMAN_SBEC0-12 + */ + +/* Encapsulate "struct qman *" as a cast of the register space address. */ + +static struct qman *qm_create(void *regs) +{ + return (struct qman *)regs; +} + +static inline u32 __qm_in(struct qman *qm, u32 offset) +{ + return in_be32((void *)qm + offset); +} +static inline void __qm_out(struct qman *qm, u32 offset, u32 val) +{ + out_be32((void *)qm + offset, val); +} +#define qm_in(reg) __qm_in(qm, REG_##reg) +#define qm_out(reg, val) __qm_out(qm, REG_##reg, val) + +static u32 __qm_err_isr_read(struct qman *qm, enum qm_isr_reg n) +{ + return __qm_in(qm, REG_ERR_ISR + (n << 2)); +} + +static void __qm_err_isr_write(struct qman *qm, enum qm_isr_reg n, u32 val) +{ + __qm_out(qm, REG_ERR_ISR + (n << 2), val); +} + +#if 0 + +static void qm_set_portal(struct qman *qm, u8 swportalID, + u16 ec_tp_cfg, u16 ecd_tp_cfg) +{ + qm_out(QCSP_DD_CFG(swportalID), + ((ec_tp_cfg & 0x1ff) << 16) | (ecd_tp_cfg & 0x1ff)); +} + +static void qm_set_ddebug(struct qman *qm, u8 mdd, u8 m_cfg) +{ + qm_out(DD_CFG, ((mdd & 0x3) << 4) | (m_cfg & 0xf)); +} + +static void qm_set_dc_ddebug(struct qman *qm, enum qm_dc_portal portal, u16 ecd_tp_cfg) +{ + qm_out(DCP_DD_CFG(portal), ecd_tp_cfg & 0x1ff); +} + +static u32 qm_get_pfdr_free_pool_count(struct qman *qm) +{ + return qm_in(PFDR_FPC); +} + +static void qm_get_pfdr_free_pool(struct qman *qm, u32 *head, u32 *tail) +{ + *head = qm_in(PFDR_FP_HEAD); + *tail = qm_in(PFDR_FP_TAIL); +} + +static void qm_set_default_wq(struct qman *qm, u16 wqid) +{ + qm_out(WQ_DEF_ENC_WQID, wqid); +} + +static void qm_set_channel_ddebug(struct qman *qm, enum qm_channel channel, + u16 tp_cfg) +{ + u32 offset; + int upperhalf = 0; + if ((channel >= qm_channel_swportal0) && + (channel <= qm_channel_swportal9)) { + offset = (channel - qm_channel_swportal0); + upperhalf = offset & 0x1; + offset = REG_WQ_SC_DD_CFG(offset / 2); + } else if ((channel >= qm_channel_pool1) && + (channel <= qm_channel_pool15)) { + offset = (channel + 1 - qm_channel_pool1); + upperhalf = offset & 0x1; + offset = REG_WQ_PC_DD_CFG(offset / 2); + } else if ((channel >= qm_channel_fman0_sp0) && + (channel <= qm_channel_fman0_sp11)) { + offset = (channel - qm_channel_fman0_sp0); + upperhalf = offset & 0x1; + offset = REG_WQ_DC0_DD_CFG(offset / 2); + } + else if ((channel >= qm_channel_fman1_sp0) && + (channel <= qm_channel_fman1_sp11)) { + offset = (channel - qm_channel_fman1_sp0); + upperhalf = offset & 0x1; + offset = REG_WQ_DC1_DD_CFG(offset / 2); + } + else if (channel == qm_channel_caam) + offset = REG_WQ_DCn_DD_CFG(2); + else if (channel == qm_channel_pme) + offset = REG_WQ_DCn_DD_CFG(3); + else { + pr_crit("Illegal qm_channel type %d\n", channel); + return; + } + __qm_out(qm, offset, upperhalf ? ((u32)tp_cfg << 16) : tp_cfg); +} + +static void qm_get_details(struct qman *qm, u8 *int_options, u8 *errata, + u8 *conf_options) +{ + u32 v = qm_in(IP_REV_1); + *int_options = (v >> 16) & 0xff; + *errata = (v >> 8) & 0xff; + *conf_options = v & 0xff; +} + +static void qm_set_corenet_bar(struct qman *qm, u16 eba, u32 ba) +{ + /* choke if 'ba' isn't properly aligned */ + DPA_ASSERT(!(ba & 0x001fffff)); + qm_out(QCSP_BARE, eba); + qm_out(QCSP_BAR, ba); +} + +static u8 qm_get_corenet_sourceid(struct qman *qm) +{ + return qm_in(SRCIDR); +} + +static u16 qm_get_liodn(struct qman *qm) +{ + return qm_in(LIODNR); +} + +static void qm_set_congestion_config(struct qman *qm, u16 pres) +{ + qm_out(CM_CFG, pres); +} + +#endif + +static void qm_set_dc(struct qman *qm, enum qm_dc_portal portal, + int ed, u8 sernd) +{ + DPA_ASSERT(!ed || (portal == qm_dc_portal_fman0) || + (portal == qm_dc_portal_fman1)); + qm_out(DCP_CFG(portal), (ed ? 0x100 : 0) | (sernd & 0x1f)); +} + +static void qm_set_wq_scheduling(struct qman *qm, enum qm_wq_class wq_class, + u8 cs_elev, u8 csw2, u8 csw3, u8 csw4, u8 csw5, + u8 csw6, u8 csw7) +{ +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 +#define csw(x) \ +do { \ + if (++x == 8) \ + x = 7; \ +} while (0) + if (qman_ip_rev == QMAN_REV10) { + csw(csw2); + csw(csw3); + csw(csw4); + csw(csw5); + csw(csw6); + csw(csw7); + } +#endif + qm_out(WQ_CS_CFG(wq_class), ((cs_elev & 0xff) << 24) | + ((csw2 & 0x7) << 20) | ((csw3 & 0x7) << 16) | + ((csw4 & 0x7) << 12) | ((csw5 & 0x7) << 8) | + ((csw6 & 0x7) << 4) | (csw7 & 0x7)); +} + +static void qm_set_hid(struct qman *qm) +{ +#ifdef CONFIG_FSL_QMAN_BUG_AND_FEATURE_REV1 + if (qman_ip_rev == QMAN_REV10) + qm_out(HID_CFG, 3); + else +#endif + qm_out(HID_CFG, 0); +} + +static void qm_set_corenet_initiator(struct qman *qm) +{ + qm_out(CI_SCHED_CFG, + 0x80000000 | /* write srcciv enable */ + (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRCCIV << 24) | + (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRQ_W << 8) | + (CONFIG_FSL_QMAN_CI_SCHED_CFG_RW_W << 4) | + CONFIG_FSL_QMAN_CI_SCHED_CFG_BMAN_W); +} + +static void qm_get_version(struct qman *qm, u16 *id, u8 *major, u8 *minor) +{ + u32 v = qm_in(IP_REV_1); + *id = (v >> 16); + *major = (v >> 8) & 0xff; + *minor = v & 0xff; +} + +static void qm_set_memory(struct qman *qm, enum qm_memory memory, u64 ba, + int enable, int prio, int stash, u32 size) +{ + u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE; + u32 exp = ilog2(size); + /* choke if size isn't within range */ + DPA_ASSERT((size >= 4096) && (size <= 1073741824) && + is_power_of_2(size)); + /* choke if 'ba' has lower-alignment than 'size' */ + DPA_ASSERT(!(ba & (size - 1))); + __qm_out(qm, offset, upper_32_bits(ba)); + __qm_out(qm, offset + REG_offset_BAR, lower_32_bits(ba)); + __qm_out(qm, offset + REG_offset_AR, + (enable ? 0x80000000 : 0) | + (prio ? 0x40000000 : 0) | + (stash ? 0x20000000 : 0) | + (exp - 1)); +} + +static void qm_set_pfdr_threshold(struct qman *qm, u32 th, u8 k) +{ + qm_out(PFDR_FP_LWIT, th & 0xffffff); + qm_out(PFDR_CFG, k); +} + +static void qm_set_sfdr_threshold(struct qman *qm, u16 th) +{ + qm_out(SFDR_CFG, th & 0x3ff); +} + +static int qm_init_pfdr(struct qman *qm, u32 pfdr_start, u32 num) +{ + u8 rslt = MCR_get_rslt(qm_in(MCR)); + + DPA_ASSERT(pfdr_start && !(pfdr_start & 7) && !(num & 7) && num); + /* Make sure the command interface is 'idle' */ + if(!MCR_rslt_idle(rslt)) + panic("QMAN_MCR isn't idle"); + + /* Write the MCR command params then the verb */ + qm_out(MCP(0), pfdr_start ); + /* TODO: remove this - it's a workaround for a model bug that is + * corrected in more recent versions. We use the workaround until + * everyone has upgraded. */ + qm_out(MCP(1), (pfdr_start + num - 16)); + lwsync(); + qm_out(MCR, MCR_INIT_PFDR); + + /* Poll for the result */ + do { + rslt = MCR_get_rslt(qm_in(MCR)); + } while(!MCR_rslt_idle(rslt)); + if (MCR_rslt_ok(rslt)) + return 0; + if (MCR_rslt_eaccess(rslt)) + return -EACCES; + if (MCR_rslt_inval(rslt)) + return -EINVAL; + pr_crit("Unexpected result from MCR_INIT_PFDR: %02x\n", rslt); + return -ENOSYS; +} + +/*****************/ +/* Config driver */ +/*****************/ + +/* TODO: Kconfig these? */ +#define DEFAULT_FQD_SZ (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ) +#define DEFAULT_PFDR_SZ (PAGE_SIZE << 12) + +/* We support only one of these */ +static struct qman *qm; +static struct device_node *qm_node; + +/* Parse the property to extract the memory location and size and + * memblock_reserve() it. If it isn't supplied, memblock_alloc() the default size. */ +static __init int parse_mem_property(struct device_node *node, const char *name, + dma_addr_t *addr, size_t *sz, int zero) +{ + const u32 *pint; + int ret; + + pint = of_get_property(node, name, &ret); + if (!pint || (ret != 16)) { + pr_info("No %s property '%s', using memblock_alloc(%016zx)\n", + node->full_name, name, *sz); + *addr = memblock_alloc(*sz, *sz); + if (zero) + memset(phys_to_virt(*addr), 0, *sz); + return 0; + } + pr_info("Using %s property '%s'\n", node->full_name, name); + /* If using a "zero-pma", don't try to zero it, even if you asked */ + if (zero && of_find_property(node, "zero-pma", &ret)) { + pr_info(" it's a 'zero-pma', not zeroing from s/w\n"); + zero = 0; + } + *addr = ((u64)pint[0] << 32) | (u64)pint[1]; + *sz = ((u64)pint[2] << 32) | (u64)pint[3]; + /* Keep things simple, it's either all in the DRAM range or it's all + * outside. */ + if (*addr < memblock_end_of_DRAM()) { + BUG_ON((u64)*addr + (u64)*sz > memblock_end_of_DRAM()); + if (memblock_reserve(*addr, *sz) < 0) { + pr_err("Failed to reserve %s\n", name); + return -ENOMEM; + } + if (zero) + memset(phys_to_virt(*addr), 0, *sz); + } else if (zero) { + /* map as cacheable, non-guarded */ + void *tmpp = ioremap_prot(*addr, *sz, 0); + memset(tmpp, 0, *sz); + iounmap(tmpp); + } + return 0; +} + +/* TODO: + * - there is obviously no handling of errors, + * - the calls to qm_set_memory() hard-code the priority and CPC-stashing for + * both memory resources to zero. + */ +static int __init fsl_qman_init(struct device_node *node) +{ + struct resource res; + u32 __iomem *regs; + const char *s; + dma_addr_t fqd_a = 0, pfdr_a = 0; + size_t fqd_sz = DEFAULT_FQD_SZ, pfdr_sz = DEFAULT_PFDR_SZ; + int ret, standby = 0; + u16 id; + u8 major, minor; + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + pr_err("Can't get %s property '%s'\n", node->full_name, "reg"); + return ret; + } + s = of_get_property(node, "fsl,hv-claimable", &ret); + if (s && !strcmp(s, "standby")) + standby = 1; + if (!standby) { + ret = parse_mem_property(node, "fsl,qman-fqd", + &fqd_a, &fqd_sz, 1); + BUG_ON(ret); + ret = parse_mem_property(node, "fsl,qman-pfdr", + &pfdr_a, &pfdr_sz, 0); + BUG_ON(ret); + } + /* Global configuration */ + regs = ioremap(res.start, res.end - res.start + 1); + qm = qm_create(regs); + qm_node = node; + qm_get_version(qm, &id, &major, &minor); + pr_info("Qman ver:%04x,%02x,%02x\n", id, major, minor); + if (!qman_ip_rev) { + if ((major == 1) && (minor == 0)) + qman_ip_rev = QMAN_REV10; + else if ((major == 1) && (minor == 1)) + qman_ip_rev = QMAN_REV11; + else if ((major == 1) && (minor == 2)) + qman_ip_rev = QMAN_REV12; + else if ((major == 2) && (minor == 0)) + qman_ip_rev = QMAN_REV20; + else { + pr_warning("unknown Qman version, default to rev1.1\n"); + qman_ip_rev = QMAN_REV11; + } + } + + if (standby) { + pr_info(" -> in standby mode\n"); + return 0; + } + /* FQD memory */ + qm_set_memory(qm, qm_memory_fqd, fqd_a, 1, 0, 0, fqd_sz); + /* PFDR memory */ + qm_set_memory(qm, qm_memory_pfdr, pfdr_a, 1, 0, 0, pfdr_sz); + qm_init_pfdr(qm, 8, pfdr_sz / 64 - 8); + /* thresholds */ + qm_set_pfdr_threshold(qm, 512, 64); + qm_set_sfdr_threshold(qm, 128); + /* clear stale PEBI bit from interrupt status register */ + qm_err_isr_status_clear(qm, QM_EIRQ_PEBI); + /* corenet initiator settings */ + qm_set_corenet_initiator(qm); + /* HID settings */ + qm_set_hid(qm); + /* Set scheduling weights to defaults */ + for (ret = qm_wq_first; ret <= qm_wq_last; ret++) + qm_set_wq_scheduling(qm, ret, 0, 0, 0, 0, 0, 0, 0); + /* We are not prepared to accept ERNs for hardware enqueues */ + qm_set_dc(qm, qm_dc_portal_fman0, 1, 0); + qm_set_dc(qm, qm_dc_portal_fman1, 1, 0); + return 0; +} + +int qman_have_ccsr(void) +{ + return qm ? 1 : 0; +} + +__init void qman_init_early(void) +{ + struct device_node *dn; + for_each_compatible_node(dn, NULL, "fsl,qman") { + if (qm) + pr_err("%s: only one 'fsl,qman' allowed\n", + dn->full_name); + else { + int ret = fsl_qman_init(dn); + BUG_ON(ret); + } + } +} + +static void log_edata_bits(u32 bit_count) +{ + u32 i, j, mask = 0xffffffff; + + pr_warning("Qman ErrInt, EDATA:\n"); + i = bit_count/32; + if (bit_count%32) { + i++; + mask = ~(mask << bit_count%32); + } + j = 16-i; + pr_warning(" 0x%08x\n", qm_in(EDATA(j)) & mask); + j++; + for (; j < 16; j++) + pr_warning(" 0x%08x\n", qm_in(EDATA(j))); +} + +static void log_additional_error_info(u32 isr_val, u32 ecsr_val) +{ + union qman_ecir ecir_val; + union qman_eadr eadr_val; + + ecir_val.ecir_raw = qm_in(ECIR); + /* Is portal info valid */ + if (ecsr_val & PORTAL_ECSR_ERR) { + pr_warning("Qman ErrInt: %s id %d\n", + (ecir_val.info.portal_type) ? + "DCP" : "SWP", ecir_val.info.portal_num); + } + if (ecsr_val & FQID_ECSR_ERR) { + pr_warning("Qman ErrInt: ecir.fqid 0x%x\n", + ecir_val.info.fqid); + } + if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) { + eadr_val.eadr_raw = qm_in(EADR); + pr_warning("Qman ErrInt: EADR Memory: %s, 0x%x\n", + error_mdata[eadr_val.info.memid].txt, + error_mdata[eadr_val.info.memid].addr_mask + & eadr_val.info.eadr); + log_edata_bits(error_mdata[eadr_val.info.memid].bits); + } +} + +/* Qman interrupt handler */ +static irqreturn_t qman_isr(int irq, void *ptr) +{ + u32 isr_val, ier_val, ecsr_val, isr_mask, i; + + ier_val = qm_err_isr_enable_read(qm); + isr_val = qm_err_isr_status_read(qm); + ecsr_val = qm_in(ECSR); + isr_mask = isr_val & ier_val; + + if (!isr_mask) + return IRQ_NONE; + for (i = 0; i < QMAN_HWE_COUNT; i++) { + if (qman_hwerr_txts[i].mask & isr_mask) { + pr_warning("Qman ErrInt: %s\n", qman_hwerr_txts[i].txt); + if (qman_hwerr_txts[i].mask & ecsr_val) { + log_additional_error_info(isr_mask, ecsr_val); + /* Re-arm error capture registers */ + qm_out(ECSR, ecsr_val); + } + if (qman_hwerr_txts[i].mask & QMAN_ERRS_TO_UNENABLE) { + pr_devel("Qman un-enabling error 0x%x\n", + qman_hwerr_txts[i].mask); + ier_val &= ~qman_hwerr_txts[i].mask; + qm_err_isr_enable_write(qm, ier_val); + } + } + } + qm_err_isr_status_clear(qm, isr_val); + return IRQ_HANDLED; +} + +static int __bind_irq(void) +{ + int ret, err_irq; + + err_irq = of_irq_to_resource(qm_node, 0, NULL); + if (err_irq == NO_IRQ) { + pr_info("Can't get %s property '%s'\n", qm_node->full_name, + "interrupts"); + return -ENODEV; + } + ret = request_irq(err_irq, qman_isr, IRQF_SHARED, "qman-err", qm_node); + if (ret) { + pr_err("request_irq() failed %d for '%s'\n", ret, + qm_node->full_name); + return -ENODEV; + } + /* Write-to-clear any stale bits, (eg. starvation being asserted prior + * to resource allocation during driver init). */ + qm_err_isr_status_clear(qm, 0xffffffff); + /* Enable Error Interrupts */ + qm_err_isr_enable_write(qm, 0xffffffff); + return 0; +} + +/* Initialise Error Interrupt Handler */ +int qman_init_error_int(struct device_node *node) +{ + if (!qman_have_ccsr()) + return 0; + if (node != qm_node) + return -EINVAL; + return __bind_irq(); +} + +#define PID_CFG_LIODN_MASK 0x0fff0000 +void qman_liodn_fixup(enum qm_channel channel) +{ + static int done; + static u32 liodn_offset; + u32 before, after; + int idx = channel - qm_channel_swportal0; + + if (!qman_have_ccsr()) + return; + before = qm_in(QCSP_PID_CFG(idx)); + if (!done) { + liodn_offset = before & PID_CFG_LIODN_MASK; + done = 1; + return; + } + after = (before & (~PID_CFG_LIODN_MASK)) | liodn_offset; + qm_out(QCSP_PID_CFG(idx), after); +} + +#ifdef CONFIG_SYSFS + +#define DRV_NAME "fsl-qman" + +static ssize_t show_pfdr_fpc(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_FPC)); +}; + +static ssize_t show_dlm_avg(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + u32 data; + int i; + + if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i)) + return -EINVAL; + data = qm_in(DCP_DLM_AVG(i)); + return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8, + (data & 0x000000ff)*390625); +}; + +static ssize_t set_dlm_avg(struct device *dev, + struct device_attribute *dev_attr, const char *buf, size_t count) +{ + unsigned long val; + int i; + + if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i)) + return -EINVAL; + if (strict_strtoul(buf, 0, &val)) { + dev_dbg(dev, "invalid input %s\n", buf); + return -EINVAL; + } + qm_out(DCP_DLM_AVG(i), val); + return count; +}; + +static ssize_t show_pfdr_cfg(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_CFG)); +}; + +static ssize_t set_pfdr_cfg(struct device *dev, + struct device_attribute *dev_attr, const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) { + dev_dbg(dev, "invalid input %s\n", buf); + return -EINVAL; + } + qm_out(PFDR_CFG, val); + return count; +}; + +static ssize_t show_sfdr_in_use(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SFDR_IN_USE)); +}; + +static ssize_t show_idle_stat(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(IDLE_STAT)); +}; + +static ssize_t show_ci_rlm_avg(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + u32 data = qm_in(CI_RLM_AVG); + return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8, + (data & 0x000000ff)*390625); +}; + +static ssize_t set_ci_rlm_avg(struct device *dev, + struct device_attribute *dev_attr, const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) { + dev_dbg(dev, "invalid input %s\n", buf); + return -EINVAL; + } + qm_out(CI_RLM_AVG, val); + return count; +}; + +static ssize_t show_err_isr(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%08x\n", qm_in(ERR_ISR)); +}; + + +static ssize_t show_sbec(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + int i; + + if (!sscanf(dev_attr->attr.name, "sbec_%d", &i)) + return -EINVAL; + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SBEC(i))); +}; + +static DEVICE_ATTR(pfdr_fpc, S_IRUSR, show_pfdr_fpc, NULL); +static DEVICE_ATTR(pfdr_cfg, S_IRUSR, show_pfdr_cfg, set_pfdr_cfg); +static DEVICE_ATTR(idle_stat, S_IRUSR, show_idle_stat, NULL); +static DEVICE_ATTR(ci_rlm_avg, (S_IRUSR|S_IWUGO), + show_ci_rlm_avg, set_ci_rlm_avg); +static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL); +static DEVICE_ATTR(sfdr_in_use, S_IRUSR, show_sfdr_in_use, NULL); + +static DEVICE_ATTR(dcp0_dlm_avg, (S_IRUSR|S_IWUGO), show_dlm_avg, set_dlm_avg); +static DEVICE_ATTR(dcp1_dlm_avg, (S_IRUSR|S_IWUGO), show_dlm_avg, set_dlm_avg); +static DEVICE_ATTR(dcp2_dlm_avg, (S_IRUSR|S_IWUGO), show_dlm_avg, set_dlm_avg); +static DEVICE_ATTR(dcp3_dlm_avg, (S_IRUSR|S_IWUGO), show_dlm_avg, set_dlm_avg); + +static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL); +static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL); +static DEVICE_ATTR(sbec_2, S_IRUSR, show_sbec, NULL); +static DEVICE_ATTR(sbec_3, S_IRUSR, show_sbec, NULL); +static DEVICE_ATTR(sbec_4, S_IRUSR, show_sbec, NULL); +static DEVICE_ATTR(sbec_5, S_IRUSR, show_sbec, NULL); +static DEVICE_ATTR(sbec_6, S_IRUSR, show_sbec, NULL); + + +static struct attribute *qman_dev_attributes[] = { + &dev_attr_pfdr_fpc.attr, + &dev_attr_pfdr_cfg.attr, + &dev_attr_idle_stat.attr, + &dev_attr_ci_rlm_avg.attr, + &dev_attr_err_isr.attr, + &dev_attr_dcp0_dlm_avg.attr, + &dev_attr_dcp1_dlm_avg.attr, + &dev_attr_dcp2_dlm_avg.attr, + &dev_attr_dcp3_dlm_avg.attr, + /* sfdr_in_use will be added if necessary */ + NULL +}; + +static struct attribute *qman_dev_ecr_attributes[] = { + &dev_attr_sbec_0.attr, + &dev_attr_sbec_1.attr, + &dev_attr_sbec_2.attr, + &dev_attr_sbec_3.attr, + &dev_attr_sbec_4.attr, + &dev_attr_sbec_5.attr, + &dev_attr_sbec_6.attr, + NULL +}; + +/* root level */ +static const struct attribute_group qman_dev_attr_grp = { + .name = NULL, + .attrs = qman_dev_attributes +}; +static const struct attribute_group qman_dev_ecr_grp = { + .name = "error_capture", + .attrs = qman_dev_ecr_attributes +}; + +static int of_fsl_qman_remove(struct platform_device *ofdev) +{ + sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp); + return 0; +}; + +static int of_fsl_qman_probe(struct platform_device *ofdev) +{ + int ret; + + ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_attr_grp); + if (ret) + goto done; + if (qman_ip_rev != QMAN_REV10) { + ret = sysfs_add_file_to_group(&ofdev->dev.kobj, + &dev_attr_sfdr_in_use.attr, qman_dev_attr_grp.name); + if (ret) + goto del_group_0; + } + ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_ecr_grp); + if (ret) + goto del_group_0; + + goto done; + +del_group_0: + sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp); +done: + if (ret) + dev_err(&ofdev->dev, + "Cannot create dev attributes ret=%d\n", ret); + return ret; +}; + +static struct of_device_id of_fsl_qman_ids[] = { + { + .compatible = "fsl,qman", + }, + {} +}; +MODULE_DEVICE_TABLE(of, of_fsl_qman_ids); + +static struct platform_driver of_fsl_qman_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = of_fsl_qman_ids, + }, + .probe = of_fsl_qman_probe, + .remove = of_fsl_qman_remove, +}; + +static int qman_ctrl_init(void) +{ + return platform_driver_register(&of_fsl_qman_driver); +} + +static void qman_ctrl_exit(void) +{ + platform_driver_unregister(&of_fsl_qman_driver); +} + +module_init(qman_ctrl_init); +module_exit(qman_ctrl_exit); + +#endif /* CONFIG_SYSFS */ --- linux-3.13.0.orig/drivers/staging/fsl_qbman/qman_test.h +++ linux-3.13.0/drivers/staging/fsl_qbman/qman_test.h @@ -0,0 +1,85 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +void qman_test_hotpotato(void); +void qman_test_high(void); +void qman_test_errata(void); +void qman_test_fqrange(void); + +static inline void __hexdump(unsigned long start, unsigned long end, + unsigned long p, size_t sz, const unsigned char *c) +{ + while (start < end) { + unsigned int pos = 0; + char buf[64]; + int nl = 0; + pos += sprintf(buf + pos, "%08lx: ", start); + do { + if ((start < p) || (start >= (p + sz))) + pos += sprintf(buf + pos, ".."); + else + pos += sprintf(buf + pos, "%02x", *(c++)); + if (!(++start & 15)) { + buf[pos++] = '\n'; + nl = 1; + } else { + nl = 0; + if(!(start & 1)) + buf[pos++] = ' '; + if(!(start & 3)) + buf[pos++] = ' '; + } + } while (start & 15); + if (!nl) + buf[pos++] = '\n'; + buf[pos] = '\0'; + pr_info("%s", buf); + } +} +static inline void hexdump(const void *ptr, size_t sz) +{ + unsigned long p = (unsigned long)ptr; + unsigned long start = p & ~(unsigned long)15; + unsigned long end = (p + sz + 15) & ~(unsigned long)15; + const unsigned char *c = ptr; + __hexdump(start, end, p, sz, c); +} + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_low.h +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_low.h @@ -0,0 +1,494 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_private.h" + +/***************************/ +/* Portal register assists */ +/***************************/ + +/* Cache-inhibited register offsets */ +#define REG_RCR_PI_CINH 0x0000 +#define REG_RCR_CI_CINH 0x0004 +#define REG_RCR_ITR 0x0008 +#define REG_CFG 0x0100 +#define REG_SCN(n) (0x0200 + ((n) << 2)) +#define REG_ISR 0x0e00 + +/* Cache-enabled register offsets */ +#define CL_CR 0x0000 +#define CL_RR0 0x0100 +#define CL_RR1 0x0140 +#define CL_RCR 0x1000 +#define CL_RCR_PI_CENA 0x3000 +#define CL_RCR_CI_CENA 0x3100 + +/* BTW, the drivers (and h/w programming model) already obtain the required + * synchronisation for portal accesses via lwsync(), hwsync(), and + * data-dependencies. Use of barrier()s or other order-preserving primitives + * simply degrade performance. Hence the use of the __raw_*() interfaces, which + * simply ensure that the compiler treats the portal registers as volatile (ie. + * non-coherent). */ + +/* Cache-inhibited register access. */ +#define __bm_in(bm, o) __raw_readl((bm)->addr_ci + (o)) +#define __bm_out(bm, o, val) __raw_writel((val), (bm)->addr_ci + (o)) +#define bm_in(reg) __bm_in(&portal->addr, REG_##reg) +#define bm_out(reg, val) __bm_out(&portal->addr, REG_##reg, val) + +/* Cache-enabled (index) register access */ +#define __bm_cl_touch_ro(bm, o) dcbt_ro((bm)->addr_ce + (o)) +#define __bm_cl_touch_rw(bm, o) dcbt_rw((bm)->addr_ce + (o)) +#define __bm_cl_in(bm, o) __raw_readl((bm)->addr_ce + (o)) +#define __bm_cl_out(bm, o, val) \ + do { \ + u32 *__tmpclout = (bm)->addr_ce + (o); \ + __raw_writel((val), __tmpclout); \ + dcbf(__tmpclout); \ + } while (0) +#define __bm_cl_invalidate(bm, o) dcbi((bm)->addr_ce + (o)) +#define bm_cl_touch_ro(reg) __bm_cl_touch_ro(&portal->addr, CL_##reg##_CENA) +#define bm_cl_touch_rw(reg) __bm_cl_touch_rw(&portal->addr, CL_##reg##_CENA) +#define bm_cl_in(reg) __bm_cl_in(&portal->addr, CL_##reg##_CENA) +#define bm_cl_out(reg, val) __bm_cl_out(&portal->addr, CL_##reg##_CENA, val) +#define bm_cl_invalidate(reg) __bm_cl_invalidate(&portal->addr, CL_##reg##_CENA) + +/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf + * analysis, look at using the "extra" bit in the ring index registers to avoid + * cyclic issues. */ +static inline u8 cyc_diff(u8 ringsize, u8 first, u8 last) +{ + /* 'first' is included, 'last' is excluded */ + if (first <= last) + return last - first; + return ringsize + last - first; +} + +/* Portal modes. + * Enum types; + * pmode == production mode + * cmode == consumption mode, + * Enum values use 3 letter codes. First letter matches the portal mode, + * remaining two letters indicate; + * ci == cache-inhibited portal register + * ce == cache-enabled portal register + * vb == in-band valid-bit (cache-enabled) + */ +enum bm_rcr_pmode { /* matches BCSP_CFG::RPM */ + bm_rcr_pci = 0, /* PI index, cache-inhibited */ + bm_rcr_pce = 1, /* PI index, cache-enabled */ + bm_rcr_pvb = 2 /* valid-bit */ +}; +enum bm_rcr_cmode { /* s/w-only */ + bm_rcr_cci, /* CI index, cache-inhibited */ + bm_rcr_cce /* CI index, cache-enabled */ +}; + + +/* ------------------------- */ +/* --- Portal structures --- */ + +#define BM_RCR_SIZE 8 + +struct bm_rcr { + struct bm_rcr_entry *ring, *cursor; + u8 ci, available, ithresh, vbit; +#ifdef CONFIG_FSL_DPA_CHECKING + u32 busy; + enum bm_rcr_pmode pmode; + enum bm_rcr_cmode cmode; +#endif +}; + +struct bm_mc { + struct bm_mc_command *cr; + struct bm_mc_result *rr; + u8 rridx, vbit; +#ifdef CONFIG_FSL_DPA_CHECKING + enum { + /* Can only be _mc_start()ed */ + mc_idle, + /* Can only be _mc_commit()ed or _mc_abort()ed */ + mc_user, + /* Can only be _mc_retry()ed */ + mc_hw + } state; +#endif +}; + +struct bm_addr { + void __iomem *addr_ce; /* cache-enabled */ + void __iomem *addr_ci; /* cache-inhibited */ +}; + +struct bm_portal { + struct bm_addr addr; + struct bm_rcr rcr; + struct bm_mc mc; + struct bm_portal_config config; +} ____cacheline_aligned; + + +/* --------------- */ +/* --- RCR API --- */ + +/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ +#define RCR_CARRYCLEAR(p) \ + (void *)((unsigned long)(p) & (~(unsigned long)(BM_RCR_SIZE << 6))) + +/* Bit-wise logic to convert a ring pointer to a ring index */ +static inline u8 RCR_PTR2IDX(struct bm_rcr_entry *e) +{ + return ((uintptr_t)e >> 6) & (BM_RCR_SIZE - 1); +} + +/* Increment the 'cursor' ring pointer, taking 'vbit' into account */ +static inline void RCR_INC(struct bm_rcr *rcr) +{ + /* NB: this is odd-looking, but experiments show that it generates + * fast code with essentially no branching overheads. We increment to + * the next RCR pointer and handle overflow and 'vbit'. */ + struct bm_rcr_entry *partial = rcr->cursor + 1; + rcr->cursor = RCR_CARRYCLEAR(partial); + if (partial != rcr->cursor) + rcr->vbit ^= BM_RCR_VERB_VBIT; +} + +static inline int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode, + __maybe_unused enum bm_rcr_cmode cmode) +{ + /* This use of 'register', as well as all other occurances, is because + * it has been observed to generate much faster code with gcc than is + * otherwise the case. */ + register struct bm_rcr *rcr = &portal->rcr; + u32 cfg; + u8 pi; + + rcr->ring = portal->addr.addr_ce + CL_RCR; + rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1); + pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1); + rcr->cursor = rcr->ring + pi; + rcr->vbit = (bm_in(RCR_PI_CINH) & BM_RCR_SIZE) ? BM_RCR_VERB_VBIT : 0; + rcr->available = BM_RCR_SIZE - 1 - cyc_diff(BM_RCR_SIZE, rcr->ci, pi); + rcr->ithresh = bm_in(RCR_ITR); +#ifdef CONFIG_FSL_DPA_CHECKING + rcr->busy = 0; + rcr->pmode = pmode; + rcr->cmode = cmode; +#endif + cfg = (bm_in(CFG) & 0xffffffe0) | (pmode & 0x3); /* BCSP_CFG::RPM */ + bm_out(CFG, cfg); + return 0; +} + +static inline void bm_rcr_finish(struct bm_portal *portal) +{ + register struct bm_rcr *rcr = &portal->rcr; + u8 pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1); + u8 ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1); + DPA_ASSERT(!rcr->busy); + if (pi != RCR_PTR2IDX(rcr->cursor)) + pr_crit("losing uncommited RCR entries\n"); + if (ci != rcr->ci) + pr_crit("missing existing RCR completions\n"); + if (rcr->ci != RCR_PTR2IDX(rcr->cursor)) + pr_crit("RCR destroyed unquiesced\n"); +} + +static inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal) +{ + register struct bm_rcr *rcr = &portal->rcr; + DPA_ASSERT(!rcr->busy); + if (!rcr->available) + return NULL; +#ifdef CONFIG_FSL_DPA_CHECKING + rcr->busy = 1; +#endif + dcbz_64(rcr->cursor); + return rcr->cursor; +} + +static inline void bm_rcr_abort(struct bm_portal *portal) +{ + __maybe_unused register struct bm_rcr *rcr = &portal->rcr; + DPA_ASSERT(rcr->busy); +#ifdef CONFIG_FSL_DPA_CHECKING + rcr->busy = 0; +#endif +} + +static inline struct bm_rcr_entry *bm_rcr_pend_and_next( + struct bm_portal *portal, u8 myverb) +{ + register struct bm_rcr *rcr = &portal->rcr; + DPA_ASSERT(rcr->busy); + DPA_ASSERT(rcr->pmode != bm_rcr_pvb); + if (rcr->available == 1) + return NULL; + rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit; + dcbf_64(rcr->cursor); + RCR_INC(rcr); + rcr->available--; + dcbz_64(rcr->cursor); + return rcr->cursor; +} + +static inline void bm_rcr_pci_commit(struct bm_portal *portal, u8 myverb) +{ + register struct bm_rcr *rcr = &portal->rcr; + DPA_ASSERT(rcr->busy); + DPA_ASSERT(rcr->pmode == bm_rcr_pci); + rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit; + RCR_INC(rcr); + rcr->available--; + hwsync(); + bm_out(RCR_PI_CINH, RCR_PTR2IDX(rcr->cursor)); +#ifdef CONFIG_FSL_DPA_CHECKING + rcr->busy = 0; +#endif +} + +static inline void bm_rcr_pce_prefetch(struct bm_portal *portal) +{ + __maybe_unused register struct bm_rcr *rcr = &portal->rcr; + DPA_ASSERT(rcr->pmode == bm_rcr_pce); + bm_cl_invalidate(RCR_PI); + bm_cl_touch_rw(RCR_PI); +} + +static inline void bm_rcr_pce_commit(struct bm_portal *portal, u8 myverb) +{ + register struct bm_rcr *rcr = &portal->rcr; + DPA_ASSERT(rcr->busy); + DPA_ASSERT(rcr->pmode == bm_rcr_pce); + rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit; + RCR_INC(rcr); + rcr->available--; + lwsync(); + bm_cl_out(RCR_PI, RCR_PTR2IDX(rcr->cursor)); +#ifdef CONFIG_FSL_DPA_CHECKING + rcr->busy = 0; +#endif +} + +static inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb) +{ + register struct bm_rcr *rcr = &portal->rcr; + struct bm_rcr_entry *rcursor; + DPA_ASSERT(rcr->busy); + DPA_ASSERT(rcr->pmode == bm_rcr_pvb); + lwsync(); + rcursor = rcr->cursor; + rcursor->__dont_write_directly__verb = myverb | rcr->vbit; + dcbf_64(rcursor); + RCR_INC(rcr); + rcr->available--; +#ifdef CONFIG_FSL_DPA_CHECKING + rcr->busy = 0; +#endif +} + +static inline u8 bm_rcr_cci_update(struct bm_portal *portal) +{ + register struct bm_rcr *rcr = &portal->rcr; + u8 diff, old_ci = rcr->ci; + DPA_ASSERT(rcr->cmode == bm_rcr_cci); + rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1); + diff = cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci); + rcr->available += diff; + return diff; +} + +static inline void bm_rcr_cce_prefetch(struct bm_portal *portal) +{ + __maybe_unused register struct bm_rcr *rcr = &portal->rcr; + DPA_ASSERT(rcr->cmode == bm_rcr_cce); + bm_cl_touch_ro(RCR_CI); +} + +static inline u8 bm_rcr_cce_update(struct bm_portal *portal) +{ + register struct bm_rcr *rcr = &portal->rcr; + u8 diff, old_ci = rcr->ci; + DPA_ASSERT(rcr->cmode == bm_rcr_cce); + rcr->ci = bm_cl_in(RCR_CI) & (BM_RCR_SIZE - 1); + bm_cl_invalidate(RCR_CI); + diff = cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci); + rcr->available += diff; + return diff; +} + +static inline u8 bm_rcr_get_ithresh(struct bm_portal *portal) +{ + register struct bm_rcr *rcr = &portal->rcr; + return rcr->ithresh; +} + +static inline void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh) +{ + register struct bm_rcr *rcr = &portal->rcr; + rcr->ithresh = ithresh; + bm_out(RCR_ITR, ithresh); +} + +static inline u8 bm_rcr_get_avail(struct bm_portal *portal) +{ + register struct bm_rcr *rcr = &portal->rcr; + return rcr->available; +} + +static inline u8 bm_rcr_get_fill(struct bm_portal *portal) +{ + register struct bm_rcr *rcr = &portal->rcr; + return BM_RCR_SIZE - 1 - rcr->available; +} + + +/* ------------------------------ */ +/* --- Management command API --- */ + +static inline int bm_mc_init(struct bm_portal *portal) +{ + register struct bm_mc *mc = &portal->mc; + mc->cr = portal->addr.addr_ce + CL_CR; + mc->rr = portal->addr.addr_ce + CL_RR0; + mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) & + BM_MCC_VERB_VBIT) ? 0 : 1; + mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0; +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_idle; +#endif + return 0; +} + +static inline void bm_mc_finish(struct bm_portal *portal) +{ + __maybe_unused register struct bm_mc *mc = &portal->mc; + DPA_ASSERT(mc->state == mc_idle); +#ifdef CONFIG_FSL_DPA_CHECKING + if (mc->state != mc_idle) + pr_crit("Losing incomplete MC command\n"); +#endif +} + +static inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal) +{ + register struct bm_mc *mc = &portal->mc; + DPA_ASSERT(mc->state == mc_idle); +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_user; +#endif + dcbz_64(mc->cr); + return mc->cr; +} + +static inline void bm_mc_abort(struct bm_portal *portal) +{ + __maybe_unused register struct bm_mc *mc = &portal->mc; + DPA_ASSERT(mc->state == mc_user); +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_idle; +#endif +} + +static inline void bm_mc_commit(struct bm_portal *portal, u8 myverb) +{ + register struct bm_mc *mc = &portal->mc; + struct bm_mc_result *rr = mc->rr + mc->rridx; + DPA_ASSERT(mc->state == mc_user); + lwsync(); + mc->cr->__dont_write_directly__verb = myverb | mc->vbit; + dcbf(mc->cr); + dcbit_ro(rr); +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_hw; +#endif +} + +static inline struct bm_mc_result *bm_mc_result(struct bm_portal *portal) +{ + register struct bm_mc *mc = &portal->mc; + struct bm_mc_result *rr = mc->rr + mc->rridx; + DPA_ASSERT(mc->state == mc_hw); + /* The inactive response register's verb byte always returns zero until + * its command is submitted and completed. This includes the valid-bit, + * in case you were wondering... */ + if (!__raw_readb(&rr->verb)) { + dcbit_ro(rr); + return NULL; + } + mc->rridx ^= 1; + mc->vbit ^= BM_MCC_VERB_VBIT; +#ifdef CONFIG_FSL_DPA_CHECKING + mc->state = mc_idle; +#endif + return rr; +} + + +/* ------------------------------------- */ +/* --- Portal interrupt register API --- */ + +static inline int bm_isr_init(__always_unused struct bm_portal *portal) +{ + return 0; +} + +static inline void bm_isr_finish(__always_unused struct bm_portal *portal) +{ +} + +#define SCN_REG(bpid) REG_SCN((bpid) / 32) +#define SCN_BIT(bpid) (0x80000000 >> (bpid & 31)) +static inline void bm_isr_bscn_mask(struct bm_portal *portal, u8 bpid, + int enable) +{ + u32 val; + DPA_ASSERT(bpid < bman_pool_max); + /* REG_SCN for bpid=0..31, REG_SCN+4 for bpid=32..63 */ + val = __bm_in(&portal->addr, SCN_REG(bpid)); + if (enable) + val |= SCN_BIT(bpid); + else + val &= ~SCN_BIT(bpid); + __bm_out(&portal->addr, SCN_REG(bpid), val); +} + +static inline u32 __bm_isr_read(struct bm_portal *portal, enum bm_isr_reg n) +{ + return __bm_in(&portal->addr, REG_ISR + (n << 2)); +} + +static inline void __bm_isr_write(struct bm_portal *portal, enum bm_isr_reg n, + u32 val) +{ + __bm_out(&portal->addr, REG_ISR + (n << 2), val); +} --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_test.h +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_test.h @@ -0,0 +1,92 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +void bman_test_high(void); +void bman_test_thresh(void); + +static inline void __hexdump(unsigned long start, unsigned long end, + unsigned long p, size_t sz, unsigned char *c) +{ + while (start < end) { + unsigned int pos = 0; + char buf[64]; + int nl = 0; + pos += sprintf(buf + pos, "%08lx: ", start); + do { + if ((start < p) || (start >= (p + sz))) + pos += sprintf(buf + pos, ".."); + else + pos += sprintf(buf + pos, "%02x", *(c++)); + if (!(++start & 15)) { + buf[pos++] = '\n'; + nl = 1; + } else { + nl = 0; + if(!(start & 1)) + buf[pos++] = ' '; + if(!(start & 3)) + buf[pos++] = ' '; + } + } while (start & 15); + if (!nl) + buf[pos++] = '\n'; + buf[pos] = '\0'; + pr_info("%s", buf); + } +} +static inline void hexdump(void *ptr, size_t sz) +{ + unsigned long p = (unsigned long)ptr; + unsigned long start = p & ~(unsigned long)15; + unsigned long end = (p + sz + 15) & ~(unsigned long)15; + unsigned char *c = ptr; + __hexdump(start, end, p, sz, c); +} +static inline void hexdump_by_cl(void *ptr, size_t sz) +{ + unsigned long p = (unsigned long)ptr; + unsigned long start = p & ~(unsigned long)63; + unsigned long end = (p + sz + 63) & ~(unsigned long)63; + unsigned char *c = ptr; + __hexdump(start, end, p, sz, c); +} + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/bman_high.c +++ linux-3.13.0/drivers/staging/fsl_qbman/bman_high.c @@ -0,0 +1,1043 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bman_low.h" + +/* Compilation constants */ +#define RCR_THRESH 2 /* reread h/w CI when running out of space */ +#define IRQNAME "BMan portal %d" +#define MAX_IRQNAME 16 /* big enough for "BMan portal %d" */ + +struct bman_portal { + struct bm_portal p; + /* 2-element array. pools[0] is mask, pools[1] is snapshot. */ + struct bman_depletion *pools; + int thresh_set; + unsigned long irq_sources; + u32 slowpoll; /* only used when interrupts are off */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + struct bman_pool *rcri_owned; /* only 1 release WAIT_SYNC at a time */ +#endif +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + spinlock_t sharing_lock; /* only used if is_shared */ + int is_shared; + struct bman_portal *sharing_redirect; +#endif + /* When the cpu-affine portal is activated, this is non-NULL */ + const struct bm_portal_config *config; + /* 64-entry hash-table of pool objects that are tracking depletion + * entry/exit (ie. BMAN_POOL_FLAG_DEPLETION). This isn't fast-path, so + * we're not fussy about cache-misses and so forth - whereas the above + * members should all fit in one cacheline. + * BTW, with 64 entries in the hash table and 64 buffer pools to track, + * you'll never guess the hash-function ... */ + struct bman_pool *cb[64]; + char irqname[MAX_IRQNAME]; +}; + +/* For an explanation of the locking, redirection, or affine-portal logic, + * please consult the Qman driver for details. This is the same, only simpler + * (no fiddly Qman-specific bits.) */ +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE +#define PORTAL_IRQ_LOCK(p, irqflags) \ + do { \ + if ((p)->is_shared) \ + spin_lock_irqsave(&(p)->sharing_lock, irqflags); \ + else \ + local_irq_save(irqflags); \ + } while (0) +#define PORTAL_IRQ_UNLOCK(p, irqflags) \ + do { \ + if ((p)->is_shared) \ + spin_unlock_irqrestore(&(p)->sharing_lock, irqflags); \ + else \ + local_irq_restore(irqflags); \ + } while (0) +#else +#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags) +#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags) +#endif + +static cpumask_t affine_mask; +static DEFINE_SPINLOCK(affine_mask_lock); +static DEFINE_PER_CPU(struct bman_portal, bman_affine_portal); +static inline struct bman_portal *get_raw_affine_portal(void) +{ + return &get_cpu_var(bman_affine_portal); +} +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE +static inline struct bman_portal *get_affine_portal(void) +{ + struct bman_portal *p = get_raw_affine_portal(); + if (p->sharing_redirect) + return p->sharing_redirect; + return p; +} +#else +#define get_affine_portal() get_raw_affine_portal() +#endif +static inline void put_affine_portal(void) +{ + put_cpu_var(bman_affine_portal); +} + +/* GOTCHA: this object type refers to a pool, it isn't *the* pool. There may be + * more than one such object per Bman buffer pool, eg. if different users of the + * pool are operating via different portals. */ +struct bman_pool { + struct bman_pool_params params; + /* Used for hash-table admin when using depletion notifications. */ + struct bman_portal *portal; + struct bman_pool *next; + /* stockpile state - NULL unless BMAN_POOL_FLAG_STOCKPILE is set */ + struct bm_buffer *sp; + unsigned int sp_fill; +#ifdef CONFIG_FSL_DPA_CHECKING + atomic_t in_use; +#endif +}; + +/* (De)Registration of depletion notification callbacks */ +static void depletion_link(struct bman_portal *portal, struct bman_pool *pool) +{ + __maybe_unused unsigned long irqflags; + pool->portal = portal; + PORTAL_IRQ_LOCK(portal, irqflags); + pool->next = portal->cb[pool->params.bpid]; + portal->cb[pool->params.bpid] = pool; + if (!pool->next) + /* First object for that bpid on this portal, enable the BSCN + * mask bit. */ + bm_isr_bscn_mask(&portal->p, pool->params.bpid, 1); + PORTAL_IRQ_UNLOCK(portal, irqflags); +} +static void depletion_unlink(struct bman_pool *pool) +{ + struct bman_pool *it, *last = NULL; + struct bman_pool **base = &pool->portal->cb[pool->params.bpid]; + __maybe_unused unsigned long irqflags; + PORTAL_IRQ_LOCK(pool->portal, irqflags); + it = *base; /* <-- gotcha, don't do this prior to the irq_save */ + while (it != pool) { + last = it; + it = it->next; + } + if (!last) + *base = pool->next; + else + last->next = pool->next; + if (!last && !pool->next) { + /* Last object for that bpid on this portal, disable the BSCN + * mask bit. */ + bm_isr_bscn_mask(&pool->portal->p, pool->params.bpid, 0); + /* And "forget" that we last saw this pool as depleted */ + bman_depletion_unset(&pool->portal->pools[1], + pool->params.bpid); + } + PORTAL_IRQ_UNLOCK(pool->portal, irqflags); +} + +/* In the case that the application's core loop calls qman_poll() and + * bman_poll(), we ought to balance how often we incur the overheads of the + * slow-path poll. We'll use two decrementer sources. The idle decrementer + * constant is used when the last slow-poll detected no work to do, and the busy + * decrementer constant when the last slow-poll had work to do. */ +#define SLOW_POLL_IDLE 1000 +#define SLOW_POLL_BUSY 10 +static u32 __poll_portal_slow(struct bman_portal *p, u32 is); + +#ifdef CONFIG_FSL_DPA_HAVE_IRQ +/* Portal interrupt handler */ +static irqreturn_t portal_isr(__always_unused int irq, void *ptr) +{ + struct bman_portal *p = ptr; + u32 clear = p->irq_sources; + u32 is = bm_isr_status_read(&p->p) & p->irq_sources; + clear |= __poll_portal_slow(p, is); + bm_isr_status_clear(&p->p, clear); + return IRQ_HANDLED; +} +#endif + +struct bman_portal *bman_create_affine_portal( + const struct bm_portal_config *config, + int recovery_mode __maybe_unused) +{ + struct bman_portal *portal = get_raw_affine_portal(); + struct bm_portal *__p = &portal->p; + const struct bman_depletion *pools = &config->public_cfg.mask; + int ret; + + /* prep the low-level portal struct with the mapped addresses from the + * config, everything that follows depends on it and "config" is more + * for (de)reference... */ + __p->addr.addr_ce = config->addr_virt[BM_ADDR_CE]; + __p->addr.addr_ci = config->addr_virt[BM_ADDR_CI]; + if (bm_rcr_init(__p, bm_rcr_pvb, bm_rcr_cce)) { + pr_err("Bman RCR initialisation failed\n"); + goto fail_rcr; + } + if (bm_mc_init(__p)) { + pr_err("Bman MC initialisation failed\n"); + goto fail_mc; + } + if (bm_isr_init(__p)) { + pr_err("Bman ISR initialisation failed\n"); + goto fail_isr; + } + if (!pools) + portal->pools = NULL; + else { + u8 bpid = 0; + portal->pools = kmalloc(2 * sizeof(*pools), GFP_KERNEL); + if (!portal->pools) + goto fail_pools; + portal->pools[0] = *pools; + bman_depletion_init(portal->pools + 1); + while (bpid < bman_pool_max) { + /* Default to all BPIDs disabled, we enable as required + * at run-time. */ + bm_isr_bscn_mask(__p, bpid, 0); + bpid++; + } + } + portal->slowpoll = 0; +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + portal->rcri_owned = NULL; +#endif +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + spin_lock_init(&portal->sharing_lock); + portal->is_shared = config->public_cfg.is_shared; + portal->sharing_redirect = NULL; +#endif + memset(&portal->cb, 0, sizeof(portal->cb)); + /* Write-to-clear any stale interrupt status bits */ + bm_isr_disable_write(__p, 0xffffffff); + portal->irq_sources = 0; + bm_isr_enable_write(__p, portal->irq_sources); + bm_isr_status_clear(__p, 0xffffffff); +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu); + if (request_irq(config->public_cfg.irq, portal_isr, + IRQF_NOBALANCING | IRQF_DISABLED, portal->irqname, + portal)) { + pr_err("request_irq() failed\n"); + goto fail_irq; + } + if (config->public_cfg.cpu != -1) { + disable_irq(config->public_cfg.irq); + irq_set_affinity(config->public_cfg.irq, + cpumask_of(config->public_cfg.cpu)); + } + enable_irq(config->public_cfg.irq); + /* Enable the bits that make sense */ + if (!recovery_mode) + bm_isr_uninhibit(__p); +#endif + /* Need RCR to be empty before continuing */ + bm_isr_disable_write(__p, ~BM_PIRQ_RCRI); + ret = bm_rcr_get_fill(__p); + if (ret) { + pr_err("Bman RCR unclean, need recovery\n"); + goto fail_rcr_empty; + } + /* Success */ + portal->config = config; + spin_lock(&affine_mask_lock); + cpumask_set_cpu(config->public_cfg.cpu, &affine_mask); + spin_unlock(&affine_mask_lock); + bm_isr_disable_write(__p, 0); + put_affine_portal(); + return portal; +fail_rcr_empty: +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + free_irq(config->public_cfg.irq, portal); +fail_irq: +#endif + if (portal->pools) + kfree(portal->pools); +fail_pools: + bm_isr_finish(__p); +fail_isr: + bm_mc_finish(__p); +fail_mc: + bm_rcr_finish(__p); +fail_rcr: + put_affine_portal(); + return NULL; +} + +struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect) +{ +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + struct bman_portal *p = get_raw_affine_portal(); + BUG_ON(p->config); + BUG_ON(p->is_shared); + BUG_ON(!redirect->config->public_cfg.is_shared); + p->irq_sources = 0; + p->sharing_redirect = redirect; + put_affine_portal(); + return p; +#else + BUG(); + return NULL; +#endif +} + +const struct bm_portal_config *bman_destroy_affine_portal(void) +{ + struct bman_portal *bm = get_raw_affine_portal(); + const struct bm_portal_config *pcfg; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (bm->sharing_redirect) { + bm->sharing_redirect = NULL; + put_affine_portal(); + return NULL; + } + bm->is_shared = 0; +#endif + pcfg = bm->config; + bm_rcr_cce_update(&bm->p); + bm_rcr_cce_update(&bm->p); +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + free_irq(pcfg->public_cfg.irq, bm); +#endif + kfree(bm->pools); + bm_isr_finish(&bm->p); + bm_mc_finish(&bm->p); + bm_rcr_finish(&bm->p); + bm->config = NULL; + spin_lock(&affine_mask_lock); + cpumask_clear_cpu(pcfg->public_cfg.cpu, &affine_mask); + spin_unlock(&affine_mask_lock); + put_affine_portal(); + return pcfg; +} + +/* When release logic waits on available RCR space, we need a global waitqueue + * in the case of "affine" use (as the waits wake on different cpus which means + * different portals - so we can't wait on any per-portal waitqueue). */ +static DECLARE_WAIT_QUEUE_HEAD(affine_queue); + +static u32 __poll_portal_slow(struct bman_portal *p, u32 is) +{ + struct bman_depletion tmp; + u32 ret = is; + + /* There is a gotcha to be aware of. If we do the query before clearing + * the status register, we may miss state changes that occur between the + * two. If we write to clear the status register before the query, the + * cache-enabled query command may overtake the status register write + * unless we use a heavyweight sync (which we don't want). Instead, we + * write-to-clear the status register then *read it back* before doing + * the query, hence the odd while loop with the 'is' accumulation. */ + if (is & BM_PIRQ_BSCN) { + struct bm_mc_result *mcr; + __maybe_unused unsigned long irqflags; + unsigned int i, j; + u32 __is; + bm_isr_status_clear(&p->p, BM_PIRQ_BSCN); + while ((__is = bm_isr_status_read(&p->p)) & BM_PIRQ_BSCN) { + is |= __is; + bm_isr_status_clear(&p->p, BM_PIRQ_BSCN); + } + is &= ~BM_PIRQ_BSCN; + PORTAL_IRQ_LOCK(p, irqflags); + bm_mc_start(&p->p); + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY); + while (!(mcr = bm_mc_result(&p->p))) + cpu_relax(); + tmp = mcr->query.ds.state; + PORTAL_IRQ_UNLOCK(p, irqflags); + for (i = 0; i < 2; i++) { + int idx = i * 32; + /* tmp is a mask of currently-depleted pools. + * pools[0] is mask of those we care about. + * pools[1] is our previous view (we only want to + * be told about changes). */ + tmp.__state[i] &= p->pools[0].__state[i]; + if (tmp.__state[i] == p->pools[1].__state[i]) + /* fast-path, nothing to see, move along */ + continue; + for (j = 0; j <= 31; j++, idx++) { + struct bman_pool *pool = p->cb[idx]; + int b4 = bman_depletion_get(&p->pools[1], idx); + int af = bman_depletion_get(&tmp, idx); + if (b4 == af) + continue; + while (pool) { + pool->params.cb(p, pool, + pool->params.cb_ctx, af); + pool = pool->next; + } + } + } + p->pools[1] = tmp; + } + + if (is & BM_PIRQ_RCRI) { + __maybe_unused unsigned long irqflags; + PORTAL_IRQ_LOCK(p, irqflags); + bm_rcr_cce_update(&p->p); +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + /* If waiting for sync, we only cancel the interrupt threshold + * when the ring utilisation hits zero. */ + if (p->rcri_owned) { + if (!bm_rcr_get_fill(&p->p)) { + p->rcri_owned = NULL; + bm_rcr_set_ithresh(&p->p, 0); + } + } else +#endif + bm_rcr_set_ithresh(&p->p, 0); + PORTAL_IRQ_UNLOCK(p, irqflags); + wake_up(&affine_queue); + bm_isr_status_clear(&p->p, BM_PIRQ_RCRI); + is &= ~BM_PIRQ_RCRI; + } + + /* There should be no status register bits left undefined */ + DPA_ASSERT(!is); + return ret; +} + +const struct bman_portal_config *bman_get_portal_config(void) +{ + struct bman_portal *p = get_affine_portal(); + const struct bman_portal_config *ret = &p->config->public_cfg; + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(bman_get_portal_config); + +u32 bman_irqsource_get(void) +{ + struct bman_portal *p = get_raw_affine_portal(); + u32 ret = p->irq_sources & BM_PIRQ_VISIBLE; + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(bman_irqsource_get); + +int bman_irqsource_add(__maybe_unused u32 bits) +{ +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + struct bman_portal *p = get_raw_affine_portal(); + int ret = 0; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (p->sharing_redirect) + ret = -EINVAL; + else +#endif + { + __maybe_unused unsigned long irqflags; + PORTAL_IRQ_LOCK(p, irqflags); + set_bits(bits & BM_PIRQ_VISIBLE, &p->irq_sources); + bm_isr_enable_write(&p->p, p->irq_sources); + PORTAL_IRQ_UNLOCK(p, irqflags); + } + put_affine_portal(); + return ret; +#else + pr_err("No Bman portal IRQ support, mustn't specify IRQ flags!"); + return -EINVAL; +#endif +} +EXPORT_SYMBOL(bman_irqsource_add); + +int bman_irqsource_remove(u32 bits) +{ +#ifdef CONFIG_FSL_DPA_HAVE_IRQ + struct bman_portal *p = get_raw_affine_portal(); + __maybe_unused unsigned long irqflags; + u32 ier; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (p->sharing_redirect) { + put_affine_portal(); + return -EINVAL; + } +#endif + /* Our interrupt handler only processes+clears status register bits that + * are in p->irq_sources. As we're trimming that mask, if one of them + * were to assert in the status register just before we remove it from + * the enable register, there would be an interrupt-storm when we + * release the IRQ lock. So we wait for the enable register update to + * take effect in h/w (by reading it back) and then clear all other bits + * in the status register. Ie. we clear them from ISR once it's certain + * IER won't allow them to reassert. */ + PORTAL_IRQ_LOCK(p, irqflags); + bits &= BM_PIRQ_VISIBLE; + clear_bits(bits, &p->irq_sources); + bm_isr_enable_write(&p->p, p->irq_sources); + ier = bm_isr_enable_read(&p->p); + /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a + * data-dependency, ie. to protect against re-ordering. */ + bm_isr_status_clear(&p->p, ~ier); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return 0; +#else + pr_err("No Bman portal IRQ support, mustn't specify IRQ flags!"); + return -EINVAL; +#endif +} +EXPORT_SYMBOL(bman_irqsource_remove); + +const cpumask_t *bman_affine_cpus(void) +{ + return &affine_mask; +} +EXPORT_SYMBOL(bman_affine_cpus); + +u32 bman_poll_slow(void) +{ + struct bman_portal *p = get_raw_affine_portal(); + u32 ret; +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (unlikely(p->sharing_redirect)) + ret = (u32)-1; + else +#endif + { + u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources; + ret = __poll_portal_slow(p, is); + bm_isr_status_clear(&p->p, ret); + } + put_affine_portal(); + return ret; +} +EXPORT_SYMBOL(bman_poll_slow); + +/* Legacy wrapper */ +void bman_poll(void) +{ + struct bman_portal *p = get_raw_affine_portal(); +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE + if (unlikely(p->sharing_redirect)) + goto done; +#endif + if (!(p->slowpoll--)) { + u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources; + u32 active = __poll_portal_slow(p, is); + if (active) + p->slowpoll = SLOW_POLL_BUSY; + else + p->slowpoll = SLOW_POLL_IDLE; + } +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE +done: +#endif + put_affine_portal(); +} +EXPORT_SYMBOL(bman_poll); + +int bman_recovery_cleanup_bpid(u32 bpid) +{ + struct bman_pool pool = { + .params = { + .bpid = bpid + } + }; + struct bm_buffer bufs[8]; + int ret = 0; + unsigned int num_bufs = 0; + do { + /* Acquire is all-or-nothing, so we drain in 8s, then in + * 1s for the remainder. */ + if (ret != 1) + ret = bman_acquire(&pool, bufs, 8, 0); + if (ret < 8) + ret = bman_acquire(&pool, bufs, 1, 0); + if (ret > 0) + num_bufs += ret; + } while (ret > 0); + if (num_bufs) + pr_info("Bman: BPID %d recovered (%d bufs)\n", bpid, num_bufs); + return 0; +} +EXPORT_SYMBOL(bman_recovery_cleanup_bpid); + +/* called from bman_driver.c::bman_recovery_exit() only (if exporting, use + * get_raw_affine_portal() and check for the "SLAVE" bit). */ +void bman_recovery_exit_local(void) +{ + struct bman_portal *p = get_affine_portal(); + bm_isr_status_clear(&p->p, 0xffffffff); + bm_isr_uninhibit(&p->p); + put_affine_portal(); +} + +static const u32 zero_thresholds[4] = {0, 0, 0, 0}; + +struct bman_pool *bman_new_pool(const struct bman_pool_params *params) +{ + struct bman_pool *pool = NULL; + u32 bpid; + + if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) { + int ret = bm_pool_new(&bpid); + if (ret) + return NULL; + } else { + if (params->bpid >= bman_pool_max) + return NULL; + bpid = params->bpid; + } +#ifdef CONFIG_FSL_BMAN_CONFIG + if (params->flags & BMAN_POOL_FLAG_THRESH) { + int ret = bm_pool_set(bpid, params->thresholds); + if (ret) + goto err; + } +#else + if (params->flags & BMAN_POOL_FLAG_THRESH) + goto err; +#endif + pool = kmalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + goto err; + pool->sp = NULL; + pool->sp_fill = 0; + pool->params = *params; +#ifdef CONFIG_FSL_DPA_CHECKING + atomic_set(&pool->in_use, 1); +#endif + if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) + pool->params.bpid = bpid; + if (params->flags & BMAN_POOL_FLAG_STOCKPILE) { + pool->sp = kmalloc(sizeof(struct bm_buffer) * BMAN_STOCKPILE_SZ, + GFP_KERNEL); + if (!pool->sp) + goto err; + } + if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION) { + struct bman_portal *p = get_affine_portal(); + if (!p->pools || !bman_depletion_get(&p->pools[0], bpid)) { + pr_err("Depletion events disabled for bpid %d\n", bpid); + goto err; + } + depletion_link(p, pool); + put_affine_portal(); + } + return pool; +err: +#ifdef CONFIG_FSL_BMAN_CONFIG + if (params->flags & BMAN_POOL_FLAG_THRESH) + bm_pool_set(bpid, zero_thresholds); +#endif + if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) + bm_pool_free(bpid); + if (pool) { + if (pool->sp) + kfree(pool->sp); + kfree(pool); + } + return NULL; +} +EXPORT_SYMBOL(bman_new_pool); + +void bman_free_pool(struct bman_pool *pool) +{ +#ifdef CONFIG_FSL_BMAN_CONFIG + if (pool->params.flags & BMAN_POOL_FLAG_THRESH) + bm_pool_set(pool->params.bpid, zero_thresholds); +#endif + if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION) + depletion_unlink(pool); + if (pool->params.flags & BMAN_POOL_FLAG_STOCKPILE) { + if (pool->sp_fill) + pr_err("Stockpile not flushed, has %u in bpid %u.\n", + pool->sp_fill, pool->params.bpid); + kfree(pool->sp); + pool->sp = NULL; + pool->params.flags ^= BMAN_POOL_FLAG_STOCKPILE; + } + if (pool->params.flags & BMAN_POOL_FLAG_DYNAMIC_BPID) { + /* When releasing a BPID to the dynamic allocator, that pool + * must be *empty*. This code makes it so by dropping everything + * into the bit-bucket. This ignores whether or not it was a + * mistake (or a leak) on the caller's part not to drain the + * pool beforehand. */ + struct bm_buffer bufs[8]; + int ret = 0; + do { + /* Acquire is all-or-nothing, so we drain in 8s, then in + * 1s for the remainder. */ + if (ret != 1) + ret = bman_acquire(pool, bufs, 8, 0); + if (ret < 8) + ret = bman_acquire(pool, bufs, 1, 0); + } while (ret > 0); + bm_pool_free(pool->params.bpid); + } + kfree(pool); +} +EXPORT_SYMBOL(bman_free_pool); + +const struct bman_pool_params *bman_get_params(const struct bman_pool *pool) +{ + return &pool->params; +} +EXPORT_SYMBOL(bman_get_params); + +static noinline void update_rcr_ci(struct bman_portal *p, u8 avail) +{ + if (avail) + bm_rcr_cce_prefetch(&p->p); + else + bm_rcr_cce_update(&p->p); +} + +int bman_rcr_is_empty(void) +{ + __maybe_unused unsigned long irqflags; + struct bman_portal *p = get_affine_portal(); + u8 avail; + + PORTAL_IRQ_LOCK(p, irqflags); + update_rcr_ci(p, 0); + avail = bm_rcr_get_fill(&p->p); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return (avail == 0); +} +EXPORT_SYMBOL(bman_rcr_is_empty); + +static inline struct bm_rcr_entry *try_rel_start(struct bman_portal **p, +#ifdef CONFIG_FSL_DPA_CAN_WAIT + __maybe_unused struct bman_pool *pool, +#endif + __maybe_unused unsigned long *irqflags, + __maybe_unused u32 flags) +{ + struct bm_rcr_entry *r; + u8 avail; + + *p = get_affine_portal(); + PORTAL_IRQ_LOCK(*p, (*irqflags)); +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) { + if ((*p)->rcri_owned) { + PORTAL_IRQ_UNLOCK(*p, (*irqflags)); + put_affine_portal(); + return NULL; + } + (*p)->rcri_owned = pool; + } +#endif + avail = bm_rcr_get_avail(&(*p)->p); + if (avail < 2) + update_rcr_ci(*p, avail); + r = bm_rcr_start(&(*p)->p); + if (unlikely(!r)) { +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) + (*p)->rcri_owned = NULL; +#endif + PORTAL_IRQ_UNLOCK(*p, (*irqflags)); + put_affine_portal(); + } + return r; +} + +#ifdef CONFIG_FSL_DPA_CAN_WAIT +static noinline struct bm_rcr_entry *__wait_rel_start(struct bman_portal **p, + struct bman_pool *pool, + __maybe_unused unsigned long *irqflags, + u32 flags) +{ + struct bm_rcr_entry *rcr = try_rel_start(p, pool, irqflags, flags); + if (!rcr) + bm_rcr_set_ithresh(&(*p)->p, 1); + return rcr; +} + +static noinline struct bm_rcr_entry *wait_rel_start(struct bman_portal **p, + struct bman_pool *pool, + __maybe_unused unsigned long *irqflags, + u32 flags) +{ + struct bm_rcr_entry *rcr; +#ifndef CONFIG_FSL_DPA_CAN_WAIT_SYNC + pool = NULL; +#endif + if (flags & BMAN_RELEASE_FLAG_WAIT_INT) + wait_event_interruptible(affine_queue, + (rcr = __wait_rel_start(p, pool, irqflags, flags))); + else + wait_event(affine_queue, + (rcr = __wait_rel_start(p, pool, irqflags, flags))); + return rcr; +} +#endif + +/* to facilitate better copying of bufs into the ring without either (a) copying + * noise into the first byte (prematurely triggering the command), nor (b) being + * very inefficient by copying small fields using read-modify-write */ +struct overlay_bm_buffer { + u32 first; + u32 second; +}; + +static inline int __bman_release(struct bman_pool *pool, + const struct bm_buffer *bufs, u8 num, u32 flags) +{ + struct bman_portal *p; + struct bm_rcr_entry *r; + struct overlay_bm_buffer *o_dest; + struct overlay_bm_buffer *o_src = (struct overlay_bm_buffer *)&bufs[0]; + __maybe_unused unsigned long irqflags; + u32 i = num - 1; + +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & BMAN_RELEASE_FLAG_WAIT) + r = wait_rel_start(&p, pool, &irqflags, flags); + else + r = try_rel_start(&p, pool, &irqflags, flags); +#else + r = try_rel_start(&p, &irqflags, flags); +#endif + if (!r) + return -EBUSY; + /* We can copy all but the first entry, as this can trigger badness + * with the valid-bit. Use the overlay to mask the verb byte. */ + o_dest = (struct overlay_bm_buffer *)&r->bufs[0]; + o_dest->first = (o_src->first & 0x0000ffff) | + (((u32)pool->params.bpid << 16) & 0x00ff0000); + o_dest->second = o_src->second; + if (i) + copy_words(&r->bufs[1], &bufs[1], i * sizeof(bufs[0])); + bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE | + (num & BM_RCR_VERB_BUFCOUNT_MASK)); +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + /* if we wish to sync we need to set the threshold after h/w sees the + * new ring entry. As we're mixing cache-enabled and cache-inhibited + * accesses, this requires a heavy-weight sync. */ + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) { + hwsync(); + bm_rcr_set_ithresh(&p->p, 1); + } +#endif + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) { + if (flags & BMAN_RELEASE_FLAG_WAIT_INT) + wait_event_interruptible(affine_queue, + (p->rcri_owned != pool)); + else + wait_event(affine_queue, (p->rcri_owned != pool)); + } +#endif + return 0; +} + +int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num, + u32 flags) +{ + int ret = 0; +#ifdef CONFIG_FSL_DPA_CHECKING + if (!num || (num > 8)) + return -EINVAL; + if (pool->params.flags & BMAN_POOL_FLAG_NO_RELEASE) + return -EINVAL; + if (!atomic_dec_and_test(&pool->in_use)) { + pr_crit("Parallel attempts to enter bman_released() detected."); + panic("only one instance of bman_released/acquired allowed"); + } +#endif + /* Without stockpile, this API is a pass-through to the h/w operation */ + if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE)) { + ret = __bman_release(pool, bufs, num, flags); + goto release_done; + } + /* This needs some explanation. Adding the given buffers may take the + * stockpile over the threshold, but in fact the stockpile may already + * *be* over the threshold if a previous release-to-hw attempt had + * failed. So we have 3 cases to cover; + * 1. we add to the stockpile and don't hit the threshold, + * 2. we add to the stockpile, hit the threshold and release-to-hw, + * 3. we have to release-to-hw before adding to the stockpile + * (not enough room in the stockpile for case 2). + * Our constraints on thresholds guarantee that in case 3, there must be + * at least 8 bufs already in the stockpile, so all release-to-hw ops + * are for 8 bufs. Despite all this, the API must indicate whether the + * given buffers were taken off the caller's hands, irrespective of + * whether a release-to-hw was attempted. */ + while (num) { + /* Add buffers to stockpile if they fit */ + if ((pool->sp_fill + num) < BMAN_STOCKPILE_SZ) { + copy_words(pool->sp + pool->sp_fill, bufs, + sizeof(struct bm_buffer) * num); + pool->sp_fill += num; + num = 0; /* --> will return success no matter what */ + } + /* Do hw op if hitting the high-water threshold */ + if ((pool->sp_fill + num) >= BMAN_STOCKPILE_HIGH) { + ret = __bman_release(pool, + pool->sp + (pool->sp_fill - 8), 8, flags); + if (ret) { + ret = (num ? ret : 0); + goto release_done; + } + pool->sp_fill -= 8; + } + } +release_done: +#ifdef CONFIG_FSL_DPA_CHECKING + atomic_inc(&pool->in_use); +#endif + return ret; +} +EXPORT_SYMBOL(bman_release); + +static inline int __bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, + u8 num) +{ + struct bman_portal *p = get_affine_portal(); + struct bm_mc_command *mcc; + struct bm_mc_result *mcr; + __maybe_unused unsigned long irqflags; + int ret; + + PORTAL_IRQ_LOCK(p, irqflags); + mcc = bm_mc_start(&p->p); + mcc->acquire.bpid = pool->params.bpid; + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | + (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT)); + while (!(mcr = bm_mc_result(&p->p))) + cpu_relax(); + ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT; + if (bufs) + copy_words(&bufs[0], &mcr->acquire.bufs[0], + num * sizeof(bufs[0])); + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + if (ret != num) + ret = -ENOMEM; + return ret; +} + +int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num, + u32 flags) +{ + int ret = 0; +#ifdef CONFIG_FSL_DPA_CHECKING + if (!num || (num > 8)) + return -EINVAL; + if (pool->params.flags & BMAN_POOL_FLAG_ONLY_RELEASE) + return -EINVAL; + if (!atomic_dec_and_test(&pool->in_use)) { + pr_crit("Parallel attempts to enter bman_acquire() detected."); + panic("only one instance of bman_released/acquired allowed"); + } +#endif + /* Without stockpile, this API is a pass-through to the h/w operation */ + if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE)) { + ret = __bman_acquire(pool, bufs, num); + goto acquire_done; + } + /* Only need a h/w op if we'll hit the low-water thresh */ + if (!(flags & BMAN_ACQUIRE_FLAG_STOCKPILE) && + (pool->sp_fill <= (BMAN_STOCKPILE_LOW + num))) { + /* refill stockpile with max amount, but if max amount + * isn't available, try amount the user wants */ + int bufcount = 8; + ret = __bman_acquire(pool, pool->sp + pool->sp_fill, bufcount); + if (ret < 0 && bufcount != num) { + bufcount = num; + /* Maybe buffer pool has less than 8 */ + ret = __bman_acquire(pool, pool->sp + pool->sp_fill, + bufcount); + } + if (ret < 0) + goto hw_starved; + DPA_ASSERT(ret == bufcount); + pool->sp_fill += bufcount; + } else { +hw_starved: + if (pool->sp_fill < num) { + ret = -ENOMEM; + goto acquire_done; + } + } + copy_words(bufs, pool->sp + (pool->sp_fill - num), + sizeof(struct bm_buffer) * num); + pool->sp_fill -= num; + ret = num; +acquire_done: +#ifdef CONFIG_FSL_DPA_CHECKING + atomic_inc(&pool->in_use); +#endif + return ret; +} +EXPORT_SYMBOL(bman_acquire); + +int bman_flush_stockpile(struct bman_pool *pool, u32 flags) +{ + u8 num; + int ret; + + while (pool->sp_fill) { + num = ((pool->sp_fill > 8) ? 8 : pool->sp_fill); + ret = __bman_release(pool, pool->sp + (pool->sp_fill - num), + num, flags); + if (ret) + return ret; + pool->sp_fill -= num; + } + return 0; +} +EXPORT_SYMBOL(bman_flush_stockpile); + +int bman_query_pools(struct bm_pool_state *state) +{ + struct bman_portal *p = get_affine_portal(); + struct bm_mc_result *mcr; + __maybe_unused unsigned long irqflags; + + PORTAL_IRQ_LOCK(p, irqflags); + bm_mc_start(&p->p); + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY); + while (!(mcr = bm_mc_result(&p->p))) + cpu_relax(); + DPA_ASSERT((mcr->verb & BM_MCR_VERB_CMD_MASK) == BM_MCR_VERB_CMD_QUERY); + *state = mcr->query; + PORTAL_IRQ_UNLOCK(p, irqflags); + put_affine_portal(); + return 0; +} +EXPORT_SYMBOL(bman_query_pools); + --- linux-3.13.0.orig/drivers/staging/fsl_qbman/dpa_sys.h +++ linux-3.13.0/drivers/staging/fsl_qbman/dpa_sys.h @@ -0,0 +1,324 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DPA_SYS_H +#define DPA_SYS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* When copying aligned words or shorts, try to avoid memcpy() */ +#define CONFIG_TRY_BETTER_MEMCPY + +/* This takes a "phandle" and dereferences to the cpu device-tree node, + * returning the cpu index. Returns negative error codes. */ +static inline int check_cpu_phandle(phandle ph) +{ + const u32 *cpu_val; + struct device_node *tmp_node = of_find_node_by_phandle(ph); + int cpu, ret; + + if (!tmp_node) { + pr_err("Bad 'cpu-handle'\n"); + return -EINVAL; + } + cpu_val = of_get_property(tmp_node, "reg", &ret); + if (!cpu_val || (ret != sizeof(*cpu_val))) { + pr_err("Can't get %s property 'reg'\n", tmp_node->full_name); + return -ENODEV; + } + for_each_present_cpu(cpu) { + if (*cpu_val == get_hard_smp_processor_id(cpu)) + goto done; + } + pr_err("Invalid cpu index %d in %s\n", *cpu_val, tmp_node->full_name); + return -ENODEV; +done: + of_node_put(tmp_node); + return cpu; +} + +/* Handle portals destined for USDPAA (user-space). + * + * The UIO layer is mostly Qman/Bman-agnostic, however the rest of the driver is + * separated along interface and implementation lines. So each Qman/Bman driver + * instantiates a dpa_uio_class and links dpa_uio_portal objects into it. If + * the dpa_uio driver module is built, it queries these two classes and creates + * the UIO devices accordingly. + */ +struct dpa_uio_class { + struct list_head list; + const char *dev_prefix; +}; +struct dpa_uio_portal { + enum { + dpa_uio_portal_bman, + dpa_uio_portal_qman, + } type; + union { + const struct bm_portal_config *bm_cfg; + const struct qm_portal_config *qm_cfg; + }; + struct list_head node; +}; +const struct dpa_uio_class *dpa_uio_bman(void); +const struct dpa_uio_class *dpa_uio_qman(void); + +/* These stubs are re-mapped to hypervisor+failover features in kernel trees + * that contain that support. */ +static inline int fsl_dpa_should_recover(void) +{ + return 0; +} +static inline int pamu_enable_liodn(struct device_node *n, int i) +{ + return 0; +} +/***********************/ +/* Misc inline assists */ +/***********************/ + +/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler + * barriers and that dcb*() won't fall victim to compiler or execution + * reordering with respect to other code/instructions that manipulate the same + * cacheline. */ +#define hwsync() \ + do { \ + __asm__ __volatile__ ("sync" : : : "memory"); \ + } while(0) +#define lwsync() \ + do { \ + __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory"); \ + } while(0) +#define dcbf(p) \ + do { \ + __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory"); \ + } while(0) +#define dcbt_ro(p) \ + do { \ + __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p)); \ + } while(0) +#define dcbt_rw(p) \ + do { \ + __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p)); \ + } while(0) +#define dcbi(p) dcbf(p) +#ifdef CONFIG_PPC_E500MC +#define dcbzl(p) \ + do { \ + __asm__ __volatile__ ("dcbzl 0,%0" : : "r" (p)); \ + } while (0) +#define dcbz_64(p) \ + do { \ + dcbzl(p); \ + } while (0) +#define dcbf_64(p) \ + do { \ + dcbf(p); \ + } while (0) +/* Commonly used combo */ +#define dcbit_ro(p) \ + do { \ + dcbi(p); \ + dcbt_ro(p); \ + } while (0) +#else +#define dcbz(p) \ + do { \ + __asm__ __volatile__ ("dcbz 0,%0" : : "r" (p)); \ + } while (0) +#define dcbz_64(p) \ + do { \ + dcbz((u32)p + 32); \ + dcbz(p); \ + } while (0) +#define dcbf_64(p) \ + do { \ + dcbf((u32)p + 32); \ + dcbf(p); \ + } while (0) +/* Commonly used combo */ +#define dcbit_ro(p) \ + do { \ + dcbi(p); \ + dcbi((u32)p + 32); \ + dcbt_ro(p); \ + dcbt_ro((u32)p + 32); \ + } while (0) +#endif /* CONFIG_PPC_E500MC */ + +static inline u64 mfatb(void) +{ + u32 hi, lo, chk; + do { + hi = mfspr(SPRN_ATBU); + lo = mfspr(SPRN_ATBL); + chk = mfspr(SPRN_ATBU); + } while (unlikely(hi != chk)); + return ((u64)hi << 32) | (u64)lo; +} + +#ifdef CONFIG_FSL_DPA_CHECKING +#define DPA_ASSERT(x) \ + do { \ + if (!(x)) { \ + pr_crit("ASSERT: (%s:%d) %s\n", __FILE__, __LINE__, \ + __stringify_1(x)); \ + dump_stack(); \ + panic("assertion failure"); \ + } \ + } while(0) +#else +#define DPA_ASSERT(x) +#endif + +/* memcpy() stuff - when you know alignments in advance */ +#ifdef CONFIG_TRY_BETTER_MEMCPY +static inline void copy_words(void *dest, const void *src, size_t sz) +{ + u32 *__dest = dest; + const u32 *__src = src; + size_t __sz = sz >> 2; + BUG_ON((unsigned long)dest & 0x3); + BUG_ON((unsigned long)src & 0x3); + BUG_ON(sz & 0x3); + while (__sz--) + *(__dest++) = *(__src++); +} +static inline void copy_shorts(void *dest, const void *src, size_t sz) +{ + u16 *__dest = dest; + const u16 *__src = src; + size_t __sz = sz >> 1; + BUG_ON((unsigned long)dest & 0x1); + BUG_ON((unsigned long)src & 0x1); + BUG_ON(sz & 0x1); + while (__sz--) + *(__dest++) = *(__src++); +} +static inline void copy_bytes(void *dest, const void *src, size_t sz) +{ + u8 *__dest = dest; + const u8 *__src = src; + while (sz--) + *(__dest++) = *(__src++); +} +#else +#define copy_words memcpy +#define copy_shorts memcpy +#define copy_bytes memcpy +#endif + +/************/ +/* RB-trees */ +/************/ + +/* We encapsulate RB-trees so that its easier to use non-linux forms in + * non-linux systems. This also encapsulates the extra plumbing that linux code + * usually provides when using RB-trees. This encapsulation assumes that the + * data type held by the tree is u32. */ + +struct dpa_rbtree { + struct rb_root root; +}; +#define DPA_RBTREE { .root = RB_ROOT } + +static inline void dpa_rbtree_init(struct dpa_rbtree *tree) +{ + tree->root = RB_ROOT; +} + +#define IMPLEMENT_DPA_RBTREE(name, type, node_field, val_field) \ +static inline int name##_push(struct dpa_rbtree *tree, type *obj) \ +{ \ + struct rb_node *parent = NULL, **p = &tree->root.rb_node; \ + while (*p) { \ + u32 item; \ + parent = *p; \ + item = rb_entry(parent, type, node_field)->val_field; \ + if (obj->val_field < item) \ + p = &parent->rb_left; \ + else if (obj->val_field > item) \ + p = &parent->rb_right; \ + else \ + return -EBUSY; \ + } \ + rb_link_node(&obj->node_field, parent, p); \ + rb_insert_color(&obj->node_field, &tree->root); \ + return 0; \ +} \ +static inline void name##_del(struct dpa_rbtree *tree, type *obj) \ +{ \ + rb_erase(&obj->node_field, &tree->root); \ +} \ +static inline type *name##_find(struct dpa_rbtree *tree, u32 val) \ +{ \ + type *ret; \ + struct rb_node *p = tree->root.rb_node; \ + while (p) { \ + ret = rb_entry(p, type, node_field); \ + if (val < ret->val_field) \ + p = p->rb_left; \ + else if (val > ret->val_field) \ + p = p->rb_right; \ + else \ + return ret; \ + } \ + return NULL; \ +} + +#endif /* DPA_SYS_H */ + --- linux-3.13.0.orig/drivers/staging/rtl8712/usb_intf.c +++ linux-3.13.0/drivers/staging/rtl8712/usb_intf.c @@ -353,6 +353,10 @@ } } +static const struct device_type wlan_type = { + .name = "wlan", +}; + /* * drv_init() - a device potentially for us * @@ -388,6 +392,7 @@ padapter->pusb_intf = pusb_intf; usb_set_intfdata(pusb_intf, pnetdev); SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); + pnetdev->dev.type = &wlan_type; /* step 2. */ padapter->dvobj_init = &r8712_usb_dvobj_init; padapter->dvobj_deinit = &r8712_usb_dvobj_deinit; --- linux-3.13.0.orig/drivers/staging/zram/zram_drv.c +++ linux-3.13.0/drivers/staging/zram/zram_drv.c @@ -552,14 +552,14 @@ size_t index; struct zram_meta *meta; - flush_work(&zram->free_work); - down_write(&zram->init_lock); if (!zram->init_done) { up_write(&zram->init_lock); return; } + flush_work(&zram->free_work); + meta = zram->meta; zram->init_done = 0; @@ -621,6 +621,8 @@ disksize = PAGE_ALIGN(disksize); meta = zram_meta_alloc(disksize); + if (!meta) + return -ENOMEM; down_write(&zram->init_lock); if (zram->init_done) { up_write(&zram->init_lock); --- linux-3.13.0.orig/drivers/staging/android/binder.c +++ linux-3.13.0/drivers/staging/android/binder.c @@ -2904,7 +2904,7 @@ refs++; if (!ref->death) - goto out; + continue; death++; @@ -2917,7 +2917,6 @@ BUG(); } -out: binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_low.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_low.c @@ -0,0 +1,276 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_private.h" + +MODULE_AUTHOR("Geoff Thorpe"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL PME2 (p4080) device usage"); + +#define PME_RESIDUE_SIZE 128 +#define PME_RESIDUE_ALIGN 64 +#define PME_FLOW_SIZE sizeof(struct pme_flow) +#define PME_FLOW_ALIGN 32 +static struct kmem_cache *slab_residue; +static struct kmem_cache *slab_flow; +static struct kmem_cache *slab_fq; + +/* Hack to support "pme_map()". The point of this is that dma_map_single() now + * requires a non-NULL device, so the idea is that address mapping must be + * device-sensitive. Now the PAMU IO-MMU already takes care of this, as can be + * seen by the device-tree structure generated by the hypervisor (each portal + * node has sub-nodes for each h/w end-point it provides access to, and each + * sub-node has its own LIODN configuration). So we just need to map cpu + * pointers to (guest-)physical address and the PAMU takes care of the rest, so + * this doesn't need to be portal-sensitive nor device-sensitive. */ +static struct platform_device *pdev; + +static int pme2_low_init(void) +{ + int ret = -ENOMEM; + + slab_residue = kmem_cache_create("pme2_residue", PME_RESIDUE_SIZE, + PME_RESIDUE_ALIGN, SLAB_HWCACHE_ALIGN, NULL); + if (!slab_residue) + goto end; + slab_flow = kmem_cache_create("pme2_flow", PME_FLOW_SIZE, + PME_FLOW_ALIGN, 0, NULL); + if (!slab_flow) + goto end; + slab_fq = kmem_cache_create("pme2_fqslab", sizeof(struct qman_fq), + __alignof__(struct qman_fq), SLAB_HWCACHE_ALIGN, NULL); + if (!slab_fq) + goto end; + ret = -ENODEV; + pdev = platform_device_alloc("pme", -1); + if (!pdev) + goto end; + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(40))) + goto end; + if (platform_device_add(pdev)) + goto end; + return 0; +end: + if (pdev) { + platform_device_put(pdev); + pdev = NULL; + } + if (slab_flow) { + kmem_cache_destroy(slab_flow); + slab_flow = NULL; + } + if (slab_residue) { + kmem_cache_destroy(slab_residue); + slab_residue = NULL; + } + if (slab_fq) { + kmem_cache_destroy(slab_fq); + slab_fq = NULL; + } + return ret; +} + +static void pme2_low_exit(void) +{ + platform_device_del(pdev); + platform_device_put(pdev); + pdev = NULL; + kmem_cache_destroy(slab_fq); + kmem_cache_destroy(slab_flow); + kmem_cache_destroy(slab_residue); + slab_fq = slab_flow = slab_residue = NULL; +} + +module_init(pme2_low_init); +module_exit(pme2_low_exit); + +struct qman_fq *slabfq_alloc(void) +{ + return kmem_cache_alloc(slab_fq, GFP_KERNEL); +} + +void slabfq_free(struct qman_fq *fq) +{ + kmem_cache_free(slab_fq, fq); +} + +/***********************/ +/* low-level functions */ +/***********************/ + +struct pme_hw_residue *pme_hw_residue_new(void) +{ + return kmem_cache_alloc(slab_residue, GFP_KERNEL); +} +EXPORT_SYMBOL(pme_hw_residue_new); + +void pme_hw_residue_free(struct pme_hw_residue *p) +{ + kmem_cache_free(slab_residue, p); +} +EXPORT_SYMBOL(pme_hw_residue_free); + +struct pme_hw_flow *pme_hw_flow_new(void) +{ + struct pme_flow *flow = kmem_cache_zalloc(slab_flow, GFP_KERNEL); + return (struct pme_hw_flow *)flow; +} +EXPORT_SYMBOL(pme_hw_flow_new); + +void pme_hw_flow_free(struct pme_hw_flow *p) +{ + kmem_cache_free(slab_flow, p); +} +EXPORT_SYMBOL(pme_hw_flow_free); + +static const struct pme_flow default_sw_flow = { + .sos = 1, + .srvm = 0, + .esee = 1, + .ren = 0, + .rlen = 0, + .seqnum_hi = 0, + .seqnum_lo = 0, + .sessionid = 0x7ffffff, + .rptr_hi = 0, + .rptr_lo = 0, + .clim = 0xffff, + .mlim = 0xffff +}; + +void pme_sw_flow_init(struct pme_flow *flow) +{ + memcpy(flow, &default_sw_flow, sizeof(*flow)); +} +EXPORT_SYMBOL(pme_sw_flow_init); + +void pme_initfq(struct qm_mcc_initfq *initfq, struct pme_hw_flow *flow, u8 qos, + u8 rbpid, u32 rfqid) +{ + struct pme_context_a *pme_a = + (struct pme_context_a *)&initfq->fqd.context_a; + struct pme_context_b *pme_b = + (struct pme_context_b *)&initfq->fqd.context_b; + + initfq->we_mask = QM_INITFQ_WE_DESTWQ | QM_INITFQ_WE_CONTEXTA | + QM_INITFQ_WE_CONTEXTB; + initfq->fqd.dest.channel = qm_channel_pme; + initfq->fqd.dest.wq = qos; + if (flow) { + dma_addr_t fcp = flow_map((struct pme_flow *)flow); + pme_a->mode = pme_mode_flow; + pme_context_a_set64(pme_a, fcp); + } else { + pme_a->mode = pme_mode_direct; + pme_context_a_set64(pme_a, 0); + } + pme_b->rbpid = rbpid; + pme_b->rfqid = rfqid; +} +EXPORT_SYMBOL(pme_initfq); + +void pme_fd_cmd_nop(struct qm_fd *fd) +{ + struct pme_cmd_nop *nop = (struct pme_cmd_nop *)&fd->cmd; + nop->cmd = pme_cmd_nop; +} +EXPORT_SYMBOL(pme_fd_cmd_nop); + +void pme_fd_cmd_fcw(struct qm_fd *fd, u8 flags, struct pme_flow *flow, + struct pme_hw_residue *residue) +{ + dma_addr_t f; + struct pme_cmd_flow_write *fcw = (struct pme_cmd_flow_write *)&fd->cmd; + + BUG_ON(!flow); + BUG_ON((unsigned long)flow & 31); + fcw->cmd = pme_cmd_flow_write; + fcw->flags = flags; + if (flags & PME_CMD_FCW_RES) { + if (residue) { + dma_addr_t rptr = residue_map(residue); + BUG_ON(!residue); + BUG_ON((unsigned long)residue & 63); + pme_flow_rptr_set64(flow, rptr); + } else + pme_flow_rptr_set64(flow, 0); + } + f = flow_map(flow); + qm_fd_addr_set64(fd, f); + fd->format = qm_fd_contig; + fd->offset = 0; + fd->length20 = sizeof(*flow); +} +EXPORT_SYMBOL(pme_fd_cmd_fcw); + +void pme_fd_cmd_fcr(struct qm_fd *fd, struct pme_flow *flow) +{ + dma_addr_t f; + struct pme_cmd_flow_read *fcr = (struct pme_cmd_flow_read *)&fd->cmd; + + BUG_ON(!flow); + BUG_ON((unsigned long)flow & 31); + fcr->cmd = pme_cmd_flow_read; + f = flow_map(flow); + qm_fd_addr_set64(fd, f); + fd->format = qm_fd_contig; + fd->offset = 0; + fd->length20 = sizeof(*flow); +} +EXPORT_SYMBOL(pme_fd_cmd_fcr); + +void pme_fd_cmd_pmtcc(struct qm_fd *fd) +{ + struct pme_cmd_pmtcc *pmtcc = (struct pme_cmd_pmtcc *)&fd->cmd; + pmtcc->cmd = pme_cmd_pmtcc; +} +EXPORT_SYMBOL(pme_fd_cmd_pmtcc); + +void pme_fd_cmd_scan(struct qm_fd *fd, u32 args) +{ + struct pme_cmd_scan *scan = (struct pme_cmd_scan *)&fd->cmd; + fd->cmd = args; + scan->cmd = pme_cmd_scan; +} +EXPORT_SYMBOL(pme_fd_cmd_scan); + +dma_addr_t pme_map(void *ptr) +{ + return dma_map_single(&pdev->dev, ptr, 1, DMA_BIDIRECTIONAL); +} +EXPORT_SYMBOL(pme_map); + +int pme_map_error(dma_addr_t dma_addr) +{ + return dma_mapping_error(&pdev->dev, dma_addr); +} +EXPORT_SYMBOL(pme_map_error); + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_scan.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_scan.c @@ -0,0 +1,1111 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_private.h" +#include +#include +#include +#include + +#define WAIT_AND_INTERRUPTABLE (PME_CTX_OP_WAIT|PME_CTX_OP_WAIT_INT) +#define INPUT_FRM 1 +#define OUTPUT_FRM 0 +/* Private structure that is allocated for each open that is done on the + * pme_scan device. */ +struct scan_session { + /* The ctx that is needed to communicate with the pme high level */ + struct pme_ctx ctx; + /* Locks completed_commands */ + spinlock_t set_subset_lock; + __u8 set; + __u16 subset; + /* For asynchronous processing */ + wait_queue_head_t waiting_for_completion; + struct list_head completed_commands; + /* Locks completed_commands */ + spinlock_t completed_commands_lock; + u32 completed_count; +}; + +/* Command Token for scan operations. One of these is created for every + * operation on a context. When the context operation is complete cleanup + * is done */ +struct cmd_token { + /* pme high level token */ + struct pme_ctx_token hl_token; + /* The kernels copy of the user op structure */ + struct pme_scan_cmd kernel_op; + /* Set to non zero if this is a synchronous request */ + u8 synchronous; + /* data */ + struct qm_fd tx_fd; + struct qm_sg_entry tx_comp[2]; + struct qm_fd rx_fd; + void *tx_data; + size_t tx_size; + void *rx_data; + size_t rx_size; + /* For blocking requests, we need a wait point and condition */ + wait_queue_head_t *queue; + /* List management for completed async requests */ + struct list_head completed_list; + u8 done; + u8 ern; +}; + +struct ctrl_op { + struct pme_ctx_ctrl_token ctx_ctr; + struct completion cb_done; + enum pme_status cmd_status; + u8 res_flag; + u8 ern; +}; + +#ifdef CONFIG_COMPAT +static void compat_to_scan_cmd(struct pme_scan_cmd *dst, + struct compat_pme_scan_cmd *src) +{ + dst->flags = src->flags; + dst->opaque = compat_ptr(src->opaque); + dst->input.data = compat_ptr(src->input.data); + dst->input.size = src->input.size; + dst->output.data = compat_ptr(src->output.data); + dst->output.size = src->output.size; +} + +static void scan_result_to_compat(struct compat_pme_scan_result *dst, + struct pme_scan_result *src) +{ + dst->flags = src->flags; + dst->opaque = ptr_to_compat(src->opaque); + dst->status = src->status; + dst->output.data = ptr_to_compat(src->output.data); + dst->output.size = src->output.size; +} + +static void compat_to_scan_result(struct pme_scan_result *dst, + struct compat_pme_scan_result *src) +{ + dst->flags = src->flags; + dst->opaque = compat_ptr(src->opaque); + dst->status = src->status; + dst->output.data = compat_ptr(src->output.data); + dst->output.size = src->output.size; +} +#endif + +static void ctrl_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_ctrl_token *token) +{ + struct ctrl_op *ctrl = (struct ctrl_op *)token; + ctrl->cmd_status = pme_fd_res_status(fd); + ctrl->res_flag = pme_fd_res_flags(fd) & PME_STATUS_UNRELIABLE; + complete(&ctrl->cb_done); +} + +static void ctrl_ern_cb(struct pme_ctx *ctx, const struct qm_mr_entry *mr, + struct pme_ctx_ctrl_token *token) +{ + struct ctrl_op *ctrl = (struct ctrl_op *)token; + ctrl->ern = 1; + complete(&ctrl->cb_done); +} + +static inline int scan_data_empty(struct scan_session *session) +{ + return list_empty(&session->completed_commands); +} + +/* Cleanup for the execute_cmd method */ +static inline void cleanup_token(struct cmd_token *token_p) +{ + kfree(token_p->tx_data); + kfree(token_p->rx_data); + return; +} + +/* Callback for scan operations */ +static void scan_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_token *ctx_token) +{ + struct cmd_token *token = (struct cmd_token *)ctx_token; + struct scan_session *session = (struct scan_session *)ctx; + + token->rx_fd = *fd; + /* If this is a asynchronous command, queue the token */ + if (!token->synchronous) { + spin_lock(&session->completed_commands_lock); + list_add_tail(&token->completed_list, + &session->completed_commands); + session->completed_count++; + spin_unlock(&session->completed_commands_lock); + } + /* Wake up the thread that's waiting for us */ + token->done = 1; + wake_up(token->queue); + return; +} + +static void scan_ern_cb(struct pme_ctx *ctx, const struct qm_mr_entry *mr, + struct pme_ctx_token *ctx_token) +{ + struct cmd_token *token = (struct cmd_token *)ctx_token; + struct scan_session *session = (struct scan_session *)ctx; + + token->ern = 1; + token->rx_fd = mr->ern.fd; + /* If this is a asynchronous command, queue the token */ + if (!token->synchronous) { + spin_lock(&session->completed_commands_lock); + list_add_tail(&token->completed_list, + &session->completed_commands); + session->completed_count++; + spin_unlock(&session->completed_commands_lock); + } + /* Wake up the thread that's waiting for us */ + token->done = 1; + wake_up(token->queue); + return; +} + +static int process_completed_token(struct file *fp, struct cmd_token *token_p, + struct pme_scan_result *scan_result) +{ + int ret = 0; + u32 src_sz, dst_sz; + + memset(scan_result, 0, sizeof(struct pme_scan_result)); + if (token_p->ern) { + ret = -EIO; + goto done; + } + scan_result->output.data = token_p->kernel_op.output.data; + + if (token_p->rx_fd.format == qm_fd_compound) { + /* Need to copy output */ + src_sz = token_p->tx_comp[OUTPUT_FRM].length; + dst_sz = token_p->kernel_op.output.size; + scan_result->output.size = min(dst_sz, src_sz); + /* Doesn't make sense we generated more than available space + * should have got truncation. + */ + BUG_ON(dst_sz < src_sz); + if (copy_to_user(scan_result->output.data, token_p->rx_data, + scan_result->output.size)) { + pr_err("Error copying to user data\n"); + cleanup_token(token_p); + return -EFAULT; + } + } else if (token_p->rx_fd.format == qm_fd_sg_big) + scan_result->output.size = 0; + else + pr_err("pme2_scan: unexpected frame type received\n"); + + scan_result->flags |= pme_fd_res_flags(&token_p->rx_fd); + scan_result->status |= pme_fd_res_status(&token_p->rx_fd); +done: + scan_result->opaque = token_p->kernel_op.opaque; + cleanup_token(token_p); + return ret; +} + +static int getscan_cmd(struct file *fp, struct scan_session *session, + struct pme_scan_params __user *user_scan_params) +{ + int ret = 0; + struct pme_flow params; + struct pme_scan_params local_scan_params; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .ctx_ctr.ern_cb = ctrl_ern_cb, + .cmd_status = 0, + .res_flag = 0, + .ern = 0 + }; + init_completion(&ctx_ctrl.cb_done); + + memset(&local_scan_params, 0, sizeof(local_scan_params)); + + /* must be enabled */ + if (pme_ctx_is_disabled(&session->ctx)) { + pr_err("pme2_scan: ctx is disabled\n"); + ret = -EINVAL; + goto done; + } + ret = pme_ctx_ctrl_read_flow(&session->ctx, WAIT_AND_INTERRUPTABLE, + ¶ms, &ctx_ctrl.ctx_ctr); + if (ret) { + PMEPRINFO("read flow error %d\n", ret); + goto done; + } + wait_for_completion(&ctx_ctrl.cb_done); + + if (ctx_ctrl.ern || ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + PMEPRINFO("read flow error %d\n", ctx_ctrl.cmd_status); + ret = -EFAULT; + goto done; + } + local_scan_params.residue.enable = params.ren; + local_scan_params.residue.length = params.rlen; + local_scan_params.sre.sessionid = params.sessionid; + local_scan_params.sre.verbose = params.srvm; + local_scan_params.sre.esee = params.esee; + local_scan_params.dxe.clim = params.clim; + local_scan_params.dxe.mlim = params.mlim; + spin_lock(&session->set_subset_lock); + local_scan_params.pattern.set = session->set; + local_scan_params.pattern.subset = session->subset; + spin_unlock(&session->set_subset_lock); + + if (copy_to_user(user_scan_params, &local_scan_params, + sizeof(local_scan_params))) { + pr_err("Error copying to user data\n"); + ret = -EFAULT; + } +done: + return ret; +} + +static int setscan_cmd(struct file *fp, struct scan_session *session, + struct pme_scan_params __user *user_params) +{ + int ret = 0; + u32 flag = WAIT_AND_INTERRUPTABLE; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .ctx_ctr.ern_cb = ctrl_ern_cb, + .cmd_status = 0, + .res_flag = 0, + .ern = 0 + }; + struct pme_flow params; + struct pme_scan_params local_params; + + pme_sw_flow_init(¶ms); + init_completion(&ctx_ctrl.cb_done); + if (copy_from_user(&local_params, user_params, sizeof(local_params))) + return -EFAULT; + + /* must be enabled */ + if (pme_ctx_is_disabled(&session->ctx)) { + ret = -EINVAL; + goto done; + } + /* Only send a flw_ctx_w if PME_SCAN_PARAMS_{RESIDUE, SRE or DXE} + * is being done */ + if (local_params.flags == PME_SCAN_PARAMS_PATTERN) + goto set_subset; + if (local_params.flags & PME_SCAN_PARAMS_RESIDUE) + flag |= PME_CMD_FCW_RES; + if (local_params.flags & PME_SCAN_PARAMS_SRE) + flag |= PME_CMD_FCW_SRE; + if (local_params.flags & PME_SCAN_PARAMS_DXE) + flag |= PME_CMD_FCW_DXE; + params.ren = local_params.residue.enable; + params.sessionid = local_params.sre.sessionid; + params.srvm = local_params.sre.verbose; + params.esee = local_params.sre.esee; + params.clim = local_params.dxe.clim; + params.mlim = local_params.dxe.mlim; + + ret = pme_ctx_ctrl_update_flow(&session->ctx, flag, ¶ms, + &ctx_ctrl.ctx_ctr); + if (ret) { + PMEPRINFO("update flow error %d\n", ret); + goto done; + } + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.ern || ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + PMEPRINFO("update flow err %d\n", ctx_ctrl.cmd_status); + ret = -EFAULT; + goto done; + } + +set_subset: + if (local_params.flags & PME_SCAN_PARAMS_PATTERN) { + spin_lock(&session->set_subset_lock); + session->set = local_params.pattern.set; + session->subset = local_params.pattern.subset; + spin_unlock(&session->set_subset_lock); + goto done; + } +done: + return ret; +} + +static int resetseq_cmd(struct file *fp, struct scan_session *session) +{ + int ret = 0; + struct pme_flow params; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .ctx_ctr.ern_cb = ctrl_ern_cb, + .cmd_status = 0, + .res_flag = 0, + .ern = 0 + }; + init_completion(&ctx_ctrl.cb_done); + pme_sw_flow_init(¶ms); + + /* must be enabled */ + if (pme_ctx_is_disabled(&session->ctx)) { + pr_err("pme2_scan: ctx is disabled\n"); + ret = -EINVAL; + goto done; + } + pme_flow_seqnum_set64(¶ms, 0); + params.sos = 1; + + ret = pme_ctx_ctrl_update_flow(&session->ctx, PME_CMD_FCW_SEQ, ¶ms, + &ctx_ctrl.ctx_ctr); + if (ret) { + pr_err("pme2_scan: update flow error %d\n", ret); + return ret; + } + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.ern || ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + PMEPRINFO("update flow err %d\n", ctx_ctrl.cmd_status); + ret = -EFAULT; + } +done: + return ret; +} + +static int resetresidue_cmd(struct file *fp, struct scan_session *session) +{ + int ret = 0; + struct pme_flow params; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .ctx_ctr.ern_cb = ctrl_ern_cb, + .cmd_status = 0, + .res_flag = 0, + .ern = 0 + }; + + init_completion(&ctx_ctrl.cb_done); + pme_sw_flow_init(¶ms); + /* must be enabled */ + if (pme_ctx_is_disabled(&session->ctx)) { + pr_err("pme2_scan: ctx is disabled\n"); + ret = -EINVAL; + goto done; + } + params.rlen = 0; + ret = pme_ctx_ctrl_update_flow(&session->ctx, + WAIT_AND_INTERRUPTABLE | PME_CTX_OP_RESETRESLEN, + ¶ms, &ctx_ctrl.ctx_ctr); + if (ret) + pr_info("pme2_scan: update flow error %d\n", ret); + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.ern || ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + PMEPRINFO("update flow err %d\n", ctx_ctrl.cmd_status); + ret = -EFAULT; + } +done: + return ret; +} + +static int process_scan_cmd( + struct file *fp, + struct scan_session *session, + struct pme_scan_cmd *user_cmd, + struct pme_scan_result *user_ret, + u8 synchronous) +{ + int ret = 0; + struct cmd_token local_token; + struct cmd_token *token_p = NULL; + DECLARE_WAIT_QUEUE_HEAD(local_waitqueue); + u8 scan_flags = 0; + + BUG_ON(synchronous && !user_ret); + + /* If synchronous, use a local token (from the stack) + * If asynchronous, allocate a token to use */ + if (synchronous) + token_p = &local_token; + else { + token_p = kmalloc(sizeof(*token_p), GFP_KERNEL); + if (!token_p) + return -ENOMEM; + } + memset(token_p, 0, sizeof(*token_p)); + /* Copy the command to kernel space */ + memcpy(&token_p->kernel_op, user_cmd, sizeof(struct pme_scan_cmd)); + /* Copy the input */ + token_p->synchronous = synchronous; + token_p->tx_size = token_p->kernel_op.input.size; + token_p->tx_data = kmalloc(token_p->kernel_op.input.size, GFP_KERNEL); + if (!token_p->tx_data) { + pr_err("pme2_scan: Err alloc %zd byte", token_p->tx_size); + cleanup_token(token_p); + return -ENOMEM; + } + if (copy_from_user(token_p->tx_data, + token_p->kernel_op.input.data, + token_p->kernel_op.input.size)) { + pr_err("Error copying contigous user data\n"); + cleanup_token(token_p); + return -EFAULT; + } + /* Setup input frame */ + token_p->tx_comp[INPUT_FRM].final = 1; + token_p->tx_comp[INPUT_FRM].length = token_p->tx_size; + qm_sg_entry_set64(&token_p->tx_comp[INPUT_FRM], + pme_map(token_p->tx_data)); + /* setup output frame, if output is expected */ + if (token_p->kernel_op.output.size) { + token_p->rx_size = token_p->kernel_op.output.size; + PMEPRINFO("pme2_scan: expect output %d\n", token_p->rx_size); + token_p->rx_data = kmalloc(token_p->rx_size, GFP_KERNEL); + if (!token_p->rx_data) { + pr_err("pme2_scan: Err alloc %zd byte", + token_p->rx_size); + cleanup_token(token_p); + return -ENOMEM; + } + /* Setup output frame */ + token_p->tx_comp[OUTPUT_FRM].length = token_p->rx_size; + qm_sg_entry_set64(&token_p->tx_comp[OUTPUT_FRM], + pme_map(token_p->rx_data)); + token_p->tx_fd.format = qm_fd_compound; + /* Build compound frame */ + qm_fd_addr_set64(&token_p->tx_fd, + pme_map(token_p->tx_comp)); + } else { + token_p->tx_fd.format = qm_fd_sg_big; + /* Build sg frame */ + qm_fd_addr_set64(&token_p->tx_fd, + pme_map(&token_p->tx_comp[INPUT_FRM])); + token_p->tx_fd.length29 = token_p->tx_size; + } + + /* use the local wait queue if synchronous, the shared + * queue if asynchronous */ + if (synchronous) + token_p->queue = &local_waitqueue; + else + token_p->queue = &session->waiting_for_completion; + token_p->done = 0; + + if (token_p->kernel_op.flags & PME_SCAN_CMD_STARTRESET) + scan_flags |= PME_CMD_SCAN_SR; + if (token_p->kernel_op.flags & PME_SCAN_CMD_END) + scan_flags |= PME_CMD_SCAN_E; + ret = pme_ctx_scan(&session->ctx, WAIT_AND_INTERRUPTABLE, + &token_p->tx_fd, + PME_SCAN_ARGS(scan_flags, session->set, session->subset), + &token_p->hl_token); + if (unlikely(ret)) { + cleanup_token(token_p); + return ret; + } + + if (!synchronous) + /* Don't wait. The command is away */ + return 0; + + PMEPRINFO("Wait for completion\n"); + /* Wait for the command to complete */ + /* TODO: Should this be wait_event_interruptible ? + * If so, will need logic to indicate */ + wait_event(*token_p->queue, token_p->done == 1); + return process_completed_token(fp, token_p, user_ret); +} + +/** + * fsl_pme2_scan_open - open the driver + * + * Open the driver and prepare for requests. + * + * Every time an application opens the driver, we create a scan_session object + * for that file handle. + */ +static int fsl_pme2_scan_open(struct inode *node, struct file *fp) +{ + int ret; + struct scan_session *session; + struct pme_flow flow; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .ctx_ctr.ern_cb = ctrl_ern_cb, + .cmd_status = 0, + .res_flag = 0, + .ern = 0 + }; + + pme_sw_flow_init(&flow); + init_completion(&ctx_ctrl.cb_done); + PMEPRINFO("pme2_scan: open %d\n", smp_processor_id()); + fp->private_data = kzalloc(sizeof(*session), GFP_KERNEL); + if (!fp->private_data) + return -ENOMEM; + session = (struct scan_session *)fp->private_data; + /* Set up the structures used for asynchronous requests */ + init_waitqueue_head(&session->waiting_for_completion); + INIT_LIST_HEAD(&session->completed_commands); + spin_lock_init(&session->completed_commands_lock); + spin_lock_init(&session->set_subset_lock); + PMEPRINFO("kmalloc session %p\n", fp->private_data); + session = fp->private_data; + session->ctx.cb = scan_cb; + session->ctx.ern_cb = scan_ern_cb; + + /* qosin, qosout should be driver attributes */ + ret = pme_ctx_init(&session->ctx, PME_CTX_FLAG_LOCAL, 0, 4, 4, 0, NULL); + if (ret) { + pr_err("pme2_scan: pme_ctx_init %d\n", ret); + goto exit; + } + /* enable the context */ + ret = pme_ctx_enable(&session->ctx); + if (ret) { + PMEPRINFO("error enabling ctx %d\n", ret); + pme_ctx_finish(&session->ctx); + goto exit; + } + /* Update flow to set sane defaults in the flow context */ + ret = pme_ctx_ctrl_update_flow(&session->ctx, + PME_CTX_OP_WAIT | PME_CMD_FCW_ALL, &flow, &ctx_ctrl.ctx_ctr); + if (!ret) { + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.ern || ctx_ctrl.cmd_status || ctx_ctrl.res_flag) + ret = -EFAULT; + } + if (ret) { + int my_ret; + PMEPRINFO("error updating flow ctx %d\n", ret); + my_ret = pme_ctx_disable(&session->ctx, PME_CTX_OP_WAIT, + &ctx_ctrl.ctx_ctr); + if (my_ret > 0) + wait_for_completion(&ctx_ctrl.cb_done); + else if (my_ret < 0) + PMEPRINFO("error disabling ctx %d\n", ret); + pme_ctx_finish(&session->ctx); + goto exit; + } + /* Set up the structures used for asynchronous requests */ + PMEPRINFO("pme2_scan: Finish pme_scan open %d\n", smp_processor_id()); + return 0; +exit: + kfree(fp->private_data); + fp->private_data = NULL; + return ret; +} + +static int fsl_pme2_scan_close(struct inode *node, struct file *fp) +{ + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .ctx_ctr.ern_cb = ctrl_ern_cb, + .cmd_status = 0, + .res_flag = 0, + .ern = 0 + }; + int ret = 0; + struct scan_session *session = fp->private_data; + + init_completion(&ctx_ctrl.cb_done); + /* Before disabling check to see if it's already disabled. This can + * happen if a pme serious error has occurred for instance.*/ + if (!pme_ctx_is_disabled(&session->ctx)) { + ret = pme_ctx_disable(&session->ctx, PME_CTX_OP_WAIT, + &ctx_ctrl.ctx_ctr); + if (ret > 0) { + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.ern) + PMEPRCRIT("Unexpected ERN\n"); + } else if (ret < 0) { + pr_err("pme2_scan: Error disabling ctx %d\n", ret); + return ret; + } + } + pme_ctx_finish(&session->ctx); + kfree(session); + PMEPRINFO("pme2_scan: Finish pme_session close\n"); + return 0; +} + +static unsigned int fsl_pme2_scan_poll(struct file *fp, + struct poll_table_struct *wait) +{ + struct scan_session *session; + unsigned int mask = POLLOUT | POLLWRNORM; + + if (!fp->private_data) + return -EINVAL; + + session = (struct scan_session *)fp->private_data; + + poll_wait(fp, &session->waiting_for_completion, wait); + + if (!scan_data_empty(session)) + mask |= (POLLIN | POLLRDNORM); + return mask; +} + + +/* Main switch loop for ioctl operations */ +static long fsl_pme2_scan_ioctl(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + struct scan_session *session = fp->private_data; + int ret = 0; + + switch (cmd) { + + case PMEIO_GETSCAN: + return getscan_cmd(fp, session, (struct pme_scan_params *)arg); + break; + + case PMEIO_SETSCAN: + return setscan_cmd(fp, session, (struct pme_scan_params *)arg); + break; + + case PMEIO_RESETSEQ: + return resetseq_cmd(fp, session); + break; + + case PMEIO_RESETRES: + return resetresidue_cmd(fp, session); + break; + + case PMEIO_SCAN: + { + int ret; + struct pme_scan scan; + + if (copy_from_user(&scan, (void __user *)arg, sizeof(scan))) + return -EFAULT; + ret = process_scan_cmd(fp, session, &scan.cmd, &scan.result, 1); + if (!ret) { + struct pme_scan_result __user *user_result = + &((struct pme_scan __user *)arg)->result; + ret = copy_to_user(user_result, &scan.result, + sizeof(*user_result)); + } + return ret; + } + break; + + case PMEIO_SCAN_W1: + { + struct pme_scan_cmd scan_cmd; + + if (copy_from_user(&scan_cmd, (void __user *)arg, + sizeof(scan_cmd))) + return -EFAULT; + return process_scan_cmd(fp, session, &scan_cmd, NULL, 0); + } + break; + + case PMEIO_SCAN_R1: + { + struct pme_scan_result result; + struct cmd_token *completed_cmd = NULL; + struct pme_scan_result __user *ur = + (struct pme_scan_result __user *)arg; + int ret; + + if (copy_from_user(&result, (void __user *)arg, + sizeof(result))) + return -EFAULT; + + /* Check to see if any results */ + spin_lock(&session->completed_commands_lock); + if (!list_empty(&session->completed_commands)) { + completed_cmd = list_first_entry( + &session->completed_commands, + struct cmd_token, + completed_list); + list_del(&completed_cmd->completed_list); + session->completed_count--; + } + spin_unlock(&session->completed_commands_lock); + if (completed_cmd) { + ret = process_completed_token(fp, completed_cmd, + &result); + if (!ret) + ret = copy_to_user(ur, &result, sizeof(result)); + return ret; + } else + return -EIO; + } + break; + + case PMEIO_SCAN_Wn: + { + struct pme_scan_cmds scan_cmds; + int i, ret = 0; + + /* Copy the command to kernel space */ + if (copy_from_user(&scan_cmds, (void __user *)arg, + sizeof(scan_cmds))) + return -EFAULT; + PMEPRINFO("Received Wn for %d cmds\n", scan_cmds.num); + for (i = 0; i < scan_cmds.num; i++) { + struct pme_scan_cmd scan_cmd; + + if (copy_from_user(&scan_cmd, &scan_cmds.cmds[i], + sizeof(scan_cmd))) { + pr_err("pme2_scan: Err with %d\n", i); + scan_cmds.num = i; + if (copy_to_user((void __user *)arg, &scan_cmds, + sizeof(scan_cmds))) { + return -EFAULT; + } + return -EFAULT; + } + ret = process_scan_cmd(fp, session, &scan_cmd, NULL, 0); + if (ret) { + pr_err("pme2_scan: Err with %d cmd %d\n", + i, ret); + scan_cmds.num = i; + if (copy_to_user((void *)arg, &scan_cmds, + sizeof(scan_cmds))) { + pr_err("Error copying to user data\n"); + return -EFAULT; + } + return -EINTR; + } + } + return ret; + } + break; + + case PMEIO_SCAN_Rn: + { + struct pme_scan_results results; + struct pme_scan_result result; + struct pme_scan_result __user *ur; + int i = 0, ret = 0; + struct cmd_token *completed_cmd = NULL; + + /* Copy the command to kernel space */ + if (copy_from_user(&results, (void __user *)arg, + sizeof(results))) + return -EFAULT; + ur = ((struct pme_scan_results __user *)arg)->results + PMEPRINFO("pme2_scan: Received Rn for %d res\n", results.num); + if (!results.num) + return 0; + do { + completed_cmd = NULL; + ret = 0; + /* Check to see if any results */ + spin_lock(&session->completed_commands_lock); + if (!list_empty(&session->completed_commands)) { + /* Move to a different list */ + PMEPRINFO("pme2_scan: Pop response\n"); + completed_cmd = list_first_entry( + &session->completed_commands, + struct cmd_token, + completed_list); + list_del(&completed_cmd->completed_list); + session->completed_count--; + } + spin_unlock(&session->completed_commands_lock); + if (completed_cmd) { + if (copy_from_user(&result, (void __user *)ur+i, + sizeof(result))) + return -EFAULT; + ret = process_completed_token(fp, completed_cmd, + &result); + if (!ret) + ret = copy_to_user(ur, &result, + sizeof(struct pme_scan_result)); + if (!ret) { + i++; + ur++; + } + } + } while (!ret && completed_cmd && (i != results.num)); + + if (i != results.num) { + PMEPRINFO("pme2_scan: Only filled %d responses\n", i); + results.num = i; + PMEPRINFO("pme2_scan: results.num = %d\n", results.num); + if (copy_to_user((void __user *)arg, &results, + sizeof(struct pme_scan_results))) { + pr_err("Error copying to user data\n"); + return -EFAULT; + } + } + return ret; + } + break; + + case PMEIO_RELEASE_BUFS: + return -EINVAL; + break; + +#ifdef CONFIG_COMPAT + case PMEIO_SCAN32: + { + int ret; + struct compat_pme_scan scan32; + struct compat_pme_scan __user *user_scan = compat_ptr(arg); + struct pme_scan scan; + + if (copy_from_user(&scan32, user_scan, sizeof(scan32))) + return -EFAULT; + /* Convert to 64-bit structs */ + compat_to_scan_cmd(&scan.cmd, &scan32.cmd); + compat_to_scan_result(&scan.result, &scan32.result); + + ret = process_scan_cmd(fp, session, &scan.cmd, &scan.result, 1); + if (!ret) { + struct compat_pme_scan_result __user *user_result = + &user_scan->result; + /* Convert to 32-bit struct */ + scan_result_to_compat(&scan32.result, &scan.result); + ret = copy_to_user(user_result, &scan32.result, + sizeof(*user_result)); + } + return ret; + } + break; + + case PMEIO_SCAN_W132: + { + struct compat_pme_scan_cmd scan_cmd32; + struct pme_scan_cmd scan_cmd; + + if (copy_from_user(&scan_cmd32, compat_ptr(arg), + sizeof(scan_cmd32))) + return -EFAULT; + /* Convert to 64-bit struct */ + compat_to_scan_cmd(&scan_cmd, &scan_cmd32); + return process_scan_cmd(fp, session, &scan_cmd, NULL, 0); + } + break; + + case PMEIO_SCAN_R132: + { + struct compat_pme_scan_result result32; + struct pme_scan_result result; + struct cmd_token *completed_cmd = NULL; + struct compat_pme_scan_result __user *ur = compat_ptr(arg); + int ret; + + if (copy_from_user(&result32, (void __user *)arg, + sizeof(result32))) + return -EFAULT; + /* copy to 64-bit structure */ + compat_to_scan_result(&result, &result32); + + /* Check to see if any results */ + spin_lock(&session->completed_commands_lock); + if (!list_empty(&session->completed_commands)) { + completed_cmd = list_first_entry( + &session->completed_commands, + struct cmd_token, + completed_list); + list_del(&completed_cmd->completed_list); + session->completed_count--; + } + spin_unlock(&session->completed_commands_lock); + if (completed_cmd) { + ret = process_completed_token(fp, completed_cmd, + &result); + scan_result_to_compat(&result32, &result); + ret = copy_to_user(ur, &result32, sizeof(result32)); + } else + return -EIO; + } + break; + + case PMEIO_SCAN_Wn32: + { + struct compat_pme_scan_cmds scan_cmds32; + int i, ret = 0; + + /* Copy the command to kernel space */ + if (copy_from_user(&scan_cmds32, compat_ptr(arg), + sizeof(scan_cmds32))) + return -EFAULT; + PMEPRINFO("Received Wn for %d cmds\n", scan_cmds32.num); + for (i = 0; i < scan_cmds32.num; i++) { + struct pme_scan_cmd scan_cmd; + struct compat_pme_scan_cmd __user *u_scan_cmd32; + struct compat_pme_scan_cmd scan_cmd32; + + u_scan_cmd32 = compat_ptr(scan_cmds32.cmds); + u_scan_cmd32 += i; + + if (copy_from_user(&scan_cmd32, u_scan_cmd32, + sizeof(scan_cmd32))) { + pr_err("pme2_scan: Err with %d\n", i); + scan_cmds32.num = i; + if (copy_to_user(compat_ptr(arg), &scan_cmds32, + sizeof(scan_cmds32))) + return -EFAULT; + return -EFAULT; + } + compat_to_scan_cmd(&scan_cmd, &scan_cmd32); + ret = process_scan_cmd(fp, session, &scan_cmd, NULL, 0); + if (ret) { + pr_err("pme2_scan: Err with %d cmd %d\n", + i, ret); + scan_cmds32.num = i; + if (copy_to_user(compat_ptr(arg), &scan_cmds32, + sizeof(scan_cmds32))) + return -EFAULT; + return -EINTR; + } + } + return ret; + } + break; + + case PMEIO_SCAN_Rn32: + { + struct compat_pme_scan_results results32; + int i = 0, ret = 0; + struct cmd_token *completed_cmd = NULL; + struct compat_pme_scan_result __user *ur; + + /* Copy the command to kernel space */ + if (copy_from_user(&results32, compat_ptr(arg), + sizeof(results32))) + return -EFAULT; + ur = compat_ptr(results32.results); + PMEPRINFO("pme2_scan: Rx Rn for %d res\n", results32.num); + if (!results32.num) + return 0; + do { + completed_cmd = NULL; + ret = 0; + /* Check to see if any results */ + spin_lock(&session->completed_commands_lock); + if (!list_empty(&session->completed_commands)) { + /* Move to a different list */ + PMEPRINFO("pme2_scan: Pop response\n"); + completed_cmd = list_first_entry( + &session->completed_commands, + struct cmd_token, + completed_list); + list_del(&completed_cmd->completed_list); + session->completed_count--; + } + spin_unlock(&session->completed_commands_lock); + if (completed_cmd) { + struct compat_pme_scan_result l_result32; + struct pme_scan_result result; + + if (copy_from_user(&l_result32, ur+i, + sizeof(l_result32))) + return -EFAULT; + compat_to_scan_result(&result, &l_result32); + ret = process_completed_token(fp, completed_cmd, + &result); + scan_result_to_compat(&l_result32, &result); + ret = copy_to_user(ur+i, &l_result32, + sizeof(l_result32)); + if (!ret) + i++; + } + } while (!ret && completed_cmd && (i != results32.num)); + + if (i != results32.num) { + PMEPRINFO("pme2_scan: Only filled %d responses\n", i); + results32.num = i; + PMEPRINFO("pme2_scan: results32.num = %d\n", + results32.num); + if (copy_to_user(compat_ptr(arg), &results32, + sizeof(struct pme_scan_results))) { + pr_err("Error copying to user data\n"); + return -EFAULT; + } + } + return ret; + } + break; +#endif /* CONFIG_COMPAT */ + + default: + pr_err("UNKNOWN IOCTL cmd 0x%x\n", cmd); + return -EINVAL; + break; + } + + return ret; +} + +static const struct file_operations fsl_pme2_scan_fops = { + .owner = THIS_MODULE, + .open = fsl_pme2_scan_open, + .release = fsl_pme2_scan_close, + .poll = fsl_pme2_scan_poll, + .unlocked_ioctl = fsl_pme2_scan_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fsl_pme2_scan_ioctl, +#endif +}; + +static struct miscdevice fsl_pme2_scan_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = PME_DEV_SCAN_NODE, + .fops = &fsl_pme2_scan_fops +}; + +static int __init fsl_pme2_scan_init(void) +{ + int err = 0; + + pr_info("Freescale pme2 scan driver\n"); + err = misc_register(&fsl_pme2_scan_dev); + if (err) { + pr_err("fsl-pme2-scan: cannot register device\n"); + return err; + } + pr_info("fsl-pme2-scan: device %s registered\n", + fsl_pme2_scan_dev.name); + return 0; +} + +static void __exit fsl_pme2_scan_exit(void) +{ + int err = misc_deregister(&fsl_pme2_scan_dev); + if (err) + pr_err("fsl-pme2-scan: Failed to deregister device %s, " + "code %d\n", fsl_pme2_scan_dev.name, err); + pr_info("fsl-pme2-scan: device %s deregistered\n", + fsl_pme2_scan_dev.name); +} + +module_init(fsl_pme2_scan_init); +module_exit(fsl_pme2_scan_exit); + +MODULE_AUTHOR("Jeffrey Ladouceur "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Freescale PME2 scan driver"); --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_test.h +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_test.h @@ -0,0 +1,74 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_sys.h" + +static inline void __hexdump(unsigned long start, unsigned long end, + unsigned long p, size_t sz, const unsigned char *c) +{ + while (start < end) { + unsigned int pos = 0; + char buf[64]; + int nl = 0; + pos += sprintf(buf + pos, "%08lx: ", start); + do { + if ((start < p) || (start >= (p + sz))) + pos += sprintf(buf + pos, ".."); + else + pos += sprintf(buf + pos, "%02x", *(c++)); + if (!(++start & 15)) { + buf[pos++] = '\n'; + nl = 1; + } else { + nl = 0; + if(!(start & 1)) + buf[pos++] = ' '; + if(!(start & 3)) + buf[pos++] = ' '; + } + } while (start & 15); + if (!nl) + buf[pos++] = '\n'; + buf[pos] = '\0'; + pr_info("%s", buf); + } +} +static inline void hexdump(const void *ptr, size_t sz) +{ + unsigned long p = (unsigned long)ptr; + unsigned long start = p & ~(unsigned long)15; + unsigned long end = (p + sz + 15) & ~(unsigned long)15; + const unsigned char *c = ptr; + __hexdump(start, end, p, sz, c); +} + +int pme2_sample_db(void); +int pme2_clear_sample_db(void); --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_regs.h +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_regs.h @@ -0,0 +1,173 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PME2_REGS_H +#define PME2_REGS_H + +#define PME_REG_ISR 0x000 +#define PME_REG_IER 0x004 +#define PME_REG_ISDR 0x008 +#define PME_REG_IIR 0x00C +#define PME_REG_RLL 0x014 +#define PME_REG_CDCR 0x018 +#define PME_REG_TRUNCI 0x024 +#define PME_REG_RBC 0x028 +#define PME_REG_ESR 0x02C +#define PME_REG_ECR0 0x030 +#define PME_REG_ECR1 0x034 +#define PME_REG_EFQC 0x050 +#define PME_REG_FACONF 0x060 +#define PME_REG_PMSTAT 0x064 +#define PME_REG_FAMCR 0x068 +#define PME_REG_PMTR 0x06C +#define PME_REG_PEHD 0x074 +#define PME_REG_BSC0 0x080 +#define PME_REG_BSC1 0x084 +#define PME_REG_BSC2 0x088 +#define PME_REG_BSC3 0x08C +#define PME_REG_BSC4 0x090 +#define PME_REG_BSC5 0x094 +#define PME_REG_BSC6 0x098 +#define PME_REG_BSC7 0x09C +#define PME_REG_QMBFD0 0x0E0 +#define PME_REG_QMBFD1 0x0E4 +#define PME_REG_QMBFD2 0x0E8 +#define PME_REG_QMBFD3 0x0EC +#define PME_REG_QMBCTXTAH 0x0F0 +#define PME_REG_QMBCTXTAL 0x0F4 +#define PME_REG_QMBCTXTB 0x0F8 +#define PME_REG_QMBCTL 0x0FC +#define PME_REG_ECC1BES 0x100 +#define PME_REG_ECC2BES 0x104 +#define PME_REG_ECCADDR 0x110 +#define PME_REG_ECCCODE 0x118 +#define PME_REG_TBT0ECC1TH 0x180 +#define PME_REG_TBT0ECC1EC 0x184 +#define PME_REG_TBT1ECC1TH 0x188 +#define PME_REG_TBT1ECC1EC 0x18C +#define PME_REG_VLT0ECC1TH 0x190 +#define PME_REG_VLT0ECC1EC 0x194 +#define PME_REG_VLT1ECC1TH 0x198 +#define PME_REG_VLT1ECC1EC 0x19C +#define PME_REG_CMECC1TH 0x1A0 +#define PME_REG_CMECC1EC 0x1A4 +#define PME_REG_DXCMECC1TH 0x1B0 +#define PME_REG_DXCMECC1EC 0x1B4 +#define PME_REG_DXEMECC1TH 0x1C0 +#define PME_REG_DXEMECC1EC 0x1C4 +#define PME_REG_STNIB 0x200 +#define PME_REG_STNIS 0x204 +#define PME_REG_STNTH1 0x208 +#define PME_REG_STNTH2 0x20C +#define PME_REG_STNTHV 0x210 +#define PME_REG_STNTHS 0x214 +#define PME_REG_STNCH 0x218 +#define PME_REG_SWDB 0x21C +#define PME_REG_KVLTS 0x220 +#define PME_REG_KEC 0x224 +#define PME_REG_STNPM 0x280 +#define PME_REG_STNS1M 0x284 +#define PME_REG_DRCIC 0x288 +#define PME_REG_DRCMC 0x28C +#define PME_REG_STNPMR 0x290 +#define PME_REG_PDSRBAH 0x2A0 +#define PME_REG_PDSRBAL 0x2A4 +#define PME_REG_DMCR 0x2A8 +#define PME_REG_DEC0 0x2AC +#define PME_REG_DEC1 0x2B0 +#define PME_REG_DLC 0x2C0 +#define PME_REG_STNDSR 0x300 +#define PME_REG_STNESR 0x304 +#define PME_REG_STNS1R 0x308 +#define PME_REG_STNOB 0x30C +#define PME_REG_SCBARH 0x310 +#define PME_REG_SCBARL 0x314 +#define PME_REG_SMCR 0x318 +#define PME_REG_SREC 0x320 +#define PME_REG_ESRP 0x328 +#define PME_REG_SRRV0 0x338 +#define PME_REG_SRRV1 0x33C +#define PME_REG_SRRV2 0x340 +#define PME_REG_SRRV3 0x344 +#define PME_REG_SRRV4 0x348 +#define PME_REG_SRRV5 0x34C +#define PME_REG_SRRV6 0x350 +#define PME_REG_SRRV7 0x354 +#define PME_REG_SRRFI 0x358 +#define PME_REG_SRRI 0x360 +#define PME_REG_SRRR 0x364 +#define PME_REG_SRRWC 0x368 +#define PME_REG_SFRCC 0x36C +#define PME_REG_SEC1 0x370 +#define PME_REG_SEC2 0x374 +#define PME_REG_SEC3 0x378 +#define PME_REG_MIA_BYC 0x380 +#define PME_REG_MIA_BLC 0x384 +#define PME_REG_MIA_CE 0x388 +#define PME_REG_MIA_CR 0x390 +#define PME_REG_PPIDMR0 0x800 +#define PME_REG_PPIDMR1 0x804 +#define PME_REG_PPIDMR2 0x808 +#define PME_REG_PPIDMR3 0x80C +#define PME_REG_PPIDMR4 0x810 +#define PME_REG_PPIDMR5 0x814 +#define PME_REG_PPIDMR6 0x818 +#define PME_REG_PPIDMR7 0x81C +#define PME_REG_PPIDMR8 0x820 +#define PME_REG_PPIDMR9 0x824 +#define PME_REG_PPIDMR10 0x828 +#define PME_REG_PPIDMR11 0x82C +#define PME_REG_PPIDMR12 0x830 +#define PME_REG_PPIDMR13 0x834 +#define PME_REG_PPIDMR14 0x838 +#define PME_REG_PPIDMR15 0x83C +#define PME_REG_PPIDMR16 0x840 +#define PME_REG_PPIDMR17 0x844 +#define PME_REG_PPIDMR18 0x848 +#define PME_REG_PPIDMR19 0x84C +#define PME_REG_PPIDMR20 0x850 +#define PME_REG_PPIDMR21 0x854 +#define PME_REG_PPIDMR22 0x858 +#define PME_REG_PPIDMR23 0x85C +#define PME_REG_PPIDMR24 0x860 +#define PME_REG_PPIDMR25 0x864 +#define PME_REG_PPIDMR26 0x868 +#define PME_REG_PPIDMR27 0x86C +#define PME_REG_PPIDMR28 0x870 +#define PME_REG_PPIDMR29 0x874 +#define PME_REG_PPIDMR30 0x878 +#define PME_REG_PPIDMR31 0x87C +#define PME_REG_SRCIDR 0xA00 +#define PME_REG_LIODNR 0xA0C +#define PME_REG_PM_IP_REV1 0xBF8 +#define PME_REG_PM_IP_REV2 0xBFC + +#endif /* REGS_H */ --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_private.h +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_private.h @@ -0,0 +1,180 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_sys.h" +#include + +#undef PME2_DEBUG + +#ifdef PME2_DEBUG +#define PMEPRINFO(fmt, args...) pr_info("PME2: %s: " fmt, __func__, ## args) +#else +#define PMEPRINFO(fmt, args...) +#endif + +#define PMEPRERR(fmt, args...) pr_err("PME2: %s: " fmt, __func__, ## args) +#define PMEPRCRIT(fmt, args...) pr_crit("PME2: %s: " fmt, __func__, ## args) + +#ifdef CONFIG_FSL_PME2_CTRL +/* Hooks */ +int pme2_create_sysfs_dev_files(struct platform_device *ofdev); +void pme2_remove_sysfs_dev_files(struct platform_device *ofdev); +void accumulator_update_interval(u32 interval); +#endif + +static inline void set_fd_addr(struct qm_fd *fd, dma_addr_t addr) +{ + qm_fd_addr_set64(fd, addr); +} +static inline dma_addr_t get_fd_addr(const struct qm_fd *fd) +{ + return (dma_addr_t)qm_fd_addr_get64(fd); +} +static inline void set_sg_addr(struct qm_sg_entry *sg, dma_addr_t addr) +{ + qm_sg_entry_set64(sg, addr); +} +static inline dma_addr_t get_sg_addr(const struct qm_sg_entry *sg) +{ + return (dma_addr_t)qm_sg_entry_get64(sg); +} + +/******************/ +/* Datapath types */ +/******************/ + +enum pme_mode { + pme_mode_direct = 0x00, + pme_mode_flow = 0x80 +}; + +struct pme_context_a { + enum pme_mode mode:8; + u8 __reserved; + /* Flow Context pointer (48-bit), ignored if mode==direct */ + u16 flow_hi; + u32 flow_lo; +} __packed; +static inline u64 pme_context_a_get64(const struct pme_context_a *p) +{ + return ((u64)p->flow_hi << 32) | (u64)p->flow_lo; +} +/* Macro, so we compile better if 'v' isn't always 64-bit */ +#define pme_context_a_set64(p, v) \ + do { \ + struct pme_context_a *__p931 = (p); \ + __p931->flow_hi = upper_32_bits(v); \ + __p931->flow_lo = lower_32_bits(v); \ + } while (0) + +struct pme_context_b { + u32 rbpid:8; + u32 rfqid:24; +} __packed; + + +/* This is the 32-bit frame "cmd/status" field, sent to PME */ +union pme_cmd { + struct pme_cmd_nop { + enum pme_cmd_type cmd:3; + } nop; + struct pme_cmd_flow_read { + enum pme_cmd_type cmd:3; + } fcr; + struct pme_cmd_flow_write { + enum pme_cmd_type cmd:3; + u8 __reserved:5; + u8 flags; /* See PME_CMD_FCW_*** */ + } __packed fcw; + struct pme_cmd_pmtcc { + enum pme_cmd_type cmd:3; + } pmtcc; + struct pme_cmd_scan { + union { + struct { + enum pme_cmd_type cmd:3; + u8 flags:5; /* See PME_CMD_SCAN_*** */ + } __packed; + }; + u8 set; + u16 subset; + } __packed scan; +}; + +/* The exported macro forms a "scan_args" u32 from 3 inputs, these private + * inlines do the inverse, if you need to crack one apart. */ +static inline u8 scan_args_get_flags(u32 args) +{ + return args >> 24; +} +static inline u8 scan_args_get_set(u32 args) +{ + return (args >> 16) & 0xff; +} +static inline u16 scan_args_get_subset(u32 args) +{ + return args & 0xffff; +} + +/* Hook from pme2_high to pme2_low */ +struct qman_fq *slabfq_alloc(void); +void slabfq_free(struct qman_fq *fq); + +/* Hook from pme2_high to pme2_ctrl */ +int pme2_have_control(void); +int pme2_exclusive_set(struct qman_fq *fq); +int pme2_exclusive_unset(void); + +#define DECLARE_GLOBAL(name, t, mt, def, desc) \ + static t name = def; \ + module_param(name, mt, 0644); \ + MODULE_PARM_DESC(name, desc ", default: " __stringify(def)); + +/* Constants used by the SRE ioctl. */ +#define PME_PMFA_SRE_POLL_MS 100 +#define PME_PMFA_SRE_INDEX_MAX (1 << 27) +#define PME_PMFA_SRE_INC_MAX (1 << 12) +#define PME_PMFA_SRE_REP_MAX (1 << 28) +#define PME_PMFA_SRE_INTERVAL_MAX (1 << 12) + +/* Encapsulations for mapping */ +#define flow_map(flow) \ +({ \ + struct pme_flow *__f913 = (flow); \ + pme_map(__f913); \ +}) + +#define residue_map(residue) \ +({ \ + struct pme_hw_residue *__f913 = (residue); \ + pme_map(__f913); \ +}) + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_test_high.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_test_high.c @@ -0,0 +1,238 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_test.h" + +MODULE_AUTHOR("Geoff Thorpe"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL PME2 (p4080) high-level self-test"); + +/* Default Flow Context State */ +static u8 fl_ctx_exp[]={ + 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 +}; + +void scan_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_token *token) +{ + hexdump(fd, sizeof(*fd)); +} + +struct ctrl_op { + struct pme_ctx_ctrl_token ctx_ctr; + struct completion cb_done; + enum pme_status cmd_status; + u8 res_flag; +}; + +static void ctrl_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_ctrl_token *token) +{ + struct ctrl_op *ctrl = (struct ctrl_op *)token; + pr_info("pme2_test_high: ctrl_cb() invoked, fd;!\n"); + ctrl->cmd_status = pme_fd_res_status(fd); + ctrl->res_flag = pme_fd_res_flags(fd); + hexdump(fd, sizeof(*fd)); + complete(&ctrl->cb_done); +} + + +#define POST_CTRL(val) \ +do { \ + if (ret) \ + val = -1;\ + else if (pme_ctx_is_dead(&ctx))\ + val = -1;\ + else if (ctx_ctrl.cmd_status)\ + val = -1;\ + else if (ctx_ctrl.res_flag)\ + val = -1;\ +} while (0) + +void pme2_test_high(void) +{ + int post_ctrl = 0; + struct pme_flow flow; + struct qm_fqd_stashing stashing; + struct pme_ctx ctx = { + .cb = scan_cb + }; + int ret; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .cmd_status = 0, + .res_flag = 0 + }; + struct cpumask backup_mask = current->cpus_allowed; + struct cpumask new_mask = *qman_affine_cpus(); + + pr_info("PME2: high-level test starting\n"); + + cpumask_and(&new_mask, &new_mask, bman_affine_cpus()); + ret = set_cpus_allowed_ptr(current, &new_mask); + if (ret) { + post_ctrl = -1; + pr_info("PME2: test high: can't set cpumask\n"); + goto done; + } + + pme_sw_flow_init(&flow); + init_completion(&ctx_ctrl.cb_done); + ret = pme_ctx_init(&ctx, PME_CTX_FLAG_LOCAL, 0, 4, 4, 0, NULL); + POST_CTRL(post_ctrl); + if (post_ctrl) + goto restore_mask; + + /* enable the context */ + pme_ctx_enable(&ctx); + pr_info("PME2: pme_ctx_enable done\n"); + ret = pme_ctx_ctrl_update_flow(&ctx, PME_CTX_OP_WAIT | PME_CMD_FCW_ALL, + &flow, &ctx_ctrl.ctx_ctr); + pr_info("PME2: pme_ctx_ctrl_update_flow done\n"); + wait_for_completion(&ctx_ctrl.cb_done); + POST_CTRL(post_ctrl); + if (post_ctrl) + goto disable_ctx; + /* read back flow settings */ + ret = pme_ctx_ctrl_read_flow(&ctx, PME_CTX_OP_WAIT, &flow, + &ctx_ctrl.ctx_ctr); + pr_info("PME2: pme_ctx_ctrl_read_flow done\n"); + wait_for_completion(&ctx_ctrl.cb_done); + POST_CTRL(post_ctrl); + if (post_ctrl) + goto disable_ctx; + if (memcmp(&flow, fl_ctx_exp, sizeof(flow))) { + pr_info("Default Flow Context Read FAIL\n"); + pr_info("Expected:\n"); + hexdump(fl_ctx_exp, sizeof(fl_ctx_exp)); + pr_info("Received:\n"); + hexdump(&flow, sizeof(flow)); + post_ctrl = -1; + goto disable_ctx; + } else + pr_info("Default Flow Context Read OK\n"); + /* start a NOP */ + ret = pme_ctx_ctrl_nop(&ctx, 0, &ctx_ctrl.ctx_ctr); + pr_info("PME2: pme_ctx_ctrl_nop done\n"); + wait_for_completion(&ctx_ctrl.cb_done); + POST_CTRL(post_ctrl); + if (post_ctrl) + goto disable_ctx; + /* start an update to add residue to the context */ + flow.ren = 1; + ret = pme_ctx_ctrl_update_flow(&ctx, PME_CTX_OP_WAIT | PME_CMD_FCW_RES, + &flow, &ctx_ctrl.ctx_ctr); + pr_info("PME2: pme_ctx_ctrl_update_flow done\n"); + wait_for_completion(&ctx_ctrl.cb_done); + POST_CTRL(post_ctrl); + if (post_ctrl) + goto disable_ctx; + /* start a blocking disable */ + ret = pme_ctx_disable(&ctx, PME_CTX_OP_WAIT, &ctx_ctrl.ctx_ctr); + if (ret < 1) { + post_ctrl = -1; + goto finish_ctx; + } + wait_for_completion(&ctx_ctrl.cb_done); + /* do some reconfiguration */ + ret = pme_ctx_reconfigure_tx(&ctx, 63, 7); + if (ret) { + post_ctrl = -1; + goto finish_ctx; + } + stashing.exclusive = 0; + stashing.annotation_cl = 0; + stashing.data_cl = 2; + stashing.context_cl = 2; + ret = pme_ctx_reconfigure_rx(&ctx, 7, 0, &stashing); + if (ret) { + post_ctrl = -1; + goto finish_ctx; + } + /* reenable */ + ret = pme_ctx_enable(&ctx); + if (ret) { + post_ctrl = -1; + goto finish_ctx; + } + /* read back flow settings */ + ret = pme_ctx_ctrl_read_flow(&ctx, + PME_CTX_OP_WAIT | PME_CTX_OP_WAIT_INT | PME_CMD_FCW_RES, &flow, + &ctx_ctrl.ctx_ctr); + pr_info("PME2: pme_ctx_ctrl_read_flow done\n"); + wait_for_completion(&ctx_ctrl.cb_done); + POST_CTRL(post_ctrl); + if (post_ctrl) + goto disable_ctx; + /* blocking NOP */ + ret = pme_ctx_ctrl_nop(&ctx, PME_CTX_OP_WAIT | PME_CTX_OP_WAIT_INT, + &ctx_ctrl.ctx_ctr); + pr_info("PME2: pme_ctx_ctrl_nop done\n"); + wait_for_completion(&ctx_ctrl.cb_done); + POST_CTRL(post_ctrl); + /* Disable, and done */ +disable_ctx: + ret = pme_ctx_disable(&ctx, PME_CTX_OP_WAIT, &ctx_ctrl.ctx_ctr); + BUG_ON(ret < 1); + wait_for_completion(&ctx_ctrl.cb_done); +finish_ctx: + pme_ctx_finish(&ctx); +restore_mask: + ret = set_cpus_allowed_ptr(current, &backup_mask); + if (ret) { + pr_err("PME2 test high: can't restore cpumask"); + post_ctrl = -1; + } +done: + if (post_ctrl) + pr_info("PME2: high-level test failed\n"); + else + pr_info("PME2: high-level test passed\n"); +} + +static int pme2_test_high_init(void) +{ + int big_loop = 2; + while (big_loop--) + pme2_test_high(); + return 0; +} + +static void pme2_test_high_exit(void) +{ +} + +module_init(pme2_test_high_init); +module_exit(pme2_test_high_exit); + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_test_scan.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_test_scan.c @@ -0,0 +1,653 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_test.h" + +enum scan_ctrl_mode { + no_scan = 0, + do_scan = 1, +}; + +enum db_ctrl_mode { + create_destroy = 0, + create = 1, + destroy = 2, + nothing = 3 +}; + +MODULE_AUTHOR("Jeffrey Ladouceur"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("PME scan testing"); + +static enum db_ctrl_mode db_ctrl; +module_param(db_ctrl, uint, 0644); +MODULE_PARM_DESC(db_ctrl, "PME Database control"); + +static enum scan_ctrl_mode scan_ctrl = 1; +module_param(scan_ctrl, uint, 0644); +MODULE_PARM_DESC(scan_ctrl, "Scan control"); + +static u8 scan_result_direct_mode_inc_mode[] = { + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 +}; + +static u8 fl_ctx_exp[] = { + 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 +}; + +/* same again with 'sos' bit cleared */ +static u8 fl_ctx_exp_post_scan[] = { + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 +}; + +struct scan_ctx { + struct pme_ctx base_ctx; + struct qm_fd result_fd; +}; + +struct ctrl_op { + struct pme_ctx_ctrl_token ctx_ctr; + struct completion cb_done; + enum pme_status cmd_status; + u8 res_flag; +}; + +static void ctrl_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_ctrl_token *token) +{ + struct ctrl_op *ctrl = (struct ctrl_op *)token; + ctrl->cmd_status = pme_fd_res_status(fd); + ctrl->res_flag = pme_fd_res_flags(fd) & PME_STATUS_UNRELIABLE; + /* hexdump(fd, sizeof(*fd)); */ + complete(&ctrl->cb_done); +} + +static DECLARE_COMPLETION(scan_comp); + +static void scan_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_token *ctx_token) +{ + struct scan_ctx *my_ctx = (struct scan_ctx *)ctx; + memcpy(&my_ctx->result_fd, fd, sizeof(*fd)); + complete(&scan_comp); +} + +#ifdef CONFIG_FSL_PME2_TEST_SCAN_WITH_BPID + +static struct bman_pool *pool; +static u32 pme_bpid; +static void *bman_buffers_virt_base; +static dma_addr_t bman_buffers_phys_base; + +static void release_buffer(dma_addr_t addr) +{ + struct bm_buffer bufs_in; + bm_buffer_set64(&bufs_in, addr); + if (bman_release(pool, &bufs_in, 1, BMAN_RELEASE_FLAG_WAIT)) + panic("bman_release() failed\n"); +} + +static void empty_buffer(void) +{ + struct bm_buffer bufs_in; + int ret; + + do { + ret = bman_acquire(pool, &bufs_in, 1, 0); + } while (!ret); +} +#endif /*CONFIG_FSL_PME2_TEST_SCAN_WITH_BPID*/ + +static int scan_test_direct(int trunc, int use_bp) +{ + struct scan_ctx a_scan_ctx = { + .base_ctx = { + .cb = scan_cb + } + }; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .cmd_status = 0, + .res_flag = 0 + }; + struct qm_fd fd; + struct qm_sg_entry sg_table[2]; + int ret; + enum pme_status status; + struct pme_ctx_token token; + u8 *scan_result; + u32 scan_result_size; + u8 scan_data[] = { + 0x41, 0x42, 0x43, 0x44, 0x45 + }; + u8 result_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }; + + init_completion(&ctx_ctrl.cb_done); + scan_result = scan_result_direct_mode_inc_mode; + scan_result_size = sizeof(scan_result_direct_mode_inc_mode); + + ret = pme_ctx_init(&a_scan_ctx.base_ctx, + PME_CTX_FLAG_DIRECT | PME_CTX_FLAG_LOCAL, + 0, 4, 4, 0, NULL); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + return ret; + } + /* enable the context */ + ret = pme_ctx_enable(&a_scan_ctx.base_ctx); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto ctx_finish; + } + + /* Do a pre-built output, scan with match test */ + /* Build a frame descriptor */ + memset(&fd, 0, sizeof(struct qm_fd)); + memset(&sg_table, 0, sizeof(sg_table)); + + if (trunc) { + fd.length20 = sizeof(scan_data); + qm_fd_addr_set64(&fd, pme_map(scan_data)); + } else { + /* build the result */ + qm_sg_entry_set64(&sg_table[0], pme_map(result_data)); + sg_table[0].length = sizeof(result_data); + qm_sg_entry_set64(&sg_table[1], pme_map(scan_data)); + sg_table[1].length = sizeof(scan_data); + sg_table[1].final = 1; + fd._format2 = qm_fd_compound; + qm_fd_addr_set64(&fd, pme_map(sg_table)); + } + + ret = pme_ctx_scan(&a_scan_ctx.base_ctx, 0, &fd, + PME_SCAN_ARGS(PME_CMD_SCAN_SR | PME_CMD_SCAN_E, 0, 0xff00), + &token); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto ctx_disable; + } + wait_for_completion(&scan_comp); + + status = pme_fd_res_status(&a_scan_ctx.result_fd); + if (status) { + pr_err("pme scan test failed 0x%x\n", status); + goto ctx_disable; + } + if (trunc) { + int res_flag = pme_fd_res_flags(&a_scan_ctx.result_fd); + /* Check the response...expect truncation bit to be set */ + if (!(res_flag & PME_STATUS_TRUNCATED)) { + pr_err("pme scan test failed, expected truncation\n"); + goto ctx_disable; + } + } else { + if (memcmp(scan_result, result_data, scan_result_size) != 0) { + pr_err("pme scan test result not expected\n"); + hexdump(scan_result, scan_result_size); + pr_err("Received...\n"); + hexdump(result_data, sizeof(result_data)); + goto ctx_disable; + } + } + + ret = pme_ctx_disable(&a_scan_ctx.base_ctx, PME_CTX_OP_WAIT, NULL); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto ctx_finish; + } + if (!use_bp) { + pme_ctx_finish(&a_scan_ctx.base_ctx); + return 0; + } + /* use buffer pool */ + /* Check with bman */ + /* reconfigure */ + +#ifdef CONFIG_FSL_PME2_TEST_SCAN_WITH_BPID + ret = pme_ctx_reconfigure_tx(&a_scan_ctx.base_ctx, pme_bpid, 5); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto ctx_finish; + } + ret = pme_ctx_enable(&a_scan_ctx.base_ctx); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto ctx_finish; + } + /* Do a pre-built output, scan with match test */ + /* Build a frame descriptor */ + memset(&fd, 0, sizeof(struct qm_fd)); + memset(&sg_table, 0, sizeof(sg_table)); + + /* build the result */ + /* result is all zero...use bman */ + qm_sg_entry_set64(&sg_table[1], pme_map(scan_data)); + sg_table[1].length = sizeof(scan_data); + sg_table[1].final = 1; + + fd._format2 = qm_fd_compound; + qm_fd_addr_set64(&fd, pme_map(sg_table)); + + ret = pme_ctx_scan(&a_scan_ctx.base_ctx, 0, &fd, + PME_SCAN_ARGS(PME_CMD_SCAN_SR | PME_CMD_SCAN_E, 0, 0xff00), + &token); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto ctx_disable; + } + wait_for_completion(&scan_comp); + + status = pme_fd_res_status(&a_scan_ctx.result_fd); + if (status) { + pr_err("pme scan test failed 0x%x\n", status); + goto ctx_disable; + } + /* sg result should point to bman buffer */ + if (!qm_sg_entry_get64(&sg_table[0])) { + pr_err("pme scan test failed, sg result not bman buffer\n"); + goto ctx_disable; + } + if (memcmp(scan_result, bman_buffers_virt_base, scan_result_size) + != 0) { + pr_err("pme scan test not expected, Expected\n"); + hexdump(scan_result, scan_result_size); + pr_err("Received...\n"); + hexdump(bman_buffers_virt_base, scan_result_size); + release_buffer(qm_sg_entry_get64(&sg_table[0])); + goto ctx_disable; + } + release_buffer(qm_sg_entry_get64(&sg_table[0])); + ret = pme_ctx_disable(&a_scan_ctx.base_ctx, PME_CTX_OP_WAIT, NULL); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto ctx_finish; + } + pme_ctx_finish(&a_scan_ctx.base_ctx); + return 0; +#endif + +/* failure path */ +ctx_disable: + ret = pme_ctx_disable(&a_scan_ctx.base_ctx, PME_CTX_OP_WAIT, NULL); +ctx_finish: + pme_ctx_finish(&a_scan_ctx.base_ctx); + return (!ret) ? -EINVAL : ret; +} + +static int scan_test_flow(void) +{ + struct pme_flow flow; + struct pme_flow rb_flow; + struct scan_ctx a_scan_ctx = { + .base_ctx = { + .cb = scan_cb + } + }; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .cmd_status = 0, + .res_flag = 0 + }; + struct qm_fd fd; + struct qm_sg_entry sg_table[2]; + int ret; + enum pme_status status; + struct pme_ctx_token token; + u8 *scan_result; + u32 scan_result_size; + u8 scan_data[] = { + 0x41, 0x42, 0x43, 0x44, 0x45 + }; + u8 result_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }; + + pme_sw_flow_init(&flow); + init_completion(&ctx_ctrl.cb_done); + scan_result = scan_result_direct_mode_inc_mode; + scan_result_size = sizeof(scan_result_direct_mode_inc_mode); + + ret = pme_ctx_init(&a_scan_ctx.base_ctx, + PME_CTX_FLAG_LOCAL, 0, 4, 4, 0, NULL); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + return ret; + } + /* enable the context */ + ret = pme_ctx_enable(&a_scan_ctx.base_ctx); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_finish; + } + ret = pme_ctx_ctrl_update_flow(&a_scan_ctx.base_ctx, + PME_CTX_OP_WAIT | PME_CMD_FCW_ALL, &flow, &ctx_ctrl.ctx_ctr); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + /* read back flow settings */ + ret = pme_ctx_ctrl_read_flow(&a_scan_ctx.base_ctx, + PME_CTX_OP_WAIT, &rb_flow, &ctx_ctrl.ctx_ctr); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + if (memcmp(&rb_flow, fl_ctx_exp, sizeof(rb_flow)) != 0) { + pr_err("pme scan test Flow Context Read FAIL\n"); + pr_err("Expected\n"); + hexdump(fl_ctx_exp, sizeof(fl_ctx_exp)); + pr_err("Received...\n"); + hexdump(&rb_flow, sizeof(rb_flow)); + goto flow_ctx_disable; + } + + /* Do a pre-built output, scan with match test */ + /* Build a frame descriptor */ + memset(&fd, 0, sizeof(struct qm_fd)); + memset(&sg_table, 0, sizeof(sg_table)); + + /* build the result */ + qm_sg_entry_set64(&sg_table[0], pme_map(result_data)); + sg_table[0].length = sizeof(result_data); + qm_sg_entry_set64(&sg_table[1], pme_map(scan_data)); + sg_table[1].length = sizeof(scan_data); + sg_table[1].final = 1; + + fd._format2 = qm_fd_compound; + qm_fd_addr_set64(&fd, pme_map(sg_table)); + + ret = pme_ctx_scan(&a_scan_ctx.base_ctx, 0, &fd, + PME_SCAN_ARGS(PME_CMD_SCAN_SR | PME_CMD_SCAN_E, 0, 0xff00), + &token); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + wait_for_completion(&scan_comp); + + status = pme_fd_res_status(&a_scan_ctx.result_fd); + if (status) { + pr_err("pme scan test failed 0x%x\n", status); + goto flow_ctx_disable; + } + + if (memcmp(scan_result, result_data, scan_result_size) != 0) { + pr_err("pme scan test result not expected\n"); + hexdump(scan_result, scan_result_size); + pr_err("Received...\n"); + hexdump(result_data, sizeof(result_data)); + goto flow_ctx_disable; + } + + /* read back flow settings */ + ret = pme_ctx_ctrl_read_flow(&a_scan_ctx.base_ctx, + PME_CTX_OP_WAIT, &rb_flow, &ctx_ctrl.ctx_ctr); + if (ret) { + pr_err("pme scan test failed 0x%x\n", status); + goto flow_ctx_disable; + } + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + if (memcmp(&rb_flow, fl_ctx_exp_post_scan, sizeof(rb_flow)) != 0) { + pr_err("pme scan test Flow Context Read FAIL\n"); + pr_err("Expected\n"); + hexdump(fl_ctx_exp_post_scan, sizeof(fl_ctx_exp_post_scan)); + pr_err("Received\n"); + hexdump(&rb_flow, sizeof(rb_flow)); + goto flow_ctx_disable; + } + + /* Test truncation test */ + /* Build a frame descriptor */ + memset(&fd, 0, sizeof(struct qm_fd)); + + fd.length20 = sizeof(scan_data); + qm_fd_addr_set64(&fd, pme_map(scan_data)); + + ret = pme_ctx_scan(&a_scan_ctx.base_ctx, 0, &fd, + PME_SCAN_ARGS(PME_CMD_SCAN_SR | PME_CMD_SCAN_E, 0, 0xff00), + &token); + if (ret) { + pr_err("pme scan test failed 0x%x\n", status); + goto flow_ctx_disable; + } + wait_for_completion(&scan_comp); + + status = pme_fd_res_status(&a_scan_ctx.result_fd); + if (status) { + pr_err("pme scan test failed 0x%x\n", status); + goto flow_ctx_disable; + } + /* Check the response...expect truncation bit to be set */ + if (!(pme_fd_res_flags(&a_scan_ctx.result_fd) & PME_STATUS_TRUNCATED)) { + pr_err("st: Scan result failed...expected trunc\n"); + goto flow_ctx_disable; + } + + /* read back flow settings */ + ret = pme_ctx_ctrl_read_flow(&a_scan_ctx.base_ctx, + PME_CTX_OP_WAIT, &rb_flow, &ctx_ctrl.ctx_ctr); + if (ret) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + wait_for_completion(&ctx_ctrl.cb_done); + if (ctx_ctrl.cmd_status || ctx_ctrl.res_flag) { + pr_err("pme scan test failed: 0x%x\n", ret); + goto flow_ctx_disable; + } + if (memcmp(&rb_flow, fl_ctx_exp_post_scan, sizeof(rb_flow)) != 0) { + pr_err("pme scan test Flow Context Read FAIL\n"); + pr_err("Expected\n"); + hexdump(fl_ctx_exp_post_scan, sizeof(fl_ctx_exp_post_scan)); + pr_err("Received\n"); + hexdump(&rb_flow, sizeof(rb_flow)); + goto flow_ctx_disable; + } + + /* Disable */ + ret = pme_ctx_disable(&a_scan_ctx.base_ctx, PME_CTX_OP_WAIT, + &ctx_ctrl.ctx_ctr); + if (ret < 1) { + pr_err("pme scan test failed 0x%x\n", ret); + goto flow_ctx_finish; + } + wait_for_completion(&ctx_ctrl.cb_done); + pme_ctx_finish(&a_scan_ctx.base_ctx); + return 0; + /* error path */ +/* failure path */ +flow_ctx_disable: + ret = pme_ctx_disable(&a_scan_ctx.base_ctx, PME_CTX_OP_WAIT, NULL); +flow_ctx_finish: + pme_ctx_finish(&a_scan_ctx.base_ctx); + return (!ret) ? -EINVAL : ret; +} + +void pme2_test_scan(void) +{ + int ret; + + ret = scan_test_direct(0, 0); + if (ret) + goto done; + ret = scan_test_direct(1, 0); + if (ret) + goto done; +#ifdef CONFIG_FSL_PME2_TEST_SCAN_WITH_BPID + ret = scan_test_direct(0, 1); + if (ret) + goto done; +#endif + ret = scan_test_flow(); +done: + if (ret) + pr_info("pme scan test FAILED 0x%x\n", ret); + else + pr_info("pme Scan Test Passed\n"); +} + +static int setup_buffer_pool(void) +{ +#ifdef CONFIG_FSL_PME2_TEST_SCAN_WITH_BPID + u32 bpid_size = CONFIG_FSL_PME2_TEST_SCAN_WITH_BPID_SIZE; + struct bman_pool_params pparams = { + .flags = BMAN_POOL_FLAG_DYNAMIC_BPID, + .thresholds = { + 0, + 0, + 0, + 0 + } + }; + + if (!pme2_have_control()) { + pr_err("pme scan test: Not the ctrl-plane\n"); + return -EINVAL; + } + pool = bman_new_pool(&pparams); + if (!pool) { + pr_err("pme scan test: can't get buffer pool\n"); + return -EINVAL; + } + pme_bpid = bman_get_params(pool)->bpid; + bman_buffers_virt_base = kmalloc(1<<(bpid_size+5), GFP_KERNEL); + bman_buffers_phys_base = pme_map(bman_buffers_virt_base); + if (pme_map_error(bman_buffers_phys_base)) { + pr_info("pme scan test: pme_map_error\n"); + bman_free_pool(pool); + kfree(bman_buffers_virt_base); + return -ENODEV; + } + release_buffer(bman_buffers_phys_base); + /* Configure the buffer pool */ + pme_attr_set(pme_attr_bsc(pme_bpid), bpid_size); + /* realease to the specified buffer pool */ + return 0; +#endif + return 0; +} + +static int teardown_buffer_pool(void) +{ +#ifdef CONFIG_FSL_PME2_TEST_SCAN_WITH_BPID + pme_attr_set(pme_attr_bsc(pme_bpid), 0); + empty_buffer(); + bman_free_pool(pool); + kfree(bman_buffers_virt_base); +#endif + return 0; +} + +static int pme2_test_scan_init(void) +{ + int big_loop = 2; + int ret = 0; + struct cpumask backup_mask = current->cpus_allowed; + struct cpumask new_mask = *qman_affine_cpus(); + + cpumask_and(&new_mask, &new_mask, bman_affine_cpus()); + ret = set_cpus_allowed_ptr(current, &new_mask); + if (ret) { + pr_info("pme scan test: can't set cpumask\n"); + goto done_all; + } + + ret = setup_buffer_pool(); + if (ret) + goto done_cpu_mask; + + /* create sample database */ + if (db_ctrl == create_destroy || db_ctrl == create) { + if (!pme2_have_control()) { + pr_err("pme scan test: Not the ctrl-plane\n"); + ret = -EINVAL; + goto done_scan; + } + if (pme2_sample_db()) { + pr_err("pme scan test: error creating db\n"); + goto done_scan; + } + } + + if (scan_ctrl == do_scan) { + while (big_loop--) + pme2_test_scan(); + } + + if (db_ctrl == create_destroy || db_ctrl == destroy) { + /* Clear database */ + if (pme2_clear_sample_db()) + pr_err("pme scan test: error clearing db\n"); + } + +done_scan: + teardown_buffer_pool(); +done_cpu_mask: + ret = set_cpus_allowed_ptr(current, &backup_mask); + if (ret) + pr_err("PME2 test high: can't restore cpumask"); +done_all: + return ret; +} + +static void pme2_test_scan_exit(void) +{ +} + +module_init(pme2_test_scan_init); +module_exit(pme2_test_scan_exit); --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_high.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_high.c @@ -0,0 +1,944 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_private.h" + +/* The pme_ctx state machine is described via the following list of + * internal PME_CTX_FLAG_*** bits and cross-referenced to the APIs (and + * functionality) they track. + * + * DEAD: set at any point, an error has been hit, doesn't "cause" disabling or + * any autonomous ref-decrement (been there, hit the gotchas, won't do it + * again). + * + * DISABLING: set by pme_ctx_disable() at any point that is not already + * disabling, disabled, or in ctrl, and the ref is decremented. DISABLING is + * unset by pme_ctx_enable(). + * + * DISABLED: once pme_ctx_disable() has set DISABLING and refs==0, DISABLED is + * set before returning. (Any failure will clear DISABLING and increment the ref + * count.) DISABLING is unset by pme_ctx_enable(). + * + * ENABLING: set by pme_ctx_enable() provided the context is disabled, not dead, + * not in RECONFIG, and not already enabling. Once set, the ref is incremented + * and the tx FQ is scheduled (for non-exclusive flows). If this fails, the ref + * is decremented and the context is re-disabled. ENABLING is unset once + * pme_ctx_enable() completes. + * + * RECONFIG: set by pme_ctx_reconfigure_[rt]x() provided the context is + * disabled, not dead, and not already in reconfig. RECONFIG is cleared prior to + * the function returning. + * + * Simplifications: the do_flag() wrapper provides synchronised modifications of + * the ctx 'flags', and callers can rely on the following implications to reduce + * the number of flags in the masks being passed in; + * DISABLED implies DISABLING (and enable will clear both) + */ + +/* Internal-only ctx flags, mustn't conflict with exported ones */ +#define PME_CTX_FLAG_DEAD 0x80000000 +#define PME_CTX_FLAG_DISABLING 0x40000000 +#define PME_CTX_FLAG_DISABLED 0x20000000 +#define PME_CTX_FLAG_ENABLING 0x10000000 +#define PME_CTX_FLAG_RECONFIG 0x08000000 +#define PME_CTX_FLAG_PRIVATE 0xf8000000 /* mask of them all */ + +/* Internal-only cmd flags, musn't conflict with exported ones */ +#define PME_CTX_OP_INSIDE_DISABLE 0x80000000 +#define PME_CTX_OP_PRIVATE 0x80000000 /* mask of them all */ + +struct pme_nostash { + struct qman_fq fqin; + struct pme_ctx *parent; +}; + +/* This wrapper simplifies conditional (and locked) read-modify-writes to + * 'flags'. Inlining should allow the compiler to optimise it based on the + * parameters, eg. if 'must_be_set'/'must_not_be_set' are zero it will + * degenerate to an unconditional read-modify-write, if 'to_set'/'to_unset' are + * zero it will degenerate to a read-only flag-check, etc. */ +static inline int do_flags(struct pme_ctx *ctx, + u32 must_be_set, u32 must_not_be_set, + u32 to_set, u32 to_unset) +{ + int err = -EBUSY; + unsigned long irqflags; + + spin_lock_irqsave(&ctx->lock, irqflags); + if (((ctx->flags & must_be_set) == must_be_set) && + !(ctx->flags & must_not_be_set)) { + ctx->flags |= to_set; + ctx->flags &= ~to_unset; + err = 0; + } + spin_unlock_irqrestore(&ctx->lock, irqflags); + return err; +} + +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *, struct qman_fq *, + const struct qm_dqrr_entry *); +static void cb_ern(struct qman_portal *, struct qman_fq *, + const struct qm_mr_entry *); +static void cb_dc_ern(struct qman_portal *, struct qman_fq *, + const struct qm_mr_entry *); +static void cb_fqs(struct qman_portal *, struct qman_fq *, + const struct qm_mr_entry *); +static const struct qman_fq_cb pme_fq_base_in = { + .fqs = cb_fqs, + .ern = cb_ern +}; +static const struct qman_fq_cb pme_fq_base_out = { + .dqrr = cb_dqrr, + .dc_ern = cb_dc_ern, + .fqs = cb_fqs +}; + +/* Globals related to competition for PME_EFQC, ie. exclusivity */ +static DECLARE_WAIT_QUEUE_HEAD(exclusive_queue); +static spinlock_t exclusive_lock = __SPIN_LOCK_UNLOCKED(exclusive_lock); +static unsigned int exclusive_refs; +static struct pme_ctx *exclusive_ctx; + +/* Index 0..255, bools do indicated which errors are serious + * 0x40, 0x41, 0x48, 0x49, 0x4c, 0x4e, 0x4f, 0x50, 0x51, 0x59, 0x5a, 0x5b, + * 0x5c, 0x5d, 0x5f, 0x60, 0x80, 0xc0, 0xc1, 0xc2, 0xc4, 0xd2, + * 0xd4, 0xd5, 0xd7, 0xd9, 0xda, 0xe0, 0xe7 + */ +static u8 serious_error_vec[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* TODO: this is hitting the rx FQ with a large blunt instrument, ie. park() + * does a retire, query, oos, and (re)init. It's possible to force-eligible the + * rx FQ instead, then use a DCA_PK within the cb_dqrr() callback to park it. + * Implement this optimisation later if it's an issue (and incur the additional + * complexity in the state-machine). */ +static int park(struct qman_fq *fq, struct qm_mcc_initfq *initfq) +{ + int ret; + u32 flags; + + ret = qman_retire_fq(fq, &flags); + if (ret) + return ret; + BUG_ON(flags & QMAN_FQ_STATE_BLOCKOOS); + /* We can't revert from now on */ + ret = qman_query_fq(fq, &initfq->fqd); + BUG_ON(ret); + ret = qman_oos_fq(fq); + BUG_ON(ret); + /* can't set QM_INITFQ_WE_OAC and QM_INITFQ_WE_TDTHRESH + * at the same time */ + initfq->we_mask = QM_INITFQ_WE_MASK & ~QM_INITFQ_WE_TDTHRESH; + ret = qman_init_fq(fq, 0, initfq); + BUG_ON(ret); + initfq->we_mask = QM_INITFQ_WE_TDTHRESH; + ret = qman_init_fq(fq, 0, initfq); + BUG_ON(ret); + return 0; +} + +static inline int reconfigure_rx(struct pme_ctx *ctx, int to_park, u8 qosout, + enum qm_channel dest, + const struct qm_fqd_stashing *stashing) +{ + struct qm_mcc_initfq initfq; + u32 flags = QMAN_INITFQ_FLAG_SCHED; + int ret; + + ret = do_flags(ctx, PME_CTX_FLAG_DISABLED, + PME_CTX_FLAG_DEAD | PME_CTX_FLAG_RECONFIG, + PME_CTX_FLAG_RECONFIG, 0); + if (ret) + return ret; + if (to_park) { + ret = park(&ctx->fq, &initfq); + if (ret) + goto done; + } + initfq.we_mask = QM_INITFQ_WE_DESTWQ | QM_INITFQ_WE_FQCTRL; + initfq.fqd.dest.wq = qosout; + if (stashing) { + initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; + initfq.fqd.context_a.stashing = *stashing; + initfq.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING; + } else + initfq.fqd.fq_ctrl = 0; /* disable stashing */ + if (ctx->flags & PME_CTX_FLAG_LOCAL) + flags |= QMAN_INITFQ_FLAG_LOCAL; + else { + initfq.fqd.dest.channel = dest; + /* Set hold-active *IFF* it's a pool channel */ + if (dest >= qm_channel_pool1) + initfq.fqd.fq_ctrl |= QM_FQCTRL_HOLDACTIVE; + } + ret = qman_init_fq(&ctx->fq, flags, &initfq); +done: + do_flags(ctx, 0, 0, 0, PME_CTX_FLAG_RECONFIG); + return ret; +} + +/* this code is factored out of pme_ctx_disable() and get_ctrl() */ +static int empty_pipeline(struct pme_ctx *ctx, __maybe_unused u32 flags) +{ + int ret; +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & PME_CTX_OP_WAIT) { + if (flags & PME_CTX_OP_WAIT_INT) { + ret = -EINTR; + wait_event_interruptible(ctx->queue, + !(ret = atomic_read(&ctx->refs))); + } else + wait_event(ctx->queue, + !(ret = atomic_read(&ctx->refs))); + } else +#endif + ret = atomic_read(&ctx->refs); + if (ret) + /* convert a +ve ref-count to a -ve error code */ + ret = -EBUSY; + return ret; +} + +int pme_ctx_init(struct pme_ctx *ctx, u32 flags, u32 bpid, u8 qosin, + u8 qosout, enum qm_channel dest, + const struct qm_fqd_stashing *stashing) +{ + u32 fqid_rx = 0, fqid_tx = 0; + int rxinit = 0, ret = -ENOMEM, fqin_inited = 0; + + ctx->fq.cb = pme_fq_base_out; + atomic_set(&ctx->refs, 0); + ctx->flags = (flags & ~PME_CTX_FLAG_PRIVATE) | PME_CTX_FLAG_DISABLED | + PME_CTX_FLAG_DISABLING; + if (ctx->flags & PME_CTX_FLAG_PMTCC) + ctx->flags |= PME_CTX_FLAG_DIRECT | PME_CTX_FLAG_EXCLUSIVE; + spin_lock_init(&ctx->lock); + init_waitqueue_head(&ctx->queue); + INIT_LIST_HEAD(&ctx->tokens); + ctx->hw_flow = NULL; + ctx->hw_residue = NULL; + + ctx->us_data = kzalloc(sizeof(struct pme_nostash), GFP_KERNEL); + if (!ctx->us_data) + goto err; + ctx->us_data->parent = ctx; + fqid_rx = qm_fq_new(); + fqid_tx = qm_fq_new(); + if (!fqid_rx || !fqid_tx || !ctx->us_data) + goto err; + ctx->us_data->fqin.cb = pme_fq_base_in; + if (qman_create_fq(fqid_rx, QMAN_FQ_FLAG_TO_DCPORTAL | + ((flags & PME_CTX_FLAG_LOCKED) ? + QMAN_FQ_FLAG_LOCKED : 0), + &ctx->us_data->fqin)) + goto err; + fqin_inited = 1; + if (qman_create_fq(fqid_tx, QMAN_FQ_FLAG_NO_ENQUEUE | + ((flags & PME_CTX_FLAG_LOCKED) ? + QMAN_FQ_FLAG_LOCKED : 0), &ctx->fq)) + goto err; + rxinit = 1; + /* Input FQ */ + if (!(flags & PME_CTX_FLAG_DIRECT)) { + ctx->hw_flow = pme_hw_flow_new(); + if (!ctx->hw_flow) + goto err; + } + ret = pme_ctx_reconfigure_tx(ctx, bpid, qosin); + if (ret) + goto err; + /* Output FQ */ + ret = reconfigure_rx(ctx, 0, qosout, dest, stashing); + if (ret) { + /* Need to OOS the FQ before it gets free'd */ + ret = qman_oos_fq(&ctx->us_data->fqin); + BUG_ON(ret); + goto err; + } + return 0; +err: + if (fqid_rx) + qm_fq_free(fqid_rx); + if (fqid_tx) + qm_fq_free(fqid_tx); + if (ctx->hw_flow) + pme_hw_flow_free(ctx->hw_flow); + if (ctx->us_data) { + if (fqin_inited) + qman_destroy_fq(&ctx->us_data->fqin, 0); + kfree(ctx->us_data); + } + if (rxinit) + qman_destroy_fq(&ctx->fq, 0); + return ret; +} +EXPORT_SYMBOL(pme_ctx_init); + +/* NB, we don't lock here because there must be no other callers (even if we + * locked, what does the loser do after we win?) */ +void pme_ctx_finish(struct pme_ctx *ctx) +{ + u32 flags, fqid_rx, fqid_tx; + int ret; + + ret = do_flags(ctx, PME_CTX_FLAG_DISABLED, PME_CTX_FLAG_RECONFIG, 0, 0); + BUG_ON(ret); + /* Rx/Tx are empty (coz ctx is disabled) so retirement should be + * immediate */ + ret = qman_retire_fq(&ctx->us_data->fqin, &flags); + BUG_ON(ret); + BUG_ON(flags & QMAN_FQ_STATE_BLOCKOOS); + ret = qman_retire_fq(&ctx->fq, &flags); + BUG_ON(ret); + BUG_ON(flags & QMAN_FQ_STATE_BLOCKOOS); + /* OOS and free (don't kfree fq, it's a static ctx member) */ + ret = qman_oos_fq(&ctx->us_data->fqin); + BUG_ON(ret); + ret = qman_oos_fq(&ctx->fq); + BUG_ON(ret); + fqid_rx = qman_fq_fqid(&ctx->us_data->fqin); + fqid_tx = qman_fq_fqid(&ctx->fq); + qman_destroy_fq(&ctx->us_data->fqin, 0); + qman_destroy_fq(&ctx->fq, 0); + qm_fq_free(fqid_rx); + qm_fq_free(fqid_tx); + kfree(ctx->us_data); + if (ctx->hw_flow) + pme_hw_flow_free(ctx->hw_flow); + if (ctx->hw_residue) + pme_hw_residue_free(ctx->hw_residue); +} +EXPORT_SYMBOL(pme_ctx_finish); + +int pme_ctx_is_disabled(struct pme_ctx *ctx) +{ + return (ctx->flags & PME_CTX_FLAG_DISABLED); +} +EXPORT_SYMBOL(pme_ctx_is_disabled); + +int pme_ctx_is_dead(struct pme_ctx *ctx) +{ + return (ctx->flags & PME_CTX_FLAG_DEAD); +} +EXPORT_SYMBOL(pme_ctx_is_dead); + +/* predeclare this here because pme_ctx_disable() may invoke it in "privileged + * mode". The code is down with the other ctrl commands, where it belongs. */ +static inline int __update_flow(struct pme_ctx *ctx, u32 flags, + struct pme_flow *params, struct pme_ctx_ctrl_token *token, + int is_disabling); + +/* This gets invoked by pme_ctx_disable() if it runs to completion, otherwise + * it's called from cb_helper. */ +static inline void __disable_done(struct pme_ctx *ctx) +{ + struct qm_mcc_initfq initfq; + int ret = 0; + if (!(ctx->flags & PME_CTX_FLAG_EXCLUSIVE)) { + /* Park fqin (exclusive is always parked) */ + ret = park(&ctx->us_data->fqin, &initfq); + /* All the conditions for park() to succeed should be met. If + * this fails, there's a bug (s/w or h/w). */ + if (ret) + pr_crit("pme2: park() should never fail! (%d)\n", ret); + } + do_flags(ctx, 0, 0, PME_CTX_FLAG_DISABLED, 0); +} + +int pme_ctx_disable(struct pme_ctx *ctx, u32 flags, + struct pme_ctx_ctrl_token *token) +{ + int ret; + + /* We must not (already) be DISABLING */ + ret = do_flags(ctx, 0, PME_CTX_FLAG_DISABLING, + PME_CTX_FLAG_DISABLING, 0); + if (ret) + return ret; + /* Make sure the pipeline is empty */ + atomic_dec(&ctx->refs); + ret = empty_pipeline(ctx, flags); + if (ret) + goto err; + /* We're idle, but is the flow context flushed from PME onboard cache? + * If it's not flushed when the system deallocates it, that 32 bytes + * could be in use later when PME decides to flush a write to it. Need + * to make it coherent again... */ + if (!(ctx->flags & PME_CTX_FLAG_DIRECT)) { + /* Pass on wait flags (if any) but cancel any flow-context field + * writes (this is not the pme_ctx_ctrl_update_flow() API). */ + ret = __update_flow(ctx, flags & ~PME_CMD_FCW_ALL, NULL, + token, 1); + if (ret) + goto err; + return 1; + } + __disable_done(ctx); + return 0; +err: + atomic_inc(&ctx->refs); + do_flags(ctx, 0, 0, 0, PME_CTX_FLAG_DISABLING); + wake_up(&ctx->queue); + return ret; +} +EXPORT_SYMBOL(pme_ctx_disable); + +int pme_ctx_enable(struct pme_ctx *ctx) +{ + int ret; + ret = do_flags(ctx, PME_CTX_FLAG_DISABLED, + PME_CTX_FLAG_DEAD | PME_CTX_FLAG_RECONFIG | + PME_CTX_FLAG_ENABLING, + PME_CTX_FLAG_ENABLING, 0); + if (ret) + return ret; + if (!(ctx->flags & PME_CTX_FLAG_EXCLUSIVE)) { + ret = qman_init_fq(&ctx->us_data->fqin, + QMAN_INITFQ_FLAG_SCHED, NULL); + if (ret) { + do_flags(ctx, 0, 0, 0, PME_CTX_FLAG_ENABLING); + return ret; + } + } + atomic_inc(&ctx->refs); + do_flags(ctx, 0, 0, 0, PME_CTX_FLAG_DISABLED | PME_CTX_FLAG_DISABLING | + PME_CTX_FLAG_ENABLING); + return 0; +} +EXPORT_SYMBOL(pme_ctx_enable); + +int pme_ctx_reconfigure_tx(struct pme_ctx *ctx, u32 bpid, u8 qosin) +{ + struct qm_mcc_initfq initfq; + int ret; + + ret = do_flags(ctx, PME_CTX_FLAG_DISABLED, + PME_CTX_FLAG_DEAD | PME_CTX_FLAG_RECONFIG, + PME_CTX_FLAG_RECONFIG, 0); + if (ret) + return ret; + memset(&initfq,0,sizeof(initfq)); + pme_initfq(&initfq, ctx->hw_flow, qosin, bpid, qman_fq_fqid(&ctx->fq)); + ret = qman_init_fq(&ctx->us_data->fqin, 0, &initfq); + do_flags(ctx, 0, 0, 0, PME_CTX_FLAG_RECONFIG); + return ret; +} +EXPORT_SYMBOL(pme_ctx_reconfigure_tx); + +int pme_ctx_reconfigure_rx(struct pme_ctx *ctx, u8 qosout, + enum qm_channel dest, const struct qm_fqd_stashing *stashing) +{ + return reconfigure_rx(ctx, 1, qosout, dest, stashing); +} +EXPORT_SYMBOL(pme_ctx_reconfigure_rx); + +/* Helpers for 'ctrl' and 'work' APIs. These are used when the 'ctx' in question + * is EXCLUSIVE. */ +static inline void release_exclusive(__maybe_unused struct pme_ctx *ctx) +{ + unsigned long irqflags; + + BUG_ON(exclusive_ctx != ctx); + BUG_ON(!exclusive_refs); + spin_lock_irqsave(&exclusive_lock, irqflags); + if (!(--exclusive_refs)) { + exclusive_ctx = NULL; + pme2_exclusive_unset(); + wake_up(&exclusive_queue); + } + spin_unlock_irqrestore(&exclusive_lock, irqflags); +} +static int __try_exclusive(struct pme_ctx *ctx) +{ + int ret = 0; + unsigned long irqflags; + + spin_lock_irqsave(&exclusive_lock, irqflags); + if (exclusive_refs) { + /* exclusivity already held, continue if we're the owner */ + if (exclusive_ctx != ctx) + ret = -EBUSY; + } else { + /* it's not currently held */ + ret = pme2_exclusive_set(&ctx->us_data->fqin); + if (!ret) + exclusive_ctx = ctx; + } + if (!ret) + exclusive_refs++; + spin_unlock_irqrestore(&exclusive_lock, irqflags); + return ret; +} +/* Use this macro as the wait expression because we don't want to continue + * looping if the reason we're failing is that we don't have CCSR access + * (-ENODEV). */ +#define try_exclusive(ret, ctx) \ + (!(ret = __try_exclusive(ctx)) || (ret == -ENODEV)) +static inline int get_exclusive(struct pme_ctx *ctx, __maybe_unused u32 flags) +{ + int ret; +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & PME_CTX_OP_WAIT) { + if (flags & PME_CTX_OP_WAIT_INT) { + ret = -EINTR; + wait_event_interruptible(exclusive_queue, + try_exclusive(ret, ctx)); + } else + wait_event(exclusive_queue, + try_exclusive(ret, ctx)); + } else +#endif + ret = __try_exclusive(ctx); + return ret; +} + +/* Used for 'work' APIs, convert PME->QMAN wait flags. The PME and + * QMAN "wait" flags have been aligned so that the below conversion should + * compile with good straight-line speed. */ +static inline u32 ctrl2eq(u32 flags) +{ +#ifdef CONFIG_FSL_DPA_CAN_WAIT + return flags & (QMAN_ENQUEUE_FLAG_WAIT | QMAN_ENQUEUE_FLAG_WAIT_INT); +#else + return flags; +#endif +} + +static inline void release_work(struct pme_ctx *ctx) +{ + if (atomic_dec_and_test(&ctx->refs)) + wake_up(&ctx->queue); +} + +#define BLOCK_NORMAL_WORK (PME_CTX_FLAG_DEAD | PME_CTX_FLAG_DISABLING) +static int try_work(struct pme_ctx *ctx, u32 flags) +{ + atomic_inc(&ctx->refs); + if (unlikely(!(flags & PME_CTX_OP_INSIDE_DISABLE) && + (ctx->flags & BLOCK_NORMAL_WORK))) { + release_work(ctx); + return -EIO; + } + return 0; +} + +static int get_work(struct pme_ctx *ctx, u32 flags) +{ + int ret = 0; +#ifdef CONFIG_FSL_DPA_CAN_WAIT + if (flags & PME_CTX_OP_WAIT) { + if (flags & PME_CTX_OP_WAIT_INT) { + ret = -EINTR; + wait_event_interruptible(ctx->queue, + !(ret = try_work(ctx, flags))); + } else + wait_event(ctx->queue, !try_work(ctx, flags)); + } else +#endif + ret = try_work(ctx, flags); + return ret; +} + +static inline int do_work(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, + struct pme_ctx_token *token, struct qman_fq *orp_fq, u16 seqnum) +{ + unsigned long irqflags; + int ret = get_work(ctx, flags); + if (ret) + return ret; + if (ctx->flags & PME_CTX_FLAG_EXCLUSIVE) { + ret = get_exclusive(ctx, flags); + if (ret) { + release_work(ctx); + return ret; + } + } + BUG_ON(sizeof(*fd) != sizeof(token->blob)); + memcpy(&token->blob, fd, sizeof(*fd)); + + spin_lock_irqsave(&ctx->lock, irqflags); + list_add_tail(&token->node, &ctx->tokens); + spin_unlock_irqrestore(&ctx->lock, irqflags); + + if (!orp_fq) + ret = qman_enqueue(&ctx->us_data->fqin, fd, ctrl2eq(flags)); + else + ret = qman_enqueue_orp(&ctx->us_data->fqin, fd, ctrl2eq(flags), + orp_fq, seqnum); + if (ret) { + spin_lock_irqsave(&ctx->lock, irqflags); + list_del(&token->node); + spin_unlock_irqrestore(&ctx->lock, irqflags); + if (ctx->flags & PME_CTX_FLAG_EXCLUSIVE) + release_exclusive(ctx); + release_work(ctx); + } + return ret; +} + +static inline int __update_flow(struct pme_ctx *ctx, u32 flags, + struct pme_flow *params, struct pme_ctx_ctrl_token *token, + int is_disabling) +{ + struct qm_fd fd; + int ret; + int hw_res_used = 0; + struct pme_hw_residue *hw_res = pme_hw_residue_new(); + unsigned long irqflags; + + BUG_ON(ctx->flags & PME_CTX_FLAG_DIRECT); + if (!hw_res) + return -ENOMEM; + token->internal_flow_ptr = pme_hw_flow_new(); + if (!token->internal_flow_ptr) { + pme_hw_residue_free(hw_res); + return -ENOMEM; + } + token->base_token.cmd_type = pme_cmd_flow_write; + + flags &= ~PME_CTX_OP_PRIVATE; + /* The callback will want to know this */ + token->base_token.is_disable_flush = is_disabling ? 1 : 0; + flags |= (is_disabling ? PME_CTX_OP_INSIDE_DISABLE : 0); + spin_lock_irqsave(&ctx->lock, irqflags); + if (flags & PME_CTX_OP_RESETRESLEN) { + if (ctx->hw_residue) { + params->ren = 1; + flags |= PME_CMD_FCW_RES; + } else + flags &= ~PME_CMD_FCW_RES; + } + /* allocate residue memory if it is being added */ + if ((flags & PME_CMD_FCW_RES) && params->ren && !ctx->hw_residue) { + ctx->hw_residue = hw_res; + hw_res_used = 1; + } + spin_unlock_irqrestore(&ctx->lock, irqflags); + if (!hw_res_used) + pme_hw_residue_free(hw_res); + /* enqueue the FCW command to PME */ + memset(&fd, 0, sizeof(fd)); + if (params) + memcpy(token->internal_flow_ptr, params, + sizeof(struct pme_flow)); + pme_fd_cmd_fcw(&fd, flags & PME_CMD_FCW_ALL, + (struct pme_flow *)token->internal_flow_ptr, + ctx->hw_residue); + ret = do_work(ctx, flags, &fd, &token->base_token, NULL, 0); + return ret; +} + +int pme_ctx_ctrl_update_flow(struct pme_ctx *ctx, u32 flags, + struct pme_flow *params, struct pme_ctx_ctrl_token *token) +{ + return __update_flow(ctx, flags, params, token, 0); +} +EXPORT_SYMBOL(pme_ctx_ctrl_update_flow); + +int pme_ctx_ctrl_read_flow(struct pme_ctx *ctx, u32 flags, + struct pme_flow *params, struct pme_ctx_ctrl_token *token) +{ + struct qm_fd fd; + + BUG_ON(ctx->flags & (PME_CTX_FLAG_DIRECT | PME_CTX_FLAG_PMTCC)); + token->base_token.cmd_type = pme_cmd_flow_read; + /* enqueue the FCR command to PME */ + token->usr_flow_ptr = params; + token->internal_flow_ptr = pme_hw_flow_new(); + if (!token->internal_flow_ptr) + return -ENOMEM; + memset(&fd, 0, sizeof(fd)); + pme_fd_cmd_fcr(&fd, (struct pme_flow *)token->internal_flow_ptr); + return do_work(ctx, flags, &fd, &token->base_token, NULL, 0); +} +EXPORT_SYMBOL(pme_ctx_ctrl_read_flow); + +int pme_ctx_ctrl_nop(struct pme_ctx *ctx, u32 flags, + struct pme_ctx_ctrl_token *token) +{ + struct qm_fd fd; + + token->base_token.cmd_type = pme_cmd_nop; + /* enqueue the NOP command to PME */ + memset(&fd, 0, sizeof(fd)); + qm_fd_addr_set64(&fd, (unsigned long)token); + pme_fd_cmd_nop(&fd); + return do_work(ctx, flags, &fd, &token->base_token, NULL, 0); +} +EXPORT_SYMBOL(pme_ctx_ctrl_nop); + +static inline void __prep_scan(__maybe_unused struct pme_ctx *ctx, + struct qm_fd *fd, u32 args, struct pme_ctx_token *token) +{ + BUG_ON(ctx->flags & PME_CTX_FLAG_PMTCC); + token->cmd_type = pme_cmd_scan; + pme_fd_cmd_scan(fd, args); +} + +int pme_ctx_scan(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, u32 args, + struct pme_ctx_token *token) +{ + __prep_scan(ctx, fd, args, token); + return do_work(ctx, flags, fd, token, NULL, 0); +} +EXPORT_SYMBOL(pme_ctx_scan); + +int pme_ctx_scan_orp(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, u32 args, + struct pme_ctx_token *token, struct qman_fq *orp_fq, u16 seqnum) +{ + __prep_scan(ctx, fd, args, token); + return do_work(ctx, flags, fd, token, orp_fq, seqnum); +} +EXPORT_SYMBOL(pme_ctx_scan_orp); + +int pme_ctx_pmtcc(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, + struct pme_ctx_token *token) +{ + BUG_ON(!(ctx->flags & PME_CTX_FLAG_PMTCC)); + token->cmd_type = pme_cmd_pmtcc; + pme_fd_cmd_pmtcc(fd); + return do_work(ctx, flags, fd, token, NULL, 0); +} +EXPORT_SYMBOL(pme_ctx_pmtcc); + +int pme_ctx_exclusive_inc(struct pme_ctx *ctx, u32 flags) +{ + return get_exclusive(ctx, flags); +} +EXPORT_SYMBOL(pme_ctx_exclusive_inc); + +void pme_ctx_exclusive_dec(struct pme_ctx *ctx) +{ + release_exclusive(ctx); +} +EXPORT_SYMBOL(pme_ctx_exclusive_dec); + +/* The 99.99% case is that enqueues happen in order or they get order-restored + * by the ORP, and so dequeues of responses happen in order too, so our FIFO + * linked-list of tokens is append-on-enqueue and pop-on-dequeue, and all's + * well. + * + * *EXCEPT*, if ever an enqueue gets rejected ... what then happens is that we + * have dequeues and ERNs to deal with, and the order we see them in is not + * necessarily the linked-list order. So we need to handle this in DQRR and MR + * callbacks, without sacrificing fast-path performance. Ouch. + * + * We use pop_matching_token() to take care of the mess (inlined, of course). */ +#define MATCH(fd1,fd2) \ + ((qm_fd_addr_get64(fd1) == qm_fd_addr_get64(fd2)) && \ + ((fd1)->opaque == (fd2)->opaque)) +static inline struct pme_ctx_token *pop_matching_token(struct pme_ctx *ctx, + const struct qm_fd *fd) +{ + struct pme_ctx_token *token; + const struct qm_fd *t_fd; + unsigned long irqflags; + + /* The fast-path case is that the for() loop actually degenerates into; + * token = list_first_entry(); + * if (likely(MATCH())) + * [done] + * The penalty of the slow-path case is the for() loop plus the fact + * we're optimising for a "likely" match first time, which might hurt + * when that assumption is wrong a few times in succession. */ + spin_lock_irqsave(&ctx->lock, irqflags); + list_for_each_entry(token, &ctx->tokens, node) { + t_fd = (const struct qm_fd *)&token->blob[0]; + if (likely(MATCH(t_fd, fd))) { + list_del(&token->node); + goto found; + } + } + token = NULL; + pr_err("PME2 Could not find matching token!\n"); + BUG(); +found: + spin_unlock_irqrestore(&ctx->lock, irqflags); + return token; +} + +static inline void cb_helper(__always_unused struct qman_portal *portal, + struct pme_ctx *ctx, const struct qm_fd *fd, int error) +{ + struct pme_ctx_token *token; + struct pme_ctx_ctrl_token *ctrl_token; + + /* Resist the urge to use "unlikely" - 'error' is a constant param to an + * inline fn, so the compiler can collapse this completely. */ + if (error) + do_flags(ctx, 0, 0, PME_CTX_FLAG_DEAD, 0); + token = pop_matching_token(ctx, fd); + if (likely(token->cmd_type == pme_cmd_scan)) + ctx->cb(ctx, fd, token); + else if (token->cmd_type == pme_cmd_pmtcc) + ctx->cb(ctx, fd, token); + else { + /* outcast ctx and call supplied callback */ + ctrl_token = container_of(token, struct pme_ctx_ctrl_token, + base_token); + if (token->cmd_type == pme_cmd_flow_write) { + /* Release the allocated flow context */ + pme_hw_flow_free(ctrl_token->internal_flow_ptr); + /* Is this pme_ctx_disable() completion? */ + if (token->is_disable_flush) + __disable_done(ctx); + } else if (token->cmd_type == pme_cmd_flow_read) { + /* Copy read result */ + memcpy(ctrl_token->usr_flow_ptr, + ctrl_token->internal_flow_ptr, + sizeof(struct pme_flow)); + /* Release the allocated flow context */ + pme_hw_flow_free(ctrl_token->internal_flow_ptr); + } + ctrl_token->cb(ctx, fd, ctrl_token); + } + /* Consume the frame */ + if (ctx->flags & PME_CTX_FLAG_EXCLUSIVE) + release_exclusive(ctx); + if (atomic_dec_and_test(&ctx->refs)) + wake_up(&ctx->queue); +} + +/* TODO: this scheme does not allow PME receivers to use held-active at all. Eg. + * there's no configuration of held-active for 'fq', and if there was, there's + * (a) nothing in the cb_dqrr() to support "park" or "defer" logic, and (b) + * nothing in cb_fqs() to support a delayed FQPN (DCAP_PK) notification. */ +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *portal, + struct qman_fq *fq, const struct qm_dqrr_entry *dq) +{ + u8 status = (u8)pme_fd_res_status(&dq->fd); + u8 flags = pme_fd_res_flags(&dq->fd); + struct pme_ctx *ctx = (struct pme_ctx *)fq; + + /* Put context into dead state is an unreliable or serious error is + * received + */ + if (unlikely(flags & PME_STATUS_UNRELIABLE)) + cb_helper(portal, ctx, &dq->fd, 1); + else if (unlikely((serious_error_vec[status]))) + cb_helper(portal, ctx, &dq->fd, 1); + else + cb_helper(portal, ctx, &dq->fd, 0); + + return qman_cb_dqrr_consume; +} + +static void cb_ern(__always_unused struct qman_portal *portal, + struct qman_fq *fq, const struct qm_mr_entry *mr) +{ + struct pme_ctx *ctx; + struct pme_nostash *data; + struct pme_ctx_token *token; + + data = container_of(fq, struct pme_nostash, fqin); + ctx = data->parent; + + token = pop_matching_token(ctx, &mr->ern.fd); + if (likely(token->cmd_type == pme_cmd_scan)) { + BUG_ON(!ctx->ern_cb); + ctx->ern_cb(ctx, mr, token); + } else if (token->cmd_type == pme_cmd_pmtcc) { + BUG_ON(!ctx->ern_cb); + ctx->ern_cb(ctx, mr, token); + } else { + struct pme_ctx_ctrl_token *ctrl_token; + /* outcast ctx and call supplied callback */ + ctrl_token = container_of(token, struct pme_ctx_ctrl_token, + base_token); + if (token->cmd_type == pme_cmd_flow_write) { + /* Release the allocated flow context */ + pme_hw_flow_free(ctrl_token->internal_flow_ptr); + } else if (token->cmd_type == pme_cmd_flow_read) { + /* Copy read result */ + memcpy(ctrl_token->usr_flow_ptr, + ctrl_token->internal_flow_ptr, + sizeof(struct pme_flow)); + /* Release the allocated flow context */ + pme_hw_flow_free(ctrl_token->internal_flow_ptr); + } + BUG_ON(!ctrl_token->ern_cb); + ctrl_token->ern_cb(ctx, mr, ctrl_token); + } + /* Consume the frame */ + if (ctx->flags & PME_CTX_FLAG_EXCLUSIVE) + release_exclusive(ctx); + if (atomic_dec_and_test(&ctx->refs)) + wake_up(&ctx->queue); +} + +static void cb_dc_ern(struct qman_portal *portal, struct qman_fq *fq, + const struct qm_mr_entry *mr) +{ + struct pme_ctx *ctx = (struct pme_ctx *)fq; + /* This, umm, *shouldn't* happen. It's pretty bad. Things are expected + * to fall apart here, but we'll continue long enough to get out of + * interrupt context and let the user unwind whatever they can. */ + pr_err("PME2 h/w enqueue rejection - expect catastrophe!\n"); + cb_helper(portal, ctx, &mr->dcern.fd, 1); +} + +static void cb_fqs(__always_unused struct qman_portal *portal, + __always_unused struct qman_fq *fq, + const struct qm_mr_entry *mr) +{ + u8 verb = mr->verb & QM_MR_VERB_TYPE_MASK; + if (verb == QM_MR_VERB_FQRNI) + return; + /* nothing else is supposed to occur */ + BUG(); +} + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_sample_db.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_sample_db.c @@ -0,0 +1,426 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "pme2_test.h" + +static u8 pme_db[] = { + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Rev 2.1 */ + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x90, 0x41, 0x40, 0x20, 0x00, 0x11, +/* Rev 2.0 */ +/* 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x20, 0x41, 0x40, 0x20, 0x00, 0x11, */ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Rev 2.1 */ + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x90, 0x41, 0xff, 0x81, 0x00, 0x00, +/* Rev 2.0 */ +/* 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, + 0x20, 0x41, 0xff, 0x81, 0x00, 0x00, */ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, + 0x01, 0xff, 0x80, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, + 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, + 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, + 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, + 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff +}; + +static u8 db_read[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Rev 2.1 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x90, 0x41 +/* Rev 2.0 */ +/* 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x20, 0x41 */ +}; + +static u8 db_read_expected_result[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Rev 2.1 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x90, 0x41, 0x40, 0x20, 0x00, 0x11 +/* Rev 2.0 */ +/* 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x20, 0x41, 0x40, 0x20, 0x00, 0x11*/ +}; + +struct pmtcc_ctx { + struct pme_ctx base_ctx; + struct qm_fd result_fd; + struct completion done; + u8 ern; +}; + +static void pmtcc_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_token *ctx_token) +{ + struct pmtcc_ctx *my_ctx = (struct pmtcc_ctx *)ctx; + memcpy(&my_ctx->result_fd, fd, sizeof(*fd)); + complete(&my_ctx->done); +} + +static void pmtcc_ern_cb(struct pme_ctx *ctx, const struct qm_mr_entry *mr, + struct pme_ctx_token *ctx_token) +{ + struct pmtcc_ctx *my_ctx = (struct pmtcc_ctx *)ctx; + my_ctx->result_fd = mr->ern.fd; + my_ctx->ern = 1; + complete(&my_ctx->done); +} + +#define FIRST_PMTCC 56 +int pme2_clear_sample_db(void) +{ + struct pmtcc_ctx ctx = { + .base_ctx.cb = pmtcc_cb, + .base_ctx.ern_cb = pmtcc_ern_cb, + .ern = 0 + }; + struct qm_fd fd; + int ret = 0; + enum pme_status status; + struct pme_ctx_token token; + void *mem; + struct cpumask backup_mask = current->cpus_allowed; + struct cpumask new_mask = *qman_affine_cpus(); + + cpumask_and(&new_mask, &new_mask, bman_affine_cpus()); + ret = set_cpus_allowed_ptr(current, &new_mask); + if (ret) { + pr_info("cleanr_sample_db: can't set cpumask\n"); + goto _clear_0; + } + init_completion(&ctx.done); + ret = pme_ctx_init(&ctx.base_ctx, + PME_CTX_FLAG_EXCLUSIVE | + PME_CTX_FLAG_PMTCC | + PME_CTX_FLAG_LOCAL, 0, 4, 4, 0, NULL); + if (ret) { + pr_err("clear_sample_db: can't init ctx\n"); + goto _clear_1; + } + + /* enable the context */ + ret = pme_ctx_enable(&ctx.base_ctx); + if (ret) { + pr_err("clear_sample_db: can't enable ctx\n"); + goto _clear_2; + } + + /* Write the database */ + memset(&fd, 0, sizeof(struct qm_fd)); + mem = kmalloc(FIRST_PMTCC, GFP_KERNEL); + if (!mem) + goto _clear_3; + memcpy(mem, pme_db, FIRST_PMTCC); + + fd.length20 = FIRST_PMTCC; + qm_fd_addr_set64(&fd, pme_map(mem)); + + ret = pme_ctx_pmtcc(&ctx.base_ctx, PME_CTX_OP_WAIT, &fd, &token); + if (ret == -ENODEV) { + pr_err("clear_sample_db: not the control plane, bailing\n"); + goto _clear_4; + } + if (ret) { + pr_err("clear_sample_db: error with pmtcc\n"); + goto _clear_4; + } + wait_for_completion(&ctx.done); + if (ctx.ern) { + pr_err("clear_sample_db: Rx ERN from pmtcc\n"); + goto _clear_4; + } + status = pme_fd_res_status(&ctx.result_fd); + if (status) { + pr_info("clear_sample_db: PMTCC write status failed %d\n", + status); + goto _clear_4; + } +_clear_4: + kfree(mem); +_clear_3: + /* Disable */ + ret = pme_ctx_disable(&ctx.base_ctx, + PME_CTX_OP_WAIT | PME_CTX_OP_WAIT_INT, NULL); +_clear_2: + pme_ctx_finish(&ctx.base_ctx); +_clear_1: + ret = set_cpus_allowed_ptr(current, &backup_mask); + if (ret) + pr_info("clear_sample_db: can't restore cpumask"); +_clear_0: + if (!ret) + pr_info("clear_sample_db: Done\n"); + else + pr_info("clear_sample_db: Error 0x%x\n", ret); + return ret; + +} + +int pme2_sample_db(void) +{ + struct pmtcc_ctx ctx = { + .base_ctx.cb = pmtcc_cb, + .base_ctx.ern_cb = pmtcc_ern_cb, + .ern = 0 + }; + struct qm_fd fd; + struct qm_sg_entry *sg_table = NULL; + int ret = 0; + enum pme_status status; + struct pme_ctx_token token; + void *mem = NULL, *mem_result = NULL; + u32 pme_rev; + struct cpumask backup_mask = current->cpus_allowed; + struct cpumask new_mask = *qman_affine_cpus(); + + cpumask_and(&new_mask, &new_mask, bman_affine_cpus()); + ret = set_cpus_allowed_ptr(current, &new_mask); + if (ret) { + pr_info("sample_db: can't set cpumask\n"); + goto _finish_0; + } + ret = pme_attr_get(pme_attr_rev1, &pme_rev); + if (ret) { + pr_err("sample_db: can't read pme revision %d\n", ret); + goto _finish_1; + } + /* If Rev 2.0...update database */ + if ((pme_rev & 0x0000FFFF) == 0x00000200) { + pr_info("sample_db: db for pme ver 2.0\n"); + pme_db[133] = 0x01; + pme_db[134] = 0x20; + pme_db[161] = 0x01; + pme_db[162] = 0x20; + db_read[21] = 0x01; + db_read[22] = 0x20; + db_read_expected_result[21] = 0x01; + db_read_expected_result[22] = 0x20; + } else + pr_info("sample_db: db for pme ver 2.1 or greater\n"); + init_completion(&ctx.done); + ret = pme_ctx_init(&ctx.base_ctx, + PME_CTX_FLAG_EXCLUSIVE | + PME_CTX_FLAG_PMTCC | + PME_CTX_FLAG_LOCAL, 0, 4, 4, 0, NULL); + if (ret) { + pr_err("sample_db: can't init ctx\n"); + goto _finish_1; + } + + /* enable the context */ + ret = pme_ctx_enable(&ctx.base_ctx); + if (ret) { + pr_err("sample_db: can't enable ctx\n"); + goto _finish_2; + } + + /* Write the database */ + memset(&fd, 0, sizeof(struct qm_fd)); + mem = kmalloc(sizeof(pme_db), GFP_KERNEL); + if (!mem) + goto _finish_3; + memcpy(mem, pme_db, sizeof(pme_db)); + + fd.length20 = sizeof(pme_db); + qm_fd_addr_set64(&fd, pme_map(mem)); + + ret = pme_ctx_pmtcc(&ctx.base_ctx, PME_CTX_OP_WAIT, &fd, &token); + if (ret == -ENODEV) { + pr_err("sample_db: not the control plane, bailing\n"); + goto _finish_4; + } + if (ret) { + pr_err("sample_db: error with pmtcc\n"); + goto _finish_4; + } + wait_for_completion(&ctx.done); + if (ctx.ern) { + pr_err("sample_db: Rx ERN from pmtcc\n"); + goto _finish_4; + } + status = pme_fd_res_status(&ctx.result_fd); + if (status) { + pr_info("sample_db: PMTCC write status failed %d\n", status); + goto _finish_4; + } + kfree(mem); + mem = NULL; + /* Read back the database */ + init_completion(&ctx.done); + memset(&fd, 0, sizeof(struct qm_fd)); + sg_table = kzalloc(2 * sizeof(*sg_table), GFP_KERNEL | GFP_DMA); + mem_result = kmalloc(28, GFP_KERNEL); + mem = kmalloc(sizeof(db_read), GFP_KERNEL); + if (!sg_table || !mem || !mem_result) { + pr_err("sample_db: out of memory\n"); + ret = -ENOMEM; + goto _finish_4; + } + memcpy(mem, db_read, sizeof(db_read)); + qm_sg_entry_set64(&sg_table[0], pme_map(mem_result)); + sg_table[0].length = 28; + qm_sg_entry_set64(&sg_table[1], pme_map(mem)); + sg_table[1].length = sizeof(db_read); + sg_table[1].final = 1; + fd.format = qm_fd_compound; + qm_fd_addr_set64(&fd, pme_map(sg_table)); + ret = pme_ctx_pmtcc(&ctx.base_ctx, PME_CTX_OP_WAIT, &fd, &token); + if (ret) { + pr_err("sample_db: error with pmtcc\n"); + goto _finish_4; + } + wait_for_completion(&ctx.done); + if (ctx.ern) { + ret = -EINVAL; + pr_err("sample_db: Rx ERN from pmtcc\n"); + goto _finish_4; + } + status = pme_fd_res_status(&ctx.result_fd); + if (status) { + ret = -EINVAL; + pr_err("sample_db: PMTCC read status failed %d\n", status); + goto _finish_4; + } + if (pme_fd_res_flags(&ctx.result_fd) & PME_STATUS_UNRELIABLE) { + pr_err("sample_db: flags result set %x\n", + pme_fd_res_flags(&ctx.result_fd)); + ret = -EINVAL; + goto _finish_4; + } + if (memcmp(db_read_expected_result, mem_result, 28) != 0) { + pr_err("sample_db: DB read result not expected\n"); + pr_err("Expected\n"); + hexdump(db_read_expected_result, + sizeof(db_read_expected_result)); + pr_info("Received\n"); + hexdump(mem_result, 28); + ret = -EINVAL; + } +_finish_4: + kfree(mem_result); + kfree(sg_table); + kfree(mem); +_finish_3: + /* Disable */ + ret = pme_ctx_disable(&ctx.base_ctx, + PME_CTX_OP_WAIT | PME_CTX_OP_WAIT_INT, NULL); +_finish_2: + pme_ctx_finish(&ctx.base_ctx); +_finish_1: + if (ret) + set_cpus_allowed_ptr(current, &backup_mask); + else { + ret = set_cpus_allowed_ptr(current, &backup_mask); + if (ret) + pr_info("sample_db: can't restore cpumask"); + } + +_finish_0: + if (!ret) + pr_info("pme: sample DB initialised\n"); + else + pr_info("pme: Error during sample DB 0x%x\n", ret); + return ret; +} + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_db.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_db.c @@ -0,0 +1,572 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pme2_private.h" +#include + +/* Forward declaration */ +static struct miscdevice fsl_pme2_db_dev; + +/* Global spinlock for handling exclusive inc/dec */ +static DEFINE_SPINLOCK(exclusive_lock); + +/* Private structure that is allocated for each open that is done on the + * pme_db device. This is used to maintain the state of a database session */ +struct db_session { + /* The ctx that is needed to communicate with the pme high level */ + struct pme_ctx ctx; + /* Used to track the EXCLUSIVE_INC and EXCLUSIVE_DEC ioctls */ + unsigned int exclusive_counter; +}; + +struct cmd_token { + /* pme high level token */ + struct pme_ctx_token hl_token; + /* data */ + struct qm_fd rx_fd; + /* Completion interface */ + struct completion cb_done; + u8 ern; +}; + +#ifdef CONFIG_COMPAT +static void compat_to_db(struct pme_db *dst, struct compat_pme_db *src) +{ + dst->flags = src->flags; + dst->status = src->status; + dst->input.data = compat_ptr(src->input.data); + dst->input.size = src->input.size; + dst->output.data = compat_ptr(src->output.data); + dst->output.size = src->output.size; +} + +static void db_to_compat(struct compat_pme_db *dst, struct pme_db *src) +{ + dst->flags = src->flags; + dst->status = src->status; + dst->output.data = ptr_to_compat(src->output.data); + dst->output.size = src->output.size; + dst->input.data = ptr_to_compat(src->input.data); + dst->input.size = src->input.size; +} +#endif + +/* PME Compound Frame Index */ +#define INPUT_FRM 1 +#define OUTPUT_FRM 0 + +/* Callback for database operations */ +static void db_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_token *ctx_token) +{ + struct cmd_token *token = (struct cmd_token *)ctx_token; + token->rx_fd = *fd; + complete(&token->cb_done); +} + +static void db_ern_cb(struct pme_ctx *ctx, const struct qm_mr_entry *mr, + struct pme_ctx_token *ctx_token) +{ + struct cmd_token *token = (struct cmd_token *)ctx_token; + token->ern = 1; + token->rx_fd = mr->ern.fd; + complete(&token->cb_done); +} + +struct ctrl_op { + struct pme_ctx_ctrl_token ctx_ctr; + struct completion cb_done; + enum pme_status cmd_status; + u8 res_flag; + u8 ern; +}; + +static void ctrl_cb(struct pme_ctx *ctx, const struct qm_fd *fd, + struct pme_ctx_ctrl_token *token) +{ + struct ctrl_op *ctrl = (struct ctrl_op *)token; + ctrl->cmd_status = pme_fd_res_status(fd); + ctrl->res_flag = pme_fd_res_flags(fd) & PME_STATUS_UNRELIABLE; + complete(&ctrl->cb_done); +} + +static void ctrl_ern_cb(struct pme_ctx *ctx, const struct qm_mr_entry *mr, + struct pme_ctx_ctrl_token *token) +{ + struct ctrl_op *ctrl = (struct ctrl_op *)token; + ctrl->ern = 1; + complete(&ctrl->cb_done); +} + +static int exclusive_inc(struct file *fp, struct db_session *db) +{ + int ret; + + BUG_ON(!db); + BUG_ON(!(db->ctx.flags & PME_CTX_FLAG_EXCLUSIVE)); + spin_lock(&exclusive_lock); + ret = pme_ctx_exclusive_inc(&db->ctx, + (PME_CTX_OP_WAIT | PME_CTX_OP_WAIT_INT)); + if (!ret) + db->exclusive_counter++; + spin_unlock(&exclusive_lock); + return ret; +} + +static int exclusive_dec(struct file *fp, struct db_session *db) +{ + int ret = 0; + + BUG_ON(!db); + BUG_ON(!(db->ctx.flags & PME_CTX_FLAG_EXCLUSIVE)); + spin_lock(&exclusive_lock); + if (!db->exclusive_counter) { + PMEPRERR("exclusivity counter already zero\n"); + ret = -EINVAL; + } else { + pme_ctx_exclusive_dec(&db->ctx); + db->exclusive_counter--; + } + spin_unlock(&exclusive_lock); + return ret; +} + +static int execute_cmd(struct file *fp, struct db_session *db, + struct pme_db *db_cmd) +{ + int ret = 0; + struct cmd_token token; + struct qm_sg_entry tx_comp[2]; + struct qm_fd tx_fd; + void *tx_data = NULL; + void *rx_data = NULL; + u32 src_sz, dst_sz; + dma_addr_t dma_addr; + + memset(&token, 0, sizeof(struct cmd_token)); + memset(tx_comp, 0, sizeof(tx_comp)); + memset(&tx_fd, 0, sizeof(struct qm_fd)); + init_completion(&token.cb_done); + + PMEPRINFO("Received User Space Contiguous mem\n"); + PMEPRINFO("length = %d\n", db_cmd->input.size); + tx_data = kmalloc(db_cmd->input.size, GFP_KERNEL); + if (!tx_data) { + PMEPRERR("Err alloc %zd byte\n", db_cmd->input.size); + return -ENOMEM; + } + + if (copy_from_user(tx_data, + (void __user *)db_cmd->input.data, + db_cmd->input.size)) { + PMEPRERR("Error copying contigous user data\n"); + ret = -EFAULT; + goto free_tx_data; + } + + /* Setup input frame */ + tx_comp[INPUT_FRM].final = 1; + tx_comp[INPUT_FRM].length = db_cmd->input.size; + dma_addr = pme_map(tx_data); + if (pme_map_error(dma_addr)) { + PMEPRERR("Error pme_map_error\n"); + ret = -EIO; + goto free_tx_data; + } + set_sg_addr(&tx_comp[INPUT_FRM], dma_addr); + /* setup output frame, if output is expected */ + if (db_cmd->output.size) { + PMEPRINFO("expect output %d\n", db_cmd->output.size); + rx_data = kmalloc(db_cmd->output.size, GFP_KERNEL); + if (!rx_data) { + PMEPRERR("Err alloc %zd byte", db_cmd->output.size); + ret = -ENOMEM; + goto unmap_input_frame; + } + /* Setup output frame */ + tx_comp[OUTPUT_FRM].length = db_cmd->output.size; + dma_addr = pme_map(rx_data); + if (pme_map_error(dma_addr)) { + PMEPRERR("Error pme_map_error\n"); + ret = -EIO; + goto comp_frame_free_rx; + } + set_sg_addr(&tx_comp[OUTPUT_FRM], dma_addr); + tx_fd.format = qm_fd_compound; + /* Build compound frame */ + dma_addr = pme_map(tx_comp); + if (pme_map_error(dma_addr)) { + PMEPRERR("Error pme_map_error\n"); + ret = -EIO; + goto comp_frame_unmap_output; + } + set_fd_addr(&tx_fd, dma_addr); + } else { + tx_fd.format = qm_fd_sg_big; + tx_fd.length29 = db_cmd->input.size; + /* Build sg frame */ + dma_addr = pme_map(&tx_comp[INPUT_FRM]); + if (pme_map_error(dma_addr)) { + PMEPRERR("Error pme_map_error\n"); + ret = -EIO; + goto unmap_input_frame; + } + set_fd_addr(&tx_fd, dma_addr); + } + ret = pme_ctx_pmtcc(&db->ctx, PME_CTX_OP_WAIT, &tx_fd, + (struct pme_ctx_token *)&token); + if (unlikely(ret)) { + PMEPRINFO("pme_ctx_pmtcc error %d\n", ret); + goto unmap_frame; + } + PMEPRINFO("Wait for completion\n"); + /* Wait for the command to complete */ + wait_for_completion(&token.cb_done); + + if (token.ern) { + ret = -EIO; + goto unmap_frame; + } + + PMEPRINFO("pme2_db: process_completed_token\n"); + PMEPRINFO("pme2_db: received %d frame type\n", token.rx_fd.format); + if (token.rx_fd.format == qm_fd_compound) { + /* Need to copy output */ + src_sz = tx_comp[OUTPUT_FRM].length; + dst_sz = db_cmd->output.size; + PMEPRINFO("pme gen %u data, have space for %u\n", + src_sz, dst_sz); + db_cmd->output.size = min(dst_sz, src_sz); + /* Doesn't make sense we generated more than available space + * should have got truncation. + */ + BUG_ON(dst_sz < src_sz); + if (copy_to_user((void __user *)db_cmd->output.data, rx_data, + db_cmd->output.size)) { + PMEPRERR("Error copying to user data\n"); + ret = -EFAULT; + goto comp_frame_unmap_cf; + } + } else if (token.rx_fd.format == qm_fd_sg_big) + db_cmd->output.size = 0; + else + panic("unexpected frame type received %d\n", + token.rx_fd.format); + + db_cmd->flags = pme_fd_res_flags(&token.rx_fd); + db_cmd->status = pme_fd_res_status(&token.rx_fd); + +unmap_frame: + if (token.rx_fd.format == qm_fd_sg_big) + goto single_frame_unmap_frame; + +comp_frame_unmap_cf: +comp_frame_unmap_output: +comp_frame_free_rx: + kfree(rx_data); + goto unmap_input_frame; +single_frame_unmap_frame: +unmap_input_frame: +free_tx_data: + kfree(tx_data); + + return ret; +} + +static int execute_nop(struct file *fp, struct db_session *db) +{ + int ret = 0; + struct ctrl_op ctx_ctrl = { + .ctx_ctr.cb = ctrl_cb, + .ctx_ctr.ern_cb = ctrl_ern_cb + }; + init_completion(&ctx_ctrl.cb_done); + + ret = pme_ctx_ctrl_nop(&db->ctx, PME_CTX_OP_WAIT|PME_CTX_OP_WAIT_INT, + &ctx_ctrl.ctx_ctr); + if (!ret) + wait_for_completion(&ctx_ctrl.cb_done); + + if (ctx_ctrl.ern) + ret = -EIO; + return ret; +} + +static atomic_t sre_reset_lock = ATOMIC_INIT(1); +static int ioctl_sre_reset(unsigned long arg) +{ + struct pme_db_sre_reset reset_vals; + int i; + u32 srrr_val; + int ret = 0; + + if (copy_from_user(&reset_vals, (struct pme_db_sre_reset __user *)arg, + sizeof(struct pme_db_sre_reset))) + return -EFAULT; + PMEPRINFO("sre_reset:\n"); + PMEPRINFO(" rule_index = 0x%x:\n", reset_vals.rule_index); + PMEPRINFO(" rule_increment = 0x%x:\n", reset_vals.rule_increment); + PMEPRINFO(" rule_repetitions = 0x%x:\n", reset_vals.rule_repetitions); + PMEPRINFO(" rule_reset_interval = 0x%x:\n", + reset_vals.rule_reset_interval); + PMEPRINFO(" rule_reset_priority = 0x%x:\n", + reset_vals.rule_reset_priority); + + /* Validate ranges */ + if ((reset_vals.rule_index >= PME_PMFA_SRE_INDEX_MAX) || + (reset_vals.rule_increment > PME_PMFA_SRE_INC_MAX) || + (reset_vals.rule_repetitions >= PME_PMFA_SRE_REP_MAX) || + (reset_vals.rule_reset_interval >= + PME_PMFA_SRE_INTERVAL_MAX)) + return -ERANGE; + /* Check and make sure only one caller is present */ + if (!atomic_dec_and_test(&sre_reset_lock)) { + /* Someone else is already in this call */ + atomic_inc(&sre_reset_lock); + return -EBUSY; + }; + /* All validated. Run the command */ + for (i = 0; i < PME_SRE_RULE_VECTOR_SIZE; i++) + pme_attr_set(pme_attr_srrv0 + i, reset_vals.rule_vector[i]); + pme_attr_set(pme_attr_srrfi, reset_vals.rule_index); + pme_attr_set(pme_attr_srri, reset_vals.rule_increment); + pme_attr_set(pme_attr_srrwc, + (0xFFF & reset_vals.rule_reset_interval) << 1 | + (reset_vals.rule_reset_priority ? 1 : 0)); + /* Need to set SRRR last */ + pme_attr_set(pme_attr_srrr, reset_vals.rule_repetitions); + do { + mdelay(PME_PMFA_SRE_POLL_MS); + ret = pme_attr_get(pme_attr_srrr, &srrr_val); + if (ret) { + PMEPRCRIT("pme2: Error reading srrr\n"); + /* bail */ + break; + } + /* Check for error */ + else if (srrr_val & 0x10000000) { + PMEPRERR("pme2: Error in SRRR\n"); + ret = -EIO; + } + PMEPRINFO("pme2: srrr count %d\n", srrr_val); + } while (srrr_val); + atomic_inc(&sre_reset_lock); + return ret; +} + +/** + * fsl_pme2_db_open - open the driver + * + * Open the driver and prepare for requests. + * + * Every time an application opens the driver, we create a db_session object + * for that file handle. + */ +static int fsl_pme2_db_open(struct inode *node, struct file *fp) +{ + int ret; + struct db_session *db = NULL; + + db = kzalloc(sizeof(struct db_session), GFP_KERNEL); + if (!db) + return -ENOMEM; + fp->private_data = db; + db->ctx.cb = db_cb; + db->ctx.ern_cb = db_ern_cb; + + ret = pme_ctx_init(&db->ctx, + PME_CTX_FLAG_EXCLUSIVE | + PME_CTX_FLAG_PMTCC | + PME_CTX_FLAG_DIRECT| + PME_CTX_FLAG_LOCAL, + 0, 4, CONFIG_FSL_PME2_DB_QOSOUT_PRIORITY, 0, NULL); + if (ret) { + PMEPRERR("pme_ctx_init %d\n", ret); + goto free_data; + } + + /* enable the context */ + ret = pme_ctx_enable(&db->ctx); + if (ret) { + PMEPRERR("error enabling ctx %d\n", ret); + pme_ctx_finish(&db->ctx); + goto free_data; + } + PMEPRINFO("pme2_db: Finish pme_db open %d\n", smp_processor_id()); + return 0; +free_data: + kfree(fp->private_data); + fp->private_data = NULL; + return ret; +} + +static int fsl_pme2_db_close(struct inode *node, struct file *fp) +{ + int ret = 0; + struct db_session *db = fp->private_data; + + PMEPRINFO("Start pme_db close\n"); + while (db->exclusive_counter) { + pme_ctx_exclusive_dec(&db->ctx); + db->exclusive_counter--; + } + + /* Disable context. */ + ret = pme_ctx_disable(&db->ctx, PME_CTX_OP_WAIT, NULL); + if (ret) + PMEPRCRIT("Error disabling ctx %d\n", ret); + pme_ctx_finish(&db->ctx); + kfree(db); + PMEPRINFO("Finish pme_db close\n"); + return 0; +} + +/* Main switch loop for ioctl operations */ +static long fsl_pme2_db_ioctl(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + struct db_session *db = fp->private_data; + int ret = 0; + + switch (cmd) { + + case PMEIO_PMTCC: { + int ret; + struct pme_db db_cmd; + + /* Copy the command to kernel space */ + if (copy_from_user(&db_cmd, (void __user *)arg, + sizeof(db_cmd))) + return -EFAULT; + ret = execute_cmd(fp, db, &db_cmd); + if (!ret) + ret = copy_to_user((struct pme_db __user *)arg, + &db_cmd, sizeof(db_cmd)); + return ret; + } + break; + + case PMEIO_EXL_INC: + return exclusive_inc(fp, db); + case PMEIO_EXL_DEC: + return exclusive_dec(fp, db); + case PMEIO_EXL_GET: + BUG_ON(!db); + BUG_ON(!(db->ctx.flags & PME_CTX_FLAG_EXCLUSIVE)); + if (copy_to_user((void __user *)arg, + &db->exclusive_counter, + sizeof(db->exclusive_counter))) + ret = -EFAULT; + return ret; + case PMEIO_NOP: + return execute_nop(fp, db); + case PMEIO_SRE_RESET: + return ioctl_sre_reset(arg); + +#ifdef CONFIG_COMPAT + case PMEIO_PMTCC32: { + int ret; + struct pme_db db_cmd; + struct compat_pme_db db_cmd32; + struct compat_pme_db __user *user_db_cmd = compat_ptr(arg); + + /* Copy the command to kernel space */ + if (copy_from_user(&db_cmd32, user_db_cmd, sizeof(db_cmd32))) + return -EFAULT; + /* Convert to 64-bit struct */ + compat_to_db(&db_cmd, &db_cmd32); + ret = execute_cmd(fp, db, &db_cmd); + if (!ret) { + /* Convert to compat struct */ + db_to_compat(&db_cmd32, &db_cmd); + ret = copy_to_user(user_db_cmd, &db_cmd32, + sizeof(*user_db_cmd)); + } + return ret; + } + break; +#endif + } + pr_info("Unknown pme_db ioctl cmd %u\n", cmd); + return -EINVAL; +} + +static const struct file_operations fsl_pme2_db_fops = { + .owner = THIS_MODULE, + .open = fsl_pme2_db_open, + .release = fsl_pme2_db_close, + .unlocked_ioctl = fsl_pme2_db_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fsl_pme2_db_ioctl, +#endif +}; + +static struct miscdevice fsl_pme2_db_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = PME_DEV_DB_NODE, + .fops = &fsl_pme2_db_fops +}; + +static int __init fsl_pme2_db_init(void) +{ + int err = 0; + + pr_info("Freescale pme2 db driver\n"); + if (!pme2_have_control()) { + PMEPRERR("not on ctrl-plane\n"); + return -ENODEV; + } + err = misc_register(&fsl_pme2_db_dev); + if (err) { + PMEPRERR("cannot register device\n"); + return err; + } + PMEPRINFO("device %s registered\n", fsl_pme2_db_dev.name); + return 0; +} + +static void __exit fsl_pme2_db_exit(void) +{ + int err = misc_deregister(&fsl_pme2_db_dev); + if (err) { + PMEPRERR("Failed to deregister device %s, " + "code %d\n", fsl_pme2_db_dev.name, err); + return; + } + PMEPRINFO("device %s deregistered\n", fsl_pme2_db_dev.name); +} + +module_init(fsl_pme2_db_init); +module_exit(fsl_pme2_db_exit); + +MODULE_AUTHOR("Freescale Semiconductor - OTC"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL PME2 db driver"); --- linux-3.13.0.orig/drivers/staging/fsl_pme2/Makefile +++ linux-3.13.0/drivers/staging/fsl_pme2/Makefile @@ -0,0 +1,10 @@ +# PME +obj-$(CONFIG_FSL_PME2_CTRL) += pme2_ctrl.o pme2_sysfs.o +obj-$(CONFIG_FSL_PME2_PORTAL) += pme2.o +pme2-y := pme2_low.o pme2_high.o +obj-$(CONFIG_FSL_PME2_TEST_HIGH) += pme2_test_high.o +obj-$(CONFIG_FSL_PME2_TEST_SCAN) += pme2_test_scanning.o +pme2_test_scanning-y = pme2_test_scan.o pme2_sample_db.o +obj-$(CONFIG_FSL_PME2_DB) += pme2_db.o +obj-$(CONFIG_FSL_PME2_SCAN) += pme2_scan.o + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/Kconfig +++ linux-3.13.0/drivers/staging/fsl_pme2/Kconfig @@ -0,0 +1,215 @@ +config FSL_PME2 + bool "Freescale Datapath Pattern Matcher support" + depends on HAS_FSL_PME && FSL_QMAN_PORTAL + default y + +menu "Freescale Datapath PME options" + depends on FSL_PME2 + +config FSL_PME2_CTRL + bool "Freescale PME2 (p4080, etc) device control" + default y + ---help--- + This compiles device support for the Freescale PME2 pattern matching + part contained in datapath-enabled SoCs (ie. accessed via Qman and + Bman portal functionality). At least one guest operating system must + have this driver support, together with the appropriate device-tree + entry, for PME2 functionality to be available. It is responsible for + allocating system memory to the device and configuring it for + operation. For this reason, it must be built into the kernel and will + initialise during early kernel boot. + +config FSL_PME2_PDSRSIZE + int "Pattern Description and Stateful Rule default table size" + depends on FSL_PME2_CTRL + range 74240 1048573 + default 131072 + help + Select the default size of the Pattern Description and Stateful Rule + table as the number of 128 byte entries. This only takes effect if + the device tree node doesn't have the 'fsl,pme-pdsr' property. + range 74240-1048573 (9.5MB-134MB) + default 131072 (16MB) + +if FSL_PME2_CTRL +comment "Statefule Rule Engine" +endif + +config FSL_PME2_SRESIZE + int "SRE Session Context Entries table default table size" + depends on FSL_PME2_CTRL + range 0 134217727 + default 327680 + help + Select the default size of the SRE Context Table as the number of 32 + byte entries. This only takes effect if the device tree node doesn't + have the 'fsl,pme-sre' property. + range 0-134217727 (0-4GB) + default 327680 (10MB) + +config FSL_PME2_SRE_AIM + bool "Alternate Inconclusive Mode" + depends on FSL_PME2_CTRL + default n + help + Select the inconclusive match mode treatment. When true the + “alternate†inconclusive mode is used. When false the “default†+ inconclusive mode is used. + +config FSL_PME2_SRE_ESR + bool "End of SUI Simple Report" + depends on FSL_PME2_CTRL + default n + help + Select if an End of SUI will produce a Simple End of SUI report. + +config FSL_PME2_SRE_CTX_SIZE_PER_SESSION + int "Default SRE Context Size per Session (16 => 64KB, 17 => 128KB)" + depends on FSL_PME2_CTRL + range 5 17 + default 17 + help + Select SRE context size per session as a power of 2. + range 5-17 + Examples: + 5 => 32 B + 6 => 64 B + 7 => 128 B + 8 => 256 B + 9 => 512 B + 10 => 1 KB + 11 => 2 KB + 12 => 4 KB + 13 => 8 KB + 14 => 16 KB + 15 => 32 KB + 16 => 64 KB + 17 => 128 KB + +config FSL_PME2_SRE_CNR + int "Configured Number of Stateful Rules as a multiple of 256 (128 => 32768 )" + depends on FSL_PME2_CTRL + range 0 128 + default 128 + help + Select number of stateful rules as a multiple of 256. + range 0-128 + Examples: + 0 => 0 + 1 => 256 + 2 => 512 + ... + 127 => 32512 + 128 => 32768 + +config FSL_PME2_SRE_MAX_INSTRUCTION_LIMIT + int "Maximum number of SRE instructions to be executed per reaction." + depends on FSL_PME2_CTRL + range 0 65535 + default 65535 + help + Select the maximum number of SRE instructions to be executed per + reaction. + range 0 65535 + +config FSL_PME2_SRE_MAX_BLOCK_NUMBER + int "Maximum number of Reaction Head blocks to be traversed per pattern match event" + depends on FSL_PME2_CTRL + range 0 32767 + default 32767 + help + Select the maximum number of reaction head blocks to be traversed per + pattern match event (e.g. a matched pattern or an End of SUI event). + range 0-32767 + +config FSL_PME2_PORTAL + tristate "Freescale PME2 (p4080, etc) device usage" + default y + ---help--- + This compiles I/O support for the Freescale PME2 pattern matching + part contained in datapath-enabled SoCs (ie. accessed via Qman and + Bman portal functionality). + +if FSL_PME2_PORTAL + +config FSL_PME2_TEST_HIGH + tristate "PME2 high-level self-test" + default n + ---help--- + This uses the high-level Qman driver (and the cpu-affine portals it + manages) to perform high-level PME2 API testing with it. + +config FSL_PME2_TEST_SCAN + tristate "PME2 scan self-test" + default n + ---help--- + This uses the high-level Qman driver (and the cpu-affine portals it + manages) to perform scan PME2 API testing with it. + +config FSL_PME2_TEST_SCAN_WITH_BPID + bool "PME2 scan self-test with buffer pool" + depends on FSL_PME2_TEST_SCAN && FSL_BMAN_PORTAL + default y + ---help--- + This uses a buffer pool id for scan test + +config FSL_PME2_TEST_SCAN_WITH_BPID_SIZE + int "Buffer Pool size." + depends on FSL_PME2_TEST_SCAN_WITH_BPID + range 0 11 + default 3 + ---help--- + This uses the specified buffer pool size. + +config FSL_PME2_DB + tristate "PME2 Database support" + depends on FSL_PME2_CTRL + default y + ---help--- + This compiles the database driver for PME2. + +config FSL_PME2_DB_QOSOUT_PRIORITY + int "PME DB output frame queue priority." + depends on FSL_PME2_DB + range 0 7 + default 2 + ---help--- + The PME DB has a scheduled output frame queue. The qos priority level is configurable. + range 0-7 + 0 => High Priority 0 + 1 => High Priority 1 + 2 => Medium Priority + 3 => Medium Priority + 4 => Medium Priority + 5 => Low Priority + 6 => Low Priority + 7 => Low Priority + +config FSL_PME2_SCAN + tristate "PME2 Scan support" + default y + ---help--- + This compiles the scan driver for PME2. + +config FSL_PME2_SCAN_DEBUG + bool "Debug Statements" + default n + depends on FSL_PME2_SCAN + ---help--- + The PME2_SCAN driver can optionally trace with more verbosity + of verbosity. + +endif + +config FSL_PME2_STAT_ACCUMULATOR_UPDATE_INTERVAL + int "Configure the pme2 statistics update interval in milliseconds" + depends on FSL_PME2_CTRL + range 0 10000 + default 3400 + help + The pme accumulator reads the current device statistics and add it + to a running counter. The frequency of these updates may be + controlled. If 0 is specified, no automatic updates is done. + range 0-10000 + +endmenu --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_ctrl.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_ctrl.c @@ -0,0 +1,1335 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "pme2_private.h" +#include "pme2_regs.h" + +/* PME HW Revision */ +#define PME_REV(rev1_reg) (rev1_reg & 0x0000FFFF) +#define PME_REV_2_0 0x00000200 +#define PME_REV_2_1 0x00000201 +#define DEC1_MAX_REV_2_0 0x000FFFFC +#define DEC1_MAX_REV_2_1 0x0007FFFC + + +/* Driver Name is used in naming the sysfs directory + * /sys/bus/of_platform/drivers/DRV_NAME + */ +#define DRV_NAME "fsl-pme" + +#define DEFAULT_PDSR_SZ (CONFIG_FSL_PME2_PDSRSIZE << 7) +#define DEFAULT_SRE_SZ (CONFIG_FSL_PME2_SRESIZE << 5) +#define PDSR_TBL_ALIGN (1 << 7) +#define SRE_TBL_ALIGN (1 << 5) +#define DEFAULT_SRFCC 400 + +/* Defaults */ +#define DEFAULT_DEC0_MTE 0x3FFF +#define DEFAULT_DLC_MPM 0xFFFF +#define DEFAULT_DLC_MPE 0xFFFF +/* Boot parameters */ +DECLARE_GLOBAL(max_test_line_per_pat, unsigned int, uint, + DEFAULT_DEC0_MTE, + "Maximum allowed Test Line Executions per pattern, " + "scaled by a factor of 8"); +DECLARE_GLOBAL(max_pat_eval_per_sui, unsigned int, uint, + DEFAULT_DLC_MPE, + "Maximum Pattern Evaluations per SUI, scaled by a factor of 8") +DECLARE_GLOBAL(max_pat_matches_per_sui, unsigned int, uint, + DEFAULT_DLC_MPM, + "Maximum Pattern Matches per SUI"); +/* SRE */ +DECLARE_GLOBAL(sre_rule_num, unsigned int, uint, + CONFIG_FSL_PME2_SRE_CNR, + "Configured Number of Stateful Rules"); +DECLARE_GLOBAL(sre_session_ctx_size, unsigned int, uint, + 1 << CONFIG_FSL_PME2_SRE_CTX_SIZE_PER_SESSION, + "SRE Context Size per Session"); + +/************ + * Section 1 + ************ + * This code is called during kernel early-boot and could never be made + * loadable. + */ +static dma_addr_t dxe_a, sre_a; +static size_t dxe_sz = DEFAULT_PDSR_SZ, sre_sz = DEFAULT_SRE_SZ; + +/* Parse the property to extract the memory location and size and + * memblock_reserve() it. If it isn't supplied, memblock_alloc() the default size. */ +static __init int parse_mem_property(struct device_node *node, const char *name, + dma_addr_t *addr, size_t *sz, u64 align, int zero) +{ + const u32 *pint; + int ret; + + pint = of_get_property(node, name, &ret); + if (!pint || (ret != 16)) { + pr_info("pme: No %s property '%s', using memblock_alloc(0x%016zx)\n", + node->full_name, name, *sz); + *addr = memblock_alloc(*sz, align); + if (zero) + memset(phys_to_virt(*addr), 0, *sz); + return 0; + } + pr_info("pme: Using %s property '%s'\n", node->full_name, name); + /* If using a "zero-pma", don't try to zero it, even if you asked */ + if (zero && of_find_property(node, "zero-pma", &ret)) { + pr_info(" it's a 'zero-pma', not zeroing from s/w\n"); + zero = 0; + } + *addr = ((u64)pint[0] << 32) | (u64)pint[1]; + *sz = ((u64)pint[2] << 32) | (u64)pint[3]; + if((u64)*addr & (align - 1)) { + pr_err("pme: Invalid alignment, address %016llx\n",(u64)*addr); + return -EINVAL; + } + /* Keep things simple, it's either all in the DRAM range or it's all + * outside. */ + if (*addr < memblock_end_of_DRAM()) { + if ((u64)*addr + (u64)*sz > memblock_end_of_DRAM()){ + pr_err("pme: outside DRAM range\n"); + return -EINVAL; + } + if (memblock_reserve(*addr, *sz) < 0) { + pr_err("pme: Failed to reserve %s\n", name); + return -ENOMEM; + } + if (zero) + memset(phys_to_virt(*addr), 0, *sz); + } else if (zero) { + /* map as cacheable, non-guarded */ + void *tmpp = ioremap_prot(*addr, *sz, 0); + memset(tmpp, 0, *sz); + iounmap(tmpp); + } + return 0; +} + +/* No errors/interrupts. Physical addresses are assumed <= 32bits. */ +static int __init fsl_pme2_init(struct device_node *node) +{ + const char *s; + int ret = 0; + + s = of_get_property(node, "fsl,hv-claimable", &ret); + if (s && !strcmp(s, "standby")) { + pr_info(" -> in standby mode\n"); + return 0; + } + /* Check if pdsr memory already allocated */ + if (dxe_a) { + pr_err("pme: Error fsl_pme2_init already done\n"); + return -EINVAL; + } + ret = parse_mem_property(node, "fsl,pme-pdsr", &dxe_a, &dxe_sz, + PDSR_TBL_ALIGN, 0); + if (ret) + return ret; + ret = parse_mem_property(node, "fsl,pme-sre", &sre_a, &sre_sz, + SRE_TBL_ALIGN, 0); + return ret; +} + +__init void pme2_init_early(void) +{ + struct device_node *dn; + int ret; + for_each_compatible_node(dn, NULL, "fsl,pme") { + ret = fsl_pme2_init(dn); + if (ret) + pr_err("pme: Error fsl_pme2_init\n"); + } +} + +/************ + * Section 2 + *********** + * This code is called during driver initialisation. It doesn't do anything with + * the device-tree entries nor the PME device, it simply creates the sysfs stuff + * and gives the user something to hold. This could be made loadable, if there + * was any benefit to doing so - but as the device is already "bound" by static + * code, there's little point to hiding the fact. + */ + +MODULE_AUTHOR("Geoff Thorpe"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL PME2 (p4080) device control"); + +/* Opaque pointer target used to represent the PME CCSR map, ... */ +struct pme; + +/* ... and the instance of it. */ +static struct pme *global_pme; +static int pme_err_irq; + +static inline void __pme_out(struct pme *p, u32 offset, u32 val) +{ + u32 __iomem *regs = (void *)p; + out_be32(regs + (offset >> 2), val); +} +#define pme_out(p, r, v) __pme_out(p, PME_REG_##r, v) +static inline u32 __pme_in(struct pme *p, u32 offset) +{ + u32 __iomem *regs = (void *)p; + return in_be32(regs + (offset >> 2)); +} +#define pme_in(p, r) __pme_in(p, PME_REG_##r) + +#define PME_EFQC(en, fq) \ + ({ \ + /* Assume a default delay of 64 cycles */ \ + u8 __i419 = 0x1; \ + u32 __fq419 = (fq) & 0x00ffffff; \ + ((en) ? 0x80000000 : 0) | (__i419 << 28) | __fq419; \ + }) + +#define PME_FACONF_ENABLE 0x00000002 +#define PME_FACONF_RESET 0x00000001 + +/* pme stats accumulator work */ +static void accumulator_update(struct work_struct *work); +void accumulator_update_interval(u32 interval); +static DECLARE_DELAYED_WORK(accumulator_work, accumulator_update); +u32 pme_stat_interval = CONFIG_FSL_PME2_STAT_ACCUMULATOR_UPDATE_INTERVAL; +#define PME_SBE_ERR 0x01000000 +#define PME_DBE_ERR 0x00080000 +#define PME_PME_ERR 0x00000100 +#define PME_ALL_ERR (PME_SBE_ERR | PME_DBE_ERR | PME_PME_ERR) + +static struct of_device_id of_fsl_pme_ids[] = { + { + .compatible = "fsl,pme", + }, + {} +}; +MODULE_DEVICE_TABLE(of, of_fsl_pme_ids); + +/* Pme interrupt handler */ +static irqreturn_t pme_isr(int irq, void *ptr) +{ + static u32 last_isrstate; + u32 isrstate = pme_in(global_pme, ISR) ^ last_isrstate; + + /* What new ISR state has been raise */ + if (!isrstate) + return IRQ_NONE; + if (isrstate & PME_SBE_ERR) + pr_crit("PME: SBE detected\n"); + if (isrstate & PME_DBE_ERR) + pr_crit("PME: DBE detected\n"); + if (isrstate & PME_PME_ERR) + pr_crit("PME: PME serious detected\n"); + /* Clear the ier interrupt bit */ + last_isrstate |= isrstate; + pme_out(global_pme, IER, ~last_isrstate); + return IRQ_HANDLED; +} + +static int of_fsl_pme_remove(struct platform_device *ofdev) +{ + /* Cancel pme accumulator */ + accumulator_update_interval(0); + cancel_delayed_work_sync(&accumulator_work); + /* Disable PME..TODO need to wait till it's quiet */ + pme_out(global_pme, FACONF, PME_FACONF_RESET); + /* Release interrupt */ + if (likely(pme_err_irq != NO_IRQ)) + free_irq(pme_err_irq, &ofdev->dev); + /* Remove sysfs attribute */ + pme2_remove_sysfs_dev_files(ofdev); + /* Unmap controller region */ + iounmap(global_pme); + global_pme = NULL; + return 0; +} + +static int of_fsl_pme_probe(struct platform_device *ofdev) +{ + int ret, err = 0; + void __iomem *regs; + struct device *dev = &ofdev->dev; + struct device_node *nprop = dev->of_node; + u32 clkfreq = DEFAULT_SRFCC * 1000000; + const u32 *value; + const char *s; + int srec_aim = 0, srec_esr = 0; + u32 srecontextsize_code; + u32 dec1; + + /* TODO: This standby handling won't work properly after failover, it's + * just to allow bring up for now. */ + s = of_get_property(nprop, "fsl,hv-claimable", &ret); + if (s && !strcmp(s, "standby")) + return 0; + pme_err_irq = of_irq_to_resource(nprop, 0, NULL); + if (unlikely(pme_err_irq == NO_IRQ)) + dev_warn(dev, "Can't get %s property '%s'\n", nprop->full_name, + "interrupts"); + + /* Get configuration properties from device tree */ + /* First, get register page */ + regs = of_iomap(nprop, 0); + if (regs == NULL) { + dev_err(dev, "of_iomap() failed\n"); + err = -EINVAL; + goto out; + } + + /* Global configuration, leave pme disabled */ + global_pme = (struct pme *)regs; + pme_out(global_pme, FACONF, 0); + pme_out(global_pme, EFQC, PME_EFQC(0, 0)); + + /* TODO: these coherency settings for PMFA, DXE, and SRE force all + * transactions to snoop, as the kernel does not yet support flushing in + * dma_map_***() APIs (ie. h/w can not treat otherwise coherent memory + * in a non-coherent manner, temporarily or otherwise). When the kernel + * supports this, we should tune these settings back to; + * FAMCR = 0x00010001 + * DMCR = 0x00000000 + * SMCR = 0x00000000 + */ + /* PME HW rev 2.1: Added TWC field in FAMCR */ + pme_out(global_pme, FAMCR, 0x11010101); + pme_out(global_pme, DMCR, 0x00000001); + pme_out(global_pme, SMCR, 0x00000211); + + if (likely(pme_err_irq != NO_IRQ)) { + /* Register the pme ISR handler */ + err = request_irq(pme_err_irq, pme_isr, IRQF_SHARED, "pme-err", + dev); + if (err) { + dev_err(dev, "request_irq() failed\n"); + goto out_unmap_ctrl_region; + } + } + +#ifdef CONFIG_FSL_PME2_SRE_AIM + srec_aim = 1; +#endif +#ifdef CONFIG_FSL_PME2_SRE_ESR + srec_esr = 1; +#endif + /* Validate some parameters */ + if (!sre_session_ctx_size || !is_power_of_2(sre_session_ctx_size) || + (sre_session_ctx_size < 32) || + (sre_session_ctx_size > (131072))) { + dev_err(dev, "invalid sre_session_ctx_size\n"); + err = -EINVAL; + goto out_free_irq; + } + srecontextsize_code = ilog2(sre_session_ctx_size); + srecontextsize_code -= 4; + + /* Configure Clock Frequency */ + value = of_get_property(nprop, "clock-frequency", NULL); + if (value) + clkfreq = *value; + pme_out(global_pme, SFRCC, DIV_ROUND_UP(clkfreq, 1000000)); + + pme_out(global_pme, PDSRBAH, upper_32_bits(dxe_a)); + pme_out(global_pme, PDSRBAL, lower_32_bits(dxe_a)); + pme_out(global_pme, SCBARH, upper_32_bits(sre_a)); + pme_out(global_pme, SCBARL, lower_32_bits(sre_a)); + /* Maximum allocated index into the PDSR table available to the DXE + * Rev 2.0: Max 0xF_FFFC + * Rev 2.1: Max 0x7_FFFC + */ + if (PME_REV(pme_in(global_pme, PM_IP_REV1)) == PME_REV_2_0) { + if (((dxe_sz/PDSR_TBL_ALIGN)-1) > DEC1_MAX_REV_2_0) + dec1 = DEC1_MAX_REV_2_0; + else + dec1 = (dxe_sz/PDSR_TBL_ALIGN)-1; + } else { + if (((dxe_sz/PDSR_TBL_ALIGN)-1) > DEC1_MAX_REV_2_1) + dec1 = DEC1_MAX_REV_2_1; + else + dec1 = (dxe_sz/PDSR_TBL_ALIGN)-1; + } + pme_out(global_pme, DEC1, dec1); + /* Maximum allocated index into the PDSR table available to the SRE */ + pme_out(global_pme, SEC2, dec1); + /* Maximum allocated 32-byte offset into SRE Context Table.*/ + if (sre_sz) + pme_out(global_pme, SEC3, (sre_sz/SRE_TBL_ALIGN)-1); + /* Max test line execution */ + pme_out(global_pme, DEC0, max_test_line_per_pat); + pme_out(global_pme, DLC, + (max_pat_eval_per_sui << 16) | max_pat_matches_per_sui); + + /* SREC - SRE Config */ + pme_out(global_pme, SREC, + /* Number of rules in database */ + (sre_rule_num << 0) | + /* Simple Report Enabled */ + ((srec_esr ? 1 : 0) << 18) | + /* Context Size per Session */ + (srecontextsize_code << 19) | + /* Alternate Inclusive Mode */ + ((srec_aim ? 1 : 0) << 29)); + pme_out(global_pme, SEC1, + (CONFIG_FSL_PME2_SRE_MAX_INSTRUCTION_LIMIT << 16) | + CONFIG_FSL_PME2_SRE_MAX_BLOCK_NUMBER); + + /* Setup Accumulator */ + if (pme_stat_interval) + schedule_delayed_work(&accumulator_work, + msecs_to_jiffies(pme_stat_interval)); + /* Create sysfs entries */ + err = pme2_create_sysfs_dev_files(ofdev); + if (err) + goto out_stop_accumulator; + + /* Enable interrupts */ + pme_out(global_pme, IER, PME_ALL_ERR); + dev_info(dev, "ver: 0x%08x\n", pme_in(global_pme, PM_IP_REV1)); + + /* Enable pme */ + pme_out(global_pme, FACONF, PME_FACONF_ENABLE); + return 0; + +out_stop_accumulator: + if (pme_stat_interval) { + accumulator_update_interval(0); + cancel_delayed_work_sync(&accumulator_work); + } +out_free_irq: + if (likely(pme_err_irq != NO_IRQ)) + free_irq(pme_err_irq, &ofdev->dev); +out_unmap_ctrl_region: + pme_out(global_pme, FACONF, PME_FACONF_RESET); + iounmap(global_pme); + global_pme = NULL; +out: + return err; +} + +static struct platform_driver of_fsl_pme_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = of_fsl_pme_ids, + }, + .probe = of_fsl_pme_probe, + .remove = of_fsl_pme_remove, +}; + +static int pme2_ctrl_init(void) +{ + return platform_driver_register(&of_fsl_pme_driver); +} + +static void pme2_ctrl_exit(void) +{ + platform_driver_unregister(&of_fsl_pme_driver); +} + +module_init(pme2_ctrl_init); +module_exit(pme2_ctrl_exit); + +/************ + * Section 3 + ************ + * These APIs are the only functional hooks into the control driver, besides the + * sysfs attributes. + */ + +int pme2_have_control(void) +{ + return global_pme ? 1 : 0; +} +EXPORT_SYMBOL(pme2_have_control); + +int pme2_exclusive_set(struct qman_fq *fq) +{ + if (!pme2_have_control()) + return -ENODEV; + pme_out(global_pme, EFQC, PME_EFQC(1, qman_fq_fqid(fq))); + return 0; +} +EXPORT_SYMBOL(pme2_exclusive_set); + +int pme2_exclusive_unset(void) +{ + if (!pme2_have_control()) + return -ENODEV; + pme_out(global_pme, EFQC, PME_EFQC(0, 0)); + return 0; +} +EXPORT_SYMBOL(pme2_exclusive_unset); + +int pme_attr_set(enum pme_attr attr, u32 val) +{ + u32 mask; + u32 attr_val; + + if (!pme2_have_control()) + return -ENODEV; + + /* Check if Buffer size configuration */ + if (attr >= pme_attr_bsc_first && attr <= pme_attr_bsc_last) { + u32 bsc_pool_id = attr - pme_attr_bsc_first; + u32 bsc_pool_offset = bsc_pool_id % 8; + u32 bsc_pool_mask = ~(0xF << ((7-bsc_pool_offset)*4)); + /* range for val 0..0xB */ + if (val > 0xb) + return -EINVAL; + /* calculate which sky-blue reg */ + /* 0..7 -> bsc_(0..7), PME_REG_BSC0 */ + /* 8..15 -> bsc_(8..15) PME_REG_BSC1*/ + /* ... */ + /* 56..63 -> bsc_(56..63) PME_REG_BSC7*/ + attr_val = pme_in(global_pme, BSC0 + ((bsc_pool_id/8)*4)); + /* Now mask in the new value */ + attr_val = attr_val & bsc_pool_mask; + attr_val = attr_val | (val << ((7-bsc_pool_offset)*4)); + pme_out(global_pme, BSC0 + ((bsc_pool_id/8)*4), attr_val); + return 0; + } + + switch (attr) { + case pme_attr_efqc_int: + if (val > 4) + return -EINVAL; + mask = 0x8FFFFFFF; + attr_val = pme_in(global_pme, EFQC); + /* clear efqc_int */ + attr_val &= mask; + val <<= 28; + val |= attr_val; + pme_out(global_pme, EFQC, val); + break; + + case pme_attr_sw_db: + pme_out(global_pme, SWDB, val); + break; + + case pme_attr_dmcr: + pme_out(global_pme, DMCR, val); + break; + + case pme_attr_smcr: + pme_out(global_pme, SMCR, val); + break; + + case pme_attr_famcr: + pme_out(global_pme, FAMCR, val); + break; + + case pme_attr_kvlts: + if (val < 2 || val > 16) + return -EINVAL; + /* HW range: 1..15, SW range: 2..16 */ + pme_out(global_pme, KVLTS, --val); + break; + + case pme_attr_max_chain_length: + if (val > 0x7FFF) + val = 0x7FFF; + pme_out(global_pme, KEC, val); + break; + + case pme_attr_pattern_range_counter_idx: + if (val > 0x1FFFF) + val = 0x1FFFF; + pme_out(global_pme, DRCIC, val); + break; + + case pme_attr_pattern_range_counter_mask: + if (val > 0x1FFFF) + val = 0x1FFFF; + pme_out(global_pme, DRCMC, val); + break; + + case pme_attr_max_allowed_test_line_per_pattern: + if (val > 0x3FFF) + val = 0x3FFF; + pme_out(global_pme, DEC0, val); + break; + + case pme_attr_max_pattern_matches_per_sui: + /* mpe, mpm */ + if (val > 0xFFFF) + val = 0xFFFF; + mask = 0xFFFF0000; + attr_val = pme_in(global_pme, DLC); + /* clear mpm */ + attr_val &= mask; + val &= ~mask; + val |= attr_val; + pme_out(global_pme, DLC, val); + break; + + case pme_attr_max_pattern_evaluations_per_sui: + /* mpe, mpm */ + if (val > 0xFFFF) + val = 0xFFFF; + mask = 0x0000FFFF; + attr_val = pme_in(global_pme, DLC); + /* clear mpe */ + attr_val &= mask; + /* clear unwanted bits in val*/ + val &= mask; + val <<= 16; + val |= attr_val; + pme_out(global_pme, DLC, val); + break; + + case pme_attr_report_length_limit: + if (val > 0xFFFF) + val = 0xFFFF; + pme_out(global_pme, RLL, val); + break; + + case pme_attr_end_of_simple_sui_report: + /* bit 13 */ + mask = 0x00040000; + attr_val = pme_in(global_pme, SREC); + if (val) + attr_val |= mask; + else + attr_val &= ~mask; + pme_out(global_pme, SREC, attr_val); + break; + + case pme_attr_aim: + /* bit 2 */ + mask = 0x20000000; + attr_val = pme_in(global_pme, SREC); + if (val) + attr_val |= mask; + else + attr_val &= ~mask; + pme_out(global_pme, SREC, attr_val); + break; + + case pme_attr_end_of_sui_reaction_ptr: + if (val > 0xFFFFF) + val = 0xFFFFF; + pme_out(global_pme, ESRP, val); + break; + + case pme_attr_sre_pscl: + pme_out(global_pme, SFRCC, val); + break; + + case pme_attr_sre_max_block_num: + /* bits 17..31 */ + if (val > 0x7FFF) + val = 0x7FFF; + mask = 0xFFFF8000; + attr_val = pme_in(global_pme, SEC1); + /* clear mbn */ + attr_val &= mask; + /* clear unwanted bits in val*/ + val &= ~mask; + val |= attr_val; + pme_out(global_pme, SEC1, val); + break; + + case pme_attr_sre_max_instruction_limit: + /* bits 0..15 */ + if (val > 0xFFFF) + val = 0xFFFF; + mask = 0x0000FFFF; + attr_val = pme_in(global_pme, SEC1); + /* clear mil */ + attr_val &= mask; + /* clear unwanted bits in val*/ + val &= mask; + val <<= 16; + val |= attr_val; + pme_out(global_pme, SEC1, val); + break; + + case pme_attr_srrv0: + pme_out(global_pme, SRRV0, val); + break; + case pme_attr_srrv1: + pme_out(global_pme, SRRV1, val); + break; + case pme_attr_srrv2: + pme_out(global_pme, SRRV2, val); + break; + case pme_attr_srrv3: + pme_out(global_pme, SRRV3, val); + break; + case pme_attr_srrv4: + pme_out(global_pme, SRRV4, val); + break; + case pme_attr_srrv5: + pme_out(global_pme, SRRV5, val); + break; + case pme_attr_srrv6: + pme_out(global_pme, SRRV6, val); + break; + case pme_attr_srrv7: + pme_out(global_pme, SRRV7, val); + break; + case pme_attr_srrfi: + pme_out(global_pme, SRRFI, val); + break; + case pme_attr_srri: + pme_out(global_pme, SRRI, val); + break; + case pme_attr_srrwc: + pme_out(global_pme, SRRWC, val); + break; + case pme_attr_srrr: + pme_out(global_pme, SRRR, val); + break; + case pme_attr_tbt0ecc1th: + pme_out(global_pme, TBT0ECC1TH, val); + break; + case pme_attr_tbt1ecc1th: + pme_out(global_pme, TBT1ECC1TH, val); + break; + case pme_attr_vlt0ecc1th: + pme_out(global_pme, VLT0ECC1TH, val); + break; + case pme_attr_vlt1ecc1th: + pme_out(global_pme, VLT1ECC1TH, val); + break; + case pme_attr_cmecc1th: + pme_out(global_pme, CMECC1TH, val); + break; + case pme_attr_dxcmecc1th: + pme_out(global_pme, DXCMECC1TH, val); + break; + case pme_attr_dxemecc1th: + pme_out(global_pme, DXEMECC1TH, val); + break; + case pme_attr_esr: + pme_out(global_pme, ESR, val); + break; + case pme_attr_pehd: + pme_out(global_pme, PEHD, val); + break; + case pme_attr_ecc1bes: + pme_out(global_pme, ECC1BES, val); + break; + case pme_attr_ecc2bes: + pme_out(global_pme, ECC2BES, val); + break; + case pme_attr_miace: + pme_out(global_pme, MIA_CE, val); + break; + case pme_attr_miacr: + pme_out(global_pme, MIA_CR, val); + break; + case pme_attr_cdcr: + pme_out(global_pme, CDCR, val); + break; + case pme_attr_pmtr: + pme_out(global_pme, PMTR, val); + break; + + default: + pr_err("pme: Unknown attr %u\n", attr); + return -EINVAL; + }; + return 0; +} +EXPORT_SYMBOL(pme_attr_set); + +int pme_attr_get(enum pme_attr attr, u32 *val) +{ + u32 mask; + u32 attr_val; + + if (!pme2_have_control()) + return -ENODEV; + + /* Check if Buffer size configuration */ + if (attr >= pme_attr_bsc_first && attr <= pme_attr_bsc_last) { + u32 bsc_pool_id = attr - pme_attr_bsc_first; + u32 bsc_pool_offset = bsc_pool_id % 8; + /* calculate which sky-blue reg */ + /* 0..7 -> bsc_(0..7), PME_REG_BSC0 */ + /* 8..15 -> bsc_(8..15) PME_REG_BSC1*/ + /* ... */ + /* 56..63 -> bsc_(56..63) PME_REG_BSC7*/ + attr_val = pme_in(global_pme, BSC0 + ((bsc_pool_id/8)*4)); + attr_val = attr_val >> ((7-bsc_pool_offset)*4); + attr_val = attr_val & 0x0000000F; + *val = attr_val; + return 0; + } + + switch (attr) { + case pme_attr_efqc_int: + mask = 0x8FFFFFFF; + attr_val = pme_in(global_pme, EFQC); + attr_val &= ~mask; + attr_val >>= 28; + break; + + case pme_attr_sw_db: + attr_val = pme_in(global_pme, SWDB); + break; + + case pme_attr_dmcr: + attr_val = pme_in(global_pme, DMCR); + break; + + case pme_attr_smcr: + attr_val = pme_in(global_pme, SMCR); + break; + + case pme_attr_famcr: + attr_val = pme_in(global_pme, FAMCR); + break; + + case pme_attr_kvlts: + /* bit 28-31 */ + attr_val = pme_in(global_pme, KVLTS); + attr_val &= 0x0000000F; + /* HW range: 1..15, SW range: 2..16 */ + attr_val += 1; + break; + + case pme_attr_max_chain_length: + /* bit 17-31 */ + attr_val = pme_in(global_pme, KEC); + attr_val &= 0x00007FFF; + break; + + case pme_attr_pattern_range_counter_idx: + /* bit 15-31 */ + attr_val = pme_in(global_pme, DRCIC); + attr_val &= 0x0001FFFF; + break; + + case pme_attr_pattern_range_counter_mask: + /* bit 15-31 */ + attr_val = pme_in(global_pme, DRCMC); + attr_val &= 0x0001FFFF; + break; + + case pme_attr_max_allowed_test_line_per_pattern: + /* bit 18-31 */ + attr_val = pme_in(global_pme, DEC0); + attr_val &= 0x00003FFF; + break; + + case pme_attr_max_pdsr_index: + /* bit 12-31 */ + attr_val = pme_in(global_pme, DEC1); + attr_val &= 0x000FFFFF; + break; + + case pme_attr_max_pattern_matches_per_sui: + attr_val = pme_in(global_pme, DLC); + attr_val &= 0x0000FFFF; + break; + + case pme_attr_max_pattern_evaluations_per_sui: + attr_val = pme_in(global_pme, DLC); + attr_val >>= 16; + break; + + case pme_attr_report_length_limit: + attr_val = pme_in(global_pme, RLL); + /* clear unwanted bits in val*/ + attr_val &= 0x0000FFFF; + break; + + case pme_attr_end_of_simple_sui_report: + /* bit 13 */ + attr_val = pme_in(global_pme, SREC); + attr_val >>= 18; + /* clear unwanted bits in val*/ + attr_val &= 0x00000001; + break; + + case pme_attr_aim: + /* bit 2 */ + attr_val = pme_in(global_pme, SREC); + attr_val >>= 29; + /* clear unwanted bits in val*/ + attr_val &= 0x00000001; + break; + + case pme_attr_sre_context_size: + /* bits 9..12 */ + attr_val = pme_in(global_pme, SREC); + attr_val >>= 19; + /* clear unwanted bits in val*/ + attr_val &= 0x0000000F; + attr_val += 4; + attr_val = 1 << attr_val; + break; + + case pme_attr_sre_rule_num: + /* bits 24..31 */ + attr_val = pme_in(global_pme, SREC); + /* clear unwanted bits in val*/ + attr_val &= 0x000000FF; + /* Multiply by 256 */ + attr_val <<= 8; + break; + + case pme_attr_sre_session_ctx_num: { + u32 ctx_sz = 0; + /* = sre_table_size / sre_session_ctx_size */ + attr_val = pme_in(global_pme, SEC3); + /* clear unwanted bits in val*/ + attr_val &= 0x07FFFFFF; + attr_val += 1; + attr_val *= 32; + ctx_sz = pme_in(global_pme, SREC); + ctx_sz >>= 19; + /* clear unwanted bits in val*/ + ctx_sz &= 0x0000000F; + ctx_sz += 4; + attr_val /= (1 << ctx_sz); + } + break; + + case pme_attr_end_of_sui_reaction_ptr: + /* bits 12..31 */ + attr_val = pme_in(global_pme, ESRP); + /* clear unwanted bits in val*/ + attr_val &= 0x000FFFFF; + break; + + case pme_attr_sre_pscl: + /* bits 22..31 */ + attr_val = pme_in(global_pme, SFRCC); + break; + + case pme_attr_sre_max_block_num: + /* bits 17..31 */ + attr_val = pme_in(global_pme, SEC1); + /* clear unwanted bits in val*/ + attr_val &= 0x00007FFF; + break; + + case pme_attr_sre_max_instruction_limit: + /* bits 0..15 */ + attr_val = pme_in(global_pme, SEC1); + attr_val >>= 16; + break; + + case pme_attr_sre_max_index_size: + /* bits 12..31 */ + attr_val = pme_in(global_pme, SEC2); + /* clear unwanted bits in val*/ + attr_val &= 0x000FFFFF; + break; + + case pme_attr_sre_max_offset_ctrl: + /* bits 5..31 */ + attr_val = pme_in(global_pme, SEC3); + /* clear unwanted bits in val*/ + attr_val &= 0x07FFFFFF; + break; + + case pme_attr_src_id: + /* bits 24..31 */ + attr_val = pme_in(global_pme, SRCIDR); + /* clear unwanted bits in val*/ + attr_val &= 0x000000FF; + break; + + case pme_attr_liodnr: + /* bits 20..31 */ + attr_val = pme_in(global_pme, LIODNR); + /* clear unwanted bits in val*/ + attr_val &= 0x00000FFF; + break; + + case pme_attr_rev1: + /* bits 0..31 */ + attr_val = pme_in(global_pme, PM_IP_REV1); + break; + + case pme_attr_rev2: + /* bits 0..31 */ + attr_val = pme_in(global_pme, PM_IP_REV2); + break; + + case pme_attr_srrr: + attr_val = pme_in(global_pme, SRRR); + break; + + case pme_attr_trunci: + attr_val = pme_in(global_pme, TRUNCI); + break; + + case pme_attr_rbc: + attr_val = pme_in(global_pme, RBC); + break; + + case pme_attr_tbt0ecc1ec: + attr_val = pme_in(global_pme, TBT0ECC1EC); + break; + + case pme_attr_tbt1ecc1ec: + attr_val = pme_in(global_pme, TBT1ECC1EC); + break; + + case pme_attr_vlt0ecc1ec: + attr_val = pme_in(global_pme, VLT0ECC1EC); + break; + + case pme_attr_vlt1ecc1ec: + attr_val = pme_in(global_pme, VLT1ECC1EC); + break; + + case pme_attr_cmecc1ec: + attr_val = pme_in(global_pme, CMECC1EC); + break; + + case pme_attr_dxcmecc1ec: + attr_val = pme_in(global_pme, DXCMECC1EC); + break; + + case pme_attr_dxemecc1ec: + attr_val = pme_in(global_pme, DXEMECC1EC); + break; + + case pme_attr_tbt0ecc1th: + attr_val = pme_in(global_pme, TBT0ECC1TH); + break; + + case pme_attr_tbt1ecc1th: + attr_val = pme_in(global_pme, TBT1ECC1TH); + break; + + case pme_attr_vlt0ecc1th: + attr_val = pme_in(global_pme, VLT0ECC1TH); + break; + + case pme_attr_vlt1ecc1th: + attr_val = pme_in(global_pme, VLT1ECC1TH); + break; + + case pme_attr_cmecc1th: + attr_val = pme_in(global_pme, CMECC1TH); + break; + + case pme_attr_dxcmecc1th: + attr_val = pme_in(global_pme, DXCMECC1TH); + break; + + case pme_attr_dxemecc1th: + attr_val = pme_in(global_pme, DXEMECC1TH); + break; + + case pme_attr_stnib: + attr_val = pme_in(global_pme, STNIB); + break; + + case pme_attr_stnis: + attr_val = pme_in(global_pme, STNIS); + break; + + case pme_attr_stnth1: + attr_val = pme_in(global_pme, STNTH1); + break; + + case pme_attr_stnth2: + attr_val = pme_in(global_pme, STNTH2); + break; + + case pme_attr_stnthv: + attr_val = pme_in(global_pme, STNTHV); + break; + + case pme_attr_stnths: + attr_val = pme_in(global_pme, STNTHS); + break; + + case pme_attr_stnch: + attr_val = pme_in(global_pme, STNCH); + break; + + case pme_attr_stnpm: + attr_val = pme_in(global_pme, STNPM); + break; + + case pme_attr_stns1m: + attr_val = pme_in(global_pme, STNS1M); + break; + + case pme_attr_stnpmr: + attr_val = pme_in(global_pme, STNPMR); + break; + + case pme_attr_stndsr: + attr_val = pme_in(global_pme, STNDSR); + break; + + case pme_attr_stnesr: + attr_val = pme_in(global_pme, STNESR); + break; + + case pme_attr_stns1r: + attr_val = pme_in(global_pme, STNS1R); + break; + + case pme_attr_stnob: + attr_val = pme_in(global_pme, STNOB); + break; + + case pme_attr_mia_byc: + attr_val = pme_in(global_pme, MIA_BYC); + break; + + case pme_attr_mia_blc: + attr_val = pme_in(global_pme, MIA_BLC); + break; + + case pme_attr_isr: + attr_val = pme_in(global_pme, ISR); + break; + + case pme_attr_ecr0: + attr_val = pme_in(global_pme, ECR0); + break; + + case pme_attr_ecr1: + attr_val = pme_in(global_pme, ECR1); + break; + + case pme_attr_esr: + attr_val = pme_in(global_pme, ESR); + break; + + case pme_attr_pmstat: + attr_val = pme_in(global_pme, PMSTAT); + break; + + case pme_attr_pehd: + attr_val = pme_in(global_pme, PEHD); + break; + + case pme_attr_ecc1bes: + attr_val = pme_in(global_pme, ECC1BES); + break; + + case pme_attr_ecc2bes: + attr_val = pme_in(global_pme, ECC2BES); + break; + + case pme_attr_eccaddr: + attr_val = pme_in(global_pme, ECCADDR); + break; + + case pme_attr_ecccode: + attr_val = pme_in(global_pme, ECCCODE); + break; + + case pme_attr_miace: + attr_val = pme_in(global_pme, MIA_CE); + break; + + case pme_attr_miacr: + attr_val = pme_in(global_pme, MIA_CR); + break; + + case pme_attr_cdcr: + attr_val = pme_in(global_pme, CDCR); + break; + + case pme_attr_pmtr: + attr_val = pme_in(global_pme, PMTR); + break; + + case pme_attr_faconf: + attr_val = pme_in(global_pme, FACONF); + break; + + case pme_attr_pdsrbah: + attr_val = pme_in(global_pme, PDSRBAH); + break; + + case pme_attr_pdsrbal: + attr_val = pme_in(global_pme, PDSRBAL); + break; + + case pme_attr_scbarh: + attr_val = pme_in(global_pme, SCBARH); + break; + + case pme_attr_scbarl: + attr_val = pme_in(global_pme, SCBARL); + break; + + case pme_attr_srrv0: + attr_val = pme_in(global_pme, SRRV0); + break; + + case pme_attr_srrv1: + attr_val = pme_in(global_pme, SRRV1); + break; + + case pme_attr_srrv2: + attr_val = pme_in(global_pme, SRRV2); + break; + + case pme_attr_srrv3: + attr_val = pme_in(global_pme, SRRV3); + break; + + case pme_attr_srrv4: + attr_val = pme_in(global_pme, SRRV4); + break; + + case pme_attr_srrv5: + attr_val = pme_in(global_pme, SRRV5); + break; + + case pme_attr_srrv6: + attr_val = pme_in(global_pme, SRRV6); + break; + + case pme_attr_srrv7: + attr_val = pme_in(global_pme, SRRV7); + break; + + case pme_attr_srrfi: + attr_val = pme_in(global_pme, SRRFI); + break; + + case pme_attr_srri: + attr_val = pme_in(global_pme, SRRI); + break; + + case pme_attr_srrwc: + attr_val = pme_in(global_pme, SRRWC); + break; + + default: + pr_err("pme: Unknown attr %u\n", attr); + return -EINVAL; + }; + *val = attr_val; + return 0; +} +EXPORT_SYMBOL(pme_attr_get); + +static enum pme_attr stat_list[] = { + pme_attr_trunci, + pme_attr_rbc, + pme_attr_tbt0ecc1ec, + pme_attr_tbt1ecc1ec, + pme_attr_vlt0ecc1ec, + pme_attr_vlt1ecc1ec, + pme_attr_cmecc1ec, + pme_attr_dxcmecc1ec, + pme_attr_dxemecc1ec, + pme_attr_stnib, + pme_attr_stnis, + pme_attr_stnth1, + pme_attr_stnth2, + pme_attr_stnthv, + pme_attr_stnths, + pme_attr_stnch, + pme_attr_stnpm, + pme_attr_stns1m, + pme_attr_stnpmr, + pme_attr_stndsr, + pme_attr_stnesr, + pme_attr_stns1r, + pme_attr_stnob, + pme_attr_mia_byc, + pme_attr_mia_blc +}; + +static u64 pme_stats[sizeof(stat_list)/sizeof(enum pme_attr)]; +static DEFINE_SPINLOCK(stat_lock); + +int pme_stat_get(enum pme_attr stat, u64 *value, int reset) +{ + int i, ret = 0; + int value_set = 0; + u32 val; + + spin_lock_irq(&stat_lock); + for (i = 0; i < sizeof(stat_list)/sizeof(enum pme_attr); i++) { + if (stat_list[i] == stat) { + ret = pme_attr_get(stat_list[i], &val); + /* Do I need to check ret */ + pme_stats[i] += val; + *value = pme_stats[i]; + value_set = 1; + if (reset) + pme_stats[i] = 0; + break; + } + } + if (!value_set) { + pr_err("pme: Invalid stat request %d\n", stat); + ret = -EINVAL; + } + spin_unlock_irq(&stat_lock); + return ret; +} +EXPORT_SYMBOL(pme_stat_get); + +void accumulator_update_interval(u32 interval) +{ + int schedule = 0; + + spin_lock_irq(&stat_lock); + if (!pme_stat_interval && interval) + schedule = 1; + pme_stat_interval = interval; + spin_unlock_irq(&stat_lock); + if (schedule) + schedule_delayed_work(&accumulator_work, + msecs_to_jiffies(interval)); +} + +static void accumulator_update(struct work_struct *work) +{ + int i, ret; + u32 local_interval; + u32 val; + + spin_lock_irq(&stat_lock); + local_interval = pme_stat_interval; + for (i = 0; i < sizeof(stat_list)/sizeof(enum pme_attr); i++) { + ret = pme_attr_get(stat_list[i], &val); + pme_stats[i] += val; + } + spin_unlock_irq(&stat_lock); + if (local_interval) + schedule_delayed_work(&accumulator_work, + msecs_to_jiffies(local_interval)); +} + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_sys.h +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_sys.h @@ -0,0 +1,64 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int pme2_create_sysfs_dev_files(struct platform_device *ofdev); +void pme2_remove_sysfs_dev_files(struct platform_device *ofdev); +void accumulator_update_interval(u32 interval); + --- linux-3.13.0.orig/drivers/staging/fsl_pme2/pme2_sysfs.c +++ linux-3.13.0/drivers/staging/fsl_pme2/pme2_sysfs.c @@ -0,0 +1,565 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "pme2_regs.h" +#include "pme2_private.h" + +#define MAX_ACCUMULATOR_INTERVAL 10000 +extern u32 pme_stat_interval; + +/* The pme sysfs contains the following types of attributes + * 1) root level: general pme confuration + * 2) bsc: bufferpool size configuration + * 3) stats: pme statistics + */ +static ssize_t pme_store(struct device *dev, struct device_attribute *dev_attr, + const char *buf, size_t count, enum pme_attr attr) +{ + unsigned long val; + size_t ret; + if (strict_strtoul(buf, 0, &val)) { + dev_dbg(dev, "invalid input %s\n",buf); + return -EINVAL; + } + ret = pme_attr_set(attr, val); + if (ret) { + dev_err(dev, "attr_set err attr=%u, val=%lu\n", attr, val); + return ret; + } + return count; +} + +static ssize_t pme_show(struct device *dev, struct device_attribute *dev_attr, + char *buf, enum pme_attr attr, const char *fmt) +{ + u32 data; + int ret; + + ret = pme_attr_get(attr, &data); + if (!ret) + return snprintf(buf, PAGE_SIZE, fmt, data); + return ret; +} + + +static ssize_t pme_stat_show(struct device *dev, + struct device_attribute *dev_attr, char *buf, enum pme_attr attr) +{ + u64 data = 0; + int ret = 0; + + ret = pme_stat_get(attr, &data, 0); + if (!ret) + return snprintf(buf, PAGE_SIZE, "%llu\n", data); + else + return ret; +} + +static ssize_t pme_stat_store(struct device *dev, + struct device_attribute *dev_attr, const char *buf, + size_t count, enum pme_attr attr) +{ + unsigned long val; + u64 data = 0; + size_t ret = 0; + if (strict_strtoul(buf, 0, &val)) { + pr_err("pme: invalid input %s\n", buf); + return -EINVAL; + } + if (val) { + pr_err("pme: invalid input %s\n", buf); + return -EINVAL; + } + ret = pme_stat_get(attr, &data, 1); + return count; +} + + +#define PME_SYSFS_ATTR(pme_attr, perm, showhex) \ +static ssize_t pme_store_##pme_attr(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return pme_store(dev, attr, buf, count, pme_attr_##pme_attr);\ +} \ +static ssize_t pme_show_##pme_attr(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + return pme_show(dev, attr, buf, pme_attr_##pme_attr, showhex);\ +} \ +static DEVICE_ATTR( pme_attr, perm, pme_show_##pme_attr, pme_store_##pme_attr); + + +#define PME_SYSFS_STAT_ATTR(pme_attr, perm) \ +static ssize_t pme_store_##pme_attr(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return pme_stat_store(dev, attr, buf, count, pme_attr_##pme_attr);\ +} \ +static ssize_t pme_show_##pme_attr(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + return pme_stat_show(dev, attr, buf, pme_attr_##pme_attr);\ +} \ +static DEVICE_ATTR(pme_attr, perm, pme_show_##pme_attr, pme_store_##pme_attr); + + +#define PME_SYSFS_BSC_ATTR(bsc_id, perm, showhex) \ +static ssize_t pme_store_bsc_##bsc_id(struct device *dev,\ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return pme_store(dev, attr, buf, count, pme_attr_bsc(bsc_id));\ +} \ +static ssize_t pme_show_bsc_##bsc_id(struct device *dev,\ + struct device_attribute *attr, char *buf) \ +{ \ + return pme_show(dev, attr, buf, pme_attr_bsc(bsc_id), showhex);\ +} \ +static DEVICE_ATTR(bsc_id, perm, pme_show_bsc_##bsc_id, \ + pme_store_bsc_##bsc_id); + +/* Statistics Ctrl: update interval */ +static ssize_t pme_store_update_interval(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + + if (!pme2_have_control()) { + PMEPRERR("not on ctrl-plane\n"); + return -ENODEV; + } + if (strict_strtoul(buf, 0, &val)) { + dev_info(dev, "invalid input %s\n", buf); + return -EINVAL; + } + if (val > MAX_ACCUMULATOR_INTERVAL) { + dev_info(dev, "invalid input %s\n", buf); + return -ERANGE; + } + accumulator_update_interval(val); + return count; +} +static ssize_t pme_show_update_interval(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!pme2_have_control()) + return -ENODEV; + return snprintf(buf, PAGE_SIZE, "%u\n", pme_stat_interval); +} + +#define FMT_0HEX "0x%08x\n" +#define FMT_HEX "0x%x\n" +#define FMT_DEC "%u\n" +#define PRIV_RO S_IRUSR +#define PRIV_RW (S_IRUSR | S_IWUSR) + +/* Register Interfaces */ +/* read-write; */ +PME_SYSFS_ATTR(efqc_int, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(sw_db, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(dmcr, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(smcr, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(famcr, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(kvlts, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(max_chain_length, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(pattern_range_counter_idx, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(pattern_range_counter_mask, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(max_allowed_test_line_per_pattern, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(max_pattern_matches_per_sui, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(max_pattern_evaluations_per_sui, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(report_length_limit, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(end_of_simple_sui_report, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(aim, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(end_of_sui_reaction_ptr, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(sre_pscl, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(sre_max_block_num, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(sre_max_instruction_limit, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(esr, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(pehd, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(ecc1bes, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(ecc2bes, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(miace, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(miacr, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(cdcr, PRIV_RW, FMT_0HEX); +PME_SYSFS_ATTR(pmtr, PRIV_RW, FMT_DEC); + +/* read-only; */ +PME_SYSFS_ATTR(max_pdsr_index, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(sre_context_size, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(sre_rule_num, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(sre_session_ctx_num, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(sre_max_index_size, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(sre_max_offset_ctrl, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(src_id, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(liodnr, PRIV_RO, FMT_DEC); +PME_SYSFS_ATTR(rev1, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(rev2, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(isr, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(ecr0, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(ecr1, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(pmstat, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(eccaddr, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(ecccode, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(faconf, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(pdsrbah, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(pdsrbal, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(scbarh, PRIV_RO, FMT_0HEX); +PME_SYSFS_ATTR(scbarl, PRIV_RO, FMT_0HEX); + + +/* Buffer Pool Size Configuration */ +PME_SYSFS_BSC_ATTR(0, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(1, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(2, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(3, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(4, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(5, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(6, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(7, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(8, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(9, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(10, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(11, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(12, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(13, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(14, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(15, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(16, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(17, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(18, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(19, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(20, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(21, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(22, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(23, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(24, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(25, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(26, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(27, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(28, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(29, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(30, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(31, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(32, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(33, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(34, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(35, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(36, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(37, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(38, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(39, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(40, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(41, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(42, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(43, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(44, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(45, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(46, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(47, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(48, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(49, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(50, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(51, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(52, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(53, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(54, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(55, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(56, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(57, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(58, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(59, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(60, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(61, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(62, PRIV_RW, FMT_DEC); +PME_SYSFS_BSC_ATTR(63, PRIV_RW, FMT_DEC); + +/* Stats Counters*/ +PME_SYSFS_STAT_ATTR(trunci, PRIV_RW); +PME_SYSFS_STAT_ATTR(rbc, PRIV_RW); +PME_SYSFS_STAT_ATTR(tbt0ecc1ec, PRIV_RW); +PME_SYSFS_STAT_ATTR(tbt1ecc1ec, PRIV_RW); +PME_SYSFS_STAT_ATTR(vlt0ecc1ec, PRIV_RW); +PME_SYSFS_STAT_ATTR(vlt1ecc1ec, PRIV_RW); +PME_SYSFS_STAT_ATTR(cmecc1ec, PRIV_RW); +PME_SYSFS_STAT_ATTR(dxcmecc1ec, PRIV_RW); +PME_SYSFS_STAT_ATTR(dxemecc1ec, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnib, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnis, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnth1, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnth2, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnthv, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnths, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnch, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnpm, PRIV_RW); +PME_SYSFS_STAT_ATTR(stns1m, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnpmr, PRIV_RW); +PME_SYSFS_STAT_ATTR(stndsr, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnesr, PRIV_RW); +PME_SYSFS_STAT_ATTR(stns1r, PRIV_RW); +PME_SYSFS_STAT_ATTR(stnob, PRIV_RW); +PME_SYSFS_STAT_ATTR(mia_byc, PRIV_RW); +PME_SYSFS_STAT_ATTR(mia_blc, PRIV_RW); + +/* Stats Control */ +PME_SYSFS_ATTR(tbt0ecc1th, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(tbt1ecc1th, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(vlt0ecc1th, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(vlt1ecc1th, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(cmecc1th, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(dxcmecc1th, PRIV_RW, FMT_DEC); +PME_SYSFS_ATTR(dxemecc1th, PRIV_RW, FMT_DEC); + +static DEVICE_ATTR(update_interval, (S_IRUSR | S_IWUSR), + pme_show_update_interval, pme_store_update_interval); + +static struct attribute *pme_dev_bsc_attributes[] = { + &dev_attr_0.attr, + &dev_attr_1.attr, + &dev_attr_2.attr, + &dev_attr_3.attr, + &dev_attr_4.attr, + &dev_attr_5.attr, + &dev_attr_6.attr, + &dev_attr_7.attr, + &dev_attr_8.attr, + &dev_attr_9.attr, + &dev_attr_10.attr, + &dev_attr_11.attr, + &dev_attr_12.attr, + &dev_attr_13.attr, + &dev_attr_14.attr, + &dev_attr_15.attr, + &dev_attr_16.attr, + &dev_attr_17.attr, + &dev_attr_18.attr, + &dev_attr_19.attr, + &dev_attr_20.attr, + &dev_attr_21.attr, + &dev_attr_22.attr, + &dev_attr_23.attr, + &dev_attr_24.attr, + &dev_attr_25.attr, + &dev_attr_26.attr, + &dev_attr_27.attr, + &dev_attr_28.attr, + &dev_attr_29.attr, + &dev_attr_30.attr, + &dev_attr_31.attr, + &dev_attr_32.attr, + &dev_attr_33.attr, + &dev_attr_34.attr, + &dev_attr_35.attr, + &dev_attr_36.attr, + &dev_attr_37.attr, + &dev_attr_38.attr, + &dev_attr_39.attr, + &dev_attr_40.attr, + &dev_attr_41.attr, + &dev_attr_42.attr, + &dev_attr_43.attr, + &dev_attr_44.attr, + &dev_attr_45.attr, + &dev_attr_46.attr, + &dev_attr_47.attr, + &dev_attr_48.attr, + &dev_attr_49.attr, + &dev_attr_50.attr, + &dev_attr_51.attr, + &dev_attr_52.attr, + &dev_attr_53.attr, + &dev_attr_54.attr, + &dev_attr_55.attr, + &dev_attr_56.attr, + &dev_attr_57.attr, + &dev_attr_58.attr, + &dev_attr_59.attr, + &dev_attr_60.attr, + &dev_attr_61.attr, + &dev_attr_62.attr, + &dev_attr_63.attr, + NULL +}; + +static struct attribute *pme_dev_attributes[] = { + &dev_attr_efqc_int.attr, + &dev_attr_sw_db.attr, + &dev_attr_dmcr.attr, + &dev_attr_smcr.attr, + &dev_attr_famcr.attr, + &dev_attr_kvlts.attr, + &dev_attr_max_chain_length.attr, + &dev_attr_pattern_range_counter_idx.attr, + &dev_attr_pattern_range_counter_mask.attr, + &dev_attr_max_allowed_test_line_per_pattern.attr, + &dev_attr_max_pdsr_index.attr, + &dev_attr_max_pattern_matches_per_sui.attr, + &dev_attr_max_pattern_evaluations_per_sui.attr, + &dev_attr_report_length_limit.attr, + &dev_attr_end_of_simple_sui_report.attr, + &dev_attr_aim.attr, + &dev_attr_sre_context_size.attr, + &dev_attr_sre_rule_num.attr, + &dev_attr_sre_session_ctx_num.attr, + &dev_attr_end_of_sui_reaction_ptr.attr, + &dev_attr_sre_pscl.attr, + &dev_attr_sre_max_block_num.attr, + &dev_attr_sre_max_instruction_limit.attr, + &dev_attr_sre_max_index_size.attr, + &dev_attr_sre_max_offset_ctrl.attr, + &dev_attr_src_id.attr, + &dev_attr_liodnr.attr, + &dev_attr_rev1.attr, + &dev_attr_rev2.attr, + &dev_attr_isr.attr, + &dev_attr_ecr0.attr, + &dev_attr_ecr1.attr, + &dev_attr_esr.attr, + &dev_attr_pmstat.attr, + &dev_attr_pehd.attr, + &dev_attr_ecc1bes.attr, + &dev_attr_ecc2bes.attr, + &dev_attr_eccaddr.attr, + &dev_attr_ecccode.attr, + &dev_attr_miace.attr, + &dev_attr_miacr.attr, + &dev_attr_cdcr.attr, + &dev_attr_pmtr.attr, + &dev_attr_faconf.attr, + &dev_attr_pdsrbah.attr, + &dev_attr_pdsrbal.attr, + &dev_attr_scbarh.attr, + &dev_attr_scbarl.attr, + NULL +}; + +static struct attribute *pme_dev_stats_counter_attributes[] = { + &dev_attr_trunci.attr, + &dev_attr_rbc.attr, + &dev_attr_tbt0ecc1ec.attr, + &dev_attr_tbt1ecc1ec.attr, + &dev_attr_vlt0ecc1ec.attr, + &dev_attr_vlt1ecc1ec.attr, + &dev_attr_cmecc1ec.attr, + &dev_attr_dxcmecc1ec.attr, + &dev_attr_dxemecc1ec.attr, + &dev_attr_stnib.attr, + &dev_attr_stnis.attr, + &dev_attr_stnth1.attr, + &dev_attr_stnth2.attr, + &dev_attr_stnthv.attr, + &dev_attr_stnths.attr, + &dev_attr_stnch.attr, + &dev_attr_stnpm.attr, + &dev_attr_stns1m.attr, + &dev_attr_stnpmr.attr, + &dev_attr_stndsr.attr, + &dev_attr_stnesr.attr, + &dev_attr_stns1r.attr, + &dev_attr_stnob.attr, + &dev_attr_mia_byc.attr, + &dev_attr_mia_blc.attr, + NULL +}; + +static struct attribute *pme_dev_stats_ctrl_attributes[] = { + &dev_attr_update_interval.attr, + &dev_attr_tbt0ecc1th.attr, + &dev_attr_tbt1ecc1th.attr, + &dev_attr_vlt0ecc1th.attr, + &dev_attr_vlt1ecc1th.attr, + &dev_attr_cmecc1th.attr, + &dev_attr_dxcmecc1th.attr, + &dev_attr_dxemecc1th.attr, + NULL +}; + +/* root level */ +static const struct attribute_group pme_dev_attr_grp = { + .name = NULL, /* put in device directory */ + .attrs = pme_dev_attributes +}; + +/* root/bsc */ +static struct attribute_group pme_dev_bsc_attr_grp = { + .name = "bsc", + .attrs = pme_dev_bsc_attributes +}; + +/* root/stats */ +static struct attribute_group pme_dev_stats_counters_attr_grp = { + .name = "stats", + .attrs = pme_dev_stats_counter_attributes +}; + +/* root/stats_ctrl */ +static struct attribute_group pme_dev_stats_ctrl_attr_grp = { + .name = "stats_ctrl", + .attrs = pme_dev_stats_ctrl_attributes +}; + + +int pme2_create_sysfs_dev_files(struct platform_device *ofdev) +{ + int ret; + + ret = sysfs_create_group(&ofdev->dev.kobj, &pme_dev_attr_grp); + if (ret) + goto done; + ret = sysfs_create_group(&ofdev->dev.kobj, &pme_dev_bsc_attr_grp); + if (ret) + goto del_group_1; + ret = sysfs_create_group(&ofdev->dev.kobj, &pme_dev_stats_counters_attr_grp); + if (ret) + goto del_group_2; + ret = sysfs_create_group(&ofdev->dev.kobj, &pme_dev_stats_ctrl_attr_grp); + if (ret) + goto del_group_3; + goto done; +del_group_3: + sysfs_remove_group(&ofdev->dev.kobj, &pme_dev_stats_counters_attr_grp); +del_group_2: + sysfs_remove_group(&ofdev->dev.kobj, &pme_dev_bsc_attr_grp); +del_group_1: + sysfs_remove_group(&ofdev->dev.kobj, &pme_dev_attr_grp); +done: + if (ret) + dev_err(&ofdev->dev, + "Cannot create dev attributes ret=%d\n", ret); + return ret; +} + +void pme2_remove_sysfs_dev_files(struct platform_device *ofdev) +{ + sysfs_remove_group(&ofdev->dev.kobj, &pme_dev_stats_ctrl_attr_grp); + sysfs_remove_group(&ofdev->dev.kobj, &pme_dev_stats_counters_attr_grp); + sysfs_remove_group(&ofdev->dev.kobj, &pme_dev_bsc_attr_grp); + sysfs_remove_group(&ofdev->dev.kobj, &pme_dev_attr_grp); +} + + --- linux-3.13.0.orig/drivers/staging/lustre/lustre/llite/dir.c +++ linux-3.13.0/drivers/staging/lustre/lustre/llite/dir.c @@ -1086,7 +1086,7 @@ break; case Q_GETQUOTA: if (((type == USRQUOTA && - uid_eq(current_euid(), make_kuid(&init_user_ns, id))) || + !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) || (type == GRPQUOTA && !in_egroup_p(make_kgid(&init_user_ns, id)))) && (!cfs_capable(CFS_CAP_SYS_ADMIN) || --- linux-3.13.0.orig/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ linux-3.13.0/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -179,7 +179,7 @@ LNET_UNLINK, LNET_INS_AFTER, &me_h); if (rc != 0) { CERROR("%s: LNetMEAttach failed x"LPU64"/%d: rc = %d\n", - desc->bd_export->exp_obd->obd_name, xid, + desc->bd_import->imp_obd->obd_name, xid, posted_md, rc); break; } @@ -189,7 +189,7 @@ &desc->bd_mds[posted_md]); if (rc != 0) { CERROR("%s: LNetMDAttach failed x"LPU64"/%d: rc = %d\n", - desc->bd_export->exp_obd->obd_name, xid, + desc->bd_import->imp_obd->obd_name, xid, posted_md, rc); rc2 = LNetMEUnlink(me_h); LASSERT(rc2 == 0); @@ -219,7 +219,7 @@ /* Holler if peer manages to touch buffers before he knows the xid */ if (desc->bd_md_count != total_md) CWARN("%s: Peer %s touched %d buffers while I registered\n", - desc->bd_export->exp_obd->obd_name, libcfs_id2str(peer), + desc->bd_import->imp_obd->obd_name, libcfs_id2str(peer), total_md - desc->bd_md_count); spin_unlock(&desc->bd_lock); --- linux-3.13.0.orig/drivers/staging/comedi/comedi_fops.c +++ linux-3.13.0/drivers/staging/comedi/comedi_fops.c @@ -1425,6 +1425,7 @@ async->cmd.chanlist_len * sizeof(int)); if (IS_ERR(async->cmd.chanlist)) { ret = PTR_ERR(async->cmd.chanlist); + async->cmd.chanlist = NULL; DPRINTK("memdup_user failed with code %d\n", ret); goto cleanup; } @@ -1547,6 +1548,7 @@ cmd.chanlist_len * sizeof(int)); if (IS_ERR(chanlist)) { ret = PTR_ERR(chanlist); + chanlist = NULL; DPRINTK("memdup_user exited with code %d", ret); goto cleanup; } --- linux-3.13.0.orig/drivers/staging/comedi/drivers/adv_pci1710.c +++ linux-3.13.0/drivers/staging/comedi/drivers/adv_pci1710.c @@ -489,6 +489,7 @@ struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, chan, range, ofs; chan = CR_CHAN(insn->chanspec); @@ -504,11 +505,14 @@ outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); ofs = PCI171x_DA1; } + val = devpriv->ao_data[chan]; - for (n = 0; n < insn->n; n++) - outw(data[n], dev->iobase + ofs); + for (n = 0; n < insn->n; n++) { + val = data[n]; + outw(val, dev->iobase + ofs); + } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; @@ -674,6 +678,7 @@ struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, rangereg, chan; chan = CR_CHAN(insn->chanspec); @@ -683,13 +688,15 @@ outb(rangereg, dev->iobase + PCI1720_RANGE); devpriv->da_ranges = rangereg; } + val = devpriv->ao_data[chan]; for (n = 0; n < insn->n; n++) { - outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1)); + val = data[n]; + outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; } --- linux-3.13.0.orig/drivers/staging/comedi/drivers/adl_pci9111.c +++ linux-3.13.0/drivers/staging/comedi/drivers/adl_pci9111.c @@ -859,7 +859,7 @@ pci9111_reset(dev); if (pcidev->irq > 0) { - ret = request_irq(dev->irq, pci9111_interrupt, + ret = request_irq(pcidev->irq, pci9111_interrupt, IRQF_SHARED, dev->board_name, dev); if (ret) return ret; --- linux-3.13.0.orig/drivers/staging/comedi/drivers/addi_apci_1032.c +++ linux-3.13.0/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -325,8 +325,8 @@ s = &dev->subdevices[1]; if (dev->irq) { dev->read_subdev = s; - s->type = COMEDI_SUBD_DI | SDF_CMD_READ; - s->subdev_flags = SDF_READABLE; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; s->n_chan = 1; s->maxdata = 1; s->range_table = &range_digital; --- linux-3.13.0.orig/drivers/staging/iio/adc/ad799x_core.c +++ linux-3.13.0/drivers/staging/iio/adc/ad799x_core.c @@ -393,7 +393,7 @@ }, { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE), + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), }, { .type = IIO_EV_TYPE_THRESH, @@ -588,7 +588,8 @@ return 0; error_free_irq: - free_irq(client->irq, indio_dev); + if (client->irq > 0) + free_irq(client->irq, indio_dev); error_cleanup_ring: ad799x_ring_cleanup(indio_dev); error_disable_reg: --- linux-3.13.0.orig/drivers/staging/iio/adc/mxs-lradc.c +++ linux-3.13.0/drivers/staging/iio/adc/mxs-lradc.c @@ -698,6 +698,7 @@ } /* if it is released, wait for the next touch via IRQ */ + lradc->cur_plate = LRADC_TOUCH; mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1); mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); } --- linux-3.13.0.orig/drivers/staging/iio/impedance-analyzer/ad5933.c +++ linux-3.13.0/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -629,7 +629,7 @@ struct iio_buffer *buffer; buffer = iio_kfifo_allocate(indio_dev); - if (buffer) + if (!buffer) return -ENOMEM; iio_device_attach_buffer(indio_dev, buffer); --- linux-3.13.0.orig/drivers/scsi/storvsc_drv.c +++ linux-3.13.0/drivers/scsi/storvsc_drv.c @@ -1419,6 +1419,9 @@ { struct stor_mem_pools *memp = sdevice->hostdata; + if (!memp) + return; + mempool_destroy(memp->request_mempool); kmem_cache_destroy(memp->request_pool); kfree(memp); @@ -1438,6 +1441,14 @@ sdevice->no_write_same = 1; + /* + * hyper-v lies about its capabilities indicating it is only SPC-2 + * compliant, but actually implements the core SPC-3 features. + * If we pretend to be SPC-3, we send RC16 which activates trim and + * will query the appropriate VPD pages to enable trim. + */ + sdevice->scsi_level = SCSI_SPC_3; + return 0; } --- linux-3.13.0.orig/drivers/scsi/scsi_sysfs.c +++ linux-3.13.0/drivers/scsi/scsi_sysfs.c @@ -369,17 +369,14 @@ { struct scsi_device *sdev; struct device *parent; - struct scsi_target *starget; struct list_head *this, *tmp; unsigned long flags; sdev = container_of(work, struct scsi_device, ew.work); parent = sdev->sdev_gendev.parent; - starget = to_scsi_target(parent); spin_lock_irqsave(sdev->host->host_lock, flags); - starget->reap_ref++; list_del(&sdev->siblings); list_del(&sdev->same_target_siblings); list_del(&sdev->starved_entry); @@ -399,8 +396,6 @@ /* NULL queue means the device can't be used */ sdev->request_queue = NULL; - scsi_target_reap(scsi_target(sdev)); - kfree(sdev->inquiry); kfree(sdev); @@ -1057,6 +1052,13 @@ sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); + /* + * Paired with the kref_get() in scsi_sysfs_initialize(). We have + * remoed sysfs visibility from the device, so make the target + * invisible if this was the last device underneath it. + */ + scsi_target_reap(scsi_target(sdev)); + put_device(dev); } @@ -1119,7 +1121,7 @@ continue; if (starget->dev.parent == dev || &starget->dev == dev) { /* assuming new targets arrive at the end */ - starget->reap_ref++; + kref_get(&starget->reap_ref); spin_unlock_irqrestore(shost->host_lock, flags); if (last) scsi_target_reap(last); @@ -1203,6 +1205,12 @@ list_add_tail(&sdev->same_target_siblings, &starget->devices); list_add_tail(&sdev->siblings, &shost->__devices); spin_unlock_irqrestore(shost->host_lock, flags); + /* + * device can now only be removed via __scsi_remove_device() so hold + * the target. Target will be held in CREATED state until something + * beneath it becomes visible (in which case it moves to RUNNING) + */ + kref_get(&starget->reap_ref); } int scsi_is_sdev_device(const struct device *dev) --- linux-3.13.0.orig/drivers/scsi/scsi_scan.c +++ linux-3.13.0/drivers/scsi/scsi_scan.c @@ -320,6 +320,7 @@ struct Scsi_Host *shost = dev_to_shost(dev->parent); unsigned long flags; + starget->state = STARGET_DEL; transport_destroy_device(dev); spin_lock_irqsave(shost->host_lock, flags); if (shost->hostt->target_destroy) @@ -371,6 +372,37 @@ } /** + * scsi_target_reap_ref_release - remove target from visibility + * @kref: the reap_ref in the target being released + * + * Called on last put of reap_ref, which is the indication that no device + * under this target is visible anymore, so render the target invisible in + * sysfs. Note: we have to be in user context here because the target reaps + * should be done in places where the scsi device visibility is being removed. + */ +static void scsi_target_reap_ref_release(struct kref *kref) +{ + struct scsi_target *starget + = container_of(kref, struct scsi_target, reap_ref); + + /* + * if we get here and the target is still in the CREATED state that + * means it was allocated but never made visible (because a scan + * turned up no LUNs), so don't call device_del() on it. + */ + if (starget->state != STARGET_CREATED) { + transport_remove_device(&starget->dev); + device_del(&starget->dev); + } + scsi_target_destroy(starget); +} + +static void scsi_target_reap_ref_put(struct scsi_target *starget) +{ + kref_put(&starget->reap_ref, scsi_target_reap_ref_release); +} + +/** * scsi_alloc_target - allocate a new or find an existing target * @parent: parent of the target (need not be a scsi host) * @channel: target channel number (zero if no channels) @@ -392,7 +424,7 @@ + shost->transportt->target_size; struct scsi_target *starget; struct scsi_target *found_target; - int error; + int error, ref_got; starget = kzalloc(size, GFP_KERNEL); if (!starget) { @@ -401,7 +433,7 @@ } dev = &starget->dev; device_initialize(dev); - starget->reap_ref = 1; + kref_init(&starget->reap_ref); dev->parent = get_device(parent); dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id); dev->bus = &scsi_bus_type; @@ -441,29 +473,36 @@ return starget; found: - found_target->reap_ref++; + /* + * release routine already fired if kref is zero, so if we can still + * take the reference, the target must be alive. If we can't, it must + * be dying and we need to wait for a new target + */ + ref_got = kref_get_unless_zero(&found_target->reap_ref); + spin_unlock_irqrestore(shost->host_lock, flags); - if (found_target->state != STARGET_DEL) { + if (ref_got) { put_device(dev); return found_target; } - /* Unfortunately, we found a dying target; need to - * wait until it's dead before we can get a new one */ + /* + * Unfortunately, we found a dying target; need to wait until it's + * dead before we can get a new one. There is an anomaly here. We + * *should* call scsi_target_reap() to balance the kref_get() of the + * reap_ref above. However, since the target being released, it's + * already invisible and the reap_ref is irrelevant. If we call + * scsi_target_reap() we might spuriously do another device_del() on + * an already invisible target. + */ put_device(&found_target->dev); - flush_scheduled_work(); + /* + * length of time is irrelevant here, we just want to yield the CPU + * for a tick to avoid busy waiting for the target to die. + */ + msleep(1); goto retry; } -static void scsi_target_reap_usercontext(struct work_struct *work) -{ - struct scsi_target *starget = - container_of(work, struct scsi_target, ew.work); - - transport_remove_device(&starget->dev); - device_del(&starget->dev); - scsi_target_destroy(starget); -} - /** * scsi_target_reap - check to see if target is in use and destroy if not * @starget: target to be checked @@ -474,28 +513,13 @@ */ void scsi_target_reap(struct scsi_target *starget) { - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - unsigned long flags; - enum scsi_target_state state; - int empty = 0; - - spin_lock_irqsave(shost->host_lock, flags); - state = starget->state; - if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { - empty = 1; - starget->state = STARGET_DEL; - } - spin_unlock_irqrestore(shost->host_lock, flags); - - if (!empty) - return; - - BUG_ON(state == STARGET_DEL); - if (state == STARGET_CREATED) - scsi_target_destroy(starget); - else - execute_in_process_context(scsi_target_reap_usercontext, - &starget->ew); + /* + * serious problem if this triggers: STARGET_DEL is only set in the if + * the reap_ref drops to zero, so we're trying to do another final put + * on an already released kref + */ + BUG_ON(starget->state == STARGET_DEL); + scsi_target_reap_ref_put(starget); } /** @@ -1532,6 +1556,10 @@ } mutex_unlock(&shost->scan_mutex); scsi_autopm_put_target(starget); + /* + * paired with scsi_alloc_target(). Target will be destroyed unless + * scsi_probe_and_add_lun made an underlying device visible + */ scsi_target_reap(starget); put_device(&starget->dev); @@ -1612,8 +1640,10 @@ out_reap: scsi_autopm_put_target(starget); - /* now determine if the target has any children at all - * and if not, nuke it */ + /* + * paired with scsi_alloc_target(): determine if the target has + * any children at all and if not, nuke it + */ scsi_target_reap(starget); put_device(&starget->dev); --- linux-3.13.0.orig/drivers/scsi/scsi_lib.c +++ linux-3.13.0/drivers/scsi/scsi_lib.c @@ -1684,7 +1684,7 @@ host_dev = scsi_get_device(shost); if (host_dev && host_dev->dma_mask) - bounce_limit = dma_max_pfn(host_dev) << PAGE_SHIFT; + bounce_limit = (u64)dma_max_pfn(host_dev) << PAGE_SHIFT; return bounce_limit; } --- linux-3.13.0.orig/drivers/scsi/virtio_scsi.c +++ linux-3.13.0/drivers/scsi/virtio_scsi.c @@ -956,6 +956,10 @@ #ifdef CONFIG_PM_SLEEP static int virtscsi_freeze(struct virtio_device *vdev) { + struct Scsi_Host *sh = virtio_scsi_host(vdev); + struct virtio_scsi *vscsi = shost_priv(sh); + + unregister_hotcpu_notifier(&vscsi->nb); virtscsi_remove_vqs(vdev); return 0; } @@ -964,8 +968,17 @@ { struct Scsi_Host *sh = virtio_scsi_host(vdev); struct virtio_scsi *vscsi = shost_priv(sh); + int err; + + err = virtscsi_init(vdev, vscsi); + if (err) + return err; + + err = register_hotcpu_notifier(&vscsi->nb); + if (err) + vdev->config->del_vqs(vdev); - return virtscsi_init(vdev, vscsi); + return err; } #endif --- linux-3.13.0.orig/drivers/scsi/qla4xxx/ql4_os.c +++ linux-3.13.0/drivers/scsi/qla4xxx/ql4_os.c @@ -802,6 +802,7 @@ int type; int rem = len; int rc = 0; + int size; memset(&chap_rec, 0, sizeof(chap_rec)); @@ -816,12 +817,14 @@ chap_rec.chap_type = param_info->value[0]; break; case ISCSI_CHAP_PARAM_USERNAME: - memcpy(chap_rec.username, param_info->value, - param_info->len); + size = min_t(size_t, sizeof(chap_rec.username), + param_info->len); + memcpy(chap_rec.username, param_info->value, size); break; case ISCSI_CHAP_PARAM_PASSWORD: - memcpy(chap_rec.password, param_info->value, - param_info->len); + size = min_t(size_t, sizeof(chap_rec.password), + param_info->len); + memcpy(chap_rec.password, param_info->value, size); break; case ISCSI_CHAP_PARAM_PASSWORD_LEN: chap_rec.password_length = param_info->value[0]; --- linux-3.13.0.orig/drivers/scsi/bfa/bfad.c +++ linux-3.13.0/drivers/scsi/bfa/bfad.c @@ -1802,7 +1802,7 @@ static u32 * bfad_load_fwimg(struct pci_dev *pdev) { - if (pdev->device == BFA_PCI_DEVICE_ID_CT2) { + if (bfa_asic_id_ct2(pdev->device)) { if (bfi_image_ct2_size == 0) bfad_read_firmware(pdev, &bfi_image_ct2, &bfi_image_ct2_size, BFAD_FW_FILE_CT2); @@ -1812,12 +1812,14 @@ bfad_read_firmware(pdev, &bfi_image_ct, &bfi_image_ct_size, BFAD_FW_FILE_CT); return bfi_image_ct; - } else { + } else if (bfa_asic_id_cb(pdev->device)) { if (bfi_image_cb_size == 0) bfad_read_firmware(pdev, &bfi_image_cb, &bfi_image_cb_size, BFAD_FW_FILE_CB); return bfi_image_cb; } + + return NULL; } static void --- linux-3.13.0.orig/drivers/scsi/qla2xxx/qla_target.c +++ linux-3.13.0/drivers/scsi/qla2xxx/qla_target.c @@ -3186,7 +3186,8 @@ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c, "SRR cmd %p (se_cmd %p, tag %d, op %x), " "sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag, - se_cmd->t_task_cdb[0], cmd->sg_cnt, cmd->offset); + se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, + cmd->sg_cnt, cmd->offset); qlt_handle_srr(vha, sctio, imm); --- linux-3.13.0.orig/drivers/scsi/qla2xxx/qla_isr.c +++ linux-3.13.0/drivers/scsi/qla2xxx/qla_isr.c @@ -2829,6 +2829,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) { #define MIN_MSIX_COUNT 2 +#define ATIO_VECTOR 2 int i, ret; struct msix_entry *entries; struct qla_msix_entry *qentry; @@ -2885,34 +2886,47 @@ } /* Enable MSI-X vectors for the base queue */ - for (i = 0; i < ha->msix_count; i++) { + for (i = 0; i < 2; i++) { qentry = &ha->msix_entries[i]; - if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) { - ret = request_irq(qentry->vector, - qla83xx_msix_entries[i].handler, - 0, qla83xx_msix_entries[i].name, rsp); - } else if (IS_P3P_TYPE(ha)) { + if (IS_P3P_TYPE(ha)) ret = request_irq(qentry->vector, qla82xx_msix_entries[i].handler, 0, qla82xx_msix_entries[i].name, rsp); - } else { + else ret = request_irq(qentry->vector, msix_entries[i].handler, 0, msix_entries[i].name, rsp); - } - if (ret) { - ql_log(ql_log_fatal, vha, 0x00cb, - "MSI-X: unable to register handler -- %x/%d.\n", - qentry->vector, ret); - qla24xx_disable_msix(ha); - ha->mqenable = 0; - goto msix_out; - } + if (ret) + goto msix_register_fail; qentry->have_irq = 1; qentry->rsp = rsp; rsp->msix = qentry; } + /* + * If target mode is enable, also request the vector for the ATIO + * queue. + */ + if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) { + qentry = &ha->msix_entries[ATIO_VECTOR]; + ret = request_irq(qentry->vector, + qla83xx_msix_entries[ATIO_VECTOR].handler, + 0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp); + qentry->have_irq = 1; + qentry->rsp = rsp; + rsp->msix = qentry; + } + +msix_register_fail: + if (ret) { + ql_log(ql_log_fatal, vha, 0x00cb, + "MSI-X: unable to register handler -- %x/%d.\n", + qentry->vector, ret); + qla24xx_disable_msix(ha); + ha->mqenable = 0; + goto msix_out; + } + /* Enable MSI-X vector for response queue update for queue 0 */ if (IS_QLA83XX(ha)) { if (ha->msixbase && ha->mqiobase && --- linux-3.13.0.orig/drivers/scsi/qla2xxx/qla_def.h +++ linux-3.13.0/drivers/scsi/qla2xxx/qla_def.h @@ -2993,8 +2993,7 @@ IS_QLA82XX(ha) || IS_QLA83XX(ha) || \ IS_QLA8044(ha)) #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha)) -#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \ - IS_QLA83XX(ha)) && (ha)->flags.msix_enabled) +#define IS_NOPOLLING_TYPE(ha) (IS_QLA81XX(ha) && (ha)->flags.msix_enabled) #define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha)) #define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha)) #define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha)) --- linux-3.13.0.orig/drivers/scsi/isci/host.h +++ linux-3.13.0/drivers/scsi/isci/host.h @@ -311,9 +311,8 @@ } #define for_each_isci_host(id, ihost, pdev) \ - for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \ - id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \ - ihost = to_pci_info(pdev)->hosts[++id]) + for (id = 0; id < SCI_MAX_CONTROLLERS && \ + (ihost = to_pci_info(pdev)->hosts[id]); id++) static inline void wait_for_start(struct isci_host *ihost) { --- linux-3.13.0.orig/drivers/scsi/isci/task.c +++ linux-3.13.0/drivers/scsi/isci/task.c @@ -801,7 +801,7 @@ /* XXX: need to cleanup any ireqs targeting this * domain_device */ - ret = TMF_RESP_FUNC_COMPLETE; + ret = -ENODEV; goto out; } --- linux-3.13.0.orig/drivers/scsi/isci/port_config.c +++ linux-3.13.0/drivers/scsi/isci/port_config.c @@ -615,13 +615,6 @@ SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); } else { /* the phy is already the part of the port */ - u32 port_state = iport->sm.current_state_id; - - /* if the PORT'S state is resetting then the link up is from - * port hard reset in this case, we need to tell the port - * that link up is recieved - */ - BUG_ON(port_state != SCI_PORT_RESETTING); port_agent->phy_ready_mask |= 1 << phy_index; sci_port_link_up(iport, iphy); } --- linux-3.13.0.orig/drivers/scsi/megaraid/megaraid_sas.h +++ linux-3.13.0/drivers/scsi/megaraid/megaraid_sas.h @@ -1527,7 +1527,7 @@ u32 *reply_queue; dma_addr_t reply_queue_h; - unsigned long base_addr; + resource_size_t base_addr; struct megasas_register_set __iomem *reg_set; u32 *reply_post_host_index_addr[MR_MAX_MSIX_REG_ARRAY]; struct megasas_pd_list pd_list[MEGASAS_MAX_PD]; --- linux-3.13.0.orig/drivers/misc/Makefile +++ linux-3.13.0/drivers/misc/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o obj-y += mic/ +obj-$(CONFIG_ARCH_XGENE) += xgene/ --- linux-3.13.0.orig/drivers/misc/Kconfig +++ linux-3.13.0/drivers/misc/Kconfig @@ -525,4 +525,5 @@ source "drivers/misc/mei/Kconfig" source "drivers/misc/vmw_vmci/Kconfig" source "drivers/misc/mic/Kconfig" +source "drivers/misc/xgene/Kconfig" endmenu --- linux-3.13.0.orig/drivers/misc/xgene/Makefile +++ linux-3.13.0/drivers/misc/xgene/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for APM X-GENE misc drivers. +# + +obj-$(CONFIG_XGENE_QMTM) += qmtm/ --- linux-3.13.0.orig/drivers/misc/xgene/Kconfig +++ linux-3.13.0/drivers/misc/xgene/Kconfig @@ -0,0 +1 @@ +source "drivers/misc/xgene/qmtm/Kconfig" --- linux-3.13.0.orig/drivers/misc/xgene/qmtm/xgene_qmtm_storm.c +++ linux-3.13.0/drivers/misc/xgene/qmtm/xgene_qmtm_storm.c @@ -0,0 +1,373 @@ +/** + * AppliedMicro X-Gene SOC Queue Manager/Traffic Manager driver + * + * Copyright (c) 2013 Applied Micro Circuits Corporation. + * Author: Ravi Patel + * Keyur Chudgar + * Fushen Chen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "xgene_qmtm_main.h" +#include "xgene_qmtm_storm.h" + +#define CSR_QSTATE_ADDR 0x0000006c +#define QNUMBER_WR(src) (((u32)(src)) & 0x000003ff) + +#define CSR_QSTATE_WR_0_ADDR 0x00000070 +#define CSR_QSTATE_WR_1_ADDR 0x00000074 +#define CSR_QSTATE_WR_2_ADDR 0x00000078 +#define CSR_QSTATE_WR_3_ADDR 0x0000007c +#define CSR_QSTATE_WR_4_ADDR 0x00000080 + +static struct xgene_qmtm_sdev storm_sdev[SLAVE_MAX] = { + [SLAVE_ETH0] = { + .name = "SGMII0", + .compatible = "apm,xgene-qmtm-soc", + .slave = SLAVE_ETH0, + .qmtm_ip = QMTM1, + .slave_id = QMTM_SLAVE_ID_ETH0, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x08, + }, + [SLAVE_ETH1] = { + .name = "SGMII1", + .compatible = "apm,xgene-qmtm-soc", + .slave = SLAVE_ETH1, + .qmtm_ip = QMTM1, + .slave_id = QMTM_SLAVE_ID_ETH0, + .wq_pbn_start = 0x08, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x28, + .fq_pbn_count = 0x08, + }, + [SLAVE_ETH2] = { + .name = "SGMII2", + .compatible = "apm,xgene-qmtm-soc", + .slave = SLAVE_ETH2, + .qmtm_ip = QMTM1, + .slave_id = QMTM_SLAVE_ID_ETH1, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x08, + }, + [SLAVE_ETH3] = { + .name = "SGMII3", + .compatible = "apm,xgene-qmtm-soc", + .slave = SLAVE_ETH3, + .qmtm_ip = QMTM1, + .slave_id = QMTM_SLAVE_ID_ETH1, + .wq_pbn_start = 0x08, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x28, + .fq_pbn_count = 0x08, + }, + [SLAVE_XGE0] = { + .name = "SXGMII0", + .compatible = "apm,xgene-qmtm-xge0", + .slave = SLAVE_XGE0, + .qmtm_ip = QMTM0, + .slave_id = QMTM_SLAVE_ID_ETH0, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x08, + }, + [SLAVE_XGE1] = { + .name = "SXGMII1", + .compatible = "apm,xgene-qmtm-xge0", + .slave = SLAVE_XGE1, + .qmtm_ip = QMTM0, + .slave_id = QMTM_SLAVE_ID_ETH1, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x08, + }, + [SLAVE_XGE2] = { + .name = "SXGMII2", + .compatible = "apm,xgene-qmtm-xge2", + .slave = SLAVE_XGE2, + .qmtm_ip = QMTM2, + .slave_id = QMTM_SLAVE_ID_ETH0, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x08, + }, + [SLAVE_XGE3] = { + .name = "SXGMII3", + .compatible = "apm,xgene-qmtm-xge2", + .slave = SLAVE_XGE3, + .qmtm_ip = QMTM2, + .slave_id = QMTM_SLAVE_ID_ETH1, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x08, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x08, + }, + [SLAVE_METH] = { + .name = "RGMII", + .compatible = "apm,xgene-qmtm-lite", + .slave = SLAVE_METH, + .qmtm_ip = QMTM3, + .slave_id = QMTM_SLAVE_ID_ETH0, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x04, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x04, + }, + [SLAVE_PKTDMA] = { + .name = "PKTDMA", + .compatible = "apm,xgene-qmtm-soc", + .slave = SLAVE_PKTDMA, + .qmtm_ip = QMTM1, + .slave_id = QMTM_SLAVE_ID_PKTDMA, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x04, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x08, + }, + [SLAVE_CPU_QMTM0] = { + .name = "CPU_QMTM0", + .compatible = "apm,xgene-qmtm-xge0", + .slave = SLAVE_CPU_QMTM0, + .qmtm_ip = QMTM0, + .slave_id = QMTM_SLAVE_ID_CPU, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x10, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x10, + }, + [SLAVE_CPU_QMTM1] = { + .name = "CPU_QMTM1", + .compatible = "apm,xgene-qmtm-soc", + .slave = SLAVE_CPU_QMTM1, + .qmtm_ip = QMTM1, + .slave_id = QMTM_SLAVE_ID_CPU, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x20, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x20, + }, + [SLAVE_CPU_QMTM2] = { + .name = "CPU_QMTM2", + .compatible = "apm,xgene-qmtm-xge2", + .slave = SLAVE_CPU_QMTM2, + .qmtm_ip = QMTM2, + .slave_id = QMTM_SLAVE_ID_CPU, + .wq_pbn_start = 0x10, + .wq_pbn_count = 0x10, + .fq_pbn_start = 0x30, + .fq_pbn_count = 0x10, + }, + [SLAVE_CPU_QMTM3] = { + .name = "CPU_QMTM3", + .compatible = "apm,xgene-qmtm-lite", + .slave = SLAVE_CPU_QMTM3, + .qmtm_ip = QMTM3, + .slave_id = QMTM_SLAVE_ID_CPU, + .wq_pbn_start = 0x00, + .wq_pbn_count = 0x01, + .fq_pbn_start = 0x20, + .fq_pbn_count = 0x01, + }, +}; + +static void storm_qmtm_write_qstate(struct xgene_qmtm_qinfo *qinfo) +{ + struct xgene_qmtm *qmtm = qinfo->qmtm; + u16 queue_id = qinfo->queue_id; + struct storm_qmtm_csr_qstate *csr_qstate = + &((union storm_qmtm_qstate *)qinfo->qstate)->csr; + + /* write queue number */ + queue_id = QNUMBER_WR(queue_id); + xgene_qmtm_wr32(qmtm, CSR_QSTATE_ADDR, (u32) queue_id); + + /* write queue state */ + xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_0_ADDR, csr_qstate->w0); + xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_1_ADDR, csr_qstate->w1); + xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_2_ADDR, csr_qstate->w2); + xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_3_ADDR, csr_qstate->w3); + xgene_qmtm_wr32(qmtm, CSR_QSTATE_WR_4_ADDR, csr_qstate->w4); +} + +static void storm_qmtm_read_qstate(struct xgene_qmtm_qinfo *qinfo) +{ + struct xgene_qmtm *qmtm = qinfo->qmtm; + struct storm_qmtm_csr_qstate *qfabric = (struct storm_qmtm_csr_qstate *) + (qmtm->fabric_vaddr + (qinfo->queue_id << 6)); + struct storm_qmtm_csr_qstate *csr_qstate = + &((union storm_qmtm_qstate *)qinfo->qstate)->csr; + struct storm_qmtm_pq_fp_qstate *pq_fp = + &((union storm_qmtm_qstate *)(qinfo->qstate))->pq; + + /* read queue state */ + csr_qstate->w0 = readl(&qfabric->w0); + csr_qstate->w1 = readl(&qfabric->w1); + csr_qstate->w2 = readl(&qfabric->w2); + csr_qstate->w3 = readl(&qfabric->w3); + csr_qstate->w4 = readl(&qfabric->w4); + qinfo->nummsgs = pq_fp->nummsg; +} + +static int storm_qmtm_set_qstate(struct xgene_qmtm_qinfo *qinfo) +{ + int rc = 0; + struct storm_qmtm_pq_fp_qstate *pq_fp = + &((union storm_qmtm_qstate *)(qinfo->qstate))->pq; + u64 cfgstartaddr; + u32 qsize = 0; + u8 qtype = qinfo->qtype; + + if (qtype != QTYPE_PQ && qtype != QTYPE_FP) { + pr_err("Queue type %d is invalid\n", qinfo->qtype); + rc = -EINVAL; + goto _ret_set_qstate; + } + + pq_fp->cfgqtype = qinfo->qtype; + + /* if its a free queue, ask QMTM to set len to 0 when dealloc */ + if (qtype == QTYPE_FP) + pq_fp->fp_mode = CHANGE_LEN; + + if (qinfo->slave >= SLAVE_XGE0 && qinfo->slave <= SLAVE_XGE3) { + pq_fp->cfgRecombBuf = 1; + pq_fp->cfgRecombBufTimeoutL = 0xf; + pq_fp->cfgRecombBufTimeoutH = 0x7; + } + + pq_fp->cfgselthrsh = 1; + + /* Allow the queue to accept message with non-zero LErr */ + pq_fp->cfgacceptlerr = 1; + pq_fp->qcoherent = 1; + + switch (qinfo->qsize) { + case QSIZE_512B: + qsize = 512; + break; + case QSIZE_2KB: + qsize = 2 * 1024; + break; + case QSIZE_16KB: + qsize = 16 * 1024; + break; + case QSIZE_64KB: + qsize = 64 * 1024; + break; + case QSIZE_512KB: + qsize = 512 * 1024; + break; + default: + pr_err("Queue size %d is invalid\n", qinfo->qsize); + rc = -EINVAL; + goto _ret_set_qstate; + } + + qinfo->qdesc = kzalloc(sizeof(struct xgene_qmtm_qdesc), GFP_KERNEL); + + if (qinfo->qdesc == NULL) { + rc = -ENOMEM; + goto _ret_set_qstate; + } + + qinfo->qdesc->count = (qtype == QTYPE_PQ) ? (qsize / 32) : (qsize / 16); + + if (qinfo->flags & XGENE_SLAVE_Q_ADDR_ALLOC) { + qinfo->qdesc->qvaddr = kzalloc(qsize, GFP_KERNEL); + if (qinfo->qdesc->qvaddr == NULL) { + kfree(qinfo->qdesc); + rc = -ENOMEM; + goto _ret_set_qstate; + } + + qinfo->qpaddr = (u64) VIRT_TO_PHYS(qinfo->qdesc->qvaddr); + } else { + qinfo->qdesc->qvaddr = PHYS_TO_VIRT(qinfo->qpaddr); + memset(qinfo->qdesc->qvaddr, 0, qsize); + } + + if ((qtype == QTYPE_PQ) && (qinfo->slave_id == QMTM_SLAVE_ID_CPU || + qinfo->slave_id == QMTM_SLAVE_ID_MSLIM)) { + u32 i; + + for (i = 0; i < qinfo->qdesc->count; i++) { + u32 *slot = (u32 *)&qinfo->qdesc->msg32[i]; + + slot[EMPTY_SLOT_INDEX] = EMPTY_SLOT; + } + } + + cfgstartaddr = qinfo->qpaddr >> 8; + pq_fp->cfgstartaddrL = (u32)(cfgstartaddr & (BIT(27) - 1)); + pq_fp->cfgstartaddrH = (u32)(cfgstartaddr >> 27); + pq_fp->cfgqsize = qinfo->qsize; + storm_qmtm_write_qstate(qinfo); + +_ret_set_qstate: + return rc; +} + +static void storm_qmtm_clr_qstate(struct xgene_qmtm_qinfo *qinfo) +{ + memset(qinfo->qstate, 0, sizeof(union storm_qmtm_qstate)); + storm_qmtm_write_qstate(qinfo); + + if (qinfo->flags & XGENE_SLAVE_Q_ADDR_ALLOC && qinfo->qdesc->qvaddr) { + kfree(qinfo->qdesc->qvaddr); + qinfo->qdesc->qvaddr = NULL; + } + + kfree(qinfo->qdesc); +} + +struct xgene_qmtm_sdev *storm_qmtm_get_sdev(char *name) +{ + struct xgene_qmtm *qmtm = NULL; + struct xgene_qmtm_sdev *sdev = NULL; + struct device_node *np = NULL; + struct platform_device *platdev; + u8 slave; + + for (slave = 0; slave < SLAVE_MAX; slave++) { + sdev = &storm_sdev[slave]; + if (sdev->name && strcmp(name, sdev->name) == 0) { + np = of_find_compatible_node(NULL, NULL, + sdev->compatible); + break; + } + } + + if (np == NULL) + return NULL; + + platdev = of_find_device_by_node(np); + qmtm = platform_get_drvdata(platdev); + + if (!qmtm->write_qstate) { + qmtm->write_qstate = storm_qmtm_write_qstate; + qmtm->read_qstate = storm_qmtm_read_qstate; + qmtm->set_qstate = storm_qmtm_set_qstate; + qmtm->clr_qstate = storm_qmtm_clr_qstate; + } + + sdev->qmtm = qmtm; + sdev->idev = qmtm->idev; + + return sdev; +} --- linux-3.13.0.orig/drivers/misc/xgene/qmtm/xgene_qmtm_main.c +++ linux-3.13.0/drivers/misc/xgene/qmtm/xgene_qmtm_main.c @@ -0,0 +1,765 @@ +/* + * AppliedMicro X-Gene SOC Queue Manager/Traffic Manager driver + * + * Copyright (c) 2013 Applied Micro Circuits Corporation. + * Author: Ravi Patel + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "xgene_qmtm_main.h" + +#define XGENE_QMTM_DRIVER_VER "1.0" +#define XGENE_QMTM_DRIVER_NAME "xgene-qmtm" +#define XGENE_QMTM_DRIVER_DESC "APM X-Gene QMTM driver" + +/* CSR Address Macros */ +#define CSR_QM_CONFIG_ADDR 0x00000004 +#define QM_ENABLE_WR(src) (((u32)(src)<<31) & 0x80000000) + +#define CSR_PBM_ADDR 0x00000008 +#define OVERWRITE_WR(src) (((u32)(src)<<31) & 0x80000000) +#define SLVID_PBN_WR(src) (((u32)(src)) & 0x000003ff) +#define SLAVE_ID_SHIFT 6 + +#define CSR_PBM_BUF_WR_ADDR 0x0000000c +#define CSR_PBM_BUF_RD_ADDR 0x00000010 +#define PB_SIZE_WR(src) (((u32)(src)<<31) & 0x80000000) +#define PREFETCH_BUF_EN_SET(dst, src) \ + (((dst) & ~0x00200000) | (((u32)(src)<<21) & 0x00200000)) +#define IS_FREE_POOL_SET(dst, src) \ + (((dst) & ~0x00100000) | (((u32)(src)<<20) & 0x00100000)) +#define TLVQ_SET(dst, src) \ + (((dst) & ~0x00080000) | (((u32)(src)<<19) & 0x00080000)) +#define CORRESPONDING_QNUM_SET(dst, src) \ + (((dst) & ~0x0007fe00) | (((u32)(src)<<9) & 0x0007fe00)) + +#define CSR_PBM_CTICK0_ADDR 0x00000018 +#define MIN_COAL_TAP 0x0 +#define MAX_COAL_TAP 0x7 + +#define CSR_THRESHOLD0_SET1_ADDR 0x00000030 +#define CSR_THRESHOLD1_SET1_ADDR 0x00000034 +#define CSR_HYSTERESIS_ADDR 0x00000068 +#define CSR_QM_MBOX_NE_INT_MODE_ADDR 0x0000017c +#define CSR_QMLITE_PBN_MAP_0_ADDR 0x00000228 + +#define CSR_RECOMB_CTRL_0_ADDR 0x00000230 +#define RECOMB_EN0_SET(dst, src) \ + (((dst) & ~0x00000001) | (((u32)(src)) & 0x00000001)) + +/* QMTM Diag CSR */ +#define QM_GLBL_DIAG_CSR_BASE_ADDR_OFFSET 0xd000 +#define QM_CFG_MEM_RAM_SHUTDOWN_ADDR 0x00000070 +#define QM_CFG_MEM_RAM_SHUTDOWN_DEFAULT 0xffffffff + +/* PBN macros */ +#define QMTM_MIN_PBN_ID 0 +#define QMTM_MAX_PBN_ID 31 + +/* Common for Queue ID and PBN */ +#define RES_MASK(nr) (1UL << ((nr) % 32)) +#define RES_WORD(nr) ((nr) / 32) + +void xgene_qmtm_wr32(struct xgene_qmtm *qmtm, u32 offset, u32 data) +{ + void *addr = (u8 *)qmtm->csr_vaddr + offset; + writel(data, addr); +} + +void xgene_qmtm_rd32(struct xgene_qmtm *qmtm, u32 offset, u32 *data) +{ + void *addr = (u8 *)qmtm->csr_vaddr + offset; + *data = readl(addr); +} + +/* Get available PBN or Queue Id */ +static int xgene_qmtm_get_resource_id(u32 *resource, u32 start, u32 end) +{ + u32 index; + + for (index = start; index < end; index++) { + if ((resource[RES_WORD(index)] & RES_MASK(index)) == 0) { + resource[RES_WORD(index)] |= RES_MASK(index); + return index; + } + } + + return -ENODEV; +} + +/* Put used PBN or Queue Id */ +static inline void xgene_qmtm_put_resource_id(u32 *resource, u32 index) +{ + resource[RES_WORD(index)] &= ~(u32) RES_MASK(index); +} + +static void xgene_qmtm_write_pbm(struct xgene_qmtm_qinfo *qinfo, u32 val) +{ + u32 pbm = SLVID_PBN_WR((qinfo->slave_id << SLAVE_ID_SHIFT) | + qinfo->pbn) | OVERWRITE_WR(1); + + xgene_qmtm_wr32(qinfo->qmtm, CSR_PBM_ADDR, pbm); + + if (qinfo->qmtm_ip == QMTM0 || qinfo->qmtm_ip == QMTM2) + val |= PB_SIZE_WR(1); + + xgene_qmtm_wr32(qinfo->qmtm, CSR_PBM_BUF_WR_ADDR, val); +} + +static u32 xgene_qmtm_read_pbm(struct xgene_qmtm_qinfo *qinfo) +{ + u32 pbm = SLVID_PBN_WR((qinfo->slave_id << SLAVE_ID_SHIFT) | + qinfo->pbn); + + xgene_qmtm_wr32(qinfo->qmtm, CSR_PBM_ADDR, pbm); + xgene_qmtm_rd32(qinfo->qmtm, CSR_PBM_BUF_RD_ADDR, &pbm); + + return pbm; +} + +static void xgene_qmtm_set_pbm(struct xgene_qmtm_qinfo *qinfo) +{ + u16 is_fp = qinfo->qtype == QTYPE_FP ? 1 : 0; + u16 is_vq = qinfo->qtype == QTYPE_VQ ? 1 : 0; + u32 val = 0; + + val = CORRESPONDING_QNUM_SET(val, qinfo->queue_id); + val = IS_FREE_POOL_SET(val, is_fp); + val = TLVQ_SET(val, is_vq); + val = PREFETCH_BUF_EN_SET(val, 1); + xgene_qmtm_write_pbm(qinfo, val); +} + +static void xgene_qmtm_clr_pbm(struct xgene_qmtm_qinfo *qinfo) +{ + xgene_qmtm_write_pbm(qinfo, 0); +} + +/** + * xgene_qmtm_set_qinfo - Create and configure a queue + * @sdev: Slave context + * @qtype: Queue type (P_QUEUE or FP_QUEUE) + * @qsize: Queue size see xgene_qmtm_qsize + * @qaccess: Queue access method see xgene_qmtm_qaccess + * @flags: Queue Information flags + * @qpaddr: If Desire Queue Physical Address to use + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to create and configure a queue. + * + * Return: 0 on Success or -1 on Failure + * On Success, updates following in qinfo, + * qmtm_ip - QMTM0, QMTM1, QMTM2 or QMTM3 + * qmtm - QMTM instance context + * slave - Slave see xgene_slave + * slave_id - Slave ID see xgene_qmtm_slave_id + * pbn - Slave ID's prefetch buffer number + * queue_id - Queue ID + * qdesc - Queue descriptor + */ +int xgene_qmtm_set_qinfo(struct xgene_qmtm_qinfo *set) +{ + struct xgene_qmtm_sdev *sdev = set->sdev; + struct device *dev; + struct xgene_qmtm *qmtm; + struct xgene_qmtm_qinfo *qinfo; + u32 *queue_resource = NULL, *pbn_resource = NULL; + int rc; + u8 pbn = 0; + u16 queue_id = 0; + + qmtm = sdev->qmtm; + dev = &qmtm->pdev->dev; + + if (set->flags & XGENE_SLAVE_PB_CONFIGURE) { + u8 pbn_start, pbn_count; + + if (set->qtype == QTYPE_FP) { + pbn_resource = &sdev->fq_pbn_pool; + pbn_start = sdev->fq_pbn_start & ~(u8) 0x20; + pbn_count = sdev->fq_pbn_count; + } else { + pbn_resource = &sdev->wq_pbn_pool; + pbn_start = sdev->wq_pbn_start; + pbn_count = sdev->wq_pbn_count; + } + + rc = xgene_qmtm_get_resource_id(pbn_resource, pbn_start, + pbn_start + pbn_count); + if (rc < 0) { + dev_err(dev, "SETQ: slave %d out of PBN\n", + sdev->slave); + goto _ret_set_qinfo; + } + + pbn = rc; + } + + queue_resource = qmtm->queue_pool; + rc = xgene_qmtm_get_resource_id(queue_resource, 0, qmtm->max_queues); + if (rc < 0) { + dev_err(dev, "SETQ: QMTM %d out of Queue ID\n", sdev->qmtm_ip); + goto _put_pbn_resource; + } + + queue_id = rc; + qinfo = kzalloc(sizeof(struct xgene_qmtm_qinfo), GFP_KERNEL); + if (qinfo == NULL) { + dev_err(dev, "SETQ: Unable to allocate qinfo\n"); + rc = -ENOMEM; + goto _put_queue_resource; + } + + qinfo->slave = sdev->slave; + qinfo->slave_id = sdev->slave_id; + qinfo->qmtm_ip = sdev->qmtm_ip; + qinfo->qtype = set->qtype; + qinfo->qsize = set->qsize; + qinfo->qaccess = set->qaccess; + qinfo->flags = set->flags; + qinfo->pbn = set->qtype == QTYPE_FP ? (pbn | 0x20) : pbn; + qinfo->queue_id = queue_id; + qinfo->qpaddr = set->qpaddr; + qinfo->qfabric = qmtm->fabric_vaddr + (queue_id << 6); + qinfo->sdev = sdev; + qinfo->qmtm = qmtm; + rc = qmtm->set_qstate(qinfo); + if (rc < 0) { + dev_err(dev, "SETQ: set_qstate error for %s Queue ID %d\n", + sdev->name, queue_id); + goto _del_qstate; + } + + if (qinfo->qaccess == QACCESS_ALT) + qinfo->qdesc->command = qinfo->qfabric + 0x2C; + + if (set->flags & XGENE_SLAVE_PB_CONFIGURE) { + xgene_qmtm_set_pbm(qinfo); + + if (set->qaccess == QACCESS_ALT && + sdev->slave_id == QMTM_SLAVE_ID_CPU && + set->qtype == QTYPE_PQ) { + u32 data; + + xgene_qmtm_rd32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, + &data); + data |= (u32) (1 << (31 - pbn)); + xgene_qmtm_wr32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, + data); + } + + if (set->qtype == QTYPE_PQ && + (sdev->slave_id == QMTM_SLAVE_ID_CPU || + sdev->slave_id == QMTM_SLAVE_ID_MSLIM)) + qinfo->qdesc->irq = qmtm->dequeue_irq[pbn]; + } + + qmtm->qinfo[queue_id] = qinfo; + memcpy(set, qinfo, sizeof(struct xgene_qmtm_qinfo)); + return rc; + +_del_qstate: + qmtm->clr_qstate(qinfo); + kfree(qinfo); + +_put_queue_resource: + xgene_qmtm_put_resource_id(queue_resource, queue_id); + +_put_pbn_resource: + if (set->flags & XGENE_SLAVE_PB_CONFIGURE) + xgene_qmtm_put_resource_id(pbn_resource, pbn); + +_ret_set_qinfo: + return rc; +} +EXPORT_SYMBOL_GPL(xgene_qmtm_set_qinfo); + +/** + * xgene_qmtm_clr_qinfo - Unconfigure and delete a queue + * @sdev: Slave context + * @queue_id: Queue ID + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to unconfigure and delete a queue. + */ +void xgene_qmtm_clr_qinfo(struct xgene_qmtm_qinfo *clr) +{ + struct xgene_qmtm_sdev *sdev = clr->sdev; + struct xgene_qmtm *qmtm; + struct xgene_qmtm_qinfo *qinfo; + u8 queue_id = clr->queue_id; + + qmtm = sdev->qmtm; + qinfo = qmtm->qinfo[queue_id]; + + if (qinfo->flags & XGENE_SLAVE_PB_CONFIGURE) { + u32 *pbn_resource; + u8 qtype = qinfo->qtype; + u8 pbn = (qtype == QTYPE_FP) ? + (qinfo->pbn & ~(u8) 0x20) : qinfo->pbn; + + if (qinfo->qaccess == QACCESS_ALT && + qinfo->slave_id == QMTM_SLAVE_ID_CPU && qtype == QTYPE_PQ) { + u32 data; + + xgene_qmtm_rd32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, + &data); + data &= ~(u32) (1 << (31 - pbn)); + xgene_qmtm_wr32(qmtm, CSR_QM_MBOX_NE_INT_MODE_ADDR, + data); + } + + if (qinfo->qtype == QTYPE_FP) + pbn_resource = &sdev->fq_pbn_pool; + else + pbn_resource = &sdev->wq_pbn_pool; + + xgene_qmtm_clr_pbm(qinfo); + xgene_qmtm_put_resource_id(pbn_resource, pbn); + } + + qmtm->clr_qstate(qinfo); + kfree(qinfo); + xgene_qmtm_put_resource_id(qmtm->queue_pool, queue_id); + qmtm->qinfo[queue_id] = NULL; +} +EXPORT_SYMBOL_GPL(xgene_qmtm_clr_qinfo); + +/** + * xgene_qmtm_read_qstate - Get Queue State information for a queue + * @qmtm: QMTM instance context + * @queue_id: Queue ID + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to read queue state of a queue. + * + * Return: Updates following in qinfo, + * qstate - Current Queue State in QMTM + * nummsgs - Number os messages in the Queue + * pbm_state - Current prefetch buffer manager state + */ +void xgene_qmtm_read_qstate(struct xgene_qmtm_qinfo *qinfo) +{ + struct xgene_qmtm *qmtm = qinfo->qmtm; + u8 queue_id = qinfo->queue_id; + + memcpy(qinfo, qmtm->qinfo[queue_id], sizeof(struct xgene_qmtm_qinfo)); + qmtm->read_qstate(qinfo); + + if (qinfo->flags & XGENE_SLAVE_PB_CONFIGURE) + qinfo->pbm_state = xgene_qmtm_read_pbm(qinfo); +} +EXPORT_SYMBOL_GPL(xgene_qmtm_read_qstate); + +/** + * xgene_qmtm_intr_coalesce - Set interrupt coalescing for ingrgess queue + * @qmtm: QMTM instance context + * @pbn: CPU's prefetch buffer number corresponding to the interrupt + * @tap: Tap value to set + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to set interrupt for its ingress queue. + * + * Return: 0 on Success or -1 on Failure + */ +int xgene_qmtm_intr_coalesce(struct xgene_qmtm_qinfo *qinfo, u8 tap) +{ + u32 val, offset, mask, shift; + u8 pbn = qinfo->pbn; + + if (tap < MIN_COAL_TAP || tap > MAX_COAL_TAP) + return -EINVAL; + + if (pbn < QMTM_MIN_PBN_ID || pbn > QMTM_MAX_PBN_ID) + return -EINVAL; + + offset = 4 * (pbn / 8); + shift = 4 * (7 - (pbn % 8)); + mask = 7 << shift; + + xgene_qmtm_rd32(qinfo->qmtm, CSR_PBM_CTICK0_ADDR + offset, &val); + val = (val & ~(u32) mask) | (((u32) tap << shift) & mask); + xgene_qmtm_wr32(qinfo->qmtm, CSR_PBM_CTICK0_ADDR + offset, val); + + return 0; +} +EXPORT_SYMBOL_GPL(xgene_qmtm_intr_coalesce); + +/** + * xgene_qmtm_fp_dealloc_msg - Fill a buffer in a free pool queue + * @qdesc: Queue descriptor + * @msg: QMTM free pool buffer message to fill in to queue + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to fill a buffer in its free pool queue. + */ +void xgene_qmtm_fp_dealloc_msg(struct xgene_qmtm_qdesc *qdesc, + struct xgene_qmtm_msg16 *msg) +{ + u32 qtail = qdesc->qtail; + u32 count = qdesc->count; + u8 *tailptr = (u8 *)&qdesc->msg16[qtail]; + + memcpy(tailptr, msg, 16); + + if (++qtail == count) + qtail = 0; + + writel(1, qdesc->command); + qdesc->qtail = qtail; +} +EXPORT_SYMBOL_GPL(xgene_qmtm_fp_dealloc_msg); + +/** + * xgene_qmtm_enqueue_msg - Enqueue a work message in subsystem's work queue + * @qdesc: Queue descriptor + * @msg: X-Gene SOC subsystem's work message to enqueue in to queue + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to enqueue work message in its work queue. + */ +void xgene_qmtm_enqueue_msg(struct xgene_qmtm_qdesc *qdesc, + struct xgene_qmtm_msg64 *msg) +{ + u32 qtail = qdesc->qtail; + u32 count = qdesc->count; + u8 *tailptr = (u8 *)&qdesc->msg32[qtail]; + + memcpy(tailptr, msg, 32); + + if (++qtail == count) + qtail = 0; + + if (!msg->msg32_1.msg16.NV) { + writel(1, qdesc->command); + } else { + memcpy(tailptr + 32, (u8 *) msg + 32, 32); + + if (++qtail == count) + qtail = 0; + + writel(2, qdesc->command); + } + + qdesc->qtail = qtail; +} +EXPORT_SYMBOL_GPL(xgene_qmtm_enqueue_msg); + +/** + * xgene_qmtm_dequeue_msg - Dequeue a work message from QMTM instance + * @qdesc: Queue descriptor + * @msg: Dequeued work message from X-Gene SOC subsystem to CPU + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to dequeue work message from its ingress + * queue. + * + * Return: 0 on Success or -1 on Failure + */ +int xgene_qmtm_dequeue_msg(struct xgene_qmtm_qdesc *qdesc, + struct xgene_qmtm_msg64 *msg) +{ + u32 qhead = qdesc->qhead; + u32 count = qdesc->count; + u32 *headptr = (u32 *)&qdesc->msg32[qhead]; + + if (headptr[EMPTY_SLOT_INDEX] == EMPTY_SLOT) + return -EAGAIN; + + memcpy(msg, headptr, 32); + headptr[EMPTY_SLOT_INDEX] = EMPTY_SLOT; + + if (++qhead == count) + qhead = 0; + + if (!msg->msg32_1.msg16.NV) { + writel(0xFFFFFFFF, qdesc->command); + } else { + headptr += 8; + + if (headptr[EMPTY_SLOT_INDEX] == EMPTY_SLOT) + return -EAGAIN; + + memcpy((u8 *) msg + 32, headptr, 32); + headptr[EMPTY_SLOT_INDEX] = EMPTY_SLOT; + + if (++qhead == count) + qhead = 0; + + writel(0xFFFFFFFE, qdesc->command); + } + + qdesc->qhead = qhead; + + return 0; +} +EXPORT_SYMBOL_GPL(xgene_qmtm_dequeue_msg); + +/** + * xgene_qmtm_get_sdev - Get slave context from slave name + * @name: Slave name + * + * This API will be called by APM X-Gene SOC Ethernet, PktDMA (XOR Engine), + * and Security Engine subsystems to get its slave context from its name. + * + * Return: Slave context on Success or NULL on Failure + */ +struct xgene_qmtm_sdev *xgene_qmtm_get_sdev(char *name) +{ + return storm_qmtm_get_sdev(name); +} +EXPORT_SYMBOL_GPL(xgene_qmtm_get_sdev); + +static int xgene_qmtm_enable(struct xgene_qmtm *qmtm) +{ + struct xgene_qmtm_qinfo qinfo; + struct device *dev = &qmtm->pdev->dev; + int rc, mwait = 0; + u32 val; + u32 queue_id; + + qmtm->clk = devm_clk_get(dev, NULL); + if (IS_ERR(qmtm->clk)) { + dev_err(dev, "can't get clock\n"); + return PTR_ERR(qmtm->clk); + } + + rc = clk_prepare_enable(qmtm->clk); + if (rc < 0) { + dev_err(dev, "clock prepare enable failed"); + return rc; + } + + xgene_qmtm_wr32(qmtm, QM_GLBL_DIAG_CSR_BASE_ADDR_OFFSET + + QM_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); + do { + /* Wait for Memory to come out of shutdown */ + usleep_range(1000, 2000); + xgene_qmtm_rd32(qmtm, QM_GLBL_DIAG_CSR_BASE_ADDR_OFFSET + + QM_CFG_MEM_RAM_SHUTDOWN_ADDR, &val); + + if (mwait++ >= 1000) { + rc = -EIO; + dev_err(dev, "RAM not out of shutdown %d\n", rc); + clk_disable_unprepare(qmtm->clk); + return rc; + } + } while (val == QM_CFG_MEM_RAM_SHUTDOWN_DEFAULT); + + switch (qmtm->qmtm_ip) { + case QMTM0: + case QMTM2: + xgene_qmtm_rd32(qmtm, CSR_RECOMB_CTRL_0_ADDR, &val); + val = RECOMB_EN0_SET(val, 1); + xgene_qmtm_wr32(qmtm, CSR_RECOMB_CTRL_0_ADDR, val); + break; + case QMTM3: + xgene_qmtm_wr32(qmtm, CSR_QMLITE_PBN_MAP_0_ADDR, 0x00000000); + } + + /* program threshold set 1 and all hysteresis */ + xgene_qmtm_wr32(qmtm, CSR_THRESHOLD0_SET1_ADDR, 100); + xgene_qmtm_wr32(qmtm, CSR_THRESHOLD1_SET1_ADDR, 200); + xgene_qmtm_wr32(qmtm, CSR_HYSTERESIS_ADDR, 0xFFFFFFFF); + + /* Enable QPcore */ + xgene_qmtm_wr32(qmtm, CSR_QM_CONFIG_ADDR, QM_ENABLE_WR(1)); + + /* Clear all HW queue state in case they were not de-activated */ + memset(&qinfo, 0, sizeof(qinfo)); + qinfo.qmtm = qmtm; + + for (queue_id = 0; queue_id < qmtm->max_queues; queue_id++) { + qinfo.queue_id = queue_id; + qmtm->write_qstate(&qinfo); + } + + /* Enable error reporting */ + return xgene_qmtm_enable_error(qmtm); +} + +static int xgene_qmtm_disable(struct xgene_qmtm *qmtm) +{ + u32 queue_id; + + /* Disable error reporting */ + xgene_qmtm_disable_error(qmtm); + + for (queue_id = 0; queue_id < qmtm->max_queues; queue_id++) { + if (qmtm->qinfo[queue_id]) { + dev_err(&qmtm->pdev->dev, + "QMTM %d Queue ID %d Resource in use\n", + qmtm->qmtm_ip, queue_id); + return -EAGAIN; + } + } + + /* Disable QPcore */ + xgene_qmtm_wr32(qmtm, CSR_QM_CONFIG_ADDR, QM_ENABLE_WR(0)); + clk_disable_unprepare(qmtm->clk); + + return 0; +} + +static struct xgene_qmtm *xgene_alloc_qmtm(struct platform_device *pdev) +{ + struct xgene_qmtm *qmtm; + int max_queues, malloc_size; + + qmtm = devm_kzalloc(&pdev->dev, sizeof(struct xgene_qmtm), GFP_KERNEL); + if (qmtm == NULL) { + dev_err(&pdev->dev, "Unable to allocate QMTM context\n"); + return NULL; + } + + qmtm->pdev = pdev; + platform_set_drvdata(pdev, qmtm); + max_queues = QMTM_MAX_QUEUES; + malloc_size = max_queues * (sizeof(struct xgene_qmtm_info *)); + qmtm->qinfo = devm_kzalloc(&pdev->dev, malloc_size, GFP_KERNEL); + if (qmtm->qinfo == NULL) { + dev_err(&pdev->dev, "Unable to allocate QMTM Queue context\n"); + return NULL; + } + + malloc_size = RES_WORD(max_queues + 31) * sizeof(u32); + qmtm->queue_pool = devm_kzalloc(&pdev->dev, malloc_size, GFP_KERNEL); + if (qmtm->queue_pool == NULL) { + dev_err(&pdev->dev, "Unable to allocate QMTM Queue Pool\n"); + return NULL; + } + + qmtm->max_queues = max_queues; + + return qmtm; +} + +static int xgene_get_qmtm(struct xgene_qmtm *qmtm) +{ + struct platform_device *pdev = qmtm->pdev; + struct resource *res; + struct xgene_qmtm_sdev *sdev; + const char *name; + int rc, inum = 1; + u16 pbn; + + /* Retrieve QM CSR register address and size */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get QMTM CSR region\n"); + return -ENODEV; + } + + qmtm->csr_vaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(qmtm->csr_vaddr)) { + dev_err(&pdev->dev, "Invalid QMTM CSR region\n"); + return PTR_ERR(qmtm->csr_vaddr); + } + + /* Retrieve Primary Fabric address and size */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(&pdev->dev, "Failed to get QMTM Fabric region\n"); + return -ENODEV; + } + + qmtm->fabric_vaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(qmtm->fabric_vaddr)) { + dev_err(&pdev->dev, "Invalid QMTM Fabric region\n"); + return PTR_ERR(qmtm->fabric_vaddr); + } + + rc = of_property_read_string(pdev->dev.of_node, "slave-name", &name); + if (rc < 0) { + dev_err(&pdev->dev, "Failed to get QMTM Ingress slave-name\n"); + return rc; + } + + sdev = xgene_qmtm_get_sdev((char *)name); + if (sdev == NULL) { + dev_err(&pdev->dev, "Ingress Slave error\n"); + return -ENODEV; + } + + qmtm->idev = sdev; + qmtm->qmtm_ip = sdev->qmtm_ip; + + for (pbn = sdev->wq_pbn_start; pbn < (sdev->wq_pbn_start + + sdev->wq_pbn_count); + pbn++, inum++) { + int irq = platform_get_irq(pdev, inum); + + if (irq < 0) { + dev_err(&pdev->dev, "Failed to map QMTM%d PBN %d IRQ\n", + qmtm->qmtm_ip, pbn); + continue; + } + + qmtm->dequeue_irq[pbn] = irq; + } + + return rc; +} + +static int xgene_qmtm_probe(struct platform_device *pdev) +{ + struct xgene_qmtm *qmtm; + int rc; + + qmtm = xgene_alloc_qmtm(pdev); + if (qmtm == NULL) + return -ENOMEM; + + rc = xgene_get_qmtm(qmtm); + if (rc) + return rc; + + return xgene_qmtm_enable(qmtm); +} + +static int xgene_qmtm_remove(struct platform_device *pdev) +{ + struct xgene_qmtm *qmtm = platform_get_drvdata(pdev); + return xgene_qmtm_disable(qmtm); +} + +static struct of_device_id xgene_qmtm_match[] = { + {.compatible = "apm,xgene-qmtm-xge0",}, + {.compatible = "apm,xgene-qmtm-soc",}, + {.compatible = "apm,xgene-qmtm-xge2",}, + {.compatible = "apm,xgene-qmtm-lite",}, + {}, +}; + +MODULE_DEVICE_TABLE(of, xgene_qmtm_match); + +static struct platform_driver xgene_qmtm_driver = { + .driver = { + .name = XGENE_QMTM_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = xgene_qmtm_match, + }, + .probe = xgene_qmtm_probe, + .remove = xgene_qmtm_remove, +}; + +module_platform_driver(xgene_qmtm_driver); + +MODULE_VERSION(XGENE_QMTM_DRIVER_VER); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ravi Patel "); +MODULE_DESCRIPTION(XGENE_QMTM_DRIVER_DESC); --- linux-3.13.0.orig/drivers/misc/xgene/qmtm/Makefile +++ linux-3.13.0/drivers/misc/xgene/qmtm/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for APM X-GENE Queue Manager Traffic Manager driver. +# + +obj-$(CONFIG_XGENE_QMTM) += xgene-qmtm.o + +xgene-qmtm-objs := xgene_qmtm_main.o xgene_qmtm_storm.o xgene_qmtm_error.o --- linux-3.13.0.orig/drivers/misc/xgene/qmtm/Kconfig +++ linux-3.13.0/drivers/misc/xgene/qmtm/Kconfig @@ -0,0 +1,9 @@ +config XGENE_QMTM + tristate "APM X-Gene Queue Manager/Traffic Manager driver" + depends on ARM64 || COMPILE_TEST + default y + help + This option enables APM X-Gene Queue Manager Traffic Manager (QMTM) + driver support. + QMTM is required for Ethernet, PktDMA (XOR Engine) and Security + Engine. --- linux-3.13.0.orig/drivers/misc/xgene/qmtm/xgene_qmtm_main.h +++ linux-3.13.0/drivers/misc/xgene/qmtm/xgene_qmtm_main.h @@ -0,0 +1,138 @@ +/* + * AppliedMicro X-Gene SOC Queue Manager/Traffic Manager driver + * + * Copyright (c) 2013 Applied Micro Circuits Corporation. + * Author: Ravi Patel + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __XGENE_QMTM_MAIN_H__ +#define __XGENE_QMTM_MAIN_H__ + +#include +#include + +/* QMTM Platform Information */ +enum xgene_qmtm_pinfo { + STORM_QMTM, + MAX_PLATFORM, +}; + +/* QMTM IP Blocks */ +enum xgene_qmtm_ip { + QMTM0, + QMTM1, + QMTM2, + QMTM3, + QMTM_MAX, +}; + +#define QMTM_MAX_QUEUES 1024 +#define QMTM_MAX_PBN 32 + +struct xgene_qmtm { + void *csr_vaddr; + void *fabric_vaddr; + u16 qmtm_ip; /* qmtm_ip, see xgene_qmtm_ip */ + u16 error_irq; + u32 max_queues; + u16 dequeue_irq[QMTM_MAX_PBN]; + char error_irq_s[16]; + char error_queue_irq_s[16]; + struct xgene_qmtm_sdev *idev; + u32 *queue_pool; + struct xgene_qmtm_qinfo *(*qinfo); + struct xgene_qmtm_qinfo *error_qinfo; + struct clk *clk; + struct platform_device *pdev; + void (*write_qstate) (struct xgene_qmtm_qinfo *qinfo); + void (*read_qstate) (struct xgene_qmtm_qinfo *qinfo); + int (*set_qstate) (struct xgene_qmtm_qinfo *qinfo); + void (*clr_qstate) (struct xgene_qmtm_qinfo *qinfo); +}; + +/* QMTM Slave */ +enum xgene_slave { + SLAVE_ETH0, + SLAVE_ETH1, + SLAVE_ETH2, + SLAVE_ETH3, + SLAVE_XGE0, + SLAVE_XGE1, + SLAVE_XGE2, + SLAVE_XGE3, + SLAVE_METH, + SLAVE_PKTDMA, + SLAVE_CTX_QMTM0, + SLAVE_CTX_QMTM1, + SLAVE_CTX_QMTM2, + SLAVE_SEC, + SLAVE_CLASS, + SLAVE_MSLIM_QMTM0, + SLAVE_MSLIM_QMTM1, + SLAVE_MSLIM_QMTM2, + SLAVE_MSLIM_QMTM3, + SLAVE_PMPRO, + SLAVE_SMPRO_QMTM0, + SLAVE_SMPRO_QMTM1, + SLAVE_SMPRO_QMTM2, + SLAVE_SMPRO_QMTM3, + SLAVE_CPU_QMTM0, + SLAVE_CPU_QMTM1, + SLAVE_CPU_QMTM2, + SLAVE_CPU_QMTM3, + SLAVE_MAX, +}; + +/* QMTM Slave IDs */ +enum xgene_qmtm_slave_id { + QMTM_SLAVE_ID_ETH0, + QMTM_SLAVE_ID_ETH1, + QMTM_SLAVE_ID_RES2, + QMTM_SLAVE_ID_PKTDMA, + QMTM_SLAVE_ID_CTX, + QMTM_SLAVE_ID_SEC, + QMTM_SLAVE_ID_CLASS, + QMTM_SLAVE_ID_MSLIM, + QMTM_SLAVE_ID_RES8, + QMTM_SLAVE_ID_RES9, + QMTM_SLAVE_ID_RESA, + QMTM_SLAVE_ID_RESB, + QMTM_SLAVE_ID_RESC, + QMTM_SLAVE_ID_PMPRO, + QMTM_SLAVE_ID_SMPRO, + QMTM_SLAVE_ID_CPU, + QMTM_SLAVE_ID_MAX, +}; + +/* QMTM Free Pool Queue modes */ +enum xgene_qmtm_fp_mode { + MSG_NO_CHANGE, + ROUND_ADDR, + REDUCE_LEN, + CHANGE_LEN, +}; + +#define VIRT_TO_PHYS(x) virt_to_phys(x) +#define PHYS_TO_VIRT(x) phys_to_virt(x) + +/* QMTM CSR read/write routine */ +void xgene_qmtm_wr32(struct xgene_qmtm *qmtm, u32 offset, u32 data); +void xgene_qmtm_rd32(struct xgene_qmtm *qmtm, u32 offset, u32 *data); + +/* QMTM Error handling */ +int xgene_qmtm_enable_error(struct xgene_qmtm *qmtm); +void xgene_qmtm_disable_error(struct xgene_qmtm *qmtm); + +struct xgene_qmtm_sdev *storm_qmtm_get_sdev(char *name); + +#endif /* __XGENE_QMTM_MAIN_H__ */ --- linux-3.13.0.orig/drivers/misc/xgene/qmtm/xgene_qmtm_storm.h +++ linux-3.13.0/drivers/misc/xgene/qmtm/xgene_qmtm_storm.h @@ -0,0 +1,241 @@ +/* + * AppliedMicro X-Gene SOC Queue Manager/Traffic Manager driver + * + * Copyright (c) 2013 Applied Micro Circuits Corporation. + * Author: Ravi Patel + * Keyur Chudgar + * Fushen Chen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __XGENE_QMTM_STORM_H__ +#define __XGENE_QMTM_STORM_H__ + +/* QMTM Queue State */ +struct storm_qmtm_csr_qstate { + u32 w0; + u32 w1; + u32 w2; + u32 w3; + u32 w4; +} __packed; + +/* + * Physical or free pool queue state (pq or fp) + */ +struct storm_qmtm_pq_fp_qstate { +#ifdef CONFIG_CPU_BIG_ENDIAN + /* register word 0 (bit 31:0) */ + u32 cpu_notify:8; /* 31:24 */ + u32 cfgsaben:1; /* 23 enable SAB broadcasting */ + u32 cfgtmvq:10; /* 22:13 parent vq */ + u32 cfgtmvqen:1; /* 12 enable pq to belong to vq */ + u32 resize_done:1; /* 11 */ + u32 resize_start:1; /* 10 */ + u32 resize_qid:10; /* 9:0 */ + + /* register word 1 (bit 63:32) */ + u32 headptr:15; /* 63:49 */ + u32 nummsg:16; /* 48:33 */ + u32 cfgnotifyqne:1; /* 32 enable Q not empty intr */ + + /* register word 2 (bit 95:64) */ + u32 cfgstartaddrL:27; /* 95:69 split 7/27 */ + u32 qcoherent:1; /* 68 */ + u32 rid:3; /* 67:65 */ + u32 cfgcrid:1; /* 64 */ + + /* register word 3 (bit 127:96) */ + u32 cfgRecombBufTimeoutL:4; /* 127:124 split 3/4 */ + u32 cfgRecombBuf:1; /* 123 */ + u32 qstatelock:1; /* 122 */ + u32 cfgqsize:3; /* 121:119 queue size */ + u32 fp_mode:3; /* 118:116 free pool mode */ + u32 cfgacceptlerr:1; /* 115 */ + u32 reserved_0:1; /* 114 */ + u32 stashing:1; /* 113 */ + u32 slot_pending:8; /* 112:105 */ + u32 vc_chanid:2; /* 104:103 */ + u32 cfgstartaddrH:7; /* 102:96 split 7/27 */ + + /* register word 4 (bit 159:128) */ + u32 resv1:11; /* 159:149 */ + u32 cfgqtype:2; /* 148:147 queue type */ + u32 resv2:5; /* 146:142 */ + u32 half_64B_override:3; /* 141:139 */ + u32 resv3:4; /* 138:135 */ + u32 CfgSupressCmpl:1; /* 134 */ + u32 cfgselthrsh:3; /* 133:131 associated threshold set */ + u32 cfgRecombBufTimeoutH:3; /* 130:128 split 3/4 */ +#else + /* register word 0 (bit 31:0) */ + u32 resize_qid:10; /* 9:0 */ + u32 resize_start:1; /* 10 */ + u32 resize_done:1; /* 11 */ + u32 cfgtmvqen:1; /* 12 enable pq to belong to vq */ + u32 cfgtmvq:10; /* 22:13 parent vq */ + u32 cfgsaben:1; /* 23 enable SAB broadcasting */ + u32 cpu_notify:8; /* 31:24 */ + + /* register word 1 (bit 63:32) */ + u32 cfgnotifyqne:1; /* 32 enable Q not empty intr */ + u32 nummsg:16; /* 48:33 */ + u32 headptr:15; /* 63:49 */ + + /* register word 2 (bit 95:64) */ + u32 cfgcrid:1; /* 64 */ + u32 rid:3; /* 67:65 */ + u32 qcoherent:1; /* 68 */ + u32 cfgstartaddrL:27; /* 95:69 split 7/27 */ + + /* register word 3 (bit 127:96) */ + u32 cfgstartaddrH:7; /* 102:96 split 7/27 */ + u32 vc_chanid:2; /* 104:103 */ + u32 slot_pending:8; /* 112:105 */ + u32 stashing:1; /* 113 */ + u32 reserved_0:1; /* 114 */ + u32 cfgacceptlerr:1; /* 115 */ + u32 fp_mode:3; /* 118:116 free pool mode */ + u32 cfgqsize:3; /* 121:119 queue size */ + u32 qstatelock:1; /* 122 */ + u32 cfgRecombBuf:1; /* 123 */ + u32 cfgRecombBufTimeoutL:4; /* 127:124 split 3/4 */ + + /* register word 4 (bit 159:128) */ + u32 cfgRecombBufTimeoutH:3; /* 130:128 split 3/4 */ + u32 cfgselthrsh:3; /* 133:131 associated threshold set */ + u32 CfgSupressCmpl:1; /* 134 */ + u32 resv3:4; /* 138:135 */ + u32 half_64B_override:3; /* 141:139 */ + u32 resv2:5; /* 146:142 */ + u32 cfgqtype:2; /* 148:147 queue type */ + u32 resv1:11; /* 159:149 */ +#endif +} __packed; + +struct storm_qmtm_vq_qstate { +#ifdef CONFIG_CPU_BIG_ENDIAN + /* register word 0 (bit 31:0) */ + u32 rid:3; /* 31:29 */ + u32 cpu_notify:8; /* 28:21 */ + u32 cfgcrid:1; /* 20 critical rid config */ + u32 cfgnotifyqne:1; /* 19 enable Q not empty intr */ + u32 cfgsaben:1; /* 18 enable SAB broadcasting */ + u32 nummsg:18; /* 17:0 */ + + /* register word 1 (bit 63:32) */ + u32 q5reqvld:1; /* 63 */ + u32 q5txallowed:1; /* 62 */ + u32 q5selarb:2; /* 61:60 */ + u32 q6_sel:10; /* 59:50 */ + u32 q6reqvld:1; /* 49 */ + u32 q6txallowed:1; /* 48 */ + u32 q6selarb:2; /* 47:46 */ + u32 q7_sel:10; /* 45:36 */ + u32 q7reqvld:1; /* 35 */ + u32 q7txallowed:1; /* 34 */ + u32 q7selarb:2; /* 33:32 */ + + /* register word 2 (bit 95:64) */ + u32 q3_selL:4; /* 95:92 split 4/6 */ + u32 q3reqvld:1; /* 91 */ + u32 q3txallowed:1; /* 90 */ + u32 q3selarb:2; /* 89:88 */ + u32 q4_sel:10; /* 87:78 */ + u32 q4reqvld:1; /* 77 */ + u32 q4txallowed:1; /* 76 */ + u32 q4selarb:2; /* 75:74 */ + u32 q5_sel:10; /* 73:64 */ + + /* register word 3 (bit 127:96) */ + u32 q1_selL:8; /* 127:120 split 2/8 */ + u32 q1reqvld:1; /* 119 */ + u32 q1txallowed:1; /* 118 */ + u32 q1selarb:2; /* 117:116 */ + u32 q2_sel:10; /* 115:106 */ + u32 q2reqvld:1; /* 105 */ + u32 q2txallowed:1; /* 104 */ + u32 q2selarb:2; /* 103:102 */ + u32 q3_selH:6; /* 101:96 split 4/6 */ + + /* register word 4 (bit 159:128) */ + u32 resv1:11; /* 159:149 */ + u32 cfgqtype:2; /* 148:147 queue type */ + u32 cfgselthrsh:3; /* 146:144 associated threshold set */ + u32 q0_sel:10; /* 143:134 */ + u32 q0reqvld:1; /* 133 */ + u32 q0txallowed:1; /* 132 */ + u32 q0selarb:2; /* 131:130 */ + u32 q1_selH:2; /* 129:128 split 2/8 */ +#else + /* register word 0 (bit 31:0) */ + u32 nummsg:18; /* 17:0 */ + u32 cfgsaben:1; /* 18 enable SAB broadcasting */ + u32 cfgnotifyqne:1; /* 19 enable Q not empty intr */ + u32 cfgcrid:1; /* 20 critical rid config */ + u32 cpu_notify:8; /* 28:21 */ + u32 rid:3; /* 31:29 */ + + /* register word 1 (bit 63:32) */ + u32 q7selarb:2; /* 33:32 */ + u32 q7txallowed:1; /* 34 */ + u32 q7reqvld:1; /* 35 */ + u32 q7_sel:10; /* 45:36 */ + u32 q6selarb:2; /* 47:46 */ + u32 q6txallowed:1; /* 48 */ + u32 q6reqvld:1; /* 49 */ + u32 q6_sel:10; /* 59:50 */ + u32 q5selarb:2; /* 61:60 */ + u32 q5txallowed:1; /* 62 */ + u32 q5reqvld:1; /* 63 */ + + /* register word 2 (bit 95:64) */ + u32 q5_sel:10; /* 73:64 */ + u32 q4selarb:2; /* 75:74 */ + u32 q4txallowed:1; /* 76 */ + u32 q4reqvld:1; /* 77 */ + u32 q4_sel:10; /* 87:78 */ + u32 q3selarb:2; /* 89:88 */ + u32 q3txallowed:1; /* 90 */ + u32 q3reqvld:1; /* 91 */ + u32 q3_selL:4; /* 95:92 split 4/6 */ + + /* register word 3 (bit 127:96) */ + u32 q3_selH:6; /* 101:96 split 4/6 */ + u32 q2selarb:2; /* 103:102 */ + u32 q2txallowed:1; /* 104 */ + u32 q2reqvld:1; /* 105 */ + u32 q2_sel:10; /* 115:106 */ + u32 q1selarb:2; /* 117:116 */ + u32 q1txallowed:1; /* 118 */ + u32 q1reqvld:1; /* 119 */ + u32 q1_selL:8; /* 127:120 split 2/8 */ + + /* register word 4 (bit 159:128) */ + u32 q1_selH:2; /* 129:128 split 2/8 */ + u32 q0selarb:2; /* 131:130 */ + u32 q0txallowed:1; /* 132 */ + u32 q0reqvld:1; /* 133 */ + u32 q0_sel:10; /* 143:134 */ + u32 cfgselthrsh:3; /* 146:144 associated threshold set */ + u32 cfgqtype:2; /* 148:147 queue type */ + u32 resv1:11; /* 159:149 */ +#endif +} __packed; + +union storm_qmtm_qstate { + struct storm_qmtm_csr_qstate csr; + struct storm_qmtm_pq_fp_qstate pq; + struct storm_qmtm_pq_fp_qstate fp; + struct storm_qmtm_vq_qstate vq; +} __packed; + +#endif /* __XGENE_QMTM_STORM_H__ */ --- linux-3.13.0.orig/drivers/misc/xgene/qmtm/xgene_qmtm_error.c +++ linux-3.13.0/drivers/misc/xgene/qmtm/xgene_qmtm_error.c @@ -0,0 +1,283 @@ +/* + * AppliedMicro X-Gene SOC Queue Manager/Traffic Manager driver + * + * Copyright (c) 2013 Applied Micro Circuits Corporation. + * Author: Ravi Patel + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "xgene_qmtm_main.h" + +#define QM_INTERRUPT_ADDR 0x00000124 +#define QM_INTERRUPTMASK_ADDR 0x00000128 +#define QUEUE_NOT_EMPTYMASK_MASK 0x80000000 +#define ACR_FIFO_CRITICALMASK_MASK 0x00000008 +#define QPCORE_ACR_ERRORMASK_MASK 0x00000004 +#define DEQ_AXI_ERRORMASK_MASK 0x00000002 +#define PBM_DEC_ERRORMASK_MASK 0x00000001 + +#define CSR_PBM_ERRINF_ADDR 0x00000134 +#define ACR_QID_RD(src) (((src) & 0x00ffc000)>>14) +#define QID_RD(src) (((src) & 0x000003ff)) + +#define CSR_MSGRD_ERRINF_ADDR 0x00000138 + +#define CSR_ERRQ_ADDR 0x00000218 +#define UNEXPECTED_EN_SET(dst, src) \ + (((dst) & ~0x80000000) | (((u32)(src)<<31) & 0x80000000)) +#define UNEXPECTED_QID_SET(dst, src) \ + (((dst) & ~0x03ff0000) | (((u32)(src)<<16) & 0x03ff0000)) +#define EXPECTED_EN_SET(dst, src) \ + (((dst) & ~0x00008000) | (((u32)(src)<<15) & 0x00008000)) +#define EXPECTED_QID_SET(dst, src) \ + (((dst) & ~0x000003ff) | (((u32)(src)) & 0x000003ff)) + +/* QMTM Error Reporting */ +enum xgene_qmtm_lerr { + QMTM_NO_ERR, + QMTM_MSG_SIZE_ERR, + QMTM_HOP_COUNT_ERR, + QMTM_VQ_ENQ_ERR, + QMTM_DISABLEDQ_ENQ_ERR, + QMTM_Q_OVERFLOW_ERR, + QMTM_ENQUEUE_ERR, + QMTM_DEQUEUE_ERR, +}; + +/* Parse Error Message received on Error Queue */ +static void xgene_qmtm_error_msg(struct xgene_qmtm_qinfo *qinfo, + struct xgene_qmtm_msg32 *msg) +{ + struct xgene_qmtm_msg16 *msg16 = &msg->msg16; + struct device *dev = &qinfo->qmtm->pdev->dev; + u16 queue_id = qinfo->queue_id; + + dev_err(dev, "Error ELErr[%d] LErr[%d] for Qid[%d]\n", + msg16->ELErr, msg16->LErr, queue_id); + + switch (msg16->LErr) { + case QMTM_MSG_SIZE_ERR: + dev_err(dev, "Msg Size Error for Enqueue on Queue %d\n", + queue_id); + break; + case QMTM_HOP_COUNT_ERR: + dev_err(dev, "Hop count error, hop count of 3 for Queue %d\n", + queue_id); + break; + case QMTM_VQ_ENQ_ERR: + dev_err(dev, "Enqueue on Virtual Queue %d\n", queue_id); + break; + case QMTM_DISABLEDQ_ENQ_ERR: + dev_err(dev, "Enqueue on disabled Queue %d\n", queue_id); + break; + case QMTM_Q_OVERFLOW_ERR: + dev_err(dev, "Queue %d overflow, message sent to Error Queue\n", + queue_id); + break; + case QMTM_ENQUEUE_ERR: + dev_err(dev, "Enqueue Queue\n"); + break; + case QMTM_DEQUEUE_ERR: + dev_err(dev, "Dequeue Queue\n"); + break; + default: + dev_err(dev, "Unknown Error\n"); + break; + } +} + +static void xgene_qmtm_error(struct xgene_qmtm *qmtm) +{ + struct device *dev = &qmtm->pdev->dev; + struct xgene_qmtm_qinfo qinfo; + u32 status; + u32 pbm_err; + u32 msgrd_err; + + memset(&qinfo, 0, sizeof(qinfo)); + qinfo.qmtm = qmtm; + + xgene_qmtm_rd32(qmtm, QM_INTERRUPT_ADDR, &status); + dev_err(dev, "error interrupt status 0x%08X\n", status); + + xgene_qmtm_rd32(qmtm, CSR_PBM_ERRINF_ADDR, &pbm_err); + dev_err(dev, "CSR PBM ERRINF (0x%X) value 0x%08X\n", + CSR_PBM_ERRINF_ADDR, pbm_err); + + xgene_qmtm_rd32(qmtm, CSR_MSGRD_ERRINF_ADDR, &msgrd_err); + dev_err(dev, "CSR MSGRD ERRINF (0x%X) value 0x%08X\n", + CSR_MSGRD_ERRINF_ADDR, msgrd_err); + + qinfo.queue_id = QID_RD(msgrd_err); + dev_err(dev, "DEQ QID %d\n", qinfo.queue_id); + xgene_qmtm_read_qstate(&qinfo); + print_hex_dump(KERN_ERR, "DEQSTATE ", DUMP_PREFIX_ADDRESS, 16, 4, + qinfo.qstate, sizeof(qinfo.qstate), 1); + + qinfo.queue_id = ACR_QID_RD(msgrd_err); + dev_err(dev, "ENQ QID %d\n", qinfo.queue_id); + xgene_qmtm_read_qstate(&qinfo); + print_hex_dump(KERN_INFO, "ENQSTATE ", DUMP_PREFIX_ADDRESS, 16, 4, + qinfo.qstate, sizeof(qinfo.qstate), 1); + + xgene_qmtm_wr32(qmtm, QM_INTERRUPT_ADDR, status); +} + +static irqreturn_t xgene_qmtm_error_intr(int irq, void *qdev) +{ + xgene_qmtm_error((struct xgene_qmtm *)qdev); + + return IRQ_HANDLED; +} + +static irqreturn_t xgene_qmtm_error_queue_intr(int irq, void *qdev) +{ + struct xgene_qmtm_msg64 msg; + struct xgene_qmtm_qinfo *qinfo = (struct xgene_qmtm_qinfo *)qdev; + struct xgene_qmtm *qmtm = qinfo->qmtm; + struct device *dev = &qmtm->pdev->dev; + u16 queue_id = qinfo->queue_id; + u8 qmtm_ip = qinfo->qmtm_ip; + int rc; + + rc = xgene_qmtm_dequeue_msg(qinfo->qdesc, &msg); + if (rc < 0) { + /* Return if invalid interrupt */ + dev_err(dev, "QMTM%d QID %d PBN %d IRQ %d spurious\n", + qmtm_ip, queue_id, qinfo->pbn, irq); + return IRQ_HANDLED; + } + + xgene_qmtm_error(qmtm); + dev_err(dev, "QMTM%d Error: QID %d\n", qmtm_ip, queue_id); + print_hex_dump(KERN_INFO, "Err q MSG: ", DUMP_PREFIX_ADDRESS, + 16, 4, &msg, msg.msg32_1.msg16.NV ? 64 : 32, 1); + xgene_qmtm_error_msg(qinfo, &msg.msg32_1); + + return IRQ_HANDLED; +} + +int xgene_qmtm_enable_error(struct xgene_qmtm *qmtm) +{ + struct device *dev = &qmtm->pdev->dev; + struct xgene_qmtm_qinfo qinfo; + int rc = 0; + u32 val; + u16 irq = platform_get_irq(qmtm->pdev, 0); + u8 qmtm_ip = qmtm->qmtm_ip; + + if (irq) { + u32 mask; + + memset(qmtm->error_irq_s, 0, sizeof(qmtm->error_irq_s)); + snprintf(qmtm->error_irq_s, sizeof(qmtm->error_irq_s), + "%s_Err", qmtm->idev->name); + + rc = devm_request_irq(dev, irq, xgene_qmtm_error_intr, 0, + qmtm->error_irq_s, qmtm); + if (rc < 0) { + dev_err(dev, "request_irq %d failed for %s (%d)\n", + irq, qmtm->error_irq_s, rc); + return rc; + } + + qmtm->error_irq = irq; + + /* Enable QM hardware interrupts */ + mask = ~(u32) (PBM_DEC_ERRORMASK_MASK + | ACR_FIFO_CRITICALMASK_MASK + | QUEUE_NOT_EMPTYMASK_MASK + | DEQ_AXI_ERRORMASK_MASK + | QPCORE_ACR_ERRORMASK_MASK); + xgene_qmtm_wr32(qmtm, QM_INTERRUPTMASK_ADDR, mask); + } + + if (qmtm_ip == QMTM3) + return rc; + + memset(&qinfo, 0, sizeof(qinfo)); + qinfo.sdev = qmtm->idev; + qinfo.qaccess = QACCESS_ALT; + qinfo.qtype = QTYPE_PQ; + qinfo.qsize = QSIZE_2KB; + qinfo.flags = XGENE_SLAVE_DEFAULT_FLAGS; + + /* create error queue */ + rc = xgene_qmtm_set_qinfo(&qinfo); + if (rc < 0) { + dev_err(dev, "QMTM %d unable to configure error queue\n", + qmtm_ip); + return rc; + } + + qmtm->error_qinfo = qmtm->qinfo[qinfo.queue_id]; + memset(qmtm->error_queue_irq_s, 0, sizeof(qmtm->error_queue_irq_s)); + snprintf(qmtm->error_queue_irq_s, sizeof(qmtm->error_queue_irq_s), + "%s_ErQ", qmtm->idev->name); + + rc = devm_request_irq(dev, qinfo.qdesc->irq, + xgene_qmtm_error_queue_intr, + 0, qmtm->error_queue_irq_s, qmtm->error_qinfo); + if (rc < 0) { + dev_err(dev, "request_irq %d failed for %s (%d)\n", + qinfo.qdesc->irq, qmtm->error_queue_irq_s, rc); + xgene_qmtm_clr_qinfo(&qinfo); + qmtm->error_qinfo = NULL; + return rc; + } + + val = 0; + val = UNEXPECTED_EN_SET(val, 1); + val = UNEXPECTED_QID_SET(val, qinfo.queue_id); + val = EXPECTED_EN_SET(val, 1); + val = EXPECTED_QID_SET(val, qinfo.queue_id); + xgene_qmtm_wr32(qmtm, CSR_ERRQ_ADDR, val); + + return rc; +} + +void xgene_qmtm_disable_error(struct xgene_qmtm *qmtm) +{ + struct xgene_qmtm_qinfo *error_qinfo = qmtm->error_qinfo; + struct device *dev = &qmtm->pdev->dev; + + /* Free QMTM Error IRQ */ + if (qmtm->error_irq) { + u32 mask; + + /* Disable QM hardware interrupts */ + mask = PBM_DEC_ERRORMASK_MASK + | ACR_FIFO_CRITICALMASK_MASK + | QUEUE_NOT_EMPTYMASK_MASK + | DEQ_AXI_ERRORMASK_MASK | QPCORE_ACR_ERRORMASK_MASK; + xgene_qmtm_wr32(qmtm, QM_INTERRUPTMASK_ADDR, mask); + devm_free_irq(dev, qmtm->error_irq, qmtm); + qmtm->error_irq = 0; + } + + if (error_qinfo) { + struct xgene_qmtm_qinfo qinfo; + + /* Free QMTM Error Queue IRQ */ + devm_free_irq(dev, error_qinfo->qdesc->irq, error_qinfo); + + /* Delete error queue */ + qinfo.sdev = error_qinfo->qmtm->idev; + qinfo.queue_id = error_qinfo->queue_id; + xgene_qmtm_clr_qinfo(&qinfo); + qmtm->error_qinfo = NULL; + + /* Unassign error queue */ + xgene_qmtm_wr32(qmtm, CSR_ERRQ_ADDR, 0); + } +} --- linux-3.13.0.orig/drivers/misc/mic/host/mic_device.h +++ linux-3.13.0/drivers/misc/mic/host/mic_device.h @@ -134,6 +134,8 @@ * @send_intr: Send an interrupt for a particular doorbell on the card. * @ack_interrupt: Hardware specific operations to ack the h/w on * receipt of an interrupt. + * @intr_workarounds: Hardware specific workarounds needed after + * handling an interrupt. * @reset: Reset the remote processor. * @reset_fw_ready: Reset firmware ready field. * @is_fw_ready: Check if firmware is ready for OS download. @@ -149,6 +151,7 @@ void (*write_spad)(struct mic_device *mdev, unsigned int idx, u32 val); void (*send_intr)(struct mic_device *mdev, int doorbell); u32 (*ack_interrupt)(struct mic_device *mdev); + void (*intr_workarounds)(struct mic_device *mdev); void (*reset)(struct mic_device *mdev); void (*reset_fw_ready)(struct mic_device *mdev); bool (*is_fw_ready)(struct mic_device *mdev); --- linux-3.13.0.orig/drivers/misc/mic/host/mic_main.c +++ linux-3.13.0/drivers/misc/mic/host/mic_main.c @@ -115,7 +115,7 @@ struct mic_device *mdev = data; struct mic_bootparam *bootparam = mdev->dp; - mdev->ops->ack_interrupt(mdev); + mdev->ops->intr_workarounds(mdev); switch (bootparam->shutdown_status) { case MIC_HALTED: --- linux-3.13.0.orig/drivers/misc/mic/host/mic_virtio.c +++ linux-3.13.0/drivers/misc/mic/host/mic_virtio.c @@ -156,7 +156,8 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, struct mic_copy_desc *copy) { - int ret = 0, iovcnt = copy->iovcnt; + int ret = 0; + u32 iovcnt = copy->iovcnt; struct iovec iov; struct iovec __user *u_iov = copy->iov; void __user *ubuf = NULL; @@ -369,7 +370,7 @@ struct mic_vdev *mvdev = data; struct mic_device *mdev = mvdev->mdev; - mdev->ops->ack_interrupt(mdev); + mdev->ops->intr_workarounds(mdev); schedule_work(&mvdev->virtio_bh_work); return IRQ_HANDLED; } --- linux-3.13.0.orig/drivers/misc/mic/host/mic_x100.c +++ linux-3.13.0/drivers/misc/mic/host/mic_x100.c @@ -174,35 +174,38 @@ } /** - * mic_ack_interrupt - Device specific interrupt handling. - * @mdev: pointer to mic_device instance + * mic_x100_ack_interrupt - Read the interrupt sources register and + * clear it. This function will be called in the MSI/INTx case. + * @mdev: Pointer to mic_device instance. * - * Returns: bitmask of doorbell events triggered. + * Returns: bitmask of interrupt sources triggered. */ static u32 mic_x100_ack_interrupt(struct mic_device *mdev) { - u32 reg = 0; - struct mic_mw *mw = &mdev->mmio; u32 sicr0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICR0; + u32 reg = mic_mmio_read(&mdev->mmio, sicr0); + mic_mmio_write(&mdev->mmio, reg, sicr0); + return reg; +} + +/** + * mic_x100_intr_workarounds - These hardware specific workarounds are + * to be invoked everytime an interrupt is handled. + * @mdev: Pointer to mic_device instance. + * + * Returns: none + */ +static void mic_x100_intr_workarounds(struct mic_device *mdev) +{ + struct mic_mw *mw = &mdev->mmio; /* Clear pending bit array. */ if (MIC_A0_STEP == mdev->stepping) mic_mmio_write(mw, 1, MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_MSIXPBACR); - if (mdev->irq_info.num_vectors <= 1) { - reg = mic_mmio_read(mw, sicr0); - - if (unlikely(!reg)) - goto done; - - mic_mmio_write(mw, reg, sicr0); - } - if (mdev->stepping >= MIC_B0_STEP) mdev->intr_ops->enable_interrupts(mdev); -done: - return reg; } /** @@ -553,6 +556,7 @@ .write_spad = mic_x100_write_spad, .send_intr = mic_x100_send_intr, .ack_interrupt = mic_x100_ack_interrupt, + .intr_workarounds = mic_x100_intr_workarounds, .reset = mic_x100_hw_reset, .reset_fw_ready = mic_x100_reset_fw_ready, .is_fw_ready = mic_x100_is_fw_ready, --- linux-3.13.0.orig/drivers/misc/mei/mei_dev.h +++ linux-3.13.0/drivers/misc/mei/mei_dev.h @@ -61,11 +61,16 @@ #define MEI_CLIENTS_MAX 256 /* + * maximum number of consecutive resets + */ +#define MEI_MAX_CONSEC_RESET 3 + +/* * Number of File descriptors/handles * that can be opened to the driver. * * Limit to 255: 256 Total Clients - * minus internal client for MEI Bus Messags + * minus internal client for MEI Bus Messages */ #define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1) @@ -178,9 +183,10 @@ unsigned long buf_idx; unsigned long read_time; struct file *file_object; + u32 internal:1; }; -/* MEI client instance carried as file->pirvate_data*/ +/* MEI client instance carried as file->private_data*/ struct mei_cl { struct list_head link; struct mei_device *dev; @@ -326,6 +332,7 @@ /** * struct mei_device - MEI private device struct + * @reset_count - limits the number of consecutive resets * @hbm_state - state of host bus message protocol * @mem_addr - mem mapped base register address @@ -369,6 +376,7 @@ /* * mei device states */ + unsigned long reset_count; enum mei_dev_state dev_state; enum mei_hbm_state hbm_state; u16 init_clients_timer; @@ -427,6 +435,7 @@ bool iamthif_canceled; struct work_struct init_work; + struct work_struct reset_work; /* List of bus devices */ struct list_head device_list; @@ -456,13 +465,25 @@ return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4); } +/** + * mei_slots2data- get data in slots - bytes from slots + * @slots - number of available slots + * returns - number of bytes in slots + */ +static inline u32 mei_slots2data(int slots) +{ + return slots * 4; +} + /* * mei init function prototypes */ void mei_device_init(struct mei_device *dev); -void mei_reset(struct mei_device *dev, int interrupts); +int mei_reset(struct mei_device *dev); int mei_start(struct mei_device *dev); +int mei_restart(struct mei_device *dev); void mei_stop(struct mei_device *dev); +void mei_cancel_work(struct mei_device *dev); /* * MEI interrupt functions prototype @@ -510,7 +531,7 @@ * NFC functions */ int mei_nfc_host_init(struct mei_device *dev); -void mei_nfc_host_exit(void); +void mei_nfc_host_exit(struct mei_device *dev); /* * NFC Client UUID @@ -626,9 +647,9 @@ int mei_register(struct mei_device *dev); void mei_deregister(struct mei_device *dev); -#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d comp=%1d" +#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d internal=%1d comp=%1d" #define MEI_HDR_PRM(hdr) \ (hdr)->host_addr, (hdr)->me_addr, \ - (hdr)->length, (hdr)->msg_complete + (hdr)->length, (hdr)->internal, (hdr)->msg_complete #endif --- linux-3.13.0.orig/drivers/misc/mei/hw.h +++ linux-3.13.0/drivers/misc/mei/hw.h @@ -111,7 +111,8 @@ u32 me_addr:8; u32 host_addr:8; u32 length:9; - u32 reserved:6; + u32 reserved:5; + u32 internal:1; u32 msg_complete:1; } __packed; --- linux-3.13.0.orig/drivers/misc/mei/nfc.c +++ linux-3.13.0/drivers/misc/mei/nfc.c @@ -92,7 +92,7 @@ * @cl: NFC host client * @cl_info: NFC info host client * @init_work: perform connection to the info client - * @fw_ivn: NFC Intervace Version Number + * @fw_ivn: NFC Interface Version Number * @vendor_id: NFC manufacturer ID * @radio_type: NFC radio type */ @@ -163,7 +163,7 @@ return 0; default: - dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n", + dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n", ndev->radio_type); return -EINVAL; @@ -175,14 +175,14 @@ ndev->bus_name = "pn544"; return 0; default: - dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n", + dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n", ndev->radio_type); return -EINVAL; } default: - dev_err(&dev->pdev->dev, "Unknow vendor ID 0x%x\n", + dev_err(&dev->pdev->dev, "Unknown vendor ID 0x%x\n", ndev->vendor_id); return -EINVAL; @@ -428,7 +428,7 @@ mutex_unlock(&dev->device_lock); if (mei_nfc_if_version(ndev) < 0) { - dev_err(&dev->pdev->dev, "Could not get the NFC interfave version"); + dev_err(&dev->pdev->dev, "Could not get the NFC interface version"); goto err; } @@ -469,7 +469,9 @@ return; err: + mutex_lock(&dev->device_lock); mei_nfc_free(ndev); + mutex_unlock(&dev->device_lock); return; } @@ -481,7 +483,7 @@ struct mei_cl *cl_info, *cl = NULL; int i, ret; - /* already initialzed */ + /* already initialized */ if (ndev->cl_info) return 0; @@ -547,12 +549,16 @@ return ret; } -void mei_nfc_host_exit(void) +void mei_nfc_host_exit(struct mei_device *dev) { struct mei_nfc_dev *ndev = &nfc_dev; + cancel_work_sync(&ndev->init_work); + + mutex_lock(&dev->device_lock); if (ndev->cl && ndev->cl->device) mei_cl_remove_device(ndev->cl->device); mei_nfc_free(ndev); + mutex_unlock(&dev->device_lock); } --- linux-3.13.0.orig/drivers/misc/mei/hbm.c +++ linux-3.13.0/drivers/misc/mei/hbm.c @@ -28,9 +28,9 @@ * * @dev: the device structure * - * returns none. + * returns 0 on success -ENOMEM on allocation failure */ -static void mei_hbm_me_cl_allocate(struct mei_device *dev) +static int mei_hbm_me_cl_allocate(struct mei_device *dev) { struct mei_me_client *clients; int b; @@ -44,7 +44,7 @@ dev->me_clients_num++; if (dev->me_clients_num == 0) - return; + return 0; kfree(dev->me_clients); dev->me_clients = NULL; @@ -56,12 +56,10 @@ sizeof(struct mei_me_client), GFP_KERNEL); if (!clients) { dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n"); - dev->dev_state = MEI_DEV_RESETTING; - mei_reset(dev, 1); - return; + return -ENOMEM; } dev->me_clients = clients; - return; + return 0; } /** @@ -85,12 +83,12 @@ } /** - * same_disconn_addr - tells if they have the same address + * mei_hbm_cl_addr_equal - tells if they have the same address * - * @file: private data of the file object. - * @disconn: disconnection request. + * @cl: - client + * @buf: buffer with cl header * - * returns true if addres are same + * returns true if addresses are the same */ static inline bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf) @@ -128,6 +126,17 @@ return false; } +/** + * mei_hbm_idle - set hbm to idle state + * + * @dev: the device structure + */ +void mei_hbm_idle(struct mei_device *dev) +{ + dev->init_clients_timer = 0; + dev->hbm_state = MEI_HBM_IDLE; +} + int mei_hbm_start_wait(struct mei_device *dev) { int ret; @@ -137,7 +146,7 @@ mutex_unlock(&dev->device_lock); ret = wait_event_interruptible_timeout(dev->wait_recvd_msg, dev->hbm_state == MEI_HBM_IDLE || - dev->hbm_state > MEI_HBM_START, + dev->hbm_state >= MEI_HBM_STARTED, mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); mutex_lock(&dev->device_lock); @@ -153,12 +162,15 @@ * mei_hbm_start_req - sends start request message. * * @dev: the device structure + * + * returns 0 on success and < 0 on failure */ int mei_hbm_start_req(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; struct hbm_host_version_request *start_req; const size_t len = sizeof(struct hbm_host_version_request); + int ret; mei_hbm_hdr(mei_hdr, len); @@ -170,12 +182,13 @@ start_req->host_version.minor_version = HBM_MINOR_VERSION; dev->hbm_state = MEI_HBM_IDLE; - if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { - dev_err(&dev->pdev->dev, "version message write failed\n"); - dev->dev_state = MEI_DEV_RESETTING; - mei_reset(dev, 1); - return -EIO; + ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + if (ret) { + dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n", + ret); + return ret; } + dev->hbm_state = MEI_HBM_START; dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; return 0; @@ -186,13 +199,15 @@ * * @dev: the device structure * - * returns none. + * returns 0 on success and < 0 on failure */ -static void mei_hbm_enum_clients_req(struct mei_device *dev) +static int mei_hbm_enum_clients_req(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; struct hbm_host_enum_request *enum_req; const size_t len = sizeof(struct hbm_host_enum_request); + int ret; + /* enumerate clients */ mei_hbm_hdr(mei_hdr, len); @@ -200,14 +215,15 @@ memset(enum_req, 0, len); enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; - if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { - dev->dev_state = MEI_DEV_RESETTING; - dev_err(&dev->pdev->dev, "enumeration request write failed.\n"); - mei_reset(dev, 1); + ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + if (ret) { + dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n", + ret); + return ret; } dev->hbm_state = MEI_HBM_ENUM_CLIENTS; dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; - return; + return 0; } /** @@ -215,7 +231,7 @@ * * @dev: the device structure * - * returns none. + * returns 0 on success and < 0 on failure */ static int mei_hbm_prop_req(struct mei_device *dev) @@ -226,7 +242,7 @@ const size_t len = sizeof(struct hbm_props_request); unsigned long next_client_index; unsigned long client_num; - + int ret; client_num = dev->me_client_presentation_num; @@ -253,12 +269,11 @@ prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; prop_req->address = next_client_index; - if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { - dev->dev_state = MEI_DEV_RESETTING; - dev_err(&dev->pdev->dev, "properties request write failed\n"); - mei_reset(dev, 1); - - return -EIO; + ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + if (ret) { + dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n", + ret); + return ret; } dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; @@ -268,7 +283,7 @@ } /** - * mei_hbm_stop_req_prepare - perpare stop request message + * mei_hbm_stop_req_prepare - prepare stop request message * * @dev - mei device * @mei_hdr - mei message header @@ -289,7 +304,7 @@ } /** - * mei_hbm_cl_flow_control_req - sends flow control requst. + * mei_hbm_cl_flow_control_req - sends flow control request. * * @dev: the device structure * @cl: client info @@ -451,7 +466,7 @@ } /** - * mei_hbm_cl_connect_res - connect resposne from the ME + * mei_hbm_cl_connect_res - connect response from the ME * * @dev: the device structure * @rs: connect response bus message @@ -505,8 +520,8 @@ /** - * mei_hbm_fw_disconnect_req - disconnect request initiated by me - * host sends disoconnect response + * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware + * host sends disconnect response * * @dev: the device structure. * @disconnect_req: disconnect request bus message from the me @@ -559,8 +574,10 @@ * * @dev: the device structure * @mei_hdr: header of bus message + * + * returns 0 on success and < 0 on failure */ -void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) +int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) { struct mei_bus_message *mei_msg; struct mei_me_client *me_client; @@ -577,8 +594,20 @@ mei_read_slots(dev, dev->rd_msg_buf, hdr->length); mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; + /* ignore spurious message and prevent reset nesting + * hbm is put to idle during system reset + */ + if (dev->hbm_state == MEI_HBM_IDLE) { + dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n"); + return 0; + } + switch (mei_msg->hbm_cmd) { case HOST_START_RES_CMD: + dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n"); + + dev->init_clients_timer = 0; + version_res = (struct hbm_host_version_response *)mei_msg; dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n", @@ -597,73 +626,89 @@ } if (!mei_hbm_version_is_supported(dev)) { - dev_warn(&dev->pdev->dev, "hbm version mismatch: stopping the driver.\n"); + dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n"); - dev->hbm_state = MEI_HBM_STOP; + dev->hbm_state = MEI_HBM_STOPPED; mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr, dev->wr_msg.data); - mei_write_message(dev, &dev->wr_msg.hdr, - dev->wr_msg.data); + if (mei_write_message(dev, &dev->wr_msg.hdr, + dev->wr_msg.data)) { + dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n"); + return -EIO; + } + break; + } - return; + if (dev->dev_state != MEI_DEV_INIT_CLIENTS || + dev->hbm_state != MEI_HBM_START) { + dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n", + dev->dev_state, dev->hbm_state); + return -EPROTO; } - if (dev->dev_state == MEI_DEV_INIT_CLIENTS && - dev->hbm_state == MEI_HBM_START) { - dev->init_clients_timer = 0; - mei_hbm_enum_clients_req(dev); - } else { - dev_err(&dev->pdev->dev, "reset: wrong host start response\n"); - mei_reset(dev, 1); - return; + dev->hbm_state = MEI_HBM_STARTED; + + if (mei_hbm_enum_clients_req(dev)) { + dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n"); + return -EIO; } wake_up_interruptible(&dev->wait_recvd_msg); - dev_dbg(&dev->pdev->dev, "host start response message received.\n"); break; case CLIENT_CONNECT_RES_CMD: + dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n"); + connect_res = (struct hbm_client_connect_response *) mei_msg; mei_hbm_cl_connect_res(dev, connect_res); - dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); wake_up(&dev->wait_recvd_msg); break; case CLIENT_DISCONNECT_RES_CMD: + dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n"); + disconnect_res = (struct hbm_client_connect_response *) mei_msg; mei_hbm_cl_disconnect_res(dev, disconnect_res); - dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); wake_up(&dev->wait_recvd_msg); break; case MEI_FLOW_CONTROL_CMD: + dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n"); + flow_control = (struct hbm_flow_control *) mei_msg; mei_hbm_cl_flow_control_res(dev, flow_control); - dev_dbg(&dev->pdev->dev, "client flow control response message received.\n"); break; case HOST_CLIENT_PROPERTIES_RES_CMD: + dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n"); + + dev->init_clients_timer = 0; + + if (dev->me_clients == NULL) { + dev_err(&dev->pdev->dev, "hbm: properties response: mei_clients not allocated\n"); + return -EPROTO; + } + props_res = (struct hbm_props_response *)mei_msg; me_client = &dev->me_clients[dev->me_client_presentation_num]; - if (props_res->status || !dev->me_clients) { - dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n"); - mei_reset(dev, 1); - return; + if (props_res->status) { + dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n", + props_res->status); + return -EPROTO; } if (me_client->client_id != props_res->address) { - dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n"); - mei_reset(dev, 1); - return; + dev_err(&dev->pdev->dev, "hbm: properties response: address mismatch %d ?= %d\n", + me_client->client_id, props_res->address); + return -EPROTO; } if (dev->dev_state != MEI_DEV_INIT_CLIENTS || dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) { - dev_err(&dev->pdev->dev, "reset: unexpected properties response\n"); - mei_reset(dev, 1); - - return; + dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n", + dev->dev_state, dev->hbm_state); + return -EPROTO; } me_client->props = props_res->client_properties; @@ -671,49 +716,70 @@ dev->me_client_presentation_num++; /* request property for the next client */ - mei_hbm_prop_req(dev); + if (mei_hbm_prop_req(dev)) + return -EIO; break; case HOST_ENUM_RES_CMD: + dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n"); + + dev->init_clients_timer = 0; + enum_res = (struct hbm_host_enum_response *) mei_msg; BUILD_BUG_ON(sizeof(dev->me_clients_map) < sizeof(enum_res->valid_addresses)); memcpy(dev->me_clients_map, enum_res->valid_addresses, sizeof(enum_res->valid_addresses)); - if (dev->dev_state == MEI_DEV_INIT_CLIENTS && - dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { - dev->init_clients_timer = 0; - mei_hbm_me_cl_allocate(dev); - dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES; - /* first property reqeust */ - mei_hbm_prop_req(dev); - } else { - dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n"); - mei_reset(dev, 1); - return; + if (dev->dev_state != MEI_DEV_INIT_CLIENTS || + dev->hbm_state != MEI_HBM_ENUM_CLIENTS) { + dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n", + dev->dev_state, dev->hbm_state); + return -EPROTO; + } + + if (mei_hbm_me_cl_allocate(dev)) { + dev_err(&dev->pdev->dev, "hbm: enumeration response: cannot allocate clients array\n"); + return -ENOMEM; } + + dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES; + + /* first property request */ + if (mei_hbm_prop_req(dev)) + return -EIO; + break; case HOST_STOP_RES_CMD: + dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n"); - if (dev->hbm_state != MEI_HBM_STOP) - dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n"); - dev->dev_state = MEI_DEV_DISABLED; - dev_info(&dev->pdev->dev, "reset: FW stop response.\n"); - mei_reset(dev, 1); + dev->init_clients_timer = 0; + + if (dev->hbm_state != MEI_HBM_STOPPED) { + dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n", + dev->dev_state, dev->hbm_state); + return -EPROTO; + } + + dev->dev_state = MEI_DEV_POWER_DOWN; + dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n"); + /* force the reset */ + return -EPROTO; break; case CLIENT_DISCONNECT_REQ_CMD: - /* search for client */ + dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n"); + disconnect_req = (struct hbm_client_connect_request *)mei_msg; mei_hbm_fw_disconnect_req(dev, disconnect_req); break; case ME_STOP_REQ_CMD: + dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n"); - dev->hbm_state = MEI_HBM_STOP; + dev->hbm_state = MEI_HBM_STOPPED; mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr, dev->wr_ext_msg.data); break; @@ -722,5 +788,6 @@ break; } + return 0; } --- linux-3.13.0.orig/drivers/misc/mei/hbm.h +++ linux-3.13.0/drivers/misc/mei/hbm.h @@ -32,13 +32,13 @@ enum mei_hbm_state { MEI_HBM_IDLE = 0, MEI_HBM_START, + MEI_HBM_STARTED, MEI_HBM_ENUM_CLIENTS, MEI_HBM_CLIENT_PROPERTIES, - MEI_HBM_STARTED, - MEI_HBM_STOP, + MEI_HBM_STOPPED, }; -void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); +int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) { @@ -49,6 +49,7 @@ hdr->reserved = 0; } +void mei_hbm_idle(struct mei_device *dev); int mei_hbm_start_req(struct mei_device *dev); int mei_hbm_start_wait(struct mei_device *dev); int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); --- linux-3.13.0.orig/drivers/misc/mei/amthif.c +++ linux-3.13.0/drivers/misc/mei/amthif.c @@ -177,7 +177,7 @@ unsigned long timeout; int i; - /* Only Posible if we are in timeout */ + /* Only possible if we are in timeout */ if (!cl || cl != &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "bad file ext.\n"); return -ETIMEDOUT; @@ -249,7 +249,7 @@ cb->response_buffer.size); dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx); - /* length is being turncated to PAGE_SIZE, however, + /* length is being truncated to PAGE_SIZE, however, * the buf_idx may point beyond */ length = min_t(size_t, length, (cb->buf_idx - *offset)); @@ -316,6 +316,7 @@ mei_hdr.host_addr = dev->iamthif_cl.host_client_id; mei_hdr.me_addr = dev->iamthif_cl.me_client_id; mei_hdr.reserved = 0; + mei_hdr.internal = 0; dev->iamthif_msg_buf_index += mei_hdr.length; ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf); if (ret) @@ -477,6 +478,7 @@ mei_hdr.host_addr = cl->host_client_id; mei_hdr.me_addr = cl->me_client_id; mei_hdr.reserved = 0; + mei_hdr.internal = 0; if (*slots >= msg_slots) { mei_hdr.length = len; --- linux-3.13.0.orig/drivers/misc/mei/hw-me.c +++ linux-3.13.0/drivers/misc/mei/hw-me.c @@ -185,7 +185,7 @@ mei_me_reg_write(hw, H_CSR, hcsr); - if (dev->dev_state == MEI_DEV_POWER_DOWN) + if (intr_enable == false) mei_me_hw_reset_release(dev); return 0; @@ -469,7 +469,7 @@ struct mei_device *dev = (struct mei_device *) dev_id; struct mei_cl_cb complete_list; s32 slots; - int rets; + int rets = 0; dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n"); /* initialize our complete list */ @@ -482,15 +482,10 @@ mei_clear_interrupts(dev); /* check if ME wants a reset */ - if (!mei_hw_is_ready(dev) && - dev->dev_state != MEI_DEV_RESETTING && - dev->dev_state != MEI_DEV_INITIALIZING && - dev->dev_state != MEI_DEV_POWER_DOWN && - dev->dev_state != MEI_DEV_POWER_UP) { - dev_dbg(&dev->pdev->dev, "FW not ready.\n"); - mei_reset(dev, 1); - mutex_unlock(&dev->device_lock); - return IRQ_HANDLED; + if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { + dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n"); + schedule_work(&dev->reset_work); + goto end; } /* check if we need to start the dev */ @@ -500,15 +495,12 @@ dev->recvd_hw_ready = true; wake_up_interruptible(&dev->wait_hw_ready); - - mutex_unlock(&dev->device_lock); - return IRQ_HANDLED; } else { + dev_dbg(&dev->pdev->dev, "Reset Completed.\n"); mei_me_hw_reset_release(dev); - mutex_unlock(&dev->device_lock); - return IRQ_HANDLED; } + goto end; } /* check slots available for reading */ slots = mei_count_full_read_slots(dev); @@ -516,21 +508,23 @@ /* we have urgent data to send so break the read */ if (dev->wr_ext_msg.hdr.length) break; - dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); - dev_dbg(&dev->pdev->dev, "call mei_irq_read_handler.\n"); + dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots); rets = mei_irq_read_handler(dev, &complete_list, &slots); - if (rets) + if (rets && dev->dev_state != MEI_DEV_RESETTING) { + schedule_work(&dev->reset_work); goto end; + } } + rets = mei_irq_write_handler(dev, &complete_list); -end: - dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); - dev->hbuf_is_ready = mei_hbuf_is_ready(dev); - mutex_unlock(&dev->device_lock); + dev->hbuf_is_ready = mei_hbuf_is_ready(dev); mei_irq_compl_handler(dev, &complete_list); +end: + dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets); + mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } static const struct mei_hw_ops mei_me_hw_ops = { --- linux-3.13.0.orig/drivers/misc/mei/client.c +++ linux-3.13.0/drivers/misc/mei/client.c @@ -154,7 +154,7 @@ return 0; } /** - * mei_io_cb_alloc_resp_buf - allocate respose buffer + * mei_io_cb_alloc_resp_buf - allocate response buffer * * @cb: io callback structure * @length: size of the buffer @@ -207,7 +207,7 @@ /** - * mei_cl_init - initializes intialize cl. + * mei_cl_init - initializes cl. * * @cl: host client to be initialized * @dev: mei device @@ -263,10 +263,10 @@ return NULL; } -/** mei_cl_link: allocte host id in the host map +/** mei_cl_link: allocate host id in the host map * * @cl - host client - * @id - fixed host id or -1 for genereting one + * @id - fixed host id or -1 for generic one * * returns 0 on success * -EINVAL on incorrect values @@ -282,19 +282,19 @@ dev = cl->dev; - /* If Id is not asigned get one*/ + /* If Id is not assigned get one*/ if (id == MEI_HOST_CLIENT_ID_ANY) id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX); if (id >= MEI_CLIENTS_MAX) { - dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ; + dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX); return -EMFILE; } open_handle_count = dev->open_handle_count + dev->iamthif_open_count; if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { - dev_err(&dev->pdev->dev, "open_handle_count exceded %d", + dev_err(&dev->pdev->dev, "open_handle_count exceeded %d", MEI_MAX_OPEN_HANDLE_COUNT); return -EMFILE; } @@ -344,8 +344,6 @@ cl->state = MEI_FILE_INITIALIZING; - list_del_init(&cl->link); - return 0; } @@ -372,13 +370,14 @@ } dev->dev_state = MEI_DEV_ENABLED; + dev->reset_count = 0; mutex_unlock(&dev->device_lock); } /** - * mei_cl_disconnect - disconnect host clinet form the me one + * mei_cl_disconnect - disconnect host client from the me one * * @cl: host client * @@ -457,7 +456,7 @@ * * @cl: private data of the file object * - * returns ture if other client is connected, 0 - otherwise. + * returns true if other client is connected, false - otherwise. */ bool mei_cl_is_other_connecting(struct mei_cl *cl) { @@ -481,7 +480,7 @@ } /** - * mei_cl_connect - connect host clinet to the me one + * mei_cl_connect - connect host client to the me one * * @cl: host client * @@ -667,7 +666,6 @@ goto err; cb->fop_type = MEI_FOP_READ; - cl->read_cb = cb; if (dev->hbuf_is_ready) { dev->hbuf_is_ready = false; if (mei_hbm_cl_flow_control_req(dev, cl)) { @@ -679,6 +677,9 @@ } else { list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } + + cl->read_cb = cb; + return rets; err: mei_io_cb_free(cb); @@ -729,6 +730,7 @@ mei_hdr.host_addr = cl->host_client_id; mei_hdr.me_addr = cl->me_client_id; mei_hdr.reserved = 0; + mei_hdr.internal = cb->internal; if (*slots >= msg_slots) { mei_hdr.length = len; @@ -775,7 +777,7 @@ * @cl: host client * @cl: write callback with filled data * - * returns numbe of bytes sent on success, <0 on failure. + * returns number of bytes sent on success, <0 on failure. */ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) { @@ -828,6 +830,7 @@ mei_hdr.host_addr = cl->host_client_id; mei_hdr.me_addr = cl->me_client_id; mei_hdr.reserved = 0; + mei_hdr.internal = cb->internal; rets = mei_write_message(dev, &mei_hdr, buf->data); @@ -907,7 +910,6 @@ list_for_each_entry_safe(cl, next, &dev->file_list, link) { cl->state = MEI_FILE_DISCONNECTED; cl->mei_flow_ctrl_creds = 0; - cl->read_cb = NULL; cl->timer_count = 0; } } @@ -941,8 +943,16 @@ void mei_cl_all_write_clear(struct mei_device *dev) { struct mei_cl_cb *cb, *next; + struct list_head *list; + + list = &dev->write_list.list; + list_for_each_entry_safe(cb, next, list, list) { + list_del(&cb->list); + mei_io_cb_free(cb); + } - list_for_each_entry_safe(cb, next, &dev->write_list.list, list) { + list = &dev->write_waiting_list.list; + list_for_each_entry_safe(cb, next, list, list) { list_del(&cb->list); mei_io_cb_free(cb); } --- linux-3.13.0.orig/drivers/misc/mei/main.c +++ linux-3.13.0/drivers/misc/mei/main.c @@ -48,7 +48,7 @@ * * @inode: pointer to inode structure * @file: pointer to file structure - e + * * returns 0 on success, <0 on error */ static int mei_open(struct inode *inode, struct file *file) --- linux-3.13.0.orig/drivers/misc/mei/hw-me-regs.h +++ linux-3.13.0/drivers/misc/mei/hw-me-regs.h @@ -115,6 +115,11 @@ #define MEI_DEV_ID_LPT_HR 0x8CBA /* Lynx Point H Refresh */ #define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */ + +/* Host Firmware Status Registers in PCI Config Space */ +#define PCI_CFG_HFS_1 0x40 +#define PCI_CFG_HFS_2 0x48 + /* * MEI HW Section */ --- linux-3.13.0.orig/drivers/misc/mei/init.c +++ linux-3.13.0/drivers/misc/mei/init.c @@ -43,41 +43,119 @@ #undef MEI_DEV_STATE } -void mei_device_init(struct mei_device *dev) -{ - /* setup our list array */ - INIT_LIST_HEAD(&dev->file_list); - INIT_LIST_HEAD(&dev->device_list); - mutex_init(&dev->device_lock); - init_waitqueue_head(&dev->wait_hw_ready); - init_waitqueue_head(&dev->wait_recvd_msg); - init_waitqueue_head(&dev->wait_stop_wd); - dev->dev_state = MEI_DEV_INITIALIZING; - mei_io_list_init(&dev->read_list); - mei_io_list_init(&dev->write_list); - mei_io_list_init(&dev->write_waiting_list); - mei_io_list_init(&dev->ctrl_wr_list); - mei_io_list_init(&dev->ctrl_rd_list); +/** + * mei_cancel_work. Cancel mei background jobs + * + * @dev: the device structure + * + * returns 0 on success or < 0 if the reset hasn't succeeded + */ +void mei_cancel_work(struct mei_device *dev) +{ + cancel_work_sync(&dev->init_work); + cancel_work_sync(&dev->reset_work); - INIT_DELAYED_WORK(&dev->timer_work, mei_timer); - INIT_WORK(&dev->init_work, mei_host_client_init); + cancel_delayed_work(&dev->timer_work); +} +EXPORT_SYMBOL_GPL(mei_cancel_work); - INIT_LIST_HEAD(&dev->wd_cl.link); - INIT_LIST_HEAD(&dev->iamthif_cl.link); - mei_io_list_init(&dev->amthif_cmd_list); - mei_io_list_init(&dev->amthif_rd_complete_list); +/** + * mei_reset - resets host and fw. + * + * @dev: the device structure + */ +int mei_reset(struct mei_device *dev) +{ + enum mei_dev_state state = dev->dev_state; + bool interrupts_enabled; + int ret; - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->open_handle_count = 0; + if (state != MEI_DEV_INITIALIZING && + state != MEI_DEV_DISABLED && + state != MEI_DEV_POWER_DOWN && + state != MEI_DEV_POWER_UP) + dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", + mei_dev_state_str(state)); - /* - * Reserving the first client ID - * 0: Reserved for MEI Bus Message communications + /* we're already in reset, cancel the init timer + * if the reset was called due the hbm protocol error + * we need to call it before hw start + * so the hbm watchdog won't kick in */ - bitmap_set(dev->host_clients_map, 0, 1); + mei_hbm_idle(dev); + + /* enter reset flow */ + interrupts_enabled = state != MEI_DEV_POWER_DOWN; + dev->dev_state = MEI_DEV_RESETTING; + + dev->reset_count++; + if (dev->reset_count > MEI_MAX_CONSEC_RESET) { + dev_err(&dev->pdev->dev, "reset: reached maximal consecutive resets: disabling the device\n"); + dev->dev_state = MEI_DEV_DISABLED; + return -ENODEV; + } + + ret = mei_hw_reset(dev, interrupts_enabled); + /* fall through and remove the sw state even if hw reset has failed */ + + /* no need to clean up software state in case of power up */ + if (state != MEI_DEV_INITIALIZING && + state != MEI_DEV_POWER_UP) { + + /* remove all waiting requests */ + mei_cl_all_write_clear(dev); + + mei_cl_all_disconnect(dev); + + /* wake up all readers and writers so they can be interrupted */ + mei_cl_all_wakeup(dev); + + /* remove entry if already in list */ + dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); + mei_cl_unlink(&dev->wd_cl); + mei_cl_unlink(&dev->iamthif_cl); + mei_amthif_reset_params(dev); + memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); + } + + + dev->me_clients_num = 0; + dev->rd_msg_hdr = 0; + dev->wd_pending = false; + + if (ret) { + dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret); + dev->dev_state = MEI_DEV_DISABLED; + return ret; + } + + if (state == MEI_DEV_POWER_DOWN) { + dev_dbg(&dev->pdev->dev, "powering down: end of reset\n"); + dev->dev_state = MEI_DEV_DISABLED; + return 0; + } + + ret = mei_hw_start(dev); + if (ret) { + dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret); + dev->dev_state = MEI_DEV_DISABLED; + return ret; + } + + dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); + + dev->dev_state = MEI_DEV_INIT_CLIENTS; + ret = mei_hbm_start_req(dev); + if (ret) { + dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret); + dev->dev_state = MEI_DEV_DISABLED; + return ret; + } + + return 0; } -EXPORT_SYMBOL_GPL(mei_device_init); +EXPORT_SYMBOL_GPL(mei_reset); /** * mei_start - initializes host and fw to start work. @@ -90,14 +168,21 @@ { mutex_lock(&dev->device_lock); - /* acknowledge interrupt and stop interupts */ + /* acknowledge interrupt and stop interrupts */ mei_clear_interrupts(dev); mei_hw_config(dev); dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); - mei_reset(dev, 1); + dev->dev_state = MEI_DEV_INITIALIZING; + dev->reset_count = 0; + mei_reset(dev); + + if (dev->dev_state == MEI_DEV_DISABLED) { + dev_err(&dev->pdev->dev, "reset failed"); + goto err; + } if (mei_hbm_start_wait(dev)) { dev_err(&dev->pdev->dev, "HBM haven't started"); @@ -132,101 +217,64 @@ EXPORT_SYMBOL_GPL(mei_start); /** - * mei_reset - resets host and fw. + * mei_restart - restart device after suspend * * @dev: the device structure - * @interrupts_enabled: if interrupt should be enabled after reset. + * + * returns 0 on success or -ENODEV if the restart hasn't succeeded */ -void mei_reset(struct mei_device *dev, int interrupts_enabled) +int mei_restart(struct mei_device *dev) { - bool unexpected; - int ret; - - unexpected = (dev->dev_state != MEI_DEV_INITIALIZING && - dev->dev_state != MEI_DEV_DISABLED && - dev->dev_state != MEI_DEV_POWER_DOWN && - dev->dev_state != MEI_DEV_POWER_UP); + int err; - if (unexpected) - dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", - mei_dev_state_str(dev->dev_state)); - - ret = mei_hw_reset(dev, interrupts_enabled); - if (ret) { - dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n"); - interrupts_enabled = false; - dev->dev_state = MEI_DEV_DISABLED; - } - - dev->hbm_state = MEI_HBM_IDLE; + mutex_lock(&dev->device_lock); - if (dev->dev_state != MEI_DEV_INITIALIZING && - dev->dev_state != MEI_DEV_POWER_UP) { - if (dev->dev_state != MEI_DEV_DISABLED && - dev->dev_state != MEI_DEV_POWER_DOWN) - dev->dev_state = MEI_DEV_RESETTING; + mei_clear_interrupts(dev); - /* remove all waiting requests */ - mei_cl_all_write_clear(dev); + dev->dev_state = MEI_DEV_POWER_UP; + dev->reset_count = 0; - mei_cl_all_disconnect(dev); + err = mei_reset(dev); - /* wake up all readings so they can be interrupted */ - mei_cl_all_wakeup(dev); - - /* remove entry if already in list */ - dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); - mei_cl_unlink(&dev->wd_cl); - mei_cl_unlink(&dev->iamthif_cl); - mei_amthif_reset_params(dev); - memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); - } + mutex_unlock(&dev->device_lock); - /* we're already in reset, cancel the init timer */ - dev->init_clients_timer = 0; + if (err || dev->dev_state == MEI_DEV_DISABLED) + return -ENODEV; - dev->me_clients_num = 0; - dev->rd_msg_hdr = 0; - dev->wd_pending = false; + return 0; +} +EXPORT_SYMBOL_GPL(mei_restart); - if (!interrupts_enabled) { - dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n"); - return; - } - ret = mei_hw_start(dev); - if (ret) { - dev_err(&dev->pdev->dev, "hw_start failed disabling the device\n"); - dev->dev_state = MEI_DEV_DISABLED; - return; - } +static void mei_reset_work(struct work_struct *work) +{ + struct mei_device *dev = + container_of(work, struct mei_device, reset_work); - dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); - /* link is established * start sending messages. */ + mutex_lock(&dev->device_lock); - dev->dev_state = MEI_DEV_INIT_CLIENTS; + mei_reset(dev); - mei_hbm_start_req(dev); + mutex_unlock(&dev->device_lock); + if (dev->dev_state == MEI_DEV_DISABLED) + dev_err(&dev->pdev->dev, "reset failed"); } -EXPORT_SYMBOL_GPL(mei_reset); void mei_stop(struct mei_device *dev) { dev_dbg(&dev->pdev->dev, "stopping the device.\n"); - flush_scheduled_work(); + mei_cancel_work(dev); - mutex_lock(&dev->device_lock); + mei_nfc_host_exit(dev); - cancel_delayed_work(&dev->timer_work); + mutex_lock(&dev->device_lock); mei_wd_stop(dev); - mei_nfc_host_exit(); - dev->dev_state = MEI_DEV_POWER_DOWN; - mei_reset(dev, 0); + mei_reset(dev); mutex_unlock(&dev->device_lock); @@ -236,3 +284,41 @@ +void mei_device_init(struct mei_device *dev) +{ + /* setup our list array */ + INIT_LIST_HEAD(&dev->file_list); + INIT_LIST_HEAD(&dev->device_list); + mutex_init(&dev->device_lock); + init_waitqueue_head(&dev->wait_hw_ready); + init_waitqueue_head(&dev->wait_recvd_msg); + init_waitqueue_head(&dev->wait_stop_wd); + dev->dev_state = MEI_DEV_INITIALIZING; + dev->reset_count = 0; + + mei_io_list_init(&dev->read_list); + mei_io_list_init(&dev->write_list); + mei_io_list_init(&dev->write_waiting_list); + mei_io_list_init(&dev->ctrl_wr_list); + mei_io_list_init(&dev->ctrl_rd_list); + + INIT_DELAYED_WORK(&dev->timer_work, mei_timer); + INIT_WORK(&dev->init_work, mei_host_client_init); + INIT_WORK(&dev->reset_work, mei_reset_work); + + INIT_LIST_HEAD(&dev->wd_cl.link); + INIT_LIST_HEAD(&dev->iamthif_cl.link); + mei_io_list_init(&dev->amthif_cmd_list); + mei_io_list_init(&dev->amthif_rd_complete_list); + + bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); + dev->open_handle_count = 0; + + /* + * Reserving the first client ID + * 0: Reserved for MEI Bus Message communications + */ + bitmap_set(dev->host_clients_map, 0, 1); +} +EXPORT_SYMBOL_GPL(mei_device_init); + --- linux-3.13.0.orig/drivers/misc/mei/interrupt.c +++ linux-3.13.0/drivers/misc/mei/interrupt.c @@ -31,7 +31,7 @@ /** - * mei_irq_compl_handler - dispatch complete handelers + * mei_irq_compl_handler - dispatch complete handlers * for the completed callbacks * * @dev - mei device @@ -301,13 +301,11 @@ struct mei_cl_cb *cmpl_list, s32 *slots) { struct mei_msg_hdr *mei_hdr; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - int ret = 0; + struct mei_cl *cl; + int ret; if (!dev->rd_msg_hdr) { dev->rd_msg_hdr = mei_read_hdr(dev); - dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); (*slots)--; dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); } @@ -315,61 +313,67 @@ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); if (mei_hdr->reserved || !dev->rd_msg_hdr) { - dev_dbg(&dev->pdev->dev, "corrupted message header.\n"); + dev_err(&dev->pdev->dev, "corrupted message header 0x%08X\n", + dev->rd_msg_hdr); ret = -EBADMSG; goto end; } - if (mei_hdr->host_addr || mei_hdr->me_addr) { - list_for_each_entry_safe(cl_pos, cl_next, - &dev->file_list, link) { - dev_dbg(&dev->pdev->dev, - "list_for_each_entry_safe read host" - " client = %d, ME client = %d\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - if (mei_cl_hbm_equal(cl_pos, mei_hdr)) - break; - } - - if (&cl_pos->link == &dev->file_list) { - dev_dbg(&dev->pdev->dev, "corrupted message header\n"); - ret = -EBADMSG; - goto end; - } - } - if (((*slots) * sizeof(u32)) < mei_hdr->length) { - dev_err(&dev->pdev->dev, - "we can't read the message slots =%08x.\n", + if (mei_slots2data(*slots) < mei_hdr->length) { + dev_err(&dev->pdev->dev, "less data available than length=%08x.\n", *slots); /* we can't read the message */ ret = -ERANGE; goto end; } - /* decide where to read the message too */ - if (!mei_hdr->host_addr) { - dev_dbg(&dev->pdev->dev, "call mei_hbm_dispatch.\n"); - mei_hbm_dispatch(dev, mei_hdr); - dev_dbg(&dev->pdev->dev, "end mei_hbm_dispatch.\n"); - } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && - (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && - (dev->iamthif_state == MEI_IAMTHIF_READING)) { + /* HBM message */ + if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) { + ret = mei_hbm_dispatch(dev, mei_hdr); + if (ret) { + dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch failed ret = %d\n", + ret); + goto end; + } + goto reset_slots; + } - dev_dbg(&dev->pdev->dev, "call mei_amthif_irq_read_msg.\n"); - dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); + /* find recipient cl */ + list_for_each_entry(cl, &dev->file_list, link) { + if (mei_cl_hbm_equal(cl, mei_hdr)) { + cl_dbg(dev, cl, "got a message\n"); + break; + } + } + + /* if no recipient cl was found we assume corrupted header */ + if (&cl->link == &dev->file_list) { + dev_err(&dev->pdev->dev, "no destination client found 0x%08X\n", + dev->rd_msg_hdr); + ret = -EBADMSG; + goto end; + } + + if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && + MEI_FILE_CONNECTED == dev->iamthif_cl.state && + dev->iamthif_state == MEI_IAMTHIF_READING) { ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); - if (ret) + if (ret) { + dev_err(&dev->pdev->dev, "mei_amthif_irq_read_msg failed = %d\n", + ret); goto end; + } } else { - dev_dbg(&dev->pdev->dev, "call mei_cl_irq_read_msg.\n"); - dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); - if (ret) + if (ret) { + dev_err(&dev->pdev->dev, "mei_cl_irq_read_msg failed = %d\n", + ret); goto end; + } } +reset_slots: /* reset the number of slots and header */ *slots = mei_count_full_read_slots(dev); dev->rd_msg_hdr = 0; @@ -533,7 +537,6 @@ * * @work: pointer to the work_struct structure * - * NOTE: This function is called by timer interrupt work */ void mei_timer(struct work_struct *work) { @@ -548,24 +551,30 @@ mutex_lock(&dev->device_lock); - if (dev->dev_state != MEI_DEV_ENABLED) { - if (dev->dev_state == MEI_DEV_INIT_CLIENTS) { - if (dev->init_clients_timer) { - if (--dev->init_clients_timer == 0) { - dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n", - dev->hbm_state); - mei_reset(dev, 1); - } + + /* Catch interrupt stalls during HBM init handshake */ + if (dev->dev_state == MEI_DEV_INIT_CLIENTS && + dev->hbm_state != MEI_HBM_IDLE) { + + if (dev->init_clients_timer) { + if (--dev->init_clients_timer == 0) { + dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n", + dev->hbm_state); + mei_reset(dev); + goto out; } } - goto out; } + + if (dev->dev_state != MEI_DEV_ENABLED) + goto out; + /*** connect/disconnect timeouts ***/ list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { if (cl_pos->timer_count) { if (--cl_pos->timer_count == 0) { - dev_err(&dev->pdev->dev, "reset: connect/disconnect timeout.\n"); - mei_reset(dev, 1); + dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n"); + mei_reset(dev); goto out; } } @@ -573,8 +582,8 @@ if (dev->iamthif_stall_timer) { if (--dev->iamthif_stall_timer == 0) { - dev_err(&dev->pdev->dev, "reset: amthif hanged.\n"); - mei_reset(dev, 1); + dev_err(&dev->pdev->dev, "timer: amthif hanged.\n"); + mei_reset(dev); dev->iamthif_msg_buf_size = 0; dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; @@ -627,7 +636,8 @@ } } out: - schedule_delayed_work(&dev->timer_work, 2 * HZ); + if (dev->dev_state != MEI_DEV_DISABLED) + schedule_delayed_work(&dev->timer_work, 2 * HZ); mutex_unlock(&dev->device_lock); } --- linux-3.13.0.orig/drivers/misc/mei/wd.c +++ linux-3.13.0/drivers/misc/mei/wd.c @@ -115,6 +115,7 @@ hdr.me_addr = dev->wd_cl.me_client_id; hdr.msg_complete = 1; hdr.reserved = 0; + hdr.internal = 0; if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE)) hdr.length = MEI_WD_START_MSG_SIZE; --- linux-3.13.0.orig/drivers/misc/mei/pci-me.c +++ linux-3.13.0/drivers/misc/mei/pci-me.c @@ -43,6 +43,9 @@ #include "hw-me.h" #include "client.h" +static bool disable_msi; +module_param(disable_msi, bool, 0); + /* mei_pci_tbl - PCI Device ID Table */ static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)}, @@ -100,15 +103,31 @@ const struct pci_device_id *ent) { u32 reg; - if (ent->device == MEI_DEV_ID_PBG_1) { - pci_read_config_dword(pdev, 0x48, ®); - /* make sure that bit 9 is up and bit 10 is down */ - if ((reg & 0x600) == 0x200) { - dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n"); - return false; - } + /* Cougar Point || Patsburg */ + if (ent->device == MEI_DEV_ID_CPT_1 || + ent->device == MEI_DEV_ID_PBG_1) { + pci_read_config_dword(pdev, PCI_CFG_HFS_2, ®); + /* make sure that bit 9 (NM) is up and bit 10 (DM) is down */ + if ((reg & 0x600) == 0x200) + goto no_mei; + } + + /* Lynx Point */ + if (ent->device == MEI_DEV_ID_LPT_H || + ent->device == MEI_DEV_ID_LPT_W || + ent->device == MEI_DEV_ID_LPT_HR) { + /* Read ME FW Status check for SPS Firmware */ + pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); + /* if bits [19:16] = 15, running SPS Firmware */ + if ((reg & 0xf0000) == 0xf0000) + goto no_mei; } + return true; + +no_mei: + dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n"); + return false; } /** * mei_probe - Device Initialization Routine @@ -144,6 +163,21 @@ dev_err(&pdev->dev, "failed to get pci regions.\n"); goto disable_device; } + + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) || + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { + + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + err = dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(32)); + } + if (err) { + dev_err(&pdev->dev, "No usable DMA configuration, aborting\n"); + goto release_regions; + } + + /* allocates and initializes the mei dev structure */ dev = mei_me_dev_init(pdev); if (!dev) { @@ -158,7 +192,8 @@ err = -ENOMEM; goto free_device; } - pci_enable_msi(pdev); + if (!disable_msi) + pci_enable_msi(pdev); /* request and enable interrupt */ if (pci_dev_msi_enabled(pdev)) @@ -197,8 +232,8 @@ return 0; release_irq: + mei_cancel_work(dev); mei_disable_interrupts(dev); - flush_scheduled_work(); free_irq(pdev->irq, dev); disable_msi: pci_disable_msi(pdev); @@ -306,16 +341,14 @@ return err; } - mutex_lock(&dev->device_lock); - dev->dev_state = MEI_DEV_POWER_UP; - mei_clear_interrupts(dev); - mei_reset(dev, 1); - mutex_unlock(&dev->device_lock); + err = mei_restart(dev); + if (err) + return err; /* Start timer if stopped in suspend */ schedule_delayed_work(&dev->timer_work, HZ); - return err; + return 0; } static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume); #define MEI_ME_PM_OPS (&mei_me_pm_ops) --- linux-3.13.0.orig/drivers/misc/mei/debugfs.c +++ linux-3.13.0/drivers/misc/mei/debugfs.c @@ -43,7 +43,7 @@ mutex_lock(&dev->device_lock); - /* if the driver is not enabled the list won't b consitent */ + /* if the driver is not enabled the list won't be consistent */ if (dev->dev_state != MEI_DEV_ENABLED) goto out; @@ -101,7 +101,7 @@ /** * mei_dbgfs_deregister - Remove the debugfs files and directories - * @mei - pointer to mei device private dat + * @mei - pointer to mei device private data */ void mei_dbgfs_deregister(struct mei_device *dev) { --- linux-3.13.0.orig/drivers/iommu/arm-smmu.c +++ linux-3.13.0/drivers/iommu/arm-smmu.c @@ -78,7 +78,6 @@ #define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES) #define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1)) -#define ARM_SMMU_PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(pte_t)) /* Stage-1 PTE */ #define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6) @@ -190,6 +189,9 @@ #define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2)) #define CBAR_VMID_SHIFT 0 #define CBAR_VMID_MASK 0xff +#define CBAR_S1_BPSHCFG_SHIFT 8 +#define CBAR_S1_BPSHCFG_MASK 3 +#define CBAR_S1_BPSHCFG_NSH 3 #define CBAR_S1_MEMATTR_SHIFT 12 #define CBAR_S1_MEMATTR_MASK 0xf #define CBAR_S1_MEMATTR_WB 0xf @@ -392,7 +394,7 @@ struct arm_smmu_cfg root_cfg; phys_addr_t output_mask; - struct mutex lock; + spinlock_t lock; }; static DEFINE_SPINLOCK(arm_smmu_devices_lock); @@ -631,6 +633,28 @@ return IRQ_HANDLED; } +static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr, + size_t size) +{ + unsigned long offset = (unsigned long)addr & ~PAGE_MASK; + + + /* Ensure new page tables are visible to the hardware walker */ + if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) { + dsb(); + } else { + /* + * If the SMMU can't walk tables in the CPU caches, treat them + * like non-coherent DMA since we need to flush the new entries + * all the way out to memory. There's no possibility of + * recursion here as the SMMU table walker will not be wired + * through another SMMU. + */ + dma_map_page(smmu->dev, virt_to_page(addr), offset, size, + DMA_TO_DEVICE); + } +} + static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) { u32 reg; @@ -649,11 +673,16 @@ if (smmu->version == 1) reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT; - /* Use the weakest memory type, so it is overridden by the pte */ - if (stage1) - reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); - else + /* + * Use the weakest shareability/memory types, so they are + * overridden by the ttbcr/pte. + */ + if (stage1) { + reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) | + (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); + } else { reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT; + } writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx)); if (smmu->version > 1) { @@ -714,6 +743,8 @@ } /* TTBR0 */ + arm_smmu_flush_pgtable(smmu, root_cfg->pgd, + PTRS_PER_PGD * sizeof(pgd_t)); reg = __pa(root_cfg->pgd); writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32; @@ -900,7 +931,7 @@ goto out_free_domain; smmu_domain->root_cfg.pgd = pgd; - mutex_init(&smmu_domain->lock); + spin_lock_init(&smmu_domain->lock); domain->priv = smmu_domain; return 0; @@ -1137,7 +1168,7 @@ * Sanity check the domain. We don't currently support domains * that cross between different SMMU chains. */ - mutex_lock(&smmu_domain->lock); + spin_lock(&smmu_domain->lock); if (!smmu_domain->leaf_smmu) { /* Now that we have a master, we can finalise the domain */ ret = arm_smmu_init_domain_context(domain, dev); @@ -1152,7 +1183,7 @@ dev_name(device_smmu->dev)); goto err_unlock; } - mutex_unlock(&smmu_domain->lock); + spin_unlock(&smmu_domain->lock); /* Looks ok, so add the device to the domain */ master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node); @@ -1162,7 +1193,7 @@ return arm_smmu_domain_add_master(smmu_domain, master); err_unlock: - mutex_unlock(&smmu_domain->lock); + spin_unlock(&smmu_domain->lock); return ret; } @@ -1176,23 +1207,6 @@ arm_smmu_domain_remove_master(smmu_domain, master); } -static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr, - size_t size) -{ - unsigned long offset = (unsigned long)addr & ~PAGE_MASK; - - /* - * If the SMMU can't walk tables in the CPU caches, treat them - * like non-coherent DMA since we need to flush the new entries - * all the way out to memory. There's no possibility of recursion - * here as the SMMU table walker will not be wired through another - * SMMU. - */ - if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)) - dma_map_page(smmu->dev, virt_to_page(addr), offset, size, - DMA_TO_DEVICE); -} - static bool arm_smmu_pte_is_contiguous_range(unsigned long addr, unsigned long end) { @@ -1209,12 +1223,11 @@ if (pmd_none(*pmd)) { /* Allocate a new set of tables */ - pgtable_t table = alloc_page(PGALLOC_GFP); + pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO); if (!table) return -ENOMEM; - arm_smmu_flush_pgtable(smmu, page_address(table), - ARM_SMMU_PTE_HWTABLE_SIZE); + arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE); if (!pgtable_page_ctor(table)) { __free_page(table); return -ENOMEM; @@ -1314,9 +1327,15 @@ #ifndef __PAGETABLE_PMD_FOLDED if (pud_none(*pud)) { - pmd = pmd_alloc_one(NULL, addr); + pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); if (!pmd) return -ENOMEM; + + arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE); + pud_populate(NULL, pud, pmd); + arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud)); + + pmd += pmd_index(addr); } else #endif pmd = pmd_offset(pud, addr); @@ -1325,8 +1344,6 @@ next = pmd_addr_end(addr, end); ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn, flags, stage); - pud_populate(NULL, pud, pmd); - arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud)); phys += next - addr; } while (pmd++, addr = next, addr < end); @@ -1343,9 +1360,15 @@ #ifndef __PAGETABLE_PUD_FOLDED if (pgd_none(*pgd)) { - pud = pud_alloc_one(NULL, addr); + pud = (pud_t *)get_zeroed_page(GFP_ATOMIC); if (!pud) return -ENOMEM; + + arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE); + pgd_populate(NULL, pgd, pud); + arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd)); + + pud += pud_index(addr); } else #endif pud = pud_offset(pgd, addr); @@ -1354,8 +1377,6 @@ next = pud_addr_end(addr, end); ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys, flags, stage); - pgd_populate(NULL, pud, pgd); - arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd)); phys += next - addr; } while (pud++, addr = next, addr < end); @@ -1394,7 +1415,7 @@ if (paddr & ~output_mask) return -ERANGE; - mutex_lock(&smmu_domain->lock); + spin_lock(&smmu_domain->lock); pgd += pgd_index(iova); end = iova + size; do { @@ -1410,11 +1431,7 @@ } while (pgd++, iova != end); out_unlock: - mutex_unlock(&smmu_domain->lock); - - /* Ensure new page tables are visible to the hardware walker */ - if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) - dsb(); + spin_unlock(&smmu_domain->lock); return ret; } --- linux-3.13.0.orig/drivers/iommu/intel-iommu.c +++ linux-3.13.0/drivers/iommu/intel-iommu.c @@ -917,7 +917,7 @@ /* If range covers entire pagetable, free it */ if (!(start_pfn > level_pfn || - last_pfn < level_pfn + level_size(level))) { + last_pfn < level_pfn + level_size(level) - 1)) { dma_clear_pte(pte); domain_flush_cache(domain, pte, sizeof(*pte)); free_pgtable_page(level_pte); --- linux-3.13.0.orig/drivers/iio/adc/max1363.c +++ linux-3.13.0/drivers/iio/adc/max1363.c @@ -1560,7 +1560,7 @@ st->client = client; st->vref_uv = st->chip_info->int_vref_mv * 1000; - vref = devm_regulator_get(&client->dev, "vref"); + vref = devm_regulator_get_optional(&client->dev, "vref"); if (!IS_ERR(vref)) { int vref_uv; --- linux-3.13.0.orig/drivers/iio/imu/adis16400.h +++ linux-3.13.0/drivers/iio/imu/adis16400.h @@ -189,6 +189,7 @@ ADIS16300_SCAN_INCLI_X, ADIS16300_SCAN_INCLI_Y, ADIS16400_SCAN_ADC, + ADIS16400_SCAN_TIMESTAMP, }; #ifdef CONFIG_IIO_BUFFER --- linux-3.13.0.orig/drivers/iio/imu/adis16400_core.c +++ linux-3.13.0/drivers/iio/imu/adis16400_core.c @@ -632,7 +632,7 @@ ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), - IIO_CHAN_SOFT_TIMESTAMP(12) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16448_channels[] = { @@ -659,7 +659,7 @@ }, }, ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(11) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16350_channels[] = { @@ -677,7 +677,7 @@ ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(11) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16300_channels[] = { @@ -690,7 +690,7 @@ ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), - IIO_CHAN_SOFT_TIMESTAMP(14) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16334_channels[] = { @@ -701,7 +701,7 @@ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(8) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static struct attribute *adis16400_attributes[] = { --- linux-3.13.0.orig/drivers/iio/gyro/st_gyro_i2c.c +++ linux-3.13.0/drivers/iio/gyro/st_gyro_i2c.c @@ -55,7 +55,6 @@ { LSM330DL_GYRO_DEV_NAME }, { LSM330DLC_GYRO_DEV_NAME }, { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, { L3G4IS_GYRO_DEV_NAME }, { LSM330_GYRO_DEV_NAME }, {}, --- linux-3.13.0.orig/drivers/iio/gyro/st_gyro_spi.c +++ linux-3.13.0/drivers/iio/gyro/st_gyro_spi.c @@ -54,7 +54,6 @@ { LSM330DL_GYRO_DEV_NAME }, { LSM330DLC_GYRO_DEV_NAME }, { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, { L3G4IS_GYRO_DEV_NAME }, { LSM330_GYRO_DEV_NAME }, {}, --- linux-3.13.0.orig/drivers/iio/gyro/st_gyro.h +++ linux-3.13.0/drivers/iio/gyro/st_gyro.h @@ -19,7 +19,6 @@ #define LSM330DL_GYRO_DEV_NAME "lsm330dl_gyro" #define LSM330DLC_GYRO_DEV_NAME "lsm330dlc_gyro" #define L3GD20_GYRO_DEV_NAME "l3gd20" -#define L3GD20H_GYRO_DEV_NAME "l3gd20h" #define L3G4IS_GYRO_DEV_NAME "l3g4is_ui" #define LSM330_GYRO_DEV_NAME "lsm330_gyro" --- linux-3.13.0.orig/drivers/iio/gyro/Kconfig +++ linux-3.13.0/drivers/iio/gyro/Kconfig @@ -70,7 +70,7 @@ select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics gyroscopes: - L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330. + L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330. This driver can also be built as a module. If so, these modules will be created: --- linux-3.13.0.orig/drivers/iio/gyro/st_gyro_core.c +++ linux-3.13.0/drivers/iio/gyro/st_gyro_core.c @@ -167,11 +167,10 @@ .wai = ST_GYRO_2_WAI_EXP, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, - [1] = L3GD20H_GYRO_DEV_NAME, - [2] = LSM330D_GYRO_DEV_NAME, - [3] = LSM330DLC_GYRO_DEV_NAME, - [4] = L3G4IS_GYRO_DEV_NAME, - [5] = LSM330_GYRO_DEV_NAME, + [1] = LSM330D_GYRO_DEV_NAME, + [2] = LSM330DLC_GYRO_DEV_NAME, + [3] = L3G4IS_GYRO_DEV_NAME, + [4] = LSM330_GYRO_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_gyro_16bit_channels, .odr = { --- linux-3.13.0.orig/drivers/iio/magnetometer/ak8975.c +++ linux-3.13.0/drivers/iio/magnetometer/ak8975.c @@ -85,6 +85,7 @@ #define AK8975_MAX_CONVERSION_TIMEOUT 500 #define AK8975_CONVERSION_DONE_POLL_TIME 10 #define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000) +#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256) /* * Per-instance context data for the device. @@ -265,15 +266,15 @@ * * Since 1uT = 0.01 gauss, our final scale factor becomes: * - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 100 - * Hadj = H * ((ASA + 128) * 30 / 256 + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100 + * Hadj = H * ((ASA + 128) * 0.003) / 256 * * Since ASA doesn't change, we cache the resultant scale factor into the * device context in ak8975_setup(). */ - data->raw_to_gauss[0] = ((data->asa[0] + 128) * 30) >> 8; - data->raw_to_gauss[1] = ((data->asa[1] + 128) * 30) >> 8; - data->raw_to_gauss[2] = ((data->asa[2] + 128) * 30) >> 8; + data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]); + data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]); + data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]); return 0; } @@ -428,8 +429,9 @@ case IIO_CHAN_INFO_RAW: return ak8975_read_axis(indio_dev, chan->address, val); case IIO_CHAN_INFO_SCALE: - *val = data->raw_to_gauss[chan->address]; - return IIO_VAL_INT; + *val = 0; + *val2 = data->raw_to_gauss[chan->address]; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } --- linux-3.13.0.orig/drivers/dma/ste_dma40.c +++ linux-3.13.0/drivers/dma/ste_dma40.c @@ -1641,6 +1641,7 @@ struct d40_chan *d40c = (struct d40_chan *) data; struct d40_desc *d40d; unsigned long flags; + bool callback_active; dma_async_tx_callback callback; void *callback_param; @@ -1668,6 +1669,7 @@ } /* Callback to client */ + callback_active = !!(d40d->txd.flags & DMA_PREP_INTERRUPT); callback = d40d->txd.callback; callback_param = d40d->txd.callback_param; @@ -1690,7 +1692,7 @@ spin_unlock_irqrestore(&d40c->lock, flags); - if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT)) + if (callback_active && callback) callback(callback_param); return; --- linux-3.13.0.orig/drivers/dma/ioat/dma.h +++ linux-3.13.0/drivers/dma/ioat/dma.h @@ -356,6 +356,7 @@ void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type); void ioat_kobject_del(struct ioatdma_device *device); int ioat_dma_setup_interrupts(struct ioatdma_device *device); +void ioat_stop(struct ioat_chan_common *chan); extern const struct sysfs_ops ioat_sysfs_ops; extern struct ioat_sysfs_entry ioat_version_attr; extern struct ioat_sysfs_entry ioat_cap_attr; --- linux-3.13.0.orig/drivers/dma/ioat/dma.c +++ linux-3.13.0/drivers/dma/ioat/dma.c @@ -77,7 +77,8 @@ attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) { chan = ioat_chan_by_index(instance, bit); - tasklet_schedule(&chan->cleanup_task); + if (test_bit(IOAT_RUN, &chan->state)) + tasklet_schedule(&chan->cleanup_task); } writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); @@ -93,7 +94,8 @@ { struct ioat_chan_common *chan = data; - tasklet_schedule(&chan->cleanup_task); + if (test_bit(IOAT_RUN, &chan->state)) + tasklet_schedule(&chan->cleanup_task); return IRQ_HANDLED; } @@ -116,7 +118,6 @@ chan->timer.function = device->timer_fn; chan->timer.data = data; tasklet_init(&chan->cleanup_task, device->cleanup_fn, data); - tasklet_disable(&chan->cleanup_task); } /** @@ -354,13 +355,49 @@ writel(((u64) chan->completion_dma) >> 32, chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); - tasklet_enable(&chan->cleanup_task); + set_bit(IOAT_RUN, &chan->state); ioat1_dma_start_null_desc(ioat); /* give chain to dma device */ dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n", __func__, ioat->desccount); return ioat->desccount; } +void ioat_stop(struct ioat_chan_common *chan) +{ + struct ioatdma_device *device = chan->device; + struct pci_dev *pdev = device->pdev; + int chan_id = chan_num(chan); + struct msix_entry *msix; + + /* 1/ stop irq from firing tasklets + * 2/ stop the tasklet from re-arming irqs + */ + clear_bit(IOAT_RUN, &chan->state); + + /* flush inflight interrupts */ + switch (device->irq_mode) { + case IOAT_MSIX: + msix = &device->msix_entries[chan_id]; + synchronize_irq(msix->vector); + break; + case IOAT_MSI: + case IOAT_INTX: + synchronize_irq(pdev->irq); + break; + default: + break; + } + + /* flush inflight timers */ + del_timer_sync(&chan->timer); + + /* flush inflight tasklet runs */ + tasklet_kill(&chan->cleanup_task); + + /* final cleanup now that everything is quiesced and can't re-arm */ + device->cleanup_fn((unsigned long) &chan->common); +} + /** * ioat1_dma_free_chan_resources - release all the descriptors * @chan: the channel to be cleaned @@ -379,9 +416,7 @@ if (ioat->desccount == 0) return; - tasklet_disable(&chan->cleanup_task); - del_timer_sync(&chan->timer); - ioat1_cleanup(ioat); + ioat_stop(chan); /* Delay 100ms after reset to allow internal DMA logic to quiesce * before removing DMA descriptor resources. @@ -526,8 +561,11 @@ static void ioat1_cleanup_event(unsigned long data) { struct ioat_dma_chan *ioat = to_ioat_chan((void *) data); + struct ioat_chan_common *chan = &ioat->base; ioat1_cleanup(ioat); + if (!test_bit(IOAT_RUN, &chan->state)) + return; writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); } --- linux-3.13.0.orig/drivers/dma/ioat/dma_v2.c +++ linux-3.13.0/drivers/dma/ioat/dma_v2.c @@ -190,8 +190,11 @@ void ioat2_cleanup_event(unsigned long data) { struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data); + struct ioat_chan_common *chan = &ioat->base; ioat2_cleanup(ioat); + if (!test_bit(IOAT_RUN, &chan->state)) + return; writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); } @@ -553,10 +556,10 @@ ioat->issued = 0; ioat->tail = 0; ioat->alloc_order = order; + set_bit(IOAT_RUN, &chan->state); spin_unlock_bh(&ioat->prep_lock); spin_unlock_bh(&chan->cleanup_lock); - tasklet_enable(&chan->cleanup_task); ioat2_start_null_desc(ioat); /* check that we got off the ground */ @@ -566,7 +569,6 @@ } while (i++ < 20 && !is_ioat_active(status) && !is_ioat_idle(status)); if (is_ioat_active(status) || is_ioat_idle(status)) { - set_bit(IOAT_RUN, &chan->state); return 1 << ioat->alloc_order; } else { u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); @@ -809,11 +811,8 @@ if (!ioat->ring) return; - tasklet_disable(&chan->cleanup_task); - del_timer_sync(&chan->timer); - device->cleanup_fn((unsigned long) c); + ioat_stop(chan); device->reset_hw(chan); - clear_bit(IOAT_RUN, &chan->state); spin_lock_bh(&chan->cleanup_lock); spin_lock_bh(&ioat->prep_lock); --- linux-3.13.0.orig/drivers/dma/ioat/dma_v3.c +++ linux-3.13.0/drivers/dma/ioat/dma_v3.c @@ -464,8 +464,11 @@ static void ioat3_cleanup_event(unsigned long data) { struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data); + struct ioat_chan_common *chan = &ioat->base; ioat3_cleanup(ioat); + if (!test_bit(IOAT_RUN, &chan->state)) + return; writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); } --- linux-3.13.0.orig/drivers/acpi/ec.c +++ linux-3.13.0/drivers/acpi/ec.c @@ -68,6 +68,8 @@ #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ +#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query + * when trying to clear the EC */ enum { EC_FLAGS_QUERY_PENDING, /* Query is pending */ @@ -121,6 +123,7 @@ static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ +static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ /* -------------------------------------------------------------------------- Transaction Management @@ -466,6 +469,29 @@ EXPORT_SYMBOL(ec_get_handle); +static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data); + +/* + * Clears stale _Q events that might have accumulated in the EC. + * Run with locked ec mutex. + */ +static void acpi_ec_clear(struct acpi_ec *ec) +{ + int i, status; + u8 value = 0; + + for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { + status = acpi_ec_query_unlocked(ec, &value); + if (status || !value) + break; + } + + if (unlikely(i == ACPI_EC_CLEAR_MAX)) + pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); + else + pr_info("%d stale EC events cleared\n", i); +} + void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -489,6 +515,10 @@ mutex_lock(&ec->mutex); /* Allow transactions to be carried out again */ clear_bit(EC_FLAGS_BLOCKED, &ec->flags); + + if (EC_FLAGS_CLEAR_ON_RESUME) + acpi_ec_clear(ec); + mutex_unlock(&ec->mutex); } @@ -847,6 +877,13 @@ /* EC is fully operational, allow queries */ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + + /* Clear stale _Q events if hardware might require that */ + if (EC_FLAGS_CLEAR_ON_RESUME) { + mutex_lock(&ec->mutex); + acpi_ec_clear(ec); + mutex_unlock(&ec->mutex); + } return ret; } @@ -948,6 +985,30 @@ return 0; } +/* + * On some hardware it is necessary to clear events accumulated by the EC during + * sleep. These ECs stop reporting GPEs until they are manually polled, if too + * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) + * + * https://bugzilla.kernel.org/show_bug.cgi?id=44161 + * + * Ideally, the EC should also be instructed NOT to accumulate events during + * sleep (which Windows seems to do somehow), but the interface to control this + * behaviour is not known at this time. + * + * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx, + * however it is very likely that other Samsung models are affected. + * + * On systems which don't accumulate _Q events during sleep, this extra check + * should be harmless. + */ +static int ec_clear_on_resume(const struct dmi_system_id *id) +{ + pr_debug("Detected system needing EC poll on resume.\n"); + EC_FLAGS_CLEAR_ON_RESUME = 1; + return 0; +} + static struct dmi_system_id ec_dmi_table[] __initdata = { { ec_skip_dsdt_scan, "Compal JFL92", { @@ -991,6 +1052,9 @@ ec_validate_ecdt, "ASUS hardware", { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL}, + { + ec_clear_on_resume, "Samsung hardware", { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, {}, }; --- linux-3.13.0.orig/drivers/acpi/video.c +++ linux-3.13.0/drivers/acpi/video.c @@ -686,6 +686,7 @@ union acpi_object *o; struct acpi_video_device_brightness *br = NULL; int result = -EINVAL; + u32 value; if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " @@ -716,7 +717,12 @@ printk(KERN_ERR PREFIX "Invalid data\n"); continue; } - br->levels[count] = (u32) o->integer.value; + value = (u32) o->integer.value; + /* Skip duplicate entries */ + if (count > 2 && br->levels[count - 1] == value) + continue; + + br->levels[count] = value; if (br->levels[count] > max_level) max_level = br->levels[count]; --- linux-3.13.0.orig/drivers/acpi/pci_irq.c +++ linux-3.13.0/drivers/acpi/pci_irq.c @@ -432,6 +432,7 @@ pin_name(pin)); } + kfree(entry); return 0; } --- linux-3.13.0.orig/drivers/acpi/bus.c +++ linux-3.13.0/drivers/acpi/bus.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #include #endif @@ -576,6 +577,14 @@ goto error0; } + /* + * If the system is using ACPI then we can be reasonably + * confident that any regulators are managed by the firmware + * so tell the regulator core it has everything it needs to + * know. + */ + regulator_has_full_constraints(); + return; error0: --- linux-3.13.0.orig/drivers/acpi/resource.c +++ linux-3.13.0/drivers/acpi/resource.c @@ -77,18 +77,24 @@ switch (ares->type) { case ACPI_RESOURCE_TYPE_MEMORY24: memory24 = &ares->data.memory24; + if (!memory24->address_length) + return false; acpi_dev_get_memresource(res, memory24->minimum, memory24->address_length, memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: memory32 = &ares->data.memory32; + if (!memory32->address_length) + return false; acpi_dev_get_memresource(res, memory32->minimum, memory32->address_length, memory32->write_protect); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: fixed_memory32 = &ares->data.fixed_memory32; + if (!fixed_memory32->address_length) + return false; acpi_dev_get_memresource(res, fixed_memory32->address, fixed_memory32->address_length, fixed_memory32->write_protect); @@ -144,12 +150,16 @@ switch (ares->type) { case ACPI_RESOURCE_TYPE_IO: io = &ares->data.io; + if (!io->address_length) + return false; acpi_dev_get_ioresource(res, io->minimum, io->address_length, io->io_decode); break; case ACPI_RESOURCE_TYPE_FIXED_IO: fixed_io = &ares->data.fixed_io; + if (!fixed_io->address_length) + return false; acpi_dev_get_ioresource(res, fixed_io->address, fixed_io->address_length, ACPI_DECODE_10); --- linux-3.13.0.orig/drivers/acpi/processor_throttling.c +++ linux-3.13.0/drivers/acpi/processor_throttling.c @@ -59,6 +59,12 @@ int target_state; /* target T-state */ }; +struct acpi_processor_throttling_arg { + struct acpi_processor *pr; + int target_state; + bool force; +}; + #define THROTTLING_PRECHANGE (1) #define THROTTLING_POSTCHANGE (2) @@ -1063,16 +1069,24 @@ return 0; } +static long acpi_processor_throttling_fn(void *data) +{ + struct acpi_processor_throttling_arg *arg = data; + struct acpi_processor *pr = arg->pr; + + return pr->throttling.acpi_processor_set_throttling(pr, + arg->target_state, arg->force); +} + int acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force) { - cpumask_var_t saved_mask; int ret = 0; unsigned int i; struct acpi_processor *match_pr; struct acpi_processor_throttling *p_throttling; + struct acpi_processor_throttling_arg arg; struct throttling_tstate t_state; - cpumask_var_t online_throttling_cpus; if (!pr) return -EINVAL; @@ -1083,14 +1097,6 @@ if ((state < 0) || (state > (pr->throttling.state_count - 1))) return -EINVAL; - if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) - return -ENOMEM; - - if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) { - free_cpumask_var(saved_mask); - return -ENOMEM; - } - if (cpu_is_offline(pr->id)) { /* * the cpu pointed by pr->id is offline. Unnecessary to change @@ -1099,17 +1105,15 @@ return -ENODEV; } - cpumask_copy(saved_mask, ¤t->cpus_allowed); t_state.target_state = state; p_throttling = &(pr->throttling); - cpumask_and(online_throttling_cpus, cpu_online_mask, - p_throttling->shared_cpu_map); + /* * The throttling notifier will be called for every * affected cpu in order to get one proper T-state. * The notifier event is THROTTLING_PRECHANGE. */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { t_state.cpu = i; acpi_processor_throttling_notifier(THROTTLING_PRECHANGE, &t_state); @@ -1121,21 +1125,18 @@ * it can be called only for the cpu pointed by pr. */ if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { - /* Can't migrate to the pr->id CPU. Exit */ - ret = -ENODEV; - goto exit; - } - ret = p_throttling->acpi_processor_set_throttling(pr, - t_state.target_state, force); + arg.pr = pr; + arg.target_state = state; + arg.force = force; + ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); } else { /* * When the T-state coordination is SW_ALL or HW_ALL, * it is necessary to set T-state for every affected * cpus. */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, + p_throttling->shared_cpu_map) { match_pr = per_cpu(processors, i); /* * If the pointer is invalid, we will report the @@ -1156,13 +1157,12 @@ "on CPU %d\n", i)); continue; } - t_state.cpu = i; - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(i))) - continue; - ret = match_pr->throttling. - acpi_processor_set_throttling( - match_pr, t_state.target_state, force); + + arg.pr = match_pr; + arg.target_state = state; + arg.force = force; + ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, + &arg); } } /* @@ -1171,17 +1171,12 @@ * affected cpu to update the T-states. * The notifier event is THROTTLING_POSTCHANGE */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { t_state.cpu = i; acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE, &t_state); } - /* restore the previous state */ - /* FIXME: use work_on_cpu() */ - set_cpus_allowed_ptr(current, saved_mask); -exit: - free_cpumask_var(online_throttling_cpus); - free_cpumask_var(saved_mask); + return ret; } --- linux-3.13.0.orig/drivers/acpi/sleep.c +++ linux-3.13.0/drivers/acpi/sleep.c @@ -75,6 +75,17 @@ return 0; } +static bool acpi_sleep_state_supported(u8 sleep_state) +{ + acpi_status status; + u8 type_a, type_b; + + status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b); + return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware + || (acpi_gbl_FADT.sleep_control.address + && acpi_gbl_FADT.sleep_status.address)); +} + #ifdef CONFIG_ACPI_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; @@ -608,15 +619,9 @@ { int i; - for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) { - acpi_status status; - u8 type_a, type_b; - - status = acpi_get_sleep_type_data(i, &type_a, &type_b); - if (ACPI_SUCCESS(status)) { + for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) + if (acpi_sleep_state_supported(i)) sleep_states[i] = 1; - } - } suspend_set_ops(old_suspend_ordering ? &acpi_suspend_ops_old : &acpi_suspend_ops); @@ -747,11 +752,7 @@ static void acpi_sleep_hibernate_setup(void) { - acpi_status status; - u8 type_a, type_b; - - status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); - if (ACPI_FAILURE(status)) + if (!acpi_sleep_state_supported(ACPI_STATE_S4)) return; hibernation_set_ops(old_suspend_ordering ? @@ -800,8 +801,6 @@ int __init acpi_sleep_init(void) { - acpi_status status; - u8 type_a, type_b; char supported[ACPI_S_STATE_COUNT * 3 + 1]; char *pos = supported; int i; @@ -816,8 +815,7 @@ acpi_sleep_suspend_setup(); acpi_sleep_hibernate_setup(); - status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); - if (ACPI_SUCCESS(status)) { + if (acpi_sleep_state_supported(ACPI_STATE_S5)) { sleep_states[ACPI_STATE_S5] = 1; pm_power_off_prepare = acpi_power_off_prepare; pm_power_off = acpi_power_off; --- linux-3.13.0.orig/drivers/acpi/blacklist.c +++ linux-3.13.0/drivers/acpi/blacklist.c @@ -325,6 +325,85 @@ }, /* + * The following Lenovo models have a broken workaround in the + * acpi_video backlight implementation to meet the Windows 8 + * requirement of 101 backlight levels. Reverting to pre-Win8 + * behavior fixes the problem. + */ + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad L430", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L430"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad T430", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad T430s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad T530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T530"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad W530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad X1 Carbon", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad X230", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Lenovo ThinkPad Edge E330", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Edge E330"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "Dell Inspiron 5537", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5537"), + }, + }, + + /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. * Linux ignores it, except for the machines enumerated below. */ --- linux-3.13.0.orig/drivers/extcon/extcon-gpio.c +++ linux-3.13.0/drivers/extcon/extcon-gpio.c @@ -105,6 +105,12 @@ extcon_data->state_off = pdata->state_off; if (pdata->state_on && pdata->state_off) extcon_data->edev.print_state = extcon_gpio_print_state; + + ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN, + pdev->name); + if (ret < 0) + return ret; + if (pdata->debounce) { ret = gpio_set_debounce(extcon_data->gpio, pdata->debounce * 1000); @@ -117,11 +123,6 @@ if (ret < 0) return ret; - ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN, - pdev->name); - if (ret < 0) - goto err; - INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work); extcon_data->irq = gpio_to_irq(extcon_data->gpio); --- linux-3.13.0.orig/drivers/base/firmware_class.c +++ linux-3.13.0/drivers/base/firmware_class.c @@ -1541,6 +1541,7 @@ switch (mode) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: + case PM_RESTORE_PREPARE: kill_requests_without_uevent(); device_cache_fw_images(); break; --- linux-3.13.0.orig/drivers/eisa/eisa-bus.c +++ linux-3.13.0/drivers/eisa/eisa-bus.c @@ -275,18 +275,19 @@ } if (slot) { + edev->res[i].name = NULL; edev->res[i].start = SLOT_ADDRESS(root, slot) + (i * 0x400); edev->res[i].end = edev->res[i].start + 0xff; edev->res[i].flags = IORESOURCE_IO; } else { + edev->res[i].name = NULL; edev->res[i].start = SLOT_ADDRESS(root, slot) + EISA_VENDOR_ID_OFFSET; edev->res[i].end = edev->res[i].start + 3; edev->res[i].flags = IORESOURCE_IO | IORESOURCE_BUSY; } - dev_printk(KERN_DEBUG, &edev->dev, "%pR\n", &edev->res[i]); if (request_resource(root->res, &edev->res[i])) goto failed; } @@ -326,19 +327,20 @@ return -ENOMEM; } - if (eisa_init_device(root, edev, 0)) { + if (eisa_request_resources(root, edev, 0)) { + dev_warn(root->dev, + "EISA: Cannot allocate resource for mainboard\n"); kfree(edev); if (!root->force_probe) - return -ENODEV; + return -EBUSY; goto force_probe; } - if (eisa_request_resources(root, edev, 0)) { - dev_warn(root->dev, - "EISA: Cannot allocate resource for mainboard\n"); + if (eisa_init_device(root, edev, 0)) { + eisa_release_resources(edev); kfree(edev); if (!root->force_probe) - return -EBUSY; + return -ENODEV; goto force_probe; } @@ -361,11 +363,6 @@ continue; } - if (eisa_init_device(root, edev, i)) { - kfree(edev); - continue; - } - if (eisa_request_resources(root, edev, i)) { dev_warn(root->dev, "Cannot allocate resource for EISA slot %d\n", @@ -373,6 +370,12 @@ kfree(edev); continue; } + + if (eisa_init_device(root, edev, i)) { + eisa_release_resources(edev); + kfree(edev); + continue; + } if (edev->state == (EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED)) enabled_str = " (forced enabled)"; --- linux-3.13.0.orig/drivers/vhost/scsi.c +++ linux-3.13.0/drivers/vhost/scsi.c @@ -728,7 +728,7 @@ } se_sess = tv_nexus->tvn_se_sess; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); if (tag < 0) { pr_err("Unable to obtain tag for tcm_vhost_cmd\n"); return ERR_PTR(-ENOMEM); --- linux-3.13.0.orig/drivers/vhost/net.c +++ linux-3.13.0/drivers/vhost/net.c @@ -70,7 +70,12 @@ }; struct vhost_net_ubuf_ref { - struct kref kref; + /* refcount follows semantics similar to kref: + * 0: object is released + * 1: no outstanding ubufs + * >1: outstanding ubufs + */ + atomic_t refcount; wait_queue_head_t wait; struct vhost_virtqueue *vq; }; @@ -116,14 +121,6 @@ vhost_net_zcopy_mask |= 0x1 << vq; } -static void vhost_net_zerocopy_done_signal(struct kref *kref) -{ - struct vhost_net_ubuf_ref *ubufs; - - ubufs = container_of(kref, struct vhost_net_ubuf_ref, kref); - wake_up(&ubufs->wait); -} - static struct vhost_net_ubuf_ref * vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) { @@ -134,21 +131,24 @@ ubufs = kmalloc(sizeof(*ubufs), GFP_KERNEL); if (!ubufs) return ERR_PTR(-ENOMEM); - kref_init(&ubufs->kref); + atomic_set(&ubufs->refcount, 1); init_waitqueue_head(&ubufs->wait); ubufs->vq = vq; return ubufs; } -static void vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) +static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); + int r = atomic_sub_return(1, &ubufs->refcount); + if (unlikely(!r)) + wake_up(&ubufs->wait); + return r; } static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); - wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); + vhost_net_ubuf_put(ubufs); + wait_event(ubufs->wait, !atomic_read(&ubufs->refcount)); } static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) @@ -306,22 +306,21 @@ { struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; struct vhost_virtqueue *vq = ubufs->vq; - int cnt = atomic_read(&ubufs->kref.refcount); + int cnt; /* set len to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = success ? VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; - vhost_net_ubuf_put(ubufs); + cnt = vhost_net_ubuf_put(ubufs); /* * Trigger polling thread if guest stopped submitting new buffers: - * in this case, the refcount after decrement will eventually reach 1 - * so here it is 2. + * in this case, the refcount after decrement will eventually reach 1. * We also trigger polling periodically after each 16 packets * (the value 16 here is more or less arbitrary, it's tuned to trigger * less than 10% of times). */ - if (cnt <= 2 || !(cnt % 16)) + if (cnt <= 1 || !(cnt % 16)) vhost_poll_queue(&vq->poll); } @@ -420,7 +419,7 @@ msg.msg_control = ubuf; msg.msg_controllen = sizeof(ubuf); ubufs = nvq->ubufs; - kref_get(&ubufs->kref); + atomic_inc(&ubufs->refcount); nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV; } else { msg.msg_control = NULL; @@ -502,9 +501,13 @@ r = -ENOBUFS; goto err; } - d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg, + r = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg, ARRAY_SIZE(vq->iov) - seg, &out, &in, log, log_num); + if (unlikely(r < 0)) + goto err; + + d = r; if (d == vq->num) { r = 0; goto err; @@ -785,7 +788,7 @@ vhost_net_ubuf_put_and_wait(n->vqs[VHOST_NET_VQ_TX].ubufs); mutex_lock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); n->tx_flush = false; - kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref); + atomic_set(&n->vqs[VHOST_NET_VQ_TX].ubufs->refcount, 1); mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); } } --- linux-3.13.0.orig/drivers/mtd/nand/omap2.c +++ linux-3.13.0/drivers/mtd/nand/omap2.c @@ -1633,6 +1633,7 @@ int i; dma_cap_mask_t mask; unsigned sig; + unsigned oob_index; struct resource *res; struct mtd_part_parser_data ppdata = {}; @@ -1832,11 +1833,14 @@ (mtd->writesize / nand_chip->ecc.size); if (nand_chip->options & NAND_BUSWIDTH_16) - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; + oob_index = BADBLOCK_MARKER_LENGTH; else - ecclayout->eccpos[0] = 1; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = 1; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + /* no reserved-marker in ecclayout for this ecc-scheme */ + ecclayout->oobfree->offset = + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: @@ -1853,9 +1857,15 @@ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) { + ecclayout->eccpos[i] = oob_index; + if (((i + 1) % nand_chip->ecc.bytes) == 0) + oob_index++; + } + /* include reserved-marker in ecclayout->oobfree calculation */ + ecclayout->oobfree->offset = 1 + + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; /* software bch library is used for locating errors */ nand_chip->ecc.priv = nand_bch_init(mtd, nand_chip->ecc.size, @@ -1889,9 +1899,12 @@ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + /* reserved marker already included in ecclayout->eccbytes */ + ecclayout->oobfree->offset = + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; /* This ECC scheme requires ELM H/W block */ if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { pr_err("nand: error: could not initialize ELM\n"); @@ -1919,9 +1932,15 @@ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) { + ecclayout->eccpos[i] = oob_index; + if (((i + 1) % nand_chip->ecc.bytes) == 0) + oob_index++; + } + /* include reserved-marker in ecclayout->oobfree calculation */ + ecclayout->oobfree->offset = 1 + + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; /* software bch library is used for locating errors */ nand_chip->ecc.priv = nand_bch_init(mtd, nand_chip->ecc.size, @@ -1962,9 +1981,12 @@ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + /* reserved marker already included in ecclayout->eccbytes */ + ecclayout->oobfree->offset = + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; #else pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); @@ -1978,11 +2000,8 @@ goto return_error; } - /* populate remaining ECC layout data */ - ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH + - ecclayout->eccbytes); - for (i = 1; i < ecclayout->eccbytes; i++) - ecclayout->eccpos[i] = ecclayout->eccpos[0] + i; + /* all OOB bytes from oobfree->offset till end off OOB are free */ + ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; /* check if NAND device's OOB is enough to store ECC signatures */ if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { pr_err("not enough OOB bytes required = %d, available=%d\n", --- linux-3.13.0.orig/drivers/mtd/nand/mxc_nand.c +++ linux-3.13.0/drivers/mtd/nand/mxc_nand.c @@ -677,7 +677,6 @@ ecc_stat >>= 4; } while (--no_subpages); - mtd->ecc_stats.corrected += ret; pr_debug("%d Symbol Correctable RS-ECC Error\n", ret); return ret; --- linux-3.13.0.orig/drivers/mmc/card/block.c +++ linux-3.13.0/drivers/mmc/card/block.c @@ -1959,6 +1959,7 @@ struct mmc_card *card = md->queue.card; struct mmc_host *host = card->host; unsigned long flags; + unsigned int cmd_flags = req ? req->cmd_flags : 0; if (req && !mq->mqrq_prev->req) /* claim host only for the first request */ @@ -1974,7 +1975,7 @@ } mq->flags &= ~MMC_QUEUE_NEW_REQUEST; - if (req && req->cmd_flags & REQ_DISCARD) { + if (cmd_flags & REQ_DISCARD) { /* complete ongoing async transfer before issuing discard */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); @@ -1983,7 +1984,7 @@ ret = mmc_blk_issue_secdiscard_rq(mq, req); else ret = mmc_blk_issue_discard_rq(mq, req); - } else if (req && req->cmd_flags & REQ_FLUSH) { + } else if (cmd_flags & REQ_FLUSH) { /* complete ongoing async transfer before issuing flush */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); @@ -1999,7 +2000,7 @@ out: if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || - (req && (req->cmd_flags & MMC_REQ_SPECIAL_MASK))) + (cmd_flags & MMC_REQ_SPECIAL_MASK)) /* * Release host when there are no more requests * and after special request(discard, flush) is done. --- linux-3.13.0.orig/drivers/mmc/card/queue.c +++ linux-3.13.0/drivers/mmc/card/queue.c @@ -197,7 +197,7 @@ struct mmc_queue_req *mqrq_prev = &mq->mqrq[1]; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) - limit = dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; + limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; mq->card = card; mq->queue = blk_init_queue(mmc_request_fn, lock); --- linux-3.13.0.orig/drivers/mmc/host/sdhci-pci-o2micro.h +++ linux-3.13.0/drivers/mmc/host/sdhci-pci-o2micro.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 BayHub Technology Ltd. + * + * Authors: Peter Guo + * Adam Lee + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SDHCI_PCI_O2MICRO_H +#define __SDHCI_PCI_O2MICRO_H + +#include "sdhci-pci.h" + +/* + * O2Micro device IDs + */ + +#define PCI_DEVICE_ID_O2_SDS0 0x8420 +#define PCI_DEVICE_ID_O2_SDS1 0x8421 +#define PCI_DEVICE_ID_O2_FUJIN2 0x8520 +#define PCI_DEVICE_ID_O2_SEABIRD0 0x8620 +#define PCI_DEVICE_ID_O2_SEABIRD1 0x8621 + +/* + * O2Micro device registers + */ + +#define O2_SD_MISC_REG5 0x64 +#define O2_SD_LD0_CTRL 0x68 +#define O2_SD_DEV_CTRL 0x88 +#define O2_SD_LOCK_WP 0xD3 +#define O2_SD_TEST_REG 0xD4 +#define O2_SD_FUNC_REG0 0xDC +#define O2_SD_MULTI_VCC3V 0xEE +#define O2_SD_CLKREQ 0xEC +#define O2_SD_CAPS 0xE0 +#define O2_SD_ADMA1 0xE2 +#define O2_SD_ADMA2 0xE7 +#define O2_SD_INF_MOD 0xF1 +#define O2_SD_MISC_CTRL4 0xFC +#define O2_SD_TUNING_CTRL 0x300 +#define O2_SD_PLL_SETTING 0x304 +#define O2_SD_CLK_SETTING 0x328 +#define O2_SD_CAP_REG2 0x330 +#define O2_SD_CAP_REG0 0x334 +#define O2_SD_UHS1_CAP_SETTING 0x33C +#define O2_SD_DELAY_CTRL 0x350 +#define O2_SD_UHS2_L1_CTRL 0x35C +#define O2_SD_FUNC_REG3 0x3E0 +#define O2_SD_FUNC_REG4 0x3E4 + +#define O2_SD_VENDOR_SETTING 0x110 +#define O2_SD_VENDOR_SETTING2 0x1C8 + +extern void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip); + +extern int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot); + +extern int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip); + +extern int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip); + +#endif /* __SDHCI_PCI_O2MICRO_H */ --- linux-3.13.0.orig/drivers/mmc/host/sdhci-pci-o2micro.c +++ linux-3.13.0/drivers/mmc/host/sdhci-pci-o2micro.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2013 BayHub Technology Ltd. + * + * Authors: Peter Guo + * Adam Lee + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +#include "sdhci.h" +#include "sdhci-pci.h" +#include "sdhci-pci-o2micro.h" + +void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) +{ + u32 scratch_32; + int ret; + /* Improve write performance for SD3.0 */ + ret = pci_read_config_dword(chip->pdev, O2_SD_DEV_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~((1 << 12) | (1 << 13) | (1 << 14)); + pci_write_config_dword(chip->pdev, O2_SD_DEV_CTRL, scratch_32); + + /* Enable Link abnormal reset generating Reset */ + ret = pci_read_config_dword(chip->pdev, O2_SD_MISC_REG5, &scratch_32); + if (ret) + return; + scratch_32 &= ~((1 << 19) | (1 << 11)); + scratch_32 |= (1 << 10); + pci_write_config_dword(chip->pdev, O2_SD_MISC_REG5, scratch_32); + + /* set card power over current protection */ + ret = pci_read_config_dword(chip->pdev, O2_SD_TEST_REG, &scratch_32); + if (ret) + return; + scratch_32 |= (1 << 4); + pci_write_config_dword(chip->pdev, O2_SD_TEST_REG, scratch_32); + + /* adjust the output delay for SD mode */ + pci_write_config_dword(chip->pdev, O2_SD_DELAY_CTRL, 0x00002492); + + /* Set the output voltage setting of Aux 1.2v LDO */ + ret = pci_read_config_dword(chip->pdev, O2_SD_LD0_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~(3 << 12); + pci_write_config_dword(chip->pdev, O2_SD_LD0_CTRL, scratch_32); + + /* Set Max power supply capability of SD host */ + ret = pci_read_config_dword(chip->pdev, O2_SD_CAP_REG0, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x01FE); + scratch_32 |= 0x00CC; + pci_write_config_dword(chip->pdev, O2_SD_CAP_REG0, scratch_32); + /* Set DLL Tuning Window */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_TUNING_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x000000FF); + scratch_32 |= 0x00000066; + pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, scratch_32); + + /* Set UHS2 T_EIDLE */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_UHS2_L1_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x000000FC); + scratch_32 |= 0x00000084; + pci_write_config_dword(chip->pdev, O2_SD_UHS2_L1_CTRL, scratch_32); + + /* Set UHS2 Termination */ + ret = pci_read_config_dword(chip->pdev, O2_SD_FUNC_REG3, &scratch_32); + if (ret) + return; + scratch_32 &= ~((1 << 21) | (1 << 30)); + + /* Set RTD3 function disabled */ + scratch_32 |= ((1 << 29) | (1 << 28)); + pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32); + + /* Set L1 Entrance Timer */ + ret = pci_read_config_dword(chip->pdev, O2_SD_CAPS, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0xf0000000); + scratch_32 |= 0x30000000; + pci_write_config_dword(chip->pdev, O2_SD_CAPS, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_MISC_CTRL4, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x000f0000); + scratch_32 |= 0x00080000; + pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32); +} +EXPORT_SYMBOL_GPL(sdhci_pci_o2_fujin2_pci_init); + +int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) +{ + struct sdhci_pci_chip *chip; + struct sdhci_host *host; + u32 reg; + + chip = slot->chip; + host = slot->host; + switch (chip->pdev->device) { + case PCI_DEVICE_ID_O2_SDS0: + case PCI_DEVICE_ID_O2_SEABIRD0: + case PCI_DEVICE_ID_O2_SEABIRD1: + case PCI_DEVICE_ID_O2_SDS1: + case PCI_DEVICE_ID_O2_FUJIN2: + reg = sdhci_readl(host, O2_SD_VENDOR_SETTING); + if (reg & 0x1) + host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; + + if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) + break; + /* set dll watch dog timer */ + reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2); + reg |= (1 << 12); + sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2); + + break; + default: + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(sdhci_pci_o2_probe_slot); + +int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) +{ + int ret; + u8 scratch; + u32 scratch_32; + + switch (chip->pdev->device) { + case PCI_DEVICE_ID_O2_8220: + case PCI_DEVICE_ID_O2_8221: + case PCI_DEVICE_ID_O2_8320: + case PCI_DEVICE_ID_O2_8321: + /* This extra setup is required due to broken ADMA. */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + /* Set Multi 3 to VCC3V# */ + pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); + + /* Disable CLK_REQ# support after media DET */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_CLKREQ, &scratch); + if (ret) + return ret; + scratch |= 0x20; + pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); + + /* Choose capabilities, enable SDMA. We have to write 0x01 + * to the capabilities register first to unlock it. + */ + ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); + if (ret) + return ret; + scratch |= 0x01; + pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); + pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); + + /* Disable ADMA1/2 */ + pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); + pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); + + /* Disable the infinite transfer mode */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_INF_MOD, &scratch); + if (ret) + return ret; + scratch |= 0x08; + pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); + + /* Lock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + break; + case PCI_DEVICE_ID_O2_SDS0: + case PCI_DEVICE_ID_O2_SDS1: + case PCI_DEVICE_ID_O2_FUJIN2: + /* UnLock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + /* Set timeout CLK */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_CLK_SETTING, &scratch_32); + if (ret) + return ret; + + scratch_32 &= ~(0xFF00); + scratch_32 |= 0x07E0C800; + pci_write_config_dword(chip->pdev, + O2_SD_CLK_SETTING, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_CLKREQ, &scratch_32); + if (ret) + return ret; + scratch_32 |= 0x3; + pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_PLL_SETTING, &scratch_32); + if (ret) + return ret; + + scratch_32 &= ~(0x1F3F070E); + scratch_32 |= 0x18270106; + pci_write_config_dword(chip->pdev, + O2_SD_PLL_SETTING, scratch_32); + + /* Disable UHS1 funciton */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_CAP_REG2, &scratch_32); + if (ret) + return ret; + scratch_32 &= ~(0xE0); + pci_write_config_dword(chip->pdev, + O2_SD_CAP_REG2, scratch_32); + + if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) + sdhci_pci_o2_fujin2_pci_init(chip); + + /* Lock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + break; + case PCI_DEVICE_ID_O2_SEABIRD0: + case PCI_DEVICE_ID_O2_SEABIRD1: + /* UnLock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_FUNC_REG0, &scratch_32); + + if ((scratch_32 & 0xff000000) == 0x01000000) { + scratch_32 &= 0x0000FFFF; + scratch_32 |= 0x1F340000; + + pci_write_config_dword(chip->pdev, + O2_SD_PLL_SETTING, scratch_32); + } else { + scratch_32 &= 0x0000FFFF; + scratch_32 |= 0x2c280000; + + pci_write_config_dword(chip->pdev, + O2_SD_PLL_SETTING, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_FUNC_REG4, + &scratch_32); + scratch_32 |= (1 << 22); + pci_write_config_dword(chip->pdev, + O2_SD_FUNC_REG4, scratch_32); + } + + /* Lock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(sdhci_pci_o2_probe); + +int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) +{ + sdhci_pci_o2_probe(chip); + return 0; +} +EXPORT_SYMBOL_GPL(sdhci_pci_o2_resume); --- linux-3.13.0.orig/drivers/mmc/host/sdhci-pci.h +++ linux-3.13.0/drivers/mmc/host/sdhci-pci.h @@ -0,0 +1,78 @@ +#ifndef __SDHCI_PCI_H +#define __SDHCI_PCI_H + +/* + * PCI device IDs + */ + +#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 +#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a +#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14 +#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15 +#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16 +#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50 +#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190 +#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9 +#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa +#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb +#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5 +#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6 + +/* + * PCI registers + */ + +#define PCI_SDHCI_IFPIO 0x00 +#define PCI_SDHCI_IFDMA 0x01 +#define PCI_SDHCI_IFVENDOR 0x02 + +#define PCI_SLOT_INFO 0x40 /* 8 bits */ +#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) +#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 + +#define MAX_SLOTS 8 + +struct sdhci_pci_chip; +struct sdhci_pci_slot; + +struct sdhci_pci_fixes { + unsigned int quirks; + unsigned int quirks2; + bool allow_runtime_pm; + bool own_cd_for_runtime_pm; + + int (*probe) (struct sdhci_pci_chip *); + + int (*probe_slot) (struct sdhci_pci_slot *); + void (*remove_slot) (struct sdhci_pci_slot *, int); + + int (*suspend) (struct sdhci_pci_chip *); + int (*resume) (struct sdhci_pci_chip *); +}; + +struct sdhci_pci_slot { + struct sdhci_pci_chip *chip; + struct sdhci_host *host; + struct sdhci_pci_data *data; + + int pci_bar; + int rst_n_gpio; + int cd_gpio; + int cd_irq; + + void (*hw_reset)(struct sdhci_host *host); +}; + +struct sdhci_pci_chip { + struct pci_dev *pdev; + + unsigned int quirks; + unsigned int quirks2; + bool allow_runtime_pm; + const struct sdhci_pci_fixes *fixes; + + int num_slots; /* Slots on controller */ + struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */ +}; + +#endif /* __SDHCI_PCI_H */ --- linux-3.13.0.orig/drivers/mmc/host/omap_hsmmc.c +++ linux-3.13.0/drivers/mmc/host/omap_hsmmc.c @@ -1812,7 +1812,7 @@ host->slot_id = 0; host->mapbase = res->start + pdata->reg_offset; host->base = ioremap(host->mapbase, SZ_4K); - host->power_mode = MMC_POWER_OFF; + host->power_mode = -1; host->next_data.cookie = 1; platform_set_drvdata(pdev, host); --- linux-3.13.0.orig/drivers/mmc/host/atmel-mci.c +++ linux-3.13.0/drivers/mmc/host/atmel-mci.c @@ -1192,11 +1192,22 @@ iflags |= ATMCI_CMDRDY; cmd = mrq->cmd; cmdflags = atmci_prepare_command(slot->mmc, cmd); - atmci_send_command(host, cmd, cmdflags); + + /* + * DMA transfer should be started before sending the command to avoid + * unexpected errors especially for read operations in SDIO mode. + * Unfortunately, in PDC mode, command has to be sent before starting + * the transfer. + */ + if (host->submit_data != &atmci_submit_data_dma) + atmci_send_command(host, cmd, cmdflags); if (data) host->submit_data(host, data); + if (host->submit_data == &atmci_submit_data_dma) + atmci_send_command(host, cmd, cmdflags); + if (mrq->stop) { host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; --- linux-3.13.0.orig/drivers/mmc/host/Makefile +++ linux-3.13.0/drivers/mmc/host/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o +obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-o2micro.o obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o --- linux-3.13.0.orig/drivers/mmc/host/sdhci.c +++ linux-3.13.0/drivers/mmc/host/sdhci.c @@ -1845,12 +1845,12 @@ unsigned long timeout; int err = 0; bool requires_tuning_nonuhs = false; + unsigned long flags; host = mmc_priv(mmc); sdhci_runtime_pm_get(host); - disable_irq(host->irq); - spin_lock(&host->lock); + spin_lock_irqsave(&host->lock, flags); ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -1870,15 +1870,13 @@ requires_tuning_nonuhs) ctrl |= SDHCI_CTRL_EXEC_TUNING; else { - spin_unlock(&host->lock); - enable_irq(host->irq); + spin_unlock_irqrestore(&host->lock, flags); sdhci_runtime_pm_put(host); return 0; } if (host->ops->platform_execute_tuning) { - spin_unlock(&host->lock); - enable_irq(host->irq); + spin_unlock_irqrestore(&host->lock, flags); err = host->ops->platform_execute_tuning(host, opcode); sdhci_runtime_pm_put(host); return err; @@ -1951,15 +1949,12 @@ host->cmd = NULL; host->mrq = NULL; - spin_unlock(&host->lock); - enable_irq(host->irq); - + spin_unlock_irqrestore(&host->lock, flags); /* Wait for Buffer Read Ready interrupt */ wait_event_interruptible_timeout(host->buf_ready_int, (host->tuning_done == 1), msecs_to_jiffies(50)); - disable_irq(host->irq); - spin_lock(&host->lock); + spin_lock_irqsave(&host->lock, flags); if (!host->tuning_done) { pr_info(DRIVER_NAME ": Timeout waiting for " @@ -2034,8 +2029,7 @@ err = 0; sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); - spin_unlock(&host->lock); - enable_irq(host->irq); + spin_unlock_irqrestore(&host->lock, flags); sdhci_runtime_pm_put(host); return err; @@ -3004,7 +2998,8 @@ /* SD3.0: SDR104 is supported so (for eMMC) the caps2 * field can be promoted to support HS200. */ - mmc->caps2 |= MMC_CAP2_HS200; + if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) + mmc->caps2 |= MMC_CAP2_HS200; } else if (caps[1] & SDHCI_SUPPORT_SDR50) mmc->caps |= MMC_CAP_UHS_SDR50; --- linux-3.13.0.orig/drivers/mmc/host/sdhci-pci.c +++ linux-3.13.0/drivers/mmc/host/sdhci-pci.c @@ -27,79 +27,8 @@ #include #include "sdhci.h" - -/* - * PCI device IDs - */ -#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 -#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a -#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14 -#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15 -#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16 -#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50 -#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190 -#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9 -#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa -#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb -#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5 -#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6 - -/* - * PCI registers - */ - -#define PCI_SDHCI_IFPIO 0x00 -#define PCI_SDHCI_IFDMA 0x01 -#define PCI_SDHCI_IFVENDOR 0x02 - -#define PCI_SLOT_INFO 0x40 /* 8 bits */ -#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) -#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 - -#define MAX_SLOTS 8 - -struct sdhci_pci_chip; -struct sdhci_pci_slot; - -struct sdhci_pci_fixes { - unsigned int quirks; - unsigned int quirks2; - bool allow_runtime_pm; - - int (*probe) (struct sdhci_pci_chip *); - - int (*probe_slot) (struct sdhci_pci_slot *); - void (*remove_slot) (struct sdhci_pci_slot *, int); - - int (*suspend) (struct sdhci_pci_chip *); - int (*resume) (struct sdhci_pci_chip *); -}; - -struct sdhci_pci_slot { - struct sdhci_pci_chip *chip; - struct sdhci_host *host; - struct sdhci_pci_data *data; - - int pci_bar; - int rst_n_gpio; - int cd_gpio; - int cd_irq; - - void (*hw_reset)(struct sdhci_host *host); -}; - -struct sdhci_pci_chip { - struct pci_dev *pdev; - - unsigned int quirks; - unsigned int quirks2; - bool allow_runtime_pm; - const struct sdhci_pci_fixes *fixes; - - int num_slots; /* Slots on controller */ - struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */ -}; - +#include "sdhci-pci.h" +#include "sdhci-pci-o2micro.h" /*****************************************************************************\ * * @@ -296,6 +225,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, + .own_cd_for_runtime_pm = true, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { @@ -360,6 +290,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON, .allow_runtime_pm = true, + .own_cd_for_runtime_pm = true, }; /* Define Host controllers for Intel Merrifield platform */ @@ -381,6 +312,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_BROKEN_HS200, .probe_slot = intel_mrfl_mmc_probe_slot, }; @@ -393,65 +325,6 @@ #define O2_SD_ADMA2 0xE7 #define O2_SD_INF_MOD 0xF1 -static int o2_probe(struct sdhci_pci_chip *chip) -{ - int ret; - u8 scratch; - - switch (chip->pdev->device) { - case PCI_DEVICE_ID_O2_8220: - case PCI_DEVICE_ID_O2_8221: - case PCI_DEVICE_ID_O2_8320: - case PCI_DEVICE_ID_O2_8321: - /* This extra setup is required due to broken ADMA. */ - ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); - if (ret) - return ret; - scratch &= 0x7f; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); - - /* Set Multi 3 to VCC3V# */ - pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); - - /* Disable CLK_REQ# support after media DET */ - ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch); - if (ret) - return ret; - scratch |= 0x20; - pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); - - /* Choose capabilities, enable SDMA. We have to write 0x01 - * to the capabilities register first to unlock it. - */ - ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); - if (ret) - return ret; - scratch |= 0x01; - pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); - pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); - - /* Disable ADMA1/2 */ - pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); - pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); - - /* Disable the infinite transfer mode */ - ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch); - if (ret) - return ret; - scratch |= 0x08; - pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); - - /* Lock WP */ - ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); - if (ret) - return ret; - scratch |= 0x80; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); - } - - return 0; -} - static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) { u8 scratch; @@ -642,7 +515,10 @@ } static const struct sdhci_pci_fixes sdhci_o2 = { - .probe = o2_probe, + .probe = sdhci_pci_o2_probe, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .probe_slot = sdhci_pci_o2_probe_slot, + .resume = sdhci_pci_o2_resume, }; static const struct sdhci_pci_fixes sdhci_jmicron = { @@ -1055,6 +931,46 @@ .driver_data = (kernel_ulong_t)&sdhci_o2, }, + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_FUJIN2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_SDS0, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_SDS1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_SEABIRD0, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_SEABIRD1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, @@ -1457,6 +1373,15 @@ sdhci_pci_add_own_cd(slot); + /* + * Check if the chip needs a separate GPIO for card detect to wake up + * from runtime suspend. If it is not there, don't allow runtime PM. + * Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure. + */ + if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && + !gpio_is_valid(slot->cd_gpio)) + chip->allow_runtime_pm = false; + return slot; remove: --- linux-3.13.0.orig/drivers/mmc/host/sdhci-esdhc-imx.c +++ linux-3.13.0/drivers/mmc/host/sdhci-esdhc-imx.c @@ -558,19 +558,17 @@ struct pltfm_imx_data *imx_data = pltfm_host->priv; struct esdhc_platform_data *boarddata = &imx_data->boarddata; - u32 f_host = clk_get_rate(pltfm_host->clk); - - if (boarddata->f_max && (boarddata->f_max < f_host)) + if (boarddata->f_max && (boarddata->f_max < pltfm_host->clock)) return boarddata->f_max; else - return f_host; + return pltfm_host->clock; } static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - return clk_get_rate(pltfm_host->clk) / 256 / 16; + return pltfm_host->clock / 256 / 16; } static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, @@ -578,7 +576,7 @@ { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = pltfm_host->priv; - unsigned int host_clock = clk_get_rate(pltfm_host->clk); + unsigned int host_clock = pltfm_host->clock; int pre_div = 2; int div = 1; u32 temp, val; @@ -976,7 +974,7 @@ } pltfm_host->clk = imx_data->clk_per; - + pltfm_host->clock = clk_get_rate(pltfm_host->clk); clk_prepare_enable(imx_data->clk_per); clk_prepare_enable(imx_data->clk_ipg); clk_prepare_enable(imx_data->clk_ahb); --- linux-3.13.0.orig/drivers/mmc/core/sd.c +++ linux-3.13.0/drivers/mmc/core/sd.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -45,6 +46,13 @@ 35, 40, 45, 50, 55, 60, 70, 80, }; +static const unsigned int sd_au_size[] = { + 0, SZ_16K / 512, SZ_32K / 512, SZ_64K / 512, + SZ_128K / 512, SZ_256K / 512, SZ_512K / 512, SZ_1M / 512, + SZ_2M / 512, SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, + SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, +}; + #define UNSTUFF_BITS(resp,start,size) \ ({ \ const int __size = size; \ @@ -216,7 +224,7 @@ static int mmc_read_ssr(struct mmc_card *card) { unsigned int au, es, et, eo; - int err, i, max_au; + int err, i; u32 *ssr; if (!(card->csd.cmdclass & CCC_APP_SPEC)) { @@ -240,26 +248,25 @@ for (i = 0; i < 16; i++) ssr[i] = be32_to_cpu(ssr[i]); - /* SD3.0 increases max AU size to 64MB (0xF) from 4MB (0x9) */ - max_au = card->scr.sda_spec3 ? 0xF : 0x9; - /* * UNSTUFF_BITS only works with four u32s so we have to offset the * bitfield positions accordingly. */ au = UNSTUFF_BITS(ssr, 428 - 384, 4); - if (au > 0 && au <= max_au) { - card->ssr.au = 1 << (au + 4); - es = UNSTUFF_BITS(ssr, 408 - 384, 16); - et = UNSTUFF_BITS(ssr, 402 - 384, 6); - eo = UNSTUFF_BITS(ssr, 400 - 384, 2); - if (es && et) { - card->ssr.erase_timeout = (et * 1000) / es; - card->ssr.erase_offset = eo * 1000; + if (au) { + if (au <= 9 || card->scr.sda_spec3) { + card->ssr.au = sd_au_size[au]; + es = UNSTUFF_BITS(ssr, 408 - 384, 16); + et = UNSTUFF_BITS(ssr, 402 - 384, 6); + if (es && et) { + eo = UNSTUFF_BITS(ssr, 400 - 384, 2); + card->ssr.erase_timeout = (et * 1000) / es; + card->ssr.erase_offset = eo * 1000; + } + } else { + pr_warning("%s: SD Status: Invalid Allocation Unit size.\n", + mmc_hostname(card->host)); } - } else { - pr_warning("%s: SD Status: Invalid Allocation Unit " - "size.\n", mmc_hostname(card->host)); } out: kfree(ssr); --- linux-3.13.0.orig/drivers/target/target_core_transport.c +++ linux-3.13.0/drivers/target/target_core_transport.c @@ -568,10 +568,11 @@ { struct se_lun *lun = cmd->se_lun; - if (!lun || !cmd->lun_ref_active) + if (!lun) return; - percpu_ref_put(&lun->lun_ref); + if (cmpxchg(&cmd->lun_ref_active, true, false)) + percpu_ref_put(&lun->lun_ref); } void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) --- linux-3.13.0.orig/drivers/target/target_core_pr.c +++ linux-3.13.0/drivers/target/target_core_pr.c @@ -2009,7 +2009,7 @@ struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; sense_reason_t ret = TCM_NO_SENSE; - int pr_holder = 0; + int pr_holder = 0, type; if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); @@ -2131,6 +2131,7 @@ ret = TCM_RESERVATION_CONFLICT; goto out; } + type = pr_reg->pr_res_type; spin_lock(&pr_tmpl->registration_lock); /* @@ -2161,6 +2162,7 @@ * Release the calling I_T Nexus registration now.. */ __core_scsi3_free_registration(cmd->se_dev, pr_reg, NULL, 1); + pr_reg = NULL; /* * From spc4r17, section 5.7.11.3 Unregistering @@ -2174,8 +2176,8 @@ * RESERVATIONS RELEASED. */ if (pr_holder && - (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || - pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) { + (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || + type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) { list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list, pr_reg_list) { @@ -2194,7 +2196,8 @@ ret = core_scsi3_update_and_write_aptpl(dev, aptpl); out: - core_scsi3_put_pr_reg(pr_reg); + if (pr_reg) + core_scsi3_put_pr_reg(pr_reg); return ret; } --- linux-3.13.0.orig/drivers/target/tcm_fc/tfc_cmd.c +++ linux-3.13.0/drivers/target/tcm_fc/tfc_cmd.c @@ -438,7 +438,7 @@ struct se_session *se_sess = sess->se_sess; int tag; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); if (tag < 0) goto busy; --- linux-3.13.0.orig/drivers/target/iscsi/iscsi_target.c +++ linux-3.13.0/drivers/target/iscsi/iscsi_target.c @@ -52,7 +52,7 @@ static LIST_HEAD(g_tiqn_list); static LIST_HEAD(g_np_list); static DEFINE_SPINLOCK(tiqn_lock); -static DEFINE_SPINLOCK(np_lock); +static DEFINE_MUTEX(np_lock); static struct idr tiqn_idr; struct idr sess_idr; @@ -307,6 +307,9 @@ return false; } +/* + * Called with mutex np_lock held + */ static struct iscsi_np *iscsit_get_np( struct __kernel_sockaddr_storage *sockaddr, int network_transport) @@ -314,11 +317,10 @@ struct iscsi_np *np; bool match; - spin_lock_bh(&np_lock); list_for_each_entry(np, &g_np_list, np_list) { - spin_lock(&np->np_thread_lock); + spin_lock_bh(&np->np_thread_lock); if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { - spin_unlock(&np->np_thread_lock); + spin_unlock_bh(&np->np_thread_lock); continue; } @@ -330,13 +332,11 @@ * while iscsi_tpg_add_network_portal() is called. */ np->np_exports++; - spin_unlock(&np->np_thread_lock); - spin_unlock_bh(&np_lock); + spin_unlock_bh(&np->np_thread_lock); return np; } - spin_unlock(&np->np_thread_lock); + spin_unlock_bh(&np->np_thread_lock); } - spin_unlock_bh(&np_lock); return NULL; } @@ -350,16 +350,22 @@ struct sockaddr_in6 *sock_in6; struct iscsi_np *np; int ret; + + mutex_lock(&np_lock); + /* * Locate the existing struct iscsi_np if already active.. */ np = iscsit_get_np(sockaddr, network_transport); - if (np) + if (np) { + mutex_unlock(&np_lock); return np; + } np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL); if (!np) { pr_err("Unable to allocate memory for struct iscsi_np\n"); + mutex_unlock(&np_lock); return ERR_PTR(-ENOMEM); } @@ -382,6 +388,7 @@ ret = iscsi_target_setup_login_socket(np, sockaddr); if (ret != 0) { kfree(np); + mutex_unlock(&np_lock); return ERR_PTR(ret); } @@ -390,6 +397,7 @@ pr_err("Unable to create kthread: iscsi_np\n"); ret = PTR_ERR(np->np_thread); kfree(np); + mutex_unlock(&np_lock); return ERR_PTR(ret); } /* @@ -400,10 +408,10 @@ * point because iscsi_np has not been added to g_np_list yet. */ np->np_exports = 1; + np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; - spin_lock_bh(&np_lock); list_add_tail(&np->np_list, &g_np_list); - spin_unlock_bh(&np_lock); + mutex_unlock(&np_lock); pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", np->np_ip, np->np_port, np->np_transport->name); @@ -470,9 +478,9 @@ np->np_transport->iscsit_free_np(np); - spin_lock_bh(&np_lock); + mutex_lock(&np_lock); list_del(&np->np_list); - spin_unlock_bh(&np_lock); + mutex_unlock(&np_lock); pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n", np->np_ip, np->np_port, np->np_transport->name); @@ -777,7 +785,7 @@ spin_unlock_bh(&conn->cmd_lock); list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) { - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); iscsit_free_cmd(cmd, false); } } @@ -3700,7 +3708,7 @@ break; case ISTATE_REMOVE: spin_lock_bh(&conn->cmd_lock); - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd, false); @@ -4143,7 +4151,7 @@ spin_lock_bh(&conn->cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_increment_maxcmdsn(cmd, sess); @@ -4188,6 +4196,10 @@ iscsit_stop_timers_for_cmds(conn); iscsit_stop_nopin_response_timer(conn); iscsit_stop_nopin_timer(conn); + + if (conn->conn_transport->iscsit_wait_conn) + conn->conn_transport->iscsit_wait_conn(conn); + iscsit_free_queue_reqs_for_conn(conn); /* --- linux-3.13.0.orig/drivers/target/iscsi/iscsi_target_util.c +++ linux-3.13.0/drivers/target/iscsi/iscsi_target_util.c @@ -156,9 +156,13 @@ { struct iscsi_cmd *cmd; struct se_session *se_sess = conn->sess->se_sess; - int size, tag; + int size, tag, state = (gfp_mask & __GFP_WAIT) ? TASK_INTERRUPTIBLE : + TASK_RUNNING; + + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state); + if (tag < 0) + return NULL; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, gfp_mask); size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size)); memset(cmd, 0, size); --- linux-3.13.0.orig/drivers/target/iscsi/iscsi_target_erl2.c +++ linux-3.13.0/drivers/target/iscsi/iscsi_target_erl2.c @@ -138,7 +138,7 @@ list_for_each_entry_safe(cmd, cmd_tmp, &cr->conn_recovery_cmd_list, i_conn_node) { - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); iscsit_free_cmd(cmd, true); @@ -160,7 +160,7 @@ list_for_each_entry_safe(cmd, cmd_tmp, &cr->conn_recovery_cmd_list, i_conn_node) { - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); iscsit_free_cmd(cmd, true); @@ -216,7 +216,7 @@ } cr = cmd->cr; - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); return --cr->cmd_count; } @@ -297,7 +297,7 @@ if (!(cmd->cmd_flags & ICF_OOO_CMDSN)) continue; - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd, true); @@ -335,7 +335,7 @@ /* * Only perform connection recovery on ISCSI_OP_SCSI_CMD or * ISCSI_OP_NOOP_OUT opcodes. For all other opcodes call - * list_del(&cmd->i_conn_node); to release the command to the + * list_del_init(&cmd->i_conn_node); to release the command to the * session pool and remove it from the connection's list. * * Also stop the DataOUT timer, which will be restarted after @@ -351,7 +351,7 @@ " CID: %hu\n", cmd->iscsi_opcode, cmd->init_task_tag, cmd->cmd_sn, conn->cid); - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); @@ -371,7 +371,7 @@ */ if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); @@ -393,7 +393,7 @@ cmd->sess = conn->sess; - list_del(&cmd->i_conn_node); + list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_all_datain_reqs(cmd); --- linux-3.13.0.orig/drivers/target/iscsi/iscsi_target_nego.c +++ linux-3.13.0/drivers/target/iscsi/iscsi_target_nego.c @@ -1192,7 +1192,7 @@ */ alloc_tags: tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth); - tag_num += (tag_num / 2) + ISCSIT_EXTRA_TAGS; + tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS; tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size); --- linux-3.13.0.orig/drivers/target/iscsi/iscsi_target_tpg.c +++ linux-3.13.0/drivers/target/iscsi/iscsi_target_tpg.c @@ -137,7 +137,7 @@ list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { spin_lock(&tpg->tpg_state_lock); - if (tpg->tpg_state == TPG_STATE_FREE) { + if (tpg->tpg_state != TPG_STATE_ACTIVE) { spin_unlock(&tpg->tpg_state_lock); continue; } --- linux-3.13.0.orig/drivers/leds/leds-gpio.c +++ linux-3.13.0/drivers/leds/leds-gpio.c @@ -224,6 +224,8 @@ { .compatible = "gpio-leds", }, {}, }; + +MODULE_DEVICE_TABLE(of, of_gpio_leds_match); #else /* CONFIG_OF_GPIO */ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) { --- linux-3.13.0.orig/drivers/cpufreq/intel_pstate.c +++ linux-3.13.0/drivers/cpufreq/intel_pstate.c @@ -34,11 +34,15 @@ #define SAMPLE_COUNT 3 -#define BYT_RATIOS 0x66a +#define BYT_RATIOS 0x66a +#define BYT_VIDS 0x66b +#define BYT_TURBO_RATIOS 0x66c -#define FRAC_BITS 8 + +#define FRAC_BITS 6 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) #define fp_toint(X) ((X) >> FRAC_BITS) +#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS) static inline int32_t mul_fp(int32_t x, int32_t y) { @@ -50,10 +54,13 @@ return div_s64((int64_t)x << FRAC_BITS, (int64_t)y); } +static u64 energy_divisor; + struct sample { int32_t core_pct_busy; u64 aperf; u64 mperf; + unsigned long long tsc; int freq; }; @@ -64,6 +71,12 @@ int turbo_pstate; }; +struct vid_data { + int32_t min; + int32_t max; + int32_t ratio; +}; + struct _pid { int setpoint; int32_t integral; @@ -82,12 +95,12 @@ struct timer_list timer; struct pstate_data pstate; + struct vid_data vid; struct _pid pid; - int min_pstate_count; - u64 prev_aperf; u64 prev_mperf; + unsigned long long prev_tsc; int sample_ptr; struct sample samples[SAMPLE_COUNT]; }; @@ -106,7 +119,8 @@ int (*get_max)(void); int (*get_min)(void); int (*get_turbo)(void); - void (*set)(int pstate); + void (*set)(struct cpudata*, int pstate); + void (*get_vid)(struct cpudata *); }; struct cpu_defaults { @@ -348,7 +362,7 @@ { u64 value; rdmsrl(BYT_RATIOS, value); - return value & 0xFF; + return (value >> 8) & 0xFF; } static int byt_get_max_pstate(void) @@ -358,6 +372,49 @@ return (value >> 16) & 0xFF; } +static int byt_get_turbo_pstate(void) +{ + u64 value; + rdmsrl(BYT_TURBO_RATIOS, value); + return value & 0x3F; +} + +static void byt_set_pstate(struct cpudata *cpudata, int pstate) +{ + u64 val; + int32_t vid_fp; + u32 vid; + + val = pstate << 8; + if (limits.no_turbo) + val |= (u64)1 << 32; + + vid_fp = cpudata->vid.min + mul_fp( + int_tofp(pstate - cpudata->pstate.min_pstate), + cpudata->vid.ratio); + + vid_fp = clamp_t(int32_t, vid_fp, cpudata->vid.min, cpudata->vid.max); + vid = fp_toint(vid_fp); + + val |= vid; + + wrmsrl(MSR_IA32_PERF_CTL, val); +} + +static void byt_get_vid(struct cpudata *cpudata) +{ + u64 value; + + rdmsrl(BYT_VIDS, value); + cpudata->vid.min = int_tofp((value >> 8) & 0x7f); + cpudata->vid.max = int_tofp((value >> 16) & 0x7f); + cpudata->vid.ratio = div_fp( + cpudata->vid.max - cpudata->vid.min, + int_tofp(cpudata->pstate.max_pstate - + cpudata->pstate.min_pstate)); +} + + static int core_get_min_pstate(void) { u64 value; @@ -384,7 +441,7 @@ return ret; } -static void core_set_pstate(int pstate) +static void core_set_pstate(struct cpudata *cpudata, int pstate) { u64 val; @@ -424,8 +481,9 @@ .funcs = { .get_max = byt_get_max_pstate, .get_min = byt_get_min_pstate, - .get_turbo = byt_get_max_pstate, - .set = core_set_pstate, + .get_turbo = byt_get_turbo_pstate, + .set = byt_set_pstate, + .get_vid = byt_get_vid, }, }; @@ -462,7 +520,7 @@ cpu->pstate.current_pstate = pstate; - pstate_funcs.set(pstate); + pstate_funcs.set(cpu, pstate); } static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps) @@ -488,6 +546,9 @@ cpu->pstate.max_pstate = pstate_funcs.get_max(); cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); + if (pstate_funcs.get_vid) + pstate_funcs.get_vid(cpu); + /* * goto max pstate so we don't slow up boot if we are built-in if we are * a module we will take care of it during normal operation @@ -498,30 +559,48 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, struct sample *sample) { - u64 core_pct; - core_pct = div64_u64(int_tofp(sample->aperf * 100), - sample->mperf); - sample->freq = fp_toint(cpu->pstate.max_pstate * core_pct * 1000); + int32_t core_pct; + int32_t c0_pct; + + core_pct = div_fp(int_tofp((sample->aperf)), + int_tofp((sample->mperf))); + core_pct = mul_fp(core_pct, int_tofp(100)); + FP_ROUNDUP(core_pct); + + c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc)); + + sample->freq = fp_toint( + mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); - sample->core_pct_busy = core_pct; + sample->core_pct_busy = mul_fp(core_pct, c0_pct); } static inline void intel_pstate_sample(struct cpudata *cpu) { u64 aperf, mperf; + unsigned long long tsc; rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); + tsc = native_read_tsc(); + + aperf = aperf >> FRAC_BITS; + mperf = mperf >> FRAC_BITS; + tsc = tsc >> FRAC_BITS; + cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].mperf = mperf; + cpu->samples[cpu->sample_ptr].tsc = tsc; cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf; cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf; + cpu->samples[cpu->sample_ptr].tsc -= cpu->prev_tsc; intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]); cpu->prev_aperf = aperf; cpu->prev_mperf = mperf; + cpu->prev_tsc = tsc; } static inline void intel_pstate_set_sample_time(struct cpudata *cpu) @@ -540,7 +619,8 @@ core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy; max_pstate = int_tofp(cpu->pstate.max_pstate); current_pstate = int_tofp(cpu->pstate.current_pstate); - return mul_fp(core_busy, div_fp(max_pstate, current_pstate)); + core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); + return FP_ROUNDUP(core_busy); } static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) @@ -556,6 +636,7 @@ ctl = pid_calc(pid, busy_scaled); steps = abs(ctl); + if (ctl < 0) intel_pstate_pstate_increase(cpu, steps); else @@ -565,17 +646,23 @@ static void intel_pstate_timer_func(unsigned long __data) { struct cpudata *cpu = (struct cpudata *) __data; + struct sample *sample; + u64 energy; intel_pstate_sample(cpu); + + sample = &cpu->samples[cpu->sample_ptr]; + rdmsrl(MSR_PKG_ENERGY_STATUS, energy); + intel_pstate_adjust_busy_pstate(cpu); - if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) { - cpu->min_pstate_count++; - if (!(cpu->min_pstate_count % 5)) { - intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate); - } - } else - cpu->min_pstate_count = 0; + trace_pstate_sample(fp_toint(sample->core_pct_busy), + fp_toint(intel_pstate_get_scaled_busy(cpu)), + cpu->pstate.current_pstate, + sample->mperf, + sample->aperf, + div64_u64(energy, energy_divisor), + sample->freq); intel_pstate_set_sample_time(cpu); } @@ -740,7 +827,7 @@ .name = "intel_pstate", }; -static int __initdata no_load; +static int __initdata no_load = 1; static int intel_pstate_msrs_not_valid(void) { @@ -782,6 +869,7 @@ pstate_funcs.get_min = funcs->get_min; pstate_funcs.get_turbo = funcs->get_turbo; pstate_funcs.set = funcs->set; + pstate_funcs.get_vid = funcs->get_vid; } #if IS_ENABLED(CONFIG_ACPI) @@ -855,6 +943,7 @@ int cpu, rc = 0; const struct x86_cpu_id *id; struct cpu_defaults *cpu_info; + u64 units; if (no_load) return -ENODEV; @@ -888,8 +977,14 @@ if (rc) goto out; + rdmsrl(MSR_RAPL_POWER_UNIT, units); + energy_divisor = 1 << ((units >> 8) & 0x1f); /* bits{12:8} */ + intel_pstate_debug_expose_params(); intel_pstate_sysfs_expose_params(); + + pr_info("Consider also installing thermald for improved thermal control.\n"); + return rc; out: get_online_cpus(); @@ -913,6 +1008,8 @@ if (!strcmp(str, "disable")) no_load = 1; + else if (!strcmp(str, "enable")) + no_load = 0; return 0; } early_param("intel_pstate", intel_pstate_setup); --- linux-3.13.0.orig/drivers/cpufreq/cpufreq.c +++ linux-3.13.0/drivers/cpufreq/cpufreq.c @@ -1051,7 +1051,7 @@ goto err_set_policy_cpu; } - if (cpufreq_driver->get) { + if (cpufreq_driver->get && !cpufreq_driver->setpolicy) { policy->cur = cpufreq_driver->get(policy->cpu); if (!policy->cur) { pr_err("%s: ->get() failed\n", __func__); @@ -1447,23 +1447,16 @@ */ unsigned int cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); unsigned int ret_freq = 0; - if (cpufreq_disabled() || !cpufreq_driver) - return -ENOENT; - - BUG_ON(!policy); - - if (!down_read_trylock(&cpufreq_rwsem)) - return 0; - - down_read(&policy->rwsem); - - ret_freq = __cpufreq_get(cpu); + if (policy) { + down_read(&policy->rwsem); + ret_freq = __cpufreq_get(cpu); + up_read(&policy->rwsem); - up_read(&policy->rwsem); - up_read(&cpufreq_rwsem); + cpufreq_cpu_put(policy); + } return ret_freq; } @@ -2058,7 +2051,7 @@ * BIOS might change freq behind our back * -> ask driver for current freq and notify governors about a change */ - if (cpufreq_driver->get) { + if (cpufreq_driver->get && !cpufreq_driver->setpolicy) { new_policy.cur = cpufreq_driver->get(cpu); if (!policy->cur) { pr_debug("Driver did not initialize current freq"); @@ -2123,6 +2116,20 @@ * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************/ +static char cpufreq_driver_name[CPUFREQ_NAME_LEN]; + +static int __init cpufreq_driver_setup(char *str) +{ + strlcpy(cpufreq_driver_name, str, CPUFREQ_NAME_LEN); + return 1; +} + +/* + * Set this name to only allow one specific cpu freq driver, e.g., + * cpufreq_driver=powernow-k8 + */ +__setup("cpufreq_driver=", cpufreq_driver_setup); + /** * cpufreq_register_driver - register a CPU Frequency driver * @driver_data: A struct cpufreq_driver containing the values# @@ -2146,7 +2153,13 @@ driver_data->target)) return -EINVAL; - pr_debug("trying to register driver %s\n", driver_data->name); + pr_debug("trying to register driver %s, cpufreq_driver=%s\n", + driver_data->name, cpufreq_driver_name); + + if (cpufreq_driver_name[0]) + if (!driver_data->name || + strcmp(cpufreq_driver_name, driver_data->name)) + return -EINVAL; if (driver_data->setpolicy) driver_data->flags |= CPUFREQ_CONST_LOOPS; --- linux-3.13.0.orig/drivers/cpufreq/powernow-k8.c +++ linux-3.13.0/drivers/cpufreq/powernow-k8.c @@ -1081,7 +1081,7 @@ { struct powernow_k8_data *data; struct init_on_cpu init_on_cpu; - int rc; + int rc, cpu; smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); if (rc) @@ -1145,7 +1145,9 @@ pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); - per_cpu(powernow_data, pol->cpu) = data; + /* Point all the CPUs in this policy to the same data */ + for_each_cpu(cpu, pol->cpus) + per_cpu(powernow_data, cpu) = data; return 0; @@ -1160,6 +1162,7 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol) { struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); + int cpu; if (!data) return -EINVAL; @@ -1170,7 +1173,8 @@ kfree(data->powernow_table); kfree(data); - per_cpu(powernow_data, pol->cpu) = NULL; + for_each_cpu(cpu, pol->cpus) + per_cpu(powernow_data, cpu) = NULL; return 0; } --- linux-3.13.0.orig/drivers/rtc/rtc-xgene.c +++ linux-3.13.0/drivers/rtc/rtc-xgene.c @@ -0,0 +1,392 @@ +/* + * AppliedMicro X-Gene SoC Real Time Clock Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Author: Rameshwar Prasad Sahu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef XGENE_RTC_DEBUG +#define DRV_NAME "xgene-rtc" + +/* RTC Register Offset */ + +#define RTC_CCVR 0x00 +#define RTC_CMR 0x04 +#define RTC_CLR 0x08 +#define RTC_CCR 0x0C +#define RTC_STAT 0x10 +#define RTC_RSTAT 0x14 +#define RTC_EOI 0x18 +#define RTC_VER 0x1C + +#define RTC_CCR_WEN 0x08 +#define RTC_CCR_EN 0x04 +#define RTC_CCR_MASK 0x02 +#define RTC_CCR_IE 0x01 + +#define RTC_STAT_BIT 0x01 + +#if defined(XGENE_RTC_DEBUG) +#define XGENE_RTC_LOG(fmt...) do { printk(KERN_INFO "X-Gene RTC CSR: " fmt); } while (0) +#else +#define XGENE_RTC_LOG(fmt...) +#endif + +struct xgene_rtc_pdata { + struct rtc_device *rtc; + struct device *dev; + unsigned long alarm_time; + void __iomem *baseaddr; + int irq; + spinlock_t lock; +}; + +static u32 xgene_rtc_readl(struct xgene_rtc_pdata *pdata, u32 reg) +{ + u32 val = readl(pdata->baseaddr + reg); + XGENE_RTC_LOG("RD: 0x%p VAL: 0x%08X\n", pdata->baseaddr + reg, val); + + return val; +} + +static void xgene_rtc_writel(struct xgene_rtc_pdata *pdata, u32 reg, u32 val) +{ + writel(val, pdata->baseaddr + reg); + XGENE_RTC_LOG("WR: 0x%p VAL: 0x%08X\n", pdata->baseaddr + reg, val); +} + +static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct xgene_rtc_pdata *pdata = dev_get_drvdata(dev); + unsigned long rtc_time; + unsigned long flags; + + spin_lock_irqsave(&pdata->lock, flags); + rtc_time = (unsigned long) xgene_rtc_readl(pdata, RTC_CCVR); + spin_unlock_irqrestore(&pdata->lock, flags); + + rtc_time_to_tm(rtc_time, tm); + + pr_debug(DRV_NAME "tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + tm->tm_sec, tm->tm_min, tm->tm_hour,tm->tm_mday, + tm->tm_mon, tm->tm_year, tm->tm_wday); + + return 0; +} + +static int xgene_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct xgene_rtc_pdata *pdata = dev_get_drvdata(dev); + volatile u32 rtc_time; + volatile u32 loop_cnt = 0; + u32 cnt = (u32) secs; + unsigned long flags; + + spin_lock_irqsave(&pdata->lock, flags); + rtc_time = xgene_rtc_readl(pdata, RTC_CCVR); + xgene_rtc_writel(pdata, RTC_CLR, cnt); + + do { + rtc_time = xgene_rtc_readl(pdata, RTC_CCVR); + loop_cnt++; + udelay(100); + } while ((rtc_time != cnt) && (loop_cnt != 50000)); + + spin_unlock_irqrestore(&pdata->lock, flags); + + if (loop_cnt >= 50000) + printk("%s: Failed to load RTC counter 0x%x\n", __func__, cnt); + + return 0; +} + +static int xgene_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xgene_rtc_pdata *pdata = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&pdata->lock, flags); + rtc_time_to_tm(pdata->alarm_time, &alrm->time); + alrm->enabled = xgene_rtc_readl(pdata, RTC_CCR) & RTC_CCR_IE; + spin_unlock_irqrestore(&pdata->lock, flags); + + return 0; +} + +static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xgene_rtc_pdata *pdata = dev_get_drvdata(dev); + unsigned long rtc_time; + unsigned long alarm_time; + u32 ccr; + int ret; + unsigned long flags; + + if (pdata->irq <= 0) + return -EINVAL; + + spin_lock_irqsave(&pdata->lock, flags); + rtc_time = (unsigned long) xgene_rtc_readl(pdata, RTC_CCVR); + + ret = rtc_tm_to_time(&alrm->time, &alarm_time); + if (ret) { + spin_unlock_irqrestore(&pdata->lock, flags); + return ret; + } + + if (alarm_time < rtc_time) { + spin_unlock_irqrestore(&pdata->lock, flags); + return -EINVAL; + } + + pdata->alarm_time = alarm_time; + xgene_rtc_writel(pdata, RTC_CMR, (u32)pdata->alarm_time); + + ccr = xgene_rtc_readl(pdata, RTC_CCR); + + if (alrm->enabled) { + ccr &= ~RTC_CCR_MASK; + ccr |= RTC_CCR_IE; + } else { + ccr &= ~RTC_CCR_IE; + ccr |= RTC_CCR_MASK; + } + + xgene_rtc_writel(pdata, RTC_CCR, ccr); + + spin_unlock_irqrestore(&pdata->lock, flags); + + return 0; +} + +static int xgene_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct xgene_rtc_pdata *pdata = dev_get_drvdata(dev); + u32 reg; + + reg= xgene_rtc_readl(pdata, RTC_CCVR); + seq_printf(seq, "Current Counter Value : %u\n", reg); + + reg = xgene_rtc_readl(pdata, RTC_CMR); + seq_printf(seq, "Counter Match Value : %u\n", reg); + + reg = xgene_rtc_readl(pdata, RTC_CLR); + seq_printf(seq, "Counter Load Value : %u\n", reg); + + reg = xgene_rtc_readl(pdata, RTC_CCR); + seq_printf(seq, "Counter Control : 0x%X\n", reg); + + reg= xgene_rtc_readl(pdata, RTC_STAT); + seq_printf(seq, "Interrupt Status : 0x%X\n", reg); + + reg = xgene_rtc_readl(pdata, RTC_RSTAT); + seq_printf(seq, "Raw Interrupt Status : 0x%X\n", reg); + + reg = xgene_rtc_readl(pdata, RTC_VER); + seq_printf(seq, "RTC Component Version : 0x%X\n", reg); + + return 0; +} + +static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled) +{ + struct xgene_rtc_pdata *pdata = dev_get_drvdata(dev); + u32 ccr; + unsigned long flags; + + spin_lock_irqsave(&pdata->lock, flags); + + ccr = xgene_rtc_readl(pdata, RTC_CCR); + + if (enabled) { + ccr &= ~RTC_CCR_MASK; + ccr |= RTC_CCR_IE; + } else { + ccr &= ~RTC_CCR_IE; + ccr |= RTC_CCR_MASK; + } + + xgene_rtc_writel(pdata, RTC_CCR, ccr); + + spin_unlock_irqrestore(&pdata->lock, flags); + + return 0; +} + +static const struct rtc_class_ops xgene_rtc_ops = { + .read_time = xgene_rtc_read_time, + .set_mmss = xgene_rtc_set_mmss, + .read_alarm = xgene_rtc_read_alarm, + .set_alarm = xgene_rtc_set_alarm, + .proc = xgene_rtc_proc, + .alarm_irq_enable = xgene_rtc_alarm_irq_enable, +}; + +static irqreturn_t xgene_rtc_interrupt(int irq, void *dev_id) +{ + struct xgene_rtc_pdata *pdata = (struct xgene_rtc_pdata *) dev_id; + unsigned long events = RTC_IRQF; + unsigned long flags; + u32 rtc_stat; + u32 rtc_eoi; + + spin_lock_irqsave(&pdata->lock, flags); + + /* read interrupt*/ + rtc_stat = xgene_rtc_readl(pdata, RTC_STAT); + if (!(rtc_stat & RTC_STAT_BIT)){ + spin_unlock_irqrestore(&pdata->lock, flags); + return IRQ_NONE; + } + + /* clear interrupt */ + rtc_eoi = xgene_rtc_readl(pdata, RTC_EOI); + + events |= RTC_AF; + if (pdata->rtc) + rtc_update_irq(pdata->rtc, 1, events); + spin_unlock_irqrestore(&pdata->lock, flags); + + return IRQ_HANDLED; +} + +static int xgene_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct xgene_rtc_pdata *pdata; + struct clk *clk = NULL; + int ret; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->dev = &pdev->dev; + + pdata->baseaddr = of_iomap(pdev->dev.of_node, 0); + if (!pdata->baseaddr) { + dev_err(pdata->dev, "No RTC IO register entry in DTS\n"); + ret = -ENOMEM; + goto fail_map; + } + + pdata->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (pdata->irq > 0){ + ret = request_irq(pdata->irq, xgene_rtc_interrupt, + 0, DRV_NAME, pdata); + if (ret) { + dev_err(pdata->dev, "Failed to Register Interrupt\n"); + goto fail_request; + } + } + + clk = clk_get(pdata->dev, NULL); + if (IS_ERR(clk)) { + dev_err(pdata->dev, "Couldn't get the clock for RTC\n"); + return -ENODEV; + } + clk_prepare_enable(clk); + + /* + * turn on the clock and the crystal, etc. + */ + xgene_rtc_writel(pdata, RTC_CCR, RTC_CCR_EN); + + device_init_wakeup(&pdev->dev, 1); + + dev_set_drvdata(&pdev->dev, pdata); + + rtc = rtc_device_register(DRV_NAME, &pdev->dev, &xgene_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } + + rtc->uie_unsupported =1; + pdata->rtc = rtc; + + spin_lock_init(&pdata->lock); + + return 0; + +out: + if (pdata->rtc) + rtc_device_unregister(pdata->rtc); + + dev_set_drvdata(&pdev->dev, NULL); + free_irq(pdata->irq, pdata); + +fail_request: + irq_dispose_mapping(pdata->irq); + iounmap(pdata->baseaddr); + +fail_map: + kfree(pdata); + return ret; +} + +static int xgene_rtc_remove(struct platform_device *pdev) +{ + struct xgene_rtc_pdata *pdata = dev_get_drvdata(&pdev->dev); + + rtc_device_unregister(pdata->rtc); + pdata->rtc = NULL; + dev_set_drvdata(&pdev->dev, NULL); + + if (pdata->irq > 0) + free_irq(pdata->irq, pdata); + + irq_dispose_mapping(pdata->irq); + iounmap(pdata->baseaddr); + + return 0; +} + +static const struct of_device_id xgene_rtc_of_match[] = { + {.compatible = "apm,xgene-rtc",} , + {}, +}; + +/* Structure for a device driver */ +static struct platform_driver xgene_rtc_driver = { + .probe = xgene_rtc_probe, + .remove = xgene_rtc_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = xgene_rtc_of_match, + }, +}; + +module_platform_driver(xgene_rtc_driver); + +MODULE_DESCRIPTION("APM X-Gene RTC driver"); +MODULE_AUTHOR("Rameshwar Sahu "); +MODULE_LICENSE("GPL"); --- linux-3.13.0.orig/drivers/rtc/rtc-max8907.c +++ linux-3.13.0/drivers/rtc/rtc-max8907.c @@ -51,7 +51,7 @@ { struct max8907_rtc *rtc = data; - regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); + regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0); rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); @@ -64,7 +64,7 @@ bcd2bin(regs[RTC_YEAR1]) - 1900; tm->tm_mon = bcd2bin(regs[RTC_MONTH] & 0x1f) - 1; tm->tm_mday = bcd2bin(regs[RTC_DATE] & 0x3f); - tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07) - 1; + tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07); if (regs[RTC_HOUR] & HOUR_12) { tm->tm_hour = bcd2bin(regs[RTC_HOUR] & 0x01f); if (tm->tm_hour == 12) @@ -88,7 +88,7 @@ regs[RTC_YEAR1] = bin2bcd(low); regs[RTC_MONTH] = bin2bcd(tm->tm_mon + 1); regs[RTC_DATE] = bin2bcd(tm->tm_mday); - regs[RTC_WEEKDAY] = tm->tm_wday + 1; + regs[RTC_WEEKDAY] = tm->tm_wday; regs[RTC_HOUR] = bin2bcd(tm->tm_hour); regs[RTC_MIN] = bin2bcd(tm->tm_min); regs[RTC_SEC] = bin2bcd(tm->tm_sec); @@ -153,7 +153,7 @@ tm_to_regs(&alrm->time, regs); /* Disable alarm while we update the target time */ - ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); + ret = regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0); if (ret < 0) return ret; @@ -163,8 +163,7 @@ return ret; if (alrm->enabled) - ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, - 0x7f, 0x7f); + ret = regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x77); return ret; } --- linux-3.13.0.orig/drivers/rtc/Makefile +++ linux-3.13.0/drivers/rtc/Makefile @@ -131,5 +131,6 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o --- linux-3.13.0.orig/drivers/rtc/Kconfig +++ linux-3.13.0/drivers/rtc/Kconfig @@ -880,6 +880,17 @@ comment "on-CPU RTC drivers" +config RTC_DRV_XGENE + tristate "APM X-Gene RTC driver support" + depends on ARCH_XGENE + help + This selects the APM X-Gene SoC RTC driver support. + If you have a APM X-Gene Platform with RTC, + say Y or M here. + + If unsure, say N. + + config RTC_DRV_DAVINCI tristate "TI DaVinci RTC" depends on ARCH_DAVINCI_DM365 --- linux-3.13.0.orig/drivers/rtc/rtc-cmos.c +++ linux-3.13.0/drivers/rtc/rtc-cmos.c @@ -34,11 +34,11 @@ #include #include #include -#include #include #include #include #include +#include /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include @@ -377,6 +377,51 @@ return 0; } +/* + * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. + */ +static bool alarm_disable_quirk; + +static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) +{ + alarm_disable_quirk = true; + pr_info("rtc-cmos: BIOS has alarm-disable quirk. "); + pr_info("RTC alarms disabled\n"); + return 0; +} + +static const struct dmi_system_id rtc_quirks[] __initconst = { + /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ + { + .callback = set_alarm_disable_quirk, + .ident = "IBM Truman", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), + }, + }, + /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ + { + .callback = set_alarm_disable_quirk, + .ident = "Gigabyte GA-990XA-UD3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), + }, + }, + /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ + { + .callback = set_alarm_disable_quirk, + .ident = "Toshiba Satellite L300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), + }, + }, + {} +}; + static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -385,6 +430,9 @@ if (!is_valid_irq(cmos->irq)) return -EINVAL; + if (alarm_disable_quirk) + return 0; + spin_lock_irqsave(&rtc_lock, flags); if (enabled) @@ -1157,6 +1205,8 @@ platform_driver_registered = true; } + dmi_check_system(rtc_quirks); + if (retval == 0) return 0; --- linux-3.13.0.orig/drivers/spi/spi-bcm63xx.c +++ linux-3.13.0/drivers/spi/spi-bcm63xx.c @@ -169,8 +169,6 @@ transfer_list); } - len -= prepend_len; - init_completion(&bs->done); /* Fill in the Message control register */ --- linux-3.13.0.orig/drivers/spi/spi-fsl-dspi.c +++ linux-3.13.0/drivers/spi/spi-fsl-dspi.c @@ -421,7 +421,6 @@ static int dspi_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); struct fsl_dspi *dspi = spi_master_get_devdata(master); @@ -505,7 +504,7 @@ clk_prepare_enable(dspi->clk); init_waitqueue_head(&dspi->waitq); - platform_set_drvdata(pdev, dspi); + platform_set_drvdata(pdev, master); ret = spi_bitbang_start(&dspi->bitbang); if (ret != 0) { @@ -526,7 +525,8 @@ static int dspi_remove(struct platform_device *pdev) { - struct fsl_dspi *dspi = platform_get_drvdata(pdev); + struct spi_master *master = platform_get_drvdata(pdev); + struct fsl_dspi *dspi = spi_master_get_devdata(master); /* Disconnect from the SPI framework */ spi_bitbang_stop(&dspi->bitbang); --- linux-3.13.0.orig/drivers/spi/spi-imx.c +++ linux-3.13.0/drivers/spi/spi-imx.c @@ -925,8 +925,8 @@ spi_bitbang_stop(&spi_imx->bitbang); writel(0, spi_imx->base + MXC_CSPICTRL); - clk_disable_unprepare(spi_imx->clk_ipg); - clk_disable_unprepare(spi_imx->clk_per); + clk_unprepare(spi_imx->clk_ipg); + clk_unprepare(spi_imx->clk_per); spi_master_put(master); return 0; --- linux-3.13.0.orig/drivers/spi/spi-coldfire-qspi.c +++ linux-3.13.0/drivers/spi/spi-coldfire-qspi.c @@ -539,7 +539,8 @@ #ifdef CONFIG_PM_RUNTIME static int mcfqspi_runtime_suspend(struct device *dev) { - struct mcfqspi *mcfqspi = dev_get_drvdata(dev); + struct spi_master *master = dev_get_drvdata(dev); + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); clk_disable(mcfqspi->clk); @@ -548,7 +549,8 @@ static int mcfqspi_runtime_resume(struct device *dev) { - struct mcfqspi *mcfqspi = dev_get_drvdata(dev); + struct spi_master *master = dev_get_drvdata(dev); + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); clk_enable(mcfqspi->clk); --- linux-3.13.0.orig/drivers/spi/spi-nuc900.c +++ linux-3.13.0/drivers/spi/spi-nuc900.c @@ -363,6 +363,8 @@ init_completion(&hw->done); master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + if (hw->pdata->lsb) + master->mode_bits |= SPI_LSB_FIRST; master->num_chipselect = hw->pdata->num_cs; master->bus_num = hw->pdata->bus_num; hw->bitbang.master = hw->master; --- linux-3.13.0.orig/drivers/spi/spi-pxa2xx.c +++ linux-3.13.0/drivers/spi/spi-pxa2xx.c @@ -1066,6 +1066,8 @@ pdata->num_chipselect = 1; pdata->enable_dma = true; + pdata->tx_chan_id = -1; + pdata->rx_chan_id = -1; return pdata; } --- linux-3.13.0.orig/drivers/spi/spi-ath79.c +++ linux-3.13.0/drivers/spi/spi-ath79.c @@ -132,9 +132,9 @@ flags = GPIOF_DIR_OUT; if (spi->mode & SPI_CS_HIGH) - flags |= GPIOF_INIT_HIGH; - else flags |= GPIOF_INIT_LOW; + else + flags |= GPIOF_INIT_HIGH; status = gpio_request_one(cdata->gpio, flags, dev_name(&spi->dev)); --- linux-3.13.0.orig/drivers/char/raw.c +++ linux-3.13.0/drivers/char/raw.c @@ -190,7 +190,7 @@ struct raw_device_data *rawdev; struct block_device *bdev; - if (number <= 0 || number >= MAX_RAW_MINORS) + if (number <= 0 || number >= max_raw_minors) return -EINVAL; rawdev = &raw_devices[number]; --- linux-3.13.0.orig/drivers/char/ipmi/ipmi_kcs_sm.c +++ linux-3.13.0/drivers/char/ipmi/ipmi_kcs_sm.c @@ -118,8 +118,8 @@ #define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH /* Timeouts in microseconds. */ -#define IBF_RETRY_TIMEOUT 5000000 -#define OBF_RETRY_TIMEOUT 5000000 +#define IBF_RETRY_TIMEOUT (5*USEC_PER_SEC) +#define OBF_RETRY_TIMEOUT (5*USEC_PER_SEC) #define MAX_ERROR_RETRIES 10 #define ERROR0_OBF_WAIT_JIFFIES (2*HZ) --- linux-3.13.0.orig/drivers/char/ipmi/ipmi_smic_sm.c +++ linux-3.13.0/drivers/char/ipmi/ipmi_smic_sm.c @@ -80,7 +80,7 @@ #define SMIC_MAX_ERROR_RETRIES 3 /* Timeouts in microseconds. */ -#define SMIC_RETRY_TIMEOUT 2000000 +#define SMIC_RETRY_TIMEOUT (2*USEC_PER_SEC) /* SMIC Flags Register Bits */ #define SMIC_RX_DATA_READY 0x80 --- linux-3.13.0.orig/drivers/char/ipmi/ipmi_bt_sm.c +++ linux-3.13.0/drivers/char/ipmi/ipmi_bt_sm.c @@ -201,7 +201,7 @@ } bt->state = BT_STATE_IDLE; /* start here */ bt->complete = BT_STATE_IDLE; /* end here */ - bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * 1000000; + bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * USEC_PER_SEC; bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT; /* BT_CAP_outreqs == zero is a flag to read BT Capabilities */ return 3; /* We claim 3 bytes of space; ought to check SPMI table */ @@ -613,7 +613,7 @@ HOST2BMC(42); /* Sequence number */ HOST2BMC(3); /* Cmd == Soft reset */ BT_CONTROL(BT_H2B_ATN); - bt->timeout = BT_RESET_DELAY * 1000000; + bt->timeout = BT_RESET_DELAY * USEC_PER_SEC; BT_STATE_CHANGE(BT_STATE_RESET3, SI_SM_CALL_WITH_DELAY); @@ -651,14 +651,14 @@ bt_init_data(bt, bt->io); if ((i == 8) && !BT_CAP[2]) { bt->BT_CAP_outreqs = BT_CAP[3]; - bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000; + bt->BT_CAP_req2rsp = BT_CAP[6] * USEC_PER_SEC; bt->BT_CAP_retries = BT_CAP[7]; } else printk(KERN_WARNING "IPMI BT: using default values\n"); if (!bt->BT_CAP_outreqs) bt->BT_CAP_outreqs = 1; printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n", - bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries); + bt->BT_CAP_req2rsp / USEC_PER_SEC, bt->BT_CAP_retries); bt->timeout = bt->BT_CAP_req2rsp; return SI_SM_CALL_WITHOUT_DELAY; --- linux-3.13.0.orig/drivers/char/ipmi/ipmi_si_intf.c +++ linux-3.13.0/drivers/char/ipmi/ipmi_si_intf.c @@ -1358,7 +1358,7 @@ if (info->si_type == SI_BT) { rv = request_irq(info->irq, si_bt_irq_handler, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, DEVICE_NAME, info); if (!rv) @@ -1368,7 +1368,7 @@ } else rv = request_irq(info->irq, si_irq_handler, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, DEVICE_NAME, info); if (rv) { @@ -1849,11 +1849,15 @@ info->irq_setup = std_irq_setup; info->slave_addr = ipmb; - if (!add_smi(info)) { - if (try_smi_init(info)) - cleanup_one_si(info); - } else { + rv = add_smi(info); + if (rv) { kfree(info); + goto out; + } + rv = try_smi_init(info); + if (rv) { + cleanup_one_si(info); + goto out; } } else { /* remove */ @@ -2067,6 +2071,7 @@ static int try_init_spmi(struct SPMITable *spmi) { struct smi_info *info; + int rv; if (spmi->IPMIlegacy != 1) { printk(KERN_INFO PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); @@ -2141,10 +2146,11 @@ info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - if (add_smi(info)) + rv = add_smi(info); + if (rv) kfree(info); - return 0; + return rv; } static void spmi_find_bmc(void) @@ -2178,6 +2184,7 @@ acpi_handle handle; acpi_status status; unsigned long long tmp; + int rv; acpi_dev = pnp_acpi_device(dev); if (!acpi_dev) @@ -2259,10 +2266,11 @@ res, info->io.regsize, info->io.regspacing, info->irq); - if (add_smi(info)) - goto err_free; + rv = add_smi(info); + if (rv) + kfree(info); - return 0; + return rv; err_free: kfree(info); @@ -2566,16 +2574,20 @@ &pdev->resource[0], info->io.regsize, info->io.regspacing, info->irq); - if (add_smi(info)) + rv = add_smi(info); + if (rv) { kfree(info); + pci_disable_device(pdev); + } - return 0; + return rv; } static void ipmi_pci_remove(struct pci_dev *pdev) { struct smi_info *info = pci_get_drvdata(pdev); cleanup_one_si(info); + pci_disable_device(pdev); } static struct pci_device_id ipmi_pci_devices[] = { @@ -2670,9 +2682,10 @@ dev_set_drvdata(&dev->dev, info); - if (add_smi(info)) { + ret = add_smi(info); + if (ret) { kfree(info); - return -EBUSY; + return ret; } #endif return 0; @@ -2711,6 +2724,7 @@ static int ipmi_parisc_probe(struct parisc_device *dev) { struct smi_info *info; + int rv; info = smi_info_alloc(); @@ -2736,9 +2750,10 @@ dev_set_drvdata(&dev->dev, info); - if (add_smi(info)) { + rv = add_smi(info); + if (rv) { kfree(info); - return -EBUSY; + return rv; } return 0; @@ -2773,7 +2788,7 @@ smi_result == SI_SM_CALL_WITH_TICK_DELAY) { schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( - smi_info->si_sm, 100); + smi_info->si_sm, jiffies_to_usecs(1)); } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { smi_result = smi_info->handlers->event( smi_info->si_sm, 0); --- linux-3.13.0.orig/drivers/char/tpm/tpm_i2c_stm_st33.c +++ linux-3.13.0/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -410,6 +410,8 @@ &chip->vendor.read_queue) == 0) { burstcnt = get_burstcount(chip); + if (burstcnt < 0) + return burstcnt; len = min_t(int, burstcnt, count - size); I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len); size += len; @@ -451,7 +453,8 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, size_t len) { - u32 status, burstcnt = 0, i, size; + u32 status, i, size; + int burstcnt = 0; int ret; u8 data; struct i2c_client *client; @@ -482,6 +485,8 @@ for (i = 0; i < len - 1;) { burstcnt = get_burstcount(chip); + if (burstcnt < 0) + return burstcnt; size = min_t(int, len - i - 1, burstcnt); ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size); if (ret < 0) --- linux-3.13.0.orig/drivers/char/tpm/tpm_ppi.c +++ linux-3.13.0/drivers/char/tpm/tpm_ppi.c @@ -172,7 +172,7 @@ * is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ - if (strcmp(version, "1.1") == -1) + if (strcmp(version, "1.1") < 0) params[2].integer.value = TPM_PPI_FN_SUBREQ; else params[2].integer.value = TPM_PPI_FN_SUBREQ2; @@ -182,7 +182,7 @@ * string/package type. For PPI version 1.0 and 1.1, use buffer type * for compatibility, and use package type since 1.2 according to spec. */ - if (strcmp(version, "1.2") == -1) { + if (strcmp(version, "1.2") < 0) { params[3].type = ACPI_TYPE_BUFFER; params[3].buffer.length = sizeof(req); sscanf(buf, "%d", &req); @@ -248,7 +248,7 @@ * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for * compatibility, define params[3].type as buffer, if PPI version < 1.2 */ - if (strcmp(version, "1.2") == -1) { + if (strcmp(version, "1.2") < 0) { params[3].type = ACPI_TYPE_BUFFER; params[3].buffer.length = 0; params[3].buffer.pointer = NULL; @@ -390,7 +390,7 @@ kfree(output.pointer); output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; - if (strcmp(version, "1.2") == -1) + if (strcmp(version, "1.2") < 0) return -EPERM; params[2].integer.value = TPM_PPI_FN_GETOPR; --- linux-3.13.0.orig/drivers/char/tpm/xen-tpmfront.c +++ linux-3.13.0/drivers/char/tpm/xen-tpmfront.c @@ -17,6 +17,7 @@ #include #include #include "tpm.h" +#include struct tpm_private { struct tpm_chip *chip; @@ -421,6 +422,9 @@ if (!xen_domain()) return -ENODEV; + if (!xen_has_pv_devices()) + return -ENODEV; + return xenbus_register_frontend(&tpmfront_driver); } module_init(xen_tpmfront_init); --- linux-3.13.0.orig/drivers/video/xen-fbfront.c +++ linux-3.13.0/drivers/video/xen-fbfront.c @@ -35,6 +35,7 @@ #include #include #include +#include struct xenfb_info { unsigned char *fb; @@ -699,6 +700,9 @@ if (xen_initial_domain()) return -ENODEV; + if (!xen_has_pv_devices()) + return -ENODEV; + return xenbus_register_frontend(&xenfb_driver); } --- linux-3.13.0.orig/drivers/video/hyperv_fb.c +++ linux-3.13.0/drivers/video/hyperv_fb.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -212,6 +213,7 @@ struct hvfb_par { struct fb_info *info; + struct resource mem; bool fb_ready; /* fb device is ready */ struct completion wait; u32 synthvid_version; @@ -460,13 +462,13 @@ goto error; } - if (par->synthvid_version == SYNTHVID_VERSION_WIN7) { + if (par->synthvid_version == SYNTHVID_VERSION_WIN7) screen_depth = SYNTHVID_DEPTH_WIN7; - screen_fb_size = SYNTHVID_FB_SIZE_WIN7; - } else { + else screen_depth = SYNTHVID_DEPTH_WIN8; - screen_fb_size = SYNTHVID_FB_SIZE_WIN8; - } + + screen_fb_size = hdev->channel->offermsg.offer. + mmio_megabytes * 1024 * 1024; return 0; @@ -627,26 +629,46 @@ /* Get framebuffer memory from Hyper-V video pci space */ static int hvfb_getmem(struct fb_info *info) { - struct pci_dev *pdev; - ulong fb_phys; + struct hvfb_par *par = info->par; + struct pci_dev *pdev = NULL; void __iomem *fb_virt; + int gen2vm = efi_enabled(EFI_BOOT); + int ret; - pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, + par->mem.name = KBUILD_MODNAME; + par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (gen2vm) { + ret = allocate_resource(&hyperv_mmio, &par->mem, + screen_fb_size, + 0, -1, + screen_fb_size, + NULL, NULL); + if (ret != 0) { + pr_err("Unable to allocate framebuffer memory\n"); + return -ENODEV; + } + } else { + pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, PCI_DEVICE_ID_HYPERV_VIDEO, NULL); - if (!pdev) { - pr_err("Unable to find PCI Hyper-V video\n"); - return -ENODEV; - } + if (!pdev) { + pr_err("Unable to find PCI Hyper-V video\n"); + return -ENODEV; + } - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || - pci_resource_len(pdev, 0) < screen_fb_size) - goto err1; - - fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1; - if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME)) - goto err1; + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || + pci_resource_len(pdev, 0) < screen_fb_size) + goto err1; + + par->mem.end = pci_resource_end(pdev, 0); + par->mem.start = par->mem.end - screen_fb_size + 1; + ret = request_resource(&pdev->resource[0], &par->mem); + if (ret != 0) { + pr_err("Unable to request framebuffer memory\n"); + goto err1; + } + } - fb_virt = ioremap(fb_phys, screen_fb_size); + fb_virt = ioremap(par->mem.start, screen_fb_size); if (!fb_virt) goto err2; @@ -654,30 +676,44 @@ if (!info->apertures) goto err3; - info->apertures->ranges[0].base = pci_resource_start(pdev, 0); - info->apertures->ranges[0].size = pci_resource_len(pdev, 0); - info->fix.smem_start = fb_phys; + if (gen2vm) { + info->apertures->ranges[0].base = screen_info.lfb_base; + info->apertures->ranges[0].size = screen_info.lfb_size; + remove_conflicting_framebuffers(info->apertures, + KBUILD_MODNAME, false); + } else { + info->apertures->ranges[0].base = pci_resource_start(pdev, 0); + info->apertures->ranges[0].size = pci_resource_len(pdev, 0); + } + + info->fix.smem_start = par->mem.start; info->fix.smem_len = screen_fb_size; info->screen_base = fb_virt; info->screen_size = screen_fb_size; - pci_dev_put(pdev); + if (!gen2vm) + pci_dev_put(pdev); + return 0; err3: iounmap(fb_virt); err2: - release_mem_region(fb_phys, screen_fb_size); + release_resource(&par->mem); err1: - pci_dev_put(pdev); + if (!gen2vm) + pci_dev_put(pdev); + return -ENOMEM; } /* Release the framebuffer */ static void hvfb_putmem(struct fb_info *info) { + struct hvfb_par *par = info->par; + iounmap(info->screen_base); - release_mem_region(info->fix.smem_start, screen_fb_size); + release_resource(&par->mem); } --- linux-3.13.0.orig/drivers/video/console/sticore.c +++ linux-3.13.0/drivers/video/console/sticore.c @@ -488,7 +488,7 @@ return 0; } -#ifdef CONFIG_FONTS +#ifdef CONFIG_FONT_SUPPORT static struct sti_cooked_font * sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) { --- linux-3.13.0.orig/drivers/irqchip/irq-armada-370-xp.c +++ linux-3.13.0/drivers/irqchip/irq-armada-370-xp.c @@ -381,7 +381,7 @@ ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) & PCI_MSI_DOORBELL_MASK; - writel(~PCI_MSI_DOORBELL_MASK, per_cpu_int_base + + writel(~msimask, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); for (msinr = PCI_MSI_DOORBELL_START; @@ -407,7 +407,7 @@ ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) & IPI_DOORBELL_MASK; - writel(~IPI_DOORBELL_MASK, per_cpu_int_base + + writel(~ipimask, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); /* Handle all pending doorbells */ --- linux-3.13.0.orig/drivers/irqchip/irq-orion.c +++ linux-3.13.0/drivers/irqchip/irq-orion.c @@ -111,7 +111,8 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) { struct irq_domain *d = irq_get_handler_data(irq); - struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq); + + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) & gc->mask_cache; @@ -123,6 +124,19 @@ } } +/* + * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register. + * To avoid interrupt events on stale irqs, we clear them before unmask. + */ +static unsigned int orion_bridge_irq_startup(struct irq_data *d) +{ + struct irq_chip_type *ct = irq_data_get_chip_type(d); + + ct->chip.irq_ack(d); + ct->chip.irq_unmask(d); + return 0; +} + static int __init orion_bridge_irq_init(struct device_node *np, struct device_node *parent) { @@ -143,7 +157,7 @@ } ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, - handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); + handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); if (ret) { pr_err("%s: unable to alloc irq domain gc\n", np->name); return ret; @@ -176,12 +190,14 @@ gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE; gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK; + gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup; gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; - /* mask all interrupts */ + /* mask and clear all interrupts */ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK); + writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE); irq_set_handler_data(irq, domain); irq_set_chained_handler(irq, orion_bridge_irq_handler); --- linux-3.13.0.orig/drivers/irqchip/irq-metag-ext.c +++ linux-3.13.0/drivers/irqchip/irq-metag-ext.c @@ -515,7 +515,7 @@ * one cpu (the interrupt code doesn't support it), so we just * pick the first cpu we find in 'cpumask'. */ - cpu = cpumask_any(cpumask); + cpu = cpumask_any_and(cpumask, cpu_online_mask); thread = cpu_2_hwthread_id[cpu]; metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR2(thread)), vec_addr); --- linux-3.13.0.orig/drivers/irqchip/irq-metag.c +++ linux-3.13.0/drivers/irqchip/irq-metag.c @@ -201,7 +201,7 @@ * one cpu (the interrupt code doesn't support it), so we just * pick the first cpu we find in 'cpumask'. */ - cpu = cpumask_any(cpumask); + cpu = cpumask_any_and(cpumask, cpu_online_mask); thread = cpu_2_hwthread_id[cpu]; metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)), --- linux-3.13.0.orig/Documentation/kernel-parameters.txt +++ linux-3.13.0/Documentation/kernel-parameters.txt @@ -652,6 +652,10 @@ /proc//coredump_filter. See also Documentation/filesystems/proc.txt. + cpufreq_driver= [X86] Allow only the named cpu frequency scaling driver + to register. Example: cpufreq_driver=powernow-k8 + Format: { none | STRING } + cpuidle.off=1 [CPU_IDLE] disable the cpuidle sub-system @@ -890,6 +894,12 @@ edd= [EDD] Format: {"off" | "on" | "skip[mbr]"} + efi= [EFI] + Format: { "old_map" } + old_map [X86-64]: switch to the old ioremap-based EFI + runtime services mapping. 32-bit still uses this one by + default. + efi_no_storage_paranoia [EFI; X86] Using this parameter you can use more than 50% of your efi variable storage. Use this parameter only if @@ -962,6 +972,13 @@ parameter will force ia64_sal_cache_flush to call ia64_pal_cache_flush instead of SAL_CACHE_FLUSH. + forcepae [X86-32] + Forcefully enable Physical Address Extension (PAE). + Many Pentium M systems disable PAE but may have a + functionally usable PAE implementation. + Note: This parameter is unsupported, may cause unknown + problems, and will taint the kernel. + ftrace=[tracer] [FTRACE] will set and start the specified tracer as early as possible in order to facilitate early --- linux-3.13.0.orig/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt +++ linux-3.13.0/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt @@ -0,0 +1,79 @@ +* APM X-Gene 15Gbps Multi-purpose PHY nodes + +PHY nodes are defined to describe on-chip 15Gbps Multi-purpose PHY. Each +PHY (pair of lanes) has its own node. + +Required properties: +- compatible : Shall be "apm,xgene-phy". +- reg : PHY memory resource is the SDS PHY access resource. +- #phy-cells : Shall be 1 as it expects one argument for setting + the mode of the PHY. Possible values are 0 (SATA), + 1 (SGMII), 2 (PCIe), 3 (USB), and 4 (XFI). + +Optional properties: +- status : Shall be "ok" if enabled or "disabled" if disabled. + Default is "ok". +- clocks : Reference to the clock entry. +- apm,tx-eye-tuning : Manual control to fine tune the capture of the serial + bit lines from the automatic calibrated position. + Two set of 3-tuple setting for each (up to 3) + supported link speed on the host. Range from 0 to + 127 in unit of one bit period. Default is 10. +- apm,tx-eye-direction : Eye tuning manual control direction. 0 means sample + data earlier than the nominal sampling point. 1 means + sample data later than the nominal sampling point. + Two set of 3-tuple setting for each (up to 3) + supported link speed on the host. Default is 0. +- apm,tx-boost-gain : Frequency boost AC (LSB 3-bit) and DC (2-bit) + gain control. Two set of 3-tuple setting for each + (up to 3) supported link speed on the host. Range is + between 0 to 31 in unit of dB. Default is 3. +- apm,tx-amplitude : Amplitude control. Two set of 3-tuple setting for + each (up to 3) supported link speed on the host. + Range is between 0 to 199500 in unit of uV. + Default is 199500 uV. +- apm,tx-pre-cursor1 : 1st pre-cursor emphasis taps control. Two set of + 3-tuple setting for each (up to 3) supported link + speed on the host. Range is 0 to 273000 in unit of + uV. Default is 0. +- apm,tx-pre-cursor2 : 2st pre-cursor emphasis taps control. Two set of + 3-tuple setting for each (up to 3) supported link + speed on the host. Range is 0 to 127400 in unit uV. + Default is 0x0. +- apm,tx-post-cursor : Post-cursor emphasis taps control. Two set of + 3-tuple setting for Gen1, Gen2, and Gen3. Range is + between 0 to 0x1f in unit of 18.2mV. Default is 0xf. +- apm,tx-speed : Tx operating speed. One set of 3-tuple for each + supported link speed on the host. + 0 = 1-2Gbps + 1 = 2-4Gbps (1st tuple default) + 2 = 4-8Gbps + 3 = 8-15Gbps (2nd tuple default) + 4 = 2.5-4Gbps + 5 = 4-5Gbps + 6 = 5-6Gbps + 7 = 6-16Gbps (3rd tuple default) + +NOTE: PHY override parameters are board specific setting. + +Example: + phy1: phy@1f21a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f21a000 0x0 0x100>; + #phy-cells = <1>; + status = "disabled"; + }; + + phy2: phy@1f22a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f22a000 0x0 0x100>; + #phy-cells = <1>; + status = "ok"; + }; + + phy3: phy@1f23a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f23a000 0x0 0x100>; + #phy-cells = <1>; + status = "ok"; + }; --- linux-3.13.0.orig/Documentation/devicetree/bindings/ata/marvell.txt +++ linux-3.13.0/Documentation/devicetree/bindings/ata/marvell.txt @@ -1,7 +1,7 @@ * Marvell Orion SATA Required Properties: -- compatibility : "marvell,orion-sata" +- compatibility : "marvell,orion-sata" or "marvell,armada-370-sata" - reg : Address range of controller - interrupts : Interrupt controller is using - nr-ports : Number of SATA ports in use. --- linux-3.13.0.orig/Documentation/devicetree/bindings/ata/apm-xgene.txt +++ linux-3.13.0/Documentation/devicetree/bindings/ata/apm-xgene.txt @@ -0,0 +1,76 @@ +* APM X-Gene 6.0 Gb/s SATA host controller nodes + +SATA host controller nodes are defined to describe on-chip Serial ATA +controllers. Each SATA controller (pair of ports) have its own node. + +Required properties: +- compatible : Shall contain: + * "apm,xgene-ahci" +- reg : First memory resource shall be the AHCI memory + resource. + Second memory resource shall be the host controller + core memory resource. + Third memory resource shall be the host controller + diagnostic memory resource. + 4th memory resource shall be the host controller + AXI memory resource. + 5th optional memory resource shall be the host + controller MUX memory resource if required. +- interrupts : Interrupt-specifier for SATA host controller IRQ. +- clocks : Reference to the clock entry. +- phys : A list of phandles + phy-specifiers, one for each + entry in phy-names. +- phy-names : Should contain: + * "sata-phy" for the SATA 6.0Gbps PHY + +Optional properties: +- status : Shall be "ok" if enabled or "disabled" if disabled. + Default is "ok". + +Example: + sataclk: sataclk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <100000000>; + clock-output-names = "sataclk"; + }; + + phy2: phy@1f22a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f22a000 0x0 0x100>; + #phy-cells = <1>; + }; + + phy3: phy@1f23a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f23a000 0x0 0x100>; + #phy-cells = <1>; + }; + + sata2: sata@1a400000 { + compatible = "apm,xgene-ahci"; + reg = <0x0 0x1a400000 0x0 0x1000>, + <0x0 0x1f220000 0x0 0x1000>, + <0x0 0x1f22d000 0x0 0x1000>, + <0x0 0x1f22e000 0x0 0x1000>, + <0x0 0x1f227000 0x0 0x1000>; + interrupts = <0x0 0x87 0x4>; + status = "ok"; + clocks = <&sataclk 0>; + phys = <&phy2 0>; + phy-names = "sata-phy"; + }; + + sata3: sata@1a800000 { + compatible = "apm,xgene-ahci-pcie"; + reg = <0x0 0x1a800000 0x0 0x1000>, + <0x0 0x1f230000 0x0 0x1000>, + <0x0 0x1f23d000 0x0 0x1000>, + <0x0 0x1f23e000 0x0 0x1000>, + <0x0 0x1f237000 0x0 0x1000>; + interrupts = <0x0 0x88 0x4>; + status = "ok"; + clocks = <&sataclk 0>; + phys = <&phy3 0>; + phy-names = "sata-phy"; + }; --- linux-3.13.0.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ linux-3.13.0/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -10,6 +10,8 @@ Optional properties: - dma-coherent : Present if dma operations are coherent +- clocks : a list of phandle + clock specifier pairs +- target-supply : regulator for SATA target power Example: sata@ffe08000 { --- linux-3.13.0.orig/Documentation/devicetree/bindings/pci/xgene-pci.txt +++ linux-3.13.0/Documentation/devicetree/bindings/pci/xgene-pci.txt @@ -0,0 +1,52 @@ +* AppliedMicro X-Gene PCIe interface + +Required properties: +- device_type: set to "pci" +- compatible: should contain "xgene,pcie" to identify the core. +- reg: A list of physical base address and length for each set of controller + registers. Must contain an entry for each entry in the reg-names + property. +- reg-names: Must include the following entries: + "csr": controller configuration registers. + "cfg": pcie configuration space registers. +- #address-cells: set to <3> +- #size-cells: set to <2> +- ranges: ranges for the outbound memory, I/O regions. +- dma-ranges: ranges for the inbound memory regions. +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI properties + to define the mapping of the PCIe interface to interrupt + numbers. +- clocks: from common clock binding: handle to pci clock. + +Optional properties: +- status: Either "ok" or "disabled". + +Example: + +SoC specific DT Entry: + pcie0: pcie@1f2b0000 { + status = "disabled"; + device_type = "pci"; + compatible = "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */ + 0xe0 0xd0000000 0x0 0x00200000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x00 0x00000000 0xe0 0x00000000 0x00 0x00010000 /* io */ + 0x02000000 0x00 0x10000000 0xe0 0x10000000 0x00 0x80000000>; /* mem */ + dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>; + clocks = <&pcie0clk 0>; + }; + +Board specific DT Entry: + &pcie0 { + status = "ok"; + }; --- linux-3.13.0.orig/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +++ linux-3.13.0/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt @@ -5,7 +5,11 @@ - reg : Offset and length of the register set for the device - compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c" - or "marvell,mv78230-i2c" + or "marvell,mv78230-i2c" or "marvell,mv78230-a0-i2c" + Note: Only use "marvell,mv78230-a0-i2c" for a very rare, + initial version of the SoC which had broken offload + support. Linux auto-detects this and sets it + appropriately. - interrupts : The interrupt number Optional properties : --- linux-3.13.0.orig/Documentation/devicetree/bindings/net/apm-xgene-enet.txt +++ linux-3.13.0/Documentation/devicetree/bindings/net/apm-xgene-enet.txt @@ -0,0 +1,67 @@ +APM X-Gene SoC Ethernet nodes + +Ethernet nodes are defined to describe on-chip ethernet interfaces in +APM X-Gene SoC. Ethernet subsystem communicates with a central Queue Manager +(QMTM) using messages for transmit, receive and allocating data buffers. +There are multiple ethernet interfaces in APM X-Gene SoC. Each ethernet +interface has its own node. Its corresponding clock nodes are shown below. + +Required properties: +- compatible : Shall be "apm,xgene-enet" +- reg : First memory resource shall be the Ethernet CSR + memory resource for indirect MAC access. + Second memory resource shall be the Ethernet CSR + memory resource. + Third memory resource shall be the Ethernet CSR + memory resource for indirect MII access. +- slave-name : Shall be QMTM slave name. +- interrupts : First interrupt resource shall be the Ethernet global + Error interrupt. + : Second interrupt resource shall be the Ethernet MAC + Error interrupt. + : Third interrupt resource shall be the Ethernet QM + interface interrupt. +- clocks : Reference to the clock entry. +- local-mac-address : Shall be ethernet mac address. +- max-frame-size : Shall be maximum ethernet frame size. +- devid : Shall be ethernet interface number. +- phyid : Shall be ethernet MII phy address. +- phy-mode : Shall be ethernet MII mode. + +Optional properties: +- status : Shall be "ok" if enabled or "disabled" if disabled. + Default is "ok". + +Example: + eth8clk: eth8clk { + compatible = "apm,xgene-device-clock"; + clock-names = "eth8clk"; + status = "ok"; + }; + + menet: ethernet@17020000 { + compatible = "apm,xgene-enet"; + status = "disabled"; + reg = <0x0 0x17020000 0x0 0x30>, + <0x0 0x17020000 0x0 0x10000>, + <0x0 0x17020000 0x0 0x20>; + slave-name = "RGMII"; + interrupts = <0x0 0x38 0x4>, + <0x0 0x39 0x4>, + <0x0 0x3a 0x4>; + clocks = <ð8clk 0>; + local-mac-address = <0x0 0x11 0x3a 0x8a 0x5a 0x78>; + max-frame-size = <0x233a>; + devid = <8>; + phyid = <3>; + phy-mode = "rgmii"; + }; + +/* Board-specific peripheral configurations */ +aliases { + ethernet0 = &menet; +}; + +&menet { + status = "ok"; +}; --- linux-3.13.0.orig/Documentation/devicetree/bindings/misc/apm-xgene-qmtm.txt +++ linux-3.13.0/Documentation/devicetree/bindings/misc/apm-xgene-qmtm.txt @@ -0,0 +1,51 @@ +* APM X-Gene SoC Queue Manager/Traffic Manager nodes + +QMTM nodes are defined to describe on-chip Queue Managers in APM X-Gene SoC. +APM X-Gene SoC Ethernet, PktDMA (XOR Engine), and Security Engine subsystems +communicate with a central Queue Manager using messages which include +information about the work to be performed and the location of the associated +data buffers. There are multiple instances of QMTM. Each QMTM instance has its +own node. Its corresponding clock nodes are shown below. + +Required properties: +- compatible : Shall be "apm,xgene-qmtm-lite" for QMLite instance +- reg : First memory resource shall be the QMTM CSR memory + resource. + Second memory resource shall be the QMTM IO-Fabric + memory resource. +- slave-name : Shall be "CPU_QMTM3" which is receiver for ingress + work messages for the QMTM. Here receiver is CPU. +- interrupts : First interrupt resource shall be the QMTM Error + interrupt. + Remaining interrupt resources shall be the Ingress + work message interrupt mapping for receiver, + receiving work messages for the QMTM. +- clocks : Reference to the clock entry. + +Optional properties: +- status : Shall be "ok" if enabled or "disabled" if disabled. + Default is "ok". + +Example: + qmlclk: qmlclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clock-names = "socplldiv2"; + status = "ok"; + csr-offset = <0x0>; + csr-mask = <0x3>; + enable-offset = <0x8>; + enable-mask = <0x3>; + }; + + qmlite: qmtm@17030000 { + compatible = "apm,xgene-qmtm-lite"; + reg = <0x0 0x17030000 0x0 0x10000>, + <0x0 0x10000000 0x0 0x400000>; + slave-name = "CPU_QMTM3"; + interrupts = <0x0 0x40 0x4>, + <0x0 0x3c 0x4>; + status = "ok"; + #clock-cells = <1>; + clocks = <&qmlclk 0>; + }; --- linux-3.13.0.orig/Documentation/filesystems/vfs.txt +++ linux-3.13.0/Documentation/filesystems/vfs.txt @@ -362,6 +362,7 @@ int (*atomic_open)(struct inode *, struct dentry *, struct file *, unsigned open_flag, umode_t create_mode, int *opened); int (*tmpfile) (struct inode *, struct dentry *, umode_t); + int (*dentry_open)(struct dentry *, struct file *, const struct cred *); }; Again, all methods are called without any locks being held, unless @@ -681,6 +682,12 @@ but instead uses bmap to find out where the blocks in the file are and uses those addresses directly. + dentry_open: this is an alternative to f_op->open(), the difference is that + this method may open a file not necessarily originating from the same + filesystem as the one i_op->open() was called on. It may be + useful for stacking filesystems which want to allow native I/O directly + on underlying files. + invalidatepage: If a page has PagePrivate set, then invalidatepage will be called when part or all of the page is to be removed --- linux-3.13.0.orig/Documentation/filesystems/Locking +++ linux-3.13.0/Documentation/filesystems/Locking @@ -65,6 +65,7 @@ struct file *, unsigned open_flag, umode_t create_mode, int *opened); int (*tmpfile) (struct inode *, struct dentry *, umode_t); + int (*dentry_open)(struct dentry *, struct file *, const struct cred *); locking rules: all may block @@ -93,6 +94,7 @@ update_time: no atomic_open: yes tmpfile: no +dentry_open: no Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on victim. --- linux-3.13.0.orig/Documentation/filesystems/overlayfs.txt +++ linux-3.13.0/Documentation/filesystems/overlayfs.txt @@ -0,0 +1,199 @@ +Written by: Neil Brown + +Overlay Filesystem +================== + +This document describes a prototype for a new approach to providing +overlay-filesystem functionality in Linux (sometimes referred to as +union-filesystems). An overlay-filesystem tries to present a +filesystem which is the result over overlaying one filesystem on top +of the other. + +The result will inevitably fail to look exactly like a normal +filesystem for various technical reasons. The expectation is that +many use cases will be able to ignore these differences. + +This approach is 'hybrid' because the objects that appear in the +filesystem do not all appear to belong to that filesystem. In many +cases an object accessed in the union will be indistinguishable +from accessing the corresponding object from the original filesystem. +This is most obvious from the 'st_dev' field returned by stat(2). + +While directories will report an st_dev from the overlay-filesystem, +all non-directory objects will report an st_dev from the lower or +upper filesystem that is providing the object. Similarly st_ino will +only be unique when combined with st_dev, and both of these can change +over the lifetime of a non-directory object. Many applications and +tools ignore these values and will not be affected. + +Upper and Lower +--------------- + +An overlay filesystem combines two filesystems - an 'upper' filesystem +and a 'lower' filesystem. When a name exists in both filesystems, the +object in the 'upper' filesystem is visible while the object in the +'lower' filesystem is either hidden or, in the case of directories, +merged with the 'upper' object. + +It would be more correct to refer to an upper and lower 'directory +tree' rather than 'filesystem' as it is quite possible for both +directory trees to be in the same filesystem and there is no +requirement that the root of a filesystem be given for either upper or +lower. + +The lower filesystem can be any filesystem supported by Linux and does +not need to be writable. The lower filesystem can even be another +overlayfs. The upper filesystem will normally be writable and if it +is it must support the creation of trusted.* extended attributes, and +must provide valid d_type in readdir responses, at least for symbolic +links - so NFS is not suitable. + +A read-only overlay of two read-only filesystems may use any +filesystem type. + +Directories +----------- + +Overlaying mainly involves directories. If a given name appears in both +upper and lower filesystems and refers to a non-directory in either, +then the lower object is hidden - the name refers only to the upper +object. + +Where both upper and lower objects are directories, a merged directory +is formed. + +At mount time, the two directories given as mount options are combined +into a merged directory: + + mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper /overlay + +Then whenever a lookup is requested in such a merged directory, the +lookup is performed in each actual directory and the combined result +is cached in the dentry belonging to the overlay filesystem. If both +actual lookups find directories, both are stored and a merged +directory is created, otherwise only one is stored: the upper if it +exists, else the lower. + +Only the lists of names from directories are merged. Other content +such as metadata and extended attributes are reported for the upper +directory only. These attributes of the lower directory are hidden. + +whiteouts and opaque directories +-------------------------------- + +In order to support rm and rmdir without changing the lower +filesystem, an overlay filesystem needs to record in the upper filesystem +that files have been removed. This is done using whiteouts and opaque +directories (non-directories are always opaque). + +The overlay filesystem uses extended attributes with a +"trusted.overlay." prefix to record these details. + +A whiteout is created as a symbolic link with target +"(overlay-whiteout)" and with xattr "trusted.overlay.whiteout" set to "y". +When a whiteout is found in the upper level of a merged directory, any +matching name in the lower level is ignored, and the whiteout itself +is also hidden. + +A directory is made opaque by setting the xattr "trusted.overlay.opaque" +to "y". Where the upper filesystem contains an opaque directory, any +directory in the lower filesystem with the same name is ignored. + +readdir +------- + +When a 'readdir' request is made on a merged directory, the upper and +lower directories are each read and the name lists merged in the +obvious way (upper is read first, then lower - entries that already +exist are not re-added). This merged name list is cached in the +'struct file' and so remains as long as the file is kept open. If the +directory is opened and read by two processes at the same time, they +will each have separate caches. A seekdir to the start of the +directory (offset 0) followed by a readdir will cause the cache to be +discarded and rebuilt. + +This means that changes to the merged directory do not appear while a +directory is being read. This is unlikely to be noticed by many +programs. + +seek offsets are assigned sequentially when the directories are read. +Thus if + - read part of a directory + - remember an offset, and close the directory + - re-open the directory some time later + - seek to the remembered offset + +there may be little correlation between the old and new locations in +the list of filenames, particularly if anything has changed in the +directory. + +Readdir on directories that are not merged is simply handled by the +underlying directory (upper or lower). + + +Non-directories +--------------- + +Objects that are not directories (files, symlinks, device-special +files etc.) are presented either from the upper or lower filesystem as +appropriate. When a file in the lower filesystem is accessed in a way +the requires write-access, such as opening for write access, changing +some metadata etc., the file is first copied from the lower filesystem +to the upper filesystem (copy_up). Note that creating a hard-link +also requires copy_up, though of course creation of a symlink does +not. + +The copy_up may turn out to be unnecessary, for example if the file is +opened for read-write but the data is not modified. + +The copy_up process first makes sure that the containing directory +exists in the upper filesystem - creating it and any parents as +necessary. It then creates the object with the same metadata (owner, +mode, mtime, symlink-target etc.) and then if the object is a file, the +data is copied from the lower to the upper filesystem. Finally any +extended attributes are copied up. + +Once the copy_up is complete, the overlay filesystem simply +provides direct access to the newly created file in the upper +filesystem - future operations on the file are barely noticed by the +overlay filesystem (though an operation on the name of the file such as +rename or unlink will of course be noticed and handled). + + +Non-standard behavior +--------------------- + +The copy_up operation essentially creates a new, identical file and +moves it over to the old name. The new file may be on a different +filesystem, so both st_dev and st_ino of the file may change. + +Any open files referring to this inode will access the old data and +metadata. Similarly any file locks obtained before copy_up will not +apply to the copied up file. + +On a file opened with O_RDONLY fchmod(2), fchown(2), futimesat(2) and +fsetxattr(2) will fail with EROFS. + +If a file with multiple hard links is copied up, then this will +"break" the link. Changes will not be propagated to other names +referring to the same inode. + +Symlinks in /proc/PID/ and /proc/PID/fd which point to a non-directory +object in overlayfs will not contain valid absolute paths, only +relative paths leading up to the filesystem's root. This will be +fixed in the future. + +Some operations are not atomic, for example a crash during copy_up or +rename will leave the filesystem in an inconsistent state. This will +be addressed in the future. + +Changes to underlying filesystems +--------------------------------- + +Offline changes, when the overlay is not mounted, are allowed to either +the upper or the lower trees. + +Changes to the underlying filesystems while part of a mounted overlay +filesystem are not allowed. If the underlying filesystem is changed, +the behavior of the overlay is undefined, though it will not result in +a crash or deadlock. --- linux-3.13.0.orig/Documentation/filesystems/proc.txt +++ linux-3.13.0/Documentation/filesystems/proc.txt @@ -1377,8 +1377,8 @@ For example, if a task is using all allowed memory, its badness score will be 1000. If it is using half of its allowed memory, its score will be 500. -There is an additional factor included in the badness score: root -processes are given 3% extra memory over other tasks. +There is an additional factor included in the badness score: the current memory +and swap usage is discounted by 3% for root processes. The amount of "allowed" memory depends on the context in which the oom killer was called. If it is due to the memory assigned to the allocating task's cpuset --- linux-3.13.0.orig/Documentation/sysctl/kernel.txt +++ linux-3.13.0/Documentation/sysctl/kernel.txt @@ -33,6 +33,7 @@ - domainname - hostname - hotplug +- kexec_load_disabled - kptr_restrict - kstack_depth_to_print [ X86 only ] - l2cr [ PPC only ] @@ -287,6 +288,18 @@ ============================================================== +kexec_load_disabled: + +A toggle indicating if the kexec_load syscall has been disabled. This +value defaults to 0 (false: kexec_load enabled), but can be set to 1 +(true: kexec_load disabled). Once true, kexec can no longer be used, and +the toggle cannot be set back to false. This allows a kexec image to be +loaded before disabling the syscall, allowing a system to set up (and +later use) an image without it being altered. Generally used together +with the "modules_disabled" sysctl. + +============================================================== + kptr_restrict: This toggle indicates whether restrictions are placed on @@ -331,7 +344,7 @@ in an otherwise modular kernel. This toggle defaults to off (0), but can be set true (1). Once true, modules can be neither loaded nor unloaded, and the toggle cannot be set back -to false. +to false. Generally used with the "kexec_load_disabled" toggle. ============================================================== --- linux-3.13.0.orig/Documentation/i2c/busses/i2c-piix4 +++ linux-3.13.0/Documentation/i2c/busses/i2c-piix4 @@ -13,7 +13,7 @@ * AMD SP5100 (SB700 derivative found on some server mainboards) Datasheet: Publicly available at the AMD website http://support.amd.com/us/Embedded_TechDocs/44413.pdf - * AMD Hudson-2, CZ + * AMD Hudson-2, ML, CZ Datasheet: Not publicly available * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge Datasheet: Publicly available at the SMSC website http://www.smsc.com --- linux-3.13.0.orig/Documentation/networking/fman.txt +++ linux-3.13.0/Documentation/networking/fman.txt @@ -0,0 +1,232 @@ +The FMan driver +Sysfs file description + +Author: Andrei Sorin Pistirica +Updated: 2010-12-08 + +FMAN SYSFS statistics counters +------------------------------ +The document contains statistics counters description for every type of +FMAN port and for all FMAN modules as well (FMAN, FMAN:DMA and FMAN:PCD). +Every counter is related to a specific register mapped as well. + +Port type: Tx +------------- +port_frame: FMBM_TFRC + "counts the total number of frames flowing on the Tx port, regardless of + whether they got transmitted or discarded." + +port_discard_frame: FMBM_TFDC + "counts the number of frames that were discarded due to DMA error indication + that was sensed during the process of frame payload or frame context + loading." + +port_dealloc_buf:FMBM_TBDC + "counts the number of buffer deallocate operations." + +port_enq_total:FMQM_PnETFC + "counts the number of enqueue operations preformed for this portID." + +port_length_err:FMBM_TFLEDC + "counts the number of frames that were discarded due to frame length error." + +port_unsupprted_format:FMBM_TFUFDC + "counts the number of frames that were discarded due to frame format + error - frame descriptor contains unsupported format." + +port_deq_total:FMQM_PnDTFC + "counts the total number of FDs that dequeued from the QMan for this + portID." + +port_deq_from_default:FMQM_PnDDCFQC + "counts the number of time the portID used the default confirmation FQID + from the BMI.s FMBM_TDCFQID" + +port_deq_confirm:FMQM_PnDCC + "counts the number of times the PortID got a FD from the dequeue response + that require confirmation." + +Port type: Rx +------------- +port_frame:FMBM_RFRC + "counts the total number of frames received on the Rx port." + +port_discard_frame:FMBM_RFDC + "counts the number of frames received on the Rx port that were not able + to enter the receive queue system due to WRED algorithm." + +port_dealloc_buf:FMBM_RBDC + "counts the number of buffer deallocate operations." + +port_enq_total:FMQM_PnETFC + "counts the number of enqueue operations preformed for this portID" + +port_rx_bad_frame:FMBM_RBFC + "counts the number of frames received on the Rx port with an error + indication" + +port_rx_large_frame:FMBM_RLFC + "counts the number of frames received on the Rx port with an over size + indication. Over size indication is marked when frame size exceeds the + maximum configured in the corresponding MAC configuration register" + +port_rx_out_of_buffers_discard:FMBM_RODC + "counts the number of frames received on the Rx port that were not able + to enter the receive queue system due to lack of external buffers, or + the lack of suitable buffers that cause the S/G list to grow beyond 16 + entries, or the lack of suitable buffer to hold S/G list (including + start margin), or the lack of suitable buffer to hold the frame header + (including start margin)." + +port_rx_filter_frame:FMBM_RFFC + "counts the number of frames received on the Rx port that were filtered + out by the parse and classify modules of the Fman" + +Port type: Oh +------------- +Oh ports have the same counters as RX and TX ports. The counters are listed +below and the description can be found at the other ports (above): + port_frame + port_discard_frame + port_dealloc_buf + port_enq_total + port_length_err + port_unsupprted_format + port_deq_total + port_deq_from_default + port_deq_confirm + port_rx_bad_frame + port_rx_large_frame + port_rx_out_of_buffers_discard + +Fman: +----- +enq_total_frame:FMQM_ETFC + "counts the total number of enqueue operations the QMI performed." + +deq_total_frame:FMQM_DTFC + "counts the total number of FDs that dequeued from the Qman." + +deq_0:FMQM_DC0 + "counts the number of times the QMI received a NULL FD from the QMan as a + response to a dequeue request (command)" + +deq_1:FMQM_DC1 + "counts the number of times the QMI got 1 FD from the QMan as a response + to a dequeue request (command)" + +deq_2:FMQM_DC2 + "counts the number of times the QMI got 2 FD from the QMan as a response + to a dequeue request (command)" + +deq_from_default:FMQM_DDCFQC + "counts the number of times the QMI used the default confirmation FQID + from the BMI's FMBM_TCFQID" + +deq_from_context:FMQM_CBCFQC + "counts the number of times the QMI used the override confirmation FQID + from the FD command field" + +deq_from_fd:FMQM_DFOCFQC + "counts the number of times the QMI used the override confirmation FQID + from the FD command field" + +deq_confirm:(FMQM_DCC + "counts the number of times the QMI gets an FD from the dequeue response + that requires confirmation" + +Fman: DMA +--------- +The FMAN:DMA counters are read from FMDMSR register. They reports bus error +events that are recognized by the FMan DMA controller on all of the +FMan DMA channels. + The counters are: + cmq_not_empty + bus_error + read_buf_ecc_error + write_buf_ecc_sys_error + write_buf_ecc_fm_error + +Fman: PCD +--------- +pcd_kg_total:FMKG_TPC + "count of packets passed in the keygen on all schemes" + +pcd_plcr_yellow:FMPL_YPC + "counts the total number of YELLOW packets that exit the Policer" + +pcd_plcr_red:FMPL_RPC + "counter counts the total number of RED packets that exit the Policer" + +pcd_plcr_recolored_to_red:FMPL_RRPC + "counts the number of packets that changed color to RED by the Policer" + +pcd_plcr_recolored_to_yellow:FMPL_RYPC + "counts the number of packets that changed color to YELLOW by the Policer" + +pcd_plcr_total:FMPL_TPC + "counts the total number of packets passed in the Policer" + +pcd_plcr_length_mismatch:FMPL_FLMC + "counts the number of packets with length mismatch indicated by an offset + value of 0xFF in the selected parser result entry or when the calculated + frame offset result is greater than the packet full length provided by + FD length" + +pcd_prs_parse_dispatch:FMPR_PDS + "counts the number of times the parser block was dispatched by FPM" + +pcd_prs_l2_parse_result_returned:FMPR_L2RRS + "counts the number of times L2 parse result was returned (including with + errors)" + +pcd_prs_l3_parse_result_returned:FMPR_L3RRS + "counts the number of times L3 parse result was returned (including with + errors) + +pcd_prs_l4_parse_result_returned:FMPR_L4RRS + "counts the number of times L4 parse result was returned (including with + errors)" + +pcd_prs_shim_parse_result_returned:FMPR_SRRS + "counts the number of times Shim parse result was returned (including with + errors)" + +pcd_prs_l2_parse_result_returned_with_err:FMPR_L2RRES + "counts the number of times L2 parse result was returned with errors" + +pcd_prs_l3_parse_result_returned_with_err:FMPR_L3RRES + "counts the number of times L3 parse result was returned with errors" + +pcd_prs_l4_parse_result_returned_with_err:FMPR_L4RRES + "counts the number of times L4 parse result was returned with errors" + +pcd_prs_shim_parse_result_returned_with_err:FMPR_SRRES + "counts the number of times Shim parse result was returned with errors" + +pcd_prs_soft_prs_cycles:FMPR_SPCS + "counts the number of cycles spent executing soft parser instruction + (including stall cycles)" + +pcd_prs_soft_prs_stall_cycles:FMPR_SPSCS + "counts the number of cycles stalled waiting for parser internal memory + reads while executing soft parser instruction." + +pcd_prs_hard_prs_cycle_incl_stall_cycles:FMPR_HXSCS + "counts the number of cycles spent executing hard parser (including stall + cycles)" + +pcd_prs_muram_read_cycles:FMPR_MRCS + "counts the number of cycles while performing FMan Memory read" + +pcd_prs_muram_read_stall_cycles:FMPR_MRSCS + "counts the number of cycles stalled while performing FMan Memory read" + +pcd_prs_muram_write_cycles:FMPR_MWCS + "counts the number of cycles while performing FMan Memory write" + +pcd_prs_muram_write_stall_cycles:FMPR_MWSCS + "counts the number of cycles stalled while performing FMan Memory write" + +pcd_prs_fpm_command_stall_cycles:FMPR_FCSCS + "counts the number of cycles stalled while performing a FPM command" --- linux-3.13.0.orig/Documentation/x86/x86_64/mm.txt +++ linux-3.13.0/Documentation/x86/x86_64/mm.txt @@ -28,4 +28,11 @@ Current X86-64 implementations only support 40 bits of address space, but we support up to 46 bits. This expands into MBZ space in the page tables. +->trampoline_pgd: + +We map EFI runtime services in the aforementioned PGD in the virtual +range of 64Gb (arbitrarily set, can be raised if needed) + +0xffffffef00000000 - 0xffffffff00000000 + -Andi Kleen, Jul 2004 --- linux-3.13.0.orig/Documentation/misc-devices/apm-xgene-qmtm +++ linux-3.13.0/Documentation/misc-devices/apm-xgene-qmtm @@ -0,0 +1,149 @@ +AppliedMicro X-Gene SOC Queue Manager/Traffic Manager Document + +Copyright (c) 2013 Applied Micro Circuits Corporation. +Author: Ravi Patel + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as published by +the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + + +Overview: +QMTM is a device which interacts with CPU, Ethernet, PktDMA and Security +subsystems through AXI BUS. Its centralized resource manager/driver exports +APIs for CPU, Ethernet, PktDMA and Security subsystems to +1. Initialize & allocate queue & pbn. +2. Read queue state so that subsystems driver knows how much more work it can + offload to its subsystem. +3. Apply QoS for subsystems on their queues. + +Layout: +The layout represents run-time flow of messages between Ethernet subsystem, CPU +and QMTM in APM X-Gene SOC. PktDMA and Security subsystems interfaces with QMTM +in the same way as Ethernet. + + + CPU + o-------------------------o + | | + +----|[2] {5}|----+ + | | [1] {4} | | +Register | o------+-----------+------o | Register +Write | CPU WR | | CPU RD | Write +to start v MSG v ^ MSG v to notify +packet | | DDR | | packet +transmit | o--------+-----o-----+--------o | received + | | Q0 M . M M | M M . M Q1 | | + | | for S . S S | S S . S for | | + | | ETH G . G G | G G . G ETH | | + | | TX n . 2 1 | 1 2 . n RX | | + | o----------+---o---+----------o | + | | | | + v v ^ v + | | | | +o--------|-------------|-------|-------------|--------o +| | | | | | Coherent +| v v ^ v | I/O +| | | | | | BUS +o--------|-------------|-------|-------------|--------o + | [3] | | {3} | + v QMTM RD v ^ QMTM WR v + | MSG | | MSG | + o----+----o--------+---o---+--------o----+----o + | Queue 0 | | | Queue 1 | + | Command o ETH PBN 0 o CPU PBN 0 o Command | Queue Manager/ + | Register| | |Register | Traffic Manager + o---------o---+--------o--------+---o---------o + | | + v ^ +Ethernet RD MSG | [4] ETH {2} | Ethernet WR MSG +from its PBN o---+-----------------+---o to CPU PBN + | | + | Egress MAC Ingress MAC | + | [5] {1} | + o------|-----------|------o + v ^ + | | + TX Data RX Data + +Transmit Flow +[1] CPU (Ethernet driver) prepares 32 byte Ethernet egress work message and + enqueues the message to the queue in DDR. +[2] CPU (Ethernet driver) notifies QMTM that there is a message enqueued in + Ethernet transmit queue (e.g. Q0). +[3] QMTM prefetches the Ethernet egress work messages into Ethernet PBN + (e.g. ETH PBN 0). +[4] Ethernet reads work messages from its PBN. +[5] Ethernet DMAs payload from DDR to its egress FIFO and transmits data out. + +Receive Flow +{1} Ethernet receives data and DMAs payload from its ingress FIFO to DDR and + prepares a Ethernet ingress work message. +{2} Ethernet pushes work message to QMTM. +{3} QMTM prefetches the Ethernet ingress work messages into CPU PBN + (e.g. CPU PBN 0) and then interrupts CPU. +{4} CPU (Ethernet driver) dequeues the 32 bytes Ethernet ingress work message + from the queue in DDR. +{5} CPU (Ethernet driver) notifies QMTM that it dequeued a message from + Ethernet receive queue (e.g. Q1). + + +Definition: +1. QMTM (Queue/Traffic Manager) + QMTM manages queues and pbns for CPU, Ethernet, PktDMA and Security + Subsystems. It also performs flow control and QoS on queues. + +2. Slave/Client/Agent + Ethernet, PktDMA (XOR Engine) and Security Engine Subsystems & CPU whose + queues and pbn are managed by QMTM are called slave/client/agent. + +3. Queue + Queue is circular FIFO memory for QMTM hardware in which a 16 bytes, + 32 bytes or 64 bytes message is dequeued OR enqueued between CPU and + Ethernet, PktDMA and Security Engine Subsystems. + +4. PB + Each subsystem in the APM X-Gene SoC device has a prefetch buffer for + storing messages in order to pipeline the QMTM processing latency with the + subsystem processing latency. The number of buffers prefetched depends on + the QM/TM processing latency and the subsystem data rate. + + There are multiple PB for a subsystem, each PB is assigned a number which is + called PBN. Each subsystem and CPU can have max 32 pbns, however QMTM limits + how many pbns it supports for each subsystem. + +5. Message + The subsystems in the APM X-Gene SoC communicate with a central Queue Manager + (QM) that manages all the messages queued to the subsystems. The subsystems + communicate with the QM using messages that include information about the + work to be performed and the location of the buffers or data on which the + work is to be performed. + + A message consists of 16, 32 or 64 bytes which resides in a queue. A message + which is + a. 16 bytes contains information of data buffer, length, etc. allocated by + subsystem driver. + b. 32 or 64 bytes contains information about the work to be done for a + subsystem. Each subsystem defines its own format of work message. + + Each subsystem defines their own format of work message. A message (or queue + descriptor) has attribute fields (QMTM specific) which are common for all + subsystem work messages. The remaining fields of a message are specific to + subsystem. QMTM device doesn't have any knowledge of these subsystems + specific fields and the data operation which subsystem is going to perform + using these fields. + + e.g. + 1. Ethernet work message includes data address & length which is used by + Ethernet DMA engine for copying the data to/from its internal FIFO. + 2. PktDMA work message includes multiple data addresses & lengths for + doing scatter/gather, XOR operations and result data address/es to give + back result to the CPU (driver). + 3. Security work message includes data address & length for doing encryption + or decryption, the type of encryption or decryption and result data + address to give back result to the CPU (driver). --- linux-3.13.0.orig/Documentation/misc-devices/mei/mei-amt-version.c +++ linux-3.13.0/Documentation/misc-devices/mei/mei-amt-version.c @@ -115,8 +115,6 @@ struct mei_client *cl; struct mei_connect_client_data data; - mei_deinit(me); - me->verbose = verbose; me->fd = open("/dev/mei", O_RDWR); --- linux-3.13.0.orig/Documentation/virtual/kvm/api.txt +++ linux-3.13.0/Documentation/virtual/kvm/api.txt @@ -2327,7 +2327,7 @@ Capability: basic Architectures: arm, arm64 Type: vcpu ioctl -Parameters: struct struct kvm_vcpu_init (in) +Parameters: struct kvm_vcpu_init (in) Returns: 0 on success; -1 on error Errors:  EINVAL:    the target is unknown, or the combination of features is invalid. --- linux-3.13.0.orig/security/security.c +++ linux-3.13.0/security/security.c @@ -407,6 +407,7 @@ return 0; return security_ops->path_rmdir(dir, dentry); } +EXPORT_SYMBOL(security_path_rmdir); int security_path_unlink(struct path *dir, struct dentry *dentry) { @@ -423,6 +424,7 @@ return 0; return security_ops->path_symlink(dir, dentry, old_name); } +EXPORT_SYMBOL(security_path_symlink); int security_path_link(struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry) @@ -431,6 +433,7 @@ return 0; return security_ops->path_link(old_dentry, new_dir, new_dentry); } +EXPORT_SYMBOL(security_path_link); int security_path_rename(struct path *old_dir, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry) @@ -449,6 +452,7 @@ return 0; return security_ops->path_truncate(path); } +EXPORT_SYMBOL(security_path_truncate); int security_path_chmod(struct path *path, umode_t mode) { @@ -456,6 +460,7 @@ return 0; return security_ops->path_chmod(path, mode); } +EXPORT_SYMBOL(security_path_chmod); int security_path_chown(struct path *path, kuid_t uid, kgid_t gid) { @@ -463,6 +468,7 @@ return 0; return security_ops->path_chown(path, uid, gid); } +EXPORT_SYMBOL(security_path_chown); int security_path_chroot(struct path *path) { @@ -539,6 +545,7 @@ return 0; return security_ops->inode_readlink(dentry); } +EXPORT_SYMBOL(security_inode_readlink); int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) { @@ -553,6 +560,7 @@ return 0; return security_ops->inode_permission(inode, mask); } +EXPORT_SYMBOL(security_inode_permission); int security_inode_setattr(struct dentry *dentry, struct iattr *attr) { @@ -675,6 +683,7 @@ return fsnotify_perm(file, mask); } +EXPORT_SYMBOL(security_file_permission); int security_file_alloc(struct file *file) { @@ -735,6 +744,7 @@ return ret; return ima_file_mmap(file, prot); } +EXPORT_SYMBOL(security_mmap_file); int security_mmap_addr(unsigned long addr) { --- linux-3.13.0.orig/security/device_cgroup.c +++ linux-3.13.0/security/device_cgroup.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -745,6 +746,7 @@ return __devcgroup_check_permission(type, imajor(inode), iminor(inode), access); } +EXPORT_SYMBOL(__devcgroup_inode_permission); int devcgroup_inode_mknod(int mode, dev_t dev) { --- linux-3.13.0.orig/security/commoncap.c +++ linux-3.13.0/security/commoncap.c @@ -988,9 +988,11 @@ } return ret; } +EXPORT_SYMBOL(cap_mmap_addr); int cap_mmap_file(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) { return 0; } +EXPORT_SYMBOL(cap_mmap_file); --- linux-3.13.0.orig/security/apparmor/audit.c +++ linux-3.13.0/security/apparmor/audit.c @@ -39,10 +39,16 @@ "getattr", "open", + "file_receive", "file_perm", "file_lock", "file_mmap", "file_mprotect", + "file_inherit", + + "pivotroot", + "mount", + "umount", "create", "post_create", @@ -59,6 +65,7 @@ "socket_shutdown", "ptrace", + "signal", "exec", "change_hat", @@ -114,34 +121,41 @@ if (aa_g_audit_header) { audit_log_format(ab, "apparmor="); - audit_log_string(ab, aa_audit_type[sa->aad->type]); + audit_log_string(ab, aa_audit_type[aad(sa)->type]); } - if (sa->aad->op) { + if (aad(sa)->op) { audit_log_format(ab, " operation="); - audit_log_string(ab, op_table[sa->aad->op]); + audit_log_string(ab, op_table[aad(sa)->op]); } - if (sa->aad->info) { + if (aad(sa)->info) { audit_log_format(ab, " info="); - audit_log_string(ab, sa->aad->info); - if (sa->aad->error) - audit_log_format(ab, " error=%d", sa->aad->error); - } - - if (sa->aad->profile) { - struct aa_profile *profile = sa->aad->profile; - if (profile->ns != root_ns) { - audit_log_format(ab, " namespace="); - audit_log_untrustedstring(ab, profile->ns->base.hname); + audit_log_string(ab, aad(sa)->info); + if (aad(sa)->error) + audit_log_format(ab, " error=%d", aad(sa)->error); + } + + if (aad(sa)->label) { + struct aa_label *label = aad(sa)->label; + if (label_isprofile(label)) { + struct aa_profile *profile = labels_profile(label); + if (profile->ns != root_ns) { + audit_log_format(ab, " namespace="); + audit_log_untrustedstring(ab, + profile->ns->base.hname); + } + audit_log_format(ab, " profile="); + audit_log_untrustedstring(ab, profile->base.hname); + } else { + audit_log_format(ab, " label="); + aa_label_audit(ab, root_ns, label, false, GFP_ATOMIC); } - audit_log_format(ab, " profile="); - audit_log_untrustedstring(ab, profile->base.hname); } - if (sa->aad->name) { + if (aad(sa)->name) { audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, sa->aad->name); + audit_log_untrustedstring(ab, aad(sa)->name); } } @@ -153,7 +167,12 @@ void aa_audit_msg(int type, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)) { - sa->aad->type = type; + /* TODO: redirect messages for profile to the correct ns + * rejects from subns should goto the audit associated + * with it, and audits from parent ns should got ns + * associated with it + */ + aad(sa)->type = type; common_lsm_audit(sa, audit_pre, cb); } @@ -161,7 +180,6 @@ * aa_audit - Log a profile based audit event to the audit subsystem * @type: audit type for the message * @profile: profile to check against (NOT NULL) - * @gfp: allocation flags to use * @sa: audit event (NOT NULL) * @cb: optional callback fn for type specific fields (MAYBE NULL) * @@ -169,14 +187,13 @@ * * Returns: error on failure */ -int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, - struct common_audit_data *sa, +int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)) { BUG_ON(!profile); if (type == AUDIT_APPARMOR_AUTO) { - if (likely(!sa->aad->error)) { + if (likely(!aad(sa)->error)) { if (AUDIT_MODE(profile) != AUDIT_ALL) return 0; type = AUDIT_APPARMOR_AUDIT; @@ -188,22 +205,22 @@ if (AUDIT_MODE(profile) == AUDIT_QUIET || (type == AUDIT_APPARMOR_DENIED && AUDIT_MODE(profile) == AUDIT_QUIET)) - return sa->aad->error; + return aad(sa)->error; if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) type = AUDIT_APPARMOR_KILL; - if (!unconfined(profile)) - sa->aad->profile = profile; + aad(sa)->label = &profile->label; aa_audit_msg(type, sa, cb); - if (sa->aad->type == AUDIT_APPARMOR_KILL) + if (aad(sa)->type == AUDIT_APPARMOR_KILL) (void)send_sig_info(SIGKILL, NULL, - sa->u.tsk ? sa->u.tsk : current); + sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ? + sa->u.tsk : current); - if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) - return complain_error(sa->aad->error); + if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED) + return complain_error(aad(sa)->error); - return sa->aad->error; + return aad(sa)->error; } --- linux-3.13.0.orig/security/apparmor/domain.c +++ linux-3.13.0/security/apparmor/domain.c @@ -51,34 +51,38 @@ /** * may_change_ptraced_domain - check if can change profile on ptraced task * @to_profile: profile to change to (NOT NULL) + * @info: message if there is an error * * Check if current is ptraced and if so if the tracing task is allowed * to trace the new domain * * Returns: %0 or error if change not allowed */ -static int may_change_ptraced_domain(struct aa_profile *to_profile) +static int may_change_ptraced_domain(struct aa_profile *to_profile, + const char **info) { struct task_struct *tracer; - struct aa_profile *tracerp = NULL; + struct aa_label *tracerl = NULL; int error = 0; rcu_read_lock(); tracer = ptrace_parent(current); if (tracer) /* released below */ - tracerp = aa_get_task_profile(tracer); + tracerl = aa_get_task_label(tracer); /* not ptraced */ - if (!tracer || unconfined(tracerp)) + if (!tracer || unconfined(tracerl)) goto out; - error = aa_may_ptrace(tracerp, to_profile, PTRACE_MODE_ATTACH); + error = aa_may_ptrace(tracerl, &to_profile->label, PTRACE_MODE_ATTACH); out: rcu_read_unlock(); - aa_put_profile(tracerp); + aa_put_label(tracerl); + if (error) + *info = "ptrace prevents transition"; return error; } @@ -101,7 +105,7 @@ struct path_cond cond = { }; unsigned int state; - if (unconfined(profile)) { + if (profile_unconfined(profile)) { perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC; perms.audit = perms.quiet = perms.kill = 0; return perms; @@ -143,7 +147,7 @@ struct aa_profile *profile, *candidate = NULL; list_for_each_entry_rcu(profile, head, base.list) { - if (profile->flags & PFLAG_NULL) + if (profile->label.flags & FLAG_NULL) continue; if (profile->xmatch && profile->xmatch_len > len) { unsigned int state = aa_dfa_match(profile->xmatch, @@ -236,7 +240,7 @@ * * Returns: refcounted profile, or NULL on failure (MAYBE NULL) */ -static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) { struct aa_profile *new_profile = NULL; struct aa_namespace *ns = profile->ns; @@ -337,6 +341,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) { struct aa_task_cxt *cxt; + struct aa_label *label; struct aa_profile *profile, *new_profile = NULL; struct aa_namespace *ns; char *buffer = NULL; @@ -357,7 +362,8 @@ cxt = cred_cxt(bprm->cred); BUG_ON(!cxt); - profile = aa_get_newest_profile(cxt->profile); + label = aa_get_newest_label(cxt->label); + profile = labels_profile(label); /* * get the namespace from the replacement profile as replacement * can change the namespace @@ -366,11 +372,12 @@ state = profile->file.start; /* buffer freed below, name is pointer into buffer */ - error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer, + get_buffers(buffer); + error = aa_path_name(&bprm->file->f_path, profile->path_flags, buffer, &name, &info); if (error) { - if (unconfined(profile) || - (profile->flags & PFLAG_IX_ON_NAME_ERROR)) + if (profile_unconfined(profile) || + (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) error = 0; name = bprm->filename; goto audit; @@ -379,11 +386,11 @@ /* Test for onexec first as onexec directives override other * x transitions. */ - if (unconfined(profile)) { + if (profile_unconfined(profile)) { /* unconfined task */ if (cxt->onexec) /* change_profile on exec already been granted */ - new_profile = aa_get_profile(cxt->onexec); + new_profile = labels_profile(aa_get_label(cxt->onexec)); else new_profile = find_attach(ns, &ns->base.profiles, name); if (!new_profile) @@ -409,13 +416,13 @@ * exec\0change_profile */ state = aa_dfa_null_transition(profile->file.dfa, state); - cp = change_profile_perms(profile, cxt->onexec->ns, - cxt->onexec->base.name, + cp = change_profile_perms(profile, labels_profile(cxt->onexec)->ns, + labels_profile(cxt->onexec)->base.name, AA_MAY_ONEXEC, state); if (!(cp.allow & AA_MAY_ONEXEC)) goto audit; - new_profile = aa_get_newest_profile(cxt->onexec); + new_profile = labels_profile(aa_get_newest_label(cxt->onexec)); goto apply; } @@ -432,17 +439,19 @@ new_profile = aa_get_profile(profile); goto x_clear; } else if (perms.xindex & AA_X_UNCONFINED) { - new_profile = aa_get_newest_profile(ns->unconfined); + new_profile = labels_profile(aa_get_newest_label(&ns->unconfined->label)); info = "ux fallback"; } else { - error = -ENOENT; + error = -EACCES; info = "profile not found"; /* remove MAY_EXEC to audit as failure */ perms.allow &= ~MAY_EXEC; } } } else if (COMPLAIN_MODE(profile)) { - /* no exec permission - are we in learning mode */ + /* no exec permission - learning mode. break rcu lock */ + put_buffers(buffer); + name = NULL; new_profile = aa_new_null_profile(profile, 0); if (!new_profile) { error = -ENOMEM; @@ -452,6 +461,12 @@ target = new_profile->base.hname; } perms.xindex |= AA_X_UNSAFE; + /* re-aquire buffer and rcu readlock and re-get name */ + get_buffers(buffer); + if (!error) + error = aa_path_name(&bprm->file->f_path, + profile->path_flags, buffer, + &name, &info); } else /* fail exec */ error = -EACCES; @@ -475,7 +490,7 @@ } if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { - error = may_change_ptraced_domain(new_profile); + error = may_change_ptraced_domain(new_profile, &info); if (error) { aa_put_profile(new_profile); goto audit; @@ -505,20 +520,20 @@ bprm->per_clear |= PER_CLEAR_ON_SETID; x_clear: - aa_put_profile(cxt->profile); + aa_put_label(cxt->label); /* transfer new profile reference will be released when cxt is freed */ - cxt->profile = new_profile; + cxt->label = &new_profile->label; /* clear out all temporary/transitional state from the context */ aa_clear_task_cxt_trans(cxt); audit: - error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC, - name, target, cond.uid, info, error); + error = aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, target, + cond.uid, info, error); cleanup: - aa_put_profile(profile); - kfree(buffer); + aa_put_label(label); + put_buffers(buffer); return error; } @@ -542,36 +557,6 @@ return ret; } -/** - * apparmor_bprm_committing_creds - do task cleanup on committing new creds - * @bprm: binprm for the exec (NOT NULL) - */ -void apparmor_bprm_committing_creds(struct linux_binprm *bprm) -{ - struct aa_profile *profile = __aa_current_profile(); - struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred); - - /* bail out if unconfined or not changing profile */ - if ((new_cxt->profile == profile) || - (unconfined(new_cxt->profile))) - return; - - current->pdeath_signal = 0; - - /* reset soft limits and set hard limits for the new profile */ - __aa_transition_rlimits(profile, new_cxt->profile); -} - -/** - * apparmor_bprm_commited_cred - do cleanup after new creds committed - * @bprm: binprm for the exec (NOT NULL) - */ -void apparmor_bprm_committed_creds(struct linux_binprm *bprm) -{ - /* TODO: cleanup signals - ipc mediation */ - return; -} - /* * Functions for self directed profile change */ @@ -609,7 +594,8 @@ { const struct cred *cred; struct aa_task_cxt *cxt; - struct aa_profile *profile, *previous_profile, *hat = NULL; + struct aa_label *label, *previous; + struct aa_profile *profile, *hat = NULL; char *name = NULL; int i; struct file_perms perms = {}; @@ -627,10 +613,12 @@ /* released below */ cred = get_current_cred(); cxt = cred_cxt(cred); - profile = aa_cred_profile(cred); - previous_profile = cxt->previous; + label = aa_get_newest_cred_label(cred); + previous = cxt->previous; + + profile = labels_profile(label); - if (unconfined(profile)) { + if (unconfined(label)) { info = "unconfined"; error = -EPERM; goto audit; @@ -642,7 +630,7 @@ if (PROFILE_IS_HAT(profile)) root = aa_get_profile_rcu(&profile->parent); else - root = aa_get_profile(profile); + root = aa_get_profile(labels_profile(label)); /* find first matching hat */ for (i = 0; i < count && !hat; i++) @@ -688,15 +676,14 @@ } } - error = may_change_ptraced_domain(hat); + error = may_change_ptraced_domain(hat, &info); if (error) { - info = "ptraced"; error = -EPERM; goto audit; } if (!permtest) { - error = aa_set_current_hat(hat, token); + error = aa_set_current_hat(&hat->label, token); if (error == -EACCES) /* kill task in case of brute force attacks */ perms.kill = AA_MAY_CHANGEHAT; @@ -704,12 +691,12 @@ /* reset error for learning of new hats */ error = -ENOENT; } - } else if (previous_profile) { - /* Return to saved profile. Kill task if restore fails + } else if (previous) { + /* Return to saved label. Kill task if restore fails * to avoid brute force attacks */ - target = previous_profile->base.hname; - error = aa_restore_previous_profile(token); + target = previous->hname; + error = aa_restore_previous_label(token); perms.kill = AA_MAY_CHANGEHAT; } else /* ignore restores when there is no saved profile */ @@ -717,12 +704,13 @@ audit: if (!permtest) - error = aa_audit_file(profile, &perms, GFP_KERNEL, - OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL, - target, GLOBAL_ROOT_UID, info, error); + error = aa_audit_file(profile, &perms, OP_CHANGE_HAT, + AA_MAY_CHANGEHAT, NULL, target, + GLOBAL_ROOT_UID, info, error); out: aa_put_profile(hat); + aa_put_label(label); kfree(name); put_cred(cred); @@ -748,6 +736,7 @@ bool permtest) { const struct cred *cred; + struct aa_label *label; struct aa_profile *profile, *target = NULL; struct aa_namespace *ns = NULL; struct file_perms perms = {}; @@ -767,7 +756,8 @@ } cred = get_current_cred(); - profile = aa_cred_profile(cred); + label = aa_get_newest_cred_label(cred); + profile = labels_profile(label); /* * Fail explicitly requested domain transitions if no_new_privs @@ -776,7 +766,8 @@ * no_new_privs is set because this aways results in a reduction * of permissions. */ - if (current->no_new_privs && !unconfined(profile)) { + if (current->no_new_privs && !unconfined(label)) { + aa_put_label(label); put_cred(cred); return -EPERM; } @@ -797,7 +788,7 @@ /* if the name was not specified, use the name of the current profile */ if (!hname) { - if (unconfined(profile)) + if (profile_unconfined(profile)) hname = ns->unconfined->base.hname; else hname = profile->base.hname; @@ -827,27 +818,26 @@ } /* check if tracing task is allowed to trace target domain */ - error = may_change_ptraced_domain(target); - if (error) { - info = "ptrace prevents transition"; + error = may_change_ptraced_domain(target, &info); + if (error) goto audit; - } if (permtest) goto audit; if (onexec) - error = aa_set_current_onexec(target); + error = aa_set_current_onexec(&target->label); else - error = aa_replace_current_profile(target); + error = aa_replace_current_label(&target->label); audit: if (!permtest) - error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, - name, hname, GLOBAL_ROOT_UID, info, error); + error = aa_audit_file(profile, &perms, op, request, name, + hname, GLOBAL_ROOT_UID, info, error); aa_put_namespace(ns); aa_put_profile(target); + aa_put_label(label); put_cred(cred); return error; --- linux-3.13.0.orig/security/apparmor/lsm.c +++ linux-3.13.0/security/apparmor/lsm.c @@ -32,19 +32,24 @@ #include "include/context.h" #include "include/file.h" #include "include/ipc.h" +#include "include/net.h" #include "include/path.h" #include "include/policy.h" #include "include/procattr.h" +#include "include/mount.h" /* Flag indicating whether initialization completed */ int apparmor_initialized __initdata; +DEFINE_PER_CPU(struct aa_buffers, aa_buffers); + + /* * LSM hook functions */ /* - * free the associated aa_task_cxt and put its profiles + * free the associated aa_task_cxt and put its labels */ static void apparmor_cred_free(struct cred *cred) { @@ -96,42 +101,62 @@ static int apparmor_ptrace_access_check(struct task_struct *child, unsigned int mode) { + struct aa_label *tracer, *tracee; int error = cap_ptrace_access_check(child, mode); if (error) return error; - return aa_ptrace(current, child, mode); + tracer = aa_current_label(); + tracee = aa_get_task_label(child); + error = aa_may_ptrace(tracer, tracee, + mode == PTRACE_MODE_READ ? AA_PTRACE_READ : AA_PTRACE_TRACE); + aa_put_label(tracee); + return error; } static int apparmor_ptrace_traceme(struct task_struct *parent) { + struct aa_label *tracer, *tracee; int error = cap_ptrace_traceme(parent); if (error) return error; - return aa_ptrace(parent, current, PTRACE_MODE_ATTACH); + tracee = aa_current_label(); + tracer = aa_get_task_label(parent); + error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE); + aa_put_label(tracer); + return error; } /* Derived from security/commoncap.c:cap_capget */ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - struct aa_profile *profile; + struct aa_label *label; const struct cred *cred; rcu_read_lock(); cred = __task_cred(target); - profile = aa_cred_profile(cred); + label = aa_get_newest_cred_label(cred); *effective = cred->cap_effective; *inheritable = cred->cap_inheritable; *permitted = cred->cap_permitted; - if (!unconfined(profile) && !COMPLAIN_MODE(profile)) { - *effective = cap_intersect(*effective, profile->caps.allow); - *permitted = cap_intersect(*permitted, profile->caps.allow); + if (!unconfined(label)) { + struct aa_profile *profile; + struct label_it i; + label_for_each_confined(i, label, profile) { + if (COMPLAIN_MODE(profile)) + continue; + *effective = cap_intersect(*effective, + profile->caps.allow); + *permitted = cap_intersect(*permitted, + profile->caps.allow); + } } rcu_read_unlock(); + aa_put_label(label); return 0; } @@ -139,14 +164,17 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, int cap, int audit) { - struct aa_profile *profile; + struct aa_label *label; /* cap_capable returns 0 on success, else -EPERM */ int error = cap_capable(cred, ns, cap, audit); - if (!error) { - profile = aa_cred_profile(cred); - if (!unconfined(profile)) - error = aa_capable(profile, cap, audit); - } + if (error) + return error; + + label = aa_get_newest_cred_label(cred); + if (!unconfined(label)) + error = aa_capable(label, cap, audit); + aa_put_label(label); + return error; } @@ -162,16 +190,36 @@ static int common_perm(int op, struct path *path, u32 mask, struct path_cond *cond) { - struct aa_profile *profile; + struct aa_label *label; int error = 0; - profile = __aa_current_profile(); - if (!unconfined(profile)) - error = aa_path_perm(op, profile, path, 0, mask, cond); + label = __aa_get_current_label(); + if (!unconfined(label)) + error = aa_path_perm(op, label, path, 0, mask, cond); + __aa_put_current_label(label); return error; } +static int common_perm_cond(int op, struct path *path, u32 mask) +{ + struct path_cond cond = { path->dentry->d_inode->i_uid, + path->dentry->d_inode->i_mode + }; + + return common_perm(op, path, mask, &cond); +} + +static void apparmor_inode_free_security(struct inode *inode) +{ + struct aa_label *cxt = inode_cxt(inode); + + if (cxt) { + inode_cxt(inode) = NULL; + aa_put_label(cxt); + } +} + /** * common_perm_dir_dentry - common permission wrapper when path is dir, dentry * @op: operation being checked @@ -204,11 +252,8 @@ struct dentry *dentry, u32 mask) { struct path path = { mnt, dentry }; - struct path_cond cond = { dentry->d_inode->i_uid, - dentry->d_inode->i_mode - }; - return common_perm(op, &path, mask, &cond); + return common_perm_cond(op, &path, mask); } /** @@ -226,7 +271,7 @@ struct inode *inode = dentry->d_inode; struct path_cond cond = { }; - if (!inode || !dir->mnt || !mediated_filesystem(inode)) + if (!inode || !dir->mnt || !path_mediated_fs(inode)) return 0; cond.uid = inode->i_uid; @@ -250,7 +295,7 @@ { struct path_cond cond = { current_fsuid(), mode }; - if (!dir->mnt || !mediated_filesystem(dir->dentry->d_inode)) + if (!dir->mnt || !path_mediated_fs(dir->dentry->d_inode)) return 0; return common_perm_dir_dentry(op, dir, dentry, mask, &cond); @@ -281,15 +326,10 @@ static int apparmor_path_truncate(struct path *path) { - struct path_cond cond = { path->dentry->d_inode->i_uid, - path->dentry->d_inode->i_mode - }; - - if (!path->mnt || !mediated_filesystem(path->dentry->d_inode)) + if (!path->mnt || !path_mediated_fs(path->dentry->d_inode)) return 0; - return common_perm(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE, - &cond); + return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE); } static int apparmor_path_symlink(struct path *dir, struct dentry *dentry, @@ -302,41 +342,41 @@ static int apparmor_path_link(struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry) { - struct aa_profile *profile; + struct aa_label *label; int error = 0; - if (!mediated_filesystem(old_dentry->d_inode)) + if (!path_mediated_fs(old_dentry->d_inode)) return 0; - profile = aa_current_profile(); - if (!unconfined(profile)) - error = aa_path_link(profile, old_dentry, new_dir, new_dentry); + label = aa_current_label(); + if (!unconfined(label)) + error = aa_path_link(label, old_dentry, new_dir, new_dentry); return error; } static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry) { - struct aa_profile *profile; + struct aa_label *label; int error = 0; - if (!mediated_filesystem(old_dentry->d_inode)) + if (!path_mediated_fs(old_dentry->d_inode)) return 0; - profile = aa_current_profile(); - if (!unconfined(profile)) { + label = aa_current_label(); + if (!unconfined(label)) { struct path old_path = { old_dir->mnt, old_dentry }; struct path new_path = { new_dir->mnt, new_dentry }; struct path_cond cond = { old_dentry->d_inode->i_uid, old_dentry->d_inode->i_mode }; - error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0, + error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0, MAY_READ | AA_MAY_META_READ | MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_DELETE, &cond); if (!error) - error = aa_path_perm(OP_RENAME_DEST, profile, &new_path, + error = aa_path_perm(OP_RENAME_DEST, label, &new_path, 0, MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CREATE, &cond); @@ -346,27 +386,23 @@ static int apparmor_path_chmod(struct path *path, umode_t mode) { - if (!mediated_filesystem(path->dentry->d_inode)) + if (!path_mediated_fs(path->dentry->d_inode)) return 0; - return common_perm_mnt_dentry(OP_CHMOD, path->mnt, path->dentry, AA_MAY_CHMOD); + return common_perm_cond(OP_CHMOD, path, AA_MAY_CHMOD); } static int apparmor_path_chown(struct path *path, kuid_t uid, kgid_t gid) { - struct path_cond cond = { path->dentry->d_inode->i_uid, - path->dentry->d_inode->i_mode - }; - - if (!mediated_filesystem(path->dentry->d_inode)) + if (!path_mediated_fs(path->dentry->d_inode)) return 0; - return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond); + return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN); } static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) { - if (!mediated_filesystem(dentry->d_inode)) + if (!path_mediated_fs(dentry->d_inode)) return 0; return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry, @@ -375,11 +411,11 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) { - struct aa_file_cxt *fcxt = file->f_security; - struct aa_profile *profile; + struct aa_file_cxt *fcxt = file_cxt(file); + struct aa_label *label; int error = 0; - if (!mediated_filesystem(file_inode(file))) + if (!path_mediated_fs(file_inode(file))) return 0; /* If in exec, permission is handled by bprm hooks. @@ -392,16 +428,17 @@ return 0; } - profile = aa_cred_profile(cred); - if (!unconfined(profile)) { + label = aa_get_newest_cred_label(cred); + if (!unconfined(label)) { struct inode *inode = file_inode(file); struct path_cond cond = { inode->i_uid, inode->i_mode }; - error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0, + error = aa_path_perm(OP_OPEN, label, &file->f_path, 0, aa_map_file_to_perms(file), &cond); /* todo cache full allowed permissions set and state */ fcxt->allow = aa_map_file_to_perms(file); } + aa_put_label(label); return error; } @@ -409,8 +446,8 @@ static int apparmor_file_alloc_security(struct file *file) { /* freed by apparmor_file_free_security */ - file->f_security = aa_alloc_file_context(GFP_KERNEL); - if (!file->f_security) + file->f_security = aa_alloc_file_cxt(aa_current_label(), GFP_KERNEL); + if (!file_cxt(file)) return -ENOMEM; return 0; @@ -418,39 +455,26 @@ static void apparmor_file_free_security(struct file *file) { - struct aa_file_cxt *cxt = file->f_security; - - aa_free_file_context(cxt); + aa_free_file_cxt(file_cxt(file)); } static int common_file_perm(int op, struct file *file, u32 mask) { - struct aa_file_cxt *fcxt = file->f_security; - struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred); + struct aa_label *label; int error = 0; - BUG_ON(!fprofile); - - if (!file->f_path.mnt || - !mediated_filesystem(file_inode(file))) - return 0; - - profile = __aa_current_profile(); - - /* revalidate access, if task is unconfined, or the cached cred - * doesn't match or if the request is for more permissions than - * was granted. - * - * Note: the test for !unconfined(fprofile) is to handle file - * delegation from unconfined tasks - */ - if (!unconfined(profile) && !unconfined(fprofile) && - ((fprofile != profile) || (mask & ~fcxt->allow))) - error = aa_file_perm(op, profile, file, mask); + label = __aa_get_current_label(); + error = aa_file_perm(op, label, file, mask); + __aa_put_current_label(label); return error; } +static int apparmor_file_receive(struct file *file) +{ + return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file)); +} + static int apparmor_file_permission(struct file *file, int mask) { return common_file_perm(OP_FPERM, file, mask); @@ -471,7 +495,7 @@ { int mask = 0; - if (!file || !file->f_security) + if (!file || !file_cxt(file)) return 0; if (prot & PROT_READ) @@ -501,6 +525,60 @@ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); } +static int apparmor_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) +{ + struct aa_label *label; + int error = 0; + + /* Discard magic */ + if ((flags & MS_MGC_MSK) == MS_MGC_VAL) + flags &= ~MS_MGC_MSK; + + flags &= ~AA_MS_IGNORE_MASK; + + label = __aa_current_label(); + if (!unconfined(label)) { + if (flags & MS_REMOUNT) + error = aa_remount(label, path, flags, data); + else if (flags & MS_BIND) + error = aa_bind_mount(label, path, dev_name, flags); + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | + MS_UNBINDABLE)) + error = aa_mount_change_type(label, path, flags); + else if (flags & MS_MOVE) + error = aa_move_mount(label, path, dev_name); + else + error = aa_new_mount(label, dev_name, path, type, + flags, data); + } + return error; +} + +static int apparmor_sb_umount(struct vfsmount *mnt, int flags) +{ + struct aa_label *label; + int error = 0; + + label = __aa_current_label(); + if (!unconfined(label)) + error = aa_umount(label, mnt, flags); + + return error; +} + +static int apparmor_sb_pivotroot(struct path *old_path, struct path *new_path) +{ + struct aa_label *label; + int error = 0; + + label = __aa_current_label(); + if (!unconfined(label)) + error = aa_pivotroot(label, old_path, new_path); + + return error; +} + static int apparmor_getprocattr(struct task_struct *task, char *name, char **value) { @@ -508,21 +586,21 @@ /* released below */ const struct cred *cred = get_task_cred(task); struct aa_task_cxt *cxt = cred_cxt(cred); - struct aa_profile *profile = NULL; + struct aa_label *label = NULL; if (strcmp(name, "current") == 0) - profile = aa_get_newest_profile(cxt->profile); + label = aa_get_newest_label(cxt->label); else if (strcmp(name, "prev") == 0 && cxt->previous) - profile = aa_get_newest_profile(cxt->previous); + label = aa_get_newest_label(cxt->previous); else if (strcmp(name, "exec") == 0 && cxt->onexec) - profile = aa_get_newest_profile(cxt->onexec); + label = aa_get_newest_label(cxt->onexec); else error = -EINVAL; - if (profile) - error = aa_getprocattr(profile, value); + if (label) + error = aa_getprocattr(label, value); - aa_put_profile(profile); + aa_put_label(label); put_cred(cred); return error; @@ -531,8 +609,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, void *value, size_t size) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETPROCATTR); char *command, *args = value; size_t arg_size; int error; @@ -593,28 +670,455 @@ return error; fail: - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.profile = aa_current_profile(); - aad.op = OP_SETPROCATTR; - aad.info = name; - aad.error = -EINVAL; + aad(&sa)->label = aa_current_label(); + aad(&sa)->info = name; + aad(&sa)->error = -EINVAL; aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL); return -EINVAL; } +/** + * apparmor_bprm_committing_creds - do task cleanup on committing new creds + * @bprm: binprm for the exec (NOT NULL) + */ +void apparmor_bprm_committing_creds(struct linux_binprm *bprm) +{ + struct aa_label *label = __aa_current_label(); + struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred); + + /* bail out if unconfined or not changing profile */ + if ((new_cxt->label == label) || (unconfined(new_cxt->label))) + return; + + aa_inherit_files(bprm->cred, current->files); + + current->pdeath_signal = 0; + + /* reset soft limits and set hard limits for the new label */ + __aa_transition_rlimits(label, new_cxt->label); +} + +/** + * apparmor_bprm_commited_cred - do cleanup after new creds committed + * @bprm: binprm for the exec (NOT NULL) + */ +void apparmor_bprm_committed_creds(struct linux_binprm *bprm) +{ + /* TODO: cleanup signals - ipc mediation */ + return; +} + static int apparmor_task_setrlimit(struct task_struct *task, unsigned int resource, struct rlimit *new_rlim) { - struct aa_profile *profile = __aa_current_profile(); + struct aa_label *label = __aa_get_current_label(); int error = 0; - if (!unconfined(profile)) - error = aa_task_setrlimit(profile, task, resource, new_rlim); + if (!unconfined(label)) + error = aa_task_setrlimit(label, task, resource, new_rlim); + __aa_put_current_label(label); return error; } +/** + * apparmor_sk_alloc_security - allocate and attach the sk_security field + */ +static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags) +{ + struct aa_sk_cxt *cxt; + + cxt = kzalloc(sizeof(*cxt), flags); + if (!cxt) + return -ENOMEM; + + SK_CXT(sk) = cxt; + + return 0; +} + +/** + * apparmor_sk_free_security - free the sk_security field + */ +static void apparmor_sk_free_security(struct sock *sk) +{ + struct aa_sk_cxt *cxt = SK_CXT(sk); + + SK_CXT(sk) = NULL; + aa_put_label(cxt->label); + aa_put_label(cxt->peer); + kfree(cxt); +} + +/** + * apparmor_clone_security - clone the sk_security field + */ +static void apparmor_sk_clone_security(const struct sock *sk, + struct sock *newsk) +{ + struct aa_sk_cxt *cxt = SK_CXT(sk); + struct aa_sk_cxt *new = SK_CXT(newsk); + + new->label = aa_get_label(cxt->label); + new->peer = aa_get_label(cxt->peer); +} + +#include +#define UNIX_ANONYMOUS(U) (!unix_sk(U)->addr) +/* from net/af_unix.c */ +#define UNIX_FS(U) (!UNIX_ANONYMOUS(U) && unix_sk(U)->addr->name->sun_path[0]) + +static int unix_fs_perm(int op, struct aa_label *label, struct sock *sk, + u32 mask) +{ + if (!LABEL_MEDIATES(label, AA_CLASS_FILE)) + return 0; + + if (!unconfined(label) && UNIX_FS(sk)) { + struct unix_sock *u = unix_sk(sk); + + /* the sunpath may not be valid for this ns so use the path */ + struct path_cond cond = { u->path.dentry->d_inode->i_uid, + u->path.dentry->d_inode->i_mode + }; + + return aa_path_perm(op, label, &u->path, 0, mask, &cond); + } + return 0; +} + +/** + * apparmor_unix_stream_connect - check perms before making unix domain conn + * + * other is locked when this hook is called + */ +static int apparmor_unix_stream_connect(struct sock *sock, struct sock *other, + struct sock *newsk) +{ + struct aa_sk_cxt *sock_cxt = SK_CXT(sock); + struct aa_sk_cxt *other_cxt = SK_CXT(other); + struct aa_sk_cxt *new_cxt = SK_CXT(newsk); + struct aa_label *label; + int error; + + label = __aa_get_current_label(); + error = unix_fs_perm(OP_CONNECT, label, other, + MAY_READ | MAY_WRITE); + __aa_put_current_label(label); + + if (error) + return error; + + /* Cross reference the peer labels for SO_PEERSEC */ + if (new_cxt->peer) { + aa_put_label(new_cxt->peer); + } + if (sock_cxt->peer) { + aa_put_label(sock_cxt->peer); + } + + new_cxt->peer = aa_get_label(sock_cxt->label); + sock_cxt->peer = aa_get_label(other_cxt->label); + + return 0; +} + +/** + * apparmor_unix_may_send - check perms before conn or sending unix dgrams + * + * other is locked when this hook is called + */ +static int apparmor_unix_may_send(struct socket *sock, struct socket *other) +{ + struct aa_sk_cxt *other_cxt = SK_CXT(other->sk); + struct aa_sk_cxt *cxt = SK_CXT(sock->sk); + struct aa_label *label = __aa_get_current_label(); + int error; + + /* TODO update label instead */ + AA_BUG(!aa_label_is_subset(cxt->label, label)); + + error = xcheck(unix_fs_perm(OP_SENDMSG, label, other->sk, MAY_WRITE), + unix_fs_perm(OP_SENDMSG, other_cxt->label, sock->sk, + MAY_READ)); + __aa_put_current_label(label); + + return error; +} + +/** + * apparmor_socket_create - check perms before create a new socket + */ +static int apparmor_socket_create(int family, int type, int protocol, int kern) +{ + struct aa_label *label; + + label = aa_current_label(); + if (kern || unconfined(label)) + return 0; + + return aa_net_perm(OP_CREATE, label, family, type, protocol, NULL); +} + +/** + * apparmor_socket_post_create - setup the per-socket security struct + * + * Note: socket likely does not have sk here + * sk labeling done in sock_graft + */ +static int apparmor_socket_post_create(struct socket *sock, int family, + int type, int protocol, int kern) +{ + if (!kern) { + SOCK_CXT(sock) = aa_get_label(aa_current_label()); + + if (sock->sk) { + struct aa_sk_cxt *cxt = SK_CXT(sock->sk); + aa_put_label(cxt->label); + cxt->label = aa_get_label(aa_current_label()); + } + } + return 0; +} + +/** + * apparmor_socket_bind - check perms before bind addr to socket + */ +static int apparmor_socket_bind(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_BIND, sk); +} + +/** + * apparmor_socket_connect - check perms before connecting @sock to @address + */ +static int apparmor_socket_connect(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_CONNECT, sk); +} + +/** + * apparmor_socket_list - check perms before allowing listen + */ +static int apparmor_socket_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_LISTEN, sk); +} + +/** + * apparmor_socket_accept - check perms before accepting a new connection. + * + * Note: while @newsock is created and has some information, the accept + * has not been done. + */ +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_ACCEPT, sk); +} + +/** + * apparmor_socket_sendmsg - check perms before sending msg to another socket + */ +static int apparmor_socket_sendmsg(struct socket *sock, + struct msghdr *msg, int size) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_SENDMSG, sk); +} + +/** + * apparmor_socket_recvmsg - check perms before receiving a message + */ +static int apparmor_socket_recvmsg(struct socket *sock, + struct msghdr *msg, int size, int flags) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_RECVMSG, sk); +} + +/** + * apparmor_socket_getsockname - check perms before getting the local address + */ +static int apparmor_socket_getsockname(struct socket *sock) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_GETSOCKNAME, sk); +} + +/** + * apparmor_socket_getpeername - check perms before getting remote address + */ +static int apparmor_socket_getpeername(struct socket *sock) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_GETPEERNAME, sk); +} + +/** + * apparmor_getsockopt - check perms before getting socket options + */ +static int apparmor_socket_getsockopt(struct socket *sock, int level, + int optname) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_GETSOCKOPT, sk); +} + +/** + * apparmor_setsockopt - check perms before setting socket options + */ +static int apparmor_socket_setsockopt(struct socket *sock, int level, + int optname) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_SETSOCKOPT, sk); +} + +/** + * apparmor_socket_shutdown - check perms before shutting down @sock conn + */ +static int apparmor_socket_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk); +} + +/* from net/af_unix.c */ +#define unix_peer(sk) (unix_sk(sk)->peer) + +static struct aa_label *sk_peer_label(struct sock *sk) +{ + struct sock *peer_sk; + struct aa_sk_cxt *cxt = SK_CXT(sk); + + if (cxt->peer) + return cxt->peer; + + if (sk->sk_family != PF_UNIX) + return ERR_PTR(-ENOPROTOOPT); + + /* check for sockpair peering which does not go through + * security_unix_stream_connect + */ + peer_sk = unix_peer(sk); + if (peer_sk) { + cxt = SK_CXT(peer_sk); + if (cxt->label) + return cxt->label; + } + + return ERR_PTR(-ENOPROTOOPT); +} + +/** + * apparmor_socket_getpeersec_stream - get security context of peer + * + * Note: for tcp only valid if using ipsec or cipso on lan + */ +static int apparmor_socket_getpeersec_stream(struct socket *sock, + char __user *optval, + int __user *optlen, unsigned len) +{ + char *name; + int slen, error = 0; + struct aa_label *label = aa_current_label(); + struct aa_label *peer = sk_peer_label(sock->sk); + + if (IS_ERR(peer)) + return PTR_ERR(peer); + + slen = aa_label_asprint(&name, labels_ns(label), peer, true, GFP_KERNEL); + /* don't include terminating \0 in slen, it breaks some apps */ + if (slen < 0) { + error = -ENOMEM; + } else { + if (slen > len) { + error = -ERANGE; + } else if (copy_to_user(optval, name, slen)) { + error = -EFAULT; + goto out; + } + if (put_user(slen, optlen)) + error = -EFAULT; + out: + kfree(name); + + } + + return error; +} + +/** + * apparmor_socket_getpeersec_dgram - get security label of packet + * @sock: the peer socket + * @skb: packet data + * @secid: pointer to where to put the secid of the packet + * + * Sets the netlabel socket state on sk from parent + */ +static int apparmor_socket_getpeersec_dgram(struct socket *sock, + struct sk_buff *skb, u32 *secid) + +{ + /* TODO: requires secid support, and netlabel */ + return -ENOPROTOOPT; +} + +/** + * apparmor_sock_graft - set the sockets to the current_label + * + * could set off of SOCK_CXT(parent) but need to track inode and we can + * just + * set sk security information off of current creating process label + */ +static void apparmor_sock_graft(struct sock *sk, struct socket *parent) +{ + struct aa_sk_cxt *cxt = SK_CXT(sk); + if (cxt->label) { + aa_put_label(cxt->label); + } + + cxt->label = aa_get_label(__aa_current_label()); +} + +static int apparmor_task_kill(struct task_struct *target, struct siginfo *info, + int sig, u32 secid) +{ + struct aa_label *cl, *tl; + int error; + + if (secid) + /* TODO: after secid to label mapping is done. + * Dealing with USB IO specific behavior + */ + return 0; + cl = __aa_current_label(); + tl = aa_get_task_label(target); + error = aa_may_signal(cl, tl, sig); + aa_put_label(tl); + __aa_put_current_label(cl); + + return error; +} + + static struct security_operations apparmor_ops = { .name = "apparmor", @@ -623,6 +1127,12 @@ .capget = apparmor_capget, .capable = apparmor_capable, + .inode_free_security = apparmor_inode_free_security, + + .sb_mount = apparmor_sb_mount, + .sb_umount = apparmor_sb_umount, + .sb_pivotroot = apparmor_sb_pivotroot, + .path_link = apparmor_path_link, .path_unlink = apparmor_path_unlink, .path_symlink = apparmor_path_symlink, @@ -636,6 +1146,7 @@ .inode_getattr = apparmor_inode_getattr, .file_open = apparmor_file_open, + .file_receive = apparmor_file_receive, .file_permission = apparmor_file_permission, .file_alloc_security = apparmor_file_alloc_security, .file_free_security = apparmor_file_free_security, @@ -647,6 +1158,30 @@ .getprocattr = apparmor_getprocattr, .setprocattr = apparmor_setprocattr, + .sk_alloc_security = apparmor_sk_alloc_security, + .sk_free_security = apparmor_sk_free_security, + .sk_clone_security = apparmor_sk_clone_security, + + .unix_stream_connect = apparmor_unix_stream_connect, + .unix_may_send = apparmor_unix_may_send, + + .socket_create = apparmor_socket_create, + .socket_post_create = apparmor_socket_post_create, + .socket_bind = apparmor_socket_bind, + .socket_connect = apparmor_socket_connect, + .socket_listen = apparmor_socket_listen, + .socket_accept = apparmor_socket_accept, + .socket_sendmsg = apparmor_socket_sendmsg, + .socket_recvmsg = apparmor_socket_recvmsg, + .socket_getsockname = apparmor_socket_getsockname, + .socket_getpeername = apparmor_socket_getpeername, + .socket_getsockopt = apparmor_socket_getsockopt, + .socket_setsockopt = apparmor_socket_setsockopt, + .socket_shutdown = apparmor_socket_shutdown, + .socket_getpeersec_stream = apparmor_socket_getpeersec_stream, + .socket_getpeersec_dgram = apparmor_socket_getpeersec_dgram, + .sock_graft = apparmor_sock_graft, + .cred_alloc_blank = apparmor_cred_alloc_blank, .cred_free = apparmor_cred_free, .cred_prepare = apparmor_cred_prepare, @@ -658,6 +1193,7 @@ .bprm_secureexec = apparmor_bprm_secureexec, .task_setrlimit = apparmor_task_setrlimit, + .task_kill = apparmor_task_kill, }; /* @@ -748,6 +1284,11 @@ static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; module_param_named(enabled, apparmor_enabled, bool, S_IRUGO); +/* Boot time to set use of default or unconfined as initial profile */ +bool aa_g_unconfined_init = CONFIG_SECURITY_APPARMOR_UNCONFINED_INIT; +module_param_named(unconfined, aa_g_unconfined_init, bool, S_IRUSR); + + static int __init apparmor_enabled_setup(char *str) { unsigned long enabled; @@ -876,8 +1417,6 @@ /** * set_init_cxt - set a task context and profile on the first task. - * - * TODO: allow setting an alternate profile than unconfined */ static int __init set_init_cxt(void) { @@ -888,12 +1427,56 @@ if (!cxt) return -ENOMEM; - cxt->profile = aa_get_profile(root_ns->unconfined); + if (!aa_g_unconfined_init) { + cxt->label = aa_setup_default_label(); + if (!cxt->label) { + aa_free_task_context(cxt); + return -ENOMEM; + } + /* fs setup of default is done in aa_create_aafs() */ + } else + cxt->label = aa_get_label(&root_ns->unconfined->label); cred_cxt(cred) = cxt; return 0; } +static void destroy_buffers(void) +{ + u32 i, j; + + for_each_possible_cpu(i) { + for_each_cpu_buffer(j) { + kfree(per_cpu(aa_buffers, i).buf[j]); + per_cpu(aa_buffers, i).buf[j] = NULL; + } + } +} + +static int __init alloc_buffers(void) +{ + u32 i, j; + + for_each_possible_cpu(i) { + for_each_cpu_buffer(j) { + char *buffer; + if (cpu_to_node(i) > num_online_nodes()) + /* fallback to kmalloc for offline nodes */ + buffer = kmalloc(aa_g_path_max, GFP_KERNEL); + else + buffer = kmalloc_node(aa_g_path_max, GFP_KERNEL, + cpu_to_node(i)); + if (!buffer) { + destroy_buffers(); + return -ENOMEM; + } + per_cpu(aa_buffers, i).buf[j] = buffer; + } + } + + return 0; +} + static int __init apparmor_init(void) { int error; @@ -910,6 +1493,12 @@ goto alloc_out; } + error = alloc_buffers(); + if (error) { + AA_ERROR("Unable to allocate work buffers\n"); + goto buffers_out; + } + error = set_init_cxt(); if (error) { AA_ERROR("Failed to set context on init task\n"); @@ -939,6 +1528,9 @@ register_security_out: aa_free_root_ns(); +buffers_out: + destroy_buffers(); + alloc_out: aa_destroy_aafs(); --- linux-3.13.0.orig/security/apparmor/procattr.c +++ linux-3.13.0/security/apparmor/procattr.c @@ -33,50 +33,29 @@ * * Returns: size of string placed in @string else error code on failure */ -int aa_getprocattr(struct aa_profile *profile, char **string) +int aa_getprocattr(struct aa_label *label, char **string) { - char *str; - int len = 0, mode_len = 0, ns_len = 0, name_len; - const char *mode_str = aa_profile_mode_names[profile->mode]; - const char *ns_name = NULL; - struct aa_namespace *ns = profile->ns; - struct aa_namespace *current_ns = __aa_current_profile()->ns; - char *s; + struct aa_namespace *ns = labels_ns(label); + struct aa_namespace *current_ns = labels_ns(__aa_current_label()); + int len; if (!aa_ns_visible(current_ns, ns)) return -EACCES; - ns_name = aa_ns_name(current_ns, ns); - ns_len = strlen(ns_name); + len = aa_label_snprint(NULL, 0, current_ns, label, true); + AA_BUG(len < 0); - /* if the visible ns_name is > 0 increase size for : :// seperator */ - if (ns_len) - ns_len += 4; - - /* unconfined profiles don't have a mode string appended */ - if (!unconfined(profile)) - mode_len = strlen(mode_str) + 3; /* + 3 for _() */ - - name_len = strlen(profile->base.hname); - len = mode_len + ns_len + name_len + 1; /* + 1 for \n */ - s = str = kmalloc(len + 1, GFP_KERNEL); /* + 1 \0 */ - if (!str) + *string = kmalloc(len + 2, GFP_KERNEL); + if (!*string) return -ENOMEM; - if (ns_len) { - /* skip over prefix current_ns->base.hname and separating // */ - sprintf(s, ":%s://", ns_name); - s += ns_len; - } - if (unconfined(profile)) - /* mode string not being appended */ - sprintf(s, "%s\n", profile->base.hname); - else - sprintf(s, "%s (%s)\n", profile->base.hname, mode_str); - *string = str; + len = aa_label_snprint(*string, len + 2, current_ns, label, true); + if (len < 0) + return len; + (*string)[len] = '\n'; + (*string)[len + 1] = 0; - /* NOTE: len does not include \0 of string, not saved as part of file */ - return len; + return len + 1; } /** @@ -138,12 +117,13 @@ for (count = 0; (hat < end) && count < 16; ++count) { char *next = hat + strlen(hat) + 1; hats[count] = hat; + AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" + , __func__, current->pid, token, count, hat); hat = next; } - } - - AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n", - __func__, token, hat ? hat : NULL); + } else + AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", + __func__, current->pid, token, count, ""); return aa_change_hat(hats, count, token, test); } --- linux-3.13.0.orig/security/apparmor/policy_unpack.c +++ linux-3.13.0/security/apparmor/policy_unpack.c @@ -26,9 +26,13 @@ #include "include/context.h" #include "include/crypto.h" #include "include/match.h" +#include "include/path.h" #include "include/policy.h" #include "include/policy_unpack.h" +#define K_ABI_MASK 0x3ff +#define FORCE_COMPLAIN_FLAG 0x800 + /* * The AppArmor interface treats data as a type byte followed by the * actual data. The interface has the notion of a a named entry @@ -70,13 +74,13 @@ static void audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; - if (sa->aad->iface.target) { - struct aa_profile *name = sa->aad->iface.target; + if (aad(sa)->target) { + const struct aa_profile *name = aad(sa)->target; audit_log_format(ab, " name="); audit_log_untrustedstring(ab, name->base.hname); } - if (sa->aad->iface.pos) - audit_log_format(ab, " offset=%ld", sa->aad->iface.pos); + if (aad(sa)->iface.pos) + audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos); } /** @@ -92,20 +96,16 @@ static int audit_iface(struct aa_profile *new, const char *name, const char *info, struct aa_ext *e, int error) { - struct aa_profile *profile = __aa_current_profile(); - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; + struct aa_profile *profile = labels_profile(__aa_current_label()); + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, 0); if (e) - aad.iface.pos = e->pos - e->start; - aad.iface.target = new; - aad.name = name; - aad.info = info; - aad.error = error; + aad(&sa)->iface.pos = e->pos - e->start; + aad(&sa)->target = new; + aad(&sa)->name = name; + aad(&sa)->info = info; + aad(&sa)->error = error; - return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa, - audit_cb); + return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb); } /* test if read will be in packed data bounds */ @@ -193,6 +193,19 @@ return 0; } +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) +{ + if (unpack_nameX(e, AA_U16, name)) { + if (!inbounds(e, sizeof(u16))) + return 0; + if (data) + *data = le16_to_cpu(get_unaligned((u16 *) e->pos)); + e->pos += sizeof(u16); + return 1; + } + return 0; +} + static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) { if (unpack_nameX(e, AA_U32, name)) { @@ -476,6 +489,7 @@ { struct aa_profile *profile = NULL; const char *name = NULL; + size_t size = 0; int i, error = -EPROTO; kernel_cap_t tmpcap; u32 tmp; @@ -516,10 +530,10 @@ if (!unpack_u32(e, &tmp, NULL)) goto fail; if (tmp & PACKED_FLAG_HAT) - profile->flags |= PFLAG_HAT; + profile->label.flags |= FLAG_HAT; if (!unpack_u32(e, &tmp, NULL)) goto fail; - if (tmp == PACKED_MODE_COMPLAIN) + if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) profile->mode = APPARMOR_COMPLAIN; else if (tmp == PACKED_MODE_KILL) profile->mode = APPARMOR_KILL; @@ -534,11 +548,9 @@ goto fail; /* path_flags is optional */ - if (unpack_u32(e, &profile->path_flags, "path_flags")) - profile->path_flags |= profile->flags & PFLAG_MEDIATE_DELETED; - else + if (!unpack_u32(e, &profile->path_flags, "path_flags")) /* set a default value if path_flags field is not present */ - profile->path_flags = PFLAG_MEDIATE_DELETED; + profile->path_flags = PATH_MEDIATE_DELETED; if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL)) goto fail; @@ -576,6 +588,38 @@ if (!unpack_rlimits(e, profile)) goto fail; + size = unpack_array(e, "net_allowed_af"); + if (size) { + + for (i = 0; i < size; i++) { + /* discard extraneous rules that this kernel will + * never request + */ + if (i >= AF_MAX) { + u16 tmp; + if (!unpack_u16(e, &tmp, NULL) || + !unpack_u16(e, &tmp, NULL) || + !unpack_u16(e, &tmp, NULL)) + goto fail; + continue; + } + if (!unpack_u16(e, &profile->net.allow[i], NULL)) + goto fail; + if (!unpack_u16(e, &profile->net.audit[i], NULL)) + goto fail; + if (!unpack_u16(e, &profile->net.quiet[i], NULL)) + goto fail; + } + if (!unpack_nameX(e, AA_ARRAYEND, NULL)) + goto fail; + } + /* + * allow unix domain and netlink sockets they are handled + * by IPC + */ + profile->net.allow[AF_UNIX] = 0xffff; + profile->net.allow[AF_NETLINK] = 0xffff; + if (unpack_nameX(e, AA_STRUCT, "policydb")) { /* generic policy dfa - optional and may be NULL */ profile->policy.dfa = unpack_dfa(e); @@ -604,12 +648,16 @@ error = PTR_ERR(profile->file.dfa); profile->file.dfa = NULL; goto fail; + } else if (profile->file.dfa) { + if (!unpack_u32(e, &profile->file.start, "dfa_start")) + /* default start state */ + profile->file.start = DFA_START; + } else if (profile->policy.dfa && + profile->policy.start[AA_CLASS_FILE]) { + profile->file.dfa = aa_get_dfa(profile->policy.dfa); + profile->file.start = profile->policy.start[AA_CLASS_FILE]; } - if (!unpack_u32(e, &profile->file.start, "dfa_start")) - /* default start state */ - profile->file.start = DFA_START; - if (!unpack_trans_table(e, profile)) goto fail; @@ -650,15 +698,18 @@ error); return error; } - - /* check that the interface version is currently supported */ - if (e->version != 5) { - audit_iface(NULL, NULL, "unsupported interface version", - e, error); - return error; - } } + /* Check that the interface version is currently supported. + * if not specified use previous version + * Mask off everything that is not kernel abi version + */ + if ((e->version & K_ABI_MASK) < 5 && + (e->version & K_ABI_MASK) > 6) { + audit_iface(NULL, NULL, "unsupported interface version", + e, error); + return error; + } /* read the namespace if present */ if (unpack_str(e, &name, "namespace")) { --- linux-3.13.0.orig/security/apparmor/capability.c +++ linux-3.13.0/security/apparmor/capability.c @@ -53,6 +53,7 @@ /** * audit_caps - audit a capability + * @sa: audit data * @profile: profile being tested for confinement (NOT NULL) * @cap: capability tested * @error: error code returned by test @@ -62,17 +63,12 @@ * * Returns: 0 or sa->error on success, error code on failure */ -static int audit_caps(struct aa_profile *profile, int cap, int error) +static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, + int cap, int error) { struct audit_cache *ent; int type = AUDIT_APPARMOR_AUTO; - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_CAP; - sa.aad = &aad; - sa.u.cap = cap; - sa.aad->op = OP_CAPABLE; - sa.aad->error = error; + aad(sa)->error = error; if (likely(!error)) { /* test if auditing is being forced */ @@ -104,24 +100,40 @@ } put_cpu_var(audit_cache); - return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb); + return aa_audit(type, profile, sa, audit_cb); } /** * profile_capable - test if profile allows use of capability @cap * @profile: profile being enforced (NOT NULL, NOT unconfined) * @cap: capability to test if allowed + * @sa: audit data (MAY BE NULL indicating no auditing) * * Returns: 0 if allowed else -EPERM */ -static int profile_capable(struct aa_profile *profile, int cap) +static int profile_capable(struct aa_profile *profile, int cap, + struct common_audit_data *sa) { - return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM; + int error; + + if (cap_raised(profile->caps.allow, cap) && + !cap_raised(profile->caps.denied, cap)) + error = 0; + else + error = -EPERM; + + if (!sa) { + if (COMPLAIN_MODE(profile)) + return complain_error(error); + return error; + } + + return audit_caps(sa, profile, cap, error); } /** * aa_capable - test permission to use capability - * @profile: profile being tested against (NOT NULL) + * @label: label being tested for capability (NOT NULL) * @cap: capability to be tested * @audit: whether an audit record should be generated * @@ -129,15 +141,15 @@ * * Returns: 0 on success, or else an error code. */ -int aa_capable(struct aa_profile *profile, int cap, int audit) +int aa_capable(struct aa_label *label, int cap, int audit) { - int error = profile_capable(profile, cap); + struct aa_profile *profile; + int error = 0; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); + sa.u.cap = cap; - if (!audit) { - if (COMPLAIN_MODE(profile)) - return complain_error(error); - return error; - } + error = fn_for_each_confined(label, profile, + profile_capable(profile, cap, audit ? &sa : NULL)); - return audit_caps(profile, cap, error); + return error; } --- linux-3.13.0.orig/security/apparmor/ipc.c +++ linux-3.13.0/security/apparmor/ipc.c @@ -4,7 +4,7 @@ * This file contains AppArmor ipc mediation * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * Copyright 2009-2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,92 +20,215 @@ #include "include/context.h" #include "include/policy.h" #include "include/ipc.h" +#include "include/sig_names.h" + +/** + * audit_ptrace_mask - convert mask to permission string + * @buffer: buffer to write string to (NOT NULL) + * @mask: permission mask to convert + */ +static void audit_ptrace_mask(struct audit_buffer *ab, u32 mask) +{ + switch (mask) { + case MAY_READ: + audit_log_string(ab, "read"); + break; + case MAY_WRITE: + audit_log_string(ab, "trace"); + break; + case AA_MAY_BE_READ: + audit_log_string(ab, "readby"); + break; + case AA_MAY_BE_TRACED: + audit_log_string(ab, "tracedby"); + break; + } +} /* call back to audit ptrace fields */ -static void audit_cb(struct audit_buffer *ab, void *va) +static void audit_ptrace_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; - audit_log_format(ab, " target="); - audit_log_untrustedstring(ab, sa->aad->target); + + if (aad(sa)->request & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " requested_mask="); + audit_ptrace_mask(ab, aad(sa)->request); + + if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " denied_mask="); + audit_ptrace_mask(ab, aad(sa)->denied); + } + } + audit_log_format(ab, " peer="); + audit_log_untrustedstring(ab, aad(sa)->target); } -/** - * aa_audit_ptrace - do auditing for ptrace - * @profile: profile being enforced (NOT NULL) - * @target: profile being traced (NOT NULL) - * @error: error condition - * - * Returns: %0 or error code - */ -static int aa_audit_ptrace(struct aa_profile *profile, - struct aa_profile *target, int error) +/* TODO: conditionals */ +static int profile_ptrace_perm(struct aa_profile *profile, + struct aa_profile *peer, u32 request, + struct common_audit_data *sa) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = OP_PTRACE; - aad.target = target; - aad.error = error; + struct aa_perms perms; - return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa, - audit_cb); + /* need because of peer in cross check */ + if (profile_unconfined(profile) || + !PROFILE_MEDIATES(profile, AA_CLASS_PTRACE)) + return 0; + + aad(sa)->target = peer->base.hname; + aa_profile_match_label(profile, aa_peer_name(peer), AA_CLASS_PTRACE, + &perms); + aa_apply_modes_to_perms(profile, &perms); + return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); +} + +static int x_profile_ptrace_perm(struct aa_profile *profile, + struct aa_profile *peer, u32 request, + struct common_audit_data *sa) +{ + return profile_ptrace_perm(profile, peer, request << PTRACE_PERM_SHIFT, + sa); +} + +static int cross_ptrace_perm(struct aa_profile *tracer, + struct aa_profile *tracee, u32 request, + struct common_audit_data *sa) +{ + if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) + return xcheck_profiles(tracer, tracee, profile_ptrace_perm, + x_profile_ptrace_perm, request, sa); + + /* policy uses the old style capability check for ptrace */ + if (profile_unconfined(tracer) || tracer == tracee) + return 0; + + aad(sa)->label = &tracer->label; + aad(sa)->target = tracee->base.hname; + aad(sa)->request = 0; + aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); + return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); } /** * aa_may_ptrace - test if tracer task can trace the tracee - * @tracer: profile of the task doing the tracing (NOT NULL) - * @tracee: task to be traced - * @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH + * @tracer: label of the task doing the tracing (NOT NULL) + * @tracee: task label to be traced + * @request: permission request * * Returns: %0 else error code if permission denied or error */ -int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee, - unsigned int mode) +int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, + u32 request) { - /* TODO: currently only based on capability, not extended ptrace - * rules, - * Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH - */ + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); - if (unconfined(tracer) || tracer == tracee) - return 0; - /* log this capability request */ - return aa_capable(tracer, CAP_SYS_PTRACE, 1); + return xcheck_labels_profiles(tracer, tracee, cross_ptrace_perm, + request, &sa); +} + + +static inline int map_signal_num(int sig) +{ + if (sig > SIGRTMAX) + return SIGUNKNOWN; + else if (sig >= SIGRTMIN) + return sig - SIGRTMIN + 128; /* rt sigs mapped to 128 */ + else if (sig <= MAXMAPPED_SIG) + return sig_map[sig]; + return SIGUNKNOWN; } /** - * aa_ptrace - do ptrace permission check and auditing - * @tracer: task doing the tracing (NOT NULL) - * @tracee: task being traced (NOT NULL) - * @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH - * - * Returns: %0 else error code if permission denied or error + * audit_file_mask - convert mask to permission string + * @buffer: buffer to write string to (NOT NULL) + * @mask: permission mask to convert */ -int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, - unsigned int mode) +static void audit_signal_mask(struct audit_buffer *ab, u32 mask) { - /* - * tracer can ptrace tracee when - * - tracer is unconfined || - * - tracer is in complain mode - * - tracer has rules allowing it to trace tracee currently this is: - * - confined by the same profile || - * - tracer profile has CAP_SYS_PTRACE - */ - - struct aa_profile *tracer_p = aa_get_task_profile(tracer); - int error = 0; - - if (!unconfined(tracer_p)) { - struct aa_profile *tracee_p = aa_get_task_profile(tracee); + if (mask & MAY_READ) + audit_log_string(ab, "receive"); + if (mask & MAY_WRITE) + audit_log_string(ab, "send"); +} - error = aa_may_ptrace(tracer_p, tracee_p, mode); - error = aa_audit_ptrace(tracer_p, tracee_p, error); +/** + * audit_cb - call back for signal specific audit fields + * @ab: audit_buffer (NOT NULL) + * @va: audit struct to audit values of (NOT NULL) + */ +static void audit_signal_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; - aa_put_profile(tracee_p); + if (aad(sa)->request & AA_SIGNAL_PERM_MASK) { + audit_log_format(ab, " requested_mask="); + audit_signal_mask(ab, aad(sa)->request); + if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) { + audit_log_format(ab, " denied_mask="); + audit_signal_mask(ab, aad(sa)->denied); + } } - aa_put_profile(tracer_p); + if (aad(sa)->signal <= MAXMAPPED_SIG) + audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]); + else + audit_log_format(ab, " signal=rtmin+%d", + aad(sa)->signal - 128); + audit_log_format(ab, " peer="); + audit_log_untrustedstring(ab, aad(sa)->target); +} + +/* TODO: update to handle compound name&name2, conditionals */ +static void profile_match_signal(struct aa_profile *profile, const char *label, + int signal, struct aa_perms *perms) +{ + unsigned int state; + if (profile->policy.dfa) { + /* TODO: secondary cache check */ + state = aa_dfa_next(profile->policy.dfa, + profile->policy.start[AA_CLASS_SIGNAL], + signal); + state = aa_dfa_match(profile->policy.dfa, state, label); + aa_compute_perms(profile->policy.dfa, state, perms); + } else + memset(perms, 0, sizeof(*perms)); +} - return error; +static int profile_signal_perm(struct aa_profile *profile, + struct aa_profile *peer, u32 request, + struct common_audit_data *sa) +{ + struct aa_perms perms; + + if (profile_unconfined(profile) || + !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL)) + return 0; + + aad(sa)->target = peer->base.hname; + profile_match_signal(profile, aa_peer_name(peer), aad(sa)->signal, + &perms); + aa_apply_modes_to_perms(profile, &perms); + return aa_check_perms(profile, &perms, request, sa, audit_signal_cb); +} + +static int x_profile_signal_perm(struct aa_profile *profile, + struct aa_profile *peer, u32 request, + struct common_audit_data *sa) +{ + return profile_signal_perm(profile, peer, MAY_READ, sa); +} + +static int aa_signal_cross_perm(struct aa_profile *sender, + struct aa_profile *target, + struct common_audit_data *sa) +{ + return xcheck_profiles(sender, target, profile_signal_perm, + x_profile_signal_perm, MAY_WRITE, sa); +} + +int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig) +{ + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL); + aad(&sa)->signal = map_signal_num(sig); + return xcheck_labels_profiles(sender, target, aa_signal_cross_perm, + &sa); } --- linux-3.13.0.orig/security/apparmor/Makefile +++ linux-3.13.0/security/apparmor/Makefile @@ -4,11 +4,43 @@ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ - resource.o sid.o file.o + resource.o sid.o file.o label.o net.o mount.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o clean-files := capability_names.h rlim_names.h +# Build a lower case string table of address family names +# Transform lines from +# define AF_LOCAL 1 /* POSIX name for AF_UNIX */ +# #define AF_INET 2 /* Internet IP Protocol */ +# to +# [1] = "local", +# [2] = "inet", +# +# and build the securityfs entries for the mapping. +# Transforms lines from +# #define AF_INET 2 /* Internet IP Protocol */ +# to +# #define AA_FS_AF_MASK "local inet" +quiet_cmd_make-af = GEN $@ +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \ + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ + echo "};" >> $@ ;\ + echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\ + sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\ + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ + +# Build a lower case string table of sock type names +# Transform lines from +# SOCK_STREAM = 1, +# to +# [1] = "stream", +quiet_cmd_make-sock = GEN $@ +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ + sed $^ >>$@ -r -n \ + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ + echo "};" >> $@ # Build a lower case string table of capability names # Transforms lines from @@ -61,6 +93,7 @@ tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ $(obj)/capability.o : $(obj)/capability_names.h +$(obj)/net.o : $(obj)/net_names.h $(obj)/resource.o : $(obj)/rlim_names.h $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ $(src)/Makefile @@ -68,3 +101,8 @@ $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ $(src)/Makefile $(call cmd,make-rlim) +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \ + $(srctree)/include/linux/net.h \ + $(src)/Makefile + $(call cmd,make-af) + $(call cmd,make-sock) --- linux-3.13.0.orig/security/apparmor/mount.c +++ linux-3.13.0/security/apparmor/mount.c @@ -0,0 +1,686 @@ +/* + * AppArmor security module + * + * This file contains AppArmor mediation of files + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2012 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#include +#include +#include + +#include "include/apparmor.h" +#include "include/audit.h" +#include "include/context.h" +#include "include/domain.h" +#include "include/file.h" +#include "include/match.h" +#include "include/mount.h" +#include "include/path.h" +#include "include/policy.h" + + +static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags) +{ + if (flags & MS_RDONLY) + audit_log_format(ab, "ro"); + else + audit_log_format(ab, "rw"); + if (flags & MS_NOSUID) + audit_log_format(ab, ", nosuid"); + if (flags & MS_NODEV) + audit_log_format(ab, ", nodev"); + if (flags & MS_NOEXEC) + audit_log_format(ab, ", noexec"); + if (flags & MS_SYNCHRONOUS) + audit_log_format(ab, ", sync"); + if (flags & MS_REMOUNT) + audit_log_format(ab, ", remount"); + if (flags & MS_MANDLOCK) + audit_log_format(ab, ", mand"); + if (flags & MS_DIRSYNC) + audit_log_format(ab, ", dirsync"); + if (flags & MS_NOATIME) + audit_log_format(ab, ", noatime"); + if (flags & MS_NODIRATIME) + audit_log_format(ab, ", nodiratime"); + if (flags & MS_BIND) + audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind"); + if (flags & MS_MOVE) + audit_log_format(ab, ", move"); + if (flags & MS_SILENT) + audit_log_format(ab, ", silent"); + if (flags & MS_POSIXACL) + audit_log_format(ab, ", acl"); + if (flags & MS_UNBINDABLE) + audit_log_format(ab, flags & MS_REC ? ", runbindable" : + ", unbindable"); + if (flags & MS_PRIVATE) + audit_log_format(ab, flags & MS_REC ? ", rprivate" : + ", private"); + if (flags & MS_SLAVE) + audit_log_format(ab, flags & MS_REC ? ", rslave" : + ", slave"); + if (flags & MS_SHARED) + audit_log_format(ab, flags & MS_REC ? ", rshared" : + ", shared"); + if (flags & MS_RELATIME) + audit_log_format(ab, ", relatime"); + if (flags & MS_I_VERSION) + audit_log_format(ab, ", iversion"); + if (flags & MS_STRICTATIME) + audit_log_format(ab, ", strictatime"); + if (flags & MS_NOUSER) + audit_log_format(ab, ", nouser"); +} + +/** + * audit_cb - call back for mount specific audit fields + * @ab: audit_buffer (NOT NULL) + * @va: audit struct to audit values of (NOT NULL) + */ +static void audit_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + if (aad(sa)->mnt.type) { + audit_log_format(ab, " fstype="); + audit_log_untrustedstring(ab, aad(sa)->mnt.type); + } + if (aad(sa)->mnt.src_name) { + audit_log_format(ab, " srcname="); + audit_log_untrustedstring(ab, aad(sa)->mnt.src_name); + } + if (aad(sa)->mnt.trans) { + audit_log_format(ab, " trans="); + audit_log_untrustedstring(ab, aad(sa)->mnt.trans); + } + if (aad(sa)->mnt.flags || aad(sa)->op == OP_MOUNT) { + audit_log_format(ab, " flags=\""); + audit_mnt_flags(ab, aad(sa)->mnt.flags); + audit_log_format(ab, "\""); + } + if (aad(sa)->mnt.data) { + audit_log_format(ab, " options="); + audit_log_untrustedstring(ab, aad(sa)->mnt.data); + } +} + +/** + * audit_mount - handle the auditing of mount operations + * @profile: the profile being enforced (NOT NULL) + * @op: operation being mediated (NOT NULL) + * @name: name of object being mediated (MAYBE NULL) + * @src_name: src_name of object being mediated (MAYBE_NULL) + * @type: type of filesystem (MAYBE_NULL) + * @trans: name of trans (MAYBE NULL) + * @flags: filesystem idependent mount flags + * @data: filesystem mount flags + * @request: permissions requested + * @perms: the permissions computed for the request (NOT NULL) + * @info: extra information message (MAYBE NULL) + * @error: 0 if operation allowed else failure error code + * + * Returns: %0 or error on failure + */ +static int audit_mount(struct aa_profile *profile, int op, const char *name, + const char *src_name, const char *type, + const char *trans, unsigned long flags, + const void *data, u32 request, struct file_perms *perms, + const char *info, int error) +{ + int audit_type = AUDIT_APPARMOR_AUTO; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); + + if (likely(!error)) { + u32 mask = perms->audit; + + if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) + mask = 0xffff; + + /* mask off perms that are not being force audited */ + request &= mask; + + if (likely(!request)) + return 0; + audit_type = AUDIT_APPARMOR_AUDIT; + } else { + /* only report permissions that were denied */ + request = request & ~perms->allow; + + if (request & perms->kill) + audit_type = AUDIT_APPARMOR_KILL; + + /* quiet known rejects, assumes quiet and kill do not overlap */ + if ((request & perms->quiet) && + AUDIT_MODE(profile) != AUDIT_NOQUIET && + AUDIT_MODE(profile) != AUDIT_ALL) + request &= ~perms->quiet; + + if (!request) + return COMPLAIN_MODE(profile) ? + complain_error(error) : error; + } + + aad(&sa)->name = name; + aad(&sa)->mnt.src_name = src_name; + aad(&sa)->mnt.type = type; + aad(&sa)->mnt.trans = trans; + aad(&sa)->mnt.flags = flags; + if (data && (perms->audit & AA_AUDIT_DATA)) + aad(&sa)->mnt.data = data; + aad(&sa)->info = info; + aad(&sa)->error = error; + + return aa_audit(audit_type, profile, &sa, audit_cb); +} + +/** + * match_mnt_flags - Do an ordered match on mount flags + * @dfa: dfa to match against + * @state: state to start in + * @flags: mount flags to match against + * + * Mount flags are encoded as an ordered match. This is done instead of + * checking against a simple bitmask, to allow for logical operations + * on the flags. + * + * Returns: next state after flags match + */ +static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state, + unsigned long flags) +{ + unsigned int i; + + for (i = 0; i <= 31 ; ++i) { + if ((1 << i) & flags) + state = aa_dfa_next(dfa, state, i + 1); + } + + return state; +} + +/** + * compute_mnt_perms - compute mount permission associated with @state + * @dfa: dfa to match against (NOT NULL) + * @state: state match finished in + * + * Returns: mount permissions + */ +static struct file_perms compute_mnt_perms(struct aa_dfa *dfa, + unsigned int state) +{ + struct file_perms perms; + + perms.kill = 0; + perms.allow = dfa_user_allow(dfa, state); + perms.audit = dfa_user_audit(dfa, state); + perms.quiet = dfa_user_quiet(dfa, state); + perms.xindex = dfa_user_xindex(dfa, state); + + return perms; +} + +static const char *mnt_info_table[] = { + "match succeeded", + "failed mntpnt match", + "failed srcname match", + "failed type match", + "failed flags match", + "failed data match" +}; + +/* + * Returns 0 on success else element that match failed in, this is the + * index into the mnt_info_table above + */ +static int do_match_mnt(struct aa_dfa *dfa, unsigned int start, + const char *mntpnt, const char *devname, + const char *type, unsigned long flags, + void *data, bool binary, struct file_perms *perms) +{ + unsigned int state; + + state = aa_dfa_match(dfa, start, mntpnt); + state = aa_dfa_null_transition(dfa, state); + if (!state) + return 1; + + if (devname) + state = aa_dfa_match(dfa, state, devname); + state = aa_dfa_null_transition(dfa, state); + if (!state) + return 2; + + if (type) + state = aa_dfa_match(dfa, state, type); + state = aa_dfa_null_transition(dfa, state); + if (!state) + return 3; + + state = match_mnt_flags(dfa, state, flags); + if (!state) + return 4; + *perms = compute_mnt_perms(dfa, state); + if (perms->allow & AA_MAY_MOUNT) + return 0; + + /* only match data if not binary and the DFA flags data is expected */ + if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) { + state = aa_dfa_null_transition(dfa, state); + if (!state) + return 4; + + state = aa_dfa_match(dfa, state, data); + if (!state) + return 5; + *perms = compute_mnt_perms(dfa, state); + if (perms->allow & AA_MAY_MOUNT) + return 0; + } + + /* failed at end of flags match */ + return 4; +} + +/** + * match_mnt - handle path matching for mount + * @profile: the confining profile + * @mntpnt: string for the mntpnt (NOT NULL) + * @devname: string for the devname/src_name (MAYBE NULL) + * @type: string for the dev type (MAYBE NULL) + * @flags: mount flags to match + * @data: fs mount data (MAYBE NULL) + * @binary: whether @data is binary + * @perms: Returns: permission found by the match + * @info: Returns: infomation string about the match for logging + * + * Returns: 0 on success else error + */ +static int match_mnt(struct aa_profile *profile, const char *mntpnt, + const char *devname, const char *type, + unsigned long flags, void *data, bool binary) +{ + struct file_perms perms = { }; + const char *info = NULL; + int pos, error = -EACCES; + + if (!profile->policy.dfa) + goto audit; + + pos = do_match_mnt(profile->policy.dfa, + profile->policy.start[AA_CLASS_MOUNT], + mntpnt, devname, type, flags, data, binary, &perms); + if (pos) { + info = mnt_info_table[pos]; + goto audit; + } + error = 0; + +audit: + return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL, + flags, data, AA_MAY_MOUNT, &perms, info, error); +} + +static int path_flags(struct aa_profile *profile, struct path *path) +{ + return profile->path_flags | + S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0; +} + +int aa_remount(struct aa_label *label, struct path *path, unsigned long flags, + void *data) +{ + struct aa_profile *profile; + const char *name, *info = NULL; + char *buffer = NULL; + bool binary; + int error; + + binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA; + + get_buffers(buffer); + error = aa_path_name(path, path_flags(labels_profile(label), path), + buffer, &name, &info); + if (error) { + error = audit_mount(labels_profile(label), OP_MOUNT, name, NULL, + NULL, NULL, flags, data, AA_MAY_MOUNT, + &nullperms, info, error); + goto out; + } + + error = fn_for_each_confined(label, profile, + match_mnt(profile, name, NULL, NULL, flags, data, + binary)); + +out: + put_buffers(buffer); + + return error; +} + +int aa_bind_mount(struct aa_label *label, struct path *path, + const char *dev_name, unsigned long flags) +{ + struct aa_profile *profile; + char *buffer = NULL, *old_buffer = NULL; + const char *name, *old_name = NULL, *info = NULL; + struct path old_path; + int error; + + if (!dev_name || !*dev_name) + return -EINVAL; + + flags &= MS_REC | MS_BIND; + + get_buffers(buffer, old_buffer); + error = aa_path_name(path, path_flags(labels_profile(label), path), buffer, &name, + &info); + if (error) + goto error; + + error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); + if (error) + goto error; + + error = aa_path_name(&old_path, path_flags(labels_profile(label), + &old_path), + old_buffer, &old_name, &info); + path_put(&old_path); + if (error) + goto error; + + error = fn_for_each_confined(label, profile, + match_mnt(profile, name, old_name, NULL, flags, NULL, + false)); + +out: + put_buffers(buffer, old_buffer); + + return error; + +error: + error = fn_for_each(label, profile, + audit_mount(profile, OP_MOUNT, name, old_name, NULL, + NULL, flags, NULL, AA_MAY_MOUNT, &nullperms, + info, error)); + goto out; +} + +int aa_mount_change_type(struct aa_label *label, struct path *path, + unsigned long flags) +{ + struct aa_profile *profile; + char *buffer = NULL; + const char *name, *info = NULL; + int error; + + /* These are the flags allowed by do_change_type() */ + flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE | + MS_UNBINDABLE); + + get_buffers(buffer); + error = aa_path_name(path, path_flags(labels_profile(label), path), + buffer, &name, &info); + if (error) { + error = fn_for_each(label, profile, + audit_mount(profile, OP_MOUNT, name, NULL, + NULL, NULL, flags, NULL, + AA_MAY_MOUNT, &nullperms, info, + error)); + goto out; + } + + error = fn_for_each_confined(label, profile, + match_mnt(profile, name, NULL, NULL, flags, NULL, + false)); + +out: + put_buffers(buffer); + + return error; +} + +int aa_move_mount(struct aa_label *label, struct path *path, + const char *orig_name) +{ + struct aa_profile *profile; + char *buffer = NULL, *old_buffer = NULL; + const char *name, *old_name = NULL, *info = NULL; + struct path old_path; + int error; + + if (!orig_name || !*orig_name) + return -EINVAL; + + get_buffers(buffer, old_buffer); + error = aa_path_name(path, path_flags(labels_profile(label), path), + buffer, &name, &info); + if (error) + goto error; + + error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path); + if (error) + goto error; + + error = aa_path_name(&old_path, path_flags(labels_profile(label), + &old_path), + old_buffer, &old_name, &info); + path_put(&old_path); + if (error) + goto error; + + error = fn_for_each_confined(label, profile, + match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, + false)); + +out: + put_buffers(buffer, old_buffer); + + return error; + +error: + error = fn_for_each(label, profile, + audit_mount(profile, OP_MOUNT, name, old_name, NULL, + NULL, MS_MOVE, NULL, AA_MAY_MOUNT, + &nullperms, info, error)); + goto out; +} + +int aa_new_mount(struct aa_label *label, const char *orig_dev_name, + struct path *path, const char *type, unsigned long flags, + void *data) +{ + struct aa_profile *profile; + char *buffer = NULL, *dev_buffer = NULL; + const char *name = NULL, *dev_name = NULL, *info = NULL; + bool binary = true; + int error; + + dev_name = orig_dev_name; + get_buffers(buffer, dev_buffer); + if (type) { + int requires_dev; + struct file_system_type *fstype = get_fs_type(type); + if (!fstype) + return -ENODEV; + + binary = fstype->fs_flags & FS_BINARY_MOUNTDATA; + requires_dev = fstype->fs_flags & FS_REQUIRES_DEV; + put_filesystem(fstype); + + if (requires_dev) { + struct path dev_path; + + if (!dev_name || !*dev_name) { + error = -ENOENT; + goto out; + } + + error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path); + if (error) + goto error; + + error = aa_path_name(&dev_path, + path_flags(labels_profile(label), + &dev_path), + dev_buffer, &dev_name, &info); + path_put(&dev_path); + if (error) + goto error; + } + } + + error = aa_path_name(path, path_flags(labels_profile(label), path), + buffer, &name, &info); + if (error) + goto error; + + error = fn_for_each_confined(label, profile, + match_mnt(profile, name, dev_name, type, flags, data, + binary)); + +cleanup: + put_buffers(buffer, dev_buffer); + +out: + return error; + +error: + error = fn_for_each(label, profile, + audit_mount(labels_profile(label), OP_MOUNT, name, + dev_name, type, NULL, flags, data, + AA_MAY_MOUNT, &nullperms, info, error)); + goto cleanup; +} + +static int profile_umount(struct aa_profile *profile, const char *name) +{ + struct file_perms perms = { }; + const char *info = NULL; + int e = 0; + + if (profile->policy.dfa) { + unsigned int state; + state = aa_dfa_match(profile->policy.dfa, + profile->policy.start[AA_CLASS_MOUNT], + name); + perms = compute_mnt_perms(profile->policy.dfa, state); + if (AA_MAY_UMOUNT & ~perms.allow) + e = -EACCES; + } else + e = -EACCES; + return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL, + AA_MAY_UMOUNT, &perms, info, e); +} + +int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags) +{ + struct aa_profile *profile; + char *buffer = NULL; + const char *name, *info = NULL; + int error; + + struct path path = { mnt, mnt->mnt_root }; + get_buffers(buffer); + error = aa_path_name(&path, path_flags(labels_profile(label), &path), + buffer, &name, &info); + if (error) { + error = fn_for_each(label, profile, + audit_mount(profile, OP_UMOUNT, name, NULL, + NULL, NULL, 0, NULL, AA_MAY_UMOUNT, + &nullperms, info, error)); + goto out; + } + + error = fn_for_each_confined(label, profile, + profile_umount(profile, name)); + +out: + put_buffers(buffer); + + return error; +} + +static int profile_pivotroot(struct aa_profile *profile, const char *new_name, + const char *old_name, struct aa_profile *target) +{ + struct file_perms perms = { }; + const char *info = NULL; + int error = -EACCES; + + /* TODO: actual domain transition computation for multiple + * profiles + */ + if (profile->policy.dfa) { + unsigned int state; + state = aa_dfa_match(profile->policy.dfa, + profile->policy.start[AA_CLASS_MOUNT], + new_name); + state = aa_dfa_null_transition(profile->policy.dfa, state); + state = aa_dfa_match(profile->policy.dfa, state, old_name); + perms = compute_mnt_perms(profile->policy.dfa, state); + + if (AA_MAY_PIVOTROOT & perms.allow) { + if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) { + target = x_table_lookup(profile, perms.xindex); + if (!target) + error = -ENOENT; + else + error = aa_replace_current_label(&target->label); + } else + error = 0; + } + } + + return audit_mount(profile, OP_PIVOTROOT, new_name, old_name, + NULL, target ? target->base.name : NULL, + 0, NULL, AA_MAY_PIVOTROOT, &perms, info, + error); +} + +int aa_pivotroot(struct aa_label *label, struct path *old_path, + struct path *new_path) +{ + struct aa_profile *profile; + struct aa_profile *target = NULL; + char *old_buffer = NULL, *new_buffer = NULL; + const char *old_name, *new_name = NULL, *info = NULL; + int error; + + get_buffers(old_buffer, new_buffer); + error = aa_path_name(old_path, path_flags(labels_profile(label), + old_path), + old_buffer, &old_name, &info); + if (error) + goto error; + + error = aa_path_name(new_path, path_flags(labels_profile(label), + new_path), + new_buffer, &new_name, &info); + if (error) + goto error; + + error = fn_for_each(label, profile, + profile_pivotroot(profile, new_name, old_name, target)); +out: + aa_put_profile(target); + put_buffers(old_buffer, new_buffer); + + return error; + +error: + error = fn_for_each(label, profile, + audit_mount(profile, OP_PIVOTROOT, new_name, old_name, + NULL, target ? target->base.name : NULL, + 0, NULL, AA_MAY_PIVOTROOT, &nullperms, info, + error)); + goto out; +} --- linux-3.13.0.orig/security/apparmor/policy.c +++ linux-3.13.0/security/apparmor/policy.c @@ -82,6 +82,7 @@ #include "include/context.h" #include "include/file.h" #include "include/ipc.h" +#include "include/label.h" #include "include/match.h" #include "include/path.h" #include "include/policy.h" @@ -92,6 +93,9 @@ /* root profile namespace */ struct aa_namespace *root_ns; +/* Note: mode names must be unique in the first character because of + * modechrs used to print modes on compound labels on some interfaces + */ const char *const aa_profile_mode_names[] = { "enforce", "complain", @@ -128,16 +132,22 @@ static bool policy_init(struct aa_policy *policy, const char *prefix, const char *name) { + char *hname; + /* freed by policy_free */ if (prefix) { - policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, - GFP_KERNEL); - if (policy->hname) - sprintf(policy->hname, "%s//%s", prefix, name); - } else - policy->hname = kstrdup(name, GFP_KERNEL); - if (!policy->hname) + hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, + GFP_KERNEL); + if (hname) + sprintf(hname, "%s//%s", prefix, name); + } else { + hname = aa_str_alloc(strlen(name) + 1, GFP_KERNEL); + if (hname) + strcpy(hname, name); + } + if (!hname) return 0; + policy->hname = hname; /* base.name is a substring of fqname */ policy->name = (char *)hname_tail(policy->hname); INIT_LIST_HEAD(&policy->list); @@ -166,7 +176,7 @@ } /* don't free name as its a subset of hname */ - kzfree(policy->hname); + aa_put_str(policy->hname); } /** @@ -219,7 +229,7 @@ * Routines for AppArmor namespaces */ -static const char *hidden_ns_name = "---"; +const char *aa_hidden_ns_name = "---"; /** * aa_ns_visible - test if @view is visible from @curr * @curr: namespace to treat as the parent (NOT NULL) @@ -261,7 +271,7 @@ */ return view->base.hname + strlen(curr->base.hname) + 2; } else - return hidden_ns_name; + return aa_hidden_ns_name; } /** @@ -290,9 +300,12 @@ ns->unconfined = aa_alloc_profile("unconfined"); if (!ns->unconfined) goto fail_unconfined; + ns->unconfined->label.replacedby = aa_alloc_replacedby(NULL); + if (!ns->unconfined->label.replacedby) + goto fail_replacedby; - ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | - PFLAG_IMMUTABLE | PFLAG_NS_COUNT; + ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR | + FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; ns->unconfined->mode = APPARMOR_UNCONFINED; /* ns and ns->unconfined share ns->unconfined refcount */ @@ -300,8 +313,13 @@ atomic_set(&ns->uniq_null, 0); + aa_labelset_init(&ns->labels); + return ns; +fail_replacedby: + aa_free_profile(ns->unconfined); + fail_unconfined: kzfree(ns->base.hname); fail_ns: @@ -310,18 +328,19 @@ } /** - * free_namespace - free a profile namespace + * aa_free_namespace - free a profile namespace * @ns: the namespace to free (MAYBE NULL) * * Requires: All references to the namespace must have been put, if the * namespace was referenced by a profile confining a task, */ -static void free_namespace(struct aa_namespace *ns) +void aa_free_namespace(struct aa_namespace *ns) { if (!ns) return; policy_destroy(&ns->base); + aa_labelset_destroy(&ns->labels); aa_put_namespace(ns->parent); ns->unconfined->ns = NULL; @@ -376,7 +395,7 @@ { struct aa_namespace *ns, *root; - root = aa_current_profile()->ns; + root = labels_ns(aa_current_label()); mutex_lock(&root->lock); @@ -397,11 +416,12 @@ if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { AA_ERROR("Failed to create interface for ns %s\n", ns->base.name); - free_namespace(ns); + aa_free_namespace(ns); ns = NULL; goto out; } ns->parent = aa_get_namespace(root); + ns->level = root->level + 1; list_add_rcu(&ns->base.list, &root->sub_ns); /* add list ref */ aa_get_namespace(ns); @@ -414,7 +434,7 @@ } /** - * __list_add_profile - add a profile to a list + * __add_profile - add a profiles to list and label tree * @list: list to add it to (NOT NULL) * @profile: the profile to add (NOT NULL) * @@ -422,12 +442,21 @@ * * Requires: namespace lock be held, or list not be shared */ -static void __list_add_profile(struct list_head *list, - struct aa_profile *profile) +static void __add_profile(struct list_head *list, struct aa_profile *profile) { + struct aa_label *l; + + AA_BUG(!list); + AA_BUG(!profile); + AA_BUG(!profile->ns); + AA_BUG(!mutex_is_locked(&profile->ns->lock)); + list_add_rcu(&profile->base.list, list); /* get list reference */ aa_get_profile(profile); + l = aa_label_insert(&profile->ns->labels, &profile->label); + AA_BUG(l != &profile->label); + aa_put_label(l); } /** @@ -444,6 +473,10 @@ */ static void __list_remove_profile(struct aa_profile *profile) { + AA_BUG(!profile); + AA_BUG(!profile->ns); + AA_BUG(!mutex_is_locked(&profile->ns->lock)); + list_del_rcu(&profile->base.list); aa_put_profile(profile); } @@ -458,10 +491,16 @@ */ static void __remove_profile(struct aa_profile *profile) { + AA_BUG(!profile); + AA_BUG(!profile->ns); + AA_BUG(!mutex_is_locked(&profile->ns->lock)); + /* release any children lists first */ __profile_list_release(&profile->base.profiles); /* released by free_profile */ - __aa_update_replacedby(profile, profile->ns->unconfined); + aa_label_remove(&profile->ns->labels, &profile->label); + __aa_update_replacedby(&profile->label, + &profile->ns->unconfined->label); __aa_fs_profile_rmdir(profile); __list_remove_profile(profile); } @@ -498,7 +537,8 @@ __ns_list_release(&ns->sub_ns); if (ns->parent) - __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); + __aa_update_replacedby(&ns->unconfined->label, + &ns->parent->unconfined->label); __aa_fs_namespace_rmdir(ns); mutex_unlock(&ns->lock); } @@ -560,23 +600,6 @@ } -static void free_replacedby(struct aa_replacedby *r) -{ - if (r) { - /* r->profile will not be updated any more as r is dead */ - aa_put_profile(rcu_dereference_protected(r->profile, true)); - kzfree(r); - } -} - - -void aa_free_replacedby_kref(struct kref *kref) -{ - struct aa_replacedby *r = container_of(kref, struct aa_replacedby, - count); - free_replacedby(r); -} - /** * aa_free_profile - free a profile * @profile: the profile to free (MAYBE NULL) @@ -603,41 +626,18 @@ aa_free_file_rules(&profile->file); aa_free_cap_rules(&profile->caps); + aa_free_net_rules(&profile->net); aa_free_rlimit_rules(&profile->rlimits); kzfree(profile->dirname); aa_put_dfa(profile->xmatch); aa_put_dfa(profile->policy.dfa); - aa_put_replacedby(profile->replacedby); kzfree(profile->hash); kzfree(profile); } /** - * aa_free_profile_rcu - free aa_profile by rcu (called by aa_free_profile_kref) - * @head: rcu_head callback for freeing of a profile (NOT NULL) - */ -static void aa_free_profile_rcu(struct rcu_head *head) -{ - struct aa_profile *p = container_of(head, struct aa_profile, rcu); - if (p->flags & PFLAG_NS_COUNT) - free_namespace(p->ns); - else - aa_free_profile(p); -} - -/** - * aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile) - * @kr: kref callback for freeing of a profile (NOT NULL) - */ -void aa_free_profile_kref(struct kref *kref) -{ - struct aa_profile *p = container_of(kref, struct aa_profile, count); - call_rcu(&p->rcu, aa_free_profile_rcu); -} - -/** * aa_alloc_profile - allocate, initialize and return a new profile * @hname: name of the profile (NOT NULL) * @@ -652,20 +652,18 @@ if (!profile) return NULL; - profile->replacedby = kzalloc(sizeof(struct aa_replacedby), GFP_KERNEL); - if (!profile->replacedby) - goto fail; - kref_init(&profile->replacedby->count); - if (!policy_init(&profile->base, NULL, hname)) goto fail; - kref_init(&profile->count); + if (!aa_label_init(&profile->label, 1)) + goto fail; + profile->label.hname = profile->base.hname; + profile->label.flags |= FLAG_PROFILE; + profile->label.ent[0] = profile; /* refcount released by caller */ return profile; fail: - kzfree(profile->replacedby); kzfree(profile); return NULL; @@ -702,26 +700,57 @@ if (!profile) goto fail; + profile->label.replacedby = aa_alloc_replacedby(NULL); + if (!profile->label.replacedby) + goto fail; + profile->mode = APPARMOR_COMPLAIN; - profile->flags = PFLAG_NULL; + profile->label.flags |= FLAG_NULL; if (hat) - profile->flags |= PFLAG_HAT; + profile->label.flags |= FLAG_HAT; /* released on free_profile */ rcu_assign_pointer(profile->parent, aa_get_profile(parent)); profile->ns = aa_get_namespace(parent->ns); mutex_lock(&profile->ns->lock); - __list_add_profile(&parent->base.profiles, profile); + __add_profile(&parent->base.profiles, profile); mutex_unlock(&profile->ns->lock); /* refcount released by caller */ return profile; fail: + aa_free_profile(profile); return NULL; } +/** + * aa_setup_default_label - create the initial default label + */ +struct aa_label *aa_setup_default_label(void) +{ + struct aa_profile *profile = aa_alloc_profile("default"); + if (!profile) + return NULL; + + /* the default profile pretends to be unconfined until it is replaced */ + profile->label.flags |= FLAG_IX_ON_NAME_ERROR | FLAG_UNCONFINED; + profile->mode = APPARMOR_UNCONFINED; + + profile->ns = aa_get_namespace(root_ns); + + /* replacedby being set needed by fs interface */ + profile->label.replacedby = aa_alloc_replacedby(&profile->label); + if (!profile->label.replacedby) { + aa_free_profile(profile); + return NULL; + } + __add_profile(&root_ns->base.profiles, profile); + + return &profile->label; +} + /* TODO: profile accounting - setup in remove */ /** @@ -810,9 +839,10 @@ } /** - * __lookup_profile - lookup the profile matching @hname + * __lookupn_profile - lookup the profile matching @hname * @base: base list to start looking up profile name from (NOT NULL) * @hname: hierarchical profile name (NOT NULL) + * @n: length of @hname * * Requires: rcu_read_lock be held * @@ -820,53 +850,87 @@ * * Do a relative name lookup, recursing through profile tree. */ -static struct aa_profile *__lookup_profile(struct aa_policy *base, - const char *hname) +static struct aa_profile *__lookupn_profile(struct aa_policy *base, + const char *hname, size_t n) { struct aa_profile *profile = NULL; - char *split; + const char *split, *name = hname; - for (split = strstr(hname, "//"); split;) { - profile = __strn_find_child(&base->profiles, hname, - split - hname); + for (split = strstr(hname, "//"); split && (split - hname <= n);) { + profile = __strn_find_child(&base->profiles, name, + split - name); if (!profile) return NULL; base = &profile->base; - hname = split + 2; - split = strstr(hname, "//"); + name = split + 2; + split = strstr(name, "//"); } - profile = __find_child(&base->profiles, hname); + if (name - hname <= n) + return __strn_find_child(&base->profiles, name, + n - (name - hname)); + return NULL; +} - return profile; +static struct aa_profile *__lookup_profile(struct aa_policy *base, + const char *hname) +{ + return __lookupn_profile(base, hname, strlen(hname)); } /** * aa_lookup_profile - find a profile by its full or partial name * @ns: the namespace to start from (NOT NULL) * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL) + * @n: size of @hname * * Returns: refcounted profile or NULL if not found */ -struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname) +struct aa_profile *aa_lookupn_profile(struct aa_namespace *ns, + const char *hname, size_t n) { struct aa_profile *profile; rcu_read_lock(); do { - profile = __lookup_profile(&ns->base, hname); + profile = __lookupn_profile(&ns->base, hname, n); } while (profile && !aa_get_profile_not0(profile)); rcu_read_unlock(); /* the unconfined profile is not in the regular profile list */ - if (!profile && strcmp(hname, "unconfined") == 0) + if (!profile && strncmp(hname, "unconfined", n) == 0) profile = aa_get_newest_profile(ns->unconfined); /* refcount released by caller */ return profile; } +struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname) +{ + return aa_lookupn_profile(ns, hname, strlen(hname)); +} + +struct aa_profile *aa_fqlookupn_profile(struct aa_namespace *base, char *fqname, + int n) +{ + struct aa_profile *profile; + struct aa_namespace *ns; + char *name, *ns_name; + + name = aa_split_fqname(fqname, &ns_name); + if (ns_name) { + ns = aa_find_namespace(base, ns_name); + if (!ns) + return NULL; + } else + ns = aa_get_namespace(base); + profile = aa_lookupn_profile(ns, name, n - (name - fqname)); + aa_put_namespace(ns); + + return profile; +} + /** * replacement_allowed - test to see if replacement is allowed * @profile: profile to test if it can be replaced (MAYBE NULL) @@ -879,7 +943,7 @@ const char **info) { if (profile) { - if (profile->flags & PFLAG_IMMUTABLE) { + if (profile->label.flags & FLAG_IMMUTIBLE) { *info = "cannot replace immutible profile"; return -EPERM; } else if (noreplace) { @@ -893,27 +957,23 @@ /** * aa_audit_policy - Do auditing of policy changes * @op: policy operation being performed - * @gfp: memory allocation flags * @name: name of profile being manipulated (NOT NULL) * @info: any extra information to be audited (MAYBE NULL) * @error: error code * * Returns: the error to be returned after audit is done */ -static int audit_policy(int op, gfp_t gfp, const char *name, const char *info, +static int audit_policy(int op, const char *name, const char *info, int error) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = op; - aad.name = name; - aad.info = info; - aad.error = error; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); + // aad(&sa)->op = op; + aad(&sa)->name = name; + aad(&sa)->info = info; + aad(&sa)->error = error; - return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp, - &sa, NULL); + return aa_audit(AUDIT_APPARMOR_STATUS, + labels_profile(__aa_current_label()), &sa, NULL); } /** @@ -926,12 +986,12 @@ { /* check if loading policy is locked out */ if (aa_g_lock_policy) { - audit_policy(op, GFP_KERNEL, NULL, "policy_locked", -EACCES); + audit_policy(op, NULL, "policy_locked", -EACCES); return 0; } if (!capable(CAP_MAC_ADMIN)) { - audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES); + audit_policy(op, NULL, "not policy admin", -EACCES); return 0; } @@ -1008,14 +1068,13 @@ struct aa_profile *parent = aa_deref_parent(old); rcu_assign_pointer(new->parent, aa_get_profile(parent)); } - __aa_update_replacedby(old, new); - if (share_replacedby) { - aa_put_replacedby(new->replacedby); - new->replacedby = aa_get_replacedby(old->replacedby); - } else if (!rcu_access_pointer(new->replacedby->profile)) + __aa_update_replacedby(&old->label, &new->label); + if (share_replacedby) + new->label.replacedby = aa_get_replacedby(old->label.replacedby); + else if (!rcu_access_pointer(new->label.replacedby->label)) /* aafs interface uses replacedby */ - rcu_assign_pointer(new->replacedby->profile, - aa_get_profile(new)); + rcu_assign_pointer(new->label.replacedby->label, + aa_get_label(&new->label)); __aa_fs_profile_migrate_dents(old, new); if (list_empty(&new->base.list)) { @@ -1053,6 +1112,35 @@ return 0; } +static void share_name(struct aa_profile *old, struct aa_profile *new) +{ + aa_put_str(new->base.hname); + aa_get_str(old->base.hname); + new->base.hname = old->base.hname; + new->base.name = old->base.name; + new->label.hname = old->label.hname; +} + +/* Update to newest version of parent after previous replacements + * Returns: unrefcount newest version of parent + */ +static struct aa_profile *update_to_newest_parent(struct aa_profile *new) +{ + struct aa_profile *parent, *newest; + parent = rcu_dereference_protected(new->parent, + mutex_is_locked(&new->ns->lock)); + newest = aa_get_newest_profile(parent); + + /* parent replaced in this atomic set? */ + if (newest != parent) { + aa_put_profile(parent); + rcu_assign_pointer(new->parent, newest); + } else + aa_put_profile(newest); + + return newest; +} + /** * aa_replace_profiles - replace profile(s) on the profile list * @udata: serialized data stream (NOT NULL) @@ -1134,6 +1222,7 @@ /* create new fs entries for introspection if needed */ list_for_each_entry(ent, &lh, list) { + struct aa_replacedby *r; if (ent->old) { /* inherit old interface files */ @@ -1143,6 +1232,14 @@ TODO: support rename */ } else { struct dentry *parent; + r = aa_alloc_replacedby(NULL); + if (!r) { + info = "failed to create"; + error = -ENOMEM; + goto fail_lock; + } + ent->new->label.replacedby = r; + if (rcu_access_pointer(ent->new->parent)) { struct aa_profile *p; p = aa_deref_parent(ent->new); @@ -1153,7 +1250,7 @@ } if (error) { - info = "failed to create "; + info = "failed to create"; goto fail_lock; } } @@ -1163,46 +1260,40 @@ list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(op, GFP_ATOMIC, ent->new->base.name, NULL, error); + audit_policy(op, ent->new->base.name, NULL, error); if (ent->old) { + share_name(ent->old, ent->new); __replace_profile(ent->old, ent->new, 1); + aa_label_replace(&ns->labels, &ent->old->label, + &ent->new->label); if (ent->rename) { /* aafs interface uses replacedby */ - struct aa_replacedby *r = ent->new->replacedby; - rcu_assign_pointer(r->profile, - aa_get_profile(ent->new)); + rcu_assign_pointer(ent->new->label.replacedby->label, + aa_get_label(&ent->new->label)); __replace_profile(ent->rename, ent->new, 0); } } else if (ent->rename) { /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, - aa_get_profile(ent->new)); - __replace_profile(ent->rename, ent->new, 0); - } else if (ent->new->parent) { - struct aa_profile *parent, *newest; - parent = aa_deref_parent(ent->new); - newest = aa_get_newest_profile(parent); - - /* parent replaced in this atomic set? */ - if (newest != parent) { - aa_get_profile(newest); - aa_put_profile(parent); - rcu_assign_pointer(ent->new->parent, newest); - } else - aa_put_profile(newest); - /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, - aa_get_profile(ent->new)); - __list_add_profile(&parent->base.profiles, ent->new); + rcu_assign_pointer(ent->new->label.replacedby->label, + aa_get_label(&ent->new->label)); } else { + struct list_head *lh; + if (rcu_access_pointer(ent->new->parent)) { + struct aa_profile *parent; + parent = update_to_newest_parent(ent->new); + lh = &parent->base.profiles; + } else + lh = &ns->base.profiles; + /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, - aa_get_profile(ent->new)); - __list_add_profile(&ns->base.profiles, ent->new); + rcu_assign_pointer(ent->new->label.replacedby->label, + aa_get_label(&ent->new->label)); + __add_profile(lh, ent->new); } aa_load_ent_free(ent); } + __aa_labelset_update_all(ns); mutex_unlock(&ns->lock); out: @@ -1215,7 +1306,7 @@ fail_lock: mutex_unlock(&ns->lock); fail: - error = audit_policy(op, GFP_KERNEL, name, info, error); + error = audit_policy(op, name, info, error); list_for_each_entry_safe(ent, tmp, &lh, list) { list_del_init(&ent->list); @@ -1250,7 +1341,7 @@ goto fail; } - root = aa_current_profile()->ns; + root = labels_ns(aa_current_label()); if (fqname[0] == ':') { char *ns_name; @@ -1282,11 +1373,12 @@ } name = profile->base.hname; __remove_profile(profile); + __aa_labelset_update_all(ns); mutex_unlock(&ns->lock); } /* don't fail removal if audit fails */ - (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); + (void) audit_policy(OP_PROF_RM, name, info, error); aa_put_namespace(ns); aa_put_profile(profile); return size; @@ -1296,6 +1388,6 @@ aa_put_namespace(ns); fail: - (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); + (void) audit_policy(OP_PROF_RM, name, info, error); return error; } --- linux-3.13.0.orig/security/apparmor/Kconfig +++ linux-3.13.0/security/apparmor/Kconfig @@ -30,6 +30,41 @@ If you are unsure how to answer this question, answer 1. +config SECURITY_APPARMOR_STATS + bool "enable debug statistics" + depends on SECURITY_APPARMOR + select APPARMOR_LABEL_STATS + default n + help + This enables keeping statistics on various internal structures + and functions in apparmor. + + If you are unsure how to answer this question, answer N. + +config SECURITY_APPARMOR_UNCONFINED_INIT + bool "Set init to unconfined on boot" + depends on SECURITY_APPARMOR + default y + help + This option determines policy behavior during early boot by + placing the init process in the unconfined state, or the + 'default' profile. + + This option determines policy behavior during early boot by + placing the init process in the unconfined state, or the + 'default' profile. + + 'Y' means init and its children are not confined, unless the + init process is re-execed after a policy load; loaded policy + will only apply to processes started after the load. + + 'N' means init and its children are confined in a profile + named 'default', which can be replaced later and thus + provide for confinement for processes started early at boot, + though not confined during early boot. + + If you are unsure how to answer this question, answer Y. + config SECURITY_APPARMOR_HASH bool "SHA1 hash of loaded profiles" depends on SECURITY_APPARMOR --- linux-3.13.0.orig/security/apparmor/resource.c +++ linux-3.13.0/security/apparmor/resource.c @@ -35,7 +35,7 @@ struct common_audit_data *sa = va; audit_log_format(ab, " rlimit=%s value=%lu", - rlim_names[sa->aad->rlim.rlim], sa->aad->rlim.max); + rlim_names[aad(sa)->rlim.rlim], aad(sa)->rlim.max); } /** @@ -50,17 +50,11 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource, unsigned long value, int error) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = OP_SETRLIMIT, - aad.rlim.rlim = resource; - aad.rlim.max = value; - aad.error = error; - return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa, - audit_cb); + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETRLIMIT); + aad(&sa)->rlim.rlim = resource; + aad(&sa)->rlim.max = value; + aad(&sa)->error = error; + return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb); } /** @@ -77,9 +71,19 @@ return rlim_map[resource]; } +static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, + struct rlimit *new_rlim) +{ + int e = 0; + if (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > + profile->rlimits.limits[resource].rlim_max) + e = -EACCES; + return audit_resource(profile, resource, new_rlim->rlim_max, e); +} + /** * aa_task_setrlimit - test permission to set an rlimit - * @profile - profile confining the task (NOT NULL) + * @label - label confining the task (NOT NULL) * @task - task the resource is being set on * @resource - the resource being set * @new_rlim - the new resource limit (NOT NULL) @@ -88,14 +92,15 @@ * * Returns: 0 or error code if setting resource failed */ -int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, +int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, unsigned int resource, struct rlimit *new_rlim) { - struct aa_profile *task_profile; + struct aa_profile *profile; + struct aa_label *task_label; int error = 0; rcu_read_lock(); - task_profile = aa_get_profile(aa_cred_profile(__task_cred(task))); + task_label = aa_get_newest_cred_label(__task_cred(task)); rcu_read_unlock(); /* TODO: extend resource control to handle other (non current) @@ -103,52 +108,65 @@ * that the task is setting the resource of a task confined with * the same profile. */ - if (profile != task_profile || - (profile->rlimits.mask & (1 << resource) && - new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) - error = -EACCES; + if (label != task_label) + error = fn_for_each(label, profile, + audit_resource(profile, resource, + new_rlim->rlim_max, EACCES)); + else + error = fn_for_each_confined(label, profile, + profile_setrlimit(profile, resource, new_rlim)); + aa_put_label(task_label); - aa_put_profile(task_profile); - - return audit_resource(profile, resource, new_rlim->rlim_max, error); + return error; } /** * __aa_transition_rlimits - apply new profile rlimits - * @old: old profile on task (NOT NULL) - * @new: new profile with rlimits to apply (NOT NULL) + * @old_l: old label on task (NOT NULL) + * @new_l: new label with rlimits to apply (NOT NULL) */ -void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new) +void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l) { unsigned int mask = 0; struct rlimit *rlim, *initrlim; - int i; + struct aa_profile *old, *new; + struct label_it i; + + old = labels_profile(old_l); + new = labels_profile(new_l); - /* for any rlimits the profile controlled reset the soft limit - * to the less of the tasks hard limit and the init tasks soft limit + /* for any rlimits the profile controlled, reset the soft limit + * to the lesser of the tasks hard limit and the init tasks soft limit */ - if (old->rlimits.mask) { - for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) { - if (old->rlimits.mask & mask) { - rlim = current->signal->rlim + i; - initrlim = init_task.signal->rlim + i; - rlim->rlim_cur = min(rlim->rlim_max, - initrlim->rlim_cur); + label_for_each_confined(i, old_l, old) { + if (old->rlimits.mask) { + int j; + for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, + mask <<= 1) { + if (old->rlimits.mask & mask) { + rlim = current->signal->rlim + j; + initrlim = init_task.signal->rlim + j; + rlim->rlim_cur = min(rlim->rlim_max, + initrlim->rlim_cur); + } } } } /* set any new hard limits as dictated by the new profile */ - if (!new->rlimits.mask) - return; - for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) { - if (!(new->rlimits.mask & mask)) + label_for_each_confined(i, new_l, new) { + int j; + if (!new->rlimits.mask) continue; - - rlim = current->signal->rlim + i; - rlim->rlim_max = min(rlim->rlim_max, - new->rlimits.limits[i].rlim_max); - /* soft limit should not exceed hard limit */ - rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max); + for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) { + if (!(new->rlimits.mask & mask)) + continue; + + rlim = current->signal->rlim + j; + rlim->rlim_max = min(rlim->rlim_max, + new->rlimits.limits[j].rlim_max); + /* soft limit should not exceed hard limit */ + rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max); + } } } --- linux-3.13.0.orig/security/apparmor/file.c +++ linux-3.13.0/security/apparmor/file.c @@ -12,8 +12,13 @@ * License. */ +#include +#include +#include + #include "include/apparmor.h" #include "include/audit.h" +#include "include/context.h" #include "include/file.h" #include "include/match.h" #include "include/path.h" @@ -21,6 +26,16 @@ struct file_perms nullperms; +static u32 map_mask_to_chr_mask(u32 mask) +{ + u32 m = mask & AA_PERM_CHR_MASK; + if (mask & AA_MAY_META_READ) + m |= MAY_READ; + if (mask & (AA_MAY_META_WRITE | AA_MAY_CHMOD | AA_MAY_CHOWN)) + m |= MAY_WRITE; + + return m; +} /** * audit_file_mask - convert mask to permission string @@ -31,29 +46,7 @@ { char str[10]; - char *m = str; - - if (mask & AA_EXEC_MMAP) - *m++ = 'm'; - if (mask & (MAY_READ | AA_MAY_META_READ)) - *m++ = 'r'; - if (mask & (MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CHMOD | - AA_MAY_CHOWN)) - *m++ = 'w'; - else if (mask & MAY_APPEND) - *m++ = 'a'; - if (mask & AA_MAY_CREATE) - *m++ = 'c'; - if (mask & AA_MAY_DELETE) - *m++ = 'd'; - if (mask & AA_MAY_LINK) - *m++ = 'l'; - if (mask & AA_MAY_LOCK) - *m++ = 'k'; - if (mask & MAY_EXEC) - *m++ = 'x'; - *m = '\0'; - + aa_perm_mask_to_chr(map_mask_to_chr_mask(mask), str); audit_log_string(ab, str); } @@ -67,24 +60,24 @@ struct common_audit_data *sa = va; kuid_t fsuid = current_fsuid(); - if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) { + if (aad(sa)->request & AA_AUDIT_FILE_MASK) { audit_log_format(ab, " requested_mask="); - audit_file_mask(ab, sa->aad->fs.request); + audit_file_mask(ab, aad(sa)->request); } - if (sa->aad->fs.denied & AA_AUDIT_FILE_MASK) { + if (aad(sa)->denied & AA_AUDIT_FILE_MASK) { audit_log_format(ab, " denied_mask="); - audit_file_mask(ab, sa->aad->fs.denied); + audit_file_mask(ab, aad(sa)->denied); } - if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) { + if (aad(sa)->request & AA_AUDIT_FILE_MASK) { audit_log_format(ab, " fsuid=%d", from_kuid(&init_user_ns, fsuid)); audit_log_format(ab, " ouid=%d", - from_kuid(&init_user_ns, sa->aad->fs.ouid)); + from_kuid(&init_user_ns, aad(sa)->fs.ouid)); } - if (sa->aad->fs.target) { + if (aad(sa)->target) { audit_log_format(ab, " target="); - audit_log_untrustedstring(ab, sa->aad->fs.target); + audit_log_untrustedstring(ab, aad(sa)->target); } } @@ -92,7 +85,6 @@ * aa_audit_file - handle the auditing of file operations * @profile: the profile being enforced (NOT NULL) * @perms: the permissions computed for the request (NOT NULL) - * @gfp: allocation flags * @op: operation being mediated * @request: permissions requested * @name: name of object being mediated (MAYBE NULL) @@ -104,53 +96,84 @@ * Returns: %0 or error on failure */ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, int op, u32 request, const char *name, - const char *target, kuid_t ouid, const char *info, int error) + int op, u32 request, const char *name, const char *target, + kuid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = op, - aad.fs.request = request; - aad.name = name; - aad.fs.target = target; - aad.fs.ouid = ouid; - aad.info = info; - aad.error = error; - if (likely(!sa.aad->error)) { + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); + aad(&sa)->request = request; + aad(&sa)->name = name; + aad(&sa)->target = target; + aad(&sa)->fs.ouid = ouid; + aad(&sa)->info = info; + aad(&sa)->error = error; + sa.u.tsk = NULL; + + if (likely(!aad(&sa)->error)) { u32 mask = perms->audit; if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) mask = 0xffff; /* mask off perms that are not being force audited */ - sa.aad->fs.request &= mask; + aad(&sa)->request &= mask; - if (likely(!sa.aad->fs.request)) + if (likely(!aad(&sa)->request)) return 0; type = AUDIT_APPARMOR_AUDIT; } else { /* only report permissions that were denied */ - sa.aad->fs.request = sa.aad->fs.request & ~perms->allow; + aad(&sa)->request = aad(&sa)->request & ~perms->allow; - if (sa.aad->fs.request & perms->kill) + if (aad(&sa)->request & perms->kill) type = AUDIT_APPARMOR_KILL; /* quiet known rejects, assumes quiet and kill do not overlap */ - if ((sa.aad->fs.request & perms->quiet) && + if ((aad(&sa)->request & perms->quiet) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) - sa.aad->fs.request &= ~perms->quiet; + aad(&sa)->request &= ~perms->quiet; - if (!sa.aad->fs.request) - return COMPLAIN_MODE(profile) ? 0 : sa.aad->error; + if (!aad(&sa)->request) + return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error; } - sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow; - return aa_audit(type, profile, gfp, &sa, file_audit_cb); + aad(&sa)->denied = aad(&sa)->request & ~perms->allow; + return aa_audit(type, profile, &sa, file_audit_cb); +} + +/** + * is_deleted - test if a file has been completely unlinked + * @dentry: dentry of file to test for deletion (NOT NULL) + * + * Returns: %1 if deleted else %0 + */ +static inline bool is_deleted(struct dentry *dentry) +{ + if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0) + return 1; + return 0; +} + +static int path_name(int op, struct aa_label *label, struct path *path, + int flags, char *buffer, const char**name, + struct path_cond *cond, u32 request, bool delegate_deleted) +{ + struct aa_profile *profile; + const char *info = NULL; + int error = aa_path_name(path, flags, buffer, name, &info); + if (error) { + if (error == -ENOENT && is_deleted(path->dentry) && + delegate_deleted) + return 0; + fn_for_each_confined(label, profile, + aa_audit_file(profile, &nullperms, op, request, *name, + NULL, cond->uid, info, error)); + return error; + } + + return 0; } /** @@ -251,23 +274,24 @@ return state; } -/** - * is_deleted - test if a file has been completely unlinked - * @dentry: dentry of file to test for deletion (NOT NULL) - * - * Returns: %1 if deleted else %0 - */ -static inline bool is_deleted(struct dentry *dentry) +static int path_perm(int op, struct aa_profile *profile, const char *name, + u32 request, struct path_cond *cond, + struct file_perms *perms) { - if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0) - return 1; - return 0; + int e = 0; + if (profile_unconfined(profile)) + return 0; + aa_str_perms(profile->file.dfa, profile->file.start, name, cond, perms); + if (request & ~perms->allow) + e = -EACCES; + return aa_audit_file(profile, perms, op, request, name, NULL, + cond->uid, NULL, e); } /** * aa_path_perm - do permissions check & audit for @path * @op: operation being checked - * @profile: profile being enforced (NOT NULL) + * @label: profile being enforced (NOT NULL) * @path: path to check permissions of (NOT NULL) * @flags: any additional path flags beyond what the profile specifies * @request: requested permissions @@ -275,35 +299,30 @@ * * Returns: %0 else error if access denied or other error */ -int aa_path_perm(int op, struct aa_profile *profile, struct path *path, +int aa_path_perm(int op, struct aa_label *label, struct path *path, int flags, u32 request, struct path_cond *cond) { - char *buffer = NULL; struct file_perms perms = {}; - const char *name, *info = NULL; + char *buffer = NULL; + const char *name; + struct aa_profile *profile; int error; - flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0); - error = aa_path_name(path, flags, &buffer, &name, &info); - if (error) { - if (error == -ENOENT && is_deleted(path->dentry)) { - /* Access to open files that are deleted are - * give a pass (implicit delegation) - */ - error = 0; - info = NULL; - perms.allow = request; - } - } else { - aa_str_perms(profile->file.dfa, profile->file.start, name, cond, - &perms); - if (request & ~perms.allow) - error = -EACCES; - } - error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name, - NULL, cond->uid, info, error); - kfree(buffer); + /* TODO: fix path lookup flags */ + flags |= labels_profile(label)->path_flags | + (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0); + get_buffers(buffer); + + error = path_name(op, label, path, flags, buffer, &name, cond, request, + true); + if (error) + goto out; + error = fn_for_each_confined(label, profile, + path_perm(op, profile, name, request, cond, &perms)); + +out: + put_buffers(buffer); return error; } @@ -327,65 +346,25 @@ return 1; } -/** - * aa_path_link - Handle hard link permission check - * @profile: the profile being enforced (NOT NULL) - * @old_dentry: the target dentry (NOT NULL) - * @new_dir: directory the new link will be created in (NOT NULL) - * @new_dentry: the link being created (NOT NULL) - * - * Handle the permission test for a link & target pair. Permission - * is encoded as a pair where the link permission is determined - * first, and if allowed, the target is tested. The target test - * is done from the point of the link match (not start of DFA) - * making the target permission dependent on the link permission match. - * - * The subset test if required forces that permissions granted - * on link are a subset of the permission granted to target. - * - * Returns: %0 if allowed else error - */ -int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, - struct path *new_dir, struct dentry *new_dentry) +static int profile_path_link(struct aa_profile *profile, const char *lname, + const char *tname, struct path_cond *cond) { - struct path link = { new_dir->mnt, new_dentry }; - struct path target = { new_dir->mnt, old_dentry }; - struct path_cond cond = { - old_dentry->d_inode->i_uid, - old_dentry->d_inode->i_mode - }; - char *buffer = NULL, *buffer2 = NULL; - const char *lname, *tname = NULL, *info = NULL; struct file_perms lperms, perms; + const char *info = NULL; u32 request = AA_MAY_LINK; unsigned int state; - int error; - - lperms = nullperms; - - /* buffer freed below, lname is pointer in buffer */ - error = aa_path_name(&link, profile->path_flags, &buffer, &lname, - &info); - if (error) - goto audit; + int e = -EACCES; - /* buffer2 freed below, tname is pointer in buffer2 */ - error = aa_path_name(&target, profile->path_flags, &buffer2, &tname, - &info); - if (error) - goto audit; - - error = -EACCES; /* aa_str_perms - handles the case of the dfa being NULL */ state = aa_str_perms(profile->file.dfa, profile->file.start, lname, - &cond, &lperms); + cond, &lperms); if (!(lperms.allow & AA_MAY_LINK)) goto audit; /* test to see if target can be paired with link */ state = aa_dfa_null_transition(profile->file.dfa, state); - aa_str_perms(profile->file.dfa, state, tname, &cond, &perms); + aa_str_perms(profile->file.dfa, state, tname, cond, &perms); /* force audit/quiet masks for link are stored in the second entry * in the link pair. @@ -403,10 +382,10 @@ if (!(perms.allow & AA_LINK_SUBSET)) goto done_tests; - /* Do link perm subset test requiring allowed permission on link are a - * subset of the allowed permissions on target. + /* Do link perm subset test requiring allowed permission on link are + * a subset of the allowed permissions on target. */ - aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond, + aa_str_perms(profile->file.dfa, profile->file.start, tname, cond, &perms); /* AA_MAY_LINK is not considered in the subset test */ @@ -425,34 +404,244 @@ } done_tests: - error = 0; + e = 0; audit: - error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request, - lname, tname, cond.uid, info, error); - kfree(buffer); - kfree(buffer2); + return aa_audit_file(profile, &lperms, OP_LINK, request, lname, tname, + cond->uid, info, e); +} + +/** + * aa_path_link - Handle hard link permission check + * @label: the label being enforced (NOT NULL) + * @old_dentry: the target dentry (NOT NULL) + * @new_dir: directory the new link will be created in (NOT NULL) + * @new_dentry: the link being created (NOT NULL) + * + * Handle the permission test for a link & target pair. Permission + * is encoded as a pair where the link permission is determined + * first, and if allowed, the target is tested. The target test + * is done from the point of the link match (not start of DFA) + * making the target permission dependent on the link permission match. + * + * The subset test if required forces that permissions granted + * on link are a subset of the permission granted to target. + * + * Returns: %0 if allowed else error + */ +int aa_path_link(struct aa_label *label, struct dentry *old_dentry, + struct path *new_dir, struct dentry *new_dentry) +{ + struct path link = { new_dir->mnt, new_dentry }; + struct path target = { new_dir->mnt, old_dentry }; + struct path_cond cond = { + old_dentry->d_inode->i_uid, + old_dentry->d_inode->i_mode + }; + char *buffer = NULL, *buffer2 = NULL; + const char *lname, *tname = NULL; + struct aa_profile *profile; + int error; + + /* TODO: fix path lookup flags, auditing of failed path for profile */ + profile = labels_profile(label); + /* buffer freed below, lname is pointer in buffer */ + get_buffers(buffer, buffer2); + error = path_name(OP_LINK, label, &link, + labels_profile(label)->path_flags, buffer, + &lname, &cond, AA_MAY_LINK, false); + if (error) + goto out; + + /* buffer2 freed below, tname is pointer in buffer2 */ + error = path_name(OP_LINK, label, &target, + labels_profile(label)->path_flags, buffer2, &tname, + &cond, AA_MAY_LINK, false); + if (error) + goto out; + + error = fn_for_each_confined(label, profile, + profile_path_link(profile, lname, tname, &cond)); + +out: + put_buffers(buffer, buffer2); return error; } +static int __file_path_perm(int op, struct aa_label *label, + struct aa_label *flabel, struct file *file, + u32 request, u32 denied) +{ + struct aa_profile *profile; + struct file_perms perms = {}; + struct path_cond cond = { + .uid = file_inode(file)->i_uid, + .mode = file_inode(file)->i_mode + }; + const char *name; + char *buffer; + int flags, error; + + /* TODO: fix path lookup flags */ + flags = PATH_DELEGATE_DELETED | labels_profile(label)->path_flags | + (S_ISDIR(cond.mode) ? PATH_IS_DIR : 0); + __get_buffers(buffer); + error = path_name(op, label, &file->f_path, flags, buffer, &name, &cond, + request, true); + if (error) { + if (error == 1) + /* Access to open files that are deleted are + * given a pass (implicit delegation) + */ + /* TODO not needed when full perms cached */ + error = 0; + goto out; + } + + /* revalidation due to label out of date. No revocation at this time */ + if (!denied && flabel == label) + goto out; + + /* TODO: skip checking profiles already cached on flabel */ + error = fn_for_each_confined(label, profile, + path_perm(op, profile, name, request, &cond, + &perms)); + if (error) + goto out; + + if (denied) { + /* expanding cached perms + * - check profiles in flabel not already checked in label + */ + /* TODO: cache full perms so this only happens because of + * conditionals */ + /* TODO: don't audit here + int e = fn_for_each_not_in_set(label, flabel, profile, + path_perm(op, profile, name, request, &cond, + &perms)); + if (e) + goto out; + */ + } + + /*update_file_cxt(fcxt, label, request);*/ + +out: + __put_buffers(buffer); + return error; +} + /** * aa_file_perm - do permission revalidation check & audit for @file * @op: operation being checked - * @profile: profile being enforced (NOT NULL) + * @label: label being enforced (NOT NULL) * @file: file to revalidate access permissions on (NOT NULL) * @request: requested permissions * * Returns: %0 if access allowed else error */ -int aa_file_perm(int op, struct aa_profile *profile, struct file *file, +int aa_file_perm(int op, struct aa_label *label, struct file *file, u32 request) { - struct path_cond cond = { - .uid = file_inode(file)->i_uid, - .mode = file_inode(file)->i_mode - }; + struct aa_file_cxt *fcxt; + struct aa_label *flabel; + u32 denied; + int error = 0; + + AA_BUG(!label); + AA_BUG(!file); + + fcxt = file_cxt(file); + + rcu_read_lock(); + flabel = rcu_dereference(fcxt->label); + AA_BUG(!flabel); + + /* revalidate access, if task is unconfined, or the cached cred + * doesn't match or if the request is for more permissions than + * was granted. + * + * Note: the test for !unconfined(flabel) is to handle file + * delegation from unconfined tasks + */ + denied = request & ~fcxt->allow; + if (unconfined(label) || unconfined(flabel) || + (!denied && ((flabel == label) || + aa_label_is_subset(flabel, label)))) + goto done; + + /* TODO: label cross check */ + + if (file->f_path.mnt && path_mediated_fs(file_inode(file))) + error = __file_path_perm(op, label, flabel, file, request, + denied); + +done: + rcu_read_unlock(); + + return error; +} + +static void revalidate_tty(struct aa_label *label) +{ + struct tty_struct *tty; + int drop_tty = 0; + + tty = get_current_tty(); + if (!tty) + return; + + spin_lock(&tty_files_lock); + if (!list_empty(&tty->tty_files)) { + struct tty_file_private *file_priv; + struct file *file; + file_priv = list_first_entry(&tty->tty_files, + struct tty_file_private, list); + file = file_priv->file; - return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED, - request, &cond); + if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE)) + drop_tty = 1; + } + spin_unlock(&tty_files_lock); + tty_kref_put(tty); + + if (drop_tty) + no_tty(); +} + +static int match_file(const void *p, struct file *file, unsigned fd) +{ + struct aa_label *label = (struct aa_label *)p; + if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file))) + return fd + 1; + return 0; +} + + +/* based on selinux's flush_unauthorized_files */ +void aa_inherit_files(const struct cred *cred, struct files_struct *files) +{ + struct aa_label *label = aa_get_newest_cred_label(cred); + struct file *devnull = NULL; + unsigned n; + + revalidate_tty(label); + + /* Revalidate access to inherited open files. */ + n = iterate_fd(files, 0, match_file, label); + if (!n) /* none found? */ + goto out; + + devnull = dentry_open(&aa_null, O_RDWR, cred); + if (IS_ERR(devnull)) + devnull = NULL; + /* replace all the matching ones with this */ + do { + replace_fd(n - 1, devnull, 0); + } while ((n = iterate_fd(files, n, match_file, label)) != 0); + if (devnull) + fput(devnull); +out: + aa_put_label(label); } --- linux-3.13.0.orig/security/apparmor/lib.c +++ linux-3.13.0/security/apparmor/lib.c @@ -4,7 +4,7 @@ * This file contains basic common functions used in AppArmor * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * Copyright 2009-2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,9 +17,11 @@ #include #include -#include "include/audit.h" #include "include/apparmor.h" - +#include "include/audit.h" +#include "include/label.h" +#include "include/perms.h" +#include "include/policy.h" /** * aa_split_fqname - split a fqname into a profile and namespace name @@ -66,11 +68,8 @@ void aa_info_message(const char *str) { if (audit_enabled) { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.info = str; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, 0); + aad(&sa)->info = str; aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); } printk(KERN_INFO "AppArmor: %s\n", str); @@ -118,3 +117,263 @@ else kfree(buffer); } + + +__counted char *aa_str_alloc(int size, gfp_t gfp) +{ + struct counted_str *str; + str = kmalloc(sizeof(struct counted_str) + size, gfp); + if (!str) + return NULL; + + kref_init(&str->count); + return str->name; +} + +void aa_str_kref(struct kref *kref) +{ + kfree(container_of(kref, struct counted_str, count)); +} + +/** + * aa_perm_mask_to_chr - convert a perm mask to its short string + * @mask: permission mask to convert + * @str: character buffer to store string in (at least 10 characters) + */ +void aa_perm_mask_to_chr(u32 mask, char *str) +{ + if (mask & AA_EXEC_MMAP) + *str++ = 'm'; + if (mask & MAY_READ) + *str++ = 'r'; + if (mask & MAY_WRITE) + *str++ = 'w'; + else if (mask & MAY_APPEND) + *str++ = 'a'; + if (mask & AA_MAY_CREATE) + *str++ = 'c'; + if (mask & AA_MAY_DELETE) + *str++ = 'd'; + if (mask & AA_MAY_LINK) + *str++ = 'l'; + if (mask & AA_MAY_LOCK) + *str++ = 'k'; + if (mask & MAY_EXEC) + *str++ = 'x'; + *str = '\0'; +} + +void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask) +{ + char str[10]; + + aa_perm_mask_to_chr(mask, str); + + audit_log_format(ab, "\"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\"", str, + mask & AA_MAY_OPEN ? " open" : "", + mask & AA_MAY_RENAME ? " rename" : "", + mask & AA_MAY_META_WRITE ? " metawrite" : "", + mask & AA_MAY_META_READ ? " metaread" : "", + mask & AA_MAY_GET_SECURITY ? " getsecurity" : "", + mask & AA_MAY_SET_SECURITY ? " setsecurity" : "", + mask & AA_MAY_CHMOD ? " chmod" : "", + mask & AA_MAY_CHOWN ? " chown" : "", + mask & AA_MAY_CHGRP ? " chgrp" : "", + mask & AA_MAY_MPROT_WX ? " mprot_wx" : "", + mask & AA_MAY_MPROT_XW ? " mprot_xw" : "", + mask & AA_MAY_SNAPSHOT ? " snapshot" : "", + mask & AA_MAY_STACK ? " stack" : "", + mask & AA_MAY_ONEXEC ? " onexec" : "", + mask & AA_MAY_CHANGE_PROFILE ? " change_profile" : "", + mask & AA_MAY_CHANGEHAT ? " change_hat" : ""); +} + +/** + * aa_audit_perms_cb - generic callback fn for auditing perms + * @ab: audit buffer (NOT NULL) + * @va: audit struct to audit values of (NOT NULL) + */ +static void aa_audit_perms_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + if (aad(sa)->request) { + audit_log_format(ab, " requested_mask="); + aa_audit_perm_mask(ab, aad(sa)->request); + } + if (aad(sa)->denied) { + audit_log_format(ab, "denied_mask="); + aa_audit_perm_mask(ab, aad(sa)->denied); + } + audit_log_format(ab, " target="); + audit_log_untrustedstring(ab, aad(sa)->target); +} + +/** + * aa_apply_modes_to_perms - apply namespace and profile flags to perms + * @profile: that perms where computed from + * @perms: perms to apply mode modifiers to + * + * TODO: split into profile and ns based flags for when accumulating perms + */ +void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) +{ + switch (AUDIT_MODE(profile)) { + case AUDIT_ALL: + perms->audit = ALL_PERMS_MASK; + /* fall through */ + case AUDIT_NOQUIET: + perms->quiet = 0; + break; + case AUDIT_QUIET: + perms->audit = 0; + /* fall through */ + case AUDIT_QUIET_DENIED: + perms->quiet = ALL_PERMS_MASK; + break; + } + + if (KILL_MODE(profile)) + perms->kill = ALL_PERMS_MASK; + else if (COMPLAIN_MODE(profile)) + perms->complain = ALL_PERMS_MASK; +} + +void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, + struct aa_perms *perms) +{ + perms->deny = 0; + perms->kill = perms->stop = 0; + perms->complain = perms->cond = 0; + perms->hide = 0; + perms->allow = dfa_user_allow(dfa, state); + perms->audit = dfa_user_audit(dfa, state); + perms->quiet = dfa_user_quiet(dfa, state); +} + +void aa_profile_match_label(struct aa_profile *profile, const char *label, + int type, struct aa_perms *perms) +{ + /* TODO: doesn't yet handle extended types */ + unsigned int state; + if (profile->policy.dfa) { + state = aa_dfa_next(profile->policy.dfa, + profile->policy.start[AA_CLASS_LABEL], + type); + state = aa_dfa_match(profile->policy.dfa, state, label); + aa_compute_perms(profile->policy.dfa, state, perms); + } else + memset(perms, 0, sizeof(*perms)); +} + + +int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, + u32 request, int type, u32 *deny, + struct common_audit_data *sa) +{ + struct aa_perms perms; + aad(sa)->label = &profile->label; + aad(sa)->target = target; + aad(sa)->request = request; + + aa_profile_match_label(profile, target->base.hname, type, &perms); + aa_apply_modes_to_perms(profile, &perms); + *deny |= request & perms.deny; + return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb); +} + +/** + * aa_check_perms - do audit mode selection based on perms set + * @profile: profile being checked + * @perms: perms computed for the request + * @request: requested perms + * @deny: Returns: explicit deny set + * @sa: initialized audit structure (MAY BE NULL if not auditing) + * @cb: callback fn for tpye specific fields (MAY BE NULL) + * + * Returns: 0 if permission else error code + * + * Note: profile audit modes need to be set before calling by setting the + * perm masks appropriately. + * + * If not auditing then complain mode is not enabled and the + * error code will indicate whether there was an explicit deny + * with a positive value. + */ +int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, + u32 request, struct common_audit_data *sa, + void (*cb) (struct audit_buffer *, void *)) +{ + int type, error; + bool stop = false; + u32 denied = request & (~perms->allow | perms->deny); + if (likely(!denied)) { + /* mask off perms that are not being force audited */ + request &= perms->audit; + if (!request || !sa) + return 0; + + type = AUDIT_APPARMOR_AUDIT; + error = 0; + } else { + error = -EACCES; + + if (denied & perms->kill) + type = AUDIT_APPARMOR_KILL; + else if (denied == (denied & perms->complain)) + type = AUDIT_APPARMOR_ALLOWED; + else + type = AUDIT_APPARMOR_DENIED; + + if (denied & perms->stop) + stop = true; + if (denied == (denied & perms->hide)) + error = -ENOENT; + + denied &= ~perms->quiet; + if (type != AUDIT_APPARMOR_ALLOWED && (!sa || !denied)) + return error; + } + + if (sa) { + aad(sa)->label = &profile->label; + aad(sa)->request = request; + aad(sa)->denied = denied; + aad(sa)->error = error; + aa_audit_msg(type, sa, cb); + } + + if (type == AUDIT_APPARMOR_ALLOWED) + error = 0; + + return error; +} + +const char *aa_imode_name(umode_t mode) +{ + switch(mode & S_IFMT) { + case S_IFSOCK: + return "sock"; + case S_IFLNK: + return "link"; + case S_IFREG: + return "reg"; + case S_IFBLK: + return "blkdev"; + case S_IFDIR: + return "dir"; + case S_IFCHR: + return "chrdev"; + case S_IFIFO: + return "fifo"; + } + return "unknown"; +} + +const char *aa_peer_name(struct aa_profile *peer) +{ + if (profile_unconfined(peer)) + return "unconfined"; + + return peer->base.hname; +} --- linux-3.13.0.orig/security/apparmor/net.c +++ linux-3.13.0/security/apparmor/net.c @@ -0,0 +1,171 @@ +/* + * AppArmor security module + * + * This file contains AppArmor network mediation + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2012 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#include "include/apparmor.h" +#include "include/audit.h" +#include "include/context.h" +#include "include/net.h" +#include "include/label.h" +#include "include/policy.h" + +#include "net_names.h" + +struct aa_fs_entry aa_fs_entry_network[] = { + AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK), + { } +}; + +/* audit callback for net specific fields */ +static void audit_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + audit_log_format(ab, " family="); + if (address_family_names[sa->u.net->family]) { + audit_log_string(ab, address_family_names[sa->u.net->family]); + } else { + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family); + } + audit_log_format(ab, " sock_type="); + if (sock_type_names[aad(sa)->net.type]) { + audit_log_string(ab, sock_type_names[aad(sa)->net.type]); + } else { + audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type); + } + audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); +} + +/** + * audit_net - audit network access + * @profile: profile being enforced (NOT NULL) + * @op: operation being checked + * @family: network family + * @type: network type + * @protocol: network protocol + * @sk: socket auditing is being applied to + * @error: error code for failure else 0 + * + * Returns: %0 or sa->error else other errorcode on failure + */ +static int audit_net(struct aa_profile *profile, int op, u16 family, int type, + int protocol, struct sock *sk, int error) +{ + int audit_type = AUDIT_APPARMOR_AUTO; + struct lsm_network_audit net = { }; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NET, op); + if (!sk) + sa.type = LSM_AUDIT_DATA_NONE; + /* todo fill in socket addr info */ + net.family = family; + net.sk = sk; + sa.u.net = &net; + aad(&sa)->net.type = type; + aad(&sa)->net.protocol = protocol; + aad(&sa)->error = error; + + if (likely(!aad(&sa)->error)) { + u16 audit_mask = profile->net.audit[sa.u.net->family]; + if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && + !(1 << aad(&sa)->net.type & audit_mask))) + return 0; + audit_type = AUDIT_APPARMOR_AUDIT; + } else { + u16 quiet_mask = profile->net.quiet[sa.u.net->family]; + u16 kill_mask = 0; + u16 denied = (1 << aad(&sa)->net.type); + + if (denied & kill_mask) + audit_type = AUDIT_APPARMOR_KILL; + + if ((denied & quiet_mask) && + AUDIT_MODE(profile) != AUDIT_NOQUIET && + AUDIT_MODE(profile) != AUDIT_ALL) + return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error; + } + + return aa_audit(audit_type, profile, &sa, audit_cb); +} + +static int af_mask_perm(int op, struct aa_profile *profile, u16 family, + int type, int protocol, struct sock *sk) +{ + u16 family_mask; + int error = 0; + + if (profile_unconfined(profile)) + return 0; + + if ((family < 0) || (family >= AF_MAX)) + return -EINVAL; + if ((type < 0) || (type >= SOCK_MAX)) + return -EINVAL; + + family_mask = profile->net.allow[family]; + error = (family_mask & (1 << type)) ? 0 : -EACCES; + return audit_net(profile, op, family, type, protocol, sk, error); +} + +/** + * aa_net_perm - very course network access check + * @op: operation being checked + * @label: label being enforced (NOT NULL) + * @family: network family + * @type: network type + * @protocol: network protocol + * + * Returns: %0 else error if permission denied + */ +int aa_net_perm(int op, struct aa_label *label, u16 family, int type, + int protocol, struct sock *sk) +{ + struct aa_profile *profile; + + if ((family < 0) || (family >= AF_MAX)) + return -EINVAL; + + if ((type < 0) || (type >= SOCK_MAX)) + return -EINVAL; + + /* unix domain and netlink sockets are handled by ipc */ + if (family == AF_UNIX || family == AF_NETLINK) + return 0; + + + return fn_for_each_confined(label, profile, + af_mask_perm(op, profile, family, type, protocol, sk)); +} + +/** + * aa_revalidate_sk - Revalidate access to a sock + * @op: operation being checked + * @sk: sock being revalidated (NOT NULL) + * + * Returns: %0 else error if permission denied + */ +int aa_revalidate_sk(int op, struct sock *sk) +{ + struct aa_label *label; + int error = 0; + + if (in_interrupt()) + label = ((struct aa_sk_cxt *) SK_CXT(sk))->label; + else + label = __aa_current_label(); + + if (!unconfined(label)) + error = aa_net_perm(op, label, sk->sk_family, sk->sk_type, + sk->sk_protocol, sk); + + return error; +} --- linux-3.13.0.orig/security/apparmor/apparmorfs.c +++ linux-3.13.0/security/apparmor/apparmorfs.c @@ -18,15 +18,18 @@ #include #include #include +#include #include #include #include +#include #include "include/apparmor.h" #include "include/apparmorfs.h" #include "include/audit.h" #include "include/context.h" #include "include/crypto.h" +#include "include/ipc.h" #include "include/policy.h" #include "include/resource.h" @@ -37,7 +40,7 @@ * * Returns: length of mangled name */ -static int mangle_name(char *name, char *target) +static int mangle_name(const char *name, char *target) { char *t = target; @@ -186,6 +189,143 @@ .llseek = default_llseek, }; +/** + * query_label - queries a label and writes permissions to buf + * @buf: the resulting permissions string is stored here (NOT NULL) + * @buf_len: size of buf + * @query: binary query string to match against the dfa + * @query_len: size of query + * + * The buffers pointed to by buf and query may overlap. The query buffer is + * parsed before buf is written to. + * + * The query should look like "LABEL_NAME\0DFA_STRING" where LABEL_NAME is + * the name of the label, in the current namespace, that is to be queried and + * DFA_STRING is a binary string to match against the label(s)'s DFA. + * + * LABEL_NAME must be NUL terminated. DFA_STRING may contain NUL characters + * but must *not* be NUL terminated. + * + * Returns: number of characters written to buf or -errno on failure + */ +static ssize_t query_label(char *buf, size_t buf_len, + char *query, size_t query_len) +{ + struct aa_profile *profile; + struct aa_label *label; + struct aa_namespace *ns; + char *label_name, *match_str; + size_t label_name_len, match_len; + u32 allow = 0, audit = 0, quiet = 0; + unsigned int state; + struct label_it i; + + if (!query_len) + return -EINVAL; + + label_name = query; + label_name_len = strnlen(query, query_len); + if (!label_name_len || label_name_len == query_len) + return -EINVAL; + + /** + * The extra byte is to account for the null byte between the + * profile name and dfa string. profile_name_len is greater + * than zero and less than query_len, so a byte can be safely + * added or subtracted. + */ + match_str = label_name + label_name_len + 1; + match_len = query_len - label_name_len - 1; + + ns = labels_ns(aa_current_label()); + label = aa_label_parse(ns, label_name, GFP_KERNEL); + if (IS_ERR(label)) + return PTR_ERR(label); + + allow = 0xffffffff; + audit = quiet = 0x00000000; + label_for_each_confined(i, label, profile) { + if (profile->policy.dfa) { + state = aa_dfa_match_len(profile->policy.dfa, + profile->policy.start[0], + match_str, match_len); + allow &= dfa_user_allow(profile->policy.dfa, state); + audit |= dfa_user_audit(profile->policy.dfa, state); + quiet |= dfa_user_quiet(profile->policy.dfa, state); + } else { + /* TODO: do we want to accumulate audit/quiet + or just clear as currently doing */ + allow = audit = quiet = 0; + break; + } + } + aa_put_label(label); + + return scnprintf(buf, buf_len, + "allow 0x%08x\ndeny 0x%08x\naudit 0x%08x\nquiet 0x%08x\n", + allow, 0, audit, quiet); +} + +#define QUERY_CMD_LABEL "label\0" +#define QUERY_CMD_LABEL_LEN 6 +#define QUERY_CMD_PROFILE "profile\0" +#define QUERY_CMD_PROFILE_LEN 8 + +/** + * aa_write_access - generic permissions query + * @file: pointer to open apparmorfs/access file + * @ubuf: user buffer containing the complete query string (NOT NULL) + * @count: size of ubuf + * @ppos: position in the file (MUST BE ZERO) + * + * Allows for one permission query per open(), write(), and read() sequence. + * The only query currently supported is a label-based query. For this query + * ubuf must begin with "label\0", followed by the profile query specific + * format described in the query_label() function documentation. + * + * Returns: number of bytes written or -errno on failure + */ +static ssize_t aa_write_access(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + char *buf; + ssize_t len; + + if (*ppos) + return -ESPIPE; + + buf = simple_transaction_get(file, ubuf, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + if (count > QUERY_CMD_PROFILE_LEN && + !memcmp(buf, QUERY_CMD_PROFILE, QUERY_CMD_PROFILE_LEN)) { + len = query_label(buf, SIMPLE_TRANSACTION_LIMIT, + buf + QUERY_CMD_PROFILE_LEN, + count - QUERY_CMD_PROFILE_LEN); + } else if (count > QUERY_CMD_LABEL_LEN && + !memcmp(buf, QUERY_CMD_LABEL, QUERY_CMD_LABEL_LEN)) { + len = query_label(buf, SIMPLE_TRANSACTION_LIMIT, + buf + QUERY_CMD_LABEL_LEN, + count - QUERY_CMD_LABEL_LEN); + } else + len = -EINVAL; + + if (len < 0) + return len; + + simple_transaction_set(file, len); + + return count; +} + +static const struct file_operations aa_fs_access = { + .write = aa_write_access, + .read = simple_transaction_read, + .release = simple_transaction_release, + .llseek = generic_file_llseek, +}; + static int aa_fs_seq_show(struct seq_file *seq, void *v) { struct aa_fs_entry *fs_file = seq->private; @@ -249,9 +389,10 @@ static int aa_fs_seq_profname_show(struct seq_file *seq, void *v) { struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_label *label = aa_get_label_rcu(&r->label); + struct aa_profile *profile = labels_profile(label); seq_printf(seq, "%s\n", profile->base.name); - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -272,9 +413,10 @@ static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v) { struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_label *label = aa_get_label_rcu(&r->label); + struct aa_profile *profile = labels_profile(label); seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]); - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -295,14 +437,15 @@ static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v) { struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_label *label = aa_get_label_rcu(&r->label); + struct aa_profile *profile = labels_profile(label); if (profile->attach) seq_printf(seq, "%s\n", profile->attach); else if (profile->xmatch) seq_puts(seq, "\n"); else seq_printf(seq, "%s\n", profile->base.name); - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -323,7 +466,8 @@ static int aa_fs_seq_hash_show(struct seq_file *seq, void *v) { struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_label *label = aa_get_label_rcu(&r->label); + struct aa_profile *profile = labels_profile(label); unsigned int i, size = aa_hash_size(); if (profile->hash) { @@ -379,6 +523,8 @@ for (i = 0; i < AAFS_PROF_SIZEOF; i++) { new->dents[i] = old->dents[i]; + if (new->dents[i]) + new->dents[i]->d_inode->i_mtime = CURRENT_TIME; old->dents[i] = NULL; } } @@ -387,7 +533,7 @@ struct aa_profile *profile, const struct file_operations *fops) { - struct aa_replacedby *r = aa_get_replacedby(profile->replacedby); + struct aa_replacedby *r = aa_get_replacedby(profile->label.replacedby); struct dentry *dent; dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops); @@ -682,7 +828,7 @@ static void *p_start(struct seq_file *f, loff_t *pos) { struct aa_profile *profile = NULL; - struct aa_namespace *root = aa_current_profile()->ns; + struct aa_namespace *root = labels_ns(aa_current_label()); loff_t l = *pos; f->private = aa_get_namespace(root); @@ -789,6 +935,16 @@ { } }; +static struct aa_fs_entry aa_fs_entry_ptrace[] = { + AA_FS_FILE_STRING("mask", "read trace"), + { } +}; + +static struct aa_fs_entry aa_fs_entry_signal[] = { + AA_FS_FILE_STRING("mask", AA_FS_SIG_MASK), + { } +}; + static struct aa_fs_entry aa_fs_entry_domain[] = { AA_FS_FILE_BOOLEAN("change_hat", 1), AA_FS_FILE_BOOLEAN("change_hatv", 1), @@ -797,18 +953,47 @@ { } }; +static struct aa_fs_entry aa_fs_entry_versions[] = { + AA_FS_FILE_BOOLEAN("v5", 1), + AA_FS_FILE_BOOLEAN("v6", 1), + { } +}; + static struct aa_fs_entry aa_fs_entry_policy[] = { + AA_FS_DIR("versions", aa_fs_entry_versions), AA_FS_FILE_BOOLEAN("set_load", 1), - {} + { } +}; + +static struct aa_fs_entry aa_fs_entry_mount[] = { + AA_FS_FILE_STRING("mask", "mount umount"), + { } +}; + +static struct aa_fs_entry aa_fs_entry_namespaces[] = { + AA_FS_FILE_BOOLEAN("profile", 1), + AA_FS_FILE_BOOLEAN("pivot_root", 1), + { } +}; + +static struct aa_fs_entry aa_fs_entry_dbus[] = { + AA_FS_FILE_STRING("mask", "acquire send receive"), + { } }; static struct aa_fs_entry aa_fs_entry_features[] = { AA_FS_DIR("policy", aa_fs_entry_policy), AA_FS_DIR("domain", aa_fs_entry_domain), AA_FS_DIR("file", aa_fs_entry_file), + AA_FS_DIR("network", aa_fs_entry_network), + AA_FS_DIR("mount", aa_fs_entry_mount), + AA_FS_DIR("namespaces", aa_fs_entry_namespaces), AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), AA_FS_DIR("rlimit", aa_fs_entry_rlimit), AA_FS_DIR("caps", aa_fs_entry_caps), + AA_FS_DIR("ptrace", aa_fs_entry_ptrace), + AA_FS_DIR("signal", aa_fs_entry_signal), + AA_FS_DIR("dbus", aa_fs_entry_dbus), { } }; @@ -816,6 +1001,7 @@ AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), + AA_FS_FILE_FOPS(".access", 0666, &aa_fs_access), AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops), AA_FS_DIR("features", aa_fs_entry_features), { } @@ -925,6 +1111,52 @@ aafs_remove_dir(&aa_fs_entry); } + +#define NULL_FILE_NAME ".null" +struct path aa_null; + +static int aa_mk_null_file(struct dentry *parent) +{ + struct vfsmount *mount = NULL; + struct dentry *dentry; + struct inode *inode; + int count = 0; + int error = simple_pin_fs(parent->d_sb->s_type, &mount, &count); + + if (error) { + return error; + } + mutex_lock(&parent->d_inode->i_mutex); + dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME)); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto out; + } + inode = new_inode(parent->d_inode->i_sb); + if (!inode) { + error = -ENOMEM; + goto out1; + } + + inode->i_ino = get_next_ino(); + inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, + MKDEV(MEM_MAJOR, 3)); + d_instantiate(dentry, inode); + aa_null.dentry = dget(dentry); + aa_null.mnt = mntget(mount); + + error = 0; + +out1: + dput(dentry); +out: + mutex_unlock(&parent->d_inode->i_mutex); + simple_release_fs(&mount, &count); + return error; +} + /** * aa_create_aafs - create the apparmor security filesystem * @@ -954,7 +1186,13 @@ if (error) goto error; - /* TODO: add support for apparmorfs_null and apparmorfs_mnt */ + error = aa_mk_null_file(aa_fs_entry.dentry); + if (error) + goto error; + + if (!aa_g_unconfined_init) { + /* TODO: add default profile to apparmorfs */ + } /* Report that AppArmor fs is enabled */ aa_info_message("AppArmor Filesystem Enabled"); --- linux-3.13.0.orig/security/apparmor/label.c +++ linux-3.13.0/security/apparmor/label.c @@ -0,0 +1,1646 @@ +/* + * AppArmor security module + * + * This file contains AppArmor label definitions + * + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#include +#include + +#include "include/apparmor.h" +#include "include/label.h" +#include "include/policy.h" +#include "include/sid.h" + + +/* + * the aa_label represents the set of profiles confining an object + * + * Labels maintain a reference count to the set of pointers they reference + * Labels are ref counted by + * tasks and object via the security field/security context off the field + * code - will take a ref count on a label if it needs the label + * beyond what is possible with an rcu_read_lock. + * profiles - each profile is a label + * sids - a pinned sid will keep a refcount of the label it is + * referencing + * objects - inode, files, sockets, ... + * + * Labels are not ref counted by the label set, so they maybe removed and + * freed when no longer in use. + * + */ + +static void free_replacedby(struct aa_replacedby *r) +{ + if (r) { + /* r->label will not updated any more as r is dead */ + aa_put_label(rcu_dereference_protected(r->label, true)); + kzfree(r); + } +} + +void aa_free_replacedby_kref(struct kref *kref) +{ + struct aa_replacedby *r = container_of(kref, struct aa_replacedby, + count); + free_replacedby(r); +} + +struct aa_replacedby *aa_alloc_replacedby(struct aa_label *l) +{ + struct aa_replacedby *r; + + r = kzalloc(sizeof(struct aa_replacedby), GFP_KERNEL); + if (r) { + kref_init(&r->count); + rcu_assign_pointer(r->label, aa_get_label(l)); + } + return r; +} + +/* requires profile list write lock held */ +void __aa_update_replacedby(struct aa_label *orig, struct aa_label *new) +{ + struct aa_label *tmp; + + AA_BUG(!orig); + AA_BUG(!new); + AA_BUG(!mutex_is_locked(&labels_ns(orig)->lock)); + + tmp = rcu_dereference_protected(orig->replacedby->label, + &labels_ns(orig)->lock); + rcu_assign_pointer(orig->replacedby->label, aa_get_label(new)); + orig->flags |= FLAG_INVALID; + aa_put_label(tmp); +} + +/* helper fn for label_for_each_confined */ +int aa_label_next_confined(struct aa_label *l, int i) +{ + for (; i < l->size; i++) { + if (!profile_unconfined(l->ent[i])) + return i; + } + + return i; +} + +static bool label_profiles_unconfined(struct aa_label *label) +{ + struct aa_profile *profile; + struct label_it i; + + label_for_each(i, label, profile) { + if (!profile_unconfined(profile)) + return false; + } + + return true; +} + +static int profile_cmp(struct aa_profile *a, struct aa_profile *b); +/** + * aa_label_next_not_in_set - return the next profile of @sub not in @set + * @I: label iterator + * @set: label to test against + * @sub: label to if is subset of @set + * + * Returns: profile in @sub that is not in @set + * else NULL if @sub is a subset of @set + */ +struct aa_profile * aa_label_next_not_in_set(struct label_it *I, + struct aa_label *set, + struct aa_label *sub) +{ + AA_BUG(!set); + AA_BUG(!I); + AA_BUG(I->i < 0); + AA_BUG(I->i > set->size); + AA_BUG(!sub); + AA_BUG(I->j < 0); + AA_BUG(I->j > sub->size); + + while (I->j < sub->size && I->i < set->size) { + int res = profile_cmp(sub->ent[I->j], set->ent[I->i]); + if (res == 0) { + (I->j)++; + (I->i)++; + } else if (res > 0) + (I->i)++; + else + return sub->ent[(I->j)++]; + } + + if (I->j < sub->size) + return sub->ent[(I->j)++]; + + return NULL; +} + +/** + * aa_label_is_subset - test if @sub is a subset of @set + * @set: label to test against + * @sub: label to test if is subset of @set + * + * Returns: true if @sub is subset of @set + * else false + */ +bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub) +{ + struct label_it i = { }; + + if (sub == set) + return true; + + return aa_label_next_not_in_set(&i, set, sub) == NULL; +} + +void aa_label_destroy(struct aa_label *label) +{ + AA_BUG(!label); + + if (label_invalid(label)) + labelsetstats_dec(labels_set(label), invalid); + + if (!label_isprofile(label)) { + struct aa_profile *profile; + struct label_it i; + + aa_put_str(label->hname); + + label_for_each(i, label, profile) + aa_put_profile(profile); + } + + aa_free_sid(label->sid); + aa_put_replacedby(label->replacedby); +} + +void aa_label_free(struct aa_label *label) +{ + if (!label) + return; + + aa_label_destroy(label); + labelstats_inc(freed); + kzfree(label); +} + +static void label_free_rcu(struct rcu_head *head) +{ + struct aa_label *l = container_of(head, struct aa_label, rcu); + + if (l->flags & FLAG_NS_COUNT) + aa_free_namespace(labels_ns(l)); + else if (label_isprofile(l)) + aa_free_profile(labels_profile(l)); + else + aa_label_free(l); +} + +bool aa_label_remove(struct aa_labelset *ls, struct aa_label *label); +void aa_label_kref(struct kref *kref) +{ + struct aa_label *l = container_of(kref, struct aa_label, count); + struct aa_namespace *ns = labels_ns(l); + + if (!ns) { + /* never live, no rcu callback needed, just using the fn */ + label_free_rcu(&l->rcu); + return; + } + + (void) aa_label_remove(&ns->labels, l); + + /* TODO: if compound label and not invalid add to reclaim cache */ + call_rcu(&l->rcu, label_free_rcu); +} + +bool aa_label_init(struct aa_label *label, int size) +{ + AA_BUG(!label); + AA_BUG(size < 1); + + label->sid = aa_alloc_sid(); + if (label->sid == AA_SID_INVALID) + return false; + + label->size = size; /* doesn't include null */ + label->ent[size] = NULL; /* null terminate */ + kref_init(&label->count); + RB_CLEAR_NODE(&label->node); + + return true; +} + +/** + * aa_label_alloc - allocate a label with a profile vector of @size length + * @size: size of profile vector in the label + * @gfp: memory allocation type + * + * Returns: new label + * else NULL if failed + */ +struct aa_label *aa_label_alloc(int size, gfp_t gfp) +{ + struct aa_label *label; + + AA_BUG(size < 1); + + /* vector: size - 2 (size of array in label struct) + 1 for null */ + label = kzalloc(sizeof(*label) + sizeof(struct aa_label *) * (size - 1), + gfp); + AA_DEBUG("%s (%p)\n", __func__, label); + if (!label) + goto fail; + + if (!aa_label_init(label, size)) + goto fail; + + labelstats_inc(allocated); + + return label; + +fail: + kfree(label); + labelstats_inc(failed); + + return NULL; +} + +static bool __aa_label_remove(struct aa_labelset *ls, struct aa_label *label) +{ + AA_BUG(!ls); + AA_BUG(!label); + AA_BUG(write_can_lock(&ls->lock)); + AA_BUG(labels_set(label) != ls); + + if (label_invalid(label)) + labelstats_dec(invalid_intree); + else + __label_invalidate(label); + + if (label->flags & FLAG_IN_TREE) { + labelsetstats_dec(ls, intree); + rb_erase(&label->node, &ls->root); + label->flags &= ~FLAG_IN_TREE; + return true; + } + + return false; +} + +/** + * aa_label_remove - remove a label from the labelset + * @ls: set to remove the label from + * @l: label to remove + * + * Returns: true if @l was removed from the tree + * else @l was not in tree so it could not be removed + */ +bool aa_label_remove(struct aa_labelset *ls, struct aa_label *l) +{ + unsigned long flags; + bool res; + + write_lock_irqsave(&ls->lock, flags); + res = __aa_label_remove(ls, l); + write_unlock_irqrestore(&ls->lock, flags); + + return res; +} + +static bool __aa_label_replace(struct aa_labelset *ls, struct aa_label *old, + struct aa_label *new) +{ + AA_BUG(!ls); + AA_BUG(!old); + AA_BUG(!new); + AA_BUG(write_can_lock(&ls->lock)); + AA_BUG(labels_set(old) != ls); + AA_BUG(new->flags & FLAG_IN_TREE); + + if (label_invalid(old)) + labelstats_dec(invalid_intree); + else + __label_invalidate(old); + + if (old->flags & FLAG_IN_TREE) { + rb_replace_node(&old->node, &new->node, &ls->root); + old->flags &= ~FLAG_IN_TREE; + new->flags |= FLAG_IN_TREE; + return true; + } + + return false; +} + +static struct aa_label *__aa_label_insert(struct aa_labelset *ls, + struct aa_label *l); + +static struct aa_label *__aa_label_remove_and_insert(struct aa_labelset *ls, + struct aa_label *remove, + struct aa_label *insert) +{ + AA_BUG(!ls); + AA_BUG(!remove); + AA_BUG(!insert); + AA_BUG(write_can_lock(&ls->lock)); + AA_BUG(labels_set(remove) != ls); + AA_BUG(insert->flags & FLAG_IN_TREE); + + __aa_label_remove(ls, remove); + return __aa_label_insert(ls, insert); +} + +struct aa_label *aa_label_remove_and_insert(struct aa_labelset *ls, + struct aa_label *remove, + struct aa_label *insert) +{ + unsigned long flags; + struct aa_label *l; + + write_lock_irqsave(&ls->lock, flags); + l = __aa_label_remove_and_insert(ls, remove, insert); + write_unlock_irqrestore(&ls->lock, flags); + + return l; +} + +/** + * aa_label_replace - replace a label @old with a new version @new + * @ls: labelset being manipulated + * @old: label to replace + * @new: label replacing @old + * + * Returns: true if @old was in tree and replaced + * else @old was not in tree, and @new was not inserted + */ +bool aa_label_replace(struct aa_labelset *ls, struct aa_label *old, + struct aa_label *new) +{ + unsigned long flags; + bool res; + + write_lock_irqsave(&ls->lock, flags); + if (!(old->flags & FLAG_IN_TREE)) { + struct aa_label *l = __aa_label_insert(ls, new); + res = (l == new); + aa_put_label(l); + } else + res = __aa_label_replace(ls, old, new); + write_unlock_irqrestore(&ls->lock, flags); + + return res; +} + +static int ns_cmp(struct aa_namespace *a, struct aa_namespace *b) +{ + int res; + + AA_BUG(!a); + AA_BUG(!b); + AA_BUG(!a->base.name); + AA_BUG(!b->base.name); + + if (a == b) + return 0; + + res = a->level - b->level; + if (res) + return res; + + return strcmp(a->base.name, b->base.name); +} + +/** + * profile_cmp - profile comparision for set ordering + * @a: profile to compare (NOT NULL) + * @b: profile to compare (NOT NULL) + * + * Returns: <0 if a < b + * ==0 if a == b + * >0 if a > b + */ +static int profile_cmp(struct aa_profile *a, struct aa_profile *b) +{ + int res; + + AA_BUG(!a); + AA_BUG(!b); + AA_BUG(!a->ns); + AA_BUG(!b->ns); + AA_BUG(!a->base.hname); + AA_BUG(!b->base.hname); + + if (a == b || a->base.hname == b->base.hname) + return 0; + res = ns_cmp(a->ns, b->ns); + if (res) + return res; + + return strcmp(a->base.hname, b->base.hname); +} + +/** + * label_cmp - label comparision for set ordering + * @a: label to compare (NOT NULL) + * @b: label to compare (NOT NULL) + * + * Returns: <0 if a < b + * ==0 if a == b + * >0 if a > b + */ +static int label_cmp(struct aa_label *a, struct aa_label *b) +{ + int i; + + AA_BUG(!a); + AA_BUG(!b); + + if (a == b) + return 0; + + for (i = 0; i < a->size && i < b->size; i++) { + int res = profile_cmp(a->ent[i], b->ent[i]); + if (res != 0) + return res; + } + + return a->size - b->size; +} + +/** + * __aa_label_find - find label @l in label set + * @ls: set of labels to search (NOT NULL) + * @l: label to find (NOT NULL) + * + * Requires: @ls lock held + * caller to hold a valid ref on l + * + * Returns: unref counted @l if @l is in tree + * unref counted label that is equiv to @l in tree + * else NULL if @l or equiv is not in tree + */ +static struct aa_label *__aa_label_find(struct aa_labelset *ls, + struct aa_label *l) +{ + struct rb_node *node; + + AA_BUG(!ls); + AA_BUG(!l); + + node = ls->root.rb_node; + while (node) { + struct aa_label *this = rb_entry(node, struct aa_label, node); + int result = label_cmp(l, this); + + if (result < 0) + node = node->rb_left; + else if (result > 0) + node = node->rb_right; + else + return this; + } + + return NULL; +} + +/** + * aa_label_find - find label @l in label set + * @ls: set of labels to search (NOT NULL) + * @l: label to find (NOT NULL) + * + * Requires: caller to hold a valid ref on l + * + * Returns: refcounted @l if @l is in tree + * refcounted label that is equiv to @l in tree + * else NULL if @l or equiv is not in tree + */ +struct aa_label *aa_label_find(struct aa_labelset *ls, struct aa_label *l) +{ + struct aa_label *label; + unsigned long flags; + + AA_BUG(!ls); + AA_BUG(!l); + + read_lock_irqsave(&ls->lock, flags); + label = aa_get_label(__aa_label_find(ls, l)); + labelstats_inc(sread); + read_unlock_irqrestore(&ls->lock, flags); + + return label; +} + +/** + * __aa_label_insert - attempt to insert @l into a label set + * @ls: set of labels to insert @l into (NOT NULL) + * @l: new label to insert (NOT NULL) + * + * Requires: @ls->lock + * caller to hold a valid ref on l + * + * Returns: ref counted @l if successful in inserting @l + * else ref counted equivalent label that is already in the set. + */ +static struct aa_label *__aa_label_insert(struct aa_labelset *ls, + struct aa_label *l) +{ + struct rb_node **new, *parent = NULL; + + AA_BUG(!ls); + AA_BUG(!l); + AA_BUG(write_can_lock(&ls->lock)); + AA_BUG(l->flags & FLAG_IN_TREE); + + /* Figure out where to put new node */ + new = &ls->root.rb_node; + while (*new) { + struct aa_label *this = rb_entry(*new, struct aa_label, node); + int result = label_cmp(l, this); + + parent = *new; + if (result == 0) { + labelsetstats_inc(ls, existing); + return aa_get_label(this); + } else if (result < 0) + new = &((*new)->rb_left); + else /* (result > 0) */ + new = &((*new)->rb_right); + } + + /* Add new node and rebalance tree. */ + rb_link_node(&l->node, parent, new); + rb_insert_color(&l->node, &ls->root); + l->flags |= FLAG_IN_TREE; + labelsetstats_inc(ls, insert); + labelsetstats_inc(ls, intree); + + return aa_get_label(l); +} + +/** + * aa_label_insert - insert label @l into @ls or return existing label + * @ls - labelset to insert @l into + * @l - label to insert + * + * Requires: caller to hold a valid ref on l + * + * Returns: ref counted @l if successful in inserting @l + * else ref counted equivalent label that is already in the set + */ +struct aa_label *aa_label_insert(struct aa_labelset *ls, struct aa_label *l) +{ + struct aa_label *label; + unsigned long flags; + + AA_BUG(!ls); + AA_BUG(!l); + + /* check if label exists before taking lock */ + if (!label_invalid(l)) { + read_lock_irqsave(&ls->lock, flags); + label = aa_get_label(__aa_label_find(ls, l)); + read_unlock_irqrestore(&ls->lock, flags); + labelstats_inc(fread); + if (label) + return label; + } + + write_lock_irqsave(&ls->lock, flags); + label = __aa_label_insert(ls, l); + write_unlock_irqrestore(&ls->lock, flags); + + return label; +} + +/** + * aa_label_next_in_merge - find the next profile when merging @a and @b + * @I: label iterator + * @a: label to merge + * @b: label to merge + * + * Returns: next profile + * else null if no more profiles + */ +struct aa_profile *aa_label_next_in_merge(struct label_it *I, + struct aa_label *a, + struct aa_label *b) +{ + AA_BUG(!a); + AA_BUG(!b); + AA_BUG(!I); + AA_BUG(I->i < 0); + AA_BUG(I->i > a->size); + AA_BUG(I->j < 0); + AA_BUG(I->j > b->size); + + if (I->i < a->size) { + if (I->j < b->size) { + int res = profile_cmp(a->ent[I->i], b->ent[I->j]); + if (res > 0) + return b->ent[(I->j)++]; + if (res == 0) + (I->j)++; + } + + return a->ent[(I->i)++]; + } + + if (I->j < b->size) + return b->ent[(I->j)++]; + + return NULL; +} + +/** + * label_merge_cmp - cmp of @a merging with @b against @z for set ordering + * @a: label to merge then compare (NOT NULL) + * @b: label to merge then compare (NOT NULL) + * @z: label to compare merge against (NOT NULL) + * + * Assumes: using the most recent versions of @a, @b, and @z + * + * Returns: <0 if a < b + * ==0 if a == b + * >0 if a > b + */ +static int label_merge_cmp(struct aa_label *a, struct aa_label *b, + struct aa_label *z) +{ + struct aa_profile *p = NULL; + struct label_it i = { }; + int k; + + AA_BUG(!a); + AA_BUG(!b); + AA_BUG(!z); + + for (k = 0; + k < z->size && (p = aa_label_next_in_merge(&i, a, b)); + k++) { + int res = profile_cmp(p, z->ent[k]); + + if (res != 0) + return res; + } + + if (p) + return 1; + else if (k < z->size) + return -1; + return 0; +} + +/** + * aa_sort_and_merge_profiles - canonical sort and merge a list of profiles + * @n: number of refcounted profiles in the list (@n > 0) + * @ps: list of profiles to sort and merge + * + * Returns: the number of duplicates eliminated == references put + */ +static int aa_sort_and_merge_profiles(int n, struct aa_profile **ps) +{ + int i, dups = 0; + + AA_BUG(n < 1); + AA_BUG(!ps); + + /* label lists are usually small so just use insertion sort */ + for (i = 1; i < n; i++) { + struct aa_profile *tmp = ps[i]; + int pos, j; + + for (pos = i - 1 - dups; pos >= 0; pos--) { + int res = profile_cmp(ps[pos], tmp); + if (res == 0) { + aa_put_profile(tmp); + dups++; + goto continue_outer; + } else if (res < 0) + break; + } + pos++; + + for (j = i - dups; j > pos; j--) + ps[j] = ps[j - 1]; + ps[pos] = tmp; + continue_outer: + ; /* sigh empty statement required after the label */ + } + + return dups; +} + +/** + * __label_merge - create a new label by merging @a and @b + * @l: preallocated label to merge into (NOT NULL) + * @a: label to merge with @b (NOT NULL) + * @b: label to merge with @a (NOT NULL) + * + * Returns: ref counted label either l if merge is unique + * a if b is a subset of a + * b if a is a subset of b + * + * NOTE: will not use l if the merge results in l == a or b + * + * Must be used within labelset write lock to avoid racing with + * label invalidation. + */ +static struct aa_label *__label_merge(struct aa_label *l, struct aa_label *a, + struct aa_label *b) +{ + struct aa_profile *next; + struct label_it i; + int k = 0, invcount = 0; + + AA_BUG(!a); + AA_BUG(a->size < 0); + AA_BUG(!b); + AA_BUG(b->size < 0); + AA_BUG(!l); + AA_BUG(l->size != a->size + b->size); + + if (a == b) + return aa_get_label(a); + + label_for_each_in_merge(i, a, b, next) { + if (PROFILE_INVALID(next)) { + l->ent[k] = aa_get_newest_profile(next); + if (next->label.replacedby != + l->ent[k]->label.replacedby) + invcount++; + k++; + } else + l->ent[k++] = aa_get_profile(next); + } + /* set to actual size which is <= allocated len */ + l->size = k; + l->ent[k] = NULL; + + if (invcount) { + l->size -= aa_sort_and_merge_profiles(l->size, &l->ent[0]); + if (label_profiles_unconfined(l)) + l->flags |= FLAG_UNCONFINED; + } else { + /* merge is same as at least one of the labels */ + if (k == a->size) + return aa_get_label(a); + else if (k == b->size) + return aa_get_label(b); + + l->flags |= a->flags & b->flags & FLAG_UNCONFINED; + } + + return aa_get_label(l); +} + +/** + * labelset_of_merge - find into which labelset a merged label should be inserted + * @a: label to merge and insert + * @b: label to merge and insert + * + * Returns: labelset that the merged label should be inserted into + */ +static struct aa_labelset *labelset_of_merge(struct aa_label *a, struct aa_label *b) +{ + struct aa_namespace *nsa = labels_ns(a); + struct aa_namespace *nsb = labels_ns(b); + + if (ns_cmp(nsa, nsb) <= 0) + return &nsa->labels; + return &nsb->labels; +} + +/** + * __aa_label_find_merge - find label that is equiv to merge of @a and @b + * @ls: set of labels to search (NOT NULL) + * @a: label to merge with @b (NOT NULL) + * @b: label to merge with @a (NOT NULL) + * + * Requires: read_lock held + * + * Returns: unref counted label that is equiv to merge of @a and @b + * else NULL if merge of @a and @b is not in set + */ +static struct aa_label *__aa_label_find_merge(struct aa_labelset *ls, + struct aa_label *a, + struct aa_label *b) +{ + struct rb_node *node; + + AA_BUG(!ls); + AA_BUG(!a); + AA_BUG(!b); + + if (a == b) + return __aa_label_find(ls, a); + + node = ls->root.rb_node; + while (node) { + struct aa_label *this = container_of(node, struct aa_label, + node); + int result = label_merge_cmp(a, b, this); + + if (result < 0) + node = node->rb_left; + else if (result > 0) + node = node->rb_right; + else + return this; + } + + return NULL; +} + + +/** + * __aa_label_find_merge - find label that is equiv to merge of @a and @b + * @a: label to merge with @b (NOT NULL) + * @b: label to merge with @a (NOT NULL) + * + * Requires: labels be fully constructed with a valid ns + * + * Returns: ref counted label that is equiv to merge of @a and @b + * else NULL if merge of @a and @b is not in set + */ +struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b) +{ + struct aa_labelset *ls; + struct aa_label *label, *ar = NULL, *br = NULL; + unsigned long flags; + + AA_BUG(!a); + AA_BUG(!b); + + ls = labelset_of_merge(a, b); + read_lock_irqsave(&ls->lock, flags); + if (label_invalid(a)) + a = ar = aa_get_newest_label(a); + if (label_invalid(b)) + b = br = aa_get_newest_label(b); + label = aa_get_label(__aa_label_find_merge(ls, a, b)); + read_unlock_irqrestore(&ls->lock, flags); + aa_put_label(ar); + aa_put_label(br); + labelsetstats_inc(ls, msread); + + return label; +} + +/** + * aa_label_merge - attempt to insert new merged label of @a and @b + * @ls: set of labels to insert label into (NOT NULL) + * @a: label to merge with @b (NOT NULL) + * @b: label to merge with @a (NOT NULL) + * @gfp: memory allocation type + * + * Requires: caller to hold valid refs on @a and @b + * labels be fully constructed with a valid ns + * + * Returns: ref counted new label if successful in inserting merge of a & b + * else ref counted equivalent label that is already in the set. + * else NULL if could not create label (-ENOMEM) + */ +struct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b, + gfp_t gfp) +{ + struct aa_label *label = NULL; + struct aa_labelset *ls; + unsigned long flags; + + AA_BUG(!a); + AA_BUG(!b); + + if (a == b) + return aa_get_label(a); + + ls = labelset_of_merge(a, b); + + /* TODO: enable when read side is lockless + * check if label exists before taking locks + if (!label_invalid(a) && !label_invalid(b)) + label = aa_label_find_merge(a, b); + */ + + if (!label) { + struct aa_label *new, *l, *ar = NULL, *br = NULL; + + /* could use label_merge_len(a, b), but requires double + * comparison for small savings + */ + new = aa_label_alloc(a->size + b->size, gfp); + if (!new) + return NULL; + + write_lock_irqsave(&ls->lock, flags); + if (label_invalid(a)) + a = ar = aa_get_newest_label(a); + if (label_invalid(b)) + b = br = aa_get_newest_label(b); + l = __label_merge(new, a, b); + if (l != new) { + /* new may not be fully setup so no put_label */ + aa_label_free(new); + new = NULL; + } + if (!(l->flags & FLAG_IN_TREE)) + label = __aa_label_insert(ls, l); + write_unlock_irqrestore(&ls->lock, flags); + aa_put_label(new); + aa_put_label(l); + aa_put_label(ar); + aa_put_label(br); + } + + return label; +} + +/** + * aa_update_label_name - update a label to have a stored name + * @ns: ns being viewed from (NOT NULL) + * @label: label to update (NOT NULL) + * @gfp: type of memory allocation + * + * Requires: labels_set(label) not locked in caller + * + * note: only updates the label name if it does not have a name already + * and if it is in the labelset + */ +bool aa_update_label_name(struct aa_namespace *ns, struct aa_label *label, + gfp_t gfp) +{ + struct aa_labelset *ls; + unsigned long flags; + char __counted *name; + bool res = false; + + AA_BUG(!ns); + AA_BUG(!label); + + if (label->hname || labels_ns(label) != ns) + return res; + + if (aa_label_acntsprint(&name, ns, label, false, gfp) == -1) + return res; + + ls = labels_set(label); + write_lock_irqsave(&ls->lock, flags); + if (!label->hname && label->flags & FLAG_IN_TREE) { + label->hname = name; + res = true; + } else + aa_put_str(name); + write_unlock_irqrestore(&ls->lock, flags); + + return res; +} + +/* cached label name is present and visible + * @label->hname only exists if label is namespace hierachical */ +static inline bool label_name_visible(struct aa_namespace *ns, + struct aa_label *label) +{ + if (label->hname && labels_ns(label) == ns) + return true; + + return false; +} + +/* helper macro for snprint routines */ +#define update_for_len(total, len, size, str) \ +do { \ + AA_BUG(len < 0); \ + total += len; \ + len = min(len, size); \ + size -= len; \ + str += len; \ +} while (0) + +/** + * aa_modename_snprint - print the mode name of a profile or label to a buffer + * @str: buffer to write to (MAY BE NULL if @size == 0) + * @size: size of buffer + * @ns: namespace profile is being viewed from (NOT NULL) + * @label: label to print the mode of (NOT NULL) + * + * Returns: size of name written or would be written if larger than + * available buffer + * + * Note: will print every mode name visible (mode1)(mode2)(mode3) + * this is likely not what is desired for most interfaces + * use aa_mode_snprint to get the standard mode format + */ +static int aa_modename_snprint(char *str, size_t size, struct aa_namespace *ns, + struct aa_label *label) +{ + struct aa_profile *profile; + struct label_it i; + int total = 0; + size_t len; + + label_for_each(i, label, profile) { + const char *modestr; + if (!aa_ns_visible(ns, profile->ns)) + continue; + /* no mode for 'unconfined' */ + if (profile_unconfined(profile) && + profile == profile->ns->unconfined) + break; + modestr = aa_profile_mode_names[profile->mode]; + len = snprintf(str, size, "(%s)", modestr); + update_for_len(total, len, size, str); + } + + return total; +} + +/** + * aa_modechr_snprint - print the mode chr of a profile or labels to a buffer + * @str: buffer to write to (MAY BE NULL if @size == 0) + * @size: size of buffer + * @ns: namespace profile is being viewed from (NOT NULL) + * @label: label to print the mode chr of (NOT NULL) + * + * Returns: size of mode string written or would be written if larger than + * available buffer + * + * Note: will print the chr of every visible profile (123) + * this is likely not what is desired for most interfaces + * use aa_mode_snprint to get the standard mode format + */ +static int aa_modechr_snprint(char *str, size_t size, struct aa_namespace *ns, + struct aa_label *label) +{ + struct aa_profile *profile; + struct label_it i; + int total = 0; + size_t len; + + len = snprintf(str, size, "("); + update_for_len(total, len, size, str); + label_for_each(i, label, profile) { + const char *modestr; + if (!aa_ns_visible(ns, profile->ns)) + continue; + modestr = aa_profile_mode_names[profile->mode]; + /* just the first char of the modestr */ + len = snprintf(str, size, "%c", *modestr); + update_for_len(total, len, size, str); + } + len = snprintf(str, size, ")"); + update_for_len(total, len, size, str); + + return total; +} + +/** + * aa_mode_snprint - print the mode of a profile or label to a buffer + * @str: buffer to write to (MAY BE NULL if @size == 0) + * @size: size of buffer + * @ns: namespace profile is being viewed from (NOT NULL) + * @label: label to print the mode of (NOT NULL) + * @count: number of label entries to be printed (<= 0 if unknown) + * + * Returns: size of name written or would be written if larger than + * available buffer + * + * Note: dynamically switches between mode name, and mode char format as + * appropriate + * will not print anything if the label is not visible + */ +static int aa_mode_snprint(char *str, size_t size, struct aa_namespace *ns, + struct aa_label *label, int count) +{ + struct aa_profile *profile; + struct label_it i; + + if (count <= 0) { + count = 0; + label_for_each(i, label, profile) { + if (aa_ns_visible(ns, profile->ns)) + count++; + } + } + + if (count == 0) + return 0; + + if (count == 1) + return aa_modename_snprint(str, size, ns, label); + + return aa_modechr_snprint(str, size, ns, label); +} + +/** + * aa_snprint_profile - print a profile name to a buffer + * @str: buffer to write to. (MAY BE NULL if @size == 0) + * @size: size of buffer + * @ns: namespace profile is being viewed from (NOT NULL) + * @profile: profile to view (NOT NULL) + * @mode: whether to include the mode string + * + * Returns: size of name written or would be written if larger than + * available buffer + * + * Note: will not print anything if the profile is not visible + */ +int aa_profile_snprint(char *str, size_t size, struct aa_namespace *ns, + struct aa_profile *profile, bool mode) +{ + const char *ns_name = aa_ns_name(ns, profile->ns); + + AA_BUG(!str && size != 0); + AA_BUG(!ns); + AA_BUG(!profile); + + if (!ns_name) + return 0; + + if (mode && profile != profile->ns->unconfined) { + const char *modestr = aa_profile_mode_names[profile->mode]; + if (strlen(ns_name)) + return snprintf(str, size, ":%s://%s (%s)", ns_name, + profile->base.hname, modestr); + return snprintf(str, size, "%s (%s)", profile->base.hname, + modestr); + } + + if (strlen(ns_name)) + return snprintf(str, size, ":%s://%s", ns_name, + profile->base.hname); + return snprintf(str, size, "%s", profile->base.hname); +} + +/** + * aa_label_snprint - print a label name to a string buffer + * @str: buffer to write to. (MAY BE NULL if @size == 0) + * @size: size of buffer + * @ns: namespace profile is being viewed from (NOT NULL) + * @label: label to view (NOT NULL) + * @mode: whether to include the mode string + * + * Returns: size of name written or would be written if larger than + * available buffer + * + * Note: labels do not have to be strictly hierarchical to the ns as + * objects may be shared across different namespaces and thus + * pickup labeling from each ns. If a particular part of the + * label is not visible it will just be excluded. And if none + * of the label is visible "---" will be used. + */ +int aa_label_snprint(char *str, size_t size, struct aa_namespace *ns, + struct aa_label *label, bool mode) +{ + struct aa_profile *profile; + struct label_it i; + int count = 0, total = 0; + size_t len; + + AA_BUG(!str && size != 0); + AA_BUG(!ns); + AA_BUG(!label); + + label_for_each(i, label, profile) { + if (aa_ns_visible(ns, profile->ns)) { + if (count > 0) { + len = snprintf(str, size, "//&"); + update_for_len(total, len, size, str); + } + len = aa_profile_snprint(str, size, ns, profile, false); + update_for_len(total, len, size, str); + count++; + } + } + + if (count == 0) + return snprintf(str, size, aa_hidden_ns_name); + + /* count == 1 && ... is for backwards compat where the mode + * is not displayed for 'unconfined' in the current ns + */ + if (mode && + !(count == 1 && labels_ns(label) == ns && + labels_profile(label) == ns->unconfined)) { + len = snprintf(str, size, " "); + update_for_len(total, len, size, str); + len = aa_mode_snprint(str, size, ns, label, count); + update_for_len(total, len, size, str); + } + + return total; +} +#undef update_for_len + +/** + * aa_label_asprint - allocate a string buffer and print label into it + * @strp: Returns - the allocated buffer with the label name. (NOT NULL) + * @ns: namespace profile is being viewed from (NOT NULL) + * @label: label to view (NOT NULL) + * @mode: whether to include the mode string + * @gfp: kernel memory allocation type + * + * Returns: size of name written or would be written if larger than + * available buffer + */ +int aa_label_asprint(char **strp, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp) +{ + int size; + + AA_BUG(!strp); + AA_BUG(!ns); + AA_BUG(!label); + + size = aa_label_snprint(NULL, 0, ns, label, mode); + if (size < 0) + return size; + + *strp = kmalloc(size + 1, gfp); + if (!*strp) + return -ENOMEM; + return aa_label_snprint(*strp, size + 1, ns, label, mode); +} + +/** + * aa_label_acntsprint - allocate a __counted string buffer and print label + * @strp: buffer to write to. (MAY BE NULL if @size == 0) + * @ns: namespace profile is being viewed from (NOT NULL) + * @label: label to view (NOT NULL) + * @mode: whether to include the mode string + * @gfp: kernel memory allocation type + * + * Returns: size of name written or would be written if larger than + * available buffer + */ +int aa_label_acntsprint(char __counted **strp, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp) +{ + int size; + + AA_BUG(!strp); + AA_BUG(!ns); + AA_BUG(!label); + + size = aa_label_snprint(NULL, 0, ns, label, mode); + if (size < 0) + return size; + + *strp = aa_str_alloc(size + 1, gfp); + if (!*strp) + return -ENOMEM; + return aa_label_snprint(*strp, size + 1, ns, label, mode); +} + + +void aa_label_audit(struct audit_buffer *ab, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp) +{ + const char *str; + char *name = NULL; + int len; + + AA_BUG(!ab); + AA_BUG(!ns); + AA_BUG(!label); + + if (label_name_visible(ns, label)) { + str = (char *) label->hname; + len = strlen(str); + } else { + labelstats_inc(audit_name_alloc); + len = aa_label_asprint(&name, ns, label, mode, gfp); + if (len == -1) { + labelstats_inc(audit_name_fail); + AA_DEBUG("label print error"); + return; + } + str = name; + } + + if (audit_string_contains_control(str, len)) + audit_log_n_hex(ab, str, len); + else + audit_log_n_string(ab, str, len); + + kfree(name); +} + +void aa_label_seq_print(struct seq_file *f, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp) +{ + AA_BUG(!f); + AA_BUG(!ns); + AA_BUG(!label); + + if (!label_name_visible(ns, label)) { + char *str; + int len; + + labelstats_inc(seq_print_name_alloc); + len = aa_label_asprint(&str, ns, label, mode, gfp); + if (len == -1) { + labelstats_inc(seq_print_name_fail); + AA_DEBUG("label print error"); + return; + } + seq_printf(f, "%s", str); + kfree(str); + } else + seq_printf(f, "%s", label->hname); +} + +void aa_label_printk(struct aa_namespace *ns, struct aa_label *label, bool mode, + gfp_t gfp) +{ + char *str; + int len; + + AA_BUG(!ns); + AA_BUG(!label); + + if (!label_name_visible(ns, label)) { + labelstats_inc(printk_name_alloc); + len = aa_label_asprint(&str, ns, label, mode, gfp); + if (len == -1) { + labelstats_inc(printk_name_fail); + AA_DEBUG("label print error"); + return; + } + printk("%s", str); + kfree(str); + } else + printk("%s", label->hname); +} + + +static int label_count_str_entries(const char *str) +{ + const char *split; + int count = 1; + + AA_BUG(!str); + + for (split = strstr(str, "//&"); split; split = strstr(str, "//&")) { + count++; + str = split + 3; + } + + return count; +} + +/** + * aa_label_parse - parse, validate and convert a text string to a label + * @base: base namespace to use for lookups (NOT NULL) + * @str: null terminated text string (NOT NULL) + * @gfp: allocation type + * + * Returns: the matching refcounted label if present + * else ERRPTR + */ +struct aa_label *aa_label_parse(struct aa_namespace *base, char *str, gfp_t gfp) +{ + struct aa_label *l, *label; + int i, len; + char *split; + + AA_BUG(!base); + AA_BUG(!str); + + len = label_count_str_entries(str); + label = aa_label_alloc(len, gfp); + if (!label) + return ERR_PTR(-ENOMEM); + + for (split = strstr(str, "//&"), i = 0; split && i < len; i++) { + *split = 0; + label->ent[i] = aa_fqlookupn_profile(base, str, split - str); + if (!label->ent[i]) + goto fail; + str = split + 3; + split = strstr(str, "//&"); + } + label->ent[i] = aa_fqlookupn_profile(base, str, strlen(str)); + if (!label->ent[i]) + goto fail; + + i = aa_sort_and_merge_profiles(len, &label->ent[0]); + label->size -= i; + label->ent[label->size] = NULL; + + if (label_profiles_unconfined(label)) + label->flags = FLAG_UNCONFINED; + + l = aa_label_find(labels_set(label), label); + if (!l) + goto fail; + aa_put_label(label); + return l; + +fail: + aa_label_free(label); + return ERR_PTR(-ENOENT); +} + + +/** + * aa_labelset_destroy - remove all labels from the label set + * @ls: label set to cleanup (NOT NULL) + * + * Labels that are removed from the set may still exist beyond the set + * being destroyed depending on their reference counting + */ +void aa_labelset_destroy(struct aa_labelset *ls) +{ + struct rb_node *node; + unsigned long flags; + + AA_BUG(!ls); + + write_lock_irqsave(&ls->lock, flags); + for (node = rb_first(&ls->root); node; node = rb_first(&ls->root)) { + struct aa_label *this = rb_entry(node, struct aa_label, node); + __aa_label_remove(ls, this); + } + write_unlock_irqrestore(&ls->lock, flags); +} + +/* + * @ls: labelset to init (NOT NULL) + */ +void aa_labelset_init(struct aa_labelset *ls) +{ + AA_BUG(!ls); + + rwlock_init(&ls->lock); + ls->root = RB_ROOT; + labelstats_init(&ls); +} + +static struct aa_label *labelset_next_invalid(struct aa_labelset *ls) +{ + struct aa_label *label; + struct rb_node *node; + unsigned long flags; + + AA_BUG(!ls); + + read_lock_irqsave(&ls->lock, flags); + + __labelset_for_each(ls, node) { + struct aa_profile *p; + struct label_it i; + + label = rb_entry(node, struct aa_label, node); + if (label_invalid(label)) + goto out; + + label_for_each(i, label, p) { + if (PROFILE_INVALID(p)) + goto out; + } + } + label = NULL; + +out: + aa_get_label(label); + read_unlock_irqrestore(&ls->lock, flags); + + return label; +} + +/** + * __label_update - insert updated version of @label into labelset + * @label - the label to update/repace + * + * Returns: new label that is up to date + * else NULL on failure + * + * Requires: @ns lock be held + * + * Note: worst case is the stale @label does not get updated and has + * to be updated at a later time. + */ +static struct aa_label *__label_update(struct aa_label *label) +{ + struct aa_label *l, *tmp; + struct aa_profile *p; + struct label_it i; + int invcount = 0; + + AA_BUG(!label); + AA_BUG(!mutex_is_locked(&labels_ns(label)->lock)); + + l = aa_label_alloc(label->size, GFP_KERNEL); + if (!l) + return NULL; + + if (!label->replacedby) { + struct aa_replacedby *r = aa_alloc_replacedby(l); + if (!r) { + aa_put_label(l); + return NULL; + } + label->replacedby = r; + } + /* circular ref only broken by replace or remove */ + l->replacedby = aa_get_replacedby(label->replacedby); + __aa_update_replacedby(label, l); + + label_for_each(i, label, p) { + if (PROFILE_INVALID(p)) { + l->ent[i.i] = aa_get_newest_profile(p); + if (&l->ent[i.i]->label.replacedby != &p->label.replacedby) + invcount++; + } else + l->ent[i.i] = aa_get_profile(p); + } + + /* updated label invalidated by being removed/renamed from labelset */ + if (invcount) { + l->size -= aa_sort_and_merge_profiles(l->size, &l->ent[0]); + + if (labels_set(label) == labels_set(l)) { + struct aa_labelset *ls = labels_set(label); + /* should not fail, as done within ns lock */ + tmp = aa_label_remove_and_insert(ls, label, l); + AA_BUG(tmp != l); + aa_put_label(tmp); + } else { + /* should not fail, as done within ns lock */ + aa_label_remove(labels_set(label), label); + tmp = aa_label_insert(labels_set(l), l); + AA_BUG(tmp != l); + aa_put_label(tmp); + } + } else { + AA_BUG(labels_ns(label) != labels_ns(l)); + aa_label_replace(labels_set(label), label, l); + } + + return l; +} + +/** + * __labelset_update - invalidate and update labels in @ns + * @ns: namespace to update and invalidate labels in (NOT NULL) + * + * Requires: @ns lock be held + * + * Walk the labelset ensuring that all labels are up to date and valid + * Any label that is outdated is replaced and by an updated version + * invalidated and removed from the tree. + * + * If failures happen due to memory pressures then stale labels will + * be left in place until the next pass. + */ +static void __labelset_update(struct aa_namespace *ns) +{ + struct aa_label *label; + + AA_BUG(!ns); + AA_BUG(!mutex_is_locked(&ns->lock)); + + do { + label = labelset_next_invalid(&ns->labels); + if (label) { + struct aa_label *l; + l = __label_update(label); + aa_put_label(l); + aa_put_label(label); + } + } while (label); +} + +/** + * __aa_labelset_invalidate_all - invalidate labels in @ns and below + * @ns: ns to start invalidation at (NOT NULL) + * + * Requires: @ns lock be held + * + * Invalidates labels based on @p in @ns and any children namespaces. +*/ +void __aa_labelset_update_all(struct aa_namespace *ns) +{ + struct aa_namespace *child; + + AA_BUG(!ns); + AA_BUG(!mutex_is_locked(&ns->lock)); + + __labelset_update(ns); + + list_for_each_entry(child, &ns->sub_ns, base.list) { + mutex_lock(&child->lock); + __aa_labelset_update_all(child); + mutex_unlock(&child->lock); + } +} --- linux-3.13.0.orig/security/apparmor/context.c +++ linux-3.13.0/security/apparmor/context.c @@ -14,9 +14,9 @@ * * * AppArmor sets confinement on every task, via the the aa_task_cxt and - * the aa_task_cxt.profile, both of which are required and are not allowed + * the aa_task_cxt.label, both of which are required and are not allowed * to be NULL. The aa_task_cxt is not reference counted and is unique - * to each cred (which is reference count). The profile pointed to by + * to each cred (which is reference count). The label pointed to by * the task_cxt is reference counted. * * TODO @@ -47,9 +47,9 @@ void aa_free_task_context(struct aa_task_cxt *cxt) { if (cxt) { - aa_put_profile(cxt->profile); - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); + aa_put_label(cxt->label); + aa_put_label(cxt->previous); + aa_put_label(cxt->onexec); kzfree(cxt); } @@ -63,41 +63,41 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old) { *new = *old; - aa_get_profile(new->profile); - aa_get_profile(new->previous); - aa_get_profile(new->onexec); + aa_get_label(new->label); + aa_get_label(new->previous); + aa_get_label(new->onexec); } /** - * aa_get_task_profile - Get another task's profile + * aa_get_task_label - Get another task's label * @task: task to query (NOT NULL) * - * Returns: counted reference to @task's profile + * Returns: counted reference to @task's label */ -struct aa_profile *aa_get_task_profile(struct task_struct *task) +struct aa_label *aa_get_task_label(struct task_struct *task) { - struct aa_profile *p; + struct aa_label *p; rcu_read_lock(); - p = aa_get_profile(__aa_task_profile(task)); + p = aa_get_newest_label(__aa_task_label(task)); rcu_read_unlock(); return p; } /** - * aa_replace_current_profile - replace the current tasks profiles - * @profile: new profile (NOT NULL) + * aa_replace_current_label - replace the current tasks label + * @label: new label (NOT NULL) * * Returns: 0 or error on failure */ -int aa_replace_current_profile(struct aa_profile *profile) +int aa_replace_current_label(struct aa_label *label) { struct aa_task_cxt *cxt = current_cxt(); struct cred *new; - BUG_ON(!profile); + BUG_ON(!label); - if (cxt->profile == profile) + if (cxt->label == label) return 0; new = prepare_creds(); @@ -105,19 +105,15 @@ return -ENOMEM; cxt = cred_cxt(new); - if (unconfined(profile) || (cxt->profile->ns != profile->ns)) - /* if switching to unconfined or a different profile namespace + if (unconfined(label) || (labels_ns(cxt->label) != labels_ns(label))) + /* if switching to unconfined or a different label namespace * clear out context state */ aa_clear_task_cxt_trans(cxt); - /* be careful switching cxt->profile, when racing replacement it - * is possible that cxt->profile->replacedby->profile is the reference - * keeping @profile valid, so make sure to get its reference before - * dropping the reference on cxt->profile */ - aa_get_profile(profile); - aa_put_profile(cxt->profile); - cxt->profile = profile; + aa_get_label(label); + aa_put_label(cxt->label); + cxt->label = label; commit_creds(new); return 0; @@ -125,11 +121,11 @@ /** * aa_set_current_onexec - set the tasks change_profile to happen onexec - * @profile: system profile to set at exec (MAYBE NULL to clear value) + * @label: system label to set at exec (MAYBE NULL to clear value) * * Returns: 0 or error on failure */ -int aa_set_current_onexec(struct aa_profile *profile) +int aa_set_current_onexec(struct aa_label *label) { struct aa_task_cxt *cxt; struct cred *new = prepare_creds(); @@ -137,9 +133,9 @@ return -ENOMEM; cxt = cred_cxt(new); - aa_get_profile(profile); - aa_put_profile(cxt->onexec); - cxt->onexec = profile; + aa_get_label(label); + aa_put_label(cxt->onexec); + cxt->onexec = label; commit_creds(new); return 0; @@ -147,7 +143,7 @@ /** * aa_set_current_hat - set the current tasks hat - * @profile: profile to set as the current hat (NOT NULL) + * @label: label to set as the current hat (NOT NULL) * @token: token value that must be specified to change from the hat * * Do switch of tasks hat. If the task is currently in a hat @@ -155,29 +151,29 @@ * * Returns: 0 or error on failure */ -int aa_set_current_hat(struct aa_profile *profile, u64 token) +int aa_set_current_hat(struct aa_label *label, u64 token) { struct aa_task_cxt *cxt; struct cred *new = prepare_creds(); if (!new) return -ENOMEM; - BUG_ON(!profile); + BUG_ON(!label); cxt = cred_cxt(new); if (!cxt->previous) { /* transfer refcount */ - cxt->previous = cxt->profile; + cxt->previous = cxt->label; cxt->token = token; } else if (cxt->token == token) { - aa_put_profile(cxt->profile); + aa_put_label(cxt->label); } else { /* previous_profile && cxt->token != token */ abort_creds(new); return -EACCES; } - cxt->profile = aa_get_newest_profile(profile); + cxt->label = aa_get_newest_label(label); /* clear exec on switching context */ - aa_put_profile(cxt->onexec); + aa_put_label(cxt->onexec); cxt->onexec = NULL; commit_creds(new); @@ -185,15 +181,15 @@ } /** - * aa_restore_previous_profile - exit from hat context restoring the profile + * aa_restore_previous_label - exit from hat context restoring previous label * @token: the token that must be matched to exit hat context * - * Attempt to return out of a hat to the previous profile. The token + * Attempt to return out of a hat to the previous label. The token * must match the stored token value. * * Returns: 0 or error of failure */ -int aa_restore_previous_profile(u64 token) +int aa_restore_previous_label(u64 token) { struct aa_task_cxt *cxt; struct cred *new = prepare_creds(); @@ -205,15 +201,15 @@ abort_creds(new); return -EACCES; } - /* ignore restores when there is no saved profile */ + /* ignore restores when there is no saved label */ if (!cxt->previous) { abort_creds(new); return 0; } - aa_put_profile(cxt->profile); - cxt->profile = aa_get_newest_profile(cxt->previous); - BUG_ON(!cxt->profile); + aa_put_label(cxt->label); + cxt->label = aa_get_newest_label(cxt->previous); + BUG_ON(!cxt->label); /* clear exec && prev information when restoring to previous context */ aa_clear_task_cxt_trans(cxt); --- linux-3.13.0.orig/security/apparmor/path.c +++ linux-3.13.0/security/apparmor/path.c @@ -43,7 +43,6 @@ * d_namespace_path - lookup a name associated with a given path * @path: path to lookup (NOT NULL) * @buf: buffer to store path to (NOT NULL) - * @buflen: length of @buf * @name: Returns - pointer for start of path name with in @buf (NOT NULL) * @flags: flags controlling path lookup * @@ -53,12 +52,14 @@ * When no error the path name is returned in @name which points to * to a position in @buf */ -static int d_namespace_path(struct path *path, char *buf, int buflen, - char **name, int flags) +static int d_namespace_path(struct path *path, char *buf, char **name, + int flags) { char *res; int error = 0; int connected = 1; + int isdir = (flags & PATH_IS_DIR) ? 1 : 0; + int buflen = aa_g_path_max - isdir; if (path->mnt->mnt_flags & MNT_INTERNAL) { /* it's not mounted anywhere */ @@ -73,9 +74,11 @@ /* TODO: convert over to using a per namespace * control instead of hard coded /proc */ - return prepend(name, *name - buf, "/proc", 5); + error = prepend(name, *name - buf, "/proc", 5); + goto out; } - return 0; + + goto out; } /* resolve paths relative to chroot?*/ @@ -94,8 +97,11 @@ * be returned. */ if (!res || IS_ERR(res)) { - if (PTR_ERR(res) == -ENAMETOOLONG) - return -ENAMETOOLONG; + if (PTR_ERR(res) == -ENAMETOOLONG) { + error = -ENAMETOOLONG; + *name = buf; + goto out; + } connected = 0; res = dentry_path_raw(path->dentry, buf, buflen); if (IS_ERR(res)) { @@ -145,51 +151,21 @@ } out: - return error; -} - -/** - * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended - * @path: path to get name for (NOT NULL) - * @flags: flags controlling path lookup - * @buffer: buffer to put name in (NOT NULL) - * @size: size of buffer - * @name: Returns - contains position of path name in @buffer (NOT NULL) - * - * Returns: %0 else error on failure - */ -static int get_name_to_buffer(struct path *path, int flags, char *buffer, - int size, char **name, const char **info) -{ - int adjust = (flags & PATH_IS_DIR) ? 1 : 0; - int error = d_namespace_path(path, buffer, size - adjust, name, flags); - - if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0') - /* - * Append "/" to the pathname. The root directory is a special - * case; it already ends in slash. - */ - strcpy(&buffer[size - 2], "/"); - - if (info && error) { - if (error == -ENOENT) - *info = "Failed name lookup - deleted entry"; - else if (error == -EACCES) - *info = "Failed name lookup - disconnected path"; - else if (error == -ENAMETOOLONG) - *info = "Failed name lookup - name too long"; - else - *info = "Failed name lookup"; - } + /* + * Append "/" to the pathname. The root directory is a special + * case; it already ends in slash. + */ + if (!error && isdir && ((*name)[1] != '\0' || (*name)[0] != '/')) + strcpy(&buf[aa_g_path_max - 2], "/"); return error; } /** - * aa_path_name - compute the pathname of a file + * aa_path_name - get the pathname to a buffer ensure dir / is appended * @path: path the file (NOT NULL) * @flags: flags controlling path name generation - * @buffer: buffer that aa_get_name() allocated (NOT NULL) + * @buffer: buffer to put name in (NOT NULL) * @name: Returns - the generated path name if !error (NOT NULL) * @info: Returns - information on why the path lookup failed (MAYBE NULL) * @@ -204,33 +180,24 @@ * * Returns: %0 else error code if could retrieve name */ -int aa_path_name(struct path *path, int flags, char **buffer, const char **name, +int aa_path_name(struct path *path, int flags, char *buffer, const char **name, const char **info) { - char *buf, *str = NULL; - int size = 256; - int error; - - *name = NULL; - *buffer = NULL; - for (;;) { - /* freed by caller */ - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - error = get_name_to_buffer(path, flags, buf, size, &str, info); - if (error != -ENAMETOOLONG) - break; - - kfree(buf); - size <<= 1; - if (size > aa_g_path_max) - return -ENAMETOOLONG; - *info = NULL; + char *str = NULL; + int error = d_namespace_path(path, buffer, &str, flags); + + + if (info && error) { + if (error == -ENOENT) + *info = "Failed name lookup - deleted entry"; + else if (error == -EACCES) + *info = "Failed name lookup - disconnected path"; + else if (error == -ENAMETOOLONG) + *info = "Failed name lookup - name too long"; + else + *info = "Failed name lookup"; } - *buffer = buf; - *name = str; + *name = str; return error; } --- linux-3.13.0.orig/security/apparmor/include/net.h +++ linux-3.13.0/security/apparmor/include/net.h @@ -0,0 +1,54 @@ +/* + * AppArmor security module + * + * This file contains AppArmor network mediation definitions. + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2012 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __AA_NET_H +#define __AA_NET_H + +#include + +#include "apparmorfs.h" +#include "label.h" + +struct aa_sk_cxt { + struct aa_label *label; + struct aa_label *peer; +}; + +#define SK_CXT(X) (X)->sk_security +#define SOCK_CXT(X) SOCK_INODE(X)->i_security + +/* struct aa_net - network confinement data + * @allowed: basic network families permissions + * @audit_network: which network permissions to force audit + * @quiet_network: which network permissions to quiet rejects + */ +struct aa_net { + u16 allow[AF_MAX]; + u16 audit[AF_MAX]; + u16 quiet[AF_MAX]; +}; + + +extern struct aa_fs_entry aa_fs_entry_network[]; + +extern int aa_net_perm(int op, struct aa_label *label, u16 family, + int type, int protocol, struct sock *sk); +extern int aa_revalidate_sk(int op, struct sock *sk); + +static inline void aa_free_net_rules(struct aa_net *new) +{ + /* NOP */ +} + +#endif /* __AA_NET_H */ --- linux-3.13.0.orig/security/apparmor/include/context.h +++ linux-3.13.0/security/apparmor/include/context.h @@ -19,59 +19,29 @@ #include #include +#include "label.h" #include "policy.h" #define cred_cxt(X) (X)->security #define current_cxt() cred_cxt(current_cred()) - -/* struct aa_file_cxt - the AppArmor context the file was opened in - * @perms: the permission the file was opened with - * - * The file_cxt could currently be directly stored in file->f_security - * as the profile reference is now stored in the f_cred. However the - * cxt struct will expand in the future so we keep the struct. - */ -struct aa_file_cxt { - u16 allow; -}; - -/** - * aa_alloc_file_context - allocate file_cxt - * @gfp: gfp flags for allocation - * - * Returns: file_cxt or NULL on failure - */ -static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp) -{ - return kzalloc(sizeof(struct aa_file_cxt), gfp); -} - -/** - * aa_free_file_context - free a file_cxt - * @cxt: file_cxt to free (MAYBE_NULL) - */ -static inline void aa_free_file_context(struct aa_file_cxt *cxt) -{ - if (cxt) - kzfree(cxt); -} +#define current_ns() labels_ns(__aa_current_label()) /** * struct aa_task_cxt - primary label for confined tasks - * @profile: the current profile (NOT NULL) - * @exec: profile to transition to on next exec (MAYBE NULL) - * @previous: profile the task may return to (MAYBE NULL) - * @token: magic value the task must know for returning to @previous_profile + * @label: the current label (NOT NULL) + * @exec: label to transition to on next exec (MAYBE NULL) + * @previous: label the task may return to (MAYBE NULL) + * @token: magic value the task must know for returning to @previous * - * Contains the task's current profile (which could change due to + * Contains the task's current label (which could change due to * change_hat). Plus the hat_magic needed during change_hat. * * TODO: make so a task can be confined by a stack of contexts */ struct aa_task_cxt { - struct aa_profile *profile; - struct aa_profile *onexec; - struct aa_profile *previous; + struct aa_label *label; + struct aa_label *onexec; + struct aa_label *previous; u64 token; }; @@ -79,39 +49,50 @@ void aa_free_task_context(struct aa_task_cxt *cxt); void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old); -int aa_replace_current_profile(struct aa_profile *profile); -int aa_set_current_onexec(struct aa_profile *profile); -int aa_set_current_hat(struct aa_profile *profile, u64 token); -int aa_restore_previous_profile(u64 cookie); -struct aa_profile *aa_get_task_profile(struct task_struct *task); +int aa_replace_current_label(struct aa_label *label); +int aa_set_current_onexec(struct aa_label *label); +int aa_set_current_hat(struct aa_label *label, u64 token); +int aa_restore_previous_label(u64 cookie); +struct aa_label *aa_get_task_label(struct task_struct *task); /** - * aa_cred_profile - obtain cred's profiles - * @cred: cred to obtain profiles from (NOT NULL) + * aa_cred_label - obtain cred's label + * @cred: cred to obtain label from (NOT NULL) * - * Returns: confining profile + * Returns: confining label * * does NOT increment reference count */ -static inline struct aa_profile *aa_cred_profile(const struct cred *cred) +static inline struct aa_label *aa_cred_label(const struct cred *cred) { struct aa_task_cxt *cxt = cred_cxt(cred); - BUG_ON(!cxt || !cxt->profile); - return cxt->profile; + BUG_ON(!cxt || !cxt->label); + return cxt->label; +} + +/** + * aa_get_newest_cred_label - obtain the newest version of the label on a cred + * @cred: cred to obtain label from (NOT NULL) + * + * Returns: newest version of confining label + */ +static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred) +{ + return aa_get_newest_label(aa_cred_label(cred)); } /** - * __aa_task_profile - retrieve another task's profile + * __aa_task_label - retrieve another task's label * @task: task to query (NOT NULL) * - * Returns: @task's profile without incrementing its ref count + * Returns: @task's label without incrementing its ref count * * If @task != current needs to be called in RCU safe critical section */ -static inline struct aa_profile *__aa_task_profile(struct task_struct *task) +static inline struct aa_label *__aa_task_label(struct task_struct *task) { - return aa_cred_profile(__task_cred(task)); + return aa_cred_label(__task_cred(task)); } /** @@ -122,44 +103,75 @@ */ static inline bool __aa_task_is_confined(struct task_struct *task) { - return !unconfined(__aa_task_profile(task)); + return !unconfined(__aa_task_label(task)); } /** - * __aa_current_profile - find the current tasks confining profile + * __aa_current_label - find the current tasks confining label * - * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) + * Returns: up to date confining label or the ns unconfined label (NOT NULL) * * This fn will not update the tasks cred to the most up to date version - * of the profile so it is safe to call when inside of locks. + * of the label so it is safe to call when inside of locks. + */ +static inline struct aa_label *__aa_current_label(void) +{ + return aa_cred_label(current_cred()); +} + +/** + * __aa_get_current_label - find newest version of the current tasks label + * + * Returns: newest version of confining label (NOT NULL) + * + * This fn will not update the tasks cred, so it is safe inside of locks + * + * The returned reference must be put with __aa_put_current_label() + */ +static inline struct aa_label *__aa_get_current_label(void) +{ + struct aa_label *l = __aa_current_label(); + + if (label_invalid(l)) + l = aa_get_newest_label(l); + return l; +} + +/** + * __aa_put_current_label - put a reference found with aa_get_current_label + * @label: label reference to put + * + * Should only be used with a reference obtained with __aa_get_current_label + * and never used in situations where the task cred may be updated */ -static inline struct aa_profile *__aa_current_profile(void) +static inline void __aa_put_current_label(struct aa_label *label) { - return aa_cred_profile(current_cred()); + if (label != __aa_current_label()) + aa_put_label(label); } /** - * aa_current_profile - find the current tasks confining profile and do updates + * aa_current_label - find the current tasks confining label and update it * - * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) + * Returns: up to date confining label or the ns unconfined label (NOT NULL) * - * This fn will update the tasks cred structure if the profile has been + * This fn will update the tasks cred structure if the label has been * replaced. Not safe to call inside locks */ -static inline struct aa_profile *aa_current_profile(void) +static inline struct aa_label *aa_current_label(void) { const struct aa_task_cxt *cxt = current_cxt(); - struct aa_profile *profile; - BUG_ON(!cxt || !cxt->profile); + struct aa_label *label; + BUG_ON(!cxt || !cxt->label); - if (PROFILE_INVALID(cxt->profile)) { - profile = aa_get_newest_profile(cxt->profile); - aa_replace_current_profile(profile); - aa_put_profile(profile); + if (label_invalid(cxt->label)) { + label = aa_get_newest_label(cxt->label); + aa_replace_current_label(label); + aa_put_label(label); cxt = current_cxt(); } - return cxt->profile; + return cxt->label; } /** @@ -168,8 +180,8 @@ */ static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt) { - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); + aa_put_label(cxt->previous); + aa_put_label(cxt->onexec); cxt->previous = NULL; cxt->onexec = NULL; cxt->token = 0; --- linux-3.13.0.orig/security/apparmor/include/match.h +++ linux-3.13.0/security/apparmor/include/match.h @@ -127,6 +127,21 @@ void aa_dfa_free_kref(struct kref *kref); /** + * aa_get_dfa - increment refcount on dfa @p + * @dfa: dfa (MAYBE NULL) + * + * Returns: pointer to @dfa if @dfa is NULL will return NULL + * Requires: @dfa must be held with valid refcount when called + */ +static inline struct aa_dfa *aa_get_dfa(struct aa_dfa *dfa) +{ + if (dfa) + kref_get(&(dfa->count)); + + return dfa; +} + +/** * aa_put_dfa - put a dfa refcount * @dfa: dfa to put refcount (MAYBE NULL) * --- linux-3.13.0.orig/security/apparmor/include/path.h +++ linux-3.13.0/security/apparmor/include/path.h @@ -23,10 +23,66 @@ PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */ PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */ - PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ + PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ }; -int aa_path_name(struct path *path, int flags, char **buffer, +int aa_path_name(struct path *path, int flags, char *buffer, const char **name, const char **info); +#define MAX_PATH_BUFFERS 2 + +/* Per cpu buffers used during mediation */ +/* preallocated buffers to use during path lookups */ +struct aa_buffers { + char *buf[MAX_PATH_BUFFERS]; +}; + +#include +#include + +DECLARE_PER_CPU(struct aa_buffers, aa_buffers); + +#define COUNT_ARGS(X...) COUNT_ARGS_HELPER ( , ##X ,9,8,7,6,5,4,3,2,1,0) +#define COUNT_ARGS_HELPER(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,n,X...) n +#define CONCAT(X, Y) X ## Y +#define CONCAT_AFTER(X, Y) CONCAT(X, Y) + +#define ASSIGN(FN, X, N) do { (X) = FN(N); } while (0) +#define EVAL1(FN, X) ASSIGN(FN, X, 0) /*X = FN(0)*/ +#define EVAL2(FN, X, Y...) ASSIGN(FN, X, 1); /*X = FN(1);*/ EVAL1(FN, Y) +#define EVAL(FN, X...) CONCAT_AFTER(EVAL, COUNT_ARGS(X))(FN, X) + +#define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++) + +#ifdef CONFIG_DEBUG_PREEMPT +#define AA_BUG_PREEMPT_ENABLED(X) AA_BUG(preempt_count() <= 0, X) +#else +#define AA_BUG_PREEMPT_ENABLED(X) /* nop */ +#endif + +#define __get_buffer(N) ({ \ + struct aa_buffers *__cpu_var; \ + AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled"); \ + __cpu_var = &__get_cpu_var(aa_buffers); \ + __cpu_var->buf[(N)]; }) + +#define __get_buffers(X...) \ +do { \ + EVAL(__get_buffer, X); \ +} while (0) + +#define __put_buffers(X, Y...) (void)&(X) + +#define get_buffers(X...) \ +do { \ + preempt_disable(); \ + __get_buffers(X); \ +} while (0) + +#define put_buffers(X, Y...) \ +do { \ + __put_buffers(X, Y); \ + preempt_enable(); \ +} while (0) + #endif /* __AA_PATH_H */ --- linux-3.13.0.orig/security/apparmor/include/file.h +++ linux-3.13.0/security/apparmor/include/file.h @@ -15,31 +15,17 @@ #ifndef __AA_FILE_H #define __AA_FILE_H +#include + #include "domain.h" #include "match.h" +#include "label.h" +#include "perms.h" struct aa_profile; struct path; -/* - * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags - * for profile permissions - */ -#define AA_MAY_CREATE 0x0010 -#define AA_MAY_DELETE 0x0020 -#define AA_MAY_META_WRITE 0x0040 -#define AA_MAY_META_READ 0x0080 - -#define AA_MAY_CHMOD 0x0100 -#define AA_MAY_CHOWN 0x0200 -#define AA_MAY_LOCK 0x0400 -#define AA_EXEC_MMAP 0x0800 - -#define AA_MAY_LINK 0x1000 -#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */ -#define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */ -#define AA_MAY_CHANGE_PROFILE 0x80000000 -#define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */ +#define mask_mode_t(X) (X & (MAY_EXEC | MAY_WRITE | MAY_READ | MAY_APPEND)) #define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\ AA_MAY_CREATE | AA_MAY_DELETE | \ @@ -47,6 +33,57 @@ AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \ AA_EXEC_MMAP | AA_MAY_LINK) +#define file_cxt(X) ((struct aa_file_cxt *)(X)->f_security) + +/* struct aa_file_cxt - the AppArmor context the file was opened in + * @lock: lock to update the cxt + * @label: label currently cached on the cxt + * @perms: the permission the file was opened with + */ +struct aa_file_cxt { + spinlock_t lock; + struct aa_label __rcu *label; + u32 allow; +}; + +/** + * aa_alloc_file_cxt - allocate file_cxt + * @label: initial label of task creating the file + * @gfp: gfp flags for allocation + * + * Returns: file_cxt or NULL on failure + */ +static inline struct aa_file_cxt *aa_alloc_file_cxt(struct aa_label *label, gfp_t gfp) +{ + struct aa_file_cxt *cxt; + + cxt = kzalloc(sizeof(struct aa_file_cxt), gfp); + if (cxt) { + spin_lock_init(&cxt->lock); + rcu_assign_pointer(cxt->label, aa_get_label(label)); + } + return cxt; +} + +/** + * aa_free_file_cxt - free a file_cxt + * @cxt: file_cxt to free (MAYBE_NULL) + */ +static inline void aa_free_file_cxt(struct aa_file_cxt *cxt) +{ + if (cxt) { + aa_put_label(rcu_access_pointer(cxt->label)); + kzfree(cxt); + } +} + +static inline struct aa_label *aa_get_file_label(struct aa_file_cxt *cxt) +{ + return aa_get_label_rcu(&cxt->label); +} + +#define inode_cxt(X) (X)->i_security + /* * The xindex is broken into 3 parts * - index - an index into either the exec name table or the variable table @@ -145,8 +182,8 @@ dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff) int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, int op, u32 request, const char *name, - const char *target, kuid_t ouid, const char *info, int error); + int op, u32 request, const char *name, const char *target, + kuid_t ouid, const char *info, int error); /** * struct aa_file_rules - components used for file rule permissions @@ -171,15 +208,17 @@ const char *name, struct path_cond *cond, struct file_perms *perms); -int aa_path_perm(int op, struct aa_profile *profile, struct path *path, +int aa_path_perm(int op, struct aa_label *label, struct path *path, int flags, u32 request, struct path_cond *cond); -int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, +int aa_path_link(struct aa_label *label, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry); -int aa_file_perm(int op, struct aa_profile *profile, struct file *file, +int aa_file_perm(int op, struct aa_label *label, struct file *file, u32 request); +void aa_inherit_files(const struct cred *cred, struct files_struct *files); + static inline void aa_free_file_rules(struct aa_file_rules *rules) { aa_put_dfa(rules->dfa); --- linux-3.13.0.orig/security/apparmor/include/policy.h +++ linux-3.13.0/security/apparmor/include/policy.h @@ -27,8 +27,11 @@ #include "capability.h" #include "domain.h" #include "file.h" +#include "label.h" +#include "net.h" #include "resource.h" +extern const char *aa_hidden_ns_name; extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 @@ -40,12 +43,14 @@ #define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL) -#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) +#define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT) -#define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID) +#define PROFILE_INVALID(_profile) ((_profile)->label.flags & FLAG_INVALID) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) +#define PROFILE_MEDIATES(P, T) ((P)->policy.start[(T)] != 0) + /* * FIXME: currently need a clean way to replace and remove profiles as a * set. It should be done at the namespace level. @@ -59,32 +64,18 @@ APPARMOR_UNCONFINED, /* profile set to unconfined */ }; -enum profile_flags { - PFLAG_HAT = 1, /* profile is a hat */ - PFLAG_NULL = 4, /* profile is null learning profile */ - PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */ - PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */ - PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */ - PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ - PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */ - PFLAG_INVALID = 0x200, /* profile replaced/removed */ - PFLAG_NS_COUNT = 0x400, /* carries NS ref count */ - - /* These flags must correspond with PATH_flags */ - PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */ -}; struct aa_profile; /* struct aa_policy - common part of both namespaces and profiles * @name: name of the object - * @hname - The hierarchical name + * @hname - The hierarchical name, NOTE: is .name of struct counted_str * @list: list policy object is on * @profiles: head of the profiles list contained in the object */ struct aa_policy { - char *name; - char *hname; + const char *name; + __counted char *hname; struct list_head list; struct list_head profiles; }; @@ -136,6 +127,8 @@ struct list_head sub_ns; atomic_t uniq_null; long uniq_id; + int level; + struct aa_labelset labels; struct dentry *dents[AAFS_NS_SIZEOF]; }; @@ -151,31 +144,23 @@ }; -struct aa_replacedby { - struct kref count; - struct aa_profile __rcu *profile; -}; - - /* struct aa_profile - basic confinement data * @base - base components of the profile (name, refcount, lists, lock ...) - * @count: reference count of the obj - * @rcu: rcu head used when removing from @list + * @label - label this profile is an extension of * @parent: parent of profile * @ns: namespace the profile is in - * @replacedby: is set to the profile that replaced this profile * @rename: optional profile name that this profile renamed * @attach: human readable attachment string * @xmatch: optional extended matching for unconfined executables names * @xmatch_len: xmatch prefix len, used to determine xmatch priority * @audit: the auditing mode of the profile * @mode: the enforcement mode of the profile - * @flags: flags controlling profile behavior * @path_flags: flags controlling path generation behavior * @size: the memory consumed by this profiles rules * @policy: general match rules governing policy * @file: The set of rules governing basic file access and domain transitions * @caps: capabilities for the profile + * @net: network controls for the profile * @rlimits: rlimits for the profile * * @dents: dentries for the profiles file entries in apparmorfs @@ -197,12 +182,10 @@ */ struct aa_profile { struct aa_policy base; - struct kref count; - struct rcu_head rcu; + struct aa_label label; struct aa_profile __rcu *parent; struct aa_namespace *ns; - struct aa_replacedby *replacedby; const char *rename; const char *attach; @@ -210,13 +193,13 @@ int xmatch_len; enum audit_mode audit; long mode; - long flags; u32 path_flags; int size; struct aa_policydb policy; struct aa_file_rules file; struct aa_caps caps; + struct aa_net net; struct aa_rlimit rlimits; unsigned char *hash; @@ -231,6 +214,7 @@ bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view); const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child); +void aa_free_namespace(struct aa_namespace *ns); int aa_alloc_root_ns(void); void aa_free_root_ns(void); void aa_free_namespace_kref(struct kref *kref); @@ -238,14 +222,18 @@ struct aa_namespace *aa_find_namespace(struct aa_namespace *root, const char *name); +struct aa_label *aa_setup_default_label(void); -void aa_free_replacedby_kref(struct kref *kref); struct aa_profile *aa_alloc_profile(const char *name); struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); +struct aa_profile *aa_lookupn_profile(struct aa_namespace *ns, + const char *hname, size_t n); struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name); +struct aa_profile *aa_fqlookupn_profile(struct aa_namespace *ns, char *fqname, + int n); struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name); ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); @@ -254,8 +242,20 @@ #define PROF_ADD 1 #define PROF_REPLACE 0 -#define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) +#define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) +/** + * aa_get_newest_profile - simple wrapper fn to wrap the label version + * @p: profile (NOT NULL) + * + * Returns refcount to newest version of the profile (maybe @p) + * + * Requires: @p must be held with a valid refcount + */ +static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) +{ + return labels_profile(aa_get_newest_label(&p->label)); +} static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) { @@ -273,7 +273,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p) { if (p) - kref_get(&(p->count)); + kref_get(&(p->label.count)); return p; } @@ -287,7 +287,7 @@ */ static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p) { - if (p && kref_get_not0(&p->count)) + if (p && kref_get_not0(&p->label.count)) return p; return NULL; @@ -307,65 +307,20 @@ rcu_read_lock(); do { c = rcu_dereference(*p); - } while (c && !kref_get_not0(&c->count)); + } while (c && !kref_get_not0(&c->label.count)); rcu_read_unlock(); return c; } /** - * aa_get_newest_profile - find the newest version of @profile - * @profile: the profile to check for newer versions of - * - * Returns: refcounted newest version of @profile taking into account - * replacement, renames and removals - * return @profile. - */ -static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) -{ - if (!p) - return NULL; - - if (PROFILE_INVALID(p)) - return aa_get_profile_rcu(&p->replacedby->profile); - - return aa_get_profile(p); -} - -/** * aa_put_profile - decrement refcount on profile @p * @p: profile (MAYBE NULL) */ static inline void aa_put_profile(struct aa_profile *p) { if (p) - kref_put(&p->count, aa_free_profile_kref); -} - -static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p) -{ - if (p) - kref_get(&(p->count)); - - return p; -} - -static inline void aa_put_replacedby(struct aa_replacedby *p) -{ - if (p) - kref_put(&p->count, aa_free_replacedby_kref); -} - -/* requires profile list write lock held */ -static inline void __aa_update_replacedby(struct aa_profile *orig, - struct aa_profile *new) -{ - struct aa_profile *tmp; - tmp = rcu_dereference_protected(orig->replacedby->profile, - mutex_is_locked(&orig->ns->lock)); - rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); - orig->flags |= PFLAG_INVALID; - aa_put_profile(tmp); + kref_put(&p->label.count, aa_label_kref); } /** --- linux-3.13.0.orig/security/apparmor/include/ipc.h +++ linux-3.13.0/security/apparmor/include/ipc.h @@ -4,7 +4,7 @@ * This file contains AppArmor ipc mediation function definitions. * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * Copyright 2009-2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,10 +19,22 @@ struct aa_profile; -int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee, - unsigned int mode); - -int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, - unsigned int mode); +#define AA_PTRACE_TRACE MAY_WRITE +#define AA_PTRACE_READ MAY_READ +#define AA_MAY_BE_TRACED AA_MAY_APPEND +#define AA_MAY_BE_READ AA_MAY_CREATE +#define PTRACE_PERM_SHIFT 2 + +#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \ + AA_MAY_BE_READ | AA_MAY_BE_TRACED) +#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE) + +#define AA_FS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \ + "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \ + "xcpu xfsz vtalrm prof winch io pwr sys emt lost" + +int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, + u32 request); +int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig); #endif /* __AA_IPC_H */ --- linux-3.13.0.orig/security/apparmor/include/capability.h +++ linux-3.13.0/security/apparmor/include/capability.h @@ -19,11 +19,12 @@ #include "apparmorfs.h" -struct aa_profile; +struct aa_label; /* aa_caps - confinement data for capabilities * @allowed: capabilities mask * @audit: caps that are to be audited + * @denied: caps that are explicitly denied * @quiet: caps that should not be audited * @kill: caps that when requested will result in the task being killed * @extended: caps that are subject finer grained mediation @@ -31,6 +32,7 @@ struct aa_caps { kernel_cap_t allow; kernel_cap_t audit; + kernel_cap_t denied; kernel_cap_t quiet; kernel_cap_t kill; kernel_cap_t extended; @@ -38,7 +40,7 @@ extern struct aa_fs_entry aa_fs_entry_caps[]; -int aa_capable(struct aa_profile *profile, int cap, int audit); +int aa_capable(struct aa_label *label, int cap, int audit); static inline void aa_free_cap_rules(struct aa_caps *caps) { --- linux-3.13.0.orig/security/apparmor/include/sig_names.h +++ linux-3.13.0/security/apparmor/include/sig_names.h @@ -0,0 +1,95 @@ +#include + +#define SIGUNKNOWN 0 +#define MAXMAPPED_SIG 35 +/* provide a mapping of arch signal to internal signal # for mediation + * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO + * map to the same entry those that may/or may not get a separate entry + */ +static const int sig_map[MAXMAPPED_SIG] = { + [0] = MAXMAPPED_SIG, /* existance test */ + [SIGHUP] = 1, + [SIGINT] = 2, + [SIGQUIT] = 3, + [SIGILL] = 4, + [SIGTRAP] = 5, /* -, 5, - */ + [SIGABRT] = 6, /* SIGIOT: -, 6, - */ + [SIGBUS] = 7, /* 10, 7, 10 */ + [SIGFPE] = 8, + [SIGKILL] = 9, + [SIGUSR1] = 10, /* 30, 10, 16 */ + [SIGSEGV] = 11, + [SIGUSR2] = 12, /* 31, 12, 17 */ + [SIGPIPE] = 13, + [SIGALRM] = 14, + [SIGTERM] = 15, + [SIGSTKFLT] = 16, /* -, 16, - */ + [SIGCHLD] = 17, /* 20, 17, 18. SIGCHLD -, -, 18 */ + [SIGCONT] = 18, /* 19, 18, 25 */ + [SIGSTOP] = 19, /* 17, 19, 23 */ + [SIGTSTP] = 20, /* 18, 20, 24 */ + [SIGTTIN] = 21, /* 21, 21, 26 */ + [SIGTTOU] = 22, /* 22, 22, 27 */ + [SIGURG] = 23, /* 16, 23, 21 */ + [SIGXCPU] = 24, /* 24, 24, 30 */ + [SIGXFSZ] = 25, /* 25, 25, 31 */ + [SIGVTALRM] = 26, /* 26, 26, 28 */ + [SIGPROF] = 27, /* 27, 27, 29 */ + [SIGWINCH] = 28, /* 28, 28, 20 */ + [SIGIO] = 29, /* SIGPOLL: 23, 29, 22 */ + [SIGPWR] = 30, /* 29, 30, 19. SIGINFO 29, -, - */ +#ifdef SIGSYS + [SIGSYS] = 31, /* 12, 31, 12. often SIG LOST/UNUSED */ +#endif +#ifdef SIGEMT + [SIGEMT] = 32, /* 7, - , 7 */ +#endif +#if defined(SIGLOST) && SIGPWR != SIGLOST /* sparc */ + [SIGLOST] = 33, /* unused on Linux */ +#endif +#if defined(SIGLOST) && defined(SIGSYS) && SIGLOST != SIGSYS + [SIGUNUSED] = 34, /* -, 31, - */ +#endif +}; + +/* this table is ordered post sig_map[sig] mapping */ +static const char *const sig_names[MAXMAPPED_SIG + 1] = { + "unknown", + "hup", + "int", + "quit", + "ill", + "trap", + "abrt", + "bus", + "fpe", + "kill", + "usr1", + "segv", + "usr2", + "pipe", + "alrm", + "term", + "stkflt", + "chld", + "cont", + "stop", + "stp", + "ttin", + "ttou", + "urg", + "xcpu", + "xfsz", + "vtalrm", + "prof", + "winch", + "io", + "pwr", + "sys", + "emt", + "lost", + "unused", + + "exists", /* always last existance test mapped to MAXMAPPED_SIG */ +}; + --- linux-3.13.0.orig/security/apparmor/include/label.h +++ linux-3.13.0/security/apparmor/include/label.h @@ -0,0 +1,379 @@ +/* + * AppArmor security module + * + * This file contains AppArmor label definitions + * + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __AA_LABEL_H +#define __AA_LABEL_H + +#include +#include +#include +#include + +#include "apparmor.h" + +struct aa_namespace; + +struct labelset_stats { + atomic_t sread; + atomic_t fread; + atomic_t msread; + atomic_t mfread; + + atomic_t insert; + atomic_t existing; + atomic_t minsert; + atomic_t mexisting; + + atomic_t invalid; /* outstanding invalid */ +}; + +struct label_stats { + struct labelset_stats set_stats; + + atomic_t allocated; + atomic_t failed; + atomic_t freed; + + atomic_t printk_name_alloc; + atomic_t printk_name_fail; + atomic_t seq_print_name_alloc; + atomic_t seq_print_name_fail; + atomic_t audit_name_alloc; + atomic_t audit_name_fail; +}; + + +#ifdef AA_LABEL_STATS +#define labelstats_inc(X) atomic_inc(stats.(X)) +#define labelstats_dec(X) atomic_dec(stats.(X)) +#define labelsetstats_inc(LS, X) \ + do { \ + labelstats_inc(set_stats.##X); \ + atomic_inc((LS)->stats.(X)); \ + } while (0) +#define labelsetstats_dec(LS, X) \ + do { \ + labelstats_dec(set_stats.##X); \ + atomic_dec((LS)->stats.(X)); \ + } while (0) +#else +#define labelstats_inc(X) +#define labelstats_dec(X) +#define labelsetstats_inc(LS, X) +#define labelsetstats_dec(LS, X) +#endif +#define labelstats_init(X) + +/* struct aa_labelset - set of labels for a namespace + * + * Labels are reference counted; aa_labelset does not contribute to label + * reference counts. Once a label's last refcount is put it is removed from + * the set. + */ +struct aa_labelset { + rwlock_t lock; + + struct rb_root root; + + /* stats */ +#ifdef APPARMOR_LABEL_STATS + struct labelset_stats stats; +#endif + +}; + +#define __labelset_for_each(LS, N) \ + for((N) = rb_first(&(LS)->root); (N); (N) = rb_next(N)) + +void aa_labelset_destroy(struct aa_labelset *ls); +void aa_labelset_init(struct aa_labelset *ls); + + +enum label_flags { + FLAG_HAT = 1, /* profile is a hat */ + FLAG_UNCONFINED = 2, /* label unconfined only if all + * constituant profiles unconfined */ + FLAG_NULL = 4, /* profile is null learning profile */ + FLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */ + FLAG_IMMUTIBLE = 0x10, /* don't allow changes/replacement */ + FLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */ + FLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ + FLAG_NS_COUNT = 0x80, /* carries NS ref count */ + FLAG_IN_TREE = 0x100, /* label is in tree */ + FLAG_PROFILE = 0x200, /* label is a profile */ + FALG_EXPLICIT = 0x400, /* explict static label */ + FLAG_INVALID = 0x800, /* replaced/removed */ + FLAG_RENAMED = 0x1000, /* label has renaming in it */ + FLAG_REVOKED = 0x2000, /* label has revocation in it */ + + /* These flags must correspond with PATH_flags */ + /* TODO: add new path flags */ +}; + +struct aa_label; +struct aa_replacedby { + struct kref count; + struct aa_label __rcu *label; +}; + +struct label_it { + int i, j; +}; + +/* struct aa_label - lazy labeling struct + * @count: ref count of active users + * @node: rbtree position + * @rcu: rcu callback struct + * @replacedby: is set to the label that replaced this label + * @hname: text representation of the label (MAYBE_NULL) + * @flags: invalid and other flags - values may change under label set lock + * @sid: sid that references this label + * @size: number of entries in @ent[] + * @ent: set of profiles for label, actual size determined by @size + */ +struct aa_label { + struct kref count; + struct rb_node node; + struct rcu_head rcu; + struct aa_replacedby *replacedby; + __counted char *hname; + long flags; + u32 sid; + int size; + struct aa_profile *ent[2]; +}; + +#define label_isprofile(X) ((X)->flags & FLAG_PROFILE) +#define label_unconfined(X) ((X)->flags & FLAG_UNCONFINED) +#define unconfined(X) label_unconfined(X) +#define label_invalid(X) ((X)->flags & FLAG_INVALID) +#define __label_invalidate(X) do { \ + labelsetstats_inc(labels_set(X), invalid); \ + ((X)->flags |= FLAG_INVALID); \ +} while (0) +#define labels_last(X) ((X)->ent[(X)->size - 1]) +#define labels_ns(X) (labels_last(X)->ns) +#define labels_set(X) (&labels_ns(X)->labels) +#define labels_profile(X) ({ \ + AA_BUG(!label_isprofile(X)); \ + container_of((X), struct aa_profile, label); \ +}) + +int aa_label_next_confined(struct aa_label *l, int i); + +/* for each profile in a label */ +#define label_for_each(I, L, P) \ + for ((I).i = 0; ((P) = (L)->ent[(I).i]); ++((I).i)) + +#define label_for_each_at(I, L, P) \ + for (; \ + (I).i < (L)->size && ((P) = (L)->ent[(I).i]); \ + ++((I).i)) + +/* for each profile that is enforcing confinement in a label */ +#define label_for_each_confined(I, L, P) \ + for ((I).i = aa_label_next_confined((L), 0); \ + ((P) = (L)->ent[(I).i]); \ + (I).i = aa_label_next_confined((L), (I).i + 1)) + +#define label_for_each_in_merge(I, A, B, P) \ + for ((I).i = (I).j = 0; \ + ((P) = aa_label_next_in_merge(&(I), (A), (B))); \ + ) + +#define label_for_each_not_in_set(I, SET, SUB, P) \ + for ((I).i = (I).j = 0; \ + ((P) = aa_label_next_not_in_set(&(I), (SET), (SUB))); \ + ) + +#define fn_for_each_XXX(L, P, FN, ...) \ +({ \ + struct label_it i; \ + int __E = 0; \ + label_for_each ## __VA_ARGS__ (i, (L), (P)) { \ + int e = (FN); \ + if (e) \ + __E = e; \ + } \ + __E; \ +}) + +#define fn_for_each(L, P, FN) fn_for_each_XXX(L, P, FN) +#define fn_for_each_confined(L, P, FN) fn_for_each_XXX(L, P, FN, _confined) + +#define fn_for_each2_XXX(L1, L2, P, FN, ...) \ +({ \ + struct label_it i; \ + int __E = 0; \ + label_for_each ## __VA_ARGS__(i, (L1), (L2), (P)) { \ + int e = (FN); \ + if (e) \ + __E = e; \ + } \ + __E; \ +}) + +#define fn_for_each_in_merge(L1, L2, P, FN) \ + fn_for_each2_XXX((L1), (L2), P, FN, _in_merge) +#define fn_for_each_not_in_set(L1, L2, P, FN) \ + fn_for_each2_XXX((L1), (L2), P, FN, _not_in_set) + +#define LABEL_MEDIATES(L, C) \ +({ \ + struct aa_profile *profile; \ + struct label_it i; \ + int ret = 0; \ + label_for_each(i, (L), profile) { \ + if (PROFILE_MEDIATES(profile, (C))) { \ + ret = 1; \ + break; \ + } \ + } \ + ret; \ +}) + +void aa_labelset_destroy(struct aa_labelset *ls); +void aa_labelset_init(struct aa_labelset *ls); +void __aa_labelset_update_all(struct aa_namespace *ns); + +void aa_label_destroy(struct aa_label *label); +void aa_label_free(struct aa_label *label); +void aa_label_kref(struct kref *kref); +bool aa_label_init(struct aa_label *label, int size); +struct aa_label *aa_label_alloc(int size, gfp_t gfp); + +bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub); +struct aa_profile * aa_label_next_not_in_set(struct label_it *I, + struct aa_label *set, + struct aa_label *sub); +bool aa_label_remove(struct aa_labelset *ls, struct aa_label *label); +struct aa_label *aa_label_insert(struct aa_labelset *ls, struct aa_label *l); +struct aa_label *aa_label_remove_and_insert(struct aa_labelset *ls, + struct aa_label *remove, + struct aa_label *insert); +bool aa_label_replace(struct aa_labelset *ls, struct aa_label *old, + struct aa_label *new); +bool aa_label_make_newest(struct aa_labelset *ls, struct aa_label *old, + struct aa_label *new); + +struct aa_label *aa_label_find(struct aa_labelset *ls, struct aa_label *l); + +struct aa_profile *aa_label_next_in_merge(struct label_it *I, + struct aa_label *a, + struct aa_label *b); +struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b); +struct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b, + gfp_t gfp); + +bool aa_update_label_name(struct aa_namespace *ns, struct aa_label *label, + gfp_t gfp); + +int aa_profile_snprint(char *str, size_t size, struct aa_namespace *ns, + struct aa_profile *profile, bool mode); +int aa_label_snprint(char *str, size_t size, struct aa_namespace *ns, + struct aa_label *label, bool mode); +int aa_label_asprint(char **strp, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp); +int aa_label_acntsprint(char __counted **strp, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp); +void aa_label_audit(struct audit_buffer *ab, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp); +void aa_label_seq_print(struct seq_file *f, struct aa_namespace *ns, + struct aa_label *label, bool mode, gfp_t gfp); +void aa_label_printk(struct aa_namespace *ns, struct aa_label *label, + bool mode, gfp_t gfp); +struct aa_label *aa_label_parse(struct aa_namespace *base, char *str, + gfp_t gfp); + +static inline struct aa_label *aa_get_label(struct aa_label *l) +{ + if (l) + kref_get(&(l->count)); + + return l; +} + +static inline struct aa_label *aa_get_label_not0(struct aa_label *l) +{ + if (l && kref_get_not0(&l->count)) + return l; + + return NULL; +} + +/** + * aa_get_label_rcu - increment refcount on a label that can be replaced + * @l: pointer to label that can be replaced (NOT NULL) + * + * Returns: pointer to a refcounted label. + * else NULL if no label + */ +static inline struct aa_label *aa_get_label_rcu(struct aa_label __rcu **l) +{ + struct aa_label *c; + + rcu_read_lock(); + do { + c = rcu_dereference(*l); + } while (c && !kref_get_not0(&c->count)); + rcu_read_unlock(); + + return c; +} + +/** + * aa_get_newest_label - find the newest version of @l + * @l: the label to check for newer versions of + * + * Returns: refcounted newest version of @l taking into account + * replacement, renames and removals + * return @l. + */ +static inline struct aa_label *aa_get_newest_label(struct aa_label *l) +{ + if (!l) + return NULL; + + if (label_invalid(l)) + return aa_get_label_rcu(&l->replacedby->label); + + return aa_get_label(l); +} + +static inline void aa_put_label(struct aa_label *l) +{ + if (l) + kref_put(&l->count, aa_label_kref); +} + + +struct aa_replacedby *aa_alloc_replacedby(struct aa_label *l); +void aa_free_replacedby_kref(struct kref *kref); + +static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *r) +{ + if (r) + kref_get(&(r->count)); + + return r; +} + +static inline void aa_put_replacedby(struct aa_replacedby *r) +{ + if (r) + kref_put(&r->count, aa_free_replacedby_kref); +} + +void __aa_update_replacedby(struct aa_label *orig, struct aa_label *new); + +#endif /* __AA_LABEL_H */ --- linux-3.13.0.orig/security/apparmor/include/resource.h +++ linux-3.13.0/security/apparmor/include/resource.h @@ -37,10 +37,10 @@ extern struct aa_fs_entry aa_fs_entry_rlimit[]; int aa_map_resource(int resource); -int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, +int aa_task_setrlimit(struct aa_label *label, struct task_struct *, unsigned int resource, struct rlimit *new_rlim); -void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new); +void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new); static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims) { --- linux-3.13.0.orig/security/apparmor/include/domain.h +++ linux-3.13.0/security/apparmor/include/domain.h @@ -23,6 +23,8 @@ char **table; }; +struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex); + int apparmor_bprm_set_creds(struct linux_binprm *bprm); int apparmor_bprm_secureexec(struct linux_binprm *bprm); void apparmor_bprm_committing_creds(struct linux_binprm *bprm); --- linux-3.13.0.orig/security/apparmor/include/audit.h +++ linux-3.13.0/security/apparmor/include/audit.h @@ -22,8 +22,7 @@ #include #include "file.h" - -struct aa_profile; +#include "label.h" extern const char *const audit_mode_names[]; #define AUDIT_MAX_INDEX 5 @@ -67,10 +66,16 @@ OP_GETATTR, OP_OPEN, + OP_FRECEIVE, OP_FPERM, OP_FLOCK, OP_FMMAP, OP_FMPROT, + OP_INHERIT, + + OP_PIVOTROOT, + OP_MOUNT, + OP_UMOUNT, OP_CREATE, OP_POST_CREATE, @@ -87,6 +92,7 @@ OP_SOCK_SHUTDOWN, OP_PTRACE, + OP_SIGNAL, OP_EXEC, OP_CHANGE_HAT, @@ -106,37 +112,67 @@ int error; int op; int type; - void *profile; + struct aa_label *label; const char *name; const char *info; + u32 request; + u32 denied; union { - void *target; struct { - long pos; - void *target; - } iface; + const void *target; + union { + struct { + long pos; + } iface; + struct { + kuid_t ouid; + } fs; + struct { + int type, protocol; + struct sock *sk; + } net; + int signal; + }; + }; struct { int rlim; unsigned long max; } rlim; struct { - const char *target; - u32 request; - u32 denied; - kuid_t ouid; - } fs; + const char *src_name; + const char *type; + const char *trans; + const char *data; + unsigned long flags; + } mnt; }; }; -/* define a short hand for apparmor_audit_data structure */ -#define aad apparmor_audit_data +/* macros for dealing with apparmor_audit_data structure */ +#define aad(SA) (SA)->apparmor_audit_data +#define DEFINE_AUDIT_DATA(NAME, T, X) \ + /* TODO: cleanup audit init so we don't need _aad = {0,} */ \ + struct apparmor_audit_data NAME ## _aad = { .op = (X), }; \ + struct common_audit_data NAME = \ + { \ + .type = (T), \ + .u.tsk = NULL, \ + { .apparmor_audit_data = &(NAME ## _aad) }, \ + } void aa_audit_msg(int type, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)); -int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, - struct common_audit_data *sa, +int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *)); +#define aa_audit_error(ERROR, SA, CB) \ +({ \ + aad((SA))->error = (ERROR); \ + aa_audit_msg(AUDIT_APPARMOR_ERROR, (SA), (CB)); \ + aad((SA))->error; \ +}) + + static inline int complain_error(int error) { if (error == -EPERM || error == -EACCES) --- linux-3.13.0.orig/security/apparmor/include/procattr.h +++ linux-3.13.0/security/apparmor/include/procattr.h @@ -18,7 +18,7 @@ #define AA_DO_TEST 1 #define AA_ONEXEC 1 -int aa_getprocattr(struct aa_profile *profile, char **string); +int aa_getprocattr(struct aa_label *label, char **string); int aa_setprocattr_changehat(char *args, size_t size, int test); int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test); --- linux-3.13.0.orig/security/apparmor/include/apparmor.h +++ linux-3.13.0/security/apparmor/include/apparmor.h @@ -4,7 +4,7 @@ * This file contains AppArmor basic global and lib definitions * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * Copyright 2009-2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,8 +30,12 @@ #define AA_CLASS_NET 4 #define AA_CLASS_RLIMITS 5 #define AA_CLASS_DOMAIN 6 +#define AA_CLASS_MOUNT 7 +#define AA_CLASS_PTRACE 9 +#define AA_CLASS_SIGNAL 10 +#define AA_CLASS_LABEL 16 -#define AA_CLASS_LAST AA_CLASS_DOMAIN +#define AA_CLASS_LAST AA_CLASS_LABEL /* Control parameters settable through module/boot flags */ extern enum audit_mode aa_g_audit; @@ -41,6 +45,7 @@ extern bool aa_g_logsyscall; extern bool aa_g_paranoid_load; extern unsigned int aa_g_path_max; +extern bool aa_g_unconfined_init; /* * DEBUG remains global (no per profile flag) since it is mostly used in sysctl @@ -53,6 +58,12 @@ printk(KERN_DEBUG "AppArmor: " fmt, ##args); \ } while (0) +#define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __FUNCTION__, #X) + +#define AA_BUG(X, args...) AA_BUG_FMT((X), "" args ) +#define AA_BUG_FMT(X, fmt, args...) \ + WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __FUNCTION__ , ##args ) + #define AA_ERROR(fmt, args...) \ do { \ if (printk_ratelimit()) \ @@ -113,9 +124,40 @@ return aa_dfa_next(dfa, start, 0); } -static inline bool mediated_filesystem(struct inode *inode) +static inline bool path_mediated_fs(struct inode *inode) { return !(inode->i_sb->s_flags & MS_NOUSER); } + +struct counted_str { + struct kref count; + char name[]; +}; + +#define str_to_counted(str) \ + ((struct counted_str *)(str - offsetof(struct counted_str,name))) + +#define __counted /* atm just a notation */ + +void aa_str_kref(struct kref *kref); +char *aa_str_alloc(int size, gfp_t gfp); + + +static inline __counted char *aa_get_str(__counted char *str) +{ + if (str) + kref_get(&(str_to_counted(str)->count)); + + return str; +} + +static inline void aa_put_str(__counted char *str) +{ + if (str) + kref_put(&str_to_counted(str)->count, aa_str_kref); +} + +const char *aa_imode_name(umode_t mode); + #endif /* __APPARMOR_H */ --- linux-3.13.0.orig/security/apparmor/include/mount.h +++ linux-3.13.0/security/apparmor/include/mount.h @@ -0,0 +1,54 @@ +/* + * AppArmor security module + * + * This file contains AppArmor file mediation function definitions. + * + * Copyright 2012 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __AA_MOUNT_H +#define __AA_MOUNT_H + +#include +#include + +#include "domain.h" +#include "policy.h" + +/* mount perms */ +#define AA_MAY_PIVOTROOT 0x01 +#define AA_MAY_MOUNT 0x02 +#define AA_MAY_UMOUNT 0x04 +#define AA_AUDIT_DATA 0x40 +#define AA_MNT_CONT_MATCH 0x40 + +#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN) + +int aa_remount(struct aa_label *label, struct path *path, unsigned long flags, + void *data); + +int aa_bind_mount(struct aa_label *label, struct path *path, + const char *old_name, unsigned long flags); + + +int aa_mount_change_type(struct aa_label *label, struct path *path, + unsigned long flags); + +int aa_move_mount(struct aa_label *label, struct path *path, + const char *old_name); + +int aa_new_mount(struct aa_label *label, const char *dev_name, + struct path *path, const char *type, unsigned long flags, + void *data); + +int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags); + +int aa_pivotroot(struct aa_label *label, struct path *old_path, + struct path *new_path); + +#endif /* __AA_MOUNT_H */ --- linux-3.13.0.orig/security/apparmor/include/perms.h +++ linux-3.13.0/security/apparmor/include/perms.h @@ -0,0 +1,170 @@ +/* + * AppArmor security module + * + * This file contains AppArmor basic permission sets definitions. + * + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __AA_PERM_H +#define __AA_PERM_H + +#include +#include "label.h" + +#define AA_MAY_EXEC MAY_EXEC +#define AA_MAY_WRITE MAY_WRITE +#define AA_MAY_READ MAY_READ +#define AA_MAY_APPEND MAY_APPEND + +#define AA_MAY_CREATE 0x0010 +#define AA_MAY_DELETE 0x0020 +#define AA_MAY_OPEN 0x0040 +#define AA_MAY_RENAME 0x0080 /* pair */ + +#define AA_MAY_META_WRITE 0x0100 +#define AA_MAY_META_READ 0x0200 +#define AA_MAY_GET_SECURITY 0x0400 +#define AA_MAY_SET_SECURITY 0x0800 + +#define AA_MAY_CHMOD 0x1000 /* pair */ +#define AA_MAY_CHOWN 0x2000 /* pair */ +#define AA_MAY_CHGRP 0x4000 /* pair */ +#define AA_MAY_LOCK 0x8000 /* LINK_SUBSET overlaid */ + +#define AA_EXEC_MMAP 0x00010000 +#define AA_MAY_MPROT_WX 0x00020000 +#define AA_MAY_MPROT_XW 0x00040000 +#define AA_MAY_LINK 0x00080000 /* pair */ + +#define AA_MAY_SNAPSHOT 0x00100000 /* pair */ +#define AA_MAY_BIND 0x00200000 +#define AA_MAY_ACCEPT 0x00400000 +#define AA_MAY_LISTEN 0x00800000 + +#define AA_MAY_DELEGATE +#define AA_CONT_MATCH 0x08000000 + +#define AA_MAY_STACK 0x10000000 +#define AA_MAY_ONEXEC 0x20000000 /* either stack or change_profile */ +#define AA_MAY_CHANGE_PROFILE 0x40000000 +#define AA_MAY_CHANGEHAT 0x80000000 + +#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */ + +#define AA_MAY_CONNECT AA_MAY_OPEN +#define AA_MAY_SEND AA_MAY_WRITE +#define AA_MAY_RECEIVE AA_MAY_READ +#define AA_MAY_XATTR_READ AA_MAY_READ /* stored on pair like link */ +#define AA_MAY_XATTR_WRITE AA_MAY_WRITE /* stored on pair like link */ + + +#define AA_PERM_CHR_MASK (MAY_READ | MAY_WRITE | AA_MAY_CREATE | \ + AA_MAY_DELETE | AA_MAY_LINK | AA_MAY_LOCK | \ + AA_MAY_EXEC | AA_EXEC_MMAP) + + +struct aa_perms { + u32 allow; + u32 audit; /* set only when allow is set */ + + u32 deny; /* explicit deny, or conflict if allow also set */ + u32 quiet; /* set only when ~allow | deny */ + u32 kill; /* set only when ~allow | deny */ + u32 stop; /* set only when ~allow | deny */ + + u32 complain; /* accumulates only used when ~allow & ~deny */ + u32 cond; /* set only when ~allow and ~deny */ + + u32 hide; /* set only when ~allow | deny */ + + /* Reserved: + * u32 subtree; / * set only when allow is set * / + * u32 prompt; / * accumulates only used when ~allow & ~deny * / + */ +}; + +#define ALL_PERMS_MASK 0xffffffff + + +#define xcheck(FN1, FN2) \ +({ \ + int e, error = FN1; \ + e = FN2; \ + if (e) \ + error = e; \ + error; \ +}) + +/* pattern: perform send/receive style paired cross check of permissions + * + */ +#define xcheck_profiles(P1, P2, FN1, FN2, PERM, args...) \ +({ \ + xcheck(FN1(P1, P2, PERM, args), \ + FN2(P2, P1, PERM, args)); \ +}) + + +/* TODO: update for labels pointing to labels instead of profiles +* Note: this only works for profiles from a single namespace +*/ + +#define xcheck_profile_label(P, L, FN, args...) \ +({ \ + struct aa_profile *__p2; \ + fn_for_each((L), __p2, FN((P), __p2, args)); \ +}) + +#define xcheck_ns_labels(L1, L2, FN, args...) \ +({ \ + struct aa_profile *__p1; \ + fn_for_each((L1), __p1, FN(__p1, (L2), args)); \ +}) + +/* todo: fix to handle multiple namespaces */ +#define xcheck_labels(L1, L2, FN, args...) \ + xcheck_ns_labels((L1), (L2), FN, args) + +/* Do the cross check but applying FN at the profiles level */ +#define xcheck_labels_profiles(L1, L2, FN, args...) \ + xcheck_ns_labels((L1), (L2), xcheck_profile_label, (FN), args) + + +#define FINAL_CHECK true + +void aa_perm_mask_to_chr(u32 mask, char *str); +void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask); +void aa_apply_modes_to_perms(struct aa_profile *profile, + struct aa_perms *perms); +void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, + struct aa_perms *perms); +void aa_profile_match_label(struct aa_profile *profile, const char *label, + int type, struct aa_perms *perms); +int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, + u32 request, int type, u32 *deny, + struct common_audit_data *sa); +int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, + u32 request, struct common_audit_data *sa, + void (*cb) (struct audit_buffer *, void *)); +const char *aa_peer_name(struct aa_profile *peer); + + +static inline int aa_cross_label_perm(struct aa_profile *profile, + struct aa_profile *target, + int type, u32 request, u32 reverse, + u32 * deny, struct common_audit_data *sa) +{ + /* TODO: ??? 2nd aa_profile_label_perm needs to reverse perms */ + return xcheck_profiles(profile, target, aa_profile_label_perm, + aa_profile_label_perm, request, type, deny, + sa); +} + + +#endif /* __AA_PERM_H */ --- linux-3.13.0.orig/security/apparmor/include/apparmorfs.h +++ linux-3.13.0/security/apparmor/include/apparmorfs.h @@ -15,6 +15,8 @@ #ifndef __AA_APPARMORFS_H #define __AA_APPARMORFS_H +extern struct path aa_null; + enum aa_fs_type { AA_FS_TYPE_BOOLEAN, AA_FS_TYPE_STRING, --- linux-3.13.0.orig/security/keys/keyring.c +++ linux-3.13.0/security/keys/keyring.c @@ -1000,7 +1000,11 @@ kenter("{%d}", key->serial); - BUG_ON(key != ctx->match_data); + /* We might get a keyring with matching index-key that is nonetheless a + * different keyring. */ + if (key != ctx->match_data) + return 0; + ctx->result = ERR_PTR(-EDEADLK); return 1; } --- linux-3.13.0.orig/security/integrity/ima/ima_template_lib.c +++ linux-3.13.0/security/integrity/ima/ima_template_lib.c @@ -255,7 +255,7 @@ struct evm_ima_xattr_data *xattr_value, int xattr_len, struct ima_field_data *field_data) { - u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST; + u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1; u32 cur_digestsize = 0; /* If iint is NULL, we are recording a violation. */ --- linux-3.13.0.orig/security/selinux/ss/policydb.c +++ linux-3.13.0/security/selinux/ss/policydb.c @@ -1941,7 +1941,19 @@ if (rc) goto out; - hashtab_insert(p->filename_trans, ft, otype); + rc = hashtab_insert(p->filename_trans, ft, otype); + if (rc) { + /* + * Do not return -EEXIST to the caller, or the system + * will not boot. + */ + if (rc != -EEXIST) + goto out; + /* But free memory to avoid memory leak. */ + kfree(ft); + kfree(name); + kfree(otype); + } } hash_eval(p->filename_trans, "filenametr"); return 0; @@ -3248,10 +3260,10 @@ if (rc) return rc; - buf[0] = ft->stype; - buf[1] = ft->ttype; - buf[2] = ft->tclass; - buf[3] = otype->otype; + buf[0] = cpu_to_le32(ft->stype); + buf[1] = cpu_to_le32(ft->ttype); + buf[2] = cpu_to_le32(ft->tclass); + buf[3] = cpu_to_le32(otype->otype); rc = put_entry(buf, sizeof(u32), 4, fp); if (rc) --- linux-3.13.0.orig/security/selinux/ss/services.c +++ linux-3.13.0/security/selinux/ss/services.c @@ -1232,6 +1232,10 @@ struct context context; int rc = 0; + /* An empty security context is never valid. */ + if (!scontext_len) + return -EINVAL; + if (!ss_initialized) { int i; @@ -1831,7 +1835,7 @@ */ int security_load_policy(void *data, size_t len) { - struct policydb oldpolicydb, newpolicydb; + struct policydb *oldpolicydb, *newpolicydb; struct sidtab oldsidtab, newsidtab; struct selinux_mapping *oldmap, *map = NULL; struct convert_context_args args; @@ -1840,12 +1844,19 @@ int rc = 0; struct policy_file file = { data, len }, *fp = &file; + oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); + if (!oldpolicydb) { + rc = -ENOMEM; + goto out; + } + newpolicydb = oldpolicydb + 1; + if (!ss_initialized) { avtab_cache_init(); rc = policydb_read(&policydb, fp); if (rc) { avtab_cache_destroy(); - return rc; + goto out; } policydb.len = len; @@ -1855,14 +1866,14 @@ if (rc) { policydb_destroy(&policydb); avtab_cache_destroy(); - return rc; + goto out; } rc = policydb_load_isids(&policydb, &sidtab); if (rc) { policydb_destroy(&policydb); avtab_cache_destroy(); - return rc; + goto out; } security_load_policycaps(); @@ -1874,36 +1885,36 @@ selinux_status_update_policyload(seqno); selinux_netlbl_cache_invalidate(); selinux_xfrm_notify_policyload(); - return 0; + goto out; } #if 0 sidtab_hash_eval(&sidtab, "sids"); #endif - rc = policydb_read(&newpolicydb, fp); + rc = policydb_read(newpolicydb, fp); if (rc) - return rc; + goto out; - newpolicydb.len = len; + newpolicydb->len = len; /* If switching between different policy types, log MLS status */ - if (policydb.mls_enabled && !newpolicydb.mls_enabled) + if (policydb.mls_enabled && !newpolicydb->mls_enabled) printk(KERN_INFO "SELinux: Disabling MLS support...\n"); - else if (!policydb.mls_enabled && newpolicydb.mls_enabled) + else if (!policydb.mls_enabled && newpolicydb->mls_enabled) printk(KERN_INFO "SELinux: Enabling MLS support...\n"); - rc = policydb_load_isids(&newpolicydb, &newsidtab); + rc = policydb_load_isids(newpolicydb, &newsidtab); if (rc) { printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); - policydb_destroy(&newpolicydb); - return rc; + policydb_destroy(newpolicydb); + goto out; } - rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); + rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); if (rc) goto err; - rc = security_preserve_bools(&newpolicydb); + rc = security_preserve_bools(newpolicydb); if (rc) { printk(KERN_ERR "SELinux: unable to preserve booleans\n"); goto err; @@ -1921,7 +1932,7 @@ * in the new SID table. */ args.oldp = &policydb; - args.newp = &newpolicydb; + args.newp = newpolicydb; rc = sidtab_map(&newsidtab, convert_context, &args); if (rc) { printk(KERN_ERR "SELinux: unable to convert the internal" @@ -1931,12 +1942,12 @@ } /* Save the old policydb and SID table to free later. */ - memcpy(&oldpolicydb, &policydb, sizeof policydb); + memcpy(oldpolicydb, &policydb, sizeof(policydb)); sidtab_set(&oldsidtab, &sidtab); /* Install the new policydb and SID table. */ write_lock_irq(&policy_rwlock); - memcpy(&policydb, &newpolicydb, sizeof policydb); + memcpy(&policydb, newpolicydb, sizeof(policydb)); sidtab_set(&sidtab, &newsidtab); security_load_policycaps(); oldmap = current_mapping; @@ -1946,7 +1957,7 @@ write_unlock_irq(&policy_rwlock); /* Free the old policydb and SID table. */ - policydb_destroy(&oldpolicydb); + policydb_destroy(oldpolicydb); sidtab_destroy(&oldsidtab); kfree(oldmap); @@ -1956,14 +1967,17 @@ selinux_netlbl_cache_invalidate(); selinux_xfrm_notify_policyload(); - return 0; + rc = 0; + goto out; err: kfree(map); sidtab_destroy(&newsidtab); - policydb_destroy(&newpolicydb); - return rc; + policydb_destroy(newpolicydb); +out: + kfree(oldpolicydb); + return rc; } size_t security_policydb_len(void) --- linux-3.13.0.orig/tools/power/x86/turbostat/turbostat.c +++ linux-3.13.0/tools/power/x86/turbostat/turbostat.c @@ -20,7 +20,7 @@ */ #define _GNU_SOURCE -#include +#include MSRHEADER #include #include #include @@ -35,6 +35,7 @@ #include #include #include +#include char *proc_stat = "/proc/stat"; unsigned int interval_sec = 5; /* set with -i interval_sec */ @@ -1978,7 +1979,7 @@ eax = ebx = ecx = edx = 0; - asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0)); + __get_cpuid(0, &max_level, &ebx, &ecx, &edx); if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) genuine_intel = 1; @@ -1987,7 +1988,7 @@ fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", (char *)&ebx, (char *)&edx, (char *)&ecx); - asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); + __get_cpuid(1, &fms, &ebx, &ecx, &edx); family = (fms >> 8) & 0xf; model = (fms >> 4) & 0xf; stepping = fms & 0xf; @@ -2009,7 +2010,7 @@ * This check is valid for both Intel and AMD. */ ebx = ecx = edx = 0; - asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000)); + __get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx); if (max_level < 0x80000007) { fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level); @@ -2020,7 +2021,7 @@ * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 * this check is valid for both Intel and AMD */ - asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007)); + __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); has_invariant_tsc = edx & (1 << 8); if (!has_invariant_tsc) { @@ -2033,7 +2034,7 @@ * this check is valid for both Intel and AMD */ - asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); + __get_cpuid(0x6, &eax, &ebx, &ecx, &edx); has_aperf = ecx & (1 << 0); do_dts = eax & (1 << 0); do_ptm = eax & (1 << 6); --- linux-3.13.0.orig/tools/power/x86/turbostat/Makefile +++ linux-3.13.0/tools/power/x86/turbostat/Makefile @@ -5,7 +5,7 @@ turbostat : turbostat.c CFLAGS += -Wall -CFLAGS += -I../../../../arch/x86/include/uapi/ +CFLAGS += -DMSRHEADER='"../../../../arch/x86/include/uapi/asm/msr-index.h"' %: %.c @mkdir -p $(BUILD_OUTPUT) --- linux-3.13.0.orig/tools/perf/perf.h +++ linux-3.13.0/tools/perf/perf.h @@ -100,8 +100,8 @@ #ifdef __aarch64__ #define mb() asm volatile("dmb ish" ::: "memory") -#define wmb() asm volatile("dmb ishld" ::: "memory") -#define rmb() asm volatile("dmb ishst" ::: "memory") +#define wmb() asm volatile("dmb ishst" ::: "memory") +#define rmb() asm volatile("dmb ishld" ::: "memory") #define cpu_relax() asm volatile("yield" ::: "memory") #endif --- linux-3.13.0.orig/tools/perf/builtin-trace.c +++ linux-3.13.0/tools/perf/builtin-trace.c @@ -35,6 +35,10 @@ # define MADV_UNMERGEABLE 13 #endif +#ifndef EFD_SEMAPHORE +# define EFD_SEMAPHORE 1 +#endif + struct tp_field { int offset; union { @@ -275,6 +279,11 @@ #define SCA_STRARRAY syscall_arg__scnprintf_strarray +#if defined(__i386__) || defined(__x86_64__) +/* + * FIXME: Make this available to all arches as soon as the ioctl beautifier + * gets rewritten to support all arches. + */ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size, struct syscall_arg *arg) { @@ -282,6 +291,7 @@ } #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray +#endif /* defined(__i386__) || defined(__x86_64__) */ static size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg); @@ -811,7 +821,6 @@ P_SIGNUM(PIPE); P_SIGNUM(ALRM); P_SIGNUM(TERM); - P_SIGNUM(STKFLT); P_SIGNUM(CHLD); P_SIGNUM(CONT); P_SIGNUM(STOP); @@ -827,6 +836,15 @@ P_SIGNUM(IO); P_SIGNUM(PWR); P_SIGNUM(SYS); +#ifdef SIGEMT + P_SIGNUM(EMT); +#endif +#ifdef SIGSTKFLT + P_SIGNUM(STKFLT); +#endif +#ifdef SIGSWI + P_SIGNUM(SWI); +#endif default: break; } @@ -835,6 +853,10 @@ #define SCA_SIGNUM syscall_arg__scnprintf_signum +#if defined(__i386__) || defined(__x86_64__) +/* + * FIXME: Make this available to all arches. + */ #define TCGETS 0x5401 static const char *tioctls[] = { @@ -856,6 +878,7 @@ }; static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); +#endif /* defined(__i386__) || defined(__x86_64__) */ #define STRARRAY(arg, name, array) \ .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ @@ -937,9 +960,16 @@ { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, { .name = "ioctl", .errmsg = true, .arg_scnprintf = { [0] = SCA_FD, /* fd */ +#if defined(__i386__) || defined(__x86_64__) +/* + * FIXME: Make this available to all arches. + */ [1] = SCA_STRHEXARRAY, /* cmd */ [2] = SCA_HEX, /* arg */ }, .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, }, +#else + [2] = SCA_HEX, /* arg */ }, }, +#endif { .name = "kill", .errmsg = true, .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, { .name = "linkat", .errmsg = true, --- linux-3.13.0.orig/tools/perf/util/session.c +++ linux-3.13.0/tools/perf/util/session.c @@ -851,6 +851,7 @@ struct perf_sample *sample) { const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + struct machine *machine; if (perf_guest && ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || @@ -863,7 +864,11 @@ else pid = sample->pid; - return perf_session__findnew_machine(session, pid); + machine = perf_session__find_machine(session, pid); + if (!machine) + machine = perf_session__findnew_machine(session, + DEFAULT_GUEST_KERNEL_ID); + return machine; } return &session->machines.host; --- linux-3.13.0.orig/tools/hv/hv_kvp_daemon.8 +++ linux-3.13.0/tools/hv/hv_kvp_daemon.8 @@ -0,0 +1,26 @@ +.\" This page Copyright (C) 2012 Andy Whitcroft +.\" Distributed under the GPL v2 or later. +.TH HV_KVP_DAEMON 8 +.SH NAME +hv_kvp_daemon \- Hyper-V Key Value Pair daemon +.SH SYNOPSIS +.ft B +.B hv_kvp_daemon +.br +.SH DESCRIPTION +\fBhv_kvp_daemon\fP +is the userspace component of the Hyper-V key value pair functionality, +communicating via a netlink socket with the kernel HV-KVP driver. +This pairing allows the Hyper-V host to pass configuration information +(such as IP addresses) to the guest and allows the host to obtain guest +version information. + +.SH FILES +.ta +.nf +/var/opt/hyperv/.kvp_pool_* +.fi + +.SH AUTHORS +.nf +Written by K. Y. Srinivasan --- linux-3.13.0.orig/tools/hv/hv_fcopy_daemon.c +++ linux-3.13.0/tools/hv/hv_fcopy_daemon.c @@ -0,0 +1,195 @@ +/* + * An implementation of host to guest copy functionality for Linux. + * + * Copyright (C) 2014, Microsoft, Inc. + * + * Author : K. Y. Srinivasan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int target_fd; +static char target_fname[W_MAX_PATH]; + +static int hv_start_fcopy(struct hv_start_fcopy *smsg) +{ + int error = HV_E_FAIL; + char *q, *p; + + /* + * If possile append a path seperator to the path. + */ + if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2)) + strcat((char *)smsg->path_name, "/"); + + p = (char *)smsg->path_name; + snprintf(target_fname, sizeof(target_fname), "%s/%s", + (char *)smsg->path_name, smsg->file_name); + + syslog(LOG_INFO, "Target file name: %s", target_fname); + /* + * Check to see if the path is already in place; if not, + * create if required. + */ + while ((q = strchr(p, '/')) != NULL) { + if (q == p) { + p++; + continue; + } + *q = '\0'; + if (access((char *)smsg->path_name, F_OK)) { + if (smsg->copy_flags & CREATE_PATH) { + if (mkdir((char *)smsg->path_name, 0755)) { + syslog(LOG_ERR, "Failed to create %s", + (char *)smsg->path_name); + goto done; + } + } else { + syslog(LOG_ERR, "Invalid path: %s", + (char *)smsg->path_name); + goto done; + } + } + p = q + 1; + *q = '/'; + } + + if (!access(target_fname, F_OK)) { + syslog(LOG_INFO, "File: %s exists", target_fname); + if (!smsg->copy_flags & OVER_WRITE) + goto done; + } + + target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744); + if (target_fd == -1) { + syslog(LOG_INFO, "Open Failed: %s", strerror(errno)); + goto done; + } + + error = 0; +done: + return error; +} + +static int hv_copy_data(struct hv_do_fcopy *cpmsg) +{ + ssize_t bytes_written; + + bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, + cpmsg->offset); + + if (bytes_written != cpmsg->size) + return HV_E_FAIL; + + return 0; +} + +static int hv_copy_finished(void) +{ + close(target_fd); + return 0; +} +static int hv_copy_cancel(void) +{ + close(target_fd); + unlink(target_fname); + return 0; + +} + +int main(void) +{ + int fd, fcopy_fd, len; + int error; + int version = FCOPY_CURRENT_VERSION; + char *buffer[4096 * 2]; + struct hv_fcopy_hdr *in_msg; + + if (daemon(1, 0)) { + syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + openlog("HV_FCOPY", 0, LOG_USER); + syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid()); + + fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); + + if (fcopy_fd < 0) { + syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s", + errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* + * Register with the kernel. + */ + if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) { + syslog(LOG_ERR, "Registration failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + while (1) { + /* + * In this loop we process fcopy messages after the + * handshake is complete. + */ + len = pread(fcopy_fd, buffer, (4096 * 2), 0); + if (len < 0) { + syslog(LOG_ERR, "pread failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + in_msg = (struct hv_fcopy_hdr *)buffer; + + switch (in_msg->operation) { + case START_FILE_COPY: + error = hv_start_fcopy((struct hv_start_fcopy *)in_msg); + break; + case WRITE_TO_FILE: + error = hv_copy_data((struct hv_do_fcopy *)in_msg); + break; + case COMPLETE_FCOPY: + error = hv_copy_finished(); + break; + case CANCEL_FCOPY: + error = hv_copy_cancel(); + break; + + default: + syslog(LOG_ERR, "Unknown operation: %d", + in_msg->operation); + + } + + if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) { + syslog(LOG_ERR, "pwrite failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + } +} --- linux-3.13.0.orig/tools/hv/hv_vss_daemon.c +++ linux-3.13.0/tools/hv/hv_vss_daemon.c @@ -88,6 +88,8 @@ continue; if (strcmp(ent->mnt_type, "iso9660") == 0) continue; + if (strcmp(ent->mnt_type, "vfat") == 0) + continue; if (strcmp(ent->mnt_dir, "/") == 0) { root_seen = 1; continue; @@ -143,8 +145,10 @@ char *vss_recv_buffer; size_t vss_recv_buffer_len; +#if 0 /* It's much easier to manage from upstart if we don't fork */ if (daemon(1, 0)) return 1; +#endif openlog("Hyper-V VSS", 0, LOG_USER); syslog(LOG_INFO, "VSS starting; pid is:%d", getpid()); --- linux-3.13.0.orig/ubuntu/aufs-update +++ linux-3.13.0/ubuntu/aufs-update @@ -0,0 +1,52 @@ +#!/bin/bash +# +# NOTE: See aufs/BOM.UPDATING for instructions on how to use this updater. +# + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi +aufs="$1" + +# Get the current tip name +{ + read x url + read x o_log_sha1 + read x o_tip_sha1 +} . + */ + +/* + * policies for selecting one among multiple writable branches + */ + +#include +#include "aufs.h" + +/* subset of cpup_attr() */ +static noinline_for_stack +int au_cpdown_attr(struct path *h_path, struct dentry *h_src) +{ + int err, sbits; + struct iattr ia; + struct inode *h_isrc; + + h_isrc = h_src->d_inode; + ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; + ia.ia_mode = h_isrc->i_mode; + ia.ia_uid = h_isrc->i_uid; + ia.ia_gid = h_isrc->i_gid; + sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); + au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc->i_flags); + /* no delegation since it is just created */ + err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); + + /* is this nfs only? */ + if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { + ia.ia_valid = ATTR_FORCE | ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); + } + + return err; +} + +#define AuCpdown_PARENT_OPQ 1 +#define AuCpdown_WHED (1 << 1) +#define AuCpdown_MADE_DIR (1 << 2) +#define AuCpdown_DIROPQ (1 << 3) +#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) +#define au_fset_cpdown(flags, name) \ + do { (flags) |= AuCpdown_##name; } while (0) +#define au_fclr_cpdown(flags, name) \ + do { (flags) &= ~AuCpdown_##name; } while (0) + +static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, + unsigned int *flags) +{ + int err; + struct dentry *opq_dentry; + + opq_dentry = au_diropq_create(dentry, bdst); + err = PTR_ERR(opq_dentry); + if (IS_ERR(opq_dentry)) + goto out; + dput(opq_dentry); + au_fset_cpdown(*flags, DIROPQ); + +out: + return err; +} + +static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, + struct inode *dir, aufs_bindex_t bdst) +{ + int err; + struct path h_path; + struct au_branch *br; + + br = au_sbr(dentry->d_sb, bdst); + h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) + goto out; + + err = 0; + if (h_path.dentry->d_inode) { + h_path.mnt = au_br_mnt(br); + err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, + dentry); + } + dput(h_path.dentry); + +out: + return err; +} + +static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent, void *arg) +{ + int err, rerr; + aufs_bindex_t bopq, bstart; + struct path h_path; + struct dentry *parent; + struct inode *h_dir, *h_inode, *inode, *dir; + unsigned int *flags = arg; + + bstart = au_dbstart(dentry); + /* dentry is di-locked */ + parent = dget_parent(dentry); + dir = parent->d_inode; + h_dir = h_parent->d_inode; + AuDebugOn(h_dir != au_h_iptr(dir, bdst)); + IMustLock(h_dir); + + err = au_lkup_neg(dentry, bdst, /*wh*/0); + if (unlikely(err < 0)) + goto out; + h_path.dentry = au_h_dptr(dentry, bdst); + h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); + err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, + S_IRWXU | S_IRUGO | S_IXUGO); + if (unlikely(err)) + goto out_put; + au_fset_cpdown(*flags, MADE_DIR); + + bopq = au_dbdiropq(dentry); + au_fclr_cpdown(*flags, WHED); + au_fclr_cpdown(*flags, DIROPQ); + if (au_dbwh(dentry) == bdst) + au_fset_cpdown(*flags, WHED); + if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) + au_fset_cpdown(*flags, PARENT_OPQ); + h_inode = h_path.dentry->d_inode; + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + if (au_ftest_cpdown(*flags, WHED)) { + err = au_cpdown_dir_opq(dentry, bdst, flags); + if (unlikely(err)) { + mutex_unlock(&h_inode->i_mutex); + goto out_dir; + } + } + + err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart)); + mutex_unlock(&h_inode->i_mutex); + if (unlikely(err)) + goto out_opq; + + if (au_ftest_cpdown(*flags, WHED)) { + err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); + if (unlikely(err)) + goto out_opq; + } + + inode = dentry->d_inode; + if (au_ibend(inode) < bdst) + au_set_ibend(inode, bdst); + au_set_h_iptr(inode, bdst, au_igrab(h_inode), + au_hi_flags(inode, /*isdir*/1)); + goto out; /* success */ + + /* revert */ +out_opq: + if (au_ftest_cpdown(*flags, DIROPQ)) { + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + rerr = au_diropq_remove(dentry, bdst); + mutex_unlock(&h_inode->i_mutex); + if (unlikely(rerr)) { + AuIOErr("failed removing diropq for %pd b%d (%d)\n", + dentry, bdst, rerr); + err = -EIO; + goto out; + } + } +out_dir: + if (au_ftest_cpdown(*flags, MADE_DIR)) { + rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); + if (unlikely(rerr)) { + AuIOErr("failed removing %pd b%d (%d)\n", + dentry, bdst, rerr); + err = -EIO; + } + } +out_put: + au_set_h_dptr(dentry, bdst, NULL); + if (au_dbend(dentry) == bdst) + au_update_dbend(dentry); +out: + dput(parent); + return err; +} + +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + int err; + unsigned int flags; + + flags = 0; + err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* policies for create */ + +int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) +{ + int err, i, j, ndentry; + aufs_bindex_t bopq; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries, *parent, *d; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + parent = dget_parent(dentry); + err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); + if (unlikely(err)) + goto out_free; + + err = bindex; + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + d = dentries[j]; + di_read_lock_parent2(d, !AuLock_IR); + bopq = au_dbdiropq(d); + di_read_unlock(d, !AuLock_IR); + if (bopq >= 0 && bopq < err) + err = bopq; + } + } + +out_free: + dput(parent); + au_dpages_free(&dpages); +out: + return err; +} + +static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) +{ + for (; bindex >= 0; bindex--) + if (!au_br_rdonly(au_sbr(sb, bindex))) + return bindex; + return -EROFS; +} + +/* top down parent */ +static int au_wbr_create_tdp(struct dentry *dentry, + unsigned int flags __maybe_unused) +{ + int err; + aufs_bindex_t bstart, bindex; + struct super_block *sb; + struct dentry *parent, *h_parent; + + sb = dentry->d_sb; + bstart = au_dbstart(dentry); + err = bstart; + if (!au_br_rdonly(au_sbr(sb, bstart))) + goto out; + + err = -EROFS; + parent = dget_parent(dentry); + for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || !h_parent->d_inode) + continue; + + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = bindex; + break; + } + } + dput(parent); + + /* bottom up here */ + if (unlikely(err < 0)) { + err = au_wbr_bu(sb, bstart - 1); + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + } + +out: + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* an exception for the policy other than tdp */ +static int au_wbr_create_exp(struct dentry *dentry) +{ + int err; + aufs_bindex_t bwh, bdiropq; + struct dentry *parent; + + err = -1; + bwh = au_dbwh(dentry); + parent = dget_parent(dentry); + bdiropq = au_dbdiropq(parent); + if (bwh >= 0) { + if (bdiropq >= 0) + err = min(bdiropq, bwh); + else + err = bwh; + AuDbg("%d\n", err); + } else if (bdiropq >= 0) { + err = bdiropq; + AuDbg("%d\n", err); + } + dput(parent); + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + + if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) + err = -1; + + AuDbg("%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* round robin */ +static int au_wbr_create_init_rr(struct super_block *sb) +{ + int err; + + err = au_wbr_bu(sb, au_sbend(sb)); + atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ + /* smp_mb(); */ + + AuDbg("b%d\n", err); + return err; +} + +static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) +{ + int err, nbr; + unsigned int u; + aufs_bindex_t bindex, bend; + struct super_block *sb; + atomic_t *next; + + err = au_wbr_create_exp(dentry); + if (err >= 0) + goto out; + + sb = dentry->d_sb; + next = &au_sbi(sb)->si_wbr_rr_next; + bend = au_sbend(sb); + nbr = bend + 1; + for (bindex = 0; bindex <= bend; bindex++) { + if (!au_ftest_wbr(flags, DIR)) { + err = atomic_dec_return(next) + 1; + /* modulo for 0 is meaningless */ + if (unlikely(!err)) + err = atomic_dec_return(next) + 1; + } else + err = atomic_read(next); + AuDbg("%d\n", err); + u = err; + err = u % nbr; + AuDbg("%d\n", err); + if (!au_br_rdonly(au_sbr(sb, err))) + break; + err = -EROFS; + } + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + +out: + AuDbg("%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* most free space */ +static void au_mfs(struct dentry *dentry, struct dentry *parent) +{ + struct super_block *sb; + struct au_branch *br; + struct au_wbr_mfs *mfs; + struct dentry *h_parent; + aufs_bindex_t bindex, bend; + int err; + unsigned long long b, bavail; + struct path h_path; + /* reduce the stack usage */ + struct kstatfs *st; + + st = kmalloc(sizeof(*st), GFP_NOFS); + if (unlikely(!st)) { + AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); + return; + } + + bavail = 0; + sb = dentry->d_sb; + mfs = &au_sbi(sb)->si_wbr_mfs; + MtxMustLock(&mfs->mfs_lock); + mfs->mfs_bindex = -EROFS; + mfs->mfsrr_bytes = 0; + if (!parent) { + bindex = 0; + bend = au_sbend(sb); + } else { + bindex = au_dbstart(parent); + bend = au_dbtaildir(parent); + } + + for (; bindex <= bend; bindex++) { + if (parent) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || !h_parent->d_inode) + continue; + } + br = au_sbr(sb, bindex); + if (au_br_rdonly(br)) + continue; + + /* sb->s_root for NFS is unreliable */ + h_path.mnt = au_br_mnt(br); + h_path.dentry = h_path.mnt->mnt_root; + err = vfs_statfs(&h_path, st); + if (unlikely(err)) { + AuWarn1("failed statfs, b%d, %d\n", bindex, err); + continue; + } + + /* when the available size is equal, select the lower one */ + BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) + || sizeof(b) < sizeof(st->f_bsize)); + b = st->f_bavail * st->f_bsize; + br->br_wbr->wbr_bytes = b; + if (b >= bavail) { + bavail = b; + mfs->mfs_bindex = bindex; + mfs->mfs_jiffy = jiffies; + } + } + + mfs->mfsrr_bytes = bavail; + AuDbg("b%d\n", mfs->mfs_bindex); + kfree(st); +} + +static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) +{ + int err; + struct dentry *parent; + struct super_block *sb; + struct au_wbr_mfs *mfs; + + err = au_wbr_create_exp(dentry); + if (err >= 0) + goto out; + + sb = dentry->d_sb; + parent = NULL; + if (au_ftest_wbr(flags, PARENT)) + parent = dget_parent(dentry); + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) + || mfs->mfs_bindex < 0 + || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) + au_mfs(dentry, parent); + mutex_unlock(&mfs->mfs_lock); + err = mfs->mfs_bindex; + dput(parent); + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + +out: + AuDbg("b%d\n", err); + return err; +} + +static int au_wbr_create_init_mfs(struct super_block *sb) +{ + struct au_wbr_mfs *mfs; + + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_init(&mfs->mfs_lock); + mfs->mfs_jiffy = 0; + mfs->mfs_bindex = -EROFS; + + return 0; +} + +static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) +{ + mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +/* most free space and then round robin */ +static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) +{ + int err; + struct au_wbr_mfs *mfs; + + err = au_wbr_create_mfs(dentry, flags); + if (err >= 0) { + mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) + err = au_wbr_create_rr(dentry, flags); + mutex_unlock(&mfs->mfs_lock); + } + + AuDbg("b%d\n", err); + return err; +} + +static int au_wbr_create_init_mfsrr(struct super_block *sb) +{ + int err; + + au_wbr_create_init_mfs(sb); /* ignore */ + err = au_wbr_create_init_rr(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* top down parent and most free space */ +static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) +{ + int err, e2; + unsigned long long b; + aufs_bindex_t bindex, bstart, bend; + struct super_block *sb; + struct dentry *parent, *h_parent; + struct au_branch *br; + + err = au_wbr_create_tdp(dentry, flags); + if (unlikely(err < 0)) + goto out; + parent = dget_parent(dentry); + bstart = au_dbstart(parent); + bend = au_dbtaildir(parent); + if (bstart == bend) + goto out_parent; /* success */ + + e2 = au_wbr_create_mfs(dentry, flags); + if (e2 < 0) + goto out_parent; /* success */ + + /* when the available size is equal, select upper one */ + sb = dentry->d_sb; + br = au_sbr(sb, err); + b = br->br_wbr->wbr_bytes; + AuDbg("b%d, %llu\n", err, b); + + for (bindex = bstart; bindex <= bend; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || !h_parent->d_inode) + continue; + + br = au_sbr(sb, bindex); + if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { + b = br->br_wbr->wbr_bytes; + err = bindex; + AuDbg("b%d, %llu\n", err, b); + } + } + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + +out_parent: + dput(parent); +out: + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * - top down parent + * - most free space with parent + * - most free space round-robin regardless parent + */ +static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) +{ + int err; + unsigned long long watermark; + struct super_block *sb; + struct au_branch *br; + struct au_wbr_mfs *mfs; + + err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); + if (unlikely(err < 0)) + goto out; + + sb = dentry->d_sb; + br = au_sbr(sb, err); + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + watermark = mfs->mfsrr_watermark; + mutex_unlock(&mfs->mfs_lock); + if (br->br_wbr->wbr_bytes < watermark) + /* regardless the parent dir */ + err = au_wbr_create_mfsrr(dentry, flags); + +out: + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* policies for copyup */ + +/* top down parent */ +static int au_wbr_copyup_tdp(struct dentry *dentry) +{ + return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); +} + +/* bottom up parent */ +static int au_wbr_copyup_bup(struct dentry *dentry) +{ + int err; + aufs_bindex_t bindex, bstart; + struct dentry *parent, *h_parent; + struct super_block *sb; + + err = -EROFS; + sb = dentry->d_sb; + parent = dget_parent(dentry); + bstart = au_dbstart(parent); + for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || !h_parent->d_inode) + continue; + + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = bindex; + break; + } + } + dput(parent); + + /* bottom up here */ + if (unlikely(err < 0)) + err = au_wbr_bu(sb, bstart - 1); + + AuDbg("b%d\n", err); + return err; +} + +/* bottom up */ +static int au_wbr_copyup_bu(struct dentry *dentry) +{ + int err; + aufs_bindex_t bstart; + + bstart = au_dbstart(dentry); + err = au_wbr_bu(dentry->d_sb, bstart); + AuDbg("b%d\n", err); + if (err > bstart) + err = au_wbr_nonopq(dentry, err); + + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { + [AuWbrCopyup_TDP] = { + .copyup = au_wbr_copyup_tdp + }, + [AuWbrCopyup_BUP] = { + .copyup = au_wbr_copyup_bup + }, + [AuWbrCopyup_BU] = { + .copyup = au_wbr_copyup_bu + } +}; + +struct au_wbr_create_operations au_wbr_create_ops[] = { + [AuWbrCreate_TDP] = { + .create = au_wbr_create_tdp + }, + [AuWbrCreate_RR] = { + .create = au_wbr_create_rr, + .init = au_wbr_create_init_rr + }, + [AuWbrCreate_MFS] = { + .create = au_wbr_create_mfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSV] = { + .create = au_wbr_create_mfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSRR] = { + .create = au_wbr_create_mfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSRRV] = { + .create = au_wbr_create_mfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFS] = { + .create = au_wbr_create_pmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFSV] = { + .create = au_wbr_create_pmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFSRR] = { + .create = au_wbr_create_pmfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFSRRV] = { + .create = au_wbr_create_pmfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + } +}; --- linux-3.13.0.orig/ubuntu/aufs/module.c +++ linux-3.13.0/ubuntu/aufs/module.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * module global variables and operations + */ + +#include +#include +#include "aufs.h" + +void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) +{ + if (new_sz <= nused) + return p; + + p = krealloc(p, new_sz, gfp); + if (p) + memset(p + nused, 0, new_sz - nused); + return p; +} + +/* ---------------------------------------------------------------------- */ + +/* + * aufs caches + */ +struct kmem_cache *au_cachep[AuCache_Last]; +static int __init au_cache_init(void) +{ + au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); + if (au_cachep[AuCache_DINFO]) + /* SLAB_DESTROY_BY_RCU */ + au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, + au_icntnr_init_once); + if (au_cachep[AuCache_ICNTNR]) + au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo, + au_fi_init_once); + if (au_cachep[AuCache_FINFO]) + au_cachep[AuCache_VDIR] = AuCache(au_vdir); + if (au_cachep[AuCache_VDIR]) + au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); + if (au_cachep[AuCache_DEHSTR]) + return 0; + + return -ENOMEM; +} + +static void au_cache_fin(void) +{ + int i; + + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); + + /* excluding AuCache_HNOTIFY */ + BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); + for (i = 0; i < AuCache_HNOTIFY; i++) + if (au_cachep[i]) { + kmem_cache_destroy(au_cachep[i]); + au_cachep[i] = NULL; + } +} + +/* ---------------------------------------------------------------------- */ + +int au_dir_roflags; + +#ifdef CONFIG_AUFS_SBILIST +/* + * iterate_supers_type() doesn't protect us from + * remounting (branch management) + */ +struct au_splhead au_sbilist; +#endif + +struct lock_class_key au_lc_key[AuLcKey_Last]; + +/* + * functions for module interface. + */ +MODULE_LICENSE("GPL"); +/* MODULE_LICENSE("GPL v2"); */ +MODULE_AUTHOR("Junjiro R. Okajima "); +MODULE_DESCRIPTION(AUFS_NAME + " -- Advanced multi layered unification filesystem"); +MODULE_VERSION(AUFS_VERSION); +MODULE_ALIAS_FS(AUFS_NAME); + +/* this module parameter has no meaning when SYSFS is disabled */ +int sysaufs_brs = 1; +MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); +module_param_named(brs, sysaufs_brs, int, S_IRUGO); + +/* ---------------------------------------------------------------------- */ + +static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ + +int au_seq_path(struct seq_file *seq, struct path *path) +{ + return seq_path(seq, path, au_esc_chars); +} + +/* ---------------------------------------------------------------------- */ + +static int __init aufs_init(void) +{ + int err, i; + char *p; + + p = au_esc_chars; + for (i = 1; i <= ' '; i++) + *p++ = i; + *p++ = '\\'; + *p++ = '\x7f'; + *p = 0; + + au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); + + au_sbilist_init(); + sysaufs_brs_init(); + au_debug_init(); + au_dy_init(); + err = sysaufs_init(); + if (unlikely(err)) + goto out; + err = au_procfs_init(); + if (unlikely(err)) + goto out_sysaufs; + err = au_wkq_init(); + if (unlikely(err)) + goto out_procfs; + err = au_loopback_init(); + if (unlikely(err)) + goto out_wkq; + err = au_hnotify_init(); + if (unlikely(err)) + goto out_loopback; + err = au_sysrq_init(); + if (unlikely(err)) + goto out_hin; + err = au_cache_init(); + if (unlikely(err)) + goto out_sysrq; + err = register_filesystem(&aufs_fs_type); + if (unlikely(err)) + goto out_cache; + /* since we define pr_fmt, call printk directly */ + printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); + goto out; /* success */ + +out_cache: + au_cache_fin(); +out_sysrq: + au_sysrq_fin(); +out_hin: + au_hnotify_fin(); +out_loopback: + au_loopback_fin(); +out_wkq: + au_wkq_fin(); +out_procfs: + au_procfs_fin(); +out_sysaufs: + sysaufs_fin(); + au_dy_fin(); +out: + return err; +} + +static void __exit aufs_exit(void) +{ + unregister_filesystem(&aufs_fs_type); + au_cache_fin(); + au_sysrq_fin(); + au_hnotify_fin(); + au_loopback_fin(); + au_wkq_fin(); + au_procfs_fin(); + sysaufs_fin(); + au_dy_fin(); +} + +module_init(aufs_init); +module_exit(aufs_exit); --- linux-3.13.0.orig/ubuntu/aufs/module.h +++ linux-3.13.0/ubuntu/aufs/module.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * module initialization and module-global + */ + +#ifndef __AUFS_MODULE_H__ +#define __AUFS_MODULE_H__ + +#ifdef __KERNEL__ + +#include + +struct path; +struct seq_file; + +/* module parameters */ +extern int sysaufs_brs; + +/* ---------------------------------------------------------------------- */ + +extern int au_dir_roflags; + +enum { + AuLcNonDir_FIINFO, + AuLcNonDir_DIINFO, + AuLcNonDir_IIINFO, + + AuLcDir_FIINFO, + AuLcDir_DIINFO, + AuLcDir_IIINFO, + + AuLcSymlink_DIINFO, + AuLcSymlink_IIINFO, + + AuLcKey_Last +}; +extern struct lock_class_key au_lc_key[AuLcKey_Last]; + +void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); +int au_seq_path(struct seq_file *seq, struct path *path); + +#ifdef CONFIG_PROC_FS +/* procfs.c */ +int __init au_procfs_init(void); +void au_procfs_fin(void); +#else +AuStubInt0(au_procfs_init, void); +AuStubVoid(au_procfs_fin, void); +#endif + +/* ---------------------------------------------------------------------- */ + +/* kmem cache */ +enum { + AuCache_DINFO, + AuCache_ICNTNR, + AuCache_FINFO, + AuCache_VDIR, + AuCache_DEHSTR, + AuCache_HNOTIFY, /* must be last */ + AuCache_Last +}; + +#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) +#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) +#define AuCacheCtor(type, ctor) \ + kmem_cache_create(#type, sizeof(struct type), \ + __alignof__(struct type), AuCacheFlags, ctor) + +extern struct kmem_cache *au_cachep[]; + +#define AuCacheFuncs(name, index) \ +static inline struct au_##name *au_cache_alloc_##name(void) \ +{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \ +static inline void au_cache_free_##name(struct au_##name *p) \ +{ kmem_cache_free(au_cachep[AuCache_##index], p); } + +AuCacheFuncs(dinfo, DINFO); +AuCacheFuncs(icntnr, ICNTNR); +AuCacheFuncs(finfo, FINFO); +AuCacheFuncs(vdir, VDIR); +AuCacheFuncs(vdir_dehstr, DEHSTR); +#ifdef CONFIG_AUFS_HNOTIFY +AuCacheFuncs(hnotify, HNOTIFY); +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_MODULE_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/poll.c +++ linux-3.13.0/ubuntu/aufs/poll.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * poll operation + * There is only one filesystem which implements ->poll operation, currently. + */ + +#include "aufs.h" + +unsigned int aufs_poll(struct file *file, poll_table *wait) +{ + unsigned int mask; + int err; + struct file *h_file; + struct dentry *dentry; + struct super_block *sb; + + /* We should pretend an error happened. */ + mask = POLLERR /* | POLLIN | POLLOUT */; + dentry = file->f_dentry; + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); + if (unlikely(err)) + goto out; + + /* it is not an error if h_file has no operation */ + mask = DEFAULT_POLLMASK; + h_file = au_hf_top(file); + if (h_file->f_op->poll) + mask = h_file->f_op->poll(h_file, wait); + + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + +out: + si_read_unlock(sb); + AuTraceErr((int)mask); + return mask; +} --- linux-3.13.0.orig/ubuntu/aufs/plink.c +++ linux-3.13.0/ubuntu/aufs/plink.c @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * pseudo-link + */ + +#include "aufs.h" + +/* + * the pseudo-link maintenance mode. + * during a user process maintains the pseudo-links, + * prohibit adding a new plink and branch manipulation. + * + * Flags + * NOPLM: + * For entry functions which will handle plink, and i_mutex is already held + * in VFS. + * They cannot wait and should return an error at once. + * Callers has to check the error. + * NOPLMW: + * For entry functions which will handle plink, but i_mutex is not held + * in VFS. + * They can wait the plink maintenance mode to finish. + * + * They behave like F_SETLK and F_SETLKW. + * If the caller never handle plink, then both flags are unnecessary. + */ + +int au_plink_maint(struct super_block *sb, int flags) +{ + int err; + pid_t pid, ppid; + struct au_sbinfo *sbi; + + SiMustAnyLock(sb); + + err = 0; + if (!au_opt_test(au_mntflags(sb), PLINK)) + goto out; + + sbi = au_sbi(sb); + pid = sbi->si_plink_maint_pid; + if (!pid || pid == current->pid) + goto out; + + /* todo: it highly depends upon /sbin/mount.aufs */ + rcu_read_lock(); + ppid = task_pid_vnr(rcu_dereference(current->real_parent)); + rcu_read_unlock(); + if (pid == ppid) + goto out; + + if (au_ftest_lock(flags, NOPLMW)) { + /* if there is no i_mutex lock in VFS, we don't need to wait */ + /* AuDebugOn(!lockdep_depth(current)); */ + while (sbi->si_plink_maint_pid) { + si_read_unlock(sb); + /* gave up wake_up_bit() */ + wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); + + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&sbi->si_nowait); + si_noflush_read_lock(sb); + } + } else if (au_ftest_lock(flags, NOPLM)) { + AuDbg("ppid %d, pid %d\n", ppid, pid); + err = -EAGAIN; + } + +out: + return err; +} + +void au_plink_maint_leave(struct au_sbinfo *sbinfo) +{ + spin_lock(&sbinfo->si_plink_maint_lock); + sbinfo->si_plink_maint_pid = 0; + spin_unlock(&sbinfo->si_plink_maint_lock); + wake_up_all(&sbinfo->si_plink_wq); +} + +int au_plink_maint_enter(struct super_block *sb) +{ + int err; + struct au_sbinfo *sbinfo; + + err = 0; + sbinfo = au_sbi(sb); + /* make sure i am the only one in this fs */ + si_write_lock(sb, AuLock_FLUSH); + if (au_opt_test(au_mntflags(sb), PLINK)) { + spin_lock(&sbinfo->si_plink_maint_lock); + if (!sbinfo->si_plink_maint_pid) + sbinfo->si_plink_maint_pid = current->pid; + else + err = -EBUSY; + spin_unlock(&sbinfo->si_plink_maint_lock); + } + si_write_unlock(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_DEBUG +void au_plink_list(struct super_block *sb) +{ + int i; + struct au_sbinfo *sbinfo; + struct hlist_head *plink_hlist; + struct pseudo_link *plink; + + SiMustAnyLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + for (i = 0; i < AuPlink_NHASH; i++) { + plink_hlist = &sbinfo->si_plink[i].head; + rcu_read_lock(); + hlist_for_each_entry_rcu(plink, plink_hlist, hlist) + AuDbg("%lu\n", plink->inode->i_ino); + rcu_read_unlock(); + } +} +#endif + +/* is the inode pseudo-linked? */ +int au_plink_test(struct inode *inode) +{ + int found, i; + struct au_sbinfo *sbinfo; + struct hlist_head *plink_hlist; + struct pseudo_link *plink; + + sbinfo = au_sbi(inode->i_sb); + AuRwMustAnyLock(&sbinfo->si_rwsem); + AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); + AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); + + found = 0; + i = au_plink_hash(inode->i_ino); + plink_hlist = &sbinfo->si_plink[i].head; + rcu_read_lock(); + hlist_for_each_entry_rcu(plink, plink_hlist, hlist) + if (plink->inode == inode) { + found = 1; + break; + } + rcu_read_unlock(); + return found; +} + +/* ---------------------------------------------------------------------- */ + +/* + * generate a name for plink. + * the file will be stored under AUFS_WH_PLINKDIR. + */ +/* 20 is max digits length of ulong 64 */ +#define PLINK_NAME_LEN ((20 + 1) * 2) + +static int plink_name(char *name, int len, struct inode *inode, + aufs_bindex_t bindex) +{ + int rlen; + struct inode *h_inode; + + h_inode = au_h_iptr(inode, bindex); + rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); + return rlen; +} + +struct au_do_plink_lkup_args { + struct dentry **errp; + struct qstr *tgtname; + struct dentry *h_parent; + struct au_branch *br; +}; + +static struct dentry *au_do_plink_lkup(struct qstr *tgtname, + struct dentry *h_parent, + struct au_branch *br) +{ + struct dentry *h_dentry; + struct mutex *h_mtx; + + h_mtx = &h_parent->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); + h_dentry = vfsub_lkup_one(tgtname, h_parent); + mutex_unlock(h_mtx); + return h_dentry; +} + +static void au_call_do_plink_lkup(void *args) +{ + struct au_do_plink_lkup_args *a = args; + *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br); +} + +/* lookup the plink-ed @inode under the branch at @bindex */ +struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) +{ + struct dentry *h_dentry, *h_parent; + struct au_branch *br; + struct inode *h_dir; + int wkq_err; + char a[PLINK_NAME_LEN]; + struct qstr tgtname = QSTR_INIT(a, 0); + + AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); + + br = au_sbr(inode->i_sb, bindex); + h_parent = br->br_wbr->wbr_plink; + h_dir = h_parent->d_inode; + tgtname.len = plink_name(a, sizeof(a), inode, bindex); + + if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { + struct au_do_plink_lkup_args args = { + .errp = &h_dentry, + .tgtname = &tgtname, + .h_parent = h_parent, + .br = br + }; + + wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); + if (unlikely(wkq_err)) + h_dentry = ERR_PTR(wkq_err); + } else + h_dentry = au_do_plink_lkup(&tgtname, h_parent, br); + + return h_dentry; +} + +/* create a pseudo-link */ +static int do_whplink(struct qstr *tgt, struct dentry *h_parent, + struct dentry *h_dentry, struct au_branch *br) +{ + int err; + struct path h_path = { + .mnt = au_br_mnt(br) + }; + struct inode *h_dir, *delegated; + + h_dir = h_parent->d_inode; + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); +again: + h_path.dentry = vfsub_lkup_one(tgt, h_parent); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) + goto out; + + err = 0; + /* wh.plink dir is not monitored */ + /* todo: is it really safe? */ + if (h_path.dentry->d_inode + && h_path.dentry->d_inode != h_dentry->d_inode) { + delegated = NULL; + err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + dput(h_path.dentry); + h_path.dentry = NULL; + if (!err) + goto again; + } + if (!err && !h_path.dentry->d_inode) { + delegated = NULL; + err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + } + dput(h_path.dentry); + +out: + mutex_unlock(&h_dir->i_mutex); + return err; +} + +struct do_whplink_args { + int *errp; + struct qstr *tgt; + struct dentry *h_parent; + struct dentry *h_dentry; + struct au_branch *br; +}; + +static void call_do_whplink(void *args) +{ + struct do_whplink_args *a = args; + *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); +} + +static int whplink(struct dentry *h_dentry, struct inode *inode, + aufs_bindex_t bindex, struct au_branch *br) +{ + int err, wkq_err; + struct au_wbr *wbr; + struct dentry *h_parent; + struct inode *h_dir; + char a[PLINK_NAME_LEN]; + struct qstr tgtname = QSTR_INIT(a, 0); + + wbr = au_sbr(inode->i_sb, bindex)->br_wbr; + h_parent = wbr->wbr_plink; + h_dir = h_parent->d_inode; + tgtname.len = plink_name(a, sizeof(a), inode, bindex); + + /* always superio. */ + if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { + struct do_whplink_args args = { + .errp = &err, + .tgt = &tgtname, + .h_parent = h_parent, + .h_dentry = h_dentry, + .br = br + }; + wkq_err = au_wkq_wait(call_do_whplink, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } else + err = do_whplink(&tgtname, h_parent, h_dentry, br); + + return err; +} + +/* free a single plink */ +static void do_put_plink(struct pseudo_link *plink, int do_del) +{ + if (do_del) + hlist_del(&plink->hlist); + iput(plink->inode); + kfree(plink); +} + +static void do_put_plink_rcu(struct rcu_head *rcu) +{ + struct pseudo_link *plink; + + plink = container_of(rcu, struct pseudo_link, rcu); + iput(plink->inode); + kfree(plink); +} + +/* + * create a new pseudo-link for @h_dentry on @bindex. + * the linked inode is held in aufs @inode. + */ +void au_plink_append(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_dentry) +{ + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct hlist_head *plink_hlist; + struct pseudo_link *plink, *tmp; + struct au_sphlhead *sphl; + int found, err, cnt, i; + + sb = inode->i_sb; + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + found = au_plink_test(inode); + if (found) + return; + + i = au_plink_hash(inode->i_ino); + sphl = sbinfo->si_plink + i; + plink_hlist = &sphl->head; + tmp = kmalloc(sizeof(*plink), GFP_NOFS); + if (tmp) + tmp->inode = au_igrab(inode); + else { + err = -ENOMEM; + goto out; + } + + spin_lock(&sphl->spin); + hlist_for_each_entry(plink, plink_hlist, hlist) { + if (plink->inode == inode) { + found = 1; + break; + } + } + if (!found) + hlist_add_head_rcu(&tmp->hlist, plink_hlist); + spin_unlock(&sphl->spin); + if (!found) { + cnt = au_sphl_count(sphl); +#define msg "unexpectedly unblanced or too many pseudo-links" + if (cnt > AUFS_PLINK_WARN) + AuWarn1(msg ", %d\n", cnt); +#undef msg + err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); + } else { + do_put_plink(tmp, 0); + return; + } + +out: + if (unlikely(err)) { + pr_warn("err %d, damaged pseudo link.\n", err); + if (tmp) { + au_sphl_del_rcu(&tmp->hlist, sphl); + call_rcu(&tmp->rcu, do_put_plink_rcu); + } + } +} + +/* free all plinks */ +void au_plink_put(struct super_block *sb, int verbose) +{ + int i, warned; + struct au_sbinfo *sbinfo; + struct hlist_head *plink_hlist; + struct hlist_node *tmp; + struct pseudo_link *plink; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + /* no spin_lock since sbinfo is write-locked */ + warned = 0; + for (i = 0; i < AuPlink_NHASH; i++) { + plink_hlist = &sbinfo->si_plink[i].head; + if (!warned && verbose && !hlist_empty(plink_hlist)) { + pr_warn("pseudo-link is not flushed"); + warned = 1; + } + hlist_for_each_entry_safe(plink, tmp, plink_hlist, hlist) + do_put_plink(plink, 0); + INIT_HLIST_HEAD(plink_hlist); + } +} + +void au_plink_clean(struct super_block *sb, int verbose) +{ + struct dentry *root; + + root = sb->s_root; + aufs_write_lock(root); + if (au_opt_test(au_mntflags(sb), PLINK)) + au_plink_put(sb, verbose); + aufs_write_unlock(root); +} + +static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) +{ + int do_put; + aufs_bindex_t bstart, bend, bindex; + + do_put = 0; + bstart = au_ibstart(inode); + bend = au_ibend(inode); + if (bstart >= 0) { + for (bindex = bstart; bindex <= bend; bindex++) { + if (!au_h_iptr(inode, bindex) + || au_ii_br_id(inode, bindex) != br_id) + continue; + au_set_h_iptr(inode, bindex, NULL, 0); + do_put = 1; + break; + } + if (do_put) + for (bindex = bstart; bindex <= bend; bindex++) + if (au_h_iptr(inode, bindex)) { + do_put = 0; + break; + } + } else + do_put = 1; + + return do_put; +} + +/* free the plinks on a branch specified by @br_id */ +void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) +{ + struct au_sbinfo *sbinfo; + struct hlist_head *plink_hlist; + struct hlist_node *tmp; + struct pseudo_link *plink; + struct inode *inode; + int i, do_put; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + /* no spin_lock since sbinfo is write-locked */ + for (i = 0; i < AuPlink_NHASH; i++) { + plink_hlist = &sbinfo->si_plink[i].head; + hlist_for_each_entry_safe(plink, tmp, plink_hlist, hlist) { + inode = au_igrab(plink->inode); + ii_write_lock_child(inode); + do_put = au_plink_do_half_refresh(inode, br_id); + if (do_put) + do_put_plink(plink, 1); + ii_write_unlock(inode); + iput(inode); + } + } +} --- linux-3.13.0.orig/ubuntu/aufs/dir.h +++ linux-3.13.0/ubuntu/aufs/dir.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * directory operations + */ + +#ifndef __AUFS_DIR_H__ +#define __AUFS_DIR_H__ + +#ifdef __KERNEL__ + +#include + +/* ---------------------------------------------------------------------- */ + +/* need to be faster and smaller */ + +struct au_nhash { + unsigned int nh_num; + struct hlist_head *nh_head; +}; + +struct au_vdir_destr { + unsigned char len; + unsigned char name[0]; +} __packed; + +struct au_vdir_dehstr { + struct hlist_node hash; + struct au_vdir_destr *str; +} ____cacheline_aligned_in_smp; + +struct au_vdir_de { + ino_t de_ino; + unsigned char de_type; + /* caution: packed */ + struct au_vdir_destr de_str; +} __packed; + +struct au_vdir_wh { + struct hlist_node wh_hash; +#ifdef CONFIG_AUFS_SHWH + ino_t wh_ino; + aufs_bindex_t wh_bindex; + unsigned char wh_type; +#else + aufs_bindex_t wh_bindex; +#endif + /* caution: packed */ + struct au_vdir_destr wh_str; +} __packed; + +union au_vdir_deblk_p { + unsigned char *deblk; + struct au_vdir_de *de; +}; + +struct au_vdir { + unsigned char **vd_deblk; + unsigned long vd_nblk; + struct { + unsigned long ul; + union au_vdir_deblk_p p; + } vd_last; + + unsigned long vd_version; + unsigned int vd_deblk_sz; + unsigned long vd_jiffy; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ + +/* dir.c */ +extern const struct file_operations aufs_dir_fop; +void au_add_nlink(struct inode *dir, struct inode *h_dir); +void au_sub_nlink(struct inode *dir, struct inode *h_dir); +loff_t au_dir_size(struct file *file, struct dentry *dentry); +int au_test_empty_lower(struct dentry *dentry); +int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); + +/* vdir.c */ +unsigned int au_rdhash_est(loff_t sz); +int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); +void au_nhash_wh_free(struct au_nhash *whlist); +int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, + int limit); +int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); +int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, + unsigned int d_type, aufs_bindex_t bindex, + unsigned char shwh); +void au_vdir_free(struct au_vdir *vdir); +int au_vdir_init(struct file *file); +int au_vdir_fill_de(struct file *file, struct dir_context *ctx); + +/* ioctl.c */ +long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); + +#ifdef CONFIG_AUFS_RDU +/* rdu.c */ +long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); +#endif +#else +static inline long au_rdu_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return -EINVAL; +} +#ifdef CONFIG_COMPAT +static inline long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return -EINVAL; +} +#endif +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DIR_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/super.h +++ linux-3.13.0/ubuntu/aufs/super.h @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * super_block operations + */ + +#ifndef __AUFS_SUPER_H__ +#define __AUFS_SUPER_H__ + +#ifdef __KERNEL__ + +#include +#include "rwsem.h" +#include "spl.h" +#include "wkq.h" + +typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *); +typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t, + loff_t *); + +/* policies to select one among multiple writable branches */ +struct au_wbr_copyup_operations { + int (*copyup)(struct dentry *dentry); +}; + +#define AuWbr_DIR 1 /* target is a dir */ +#define AuWbr_PARENT (1 << 1) /* always require a parent */ + +#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) +#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } +#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } + +struct au_wbr_create_operations { + int (*create)(struct dentry *dentry, unsigned int flags); + int (*init)(struct super_block *sb); + int (*fin)(struct super_block *sb); +}; + +struct au_wbr_mfs { + struct mutex mfs_lock; /* protect this structure */ + unsigned long mfs_jiffy; + unsigned long mfs_expire; + aufs_bindex_t mfs_bindex; + + unsigned long long mfsrr_bytes; + unsigned long long mfsrr_watermark; +}; + +struct pseudo_link { + union { + struct hlist_node hlist; + struct rcu_head rcu; + }; + struct inode *inode; +}; + +#define AuPlink_NHASH 100 +static inline int au_plink_hash(ino_t ino) +{ + return ino % AuPlink_NHASH; +} + +struct au_branch; +struct au_sbinfo { + /* nowait tasks in the system-wide workqueue */ + struct au_nowait_tasks si_nowait; + + /* + * tried sb->s_umount, but failed due to the dependecy between i_mutex. + * rwsem for au_sbinfo is necessary. + */ + struct au_rwsem si_rwsem; + + /* prevent recursive locking in deleting inode */ + struct { + unsigned long *bitmap; + spinlock_t tree_lock; + struct radix_tree_root tree; + } au_si_pid; + + /* + * dirty approach to protect sb->sb_inodes and ->s_files (gone) from + * remount. + */ + atomic_long_t si_ninodes, si_nfiles; + + /* branch management */ + unsigned int si_generation; + + /* see above flags */ + unsigned char au_si_status; + + aufs_bindex_t si_bend; + + /* dirty trick to keep br_id plus */ + unsigned int si_last_br_id : + sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; + struct au_branch **si_branch; + + /* policy to select a writable branch */ + unsigned char si_wbr_copyup; + unsigned char si_wbr_create; + struct au_wbr_copyup_operations *si_wbr_copyup_ops; + struct au_wbr_create_operations *si_wbr_create_ops; + + /* round robin */ + atomic_t si_wbr_rr_next; + + /* most free space */ + struct au_wbr_mfs si_wbr_mfs; + + /* mount flags */ + /* include/asm-ia64/siginfo.h defines a macro named si_flags */ + unsigned int si_mntflags; + + /* external inode number (bitmap and translation table) */ + au_readf_t si_xread; + au_writef_t si_xwrite; + struct file *si_xib; + struct mutex si_xib_mtx; /* protect xib members */ + unsigned long *si_xib_buf; + unsigned long si_xib_last_pindex; + int si_xib_next_bit; + aufs_bindex_t si_xino_brid; + unsigned long si_xino_jiffy; + unsigned long si_xino_expire; + /* reserved for future use */ + /* unsigned long long si_xib_limit; */ /* Max xib file size */ + +#ifdef CONFIG_AUFS_EXPORT + /* i_generation */ + struct file *si_xigen; + atomic_t si_xigen_next; +#endif + + /* vdir parameters */ + unsigned long si_rdcache; /* max cache time in jiffies */ + unsigned int si_rdblk; /* deblk size */ + unsigned int si_rdhash; /* hash size */ + + /* + * If the number of whiteouts are larger than si_dirwh, leave all of + * them after au_whtmp_ren to reduce the cost of rmdir(2). + * future fsck.aufs or kernel thread will remove them later. + * Otherwise, remove all whiteouts and the dir in rmdir(2). + */ + unsigned int si_dirwh; + + /* + * rename(2) a directory with all children. + */ + /* reserved for future use */ + /* int si_rendir; */ + + /* pseudo_link list */ + struct au_sphlhead si_plink[AuPlink_NHASH]; + wait_queue_head_t si_plink_wq; + spinlock_t si_plink_maint_lock; + pid_t si_plink_maint_pid; + + /* file list */ + struct au_sphlhead si_files; + + /* + * sysfs and lifetime management. + * this is not a small structure and it may be a waste of memory in case + * of sysfs is disabled, particulary when many aufs-es are mounted. + * but using sysfs is majority. + */ + struct kobject si_kobj; +#ifdef CONFIG_DEBUG_FS + struct dentry *si_dbgaufs; + struct dentry *si_dbgaufs_plink; + struct dentry *si_dbgaufs_xib; +#ifdef CONFIG_AUFS_EXPORT + struct dentry *si_dbgaufs_xigen; +#endif +#endif + +#ifdef CONFIG_AUFS_SBILIST + struct list_head si_list; +#endif + + /* dirty, necessary for unmounting, sysfs and sysrq */ + struct super_block *si_sb; +}; + +/* sbinfo status flags */ +/* + * set true when refresh_dirs() failed at remount time. + * then try refreshing dirs at access time again. + * if it is false, refreshing dirs at access time is unnecesary + */ +#define AuSi_FAILED_REFRESH_DIR 1 +static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, + unsigned int flag) +{ + AuRwMustAnyLock(&sbi->si_rwsem); + return sbi->au_si_status & flag; +} +#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) +#define au_fset_si(sbinfo, name) do { \ + AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ + (sbinfo)->au_si_status |= AuSi_##name; \ +} while (0) +#define au_fclr_si(sbinfo, name) do { \ + AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ + (sbinfo)->au_si_status &= ~AuSi_##name; \ +} while (0) + +/* ---------------------------------------------------------------------- */ + +/* policy to select one among writable branches */ +#define AuWbrCopyup(sbinfo, ...) \ + ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) +#define AuWbrCreate(sbinfo, ...) \ + ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) + +/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ +#define AuLock_DW 1 /* write-lock dentry */ +#define AuLock_IR (1 << 1) /* read-lock inode */ +#define AuLock_IW (1 << 2) /* write-lock inode */ +#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ +#define AuLock_DIR (1 << 4) /* target is a dir */ +#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ +#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ +#define AuLock_GEN (1 << 7) /* test digen/iigen */ +#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) +#define au_fset_lock(flags, name) \ + do { (flags) |= AuLock_##name; } while (0) +#define au_fclr_lock(flags, name) \ + do { (flags) &= ~AuLock_##name; } while (0) + +/* ---------------------------------------------------------------------- */ + +/* super.c */ +extern struct file_system_type aufs_fs_type; +struct inode *au_iget_locked(struct super_block *sb, ino_t ino); +typedef unsigned long long (*au_arraycb_t)(void *array, unsigned long long max, + void *arg); +void au_array_free(void *array); +void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg); +struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); +void au_iarray_free(struct inode **a, unsigned long long max); + +/* sbinfo.c */ +void au_si_free(struct kobject *kobj); +int au_si_alloc(struct super_block *sb); +int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr); + +unsigned int au_sigen_inc(struct super_block *sb); +aufs_bindex_t au_new_br_id(struct super_block *sb); + +int si_read_lock(struct super_block *sb, int flags); +int si_write_lock(struct super_block *sb, int flags); +int aufs_read_lock(struct dentry *dentry, int flags); +void aufs_read_unlock(struct dentry *dentry, int flags); +void aufs_write_lock(struct dentry *dentry); +void aufs_write_unlock(struct dentry *dentry); +int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); +void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); + +int si_pid_test_slow(struct super_block *sb); +void si_pid_set_slow(struct super_block *sb); +void si_pid_clr_slow(struct super_block *sb); + +/* wbr_policy.c */ +extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; +extern struct au_wbr_create_operations au_wbr_create_ops[]; +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); +int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); + +/* mvdown.c */ +int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); + +/* ---------------------------------------------------------------------- */ + +static inline struct au_sbinfo *au_sbi(struct super_block *sb) +{ + return sb->s_fs_info; +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_EXPORT +int au_test_nfsd(void); +void au_export_init(struct super_block *sb); +void au_xigen_inc(struct inode *inode); +int au_xigen_new(struct inode *inode); +int au_xigen_set(struct super_block *sb, struct file *base); +void au_xigen_clr(struct super_block *sb); + +static inline int au_busy_or_stale(void) +{ + if (!au_test_nfsd()) + return -EBUSY; + return -ESTALE; +} +#else +AuStubInt0(au_test_nfsd, void) +AuStubVoid(au_export_init, struct super_block *sb) +AuStubVoid(au_xigen_inc, struct inode *inode) +AuStubInt0(au_xigen_new, struct inode *inode) +AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base) +AuStubVoid(au_xigen_clr, struct super_block *sb) +static inline int au_busy_or_stale(void) +{ + return -EBUSY; +} +#endif /* CONFIG_AUFS_EXPORT */ + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_SBILIST +/* module.c */ +extern struct au_splhead au_sbilist; + +static inline void au_sbilist_init(void) +{ + au_spl_init(&au_sbilist); +} + +static inline void au_sbilist_add(struct super_block *sb) +{ + au_spl_add(&au_sbi(sb)->si_list, &au_sbilist); +} + +static inline void au_sbilist_del(struct super_block *sb) +{ + au_spl_del(&au_sbi(sb)->si_list, &au_sbilist); +} + +#ifdef CONFIG_AUFS_MAGIC_SYSRQ +static inline void au_sbilist_lock(void) +{ + spin_lock(&au_sbilist.spin); +} + +static inline void au_sbilist_unlock(void) +{ + spin_unlock(&au_sbilist.spin); +} +#define AuGFP_SBILIST GFP_ATOMIC +#else +AuStubVoid(au_sbilist_lock, void) +AuStubVoid(au_sbilist_unlock, void) +#define AuGFP_SBILIST GFP_NOFS +#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ +#else +AuStubVoid(au_sbilist_init, void) +AuStubVoid(au_sbilist_add, struct super_block*) +AuStubVoid(au_sbilist_del, struct super_block*) +AuStubVoid(au_sbilist_lock, void) +AuStubVoid(au_sbilist_unlock, void) +#define AuGFP_SBILIST GFP_NOFS +#endif + +/* ---------------------------------------------------------------------- */ + +static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) +{ + /* + * This function is a dynamic '__init' fucntion actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ +#ifdef CONFIG_DEBUG_FS + sbinfo->si_dbgaufs = NULL; + sbinfo->si_dbgaufs_plink = NULL; + sbinfo->si_dbgaufs_xib = NULL; +#ifdef CONFIG_AUFS_EXPORT + sbinfo->si_dbgaufs_xigen = NULL; +#endif +#endif +} + +/* ---------------------------------------------------------------------- */ + +static inline pid_t si_pid_bit(void) +{ + /* the origin of pid is 1, but the bitmap's is 0 */ + return current->pid - 1; +} + +static inline int si_pid_test(struct super_block *sb) +{ + pid_t bit = si_pid_bit(); + if (bit < PID_MAX_DEFAULT) + return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap); + else + return si_pid_test_slow(sb); +} + +static inline void si_pid_set(struct super_block *sb) +{ + pid_t bit = si_pid_bit(); + if (bit < PID_MAX_DEFAULT) { + AuDebugOn(test_bit(bit, au_sbi(sb)->au_si_pid.bitmap)); + set_bit(bit, au_sbi(sb)->au_si_pid.bitmap); + /* smp_mb(); */ + } else + si_pid_set_slow(sb); +} + +static inline void si_pid_clr(struct super_block *sb) +{ + pid_t bit = si_pid_bit(); + if (bit < PID_MAX_DEFAULT) { + AuDebugOn(!test_bit(bit, au_sbi(sb)->au_si_pid.bitmap)); + clear_bit(bit, au_sbi(sb)->au_si_pid.bitmap); + /* smp_mb(); */ + } else + si_pid_clr_slow(sb); +} + +/* ---------------------------------------------------------------------- */ + +/* lock superblock. mainly for entry point functions */ +/* + * __si_read_lock, __si_write_lock, + * __si_read_unlock, __si_write_unlock, __si_downgrade_lock + */ +AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem); + +#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) +#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) +#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) + +static inline void si_noflush_read_lock(struct super_block *sb) +{ + __si_read_lock(sb); + si_pid_set(sb); +} + +static inline int si_noflush_read_trylock(struct super_block *sb) +{ + int locked = __si_read_trylock(sb); + if (locked) + si_pid_set(sb); + return locked; +} + +static inline void si_noflush_write_lock(struct super_block *sb) +{ + __si_write_lock(sb); + si_pid_set(sb); +} + +static inline int si_noflush_write_trylock(struct super_block *sb) +{ + int locked = __si_write_trylock(sb); + if (locked) + si_pid_set(sb); + return locked; +} + +#if 0 /* unused */ +static inline int si_read_trylock(struct super_block *sb, int flags) +{ + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + return si_noflush_read_trylock(sb); +} +#endif + +static inline void si_read_unlock(struct super_block *sb) +{ + si_pid_clr(sb); + __si_read_unlock(sb); +} + +#if 0 /* unused */ +static inline int si_write_trylock(struct super_block *sb, int flags) +{ + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + return si_noflush_write_trylock(sb); +} +#endif + +static inline void si_write_unlock(struct super_block *sb) +{ + si_pid_clr(sb); + __si_write_unlock(sb); +} + +#if 0 /* unused */ +static inline void si_downgrade_lock(struct super_block *sb) +{ + __si_downgrade_lock(sb); +} +#endif + +/* ---------------------------------------------------------------------- */ + +static inline aufs_bindex_t au_sbend(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_bend; +} + +static inline unsigned int au_mntflags(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_mntflags; +} + +static inline unsigned int au_sigen(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_generation; +} + +static inline void au_ninodes_inc(struct super_block *sb) +{ + atomic_long_inc(&au_sbi(sb)->si_ninodes); +} + +static inline void au_ninodes_dec(struct super_block *sb) +{ + AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_ninodes)); + atomic_long_dec(&au_sbi(sb)->si_ninodes); +} + +static inline void au_nfiles_inc(struct super_block *sb) +{ + atomic_long_inc(&au_sbi(sb)->si_nfiles); +} + +static inline void au_nfiles_dec(struct super_block *sb) +{ + AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_nfiles)); + atomic_long_dec(&au_sbi(sb)->si_nfiles); +} + +static inline struct au_branch *au_sbr(struct super_block *sb, + aufs_bindex_t bindex) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_branch[0 + bindex]; +} + +static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid) +{ + SiMustWriteLock(sb); + au_sbi(sb)->si_xino_brid = brid; +} + +static inline aufs_bindex_t au_xino_brid(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_xino_brid; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SUPER_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/loop.c +++ linux-3.13.0/ubuntu/aufs/loop.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * support for loopback block device as a branch + */ + +#include "aufs.h" + +/* added into drivers/block/loop.c */ +static struct file *(*backing_file_func)(struct super_block *sb); + +/* + * test if two lower dentries have overlapping branches. + */ +int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) +{ + struct super_block *h_sb; + struct file *backing_file; + + if (unlikely(!backing_file_func)) { + /* don't load "loop" module here */ + backing_file_func = symbol_get(loop_backing_file); + if (unlikely(!backing_file_func)) + /* "loop" module is not loaded */ + return 0; + } + + h_sb = h_adding->d_sb; + backing_file = backing_file_func(h_sb); + if (!backing_file) + return 0; + + h_adding = backing_file->f_dentry; + /* + * h_adding can be local NFS. + * in this case aufs cannot detect the loop. + */ + if (unlikely(h_adding->d_sb == sb)) + return 1; + return !!au_test_subdir(h_adding, sb->s_root); +} + +/* true if a kernel thread named 'loop[0-9].*' accesses a file */ +int au_test_loopback_kthread(void) +{ + int ret; + struct task_struct *tsk = current; + char c, comm[sizeof(tsk->comm)]; + + ret = 0; + if (tsk->flags & PF_KTHREAD) { + get_task_comm(comm, tsk); + c = comm[4]; + ret = ('0' <= c && c <= '9' + && !strncmp(comm, "loop", 4)); + } + + return ret; +} + +/* ---------------------------------------------------------------------- */ + +#define au_warn_loopback_step 16 +static int au_warn_loopback_nelem = au_warn_loopback_step; +static unsigned long *au_warn_loopback_array; + +void au_warn_loopback(struct super_block *h_sb) +{ + int i, new_nelem; + unsigned long *a, magic; + static DEFINE_SPINLOCK(spin); + + magic = h_sb->s_magic; + spin_lock(&spin); + a = au_warn_loopback_array; + for (i = 0; i < au_warn_loopback_nelem && *a; i++) + if (a[i] == magic) { + spin_unlock(&spin); + return; + } + + /* h_sb is new to us, print it */ + if (i < au_warn_loopback_nelem) { + a[i] = magic; + goto pr; + } + + /* expand the array */ + new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; + a = au_kzrealloc(au_warn_loopback_array, + au_warn_loopback_nelem * sizeof(unsigned long), + new_nelem * sizeof(unsigned long), GFP_ATOMIC); + if (a) { + au_warn_loopback_nelem = new_nelem; + au_warn_loopback_array = a; + a[i] = magic; + goto pr; + } + + spin_unlock(&spin); + AuWarn1("realloc failed, ignored\n"); + return; + +pr: + spin_unlock(&spin); + pr_warn("you may want to try another patch for loopback file " + "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); +} + +int au_loopback_init(void) +{ + int err; + struct super_block *sb __maybe_unused; + + AuDebugOn(sizeof(sb->s_magic) != sizeof(unsigned long)); + + err = 0; + au_warn_loopback_array = kcalloc(au_warn_loopback_step, + sizeof(unsigned long), GFP_NOFS); + if (unlikely(!au_warn_loopback_array)) + err = -ENOMEM; + + return err; +} + +void au_loopback_fin(void) +{ + symbol_put(loop_backing_file); + kfree(au_warn_loopback_array); +} --- linux-3.13.0.orig/ubuntu/aufs/vfsub.c +++ linux-3.13.0/ubuntu/aufs/vfsub.c @@ -0,0 +1,782 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for VFS + */ + +#include +#include +#include +#include +#include "aufs.h" + +int vfsub_update_h_iattr(struct path *h_path, int *did) +{ + int err; + struct kstat st; + struct super_block *h_sb; + + /* for remote fs, leave work for its getattr or d_revalidate */ + /* for bad i_attr fs, handle them in aufs_getattr() */ + /* still some fs may acquire i_mutex. we need to skip them */ + err = 0; + if (!did) + did = &err; + h_sb = h_path->dentry->d_sb; + *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); + if (*did) + err = vfs_getattr(h_path, &st); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct file *vfsub_dentry_open(struct path *path, int flags) +{ + struct file *file; + + file = dentry_open(path, flags /* | __FMODE_NONOTIFY */, + current_cred()); + if (!IS_ERR_OR_NULL(file) + && (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + i_readcount_inc(path->dentry->d_inode); + + return file; +} + +struct file *vfsub_filp_open(const char *path, int oflags, int mode) +{ + struct file *file; + + lockdep_off(); + file = filp_open(path, + oflags /* | __FMODE_NONOTIFY */, + mode); + lockdep_on(); + if (IS_ERR(file)) + goto out; + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + +out: + return file; +} + +int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) +{ + int err; + + err = kern_path(name, flags, path); + if (!err && path->dentry->d_inode) + vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ + return err; +} + +struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, + int len) +{ + struct path path = { + .mnt = NULL + }; + + /* VFS checks it too, but by WARN_ON_ONCE() */ + IMustLock(parent->d_inode); + + path.dentry = lookup_one_len(name, parent, len); + if (IS_ERR(path.dentry)) + goto out; + if (path.dentry->d_inode) + vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ + +out: + AuTraceErrPtr(path.dentry); + return path.dentry; +} + +void vfsub_call_lkup_one(void *args) +{ + struct vfsub_lkup_one_args *a = args; + *a->errp = vfsub_lkup_one(a->name, a->parent); +} + +/* ---------------------------------------------------------------------- */ + +struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2) +{ + struct dentry *d; + + lockdep_off(); + d = lock_rename(d1, d2); + lockdep_on(); + au_hn_suspend(hdir1); + if (hdir1 != hdir2) + au_hn_suspend(hdir2); + + return d; +} + +void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2) +{ + au_hn_resume(hdir1); + if (hdir1 != hdir2) + au_hn_resume(hdir2); + lockdep_off(); + unlock_rename(d1, d2); + lockdep_on(); +} + +/* ---------------------------------------------------------------------- */ + +int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_mknod(path, d, mode, 0); + path->dentry = d; + if (unlikely(err)) + goto out; + + err = vfs_create(dir, path->dentry, mode, want_excl); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_symlink(path, d, symname); + path->dentry = d; + if (unlikely(err)) + goto out; + + err = vfs_symlink(dir, path->dentry, symname); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_mknod(path, d, mode, new_encode_dev(dev)); + path->dentry = d; + if (unlikely(err)) + goto out; + + err = vfs_mknod(dir, path->dentry, mode, dev); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +static int au_test_nlink(struct inode *inode) +{ + const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ + + if (!au_test_fs_no_limit_nlink(inode->i_sb) + || inode->i_nlink < link_max) + return 0; + return -EMLINK; +} + +int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, + struct inode **delegated_inode) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + err = au_test_nlink(src_dentry->d_inode); + if (unlikely(err)) + return err; + + /* we don't call may_linkat() */ + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_link(src_dentry, path, d); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_link(src_dentry, dir, path->dentry, delegated_inode); + lockdep_on(); + if (!err) { + struct path tmp = *path; + int did; + + /* fuse has different memory inode for the same inumber */ + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + tmp.dentry = src_dentry; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct path *path, + struct inode **delegated_inode) +{ + int err; + struct path tmp = { + .mnt = path->mnt + }; + struct dentry *d; + + IMustLock(dir); + IMustLock(src_dir); + + d = path->dentry; + path->dentry = d->d_parent; + tmp.dentry = src_dentry->d_parent; + err = security_path_rename(&tmp, src_dentry, path, d); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_rename(src_dir, src_dentry, dir, path->dentry, + delegated_inode); + lockdep_on(); + if (!err) { + int did; + + tmp.dentry = d->d_parent; + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = src_dentry; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + tmp.dentry = src_dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_mkdir(struct inode *dir, struct path *path, int mode) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_mkdir(path, d, mode); + path->dentry = d; + if (unlikely(err)) + goto out; + + err = vfs_mkdir(dir, path->dentry, mode); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_rmdir(struct inode *dir, struct path *path) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_rmdir(path, d); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_rmdir(dir, path->dentry); + lockdep_on(); + if (!err) { + struct path tmp = { + .dentry = path->dentry->d_parent, + .mnt = path->mnt + }; + + vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ + } + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* todo: support mmap_sem? */ +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + + lockdep_off(); + err = vfs_read(file, ubuf, count, ppos); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +/* todo: kernel_read()? */ +ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + mm_segment_t oldfs; + union { + void *k; + char __user *u; + } buf; + + buf.k = kbuf; + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = vfsub_read_u(file, buf.u, count, ppos); + set_fs(oldfs); + return err; +} + +ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + + lockdep_off(); + err = vfs_write(file, ubuf, count, ppos); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) +{ + ssize_t err; + mm_segment_t oldfs; + union { + void *k; + const char __user *u; + } buf; + + buf.k = kbuf; + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = vfsub_write_u(file, buf.u, count, ppos); + set_fs(oldfs); + return err; +} + +int vfsub_flush(struct file *file, fl_owner_t id) +{ + int err; + + err = 0; + if (file->f_op->flush) { + if (!au_test_nfs(file->f_dentry->d_sb)) + err = file->f_op->flush(file, id); + else { + lockdep_off(); + err = file->f_op->flush(file, id); + lockdep_on(); + } + if (!err) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); + /*ignore*/ + } + return err; +} + +int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) +{ + int err; + + AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); + + lockdep_off(); + err = iterate_dir(file, ctx); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +long vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + long err; + + lockdep_off(); + err = do_splice_to(in, ppos, pipe, len, flags); + lockdep_on(); + file_accessed(in); + if (err >= 0) + vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + long err; + + lockdep_off(); + err = do_splice_from(pipe, out, ppos, len, flags); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +int vfsub_fsync(struct file *file, struct path *path, int datasync) +{ + int err; + + /* file can be NULL */ + lockdep_off(); + err = vfs_fsync(file, datasync); + lockdep_on(); + if (!err) { + if (!path) { + AuDebugOn(!file); + path = &file->f_path; + } + vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ + } + return err; +} + +/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ +int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, + struct file *h_file) +{ + int err; + struct inode *h_inode; + struct super_block *h_sb; + + if (!h_file) { + err = vfsub_truncate(h_path, length); + goto out; + } + + h_inode = h_path->dentry->d_inode; + h_sb = h_inode->i_sb; + lockdep_off(); + sb_start_write(h_sb); + lockdep_on(); + err = locks_verify_truncate(h_inode, h_file, length); + if (!err) + err = security_path_truncate(h_path); + if (!err) { + lockdep_off(); + err = do_truncate(h_path->dentry, length, attr, h_file); + lockdep_on(); + } + lockdep_off(); + sb_end_write(h_sb); + lockdep_on(); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_vfsub_mkdir_args { + int *errp; + struct inode *dir; + struct path *path; + int mode; +}; + +static void au_call_vfsub_mkdir(void *args) +{ + struct au_vfsub_mkdir_args *a = args; + *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); +} + +int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) +{ + int err, do_sio, wkq_err; + + do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); + if (!do_sio) + err = vfsub_mkdir(dir, path, mode); + else { + struct au_vfsub_mkdir_args args = { + .errp = &err, + .dir = dir, + .path = path, + .mode = mode + }; + wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} + +struct au_vfsub_rmdir_args { + int *errp; + struct inode *dir; + struct path *path; +}; + +static void au_call_vfsub_rmdir(void *args) +{ + struct au_vfsub_rmdir_args *a = args; + *a->errp = vfsub_rmdir(a->dir, a->path); +} + +int vfsub_sio_rmdir(struct inode *dir, struct path *path) +{ + int err, do_sio, wkq_err; + + do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); + if (!do_sio) + err = vfsub_rmdir(dir, path); + else { + struct au_vfsub_rmdir_args args = { + .errp = &err, + .dir = dir, + .path = path + }; + wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct notify_change_args { + int *errp; + struct path *path; + struct iattr *ia; + struct inode **delegated_inode; +}; + +static void call_notify_change(void *args) +{ + struct notify_change_args *a = args; + struct inode *h_inode; + + h_inode = a->path->dentry->d_inode; + IMustLock(h_inode); + + *a->errp = -EPERM; + if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { + *a->errp = notify_change(a->path->dentry, a->ia, + a->delegated_inode); + if (!*a->errp) + vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ + } + AuTraceErr(*a->errp); +} + +int vfsub_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode) +{ + int err; + struct notify_change_args args = { + .errp = &err, + .path = path, + .ia = ia, + .delegated_inode = delegated_inode + }; + + call_notify_change(&args); + + return err; +} + +int vfsub_sio_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode) +{ + int err, wkq_err; + struct notify_change_args args = { + .errp = &err, + .path = path, + .ia = ia, + .delegated_inode = delegated_inode + }; + + wkq_err = au_wkq_wait(call_notify_change, &args); + if (unlikely(wkq_err)) + err = wkq_err; + + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct unlink_args { + int *errp; + struct inode *dir; + struct path *path; + struct inode **delegated_inode; +}; + +static void call_unlink(void *args) +{ + struct unlink_args *a = args; + struct dentry *d = a->path->dentry; + struct inode *h_inode; + const int stop_sillyrename = (au_test_nfs(d->d_sb) + && d_count(d) == 1); + + IMustLock(a->dir); + + a->path->dentry = d->d_parent; + *a->errp = security_path_unlink(a->path, d); + a->path->dentry = d; + if (unlikely(*a->errp)) + return; + + if (!stop_sillyrename) + dget(d); + h_inode = d->d_inode; + if (h_inode) + ihold(h_inode); + + lockdep_off(); + *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); + lockdep_on(); + if (!*a->errp) { + struct path tmp = { + .dentry = d->d_parent, + .mnt = a->path->mnt + }; + vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ + } + + if (!stop_sillyrename) + dput(d); + if (h_inode) + iput(h_inode); + + AuTraceErr(*a->errp); +} + +/* + * @dir: must be locked. + * @dentry: target dentry. + */ +int vfsub_unlink(struct inode *dir, struct path *path, + struct inode **delegated_inode, int force) +{ + int err; + struct unlink_args args = { + .errp = &err, + .dir = dir, + .path = path, + .delegated_inode = delegated_inode + }; + + if (!force) + call_unlink(&args); + else { + int wkq_err; + + wkq_err = au_wkq_wait(call_unlink, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/spl.h +++ linux-3.13.0/ubuntu/aufs/spl.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * simple list protected by a spinlock + */ + +#ifndef __AUFS_SPL_H__ +#define __AUFS_SPL_H__ + +#ifdef __KERNEL__ + +struct au_splhead { + spinlock_t spin; + struct list_head head; +}; + +static inline void au_spl_init(struct au_splhead *spl) +{ + spin_lock_init(&spl->spin); + INIT_LIST_HEAD(&spl->head); +} + +static inline void au_spl_add(struct list_head *list, struct au_splhead *spl) +{ + spin_lock(&spl->spin); + list_add(list, &spl->head); + spin_unlock(&spl->spin); +} + +static inline void au_spl_del(struct list_head *list, struct au_splhead *spl) +{ + spin_lock(&spl->spin); + list_del(list); + spin_unlock(&spl->spin); +} + +static inline void au_spl_del_rcu(struct list_head *list, + struct au_splhead *spl) +{ + spin_lock(&spl->spin); + list_del_rcu(list); + spin_unlock(&spl->spin); +} + +/* ---------------------------------------------------------------------- */ + +struct au_sphlhead { + spinlock_t spin; + struct hlist_head head; +}; + +static inline void au_sphl_init(struct au_sphlhead *sphl) +{ + spin_lock_init(&sphl->spin); + INIT_HLIST_HEAD(&sphl->head); +} + +static inline void au_sphl_add(struct hlist_node *hlist, + struct au_sphlhead *sphl) +{ + spin_lock(&sphl->spin); + hlist_add_head(hlist, &sphl->head); + spin_unlock(&sphl->spin); +} + +static inline void au_sphl_del(struct hlist_node *hlist, + struct au_sphlhead *sphl) +{ + spin_lock(&sphl->spin); + hlist_del(hlist); + spin_unlock(&sphl->spin); +} + +static inline void au_sphl_del_rcu(struct hlist_node *hlist, + struct au_sphlhead *sphl) +{ + spin_lock(&sphl->spin); + hlist_del_rcu(hlist); + spin_unlock(&sphl->spin); +} + +static inline unsigned long au_sphl_count(struct au_sphlhead *sphl) +{ + unsigned long cnt; + struct hlist_node *pos; + + cnt = 0; + spin_lock(&sphl->spin); + hlist_for_each(pos, &sphl->head) + cnt++; + spin_unlock(&sphl->spin); + return cnt; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SPL_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/cpup.c +++ linux-3.13.0/ubuntu/aufs/cpup.c @@ -0,0 +1,1277 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * copy-up functions, see wbr_policy.c for copy-down + */ + +#include +#include +#include "aufs.h" + +void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) +{ + const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE + | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; + + BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); + + dst->i_flags |= iflags & ~mask; + if (au_test_fs_notime(dst->i_sb)) + dst->i_flags |= S_NOATIME | S_NOCMTIME; +} + +void au_cpup_attr_timesizes(struct inode *inode) +{ + struct inode *h_inode; + + h_inode = au_h_iptr(inode, au_ibstart(inode)); + fsstack_copy_attr_times(inode, h_inode); + fsstack_copy_inode_size(inode, h_inode); +} + +void au_cpup_attr_nlink(struct inode *inode, int force) +{ + struct inode *h_inode; + struct super_block *sb; + aufs_bindex_t bindex, bend; + + sb = inode->i_sb; + bindex = au_ibstart(inode); + h_inode = au_h_iptr(inode, bindex); + if (!force + && !S_ISDIR(h_inode->i_mode) + && au_opt_test(au_mntflags(sb), PLINK) + && au_plink_test(inode)) + return; + + /* + * 0 can happen in revalidating. + * h_inode->i_mutex is not held, but it is harmless since once i_nlink + * reaches 0, it will never become positive. + */ + set_nlink(inode, h_inode->i_nlink); + + /* + * fewer nlink makes find(1) noisy, but larger nlink doesn't. + * it may includes whplink directory. + */ + if (S_ISDIR(h_inode->i_mode)) { + bend = au_ibend(inode); + for (bindex++; bindex <= bend; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (h_inode) + au_add_nlink(inode, h_inode); + } + } +} + +void au_cpup_attr_changeable(struct inode *inode) +{ + struct inode *h_inode; + + h_inode = au_h_iptr(inode, au_ibstart(inode)); + inode->i_mode = h_inode->i_mode; + inode->i_uid = h_inode->i_uid; + inode->i_gid = h_inode->i_gid; + au_cpup_attr_timesizes(inode); + au_cpup_attr_flags(inode, h_inode->i_flags); +} + +void au_cpup_igen(struct inode *inode, struct inode *h_inode) +{ + struct au_iinfo *iinfo = au_ii(inode); + + IiMustWriteLock(inode); + + iinfo->ii_higen = h_inode->i_generation; + iinfo->ii_hsb1 = h_inode->i_sb; +} + +void au_cpup_attr_all(struct inode *inode, int force) +{ + struct inode *h_inode; + + h_inode = au_h_iptr(inode, au_ibstart(inode)); + au_cpup_attr_changeable(inode); + if (inode->i_nlink > 0) + au_cpup_attr_nlink(inode, force); + inode->i_rdev = h_inode->i_rdev; + inode->i_blkbits = h_inode->i_blkbits; + au_cpup_igen(inode, h_inode); +} + +/* ---------------------------------------------------------------------- */ + +/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ + +/* keep the timestamps of the parent dir when cpup */ +void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, + struct path *h_path) +{ + struct inode *h_inode; + + dt->dt_dentry = dentry; + dt->dt_h_path = *h_path; + h_inode = h_path->dentry->d_inode; + dt->dt_atime = h_inode->i_atime; + dt->dt_mtime = h_inode->i_mtime; + /* smp_mb(); */ +} + +void au_dtime_revert(struct au_dtime *dt) +{ + struct iattr attr; + int err; + + attr.ia_atime = dt->dt_atime; + attr.ia_mtime = dt->dt_mtime; + attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET + | ATTR_ATIME | ATTR_ATIME_SET; + + /* no delegation since this is a directory */ + err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); + if (unlikely(err)) + pr_warn("restoring timestamps failed(%d). ignored\n", err); +} + +/* ---------------------------------------------------------------------- */ + +/* internal use only */ +struct au_cpup_reg_attr { + int valid; + struct kstat st; + unsigned int iflags; /* inode->i_flags */ +}; + +static noinline_for_stack +int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, + struct au_cpup_reg_attr *h_src_attr) +{ + int err, sbits; + struct iattr ia; + struct path h_path; + struct inode *h_isrc, *h_idst; + struct kstat *h_st; + + h_path.dentry = au_h_dptr(dst, bindex); + h_idst = h_path.dentry->d_inode; + h_path.mnt = au_sbr_mnt(dst->d_sb, bindex); + h_isrc = h_src->d_inode; + ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID + | ATTR_ATIME | ATTR_MTIME + | ATTR_ATIME_SET | ATTR_MTIME_SET; + if (h_src_attr && h_src_attr->valid) { + h_st = &h_src_attr->st; + ia.ia_uid = h_st->uid; + ia.ia_gid = h_st->gid; + ia.ia_atime = h_st->atime; + ia.ia_mtime = h_st->mtime; + if (h_idst->i_mode != h_st->mode + && !S_ISLNK(h_idst->i_mode)) { + ia.ia_valid |= ATTR_MODE; + ia.ia_mode = h_st->mode; + } + sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); + au_cpup_attr_flags(h_idst, h_src_attr->iflags); + } else { + ia.ia_uid = h_isrc->i_uid; + ia.ia_gid = h_isrc->i_gid; + ia.ia_atime = h_isrc->i_atime; + ia.ia_mtime = h_isrc->i_mtime; + if (h_idst->i_mode != h_isrc->i_mode + && !S_ISLNK(h_idst->i_mode)) { + ia.ia_valid |= ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + } + sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); + au_cpup_attr_flags(h_idst, h_isrc->i_flags); + } + /* no delegation since it is just created */ + err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); + + /* is this nfs only? */ + if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { + ia.ia_valid = ATTR_FORCE | ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, + char *buf, unsigned long blksize) +{ + int err; + size_t sz, rbytes, wbytes; + unsigned char all_zero; + char *p, *zp; + struct mutex *h_mtx; + /* reduce stack usage */ + struct iattr *ia; + + zp = page_address(ZERO_PAGE(0)); + if (unlikely(!zp)) + return -ENOMEM; /* possible? */ + + err = 0; + all_zero = 0; + while (len) { + AuDbg("len %lld\n", len); + sz = blksize; + if (len < blksize) + sz = len; + + rbytes = 0; + /* todo: signal_pending? */ + while (!rbytes || err == -EAGAIN || err == -EINTR) { + rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); + err = rbytes; + } + if (unlikely(err < 0)) + break; + + all_zero = 0; + if (len >= rbytes && rbytes == blksize) + all_zero = !memcmp(buf, zp, rbytes); + if (!all_zero) { + wbytes = rbytes; + p = buf; + while (wbytes) { + size_t b; + + b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); + err = b; + /* todo: signal_pending? */ + if (unlikely(err == -EAGAIN || err == -EINTR)) + continue; + if (unlikely(err < 0)) + break; + wbytes -= b; + p += b; + } + if (unlikely(err < 0)) + break; + } else { + loff_t res; + + AuLabel(hole); + res = vfsub_llseek(dst, rbytes, SEEK_CUR); + err = res; + if (unlikely(res < 0)) + break; + } + len -= rbytes; + err = 0; + } + + /* the last block may be a hole */ + if (!err && all_zero) { + AuLabel(last hole); + + err = 1; + if (au_test_nfs(dst->f_dentry->d_sb)) { + /* nfs requires this step to make last hole */ + /* is this only nfs? */ + do { + /* todo: signal_pending? */ + err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); + } while (err == -EAGAIN || err == -EINTR); + if (err == 1) + dst->f_pos--; + } + + if (err == 1) { + ia = (void *)buf; + ia->ia_size = dst->f_pos; + ia->ia_valid = ATTR_SIZE | ATTR_FILE; + ia->ia_file = dst; + h_mtx = &file_inode(dst)->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); + /* no delegation since it is just created */ + err = vfsub_notify_change(&dst->f_path, ia, + /*delegated*/NULL); + mutex_unlock(h_mtx); + } + } + + return err; +} + +int au_copy_file(struct file *dst, struct file *src, loff_t len) +{ + int err; + unsigned long blksize; + unsigned char do_kfree; + char *buf; + + err = -ENOMEM; + blksize = dst->f_dentry->d_sb->s_blocksize; + if (!blksize || PAGE_SIZE < blksize) + blksize = PAGE_SIZE; + AuDbg("blksize %lu\n", blksize); + do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); + if (do_kfree) + buf = kmalloc(blksize, GFP_NOFS); + else + buf = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!buf)) + goto out; + + if (len > (1 << 22)) + AuDbg("copying a large file %lld\n", (long long)len); + + src->f_pos = 0; + dst->f_pos = 0; + err = au_do_copy_file(dst, src, len, buf, blksize); + if (do_kfree) + kfree(buf); + else + free_page((unsigned long)buf); + +out: + return err; +} + +/* + * to support a sparse file which is opened with O_APPEND, + * we need to close the file. + */ +static int au_cp_regular(struct au_cp_generic *cpg) +{ + int err, i; + enum { SRC, DST }; + struct { + aufs_bindex_t bindex; + unsigned int flags; + struct dentry *dentry; + int force_wr; + struct file *file; + void *label; + } *f, file[] = { + { + .bindex = cpg->bsrc, + .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, + .label = &&out + }, + { + .bindex = cpg->bdst, + .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, + .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), + .label = &&out_src + } + }; + struct super_block *sb; + + /* bsrc branch can be ro/rw. */ + sb = cpg->dentry->d_sb; + f = file; + for (i = 0; i < 2; i++, f++) { + f->dentry = au_h_dptr(cpg->dentry, f->bindex); + f->file = au_h_open(cpg->dentry, f->bindex, f->flags, + /*file*/NULL, f->force_wr); + err = PTR_ERR(f->file); + if (IS_ERR(f->file)) + goto *f->label; + } + + /* try stopping to update while we copyup */ + IMustLock(file[SRC].dentry->d_inode); + err = au_copy_file(file[DST].file, file[SRC].file, cpg->len); + + fput(file[DST].file); + au_sbr_put(sb, file[DST].bindex); + +out_src: + fput(file[SRC].file); + au_sbr_put(sb, file[SRC].bindex); +out: + return err; +} + +static int au_do_cpup_regular(struct au_cp_generic *cpg, + struct au_cpup_reg_attr *h_src_attr) +{ + int err, rerr; + loff_t l; + struct path h_path; + struct inode *h_src_inode; + + err = 0; + h_src_inode = au_h_iptr(cpg->dentry->d_inode, cpg->bsrc); + l = i_size_read(h_src_inode); + if (cpg->len == -1 || l < cpg->len) + cpg->len = l; + if (cpg->len) { + /* try stopping to update while we are referencing */ + mutex_lock_nested(&h_src_inode->i_mutex, AuLsc_I_CHILD); + au_pin_hdir_unlock(cpg->pin); + + h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); + h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); + h_src_attr->iflags = h_src_inode->i_flags; + err = vfs_getattr(&h_path, &h_src_attr->st); + if (unlikely(err)) { + mutex_unlock(&h_src_inode->i_mutex); + goto out; + } + h_src_attr->valid = 1; + err = au_cp_regular(cpg); + mutex_unlock(&h_src_inode->i_mutex); + rerr = au_pin_hdir_relock(cpg->pin); + if (!err && rerr) + err = rerr; + } + +out: + return err; +} + +static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, + struct inode *h_dir) +{ + int err, symlen; + mm_segment_t old_fs; + union { + char *k; + char __user *u; + } sym; + + err = -ENOSYS; + if (unlikely(!h_src->d_inode->i_op->readlink)) + goto out; + + err = -ENOMEM; + sym.k = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!sym.k)) + goto out; + + /* unnecessary to support mmap_sem since symlink is not mmap-able */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + symlen = h_src->d_inode->i_op->readlink(h_src, sym.u, PATH_MAX); + err = symlen; + set_fs(old_fs); + + if (symlen > 0) { + sym.k[symlen] = 0; + err = vfsub_symlink(h_dir, h_path, sym.k); + } + free_page((unsigned long)sym.k); + +out: + return err; +} + +static noinline_for_stack +int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, + struct au_cpup_reg_attr *h_src_attr) +{ + int err; + umode_t mode; + unsigned int mnt_flags; + unsigned char isdir; + const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); + struct au_dtime dt; + struct path h_path; + struct dentry *h_src, *h_dst, *h_parent; + struct inode *h_inode, *h_dir; + struct super_block *sb; + + /* bsrc branch can be ro/rw. */ + h_src = au_h_dptr(cpg->dentry, cpg->bsrc); + h_inode = h_src->d_inode; + AuDebugOn(h_inode != au_h_iptr(cpg->dentry->d_inode, cpg->bsrc)); + + /* try stopping to be referenced while we are creating */ + h_dst = au_h_dptr(cpg->dentry, cpg->bdst); + if (au_ftest_cpup(cpg->flags, RENAME)) + AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, + AUFS_WH_PFX_LEN)); + h_parent = h_dst->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + AuDebugOn(h_parent != h_dst->d_parent); + + sb = cpg->dentry->d_sb; + h_path.mnt = au_sbr_mnt(sb, cpg->bdst); + if (do_dt) { + h_path.dentry = h_parent; + au_dtime_store(&dt, dst_parent, &h_path); + } + h_path.dentry = h_dst; + + isdir = 0; + mode = h_inode->i_mode; + switch (mode & S_IFMT) { + case S_IFREG: + err = vfsub_create(h_dir, &h_path, mode | S_IWUSR, + /*want_excl*/true); + if (!err) + err = au_do_cpup_regular(cpg, h_src_attr); + break; + case S_IFDIR: + isdir = 1; + err = vfsub_mkdir(h_dir, &h_path, mode); + if (!err) { + /* + * strange behaviour from the users view, + * particularry setattr case + */ + if (au_ibstart(dst_parent->d_inode) == cpg->bdst) + au_cpup_attr_nlink(dst_parent->d_inode, + /*force*/1); + au_cpup_attr_nlink(cpg->dentry->d_inode, /*force*/1); + } + break; + case S_IFLNK: + err = au_do_cpup_symlink(&h_path, h_src, h_dir); + break; + case S_IFCHR: + case S_IFBLK: + AuDebugOn(!capable(CAP_MKNOD)); + /*FALLTHROUGH*/ + case S_IFIFO: + case S_IFSOCK: + err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); + break; + default: + AuIOErr("Unknown inode type 0%o\n", mode); + err = -EIO; + } + + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, UDBA_NONE) + && !isdir + && au_opt_test(mnt_flags, XINO) + && h_inode->i_nlink == 1 + /* todo: unnecessary? */ + /* && cpg->dentry->d_inode->i_nlink == 1 */ + && cpg->bdst < cpg->bsrc + && !au_ftest_cpup(cpg->flags, KEEPLINO)) + au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); + /* ignore this error */ + + if (do_dt) + au_dtime_revert(&dt); + return err; +} + +static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) +{ + int err; + struct dentry *dentry, *h_dentry, *h_parent, *parent; + struct inode *h_dir; + aufs_bindex_t bdst; + + dentry = cpg->dentry; + bdst = cpg->bdst; + h_dentry = au_h_dptr(dentry, bdst); + if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { + dget(h_dentry); + au_set_h_dptr(dentry, bdst, NULL); + err = au_lkup_neg(dentry, bdst, /*wh*/0); + if (!err) + h_path->dentry = dget(au_h_dptr(dentry, bdst)); + au_set_h_dptr(dentry, bdst, h_dentry); + } else { + err = 0; + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bdst); + dput(parent); + h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); + if (IS_ERR(h_path->dentry)) + err = PTR_ERR(h_path->dentry); + } + if (unlikely(err)) + goto out; + + h_parent = h_dentry->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + AuDbg("%pd %pd\n", h_dentry, h_path->dentry); + /* no delegation since it is just created */ + err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL); + dput(h_path->dentry); + +out: + return err; +} + +/* + * copyup the @dentry from @bsrc to @bdst. + * the caller must set the both of lower dentries. + * @len is for truncating when it is -1 copyup the entire file. + * in link/rename cases, @dst_parent may be different from the real one. + * basic->bsrc can be larger than basic->bdst. + */ +static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) +{ + int err, rerr; + aufs_bindex_t old_ibstart; + unsigned char isdir, plink; + struct dentry *h_src, *h_dst, *h_parent; + struct inode *dst_inode, *h_dir, *inode, *delegated; + struct super_block *sb; + struct au_branch *br; + /* to reuduce stack size */ + struct { + struct au_dtime dt; + struct path h_path; + struct au_cpup_reg_attr h_src_attr; + } *a; + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + a->h_src_attr.valid = 0; + + sb = cpg->dentry->d_sb; + br = au_sbr(sb, cpg->bdst); + a->h_path.mnt = au_br_mnt(br); + h_dst = au_h_dptr(cpg->dentry, cpg->bdst); + h_parent = h_dst->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + + h_src = au_h_dptr(cpg->dentry, cpg->bsrc); + inode = cpg->dentry->d_inode; + + if (!dst_parent) + dst_parent = dget_parent(cpg->dentry); + else + dget(dst_parent); + + plink = !!au_opt_test(au_mntflags(sb), PLINK); + dst_inode = au_h_iptr(inode, cpg->bdst); + if (dst_inode) { + if (unlikely(!plink)) { + err = -EIO; + AuIOErr("hi%lu(i%lu) exists on b%d " + "but plink is disabled\n", + dst_inode->i_ino, inode->i_ino, cpg->bdst); + goto out_parent; + } + + if (dst_inode->i_nlink) { + const int do_dt = au_ftest_cpup(cpg->flags, DTIME); + + h_src = au_plink_lkup(inode, cpg->bdst); + err = PTR_ERR(h_src); + if (IS_ERR(h_src)) + goto out_parent; + if (unlikely(!h_src->d_inode)) { + err = -EIO; + AuIOErr("i%lu exists on a upper branch " + "but not pseudo-linked\n", + inode->i_ino); + dput(h_src); + goto out_parent; + } + + if (do_dt) { + a->h_path.dentry = h_parent; + au_dtime_store(&a->dt, dst_parent, &a->h_path); + } + + a->h_path.dentry = h_dst; + delegated = NULL; + err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); + if (!err && au_ftest_cpup(cpg->flags, RENAME)) + err = au_do_ren_after_cpup(cpg, &a->h_path); + if (do_dt) + au_dtime_revert(&a->dt); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + dput(h_src); + goto out_parent; + } else + /* todo: cpup_wh_file? */ + /* udba work */ + au_update_ibrange(inode, /*do_put_zero*/1); + } + + isdir = S_ISDIR(inode->i_mode); + old_ibstart = au_ibstart(inode); + err = cpup_entry(cpg, dst_parent, &a->h_src_attr); + if (unlikely(err)) + goto out_rev; + dst_inode = h_dst->d_inode; + mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2); + /* todo: necessary? */ + /* au_pin_hdir_unlock(cpg->pin); */ + + err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr); + if (unlikely(err)) { + /* todo: necessary? */ + /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ + mutex_unlock(&dst_inode->i_mutex); + goto out_rev; + } + + if (cpg->bdst < old_ibstart) { + if (S_ISREG(inode->i_mode)) { + err = au_dy_iaop(inode, cpg->bdst, dst_inode); + if (unlikely(err)) { + /* ignore an error */ + /* au_pin_hdir_relock(cpg->pin); */ + mutex_unlock(&dst_inode->i_mutex); + goto out_rev; + } + } + au_set_ibstart(inode, cpg->bdst); + } else + au_set_ibend(inode, cpg->bdst); + au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), + au_hi_flags(inode, isdir)); + + /* todo: necessary? */ + /* err = au_pin_hdir_relock(cpg->pin); */ + mutex_unlock(&dst_inode->i_mutex); + if (unlikely(err)) + goto out_rev; + + if (!isdir + && h_src->d_inode->i_nlink > 1 + && plink) + au_plink_append(inode, cpg->bdst, h_dst); + + if (au_ftest_cpup(cpg->flags, RENAME)) { + a->h_path.dentry = h_dst; + err = au_do_ren_after_cpup(cpg, &a->h_path); + } + if (!err) + goto out_parent; /* success */ + + /* revert */ +out_rev: + a->h_path.dentry = h_parent; + au_dtime_store(&a->dt, dst_parent, &a->h_path); + a->h_path.dentry = h_dst; + rerr = 0; + if (h_dst->d_inode) { + if (!isdir) { + /* no delegation since it is just created */ + rerr = vfsub_unlink(h_dir, &a->h_path, + /*delegated*/NULL, /*force*/0); + } else + rerr = vfsub_rmdir(h_dir, &a->h_path); + } + au_dtime_revert(&a->dt); + if (rerr) { + AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); + err = -EIO; + } +out_parent: + dput(dst_parent); + kfree(a); +out: + return err; +} + +#if 0 /* unused */ +struct au_cpup_single_args { + int *errp; + struct au_cp_generic *cpg; + struct dentry *dst_parent; +}; + +static void au_call_cpup_single(void *args) +{ + struct au_cpup_single_args *a = args; + + au_pin_hdir_acquire_nest(a->cpg->pin); + *a->errp = au_cpup_single(a->cpg, a->dst_parent); + au_pin_hdir_release(a->cpg->pin); +} +#endif + +/* + * prevent SIGXFSZ in copy-up. + * testing CAP_MKNOD is for generic fs, + * but CAP_FSETID is for xfs only, currently. + */ +static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) +{ + int do_sio; + struct super_block *sb; + struct inode *h_dir; + + do_sio = 0; + sb = au_pinned_parent(pin)->d_sb; + if (!au_wkq_test() + && (!au_sbi(sb)->si_plink_maint_pid + || au_plink_maint(sb, AuLock_NOPLM))) { + switch (mode & S_IFMT) { + case S_IFREG: + /* no condition about RLIMIT_FSIZE and the file size */ + do_sio = 1; + break; + case S_IFCHR: + case S_IFBLK: + do_sio = !capable(CAP_MKNOD); + break; + } + if (!do_sio) + do_sio = ((mode & (S_ISUID | S_ISGID)) + && !capable(CAP_FSETID)); + /* this workaround may be removed in the future */ + if (!do_sio) { + h_dir = au_pinned_h_dir(pin); + do_sio = h_dir->i_mode & S_ISVTX; + } + } + + return do_sio; +} + +#if 0 /* unused */ +int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) +{ + int err, wkq_err; + struct dentry *h_dentry; + + h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); + if (!au_cpup_sio_test(pin, h_dentry->d_inode->i_mode)) + err = au_cpup_single(cpg, dst_parent); + else { + struct au_cpup_single_args args = { + .errp = &err, + .cpg = cpg, + .dst_parent = dst_parent + }; + wkq_err = au_wkq_wait(au_call_cpup_single, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} +#endif + +/* + * copyup the @dentry from the first active lower branch to @bdst, + * using au_cpup_single(). + */ +static int au_cpup_simple(struct au_cp_generic *cpg) +{ + int err; + unsigned int flags_orig; + struct dentry *dentry; + + AuDebugOn(cpg->bsrc < 0); + + dentry = cpg->dentry; + DiMustWriteLock(dentry); + + err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); + if (!err) { + flags_orig = cpg->flags; + au_fset_cpup(cpg->flags, RENAME); + err = au_cpup_single(cpg, NULL); + cpg->flags = flags_orig; + if (!err) + return 0; /* success */ + + /* revert */ + au_set_h_dptr(dentry, cpg->bdst, NULL); + au_set_dbstart(dentry, cpg->bsrc); + } + + return err; +} + +struct au_cpup_simple_args { + int *errp; + struct au_cp_generic *cpg; +}; + +static void au_call_cpup_simple(void *args) +{ + struct au_cpup_simple_args *a = args; + + au_pin_hdir_acquire_nest(a->cpg->pin); + *a->errp = au_cpup_simple(a->cpg); + au_pin_hdir_release(a->cpg->pin); +} + +static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) +{ + int err, wkq_err; + struct dentry *dentry, *parent; + struct file *h_file; + struct inode *h_dir; + + dentry = cpg->dentry; + h_file = NULL; + if (au_ftest_cpup(cpg->flags, HOPEN)) { + AuDebugOn(cpg->bsrc < 0); + h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + } + + parent = dget_parent(dentry); + h_dir = au_h_iptr(parent->d_inode, cpg->bdst); + if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) + && !au_cpup_sio_test(cpg->pin, dentry->d_inode->i_mode)) + err = au_cpup_simple(cpg); + else { + struct au_cpup_simple_args args = { + .errp = &err, + .cpg = cpg + }; + wkq_err = au_wkq_wait(au_call_cpup_simple, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + dput(parent); + if (h_file) + au_h_open_post(dentry, cpg->bsrc, h_file); + +out: + return err; +} + +int au_sio_cpup_simple(struct au_cp_generic *cpg) +{ + aufs_bindex_t bsrc, bend; + struct dentry *dentry, *h_dentry; + + if (cpg->bsrc < 0) { + dentry = cpg->dentry; + bend = au_dbend(dentry); + for (bsrc = cpg->bdst + 1; bsrc <= bend; bsrc++) { + h_dentry = au_h_dptr(dentry, bsrc); + if (h_dentry) { + AuDebugOn(!h_dentry->d_inode); + break; + } + } + AuDebugOn(bsrc > bend); + cpg->bsrc = bsrc; + } + AuDebugOn(cpg->bsrc <= cpg->bdst); + return au_do_sio_cpup_simple(cpg); +} + +int au_sio_cpdown_simple(struct au_cp_generic *cpg) +{ + AuDebugOn(cpg->bdst <= cpg->bsrc); + return au_do_sio_cpup_simple(cpg); +} + +/* ---------------------------------------------------------------------- */ + +/* + * copyup the deleted file for writing. + */ +static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, + struct file *file) +{ + int err; + unsigned int flags_orig; + aufs_bindex_t bsrc_orig; + struct dentry *h_d_dst, *h_d_start; + struct au_dinfo *dinfo; + struct au_hdentry *hdp; + + dinfo = au_di(cpg->dentry); + AuRwMustWriteLock(&dinfo->di_rwsem); + + bsrc_orig = cpg->bsrc; + cpg->bsrc = dinfo->di_bstart; + hdp = dinfo->di_hdentry; + h_d_dst = hdp[0 + cpg->bdst].hd_dentry; + dinfo->di_bstart = cpg->bdst; + hdp[0 + cpg->bdst].hd_dentry = wh_dentry; + h_d_start = NULL; + if (file) { + h_d_start = hdp[0 + cpg->bsrc].hd_dentry; + hdp[0 + cpg->bsrc].hd_dentry = au_hf_top(file)->f_dentry; + } + flags_orig = cpg->flags; + cpg->flags = !AuCpup_DTIME; + err = au_cpup_single(cpg, /*h_parent*/NULL); + cpg->flags = flags_orig; + if (file) { + if (!err) + err = au_reopen_nondir(file); + hdp[0 + cpg->bsrc].hd_dentry = h_d_start; + } + hdp[0 + cpg->bdst].hd_dentry = h_d_dst; + dinfo->di_bstart = cpg->bsrc; + cpg->bsrc = bsrc_orig; + + return err; +} + +static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) +{ + int err; + aufs_bindex_t bdst; + struct au_dtime dt; + struct dentry *dentry, *parent, *h_parent, *wh_dentry; + struct au_branch *br; + struct path h_path; + + dentry = cpg->dentry; + bdst = cpg->bdst; + br = au_sbr(dentry->d_sb, bdst); + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bdst); + wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + h_path.dentry = h_parent; + h_path.mnt = au_br_mnt(br); + au_dtime_store(&dt, parent, &h_path); + err = au_do_cpup_wh(cpg, wh_dentry, file); + if (unlikely(err)) + goto out_wh; + + dget(wh_dentry); + h_path.dentry = wh_dentry; + if (!S_ISDIR(wh_dentry->d_inode->i_mode)) { + /* no delegation since it is just created */ + err = vfsub_unlink(h_parent->d_inode, &h_path, + /*delegated*/NULL, /*force*/0); + } else + err = vfsub_rmdir(h_parent->d_inode, &h_path); + if (unlikely(err)) { + AuIOErr("failed remove copied-up tmp file %pd(%d)\n", + wh_dentry, err); + err = -EIO; + } + au_dtime_revert(&dt); + au_set_hi_wh(dentry->d_inode, bdst, wh_dentry); + +out_wh: + dput(wh_dentry); +out: + dput(parent); + return err; +} + +struct au_cpup_wh_args { + int *errp; + struct au_cp_generic *cpg; + struct file *file; +}; + +static void au_call_cpup_wh(void *args) +{ + struct au_cpup_wh_args *a = args; + + au_pin_hdir_acquire_nest(a->cpg->pin); + *a->errp = au_cpup_wh(a->cpg, a->file); + au_pin_hdir_release(a->cpg->pin); +} + +int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) +{ + int err, wkq_err; + aufs_bindex_t bdst; + struct dentry *dentry, *parent, *h_orph, *h_parent, *h_dentry; + struct inode *dir, *h_dir, *h_tmpdir; + struct au_wbr *wbr; + struct au_pin wh_pin, *pin_orig; + + dentry = cpg->dentry; + bdst = cpg->bdst; + parent = dget_parent(dentry); + dir = parent->d_inode; + h_orph = NULL; + h_parent = NULL; + h_dir = au_igrab(au_h_iptr(dir, bdst)); + h_tmpdir = h_dir; + pin_orig = NULL; + if (!h_dir->i_nlink) { + wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; + h_orph = wbr->wbr_orph; + + h_parent = dget(au_h_dptr(parent, bdst)); + au_set_h_dptr(parent, bdst, dget(h_orph)); + h_tmpdir = h_orph->d_inode; + au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); + + if (file) + h_dentry = au_hf_top(file)->f_dentry; + else + h_dentry = au_h_dptr(dentry, au_dbstart(dentry)); + mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3); + /* todo: au_h_open_pre()? */ + + pin_orig = cpg->pin; + au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, + AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); + cpg->pin = &wh_pin; + } + + if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) + && !au_cpup_sio_test(cpg->pin, dentry->d_inode->i_mode)) + err = au_cpup_wh(cpg, file); + else { + struct au_cpup_wh_args args = { + .errp = &err, + .cpg = cpg, + .file = file + }; + wkq_err = au_wkq_wait(au_call_cpup_wh, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + if (h_orph) { + mutex_unlock(&h_tmpdir->i_mutex); + /* todo: au_h_open_post()? */ + au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); + au_set_h_dptr(parent, bdst, h_parent); + AuDebugOn(!pin_orig); + cpg->pin = pin_orig; + } + iput(h_dir); + dput(parent); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * generic routine for both of copy-up and copy-down. + */ +/* cf. revalidate function in file.c */ +int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, + int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent, void *arg), + void *arg) +{ + int err; + struct au_pin pin; + struct dentry *d, *parent, *h_parent, *real_parent; + + err = 0; + parent = dget_parent(dentry); + if (IS_ROOT(parent)) + goto out; + + au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, + au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); + + /* do not use au_dpage */ + real_parent = parent; + while (1) { + dput(parent); + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bdst); + if (h_parent) + goto out; /* success */ + + /* find top dir which is necessary to cpup */ + do { + d = parent; + dput(parent); + parent = dget_parent(d); + di_read_lock_parent3(parent, !AuLock_IR); + h_parent = au_h_dptr(parent, bdst); + di_read_unlock(parent, !AuLock_IR); + } while (!h_parent); + + if (d != real_parent) + di_write_lock_child3(d); + + /* somebody else might create while we were sleeping */ + if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) { + if (au_h_dptr(d, bdst)) + au_update_dbstart(d); + + au_pin_set_dentry(&pin, d); + err = au_do_pin(&pin); + if (!err) { + err = cp(d, bdst, &pin, h_parent, arg); + au_unpin(&pin); + } + } + + if (d != real_parent) + di_write_unlock(d); + if (unlikely(err)) + break; + } + +out: + dput(parent); + return err; +} + +static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent __maybe_unused , + void *arg __maybe_unused) +{ + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = bdst, + .bsrc = -1, + .len = 0, + .pin = pin, + .flags = AuCpup_DTIME + }; + return au_sio_cpup_simple(&cpg); +} + +int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); +} + +int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + int err; + struct dentry *parent; + struct inode *dir; + + parent = dget_parent(dentry); + dir = parent->d_inode; + err = 0; + if (au_h_iptr(dir, bdst)) + goto out; + + di_read_unlock(parent, AuLock_IR); + di_write_lock_parent(parent); + /* someone else might change our inode while we were sleeping */ + if (!au_h_iptr(dir, bdst)) + err = au_cpup_dirs(dentry, bdst); + di_downgrade_lock(parent, AuLock_IR); + +out: + dput(parent); + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/iinfo.c +++ linux-3.13.0/ubuntu/aufs/iinfo.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode private data + */ + +#include "aufs.h" + +struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) +{ + struct inode *h_inode; + + IiMustAnyLock(inode); + + h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode; + AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); + return h_inode; +} + +/* todo: hard/soft set? */ +void au_hiput(struct au_hinode *hinode) +{ + au_hn_free(hinode); + dput(hinode->hi_whdentry); + iput(hinode->hi_inode); +} + +unsigned int au_hi_flags(struct inode *inode, int isdir) +{ + unsigned int flags; + const unsigned int mnt_flags = au_mntflags(inode->i_sb); + + flags = 0; + if (au_opt_test(mnt_flags, XINO)) + au_fset_hi(flags, XINO); + if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) + au_fset_hi(flags, HNOTIFY); + return flags; +} + +void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode, unsigned int flags) +{ + struct au_hinode *hinode; + struct inode *hi; + struct au_iinfo *iinfo = au_ii(inode); + + IiMustWriteLock(inode); + + hinode = iinfo->ii_hinode + bindex; + hi = hinode->hi_inode; + AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); + + if (hi) + au_hiput(hinode); + hinode->hi_inode = h_inode; + if (h_inode) { + int err; + struct super_block *sb = inode->i_sb; + struct au_branch *br; + + AuDebugOn(inode->i_mode + && (h_inode->i_mode & S_IFMT) + != (inode->i_mode & S_IFMT)); + if (bindex == iinfo->ii_bstart) + au_cpup_igen(inode, h_inode); + br = au_sbr(sb, bindex); + hinode->hi_id = br->br_id; + if (au_ftest_hi(flags, XINO)) { + err = au_xino_write(sb, bindex, h_inode->i_ino, + inode->i_ino); + if (unlikely(err)) + AuIOErr1("failed au_xino_write() %d\n", err); + } + + if (au_ftest_hi(flags, HNOTIFY) + && au_br_hnotifyable(br->br_perm)) { + err = au_hn_alloc(hinode, inode); + if (unlikely(err)) + AuIOErr1("au_hn_alloc() %d\n", err); + } + } +} + +void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_wh) +{ + struct au_hinode *hinode; + + IiMustWriteLock(inode); + + hinode = au_ii(inode)->ii_hinode + bindex; + AuDebugOn(hinode->hi_whdentry); + hinode->hi_whdentry = h_wh; +} + +void au_update_iigen(struct inode *inode, int half) +{ + struct au_iinfo *iinfo; + struct au_iigen *iigen; + unsigned int sigen; + + sigen = au_sigen(inode->i_sb); + iinfo = au_ii(inode); + iigen = &iinfo->ii_generation; + spin_lock(&iinfo->ii_genspin); + iigen->ig_generation = sigen; + if (half) + au_ig_fset(iigen->ig_flags, HALF_REFRESHED); + else + au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); + spin_unlock(&iinfo->ii_genspin); +} + +/* it may be called at remount time, too */ +void au_update_ibrange(struct inode *inode, int do_put_zero) +{ + struct au_iinfo *iinfo; + aufs_bindex_t bindex, bend; + + iinfo = au_ii(inode); + if (!iinfo) + return; + + IiMustWriteLock(inode); + + if (do_put_zero && iinfo->ii_bstart >= 0) { + for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; + bindex++) { + struct inode *h_i; + + h_i = iinfo->ii_hinode[0 + bindex].hi_inode; + if (h_i && !h_i->i_nlink) + au_set_h_iptr(inode, bindex, NULL, 0); + } + } + + iinfo->ii_bstart = -1; + iinfo->ii_bend = -1; + bend = au_sbend(inode->i_sb); + for (bindex = 0; bindex <= bend; bindex++) + if (iinfo->ii_hinode[0 + bindex].hi_inode) { + iinfo->ii_bstart = bindex; + break; + } + if (iinfo->ii_bstart >= 0) + for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--) + if (iinfo->ii_hinode[0 + bindex].hi_inode) { + iinfo->ii_bend = bindex; + break; + } + AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend); +} + +/* ---------------------------------------------------------------------- */ + +void au_icntnr_init_once(void *_c) +{ + struct au_icntnr *c = _c; + struct au_iinfo *iinfo = &c->iinfo; + static struct lock_class_key aufs_ii; + + spin_lock_init(&iinfo->ii_genspin); + au_rw_init(&iinfo->ii_rwsem); + au_rw_class(&iinfo->ii_rwsem, &aufs_ii); + inode_init_once(&c->vfs_inode); +} + +int au_iinfo_init(struct inode *inode) +{ + struct au_iinfo *iinfo; + struct super_block *sb; + int nbr, i; + + sb = inode->i_sb; + iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); + nbr = au_sbend(sb) + 1; + if (unlikely(nbr <= 0)) + nbr = 1; + iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); + if (iinfo->ii_hinode) { + au_ninodes_inc(sb); + for (i = 0; i < nbr; i++) + iinfo->ii_hinode[i].hi_id = -1; + + iinfo->ii_generation.ig_generation = au_sigen(sb); + iinfo->ii_bstart = -1; + iinfo->ii_bend = -1; + iinfo->ii_vdir = NULL; + return 0; + } + return -ENOMEM; +} + +int au_ii_realloc(struct au_iinfo *iinfo, int nbr) +{ + int err, sz; + struct au_hinode *hip; + + AuRwMustWriteLock(&iinfo->ii_rwsem); + + err = -ENOMEM; + sz = sizeof(*hip) * (iinfo->ii_bend + 1); + if (!sz) + sz = sizeof(*hip); + hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS); + if (hip) { + iinfo->ii_hinode = hip; + err = 0; + } + + return err; +} + +void au_iinfo_fin(struct inode *inode) +{ + struct au_iinfo *iinfo; + struct au_hinode *hi; + struct super_block *sb; + aufs_bindex_t bindex, bend; + const unsigned char unlinked = !inode->i_nlink; + + iinfo = au_ii(inode); + /* bad_inode case */ + if (!iinfo) + return; + + sb = inode->i_sb; + au_ninodes_dec(sb); + if (si_pid_test(sb)) + au_xino_delete_inode(inode, unlinked); + else { + /* + * it is safe to hide the dependency between sbinfo and + * sb->s_umount. + */ + lockdep_off(); + si_noflush_read_lock(sb); + au_xino_delete_inode(inode, unlinked); + si_read_unlock(sb); + lockdep_on(); + } + + if (iinfo->ii_vdir) + au_vdir_free(iinfo->ii_vdir); + + bindex = iinfo->ii_bstart; + if (bindex >= 0) { + hi = iinfo->ii_hinode + bindex; + bend = iinfo->ii_bend; + while (bindex++ <= bend) { + if (hi->hi_inode) + au_hiput(hi); + hi++; + } + } + kfree(iinfo->ii_hinode); + iinfo->ii_hinode = NULL; + AuRwDestroy(&iinfo->ii_rwsem); +} --- linux-3.13.0.orig/ubuntu/aufs/file.h +++ linux-3.13.0/ubuntu/aufs/file.h @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * file operations + */ + +#ifndef __AUFS_FILE_H__ +#define __AUFS_FILE_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include "rwsem.h" + +struct au_branch; +struct au_hfile { + struct file *hf_file; + struct au_branch *hf_br; +}; + +struct au_vdir; +struct au_fidir { + aufs_bindex_t fd_bbot; + aufs_bindex_t fd_nent; + struct au_vdir *fd_vdir_cache; + struct au_hfile fd_hfile[]; +}; + +static inline int au_fidir_sz(int nent) +{ + AuDebugOn(nent < 0); + return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; +} + +struct au_finfo { + atomic_t fi_generation; + + struct au_rwsem fi_rwsem; + aufs_bindex_t fi_btop; + + /* do not union them */ + struct { /* for non-dir */ + struct au_hfile fi_htop; + atomic_t fi_mmapped; + }; + struct au_fidir *fi_hdir; /* for dir only */ + + struct hlist_node fi_hlist; + struct file *fi_file; /* very ugly */ +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ + +/* file.c */ +extern const struct address_space_operations aufs_aop; +unsigned int au_file_roflags(unsigned int flags); +struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, + struct file *file, int force_wr); +int au_do_open(struct file *file, int (*open)(struct file *file, int flags), + struct au_fidir *fidir); +int au_reopen_nondir(struct file *file); +struct au_pin; +int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); +int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), + int wlock); +int au_do_flush(struct file *file, fl_owner_t id, + int (*flush)(struct file *file, fl_owner_t id)); + +/* poll.c */ +#ifdef CONFIG_AUFS_POLL +unsigned int aufs_poll(struct file *file, poll_table *wait); +#endif + +#ifdef CONFIG_AUFS_BR_HFSPLUS +/* hfsplus.c */ +struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, + int force_wr); +void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, + struct file *h_file); +#else +static inline +struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, + int force_wr) +{ + return NULL; +} + +AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, + struct file *h_file); +#endif + +/* f_op.c */ +extern const struct file_operations aufs_file_fop; +int au_do_open_nondir(struct file *file, int flags); +int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); + +#ifdef CONFIG_AUFS_SP_IATTR +/* f_op_sp.c */ +struct au_finfo *au_fi_sp(struct file *file); +int au_special_file(umode_t mode); +void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev); +#else +static inline struct au_finfo *au_fi_sp(struct file *file) +{ + return NULL; +} +AuStubInt0(au_special_file, umode_t mode) +static inline void au_init_special_fop(struct inode *inode, umode_t mode, + dev_t rdev) +{ + init_special_inode(inode, mode, rdev); +} +#endif + +/* finfo.c */ +void au_hfput(struct au_hfile *hf, struct file *file); +void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, + struct file *h_file); + +void au_update_figen(struct file *file); +struct au_fidir *au_fidir_alloc(struct super_block *sb); +int au_fidir_realloc(struct au_finfo *finfo, int nbr); + +void au_fi_init_once(void *_fi); +void au_finfo_fin(struct file *file); +int au_finfo_init(struct file *file, struct au_fidir *fidir); + +/* ioctl.c */ +long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, + unsigned long arg); +long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, + unsigned long arg); +#endif + +/* ---------------------------------------------------------------------- */ + +static inline struct au_finfo *au_fi(struct file *file) +{ + struct au_finfo *finfo; + + finfo = au_fi_sp(file); + if (!finfo) + finfo = file->private_data; + return finfo; +} + +/* ---------------------------------------------------------------------- */ + +/* + * fi_read_lock, fi_write_lock, + * fi_read_unlock, fi_write_unlock, fi_downgrade_lock + */ +AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem); + +#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) +#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) +#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) + +/* ---------------------------------------------------------------------- */ + +/* todo: hard/soft set? */ +static inline aufs_bindex_t au_fbstart(struct file *file) +{ + FiMustAnyLock(file); + return au_fi(file)->fi_btop; +} + +static inline aufs_bindex_t au_fbend_dir(struct file *file) +{ + FiMustAnyLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + return au_fi(file)->fi_hdir->fd_bbot; +} + +static inline struct au_vdir *au_fvdir_cache(struct file *file) +{ + FiMustAnyLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + return au_fi(file)->fi_hdir->fd_vdir_cache; +} + +static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex) +{ + FiMustWriteLock(file); + au_fi(file)->fi_btop = bindex; +} + +static inline void au_set_fbend_dir(struct file *file, aufs_bindex_t bindex) +{ + FiMustWriteLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + au_fi(file)->fi_hdir->fd_bbot = bindex; +} + +static inline void au_set_fvdir_cache(struct file *file, + struct au_vdir *vdir_cache) +{ + FiMustWriteLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; +} + +static inline struct file *au_hf_top(struct file *file) +{ + FiMustAnyLock(file); + AuDebugOn(au_fi(file)->fi_hdir); + return au_fi(file)->fi_htop.hf_file; +} + +static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) +{ + FiMustAnyLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; +} + +/* todo: memory barrier? */ +static inline unsigned int au_figen(struct file *f) +{ + return atomic_read(&au_fi(f)->fi_generation); +} + +static inline void au_set_mmapped(struct file *f) +{ + if (atomic_inc_return(&au_fi(f)->fi_mmapped)) + return; + pr_warn("fi_mmapped wrapped around\n"); + while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) + ; +} + +static inline void au_unset_mmapped(struct file *f) +{ + atomic_dec(&au_fi(f)->fi_mmapped); +} + +static inline int au_test_mmapped(struct file *f) +{ + return atomic_read(&au_fi(f)->fi_mmapped); +} + +/* customize vma->vm_file */ + +static inline void au_do_vm_file_reset(struct vm_area_struct *vma, + struct file *file) +{ + struct file *f; + + f = vma->vm_file; + get_file(file); + vma->vm_file = file; + fput(f); +} + +#ifdef CONFIG_MMU +#define AuDbgVmRegion(file, vma) do {} while (0) + +static inline void au_vm_file_reset(struct vm_area_struct *vma, + struct file *file) +{ + au_do_vm_file_reset(vma, file); +} +#else +#define AuDbgVmRegion(file, vma) \ + AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) + +static inline void au_vm_file_reset(struct vm_area_struct *vma, + struct file *file) +{ + struct file *f; + + au_do_vm_file_reset(vma, file); + f = vma->vm_region->vm_file; + get_file(file); + vma->vm_region->vm_file = file; + fput(f); +} +#endif /* CONFIG_MMU */ + +/* handle vma->vm_prfile */ +static inline void au_vm_prfile_set(struct vm_area_struct *vma, + struct file *file) +{ + get_file(file); + vma->vm_prfile = file; +#ifndef CONFIG_MMU + get_file(file); + vma->vm_region->vm_prfile = file; +#endif +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FILE_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/aufs.h +++ linux-3.13.0/ubuntu/aufs/aufs.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * all header files + */ + +#ifndef __AUFS_H__ +#define __AUFS_H__ + +#ifdef __KERNEL__ + +#define AuStub(type, name, body, ...) \ + static inline type name(__VA_ARGS__) { body; } + +#define AuStubVoid(name, ...) \ + AuStub(void, name, , __VA_ARGS__) +#define AuStubInt0(name, ...) \ + AuStub(int, name, return 0, __VA_ARGS__) + +#include "debug.h" + +#include "branch.h" +#include "cpup.h" +#include "dcsub.h" +#include "dbgaufs.h" +#include "dentry.h" +#include "dir.h" +#include "dynop.h" +#include "file.h" +#include "fstype.h" +#include "inode.h" +#include "loop.h" +#include "module.h" +#include "opts.h" +#include "rwsem.h" +#include "spl.h" +#include "super.h" +#include "sysaufs.h" +#include "vfsub.h" +#include "whout.h" +#include "wkq.h" + +#endif /* __KERNEL__ */ +#endif /* __AUFS_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/branch.h +++ linux-3.13.0/ubuntu/aufs/branch.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * branch filesystems and xino for them + */ + +#ifndef __AUFS_BRANCH_H__ +#define __AUFS_BRANCH_H__ + +#ifdef __KERNEL__ + +#include +#include "dynop.h" +#include "rwsem.h" +#include "super.h" + +/* ---------------------------------------------------------------------- */ + +/* a xino file */ +struct au_xino_file { + struct file *xi_file; + struct mutex xi_nondir_mtx; + + /* todo: make xino files an array to support huge inode number */ + +#ifdef CONFIG_DEBUG_FS + struct dentry *xi_dbgaufs; +#endif +}; + +/* members for writable branch only */ +enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; +struct au_wbr { + struct au_rwsem wbr_wh_rwsem; + struct dentry *wbr_wh[AuBrWh_Last]; + atomic_t wbr_wh_running; +#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ +#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ +#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ + + /* mfs mode */ + unsigned long long wbr_bytes; +}; + +/* ext2 has 3 types of operations at least, ext3 has 4 */ +#define AuBrDynOp (AuDyLast * 4) + +#ifdef CONFIG_AUFS_HFSNOTIFY +/* support for asynchronous destruction */ +struct au_br_hfsnotify { + struct fsnotify_group *hfsn_group; +}; +#endif + +/* sysfs entries */ +struct au_brsysfs { + char name[16]; + struct attribute attr; +}; + +enum { + AuBrSysfs_BR, + AuBrSysfs_BRID, + AuBrSysfs_Last +}; + +/* protected by superblock rwsem */ +struct au_branch { + struct au_xino_file br_xino; + + aufs_bindex_t br_id; + + int br_perm; + unsigned int br_dflags; + struct path br_path; + spinlock_t br_dykey_lock; + struct au_dykey *br_dykey[AuBrDynOp]; + atomic_t br_count; + + struct au_wbr *br_wbr; + + /* xino truncation */ + atomic_t br_xino_running; + +#ifdef CONFIG_AUFS_HFSNOTIFY + struct au_br_hfsnotify *br_hfsn; +#endif + +#ifdef CONFIG_SYSFS + /* entries under sysfs per mount-point */ + struct au_brsysfs br_sysfs[AuBrSysfs_Last]; +#endif +}; + +/* ---------------------------------------------------------------------- */ + +static inline struct vfsmount *au_br_mnt(struct au_branch *br) +{ + return br->br_path.mnt; +} + +static inline struct dentry *au_br_dentry(struct au_branch *br) +{ + return br->br_path.dentry; +} + +static inline struct super_block *au_br_sb(struct au_branch *br) +{ + return au_br_mnt(br)->mnt_sb; +} + +/* branch permissions and attributes */ +#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ +#define AuBrPerm_RO (1 << 1) /* readonly */ +#define AuBrPerm_RR (1 << 2) /* natively readonly */ +#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) + +#define AuBrRAttr_WH (1 << 3) /* whiteout-able */ + +#define AuBrWAttr_NoLinkWH (1 << 4) /* un-hardlinkable whiteouts */ + +#define AuBrAttr_UNPIN (1 << 5) /* rename-able top dir of + branch */ + +static inline int au_br_writable(int brperm) +{ + return brperm & AuBrPerm_RW; +} + +static inline int au_br_whable(int brperm) +{ + return brperm & (AuBrPerm_RW | AuBrRAttr_WH); +} + +static inline int au_br_wh_linkable(int brperm) +{ + return !(brperm & AuBrWAttr_NoLinkWH); +} + +static inline int au_br_rdonly(struct au_branch *br) +{ + return ((au_br_sb(br)->s_flags & MS_RDONLY) + || !au_br_writable(br->br_perm)) + ? -EROFS : 0; +} + +static inline int au_br_hnotifyable(int brperm __maybe_unused) +{ +#ifdef CONFIG_AUFS_HNOTIFY + return !(brperm & AuBrPerm_RR); +#else + return 0; +#endif +} + +/* ---------------------------------------------------------------------- */ + +/* branch.c */ +struct au_sbinfo; +void au_br_free(struct au_sbinfo *sinfo); +int au_br_index(struct super_block *sb, aufs_bindex_t br_id); +struct au_opt_add; +int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); +struct au_opt_del; +int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); +long au_ibusy_ioctl(struct file *file, unsigned long arg); +#ifdef CONFIG_COMPAT +long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); +#endif +struct au_opt_mod; +int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, + int *do_refresh); + +/* xino.c */ +static const loff_t au_loff_max = LLONG_MAX; + +int au_xib_trunc(struct super_block *sb); +ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, + loff_t *pos); +ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, + loff_t *pos); +struct file *au_xino_create2(struct file *base_file, struct file *copy_src); +struct file *au_xino_create(struct super_block *sb, char *fname, int silent); +ino_t au_xino_new_ino(struct super_block *sb); +void au_xino_delete_inode(struct inode *inode, const int unlinked); +int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t ino); +int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t *ino); +int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, + struct file *base_file, int do_test); +int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); + +struct au_opt_xino; +int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); +void au_xino_clr(struct super_block *sb); +struct file *au_xino_def(struct super_block *sb); +int au_xino_path(struct seq_file *seq, struct file *file); + +/* ---------------------------------------------------------------------- */ + +/* Superblock to branch */ +static inline +aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_id; +} + +static inline +struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_mnt(au_sbr(sb, bindex)); +} + +static inline +struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_sb(au_sbr(sb, bindex)); +} + +static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) +{ + atomic_dec(&au_sbr(sb, bindex)->br_count); +} + +static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_perm; +} + +static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_whable(au_sbr_perm(sb, bindex)); +} + +/* ---------------------------------------------------------------------- */ + +/* + * wbr_wh_read_lock, wbr_wh_write_lock + * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock + */ +AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem); + +#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem) +#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem) +#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem) + +#endif /* __KERNEL__ */ +#endif /* __AUFS_BRANCH_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/loop.h +++ linux-3.13.0/ubuntu/aufs/loop.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * support for loopback mount as a branch + */ + +#ifndef __AUFS_LOOP_H__ +#define __AUFS_LOOP_H__ + +#ifdef __KERNEL__ + +struct dentry; +struct super_block; + +#ifdef CONFIG_AUFS_BDEV_LOOP +/* drivers/block/loop.c */ +struct file *loop_backing_file(struct super_block *sb); + +/* loop.c */ +int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); +int au_test_loopback_kthread(void); +void au_warn_loopback(struct super_block *h_sb); + +int au_loopback_init(void); +void au_loopback_fin(void); +#else +AuStubInt0(au_test_loopback_overlap, struct super_block *sb, + struct dentry *h_adding) +AuStubInt0(au_test_loopback_kthread, void) +AuStubVoid(au_warn_loopback, struct super_block *h_sb) + +AuStubInt0(au_loopback_init, void) +AuStubVoid(au_loopback_fin, void) +#endif /* BLK_DEV_LOOP */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_LOOP_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/dynop.h +++ linux-3.13.0/ubuntu/aufs/dynop.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * dynamically customizable operations (for regular files only) + */ + +#ifndef __AUFS_DYNOP_H__ +#define __AUFS_DYNOP_H__ + +#ifdef __KERNEL__ + +#include "inode.h" + +enum {AuDy_AOP, AuDyLast}; + +struct au_dynop { + int dy_type; + union { + const void *dy_hop; + const struct address_space_operations *dy_haop; + }; +}; + +struct au_dykey { + union { + struct list_head dk_list; + struct rcu_head dk_rcu; + }; + struct au_dynop dk_op; + + /* + * during I am in the branch local array, kref is gotten. when the + * branch is removed, kref is put. + */ + struct kref dk_kref; +}; + +/* stop unioning since their sizes are very different from each other */ +struct au_dyaop { + struct au_dykey da_key; + struct address_space_operations da_op; /* not const */ + int (*da_get_xip_mem)(struct address_space *, pgoff_t, int, + void **, unsigned long *); +}; + +/* ---------------------------------------------------------------------- */ + +/* dynop.c */ +struct au_branch; +void au_dy_put(struct au_dykey *key); +int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode); +int au_dy_irefresh(struct inode *inode); +void au_dy_arefresh(int do_dio); + +void __init au_dy_init(void); +void au_dy_fin(void); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DYNOP_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/branch.c +++ linux-3.13.0/ubuntu/aufs/branch.c @@ -0,0 +1,1219 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * branch management + */ + +#include +#include +#include "aufs.h" + +/* + * free a single branch + */ + +/* prohibit rmdir to the root of the branch */ +/* todo: another new flag? */ +static void au_br_dflags_force(struct au_branch *br) +{ + struct dentry *h_dentry; + + h_dentry = au_br_dentry(br); + spin_lock(&h_dentry->d_lock); + br->br_dflags = h_dentry->d_flags & DCACHE_MOUNTED; + h_dentry->d_flags |= DCACHE_MOUNTED; + spin_unlock(&h_dentry->d_lock); +} + +/* restore its d_flags */ +static void au_br_dflags_restore(struct au_branch *br) +{ + struct dentry *h_dentry; + + if (br->br_dflags) + return; + + h_dentry = au_br_dentry(br); + spin_lock(&h_dentry->d_lock); + h_dentry->d_flags &= ~DCACHE_MOUNTED; + spin_unlock(&h_dentry->d_lock); +} + +static void au_br_do_free(struct au_branch *br) +{ + int i; + struct au_wbr *wbr; + struct au_dykey **key; + + au_hnotify_fin_br(br); + + if (br->br_xino.xi_file) + fput(br->br_xino.xi_file); + mutex_destroy(&br->br_xino.xi_nondir_mtx); + + AuDebugOn(atomic_read(&br->br_count)); + + wbr = br->br_wbr; + if (wbr) { + for (i = 0; i < AuBrWh_Last; i++) + dput(wbr->wbr_wh[i]); + AuDebugOn(atomic_read(&wbr->wbr_wh_running)); + AuRwDestroy(&wbr->wbr_wh_rwsem); + } + + key = br->br_dykey; + for (i = 0; i < AuBrDynOp; i++, key++) + if (*key) + au_dy_put(*key); + else + break; + + au_br_dflags_restore(br); + + /* recursive lock, s_umount of branch's */ + lockdep_off(); + path_put(&br->br_path); + lockdep_on(); + kfree(wbr); + kfree(br); +} + +/* + * frees all branches + */ +void au_br_free(struct au_sbinfo *sbinfo) +{ + aufs_bindex_t bmax; + struct au_branch **br; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + bmax = sbinfo->si_bend + 1; + br = sbinfo->si_branch; + while (bmax--) + au_br_do_free(*br++); +} + +/* + * find the index of a branch which is specified by @br_id. + */ +int au_br_index(struct super_block *sb, aufs_bindex_t br_id) +{ + aufs_bindex_t bindex, bend; + + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) + if (au_sbr_id(sb, bindex) == br_id) + return bindex; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/* + * add a branch + */ + +static int test_overlap(struct super_block *sb, struct dentry *h_adding, + struct dentry *h_root) +{ + if (unlikely(h_adding == h_root + || au_test_loopback_overlap(sb, h_adding))) + return 1; + if (h_adding->d_sb != h_root->d_sb) + return 0; + return au_test_subdir(h_adding, h_root) + || au_test_subdir(h_root, h_adding); +} + +/* + * returns a newly allocated branch. @new_nbranch is a number of branches + * after adding a branch. + */ +static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, + int perm) +{ + struct au_branch *add_branch; + struct dentry *root; + int err; + + err = -ENOMEM; + root = sb->s_root; + add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS); + if (unlikely(!add_branch)) + goto out; + + err = au_hnotify_init_br(add_branch, perm); + if (unlikely(err)) + goto out_br; + + add_branch->br_wbr = NULL; + if (au_br_writable(perm)) { + /* may be freed separately at changing the branch permission */ + add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr), + GFP_NOFS); + if (unlikely(!add_branch->br_wbr)) + goto out_hnotify; + } + + err = au_sbr_realloc(au_sbi(sb), new_nbranch); + if (!err) + err = au_di_realloc(au_di(root), new_nbranch); + if (!err) + err = au_ii_realloc(au_ii(root->d_inode), new_nbranch); + if (!err) + return add_branch; /* success */ + + kfree(add_branch->br_wbr); + +out_hnotify: + au_hnotify_fin_br(add_branch); +out_br: + kfree(add_branch); +out: + return ERR_PTR(err); +} + +/* + * test if the branch permission is legal or not. + */ +static int test_br(struct inode *inode, int brperm, char *path) +{ + int err; + + err = (au_br_writable(brperm) && IS_RDONLY(inode)); + if (!err) + goto out; + + err = -EINVAL; + pr_err("write permission for readonly mount or inode, %s\n", path); + +out: + return err; +} + +/* + * returns: + * 0: success, the caller will add it + * plus: success, it is already unified, the caller should ignore it + * minus: error + */ +static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) +{ + int err; + aufs_bindex_t bend, bindex; + struct dentry *root; + struct inode *inode, *h_inode; + + root = sb->s_root; + bend = au_sbend(sb); + if (unlikely(bend >= 0 + && au_find_dbindex(root, add->path.dentry) >= 0)) { + err = 1; + if (!remount) { + err = -EINVAL; + pr_err("%s duplicated\n", add->pathname); + } + goto out; + } + + err = -ENOSPC; /* -E2BIG; */ + if (unlikely(AUFS_BRANCH_MAX <= add->bindex + || AUFS_BRANCH_MAX - 1 <= bend)) { + pr_err("number of branches exceeded %s\n", add->pathname); + goto out; + } + + err = -EDOM; + if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { + pr_err("bad index %d\n", add->bindex); + goto out; + } + + inode = add->path.dentry->d_inode; + err = -ENOENT; + if (unlikely(!inode->i_nlink)) { + pr_err("no existence %s\n", add->pathname); + goto out; + } + + err = -EINVAL; + if (unlikely(inode->i_sb == sb)) { + pr_err("%s must be outside\n", add->pathname); + goto out; + } + + if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { + pr_err("unsupported filesystem, %s (%s)\n", + add->pathname, au_sbtype(inode->i_sb)); + goto out; + } + + err = test_br(add->path.dentry->d_inode, add->perm, add->pathname); + if (unlikely(err)) + goto out; + + if (bend < 0) + return 0; /* success */ + + err = -EINVAL; + for (bindex = 0; bindex <= bend; bindex++) + if (unlikely(test_overlap(sb, add->path.dentry, + au_h_dptr(root, bindex)))) { + pr_err("%s is overlapped\n", add->pathname); + goto out; + } + + err = 0; + if (au_opt_test(au_mntflags(sb), WARN_PERM)) { + h_inode = au_h_dptr(root, 0)->d_inode; + if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) + || !uid_eq(h_inode->i_uid, inode->i_uid) + || !gid_eq(h_inode->i_gid, inode->i_gid)) + pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", + add->pathname, + i_uid_read(inode), i_gid_read(inode), + (inode->i_mode & S_IALLUGO), + i_uid_read(h_inode), i_gid_read(h_inode), + (h_inode->i_mode & S_IALLUGO)); + } + +out: + return err; +} + +/* + * initialize or clean the whiteouts for an adding branch + */ +static int au_br_init_wh(struct super_block *sb, struct au_branch *br, + int new_perm) +{ + int err, old_perm; + aufs_bindex_t bindex; + struct mutex *h_mtx; + struct au_wbr *wbr; + struct au_hinode *hdir; + + err = vfsub_mnt_want_write(au_br_mnt(br)); + if (unlikely(err)) + goto out; + + wbr = br->br_wbr; + old_perm = br->br_perm; + br->br_perm = new_perm; + hdir = NULL; + h_mtx = NULL; + bindex = au_br_index(sb, br->br_id); + if (0 <= bindex) { + hdir = au_hi(sb->s_root->d_inode, bindex); + au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); + } else { + h_mtx = &au_br_dentry(br)->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_PARENT); + } + if (!wbr) + err = au_wh_init(br, sb); + else { + wbr_wh_write_lock(wbr); + err = au_wh_init(br, sb); + wbr_wh_write_unlock(wbr); + } + if (hdir) + au_hn_imtx_unlock(hdir); + else + mutex_unlock(h_mtx); + vfsub_mnt_drop_write(au_br_mnt(br)); + br->br_perm = old_perm; + + if (!err && wbr && !au_br_writable(new_perm)) { + kfree(wbr); + br->br_wbr = NULL; + } + +out: + return err; +} + +static int au_wbr_init(struct au_branch *br, struct super_block *sb, + int perm) +{ + int err; + struct kstatfs kst; + struct au_wbr *wbr; + + wbr = br->br_wbr; + au_rw_init(&wbr->wbr_wh_rwsem); + memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh)); + atomic_set(&wbr->wbr_wh_running, 0); + wbr->wbr_bytes = 0; + + /* + * a limit for rmdir/rename a dir + * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h + */ + err = vfs_statfs(&br->br_path, &kst); + if (unlikely(err)) + goto out; + err = -EINVAL; + if (kst.f_namelen >= NAME_MAX) + err = au_br_init_wh(sb, br, perm); + else + pr_err("%pd(%s), unsupported namelen %ld\n", + au_br_dentry(br), + au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); + +out: + return err; +} + +/* intialize a new branch */ +static int au_br_init(struct au_branch *br, struct super_block *sb, + struct au_opt_add *add) +{ + int err; + + err = 0; + memset(&br->br_xino, 0, sizeof(br->br_xino)); + mutex_init(&br->br_xino.xi_nondir_mtx); + br->br_perm = add->perm; + BUILD_BUG_ON(sizeof(br->br_dflags) + != sizeof(br->br_path.dentry->d_flags)); + br->br_dflags = DCACHE_MOUNTED; + br->br_path = add->path; /* set first, path_get() later */ + spin_lock_init(&br->br_dykey_lock); + memset(br->br_dykey, 0, sizeof(br->br_dykey)); + atomic_set(&br->br_count, 0); + atomic_set(&br->br_xino_running, 0); + br->br_id = au_new_br_id(sb); + AuDebugOn(br->br_id < 0); + + if (au_br_writable(add->perm)) { + err = au_wbr_init(br, sb, add->perm); + if (unlikely(err)) + goto out_err; + } + + if (au_opt_test(au_mntflags(sb), XINO)) { + err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino, + au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); + if (unlikely(err)) { + AuDebugOn(br->br_xino.xi_file); + goto out_err; + } + } + + sysaufs_br_init(br); + path_get(&br->br_path); + goto out; /* success */ + +out_err: + memset(&br->br_path, 0, sizeof(br->br_path)); +out: + return err; +} + +static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, + struct au_branch *br, aufs_bindex_t bend, + aufs_bindex_t amount) +{ + struct au_branch **brp; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + brp = sbinfo->si_branch + bindex; + memmove(brp + 1, brp, sizeof(*brp) * amount); + *brp = br; + sbinfo->si_bend++; + if (unlikely(bend < 0)) + sbinfo->si_bend = 0; +} + +static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, + aufs_bindex_t bend, aufs_bindex_t amount) +{ + struct au_hdentry *hdp; + + AuRwMustWriteLock(&dinfo->di_rwsem); + + hdp = dinfo->di_hdentry + bindex; + memmove(hdp + 1, hdp, sizeof(*hdp) * amount); + au_h_dentry_init(hdp); + dinfo->di_bend++; + if (unlikely(bend < 0)) + dinfo->di_bstart = 0; +} + +static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, + aufs_bindex_t bend, aufs_bindex_t amount) +{ + struct au_hinode *hip; + + AuRwMustWriteLock(&iinfo->ii_rwsem); + + hip = iinfo->ii_hinode + bindex; + memmove(hip + 1, hip, sizeof(*hip) * amount); + hip->hi_inode = NULL; + au_hn_init(hip); + iinfo->ii_bend++; + if (unlikely(bend < 0)) + iinfo->ii_bstart = 0; +} + +static void au_br_do_add(struct super_block *sb, struct au_branch *br, + aufs_bindex_t bindex) +{ + struct dentry *root, *h_dentry; + struct inode *root_inode; + aufs_bindex_t bend, amount; + + au_br_dflags_force(br); + + root = sb->s_root; + root_inode = root->d_inode; + bend = au_sbend(sb); + amount = bend + 1 - bindex; + h_dentry = au_br_dentry(br); + au_sbilist_lock(); + au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount); + au_br_do_add_hdp(au_di(root), bindex, bend, amount); + au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount); + au_set_h_dptr(root, bindex, dget(h_dentry)); + au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode), + /*flags*/0); + au_sbilist_unlock(); +} + +int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) +{ + int err; + aufs_bindex_t bend, add_bindex; + struct dentry *root, *h_dentry; + struct inode *root_inode; + struct au_branch *add_branch; + + root = sb->s_root; + root_inode = root->d_inode; + IMustLock(root_inode); + err = test_add(sb, add, remount); + if (unlikely(err < 0)) + goto out; + if (err) { + err = 0; + goto out; /* success */ + } + + bend = au_sbend(sb); + add_branch = au_br_alloc(sb, bend + 2, add->perm); + err = PTR_ERR(add_branch); + if (IS_ERR(add_branch)) + goto out; + + err = au_br_init(add_branch, sb, add); + if (unlikely(err)) { + au_br_do_free(add_branch); + goto out; + } + + add_bindex = add->bindex; + if (!remount) + au_br_do_add(sb, add_branch, add_bindex); + else { + sysaufs_brs_del(sb, add_bindex); + au_br_do_add(sb, add_branch, add_bindex); + sysaufs_brs_add(sb, add_bindex); + } + + h_dentry = add->path.dentry; + if (!add_bindex) { + au_cpup_attr_all(root_inode, /*force*/1); + sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; + } else + au_add_nlink(root_inode, h_dentry->d_inode); + + /* + * this test/set prevents aufs from handling unnecesary notify events + * of xino files, in case of re-adding a writable branch which was + * once detached from aufs. + */ + if (au_xino_brid(sb) < 0 + && au_br_writable(add_branch->br_perm) + && !au_test_fs_bad_xino(h_dentry->d_sb) + && add_branch->br_xino.xi_file + && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry) + au_xino_brid_set(sb, add_branch->br_id); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * delete a branch + */ + +/* to show the line number, do not make it inlined function */ +#define AuVerbose(do_info, fmt, ...) do { \ + if (do_info) \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + +static int au_test_ibusy(struct inode *inode, aufs_bindex_t bstart, + aufs_bindex_t bend) +{ + return (inode && !S_ISDIR(inode->i_mode)) || bstart == bend; +} + +static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t bstart, + aufs_bindex_t bend) +{ + return au_test_ibusy(dentry->d_inode, bstart, bend); +} + +/* + * test if the branch is deletable or not. + */ +static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, + unsigned int sigen, const unsigned int verbose) +{ + int err, i, j, ndentry; + aufs_bindex_t bstart, bend; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry *d; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, root, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + for (i = 0; !err && i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + ndentry = dpage->ndentry; + for (j = 0; !err && j < ndentry; j++) { + d = dpage->dentries[j]; + AuDebugOn(!d_count(d)); + if (!au_digen_test(d, sigen)) { + di_read_lock_child(d, AuLock_IR); + if (unlikely(au_dbrange_test(d))) { + di_read_unlock(d, AuLock_IR); + continue; + } + } else { + di_write_lock_child(d); + if (unlikely(au_dbrange_test(d))) { + di_write_unlock(d); + continue; + } + err = au_reval_dpath(d, sigen); + if (!err) + di_downgrade_lock(d, AuLock_IR); + else { + di_write_unlock(d); + break; + } + } + + /* AuDbgDentry(d); */ + bstart = au_dbstart(d); + bend = au_dbend(d); + if (bstart <= bindex + && bindex <= bend + && au_h_dptr(d, bindex) + && au_test_dbusy(d, bstart, bend)) { + err = -EBUSY; + AuVerbose(verbose, "busy %pd\n", d); + AuDbgDentry(d); + } + di_read_unlock(d, AuLock_IR); + } + } + +out_dpages: + au_dpages_free(&dpages); +out: + return err; +} + +static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, + unsigned int sigen, const unsigned int verbose) +{ + int err; + unsigned long long max, ull; + struct inode *i, **array; + aufs_bindex_t bstart, bend; + + array = au_iarray_alloc(sb, &max); + err = PTR_ERR(array); + if (IS_ERR(array)) + goto out; + + err = 0; + AuDbg("b%d\n", bindex); + for (ull = 0; !err && ull < max; ull++) { + i = array[ull]; + if (i->i_ino == AUFS_ROOT_INO) + continue; + + /* AuDbgInode(i); */ + if (au_iigen(i, NULL) == sigen) + ii_read_lock_child(i); + else { + ii_write_lock_child(i); + err = au_refresh_hinode_self(i); + au_iigen_dec(i); + if (!err) + ii_downgrade_lock(i); + else { + ii_write_unlock(i); + break; + } + } + + bstart = au_ibstart(i); + bend = au_ibend(i); + if (bstart <= bindex + && bindex <= bend + && au_h_iptr(i, bindex) + && au_test_ibusy(i, bstart, bend)) { + err = -EBUSY; + AuVerbose(verbose, "busy i%lu\n", i->i_ino); + AuDbgInode(i); + } + ii_read_unlock(i); + } + au_iarray_free(array, max); + +out: + return err; +} + +static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, + const unsigned int verbose) +{ + int err; + unsigned int sigen; + + sigen = au_sigen(root->d_sb); + DiMustNoWaiters(root); + IiMustNoWaiters(root->d_inode); + di_write_unlock(root); + err = test_dentry_busy(root, bindex, sigen, verbose); + if (!err) + err = test_inode_busy(root->d_sb, bindex, sigen, verbose); + di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ + + return err; +} + +static void au_br_do_del_brp(struct au_sbinfo *sbinfo, + const aufs_bindex_t bindex, + const aufs_bindex_t bend) +{ + struct au_branch **brp, **p; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + brp = sbinfo->si_branch + bindex; + if (bindex < bend) + memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex)); + sbinfo->si_branch[0 + bend] = NULL; + sbinfo->si_bend--; + + p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, AuGFP_SBILIST); + if (p) + sbinfo->si_branch = p; + /* harmless error */ +} + +static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, + const aufs_bindex_t bend) +{ + struct au_hdentry *hdp, *p; + + AuRwMustWriteLock(&dinfo->di_rwsem); + + hdp = dinfo->di_hdentry; + if (bindex < bend) + memmove(hdp + bindex, hdp + bindex + 1, + sizeof(*hdp) * (bend - bindex)); + hdp[0 + bend].hd_dentry = NULL; + dinfo->di_bend--; + + p = krealloc(hdp, sizeof(*p) * bend, AuGFP_SBILIST); + if (p) + dinfo->di_hdentry = p; + /* harmless error */ +} + +static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, + const aufs_bindex_t bend) +{ + struct au_hinode *hip, *p; + + AuRwMustWriteLock(&iinfo->ii_rwsem); + + hip = iinfo->ii_hinode + bindex; + if (bindex < bend) + memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex)); + iinfo->ii_hinode[0 + bend].hi_inode = NULL; + au_hn_init(iinfo->ii_hinode + bend); + iinfo->ii_bend--; + + p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, AuGFP_SBILIST); + if (p) + iinfo->ii_hinode = p; + /* harmless error */ +} + +static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, + struct au_branch *br) +{ + aufs_bindex_t bend; + struct au_sbinfo *sbinfo; + struct dentry *root, *h_root; + struct inode *inode, *h_inode; + struct au_hinode *hinode; + + SiMustWriteLock(sb); + + root = sb->s_root; + inode = root->d_inode; + sbinfo = au_sbi(sb); + bend = sbinfo->si_bend; + + h_root = au_h_dptr(root, bindex); + hinode = au_hi(inode, bindex); + h_inode = au_igrab(hinode->hi_inode); + au_hiput(hinode); + + au_sbilist_lock(); + au_br_do_del_brp(sbinfo, bindex, bend); + au_br_do_del_hdp(au_di(root), bindex, bend); + au_br_do_del_hip(au_ii(inode), bindex, bend); + au_sbilist_unlock(); + + dput(h_root); + iput(h_inode); + au_br_do_free(br); +} + +int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) +{ + int err, rerr, i; + unsigned int mnt_flags; + aufs_bindex_t bindex, bend, br_id; + unsigned char do_wh, verbose; + struct au_branch *br; + struct au_wbr *wbr; + + err = 0; + bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); + if (bindex < 0) { + if (remount) + goto out; /* success */ + err = -ENOENT; + pr_err("%s no such branch\n", del->pathname); + goto out; + } + AuDbg("bindex b%d\n", bindex); + + err = -EBUSY; + mnt_flags = au_mntflags(sb); + verbose = !!au_opt_test(mnt_flags, VERBOSE); + bend = au_sbend(sb); + if (unlikely(!bend)) { + AuVerbose(verbose, "no more branches left\n"); + goto out; + } + br = au_sbr(sb, bindex); + AuDebugOn(!path_equal(&br->br_path, &del->h_path)); + i = atomic_read(&br->br_count); + if (unlikely(i)) { + AuVerbose(verbose, "%d file(s) opened\n", i); + goto out; + } + + wbr = br->br_wbr; + do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); + if (do_wh) { + /* instead of WbrWhMustWriteLock(wbr) */ + SiMustWriteLock(sb); + for (i = 0; i < AuBrWh_Last; i++) { + dput(wbr->wbr_wh[i]); + wbr->wbr_wh[i] = NULL; + } + } + + err = test_children_busy(sb->s_root, bindex, verbose); + if (unlikely(err)) { + if (do_wh) + goto out_wh; + goto out; + } + + err = 0; + br_id = br->br_id; + if (!remount) + au_br_do_del(sb, bindex, br); + else { + sysaufs_brs_del(sb, bindex); + au_br_do_del(sb, bindex, br); + sysaufs_brs_add(sb, bindex); + } + + if (!bindex) { + au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); + sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; + } else + au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); + if (au_opt_test(mnt_flags, PLINK)) + au_plink_half_refresh(sb, br_id); + + if (au_xino_brid(sb) == br_id) + au_xino_brid_set(sb, -1); + goto out; /* success */ + +out_wh: + /* revert */ + rerr = au_br_init_wh(sb, br, br->br_perm); + if (rerr) + pr_warn("failed re-creating base whiteout, %s. (%d)\n", + del->pathname, rerr); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) +{ + int err; + aufs_bindex_t bstart, bend; + struct aufs_ibusy ibusy; + struct inode *inode, *h_inode; + + err = -EPERM; + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + + err = copy_from_user(&ibusy, arg, sizeof(ibusy)); + if (!err) + err = !access_ok(VERIFY_WRITE, &arg->h_ino, sizeof(arg->h_ino)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + + err = -EINVAL; + si_read_lock(sb, AuLock_FLUSH); + if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbend(sb))) + goto out_unlock; + + err = 0; + ibusy.h_ino = 0; /* invalid */ + inode = ilookup(sb, ibusy.ino); + if (!inode + || inode->i_ino == AUFS_ROOT_INO + || is_bad_inode(inode)) + goto out_unlock; + + ii_read_lock_child(inode); + bstart = au_ibstart(inode); + bend = au_ibend(inode); + if (bstart <= ibusy.bindex && ibusy.bindex <= bend) { + h_inode = au_h_iptr(inode, ibusy.bindex); + if (h_inode && au_test_ibusy(inode, bstart, bend)) + ibusy.h_ino = h_inode->i_ino; + } + ii_read_unlock(inode); + iput(inode); + +out_unlock: + si_read_unlock(sb); + if (!err) { + err = __put_user(ibusy.h_ino, &arg->h_ino); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + } + } +out: + return err; +} + +long au_ibusy_ioctl(struct file *file, unsigned long arg) +{ + return au_ibusy(file->f_dentry->d_sb, (void __user *)arg); +} + +#ifdef CONFIG_COMPAT +long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) +{ + return au_ibusy(file->f_dentry->d_sb, compat_ptr(arg)); +} +#endif + +/* ---------------------------------------------------------------------- */ + +/* + * change a branch permission + */ + +static void au_warn_ima(void) +{ +#ifdef CONFIG_IMA + /* since it doesn't support mark_files_ro() */ + AuWarn1("RW -> RO makes IMA to produce wrong message\n"); +#endif +} + +static int do_need_sigen_inc(int a, int b) +{ + return au_br_whable(a) && !au_br_whable(b); +} + +static int need_sigen_inc(int old, int new) +{ + return do_need_sigen_inc(old, new) + || do_need_sigen_inc(new, old); +} + +static unsigned long long au_farray_cb(void *a, + unsigned long long max __maybe_unused, + void *arg) +{ + unsigned long long n; + struct file **p, *f; + struct au_sphlhead *files; + struct au_finfo *finfo; + struct super_block *sb = arg; + + n = 0; + p = a; + files = &au_sbi(sb)->si_files; + spin_lock(&files->spin); + hlist_for_each_entry(finfo, &files->head, fi_hlist) { + f = finfo->fi_file; + if (file_count(f) + && !special_file(file_inode(f)->i_mode)) { + get_file(f); + *p++ = f; + n++; + AuDebugOn(n > max); + } + } + spin_unlock(&files->spin); + + return n; +} + +static struct file **au_farray_alloc(struct super_block *sb, + unsigned long long *max) +{ + *max = atomic_long_read(&au_sbi(sb)->si_nfiles); + return au_array_alloc(max, au_farray_cb, sb); +} + +static void au_farray_free(struct file **a, unsigned long long max) +{ + unsigned long long ull; + + for (ull = 0; ull < max; ull++) + if (a[ull]) + fput(a[ull]); + au_array_free(a); +} + +static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) +{ + int err, do_warn; + unsigned int mnt_flags; + unsigned long long ull, max; + aufs_bindex_t br_id; + unsigned char verbose; + struct file *file, *hf, **array; + struct inode *inode; + struct au_hfile *hfile; + + mnt_flags = au_mntflags(sb); + verbose = !!au_opt_test(mnt_flags, VERBOSE); + + array = au_farray_alloc(sb, &max); + err = PTR_ERR(array); + if (IS_ERR(array)) + goto out; + + do_warn = 0; + br_id = au_sbr_id(sb, bindex); + for (ull = 0; ull < max; ull++) { + file = array[ull]; + + /* AuDbg("%pD\n", file); */ + fi_read_lock(file); + if (unlikely(au_test_mmapped(file))) { + err = -EBUSY; + AuVerbose(verbose, "mmapped %pD\n", file); + AuDbgFile(file); + FiMustNoWaiters(file); + fi_read_unlock(file); + goto out_array; + } + + inode = file_inode(file); + hfile = &au_fi(file)->fi_htop; + hf = hfile->hf_file; + if (!S_ISREG(inode->i_mode) + || !(file->f_mode & FMODE_WRITE) + || hfile->hf_br->br_id != br_id + || !(hf->f_mode & FMODE_WRITE)) + array[ull] = NULL; + else { + do_warn = 1; + get_file(file); + } + + FiMustNoWaiters(file); + fi_read_unlock(file); + fput(file); + } + + err = 0; + if (do_warn) + au_warn_ima(); + + for (ull = 0; ull < max; ull++) { + file = array[ull]; + if (!file) + continue; + + /* todo: already flushed? */ + /* + * fs/super.c:mark_files_ro() is gone, but aufs keeps its + * approach which resets f_mode and calls mnt_drop_write() and + * file_release_write() for each file, because the branch + * attribute in aufs world is totally different from the native + * fs rw/ro mode. + */ + /* fi_read_lock(file); */ + hfile = &au_fi(file)->fi_htop; + hf = hfile->hf_file; + /* fi_read_unlock(file); */ + spin_lock(&hf->f_lock); + hf->f_mode &= ~FMODE_WRITE; + spin_unlock(&hf->f_lock); + if (!file_check_writeable(hf)) { + __mnt_drop_write(hf->f_path.mnt); + file_release_write(hf); + } + } + +out_array: + au_farray_free(array, max); +out: + AuTraceErr(err); + return err; +} + +int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, + int *do_refresh) +{ + int err, rerr; + aufs_bindex_t bindex; + struct dentry *root; + struct au_branch *br; + + root = sb->s_root; + bindex = au_find_dbindex(root, mod->h_root); + if (bindex < 0) { + if (remount) + return 0; /* success */ + err = -ENOENT; + pr_err("%s no such branch\n", mod->path); + goto out; + } + AuDbg("bindex b%d\n", bindex); + + err = test_br(mod->h_root->d_inode, mod->perm, mod->path); + if (unlikely(err)) + goto out; + + br = au_sbr(sb, bindex); + AuDebugOn(mod->h_root != au_br_dentry(br)); + if (br->br_perm == mod->perm) + return 0; /* success */ + + if (au_br_writable(br->br_perm)) { + /* remove whiteout base */ + err = au_br_init_wh(sb, br, mod->perm); + if (unlikely(err)) + goto out; + + if (!au_br_writable(mod->perm)) { + /* rw --> ro, file might be mmapped */ + DiMustNoWaiters(root); + IiMustNoWaiters(root->d_inode); + di_write_unlock(root); + err = au_br_mod_files_ro(sb, bindex); + /* aufs_write_lock() calls ..._child() */ + di_write_lock_child(root); + + if (unlikely(err)) { + rerr = -ENOMEM; + br->br_wbr = kmalloc(sizeof(*br->br_wbr), + GFP_NOFS); + if (br->br_wbr) + rerr = au_wbr_init(br, sb, br->br_perm); + if (unlikely(rerr)) { + AuIOErr("nested error %d (%d)\n", + rerr, err); + br->br_perm = mod->perm; + } + } + } + } else if (au_br_writable(mod->perm)) { + /* ro --> rw */ + err = -ENOMEM; + br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS); + if (br->br_wbr) { + err = au_wbr_init(br, sb, mod->perm); + if (unlikely(err)) { + kfree(br->br_wbr); + br->br_wbr = NULL; + } + } + } + + if (!err) { + if ((br->br_perm & AuBrAttr_UNPIN) + && !(mod->perm & AuBrAttr_UNPIN)) + au_br_dflags_force(br); + else if (!(br->br_perm & AuBrAttr_UNPIN) + && (mod->perm & AuBrAttr_UNPIN)) + au_br_dflags_restore(br); + *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); + br->br_perm = mod->perm; + } + +out: + AuTraceErr(err); + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/procfs.c +++ linux-3.13.0/ubuntu/aufs/procfs.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * procfs interfaces + */ + +#include +#include "aufs.h" + +static int au_procfs_plm_release(struct inode *inode, struct file *file) +{ + struct au_sbinfo *sbinfo; + + sbinfo = file->private_data; + if (sbinfo) { + au_plink_maint_leave(sbinfo); + kobject_put(&sbinfo->si_kobj); + } + + return 0; +} + +static void au_procfs_plm_write_clean(struct file *file) +{ + struct au_sbinfo *sbinfo; + + sbinfo = file->private_data; + if (sbinfo) + au_plink_clean(sbinfo->si_sb, /*verbose*/0); +} + +static int au_procfs_plm_write_si(struct file *file, unsigned long id) +{ + int err; + struct super_block *sb; + struct au_sbinfo *sbinfo; + + err = -EBUSY; + if (unlikely(file->private_data)) + goto out; + + sb = NULL; + /* don't use au_sbilist_lock() here */ + spin_lock(&au_sbilist.spin); + list_for_each_entry(sbinfo, &au_sbilist.head, si_list) + if (id == sysaufs_si_id(sbinfo)) { + kobject_get(&sbinfo->si_kobj); + sb = sbinfo->si_sb; + break; + } + spin_unlock(&au_sbilist.spin); + + err = -EINVAL; + if (unlikely(!sb)) + goto out; + + err = au_plink_maint_enter(sb); + if (!err) + /* keep kobject_get() */ + file->private_data = sbinfo; + else + kobject_put(&sbinfo->si_kobj); +out: + return err; +} + +/* + * Accept a valid "si=xxxx" only. + * Once it is accepted successfully, accept "clean" too. + */ +static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t err; + unsigned long id; + /* last newline is allowed */ + char buf[3 + sizeof(unsigned long) * 2 + 1]; + + err = -EACCES; + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + + err = -EINVAL; + if (unlikely(count > sizeof(buf))) + goto out; + + err = copy_from_user(buf, ubuf, count); + if (unlikely(err)) { + err = -EFAULT; + goto out; + } + buf[count] = 0; + + err = -EINVAL; + if (!strcmp("clean", buf)) { + au_procfs_plm_write_clean(file); + goto out_success; + } else if (unlikely(strncmp("si=", buf, 3))) + goto out; + + err = kstrtoul(buf + 3, 16, &id); + if (unlikely(err)) + goto out; + + err = au_procfs_plm_write_si(file, id); + if (unlikely(err)) + goto out; + +out_success: + err = count; /* success */ +out: + return err; +} + +static const struct file_operations au_procfs_plm_fop = { + .write = au_procfs_plm_write, + .release = au_procfs_plm_release, + .owner = THIS_MODULE +}; + +/* ---------------------------------------------------------------------- */ + +static struct proc_dir_entry *au_procfs_dir; + +void au_procfs_fin(void) +{ + remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); + remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); +} + +int __init au_procfs_init(void) +{ + int err; + struct proc_dir_entry *entry; + + err = -ENOMEM; + au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); + if (unlikely(!au_procfs_dir)) + goto out; + + entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR, + au_procfs_dir, &au_procfs_plm_fop); + if (unlikely(!entry)) + goto out_dir; + + err = 0; + goto out; /* success */ + + +out_dir: + remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); +out: + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/whout.c +++ linux-3.13.0/ubuntu/aufs/whout.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * whiteout for logical deletion and opaque directory + */ + +#include "aufs.h" + +#define WH_MASK S_IRUGO + +/* + * If a directory contains this file, then it is opaque. We start with the + * .wh. flag so that it is blocked by lookup. + */ +static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, + sizeof(AUFS_WH_DIROPQ) - 1); + +/* + * generate whiteout name, which is NOT terminated by NULL. + * @name: original d_name.name + * @len: original d_name.len + * @wh: whiteout qstr + * returns zero when succeeds, otherwise error. + * succeeded value as wh->name should be freed by kfree(). + */ +int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) +{ + char *p; + + if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) + return -ENAMETOOLONG; + + wh->len = name->len + AUFS_WH_PFX_LEN; + p = kmalloc(wh->len, GFP_NOFS); + wh->name = p; + if (p) { + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); + /* smp_mb(); */ + return 0; + } + return -ENOMEM; +} + +/* ---------------------------------------------------------------------- */ + +/* + * test if the @wh_name exists under @h_parent. + * @try_sio specifies the necessary of super-io. + */ +int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, + struct au_branch *br, int try_sio) +{ + int err; + struct dentry *wh_dentry; + + if (!try_sio) + wh_dentry = vfsub_lkup_one(wh_name, h_parent); + else + wh_dentry = au_sio_lkup_one(wh_name, h_parent, br); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + err = 0; + if (!wh_dentry->d_inode) + goto out_wh; /* success */ + + err = 1; + if (S_ISREG(wh_dentry->d_inode->i_mode)) + goto out_wh; /* success */ + + err = -EIO; + AuIOErr("%pd Invalid whiteout entry type 0%o.\n", + wh_dentry, wh_dentry->d_inode->i_mode); + +out_wh: + dput(wh_dentry); +out: + return err; +} + +/* + * test if the @h_dentry sets opaque or not. + */ +int au_diropq_test(struct dentry *h_dentry, struct au_branch *br) +{ + int err; + struct inode *h_dir; + + h_dir = h_dentry->d_inode; + err = au_wh_test(h_dentry, &diropq_name, br, + au_test_h_perm_sio(h_dir, MAY_EXEC)); + return err; +} + +/* + * returns a negative dentry whose name is unique and temporary. + */ +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, + struct qstr *prefix) +{ + struct dentry *dentry; + int i; + char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], + *name, *p; + /* strict atomic_t is unnecessary here */ + static unsigned short cnt; + struct qstr qs; + + BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); + + name = defname; + qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; + if (unlikely(prefix->len > DNAME_INLINE_LEN)) { + dentry = ERR_PTR(-ENAMETOOLONG); + if (unlikely(qs.len > NAME_MAX)) + goto out; + dentry = ERR_PTR(-ENOMEM); + name = kmalloc(qs.len + 1, GFP_NOFS); + if (unlikely(!name)) + goto out; + } + + /* doubly whiteout-ed */ + memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); + p = name + AUFS_WH_PFX_LEN * 2; + memcpy(p, prefix->name, prefix->len); + p += prefix->len; + *p++ = '.'; + AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); + + qs.name = name; + for (i = 0; i < 3; i++) { + sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); + dentry = au_sio_lkup_one(&qs, h_parent, br); + if (IS_ERR(dentry) || !dentry->d_inode) + goto out_name; + dput(dentry); + } + /* pr_warn("could not get random name\n"); */ + dentry = ERR_PTR(-EEXIST); + AuDbg("%.*s\n", AuLNPair(&qs)); + BUG(); + +out_name: + if (name != defname) + kfree(name); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* + * rename the @h_dentry on @br to the whiteouted temporary name. + */ +int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) +{ + int err; + struct path h_path = { + .mnt = au_br_mnt(br) + }; + struct inode *h_dir, *delegated; + struct dentry *h_parent; + + h_parent = h_dentry->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + + h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) + goto out; + + /* under the same dir, no need to lock_rename() */ + delegated = NULL; + err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated); + AuTraceErr(err); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + dput(h_path.dentry); + +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ +/* + * functions for removing a whiteout + */ + +static int do_unlink_wh(struct inode *h_dir, struct path *h_path) +{ + int err, force; + struct inode *delegated; + + /* + * forces superio when the dir has a sticky bit. + * this may be a violation of unix fs semantics. + */ + force = (h_dir->i_mode & S_ISVTX) + && !uid_eq(current_fsuid(), h_path->dentry->d_inode->i_uid); + delegated = NULL; + err = vfsub_unlink(h_dir, h_path, &delegated, force); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + return err; +} + +int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, + struct dentry *dentry) +{ + int err; + + err = do_unlink_wh(h_dir, h_path); + if (!err && dentry) + au_set_dbwh(dentry, -1); + + return err; +} + +static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, + struct au_branch *br) +{ + int err; + struct path h_path = { + .mnt = au_br_mnt(br) + }; + + err = 0; + h_path.dentry = vfsub_lkup_one(wh, h_parent); + if (IS_ERR(h_path.dentry)) + err = PTR_ERR(h_path.dentry); + else { + if (h_path.dentry->d_inode + && S_ISREG(h_path.dentry->d_inode->i_mode)) + err = do_unlink_wh(h_parent->d_inode, &h_path); + dput(h_path.dentry); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ +/* + * initialize/clean whiteout for a branch + */ + +static void au_wh_clean(struct inode *h_dir, struct path *whpath, + const int isdir) +{ + int err; + struct inode *delegated; + + if (!whpath->dentry->d_inode) + return; + + if (isdir) + err = vfsub_rmdir(h_dir, whpath); + else { + delegated = NULL; + err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + } + if (unlikely(err)) + pr_warn("failed removing %pd (%d), ignored.\n", + whpath->dentry, err); +} + +static int test_linkable(struct dentry *h_root) +{ + struct inode *h_dir = h_root->d_inode; + + if (h_dir->i_op->link) + return 0; + + pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", + h_root, au_sbtype(h_root->d_sb)); + return -ENOSYS; +} + +/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ +static int au_whdir(struct inode *h_dir, struct path *path) +{ + int err; + + err = -EEXIST; + if (!path->dentry->d_inode) { + int mode = S_IRWXU; + + if (au_test_nfs(path->dentry->d_sb)) + mode |= S_IXUGO; + err = vfsub_mkdir(h_dir, path, mode); + } else if (S_ISDIR(path->dentry->d_inode->i_mode)) + err = 0; + else + pr_err("unknown %pd exists\n", path->dentry); + + return err; +} + +struct au_wh_base { + const struct qstr *name; + struct dentry *dentry; +}; + +static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], + struct path *h_path) +{ + h_path->dentry = base[AuBrWh_BASE].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/0); + h_path->dentry = base[AuBrWh_PLINK].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/1); + h_path->dentry = base[AuBrWh_ORPH].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/1); +} + +/* + * returns tri-state, + * minus: error, caller should print the mesage + * zero: succuess + * plus: error, caller should NOT print the mesage + */ +static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, + int do_plink, struct au_wh_base base[], + struct path *h_path) +{ + int err; + struct inode *h_dir; + + h_dir = h_root->d_inode; + h_path->dentry = base[AuBrWh_BASE].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/0); + h_path->dentry = base[AuBrWh_PLINK].dentry; + if (do_plink) { + err = test_linkable(h_root); + if (unlikely(err)) { + err = 1; + goto out; + } + + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); + } else + au_wh_clean(h_dir, h_path, /*isdir*/1); + h_path->dentry = base[AuBrWh_ORPH].dentry; + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); + +out: + return err; +} + +/* + * for the moment, aufs supports the branch filesystem which does not support + * link(2). testing on FAT which does not support i_op->setattr() fully either, + * copyup failed. finally, such filesystem will not be used as the writable + * branch. + * + * returns tri-state, see above. + */ +static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, + int do_plink, struct au_wh_base base[], + struct path *h_path) +{ + int err; + struct inode *h_dir; + + WbrWhMustWriteLock(wbr); + + err = test_linkable(h_root); + if (unlikely(err)) { + err = 1; + goto out; + } + + /* + * todo: should this create be done in /sbin/mount.aufs helper? + */ + err = -EEXIST; + h_dir = h_root->d_inode; + if (!base[AuBrWh_BASE].dentry->d_inode) { + h_path->dentry = base[AuBrWh_BASE].dentry; + err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); + } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode)) + err = 0; + else + pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); + if (unlikely(err)) + goto out; + + h_path->dentry = base[AuBrWh_PLINK].dentry; + if (do_plink) { + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); + } else + au_wh_clean(h_dir, h_path, /*isdir*/1); + wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); + + h_path->dentry = base[AuBrWh_ORPH].dentry; + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); + +out: + return err; +} + +/* + * initialize the whiteout base file/dir for @br. + */ +int au_wh_init(struct au_branch *br, struct super_block *sb) +{ + int err, i; + const unsigned char do_plink + = !!au_opt_test(au_mntflags(sb), PLINK); + struct inode *h_dir; + struct path path = br->br_path; + struct dentry *h_root = path.dentry; + struct au_wbr *wbr = br->br_wbr; + static const struct qstr base_name[] = { + [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, + sizeof(AUFS_BASE_NAME) - 1), + [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, + sizeof(AUFS_PLINKDIR_NAME) - 1), + [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, + sizeof(AUFS_ORPHDIR_NAME) - 1) + }; + struct au_wh_base base[] = { + [AuBrWh_BASE] = { + .name = base_name + AuBrWh_BASE, + .dentry = NULL + }, + [AuBrWh_PLINK] = { + .name = base_name + AuBrWh_PLINK, + .dentry = NULL + }, + [AuBrWh_ORPH] = { + .name = base_name + AuBrWh_ORPH, + .dentry = NULL + } + }; + + if (wbr) + WbrWhMustWriteLock(wbr); + + for (i = 0; i < AuBrWh_Last; i++) { + /* doubly whiteouted */ + struct dentry *d; + + d = au_wh_lkup(h_root, (void *)base[i].name, br); + err = PTR_ERR(d); + if (IS_ERR(d)) + goto out; + + base[i].dentry = d; + AuDebugOn(wbr + && wbr->wbr_wh[i] + && wbr->wbr_wh[i] != base[i].dentry); + } + + if (wbr) + for (i = 0; i < AuBrWh_Last; i++) { + dput(wbr->wbr_wh[i]); + wbr->wbr_wh[i] = NULL; + } + + err = 0; + if (!au_br_writable(br->br_perm)) { + h_dir = h_root->d_inode; + au_wh_init_ro(h_dir, base, &path); + } else if (!au_br_wh_linkable(br->br_perm)) { + err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); + if (err > 0) + goto out; + else if (err) + goto out_err; + } else { + err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); + if (err > 0) + goto out; + else if (err) + goto out_err; + } + goto out; /* success */ + +out_err: + pr_err("an error(%d) on the writable branch %pd(%s)\n", + err, h_root, au_sbtype(h_root->d_sb)); +out: + for (i = 0; i < AuBrWh_Last; i++) + dput(base[i].dentry); + return err; +} + +/* ---------------------------------------------------------------------- */ +/* + * whiteouts are all hard-linked usually. + * when its link count reaches a ceiling, we create a new whiteout base + * asynchronously. + */ + +struct reinit_br_wh { + struct super_block *sb; + struct au_branch *br; +}; + +static void reinit_br_wh(void *arg) +{ + int err; + aufs_bindex_t bindex; + struct path h_path; + struct reinit_br_wh *a = arg; + struct au_wbr *wbr; + struct inode *dir, *delegated; + struct dentry *h_root; + struct au_hinode *hdir; + + err = 0; + wbr = a->br->br_wbr; + /* big aufs lock */ + si_noflush_write_lock(a->sb); + if (!au_br_writable(a->br->br_perm)) + goto out; + bindex = au_br_index(a->sb, a->br->br_id); + if (unlikely(bindex < 0)) + goto out; + + di_read_lock_parent(a->sb->s_root, AuLock_IR); + dir = a->sb->s_root->d_inode; + hdir = au_hi(dir, bindex); + h_root = au_h_dptr(a->sb->s_root, bindex); + AuDebugOn(h_root != au_br_dentry(a->br)); + + au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); + wbr_wh_write_lock(wbr); + err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, + h_root, a->br); + if (!err) { + h_path.dentry = wbr->wbr_whbase; + h_path.mnt = au_br_mnt(a->br); + delegated = NULL; + err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, + /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + } else { + pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); + err = 0; + } + dput(wbr->wbr_whbase); + wbr->wbr_whbase = NULL; + if (!err) + err = au_wh_init(a->br, a->sb); + wbr_wh_write_unlock(wbr); + au_hn_imtx_unlock(hdir); + di_read_unlock(a->sb->s_root, AuLock_IR); + +out: + if (wbr) + atomic_dec(&wbr->wbr_wh_running); + atomic_dec(&a->br->br_count); + si_write_unlock(a->sb); + au_nwt_done(&au_sbi(a->sb)->si_nowait); + kfree(arg); + if (unlikely(err)) + AuIOErr("err %d\n", err); +} + +static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) +{ + int do_dec, wkq_err; + struct reinit_br_wh *arg; + + do_dec = 1; + if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) + goto out; + + /* ignore ENOMEM */ + arg = kmalloc(sizeof(*arg), GFP_NOFS); + if (arg) { + /* + * dec(wh_running), kfree(arg) and dec(br_count) + * in reinit function + */ + arg->sb = sb; + arg->br = br; + atomic_inc(&br->br_count); + wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); + if (unlikely(wkq_err)) { + atomic_dec(&br->br_wbr->wbr_wh_running); + atomic_dec(&br->br_count); + kfree(arg); + } + do_dec = 0; + } + +out: + if (do_dec) + atomic_dec(&br->br_wbr->wbr_wh_running); +} + +/* ---------------------------------------------------------------------- */ + +/* + * create the whiteout @wh. + */ +static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, + struct dentry *wh) +{ + int err; + struct path h_path = { + .dentry = wh + }; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *h_parent; + struct inode *h_dir, *delegated; + + h_parent = wh->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + + br = au_sbr(sb, bindex); + h_path.mnt = au_br_mnt(br); + wbr = br->br_wbr; + wbr_wh_read_lock(wbr); + if (wbr->wbr_whbase) { + delegated = NULL; + err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + if (!err || err != -EMLINK) + goto out; + + /* link count full. re-initialize br_whbase. */ + kick_reinit_br_wh(sb, br); + } + + /* return this error in this context */ + err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); + +out: + wbr_wh_read_unlock(wbr); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * create or remove the diropq. + */ +static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags) +{ + struct dentry *opq_dentry, *h_dentry; + struct super_block *sb; + struct au_branch *br; + int err; + + sb = dentry->d_sb; + br = au_sbr(sb, bindex); + h_dentry = au_h_dptr(dentry, bindex); + opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); + if (IS_ERR(opq_dentry)) + goto out; + + if (au_ftest_diropq(flags, CREATE)) { + err = link_or_create_wh(sb, bindex, opq_dentry); + if (!err) { + au_set_dbdiropq(dentry, bindex); + goto out; /* success */ + } + } else { + struct path tmp = { + .dentry = opq_dentry, + .mnt = au_br_mnt(br) + }; + err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp); + if (!err) + au_set_dbdiropq(dentry, -1); + } + dput(opq_dentry); + opq_dentry = ERR_PTR(err); + +out: + return opq_dentry; +} + +struct do_diropq_args { + struct dentry **errp; + struct dentry *dentry; + aufs_bindex_t bindex; + unsigned int flags; +}; + +static void call_do_diropq(void *args) +{ + struct do_diropq_args *a = args; + *a->errp = do_diropq(a->dentry, a->bindex, a->flags); +} + +struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags) +{ + struct dentry *diropq, *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE)) + diropq = do_diropq(dentry, bindex, flags); + else { + int wkq_err; + struct do_diropq_args args = { + .errp = &diropq, + .dentry = dentry, + .bindex = bindex, + .flags = flags + }; + + wkq_err = au_wkq_wait(call_do_diropq, &args); + if (unlikely(wkq_err)) + diropq = ERR_PTR(wkq_err); + } + + return diropq; +} + +/* ---------------------------------------------------------------------- */ + +/* + * lookup whiteout dentry. + * @h_parent: lower parent dentry which must exist and be locked + * @base_name: name of dentry which will be whiteouted + * returns dentry for whiteout. + */ +struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, + struct au_branch *br) +{ + int err; + struct qstr wh_name; + struct dentry *wh_dentry; + + err = au_wh_name_alloc(&wh_name, base_name); + wh_dentry = ERR_PTR(err); + if (!err) { + wh_dentry = vfsub_lkup_one(&wh_name, h_parent); + kfree(wh_name.name); + } + return wh_dentry; +} + +/* + * link/create a whiteout for @dentry on @bindex. + */ +struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent) +{ + struct dentry *wh_dentry; + struct super_block *sb; + int err; + + sb = dentry->d_sb; + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); + if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { + err = link_or_create_wh(sb, bindex, wh_dentry); + if (!err) + au_set_dbwh(dentry, bindex); + else { + dput(wh_dentry); + wh_dentry = ERR_PTR(err); + } + } + + return wh_dentry; +} + +/* ---------------------------------------------------------------------- */ + +/* Delete all whiteouts in this directory on branch bindex. */ +static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, + aufs_bindex_t bindex, struct au_branch *br) +{ + int err; + unsigned long ul, n; + struct qstr wh_name; + char *p; + struct hlist_head *head; + struct au_vdir_wh *pos; + struct au_vdir_destr *str; + + err = -ENOMEM; + p = (void *)__get_free_page(GFP_NOFS); + wh_name.name = p; + if (unlikely(!wh_name.name)) + goto out; + + err = 0; + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + p += AUFS_WH_PFX_LEN; + n = whlist->nh_num; + head = whlist->nh_head; + for (ul = 0; !err && ul < n; ul++, head++) { + hlist_for_each_entry(pos, head, wh_hash) { + if (pos->wh_bindex != bindex) + continue; + + str = &pos->wh_str; + if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { + memcpy(p, str->name, str->len); + wh_name.len = AUFS_WH_PFX_LEN + str->len; + err = unlink_wh_name(h_dentry, &wh_name, br); + if (!err) + continue; + break; + } + AuIOErr("whiteout name too long %.*s\n", + str->len, str->name); + err = -EIO; + break; + } + } + free_page((unsigned long)wh_name.name); + +out: + return err; +} + +struct del_wh_children_args { + int *errp; + struct dentry *h_dentry; + struct au_nhash *whlist; + aufs_bindex_t bindex; + struct au_branch *br; +}; + +static void call_del_wh_children(void *args) +{ + struct del_wh_children_args *a = args; + *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); +} + +/* ---------------------------------------------------------------------- */ + +struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) +{ + struct au_whtmp_rmdir *whtmp; + int err; + unsigned int rdhash; + + SiMustAnyLock(sb); + + whtmp = kmalloc(sizeof(*whtmp), gfp); + if (unlikely(!whtmp)) { + whtmp = ERR_PTR(-ENOMEM); + goto out; + } + + whtmp->dir = NULL; + whtmp->br = NULL; + whtmp->wh_dentry = NULL; + /* no estimation for dir size */ + rdhash = au_sbi(sb)->si_rdhash; + if (!rdhash) + rdhash = AUFS_RDHASH_DEF; + err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); + if (unlikely(err)) { + kfree(whtmp); + whtmp = ERR_PTR(err); + } + +out: + return whtmp; +} + +void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) +{ + if (whtmp->br) + atomic_dec(&whtmp->br->br_count); + dput(whtmp->wh_dentry); + iput(whtmp->dir); + au_nhash_wh_free(&whtmp->whlist); + kfree(whtmp); +} + +/* + * rmdir the whiteouted temporary named dir @h_dentry. + * @whlist: whiteouted children. + */ +int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist) +{ + int err; + struct path h_tmp; + struct inode *wh_inode, *h_dir; + struct au_branch *br; + + h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ + IMustLock(h_dir); + + br = au_sbr(dir->i_sb, bindex); + wh_inode = wh_dentry->d_inode; + mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD); + + /* + * someone else might change some whiteouts while we were sleeping. + * it means this whlist may have an obsoleted entry. + */ + if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) + err = del_wh_children(wh_dentry, whlist, bindex, br); + else { + int wkq_err; + struct del_wh_children_args args = { + .errp = &err, + .h_dentry = wh_dentry, + .whlist = whlist, + .bindex = bindex, + .br = br + }; + + wkq_err = au_wkq_wait(call_del_wh_children, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + mutex_unlock(&wh_inode->i_mutex); + + if (!err) { + h_tmp.dentry = wh_dentry; + h_tmp.mnt = au_br_mnt(br); + err = vfsub_rmdir(h_dir, &h_tmp); + } + + if (!err) { + if (au_ibstart(dir) == bindex) { + /* todo: dir->i_mutex is necessary */ + au_cpup_attr_timesizes(dir); + vfsub_drop_nlink(dir); + } + return 0; /* success */ + } + + pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); + return err; +} + +static void call_rmdir_whtmp(void *args) +{ + int err; + aufs_bindex_t bindex; + struct au_whtmp_rmdir *a = args; + struct super_block *sb; + struct dentry *h_parent; + struct inode *h_dir; + struct au_hinode *hdir; + + /* rmdir by nfsd may cause deadlock with this i_mutex */ + /* mutex_lock(&a->dir->i_mutex); */ + err = -EROFS; + sb = a->dir->i_sb; + si_read_lock(sb, !AuLock_FLUSH); + if (!au_br_writable(a->br->br_perm)) + goto out; + bindex = au_br_index(sb, a->br->br_id); + if (unlikely(bindex < 0)) + goto out; + + err = -EIO; + ii_write_lock_parent(a->dir); + h_parent = dget_parent(a->wh_dentry); + h_dir = h_parent->d_inode; + hdir = au_hi(a->dir, bindex); + err = vfsub_mnt_want_write(au_br_mnt(a->br)); + if (unlikely(err)) + goto out_mnt; + au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); + err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, + a->br); + if (!err) + err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); + au_hn_imtx_unlock(hdir); + vfsub_mnt_drop_write(au_br_mnt(a->br)); + +out_mnt: + dput(h_parent); + ii_write_unlock(a->dir); +out: + /* mutex_unlock(&a->dir->i_mutex); */ + au_whtmp_rmdir_free(a); + si_read_unlock(sb); + au_nwt_done(&au_sbi(sb)->si_nowait); + if (unlikely(err)) + AuIOErr("err %d\n", err); +} + +void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_whtmp_rmdir *args) +{ + int wkq_err; + struct super_block *sb; + + IMustLock(dir); + + /* all post-process will be done in do_rmdir_whtmp(). */ + sb = dir->i_sb; + args->dir = au_igrab(dir); + args->br = au_sbr(sb, bindex); + atomic_inc(&args->br->br_count); + args->wh_dentry = dget(wh_dentry); + wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); + if (unlikely(wkq_err)) { + pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); + au_whtmp_rmdir_free(args); + } +} --- linux-3.13.0.orig/ubuntu/aufs/opts.h +++ linux-3.13.0/ubuntu/aufs/opts.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * mount options/flags + */ + +#ifndef __AUFS_OPTS_H__ +#define __AUFS_OPTS_H__ + +#ifdef __KERNEL__ + +#include + +struct file; +struct super_block; + +/* ---------------------------------------------------------------------- */ + +/* mount flags */ +#define AuOpt_XINO 1 /* external inode number bitmap + and translation table */ +#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ +#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ +#define AuOpt_UDBA_REVAL (1 << 3) +#define AuOpt_UDBA_HNOTIFY (1 << 4) +#define AuOpt_SHWH (1 << 5) /* show whiteout */ +#define AuOpt_PLINK (1 << 6) /* pseudo-link */ +#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */ +#define AuOpt_REFROF (1 << 8) /* unimplemented */ +#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ +#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ +#define AuOpt_SUM_W (1 << 11) /* unimplemented */ +#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ +#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */ +#define AuOpt_DIO (1 << 14) /* direct io */ + +#ifndef CONFIG_AUFS_HNOTIFY +#undef AuOpt_UDBA_HNOTIFY +#define AuOpt_UDBA_HNOTIFY 0 +#endif +#ifndef CONFIG_AUFS_SHWH +#undef AuOpt_SHWH +#define AuOpt_SHWH 0 +#endif + +#define AuOpt_Def (AuOpt_XINO \ + | AuOpt_UDBA_REVAL \ + | AuOpt_PLINK \ + /* | AuOpt_DIRPERM1 */ \ + | AuOpt_WARN_PERM) +#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ + | AuOpt_UDBA_REVAL \ + | AuOpt_UDBA_HNOTIFY) + +#define au_opt_test(flags, name) (flags & AuOpt_##name) +#define au_opt_set(flags, name) do { \ + BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ + ((flags) |= AuOpt_##name); \ +} while (0) +#define au_opt_set_udba(flags, name) do { \ + (flags) &= ~AuOptMask_UDBA; \ + ((flags) |= AuOpt_##name); \ +} while (0) +#define au_opt_clr(flags, name) do { \ + ((flags) &= ~AuOpt_##name); \ +} while (0) + +static inline unsigned int au_opts_plink(unsigned int mntflags) +{ +#ifdef CONFIG_PROC_FS + return mntflags; +#else + return mntflags & ~AuOpt_PLINK; +#endif +} + +/* ---------------------------------------------------------------------- */ + +/* policies to select one among multiple writable branches */ +enum { + AuWbrCreate_TDP, /* top down parent */ + AuWbrCreate_RR, /* round robin */ + AuWbrCreate_MFS, /* most free space */ + AuWbrCreate_MFSV, /* mfs with seconds */ + AuWbrCreate_MFSRR, /* mfs then rr */ + AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ + AuWbrCreate_PMFS, /* parent and mfs */ + AuWbrCreate_PMFSV, /* parent and mfs with seconds */ + AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ + AuWbrCreate_PMFSRRV, /* plus seconds */ + + AuWbrCreate_Def = AuWbrCreate_TDP +}; + +enum { + AuWbrCopyup_TDP, /* top down parent */ + AuWbrCopyup_BUP, /* bottom up parent */ + AuWbrCopyup_BU, /* bottom up */ + + AuWbrCopyup_Def = AuWbrCopyup_TDP +}; + +/* ---------------------------------------------------------------------- */ + +struct au_opt_add { + aufs_bindex_t bindex; + char *pathname; + int perm; + struct path path; +}; + +struct au_opt_del { + char *pathname; + struct path h_path; +}; + +struct au_opt_mod { + char *path; + int perm; + struct dentry *h_root; +}; + +struct au_opt_xino { + char *path; + struct file *file; +}; + +struct au_opt_xino_itrunc { + aufs_bindex_t bindex; +}; + +struct au_opt_wbr_create { + int wbr_create; + int mfs_second; + unsigned long long mfsrr_watermark; +}; + +struct au_opt { + int type; + union { + struct au_opt_xino xino; + struct au_opt_xino_itrunc xino_itrunc; + struct au_opt_add add; + struct au_opt_del del; + struct au_opt_mod mod; + int dirwh; + int rdcache; + unsigned int rdblk; + unsigned int rdhash; + int udba; + struct au_opt_wbr_create wbr_create; + int wbr_copyup; + }; +}; + +/* opts flags */ +#define AuOpts_REMOUNT 1 +#define AuOpts_REFRESH (1 << 1) +#define AuOpts_TRUNC_XIB (1 << 2) +#define AuOpts_REFRESH_DYAOP (1 << 3) +#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) +#define au_fset_opts(flags, name) \ + do { (flags) |= AuOpts_##name; } while (0) +#define au_fclr_opts(flags, name) \ + do { (flags) &= ~AuOpts_##name; } while (0) + +struct au_opts { + struct au_opt *opt; + int max_opt; + + unsigned int given_udba; + unsigned int flags; + unsigned long sb_flags; +}; + +/* ---------------------------------------------------------------------- */ + +char *au_optstr_br_perm(int brperm); +const char *au_optstr_udba(int udba); +const char *au_optstr_wbr_copyup(int wbr_copyup); +const char *au_optstr_wbr_create(int wbr_create); + +void au_opts_free(struct au_opts *opts); +int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); +int au_opts_verify(struct super_block *sb, unsigned long sb_flags, + unsigned int pending); +int au_opts_mount(struct super_block *sb, struct au_opts *opts); +int au_opts_remount(struct super_block *sb, struct au_opts *opts); + +unsigned int au_opt_udba(struct super_block *sb); + +/* ---------------------------------------------------------------------- */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_OPTS_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/sbinfo.c +++ linux-3.13.0/ubuntu/aufs/sbinfo.c @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * superblock private data + */ + +#include "aufs.h" + +/* + * they are necessary regardless sysfs is disabled. + */ +void au_si_free(struct kobject *kobj) +{ + int i; + struct au_sbinfo *sbinfo; + char *locked __maybe_unused; /* debug only */ + + sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); + for (i = 0; i < AuPlink_NHASH; i++) + AuDebugOn(!hlist_empty(&sbinfo->si_plink[i].head)); + AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); + + au_rw_write_lock(&sbinfo->si_rwsem); + au_br_free(sbinfo); + au_rw_write_unlock(&sbinfo->si_rwsem); + + AuDebugOn(radix_tree_gang_lookup + (&sbinfo->au_si_pid.tree, (void **)&locked, + /*first_index*/PID_MAX_DEFAULT - 1, + /*max_items*/sizeof(locked)/sizeof(*locked))); + + kfree(sbinfo->si_branch); + kfree(sbinfo->au_si_pid.bitmap); + mutex_destroy(&sbinfo->si_xib_mtx); + AuRwDestroy(&sbinfo->si_rwsem); + + kfree(sbinfo); +} + +int au_si_alloc(struct super_block *sb) +{ + int err, i; + struct au_sbinfo *sbinfo; + static struct lock_class_key aufs_si; + + err = -ENOMEM; + sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); + if (unlikely(!sbinfo)) + goto out; + + BUILD_BUG_ON(sizeof(unsigned long) != + sizeof(*sbinfo->au_si_pid.bitmap)); + sbinfo->au_si_pid.bitmap = kcalloc(BITS_TO_LONGS(PID_MAX_DEFAULT), + sizeof(*sbinfo->au_si_pid.bitmap), + GFP_NOFS); + if (unlikely(!sbinfo->au_si_pid.bitmap)) + goto out_sbinfo; + + /* will be reallocated separately */ + sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); + if (unlikely(!sbinfo->si_branch)) + goto out_pidmap; + + err = sysaufs_si_init(sbinfo); + if (unlikely(err)) + goto out_br; + + au_nwt_init(&sbinfo->si_nowait); + au_rw_init_wlock(&sbinfo->si_rwsem); + au_rw_class(&sbinfo->si_rwsem, &aufs_si); + spin_lock_init(&sbinfo->au_si_pid.tree_lock); + INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL); + + atomic_long_set(&sbinfo->si_ninodes, 0); + atomic_long_set(&sbinfo->si_nfiles, 0); + + sbinfo->si_bend = -1; + sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; + + sbinfo->si_wbr_copyup = AuWbrCopyup_Def; + sbinfo->si_wbr_create = AuWbrCreate_Def; + sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; + sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; + + sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); + + sbinfo->si_xino_jiffy = jiffies; + sbinfo->si_xino_expire + = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); + mutex_init(&sbinfo->si_xib_mtx); + sbinfo->si_xino_brid = -1; + /* leave si_xib_last_pindex and si_xib_next_bit */ + + sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); + sbinfo->si_rdblk = AUFS_RDBLK_DEF; + sbinfo->si_rdhash = AUFS_RDHASH_DEF; + sbinfo->si_dirwh = AUFS_DIRWH_DEF; + + for (i = 0; i < AuPlink_NHASH; i++) + au_sphl_init(sbinfo->si_plink + i); + init_waitqueue_head(&sbinfo->si_plink_wq); + spin_lock_init(&sbinfo->si_plink_maint_lock); + + au_sphl_init(&sbinfo->si_files); + + /* leave other members for sysaufs and si_mnt. */ + sbinfo->si_sb = sb; + sb->s_fs_info = sbinfo; + si_pid_set(sb); + au_debug_sbinfo_init(sbinfo); + return 0; /* success */ + +out_br: + kfree(sbinfo->si_branch); +out_pidmap: + kfree(sbinfo->au_si_pid.bitmap); +out_sbinfo: + kfree(sbinfo); +out: + return err; +} + +int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr) +{ + int err, sz; + struct au_branch **brp; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + err = -ENOMEM; + sz = sizeof(*brp) * (sbinfo->si_bend + 1); + if (unlikely(!sz)) + sz = sizeof(*brp); + brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS); + if (brp) { + sbinfo->si_branch = brp; + err = 0; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +unsigned int au_sigen_inc(struct super_block *sb) +{ + unsigned int gen; + + SiMustWriteLock(sb); + + gen = ++au_sbi(sb)->si_generation; + au_update_digen(sb->s_root); + au_update_iigen(sb->s_root->d_inode, /*half*/0); + sb->s_root->d_inode->i_version++; + return gen; +} + +aufs_bindex_t au_new_br_id(struct super_block *sb) +{ + aufs_bindex_t br_id; + int i; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + for (i = 0; i <= AUFS_BRANCH_MAX; i++) { + br_id = ++sbinfo->si_last_br_id; + AuDebugOn(br_id < 0); + if (br_id && au_br_index(sb, br_id) < 0) + return br_id; + } + + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/* it is ok that new 'nwt' tasks are appended while we are sleeping */ +int si_read_lock(struct super_block *sb, int flags) +{ + int err; + + err = 0; + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + + si_noflush_read_lock(sb); + err = au_plink_maint(sb, flags); + if (unlikely(err)) + si_read_unlock(sb); + + return err; +} + +int si_write_lock(struct super_block *sb, int flags) +{ + int err; + + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + + si_noflush_write_lock(sb); + err = au_plink_maint(sb, flags); + if (unlikely(err)) + si_write_unlock(sb); + + return err; +} + +/* dentry and super_block lock. call at entry point */ +int aufs_read_lock(struct dentry *dentry, int flags) +{ + int err; + struct super_block *sb; + + sb = dentry->d_sb; + err = si_read_lock(sb, flags); + if (unlikely(err)) + goto out; + + if (au_ftest_lock(flags, DW)) + di_write_lock_child(dentry); + else + di_read_lock_child(dentry, flags); + + if (au_ftest_lock(flags, GEN)) { + err = au_digen_test(dentry, au_sigen(sb)); + AuDebugOn(!err && au_dbrange_test(dentry)); + if (unlikely(err)) + aufs_read_unlock(dentry, flags); + } + +out: + return err; +} + +void aufs_read_unlock(struct dentry *dentry, int flags) +{ + if (au_ftest_lock(flags, DW)) + di_write_unlock(dentry); + else + di_read_unlock(dentry, flags); + si_read_unlock(dentry->d_sb); +} + +void aufs_write_lock(struct dentry *dentry) +{ + si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); + di_write_lock_child(dentry); +} + +void aufs_write_unlock(struct dentry *dentry) +{ + di_write_unlock(dentry); + si_write_unlock(dentry->d_sb); +} + +int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) +{ + int err; + unsigned int sigen; + struct super_block *sb; + + sb = d1->d_sb; + err = si_read_lock(sb, flags); + if (unlikely(err)) + goto out; + + di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR)); + + if (au_ftest_lock(flags, GEN)) { + sigen = au_sigen(sb); + err = au_digen_test(d1, sigen); + AuDebugOn(!err && au_dbrange_test(d1)); + if (!err) { + err = au_digen_test(d2, sigen); + AuDebugOn(!err && au_dbrange_test(d2)); + } + if (unlikely(err)) + aufs_read_and_write_unlock2(d1, d2); + } + +out: + return err; +} + +void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) +{ + di_write_unlock2(d1, d2); + si_read_unlock(d1->d_sb); +} + +/* ---------------------------------------------------------------------- */ + +int si_pid_test_slow(struct super_block *sb) +{ + void *p; + + rcu_read_lock(); + p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid); + rcu_read_unlock(); + + return (long)!!p; +} + +void si_pid_set_slow(struct super_block *sb) +{ + int err; + struct au_sbinfo *sbinfo; + + AuDebugOn(si_pid_test_slow(sb)); + + sbinfo = au_sbi(sb); + err = radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); + AuDebugOn(err); + spin_lock(&sbinfo->au_si_pid.tree_lock); + err = radix_tree_insert(&sbinfo->au_si_pid.tree, current->pid, + /*any valid ptr*/sb); + spin_unlock(&sbinfo->au_si_pid.tree_lock); + AuDebugOn(err); + radix_tree_preload_end(); +} + +void si_pid_clr_slow(struct super_block *sb) +{ + void *p; + struct au_sbinfo *sbinfo; + + AuDebugOn(!si_pid_test_slow(sb)); + + sbinfo = au_sbi(sb); + spin_lock(&sbinfo->au_si_pid.tree_lock); + p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid); + spin_unlock(&sbinfo->au_si_pid.tree_lock); +} --- linux-3.13.0.orig/ubuntu/aufs/dcsub.h +++ linux-3.13.0/ubuntu/aufs/dcsub.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for dentry cache + */ + +#ifndef __AUFS_DCSUB_H__ +#define __AUFS_DCSUB_H__ + +#ifdef __KERNEL__ + +#include +#include + +struct dentry; + +struct au_dpage { + int ndentry; + struct dentry **dentries; +}; + +struct au_dcsub_pages { + int ndpage; + struct au_dpage *dpages; +}; + +/* ---------------------------------------------------------------------- */ + +/* dcsub.c */ +int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); +void au_dpages_free(struct au_dcsub_pages *dpages); +typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); +int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, + au_dpages_test test, void *arg); +int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, + int do_include, au_dpages_test test, void *arg); +int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, + struct dentry *dentry, int do_include); +int au_test_subdir(struct dentry *d1, struct dentry *d2); + +/* ---------------------------------------------------------------------- */ + +/* + * todo: in linux-3.13, several similar (but faster) helpers are added to + * include/linux/dcache.h. Try them (in the future). + */ + +static inline int au_d_hashed_positive(struct dentry *d) +{ + int err; + struct inode *inode = d->d_inode; + err = 0; + if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink)) + err = -ENOENT; + return err; +} + +static inline int au_d_alive(struct dentry *d) +{ + int err; + struct inode *inode; + err = 0; + if (!IS_ROOT(d)) + err = au_d_hashed_positive(d); + else { + inode = d->d_inode; + if (unlikely(d_unlinked(d) || !inode || !inode->i_nlink)) + err = -ENOENT; + } + return err; +} + +static inline int au_alive_dir(struct dentry *d) +{ + int err; + err = au_d_alive(d); + if (unlikely(err || IS_DEADDIR(d->d_inode))) + err = -ENOENT; + return err; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DCSUB_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/wkq.c +++ linux-3.13.0/ubuntu/aufs/wkq.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * workqueue for asynchronous/super-io operations + * todo: try new dredential scheme + */ + +#include +#include "aufs.h" + +/* internal workqueue named AUFS_WKQ_NAME */ + +static struct workqueue_struct *au_wkq; + +struct au_wkinfo { + struct work_struct wk; + struct kobject *kobj; + + unsigned int flags; /* see wkq.h */ + + au_wkq_func_t func; + void *args; + + struct completion *comp; +}; + +/* ---------------------------------------------------------------------- */ + +static void wkq_func(struct work_struct *wk) +{ + struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); + + AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); + AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); + + wkinfo->func(wkinfo->args); + if (au_ftest_wkq(wkinfo->flags, WAIT)) + complete(wkinfo->comp); + else { + kobject_put(wkinfo->kobj); + module_put(THIS_MODULE); /* todo: ?? */ + kfree(wkinfo); + } +} + +/* + * Since struct completion is large, try allocating it dynamically. + */ +#if 1 /* defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) */ +#define AuWkqCompDeclare(name) struct completion *comp = NULL + +static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) +{ + *comp = kmalloc(sizeof(**comp), GFP_NOFS); + if (*comp) { + init_completion(*comp); + wkinfo->comp = *comp; + return 0; + } + return -ENOMEM; +} + +static void au_wkq_comp_free(struct completion *comp) +{ + kfree(comp); +} + +#else + +/* no braces */ +#define AuWkqCompDeclare(name) \ + DECLARE_COMPLETION_ONSTACK(_ ## name); \ + struct completion *comp = &_ ## name + +static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) +{ + wkinfo->comp = *comp; + return 0; +} + +static void au_wkq_comp_free(struct completion *comp __maybe_unused) +{ + /* empty */ +} +#endif /* 4KSTACKS */ + +static void au_wkq_run(struct au_wkinfo *wkinfo) +{ + if (au_ftest_wkq(wkinfo->flags, NEST)) { + if (au_wkq_test()) { + AuWarn1("wkq from wkq, due to a dead dir by UDBA?\n"); + AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); + } + } else + au_dbg_verify_kthread(); + + if (au_ftest_wkq(wkinfo->flags, WAIT)) { + INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); + queue_work(au_wkq, &wkinfo->wk); + } else { + INIT_WORK(&wkinfo->wk, wkq_func); + schedule_work(&wkinfo->wk); + } +} + +/* + * Be careful. It is easy to make deadlock happen. + * processA: lock, wkq and wait + * processB: wkq and wait, lock in wkq + * --> deadlock + */ +int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) +{ + int err; + AuWkqCompDeclare(comp); + struct au_wkinfo wkinfo = { + .flags = flags, + .func = func, + .args = args + }; + + err = au_wkq_comp_alloc(&wkinfo, &comp); + if (!err) { + au_wkq_run(&wkinfo); + /* no timeout, no interrupt */ + wait_for_completion(wkinfo.comp); + au_wkq_comp_free(comp); + destroy_work_on_stack(&wkinfo.wk); + } + + return err; + +} + +/* + * Note: dget/dput() in func for aufs dentries are not supported. It will be a + * problem in a concurrent umounting. + */ +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, + unsigned int flags) +{ + int err; + struct au_wkinfo *wkinfo; + + atomic_inc(&au_sbi(sb)->si_nowait.nw_len); + + /* + * wkq_func() must free this wkinfo. + * it highly depends upon the implementation of workqueue. + */ + err = 0; + wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); + if (wkinfo) { + wkinfo->kobj = &au_sbi(sb)->si_kobj; + wkinfo->flags = flags & ~AuWkq_WAIT; + wkinfo->func = func; + wkinfo->args = args; + wkinfo->comp = NULL; + kobject_get(wkinfo->kobj); + __module_get(THIS_MODULE); /* todo: ?? */ + + au_wkq_run(wkinfo); + } else { + err = -ENOMEM; + au_nwt_done(&au_sbi(sb)->si_nowait); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_nwt_init(struct au_nowait_tasks *nwt) +{ + atomic_set(&nwt->nw_len, 0); + /* smp_mb(); */ /* atomic_set */ + init_waitqueue_head(&nwt->nw_wq); +} + +void au_wkq_fin(void) +{ + destroy_workqueue(au_wkq); +} + +int __init au_wkq_init(void) +{ + int err; + + err = 0; + au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); + if (IS_ERR(au_wkq)) + err = PTR_ERR(au_wkq); + else if (!au_wkq) + err = -ENOMEM; + + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/i_op_add.c +++ linux-3.13.0/ubuntu/aufs/i_op_add.c @@ -0,0 +1,762 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations (add entry) + */ + +#include "aufs.h" + +/* + * final procedure of adding a new entry, except link(2). + * remove whiteout, instantiate, copyup the parent dir's times and size + * and update version. + * if it failed, re-create the removed whiteout. + */ +static int epilog(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct dentry *dentry) +{ + int err, rerr; + aufs_bindex_t bwh; + struct path h_path; + struct inode *inode, *h_dir; + struct dentry *wh; + + bwh = -1; + if (wh_dentry) { + h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ + IMustLock(h_dir); + AuDebugOn(au_h_iptr(dir, bindex) != h_dir); + bwh = au_dbwh(dentry); + h_path.dentry = wh_dentry; + h_path.mnt = au_sbr_mnt(dir->i_sb, bindex); + err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, + dentry); + if (unlikely(err)) + goto out; + } + + inode = au_new_inode(dentry, /*must_new*/1); + if (!IS_ERR(inode)) { + d_instantiate(dentry, inode); + dir = dentry->d_parent->d_inode; /* dir inode is locked */ + IMustLock(dir); + if (au_ibstart(dir) == au_dbstart(dentry)) + au_cpup_attr_timesizes(dir); + dir->i_version++; + return 0; /* success */ + } + + err = PTR_ERR(inode); + if (!wh_dentry) + goto out; + + /* revert */ + /* dir inode is locked */ + wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); + rerr = PTR_ERR(wh); + if (IS_ERR(wh)) { + AuIOErr("%pd reverting whiteout failed(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } else + dput(wh); + +out: + return err; +} + +static int au_d_may_add(struct dentry *dentry) +{ + int err; + + err = 0; + if (unlikely(d_unhashed(dentry))) + err = -ENOENT; + if (unlikely(dentry->d_inode)) + err = -EEXIST; + return err; +} + +/* + * simple tests for the adding inode operations. + * following the checks in vfs, plus the parent-child relationship. + */ +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir) +{ + int err; + umode_t h_mode; + struct dentry *h_dentry; + struct inode *h_inode; + + err = -ENAMETOOLONG; + if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) + goto out; + + h_dentry = au_h_dptr(dentry, bindex); + h_inode = h_dentry->d_inode; + if (!dentry->d_inode) { + err = -EEXIST; + if (unlikely(h_inode)) + goto out; + } else { + /* rename(2) case */ + err = -EIO; + if (unlikely(!h_inode || !h_inode->i_nlink)) + goto out; + + h_mode = h_inode->i_mode; + if (!isdir) { + err = -EISDIR; + if (unlikely(S_ISDIR(h_mode))) + goto out; + } else if (unlikely(!S_ISDIR(h_mode))) { + err = -ENOTDIR; + goto out; + } + } + + err = 0; + /* expected parent dir is locked */ + if (unlikely(h_parent != h_dentry->d_parent)) + err = -EIO; + +out: + AuTraceErr(err); + return err; +} + +/* + * initial procedure of adding a new entry. + * prepare writable branch and the parent dir, lock it, + * and lookup whiteout for the new entry. + */ +static struct dentry* +lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, + struct dentry *src_dentry, struct au_pin *pin, + struct au_wr_dir_args *wr_dir_args) +{ + struct dentry *wh_dentry, *h_parent; + struct super_block *sb; + struct au_branch *br; + int err; + unsigned int udba; + aufs_bindex_t bcpup; + + AuDbg("%pd\n", dentry); + + err = au_wr_dir(dentry, src_dentry, wr_dir_args); + bcpup = err; + wh_dentry = ERR_PTR(err); + if (unlikely(err < 0)) + goto out; + + sb = dentry->d_sb; + udba = au_opt_udba(sb); + err = au_pin(pin, dentry, bcpup, udba, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out; + + h_parent = au_pinned_h_parent(pin); + if (udba != AuOpt_UDBA_NONE + && au_dbstart(dentry) == bcpup) + err = au_may_add(dentry, bcpup, h_parent, + au_ftest_wrdir(wr_dir_args->flags, ISDIR)); + else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) + err = -ENAMETOOLONG; + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_unpin; + + br = au_sbr(sb, bcpup); + if (dt) { + struct path tmp = { + .dentry = h_parent, + .mnt = au_br_mnt(br) + }; + au_dtime_store(dt, au_pinned_parent(pin), &tmp); + } + + wh_dentry = NULL; + if (bcpup != au_dbwh(dentry)) + goto out; /* success */ + + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); + +out_unpin: + if (IS_ERR(wh_dentry)) + au_unpin(pin); +out: + return wh_dentry; +} + +/* ---------------------------------------------------------------------- */ + +enum { Mknod, Symlink, Creat }; +struct simple_arg { + int type; + union { + struct { + umode_t mode; + bool want_excl; + } c; + struct { + const char *symname; + } s; + struct { + umode_t mode; + dev_t dev; + } m; + } u; +}; + +static int add_simple(struct inode *dir, struct dentry *dentry, + struct simple_arg *arg) +{ + int err; + aufs_bindex_t bstart; + unsigned char created; + struct dentry *wh_dentry, *parent; + struct inode *h_dir; + /* to reuduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; + struct path h_path; + struct au_wr_dir_args wr_dir_args; + } *a; + + AuDbg("%pd\n", dentry); + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + a->wr_dir_args.force_btgt = -1; + a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; + + parent = dentry->d_parent; /* dir inode is locked */ + err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); + if (unlikely(err)) + goto out_free; + err = au_d_may_add(dentry); + if (unlikely(err)) + goto out_unlock; + di_write_lock_parent(parent); + wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, + &a->pin, &a->wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + bstart = au_dbstart(dentry); + a->h_path.dentry = au_h_dptr(dentry, bstart); + a->h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); + h_dir = au_pinned_h_dir(&a->pin); + switch (arg->type) { + case Creat: + err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, + arg->u.c.want_excl); + break; + case Symlink: + err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); + break; + case Mknod: + err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, + arg->u.m.dev); + break; + default: + BUG(); + } + created = !err; + if (!err) + err = epilog(dir, bstart, wh_dentry, dentry); + + /* revert */ + if (unlikely(created && err && a->h_path.dentry->d_inode)) { + int rerr; + /* no delegation since it is just created */ + rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, + /*force*/0); + if (rerr) { + AuIOErr("%pd revert failure(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } + au_dtime_revert(&a->dt); + } + + au_unpin(&a->pin); + dput(wh_dentry); + +out_parent: + di_write_unlock(parent); +out_unlock: + if (unlikely(err)) { + au_update_dbstart(dentry); + d_drop(dentry); + } + aufs_read_unlock(dentry, AuLock_DW); +out_free: + kfree(a); +out: + return err; +} + +int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + dev_t dev) +{ + struct simple_arg arg = { + .type = Mknod, + .u.m = { + .mode = mode, + .dev = dev + } + }; + return add_simple(dir, dentry, &arg); +} + +int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + struct simple_arg arg = { + .type = Symlink, + .u.s.symname = symname + }; + return add_simple(dir, dentry, &arg); +} + +int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool want_excl) +{ + struct simple_arg arg = { + .type = Creat, + .u.c = { + .mode = mode, + .want_excl = want_excl + } + }; + return add_simple(dir, dentry, &arg); +} + +/* ---------------------------------------------------------------------- */ + +struct au_link_args { + aufs_bindex_t bdst, bsrc; + struct au_pin pin; + struct path h_path; + struct dentry *src_parent, *parent; +}; + +static int au_cpup_before_link(struct dentry *src_dentry, + struct au_link_args *a) +{ + int err; + struct dentry *h_src_dentry; + struct au_cp_generic cpg = { + .dentry = src_dentry, + .bdst = a->bdst, + .bsrc = a->bsrc, + .len = -1, + .pin = &a->pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ + }; + + di_read_lock_parent(a->src_parent, AuLock_IR); + err = au_test_and_cpup_dirs(src_dentry, a->bdst); + if (unlikely(err)) + goto out; + + h_src_dentry = au_h_dptr(src_dentry, a->bsrc); + err = au_pin(&a->pin, src_dentry, a->bdst, + au_opt_udba(src_dentry->d_sb), + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out; + + err = au_sio_cpup_simple(&cpg); + au_unpin(&a->pin); + +out: + di_read_unlock(a->src_parent, AuLock_IR); + return err; +} + +static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, + struct au_link_args *a) +{ + int err; + unsigned char plink; + aufs_bindex_t bend; + struct dentry *h_src_dentry; + struct inode *h_inode, *inode, *delegated; + struct super_block *sb; + struct file *h_file; + + plink = 0; + h_inode = NULL; + sb = src_dentry->d_sb; + inode = src_dentry->d_inode; + if (au_ibstart(inode) <= a->bdst) + h_inode = au_h_iptr(inode, a->bdst); + if (!h_inode || !h_inode->i_nlink) { + /* copyup src_dentry as the name of dentry. */ + bend = au_dbend(dentry); + if (bend < a->bsrc) + au_set_dbend(dentry, a->bsrc); + au_set_h_dptr(dentry, a->bsrc, + dget(au_h_dptr(src_dentry, a->bsrc))); + dget(a->h_path.dentry); + au_set_h_dptr(dentry, a->bdst, NULL); + dentry->d_inode = src_dentry->d_inode; /* tmp */ + h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); + if (IS_ERR(h_file)) + err = PTR_ERR(h_file); + else { + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = a->bdst, + .bsrc = -1, + .len = -1, + .pin = &a->pin, + .flags = AuCpup_KEEPLINO + }; + err = au_sio_cpup_simple(&cpg); + au_h_open_post(dentry, a->bsrc, h_file); + if (!err) { + dput(a->h_path.dentry); + a->h_path.dentry = au_h_dptr(dentry, a->bdst); + } else + au_set_h_dptr(dentry, a->bdst, + a->h_path.dentry); + } + dentry->d_inode = NULL; /* restore */ + au_set_h_dptr(dentry, a->bsrc, NULL); + au_set_dbend(dentry, bend); + } else { + /* the inode of src_dentry already exists on a.bdst branch */ + h_src_dentry = d_find_alias(h_inode); + if (!h_src_dentry && au_plink_test(inode)) { + plink = 1; + h_src_dentry = au_plink_lkup(inode, a->bdst); + err = PTR_ERR(h_src_dentry); + if (IS_ERR(h_src_dentry)) + goto out; + + if (unlikely(!h_src_dentry->d_inode)) { + dput(h_src_dentry); + h_src_dentry = NULL; + } + + } + if (h_src_dentry) { + delegated = NULL; + err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), + &a->h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + dput(h_src_dentry); + } else { + AuIOErr("no dentry found for hi%lu on b%d\n", + h_inode->i_ino, a->bdst); + err = -EIO; + } + } + + if (!err && !plink) + au_plink_append(inode, a->bdst, a->h_path.dentry); + +out: + AuTraceErr(err); + return err; +} + +int aufs_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry) +{ + int err, rerr; + struct au_dtime dt; + struct au_link_args *a; + struct dentry *wh_dentry, *h_src_dentry; + struct inode *inode, *delegated; + struct super_block *sb; + struct au_wr_dir_args wr_dir_args = { + /* .force_btgt = -1, */ + .flags = AuWrDir_ADD_ENTRY + }; + + IMustLock(dir); + inode = src_dentry->d_inode; + IMustLock(inode); + + err = -ENOMEM; + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + a->parent = dentry->d_parent; /* dir inode is locked */ + err = aufs_read_and_write_lock2(dentry, src_dentry, + AuLock_NOPLM | AuLock_GEN); + if (unlikely(err)) + goto out_kfree; + err = au_d_hashed_positive(src_dentry); + if (unlikely(err)) + goto out_unlock; + err = au_d_may_add(dentry); + if (unlikely(err)) + goto out_unlock; + + a->src_parent = dget_parent(src_dentry); + wr_dir_args.force_btgt = au_ibstart(inode); + + di_write_lock_parent(a->parent); + wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); + wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, + &wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + err = 0; + sb = dentry->d_sb; + a->bdst = au_dbstart(dentry); + a->h_path.dentry = au_h_dptr(dentry, a->bdst); + a->h_path.mnt = au_sbr_mnt(sb, a->bdst); + a->bsrc = au_ibstart(inode); + h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); + if (!h_src_dentry) { + a->bsrc = au_dbstart(src_dentry); + h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); + AuDebugOn(!h_src_dentry); + } else if (IS_ERR(h_src_dentry)) + goto out_parent; + + if (au_opt_test(au_mntflags(sb), PLINK)) { + if (a->bdst < a->bsrc + /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) + err = au_cpup_or_link(src_dentry, dentry, a); + else { + delegated = NULL; + err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), + &a->h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + } + dput(h_src_dentry); + } else { + /* + * copyup src_dentry to the branch we process, + * and then link(2) to it. + */ + dput(h_src_dentry); + if (a->bdst < a->bsrc + /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { + au_unpin(&a->pin); + di_write_unlock(a->parent); + err = au_cpup_before_link(src_dentry, a); + di_write_lock_parent(a->parent); + if (!err) + err = au_pin(&a->pin, dentry, a->bdst, + au_opt_udba(sb), + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out_wh; + } + if (!err) { + h_src_dentry = au_h_dptr(src_dentry, a->bdst); + err = -ENOENT; + if (h_src_dentry && h_src_dentry->d_inode) { + delegated = NULL; + err = vfsub_link(h_src_dentry, + au_pinned_h_dir(&a->pin), + &a->h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry" + " for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + } + } + } + if (unlikely(err)) + goto out_unpin; + + if (wh_dentry) { + a->h_path.dentry = wh_dentry; + err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, + dentry); + if (unlikely(err)) + goto out_revert; + } + + dir->i_version++; + if (au_ibstart(dir) == au_dbstart(dentry)) + au_cpup_attr_timesizes(dir); + inc_nlink(inode); + inode->i_ctime = dir->i_ctime; + d_instantiate(dentry, au_igrab(inode)); + if (d_unhashed(a->h_path.dentry)) + /* some filesystem calls d_drop() */ + d_drop(dentry); + goto out_unpin; /* success */ + +out_revert: + /* no delegation since it is just created */ + rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, + /*delegated*/NULL, /*force*/0); + if (unlikely(rerr)) { + AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); + err = -EIO; + } + au_dtime_revert(&dt); +out_unpin: + au_unpin(&a->pin); +out_wh: + dput(wh_dentry); +out_parent: + di_write_unlock(a->parent); + dput(a->src_parent); +out_unlock: + if (unlikely(err)) { + au_update_dbstart(dentry); + d_drop(dentry); + } + aufs_read_and_write_unlock2(dentry, src_dentry); +out_kfree: + kfree(a); +out: + AuTraceErr(err); + return err; +} + +int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + int err, rerr; + aufs_bindex_t bindex; + unsigned char diropq; + struct path h_path; + struct dentry *wh_dentry, *parent, *opq_dentry; + struct mutex *h_mtx; + struct super_block *sb; + struct { + struct au_pin pin; + struct au_dtime dt; + } *a; /* reduce the stack usage */ + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR + }; + + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); + if (unlikely(err)) + goto out_free; + err = au_d_may_add(dentry); + if (unlikely(err)) + goto out_unlock; + + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, + &a->pin, &wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + sb = dentry->d_sb; + bindex = au_dbstart(dentry); + h_path.dentry = au_h_dptr(dentry, bindex); + h_path.mnt = au_sbr_mnt(sb, bindex); + err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); + if (unlikely(err)) + goto out_unpin; + + /* make the dir opaque */ + diropq = 0; + h_mtx = &h_path.dentry->d_inode->i_mutex; + if (wh_dentry + || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + opq_dentry = au_diropq_create(dentry, bindex); + mutex_unlock(h_mtx); + err = PTR_ERR(opq_dentry); + if (IS_ERR(opq_dentry)) + goto out_dir; + dput(opq_dentry); + diropq = 1; + } + + err = epilog(dir, bindex, wh_dentry, dentry); + if (!err) { + inc_nlink(dir); + goto out_unpin; /* success */ + } + + /* revert */ + if (diropq) { + AuLabel(revert opq); + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + rerr = au_diropq_remove(dentry, bindex); + mutex_unlock(h_mtx); + if (rerr) { + AuIOErr("%pd reverting diropq failed(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } + } + +out_dir: + AuLabel(revert dir); + rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); + if (rerr) { + AuIOErr("%pd reverting dir failed(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } + au_dtime_revert(&a->dt); +out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); +out_parent: + di_write_unlock(parent); +out_unlock: + if (unlikely(err)) { + au_update_dbstart(dentry); + d_drop(dentry); + } + aufs_read_unlock(dentry, AuLock_DW); +out_free: + kfree(a); +out: + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/vdir.c +++ linux-3.13.0/ubuntu/aufs/vdir.c @@ -0,0 +1,887 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * virtual or vertical directory + */ + +#include "aufs.h" + +static unsigned int calc_size(int nlen) +{ + return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); +} + +static int set_deblk_end(union au_vdir_deblk_p *p, + union au_vdir_deblk_p *deblk_end) +{ + if (calc_size(0) <= deblk_end->deblk - p->deblk) { + p->de->de_str.len = 0; + /* smp_mb(); */ + return 0; + } + return -1; /* error */ +} + +/* returns true or false */ +static int is_deblk_end(union au_vdir_deblk_p *p, + union au_vdir_deblk_p *deblk_end) +{ + if (calc_size(0) <= deblk_end->deblk - p->deblk) + return !p->de->de_str.len; + return 1; +} + +static unsigned char *last_deblk(struct au_vdir *vdir) +{ + return vdir->vd_deblk[vdir->vd_nblk - 1]; +} + +/* ---------------------------------------------------------------------- */ + +/* estimate the apropriate size for name hash table */ +unsigned int au_rdhash_est(loff_t sz) +{ + unsigned int n; + + n = UINT_MAX; + sz >>= 10; + if (sz < n) + n = sz; + if (sz < AUFS_RDHASH_DEF) + n = AUFS_RDHASH_DEF; + /* pr_info("n %u\n", n); */ + return n; +} + +/* + * the allocated memory has to be freed by + * au_nhash_wh_free() or au_nhash_de_free(). + */ +int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) +{ + struct hlist_head *head; + unsigned int u; + + head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp); + if (head) { + nhash->nh_num = num_hash; + nhash->nh_head = head; + for (u = 0; u < num_hash; u++) + INIT_HLIST_HEAD(head++); + return 0; /* success */ + } + + return -ENOMEM; +} + +static void nhash_count(struct hlist_head *head) +{ +#if 0 + unsigned long n; + struct hlist_node *pos; + + n = 0; + hlist_for_each(pos, head) + n++; + pr_info("%lu\n", n); +#endif +} + +static void au_nhash_wh_do_free(struct hlist_head *head) +{ + struct au_vdir_wh *pos; + struct hlist_node *node; + + hlist_for_each_entry_safe(pos, node, head, wh_hash) + kfree(pos); +} + +static void au_nhash_de_do_free(struct hlist_head *head) +{ + struct au_vdir_dehstr *pos; + struct hlist_node *node; + + hlist_for_each_entry_safe(pos, node, head, hash) + au_cache_free_vdir_dehstr(pos); +} + +static void au_nhash_do_free(struct au_nhash *nhash, + void (*free)(struct hlist_head *head)) +{ + unsigned int n; + struct hlist_head *head; + + n = nhash->nh_num; + if (!n) + return; + + head = nhash->nh_head; + while (n-- > 0) { + nhash_count(head); + free(head++); + } + kfree(nhash->nh_head); +} + +void au_nhash_wh_free(struct au_nhash *whlist) +{ + au_nhash_do_free(whlist, au_nhash_wh_do_free); +} + +static void au_nhash_de_free(struct au_nhash *delist) +{ + au_nhash_do_free(delist, au_nhash_de_do_free); +} + +/* ---------------------------------------------------------------------- */ + +int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, + int limit) +{ + int num; + unsigned int u, n; + struct hlist_head *head; + struct au_vdir_wh *pos; + + num = 0; + n = whlist->nh_num; + head = whlist->nh_head; + for (u = 0; u < n; u++, head++) + hlist_for_each_entry(pos, head, wh_hash) + if (pos->wh_bindex == btgt && ++num > limit) + return 1; + return 0; +} + +static struct hlist_head *au_name_hash(struct au_nhash *nhash, + unsigned char *name, + unsigned int len) +{ + unsigned int v; + /* const unsigned int magic_bit = 12; */ + + AuDebugOn(!nhash->nh_num || !nhash->nh_head); + + v = 0; + while (len--) + v += *name++; + /* v = hash_long(v, magic_bit); */ + v %= nhash->nh_num; + return nhash->nh_head + v; +} + +static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, + int nlen) +{ + return str->len == nlen && !memcmp(str->name, name, nlen); +} + +/* returns found or not */ +int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) +{ + struct hlist_head *head; + struct au_vdir_wh *pos; + struct au_vdir_destr *str; + + head = au_name_hash(whlist, name, nlen); + hlist_for_each_entry(pos, head, wh_hash) { + str = &pos->wh_str; + AuDbg("%.*s\n", str->len, str->name); + if (au_nhash_test_name(str, name, nlen)) + return 1; + } + return 0; +} + +/* returns found(true) or not */ +static int test_known(struct au_nhash *delist, char *name, int nlen) +{ + struct hlist_head *head; + struct au_vdir_dehstr *pos; + struct au_vdir_destr *str; + + head = au_name_hash(delist, name, nlen); + hlist_for_each_entry(pos, head, hash) { + str = pos->str; + AuDbg("%.*s\n", str->len, str->name); + if (au_nhash_test_name(str, name, nlen)) + return 1; + } + return 0; +} + +static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, + unsigned char d_type) +{ +#ifdef CONFIG_AUFS_SHWH + wh->wh_ino = ino; + wh->wh_type = d_type; +#endif +} + +/* ---------------------------------------------------------------------- */ + +int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, + unsigned int d_type, aufs_bindex_t bindex, + unsigned char shwh) +{ + int err; + struct au_vdir_destr *str; + struct au_vdir_wh *wh; + + AuDbg("%.*s\n", nlen, name); + AuDebugOn(!whlist->nh_num || !whlist->nh_head); + + err = -ENOMEM; + wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); + if (unlikely(!wh)) + goto out; + + err = 0; + wh->wh_bindex = bindex; + if (shwh) + au_shwh_init_wh(wh, ino, d_type); + str = &wh->wh_str; + str->len = nlen; + memcpy(str->name, name, nlen); + hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); + /* smp_mb(); */ + +out: + return err; +} + +static int append_deblk(struct au_vdir *vdir) +{ + int err; + unsigned long ul; + const unsigned int deblk_sz = vdir->vd_deblk_sz; + union au_vdir_deblk_p p, deblk_end; + unsigned char **o; + + err = -ENOMEM; + o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), + GFP_NOFS); + if (unlikely(!o)) + goto out; + + vdir->vd_deblk = o; + p.deblk = kmalloc(deblk_sz, GFP_NOFS); + if (p.deblk) { + ul = vdir->vd_nblk++; + vdir->vd_deblk[ul] = p.deblk; + vdir->vd_last.ul = ul; + vdir->vd_last.p.deblk = p.deblk; + deblk_end.deblk = p.deblk + deblk_sz; + err = set_deblk_end(&p, &deblk_end); + } + +out: + return err; +} + +static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, + unsigned int d_type, struct au_nhash *delist) +{ + int err; + unsigned int sz; + const unsigned int deblk_sz = vdir->vd_deblk_sz; + union au_vdir_deblk_p p, *room, deblk_end; + struct au_vdir_dehstr *dehstr; + + p.deblk = last_deblk(vdir); + deblk_end.deblk = p.deblk + deblk_sz; + room = &vdir->vd_last.p; + AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk + || !is_deblk_end(room, &deblk_end)); + + sz = calc_size(nlen); + if (unlikely(sz > deblk_end.deblk - room->deblk)) { + err = append_deblk(vdir); + if (unlikely(err)) + goto out; + + p.deblk = last_deblk(vdir); + deblk_end.deblk = p.deblk + deblk_sz; + /* smp_mb(); */ + AuDebugOn(room->deblk != p.deblk); + } + + err = -ENOMEM; + dehstr = au_cache_alloc_vdir_dehstr(); + if (unlikely(!dehstr)) + goto out; + + dehstr->str = &room->de->de_str; + hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); + room->de->de_ino = ino; + room->de->de_type = d_type; + room->de->de_str.len = nlen; + memcpy(room->de->de_str.name, name, nlen); + + err = 0; + room->deblk += sz; + if (unlikely(set_deblk_end(room, &deblk_end))) + err = append_deblk(vdir); + /* smp_mb(); */ + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_vdir_free(struct au_vdir *vdir) +{ + unsigned char **deblk; + + deblk = vdir->vd_deblk; + while (vdir->vd_nblk--) + kfree(*deblk++); + kfree(vdir->vd_deblk); + au_cache_free_vdir(vdir); +} + +static struct au_vdir *alloc_vdir(struct file *file) +{ + struct au_vdir *vdir; + struct super_block *sb; + int err; + + sb = file->f_dentry->d_sb; + SiMustAnyLock(sb); + + err = -ENOMEM; + vdir = au_cache_alloc_vdir(); + if (unlikely(!vdir)) + goto out; + + vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); + if (unlikely(!vdir->vd_deblk)) + goto out_free; + + vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; + if (!vdir->vd_deblk_sz) { + /* estimate the apropriate size for deblk */ + vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); + /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ + } + vdir->vd_nblk = 0; + vdir->vd_version = 0; + vdir->vd_jiffy = 0; + err = append_deblk(vdir); + if (!err) + return vdir; /* success */ + + kfree(vdir->vd_deblk); + +out_free: + au_cache_free_vdir(vdir); +out: + vdir = ERR_PTR(err); + return vdir; +} + +static int reinit_vdir(struct au_vdir *vdir) +{ + int err; + union au_vdir_deblk_p p, deblk_end; + + while (vdir->vd_nblk > 1) { + kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); + /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ + vdir->vd_nblk--; + } + p.deblk = vdir->vd_deblk[0]; + deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; + err = set_deblk_end(&p, &deblk_end); + /* keep vd_dblk_sz */ + vdir->vd_last.ul = 0; + vdir->vd_last.p.deblk = vdir->vd_deblk[0]; + vdir->vd_version = 0; + vdir->vd_jiffy = 0; + /* smp_mb(); */ + return err; +} + +/* ---------------------------------------------------------------------- */ + +#define AuFillVdir_CALLED 1 +#define AuFillVdir_WHABLE (1 << 1) +#define AuFillVdir_SHWH (1 << 2) +#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) +#define au_fset_fillvdir(flags, name) \ + do { (flags) |= AuFillVdir_##name; } while (0) +#define au_fclr_fillvdir(flags, name) \ + do { (flags) &= ~AuFillVdir_##name; } while (0) + +#ifndef CONFIG_AUFS_SHWH +#undef AuFillVdir_SHWH +#define AuFillVdir_SHWH 0 +#endif + +struct fillvdir_arg { + struct dir_context ctx; + struct file *file; + struct au_vdir *vdir; + struct au_nhash delist; + struct au_nhash whlist; + aufs_bindex_t bindex; + unsigned int flags; + int err; +}; + +static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, + loff_t offset __maybe_unused, u64 h_ino, + unsigned int d_type) +{ + struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); + char *name = (void *)__name; + struct super_block *sb; + ino_t ino; + const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); + + arg->err = 0; + sb = arg->file->f_dentry->d_sb; + au_fset_fillvdir(arg->flags, CALLED); + /* smp_mb(); */ + if (nlen <= AUFS_WH_PFX_LEN + || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + if (test_known(&arg->delist, name, nlen) + || au_nhash_test_known_wh(&arg->whlist, name, nlen)) + goto out; /* already exists or whiteouted */ + + sb = arg->file->f_dentry->d_sb; + arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); + if (!arg->err) { + if (unlikely(nlen > AUFS_MAX_NAMELEN)) + d_type = DT_UNKNOWN; + arg->err = append_de(arg->vdir, name, nlen, ino, + d_type, &arg->delist); + } + } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { + name += AUFS_WH_PFX_LEN; + nlen -= AUFS_WH_PFX_LEN; + if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) + goto out; /* already whiteouted */ + + if (shwh) + arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, + &ino); + if (!arg->err) { + if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) + d_type = DT_UNKNOWN; + arg->err = au_nhash_append_wh + (&arg->whlist, name, nlen, ino, d_type, + arg->bindex, shwh); + } + } + +out: + if (!arg->err) + arg->vdir->vd_jiffy = jiffies; + /* smp_mb(); */ + AuTraceErr(arg->err); + return arg->err; +} + +static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, + struct au_nhash *whlist, struct au_nhash *delist) +{ +#ifdef CONFIG_AUFS_SHWH + int err; + unsigned int nh, u; + struct hlist_head *head; + struct au_vdir_wh *pos; + struct hlist_node *n; + char *p, *o; + struct au_vdir_destr *destr; + + AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); + + err = -ENOMEM; + o = p = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!p)) + goto out; + + err = 0; + nh = whlist->nh_num; + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + p += AUFS_WH_PFX_LEN; + for (u = 0; u < nh; u++) { + head = whlist->nh_head + u; + hlist_for_each_entry_safe(pos, n, head, wh_hash) { + destr = &pos->wh_str; + memcpy(p, destr->name, destr->len); + err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, + pos->wh_ino, pos->wh_type, delist); + if (unlikely(err)) + break; + } + } + + free_page((unsigned long)o); + +out: + AuTraceErr(err); + return err; +#else + return 0; +#endif +} + +static int au_do_read_vdir(struct fillvdir_arg *arg) +{ + int err; + unsigned int rdhash; + loff_t offset; + aufs_bindex_t bend, bindex, bstart; + unsigned char shwh; + struct file *hf, *file; + struct super_block *sb; + + file = arg->file; + sb = file->f_dentry->d_sb; + SiMustAnyLock(sb); + + rdhash = au_sbi(sb)->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); + err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out_delist; + + err = 0; + arg->flags = 0; + shwh = 0; + if (au_opt_test(au_mntflags(sb), SHWH)) { + shwh = 1; + au_fset_fillvdir(arg->flags, SHWH); + } + bstart = au_fbstart(file); + bend = au_fbend_dir(file); + for (bindex = bstart; !err && bindex <= bend; bindex++) { + hf = au_hf_dir(file, bindex); + if (!hf) + continue; + + offset = vfsub_llseek(hf, 0, SEEK_SET); + err = offset; + if (unlikely(offset)) + break; + + arg->bindex = bindex; + au_fclr_fillvdir(arg->flags, WHABLE); + if (shwh + || (bindex != bend + && au_br_whable(au_sbr_perm(sb, bindex)))) + au_fset_fillvdir(arg->flags, WHABLE); + do { + arg->err = 0; + au_fclr_fillvdir(arg->flags, CALLED); + /* smp_mb(); */ + err = vfsub_iterate_dir(hf, &arg->ctx); + if (err >= 0) + err = arg->err; + } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); + + /* + * dir_relax() may be good for concurrency, but aufs should not + * use it since it will cause a lockdep problem. + */ + } + + if (!err && shwh) + err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); + + au_nhash_wh_free(&arg->whlist); + +out_delist: + au_nhash_de_free(&arg->delist); +out: + return err; +} + +static int read_vdir(struct file *file, int may_read) +{ + int err; + unsigned long expire; + unsigned char do_read; + struct fillvdir_arg arg = { + .ctx = { + .actor = au_diractor(fillvdir) + } + }; + struct inode *inode; + struct au_vdir *vdir, *allocated; + + err = 0; + inode = file_inode(file); + IMustLock(inode); + SiMustAnyLock(inode->i_sb); + + allocated = NULL; + do_read = 0; + expire = au_sbi(inode->i_sb)->si_rdcache; + vdir = au_ivdir(inode); + if (!vdir) { + do_read = 1; + vdir = alloc_vdir(file); + err = PTR_ERR(vdir); + if (IS_ERR(vdir)) + goto out; + err = 0; + allocated = vdir; + } else if (may_read + && (inode->i_version != vdir->vd_version + || time_after(jiffies, vdir->vd_jiffy + expire))) { + do_read = 1; + err = reinit_vdir(vdir); + if (unlikely(err)) + goto out; + } + + if (!do_read) + return 0; /* success */ + + arg.file = file; + arg.vdir = vdir; + err = au_do_read_vdir(&arg); + if (!err) { + /* file->f_pos = 0; */ /* todo: ctx->pos? */ + vdir->vd_version = inode->i_version; + vdir->vd_last.ul = 0; + vdir->vd_last.p.deblk = vdir->vd_deblk[0]; + if (allocated) + au_set_ivdir(inode, allocated); + } else if (allocated) + au_vdir_free(allocated); + +out: + return err; +} + +static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) +{ + int err, rerr; + unsigned long ul, n; + const unsigned int deblk_sz = src->vd_deblk_sz; + + AuDebugOn(tgt->vd_nblk != 1); + + err = -ENOMEM; + if (tgt->vd_nblk < src->vd_nblk) { + unsigned char **p; + + p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, + GFP_NOFS); + if (unlikely(!p)) + goto out; + tgt->vd_deblk = p; + } + + if (tgt->vd_deblk_sz != deblk_sz) { + unsigned char *p; + + tgt->vd_deblk_sz = deblk_sz; + p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS); + if (unlikely(!p)) + goto out; + tgt->vd_deblk[0] = p; + } + memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); + tgt->vd_version = src->vd_version; + tgt->vd_jiffy = src->vd_jiffy; + + n = src->vd_nblk; + for (ul = 1; ul < n; ul++) { + tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, + GFP_NOFS); + if (unlikely(!tgt->vd_deblk[ul])) + goto out; + tgt->vd_nblk++; + } + tgt->vd_nblk = n; + tgt->vd_last.ul = tgt->vd_last.ul; + tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; + tgt->vd_last.p.deblk += src->vd_last.p.deblk + - src->vd_deblk[src->vd_last.ul]; + /* smp_mb(); */ + return 0; /* success */ + +out: + rerr = reinit_vdir(tgt); + BUG_ON(rerr); + return err; +} + +int au_vdir_init(struct file *file) +{ + int err; + struct inode *inode; + struct au_vdir *vdir_cache, *allocated; + + /* test file->f_pos here instead of ctx->pos */ + err = read_vdir(file, !file->f_pos); + if (unlikely(err)) + goto out; + + allocated = NULL; + vdir_cache = au_fvdir_cache(file); + if (!vdir_cache) { + vdir_cache = alloc_vdir(file); + err = PTR_ERR(vdir_cache); + if (IS_ERR(vdir_cache)) + goto out; + allocated = vdir_cache; + } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { + /* test file->f_pos here instead of ctx->pos */ + err = reinit_vdir(vdir_cache); + if (unlikely(err)) + goto out; + } else + return 0; /* success */ + + inode = file_inode(file); + err = copy_vdir(vdir_cache, au_ivdir(inode)); + if (!err) { + file->f_version = inode->i_version; + if (allocated) + au_set_fvdir_cache(file, allocated); + } else if (allocated) + au_vdir_free(allocated); + +out: + return err; +} + +static loff_t calc_offset(struct au_vdir *vdir) +{ + loff_t offset; + union au_vdir_deblk_p p; + + p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; + offset = vdir->vd_last.p.deblk - p.deblk; + offset += vdir->vd_deblk_sz * vdir->vd_last.ul; + return offset; +} + +/* returns true or false */ +static int seek_vdir(struct file *file, struct dir_context *ctx) +{ + int valid; + unsigned int deblk_sz; + unsigned long ul, n; + loff_t offset; + union au_vdir_deblk_p p, deblk_end; + struct au_vdir *vdir_cache; + + valid = 1; + vdir_cache = au_fvdir_cache(file); + offset = calc_offset(vdir_cache); + AuDbg("offset %lld\n", offset); + if (ctx->pos == offset) + goto out; + + vdir_cache->vd_last.ul = 0; + vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; + if (!ctx->pos) + goto out; + + valid = 0; + deblk_sz = vdir_cache->vd_deblk_sz; + ul = div64_u64(ctx->pos, deblk_sz); + AuDbg("ul %lu\n", ul); + if (ul >= vdir_cache->vd_nblk) + goto out; + + n = vdir_cache->vd_nblk; + for (; ul < n; ul++) { + p.deblk = vdir_cache->vd_deblk[ul]; + deblk_end.deblk = p.deblk + deblk_sz; + offset = ul; + offset *= deblk_sz; + while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { + unsigned int l; + + l = calc_size(p.de->de_str.len); + offset += l; + p.deblk += l; + } + if (!is_deblk_end(&p, &deblk_end)) { + valid = 1; + vdir_cache->vd_last.ul = ul; + vdir_cache->vd_last.p = p; + break; + } + } + +out: + /* smp_mb(); */ + AuTraceErr(!valid); + return valid; +} + +int au_vdir_fill_de(struct file *file, struct dir_context *ctx) +{ + unsigned int l, deblk_sz; + union au_vdir_deblk_p deblk_end; + struct au_vdir *vdir_cache; + struct au_vdir_de *de; + + vdir_cache = au_fvdir_cache(file); + if (!seek_vdir(file, ctx)) + return 0; + + deblk_sz = vdir_cache->vd_deblk_sz; + while (1) { + deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; + deblk_end.deblk += deblk_sz; + while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { + de = vdir_cache->vd_last.p.de; + AuDbg("%.*s, off%lld, i%lu, dt%d\n", + de->de_str.len, de->de_str.name, ctx->pos, + (unsigned long)de->de_ino, de->de_type); + if (unlikely(!dir_emit(ctx, de->de_str.name, + de->de_str.len, de->de_ino, + de->de_type))) { + /* todo: ignore the error caused by udba? */ + /* return err; */ + return 0; + } + + l = calc_size(de->de_str.len); + vdir_cache->vd_last.p.deblk += l; + ctx->pos += l; + } + if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { + vdir_cache->vd_last.ul++; + vdir_cache->vd_last.p.deblk + = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; + ctx->pos = deblk_sz * vdir_cache->vd_last.ul; + continue; + } + break; + } + + /* smp_mb(); */ + return 0; +} --- linux-3.13.0.orig/ubuntu/aufs/dentry.c +++ linux-3.13.0/ubuntu/aufs/dentry.c @@ -0,0 +1,1081 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * lookup and dentry operations + */ + +#include +#include "aufs.h" + +#define AuLkup_ALLOW_NEG 1 +#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) +#define au_fset_lkup(flags, name) \ + do { (flags) |= AuLkup_##name; } while (0) +#define au_fclr_lkup(flags, name) \ + do { (flags) &= ~AuLkup_##name; } while (0) + +struct au_do_lookup_args { + unsigned int flags; + mode_t type; +}; + +/* + * returns positive/negative dentry, NULL or an error. + * NULL means whiteout-ed or not-found. + */ +static struct dentry* +au_do_lookup(struct dentry *h_parent, struct dentry *dentry, + aufs_bindex_t bindex, struct qstr *wh_name, + struct au_do_lookup_args *args) +{ + struct dentry *h_dentry; + struct inode *h_inode, *inode; + struct au_branch *br; + int wh_found, opq; + unsigned char wh_able; + const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); + + wh_found = 0; + br = au_sbr(dentry->d_sb, bindex); + wh_able = !!au_br_whable(br->br_perm); + if (wh_able) + wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0); + h_dentry = ERR_PTR(wh_found); + if (!wh_found) + goto real_lookup; + if (unlikely(wh_found < 0)) + goto out; + + /* We found a whiteout */ + /* au_set_dbend(dentry, bindex); */ + au_set_dbwh(dentry, bindex); + if (!allow_neg) + return NULL; /* success */ + +real_lookup: + h_dentry = vfsub_lkup_one(&dentry->d_name, h_parent); + if (IS_ERR(h_dentry)) + goto out; + + h_inode = h_dentry->d_inode; + if (!h_inode) { + if (!allow_neg) + goto out_neg; + } else if (wh_found + || (args->type && args->type != (h_inode->i_mode & S_IFMT))) + goto out_neg; + + if (au_dbend(dentry) <= bindex) + au_set_dbend(dentry, bindex); + if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) + au_set_dbstart(dentry, bindex); + au_set_h_dptr(dentry, bindex, h_dentry); + + inode = dentry->d_inode; + if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able + || (inode && !S_ISDIR(inode->i_mode))) + goto out; /* success */ + + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + opq = au_diropq_test(h_dentry, br); + mutex_unlock(&h_inode->i_mutex); + if (opq > 0) + au_set_dbdiropq(dentry, bindex); + else if (unlikely(opq < 0)) { + au_set_h_dptr(dentry, bindex, NULL); + h_dentry = ERR_PTR(opq); + } + goto out; + +out_neg: + dput(h_dentry); + h_dentry = NULL; +out: + return h_dentry; +} + +static int au_test_shwh(struct super_block *sb, const struct qstr *name) +{ + if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) + && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) + return -EPERM; + return 0; +} + +/* + * returns the number of lower positive dentries, + * otherwise an error. + * can be called at unlinking with @type is zero. + */ +int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type) +{ + int npositive, err; + aufs_bindex_t bindex, btail, bdiropq; + unsigned char isdir; + struct qstr whname; + struct au_do_lookup_args args = { + .flags = 0, + .type = type + }; + const struct qstr *name = &dentry->d_name; + struct dentry *parent; + struct inode *inode; + + err = au_test_shwh(dentry->d_sb, name); + if (unlikely(err)) + goto out; + + err = au_wh_name_alloc(&whname, name); + if (unlikely(err)) + goto out; + + inode = dentry->d_inode; + isdir = !!(inode && S_ISDIR(inode->i_mode)); + if (!type) + au_fset_lkup(args.flags, ALLOW_NEG); + + npositive = 0; + parent = dget_parent(dentry); + btail = au_dbtaildir(parent); + for (bindex = bstart; bindex <= btail; bindex++) { + struct dentry *h_parent, *h_dentry; + struct inode *h_inode, *h_dir; + + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry) { + if (h_dentry->d_inode) + npositive++; + if (type != S_IFDIR) + break; + continue; + } + h_parent = au_h_dptr(parent, bindex); + if (!h_parent) + continue; + h_dir = h_parent->d_inode; + if (!h_dir || !S_ISDIR(h_dir->i_mode)) + continue; + + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname, + &args); + mutex_unlock(&h_dir->i_mutex); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out_parent; + au_fclr_lkup(args.flags, ALLOW_NEG); + + if (au_dbwh(dentry) >= 0) + break; + if (!h_dentry) + continue; + h_inode = h_dentry->d_inode; + if (!h_inode) + continue; + npositive++; + if (!args.type) + args.type = h_inode->i_mode & S_IFMT; + if (args.type != S_IFDIR) + break; + else if (isdir) { + /* the type of lower may be different */ + bdiropq = au_dbdiropq(dentry); + if (bdiropq >= 0 && bdiropq <= bindex) + break; + } + } + + if (npositive) { + AuLabel(positive); + au_update_dbstart(dentry); + } + err = npositive; + if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) + && au_dbstart(dentry) < 0)) { + err = -EIO; + AuIOErr("both of real entry and whiteout found, %pd, err %d\n", + dentry, err); + } + +out_parent: + dput(parent); + kfree(whname.name); +out: + return err; +} + +struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, + struct au_branch *br) +{ + struct dentry *dentry; + int wkq_err; + + if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC)) + dentry = vfsub_lkup_one(name, parent); + else { + struct vfsub_lkup_one_args args = { + .errp = &dentry, + .name = name, + .parent = parent + }; + + wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); + if (unlikely(wkq_err)) + dentry = ERR_PTR(wkq_err); + } + + return dentry; +} + +/* + * lookup @dentry on @bindex which should be negative. + */ +int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) +{ + int err; + struct dentry *parent, *h_parent, *h_dentry; + struct au_branch *br; + + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bindex); + br = au_sbr(dentry->d_sb, bindex); + if (wh) + h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); + else + h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent, br); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out; + if (unlikely(h_dentry->d_inode)) { + err = -EIO; + AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); + dput(h_dentry); + goto out; + } + + err = 0; + if (bindex < au_dbstart(dentry)) + au_set_dbstart(dentry, bindex); + if (au_dbend(dentry) < bindex) + au_set_dbend(dentry, bindex); + au_set_h_dptr(dentry, bindex, h_dentry); + +out: + dput(parent); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* subset of struct inode */ +struct au_iattr { + unsigned long i_ino; + /* unsigned int i_nlink; */ + kuid_t i_uid; + kgid_t i_gid; + u64 i_version; +/* + loff_t i_size; + blkcnt_t i_blocks; +*/ + umode_t i_mode; +}; + +static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) +{ + ia->i_ino = h_inode->i_ino; + /* ia->i_nlink = h_inode->i_nlink; */ + ia->i_uid = h_inode->i_uid; + ia->i_gid = h_inode->i_gid; + ia->i_version = h_inode->i_version; +/* + ia->i_size = h_inode->i_size; + ia->i_blocks = h_inode->i_blocks; +*/ + ia->i_mode = (h_inode->i_mode & S_IFMT); +} + +static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) +{ + return ia->i_ino != h_inode->i_ino + /* || ia->i_nlink != h_inode->i_nlink */ + || !uid_eq(ia->i_uid, h_inode->i_uid) + || !gid_eq(ia->i_gid, h_inode->i_gid) + || ia->i_version != h_inode->i_version +/* + || ia->i_size != h_inode->i_size + || ia->i_blocks != h_inode->i_blocks +*/ + || ia->i_mode != (h_inode->i_mode & S_IFMT); +} + +static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, + struct au_branch *br) +{ + int err; + struct au_iattr ia; + struct inode *h_inode; + struct dentry *h_d; + struct super_block *h_sb; + + err = 0; + memset(&ia, -1, sizeof(ia)); + h_sb = h_dentry->d_sb; + h_inode = h_dentry->d_inode; + if (h_inode) + au_iattr_save(&ia, h_inode); + else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) + /* nfs d_revalidate may return 0 for negative dentry */ + /* fuse d_revalidate always return 0 for negative dentry */ + goto out; + + /* main purpose is namei.c:cached_lookup() and d_revalidate */ + h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); + err = PTR_ERR(h_d); + if (IS_ERR(h_d)) + goto out; + + err = 0; + if (unlikely(h_d != h_dentry + || h_d->d_inode != h_inode + || (h_inode && au_iattr_test(&ia, h_inode)))) + err = au_busy_or_stale(); + dput(h_d); + +out: + AuTraceErr(err); + return err; +} + +int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, + struct dentry *h_parent, struct au_branch *br) +{ + int err; + + err = 0; + if (udba == AuOpt_UDBA_REVAL + && !au_test_fs_remote(h_dentry->d_sb)) { + IMustLock(h_dir); + err = (h_dentry->d_parent->d_inode != h_dir); + } else if (udba != AuOpt_UDBA_NONE) + err = au_h_verify_dentry(h_dentry, h_parent, br); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) +{ + int err; + aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq; + struct au_hdentry tmp, *p, *q; + struct au_dinfo *dinfo; + struct super_block *sb; + + DiMustWriteLock(dentry); + + sb = dentry->d_sb; + dinfo = au_di(dentry); + bend = dinfo->di_bend; + bwh = dinfo->di_bwh; + bdiropq = dinfo->di_bdiropq; + p = dinfo->di_hdentry + dinfo->di_bstart; + for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { + if (!p->hd_dentry) + continue; + + new_bindex = au_br_index(sb, p->hd_id); + if (new_bindex == bindex) + continue; + + if (dinfo->di_bwh == bindex) + bwh = new_bindex; + if (dinfo->di_bdiropq == bindex) + bdiropq = new_bindex; + if (new_bindex < 0) { + au_hdput(p); + p->hd_dentry = NULL; + continue; + } + + /* swap two lower dentries, and loop again */ + q = dinfo->di_hdentry + new_bindex; + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hd_dentry) { + bindex--; + p--; + } + } + + dinfo->di_bwh = -1; + if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh)) + dinfo->di_bwh = bwh; + + dinfo->di_bdiropq = -1; + if (bdiropq >= 0 + && bdiropq <= au_sbend(sb) + && au_sbr_whable(sb, bdiropq)) + dinfo->di_bdiropq = bdiropq; + + err = -EIO; + dinfo->di_bstart = -1; + dinfo->di_bend = -1; + bend = au_dbend(parent); + p = dinfo->di_hdentry; + for (bindex = 0; bindex <= bend; bindex++, p++) + if (p->hd_dentry) { + dinfo->di_bstart = bindex; + break; + } + + if (dinfo->di_bstart >= 0) { + p = dinfo->di_hdentry + bend; + for (bindex = bend; bindex >= 0; bindex--, p--) + if (p->hd_dentry) { + dinfo->di_bend = bindex; + err = 0; + break; + } + } + + return err; +} + +static void au_do_hide(struct dentry *dentry) +{ + struct inode *inode; + + inode = dentry->d_inode; + if (inode) { + if (!S_ISDIR(inode->i_mode)) { + if (inode->i_nlink && !d_unhashed(dentry)) + drop_nlink(inode); + } else { + clear_nlink(inode); + /* stop next lookup */ + inode->i_flags |= S_DEAD; + } + smp_mb(); /* necessary? */ + } + d_drop(dentry); +} + +static int au_hide_children(struct dentry *parent) +{ + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry *dentry; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, parent, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + /* in reverse order */ + for (i = dpages.ndpage - 1; i >= 0; i--) { + dpage = dpages.dpages + i; + ndentry = dpage->ndentry; + for (j = ndentry - 1; j >= 0; j--) { + dentry = dpage->dentries[j]; + if (dentry != parent) + au_do_hide(dentry); + } + } + +out_dpages: + au_dpages_free(&dpages); +out: + return err; +} + +static void au_hide(struct dentry *dentry) +{ + int err; + struct inode *inode; + + AuDbgDentry(dentry); + inode = dentry->d_inode; + if (inode && S_ISDIR(inode->i_mode)) { + /* shrink_dcache_parent(dentry); */ + err = au_hide_children(dentry); + if (unlikely(err)) + AuIOErr("%pd, failed hiding children, ignored %d\n", + dentry, err); + } + au_do_hide(dentry); +} + +/* + * By adding a dirty branch, a cached dentry may be affected in various ways. + * + * a dirty branch is added + * - on the top of layers + * - in the middle of layers + * - to the bottom of layers + * + * on the added branch there exists + * - a whiteout + * - a diropq + * - a same named entry + * + exist + * * negative --> positive + * * positive --> positive + * - type is unchanged + * - type is changed + * + doesn't exist + * * negative --> negative + * * positive --> negative (rejected by au_br_del() for non-dir case) + * - none + */ +static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, + struct au_dinfo *tmp) +{ + int err; + aufs_bindex_t bindex, bend; + struct { + struct dentry *dentry; + struct inode *inode; + mode_t mode; + } orig_h, tmp_h; + struct au_hdentry *hd; + struct inode *inode, *h_inode; + struct dentry *h_dentry; + + err = 0; + AuDebugOn(dinfo->di_bstart < 0); + orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry; + orig_h.inode = orig_h.dentry->d_inode; + orig_h.mode = 0; + if (orig_h.inode) + orig_h.mode = orig_h.inode->i_mode & S_IFMT; + memset(&tmp_h, 0, sizeof(tmp_h)); + if (tmp->di_bstart >= 0) { + tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry; + tmp_h.inode = tmp_h.dentry->d_inode; + if (tmp_h.inode) + tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; + } + + inode = dentry->d_inode; + if (!orig_h.inode) { + AuDbg("nagative originally\n"); + if (inode) { + au_hide(dentry); + goto out; + } + AuDebugOn(inode); + AuDebugOn(dinfo->di_bstart != dinfo->di_bend); + AuDebugOn(dinfo->di_bdiropq != -1); + + if (!tmp_h.inode) { + AuDbg("negative --> negative\n"); + /* should have only one negative lower */ + if (tmp->di_bstart >= 0 + && tmp->di_bstart < dinfo->di_bstart) { + AuDebugOn(tmp->di_bstart != tmp->di_bend); + AuDebugOn(dinfo->di_bstart != dinfo->di_bend); + au_set_h_dptr(dentry, dinfo->di_bstart, NULL); + au_di_cp(dinfo, tmp); + hd = tmp->di_hdentry + tmp->di_bstart; + au_set_h_dptr(dentry, tmp->di_bstart, + dget(hd->hd_dentry)); + } + au_dbg_verify_dinode(dentry); + } else { + AuDbg("negative --> positive\n"); + /* + * similar to the behaviour of creating with bypassing + * aufs. + * unhash it in order to force an error in the + * succeeding create operation. + * we should not set S_DEAD here. + */ + d_drop(dentry); + /* au_di_swap(tmp, dinfo); */ + au_dbg_verify_dinode(dentry); + } + } else { + AuDbg("positive originally\n"); + /* inode may be NULL */ + AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); + if (!tmp_h.inode) { + AuDbg("positive --> negative\n"); + /* or bypassing aufs */ + au_hide(dentry); + if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart) + dinfo->di_bwh = tmp->di_bwh; + if (inode) + err = au_refresh_hinode_self(inode); + au_dbg_verify_dinode(dentry); + } else if (orig_h.mode == tmp_h.mode) { + AuDbg("positive --> positive, same type\n"); + if (!S_ISDIR(orig_h.mode) + && dinfo->di_bstart > tmp->di_bstart) { + /* + * similar to the behaviour of removing and + * creating. + */ + au_hide(dentry); + if (inode) + err = au_refresh_hinode_self(inode); + au_dbg_verify_dinode(dentry); + } else { + /* fill empty slots */ + if (dinfo->di_bstart > tmp->di_bstart) + dinfo->di_bstart = tmp->di_bstart; + if (dinfo->di_bend < tmp->di_bend) + dinfo->di_bend = tmp->di_bend; + dinfo->di_bwh = tmp->di_bwh; + dinfo->di_bdiropq = tmp->di_bdiropq; + hd = tmp->di_hdentry; + bend = dinfo->di_bend; + for (bindex = tmp->di_bstart; bindex <= bend; + bindex++) { + if (au_h_dptr(dentry, bindex)) + continue; + h_dentry = hd[bindex].hd_dentry; + if (!h_dentry) + continue; + h_inode = h_dentry->d_inode; + AuDebugOn(!h_inode); + AuDebugOn(orig_h.mode + != (h_inode->i_mode + & S_IFMT)); + au_set_h_dptr(dentry, bindex, + dget(h_dentry)); + } + err = au_refresh_hinode(inode, dentry); + au_dbg_verify_dinode(dentry); + } + } else { + AuDbg("positive --> positive, different type\n"); + /* similar to the behaviour of removing and creating */ + au_hide(dentry); + if (inode) + err = au_refresh_hinode_self(inode); + au_dbg_verify_dinode(dentry); + } + } + +out: + return err; +} + +int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) +{ + int err, ebrange; + unsigned int sigen; + struct au_dinfo *dinfo, *tmp; + struct super_block *sb; + struct inode *inode; + + DiMustWriteLock(dentry); + AuDebugOn(IS_ROOT(dentry)); + AuDebugOn(!parent->d_inode); + + sb = dentry->d_sb; + inode = dentry->d_inode; + sigen = au_sigen(sb); + err = au_digen_test(parent, sigen); + if (unlikely(err)) + goto out; + + dinfo = au_di(dentry); + err = au_di_realloc(dinfo, au_sbend(sb) + 1); + if (unlikely(err)) + goto out; + ebrange = au_dbrange_test(dentry); + if (!ebrange) + ebrange = au_do_refresh_hdentry(dentry, parent); + + if (d_unhashed(dentry) || ebrange) { + AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0); + if (inode) + err = au_refresh_hinode_self(inode); + au_dbg_verify_dinode(dentry); + if (!err) + goto out_dgen; /* success */ + goto out; + } + + /* temporary dinfo */ + AuDbgDentry(dentry); + err = -ENOMEM; + tmp = au_di_alloc(sb, AuLsc_DI_TMP); + if (unlikely(!tmp)) + goto out; + au_di_swap(tmp, dinfo); + /* returns the number of positive dentries */ + /* + * if current working dir is removed, it returns an error. + * but the dentry is legal. + */ + err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0); + AuDbgDentry(dentry); + au_di_swap(tmp, dinfo); + if (err == -ENOENT) + err = 0; + if (err >= 0) { + /* compare/refresh by dinfo */ + AuDbgDentry(dentry); + err = au_refresh_by_dinfo(dentry, dinfo, tmp); + au_dbg_verify_dinode(dentry); + AuTraceErr(err); + } + au_rw_write_unlock(&tmp->di_rwsem); + au_di_free(tmp); + if (unlikely(err)) + goto out; + +out_dgen: + au_update_digen(dentry); +out: + if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { + AuIOErr("failed refreshing %pd, %d\n", dentry, err); + AuDbgDentry(dentry); + } + AuTraceErr(err); + return err; +} + +static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, + struct dentry *dentry, aufs_bindex_t bindex) +{ + int err, valid; + + err = 0; + if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) + goto out; + + AuDbg("b%d\n", bindex); + /* + * gave up supporting LOOKUP_CREATE/OPEN for lower fs, + * due to whiteout and branch permission. + */ + flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE + | LOOKUP_FOLLOW | LOOKUP_EXCL); + /* it may return tri-state */ + valid = h_dentry->d_op->d_revalidate(h_dentry, flags); + + if (unlikely(valid < 0)) + err = valid; + else if (!valid) + err = -EINVAL; + +out: + AuTraceErr(err); + return err; +} + +/* todo: remove this */ +static int h_d_revalidate(struct dentry *dentry, struct inode *inode, + unsigned int flags, int do_udba) +{ + int err; + umode_t mode, h_mode; + aufs_bindex_t bindex, btail, bstart, ibs, ibe; + unsigned char plus, unhashed, is_root, h_plus, h_nfs; + struct inode *h_inode, *h_cached_inode; + struct dentry *h_dentry; + struct qstr *name, *h_name; + + err = 0; + plus = 0; + mode = 0; + ibs = -1; + ibe = -1; + unhashed = !!d_unhashed(dentry); + is_root = !!IS_ROOT(dentry); + name = &dentry->d_name; + + /* + * Theoretically, REVAL test should be unnecessary in case of + * {FS,I}NOTIFY. + * But {fs,i}notify doesn't fire some necessary events, + * IN_ATTRIB for atime/nlink/pageio + * IN_DELETE for NFS dentry + * Let's do REVAL test too. + */ + if (do_udba && inode) { + mode = (inode->i_mode & S_IFMT); + plus = (inode->i_nlink > 0); + ibs = au_ibstart(inode); + ibe = au_ibend(inode); + } + + bstart = au_dbstart(dentry); + btail = bstart; + if (inode && S_ISDIR(inode->i_mode)) + btail = au_dbtaildir(dentry); + for (bindex = bstart; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + + AuDbg("b%d, %pd\n", bindex, h_dentry); + h_nfs = !!au_test_nfs(h_dentry->d_sb); + spin_lock(&h_dentry->d_lock); + h_name = &h_dentry->d_name; + if (unlikely(do_udba + && !is_root + && ((!h_nfs + && (unhashed != !!d_unhashed(h_dentry) + || name->len != h_name->len + || memcmp(name->name, h_name->name, + name->len))) + || (h_nfs + && !(flags & LOOKUP_OPEN) + && (h_dentry->d_flags + & DCACHE_NFSFS_RENAMED))) + )) { + AuDbg("unhash 0x%x 0x%x, %pd %pd\n", + unhashed, d_unhashed(h_dentry), + dentry, h_dentry); + spin_unlock(&h_dentry->d_lock); + goto err; + } + spin_unlock(&h_dentry->d_lock); + + err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); + if (unlikely(err)) + /* do not goto err, to keep the errno */ + break; + + /* todo: plink too? */ + if (!do_udba) + continue; + + /* UDBA tests */ + h_inode = h_dentry->d_inode; + if (unlikely(!!inode != !!h_inode)) + goto err; + + h_plus = plus; + h_mode = mode; + h_cached_inode = h_inode; + if (h_inode) { + h_mode = (h_inode->i_mode & S_IFMT); + h_plus = (h_inode->i_nlink > 0); + } + if (inode && ibs <= bindex && bindex <= ibe) + h_cached_inode = au_h_iptr(inode, bindex); + + if (!h_nfs) { + if (unlikely(plus != h_plus)) + goto err; + } else { + if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) + && !is_root + && !IS_ROOT(h_dentry) + && unhashed != d_unhashed(h_dentry))) + goto err; + } + if (unlikely(mode != h_mode + || h_cached_inode != h_inode)) + goto err; + continue; + +err: + err = -EINVAL; + break; + } + + AuTraceErr(err); + return err; +} + +/* todo: consolidate with do_refresh() and au_reval_for_attr() */ +static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) +{ + int err; + struct dentry *parent; + + if (!au_digen_test(dentry, sigen)) + return 0; + + parent = dget_parent(dentry); + di_read_lock_parent(parent, AuLock_IR); + AuDebugOn(au_digen_test(parent, sigen)); + au_dbg_verify_gen(parent, sigen); + err = au_refresh_dentry(dentry, parent); + di_read_unlock(parent, AuLock_IR); + dput(parent); + AuTraceErr(err); + return err; +} + +int au_reval_dpath(struct dentry *dentry, unsigned int sigen) +{ + int err; + struct dentry *d, *parent; + struct inode *inode; + + if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) + return simple_reval_dpath(dentry, sigen); + + /* slow loop, keep it simple and stupid */ + /* cf: au_cpup_dirs() */ + err = 0; + parent = NULL; + while (au_digen_test(dentry, sigen)) { + d = dentry; + while (1) { + dput(parent); + parent = dget_parent(d); + if (!au_digen_test(parent, sigen)) + break; + d = parent; + } + + inode = d->d_inode; + if (d != dentry) + di_write_lock_child2(d); + + /* someone might update our dentry while we were sleeping */ + if (au_digen_test(d, sigen)) { + /* + * todo: consolidate with simple_reval_dpath(), + * do_refresh() and au_reval_for_attr(). + */ + di_read_lock_parent(parent, AuLock_IR); + err = au_refresh_dentry(d, parent); + di_read_unlock(parent, AuLock_IR); + } + + if (d != dentry) + di_write_unlock(d); + dput(parent); + if (unlikely(err)) + break; + } + + return err; +} + +/* + * if valid returns 1, otherwise 0. + */ +static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + int valid, err; + unsigned int sigen; + unsigned char do_udba; + struct super_block *sb; + struct inode *inode; + + /* todo: support rcu-walk? */ + if (flags & LOOKUP_RCU) + return -ECHILD; + + valid = 0; + if (unlikely(!au_di(dentry))) + goto out; + + inode = dentry->d_inode; + if (inode && is_bad_inode(inode)) + goto out; + + valid = 1; + sb = dentry->d_sb; + /* + * todo: very ugly + * i_mutex of parent dir may be held, + * but we should not return 'invalid' due to busy. + */ + err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); + if (unlikely(err)) { + valid = err; + AuTraceErr(err); + goto out; + } + if (unlikely(au_dbrange_test(dentry))) { + err = -EINVAL; + AuTraceErr(err); + goto out_dgrade; + } + + sigen = au_sigen(sb); + if (au_digen_test(dentry, sigen)) { + AuDebugOn(IS_ROOT(dentry)); + err = au_reval_dpath(dentry, sigen); + if (unlikely(err)) { + AuTraceErr(err); + goto out_dgrade; + } + } + di_downgrade_lock(dentry, AuLock_IR); + + err = -EINVAL; + if (!(flags & LOOKUP_OPEN) + && inode + && (IS_DEADDIR(inode) || !inode->i_nlink)) + goto out_inval; + + do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); + if (do_udba && inode) { + aufs_bindex_t bstart = au_ibstart(inode); + struct inode *h_inode; + + if (bstart >= 0) { + h_inode = au_h_iptr(inode, bstart); + if (h_inode && au_test_higen(inode, h_inode)) + goto out_inval; + } + } + + err = h_d_revalidate(dentry, inode, flags, do_udba); + if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) { + err = -EIO; + AuDbg("both of real entry and whiteout found, %p, err %d\n", + dentry, err); + } + goto out_inval; + +out_dgrade: + di_downgrade_lock(dentry, AuLock_IR); +out_inval: + aufs_read_unlock(dentry, AuLock_IR); + AuTraceErr(err); + valid = !err; +out: + if (!valid) { + AuDbg("%pd invalid, %d\n", dentry, valid); + d_drop(dentry); + } + return valid; +} + +static void aufs_d_release(struct dentry *dentry) +{ + if (au_di(dentry)) { + au_di_fin(dentry); + au_hn_di_reinit(dentry); + } +} + +const struct dentry_operations aufs_dop = { + .d_revalidate = aufs_d_revalidate, + .d_weak_revalidate = aufs_d_revalidate, + .d_release = aufs_d_release +}; --- linux-3.13.0.orig/ubuntu/aufs/dbgaufs.h +++ linux-3.13.0/ubuntu/aufs/dbgaufs.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debugfs interface + */ + +#ifndef __DBGAUFS_H__ +#define __DBGAUFS_H__ + +#ifdef __KERNEL__ + +struct super_block; +struct au_sbinfo; + +#ifdef CONFIG_DEBUG_FS +/* dbgaufs.c */ +void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); +void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); +void dbgaufs_si_fin(struct au_sbinfo *sbinfo); +int dbgaufs_si_init(struct au_sbinfo *sbinfo); +void dbgaufs_fin(void); +int __init dbgaufs_init(void); +#else +AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) +AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) +AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) +AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) +AuStubVoid(dbgaufs_fin, void) +AuStubInt0(__init dbgaufs_init, void) +#endif /* CONFIG_DEBUG_FS */ + +#endif /* __KERNEL__ */ +#endif /* __DBGAUFS_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/f_op.c +++ linux-3.13.0/ubuntu/aufs/f_op.c @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * file and vm operations + */ + +#include +#include +#include +#include +#include "aufs.h" + +int au_do_open_nondir(struct file *file, int flags) +{ + int err; + aufs_bindex_t bindex; + struct file *h_file; + struct dentry *dentry; + struct au_finfo *finfo; + + FiMustWriteLock(file); + + err = 0; + dentry = file->f_dentry; + finfo = au_fi(file); + memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); + atomic_set(&finfo->fi_mmapped, 0); + bindex = au_dbstart(dentry); + h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); + if (IS_ERR(h_file)) + err = PTR_ERR(h_file); + else { + au_set_fbstart(file, bindex); + au_set_h_fptr(file, bindex, h_file); + au_update_figen(file); + finfo->fi_file = file; + au_sphl_add(&finfo->fi_hlist, &au_sbi(dentry->d_sb)->si_files); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + } + + return err; +} + +static int aufs_open_nondir(struct inode *inode __maybe_unused, + struct file *file) +{ + int err; + struct super_block *sb; + + AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", + file, vfsub_file_flags(file), file->f_mode); + + sb = file->f_dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_do_open(file, au_do_open_nondir, /*fidir*/NULL); + si_read_unlock(sb); + return err; +} + +int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) +{ + struct au_finfo *finfo; + aufs_bindex_t bindex; + + finfo = au_fi(file); + au_sphl_del(&finfo->fi_hlist, &au_sbi(file->f_dentry->d_sb)->si_files); + bindex = finfo->fi_btop; + if (bindex >= 0) + au_set_h_fptr(file, bindex, NULL); + + au_finfo_fin(file); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_flush_nondir(struct file *file, fl_owner_t id) +{ + int err; + struct file *h_file; + + err = 0; + h_file = au_hf_top(file); + if (h_file) + err = vfsub_flush(h_file, id); + return err; +} + +static int aufs_flush_nondir(struct file *file, fl_owner_t id) +{ + return au_do_flush(file, id, au_do_flush_nondir); +} + +/* ---------------------------------------------------------------------- */ +/* + * read and write functions acquire [fdi]_rwsem once, but release before + * mmap_sem. This is because to stop a race condition between mmap(2). + * Releasing these aufs-rwsem should be safe, no branch-mamagement (by keeping + * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in + * read functions after [fdi]_rwsem are released, but it should be harmless. + */ + +static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + ssize_t err; + struct dentry *dentry; + struct file *h_file; + struct super_block *sb; + + dentry = file->f_dentry; + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); + if (unlikely(err)) + goto out; + + h_file = au_hf_top(file); + get_file(h_file); + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + + /* filedata may be obsoleted by concurrent copyup, but no problem */ + err = vfsub_read_u(h_file, buf, count, ppos); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + /* update without lock, I don't think it a problem */ + fsstack_copy_attr_atime(dentry->d_inode, file_inode(h_file)); + fput(h_file); + +out: + si_read_unlock(sb); + return err; +} + +/* + * todo: very ugly + * it locks both of i_mutex and si_rwsem for read in safe. + * if the plink maintenance mode continues forever (that is the problem), + * may loop forever. + */ +static void au_mtx_and_read_lock(struct inode *inode) +{ + int err; + struct super_block *sb = inode->i_sb; + + while (1) { + mutex_lock(&inode->i_mutex); + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (!err) + break; + mutex_unlock(&inode->i_mutex); + si_read_lock(sb, AuLock_NOPLMW); + si_read_unlock(sb); + } +} + +static ssize_t aufs_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t err; + struct au_pin pin; + struct dentry *dentry; + struct super_block *sb; + struct inode *inode; + struct file *h_file; + char __user *buf = (char __user *)ubuf; + + dentry = file->f_dentry; + sb = dentry->d_sb; + inode = dentry->d_inode; + au_mtx_and_read_lock(inode); + + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); + if (unlikely(err)) + goto out; + + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) { + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + goto out; + } + + h_file = au_hf_top(file); + get_file(h_file); + au_unpin(&pin); + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + + err = vfsub_write_u(h_file, buf, count, ppos); + ii_write_lock_child(inode); + au_cpup_attr_timesizes(inode); + inode->i_mode = file_inode(h_file)->i_mode; + ii_write_unlock(inode); + fput(h_file); + +out: + si_read_unlock(sb); + mutex_unlock(&inode->i_mutex); + return err; +} + +static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio, + const struct iovec *iov, unsigned long nv, loff_t pos) +{ + ssize_t err; + struct file *file; + ssize_t (*func)(struct kiocb *, const struct iovec *, unsigned long, + loff_t); + + err = security_file_permission(h_file, rw); + if (unlikely(err)) + goto out; + + err = -ENOSYS; + func = NULL; + if (rw == MAY_READ) + func = h_file->f_op->aio_read; + else if (rw == MAY_WRITE) + func = h_file->f_op->aio_write; + if (func) { + file = kio->ki_filp; + kio->ki_filp = h_file; + lockdep_off(); + err = func(kio, iov, nv, pos); + lockdep_on(); + kio->ki_filp = file; + } else + /* currently there is no such fs */ + WARN_ON_ONCE(1); + +out: + return err; +} + +static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, + unsigned long nv, loff_t pos) +{ + ssize_t err; + struct file *file, *h_file; + struct dentry *dentry; + struct super_block *sb; + + file = kio->ki_filp; + dentry = file->f_dentry; + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); + if (unlikely(err)) + goto out; + + h_file = au_hf_top(file); + get_file(h_file); + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + + err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + /* update without lock, I don't think it a problem */ + fsstack_copy_attr_atime(dentry->d_inode, file_inode(h_file)); + fput(h_file); + +out: + si_read_unlock(sb); + return err; +} + +static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov, + unsigned long nv, loff_t pos) +{ + ssize_t err; + struct au_pin pin; + struct dentry *dentry; + struct inode *inode; + struct file *file, *h_file; + struct super_block *sb; + + file = kio->ki_filp; + dentry = file->f_dentry; + sb = dentry->d_sb; + inode = dentry->d_inode; + au_mtx_and_read_lock(inode); + + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); + if (unlikely(err)) + goto out; + + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) { + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + goto out; + } + + h_file = au_hf_top(file); + get_file(h_file); + au_unpin(&pin); + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + + err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos); + ii_write_lock_child(inode); + au_cpup_attr_timesizes(inode); + inode->i_mode = file_inode(h_file)->i_mode; + ii_write_unlock(inode); + fput(h_file); + +out: + si_read_unlock(sb); + mutex_unlock(&inode->i_mutex); + return err; +} + +static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + ssize_t err; + struct file *h_file; + struct dentry *dentry; + struct super_block *sb; + + dentry = file->f_dentry; + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); + if (unlikely(err)) + goto out; + + err = -EINVAL; + h_file = au_hf_top(file); + get_file(h_file); + if (au_test_loopback_kthread()) { + au_warn_loopback(h_file->f_dentry->d_sb); + if (file->f_mapping != h_file->f_mapping) { + file->f_mapping = h_file->f_mapping; + smp_mb(); /* unnecessary? */ + } + } + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + + err = vfsub_splice_to(h_file, ppos, pipe, len, flags); + /* todo: necessasry? */ + /* file->f_ra = h_file->f_ra; */ + /* update without lock, I don't think it a problem */ + fsstack_copy_attr_atime(dentry->d_inode, file_inode(h_file)); + fput(h_file); + +out: + si_read_unlock(sb); + return err; +} + +static ssize_t +aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, + size_t len, unsigned int flags) +{ + ssize_t err; + struct au_pin pin; + struct dentry *dentry; + struct inode *inode; + struct file *h_file; + struct super_block *sb; + + dentry = file->f_dentry; + sb = dentry->d_sb; + inode = dentry->d_inode; + au_mtx_and_read_lock(inode); + + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); + if (unlikely(err)) + goto out; + + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) { + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + goto out; + } + + h_file = au_hf_top(file); + get_file(h_file); + au_unpin(&pin); + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + + err = vfsub_splice_from(pipe, h_file, ppos, len, flags); + ii_write_lock_child(inode); + au_cpup_attr_timesizes(inode); + inode->i_mode = file_inode(h_file)->i_mode; + ii_write_unlock(inode); + fput(h_file); + +out: + si_read_unlock(sb); + mutex_unlock(&inode->i_mutex); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * The locking order around current->mmap_sem. + * - in most and regular cases + * file I/O syscall -- aufs_read() or something + * -- si_rwsem for read -- mmap_sem + * (Note that [fdi]i_rwsem are released before mmap_sem). + * - in mmap case + * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem + * This AB-BA order is definitly bad, but is not a problem since "si_rwsem for + * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in + * file I/O. Aufs needs to stop lockdep in aufs_mmap() though. + * It means that when aufs acquires si_rwsem for write, the process should never + * acquire mmap_sem. + * + * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a + * problem either since any directory is not able to be mmap-ed. + * The similar scenario is applied to aufs_readlink() too. + */ + +/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ +#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) + +static unsigned long au_arch_prot_conv(unsigned long flags) +{ + /* currently ppc64 only */ +#ifdef CONFIG_PPC64 + /* cf. linux/arch/powerpc/include/asm/mman.h */ + AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); + return AuConv_VM_PROT(flags, SAO); +#else + AuDebugOn(arch_calc_vm_prot_bits(-1)); + return 0; +#endif +} + +static unsigned long au_prot_conv(unsigned long flags) +{ + return AuConv_VM_PROT(flags, READ) + | AuConv_VM_PROT(flags, WRITE) + | AuConv_VM_PROT(flags, EXEC) + | au_arch_prot_conv(flags); +} + +/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ +#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) + +static unsigned long au_flag_conv(unsigned long flags) +{ + return AuConv_VM_MAP(flags, GROWSDOWN) + | AuConv_VM_MAP(flags, DENYWRITE) + | AuConv_VM_MAP(flags, LOCKED); +} + +static int aufs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err; + aufs_bindex_t bstart; + const unsigned char wlock + = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); + struct dentry *dentry; + struct super_block *sb; + struct file *h_file; + struct au_branch *br; + struct au_pin pin; + + AuDbgVmRegion(file, vma); + + dentry = file->f_dentry; + sb = dentry->d_sb; + lockdep_off(); + si_read_lock(sb, AuLock_NOPLMW); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); + if (unlikely(err)) + goto out; + + if (wlock) { + err = au_ready_to_write(file, -1, &pin); + di_write_unlock(dentry); + if (unlikely(err)) { + fi_write_unlock(file); + goto out; + } + au_unpin(&pin); + } else + di_write_unlock(dentry); + + bstart = au_fbstart(file); + br = au_sbr(sb, bstart); + h_file = au_hf_top(file); + get_file(h_file); + au_set_mmapped(file); + fi_write_unlock(file); + lockdep_on(); + + au_vm_file_reset(vma, h_file); + err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), + au_flag_conv(vma->vm_flags)); + if (!err) + err = h_file->f_op->mmap(h_file, vma); + if (unlikely(err)) + goto out_reset; + + au_vm_prfile_set(vma, file); + /* update without lock, I don't think it a problem */ + fsstack_copy_attr_atime(file_inode(file), file_inode(h_file)); + goto out_fput; /* success */ + +out_reset: + au_unset_mmapped(file); + au_vm_file_reset(vma, file); +out_fput: + fput(h_file); + lockdep_off(); +out: + si_read_unlock(sb); + lockdep_on(); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, + int datasync) +{ + int err; + struct au_pin pin; + struct dentry *dentry; + struct inode *inode; + struct file *h_file; + struct super_block *sb; + + dentry = file->f_dentry; + inode = dentry->d_inode; + sb = dentry->d_sb; + mutex_lock(&inode->i_mutex); + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out; + + err = 0; /* -EBADF; */ /* posix? */ + if (unlikely(!(file->f_mode & FMODE_WRITE))) + goto out_si; + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); + if (unlikely(err)) + goto out_si; + + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + au_unpin(&pin); + + err = -EINVAL; + h_file = au_hf_top(file); + err = vfsub_fsync(h_file, &h_file->f_path, datasync); + au_cpup_attr_timesizes(inode); + +out_unlock: + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out_si: + si_read_unlock(sb); +out: + mutex_unlock(&inode->i_mutex); + return err; +} + +/* no one supports this operation, currently */ +#if 0 +static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) +{ + int err; + struct au_pin pin; + struct dentry *dentry; + struct inode *inode; + struct file *file, *h_file; + + file = kio->ki_filp; + dentry = file->f_dentry; + inode = dentry->d_inode; + au_mtx_and_read_lock(inode); + + err = 0; /* -EBADF; */ /* posix? */ + if (unlikely(!(file->f_mode & FMODE_WRITE))) + goto out; + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); + if (unlikely(err)) + goto out; + + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + au_unpin(&pin); + + err = -ENOSYS; + h_file = au_hf_top(file); + if (h_file->f_op->aio_fsync) { + struct mutex *h_mtx; + + h_mtx = &file_inode(h_file)->i_mutex; + if (!is_sync_kiocb(kio)) { + get_file(h_file); + fput(file); + } + kio->ki_filp = h_file; + err = h_file->f_op->aio_fsync(kio, datasync); + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + if (!err) + vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); + /*ignore*/ + au_cpup_attr_timesizes(inode); + mutex_unlock(h_mtx); + } + +out_unlock: + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out: + si_read_unlock(inode->sb); + mutex_unlock(&inode->i_mutex); + return err; +} +#endif + +static int aufs_fasync(int fd, struct file *file, int flag) +{ + int err; + struct file *h_file; + struct dentry *dentry; + struct super_block *sb; + + dentry = file->f_dentry; + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); + if (unlikely(err)) + goto out; + + h_file = au_hf_top(file); + if (h_file->f_op->fasync) + err = h_file->f_op->fasync(fd, h_file, flag); + + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + +out: + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* no one supports this operation, currently */ +#if 0 +static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, + size_t len, loff_t *pos , int more) +{ +} +#endif + +/* ---------------------------------------------------------------------- */ + +const struct file_operations aufs_file_fop = { + .owner = THIS_MODULE, + + .llseek = default_llseek, + + .read = aufs_read, + .write = aufs_write, + .aio_read = aufs_aio_read, + .aio_write = aufs_aio_write, +#ifdef CONFIG_AUFS_POLL + .poll = aufs_poll, +#endif + .unlocked_ioctl = aufs_ioctl_nondir, +#ifdef CONFIG_COMPAT + .compat_ioctl = aufs_compat_ioctl_nondir, +#endif + .mmap = aufs_mmap, + .open = aufs_open_nondir, + .flush = aufs_flush_nondir, + .release = aufs_release_nondir, + .fsync = aufs_fsync_nondir, + /* .aio_fsync = aufs_aio_fsync_nondir, */ + .fasync = aufs_fasync, + /* .sendpage = aufs_sendpage, */ + .splice_write = aufs_splice_write, + .splice_read = aufs_splice_read, +#if 0 + .aio_splice_write = aufs_aio_splice_write, + .aio_splice_read = aufs_aio_splice_read +#endif +}; --- linux-3.13.0.orig/ubuntu/aufs/finfo.c +++ linux-3.13.0/ubuntu/aufs/finfo.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * file private data + */ + +#include "aufs.h" + +void au_hfput(struct au_hfile *hf, struct file *file) +{ + /* todo: direct access f_flags */ + if (vfsub_file_flags(file) & __FMODE_EXEC) + allow_write_access(hf->hf_file); + fput(hf->hf_file); + hf->hf_file = NULL; + atomic_dec(&hf->hf_br->br_count); + hf->hf_br = NULL; +} + +void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) +{ + struct au_finfo *finfo = au_fi(file); + struct au_hfile *hf; + struct au_fidir *fidir; + + fidir = finfo->fi_hdir; + if (!fidir) { + AuDebugOn(finfo->fi_btop != bindex); + hf = &finfo->fi_htop; + } else + hf = fidir->fd_hfile + bindex; + + if (hf && hf->hf_file) + au_hfput(hf, file); + if (val) { + FiMustWriteLock(file); + hf->hf_file = val; + hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex); + } +} + +void au_update_figen(struct file *file) +{ + atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry)); + /* smp_mb(); */ /* atomic_set */ +} + +/* ---------------------------------------------------------------------- */ + +struct au_fidir *au_fidir_alloc(struct super_block *sb) +{ + struct au_fidir *fidir; + int nbr; + + nbr = au_sbend(sb) + 1; + if (nbr < 2) + nbr = 2; /* initial allocate for 2 branches */ + fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); + if (fidir) { + fidir->fd_bbot = -1; + fidir->fd_nent = nbr; + fidir->fd_vdir_cache = NULL; + } + + return fidir; +} + +int au_fidir_realloc(struct au_finfo *finfo, int nbr) +{ + int err; + struct au_fidir *fidir, *p; + + AuRwMustWriteLock(&finfo->fi_rwsem); + fidir = finfo->fi_hdir; + AuDebugOn(!fidir); + + err = -ENOMEM; + p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), + GFP_NOFS); + if (p) { + p->fd_nent = nbr; + finfo->fi_hdir = p; + err = 0; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_finfo_fin(struct file *file) +{ + struct au_finfo *finfo; + + au_nfiles_dec(file->f_dentry->d_sb); + + finfo = au_fi(file); + AuDebugOn(finfo->fi_hdir); + AuRwDestroy(&finfo->fi_rwsem); + au_cache_free_finfo(finfo); +} + +void au_fi_init_once(void *_finfo) +{ + struct au_finfo *finfo = _finfo; + static struct lock_class_key aufs_fi; + + au_rw_init(&finfo->fi_rwsem); + au_rw_class(&finfo->fi_rwsem, &aufs_fi); +} + +int au_finfo_init(struct file *file, struct au_fidir *fidir) +{ + int err; + struct au_finfo *finfo; + struct dentry *dentry; + + err = -ENOMEM; + dentry = file->f_dentry; + finfo = au_cache_alloc_finfo(); + if (unlikely(!finfo)) + goto out; + + err = 0; + au_nfiles_inc(dentry->d_sb); + /* verbose coding for lock class name */ + if (!fidir) + au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcNonDir_FIINFO); + else + au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcDir_FIINFO); + au_rw_write_lock(&finfo->fi_rwsem); + finfo->fi_btop = -1; + finfo->fi_hdir = fidir; + atomic_set(&finfo->fi_generation, au_digen(dentry)); + /* smp_mb(); */ /* atomic_set */ + + file->private_data = finfo; + +out: + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/dir.c +++ linux-3.13.0/ubuntu/aufs/dir.c @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * directory operations + */ + +#include +#include "aufs.h" + +void au_add_nlink(struct inode *dir, struct inode *h_dir) +{ + unsigned int nlink; + + AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); + + nlink = dir->i_nlink; + nlink += h_dir->i_nlink - 2; + if (h_dir->i_nlink < 2) + nlink += 2; + smp_mb(); /* for i_nlink */ + /* 0 can happen in revaliding */ + set_nlink(dir, nlink); +} + +void au_sub_nlink(struct inode *dir, struct inode *h_dir) +{ + unsigned int nlink; + + AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); + + nlink = dir->i_nlink; + nlink -= h_dir->i_nlink - 2; + if (h_dir->i_nlink < 2) + nlink -= 2; + smp_mb(); /* for i_nlink */ + /* nlink == 0 means the branch-fs is broken */ + set_nlink(dir, nlink); +} + +loff_t au_dir_size(struct file *file, struct dentry *dentry) +{ + loff_t sz; + aufs_bindex_t bindex, bend; + struct file *h_file; + struct dentry *h_dentry; + + sz = 0; + if (file) { + AuDebugOn(!file_inode(file)); + AuDebugOn(!S_ISDIR(file_inode(file)->i_mode)); + + bend = au_fbend_dir(file); + for (bindex = au_fbstart(file); + bindex <= bend && sz < KMALLOC_MAX_SIZE; + bindex++) { + h_file = au_hf_dir(file, bindex); + if (h_file && file_inode(h_file)) + sz += vfsub_f_size_read(h_file); + } + } else { + AuDebugOn(!dentry); + AuDebugOn(!dentry->d_inode); + AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); + + bend = au_dbtaildir(dentry); + for (bindex = au_dbstart(dentry); + bindex <= bend && sz < KMALLOC_MAX_SIZE; + bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && h_dentry->d_inode) + sz += i_size_read(h_dentry->d_inode); + } + } + if (sz < KMALLOC_MAX_SIZE) + sz = roundup_pow_of_two(sz); + if (sz > KMALLOC_MAX_SIZE) + sz = KMALLOC_MAX_SIZE; + else if (sz < NAME_MAX) { + BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); + sz = AUFS_RDBLK_DEF; + } + return sz; +} + +/* ---------------------------------------------------------------------- */ + +static int reopen_dir(struct file *file) +{ + int err; + unsigned int flags; + aufs_bindex_t bindex, btail, bstart; + struct dentry *dentry, *h_dentry; + struct file *h_file; + + /* open all lower dirs */ + dentry = file->f_dentry; + bstart = au_dbstart(dentry); + for (bindex = au_fbstart(file); bindex < bstart; bindex++) + au_set_h_fptr(file, bindex, NULL); + au_set_fbstart(file, bstart); + + btail = au_dbtaildir(dentry); + for (bindex = au_fbend_dir(file); btail < bindex; bindex--) + au_set_h_fptr(file, bindex, NULL); + au_set_fbend_dir(file, btail); + + flags = vfsub_file_flags(file); + for (bindex = bstart; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + h_file = au_hf_dir(file, bindex); + if (h_file) + continue; + + h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; /* close all? */ + au_set_h_fptr(file, bindex, h_file); + } + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + err = 0; + +out: + return err; +} + +static int do_open_dir(struct file *file, int flags) +{ + int err; + aufs_bindex_t bindex, btail; + struct dentry *dentry, *h_dentry; + struct file *h_file; + + FiMustWriteLock(file); + + err = 0; + dentry = file->f_dentry; + file->f_version = dentry->d_inode->i_version; + bindex = au_dbstart(dentry); + au_set_fbstart(file, bindex); + btail = au_dbtaildir(dentry); + au_set_fbend_dir(file, btail); + for (; !err && bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + + h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); + if (IS_ERR(h_file)) { + err = PTR_ERR(h_file); + break; + } + au_set_h_fptr(file, bindex, h_file); + } + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + if (!err) + return 0; /* success */ + + /* close all */ + for (bindex = au_fbstart(file); bindex <= btail; bindex++) + au_set_h_fptr(file, bindex, NULL); + au_set_fbstart(file, -1); + au_set_fbend_dir(file, -1); + + return err; +} + +static int aufs_open_dir(struct inode *inode __maybe_unused, + struct file *file) +{ + int err; + struct super_block *sb; + struct au_fidir *fidir; + + err = -ENOMEM; + sb = file->f_dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + fidir = au_fidir_alloc(sb); + if (fidir) { + err = au_do_open(file, do_open_dir, fidir); + if (unlikely(err)) + kfree(fidir); + } + si_read_unlock(sb); + return err; +} + +static int aufs_release_dir(struct inode *inode __maybe_unused, + struct file *file) +{ + struct au_vdir *vdir_cache; + struct au_finfo *finfo; + struct au_fidir *fidir; + aufs_bindex_t bindex, bend; + + finfo = au_fi(file); + fidir = finfo->fi_hdir; + if (fidir) { + vdir_cache = fidir->fd_vdir_cache; /* lock-free */ + if (vdir_cache) + au_vdir_free(vdir_cache); + + bindex = finfo->fi_btop; + if (bindex >= 0) { + /* + * calls fput() instead of filp_close(), + * since no dnotify or lock for the lower file. + */ + bend = fidir->fd_bbot; + for (; bindex <= bend; bindex++) + au_set_h_fptr(file, bindex, NULL); + } + kfree(fidir); + finfo->fi_hdir = NULL; + } + au_finfo_fin(file); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_flush_dir(struct file *file, fl_owner_t id) +{ + int err; + aufs_bindex_t bindex, bend; + struct file *h_file; + + err = 0; + bend = au_fbend_dir(file); + for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { + h_file = au_hf_dir(file, bindex); + if (h_file) + err = vfsub_flush(h_file, id); + } + return err; +} + +static int aufs_flush_dir(struct file *file, fl_owner_t id) +{ + return au_do_flush(file, id, au_do_flush_dir); +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) +{ + int err; + aufs_bindex_t bend, bindex; + struct inode *inode; + struct super_block *sb; + + err = 0; + sb = dentry->d_sb; + inode = dentry->d_inode; + IMustLock(inode); + bend = au_dbend(dentry); + for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) { + struct path h_path; + + if (au_test_ro(sb, bindex, inode)) + continue; + h_path.dentry = au_h_dptr(dentry, bindex); + if (!h_path.dentry) + continue; + + h_path.mnt = au_sbr_mnt(sb, bindex); + err = vfsub_fsync(NULL, &h_path, datasync); + } + + return err; +} + +static int au_do_fsync_dir(struct file *file, int datasync) +{ + int err; + aufs_bindex_t bend, bindex; + struct file *h_file; + struct super_block *sb; + struct inode *inode; + + err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); + if (unlikely(err)) + goto out; + + sb = file->f_dentry->d_sb; + inode = file_inode(file); + bend = au_fbend_dir(file); + for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { + h_file = au_hf_dir(file, bindex); + if (!h_file || au_test_ro(sb, bindex, inode)) + continue; + + err = vfsub_fsync(h_file, &h_file->f_path, datasync); + } + +out: + return err; +} + +/* + * @file may be NULL + */ +static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, + int datasync) +{ + int err; + struct dentry *dentry; + struct super_block *sb; + struct mutex *mtx; + + err = 0; + dentry = file->f_dentry; + mtx = &dentry->d_inode->i_mutex; + mutex_lock(mtx); + sb = dentry->d_sb; + si_noflush_read_lock(sb); + if (file) + err = au_do_fsync_dir(file, datasync); + else { + di_write_lock_child(dentry); + err = au_do_fsync_dir_no_file(dentry, datasync); + } + au_cpup_attr_timesizes(dentry->d_inode); + di_write_unlock(dentry); + if (file) + fi_write_unlock(file); + + si_read_unlock(sb); + mutex_unlock(mtx); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_iterate(struct file *file, struct dir_context *ctx) +{ + int err; + struct dentry *dentry; + struct inode *inode, *h_inode; + struct super_block *sb; + + AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); + + dentry = file->f_dentry; + inode = dentry->d_inode; + IMustLock(inode); + + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); + if (unlikely(err)) + goto out; + err = au_alive_dir(dentry); + if (!err) + err = au_vdir_init(file); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + + h_inode = au_h_iptr(inode, au_ibstart(inode)); + if (!au_test_nfsd()) { + err = au_vdir_fill_de(file, ctx); + fsstack_copy_attr_atime(inode, h_inode); + } else { + /* + * nfsd filldir may call lookup_one_len(), vfs_getattr(), + * encode_fh() and others. + */ + atomic_inc(&h_inode->i_count); + di_read_unlock(dentry, AuLock_IR); + si_read_unlock(sb); + err = au_vdir_fill_de(file, ctx); + fsstack_copy_attr_atime(inode, h_inode); + fi_write_unlock(file); + iput(h_inode); + + AuTraceErr(err); + return err; + } + +out_unlock: + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out: + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +#define AuTestEmpty_WHONLY 1 +#define AuTestEmpty_CALLED (1 << 1) +#define AuTestEmpty_SHWH (1 << 2) +#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) +#define au_fset_testempty(flags, name) \ + do { (flags) |= AuTestEmpty_##name; } while (0) +#define au_fclr_testempty(flags, name) \ + do { (flags) &= ~AuTestEmpty_##name; } while (0) + +#ifndef CONFIG_AUFS_SHWH +#undef AuTestEmpty_SHWH +#define AuTestEmpty_SHWH 0 +#endif + +struct test_empty_arg { + struct dir_context ctx; + struct au_nhash *whlist; + unsigned int flags; + int err; + aufs_bindex_t bindex; +}; + +static int test_empty_cb(struct dir_context *ctx, const char *__name, + int namelen, loff_t offset __maybe_unused, u64 ino, + unsigned int d_type) +{ + struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, + ctx); + char *name = (void *)__name; + + arg->err = 0; + au_fset_testempty(arg->flags, CALLED); + /* smp_mb(); */ + if (name[0] == '.' + && (namelen == 1 || (name[1] == '.' && namelen == 2))) + goto out; /* success */ + + if (namelen <= AUFS_WH_PFX_LEN + || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + if (au_ftest_testempty(arg->flags, WHONLY) + && !au_nhash_test_known_wh(arg->whlist, name, namelen)) + arg->err = -ENOTEMPTY; + goto out; + } + + name += AUFS_WH_PFX_LEN; + namelen -= AUFS_WH_PFX_LEN; + if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) + arg->err = au_nhash_append_wh + (arg->whlist, name, namelen, ino, d_type, arg->bindex, + au_ftest_testempty(arg->flags, SHWH)); + +out: + /* smp_mb(); */ + AuTraceErr(arg->err); + return arg->err; +} + +static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +{ + int err; + struct file *h_file; + + h_file = au_h_open(dentry, arg->bindex, + O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, + /*file*/NULL, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + err = 0; + if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) + && !file_inode(h_file)->i_nlink) + goto out_put; + + do { + arg->err = 0; + au_fclr_testempty(arg->flags, CALLED); + /* smp_mb(); */ + err = vfsub_iterate_dir(h_file, &arg->ctx); + if (err >= 0) + err = arg->err; + } while (!err && au_ftest_testempty(arg->flags, CALLED)); + +out_put: + fput(h_file); + au_sbr_put(dentry->d_sb, arg->bindex); +out: + return err; +} + +struct do_test_empty_args { + int *errp; + struct dentry *dentry; + struct test_empty_arg *arg; +}; + +static void call_do_test_empty(void *args) +{ + struct do_test_empty_args *a = args; + *a->errp = do_test_empty(a->dentry, a->arg); +} + +static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +{ + int err, wkq_err; + struct dentry *h_dentry; + struct inode *h_inode; + + h_dentry = au_h_dptr(dentry, arg->bindex); + h_inode = h_dentry->d_inode; + /* todo: i_mode changes anytime? */ + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); + mutex_unlock(&h_inode->i_mutex); + if (!err) + err = do_test_empty(dentry, arg); + else { + struct do_test_empty_args args = { + .errp = &err, + .dentry = dentry, + .arg = arg + }; + unsigned int flags = arg->flags; + + wkq_err = au_wkq_wait(call_do_test_empty, &args); + if (unlikely(wkq_err)) + err = wkq_err; + arg->flags = flags; + } + + return err; +} + +int au_test_empty_lower(struct dentry *dentry) +{ + int err; + unsigned int rdhash; + aufs_bindex_t bindex, bstart, btail; + struct au_nhash whlist; + struct test_empty_arg arg = { + .ctx = { + .actor = au_diractor(test_empty_cb) + } + }; + + SiMustAnyLock(dentry->d_sb); + + rdhash = au_sbi(dentry->d_sb)->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); + err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + + arg.flags = 0; + arg.whlist = &whlist; + bstart = au_dbstart(dentry); + if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) + au_fset_testempty(arg.flags, SHWH); + arg.bindex = bstart; + err = do_test_empty(dentry, &arg); + if (unlikely(err)) + goto out_whlist; + + au_fset_testempty(arg.flags, WHONLY); + btail = au_dbtaildir(dentry); + for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { + struct dentry *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && h_dentry->d_inode) { + arg.bindex = bindex; + err = do_test_empty(dentry, &arg); + } + } + +out_whlist: + au_nhash_wh_free(&whlist); +out: + return err; +} + +int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) +{ + int err; + struct test_empty_arg arg = { + .ctx = { + .actor = au_diractor(test_empty_cb) + } + }; + aufs_bindex_t bindex, btail; + + err = 0; + arg.whlist = whlist; + arg.flags = AuTestEmpty_WHONLY; + if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) + au_fset_testempty(arg.flags, SHWH); + btail = au_dbtaildir(dentry); + for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) { + struct dentry *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && h_dentry->d_inode) { + arg.bindex = bindex; + err = sio_test_empty(dentry, &arg); + } + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +const struct file_operations aufs_dir_fop = { + .owner = THIS_MODULE, + .llseek = default_llseek, + .read = generic_read_dir, + .iterate = aufs_iterate, + .unlocked_ioctl = aufs_ioctl_dir, +#ifdef CONFIG_COMPAT + .compat_ioctl = aufs_compat_ioctl_dir, +#endif + .open = aufs_open_dir, + .release = aufs_release_dir, + .flush = aufs_flush_dir, + .fsync = aufs_fsync_dir +}; --- linux-3.13.0.orig/ubuntu/aufs/BOM +++ linux-3.13.0/ubuntu/aufs/BOM @@ -0,0 +1,3 @@ +URL: git://aufs.git.sourceforge.net/gitroot/aufs/aufs3-standalone.git +CHANGELOG: +COMMIT: 75dbb997b5812e16771bec20e92449ba0b1705d9 --- linux-3.13.0.orig/ubuntu/aufs/dbgaufs.c +++ linux-3.13.0/ubuntu/aufs/dbgaufs.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debugfs interface + */ + +#include +#include "aufs.h" + +#ifndef CONFIG_SYSFS +#error DEBUG_FS depends upon SYSFS +#endif + +static struct dentry *dbgaufs; +static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH; + +/* 20 is max digits length of ulong 64 */ +struct dbgaufs_arg { + int n; + char a[20 * 4]; +}; + +/* + * common function for all XINO files + */ +static int dbgaufs_xi_release(struct inode *inode __maybe_unused, + struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt) +{ + int err; + struct kstat st; + struct dbgaufs_arg *p; + + err = -ENOMEM; + p = kmalloc(sizeof(*p), GFP_NOFS); + if (unlikely(!p)) + goto out; + + err = 0; + p->n = 0; + file->private_data = p; + if (!xf) + goto out; + + err = vfs_getattr(&xf->f_path, &st); + if (!err) { + if (do_fcnt) + p->n = snprintf + (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n", + (long)file_count(xf), st.blocks, st.blksize, + (long long)st.size); + else + p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n", + st.blocks, st.blksize, + (long long)st.size); + AuDebugOn(p->n >= sizeof(p->a)); + } else { + p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); + err = 0; + } + +out: + return err; + +} + +static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dbgaufs_arg *p; + + p = file->private_data; + return simple_read_from_buffer(buf, count, ppos, p->a, p->n); +} + +/* ---------------------------------------------------------------------- */ + +struct dbgaufs_plink_arg { + int n; + char a[]; +}; + +static int dbgaufs_plink_release(struct inode *inode __maybe_unused, + struct file *file) +{ + free_page((unsigned long)file->private_data); + return 0; +} + +static int dbgaufs_plink_open(struct inode *inode, struct file *file) +{ + int err, i, limit; + unsigned long n, sum; + struct dbgaufs_plink_arg *p; + struct au_sbinfo *sbinfo; + struct super_block *sb; + struct au_sphlhead *sphl; + + err = -ENOMEM; + p = (void *)get_zeroed_page(GFP_NOFS); + if (unlikely(!p)) + goto out; + + err = -EFBIG; + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + if (au_opt_test(au_mntflags(sb), PLINK)) { + limit = PAGE_SIZE - sizeof(p->n); + + /* the number of buckets */ + n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); + p->n += n; + limit -= n; + + sum = 0; + for (i = 0, sphl = sbinfo->si_plink; + i < AuPlink_NHASH; + i++, sphl++) { + n = au_sphl_count(sphl); + sum += n; + + n = snprintf(p->a + p->n, limit, "%lu ", n); + p->n += n; + limit -= n; + if (unlikely(limit <= 0)) + goto out_free; + } + p->a[p->n - 1] = '\n'; + + /* the sum of plinks */ + n = snprintf(p->a + p->n, limit, "%lu\n", sum); + p->n += n; + limit -= n; + if (unlikely(limit <= 0)) + goto out_free; + } else { +#define str "1\n0\n0\n" + p->n = sizeof(str) - 1; + strcpy(p->a, str); +#undef str + } + si_read_unlock(sb); + + err = 0; + file->private_data = p; + goto out; /* success */ + +out_free: + free_page((unsigned long)p); +out: + return err; +} + +static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dbgaufs_plink_arg *p; + + p = file->private_data; + return simple_read_from_buffer(buf, count, ppos, p->a, p->n); +} + +static const struct file_operations dbgaufs_plink_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_plink_open, + .release = dbgaufs_plink_release, + .read = dbgaufs_plink_read +}; + +/* ---------------------------------------------------------------------- */ + +static int dbgaufs_xib_open(struct inode *inode, struct file *file) +{ + int err; + struct au_sbinfo *sbinfo; + struct super_block *sb; + + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0); + si_read_unlock(sb); + return err; +} + +static const struct file_operations dbgaufs_xib_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_xib_open, + .release = dbgaufs_xi_release, + .read = dbgaufs_xi_read +}; + +/* ---------------------------------------------------------------------- */ + +#define DbgaufsXi_PREFIX "xi" + +static int dbgaufs_xino_open(struct inode *inode, struct file *file) +{ + int err; + long l; + struct au_sbinfo *sbinfo; + struct super_block *sb; + struct file *xf; + struct qstr *name; + + err = -ENOENT; + xf = NULL; + name = &file->f_dentry->d_name; + if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) + || memcmp(name->name, DbgaufsXi_PREFIX, + sizeof(DbgaufsXi_PREFIX) - 1))) + goto out; + err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); + if (unlikely(err)) + goto out; + + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + if (l <= au_sbend(sb)) { + xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file; + err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1); + } else + err = -ENOENT; + si_read_unlock(sb); + +out: + return err; +} + +static const struct file_operations dbgaufs_xino_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_xino_open, + .release = dbgaufs_xi_release, + .read = dbgaufs_xi_read +}; + +void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +{ + aufs_bindex_t bend; + struct au_branch *br; + struct au_xino_file *xi; + + if (!au_sbi(sb)->si_dbgaufs) + return; + + bend = au_sbend(sb); + for (; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + xi = &br->br_xino; + debugfs_remove(xi->xi_dbgaufs); + xi->xi_dbgaufs = NULL; + } +} + +void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) +{ + struct au_sbinfo *sbinfo; + struct dentry *parent; + struct au_branch *br; + struct au_xino_file *xi; + aufs_bindex_t bend; + char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */ + + sbinfo = au_sbi(sb); + parent = sbinfo->si_dbgaufs; + if (!parent) + return; + + bend = au_sbend(sb); + for (; bindex <= bend; bindex++) { + snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); + br = au_sbr(sb, bindex); + xi = &br->br_xino; + AuDebugOn(xi->xi_dbgaufs); + xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, + sbinfo, &dbgaufs_xino_fop); + /* ignore an error */ + if (unlikely(!xi->xi_dbgaufs)) + AuWarn1("failed %s under debugfs\n", name); + } +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_EXPORT +static int dbgaufs_xigen_open(struct inode *inode, struct file *file) +{ + int err; + struct au_sbinfo *sbinfo; + struct super_block *sb; + + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0); + si_read_unlock(sb); + return err; +} + +static const struct file_operations dbgaufs_xigen_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_xigen_open, + .release = dbgaufs_xi_release, + .read = dbgaufs_xi_read +}; + +static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) +{ + int err; + + /* + * This function is a dynamic '__init' fucntion actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ + + err = -EIO; + sbinfo->si_dbgaufs_xigen = debugfs_create_file + ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, + &dbgaufs_xigen_fop); + if (sbinfo->si_dbgaufs_xigen) + err = 0; + + return err; +} +#else +static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) +{ + return 0; +} +#endif /* CONFIG_AUFS_EXPORT */ + +/* ---------------------------------------------------------------------- */ + +void dbgaufs_si_fin(struct au_sbinfo *sbinfo) +{ + /* + * This function is a dynamic '__init' fucntion actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ + + debugfs_remove_recursive(sbinfo->si_dbgaufs); + sbinfo->si_dbgaufs = NULL; + kobject_put(&sbinfo->si_kobj); +} + +int dbgaufs_si_init(struct au_sbinfo *sbinfo) +{ + int err; + char name[SysaufsSiNameLen]; + + /* + * This function is a dynamic '__init' fucntion actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ + + err = -ENOENT; + if (!dbgaufs) { + AuErr1("/debug/aufs is uninitialized\n"); + goto out; + } + + err = -EIO; + sysaufs_name(sbinfo, name); + sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); + if (unlikely(!sbinfo->si_dbgaufs)) + goto out; + kobject_get(&sbinfo->si_kobj); + + sbinfo->si_dbgaufs_xib = debugfs_create_file + ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, + &dbgaufs_xib_fop); + if (unlikely(!sbinfo->si_dbgaufs_xib)) + goto out_dir; + + sbinfo->si_dbgaufs_plink = debugfs_create_file + ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, + &dbgaufs_plink_fop); + if (unlikely(!sbinfo->si_dbgaufs_plink)) + goto out_dir; + + err = dbgaufs_xigen_init(sbinfo); + if (!err) + goto out; /* success */ + +out_dir: + dbgaufs_si_fin(sbinfo); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +void dbgaufs_fin(void) +{ + debugfs_remove(dbgaufs); +} + +int __init dbgaufs_init(void) +{ + int err; + + err = -EIO; + dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); + if (dbgaufs) + err = 0; + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/sysfs.c +++ linux-3.13.0/ubuntu/aufs/sysfs.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sysfs interface + */ + +#include +#include "aufs.h" + +#ifdef CONFIG_AUFS_FS_MODULE +/* this entry violates the "one line per file" policy of sysfs */ +static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + ssize_t err; + static char *conf = +/* this file is generated at compiling */ +#include "conf.str" + ; + + err = snprintf(buf, PAGE_SIZE, conf); + if (unlikely(err >= PAGE_SIZE)) + err = -EFBIG; + return err; +} + +static struct kobj_attribute au_config_attr = __ATTR_RO(config); +#endif + +static struct attribute *au_attr[] = { +#ifdef CONFIG_AUFS_FS_MODULE + &au_config_attr.attr, +#endif + NULL, /* need to NULL terminate the list of attributes */ +}; + +static struct attribute_group sysaufs_attr_group_body = { + .attrs = au_attr +}; + +struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; + +/* ---------------------------------------------------------------------- */ + +int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) +{ + int err; + + SiMustAnyLock(sb); + + err = 0; + if (au_opt_test(au_mntflags(sb), XINO)) { + err = au_xino_path(seq, au_sbi(sb)->si_xib); + seq_putc(seq, '\n'); + } + return err; +} + +/* + * the lifetime of branch is independent from the entry under sysfs. + * sysfs handles the lifetime of the entry, and never call ->show() after it is + * unlinked. + */ +static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, + aufs_bindex_t bindex, int idx) +{ + int err; + struct path path; + struct dentry *root; + struct au_branch *br; + char *perm; + + AuDbg("b%d\n", bindex); + + err = 0; + root = sb->s_root; + di_read_lock_parent(root, !AuLock_IR); + br = au_sbr(sb, bindex); + + switch (idx) { + case AuBrSysfs_BR: + path.mnt = au_br_mnt(br); + path.dentry = au_h_dptr(root, bindex); + au_seq_path(seq, &path); + di_read_unlock(root, !AuLock_IR); + perm = au_optstr_br_perm(br->br_perm); + if (perm) { + err = seq_printf(seq, "=%s\n", perm); + kfree(perm); + if (err == -1) + err = -E2BIG; + } else + err = -ENOMEM; + break; + case AuBrSysfs_BRID: + err = seq_printf(seq, "%d\n", br->br_id); + di_read_unlock(root, !AuLock_IR); + if (err == -1) + err = -E2BIG; + break; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct seq_file *au_seq(char *p, ssize_t len) +{ + struct seq_file *seq; + + seq = kzalloc(sizeof(*seq), GFP_NOFS); + if (seq) { + /* mutex_init(&seq.lock); */ + seq->buf = p; + seq->size = len; + return seq; /* success */ + } + + seq = ERR_PTR(-ENOMEM); + return seq; +} + +#define SysaufsBr_PREFIX "br" +#define SysaufsBrid_PREFIX "brid" + +/* todo: file size may exceed PAGE_SIZE */ +ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + ssize_t err; + int idx; + long l; + aufs_bindex_t bend; + struct au_sbinfo *sbinfo; + struct super_block *sb; + struct seq_file *seq; + char *name; + struct attribute **cattr; + + sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); + sb = sbinfo->si_sb; + + /* + * prevent a race condition between sysfs and aufs. + * for instance, sysfs_file_read() calls sysfs_get_active_two() which + * prohibits maintaining the sysfs entries. + * hew we acquire read lock after sysfs_get_active_two(). + * on the other hand, the remount process may maintain the sysfs/aufs + * entries after acquiring write lock. + * it can cause a deadlock. + * simply we gave up processing read here. + */ + err = -EBUSY; + if (unlikely(!si_noflush_read_trylock(sb))) + goto out; + + seq = au_seq(buf, PAGE_SIZE); + err = PTR_ERR(seq); + if (IS_ERR(seq)) + goto out_unlock; + + name = (void *)attr->name; + cattr = sysaufs_si_attrs; + while (*cattr) { + if (!strcmp(name, (*cattr)->name)) { + err = container_of(*cattr, struct sysaufs_si_attr, attr) + ->show(seq, sb); + goto out_seq; + } + cattr++; + } + + if (!strncmp(name, SysaufsBrid_PREFIX, + sizeof(SysaufsBrid_PREFIX) - 1)) { + idx = AuBrSysfs_BRID; + name += sizeof(SysaufsBrid_PREFIX) - 1; + } else if (!strncmp(name, SysaufsBr_PREFIX, + sizeof(SysaufsBr_PREFIX) - 1)) { + idx = AuBrSysfs_BR; + name += sizeof(SysaufsBr_PREFIX) - 1; + } else + BUG(); + + err = kstrtol(name, 10, &l); + if (!err) { + bend = au_sbend(sb); + if (l <= bend) + err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); + else + err = -ENOENT; + } + +out_seq: + if (!err) { + err = seq->count; + /* sysfs limit */ + if (unlikely(err == PAGE_SIZE)) + err = -EFBIG; + } + kfree(seq); +out_unlock: + si_read_unlock(sb); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +void sysaufs_br_init(struct au_branch *br) +{ + int i; + struct au_brsysfs *br_sysfs; + struct attribute *attr; + + br_sysfs = br->br_sysfs; + for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { + attr = &br_sysfs->attr; + sysfs_attr_init(attr); + attr->name = br_sysfs->name; + attr->mode = S_IRUGO; + br_sysfs++; + } +} + +void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +{ + struct au_branch *br; + struct kobject *kobj; + struct au_brsysfs *br_sysfs; + int i; + aufs_bindex_t bend; + + dbgaufs_brs_del(sb, bindex); + + if (!sysaufs_brs) + return; + + kobj = &au_sbi(sb)->si_kobj; + bend = au_sbend(sb); + for (; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + br_sysfs = br->br_sysfs; + for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { + sysfs_remove_file(kobj, &br_sysfs->attr); + br_sysfs++; + } + } +} + +void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) +{ + int err, i; + aufs_bindex_t bend; + struct kobject *kobj; + struct au_branch *br; + struct au_brsysfs *br_sysfs; + + dbgaufs_brs_add(sb, bindex); + + if (!sysaufs_brs) + return; + + kobj = &au_sbi(sb)->si_kobj; + bend = au_sbend(sb); + for (; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + br_sysfs = br->br_sysfs; + snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), + SysaufsBr_PREFIX "%d", bindex); + snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), + SysaufsBrid_PREFIX "%d", bindex); + for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { + err = sysfs_create_file(kobj, &br_sysfs->attr); + if (unlikely(err)) + pr_warn("failed %s under sysfs(%d)\n", + br_sysfs->name, err); + br_sysfs++; + } + } +} --- linux-3.13.0.orig/ubuntu/aufs/rwsem.h +++ linux-3.13.0/ubuntu/aufs/rwsem.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * simple read-write semaphore wrappers + */ + +#ifndef __AUFS_RWSEM_H__ +#define __AUFS_RWSEM_H__ + +#ifdef __KERNEL__ + +#include "debug.h" + +struct au_rwsem { + struct rw_semaphore rwsem; +#ifdef CONFIG_AUFS_DEBUG + /* just for debugging, not almighty counter */ + atomic_t rcnt, wcnt; +#endif +}; + +#ifdef CONFIG_AUFS_DEBUG +#define AuDbgCntInit(rw) do { \ + atomic_set(&(rw)->rcnt, 0); \ + atomic_set(&(rw)->wcnt, 0); \ + smp_mb(); /* atomic set */ \ +} while (0) + +#define AuDbgRcntInc(rw) atomic_inc(&(rw)->rcnt) +#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) +#define AuDbgWcntInc(rw) atomic_inc(&(rw)->wcnt) +#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0) +#else +#define AuDbgCntInit(rw) do {} while (0) +#define AuDbgRcntInc(rw) do {} while (0) +#define AuDbgRcntDec(rw) do {} while (0) +#define AuDbgWcntInc(rw) do {} while (0) +#define AuDbgWcntDec(rw) do {} while (0) +#endif /* CONFIG_AUFS_DEBUG */ + +/* to debug easier, do not make them inlined functions */ +#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list)) +/* rwsem_is_locked() is unusable */ +#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0) +#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0) +#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \ + && atomic_read(&(rw)->wcnt) <= 0) +#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \ + || atomic_read(&(rw)->wcnt)) + +#define au_rw_class(rw, key) lockdep_set_class(&(rw)->rwsem, key) + +static inline void au_rw_init(struct au_rwsem *rw) +{ + AuDbgCntInit(rw); + init_rwsem(&rw->rwsem); +} + +static inline void au_rw_init_wlock(struct au_rwsem *rw) +{ + au_rw_init(rw); + down_write(&rw->rwsem); + AuDbgWcntInc(rw); +} + +static inline void au_rw_init_wlock_nested(struct au_rwsem *rw, + unsigned int lsc) +{ + au_rw_init(rw); + down_write_nested(&rw->rwsem, lsc); + AuDbgWcntInc(rw); +} + +static inline void au_rw_read_lock(struct au_rwsem *rw) +{ + down_read(&rw->rwsem); + AuDbgRcntInc(rw); +} + +static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc) +{ + down_read_nested(&rw->rwsem, lsc); + AuDbgRcntInc(rw); +} + +static inline void au_rw_read_unlock(struct au_rwsem *rw) +{ + AuRwMustReadLock(rw); + AuDbgRcntDec(rw); + up_read(&rw->rwsem); +} + +static inline void au_rw_dgrade_lock(struct au_rwsem *rw) +{ + AuRwMustWriteLock(rw); + AuDbgRcntInc(rw); + AuDbgWcntDec(rw); + downgrade_write(&rw->rwsem); +} + +static inline void au_rw_write_lock(struct au_rwsem *rw) +{ + down_write(&rw->rwsem); + AuDbgWcntInc(rw); +} + +static inline void au_rw_write_lock_nested(struct au_rwsem *rw, + unsigned int lsc) +{ + down_write_nested(&rw->rwsem, lsc); + AuDbgWcntInc(rw); +} + +static inline void au_rw_write_unlock(struct au_rwsem *rw) +{ + AuRwMustWriteLock(rw); + AuDbgWcntDec(rw); + up_write(&rw->rwsem); +} + +/* why is not _nested version defined */ +static inline int au_rw_read_trylock(struct au_rwsem *rw) +{ + int ret = down_read_trylock(&rw->rwsem); + if (ret) + AuDbgRcntInc(rw); + return ret; +} + +static inline int au_rw_write_trylock(struct au_rwsem *rw) +{ + int ret = down_write_trylock(&rw->rwsem); + if (ret) + AuDbgWcntInc(rw); + return ret; +} + +#undef AuDbgCntInit +#undef AuDbgRcntInc +#undef AuDbgRcntDec +#undef AuDbgWcntInc +#undef AuDbgWcntDec + +#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ +static inline void prefix##_read_lock(param) \ +{ au_rw_read_lock(rwsem); } \ +static inline void prefix##_write_lock(param) \ +{ au_rw_write_lock(rwsem); } \ +static inline int prefix##_read_trylock(param) \ +{ return au_rw_read_trylock(rwsem); } \ +static inline int prefix##_write_trylock(param) \ +{ return au_rw_write_trylock(rwsem); } +/* why is not _nested version defined */ +/* static inline void prefix##_read_trylock_nested(param, lsc) +{ au_rw_read_trylock_nested(rwsem, lsc)); } +static inline void prefix##_write_trylock_nestd(param, lsc) +{ au_rw_write_trylock_nested(rwsem, lsc); } */ + +#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \ +static inline void prefix##_read_unlock(param) \ +{ au_rw_read_unlock(rwsem); } \ +static inline void prefix##_write_unlock(param) \ +{ au_rw_write_unlock(rwsem); } \ +static inline void prefix##_downgrade_lock(param) \ +{ au_rw_dgrade_lock(rwsem); } + +#define AuSimpleRwsemFuncs(prefix, param, rwsem) \ + AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ + AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) + +#endif /* __KERNEL__ */ +#endif /* __AUFS_RWSEM_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/f_op_sp.c +++ linux-3.13.0/ubuntu/aufs/f_op_sp.c @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * file operations for special files. + * while they exist in aufs virtually, + * their file I/O is handled out of aufs. + */ + +#include +#include "aufs.h" + +/* + * I don't think the size of this list grows much. + * so here is a very simple list implemented in order to find finfo matching a + * given file. + */ +static struct au_sphlhead au_finfo_sp = { + .spin = __SPIN_LOCK_INITIALIZER(au_finfo_sp.spin), + .head = HLIST_HEAD_INIT +}; + +struct au_finfo_sp { + struct hlist_node hlist; + struct file *file; + struct au_finfo *finfo; +}; + +struct au_finfo *au_fi_sp(struct file *file) +{ + struct au_finfo *finfo; + struct au_finfo_sp *sp; + + finfo = NULL; + spin_lock(&au_finfo_sp.spin); + hlist_for_each_entry(sp, &au_finfo_sp.head, hlist) { + if (sp->file != file) + continue; + finfo = sp->finfo; + break; + } + spin_unlock(&au_finfo_sp.spin); + + return finfo; +} + +static int au_fi_sp_add(struct file *file) +{ + int err; + struct au_finfo_sp *sp; + + err = -ENOMEM; + sp = kmalloc(sizeof(*sp), GFP_NOFS); + if (sp) { + err = 0; + sp->file = file; + sp->finfo = file->private_data; + spin_lock(&au_finfo_sp.spin); + hlist_add_head(&sp->hlist, &au_finfo_sp.head); + spin_unlock(&au_finfo_sp.spin); + } + return err; +} + +static void au_fi_sp_del(struct file *file) +{ + struct au_finfo_sp *sp, *do_free; + + do_free = NULL; + spin_lock(&au_finfo_sp.spin); + hlist_for_each_entry(sp, &au_finfo_sp.head, hlist) { + if (sp->file != file) + continue; + hlist_del(&sp->hlist); + do_free = sp; + break; + } + spin_unlock(&au_finfo_sp.spin); + kfree(do_free); +} + +/* ---------------------------------------------------------------------- */ + +static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov, + unsigned long nv, loff_t pos) +{ + ssize_t err; + aufs_bindex_t bstart; + unsigned char wbr; + struct file *file, *h_file; + struct super_block *sb; + + file = kio->ki_filp; + sb = file->f_dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + fi_read_lock(file); + bstart = au_fbstart(file); + h_file = au_hf_top(file); + fi_read_unlock(file); + wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); + si_read_unlock(sb); + + /* do not change the file in kio */ + AuDebugOn(!h_file->f_op || !h_file->f_op->aio_read); + err = h_file->f_op->aio_read(kio, iov, nv, pos); + if (err > 0 && wbr) + file_accessed(h_file); + + return err; +} + +static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov, + unsigned long nv, loff_t pos) +{ + ssize_t err; + aufs_bindex_t bstart; + unsigned char wbr; + struct super_block *sb; + struct file *file, *h_file; + + file = kio->ki_filp; + sb = file->f_dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + fi_read_lock(file); + bstart = au_fbstart(file); + h_file = au_hf_top(file); + fi_read_unlock(file); + wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); + si_read_unlock(sb); + + /* do not change the file in kio */ + AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write); + err = h_file->f_op->aio_write(kio, iov, nv, pos); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_release_sp(struct inode *inode, struct file *file) +{ + int err; + struct file *h_file; + + fi_read_lock(file); + h_file = au_hf_top(file); + fi_read_unlock(file); + /* close this fifo in aufs */ + err = h_file->f_op->release(inode, file); /* ignore */ + aufs_release_nondir(inode, file); /* ignore */ + au_fi_sp_del(file); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* currently, support only FIFO */ +enum { + AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW, + /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */ + AuSp_Last +}; +static int aufs_open_sp(struct inode *inode, struct file *file); +static struct au_sp_fop { + int done; + struct file_operations fop; /* not 'const' */ + spinlock_t spin; +} au_sp_fop[AuSp_Last] = { + [AuSp_FIFO] = { + .fop = { + .owner = THIS_MODULE, + .open = aufs_open_sp + } + } +}; + +static void au_init_fop_sp(struct file *file) +{ + struct au_sp_fop *p; + int i; + struct file *h_file; + + p = au_sp_fop; + if (unlikely(!p->done)) { + /* initialize first time only */ + static DEFINE_SPINLOCK(spin); + + spin_lock(&spin); + if (!p->done) { + BUILD_BUG_ON(sizeof(au_sp_fop)/sizeof(*au_sp_fop) + != AuSp_Last); + for (i = 0; i < AuSp_Last; i++) + spin_lock_init(&p[i].spin); + p->done = 1; + } + spin_unlock(&spin); + } + + switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) { + case FMODE_READ: + i = AuSp_FIFO_R; + break; + case FMODE_WRITE: + i = AuSp_FIFO_W; + break; + case FMODE_READ | FMODE_WRITE: + i = AuSp_FIFO_RW; + break; + default: + BUG(); + } + + p += i; + if (unlikely(!p->done)) { + /* initialize first time only */ + h_file = au_hf_top(file); + spin_lock(&p->spin); + if (!p->done) { + p->fop = *h_file->f_op; + p->fop.owner = THIS_MODULE; + if (p->fop.aio_read) + p->fop.aio_read = aufs_aio_read_sp; + if (p->fop.aio_write) + p->fop.aio_write = aufs_aio_write_sp; + p->fop.release = aufs_release_sp; + p->done = 1; + } + spin_unlock(&p->spin); + } + file->f_op = &p->fop; +} + +static int au_cpup_sp(struct dentry *dentry) +{ + int err; + struct au_pin pin; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = 0 + }; + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = -1, + .bsrc = -1, + .len = -1, + .pin = &pin, + .flags = AuCpup_DTIME + }; + + AuDbg("%pd\n", dentry); + + di_read_unlock(dentry, AuLock_IR); + di_write_lock_child(dentry); + err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); + if (unlikely(err < 0)) + goto out; + cpg.bdst = err; + err = 0; + if (cpg.bdst == au_dbstart(dentry)) + goto out; /* success */ + + err = au_pin(&pin, dentry, cpg.bdst, au_opt_udba(dentry->d_sb), + AuPin_MNT_WRITE); + if (!err) { + err = au_sio_cpup_simple(&cpg); + au_unpin(&pin); + } + +out: + di_downgrade_lock(dentry, AuLock_IR); + return err; +} + +static int au_do_open_sp(struct file *file, int flags) +{ + int err; + struct dentry *dentry; + struct super_block *sb; + struct file *h_file; + struct inode *h_inode; + + err = au_fi_sp_add(file); + if (unlikely(err)) + goto out; + + dentry = file->f_dentry; + AuDbg("%pd\n", dentry); + + /* + * try copying-up. + * operate on the ro branch is not an error. + */ + au_cpup_sp(dentry); /* ignore */ + + /* prepare h_file */ + err = au_do_open_nondir(file, vfsub_file_flags(file)); + if (unlikely(err)) + goto out_del; + + sb = dentry->d_sb; + h_file = au_hf_top(file); + h_inode = file_inode(h_file); + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + si_read_unlock(sb); + /* open this fifo in aufs */ + err = h_inode->i_fop->open(file_inode(file), file); + si_noflush_read_lock(sb); + fi_write_lock(file); + di_read_lock_child(dentry, AuLock_IR); + if (!err) { + au_init_fop_sp(file); + goto out; /* success */ + } + +out_del: + au_fi_sp_del(file); +out: + return err; +} + +static int aufs_open_sp(struct inode *inode, struct file *file) +{ + int err; + struct super_block *sb; + + sb = file->f_dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_do_open(file, au_do_open_sp, /*fidir*/NULL); + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev) +{ + init_special_inode(inode, mode, rdev); + + switch (mode & S_IFMT) { + case S_IFIFO: + inode->i_fop = &au_sp_fop[AuSp_FIFO].fop; + /*FALLTHROUGH*/ + case S_IFCHR: + case S_IFBLK: + case S_IFSOCK: + break; + default: + AuDebugOn(1); + } +} + +int au_special_file(umode_t mode) +{ + int ret; + + ret = 0; + switch (mode & S_IFMT) { + case S_IFIFO: +#if 0 + case S_IFCHR: + case S_IFBLK: + case S_IFSOCK: +#endif + ret = 1; + } + + return ret; +} --- linux-3.13.0.orig/ubuntu/aufs/dentry.h +++ linux-3.13.0/ubuntu/aufs/dentry.h @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * lookup and dentry operations + */ + +#ifndef __AUFS_DENTRY_H__ +#define __AUFS_DENTRY_H__ + +#ifdef __KERNEL__ + +#include +#include "rwsem.h" + +struct au_hdentry { + struct dentry *hd_dentry; + aufs_bindex_t hd_id; +}; + +struct au_dinfo { + atomic_t di_generation; + + struct au_rwsem di_rwsem; + aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; + struct au_hdentry *di_hdentry; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ + +/* dentry.c */ +extern const struct dentry_operations aufs_dop; +struct au_branch; +struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, + struct au_branch *br); +int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, + struct dentry *h_parent, struct au_branch *br); + +int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type); +int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); +int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); +int au_reval_dpath(struct dentry *dentry, unsigned int sigen); + +/* dinfo.c */ +void au_di_init_once(void *_di); +struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); +void au_di_free(struct au_dinfo *dinfo); +void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); +void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); +int au_di_init(struct dentry *dentry); +void au_di_fin(struct dentry *dentry); +int au_di_realloc(struct au_dinfo *dinfo, int nbr); + +void di_read_lock(struct dentry *d, int flags, unsigned int lsc); +void di_read_unlock(struct dentry *d, int flags); +void di_downgrade_lock(struct dentry *d, int flags); +void di_write_lock(struct dentry *d, unsigned int lsc); +void di_write_unlock(struct dentry *d); +void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); +void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); +void di_write_unlock2(struct dentry *d1, struct dentry *d2); + +struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); +struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); +aufs_bindex_t au_dbtail(struct dentry *dentry); +aufs_bindex_t au_dbtaildir(struct dentry *dentry); + +void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_dentry); +int au_digen_test(struct dentry *dentry, unsigned int sigen); +int au_dbrange_test(struct dentry *dentry); +void au_update_digen(struct dentry *dentry); +void au_update_dbrange(struct dentry *dentry, int do_put_zero); +void au_update_dbstart(struct dentry *dentry); +void au_update_dbend(struct dentry *dentry); +int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); + +/* ---------------------------------------------------------------------- */ + +static inline struct au_dinfo *au_di(struct dentry *dentry) +{ + return dentry->d_fsdata; +} + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for dinfo */ +enum { + AuLsc_DI_CHILD, /* child first */ + AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ + AuLsc_DI_CHILD3, /* copyup dirs */ + AuLsc_DI_PARENT, + AuLsc_DI_PARENT2, + AuLsc_DI_PARENT3, + AuLsc_DI_TMP /* temp for replacing dinfo */ +}; + +/* + * di_read_lock_child, di_write_lock_child, + * di_read_lock_child2, di_write_lock_child2, + * di_read_lock_child3, di_write_lock_child3, + * di_read_lock_parent, di_write_lock_parent, + * di_read_lock_parent2, di_write_lock_parent2, + * di_read_lock_parent3, di_write_lock_parent3, + */ +#define AuReadLockFunc(name, lsc) \ +static inline void di_read_lock_##name(struct dentry *d, int flags) \ +{ di_read_lock(d, flags, AuLsc_DI_##lsc); } + +#define AuWriteLockFunc(name, lsc) \ +static inline void di_write_lock_##name(struct dentry *d) \ +{ di_write_lock(d, AuLsc_DI_##lsc); } + +#define AuRWLockFuncs(name, lsc) \ + AuReadLockFunc(name, lsc) \ + AuWriteLockFunc(name, lsc) + +AuRWLockFuncs(child, CHILD); +AuRWLockFuncs(child2, CHILD2); +AuRWLockFuncs(child3, CHILD3); +AuRWLockFuncs(parent, PARENT); +AuRWLockFuncs(parent2, PARENT2); +AuRWLockFuncs(parent3, PARENT3); + +#undef AuReadLockFunc +#undef AuWriteLockFunc +#undef AuRWLockFuncs + +#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) +#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) +#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) + +/* ---------------------------------------------------------------------- */ + +/* todo: memory barrier? */ +static inline unsigned int au_digen(struct dentry *d) +{ + return atomic_read(&au_di(d)->di_generation); +} + +static inline void au_h_dentry_init(struct au_hdentry *hdentry) +{ + hdentry->hd_dentry = NULL; +} + +static inline void au_hdput(struct au_hdentry *hd) +{ + if (hd) + dput(hd->hd_dentry); +} + +static inline aufs_bindex_t au_dbstart(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bstart; +} + +static inline aufs_bindex_t au_dbend(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bend; +} + +static inline aufs_bindex_t au_dbwh(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bwh; +} + +static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bdiropq; +} + +/* todo: hard/soft set? */ +static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + au_di(dentry)->di_bstart = bindex; +} + +static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + au_di(dentry)->di_bend = bindex; +} + +static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + /* dbwh can be outside of bstart - bend range */ + au_di(dentry)->di_bwh = bindex; +} + +static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + au_di(dentry)->di_bdiropq = bindex; +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_HNOTIFY +static inline void au_digen_dec(struct dentry *d) +{ + atomic_dec(&au_di(d)->di_generation); +} + +static inline void au_hn_di_reinit(struct dentry *dentry) +{ + dentry->d_fsdata = NULL; +} +#else +AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) +#endif /* CONFIG_AUFS_HNOTIFY */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DENTRY_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/mvdown.c +++ linux-3.13.0/ubuntu/aufs/mvdown.c @@ -0,0 +1,627 @@ +/* + * Copyright (C) 2011-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * move-down, opposite of copy-up + */ + +#include "aufs.h" + +struct au_mvd_args { + struct { + struct super_block *h_sb; + struct dentry *h_parent; + struct au_hinode *hdir; + struct inode *h_dir, *h_inode; + } info[AUFS_MVDOWN_NARRAY]; + + struct aufs_mvdown mvdown; + struct dentry *dentry, *parent; + struct inode *inode, *dir; + struct super_block *sb; + aufs_bindex_t bopq, bwh, bfound; + unsigned char rename_lock; + struct au_pin pin; +}; + +#define mvd_errno mvdown.au_errno +#define mvd_bsrc mvdown.a[AUFS_MVDOWN_UPPER].bindex +#define mvd_src_brid mvdown.a[AUFS_MVDOWN_UPPER].brid +#define mvd_bdst mvdown.a[AUFS_MVDOWN_LOWER].bindex +#define mvd_dst_brid mvdown.a[AUFS_MVDOWN_LOWER].brid + +#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb +#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent +#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir +#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir +#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode + +#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb +#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent +#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir +#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir +#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode + +#define AU_MVD_PR(flag, ...) do { \ + if (flag) \ + pr_err(__VA_ARGS__); \ + } while (0) + +/* make the parent dir on bdst */ +static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + + err = 0; + a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); + a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); + a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); + a->mvd_h_dst_parent = NULL; + if (au_dbend(a->parent) >= a->mvd_bdst) + a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); + if (!a->mvd_h_dst_parent) { + err = au_cpdown_dirs(a->dentry, a->mvd_bdst); + if (unlikely(err)) { + AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); + goto out; + } + a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); + } + +out: + AuTraceErr(err); + return err; +} + +/* lock them all */ +static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct dentry *h_trap; + + a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); + a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); + if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { + a->rename_lock = 0; + err = au_pin(&a->pin, a->dentry, a->mvd_bdst, + au_opt_udba(a->sb), + AuPin_MNT_WRITE | AuPin_DI_LOCKED); + if (!err) { + a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode; + mutex_lock_nested(&a->mvd_h_src_dir->i_mutex, + AuLsc_I_PARENT3); + } else + AU_MVD_PR(dmsg, "pin failed\n"); + goto out; + } + + err = 0; + a->rename_lock = 1; + h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, + a->mvd_h_dst_parent, a->mvd_hdir_dst); + if (h_trap) { + err = (h_trap != a->mvd_h_src_parent); + if (err) + err = (h_trap != a->mvd_h_dst_parent); + } + BUG_ON(err); /* it should never happen */ + +out: + AuTraceErr(err); + return err; +} + +static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) +{ + if (!a->rename_lock) { + mutex_unlock(&a->mvd_h_src_dir->i_mutex); + au_unpin(&a->pin); + } else + vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, + a->mvd_h_dst_parent, a->mvd_hdir_dst); +} + +/* copy-down the file */ +static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct au_cp_generic cpg = { + .dentry = a->dentry, + .bdst = a->mvd_bdst, + .bsrc = a->mvd_bsrc, + .len = -1, + .pin = &a->pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + + AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); + if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) + au_fset_cpup(cpg.flags, OVERWRITE); + if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) + au_fset_cpup(cpg.flags, RWDST); + err = au_sio_cpdown_simple(&cpg); + if (unlikely(err)) + AU_MVD_PR(dmsg, "cpdown failed\n"); + + AuTraceErr(err); + return err; +} + +/* + * unlink the whiteout on bdst if exist which may be created by UDBA while we + * were sleeping + */ +static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct path h_path; + struct au_branch *br; + struct inode *delegated; + + br = au_sbr(a->sb, a->mvd_bdst); + h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) { + AU_MVD_PR(dmsg, "wh_lkup failed\n"); + goto out; + } + + err = 0; + if (h_path.dentry->d_inode) { + h_path.mnt = au_br_mnt(br); + delegated = NULL; + err = vfsub_unlink(a->mvd_h_dst_parent->d_inode, &h_path, + &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + if (unlikely(err)) + AU_MVD_PR(dmsg, "wh_unlink failed\n"); + } + dput(h_path.dentry); + +out: + AuTraceErr(err); + return err; +} + +/* + * unlink the topmost h_dentry + * Note: the target file MAY be modified by UDBA between this mutex_unlock() and + * mutex_lock() in vfs_unlink(). in this case, such changes may be lost. + */ +static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct path h_path; + struct inode *delegated; + + h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); + h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); + delegated = NULL; + err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + if (unlikely(err)) + AU_MVD_PR(dmsg, "unlink failed\n"); + + AuTraceErr(err); + return err; +} + +/* + * copy-down the file and unlink the bsrc file. + * - unlink the bdst whout if exist + * - copy-down the file (with whtmp name and rename) + * - unlink the bsrc file + */ +static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + + err = au_do_mkdir(dmsg, a); + if (!err) + err = au_do_lock(dmsg, a); + if (unlikely(err)) + goto out; + + /* + * do not revert the activities we made on bdst since they should be + * harmless in aufs. + */ + + err = au_do_cpdown(dmsg, a); + if (!err) + err = au_do_unlink_wh(dmsg, a); + if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) + err = au_do_unlink(dmsg, a); + if (unlikely(err)) + goto out_unlock; + + /* maintain internal array */ + if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { + au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); + au_set_dbstart(a->dentry, a->mvd_bdst); + au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); + au_set_ibstart(a->inode, a->mvd_bdst); + } + if (au_dbend(a->dentry) < a->mvd_bdst) + au_set_dbend(a->dentry, a->mvd_bdst); + if (au_ibend(a->inode) < a->mvd_bdst) + au_set_ibend(a->inode, a->mvd_bdst); + +out_unlock: + au_do_unlock(dmsg, a); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int find_lower_writable(struct au_mvd_args *a) +{ + struct super_block *sb; + aufs_bindex_t bindex, bend; + struct au_branch *br; + + sb = a->sb; + bindex = a->mvd_bsrc; + bend = au_sbend(sb); + if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) { + for (bindex++; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (!au_br_rdonly(br)) + return bindex; + } + } else { + for (bindex++; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (!(au_br_sb(br)->s_flags & MS_RDONLY)) { + if (au_br_rdonly(br)) + a->mvdown.flags + |= AUFS_MVDOWN_ROLOWER_R; + return bindex; + } + } + } + + return -1; +} + +/* make sure the file is idle */ +static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err, plinked; + + err = 0; + plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); + if (au_dbstart(a->dentry) == a->mvd_bsrc + && d_count(a->dentry) == 1 + && atomic_read(&a->inode->i_count) == 1 + /* && a->mvd_h_src_inode->i_nlink == 1 */ + && (!plinked || !au_plink_test(a->inode)) + && a->inode->i_nlink == 1) + goto out; + + err = -EBUSY; + AU_MVD_PR(dmsg, + "b%d, d{b%d, c%u?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", + a->mvd_bsrc, au_dbstart(a->dentry), d_count(a->dentry), + atomic_read(&a->inode->i_count), a->inode->i_nlink, + a->mvd_h_src_inode->i_nlink, + plinked, plinked ? au_plink_test(a->inode) : 0); + +out: + AuTraceErr(err); + return err; +} + +/* make sure the parent dir is fine */ +static int au_mvd_args_parent(const unsigned char dmsg, + struct au_mvd_args *a) +{ + int err; + aufs_bindex_t bindex; + + err = 0; + if (unlikely(au_alive_dir(a->parent))) { + err = -ENOENT; + AU_MVD_PR(dmsg, "parent dir is dead\n"); + goto out; + } + + a->bopq = au_dbdiropq(a->parent); + bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); + AuDbg("b%d\n", bindex); + if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) + || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { + err = -EINVAL; + a->mvd_errno = EAU_MVDOWN_OPAQUE; + AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", + a->bopq, a->mvd_bdst); + } + +out: + AuTraceErr(err); + return err; +} + +static int au_mvd_args_intermediate(const unsigned char dmsg, + struct au_mvd_args *a) +{ + int err; + struct au_dinfo *dinfo, *tmp; + + /* lookup the next lower positive entry */ + err = -ENOMEM; + tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); + if (unlikely(!tmp)) + goto out; + + a->bfound = -1; + a->bwh = -1; + dinfo = au_di(a->dentry); + au_di_cp(tmp, dinfo); + au_di_swap(tmp, dinfo); + + /* returns the number of positive dentries */ + err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, /*type*/0); + if (!err) + a->bwh = au_dbwh(a->dentry); + else if (err > 0) + a->bfound = au_dbstart(a->dentry); + + au_di_swap(tmp, dinfo); + au_rw_write_unlock(&tmp->di_rwsem); + au_di_free(tmp); + if (unlikely(err < 0)) + AU_MVD_PR(dmsg, "failed look-up lower\n"); + + /* + * here, we have these cases. + * bfound == -1 + * no positive dentry under bsrc. there are more sub-cases. + * bwh < 0 + * there no whiteout, we can safely move-down. + * bwh <= bsrc + * impossible + * bsrc < bwh && bwh < bdst + * there is a whiteout on RO branch. cannot proceed. + * bwh == bdst + * there is a whiteout on the RW target branch. it should + * be removed. + * bdst < bwh + * there is a whiteout somewhere unrelated branch. + * -1 < bfound && bfound <= bsrc + * impossible. + * bfound < bdst + * found, but it is on RO branch between bsrc and bdst. cannot + * proceed. + * bfound == bdst + * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return + * error. + * bdst < bfound + * found, after we create the file on bdst, it will be hidden. + */ + + AuDebugOn(a->bfound == -1 + && a->bwh != -1 + && a->bwh <= a->mvd_bsrc); + AuDebugOn(-1 < a->bfound + && a->bfound <= a->mvd_bsrc); + + err = -EINVAL; + if (a->bfound == -1 + && a->mvd_bsrc < a->bwh + && a->bwh != -1 + && a->bwh < a->mvd_bdst) { + a->mvd_errno = EAU_MVDOWN_WHITEOUT; + AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", + a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); + goto out; + } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { + a->mvd_errno = EAU_MVDOWN_UPPER; + AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", + a->mvd_bdst, a->bfound); + goto out; + } + + err = 0; /* success */ + +out: + AuTraceErr(err); + return err; +} + +static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + + err = 0; + if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) + && a->bfound == a->mvd_bdst) + err = -EEXIST; + AuTraceErr(err); + return err; +} + +static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct au_branch *br; + + err = -EISDIR; + if (unlikely(S_ISDIR(a->inode->i_mode))) + goto out; + + err = -EINVAL; + if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) + a->mvd_bsrc = au_ibstart(a->inode); + else { + a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); + if (unlikely(a->mvd_bsrc < 0 + || (a->mvd_bsrc < au_dbstart(a->dentry) + || au_dbend(a->dentry) < a->mvd_bsrc + || !au_h_dptr(a->dentry, a->mvd_bsrc)) + || (a->mvd_bsrc < au_ibstart(a->inode) + || au_ibend(a->inode) < a->mvd_bsrc + || !au_h_iptr(a->inode, a->mvd_bsrc)))) { + a->mvd_errno = EAU_MVDOWN_NOUPPER; + AU_MVD_PR(dmsg, "no upper\n"); + goto out; + } + } + if (unlikely(a->mvd_bsrc == au_sbend(a->sb))) { + a->mvd_errno = EAU_MVDOWN_BOTTOM; + AU_MVD_PR(dmsg, "on the bottom\n"); + goto out; + } + a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); + br = au_sbr(a->sb, a->mvd_bsrc); + err = au_br_rdonly(br); + if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { + if (unlikely(err)) + goto out; + } else if (!(vfsub_native_ro(a->mvd_h_src_inode) + || IS_APPEND(a->mvd_h_src_inode))) { + if (err) + a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; + /* go on */ + } else + goto out; + + err = -EINVAL; + if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { + a->mvd_bdst = find_lower_writable(a); + if (unlikely(a->mvd_bdst < 0)) { + a->mvd_errno = EAU_MVDOWN_BOTTOM; + AU_MVD_PR(dmsg, "no writable lower branch\n"); + goto out; + } + } else { + a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); + if (unlikely(a->mvd_bdst < 0 + || au_sbend(a->sb) < a->mvd_bdst)) { + a->mvd_errno = EAU_MVDOWN_NOLOWERBR; + AU_MVD_PR(dmsg, "no lower brid\n"); + goto out; + } + } + + err = au_mvd_args_busy(dmsg, a); + if (!err) + err = au_mvd_args_parent(dmsg, a); + if (!err) + err = au_mvd_args_intermediate(dmsg, a); + if (!err) + err = au_mvd_args_exist(dmsg, a); + if (!err) + AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); + +out: + AuTraceErr(err); + return err; +} + +int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) +{ + int err, e; + unsigned char dmsg; + struct au_mvd_args *args; + + err = -EPERM; + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + + WARN_ONCE(1, "move-down is still testing...\n"); + + err = -ENOMEM; + args = kmalloc(sizeof(*args), GFP_NOFS); + if (unlikely(!args)) + goto out; + + err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); + if (!err) + err = !access_ok(VERIFY_WRITE, uarg, sizeof(*uarg)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out_free; + } + AuDbg("flags 0x%x\n", args->mvdown.flags); + args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); + args->mvdown.au_errno = 0; + args->dentry = dentry; + args->inode = dentry->d_inode; + args->sb = dentry->d_sb; + + err = -ENOENT; + dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); + args->parent = dget_parent(dentry); + args->dir = args->parent->d_inode; + mutex_lock_nested(&args->dir->i_mutex, I_MUTEX_PARENT); + dput(args->parent); + if (unlikely(args->parent != dentry->d_parent)) { + AU_MVD_PR(dmsg, "parent dir is moved\n"); + goto out_dir; + } + + mutex_lock_nested(&args->inode->i_mutex, I_MUTEX_CHILD); + err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH); + if (unlikely(err)) + goto out_inode; + + di_write_lock_parent(args->parent); + err = au_mvd_args(dmsg, args); + if (unlikely(err)) + goto out_parent; + + AuDbgDentry(dentry); + AuDbgInode(args->inode); + err = au_do_mvdown(dmsg, args); + if (unlikely(err)) + goto out_parent; + AuDbgDentry(dentry); + AuDbgInode(args->inode); + + au_cpup_attr_timesizes(args->dir); + au_cpup_attr_timesizes(args->inode); + au_cpup_igen(args->inode, au_h_iptr(args->inode, args->mvd_bdst)); + /* au_digen_dec(dentry); */ + +out_parent: + di_write_unlock(args->parent); + aufs_read_unlock(dentry, AuLock_DW); +out_inode: + mutex_unlock(&args->inode->i_mutex); +out_dir: + mutex_unlock(&args->dir->i_mutex); +out_free: + e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); + if (unlikely(e)) + err = -EFAULT; + kfree(args); +out: + AuTraceErr(err); + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/sysaufs.h +++ linux-3.13.0/ubuntu/aufs/sysaufs.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sysfs interface and mount lifetime management + */ + +#ifndef __SYSAUFS_H__ +#define __SYSAUFS_H__ + +#ifdef __KERNEL__ + +#include +#include "module.h" + +struct super_block; +struct au_sbinfo; + +struct sysaufs_si_attr { + struct attribute attr; + int (*show)(struct seq_file *seq, struct super_block *sb); +}; + +/* ---------------------------------------------------------------------- */ + +/* sysaufs.c */ +extern unsigned long sysaufs_si_mask; +extern struct kset *sysaufs_kset; +extern struct attribute *sysaufs_si_attrs[]; +int sysaufs_si_init(struct au_sbinfo *sbinfo); +int __init sysaufs_init(void); +void sysaufs_fin(void); + +/* ---------------------------------------------------------------------- */ + +/* some people doesn't like to show a pointer in kernel */ +static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) +{ + return sysaufs_si_mask ^ (unsigned long)sbinfo; +} + +#define SysaufsSiNamePrefix "si_" +#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) +static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) +{ + snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", + sysaufs_si_id(sbinfo)); +} + +struct au_branch; +#ifdef CONFIG_SYSFS +/* sysfs.c */ +extern struct attribute_group *sysaufs_attr_group; + +int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); +ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, + char *buf); + +void sysaufs_br_init(struct au_branch *br); +void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); +void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); + +#define sysaufs_brs_init() do {} while (0) + +#else +#define sysaufs_attr_group NULL + +AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) + +static inline +ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return 0; +} + +AuStubVoid(sysaufs_br_init, struct au_branch *br) +AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) +AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) + +static inline void sysaufs_brs_init(void) +{ + sysaufs_brs = 0; +} + +#endif /* CONFIG_SYSFS */ + +#endif /* __KERNEL__ */ +#endif /* __SYSAUFS_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/sysaufs.c +++ linux-3.13.0/ubuntu/aufs/sysaufs.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sysfs interface and lifetime management + * they are necessary regardless sysfs is disabled. + */ + +#include +#include "aufs.h" + +unsigned long sysaufs_si_mask; +struct kset *sysaufs_kset; + +#define AuSiAttr(_name) { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = sysaufs_si_##_name, \ +} + +static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); +struct attribute *sysaufs_si_attrs[] = { + &sysaufs_si_attr_xi_path.attr, + NULL, +}; + +static const struct sysfs_ops au_sbi_ops = { + .show = sysaufs_si_show +}; + +static struct kobj_type au_sbi_ktype = { + .release = au_si_free, + .sysfs_ops = &au_sbi_ops, + .default_attrs = sysaufs_si_attrs +}; + +/* ---------------------------------------------------------------------- */ + +int sysaufs_si_init(struct au_sbinfo *sbinfo) +{ + int err; + + sbinfo->si_kobj.kset = sysaufs_kset; + /* cf. sysaufs_name() */ + err = kobject_init_and_add + (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, + SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); + + dbgaufs_si_null(sbinfo); + if (!err) { + err = dbgaufs_si_init(sbinfo); + if (unlikely(err)) + kobject_put(&sbinfo->si_kobj); + } + return err; +} + +void sysaufs_fin(void) +{ + dbgaufs_fin(); + sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); + kset_unregister(sysaufs_kset); +} + +int __init sysaufs_init(void) +{ + int err; + + do { + get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); + } while (!sysaufs_si_mask); + + err = -EINVAL; + sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); + if (unlikely(!sysaufs_kset)) + goto out; + err = PTR_ERR(sysaufs_kset); + if (IS_ERR(sysaufs_kset)) + goto out; + err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); + if (unlikely(err)) { + kset_unregister(sysaufs_kset); + goto out; + } + + err = dbgaufs_init(); + if (unlikely(err)) + sysaufs_fin(); +out: + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/i_op_ren.c +++ linux-3.13.0/ubuntu/aufs/i_op_ren.c @@ -0,0 +1,1032 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operation (rename entry) + * todo: this is crazy monster + */ + +#include "aufs.h" + +enum { AuSRC, AuDST, AuSrcDst }; +enum { AuPARENT, AuCHILD, AuParentChild }; + +#define AuRen_ISDIR 1 +#define AuRen_ISSAMEDIR (1 << 1) +#define AuRen_WHSRC (1 << 2) +#define AuRen_WHDST (1 << 3) +#define AuRen_MNT_WRITE (1 << 4) +#define AuRen_DT_DSTDIR (1 << 5) +#define AuRen_DIROPQ (1 << 6) +#define AuRen_CPUP (1 << 7) +#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) +#define au_fset_ren(flags, name) \ + do { (flags) |= AuRen_##name; } while (0) +#define au_fclr_ren(flags, name) \ + do { (flags) &= ~AuRen_##name; } while (0) + +struct au_ren_args { + struct { + struct dentry *dentry, *h_dentry, *parent, *h_parent, + *wh_dentry; + struct inode *dir, *inode; + struct au_hinode *hdir; + struct au_dtime dt[AuParentChild]; + aufs_bindex_t bstart; + } sd[AuSrcDst]; + +#define src_dentry sd[AuSRC].dentry +#define src_dir sd[AuSRC].dir +#define src_inode sd[AuSRC].inode +#define src_h_dentry sd[AuSRC].h_dentry +#define src_parent sd[AuSRC].parent +#define src_h_parent sd[AuSRC].h_parent +#define src_wh_dentry sd[AuSRC].wh_dentry +#define src_hdir sd[AuSRC].hdir +#define src_h_dir sd[AuSRC].hdir->hi_inode +#define src_dt sd[AuSRC].dt +#define src_bstart sd[AuSRC].bstart + +#define dst_dentry sd[AuDST].dentry +#define dst_dir sd[AuDST].dir +#define dst_inode sd[AuDST].inode +#define dst_h_dentry sd[AuDST].h_dentry +#define dst_parent sd[AuDST].parent +#define dst_h_parent sd[AuDST].h_parent +#define dst_wh_dentry sd[AuDST].wh_dentry +#define dst_hdir sd[AuDST].hdir +#define dst_h_dir sd[AuDST].hdir->hi_inode +#define dst_dt sd[AuDST].dt +#define dst_bstart sd[AuDST].bstart + + struct dentry *h_trap; + struct au_branch *br; + struct au_hinode *src_hinode; + struct path h_path; + struct au_nhash whlist; + aufs_bindex_t btgt, src_bwh, src_bdiropq; + + unsigned int flags; + + struct au_whtmp_rmdir *thargs; + struct dentry *h_dst; +}; + +/* ---------------------------------------------------------------------- */ + +/* + * functions for reverting. + * when an error happened in a single rename systemcall, we should revert + * everything as if nothing happend. + * we don't need to revert the copied-up/down the parent dir since they are + * harmless. + */ + +#define RevertFailure(fmt, ...) do { \ + AuIOErr("revert failure: " fmt " (%d, %d)\n", \ + ##__VA_ARGS__, err, rerr); \ + err = -EIO; \ +} while (0) + +static void au_ren_rev_diropq(int err, struct au_ren_args *a) +{ + int rerr; + + au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); + rerr = au_diropq_remove(a->src_dentry, a->btgt); + au_hn_imtx_unlock(a->src_hinode); + au_set_dbdiropq(a->src_dentry, a->src_bdiropq); + if (rerr) + RevertFailure("remove diropq %pd", a->src_dentry); +} + +static void au_ren_rev_rename(int err, struct au_ren_args *a) +{ + int rerr; + struct inode *delegated; + + a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, + a->src_h_parent); + rerr = PTR_ERR(a->h_path.dentry); + if (IS_ERR(a->h_path.dentry)) { + RevertFailure("lkup one %pd", a->src_dentry); + return; + } + + delegated = NULL; + rerr = vfsub_rename(a->dst_h_dir, + au_h_dptr(a->src_dentry, a->btgt), + a->src_h_dir, &a->h_path, &delegated); + if (unlikely(rerr == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + d_drop(a->h_path.dentry); + dput(a->h_path.dentry); + /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ + if (rerr) + RevertFailure("rename %pd", a->src_dentry); +} + +static void au_ren_rev_cpup(int err, struct au_ren_args *a) +{ + int rerr; + + a->h_path.dentry = a->dst_h_dentry; + /* no delegation since it is just created */ + rerr = vfsub_unlink(a->dst_h_dir, &a->h_path, /*delegated*/NULL, + /*force*/0); + au_set_h_dptr(a->src_dentry, a->btgt, NULL); + au_set_dbstart(a->src_dentry, a->src_bstart); + if (rerr) + RevertFailure("unlink %pd", a->dst_h_dentry); +} + +static void au_ren_rev_whtmp(int err, struct au_ren_args *a) +{ + int rerr; + struct inode *delegated; + + a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, + a->dst_h_parent); + rerr = PTR_ERR(a->h_path.dentry); + if (IS_ERR(a->h_path.dentry)) { + RevertFailure("lkup one %pd", a->dst_dentry); + return; + } + if (a->h_path.dentry->d_inode) { + d_drop(a->h_path.dentry); + dput(a->h_path.dentry); + return; + } + + delegated = NULL; + rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, + &delegated); + if (unlikely(rerr == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + d_drop(a->h_path.dentry); + dput(a->h_path.dentry); + if (!rerr) + au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); + else + RevertFailure("rename %pd", a->h_dst); +} + +static void au_ren_rev_whsrc(int err, struct au_ren_args *a) +{ + int rerr; + + a->h_path.dentry = a->src_wh_dentry; + rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); + au_set_dbwh(a->src_dentry, a->src_bwh); + if (rerr) + RevertFailure("unlink %pd", a->src_wh_dentry); +} +#undef RevertFailure + +/* ---------------------------------------------------------------------- */ + +/* + * when we have to copyup the renaming entry, do it with the rename-target name + * in order to minimize the cost (the later actual rename is unnecessary). + * otherwise rename it on the target branch. + */ +static int au_ren_or_cpup(struct au_ren_args *a) +{ + int err; + struct dentry *d; + struct inode *delegated; + + d = a->src_dentry; + if (au_dbstart(d) == a->btgt) { + a->h_path.dentry = a->dst_h_dentry; + if (au_ftest_ren(a->flags, DIROPQ) + && au_dbdiropq(d) == a->btgt) + au_fclr_ren(a->flags, DIROPQ); + AuDebugOn(au_dbstart(d) != a->btgt); + delegated = NULL; + err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), + a->dst_h_dir, &a->h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + } else + BUG(); + + if (!err && a->h_dst) + /* it will be set to dinfo later */ + dget(a->h_dst); + + return err; +} + +/* cf. aufs_rmdir() */ +static int au_ren_del_whtmp(struct au_ren_args *a) +{ + int err; + struct inode *dir; + + dir = a->dst_dir; + SiMustAnyLock(dir->i_sb); + if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, + au_sbi(dir->i_sb)->si_dirwh) + || au_test_fs_remote(a->h_dst->d_sb)) { + err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); + if (unlikely(err)) + pr_warn("failed removing whtmp dir %pd (%d), " + "ignored.\n", a->h_dst, err); + } else { + au_nhash_wh_free(&a->thargs->whlist); + a->thargs->whlist = a->whlist; + a->whlist.nh_num = 0; + au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); + dput(a->h_dst); + a->thargs = NULL; + } + + return 0; +} + +/* make it 'opaque' dir. */ +static int au_ren_diropq(struct au_ren_args *a) +{ + int err; + struct dentry *diropq; + + err = 0; + a->src_bdiropq = au_dbdiropq(a->src_dentry); + a->src_hinode = au_hi(a->src_inode, a->btgt); + au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); + diropq = au_diropq_create(a->src_dentry, a->btgt); + au_hn_imtx_unlock(a->src_hinode); + if (IS_ERR(diropq)) + err = PTR_ERR(diropq); + dput(diropq); + + return err; +} + +static int do_rename(struct au_ren_args *a) +{ + int err; + struct dentry *d, *h_d; + + /* prepare workqueue args for asynchronous rmdir */ + h_d = a->dst_h_dentry; + if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) { + err = -ENOMEM; + a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS); + if (unlikely(!a->thargs)) + goto out; + a->h_dst = dget(h_d); + } + + /* create whiteout for src_dentry */ + if (au_ftest_ren(a->flags, WHSRC)) { + a->src_bwh = au_dbwh(a->src_dentry); + AuDebugOn(a->src_bwh >= 0); + a->src_wh_dentry + = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent); + err = PTR_ERR(a->src_wh_dentry); + if (IS_ERR(a->src_wh_dentry)) + goto out_thargs; + } + + /* lookup whiteout for dentry */ + if (au_ftest_ren(a->flags, WHDST)) { + h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name, + a->br); + err = PTR_ERR(h_d); + if (IS_ERR(h_d)) + goto out_whsrc; + if (!h_d->d_inode) + dput(h_d); + else + a->dst_wh_dentry = h_d; + } + + /* rename dentry to tmpwh */ + if (a->thargs) { + err = au_whtmp_ren(a->dst_h_dentry, a->br); + if (unlikely(err)) + goto out_whdst; + + d = a->dst_dentry; + au_set_h_dptr(d, a->btgt, NULL); + err = au_lkup_neg(d, a->btgt, /*wh*/0); + if (unlikely(err)) + goto out_whtmp; + a->dst_h_dentry = au_h_dptr(d, a->btgt); + } + + BUG_ON(a->dst_h_dentry->d_inode && a->src_bstart != a->btgt); + + /* rename by vfs_rename or cpup */ + d = a->dst_dentry; + if (au_ftest_ren(a->flags, ISDIR) + && (a->dst_wh_dentry + || au_dbdiropq(d) == a->btgt + /* hide the lower to keep xino */ + || a->btgt < au_dbend(d) + || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ))) + au_fset_ren(a->flags, DIROPQ); + err = au_ren_or_cpup(a); + if (unlikely(err)) + /* leave the copied-up one */ + goto out_whtmp; + + /* make dir opaque */ + if (au_ftest_ren(a->flags, DIROPQ)) { + err = au_ren_diropq(a); + if (unlikely(err)) + goto out_rename; + } + + /* update target timestamps */ + AuDebugOn(au_dbstart(a->src_dentry) != a->btgt); + a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); + vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ + a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime; + + /* remove whiteout for dentry */ + if (a->dst_wh_dentry) { + a->h_path.dentry = a->dst_wh_dentry; + err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, + a->dst_dentry); + if (unlikely(err)) + goto out_diropq; + } + + /* remove whtmp */ + if (a->thargs) + au_ren_del_whtmp(a); /* ignore this error */ + + err = 0; + goto out_success; + +out_diropq: + if (au_ftest_ren(a->flags, DIROPQ)) + au_ren_rev_diropq(err, a); +out_rename: + if (!au_ftest_ren(a->flags, CPUP)) + au_ren_rev_rename(err, a); + else + au_ren_rev_cpup(err, a); + dput(a->h_dst); +out_whtmp: + if (a->thargs) + au_ren_rev_whtmp(err, a); +out_whdst: + dput(a->dst_wh_dentry); + a->dst_wh_dentry = NULL; +out_whsrc: + if (a->src_wh_dentry) + au_ren_rev_whsrc(err, a); +out_success: + dput(a->src_wh_dentry); + dput(a->dst_wh_dentry); +out_thargs: + if (a->thargs) { + dput(a->h_dst); + au_whtmp_rmdir_free(a->thargs); + a->thargs = NULL; + } +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * test if @dentry dir can be rename destination or not. + * success means, it is a logically empty dir. + */ +static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) +{ + return au_test_empty(dentry, whlist); +} + +/* + * test if @dentry dir can be rename source or not. + * if it can, return 0 and @children is filled. + * success means, + * - it is a logically empty dir. + * - or, it exists on writable branch and has no children including whiteouts + * on the lower branch. + */ +static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) +{ + int err; + unsigned int rdhash; + aufs_bindex_t bstart; + + bstart = au_dbstart(dentry); + if (bstart != btgt) { + struct au_nhash whlist; + + SiMustAnyLock(dentry->d_sb); + rdhash = au_sbi(dentry->d_sb)->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, + dentry)); + err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_test_empty(dentry, &whlist); + au_nhash_wh_free(&whlist); + goto out; + } + + if (bstart == au_dbtaildir(dentry)) + return 0; /* success */ + + err = au_test_empty_lower(dentry); + +out: + if (err == -ENOTEMPTY) { + AuWarn1("renaming dir who has child(ren) on multiple branches," + " is not supported\n"); + err = -EXDEV; + } + return err; +} + +/* side effect: sets whlist and h_dentry */ +static int au_ren_may_dir(struct au_ren_args *a) +{ + int err; + unsigned int rdhash; + struct dentry *d; + + d = a->dst_dentry; + SiMustAnyLock(d->d_sb); + + err = 0; + if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) { + rdhash = au_sbi(d->d_sb)->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); + err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + + au_set_dbstart(d, a->dst_bstart); + err = may_rename_dstdir(d, &a->whlist); + au_set_dbstart(d, a->btgt); + } + a->dst_h_dentry = au_h_dptr(d, au_dbstart(d)); + if (unlikely(err)) + goto out; + + d = a->src_dentry; + a->src_h_dentry = au_h_dptr(d, au_dbstart(d)); + if (au_ftest_ren(a->flags, ISDIR)) { + err = may_rename_srcdir(d, a->btgt); + if (unlikely(err)) { + au_nhash_wh_free(&a->whlist); + a->whlist.nh_num = 0; + } + } +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * simple tests for rename. + * following the checks in vfs, plus the parent-child relationship. + */ +static int au_may_ren(struct au_ren_args *a) +{ + int err, isdir; + struct inode *h_inode; + + if (a->src_bstart == a->btgt) { + err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, + au_ftest_ren(a->flags, ISDIR)); + if (unlikely(err)) + goto out; + err = -EINVAL; + if (unlikely(a->src_h_dentry == a->h_trap)) + goto out; + } + + err = 0; + if (a->dst_bstart != a->btgt) + goto out; + + err = -ENOTEMPTY; + if (unlikely(a->dst_h_dentry == a->h_trap)) + goto out; + + err = -EIO; + h_inode = a->dst_h_dentry->d_inode; + isdir = !!au_ftest_ren(a->flags, ISDIR); + if (!a->dst_dentry->d_inode) { + if (unlikely(h_inode)) + goto out; + err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent, + isdir); + } else { + if (unlikely(!h_inode || !h_inode->i_nlink)) + goto out; + err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent, + isdir); + if (unlikely(err)) + goto out; + } + +out: + if (unlikely(err == -ENOENT || err == -EEXIST)) + err = -EIO; + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * locking order + * (VFS) + * - src_dir and dir by lock_rename() + * - inode if exitsts + * (aufs) + * - lock all + * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, + * + si_read_lock + * + di_write_lock2_child() + * + di_write_lock_child() + * + ii_write_lock_child() + * + di_write_lock_child2() + * + ii_write_lock_child2() + * + src_parent and parent + * + di_write_lock_parent() + * + ii_write_lock_parent() + * + di_write_lock_parent2() + * + ii_write_lock_parent2() + * + lower src_dir and dir by vfsub_lock_rename() + * + verify the every relationships between child and parent. if any + * of them failed, unlock all and return -EBUSY. + */ +static void au_ren_unlock(struct au_ren_args *a) +{ + vfsub_unlock_rename(a->src_h_parent, a->src_hdir, + a->dst_h_parent, a->dst_hdir); + if (au_ftest_ren(a->flags, MNT_WRITE)) + vfsub_mnt_drop_write(au_br_mnt(a->br)); +} + +static int au_ren_lock(struct au_ren_args *a) +{ + int err; + unsigned int udba; + + err = 0; + a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); + a->src_hdir = au_hi(a->src_dir, a->btgt); + a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); + a->dst_hdir = au_hi(a->dst_dir, a->btgt); + + err = vfsub_mnt_want_write(au_br_mnt(a->br)); + if (unlikely(err)) + goto out; + au_fset_ren(a->flags, MNT_WRITE); + a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, + a->dst_h_parent, a->dst_hdir); + udba = au_opt_udba(a->src_dentry->d_sb); + if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode + || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode)) + err = au_busy_or_stale(); + if (!err && au_dbstart(a->src_dentry) == a->btgt) + err = au_h_verify(a->src_h_dentry, udba, + a->src_h_parent->d_inode, a->src_h_parent, + a->br); + if (!err && au_dbstart(a->dst_dentry) == a->btgt) + err = au_h_verify(a->dst_h_dentry, udba, + a->dst_h_parent->d_inode, a->dst_h_parent, + a->br); + if (!err) + goto out; /* success */ + + err = au_busy_or_stale(); + au_ren_unlock(a); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void au_ren_refresh_dir(struct au_ren_args *a) +{ + struct inode *dir; + + dir = a->dst_dir; + dir->i_version++; + if (au_ftest_ren(a->flags, ISDIR)) { + /* is this updating defined in POSIX? */ + au_cpup_attr_timesizes(a->src_inode); + au_cpup_attr_nlink(dir, /*force*/1); + } + + if (au_ibstart(dir) == a->btgt) + au_cpup_attr_timesizes(dir); + + if (au_ftest_ren(a->flags, ISSAMEDIR)) + return; + + dir = a->src_dir; + dir->i_version++; + if (au_ftest_ren(a->flags, ISDIR)) + au_cpup_attr_nlink(dir, /*force*/1); + if (au_ibstart(dir) == a->btgt) + au_cpup_attr_timesizes(dir); +} + +static void au_ren_refresh(struct au_ren_args *a) +{ + aufs_bindex_t bend, bindex; + struct dentry *d, *h_d; + struct inode *i, *h_i; + struct super_block *sb; + + d = a->dst_dentry; + d_drop(d); + if (a->h_dst) + /* already dget-ed by au_ren_or_cpup() */ + au_set_h_dptr(d, a->btgt, a->h_dst); + + i = a->dst_inode; + if (i) { + if (!au_ftest_ren(a->flags, ISDIR)) + vfsub_drop_nlink(i); + else { + vfsub_dead_dir(i); + au_cpup_attr_timesizes(i); + } + au_update_dbrange(d, /*do_put_zero*/1); + } else { + bend = a->btgt; + for (bindex = au_dbstart(d); bindex < bend; bindex++) + au_set_h_dptr(d, bindex, NULL); + bend = au_dbend(d); + for (bindex = a->btgt + 1; bindex <= bend; bindex++) + au_set_h_dptr(d, bindex, NULL); + au_update_dbrange(d, /*do_put_zero*/0); + } + + d = a->src_dentry; + au_set_dbwh(d, -1); + bend = au_dbend(d); + for (bindex = a->btgt + 1; bindex <= bend; bindex++) { + h_d = au_h_dptr(d, bindex); + if (h_d) + au_set_h_dptr(d, bindex, NULL); + } + au_set_dbend(d, a->btgt); + + sb = d->d_sb; + i = a->src_inode; + if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) + return; /* success */ + + bend = au_ibend(i); + for (bindex = a->btgt + 1; bindex <= bend; bindex++) { + h_i = au_h_iptr(i, bindex); + if (h_i) { + au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); + /* ignore this error */ + au_set_h_iptr(i, bindex, NULL, 0); + } + } + au_set_ibend(i, a->btgt); +} + +/* ---------------------------------------------------------------------- */ + +/* mainly for link(2) and rename(2) */ +int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) +{ + aufs_bindex_t bdiropq, bwh; + struct dentry *parent; + struct au_branch *br; + + parent = dentry->d_parent; + IMustLock(parent->d_inode); /* dir is locked */ + + bdiropq = au_dbdiropq(parent); + bwh = au_dbwh(dentry); + br = au_sbr(dentry->d_sb, btgt); + if (au_br_rdonly(br) + || (0 <= bdiropq && bdiropq < btgt) + || (0 <= bwh && bwh < btgt)) + btgt = -1; + + AuDbg("btgt %d\n", btgt); + return btgt; +} + +/* sets src_bstart, dst_bstart and btgt */ +static int au_ren_wbr(struct au_ren_args *a) +{ + int err; + struct au_wr_dir_args wr_dir_args = { + /* .force_btgt = -1, */ + .flags = AuWrDir_ADD_ENTRY + }; + + a->src_bstart = au_dbstart(a->src_dentry); + a->dst_bstart = au_dbstart(a->dst_dentry); + if (au_ftest_ren(a->flags, ISDIR)) + au_fset_wrdir(wr_dir_args.flags, ISDIR); + wr_dir_args.force_btgt = a->src_bstart; + if (a->dst_inode && a->dst_bstart < a->src_bstart) + wr_dir_args.force_btgt = a->dst_bstart; + wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); + err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); + a->btgt = err; + + return err; +} + +static void au_ren_dt(struct au_ren_args *a) +{ + a->h_path.dentry = a->src_h_parent; + au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); + if (!au_ftest_ren(a->flags, ISSAMEDIR)) { + a->h_path.dentry = a->dst_h_parent; + au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); + } + + au_fclr_ren(a->flags, DT_DSTDIR); + if (!au_ftest_ren(a->flags, ISDIR)) + return; + + a->h_path.dentry = a->src_h_dentry; + au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); + if (a->dst_h_dentry->d_inode) { + au_fset_ren(a->flags, DT_DSTDIR); + a->h_path.dentry = a->dst_h_dentry; + au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); + } +} + +static void au_ren_rev_dt(int err, struct au_ren_args *a) +{ + struct dentry *h_d; + struct mutex *h_mtx; + + au_dtime_revert(a->src_dt + AuPARENT); + if (!au_ftest_ren(a->flags, ISSAMEDIR)) + au_dtime_revert(a->dst_dt + AuPARENT); + + if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) { + h_d = a->src_dt[AuCHILD].dt_h_path.dentry; + h_mtx = &h_d->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + au_dtime_revert(a->src_dt + AuCHILD); + mutex_unlock(h_mtx); + + if (au_ftest_ren(a->flags, DT_DSTDIR)) { + h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; + h_mtx = &h_d->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + au_dtime_revert(a->dst_dt + AuCHILD); + mutex_unlock(h_mtx); + } + } +} + +/* ---------------------------------------------------------------------- */ + +int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, + struct inode *_dst_dir, struct dentry *_dst_dentry) +{ + int err, flags; + /* reduce stack space */ + struct au_ren_args *a; + + AuDbg("%pd, %pd\n", _src_dentry, _dst_dentry); + IMustLock(_src_dir); + IMustLock(_dst_dir); + + err = -ENOMEM; + BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + a->src_dir = _src_dir; + a->src_dentry = _src_dentry; + a->src_inode = a->src_dentry->d_inode; + a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ + a->dst_dir = _dst_dir; + a->dst_dentry = _dst_dentry; + a->dst_inode = a->dst_dentry->d_inode; + a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ + if (a->dst_inode) { + IMustLock(a->dst_inode); + au_igrab(a->dst_inode); + } + + err = -ENOTDIR; + flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; + if (S_ISDIR(a->src_inode->i_mode)) { + au_fset_ren(a->flags, ISDIR); + if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode))) + goto out_free; + err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, + AuLock_DIR | flags); + } else + err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, + flags); + if (unlikely(err)) + goto out_free; + + err = au_d_hashed_positive(a->src_dentry); + if (unlikely(err)) + goto out_unlock; + err = -ENOENT; + if (a->dst_inode) { + /* + * If it is a dir, VFS unhash dst_dentry before this + * function. It means we cannot rely upon d_unhashed(). + */ + if (unlikely(!a->dst_inode->i_nlink)) + goto out_unlock; + if (!S_ISDIR(a->dst_inode->i_mode)) { + err = au_d_hashed_positive(a->dst_dentry); + if (unlikely(err)) + goto out_unlock; + } else if (unlikely(IS_DEADDIR(a->dst_inode))) + goto out_unlock; + } else if (unlikely(d_unhashed(a->dst_dentry))) + goto out_unlock; + + /* + * is it possible? + * yes, it happend (in linux-3.3-rcN) but I don't know why. + * there may exist a problem somewhere else. + */ + err = -EINVAL; + if (unlikely(a->dst_parent->d_inode == a->src_dentry->d_inode)) + goto out_unlock; + + au_fset_ren(a->flags, ISSAMEDIR); /* temporary */ + di_write_lock_parent(a->dst_parent); + + /* which branch we process */ + err = au_ren_wbr(a); + if (unlikely(err < 0)) + goto out_parent; + a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); + a->h_path.mnt = au_br_mnt(a->br); + + /* are they available to be renamed */ + err = au_ren_may_dir(a); + if (unlikely(err)) + goto out_children; + + /* prepare the writable parent dir on the same branch */ + if (a->dst_bstart == a->btgt) { + au_fset_ren(a->flags, WHDST); + } else { + err = au_cpup_dirs(a->dst_dentry, a->btgt); + if (unlikely(err)) + goto out_children; + } + + if (a->src_dir != a->dst_dir) { + /* + * this temporary unlock is safe, + * because both dir->i_mutex are locked. + */ + di_write_unlock(a->dst_parent); + di_write_lock_parent(a->src_parent); + err = au_wr_dir_need_wh(a->src_dentry, + au_ftest_ren(a->flags, ISDIR), + &a->btgt); + di_write_unlock(a->src_parent); + di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1); + au_fclr_ren(a->flags, ISSAMEDIR); + } else + err = au_wr_dir_need_wh(a->src_dentry, + au_ftest_ren(a->flags, ISDIR), + &a->btgt); + if (unlikely(err < 0)) + goto out_children; + if (err) + au_fset_ren(a->flags, WHSRC); + + /* cpup src */ + if (a->src_bstart != a->btgt) { + struct au_pin pin; + + err = au_pin(&pin, a->src_dentry, a->btgt, + au_opt_udba(a->src_dentry->d_sb), + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (!err) { + struct au_cp_generic cpg = { + .dentry = a->src_dentry, + .bdst = a->btgt, + .bsrc = a->src_bstart, + .len = -1, + .pin = &pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart); + err = au_sio_cpup_simple(&cpg); + au_unpin(&pin); + } + if (unlikely(err)) + goto out_children; + a->src_bstart = a->btgt; + a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); + au_fset_ren(a->flags, WHSRC); + } + + /* lock them all */ + err = au_ren_lock(a); + if (unlikely(err)) + /* leave the copied-up one */ + goto out_children; + + if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) + err = au_may_ren(a); + else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) + err = -ENAMETOOLONG; + if (unlikely(err)) + goto out_hdir; + + /* store timestamps to be revertible */ + au_ren_dt(a); + + /* here we go */ + err = do_rename(a); + if (unlikely(err)) + goto out_dt; + + /* update dir attributes */ + au_ren_refresh_dir(a); + + /* dput/iput all lower dentries */ + au_ren_refresh(a); + + goto out_hdir; /* success */ + +out_dt: + au_ren_rev_dt(err, a); +out_hdir: + au_ren_unlock(a); +out_children: + au_nhash_wh_free(&a->whlist); + if (err && a->dst_inode && a->dst_bstart != a->btgt) { + AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt); + au_set_h_dptr(a->dst_dentry, a->btgt, NULL); + au_set_dbstart(a->dst_dentry, a->dst_bstart); + } +out_parent: + if (!err) + d_move(a->src_dentry, a->dst_dentry); + else { + au_update_dbstart(a->dst_dentry); + if (!a->dst_inode) + d_drop(a->dst_dentry); + } + if (au_ftest_ren(a->flags, ISSAMEDIR)) + di_write_unlock(a->dst_parent); + else + di_write_unlock2(a->src_parent, a->dst_parent); +out_unlock: + aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); +out_free: + iput(a->dst_inode); + if (a->thargs) + au_whtmp_rmdir_free(a->thargs); + kfree(a); +out: + AuTraceErr(err); + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/hfsplus.c +++ linux-3.13.0/ubuntu/aufs/hfsplus.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * special support for filesystems which aqucires an inode mutex + * at final closing a file, eg, hfsplus. + * + * This trick is very simple and stupid, just to open the file before really + * neceeary open to tell hfsplus that this is not the final closing. + * The caller should call au_h_open_pre() after acquiring the inode mutex, + * and au_h_open_post() after releasing it. + */ + +#include "aufs.h" + +struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, + int force_wr) +{ + struct file *h_file; + struct dentry *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + AuDebugOn(!h_dentry); + AuDebugOn(!h_dentry->d_inode); + + h_file = NULL; + if (au_test_hfsplus(h_dentry->d_sb) + && S_ISREG(h_dentry->d_inode->i_mode)) + h_file = au_h_open(dentry, bindex, + O_RDONLY | O_NOATIME | O_LARGEFILE, + /*file*/NULL, force_wr); + return h_file; +} + +void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, + struct file *h_file) +{ + if (h_file) { + fput(h_file); + au_sbr_put(dentry->d_sb, bindex); + } +} --- linux-3.13.0.orig/ubuntu/aufs/i_op_del.c +++ linux-3.13.0/ubuntu/aufs/i_op_del.c @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations (del entry) + */ + +#include "aufs.h" + +/* + * decide if a new whiteout for @dentry is necessary or not. + * when it is necessary, prepare the parent dir for the upper branch whose + * branch index is @bcpup for creation. the actual creation of the whiteout will + * be done by caller. + * return value: + * 0: wh is unnecessary + * plus: wh is necessary + * minus: error + */ +int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) +{ + int need_wh, err; + aufs_bindex_t bstart; + struct super_block *sb; + + sb = dentry->d_sb; + bstart = au_dbstart(dentry); + if (*bcpup < 0) { + *bcpup = bstart; + if (au_test_ro(sb, bstart, dentry->d_inode)) { + err = AuWbrCopyup(au_sbi(sb), dentry); + *bcpup = err; + if (unlikely(err < 0)) + goto out; + } + } else + AuDebugOn(bstart < *bcpup + || au_test_ro(sb, *bcpup, dentry->d_inode)); + AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart); + + if (*bcpup != bstart) { + err = au_cpup_dirs(dentry, *bcpup); + if (unlikely(err)) + goto out; + need_wh = 1; + } else { + struct au_dinfo *dinfo, *tmp; + + need_wh = -ENOMEM; + dinfo = au_di(dentry); + tmp = au_di_alloc(sb, AuLsc_DI_TMP); + if (tmp) { + au_di_cp(tmp, dinfo); + au_di_swap(tmp, dinfo); + /* returns the number of positive dentries */ + need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0); + au_di_swap(tmp, dinfo); + au_rw_write_unlock(&tmp->di_rwsem); + au_di_free(tmp); + } + } + AuDbg("need_wh %d\n", need_wh); + err = need_wh; + +out: + return err; +} + +/* + * simple tests for the del-entry operations. + * following the checks in vfs, plus the parent-child relationship. + */ +int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir) +{ + int err; + umode_t h_mode; + struct dentry *h_dentry, *h_latest; + struct inode *h_inode; + + h_dentry = au_h_dptr(dentry, bindex); + h_inode = h_dentry->d_inode; + if (dentry->d_inode) { + err = -ENOENT; + if (unlikely(!h_inode || !h_inode->i_nlink)) + goto out; + + h_mode = h_inode->i_mode; + if (!isdir) { + err = -EISDIR; + if (unlikely(S_ISDIR(h_mode))) + goto out; + } else if (unlikely(!S_ISDIR(h_mode))) { + err = -ENOTDIR; + goto out; + } + } else { + /* rename(2) case */ + err = -EIO; + if (unlikely(h_inode)) + goto out; + } + + err = -ENOENT; + /* expected parent dir is locked */ + if (unlikely(h_parent != h_dentry->d_parent)) + goto out; + err = 0; + + /* + * rmdir a dir may break the consistency on some filesystem. + * let's try heavy test. + */ + err = -EACCES; + if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE))) + goto out; + + h_latest = au_sio_lkup_one(&dentry->d_name, h_parent, + au_sbr(dentry->d_sb, bindex)); + err = -EIO; + if (IS_ERR(h_latest)) + goto out; + if (h_latest == h_dentry) + err = 0; + dput(h_latest); + +out: + return err; +} + +/* + * decide the branch where we operate for @dentry. the branch index will be set + * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent + * dir for reverting. + * when a new whiteout is necessary, create it. + */ +static struct dentry* +lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, + struct au_dtime *dt, struct au_pin *pin) +{ + struct dentry *wh_dentry; + struct super_block *sb; + struct path h_path; + int err, need_wh; + unsigned int udba; + aufs_bindex_t bcpup; + + need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); + wh_dentry = ERR_PTR(need_wh); + if (unlikely(need_wh < 0)) + goto out; + + sb = dentry->d_sb; + udba = au_opt_udba(sb); + bcpup = *rbcpup; + err = au_pin(pin, dentry, bcpup, udba, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out; + + h_path.dentry = au_pinned_h_parent(pin); + if (udba != AuOpt_UDBA_NONE + && au_dbstart(dentry) == bcpup) { + err = au_may_del(dentry, bcpup, h_path.dentry, isdir); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_unpin; + } + + h_path.mnt = au_sbr_mnt(sb, bcpup); + au_dtime_store(dt, au_pinned_parent(pin), &h_path); + wh_dentry = NULL; + if (!need_wh) + goto out; /* success, no need to create whiteout */ + + wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); + if (IS_ERR(wh_dentry)) + goto out_unpin; + + /* returns with the parent is locked and wh_dentry is dget-ed */ + goto out; /* success */ + +out_unpin: + au_unpin(pin); +out: + return wh_dentry; +} + +/* + * when removing a dir, rename it to a unique temporary whiteout-ed name first + * in order to be revertible and save time for removing many child whiteouts + * under the dir. + * returns 1 when there are too many child whiteout and caller should remove + * them asynchronously. returns 0 when the number of children is enough small to + * remove now or the branch fs is a remote fs. + * otherwise return an error. + */ +static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, + struct au_nhash *whlist, struct inode *dir) +{ + int rmdir_later, err, dirwh; + struct dentry *h_dentry; + struct super_block *sb; + + sb = dentry->d_sb; + SiMustAnyLock(sb); + h_dentry = au_h_dptr(dentry, bindex); + err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); + if (unlikely(err)) + goto out; + + /* stop monitoring */ + au_hn_free(au_hi(dentry->d_inode, bindex)); + + if (!au_test_fs_remote(h_dentry->d_sb)) { + dirwh = au_sbi(sb)->si_dirwh; + rmdir_later = (dirwh <= 1); + if (!rmdir_later) + rmdir_later = au_nhash_test_longer_wh(whlist, bindex, + dirwh); + if (rmdir_later) + return rmdir_later; + } + + err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); + if (unlikely(err)) { + AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", + h_dentry, bindex, err); + err = 0; + } + +out: + AuTraceErr(err); + return err; +} + +/* + * final procedure for deleting a entry. + * maintain dentry and iattr. + */ +static void epilog(struct inode *dir, struct dentry *dentry, + aufs_bindex_t bindex) +{ + struct inode *inode; + + inode = dentry->d_inode; + d_drop(dentry); + inode->i_ctime = dir->i_ctime; + + if (au_ibstart(dir) == bindex) + au_cpup_attr_timesizes(dir); + dir->i_version++; +} + +/* + * when an error happened, remove the created whiteout and revert everything. + */ +static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, + aufs_bindex_t bwh, struct dentry *wh_dentry, + struct dentry *dentry, struct au_dtime *dt) +{ + int rerr; + struct path h_path = { + .dentry = wh_dentry, + .mnt = au_sbr_mnt(dir->i_sb, bindex) + }; + + rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); + if (!rerr) { + au_set_dbwh(dentry, bwh); + au_dtime_revert(dt); + return 0; + } + + AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); + return -EIO; +} + +/* ---------------------------------------------------------------------- */ + +int aufs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err; + aufs_bindex_t bwh, bindex, bstart; + struct inode *inode, *h_dir, *delegated; + struct dentry *parent, *wh_dentry; + /* to reuduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; + struct path h_path; + } *a; + + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); + if (unlikely(err)) + goto out_free; + err = au_d_hashed_positive(dentry); + if (unlikely(err)) + goto out_unlock; + inode = dentry->d_inode; + IMustLock(inode); + err = -EISDIR; + if (unlikely(S_ISDIR(inode->i_mode))) + goto out_unlock; /* possible? */ + + bstart = au_dbstart(dentry); + bwh = au_dbwh(dentry); + bindex = -1; + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, + &a->pin); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + a->h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); + a->h_path.dentry = au_h_dptr(dentry, bstart); + dget(a->h_path.dentry); + if (bindex == bstart) { + h_dir = au_pinned_h_dir(&a->pin); + delegated = NULL; + err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + } else { + /* dir inode is locked */ + h_dir = wh_dentry->d_parent->d_inode; + IMustLock(h_dir); + err = 0; + } + + if (!err) { + vfsub_drop_nlink(inode); + epilog(dir, dentry, bindex); + + /* update target timestamps */ + if (bindex == bstart) { + vfsub_update_h_iattr(&a->h_path, /*did*/NULL); + /*ignore*/ + inode->i_ctime = a->h_path.dentry->d_inode->i_ctime; + } else + /* todo: this timestamp may be reverted later */ + inode->i_ctime = h_dir->i_ctime; + goto out_unpin; /* success */ + } + + /* revert */ + if (wh_dentry) { + int rerr; + + rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, + &a->dt); + if (rerr) + err = rerr; + } + +out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); + dput(a->h_path.dentry); +out_parent: + di_write_unlock(parent); +out_unlock: + aufs_read_unlock(dentry, AuLock_DW); +out_free: + kfree(a); +out: + return err; +} + +int aufs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err, rmdir_later; + aufs_bindex_t bwh, bindex, bstart; + struct inode *inode; + struct dentry *parent, *wh_dentry, *h_dentry; + struct au_whtmp_rmdir *args; + /* to reuduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; + } *a; + + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); + if (unlikely(err)) + goto out_free; + err = au_alive_dir(dentry); + if (unlikely(err)) + goto out_unlock; + inode = dentry->d_inode; + IMustLock(inode); + err = -ENOTDIR; + if (unlikely(!S_ISDIR(inode->i_mode))) + goto out_unlock; /* possible? */ + + err = -ENOMEM; + args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); + if (unlikely(!args)) + goto out_unlock; + + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + err = au_test_empty(dentry, &args->whlist); + if (unlikely(err)) + goto out_parent; + + bstart = au_dbstart(dentry); + bwh = au_dbwh(dentry); + bindex = -1; + wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, + &a->pin); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + h_dentry = au_h_dptr(dentry, bstart); + dget(h_dentry); + rmdir_later = 0; + if (bindex == bstart) { + err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir); + if (err > 0) { + rmdir_later = err; + err = 0; + } + } else { + /* stop monitoring */ + au_hn_free(au_hi(inode, bstart)); + + /* dir inode is locked */ + IMustLock(wh_dentry->d_parent->d_inode); + err = 0; + } + + if (!err) { + vfsub_dead_dir(inode); + au_set_dbdiropq(dentry, -1); + epilog(dir, dentry, bindex); + + if (rmdir_later) { + au_whtmp_kick_rmdir(dir, bstart, h_dentry, args); + args = NULL; + } + + goto out_unpin; /* success */ + } + + /* revert */ + AuLabel(revert); + if (wh_dentry) { + int rerr; + + rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, + &a->dt); + if (rerr) + err = rerr; + } + +out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); + dput(h_dentry); +out_parent: + di_write_unlock(parent); + if (args) + au_whtmp_rmdir_free(args); +out_unlock: + aufs_read_unlock(dentry, AuLock_DW); +out_free: + kfree(a); +out: + AuTraceErr(err); + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/Makefile +++ linux-3.13.0/ubuntu/aufs/Makefile @@ -0,0 +1,42 @@ + +include ${src}/magic.mk +ifeq (${CONFIG_AUFS_FS},m) +include ${src}/conf.mk +endif +-include ${src}/priv_def.mk + +# cf. include/linux/kernel.h +# enable pr_debug +ccflags-y += -DDEBUG +# sparse requires the full pathname +ifdef M +ccflags-y += -include ${M}/../../ubuntu/include/uapi/linux/aufs_type.h +else +ccflags-y += -include ${srctree}/ubuntu/include/uapi/linux/aufs_type.h +endif + +obj-$(CONFIG_AUFS_FS) += aufs.o +aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ + wkq.o vfsub.o dcsub.o \ + cpup.o whout.o wbr_policy.o \ + dinfo.o dentry.o \ + dynop.o \ + finfo.o file.o f_op.o \ + dir.o vdir.o \ + iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ + mvdown.o ioctl.o + +# all are boolean +aufs-$(CONFIG_PROC_FS) += procfs.o plink.o +aufs-$(CONFIG_SYSFS) += sysfs.o +aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o +aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o +aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o +aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o +aufs-$(CONFIG_AUFS_EXPORT) += export.o +aufs-$(CONFIG_AUFS_POLL) += poll.o +aufs-$(CONFIG_AUFS_RDU) += rdu.o +aufs-$(CONFIG_AUFS_SP_IATTR) += f_op_sp.o +aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o +aufs-$(CONFIG_AUFS_DEBUG) += debug.o +aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o --- linux-3.13.0.orig/ubuntu/aufs/inode.h +++ linux-3.13.0/ubuntu/aufs/inode.h @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations + */ + +#ifndef __AUFS_INODE_H__ +#define __AUFS_INODE_H__ + +#ifdef __KERNEL__ + +#include +#include "rwsem.h" + +struct vfsmount; + +struct au_hnotify { +#ifdef CONFIG_AUFS_HNOTIFY +#ifdef CONFIG_AUFS_HFSNOTIFY + /* never use fsnotify_add_vfsmount_mark() */ + struct fsnotify_mark hn_mark; +#endif + struct inode *hn_aufs_inode; /* no get/put */ +#endif +} ____cacheline_aligned_in_smp; + +struct au_hinode { + struct inode *hi_inode; + aufs_bindex_t hi_id; +#ifdef CONFIG_AUFS_HNOTIFY + struct au_hnotify *hi_notify; +#endif + + /* reference to the copied-up whiteout with get/put */ + struct dentry *hi_whdentry; +}; + +/* ig_flags */ +#define AuIG_HALF_REFRESHED 1 +#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) +#define au_ig_fset(flags, name) \ + do { (flags) |= AuIG_##name; } while (0) +#define au_ig_fclr(flags, name) \ + do { (flags) &= ~AuIG_##name; } while (0) + +struct au_iigen { + __u32 ig_generation, ig_flags; +}; + +struct au_vdir; +struct au_iinfo { + spinlock_t ii_genspin; + struct au_iigen ii_generation; + struct super_block *ii_hsb1; /* no get/put */ + + struct au_rwsem ii_rwsem; + aufs_bindex_t ii_bstart, ii_bend; + __u32 ii_higen; + struct au_hinode *ii_hinode; + struct au_vdir *ii_vdir; +}; + +struct au_icntnr { + struct au_iinfo iinfo; + struct inode vfs_inode; +} ____cacheline_aligned_in_smp; + +/* au_pin flags */ +#define AuPin_DI_LOCKED 1 +#define AuPin_MNT_WRITE (1 << 1) +#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) +#define au_fset_pin(flags, name) \ + do { (flags) |= AuPin_##name; } while (0) +#define au_fclr_pin(flags, name) \ + do { (flags) &= ~AuPin_##name; } while (0) + +struct au_pin { + /* input */ + struct dentry *dentry; + unsigned int udba; + unsigned char lsc_di, lsc_hi, flags; + aufs_bindex_t bindex; + + /* output */ + struct dentry *parent; + struct au_hinode *hdir; + struct vfsmount *h_mnt; + + /* temporary unlock/relock for copyup */ + struct dentry *h_dentry, *h_parent; + struct au_branch *br; + struct task_struct *task; +}; + +void au_pin_hdir_unlock(struct au_pin *p); +int au_pin_hdir_relock(struct au_pin *p); +void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task); +void au_pin_hdir_acquire_nest(struct au_pin *p); +void au_pin_hdir_release(struct au_pin *p); + +/* ---------------------------------------------------------------------- */ + +static inline struct au_iinfo *au_ii(struct inode *inode) +{ + struct au_iinfo *iinfo; + + iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); + if (iinfo->ii_hinode) + return iinfo; + return NULL; /* debugging bad_inode case */ +} + +/* ---------------------------------------------------------------------- */ + +/* inode.c */ +struct inode *au_igrab(struct inode *inode); +int au_refresh_hinode_self(struct inode *inode); +int au_refresh_hinode(struct inode *inode, struct dentry *dentry); +int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + unsigned int d_type, ino_t *ino); +struct inode *au_new_inode(struct dentry *dentry, int must_new); +int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode); +int au_test_h_perm(struct inode *h_inode, int mask); +int au_test_h_perm_sio(struct inode *h_inode, int mask); + +static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, + ino_t h_ino, unsigned int d_type, ino_t *ino) +{ +#ifdef CONFIG_AUFS_SHWH + return au_ino(sb, bindex, h_ino, d_type, ino); +#else + return 0; +#endif +} + +/* i_op.c */ +extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; + +/* au_wr_dir flags */ +#define AuWrDir_ADD_ENTRY 1 +#define AuWrDir_TMP_WHENTRY (1 << 1) +#define AuWrDir_ISDIR (1 << 2) +#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) +#define au_fset_wrdir(flags, name) \ + do { (flags) |= AuWrDir_##name; } while (0) +#define au_fclr_wrdir(flags, name) \ + do { (flags) &= ~AuWrDir_##name; } while (0) + +struct au_wr_dir_args { + aufs_bindex_t force_btgt; + unsigned char flags; +}; +int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, + struct au_wr_dir_args *args); + +struct dentry *au_pinned_h_parent(struct au_pin *pin); +void au_pin_init(struct au_pin *pin, struct dentry *dentry, + aufs_bindex_t bindex, int lsc_di, int lsc_hi, + unsigned int udba, unsigned char flags); +int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, + unsigned int udba, unsigned char flags) __must_check; +int au_do_pin(struct au_pin *pin) __must_check; +void au_unpin(struct au_pin *pin); + +/* i_op_add.c */ +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir); +int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + dev_t dev); +int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); +int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool want_excl); +int aufs_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry); +int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); + +/* i_op_del.c */ +int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); +int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir); +int aufs_unlink(struct inode *dir, struct dentry *dentry); +int aufs_rmdir(struct inode *dir, struct dentry *dentry); + +/* i_op_ren.c */ +int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); +int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry); + +/* iinfo.c */ +struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); +void au_hiput(struct au_hinode *hinode); +void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_wh); +unsigned int au_hi_flags(struct inode *inode, int isdir); + +/* hinode flags */ +#define AuHi_XINO 1 +#define AuHi_HNOTIFY (1 << 1) +#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) +#define au_fset_hi(flags, name) \ + do { (flags) |= AuHi_##name; } while (0) +#define au_fclr_hi(flags, name) \ + do { (flags) &= ~AuHi_##name; } while (0) + +#ifndef CONFIG_AUFS_HNOTIFY +#undef AuHi_HNOTIFY +#define AuHi_HNOTIFY 0 +#endif + +void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode, unsigned int flags); + +void au_update_iigen(struct inode *inode, int half); +void au_update_ibrange(struct inode *inode, int do_put_zero); + +void au_icntnr_init_once(void *_c); +int au_iinfo_init(struct inode *inode); +void au_iinfo_fin(struct inode *inode); +int au_ii_realloc(struct au_iinfo *iinfo, int nbr); + +#ifdef CONFIG_PROC_FS +/* plink.c */ +int au_plink_maint(struct super_block *sb, int flags); +void au_plink_maint_leave(struct au_sbinfo *sbinfo); +int au_plink_maint_enter(struct super_block *sb); +#ifdef CONFIG_AUFS_DEBUG +void au_plink_list(struct super_block *sb); +#else +AuStubVoid(au_plink_list, struct super_block *sb) +#endif +int au_plink_test(struct inode *inode); +struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); +void au_plink_append(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_dentry); +void au_plink_put(struct super_block *sb, int verbose); +void au_plink_clean(struct super_block *sb, int verbose); +void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); +#else +AuStubInt0(au_plink_maint, struct super_block *sb, int flags); +AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); +AuStubInt0(au_plink_maint_enter, struct super_block *sb); +AuStubVoid(au_plink_list, struct super_block *sb); +AuStubInt0(au_plink_test, struct inode *inode); +AuStub(struct dentry *, au_plink_lkup, return NULL, + struct inode *inode, aufs_bindex_t bindex); +AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_dentry); +AuStubVoid(au_plink_put, struct super_block *sb, int verbose); +AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); +AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); +#endif /* CONFIG_PROC_FS */ + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for iinfo */ +enum { + AuLsc_II_CHILD, /* child first */ + AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ + AuLsc_II_CHILD3, /* copyup dirs */ + AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ + AuLsc_II_PARENT2, + AuLsc_II_PARENT3, /* copyup dirs */ + AuLsc_II_NEW_CHILD +}; + +/* + * ii_read_lock_child, ii_write_lock_child, + * ii_read_lock_child2, ii_write_lock_child2, + * ii_read_lock_child3, ii_write_lock_child3, + * ii_read_lock_parent, ii_write_lock_parent, + * ii_read_lock_parent2, ii_write_lock_parent2, + * ii_read_lock_parent3, ii_write_lock_parent3, + * ii_read_lock_new_child, ii_write_lock_new_child, + */ +#define AuReadLockFunc(name, lsc) \ +static inline void ii_read_lock_##name(struct inode *i) \ +{ \ + au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ +} + +#define AuWriteLockFunc(name, lsc) \ +static inline void ii_write_lock_##name(struct inode *i) \ +{ \ + au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ +} + +#define AuRWLockFuncs(name, lsc) \ + AuReadLockFunc(name, lsc) \ + AuWriteLockFunc(name, lsc) + +AuRWLockFuncs(child, CHILD); +AuRWLockFuncs(child2, CHILD2); +AuRWLockFuncs(child3, CHILD3); +AuRWLockFuncs(parent, PARENT); +AuRWLockFuncs(parent2, PARENT2); +AuRWLockFuncs(parent3, PARENT3); +AuRWLockFuncs(new_child, NEW_CHILD); + +#undef AuReadLockFunc +#undef AuWriteLockFunc +#undef AuRWLockFuncs + +/* + * ii_read_unlock, ii_write_unlock, ii_downgrade_lock + */ +AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem); + +#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) +#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) +#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) + +/* ---------------------------------------------------------------------- */ + +static inline void au_icntnr_init(struct au_icntnr *c) +{ +#ifdef CONFIG_AUFS_DEBUG + c->vfs_inode.i_mode = 0; +#endif +} + +static inline unsigned int au_iigen(struct inode *inode, struct au_iigen *iigen) +{ + unsigned int gen; + struct au_iinfo *iinfo; + + iinfo = au_ii(inode); + spin_lock(&iinfo->ii_genspin); + if (iigen) + *iigen = iinfo->ii_generation; + gen = iinfo->ii_generation.ig_generation; + spin_unlock(&iinfo->ii_genspin); + + return gen; +} + +/* tiny test for inode number */ +/* tmpfs generation is too rough */ +static inline int au_test_higen(struct inode *inode, struct inode *h_inode) +{ + struct au_iinfo *iinfo; + + iinfo = au_ii(inode); + AuRwMustAnyLock(&iinfo->ii_rwsem); + return !(iinfo->ii_hsb1 == h_inode->i_sb + && iinfo->ii_higen == h_inode->i_generation); +} + +static inline void au_iigen_dec(struct inode *inode) +{ + struct au_iinfo *iinfo; + + iinfo = au_ii(inode); + spin_lock(&iinfo->ii_genspin); + iinfo->ii_generation.ig_generation--; + spin_unlock(&iinfo->ii_genspin); +} + +static inline int au_iigen_test(struct inode *inode, unsigned int sigen) +{ + int err; + + err = 0; + if (unlikely(inode && au_iigen(inode, NULL) != sigen)) + err = -EIO; + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static inline aufs_bindex_t au_ii_br_id(struct inode *inode, + aufs_bindex_t bindex) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_hinode[0 + bindex].hi_id; +} + +static inline aufs_bindex_t au_ibstart(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_bstart; +} + +static inline aufs_bindex_t au_ibend(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_bend; +} + +static inline struct au_vdir *au_ivdir(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_vdir; +} + +static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry; +} + +static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustWriteLock(inode); + au_ii(inode)->ii_bstart = bindex; +} + +static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustWriteLock(inode); + au_ii(inode)->ii_bend = bindex; +} + +static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) +{ + IiMustWriteLock(inode); + au_ii(inode)->ii_vdir = vdir; +} + +static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_hinode + bindex; +} + +/* ---------------------------------------------------------------------- */ + +static inline struct dentry *au_pinned_parent(struct au_pin *pin) +{ + if (pin) + return pin->parent; + return NULL; +} + +static inline struct inode *au_pinned_h_dir(struct au_pin *pin) +{ + if (pin && pin->hdir) + return pin->hdir->hi_inode; + return NULL; +} + +static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) +{ + if (pin) + return pin->hdir; + return NULL; +} + +static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) +{ + if (pin) + pin->dentry = dentry; +} + +static inline void au_pin_set_parent_lflag(struct au_pin *pin, + unsigned char lflag) +{ + if (pin) { + if (lflag) + au_fset_pin(pin->flags, DI_LOCKED); + else + au_fclr_pin(pin->flags, DI_LOCKED); + } +} + +static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) +{ + if (pin) { + dput(pin->parent); + pin->parent = dget(parent); + } +} + +/* ---------------------------------------------------------------------- */ + +struct au_branch; +#ifdef CONFIG_AUFS_HNOTIFY +struct au_hnotify_op { + void (*ctl)(struct au_hinode *hinode, int do_set); + int (*alloc)(struct au_hinode *hinode); + + /* + * if it returns true, the the caller should free hinode->hi_notify, + * otherwise ->free() frees it. + */ + int (*free)(struct au_hinode *hinode, + struct au_hnotify *hn) __must_check; + + void (*fin)(void); + int (*init)(void); + + int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); + void (*fin_br)(struct au_branch *br); + int (*init_br)(struct au_branch *br, int perm); +}; + +/* hnotify.c */ +int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); +void au_hn_free(struct au_hinode *hinode); +void au_hn_ctl(struct au_hinode *hinode, int do_set); +void au_hn_reset(struct inode *inode, unsigned int flags); +int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, + struct qstr *h_child_qstr, struct inode *h_child_inode); +int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); +int au_hnotify_init_br(struct au_branch *br, int perm); +void au_hnotify_fin_br(struct au_branch *br); +int __init au_hnotify_init(void); +void au_hnotify_fin(void); + +/* hfsnotify.c */ +extern const struct au_hnotify_op au_hnotify_op; + +static inline +void au_hn_init(struct au_hinode *hinode) +{ + hinode->hi_notify = NULL; +} + +static inline struct au_hnotify *au_hn(struct au_hinode *hinode) +{ + return hinode->hi_notify; +} + +#else +static inline +int au_hn_alloc(struct au_hinode *hinode __maybe_unused, + struct inode *inode __maybe_unused) +{ + return -EOPNOTSUPP; +} + +static inline struct au_hnotify *au_hn(struct au_hinode *hinode) +{ + return NULL; +} + +AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) +AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, + int do_set __maybe_unused) +AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, + unsigned int flags __maybe_unused) +AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, + struct au_branch *br __maybe_unused, + int perm __maybe_unused) +AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, + int perm __maybe_unused) +AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) +AuStubInt0(__init au_hnotify_init, void) +AuStubVoid(au_hnotify_fin, void) +AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) +#endif /* CONFIG_AUFS_HNOTIFY */ + +static inline void au_hn_suspend(struct au_hinode *hdir) +{ + au_hn_ctl(hdir, /*do_set*/0); +} + +static inline void au_hn_resume(struct au_hinode *hdir) +{ + au_hn_ctl(hdir, /*do_set*/1); +} + +static inline void au_hn_imtx_lock(struct au_hinode *hdir) +{ + mutex_lock(&hdir->hi_inode->i_mutex); + au_hn_suspend(hdir); +} + +static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir, + unsigned int sc __maybe_unused) +{ + mutex_lock_nested(&hdir->hi_inode->i_mutex, sc); + au_hn_suspend(hdir); +} + +static inline void au_hn_imtx_unlock(struct au_hinode *hdir) +{ + au_hn_resume(hdir); + mutex_unlock(&hdir->hi_inode->i_mutex); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_INODE_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/dynop.c +++ linux-3.13.0/ubuntu/aufs/dynop.c @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * dynamically customizable operations for regular files + */ + +#include "aufs.h" + +#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) + +/* + * How large will these lists be? + * Usually just a few elements, 20-30 at most for each, I guess. + */ +static struct au_splhead dynop[AuDyLast]; + +static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op) +{ + struct au_dykey *key, *tmp; + struct list_head *head; + + key = NULL; + head = &spl->head; + rcu_read_lock(); + list_for_each_entry_rcu(tmp, head, dk_list) + if (tmp->dk_op.dy_hop == h_op) { + key = tmp; + kref_get(&key->dk_kref); + break; + } + rcu_read_unlock(); + + return key; +} + +static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) +{ + struct au_dykey **k, *found; + const void *h_op = key->dk_op.dy_hop; + int i; + + found = NULL; + k = br->br_dykey; + for (i = 0; i < AuBrDynOp; i++) + if (k[i]) { + if (k[i]->dk_op.dy_hop == h_op) { + found = k[i]; + break; + } + } else + break; + if (!found) { + spin_lock(&br->br_dykey_lock); + for (; i < AuBrDynOp; i++) + if (k[i]) { + if (k[i]->dk_op.dy_hop == h_op) { + found = k[i]; + break; + } + } else { + k[i] = key; + break; + } + spin_unlock(&br->br_dykey_lock); + BUG_ON(i == AuBrDynOp); /* expand the array */ + } + + return found; +} + +/* kref_get() if @key is already added */ +static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key) +{ + struct au_dykey *tmp, *found; + struct list_head *head; + const void *h_op = key->dk_op.dy_hop; + + found = NULL; + head = &spl->head; + spin_lock(&spl->spin); + list_for_each_entry(tmp, head, dk_list) + if (tmp->dk_op.dy_hop == h_op) { + kref_get(&tmp->dk_kref); + found = tmp; + break; + } + if (!found) + list_add_rcu(&key->dk_list, head); + spin_unlock(&spl->spin); + + if (!found) + DyPrSym(key); + return found; +} + +static void dy_free_rcu(struct rcu_head *rcu) +{ + struct au_dykey *key; + + key = container_of(rcu, struct au_dykey, dk_rcu); + DyPrSym(key); + kfree(key); +} + +static void dy_free(struct kref *kref) +{ + struct au_dykey *key; + struct au_splhead *spl; + + key = container_of(kref, struct au_dykey, dk_kref); + spl = dynop + key->dk_op.dy_type; + au_spl_del_rcu(&key->dk_list, spl); + call_rcu(&key->dk_rcu, dy_free_rcu); +} + +void au_dy_put(struct au_dykey *key) +{ + kref_put(&key->dk_kref, dy_free); +} + +/* ---------------------------------------------------------------------- */ + +#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) + +#ifdef CONFIG_AUFS_DEBUG +#define DyDbgDeclare(cnt) unsigned int cnt = 0 +#define DyDbgInc(cnt) do { cnt++; } while (0) +#else +#define DyDbgDeclare(cnt) do {} while (0) +#define DyDbgInc(cnt) do {} while (0) +#endif + +#define DySet(func, dst, src, h_op, h_sb) do { \ + DyDbgInc(cnt); \ + if (h_op->func) { \ + if (src.func) \ + dst.func = src.func; \ + else \ + AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ + } \ +} while (0) + +#define DySetForce(func, dst, src) do { \ + AuDebugOn(!src.func); \ + DyDbgInc(cnt); \ + dst.func = src.func; \ +} while (0) + +#define DySetAop(func) \ + DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) +#define DySetAopForce(func) \ + DySetForce(func, dyaop->da_op, aufs_aop) + +static void dy_aop(struct au_dykey *key, const void *h_op, + struct super_block *h_sb __maybe_unused) +{ + struct au_dyaop *dyaop = (void *)key; + const struct address_space_operations *h_aop = h_op; + DyDbgDeclare(cnt); + + AuDbg("%s\n", au_sbtype(h_sb)); + + DySetAop(writepage); + DySetAopForce(readpage); /* force */ + DySetAop(writepages); + DySetAop(set_page_dirty); + DySetAop(readpages); + DySetAop(write_begin); + DySetAop(write_end); + DySetAop(bmap); + DySetAop(invalidatepage); + DySetAop(releasepage); + DySetAop(freepage); + /* these two will be changed according to an aufs mount option */ + DySetAop(direct_IO); + DySetAop(get_xip_mem); + DySetAop(migratepage); + DySetAop(launder_page); + DySetAop(is_partially_uptodate); + DySetAop(is_dirty_writeback); + DySetAop(error_remove_page); + DySetAop(swap_activate); + DySetAop(swap_deactivate); + + DyDbgSize(cnt, *h_aop); + dyaop->da_get_xip_mem = h_aop->get_xip_mem; +} + +/* ---------------------------------------------------------------------- */ + +static void dy_bug(struct kref *kref) +{ + BUG(); +} + +static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) +{ + struct au_dykey *key, *old; + struct au_splhead *spl; + struct op { + unsigned int sz; + void (*set)(struct au_dykey *key, const void *h_op, + struct super_block *h_sb __maybe_unused); + }; + static const struct op a[] = { + [AuDy_AOP] = { + .sz = sizeof(struct au_dyaop), + .set = dy_aop + } + }; + const struct op *p; + + spl = dynop + op->dy_type; + key = dy_gfind_get(spl, op->dy_hop); + if (key) + goto out_add; /* success */ + + p = a + op->dy_type; + key = kzalloc(p->sz, GFP_NOFS); + if (unlikely(!key)) { + key = ERR_PTR(-ENOMEM); + goto out; + } + + key->dk_op.dy_hop = op->dy_hop; + kref_init(&key->dk_kref); + p->set(key, op->dy_hop, au_br_sb(br)); + old = dy_gadd(spl, key); + if (old) { + kfree(key); + key = old; + } + +out_add: + old = dy_bradd(br, key); + if (old) + /* its ref-count should never be zero here */ + kref_put(&key->dk_kref, dy_bug); +out: + return key; +} + +/* ---------------------------------------------------------------------- */ +/* + * Aufs prohibits O_DIRECT by defaut even if the branch supports it. + * This behaviour is neccessary to return an error from open(O_DIRECT) instead + * of the succeeding I/O. The dio mount option enables O_DIRECT and makes + * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. + * See the aufs manual in detail. + * + * To keep this behaviour, aufs has to set NULL to ->get_xip_mem too, and the + * performance of fadvise() and madvise() may be affected. + */ +static void dy_adx(struct au_dyaop *dyaop, int do_dx) +{ + if (!do_dx) { + dyaop->da_op.direct_IO = NULL; + dyaop->da_op.get_xip_mem = NULL; + } else { + dyaop->da_op.direct_IO = aufs_aop.direct_IO; + dyaop->da_op.get_xip_mem = aufs_aop.get_xip_mem; + if (!dyaop->da_get_xip_mem) + dyaop->da_op.get_xip_mem = NULL; + } +} + +static struct au_dyaop *dy_aget(struct au_branch *br, + const struct address_space_operations *h_aop, + int do_dx) +{ + struct au_dyaop *dyaop; + struct au_dynop op; + + op.dy_type = AuDy_AOP; + op.dy_haop = h_aop; + dyaop = (void *)dy_get(&op, br); + if (IS_ERR(dyaop)) + goto out; + dy_adx(dyaop, do_dx); + +out: + return dyaop; +} + +int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode) +{ + int err, do_dx; + struct super_block *sb; + struct au_branch *br; + struct au_dyaop *dyaop; + + AuDebugOn(!S_ISREG(h_inode->i_mode)); + IiMustWriteLock(inode); + + sb = inode->i_sb; + br = au_sbr(sb, bindex); + do_dx = !!au_opt_test(au_mntflags(sb), DIO); + dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); + err = PTR_ERR(dyaop); + if (IS_ERR(dyaop)) + /* unnecessary to call dy_fput() */ + goto out; + + err = 0; + inode->i_mapping->a_ops = &dyaop->da_op; + +out: + return err; +} + +/* + * Is it safe to replace a_ops during the inode/file is in operation? + * Yes, I hope so. + */ +int au_dy_irefresh(struct inode *inode) +{ + int err; + aufs_bindex_t bstart; + struct inode *h_inode; + + err = 0; + if (S_ISREG(inode->i_mode)) { + bstart = au_ibstart(inode); + h_inode = au_h_iptr(inode, bstart); + err = au_dy_iaop(inode, bstart, h_inode); + } + return err; +} + +void au_dy_arefresh(int do_dx) +{ + struct au_splhead *spl; + struct list_head *head; + struct au_dykey *key; + + spl = dynop + AuDy_AOP; + head = &spl->head; + spin_lock(&spl->spin); + list_for_each_entry(key, head, dk_list) + dy_adx((void *)key, do_dx); + spin_unlock(&spl->spin); +} + +/* ---------------------------------------------------------------------- */ + +void __init au_dy_init(void) +{ + int i; + + /* make sure that 'struct au_dykey *' can be any type */ + BUILD_BUG_ON(offsetof(struct au_dyaop, da_key)); + + for (i = 0; i < AuDyLast; i++) + au_spl_init(dynop + i); +} + +void au_dy_fin(void) +{ + int i; + + for (i = 0; i < AuDyLast; i++) + WARN_ON(!list_empty(&dynop[i].head)); +} --- linux-3.13.0.orig/ubuntu/aufs/export.c +++ linux-3.13.0/ubuntu/aufs/export.c @@ -0,0 +1,831 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * export via nfs + */ + +#include +#include +#include +#include +#include +#include +#include "../fs/mount.h" +#include "aufs.h" + +union conv { +#ifdef CONFIG_AUFS_INO_T_64 + __u32 a[2]; +#else + __u32 a[1]; +#endif + ino_t ino; +}; + +static ino_t decode_ino(__u32 *a) +{ + union conv u; + + BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); + u.a[0] = a[0]; +#ifdef CONFIG_AUFS_INO_T_64 + u.a[1] = a[1]; +#endif + return u.ino; +} + +static void encode_ino(__u32 *a, ino_t ino) +{ + union conv u; + + u.ino = ino; + a[0] = u.a[0]; +#ifdef CONFIG_AUFS_INO_T_64 + a[1] = u.a[1]; +#endif +} + +/* NFS file handle */ +enum { + Fh_br_id, + Fh_sigen, +#ifdef CONFIG_AUFS_INO_T_64 + /* support 64bit inode number */ + Fh_ino1, + Fh_ino2, + Fh_dir_ino1, + Fh_dir_ino2, +#else + Fh_ino1, + Fh_dir_ino1, +#endif + Fh_igen, + Fh_h_type, + Fh_tail, + + Fh_ino = Fh_ino1, + Fh_dir_ino = Fh_dir_ino1 +}; + +static int au_test_anon(struct dentry *dentry) +{ + /* note: read d_flags without d_lock */ + return !!(dentry->d_flags & DCACHE_DISCONNECTED); +} + +int au_test_nfsd(void) +{ + int ret; + struct task_struct *tsk = current; + char comm[sizeof(tsk->comm)]; + + ret = 0; + if (tsk->flags & PF_KTHREAD) { + get_task_comm(comm, tsk); + ret = !strcmp(comm, "nfsd"); + } + + return ret; +} + +/* ---------------------------------------------------------------------- */ +/* inode generation external table */ + +void au_xigen_inc(struct inode *inode) +{ + loff_t pos; + ssize_t sz; + __u32 igen; + struct super_block *sb; + struct au_sbinfo *sbinfo; + + sb = inode->i_sb; + AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); + + sbinfo = au_sbi(sb); + pos = inode->i_ino; + pos *= sizeof(igen); + igen = inode->i_generation + 1; + sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, + sizeof(igen), &pos); + if (sz == sizeof(igen)) + return; /* success */ + + if (unlikely(sz >= 0)) + AuIOErr("xigen error (%zd)\n", sz); +} + +int au_xigen_new(struct inode *inode) +{ + int err; + loff_t pos; + ssize_t sz; + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct file *file; + + err = 0; + /* todo: dirty, at mount time */ + if (inode->i_ino == AUFS_ROOT_INO) + goto out; + sb = inode->i_sb; + SiMustAnyLock(sb); + if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) + goto out; + + err = -EFBIG; + pos = inode->i_ino; + if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { + AuIOErr1("too large i%lld\n", pos); + goto out; + } + pos *= sizeof(inode->i_generation); + + err = 0; + sbinfo = au_sbi(sb); + file = sbinfo->si_xigen; + BUG_ON(!file); + + if (vfsub_f_size_read(file) + < pos + sizeof(inode->i_generation)) { + inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); + sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, + sizeof(inode->i_generation), &pos); + } else + sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, + sizeof(inode->i_generation), &pos); + if (sz == sizeof(inode->i_generation)) + goto out; /* success */ + + err = sz; + if (unlikely(sz >= 0)) { + err = -EIO; + AuIOErr("xigen error (%zd)\n", sz); + } + +out: + return err; +} + +int au_xigen_set(struct super_block *sb, struct file *base) +{ + int err; + struct au_sbinfo *sbinfo; + struct file *file; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + file = au_xino_create2(base, sbinfo->si_xigen); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + err = 0; + if (sbinfo->si_xigen) + fput(sbinfo->si_xigen); + sbinfo->si_xigen = file; + +out: + return err; +} + +void au_xigen_clr(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + if (sbinfo->si_xigen) { + fput(sbinfo->si_xigen); + sbinfo->si_xigen = NULL; + } +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, + ino_t dir_ino) +{ + struct dentry *dentry, *d; + struct inode *inode; + unsigned int sigen; + + dentry = NULL; + inode = ilookup(sb, ino); + if (!inode) + goto out; + + dentry = ERR_PTR(-ESTALE); + sigen = au_sigen(sb); + if (unlikely(is_bad_inode(inode) + || IS_DEADDIR(inode) + || sigen != au_iigen(inode, NULL))) + goto out_iput; + + dentry = NULL; + if (!dir_ino || S_ISDIR(inode->i_mode)) + dentry = d_find_alias(inode); + else { + spin_lock(&inode->i_lock); + hlist_for_each_entry(d, &inode->i_dentry, d_alias) { + spin_lock(&d->d_lock); + if (!au_test_anon(d) + && d->d_parent->d_inode->i_ino == dir_ino) { + dentry = dget_dlock(d); + spin_unlock(&d->d_lock); + break; + } + spin_unlock(&d->d_lock); + } + spin_unlock(&inode->i_lock); + } + if (unlikely(dentry && au_digen_test(dentry, sigen))) { + /* need to refresh */ + dput(dentry); + dentry = NULL; + } + +out_iput: + iput(inode); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +/* todo: dirty? */ +/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ + +struct au_compare_mnt_args { + /* input */ + struct super_block *sb; + + /* output */ + struct vfsmount *mnt; +}; + +static int au_compare_mnt(struct vfsmount *mnt, void *arg) +{ + struct au_compare_mnt_args *a = arg; + + if (mnt->mnt_sb != a->sb) + return 0; + a->mnt = mntget(mnt); + return 1; +} + +static struct vfsmount *au_mnt_get(struct super_block *sb) +{ + int err; + struct path root; + struct au_compare_mnt_args args = { + .sb = sb + }; + + get_fs_root(current->fs, &root); + rcu_read_lock(); + err = iterate_mounts(au_compare_mnt, &args, root.mnt); + rcu_read_unlock(); + path_put(&root); + AuDebugOn(!err); + AuDebugOn(!args.mnt); + return args.mnt; +} + +struct au_nfsd_si_lock { + unsigned int sigen; + aufs_bindex_t bindex, br_id; + unsigned char force_lock; +}; + +static int si_nfsd_read_lock(struct super_block *sb, + struct au_nfsd_si_lock *nsi_lock) +{ + int err; + aufs_bindex_t bindex; + + si_read_lock(sb, AuLock_FLUSH); + + /* branch id may be wrapped around */ + err = 0; + bindex = au_br_index(sb, nsi_lock->br_id); + if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) + goto out; /* success */ + + err = -ESTALE; + bindex = -1; + if (!nsi_lock->force_lock) + si_read_unlock(sb); + +out: + nsi_lock->bindex = bindex; + return err; +} + +struct find_name_by_ino { + struct dir_context ctx; + int called, found; + ino_t ino; + char *name; + int namelen; +}; + +static int +find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, + ctx); + + a->called++; + if (a->ino != ino) + return 0; + + memcpy(a->name, name, namelen); + a->namelen = namelen; + a->found = 1; + return 1; +} + +static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, + struct au_nfsd_si_lock *nsi_lock) +{ + struct dentry *dentry, *parent; + struct file *file; + struct inode *dir; + struct find_name_by_ino arg = { + .ctx = { + .actor = au_diractor(find_name_by_ino) + } + }; + int err; + + parent = path->dentry; + if (nsi_lock) + si_read_unlock(parent->d_sb); + file = vfsub_dentry_open(path, au_dir_roflags); + dentry = (void *)file; + if (IS_ERR(file)) + goto out; + + dentry = ERR_PTR(-ENOMEM); + arg.name = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!arg.name)) + goto out_file; + arg.ino = ino; + arg.found = 0; + do { + arg.called = 0; + /* smp_mb(); */ + err = vfsub_iterate_dir(file, &arg.ctx); + } while (!err && !arg.found && arg.called); + dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_name; + /* instead of ENOENT */ + dentry = ERR_PTR(-ESTALE); + if (!arg.found) + goto out_name; + + /* do not call vfsub_lkup_one() */ + dir = parent->d_inode; + mutex_lock(&dir->i_mutex); + dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); + mutex_unlock(&dir->i_mutex); + AuTraceErrPtr(dentry); + if (IS_ERR(dentry)) + goto out_name; + AuDebugOn(au_test_anon(dentry)); + if (unlikely(!dentry->d_inode)) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } + +out_name: + free_page((unsigned long)arg.name); +out_file: + fput(file); +out: + if (unlikely(nsi_lock + && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) + if (!IS_ERR(dentry)) { + dput(dentry); + dentry = ERR_PTR(-ESTALE); + } + AuTraceErrPtr(dentry); + return dentry; +} + +static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, + ino_t dir_ino, + struct au_nfsd_si_lock *nsi_lock) +{ + struct dentry *dentry; + struct path path; + + if (dir_ino != AUFS_ROOT_INO) { + path.dentry = decode_by_ino(sb, dir_ino, 0); + dentry = path.dentry; + if (!path.dentry || IS_ERR(path.dentry)) + goto out; + AuDebugOn(au_test_anon(path.dentry)); + } else + path.dentry = dget(sb->s_root); + + path.mnt = au_mnt_get(sb); + dentry = au_lkup_by_ino(&path, ino, nsi_lock); + path_put(&path); + +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +static int h_acceptable(void *expv, struct dentry *dentry) +{ + return 1; +} + +static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, + char *buf, int len, struct super_block *sb) +{ + char *p; + int n; + struct path path; + + p = d_path(h_rootpath, buf, len); + if (IS_ERR(p)) + goto out; + n = strlen(p); + + path.mnt = h_rootpath->mnt; + path.dentry = h_parent; + p = d_path(&path, buf, len); + if (IS_ERR(p)) + goto out; + if (n != 1) + p += n; + + path.mnt = au_mnt_get(sb); + path.dentry = sb->s_root; + p = d_path(&path, buf, len - strlen(p)); + mntput(path.mnt); + if (IS_ERR(p)) + goto out; + if (n != 1) + p[strlen(p)] = '/'; + +out: + AuTraceErrPtr(p); + return p; +} + +static +struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, + int fh_len, struct au_nfsd_si_lock *nsi_lock) +{ + struct dentry *dentry, *h_parent, *root; + struct super_block *h_sb; + char *pathname, *p; + struct vfsmount *h_mnt; + struct au_branch *br; + int err; + struct path path; + + br = au_sbr(sb, nsi_lock->bindex); + h_mnt = au_br_mnt(br); + h_sb = h_mnt->mnt_sb; + /* todo: call lower fh_to_dentry()? fh_to_parent()? */ + h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), + fh_len - Fh_tail, fh[Fh_h_type], + h_acceptable, /*context*/NULL); + dentry = h_parent; + if (unlikely(!h_parent || IS_ERR(h_parent))) { + AuWarn1("%s decode_fh failed, %ld\n", + au_sbtype(h_sb), PTR_ERR(h_parent)); + goto out; + } + dentry = NULL; + if (unlikely(au_test_anon(h_parent))) { + AuWarn1("%s decode_fh returned a disconnected dentry\n", + au_sbtype(h_sb)); + goto out_h_parent; + } + + dentry = ERR_PTR(-ENOMEM); + pathname = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!pathname)) + goto out_h_parent; + + root = sb->s_root; + path.mnt = h_mnt; + di_read_lock_parent(root, !AuLock_IR); + path.dentry = au_h_dptr(root, nsi_lock->bindex); + di_read_unlock(root, !AuLock_IR); + p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); + dentry = (void *)p; + if (IS_ERR(p)) + goto out_pathname; + + si_read_unlock(sb); + err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_relock; + + dentry = ERR_PTR(-ENOENT); + AuDebugOn(au_test_anon(path.dentry)); + if (unlikely(!path.dentry->d_inode)) + goto out_path; + + if (ino != path.dentry->d_inode->i_ino) + dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); + else + dentry = dget(path.dentry); + +out_path: + path_put(&path); +out_relock: + if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) + if (!IS_ERR(dentry)) { + dput(dentry); + dentry = ERR_PTR(-ESTALE); + } +out_pathname: + free_page((unsigned long)pathname); +out_h_parent: + dput(h_parent); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry * +aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, + int fh_type) +{ + struct dentry *dentry; + __u32 *fh = fid->raw; + struct au_branch *br; + ino_t ino, dir_ino; + struct au_nfsd_si_lock nsi_lock = { + .force_lock = 0 + }; + + dentry = ERR_PTR(-ESTALE); + /* it should never happen, but the file handle is unreliable */ + if (unlikely(fh_len < Fh_tail)) + goto out; + nsi_lock.sigen = fh[Fh_sigen]; + nsi_lock.br_id = fh[Fh_br_id]; + + /* branch id may be wrapped around */ + br = NULL; + if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) + goto out; + nsi_lock.force_lock = 1; + + /* is this inode still cached? */ + ino = decode_ino(fh + Fh_ino); + /* it should never happen */ + if (unlikely(ino == AUFS_ROOT_INO)) + goto out; + + dir_ino = decode_ino(fh + Fh_dir_ino); + dentry = decode_by_ino(sb, ino, dir_ino); + if (IS_ERR(dentry)) + goto out_unlock; + if (dentry) + goto accept; + + /* is the parent dir cached? */ + br = au_sbr(sb, nsi_lock.bindex); + atomic_inc(&br->br_count); + dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); + if (IS_ERR(dentry)) + goto out_unlock; + if (dentry) + goto accept; + + /* lookup path */ + dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); + if (IS_ERR(dentry)) + goto out_unlock; + if (unlikely(!dentry)) + /* todo?: make it ESTALE */ + goto out_unlock; + +accept: + if (!au_digen_test(dentry, au_sigen(sb)) + && dentry->d_inode->i_generation == fh[Fh_igen]) + goto out_unlock; /* success */ + + dput(dentry); + dentry = ERR_PTR(-ESTALE); +out_unlock: + if (br) + atomic_dec(&br->br_count); + si_read_unlock(sb); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +#if 0 /* reserved for future use */ +/* support subtreecheck option */ +static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + struct dentry *parent; + __u32 *fh = fid->raw; + ino_t dir_ino; + + dir_ino = decode_ino(fh + Fh_dir_ino); + parent = decode_by_ino(sb, dir_ino, 0); + if (IS_ERR(parent)) + goto out; + if (!parent) + parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), + dir_ino, fh, fh_len); + +out: + AuTraceErrPtr(parent); + return parent; +} +#endif + +/* ---------------------------------------------------------------------- */ + +static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, + struct inode *dir) +{ + int err; + aufs_bindex_t bindex; + struct super_block *sb, *h_sb; + struct dentry *dentry, *parent, *h_parent; + struct inode *h_dir; + struct au_branch *br; + + err = -ENOSPC; + if (unlikely(*max_len <= Fh_tail)) { + AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); + goto out; + } + + err = FILEID_ROOT; + if (inode->i_ino == AUFS_ROOT_INO) { + AuDebugOn(inode->i_ino != AUFS_ROOT_INO); + goto out; + } + + h_parent = NULL; + sb = inode->i_sb; + err = si_read_lock(sb, AuLock_FLUSH); + if (unlikely(err)) + goto out; + +#ifdef CONFIG_AUFS_DEBUG + if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) + AuWarn1("NFS-exporting requires xino\n"); +#endif + err = -EIO; + parent = NULL; + ii_read_lock_child(inode); + bindex = au_ibstart(inode); + if (!dir) { + dentry = d_find_alias(inode); + if (unlikely(!dentry)) + goto out_unlock; + AuDebugOn(au_test_anon(dentry)); + parent = dget_parent(dentry); + dput(dentry); + if (unlikely(!parent)) + goto out_unlock; + dir = parent->d_inode; + } + + ii_read_lock_parent(dir); + h_dir = au_h_iptr(dir, bindex); + ii_read_unlock(dir); + if (unlikely(!h_dir)) + goto out_parent; + h_parent = d_find_alias(h_dir); + if (unlikely(!h_parent)) + goto out_hparent; + + err = -EPERM; + br = au_sbr(sb, bindex); + h_sb = au_br_sb(br); + if (unlikely(!h_sb->s_export_op)) { + AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); + goto out_hparent; + } + + fh[Fh_br_id] = br->br_id; + fh[Fh_sigen] = au_sigen(sb); + encode_ino(fh + Fh_ino, inode->i_ino); + encode_ino(fh + Fh_dir_ino, dir->i_ino); + fh[Fh_igen] = inode->i_generation; + + *max_len -= Fh_tail; + fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), + max_len, + /*connectable or subtreecheck*/0); + err = fh[Fh_h_type]; + *max_len += Fh_tail; + /* todo: macros? */ + if (err != FILEID_INVALID) + err = 99; + else + AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); + +out_hparent: + dput(h_parent); +out_parent: + dput(parent); +out_unlock: + ii_read_unlock(inode); + si_read_unlock(sb); +out: + if (unlikely(err < 0)) + err = FILEID_INVALID; + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_commit_metadata(struct inode *inode) +{ + int err; + aufs_bindex_t bindex; + struct super_block *sb; + struct inode *h_inode; + int (*f)(struct inode *inode); + + sb = inode->i_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + ii_write_lock_child(inode); + bindex = au_ibstart(inode); + AuDebugOn(bindex < 0); + h_inode = au_h_iptr(inode, bindex); + + f = h_inode->i_sb->s_export_op->commit_metadata; + if (f) + err = f(h_inode); + else { + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0 /* metadata only */ + }; + + err = sync_inode(h_inode, &wbc); + } + + au_cpup_attr_timesizes(inode); + ii_write_unlock(inode); + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct export_operations aufs_export_op = { + .fh_to_dentry = aufs_fh_to_dentry, + /* .fh_to_parent = aufs_fh_to_parent, */ + .encode_fh = aufs_encode_fh, + .commit_metadata = aufs_commit_metadata +}; + +void au_export_init(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + __u32 u; + + sb->s_export_op = &aufs_export_op; + sbinfo = au_sbi(sb); + sbinfo->si_xigen = NULL; + get_random_bytes(&u, sizeof(u)); + BUILD_BUG_ON(sizeof(u) != sizeof(int)); + atomic_set(&sbinfo->si_xigen_next, u); +} --- linux-3.13.0.orig/ubuntu/aufs/sysrq.c +++ linux-3.13.0/ubuntu/aufs/sysrq.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * magic sysrq hanlder + */ + +/* #include */ +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +static void sysrq_sb(struct super_block *sb) +{ + char *plevel; + struct au_sbinfo *sbinfo; + struct file *file; + struct au_sphlhead *files; + struct au_finfo *finfo; + + plevel = au_plevel; + au_plevel = KERN_WARNING; + + /* since we define pr_fmt, call printk directly */ +#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) + + sbinfo = au_sbi(sb); + printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); + pr("superblock\n"); + au_dpri_sb(sb); + +#if 0 + pr("root dentry\n"); + au_dpri_dentry(sb->s_root); + pr("root inode\n"); + au_dpri_inode(sb->s_root->d_inode); +#endif + +#if 0 + do { + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + + err = au_dpages_init(&dpages, GFP_ATOMIC); + if (unlikely(err)) + break; + err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); + if (!err) + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) + au_dpri_dentry(dpage->dentries[j]); + } + au_dpages_free(&dpages); + } while (0); +#endif + +#if 1 + { + struct inode *i; + pr("isolated inode\n"); + spin_lock(&inode_sb_list_lock); + list_for_each_entry(i, &sb->s_inodes, i_sb_list) { + spin_lock(&i->i_lock); + if (1 || hlist_empty(&i->i_dentry)) + au_dpri_inode(i); + spin_unlock(&i->i_lock); + } + spin_unlock(&inode_sb_list_lock); + } +#endif + pr("files\n"); + files = &au_sbi(sb)->si_files; + spin_lock(&files->spin); + hlist_for_each_entry(finfo, &files->head, fi_hlist) { + umode_t mode; + file = finfo->fi_file; + mode = file_inode(file)->i_mode; + if (!special_file(mode) || au_special_file(mode)) + au_dpri_file(file); + } + spin_unlock(&files->spin); + pr("done\n"); + +#undef pr + au_plevel = plevel; +} + +/* ---------------------------------------------------------------------- */ + +/* module parameter */ +static char *aufs_sysrq_key = "a"; +module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); +MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); + +static void au_sysrq(int key __maybe_unused) +{ + struct au_sbinfo *sbinfo; + + lockdep_off(); + au_sbilist_lock(); + list_for_each_entry(sbinfo, &au_sbilist.head, si_list) + sysrq_sb(sbinfo->si_sb); + au_sbilist_unlock(); + lockdep_on(); +} + +static struct sysrq_key_op au_sysrq_op = { + .handler = au_sysrq, + .help_msg = "Aufs", + .action_msg = "Aufs", + .enable_mask = SYSRQ_ENABLE_DUMP +}; + +/* ---------------------------------------------------------------------- */ + +int __init au_sysrq_init(void) +{ + int err; + char key; + + err = -1; + key = *aufs_sysrq_key; + if ('a' <= key && key <= 'z') + err = register_sysrq_key(key, &au_sysrq_op); + if (unlikely(err)) + pr_err("err %d, sysrq=%c\n", err, key); + return err; +} + +void au_sysrq_fin(void) +{ + int err; + err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); + if (unlikely(err)) + pr_err("err %d (ignored)\n", err); +} --- linux-3.13.0.orig/ubuntu/aufs/xino.c +++ linux-3.13.0/ubuntu/aufs/xino.c @@ -0,0 +1,1314 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * external inode number translation table and bitmap + */ + +#include +#include +#include "aufs.h" + +/* todo: unnecessary to support mmap_sem since kernel-space? */ +ssize_t xino_fread(au_readf_t func, struct file *file, void *kbuf, size_t size, + loff_t *pos) +{ + ssize_t err; + mm_segment_t oldfs; + union { + void *k; + char __user *u; + } buf; + + buf.k = kbuf; + oldfs = get_fs(); + set_fs(KERNEL_DS); + do { + /* todo: signal_pending? */ + err = func(file, buf.u, size, pos); + } while (err == -EAGAIN || err == -EINTR); + set_fs(oldfs); + +#if 0 /* reserved for future use */ + if (err > 0) + fsnotify_access(file->f_dentry); +#endif + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *kbuf, + size_t size, loff_t *pos) +{ + ssize_t err; + mm_segment_t oldfs; + union { + void *k; + const char __user *u; + } buf; + + buf.k = kbuf; + oldfs = get_fs(); + set_fs(KERNEL_DS); + do { + /* todo: signal_pending? */ + err = func(file, buf.u, size, pos); + } while (err == -EAGAIN || err == -EINTR); + set_fs(oldfs); + +#if 0 /* reserved for future use */ + if (err > 0) + fsnotify_modify(file->f_dentry); +#endif + + return err; +} + +struct do_xino_fwrite_args { + ssize_t *errp; + au_writef_t func; + struct file *file; + void *buf; + size_t size; + loff_t *pos; +}; + +static void call_do_xino_fwrite(void *args) +{ + struct do_xino_fwrite_args *a = args; + *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); +} + +ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, + loff_t *pos) +{ + ssize_t err; + + /* todo: signal block and no wkq? */ + if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { + lockdep_off(); + err = do_xino_fwrite(func, file, buf, size, pos); + lockdep_on(); + } else { + /* + * it breaks RLIMIT_FSIZE and normal user's limit, + * users should care about quota and real 'filesystem full.' + */ + int wkq_err; + struct do_xino_fwrite_args args = { + .errp = &err, + .func = func, + .file = file, + .buf = buf, + .size = size, + .pos = pos + }; + + wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * create a new xinofile at the same place/path as @base_file. + */ +struct file *au_xino_create2(struct file *base_file, struct file *copy_src) +{ + struct file *file; + struct dentry *base, *parent; + struct inode *dir, *delegated; + struct qstr *name; + struct path path; + int err; + + base = base_file->f_dentry; + parent = base->d_parent; /* dir inode is locked */ + dir = parent->d_inode; + IMustLock(dir); + + file = ERR_PTR(-EINVAL); + name = &base->d_name; + path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); + if (IS_ERR(path.dentry)) { + file = (void *)path.dentry; + pr_err("%pd lookup err %ld\n", + base, PTR_ERR(path.dentry)); + goto out; + } + + /* no need to mnt_want_write() since we call dentry_open() later */ + err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL); + if (unlikely(err)) { + file = ERR_PTR(err); + pr_err("%pd create err %d\n", base, err); + goto out_dput; + } + + path.mnt = base_file->f_path.mnt; + file = vfsub_dentry_open(&path, + O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE + /* | __FMODE_NONOTIFY */); + if (IS_ERR(file)) { + pr_err("%pd open err %ld\n", base, PTR_ERR(file)); + goto out_dput; + } + + delegated = NULL; + err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + if (unlikely(err)) { + pr_err("%pd unlink err %d\n", base, err); + goto out_fput; + } + + if (copy_src) { + /* no one can touch copy_src xino */ + err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); + if (unlikely(err)) { + pr_err("%pd copy err %d\n", base, err); + goto out_fput; + } + } + goto out_dput; /* success */ + +out_fput: + fput(file); + file = ERR_PTR(err); +out_dput: + dput(path.dentry); +out: + return file; +} + +struct au_xino_lock_dir { + struct au_hinode *hdir; + struct dentry *parent; + struct mutex *mtx; +}; + +static void au_xino_lock_dir(struct super_block *sb, struct file *xino, + struct au_xino_lock_dir *ldir) +{ + aufs_bindex_t brid, bindex; + + ldir->hdir = NULL; + bindex = -1; + brid = au_xino_brid(sb); + if (brid >= 0) + bindex = au_br_index(sb, brid); + if (bindex >= 0) { + ldir->hdir = au_hi(sb->s_root->d_inode, bindex); + au_hn_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT); + } else { + ldir->parent = dget_parent(xino->f_dentry); + ldir->mtx = &ldir->parent->d_inode->i_mutex; + mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT); + } +} + +static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) +{ + if (ldir->hdir) + au_hn_imtx_unlock(ldir->hdir); + else { + mutex_unlock(ldir->mtx); + dput(ldir->parent); + } +} + +/* ---------------------------------------------------------------------- */ + +/* trucate xino files asynchronously */ + +int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) +{ + int err; + unsigned long jiffy; + blkcnt_t blocks; + aufs_bindex_t bi, bend; + struct kstatfs *st; + struct au_branch *br; + struct file *new_xino, *file; + struct super_block *h_sb; + struct au_xino_lock_dir ldir; + + err = -ENOMEM; + st = kzalloc(sizeof(*st), GFP_NOFS); + if (unlikely(!st)) + goto out; + + err = -EINVAL; + bend = au_sbend(sb); + if (unlikely(bindex < 0 || bend < bindex)) + goto out_st; + br = au_sbr(sb, bindex); + file = br->br_xino.xi_file; + if (!file) + goto out_st; + + err = vfs_statfs(&file->f_path, st); + if (unlikely(err)) + AuErr1("statfs err %d, ignored\n", err); + jiffy = jiffies; + blocks = file_inode(file)->i_blocks; + pr_info("begin truncating xino(b%d), ib%llu, %llu/%llu free blks\n", + bindex, (u64)blocks, st->f_bfree, st->f_blocks); + + au_xino_lock_dir(sb, file, &ldir); + /* mnt_want_write() is unnecessary here */ + new_xino = au_xino_create2(file, file); + au_xino_unlock_dir(&ldir); + err = PTR_ERR(new_xino); + if (IS_ERR(new_xino)) { + pr_err("err %d, ignored\n", err); + goto out_st; + } + err = 0; + fput(file); + br->br_xino.xi_file = new_xino; + + h_sb = au_br_sb(br); + for (bi = 0; bi <= bend; bi++) { + if (unlikely(bi == bindex)) + continue; + br = au_sbr(sb, bi); + if (au_br_sb(br) != h_sb) + continue; + + fput(br->br_xino.xi_file); + br->br_xino.xi_file = new_xino; + get_file(new_xino); + } + + err = vfs_statfs(&new_xino->f_path, st); + if (!err) { + pr_info("end truncating xino(b%d), ib%llu, %llu/%llu free blks\n", + bindex, (u64)file_inode(new_xino)->i_blocks, + st->f_bfree, st->f_blocks); + if (file_inode(new_xino)->i_blocks < blocks) + au_sbi(sb)->si_xino_jiffy = jiffy; + } else + AuErr1("statfs err %d, ignored\n", err); + +out_st: + kfree(st); +out: + return err; +} + +struct xino_do_trunc_args { + struct super_block *sb; + struct au_branch *br; +}; + +static void xino_do_trunc(void *_args) +{ + struct xino_do_trunc_args *args = _args; + struct super_block *sb; + struct au_branch *br; + struct inode *dir; + int err; + aufs_bindex_t bindex; + + err = 0; + sb = args->sb; + dir = sb->s_root->d_inode; + br = args->br; + + si_noflush_write_lock(sb); + ii_read_lock_parent(dir); + bindex = au_br_index(sb, br->br_id); + err = au_xino_trunc(sb, bindex); + ii_read_unlock(dir); + if (unlikely(err)) + pr_warn("err b%d, (%d)\n", bindex, err); + atomic_dec(&br->br_xino_running); + atomic_dec(&br->br_count); + si_write_unlock(sb); + au_nwt_done(&au_sbi(sb)->si_nowait); + kfree(args); +} + +static int xino_trunc_test(struct super_block *sb, struct au_branch *br) +{ + int err; + struct kstatfs st; + struct au_sbinfo *sbinfo; + + /* todo: si_xino_expire and the ratio should be customizable */ + sbinfo = au_sbi(sb); + if (time_before(jiffies, + sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) + return 0; + + /* truncation border */ + err = vfs_statfs(&br->br_xino.xi_file->f_path, &st); + if (unlikely(err)) { + AuErr1("statfs err %d, ignored\n", err); + return 0; + } + if (div64_u64(st.f_bfree * 100, st.f_blocks) >= AUFS_XINO_DEF_TRUNC) + return 0; + + return 1; +} + +static void xino_try_trunc(struct super_block *sb, struct au_branch *br) +{ + struct xino_do_trunc_args *args; + int wkq_err; + + if (!xino_trunc_test(sb, br)) + return; + + if (atomic_inc_return(&br->br_xino_running) > 1) + goto out; + + /* lock and kfree() will be called in trunc_xino() */ + args = kmalloc(sizeof(*args), GFP_NOFS); + if (unlikely(!args)) { + AuErr1("no memory\n"); + goto out_args; + } + + atomic_inc(&br->br_count); + args->sb = sb; + args->br = br; + wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); + if (!wkq_err) + return; /* success */ + + pr_err("wkq %d\n", wkq_err); + atomic_dec(&br->br_count); + +out_args: + kfree(args); +out: + atomic_dec(&br->br_xino_running); +} + +/* ---------------------------------------------------------------------- */ + +static int au_xino_do_write(au_writef_t write, struct file *file, + ino_t h_ino, ino_t ino) +{ + loff_t pos; + ssize_t sz; + + pos = h_ino; + if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) { + AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); + return -EFBIG; + } + pos *= sizeof(ino); + sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos); + if (sz == sizeof(ino)) + return 0; /* success */ + + AuIOErr("write failed (%zd)\n", sz); + return -EIO; +} + +/* + * write @ino to the xinofile for the specified branch{@sb, @bindex} + * at the position of @h_ino. + * even if @ino is zero, it is written to the xinofile and means no entry. + * if the size of the xino file on a specific filesystem exceeds the watermark, + * try truncating it. + */ +int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t ino) +{ + int err; + unsigned int mnt_flags; + struct au_branch *br; + + BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max) + || ((loff_t)-1) > 0); + SiMustAnyLock(sb); + + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, XINO)) + return 0; + + br = au_sbr(sb, bindex); + err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, + h_ino, ino); + if (!err) { + if (au_opt_test(mnt_flags, TRUNC_XINO) + && au_test_fs_trunc_xino(au_br_sb(br))) + xino_try_trunc(sb, br); + return 0; /* success */ + } + + AuIOErr("write failed (%d)\n", err); + return -EIO; +} + +/* ---------------------------------------------------------------------- */ + +/* aufs inode number bitmap */ + +static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; +static ino_t xib_calc_ino(unsigned long pindex, int bit) +{ + ino_t ino; + + AuDebugOn(bit < 0 || page_bits <= bit); + ino = AUFS_FIRST_INO + pindex * page_bits + bit; + return ino; +} + +static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) +{ + AuDebugOn(ino < AUFS_FIRST_INO); + ino -= AUFS_FIRST_INO; + *pindex = ino / page_bits; + *bit = ino % page_bits; +} + +static int xib_pindex(struct super_block *sb, unsigned long pindex) +{ + int err; + loff_t pos; + ssize_t sz; + struct au_sbinfo *sbinfo; + struct file *xib; + unsigned long *p; + + sbinfo = au_sbi(sb); + MtxMustLock(&sbinfo->si_xib_mtx); + AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE + || !au_opt_test(sbinfo->si_mntflags, XINO)); + + if (pindex == sbinfo->si_xib_last_pindex) + return 0; + + xib = sbinfo->si_xib; + p = sbinfo->si_xib_buf; + pos = sbinfo->si_xib_last_pindex; + pos *= PAGE_SIZE; + sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); + if (unlikely(sz != PAGE_SIZE)) + goto out; + + pos = pindex; + pos *= PAGE_SIZE; + if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) + sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); + else { + memset(p, 0, PAGE_SIZE); + sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); + } + if (sz == PAGE_SIZE) { + sbinfo->si_xib_last_pindex = pindex; + return 0; /* success */ + } + +out: + AuIOErr1("write failed (%zd)\n", sz); + err = sz; + if (sz >= 0) + err = -EIO; + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void au_xib_clear_bit(struct inode *inode) +{ + int err, bit; + unsigned long pindex; + struct super_block *sb; + struct au_sbinfo *sbinfo; + + AuDebugOn(inode->i_nlink); + + sb = inode->i_sb; + xib_calc_bit(inode->i_ino, &pindex, &bit); + AuDebugOn(page_bits <= bit); + sbinfo = au_sbi(sb); + mutex_lock(&sbinfo->si_xib_mtx); + err = xib_pindex(sb, pindex); + if (!err) { + clear_bit(bit, sbinfo->si_xib_buf); + sbinfo->si_xib_next_bit = bit; + } + mutex_unlock(&sbinfo->si_xib_mtx); +} + +/* for s_op->delete_inode() */ +void au_xino_delete_inode(struct inode *inode, const int unlinked) +{ + int err; + unsigned int mnt_flags; + aufs_bindex_t bindex, bend, bi; + unsigned char try_trunc; + struct au_iinfo *iinfo; + struct super_block *sb; + struct au_hinode *hi; + struct inode *h_inode; + struct au_branch *br; + au_writef_t xwrite; + + sb = inode->i_sb; + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, XINO) + || inode->i_ino == AUFS_ROOT_INO) + return; + + if (unlinked) { + au_xigen_inc(inode); + au_xib_clear_bit(inode); + } + + iinfo = au_ii(inode); + if (!iinfo) + return; + + bindex = iinfo->ii_bstart; + if (bindex < 0) + return; + + xwrite = au_sbi(sb)->si_xwrite; + try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); + hi = iinfo->ii_hinode + bindex; + bend = iinfo->ii_bend; + for (; bindex <= bend; bindex++, hi++) { + h_inode = hi->hi_inode; + if (!h_inode + || (!unlinked && h_inode->i_nlink)) + continue; + + /* inode may not be revalidated */ + bi = au_br_index(sb, hi->hi_id); + if (bi < 0) + continue; + + br = au_sbr(sb, bi); + err = au_xino_do_write(xwrite, br->br_xino.xi_file, + h_inode->i_ino, /*ino*/0); + if (!err && try_trunc + && au_test_fs_trunc_xino(au_br_sb(br))) + xino_try_trunc(sb, br); + } +} + +/* get an unused inode number from bitmap */ +ino_t au_xino_new_ino(struct super_block *sb) +{ + ino_t ino; + unsigned long *p, pindex, ul, pend; + struct au_sbinfo *sbinfo; + struct file *file; + int free_bit, err; + + if (!au_opt_test(au_mntflags(sb), XINO)) + return iunique(sb, AUFS_FIRST_INO); + + sbinfo = au_sbi(sb); + mutex_lock(&sbinfo->si_xib_mtx); + p = sbinfo->si_xib_buf; + free_bit = sbinfo->si_xib_next_bit; + if (free_bit < page_bits && !test_bit(free_bit, p)) + goto out; /* success */ + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + + pindex = sbinfo->si_xib_last_pindex; + for (ul = pindex - 1; ul < ULONG_MAX; ul--) { + err = xib_pindex(sb, ul); + if (unlikely(err)) + goto out_err; + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + } + + file = sbinfo->si_xib; + pend = vfsub_f_size_read(file) / PAGE_SIZE; + for (ul = pindex + 1; ul <= pend; ul++) { + err = xib_pindex(sb, ul); + if (unlikely(err)) + goto out_err; + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + } + BUG(); + +out: + set_bit(free_bit, p); + sbinfo->si_xib_next_bit = free_bit + 1; + pindex = sbinfo->si_xib_last_pindex; + mutex_unlock(&sbinfo->si_xib_mtx); + ino = xib_calc_ino(pindex, free_bit); + AuDbg("i%lu\n", (unsigned long)ino); + return ino; +out_err: + mutex_unlock(&sbinfo->si_xib_mtx); + AuDbg("i0\n"); + return 0; +} + +/* + * read @ino from xinofile for the specified branch{@sb, @bindex} + * at the position of @h_ino. + * if @ino does not exist and @do_new is true, get new one. + */ +int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t *ino) +{ + int err; + ssize_t sz; + loff_t pos; + struct file *file; + struct au_sbinfo *sbinfo; + + *ino = 0; + if (!au_opt_test(au_mntflags(sb), XINO)) + return 0; /* no xino */ + + err = 0; + sbinfo = au_sbi(sb); + pos = h_ino; + if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) { + AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); + return -EFBIG; + } + pos *= sizeof(*ino); + + file = au_sbr(sb, bindex)->br_xino.xi_file; + if (vfsub_f_size_read(file) < pos + sizeof(*ino)) + return 0; /* no ino */ + + sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos); + if (sz == sizeof(*ino)) + return 0; /* success */ + + err = sz; + if (unlikely(sz >= 0)) { + err = -EIO; + AuIOErr("xino read error (%zd)\n", sz); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* create and set a new xino file */ + +struct file *au_xino_create(struct super_block *sb, char *fname, int silent) +{ + struct file *file; + struct dentry *h_parent, *d; + struct inode *h_dir; + int err; + + /* + * at mount-time, and the xino file is the default path, + * hnotify is disabled so we have no notify events to ignore. + * when a user specified the xino, we cannot get au_hdir to be ignored. + */ + file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE + /* | __FMODE_NONOTIFY */, + S_IRUGO | S_IWUGO); + if (IS_ERR(file)) { + if (!silent) + pr_err("open %s(%ld)\n", fname, PTR_ERR(file)); + return file; + } + + /* keep file count */ + h_parent = dget_parent(file->f_dentry); + h_dir = h_parent->d_inode; + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + /* mnt_want_write() is unnecessary here */ + /* no delegation since it is just created */ + err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, /*force*/0); + mutex_unlock(&h_dir->i_mutex); + dput(h_parent); + if (unlikely(err)) { + if (!silent) + pr_err("unlink %s(%d)\n", fname, err); + goto out; + } + + err = -EINVAL; + d = file->f_dentry; + if (unlikely(sb == d->d_sb)) { + if (!silent) + pr_err("%s must be outside\n", fname); + goto out; + } + if (unlikely(au_test_fs_bad_xino(d->d_sb))) { + if (!silent) + pr_err("xino doesn't support %s(%s)\n", + fname, au_sbtype(d->d_sb)); + goto out; + } + return file; /* success */ + +out: + fput(file); + file = ERR_PTR(err); + return file; +} + +/* + * find another branch who is on the same filesystem of the specified + * branch{@btgt}. search until @bend. + */ +static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, + aufs_bindex_t bend) +{ + aufs_bindex_t bindex; + struct super_block *tgt_sb = au_sbr_sb(sb, btgt); + + for (bindex = 0; bindex < btgt; bindex++) + if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) + return bindex; + for (bindex++; bindex <= bend; bindex++) + if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) + return bindex; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/* + * initialize the xinofile for the specified branch @br + * at the place/path where @base_file indicates. + * test whether another branch is on the same filesystem or not, + * if @do_test is true. + */ +int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, + struct file *base_file, int do_test) +{ + int err; + ino_t ino; + aufs_bindex_t bend, bindex; + struct au_branch *shared_br, *b; + struct file *file; + struct super_block *tgt_sb; + + shared_br = NULL; + bend = au_sbend(sb); + if (do_test) { + tgt_sb = au_br_sb(br); + for (bindex = 0; bindex <= bend; bindex++) { + b = au_sbr(sb, bindex); + if (tgt_sb == au_br_sb(b)) { + shared_br = b; + break; + } + } + } + + if (!shared_br || !shared_br->br_xino.xi_file) { + struct au_xino_lock_dir ldir; + + au_xino_lock_dir(sb, base_file, &ldir); + /* mnt_want_write() is unnecessary here */ + file = au_xino_create2(base_file, NULL); + au_xino_unlock_dir(&ldir); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + br->br_xino.xi_file = file; + } else { + br->br_xino.xi_file = shared_br->br_xino.xi_file; + get_file(br->br_xino.xi_file); + } + + ino = AUFS_ROOT_INO; + err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, + h_ino, ino); + if (unlikely(err)) { + fput(br->br_xino.xi_file); + br->br_xino.xi_file = NULL; + } + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* trucate a xino bitmap file */ + +/* todo: slow */ +static int do_xib_restore(struct super_block *sb, struct file *file, void *page) +{ + int err, bit; + ssize_t sz; + unsigned long pindex; + loff_t pos, pend; + struct au_sbinfo *sbinfo; + au_readf_t func; + ino_t *ino; + unsigned long *p; + + err = 0; + sbinfo = au_sbi(sb); + MtxMustLock(&sbinfo->si_xib_mtx); + p = sbinfo->si_xib_buf; + func = sbinfo->si_xread; + pend = vfsub_f_size_read(file); + pos = 0; + while (pos < pend) { + sz = xino_fread(func, file, page, PAGE_SIZE, &pos); + err = sz; + if (unlikely(sz <= 0)) + goto out; + + err = 0; + for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { + if (unlikely(*ino < AUFS_FIRST_INO)) + continue; + + xib_calc_bit(*ino, &pindex, &bit); + AuDebugOn(page_bits <= bit); + err = xib_pindex(sb, pindex); + if (!err) + set_bit(bit, p); + else + goto out; + } + } + +out: + return err; +} + +static int xib_restore(struct super_block *sb) +{ + int err; + aufs_bindex_t bindex, bend; + void *page; + + err = -ENOMEM; + page = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!page)) + goto out; + + err = 0; + bend = au_sbend(sb); + for (bindex = 0; !err && bindex <= bend; bindex++) + if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) + err = do_xib_restore + (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); + else + AuDbg("b%d\n", bindex); + free_page((unsigned long)page); + +out: + return err; +} + +int au_xib_trunc(struct super_block *sb) +{ + int err; + ssize_t sz; + loff_t pos; + struct au_xino_lock_dir ldir; + struct au_sbinfo *sbinfo; + unsigned long *p; + struct file *file; + + SiMustWriteLock(sb); + + err = 0; + sbinfo = au_sbi(sb); + if (!au_opt_test(sbinfo->si_mntflags, XINO)) + goto out; + + file = sbinfo->si_xib; + if (vfsub_f_size_read(file) <= PAGE_SIZE) + goto out; + + au_xino_lock_dir(sb, file, &ldir); + /* mnt_want_write() is unnecessary here */ + file = au_xino_create2(sbinfo->si_xib, NULL); + au_xino_unlock_dir(&ldir); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + fput(sbinfo->si_xib); + sbinfo->si_xib = file; + + p = sbinfo->si_xib_buf; + memset(p, 0, PAGE_SIZE); + pos = 0; + sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); + if (unlikely(sz != PAGE_SIZE)) { + err = sz; + AuIOErr("err %d\n", err); + if (sz >= 0) + err = -EIO; + goto out; + } + + mutex_lock(&sbinfo->si_xib_mtx); + /* mnt_want_write() is unnecessary here */ + err = xib_restore(sb); + mutex_unlock(&sbinfo->si_xib_mtx); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * xino mount option handlers + */ +static au_readf_t find_readf(struct file *h_file) +{ + const struct file_operations *fop = h_file->f_op; + + if (fop->read) + return fop->read; + if (fop->aio_read) + return do_sync_read; + return ERR_PTR(-ENOSYS); +} + +static au_writef_t find_writef(struct file *h_file) +{ + const struct file_operations *fop = h_file->f_op; + + if (fop->write) + return fop->write; + if (fop->aio_write) + return do_sync_write; + return ERR_PTR(-ENOSYS); +} + +/* xino bitmap */ +static void xino_clear_xib(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + sbinfo->si_xread = NULL; + sbinfo->si_xwrite = NULL; + if (sbinfo->si_xib) + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; + free_page((unsigned long)sbinfo->si_xib_buf); + sbinfo->si_xib_buf = NULL; +} + +static int au_xino_set_xib(struct super_block *sb, struct file *base) +{ + int err; + loff_t pos; + struct au_sbinfo *sbinfo; + struct file *file; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + file = au_xino_create2(base, sbinfo->si_xib); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + if (sbinfo->si_xib) + fput(sbinfo->si_xib); + sbinfo->si_xib = file; + sbinfo->si_xread = find_readf(file); + sbinfo->si_xwrite = find_writef(file); + + err = -ENOMEM; + if (!sbinfo->si_xib_buf) + sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); + if (unlikely(!sbinfo->si_xib_buf)) + goto out_unset; + + sbinfo->si_xib_last_pindex = 0; + sbinfo->si_xib_next_bit = 0; + if (vfsub_f_size_read(file) < PAGE_SIZE) { + pos = 0; + err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, + PAGE_SIZE, &pos); + if (unlikely(err != PAGE_SIZE)) + goto out_free; + } + err = 0; + goto out; /* success */ + +out_free: + free_page((unsigned long)sbinfo->si_xib_buf); + sbinfo->si_xib_buf = NULL; + if (err >= 0) + err = -EIO; +out_unset: + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; + sbinfo->si_xread = NULL; + sbinfo->si_xwrite = NULL; +out: + return err; +} + +/* xino for each branch */ +static void xino_clear_br(struct super_block *sb) +{ + aufs_bindex_t bindex, bend; + struct au_branch *br; + + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (!br || !br->br_xino.xi_file) + continue; + + fput(br->br_xino.xi_file); + br->br_xino.xi_file = NULL; + } +} + +static int au_xino_set_br(struct super_block *sb, struct file *base) +{ + int err; + ino_t ino; + aufs_bindex_t bindex, bend, bshared; + struct { + struct file *old, *new; + } *fpair, *p; + struct au_branch *br; + struct inode *inode; + au_writef_t writef; + + SiMustWriteLock(sb); + + err = -ENOMEM; + bend = au_sbend(sb); + fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS); + if (unlikely(!fpair)) + goto out; + + inode = sb->s_root->d_inode; + ino = AUFS_ROOT_INO; + writef = au_sbi(sb)->si_xwrite; + for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { + br = au_sbr(sb, bindex); + bshared = is_sb_shared(sb, bindex, bindex - 1); + if (bshared >= 0) { + /* shared xino */ + *p = fpair[bshared]; + get_file(p->new); + } + + if (!p->new) { + /* new xino */ + p->old = br->br_xino.xi_file; + p->new = au_xino_create2(base, br->br_xino.xi_file); + err = PTR_ERR(p->new); + if (IS_ERR(p->new)) { + p->new = NULL; + goto out_pair; + } + } + + err = au_xino_do_write(writef, p->new, + au_h_iptr(inode, bindex)->i_ino, ino); + if (unlikely(err)) + goto out_pair; + } + + for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { + br = au_sbr(sb, bindex); + if (br->br_xino.xi_file) + fput(br->br_xino.xi_file); + get_file(p->new); + br->br_xino.xi_file = p->new; + } + +out_pair: + for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) + if (p->new) + fput(p->new); + else + break; + kfree(fpair); +out: + return err; +} + +void au_xino_clr(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + au_xigen_clr(sb); + xino_clear_xib(sb); + xino_clear_br(sb); + sbinfo = au_sbi(sb); + /* lvalue, do not call au_mntflags() */ + au_opt_clr(sbinfo->si_mntflags, XINO); +} + +int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) +{ + int err, skip; + struct dentry *parent, *cur_parent; + struct qstr *dname, *cur_name; + struct file *cur_xino; + struct inode *dir; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + err = 0; + sbinfo = au_sbi(sb); + parent = dget_parent(xino->file->f_dentry); + if (remount) { + skip = 0; + dname = &xino->file->f_dentry->d_name; + cur_xino = sbinfo->si_xib; + if (cur_xino) { + cur_parent = dget_parent(cur_xino->f_dentry); + cur_name = &cur_xino->f_dentry->d_name; + skip = (cur_parent == parent + && dname->len == cur_name->len + && !memcmp(dname->name, cur_name->name, + dname->len)); + dput(cur_parent); + } + if (skip) + goto out; + } + + au_opt_set(sbinfo->si_mntflags, XINO); + dir = parent->d_inode; + mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); + /* mnt_want_write() is unnecessary here */ + err = au_xino_set_xib(sb, xino->file); + if (!err) + err = au_xigen_set(sb, xino->file); + if (!err) + err = au_xino_set_br(sb, xino->file); + mutex_unlock(&dir->i_mutex); + if (!err) + goto out; /* success */ + + /* reset all */ + AuIOErr("failed creating xino(%d).\n", err); + +out: + dput(parent); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * create a xinofile at the default place/path. + */ +struct file *au_xino_def(struct super_block *sb) +{ + struct file *file; + char *page, *p; + struct au_branch *br; + struct super_block *h_sb; + struct path path; + aufs_bindex_t bend, bindex, bwr; + + br = NULL; + bend = au_sbend(sb); + bwr = -1; + for (bindex = 0; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_writable(br->br_perm) + && !au_test_fs_bad_xino(au_br_sb(br))) { + bwr = bindex; + break; + } + } + + if (bwr >= 0) { + file = ERR_PTR(-ENOMEM); + page = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!page)) + goto out; + path.mnt = au_br_mnt(br); + path.dentry = au_h_dptr(sb->s_root, bwr); + p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); + file = (void *)p; + if (!IS_ERR(p)) { + strcat(p, "/" AUFS_XINO_FNAME); + AuDbg("%s\n", p); + file = au_xino_create(sb, p, /*silent*/0); + if (!IS_ERR(file)) + au_xino_brid_set(sb, br->br_id); + } + free_page((unsigned long)page); + } else { + file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0); + if (IS_ERR(file)) + goto out; + h_sb = file->f_dentry->d_sb; + if (unlikely(au_test_fs_bad_xino(h_sb))) { + pr_err("xino doesn't support %s(%s)\n", + AUFS_XINO_DEFPATH, au_sbtype(h_sb)); + fput(file); + file = ERR_PTR(-EINVAL); + } + if (!IS_ERR(file)) + au_xino_brid_set(sb, -1); + } + +out: + return file; +} + +/* ---------------------------------------------------------------------- */ + +int au_xino_path(struct seq_file *seq, struct file *file) +{ + int err; + + err = au_seq_path(seq, &file->f_path); + if (unlikely(err < 0)) + goto out; + + err = 0; +#define Deleted "\\040(deleted)" + seq->count -= sizeof(Deleted) - 1; + AuDebugOn(memcmp(seq->buf + seq->count, Deleted, + sizeof(Deleted) - 1)); +#undef Deleted + +out: + return err; +} --- linux-3.13.0.orig/ubuntu/aufs/Kconfig +++ linux-3.13.0/ubuntu/aufs/Kconfig @@ -0,0 +1,179 @@ +config AUFS_FS + tristate "Aufs (Advanced multi layered unification filesystem) support" + help + Aufs is a stackable unification filesystem such as Unionfs, + which unifies several directories and provides a merged single + directory. + In the early days, aufs was entirely re-designed and + re-implemented Unionfs Version 1.x series. Introducing many + original ideas, approaches and improvements, it becomes totally + different from Unionfs while keeping the basic features. + +if AUFS_FS +choice + prompt "Maximum number of branches" + default AUFS_BRANCH_MAX_127 + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_127 + bool "127" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_511 + bool "511" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_1023 + bool "1023" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_32767 + bool "32767" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +endchoice + +config AUFS_SBILIST + bool + depends on AUFS_MAGIC_SYSRQ || PROC_FS + default y + help + Automatic configuration for internal use. + When aufs supports Magic SysRq or /proc, enabled automatically. + +config AUFS_HNOTIFY + bool "Detect direct branch access (bypassing aufs)" + help + If you want to modify files on branches directly, eg. bypassing aufs, + and want aufs to detect the changes of them fully, then enable this + option and use 'udba=notify' mount option. + Currently there is only one available configuration, "fsnotify". + It will have a negative impact to the performance. + See detail in aufs.5. + +choice + prompt "method" if AUFS_HNOTIFY + default AUFS_HFSNOTIFY +config AUFS_HFSNOTIFY + bool "fsnotify" + select FSNOTIFY +endchoice + +config AUFS_EXPORT + bool "NFS-exportable aufs" + depends on EXPORTFS + help + If you want to export your mounted aufs via NFS, then enable this + option. There are several requirements for this configuration. + See detail in aufs.5. + +config AUFS_INO_T_64 + bool + depends on AUFS_EXPORT + depends on 64BIT && !(ALPHA || S390) + default y + help + Automatic configuration for internal use. + /* typedef unsigned long/int __kernel_ino_t */ + /* alpha and s390x are int */ + +config AUFS_RDU + bool "Readdir in userspace" + help + Aufs has two methods to provide a merged view for a directory, + by a user-space library and by kernel-space natively. The latter + is always enabled but sometimes large and slow. + If you enable this option, install the library in aufs2-util + package, and set some environment variables for your readdir(3), + then the work will be handled in user-space which generally + shows better performance in most cases. + See detail in aufs.5. + +config AUFS_SP_IATTR + bool "Respect the attributes (mtime/ctime mainly) of special files" + help + When you write something to a special file, some attributes of it + (mtime/ctime mainly) may be updated. Generally such updates are + less important (actually some device drivers and NFS ignore + it). But some applications (such like test program) requires + such updates. If you need these updates, then enable this + configuration which introduces some overhead. + Currently this configuration handles FIFO only. + +config AUFS_SHWH + bool "Show whiteouts" + help + If you want to make the whiteouts in aufs visible, then enable + this option and specify 'shwh' mount option. Although it may + sounds like philosophy or something, but in technically it + simply shows the name of whiteout with keeping its behaviour. + +config AUFS_BR_RAMFS + bool "Ramfs (initramfs/rootfs) as an aufs branch" + help + If you want to use ramfs as an aufs branch fs, then enable this + option. Generally tmpfs is recommended. + Aufs prohibited them to be a branch fs by default, because + initramfs becomes unusable after switch_root or something + generally. If you sets initramfs as an aufs branch and boot your + system by switch_root, you will meet a problem easily since the + files in initramfs may be inaccessible. + Unless you are going to use ramfs as an aufs branch fs without + switch_root or something, leave it N. + +config AUFS_BR_FUSE + bool "Fuse fs as an aufs branch" + depends on FUSE_FS + select AUFS_POLL + help + If you want to use fuse-based userspace filesystem as an aufs + branch fs, then enable this option. + It implements the internal poll(2) operation which is + implemented by fuse only (curretnly). + +config AUFS_POLL + bool + help + Automatic configuration for internal use. + +config AUFS_BR_HFSPLUS + bool "Hfsplus as an aufs branch" + depends on HFSPLUS_FS + default y + help + If you want to use hfsplus fs as an aufs branch fs, then enable + this option. This option introduces a small overhead at + copying-up a file on hfsplus. + +config AUFS_BDEV_LOOP + bool + depends on BLK_DEV_LOOP + default y + help + Automatic configuration for internal use. + Convert =[ym] into =y. + +config AUFS_DEBUG + bool "Debug aufs" + help + Enable this to compile aufs internal debug code. + It will have a negative impact to the performance. + +config AUFS_MAGIC_SYSRQ + bool + depends on AUFS_DEBUG && MAGIC_SYSRQ + default y + help + Automatic configuration for internal use. + When aufs supports Magic SysRq, enabled automatically. +endif --- linux-3.13.0.orig/ubuntu/aufs/dinfo.c +++ linux-3.13.0/ubuntu/aufs/dinfo.c @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * dentry private data + */ + +#include "aufs.h" + +void au_di_init_once(void *_dinfo) +{ + struct au_dinfo *dinfo = _dinfo; + static struct lock_class_key aufs_di; + + au_rw_init(&dinfo->di_rwsem); + au_rw_class(&dinfo->di_rwsem, &aufs_di); +} + +struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) +{ + struct au_dinfo *dinfo; + int nbr, i; + + dinfo = au_cache_alloc_dinfo(); + if (unlikely(!dinfo)) + goto out; + + nbr = au_sbend(sb) + 1; + if (nbr <= 0) + nbr = 1; + dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); + if (dinfo->di_hdentry) { + au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); + dinfo->di_bstart = -1; + dinfo->di_bend = -1; + dinfo->di_bwh = -1; + dinfo->di_bdiropq = -1; + for (i = 0; i < nbr; i++) + dinfo->di_hdentry[i].hd_id = -1; + goto out; + } + + au_cache_free_dinfo(dinfo); + dinfo = NULL; + +out: + return dinfo; +} + +void au_di_free(struct au_dinfo *dinfo) +{ + struct au_hdentry *p; + aufs_bindex_t bend, bindex; + + /* dentry may not be revalidated */ + bindex = dinfo->di_bstart; + if (bindex >= 0) { + bend = dinfo->di_bend; + p = dinfo->di_hdentry + bindex; + while (bindex++ <= bend) + au_hdput(p++); + } + kfree(dinfo->di_hdentry); + au_cache_free_dinfo(dinfo); +} + +void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) +{ + struct au_hdentry *p; + aufs_bindex_t bi; + + AuRwMustWriteLock(&a->di_rwsem); + AuRwMustWriteLock(&b->di_rwsem); + +#define DiSwap(v, name) \ + do { \ + v = a->di_##name; \ + a->di_##name = b->di_##name; \ + b->di_##name = v; \ + } while (0) + + DiSwap(p, hdentry); + DiSwap(bi, bstart); + DiSwap(bi, bend); + DiSwap(bi, bwh); + DiSwap(bi, bdiropq); + /* smp_mb(); */ + +#undef DiSwap +} + +void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) +{ + AuRwMustWriteLock(&dst->di_rwsem); + AuRwMustWriteLock(&src->di_rwsem); + + dst->di_bstart = src->di_bstart; + dst->di_bend = src->di_bend; + dst->di_bwh = src->di_bwh; + dst->di_bdiropq = src->di_bdiropq; + /* smp_mb(); */ +} + +int au_di_init(struct dentry *dentry) +{ + int err; + struct super_block *sb; + struct au_dinfo *dinfo; + + err = 0; + sb = dentry->d_sb; + dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); + if (dinfo) { + atomic_set(&dinfo->di_generation, au_sigen(sb)); + /* smp_mb(); */ /* atomic_set */ + dentry->d_fsdata = dinfo; + } else + err = -ENOMEM; + + return err; +} + +void au_di_fin(struct dentry *dentry) +{ + struct au_dinfo *dinfo; + + dinfo = au_di(dentry); + AuRwDestroy(&dinfo->di_rwsem); + au_di_free(dinfo); +} + +int au_di_realloc(struct au_dinfo *dinfo, int nbr) +{ + int err, sz; + struct au_hdentry *hdp; + + AuRwMustWriteLock(&dinfo->di_rwsem); + + err = -ENOMEM; + sz = sizeof(*hdp) * (dinfo->di_bend + 1); + if (!sz) + sz = sizeof(*hdp); + hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS); + if (hdp) { + dinfo->di_hdentry = hdp; + err = 0; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void do_ii_write_lock(struct inode *inode, unsigned int lsc) +{ + switch (lsc) { + case AuLsc_DI_CHILD: + ii_write_lock_child(inode); + break; + case AuLsc_DI_CHILD2: + ii_write_lock_child2(inode); + break; + case AuLsc_DI_CHILD3: + ii_write_lock_child3(inode); + break; + case AuLsc_DI_PARENT: + ii_write_lock_parent(inode); + break; + case AuLsc_DI_PARENT2: + ii_write_lock_parent2(inode); + break; + case AuLsc_DI_PARENT3: + ii_write_lock_parent3(inode); + break; + default: + BUG(); + } +} + +static void do_ii_read_lock(struct inode *inode, unsigned int lsc) +{ + switch (lsc) { + case AuLsc_DI_CHILD: + ii_read_lock_child(inode); + break; + case AuLsc_DI_CHILD2: + ii_read_lock_child2(inode); + break; + case AuLsc_DI_CHILD3: + ii_read_lock_child3(inode); + break; + case AuLsc_DI_PARENT: + ii_read_lock_parent(inode); + break; + case AuLsc_DI_PARENT2: + ii_read_lock_parent2(inode); + break; + case AuLsc_DI_PARENT3: + ii_read_lock_parent3(inode); + break; + default: + BUG(); + } +} + +void di_read_lock(struct dentry *d, int flags, unsigned int lsc) +{ + au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); + if (d->d_inode) { + if (au_ftest_lock(flags, IW)) + do_ii_write_lock(d->d_inode, lsc); + else if (au_ftest_lock(flags, IR)) + do_ii_read_lock(d->d_inode, lsc); + } +} + +void di_read_unlock(struct dentry *d, int flags) +{ + if (d->d_inode) { + if (au_ftest_lock(flags, IW)) { + au_dbg_verify_dinode(d); + ii_write_unlock(d->d_inode); + } else if (au_ftest_lock(flags, IR)) { + au_dbg_verify_dinode(d); + ii_read_unlock(d->d_inode); + } + } + au_rw_read_unlock(&au_di(d)->di_rwsem); +} + +void di_downgrade_lock(struct dentry *d, int flags) +{ + if (d->d_inode && au_ftest_lock(flags, IR)) + ii_downgrade_lock(d->d_inode); + au_rw_dgrade_lock(&au_di(d)->di_rwsem); +} + +void di_write_lock(struct dentry *d, unsigned int lsc) +{ + au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); + if (d->d_inode) + do_ii_write_lock(d->d_inode, lsc); +} + +void di_write_unlock(struct dentry *d) +{ + au_dbg_verify_dinode(d); + if (d->d_inode) + ii_write_unlock(d->d_inode); + au_rw_write_unlock(&au_di(d)->di_rwsem); +} + +void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) +{ + AuDebugOn(d1 == d2 + || d1->d_inode == d2->d_inode + || d1->d_sb != d2->d_sb); + + if (isdir && au_test_subdir(d1, d2)) { + di_write_lock_child(d1); + di_write_lock_child2(d2); + } else { + /* there should be no races */ + di_write_lock_child(d2); + di_write_lock_child2(d1); + } +} + +void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) +{ + AuDebugOn(d1 == d2 + || d1->d_inode == d2->d_inode + || d1->d_sb != d2->d_sb); + + if (isdir && au_test_subdir(d1, d2)) { + di_write_lock_parent(d1); + di_write_lock_parent2(d2); + } else { + /* there should be no races */ + di_write_lock_parent(d2); + di_write_lock_parent2(d1); + } +} + +void di_write_unlock2(struct dentry *d1, struct dentry *d2) +{ + di_write_unlock(d1); + if (d1->d_inode == d2->d_inode) + au_rw_write_unlock(&au_di(d2)->di_rwsem); + else + di_write_unlock(d2); +} + +/* ---------------------------------------------------------------------- */ + +struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) +{ + struct dentry *d; + + DiMustAnyLock(dentry); + + if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) + return NULL; + AuDebugOn(bindex < 0); + d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; + AuDebugOn(d && d_count(d) <= 0); + return d; +} + +/* + * extended version of au_h_dptr(). + * returns a hashed and positive h_dentry in bindex, NULL, or error. + */ +struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) +{ + struct dentry *h_dentry; + struct inode *inode, *h_inode; + + inode = dentry->d_inode; + AuDebugOn(!inode); + + h_dentry = NULL; + if (au_dbstart(dentry) <= bindex + && bindex <= au_dbend(dentry)) + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && !au_d_hashed_positive(h_dentry)) { + dget(h_dentry); + goto out; /* success */ + } + + AuDebugOn(bindex < au_ibstart(inode)); + AuDebugOn(au_ibend(inode) < bindex); + h_inode = au_h_iptr(inode, bindex); + h_dentry = d_find_alias(h_inode); + if (h_dentry) { + if (!IS_ERR(h_dentry)) { + if (!au_d_hashed_positive(h_dentry)) + goto out; /* success */ + dput(h_dentry); + } else + goto out; + } + + if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { + h_dentry = au_plink_lkup(inode, bindex); + AuDebugOn(!h_dentry); + if (!IS_ERR(h_dentry)) { + if (!au_d_hashed_positive(h_dentry)) + goto out; /* success */ + dput(h_dentry); + h_dentry = NULL; + } + } + +out: + AuDbgDentry(h_dentry); + return h_dentry; +} + +aufs_bindex_t au_dbtail(struct dentry *dentry) +{ + aufs_bindex_t bend, bwh; + + bend = au_dbend(dentry); + if (0 <= bend) { + bwh = au_dbwh(dentry); + if (!bwh) + return bwh; + if (0 < bwh && bwh < bend) + return bwh - 1; + } + return bend; +} + +aufs_bindex_t au_dbtaildir(struct dentry *dentry) +{ + aufs_bindex_t bend, bopq; + + bend = au_dbtail(dentry); + if (0 <= bend) { + bopq = au_dbdiropq(dentry); + if (0 <= bopq && bopq < bend) + bend = bopq; + } + return bend; +} + +/* ---------------------------------------------------------------------- */ + +void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_dentry) +{ + struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; + struct au_branch *br; + + DiMustWriteLock(dentry); + + au_hdput(hd); + hd->hd_dentry = h_dentry; + if (h_dentry) { + br = au_sbr(dentry->d_sb, bindex); + hd->hd_id = br->br_id; + } +} + +int au_dbrange_test(struct dentry *dentry) +{ + int err; + aufs_bindex_t bstart, bend; + + err = 0; + bstart = au_dbstart(dentry); + bend = au_dbend(dentry); + if (bstart >= 0) + AuDebugOn(bend < 0 && bstart > bend); + else { + err = -EIO; + AuDebugOn(bend >= 0); + } + + return err; +} + +int au_digen_test(struct dentry *dentry, unsigned int sigen) +{ + int err; + + err = 0; + if (unlikely(au_digen(dentry) != sigen + || au_iigen_test(dentry->d_inode, sigen))) + err = -EIO; + + return err; +} + +void au_update_digen(struct dentry *dentry) +{ + atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); + /* smp_mb(); */ /* atomic_set */ +} + +void au_update_dbrange(struct dentry *dentry, int do_put_zero) +{ + struct au_dinfo *dinfo; + struct dentry *h_d; + struct au_hdentry *hdp; + + DiMustWriteLock(dentry); + + dinfo = au_di(dentry); + if (!dinfo || dinfo->di_bstart < 0) + return; + + hdp = dinfo->di_hdentry; + if (do_put_zero) { + aufs_bindex_t bindex, bend; + + bend = dinfo->di_bend; + for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) { + h_d = hdp[0 + bindex].hd_dentry; + if (h_d && !h_d->d_inode) + au_set_h_dptr(dentry, bindex, NULL); + } + } + + dinfo->di_bstart = -1; + while (++dinfo->di_bstart <= dinfo->di_bend) + if (hdp[0 + dinfo->di_bstart].hd_dentry) + break; + if (dinfo->di_bstart > dinfo->di_bend) { + dinfo->di_bstart = -1; + dinfo->di_bend = -1; + return; + } + + dinfo->di_bend++; + while (0 <= --dinfo->di_bend) + if (hdp[0 + dinfo->di_bend].hd_dentry) + break; + AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0); +} + +void au_update_dbstart(struct dentry *dentry) +{ + aufs_bindex_t bindex, bend; + struct dentry *h_dentry; + + bend = au_dbend(dentry); + for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + if (h_dentry->d_inode) { + au_set_dbstart(dentry, bindex); + return; + } + au_set_h_dptr(dentry, bindex, NULL); + } +} + +void au_update_dbend(struct dentry *dentry) +{ + aufs_bindex_t bindex, bstart; + struct dentry *h_dentry; + + bstart = au_dbstart(dentry); + for (bindex = au_dbend(dentry); bindex >= bstart; bindex--) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + if (h_dentry->d_inode) { + au_set_dbend(dentry, bindex); + return; + } + au_set_h_dptr(dentry, bindex, NULL); + } +} + +int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) +{ + aufs_bindex_t bindex, bend; + + bend = au_dbend(dentry); + for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) + if (au_h_dptr(dentry, bindex) == h_dentry) + return bindex; + return -1; +} --- linux-3.13.0.orig/ubuntu/aufs/file.c +++ linux-3.13.0/ubuntu/aufs/file.c @@ -0,0 +1,724 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * handling file/dir, and address_space operation + */ + +#ifdef CONFIG_AUFS_DEBUG +#include +#endif +#include +#include "aufs.h" + +/* drop flags for writing */ +unsigned int au_file_roflags(unsigned int flags) +{ + flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); + flags |= O_RDONLY | O_NOATIME; + return flags; +} + +/* common functions to regular file and dir */ +struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, + struct file *file, int force_wr) +{ + struct file *h_file; + struct dentry *h_dentry; + struct inode *h_inode; + struct super_block *sb; + struct au_branch *br; + struct path h_path; + int err, exec_flag; + + /* a race condition can happen between open and unlink/rmdir */ + h_file = ERR_PTR(-ENOENT); + h_dentry = au_h_dptr(dentry, bindex); + if (au_test_nfsd() && !h_dentry) + goto out; + h_inode = h_dentry->d_inode; + if (au_test_nfsd() && !h_inode) + goto out; + spin_lock(&h_dentry->d_lock); + err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) + || !h_inode + /* || !dentry->d_inode->i_nlink */ + ; + spin_unlock(&h_dentry->d_lock); + if (unlikely(err)) + goto out; + + sb = dentry->d_sb; + br = au_sbr(sb, bindex); + h_file = ERR_PTR(-EACCES); + exec_flag = flags & __FMODE_EXEC; + if (exec_flag && (au_br_mnt(br)->mnt_flags & MNT_NOEXEC)) + goto out; + + /* drop flags for writing */ + if (au_test_ro(sb, bindex, dentry->d_inode)) { + if (force_wr && !(flags & O_WRONLY)) + force_wr = 0; + flags = au_file_roflags(flags); + if (force_wr) { + h_file = ERR_PTR(-EROFS); + flags = au_file_roflags(flags); + if (unlikely(vfsub_native_ro(h_inode) + || IS_APPEND(h_inode))) + goto out; + flags &= ~O_ACCMODE; + flags |= O_WRONLY; + } + } + flags &= ~O_CREAT; + atomic_inc(&br->br_count); + h_path.dentry = h_dentry; + h_path.mnt = au_br_mnt(br); + if (!au_special_file(h_inode->i_mode)) + h_file = vfsub_dentry_open(&h_path, flags); + else { + /* this block depends upon the configuration */ + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + si_read_unlock(sb); + h_file = vfsub_dentry_open(&h_path, flags); + si_noflush_read_lock(sb); + fi_write_lock(file); + di_read_lock_child(dentry, AuLock_IR); + } + if (IS_ERR(h_file)) + goto out_br; + + if (exec_flag) { + err = deny_write_access(h_file); + if (unlikely(err)) { + fput(h_file); + h_file = ERR_PTR(err); + goto out_br; + } + } + fsnotify_open(h_file); + goto out; /* success */ + +out_br: + atomic_dec(&br->br_count); +out: + return h_file; +} + +int au_do_open(struct file *file, int (*open)(struct file *file, int flags), + struct au_fidir *fidir) +{ + int err; + struct dentry *dentry; + + err = au_finfo_init(file, fidir); + if (unlikely(err)) + goto out; + + dentry = file->f_dentry; + di_read_lock_child(dentry, AuLock_IR); + err = open(file, vfsub_file_flags(file)); + di_read_unlock(dentry, AuLock_IR); + + fi_write_unlock(file); + if (unlikely(err)) { + au_fi(file)->fi_hdir = NULL; + au_finfo_fin(file); + } + +out: + return err; +} + +int au_reopen_nondir(struct file *file) +{ + int err; + aufs_bindex_t bstart; + struct dentry *dentry; + struct file *h_file, *h_file_tmp; + + dentry = file->f_dentry; + AuDebugOn(au_special_file(dentry->d_inode->i_mode)); + bstart = au_dbstart(dentry); + h_file_tmp = NULL; + if (au_fbstart(file) == bstart) { + h_file = au_hf_top(file); + if (file->f_mode == h_file->f_mode) + return 0; /* success */ + h_file_tmp = h_file; + get_file(h_file_tmp); + au_set_h_fptr(file, bstart, NULL); + } + AuDebugOn(au_fi(file)->fi_hdir); + /* + * it can happen + * file exists on both of rw and ro + * open --> dbstart and fbstart are both 0 + * prepend a branch as rw, "rw" become ro + * remove rw/file + * delete the top branch, "rw" becomes rw again + * --> dbstart is 1, fbstart is still 0 + * write --> fbstart is 0 but dbstart is 1 + */ + /* AuDebugOn(au_fbstart(file) < bstart); */ + + h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, + file, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) { + if (h_file_tmp) { + atomic_inc(&au_sbr(dentry->d_sb, bstart)->br_count); + au_set_h_fptr(file, bstart, h_file_tmp); + h_file_tmp = NULL; + } + goto out; /* todo: close all? */ + } + + err = 0; + au_set_fbstart(file, bstart); + au_set_h_fptr(file, bstart, h_file); + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + +out: + if (h_file_tmp) + fput(h_file_tmp); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, + struct dentry *hi_wh) +{ + int err; + aufs_bindex_t bstart; + struct au_dinfo *dinfo; + struct dentry *h_dentry; + struct au_hdentry *hdp; + + dinfo = au_di(file->f_dentry); + AuRwMustWriteLock(&dinfo->di_rwsem); + + bstart = dinfo->di_bstart; + dinfo->di_bstart = btgt; + hdp = dinfo->di_hdentry; + h_dentry = hdp[0 + btgt].hd_dentry; + hdp[0 + btgt].hd_dentry = hi_wh; + err = au_reopen_nondir(file); + hdp[0 + btgt].hd_dentry = h_dentry; + dinfo->di_bstart = bstart; + + return err; +} + +static int au_ready_to_write_wh(struct file *file, loff_t len, + aufs_bindex_t bcpup, struct au_pin *pin) +{ + int err; + struct inode *inode, *h_inode; + struct dentry *h_dentry, *hi_wh; + struct au_cp_generic cpg = { + .dentry = file->f_dentry, + .bdst = bcpup, + .bsrc = -1, + .len = len, + .pin = pin + }; + + au_update_dbstart(cpg.dentry); + inode = cpg.dentry->d_inode; + h_inode = NULL; + if (au_dbstart(cpg.dentry) <= bcpup + && au_dbend(cpg.dentry) >= bcpup) { + h_dentry = au_h_dptr(cpg.dentry, bcpup); + if (h_dentry) + h_inode = h_dentry->d_inode; + } + hi_wh = au_hi_wh(inode, bcpup); + if (!hi_wh && !h_inode) + err = au_sio_cpup_wh(&cpg, file); + else + /* already copied-up after unlink */ + err = au_reopen_wh(file, bcpup, hi_wh); + + if (!err + && inode->i_nlink > 1 + && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) + au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); + + return err; +} + +/* + * prepare the @file for writing. + */ +int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) +{ + int err; + aufs_bindex_t dbstart; + struct dentry *parent, *h_dentry; + struct inode *inode; + struct super_block *sb; + struct file *h_file; + struct au_cp_generic cpg = { + .dentry = file->f_dentry, + .bdst = -1, + .bsrc = -1, + .len = len, + .pin = pin, + .flags = AuCpup_DTIME + }; + + sb = cpg.dentry->d_sb; + inode = cpg.dentry->d_inode; + AuDebugOn(au_special_file(inode->i_mode)); + cpg.bsrc = au_fbstart(file); + err = au_test_ro(sb, cpg.bsrc, inode); + if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { + err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, + /*flags*/0); + goto out; + } + + /* need to cpup or reopen */ + parent = dget_parent(cpg.dentry); + di_write_lock_parent(parent); + err = AuWbrCopyup(au_sbi(sb), cpg.dentry); + cpg.bdst = err; + if (unlikely(err < 0)) + goto out_dgrade; + err = 0; + + if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { + err = au_cpup_dirs(cpg.dentry, cpg.bdst); + if (unlikely(err)) + goto out_dgrade; + } + + err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out_dgrade; + + h_dentry = au_hf_top(file)->f_dentry; + dbstart = au_dbstart(cpg.dentry); + if (dbstart <= cpg.bdst) { + h_dentry = au_h_dptr(cpg.dentry, cpg.bdst); + AuDebugOn(!h_dentry); + cpg.bsrc = cpg.bdst; + } + + if (dbstart <= cpg.bdst /* just reopen */ + || !d_unhashed(cpg.dentry) /* copyup and reopen */ + ) { + h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); + if (IS_ERR(h_file)) + err = PTR_ERR(h_file); + else { + di_downgrade_lock(parent, AuLock_IR); + if (dbstart > cpg.bdst) + err = au_sio_cpup_simple(&cpg); + if (!err) + err = au_reopen_nondir(file); + au_h_open_post(cpg.dentry, cpg.bsrc, h_file); + } + } else { /* copyup as wh and reopen */ + /* + * since writable hfsplus branch is not supported, + * h_open_pre/post() are unnecessary. + */ + err = au_ready_to_write_wh(file, len, cpg.bdst, pin); + di_downgrade_lock(parent, AuLock_IR); + } + + if (!err) { + au_pin_set_parent_lflag(pin, /*lflag*/0); + goto out_dput; /* success */ + } + au_unpin(pin); + goto out_unlock; + +out_dgrade: + di_downgrade_lock(parent, AuLock_IR); +out_unlock: + di_read_unlock(parent, AuLock_IR); +out_dput: + dput(parent); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_do_flush(struct file *file, fl_owner_t id, + int (*flush)(struct file *file, fl_owner_t id)) +{ + int err; + struct super_block *sb; + struct inode *inode; + + inode = file_inode(file); + sb = inode->i_sb; + si_noflush_read_lock(sb); + fi_read_lock(file); + ii_read_lock_child(inode); + + err = flush(file, id); + au_cpup_attr_timesizes(inode); + + ii_read_unlock(inode); + fi_read_unlock(file); + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_file_refresh_by_inode(struct file *file, int *need_reopen) +{ + int err; + struct au_pin pin; + struct au_finfo *finfo; + struct dentry *parent, *hi_wh; + struct inode *inode; + struct super_block *sb; + struct au_cp_generic cpg = { + .dentry = file->f_dentry, + .bdst = -1, + .bsrc = -1, + .len = -1, + .pin = &pin, + .flags = AuCpup_DTIME + }; + + FiMustWriteLock(file); + + err = 0; + finfo = au_fi(file); + sb = cpg.dentry->d_sb; + inode = cpg.dentry->d_inode; + cpg.bdst = au_ibstart(inode); + if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) + goto out; + + parent = dget_parent(cpg.dentry); + if (au_test_ro(sb, cpg.bdst, inode)) { + di_read_lock_parent(parent, !AuLock_IR); + err = AuWbrCopyup(au_sbi(sb), cpg.dentry); + cpg.bdst = err; + di_read_unlock(parent, !AuLock_IR); + if (unlikely(err < 0)) + goto out_parent; + err = 0; + } + + di_read_lock_parent(parent, AuLock_IR); + hi_wh = au_hi_wh(inode, cpg.bdst); + if (!S_ISDIR(inode->i_mode) + && au_opt_test(au_mntflags(sb), PLINK) + && au_plink_test(inode) + && !d_unhashed(cpg.dentry) + && cpg.bdst < au_dbstart(cpg.dentry)) { + err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); + if (unlikely(err)) + goto out_unlock; + + /* always superio. */ + err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (!err) { + err = au_sio_cpup_simple(&cpg); + au_unpin(&pin); + } + } else if (hi_wh) { + /* already copied-up after unlink */ + err = au_reopen_wh(file, cpg.bdst, hi_wh); + *need_reopen = 0; + } + +out_unlock: + di_read_unlock(parent, AuLock_IR); +out_parent: + dput(parent); +out: + return err; +} + +static void au_do_refresh_dir(struct file *file) +{ + aufs_bindex_t bindex, bend, new_bindex, brid; + struct au_hfile *p, tmp, *q; + struct au_finfo *finfo; + struct super_block *sb; + struct au_fidir *fidir; + + FiMustWriteLock(file); + + sb = file->f_dentry->d_sb; + finfo = au_fi(file); + fidir = finfo->fi_hdir; + AuDebugOn(!fidir); + p = fidir->fd_hfile + finfo->fi_btop; + brid = p->hf_br->br_id; + bend = fidir->fd_bbot; + for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) { + if (!p->hf_file) + continue; + + new_bindex = au_br_index(sb, p->hf_br->br_id); + if (new_bindex == bindex) + continue; + if (new_bindex < 0) { + au_set_h_fptr(file, bindex, NULL); + continue; + } + + /* swap two lower inode, and loop again */ + q = fidir->fd_hfile + new_bindex; + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hf_file) { + bindex--; + p--; + } + } + + p = fidir->fd_hfile; + if (!au_test_mmapped(file) && !d_unlinked(file->f_dentry)) { + bend = au_sbend(sb); + for (finfo->fi_btop = 0; finfo->fi_btop <= bend; + finfo->fi_btop++, p++) + if (p->hf_file) { + if (file_inode(p->hf_file)) + break; + else + au_hfput(p, file); + } + } else { + bend = au_br_index(sb, brid); + for (finfo->fi_btop = 0; finfo->fi_btop < bend; + finfo->fi_btop++, p++) + if (p->hf_file) + au_hfput(p, file); + bend = au_sbend(sb); + } + + p = fidir->fd_hfile + bend; + for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop; + fidir->fd_bbot--, p--) + if (p->hf_file) { + if (file_inode(p->hf_file)) + break; + else + au_hfput(p, file); + } + AuDebugOn(fidir->fd_bbot < finfo->fi_btop); +} + +/* + * after branch manipulating, refresh the file. + */ +static int refresh_file(struct file *file, int (*reopen)(struct file *file)) +{ + int err, need_reopen; + aufs_bindex_t bend, bindex; + struct dentry *dentry; + struct au_finfo *finfo; + struct au_hfile *hfile; + + dentry = file->f_dentry; + finfo = au_fi(file); + if (!finfo->fi_hdir) { + hfile = &finfo->fi_htop; + AuDebugOn(!hfile->hf_file); + bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id); + AuDebugOn(bindex < 0); + if (bindex != finfo->fi_btop) + au_set_fbstart(file, bindex); + } else { + err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1); + if (unlikely(err)) + goto out; + au_do_refresh_dir(file); + } + + err = 0; + need_reopen = 1; + if (!au_test_mmapped(file)) + err = au_file_refresh_by_inode(file, &need_reopen); + if (!err && need_reopen && !d_unlinked(dentry)) + err = reopen(file); + if (!err) { + au_update_figen(file); + goto out; /* success */ + } + + /* error, close all lower files */ + if (finfo->fi_hdir) { + bend = au_fbend_dir(file); + for (bindex = au_fbstart(file); bindex <= bend; bindex++) + au_set_h_fptr(file, bindex, NULL); + } + +out: + return err; +} + +/* common function to regular file and dir */ +int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), + int wlock) +{ + int err; + unsigned int sigen, figen; + aufs_bindex_t bstart; + unsigned char pseudo_link; + struct dentry *dentry; + struct inode *inode; + + err = 0; + dentry = file->f_dentry; + inode = dentry->d_inode; + AuDebugOn(au_special_file(inode->i_mode)); + sigen = au_sigen(dentry->d_sb); + fi_write_lock(file); + figen = au_figen(file); + di_write_lock_child(dentry); + bstart = au_dbstart(dentry); + pseudo_link = (bstart != au_ibstart(inode)); + if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) { + if (!wlock) { + di_downgrade_lock(dentry, AuLock_IR); + fi_downgrade_lock(file); + } + goto out; /* success */ + } + + AuDbg("sigen %d, figen %d\n", sigen, figen); + if (au_digen_test(dentry, sigen)) { + err = au_reval_dpath(dentry, sigen); + AuDebugOn(!err && au_digen_test(dentry, sigen)); + } + + if (!err) + err = refresh_file(file, reopen); + if (!err) { + if (!wlock) { + di_downgrade_lock(dentry, AuLock_IR); + fi_downgrade_lock(file); + } + } else { + di_write_unlock(dentry); + fi_write_unlock(file); + } + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* cf. aufs_nopage() */ +/* for madvise(2) */ +static int aufs_readpage(struct file *file __maybe_unused, struct page *page) +{ + unlock_page(page); + return 0; +} + +/* it will never be called, but necessary to support O_DIRECT */ +static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) +{ BUG(); return 0; } + +/* + * it will never be called, but madvise and fadvise behaves differently + * when get_xip_mem is defined + */ +static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, + int create, void **kmem, unsigned long *pfn) +{ BUG(); return 0; } + +/* they will never be called. */ +#ifdef CONFIG_AUFS_DEBUG +static int aufs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ AuUnsupport(); return 0; } +static int aufs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ AuUnsupport(); return 0; } +static int aufs_writepage(struct page *page, struct writeback_control *wbc) +{ AuUnsupport(); return 0; } + +static int aufs_set_page_dirty(struct page *page) +{ AuUnsupport(); return 0; } +static void aufs_invalidatepage(struct page *page, unsigned int offset, + unsigned int length) +{ AuUnsupport(); } +static int aufs_releasepage(struct page *page, gfp_t gfp) +{ AuUnsupport(); return 0; } +static int aufs_migratepage(struct address_space *mapping, struct page *newpage, + struct page *page, enum migrate_mode mode) +{ AuUnsupport(); return 0; } +static int aufs_launder_page(struct page *page) +{ AuUnsupport(); return 0; } +static int aufs_is_partially_uptodate(struct page *page, + read_descriptor_t *desc, + unsigned long from) +{ AuUnsupport(); return 0; } +static void aufs_is_dirty_writeback(struct page *page, bool *dirty, + bool *writeback) +{ AuUnsupport(); } +static int aufs_error_remove_page(struct address_space *mapping, + struct page *page) +{ AuUnsupport(); return 0; } +static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, + sector_t *span) +{ AuUnsupport(); return 0; } +static void aufs_swap_deactivate(struct file *file) +{ AuUnsupport(); } +#endif /* CONFIG_AUFS_DEBUG */ + +const struct address_space_operations aufs_aop = { + .readpage = aufs_readpage, + .direct_IO = aufs_direct_IO, + .get_xip_mem = aufs_get_xip_mem, +#ifdef CONFIG_AUFS_DEBUG + .writepage = aufs_writepage, + /* no writepages, because of writepage */ + .set_page_dirty = aufs_set_page_dirty, + /* no readpages, because of readpage */ + .write_begin = aufs_write_begin, + .write_end = aufs_write_end, + /* no bmap, no block device */ + .invalidatepage = aufs_invalidatepage, + .releasepage = aufs_releasepage, + .migratepage = aufs_migratepage, + .launder_page = aufs_launder_page, + .is_partially_uptodate = aufs_is_partially_uptodate, + .is_dirty_writeback = aufs_is_dirty_writeback, + .error_remove_page = aufs_error_remove_page, + .swap_activate = aufs_swap_activate, + .swap_deactivate = aufs_swap_deactivate +#endif /* CONFIG_AUFS_DEBUG */ +}; --- linux-3.13.0.orig/ubuntu/aufs/conf.mk +++ linux-3.13.0/ubuntu/aufs/conf.mk @@ -0,0 +1,37 @@ + +AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} + +define AuConf +ifdef ${1} +AuConfStr += ${1}=${${1}} +endif +endef + +AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ + SBILIST \ + HNOTIFY HFSNOTIFY \ + EXPORT INO_T_64 \ + RDU \ + SP_IATTR \ + SHWH \ + BR_RAMFS \ + BR_FUSE POLL \ + BR_HFSPLUS \ + BDEV_LOOP \ + DEBUG MAGIC_SYSRQ +$(foreach i, ${AuConfAll}, \ + $(eval $(call AuConf,CONFIG_AUFS_${i}))) + +AuConfName = ${obj}/conf.str +${AuConfName}.tmp: FORCE + @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ +${AuConfName}: ${AuConfName}.tmp + @diff -q $< $@ > /dev/null 2>&1 || { \ + echo ' GEN ' $@; \ + cp -p $< $@; \ + } +FORCE: +clean-files += ${AuConfName} ${AuConfName}.tmp +${obj}/sysfs.o: ${AuConfName} + +-include ${srctree}/${src}/conf_priv.mk --- linux-3.13.0.orig/ubuntu/aufs/i_op.c +++ linux-3.13.0/ubuntu/aufs/i_op.c @@ -0,0 +1,1127 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations (except add/del/rename) + */ + +#include +#include +#include +#include +#include +#include "aufs.h" + +static int h_permission(struct inode *h_inode, int mask, + struct vfsmount *h_mnt, int brperm) +{ + int err; + const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); + + err = -EACCES; + if ((write_mask && IS_IMMUTABLE(h_inode)) + || ((mask & MAY_EXEC) + && S_ISREG(h_inode->i_mode) + && ((h_mnt->mnt_flags & MNT_NOEXEC) + || !(h_inode->i_mode & S_IXUGO)))) + goto out; + + /* + * - skip the lower fs test in the case of write to ro branch. + * - nfs dir permission write check is optimized, but a policy for + * link/rename requires a real check. + */ + if ((write_mask && !au_br_writable(brperm)) + || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) + && write_mask && !(mask & MAY_READ)) + || !h_inode->i_op->permission) { + /* AuLabel(generic_permission); */ + err = generic_permission(h_inode, mask); + } else { + /* AuLabel(h_inode->permission); */ + err = h_inode->i_op->permission(h_inode, mask); + AuTraceErr(err); + } + + if (!err) + err = devcgroup_inode_permission(h_inode, mask); + if (!err) + err = security_inode_permission(h_inode, mask); + +#if 0 + if (!err) { + /* todo: do we need to call ima_path_check()? */ + struct path h_path = { + .dentry = + .mnt = h_mnt + }; + err = ima_path_check(&h_path, + mask & (MAY_READ | MAY_WRITE | MAY_EXEC), + IMA_COUNT_LEAVE); + } +#endif + +out: + return err; +} + +static int aufs_permission(struct inode *inode, int mask) +{ + int err; + aufs_bindex_t bindex, bend; + const unsigned char isdir = !!S_ISDIR(inode->i_mode), + write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); + struct inode *h_inode; + struct super_block *sb; + struct au_branch *br; + + /* todo: support rcu-walk? */ + if (mask & MAY_NOT_BLOCK) + return -ECHILD; + + sb = inode->i_sb; + si_read_lock(sb, AuLock_FLUSH); + ii_read_lock_child(inode); +#if 0 + err = au_iigen_test(inode, au_sigen(sb)); + if (unlikely(err)) + goto out; +#endif + + if (!isdir || write_mask) { + err = au_busy_or_stale(); + h_inode = au_h_iptr(inode, au_ibstart(inode)); + if (unlikely(!h_inode + || (h_inode->i_mode & S_IFMT) + != (inode->i_mode & S_IFMT))) + goto out; + + err = 0; + bindex = au_ibstart(inode); + br = au_sbr(sb, bindex); + err = h_permission(h_inode, mask, au_br_mnt(br), br->br_perm); + if (write_mask + && !err + && !special_file(h_inode->i_mode)) { + /* test whether the upper writable branch exists */ + err = -EROFS; + for (; bindex >= 0; bindex--) + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = 0; + break; + } + } + goto out; + } + + /* non-write to dir */ + err = 0; + bend = au_ibend(inode); + for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (h_inode) { + err = au_busy_or_stale(); + if (unlikely(!S_ISDIR(h_inode->i_mode))) + break; + + br = au_sbr(sb, bindex); + err = h_permission(h_inode, mask, au_br_mnt(br), + br->br_perm); + } + } + +out: + ii_read_unlock(inode); + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + struct dentry *ret, *parent; + struct inode *inode; + struct super_block *sb; + int err, npositive; + + IMustLock(dir); + + /* todo: support rcu-walk? */ + ret = ERR_PTR(-ECHILD); + if (flags & LOOKUP_RCU) + goto out; + + ret = ERR_PTR(-ENAMETOOLONG); + if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) + goto out; + + sb = dir->i_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + ret = ERR_PTR(err); + if (unlikely(err)) + goto out; + + err = au_di_init(dentry); + ret = ERR_PTR(err); + if (unlikely(err)) + goto out_si; + + inode = NULL; + npositive = 0; /* suppress a warning */ + parent = dentry->d_parent; /* dir inode is locked */ + di_read_lock_parent(parent, AuLock_IR); + err = au_alive_dir(parent); + if (!err) + err = au_digen_test(parent, au_sigen(sb)); + if (!err) { + npositive = au_lkup_dentry(dentry, au_dbstart(parent), + /*type*/0); + err = npositive; + } + di_read_unlock(parent, AuLock_IR); + ret = ERR_PTR(err); + if (unlikely(err < 0)) + goto out_unlock; + + if (npositive) { + inode = au_new_inode(dentry, /*must_new*/0); + ret = (void *)inode; + } + if (IS_ERR(inode)) { + inode = NULL; + goto out_unlock; + } + + ret = d_splice_alias(inode, dentry); +#if 0 + if (unlikely(d_need_lookup(dentry))) { + spin_lock(&dentry->d_lock); + dentry->d_flags &= ~DCACHE_NEED_LOOKUP; + spin_unlock(&dentry->d_lock); + } else +#endif + if (unlikely(IS_ERR(ret) && inode)) { + ii_write_unlock(inode); + iput(inode); + inode = NULL; + } + +out_unlock: + di_write_unlock(dentry); + if (inode) { + /* verbose coding for lock class name */ + if (unlikely(S_ISLNK(inode->i_mode))) + au_rw_class(&au_di(dentry)->di_rwsem, + au_lc_key + AuLcSymlink_DIINFO); + else if (unlikely(S_ISDIR(inode->i_mode))) + au_rw_class(&au_di(dentry)->di_rwsem, + au_lc_key + AuLcDir_DIINFO); + else /* likely */ + au_rw_class(&au_di(dentry)->di_rwsem, + au_lc_key + AuLcNonDir_DIINFO); + } +out_si: + si_read_unlock(sb); +out: + return ret; +} + +/* ---------------------------------------------------------------------- */ + +static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, + const unsigned char add_entry, aufs_bindex_t bcpup, + aufs_bindex_t bstart) +{ + int err; + struct dentry *h_parent; + struct inode *h_dir; + + if (add_entry) + IMustLock(parent->d_inode); + else + di_write_lock_parent(parent); + + err = 0; + if (!au_h_dptr(parent, bcpup)) { + if (bstart > bcpup) + err = au_cpup_dirs(dentry, bcpup); + else if (bstart < bcpup) + err = au_cpdown_dirs(dentry, bcpup); + else + BUG(); + } + if (!err && add_entry) { + h_parent = au_h_dptr(parent, bcpup); + h_dir = h_parent->d_inode; + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + err = au_lkup_neg(dentry, bcpup, + au_ftest_wrdir(add_entry, TMP_WHENTRY)); + /* todo: no unlock here */ + mutex_unlock(&h_dir->i_mutex); + + AuDbg("bcpup %d\n", bcpup); + if (!err) { + if (!dentry->d_inode) + au_set_h_dptr(dentry, bstart, NULL); + au_update_dbrange(dentry, /*do_put_zero*/0); + } + } + + if (!add_entry) + di_write_unlock(parent); + if (!err) + err = bcpup; /* success */ + + AuTraceErr(err); + return err; +} + +/* + * decide the branch and the parent dir where we will create a new entry. + * returns new bindex or an error. + * copyup the parent dir if needed. + */ +int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, + struct au_wr_dir_args *args) +{ + int err; + unsigned int flags; + aufs_bindex_t bcpup, bstart, src_bstart; + const unsigned char add_entry + = au_ftest_wrdir(args->flags, ADD_ENTRY) + | au_ftest_wrdir(args->flags, TMP_WHENTRY); + struct super_block *sb; + struct dentry *parent; + struct au_sbinfo *sbinfo; + + sb = dentry->d_sb; + sbinfo = au_sbi(sb); + parent = dget_parent(dentry); + bstart = au_dbstart(dentry); + bcpup = bstart; + if (args->force_btgt < 0) { + if (src_dentry) { + src_bstart = au_dbstart(src_dentry); + if (src_bstart < bstart) + bcpup = src_bstart; + } else if (add_entry) { + flags = 0; + if (au_ftest_wrdir(args->flags, ISDIR)) + au_fset_wbr(flags, DIR); + err = AuWbrCreate(sbinfo, dentry, flags); + bcpup = err; + } + + if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { + if (add_entry) + err = AuWbrCopyup(sbinfo, dentry); + else { + if (!IS_ROOT(dentry)) { + di_read_lock_parent(parent, !AuLock_IR); + err = AuWbrCopyup(sbinfo, dentry); + di_read_unlock(parent, !AuLock_IR); + } else + err = AuWbrCopyup(sbinfo, dentry); + } + bcpup = err; + if (unlikely(err < 0)) + goto out; + } + } else { + bcpup = args->force_btgt; + AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); + } + + AuDbg("bstart %d, bcpup %d\n", bstart, bcpup); + err = bcpup; + if (bcpup == bstart) + goto out; /* success */ + + /* copyup the new parent into the branch we process */ + err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart); + if (err >= 0) { + if (!dentry->d_inode) { + au_set_h_dptr(dentry, bstart, NULL); + au_set_dbstart(dentry, bcpup); + au_set_dbend(dentry, bcpup); + } + AuDebugOn(add_entry && !au_h_dptr(dentry, bcpup)); + } + +out: + dput(parent); + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_pin_hdir_unlock(struct au_pin *p) +{ + if (p->hdir) + au_hn_imtx_unlock(p->hdir); +} + +static int au_pin_hdir_lock(struct au_pin *p) +{ + int err; + + err = 0; + if (!p->hdir) + goto out; + + /* even if an error happens later, keep this lock */ + au_hn_imtx_lock_nested(p->hdir, p->lsc_hi); + + err = -EBUSY; + if (unlikely(p->hdir->hi_inode != p->h_parent->d_inode)) + goto out; + + err = 0; + if (p->h_dentry) + err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, + p->h_parent, p->br); + +out: + return err; +} + +int au_pin_hdir_relock(struct au_pin *p) +{ + int err, i; + struct inode *h_i; + struct dentry *h_d[] = { + p->h_dentry, + p->h_parent + }; + + err = au_pin_hdir_lock(p); + if (unlikely(err)) + goto out; + + for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { + if (!h_d[i]) + continue; + h_i = h_d[i]->d_inode; + if (h_i) + err = !h_i->i_nlink; + } + +out: + return err; +} + +void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) +{ +#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) + p->hdir->hi_inode->i_mutex.owner = task; +#endif +} + +void au_pin_hdir_acquire_nest(struct au_pin *p) +{ + if (p->hdir) { + mutex_acquire_nest(&p->hdir->hi_inode->i_mutex.dep_map, + p->lsc_hi, 0, NULL, _RET_IP_); + au_pin_hdir_set_owner(p, current); + } +} + +void au_pin_hdir_release(struct au_pin *p) +{ + if (p->hdir) { + au_pin_hdir_set_owner(p, p->task); + mutex_release(&p->hdir->hi_inode->i_mutex.dep_map, 1, _RET_IP_); + } +} + +struct dentry *au_pinned_h_parent(struct au_pin *pin) +{ + if (pin && pin->parent) + return au_h_dptr(pin->parent, pin->bindex); + return NULL; +} + +void au_unpin(struct au_pin *p) +{ + if (p->hdir) + au_pin_hdir_unlock(p); + if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) + vfsub_mnt_drop_write(p->h_mnt); + if (!p->hdir) + return; + + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_unlock(p->parent, AuLock_IR); + iput(p->hdir->hi_inode); + dput(p->parent); + p->parent = NULL; + p->hdir = NULL; + p->h_mnt = NULL; + /* do not clear p->task */ +} + +int au_do_pin(struct au_pin *p) +{ + int err; + struct super_block *sb; + struct inode *h_dir; + + err = 0; + sb = p->dentry->d_sb; + p->br = au_sbr(sb, p->bindex); + if (IS_ROOT(p->dentry)) { + if (au_ftest_pin(p->flags, MNT_WRITE)) { + p->h_mnt = au_br_mnt(p->br); + err = vfsub_mnt_want_write(p->h_mnt); + if (unlikely(err)) { + au_fclr_pin(p->flags, MNT_WRITE); + goto out_err; + } + } + goto out; + } + + p->h_dentry = NULL; + if (p->bindex <= au_dbend(p->dentry)) + p->h_dentry = au_h_dptr(p->dentry, p->bindex); + + p->parent = dget_parent(p->dentry); + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_lock(p->parent, AuLock_IR, p->lsc_di); + + h_dir = NULL; + p->h_parent = au_h_dptr(p->parent, p->bindex); + p->hdir = au_hi(p->parent->d_inode, p->bindex); + if (p->hdir) + h_dir = p->hdir->hi_inode; + + /* + * udba case, or + * if DI_LOCKED is not set, then p->parent may be different + * and h_parent can be NULL. + */ + if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { + err = -EBUSY; + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_unlock(p->parent, AuLock_IR); + dput(p->parent); + p->parent = NULL; + goto out_err; + } + + if (au_ftest_pin(p->flags, MNT_WRITE)) { + p->h_mnt = au_br_mnt(p->br); + err = vfsub_mnt_want_write(p->h_mnt); + if (unlikely(err)) { + au_fclr_pin(p->flags, MNT_WRITE); + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_unlock(p->parent, AuLock_IR); + dput(p->parent); + p->parent = NULL; + goto out_err; + } + } + + au_igrab(h_dir); + err = au_pin_hdir_lock(p); + if (!err) + goto out; /* success */ + +out_err: + pr_err("err %d\n", err); + err = au_busy_or_stale(); +out: + return err; +} + +void au_pin_init(struct au_pin *p, struct dentry *dentry, + aufs_bindex_t bindex, int lsc_di, int lsc_hi, + unsigned int udba, unsigned char flags) +{ + p->dentry = dentry; + p->udba = udba; + p->lsc_di = lsc_di; + p->lsc_hi = lsc_hi; + p->flags = flags; + p->bindex = bindex; + + p->parent = NULL; + p->hdir = NULL; + p->h_mnt = NULL; + + p->h_dentry = NULL; + p->h_parent = NULL; + p->br = NULL; + p->task = current; +} + +int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, + unsigned int udba, unsigned char flags) +{ + au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, + udba, flags); + return au_do_pin(pin); +} + +/* ---------------------------------------------------------------------- */ + +/* + * ->setattr() and ->getattr() are called in various cases. + * chmod, stat: dentry is revalidated. + * fchmod, fstat: file and dentry are not revalidated, additionally they may be + * unhashed. + * for ->setattr(), ia->ia_file is passed from ftruncate only. + */ +/* todo: consolidate with do_refresh() and simple_reval_dpath() */ +static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) +{ + int err; + struct inode *inode; + struct dentry *parent; + + err = 0; + inode = dentry->d_inode; + if (au_digen_test(dentry, sigen)) { + parent = dget_parent(dentry); + di_read_lock_parent(parent, AuLock_IR); + err = au_refresh_dentry(dentry, parent); + di_read_unlock(parent, AuLock_IR); + dput(parent); + } + + AuTraceErr(err); + return err; +} + +#define AuIcpup_DID_CPUP 1 +#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) +#define au_fset_icpup(flags, name) \ + do { (flags) |= AuIcpup_##name; } while (0) +#define au_fclr_icpup(flags, name) \ + do { (flags) &= ~AuIcpup_##name; } while (0) + +struct au_icpup_args { + unsigned char flags; + unsigned char pin_flags; + aufs_bindex_t btgt; + unsigned int udba; + struct au_pin pin; + struct path h_path; + struct inode *h_inode; +}; + +static int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, + struct au_icpup_args *a) +{ + int err; + loff_t sz; + aufs_bindex_t bstart, ibstart; + struct dentry *hi_wh, *parent; + struct inode *inode; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = 0 + }; + + bstart = au_dbstart(dentry); + inode = dentry->d_inode; + if (S_ISDIR(inode->i_mode)) + au_fset_wrdir(wr_dir_args.flags, ISDIR); + /* plink or hi_wh() case */ + ibstart = au_ibstart(inode); + if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode)) + wr_dir_args.force_btgt = ibstart; + err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); + if (unlikely(err < 0)) + goto out; + a->btgt = err; + if (err != bstart) + au_fset_icpup(a->flags, DID_CPUP); + + err = 0; + a->pin_flags = AuPin_MNT_WRITE; + parent = NULL; + if (!IS_ROOT(dentry)) { + au_fset_pin(a->pin_flags, DI_LOCKED); + parent = dget_parent(dentry); + di_write_lock_parent(parent); + } + + err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); + if (unlikely(err)) + goto out_parent; + + a->h_path.dentry = au_h_dptr(dentry, bstart); + a->h_inode = a->h_path.dentry->d_inode; + mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); + sz = -1; + if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode)) + sz = ia->ia_size; + mutex_unlock(&a->h_inode->i_mutex); + + hi_wh = NULL; + if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { + hi_wh = au_hi_wh(inode, a->btgt); + if (!hi_wh) { + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = a->btgt, + .bsrc = -1, + .len = sz, + .pin = &a->pin + }; + err = au_sio_cpup_wh(&cpg, /*file*/NULL); + if (unlikely(err)) + goto out_unlock; + hi_wh = au_hi_wh(inode, a->btgt); + /* todo: revalidate hi_wh? */ + } + } + + if (parent) { + au_pin_set_parent_lflag(&a->pin, /*lflag*/0); + di_downgrade_lock(parent, AuLock_IR); + dput(parent); + parent = NULL; + } + if (!au_ftest_icpup(a->flags, DID_CPUP)) + goto out; /* success */ + + if (!d_unhashed(dentry)) { + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = a->btgt, + .bsrc = bstart, + .len = sz, + .pin = &a->pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + err = au_sio_cpup_simple(&cpg); + if (!err) + a->h_path.dentry = au_h_dptr(dentry, a->btgt); + } else if (!hi_wh) + a->h_path.dentry = au_h_dptr(dentry, a->btgt); + else + a->h_path.dentry = hi_wh; /* do not dget here */ + +out_unlock: + a->h_inode = a->h_path.dentry->d_inode; + if (!err) + goto out; /* success */ + au_unpin(&a->pin); +out_parent: + if (parent) { + di_write_unlock(parent); + dput(parent); + } +out: + if (!err) + mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); + return err; +} + +static int aufs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int err; + struct inode *inode, *delegated; + struct super_block *sb; + struct file *file; + struct au_icpup_args *a; + + inode = dentry->d_inode; + IMustLock(inode); + + err = -ENOMEM; + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + ia->ia_valid &= ~ATTR_MODE; + + file = NULL; + sb = dentry->d_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out_kfree; + + if (ia->ia_valid & ATTR_FILE) { + /* currently ftruncate(2) only */ + AuDebugOn(!S_ISREG(inode->i_mode)); + file = ia->ia_file; + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); + if (unlikely(err)) + goto out_si; + ia->ia_file = au_hf_top(file); + a->udba = AuOpt_UDBA_NONE; + } else { + /* fchmod() doesn't pass ia_file */ + a->udba = au_opt_udba(sb); + di_write_lock_child(dentry); + /* no d_unlinked(), to set UDBA_NONE for root */ + if (d_unhashed(dentry)) + a->udba = AuOpt_UDBA_NONE; + if (a->udba != AuOpt_UDBA_NONE) { + AuDebugOn(IS_ROOT(dentry)); + err = au_reval_for_attr(dentry, au_sigen(sb)); + if (unlikely(err)) + goto out_dentry; + } + } + + err = au_pin_and_icpup(dentry, ia, a); + if (unlikely(err < 0)) + goto out_dentry; + if (au_ftest_icpup(a->flags, DID_CPUP)) { + ia->ia_file = NULL; + ia->ia_valid &= ~ATTR_FILE; + } + + a->h_path.mnt = au_sbr_mnt(sb, a->btgt); + if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) + == (ATTR_MODE | ATTR_CTIME)) { + err = security_path_chmod(&a->h_path, ia->ia_mode); + if (unlikely(err)) + goto out_unlock; + } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) + && (ia->ia_valid & ATTR_CTIME)) { + err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); + if (unlikely(err)) + goto out_unlock; + } + + if (ia->ia_valid & ATTR_SIZE) { + struct file *f; + + if (ia->ia_size < i_size_read(inode)) + /* unmap only */ + truncate_setsize(inode, ia->ia_size); + + f = NULL; + if (ia->ia_valid & ATTR_FILE) + f = ia->ia_file; + mutex_unlock(&a->h_inode->i_mutex); + err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); + mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); + } else { + delegated = NULL; + while (1) { + err = vfsub_notify_change(&a->h_path, ia, &delegated); + if (delegated) { + err = break_deleg_wait(&delegated); + if (!err) + continue; + } + break; + } + } + if (!err) + au_cpup_attr_changeable(inode); + +out_unlock: + mutex_unlock(&a->h_inode->i_mutex); + au_unpin(&a->pin); + if (unlikely(err)) + au_update_dbstart(dentry); +out_dentry: + di_write_unlock(dentry); + if (file) { + fi_write_unlock(file); + ia->ia_file = file; + ia->ia_valid |= ATTR_FILE; + } +out_si: + si_read_unlock(sb); +out_kfree: + kfree(a); +out: + AuTraceErr(err); + return err; +} + +static void au_refresh_iattr(struct inode *inode, struct kstat *st, + unsigned int nlink) +{ + unsigned int n; + + inode->i_mode = st->mode; + /* don't i_[ug]id_write() here */ + inode->i_uid = st->uid; + inode->i_gid = st->gid; + inode->i_atime = st->atime; + inode->i_mtime = st->mtime; + inode->i_ctime = st->ctime; + + au_cpup_attr_nlink(inode, /*force*/0); + if (S_ISDIR(inode->i_mode)) { + n = inode->i_nlink; + n -= nlink; + n += st->nlink; + smp_mb(); /* for i_nlink */ + /* 0 can happen */ + set_nlink(inode, n); + } + + spin_lock(&inode->i_lock); + inode->i_blocks = st->blocks; + i_size_write(inode, st->size); + spin_unlock(&inode->i_lock); +} + +static int aufs_getattr(struct vfsmount *mnt __maybe_unused, + struct dentry *dentry, struct kstat *st) +{ + int err; + unsigned int mnt_flags; + aufs_bindex_t bindex; + unsigned char udba_none, positive; + struct super_block *sb, *h_sb; + struct inode *inode; + struct path h_path; + + sb = dentry->d_sb; + inode = dentry->d_inode; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out; + mnt_flags = au_mntflags(sb); + udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); + + /* support fstat(2) */ + if (!d_unlinked(dentry) && !udba_none) { + unsigned int sigen = au_sigen(sb); + err = au_digen_test(dentry, sigen); + if (!err) { + di_read_lock_child(dentry, AuLock_IR); + err = au_dbrange_test(dentry); + if (unlikely(err)) + goto out_unlock; + } else { + AuDebugOn(IS_ROOT(dentry)); + di_write_lock_child(dentry); + err = au_dbrange_test(dentry); + if (!err) + err = au_reval_for_attr(dentry, sigen); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + } + } else + di_read_lock_child(dentry, AuLock_IR); + + bindex = au_ibstart(inode); + h_path.mnt = au_sbr_mnt(sb, bindex); + h_sb = h_path.mnt->mnt_sb; + if (!au_test_fs_bad_iattr(h_sb) && udba_none) + goto out_fill; /* success */ + + h_path.dentry = NULL; + if (au_dbstart(dentry) == bindex) + h_path.dentry = dget(au_h_dptr(dentry, bindex)); + else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { + h_path.dentry = au_plink_lkup(inode, bindex); + if (IS_ERR(h_path.dentry)) + goto out_fill; /* pretending success */ + } + /* illegally overlapped or something */ + if (unlikely(!h_path.dentry)) + goto out_fill; /* pretending success */ + + positive = !!h_path.dentry->d_inode; + if (positive) + err = vfs_getattr(&h_path, st); + dput(h_path.dentry); + if (!err) { + if (positive) + au_refresh_iattr(inode, st, + h_path.dentry->d_inode->i_nlink); + goto out_fill; /* success */ + } + AuTraceErr(err); + goto out_unlock; + +out_fill: + generic_fillattr(inode, st); +out_unlock: + di_read_unlock(dentry, AuLock_IR); + si_read_unlock(sb); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int h_readlink(struct dentry *dentry, int bindex, char __user *buf, + int bufsiz) +{ + int err; + struct super_block *sb; + struct dentry *h_dentry; + + err = -EINVAL; + h_dentry = au_h_dptr(dentry, bindex); + if (unlikely(!h_dentry->d_inode->i_op->readlink)) + goto out; + + err = security_inode_readlink(h_dentry); + if (unlikely(err)) + goto out; + + sb = dentry->d_sb; + if (!au_test_ro(sb, bindex, dentry->d_inode)) { + vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry); + fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode); + } + err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz); + +out: + return err; +} + +static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) +{ + int err; + + err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); + if (unlikely(err)) + goto out; + err = au_d_hashed_positive(dentry); + if (!err) + err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz); + aufs_read_unlock(dentry, AuLock_IR); + +out: + return err; +} + +static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + int err; + mm_segment_t old_fs; + union { + char *k; + char __user *u; + } buf; + + err = -ENOMEM; + buf.k = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!buf.k)) + goto out; + + err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); + if (unlikely(err)) + goto out_name; + + err = au_d_hashed_positive(dentry); + if (!err) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX); + set_fs(old_fs); + } + aufs_read_unlock(dentry, AuLock_IR); + + if (err >= 0) { + buf.k[err] = 0; + /* will be freed by put_link */ + nd_set_link(nd, buf.k); + return NULL; /* success */ + } + +out_name: + free_page((unsigned long)buf.k); +out: + AuTraceErr(err); + return ERR_PTR(err); +} + +static void aufs_put_link(struct dentry *dentry __maybe_unused, + struct nameidata *nd, void *cookie __maybe_unused) +{ + char *p; + + p = nd_get_link(nd); + if (!IS_ERR_OR_NULL(p)) + free_page((unsigned long)p); +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_update_time(struct inode *inode, struct timespec *ts, int flags) +{ + int err; + struct super_block *sb; + struct inode *h_inode; + + sb = inode->i_sb; + /* mmap_sem might be acquired already, cf. aufs_mmap() */ + lockdep_off(); + si_read_lock(sb, AuLock_FLUSH); + ii_write_lock_child(inode); + lockdep_on(); + h_inode = au_h_iptr(inode, au_ibstart(inode)); + err = vfsub_update_time(h_inode, ts, flags); + lockdep_off(); + ii_write_unlock(inode); + si_read_unlock(sb); + lockdep_on(); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct inode_operations aufs_symlink_iop = { + .permission = aufs_permission, + .setattr = aufs_setattr, + .getattr = aufs_getattr, + + .readlink = aufs_readlink, + .follow_link = aufs_follow_link, + .put_link = aufs_put_link, + + /* .update_time = aufs_update_time */ +}; + +struct inode_operations aufs_dir_iop = { + .create = aufs_create, + .lookup = aufs_lookup, + .link = aufs_link, + .unlink = aufs_unlink, + .symlink = aufs_symlink, + .mkdir = aufs_mkdir, + .rmdir = aufs_rmdir, + .mknod = aufs_mknod, + .rename = aufs_rename, + + .permission = aufs_permission, + .setattr = aufs_setattr, + .getattr = aufs_getattr, + + .update_time = aufs_update_time + /* no support for atomic_open() */ +}; + +struct inode_operations aufs_iop = { + .permission = aufs_permission, + .setattr = aufs_setattr, + .getattr = aufs_getattr, + + .update_time = aufs_update_time +}; --- linux-3.13.0.orig/ubuntu/aufs/ioctl.c +++ linux-3.13.0/ubuntu/aufs/ioctl.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * ioctl + * plink-management and readdir in userspace. + * assist the pathconf(3) wrapper library. + * move-down + */ + +#include +#include +#include "aufs.h" + +static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) +{ + int err, fd; + aufs_bindex_t wbi, bindex, bend; + struct file *h_file; + struct super_block *sb; + struct dentry *root; + struct au_branch *br; + struct aufs_wbr_fd wbrfd = { + .oflags = au_dir_roflags, + .brid = -1 + }; + const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY + | O_NOATIME | O_CLOEXEC; + + AuDebugOn(wbrfd.oflags & ~valid); + + if (arg) { + err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); + if (unlikely(err)) { + err = -EFAULT; + goto out; + } + + err = -EINVAL; + AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); + wbrfd.oflags |= au_dir_roflags; + AuDbg("0%o\n", wbrfd.oflags); + if (unlikely(wbrfd.oflags & ~valid)) + goto out; + } + + fd = get_unused_fd(); + err = fd; + if (unlikely(fd < 0)) + goto out; + + h_file = ERR_PTR(-EINVAL); + wbi = 0; + br = NULL; + sb = path->dentry->d_sb; + root = sb->s_root; + aufs_read_lock(root, AuLock_IR); + bend = au_sbend(sb); + if (wbrfd.brid >= 0) { + wbi = au_br_index(sb, wbrfd.brid); + if (unlikely(wbi < 0 || wbi > bend)) + goto out_unlock; + } + + h_file = ERR_PTR(-ENOENT); + br = au_sbr(sb, wbi); + if (!au_br_writable(br->br_perm)) { + if (arg) + goto out_unlock; + + bindex = wbi + 1; + wbi = -1; + for (; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_writable(br->br_perm)) { + wbi = bindex; + br = au_sbr(sb, wbi); + break; + } + } + } + AuDbg("wbi %d\n", wbi); + if (wbi >= 0) + h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, + /*force_wr*/0); + +out_unlock: + aufs_read_unlock(root, AuLock_IR); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out_fd; + + atomic_dec(&br->br_count); /* cf. au_h_open() */ + fd_install(fd, h_file); + err = fd; + goto out; /* success */ + +out_fd: + put_unused_fd(fd); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err; + + switch (cmd) { + case AUFS_CTL_RDU: + case AUFS_CTL_RDU_INO: + err = au_rdu_ioctl(file, cmd, arg); + break; + + case AUFS_CTL_WBR_FD: + err = au_wbr_fd(&file->f_path, (void __user *)arg); + break; + + case AUFS_CTL_IBUSY: + err = au_ibusy_ioctl(file, arg); + break; + + default: + /* do not call the lower */ + AuDbg("0x%x\n", cmd); + err = -ENOTTY; + } + + AuTraceErr(err); + return err; +} + +long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err; + + switch (cmd) { + case AUFS_CTL_MVDOWN: + err = au_mvdown(file->f_dentry, (void __user *)arg); + break; + + case AUFS_CTL_WBR_FD: + err = au_wbr_fd(&file->f_path, (void __user *)arg); + break; + + default: + /* do not call the lower */ + AuDbg("0x%x\n", cmd); + err = -ENOTTY; + } + + AuTraceErr(err); + return err; +} + +#ifdef CONFIG_COMPAT +long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long err; + + switch (cmd) { + case AUFS_CTL_RDU: + case AUFS_CTL_RDU_INO: + err = au_rdu_compat_ioctl(file, cmd, arg); + break; + + case AUFS_CTL_IBUSY: + err = au_ibusy_compat_ioctl(file, arg); + break; + + default: + err = aufs_ioctl_dir(file, cmd, arg); + } + + AuTraceErr(err); + return err; +} + +long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif --- linux-3.13.0.orig/ubuntu/aufs/cpup.h +++ linux-3.13.0/ubuntu/aufs/cpup.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * copy-up/down functions + */ + +#ifndef __AUFS_CPUP_H__ +#define __AUFS_CPUP_H__ + +#ifdef __KERNEL__ + +#include + +struct inode; +struct file; +struct au_pin; + +void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); +void au_cpup_attr_timesizes(struct inode *inode); +void au_cpup_attr_nlink(struct inode *inode, int force); +void au_cpup_attr_changeable(struct inode *inode); +void au_cpup_igen(struct inode *inode, struct inode *h_inode); +void au_cpup_attr_all(struct inode *inode, int force); + +/* ---------------------------------------------------------------------- */ + +struct au_cp_generic { + struct dentry *dentry; + aufs_bindex_t bdst, bsrc; + loff_t len; + struct au_pin *pin; + unsigned int flags; +}; + +/* cpup flags */ +#define AuCpup_DTIME 1 /* do dtime_store/revert */ +#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, + for link(2) */ +#define AuCpup_RENAME (1 << 2) /* rename after cpup */ +#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in + cpup */ +#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the + existing entry */ +#define AuCpup_RWDST (1 << 5) /* force write target even if + the branch is marked as RO */ + +#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) +#define au_fset_cpup(flags, name) \ + do { (flags) |= AuCpup_##name; } while (0) +#define au_fclr_cpup(flags, name) \ + do { (flags) &= ~AuCpup_##name; } while (0) + +int au_copy_file(struct file *dst, struct file *src, loff_t len); +int au_sio_cpup_simple(struct au_cp_generic *cpg); +int au_sio_cpdown_simple(struct au_cp_generic *cpg); +int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); + +int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, + int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent, void *arg), + void *arg); +int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); +int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); + +/* ---------------------------------------------------------------------- */ + +/* keep timestamps when copyup */ +struct au_dtime { + struct dentry *dt_dentry; + struct path dt_h_path; + struct timespec dt_atime, dt_mtime; +}; +void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, + struct path *h_path); +void au_dtime_revert(struct au_dtime *dt); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_CPUP_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/rdu.c +++ linux-3.13.0/ubuntu/aufs/rdu.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * readdir in userspace. + */ + +#include +#include +#include +#include "aufs.h" + +/* bits for struct aufs_rdu.flags */ +#define AuRdu_CALLED 1 +#define AuRdu_CONT (1 << 1) +#define AuRdu_FULL (1 << 2) +#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) +#define au_fset_rdu(flags, name) \ + do { (flags) |= AuRdu_##name; } while (0) +#define au_fclr_rdu(flags, name) \ + do { (flags) &= ~AuRdu_##name; } while (0) + +struct au_rdu_arg { + struct dir_context ctx; + struct aufs_rdu *rdu; + union au_rdu_ent_ul ent; + unsigned long end; + + struct super_block *sb; + int err; +}; + +static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, + loff_t offset, u64 h_ino, unsigned int d_type) +{ + int err, len; + struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); + struct aufs_rdu *rdu = arg->rdu; + struct au_rdu_ent ent; + + err = 0; + arg->err = 0; + au_fset_rdu(rdu->cookie.flags, CALLED); + len = au_rdu_len(nlen); + if (arg->ent.ul + len < arg->end) { + ent.ino = h_ino; + ent.bindex = rdu->cookie.bindex; + ent.type = d_type; + ent.nlen = nlen; + if (unlikely(nlen > AUFS_MAX_NAMELEN)) + ent.type = DT_UNKNOWN; + + /* unnecessary to support mmap_sem since this is a dir */ + err = -EFAULT; + if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) + goto out; + if (copy_to_user(arg->ent.e->name, name, nlen)) + goto out; + /* the terminating NULL */ + if (__put_user(0, arg->ent.e->name + nlen)) + goto out; + err = 0; + /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ + arg->ent.ul += len; + rdu->rent++; + } else { + err = -EFAULT; + au_fset_rdu(rdu->cookie.flags, FULL); + rdu->full = 1; + rdu->tail = arg->ent; + } + +out: + /* AuTraceErr(err); */ + return err; +} + +static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) +{ + int err; + loff_t offset; + struct au_rdu_cookie *cookie = &arg->rdu->cookie; + + /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ + offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); + err = offset; + if (unlikely(offset != cookie->h_pos)) + goto out; + + err = 0; + do { + arg->err = 0; + au_fclr_rdu(cookie->flags, CALLED); + /* smp_mb(); */ + err = vfsub_iterate_dir(h_file, &arg->ctx); + if (err >= 0) + err = arg->err; + } while (!err + && au_ftest_rdu(cookie->flags, CALLED) + && !au_ftest_rdu(cookie->flags, FULL)); + cookie->h_pos = h_file->f_pos; + +out: + AuTraceErr(err); + return err; +} + +static int au_rdu(struct file *file, struct aufs_rdu *rdu) +{ + int err; + aufs_bindex_t bend; + struct au_rdu_arg arg = { + .ctx = { + .actor = au_diractor(au_rdu_fill) + } + }; + struct dentry *dentry; + struct inode *inode; + struct file *h_file; + struct au_rdu_cookie *cookie = &rdu->cookie; + + err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + rdu->rent = 0; + rdu->tail = rdu->ent; + rdu->full = 0; + arg.rdu = rdu; + arg.ent = rdu->ent; + arg.end = arg.ent.ul; + arg.end += rdu->sz; + + err = -ENOTDIR; + if (unlikely(!file->f_op->iterate)) + goto out; + + err = security_file_permission(file, MAY_READ); + AuTraceErr(err); + if (unlikely(err)) + goto out; + + dentry = file->f_dentry; + inode = dentry->d_inode; +#if 1 + mutex_lock(&inode->i_mutex); +#else + err = mutex_lock_killable(&inode->i_mutex); + AuTraceErr(err); + if (unlikely(err)) + goto out; +#endif + + arg.sb = inode->i_sb; + err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out_mtx; + err = au_alive_dir(dentry); + if (unlikely(err)) + goto out_si; + /* todo: reval? */ + fi_read_lock(file); + + err = -EAGAIN; + if (unlikely(au_ftest_rdu(cookie->flags, CONT) + && cookie->generation != au_figen(file))) + goto out_unlock; + + err = 0; + if (!rdu->blk) { + rdu->blk = au_sbi(arg.sb)->si_rdblk; + if (!rdu->blk) + rdu->blk = au_dir_size(file, /*dentry*/NULL); + } + bend = au_fbstart(file); + if (cookie->bindex < bend) + cookie->bindex = bend; + bend = au_fbend_dir(file); + /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */ + for (; !err && cookie->bindex <= bend; + cookie->bindex++, cookie->h_pos = 0) { + h_file = au_hf_dir(file, cookie->bindex); + if (!h_file) + continue; + + au_fclr_rdu(cookie->flags, FULL); + err = au_rdu_do(h_file, &arg); + AuTraceErr(err); + if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) + break; + } + AuDbg("rent %llu\n", rdu->rent); + + if (!err && !au_ftest_rdu(cookie->flags, CONT)) { + rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); + au_fset_rdu(cookie->flags, CONT); + cookie->generation = au_figen(file); + } + + ii_read_lock_child(inode); + fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode))); + ii_read_unlock(inode); + +out_unlock: + fi_read_unlock(file); +out_si: + si_read_unlock(arg.sb); +out_mtx: + mutex_unlock(&inode->i_mutex); +out: + AuTraceErr(err); + return err; +} + +static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) +{ + int err; + ino_t ino; + unsigned long long nent; + union au_rdu_ent_ul *u; + struct au_rdu_ent ent; + struct super_block *sb; + + err = 0; + nent = rdu->nent; + u = &rdu->ent; + sb = file->f_dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + while (nent-- > 0) { + /* unnecessary to support mmap_sem since this is a dir */ + err = copy_from_user(&ent, u->e, sizeof(ent)); + if (!err) + err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + break; + } + + /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ + if (!ent.wh) + err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); + else + err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, + &ino); + if (unlikely(err)) { + AuTraceErr(err); + break; + } + + err = __put_user(ino, &u->e->ino); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + break; + } + u->ul += au_rdu_len(ent.nlen); + } + si_read_unlock(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_rdu_verify(struct aufs_rdu *rdu) +{ + AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " + "%llu, b%d, 0x%x, g%u}\n", + rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], + rdu->blk, + rdu->rent, rdu->shwh, rdu->full, + rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, + rdu->cookie.generation); + + if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) + return 0; + + AuDbg("%u:%u\n", + rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); + return -EINVAL; +} + +long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err, e; + struct aufs_rdu rdu; + void __user *p = (void __user *)arg; + + err = copy_from_user(&rdu, p, sizeof(rdu)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + err = au_rdu_verify(&rdu); + if (unlikely(err)) + goto out; + + switch (cmd) { + case AUFS_CTL_RDU: + err = au_rdu(file, &rdu); + if (unlikely(err)) + break; + + e = copy_to_user(p, &rdu, sizeof(rdu)); + if (unlikely(e)) { + err = -EFAULT; + AuTraceErr(err); + } + break; + case AUFS_CTL_RDU_INO: + err = au_rdu_ino(file, &rdu); + break; + + default: + /* err = -ENOTTY; */ + err = -EINVAL; + } + +out: + AuTraceErr(err); + return err; +} + +#ifdef CONFIG_COMPAT +long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err, e; + struct aufs_rdu rdu; + void __user *p = compat_ptr(arg); + + /* todo: get_user()? */ + err = copy_from_user(&rdu, p, sizeof(rdu)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + rdu.ent.e = compat_ptr(rdu.ent.ul); + err = au_rdu_verify(&rdu); + if (unlikely(err)) + goto out; + + switch (cmd) { + case AUFS_CTL_RDU: + err = au_rdu(file, &rdu); + if (unlikely(err)) + break; + + rdu.ent.ul = ptr_to_compat(rdu.ent.e); + rdu.tail.ul = ptr_to_compat(rdu.tail.e); + e = copy_to_user(p, &rdu, sizeof(rdu)); + if (unlikely(e)) { + err = -EFAULT; + AuTraceErr(err); + } + break; + case AUFS_CTL_RDU_INO: + err = au_rdu_ino(file, &rdu); + break; + + default: + /* err = -ENOTTY; */ + err = -EINVAL; + } + +out: + AuTraceErr(err); + return err; +} +#endif --- linux-3.13.0.orig/ubuntu/aufs/inode.c +++ linux-3.13.0/ubuntu/aufs/inode.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode functions + */ + +#include "aufs.h" + +struct inode *au_igrab(struct inode *inode) +{ + if (inode) { + AuDebugOn(!atomic_read(&inode->i_count)); + ihold(inode); + } + return inode; +} + +static void au_refresh_hinode_attr(struct inode *inode, int do_version) +{ + au_cpup_attr_all(inode, /*force*/0); + au_update_iigen(inode, /*half*/1); + if (do_version) + inode->i_version++; +} + +static int au_ii_refresh(struct inode *inode, int *update) +{ + int err, e; + umode_t type; + aufs_bindex_t bindex, new_bindex; + struct super_block *sb; + struct au_iinfo *iinfo; + struct au_hinode *p, *q, tmp; + + IiMustWriteLock(inode); + + *update = 0; + sb = inode->i_sb; + type = inode->i_mode & S_IFMT; + iinfo = au_ii(inode); + err = au_ii_realloc(iinfo, au_sbend(sb) + 1); + if (unlikely(err)) + goto out; + + AuDebugOn(iinfo->ii_bstart < 0); + p = iinfo->ii_hinode + iinfo->ii_bstart; + for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; + bindex++, p++) { + if (!p->hi_inode) + continue; + + AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); + new_bindex = au_br_index(sb, p->hi_id); + if (new_bindex == bindex) + continue; + + if (new_bindex < 0) { + *update = 1; + au_hiput(p); + p->hi_inode = NULL; + continue; + } + + if (new_bindex < iinfo->ii_bstart) + iinfo->ii_bstart = new_bindex; + if (iinfo->ii_bend < new_bindex) + iinfo->ii_bend = new_bindex; + /* swap two lower inode, and loop again */ + q = iinfo->ii_hinode + new_bindex; + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hi_inode) { + bindex--; + p--; + } + } + au_update_ibrange(inode, /*do_put_zero*/0); + e = au_dy_irefresh(inode); + if (unlikely(e && !err)) + err = e; + +out: + AuTraceErr(err); + return err; +} + +int au_refresh_hinode_self(struct inode *inode) +{ + int err, update; + + err = au_ii_refresh(inode, &update); + if (!err) + au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); + + AuTraceErr(err); + return err; +} + +int au_refresh_hinode(struct inode *inode, struct dentry *dentry) +{ + int err, e, update; + unsigned int flags; + umode_t mode; + aufs_bindex_t bindex, bend; + unsigned char isdir; + struct au_hinode *p; + struct au_iinfo *iinfo; + + err = au_ii_refresh(inode, &update); + if (unlikely(err)) + goto out; + + update = 0; + iinfo = au_ii(inode); + p = iinfo->ii_hinode + iinfo->ii_bstart; + mode = (inode->i_mode & S_IFMT); + isdir = S_ISDIR(mode); + flags = au_hi_flags(inode, isdir); + bend = au_dbend(dentry); + for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { + struct inode *h_i; + struct dentry *h_d; + + h_d = au_h_dptr(dentry, bindex); + if (!h_d || !h_d->d_inode) + continue; + + AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT)); + if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { + h_i = au_h_iptr(inode, bindex); + if (h_i) { + if (h_i == h_d->d_inode) + continue; + err = -EIO; + break; + } + } + if (bindex < iinfo->ii_bstart) + iinfo->ii_bstart = bindex; + if (iinfo->ii_bend < bindex) + iinfo->ii_bend = bindex; + au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags); + update = 1; + } + au_update_ibrange(inode, /*do_put_zero*/0); + e = au_dy_irefresh(inode); + if (unlikely(e && !err)) + err = e; + if (!err) + au_refresh_hinode_attr(inode, update && isdir); + +out: + AuTraceErr(err); + return err; +} + +static int set_inode(struct inode *inode, struct dentry *dentry) +{ + int err; + unsigned int flags; + umode_t mode; + aufs_bindex_t bindex, bstart, btail; + unsigned char isdir; + struct dentry *h_dentry; + struct inode *h_inode; + struct au_iinfo *iinfo; + + IiMustWriteLock(inode); + + err = 0; + isdir = 0; + bstart = au_dbstart(dentry); + h_inode = au_h_dptr(dentry, bstart)->d_inode; + mode = h_inode->i_mode; + switch (mode & S_IFMT) { + case S_IFREG: + btail = au_dbtail(dentry); + inode->i_op = &aufs_iop; + inode->i_fop = &aufs_file_fop; + err = au_dy_iaop(inode, bstart, h_inode); + if (unlikely(err)) + goto out; + break; + case S_IFDIR: + isdir = 1; + btail = au_dbtaildir(dentry); + inode->i_op = &aufs_dir_iop; + inode->i_fop = &aufs_dir_fop; + break; + case S_IFLNK: + btail = au_dbtail(dentry); + inode->i_op = &aufs_symlink_iop; + break; + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + case S_IFSOCK: + btail = au_dbtail(dentry); + inode->i_op = &aufs_iop; + au_init_special_fop(inode, mode, h_inode->i_rdev); + break; + default: + AuIOErr("Unknown file type 0%o\n", mode); + err = -EIO; + goto out; + } + + /* do not set hnotify for whiteouted dirs (SHWH mode) */ + flags = au_hi_flags(inode, isdir); + if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) + && au_ftest_hi(flags, HNOTIFY) + && dentry->d_name.len > AUFS_WH_PFX_LEN + && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) + au_fclr_hi(flags, HNOTIFY); + iinfo = au_ii(inode); + iinfo->ii_bstart = bstart; + iinfo->ii_bend = btail; + for (bindex = bstart; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry) + au_set_h_iptr(inode, bindex, + au_igrab(h_dentry->d_inode), flags); + } + au_cpup_attr_all(inode, /*force*/1); + +out: + return err; +} + +/* + * successful returns with iinfo write_locked + * minus: errno + * zero: success, matched + * plus: no error, but unmatched + */ +static int reval_inode(struct inode *inode, struct dentry *dentry) +{ + int err; + unsigned int gen; + struct au_iigen iigen; + aufs_bindex_t bindex, bend; + struct inode *h_inode, *h_dinode; + + /* + * before this function, if aufs got any iinfo lock, it must be only + * one, the parent dir. + * it can happen by UDBA and the obsoleted inode number. + */ + err = -EIO; + if (unlikely(inode->i_ino == parent_ino(dentry))) + goto out; + + err = 1; + ii_write_lock_new_child(inode); + h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode; + bend = au_ibend(inode); + for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (!h_inode || h_inode != h_dinode) + continue; + + err = 0; + gen = au_iigen(inode, &iigen); + if (gen == au_digen(dentry) + && !au_ig_ftest(iigen.ig_flags, HALF_REFRESHED)) + break; + + /* fully refresh inode using dentry */ + err = au_refresh_hinode(inode, dentry); + if (!err) + au_update_iigen(inode, /*half*/0); + break; + } + + if (unlikely(err)) + ii_write_unlock(inode); +out: + return err; +} + +int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + unsigned int d_type, ino_t *ino) +{ + int err; + struct mutex *mtx; + + /* prevent hardlinked inode number from race condition */ + mtx = NULL; + if (d_type != DT_DIR) { + mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; + mutex_lock(mtx); + } + err = au_xino_read(sb, bindex, h_ino, ino); + if (unlikely(err)) + goto out; + + if (!*ino) { + err = -EIO; + *ino = au_xino_new_ino(sb); + if (unlikely(!*ino)) + goto out; + err = au_xino_write(sb, bindex, h_ino, *ino); + if (unlikely(err)) + goto out; + } + +out: + if (mtx) + mutex_unlock(mtx); + return err; +} + +/* successful returns with iinfo write_locked */ +/* todo: return with unlocked? */ +struct inode *au_new_inode(struct dentry *dentry, int must_new) +{ + struct inode *inode, *h_inode; + struct dentry *h_dentry; + struct super_block *sb; + struct mutex *mtx; + ino_t h_ino, ino; + int err; + aufs_bindex_t bstart; + + sb = dentry->d_sb; + bstart = au_dbstart(dentry); + h_dentry = au_h_dptr(dentry, bstart); + h_inode = h_dentry->d_inode; + h_ino = h_inode->i_ino; + + /* + * stop 'race'-ing between hardlinks under different + * parents. + */ + mtx = NULL; + if (!S_ISDIR(h_inode->i_mode)) + mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; + +new_ino: + if (mtx) + mutex_lock(mtx); + err = au_xino_read(sb, bstart, h_ino, &ino); + inode = ERR_PTR(err); + if (unlikely(err)) + goto out; + + if (!ino) { + ino = au_xino_new_ino(sb); + if (unlikely(!ino)) { + inode = ERR_PTR(-EIO); + goto out; + } + } + + AuDbg("i%lu\n", (unsigned long)ino); + inode = au_iget_locked(sb, ino); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out; + + AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); + if (inode->i_state & I_NEW) { + /* verbose coding for lock class name */ + if (unlikely(S_ISLNK(h_inode->i_mode))) + au_rw_class(&au_ii(inode)->ii_rwsem, + au_lc_key + AuLcSymlink_IIINFO); + else if (unlikely(S_ISDIR(h_inode->i_mode))) + au_rw_class(&au_ii(inode)->ii_rwsem, + au_lc_key + AuLcDir_IIINFO); + else /* likely */ + au_rw_class(&au_ii(inode)->ii_rwsem, + au_lc_key + AuLcNonDir_IIINFO); + + ii_write_lock_new_child(inode); + err = set_inode(inode, dentry); + if (!err) { + unlock_new_inode(inode); + goto out; /* success */ + } + + /* + * iget_failed() calls iput(), but we need to call + * ii_write_unlock() after iget_failed(). so dirty hack for + * i_count. + */ + atomic_inc(&inode->i_count); + iget_failed(inode); + ii_write_unlock(inode); + au_xino_write(sb, bstart, h_ino, /*ino*/0); + /* ignore this error */ + goto out_iput; + } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { + /* + * horrible race condition between lookup, readdir and copyup + * (or something). + */ + if (mtx) + mutex_unlock(mtx); + err = reval_inode(inode, dentry); + if (unlikely(err < 0)) { + mtx = NULL; + goto out_iput; + } + + if (!err) { + mtx = NULL; + goto out; /* success */ + } else if (mtx) + mutex_lock(mtx); + } + + if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode))) + AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," + " b%d, %s, %pd, hi%lu, i%lu.\n", + bstart, au_sbtype(h_dentry->d_sb), dentry, + (unsigned long)h_ino, (unsigned long)ino); + ino = 0; + err = au_xino_write(sb, bstart, h_ino, /*ino*/0); + if (!err) { + iput(inode); + if (mtx) + mutex_unlock(mtx); + goto new_ino; + } + +out_iput: + iput(inode); + inode = ERR_PTR(err); +out: + if (mtx) + mutex_unlock(mtx); + return inode; +} + +/* ---------------------------------------------------------------------- */ + +int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode) +{ + int err; + + err = au_br_rdonly(au_sbr(sb, bindex)); + + /* pseudo-link after flushed may happen out of bounds */ + if (!err + && inode + && au_ibstart(inode) <= bindex + && bindex <= au_ibend(inode)) { + /* + * permission check is unnecessary since vfsub routine + * will be called later + */ + struct inode *hi = au_h_iptr(inode, bindex); + if (hi) + err = IS_IMMUTABLE(hi) ? -EROFS : 0; + } + + return err; +} + +int au_test_h_perm(struct inode *h_inode, int mask) +{ + if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) + return 0; + return inode_permission(h_inode, mask); +} + +int au_test_h_perm_sio(struct inode *h_inode, int mask) +{ + if (au_test_nfs(h_inode->i_sb) + && (mask & MAY_WRITE) + && S_ISDIR(h_inode->i_mode)) + mask |= MAY_READ; /* force permission check */ + return au_test_h_perm(h_inode, mask); +} --- linux-3.13.0.orig/ubuntu/aufs/opts.c +++ linux-3.13.0/ubuntu/aufs/opts.c @@ -0,0 +1,1701 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * mount options/flags + */ + +#include +#include /* a distribution requires */ +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +enum { + Opt_br, + Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend, + Opt_idel, Opt_imod, Opt_ireorder, + Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rendir, + Opt_rdblk_def, Opt_rdhash_def, + Opt_xino, Opt_zxino, Opt_noxino, + Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, + Opt_trunc_xino_path, Opt_itrunc_xino, + Opt_trunc_xib, Opt_notrunc_xib, + Opt_shwh, Opt_noshwh, + Opt_plink, Opt_noplink, Opt_list_plink, + Opt_udba, + Opt_dio, Opt_nodio, + /* Opt_lock, Opt_unlock, */ + Opt_cmd, Opt_cmd_args, + Opt_diropq_a, Opt_diropq_w, + Opt_warn_perm, Opt_nowarn_perm, + Opt_wbr_copyup, Opt_wbr_create, + Opt_refrof, Opt_norefrof, + Opt_verbose, Opt_noverbose, + Opt_sum, Opt_nosum, Opt_wsum, + Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err +}; + +static match_table_t options = { + {Opt_br, "br=%s"}, + {Opt_br, "br:%s"}, + + {Opt_add, "add=%d:%s"}, + {Opt_add, "add:%d:%s"}, + {Opt_add, "ins=%d:%s"}, + {Opt_add, "ins:%d:%s"}, + {Opt_append, "append=%s"}, + {Opt_append, "append:%s"}, + {Opt_prepend, "prepend=%s"}, + {Opt_prepend, "prepend:%s"}, + + {Opt_del, "del=%s"}, + {Opt_del, "del:%s"}, + /* {Opt_idel, "idel:%d"}, */ + {Opt_mod, "mod=%s"}, + {Opt_mod, "mod:%s"}, + /* {Opt_imod, "imod:%d:%s"}, */ + + {Opt_dirwh, "dirwh=%d"}, + + {Opt_xino, "xino=%s"}, + {Opt_noxino, "noxino"}, + {Opt_trunc_xino, "trunc_xino"}, + {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, + {Opt_notrunc_xino, "notrunc_xino"}, + {Opt_trunc_xino_path, "trunc_xino=%s"}, + {Opt_itrunc_xino, "itrunc_xino=%d"}, + /* {Opt_zxino, "zxino=%s"}, */ + {Opt_trunc_xib, "trunc_xib"}, + {Opt_notrunc_xib, "notrunc_xib"}, + +#ifdef CONFIG_PROC_FS + {Opt_plink, "plink"}, +#else + {Opt_ignore_silent, "plink"}, +#endif + + {Opt_noplink, "noplink"}, + +#ifdef CONFIG_AUFS_DEBUG + {Opt_list_plink, "list_plink"}, +#endif + + {Opt_udba, "udba=%s"}, + + {Opt_dio, "dio"}, + {Opt_nodio, "nodio"}, + + {Opt_diropq_a, "diropq=always"}, + {Opt_diropq_a, "diropq=a"}, + {Opt_diropq_w, "diropq=whiteouted"}, + {Opt_diropq_w, "diropq=w"}, + + {Opt_warn_perm, "warn_perm"}, + {Opt_nowarn_perm, "nowarn_perm"}, + + /* keep them temporary */ + {Opt_ignore_silent, "coo=%s"}, + {Opt_ignore_silent, "nodlgt"}, + {Opt_ignore_silent, "nodirperm1"}, + {Opt_ignore_silent, "clean_plink"}, + +#ifdef CONFIG_AUFS_SHWH + {Opt_shwh, "shwh"}, +#endif + {Opt_noshwh, "noshwh"}, + + {Opt_rendir, "rendir=%d"}, + + {Opt_refrof, "refrof"}, + {Opt_norefrof, "norefrof"}, + + {Opt_verbose, "verbose"}, + {Opt_verbose, "v"}, + {Opt_noverbose, "noverbose"}, + {Opt_noverbose, "quiet"}, + {Opt_noverbose, "q"}, + {Opt_noverbose, "silent"}, + + {Opt_sum, "sum"}, + {Opt_nosum, "nosum"}, + {Opt_wsum, "wsum"}, + + {Opt_rdcache, "rdcache=%d"}, + {Opt_rdblk, "rdblk=%d"}, + {Opt_rdblk_def, "rdblk=def"}, + {Opt_rdhash, "rdhash=%d"}, + {Opt_rdhash_def, "rdhash=def"}, + + {Opt_wbr_create, "create=%s"}, + {Opt_wbr_create, "create_policy=%s"}, + {Opt_wbr_copyup, "cpup=%s"}, + {Opt_wbr_copyup, "copyup=%s"}, + {Opt_wbr_copyup, "copyup_policy=%s"}, + + /* internal use for the scripts */ + {Opt_ignore_silent, "si=%s"}, + + {Opt_br, "dirs=%s"}, + {Opt_ignore, "debug=%d"}, + {Opt_ignore, "delete=whiteout"}, + {Opt_ignore, "delete=all"}, + {Opt_ignore, "imap=%s"}, + + /* temporary workaround, due to old mount(8)? */ + {Opt_ignore_silent, "relatime"}, + + {Opt_err, NULL} +}; + +/* ---------------------------------------------------------------------- */ + +static const char *au_parser_pattern(int val, struct match_token *token) +{ + while (token->pattern) { + if (token->token == val) + return token->pattern; + token++; + } + BUG(); + return "??"; +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t brperm = { + {AuBrPerm_RO, AUFS_BRPERM_RO}, + {AuBrPerm_RR, AUFS_BRPERM_RR}, + {AuBrPerm_RW, AUFS_BRPERM_RW}, + {0, NULL} +}; + +static match_table_t brattr = { + {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, + {AuBrRAttr_WH, AUFS_BRRATTR_WH}, + {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, + {0, NULL} +}; + +#define AuBrStr_LONGEST AUFS_BRPERM_RW \ + "+" AUFS_BRATTR_UNPIN \ + "+" AUFS_BRWATTR_NLWH + +static int br_attr_val(char *str, match_table_t table, substring_t args[]) +{ + int attr, v; + char *p; + + attr = 0; + do { + p = strchr(str, '+'); + if (p) + *p = 0; + v = match_token(str, table, args); + if (v) + attr |= v; + else { + if (p) + *p = '+'; + pr_warn("ignored branch attribute %s\n", str); + break; + } + if (p) + str = p + 1; + } while (p); + + return attr; +} + +static int noinline_for_stack br_perm_val(char *perm) +{ + int val; + char *p, *q; + substring_t args[MAX_OPT_ARGS]; + + p = strchr(perm, '+'); + if (p) + *p = 0; + val = match_token(perm, brperm, args); + if (!val) { + if (p) + *p = '+'; + pr_warn("ignored branch permission %s\n", perm); + val = AuBrPerm_RO; + goto out; + } + if (!p) + goto out; + + p++; + while (1) { + q = strchr(p, '+'); + if (q) + *q = 0; + val |= br_attr_val(p, brattr, args); + if (q) { + *q = '+'; + p = q + 1; + } else + break; + } + switch (val & AuBrPerm_Mask) { + case AuBrPerm_RO: + case AuBrPerm_RR: + if (unlikely(val & AuBrWAttr_NoLinkWH)) { + pr_warn("ignored branch attribute %s\n", + AUFS_BRWATTR_NLWH); + val &= ~AuBrWAttr_NoLinkWH; + } + break; + case AuBrPerm_RW: + if (unlikely(val & AuBrRAttr_WH)) { + pr_warn("ignored branch attribute %s\n", + AUFS_BRRATTR_WH); + val &= ~AuBrRAttr_WH; + } + break; + } + +out: + return val; +} + +/* Caller should free the return value */ +char *au_optstr_br_perm(int brperm) +{ + char *p, a[sizeof(AuBrStr_LONGEST)]; + int sz; + +#define SetPerm(str) do { \ + sz = sizeof(str); \ + memcpy(a, str, sz); \ + p = a + sz - 1; \ + } while (0) + +#define AppendAttr(flag, str) do { \ + if (brperm & flag) { \ + sz = sizeof(str); \ + *p++ = '+'; \ + memcpy(p, str, sz); \ + p += sz - 1; \ + } \ + } while (0) + + switch (brperm & AuBrPerm_Mask) { + case AuBrPerm_RO: + SetPerm(AUFS_BRPERM_RO); + break; + case AuBrPerm_RR: + SetPerm(AUFS_BRPERM_RR); + break; + case AuBrPerm_RW: + SetPerm(AUFS_BRPERM_RW); + break; + default: + AuDebugOn(1); + } + + AppendAttr(AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN); + AppendAttr(AuBrRAttr_WH, AUFS_BRRATTR_WH); + AppendAttr(AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH); + + AuDebugOn(strlen(a) >= sizeof(a)); + return kstrdup(a, GFP_NOFS); +#undef SetPerm +#undef AppendAttr +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t udbalevel = { + {AuOpt_UDBA_REVAL, "reval"}, + {AuOpt_UDBA_NONE, "none"}, +#ifdef CONFIG_AUFS_HNOTIFY + {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ +#ifdef CONFIG_AUFS_HFSNOTIFY + {AuOpt_UDBA_HNOTIFY, "fsnotify"}, +#endif +#endif + {-1, NULL} +}; + +static int noinline_for_stack udba_val(char *str) +{ + substring_t args[MAX_OPT_ARGS]; + + return match_token(str, udbalevel, args); +} + +const char *au_optstr_udba(int udba) +{ + return au_parser_pattern(udba, (void *)udbalevel); +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t au_wbr_create_policy = { + {AuWbrCreate_TDP, "tdp"}, + {AuWbrCreate_TDP, "top-down-parent"}, + {AuWbrCreate_RR, "rr"}, + {AuWbrCreate_RR, "round-robin"}, + {AuWbrCreate_MFS, "mfs"}, + {AuWbrCreate_MFS, "most-free-space"}, + {AuWbrCreate_MFSV, "mfs:%d"}, + {AuWbrCreate_MFSV, "most-free-space:%d"}, + + {AuWbrCreate_MFSRR, "mfsrr:%d"}, + {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, + {AuWbrCreate_PMFS, "pmfs"}, + {AuWbrCreate_PMFSV, "pmfs:%d"}, + {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, + {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, + + {-1, NULL} +}; + +/* + * cf. linux/lib/parser.c and cmdline.c + * gave up calling memparse() since it uses simple_strtoull() instead of + * kstrto...(). + */ +static int noinline_for_stack +au_match_ull(substring_t *s, unsigned long long *result) +{ + int err; + unsigned int len; + char a[32]; + + err = -ERANGE; + len = s->to - s->from; + if (len + 1 <= sizeof(a)) { + memcpy(a, s->from, len); + a[len] = '\0'; + err = kstrtoull(a, 0, result); + } + return err; +} + +static int au_wbr_mfs_wmark(substring_t *arg, char *str, + struct au_opt_wbr_create *create) +{ + int err; + unsigned long long ull; + + err = 0; + if (!au_match_ull(arg, &ull)) + create->mfsrr_watermark = ull; + else { + pr_err("bad integer in %s\n", str); + err = -EINVAL; + } + + return err; +} + +static int au_wbr_mfs_sec(substring_t *arg, char *str, + struct au_opt_wbr_create *create) +{ + int n, err; + + err = 0; + if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) + create->mfs_second = n; + else { + pr_err("bad integer in %s\n", str); + err = -EINVAL; + } + + return err; +} + +static int noinline_for_stack +au_wbr_create_val(char *str, struct au_opt_wbr_create *create) +{ + int err, e; + substring_t args[MAX_OPT_ARGS]; + + err = match_token(str, au_wbr_create_policy, args); + create->wbr_create = err; + switch (err) { + case AuWbrCreate_MFSRRV: + case AuWbrCreate_PMFSRRV: + e = au_wbr_mfs_wmark(&args[0], str, create); + if (!e) + e = au_wbr_mfs_sec(&args[1], str, create); + if (unlikely(e)) + err = e; + break; + case AuWbrCreate_MFSRR: + case AuWbrCreate_PMFSRR: + e = au_wbr_mfs_wmark(&args[0], str, create); + if (unlikely(e)) { + err = e; + break; + } + /*FALLTHROUGH*/ + case AuWbrCreate_MFS: + case AuWbrCreate_PMFS: + create->mfs_second = AUFS_MFS_DEF_SEC; + break; + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFSV: + e = au_wbr_mfs_sec(&args[0], str, create); + if (unlikely(e)) + err = e; + break; + } + + return err; +} + +const char *au_optstr_wbr_create(int wbr_create) +{ + return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy); +} + +static match_table_t au_wbr_copyup_policy = { + {AuWbrCopyup_TDP, "tdp"}, + {AuWbrCopyup_TDP, "top-down-parent"}, + {AuWbrCopyup_BUP, "bup"}, + {AuWbrCopyup_BUP, "bottom-up-parent"}, + {AuWbrCopyup_BU, "bu"}, + {AuWbrCopyup_BU, "bottom-up"}, + {-1, NULL} +}; + +static int noinline_for_stack au_wbr_copyup_val(char *str) +{ + substring_t args[MAX_OPT_ARGS]; + + return match_token(str, au_wbr_copyup_policy, args); +} + +const char *au_optstr_wbr_copyup(int wbr_copyup) +{ + return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy); +} + +/* ---------------------------------------------------------------------- */ + +static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; + +static void dump_opts(struct au_opts *opts) +{ +#ifdef CONFIG_AUFS_DEBUG + /* reduce stack space */ + union { + struct au_opt_add *add; + struct au_opt_del *del; + struct au_opt_mod *mod; + struct au_opt_xino *xino; + struct au_opt_xino_itrunc *xino_itrunc; + struct au_opt_wbr_create *create; + } u; + struct au_opt *opt; + + opt = opts->opt; + while (opt->type != Opt_tail) { + switch (opt->type) { + case Opt_add: + u.add = &opt->add; + AuDbg("add {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->pathname, u.add->perm, + u.add->path.dentry); + break; + case Opt_del: + case Opt_idel: + u.del = &opt->del; + AuDbg("del {%s, %p}\n", + u.del->pathname, u.del->h_path.dentry); + break; + case Opt_mod: + case Opt_imod: + u.mod = &opt->mod; + AuDbg("mod {%s, 0x%x, %p}\n", + u.mod->path, u.mod->perm, u.mod->h_root); + break; + case Opt_append: + u.add = &opt->add; + AuDbg("append {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->pathname, u.add->perm, + u.add->path.dentry); + break; + case Opt_prepend: + u.add = &opt->add; + AuDbg("prepend {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->pathname, u.add->perm, + u.add->path.dentry); + break; + case Opt_dirwh: + AuDbg("dirwh %d\n", opt->dirwh); + break; + case Opt_rdcache: + AuDbg("rdcache %d\n", opt->rdcache); + break; + case Opt_rdblk: + AuDbg("rdblk %u\n", opt->rdblk); + break; + case Opt_rdblk_def: + AuDbg("rdblk_def\n"); + break; + case Opt_rdhash: + AuDbg("rdhash %u\n", opt->rdhash); + break; + case Opt_rdhash_def: + AuDbg("rdhash_def\n"); + break; + case Opt_xino: + u.xino = &opt->xino; + AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); + break; + case Opt_trunc_xino: + AuLabel(trunc_xino); + break; + case Opt_notrunc_xino: + AuLabel(notrunc_xino); + break; + case Opt_trunc_xino_path: + case Opt_itrunc_xino: + u.xino_itrunc = &opt->xino_itrunc; + AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); + break; + + case Opt_noxino: + AuLabel(noxino); + break; + case Opt_trunc_xib: + AuLabel(trunc_xib); + break; + case Opt_notrunc_xib: + AuLabel(notrunc_xib); + break; + case Opt_shwh: + AuLabel(shwh); + break; + case Opt_noshwh: + AuLabel(noshwh); + break; + case Opt_plink: + AuLabel(plink); + break; + case Opt_noplink: + AuLabel(noplink); + break; + case Opt_list_plink: + AuLabel(list_plink); + break; + case Opt_udba: + AuDbg("udba %d, %s\n", + opt->udba, au_optstr_udba(opt->udba)); + break; + case Opt_dio: + AuLabel(dio); + break; + case Opt_nodio: + AuLabel(nodio); + break; + case Opt_diropq_a: + AuLabel(diropq_a); + break; + case Opt_diropq_w: + AuLabel(diropq_w); + break; + case Opt_warn_perm: + AuLabel(warn_perm); + break; + case Opt_nowarn_perm: + AuLabel(nowarn_perm); + break; + case Opt_refrof: + AuLabel(refrof); + break; + case Opt_norefrof: + AuLabel(norefrof); + break; + case Opt_verbose: + AuLabel(verbose); + break; + case Opt_noverbose: + AuLabel(noverbose); + break; + case Opt_sum: + AuLabel(sum); + break; + case Opt_nosum: + AuLabel(nosum); + break; + case Opt_wsum: + AuLabel(wsum); + break; + case Opt_wbr_create: + u.create = &opt->wbr_create; + AuDbg("create %d, %s\n", u.create->wbr_create, + au_optstr_wbr_create(u.create->wbr_create)); + switch (u.create->wbr_create) { + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFSV: + AuDbg("%d sec\n", u.create->mfs_second); + break; + case AuWbrCreate_MFSRR: + AuDbg("%llu watermark\n", + u.create->mfsrr_watermark); + break; + case AuWbrCreate_MFSRRV: + case AuWbrCreate_PMFSRRV: + AuDbg("%llu watermark, %d sec\n", + u.create->mfsrr_watermark, + u.create->mfs_second); + break; + } + break; + case Opt_wbr_copyup: + AuDbg("copyup %d, %s\n", opt->wbr_copyup, + au_optstr_wbr_copyup(opt->wbr_copyup)); + break; + default: + BUG(); + } + opt++; + } +#endif +} + +void au_opts_free(struct au_opts *opts) +{ + struct au_opt *opt; + + opt = opts->opt; + while (opt->type != Opt_tail) { + switch (opt->type) { + case Opt_add: + case Opt_append: + case Opt_prepend: + path_put(&opt->add.path); + break; + case Opt_del: + case Opt_idel: + path_put(&opt->del.h_path); + break; + case Opt_mod: + case Opt_imod: + dput(opt->mod.h_root); + break; + case Opt_xino: + fput(opt->xino.file); + break; + } + opt++; + } +} + +static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, + aufs_bindex_t bindex) +{ + int err; + struct au_opt_add *add = &opt->add; + char *p; + + add->bindex = bindex; + add->perm = AuBrPerm_RO; + add->pathname = opt_str; + p = strchr(opt_str, '='); + if (p) { + *p++ = 0; + if (*p) + add->perm = br_perm_val(p); + } + + err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); + if (!err) { + if (!p) { + add->perm = AuBrPerm_RO; + if (au_test_fs_rr(add->path.dentry->d_sb)) + add->perm = AuBrPerm_RR; + else if (!bindex && !(sb_flags & MS_RDONLY)) + add->perm = AuBrPerm_RW; + } + opt->type = Opt_add; + goto out; + } + pr_err("lookup failed %s (%d)\n", add->pathname, err); + err = -EINVAL; + +out: + return err; +} + +static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) +{ + int err; + + del->pathname = args[0].from; + AuDbg("del path %s\n", del->pathname); + + err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); + if (unlikely(err)) + pr_err("lookup failed %s (%d)\n", del->pathname, err); + + return err; +} + +#if 0 /* reserved for future use */ +static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, + struct au_opt_del *del, substring_t args[]) +{ + int err; + struct dentry *root; + + err = -EINVAL; + root = sb->s_root; + aufs_read_lock(root, AuLock_FLUSH); + if (bindex < 0 || au_sbend(sb) < bindex) { + pr_err("out of bounds, %d\n", bindex); + goto out; + } + + err = 0; + del->h_path.dentry = dget(au_h_dptr(root, bindex)); + del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); + +out: + aufs_read_unlock(root, !AuLock_IR); + return err; +} +#endif + +static int noinline_for_stack +au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) +{ + int err; + struct path path; + char *p; + + err = -EINVAL; + mod->path = args[0].from; + p = strchr(mod->path, '='); + if (unlikely(!p)) { + pr_err("no permssion %s\n", args[0].from); + goto out; + } + + *p++ = 0; + err = vfsub_kern_path(mod->path, lkup_dirflags, &path); + if (unlikely(err)) { + pr_err("lookup failed %s (%d)\n", mod->path, err); + goto out; + } + + mod->perm = br_perm_val(p); + AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); + mod->h_root = dget(path.dentry); + path_put(&path); + +out: + return err; +} + +#if 0 /* reserved for future use */ +static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, + struct au_opt_mod *mod, substring_t args[]) +{ + int err; + struct dentry *root; + + err = -EINVAL; + root = sb->s_root; + aufs_read_lock(root, AuLock_FLUSH); + if (bindex < 0 || au_sbend(sb) < bindex) { + pr_err("out of bounds, %d\n", bindex); + goto out; + } + + err = 0; + mod->perm = br_perm_val(args[1].from); + AuDbg("mod path %s, perm 0x%x, %s\n", + mod->path, mod->perm, args[1].from); + mod->h_root = dget(au_h_dptr(root, bindex)); + +out: + aufs_read_unlock(root, !AuLock_IR); + return err; +} +#endif + +static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, + substring_t args[]) +{ + int err; + struct file *file; + + file = au_xino_create(sb, args[0].from, /*silent*/0); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + + err = -EINVAL; + if (unlikely(file->f_dentry->d_sb == sb)) { + fput(file); + pr_err("%s must be outside\n", args[0].from); + goto out; + } + + err = 0; + xino->file = file; + xino->path = args[0].from; + +out: + return err; +} + +static int noinline_for_stack +au_opts_parse_xino_itrunc_path(struct super_block *sb, + struct au_opt_xino_itrunc *xino_itrunc, + substring_t args[]) +{ + int err; + aufs_bindex_t bend, bindex; + struct path path; + struct dentry *root; + + err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); + if (unlikely(err)) { + pr_err("lookup failed %s (%d)\n", args[0].from, err); + goto out; + } + + xino_itrunc->bindex = -1; + root = sb->s_root; + aufs_read_lock(root, AuLock_FLUSH); + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + if (au_h_dptr(root, bindex) == path.dentry) { + xino_itrunc->bindex = bindex; + break; + } + } + aufs_read_unlock(root, !AuLock_IR); + path_put(&path); + + if (unlikely(xino_itrunc->bindex < 0)) { + pr_err("no such branch %s\n", args[0].from); + err = -EINVAL; + } + +out: + return err; +} + +/* called without aufs lock */ +int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) +{ + int err, n, token; + aufs_bindex_t bindex; + unsigned char skipped; + struct dentry *root; + struct au_opt *opt, *opt_tail; + char *opt_str; + /* reduce the stack space */ + union { + struct au_opt_xino_itrunc *xino_itrunc; + struct au_opt_wbr_create *create; + } u; + struct { + substring_t args[MAX_OPT_ARGS]; + } *a; + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + root = sb->s_root; + err = 0; + bindex = 0; + opt = opts->opt; + opt_tail = opt + opts->max_opt - 1; + opt->type = Opt_tail; + while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { + err = -EINVAL; + skipped = 0; + token = match_token(opt_str, options, a->args); + switch (token) { + case Opt_br: + err = 0; + while (!err && (opt_str = strsep(&a->args[0].from, ":")) + && *opt_str) { + err = opt_add(opt, opt_str, opts->sb_flags, + bindex++); + if (unlikely(!err && ++opt > opt_tail)) { + err = -E2BIG; + break; + } + opt->type = Opt_tail; + skipped = 1; + } + break; + case Opt_add: + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + bindex = n; + err = opt_add(opt, a->args[1].from, opts->sb_flags, + bindex); + if (!err) + opt->type = token; + break; + case Opt_append: + err = opt_add(opt, a->args[0].from, opts->sb_flags, + /*dummy bindex*/1); + if (!err) + opt->type = token; + break; + case Opt_prepend: + err = opt_add(opt, a->args[0].from, opts->sb_flags, + /*bindex*/0); + if (!err) + opt->type = token; + break; + case Opt_del: + err = au_opts_parse_del(&opt->del, a->args); + if (!err) + opt->type = token; + break; +#if 0 /* reserved for future use */ + case Opt_idel: + del->pathname = "(indexed)"; + if (unlikely(match_int(&args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + err = au_opts_parse_idel(sb, n, &opt->del, a->args); + if (!err) + opt->type = token; + break; +#endif + case Opt_mod: + err = au_opts_parse_mod(&opt->mod, a->args); + if (!err) + opt->type = token; + break; +#ifdef IMOD /* reserved for future use */ + case Opt_imod: + u.mod->path = "(indexed)"; + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + err = au_opts_parse_imod(sb, n, &opt->mod, a->args); + if (!err) + opt->type = token; + break; +#endif + case Opt_xino: + err = au_opts_parse_xino(sb, &opt->xino, a->args); + if (!err) + opt->type = token; + break; + + case Opt_trunc_xino_path: + err = au_opts_parse_xino_itrunc_path + (sb, &opt->xino_itrunc, a->args); + if (!err) + opt->type = token; + break; + + case Opt_itrunc_xino: + u.xino_itrunc = &opt->xino_itrunc; + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + u.xino_itrunc->bindex = n; + aufs_read_lock(root, AuLock_FLUSH); + if (n < 0 || au_sbend(sb) < n) { + pr_err("out of bounds, %d\n", n); + aufs_read_unlock(root, !AuLock_IR); + break; + } + aufs_read_unlock(root, !AuLock_IR); + err = 0; + opt->type = token; + break; + + case Opt_dirwh: + if (unlikely(match_int(&a->args[0], &opt->dirwh))) + break; + err = 0; + opt->type = token; + break; + + case Opt_rdcache: + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + if (unlikely(n > AUFS_RDCACHE_MAX)) { + pr_err("rdcache must be smaller than %d\n", + AUFS_RDCACHE_MAX); + break; + } + opt->rdcache = n; + err = 0; + opt->type = token; + break; + case Opt_rdblk: + if (unlikely(match_int(&a->args[0], &n) + || n < 0 + || n > KMALLOC_MAX_SIZE)) { + pr_err("bad integer in %s\n", opt_str); + break; + } + if (unlikely(n && n < NAME_MAX)) { + pr_err("rdblk must be larger than %d\n", + NAME_MAX); + break; + } + opt->rdblk = n; + err = 0; + opt->type = token; + break; + case Opt_rdhash: + if (unlikely(match_int(&a->args[0], &n) + || n < 0 + || n * sizeof(struct hlist_head) + > KMALLOC_MAX_SIZE)) { + pr_err("bad integer in %s\n", opt_str); + break; + } + opt->rdhash = n; + err = 0; + opt->type = token; + break; + + case Opt_trunc_xino: + case Opt_notrunc_xino: + case Opt_noxino: + case Opt_trunc_xib: + case Opt_notrunc_xib: + case Opt_shwh: + case Opt_noshwh: + case Opt_plink: + case Opt_noplink: + case Opt_list_plink: + case Opt_dio: + case Opt_nodio: + case Opt_diropq_a: + case Opt_diropq_w: + case Opt_warn_perm: + case Opt_nowarn_perm: + case Opt_refrof: + case Opt_norefrof: + case Opt_verbose: + case Opt_noverbose: + case Opt_sum: + case Opt_nosum: + case Opt_wsum: + case Opt_rdblk_def: + case Opt_rdhash_def: + err = 0; + opt->type = token; + break; + + case Opt_udba: + opt->udba = udba_val(a->args[0].from); + if (opt->udba >= 0) { + err = 0; + opt->type = token; + } else + pr_err("wrong value, %s\n", opt_str); + break; + + case Opt_wbr_create: + u.create = &opt->wbr_create; + u.create->wbr_create + = au_wbr_create_val(a->args[0].from, u.create); + if (u.create->wbr_create >= 0) { + err = 0; + opt->type = token; + } else + pr_err("wrong value, %s\n", opt_str); + break; + case Opt_wbr_copyup: + opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); + if (opt->wbr_copyup >= 0) { + err = 0; + opt->type = token; + } else + pr_err("wrong value, %s\n", opt_str); + break; + + case Opt_ignore: + pr_warn("ignored %s\n", opt_str); + /*FALLTHROUGH*/ + case Opt_ignore_silent: + skipped = 1; + err = 0; + break; + case Opt_err: + pr_err("unknown option %s\n", opt_str); + break; + } + + if (!err && !skipped) { + if (unlikely(++opt > opt_tail)) { + err = -E2BIG; + opt--; + opt->type = Opt_tail; + break; + } + opt->type = Opt_tail; + } + } + + kfree(a); + dump_opts(opts); + if (unlikely(err)) + au_opts_free(opts); + +out: + return err; +} + +static int au_opt_wbr_create(struct super_block *sb, + struct au_opt_wbr_create *create) +{ + int err; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + err = 1; /* handled */ + sbinfo = au_sbi(sb); + if (sbinfo->si_wbr_create_ops->fin) { + err = sbinfo->si_wbr_create_ops->fin(sb); + if (!err) + err = 1; + } + + sbinfo->si_wbr_create = create->wbr_create; + sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; + switch (create->wbr_create) { + case AuWbrCreate_MFSRRV: + case AuWbrCreate_MFSRR: + case AuWbrCreate_PMFSRR: + case AuWbrCreate_PMFSRRV: + sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; + /*FALLTHROUGH*/ + case AuWbrCreate_MFS: + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFS: + case AuWbrCreate_PMFSV: + sbinfo->si_wbr_mfs.mfs_expire + = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); + break; + } + + if (sbinfo->si_wbr_create_ops->init) + sbinfo->si_wbr_create_ops->init(sb); /* ignore */ + + return err; +} + +/* + * returns, + * plus: processed without an error + * zero: unprocessed + */ +static int au_opt_simple(struct super_block *sb, struct au_opt *opt, + struct au_opts *opts) +{ + int err; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + err = 1; /* handled */ + sbinfo = au_sbi(sb); + switch (opt->type) { + case Opt_udba: + sbinfo->si_mntflags &= ~AuOptMask_UDBA; + sbinfo->si_mntflags |= opt->udba; + opts->given_udba |= opt->udba; + break; + + case Opt_plink: + au_opt_set(sbinfo->si_mntflags, PLINK); + break; + case Opt_noplink: + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_put(sb, /*verbose*/1); + au_opt_clr(sbinfo->si_mntflags, PLINK); + break; + case Opt_list_plink: + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_list(sb); + break; + + case Opt_dio: + au_opt_set(sbinfo->si_mntflags, DIO); + au_fset_opts(opts->flags, REFRESH_DYAOP); + break; + case Opt_nodio: + au_opt_clr(sbinfo->si_mntflags, DIO); + au_fset_opts(opts->flags, REFRESH_DYAOP); + break; + + case Opt_diropq_a: + au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); + break; + case Opt_diropq_w: + au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); + break; + + case Opt_warn_perm: + au_opt_set(sbinfo->si_mntflags, WARN_PERM); + break; + case Opt_nowarn_perm: + au_opt_clr(sbinfo->si_mntflags, WARN_PERM); + break; + + case Opt_refrof: + au_opt_set(sbinfo->si_mntflags, REFROF); + break; + case Opt_norefrof: + au_opt_clr(sbinfo->si_mntflags, REFROF); + break; + + case Opt_verbose: + au_opt_set(sbinfo->si_mntflags, VERBOSE); + break; + case Opt_noverbose: + au_opt_clr(sbinfo->si_mntflags, VERBOSE); + break; + + case Opt_sum: + au_opt_set(sbinfo->si_mntflags, SUM); + break; + case Opt_wsum: + au_opt_clr(sbinfo->si_mntflags, SUM); + au_opt_set(sbinfo->si_mntflags, SUM_W); + case Opt_nosum: + au_opt_clr(sbinfo->si_mntflags, SUM); + au_opt_clr(sbinfo->si_mntflags, SUM_W); + break; + + case Opt_wbr_create: + err = au_opt_wbr_create(sb, &opt->wbr_create); + break; + case Opt_wbr_copyup: + sbinfo->si_wbr_copyup = opt->wbr_copyup; + sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; + break; + + case Opt_dirwh: + sbinfo->si_dirwh = opt->dirwh; + break; + + case Opt_rdcache: + sbinfo->si_rdcache + = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); + break; + case Opt_rdblk: + sbinfo->si_rdblk = opt->rdblk; + break; + case Opt_rdblk_def: + sbinfo->si_rdblk = AUFS_RDBLK_DEF; + break; + case Opt_rdhash: + sbinfo->si_rdhash = opt->rdhash; + break; + case Opt_rdhash_def: + sbinfo->si_rdhash = AUFS_RDHASH_DEF; + break; + + case Opt_shwh: + au_opt_set(sbinfo->si_mntflags, SHWH); + break; + case Opt_noshwh: + au_opt_clr(sbinfo->si_mntflags, SHWH); + break; + + case Opt_trunc_xino: + au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); + break; + case Opt_notrunc_xino: + au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); + break; + + case Opt_trunc_xino_path: + case Opt_itrunc_xino: + err = au_xino_trunc(sb, opt->xino_itrunc.bindex); + if (!err) + err = 1; + break; + + case Opt_trunc_xib: + au_fset_opts(opts->flags, TRUNC_XIB); + break; + case Opt_notrunc_xib: + au_fclr_opts(opts->flags, TRUNC_XIB); + break; + + default: + err = 0; + break; + } + + return err; +} + +/* + * returns tri-state. + * plus: processed without an error + * zero: unprocessed + * minus: error + */ +static int au_opt_br(struct super_block *sb, struct au_opt *opt, + struct au_opts *opts) +{ + int err, do_refresh; + + err = 0; + switch (opt->type) { + case Opt_append: + opt->add.bindex = au_sbend(sb) + 1; + if (opt->add.bindex < 0) + opt->add.bindex = 0; + goto add; + case Opt_prepend: + opt->add.bindex = 0; + add: /* indented label */ + case Opt_add: + err = au_br_add(sb, &opt->add, + au_ftest_opts(opts->flags, REMOUNT)); + if (!err) { + err = 1; + au_fset_opts(opts->flags, REFRESH); + } + break; + + case Opt_del: + case Opt_idel: + err = au_br_del(sb, &opt->del, + au_ftest_opts(opts->flags, REMOUNT)); + if (!err) { + err = 1; + au_fset_opts(opts->flags, TRUNC_XIB); + au_fset_opts(opts->flags, REFRESH); + } + break; + + case Opt_mod: + case Opt_imod: + err = au_br_mod(sb, &opt->mod, + au_ftest_opts(opts->flags, REMOUNT), + &do_refresh); + if (!err) { + err = 1; + if (do_refresh) + au_fset_opts(opts->flags, REFRESH); + } + break; + } + + return err; +} + +static int au_opt_xino(struct super_block *sb, struct au_opt *opt, + struct au_opt_xino **opt_xino, + struct au_opts *opts) +{ + int err; + aufs_bindex_t bend, bindex; + struct dentry *root, *parent, *h_root; + + err = 0; + switch (opt->type) { + case Opt_xino: + err = au_xino_set(sb, &opt->xino, + !!au_ftest_opts(opts->flags, REMOUNT)); + if (unlikely(err)) + break; + + *opt_xino = &opt->xino; + au_xino_brid_set(sb, -1); + + /* safe d_parent access */ + parent = opt->xino.file->f_dentry->d_parent; + root = sb->s_root; + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + h_root = au_h_dptr(root, bindex); + if (h_root == parent) { + au_xino_brid_set(sb, au_sbr_id(sb, bindex)); + break; + } + } + break; + + case Opt_noxino: + au_xino_clr(sb); + au_xino_brid_set(sb, -1); + *opt_xino = (void *)-1; + break; + } + + return err; +} + +int au_opts_verify(struct super_block *sb, unsigned long sb_flags, + unsigned int pending) +{ + int err; + aufs_bindex_t bindex, bend; + unsigned char do_plink, skip, do_free; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *root; + struct inode *dir, *h_dir; + struct au_sbinfo *sbinfo; + struct au_hinode *hdir; + + SiMustAnyLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); + + if (!(sb_flags & MS_RDONLY)) { + if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) + pr_warn("first branch should be rw\n"); + if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) + pr_warn("shwh should be used with ro\n"); + } + + if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) + && !au_opt_test(sbinfo->si_mntflags, XINO)) + pr_warn("udba=*notify requires xino\n"); + + err = 0; + root = sb->s_root; + dir = root->d_inode; + do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); + bend = au_sbend(sb); + for (bindex = 0; !err && bindex <= bend; bindex++) { + skip = 0; + h_dir = au_h_iptr(dir, bindex); + br = au_sbr(sb, bindex); + do_free = 0; + + wbr = br->br_wbr; + if (wbr) + wbr_wh_read_lock(wbr); + + if (!au_br_writable(br->br_perm)) { + do_free = !!wbr; + skip = (!wbr + || (!wbr->wbr_whbase + && !wbr->wbr_plink + && !wbr->wbr_orph)); + } else if (!au_br_wh_linkable(br->br_perm)) { + /* skip = (!br->br_whbase && !br->br_orph); */ + skip = (!wbr || !wbr->wbr_whbase); + if (skip && wbr) { + if (do_plink) + skip = !!wbr->wbr_plink; + else + skip = !wbr->wbr_plink; + } + } else { + /* skip = (br->br_whbase && br->br_ohph); */ + skip = (wbr && wbr->wbr_whbase); + if (skip) { + if (do_plink) + skip = !!wbr->wbr_plink; + else + skip = !wbr->wbr_plink; + } + } + if (wbr) + wbr_wh_read_unlock(wbr); + + if (skip) + continue; + + hdir = au_hi(dir, bindex); + au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); + if (wbr) + wbr_wh_write_lock(wbr); + err = au_wh_init(br, sb); + if (wbr) + wbr_wh_write_unlock(wbr); + au_hn_imtx_unlock(hdir); + + if (!err && do_free) { + kfree(wbr); + br->br_wbr = NULL; + } + } + + return err; +} + +int au_opts_mount(struct super_block *sb, struct au_opts *opts) +{ + int err; + unsigned int tmp; + aufs_bindex_t bindex, bend; + struct au_opt *opt; + struct au_opt_xino *opt_xino, xino; + struct au_sbinfo *sbinfo; + struct au_branch *br; + + SiMustWriteLock(sb); + + err = 0; + opt_xino = NULL; + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) + err = au_opt_simple(sb, opt++, opts); + if (err > 0) + err = 0; + else if (unlikely(err < 0)) + goto out; + + /* disable xino and udba temporary */ + sbinfo = au_sbi(sb); + tmp = sbinfo->si_mntflags; + au_opt_clr(sbinfo->si_mntflags, XINO); + au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); + + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) + err = au_opt_br(sb, opt++, opts); + if (err > 0) + err = 0; + else if (unlikely(err < 0)) + goto out; + + bend = au_sbend(sb); + if (unlikely(bend < 0)) { + err = -EINVAL; + pr_err("no branches\n"); + goto out; + } + + if (au_opt_test(tmp, XINO)) + au_opt_set(sbinfo->si_mntflags, XINO); + opt = opts->opt; + while (!err && opt->type != Opt_tail) + err = au_opt_xino(sb, opt++, &opt_xino, opts); + if (unlikely(err)) + goto out; + + err = au_opts_verify(sb, sb->s_flags, tmp); + if (unlikely(err)) + goto out; + + /* restore xino */ + if (au_opt_test(tmp, XINO) && !opt_xino) { + xino.file = au_xino_def(sb); + err = PTR_ERR(xino.file); + if (IS_ERR(xino.file)) + goto out; + + err = au_xino_set(sb, &xino, /*remount*/0); + fput(xino.file); + if (unlikely(err)) + goto out; + } + + /* restore udba */ + tmp &= AuOptMask_UDBA; + sbinfo->si_mntflags &= ~AuOptMask_UDBA; + sbinfo->si_mntflags |= tmp; + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + err = au_hnotify_reset_br(tmp, br, br->br_perm); + if (unlikely(err)) + AuIOErr("hnotify failed on br %d, %d, ignored\n", + bindex, err); + /* go on even if err */ + } + if (au_opt_test(tmp, UDBA_HNOTIFY)) { + struct inode *dir = sb->s_root->d_inode; + au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); + } + +out: + return err; +} + +int au_opts_remount(struct super_block *sb, struct au_opts *opts) +{ + int err, rerr; + struct inode *dir; + struct au_opt_xino *opt_xino; + struct au_opt *opt; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + dir = sb->s_root->d_inode; + sbinfo = au_sbi(sb); + err = 0; + opt_xino = NULL; + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) { + err = au_opt_simple(sb, opt, opts); + if (!err) + err = au_opt_br(sb, opt, opts); + if (!err) + err = au_opt_xino(sb, opt, &opt_xino, opts); + opt++; + } + if (err > 0) + err = 0; + AuTraceErr(err); + /* go on even err */ + + rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); + if (unlikely(rerr && !err)) + err = rerr; + + if (au_ftest_opts(opts->flags, TRUNC_XIB)) { + rerr = au_xib_trunc(sb); + if (unlikely(rerr && !err)) + err = rerr; + } + + /* will be handled by the caller */ + if (!au_ftest_opts(opts->flags, REFRESH) + && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO))) + au_fset_opts(opts->flags, REFRESH); + + AuDbg("status 0x%x\n", opts->flags); + return err; +} + +/* ---------------------------------------------------------------------- */ + +unsigned int au_opt_udba(struct super_block *sb) +{ + return au_mntflags(sb) & AuOptMask_UDBA; +} --- linux-3.13.0.orig/ubuntu/aufs/vfsub.h +++ linux-3.13.0/ubuntu/aufs/vfsub.h @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for VFS + */ + +#ifndef __AUFS_VFSUB_H__ +#define __AUFS_VFSUB_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include "debug.h" + +/* copied from linux/fs/internal.h */ +/* todo: BAD approach!! */ +extern void __mnt_drop_write(struct vfsmount *); +extern spinlock_t inode_sb_list_lock; + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for lower inode */ +/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ +/* reduce? gave up. */ +enum { + AuLsc_I_Begin = I_MUTEX_NONDIR2, /* 4 */ + AuLsc_I_PARENT, /* lower inode, parent first */ + AuLsc_I_PARENT2, /* copyup dirs */ + AuLsc_I_PARENT3, /* copyup wh */ + AuLsc_I_CHILD, + AuLsc_I_CHILD2, + AuLsc_I_End +}; + +/* to debug easier, do not make them inlined functions */ +#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) +#define IMustLock(i) MtxMustLock(&(i)->i_mutex) + +/* ---------------------------------------------------------------------- */ + +static inline void vfsub_drop_nlink(struct inode *inode) +{ + AuDebugOn(!inode->i_nlink); + drop_nlink(inode); +} + +static inline void vfsub_dead_dir(struct inode *inode) +{ + AuDebugOn(!S_ISDIR(inode->i_mode)); + inode->i_flags |= S_DEAD; + clear_nlink(inode); +} + +static inline int vfsub_native_ro(struct inode *inode) +{ + return (inode->i_sb->s_flags & MS_RDONLY) + || IS_RDONLY(inode) + /* || IS_APPEND(inode) */ + || IS_IMMUTABLE(inode); +} + +/* ---------------------------------------------------------------------- */ + +int vfsub_update_h_iattr(struct path *h_path, int *did); +struct file *vfsub_dentry_open(struct path *path, int flags); +struct file *vfsub_filp_open(const char *path, int oflags, int mode); +int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); + +struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, + int len); + +struct vfsub_lkup_one_args { + struct dentry **errp; + struct qstr *name; + struct dentry *parent; +}; + +static inline struct dentry *vfsub_lkup_one(struct qstr *name, + struct dentry *parent) +{ + return vfsub_lookup_one_len(name->name, parent, name->len); +} + +void vfsub_call_lkup_one(void *args); + +/* ---------------------------------------------------------------------- */ + +static inline int vfsub_mnt_want_write(struct vfsmount *mnt) +{ + int err; + lockdep_off(); + err = mnt_want_write(mnt); + lockdep_on(); + return err; +} + +static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) +{ + lockdep_off(); + mnt_drop_write(mnt); + lockdep_on(); +} + +static inline void vfsub_mnt_drop_write_file(struct file *file) +{ + lockdep_off(); + mnt_drop_write_file(file); + lockdep_on(); +} + +/* ---------------------------------------------------------------------- */ + +struct au_hinode; +struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2); +void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2); + +int vfsub_create(struct inode *dir, struct path *path, int mode, + bool want_excl); +int vfsub_symlink(struct inode *dir, struct path *path, + const char *symname); +int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); +int vfsub_link(struct dentry *src_dentry, struct inode *dir, + struct path *path, struct inode **delegated_inode); +int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, + struct inode *hdir, struct path *path, + struct inode **delegated_inode); +int vfsub_mkdir(struct inode *dir, struct path *path, int mode); +int vfsub_rmdir(struct inode *dir, struct path *path); + +/* ---------------------------------------------------------------------- */ + +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos); +ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos); +ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos); +ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos); +int vfsub_flush(struct file *file, fl_owner_t id); +int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); + +/* just for type-check */ +static inline filldir_t au_diractor(int (*func)(struct dir_context *, + const char *, int, loff_t, u64, + unsigned)) +{ + return (filldir_t)func; +} + + +static inline loff_t vfsub_f_size_read(struct file *file) +{ + return i_size_read(file_inode(file)); +} + +static inline unsigned int vfsub_file_flags(struct file *file) +{ + unsigned int flags; + + spin_lock(&file->f_lock); + flags = file->f_flags; + spin_unlock(&file->f_lock); + + return flags; +} + +static inline void vfsub_file_accessed(struct file *h_file) +{ + file_accessed(h_file); + vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ +} + +static inline void vfsub_touch_atime(struct vfsmount *h_mnt, + struct dentry *h_dentry) +{ + struct path h_path = { + .dentry = h_dentry, + .mnt = h_mnt + }; + touch_atime(&h_path); + vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ +} + +static inline int vfsub_update_time(struct inode *h_inode, struct timespec *ts, + int flags) +{ + return update_time(h_inode, ts, flags); + /* no vfsub_update_h_iattr() since we don't have struct path */ +} + +long vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); +long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); + +static inline long vfsub_truncate(struct path *path, loff_t length) +{ + long err; + lockdep_off(); + err = vfs_truncate(path, length); + lockdep_on(); + return err; +} + +int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, + struct file *h_file); +int vfsub_fsync(struct file *file, struct path *path, int datasync); + +/* ---------------------------------------------------------------------- */ + +static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t err; + + lockdep_off(); + err = vfs_llseek(file, offset, origin); + lockdep_on(); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* dirty workaround for strict type of fmode_t */ +union vfsub_fmu { + fmode_t fm; + unsigned int ui; +}; + +static inline unsigned int vfsub_fmode_to_uint(fmode_t fm) +{ + union vfsub_fmu u = { + .fm = fm + }; + + BUILD_BUG_ON(sizeof(u.fm) != sizeof(u.ui)); + + return u.ui; +} + +static inline fmode_t vfsub_uint_to_fmode(unsigned int ui) +{ + union vfsub_fmu u = { + .ui = ui + }; + + return u.fm; +} + +/* ---------------------------------------------------------------------- */ + +int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); +int vfsub_sio_rmdir(struct inode *dir, struct path *path); +int vfsub_sio_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode); +int vfsub_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode); +int vfsub_unlink(struct inode *dir, struct path *path, + struct inode **delegated_inode, int force); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_VFSUB_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/fstype.h +++ linux-3.13.0/ubuntu/aufs/fstype.h @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * judging filesystem type + */ + +#ifndef __AUFS_FSTYPE_H__ +#define __AUFS_FSTYPE_H__ + +#ifdef __KERNEL__ + +#include +#include +#include + +static inline int au_test_aufs(struct super_block *sb) +{ + return sb->s_magic == AUFS_SUPER_MAGIC; +} + +static inline const char *au_sbtype(struct super_block *sb) +{ + return sb->s_type->name; +} + +static inline int au_test_iso9660(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE) + return sb->s_magic == ROMFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_romfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE) + return sb->s_magic == ISOFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_cramfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) + return sb->s_magic == CRAMFS_MAGIC; +#endif + return 0; +} + +static inline int au_test_nfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) + return sb->s_magic == NFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_fuse(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE) + return sb->s_magic == FUSE_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_xfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE) + return sb->s_magic == XFS_SB_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_TMPFS + return sb->s_magic == TMPFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE) + return !strcmp(au_sbtype(sb), "ecryptfs"); +#else + return 0; +#endif +} + +static inline int au_test_ocfs2(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE) + return sb->s_magic == OCFS2_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_ocfs2_dlmfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_OCFS2_FS_O2CB) || defined(CONFIG_OCFS2_FS_O2CB_MODULE) + return sb->s_magic == DLMFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_coda(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_CODA_FS) || defined(CONFIG_CODA_FS_MODULE) + return sb->s_magic == CODA_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_v9fs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_9P_FS) || defined(CONFIG_9P_FS_MODULE) + return sb->s_magic == V9FS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_ext4(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_EXT4_FS) || defined(CONFIG_EXT4_FS_MODULE) + return sb->s_magic == EXT4_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_sysv(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_SYSV_FS) || defined(CONFIG_SYSV_FS_MODULE) + return !strcmp(au_sbtype(sb), "sysv"); +#else + return 0; +#endif +} + +static inline int au_test_ramfs(struct super_block *sb) +{ + return sb->s_magic == RAMFS_MAGIC; +} + +static inline int au_test_ubifs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE) + return sb->s_magic == UBIFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_procfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_PROC_FS + return sb->s_magic == PROC_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_sysfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_SYSFS + return sb->s_magic == SYSFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_configfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE) + return sb->s_magic == CONFIGFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_minix(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE) + return sb->s_magic == MINIX3_SUPER_MAGIC + || sb->s_magic == MINIX2_SUPER_MAGIC + || sb->s_magic == MINIX2_SUPER_MAGIC2 + || sb->s_magic == MINIX_SUPER_MAGIC + || sb->s_magic == MINIX_SUPER_MAGIC2; +#else + return 0; +#endif +} + +static inline int au_test_cifs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_CIFS_FS) || defined(CONFIGCIFS_FS_MODULE) + return sb->s_magic == CIFS_MAGIC_NUMBER; +#else + return 0; +#endif +} + +static inline int au_test_fat(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE) + return sb->s_magic == MSDOS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_msdos(struct super_block *sb) +{ + return au_test_fat(sb); +} + +static inline int au_test_vfat(struct super_block *sb) +{ + return au_test_fat(sb); +} + +static inline int au_test_securityfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_SECURITYFS + return sb->s_magic == SECURITYFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_squashfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE) + return sb->s_magic == SQUASHFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_btrfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE) + return sb->s_magic == BTRFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_xenfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE) + return sb->s_magic == XENFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_debugfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_DEBUG_FS + return sb->s_magic == DEBUGFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_nilfs(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE) + return sb->s_magic == NILFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) +{ +#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE) + return sb->s_magic == HFSPLUS_SUPER_MAGIC; +#else + return 0; +#endif +} + +/* ---------------------------------------------------------------------- */ +/* + * they can't be an aufs branch. + */ +static inline int au_test_fs_unsuppoted(struct super_block *sb) +{ + return +#ifndef CONFIG_AUFS_BR_RAMFS + au_test_ramfs(sb) || +#endif + au_test_procfs(sb) + || au_test_sysfs(sb) + || au_test_configfs(sb) + || au_test_debugfs(sb) + || au_test_securityfs(sb) + || au_test_xenfs(sb) + || au_test_ecryptfs(sb) + /* || !strcmp(au_sbtype(sb), "unionfs") */ + || au_test_aufs(sb); /* will be supported in next version */ +} + +static inline int au_test_fs_remote(struct super_block *sb) +{ + return !au_test_tmpfs(sb) +#ifdef CONFIG_AUFS_BR_RAMFS + && !au_test_ramfs(sb) +#endif + && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); +} + +/* ---------------------------------------------------------------------- */ + +/* + * Note: these functions (below) are created after reading ->getattr() in all + * filesystems under linux/fs. it means we have to do so in every update... + */ + +/* + * some filesystems require getattr to refresh the inode attributes before + * referencing. + * in most cases, we can rely on the inode attribute in NFS (or every remote fs) + * and leave the work for d_revalidate() + */ +static inline int au_test_fs_refresh_iattr(struct super_block *sb) +{ + return au_test_nfs(sb) + || au_test_fuse(sb) + /* || au_test_ocfs2(sb) */ /* untested */ + /* || au_test_btrfs(sb) */ /* untested */ + /* || au_test_coda(sb) */ /* untested */ + /* || au_test_v9fs(sb) */ /* untested */ + ; +} + +/* + * filesystems which don't maintain i_size or i_blocks. + */ +static inline int au_test_fs_bad_iattr_size(struct super_block *sb) +{ + return au_test_xfs(sb) + || au_test_btrfs(sb) + || au_test_ubifs(sb) + || au_test_hfsplus(sb) /* maintained, but incorrect */ + /* || au_test_ext4(sb) */ /* untested */ + /* || au_test_ocfs2(sb) */ /* untested */ + /* || au_test_ocfs2_dlmfs(sb) */ /* untested */ + /* || au_test_sysv(sb) */ /* untested */ + /* || au_test_minix(sb) */ /* untested */ + ; +} + +/* + * filesystems which don't store the correct value in some of their inode + * attributes. + */ +static inline int au_test_fs_bad_iattr(struct super_block *sb) +{ + return au_test_fs_bad_iattr_size(sb) + /* || au_test_cifs(sb) */ /* untested */ + || au_test_fat(sb) + || au_test_msdos(sb) + || au_test_vfat(sb); +} + +/* they don't check i_nlink in link(2) */ +static inline int au_test_fs_no_limit_nlink(struct super_block *sb) +{ + return au_test_tmpfs(sb) +#ifdef CONFIG_AUFS_BR_RAMFS + || au_test_ramfs(sb) +#endif + || au_test_ubifs(sb) + || au_test_hfsplus(sb); +} + +/* + * filesystems which sets S_NOATIME and S_NOCMTIME. + */ +static inline int au_test_fs_notime(struct super_block *sb) +{ + return au_test_nfs(sb) + || au_test_fuse(sb) + || au_test_ubifs(sb) + /* || au_test_cifs(sb) */ /* untested */ + ; +} + +/* + * filesystems which requires replacing i_mapping. + */ +static inline int au_test_fs_bad_mapping(struct super_block *sb) +{ + return au_test_fuse(sb) + || au_test_ubifs(sb); +} + +/* temporary support for i#1 in cramfs */ +static inline int au_test_fs_unique_ino(struct inode *inode) +{ + if (au_test_cramfs(inode->i_sb)) + return inode->i_ino != 1; + return 1; +} + +/* ---------------------------------------------------------------------- */ + +/* + * the filesystem where the xino files placed must support i/o after unlink and + * maintain i_size and i_blocks. + */ +static inline int au_test_fs_bad_xino(struct super_block *sb) +{ + return au_test_fs_remote(sb) + || au_test_fs_bad_iattr_size(sb) + /* don't want unnecessary work for xino */ + || au_test_aufs(sb) + || au_test_ecryptfs(sb) + || au_test_nilfs(sb); +} + +static inline int au_test_fs_trunc_xino(struct super_block *sb) +{ + return au_test_tmpfs(sb) + || au_test_ramfs(sb); +} + +/* + * test if the @sb is real-readonly. + */ +static inline int au_test_fs_rr(struct super_block *sb) +{ + return au_test_squashfs(sb) + || au_test_iso9660(sb) + || au_test_cramfs(sb) + || au_test_romfs(sb); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FSTYPE_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/super.c +++ linux-3.13.0/ubuntu/aufs/super.c @@ -0,0 +1,1001 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * mount and super_block operations + */ + +#include +#include +#include +#include +#include +#include +#include "aufs.h" + +/* + * super_operations + */ +static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) +{ + struct au_icntnr *c; + + c = au_cache_alloc_icntnr(); + if (c) { + au_icntnr_init(c); + c->vfs_inode.i_version = 1; /* sigen(sb); */ + c->iinfo.ii_hinode = NULL; + return &c->vfs_inode; + } + return NULL; +} + +static void aufs_destroy_inode_cb(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + + INIT_HLIST_HEAD(&inode->i_dentry); + au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); +} + +static void aufs_destroy_inode(struct inode *inode) +{ + au_iinfo_fin(inode); + call_rcu(&inode->i_rcu, aufs_destroy_inode_cb); +} + +struct inode *au_iget_locked(struct super_block *sb, ino_t ino) +{ + struct inode *inode; + int err; + + inode = iget_locked(sb, ino); + if (unlikely(!inode)) { + inode = ERR_PTR(-ENOMEM); + goto out; + } + if (!(inode->i_state & I_NEW)) + goto out; + + err = au_xigen_new(inode); + if (!err) + err = au_iinfo_init(inode); + if (!err) + inode->i_version++; + else { + iget_failed(inode); + inode = ERR_PTR(err); + } + +out: + /* never return NULL */ + AuDebugOn(!inode); + AuTraceErrPtr(inode); + return inode; +} + +/* lock free root dinfo */ +static int au_show_brs(struct seq_file *seq, struct super_block *sb) +{ + int err; + aufs_bindex_t bindex, bend; + struct path path; + struct au_hdentry *hdp; + struct au_branch *br; + char *perm; + + err = 0; + bend = au_sbend(sb); + hdp = au_di(sb->s_root)->di_hdentry; + for (bindex = 0; !err && bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + path.mnt = au_br_mnt(br); + path.dentry = hdp[bindex].hd_dentry; + err = au_seq_path(seq, &path); + if (err > 0) { + perm = au_optstr_br_perm(br->br_perm); + if (perm) { + err = seq_printf(seq, "=%s", perm); + kfree(perm); + if (err == -1) + err = -E2BIG; + } else + err = -ENOMEM; + } + if (!err && bindex != bend) + err = seq_putc(seq, ':'); + } + + return err; +} + +static void au_show_wbr_create(struct seq_file *m, int v, + struct au_sbinfo *sbinfo) +{ + const char *pat; + + AuRwMustAnyLock(&sbinfo->si_rwsem); + + seq_puts(m, ",create="); + pat = au_optstr_wbr_create(v); + switch (v) { + case AuWbrCreate_TDP: + case AuWbrCreate_RR: + case AuWbrCreate_MFS: + case AuWbrCreate_PMFS: + seq_puts(m, pat); + break; + case AuWbrCreate_MFSV: + seq_printf(m, /*pat*/"mfs:%lu", + jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) + / MSEC_PER_SEC); + break; + case AuWbrCreate_PMFSV: + seq_printf(m, /*pat*/"pmfs:%lu", + jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) + / MSEC_PER_SEC); + break; + case AuWbrCreate_MFSRR: + seq_printf(m, /*pat*/"mfsrr:%llu", + sbinfo->si_wbr_mfs.mfsrr_watermark); + break; + case AuWbrCreate_MFSRRV: + seq_printf(m, /*pat*/"mfsrr:%llu:%lu", + sbinfo->si_wbr_mfs.mfsrr_watermark, + jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) + / MSEC_PER_SEC); + break; + case AuWbrCreate_PMFSRR: + seq_printf(m, /*pat*/"pmfsrr:%llu", + sbinfo->si_wbr_mfs.mfsrr_watermark); + break; + case AuWbrCreate_PMFSRRV: + seq_printf(m, /*pat*/"pmfsrr:%llu:%lu", + sbinfo->si_wbr_mfs.mfsrr_watermark, + jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) + / MSEC_PER_SEC); + break; + } +} + +static int au_show_xino(struct seq_file *seq, struct super_block *sb) +{ +#ifdef CONFIG_SYSFS + return 0; +#else + int err; + const int len = sizeof(AUFS_XINO_FNAME) - 1; + aufs_bindex_t bindex, brid; + struct qstr *name; + struct file *f; + struct dentry *d, *h_root; + struct au_hdentry *hdp; + + AuRwMustAnyLock(&sbinfo->si_rwsem); + + err = 0; + f = au_sbi(sb)->si_xib; + if (!f) + goto out; + + /* stop printing the default xino path on the first writable branch */ + h_root = NULL; + brid = au_xino_brid(sb); + if (brid >= 0) { + bindex = au_br_index(sb, brid); + hdp = au_di(sb->s_root)->di_hdentry; + h_root = hdp[0 + bindex].hd_dentry; + } + d = f->f_dentry; + name = &d->d_name; + /* safe ->d_parent because the file is unlinked */ + if (d->d_parent == h_root + && name->len == len + && !memcmp(name->name, AUFS_XINO_FNAME, len)) + goto out; + + seq_puts(seq, ",xino="); + err = au_xino_path(seq, f); + +out: + return err; +#endif +} + +/* seq_file will re-call me in case of too long string */ +static int aufs_show_options(struct seq_file *m, struct dentry *dentry) +{ + int err; + unsigned int mnt_flags, v; + struct super_block *sb; + struct au_sbinfo *sbinfo; + +#define AuBool(name, str) do { \ + v = au_opt_test(mnt_flags, name); \ + if (v != au_opt_test(AuOpt_Def, name)) \ + seq_printf(m, ",%s" #str, v ? "" : "no"); \ +} while (0) + +#define AuStr(name, str) do { \ + v = mnt_flags & AuOptMask_##name; \ + if (v != (AuOpt_Def & AuOptMask_##name)) \ + seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ +} while (0) + +#define AuUInt(name, str, val) do { \ + if (val != AUFS_##name##_DEF) \ + seq_printf(m, "," #str "=%u", val); \ +} while (0) + + /* lock free root dinfo */ + sb = dentry->d_sb; + si_noflush_read_lock(sb); + sbinfo = au_sbi(sb); + seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); + + mnt_flags = au_mntflags(sb); + if (au_opt_test(mnt_flags, XINO)) { + err = au_show_xino(m, sb); + if (unlikely(err)) + goto out; + } else + seq_puts(m, ",noxino"); + + AuBool(TRUNC_XINO, trunc_xino); + AuStr(UDBA, udba); + AuBool(SHWH, shwh); + AuBool(PLINK, plink); + AuBool(DIO, dio); + /* AuBool(DIRPERM1, dirperm1); */ + /* AuBool(REFROF, refrof); */ + + v = sbinfo->si_wbr_create; + if (v != AuWbrCreate_Def) + au_show_wbr_create(m, v, sbinfo); + + v = sbinfo->si_wbr_copyup; + if (v != AuWbrCopyup_Def) + seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); + + v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); + if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) + seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); + + AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); + + v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; + AuUInt(RDCACHE, rdcache, v); + + AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); + AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); + + AuBool(SUM, sum); + /* AuBool(SUM_W, wsum); */ + AuBool(WARN_PERM, warn_perm); + AuBool(VERBOSE, verbose); + +out: + /* be sure to print "br:" last */ + if (!sysaufs_brs) { + seq_puts(m, ",br:"); + au_show_brs(m, sb); + } + si_read_unlock(sb); + return 0; + +#undef AuBool +#undef AuStr +#undef AuUInt +} + +/* ---------------------------------------------------------------------- */ + +/* sum mode which returns the summation for statfs(2) */ + +static u64 au_add_till_max(u64 a, u64 b) +{ + u64 old; + + old = a; + a += b; + if (old <= a) + return a; + return ULLONG_MAX; +} + +static u64 au_mul_till_max(u64 a, long mul) +{ + u64 old; + + old = a; + a *= mul; + if (old <= a) + return a; + return ULLONG_MAX; +} + +static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) +{ + int err; + long bsize, factor; + u64 blocks, bfree, bavail, files, ffree; + aufs_bindex_t bend, bindex, i; + unsigned char shared; + struct path h_path; + struct super_block *h_sb; + + err = 0; + bsize = LONG_MAX; + files = 0; + ffree = 0; + blocks = 0; + bfree = 0; + bavail = 0; + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + h_path.mnt = au_sbr_mnt(sb, bindex); + h_sb = h_path.mnt->mnt_sb; + shared = 0; + for (i = 0; !shared && i < bindex; i++) + shared = (au_sbr_sb(sb, i) == h_sb); + if (shared) + continue; + + /* sb->s_root for NFS is unreliable */ + h_path.dentry = h_path.mnt->mnt_root; + err = vfs_statfs(&h_path, buf); + if (unlikely(err)) + goto out; + + if (bsize > buf->f_bsize) { + /* + * we will reduce bsize, so we have to expand blocks + * etc. to match them again + */ + factor = (bsize / buf->f_bsize); + blocks = au_mul_till_max(blocks, factor); + bfree = au_mul_till_max(bfree, factor); + bavail = au_mul_till_max(bavail, factor); + bsize = buf->f_bsize; + } + + factor = (buf->f_bsize / bsize); + blocks = au_add_till_max(blocks, + au_mul_till_max(buf->f_blocks, factor)); + bfree = au_add_till_max(bfree, + au_mul_till_max(buf->f_bfree, factor)); + bavail = au_add_till_max(bavail, + au_mul_till_max(buf->f_bavail, factor)); + files = au_add_till_max(files, buf->f_files); + ffree = au_add_till_max(ffree, buf->f_ffree); + } + + buf->f_bsize = bsize; + buf->f_blocks = blocks; + buf->f_bfree = bfree; + buf->f_bavail = bavail; + buf->f_files = files; + buf->f_ffree = ffree; + buf->f_frsize = 0; + +out: + return err; +} + +static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + int err; + struct path h_path; + struct super_block *sb; + + /* lock free root dinfo */ + sb = dentry->d_sb; + si_noflush_read_lock(sb); + if (!au_opt_test(au_mntflags(sb), SUM)) { + /* sb->s_root for NFS is unreliable */ + h_path.mnt = au_sbr_mnt(sb, 0); + h_path.dentry = h_path.mnt->mnt_root; + err = vfs_statfs(&h_path, buf); + } else + err = au_statfs_sum(sb, buf); + si_read_unlock(sb); + + if (!err) { + buf->f_type = AUFS_SUPER_MAGIC; + buf->f_namelen = AUFS_MAX_NAMELEN; + memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); + } + /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_sync_fs(struct super_block *sb, int wait) +{ + int err, e; + aufs_bindex_t bend, bindex; + struct au_branch *br; + struct super_block *h_sb; + + err = 0; + si_noflush_read_lock(sb); + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (!au_br_writable(br->br_perm)) + continue; + + h_sb = au_sbr_sb(sb, bindex); + if (h_sb->s_op->sync_fs) { + e = h_sb->s_op->sync_fs(h_sb, wait); + if (unlikely(e && !err)) + err = e; + /* go on even if an error happens */ + } + } + si_read_unlock(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* final actions when unmounting a file system */ +static void aufs_put_super(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + sbinfo = au_sbi(sb); + if (!sbinfo) + return; + + dbgaufs_si_fin(sbinfo); + kobject_put(&sbinfo->si_kobj); +} + +/* ---------------------------------------------------------------------- */ + +void au_array_free(void *array) +{ + if (array) { + if (!is_vmalloc_addr(array)) + kfree(array); + else + vfree(array); + } +} + +void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg) +{ + void *array; + unsigned long long n; + + array = NULL; + n = 0; + if (!*hint) + goto out; + + if (*hint > ULLONG_MAX / sizeof(array)) { + array = ERR_PTR(-EMFILE); + pr_err("hint %llu\n", *hint); + goto out; + } + + array = kmalloc(sizeof(array) * *hint, GFP_NOFS); + if (unlikely(!array)) + array = vmalloc(sizeof(array) * *hint); + if (unlikely(!array)) { + array = ERR_PTR(-ENOMEM); + goto out; + } + + n = cb(array, *hint, arg); + AuDebugOn(n > *hint); + +out: + *hint = n; + return array; +} + +static unsigned long long au_iarray_cb(void *a, + unsigned long long max __maybe_unused, + void *arg) +{ + unsigned long long n; + struct inode **p, *inode; + struct list_head *head; + + n = 0; + p = a; + head = arg; + spin_lock(&inode_sb_list_lock); + list_for_each_entry(inode, head, i_sb_list) { + if (!is_bad_inode(inode) + && au_ii(inode)->ii_bstart >= 0) { + spin_lock(&inode->i_lock); + if (atomic_read(&inode->i_count)) { + au_igrab(inode); + *p++ = inode; + n++; + AuDebugOn(n > max); + } + spin_unlock(&inode->i_lock); + } + } + spin_unlock(&inode_sb_list_lock); + + return n; +} + +struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) +{ + *max = atomic_long_read(&au_sbi(sb)->si_ninodes); + return au_array_alloc(max, au_iarray_cb, &sb->s_inodes); +} + +void au_iarray_free(struct inode **a, unsigned long long max) +{ + unsigned long long ull; + + for (ull = 0; ull < max; ull++) + iput(a[ull]); + au_array_free(a); +} + +/* ---------------------------------------------------------------------- */ + +/* + * refresh dentry and inode at remount time. + */ +/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ +static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, + struct dentry *parent) +{ + int err; + + di_write_lock_child(dentry); + di_read_lock_parent(parent, AuLock_IR); + err = au_refresh_dentry(dentry, parent); + if (!err && dir_flags) + au_hn_reset(dentry->d_inode, dir_flags); + di_read_unlock(parent, AuLock_IR); + di_write_unlock(dentry); + + return err; +} + +static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, + struct au_sbinfo *sbinfo, + const unsigned int dir_flags) +{ + int err; + struct dentry *parent; + struct inode *inode; + + err = 0; + parent = dget_parent(dentry); + if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { + inode = dentry->d_inode; + if (inode) { + if (!S_ISDIR(inode->i_mode)) + err = au_do_refresh(dentry, /*dir_flags*/0, + parent); + else { + err = au_do_refresh(dentry, dir_flags, parent); + if (unlikely(err)) + au_fset_si(sbinfo, FAILED_REFRESH_DIR); + } + } else + err = au_do_refresh(dentry, /*dir_flags*/0, parent); + AuDbgDentry(dentry); + } + dput(parent); + + AuTraceErr(err); + return err; +} + +static int au_refresh_d(struct super_block *sb) +{ + int err, i, j, ndentry, e; + unsigned int sigen; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries, *d; + struct au_sbinfo *sbinfo; + struct dentry *root = sb->s_root; + const unsigned int dir_flags = au_hi_flags(root->d_inode, /*isdir*/1); + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, root, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + sigen = au_sigen(sb); + sbinfo = au_sbi(sb); + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + d = dentries[j]; + e = au_do_refresh_d(d, sigen, sbinfo, dir_flags); + if (unlikely(e && !err)) + err = e; + /* go on even err */ + } + } + +out_dpages: + au_dpages_free(&dpages); +out: + return err; +} + +static int au_refresh_i(struct super_block *sb) +{ + int err, e; + unsigned int sigen; + unsigned long long max, ull; + struct inode *inode, **array; + + array = au_iarray_alloc(sb, &max); + err = PTR_ERR(array); + if (IS_ERR(array)) + goto out; + + err = 0; + sigen = au_sigen(sb); + for (ull = 0; ull < max; ull++) { + inode = array[ull]; + if (au_iigen(inode, NULL) != sigen) { + ii_write_lock_child(inode); + e = au_refresh_hinode_self(inode); + ii_write_unlock(inode); + if (unlikely(e)) { + pr_err("error %d, i%lu\n", e, inode->i_ino); + if (!err) + err = e; + /* go on even if err */ + } + } + } + + au_iarray_free(array, max); + +out: + return err; +} + +static void au_remount_refresh(struct super_block *sb) +{ + int err, e; + unsigned int udba; + aufs_bindex_t bindex, bend; + struct dentry *root; + struct inode *inode; + struct au_branch *br; + + au_sigen_inc(sb); + au_fclr_si(au_sbi(sb), FAILED_REFRESH_DIR); + + root = sb->s_root; + DiMustNoWaiters(root); + inode = root->d_inode; + IiMustNoWaiters(inode); + + udba = au_opt_udba(sb); + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + err = au_hnotify_reset_br(udba, br, br->br_perm); + if (unlikely(err)) + AuIOErr("hnotify failed on br %d, %d, ignored\n", + bindex, err); + /* go on even if err */ + } + au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); + + di_write_unlock(root); + err = au_refresh_d(sb); + e = au_refresh_i(sb); + if (unlikely(e && !err)) + err = e; + /* aufs_write_lock() calls ..._child() */ + di_write_lock_child(root); + + au_cpup_attr_all(inode, /*force*/1); + + if (unlikely(err)) + AuIOErr("refresh failed, ignored, %d\n", err); +} + +/* stop extra interpretation of errno in mount(8), and strange error messages */ +static int cvt_err(int err) +{ + AuTraceErr(err); + + switch (err) { + case -ENOENT: + case -ENOTDIR: + case -EEXIST: + case -EIO: + err = -EINVAL; + } + return err; +} + +static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + int err, do_dx; + unsigned int mntflags; + struct au_opts opts; + struct dentry *root; + struct inode *inode; + struct au_sbinfo *sbinfo; + + err = 0; + root = sb->s_root; + if (!data || !*data) { + err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (!err) { + di_write_lock_child(root); + err = au_opts_verify(sb, *flags, /*pending*/0); + aufs_write_unlock(root); + } + goto out; + } + + err = -ENOMEM; + memset(&opts, 0, sizeof(opts)); + opts.opt = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!opts.opt)) + goto out; + opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); + opts.flags = AuOpts_REMOUNT; + opts.sb_flags = *flags; + + /* parse it before aufs lock */ + err = au_opts_parse(sb, data, &opts); + if (unlikely(err)) + goto out_opts; + + sbinfo = au_sbi(sb); + inode = root->d_inode; + mutex_lock(&inode->i_mutex); + err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out_mtx; + di_write_lock_child(root); + + /* au_opts_remount() may return an error */ + err = au_opts_remount(sb, &opts); + au_opts_free(&opts); + + if (au_ftest_opts(opts.flags, REFRESH)) + au_remount_refresh(sb); + + if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { + mntflags = au_mntflags(sb); + do_dx = !!au_opt_test(mntflags, DIO); + au_dy_arefresh(do_dx); + } + + aufs_write_unlock(root); + +out_mtx: + mutex_unlock(&inode->i_mutex); +out_opts: + free_page((unsigned long)opts.opt); +out: + err = cvt_err(err); + AuTraceErr(err); + return err; +} + +static const struct super_operations aufs_sop = { + .alloc_inode = aufs_alloc_inode, + .destroy_inode = aufs_destroy_inode, + /* always deleting, no clearing */ + .drop_inode = generic_delete_inode, + .show_options = aufs_show_options, + .statfs = aufs_statfs, + .put_super = aufs_put_super, + .sync_fs = aufs_sync_fs, + .remount_fs = aufs_remount_fs +}; + +/* ---------------------------------------------------------------------- */ + +static int alloc_root(struct super_block *sb) +{ + int err; + struct inode *inode; + struct dentry *root; + + err = -ENOMEM; + inode = au_iget_locked(sb, AUFS_ROOT_INO); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out; + + inode->i_op = &aufs_dir_iop; + inode->i_fop = &aufs_dir_fop; + inode->i_mode = S_IFDIR; + set_nlink(inode, 2); + unlock_new_inode(inode); + + root = d_make_root(inode); + if (unlikely(!root)) + goto out; + err = PTR_ERR(root); + if (IS_ERR(root)) + goto out; + + err = au_di_init(root); + if (!err) { + sb->s_root = root; + return 0; /* success */ + } + dput(root); + +out: + return err; +} + +static int aufs_fill_super(struct super_block *sb, void *raw_data, + int silent __maybe_unused) +{ + int err; + struct au_opts opts; + struct dentry *root; + struct inode *inode; + char *arg = raw_data; + + if (unlikely(!arg || !*arg)) { + err = -EINVAL; + pr_err("no arg\n"); + goto out; + } + + err = -ENOMEM; + memset(&opts, 0, sizeof(opts)); + opts.opt = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!opts.opt)) + goto out; + opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); + opts.sb_flags = sb->s_flags; + + err = au_si_alloc(sb); + if (unlikely(err)) + goto out_opts; + + /* all timestamps always follow the ones on the branch */ + sb->s_flags |= MS_NOATIME | MS_NODIRATIME; + sb->s_op = &aufs_sop; + sb->s_d_op = &aufs_dop; + sb->s_magic = AUFS_SUPER_MAGIC; + sb->s_maxbytes = 0; + au_export_init(sb); + + err = alloc_root(sb); + if (unlikely(err)) { + si_write_unlock(sb); + goto out_info; + } + root = sb->s_root; + inode = root->d_inode; + + /* + * actually we can parse options regardless aufs lock here. + * but at remount time, parsing must be done before aufs lock. + * so we follow the same rule. + */ + ii_write_lock_parent(inode); + aufs_write_unlock(root); + err = au_opts_parse(sb, arg, &opts); + if (unlikely(err)) + goto out_root; + + /* lock vfs_inode first, then aufs. */ + mutex_lock(&inode->i_mutex); + aufs_write_lock(root); + err = au_opts_mount(sb, &opts); + au_opts_free(&opts); + aufs_write_unlock(root); + mutex_unlock(&inode->i_mutex); + if (!err) + goto out_opts; /* success */ + +out_root: + dput(root); + sb->s_root = NULL; +out_info: + dbgaufs_si_fin(au_sbi(sb)); + kobject_put(&au_sbi(sb)->si_kobj); + sb->s_fs_info = NULL; +out_opts: + free_page((unsigned long)opts.opt); +out: + AuTraceErr(err); + err = cvt_err(err); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name __maybe_unused, + void *raw_data) +{ + struct dentry *root; + struct super_block *sb; + + /* all timestamps always follow the ones on the branch */ + /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ + root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); + if (IS_ERR(root)) + goto out; + + sb = root->d_sb; + si_write_lock(sb, !AuLock_FLUSH); + sysaufs_brs_add(sb, 0); + si_write_unlock(sb); + au_sbilist_add(sb); + +out: + return root; +} + +static void aufs_kill_sb(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + sbinfo = au_sbi(sb); + if (sbinfo) { + au_sbilist_del(sb); + aufs_write_lock(sb->s_root); + if (sbinfo->si_wbr_create_ops->fin) + sbinfo->si_wbr_create_ops->fin(sb); + if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { + au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); + au_remount_refresh(sb); + } + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_put(sb, /*verbose*/1); + au_xino_clr(sb); + sbinfo->si_sb = NULL; + aufs_write_unlock(sb->s_root); + au_nwt_flush(&sbinfo->si_nowait); + } + kill_anon_super(sb); +} + +struct file_system_type aufs_fs_type = { + .name = AUFS_FSTYPE, + /* a race between rename and others */ + .fs_flags = FS_RENAME_DOES_D_MOVE, + .mount = aufs_mount, + .kill_sb = aufs_kill_sb, + /* no need to __module_get() and module_put(). */ + .owner = THIS_MODULE, +}; --- linux-3.13.0.orig/ubuntu/aufs/hfsnotify.c +++ linux-3.13.0/ubuntu/aufs/hfsnotify.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * fsnotify for the lower directories + */ + +#include "aufs.h" + +/* FS_IN_IGNORED is unnecessary */ +static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE + | FS_CREATE | FS_EVENT_ON_CHILD); +static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); +static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); + +static void au_hfsn_free_mark(struct fsnotify_mark *mark) +{ + struct au_hnotify *hn = container_of(mark, struct au_hnotify, + hn_mark); + AuDbg("here\n"); + au_cache_free_hnotify(hn); + smp_mb__before_atomic_dec(); + if (atomic64_dec_and_test(&au_hfsn_ifree)) + wake_up(&au_hfsn_wq); +} + +static int au_hfsn_alloc(struct au_hinode *hinode) +{ + int err; + struct au_hnotify *hn; + struct super_block *sb; + struct au_branch *br; + struct fsnotify_mark *mark; + aufs_bindex_t bindex; + + hn = hinode->hi_notify; + sb = hn->hn_aufs_inode->i_sb; + bindex = au_br_index(sb, hinode->hi_id); + br = au_sbr(sb, bindex); + AuDebugOn(!br->br_hfsn); + + mark = &hn->hn_mark; + fsnotify_init_mark(mark, au_hfsn_free_mark); + mark->mask = AuHfsnMask; + /* + * by udba rename or rmdir, aufs assign a new inode to the known + * h_inode, so specify 1 to allow dups. + */ + err = fsnotify_add_mark(mark, br->br_hfsn->hfsn_group, hinode->hi_inode, + /*mnt*/NULL, /*allow_dups*/1); + /* even if err */ + fsnotify_put_mark(mark); + + return err; +} + +static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) +{ + struct fsnotify_mark *mark; + unsigned long long ull; + struct fsnotify_group *group; + + ull = atomic64_inc_return(&au_hfsn_ifree); + BUG_ON(!ull); + + mark = &hn->hn_mark; + spin_lock(&mark->lock); + group = mark->group; + fsnotify_get_group(group); + spin_unlock(&mark->lock); + fsnotify_destroy_mark(mark, group); + fsnotify_put_group(group); + + /* free hn by myself */ + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) +{ + struct fsnotify_mark *mark; + + mark = &hinode->hi_notify->hn_mark; + spin_lock(&mark->lock); + if (do_set) { + AuDebugOn(mark->mask & AuHfsnMask); + mark->mask |= AuHfsnMask; + } else { + AuDebugOn(!(mark->mask & AuHfsnMask)); + mark->mask &= ~AuHfsnMask; + } + spin_unlock(&mark->lock); + /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ +} + +/* ---------------------------------------------------------------------- */ + +/* #define AuDbgHnotify */ +#ifdef AuDbgHnotify +static char *au_hfsn_name(u32 mask) +{ +#ifdef CONFIG_AUFS_DEBUG +#define test_ret(flag) \ + do { \ + if (mask & flag) \ + return #flag; \ + } while (0) + test_ret(FS_ACCESS); + test_ret(FS_MODIFY); + test_ret(FS_ATTRIB); + test_ret(FS_CLOSE_WRITE); + test_ret(FS_CLOSE_NOWRITE); + test_ret(FS_OPEN); + test_ret(FS_MOVED_FROM); + test_ret(FS_MOVED_TO); + test_ret(FS_CREATE); + test_ret(FS_DELETE); + test_ret(FS_DELETE_SELF); + test_ret(FS_MOVE_SELF); + test_ret(FS_UNMOUNT); + test_ret(FS_Q_OVERFLOW); + test_ret(FS_IN_IGNORED); + test_ret(FS_IN_ISDIR); + test_ret(FS_IN_ONESHOT); + test_ret(FS_EVENT_ON_CHILD); + return ""; +#undef test_ret +#else + return "??"; +#endif +} +#endif + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_free_group(struct fsnotify_group *group) +{ + struct au_br_hfsnotify *hfsn = group->private; + + AuDbg("here\n"); + kfree(hfsn); +} + +static int au_hfsn_handle_event(struct fsnotify_group *group, + struct fsnotify_mark *inode_mark, + struct fsnotify_mark *vfsmount_mark, + struct fsnotify_event *event) +{ + int err; + struct au_hnotify *hnotify; + struct inode *h_dir, *h_inode; + __u32 mask; + struct qstr h_child_qstr = QSTR_INIT(event->file_name, event->name_len); + + AuDebugOn(event->data_type != FSNOTIFY_EVENT_INODE); + + err = 0; + /* if FS_UNMOUNT happens, there must be another bug */ + mask = event->mask; + AuDebugOn(mask & FS_UNMOUNT); + if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) + goto out; + + h_dir = event->to_tell; + h_inode = event->inode; +#ifdef AuDbgHnotify + au_debug_on(); + if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 + || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { + AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", + h_dir->i_ino, mask, au_hfsn_name(mask), + AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); + /* WARN_ON(1); */ + } + au_debug_off(); +#endif + + AuDebugOn(!inode_mark); + hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); + err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode); + +out: + return err; +} + +/* isn't it waste to ask every registered 'group'? */ +/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */ +/* it should be exported to modules */ +static bool au_hfsn_should_send_event(struct fsnotify_group *group, + struct inode *h_inode, + struct fsnotify_mark *inode_mark, + struct fsnotify_mark *vfsmount_mark, + __u32 mask, void *data, int data_type) +{ + mask = (mask & ~FS_EVENT_ON_CHILD); + return inode_mark->mask & mask; +} + +static struct fsnotify_ops au_hfsn_ops = { + .should_send_event = au_hfsn_should_send_event, + .handle_event = au_hfsn_handle_event, + .free_group_priv = au_hfsn_free_group +}; + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_fin_br(struct au_branch *br) +{ + struct au_br_hfsnotify *hfsn; + + hfsn = br->br_hfsn; + if (hfsn) + fsnotify_put_group(hfsn->hfsn_group); +} + +static int au_hfsn_init_br(struct au_branch *br, int perm) +{ + int err; + struct fsnotify_group *group; + struct au_br_hfsnotify *hfsn; + + err = 0; + br->br_hfsn = NULL; + if (!au_br_hnotifyable(perm)) + goto out; + + err = -ENOMEM; + hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); + if (unlikely(!hfsn)) + goto out; + + err = 0; + group = fsnotify_alloc_group(&au_hfsn_ops); + if (IS_ERR(group)) { + err = PTR_ERR(group); + pr_err("fsnotify_alloc_group() failed, %d\n", err); + goto out_hfsn; + } + + group->private = hfsn; + hfsn->hfsn_group = group; + br->br_hfsn = hfsn; + goto out; /* success */ + +out_hfsn: + kfree(hfsn); +out: + return err; +} + +static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) +{ + int err; + + err = 0; + if (!br->br_hfsn) + err = au_hfsn_init_br(br, perm); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_fin(void) +{ + AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); + wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); +} + +const struct au_hnotify_op au_hnotify_op = { + .ctl = au_hfsn_ctl, + .alloc = au_hfsn_alloc, + .free = au_hfsn_free, + + .fin = au_hfsn_fin, + + .reset_br = au_hfsn_reset_br, + .fin_br = au_hfsn_fin_br, + .init_br = au_hfsn_init_br +}; --- linux-3.13.0.orig/ubuntu/aufs/hnotify.c +++ linux-3.13.0/ubuntu/aufs/hnotify.c @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * abstraction to notify the direct changes on lower directories + */ + +#include "aufs.h" + +int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) +{ + int err; + struct au_hnotify *hn; + + err = -ENOMEM; + hn = au_cache_alloc_hnotify(); + if (hn) { + hn->hn_aufs_inode = inode; + hinode->hi_notify = hn; + err = au_hnotify_op.alloc(hinode); + AuTraceErr(err); + if (unlikely(err)) { + hinode->hi_notify = NULL; + au_cache_free_hnotify(hn); + /* + * The upper dir was removed by udba, but the same named + * dir left. In this case, aufs assignes a new inode + * number and set the monitor again. + * For the lower dir, the old monitnor is still left. + */ + if (err == -EEXIST) + err = 0; + } + } + + AuTraceErr(err); + return err; +} + +void au_hn_free(struct au_hinode *hinode) +{ + struct au_hnotify *hn; + + hn = hinode->hi_notify; + if (hn) { + hinode->hi_notify = NULL; + if (au_hnotify_op.free(hinode, hn)) + au_cache_free_hnotify(hn); + } +} + +/* ---------------------------------------------------------------------- */ + +void au_hn_ctl(struct au_hinode *hinode, int do_set) +{ + if (hinode->hi_notify) + au_hnotify_op.ctl(hinode, do_set); +} + +void au_hn_reset(struct inode *inode, unsigned int flags) +{ + aufs_bindex_t bindex, bend; + struct inode *hi; + struct dentry *iwhdentry; + + bend = au_ibend(inode); + for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { + hi = au_h_iptr(inode, bindex); + if (!hi) + continue; + + /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */ + iwhdentry = au_hi_wh(inode, bindex); + if (iwhdentry) + dget(iwhdentry); + au_igrab(hi); + au_set_h_iptr(inode, bindex, NULL, 0); + au_set_h_iptr(inode, bindex, au_igrab(hi), + flags & ~AuHi_XINO); + iput(hi); + dput(iwhdentry); + /* mutex_unlock(&hi->i_mutex); */ + } +} + +/* ---------------------------------------------------------------------- */ + +static int hn_xino(struct inode *inode, struct inode *h_inode) +{ + int err; + aufs_bindex_t bindex, bend, bfound, bstart; + struct inode *h_i; + + err = 0; + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + pr_warn("branch root dir was changed\n"); + goto out; + } + + bfound = -1; + bend = au_ibend(inode); + bstart = au_ibstart(inode); +#if 0 /* reserved for future use */ + if (bindex == bend) { + /* keep this ino in rename case */ + goto out; + } +#endif + for (bindex = bstart; bindex <= bend; bindex++) + if (au_h_iptr(inode, bindex) == h_inode) { + bfound = bindex; + break; + } + if (bfound < 0) + goto out; + + for (bindex = bstart; bindex <= bend; bindex++) { + h_i = au_h_iptr(inode, bindex); + if (!h_i) + continue; + + err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); + /* ignore this error */ + /* bad action? */ + } + + /* children inode number will be broken */ + +out: + AuTraceErr(err); + return err; +} + +static int hn_gen_tree(struct dentry *dentry) +{ + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, dentry, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + struct dentry *d; + + d = dentries[j]; + if (IS_ROOT(d)) + continue; + + au_digen_dec(d); + if (d->d_inode) + /* todo: reset children xino? + cached children only? */ + au_iigen_dec(d->d_inode); + } + } + +out_dpages: + au_dpages_free(&dpages); + +#if 0 + /* discard children */ + dentry_unhash(dentry); + dput(dentry); +#endif +out: + return err; +} + +/* + * return 0 if processed. + */ +static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, + const unsigned int isdir) +{ + int err; + struct dentry *d; + struct qstr *dname; + + err = 1; + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + pr_warn("branch root dir was changed\n"); + err = 0; + goto out; + } + + if (!isdir) { + AuDebugOn(!name); + au_iigen_dec(inode); + spin_lock(&inode->i_lock); + hlist_for_each_entry(d, &inode->i_dentry, d_alias) { + spin_lock(&d->d_lock); + dname = &d->d_name; + if (dname->len != nlen + && memcmp(dname->name, name, nlen)) { + spin_unlock(&d->d_lock); + continue; + } + err = 0; + au_digen_dec(d); + spin_unlock(&d->d_lock); + break; + } + spin_unlock(&inode->i_lock); + } else { + au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); + d = d_find_alias(inode); + if (!d) { + au_iigen_dec(inode); + goto out; + } + + spin_lock(&d->d_lock); + dname = &d->d_name; + if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { + spin_unlock(&d->d_lock); + err = hn_gen_tree(d); + spin_lock(&d->d_lock); + } + spin_unlock(&d->d_lock); + dput(d); + } + +out: + AuTraceErr(err); + return err; +} + +static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) +{ + int err; + struct inode *inode; + + inode = dentry->d_inode; + if (IS_ROOT(dentry) + /* || (inode && inode->i_ino == AUFS_ROOT_INO) */ + ) { + pr_warn("branch root dir was changed\n"); + return 0; + } + + err = 0; + if (!isdir) { + au_digen_dec(dentry); + if (inode) + au_iigen_dec(inode); + } else { + au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); + if (inode) + err = hn_gen_tree(dentry); + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* hnotify job flags */ +#define AuHnJob_XINO0 1 +#define AuHnJob_GEN (1 << 1) +#define AuHnJob_DIRENT (1 << 2) +#define AuHnJob_ISDIR (1 << 3) +#define AuHnJob_TRYXINO0 (1 << 4) +#define AuHnJob_MNTPNT (1 << 5) +#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) +#define au_fset_hnjob(flags, name) \ + do { (flags) |= AuHnJob_##name; } while (0) +#define au_fclr_hnjob(flags, name) \ + do { (flags) &= ~AuHnJob_##name; } while (0) + +enum { + AuHn_CHILD, + AuHn_PARENT, + AuHnLast +}; + +struct au_hnotify_args { + struct inode *h_dir, *dir, *h_child_inode; + u32 mask; + unsigned int flags[AuHnLast]; + unsigned int h_child_nlen; + char h_child_name[]; +}; + +struct hn_job_args { + unsigned int flags; + struct inode *inode, *h_inode, *dir, *h_dir; + struct dentry *dentry; + char *h_name; + int h_nlen; +}; + +static int hn_job(struct hn_job_args *a) +{ + const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); + + /* reset xino */ + if (au_ftest_hnjob(a->flags, XINO0) && a->inode) + hn_xino(a->inode, a->h_inode); /* ignore this error */ + + if (au_ftest_hnjob(a->flags, TRYXINO0) + && a->inode + && a->h_inode) { + mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); + if (!a->h_inode->i_nlink) + hn_xino(a->inode, a->h_inode); /* ignore this error */ + mutex_unlock(&a->h_inode->i_mutex); + } + + /* make the generation obsolete */ + if (au_ftest_hnjob(a->flags, GEN)) { + int err = -1; + if (a->inode) + err = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, + isdir); + if (err && a->dentry) + hn_gen_by_name(a->dentry, isdir); + /* ignore this error */ + } + + /* make dir entries obsolete */ + if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { + struct au_vdir *vdir; + + vdir = au_ivdir(a->inode); + if (vdir) + vdir->vd_jiffy = 0; + /* IMustLock(a->inode); */ + /* a->inode->i_version++; */ + } + + /* can do nothing but warn */ + if (au_ftest_hnjob(a->flags, MNTPNT) + && a->dentry + && d_mountpoint(a->dentry)) + pr_warn("mount-point %pd is removed or renamed\n", a->dentry); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, + struct inode *dir) +{ + struct dentry *dentry, *d, *parent; + struct qstr *dname; + + parent = d_find_alias(dir); + if (!parent) + return NULL; + + dentry = NULL; + spin_lock(&parent->d_lock); + list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) { + /* AuDbg("%pd\n", d); */ + spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); + dname = &d->d_name; + if (dname->len != nlen || memcmp(dname->name, name, nlen)) + goto cont_unlock; + if (au_di(d)) + au_digen_dec(d); + else + goto cont_unlock; + if (d_count(d)) { + dentry = dget_dlock(d); + spin_unlock(&d->d_lock); + break; + } + +cont_unlock: + spin_unlock(&d->d_lock); + } + spin_unlock(&parent->d_lock); + dput(parent); + + if (dentry) + di_write_lock_child(dentry); + + return dentry; +} + +static struct inode *lookup_wlock_by_ino(struct super_block *sb, + aufs_bindex_t bindex, ino_t h_ino) +{ + struct inode *inode; + ino_t ino; + int err; + + inode = NULL; + err = au_xino_read(sb, bindex, h_ino, &ino); + if (!err && ino) + inode = ilookup(sb, ino); + if (!inode) + goto out; + + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + pr_warn("wrong root branch\n"); + iput(inode); + inode = NULL; + goto out; + } + + ii_write_lock_child(inode); + +out: + return inode; +} + +static void au_hn_bh(void *_args) +{ + struct au_hnotify_args *a = _args; + struct super_block *sb; + aufs_bindex_t bindex, bend, bfound; + unsigned char xino, try_iput; + int err; + struct inode *inode; + ino_t h_ino; + struct hn_job_args args; + struct dentry *dentry; + struct au_sbinfo *sbinfo; + + AuDebugOn(!_args); + AuDebugOn(!a->h_dir); + AuDebugOn(!a->dir); + AuDebugOn(!a->mask); + AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", + a->mask, a->dir->i_ino, a->h_dir->i_ino, + a->h_child_inode ? a->h_child_inode->i_ino : 0); + + inode = NULL; + dentry = NULL; + /* + * do not lock a->dir->i_mutex here + * because of d_revalidate() may cause a deadlock. + */ + sb = a->dir->i_sb; + AuDebugOn(!sb); + sbinfo = au_sbi(sb); + AuDebugOn(!sbinfo); + si_write_lock(sb, AuLock_NOPLMW); + + ii_read_lock_parent(a->dir); + bfound = -1; + bend = au_ibend(a->dir); + for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++) + if (au_h_iptr(a->dir, bindex) == a->h_dir) { + bfound = bindex; + break; + } + ii_read_unlock(a->dir); + if (unlikely(bfound < 0)) + goto out; + + xino = !!au_opt_test(au_mntflags(sb), XINO); + h_ino = 0; + if (a->h_child_inode) + h_ino = a->h_child_inode->i_ino; + + if (a->h_child_nlen + && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) + || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) + dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, + a->dir); + try_iput = 0; + if (dentry) + inode = dentry->d_inode; + if (xino && !inode && h_ino + && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) + || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) + || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { + inode = lookup_wlock_by_ino(sb, bfound, h_ino); + try_iput = 1; + } + + args.flags = a->flags[AuHn_CHILD]; + args.dentry = dentry; + args.inode = inode; + args.h_inode = a->h_child_inode; + args.dir = a->dir; + args.h_dir = a->h_dir; + args.h_name = a->h_child_name; + args.h_nlen = a->h_child_nlen; + err = hn_job(&args); + if (dentry) { + if (au_di(dentry)) + di_write_unlock(dentry); + dput(dentry); + } + if (inode && try_iput) { + ii_write_unlock(inode); + iput(inode); + } + + ii_write_lock_parent(a->dir); + args.flags = a->flags[AuHn_PARENT]; + args.dentry = NULL; + args.inode = a->dir; + args.h_inode = a->h_dir; + args.dir = NULL; + args.h_dir = NULL; + args.h_name = NULL; + args.h_nlen = 0; + err = hn_job(&args); + ii_write_unlock(a->dir); + +out: + iput(a->h_child_inode); + iput(a->h_dir); + iput(a->dir); + si_write_unlock(sb); + au_nwt_done(&sbinfo->si_nowait); + kfree(a); +} + +/* ---------------------------------------------------------------------- */ + +int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, + struct qstr *h_child_qstr, struct inode *h_child_inode) +{ + int err, len; + unsigned int flags[AuHnLast], f; + unsigned char isdir, isroot, wh; + struct inode *dir; + struct au_hnotify_args *args; + char *p, *h_child_name; + + err = 0; + AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); + dir = igrab(hnotify->hn_aufs_inode); + if (!dir) + goto out; + + isroot = (dir->i_ino == AUFS_ROOT_INO); + wh = 0; + h_child_name = (void *)h_child_qstr->name; + len = h_child_qstr->len; + if (h_child_name) { + if (len > AUFS_WH_PFX_LEN + && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + h_child_name += AUFS_WH_PFX_LEN; + len -= AUFS_WH_PFX_LEN; + wh = 1; + } + } + + isdir = 0; + if (h_child_inode) + isdir = !!S_ISDIR(h_child_inode->i_mode); + flags[AuHn_PARENT] = AuHnJob_ISDIR; + flags[AuHn_CHILD] = 0; + if (isdir) + flags[AuHn_CHILD] = AuHnJob_ISDIR; + au_fset_hnjob(flags[AuHn_PARENT], DIRENT); + au_fset_hnjob(flags[AuHn_CHILD], GEN); + switch (mask & FS_EVENTS_POSS_ON_CHILD) { + case FS_MOVED_FROM: + case FS_MOVED_TO: + au_fset_hnjob(flags[AuHn_CHILD], XINO0); + au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); + /*FALLTHROUGH*/ + case FS_CREATE: + AuDebugOn(!h_child_name || !h_child_inode); + break; + + case FS_DELETE: + /* + * aufs never be able to get this child inode. + * revalidation should be in d_revalidate() + * by checking i_nlink, i_generation or d_unhashed(). + */ + AuDebugOn(!h_child_name); + au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); + au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); + break; + + default: + AuDebugOn(1); + } + + if (wh) + h_child_inode = NULL; + + err = -ENOMEM; + /* iput() and kfree() will be called in au_hnotify() */ + args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); + if (unlikely(!args)) { + AuErr1("no memory\n"); + iput(dir); + goto out; + } + args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; + args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; + args->mask = mask; + args->dir = dir; + args->h_dir = igrab(h_dir); + if (h_child_inode) + h_child_inode = igrab(h_child_inode); /* can be NULL */ + args->h_child_inode = h_child_inode; + args->h_child_nlen = len; + if (len) { + p = (void *)args; + p += sizeof(*args); + memcpy(p, h_child_name, len); + p[len] = 0; + } + + f = 0; + if (!dir->i_nlink) + f = AuWkq_NEST; + err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); + if (unlikely(err)) { + pr_err("wkq %d\n", err); + iput(args->h_child_inode); + iput(args->h_dir); + iput(args->dir); + kfree(args); + } + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) +{ + int err; + + AuDebugOn(!(udba & AuOptMask_UDBA)); + + err = 0; + if (au_hnotify_op.reset_br) + err = au_hnotify_op.reset_br(udba, br, perm); + + return err; +} + +int au_hnotify_init_br(struct au_branch *br, int perm) +{ + int err; + + err = 0; + if (au_hnotify_op.init_br) + err = au_hnotify_op.init_br(br, perm); + + return err; +} + +void au_hnotify_fin_br(struct au_branch *br) +{ + if (au_hnotify_op.fin_br) + au_hnotify_op.fin_br(br); +} + +static void au_hn_destroy_cache(void) +{ + kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]); + au_cachep[AuCache_HNOTIFY] = NULL; +} + +int __init au_hnotify_init(void) +{ + int err; + + err = -ENOMEM; + au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify); + if (au_cachep[AuCache_HNOTIFY]) { + err = 0; + if (au_hnotify_op.init) + err = au_hnotify_op.init(); + if (unlikely(err)) + au_hn_destroy_cache(); + } + AuTraceErr(err); + return err; +} + +void au_hnotify_fin(void) +{ + if (au_hnotify_op.fin) + au_hnotify_op.fin(); + /* cf. au_cache_fin() */ + if (au_cachep[AuCache_HNOTIFY]) + au_hn_destroy_cache(); +} --- linux-3.13.0.orig/ubuntu/aufs/debug.h +++ linux-3.13.0/ubuntu/aufs/debug.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debug print functions + */ + +#ifndef __AUFS_DEBUG_H__ +#define __AUFS_DEBUG_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#ifdef CONFIG_AUFS_DEBUG +#define AuDebugOn(a) BUG_ON(a) + +/* module parameter */ +extern atomic_t aufs_debug; +static inline void au_debug_on(void) +{ + atomic_inc(&aufs_debug); +} +static inline void au_debug_off(void) +{ + atomic_dec_if_positive(&aufs_debug); +} + +static inline int au_debug_test(void) +{ + return atomic_read(&aufs_debug) > 0; +} +#else +#define AuDebugOn(a) do {} while (0) +AuStubVoid(au_debug_on, void) +AuStubVoid(au_debug_off, void) +AuStubInt0(au_debug_test, void) +#endif /* CONFIG_AUFS_DEBUG */ + +#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) + +/* ---------------------------------------------------------------------- */ + +/* debug print */ + +#define AuDbg(fmt, ...) do { \ + if (au_debug_test()) \ + pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ +} while (0) +#define AuLabel(l) AuDbg(#l "\n") +#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) +#define AuWarn1(fmt, ...) do { \ + static unsigned char _c; \ + if (!_c++) \ + pr_warn(fmt, ##__VA_ARGS__); \ +} while (0) + +#define AuErr1(fmt, ...) do { \ + static unsigned char _c; \ + if (!_c++) \ + pr_err(fmt, ##__VA_ARGS__); \ +} while (0) + +#define AuIOErr1(fmt, ...) do { \ + static unsigned char _c; \ + if (!_c++) \ + AuIOErr(fmt, ##__VA_ARGS__); \ +} while (0) + +#define AuUnsupportMsg "This operation is not supported." \ + " Please report this application to aufs-users ML." +#define AuUnsupport(fmt, ...) do { \ + pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ + dump_stack(); \ +} while (0) + +#define AuTraceErr(e) do { \ + if (unlikely((e) < 0)) \ + AuDbg("err %d\n", (int)(e)); \ +} while (0) + +#define AuTraceErrPtr(p) do { \ + if (IS_ERR(p)) \ + AuDbg("err %ld\n", PTR_ERR(p)); \ +} while (0) + +/* dirty macros for debug print, use with "%.*s" and caution */ +#define AuLNPair(qstr) (qstr)->len, (qstr)->name + +/* ---------------------------------------------------------------------- */ + +struct au_sbinfo; +struct au_finfo; +struct dentry; +#ifdef CONFIG_AUFS_DEBUG +extern char *au_plevel; +struct au_nhash; +void au_dpri_whlist(struct au_nhash *whlist); +struct au_vdir; +void au_dpri_vdir(struct au_vdir *vdir); +struct inode; +void au_dpri_inode(struct inode *inode); +void au_dpri_dalias(struct inode *inode); +void au_dpri_dentry(struct dentry *dentry); +struct file; +void au_dpri_file(struct file *filp); +struct super_block; +void au_dpri_sb(struct super_block *sb); + +void au_dbg_sleep_jiffy(int jiffy); +struct iattr; +void au_dbg_iattr(struct iattr *ia); + +#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) +void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); +void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen); +void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen); +void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); +void au_dbg_verify_kthread(void); + +int __init au_debug_init(void); +void au_debug_sbinfo_init(struct au_sbinfo *sbinfo); +#define AuDbgWhlist(w) do { \ + AuDbg(#w "\n"); \ + au_dpri_whlist(w); \ +} while (0) + +#define AuDbgVdir(v) do { \ + AuDbg(#v "\n"); \ + au_dpri_vdir(v); \ +} while (0) + +#define AuDbgInode(i) do { \ + AuDbg(#i "\n"); \ + au_dpri_inode(i); \ +} while (0) + +#define AuDbgDAlias(i) do { \ + AuDbg(#i "\n"); \ + au_dpri_dalias(i); \ +} while (0) + +#define AuDbgDentry(d) do { \ + AuDbg(#d "\n"); \ + au_dpri_dentry(d); \ +} while (0) + +#define AuDbgFile(f) do { \ + AuDbg(#f "\n"); \ + au_dpri_file(f); \ +} while (0) + +#define AuDbgSb(sb) do { \ + AuDbg(#sb "\n"); \ + au_dpri_sb(sb); \ +} while (0) + +#define AuDbgSleep(sec) do { \ + AuDbg("sleep %d sec\n", sec); \ + ssleep(sec); \ +} while (0) + +#define AuDbgSleepJiffy(jiffy) do { \ + AuDbg("sleep %d jiffies\n", jiffy); \ + au_dbg_sleep_jiffy(jiffy); \ +} while (0) + +#define AuDbgIAttr(ia) do { \ + AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \ + au_dbg_iattr(ia); \ +} while (0) + +#define AuDbgSym(addr) do { \ + char sym[KSYM_SYMBOL_LEN]; \ + sprint_symbol(sym, (unsigned long)addr); \ + AuDbg("%s\n", sym); \ +} while (0) + +#define AuInfoSym(addr) do { \ + char sym[KSYM_SYMBOL_LEN]; \ + sprint_symbol(sym, (unsigned long)addr); \ + AuInfo("%s\n", sym); \ +} while (0) +#else +AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) +AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen) +AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry, + unsigned int sigen) +AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) +AuStubVoid(au_dbg_verify_kthread, void) +AuStubInt0(__init au_debug_init, void) +AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo) + +#define AuDbgWhlist(w) do {} while (0) +#define AuDbgVdir(v) do {} while (0) +#define AuDbgInode(i) do {} while (0) +#define AuDbgDAlias(i) do {} while (0) +#define AuDbgDentry(d) do {} while (0) +#define AuDbgFile(f) do {} while (0) +#define AuDbgSb(sb) do {} while (0) +#define AuDbgSleep(sec) do {} while (0) +#define AuDbgSleepJiffy(jiffy) do {} while (0) +#define AuDbgIAttr(ia) do {} while (0) +#define AuDbgSym(addr) do {} while (0) +#define AuInfoSym(addr) do {} while (0) +#endif /* CONFIG_AUFS_DEBUG */ + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_MAGIC_SYSRQ +int __init au_sysrq_init(void); +void au_sysrq_fin(void); + +#ifdef CONFIG_HW_CONSOLE +#define au_dbg_blocked() do { \ + WARN_ON(1); \ + handle_sysrq('w'); \ +} while (0) +#else +AuStubVoid(au_dbg_blocked, void) +#endif + +#else +AuStubInt0(__init au_sysrq_init, void) +AuStubVoid(au_sysrq_fin, void) +AuStubVoid(au_dbg_blocked, void) +#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DEBUG_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/whout.h +++ linux-3.13.0/ubuntu/aufs/whout.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * whiteout for logical deletion and opaque directory + */ + +#ifndef __AUFS_WHOUT_H__ +#define __AUFS_WHOUT_H__ + +#ifdef __KERNEL__ + +#include "dir.h" + +/* whout.c */ +int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); +struct au_branch; +int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, + struct au_branch *br, int try_sio); +int au_diropq_test(struct dentry *h_dentry, struct au_branch *br); +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, + struct qstr *prefix); +int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); +int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, + struct dentry *dentry); +int au_wh_init(struct au_branch *br, struct super_block *sb); + +/* diropq flags */ +#define AuDiropq_CREATE 1 +#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) +#define au_fset_diropq(flags, name) \ + do { (flags) |= AuDiropq_##name; } while (0) +#define au_fclr_diropq(flags, name) \ + do { (flags) &= ~AuDiropq_##name; } while (0) + +struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags); +struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, + struct au_branch *br); +struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent); + +/* real rmdir for the whiteout-ed dir */ +struct au_whtmp_rmdir { + struct inode *dir; + struct au_branch *br; + struct dentry *wh_dentry; + struct au_nhash whlist; +}; + +struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); +void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); +int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist); +void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_whtmp_rmdir *args); + +/* ---------------------------------------------------------------------- */ + +static inline struct dentry *au_diropq_create(struct dentry *dentry, + aufs_bindex_t bindex) +{ + return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); +} + +static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) +{ + return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WHOUT_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/dcsub.c +++ linux-3.13.0/ubuntu/aufs/dcsub.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for dentry cache + */ + +#include "aufs.h" + +static void au_dpage_free(struct au_dpage *dpage) +{ + int i; + struct dentry **p; + + p = dpage->dentries; + for (i = 0; i < dpage->ndentry; i++) + dput(*p++); + free_page((unsigned long)dpage->dentries); +} + +int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) +{ + int err; + void *p; + + err = -ENOMEM; + dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); + if (unlikely(!dpages->dpages)) + goto out; + + p = (void *)__get_free_page(gfp); + if (unlikely(!p)) + goto out_dpages; + + dpages->dpages[0].ndentry = 0; + dpages->dpages[0].dentries = p; + dpages->ndpage = 1; + return 0; /* success */ + +out_dpages: + kfree(dpages->dpages); +out: + return err; +} + +void au_dpages_free(struct au_dcsub_pages *dpages) +{ + int i; + struct au_dpage *p; + + p = dpages->dpages; + for (i = 0; i < dpages->ndpage; i++) + au_dpage_free(p++); + kfree(dpages->dpages); +} + +static int au_dpages_append(struct au_dcsub_pages *dpages, + struct dentry *dentry, gfp_t gfp) +{ + int err, sz; + struct au_dpage *dpage; + void *p; + + dpage = dpages->dpages + dpages->ndpage - 1; + sz = PAGE_SIZE / sizeof(dentry); + if (unlikely(dpage->ndentry >= sz)) { + AuLabel(new dpage); + err = -ENOMEM; + sz = dpages->ndpage * sizeof(*dpages->dpages); + p = au_kzrealloc(dpages->dpages, sz, + sz + sizeof(*dpages->dpages), gfp); + if (unlikely(!p)) + goto out; + + dpages->dpages = p; + dpage = dpages->dpages + dpages->ndpage; + p = (void *)__get_free_page(gfp); + if (unlikely(!p)) + goto out; + + dpage->ndentry = 0; + dpage->dentries = p; + dpages->ndpage++; + } + + AuDebugOn(!d_count(dentry)); + dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); + return 0; /* success */ + +out: + return err; +} + +/* try d_walk() in linux/fs/dcache.c */ +int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, + au_dpages_test test, void *arg) +{ + int err; + struct dentry *this_parent; + struct list_head *next; + struct super_block *sb = root->d_sb; + + err = 0; + write_seqlock(&rename_lock); + this_parent = root; + spin_lock(&this_parent->d_lock); +repeat: + next = this_parent->d_subdirs.next; +resume: + if (this_parent->d_sb == sb + && !IS_ROOT(this_parent) + && au_di(this_parent) + && d_count(this_parent) + && (!test || test(this_parent, arg))) { + err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); + if (unlikely(err)) + goto out; + } + + while (next != &this_parent->d_subdirs) { + struct list_head *tmp = next; + struct dentry *dentry = list_entry(tmp, struct dentry, + d_u.d_child); + + next = tmp->next; + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); + if (d_count(dentry)) { + if (!list_empty(&dentry->d_subdirs)) { + spin_unlock(&this_parent->d_lock); + spin_release(&dentry->d_lock.dep_map, 1, + _RET_IP_); + this_parent = dentry; + spin_acquire(&this_parent->d_lock.dep_map, 0, 1, + _RET_IP_); + goto repeat; + } + if (dentry->d_sb == sb + && au_di(dentry) + && (!test || test(dentry, arg))) + err = au_dpages_append(dpages, dentry, + GFP_ATOMIC); + } + spin_unlock(&dentry->d_lock); + if (unlikely(err)) + goto out; + } + + if (this_parent != root) { + struct dentry *tmp; + struct dentry *child; + + tmp = this_parent->d_parent; + rcu_read_lock(); + spin_unlock(&this_parent->d_lock); + child = this_parent; + this_parent = tmp; + spin_lock(&this_parent->d_lock); + rcu_read_unlock(); + next = child->d_u.d_child.next; + goto resume; + } + +out: + spin_unlock(&this_parent->d_lock); + write_sequnlock(&rename_lock); + return err; +} + +int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, + int do_include, au_dpages_test test, void *arg) +{ + int err; + + err = 0; + write_seqlock(&rename_lock); + spin_lock(&dentry->d_lock); + if (do_include + && d_count(dentry) + && (!test || test(dentry, arg))) + err = au_dpages_append(dpages, dentry, GFP_ATOMIC); + spin_unlock(&dentry->d_lock); + if (unlikely(err)) + goto out; + + /* + * RCU for vfsmount is unnecessary since this is a traverse in a single + * mount + */ + while (!IS_ROOT(dentry)) { + dentry = dentry->d_parent; /* rename_lock is locked */ + spin_lock(&dentry->d_lock); + if (d_count(dentry) + && (!test || test(dentry, arg))) + err = au_dpages_append(dpages, dentry, GFP_ATOMIC); + spin_unlock(&dentry->d_lock); + if (unlikely(err)) + break; + } + +out: + write_sequnlock(&rename_lock); + return err; +} + +static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) +{ + return au_di(dentry) && dentry->d_sb == arg; +} + +int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, + struct dentry *dentry, int do_include) +{ + return au_dcsub_pages_rev(dpages, dentry, do_include, + au_dcsub_dpages_aufs, dentry->d_sb); +} + +int au_test_subdir(struct dentry *d1, struct dentry *d2) +{ + struct path path[2] = { + { + .dentry = d1 + }, + { + .dentry = d2 + } + }; + + return path_is_under(path + 0, path + 1); +} --- linux-3.13.0.orig/ubuntu/aufs/debug.c +++ linux-3.13.0/ubuntu/aufs/debug.c @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debug print functions + */ + +#include +#include "aufs.h" + +/* Returns 0, or -errno. arg is in kp->arg. */ +static int param_atomic_t_set(const char *val, const struct kernel_param *kp) +{ + int err, n; + + err = kstrtoint(val, 0, &n); + if (!err) { + if (n > 0) + au_debug_on(); + else + au_debug_off(); + } + return err; +} + +/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ +static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) +{ + atomic_t *a; + + a = kp->arg; + return sprintf(buffer, "%d", atomic_read(a)); +} + +static struct kernel_param_ops param_ops_atomic_t = { + .set = param_atomic_t_set, + .get = param_atomic_t_get + /* void (*free)(void *arg) */ +}; + +atomic_t aufs_debug = ATOMIC_INIT(0); +MODULE_PARM_DESC(debug, "debug print"); +module_param_named(debug, aufs_debug, atomic_t, S_IRUGO | S_IWUSR | S_IWGRP); + +char *au_plevel = KERN_DEBUG; +#define dpri(fmt, ...) do { \ + if ((au_plevel \ + && strcmp(au_plevel, KERN_DEBUG)) \ + || au_debug_test()) \ + printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ +} while (0) + +/* ---------------------------------------------------------------------- */ + +void au_dpri_whlist(struct au_nhash *whlist) +{ + unsigned long ul, n; + struct hlist_head *head; + struct au_vdir_wh *pos; + + n = whlist->nh_num; + head = whlist->nh_head; + for (ul = 0; ul < n; ul++) { + hlist_for_each_entry(pos, head, wh_hash) + dpri("b%d, %.*s, %d\n", + pos->wh_bindex, + pos->wh_str.len, pos->wh_str.name, + pos->wh_str.len); + head++; + } +} + +void au_dpri_vdir(struct au_vdir *vdir) +{ + unsigned long ul; + union au_vdir_deblk_p p; + unsigned char *o; + + if (!vdir || IS_ERR(vdir)) { + dpri("err %ld\n", PTR_ERR(vdir)); + return; + } + + dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n", + vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, + vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); + for (ul = 0; ul < vdir->vd_nblk; ul++) { + p.deblk = vdir->vd_deblk[ul]; + o = p.deblk; + dpri("[%lu]: %p\n", ul, o); + } +} + +static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, + struct dentry *wh) +{ + char *n = NULL; + int l = 0; + + if (!inode || IS_ERR(inode)) { + dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); + return -1; + } + + /* the type of i_blocks depends upon CONFIG_LBDAF */ + BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) + && sizeof(inode->i_blocks) != sizeof(u64)); + if (wh) { + n = (void *)wh->d_name.name; + l = wh->d_name.len; + } + + dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," + " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", + bindex, inode, + inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", + atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, + i_size_read(inode), (unsigned long long)inode->i_blocks, + hn, (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, + inode->i_mapping ? inode->i_mapping->nrpages : 0, + inode->i_state, inode->i_flags, inode->i_version, + inode->i_generation, + l ? ", wh " : "", l, n); + return 0; +} + +void au_dpri_inode(struct inode *inode) +{ + struct au_iinfo *iinfo; + aufs_bindex_t bindex; + int err, hn; + + err = do_pri_inode(-1, inode, -1, NULL); + if (err || !au_test_aufs(inode->i_sb)) + return; + + iinfo = au_ii(inode); + if (!iinfo) + return; + dpri("i-1: bstart %d, bend %d, gen %d\n", + iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode, NULL)); + if (iinfo->ii_bstart < 0) + return; + hn = 0; + for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) { + hn = !!au_hn(iinfo->ii_hinode + bindex); + do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode, hn, + iinfo->ii_hinode[0 + bindex].hi_whdentry); + } +} + +void au_dpri_dalias(struct inode *inode) +{ + struct dentry *d; + + spin_lock(&inode->i_lock); + hlist_for_each_entry(d, &inode->i_dentry, d_alias) + au_dpri_dentry(d); + spin_unlock(&inode->i_lock); +} + +static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) +{ + struct dentry *wh = NULL; + int hn; + + if (!dentry || IS_ERR(dentry)) { + dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); + return -1; + } + /* do not call dget_parent() here */ + /* note: access d_xxx without d_lock */ + dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", + bindex, dentry, dentry, + dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", + d_count(dentry), dentry->d_flags, + d_unhashed(dentry) ? "un" : ""); + hn = -1; + if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) { + struct au_iinfo *iinfo = au_ii(dentry->d_inode); + if (iinfo) { + hn = !!au_hn(iinfo->ii_hinode + bindex); + wh = iinfo->ii_hinode[0 + bindex].hi_whdentry; + } + } + do_pri_inode(bindex, dentry->d_inode, hn, wh); + return 0; +} + +void au_dpri_dentry(struct dentry *dentry) +{ + struct au_dinfo *dinfo; + aufs_bindex_t bindex; + int err; + struct au_hdentry *hdp; + + err = do_pri_dentry(-1, dentry); + if (err || !au_test_aufs(dentry->d_sb)) + return; + + dinfo = au_di(dentry); + if (!dinfo) + return; + dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", + dinfo->di_bstart, dinfo->di_bend, + dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); + if (dinfo->di_bstart < 0) + return; + hdp = dinfo->di_hdentry; + for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) + do_pri_dentry(bindex, hdp[0 + bindex].hd_dentry); +} + +static int do_pri_file(aufs_bindex_t bindex, struct file *file) +{ + char a[32]; + + if (!file || IS_ERR(file)) { + dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); + return -1; + } + a[0] = 0; + if (bindex < 0 + && file->f_dentry + && au_test_aufs(file->f_dentry->d_sb) + && au_fi(file)) + snprintf(a, sizeof(a), ", gen %d, mmapped %d", + au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); + dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", + bindex, file->f_mode, file->f_flags, (long)file_count(file), + file->f_version, file->f_pos, a); + if (file->f_dentry) + do_pri_dentry(bindex, file->f_dentry); + return 0; +} + +void au_dpri_file(struct file *file) +{ + struct au_finfo *finfo; + struct au_fidir *fidir; + struct au_hfile *hfile; + aufs_bindex_t bindex; + int err; + + err = do_pri_file(-1, file); + if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb)) + return; + + finfo = au_fi(file); + if (!finfo) + return; + if (finfo->fi_btop < 0) + return; + fidir = finfo->fi_hdir; + if (!fidir) + do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); + else + for (bindex = finfo->fi_btop; + bindex >= 0 && bindex <= fidir->fd_bbot; + bindex++) { + hfile = fidir->fd_hfile + bindex; + do_pri_file(bindex, hfile ? hfile->hf_file : NULL); + } +} + +static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) +{ + struct vfsmount *mnt; + struct super_block *sb; + + if (!br || IS_ERR(br)) + goto out; + mnt = au_br_mnt(br); + if (!mnt || IS_ERR(mnt)) + goto out; + sb = mnt->mnt_sb; + if (!sb || IS_ERR(sb)) + goto out; + + dpri("s%d: {perm 0x%x, id %d, cnt %d, wbr %p}, " + "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " + "xino %d\n", + bindex, br->br_perm, br->br_id, atomic_read(&br->br_count), + br->br_wbr, au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), + sb->s_flags, sb->s_count, + atomic_read(&sb->s_active), !!br->br_xino.xi_file); + return 0; + +out: + dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); + return -1; +} + +void au_dpri_sb(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + aufs_bindex_t bindex; + int err; + /* to reuduce stack size */ + struct { + struct vfsmount mnt; + struct au_branch fake; + } *a; + + /* this function can be called from magic sysrq */ + a = kzalloc(sizeof(*a), GFP_ATOMIC); + if (unlikely(!a)) { + dpri("no memory\n"); + return; + } + + a->mnt.mnt_sb = sb; + a->fake.br_perm = 0; + a->fake.br_path.mnt = &a->mnt; + a->fake.br_xino.xi_file = NULL; + atomic_set(&a->fake.br_count, 0); + smp_mb(); /* atomic_set */ + err = do_pri_br(-1, &a->fake); + kfree(a); + dpri("dev 0x%x\n", sb->s_dev); + if (err || !au_test_aufs(sb)) + return; + + sbinfo = au_sbi(sb); + if (!sbinfo) + return; + dpri("nw %d, gen %u, kobj %d\n", + atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, + atomic_read(&sbinfo->si_kobj.kref.refcount)); + for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) + do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); +} + +/* ---------------------------------------------------------------------- */ + +void au_dbg_sleep_jiffy(int jiffy) +{ + while (jiffy) + jiffy = schedule_timeout_uninterruptible(jiffy); +} + +void au_dbg_iattr(struct iattr *ia) +{ +#define AuBit(name) \ + do { \ + if (ia->ia_valid & ATTR_ ## name) \ + dpri(#name "\n"); \ + } while (0) + AuBit(MODE); + AuBit(UID); + AuBit(GID); + AuBit(SIZE); + AuBit(ATIME); + AuBit(MTIME); + AuBit(CTIME); + AuBit(ATIME_SET); + AuBit(MTIME_SET); + AuBit(FORCE); + AuBit(ATTR_FLAG); + AuBit(KILL_SUID); + AuBit(KILL_SGID); + AuBit(FILE); + AuBit(KILL_PRIV); + AuBit(OPEN); + AuBit(TIMES_SET); +#undef AuBit + dpri("ia_file %p\n", ia->ia_file); +} + +/* ---------------------------------------------------------------------- */ + +void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) +{ + struct inode *h_inode, *inode = dentry->d_inode; + struct dentry *h_dentry; + aufs_bindex_t bindex, bend, bi; + + if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) + return; + + bend = au_dbend(dentry); + bi = au_ibend(inode); + if (bi < bend) + bend = bi; + bindex = au_dbstart(dentry); + bi = au_ibstart(inode); + if (bi > bindex) + bindex = bi; + + for (; bindex <= bend; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + h_inode = au_h_iptr(inode, bindex); + if (unlikely(h_inode != h_dentry->d_inode)) { + au_debug_on(); + AuDbg("b%d, %s:%d\n", bindex, func, line); + AuDbgDentry(dentry); + AuDbgInode(inode); + au_debug_off(); + BUG(); + } + } +} + +void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen) +{ + struct dentry *parent; + + parent = dget_parent(dentry); + AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); + AuDebugOn(IS_ROOT(dentry)); + AuDebugOn(au_digen_test(parent, sigen)); + dput(parent); +} + +void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen) +{ + struct dentry *parent; + struct inode *inode; + + parent = dget_parent(dentry); + inode = dentry->d_inode; + AuDebugOn(inode && S_ISDIR(dentry->d_inode->i_mode)); + AuDebugOn(au_digen_test(parent, sigen)); + dput(parent); +} + +void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) +{ + int err, i, j; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + + err = au_dpages_init(&dpages, GFP_NOFS); + AuDebugOn(err); + err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); + AuDebugOn(err); + for (i = dpages.ndpage - 1; !err && i >= 0; i--) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + for (j = dpage->ndentry - 1; !err && j >= 0; j--) + AuDebugOn(au_digen_test(dentries[j], sigen)); + } + au_dpages_free(&dpages); +} + +void au_dbg_verify_kthread(void) +{ + if (au_wkq_test()) { + au_dbg_blocked(); + /* + * It may be recursive, but udba=notify between two aufs mounts, + * where a single ro branch is shared, is not a problem. + */ + /* WARN_ON(1); */ + } +} + +/* ---------------------------------------------------------------------- */ + +void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused) +{ +#ifdef AuForceNoPlink + au_opt_clr(sbinfo->si_mntflags, PLINK); +#endif +#ifdef AuForceNoXino + au_opt_clr(sbinfo->si_mntflags, XINO); +#endif +#ifdef AuForceNoRefrof + au_opt_clr(sbinfo->si_mntflags, REFROF); +#endif +#ifdef AuForceHnotify + au_opt_set_udba(sbinfo->si_mntflags, UDBA_HNOTIFY); +#endif +#ifdef AuForceRd0 + sbinfo->si_rdblk = 0; + sbinfo->si_rdhash = 0; +#endif +} + +int __init au_debug_init(void) +{ + aufs_bindex_t bindex; + struct au_vdir_destr destr; + + bindex = -1; + AuDebugOn(bindex >= 0); + + destr.len = -1; + AuDebugOn(destr.len < NAME_MAX); + +#ifdef CONFIG_4KSTACKS + pr_warn("CONFIG_4KSTACKS is defined.\n"); +#endif + +#ifdef AuForceNoBrs + sysaufs_brs = 0; +#endif + + return 0; +} --- linux-3.13.0.orig/ubuntu/aufs/BOM.UPDATING +++ linux-3.13.0/ubuntu/aufs/BOM.UPDATING @@ -0,0 +1,80 @@ += How to update AUFS2 = + +This document covers the process for updating aufs2 within the Ubuntu +drivers directory. + +== Background == + +Upstream aufs2 is maintained in a git tree as below (which is _not_ used +when updating Ubuntu). This represents the primary upstream source tree: + + http://git.c3sl.ufpr.br/pub/scm/aufs/aufs2-2.6.git + +However this is on an http: transport and incredibly slow. It is advisable +to also add the gitorius mirror to your tree, fetching that before origin +to reduce the objects you need from the main tree: + + git://gitorious.org/aufs2/aufs2.git + +Ubuntu updates are actually taken from the aufs2-standalone tree, somewhat +similar to the compat-wireless tree. The version in this tree is based on +the mainline tree above but is modularisable, a key requirement for Ubuntu. +This tree is found at the git tree below (check the BOM for the definative +location): + + http://git.c3sl.ufpr.br/pub/scm/aufs/aufs2-standalone.git + +This tree contains a set of branches, one per upstream release. The +aufs2.1 branch represents the mainline tracking branch, with aufs-2.1-38 +representing the delta to mainline 2.6.38. Each branch contains a set +of patches which affect the core enabling the application of aufs2, plus +an open tree for the fs/aufs tree. The core patches tend to be static +from early in the line of an upstream release, and thus generally do not +need updating as often. + +== Updating the core patches == + +Ubuntu uses two of the core enablement patches, which are applied in the +order below. The remaining changes required to enable aufs are Ubuntu +specific and static: + + aufs2-base.patch + aufs2-standalone.patch + +In order to update these patches it is simplest to simply revert the +existing pair and apply these as two commit. This allows us to more +easily drop aufs in the future should that be required. + +As these core enablement patches are very slow in changing we normally +do not need to update these more than once per upstream mainline release +though sometimes changes do affect these. + +== Updating aufs2 == + +Once the enablement patches are updated we can simply use the aufs-update +script in the ubuntu/ directory to update the existing source. There are +regular updates to the aufs2 upstream and it is likely we will see updates +there more than once a month. + +Firstly checkout the upstream standalone tree (see the BOM for the +location) and checkout an appropriate branch for the release you are +updating. Then simply run the aufs-update command from within the ubuntu/ +drivers directory, supplying the location of the local aufs2-standalone tree +on the command line: + + cd ubuntu + sh aufs-update ../../aufs2-standalone + +This will result in an update commit containing the updated code and +also updating the BOM. Note that any local modifications are now lost. +Where those exist they should be cherry-picked and then squashed into +the update commit to ensure we retain them. + +== Ubuntu modifications == + +We carry a very small delta to the upstream aufs2 source. Any such changes +need to be cherry-picked from the history and squashed into any update +commit in order to prevent regression. Any current patches are listed below: + +Lucid/Maverick/Natty/Oneiric: + UBUNTU: ubuntu: AUFS -- suppress benign plink warning messages --- linux-3.13.0.orig/ubuntu/aufs/wkq.h +++ linux-3.13.0/ubuntu/aufs/wkq.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * workqueue for asynchronous/super-io operations + * todo: try new credentials management scheme + */ + +#ifndef __AUFS_WKQ_H__ +#define __AUFS_WKQ_H__ + +#ifdef __KERNEL__ + +struct super_block; + +/* ---------------------------------------------------------------------- */ + +/* + * in the next operation, wait for the 'nowait' tasks in system-wide workqueue + */ +struct au_nowait_tasks { + atomic_t nw_len; + wait_queue_head_t nw_wq; +}; + +/* ---------------------------------------------------------------------- */ + +typedef void (*au_wkq_func_t)(void *args); + +/* wkq flags */ +#define AuWkq_WAIT 1 +#define AuWkq_NEST (1 << 1) +#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) +#define au_fset_wkq(flags, name) \ + do { (flags) |= AuWkq_##name; } while (0) +#define au_fclr_wkq(flags, name) \ + do { (flags) &= ~AuWkq_##name; } while (0) + +#ifndef CONFIG_AUFS_HNOTIFY +#undef AuWkq_NEST +#define AuWkq_NEST 0 +#endif + +/* wkq.c */ +int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, + unsigned int flags); +void au_nwt_init(struct au_nowait_tasks *nwt); +int __init au_wkq_init(void); +void au_wkq_fin(void); + +/* ---------------------------------------------------------------------- */ + +static inline int au_wkq_test(void) +{ + return current->flags & PF_WQ_WORKER; +} + +static inline int au_wkq_wait(au_wkq_func_t func, void *args) +{ + return au_wkq_do_wait(AuWkq_WAIT, func, args); +} + +static inline void au_nwt_done(struct au_nowait_tasks *nwt) +{ + if (atomic_dec_and_test(&nwt->nw_len)) + wake_up_all(&nwt->nw_wq); +} + +static inline int au_nwt_flush(struct au_nowait_tasks *nwt) +{ + wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); + return 0; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WKQ_H__ */ --- linux-3.13.0.orig/ubuntu/aufs/magic.mk +++ linux-3.13.0/ubuntu/aufs/magic.mk @@ -0,0 +1,54 @@ + +# defined in ${srctree}/fs/fuse/inode.c +# tristate +ifdef CONFIG_FUSE_FS +ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 +endif + +# defined in ${srctree}/fs/ocfs2/ocfs2_fs.h +# tristate +ifdef CONFIG_OCFS2_FS +ccflags-y += -DOCFS2_SUPER_MAGIC=0x7461636f +endif + +# defined in ${srctree}/fs/ocfs2/dlm/userdlm.h +# tristate +ifdef CONFIG_OCFS2_FS_O2CB +ccflags-y += -DDLMFS_MAGIC=0x76a9f425 +endif + +# defined in ${srctree}/fs/cifs/cifsfs.c +# tristate +ifdef CONFIG_CIFS_FS +ccflags-y += -DCIFS_MAGIC_NUMBER=0xFF534D42 +endif + +# defined in ${srctree}/fs/xfs/xfs_sb.h +# tristate +ifdef CONFIG_XFS_FS +ccflags-y += -DXFS_SB_MAGIC=0x58465342 +endif + +# defined in ${srctree}/fs/configfs/mount.c +# tristate +ifdef CONFIG_CONFIGFS_FS +ccflags-y += -DCONFIGFS_MAGIC=0x62656570 +endif + +# defined in ${srctree}/fs/9p/v9fs.h +# tristate +ifdef CONFIG_9P_FS +ccflags-y += -DV9FS_MAGIC=0x01021997 +endif + +# defined in ${srctree}/fs/ubifs/ubifs.h +# tristate +ifdef CONFIG_UBIFS_FS +ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 +endif + +# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h +# tristate +ifdef CONFIG_HFSPLUS_FS +ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b +endif --- linux-3.13.0.orig/ubuntu/include/README +++ linux-3.13.0/ubuntu/include/README @@ -0,0 +1,4 @@ +Only use this directory for things which need to share their headers with +other parts of the kernel or other modules in ubuntu/ + +Otherwise, keep them local to the module directory. --- linux-3.13.0.orig/ubuntu/include/Kbuild +++ linux-3.13.0/ubuntu/include/Kbuild @@ -0,0 +1 @@ +header-y += uapi/ --- linux-3.13.0.orig/ubuntu/include/uapi/Kbuild +++ linux-3.13.0/ubuntu/include/uapi/Kbuild @@ -0,0 +1 @@ +header-y += linux/ --- linux-3.13.0.orig/ubuntu/include/uapi/linux/Kbuild +++ linux-3.13.0/ubuntu/include/uapi/linux/Kbuild @@ -0,0 +1 @@ +header-y = aufs_type.h --- linux-3.13.0.orig/ubuntu/include/uapi/linux/aufs_type.h +++ linux-3.13.0/ubuntu/include/uapi/linux/aufs_type.h @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __AUFS_TYPE_H__ +#define __AUFS_TYPE_H__ + +#define AUFS_NAME "aufs" + +#ifdef __KERNEL__ +/* + * define it before including all other headers. + * sched.h may use pr_* macros before defining "current", so define the + * no-current version first, and re-define later. + */ +#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ +#include +#undef pr_fmt +#define pr_fmt(fmt) \ + AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ + (int)sizeof(current->comm), current->comm, current->pid +#else +#include +#include +#endif /* __KERNEL__ */ + +#include + +#define AUFS_VERSION "3.13-20140303" + +/* todo? move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_BRANCH_MAX_127 +typedef int8_t aufs_bindex_t; +#define AUFS_BRANCH_MAX 127 +#else +typedef int16_t aufs_bindex_t; +#ifdef CONFIG_AUFS_BRANCH_MAX_511 +#define AUFS_BRANCH_MAX 511 +#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) +#define AUFS_BRANCH_MAX 1023 +#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) +#define AUFS_BRANCH_MAX 32767 +#endif +#endif + +#ifdef __KERNEL__ +#ifndef AUFS_BRANCH_MAX +#error unknown CONFIG_AUFS_BRANCH_MAX value +#endif +#endif /* __KERNEL__ */ + +/* ---------------------------------------------------------------------- */ + +#define AUFS_FSTYPE AUFS_NAME + +#define AUFS_ROOT_INO 2 +#define AUFS_FIRST_INO 11 + +#define AUFS_WH_PFX ".wh." +#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) +#define AUFS_WH_TMP_LEN 4 +/* a limit for rmdir/rename a dir and copyup */ +#define AUFS_MAX_NAMELEN (NAME_MAX \ + - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ + - 1 /* dot */\ + - AUFS_WH_TMP_LEN) /* hex */ +#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" +#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME +#define AUFS_XINO_DEF_SEC 30 /* seconds */ +#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ +#define AUFS_DIRWH_DEF 3 +#define AUFS_RDCACHE_DEF 10 /* seconds */ +#define AUFS_RDCACHE_MAX 3600 /* seconds */ +#define AUFS_RDBLK_DEF 512 /* bytes */ +#define AUFS_RDHASH_DEF 32 +#define AUFS_WKQ_NAME AUFS_NAME "d" +#define AUFS_MFS_DEF_SEC 30 /* seconds */ +#define AUFS_MFS_MAX_SEC 3600 /* seconds */ +#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ + +/* pseudo-link maintenace under /proc */ +#define AUFS_PLINK_MAINT_NAME "plink_maint" +#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME +#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME + +#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ +#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME + +#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME +#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" +#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" + +/* doubly whiteouted */ +#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME +#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME +#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME + +/* branch permissions and attributes */ +#define AUFS_BRPERM_RW "rw" +#define AUFS_BRPERM_RO "ro" +#define AUFS_BRPERM_RR "rr" +#define AUFS_BRRATTR_WH "wh" +#define AUFS_BRWATTR_NLWH "nolwh" +#define AUFS_BRATTR_UNPIN "unpin" + +/* ---------------------------------------------------------------------- */ + +/* ioctl */ +enum { + /* readdir in userspace */ + AuCtl_RDU, + AuCtl_RDU_INO, + + /* pathconf wrapper */ + AuCtl_WBR_FD, + + /* busy inode */ + AuCtl_IBUSY, + + /* move-down */ + AuCtl_MVDOWN +}; + +/* borrowed from linux/include/linux/kernel.h */ +#ifndef ALIGN +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) +#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) +#endif + +/* borrowed from linux/include/linux/compiler-gcc3.h */ +#ifndef __aligned +#define __aligned(x) __attribute__((aligned(x))) +#endif + +#ifdef __KERNEL__ +#ifndef __packed +#define __packed __attribute__((packed)) +#endif +#endif + +struct au_rdu_cookie { + uint64_t h_pos; + int16_t bindex; + uint8_t flags; + uint8_t pad; + uint32_t generation; +} __aligned(8); + +struct au_rdu_ent { + uint64_t ino; + int16_t bindex; + uint8_t type; + uint8_t nlen; + uint8_t wh; + char name[0]; +} __aligned(8); + +static inline int au_rdu_len(int nlen) +{ + /* include the terminating NULL */ + return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, + sizeof(uint64_t)); +} + +union au_rdu_ent_ul { + struct au_rdu_ent __user *e; + uint64_t ul; +}; + +enum { + AufsCtlRduV_SZ, + AufsCtlRduV_End +}; + +struct aufs_rdu { + /* input */ + union { + uint64_t sz; /* AuCtl_RDU */ + uint64_t nent; /* AuCtl_RDU_INO */ + }; + union au_rdu_ent_ul ent; + uint16_t verify[AufsCtlRduV_End]; + + /* input/output */ + uint32_t blk; + + /* output */ + union au_rdu_ent_ul tail; + /* number of entries which were added in a single call */ + uint64_t rent; + uint8_t full; + uint8_t shwh; + + struct au_rdu_cookie cookie; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +struct aufs_wbr_fd { + uint32_t oflags; + int16_t brid; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +struct aufs_ibusy { + uint64_t ino, h_ino; + int16_t bindex; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +/* error code for move-down */ +/* the actual message strings are implemented in aufs-util.git */ +enum { + EAU_MVDOWN_OPAQUE = 1, + EAU_MVDOWN_WHITEOUT, + EAU_MVDOWN_UPPER, + EAU_MVDOWN_BOTTOM, + EAU_MVDOWN_NOUPPER, + EAU_MVDOWN_NOLOWERBR, + EAU_Last +}; + +/* flags for move-down */ +#define AUFS_MVDOWN_DMSG 1 +#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ +#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ +#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ +#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ +#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ +#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ +#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ +#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ +/* will be added more */ + +enum { + AUFS_MVDOWN_UPPER, + AUFS_MVDOWN_LOWER, + AUFS_MVDOWN_NARRAY +}; + +struct aufs_mvdown { + uint32_t flags; + struct { + int16_t bindex; + int16_t brid; + } a[AUFS_MVDOWN_NARRAY]; + int8_t au_errno; + /* will be added more */ +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +#define AuCtlType 'A' +#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) +#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) +#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ + struct aufs_wbr_fd) +#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) +#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ + struct aufs_mvdown) + +#endif /* __AUFS_TYPE_H__ */ --- linux-3.13.0.orig/ubuntu/i915/i915_dma.c +++ linux-3.13.0/ubuntu/i915/i915_dma.c @@ -0,0 +1,1934 @@ +/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- + */ +/* + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include "intel_drv.h" +#include +#include "i915_drv.h" +#include "i915_trace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS]) + +#define BEGIN_LP_RING(n) \ + intel_ring_begin(LP_RING(dev_priv), (n)) + +#define OUT_RING(x) \ + intel_ring_emit(LP_RING(dev_priv), x) + +#define ADVANCE_LP_RING() \ + __intel_ring_advance(LP_RING(dev_priv)) + +/** + * Lock test for when it's just for synchronization of ring access. + * + * In that case, we don't need to do it when GEM is initialized as nobody else + * has access to the ring. + */ +#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \ + if (LP_RING(dev->dev_private)->obj == NULL) \ + LOCK_TEST_WITH_RETURN(dev, file); \ +} while (0) + +static inline u32 +intel_read_legacy_status_page(struct drm_i915_private *dev_priv, int reg) +{ + if (I915_NEED_GFX_HWS(dev_priv->dev)) + return ioread32(dev_priv->dri1.gfx_hws_cpu_addr + reg); + else + return intel_read_status_page(LP_RING(dev_priv), reg); +} + +#define READ_HWSP(dev_priv, reg) intel_read_legacy_status_page(dev_priv, reg) +#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) +#define I915_BREADCRUMB_INDEX 0x21 + +void i915_update_dri1_breadcrumb(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv; + + /* + * The dri breadcrumb update races against the drm master disappearing. + * Instead of trying to fix this (this is by far not the only ums issue) + * just don't do the update in kms mode. + */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + } +} + +static void i915_write_hws_pga(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 addr; + + addr = dev_priv->status_page_dmah->busaddr; + if (INTEL_INFO(dev)->gen >= 4) + addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; + I915_WRITE(HWS_PGA, addr); +} + +/** + * Frees the hardware status page, whether it's a physical address or a virtual + * address set up by the X Server. + */ +static void i915_free_hws(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = LP_RING(dev_priv); + + if (dev_priv->status_page_dmah) { + drm_pci_free(dev, dev_priv->status_page_dmah); + dev_priv->status_page_dmah = NULL; + } + + if (ring->status_page.gfx_addr) { + ring->status_page.gfx_addr = 0; + iounmap(dev_priv->dri1.gfx_hws_cpu_addr); + } + + /* Need to rewrite hardware status page */ + I915_WRITE(HWS_PGA, 0x1ffff000); +} + +void i915_kernel_lost_context(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv; + struct intel_ring_buffer *ring = LP_RING(dev_priv); + + /* + * We should never lose context on the ring with modesetting + * as we don't expose it to userspace + */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; + ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; + ring->space = ring->head - (ring->tail + I915_RING_FREE_SPACE); + if (ring->space < 0) + ring->space += ring->size; + + if (!dev->primary->master) + return; + + master_priv = dev->primary->master->driver_priv; + if (ring->head == ring->tail && master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; +} + +static int i915_dma_cleanup(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int i; + + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if (dev->irq_enabled) + drm_irq_uninstall(dev); + + mutex_lock(&dev->struct_mutex); + for (i = 0; i < I915_NUM_RINGS; i++) + intel_cleanup_ring_buffer(&dev_priv->ring[i]); + mutex_unlock(&dev->struct_mutex); + + /* Clear the HWS virtual address at teardown */ + if (I915_NEED_GFX_HWS(dev)) + i915_free_hws(dev); + + return 0; +} + +static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + int ret; + + master_priv->sarea = drm_getsarea(dev); + if (master_priv->sarea) { + master_priv->sarea_priv = (drm_i915_sarea_t *) + ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset); + } else { + DRM_DEBUG_DRIVER("sarea not found assuming DRI2 userspace\n"); + } + + if (init->ring_size != 0) { + if (LP_RING(dev_priv)->obj != NULL) { + i915_dma_cleanup(dev); + DRM_ERROR("Client tried to initialize ringbuffer in " + "GEM mode\n"); + return -EINVAL; + } + + ret = intel_render_ring_init_dri(dev, + init->ring_start, + init->ring_size); + if (ret) { + i915_dma_cleanup(dev); + return ret; + } + } + + dev_priv->dri1.cpp = init->cpp; + dev_priv->dri1.back_offset = init->back_offset; + dev_priv->dri1.front_offset = init->front_offset; + dev_priv->dri1.current_page = 0; + if (master_priv->sarea_priv) + master_priv->sarea_priv->pf_current_page = 0; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->dri1.allow_batchbuffer = 1; + + return 0; +} + +static int i915_dma_resume(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct intel_ring_buffer *ring = LP_RING(dev_priv); + + DRM_DEBUG_DRIVER("%s\n", __func__); + + if (ring->virtual_start == NULL) { + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; + } + + /* Program Hardware Status Page */ + if (!ring->status_page.page_addr) { + DRM_ERROR("Can not find hardware status page\n"); + return -EINVAL; + } + DRM_DEBUG_DRIVER("hw status page @ %p\n", + ring->status_page.page_addr); + if (ring->status_page.gfx_addr != 0) + intel_ring_setup_status_page(ring); + else + i915_write_hws_pga(dev); + + DRM_DEBUG_DRIVER("Enabled hardware status page\n"); + + return 0; +} + +static int i915_dma_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_init_t *init = data; + int retcode = 0; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + switch (init->func) { + case I915_INIT_DMA: + retcode = i915_initialize(dev, init); + break; + case I915_CLEANUP_DMA: + retcode = i915_dma_cleanup(dev); + break; + case I915_RESUME_DMA: + retcode = i915_dma_resume(dev); + break; + default: + retcode = -EINVAL; + break; + } + + return retcode; +} + +/* Implement basically the same security restrictions as hardware does + * for MI_BATCH_NON_SECURE. These can be made stricter at any time. + * + * Most of the calculations below involve calculating the size of a + * particular instruction. It's important to get the size right as + * that tells us where the next instruction to check is. Any illegal + * instruction detected will be given a size of zero, which is a + * signal to abort the rest of the buffer. + */ +static int validate_cmd(int cmd) +{ + switch (((cmd >> 29) & 0x7)) { + case 0x0: + switch ((cmd >> 23) & 0x3f) { + case 0x0: + return 1; /* MI_NOOP */ + case 0x4: + return 1; /* MI_FLUSH */ + default: + return 0; /* disallow everything else */ + } + break; + case 0x1: + return 0; /* reserved */ + case 0x2: + return (cmd & 0xff) + 2; /* 2d commands */ + case 0x3: + if (((cmd >> 24) & 0x1f) <= 0x18) + return 1; + + switch ((cmd >> 24) & 0x1f) { + case 0x1c: + return 1; + case 0x1d: + switch ((cmd >> 16) & 0xff) { + case 0x3: + return (cmd & 0x1f) + 2; + case 0x4: + return (cmd & 0xf) + 2; + default: + return (cmd & 0xffff) + 2; + } + case 0x1e: + if (cmd & (1 << 23)) + return (cmd & 0xffff) + 1; + else + return 1; + case 0x1f: + if ((cmd & (1 << 23)) == 0) /* inline vertices */ + return (cmd & 0x1ffff) + 2; + else if (cmd & (1 << 17)) /* indirect random */ + if ((cmd & 0xffff) == 0) + return 0; /* unknown length, too hard */ + else + return (((cmd & 0xffff) + 1) / 2) + 1; + else + return 2; /* indirect sequential */ + default: + return 0; + } + default: + return 0; + } + + return 0; +} + +static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int i, ret; + + if ((dwords+1) * sizeof(int) >= LP_RING(dev_priv)->size - 8) + return -EINVAL; + + for (i = 0; i < dwords;) { + int sz = validate_cmd(buffer[i]); + if (sz == 0 || i + sz > dwords) + return -EINVAL; + i += sz; + } + + ret = BEGIN_LP_RING((dwords+1)&~1); + if (ret) + return ret; + + for (i = 0; i < dwords; i++) + OUT_RING(buffer[i]); + if (dwords & 1) + OUT_RING(0); + + ADVANCE_LP_RING(); + + return 0; +} + +int +i915_emit_box(struct drm_device *dev, + struct drm_clip_rect *box, + int DR1, int DR4) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (box->y2 <= box->y1 || box->x2 <= box->x1 || + box->y2 <= 0 || box->x2 <= 0) { + DRM_ERROR("Bad box %d,%d..%d,%d\n", + box->x1, box->y1, box->x2, box->y2); + return -EINVAL; + } + + if (INTEL_INFO(dev)->gen >= 4) { + ret = BEGIN_LP_RING(4); + if (ret) + return ret; + + OUT_RING(GFX_OP_DRAWRECT_INFO_I965); + OUT_RING((box->x1 & 0xffff) | (box->y1 << 16)); + OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16)); + OUT_RING(DR4); + } else { + ret = BEGIN_LP_RING(6); + if (ret) + return ret; + + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(DR1); + OUT_RING((box->x1 & 0xffff) | (box->y1 << 16)); + OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16)); + OUT_RING(DR4); + OUT_RING(0); + } + ADVANCE_LP_RING(); + + return 0; +} + +/* XXX: Emitting the counter should really be moved to part of the IRQ + * emit. For now, do it in both places: + */ + +static void i915_emit_breadcrumb(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + + dev_priv->dri1.counter++; + if (dev_priv->dri1.counter > 0x7FFFFFFFUL) + dev_priv->dri1.counter = 0; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_enqueue = dev_priv->dri1.counter; + + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(dev_priv->dri1.counter); + OUT_RING(0); + ADVANCE_LP_RING(); + } +} + +static int i915_dispatch_cmdbuffer(struct drm_device * dev, + drm_i915_cmdbuffer_t *cmd, + struct drm_clip_rect *cliprects, + void *cmdbuf) +{ + int nbox = cmd->num_cliprects; + int i = 0, count, ret; + + if (cmd->sz & 0x3) { + DRM_ERROR("alignment"); + return -EINVAL; + } + + i915_kernel_lost_context(dev); + + count = nbox ? nbox : 1; + + for (i = 0; i < count; i++) { + if (i < nbox) { + ret = i915_emit_box(dev, &cliprects[i], + cmd->DR1, cmd->DR4); + if (ret) + return ret; + } + + ret = i915_emit_cmds(dev, cmdbuf, cmd->sz / 4); + if (ret) + return ret; + } + + i915_emit_breadcrumb(dev); + return 0; +} + +static int i915_dispatch_batchbuffer(struct drm_device * dev, + drm_i915_batchbuffer_t * batch, + struct drm_clip_rect *cliprects) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int nbox = batch->num_cliprects; + int i, count, ret; + + if ((batch->start | batch->used) & 0x7) { + DRM_ERROR("alignment"); + return -EINVAL; + } + + i915_kernel_lost_context(dev); + + count = nbox ? nbox : 1; + for (i = 0; i < count; i++) { + if (i < nbox) { + ret = i915_emit_box(dev, &cliprects[i], + batch->DR1, batch->DR4); + if (ret) + return ret; + } + + if (!IS_I830(dev) && !IS_845G(dev)) { + ret = BEGIN_LP_RING(2); + if (ret) + return ret; + + if (INTEL_INFO(dev)->gen >= 4) { + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); + OUT_RING(batch->start); + } else { + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + } + } else { + ret = BEGIN_LP_RING(4); + if (ret) + return ret; + + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + OUT_RING(batch->start + batch->used - 4); + OUT_RING(0); + } + ADVANCE_LP_RING(); + } + + + if (IS_G4X(dev) || IS_GEN5(dev)) { + if (BEGIN_LP_RING(2) == 0) { + OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + } + + i915_emit_breadcrumb(dev); + return 0; +} + +static int i915_dispatch_flip(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = + dev->primary->master->driver_priv; + int ret; + + if (!master_priv->sarea_priv) + return -EINVAL; + + DRM_DEBUG_DRIVER("%s: page=%d pfCurrentPage=%d\n", + __func__, + dev_priv->dri1.current_page, + master_priv->sarea_priv->pf_current_page); + + i915_kernel_lost_context(dev); + + ret = BEGIN_LP_RING(10); + if (ret) + return ret; + + OUT_RING(MI_FLUSH | MI_READ_FLUSH); + OUT_RING(0); + + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); + OUT_RING(0); + if (dev_priv->dri1.current_page == 0) { + OUT_RING(dev_priv->dri1.back_offset); + dev_priv->dri1.current_page = 1; + } else { + OUT_RING(dev_priv->dri1.front_offset); + dev_priv->dri1.current_page = 0; + } + OUT_RING(0); + + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); + OUT_RING(0); + + ADVANCE_LP_RING(); + + master_priv->sarea_priv->last_enqueue = dev_priv->dri1.counter++; + + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(dev_priv->dri1.counter); + OUT_RING(0); + ADVANCE_LP_RING(); + } + + master_priv->sarea_priv->pf_current_page = dev_priv->dri1.current_page; + return 0; +} + +static int i915_quiescent(struct drm_device *dev) +{ + i915_kernel_lost_context(dev); + return intel_ring_idle(LP_RING(dev->dev_private)); +} + +static int i915_flush_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + int ret; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + + mutex_lock(&dev->struct_mutex); + ret = i915_quiescent(dev); + mutex_unlock(&dev->struct_mutex); + + return ret; +} + +static int i915_batchbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + master_priv->sarea_priv; + drm_i915_batchbuffer_t *batch = data; + int ret; + struct drm_clip_rect *cliprects = NULL; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!dev_priv->dri1.allow_batchbuffer) { + DRM_ERROR("Batchbuffer ioctl disabled\n"); + return -EINVAL; + } + + DRM_DEBUG_DRIVER("i915 batchbuffer, start %x used %d cliprects %d\n", + batch->start, batch->used, batch->num_cliprects); + + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + + if (batch->num_cliprects < 0) + return -EINVAL; + + if (batch->num_cliprects) { + cliprects = kcalloc(batch->num_cliprects, + sizeof(*cliprects), + GFP_KERNEL); + if (cliprects == NULL) + return -ENOMEM; + + ret = copy_from_user(cliprects, batch->cliprects, + batch->num_cliprects * + sizeof(struct drm_clip_rect)); + if (ret != 0) { + ret = -EFAULT; + goto fail_free; + } + } + + mutex_lock(&dev->struct_mutex); + ret = i915_dispatch_batchbuffer(dev, batch, cliprects); + mutex_unlock(&dev->struct_mutex); + + if (sarea_priv) + sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + +fail_free: + kfree(cliprects); + + return ret; +} + +static int i915_cmdbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + master_priv->sarea_priv; + drm_i915_cmdbuffer_t *cmdbuf = data; + struct drm_clip_rect *cliprects = NULL; + void *batch_data; + int ret; + + DRM_DEBUG_DRIVER("i915 cmdbuffer, buf %p sz %d cliprects %d\n", + cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + + if (cmdbuf->num_cliprects < 0) + return -EINVAL; + + batch_data = kmalloc(cmdbuf->sz, GFP_KERNEL); + if (batch_data == NULL) + return -ENOMEM; + + ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz); + if (ret != 0) { + ret = -EFAULT; + goto fail_batch_free; + } + + if (cmdbuf->num_cliprects) { + cliprects = kcalloc(cmdbuf->num_cliprects, + sizeof(*cliprects), GFP_KERNEL); + if (cliprects == NULL) { + ret = -ENOMEM; + goto fail_batch_free; + } + + ret = copy_from_user(cliprects, cmdbuf->cliprects, + cmdbuf->num_cliprects * + sizeof(struct drm_clip_rect)); + if (ret != 0) { + ret = -EFAULT; + goto fail_clip_free; + } + } + + mutex_lock(&dev->struct_mutex); + ret = i915_dispatch_cmdbuffer(dev, cmdbuf, cliprects, batch_data); + mutex_unlock(&dev->struct_mutex); + if (ret) { + DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); + goto fail_clip_free; + } + + if (sarea_priv) + sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + +fail_clip_free: + kfree(cliprects); +fail_batch_free: + kfree(batch_data); + + return ret; +} + +static int i915_emit_irq(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + + i915_kernel_lost_context(dev); + + DRM_DEBUG_DRIVER("\n"); + + dev_priv->dri1.counter++; + if (dev_priv->dri1.counter > 0x7FFFFFFFUL) + dev_priv->dri1.counter = 1; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_enqueue = dev_priv->dri1.counter; + + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(dev_priv->dri1.counter); + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + } + + return dev_priv->dri1.counter; +} + +static int i915_wait_irq(struct drm_device * dev, int irq_nr) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + int ret = 0; + struct intel_ring_buffer *ring = LP_RING(dev_priv); + + DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr, + READ_BREADCRUMB(dev_priv)); + + if (READ_BREADCRUMB(dev_priv) >= irq_nr) { + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + return 0; + } + + if (master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + + if (ring->irq_get(ring)) { + DRM_WAIT_ON(ret, ring->irq_queue, 3 * HZ, + READ_BREADCRUMB(dev_priv) >= irq_nr); + ring->irq_put(ring); + } else if (wait_for(READ_BREADCRUMB(dev_priv) >= irq_nr, 3000)) + ret = -EBUSY; + + if (ret == -EBUSY) { + DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", + READ_BREADCRUMB(dev_priv), (int)dev_priv->dri1.counter); + } + + return ret; +} + +/* Needs the lock as it touches the ring. + */ +static int i915_irq_emit(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_emit_t *emit = data; + int result; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!dev_priv || !LP_RING(dev_priv)->virtual_start) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + + mutex_lock(&dev->struct_mutex); + result = i915_emit_irq(dev); + mutex_unlock(&dev->struct_mutex); + + if (copy_to_user(emit->irq_seq, &result, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return -EFAULT; + } + + return 0; +} + +/* Doesn't need the hardware lock. + */ +static int i915_irq_wait(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_wait_t *irqwait = data; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + return i915_wait_irq(dev, irqwait->irq_seq); +} + +static int i915_vblank_pipe_get(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_pipe_t *pipe = data; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; + + return 0; +} + +/** + * Schedule buffer swap at given vertical blank. + */ +static int i915_vblank_swap(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + /* The delayed swap mechanism was fundamentally racy, and has been + * removed. The model was that the client requested a delayed flip/swap + * from the kernel, then waited for vblank before continuing to perform + * rendering. The problem was that the kernel might wake the client + * up before it dispatched the vblank swap (since the lock has to be + * held while touching the ringbuffer), in which case the client would + * clear and start the next frame before the swap occurred, and + * flicker would occur in addition to likely missing the vblank. + * + * In the absence of this ioctl, userland falls back to a correct path + * of waiting for a vblank, then dispatching the swap on its own. + * Context switching to userland and back is plenty fast enough for + * meeting the requirements of vblank swapping. + */ + return -EINVAL; +} + +static int i915_flip_bufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + int ret; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + DRM_DEBUG_DRIVER("%s\n", __func__); + + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + + mutex_lock(&dev->struct_mutex); + ret = i915_dispatch_flip(dev); + mutex_unlock(&dev->struct_mutex); + + return ret; +} + +static int i915_getparam(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_getparam_t *param = data; + int value; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + switch (param->param) { + case I915_PARAM_IRQ_ACTIVE: + value = dev->pdev->irq ? 1 : 0; + break; + case I915_PARAM_ALLOW_BATCHBUFFER: + value = dev_priv->dri1.allow_batchbuffer ? 1 : 0; + break; + case I915_PARAM_LAST_DISPATCH: + value = READ_BREADCRUMB(dev_priv); + break; + case I915_PARAM_CHIPSET_ID: + value = dev->pdev->device; + break; + case I915_PARAM_HAS_GEM: + value = 1; + break; + case I915_PARAM_NUM_FENCES_AVAIL: + value = dev_priv->num_fence_regs - dev_priv->fence_reg_start; + break; + case I915_PARAM_HAS_OVERLAY: + value = dev_priv->overlay ? 1 : 0; + break; + case I915_PARAM_HAS_PAGEFLIPPING: + value = 1; + break; + case I915_PARAM_HAS_EXECBUF2: + /* depends on GEM */ + value = 1; + break; + case I915_PARAM_HAS_BSD: + value = intel_ring_initialized(&dev_priv->ring[VCS]); + break; + case I915_PARAM_HAS_BLT: + value = intel_ring_initialized(&dev_priv->ring[BCS]); + break; + case I915_PARAM_HAS_VEBOX: + value = intel_ring_initialized(&dev_priv->ring[VECS]); + break; + case I915_PARAM_HAS_RELAXED_FENCING: + value = 1; + break; + case I915_PARAM_HAS_COHERENT_RINGS: + value = 1; + break; + case I915_PARAM_HAS_EXEC_CONSTANTS: + value = INTEL_INFO(dev)->gen >= 4; + break; + case I915_PARAM_HAS_RELAXED_DELTA: + value = 1; + break; + case I915_PARAM_HAS_GEN7_SOL_RESET: + value = 1; + break; + case I915_PARAM_HAS_LLC: + value = HAS_LLC(dev); + break; + case I915_PARAM_HAS_WT: + value = HAS_WT(dev); + break; + case I915_PARAM_HAS_ALIASING_PPGTT: + value = dev_priv->mm.aliasing_ppgtt ? 1 : 0; + break; + case I915_PARAM_HAS_WAIT_TIMEOUT: + value = 1; + break; + case I915_PARAM_HAS_SEMAPHORES: + value = i915_semaphore_is_enabled(dev); + break; + case I915_PARAM_HAS_PRIME_VMAP_FLUSH: + value = 1; + break; + case I915_PARAM_HAS_SECURE_BATCHES: + value = capable(CAP_SYS_ADMIN); + break; + case I915_PARAM_HAS_PINNED_BATCHES: + value = 1; + break; + case I915_PARAM_HAS_EXEC_NO_RELOC: + value = 1; + break; + case I915_PARAM_HAS_EXEC_HANDLE_LUT: + value = 1; + break; + default: + DRM_DEBUG("Unknown parameter %d\n", param->param); + return -EINVAL; + } + + if (copy_to_user(param->value, &value, sizeof(int))) { + DRM_ERROR("copy_to_user failed\n"); + return -EFAULT; + } + + return 0; +} + +static int i915_setparam(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_setparam_t *param = data; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + switch (param->param) { + case I915_SETPARAM_USE_MI_BATCHBUFFER_START: + break; + case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: + break; + case I915_SETPARAM_ALLOW_BATCHBUFFER: + dev_priv->dri1.allow_batchbuffer = param->value ? 1 : 0; + break; + case I915_SETPARAM_NUM_USED_FENCES: + if (param->value > dev_priv->num_fence_regs || + param->value < 0) + return -EINVAL; + /* Userspace can use first N regs */ + dev_priv->fence_reg_start = param->value; + break; + default: + DRM_DEBUG_DRIVER("unknown parameter %d\n", + param->param); + return -EINVAL; + } + + return 0; +} + +static int i915_set_status_page(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_hws_addr_t *hws = data; + struct intel_ring_buffer *ring; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!I915_NEED_GFX_HWS(dev)) + return -EINVAL; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + WARN(1, "tried to set status page when mode setting active\n"); + return 0; + } + + DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr); + + ring = LP_RING(dev_priv); + ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12); + + dev_priv->dri1.gfx_hws_cpu_addr = + ioremap_wc(dev_priv->gtt.mappable_base + hws->addr, 4096); + if (dev_priv->dri1.gfx_hws_cpu_addr == NULL) { + i915_dma_cleanup(dev); + ring->status_page.gfx_addr = 0; + DRM_ERROR("can not ioremap virtual address for" + " G33 hw status page\n"); + return -ENOMEM; + } + + memset_io(dev_priv->dri1.gfx_hws_cpu_addr, 0, PAGE_SIZE); + I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); + + DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", + ring->status_page.gfx_addr); + DRM_DEBUG_DRIVER("load hws at %p\n", + ring->status_page.page_addr); + return 0; +} + +static int i915_get_bridge_dev(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); + if (!dev_priv->bridge_dev) { + DRM_ERROR("bridge device not found\n"); + return -1; + } + return 0; +} + +#define MCHBAR_I915 0x44 +#define MCHBAR_I965 0x48 +#define MCHBAR_SIZE (4*4096) + +#define DEVEN_REG 0x54 +#define DEVEN_MCHBAR_EN (1 << 28) + +/* Allocate space for the MCH regs if needed, return nonzero on error */ +static int +intel_alloc_mchbar_resource(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; + u32 temp_lo, temp_hi = 0; + u64 mchbar_addr; + int ret; + + if (INTEL_INFO(dev)->gen >= 4) + pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi); + pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo); + mchbar_addr = ((u64)temp_hi << 32) | temp_lo; + + /* If ACPI doesn't have it, assume we need to allocate it ourselves */ +#ifdef CONFIG_PNP + if (mchbar_addr && + pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) + return 0; +#endif + + /* Get some space for it */ + dev_priv->mch_res.name = "i915 MCHBAR"; + dev_priv->mch_res.flags = IORESOURCE_MEM; + ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, + &dev_priv->mch_res, + MCHBAR_SIZE, MCHBAR_SIZE, + PCIBIOS_MIN_MEM, + 0, pcibios_align_resource, + dev_priv->bridge_dev); + if (ret) { + DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret); + dev_priv->mch_res.start = 0; + return ret; + } + + if (INTEL_INFO(dev)->gen >= 4) + pci_write_config_dword(dev_priv->bridge_dev, reg + 4, + upper_32_bits(dev_priv->mch_res.start)); + + pci_write_config_dword(dev_priv->bridge_dev, reg, + lower_32_bits(dev_priv->mch_res.start)); + return 0; +} + +/* Setup MCHBAR if possible, return true if we should disable it again */ +static void +intel_setup_mchbar(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; + u32 temp; + bool enabled; + + dev_priv->mchbar_need_disable = false; + + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp); + enabled = !!(temp & DEVEN_MCHBAR_EN); + } else { + pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp); + enabled = temp & 1; + } + + /* If it's already enabled, don't have to do anything */ + if (enabled) + return; + + if (intel_alloc_mchbar_resource(dev)) + return; + + dev_priv->mchbar_need_disable = true; + + /* Space is allocated or reserved, so enable it. */ + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, + temp | DEVEN_MCHBAR_EN); + } else { + pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp); + pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1); + } +} + +static void +intel_teardown_mchbar(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; + u32 temp; + + if (dev_priv->mchbar_need_disable) { + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp); + temp &= ~DEVEN_MCHBAR_EN; + pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp); + } else { + pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp); + temp &= ~1; + pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp); + } + } + + if (dev_priv->mch_res.start) + release_resource(&dev_priv->mch_res); +} + +/* true = enable decode, false = disable decoder */ +static unsigned int i915_vga_set_decode(void *cookie, bool state) +{ + struct drm_device *dev = cookie; + + intel_modeset_vga_set_state(dev, state); + if (state) + return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | + VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; + else + return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; +} + +static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; + if (state == VGA_SWITCHEROO_ON) { + pr_info("switched on\n"); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + /* i915 resume handler doesn't set to D0 */ + pci_set_power_state(dev->pdev, PCI_D0); + i915_resume(dev); + dev->switch_power_state = DRM_SWITCH_POWER_ON; + } else { + pr_err("switched off\n"); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + i915_suspend(dev, pmm); + dev->switch_power_state = DRM_SWITCH_POWER_OFF; + } +} + +static bool i915_switcheroo_can_switch(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + bool can_switch; + + spin_lock(&dev->count_lock); + can_switch = (dev->open_count == 0); + spin_unlock(&dev->count_lock); + return can_switch; +} + +static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { + .set_gpu_state = i915_switcheroo_set_state, + .reprobe = NULL, + .can_switch = i915_switcheroo_can_switch, +}; + +static int i915_load_modeset_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = intel_parse_bios(dev); + if (ret) + DRM_INFO("failed to find VBIOS tables\n"); + + /* If we have > 1 VGA cards, then we need to arbitrate access + * to the common VGA resources. + * + * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA), + * then we do not take part in VGA arbitration and the + * vga_client_register() fails with -ENODEV. + */ + ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode); + if (ret && ret != -ENODEV) + goto out; + + intel_register_dsm_handler(); + + ret = vga_switcheroo_register_client(dev->pdev, &i915_switcheroo_ops, false); + if (ret) + goto cleanup_vga_client; + + /* Initialise stolen first so that we may reserve preallocated + * objects for the BIOS to KMS transition. + */ + ret = i915_gem_init_stolen(dev); + if (ret) + goto cleanup_vga_switcheroo; + + ret = drm_irq_install(dev); + if (ret) + goto cleanup_gem_stolen; + + intel_power_domains_init_hw(dev); + + /* Important: The output setup functions called by modeset_init need + * working irqs for e.g. gmbus and dp aux transfers. */ + intel_modeset_init(dev); + + ret = i915_gem_init(dev); + if (ret) + goto cleanup_power; + + INIT_WORK(&dev_priv->console_resume_work, intel_console_resume); + + intel_modeset_gem_init(dev); + + /* Always safe in the mode setting case. */ + /* FIXME: do pre/post-mode set stuff in core KMS code */ + dev->vblank_disable_allowed = true; + if (INTEL_INFO(dev)->num_pipes == 0) { + intel_display_power_put(dev, POWER_DOMAIN_VGA); + return 0; + } + + ret = intel_fbdev_init(dev); + if (ret) + goto cleanup_gem; + + /* Only enable hotplug handling once the fbdev is fully set up. */ + intel_hpd_init(dev); + + /* + * Some ports require correctly set-up hpd registers for detection to + * work properly (leading to ghost connected connector status), e.g. VGA + * on gm45. Hence we can only set up the initial fbdev config after hpd + * irqs are fully enabled. Now we should scan for the initial config + * only once hotplug handling is enabled, but due to screwed-up locking + * around kms/fbdev init we can't protect the fdbev initial config + * scanning against hotplug events. Hence do this first and ignore the + * tiny window where we will loose hotplug notifactions. + */ + intel_fbdev_initial_config(dev); + + /* Only enable hotplug handling once the fbdev is fully set up. */ + dev_priv->enable_hotplug_processing = true; + + drm_kms_helper_poll_init(dev); + + return 0; + +cleanup_gem: + mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); + i915_gem_context_fini(dev); + mutex_unlock(&dev->struct_mutex); + i915_gem_cleanup_aliasing_ppgtt(dev); + drm_mm_takedown(&dev_priv->gtt.base.mm); +cleanup_power: + intel_display_power_put(dev, POWER_DOMAIN_VGA); + drm_irq_uninstall(dev); +cleanup_gem_stolen: + i915_gem_cleanup_stolen(dev); +cleanup_vga_switcheroo: + vga_switcheroo_unregister_client(dev->pdev); +cleanup_vga_client: + vga_client_register(dev->pdev, NULL, NULL, NULL); +out: + return ret; +} + +int i915_master_create(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv; + + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); + if (!master_priv) + return -ENOMEM; + + master->driver_priv = master_priv; + return 0; +} + +void i915_master_destroy(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv = master->driver_priv; + + if (!master_priv) + return; + + kfree(master_priv); + + master->driver_priv = NULL; +} + +#if IS_ENABLED(CONFIG_FB) +static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) +{ + struct apertures_struct *ap; + struct pci_dev *pdev = dev_priv->dev->pdev; + bool primary; + + ap = alloc_apertures(1); + if (!ap) + return; + + ap->ranges[0].base = dev_priv->gtt.mappable_base; + ap->ranges[0].size = dev_priv->gtt.mappable_end; + + primary = + pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; + + remove_conflicting_framebuffers(ap, "inteldrmfb", primary); + + kfree(ap); +} +#else +static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) +{ +} +#endif + +static void i915_dump_device_info(struct drm_i915_private *dev_priv) +{ + const struct intel_device_info *info = dev_priv->info; + +#define PRINT_S(name) "%s" +#define SEP_EMPTY +#define PRINT_FLAG(name) info->name ? #name "," : "" +#define SEP_COMMA , + DRM_DEBUG_DRIVER("i915 device info: gen=%i, pciid=0x%04x flags=" + DEV_INFO_FOR_EACH_FLAG(PRINT_S, SEP_EMPTY), + info->gen, + dev_priv->dev->pdev->device, + DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_COMMA)); +#undef PRINT_S +#undef SEP_EMPTY +#undef PRINT_FLAG +#undef SEP_COMMA +} + +/** + * i915_driver_load - setup chip and create an initial config + * @dev: DRM device + * @flags: startup flags + * + * The driver load routine has to do several things: + * - drive output discovery via intel_modeset_init() + * - initialize the memory manager + * - allocate initial config memory + * - setup the DRM framebuffer with the allocated memory + */ +int i915_driver_load(struct drm_device *dev, unsigned long flags) +{ + struct drm_i915_private *dev_priv; + struct intel_device_info *info; + int ret = 0, mmio_bar, mmio_size; + uint32_t aperture_size; + + info = (struct intel_device_info *) flags; + + /* Refuse to load on gen6+ without kms enabled. */ + if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET)) { + DRM_INFO("Your hardware requires kernel modesetting (KMS)\n"); + DRM_INFO("See CONFIG_DRM_I915_KMS, nomodeset, and i915.modeset parameters\n"); + return -ENODEV; + } + + /* UMS needs agp support. */ + if (!drm_core_check_feature(dev, DRIVER_MODESET) && !dev->agp) + return -EINVAL; + + dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); + if (dev_priv == NULL) + return -ENOMEM; + + dev->dev_private = (void *)dev_priv; + dev_priv->dev = dev; + dev_priv->info = info; + + spin_lock_init(&dev_priv->irq_lock); + spin_lock_init(&dev_priv->gpu_error.lock); + spin_lock_init(&dev_priv->backlight_lock); + spin_lock_init(&dev_priv->uncore.lock); + spin_lock_init(&dev_priv->mm.object_stat_lock); + mutex_init(&dev_priv->dpio_lock); + mutex_init(&dev_priv->modeset_restore_lock); + + intel_pm_setup(dev); + + intel_display_crc_init(dev); + + i915_dump_device_info(dev_priv); + + /* Not all pre-production machines fall into this category, only the + * very first ones. Almost everything should work, except for maybe + * suspend/resume. And we don't implement workarounds that affect only + * pre-production machines. */ + if (IS_HSW_EARLY_SDV(dev)) + DRM_INFO("This is an early pre-production Haswell machine. " + "It may not be fully functional.\n"); + + if (i915_get_bridge_dev(dev)) { + ret = -EIO; + goto free_priv; + } + + mmio_bar = IS_GEN2(dev) ? 1 : 0; + /* Before gen4, the registers and the GTT are behind different BARs. + * However, from gen4 onwards, the registers and the GTT are shared + * in the same BAR, so we want to restrict this ioremap from + * clobbering the GTT which we want ioremap_wc instead. Fortunately, + * the register BAR remains the same size for all the earlier + * generations up to Ironlake. + */ + if (info->gen < 5) + mmio_size = 512*1024; + else + mmio_size = 2*1024*1024; + + dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); + if (!dev_priv->regs) { + DRM_ERROR("failed to map registers\n"); + ret = -EIO; + goto put_bridge; + } + + intel_uncore_early_sanitize(dev); + + /* This must be called before any calls to HAS_PCH_* */ + intel_detect_pch(dev); + + intel_uncore_init(dev); + + ret = i915_gem_gtt_init(dev); + if (ret) + goto out_regs; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + i915_kick_out_firmware_fb(dev_priv); + + pci_set_master(dev->pdev); + + /* overlay on gen2 is broken and can't address above 1G */ + if (IS_GEN2(dev)) + dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30)); + + /* 965GM sometimes incorrectly writes to hardware status page (HWS) + * using 32bit addressing, overwriting memory if HWS is located + * above 4GB. + * + * The documentation also mentions an issue with undefined + * behaviour if any general state is accessed within a page above 4GB, + * which also needs to be handled carefully. + */ + if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) + dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); + + aperture_size = dev_priv->gtt.mappable_end; + + dev_priv->gtt.mappable = + io_mapping_create_wc(dev_priv->gtt.mappable_base, + aperture_size); + if (dev_priv->gtt.mappable == NULL) { + ret = -EIO; + goto out_gtt; + } + + dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base, + aperture_size); + + /* The i915 workqueue is primarily used for batched retirement of + * requests (and thus managing bo) once the task has been completed + * by the GPU. i915_gem_retire_requests() is called directly when we + * need high-priority retirement, such as waiting for an explicit + * bo. + * + * It is also used for periodic low-priority events, such as + * idle-timers and recording error state. + * + * All tasks on the workqueue are expected to acquire the dev mutex + * so there is no point in running more than one instance of the + * workqueue at any time. Use an ordered one. + */ + dev_priv->wq = alloc_ordered_workqueue("i915", 0); + if (dev_priv->wq == NULL) { + DRM_ERROR("Failed to create our workqueue.\n"); + ret = -ENOMEM; + goto out_mtrrfree; + } + + intel_irq_init(dev); + intel_uncore_sanitize(dev); + + /* Try to make sure MCHBAR is enabled before poking at it */ + intel_setup_mchbar(dev); + intel_setup_gmbus(dev); + intel_opregion_setup(dev); + + intel_setup_bios(dev); + + i915_gem_load(dev); + + /* On the 945G/GM, the chipset reports the MSI capability on the + * integrated graphics even though the support isn't actually there + * according to the published specs. It doesn't appear to function + * correctly in testing on 945G. + * This may be a side effect of MSI having been made available for PEG + * and the registers being closely associated. + * + * According to chipset errata, on the 965GM, MSI interrupts may + * be lost or delayed, but we use them anyways to avoid + * stuck interrupts on some machines. + */ + if (!IS_I945G(dev) && !IS_I945GM(dev)) + pci_enable_msi(dev->pdev); + + dev_priv->num_plane = 1; + if (IS_VALLEYVIEW(dev)) + dev_priv->num_plane = 2; + + if (INTEL_INFO(dev)->num_pipes) { + ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes); + if (ret) + goto out_gem_unload; + } + + intel_power_domains_init(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = i915_load_modeset_init(dev); + if (ret < 0) { + DRM_ERROR("failed to init modeset\n"); + goto out_power_well; + } + } else { + /* Start out suspended in ums mode. */ + dev_priv->ums.mm_suspended = 1; + } + + i915_setup_sysfs(dev); + + if (INTEL_INFO(dev)->num_pipes) { + /* Must be done after probing outputs */ + intel_opregion_init(dev); + acpi_video_register(); + } + + if (IS_GEN5(dev)) + intel_gpu_ips_init(dev_priv); + + intel_init_runtime_pm(dev_priv); + + return 0; + +out_power_well: + intel_power_domains_remove(dev); + drm_vblank_cleanup(dev); +out_gem_unload: + if (dev_priv->mm.inactive_shrinker.scan_objects) + unregister_shrinker(&dev_priv->mm.inactive_shrinker); + + if (dev->pdev->msi_enabled) + pci_disable_msi(dev->pdev); + + intel_teardown_gmbus(dev); + intel_teardown_mchbar(dev); + pm_qos_remove_request(&dev_priv->pm_qos); + destroy_workqueue(dev_priv->wq); +out_mtrrfree: + arch_phys_wc_del(dev_priv->gtt.mtrr); + io_mapping_free(dev_priv->gtt.mappable); +out_gtt: + list_del(&dev_priv->gtt.base.global_link); + drm_mm_takedown(&dev_priv->gtt.base.mm); + dev_priv->gtt.base.cleanup(&dev_priv->gtt.base); +out_regs: + intel_uncore_fini(dev); + pci_iounmap(dev->pdev, dev_priv->regs); +put_bridge: + pci_dev_put(dev_priv->bridge_dev); +free_priv: + if (dev_priv->slab) + kmem_cache_destroy(dev_priv->slab); + kfree(dev_priv); + return ret; +} + +int i915_driver_unload(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = i915_gem_suspend(dev); + if (ret) { + DRM_ERROR("failed to idle hardware: %d\n", ret); + return ret; + } + + intel_fini_runtime_pm(dev_priv); + + intel_gpu_ips_teardown(); + + /* The i915.ko module is still not prepared to be loaded when + * the power well is not enabled, so just enable it in case + * we're going to unload/reload. */ + intel_display_set_init_power(dev, true); + intel_power_domains_remove(dev); + + i915_teardown_sysfs(dev); + + if (dev_priv->mm.inactive_shrinker.scan_objects) + unregister_shrinker(&dev_priv->mm.inactive_shrinker); + + io_mapping_free(dev_priv->gtt.mappable); + arch_phys_wc_del(dev_priv->gtt.mtrr); + + acpi_video_unregister(); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + intel_fbdev_fini(dev); + intel_modeset_cleanup(dev); + cancel_work_sync(&dev_priv->console_resume_work); + + /* + * free the memory space allocated for the child device + * config parsed from VBT + */ + if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) { + kfree(dev_priv->vbt.child_dev); + dev_priv->vbt.child_dev = NULL; + dev_priv->vbt.child_dev_num = 0; + } + + vga_switcheroo_unregister_client(dev->pdev); + vga_client_register(dev->pdev, NULL, NULL, NULL); + } + + /* Free error state after interrupts are fully disabled. */ + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); + cancel_work_sync(&dev_priv->gpu_error.work); + i915_destroy_error_state(dev); + + cancel_delayed_work_sync(&dev_priv->pc8.enable_work); + + if (dev->pdev->msi_enabled) + pci_disable_msi(dev->pdev); + + intel_opregion_fini(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Flush any outstanding unpin_work. */ + flush_workqueue(dev_priv->wq); + + mutex_lock(&dev->struct_mutex); + i915_gem_free_all_phys_object(dev); + i915_gem_cleanup_ringbuffer(dev); + i915_gem_context_fini(dev); + mutex_unlock(&dev->struct_mutex); + i915_gem_cleanup_aliasing_ppgtt(dev); + i915_gem_cleanup_stolen(dev); + + if (!I915_NEED_GFX_HWS(dev)) + i915_free_hws(dev); + } + + list_del(&dev_priv->gtt.base.global_link); + WARN_ON(!list_empty(&dev_priv->vm_list)); + + drm_vblank_cleanup(dev); + + intel_teardown_gmbus(dev); + intel_teardown_mchbar(dev); + + destroy_workqueue(dev_priv->wq); + pm_qos_remove_request(&dev_priv->pm_qos); + + dev_priv->gtt.base.cleanup(&dev_priv->gtt.base); + + intel_uncore_fini(dev); + if (dev_priv->regs != NULL) + pci_iounmap(dev->pdev, dev_priv->regs); + + if (dev_priv->slab) + kmem_cache_destroy(dev_priv->slab); + + pci_dev_put(dev_priv->bridge_dev); + kfree(dev->dev_private); + + return 0; +} + +int i915_driver_open(struct drm_device *dev, struct drm_file *file) +{ + int ret; + + ret = i915_gem_open(dev, file); + if (ret) + return ret; + + return 0; +} + +/** + * i915_driver_lastclose - clean up after all DRM clients have exited + * @dev: DRM device + * + * Take care of cleaning up after all DRM clients have exited. In the + * mode setting case, we want to restore the kernel's initial mode (just + * in case the last client left us in a bad state). + * + * Additionally, in the non-mode setting case, we'll tear down the GTT + * and DMA structures, since the kernel won't be using them, and clea + * up any GEM state. + */ +void i915_driver_lastclose(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + /* On gen6+ we refuse to init without kms enabled, but then the drm core + * goes right around and calls lastclose. Check for this and don't clean + * up anything. */ + if (!dev_priv) + return; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + intel_fbdev_restore_mode(dev); + vga_switcheroo_process_delayed_switch(); + return; + } + + i915_gem_lastclose(dev); + + i915_dma_cleanup(dev); +} + +void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) +{ + mutex_lock(&dev->struct_mutex); + i915_gem_context_close(dev, file_priv); + i915_gem_release(dev, file_priv); + mutex_unlock(&dev->struct_mutex); +} + +void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + + kfree(file_priv); +} + +const struct drm_ioctl_desc i915_ioctls[] = { + DRM_IOCTL_DEF_DRV(I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_FLUSH, i915_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_FLIP, i915_flip_bufs, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), +}; + +int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); + +/* + * This is really ugly: Because old userspace abused the linux agp interface to + * manage the gtt, we need to claim that all intel devices are agp. For + * otherwise the drm core refuses to initialize the agp support code. + */ +int i915_driver_device_is_agp(struct drm_device * dev) +{ + return 1; +} --- linux-3.13.0.orig/ubuntu/i915/intel_ringbuffer.h +++ linux-3.13.0/ubuntu/i915/intel_ringbuffer.h @@ -0,0 +1,282 @@ +#ifndef _INTEL_RINGBUFFER_H_ +#define _INTEL_RINGBUFFER_H_ + +/* + * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use" + * Gen3 BSpec "vol1c Memory Interface Functions" / 2.3.4.5 "Ring Buffer Use" + * Gen4+ BSpec "vol1c Memory Interface and Command Stream" / 5.3.4.5 "Ring Buffer Use" + * + * "If the Ring Buffer Head Pointer and the Tail Pointer are on the same + * cacheline, the Head Pointer must not be greater than the Tail + * Pointer." + */ +#define I915_RING_FREE_SPACE 64 + +struct intel_hw_status_page { + u32 *page_addr; + unsigned int gfx_addr; + struct drm_i915_gem_object *obj; +}; + +#define I915_READ_TAIL(ring) I915_READ(RING_TAIL((ring)->mmio_base)) +#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val) + +#define I915_READ_START(ring) I915_READ(RING_START((ring)->mmio_base)) +#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val) + +#define I915_READ_HEAD(ring) I915_READ(RING_HEAD((ring)->mmio_base)) +#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val) + +#define I915_READ_CTL(ring) I915_READ(RING_CTL((ring)->mmio_base)) +#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val) + +#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base)) +#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val) + +enum intel_ring_hangcheck_action { + HANGCHECK_IDLE = 0, + HANGCHECK_WAIT, + HANGCHECK_ACTIVE, + HANGCHECK_KICK, + HANGCHECK_HUNG, +}; + +struct intel_ring_hangcheck { + bool deadlock; + u32 seqno; + u32 acthd; + int score; + enum intel_ring_hangcheck_action action; +}; + +struct intel_ring_buffer { + const char *name; + enum intel_ring_id { + RCS = 0x0, + VCS, + BCS, + VECS, + } id; +#define I915_NUM_RINGS 4 + u32 mmio_base; + void __iomem *virtual_start; + struct drm_device *dev; + struct drm_i915_gem_object *obj; + + u32 head; + u32 tail; + int space; + int size; + int effective_size; + struct intel_hw_status_page status_page; + + /** We track the position of the requests in the ring buffer, and + * when each is retired we increment last_retired_head as the GPU + * must have finished processing the request and so we know we + * can advance the ringbuffer up to that position. + * + * last_retired_head is set to -1 after the value is consumed so + * we can detect new retirements. + */ + u32 last_retired_head; + + unsigned irq_refcount; /* protected by dev_priv->irq_lock */ + u32 irq_enable_mask; /* bitmask to enable ring interrupt */ + u32 trace_irq_seqno; + u32 sync_seqno[I915_NUM_RINGS-1]; + bool __must_check (*irq_get)(struct intel_ring_buffer *ring); + void (*irq_put)(struct intel_ring_buffer *ring); + + int (*init)(struct intel_ring_buffer *ring); + + void (*write_tail)(struct intel_ring_buffer *ring, + u32 value); + int __must_check (*flush)(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains); + int (*add_request)(struct intel_ring_buffer *ring); + /* Some chipsets are not quite as coherent as advertised and need + * an expensive kick to force a true read of the up-to-date seqno. + * However, the up-to-date seqno is not always required and the last + * seen value is good enough. Note that the seqno will always be + * monotonic, even if not coherent. + */ + u32 (*get_seqno)(struct intel_ring_buffer *ring, + bool lazy_coherency); + void (*set_seqno)(struct intel_ring_buffer *ring, + u32 seqno); + int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, + u32 offset, u32 length, + unsigned flags); +#define I915_DISPATCH_SECURE 0x1 +#define I915_DISPATCH_PINNED 0x2 + void (*cleanup)(struct intel_ring_buffer *ring); + int (*sync_to)(struct intel_ring_buffer *ring, + struct intel_ring_buffer *to, + u32 seqno); + + /* our mbox written by others */ + u32 semaphore_register[I915_NUM_RINGS]; + /* mboxes this ring signals to */ + u32 signal_mbox[I915_NUM_RINGS]; + + /** + * List of objects currently involved in rendering from the + * ringbuffer. + * + * Includes buffers having the contents of their GPU caches + * flushed, not necessarily primitives. last_rendering_seqno + * represents when the rendering involved will be completed. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * List of breadcrumbs associated with GPU requests currently + * outstanding. + */ + struct list_head request_list; + + /** + * Do we have some not yet emitted requests outstanding? + */ + struct drm_i915_gem_request *preallocated_lazy_request; + u32 outstanding_lazy_seqno; + bool gpu_caches_dirty; + bool fbc_dirty; + + wait_queue_head_t irq_queue; + + /** + * Do an explicit TLB flush before MI_SET_CONTEXT + */ + bool itlb_before_ctx_switch; + struct i915_hw_context *default_context; + struct i915_hw_context *last_context; + + struct intel_ring_hangcheck hangcheck; + + struct { + struct drm_i915_gem_object *obj; + u32 gtt_offset; + volatile u32 *cpu_page; + } scratch; +}; + +static inline bool +intel_ring_initialized(struct intel_ring_buffer *ring) +{ + return ring->obj != NULL; +} + +static inline unsigned +intel_ring_flag(struct intel_ring_buffer *ring) +{ + return 1 << ring->id; +} + +static inline u32 +intel_ring_sync_index(struct intel_ring_buffer *ring, + struct intel_ring_buffer *other) +{ + int idx; + + /* + * cs -> 0 = vcs, 1 = bcs + * vcs -> 0 = bcs, 1 = cs, + * bcs -> 0 = cs, 1 = vcs. + */ + + idx = (other - ring) - 1; + if (idx < 0) + idx += I915_NUM_RINGS; + + return idx; +} + +static inline u32 +intel_read_status_page(struct intel_ring_buffer *ring, + int reg) +{ + /* Ensure that the compiler doesn't optimize away the load. */ + barrier(); + return ring->status_page.page_addr[reg]; +} + +static inline void +intel_write_status_page(struct intel_ring_buffer *ring, + int reg, u32 value) +{ + ring->status_page.page_addr[reg] = value; +} + +/** + * Reads a dword out of the status page, which is written to from the command + * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or + * MI_STORE_DATA_IMM. + * + * The following dwords have a reserved meaning: + * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes. + * 0x04: ring 0 head pointer + * 0x05: ring 1 head pointer (915-class) + * 0x06: ring 2 head pointer (915-class) + * 0x10-0x1b: Context status DWords (GM45) + * 0x1f: Last written status offset. (GM45) + * + * The area from dword 0x20 to 0x3ff is available for driver usage. + */ +#define I915_GEM_HWS_INDEX 0x20 +#define I915_GEM_HWS_SCRATCH_INDEX 0x30 +#define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT) + +void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); + +int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); +int __must_check intel_ring_cacheline_align(struct intel_ring_buffer *ring); +static inline void intel_ring_emit(struct intel_ring_buffer *ring, + u32 data) +{ + iowrite32(data, ring->virtual_start + ring->tail); + ring->tail += 4; +} +static inline void intel_ring_advance(struct intel_ring_buffer *ring) +{ + ring->tail &= ring->size - 1; +} +void __intel_ring_advance(struct intel_ring_buffer *ring); + +int __must_check intel_ring_idle(struct intel_ring_buffer *ring); +void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno); +int intel_ring_flush_all_caches(struct intel_ring_buffer *ring); +int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring); + +int intel_init_render_ring_buffer(struct drm_device *dev); +int intel_init_bsd_ring_buffer(struct drm_device *dev); +int intel_init_blt_ring_buffer(struct drm_device *dev); +int intel_init_vebox_ring_buffer(struct drm_device *dev); + +u32 intel_ring_get_active_head(struct intel_ring_buffer *ring); +void intel_ring_setup_status_page(struct intel_ring_buffer *ring); + +static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring) +{ + return ring->tail; +} + +static inline u32 intel_ring_get_seqno(struct intel_ring_buffer *ring) +{ + BUG_ON(ring->outstanding_lazy_seqno == 0); + return ring->outstanding_lazy_seqno; +} + +static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno) +{ + if (ring->trace_irq_seqno == 0 && ring->irq_get(ring)) + ring->trace_irq_seqno = seqno; +} + +/* DRI warts */ +int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size); + +#endif /* _INTEL_RINGBUFFER_H_ */ --- linux-3.13.0.orig/ubuntu/i915/i915_ioc32.c +++ linux-3.13.0/ubuntu/i915/i915_ioc32.c @@ -0,0 +1,221 @@ +/** + * \file i915_ioc32.c + * + * 32-bit ioctl compatibility routines for the i915 DRM. + * + * \author Alan Hourihane + * + * + * Copyright (C) Paul Mackerras 2005 + * Copyright (C) Alan Hourihane 2005 + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include + +#include +#include +#include "i915_drv.h" + +typedef struct _drm_i915_batchbuffer32 { + int start; /* agp offset */ + int used; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + u32 cliprects; /* pointer to userspace cliprects */ +} drm_i915_batchbuffer32_t; + +static int compat_i915_batchbuffer(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_batchbuffer32_t batchbuffer32; + drm_i915_batchbuffer_t __user *batchbuffer; + + if (copy_from_user + (&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32))) + return -EFAULT; + + batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer)); + if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer)) + || __put_user(batchbuffer32.start, &batchbuffer->start) + || __put_user(batchbuffer32.used, &batchbuffer->used) + || __put_user(batchbuffer32.DR1, &batchbuffer->DR1) + || __put_user(batchbuffer32.DR4, &batchbuffer->DR4) + || __put_user(batchbuffer32.num_cliprects, + &batchbuffer->num_cliprects) + || __put_user((int __user *)(unsigned long)batchbuffer32.cliprects, + &batchbuffer->cliprects)) + return -EFAULT; + + return drm_ioctl(file, DRM_IOCTL_I915_BATCHBUFFER, + (unsigned long)batchbuffer); +} + +typedef struct _drm_i915_cmdbuffer32 { + u32 buf; /* pointer to userspace command buffer */ + int sz; /* nr bytes in buf */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + u32 cliprects; /* pointer to userspace cliprects */ +} drm_i915_cmdbuffer32_t; + +static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_cmdbuffer32_t cmdbuffer32; + drm_i915_cmdbuffer_t __user *cmdbuffer; + + if (copy_from_user + (&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32))) + return -EFAULT; + + cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer)); + if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer)) + || __put_user((int __user *)(unsigned long)cmdbuffer32.buf, + &cmdbuffer->buf) + || __put_user(cmdbuffer32.sz, &cmdbuffer->sz) + || __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1) + || __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4) + || __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects) + || __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects, + &cmdbuffer->cliprects)) + return -EFAULT; + + return drm_ioctl(file, DRM_IOCTL_I915_CMDBUFFER, + (unsigned long)cmdbuffer); +} + +typedef struct drm_i915_irq_emit32 { + u32 irq_seq; +} drm_i915_irq_emit32_t; + +static int compat_i915_irq_emit(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_irq_emit32_t req32; + drm_i915_irq_emit_t __user *request; + + if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user((int __user *)(unsigned long)req32.irq_seq, + &request->irq_seq)) + return -EFAULT; + + return drm_ioctl(file, DRM_IOCTL_I915_IRQ_EMIT, + (unsigned long)request); +} +typedef struct drm_i915_getparam32 { + int param; + u32 value; +} drm_i915_getparam32_t; + +static int compat_i915_getparam(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_getparam32_t req32; + drm_i915_getparam_t __user *request; + + if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.param, &request->param) + || __put_user((void __user *)(unsigned long)req32.value, + &request->value)) + return -EFAULT; + + return drm_ioctl(file, DRM_IOCTL_I915_GETPARAM, + (unsigned long)request); +} + +typedef struct drm_i915_mem_alloc32 { + int region; + int alignment; + int size; + u32 region_offset; /* offset from start of fb or agp */ +} drm_i915_mem_alloc32_t; + +static int compat_i915_alloc(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_mem_alloc32_t req32; + drm_i915_mem_alloc_t __user *request; + + if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.region, &request->region) + || __put_user(req32.alignment, &request->alignment) + || __put_user(req32.size, &request->size) + || __put_user((void __user *)(unsigned long)req32.region_offset, + &request->region_offset)) + return -EFAULT; + + return drm_ioctl(file, DRM_IOCTL_I915_ALLOC, + (unsigned long)request); +} + +static drm_ioctl_compat_t *i915_compat_ioctls[] = { + [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer, + [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer, + [DRM_I915_GETPARAM] = compat_i915_getparam, + [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit, + [DRM_I915_ALLOC] = compat_i915_alloc +}; + +#ifdef CONFIG_COMPAT +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/dri/card. + * + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + unsigned int nr = DRM_IOCTL_NR(cmd); + drm_ioctl_compat_t *fn = NULL; + int ret; + + if (nr < DRM_COMMAND_BASE) + return drm_compat_ioctl(filp, cmd, arg); + + if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls)) + fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE]; + + if (fn != NULL) + ret = (*fn) (filp, cmd, arg); + else + ret = drm_ioctl(filp, cmd, arg); + + return ret; +} +#endif --- linux-3.13.0.orig/ubuntu/i915/intel_acpi.c +++ linux-3.13.0/ubuntu/i915/intel_acpi.c @@ -0,0 +1,249 @@ +/* + * Intel ACPI functions + * + * _DSM related code stolen from nouveau_acpi.c. + */ +#include +#include +#include +#include +#include "i915_drv.h" + +#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ + +#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */ +#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ + +static struct intel_dsm_priv { + acpi_handle dhandle; +} intel_dsm_priv; + +static const u8 intel_dsm_guid[] = { + 0xd3, 0x73, 0xd8, 0x7e, + 0xd0, 0xc2, + 0x4f, 0x4e, + 0xa8, 0x54, + 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c +}; + +static int intel_dsm(acpi_handle handle, int func) +{ + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_object_list input; + union acpi_object params[4]; + union acpi_object *obj; + u32 result; + int ret = 0; + + input.count = 4; + input.pointer = params; + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = sizeof(intel_dsm_guid); + params[0].buffer.pointer = (char *)intel_dsm_guid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = INTEL_DSM_REVISION_ID; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = func; + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + + ret = acpi_evaluate_object(handle, "_DSM", &input, &output); + if (ret) { + DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); + return ret; + } + + obj = (union acpi_object *)output.pointer; + + result = 0; + switch (obj->type) { + case ACPI_TYPE_INTEGER: + result = obj->integer.value; + break; + + case ACPI_TYPE_BUFFER: + if (obj->buffer.length == 4) { + result = (obj->buffer.pointer[0] | + (obj->buffer.pointer[1] << 8) | + (obj->buffer.pointer[2] << 16) | + (obj->buffer.pointer[3] << 24)); + break; + } + default: + ret = -EINVAL; + break; + } + if (result == 0x80000002) + ret = -ENODEV; + + kfree(output.pointer); + return ret; +} + +static char *intel_dsm_port_name(u8 id) +{ + switch (id) { + case 0: + return "Reserved"; + case 1: + return "Analog VGA"; + case 2: + return "LVDS"; + case 3: + return "Reserved"; + case 4: + return "HDMI/DVI_B"; + case 5: + return "HDMI/DVI_C"; + case 6: + return "HDMI/DVI_D"; + case 7: + return "DisplayPort_A"; + case 8: + return "DisplayPort_B"; + case 9: + return "DisplayPort_C"; + case 0xa: + return "DisplayPort_D"; + case 0xb: + case 0xc: + case 0xd: + return "Reserved"; + case 0xe: + return "WiDi"; + default: + return "bad type"; + } +} + +static char *intel_dsm_mux_type(u8 type) +{ + switch (type) { + case 0: + return "unknown"; + case 1: + return "No MUX, iGPU only"; + case 2: + return "No MUX, dGPU only"; + case 3: + return "MUXed between iGPU and dGPU"; + default: + return "bad type"; + } +} + +static void intel_dsm_platform_mux_info(void) +{ + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_object_list input; + union acpi_object params[4]; + union acpi_object *pkg; + int i, ret; + + input.count = 4; + input.pointer = params; + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = sizeof(intel_dsm_guid); + params[0].buffer.pointer = (char *)intel_dsm_guid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = INTEL_DSM_REVISION_ID; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO; + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + + ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input, + &output); + if (ret) { + DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); + goto out; + } + + pkg = (union acpi_object *)output.pointer; + + if (pkg->type == ACPI_TYPE_PACKAGE) { + union acpi_object *connector_count = &pkg->package.elements[0]; + DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", + (unsigned long long)connector_count->integer.value); + for (i = 1; i < pkg->package.count; i++) { + union acpi_object *obj = &pkg->package.elements[i]; + union acpi_object *connector_id = + &obj->package.elements[0]; + union acpi_object *info = &obj->package.elements[1]; + DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", + (unsigned long long)connector_id->integer.value); + DRM_DEBUG_DRIVER(" port id: %s\n", + intel_dsm_port_name(info->buffer.pointer[0])); + DRM_DEBUG_DRIVER(" display mux info: %s\n", + intel_dsm_mux_type(info->buffer.pointer[1])); + DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", + intel_dsm_mux_type(info->buffer.pointer[2])); + DRM_DEBUG_DRIVER(" hpd mux info: %s\n", + intel_dsm_mux_type(info->buffer.pointer[3])); + } + } + +out: + kfree(output.pointer); +} + +static bool intel_dsm_pci_probe(struct pci_dev *pdev) +{ + acpi_handle dhandle; + int ret; + + dhandle = ACPI_HANDLE(&pdev->dev); + if (!dhandle) + return false; + + if (!acpi_has_method(dhandle, "_DSM")) { + DRM_DEBUG_KMS("no _DSM method for intel device\n"); + return false; + } + + ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS); + if (ret < 0) { + DRM_DEBUG_KMS("failed to get supported _DSM functions\n"); + return false; + } + + intel_dsm_priv.dhandle = dhandle; + + intel_dsm_platform_mux_info(); + return true; +} + +static bool intel_dsm_detect(void) +{ + char acpi_method_name[255] = { 0 }; + struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; + struct pci_dev *pdev = NULL; + bool has_dsm = false; + int vga_count = 0; + + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { + vga_count++; + has_dsm |= intel_dsm_pci_probe(pdev); + } + + if (vga_count == 2 && has_dsm) { + acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); + DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n", + acpi_method_name); + return true; + } + + return false; +} + +void intel_register_dsm_handler(void) +{ + if (!intel_dsm_detect()) + return; +} + +void intel_unregister_dsm_handler(void) +{ +} --- linux-3.13.0.orig/ubuntu/i915/intel_sideband.c +++ linux-3.13.0/ubuntu/i915/intel_sideband.c @@ -0,0 +1,265 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include "i915_drv.h" +#include "intel_drv.h" + +/* + * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and + * VLV_VLV2_PUNIT_HAS_0.8.docx + */ +static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn, + u32 port, u32 opcode, u32 addr, u32 *val) +{ + u32 cmd, be = 0xf, bar = 0; + bool is_read = (opcode == PUNIT_OPCODE_REG_READ || + opcode == DPIO_OPCODE_REG_READ); + + cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | + (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) | + (bar << IOSF_BAR_SHIFT); + + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) { + DRM_DEBUG_DRIVER("IOSF sideband idle wait (%s) timed out\n", + is_read ? "read" : "write"); + return -EAGAIN; + } + + I915_WRITE(VLV_IOSF_ADDR, addr); + if (!is_read) + I915_WRITE(VLV_IOSF_DATA, *val); + I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); + + if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) { + DRM_DEBUG_DRIVER("IOSF sideband finish wait (%s) timed out\n", + is_read ? "read" : "write"); + return -ETIMEDOUT; + } + + if (is_read) + *val = I915_READ(VLV_IOSF_DATA); + I915_WRITE(VLV_IOSF_DATA, 0); + + return 0; +} + +u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr) +{ + u32 val = 0; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + mutex_lock(&dev_priv->dpio_lock); + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, + PUNIT_OPCODE_REG_READ, addr, &val); + mutex_unlock(&dev_priv->dpio_lock); + + return val; +} + +void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) +{ + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + mutex_lock(&dev_priv->dpio_lock); + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, + PUNIT_OPCODE_REG_WRITE, addr, &val); + mutex_unlock(&dev_priv->dpio_lock); +} + +u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT, + PUNIT_OPCODE_REG_READ, reg, &val); + + return val; +} + +void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT, + PUNIT_OPCODE_REG_WRITE, reg, &val); +} + +u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr) +{ + u32 val = 0; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + mutex_lock(&dev_priv->dpio_lock); + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC, + PUNIT_OPCODE_REG_READ, addr, &val); + mutex_unlock(&dev_priv->dpio_lock); + + return val; +} + +u32 vlv_gpio_nc_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPIO_NC, + PUNIT_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_gpio_nc_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPIO_NC, + PUNIT_OPCODE_REG_WRITE, reg, &val); +} + +u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCK, + PUNIT_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCK, + PUNIT_OPCODE_REG_WRITE, reg, &val); +} + +u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCU, + PUNIT_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCU, + PUNIT_OPCODE_REG_WRITE, reg, &val); +} + +u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPS_CORE, + PUNIT_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPS_CORE, + PUNIT_OPCODE_REG_WRITE, reg, &val); +} + +u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) +{ + u32 val = 0; + + vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), + DPIO_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_dpio_write(struct drm_i915_private *dev_priv, enum pipe pipe, int reg, u32 val) +{ + vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), + DPIO_OPCODE_REG_WRITE, reg, &val); +} + +/* SBI access */ +u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, + enum intel_sbi_destination destination) +{ + u32 value = 0; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to become ready\n"); + return 0; + } + + I915_WRITE(SBI_ADDR, (reg << 16)); + + if (destination == SBI_ICLK) + value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD; + else + value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD; + I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY); + + if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to complete read transaction\n"); + return 0; + } + + return I915_READ(SBI_DATA); +} + +void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, + enum intel_sbi_destination destination) +{ + u32 tmp; + + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to become ready\n"); + return; + } + + I915_WRITE(SBI_ADDR, (reg << 16)); + I915_WRITE(SBI_DATA, value); + + if (destination == SBI_ICLK) + tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR; + else + tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR; + I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp); + + if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to complete write transaction\n"); + return; + } +} + +u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_WRITE, reg, &val); +} --- linux-3.13.0.orig/ubuntu/i915/intel_bios.c +++ linux-3.13.0/ubuntu/i915/intel_bios.c @@ -0,0 +1,956 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ +#include +#include +#include +#include +#include "i915_drv.h" +#include "intel_bios.h" + +#define SLAVE_ADDR1 0x70 +#define SLAVE_ADDR2 0x72 + +static int panel_type; + +static void * +find_section(struct bdb_header *bdb, int section_id) +{ + u8 *base = (u8 *)bdb; + int index = 0; + u16 total, current_size; + u8 current_id; + + /* skip to first section */ + index += bdb->header_size; + total = bdb->bdb_size; + + /* walk the sections looking for section_id */ + while (index < total) { + current_id = *(base + index); + index++; + current_size = *((u16 *)(base + index)); + index += 2; + if (current_id == section_id) + return base + index; + index += current_size; + } + + return NULL; +} + +static u16 +get_blocksize(void *p) +{ + u16 *block_ptr, block_size; + + block_ptr = (u16 *)((char *)p - 2); + block_size = *block_ptr; + return block_size; +} + +static void +fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, + const struct lvds_dvo_timing *dvo_timing) +{ + panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | + dvo_timing->hactive_lo; + panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + + ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); + panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + + dvo_timing->hsync_pulse_width; + panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + + ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); + + panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | + dvo_timing->vactive_lo; + panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + + dvo_timing->vsync_off; + panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + + dvo_timing->vsync_pulse_width; + panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + + ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); + panel_fixed_mode->clock = dvo_timing->clock * 10; + panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; + + if (dvo_timing->hsync_positive) + panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; + else + panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; + + if (dvo_timing->vsync_positive) + panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; + else + panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; + + /* Some VBTs have bogus h/vtotal values */ + if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) + panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; + if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) + panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; + + drm_mode_set_name(panel_fixed_mode); +} + +static bool +lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, + const struct lvds_dvo_timing *b) +{ + if (a->hactive_hi != b->hactive_hi || + a->hactive_lo != b->hactive_lo) + return false; + + if (a->hsync_off_hi != b->hsync_off_hi || + a->hsync_off_lo != b->hsync_off_lo) + return false; + + if (a->hsync_pulse_width != b->hsync_pulse_width) + return false; + + if (a->hblank_hi != b->hblank_hi || + a->hblank_lo != b->hblank_lo) + return false; + + if (a->vactive_hi != b->vactive_hi || + a->vactive_lo != b->vactive_lo) + return false; + + if (a->vsync_off != b->vsync_off) + return false; + + if (a->vsync_pulse_width != b->vsync_pulse_width) + return false; + + if (a->vblank_hi != b->vblank_hi || + a->vblank_lo != b->vblank_lo) + return false; + + return true; +} + +static const struct lvds_dvo_timing * +get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, + const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, + int index) +{ + /* + * the size of fp_timing varies on the different platform. + * So calculate the DVO timing relative offset in LVDS data + * entry to get the DVO timing entry + */ + + int lfp_data_size = + lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - + lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; + int dvo_timing_offset = + lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - + lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; + char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; + + return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); +} + +/* get lvds_fp_timing entry + * this function may return NULL if the corresponding entry is invalid + */ +static const struct lvds_fp_timing * +get_lvds_fp_timing(const struct bdb_header *bdb, + const struct bdb_lvds_lfp_data *data, + const struct bdb_lvds_lfp_data_ptrs *ptrs, + int index) +{ + size_t data_ofs = (const u8 *)data - (const u8 *)bdb; + u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ + size_t ofs; + + if (index >= ARRAY_SIZE(ptrs->ptr)) + return NULL; + ofs = ptrs->ptr[index].fp_timing_offset; + if (ofs < data_ofs || + ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) + return NULL; + return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); +} + +/* Try to find integrated panel data */ +static void +parse_lfp_panel_data(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + const struct bdb_lvds_options *lvds_options; + const struct bdb_lvds_lfp_data *lvds_lfp_data; + const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; + const struct lvds_dvo_timing *panel_dvo_timing; + const struct lvds_fp_timing *fp_timing; + struct drm_display_mode *panel_fixed_mode; + int i, downclock; + + lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); + if (!lvds_options) + return; + + dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; + if (lvds_options->panel_type == 0xff) + return; + + panel_type = lvds_options->panel_type; + + lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); + if (!lvds_lfp_data) + return; + + lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); + if (!lvds_lfp_data_ptrs) + return; + + dev_priv->vbt.lvds_vbt = 1; + + panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, + lvds_lfp_data_ptrs, + lvds_options->panel_type); + + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); + if (!panel_fixed_mode) + return; + + fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); + + dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; + + DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); + drm_mode_debug_printmodeline(panel_fixed_mode); + + /* + * Iterate over the LVDS panel timing info to find the lowest clock + * for the native resolution. + */ + downclock = panel_dvo_timing->clock; + for (i = 0; i < 16; i++) { + const struct lvds_dvo_timing *dvo_timing; + + dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, + lvds_lfp_data_ptrs, + i); + if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && + dvo_timing->clock < downclock) + downclock = dvo_timing->clock; + } + + if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) { + dev_priv->lvds_downclock_avail = 1; + dev_priv->lvds_downclock = downclock * 10; + DRM_DEBUG_KMS("LVDS downclock is found in VBT. " + "Normal Clock %dKHz, downclock %dKHz\n", + panel_fixed_mode->clock, 10*downclock); + } + + fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, + lvds_lfp_data_ptrs, + lvds_options->panel_type); + if (fp_timing) { + /* check the resolution, just to be sure */ + if (fp_timing->x_res == panel_fixed_mode->hdisplay && + fp_timing->y_res == panel_fixed_mode->vdisplay) { + dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val; + DRM_DEBUG_KMS("VBT initial LVDS value %x\n", + dev_priv->vbt.bios_lvds_val); + } + } +} + +static void +parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + const struct bdb_lfp_backlight_data *backlight_data; + const struct bdb_lfp_backlight_data_entry *entry; + + backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); + if (!backlight_data) + return; + + if (backlight_data->entry_size != sizeof(backlight_data->data[0])) { + DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n", + backlight_data->entry_size); + return; + } + + entry = &backlight_data->data[panel_type]; + + dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; + dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; + DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " + "active %s, min brightness %u, level %u\n", + dev_priv->vbt.backlight.pwm_freq_hz, + dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", + entry->min_brightness, + backlight_data->level[panel_type]); +} + +/* Try to find sdvo panel data */ +static void +parse_sdvo_panel_data(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct lvds_dvo_timing *dvo_timing; + struct drm_display_mode *panel_fixed_mode; + int index; + + index = i915_vbt_sdvo_panel_type; + if (index == -2) { + DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n"); + return; + } + + if (index == -1) { + struct bdb_sdvo_lvds_options *sdvo_lvds_options; + + sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); + if (!sdvo_lvds_options) + return; + + index = sdvo_lvds_options->panel_type; + } + + dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); + if (!dvo_timing) + return; + + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); + if (!panel_fixed_mode) + return; + + fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); + + dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; + + DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); + drm_mode_debug_printmodeline(panel_fixed_mode); +} + +static int intel_bios_ssc_frequency(struct drm_device *dev, + bool alternate) +{ + switch (INTEL_INFO(dev)->gen) { + case 2: + return alternate ? 66667 : 48000; + case 3: + case 4: + return alternate ? 100000 : 96000; + default: + return alternate ? 100000 : 120000; + } +} + +static void +parse_general_features(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct drm_device *dev = dev_priv->dev; + struct bdb_general_features *general; + + general = find_section(bdb, BDB_GENERAL_FEATURES); + if (general) { + dev_priv->vbt.int_tv_support = general->int_tv_support; + dev_priv->vbt.int_crt_support = general->int_crt_support; + dev_priv->vbt.lvds_use_ssc = general->enable_ssc; + dev_priv->vbt.lvds_ssc_freq = + intel_bios_ssc_frequency(dev, general->ssc_freq); + dev_priv->vbt.display_clock_mode = general->display_clock_mode; + dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; + DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", + dev_priv->vbt.int_tv_support, + dev_priv->vbt.int_crt_support, + dev_priv->vbt.lvds_use_ssc, + dev_priv->vbt.lvds_ssc_freq, + dev_priv->vbt.display_clock_mode, + dev_priv->vbt.fdi_rx_polarity_inverted); + } +} + +static void +parse_general_definitions(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct bdb_general_definitions *general; + + general = find_section(bdb, BDB_GENERAL_DEFINITIONS); + if (general) { + u16 block_size = get_blocksize(general); + if (block_size >= sizeof(*general)) { + int bus_pin = general->crt_ddc_gmbus_pin; + DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); + if (intel_gmbus_is_port_valid(bus_pin)) + dev_priv->vbt.crt_ddc_pin = bus_pin; + } else { + DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", + block_size); + } + } +} + +static void +parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct sdvo_device_mapping *p_mapping; + struct bdb_general_definitions *p_defs; + union child_device_config *p_child; + int i, child_device_num, count; + u16 block_size; + + p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); + if (!p_defs) { + DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); + return; + } + /* judge whether the size of child device meets the requirements. + * If the child device size obtained from general definition block + * is different with sizeof(struct child_device_config), skip the + * parsing of sdvo device info + */ + if (p_defs->child_dev_size != sizeof(*p_child)) { + /* different child dev size . Ignore it */ + DRM_DEBUG_KMS("different child size is found. Invalid.\n"); + return; + } + /* get the block size of general definitions */ + block_size = get_blocksize(p_defs); + /* get the number of child device */ + child_device_num = (block_size - sizeof(*p_defs)) / + sizeof(*p_child); + count = 0; + for (i = 0; i < child_device_num; i++) { + p_child = &(p_defs->devices[i]); + if (!p_child->old.device_type) { + /* skip the device block if device type is invalid */ + continue; + } + if (p_child->old.slave_addr != SLAVE_ADDR1 && + p_child->old.slave_addr != SLAVE_ADDR2) { + /* + * If the slave address is neither 0x70 nor 0x72, + * it is not a SDVO device. Skip it. + */ + continue; + } + if (p_child->old.dvo_port != DEVICE_PORT_DVOB && + p_child->old.dvo_port != DEVICE_PORT_DVOC) { + /* skip the incorrect SDVO port */ + DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); + continue; + } + DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" + " %s port\n", + p_child->old.slave_addr, + (p_child->old.dvo_port == DEVICE_PORT_DVOB) ? + "SDVOB" : "SDVOC"); + p_mapping = &(dev_priv->sdvo_mappings[p_child->old.dvo_port - 1]); + if (!p_mapping->initialized) { + p_mapping->dvo_port = p_child->old.dvo_port; + p_mapping->slave_addr = p_child->old.slave_addr; + p_mapping->dvo_wiring = p_child->old.dvo_wiring; + p_mapping->ddc_pin = p_child->old.ddc_pin; + p_mapping->i2c_pin = p_child->old.i2c_pin; + p_mapping->initialized = 1; + DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", + p_mapping->dvo_port, + p_mapping->slave_addr, + p_mapping->dvo_wiring, + p_mapping->ddc_pin, + p_mapping->i2c_pin); + } else { + DRM_DEBUG_KMS("Maybe one SDVO port is shared by " + "two SDVO device.\n"); + } + if (p_child->old.slave2_addr) { + /* Maybe this is a SDVO device with multiple inputs */ + /* And the mapping info is not added */ + DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" + " is a SDVO device with multiple inputs.\n"); + } + count++; + } + + if (!count) { + /* No SDVO device info is found */ + DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); + } + return; +} + +static void +parse_driver_features(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct bdb_driver_features *driver; + + driver = find_section(bdb, BDB_DRIVER_FEATURES); + if (!driver) + return; + + if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) + dev_priv->vbt.edp_support = 1; + + if (driver->dual_frequency) + dev_priv->render_reclock_avail = true; +} + +static void +parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + struct bdb_edp *edp; + struct edp_power_seq *edp_pps; + struct edp_link_params *edp_link_params; + + edp = find_section(bdb, BDB_EDP); + if (!edp) { + if (dev_priv->vbt.edp_support) + DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); + return; + } + + switch ((edp->color_depth >> (panel_type * 2)) & 3) { + case EDP_18BPP: + dev_priv->vbt.edp_bpp = 18; + break; + case EDP_24BPP: + dev_priv->vbt.edp_bpp = 24; + break; + case EDP_30BPP: + dev_priv->vbt.edp_bpp = 30; + break; + } + + /* Get the eDP sequencing and link info */ + edp_pps = &edp->power_seqs[panel_type]; + edp_link_params = &edp->link_params[panel_type]; + + dev_priv->vbt.edp_pps = *edp_pps; + + dev_priv->vbt.edp_rate = edp_link_params->rate ? DP_LINK_BW_2_7 : + DP_LINK_BW_1_62; + switch (edp_link_params->lanes) { + case 0: + dev_priv->vbt.edp_lanes = 1; + break; + case 1: + dev_priv->vbt.edp_lanes = 2; + break; + case 3: + default: + dev_priv->vbt.edp_lanes = 4; + break; + } + switch (edp_link_params->preemphasis) { + case 0: + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0; + break; + case 1: + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; + break; + case 2: + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6; + break; + case 3: + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; + break; + } + switch (edp_link_params->vswing) { + case 0: + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400; + break; + case 1: + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600; + break; + case 2: + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800; + break; + case 3: + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200; + break; + } +} + +static void +parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + struct bdb_mipi *mipi; + + mipi = find_section(bdb, BDB_MIPI); + if (!mipi) { + DRM_DEBUG_KMS("No MIPI BDB found"); + return; + } + + /* XXX: add more info */ + dev_priv->vbt.dsi.panel_id = mipi->panel_id; +} + +static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, + struct bdb_header *bdb) +{ + union child_device_config *it, *child = NULL; + struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; + uint8_t hdmi_level_shift; + int i, j; + bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; + uint8_t aux_channel; + /* Each DDI port can have more than one value on the "DVO Port" field, + * so look for all the possible values for each port and abort if more + * than one is found. */ + int dvo_ports[][2] = { + {DVO_PORT_HDMIA, DVO_PORT_DPA}, + {DVO_PORT_HDMIB, DVO_PORT_DPB}, + {DVO_PORT_HDMIC, DVO_PORT_DPC}, + {DVO_PORT_HDMID, DVO_PORT_DPD}, + {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, + }; + + /* Find the child device to use, abort if more than one found. */ + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + it = dev_priv->vbt.child_dev + i; + + for (j = 0; j < 2; j++) { + if (dvo_ports[port][j] == -1) + break; + + if (it->common.dvo_port == dvo_ports[port][j]) { + if (child) { + DRM_DEBUG_KMS("More than one child device for port %c in VBT.\n", + port_name(port)); + return; + } + child = it; + } + } + } + if (!child) + return; + + aux_channel = child->raw[25]; + + is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; + is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; + is_crt = child->common.device_type & DEVICE_TYPE_ANALOG_OUTPUT; + is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; + is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); + + info->supports_dvi = is_dvi; + info->supports_hdmi = is_hdmi; + info->supports_dp = is_dp; + + DRM_DEBUG_KMS("Port %c VBT info: DP:%d HDMI:%d DVI:%d EDP:%d CRT:%d\n", + port_name(port), is_dp, is_hdmi, is_dvi, is_edp, is_crt); + + if (is_edp && is_dvi) + DRM_DEBUG_KMS("Internal DP port %c is TMDS compatible\n", + port_name(port)); + if (is_crt && port != PORT_E) + DRM_DEBUG_KMS("Port %c is analog\n", port_name(port)); + if (is_crt && (is_dvi || is_dp)) + DRM_DEBUG_KMS("Analog port %c is also DP or TMDS compatible\n", + port_name(port)); + if (is_dvi && (port == PORT_A || port == PORT_E)) + DRM_DEBUG_KMS("Port %c is TMDS compabile\n", port_name(port)); + if (!is_dvi && !is_dp && !is_crt) + DRM_DEBUG_KMS("Port %c is not DP/TMDS/CRT compatible\n", + port_name(port)); + if (is_edp && (port == PORT_B || port == PORT_C || port == PORT_E)) + DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); + + if (is_dvi) { + if (child->common.ddc_pin == 0x05 && port != PORT_B) + DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); + if (child->common.ddc_pin == 0x04 && port != PORT_C) + DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); + if (child->common.ddc_pin == 0x06 && port != PORT_D) + DRM_DEBUG_KMS("Unexpected DDC pin for port D\n"); + } + + if (is_dp) { + if (aux_channel == 0x40 && port != PORT_A) + DRM_DEBUG_KMS("Unexpected AUX channel for port A\n"); + if (aux_channel == 0x10 && port != PORT_B) + DRM_DEBUG_KMS("Unexpected AUX channel for port B\n"); + if (aux_channel == 0x20 && port != PORT_C) + DRM_DEBUG_KMS("Unexpected AUX channel for port C\n"); + if (aux_channel == 0x30 && port != PORT_D) + DRM_DEBUG_KMS("Unexpected AUX channel for port D\n"); + } + + if (bdb->version >= 158) { + /* The VBT HDMI level shift values match the table we have. */ + hdmi_level_shift = child->raw[7] & 0xF; + if (hdmi_level_shift < 0xC) { + DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", + port_name(port), + hdmi_level_shift); + info->hdmi_level_shift = hdmi_level_shift; + } + } +} + +static void parse_ddi_ports(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct drm_device *dev = dev_priv->dev; + enum port port; + + if (!HAS_DDI(dev)) + return; + + if (!dev_priv->vbt.child_dev_num) + return; + + if (bdb->version < 155) + return; + + for (port = PORT_A; port < I915_MAX_PORTS; port++) + parse_ddi_port(dev_priv, port, bdb); +} + +static void +parse_device_mapping(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct bdb_general_definitions *p_defs; + union child_device_config *p_child, *child_dev_ptr; + int i, child_device_num, count; + u16 block_size; + + p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); + if (!p_defs) { + DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); + return; + } + /* judge whether the size of child device meets the requirements. + * If the child device size obtained from general definition block + * is different with sizeof(struct child_device_config), skip the + * parsing of sdvo device info + */ + if (p_defs->child_dev_size != sizeof(*p_child)) { + /* different child dev size . Ignore it */ + DRM_DEBUG_KMS("different child size is found. Invalid.\n"); + return; + } + /* get the block size of general definitions */ + block_size = get_blocksize(p_defs); + /* get the number of child device */ + child_device_num = (block_size - sizeof(*p_defs)) / + sizeof(*p_child); + count = 0; + /* get the number of child device that is present */ + for (i = 0; i < child_device_num; i++) { + p_child = &(p_defs->devices[i]); + if (!p_child->common.device_type) { + /* skip the device block if device type is invalid */ + continue; + } + count++; + } + if (!count) { + DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); + return; + } + dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); + if (!dev_priv->vbt.child_dev) { + DRM_DEBUG_KMS("No memory space for child device\n"); + return; + } + + dev_priv->vbt.child_dev_num = count; + count = 0; + for (i = 0; i < child_device_num; i++) { + p_child = &(p_defs->devices[i]); + if (!p_child->common.device_type) { + /* skip the device block if device type is invalid */ + continue; + } + child_dev_ptr = dev_priv->vbt.child_dev + count; + count++; + memcpy((void *)child_dev_ptr, (void *)p_child, + sizeof(*p_child)); + } + return; +} + +static void +init_vbt_defaults(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + enum port port; + + dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; + + /* LFP panel data */ + dev_priv->vbt.lvds_dither = 1; + dev_priv->vbt.lvds_vbt = 0; + + /* SDVO panel data */ + dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; + + /* general features */ + dev_priv->vbt.int_tv_support = 1; + dev_priv->vbt.int_crt_support = 1; + + /* Default to using SSC */ + dev_priv->vbt.lvds_use_ssc = 1; + /* + * Core/SandyBridge/IvyBridge use alternative (120MHz) reference + * clock for LVDS. + */ + dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, + !HAS_PCH_SPLIT(dev)); + DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); + + for (port = PORT_A; port < I915_MAX_PORTS; port++) { + struct ddi_vbt_port_info *info = + &dev_priv->vbt.ddi_port_info[port]; + + /* Recommended BSpec default: 800mV 0dB. */ + info->hdmi_level_shift = 6; + + info->supports_dvi = (port != PORT_A && port != PORT_E); + info->supports_hdmi = info->supports_dvi; + info->supports_dp = (port != PORT_E); + } +} + +static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) +{ + DRM_DEBUG_KMS("Falling back to manually reading VBT from " + "VBIOS ROM for %s\n", + id->ident); + return 1; +} + +static const struct dmi_system_id intel_no_opregion_vbt[] = { + { + .callback = intel_no_opregion_vbt_callback, + .ident = "ThinkCentre A57", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"), + }, + }, + { } +}; + +/** + * intel_parse_bios - find VBT and initialize settings from the BIOS + * @dev: DRM device + * + * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers + * to appropriate values. + * + * Returns 0 on success, nonzero on failure. + */ +int +intel_parse_bios(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev->pdev; + struct bdb_header *bdb = NULL; + u8 __iomem *bios = NULL; + + if (HAS_PCH_NOP(dev)) + return -ENODEV; + + init_vbt_defaults(dev_priv); + + /* XXX Should this validation be moved to intel_opregion.c? */ + if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) { + struct vbt_header *vbt = dev_priv->opregion.vbt; + if (memcmp(vbt->signature, "$VBT", 4) == 0) { + DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n", + vbt->signature); + bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); + } else + dev_priv->opregion.vbt = NULL; + } + + if (bdb == NULL) { + struct vbt_header *vbt = NULL; + size_t size; + int i; + + bios = pci_map_rom(pdev, &size); + if (!bios) + return -1; + + /* Scour memory looking for the VBT signature */ + for (i = 0; i + 4 < size; i++) { + if (!memcmp(bios + i, "$VBT", 4)) { + vbt = (struct vbt_header *)(bios + i); + break; + } + } + + if (!vbt) { + DRM_DEBUG_DRIVER("VBT signature missing\n"); + pci_unmap_rom(pdev, bios); + return -1; + } + + bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); + } + + /* Grab useful general definitions */ + parse_general_features(dev_priv, bdb); + parse_general_definitions(dev_priv, bdb); + parse_lfp_panel_data(dev_priv, bdb); + parse_lfp_backlight(dev_priv, bdb); + parse_sdvo_panel_data(dev_priv, bdb); + parse_sdvo_device_mapping(dev_priv, bdb); + parse_device_mapping(dev_priv, bdb); + parse_driver_features(dev_priv, bdb); + parse_edp(dev_priv, bdb); + parse_mipi(dev_priv, bdb); + parse_ddi_ports(dev_priv, bdb); + + if (bios) + pci_unmap_rom(pdev, bios); + + return 0; +} + +/* Ensure that vital registers have been initialised, even if the BIOS + * is absent or just failing to do its job. + */ +void intel_setup_bios(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Set the Panel Power On/Off timings if uninitialized. */ + if (!HAS_PCH_SPLIT(dev) && + I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) { + /* Set T2 to 40ms and T5 to 200ms */ + I915_WRITE(PP_ON_DELAYS, 0x019007d0); + + /* Set T3 to 35ms and Tx to 200ms */ + I915_WRITE(PP_OFF_DELAYS, 0x015e07d0); + } +} --- linux-3.13.0.orig/ubuntu/i915/intel_opregion.c +++ linux-3.13.0/ubuntu/i915/intel_opregion.c @@ -0,0 +1,902 @@ +/* + * Copyright 2008 Intel Corporation + * Copyright 2008 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#include +#include +#include "i915_drv.h" +#include "intel_drv.h" + +#define PCI_ASLE 0xe4 +#define PCI_ASLS 0xfc +#define PCI_SWSCI 0xe8 +#define PCI_SWSCI_SCISEL (1 << 15) +#define PCI_SWSCI_GSSCIE (1 << 0) + +#define OPREGION_HEADER_OFFSET 0 +#define OPREGION_ACPI_OFFSET 0x100 +#define ACPI_CLID 0x01ac /* current lid state indicator */ +#define ACPI_CDCK 0x01b0 /* current docking state indicator */ +#define OPREGION_SWSCI_OFFSET 0x200 +#define OPREGION_ASLE_OFFSET 0x300 +#define OPREGION_VBT_OFFSET 0x400 + +#define OPREGION_SIGNATURE "IntelGraphicsMem" +#define MBOX_ACPI (1<<0) +#define MBOX_SWSCI (1<<1) +#define MBOX_ASLE (1<<2) + +struct opregion_header { + u8 signature[16]; + u32 size; + u32 opregion_ver; + u8 bios_ver[32]; + u8 vbios_ver[16]; + u8 driver_ver[16]; + u32 mboxes; + u8 reserved[164]; +} __packed; + +/* OpRegion mailbox #1: public ACPI methods */ +struct opregion_acpi { + u32 drdy; /* driver readiness */ + u32 csts; /* notification status */ + u32 cevt; /* current event */ + u8 rsvd1[20]; + u32 didl[8]; /* supported display devices ID list */ + u32 cpdl[8]; /* currently presented display list */ + u32 cadl[8]; /* currently active display list */ + u32 nadl[8]; /* next active devices list */ + u32 aslp; /* ASL sleep time-out */ + u32 tidx; /* toggle table index */ + u32 chpd; /* current hotplug enable indicator */ + u32 clid; /* current lid state*/ + u32 cdck; /* current docking state */ + u32 sxsw; /* Sx state resume */ + u32 evts; /* ASL supported events */ + u32 cnot; /* current OS notification */ + u32 nrdy; /* driver status */ + u8 rsvd2[60]; +} __packed; + +/* OpRegion mailbox #2: SWSCI */ +struct opregion_swsci { + u32 scic; /* SWSCI command|status|data */ + u32 parm; /* command parameters */ + u32 dslp; /* driver sleep time-out */ + u8 rsvd[244]; +} __packed; + +/* OpRegion mailbox #3: ASLE */ +struct opregion_asle { + u32 ardy; /* driver readiness */ + u32 aslc; /* ASLE interrupt command */ + u32 tche; /* technology enabled indicator */ + u32 alsi; /* current ALS illuminance reading */ + u32 bclp; /* backlight brightness to set */ + u32 pfit; /* panel fitting state */ + u32 cblv; /* current brightness level */ + u16 bclm[20]; /* backlight level duty cycle mapping table */ + u32 cpfm; /* current panel fitting mode */ + u32 epfm; /* enabled panel fitting modes */ + u8 plut[74]; /* panel LUT and identifier */ + u32 pfmb; /* PWM freq and min brightness */ + u32 cddv; /* color correction default values */ + u32 pcft; /* power conservation features */ + u32 srot; /* supported rotation angles */ + u32 iuer; /* IUER events */ + u8 rsvd[86]; +} __packed; + +/* Driver readiness indicator */ +#define ASLE_ARDY_READY (1 << 0) +#define ASLE_ARDY_NOT_READY (0 << 0) + +/* ASLE Interrupt Command (ASLC) bits */ +#define ASLC_SET_ALS_ILLUM (1 << 0) +#define ASLC_SET_BACKLIGHT (1 << 1) +#define ASLC_SET_PFIT (1 << 2) +#define ASLC_SET_PWM_FREQ (1 << 3) +#define ASLC_SUPPORTED_ROTATION_ANGLES (1 << 4) +#define ASLC_BUTTON_ARRAY (1 << 5) +#define ASLC_CONVERTIBLE_INDICATOR (1 << 6) +#define ASLC_DOCKING_INDICATOR (1 << 7) +#define ASLC_ISCT_STATE_CHANGE (1 << 8) +#define ASLC_REQ_MSK 0x1ff +/* response bits */ +#define ASLC_ALS_ILLUM_FAILED (1 << 10) +#define ASLC_BACKLIGHT_FAILED (1 << 12) +#define ASLC_PFIT_FAILED (1 << 14) +#define ASLC_PWM_FREQ_FAILED (1 << 16) +#define ASLC_ROTATION_ANGLES_FAILED (1 << 18) +#define ASLC_BUTTON_ARRAY_FAILED (1 << 20) +#define ASLC_CONVERTIBLE_FAILED (1 << 22) +#define ASLC_DOCKING_FAILED (1 << 24) +#define ASLC_ISCT_STATE_FAILED (1 << 26) + +/* Technology enabled indicator */ +#define ASLE_TCHE_ALS_EN (1 << 0) +#define ASLE_TCHE_BLC_EN (1 << 1) +#define ASLE_TCHE_PFIT_EN (1 << 2) +#define ASLE_TCHE_PFMB_EN (1 << 3) + +/* ASLE backlight brightness to set */ +#define ASLE_BCLP_VALID (1<<31) +#define ASLE_BCLP_MSK (~(1<<31)) + +/* ASLE panel fitting request */ +#define ASLE_PFIT_VALID (1<<31) +#define ASLE_PFIT_CENTER (1<<0) +#define ASLE_PFIT_STRETCH_TEXT (1<<1) +#define ASLE_PFIT_STRETCH_GFX (1<<2) + +/* PWM frequency and minimum brightness */ +#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) +#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) +#define ASLE_PFMB_PWM_MASK (0x7ffffe00) +#define ASLE_PFMB_PWM_VALID (1<<31) + +#define ASLE_CBLV_VALID (1<<31) + +/* IUER */ +#define ASLE_IUER_DOCKING (1 << 7) +#define ASLE_IUER_CONVERTIBLE (1 << 6) +#define ASLE_IUER_ROTATION_LOCK_BTN (1 << 4) +#define ASLE_IUER_VOLUME_DOWN_BTN (1 << 3) +#define ASLE_IUER_VOLUME_UP_BTN (1 << 2) +#define ASLE_IUER_WINDOWS_BTN (1 << 1) +#define ASLE_IUER_POWER_BTN (1 << 0) + +/* Software System Control Interrupt (SWSCI) */ +#define SWSCI_SCIC_INDICATOR (1 << 0) +#define SWSCI_SCIC_MAIN_FUNCTION_SHIFT 1 +#define SWSCI_SCIC_MAIN_FUNCTION_MASK (0xf << 1) +#define SWSCI_SCIC_SUB_FUNCTION_SHIFT 8 +#define SWSCI_SCIC_SUB_FUNCTION_MASK (0xff << 8) +#define SWSCI_SCIC_EXIT_PARAMETER_SHIFT 8 +#define SWSCI_SCIC_EXIT_PARAMETER_MASK (0xff << 8) +#define SWSCI_SCIC_EXIT_STATUS_SHIFT 5 +#define SWSCI_SCIC_EXIT_STATUS_MASK (7 << 5) +#define SWSCI_SCIC_EXIT_STATUS_SUCCESS 1 + +#define SWSCI_FUNCTION_CODE(main, sub) \ + ((main) << SWSCI_SCIC_MAIN_FUNCTION_SHIFT | \ + (sub) << SWSCI_SCIC_SUB_FUNCTION_SHIFT) + +/* SWSCI: Get BIOS Data (GBDA) */ +#define SWSCI_GBDA 4 +#define SWSCI_GBDA_SUPPORTED_CALLS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 0) +#define SWSCI_GBDA_REQUESTED_CALLBACKS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 1) +#define SWSCI_GBDA_BOOT_DISPLAY_PREF SWSCI_FUNCTION_CODE(SWSCI_GBDA, 4) +#define SWSCI_GBDA_PANEL_DETAILS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 5) +#define SWSCI_GBDA_TV_STANDARD SWSCI_FUNCTION_CODE(SWSCI_GBDA, 6) +#define SWSCI_GBDA_INTERNAL_GRAPHICS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 7) +#define SWSCI_GBDA_SPREAD_SPECTRUM SWSCI_FUNCTION_CODE(SWSCI_GBDA, 10) + +/* SWSCI: System BIOS Callbacks (SBCB) */ +#define SWSCI_SBCB 6 +#define SWSCI_SBCB_SUPPORTED_CALLBACKS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 0) +#define SWSCI_SBCB_INIT_COMPLETION SWSCI_FUNCTION_CODE(SWSCI_SBCB, 1) +#define SWSCI_SBCB_PRE_HIRES_SET_MODE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 3) +#define SWSCI_SBCB_POST_HIRES_SET_MODE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 4) +#define SWSCI_SBCB_DISPLAY_SWITCH SWSCI_FUNCTION_CODE(SWSCI_SBCB, 5) +#define SWSCI_SBCB_SET_TV_FORMAT SWSCI_FUNCTION_CODE(SWSCI_SBCB, 6) +#define SWSCI_SBCB_ADAPTER_POWER_STATE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 7) +#define SWSCI_SBCB_DISPLAY_POWER_STATE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 8) +#define SWSCI_SBCB_SET_BOOT_DISPLAY SWSCI_FUNCTION_CODE(SWSCI_SBCB, 9) +#define SWSCI_SBCB_SET_PANEL_DETAILS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 10) +#define SWSCI_SBCB_SET_INTERNAL_GFX SWSCI_FUNCTION_CODE(SWSCI_SBCB, 11) +#define SWSCI_SBCB_POST_HIRES_TO_DOS_FS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 16) +#define SWSCI_SBCB_SUSPEND_RESUME SWSCI_FUNCTION_CODE(SWSCI_SBCB, 17) +#define SWSCI_SBCB_SET_SPREAD_SPECTRUM SWSCI_FUNCTION_CODE(SWSCI_SBCB, 18) +#define SWSCI_SBCB_POST_VBE_PM SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19) +#define SWSCI_SBCB_ENABLE_DISABLE_AUDIO SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21) + +#define ACPI_OTHER_OUTPUT (0<<8) +#define ACPI_VGA_OUTPUT (1<<8) +#define ACPI_TV_OUTPUT (2<<8) +#define ACPI_DIGITAL_OUTPUT (3<<8) +#define ACPI_LVDS_OUTPUT (4<<8) + +#define MAX_DSLP 1500 + +#ifdef CONFIG_ACPI +static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_swsci __iomem *swsci = dev_priv->opregion.swsci; + u32 main_function, sub_function, scic; + u16 pci_swsci; + u32 dslp; + + if (!swsci) + return -ENODEV; + + main_function = (function & SWSCI_SCIC_MAIN_FUNCTION_MASK) >> + SWSCI_SCIC_MAIN_FUNCTION_SHIFT; + sub_function = (function & SWSCI_SCIC_SUB_FUNCTION_MASK) >> + SWSCI_SCIC_SUB_FUNCTION_SHIFT; + + /* Check if we can call the function. See swsci_setup for details. */ + if (main_function == SWSCI_SBCB) { + if ((dev_priv->opregion.swsci_sbcb_sub_functions & + (1 << sub_function)) == 0) + return -EINVAL; + } else if (main_function == SWSCI_GBDA) { + if ((dev_priv->opregion.swsci_gbda_sub_functions & + (1 << sub_function)) == 0) + return -EINVAL; + } + + /* Driver sleep timeout in ms. */ + dslp = ioread32(&swsci->dslp); + if (!dslp) { + /* The spec says 2ms should be the default, but it's too small + * for some machines. */ + dslp = 50; + } else if (dslp > MAX_DSLP) { + /* Hey bios, trust must be earned. */ + DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, " + "using %u ms instead\n", dslp, MAX_DSLP); + dslp = MAX_DSLP; + } + + /* The spec tells us to do this, but we are the only user... */ + scic = ioread32(&swsci->scic); + if (scic & SWSCI_SCIC_INDICATOR) { + DRM_DEBUG_DRIVER("SWSCI request already in progress\n"); + return -EBUSY; + } + + scic = function | SWSCI_SCIC_INDICATOR; + + iowrite32(parm, &swsci->parm); + iowrite32(scic, &swsci->scic); + + /* Ensure SCI event is selected and event trigger is cleared. */ + pci_read_config_word(dev->pdev, PCI_SWSCI, &pci_swsci); + if (!(pci_swsci & PCI_SWSCI_SCISEL) || (pci_swsci & PCI_SWSCI_GSSCIE)) { + pci_swsci |= PCI_SWSCI_SCISEL; + pci_swsci &= ~PCI_SWSCI_GSSCIE; + pci_write_config_word(dev->pdev, PCI_SWSCI, pci_swsci); + } + + /* Use event trigger to tell bios to check the mail. */ + pci_swsci |= PCI_SWSCI_GSSCIE; + pci_write_config_word(dev->pdev, PCI_SWSCI, pci_swsci); + + /* Poll for the result. */ +#define C (((scic = ioread32(&swsci->scic)) & SWSCI_SCIC_INDICATOR) == 0) + if (wait_for(C, dslp)) { + DRM_DEBUG_DRIVER("SWSCI request timed out\n"); + return -ETIMEDOUT; + } + + scic = (scic & SWSCI_SCIC_EXIT_STATUS_MASK) >> + SWSCI_SCIC_EXIT_STATUS_SHIFT; + + /* Note: scic == 0 is an error! */ + if (scic != SWSCI_SCIC_EXIT_STATUS_SUCCESS) { + DRM_DEBUG_DRIVER("SWSCI request error %u\n", scic); + return -EIO; + } + + if (parm_out) + *parm_out = ioread32(&swsci->parm); + + return 0; + +#undef C +} + +#define DISPLAY_TYPE_CRT 0 +#define DISPLAY_TYPE_TV 1 +#define DISPLAY_TYPE_EXTERNAL_FLAT_PANEL 2 +#define DISPLAY_TYPE_INTERNAL_FLAT_PANEL 3 + +int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, + bool enable) +{ + struct drm_device *dev = intel_encoder->base.dev; + u32 parm = 0; + u32 type = 0; + u32 port; + + /* don't care about old stuff for now */ + if (!HAS_DDI(dev)) + return 0; + + port = intel_ddi_get_encoder_port(intel_encoder); + if (port == PORT_E) { + port = 0; + } else { + parm |= 1 << port; + port++; + } + + if (!enable) + parm |= 4 << 8; + + switch (intel_encoder->type) { + case INTEL_OUTPUT_ANALOG: + type = DISPLAY_TYPE_CRT; + break; + case INTEL_OUTPUT_UNKNOWN: + case INTEL_OUTPUT_DISPLAYPORT: + case INTEL_OUTPUT_HDMI: + type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL; + break; + case INTEL_OUTPUT_EDP: + type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL; + break; + default: + WARN_ONCE(1, "unsupported intel_encoder type %d\n", + intel_encoder->type); + return -EINVAL; + } + + parm |= type << (16 + port * 3); + + return swsci(dev, SWSCI_SBCB_DISPLAY_POWER_STATE, parm, NULL); +} + +static const struct { + pci_power_t pci_power_state; + u32 parm; +} power_state_map[] = { + { PCI_D0, 0x00 }, + { PCI_D1, 0x01 }, + { PCI_D2, 0x02 }, + { PCI_D3hot, 0x04 }, + { PCI_D3cold, 0x04 }, +}; + +int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) +{ + int i; + + if (!HAS_DDI(dev)) + return 0; + + for (i = 0; i < ARRAY_SIZE(power_state_map); i++) { + if (state == power_state_map[i].pci_power_state) + return swsci(dev, SWSCI_SBCB_ADAPTER_POWER_STATE, + power_state_map[i].parm, NULL); + } + + return -EINVAL; +} + +static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_connector *intel_connector; + struct opregion_asle __iomem *asle = dev_priv->opregion.asle; + + DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); + + if (!(bclp & ASLE_BCLP_VALID)) + return ASLC_BACKLIGHT_FAILED; + + bclp &= ASLE_BCLP_MSK; + if (bclp > 255) + return ASLC_BACKLIGHT_FAILED; + + mutex_lock(&dev->mode_config.mutex); + + /* + * Update backlight on all connectors that support backlight (usually + * only one). + */ + DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp); + list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) + intel_panel_set_backlight(intel_connector, bclp, 255); + iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); + + mutex_unlock(&dev->mode_config.mutex); + + + return 0; +} + +static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) +{ + /* alsi is the current ALS reading in lux. 0 indicates below sensor + range, 0xffff indicates above sensor range. 1-0xfffe are valid */ + DRM_DEBUG_DRIVER("Illum is not supported\n"); + return ASLC_ALS_ILLUM_FAILED; +} + +static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) +{ + DRM_DEBUG_DRIVER("PWM freq is not supported\n"); + return ASLC_PWM_FREQ_FAILED; +} + +static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) +{ + /* Panel fitting is currently controlled by the X code, so this is a + noop until modesetting support works fully */ + DRM_DEBUG_DRIVER("Pfit is not supported\n"); + return ASLC_PFIT_FAILED; +} + +static u32 asle_set_supported_rotation_angles(struct drm_device *dev, u32 srot) +{ + DRM_DEBUG_DRIVER("SROT is not supported\n"); + return ASLC_ROTATION_ANGLES_FAILED; +} + +static u32 asle_set_button_array(struct drm_device *dev, u32 iuer) +{ + if (!iuer) + DRM_DEBUG_DRIVER("Button array event is not supported (nothing)\n"); + if (iuer & ASLE_IUER_ROTATION_LOCK_BTN) + DRM_DEBUG_DRIVER("Button array event is not supported (rotation lock)\n"); + if (iuer & ASLE_IUER_VOLUME_DOWN_BTN) + DRM_DEBUG_DRIVER("Button array event is not supported (volume down)\n"); + if (iuer & ASLE_IUER_VOLUME_UP_BTN) + DRM_DEBUG_DRIVER("Button array event is not supported (volume up)\n"); + if (iuer & ASLE_IUER_WINDOWS_BTN) + DRM_DEBUG_DRIVER("Button array event is not supported (windows)\n"); + if (iuer & ASLE_IUER_POWER_BTN) + DRM_DEBUG_DRIVER("Button array event is not supported (power)\n"); + + return ASLC_BUTTON_ARRAY_FAILED; +} + +static u32 asle_set_convertible(struct drm_device *dev, u32 iuer) +{ + if (iuer & ASLE_IUER_CONVERTIBLE) + DRM_DEBUG_DRIVER("Convertible is not supported (clamshell)\n"); + else + DRM_DEBUG_DRIVER("Convertible is not supported (slate)\n"); + + return ASLC_CONVERTIBLE_FAILED; +} + +static u32 asle_set_docking(struct drm_device *dev, u32 iuer) +{ + if (iuer & ASLE_IUER_DOCKING) + DRM_DEBUG_DRIVER("Docking is not supported (docked)\n"); + else + DRM_DEBUG_DRIVER("Docking is not supported (undocked)\n"); + + return ASLC_DOCKING_FAILED; +} + +static u32 asle_isct_state(struct drm_device *dev) +{ + DRM_DEBUG_DRIVER("ISCT is not supported\n"); + return ASLC_ISCT_STATE_FAILED; +} + +static void asle_work(struct work_struct *work) +{ + struct intel_opregion *opregion = + container_of(work, struct intel_opregion, asle_work); + struct drm_i915_private *dev_priv = + container_of(opregion, struct drm_i915_private, opregion); + struct drm_device *dev = dev_priv->dev; + struct opregion_asle __iomem *asle = dev_priv->opregion.asle; + u32 aslc_stat = 0; + u32 aslc_req; + + if (!asle) + return; + + aslc_req = ioread32(&asle->aslc); + + if (!(aslc_req & ASLC_REQ_MSK)) { + DRM_DEBUG_DRIVER("No request on ASLC interrupt 0x%08x\n", + aslc_req); + return; + } + + if (aslc_req & ASLC_SET_ALS_ILLUM) + aslc_stat |= asle_set_als_illum(dev, ioread32(&asle->alsi)); + + if (aslc_req & ASLC_SET_BACKLIGHT) + aslc_stat |= asle_set_backlight(dev, ioread32(&asle->bclp)); + + if (aslc_req & ASLC_SET_PFIT) + aslc_stat |= asle_set_pfit(dev, ioread32(&asle->pfit)); + + if (aslc_req & ASLC_SET_PWM_FREQ) + aslc_stat |= asle_set_pwm_freq(dev, ioread32(&asle->pfmb)); + + if (aslc_req & ASLC_SUPPORTED_ROTATION_ANGLES) + aslc_stat |= asle_set_supported_rotation_angles(dev, + ioread32(&asle->srot)); + + if (aslc_req & ASLC_BUTTON_ARRAY) + aslc_stat |= asle_set_button_array(dev, ioread32(&asle->iuer)); + + if (aslc_req & ASLC_CONVERTIBLE_INDICATOR) + aslc_stat |= asle_set_convertible(dev, ioread32(&asle->iuer)); + + if (aslc_req & ASLC_DOCKING_INDICATOR) + aslc_stat |= asle_set_docking(dev, ioread32(&asle->iuer)); + + if (aslc_req & ASLC_ISCT_STATE_CHANGE) + aslc_stat |= asle_isct_state(dev); + + iowrite32(aslc_stat, &asle->aslc); +} + +void intel_opregion_asle_intr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->opregion.asle) + schedule_work(&dev_priv->opregion.asle_work); +} + +#define ACPI_EV_DISPLAY_SWITCH (1<<0) +#define ACPI_EV_LID (1<<1) +#define ACPI_EV_DOCK (1<<2) + +static struct intel_opregion *system_opregion; + +static int intel_opregion_video_event(struct notifier_block *nb, + unsigned long val, void *data) +{ + /* The only video events relevant to opregion are 0x80. These indicate + either a docking event, lid switch or display switch request. In + Linux, these are handled by the dock, button and video drivers. + */ + + struct opregion_acpi __iomem *acpi; + struct acpi_bus_event *event = data; + int ret = NOTIFY_OK; + + if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) + return NOTIFY_DONE; + + if (!system_opregion) + return NOTIFY_DONE; + + acpi = system_opregion->acpi; + + if (event->type == 0x80 && + (ioread32(&acpi->cevt) & 1) == 0) + ret = NOTIFY_BAD; + + iowrite32(0, &acpi->csts); + + return ret; +} + +static struct notifier_block intel_opregion_notifier = { + .notifier_call = intel_opregion_video_event, +}; + +/* + * Initialise the DIDL field in opregion. This passes a list of devices to + * the firmware. Values are defined by section B.4.2 of the ACPI specification + * (version 3) + */ + +static void intel_didl_outputs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + struct drm_connector *connector; + acpi_handle handle; + struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; + unsigned long long device_id; + acpi_status status; + u32 temp; + int i = 0; + + handle = ACPI_HANDLE(&dev->pdev->dev); + if (!handle || acpi_bus_get_device(handle, &acpi_dev)) + return; + + if (acpi_is_video_device(handle)) + acpi_video_bus = acpi_dev; + else { + list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { + if (acpi_is_video_device(acpi_cdev->handle)) { + acpi_video_bus = acpi_cdev; + break; + } + } + } + + if (!acpi_video_bus) { + pr_warn("No ACPI video bus found\n"); + return; + } + + list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { + if (i >= 8) { + dev_dbg(&dev->pdev->dev, + "More than 8 outputs detected via ACPI\n"); + return; + } + status = + acpi_evaluate_integer(acpi_cdev->handle, "_ADR", + NULL, &device_id); + if (ACPI_SUCCESS(status)) { + if (!device_id) + goto blind_set; + iowrite32((u32)(device_id & 0x0f0f), + &opregion->acpi->didl[i]); + i++; + } + } + +end: + /* If fewer than 8 outputs, the list must be null terminated */ + if (i < 8) + iowrite32(0, &opregion->acpi->didl[i]); + return; + +blind_set: + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + int output_type = ACPI_OTHER_OUTPUT; + if (i >= 8) { + dev_dbg(&dev->pdev->dev, + "More than 8 outputs in connector list\n"); + return; + } + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_DVIA: + output_type = ACPI_VGA_OUTPUT; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + case DRM_MODE_CONNECTOR_9PinDIN: + output_type = ACPI_TV_OUTPUT; + break; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + output_type = ACPI_DIGITAL_OUTPUT; + break; + case DRM_MODE_CONNECTOR_LVDS: + output_type = ACPI_LVDS_OUTPUT; + break; + } + temp = ioread32(&opregion->acpi->didl[i]); + iowrite32(temp | (1<<31) | output_type | i, + &opregion->acpi->didl[i]); + i++; + } + goto end; +} + +static void intel_setup_cadls(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + int i = 0; + u32 disp_id; + + /* Initialize the CADL field by duplicating the DIDL values. + * Technically, this is not always correct as display outputs may exist, + * but not active. This initialization is necessary for some Clevo + * laptops that check this field before processing the brightness and + * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if + * there are less than eight devices. */ + do { + disp_id = ioread32(&opregion->acpi->didl[i]); + iowrite32(disp_id, &opregion->acpi->cadl[i]); + } while (++i < 8 && disp_id != 0); +} + +void intel_opregion_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + + if (!opregion->header) + return; + + if (opregion->acpi) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + intel_didl_outputs(dev); + intel_setup_cadls(dev); + } + + /* Notify BIOS we are ready to handle ACPI video ext notifs. + * Right now, all the events are handled by the ACPI video module. + * We don't actually need to do anything with them. */ + iowrite32(0, &opregion->acpi->csts); + iowrite32(1, &opregion->acpi->drdy); + + system_opregion = opregion; + register_acpi_notifier(&intel_opregion_notifier); + } + + if (opregion->asle) { + iowrite32(ASLE_TCHE_BLC_EN, &opregion->asle->tche); + iowrite32(ASLE_ARDY_READY, &opregion->asle->ardy); + } +} + +void intel_opregion_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + + if (!opregion->header) + return; + + if (opregion->asle) + iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy); + + cancel_work_sync(&dev_priv->opregion.asle_work); + + if (opregion->acpi) { + iowrite32(0, &opregion->acpi->drdy); + + system_opregion = NULL; + unregister_acpi_notifier(&intel_opregion_notifier); + } + + /* just clear all opregion memory pointers now */ + iounmap(opregion->header); + opregion->header = NULL; + opregion->acpi = NULL; + opregion->swsci = NULL; + opregion->asle = NULL; + opregion->vbt = NULL; + opregion->lid_state = NULL; +} + +static void swsci_setup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + bool requested_callbacks = false; + u32 tmp; + + /* Sub-function code 0 is okay, let's allow them. */ + opregion->swsci_gbda_sub_functions = 1; + opregion->swsci_sbcb_sub_functions = 1; + + /* We use GBDA to ask for supported GBDA calls. */ + if (swsci(dev, SWSCI_GBDA_SUPPORTED_CALLS, 0, &tmp) == 0) { + /* make the bits match the sub-function codes */ + tmp <<= 1; + opregion->swsci_gbda_sub_functions |= tmp; + } + + /* + * We also use GBDA to ask for _requested_ SBCB callbacks. The driver + * must not call interfaces that are not specifically requested by the + * bios. + */ + if (swsci(dev, SWSCI_GBDA_REQUESTED_CALLBACKS, 0, &tmp) == 0) { + /* here, the bits already match sub-function codes */ + opregion->swsci_sbcb_sub_functions |= tmp; + requested_callbacks = true; + } + + /* + * But we use SBCB to ask for _supported_ SBCB calls. This does not mean + * the callback is _requested_. But we still can't call interfaces that + * are not requested. + */ + if (swsci(dev, SWSCI_SBCB_SUPPORTED_CALLBACKS, 0, &tmp) == 0) { + /* make the bits match the sub-function codes */ + u32 low = tmp & 0x7ff; + u32 high = tmp & ~0xfff; /* bit 11 is reserved */ + tmp = (high << 4) | (low << 1) | 1; + + /* best guess what to do with supported wrt requested */ + if (requested_callbacks) { + u32 req = opregion->swsci_sbcb_sub_functions; + if ((req & tmp) != req) + DRM_DEBUG_DRIVER("SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n", req, tmp); + /* XXX: for now, trust the requested callbacks */ + /* opregion->swsci_sbcb_sub_functions &= tmp; */ + } else { + opregion->swsci_sbcb_sub_functions |= tmp; + } + } + + DRM_DEBUG_DRIVER("SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n", + opregion->swsci_gbda_sub_functions, + opregion->swsci_sbcb_sub_functions); +} +#else /* CONFIG_ACPI */ +static inline void swsci_setup(struct drm_device *dev) {} +#endif /* CONFIG_ACPI */ + +int intel_opregion_setup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + void __iomem *base; + u32 asls, mboxes; + char buf[sizeof(OPREGION_SIGNATURE)]; + int err = 0; + + pci_read_config_dword(dev->pdev, PCI_ASLS, &asls); + DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls); + if (asls == 0) { + DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n"); + return -ENOTSUPP; + } + +#ifdef CONFIG_ACPI + INIT_WORK(&opregion->asle_work, asle_work); +#endif + + base = acpi_os_ioremap(asls, OPREGION_SIZE); + if (!base) + return -ENOMEM; + + memcpy_fromio(buf, base, sizeof(buf)); + + if (memcmp(buf, OPREGION_SIGNATURE, 16)) { + DRM_DEBUG_DRIVER("opregion signature mismatch\n"); + err = -EINVAL; + goto err_out; + } + opregion->header = base; + opregion->vbt = base + OPREGION_VBT_OFFSET; + + opregion->lid_state = base + ACPI_CLID; + + mboxes = ioread32(&opregion->header->mboxes); + if (mboxes & MBOX_ACPI) { + DRM_DEBUG_DRIVER("Public ACPI methods supported\n"); + opregion->acpi = base + OPREGION_ACPI_OFFSET; + } + + if (mboxes & MBOX_SWSCI) { + DRM_DEBUG_DRIVER("SWSCI supported\n"); + opregion->swsci = base + OPREGION_SWSCI_OFFSET; + swsci_setup(dev); + } + if (mboxes & MBOX_ASLE) { + DRM_DEBUG_DRIVER("ASLE supported\n"); + opregion->asle = base + OPREGION_ASLE_OFFSET; + + iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy); + } + + return 0; + +err_out: + iounmap(base); + return err; +} --- linux-3.13.0.orig/ubuntu/i915/intel_sdvo.c +++ linux-3.13.0/ubuntu/i915/intel_sdvo.c @@ -0,0 +1,3025 @@ +/* + * Copyright 2006 Dave Airlie + * Copyright © 2006-2007 Intel Corporation + * Jesse Barnes + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ +#include +#include +#include +#include +#include +#include +#include +#include "intel_drv.h" +#include +#include "i915_drv.h" +#include "intel_sdvo_regs.h" + +#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) +#define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) +#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1) +#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0) + +#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\ + SDVO_TV_MASK) + +#define IS_TV(c) (c->output_flag & SDVO_TV_MASK) +#define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK) +#define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) +#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) +#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK)) + + +static const char *tv_format_names[] = { + "NTSC_M" , "NTSC_J" , "NTSC_443", + "PAL_B" , "PAL_D" , "PAL_G" , + "PAL_H" , "PAL_I" , "PAL_M" , + "PAL_N" , "PAL_NC" , "PAL_60" , + "SECAM_B" , "SECAM_D" , "SECAM_G" , + "SECAM_K" , "SECAM_K1", "SECAM_L" , + "SECAM_60" +}; + +#define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names)) + +struct intel_sdvo { + struct intel_encoder base; + + struct i2c_adapter *i2c; + u8 slave_addr; + + struct i2c_adapter ddc; + + /* Register for the SDVO device: SDVOB or SDVOC */ + uint32_t sdvo_reg; + + /* Active outputs controlled by this SDVO output */ + uint16_t controlled_output; + + /* + * Capabilities of the SDVO device returned by + * intel_sdvo_get_capabilities() + */ + struct intel_sdvo_caps caps; + + /* Pixel clock limitations reported by the SDVO device, in kHz */ + int pixel_clock_min, pixel_clock_max; + + /* + * For multiple function SDVO device, + * this is for current attached outputs. + */ + uint16_t attached_output; + + /* + * Hotplug activation bits for this device + */ + uint16_t hotplug_active; + + /** + * This is used to select the color range of RBG outputs in HDMI mode. + * It is only valid when using TMDS encoding and 8 bit per color mode. + */ + uint32_t color_range; + bool color_range_auto; + + /** + * This is set if we're going to treat the device as TV-out. + * + * While we have these nice friendly flags for output types that ought + * to decide this for us, the S-Video output on our HDMI+S-Video card + * shows up as RGB1 (VGA). + */ + bool is_tv; + + /* On different gens SDVOB is at different places. */ + bool is_sdvob; + + /* This is for current tv format name */ + int tv_format_index; + + /** + * This is set if we treat the device as HDMI, instead of DVI. + */ + bool is_hdmi; + bool has_hdmi_monitor; + bool has_hdmi_audio; + bool rgb_quant_range_selectable; + + /** + * This is set if we detect output of sdvo device as LVDS and + * have a valid fixed mode to use with the panel. + */ + bool is_lvds; + + /** + * This is sdvo fixed pannel mode pointer + */ + struct drm_display_mode *sdvo_lvds_fixed_mode; + + /* DDC bus used by this SDVO encoder */ + uint8_t ddc_bus; + + /* + * the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd + */ + uint8_t dtd_sdvo_flags; +}; + +struct intel_sdvo_connector { + struct intel_connector base; + + /* Mark the type of connector */ + uint16_t output_flag; + + enum hdmi_force_audio force_audio; + + /* This contains all current supported TV format */ + u8 tv_format_supported[TV_FORMAT_NUM]; + int format_supported_num; + struct drm_property *tv_format; + + /* add the property for the SDVO-TV */ + struct drm_property *left; + struct drm_property *right; + struct drm_property *top; + struct drm_property *bottom; + struct drm_property *hpos; + struct drm_property *vpos; + struct drm_property *contrast; + struct drm_property *saturation; + struct drm_property *hue; + struct drm_property *sharpness; + struct drm_property *flicker_filter; + struct drm_property *flicker_filter_adaptive; + struct drm_property *flicker_filter_2d; + struct drm_property *tv_chroma_filter; + struct drm_property *tv_luma_filter; + struct drm_property *dot_crawl; + + /* add the property for the SDVO-TV/LVDS */ + struct drm_property *brightness; + + /* Add variable to record current setting for the above property */ + u32 left_margin, right_margin, top_margin, bottom_margin; + + /* this is to get the range of margin.*/ + u32 max_hscan, max_vscan; + u32 max_hpos, cur_hpos; + u32 max_vpos, cur_vpos; + u32 cur_brightness, max_brightness; + u32 cur_contrast, max_contrast; + u32 cur_saturation, max_saturation; + u32 cur_hue, max_hue; + u32 cur_sharpness, max_sharpness; + u32 cur_flicker_filter, max_flicker_filter; + u32 cur_flicker_filter_adaptive, max_flicker_filter_adaptive; + u32 cur_flicker_filter_2d, max_flicker_filter_2d; + u32 cur_tv_chroma_filter, max_tv_chroma_filter; + u32 cur_tv_luma_filter, max_tv_luma_filter; + u32 cur_dot_crawl, max_dot_crawl; +}; + +static struct intel_sdvo *to_sdvo(struct intel_encoder *encoder) +{ + return container_of(encoder, struct intel_sdvo, base); +} + +static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector) +{ + return to_sdvo(intel_attached_encoder(connector)); +} + +static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector) +{ + return container_of(to_intel_connector(connector), struct intel_sdvo_connector, base); +} + +static bool +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags); +static bool +intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + int type); +static bool +intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector); + +/** + * Writes the SDVOB or SDVOC with the given value, but always writes both + * SDVOB and SDVOC to work around apparent hardware issues (according to + * comments in the BIOS). + */ +static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) +{ + struct drm_device *dev = intel_sdvo->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 bval = val, cval = val; + int i; + + if (intel_sdvo->sdvo_reg == PCH_SDVOB) { + I915_WRITE(intel_sdvo->sdvo_reg, val); + I915_READ(intel_sdvo->sdvo_reg); + return; + } + + if (intel_sdvo->sdvo_reg == GEN3_SDVOB) + cval = I915_READ(GEN3_SDVOC); + else + bval = I915_READ(GEN3_SDVOB); + + /* + * Write the registers twice for luck. Sometimes, + * writing them only once doesn't appear to 'stick'. + * The BIOS does this too. Yay, magic + */ + for (i = 0; i < 2; i++) + { + I915_WRITE(GEN3_SDVOB, bval); + I915_READ(GEN3_SDVOB); + I915_WRITE(GEN3_SDVOC, cval); + I915_READ(GEN3_SDVOC); + } +} + +static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) +{ + struct i2c_msg msgs[] = { + { + .addr = intel_sdvo->slave_addr, + .flags = 0, + .len = 1, + .buf = &addr, + }, + { + .addr = intel_sdvo->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = ch, + } + }; + int ret; + + if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2) + return true; + + DRM_DEBUG_KMS("i2c transfer returned %d\n", ret); + return false; +} + +#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} +/** Mapping of command numbers to names, for debug output */ +static const struct _sdvo_cmd_name { + u8 cmd; + const char *name; +} sdvo_cmd_names[] = { + SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POWER_STATE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DISPLAY_POWER_STATE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS), + + /* Add the op code for SDVO enhancements */ + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_VPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_VPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_VPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HUE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HUE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HUE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_CONTRAST), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CONTRAST), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTRAST), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_BRIGHTNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_BRIGHTNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_BRIGHTNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_H), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_H), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_H), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DOT_CRAWL), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DOT_CRAWL), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_LUMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_LUMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_LUMA_FILTER), + + /* HDMI op code */ + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_PIXEL_REPLI), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_COLORIMETRY), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_AUDIO_STAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_STAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INDEX), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_INDEX), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INFO), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_AV_SPLIT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_AV_SPLIT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_TXRATE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_DATA), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA), +}; + +#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC") + +static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, + const void *args, int args_len) +{ + int i, pos = 0; +#define BUF_LEN 256 + char buffer[BUF_LEN]; + +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args) + + + for (i = 0; i < args_len; i++) { + BUF_PRINT("%02X ", ((u8 *)args)[i]); + } + for (; i < 8; i++) { + BUF_PRINT(" "); + } + for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { + if (cmd == sdvo_cmd_names[i].cmd) { + BUF_PRINT("(%s)", sdvo_cmd_names[i].name); + break; + } + } + if (i == ARRAY_SIZE(sdvo_cmd_names)) { + BUF_PRINT("(%02X)", cmd); + } + BUG_ON(pos >= BUF_LEN - 1); +#undef BUF_PRINT +#undef BUF_LEN + + DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer); +} + +static const char *cmd_status_names[] = { + "Power on", + "Success", + "Not supported", + "Invalid arg", + "Pending", + "Target not specified", + "Scaling not supported" +}; + +static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, + const void *args, int args_len) +{ + u8 *buf, status; + struct i2c_msg *msgs; + int i, ret = true; + + /* Would be simpler to allocate both in one go ? */ + buf = kzalloc(args_len * 2 + 2, GFP_KERNEL); + if (!buf) + return false; + + msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL); + if (!msgs) { + kfree(buf); + return false; + } + + intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); + + for (i = 0; i < args_len; i++) { + msgs[i].addr = intel_sdvo->slave_addr; + msgs[i].flags = 0; + msgs[i].len = 2; + msgs[i].buf = buf + 2 *i; + buf[2*i + 0] = SDVO_I2C_ARG_0 - i; + buf[2*i + 1] = ((u8*)args)[i]; + } + msgs[i].addr = intel_sdvo->slave_addr; + msgs[i].flags = 0; + msgs[i].len = 2; + msgs[i].buf = buf + 2*i; + buf[2*i + 0] = SDVO_I2C_OPCODE; + buf[2*i + 1] = cmd; + + /* the following two are to read the response */ + status = SDVO_I2C_CMD_STATUS; + msgs[i+1].addr = intel_sdvo->slave_addr; + msgs[i+1].flags = 0; + msgs[i+1].len = 1; + msgs[i+1].buf = &status; + + msgs[i+2].addr = intel_sdvo->slave_addr; + msgs[i+2].flags = I2C_M_RD; + msgs[i+2].len = 1; + msgs[i+2].buf = &status; + + ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3); + if (ret < 0) { + DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); + ret = false; + goto out; + } + if (ret != i+3) { + /* failure in I2C transfer */ + DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3); + ret = false; + } + +out: + kfree(msgs); + kfree(buf); + return ret; +} + +static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, + void *response, int response_len) +{ + u8 retry = 15; /* 5 quick checks, followed by 10 long checks */ + u8 status; + int i, pos = 0; +#define BUF_LEN 256 + char buffer[BUF_LEN]; + + + /* + * The documentation states that all commands will be + * processed within 15µs, and that we need only poll + * the status byte a maximum of 3 times in order for the + * command to be complete. + * + * Check 5 times in case the hardware failed to read the docs. + * + * Also beware that the first response by many devices is to + * reply PENDING and stall for time. TVs are notorious for + * requiring longer than specified to complete their replies. + * Originally (in the DDX long ago), the delay was only ever 15ms + * with an additional delay of 30ms applied for TVs added later after + * many experiments. To accommodate both sets of delays, we do a + * sequence of slow checks if the device is falling behind and fails + * to reply within 5*15µs. + */ + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_CMD_STATUS, + &status)) + goto log_fail; + + while ((status == SDVO_CMD_STATUS_PENDING || + status == SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED) && --retry) { + if (retry < 10) + msleep(15); + else + udelay(15); + + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_CMD_STATUS, + &status)) + goto log_fail; + } + +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args) + + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) + BUF_PRINT("(%s)", cmd_status_names[status]); + else + BUF_PRINT("(??? %d)", status); + + if (status != SDVO_CMD_STATUS_SUCCESS) + goto log_fail; + + /* Read the command response */ + for (i = 0; i < response_len; i++) { + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_RETURN_0 + i, + &((u8 *)response)[i])) + goto log_fail; + BUF_PRINT(" %02X", ((u8 *)response)[i]); + } + BUG_ON(pos >= BUF_LEN - 1); +#undef BUF_PRINT +#undef BUF_LEN + + DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer); + return true; + +log_fail: + DRM_DEBUG_KMS("%s: R: ... failed\n", SDVO_NAME(intel_sdvo)); + return false; +} + +static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) +{ + if (mode->clock >= 100000) + return 1; + else if (mode->clock >= 50000) + return 2; + else + return 4; +} + +static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, + u8 ddc_bus) +{ + /* This must be the immediately preceding write before the i2c xfer */ + return intel_sdvo_write_cmd(intel_sdvo, + SDVO_CMD_SET_CONTROL_BUS_SWITCH, + &ddc_bus, 1); +} + +static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len) +{ + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len)) + return false; + + return intel_sdvo_read_response(intel_sdvo, NULL, 0); +} + +static bool +intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len) +{ + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, NULL, 0)) + return false; + + return intel_sdvo_read_response(intel_sdvo, value, len); +} + +static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo) +{ + struct intel_sdvo_set_target_input_args targets = {0}; + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TARGET_INPUT, + &targets, sizeof(targets)); +} + +/** + * Return whether each input is trained. + * + * This function is making an assumption about the layout of the response, + * which should be checked against the docs. + */ +static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2) +{ + struct intel_sdvo_get_trained_inputs_response response; + + BUILD_BUG_ON(sizeof(response) != 1); + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, + &response, sizeof(response))) + return false; + + *input_1 = response.input0_trained; + *input_2 = response.input1_trained; + return true; +} + +static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo, + u16 outputs) +{ + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_ACTIVE_OUTPUTS, + &outputs, sizeof(outputs)); +} + +static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo, + u16 *outputs) +{ + return intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_ACTIVE_OUTPUTS, + outputs, sizeof(*outputs)); +} + +static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, + int mode) +{ + u8 state = SDVO_ENCODER_STATE_ON; + + switch (mode) { + case DRM_MODE_DPMS_ON: + state = SDVO_ENCODER_STATE_ON; + break; + case DRM_MODE_DPMS_STANDBY: + state = SDVO_ENCODER_STATE_STANDBY; + break; + case DRM_MODE_DPMS_SUSPEND: + state = SDVO_ENCODER_STATE_SUSPEND; + break; + case DRM_MODE_DPMS_OFF: + state = SDVO_ENCODER_STATE_OFF; + break; + } + + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state)); +} + +static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo, + int *clock_min, + int *clock_max) +{ + struct intel_sdvo_pixel_clock_range clocks; + + BUILD_BUG_ON(sizeof(clocks) != 4); + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, + &clocks, sizeof(clocks))) + return false; + + /* Convert the values from units of 10 kHz to kHz. */ + *clock_min = clocks.min * 10; + *clock_max = clocks.max * 10; + return true; +} + +static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo, + u16 outputs) +{ + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TARGET_OUTPUT, + &outputs, sizeof(outputs)); +} + +static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_set_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); +} + +static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); +} + +static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_set_timing(intel_sdvo, + SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_set_timing(intel_sdvo, + SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_get_timing(intel_sdvo, + SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); +} + +static bool +intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, + uint16_t clock, + uint16_t width, + uint16_t height) +{ + struct intel_sdvo_preferred_input_timing_args args; + + memset(&args, 0, sizeof(args)); + args.clock = clock; + args.width = width; + args.height = height; + args.interlace = 0; + + if (intel_sdvo->is_lvds && + (intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width || + intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height)) + args.scaled = 1; + + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, + &args, sizeof(args)); +} + +static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_dtd *dtd) +{ + BUILD_BUG_ON(sizeof(dtd->part1) != 8); + BUILD_BUG_ON(sizeof(dtd->part2) != 8); + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + &dtd->part2, sizeof(dtd->part2)); +} + +static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val) +{ + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); +} + +static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, + const struct drm_display_mode *mode) +{ + uint16_t width, height; + uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len; + uint16_t h_sync_offset, v_sync_offset; + int mode_clock; + + memset(dtd, 0, sizeof(*dtd)); + + width = mode->hdisplay; + height = mode->vdisplay; + + /* do some mode translations */ + h_blank_len = mode->htotal - mode->hdisplay; + h_sync_len = mode->hsync_end - mode->hsync_start; + + v_blank_len = mode->vtotal - mode->vdisplay; + v_sync_len = mode->vsync_end - mode->vsync_start; + + h_sync_offset = mode->hsync_start - mode->hdisplay; + v_sync_offset = mode->vsync_start - mode->vdisplay; + + mode_clock = mode->clock; + mode_clock /= 10; + dtd->part1.clock = mode_clock; + + dtd->part1.h_active = width & 0xff; + dtd->part1.h_blank = h_blank_len & 0xff; + dtd->part1.h_high = (((width >> 8) & 0xf) << 4) | + ((h_blank_len >> 8) & 0xf); + dtd->part1.v_active = height & 0xff; + dtd->part1.v_blank = v_blank_len & 0xff; + dtd->part1.v_high = (((height >> 8) & 0xf) << 4) | + ((v_blank_len >> 8) & 0xf); + + dtd->part2.h_sync_off = h_sync_offset & 0xff; + dtd->part2.h_sync_width = h_sync_len & 0xff; + dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | + (v_sync_len & 0xf); + dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | + ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | + ((v_sync_len & 0x30) >> 4); + + dtd->part2.dtd_flags = 0x18; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE; + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE; + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE; + + dtd->part2.v_sync_off_high = v_sync_offset & 0xc0; +} + +static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode *pmode, + const struct intel_sdvo_dtd *dtd) +{ + struct drm_display_mode mode = {}; + + mode.hdisplay = dtd->part1.h_active; + mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8; + mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off; + mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2; + mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width; + mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4; + mode.htotal = mode.hdisplay + dtd->part1.h_blank; + mode.htotal += (dtd->part1.h_high & 0xf) << 8; + + mode.vdisplay = dtd->part1.v_active; + mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8; + mode.vsync_start = mode.vdisplay; + mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf; + mode.vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2; + mode.vsync_start += dtd->part2.v_sync_off_high & 0xc0; + mode.vsync_end = mode.vsync_start + + (dtd->part2.v_sync_off_width & 0xf); + mode.vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4; + mode.vtotal = mode.vdisplay + dtd->part1.v_blank; + mode.vtotal += (dtd->part1.v_high & 0xf) << 8; + + mode.clock = dtd->part1.clock * 10; + + if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE) + mode.flags |= DRM_MODE_FLAG_INTERLACE; + if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) + mode.flags |= DRM_MODE_FLAG_PHSYNC; + else + mode.flags |= DRM_MODE_FLAG_NHSYNC; + if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) + mode.flags |= DRM_MODE_FLAG_PVSYNC; + else + mode.flags |= DRM_MODE_FLAG_NVSYNC; + + drm_mode_set_crtcinfo(&mode, 0); + + drm_mode_copy(pmode, &mode); +} + +static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo) +{ + struct intel_sdvo_encode encode; + + BUILD_BUG_ON(sizeof(encode) != 2); + return intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPP_ENCODE, + &encode, sizeof(encode)); +} + +static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo, + uint8_t mode) +{ + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); +} + +static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo, + uint8_t mode) +{ + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); +} + +#if 0 +static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) +{ + int i, j; + uint8_t set_buf_index[2]; + uint8_t av_split; + uint8_t buf_size; + uint8_t buf[48]; + uint8_t *pos; + + intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1); + + for (i = 0; i <= av_split; i++) { + set_buf_index[0] = i; set_buf_index[1] = 0; + intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_HBUF_INDEX, + set_buf_index, 2); + intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_INFO, NULL, 0); + intel_sdvo_read_response(encoder, &buf_size, 1); + + pos = buf; + for (j = 0; j <= buf_size; j += 8) { + intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_DATA, + NULL, 0); + intel_sdvo_read_response(encoder, pos, 8); + pos += 8; + } + } +} +#endif + +static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, + unsigned if_index, uint8_t tx_rate, + const uint8_t *data, unsigned length) +{ + uint8_t set_buf_index[2] = { if_index, 0 }; + uint8_t hbuf_size, tmp[8]; + int i; + + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_INDEX, + set_buf_index, 2)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO, + &hbuf_size, 1)) + return false; + + /* Buffer size is 0 based, hooray! */ + hbuf_size++; + + DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n", + if_index, length, hbuf_size); + + for (i = 0; i < hbuf_size; i += 8) { + memset(tmp, 0, 8); + if (i < length) + memcpy(tmp, data + i, min_t(unsigned, 8, length - i)); + + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_DATA, + tmp, 8)) + return false; + } + + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_TXRATE, + &tx_rate, 1); +} + +static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, + const struct drm_display_mode *adjusted_mode) +{ + uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)]; + struct drm_crtc *crtc = intel_sdvo->base.base.crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + union hdmi_infoframe frame; + int ret; + ssize_t len; + + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + adjusted_mode); + if (ret < 0) { + DRM_ERROR("couldn't fill AVI infoframe\n"); + return false; + } + + if (intel_sdvo->rgb_quant_range_selectable) { + if (intel_crtc->config.limited_color_range) + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_LIMITED; + else + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_FULL; + } + + len = hdmi_infoframe_pack(&frame, sdvo_data, sizeof(sdvo_data)); + if (len < 0) + return false; + + return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF, + SDVO_HBUF_TX_VSYNC, + sdvo_data, sizeof(sdvo_data)); +} + +static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) +{ + struct intel_sdvo_tv_format format; + uint32_t format_map; + + format_map = 1 << intel_sdvo->tv_format_index; + memset(&format, 0, sizeof(format)); + memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); + + BUILD_BUG_ON(sizeof(format) != 6); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TV_FORMAT, + &format, sizeof(format)); +} + +static bool +intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo, + const struct drm_display_mode *mode) +{ + struct intel_sdvo_dtd output_dtd; + + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output)) + return false; + + intel_sdvo_get_dtd_from_mode(&output_dtd, mode); + if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd)) + return false; + + return true; +} + +/* Asks the sdvo controller for the preferred input mode given the output mode. + * Unfortunately we have to set up the full output mode to do that. */ +static bool +intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_sdvo_dtd input_dtd; + + /* Reset the input timing to the screen. Assume always input 0. */ + if (!intel_sdvo_set_target_input(intel_sdvo)) + return false; + + if (!intel_sdvo_create_preferred_input_timing(intel_sdvo, + mode->clock / 10, + mode->hdisplay, + mode->vdisplay)) + return false; + + if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, + &input_dtd)) + return false; + + intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + intel_sdvo->dtd_sdvo_flags = input_dtd.part2.sdvo_flags; + + return true; +} + +static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config) +{ + unsigned dotclock = pipe_config->port_clock; + struct dpll *clock = &pipe_config->dpll; + + /* SDVO TV has fixed PLL values depend on its clock range, + this mirrors vbios setting. */ + if (dotclock >= 100000 && dotclock < 140500) { + clock->p1 = 2; + clock->p2 = 10; + clock->n = 3; + clock->m1 = 16; + clock->m2 = 8; + } else if (dotclock >= 140500 && dotclock <= 200000) { + clock->p1 = 1; + clock->p2 = 10; + clock->n = 6; + clock->m1 = 12; + clock->m2 = 8; + } else { + WARN(1, "SDVO TV clock out of range: %i\n", dotclock); + } + + pipe_config->clock_set = true; +} + +static bool intel_sdvo_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + struct drm_display_mode *mode = &pipe_config->requested_mode; + + DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n"); + pipe_config->pipe_bpp = 8*3; + + if (HAS_PCH_SPLIT(encoder->base.dev)) + pipe_config->has_pch_encoder = true; + + /* We need to construct preferred input timings based on our + * output timings. To do that, we have to set the output + * timings, even though this isn't really the right place in + * the sequence to do it. Oh well. + */ + if (intel_sdvo->is_tv) { + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) + return false; + + (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, + mode, + adjusted_mode); + pipe_config->sdvo_tv_clock = true; + } else if (intel_sdvo->is_lvds) { + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, + intel_sdvo->sdvo_lvds_fixed_mode)) + return false; + + (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, + mode, + adjusted_mode); + } + + /* Make the CRTC code factor in the SDVO pixel multiplier. The + * SDVO device will factor out the multiplier during mode_set. + */ + pipe_config->pixel_multiplier = + intel_sdvo_get_pixel_multiplier(adjusted_mode); + + if (intel_sdvo->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + /* FIXME: This bit is only valid when using TMDS encoding and 8 + * bit per color mode. */ + if (intel_sdvo->has_hdmi_monitor && + drm_match_cea_mode(adjusted_mode) > 1) + intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; + else + intel_sdvo->color_range = 0; + } + + if (intel_sdvo->color_range) + pipe_config->limited_color_range = true; + + /* Clock computation needs to happen after pixel multiplier. */ + if (intel_sdvo->is_tv) + i9xx_adjust_sdvo_tv_clock(pipe_config); + + return true; +} + +static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder) +{ + struct drm_device *dev = intel_encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc); + struct drm_display_mode *adjusted_mode = + &crtc->config.adjusted_mode; + struct drm_display_mode *mode = &crtc->config.requested_mode; + struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder); + u32 sdvox; + struct intel_sdvo_in_out_map in_out; + struct intel_sdvo_dtd input_dtd, output_dtd; + int rate; + + if (!mode) + return; + + /* First, set the input mapping for the first input to our controlled + * output. This is only correct if we're a single-input device, in + * which case the first input is the output from the appropriate SDVO + * channel on the motherboard. In a two-input device, the first input + * will be SDVOB and the second SDVOC. + */ + in_out.in0 = intel_sdvo->attached_output; + in_out.in1 = 0; + + intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_IN_OUT_MAP, + &in_out, sizeof(in_out)); + + /* Set the output timings to the screen */ + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output)) + return; + + /* lvds has a special fixed output timing. */ + if (intel_sdvo->is_lvds) + intel_sdvo_get_dtd_from_mode(&output_dtd, + intel_sdvo->sdvo_lvds_fixed_mode); + else + intel_sdvo_get_dtd_from_mode(&output_dtd, mode); + if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd)) + DRM_INFO("Setting output timings on %s failed\n", + SDVO_NAME(intel_sdvo)); + + /* Set the input timing to the screen. Assume always input 0. */ + if (!intel_sdvo_set_target_input(intel_sdvo)) + return; + + if (intel_sdvo->has_hdmi_monitor) { + intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); + intel_sdvo_set_colorimetry(intel_sdvo, + SDVO_COLORIMETRY_RGB256); + intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode); + } else + intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); + + if (intel_sdvo->is_tv && + !intel_sdvo_set_tv_format(intel_sdvo)) + return; + + intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); + + if (intel_sdvo->is_tv || intel_sdvo->is_lvds) + input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags; + if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd)) + DRM_INFO("Setting input timings on %s failed\n", + SDVO_NAME(intel_sdvo)); + + switch (crtc->config.pixel_multiplier) { + default: + WARN(1, "unknown pixel mutlipler specified\n"); + case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; + case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; + case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; + } + if (!intel_sdvo_set_clock_rate_mult(intel_sdvo, rate)) + return; + + /* Set the SDVO control regs. */ + if (INTEL_INFO(dev)->gen >= 4) { + /* The real mode polarity is set by the SDVO commands, using + * struct intel_sdvo_dtd. */ + sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; + if (!HAS_PCH_SPLIT(dev) && intel_sdvo->is_hdmi) + sdvox |= intel_sdvo->color_range; + if (INTEL_INFO(dev)->gen < 5) + sdvox |= SDVO_BORDER_ENABLE; + } else { + sdvox = I915_READ(intel_sdvo->sdvo_reg); + switch (intel_sdvo->sdvo_reg) { + case GEN3_SDVOB: + sdvox &= SDVOB_PRESERVE_MASK; + break; + case GEN3_SDVOC: + sdvox &= SDVOC_PRESERVE_MASK; + break; + } + sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; + } + + if (INTEL_PCH_TYPE(dev) >= PCH_CPT) + sdvox |= SDVO_PIPE_SEL_CPT(crtc->pipe); + else + sdvox |= SDVO_PIPE_SEL(crtc->pipe); + + if (intel_sdvo->has_hdmi_audio) + sdvox |= SDVO_AUDIO_ENABLE; + + if (INTEL_INFO(dev)->gen >= 4) { + /* done in crtc_mode_set as the dpll_md reg must be written early */ + } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { + /* done in crtc_mode_set as it lives inside the dpll register */ + } else { + sdvox |= (crtc->config.pixel_multiplier - 1) + << SDVO_PORT_MULTIPLY_SHIFT; + } + + if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL && + INTEL_INFO(dev)->gen < 5) + sdvox |= SDVO_STALL_SELECT; + intel_sdvo_write_sdvox(intel_sdvo, sdvox); +} + +static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector) +{ + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(&connector->base); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base); + u16 active_outputs = 0; + + intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); + + if (active_outputs & intel_sdvo_connector->output_flag) + return true; + else + return false; +} + +static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, + enum pipe *pipe) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + u16 active_outputs = 0; + u32 tmp; + + tmp = I915_READ(intel_sdvo->sdvo_reg); + intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); + + if (!(tmp & SDVO_ENABLE) && (active_outputs == 0)) + return false; + + if (HAS_PCH_CPT(dev)) + *pipe = PORT_TO_PIPE_CPT(tmp); + else + *pipe = PORT_TO_PIPE(tmp); + + return true; +} + +static void intel_sdvo_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + struct intel_sdvo_dtd dtd; + int encoder_pixel_multiplier = 0; + int dotclock; + u32 flags = 0, sdvox; + u8 val; + bool ret; + + ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd); + if (!ret) { + /* Some sdvo encoders are not spec compliant and don't + * implement the mandatory get_timings function. */ + DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n"); + pipe_config->quirks |= PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS; + } else { + if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + } + + pipe_config->adjusted_mode.flags |= flags; + + /* + * pixel multiplier readout is tricky: Only on i915g/gm it is stored in + * the sdvo port register, on all other platforms it is part of the dpll + * state. Since the general pipe state readout happens before the + * encoder->get_config we so already have a valid pixel multplier on all + * other platfroms. + */ + if (IS_I915G(dev) || IS_I915GM(dev)) { + sdvox = I915_READ(intel_sdvo->sdvo_reg); + pipe_config->pixel_multiplier = + ((sdvox & SDVO_PORT_MULTIPLY_MASK) + >> SDVO_PORT_MULTIPLY_SHIFT) + 1; + } + + dotclock = pipe_config->port_clock / pipe_config->pixel_multiplier; + + if (HAS_PCH_SPLIT(dev)) + ironlake_check_encoder_dotclock(pipe_config, dotclock); + + pipe_config->adjusted_mode.crtc_clock = dotclock; + + /* Cross check the port pixel multiplier with the sdvo encoder state. */ + if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, + &val, 1)) { + switch (val) { + case SDVO_CLOCK_RATE_MULT_1X: + encoder_pixel_multiplier = 1; + break; + case SDVO_CLOCK_RATE_MULT_2X: + encoder_pixel_multiplier = 2; + break; + case SDVO_CLOCK_RATE_MULT_4X: + encoder_pixel_multiplier = 4; + break; + } + } + + WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier, + "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n", + pipe_config->pixel_multiplier, encoder_pixel_multiplier); +} + +static void intel_disable_sdvo(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + u32 temp; + + intel_sdvo_set_active_outputs(intel_sdvo, 0); + if (0) + intel_sdvo_set_encoder_power_state(intel_sdvo, + DRM_MODE_DPMS_OFF); + + temp = I915_READ(intel_sdvo->sdvo_reg); + if ((temp & SDVO_ENABLE) != 0) { + /* HW workaround for IBX, we need to move the port to + * transcoder A before disabling it. */ + if (HAS_PCH_IBX(encoder->base.dev)) { + struct drm_crtc *crtc = encoder->base.crtc; + int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; + + if (temp & SDVO_PIPE_B_SELECT) { + temp &= ~SDVO_PIPE_B_SELECT; + I915_WRITE(intel_sdvo->sdvo_reg, temp); + POSTING_READ(intel_sdvo->sdvo_reg); + + /* Again we need to write this twice. */ + I915_WRITE(intel_sdvo->sdvo_reg, temp); + POSTING_READ(intel_sdvo->sdvo_reg); + + /* Transcoder selection bits only update + * effectively on vblank. */ + if (crtc) + intel_wait_for_vblank(encoder->base.dev, pipe); + else + msleep(50); + } + } + + intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE); + } +} + +static void intel_enable_sdvo(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + u32 temp; + bool input1, input2; + int i; + u8 status; + + temp = I915_READ(intel_sdvo->sdvo_reg); + if ((temp & SDVO_ENABLE) == 0) { + /* HW workaround for IBX, we need to move the port + * to transcoder A before disabling it, so restore it here. */ + if (HAS_PCH_IBX(dev)) + temp |= SDVO_PIPE_SEL(intel_crtc->pipe); + + intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); + } + for (i = 0; i < 2; i++) + intel_wait_for_vblank(dev, intel_crtc->pipe); + + status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); + /* Warn if the device reported failure to sync. + * A lot of SDVO devices fail to notify of sync, but it's + * a given it the status is a success, we succeeded. + */ + if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { + DRM_DEBUG_KMS("First %s output reported failure to " + "sync\n", SDVO_NAME(intel_sdvo)); + } + + if (0) + intel_sdvo_set_encoder_power_state(intel_sdvo, + DRM_MODE_DPMS_ON); + intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); +} + +/* Special dpms function to support cloning between dvo/sdvo/crt. */ +static void intel_sdvo_dpms(struct drm_connector *connector, int mode) +{ + struct drm_crtc *crtc; + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + + /* dvo supports only 2 dpms states. */ + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + if (mode == connector->dpms) + return; + + connector->dpms = mode; + + /* Only need to change hw state when actually enabled */ + crtc = intel_sdvo->base.base.crtc; + if (!crtc) { + intel_sdvo->base.connectors_active = false; + return; + } + + /* We set active outputs manually below in case pipe dpms doesn't change + * due to cloning. */ + if (mode != DRM_MODE_DPMS_ON) { + intel_sdvo_set_active_outputs(intel_sdvo, 0); + if (0) + intel_sdvo_set_encoder_power_state(intel_sdvo, mode); + + intel_sdvo->base.connectors_active = false; + + intel_crtc_update_dpms(crtc); + } else { + intel_sdvo->base.connectors_active = true; + + intel_crtc_update_dpms(crtc); + + if (0) + intel_sdvo_set_encoder_power_state(intel_sdvo, mode); + intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); + } + + intel_modeset_check_state(connector->dev); +} + +static enum drm_mode_status +intel_sdvo_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (intel_sdvo->pixel_clock_min > mode->clock) + return MODE_CLOCK_LOW; + + if (intel_sdvo->pixel_clock_max < mode->clock) + return MODE_CLOCK_HIGH; + + if (intel_sdvo->is_lvds) { + if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) + return MODE_PANEL; + + if (mode->vdisplay > intel_sdvo->sdvo_lvds_fixed_mode->vdisplay) + return MODE_PANEL; + } + + return MODE_OK; +} + +static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) +{ + BUILD_BUG_ON(sizeof(*caps) != 8); + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_DEVICE_CAPS, + caps, sizeof(*caps))) + return false; + + DRM_DEBUG_KMS("SDVO capabilities:\n" + " vendor_id: %d\n" + " device_id: %d\n" + " device_rev_id: %d\n" + " sdvo_version_major: %d\n" + " sdvo_version_minor: %d\n" + " sdvo_inputs_mask: %d\n" + " smooth_scaling: %d\n" + " sharp_scaling: %d\n" + " up_scaling: %d\n" + " down_scaling: %d\n" + " stall_support: %d\n" + " output_flags: %d\n", + caps->vendor_id, + caps->device_id, + caps->device_rev_id, + caps->sdvo_version_major, + caps->sdvo_version_minor, + caps->sdvo_inputs_mask, + caps->smooth_scaling, + caps->sharp_scaling, + caps->up_scaling, + caps->down_scaling, + caps->stall_support, + caps->output_flags); + + return true; +} + +static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo) +{ + struct drm_device *dev = intel_sdvo->base.base.dev; + uint16_t hotplug; + + /* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise + * on the line. */ + if (IS_I945G(dev) || IS_I945GM(dev)) + return 0; + + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, + &hotplug, sizeof(hotplug))) + return 0; + + return hotplug; +} + +static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder) +{ + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, + &intel_sdvo->hotplug_active, 2); +} + +static bool +intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) +{ + /* Is there more than one type of output? */ + return hweight16(intel_sdvo->caps.output_flags) > 1; +} + +static struct edid * +intel_sdvo_get_edid(struct drm_connector *connector) +{ + struct intel_sdvo *sdvo = intel_attached_sdvo(connector); + return drm_get_edid(connector, &sdvo->ddc); +} + +/* Mac mini hack -- use the same DDC as the analog connector */ +static struct edid * +intel_sdvo_get_analog_edid(struct drm_connector *connector) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + + return drm_get_edid(connector, + intel_gmbus_get_adapter(dev_priv, + dev_priv->vbt.crt_ddc_pin)); +} + +static enum drm_connector_status +intel_sdvo_tmds_sink_detect(struct drm_connector *connector) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + enum drm_connector_status status; + struct edid *edid; + + edid = intel_sdvo_get_edid(connector); + + if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) { + u8 ddc, saved_ddc = intel_sdvo->ddc_bus; + + /* + * Don't use the 1 as the argument of DDC bus switch to get + * the EDID. It is used for SDVO SPD ROM. + */ + for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { + intel_sdvo->ddc_bus = ddc; + edid = intel_sdvo_get_edid(connector); + if (edid) + break; + } + /* + * If we found the EDID on the other bus, + * assume that is the correct DDC bus. + */ + if (edid == NULL) + intel_sdvo->ddc_bus = saved_ddc; + } + + /* + * When there is no edid and no monitor is connected with VGA + * port, try to use the CRT ddc to read the EDID for DVI-connector. + */ + if (edid == NULL) + edid = intel_sdvo_get_analog_edid(connector); + + status = connector_status_unknown; + if (edid != NULL) { + /* DDC bus is shared, match EDID to connector type */ + if (edid->input & DRM_EDID_INPUT_DIGITAL) { + status = connector_status_connected; + if (intel_sdvo->is_hdmi) { + intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); + intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); + intel_sdvo->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); + } + } else + status = connector_status_disconnected; + kfree(edid); + } + + if (status == connector_status_connected) { + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + if (intel_sdvo_connector->force_audio != HDMI_AUDIO_AUTO) + intel_sdvo->has_hdmi_audio = (intel_sdvo_connector->force_audio == HDMI_AUDIO_ON); + } + + return status; +} + +static bool +intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo, + struct edid *edid) +{ + bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); + bool connector_is_digital = !!IS_DIGITAL(sdvo); + + DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n", + connector_is_digital, monitor_is_digital); + return connector_is_digital == monitor_is_digital; +} + +static enum drm_connector_status +intel_sdvo_detect(struct drm_connector *connector, bool force) +{ + uint16_t response; + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + enum drm_connector_status ret; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector)); + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_ATTACHED_DISPLAYS, + &response, 2)) + return connector_status_unknown; + + DRM_DEBUG_KMS("SDVO response %d %d [%x]\n", + response & 0xff, response >> 8, + intel_sdvo_connector->output_flag); + + if (response == 0) + return connector_status_disconnected; + + intel_sdvo->attached_output = response; + + intel_sdvo->has_hdmi_monitor = false; + intel_sdvo->has_hdmi_audio = false; + intel_sdvo->rgb_quant_range_selectable = false; + + if ((intel_sdvo_connector->output_flag & response) == 0) + ret = connector_status_disconnected; + else if (IS_TMDS(intel_sdvo_connector)) + ret = intel_sdvo_tmds_sink_detect(connector); + else { + struct edid *edid; + + /* if we have an edid check it matches the connection */ + edid = intel_sdvo_get_edid(connector); + if (edid == NULL) + edid = intel_sdvo_get_analog_edid(connector); + if (edid != NULL) { + if (intel_sdvo_connector_matches_edid(intel_sdvo_connector, + edid)) + ret = connector_status_connected; + else + ret = connector_status_disconnected; + + kfree(edid); + } else + ret = connector_status_connected; + } + + /* May update encoder flag for like clock for SDVO TV, etc.*/ + if (ret == connector_status_connected) { + intel_sdvo->is_tv = false; + intel_sdvo->is_lvds = false; + + if (response & SDVO_TV_MASK) + intel_sdvo->is_tv = true; + if (response & SDVO_LVDS_MASK) + intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL; + } + + return ret; +} + +static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) +{ + struct edid *edid; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector)); + + /* set the bus switch and get the modes */ + edid = intel_sdvo_get_edid(connector); + + /* + * Mac mini hack. On this device, the DVI-I connector shares one DDC + * link between analog and digital outputs. So, if the regular SDVO + * DDC fails, check to see if the analog output is disconnected, in + * which case we'll look there for the digital DDC data. + */ + if (edid == NULL) + edid = intel_sdvo_get_analog_edid(connector); + + if (edid != NULL) { + if (intel_sdvo_connector_matches_edid(to_intel_sdvo_connector(connector), + edid)) { + drm_mode_connector_update_edid_property(connector, edid); + drm_add_edid_modes(connector, edid); + } + + kfree(edid); + } +} + +/* + * Set of SDVO TV modes. + * Note! This is in reply order (see loop in get_tv_modes). + * XXX: all 60Hz refresh? + */ +static const struct drm_display_mode sdvo_tv_modes[] = { + { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384, + 416, 0, 200, 201, 232, 233, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384, + 416, 0, 240, 241, 272, 273, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464, + 496, 0, 300, 301, 332, 333, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704, + 736, 0, 350, 351, 382, 383, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704, + 736, 0, 400, 401, 432, 433, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704, + 736, 0, 480, 481, 512, 513, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768, + 800, 0, 480, 481, 512, 513, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768, + 800, 0, 576, 577, 608, 609, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784, + 816, 0, 350, 351, 382, 383, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784, + 816, 0, 400, 401, 432, 433, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784, + 816, 0, 480, 481, 512, 513, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784, + 816, 0, 540, 541, 572, 573, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784, + 816, 0, 576, 577, 608, 609, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832, + 864, 0, 576, 577, 608, 609, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864, + 896, 0, 600, 601, 632, 633, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896, + 928, 0, 624, 625, 656, 657, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984, + 1016, 0, 766, 767, 798, 799, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088, + 1120, 0, 768, 769, 800, 801, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344, + 1376, 0, 1024, 1025, 1056, 1057, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, +}; + +static void intel_sdvo_get_tv_modes(struct drm_connector *connector) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct intel_sdvo_sdtv_resolution_request tv_res; + uint32_t reply = 0, format_map = 0; + int i; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector)); + + /* Read the list of supported input resolutions for the selected TV + * format. + */ + format_map = 1 << intel_sdvo->tv_format_index; + memcpy(&tv_res, &format_map, + min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); + + if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output)) + return; + + BUILD_BUG_ON(sizeof(tv_res) != 3); + if (!intel_sdvo_write_cmd(intel_sdvo, + SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, + &tv_res, sizeof(tv_res))) + return; + if (!intel_sdvo_read_response(intel_sdvo, &reply, 3)) + return; + + for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++) + if (reply & (1 << i)) { + struct drm_display_mode *nmode; + nmode = drm_mode_duplicate(connector->dev, + &sdvo_tv_modes[i]); + if (nmode) + drm_mode_probed_add(connector, nmode); + } +} + +static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct drm_display_mode *newmode; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector)); + + /* + * Fetch modes from VBT. For SDVO prefer the VBT mode since some + * SDVO->LVDS transcoders can't cope with the EDID mode. + */ + if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) { + newmode = drm_mode_duplicate(connector->dev, + dev_priv->vbt.sdvo_lvds_vbt_mode); + if (newmode != NULL) { + /* Guarantee the mode is preferred */ + newmode->type = (DRM_MODE_TYPE_PREFERRED | + DRM_MODE_TYPE_DRIVER); + drm_mode_probed_add(connector, newmode); + } + } + + /* + * Attempt to get the mode list from DDC. + * Assume that the preferred modes are + * arranged in priority order. + */ + intel_ddc_get_modes(connector, &intel_sdvo->ddc); + + list_for_each_entry(newmode, &connector->probed_modes, head) { + if (newmode->type & DRM_MODE_TYPE_PREFERRED) { + intel_sdvo->sdvo_lvds_fixed_mode = + drm_mode_duplicate(connector->dev, newmode); + + intel_sdvo->is_lvds = true; + break; + } + } +} + +static int intel_sdvo_get_modes(struct drm_connector *connector) +{ + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + + if (IS_TV(intel_sdvo_connector)) + intel_sdvo_get_tv_modes(connector); + else if (IS_LVDS(intel_sdvo_connector)) + intel_sdvo_get_lvds_modes(connector); + else + intel_sdvo_get_ddc_modes(connector); + + return !list_empty(&connector->probed_modes); +} + +static void +intel_sdvo_destroy_enhance_property(struct drm_connector *connector) +{ + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + struct drm_device *dev = connector->dev; + + if (intel_sdvo_connector->left) + drm_property_destroy(dev, intel_sdvo_connector->left); + if (intel_sdvo_connector->right) + drm_property_destroy(dev, intel_sdvo_connector->right); + if (intel_sdvo_connector->top) + drm_property_destroy(dev, intel_sdvo_connector->top); + if (intel_sdvo_connector->bottom) + drm_property_destroy(dev, intel_sdvo_connector->bottom); + if (intel_sdvo_connector->hpos) + drm_property_destroy(dev, intel_sdvo_connector->hpos); + if (intel_sdvo_connector->vpos) + drm_property_destroy(dev, intel_sdvo_connector->vpos); + if (intel_sdvo_connector->saturation) + drm_property_destroy(dev, intel_sdvo_connector->saturation); + if (intel_sdvo_connector->contrast) + drm_property_destroy(dev, intel_sdvo_connector->contrast); + if (intel_sdvo_connector->hue) + drm_property_destroy(dev, intel_sdvo_connector->hue); + if (intel_sdvo_connector->sharpness) + drm_property_destroy(dev, intel_sdvo_connector->sharpness); + if (intel_sdvo_connector->flicker_filter) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter); + if (intel_sdvo_connector->flicker_filter_2d) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_2d); + if (intel_sdvo_connector->flicker_filter_adaptive) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_adaptive); + if (intel_sdvo_connector->tv_luma_filter) + drm_property_destroy(dev, intel_sdvo_connector->tv_luma_filter); + if (intel_sdvo_connector->tv_chroma_filter) + drm_property_destroy(dev, intel_sdvo_connector->tv_chroma_filter); + if (intel_sdvo_connector->dot_crawl) + drm_property_destroy(dev, intel_sdvo_connector->dot_crawl); + if (intel_sdvo_connector->brightness) + drm_property_destroy(dev, intel_sdvo_connector->brightness); +} + +static void intel_sdvo_destroy(struct drm_connector *connector) +{ + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + + if (intel_sdvo_connector->tv_format) + drm_property_destroy(connector->dev, + intel_sdvo_connector->tv_format); + + intel_sdvo_destroy_enhance_property(connector); + drm_connector_cleanup(connector); + kfree(intel_sdvo_connector); +} + +static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct edid *edid; + bool has_audio = false; + + if (!intel_sdvo->is_hdmi) + return false; + + edid = intel_sdvo_get_edid(connector); + if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL) + has_audio = drm_detect_monitor_audio(edid); + kfree(edid); + + return has_audio; +} + +static int +intel_sdvo_set_property(struct drm_connector *connector, + struct drm_property *property, + uint64_t val) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint16_t temp_value; + uint8_t cmd; + int ret; + + ret = drm_object_property_set_value(&connector->base, property, val); + if (ret) + return ret; + + if (property == dev_priv->force_audio_property) { + int i = val; + bool has_audio; + + if (i == intel_sdvo_connector->force_audio) + return 0; + + intel_sdvo_connector->force_audio = i; + + if (i == HDMI_AUDIO_AUTO) + has_audio = intel_sdvo_detect_hdmi_audio(connector); + else + has_audio = (i == HDMI_AUDIO_ON); + + if (has_audio == intel_sdvo->has_hdmi_audio) + return 0; + + intel_sdvo->has_hdmi_audio = has_audio; + goto done; + } + + if (property == dev_priv->broadcast_rgb_property) { + bool old_auto = intel_sdvo->color_range_auto; + uint32_t old_range = intel_sdvo->color_range; + + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_sdvo->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_sdvo->color_range_auto = false; + intel_sdvo->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_sdvo->color_range_auto = false; + /* FIXME: this bit is only valid when using TMDS + * encoding and 8 bit per color mode. */ + intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } + + if (old_auto == intel_sdvo->color_range_auto && + old_range == intel_sdvo->color_range) + return 0; + + goto done; + } + +#define CHECK_PROPERTY(name, NAME) \ + if (intel_sdvo_connector->name == property) { \ + if (intel_sdvo_connector->cur_##name == temp_value) return 0; \ + if (intel_sdvo_connector->max_##name < temp_value) return -EINVAL; \ + cmd = SDVO_CMD_SET_##NAME; \ + intel_sdvo_connector->cur_##name = temp_value; \ + goto set_value; \ + } + + if (property == intel_sdvo_connector->tv_format) { + if (val >= TV_FORMAT_NUM) + return -EINVAL; + + if (intel_sdvo->tv_format_index == + intel_sdvo_connector->tv_format_supported[val]) + return 0; + + intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val]; + goto done; + } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { + temp_value = val; + if (intel_sdvo_connector->left == property) { + drm_object_property_set_value(&connector->base, + intel_sdvo_connector->right, val); + if (intel_sdvo_connector->left_margin == temp_value) + return 0; + + intel_sdvo_connector->left_margin = temp_value; + intel_sdvo_connector->right_margin = temp_value; + temp_value = intel_sdvo_connector->max_hscan - + intel_sdvo_connector->left_margin; + cmd = SDVO_CMD_SET_OVERSCAN_H; + goto set_value; + } else if (intel_sdvo_connector->right == property) { + drm_object_property_set_value(&connector->base, + intel_sdvo_connector->left, val); + if (intel_sdvo_connector->right_margin == temp_value) + return 0; + + intel_sdvo_connector->left_margin = temp_value; + intel_sdvo_connector->right_margin = temp_value; + temp_value = intel_sdvo_connector->max_hscan - + intel_sdvo_connector->left_margin; + cmd = SDVO_CMD_SET_OVERSCAN_H; + goto set_value; + } else if (intel_sdvo_connector->top == property) { + drm_object_property_set_value(&connector->base, + intel_sdvo_connector->bottom, val); + if (intel_sdvo_connector->top_margin == temp_value) + return 0; + + intel_sdvo_connector->top_margin = temp_value; + intel_sdvo_connector->bottom_margin = temp_value; + temp_value = intel_sdvo_connector->max_vscan - + intel_sdvo_connector->top_margin; + cmd = SDVO_CMD_SET_OVERSCAN_V; + goto set_value; + } else if (intel_sdvo_connector->bottom == property) { + drm_object_property_set_value(&connector->base, + intel_sdvo_connector->top, val); + if (intel_sdvo_connector->bottom_margin == temp_value) + return 0; + + intel_sdvo_connector->top_margin = temp_value; + intel_sdvo_connector->bottom_margin = temp_value; + temp_value = intel_sdvo_connector->max_vscan - + intel_sdvo_connector->top_margin; + cmd = SDVO_CMD_SET_OVERSCAN_V; + goto set_value; + } + CHECK_PROPERTY(hpos, HPOS) + CHECK_PROPERTY(vpos, VPOS) + CHECK_PROPERTY(saturation, SATURATION) + CHECK_PROPERTY(contrast, CONTRAST) + CHECK_PROPERTY(hue, HUE) + CHECK_PROPERTY(brightness, BRIGHTNESS) + CHECK_PROPERTY(sharpness, SHARPNESS) + CHECK_PROPERTY(flicker_filter, FLICKER_FILTER) + CHECK_PROPERTY(flicker_filter_2d, FLICKER_FILTER_2D) + CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE) + CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER) + CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER) + CHECK_PROPERTY(dot_crawl, DOT_CRAWL) + } + + return -EINVAL; /* unknown property */ + +set_value: + if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) + return -EIO; + + +done: + if (intel_sdvo->base.base.crtc) + intel_crtc_restore_mode(intel_sdvo->base.base.crtc); + + return 0; +#undef CHECK_PROPERTY +} + +static const struct drm_connector_funcs intel_sdvo_connector_funcs = { + .dpms = intel_sdvo_dpms, + .detect = intel_sdvo_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = intel_sdvo_set_property, + .destroy = intel_sdvo_destroy, +}; + +static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { + .get_modes = intel_sdvo_get_modes, + .mode_valid = intel_sdvo_mode_valid, + .best_encoder = intel_best_encoder, +}; + +static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) +{ + struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder)); + + if (intel_sdvo->sdvo_lvds_fixed_mode != NULL) + drm_mode_destroy(encoder->dev, + intel_sdvo->sdvo_lvds_fixed_mode); + + i2c_del_adapter(&intel_sdvo->ddc); + intel_encoder_destroy(encoder); +} + +static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { + .destroy = intel_sdvo_enc_destroy, +}; + +static void +intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) +{ + uint16_t mask = 0; + unsigned int num_bits; + + /* Make a mask of outputs less than or equal to our own priority in the + * list. + */ + switch (sdvo->controlled_output) { + case SDVO_OUTPUT_LVDS1: + mask |= SDVO_OUTPUT_LVDS1; + case SDVO_OUTPUT_LVDS0: + mask |= SDVO_OUTPUT_LVDS0; + case SDVO_OUTPUT_TMDS1: + mask |= SDVO_OUTPUT_TMDS1; + case SDVO_OUTPUT_TMDS0: + mask |= SDVO_OUTPUT_TMDS0; + case SDVO_OUTPUT_RGB1: + mask |= SDVO_OUTPUT_RGB1; + case SDVO_OUTPUT_RGB0: + mask |= SDVO_OUTPUT_RGB0; + break; + } + + /* Count bits to find what number we are in the priority list. */ + mask &= sdvo->caps.output_flags; + num_bits = hweight16(mask); + /* If more than 3 outputs, default to DDC bus 3 for now. */ + if (num_bits > 3) + num_bits = 3; + + /* Corresponds to SDVO_CONTROL_BUS_DDCx */ + sdvo->ddc_bus = 1 << num_bits; +} + +/** + * Choose the appropriate DDC bus for control bus switch command for this + * SDVO output based on the controlled output. + * + * DDC bus number assignment is in a priority order of RGB outputs, then TMDS + * outputs, then LVDS outputs. + */ +static void +intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, + struct intel_sdvo *sdvo, u32 reg) +{ + struct sdvo_device_mapping *mapping; + + if (sdvo->is_sdvob) + mapping = &(dev_priv->sdvo_mappings[0]); + else + mapping = &(dev_priv->sdvo_mappings[1]); + + if (mapping->initialized) + sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4); + else + intel_sdvo_guess_ddc_bus(sdvo); +} + +static void +intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, + struct intel_sdvo *sdvo, u32 reg) +{ + struct sdvo_device_mapping *mapping; + u8 pin; + + if (sdvo->is_sdvob) + mapping = &dev_priv->sdvo_mappings[0]; + else + mapping = &dev_priv->sdvo_mappings[1]; + + if (mapping->initialized && intel_gmbus_is_port_valid(mapping->i2c_pin)) + pin = mapping->i2c_pin; + else + pin = GMBUS_PORT_DPB; + + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); + + /* With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow + * our code totally fails once we start using gmbus. Hence fall back to + * bit banging for now. */ + intel_gmbus_force_bit(sdvo->i2c, true); +} + +/* undo any changes intel_sdvo_select_i2c_bus() did to sdvo->i2c */ +static void +intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo) +{ + intel_gmbus_force_bit(sdvo->i2c, false); +} + +static bool +intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device) +{ + return intel_sdvo_check_supp_encode(intel_sdvo); +} + +static u8 +intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct sdvo_device_mapping *my_mapping, *other_mapping; + + if (sdvo->is_sdvob) { + my_mapping = &dev_priv->sdvo_mappings[0]; + other_mapping = &dev_priv->sdvo_mappings[1]; + } else { + my_mapping = &dev_priv->sdvo_mappings[1]; + other_mapping = &dev_priv->sdvo_mappings[0]; + } + + /* If the BIOS described our SDVO device, take advantage of it. */ + if (my_mapping->slave_addr) + return my_mapping->slave_addr; + + /* If the BIOS only described a different SDVO device, use the + * address that it isn't using. + */ + if (other_mapping->slave_addr) { + if (other_mapping->slave_addr == 0x70) + return 0x72; + else + return 0x70; + } + + /* No SDVO device info is found for another DVO port, + * so use mapping assumption we had before BIOS parsing. + */ + if (sdvo->is_sdvob) + return 0x70; + else + return 0x72; +} + +static void +intel_sdvo_connector_init(struct intel_sdvo_connector *connector, + struct intel_sdvo *encoder) +{ + drm_connector_init(encoder->base.base.dev, + &connector->base.base, + &intel_sdvo_connector_funcs, + connector->base.base.connector_type); + + drm_connector_helper_add(&connector->base.base, + &intel_sdvo_connector_helper_funcs); + + connector->base.base.interlace_allowed = 1; + connector->base.base.doublescan_allowed = 0; + connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; + connector->base.get_hw_state = intel_sdvo_connector_get_hw_state; + + intel_connector_attach_encoder(&connector->base, &encoder->base); + drm_sysfs_connector_add(&connector->base.base); +} + +static void +intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *connector) +{ + struct drm_device *dev = connector->base.base.dev; + + intel_attach_force_audio_property(&connector->base.base); + if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) { + intel_attach_broadcast_rgb_property(&connector->base.base); + intel_sdvo->color_range_auto = true; + } +} + +static bool +intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) +{ + struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_connector *connector; + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; + + DRM_DEBUG_KMS("initialising DVI device %d\n", device); + + intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + + if (device == 0) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; + } else if (device == 1) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; + } + + intel_connector = &intel_sdvo_connector->base; + connector = &intel_connector->base; + if (intel_sdvo_get_hotplug_support(intel_sdvo) & + intel_sdvo_connector->output_flag) { + intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag; + /* Some SDVO devices have one-shot hotplug interrupts. + * Ensure that they get re-enabled when an interrupt happens. + */ + intel_encoder->hot_plug = intel_sdvo_enable_hotplug; + intel_sdvo_enable_hotplug(intel_encoder); + } else { + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + } + encoder->encoder_type = DRM_MODE_ENCODER_TMDS; + connector->connector_type = DRM_MODE_CONNECTOR_DVID; + + if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) { + connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; + intel_sdvo->is_hdmi = true; + } + + intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); + if (intel_sdvo->is_hdmi) + intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector); + + return true; +} + +static bool +intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) +{ + struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; + + DRM_DEBUG_KMS("initialising TV type %d\n", type); + + intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + + intel_connector = &intel_sdvo_connector->base; + connector = &intel_connector->base; + encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; + connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; + + intel_sdvo->controlled_output |= type; + intel_sdvo_connector->output_flag = type; + + intel_sdvo->is_tv = true; + + intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); + + if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type)) + goto err; + + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + goto err; + + return true; + +err: + drm_sysfs_connector_remove(connector); + intel_sdvo_destroy(connector); + return false; +} + +static bool +intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) +{ + struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; + + DRM_DEBUG_KMS("initialising analog device %d\n", device); + + intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + + intel_connector = &intel_sdvo_connector->base; + connector = &intel_connector->base; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; + encoder->encoder_type = DRM_MODE_ENCODER_DAC; + connector->connector_type = DRM_MODE_CONNECTOR_VGA; + + if (device == 0) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; + } else if (device == 1) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; + } + + intel_sdvo_connector_init(intel_sdvo_connector, + intel_sdvo); + return true; +} + +static bool +intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) +{ + struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; + + DRM_DEBUG_KMS("initialising LVDS device %d\n", device); + + intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + + intel_connector = &intel_sdvo_connector->base; + connector = &intel_connector->base; + encoder->encoder_type = DRM_MODE_ENCODER_LVDS; + connector->connector_type = DRM_MODE_CONNECTOR_LVDS; + + if (device == 0) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; + } else if (device == 1) { + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; + } + + intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + goto err; + + return true; + +err: + drm_sysfs_connector_remove(connector); + intel_sdvo_destroy(connector); + return false; +} + +static bool +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) +{ + intel_sdvo->is_tv = false; + intel_sdvo->is_lvds = false; + + /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ + + if (flags & SDVO_OUTPUT_TMDS0) + if (!intel_sdvo_dvi_init(intel_sdvo, 0)) + return false; + + if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK) + if (!intel_sdvo_dvi_init(intel_sdvo, 1)) + return false; + + /* TV has no XXX1 function block */ + if (flags & SDVO_OUTPUT_SVID0) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0)) + return false; + + if (flags & SDVO_OUTPUT_CVBS0) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0)) + return false; + + if (flags & SDVO_OUTPUT_YPRPB0) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0)) + return false; + + if (flags & SDVO_OUTPUT_RGB0) + if (!intel_sdvo_analog_init(intel_sdvo, 0)) + return false; + + if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK) + if (!intel_sdvo_analog_init(intel_sdvo, 1)) + return false; + + if (flags & SDVO_OUTPUT_LVDS0) + if (!intel_sdvo_lvds_init(intel_sdvo, 0)) + return false; + + if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK) + if (!intel_sdvo_lvds_init(intel_sdvo, 1)) + return false; + + if ((flags & SDVO_OUTPUT_MASK) == 0) { + unsigned char bytes[2]; + + intel_sdvo->controlled_output = 0; + memcpy(bytes, &intel_sdvo->caps.output_flags, 2); + DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", + SDVO_NAME(intel_sdvo), + bytes[0], bytes[1]); + return false; + } + intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + + return true; +} + +static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo) +{ + struct drm_device *dev = intel_sdvo->base.base.dev; + struct drm_connector *connector, *tmp; + + list_for_each_entry_safe(connector, tmp, + &dev->mode_config.connector_list, head) { + if (intel_attached_encoder(connector) == &intel_sdvo->base) { + drm_sysfs_connector_remove(connector); + intel_sdvo_destroy(connector); + } + } +} + +static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + int type) +{ + struct drm_device *dev = intel_sdvo->base.base.dev; + struct intel_sdvo_tv_format format; + uint32_t format_map, i; + + if (!intel_sdvo_set_target_output(intel_sdvo, type)) + return false; + + BUILD_BUG_ON(sizeof(format) != 6); + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_TV_FORMATS, + &format, sizeof(format))) + return false; + + memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format))); + + if (format_map == 0) + return false; + + intel_sdvo_connector->format_supported_num = 0; + for (i = 0 ; i < TV_FORMAT_NUM; i++) + if (format_map & (1 << i)) + intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i; + + + intel_sdvo_connector->tv_format = + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "mode", intel_sdvo_connector->format_supported_num); + if (!intel_sdvo_connector->tv_format) + return false; + + for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) + drm_property_add_enum( + intel_sdvo_connector->tv_format, i, + i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); + + intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; + drm_object_attach_property(&intel_sdvo_connector->base.base.base, + intel_sdvo_connector->tv_format, 0); + return true; + +} + +#define ENHANCEMENT(name, NAME) do { \ + if (enhancements.name) { \ + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \ + !intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \ + return false; \ + intel_sdvo_connector->max_##name = data_value[0]; \ + intel_sdvo_connector->cur_##name = response; \ + intel_sdvo_connector->name = \ + drm_property_create_range(dev, 0, #name, 0, data_value[0]); \ + if (!intel_sdvo_connector->name) return false; \ + drm_object_attach_property(&connector->base, \ + intel_sdvo_connector->name, \ + intel_sdvo_connector->cur_##name); \ + DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ + data_value[0], data_value[1], response); \ + } \ +} while (0) + +static bool +intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + struct intel_sdvo_enhancements_reply enhancements) +{ + struct drm_device *dev = intel_sdvo->base.base.dev; + struct drm_connector *connector = &intel_sdvo_connector->base.base; + uint16_t response, data_value[2]; + + /* when horizontal overscan is supported, Add the left/right property */ + if (enhancements.overscan_h) { + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_H, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_H, + &response, 2)) + return false; + + intel_sdvo_connector->max_hscan = data_value[0]; + intel_sdvo_connector->left_margin = data_value[0] - response; + intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; + intel_sdvo_connector->left = + drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]); + if (!intel_sdvo_connector->left) + return false; + + drm_object_attach_property(&connector->base, + intel_sdvo_connector->left, + intel_sdvo_connector->left_margin); + + intel_sdvo_connector->right = + drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]); + if (!intel_sdvo_connector->right) + return false; + + drm_object_attach_property(&connector->base, + intel_sdvo_connector->right, + intel_sdvo_connector->right_margin); + DRM_DEBUG_KMS("h_overscan: max %d, " + "default %d, current %d\n", + data_value[0], data_value[1], response); + } + + if (enhancements.overscan_v) { + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_V, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_V, + &response, 2)) + return false; + + intel_sdvo_connector->max_vscan = data_value[0]; + intel_sdvo_connector->top_margin = data_value[0] - response; + intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; + intel_sdvo_connector->top = + drm_property_create_range(dev, 0, + "top_margin", 0, data_value[0]); + if (!intel_sdvo_connector->top) + return false; + + drm_object_attach_property(&connector->base, + intel_sdvo_connector->top, + intel_sdvo_connector->top_margin); + + intel_sdvo_connector->bottom = + drm_property_create_range(dev, 0, + "bottom_margin", 0, data_value[0]); + if (!intel_sdvo_connector->bottom) + return false; + + drm_object_attach_property(&connector->base, + intel_sdvo_connector->bottom, + intel_sdvo_connector->bottom_margin); + DRM_DEBUG_KMS("v_overscan: max %d, " + "default %d, current %d\n", + data_value[0], data_value[1], response); + } + + ENHANCEMENT(hpos, HPOS); + ENHANCEMENT(vpos, VPOS); + ENHANCEMENT(saturation, SATURATION); + ENHANCEMENT(contrast, CONTRAST); + ENHANCEMENT(hue, HUE); + ENHANCEMENT(sharpness, SHARPNESS); + ENHANCEMENT(brightness, BRIGHTNESS); + ENHANCEMENT(flicker_filter, FLICKER_FILTER); + ENHANCEMENT(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE); + ENHANCEMENT(flicker_filter_2d, FLICKER_FILTER_2D); + ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER); + ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER); + + if (enhancements.dot_crawl) { + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2)) + return false; + + intel_sdvo_connector->max_dot_crawl = 1; + intel_sdvo_connector->cur_dot_crawl = response & 0x1; + intel_sdvo_connector->dot_crawl = + drm_property_create_range(dev, 0, "dot_crawl", 0, 1); + if (!intel_sdvo_connector->dot_crawl) + return false; + + drm_object_attach_property(&connector->base, + intel_sdvo_connector->dot_crawl, + intel_sdvo_connector->cur_dot_crawl); + DRM_DEBUG_KMS("dot crawl: current %d\n", response); + } + + return true; +} + +static bool +intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + struct intel_sdvo_enhancements_reply enhancements) +{ + struct drm_device *dev = intel_sdvo->base.base.dev; + struct drm_connector *connector = &intel_sdvo_connector->base.base; + uint16_t response, data_value[2]; + + ENHANCEMENT(brightness, BRIGHTNESS); + + return true; +} +#undef ENHANCEMENT + +static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector) +{ + union { + struct intel_sdvo_enhancements_reply reply; + uint16_t response; + } enhancements; + + BUILD_BUG_ON(sizeof(enhancements) != 2); + + enhancements.response = 0; + intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + &enhancements, sizeof(enhancements)); + if (enhancements.response == 0) { + DRM_DEBUG_KMS("No enhancement is supported\n"); + return true; + } + + if (IS_TV(intel_sdvo_connector)) + return intel_sdvo_create_enhance_property_tv(intel_sdvo, intel_sdvo_connector, enhancements.reply); + else if (IS_LVDS(intel_sdvo_connector)) + return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply); + else + return true; +} + +static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) +{ + struct intel_sdvo *sdvo = adapter->algo_data; + + if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus)) + return -EIO; + + return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num); +} + +static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter) +{ + struct intel_sdvo *sdvo = adapter->algo_data; + return sdvo->i2c->algo->functionality(sdvo->i2c); +} + +static const struct i2c_algorithm intel_sdvo_ddc_proxy = { + .master_xfer = intel_sdvo_ddc_proxy_xfer, + .functionality = intel_sdvo_ddc_proxy_func +}; + +static bool +intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, + struct drm_device *dev) +{ + sdvo->ddc.owner = THIS_MODULE; + sdvo->ddc.class = I2C_CLASS_DDC; + snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); + sdvo->ddc.dev.parent = &dev->pdev->dev; + sdvo->ddc.algo_data = sdvo; + sdvo->ddc.algo = &intel_sdvo_ddc_proxy; + + return i2c_add_adapter(&sdvo->ddc) == 0; +} + +bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + struct intel_sdvo *intel_sdvo; + int i; + intel_sdvo = kzalloc(sizeof(*intel_sdvo), GFP_KERNEL); + if (!intel_sdvo) + return false; + + intel_sdvo->sdvo_reg = sdvo_reg; + intel_sdvo->is_sdvob = is_sdvob; + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1; + intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg); + if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) + goto err_i2c_bus; + + /* encoder type will be decided later */ + intel_encoder = &intel_sdvo->base; + intel_encoder->type = INTEL_OUTPUT_SDVO; + drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0); + + /* Read the regs to test if we can talk to the device */ + for (i = 0; i < 0x40; i++) { + u8 byte; + + if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) { + DRM_DEBUG_KMS("No SDVO device found on %s\n", + SDVO_NAME(intel_sdvo)); + goto err; + } + } + + intel_encoder->compute_config = intel_sdvo_compute_config; + intel_encoder->disable = intel_disable_sdvo; + intel_encoder->mode_set = intel_sdvo_mode_set; + intel_encoder->enable = intel_enable_sdvo; + intel_encoder->get_hw_state = intel_sdvo_get_hw_state; + intel_encoder->get_config = intel_sdvo_get_config; + + /* In default case sdvo lvds is false */ + if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) + goto err; + + if (intel_sdvo_output_setup(intel_sdvo, + intel_sdvo->caps.output_flags) != true) { + DRM_DEBUG_KMS("SDVO output failed to setup on %s\n", + SDVO_NAME(intel_sdvo)); + /* Output_setup can leave behind connectors! */ + goto err_output; + } + + /* Only enable the hotplug irq if we need it, to work around noisy + * hotplug lines. + */ + if (intel_sdvo->hotplug_active) { + intel_encoder->hpd_pin = + intel_sdvo->is_sdvob ? HPD_SDVO_B : HPD_SDVO_C; + } + + /* + * Cloning SDVO with anything is often impossible, since the SDVO + * encoder can request a special input timing mode. And even if that's + * not the case we have evidence that cloning a plain unscaled mode with + * VGA doesn't really work. Furthermore the cloning flags are way too + * simplistic anyway to express such constraints, so just give up on + * cloning for SDVO encoders. + */ + intel_sdvo->base.cloneable = false; + + intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); + + /* Set the input timing to the screen. Assume always input 0. */ + if (!intel_sdvo_set_target_input(intel_sdvo)) + goto err_output; + + if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo, + &intel_sdvo->pixel_clock_min, + &intel_sdvo->pixel_clock_max)) + goto err_output; + + DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " + "clock range %dMHz - %dMHz, " + "input 1: %c, input 2: %c, " + "output 1: %c, output 2: %c\n", + SDVO_NAME(intel_sdvo), + intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id, + intel_sdvo->caps.device_rev_id, + intel_sdvo->pixel_clock_min / 1000, + intel_sdvo->pixel_clock_max / 1000, + (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + /* check currently supported outputs */ + intel_sdvo->caps.output_flags & + (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', + intel_sdvo->caps.output_flags & + (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); + return true; + +err_output: + intel_sdvo_output_cleanup(intel_sdvo); + +err: + drm_encoder_cleanup(&intel_encoder->base); + i2c_del_adapter(&intel_sdvo->ddc); +err_i2c_bus: + intel_sdvo_unselect_i2c_bus(intel_sdvo); + kfree(intel_sdvo); + + return false; +} --- linux-3.13.0.orig/ubuntu/i915/i915_gem_execbuffer.c +++ linux-3.13.0/ubuntu/i915/i915_gem_execbuffer.c @@ -0,0 +1,1404 @@ +/* + * Copyright © 2008,2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Chris Wilson + * + */ + +#include +#include +#include "i915_drv.h" +#include "i915_trace.h" +#include "intel_drv.h" +#include + +#define __EXEC_OBJECT_HAS_PIN (1<<31) +#define __EXEC_OBJECT_HAS_FENCE (1<<30) + +struct eb_vmas { + struct list_head vmas; + int and; + union { + struct i915_vma *lut[0]; + struct hlist_head buckets[0]; + }; +}; + +static struct eb_vmas * +eb_create(struct drm_i915_gem_execbuffer2 *args) +{ + struct eb_vmas *eb = NULL; + + if (args->flags & I915_EXEC_HANDLE_LUT) { + unsigned size = args->buffer_count; + size *= sizeof(struct i915_vma *); + size += sizeof(struct eb_vmas); + eb = kmalloc(size, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); + } + + if (eb == NULL) { + unsigned size = args->buffer_count; + unsigned count = PAGE_SIZE / sizeof(struct hlist_head) / 2; + BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head)); + while (count > 2*size) + count >>= 1; + eb = kzalloc(count*sizeof(struct hlist_head) + + sizeof(struct eb_vmas), + GFP_TEMPORARY); + if (eb == NULL) + return eb; + + eb->and = count - 1; + } else + eb->and = -args->buffer_count; + + INIT_LIST_HEAD(&eb->vmas); + return eb; +} + +static void +eb_reset(struct eb_vmas *eb) +{ + if (eb->and >= 0) + memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); +} + +static int +eb_lookup_vmas(struct eb_vmas *eb, + struct drm_i915_gem_exec_object2 *exec, + const struct drm_i915_gem_execbuffer2 *args, + struct i915_address_space *vm, + struct drm_file *file) +{ + struct drm_i915_gem_object *obj; + struct list_head objects; + int i, ret; + + INIT_LIST_HEAD(&objects); + spin_lock(&file->table_lock); + /* Grab a reference to the object and release the lock so we can lookup + * or create the VMA without using GFP_ATOMIC */ + for (i = 0; i < args->buffer_count; i++) { + obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle)); + if (obj == NULL) { + spin_unlock(&file->table_lock); + DRM_DEBUG("Invalid object handle %d at index %d\n", + exec[i].handle, i); + ret = -ENOENT; + goto err; + } + + if (!list_empty(&obj->obj_exec_link)) { + spin_unlock(&file->table_lock); + DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n", + obj, exec[i].handle, i); + ret = -EINVAL; + goto err; + } + + drm_gem_object_reference(&obj->base); + list_add_tail(&obj->obj_exec_link, &objects); + } + spin_unlock(&file->table_lock); + + i = 0; + while (!list_empty(&objects)) { + struct i915_vma *vma; + + obj = list_first_entry(&objects, + struct drm_i915_gem_object, + obj_exec_link); + + /* + * NOTE: We can leak any vmas created here when something fails + * later on. But that's no issue since vma_unbind can deal with + * vmas which are not actually bound. And since only + * lookup_or_create exists as an interface to get at the vma + * from the (obj, vm) we don't run the risk of creating + * duplicated vmas for the same vm. + */ + vma = i915_gem_obj_lookup_or_create_vma(obj, vm); + if (IS_ERR(vma)) { + DRM_DEBUG("Failed to lookup VMA\n"); + ret = PTR_ERR(vma); + goto err; + } + + /* Transfer ownership from the objects list to the vmas list. */ + list_add_tail(&vma->exec_list, &eb->vmas); + list_del_init(&obj->obj_exec_link); + + vma->exec_entry = &exec[i]; + if (eb->and < 0) { + eb->lut[i] = vma; + } else { + uint32_t handle = args->flags & I915_EXEC_HANDLE_LUT ? i : exec[i].handle; + vma->exec_handle = handle; + hlist_add_head(&vma->exec_node, + &eb->buckets[handle & eb->and]); + } + ++i; + } + + return 0; + + +err: + while (!list_empty(&objects)) { + obj = list_first_entry(&objects, + struct drm_i915_gem_object, + obj_exec_link); + list_del_init(&obj->obj_exec_link); + drm_gem_object_unreference(&obj->base); + } + /* + * Objects already transfered to the vmas list will be unreferenced by + * eb_destroy. + */ + + return ret; +} + +static struct i915_vma *eb_get_vma(struct eb_vmas *eb, unsigned long handle) +{ + if (eb->and < 0) { + if (handle >= -eb->and) + return NULL; + return eb->lut[handle]; + } else { + struct hlist_head *head; + struct hlist_node *node; + + head = &eb->buckets[handle & eb->and]; + hlist_for_each(node, head) { + struct i915_vma *vma; + + vma = hlist_entry(node, struct i915_vma, exec_node); + if (vma->exec_handle == handle) + return vma; + } + return NULL; + } +} + +static void +i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma) +{ + struct drm_i915_gem_exec_object2 *entry; + struct drm_i915_gem_object *obj = vma->obj; + + if (!drm_mm_node_allocated(&vma->node)) + return; + + entry = vma->exec_entry; + + if (entry->flags & __EXEC_OBJECT_HAS_FENCE) + i915_gem_object_unpin_fence(obj); + + if (entry->flags & __EXEC_OBJECT_HAS_PIN) + i915_gem_object_unpin(obj); + + entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN); +} + +static void eb_destroy(struct eb_vmas *eb) +{ + while (!list_empty(&eb->vmas)) { + struct i915_vma *vma; + + vma = list_first_entry(&eb->vmas, + struct i915_vma, + exec_list); + list_del_init(&vma->exec_list); + i915_gem_execbuffer_unreserve_vma(vma); + drm_gem_object_unreference(&vma->obj->base); + } + kfree(eb); +} + +static inline int use_cpu_reloc(struct drm_i915_gem_object *obj) +{ + return (HAS_LLC(obj->base.dev) || + obj->base.write_domain == I915_GEM_DOMAIN_CPU || + !obj->map_and_fenceable || + obj->cache_level != I915_CACHE_NONE); +} + +static int +relocate_entry_cpu(struct drm_i915_gem_object *obj, + struct drm_i915_gem_relocation_entry *reloc) +{ + struct drm_device *dev = obj->base.dev; + uint32_t page_offset = offset_in_page(reloc->offset); + char *vaddr; + int ret; + + ret = i915_gem_object_set_to_cpu_domain(obj, true); + if (ret) + return ret; + + vaddr = kmap_atomic(i915_gem_object_get_page(obj, + reloc->offset >> PAGE_SHIFT)); + *(uint32_t *)(vaddr + page_offset) = reloc->delta; + + if (INTEL_INFO(dev)->gen >= 8) { + page_offset = offset_in_page(page_offset + sizeof(uint32_t)); + + if (page_offset == 0) { + kunmap_atomic(vaddr); + vaddr = kmap_atomic(i915_gem_object_get_page(obj, + (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT)); + } + + *(uint32_t *)(vaddr + page_offset) = 0; + } + + kunmap_atomic(vaddr); + + return 0; +} + +static int +relocate_entry_gtt(struct drm_i915_gem_object *obj, + struct drm_i915_gem_relocation_entry *reloc) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t __iomem *reloc_entry; + void __iomem *reloc_page; + int ret; + + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + return ret; + + ret = i915_gem_object_put_fence(obj); + if (ret) + return ret; + + /* Map the page containing the relocation we're going to perform. */ + reloc->offset += i915_gem_obj_ggtt_offset(obj); + reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, + reloc->offset & PAGE_MASK); + reloc_entry = (uint32_t __iomem *) + (reloc_page + offset_in_page(reloc->offset)); + iowrite32(reloc->delta, reloc_entry); + + if (INTEL_INFO(dev)->gen >= 8) { + reloc_entry += 1; + + if (offset_in_page(reloc->offset + sizeof(uint32_t)) == 0) { + io_mapping_unmap_atomic(reloc_page); + reloc_page = io_mapping_map_atomic_wc( + dev_priv->gtt.mappable, + reloc->offset + sizeof(uint32_t)); + reloc_entry = reloc_page; + } + + iowrite32(0, reloc_entry); + } + + io_mapping_unmap_atomic(reloc_page); + + return 0; +} + +static int +i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, + struct eb_vmas *eb, + struct drm_i915_gem_relocation_entry *reloc, + struct i915_address_space *vm) +{ + struct drm_device *dev = obj->base.dev; + struct drm_gem_object *target_obj; + struct drm_i915_gem_object *target_i915_obj; + struct i915_vma *target_vma; + uint32_t target_offset; + int ret; + + /* we've already hold a reference to all valid objects */ + target_vma = eb_get_vma(eb, reloc->target_handle); + if (unlikely(target_vma == NULL)) + return -ENOENT; + target_i915_obj = target_vma->obj; + target_obj = &target_vma->obj->base; + + target_offset = target_vma->node.start; + + /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and + * pipe_control writes because the gpu doesn't properly redirect them + * through the ppgtt for non_secure batchbuffers. */ + if (unlikely(IS_GEN6(dev) && + reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && + !target_i915_obj->has_global_gtt_mapping)) { + i915_gem_gtt_bind_object(target_i915_obj, + target_i915_obj->cache_level); + } + + /* Validate that the target is in a valid r/w GPU domain */ + if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) { + DRM_DEBUG("reloc with multiple write domains: " + "obj %p target %d offset %d " + "read %08x write %08x", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->read_domains, + reloc->write_domain); + return -EINVAL; + } + if (unlikely((reloc->write_domain | reloc->read_domains) + & ~I915_GEM_GPU_DOMAINS)) { + DRM_DEBUG("reloc with read/write non-GPU domains: " + "obj %p target %d offset %d " + "read %08x write %08x", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->read_domains, + reloc->write_domain); + return -EINVAL; + } + + target_obj->pending_read_domains |= reloc->read_domains; + target_obj->pending_write_domain |= reloc->write_domain; + + /* If the relocation already has the right value in it, no + * more work needs to be done. + */ + if (target_offset == reloc->presumed_offset) + return 0; + + /* Check that the relocation address is valid... */ + if (unlikely(reloc->offset > + obj->base.size - (INTEL_INFO(dev)->gen >= 8 ? 8 : 4))) { + DRM_DEBUG("Relocation beyond object bounds: " + "obj %p target %d offset %d size %d.\n", + obj, reloc->target_handle, + (int) reloc->offset, + (int) obj->base.size); + return -EINVAL; + } + if (unlikely(reloc->offset & 3)) { + DRM_DEBUG("Relocation not 4-byte aligned: " + "obj %p target %d offset %d.\n", + obj, reloc->target_handle, + (int) reloc->offset); + return -EINVAL; + } + + /* We can't wait for rendering with pagefaults disabled */ + if (obj->active && in_atomic()) + return -EFAULT; + + reloc->delta += target_offset; + if (use_cpu_reloc(obj)) + ret = relocate_entry_cpu(obj, reloc); + else + ret = relocate_entry_gtt(obj, reloc); + + if (ret) + return ret; + + /* and update the user's relocation entry */ + reloc->presumed_offset = target_offset; + + return 0; +} + +static int +i915_gem_execbuffer_relocate_vma(struct i915_vma *vma, + struct eb_vmas *eb) +{ +#define N_RELOC(x) ((x) / sizeof(struct drm_i915_gem_relocation_entry)) + struct drm_i915_gem_relocation_entry stack_reloc[N_RELOC(512)]; + struct drm_i915_gem_relocation_entry __user *user_relocs; + struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; + int remain, ret; + + user_relocs = to_user_ptr(entry->relocs_ptr); + + remain = entry->relocation_count; + while (remain) { + struct drm_i915_gem_relocation_entry *r = stack_reloc; + int count = remain; + if (count > ARRAY_SIZE(stack_reloc)) + count = ARRAY_SIZE(stack_reloc); + remain -= count; + + if (__copy_from_user_inatomic(r, user_relocs, count*sizeof(r[0]))) + return -EFAULT; + + do { + u64 offset = r->presumed_offset; + + ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r, + vma->vm); + if (ret) + return ret; + + if (r->presumed_offset != offset && + __copy_to_user_inatomic(&user_relocs->presumed_offset, + &r->presumed_offset, + sizeof(r->presumed_offset))) { + return -EFAULT; + } + + user_relocs++; + r++; + } while (--count); + } + + return 0; +#undef N_RELOC +} + +static int +i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma, + struct eb_vmas *eb, + struct drm_i915_gem_relocation_entry *relocs) +{ + const struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; + int i, ret; + + for (i = 0; i < entry->relocation_count; i++) { + ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i], + vma->vm); + if (ret) + return ret; + } + + return 0; +} + +static int +i915_gem_execbuffer_relocate(struct eb_vmas *eb) +{ + struct i915_vma *vma; + int ret = 0; + + /* This is the fast path and we cannot handle a pagefault whilst + * holding the struct mutex lest the user pass in the relocations + * contained within a mmaped bo. For in such a case we, the page + * fault handler would call i915_gem_fault() and we would try to + * acquire the struct mutex again. Obviously this is bad and so + * lockdep complains vehemently. + */ + pagefault_disable(); + list_for_each_entry(vma, &eb->vmas, exec_list) { + ret = i915_gem_execbuffer_relocate_vma(vma, eb); + if (ret) + break; + } + pagefault_enable(); + + return ret; +} + +static int +need_reloc_mappable(struct i915_vma *vma) +{ + struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; + return entry->relocation_count && !use_cpu_reloc(vma->obj) && + i915_is_ggtt(vma->vm); +} + +static int +i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, + struct intel_ring_buffer *ring, + bool *need_reloc) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; + bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; + bool need_fence, need_mappable; + struct drm_i915_gem_object *obj = vma->obj; + int ret; + + need_fence = + has_fenced_gpu_access && + entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode != I915_TILING_NONE; + need_mappable = need_fence || need_reloc_mappable(vma); + + ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, need_mappable, + false); + if (ret) + return ret; + + entry->flags |= __EXEC_OBJECT_HAS_PIN; + + if (has_fenced_gpu_access) { + if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { + ret = i915_gem_object_get_fence(obj); + if (ret) + return ret; + + if (i915_gem_object_pin_fence(obj)) + entry->flags |= __EXEC_OBJECT_HAS_FENCE; + + obj->pending_fenced_gpu_access = true; + } + } + + /* Ensure ppgtt mapping exists if needed */ + if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) { + i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, + obj, obj->cache_level); + + obj->has_aliasing_ppgtt_mapping = 1; + } + + if (entry->offset != vma->node.start) { + entry->offset = vma->node.start; + *need_reloc = true; + } + + if (entry->flags & EXEC_OBJECT_WRITE) { + obj->base.pending_read_domains = I915_GEM_DOMAIN_RENDER; + obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER; + } + + if (entry->flags & EXEC_OBJECT_NEEDS_GTT && + !obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(obj, obj->cache_level); + + return 0; +} + +static int +i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, + struct list_head *vmas, + bool *need_relocs) +{ + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + struct i915_address_space *vm; + struct list_head ordered_vmas; + bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; + int retry; + + if (list_empty(vmas)) + return 0; + + vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm; + + INIT_LIST_HEAD(&ordered_vmas); + while (!list_empty(vmas)) { + struct drm_i915_gem_exec_object2 *entry; + bool need_fence, need_mappable; + + vma = list_first_entry(vmas, struct i915_vma, exec_list); + obj = vma->obj; + entry = vma->exec_entry; + + need_fence = + has_fenced_gpu_access && + entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode != I915_TILING_NONE; + need_mappable = need_fence || need_reloc_mappable(vma); + + if (need_mappable) + list_move(&vma->exec_list, &ordered_vmas); + else + list_move_tail(&vma->exec_list, &ordered_vmas); + + obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND; + obj->base.pending_write_domain = 0; + obj->pending_fenced_gpu_access = false; + } + list_splice(&ordered_vmas, vmas); + + /* Attempt to pin all of the buffers into the GTT. + * This is done in 3 phases: + * + * 1a. Unbind all objects that do not match the GTT constraints for + * the execbuffer (fenceable, mappable, alignment etc). + * 1b. Increment pin count for already bound objects. + * 2. Bind new objects. + * 3. Decrement pin count. + * + * This avoid unnecessary unbinding of later objects in order to make + * room for the earlier objects *unless* we need to defragment. + */ + retry = 0; + do { + int ret = 0; + + /* Unbind any ill-fitting objects or pin. */ + list_for_each_entry(vma, vmas, exec_list) { + struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; + bool need_fence, need_mappable; + + obj = vma->obj; + + if (!drm_mm_node_allocated(&vma->node)) + continue; + + need_fence = + has_fenced_gpu_access && + entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode != I915_TILING_NONE; + need_mappable = need_fence || need_reloc_mappable(vma); + + WARN_ON((need_mappable || need_fence) && + !i915_is_ggtt(vma->vm)); + + if ((entry->alignment && + vma->node.start & (entry->alignment - 1)) || + (need_mappable && !obj->map_and_fenceable)) + ret = i915_vma_unbind(vma); + else + ret = i915_gem_execbuffer_reserve_vma(vma, ring, need_relocs); + if (ret) + goto err; + } + + /* Bind fresh objects */ + list_for_each_entry(vma, vmas, exec_list) { + if (drm_mm_node_allocated(&vma->node)) + continue; + + ret = i915_gem_execbuffer_reserve_vma(vma, ring, need_relocs); + if (ret) + goto err; + } + +err: + if (ret != -ENOSPC || retry++) + return ret; + + /* Decrement pin count for bound objects */ + list_for_each_entry(vma, vmas, exec_list) + i915_gem_execbuffer_unreserve_vma(vma); + + ret = i915_gem_evict_vm(vm, true); + if (ret) + return ret; + } while (1); +} + +static int +i915_gem_execbuffer_relocate_slow(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *args, + struct drm_file *file, + struct intel_ring_buffer *ring, + struct eb_vmas *eb, + struct drm_i915_gem_exec_object2 *exec) +{ + struct drm_i915_gem_relocation_entry *reloc; + struct i915_address_space *vm; + struct i915_vma *vma; + bool need_relocs; + int *reloc_offset; + int i, total, ret; + unsigned count = args->buffer_count; + + if (WARN_ON(list_empty(&eb->vmas))) + return 0; + + vm = list_first_entry(&eb->vmas, struct i915_vma, exec_list)->vm; + + /* We may process another execbuffer during the unlock... */ + while (!list_empty(&eb->vmas)) { + vma = list_first_entry(&eb->vmas, struct i915_vma, exec_list); + list_del_init(&vma->exec_list); + i915_gem_execbuffer_unreserve_vma(vma); + drm_gem_object_unreference(&vma->obj->base); + } + + mutex_unlock(&dev->struct_mutex); + + total = 0; + for (i = 0; i < count; i++) + total += exec[i].relocation_count; + + reloc_offset = drm_malloc_ab(count, sizeof(*reloc_offset)); + reloc = drm_malloc_ab(total, sizeof(*reloc)); + if (reloc == NULL || reloc_offset == NULL) { + drm_free_large(reloc); + drm_free_large(reloc_offset); + mutex_lock(&dev->struct_mutex); + return -ENOMEM; + } + + total = 0; + for (i = 0; i < count; i++) { + struct drm_i915_gem_relocation_entry __user *user_relocs; + u64 invalid_offset = (u64)-1; + int j; + + user_relocs = to_user_ptr(exec[i].relocs_ptr); + + if (copy_from_user(reloc+total, user_relocs, + exec[i].relocation_count * sizeof(*reloc))) { + ret = -EFAULT; + mutex_lock(&dev->struct_mutex); + goto err; + } + + /* As we do not update the known relocation offsets after + * relocating (due to the complexities in lock handling), + * we need to mark them as invalid now so that we force the + * relocation processing next time. Just in case the target + * object is evicted and then rebound into its old + * presumed_offset before the next execbuffer - if that + * happened we would make the mistake of assuming that the + * relocations were valid. + */ + for (j = 0; j < exec[i].relocation_count; j++) { + if (copy_to_user(&user_relocs[j].presumed_offset, + &invalid_offset, + sizeof(invalid_offset))) { + ret = -EFAULT; + mutex_lock(&dev->struct_mutex); + goto err; + } + } + + reloc_offset[i] = total; + total += exec[i].relocation_count; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + mutex_lock(&dev->struct_mutex); + goto err; + } + + /* reacquire the objects */ + eb_reset(eb); + ret = eb_lookup_vmas(eb, exec, args, vm, file); + if (ret) + goto err; + + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, &need_relocs); + if (ret) + goto err; + + list_for_each_entry(vma, &eb->vmas, exec_list) { + int offset = vma->exec_entry - exec; + ret = i915_gem_execbuffer_relocate_vma_slow(vma, eb, + reloc + reloc_offset[offset]); + if (ret) + goto err; + } + + /* Leave the user relocations as are, this is the painfully slow path, + * and we want to avoid the complication of dropping the lock whilst + * having buffers reserved in the aperture and so causing spurious + * ENOSPC for random operations. + */ + +err: + drm_free_large(reloc); + drm_free_large(reloc_offset); + return ret; +} + +static int +i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, + struct list_head *vmas) +{ + struct i915_vma *vma; + uint32_t flush_domains = 0; + bool flush_chipset = false; + int ret; + + list_for_each_entry(vma, vmas, exec_list) { + struct drm_i915_gem_object *obj = vma->obj; + ret = i915_gem_object_sync(obj, ring); + if (ret) + return ret; + + if (obj->base.write_domain & I915_GEM_DOMAIN_CPU) + flush_chipset |= i915_gem_clflush_object(obj, false); + + flush_domains |= obj->base.write_domain; + } + + if (flush_chipset) + i915_gem_chipset_flush(ring->dev); + + if (flush_domains & I915_GEM_DOMAIN_GTT) + wmb(); + + /* Unconditionally invalidate gpu caches and ensure that we do flush + * any residual writes from the previous batch. + */ + return intel_ring_invalidate_all_caches(ring); +} + +static bool +i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) +{ + if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS) + return false; + + return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0; +} + +static int +validate_exec_list(struct drm_i915_gem_exec_object2 *exec, + int count) +{ + int i; + unsigned relocs_total = 0; + unsigned relocs_max = UINT_MAX / sizeof(struct drm_i915_gem_relocation_entry); + + for (i = 0; i < count; i++) { + char __user *ptr = to_user_ptr(exec[i].relocs_ptr); + int length; /* limited by fault_in_pages_readable() */ + + if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) + return -EINVAL; + + /* First check for malicious input causing overflow in + * the worst case where we need to allocate the entire + * relocation tree as a single array. + */ + if (exec[i].relocation_count > relocs_max - relocs_total) + return -EINVAL; + relocs_total += exec[i].relocation_count; + + length = exec[i].relocation_count * + sizeof(struct drm_i915_gem_relocation_entry); + /* + * We must check that the entire relocation array is safe + * to read, but since we may need to update the presumed + * offsets during execution, check for full write access. + */ + if (!access_ok(VERIFY_WRITE, ptr, length)) + return -EFAULT; + + if (likely(!i915_prefault_disable)) { + if (fault_in_multipages_readable(ptr, length)) + return -EFAULT; + } + } + + return 0; +} + +static int +i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, + const u32 ctx_id) +{ + struct i915_ctx_hang_stats *hs; + + hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); + if (IS_ERR(hs)) + return PTR_ERR(hs); + + if (hs->banned) { + DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id); + return -EIO; + } + + return 0; +} + +static void +i915_gem_execbuffer_move_to_active(struct list_head *vmas, + struct intel_ring_buffer *ring) +{ + struct i915_vma *vma; + + list_for_each_entry(vma, vmas, exec_list) { + struct drm_i915_gem_object *obj = vma->obj; + u32 old_read = obj->base.read_domains; + u32 old_write = obj->base.write_domain; + + obj->base.write_domain = obj->base.pending_write_domain; + if (obj->base.write_domain == 0) + obj->base.pending_read_domains |= obj->base.read_domains; + obj->base.read_domains = obj->base.pending_read_domains; + obj->fenced_gpu_access = obj->pending_fenced_gpu_access; + + i915_vma_move_to_active(vma, ring); + if (obj->base.write_domain) { + obj->dirty = 1; + obj->last_write_seqno = intel_ring_get_seqno(ring); + if (obj->pin_count) /* check for potential scanout */ + intel_mark_fb_busy(obj, ring); + } + + trace_i915_gem_object_change_domain(obj, old_read, old_write); + } +} + +static void +i915_gem_execbuffer_retire_commands(struct drm_device *dev, + struct drm_file *file, + struct intel_ring_buffer *ring, + struct drm_i915_gem_object *obj) +{ + /* Unconditionally force add_request to emit a full flush. */ + ring->gpu_caches_dirty = true; + + /* Add a breadcrumb for the completion of the batch buffer */ + (void)__i915_add_request(ring, file, obj, NULL); +} + +static int +i915_reset_gen7_sol_offsets(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret, i; + + if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS]) + return 0; + + ret = intel_ring_begin(ring, 4 * 3); + if (ret) + return ret; + + for (i = 0; i < 4; i++) { + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, GEN7_SO_WRITE_OFFSET(i)); + intel_ring_emit(ring, 0); + } + + intel_ring_advance(ring); + + return 0; +} + +static int +i915_gem_do_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file, + struct drm_i915_gem_execbuffer2 *args, + struct drm_i915_gem_exec_object2 *exec, + struct i915_address_space *vm) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct eb_vmas *eb; + struct drm_i915_gem_object *batch_obj; + struct drm_clip_rect *cliprects = NULL; + struct intel_ring_buffer *ring; + const u32 ctx_id = i915_execbuffer2_get_context_id(*args); + u32 exec_start, exec_len; + u32 mask, flags; + int ret, mode, i; + bool need_relocs; + + if (!i915_gem_check_execbuffer(args)) + return -EINVAL; + + ret = validate_exec_list(exec, args->buffer_count); + if (ret) + return ret; + + flags = 0; + if (args->flags & I915_EXEC_SECURE) { + if (!file->is_master || !capable(CAP_SYS_ADMIN)) + return -EPERM; + + flags |= I915_DISPATCH_SECURE; + } + if (args->flags & I915_EXEC_IS_PINNED) + flags |= I915_DISPATCH_PINNED; + + switch (args->flags & I915_EXEC_RING_MASK) { + case I915_EXEC_DEFAULT: + case I915_EXEC_RENDER: + ring = &dev_priv->ring[RCS]; + break; + case I915_EXEC_BSD: + ring = &dev_priv->ring[VCS]; + if (ctx_id != DEFAULT_CONTEXT_ID) { + DRM_DEBUG("Ring %s doesn't support contexts\n", + ring->name); + return -EPERM; + } + break; + case I915_EXEC_BLT: + ring = &dev_priv->ring[BCS]; + if (ctx_id != DEFAULT_CONTEXT_ID) { + DRM_DEBUG("Ring %s doesn't support contexts\n", + ring->name); + return -EPERM; + } + break; + case I915_EXEC_VEBOX: + ring = &dev_priv->ring[VECS]; + if (ctx_id != DEFAULT_CONTEXT_ID) { + DRM_DEBUG("Ring %s doesn't support contexts\n", + ring->name); + return -EPERM; + } + break; + + default: + DRM_DEBUG("execbuf with unknown ring: %d\n", + (int)(args->flags & I915_EXEC_RING_MASK)); + return -EINVAL; + } + if (!intel_ring_initialized(ring)) { + DRM_DEBUG("execbuf with invalid ring: %d\n", + (int)(args->flags & I915_EXEC_RING_MASK)); + return -EINVAL; + } + + mode = args->flags & I915_EXEC_CONSTANTS_MASK; + mask = I915_EXEC_CONSTANTS_MASK; + switch (mode) { + case I915_EXEC_CONSTANTS_REL_GENERAL: + case I915_EXEC_CONSTANTS_ABSOLUTE: + case I915_EXEC_CONSTANTS_REL_SURFACE: + if (ring == &dev_priv->ring[RCS] && + mode != dev_priv->relative_constants_mode) { + if (INTEL_INFO(dev)->gen < 4) + return -EINVAL; + + if (INTEL_INFO(dev)->gen > 5 && + mode == I915_EXEC_CONSTANTS_REL_SURFACE) + return -EINVAL; + + /* The HW changed the meaning on this bit on gen6 */ + if (INTEL_INFO(dev)->gen >= 6) + mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE; + } + break; + default: + DRM_DEBUG("execbuf with unknown constants: %d\n", mode); + return -EINVAL; + } + + if (args->buffer_count < 1) { + DRM_DEBUG("execbuf with %d buffers\n", args->buffer_count); + return -EINVAL; + } + + if (args->num_cliprects != 0) { + if (ring != &dev_priv->ring[RCS]) { + DRM_DEBUG("clip rectangles are only valid with the render ring\n"); + return -EINVAL; + } + + if (INTEL_INFO(dev)->gen >= 5) { + DRM_DEBUG("clip rectangles are only valid on pre-gen5\n"); + return -EINVAL; + } + + if (args->num_cliprects > UINT_MAX / sizeof(*cliprects)) { + DRM_DEBUG("execbuf with %u cliprects\n", + args->num_cliprects); + return -EINVAL; + } + + cliprects = kcalloc(args->num_cliprects, + sizeof(*cliprects), + GFP_KERNEL); + if (cliprects == NULL) { + ret = -ENOMEM; + goto pre_mutex_err; + } + + if (copy_from_user(cliprects, + to_user_ptr(args->cliprects_ptr), + sizeof(*cliprects)*args->num_cliprects)) { + ret = -EFAULT; + goto pre_mutex_err; + } + } + + intel_runtime_pm_get(dev_priv); + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto pre_mutex_err; + + if (dev_priv->ums.mm_suspended) { + mutex_unlock(&dev->struct_mutex); + ret = -EBUSY; + goto pre_mutex_err; + } + + ret = i915_gem_validate_context(dev, file, ctx_id); + if (ret) { + mutex_unlock(&dev->struct_mutex); + goto pre_mutex_err; + } + + eb = eb_create(args); + if (eb == NULL) { + mutex_unlock(&dev->struct_mutex); + ret = -ENOMEM; + goto pre_mutex_err; + } + + /* Look up object handles */ + ret = eb_lookup_vmas(eb, exec, args, vm, file); + if (ret) + goto err; + + /* take note of the batch buffer before we might reorder the lists */ + batch_obj = list_entry(eb->vmas.prev, struct i915_vma, exec_list)->obj; + + /* Move the objects en-masse into the GTT, evicting if necessary. */ + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, &need_relocs); + if (ret) + goto err; + + /* The objects are in their final locations, apply the relocations. */ + if (need_relocs) + ret = i915_gem_execbuffer_relocate(eb); + if (ret) { + if (ret == -EFAULT) { + ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, + eb, exec); + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + } + if (ret) + goto err; + } + + /* Set the pending read domains for the batch buffer to COMMAND */ + if (batch_obj->base.pending_write_domain) { + DRM_DEBUG("Attempting to use self-modifying batch buffer\n"); + ret = -EINVAL; + goto err; + } + batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + + /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure + * batch" bit. Hence we need to pin secure batches into the global gtt. + * hsw should have this fixed, but bdw mucks it up again. */ + if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level); + + ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->vmas); + if (ret) + goto err; + + ret = i915_switch_context(ring, file, ctx_id); + if (ret) + goto err; + + if (ring == &dev_priv->ring[RCS] && + mode != dev_priv->relative_constants_mode) { + ret = intel_ring_begin(ring, 4); + if (ret) + goto err; + + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, INSTPM); + intel_ring_emit(ring, mask << 16 | mode); + intel_ring_advance(ring); + + dev_priv->relative_constants_mode = mode; + } + + if (args->flags & I915_EXEC_GEN7_SOL_RESET) { + ret = i915_reset_gen7_sol_offsets(dev, ring); + if (ret) + goto err; + } + + exec_start = i915_gem_obj_offset(batch_obj, vm) + + args->batch_start_offset; + exec_len = args->batch_len; + if (cliprects) { + for (i = 0; i < args->num_cliprects; i++) { + ret = i915_emit_box(dev, &cliprects[i], + args->DR1, args->DR4); + if (ret) + goto err; + + ret = ring->dispatch_execbuffer(ring, + exec_start, exec_len, + flags); + if (ret) + goto err; + } + } else { + ret = ring->dispatch_execbuffer(ring, + exec_start, exec_len, + flags); + if (ret) + goto err; + } + + trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); + + i915_gem_execbuffer_move_to_active(&eb->vmas, ring); + i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); + +err: + eb_destroy(eb); + + mutex_unlock(&dev->struct_mutex); + +pre_mutex_err: + kfree(cliprects); + + /* intel_gpu_busy should also get a ref, so it will free when the device + * is really idle. */ + intel_runtime_pm_put(dev_priv); + return ret; +} + +/* + * Legacy execbuffer just creates an exec2 list from the original exec object + * list array and passes it to the real function. + */ +int +i915_gem_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_execbuffer *args = data; + struct drm_i915_gem_execbuffer2 exec2; + struct drm_i915_gem_exec_object *exec_list = NULL; + struct drm_i915_gem_exec_object2 *exec2_list = NULL; + int ret, i; + + if (args->buffer_count < 1) { + DRM_DEBUG("execbuf with %d buffers\n", args->buffer_count); + return -EINVAL; + } + + /* Copy in the exec list from userland */ + exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count); + exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); + if (exec_list == NULL || exec2_list == NULL) { + DRM_DEBUG("Failed to allocate exec list for %d buffers\n", + args->buffer_count); + drm_free_large(exec_list); + drm_free_large(exec2_list); + return -ENOMEM; + } + ret = copy_from_user(exec_list, + to_user_ptr(args->buffers_ptr), + sizeof(*exec_list) * args->buffer_count); + if (ret != 0) { + DRM_DEBUG("copy %d exec entries failed %d\n", + args->buffer_count, ret); + drm_free_large(exec_list); + drm_free_large(exec2_list); + return -EFAULT; + } + + for (i = 0; i < args->buffer_count; i++) { + exec2_list[i].handle = exec_list[i].handle; + exec2_list[i].relocation_count = exec_list[i].relocation_count; + exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr; + exec2_list[i].alignment = exec_list[i].alignment; + exec2_list[i].offset = exec_list[i].offset; + if (INTEL_INFO(dev)->gen < 4) + exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE; + else + exec2_list[i].flags = 0; + } + + exec2.buffers_ptr = args->buffers_ptr; + exec2.buffer_count = args->buffer_count; + exec2.batch_start_offset = args->batch_start_offset; + exec2.batch_len = args->batch_len; + exec2.DR1 = args->DR1; + exec2.DR4 = args->DR4; + exec2.num_cliprects = args->num_cliprects; + exec2.cliprects_ptr = args->cliprects_ptr; + exec2.flags = I915_EXEC_RENDER; + i915_execbuffer2_set_context_id(exec2, 0); + + ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list, + &dev_priv->gtt.base); + if (!ret) { + /* Copy the new buffer offsets back to the user's exec list. */ + for (i = 0; i < args->buffer_count; i++) + exec_list[i].offset = exec2_list[i].offset; + /* ... and back out to userspace */ + ret = copy_to_user(to_user_ptr(args->buffers_ptr), + exec_list, + sizeof(*exec_list) * args->buffer_count); + if (ret) { + ret = -EFAULT; + DRM_DEBUG("failed to copy %d exec entries " + "back to user (%d)\n", + args->buffer_count, ret); + } + } + + drm_free_large(exec_list); + drm_free_large(exec2_list); + return ret; +} + +int +i915_gem_execbuffer2(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_execbuffer2 *args = data; + struct drm_i915_gem_exec_object2 *exec2_list = NULL; + int ret; + + if (args->buffer_count < 1 || + args->buffer_count > UINT_MAX / sizeof(*exec2_list)) { + DRM_DEBUG("execbuf2 with %d buffers\n", args->buffer_count); + return -EINVAL; + } + + exec2_list = kmalloc(sizeof(*exec2_list)*args->buffer_count, + GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); + if (exec2_list == NULL) + exec2_list = drm_malloc_ab(sizeof(*exec2_list), + args->buffer_count); + if (exec2_list == NULL) { + DRM_DEBUG("Failed to allocate exec list for %d buffers\n", + args->buffer_count); + return -ENOMEM; + } + ret = copy_from_user(exec2_list, + to_user_ptr(args->buffers_ptr), + sizeof(*exec2_list) * args->buffer_count); + if (ret != 0) { + DRM_DEBUG("copy %d exec entries failed %d\n", + args->buffer_count, ret); + drm_free_large(exec2_list); + return -EFAULT; + } + + ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list, + &dev_priv->gtt.base); + if (!ret) { + /* Copy the new buffer offsets back to the user's exec list. */ + ret = copy_to_user(to_user_ptr(args->buffers_ptr), + exec2_list, + sizeof(*exec2_list) * args->buffer_count); + if (ret) { + ret = -EFAULT; + DRM_DEBUG("failed to copy %d exec entries " + "back to user (%d)\n", + args->buffer_count, ret); + } + } + + drm_free_large(exec2_list); + return ret; +} --- linux-3.13.0.orig/ubuntu/i915/intel_display.c +++ linux-3.13.0/ubuntu/i915/intel_display.c @@ -0,0 +1,11604 @@ +/* + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intel_drv.h" +#include +#include "i915_drv.h" +#include "i915_trace.h" +#include +#include +#include + +static void intel_increase_pllclock(struct drm_crtc *crtc); +static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); + +static void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config); +static void ironlake_pch_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config); + +static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *old_fb); + + +typedef struct { + int min, max; +} intel_range_t; + +typedef struct { + int dot_limit; + int p2_slow, p2_fast; +} intel_p2_t; + +typedef struct intel_limit intel_limit_t; +struct intel_limit { + intel_range_t dot, vco, n, m, m1, m2, p, p1; + intel_p2_t p2; +}; + +int +intel_pch_rawclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_PCH_SPLIT(dev)); + + return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK; +} + +static inline u32 /* units of 100MHz */ +intel_fdi_link_freq(struct drm_device *dev) +{ + if (IS_GEN5(dev)) { + struct drm_i915_private *dev_priv = dev->dev_private; + return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2; + } else + return 27; +} + +static const intel_limit_t intel_limits_i8xx_dac = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, + .m = { .min = 96, .max = 140 }, + .m1 = { .min = 18, .max = 26 }, + .m2 = { .min = 6, .max = 16 }, + .p = { .min = 4, .max = 128 }, + .p1 = { .min = 2, .max = 33 }, + .p2 = { .dot_limit = 165000, + .p2_slow = 4, .p2_fast = 2 }, +}; + +static const intel_limit_t intel_limits_i8xx_dvo = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, + .m = { .min = 96, .max = 140 }, + .m1 = { .min = 18, .max = 26 }, + .m2 = { .min = 6, .max = 16 }, + .p = { .min = 4, .max = 128 }, + .p1 = { .min = 2, .max = 33 }, + .p2 = { .dot_limit = 165000, + .p2_slow = 4, .p2_fast = 4 }, +}; + +static const intel_limit_t intel_limits_i8xx_lvds = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, + .m = { .min = 96, .max = 140 }, + .m1 = { .min = 18, .max = 26 }, + .m2 = { .min = 6, .max = 16 }, + .p = { .min = 4, .max = 128 }, + .p1 = { .min = 1, .max = 6 }, + .p2 = { .dot_limit = 165000, + .p2_slow = 14, .p2_fast = 7 }, +}; + +static const intel_limit_t intel_limits_i9xx_sdvo = { + .dot = { .min = 20000, .max = 400000 }, + .vco = { .min = 1400000, .max = 2800000 }, + .n = { .min = 1, .max = 6 }, + .m = { .min = 70, .max = 120 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 200000, + .p2_slow = 10, .p2_fast = 5 }, +}; + +static const intel_limit_t intel_limits_i9xx_lvds = { + .dot = { .min = 20000, .max = 400000 }, + .vco = { .min = 1400000, .max = 2800000 }, + .n = { .min = 1, .max = 6 }, + .m = { .min = 70, .max = 120 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, + .p = { .min = 7, .max = 98 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 112000, + .p2_slow = 14, .p2_fast = 7 }, +}; + + +static const intel_limit_t intel_limits_g4x_sdvo = { + .dot = { .min = 25000, .max = 270000 }, + .vco = { .min = 1750000, .max = 3500000}, + .n = { .min = 1, .max = 4 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 17, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 10, .max = 30 }, + .p1 = { .min = 1, .max = 3}, + .p2 = { .dot_limit = 270000, + .p2_slow = 10, + .p2_fast = 10 + }, +}; + +static const intel_limit_t intel_limits_g4x_hdmi = { + .dot = { .min = 22000, .max = 400000 }, + .vco = { .min = 1750000, .max = 3500000}, + .n = { .min = 1, .max = 4 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 16, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8}, + .p2 = { .dot_limit = 165000, + .p2_slow = 10, .p2_fast = 5 }, +}; + +static const intel_limit_t intel_limits_g4x_single_channel_lvds = { + .dot = { .min = 20000, .max = 115000 }, + .vco = { .min = 1750000, .max = 3500000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 17, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 28, .max = 112 }, + .p1 = { .min = 2, .max = 8 }, + .p2 = { .dot_limit = 0, + .p2_slow = 14, .p2_fast = 14 + }, +}; + +static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { + .dot = { .min = 80000, .max = 224000 }, + .vco = { .min = 1750000, .max = 3500000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 17, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 14, .max = 42 }, + .p1 = { .min = 2, .max = 6 }, + .p2 = { .dot_limit = 0, + .p2_slow = 7, .p2_fast = 7 + }, +}; + +static const intel_limit_t intel_limits_pineview_sdvo = { + .dot = { .min = 20000, .max = 400000}, + .vco = { .min = 1700000, .max = 3500000 }, + /* Pineview's Ncounter is a ring counter */ + .n = { .min = 3, .max = 6 }, + .m = { .min = 2, .max = 256 }, + /* Pineview only has one combined m divider, which we treat as m2. */ + .m1 = { .min = 0, .max = 0 }, + .m2 = { .min = 0, .max = 254 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 200000, + .p2_slow = 10, .p2_fast = 5 }, +}; + +static const intel_limit_t intel_limits_pineview_lvds = { + .dot = { .min = 20000, .max = 400000 }, + .vco = { .min = 1700000, .max = 3500000 }, + .n = { .min = 3, .max = 6 }, + .m = { .min = 2, .max = 256 }, + .m1 = { .min = 0, .max = 0 }, + .m2 = { .min = 0, .max = 254 }, + .p = { .min = 7, .max = 112 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 112000, + .p2_slow = 14, .p2_fast = 14 }, +}; + +/* Ironlake / Sandybridge + * + * We calculate clock using (register_value + 2) for N/M1/M2, so here + * the range value for them is (actual_value - 2). + */ +static const intel_limit_t intel_limits_ironlake_dac = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 5 }, + .m = { .min = 79, .max = 127 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 10, .p2_fast = 5 }, +}; + +static const intel_limit_t intel_limits_ironlake_single_lvds = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 79, .max = 118 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 28, .max = 112 }, + .p1 = { .min = 2, .max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 14, .p2_fast = 14 }, +}; + +static const intel_limit_t intel_limits_ironlake_dual_lvds = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 79, .max = 127 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 14, .max = 56 }, + .p1 = { .min = 2, .max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 7, .p2_fast = 7 }, +}; + +/* LVDS 100mhz refclk limits. */ +static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 2 }, + .m = { .min = 79, .max = 126 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 28, .max = 112 }, + .p1 = { .min = 2, .max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 14, .p2_fast = 14 }, +}; + +static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 79, .max = 126 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 14, .max = 42 }, + .p1 = { .min = 2, .max = 6 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 7, .p2_fast = 7 }, +}; + +static const intel_limit_t intel_limits_vlv = { + /* + * These are the data rate limits (measured in fast clocks) + * since those are the strictest limits we have. The fast + * clock and actual rate limits are more relaxed, so checking + * them would make no difference. + */ + .dot = { .min = 25000 * 5, .max = 270000 * 5 }, + .vco = { .min = 4000000, .max = 6000000 }, + .n = { .min = 1, .max = 7 }, + .m1 = { .min = 2, .max = 3 }, + .m2 = { .min = 11, .max = 156 }, + .p1 = { .min = 2, .max = 3 }, + .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ +}; + +static void vlv_clock(int refclk, intel_clock_t *clock) +{ + clock->m = clock->m1 * clock->m2; + clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); +} + +/** + * Returns whether any output on the specified pipe is of the specified type + */ +static bool intel_pipe_has_type(struct drm_crtc *crtc, int type) +{ + struct drm_device *dev = crtc->dev; + struct intel_encoder *encoder; + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->type == type) + return true; + + return false; +} + +static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, + int refclk) +{ + struct drm_device *dev = crtc->dev; + const intel_limit_t *limit; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_is_dual_link_lvds(dev)) { + if (refclk == 100000) + limit = &intel_limits_ironlake_dual_lvds_100m; + else + limit = &intel_limits_ironlake_dual_lvds; + } else { + if (refclk == 100000) + limit = &intel_limits_ironlake_single_lvds_100m; + else + limit = &intel_limits_ironlake_single_lvds; + } + } else + limit = &intel_limits_ironlake_dac; + + return limit; +} + +static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + const intel_limit_t *limit; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_is_dual_link_lvds(dev)) + limit = &intel_limits_g4x_dual_channel_lvds; + else + limit = &intel_limits_g4x_single_channel_lvds; + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { + limit = &intel_limits_g4x_hdmi; + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { + limit = &intel_limits_g4x_sdvo; + } else /* The option is for other outputs */ + limit = &intel_limits_i9xx_sdvo; + + return limit; +} + +static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk) +{ + struct drm_device *dev = crtc->dev; + const intel_limit_t *limit; + + if (HAS_PCH_SPLIT(dev)) + limit = intel_ironlake_limit(crtc, refclk); + else if (IS_G4X(dev)) { + limit = intel_g4x_limit(crtc); + } else if (IS_PINEVIEW(dev)) { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits_pineview_lvds; + else + limit = &intel_limits_pineview_sdvo; + } else if (IS_VALLEYVIEW(dev)) { + limit = &intel_limits_vlv; + } else if (!IS_GEN2(dev)) { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits_i9xx_lvds; + else + limit = &intel_limits_i9xx_sdvo; + } else { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits_i8xx_lvds; + else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO)) + limit = &intel_limits_i8xx_dvo; + else + limit = &intel_limits_i8xx_dac; + } + return limit; +} + +/* m1 is reserved as 0 in Pineview, n is a ring counter */ +static void pineview_clock(int refclk, intel_clock_t *clock) +{ + clock->m = clock->m2 + 2; + clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); +} + +static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) +{ + return 5 * (dpll->m1 + 2) + (dpll->m2 + 2); +} + +static void i9xx_clock(int refclk, intel_clock_t *clock) +{ + clock->m = i9xx_dpll_compute_m(clock); + clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) + return; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); +} + +#define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) +/** + * Returns whether the given set of divisors are valid for a given refclk with + * the given connectors. + */ + +static bool intel_PLL_is_valid(struct drm_device *dev, + const intel_limit_t *limit, + const intel_clock_t *clock) +{ + if (clock->n < limit->n.min || limit->n.max < clock->n) + INTELPllInvalid("n out of range\n"); + if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) + INTELPllInvalid("p1 out of range\n"); + if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) + INTELPllInvalid("m2 out of range\n"); + if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) + INTELPllInvalid("m1 out of range\n"); + + if (!IS_PINEVIEW(dev) && !IS_VALLEYVIEW(dev)) + if (clock->m1 <= clock->m2) + INTELPllInvalid("m1 <= m2\n"); + + if (!IS_VALLEYVIEW(dev)) { + if (clock->p < limit->p.min || limit->p.max < clock->p) + INTELPllInvalid("p out of range\n"); + if (clock->m < limit->m.min || limit->m.max < clock->m) + INTELPllInvalid("m out of range\n"); + } + + if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) + INTELPllInvalid("vco out of range\n"); + /* XXX: We may need to be checking "Dot clock" depending on the multiplier, + * connector, etc., rather than just a single range. + */ + if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) + INTELPllInvalid("dot out of range\n"); + + return true; +} + +static bool +i9xx_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + intel_clock_t clock; + int err = target; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + /* + * For LVDS just rely on its current settings for dual-channel. + * We haven't figured out how to reliably set up different + * single/dual channel state, if we even can. + */ + if (intel_is_dual_link_lvds(dev)) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset(best_clock, 0, sizeof(*best_clock)); + + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; + clock.m1++) { + for (clock.m2 = limit->m2.min; + clock.m2 <= limit->m2.max; clock.m2++) { + if (clock.m2 >= clock.m1) + break; + for (clock.n = limit->n.min; + clock.n <= limit->n.max; clock.n++) { + for (clock.p1 = limit->p1.min; + clock.p1 <= limit->p1.max; clock.p1++) { + int this_err; + + i9xx_clock(refclk, &clock); + if (!intel_PLL_is_valid(dev, limit, + &clock)) + continue; + if (match_clock && + clock.p != match_clock->p) + continue; + + this_err = abs(clock.dot - target); + if (this_err < err) { + *best_clock = clock; + err = this_err; + } + } + } + } + } + + return (err != target); +} + +static bool +pnv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + intel_clock_t clock; + int err = target; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + /* + * For LVDS just rely on its current settings for dual-channel. + * We haven't figured out how to reliably set up different + * single/dual channel state, if we even can. + */ + if (intel_is_dual_link_lvds(dev)) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset(best_clock, 0, sizeof(*best_clock)); + + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; + clock.m1++) { + for (clock.m2 = limit->m2.min; + clock.m2 <= limit->m2.max; clock.m2++) { + for (clock.n = limit->n.min; + clock.n <= limit->n.max; clock.n++) { + for (clock.p1 = limit->p1.min; + clock.p1 <= limit->p1.max; clock.p1++) { + int this_err; + + pineview_clock(refclk, &clock); + if (!intel_PLL_is_valid(dev, limit, + &clock)) + continue; + if (match_clock && + clock.p != match_clock->p) + continue; + + this_err = abs(clock.dot - target); + if (this_err < err) { + *best_clock = clock; + err = this_err; + } + } + } + } + } + + return (err != target); +} + +static bool +g4x_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + intel_clock_t clock; + int max_n; + bool found; + /* approximately equals target * 0.00585 */ + int err_most = (target >> 8) + (target >> 9); + found = false; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_is_dual_link_lvds(dev)) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset(best_clock, 0, sizeof(*best_clock)); + max_n = limit->n.max; + /* based on hardware requirement, prefer smaller n to precision */ + for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { + /* based on hardware requirement, prefere larger m1,m2 */ + for (clock.m1 = limit->m1.max; + clock.m1 >= limit->m1.min; clock.m1--) { + for (clock.m2 = limit->m2.max; + clock.m2 >= limit->m2.min; clock.m2--) { + for (clock.p1 = limit->p1.max; + clock.p1 >= limit->p1.min; clock.p1--) { + int this_err; + + i9xx_clock(refclk, &clock); + if (!intel_PLL_is_valid(dev, limit, + &clock)) + continue; + + this_err = abs(clock.dot - target); + if (this_err < err_most) { + *best_clock = clock; + err_most = this_err; + max_n = clock.n; + found = true; + } + } + } + } + } + return found; +} + +static bool +vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + intel_clock_t clock; + unsigned int bestppm = 1000000; + /* min update 19.2 MHz */ + int max_n = min(limit->n.max, refclk / 19200); + bool found = false; + + target *= 5; /* fast clock */ + + memset(best_clock, 0, sizeof(*best_clock)); + + /* based on hardware requirement, prefer smaller n to precision */ + for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { + for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { + for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow; + clock.p2 -= clock.p2 > 10 ? 2 : 1) { + clock.p = clock.p1 * clock.p2; + /* based on hardware requirement, prefer bigger m1,m2 values */ + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { + unsigned int ppm, diff; + + clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n, + refclk * clock.m1); + + vlv_clock(refclk, &clock); + + if (!intel_PLL_is_valid(dev, limit, + &clock)) + continue; + + diff = abs(clock.dot - target); + ppm = div_u64(1000000ULL * diff, target); + + if (ppm < 100 && clock.p > best_clock->p) { + bestppm = 0; + *best_clock = clock; + found = true; + } + + if (bestppm >= 10 && ppm < bestppm - 10) { + bestppm = ppm; + *best_clock = clock; + found = true; + } + } + } + } + } + + return found; +} + +bool intel_crtc_active(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* Be paranoid as we can arrive here with only partial + * state retrieved from the hardware during setup. + * + * We can ditch the adjusted_mode.crtc_clock check as soon + * as Haswell has gained clock readout/fastboot support. + * + * We can ditch the crtc->fb check as soon as we can + * properly reconstruct framebuffers. + */ + return intel_crtc->active && crtc->fb && + intel_crtc->config.adjusted_mode.crtc_clock; +} + +enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + return intel_crtc->config.cpu_transcoder; +} + +static void g4x_wait_for_vblank(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 frame, frame_reg = PIPE_FRMCOUNT_GM45(pipe); + + frame = I915_READ(frame_reg); + + if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50)) + DRM_DEBUG_KMS("vblank wait timed out\n"); +} + +/** + * intel_wait_for_vblank - wait for vblank on a given pipe + * @dev: drm device + * @pipe: pipe to wait for + * + * Wait for vblank to occur on a given pipe. Needed for various bits of + * mode setting code. + */ +void intel_wait_for_vblank(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipestat_reg = PIPESTAT(pipe); + + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + g4x_wait_for_vblank(dev, pipe); + return; + } + + /* Clear existing vblank status. Note this will clear any other + * sticky status fields as well. + * + * This races with i915_driver_irq_handler() with the result + * that either function could miss a vblank event. Here it is not + * fatal, as we will either wait upon the next vblank interrupt or + * timeout. Generally speaking intel_wait_for_vblank() is only + * called during modeset at which time the GPU should be idle and + * should *not* be performing page flips and thus not waiting on + * vblanks... + * Currently, the result of us stealing a vblank from the irq + * handler is that a single frame will be skipped during swapbuffers. + */ + I915_WRITE(pipestat_reg, + I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS); + + /* Wait for vblank interrupt bit to set */ + if (wait_for(I915_READ(pipestat_reg) & + PIPE_VBLANK_INTERRUPT_STATUS, + 50)) + DRM_DEBUG_KMS("vblank wait timed out\n"); +} + +static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg = PIPEDSL(pipe); + u32 line1, line2; + u32 line_mask; + + if (IS_GEN2(dev)) + line_mask = DSL_LINEMASK_GEN2; + else + line_mask = DSL_LINEMASK_GEN3; + + line1 = I915_READ(reg) & line_mask; + mdelay(5); + line2 = I915_READ(reg) & line_mask; + + return line1 == line2; +} + +/* + * intel_wait_for_pipe_off - wait for pipe to turn off + * @dev: drm device + * @pipe: pipe to wait for + * + * After disabling a pipe, we can't wait for vblank in the usual way, + * spinning on the vblank interrupt status bit, since we won't actually + * see an interrupt when the pipe is disabled. + * + * On Gen4 and above: + * wait for the pipe register state bit to turn off + * + * Otherwise: + * wait for the display line value to settle (it usually + * ends up stopping at the start of the next frame). + * + */ +void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + + if (INTEL_INFO(dev)->gen >= 4) { + int reg = PIPECONF(cpu_transcoder); + + /* Wait for the Pipe State to go off */ + if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, + 100)) + WARN(1, "pipe_off wait timed out\n"); + } else { + /* Wait for the display line to settle */ + if (wait_for(pipe_dsl_stopped(dev, pipe), 100)) + WARN(1, "pipe_off wait timed out\n"); + } +} + +/* + * ibx_digital_port_connected - is the specified port connected? + * @dev_priv: i915 private structure + * @port: the port to test + * + * Returns true if @port is connected, false otherwise. + */ +bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, + struct intel_digital_port *port) +{ + u32 bit; + + if (HAS_PCH_IBX(dev_priv->dev)) { + switch(port->port) { + case PORT_B: + bit = SDE_PORTB_HOTPLUG; + break; + case PORT_C: + bit = SDE_PORTC_HOTPLUG; + break; + case PORT_D: + bit = SDE_PORTD_HOTPLUG; + break; + default: + return true; + } + } else { + switch(port->port) { + case PORT_B: + bit = SDE_PORTB_HOTPLUG_CPT; + break; + case PORT_C: + bit = SDE_PORTC_HOTPLUG_CPT; + break; + case PORT_D: + bit = SDE_PORTD_HOTPLUG_CPT; + break; + default: + return true; + } + } + + return I915_READ(SDEISR) & bit; +} + +static const char *state_string(bool enabled) +{ + return enabled ? "on" : "off"; +} + +/* Only for pre-ILK configs */ +void assert_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = DPLL(pipe); + val = I915_READ(reg); + cur_state = !!(val & DPLL_VCO_ENABLE); + WARN(cur_state != state, + "PLL state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} + +/* XXX: the dsi pll is shared between MIPI DSI ports */ +static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state) +{ + u32 val; + bool cur_state; + + mutex_lock(&dev_priv->dpio_lock); + val = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL); + mutex_unlock(&dev_priv->dpio_lock); + + cur_state = val & DSI_PLL_VCO_EN; + WARN(cur_state != state, + "DSI PLL state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true) +#define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false) + +struct intel_shared_dpll * +intel_crtc_to_shared_dpll(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (crtc->config.shared_dpll < 0) + return NULL; + + return &dev_priv->shared_dplls[crtc->config.shared_dpll]; +} + +/* For ILK+ */ +void assert_shared_dpll(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + bool state) +{ + bool cur_state; + struct intel_dpll_hw_state hw_state; + + if (HAS_PCH_LPT(dev_priv->dev)) { + DRM_DEBUG_DRIVER("LPT detected: skipping PCH PLL test\n"); + return; + } + + if (WARN (!pll, + "asserting DPLL %s with no DPLL\n", state_string(state))) + return; + + cur_state = pll->get_hw_state(dev_priv, pll, &hw_state); + WARN(cur_state != state, + "%s assertion failure (expected %s, current %s)\n", + pll->name, state_string(state), state_string(cur_state)); +} + +static void assert_fdi_tx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + + if (HAS_DDI(dev_priv->dev)) { + /* DDI does not have a specific FDI_TX register */ + reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); + val = I915_READ(reg); + cur_state = !!(val & TRANS_DDI_FUNC_ENABLE); + } else { + reg = FDI_TX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_TX_ENABLE); + } + WARN(cur_state != state, + "FDI TX state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true) +#define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false) + +static void assert_fdi_rx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = FDI_RX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_RX_ENABLE); + WARN(cur_state != state, + "FDI RX state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true) +#define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false) + +static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + /* ILK FDI PLL is always enabled */ + if (dev_priv->info->gen == 5) + return; + + /* On Haswell, DDI ports are responsible for the FDI PLL setup */ + if (HAS_DDI(dev_priv->dev)) + return; + + reg = FDI_TX_CTL(pipe); + val = I915_READ(reg); + WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n"); +} + +void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = FDI_RX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_RX_PLL_ENABLE); + WARN(cur_state != state, + "FDI RX PLL assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} + +static void assert_panel_unlocked(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int pp_reg, lvds_reg; + u32 val; + enum pipe panel_pipe = PIPE_A; + bool locked = true; + + if (HAS_PCH_SPLIT(dev_priv->dev)) { + pp_reg = PCH_PP_CONTROL; + lvds_reg = PCH_LVDS; + } else { + pp_reg = PP_CONTROL; + lvds_reg = LVDS; + } + + val = I915_READ(pp_reg); + if (!(val & PANEL_POWER_ON) || + ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)) + locked = false; + + if (I915_READ(lvds_reg) & LVDS_PIPEB_SELECT) + panel_pipe = PIPE_B; + + WARN(panel_pipe == pipe && locked, + "panel assertion failure, pipe %c regs locked\n", + pipe_name(pipe)); +} + +static void assert_cursor(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + struct drm_device *dev = dev_priv->dev; + bool cur_state; + + if (IS_845G(dev) || IS_I865G(dev)) + cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE; + else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) + cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; + else + cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE; + + WARN(cur_state != state, + "cursor on pipe %c assertion failure (expected %s, current %s)\n", + pipe_name(pipe), state_string(state), state_string(cur_state)); +} +#define assert_cursor_enabled(d, p) assert_cursor(d, p, true) +#define assert_cursor_disabled(d, p) assert_cursor(d, p, false) + +void assert_pipe(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + + /* if we need the pipe A quirk it must be always on */ + if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) + state = true; + + if (!intel_display_power_enabled(dev_priv->dev, + POWER_DOMAIN_TRANSCODER(cpu_transcoder))) { + cur_state = false; + } else { + reg = PIPECONF(cpu_transcoder); + val = I915_READ(reg); + cur_state = !!(val & PIPECONF_ENABLE); + } + + WARN(cur_state != state, + "pipe %c assertion failure (expected %s, current %s)\n", + pipe_name(pipe), state_string(state), state_string(cur_state)); +} + +static void assert_plane(struct drm_i915_private *dev_priv, + enum plane plane, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = DSPCNTR(plane); + val = I915_READ(reg); + cur_state = !!(val & DISPLAY_PLANE_ENABLE); + WARN(cur_state != state, + "plane %c assertion failure (expected %s, current %s)\n", + plane_name(plane), state_string(state), state_string(cur_state)); +} + +#define assert_plane_enabled(d, p) assert_plane(d, p, true) +#define assert_plane_disabled(d, p) assert_plane(d, p, false) + +static void assert_planes_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + struct drm_device *dev = dev_priv->dev; + int reg, i; + u32 val; + int cur_pipe; + + /* Primary planes are fixed to pipes on gen4+ */ + if (INTEL_INFO(dev)->gen >= 4) { + reg = DSPCNTR(pipe); + val = I915_READ(reg); + WARN((val & DISPLAY_PLANE_ENABLE), + "plane %c assertion failure, should be disabled but not\n", + plane_name(pipe)); + return; + } + + /* Need to check both planes against the pipe */ + for_each_pipe(i) { + reg = DSPCNTR(i); + val = I915_READ(reg); + cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> + DISPPLANE_SEL_PIPE_SHIFT; + WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe, + "plane %c assertion failure, should be off on pipe %c but is still active\n", + plane_name(i), pipe_name(pipe)); + } +} + +static void assert_sprites_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + struct drm_device *dev = dev_priv->dev; + int reg, i; + u32 val; + + if (IS_VALLEYVIEW(dev)) { + for (i = 0; i < dev_priv->num_plane; i++) { + reg = SPCNTR(pipe, i); + val = I915_READ(reg); + WARN((val & SP_ENABLE), + "sprite %c assertion failure, should be off on pipe %c but is still active\n", + sprite_name(pipe, i), pipe_name(pipe)); + } + } else if (INTEL_INFO(dev)->gen >= 7) { + reg = SPRCTL(pipe); + val = I915_READ(reg); + WARN((val & SPRITE_ENABLE), + "sprite %c assertion failure, should be off on pipe %c but is still active\n", + plane_name(pipe), pipe_name(pipe)); + } else if (INTEL_INFO(dev)->gen >= 5) { + reg = DVSCNTR(pipe); + val = I915_READ(reg); + WARN((val & DVS_ENABLE), + "sprite %c assertion failure, should be off on pipe %c but is still active\n", + plane_name(pipe), pipe_name(pipe)); + } +} + +static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) +{ + u32 val; + bool enabled; + + WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev))); + + val = I915_READ(PCH_DREF_CONTROL); + enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | + DREF_SUPERSPREAD_SOURCE_MASK)); + WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n"); +} + +static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + bool enabled; + + reg = PCH_TRANSCONF(pipe); + val = I915_READ(reg); + enabled = !!(val & TRANS_ENABLE); + WARN(enabled, + "transcoder assertion failed, should be off on pipe %c but is still active\n", + pipe_name(pipe)); +} + +static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, + enum pipe pipe, u32 port_sel, u32 val) +{ + if ((val & DP_PORT_EN) == 0) + return false; + + if (HAS_PCH_CPT(dev_priv->dev)) { + u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe); + u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg); + if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel) + return false; + } else { + if ((val & DP_PIPE_MASK) != (pipe << 30)) + return false; + } + return true; +} + +static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, + enum pipe pipe, u32 val) +{ + if ((val & SDVO_ENABLE) == 0) + return false; + + if (HAS_PCH_CPT(dev_priv->dev)) { + if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe)) + return false; + } else { + if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe)) + return false; + } + return true; +} + +static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv, + enum pipe pipe, u32 val) +{ + if ((val & LVDS_PORT_EN) == 0) + return false; + + if (HAS_PCH_CPT(dev_priv->dev)) { + if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) + return false; + } else { + if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe)) + return false; + } + return true; +} + +static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv, + enum pipe pipe, u32 val) +{ + if ((val & ADPA_DAC_ENABLE) == 0) + return false; + if (HAS_PCH_CPT(dev_priv->dev)) { + if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) + return false; + } else { + if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe)) + return false; + } + return true; +} + +static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe, int reg, u32 port_sel) +{ + u32 val = I915_READ(reg); + WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val), + "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", + reg, pipe_name(pipe)); + + WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0 + && (val & DP_PIPEB_SELECT), + "IBX PCH dp port still using transcoder B\n"); +} + +static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe, int reg) +{ + u32 val = I915_READ(reg); + WARN(hdmi_pipe_enabled(dev_priv, pipe, val), + "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", + reg, pipe_name(pipe)); + + WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 + && (val & SDVO_PIPE_B_SELECT), + "IBX PCH hdmi port still using transcoder B\n"); +} + +static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); + + reg = PCH_ADPA; + val = I915_READ(reg); + WARN(adpa_pipe_enabled(dev_priv, pipe, val), + "PCH VGA enabled on transcoder %c, should be disabled\n", + pipe_name(pipe)); + + reg = PCH_LVDS; + val = I915_READ(reg); + WARN(lvds_pipe_enabled(dev_priv, pipe, val), + "PCH LVDS enabled on transcoder %c, should be disabled\n", + pipe_name(pipe)); + + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); +} + +static void intel_init_dpio(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_VALLEYVIEW(dev)) + return; + + DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; +} + +static void intel_reset_dpio(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_VALLEYVIEW(dev)) + return; + + /* + * Enable the CRI clock source so we can get at the display and the + * reference clock for VGA hotplug / manual detection. + */ + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + DPLL_REFA_CLK_ENABLE_VLV | + DPLL_INTEGRATED_CRI_CLK_VLV); + + /* + * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx - + * 6. De-assert cmn_reset/side_reset. Same as VLV X0. + * a. GUnit 0x2110 bit[0] set to 1 (def 0) + * b. The other bits such as sfr settings / modesel may all be set + * to 0. + * + * This should only be done on init and resume from S3 with both + * PLLs disabled, or we risk losing DPIO and PLL synchronization. + */ + I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) | DPIO_CMNRST); +} + +static void vlv_enable_pll(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int reg = DPLL(crtc->pipe); + u32 dpll = crtc->config.dpll_hw_state.dpll; + + assert_pipe_disabled(dev_priv, crtc->pipe); + + /* No really, not for ILK+ */ + BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); + + /* PLL is protected by panel, make sure we can write it */ + if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev)) + assert_panel_unlocked(dev_priv, crtc->pipe); + + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); + + if (wait_for(((I915_READ(reg) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) + DRM_ERROR("DPLL %d failed to lock\n", crtc->pipe); + + I915_WRITE(DPLL_MD(crtc->pipe), crtc->config.dpll_hw_state.dpll_md); + POSTING_READ(DPLL_MD(crtc->pipe)); + + /* We do this three times for luck */ + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ +} + +static void i9xx_enable_pll(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int reg = DPLL(crtc->pipe); + u32 dpll = crtc->config.dpll_hw_state.dpll; + + assert_pipe_disabled(dev_priv, crtc->pipe); + + /* No really, not for ILK+ */ + BUG_ON(dev_priv->info->gen >= 5); + + /* PLL is protected by panel, make sure we can write it */ + if (IS_MOBILE(dev) && !IS_I830(dev)) + assert_panel_unlocked(dev_priv, crtc->pipe); + + I915_WRITE(reg, dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(reg); + udelay(150); + + if (INTEL_INFO(dev)->gen >= 4) { + I915_WRITE(DPLL_MD(crtc->pipe), + crtc->config.dpll_hw_state.dpll_md); + } else { + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(reg, dpll); + } + + /* We do this three times for luck */ + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ +} + +/** + * i9xx_disable_pll - disable a PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to disable + * + * Disable the PLL for @pipe, making sure the pipe is off first. + * + * Note! This is for pre-ILK only. + */ +static void i9xx_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + /* Don't disable pipe A or pipe A PLLs if needed */ + if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + return; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, pipe); + + I915_WRITE(DPLL(pipe), 0); + POSTING_READ(DPLL(pipe)); +} + +static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + u32 val = 0; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, pipe); + + /* + * Leave integrated clock source and reference clock enabled for pipe B. + * The latter is needed for VGA hotplug / manual detection. + */ + if (pipe == PIPE_B) + val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV; + I915_WRITE(DPLL(pipe), val); + POSTING_READ(DPLL(pipe)); +} + +void vlv_wait_port_ready(struct drm_i915_private *dev_priv, + struct intel_digital_port *dport) +{ + u32 port_mask; + + switch (dport->port) { + case PORT_B: + port_mask = DPLL_PORTB_READY_MASK; + break; + case PORT_C: + port_mask = DPLL_PORTC_READY_MASK; + break; + default: + BUG(); + } + + if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000)) + WARN(1, "timed out waiting for port %c ready: 0x%08x\n", + port_name(dport->port), I915_READ(DPLL(0))); +} + +/** + * ironlake_enable_shared_dpll - enable PCH PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to enable + * + * The PCH PLL needs to be enabled before the PCH transcoder, since it + * drives the transcoder clock. + */ +static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); + + /* PCH PLLs only available on ILK, SNB and IVB */ + BUG_ON(dev_priv->info->gen < 5); + if (WARN_ON(pll == NULL)) + return; + + if (WARN_ON(pll->refcount == 0)) + return; + + DRM_DEBUG_KMS("enable %s (active %d, on? %d)for crtc %d\n", + pll->name, pll->active, pll->on, + crtc->base.base.id); + + if (pll->active++) { + WARN_ON(!pll->on); + assert_shared_dpll_enabled(dev_priv, pll); + return; + } + WARN_ON(pll->on); + + DRM_DEBUG_KMS("enabling %s\n", pll->name); + pll->enable(dev_priv, pll); + pll->on = true; +} + +static void intel_disable_shared_dpll(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); + + /* PCH only available on ILK+ */ + BUG_ON(dev_priv->info->gen < 5); + if (WARN_ON(pll == NULL)) + return; + + if (WARN_ON(pll->refcount == 0)) + return; + + DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n", + pll->name, pll->active, pll->on, + crtc->base.base.id); + + if (WARN_ON(pll->active == 0)) { + assert_shared_dpll_disabled(dev_priv, pll); + return; + } + + assert_shared_dpll_enabled(dev_priv, pll); + WARN_ON(!pll->on); + if (--pll->active) + return; + + DRM_DEBUG_KMS("disabling %s\n", pll->name); + pll->disable(dev_priv, pll); + pll->on = false; +} + +static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t reg, val, pipeconf_val; + + /* PCH only available on ILK+ */ + BUG_ON(dev_priv->info->gen < 5); + + /* Make sure PCH DPLL is enabled */ + assert_shared_dpll_enabled(dev_priv, + intel_crtc_to_shared_dpll(intel_crtc)); + + /* FDI must be feeding us bits for PCH ports */ + assert_fdi_tx_enabled(dev_priv, pipe); + assert_fdi_rx_enabled(dev_priv, pipe); + + if (HAS_PCH_CPT(dev)) { + /* Workaround: Set the timing override bit before enabling the + * pch transcoder. */ + reg = TRANS_CHICKEN2(pipe); + val = I915_READ(reg); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(reg, val); + } + + reg = PCH_TRANSCONF(pipe); + val = I915_READ(reg); + pipeconf_val = I915_READ(PIPECONF(pipe)); + + if (HAS_PCH_IBX(dev_priv->dev)) { + /* + * make the BPC in transcoder be consistent with + * that in pipeconf reg. + */ + val &= ~PIPECONF_BPC_MASK; + val |= pipeconf_val & PIPECONF_BPC_MASK; + } + + val &= ~TRANS_INTERLACE_MASK; + if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK) + if (HAS_PCH_IBX(dev_priv->dev) && + intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) + val |= TRANS_LEGACY_INTERLACED_ILK; + else + val |= TRANS_INTERLACED; + else + val |= TRANS_PROGRESSIVE; + + I915_WRITE(reg, val | TRANS_ENABLE); + if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100)) + DRM_ERROR("failed to enable transcoder %c\n", pipe_name(pipe)); +} + +static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder) +{ + u32 val, pipeconf_val; + + /* PCH only available on ILK+ */ + BUG_ON(dev_priv->info->gen < 5); + + /* FDI must be feeding us bits for PCH ports */ + assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder); + assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); + + /* Workaround: set timing override bit. */ + val = I915_READ(_TRANSA_CHICKEN2); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(_TRANSA_CHICKEN2, val); + + val = TRANS_ENABLE; + pipeconf_val = I915_READ(PIPECONF(cpu_transcoder)); + + if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) == + PIPECONF_INTERLACED_ILK) + val |= TRANS_INTERLACED; + else + val |= TRANS_PROGRESSIVE; + + I915_WRITE(LPT_TRANSCONF, val); + if (wait_for(I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE, 100)) + DRM_ERROR("Failed to enable PCH transcoder\n"); +} + +static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + struct drm_device *dev = dev_priv->dev; + uint32_t reg, val; + + /* FDI relies on the transcoder */ + assert_fdi_tx_disabled(dev_priv, pipe); + assert_fdi_rx_disabled(dev_priv, pipe); + + /* Ports must be off as well */ + assert_pch_ports_disabled(dev_priv, pipe); + + reg = PCH_TRANSCONF(pipe); + val = I915_READ(reg); + val &= ~TRANS_ENABLE; + I915_WRITE(reg, val); + /* wait for PCH transcoder off, transcoder state */ + if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) + DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe)); + + if (!HAS_PCH_IBX(dev)) { + /* Workaround: Clear the timing override chicken bit again. */ + reg = TRANS_CHICKEN2(pipe); + val = I915_READ(reg); + val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(reg, val); + } +} + +static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv) +{ + u32 val; + + val = I915_READ(LPT_TRANSCONF); + val &= ~TRANS_ENABLE; + I915_WRITE(LPT_TRANSCONF, val); + /* wait for PCH transcoder off, transcoder state */ + if (wait_for((I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE) == 0, 50)) + DRM_ERROR("Failed to disable PCH transcoder\n"); + + /* Workaround: clear timing override bit. */ + val = I915_READ(_TRANSA_CHICKEN2); + val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(_TRANSA_CHICKEN2, val); +} + +/** + * intel_enable_pipe - enable a pipe, asserting requirements + * @dev_priv: i915 private structure + * @pipe: pipe to enable + * @pch_port: on ILK+, is this pipe driving a PCH port or not + * + * Enable @pipe, making sure that various hardware specific requirements + * are met, if applicable, e.g. PLL enabled, LVDS pairs enabled, etc. + * + * @pipe should be %PIPE_A or %PIPE_B. + * + * Will wait until the pipe is actually running (i.e. first vblank) before + * returning. + */ +static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, + bool pch_port, bool dsi) +{ + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + enum pipe pch_transcoder; + int reg; + u32 val; + + assert_planes_disabled(dev_priv, pipe); + assert_cursor_disabled(dev_priv, pipe); + assert_sprites_disabled(dev_priv, pipe); + + if (HAS_PCH_LPT(dev_priv->dev)) + pch_transcoder = TRANSCODER_A; + else + pch_transcoder = pipe; + + /* + * A pipe without a PLL won't actually be able to drive bits from + * a plane. On ILK+ the pipe PLLs are integrated, so we don't + * need the check. + */ + if (!HAS_PCH_SPLIT(dev_priv->dev)) + if (dsi) + assert_dsi_pll_enabled(dev_priv); + else + assert_pll_enabled(dev_priv, pipe); + else { + if (pch_port) { + /* if driving the PCH, we need FDI enabled */ + assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder); + assert_fdi_tx_pll_enabled(dev_priv, + (enum pipe) cpu_transcoder); + } + /* FIXME: assert CPU port conditions for SNB+ */ + } + + reg = PIPECONF(cpu_transcoder); + val = I915_READ(reg); + if (val & PIPECONF_ENABLE) + return; + + I915_WRITE(reg, val | PIPECONF_ENABLE); + intel_wait_for_vblank(dev_priv->dev, pipe); +} + +/** + * intel_disable_pipe - disable a pipe, asserting requirements + * @dev_priv: i915 private structure + * @pipe: pipe to disable + * + * Disable @pipe, making sure that various hardware specific requirements + * are met, if applicable, e.g. plane disabled, panel fitter off, etc. + * + * @pipe should be %PIPE_A or %PIPE_B. + * + * Will wait until the pipe has shut down before returning. + */ +static void intel_disable_pipe(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + int reg; + u32 val; + + /* + * Make sure planes won't keep trying to pump pixels to us, + * or we might hang the display. + */ + assert_planes_disabled(dev_priv, pipe); + assert_cursor_disabled(dev_priv, pipe); + assert_sprites_disabled(dev_priv, pipe); + + /* Don't disable pipe A or pipe A PLLs if needed */ + if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + return; + + reg = PIPECONF(cpu_transcoder); + val = I915_READ(reg); + if ((val & PIPECONF_ENABLE) == 0) + return; + + I915_WRITE(reg, val & ~PIPECONF_ENABLE); + intel_wait_for_pipe_off(dev_priv->dev, pipe); +} + +/* + * Plane regs are double buffered, going from enabled->disabled needs a + * trigger in order to latch. The display address reg provides this. + */ +void intel_flush_primary_plane(struct drm_i915_private *dev_priv, + enum plane plane) +{ + u32 reg = dev_priv->info->gen >= 4 ? DSPSURF(plane) : DSPADDR(plane); + + I915_WRITE(reg, I915_READ(reg)); + POSTING_READ(reg); +} + +/** + * intel_enable_primary_plane - enable the primary plane on a given pipe + * @dev_priv: i915 private structure + * @plane: plane to enable + * @pipe: pipe being fed + * + * Enable @plane on @pipe, making sure that @pipe is running first. + */ +static void intel_enable_primary_plane(struct drm_i915_private *dev_priv, + enum plane plane, enum pipe pipe) +{ + struct intel_crtc *intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + int reg; + u32 val; + + /* If the pipe isn't enabled, we can't pump pixels and may hang */ + assert_pipe_enabled(dev_priv, pipe); + + WARN(intel_crtc->primary_enabled, "Primary plane already enabled\n"); + + intel_crtc->primary_enabled = true; + + reg = DSPCNTR(plane); + val = I915_READ(reg); + if (val & DISPLAY_PLANE_ENABLE) + return; + + I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); + intel_flush_primary_plane(dev_priv, plane); + intel_wait_for_vblank(dev_priv->dev, pipe); +} + +/** + * intel_disable_primary_plane - disable the primary plane + * @dev_priv: i915 private structure + * @plane: plane to disable + * @pipe: pipe consuming the data + * + * Disable @plane; should be an independent operation. + */ +static void intel_disable_primary_plane(struct drm_i915_private *dev_priv, + enum plane plane, enum pipe pipe) +{ + struct intel_crtc *intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + int reg; + u32 val; + + WARN(!intel_crtc->primary_enabled, "Primary plane already disabled\n"); + + intel_crtc->primary_enabled = false; + + reg = DSPCNTR(plane); + val = I915_READ(reg); + if ((val & DISPLAY_PLANE_ENABLE) == 0) + return; + + I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); + intel_flush_primary_plane(dev_priv, plane); + intel_wait_for_vblank(dev_priv->dev, pipe); +} + +static bool need_vtd_wa(struct drm_device *dev) +{ +#ifdef CONFIG_INTEL_IOMMU + if (INTEL_INFO(dev)->gen >= 6 && intel_iommu_gfx_mapped) + return true; +#endif + return false; +} + +int +intel_pin_and_fence_fb_obj(struct drm_device *dev, + struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 alignment; + int ret; + + switch (obj->tiling_mode) { + case I915_TILING_NONE: + if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) + alignment = 128 * 1024; + else if (INTEL_INFO(dev)->gen >= 4) + alignment = 4 * 1024; + else + alignment = 64 * 1024; + break; + case I915_TILING_X: + /* pin() will align the object as required by fence */ + alignment = 0; + break; + case I915_TILING_Y: + WARN(1, "Y tiled bo slipped through, driver bug!\n"); + return -EINVAL; + default: + BUG(); + } + + /* Note that the w/a also requires 64 PTE of padding following the + * bo. We currently fill all unused PTE with the shadow page and so + * we should always have valid PTE following the scanout preventing + * the VT-d warning. + */ + if (need_vtd_wa(dev) && alignment < 256 * 1024) + alignment = 256 * 1024; + + dev_priv->mm.interruptible = false; + ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined); + if (ret) + goto err_interruptible; + + /* Install a fence for tiled scan-out. Pre-i965 always needs a + * fence, whereas 965+ only requires a fence if using + * framebuffer compression. For simplicity, we always install + * a fence as the cost is not that onerous. + */ + ret = i915_gem_object_get_fence(obj); + if (ret) + goto err_unpin; + + i915_gem_object_pin_fence(obj); + + dev_priv->mm.interruptible = true; + return 0; + +err_unpin: + i915_gem_object_unpin_from_display_plane(obj); +err_interruptible: + dev_priv->mm.interruptible = true; + return ret; +} + +void intel_unpin_fb_obj(struct drm_i915_gem_object *obj) +{ + i915_gem_object_unpin_fence(obj); + i915_gem_object_unpin_from_display_plane(obj); +} + +/* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel + * is assumed to be a power-of-two. */ +unsigned long intel_gen4_compute_page_offset(int *x, int *y, + unsigned int tiling_mode, + unsigned int cpp, + unsigned int pitch) +{ + if (tiling_mode != I915_TILING_NONE) { + unsigned int tile_rows, tiles; + + tile_rows = *y / 8; + *y %= 8; + + tiles = *x / (512/cpp); + *x %= 512/cpp; + + return tile_rows * pitch * 8 + tiles * 4096; + } else { + unsigned int offset; + + offset = *y * pitch + *x * cpp; + *y = 0; + *x = (offset & 4095) / cpp; + return offset & -4096; + } +} + +static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj; + int plane = intel_crtc->plane; + unsigned long linear_offset; + u32 dspcntr; + u32 reg; + + switch (plane) { + case 0: + case 1: + break; + default: + DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane)); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + + reg = DSPCNTR(plane); + dspcntr = I915_READ(reg); + /* Mask out pixel format bits in case we change it */ + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + switch (fb->pixel_format) { + case DRM_FORMAT_C8: + dspcntr |= DISPPLANE_8BPP; + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: + dspcntr |= DISPPLANE_BGRX555; + break; + case DRM_FORMAT_RGB565: + dspcntr |= DISPPLANE_BGRX565; + break; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + dspcntr |= DISPPLANE_BGRX888; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + dspcntr |= DISPPLANE_RGBX888; + break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + dspcntr |= DISPPLANE_BGRX101010; + break; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + dspcntr |= DISPPLANE_RGBX101010; + break; + default: + BUG(); + } + + if (INTEL_INFO(dev)->gen >= 4) { + if (obj->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else + dspcntr &= ~DISPPLANE_TILED; + } + + if (IS_G4X(dev)) + dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + + I915_WRITE(reg, dspcntr); + + linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + + if (INTEL_INFO(dev)->gen >= 4) { + intel_crtc->dspaddr_offset = + intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + fb->bits_per_pixel / 8, + fb->pitches[0]); + linear_offset -= intel_crtc->dspaddr_offset; + } else { + intel_crtc->dspaddr_offset = linear_offset; + } + + DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", + i915_gem_obj_ggtt_offset(obj), linear_offset, x, y, + fb->pitches[0]); + I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); + if (INTEL_INFO(dev)->gen >= 4) { + I915_WRITE(DSPSURF(plane), + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); + I915_WRITE(DSPLINOFF(plane), linear_offset); + } else + I915_WRITE(DSPADDR(plane), i915_gem_obj_ggtt_offset(obj) + linear_offset); + POSTING_READ(reg); + + return 0; +} + +static int ironlake_update_plane(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj; + int plane = intel_crtc->plane; + unsigned long linear_offset; + u32 dspcntr; + u32 reg; + + switch (plane) { + case 0: + case 1: + case 2: + break; + default: + DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane)); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + + reg = DSPCNTR(plane); + dspcntr = I915_READ(reg); + /* Mask out pixel format bits in case we change it */ + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + switch (fb->pixel_format) { + case DRM_FORMAT_C8: + dspcntr |= DISPPLANE_8BPP; + break; + case DRM_FORMAT_RGB565: + dspcntr |= DISPPLANE_BGRX565; + break; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + dspcntr |= DISPPLANE_BGRX888; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + dspcntr |= DISPPLANE_RGBX888; + break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + dspcntr |= DISPPLANE_BGRX101010; + break; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + dspcntr |= DISPPLANE_RGBX101010; + break; + default: + BUG(); + } + + if (obj->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else + dspcntr &= ~DISPPLANE_TILED; + + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + dspcntr &= ~DISPPLANE_TRICKLE_FEED_DISABLE; + else + dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + + I915_WRITE(reg, dspcntr); + + linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + intel_crtc->dspaddr_offset = + intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + fb->bits_per_pixel / 8, + fb->pitches[0]); + linear_offset -= intel_crtc->dspaddr_offset; + + DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", + i915_gem_obj_ggtt_offset(obj), linear_offset, x, y, + fb->pitches[0]); + I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); + I915_WRITE(DSPSURF(plane), + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + I915_WRITE(DSPOFFSET(plane), (y << 16) | x); + } else { + I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); + I915_WRITE(DSPLINOFF(plane), linear_offset); + } + POSTING_READ(reg); + + return 0; +} + +/* Assume fb object is pinned & idle & fenced and just update base pointers */ +static int +intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y, enum mode_set_atomic state) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.disable_fbc) + dev_priv->display.disable_fbc(dev); + intel_increase_pllclock(crtc); + + return dev_priv->display.update_plane(crtc, fb, x, y); +} + +void intel_display_handle_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + + /* + * Flips in the rings have been nuked by the reset, + * so complete all pending flips so that user space + * will get its events and not get stuck. + * + * Also update the base address of all primary + * planes to the the last fb to make sure we're + * showing the correct fb after a reset. + * + * Need to make two loops over the crtcs so that we + * don't try to grab a crtc mutex before the + * pending_flip_queue really got woken up. + */ + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum plane plane = intel_crtc->plane; + + intel_prepare_page_flip(dev, plane); + intel_finish_page_flip_plane(dev, plane); + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + mutex_lock(&crtc->mutex); + /* + * FIXME: Once we have proper support for primary planes (and + * disabling them without disabling the entire crtc) allow again + * a NULL crtc->fb. + */ + if (intel_crtc->active && crtc->fb) + dev_priv->display.update_plane(crtc, crtc->fb, + crtc->x, crtc->y); + mutex_unlock(&crtc->mutex); + } +} + +static int +intel_finish_fb(struct drm_framebuffer *old_fb) +{ + struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + bool was_interruptible = dev_priv->mm.interruptible; + int ret; + + /* Big Hammer, we also need to ensure that any pending + * MI_WAIT_FOR_EVENT inside a user batch buffer on the + * current scanout is retired before unpinning the old + * framebuffer. + * + * This should only fail upon a hung GPU, in which case we + * can safely continue. + */ + dev_priv->mm.interruptible = false; + ret = i915_gem_object_finish_gpu(obj); + dev_priv->mm.interruptible = was_interruptible; + + return ret; +} + +static void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_master_private *master_priv; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + if (!dev->primary->master) + return; + + master_priv = dev->primary->master->driver_priv; + if (!master_priv->sarea_priv) + return; + + switch (intel_crtc->pipe) { + case 0: + master_priv->sarea_priv->pipeA_x = x; + master_priv->sarea_priv->pipeA_y = y; + break; + case 1: + master_priv->sarea_priv->pipeB_x = x; + master_priv->sarea_priv->pipeB_y = y; + break; + default: + break; + } +} + +static int +intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_framebuffer *old_fb; + int ret; + + /* no fb bound */ + if (!fb) { + DRM_ERROR("No FB bound\n"); + return 0; + } + + if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) { + DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n", + plane_name(intel_crtc->plane), + INTEL_INFO(dev)->num_pipes); + return -EINVAL; + } + + mutex_lock(&dev->struct_mutex); + ret = intel_pin_and_fence_fb_obj(dev, + to_intel_framebuffer(fb)->obj, + NULL); + if (ret != 0) { + mutex_unlock(&dev->struct_mutex); + DRM_ERROR("pin & fence failed\n"); + return ret; + } + + /* + * Update pipe size and adjust fitter if needed: the reason for this is + * that in compute_mode_changes we check the native mode (not the pfit + * mode) to see if we can flip rather than do a full mode set. In the + * fastboot case, we'll flip, but if we don't update the pipesrc and + * pfit state, we'll end up with a big fb scanned out into the wrong + * sized surface. + * + * To fix this properly, we need to hoist the checks up into + * compute_mode_changes (or above), check the actual pfit state and + * whether the platform allows pfit disable with pipe active, and only + * then update the pipesrc and pfit state, even on the flip path. + */ + if (i915_fastboot) { + const struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + + I915_WRITE(PIPESRC(intel_crtc->pipe), + ((adjusted_mode->crtc_hdisplay - 1) << 16) | + (adjusted_mode->crtc_vdisplay - 1)); + if (!intel_crtc->config.pch_pfit.enabled && + (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { + I915_WRITE(PF_CTL(intel_crtc->pipe), 0); + I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0); + I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0); + } + intel_crtc->config.pipe_src_w = adjusted_mode->crtc_hdisplay; + intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay; + } + + ret = dev_priv->display.update_plane(crtc, fb, x, y); + if (ret) { + intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj); + mutex_unlock(&dev->struct_mutex); + DRM_ERROR("failed to update base address\n"); + return ret; + } + + old_fb = crtc->fb; + crtc->fb = fb; + crtc->x = x; + crtc->y = y; + + if (old_fb) { + if (intel_crtc->active && old_fb != fb) + intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj); + } + + intel_update_fbc(dev); + intel_edp_psr_update(dev); + mutex_unlock(&dev->struct_mutex); + + intel_crtc_update_sarea_pos(crtc, x, y); + + return 0; +} + +static void intel_fdi_normal_train(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp; + + /* enable normal train */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + if (IS_IVYBRIDGE(dev)) { + temp &= ~FDI_LINK_TRAIN_NONE_IVB; + temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE; + } else { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; + } + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_NORMAL_CPT; + } else { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_NONE; + } + I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); + + /* wait one idle pattern time */ + POSTING_READ(reg); + udelay(1000); + + /* IVB wants error correction enabled */ + if (IS_IVYBRIDGE(dev)) + I915_WRITE(reg, I915_READ(reg) | FDI_FS_ERRC_ENABLE | + FDI_FE_ERRC_ENABLE); +} + +static bool pipe_has_enabled_pch(struct intel_crtc *crtc) +{ + return crtc->base.enabled && crtc->active && + crtc->config.has_pch_encoder; +} + +static void ivb_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *pipe_B_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); + struct intel_crtc *pipe_C_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_C]); + uint32_t temp; + + /* + * When everything is off disable fdi C so that we could enable fdi B + * with all lanes. Note that we don't care about enabled pipes without + * an enabled pch encoder. + */ + if (!pipe_has_enabled_pch(pipe_B_crtc) && + !pipe_has_enabled_pch(pipe_C_crtc)) { + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); + + temp = I915_READ(SOUTH_CHICKEN1); + temp &= ~FDI_BC_BIFURCATION_SELECT; + DRM_DEBUG_KMS("disabling fdi C rx\n"); + I915_WRITE(SOUTH_CHICKEN1, temp); + } +} + +/* The FDI link training functions for ILK/Ibexpeak. */ +static void ironlake_fdi_link_train(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + u32 reg, temp, tries; + + /* FDI needs bits from pipe & plane first */ + assert_pipe_enabled(dev_priv, pipe); + assert_plane_enabled(dev_priv, plane); + + /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + reg = FDI_RX_IMR(pipe); + temp = I915_READ(reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(reg, temp); + I915_READ(reg); + udelay(150); + + /* enable CPU FDI TX and PCH FDI RX */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_DP_PORT_WIDTH_MASK; + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(reg, temp | FDI_TX_ENABLE); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(reg, temp | FDI_RX_ENABLE); + + POSTING_READ(reg); + udelay(150); + + /* Ironlake workaround, enable clock pointer after FDI enable*/ + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR); + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR | + FDI_RX_PHASE_SYNC_POINTER_EN); + + reg = FDI_RX_IIR(pipe); + for (tries = 0; tries < 5; tries++) { + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + + if ((temp & FDI_RX_BIT_LOCK)) { + DRM_DEBUG_KMS("FDI train 1 done.\n"); + I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); + break; + } + } + if (tries == 5) + DRM_ERROR("FDI train 1 fail!\n"); + + /* Train 2 */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(150); + + reg = FDI_RX_IIR(pipe); + for (tries = 0; tries < 5; tries++) { + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + + if (temp & FDI_RX_SYMBOL_LOCK) { + I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG_KMS("FDI train 2 done.\n"); + break; + } + } + if (tries == 5) + DRM_ERROR("FDI train 2 fail!\n"); + + DRM_DEBUG_KMS("FDI train done\n"); + +} + +static const int snb_b_fdi_train_param[] = { + FDI_LINK_TRAIN_400MV_0DB_SNB_B, + FDI_LINK_TRAIN_400MV_6DB_SNB_B, + FDI_LINK_TRAIN_600MV_3_5DB_SNB_B, + FDI_LINK_TRAIN_800MV_0DB_SNB_B, +}; + +/* The FDI link training functions for SNB/Cougarpoint. */ +static void gen6_fdi_link_train(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp, i, retry; + + /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + reg = FDI_RX_IMR(pipe); + temp = I915_READ(reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(150); + + /* enable CPU FDI TX and PCH FDI RX */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_DP_PORT_WIDTH_MASK; + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + /* SNB-B */ + temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; + I915_WRITE(reg, temp | FDI_TX_ENABLE); + + I915_WRITE(FDI_RX_MISC(pipe), + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; + } else { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + } + I915_WRITE(reg, temp | FDI_RX_ENABLE); + + POSTING_READ(reg); + udelay(150); + + for (i = 0; i < 4; i++) { + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + temp |= snb_b_fdi_train_param[i]; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(500); + + for (retry = 0; retry < 5; retry++) { + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_BIT_LOCK) { + I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); + DRM_DEBUG_KMS("FDI train 1 done.\n"); + break; + } + udelay(50); + } + if (retry < 5) + break; + } + if (i == 4) + DRM_ERROR("FDI train 1 fail!\n"); + + /* Train 2 */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + if (IS_GEN6(dev)) { + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + /* SNB-B */ + temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; + } + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_2_CPT; + } else { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + } + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(150); + + for (i = 0; i < 4; i++) { + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + temp |= snb_b_fdi_train_param[i]; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(500); + + for (retry = 0; retry < 5; retry++) { + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_SYMBOL_LOCK) { + I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG_KMS("FDI train 2 done.\n"); + break; + } + udelay(50); + } + if (retry < 5) + break; + } + if (i == 4) + DRM_ERROR("FDI train 2 fail!\n"); + + DRM_DEBUG_KMS("FDI train done.\n"); +} + +/* Manual link training for Ivy Bridge A0 parts */ +static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp, i, j; + + /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + reg = FDI_RX_IMR(pipe); + temp = I915_READ(reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(150); + + DRM_DEBUG_KMS("FDI_RX_IIR before link train 0x%x\n", + I915_READ(FDI_RX_IIR(pipe))); + + /* Try each vswing and preemphasis setting twice before moving on */ + for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) { + /* disable first in case we need to retry */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB); + temp &= ~FDI_TX_ENABLE; + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_AUTO; + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp &= ~FDI_RX_ENABLE; + I915_WRITE(reg, temp); + + /* enable CPU FDI TX and PCH FDI RX */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_DP_PORT_WIDTH_MASK; + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); + temp |= FDI_LINK_TRAIN_PATTERN_1_IVB; + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + temp |= snb_b_fdi_train_param[j/2]; + temp |= FDI_COMPOSITE_SYNC; + I915_WRITE(reg, temp | FDI_TX_ENABLE); + + I915_WRITE(FDI_RX_MISC(pipe), + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; + temp |= FDI_COMPOSITE_SYNC; + I915_WRITE(reg, temp | FDI_RX_ENABLE); + + POSTING_READ(reg); + udelay(1); /* should be 0.5us */ + + for (i = 0; i < 4; i++) { + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + + if (temp & FDI_RX_BIT_LOCK || + (I915_READ(reg) & FDI_RX_BIT_LOCK)) { + I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); + DRM_DEBUG_KMS("FDI train 1 done, level %i.\n", + i); + break; + } + udelay(1); /* should be 0.5us */ + } + if (i == 4) { + DRM_DEBUG_KMS("FDI train 1 fail on vswing %d\n", j / 2); + continue; + } + + /* Train 2 */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE_IVB; + temp |= FDI_LINK_TRAIN_PATTERN_2_IVB; + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_2_CPT; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(2); /* should be 1.5us */ + + for (i = 0; i < 4; i++) { + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + + if (temp & FDI_RX_SYMBOL_LOCK || + (I915_READ(reg) & FDI_RX_SYMBOL_LOCK)) { + I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG_KMS("FDI train 2 done, level %i.\n", + i); + goto train_done; + } + udelay(2); /* should be 1.5us */ + } + if (i == 4) + DRM_DEBUG_KMS("FDI train 2 fail on vswing %d\n", j / 2); + } + +train_done: + DRM_DEBUG_KMS("FDI train done.\n"); +} + +static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = intel_crtc->pipe; + u32 reg, temp; + + + /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16)); + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; + I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); + + POSTING_READ(reg); + udelay(200); + + /* Switch from Rawclk to PCDclk */ + temp = I915_READ(reg); + I915_WRITE(reg, temp | FDI_PCDCLK); + + POSTING_READ(reg); + udelay(200); + + /* Enable CPU FDI TX PLL, always on for Ironlake */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); + + POSTING_READ(reg); + udelay(100); + } +} + +static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = intel_crtc->pipe; + u32 reg, temp; + + /* Switch from PCDclk to Rawclk */ + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_PCDCLK); + + /* Disable CPU FDI TX PLL */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE); + + POSTING_READ(reg); + udelay(100); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE); + + /* Wait for the clocks to turn off. */ + POSTING_READ(reg); + udelay(100); +} + +static void ironlake_fdi_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp; + + /* disable CPU FDI tx and PCH FDI rx */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_TX_ENABLE); + POSTING_READ(reg); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(0x7 << 16); + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; + I915_WRITE(reg, temp & ~FDI_RX_ENABLE); + + POSTING_READ(reg); + udelay(100); + + /* Ironlake workaround, disable clock pointer after downing FDI */ + if (HAS_PCH_IBX(dev)) { + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR); + } + + /* still set train pattern 1 */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; + } else { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + } + /* BPC in FDI rx is consistent with that in PIPECONF */ + temp &= ~(0x07 << 16); + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(100); +} + +static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long flags; + bool pending; + + if (i915_reset_in_progress(&dev_priv->gpu_error) || + intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) + return false; + + spin_lock_irqsave(&dev->event_lock, flags); + pending = to_intel_crtc(crtc)->unpin_work != NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + return pending; +} + +bool intel_has_pending_fb_unpin(struct drm_device *dev) +{ + struct intel_crtc *crtc; + + /* Note that we don't need to be called with mode_config.lock here + * as our list of CRTC objects is static for the lifetime of the + * device and so cannot disappear as we iterate. Similarly, we can + * happily treat the predicates as racy, atomic checks as userspace + * cannot claim and pin a new fb without at least acquring the + * struct_mutex and so serialising with us. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + if (atomic_read(&crtc->unpin_work_count) == 0) + continue; + + if (crtc->unpin_work) + intel_wait_for_vblank(dev, crtc->pipe); + + return true; + } + + return false; +} + +static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (crtc->fb == NULL) + return; + + WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); + + wait_event(dev_priv->pending_flip_queue, + !intel_crtc_has_pending_flip(crtc)); + + mutex_lock(&dev->struct_mutex); + intel_finish_fb(crtc->fb); + mutex_unlock(&dev->struct_mutex); +} + +/* Program iCLKIP clock to the desired frequency */ +static void lpt_program_iclkip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; + u32 divsel, phaseinc, auxdiv, phasedir = 0; + u32 temp; + + mutex_lock(&dev_priv->dpio_lock); + + /* It is necessary to ungate the pixclk gate prior to programming + * the divisors, and gate it back when it is done. + */ + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE); + + /* Disable SSCCTL */ + intel_sbi_write(dev_priv, SBI_SSCCTL6, + intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK) | + SBI_SSCCTL_DISABLE, + SBI_ICLK); + + /* 20MHz is a corner case which is out of range for the 7-bit divisor */ + if (clock == 20000) { + auxdiv = 1; + divsel = 0x41; + phaseinc = 0x20; + } else { + /* The iCLK virtual clock root frequency is in MHz, + * but the adjusted_mode->crtc_clock in in KHz. To get the + * divisors, it is necessary to divide one by another, so we + * convert the virtual clock precision to KHz here for higher + * precision. + */ + u32 iclk_virtual_root_freq = 172800 * 1000; + u32 iclk_pi_range = 64; + u32 desired_divisor, msb_divisor_value, pi_value; + + desired_divisor = (iclk_virtual_root_freq / clock); + msb_divisor_value = desired_divisor / iclk_pi_range; + pi_value = desired_divisor % iclk_pi_range; + + auxdiv = 0; + divsel = msb_divisor_value - 2; + phaseinc = pi_value; + } + + /* This should not happen with any sane values */ + WARN_ON(SBI_SSCDIVINTPHASE_DIVSEL(divsel) & + ~SBI_SSCDIVINTPHASE_DIVSEL_MASK); + WARN_ON(SBI_SSCDIVINTPHASE_DIR(phasedir) & + ~SBI_SSCDIVINTPHASE_INCVAL_MASK); + + DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n", + clock, + auxdiv, + divsel, + phasedir, + phaseinc); + + /* Program SSCDIVINTPHASE6 */ + temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK); + temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK; + temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel); + temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK; + temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc); + temp |= SBI_SSCDIVINTPHASE_DIR(phasedir); + temp |= SBI_SSCDIVINTPHASE_PROPAGATE; + intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK); + + /* Program SSCAUXDIV */ + temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK); + temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1); + temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv); + intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK); + + /* Enable modulator and associated divider */ + temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK); + temp &= ~SBI_SSCCTL_DISABLE; + intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK); + + /* Wait for initialization time */ + udelay(24); + + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); + + mutex_unlock(&dev_priv->dpio_lock); +} + +static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc, + enum pipe pch_transcoder) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; + + I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder), + I915_READ(HTOTAL(cpu_transcoder))); + I915_WRITE(PCH_TRANS_HBLANK(pch_transcoder), + I915_READ(HBLANK(cpu_transcoder))); + I915_WRITE(PCH_TRANS_HSYNC(pch_transcoder), + I915_READ(HSYNC(cpu_transcoder))); + + I915_WRITE(PCH_TRANS_VTOTAL(pch_transcoder), + I915_READ(VTOTAL(cpu_transcoder))); + I915_WRITE(PCH_TRANS_VBLANK(pch_transcoder), + I915_READ(VBLANK(cpu_transcoder))); + I915_WRITE(PCH_TRANS_VSYNC(pch_transcoder), + I915_READ(VSYNC(cpu_transcoder))); + I915_WRITE(PCH_TRANS_VSYNCSHIFT(pch_transcoder), + I915_READ(VSYNCSHIFT(cpu_transcoder))); +} + +static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t temp; + + temp = I915_READ(SOUTH_CHICKEN1); + if (temp & FDI_BC_BIFURCATION_SELECT) + return; + + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); + + temp |= FDI_BC_BIFURCATION_SELECT; + DRM_DEBUG_KMS("enabling fdi C rx\n"); + I915_WRITE(SOUTH_CHICKEN1, temp); + POSTING_READ(SOUTH_CHICKEN1); +} + +static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + switch (intel_crtc->pipe) { + case PIPE_A: + break; + case PIPE_B: + if (intel_crtc->config.fdi_lanes > 2) + WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); + else + cpt_enable_fdi_bc_bifurcation(dev); + + break; + case PIPE_C: + cpt_enable_fdi_bc_bifurcation(dev); + + break; + default: + BUG(); + } +} + +/* + * Enable PCH resources required for PCH ports: + * - PCH PLLs + * - FDI training & RX/TX + * - update transcoder timings + * - DP transcoding bits + * - transcoder + */ +static void ironlake_pch_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp; + + assert_pch_transcoder_disabled(dev_priv, pipe); + + if (IS_IVYBRIDGE(dev)) + ivybridge_update_fdi_bc_bifurcation(intel_crtc); + + /* Write the TU size bits before fdi link training, so that error + * detection works. */ + I915_WRITE(FDI_RX_TUSIZE1(pipe), + I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK); + + /* For PCH output, training FDI link */ + dev_priv->display.fdi_link_train(crtc); + + /* We need to program the right clock selection before writing the pixel + * mutliplier into the DPLL. */ + if (HAS_PCH_CPT(dev)) { + u32 sel; + + temp = I915_READ(PCH_DPLL_SEL); + temp |= TRANS_DPLL_ENABLE(pipe); + sel = TRANS_DPLLB_SEL(pipe); + if (intel_crtc->config.shared_dpll == DPLL_ID_PCH_PLL_B) + temp |= sel; + else + temp &= ~sel; + I915_WRITE(PCH_DPLL_SEL, temp); + } + + /* XXX: pch pll's can be enabled any time before we enable the PCH + * transcoder, and we actually should do this to not upset any PCH + * transcoder that already use the clock when we share it. + * + * Note that enable_shared_dpll tries to do the right thing, but + * get_shared_dpll unconditionally resets the pll - we need that to have + * the right LVDS enable sequence. */ + ironlake_enable_shared_dpll(intel_crtc); + + /* set transcoder timing, panel must allow it */ + assert_panel_unlocked(dev_priv, pipe); + ironlake_pch_transcoder_set_timings(intel_crtc, pipe); + + intel_fdi_normal_train(crtc); + + /* For PCH DP, enable TRANS_DP_CTL */ + if (HAS_PCH_CPT(dev) && + (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { + u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; + reg = TRANS_DP_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(TRANS_DP_PORT_SEL_MASK | + TRANS_DP_SYNC_MASK | + TRANS_DP_BPC_MASK); + temp |= (TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_ENH_FRAMING); + temp |= bpc << 9; /* same format but at 11:9 */ + + if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) + temp |= TRANS_DP_HSYNC_ACTIVE_HIGH; + if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) + temp |= TRANS_DP_VSYNC_ACTIVE_HIGH; + + switch (intel_trans_dp_port_sel(crtc)) { + case PCH_DP_B: + temp |= TRANS_DP_PORT_SEL_B; + break; + case PCH_DP_C: + temp |= TRANS_DP_PORT_SEL_C; + break; + case PCH_DP_D: + temp |= TRANS_DP_PORT_SEL_D; + break; + default: + BUG(); + } + + I915_WRITE(reg, temp); + } + + ironlake_enable_pch_transcoder(dev_priv, pipe); +} + +static void lpt_pch_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + + assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A); + + lpt_program_iclkip(crtc); + + /* Set transcoder timing. */ + ironlake_pch_transcoder_set_timings(intel_crtc, PIPE_A); + + lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); +} + +static void intel_put_shared_dpll(struct intel_crtc *crtc) +{ + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); + + if (pll == NULL) + return; + + if (pll->refcount == 0) { + WARN(1, "bad %s refcount\n", pll->name); + return; + } + + if (--pll->refcount == 0) { + WARN_ON(pll->on); + WARN_ON(pll->active); + } + + crtc->config.shared_dpll = DPLL_ID_PRIVATE; +} + +static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); + enum intel_dpll_id i; + + if (pll) { + DRM_DEBUG_KMS("CRTC:%d dropping existing %s\n", + crtc->base.base.id, pll->name); + intel_put_shared_dpll(crtc); + } + + if (HAS_PCH_IBX(dev_priv->dev)) { + /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ + i = (enum intel_dpll_id) crtc->pipe; + pll = &dev_priv->shared_dplls[i]; + + DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", + crtc->base.base.id, pll->name); + + goto found; + } + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + pll = &dev_priv->shared_dplls[i]; + + /* Only want to check enabled timings first */ + if (pll->refcount == 0) + continue; + + if (memcmp(&crtc->config.dpll_hw_state, &pll->hw_state, + sizeof(pll->hw_state)) == 0) { + DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n", + crtc->base.base.id, + pll->name, pll->refcount, pll->active); + + goto found; + } + } + + /* Ok no matching timings, maybe there's a free one? */ + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + pll = &dev_priv->shared_dplls[i]; + if (pll->refcount == 0) { + DRM_DEBUG_KMS("CRTC:%d allocated %s\n", + crtc->base.base.id, pll->name); + goto found; + } + } + + return NULL; + +found: + crtc->config.shared_dpll = i; + DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, + pipe_name(crtc->pipe)); + + if (pll->active == 0) { + memcpy(&pll->hw_state, &crtc->config.dpll_hw_state, + sizeof(pll->hw_state)); + + DRM_DEBUG_DRIVER("setting up %s\n", pll->name); + WARN_ON(pll->on); + assert_shared_dpll_disabled(dev_priv, pll); + + pll->mode_set(dev_priv, pll); + } + pll->refcount++; + + return pll; +} + +static void cpt_verify_modeset(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int dslreg = PIPEDSL(pipe); + u32 temp; + + temp = I915_READ(dslreg); + udelay(500); + if (wait_for(I915_READ(dslreg) != temp, 5)) { + if (wait_for(I915_READ(dslreg) != temp, 5)) + DRM_ERROR("mode set failed: pipe %c stuck\n", pipe_name(pipe)); + } +} + +static void ironlake_pfit_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + + if (crtc->config.pch_pfit.enabled) { + /* Force use of hard-coded filter coefficients + * as some pre-programmed values are broken, + * e.g. x201. + */ + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | + PF_PIPE_SEL_IVB(pipe)); + else + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(PF_WIN_POS(pipe), crtc->config.pch_pfit.pos); + I915_WRITE(PF_WIN_SZ(pipe), crtc->config.pch_pfit.size); + } +} + +static void intel_enable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct intel_plane *intel_plane; + + list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) + if (intel_plane->pipe == pipe) + intel_plane_restore(&intel_plane->base); +} + +static void intel_disable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct intel_plane *intel_plane; + + list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) + if (intel_plane->pipe == pipe) + intel_plane_disable(&intel_plane->base); +} + +void hsw_enable_ips(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (!crtc->config.ips_enabled) + return; + + /* We can only enable IPS after we enable a plane and wait for a vblank. + * We guarantee that the plane is enabled by calling intel_enable_ips + * only after intel_enable_plane. And intel_enable_plane already waits + * for a vblank, so all we need to do here is to enable the IPS bit. */ + assert_plane_enabled(dev_priv, crtc->plane); + if (IS_BROADWELL(crtc->base.dev)) { + mutex_lock(&dev_priv->rps.hw_lock); + WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0xc0000000)); + mutex_unlock(&dev_priv->rps.hw_lock); + /* Quoting Art Runyan: "its not safe to expect any particular + * value in IPS_CTL bit 31 after enabling IPS through the + * mailbox." Moreover, the mailbox may return a bogus state, + * so we need to just enable it and continue on. + */ + } else { + I915_WRITE(IPS_CTL, IPS_ENABLE); + /* The bit only becomes 1 in the next vblank, so this wait here + * is essentially intel_wait_for_vblank. If we don't have this + * and don't wait for vblanks until the end of crtc_enable, then + * the HW state readout code will complain that the expected + * IPS_CTL value is not the one we read. */ + if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50)) + DRM_ERROR("Timed out waiting for IPS enable\n"); + } +} + +void hsw_disable_ips(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!crtc->config.ips_enabled) + return; + + assert_plane_enabled(dev_priv, crtc->plane); + if (IS_BROADWELL(crtc->base.dev)) { + mutex_lock(&dev_priv->rps.hw_lock); + WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0)); + mutex_unlock(&dev_priv->rps.hw_lock); + } else { + I915_WRITE(IPS_CTL, 0); + POSTING_READ(IPS_CTL); + } + + /* We need to wait for a vblank before we can disable the plane. */ + intel_wait_for_vblank(dev, crtc->pipe); +} + +/** Loads the palette/gamma unit for the CRTC with the prepared values */ +static void intel_crtc_load_lut(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + int palreg = PALETTE(pipe); + int i; + bool reenable_ips = false; + + /* The clocks have to be on to load the palette. */ + if (!crtc->enabled || !intel_crtc->active) + return; + + if (!HAS_PCH_SPLIT(dev_priv->dev)) { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI)) + assert_dsi_pll_enabled(dev_priv); + else + assert_pll_enabled(dev_priv, pipe); + } + + /* use legacy palette for Ironlake */ + if (HAS_PCH_SPLIT(dev)) + palreg = LGC_PALETTE(pipe); + + /* Workaround : Do not read or write the pipe palette/gamma data while + * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. + */ + if (IS_HASWELL(dev) && intel_crtc->config.ips_enabled && + ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) == + GAMMA_MODE_MODE_SPLIT)) { + hsw_disable_ips(intel_crtc); + reenable_ips = true; + } + + for (i = 0; i < 256; i++) { + I915_WRITE(palreg + 4 * i, + (intel_crtc->lut_r[i] << 16) | + (intel_crtc->lut_g[i] << 8) | + intel_crtc->lut_b[i]); + } + + if (reenable_ips) + hsw_enable_ips(intel_crtc); +} + +static void ironlake_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + WARN_ON(!crtc->enabled); + + if (intel_crtc->active) + return; + + intel_crtc->active = true; + + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); + intel_set_pch_fifo_underrun_reporting(dev, pipe, true); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + + if (intel_crtc->config.has_pch_encoder) { + /* Note: FDI PLL enabling _must_ be done before we enable the + * cpu pipes, hence this is separate from all the other fdi/pch + * enabling. */ + ironlake_fdi_pll_enable(intel_crtc); + } else { + assert_fdi_tx_disabled(dev_priv, pipe); + assert_fdi_rx_disabled(dev_priv, pipe); + } + + ironlake_pfit_enable(intel_crtc); + + /* + * On ILK+ LUT must be loaded before the pipe is running but with + * clocks enabled + */ + intel_crtc_load_lut(crtc); + + intel_update_watermarks(crtc); + intel_enable_pipe(dev_priv, pipe, + intel_crtc->config.has_pch_encoder, false); + intel_enable_primary_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); + intel_crtc_update_cursor(crtc, true); + + if (intel_crtc->config.has_pch_encoder) + ironlake_pch_enable(crtc); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); + + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); + + if (HAS_PCH_CPT(dev)) + cpt_verify_modeset(dev, intel_crtc->pipe); + + /* + * There seems to be a race in PCH platform hw (at least on some + * outputs) where an enabled pipe still completes any pageflip right + * away (as if the pipe is off) instead of waiting for vblank. As soon + * as the first vblank happend, everything works as expected. Hence just + * wait for one vblank before returning to avoid strange things + * happening. + */ + intel_wait_for_vblank(dev, intel_crtc->pipe); +} + +/* IPS only exists on ULT machines and is tied to pipe A. */ +static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) +{ + return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A; +} + +static void haswell_crtc_enable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + intel_enable_primary_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); + intel_crtc_update_cursor(crtc, true); + + hsw_enable_ips(intel_crtc); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); +} + +static void haswell_crtc_disable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + intel_crtc_wait_for_pending_flips(crtc); + drm_vblank_off(dev, pipe); + + /* FBC must be disabled before disabling the plane on HSW. */ + if (dev_priv->fbc.plane == plane) + intel_disable_fbc(dev); + + hsw_disable_ips(intel_crtc); + + intel_crtc_update_cursor(crtc, false); + intel_disable_planes(crtc); + intel_disable_primary_plane(dev_priv, plane, pipe); +} + +/* + * This implements the workaround described in the "notes" section of the mode + * set sequence documentation. When going from no pipes or single pipe to + * multiple pipes, and planes are enabled after the pipe, we need to wait at + * least 2 vblanks on the first pipe before enabling planes on the second pipe. + */ +static void haswell_mode_set_planes_workaround(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_crtc *crtc_it, *other_active_crtc = NULL; + + /* We want to get the other_active_crtc only if there's only 1 other + * active crtc. */ + list_for_each_entry(crtc_it, &dev->mode_config.crtc_list, base.head) { + if (!crtc_it->active || crtc_it == crtc) + continue; + + if (other_active_crtc) + return; + + other_active_crtc = crtc_it; + } + if (!other_active_crtc) + return; + + intel_wait_for_vblank(dev, other_active_crtc->pipe); + intel_wait_for_vblank(dev, other_active_crtc->pipe); +} + +static void haswell_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + + WARN_ON(!crtc->enabled); + + if (intel_crtc->active) + return; + + intel_crtc->active = true; + + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); + if (intel_crtc->config.has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); + + if (intel_crtc->config.has_pch_encoder) + dev_priv->display.fdi_link_train(crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + + intel_ddi_enable_pipe_clock(intel_crtc); + + ironlake_pfit_enable(intel_crtc); + + /* + * On ILK+ LUT must be loaded before the pipe is running but with + * clocks enabled + */ + intel_crtc_load_lut(crtc); + + intel_ddi_set_pipe_settings(crtc); + intel_ddi_enable_transcoder_func(crtc); + + intel_update_watermarks(crtc); + intel_enable_pipe(dev_priv, pipe, + intel_crtc->config.has_pch_encoder, false); + + if (intel_crtc->config.has_pch_encoder) + lpt_pch_enable(crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) { + encoder->enable(encoder); + intel_opregion_notify_encoder(encoder, true); + } + + /* If we change the relative order between pipe/planes enabling, we need + * to change the workaround. */ + haswell_mode_set_planes_workaround(intel_crtc); + haswell_crtc_enable_planes(crtc); + + /* + * There seems to be a race in PCH platform hw (at least on some + * outputs) where an enabled pipe still completes any pageflip right + * away (as if the pipe is off) instead of waiting for vblank. As soon + * as the first vblank happend, everything works as expected. Hence just + * wait for one vblank before returning to avoid strange things + * happening. + */ + intel_wait_for_vblank(dev, intel_crtc->pipe); +} + +static void ironlake_pfit_disable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + + /* To avoid upsetting the power well on haswell only disable the pfit if + * it's in use. The hw state code will make sure we get this right. */ + if (crtc->config.pch_pfit.enabled) { + I915_WRITE(PF_CTL(pipe), 0); + I915_WRITE(PF_WIN_POS(pipe), 0); + I915_WRITE(PF_WIN_SZ(pipe), 0); + } +} + +static void ironlake_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + u32 reg, temp; + + + if (!intel_crtc->active) + return; + + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->disable(encoder); + + intel_crtc_wait_for_pending_flips(crtc); + drm_vblank_off(dev, pipe); + + if (dev_priv->fbc.plane == plane) + intel_disable_fbc(dev); + + intel_crtc_update_cursor(crtc, false); + intel_disable_planes(crtc); + intel_disable_primary_plane(dev_priv, plane, pipe); + + if (intel_crtc->config.has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev, pipe, false); + + intel_disable_pipe(dev_priv, pipe); + + ironlake_pfit_disable(intel_crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->post_disable) + encoder->post_disable(encoder); + + if (intel_crtc->config.has_pch_encoder) { + ironlake_fdi_disable(crtc); + + ironlake_disable_pch_transcoder(dev_priv, pipe); + intel_set_pch_fifo_underrun_reporting(dev, pipe, true); + + if (HAS_PCH_CPT(dev)) { + /* disable TRANS_DP_CTL */ + reg = TRANS_DP_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_PORT_SEL_MASK); + temp |= TRANS_DP_PORT_SEL_NONE; + I915_WRITE(reg, temp); + + /* disable DPLL_SEL */ + temp = I915_READ(PCH_DPLL_SEL); + temp &= ~(TRANS_DPLL_ENABLE(pipe) | TRANS_DPLLB_SEL(pipe)); + I915_WRITE(PCH_DPLL_SEL, temp); + } + + /* disable PCH DPLL */ + intel_disable_shared_dpll(intel_crtc); + + ironlake_fdi_pll_disable(intel_crtc); + } + + intel_crtc->active = false; + intel_update_watermarks(crtc); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); +} + +static void haswell_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + + if (!intel_crtc->active) + return; + + haswell_crtc_disable_planes(crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) { + intel_opregion_notify_encoder(encoder, false); + encoder->disable(encoder); + } + + if (intel_crtc->config.has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false); + intel_disable_pipe(dev_priv, pipe); + + intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); + + ironlake_pfit_disable(intel_crtc); + + intel_ddi_disable_pipe_clock(intel_crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->post_disable) + encoder->post_disable(encoder); + + if (intel_crtc->config.has_pch_encoder) { + lpt_disable_pch_transcoder(dev_priv); + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); + intel_ddi_fdi_disable(crtc); + } + + intel_crtc->active = false; + intel_update_watermarks(crtc); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); +} + +static void ironlake_crtc_off(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + intel_put_shared_dpll(intel_crtc); +} + +static void haswell_crtc_off(struct drm_crtc *crtc) +{ + intel_ddi_put_crtc_pll(crtc); +} + +static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) +{ + if (!enable && intel_crtc->overlay) { + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev->struct_mutex); + dev_priv->mm.interruptible = false; + (void) intel_overlay_switch_off(intel_crtc->overlay); + dev_priv->mm.interruptible = true; + mutex_unlock(&dev->struct_mutex); + } + + /* Let userspace switch the overlay on again. In most cases userspace + * has to recompute where to put it anyway. + */ +} + +/** + * i9xx_fixup_plane - ugly workaround for G45 to fire up the hardware + * cursor plane briefly if not already running after enabling the display + * plane. + * This workaround avoids occasional blank screens when self refresh is + * enabled. + */ +static void +g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + u32 cntl = I915_READ(CURCNTR(pipe)); + + if ((cntl & CURSOR_MODE) == 0) { + u32 fw_bcl_self = I915_READ(FW_BLC_SELF); + + I915_WRITE(FW_BLC_SELF, fw_bcl_self & ~FW_BLC_SELF_EN); + I915_WRITE(CURCNTR(pipe), CURSOR_MODE_64_ARGB_AX); + intel_wait_for_vblank(dev_priv->dev, pipe); + I915_WRITE(CURCNTR(pipe), cntl); + I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe))); + I915_WRITE(FW_BLC_SELF, fw_bcl_self); + } +} + +static void i9xx_pfit_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc_config *pipe_config = &crtc->config; + + if (!crtc->config.gmch_pfit.control) + return; + + /* + * The panel fitter should only be adjusted whilst the pipe is disabled, + * according to register description and PRM. + */ + WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); + assert_pipe_disabled(dev_priv, crtc->pipe); + + I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios); + I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control); + + /* Border color in case we don't scale up to the full screen. Black by + * default, change to something else for debugging. */ + I915_WRITE(BCLRPAT(crtc->pipe), 0); +} + +int valleyview_get_vco(struct drm_i915_private *dev_priv) +{ + int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; + + /* Obtain SKU information */ + mutex_lock(&dev_priv->dpio_lock); + hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + mutex_unlock(&dev_priv->dpio_lock); + + return vco_freq[hpll_freq]; +} + +/* Adjust CDclk dividers to allow high res or save power if possible */ +static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val, cmd; + + if (cdclk >= 320) /* jump to highest voltage for 400MHz too */ + cmd = 2; + else if (cdclk == 266) + cmd = 1; + else + cmd = 0; + + mutex_lock(&dev_priv->rps.hw_lock); + val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + val &= ~DSPFREQGUAR_MASK; + val |= (cmd << DSPFREQGUAR_SHIFT); + vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val); + if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & + DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), + 50)) { + DRM_ERROR("timed out waiting for CDclk change\n"); + } + mutex_unlock(&dev_priv->rps.hw_lock); + + if (cdclk == 400) { + u32 divider, vco; + + vco = valleyview_get_vco(dev_priv); + divider = ((vco << 1) / cdclk) - 1; + + mutex_lock(&dev_priv->dpio_lock); + /* adjust cdclk divider */ + val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); + val &= ~0xf; + val |= divider; + vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val); + mutex_unlock(&dev_priv->dpio_lock); + } + + mutex_lock(&dev_priv->dpio_lock); + /* adjust self-refresh exit latency value */ + val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC); + val &= ~0x7f; + + /* + * For high bandwidth configs, we set a higher latency in the bunit + * so that the core display fetch happens in time to avoid underruns. + */ + if (cdclk == 400) + val |= 4500 / 250; /* 4.5 usec */ + else + val |= 3000 / 250; /* 3.0 usec */ + vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val); + mutex_unlock(&dev_priv->dpio_lock); + + /* Since we changed the CDclk, we need to update the GMBUSFREQ too */ + intel_i2c_reset(dev); +} + +static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv) +{ + int cur_cdclk, vco; + int divider; + + vco = valleyview_get_vco(dev_priv); + + mutex_lock(&dev_priv->dpio_lock); + divider = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); + mutex_unlock(&dev_priv->dpio_lock); + + divider &= 0xf; + + cur_cdclk = (vco << 1) / (divider + 1); + + return cur_cdclk; +} + +static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, + int max_pixclk) +{ + int cur_cdclk; + + cur_cdclk = valleyview_cur_cdclk(dev_priv); + + /* + * Really only a few cases to deal with, as only 4 CDclks are supported: + * 200MHz + * 267MHz + * 320MHz + * 400MHz + * So we check to see whether we're above 90% of the lower bin and + * adjust if needed. + */ + if (max_pixclk > 288000) { + return 400; + } else if (max_pixclk > 240000) { + return 320; + } else + return 266; + /* Looks like the 200MHz CDclk freq doesn't work on some configs */ +} + +static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv, + unsigned modeset_pipes, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc; + int max_pixclk = 0; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + if (modeset_pipes & (1 << intel_crtc->pipe)) + max_pixclk = max(max_pixclk, + pipe_config->adjusted_mode.crtc_clock); + else if (intel_crtc->base.enabled) + max_pixclk = max(max_pixclk, + intel_crtc->config.adjusted_mode.crtc_clock); + } + + return max_pixclk; +} + +static void valleyview_modeset_global_pipes(struct drm_device *dev, + unsigned *prepare_pipes, + unsigned modeset_pipes, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc; + int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes, + pipe_config); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + + if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk) + return; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) + if (intel_crtc->base.enabled) + *prepare_pipes |= (1 << intel_crtc->pipe); +} + +static void valleyview_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); + + if (req_cdclk != cur_cdclk) + valleyview_set_cdclk(dev, req_cdclk); +} + +static void valleyview_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + bool is_dsi; + + WARN_ON(!crtc->enabled); + + if (intel_crtc->active) + return; + + intel_crtc->active = true; + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); + + is_dsi = intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI); + + if (!is_dsi) + vlv_enable_pll(intel_crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + + i9xx_pfit_enable(intel_crtc); + + intel_crtc_load_lut(crtc); + + intel_update_watermarks(crtc); + intel_enable_pipe(dev_priv, pipe, false, is_dsi); + intel_enable_primary_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); + intel_crtc_update_cursor(crtc, true); + + intel_update_fbc(dev); + + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); +} + +static void i9xx_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + WARN_ON(!crtc->enabled); + + if (intel_crtc->active) + return; + + intel_crtc->active = true; + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + + i9xx_enable_pll(intel_crtc); + + i9xx_pfit_enable(intel_crtc); + + intel_crtc_load_lut(crtc); + + intel_update_watermarks(crtc); + intel_enable_pipe(dev_priv, pipe, false, false); + intel_enable_primary_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); + /* The fixup needs to happen before cursor is enabled */ + if (IS_G4X(dev)) + g4x_fixup_plane(dev_priv, pipe); + intel_crtc_update_cursor(crtc, true); + + /* Give the overlay scaler a chance to enable if it's on this pipe */ + intel_crtc_dpms_overlay(intel_crtc, true); + + intel_update_fbc(dev); + + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); +} + +static void i9xx_pfit_disable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!crtc->config.gmch_pfit.control) + return; + + assert_pipe_disabled(dev_priv, crtc->pipe); + + DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", + I915_READ(PFIT_CONTROL)); + I915_WRITE(PFIT_CONTROL, 0); +} + +static void i9xx_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + if (!intel_crtc->active) + return; + + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->disable(encoder); + + /* Give the overlay scaler a chance to disable if it's on this pipe */ + intel_crtc_wait_for_pending_flips(crtc); + drm_vblank_off(dev, pipe); + + if (dev_priv->fbc.plane == plane) + intel_disable_fbc(dev); + + intel_crtc_dpms_overlay(intel_crtc, false); + intel_crtc_update_cursor(crtc, false); + intel_disable_planes(crtc); + intel_disable_primary_plane(dev_priv, plane, pipe); + + intel_disable_pipe(dev_priv, pipe); + + i9xx_pfit_disable(intel_crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->post_disable) + encoder->post_disable(encoder); + + if (IS_VALLEYVIEW(dev) && !intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI)) + vlv_disable_pll(dev_priv, pipe); + else if (!IS_VALLEYVIEW(dev)) + i9xx_disable_pll(dev_priv, pipe); + + intel_crtc->active = false; + intel_update_watermarks(crtc); + + intel_update_fbc(dev); +} + +static void i9xx_crtc_off(struct drm_crtc *crtc) +{ +} + +static void intel_crtc_update_sarea(struct drm_crtc *crtc, + bool enabled) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_master_private *master_priv; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + + if (!dev->primary->master) + return; + + master_priv = dev->primary->master->driver_priv; + if (!master_priv->sarea_priv) + return; + + switch (pipe) { + case 0: + master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; + master_priv->sarea_priv->pipeA_h = enabled ? crtc->mode.vdisplay : 0; + break; + case 1: + master_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0; + master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0; + break; + default: + DRM_ERROR("Can't update pipe %c in SAREA\n", pipe_name(pipe)); + break; + } +} + +/** + * Sets the power management mode of the pipe and plane. + */ +void intel_crtc_update_dpms(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + bool enable = false; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) + enable |= intel_encoder->connectors_active; + + if (enable) + dev_priv->display.crtc_enable(crtc); + else + dev_priv->display.crtc_disable(crtc); + + intel_crtc_update_sarea(crtc, enable); +} + +static void intel_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_connector *connector; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* crtc should still be enabled when we disable it. */ + WARN_ON(!crtc->enabled); + + dev_priv->display.crtc_disable(crtc); + intel_crtc->eld_vld = false; + intel_crtc_update_sarea(crtc, false); + dev_priv->display.off(crtc); + + assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); + assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe); + assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); + + if (crtc->fb) { + mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); + mutex_unlock(&dev->struct_mutex); + crtc->fb = NULL; + } + + /* Update computed state. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (!connector->encoder || !connector->encoder->crtc) + continue; + + if (connector->encoder->crtc != crtc) + continue; + + connector->dpms = DRM_MODE_DPMS_OFF; + to_intel_encoder(connector->encoder)->connectors_active = false; + } +} + +void intel_encoder_destroy(struct drm_encoder *encoder) +{ + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + + drm_encoder_cleanup(encoder); + kfree(intel_encoder); +} + +/* Simple dpms helper for encoders with just one connector, no cloning and only + * one kind of off state. It clamps all !ON modes to fully OFF and changes the + * state of the entire output pipe. */ +static void intel_encoder_dpms(struct intel_encoder *encoder, int mode) +{ + if (mode == DRM_MODE_DPMS_ON) { + encoder->connectors_active = true; + + intel_crtc_update_dpms(encoder->base.crtc); + } else { + encoder->connectors_active = false; + + intel_crtc_update_dpms(encoder->base.crtc); + } +} + +/* Cross check the actual hw state with our own modeset state tracking (and it's + * internal consistency). */ +static void intel_connector_check_state(struct intel_connector *connector) +{ + if (connector->get_hw_state(connector)) { + struct intel_encoder *encoder = connector->encoder; + struct drm_crtc *crtc; + bool encoder_enabled; + enum pipe pipe; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.base.id, + drm_get_connector_name(&connector->base)); + + WARN(connector->base.dpms == DRM_MODE_DPMS_OFF, + "wrong connector dpms state\n"); + WARN(connector->base.encoder != &encoder->base, + "active connector not linked to encoder\n"); + WARN(!encoder->connectors_active, + "encoder->connectors_active not set\n"); + + encoder_enabled = encoder->get_hw_state(encoder, &pipe); + WARN(!encoder_enabled, "encoder not enabled\n"); + if (WARN_ON(!encoder->base.crtc)) + return; + + crtc = encoder->base.crtc; + + WARN(!crtc->enabled, "crtc not enabled\n"); + WARN(!to_intel_crtc(crtc)->active, "crtc not active\n"); + WARN(pipe != to_intel_crtc(crtc)->pipe, + "encoder active on the wrong pipe\n"); + } +} + +/* Even simpler default implementation, if there's really no special case to + * consider. */ +void intel_connector_dpms(struct drm_connector *connector, int mode) +{ + /* All the simple cases only support two dpms states. */ + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + if (mode == connector->dpms) + return; + + connector->dpms = mode; + + /* Only need to change hw state when actually enabled */ + if (connector->encoder) + intel_encoder_dpms(to_intel_encoder(connector->encoder), mode); + + intel_modeset_check_state(connector->dev); +} + +/* Simple connector->get_hw_state implementation for encoders that support only + * one connector and no cloning and hence the encoder state determines the state + * of the connector. */ +bool intel_connector_get_hw_state(struct intel_connector *connector) +{ + enum pipe pipe = 0; + struct intel_encoder *encoder = connector->encoder; + + return encoder->get_hw_state(encoder, &pipe); +} + +static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *pipe_B_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); + + DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n", + pipe_name(pipe), pipe_config->fdi_lanes); + if (pipe_config->fdi_lanes > 4) { + DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n", + pipe_name(pipe), pipe_config->fdi_lanes); + return false; + } + + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + if (pipe_config->fdi_lanes > 2) { + DRM_DEBUG_KMS("only 2 lanes on haswell, required: %i lanes\n", + pipe_config->fdi_lanes); + return false; + } else { + return true; + } + } + + if (INTEL_INFO(dev)->num_pipes == 2) + return true; + + /* Ivybridge 3 pipe is really complicated */ + switch (pipe) { + case PIPE_A: + return true; + case PIPE_B: + if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled && + pipe_config->fdi_lanes > 2) { + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", + pipe_name(pipe), pipe_config->fdi_lanes); + return false; + } + return true; + case PIPE_C: + if (!pipe_has_enabled_pch(pipe_B_crtc) || + pipe_B_crtc->config.fdi_lanes <= 2) { + if (pipe_config->fdi_lanes > 2) { + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", + pipe_name(pipe), pipe_config->fdi_lanes); + return false; + } + } else { + DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n"); + return false; + } + return true; + default: + BUG(); + } +} + +#define RETRY 1 +static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + int lane, link_bw, fdi_dotclock; + bool setup_ok, needs_recompute = false; + +retry: + /* FDI is a binary signal running at ~2.7GHz, encoding + * each output octet as 10 bits. The actual frequency + * is stored as a divider into a 100MHz clock, and the + * mode pixel clock is stored in units of 1KHz. + * Hence the bw of each lane in terms of the mode signal + * is: + */ + link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; + + fdi_dotclock = adjusted_mode->crtc_clock; + + lane = ironlake_get_lanes_required(fdi_dotclock, link_bw, + pipe_config->pipe_bpp); + + pipe_config->fdi_lanes = lane; + + intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, + link_bw, &pipe_config->fdi_m_n); + + setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev, + intel_crtc->pipe, pipe_config); + if (!setup_ok && pipe_config->pipe_bpp > 6*3) { + pipe_config->pipe_bpp -= 2*3; + DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n", + pipe_config->pipe_bpp); + needs_recompute = true; + pipe_config->bw_constrained = true; + + goto retry; + } + + if (needs_recompute) + return RETRY; + + return setup_ok ? 0 : -EINVAL; +} + +static void hsw_compute_ips_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + pipe_config->ips_enabled = i915_enable_ips && + hsw_crtc_supports_ips(crtc) && + pipe_config->pipe_bpp <= 24; +} + +static int intel_crtc_compute_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + + /* FIXME should check pixel clock limits on all platforms */ + if (INTEL_INFO(dev)->gen < 4) { + struct drm_i915_private *dev_priv = dev->dev_private; + int clock_limit = + dev_priv->display.get_display_clock_speed(dev); + + /* + * Enable pixel doubling when the dot clock + * is > 90% of the (display) core speed. + * + * GDG double wide on either pipe, + * otherwise pipe A only. + */ + if ((crtc->pipe == PIPE_A || IS_I915G(dev)) && + adjusted_mode->crtc_clock > clock_limit * 9 / 10) { + clock_limit *= 2; + pipe_config->double_wide = true; + } + + if (adjusted_mode->crtc_clock > clock_limit * 9 / 10) + return -EINVAL; + } + + /* + * Pipe horizontal size must be even in: + * - DVO ganged mode + * - LVDS dual channel mode + * - Double wide pipe + */ + if ((intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && + intel_is_dual_link_lvds(dev)) || pipe_config->double_wide) + pipe_config->pipe_src_w &= ~1; + + /* Cantiga+ cannot handle modes with a hsync front porch of 0. + * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. + */ + if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && + adjusted_mode->hsync_start == adjusted_mode->hdisplay) + return -EINVAL; + + if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { + pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ + } else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8*3) { + /* only a 8bpc pipe, with 6bpc dither through the panel fitter + * for lvds. */ + pipe_config->pipe_bpp = 8*3; + } + + if (HAS_IPS(dev)) + hsw_compute_ips_config(crtc, pipe_config); + + /* XXX: PCH clock sharing is done in ->mode_set, so make sure the old + * clock survives for now. */ + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + pipe_config->shared_dpll = crtc->config.shared_dpll; + + if (pipe_config->has_pch_encoder) + return ironlake_fdi_compute_config(crtc, pipe_config); + + return 0; +} + +static int valleyview_get_display_clock_speed(struct drm_device *dev) +{ + return 400000; /* FIXME */ +} + +static int i945_get_display_clock_speed(struct drm_device *dev) +{ + return 400000; +} + +static int i915_get_display_clock_speed(struct drm_device *dev) +{ + return 333000; +} + +static int i9xx_misc_get_display_clock_speed(struct drm_device *dev) +{ + return 200000; +} + +static int pnv_get_display_clock_speed(struct drm_device *dev) +{ + u16 gcfgc = 0; + + pci_read_config_word(dev->pdev, GCFGC, &gcfgc); + + switch (gcfgc & GC_DISPLAY_CLOCK_MASK) { + case GC_DISPLAY_CLOCK_267_MHZ_PNV: + return 267000; + case GC_DISPLAY_CLOCK_333_MHZ_PNV: + return 333000; + case GC_DISPLAY_CLOCK_444_MHZ_PNV: + return 444000; + case GC_DISPLAY_CLOCK_200_MHZ_PNV: + return 200000; + default: + DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc); + case GC_DISPLAY_CLOCK_133_MHZ_PNV: + return 133000; + case GC_DISPLAY_CLOCK_167_MHZ_PNV: + return 167000; + } +} + +static int i915gm_get_display_clock_speed(struct drm_device *dev) +{ + u16 gcfgc = 0; + + pci_read_config_word(dev->pdev, GCFGC, &gcfgc); + + if (gcfgc & GC_LOW_FREQUENCY_ENABLE) + return 133000; + else { + switch (gcfgc & GC_DISPLAY_CLOCK_MASK) { + case GC_DISPLAY_CLOCK_333_MHZ: + return 333000; + default: + case GC_DISPLAY_CLOCK_190_200_MHZ: + return 190000; + } + } +} + +static int i865_get_display_clock_speed(struct drm_device *dev) +{ + return 266000; +} + +static int i855_get_display_clock_speed(struct drm_device *dev) +{ + u16 hpllcc = 0; + /* Assume that the hardware is in the high speed state. This + * should be the default. + */ + switch (hpllcc & GC_CLOCK_CONTROL_MASK) { + case GC_CLOCK_133_200: + case GC_CLOCK_100_200: + return 200000; + case GC_CLOCK_166_250: + return 250000; + case GC_CLOCK_100_133: + return 133000; + } + + /* Shouldn't happen */ + return 0; +} + +static int i830_get_display_clock_speed(struct drm_device *dev) +{ + return 133000; +} + +static void +intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) +{ + while (*num > DATA_LINK_M_N_MASK || + *den > DATA_LINK_M_N_MASK) { + *num >>= 1; + *den >>= 1; + } +} + +static void compute_m_n(unsigned int m, unsigned int n, + uint32_t *ret_m, uint32_t *ret_n) +{ + *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); + *ret_m = div_u64((uint64_t) m * *ret_n, n); + intel_reduce_m_n_ratio(ret_m, ret_n); +} + +void +intel_link_compute_m_n(int bits_per_pixel, int nlanes, + int pixel_clock, int link_clock, + struct intel_link_m_n *m_n) +{ + m_n->tu = 64; + + compute_m_n(bits_per_pixel * pixel_clock, + link_clock * nlanes * 8, + &m_n->gmch_m, &m_n->gmch_n); + + compute_m_n(pixel_clock, link_clock, + &m_n->link_m, &m_n->link_n); +} + +static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) +{ + if (i915_panel_use_ssc >= 0) + return i915_panel_use_ssc != 0; + return dev_priv->vbt.lvds_use_ssc + && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); +} + +static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int refclk; + + if (IS_VALLEYVIEW(dev)) { + refclk = 100000; + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + intel_panel_use_ssc(dev_priv) && num_connectors < 2) { + refclk = dev_priv->vbt.lvds_ssc_freq; + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk); + } else if (!IS_GEN2(dev)) { + refclk = 96000; + } else { + refclk = 48000; + } + + return refclk; +} + +static uint32_t pnv_dpll_compute_fp(struct dpll *dpll) +{ + return (1 << dpll->n) << 16 | dpll->m2; +} + +static uint32_t i9xx_dpll_compute_fp(struct dpll *dpll) +{ + return dpll->n << 16 | dpll->m1 << 8 | dpll->m2; +} + +static void i9xx_update_pll_dividers(struct intel_crtc *crtc, + intel_clock_t *reduced_clock) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + u32 fp, fp2 = 0; + + if (IS_PINEVIEW(dev)) { + fp = pnv_dpll_compute_fp(&crtc->config.dpll); + if (reduced_clock) + fp2 = pnv_dpll_compute_fp(reduced_clock); + } else { + fp = i9xx_dpll_compute_fp(&crtc->config.dpll); + if (reduced_clock) + fp2 = i9xx_dpll_compute_fp(reduced_clock); + } + + I915_WRITE(FP0(pipe), fp); + crtc->config.dpll_hw_state.fp0 = fp; + + crtc->lowfreq_avail = false; + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && + reduced_clock && i915_powersave) { + I915_WRITE(FP1(pipe), fp2); + crtc->config.dpll_hw_state.fp1 = fp2; + crtc->lowfreq_avail = true; + } else { + I915_WRITE(FP1(pipe), fp); + crtc->config.dpll_hw_state.fp1 = fp; + } +} + +static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe + pipe) +{ + u32 reg_val; + + /* + * PLLB opamp always calibrates to max value of 0x3f, force enable it + * and set it to a reasonable value instead. + */ + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val &= 0xffffff00; + reg_val |= 0x00000030; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val &= 0x8cffffff; + reg_val = 0x8c000000; + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val &= 0xffffff00; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val &= 0x00ffffff; + reg_val |= 0xb0000000; + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); +} + +static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + + I915_WRITE(PCH_TRANS_DATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PCH_TRANS_DATA_N1(pipe), m_n->gmch_n); + I915_WRITE(PCH_TRANS_LINK_M1(pipe), m_n->link_m); + I915_WRITE(PCH_TRANS_LINK_N1(pipe), m_n->link_n); +} + +static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + enum transcoder transcoder = crtc->config.cpu_transcoder; + + if (INTEL_INFO(dev)->gen >= 5) { + I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n); + I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m); + I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n); + } else { + I915_WRITE(PIPE_DATA_M_G4X(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_DATA_N_G4X(pipe), m_n->gmch_n); + I915_WRITE(PIPE_LINK_M_G4X(pipe), m_n->link_m); + I915_WRITE(PIPE_LINK_N_G4X(pipe), m_n->link_n); + } +} + +static void intel_dp_set_m_n(struct intel_crtc *crtc) +{ + if (crtc->config.has_pch_encoder) + intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); + else + intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); +} + +static void vlv_update_pll(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + u32 dpll, mdiv; + u32 bestn, bestm1, bestm2, bestp1, bestp2; + u32 coreclk, reg_val, dpll_md; + + mutex_lock(&dev_priv->dpio_lock); + + bestn = crtc->config.dpll.n; + bestm1 = crtc->config.dpll.m1; + bestm2 = crtc->config.dpll.m2; + bestp1 = crtc->config.dpll.p1; + bestp2 = crtc->config.dpll.p2; + + /* See eDP HDMI DPIO driver vbios notes doc */ + + /* PLL B needs special handling */ + if (pipe) + vlv_pllb_recal_opamp(dev_priv, pipe); + + /* Set up Tx target for periodic Rcomp update */ + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); + + /* Disable target IRef on PLL */ + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); + reg_val &= 0x00ffffff; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); + + /* Disable fast lock */ + vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); + + /* Set idtafcrecal before PLL is enabled */ + mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); + mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); + mdiv |= ((bestn << DPIO_N_SHIFT)); + mdiv |= (1 << DPIO_K_SHIFT); + + /* + * Post divider depends on pixel clock rate, DAC vs digital (and LVDS, + * but we don't support that). + * Note: don't use the DAC post divider as it seems unstable. + */ + mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + + mdiv |= DPIO_ENABLE_CALIBRATION; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + + /* Set HBR and RBR LPF coefficients */ + if (crtc->config.port_clock == 162000 || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + 0x009f0003); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + 0x00d0000f); + + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) { + /* Use SSC source */ + if (!pipe) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df40000); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df70000); + } else { /* HDMI or VGA */ + /* Use bend source */ + if (!pipe) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df70000); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df40000); + } + + coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); + coreclk = (coreclk & 0x0000ff00) | 0x01c00000; + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) + coreclk |= 0x01000000; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); + + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); + + /* + * Enable DPIO clock input. We should never disable the reference + * clock for pipe B, since VGA hotplug / manual detection depends + * on it. + */ + dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | + DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; + /* We should never disable this, set it here for state tracking */ + if (pipe == PIPE_B) + dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; + dpll |= DPLL_VCO_ENABLE; + crtc->config.dpll_hw_state.dpll = dpll; + + dpll_md = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; + crtc->config.dpll_hw_state.dpll_md = dpll_md; + + if (crtc->config.has_dp_encoder) + intel_dp_set_m_n(crtc); + + mutex_unlock(&dev_priv->dpio_lock); +} + +static void i9xx_update_pll(struct intel_crtc *crtc, + intel_clock_t *reduced_clock, + int num_connectors) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpll; + bool is_sdvo; + struct dpll *clock = &crtc->config.dpll; + + i9xx_update_pll_dividers(crtc, reduced_clock); + + is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI); + + dpll = DPLL_VGA_MODE_DIS; + + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) + dpll |= DPLLB_MODE_LVDS; + else + dpll |= DPLLB_MODE_DAC_SERIAL; + + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { + dpll |= (crtc->config.pixel_multiplier - 1) + << SDVO_MULTIPLIER_SHIFT_HIRES; + } + + if (is_sdvo) + dpll |= DPLL_SDVO_HIGH_SPEED; + + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) + dpll |= DPLL_SDVO_HIGH_SPEED; + + /* compute bitmask from p1 value */ + if (IS_PINEVIEW(dev)) + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW; + else { + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + if (IS_G4X(dev) && reduced_clock) + dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + } + switch (clock->p2) { + case 5: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; + break; + case 7: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; + break; + case 10: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; + break; + case 14: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; + break; + } + if (INTEL_INFO(dev)->gen >= 4) + dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); + + if (crtc->config.sdvo_tv_clock) + dpll |= PLL_REF_INPUT_TVCLKINBC; + else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && + intel_panel_use_ssc(dev_priv) && num_connectors < 2) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; + else + dpll |= PLL_REF_INPUT_DREFCLK; + + dpll |= DPLL_VCO_ENABLE; + crtc->config.dpll_hw_state.dpll = dpll; + + if (INTEL_INFO(dev)->gen >= 4) { + u32 dpll_md = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; + crtc->config.dpll_hw_state.dpll_md = dpll_md; + } + + if (crtc->config.has_dp_encoder) + intel_dp_set_m_n(crtc); +} + +static void i8xx_update_pll(struct intel_crtc *crtc, + intel_clock_t *reduced_clock, + int num_connectors) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpll; + struct dpll *clock = &crtc->config.dpll; + + i9xx_update_pll_dividers(crtc, reduced_clock); + + dpll = DPLL_VGA_MODE_DIS; + + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) { + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + } else { + if (clock->p1 == 2) + dpll |= PLL_P1_DIVIDE_BY_TWO; + else + dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; + if (clock->p2 == 4) + dpll |= PLL_P2_DIVIDE_BY_4; + } + + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO)) + dpll |= DPLL_DVO_2X_MODE; + + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && + intel_panel_use_ssc(dev_priv) && num_connectors < 2) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; + else + dpll |= PLL_REF_INPUT_DREFCLK; + + dpll |= DPLL_VCO_ENABLE; + crtc->config.dpll_hw_state.dpll = dpll; +} + +static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_crtc->pipe; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + uint32_t vsyncshift, crtc_vtotal, crtc_vblank_end; + + /* We need to be careful not to changed the adjusted mode, for otherwise + * the hw state checker will get angry at the mismatch. */ + crtc_vtotal = adjusted_mode->crtc_vtotal; + crtc_vblank_end = adjusted_mode->crtc_vblank_end; + + if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + /* the chip adds 2 halflines automatically */ + crtc_vtotal -= 1; + crtc_vblank_end -= 1; + vsyncshift = adjusted_mode->crtc_hsync_start + - adjusted_mode->crtc_htotal / 2; + } else { + vsyncshift = 0; + } + + if (INTEL_INFO(dev)->gen > 3) + I915_WRITE(VSYNCSHIFT(cpu_transcoder), vsyncshift); + + I915_WRITE(HTOTAL(cpu_transcoder), + (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + I915_WRITE(HBLANK(cpu_transcoder), + (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + I915_WRITE(HSYNC(cpu_transcoder), + (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + + I915_WRITE(VTOTAL(cpu_transcoder), + (adjusted_mode->crtc_vdisplay - 1) | + ((crtc_vtotal - 1) << 16)); + I915_WRITE(VBLANK(cpu_transcoder), + (adjusted_mode->crtc_vblank_start - 1) | + ((crtc_vblank_end - 1) << 16)); + I915_WRITE(VSYNC(cpu_transcoder), + (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + + /* Workaround: when the EDP input selection is B, the VTOTAL_B must be + * programmed with the VTOTAL_EDP value. Same for VTOTAL_C. This is + * documented on the DDI_FUNC_CTL register description, EDP Input Select + * bits. */ + if (IS_HASWELL(dev) && cpu_transcoder == TRANSCODER_EDP && + (pipe == PIPE_B || pipe == PIPE_C)) + I915_WRITE(VTOTAL(pipe), I915_READ(VTOTAL(cpu_transcoder))); + + /* pipesrc controls the size that is scaled from, which should + * always be the user's requested size. + */ + I915_WRITE(PIPESRC(pipe), + ((intel_crtc->config.pipe_src_w - 1) << 16) | + (intel_crtc->config.pipe_src_h - 1)); +} + +static void intel_get_pipe_timings(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; + uint32_t tmp; + + tmp = I915_READ(HTOTAL(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(HBLANK(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(HSYNC(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1; + + tmp = I915_READ(VTOTAL(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(VBLANK(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(VSYNC(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1; + + if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) { + pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE; + pipe_config->adjusted_mode.crtc_vtotal += 1; + pipe_config->adjusted_mode.crtc_vblank_end += 1; + } + + tmp = I915_READ(PIPESRC(crtc->pipe)); + pipe_config->pipe_src_h = (tmp & 0xffff) + 1; + pipe_config->pipe_src_w = ((tmp >> 16) & 0xffff) + 1; + + pipe_config->requested_mode.vdisplay = pipe_config->pipe_src_h; + pipe_config->requested_mode.hdisplay = pipe_config->pipe_src_w; +} + +static void intel_crtc_mode_from_pipe_config(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_crtc *crtc = &intel_crtc->base; + + crtc->mode.hdisplay = pipe_config->adjusted_mode.crtc_hdisplay; + crtc->mode.htotal = pipe_config->adjusted_mode.crtc_htotal; + crtc->mode.hsync_start = pipe_config->adjusted_mode.crtc_hsync_start; + crtc->mode.hsync_end = pipe_config->adjusted_mode.crtc_hsync_end; + + crtc->mode.vdisplay = pipe_config->adjusted_mode.crtc_vdisplay; + crtc->mode.vtotal = pipe_config->adjusted_mode.crtc_vtotal; + crtc->mode.vsync_start = pipe_config->adjusted_mode.crtc_vsync_start; + crtc->mode.vsync_end = pipe_config->adjusted_mode.crtc_vsync_end; + + crtc->mode.flags = pipe_config->adjusted_mode.flags; + + crtc->mode.clock = pipe_config->adjusted_mode.crtc_clock; + crtc->mode.flags |= pipe_config->adjusted_mode.flags; +} + +static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t pipeconf; + + pipeconf = 0; + + if (dev_priv->quirks & QUIRK_PIPEA_FORCE && + I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE) + pipeconf |= PIPECONF_ENABLE; + + if (intel_crtc->config.double_wide) + pipeconf |= PIPECONF_DOUBLE_WIDE; + + /* only g4x and later have fancy bpc/dither controls */ + if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { + /* Bspec claims that we can't use dithering for 30bpp pipes. */ + if (intel_crtc->config.dither && intel_crtc->config.pipe_bpp != 30) + pipeconf |= PIPECONF_DITHER_EN | + PIPECONF_DITHER_TYPE_SP; + + switch (intel_crtc->config.pipe_bpp) { + case 18: + pipeconf |= PIPECONF_6BPC; + break; + case 24: + pipeconf |= PIPECONF_8BPC; + break; + case 30: + pipeconf |= PIPECONF_10BPC; + break; + default: + /* Case prevented by intel_choose_pipe_bpp_dither. */ + BUG(); + } + } + + if (HAS_PIPE_CXSR(dev)) { + if (intel_crtc->lowfreq_avail) { + DRM_DEBUG_KMS("enabling CxSR downclocking\n"); + pipeconf |= PIPECONF_CXSR_DOWNCLOCK; + } else { + DRM_DEBUG_KMS("disabling CxSR downclocking\n"); + } + } + + if (!IS_GEN2(dev) && + intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) + pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; + else + pipeconf |= PIPECONF_PROGRESSIVE; + + if (IS_VALLEYVIEW(dev) && intel_crtc->config.limited_color_range) + pipeconf |= PIPECONF_COLOR_RANGE_SELECT; + + I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf); + POSTING_READ(PIPECONF(intel_crtc->pipe)); +} + +static int i9xx_crtc_mode_set(struct drm_crtc *crtc, + int x, int y, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int refclk, num_connectors = 0; + intel_clock_t clock, reduced_clock; + u32 dspcntr; + bool ok, has_reduced_clock = false; + bool is_lvds = false, is_dsi = false; + struct intel_encoder *encoder; + const intel_limit_t *limit; + int ret; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_DSI: + is_dsi = true; + break; + } + + num_connectors++; + } + + if (is_dsi) + goto skip_dpll; + + if (!intel_crtc->config.clock_set) { + refclk = i9xx_get_refclk(crtc, num_connectors); + + /* + * Returns a set of divisors for the desired target clock with + * the given refclk, or FALSE. The returned values represent + * the clock equation: reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + + * 2) / p1 / p2. + */ + limit = intel_limit(crtc, refclk); + ok = dev_priv->display.find_dpll(limit, crtc, + intel_crtc->config.port_clock, + refclk, NULL, &clock); + if (!ok) { + DRM_ERROR("Couldn't find PLL settings for mode!\n"); + return -EINVAL; + } + + if (is_lvds && dev_priv->lvds_downclock_avail) { + /* + * Ensure we match the reduced clock's P to the target + * clock. If the clocks don't match, we can't switch + * the display clock by using the FP0/FP1. In such case + * we will disable the LVDS downclock feature. + */ + has_reduced_clock = + dev_priv->display.find_dpll(limit, crtc, + dev_priv->lvds_downclock, + refclk, &clock, + &reduced_clock); + } + /* Compat-code for transition, will disappear. */ + intel_crtc->config.dpll.n = clock.n; + intel_crtc->config.dpll.m1 = clock.m1; + intel_crtc->config.dpll.m2 = clock.m2; + intel_crtc->config.dpll.p1 = clock.p1; + intel_crtc->config.dpll.p2 = clock.p2; + } + + if (IS_GEN2(dev)) { + i8xx_update_pll(intel_crtc, + has_reduced_clock ? &reduced_clock : NULL, + num_connectors); + } else if (IS_VALLEYVIEW(dev)) { + vlv_update_pll(intel_crtc); + } else { + i9xx_update_pll(intel_crtc, + has_reduced_clock ? &reduced_clock : NULL, + num_connectors); + } + +skip_dpll: + /* Set up the display plane register */ + dspcntr = DISPPLANE_GAMMA_ENABLE; + + if (!IS_VALLEYVIEW(dev)) { + if (pipe == 0) + dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; + } + + intel_set_pipe_timings(intel_crtc); + + /* pipesrc and dspsize control the size that is scaled from, + * which should always be the user's requested size. + */ + I915_WRITE(DSPSIZE(plane), + ((intel_crtc->config.pipe_src_h - 1) << 16) | + (intel_crtc->config.pipe_src_w - 1)); + I915_WRITE(DSPPOS(plane), 0); + + i9xx_set_pipeconf(intel_crtc); + + I915_WRITE(DSPCNTR(plane), dspcntr); + POSTING_READ(DSPCNTR(plane)); + + ret = intel_pipe_set_base(crtc, x, y, fb); + + return ret; +} + +static void i9xx_get_pfit_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev))) + return; + + tmp = I915_READ(PFIT_CONTROL); + if (!(tmp & PFIT_ENABLE)) + return; + + /* Check whether the pfit is attached to our pipe. */ + if (INTEL_INFO(dev)->gen < 4) { + if (crtc->pipe != PIPE_B) + return; + } else { + if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT)) + return; + } + + pipe_config->gmch_pfit.control = tmp; + pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS); + if (INTEL_INFO(dev)->gen < 5) + pipe_config->gmch_pfit.lvds_border_bits = + I915_READ(LVDS) & LVDS_BORDER_ENABLE; +} + +static void vlv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = pipe_config->cpu_transcoder; + intel_clock_t clock; + u32 mdiv; + int refclk = 100000; + + mutex_lock(&dev_priv->dpio_lock); + mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); + mutex_unlock(&dev_priv->dpio_lock); + + clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; + clock.m2 = mdiv & DPIO_M2DIV_MASK; + clock.n = (mdiv >> DPIO_N_SHIFT) & 0xf; + clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; + clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; + + vlv_clock(refclk, &clock); + + /* clock.dot is the fast clock */ + pipe_config->port_clock = clock.dot / 5; +} + +static bool i9xx_get_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; + + tmp = I915_READ(PIPECONF(crtc->pipe)); + if (!(tmp & PIPECONF_ENABLE)) + return false; + + if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { + switch (tmp & PIPECONF_BPC_MASK) { + case PIPECONF_6BPC: + pipe_config->pipe_bpp = 18; + break; + case PIPECONF_8BPC: + pipe_config->pipe_bpp = 24; + break; + case PIPECONF_10BPC: + pipe_config->pipe_bpp = 30; + break; + default: + break; + } + } + + if (INTEL_INFO(dev)->gen < 4) + pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE; + + intel_get_pipe_timings(crtc, pipe_config); + + i9xx_get_pfit_config(crtc, pipe_config); + + if (INTEL_INFO(dev)->gen >= 4) { + tmp = I915_READ(DPLL_MD(crtc->pipe)); + pipe_config->pixel_multiplier = + ((tmp & DPLL_MD_UDI_MULTIPLIER_MASK) + >> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1; + pipe_config->dpll_hw_state.dpll_md = tmp; + } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { + tmp = I915_READ(DPLL(crtc->pipe)); + pipe_config->pixel_multiplier = + ((tmp & SDVO_MULTIPLIER_MASK) + >> SDVO_MULTIPLIER_SHIFT_HIRES) + 1; + } else { + /* Note that on i915G/GM the pixel multiplier is in the sdvo + * port and will be fixed up in the encoder->get_config + * function. */ + pipe_config->pixel_multiplier = 1; + } + pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe)); + if (!IS_VALLEYVIEW(dev)) { + pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(crtc->pipe)); + pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(crtc->pipe)); + } else { + /* Mask out read-only status bits. */ + pipe_config->dpll_hw_state.dpll &= ~(DPLL_LOCK_VLV | + DPLL_PORTC_READY_MASK | + DPLL_PORTB_READY_MASK); + } + + if (IS_VALLEYVIEW(dev)) + vlv_crtc_clock_get(crtc, pipe_config); + else + i9xx_crtc_clock_get(crtc, pipe_config); + + return true; +} + +static void ironlake_init_pch_refclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; + u32 val, final; + bool has_lvds = false; + bool has_cpu_edp = false; + bool has_panel = false; + bool has_ck505 = false; + bool can_ssc = false; + + /* We need to take the global config into account */ + list_for_each_entry(encoder, &mode_config->encoder_list, + base.head) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + has_panel = true; + has_lvds = true; + break; + case INTEL_OUTPUT_EDP: + has_panel = true; + if (enc_to_dig_port(&encoder->base)->port == PORT_A) + has_cpu_edp = true; + break; + } + } + + if (HAS_PCH_IBX(dev)) { + has_ck505 = dev_priv->vbt.display_clock_mode; + can_ssc = has_ck505; + } else { + has_ck505 = false; + can_ssc = true; + } + + DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n", + has_panel, has_lvds, has_ck505); + + /* Ironlake: try to setup display ref clock before DPLL + * enabling. This is only under driver's control after + * PCH B stepping, previous chipset stepping should be + * ignoring this setting. + */ + val = I915_READ(PCH_DREF_CONTROL); + + /* As we must carefully and slowly disable/enable each source in turn, + * compute the final state we want first and check if we need to + * make any changes at all. + */ + final = val; + final &= ~DREF_NONSPREAD_SOURCE_MASK; + if (has_ck505) + final |= DREF_NONSPREAD_CK505_ENABLE; + else + final |= DREF_NONSPREAD_SOURCE_ENABLE; + + final &= ~DREF_SSC_SOURCE_MASK; + final &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + final &= ~DREF_SSC1_ENABLE; + + if (has_panel) { + final |= DREF_SSC_SOURCE_ENABLE; + + if (intel_panel_use_ssc(dev_priv) && can_ssc) + final |= DREF_SSC1_ENABLE; + + if (has_cpu_edp) { + if (intel_panel_use_ssc(dev_priv) && can_ssc) + final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; + else + final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; + } else + final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + } else { + final |= DREF_SSC_SOURCE_DISABLE; + final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + } + + if (final == val) + return; + + /* Always enable nonspread source */ + val &= ~DREF_NONSPREAD_SOURCE_MASK; + + if (has_ck505) + val |= DREF_NONSPREAD_CK505_ENABLE; + else + val |= DREF_NONSPREAD_SOURCE_ENABLE; + + if (has_panel) { + val &= ~DREF_SSC_SOURCE_MASK; + val |= DREF_SSC_SOURCE_ENABLE; + + /* SSC must be turned on before enabling the CPU output */ + if (intel_panel_use_ssc(dev_priv) && can_ssc) { + DRM_DEBUG_KMS("Using SSC on panel\n"); + val |= DREF_SSC1_ENABLE; + } else + val &= ~DREF_SSC1_ENABLE; + + /* Get SSC going before enabling the outputs */ + I915_WRITE(PCH_DREF_CONTROL, val); + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + + val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + + /* Enable CPU source on CPU attached eDP */ + if (has_cpu_edp) { + if (intel_panel_use_ssc(dev_priv) && can_ssc) { + DRM_DEBUG_KMS("Using SSC on eDP\n"); + val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; + } + else + val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; + } else + val |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + + I915_WRITE(PCH_DREF_CONTROL, val); + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + } else { + DRM_DEBUG_KMS("Disabling SSC entirely\n"); + + val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + + /* Turn off CPU output */ + val |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + + I915_WRITE(PCH_DREF_CONTROL, val); + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + + /* Turn off the SSC source */ + val &= ~DREF_SSC_SOURCE_MASK; + val |= DREF_SSC_SOURCE_DISABLE; + + /* Turn off SSC1 */ + val &= ~DREF_SSC1_ENABLE; + + I915_WRITE(PCH_DREF_CONTROL, val); + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + } + + BUG_ON(val != final); +} + +static void lpt_reset_fdi_mphy(struct drm_i915_private *dev_priv) +{ + uint32_t tmp; + + tmp = I915_READ(SOUTH_CHICKEN2); + tmp |= FDI_MPHY_IOSFSB_RESET_CTL; + I915_WRITE(SOUTH_CHICKEN2, tmp); + + if (wait_for_atomic_us(I915_READ(SOUTH_CHICKEN2) & + FDI_MPHY_IOSFSB_RESET_STATUS, 100)) + DRM_ERROR("FDI mPHY reset assert timeout\n"); + + tmp = I915_READ(SOUTH_CHICKEN2); + tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL; + I915_WRITE(SOUTH_CHICKEN2, tmp); + + if (wait_for_atomic_us((I915_READ(SOUTH_CHICKEN2) & + FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100)) + DRM_ERROR("FDI mPHY reset de-assert timeout\n"); +} + +/* WaMPhyProgramming:hsw */ +static void lpt_program_fdi_mphy(struct drm_i915_private *dev_priv) +{ + uint32_t tmp; + + tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY); + tmp &= ~(0xFF << 24); + tmp |= (0x12 << 24); + intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY); + tmp |= (1 << 11); + intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY); + tmp |= (1 << 11); + intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY); + tmp |= (1 << 24) | (1 << 21) | (1 << 18); + intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY); + tmp |= (1 << 24) | (1 << 21) | (1 << 18); + intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY); + tmp &= ~(7 << 13); + tmp |= (5 << 13); + intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY); + tmp &= ~(7 << 13); + tmp |= (5 << 13); + intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY); + tmp &= ~0xFF; + tmp |= 0x1C; + intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY); + tmp &= ~0xFF; + tmp |= 0x1C; + intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY); + tmp &= ~(0xFF << 16); + tmp |= (0x1C << 16); + intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY); + tmp &= ~(0xFF << 16); + tmp |= (0x1C << 16); + intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY); + tmp |= (1 << 27); + intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY); + tmp |= (1 << 27); + intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY); + tmp &= ~(0xF << 28); + tmp |= (4 << 28); + intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY); + tmp &= ~(0xF << 28); + tmp |= (4 << 28); + intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY); +} + +/* Implements 3 different sequences from BSpec chapter "Display iCLK + * Programming" based on the parameters passed: + * - Sequence to enable CLKOUT_DP + * - Sequence to enable CLKOUT_DP without spread + * - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O + */ +static void lpt_enable_clkout_dp(struct drm_device *dev, bool with_spread, + bool with_fdi) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t reg, tmp; + + if (WARN(with_fdi && !with_spread, "FDI requires downspread\n")) + with_spread = true; + if (WARN(dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE && + with_fdi, "LP PCH doesn't have FDI\n")) + with_fdi = false; + + mutex_lock(&dev_priv->dpio_lock); + + tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK); + tmp &= ~SBI_SSCCTL_DISABLE; + tmp |= SBI_SSCCTL_PATHALT; + intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK); + + udelay(24); + + if (with_spread) { + tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK); + tmp &= ~SBI_SSCCTL_PATHALT; + intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK); + + if (with_fdi) { + lpt_reset_fdi_mphy(dev_priv); + lpt_program_fdi_mphy(dev_priv); + } + } + + reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ? + SBI_GEN0 : SBI_DBUFF0; + tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK); + tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE; + intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK); + + mutex_unlock(&dev_priv->dpio_lock); +} + +/* Sequence to disable CLKOUT_DP */ +static void lpt_disable_clkout_dp(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t reg, tmp; + + mutex_lock(&dev_priv->dpio_lock); + + reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ? + SBI_GEN0 : SBI_DBUFF0; + tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK); + tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE; + intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK); + + tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK); + if (!(tmp & SBI_SSCCTL_DISABLE)) { + if (!(tmp & SBI_SSCCTL_PATHALT)) { + tmp |= SBI_SSCCTL_PATHALT; + intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK); + udelay(32); + } + tmp |= SBI_SSCCTL_DISABLE; + intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK); + } + + mutex_unlock(&dev_priv->dpio_lock); +} + +static void lpt_init_pch_refclk(struct drm_device *dev) +{ + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; + bool has_vga = false; + + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { + switch (encoder->type) { + case INTEL_OUTPUT_ANALOG: + has_vga = true; + break; + } + } + + if (has_vga) + lpt_enable_clkout_dp(dev, true, true); + else + lpt_disable_clkout_dp(dev); +} + +/* + * Initialize reference clocks when the driver loads + */ +void intel_init_pch_refclk(struct drm_device *dev) +{ + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + ironlake_init_pch_refclk(dev); + else if (HAS_PCH_LPT(dev)) + lpt_init_pch_refclk(dev); +} + +static int ironlake_get_refclk(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; + int num_connectors = 0; + bool is_lvds = false; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + } + num_connectors++; + } + + if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", + dev_priv->vbt.lvds_ssc_freq); + return dev_priv->vbt.lvds_ssc_freq; + } + + return 120000; +} + +static void ironlake_set_pipeconf(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + uint32_t val; + + val = 0; + + switch (intel_crtc->config.pipe_bpp) { + case 18: + val |= PIPECONF_6BPC; + break; + case 24: + val |= PIPECONF_8BPC; + break; + case 30: + val |= PIPECONF_10BPC; + break; + case 36: + val |= PIPECONF_12BPC; + break; + default: + /* Case prevented by intel_choose_pipe_bpp_dither. */ + BUG(); + } + + if (intel_crtc->config.dither) + val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); + + if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) + val |= PIPECONF_INTERLACED_ILK; + else + val |= PIPECONF_PROGRESSIVE; + + if (intel_crtc->config.limited_color_range) + val |= PIPECONF_COLOR_RANGE_SELECT; + + I915_WRITE(PIPECONF(pipe), val); + POSTING_READ(PIPECONF(pipe)); +} + +/* + * Set up the pipe CSC unit. + * + * Currently only full range RGB to limited range RGB conversion + * is supported, but eventually this should handle various + * RGB<->YCbCr scenarios as well. + */ +static void intel_set_pipe_csc(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + uint16_t coeff = 0x7800; /* 1.0 */ + + /* + * TODO: Check what kind of values actually come out of the pipe + * with these coeff/postoff values and adjust to get the best + * accuracy. Perhaps we even need to take the bpc value into + * consideration. + */ + + if (intel_crtc->config.limited_color_range) + coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */ + + /* + * GY/GU and RY/RU should be the other way around according + * to BSpec, but reality doesn't agree. Just set them up in + * a way that results in the correct picture. + */ + I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16); + I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff); + I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0); + I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16); + + I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0); + + if (INTEL_INFO(dev)->gen > 6) { + uint16_t postoff = 0; + + if (intel_crtc->config.limited_color_range) + postoff = (16 * (1 << 12) / 255) & 0x1fff; + + I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff); + + I915_WRITE(PIPE_CSC_MODE(pipe), 0); + } else { + uint32_t mode = CSC_MODE_YUV_TO_RGB; + + if (intel_crtc->config.limited_color_range) + mode |= CSC_BLACK_SCREEN_OFFSET; + + I915_WRITE(PIPE_CSC_MODE(pipe), mode); + } +} + +static void haswell_set_pipeconf(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + uint32_t val; + + val = 0; + + if (IS_HASWELL(dev) && intel_crtc->config.dither) + val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); + + if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) + val |= PIPECONF_INTERLACED_ILK; + else + val |= PIPECONF_PROGRESSIVE; + + I915_WRITE(PIPECONF(cpu_transcoder), val); + POSTING_READ(PIPECONF(cpu_transcoder)); + + I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT); + POSTING_READ(GAMMA_MODE(intel_crtc->pipe)); + + if (IS_BROADWELL(dev)) { + val = 0; + + switch (intel_crtc->config.pipe_bpp) { + case 18: + val |= PIPEMISC_DITHER_6_BPC; + break; + case 24: + val |= PIPEMISC_DITHER_8_BPC; + break; + case 30: + val |= PIPEMISC_DITHER_10_BPC; + break; + case 36: + val |= PIPEMISC_DITHER_12_BPC; + break; + default: + /* Case prevented by pipe_config_set_bpp. */ + BUG(); + } + + if (intel_crtc->config.dither) + val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP; + + I915_WRITE(PIPEMISC(pipe), val); + } +} + +static bool ironlake_compute_clocks(struct drm_crtc *crtc, + intel_clock_t *clock, + bool *has_reduced_clock, + intel_clock_t *reduced_clock) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + int refclk; + const intel_limit_t *limit; + bool ret, is_lvds = false; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + switch (intel_encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + } + } + + refclk = ironlake_get_refclk(crtc); + + /* + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE. The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + */ + limit = intel_limit(crtc, refclk); + ret = dev_priv->display.find_dpll(limit, crtc, + to_intel_crtc(crtc)->config.port_clock, + refclk, NULL, clock); + if (!ret) + return false; + + if (is_lvds && dev_priv->lvds_downclock_avail) { + /* + * Ensure we match the reduced clock's P to the target clock. + * If the clocks don't match, we can't switch the display clock + * by using the FP0/FP1. In such case we will disable the LVDS + * downclock feature. + */ + *has_reduced_clock = + dev_priv->display.find_dpll(limit, crtc, + dev_priv->lvds_downclock, + refclk, clock, + reduced_clock); + } + + return true; +} + +int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp) +{ + /* + * Account for spread spectrum to avoid + * oversubscribing the link. Max center spread + * is 2.5%; use 5% for safety's sake. + */ + u32 bps = target_clock * bpp * 21 / 20; + return bps / (link_bw * 8) + 1; +} + +static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor) +{ + return i9xx_dpll_compute_m(dpll) < factor * dpll->n; +} + +static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, + u32 *fp, + intel_clock_t *reduced_clock, u32 *fp2) +{ + struct drm_crtc *crtc = &intel_crtc->base; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + uint32_t dpll; + int factor, num_connectors = 0; + bool is_lvds = false, is_sdvo = false; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + switch (intel_encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + case INTEL_OUTPUT_HDMI: + is_sdvo = true; + break; + } + + num_connectors++; + } + + /* Enable autotuning of the PLL clock (if permissible) */ + factor = 21; + if (is_lvds) { + if ((intel_panel_use_ssc(dev_priv) && + dev_priv->vbt.lvds_ssc_freq == 100000) || + (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) + factor = 25; + } else if (intel_crtc->config.sdvo_tv_clock) + factor = 20; + + if (ironlake_needs_fb_cb_tune(&intel_crtc->config.dpll, factor)) + *fp |= FP_CB_TUNE; + + if (fp2 && (reduced_clock->m < factor * reduced_clock->n)) + *fp2 |= FP_CB_TUNE; + + dpll = 0; + + if (is_lvds) + dpll |= DPLLB_MODE_LVDS; + else + dpll |= DPLLB_MODE_DAC_SERIAL; + + dpll |= (intel_crtc->config.pixel_multiplier - 1) + << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; + + if (is_sdvo) + dpll |= DPLL_SDVO_HIGH_SPEED; + if (intel_crtc->config.has_dp_encoder) + dpll |= DPLL_SDVO_HIGH_SPEED; + + /* compute bitmask from p1 value */ + dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + /* also FPA1 */ + dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + + switch (intel_crtc->config.dpll.p2) { + case 5: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; + break; + case 7: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; + break; + case 10: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; + break; + case 14: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; + break; + } + + if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; + else + dpll |= PLL_REF_INPUT_DREFCLK; + + return dpll | DPLL_VCO_ENABLE; +} + +static int ironlake_crtc_mode_set(struct drm_crtc *crtc, + int x, int y, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int num_connectors = 0; + intel_clock_t clock, reduced_clock; + u32 dpll = 0, fp = 0, fp2 = 0; + bool ok, has_reduced_clock = false; + bool is_lvds = false; + struct intel_encoder *encoder; + struct intel_shared_dpll *pll; + int ret; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + } + + num_connectors++; + } + + WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), + "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); + + ok = ironlake_compute_clocks(crtc, &clock, + &has_reduced_clock, &reduced_clock); + if (!ok && !intel_crtc->config.clock_set) { + DRM_ERROR("Couldn't find PLL settings for mode!\n"); + return -EINVAL; + } + /* Compat-code for transition, will disappear. */ + if (!intel_crtc->config.clock_set) { + intel_crtc->config.dpll.n = clock.n; + intel_crtc->config.dpll.m1 = clock.m1; + intel_crtc->config.dpll.m2 = clock.m2; + intel_crtc->config.dpll.p1 = clock.p1; + intel_crtc->config.dpll.p2 = clock.p2; + } + + /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ + if (intel_crtc->config.has_pch_encoder) { + fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll); + if (has_reduced_clock) + fp2 = i9xx_dpll_compute_fp(&reduced_clock); + + dpll = ironlake_compute_dpll(intel_crtc, + &fp, &reduced_clock, + has_reduced_clock ? &fp2 : NULL); + + intel_crtc->config.dpll_hw_state.dpll = dpll; + intel_crtc->config.dpll_hw_state.fp0 = fp; + if (has_reduced_clock) + intel_crtc->config.dpll_hw_state.fp1 = fp2; + else + intel_crtc->config.dpll_hw_state.fp1 = fp; + + pll = intel_get_shared_dpll(intel_crtc); + if (pll == NULL) { + DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", + pipe_name(pipe)); + return -EINVAL; + } + } else + intel_put_shared_dpll(intel_crtc); + + if (intel_crtc->config.has_dp_encoder) + intel_dp_set_m_n(intel_crtc); + + if (is_lvds && has_reduced_clock && i915_powersave) + intel_crtc->lowfreq_avail = true; + else + intel_crtc->lowfreq_avail = false; + + intel_set_pipe_timings(intel_crtc); + + if (intel_crtc->config.has_pch_encoder) { + intel_cpu_transcoder_set_m_n(intel_crtc, + &intel_crtc->config.fdi_m_n); + } + + ironlake_set_pipeconf(crtc); + + /* Set up the display plane register */ + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); + POSTING_READ(DSPCNTR(plane)); + + ret = intel_pipe_set_base(crtc, x, y, fb); + + return ret; +} + +static void intel_pch_transcoder_get_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = crtc->pipe; + + m_n->link_m = I915_READ(PCH_TRANS_LINK_M1(pipe)); + m_n->link_n = I915_READ(PCH_TRANS_LINK_N1(pipe)); + m_n->gmch_m = I915_READ(PCH_TRANS_DATA_M1(pipe)) + & ~TU_SIZE_MASK; + m_n->gmch_n = I915_READ(PCH_TRANS_DATA_N1(pipe)); + m_n->tu = ((I915_READ(PCH_TRANS_DATA_M1(pipe)) + & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; +} + +static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc, + enum transcoder transcoder, + struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = crtc->pipe; + + if (INTEL_INFO(dev)->gen >= 5) { + m_n->link_m = I915_READ(PIPE_LINK_M1(transcoder)); + m_n->link_n = I915_READ(PIPE_LINK_N1(transcoder)); + m_n->gmch_m = I915_READ(PIPE_DATA_M1(transcoder)) + & ~TU_SIZE_MASK; + m_n->gmch_n = I915_READ(PIPE_DATA_N1(transcoder)); + m_n->tu = ((I915_READ(PIPE_DATA_M1(transcoder)) + & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; + } else { + m_n->link_m = I915_READ(PIPE_LINK_M_G4X(pipe)); + m_n->link_n = I915_READ(PIPE_LINK_N_G4X(pipe)); + m_n->gmch_m = I915_READ(PIPE_DATA_M_G4X(pipe)) + & ~TU_SIZE_MASK; + m_n->gmch_n = I915_READ(PIPE_DATA_N_G4X(pipe)); + m_n->tu = ((I915_READ(PIPE_DATA_M_G4X(pipe)) + & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; + } +} + +void intel_dp_get_m_n(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + if (crtc->config.has_pch_encoder) + intel_pch_transcoder_get_m_n(crtc, &pipe_config->dp_m_n); + else + intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder, + &pipe_config->dp_m_n); +} + +static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder, + &pipe_config->fdi_m_n); +} + +static void ironlake_get_pfit_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(PF_CTL(crtc->pipe)); + + if (tmp & PF_ENABLE) { + pipe_config->pch_pfit.enabled = true; + pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe)); + pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe)); + + /* We currently do not free assignements of panel fitters on + * ivb/hsw (since we don't use the higher upscaling modes which + * differentiates them) so just WARN about this case for now. */ + if (IS_GEN7(dev)) { + WARN_ON((tmp & PF_PIPE_SEL_MASK_IVB) != + PF_PIPE_SEL_IVB(crtc->pipe)); + } + } +} + +static bool ironlake_get_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; + + tmp = I915_READ(PIPECONF(crtc->pipe)); + if (!(tmp & PIPECONF_ENABLE)) + return false; + + switch (tmp & PIPECONF_BPC_MASK) { + case PIPECONF_6BPC: + pipe_config->pipe_bpp = 18; + break; + case PIPECONF_8BPC: + pipe_config->pipe_bpp = 24; + break; + case PIPECONF_10BPC: + pipe_config->pipe_bpp = 30; + break; + case PIPECONF_12BPC: + pipe_config->pipe_bpp = 36; + break; + default: + break; + } + + if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) { + struct intel_shared_dpll *pll; + + pipe_config->has_pch_encoder = true; + + tmp = I915_READ(FDI_RX_CTL(crtc->pipe)); + pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >> + FDI_DP_PORT_WIDTH_SHIFT) + 1; + + ironlake_get_fdi_m_n_config(crtc, pipe_config); + + if (HAS_PCH_IBX(dev_priv->dev)) { + pipe_config->shared_dpll = + (enum intel_dpll_id) crtc->pipe; + } else { + tmp = I915_READ(PCH_DPLL_SEL); + if (tmp & TRANS_DPLLB_SEL(crtc->pipe)) + pipe_config->shared_dpll = DPLL_ID_PCH_PLL_B; + else + pipe_config->shared_dpll = DPLL_ID_PCH_PLL_A; + } + + pll = &dev_priv->shared_dplls[pipe_config->shared_dpll]; + + WARN_ON(!pll->get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state)); + + tmp = pipe_config->dpll_hw_state.dpll; + pipe_config->pixel_multiplier = + ((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK) + >> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1; + + ironlake_pch_clock_get(crtc, pipe_config); + } else { + pipe_config->pixel_multiplier = 1; + } + + intel_get_pipe_timings(crtc, pipe_config); + + ironlake_get_pfit_config(crtc, pipe_config); + + return true; +} + +static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + struct intel_crtc *crtc; + unsigned long irqflags; + uint32_t val; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) + WARN(crtc->active, "CRTC for pipe %c enabled\n", + pipe_name(crtc->pipe)); + + WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); + WARN(plls->spll_refcount, "SPLL enabled\n"); + WARN(plls->wrpll1_refcount, "WRPLL1 enabled\n"); + WARN(plls->wrpll2_refcount, "WRPLL2 enabled\n"); + WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n"); + WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE, + "CPU PWM1 enabled\n"); + WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE, + "CPU PWM2 enabled\n"); + WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE, + "PCH PWM1 enabled\n"); + WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, + "Utility pin enabled\n"); + WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n"); + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + val = I915_READ(DEIMR); + WARN((val | DE_PCH_EVENT_IVB) != 0xffffffff, + "Unexpected DEIMR bits enabled: 0x%x\n", val); + val = I915_READ(SDEIMR); + WARN((val | SDE_HOTPLUG_MASK_CPT) != 0xffffffff, + "Unexpected SDEIMR bits enabled: 0x%x\n", val); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +/* + * This function implements pieces of two sequences from BSpec: + * - Sequence for display software to disable LCPLL + * - Sequence for display software to allow package C8+ + * The steps implemented here are just the steps that actually touch the LCPLL + * register. Callers should take care of disabling all the display engine + * functions, doing the mode unset, fixing interrupts, etc. + */ +static void hsw_disable_lcpll(struct drm_i915_private *dev_priv, + bool switch_to_fclk, bool allow_power_down) +{ + uint32_t val; + + assert_can_disable_lcpll(dev_priv); + + val = I915_READ(LCPLL_CTL); + + if (switch_to_fclk) { + val |= LCPLL_CD_SOURCE_FCLK; + I915_WRITE(LCPLL_CTL, val); + + if (wait_for_atomic_us(I915_READ(LCPLL_CTL) & + LCPLL_CD_SOURCE_FCLK_DONE, 1)) + DRM_ERROR("Switching to FCLK failed\n"); + + val = I915_READ(LCPLL_CTL); + } + + val |= LCPLL_PLL_DISABLE; + I915_WRITE(LCPLL_CTL, val); + POSTING_READ(LCPLL_CTL); + + if (wait_for((I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK) == 0, 1)) + DRM_ERROR("LCPLL still locked\n"); + + val = I915_READ(D_COMP); + val |= D_COMP_COMP_DISABLE; + mutex_lock(&dev_priv->rps.hw_lock); + if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val)) + DRM_ERROR("Failed to disable D_COMP\n"); + mutex_unlock(&dev_priv->rps.hw_lock); + POSTING_READ(D_COMP); + ndelay(100); + + if (wait_for((I915_READ(D_COMP) & D_COMP_RCOMP_IN_PROGRESS) == 0, 1)) + DRM_ERROR("D_COMP RCOMP still in progress\n"); + + if (allow_power_down) { + val = I915_READ(LCPLL_CTL); + val |= LCPLL_POWER_DOWN_ALLOW; + I915_WRITE(LCPLL_CTL, val); + POSTING_READ(LCPLL_CTL); + } +} + +/* + * Fully restores LCPLL, disallowing power down and switching back to LCPLL + * source. + */ +static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) +{ + uint32_t val; + + val = I915_READ(LCPLL_CTL); + + if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK | + LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK) + return; + + /* Make sure we're not on PC8 state before disabling PC8, otherwise + * we'll hang the machine! */ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); + + if (val & LCPLL_POWER_DOWN_ALLOW) { + val &= ~LCPLL_POWER_DOWN_ALLOW; + I915_WRITE(LCPLL_CTL, val); + POSTING_READ(LCPLL_CTL); + } + + val = I915_READ(D_COMP); + val |= D_COMP_COMP_FORCE; + val &= ~D_COMP_COMP_DISABLE; + mutex_lock(&dev_priv->rps.hw_lock); + if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP, val)) + DRM_ERROR("Failed to enable D_COMP\n"); + mutex_unlock(&dev_priv->rps.hw_lock); + POSTING_READ(D_COMP); + + val = I915_READ(LCPLL_CTL); + val &= ~LCPLL_PLL_DISABLE; + I915_WRITE(LCPLL_CTL, val); + + if (wait_for(I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK, 5)) + DRM_ERROR("LCPLL not locked yet\n"); + + if (val & LCPLL_CD_SOURCE_FCLK) { + val = I915_READ(LCPLL_CTL); + val &= ~LCPLL_CD_SOURCE_FCLK; + I915_WRITE(LCPLL_CTL, val); + + if (wait_for_atomic_us((I915_READ(LCPLL_CTL) & + LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) + DRM_ERROR("Switching back to LCPLL failed\n"); + } + + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); +} + +void hsw_enable_pc8_work(struct work_struct *__work) +{ + struct drm_i915_private *dev_priv = + container_of(to_delayed_work(__work), struct drm_i915_private, + pc8.enable_work); + struct drm_device *dev = dev_priv->dev; + uint32_t val; + + WARN_ON(!HAS_PC8(dev)); + + if (dev_priv->pc8.enabled) + return; + + DRM_DEBUG_KMS("Enabling package C8+\n"); + + dev_priv->pc8.enabled = true; + + if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { + val = I915_READ(SOUTH_DSPCLK_GATE_D); + val &= ~PCH_LP_PARTITION_LEVEL_DISABLE; + I915_WRITE(SOUTH_DSPCLK_GATE_D, val); + } + + lpt_disable_clkout_dp(dev); + hsw_pc8_disable_interrupts(dev); + hsw_disable_lcpll(dev_priv, true, true); + + intel_runtime_pm_put(dev_priv); +} + +static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv) +{ + WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock)); + WARN(dev_priv->pc8.disable_count < 1, + "pc8.disable_count: %d\n", dev_priv->pc8.disable_count); + + dev_priv->pc8.disable_count--; + if (dev_priv->pc8.disable_count != 0) + return; + + schedule_delayed_work(&dev_priv->pc8.enable_work, + msecs_to_jiffies(i915_pc8_timeout)); +} + +static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + uint32_t val; + + WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock)); + WARN(dev_priv->pc8.disable_count < 0, + "pc8.disable_count: %d\n", dev_priv->pc8.disable_count); + + dev_priv->pc8.disable_count++; + if (dev_priv->pc8.disable_count != 1) + return; + + WARN_ON(!HAS_PC8(dev)); + + cancel_delayed_work_sync(&dev_priv->pc8.enable_work); + if (!dev_priv->pc8.enabled) + return; + + DRM_DEBUG_KMS("Disabling package C8+\n"); + + intel_runtime_pm_get(dev_priv); + + hsw_restore_lcpll(dev_priv); + hsw_pc8_restore_interrupts(dev); + lpt_init_pch_refclk(dev); + + if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { + val = I915_READ(SOUTH_DSPCLK_GATE_D); + val |= PCH_LP_PARTITION_LEVEL_DISABLE; + I915_WRITE(SOUTH_DSPCLK_GATE_D, val); + } + + intel_prepare_ddi(dev); + i915_gem_init_swizzling(dev); + mutex_lock(&dev_priv->rps.hw_lock); + gen6_update_ring_freq(dev); + mutex_unlock(&dev_priv->rps.hw_lock); + dev_priv->pc8.enabled = false; +} + +void hsw_enable_package_c8(struct drm_i915_private *dev_priv) +{ + if (!HAS_PC8(dev_priv->dev)) + return; + + mutex_lock(&dev_priv->pc8.lock); + __hsw_enable_package_c8(dev_priv); + mutex_unlock(&dev_priv->pc8.lock); +} + +void hsw_disable_package_c8(struct drm_i915_private *dev_priv) +{ + if (!HAS_PC8(dev_priv->dev)) + return; + + mutex_lock(&dev_priv->pc8.lock); + __hsw_disable_package_c8(dev_priv); + mutex_unlock(&dev_priv->pc8.lock); +} + +static bool hsw_can_enable_package_c8(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *crtc; + uint32_t val; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) + if (crtc->base.enabled) + return false; + + /* This case is still possible since we have the i915.disable_power_well + * parameter and also the KVMr or something else might be requesting the + * power well. */ + val = I915_READ(HSW_PWR_WELL_DRIVER); + if (val != 0) { + DRM_DEBUG_KMS("Not enabling PC8: power well on\n"); + return false; + } + + return true; +} + +/* Since we're called from modeset_global_resources there's no way to + * symmetrically increase and decrease the refcount, so we use + * dev_priv->pc8.requirements_met to track whether we already have the refcount + * or not. + */ +static void hsw_update_package_c8(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + bool allow; + + if (!HAS_PC8(dev_priv->dev)) + return; + + if (!i915_enable_pc8) + return; + + mutex_lock(&dev_priv->pc8.lock); + + allow = hsw_can_enable_package_c8(dev_priv); + + if (allow == dev_priv->pc8.requirements_met) + goto done; + + dev_priv->pc8.requirements_met = allow; + + if (allow) + __hsw_enable_package_c8(dev_priv); + else + __hsw_disable_package_c8(dev_priv); + +done: + mutex_unlock(&dev_priv->pc8.lock); +} + +static void hsw_package_c8_gpu_idle(struct drm_i915_private *dev_priv) +{ + if (!HAS_PC8(dev_priv->dev)) + return; + + mutex_lock(&dev_priv->pc8.lock); + if (!dev_priv->pc8.gpu_idle) { + dev_priv->pc8.gpu_idle = true; + __hsw_enable_package_c8(dev_priv); + } + mutex_unlock(&dev_priv->pc8.lock); +} + +static void hsw_package_c8_gpu_busy(struct drm_i915_private *dev_priv) +{ + if (!HAS_PC8(dev_priv->dev)) + return; + + mutex_lock(&dev_priv->pc8.lock); + if (dev_priv->pc8.gpu_idle) { + dev_priv->pc8.gpu_idle = false; + __hsw_disable_package_c8(dev_priv); + } + mutex_unlock(&dev_priv->pc8.lock); +} + +#define for_each_power_domain(domain, mask) \ + for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ + if ((1 << (domain)) & (mask)) + +static unsigned long get_pipe_power_domains(struct drm_device *dev, + enum pipe pipe, bool pfit_enabled) +{ + unsigned long mask; + enum transcoder transcoder; + + transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe); + + mask = BIT(POWER_DOMAIN_PIPE(pipe)); + mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder)); + if (pfit_enabled) + mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe)); + + return mask; +} + +void intel_display_set_init_power(struct drm_device *dev, bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->power_domains.init_power_on == enable) + return; + + if (enable) + intel_display_power_get(dev, POWER_DOMAIN_INIT); + else + intel_display_power_put(dev, POWER_DOMAIN_INIT); + + dev_priv->power_domains.init_power_on = enable; +} + +static void modeset_update_power_wells(struct drm_device *dev) +{ + unsigned long pipe_domains[I915_MAX_PIPES] = { 0, }; + struct intel_crtc *crtc; + + /* + * First get all needed power domains, then put all unneeded, to avoid + * any unnecessary toggling of the power wells. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + enum intel_display_power_domain domain; + + if (!crtc->base.enabled) + continue; + + pipe_domains[crtc->pipe] = get_pipe_power_domains(dev, + crtc->pipe, + crtc->config.pch_pfit.enabled); + + for_each_power_domain(domain, pipe_domains[crtc->pipe]) + intel_display_power_get(dev, domain); + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + enum intel_display_power_domain domain; + + for_each_power_domain(domain, crtc->enabled_power_domains) + intel_display_power_put(dev, domain); + + crtc->enabled_power_domains = pipe_domains[crtc->pipe]; + } + + intel_display_set_init_power(dev, false); +} + +static void haswell_modeset_global_resources(struct drm_device *dev) +{ + modeset_update_power_wells(dev); + hsw_update_package_c8(dev); +} + +static int haswell_crtc_mode_set(struct drm_crtc *crtc, + int x, int y, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane; + int ret; + + if (!intel_ddi_pll_select(intel_crtc)) + return -EINVAL; + intel_ddi_pll_enable(intel_crtc); + + if (intel_crtc->config.has_dp_encoder) + intel_dp_set_m_n(intel_crtc); + + intel_crtc->lowfreq_avail = false; + + intel_set_pipe_timings(intel_crtc); + + if (intel_crtc->config.has_pch_encoder) { + intel_cpu_transcoder_set_m_n(intel_crtc, + &intel_crtc->config.fdi_m_n); + } + + haswell_set_pipeconf(crtc); + + intel_set_pipe_csc(crtc); + + /* Set up the display plane register */ + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE); + POSTING_READ(DSPCNTR(plane)); + + ret = intel_pipe_set_base(crtc, x, y, fb); + + return ret; +} + +static bool haswell_get_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum intel_display_power_domain pfit_domain; + uint32_t tmp; + + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; + + tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); + if (tmp & TRANS_DDI_FUNC_ENABLE) { + enum pipe trans_edp_pipe; + switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { + default: + WARN(1, "unknown pipe linked to edp transcoder\n"); + case TRANS_DDI_EDP_INPUT_A_ONOFF: + case TRANS_DDI_EDP_INPUT_A_ON: + trans_edp_pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + trans_edp_pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + trans_edp_pipe = PIPE_C; + break; + } + + if (trans_edp_pipe == crtc->pipe) + pipe_config->cpu_transcoder = TRANSCODER_EDP; + } + + if (!intel_display_power_enabled(dev, + POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder))) + return false; + + tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder)); + if (!(tmp & PIPECONF_ENABLE)) + return false; + + /* + * Haswell has only FDI/PCH transcoder A. It is which is connected to + * DDI E. So just check whether this pipe is wired to DDI E and whether + * the PCH transcoder is on. + */ + tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe_config->cpu_transcoder)); + if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) && + I915_READ(LPT_TRANSCONF) & TRANS_ENABLE) { + pipe_config->has_pch_encoder = true; + + tmp = I915_READ(FDI_RX_CTL(PIPE_A)); + pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >> + FDI_DP_PORT_WIDTH_SHIFT) + 1; + + ironlake_get_fdi_m_n_config(crtc, pipe_config); + } + + intel_get_pipe_timings(crtc, pipe_config); + + pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe); + if (intel_display_power_enabled(dev, pfit_domain)) + ironlake_get_pfit_config(crtc, pipe_config); + + if (IS_HASWELL(dev)) + pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && + (I915_READ(IPS_CTL) & IPS_ENABLE); + + pipe_config->pixel_multiplier = 1; + + return true; +} + +static int intel_crtc_mode_set(struct drm_crtc *crtc, + int x, int y, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; + int pipe = intel_crtc->pipe; + int ret; + + drm_vblank_pre_modeset(dev, pipe); + + ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb); + + drm_vblank_post_modeset(dev, pipe); + + if (ret != 0) + return ret; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base), + mode->base.id, mode->name); + encoder->mode_set(encoder); + } + + return 0; +} + +static struct { + int clock; + u32 config; +} hdmi_audio_clock[] = { + { DIV_ROUND_UP(25200 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 }, + { 25200, AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 }, /* default per bspec */ + { 27000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 }, + { 27000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 }, + { 54000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 }, + { 54000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 }, + { DIV_ROUND_UP(74250 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 }, + { 74250, AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 }, + { DIV_ROUND_UP(148500 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 }, + { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 }, +}; + +/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ +static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) { + if (mode->clock == hdmi_audio_clock[i].clock) + break; + } + + if (i == ARRAY_SIZE(hdmi_audio_clock)) { + DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", mode->clock); + i = 1; + } + + DRM_DEBUG_KMS("Configuring HDMI audio for pixel clock %d (0x%08x)\n", + hdmi_audio_clock[i].clock, + hdmi_audio_clock[i].config); + + return hdmi_audio_clock[i].config; +} + +static bool intel_eld_uptodate(struct drm_connector *connector, + int reg_eldv, uint32_t bits_eldv, + int reg_elda, uint32_t bits_elda, + int reg_edid) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + uint32_t i; + + i = I915_READ(reg_eldv); + i &= bits_eldv; + + if (!eld[0]) + return !i; + + if (!i) + return false; + + i = I915_READ(reg_elda); + i &= ~bits_elda; + I915_WRITE(reg_elda, i); + + for (i = 0; i < eld[2]; i++) + if (I915_READ(reg_edid) != *((uint32_t *)eld + i)) + return false; + + return true; +} + +static void g4x_write_eld(struct drm_connector *connector, + struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + uint32_t eldv; + uint32_t len; + uint32_t i; + + i = I915_READ(G4X_AUD_VID_DID); + + if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL) + eldv = G4X_ELDV_DEVCL_DEVBLC; + else + eldv = G4X_ELDV_DEVCTG; + + if (intel_eld_uptodate(connector, + G4X_AUD_CNTL_ST, eldv, + G4X_AUD_CNTL_ST, G4X_ELD_ADDR, + G4X_HDMIW_HDMIEDID)) + return; + + i = I915_READ(G4X_AUD_CNTL_ST); + i &= ~(eldv | G4X_ELD_ADDR); + len = (i >> 9) & 0x1f; /* ELD buffer size */ + I915_WRITE(G4X_AUD_CNTL_ST, i); + + if (!eld[0]) + return; + + len = min_t(uint8_t, eld[2], len); + DRM_DEBUG_DRIVER("ELD size %d\n", len); + for (i = 0; i < len; i++) + I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i)); + + i = I915_READ(G4X_AUD_CNTL_ST); + i |= eldv; + I915_WRITE(G4X_AUD_CNTL_ST, i); +} + +static void haswell_write_eld(struct drm_connector *connector, + struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t eldv; + uint32_t i; + int len; + int pipe = to_intel_crtc(crtc)->pipe; + int tmp; + + int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe); + int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe); + int aud_config = HSW_AUD_CFG(pipe); + int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD; + + + DRM_DEBUG_DRIVER("HDMI: Haswell Audio initialize....\n"); + + /* Audio output enable */ + DRM_DEBUG_DRIVER("HDMI audio: enable codec\n"); + tmp = I915_READ(aud_cntrl_st2); + tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4)); + I915_WRITE(aud_cntrl_st2, tmp); + + /* Wait for 1 vertical blank */ + intel_wait_for_vblank(dev, pipe); + + /* Set ELD valid state */ + tmp = I915_READ(aud_cntrl_st2); + DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp); + tmp |= (AUDIO_ELD_VALID_A << (pipe * 4)); + I915_WRITE(aud_cntrl_st2, tmp); + tmp = I915_READ(aud_cntrl_st2); + DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp); + + /* Enable HDMI mode */ + tmp = I915_READ(aud_config); + DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp); + /* clear N_programing_enable and N_value_index */ + tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE); + I915_WRITE(aud_config, tmp); + + DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); + + eldv = AUDIO_ELD_VALID_A << (pipe * 4); + intel_crtc->eld_vld = true; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { + DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); + eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ + I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ + } else { + I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); + } + + if (intel_eld_uptodate(connector, + aud_cntrl_st2, eldv, + aud_cntl_st, IBX_ELD_ADDRESS, + hdmiw_hdmiedid)) + return; + + i = I915_READ(aud_cntrl_st2); + i &= ~eldv; + I915_WRITE(aud_cntrl_st2, i); + + if (!eld[0]) + return; + + i = I915_READ(aud_cntl_st); + i &= ~IBX_ELD_ADDRESS; + I915_WRITE(aud_cntl_st, i); + i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ + DRM_DEBUG_DRIVER("port num:%d\n", i); + + len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ + DRM_DEBUG_DRIVER("ELD size %d\n", len); + for (i = 0; i < len; i++) + I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); + + i = I915_READ(aud_cntrl_st2); + i |= eldv; + I915_WRITE(aud_cntrl_st2, i); + +} + +static void ironlake_write_eld(struct drm_connector *connector, + struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + uint32_t eldv; + uint32_t i; + int len; + int hdmiw_hdmiedid; + int aud_config; + int aud_cntl_st; + int aud_cntrl_st2; + int pipe = to_intel_crtc(crtc)->pipe; + + if (HAS_PCH_IBX(connector->dev)) { + hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); + aud_config = IBX_AUD_CFG(pipe); + aud_cntl_st = IBX_AUD_CNTL_ST(pipe); + aud_cntrl_st2 = IBX_AUD_CNTL_ST2; + } else if (IS_VALLEYVIEW(connector->dev)) { + hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe); + aud_config = VLV_AUD_CFG(pipe); + aud_cntl_st = VLV_AUD_CNTL_ST(pipe); + aud_cntrl_st2 = VLV_AUD_CNTL_ST2; + } else { + hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe); + aud_config = CPT_AUD_CFG(pipe); + aud_cntl_st = CPT_AUD_CNTL_ST(pipe); + aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; + } + + DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); + + if (IS_VALLEYVIEW(connector->dev)) { + struct intel_encoder *intel_encoder; + struct intel_digital_port *intel_dig_port; + + intel_encoder = intel_attached_encoder(connector); + intel_dig_port = enc_to_dig_port(&intel_encoder->base); + i = intel_dig_port->port; + } else { + i = I915_READ(aud_cntl_st); + i = (i >> 29) & DIP_PORT_SEL_MASK; + /* DIP_Port_Select, 0x1 = PortB */ + } + + if (!i) { + DRM_DEBUG_DRIVER("Audio directed to unknown port\n"); + /* operate blindly on all ports */ + eldv = IBX_ELD_VALIDB; + eldv |= IBX_ELD_VALIDB << 4; + eldv |= IBX_ELD_VALIDB << 8; + } else { + DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(i)); + eldv = IBX_ELD_VALIDB << ((i - 1) * 4); + } + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { + DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); + eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ + I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ + } else { + I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); + } + + if (intel_eld_uptodate(connector, + aud_cntrl_st2, eldv, + aud_cntl_st, IBX_ELD_ADDRESS, + hdmiw_hdmiedid)) + return; + + i = I915_READ(aud_cntrl_st2); + i &= ~eldv; + I915_WRITE(aud_cntrl_st2, i); + + if (!eld[0]) + return; + + i = I915_READ(aud_cntl_st); + i &= ~IBX_ELD_ADDRESS; + I915_WRITE(aud_cntl_st, i); + + len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ + DRM_DEBUG_DRIVER("ELD size %d\n", len); + for (i = 0; i < len; i++) + I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); + + i = I915_READ(aud_cntrl_st2); + i |= eldv; + I915_WRITE(aud_cntrl_st2, i); +} + +void intel_write_eld(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_crtc *crtc = encoder->crtc; + struct drm_connector *connector; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + connector = drm_select_eld(encoder, mode); + if (!connector) + return; + + DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", + connector->base.id, + drm_get_connector_name(connector), + connector->encoder->base.id, + drm_get_encoder_name(connector->encoder)); + + connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; + + if (dev_priv->display.write_eld) + dev_priv->display.write_eld(connector, crtc, mode); +} + +static void i845_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + bool visible = base != 0; + u32 cntl; + + if (intel_crtc->cursor_visible == visible) + return; + + cntl = I915_READ(_CURACNTR); + if (visible) { + /* On these chipsets we can only modify the base whilst + * the cursor is disabled. + */ + I915_WRITE(_CURABASE, base); + + cntl &= ~(CURSOR_FORMAT_MASK); + /* XXX width must be 64, stride 256 => 0x00 << 28 */ + cntl |= CURSOR_ENABLE | + CURSOR_GAMMA_ENABLE | + CURSOR_FORMAT_ARGB; + } else + cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); + I915_WRITE(_CURACNTR, cntl); + + intel_crtc->cursor_visible = visible; +} + +static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + bool visible = base != 0; + + if (intel_crtc->cursor_visible != visible) { + uint32_t cntl = I915_READ(CURCNTR(pipe)); + if (base) { + cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); + cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + cntl |= pipe << 28; /* Connect to correct pipe */ + } else { + cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); + cntl |= CURSOR_MODE_DISABLE; + } + I915_WRITE(CURCNTR(pipe), cntl); + + intel_crtc->cursor_visible = visible; + } + /* and commit changes on next vblank */ + POSTING_READ(CURCNTR(pipe)); + I915_WRITE(CURBASE(pipe), base); + POSTING_READ(CURBASE(pipe)); +} + +static void ivb_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + bool visible = base != 0; + + if (intel_crtc->cursor_visible != visible) { + uint32_t cntl = I915_READ(CURCNTR_IVB(pipe)); + if (base) { + cntl &= ~CURSOR_MODE; + cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + } else { + cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); + cntl |= CURSOR_MODE_DISABLE; + } + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + cntl |= CURSOR_PIPE_CSC_ENABLE; + cntl &= ~CURSOR_TRICKLE_FEED_DISABLE; + } + I915_WRITE(CURCNTR_IVB(pipe), cntl); + + intel_crtc->cursor_visible = visible; + } + /* and commit changes on next vblank */ + POSTING_READ(CURCNTR_IVB(pipe)); + I915_WRITE(CURBASE_IVB(pipe), base); + POSTING_READ(CURBASE_IVB(pipe)); +} + +/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ +static void intel_crtc_update_cursor(struct drm_crtc *crtc, + bool on) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int x = intel_crtc->cursor_x; + int y = intel_crtc->cursor_y; + u32 base = 0, pos = 0; + bool visible; + + if (on) + base = intel_crtc->cursor_addr; + + if (x >= intel_crtc->config.pipe_src_w) + base = 0; + + if (y >= intel_crtc->config.pipe_src_h) + base = 0; + + if (x < 0) { + if (x + intel_crtc->cursor_width <= 0) + base = 0; + + pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT; + x = -x; + } + pos |= x << CURSOR_X_SHIFT; + + if (y < 0) { + if (y + intel_crtc->cursor_height <= 0) + base = 0; + + pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT; + y = -y; + } + pos |= y << CURSOR_Y_SHIFT; + + visible = base != 0; + if (!visible && !intel_crtc->cursor_visible) + return; + + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev)) { + I915_WRITE(CURPOS_IVB(pipe), pos); + ivb_update_cursor(crtc, base); + } else { + I915_WRITE(CURPOS(pipe), pos); + if (IS_845G(dev) || IS_I865G(dev)) + i845_update_cursor(crtc, base); + else + i9xx_update_cursor(crtc, base); + } +} + +static int intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file, + uint32_t handle, + uint32_t width, uint32_t height) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_i915_gem_object *obj; + uint32_t addr; + int ret; + + /* if we want to turn off the cursor ignore width and height */ + if (!handle) { + DRM_DEBUG_KMS("cursor off\n"); + addr = 0; + obj = NULL; + mutex_lock(&dev->struct_mutex); + goto finish; + } + + /* Currently we only support 64x64 cursors */ + if (width != 64 || height != 64) { + DRM_ERROR("we currently only support 64x64 cursors\n"); + return -EINVAL; + } + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); + if (&obj->base == NULL) + return -ENOENT; + + if (obj->base.size < width * height * 4) { + DRM_ERROR("buffer is to small\n"); + ret = -ENOMEM; + goto fail; + } + + /* we only need to pin inside GTT if cursor is non-phy */ + mutex_lock(&dev->struct_mutex); + if (!dev_priv->info->cursor_needs_physical) { + unsigned alignment; + + if (obj->tiling_mode) { + DRM_ERROR("cursor cannot be tiled\n"); + ret = -EINVAL; + goto fail_locked; + } + + /* Note that the w/a also requires 2 PTE of padding following + * the bo. We currently fill all unused PTE with the shadow + * page and so we should always have valid PTE following the + * cursor preventing the VT-d warning. + */ + alignment = 0; + if (need_vtd_wa(dev)) + alignment = 64*1024; + + ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL); + if (ret) { + DRM_ERROR("failed to move cursor bo into the GTT\n"); + goto fail_locked; + } + + ret = i915_gem_object_put_fence(obj); + if (ret) { + DRM_ERROR("failed to release fence for cursor"); + goto fail_unpin; + } + + addr = i915_gem_obj_ggtt_offset(obj); + } else { + int align = IS_I830(dev) ? 16 * 1024 : 256; + ret = i915_gem_attach_phys_object(dev, obj, + (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1, + align); + if (ret) { + DRM_ERROR("failed to attach phys object\n"); + goto fail_locked; + } + addr = obj->phys_obj->handle->busaddr; + } + + if (IS_GEN2(dev)) + I915_WRITE(CURSIZE, (height << 12) | width); + + finish: + if (intel_crtc->cursor_bo) { + if (dev_priv->info->cursor_needs_physical) { + if (intel_crtc->cursor_bo != obj) + i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo); + } else + i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo); + drm_gem_object_unreference(&intel_crtc->cursor_bo->base); + } + + mutex_unlock(&dev->struct_mutex); + + intel_crtc->cursor_addr = addr; + intel_crtc->cursor_bo = obj; + intel_crtc->cursor_width = width; + intel_crtc->cursor_height = height; + + if (intel_crtc->active) + intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL); + + return 0; +fail_unpin: + i915_gem_object_unpin_from_display_plane(obj); +fail_locked: + mutex_unlock(&dev->struct_mutex); +fail: + drm_gem_object_unreference_unlocked(&obj->base); + return ret; +} + +static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_crtc->cursor_x = clamp_t(int, x, SHRT_MIN, SHRT_MAX); + intel_crtc->cursor_y = clamp_t(int, y, SHRT_MIN, SHRT_MAX); + + if (intel_crtc->active) + intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL); + + return 0; +} + +static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, uint32_t start, uint32_t size) +{ + int end = (start + size > 256) ? 256 : start + size, i; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + for (i = start; i < end; i++) { + intel_crtc->lut_r[i] = red[i] >> 8; + intel_crtc->lut_g[i] = green[i] >> 8; + intel_crtc->lut_b[i] = blue[i] >> 8; + } + + intel_crtc_load_lut(crtc); +} + +/* VESA 640x480x72Hz mode to set on the pipe */ +static struct drm_display_mode load_detect_mode = { + DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, + 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), +}; + +static struct drm_framebuffer * +intel_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_i915_gem_object *obj) +{ + struct intel_framebuffer *intel_fb; + int ret; + + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) { + drm_gem_object_unreference_unlocked(&obj->base); + return ERR_PTR(-ENOMEM); + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto err; + + ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); + mutex_unlock(&dev->struct_mutex); + if (ret) + goto err; + + return &intel_fb->base; +err: + drm_gem_object_unreference_unlocked(&obj->base); + kfree(intel_fb); + + return ERR_PTR(ret); +} + +static u32 +intel_framebuffer_pitch_for_width(int width, int bpp) +{ + u32 pitch = DIV_ROUND_UP(width * bpp, 8); + return ALIGN(pitch, 64); +} + +static u32 +intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp) +{ + u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp); + return ALIGN(pitch * mode->vdisplay, PAGE_SIZE); +} + +static struct drm_framebuffer * +intel_framebuffer_create_for_mode(struct drm_device *dev, + struct drm_display_mode *mode, + int depth, int bpp) +{ + struct drm_i915_gem_object *obj; + struct drm_mode_fb_cmd2 mode_cmd = { 0 }; + + obj = i915_gem_alloc_object(dev, + intel_framebuffer_size_for_mode(mode, bpp)); + if (obj == NULL) + return ERR_PTR(-ENOMEM); + + mode_cmd.width = mode->hdisplay; + mode_cmd.height = mode->vdisplay; + mode_cmd.pitches[0] = intel_framebuffer_pitch_for_width(mode_cmd.width, + bpp); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); + + return intel_framebuffer_create(dev, &mode_cmd, obj); +} + +static struct drm_framebuffer * +mode_fits_in_fbdev(struct drm_device *dev, + struct drm_display_mode *mode) +{ +#ifdef CONFIG_DRM_I915_FBDEV + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + struct drm_framebuffer *fb; + + if (dev_priv->fbdev == NULL) + return NULL; + + obj = dev_priv->fbdev->ifb.obj; + if (obj == NULL) + return NULL; + + fb = &dev_priv->fbdev->ifb.base; + if (fb->pitches[0] < intel_framebuffer_pitch_for_width(mode->hdisplay, + fb->bits_per_pixel)) + return NULL; + + if (obj->base.size < mode->vdisplay * fb->pitches[0]) + return NULL; + + return fb; +#else + return NULL; +#endif +} + +bool intel_get_load_detect_pipe(struct drm_connector *connector, + struct drm_display_mode *mode, + struct intel_load_detect_pipe *old) +{ + struct intel_crtc *intel_crtc; + struct intel_encoder *intel_encoder = + intel_attached_encoder(connector); + struct drm_crtc *possible_crtc; + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = NULL; + struct drm_device *dev = encoder->dev; + struct drm_framebuffer *fb; + int i = -1; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector), + encoder->base.id, drm_get_encoder_name(encoder)); + + /* + * Algorithm gets a little messy: + * + * - if the connector already has an assigned crtc, use it (but make + * sure it's on first) + * + * - try to find the first unused crtc that can drive this connector, + * and use that if we find one + */ + + /* See if we already have a CRTC for this connector */ + if (encoder->crtc) { + crtc = encoder->crtc; + + mutex_lock(&crtc->mutex); + + old->dpms_mode = connector->dpms; + old->load_detect_temp = false; + + /* Make sure the crtc and connector are running */ + if (connector->dpms != DRM_MODE_DPMS_ON) + connector->funcs->dpms(connector, DRM_MODE_DPMS_ON); + + return true; + } + + /* Find an unused one (if possible) */ + list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { + i++; + if (!(encoder->possible_crtcs & (1 << i))) + continue; + if (!possible_crtc->enabled) { + crtc = possible_crtc; + break; + } + } + + /* + * If we didn't find an unused CRTC, don't use any. + */ + if (!crtc) { + DRM_DEBUG_KMS("no pipe available for load-detect\n"); + return false; + } + + mutex_lock(&crtc->mutex); + intel_encoder->new_crtc = to_intel_crtc(crtc); + to_intel_connector(connector)->new_encoder = intel_encoder; + + intel_crtc = to_intel_crtc(crtc); + old->dpms_mode = connector->dpms; + old->load_detect_temp = true; + old->release_fb = NULL; + + if (!mode) + mode = &load_detect_mode; + + /* We need a framebuffer large enough to accommodate all accesses + * that the plane may generate whilst we perform load detection. + * We can not rely on the fbcon either being present (we get called + * during its initialisation to detect all boot displays, or it may + * not even exist) or that it is large enough to satisfy the + * requested mode. + */ + fb = mode_fits_in_fbdev(dev, mode); + if (fb == NULL) { + DRM_DEBUG_KMS("creating tmp fb for load-detection\n"); + fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32); + old->release_fb = fb; + } else + DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); + if (IS_ERR(fb)) { + DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); + mutex_unlock(&crtc->mutex); + return false; + } + + if (intel_set_mode(crtc, mode, 0, 0, fb)) { + DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); + if (old->release_fb) + old->release_fb->funcs->destroy(old->release_fb); + mutex_unlock(&crtc->mutex); + return false; + } + + /* let the connector get through one full cycle before testing */ + intel_wait_for_vblank(dev, intel_crtc->pipe); + return true; +} + +void intel_release_load_detect_pipe(struct drm_connector *connector, + struct intel_load_detect_pipe *old) +{ + struct intel_encoder *intel_encoder = + intel_attached_encoder(connector); + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector), + encoder->base.id, drm_get_encoder_name(encoder)); + + if (old->load_detect_temp) { + to_intel_connector(connector)->new_encoder = NULL; + intel_encoder->new_crtc = NULL; + intel_set_mode(crtc, NULL, 0, 0, NULL); + + if (old->release_fb) { + drm_framebuffer_unregister_private(old->release_fb); + drm_framebuffer_unreference(old->release_fb); + } + + mutex_unlock(&crtc->mutex); + return; + } + + /* Switch crtc and encoder back off if necessary */ + if (old->dpms_mode != DRM_MODE_DPMS_ON) + connector->funcs->dpms(connector, old->dpms_mode); + + mutex_unlock(&crtc->mutex); +} + +static int i9xx_pll_refclk(struct drm_device *dev, + const struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpll = pipe_config->dpll_hw_state.dpll; + + if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) + return dev_priv->vbt.lvds_ssc_freq; + else if (HAS_PCH_SPLIT(dev)) + return 120000; + else if (!IS_GEN2(dev)) + return 96000; + else + return 48000; +} + +/* Returns the clock of the currently programmed mode of the given pipe. */ +static void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = pipe_config->cpu_transcoder; + u32 dpll = pipe_config->dpll_hw_state.dpll; + u32 fp; + intel_clock_t clock; + int refclk = i9xx_pll_refclk(dev, pipe_config); + + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = pipe_config->dpll_hw_state.fp0; + else + fp = pipe_config->dpll_hw_state.fp1; + + clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; + if (IS_PINEVIEW(dev)) { + clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; + clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT; + } else { + clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; + clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; + } + + if (!IS_GEN2(dev)) { + if (IS_PINEVIEW(dev)) + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> + DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); + else + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + switch (dpll & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? + 5 : 10; + break; + case DPLLB_MODE_LVDS: + clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? + 7 : 14; + break; + default: + DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed " + "mode\n", (int)(dpll & DPLL_MODE_MASK)); + return; + } + + if (IS_PINEVIEW(dev)) + pineview_clock(refclk, &clock); + else + i9xx_clock(refclk, &clock); + } else { + u32 lvds = IS_I830(dev) ? 0 : I915_READ(LVDS); + bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN); + + if (is_lvds) { + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + if (lvds & LVDS_CLKB_POWER_UP) + clock.p2 = 7; + else + clock.p2 = 14; + } else { + if (dpll & PLL_P1_DIVIDE_BY_TWO) + clock.p1 = 2; + else { + clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> + DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (dpll & PLL_P2_DIVIDE_BY_4) + clock.p2 = 4; + else + clock.p2 = 2; + } + + i9xx_clock(refclk, &clock); + } + + /* + * This value includes pixel_multiplier. We will use + * port_clock to compute adjusted_mode.crtc_clock in the + * encoder's get_config() function. + */ + pipe_config->port_clock = clock.dot; +} + +int intel_dotclock_calculate(int link_freq, + const struct intel_link_m_n *m_n) +{ + /* + * The calculation for the data clock is: + * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp + * But we want to avoid losing precison if possible, so: + * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp)) + * + * and the link clock is simpler: + * link_clock = (m * link_clock) / n + */ + + if (!m_n->link_n) + return 0; + + return div_u64((u64)m_n->link_m * link_freq, m_n->link_n); +} + +static void ironlake_pch_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + + /* read out port_clock from the DPLL */ + i9xx_crtc_clock_get(crtc, pipe_config); + + /* + * This value does not include pixel_multiplier. + * We will check that port_clock and adjusted_mode.crtc_clock + * agree once we know their relationship in the encoder's + * get_config() function. + */ + pipe_config->adjusted_mode.crtc_clock = + intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000, + &pipe_config->fdi_m_n); +} + +/** Returns the currently programmed mode of the given pipe. */ +struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, + struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + struct drm_display_mode *mode; + struct intel_crtc_config pipe_config; + int htot = I915_READ(HTOTAL(cpu_transcoder)); + int hsync = I915_READ(HSYNC(cpu_transcoder)); + int vtot = I915_READ(VTOTAL(cpu_transcoder)); + int vsync = I915_READ(VSYNC(cpu_transcoder)); + enum pipe pipe = intel_crtc->pipe; + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) + return NULL; + + /* + * Construct a pipe_config sufficient for getting the clock info + * back out of crtc_clock_get. + * + * Note, if LVDS ever uses a non-1 pixel multiplier, we'll need + * to use a real value here instead. + */ + pipe_config.cpu_transcoder = (enum transcoder) pipe; + pipe_config.pixel_multiplier = 1; + pipe_config.dpll_hw_state.dpll = I915_READ(DPLL(pipe)); + pipe_config.dpll_hw_state.fp0 = I915_READ(FP0(pipe)); + pipe_config.dpll_hw_state.fp1 = I915_READ(FP1(pipe)); + i9xx_crtc_clock_get(intel_crtc, &pipe_config); + + mode->clock = pipe_config.port_clock / pipe_config.pixel_multiplier; + mode->hdisplay = (htot & 0xffff) + 1; + mode->htotal = ((htot & 0xffff0000) >> 16) + 1; + mode->hsync_start = (hsync & 0xffff) + 1; + mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; + mode->vdisplay = (vtot & 0xffff) + 1; + mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; + mode->vsync_start = (vsync & 0xffff) + 1; + mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; + + drm_mode_set_name(mode); + + return mode; +} + +static void intel_increase_pllclock(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int dpll_reg = DPLL(pipe); + int dpll; + + if (HAS_PCH_SPLIT(dev)) + return; + + if (!dev_priv->lvds_downclock_avail) + return; + + dpll = I915_READ(dpll_reg); + if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) { + DRM_DEBUG_DRIVER("upclocking LVDS\n"); + + assert_panel_unlocked(dev_priv, pipe); + + dpll &= ~DISPLAY_RATE_SELECT_FPA1; + I915_WRITE(dpll_reg, dpll); + intel_wait_for_vblank(dev, pipe); + + dpll = I915_READ(dpll_reg); + if (dpll & DISPLAY_RATE_SELECT_FPA1) + DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); + } +} + +static void intel_decrease_pllclock(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + if (HAS_PCH_SPLIT(dev)) + return; + + if (!dev_priv->lvds_downclock_avail) + return; + + /* + * Since this is called by a timer, we should never get here in + * the manual case. + */ + if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) { + int pipe = intel_crtc->pipe; + int dpll_reg = DPLL(pipe); + int dpll; + + DRM_DEBUG_DRIVER("downclocking LVDS\n"); + + assert_panel_unlocked(dev_priv, pipe); + + dpll = I915_READ(dpll_reg); + dpll |= DISPLAY_RATE_SELECT_FPA1; + I915_WRITE(dpll_reg, dpll); + intel_wait_for_vblank(dev, pipe); + dpll = I915_READ(dpll_reg); + if (!(dpll & DISPLAY_RATE_SELECT_FPA1)) + DRM_DEBUG_DRIVER("failed to downclock LVDS!\n"); + } + +} + +void intel_mark_busy(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + hsw_package_c8_gpu_busy(dev_priv); + i915_update_gfx_val(dev_priv); +} + +void intel_mark_idle(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + + hsw_package_c8_gpu_idle(dev_priv); + + if (!i915_powersave) + return; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (!crtc->fb) + continue; + + intel_decrease_pllclock(crtc); + } + + if (dev_priv->info->gen >= 6) + gen6_rps_idle(dev->dev_private); +} + +void intel_mark_fb_busy(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring) +{ + struct drm_device *dev = obj->base.dev; + struct drm_crtc *crtc; + + if (!i915_powersave) + return; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (!crtc->fb) + continue; + + if (to_intel_framebuffer(crtc->fb)->obj != obj) + continue; + + intel_increase_pllclock(crtc); + if (ring && intel_fbc_enabled(dev)) + ring->fbc_dirty = true; + } +} + +static void intel_crtc_destroy(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct intel_unpin_work *work; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + work = intel_crtc->unpin_work; + intel_crtc->unpin_work = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + if (work) { + cancel_work_sync(&work->work); + kfree(work); + } + + intel_crtc_cursor_set(crtc, NULL, 0, 0, 0); + + drm_crtc_cleanup(crtc); + + kfree(intel_crtc); +} + +static void intel_unpin_work_fn(struct work_struct *__work) +{ + struct intel_unpin_work *work = + container_of(__work, struct intel_unpin_work, work); + struct drm_device *dev = work->crtc->dev; + + mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(work->old_fb_obj); + drm_gem_object_unreference(&work->pending_flip_obj->base); + drm_gem_object_unreference(&work->old_fb_obj->base); + + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); + + BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0); + atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count); + + kfree(work); +} + +static void do_intel_finish_page_flip(struct drm_device *dev, + struct drm_crtc *crtc) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_unpin_work *work; + unsigned long flags; + + /* Ignore early vblank irqs */ + if (intel_crtc == NULL) + return; + + spin_lock_irqsave(&dev->event_lock, flags); + work = intel_crtc->unpin_work; + + /* Ensure we don't miss a work->pending update ... */ + smp_rmb(); + + if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { + spin_unlock_irqrestore(&dev->event_lock, flags); + return; + } + + /* and that the unpin work is consistent wrt ->pending. */ + smp_rmb(); + + intel_crtc->unpin_work = NULL; + + if (work->event) + drm_send_vblank_event(dev, intel_crtc->pipe, work->event); + + drm_vblank_put(dev, intel_crtc->pipe); + + spin_unlock_irqrestore(&dev->event_lock, flags); + + wake_up_all(&dev_priv->pending_flip_queue); + + queue_work(dev_priv->wq, &work->work); + + trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); +} + +void intel_finish_page_flip(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + + do_intel_finish_page_flip(dev, crtc); +} + +void intel_finish_page_flip_plane(struct drm_device *dev, int plane) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane]; + + do_intel_finish_page_flip(dev, crtc); +} + +void intel_prepare_page_flip(struct drm_device *dev, int plane) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = + to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]); + unsigned long flags; + + /* NB: An MMIO update of the plane base pointer will also + * generate a page-flip completion irq, i.e. every modeset + * is also accompanied by a spurious intel_prepare_page_flip(). + */ + spin_lock_irqsave(&dev->event_lock, flags); + if (intel_crtc->unpin_work) + atomic_inc_not_zero(&intel_crtc->unpin_work->pending); + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc) +{ + /* Ensure that the work item is consistent when activating it ... */ + smp_wmb(); + atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING); + /* and that it is marked active as soon as the irq could fire. */ + smp_wmb(); +} + +static int intel_gen2_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + uint32_t flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 flip_mask; + struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + if (ret) + goto err; + + ret = intel_ring_begin(ring, 6); + if (ret) + goto err_unpin; + + /* Can't queue multiple flips, so wait for the previous + * one to finish before executing the next. + */ + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0]); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, 0); /* aux display base address, unused */ + + intel_mark_page_flip_active(intel_crtc); + __intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: + return ret; +} + +static int intel_gen3_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + uint32_t flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 flip_mask; + struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + if (ret) + goto err; + + ret = intel_ring_begin(ring, 6); + if (ret) + goto err_unpin; + + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0]); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, MI_NOOP); + + intel_mark_page_flip_active(intel_crtc); + __intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: + return ret; +} + +static int intel_gen4_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + uint32_t flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t pf, pipesrc; + struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + if (ret) + goto err; + + ret = intel_ring_begin(ring, 4); + if (ret) + goto err_unpin; + + /* i965+ uses the linear or tiled offsets from the + * Display Registers (which do not change across a page-flip) + * so we need only reprogram the base address. + */ + intel_ring_emit(ring, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0]); + intel_ring_emit(ring, + (i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset) | + obj->tiling_mode); + + /* XXX Enabling the panel-fitter across page-flip is so far + * untested on non-native modes, so ignore it for now. + * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; + */ + pf = 0; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + intel_ring_emit(ring, pf | pipesrc); + + intel_mark_page_flip_active(intel_crtc); + __intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: + return ret; +} + +static int intel_gen6_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + uint32_t flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; + uint32_t pf, pipesrc; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + if (ret) + goto err; + + ret = intel_ring_begin(ring, 4); + if (ret) + goto err_unpin; + + intel_ring_emit(ring, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + + /* Contrary to the suggestions in the documentation, + * "Enable Panel Fitter" does not seem to be required when page + * flipping with a non-native mode, and worse causes a normal + * modeset to fail. + * pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE; + */ + pf = 0; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + intel_ring_emit(ring, pf | pipesrc); + + intel_mark_page_flip_active(intel_crtc); + __intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: + return ret; +} + +static int intel_gen7_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + uint32_t flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_ring_buffer *ring; + uint32_t plane_bit = 0; + int len, ret; + + ring = obj->ring; + if (IS_VALLEYVIEW(dev) || ring == NULL || ring->id != RCS) + ring = &dev_priv->ring[BCS]; + + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); + if (ret) + goto err; + + switch(intel_crtc->plane) { + case PLANE_A: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A; + break; + case PLANE_B: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_B; + break; + case PLANE_C: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_C; + break; + default: + WARN_ONCE(1, "unknown plane in flip command\n"); + ret = -ENODEV; + goto err_unpin; + } + + len = 4; + if (ring->id == RCS) + len += 6; + + /* + * BSpec MI_DISPLAY_FLIP for IVB: + * "The full packet must be contained within the same cache line." + * + * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same + * cacheline, if we ever start emitting more commands before + * the MI_DISPLAY_FLIP we may need to first emit everything else, + * then do the cacheline alignment, and finally emit the + * MI_DISPLAY_FLIP. + */ + ret = intel_ring_cacheline_align(ring); + if (ret) + goto err_unpin; + + ret = intel_ring_begin(ring, len); + if (ret) + goto err_unpin; + + /* Unmask the flip-done completion message. Note that the bspec says that + * we should do this for both the BCS and RCS, and that we must not unmask + * more than one flip event at any time (or ensure that one flip message + * can be sent by waiting for flip-done prior to queueing new flips). + * Experimentation says that BCS works despite DERRMR masking all + * flip-done completion events and that unmasking all planes at once + * for the RCS also doesn't appear to drop events. Setting the DERRMR + * to zero does lead to lockups within MI_DISPLAY_FLIP. + */ + if (ring->id == RCS) { + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, DERRMR); + intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE | + DERRMR_PIPEB_PRI_FLIP_DONE | + DERRMR_PIPEC_PRI_FLIP_DONE)); + intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) | + MI_SRM_LRM_GLOBAL_GTT); + intel_ring_emit(ring, DERRMR); + intel_ring_emit(ring, ring->scratch.gtt_offset + 256); + } + + intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit); + intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, (MI_NOOP)); + + intel_mark_page_flip_active(intel_crtc); + __intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: + return ret; +} + +static int intel_default_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + uint32_t flags) +{ + return -ENODEV; +} + +static int intel_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *old_fb = crtc->fb; + struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_unpin_work *work; + unsigned long flags; + int ret; + + /* Can't change pixel format via MI display flips. */ + if (fb->pixel_format != crtc->fb->pixel_format) + return -EINVAL; + + /* + * TILEOFF/LINOFF registers can't be changed via MI display flips. + * Note that pitch changes could also affect these register. + */ + if (INTEL_INFO(dev)->gen > 3 && + (fb->offsets[0] != crtc->fb->offsets[0] || + fb->pitches[0] != crtc->fb->pitches[0])) + return -EINVAL; + + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (work == NULL) + return -ENOMEM; + + work->event = event; + work->crtc = crtc; + work->old_fb_obj = to_intel_framebuffer(old_fb)->obj; + INIT_WORK(&work->work, intel_unpin_work_fn); + + ret = drm_vblank_get(dev, intel_crtc->pipe); + if (ret) + goto free_work; + + /* We borrow the event spin lock for protecting unpin_work */ + spin_lock_irqsave(&dev->event_lock, flags); + if (intel_crtc->unpin_work) { + spin_unlock_irqrestore(&dev->event_lock, flags); + kfree(work); + drm_vblank_put(dev, intel_crtc->pipe); + + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); + return -EBUSY; + } + intel_crtc->unpin_work = work; + spin_unlock_irqrestore(&dev->event_lock, flags); + + if (atomic_read(&intel_crtc->unpin_work_count) >= 2) + flush_workqueue(dev_priv->wq); + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto cleanup; + + /* Reference the objects for the scheduled work. */ + drm_gem_object_reference(&work->old_fb_obj->base); + drm_gem_object_reference(&obj->base); + + crtc->fb = fb; + + work->pending_flip_obj = obj; + + work->enable_stall_check = true; + + atomic_inc(&intel_crtc->unpin_work_count); + intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + + ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, page_flip_flags); + if (ret) + goto cleanup_pending; + + intel_disable_fbc(dev); + intel_mark_fb_busy(obj, NULL); + mutex_unlock(&dev->struct_mutex); + + trace_i915_flip_request(intel_crtc->plane, obj); + + return 0; + +cleanup_pending: + atomic_dec(&intel_crtc->unpin_work_count); + crtc->fb = old_fb; + drm_gem_object_unreference(&work->old_fb_obj->base); + drm_gem_object_unreference(&obj->base); + mutex_unlock(&dev->struct_mutex); + +cleanup: + spin_lock_irqsave(&dev->event_lock, flags); + intel_crtc->unpin_work = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + drm_vblank_put(dev, intel_crtc->pipe); +free_work: + kfree(work); + + return ret; +} + +static struct drm_crtc_helper_funcs intel_helper_funcs = { + .mode_set_base_atomic = intel_pipe_set_base_atomic, + .load_lut = intel_crtc_load_lut, +}; + +/** + * intel_modeset_update_staged_output_state + * + * Updates the staged output configuration state, e.g. after we've read out the + * current hw state. + */ +static void intel_modeset_update_staged_output_state(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + connector->new_encoder = + to_intel_encoder(connector->base.encoder); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + encoder->new_crtc = + to_intel_crtc(encoder->base.crtc); + } +} + +/** + * intel_modeset_commit_output_state + * + * This function copies the stage display pipe configuration to the real one. + */ +static void intel_modeset_commit_output_state(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + connector->base.encoder = &connector->new_encoder->base; + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + encoder->base.crtc = &encoder->new_crtc->base; + } +} + +static void +connected_sink_compute_bpp(struct intel_connector * connector, + struct intel_crtc_config *pipe_config) +{ + int bpp = pipe_config->pipe_bpp; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n", + connector->base.base.id, + drm_get_connector_name(&connector->base)); + + /* Don't use an invalid EDID bpc value */ + if (connector->base.display_info.bpc && + connector->base.display_info.bpc * 3 < bpp) { + DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n", + bpp, connector->base.display_info.bpc*3); + pipe_config->pipe_bpp = connector->base.display_info.bpc*3; + } + + /* Clamp bpp to 8 on screens without EDID 1.4 */ + if (connector->base.display_info.bpc == 0 && bpp > 24) { + DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n", + bpp); + pipe_config->pipe_bpp = 24; + } +} + +static int +compute_baseline_pipe_bpp(struct intel_crtc *crtc, + struct drm_framebuffer *fb, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_connector *connector; + int bpp; + + switch (fb->pixel_format) { + case DRM_FORMAT_C8: + bpp = 8*3; /* since we go through a colormap */ + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: + /* checked in intel_framebuffer_init already */ + if (WARN_ON(INTEL_INFO(dev)->gen > 3)) + return -EINVAL; + case DRM_FORMAT_RGB565: + bpp = 6*3; /* min is 18bpp */ + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + /* checked in intel_framebuffer_init already */ + if (WARN_ON(INTEL_INFO(dev)->gen < 4)) + return -EINVAL; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + bpp = 8*3; + break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + /* checked in intel_framebuffer_init already */ + if (WARN_ON(INTEL_INFO(dev)->gen < 4)) + return -EINVAL; + bpp = 10*3; + break; + /* TODO: gen4+ supports 16 bpc floating point, too. */ + default: + DRM_DEBUG_KMS("unsupported depth\n"); + return -EINVAL; + } + + pipe_config->pipe_bpp = bpp; + + /* Clamp display bpp to EDID value */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (!connector->new_encoder || + connector->new_encoder->new_crtc != crtc) + continue; + + connected_sink_compute_bpp(connector, pipe_config); + } + + return bpp; +} + +static void intel_dump_crtc_timings(const struct drm_display_mode *mode) +{ + DRM_DEBUG_KMS("crtc timings: %d %d %d %d %d %d %d %d %d, " + "type: 0x%x flags: 0x%x\n", + mode->crtc_clock, + mode->crtc_hdisplay, mode->crtc_hsync_start, + mode->crtc_hsync_end, mode->crtc_htotal, + mode->crtc_vdisplay, mode->crtc_vsync_start, + mode->crtc_vsync_end, mode->crtc_vtotal, mode->type, mode->flags); +} + +static void intel_dump_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config, + const char *context) +{ + DRM_DEBUG_KMS("[CRTC:%d]%s config for pipe %c\n", crtc->base.base.id, + context, pipe_name(crtc->pipe)); + + DRM_DEBUG_KMS("cpu_transcoder: %c\n", transcoder_name(pipe_config->cpu_transcoder)); + DRM_DEBUG_KMS("pipe bpp: %i, dithering: %i\n", + pipe_config->pipe_bpp, pipe_config->dither); + DRM_DEBUG_KMS("fdi/pch: %i, lanes: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n", + pipe_config->has_pch_encoder, + pipe_config->fdi_lanes, + pipe_config->fdi_m_n.gmch_m, pipe_config->fdi_m_n.gmch_n, + pipe_config->fdi_m_n.link_m, pipe_config->fdi_m_n.link_n, + pipe_config->fdi_m_n.tu); + DRM_DEBUG_KMS("dp: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n", + pipe_config->has_dp_encoder, + pipe_config->dp_m_n.gmch_m, pipe_config->dp_m_n.gmch_n, + pipe_config->dp_m_n.link_m, pipe_config->dp_m_n.link_n, + pipe_config->dp_m_n.tu); + DRM_DEBUG_KMS("requested mode:\n"); + drm_mode_debug_printmodeline(&pipe_config->requested_mode); + DRM_DEBUG_KMS("adjusted mode:\n"); + drm_mode_debug_printmodeline(&pipe_config->adjusted_mode); + intel_dump_crtc_timings(&pipe_config->adjusted_mode); + DRM_DEBUG_KMS("port clock: %d\n", pipe_config->port_clock); + DRM_DEBUG_KMS("pipe src size: %dx%d\n", + pipe_config->pipe_src_w, pipe_config->pipe_src_h); + DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n", + pipe_config->gmch_pfit.control, + pipe_config->gmch_pfit.pgm_ratios, + pipe_config->gmch_pfit.lvds_border_bits); + DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n", + pipe_config->pch_pfit.pos, + pipe_config->pch_pfit.size, + pipe_config->pch_pfit.enabled ? "enabled" : "disabled"); + DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled); + DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide); +} + +static bool check_encoder_cloning(struct drm_crtc *crtc) +{ + int num_encoders = 0; + bool uncloneable_encoders = false; + struct intel_encoder *encoder; + + list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, + base.head) { + if (&encoder->new_crtc->base != crtc) + continue; + + num_encoders++; + if (!encoder->cloneable) + uncloneable_encoders = true; + } + + return !(num_encoders > 1 && uncloneable_encoders); +} + +static struct intel_crtc_config * +intel_modeset_pipe_config(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_display_mode *mode) +{ + struct drm_device *dev = crtc->dev; + struct intel_encoder *encoder; + struct intel_crtc_config *pipe_config; + int plane_bpp, ret = -EINVAL; + bool retry = true; + + if (!check_encoder_cloning(crtc)) { + DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); + return ERR_PTR(-EINVAL); + } + + pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); + if (!pipe_config) + return ERR_PTR(-ENOMEM); + + drm_mode_copy(&pipe_config->adjusted_mode, mode); + drm_mode_copy(&pipe_config->requested_mode, mode); + + pipe_config->cpu_transcoder = + (enum transcoder) to_intel_crtc(crtc)->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; + + /* + * Sanitize sync polarity flags based on requested ones. If neither + * positive or negative polarity is requested, treat this as meaning + * negative polarity. + */ + if (!(pipe_config->adjusted_mode.flags & + (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC))) + pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_NHSYNC; + + if (!(pipe_config->adjusted_mode.flags & + (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))) + pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC; + + /* Compute a starting value for pipe_config->pipe_bpp taking the source + * plane pixel format and any sink constraints into account. Returns the + * source plane bpp so that dithering can be selected on mismatches + * after encoders and crtc also have had their say. */ + plane_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc), + fb, pipe_config); + if (plane_bpp < 0) + goto fail; + + /* + * Determine the real pipe dimensions. Note that stereo modes can + * increase the actual pipe size due to the frame doubling and + * insertion of additional space for blanks between the frame. This + * is stored in the crtc timings. We use the requested mode to do this + * computation to clearly distinguish it from the adjusted mode, which + * can be changed by the connectors in the below retry loop. + */ + drm_mode_set_crtcinfo(&pipe_config->requested_mode, CRTC_STEREO_DOUBLE); + pipe_config->pipe_src_w = pipe_config->requested_mode.crtc_hdisplay; + pipe_config->pipe_src_h = pipe_config->requested_mode.crtc_vdisplay; + +encoder_retry: + /* Ensure the port clock defaults are reset when retrying. */ + pipe_config->port_clock = 0; + pipe_config->pixel_multiplier = 1; + + /* Fill in default crtc timings, allow encoders to overwrite them. */ + drm_mode_set_crtcinfo(&pipe_config->adjusted_mode, CRTC_STEREO_DOUBLE); + + /* Pass our mode to the connectors and the CRTC to give them a chance to + * adjust it according to limitations or connector properties, and also + * a chance to reject the mode entirely. + */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + + if (&encoder->new_crtc->base != crtc) + continue; + + if (!(encoder->compute_config(encoder, pipe_config))) { + DRM_DEBUG_KMS("Encoder config failure\n"); + goto fail; + } + } + + /* Set default port clock if not overwritten by the encoder. Needs to be + * done afterwards in case the encoder adjusts the mode. */ + if (!pipe_config->port_clock) + pipe_config->port_clock = pipe_config->adjusted_mode.crtc_clock + * pipe_config->pixel_multiplier; + + ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config); + if (ret < 0) { + DRM_DEBUG_KMS("CRTC fixup failed\n"); + goto fail; + } + + if (ret == RETRY) { + if (WARN(!retry, "loop in pipe configuration computation\n")) { + ret = -EINVAL; + goto fail; + } + + DRM_DEBUG_KMS("CRTC bw constrained, retrying\n"); + retry = false; + goto encoder_retry; + } + + pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; + DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", + plane_bpp, pipe_config->pipe_bpp, pipe_config->dither); + + return pipe_config; +fail: + kfree(pipe_config); + return ERR_PTR(ret); +} + +/* Computes which crtcs are affected and sets the relevant bits in the mask. For + * simplicity we use the crtc's pipe number (because it's easier to obtain). */ +static void +intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, + unsigned *prepare_pipes, unsigned *disable_pipes) +{ + struct intel_crtc *intel_crtc; + struct drm_device *dev = crtc->dev; + struct intel_encoder *encoder; + struct intel_connector *connector; + struct drm_crtc *tmp_crtc; + + *disable_pipes = *modeset_pipes = *prepare_pipes = 0; + + /* Check which crtcs have changed outputs connected to them, these need + * to be part of the prepare_pipes mask. We don't (yet) support global + * modeset across multiple crtcs, so modeset_pipes will only have one + * bit set at most. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->base.encoder == &connector->new_encoder->base) + continue; + + if (connector->base.encoder) { + tmp_crtc = connector->base.encoder->crtc; + + *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe; + } + + if (connector->new_encoder) + *prepare_pipes |= + 1 << connector->new_encoder->new_crtc->pipe; + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->base.crtc == &encoder->new_crtc->base) + continue; + + if (encoder->base.crtc) { + tmp_crtc = encoder->base.crtc; + + *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe; + } + + if (encoder->new_crtc) + *prepare_pipes |= 1 << encoder->new_crtc->pipe; + } + + /* Check for any pipes that will be fully disabled ... */ + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + bool used = false; + + /* Don't try to disable disabled crtcs. */ + if (!intel_crtc->base.enabled) + continue; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->new_crtc == intel_crtc) + used = true; + } + + if (!used) + *disable_pipes |= 1 << intel_crtc->pipe; + } + + + /* set_mode is also used to update properties on life display pipes. */ + intel_crtc = to_intel_crtc(crtc); + if (crtc->enabled) + *prepare_pipes |= 1 << intel_crtc->pipe; + + /* + * For simplicity do a full modeset on any pipe where the output routing + * changed. We could be more clever, but that would require us to be + * more careful with calling the relevant encoder->mode_set functions. + */ + if (*prepare_pipes) + *modeset_pipes = *prepare_pipes; + + /* ... and mask these out. */ + *modeset_pipes &= ~(*disable_pipes); + *prepare_pipes &= ~(*disable_pipes); + + /* + * HACK: We don't (yet) fully support global modesets. intel_set_config + * obies this rule, but the modeset restore mode of + * intel_modeset_setup_hw_state does not. + */ + *modeset_pipes &= 1 << intel_crtc->pipe; + *prepare_pipes &= 1 << intel_crtc->pipe; + + DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", + *modeset_pipes, *prepare_pipes, *disable_pipes); +} + +static bool intel_crtc_in_use(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev = crtc->dev; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->crtc == crtc) + return true; + + return false; +} + +static void +intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) +{ + struct intel_encoder *intel_encoder; + struct intel_crtc *intel_crtc; + struct drm_connector *connector; + + list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list, + base.head) { + if (!intel_encoder->base.crtc) + continue; + + intel_crtc = to_intel_crtc(intel_encoder->base.crtc); + + if (prepare_pipes & (1 << intel_crtc->pipe)) + intel_encoder->connectors_active = false; + } + + intel_modeset_commit_output_state(dev); + + /* Update computed state. */ + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + intel_crtc->base.enabled = intel_crtc_in_use(&intel_crtc->base); + } + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (!connector->encoder || !connector->encoder->crtc) + continue; + + intel_crtc = to_intel_crtc(connector->encoder->crtc); + + if (prepare_pipes & (1 << intel_crtc->pipe)) { + struct drm_property *dpms_property = + dev->mode_config.dpms_property; + + connector->dpms = DRM_MODE_DPMS_ON; + drm_object_property_set_value(&connector->base, + dpms_property, + DRM_MODE_DPMS_ON); + + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder->connectors_active = true; + } + } + +} + +static bool intel_fuzzy_clock_check(int clock1, int clock2) +{ + int diff; + + if (clock1 == clock2) + return true; + + if (!clock1 || !clock2) + return false; + + diff = abs(clock1 - clock2); + + if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105) + return true; + + return false; +} + +#define for_each_intel_crtc_masked(dev, mask, intel_crtc) \ + list_for_each_entry((intel_crtc), \ + &(dev)->mode_config.crtc_list, \ + base.head) \ + if (mask & (1 <<(intel_crtc)->pipe)) + +static bool +intel_pipe_config_compare(struct drm_device *dev, + struct intel_crtc_config *current_config, + struct intel_crtc_config *pipe_config) +{ +#define PIPE_CONF_CHECK_X(name) \ + if (current_config->name != pipe_config->name) { \ + DRM_ERROR("mismatch in " #name " " \ + "(expected 0x%08x, found 0x%08x)\n", \ + current_config->name, \ + pipe_config->name); \ + return false; \ + } + +#define PIPE_CONF_CHECK_I(name) \ + if (current_config->name != pipe_config->name) { \ + DRM_ERROR("mismatch in " #name " " \ + "(expected %i, found %i)\n", \ + current_config->name, \ + pipe_config->name); \ + return false; \ + } + +#define PIPE_CONF_CHECK_FLAGS(name, mask) \ + if ((current_config->name ^ pipe_config->name) & (mask)) { \ + DRM_ERROR("mismatch in " #name "(" #mask ") " \ + "(expected %i, found %i)\n", \ + current_config->name & (mask), \ + pipe_config->name & (mask)); \ + return false; \ + } + +#define PIPE_CONF_CHECK_CLOCK_FUZZY(name) \ + if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \ + DRM_ERROR("mismatch in " #name " " \ + "(expected %i, found %i)\n", \ + current_config->name, \ + pipe_config->name); \ + return false; \ + } + +#define PIPE_CONF_QUIRK(quirk) \ + ((current_config->quirks | pipe_config->quirks) & (quirk)) + + PIPE_CONF_CHECK_I(cpu_transcoder); + + PIPE_CONF_CHECK_I(has_pch_encoder); + PIPE_CONF_CHECK_I(fdi_lanes); + PIPE_CONF_CHECK_I(fdi_m_n.gmch_m); + PIPE_CONF_CHECK_I(fdi_m_n.gmch_n); + PIPE_CONF_CHECK_I(fdi_m_n.link_m); + PIPE_CONF_CHECK_I(fdi_m_n.link_n); + PIPE_CONF_CHECK_I(fdi_m_n.tu); + + PIPE_CONF_CHECK_I(has_dp_encoder); + PIPE_CONF_CHECK_I(dp_m_n.gmch_m); + PIPE_CONF_CHECK_I(dp_m_n.gmch_n); + PIPE_CONF_CHECK_I(dp_m_n.link_m); + PIPE_CONF_CHECK_I(dp_m_n.link_n); + PIPE_CONF_CHECK_I(dp_m_n.tu); + + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_end); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_end); + + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vdisplay); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vtotal); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_end); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end); + + PIPE_CONF_CHECK_I(pixel_multiplier); + + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_INTERLACE); + + if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) { + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_PHSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_NHSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_PVSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_NVSYNC); + } + + PIPE_CONF_CHECK_I(pipe_src_w); + PIPE_CONF_CHECK_I(pipe_src_h); + + PIPE_CONF_CHECK_I(gmch_pfit.control); + /* pfit ratios are autocomputed by the hw on gen4+ */ + if (INTEL_INFO(dev)->gen < 4) + PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); + PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); + PIPE_CONF_CHECK_I(pch_pfit.enabled); + if (current_config->pch_pfit.enabled) { + PIPE_CONF_CHECK_I(pch_pfit.pos); + PIPE_CONF_CHECK_I(pch_pfit.size); + } + + /* BDW+ don't expose a synchronous way to read the state */ + if (IS_HASWELL(dev)) + PIPE_CONF_CHECK_I(ips_enabled); + + PIPE_CONF_CHECK_I(double_wide); + + PIPE_CONF_CHECK_I(shared_dpll); + PIPE_CONF_CHECK_X(dpll_hw_state.dpll); + PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md); + PIPE_CONF_CHECK_X(dpll_hw_state.fp0); + PIPE_CONF_CHECK_X(dpll_hw_state.fp1); + + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) + PIPE_CONF_CHECK_I(pipe_bpp); + + if (!HAS_DDI(dev)) { + PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock); + PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock); + } + +#undef PIPE_CONF_CHECK_X +#undef PIPE_CONF_CHECK_I +#undef PIPE_CONF_CHECK_FLAGS +#undef PIPE_CONF_CHECK_CLOCK_FUZZY +#undef PIPE_CONF_QUIRK + + return true; +} + +static void +check_connector_state(struct drm_device *dev) +{ + struct intel_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + /* This also checks the encoder/connector hw state with the + * ->get_hw_state callbacks. */ + intel_connector_check_state(connector); + + WARN(&connector->new_encoder->base != connector->base.encoder, + "connector's staged encoder doesn't match current encoder\n"); + } +} + +static void +check_encoder_state(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_connector *connector; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + bool enabled = false; + bool active = false; + enum pipe pipe, tracked_pipe; + + DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base)); + + WARN(&encoder->new_crtc->base != encoder->base.crtc, + "encoder's stage crtc doesn't match current crtc\n"); + WARN(encoder->connectors_active && !encoder->base.crtc, + "encoder's active_connectors set, but no crtc\n"); + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->base.encoder != &encoder->base) + continue; + enabled = true; + if (connector->base.dpms != DRM_MODE_DPMS_OFF) + active = true; + } + WARN(!!encoder->base.crtc != enabled, + "encoder's enabled state mismatch " + "(expected %i, found %i)\n", + !!encoder->base.crtc, enabled); + WARN(active && !encoder->base.crtc, + "active encoder with no crtc\n"); + + WARN(encoder->connectors_active != active, + "encoder's computed active state doesn't match tracked active state " + "(expected %i, found %i)\n", active, encoder->connectors_active); + + active = encoder->get_hw_state(encoder, &pipe); + WARN(active != encoder->connectors_active, + "encoder's hw state doesn't match sw tracking " + "(expected %i, found %i)\n", + encoder->connectors_active, active); + + if (!encoder->base.crtc) + continue; + + tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe; + WARN(active && pipe != tracked_pipe, + "active encoder's pipe doesn't match" + "(expected %i, found %i)\n", + tracked_pipe, pipe); + + } +} + +static void +check_crtc_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_crtc_config pipe_config; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + bool enabled = false; + bool active = false; + + memset(&pipe_config, 0, sizeof(pipe_config)); + + DRM_DEBUG_KMS("[CRTC:%d]\n", + crtc->base.base.id); + + WARN(crtc->active && !crtc->base.enabled, + "active crtc, but not enabled in sw tracking\n"); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->base.crtc != &crtc->base) + continue; + enabled = true; + if (encoder->connectors_active) + active = true; + } + + WARN(active != crtc->active, + "crtc's computed active state doesn't match tracked active state " + "(expected %i, found %i)\n", active, crtc->active); + WARN(enabled != crtc->base.enabled, + "crtc's computed enabled state doesn't match tracked enabled state " + "(expected %i, found %i)\n", enabled, crtc->base.enabled); + + active = dev_priv->display.get_pipe_config(crtc, + &pipe_config); + + /* hw state is inconsistent with the pipe A quirk */ + if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) + active = crtc->active; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + enum pipe pipe; + if (encoder->base.crtc != &crtc->base) + continue; + if (encoder->get_hw_state(encoder, &pipe)) + encoder->get_config(encoder, &pipe_config); + } + + WARN(crtc->active != active, + "crtc active state doesn't match with hw state " + "(expected %i, found %i)\n", crtc->active, active); + + if (active && + !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) { + WARN(1, "pipe state doesn't match!\n"); + intel_dump_pipe_config(crtc, &pipe_config, + "[hw state]"); + intel_dump_pipe_config(crtc, &crtc->config, + "[sw state]"); + } + } +} + +static void +check_shared_dpll_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + struct intel_dpll_hw_state dpll_hw_state; + int i; + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + int enabled_crtcs = 0, active_crtcs = 0; + bool active; + + memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); + + DRM_DEBUG_KMS("%s\n", pll->name); + + active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state); + + WARN(pll->active > pll->refcount, + "more active pll users than references: %i vs %i\n", + pll->active, pll->refcount); + WARN(pll->active && !pll->on, + "pll in active use but not on in sw tracking\n"); + WARN(pll->on && !pll->active, + "pll in on but not on in use in sw tracking\n"); + WARN(pll->on != active, + "pll on state mismatch (expected %i, found %i)\n", + pll->on, active); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (crtc->base.enabled && intel_crtc_to_shared_dpll(crtc) == pll) + enabled_crtcs++; + if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) + active_crtcs++; + } + WARN(pll->active != active_crtcs, + "pll active crtcs mismatch (expected %i, found %i)\n", + pll->active, active_crtcs); + WARN(pll->refcount != enabled_crtcs, + "pll enabled crtcs mismatch (expected %i, found %i)\n", + pll->refcount, enabled_crtcs); + + WARN(pll->on && memcmp(&pll->hw_state, &dpll_hw_state, + sizeof(dpll_hw_state)), + "pll hw state mismatch\n"); + } +} + +void +intel_modeset_check_state(struct drm_device *dev) +{ + check_connector_state(dev); + check_encoder_state(dev); + check_crtc_state(dev); + check_shared_dpll_state(dev); +} + +void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, + int dotclock) +{ + /* + * FDI already provided one idea for the dotclock. + * Yell if the encoder disagrees. + */ + WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.crtc_clock, dotclock), + "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n", + pipe_config->adjusted_mode.crtc_clock, dotclock); +} + +static int __intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_display_mode *saved_mode; + struct intel_crtc_config *pipe_config = NULL; + struct intel_crtc *intel_crtc; + unsigned disable_pipes, prepare_pipes, modeset_pipes; + int ret = 0; + + saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL); + if (!saved_mode) + return -ENOMEM; + + intel_modeset_affected_pipes(crtc, &modeset_pipes, + &prepare_pipes, &disable_pipes); + + *saved_mode = crtc->mode; + + /* Hack: Because we don't (yet) support global modeset on multiple + * crtcs, we don't keep track of the new mode for more than one crtc. + * Hence simply check whether any bit is set in modeset_pipes in all the + * pieces of code that are not yet converted to deal with mutliple crtcs + * changing their mode at the same time. */ + if (modeset_pipes) { + pipe_config = intel_modeset_pipe_config(crtc, fb, mode); + if (IS_ERR(pipe_config)) { + ret = PTR_ERR(pipe_config); + pipe_config = NULL; + + goto out; + } + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, + "[modeset]"); + } + + /* + * See if the config requires any additional preparation, e.g. + * to adjust global state with pipes off. We need to do this + * here so we can get the modeset_pipe updated config for the new + * mode set on this crtc. For other crtcs we need to use the + * adjusted_mode bits in the crtc directly. + */ + if (IS_VALLEYVIEW(dev)) { + valleyview_modeset_global_pipes(dev, &prepare_pipes, + modeset_pipes, pipe_config); + + /* may have added more to prepare_pipes than we should */ + prepare_pipes &= ~disable_pipes; + } + + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) + intel_crtc_disable(&intel_crtc->base); + + for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { + if (intel_crtc->base.enabled) + dev_priv->display.crtc_disable(&intel_crtc->base); + } + + /* crtc->mode is already used by the ->mode_set callbacks, hence we need + * to set it here already despite that we pass it down the callchain. + */ + if (modeset_pipes) { + crtc->mode = *mode; + /* mode_set/enable/disable functions rely on a correct pipe + * config. */ + to_intel_crtc(crtc)->config = *pipe_config; + + /* + * Calculate and store various constants which + * are later needed by vblank and swap-completion + * timestamping. They are derived from true hwmode. + */ + drm_calc_timestamping_constants(crtc, + &pipe_config->adjusted_mode); + } + + /* Only after disabling all output pipelines that will be changed can we + * update the the output configuration. */ + intel_modeset_update_state(dev, prepare_pipes); + + if (dev_priv->display.modeset_global_resources) + dev_priv->display.modeset_global_resources(dev); + + /* Set up the DPLL and any encoders state that needs to adjust or depend + * on the DPLL. + */ + for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { + ret = intel_crtc_mode_set(&intel_crtc->base, + x, y, fb); + if (ret) + goto done; + } + + /* Now enable the clocks, plane, pipe, and connectors that we set up. */ + for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) + dev_priv->display.crtc_enable(&intel_crtc->base); + + /* FIXME: add subpixel order */ +done: + if (ret && crtc->enabled) + crtc->mode = *saved_mode; + +out: + kfree(pipe_config); + kfree(saved_mode); + return ret; +} + +static int intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) +{ + int ret; + + ret = __intel_set_mode(crtc, mode, x, y, fb); + + if (ret == 0) + intel_modeset_check_state(crtc->dev); + + return ret; +} + +void intel_crtc_restore_mode(struct drm_crtc *crtc) +{ + intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); +} + +#undef for_each_intel_crtc_masked + +static void intel_set_config_free(struct intel_set_config *config) +{ + if (!config) + return; + + kfree(config->save_connector_encoders); + kfree(config->save_encoder_crtcs); + kfree(config); +} + +static int intel_set_config_save_state(struct drm_device *dev, + struct intel_set_config *config) +{ + struct drm_encoder *encoder; + struct drm_connector *connector; + int count; + + config->save_encoder_crtcs = + kcalloc(dev->mode_config.num_encoder, + sizeof(struct drm_crtc *), GFP_KERNEL); + if (!config->save_encoder_crtcs) + return -ENOMEM; + + config->save_connector_encoders = + kcalloc(dev->mode_config.num_connector, + sizeof(struct drm_encoder *), GFP_KERNEL); + if (!config->save_connector_encoders) + return -ENOMEM; + + /* Copy data. Note that driver private data is not affected. + * Should anything bad happen only the expected state is + * restored, not the drivers personal bookkeeping. + */ + count = 0; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + config->save_encoder_crtcs[count++] = encoder->crtc; + } + + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + config->save_connector_encoders[count++] = connector->encoder; + } + + return 0; +} + +static void intel_set_config_restore_state(struct drm_device *dev, + struct intel_set_config *config) +{ + struct intel_encoder *encoder; + struct intel_connector *connector; + int count; + + count = 0; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + encoder->new_crtc = + to_intel_crtc(config->save_encoder_crtcs[count++]); + } + + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { + connector->new_encoder = + to_intel_encoder(config->save_connector_encoders[count++]); + } +} + +static bool +is_crtc_connector_off(struct drm_mode_set *set) +{ + int i; + + if (set->num_connectors == 0) + return false; + + if (WARN_ON(set->connectors == NULL)) + return false; + + for (i = 0; i < set->num_connectors; i++) + if (set->connectors[i]->encoder && + set->connectors[i]->encoder->crtc == set->crtc && + set->connectors[i]->dpms != DRM_MODE_DPMS_ON) + return true; + + return false; +} + +static void +intel_set_config_compute_mode_changes(struct drm_mode_set *set, + struct intel_set_config *config) +{ + + /* We should be able to check here if the fb has the same properties + * and then just flip_or_move it */ + if (is_crtc_connector_off(set)) { + config->mode_changed = true; + } else if (set->crtc->fb != set->fb) { + /* If we have no fb then treat it as a full mode set */ + if (set->crtc->fb == NULL) { + struct intel_crtc *intel_crtc = + to_intel_crtc(set->crtc); + + if (intel_crtc->active && i915_fastboot) { + DRM_DEBUG_KMS("crtc has no fb, will flip\n"); + config->fb_changed = true; + } else { + DRM_DEBUG_KMS("inactive crtc, full mode set\n"); + config->mode_changed = true; + } + } else if (set->fb == NULL) { + config->mode_changed = true; + } else if (set->fb->pixel_format != + set->crtc->fb->pixel_format) { + config->mode_changed = true; + } else { + config->fb_changed = true; + } + } + + if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y)) + config->fb_changed = true; + + if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { + DRM_DEBUG_KMS("modes are different, full mode set\n"); + drm_mode_debug_printmodeline(&set->crtc->mode); + drm_mode_debug_printmodeline(set->mode); + config->mode_changed = true; + } + + DRM_DEBUG_KMS("computed changes for [CRTC:%d], mode_changed=%d, fb_changed=%d\n", + set->crtc->base.id, config->mode_changed, config->fb_changed); +} + +static int +intel_modeset_stage_output_state(struct drm_device *dev, + struct drm_mode_set *set, + struct intel_set_config *config) +{ + struct drm_crtc *new_crtc; + struct intel_connector *connector; + struct intel_encoder *encoder; + int ro; + + /* The upper layers ensure that we either disable a crtc or have a list + * of connectors. For paranoia, double-check this. */ + WARN_ON(!set->fb && (set->num_connectors != 0)); + WARN_ON(set->fb && (set->num_connectors == 0)); + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + /* Otherwise traverse passed in connector list and get encoders + * for them. */ + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == &connector->base) { + connector->new_encoder = connector->encoder; + break; + } + } + + /* If we disable the crtc, disable all its connectors. Also, if + * the connector is on the changing crtc but not on the new + * connector list, disable it. */ + if ((!set->fb || ro == set->num_connectors) && + connector->base.encoder && + connector->base.encoder->crtc == set->crtc) { + connector->new_encoder = NULL; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", + connector->base.base.id, + drm_get_connector_name(&connector->base)); + } + + + if (&connector->new_encoder->base != connector->base.encoder) { + DRM_DEBUG_KMS("encoder changed, full mode switch\n"); + config->mode_changed = true; + } + } + /* connector->new_encoder is now updated for all connectors. */ + + /* Update crtc of enabled connectors. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (!connector->new_encoder) + continue; + + new_crtc = connector->new_encoder->base.crtc; + + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == &connector->base) + new_crtc = set->crtc; + } + + /* Make sure the new CRTC will work with the encoder */ + if (!drm_encoder_crtc_ok(&connector->new_encoder->base, + new_crtc)) { + return -EINVAL; + } + connector->encoder->new_crtc = to_intel_crtc(new_crtc); + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", + connector->base.base.id, + drm_get_connector_name(&connector->base), + new_crtc->base.id); + } + + /* Check for any encoders that needs to be disabled. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + int num_connectors = 0; + list_for_each_entry(connector, + &dev->mode_config.connector_list, + base.head) { + if (connector->new_encoder == encoder) { + WARN_ON(!connector->new_encoder->new_crtc); + num_connectors++; + } + } + + if (num_connectors == 0) + encoder->new_crtc = NULL; + else if (num_connectors > 1) + return -EINVAL; + + /* Only now check for crtc changes so we don't miss encoders + * that will be disabled. */ + if (&encoder->new_crtc->base != encoder->base.crtc) { + DRM_DEBUG_KMS("crtc changed, full mode switch\n"); + config->mode_changed = true; + } + } + /* Now we've also updated encoder->new_crtc for all encoders. */ + + return 0; +} + +static int intel_crtc_set_config(struct drm_mode_set *set) +{ + struct drm_device *dev; + struct drm_mode_set save_set; + struct intel_set_config *config; + int ret; + + BUG_ON(!set); + BUG_ON(!set->crtc); + BUG_ON(!set->crtc->helper_private); + + /* Enforce sane interface api - has been abused by the fb helper. */ + BUG_ON(!set->mode && set->fb); + BUG_ON(set->fb && set->num_connectors == 0); + + if (set->fb) { + DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", + set->crtc->base.id, set->fb->base.id, + (int)set->num_connectors, set->x, set->y); + } else { + DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); + } + + dev = set->crtc->dev; + + ret = -ENOMEM; + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) + goto out_config; + + ret = intel_set_config_save_state(dev, config); + if (ret) + goto out_config; + + save_set.crtc = set->crtc; + save_set.mode = &set->crtc->mode; + save_set.x = set->crtc->x; + save_set.y = set->crtc->y; + save_set.fb = set->crtc->fb; + + /* Compute whether we need a full modeset, only an fb base update or no + * change at all. In the future we might also check whether only the + * mode changed, e.g. for LVDS where we only change the panel fitter in + * such cases. */ + intel_set_config_compute_mode_changes(set, config); + + ret = intel_modeset_stage_output_state(dev, set, config); + if (ret) + goto fail; + + if (config->mode_changed) { + ret = intel_set_mode(set->crtc, set->mode, + set->x, set->y, set->fb); + } else if (config->fb_changed) { + intel_crtc_wait_for_pending_flips(set->crtc); + + ret = intel_pipe_set_base(set->crtc, + set->x, set->y, set->fb); + /* + * In the fastboot case this may be our only check of the + * state after boot. It would be better to only do it on + * the first update, but we don't have a nice way of doing that + * (and really, set_config isn't used much for high freq page + * flipping, so increasing its cost here shouldn't be a big + * deal). + */ + if (i915_fastboot && ret == 0) + intel_modeset_check_state(set->crtc->dev); + } + + if (ret) { + DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", + set->crtc->base.id, ret); +fail: + intel_set_config_restore_state(dev, config); + + /* Try to restore the config */ + if (config->mode_changed && + intel_set_mode(save_set.crtc, save_set.mode, + save_set.x, save_set.y, save_set.fb)) + DRM_ERROR("failed to restore config after modeset failure\n"); + } + +out_config: + intel_set_config_free(config); + return ret; +} + +static const struct drm_crtc_funcs intel_crtc_funcs = { + .cursor_set = intel_crtc_cursor_set, + .cursor_move = intel_crtc_cursor_move, + .gamma_set = intel_crtc_gamma_set, + .set_config = intel_crtc_set_config, + .destroy = intel_crtc_destroy, + .page_flip = intel_crtc_page_flip, +}; + +static void intel_cpu_pll_init(struct drm_device *dev) +{ + if (HAS_DDI(dev)) + intel_ddi_pll_init(dev); +} + +static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) +{ + uint32_t val; + + val = I915_READ(PCH_DPLL(pll->id)); + hw_state->dpll = val; + hw_state->fp0 = I915_READ(PCH_FP0(pll->id)); + hw_state->fp1 = I915_READ(PCH_FP1(pll->id)); + + return val & DPLL_VCO_ENABLE; +} + +static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + I915_WRITE(PCH_FP0(pll->id), pll->hw_state.fp0); + I915_WRITE(PCH_FP1(pll->id), pll->hw_state.fp1); +} + +static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + /* PCH refclock must be enabled first */ + ibx_assert_pch_refclk_enabled(dev_priv); + + I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(PCH_DPLL(pll->id)); + udelay(150); + + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll); + POSTING_READ(PCH_DPLL(pll->id)); + udelay(200); +} + +static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *crtc; + + /* Make sure no transcoder isn't still depending on us. */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + if (intel_crtc_to_shared_dpll(crtc) == pll) + assert_pch_transcoder_disabled(dev_priv, crtc->pipe); + } + + I915_WRITE(PCH_DPLL(pll->id), 0); + POSTING_READ(PCH_DPLL(pll->id)); + udelay(200); +} + +static char *ibx_pch_dpll_names[] = { + "PCH DPLL A", + "PCH DPLL B", +}; + +static void ibx_pch_dpll_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + dev_priv->num_shared_dpll = 2; + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + dev_priv->shared_dplls[i].id = i; + dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i]; + dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set; + dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable; + dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable; + dev_priv->shared_dplls[i].get_hw_state = + ibx_pch_dpll_get_hw_state; + } +} + +static void intel_shared_dpll_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + ibx_pch_dpll_init(dev); + else + dev_priv->num_shared_dpll = 0; + + BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); +} + +static void intel_crtc_init(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc; + int i; + + intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL); + if (intel_crtc == NULL) + return; + + drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); + + drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); + for (i = 0; i < 256; i++) { + intel_crtc->lut_r[i] = i; + intel_crtc->lut_g[i] = i; + intel_crtc->lut_b[i] = i; + } + + /* + * On gen2/3 only plane A can do fbc, but the panel fitter and lvds port + * is hooked to plane B. Hence we want plane A feeding pipe B. + */ + intel_crtc->pipe = pipe; + intel_crtc->plane = pipe; + if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) { + DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); + intel_crtc->plane = !pipe; + } + + BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || + dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL); + dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; + dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; + + drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); +} + +enum pipe intel_get_pipe_from_connector(struct intel_connector *connector) +{ + struct drm_encoder *encoder = connector->base.encoder; + + WARN_ON(!mutex_is_locked(&connector->base.dev->mode_config.mutex)); + + if (!encoder) + return INVALID_PIPE; + + return to_intel_crtc(encoder->crtc)->pipe; +} + +int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data; + struct drm_mode_object *drmmode_obj; + struct intel_crtc *crtc; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id, + DRM_MODE_OBJECT_CRTC); + + if (!drmmode_obj) { + DRM_ERROR("no such CRTC id\n"); + return -ENOENT; + } + + crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); + pipe_from_crtc_id->pipe = crtc->pipe; + + return 0; +} + +static int intel_encoder_clones(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct intel_encoder *source_encoder; + int index_mask = 0; + int entry = 0; + + list_for_each_entry(source_encoder, + &dev->mode_config.encoder_list, base.head) { + + if (encoder == source_encoder) + index_mask |= (1 << entry); + + /* Intel hw has only one MUX where enocoders could be cloned. */ + if (encoder->cloneable && source_encoder->cloneable) + index_mask |= (1 << entry); + + entry++; + } + + return index_mask; +} + +static bool has_edp_a(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_MOBILE(dev)) + return false; + + if ((I915_READ(DP_A) & DP_DETECTED) == 0) + return false; + + if (IS_GEN5(dev) && + (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE)) + return false; + + return true; +} + +const char *intel_output_name(int output) +{ + static const char *names[] = { + [INTEL_OUTPUT_UNUSED] = "Unused", + [INTEL_OUTPUT_ANALOG] = "Analog", + [INTEL_OUTPUT_DVO] = "DVO", + [INTEL_OUTPUT_SDVO] = "SDVO", + [INTEL_OUTPUT_LVDS] = "LVDS", + [INTEL_OUTPUT_TVOUT] = "TV", + [INTEL_OUTPUT_HDMI] = "HDMI", + [INTEL_OUTPUT_DISPLAYPORT] = "DisplayPort", + [INTEL_OUTPUT_EDP] = "eDP", + [INTEL_OUTPUT_DSI] = "DSI", + [INTEL_OUTPUT_UNKNOWN] = "Unknown", + }; + + if (output < 0 || output >= ARRAY_SIZE(names) || !names[output]) + return "Invalid"; + + return names[output]; +} + +static void intel_setup_outputs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; + bool dpd_is_edp = false; + + intel_lvds_init(dev); + + if (!IS_ULT(dev)) + intel_crt_init(dev); + + if (HAS_DDI(dev)) { + int found; + + /* Haswell uses DDI functions to detect digital outputs */ + found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED; + /* DDI A only supports eDP */ + if (found) + intel_ddi_init(dev, PORT_A); + + /* DDI B, C and D detection is indicated by the SFUSE_STRAP + * register */ + found = I915_READ(SFUSE_STRAP); + + if (found & SFUSE_STRAP_DDIB_DETECTED) + intel_ddi_init(dev, PORT_B); + if (found & SFUSE_STRAP_DDIC_DETECTED) + intel_ddi_init(dev, PORT_C); + if (found & SFUSE_STRAP_DDID_DETECTED) + intel_ddi_init(dev, PORT_D); + } else if (HAS_PCH_SPLIT(dev)) { + int found; + dpd_is_edp = intel_dp_is_edp(dev, PORT_D); + + if (has_edp_a(dev)) + intel_dp_init(dev, DP_A, PORT_A); + + if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) { + /* PCH SDVOB multiplex with HDMIB */ + found = intel_sdvo_init(dev, PCH_SDVOB, true); + if (!found) + intel_hdmi_init(dev, PCH_HDMIB, PORT_B); + if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) + intel_dp_init(dev, PCH_DP_B, PORT_B); + } + + if (I915_READ(PCH_HDMIC) & SDVO_DETECTED) + intel_hdmi_init(dev, PCH_HDMIC, PORT_C); + + if (!dpd_is_edp && I915_READ(PCH_HDMID) & SDVO_DETECTED) + intel_hdmi_init(dev, PCH_HDMID, PORT_D); + + if (I915_READ(PCH_DP_C) & DP_DETECTED) + intel_dp_init(dev, PCH_DP_C, PORT_C); + + if (I915_READ(PCH_DP_D) & DP_DETECTED) + intel_dp_init(dev, PCH_DP_D, PORT_D); + } else if (IS_VALLEYVIEW(dev)) { + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, + PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); + } + + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, + PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); + } + + intel_dsi_init(dev); + } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { + bool found = false; + + if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { + DRM_DEBUG_KMS("probing SDVOB\n"); + found = intel_sdvo_init(dev, GEN3_SDVOB, true); + if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { + DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); + intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); + } + + if (!found && SUPPORTS_INTEGRATED_DP(dev)) + intel_dp_init(dev, DP_B, PORT_B); + } + + /* Before G4X SDVOC doesn't have its own detect register */ + + if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { + DRM_DEBUG_KMS("probing SDVOC\n"); + found = intel_sdvo_init(dev, GEN3_SDVOC, false); + } + + if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) { + + if (SUPPORTS_INTEGRATED_HDMI(dev)) { + DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); + intel_hdmi_init(dev, GEN4_HDMIC, PORT_C); + } + if (SUPPORTS_INTEGRATED_DP(dev)) + intel_dp_init(dev, DP_C, PORT_C); + } + + if (SUPPORTS_INTEGRATED_DP(dev) && + (I915_READ(DP_D) & DP_DETECTED)) + intel_dp_init(dev, DP_D, PORT_D); + } else if (IS_GEN2(dev)) + intel_dvo_init(dev); + + if (SUPPORTS_TV(dev)) + intel_tv_init(dev); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + encoder->base.possible_crtcs = encoder->crtc_mask; + encoder->base.possible_clones = + intel_encoder_clones(encoder); + } + + intel_init_pch_refclk(dev); + + drm_helper_move_panel_connectors_to_head(dev); +} + +void intel_framebuffer_fini(struct intel_framebuffer *fb) +{ + drm_framebuffer_cleanup(&fb->base); + WARN_ON(!fb->obj->framebuffer_references--); + drm_gem_object_unreference_unlocked(&fb->obj->base); +} + +static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + + intel_framebuffer_fini(intel_fb); + kfree(intel_fb); +} + +static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file, + unsigned int *handle) +{ + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + + return drm_gem_handle_create(file, &obj->base, handle); +} + +static const struct drm_framebuffer_funcs intel_fb_funcs = { + .destroy = intel_user_framebuffer_destroy, + .create_handle = intel_user_framebuffer_create_handle, +}; + +int intel_framebuffer_init(struct drm_device *dev, + struct intel_framebuffer *intel_fb, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_i915_gem_object *obj) +{ + int aligned_height, tile_height; + int pitch_limit; + int ret; + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + if (obj->tiling_mode == I915_TILING_Y) { + DRM_DEBUG("hardware does not support tiling Y\n"); + return -EINVAL; + } + + if (mode_cmd->pitches[0] & 63) { + DRM_DEBUG("pitch (%d) must be at least 64 byte aligned\n", + mode_cmd->pitches[0]); + return -EINVAL; + } + + if (INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)) { + pitch_limit = 32*1024; + } else if (INTEL_INFO(dev)->gen >= 4) { + if (obj->tiling_mode) + pitch_limit = 16*1024; + else + pitch_limit = 32*1024; + } else if (INTEL_INFO(dev)->gen >= 3) { + if (obj->tiling_mode) + pitch_limit = 8*1024; + else + pitch_limit = 16*1024; + } else + /* XXX DSPC is limited to 4k tiled */ + pitch_limit = 8*1024; + + if (mode_cmd->pitches[0] > pitch_limit) { + DRM_DEBUG("%s pitch (%d) must be at less than %d\n", + obj->tiling_mode ? "tiled" : "linear", + mode_cmd->pitches[0], pitch_limit); + return -EINVAL; + } + + if (obj->tiling_mode != I915_TILING_NONE && + mode_cmd->pitches[0] != obj->stride) { + DRM_DEBUG("pitch (%d) must match tiling stride (%d)\n", + mode_cmd->pitches[0], obj->stride); + return -EINVAL; + } + + /* Reject formats not supported by any plane early. */ + switch (mode_cmd->pixel_format) { + case DRM_FORMAT_C8: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: + if (INTEL_INFO(dev)->gen > 3) { + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); + return -EINVAL; + } + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + if (INTEL_INFO(dev)->gen < 4) { + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); + return -EINVAL; + } + break; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_VYUY: + if (INTEL_INFO(dev)->gen < 5) { + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); + return -EINVAL; + } + break; + default: + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); + return -EINVAL; + } + + /* FIXME need to adjust LINOFF/TILEOFF accordingly. */ + if (mode_cmd->offsets[0] != 0) + return -EINVAL; + + tile_height = IS_GEN2(dev) ? 16 : 8; + aligned_height = ALIGN(mode_cmd->height, + obj->tiling_mode ? tile_height : 1); + /* FIXME drm helper for size checks (especially planar formats)? */ + if (obj->base.size < aligned_height * mode_cmd->pitches[0]) + return -EINVAL; + + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); + intel_fb->obj = obj; + intel_fb->obj->framebuffer_references++; + + ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); + if (ret) { + DRM_ERROR("framebuffer init failed %d\n", ret); + return ret; + } + + return 0; +} + +static struct drm_framebuffer * +intel_user_framebuffer_create(struct drm_device *dev, + struct drm_file *filp, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_i915_gem_object *obj; + + obj = to_intel_bo(drm_gem_object_lookup(dev, filp, + mode_cmd->handles[0])); + if (&obj->base == NULL) + return ERR_PTR(-ENOENT); + + return intel_framebuffer_create(dev, mode_cmd, obj); +} + +#ifndef CONFIG_DRM_I915_FBDEV +static inline void intel_fbdev_output_poll_changed(struct drm_device *dev) +{ +} +#endif + +static const struct drm_mode_config_funcs intel_mode_funcs = { + .fb_create = intel_user_framebuffer_create, + .output_poll_changed = intel_fbdev_output_poll_changed, +}; + +/* Set up chip specific display functions */ +static void intel_init_display(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_SPLIT(dev) || IS_G4X(dev)) + dev_priv->display.find_dpll = g4x_find_best_dpll; + else if (IS_VALLEYVIEW(dev)) + dev_priv->display.find_dpll = vlv_find_best_dpll; + else if (IS_PINEVIEW(dev)) + dev_priv->display.find_dpll = pnv_find_best_dpll; + else + dev_priv->display.find_dpll = i9xx_find_best_dpll; + + if (HAS_DDI(dev)) { + dev_priv->display.get_pipe_config = haswell_get_pipe_config; + dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; + dev_priv->display.crtc_enable = haswell_crtc_enable; + dev_priv->display.crtc_disable = haswell_crtc_disable; + dev_priv->display.off = haswell_crtc_off; + dev_priv->display.update_plane = ironlake_update_plane; + } else if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.get_pipe_config = ironlake_get_pipe_config; + dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; + dev_priv->display.crtc_enable = ironlake_crtc_enable; + dev_priv->display.crtc_disable = ironlake_crtc_disable; + dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.update_plane = ironlake_update_plane; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.get_pipe_config = i9xx_get_pipe_config; + dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + dev_priv->display.crtc_enable = valleyview_crtc_enable; + dev_priv->display.crtc_disable = i9xx_crtc_disable; + dev_priv->display.off = i9xx_crtc_off; + dev_priv->display.update_plane = i9xx_update_plane; + } else { + dev_priv->display.get_pipe_config = i9xx_get_pipe_config; + dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + dev_priv->display.crtc_enable = i9xx_crtc_enable; + dev_priv->display.crtc_disable = i9xx_crtc_disable; + dev_priv->display.off = i9xx_crtc_off; + dev_priv->display.update_plane = i9xx_update_plane; + } + + /* Returns the core display clock speed */ + if (IS_VALLEYVIEW(dev)) + dev_priv->display.get_display_clock_speed = + valleyview_get_display_clock_speed; + else if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev))) + dev_priv->display.get_display_clock_speed = + i945_get_display_clock_speed; + else if (IS_I915G(dev)) + dev_priv->display.get_display_clock_speed = + i915_get_display_clock_speed; + else if (IS_I945GM(dev) || IS_845G(dev)) + dev_priv->display.get_display_clock_speed = + i9xx_misc_get_display_clock_speed; + else if (IS_PINEVIEW(dev)) + dev_priv->display.get_display_clock_speed = + pnv_get_display_clock_speed; + else if (IS_I915GM(dev)) + dev_priv->display.get_display_clock_speed = + i915gm_get_display_clock_speed; + else if (IS_I865G(dev)) + dev_priv->display.get_display_clock_speed = + i865_get_display_clock_speed; + else if (IS_I85X(dev)) + dev_priv->display.get_display_clock_speed = + i855_get_display_clock_speed; + else /* 852, 830 */ + dev_priv->display.get_display_clock_speed = + i830_get_display_clock_speed; + + if (HAS_PCH_SPLIT(dev)) { + if (IS_GEN5(dev)) { + dev_priv->display.fdi_link_train = ironlake_fdi_link_train; + dev_priv->display.write_eld = ironlake_write_eld; + } else if (IS_GEN6(dev)) { + dev_priv->display.fdi_link_train = gen6_fdi_link_train; + dev_priv->display.write_eld = ironlake_write_eld; + } else if (IS_IVYBRIDGE(dev)) { + /* FIXME: detect B0+ stepping and use auto training */ + dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; + dev_priv->display.write_eld = ironlake_write_eld; + dev_priv->display.modeset_global_resources = + ivb_modeset_global_resources; + } else if (IS_HASWELL(dev) || IS_GEN8(dev)) { + dev_priv->display.fdi_link_train = hsw_fdi_link_train; + dev_priv->display.write_eld = haswell_write_eld; + dev_priv->display.modeset_global_resources = + haswell_modeset_global_resources; + } + } else if (IS_G4X(dev)) { + dev_priv->display.write_eld = g4x_write_eld; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.modeset_global_resources = + valleyview_modeset_global_resources; + dev_priv->display.write_eld = ironlake_write_eld; + } + + /* Default just returns -ENODEV to indicate unsupported */ + dev_priv->display.queue_flip = intel_default_queue_flip; + + switch (INTEL_INFO(dev)->gen) { + case 2: + dev_priv->display.queue_flip = intel_gen2_queue_flip; + break; + + case 3: + dev_priv->display.queue_flip = intel_gen3_queue_flip; + break; + + case 4: + case 5: + dev_priv->display.queue_flip = intel_gen4_queue_flip; + break; + + case 6: + dev_priv->display.queue_flip = intel_gen6_queue_flip; + break; + case 7: + case 8: /* FIXME(BDW): Check that the gen8 RCS flip works. */ + dev_priv->display.queue_flip = intel_gen7_queue_flip; + break; + } + + intel_panel_init_backlight_funcs(dev); +} + +/* + * Some BIOSes insist on assuming the GPU's pipe A is enabled at suspend, + * resume, or other times. This quirk makes sure that's the case for + * affected systems. + */ +static void quirk_pipea_force(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->quirks |= QUIRK_PIPEA_FORCE; + DRM_INFO("applying pipe a force quirk\n"); +} + +/* + * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason + */ +static void quirk_ssc_force_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE; + DRM_INFO("applying lvds SSC disable quirk\n"); +} + +/* + * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight + * brightness value + */ +static void quirk_invert_brightness(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS; + DRM_INFO("applying inverted panel brightness quirk\n"); +} + +struct intel_quirk { + int device; + int subsystem_vendor; + int subsystem_device; + void (*hook)(struct drm_device *dev); +}; + +/* For systems that don't have a meaningful PCI subdevice/subvendor ID */ +struct intel_dmi_quirk { + void (*hook)(struct drm_device *dev); + const struct dmi_system_id (*dmi_id_list)[]; +}; + +static int intel_dmi_reverse_brightness(const struct dmi_system_id *id) +{ + DRM_INFO("Backlight polarity reversed on %s\n", id->ident); + return 1; +} + +static const struct intel_dmi_quirk intel_dmi_quirks[] = { + { + .dmi_id_list = &(const struct dmi_system_id[]) { + { + .callback = intel_dmi_reverse_brightness, + .ident = "NCR Corporation", + .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, ""), + }, + }, + { } /* terminating entry */ + }, + .hook = quirk_invert_brightness, + }, +}; + +static struct intel_quirk intel_quirks[] = { + /* HP Mini needs pipe A force quirk (LP: #322104) */ + { 0x27ae, 0x103c, 0x361a, quirk_pipea_force }, + + /* Toshiba Protege R-205, S-209 needs pipe A force quirk */ + { 0x2592, 0x1179, 0x0001, quirk_pipea_force }, + + /* ThinkPad T60 needs pipe A force quirk (bug #16494) */ + { 0x2782, 0x17aa, 0x201a, quirk_pipea_force }, + + /* 830 needs to leave pipe A & dpll A up */ + { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, + + /* Lenovo U160 cannot use SSC on LVDS */ + { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable }, + + /* Sony Vaio Y cannot use SSC on LVDS */ + { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable }, + + /* Acer Aspire 5734Z must invert backlight brightness */ + { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness }, + + /* Acer/eMachines G725 */ + { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness }, + + /* Acer/eMachines e725 */ + { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness }, + + /* Acer/Packard Bell NCL20 */ + { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness }, + + /* Acer Aspire 4736Z */ + { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, +}; + +static void intel_init_quirks(struct drm_device *dev) +{ + struct pci_dev *d = dev->pdev; + int i; + + for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) { + struct intel_quirk *q = &intel_quirks[i]; + + if (d->device == q->device && + (d->subsystem_vendor == q->subsystem_vendor || + q->subsystem_vendor == PCI_ANY_ID) && + (d->subsystem_device == q->subsystem_device || + q->subsystem_device == PCI_ANY_ID)) + q->hook(dev); + } + for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) { + if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0) + intel_dmi_quirks[i].hook(dev); + } +} + +/* Disable the VGA plane that we never use */ +static void i915_disable_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u8 sr1; + u32 vga_reg = i915_vgacntrl_reg(dev); + + vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); + outb(SR01, VGA_SR_INDEX); + sr1 = inb(VGA_SR_DATA); + outb(sr1 | 1<<5, VGA_SR_DATA); + vga_put(dev->pdev, VGA_RSRC_LEGACY_IO); + udelay(300); + + I915_WRITE(vga_reg, VGA_DISP_DISABLE); + POSTING_READ(vga_reg); +} + +void intel_modeset_init_hw(struct drm_device *dev) +{ + intel_prepare_ddi(dev); + + intel_init_clock_gating(dev); + + intel_reset_dpio(dev); + + mutex_lock(&dev->struct_mutex); + intel_enable_gt_powersave(dev); + mutex_unlock(&dev->struct_mutex); +} + +void intel_modeset_suspend_hw(struct drm_device *dev) +{ + intel_suspend_hw(dev); +} + +void intel_modeset_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i, j, ret; + + drm_mode_config_init(dev); + + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + + dev->mode_config.preferred_depth = 24; + dev->mode_config.prefer_shadow = 1; + + dev->mode_config.funcs = &intel_mode_funcs; + + intel_init_quirks(dev); + + intel_init_pm(dev); + + if (INTEL_INFO(dev)->num_pipes == 0) + return; + + intel_init_display(dev); + + if (IS_GEN2(dev)) { + dev->mode_config.max_width = 2048; + dev->mode_config.max_height = 2048; + } else if (IS_GEN3(dev)) { + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; + } else { + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; + } + dev->mode_config.fb_base = dev_priv->gtt.mappable_base; + + DRM_DEBUG_KMS("%d display pipe%s available.\n", + INTEL_INFO(dev)->num_pipes, + INTEL_INFO(dev)->num_pipes > 1 ? "s" : ""); + + for_each_pipe(i) { + intel_crtc_init(dev, i); + for (j = 0; j < dev_priv->num_plane; j++) { + ret = intel_plane_init(dev, i, j); + if (ret) + DRM_DEBUG_KMS("pipe %c sprite %c init failed: %d\n", + pipe_name(i), sprite_name(i, j), ret); + } + } + + intel_init_dpio(dev); + intel_reset_dpio(dev); + + intel_cpu_pll_init(dev); + intel_shared_dpll_init(dev); + + /* Just disable it once at startup */ + i915_disable_vga(dev); + intel_setup_outputs(dev); + + /* Just in case the BIOS is doing something questionable. */ + intel_disable_fbc(dev); +} + +static void +intel_connector_break_all_links(struct intel_connector *connector) +{ + connector->base.dpms = DRM_MODE_DPMS_OFF; + connector->base.encoder = NULL; + connector->encoder->connectors_active = false; + connector->encoder->base.crtc = NULL; +} + +static void intel_enable_pipe_a(struct drm_device *dev) +{ + struct intel_connector *connector; + struct drm_connector *crt = NULL; + struct intel_load_detect_pipe load_detect_temp; + + /* We can't just switch on the pipe A, we need to set things up with a + * proper mode and output configuration. As a gross hack, enable pipe A + * by enabling the load detect pipe once. */ + list_for_each_entry(connector, + &dev->mode_config.connector_list, + base.head) { + if (connector->encoder->type == INTEL_OUTPUT_ANALOG) { + crt = &connector->base; + break; + } + } + + if (!crt) + return; + + if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp)) + intel_release_load_detect_pipe(crt, &load_detect_temp); + + +} + +static bool +intel_check_plane_mapping(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg, val; + + if (INTEL_INFO(dev)->num_pipes == 1) + return true; + + reg = DSPCNTR(!crtc->plane); + val = I915_READ(reg); + + if ((val & DISPLAY_PLANE_ENABLE) && + (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe)) + return false; + + return true; +} + +static void intel_sanitize_crtc(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + + /* Clear any frame start delays used for debugging left by the BIOS */ + reg = PIPECONF(crtc->config.cpu_transcoder); + I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); + + /* We need to sanitize the plane -> pipe mapping first because this will + * disable the crtc (and hence change the state) if it is wrong. Note + * that gen4+ has a fixed plane -> pipe mapping. */ + if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) { + struct intel_connector *connector; + bool plane; + + DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n", + crtc->base.base.id); + + /* Pipe has the wrong plane attached and the plane is active. + * Temporarily change the plane mapping and disable everything + * ... */ + plane = crtc->plane; + crtc->plane = !plane; + dev_priv->display.crtc_disable(&crtc->base); + crtc->plane = plane; + + /* ... and break all links. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->encoder->base.crtc != &crtc->base) + continue; + + intel_connector_break_all_links(connector); + } + + WARN_ON(crtc->active); + crtc->base.enabled = false; + } + + if (dev_priv->quirks & QUIRK_PIPEA_FORCE && + crtc->pipe == PIPE_A && !crtc->active) { + /* BIOS forgot to enable pipe A, this mostly happens after + * resume. Force-enable the pipe to fix this, the update_dpms + * call below we restore the pipe to the right state, but leave + * the required bits on. */ + intel_enable_pipe_a(dev); + } + + /* Adjust the state of the output pipe according to whether we + * have active connectors/encoders. */ + intel_crtc_update_dpms(&crtc->base); + + if (crtc->active != crtc->base.enabled) { + struct intel_encoder *encoder; + + /* This can happen either due to bugs in the get_hw_state + * functions or because the pipe is force-enabled due to the + * pipe A quirk. */ + DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n", + crtc->base.base.id, + crtc->base.enabled ? "enabled" : "disabled", + crtc->active ? "enabled" : "disabled"); + + crtc->base.enabled = crtc->active; + + /* Because we only establish the connector -> encoder -> + * crtc links if something is active, this means the + * crtc is now deactivated. Break the links. connector + * -> encoder links are only establish when things are + * actually up, hence no need to break them. */ + WARN_ON(crtc->active); + + for_each_encoder_on_crtc(dev, &crtc->base, encoder) { + WARN_ON(encoder->connectors_active); + encoder->base.crtc = NULL; + } + } +} + +static void intel_sanitize_encoder(struct intel_encoder *encoder) +{ + struct intel_connector *connector; + struct drm_device *dev = encoder->base.dev; + + /* We need to check both for a crtc link (meaning that the + * encoder is active and trying to read from a pipe) and the + * pipe itself being active. */ + bool has_active_crtc = encoder->base.crtc && + to_intel_crtc(encoder->base.crtc)->active; + + if (encoder->connectors_active && !has_active_crtc) { + DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base)); + + /* Connector is active, but has no active pipe. This is + * fallout from our resume register restoring. Disable + * the encoder manually again. */ + if (encoder->base.crtc) { + DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base)); + encoder->disable(encoder); + } + + /* Inconsistent output/port/pipe state happens presumably due to + * a bug in one of the get_hw_state functions. Or someplace else + * in our code, like the register restore mess on resume. Clamp + * things to off as a safer default. */ + list_for_each_entry(connector, + &dev->mode_config.connector_list, + base.head) { + if (connector->encoder != encoder) + continue; + + intel_connector_break_all_links(connector); + } + } + /* Enabled encoders without active connectors will be fixed in + * the crtc fixup. */ +} + +void i915_redisable_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 vga_reg = i915_vgacntrl_reg(dev); + + /* This function can be called both from intel_modeset_setup_hw_state or + * at a very early point in our resume sequence, where the power well + * structures are not yet restored. Since this function is at a very + * paranoid "someone might have enabled VGA while we were not looking" + * level, just check if the power well is enabled instead of trying to + * follow the "don't touch the power well if we don't need it" policy + * the rest of the driver uses. */ + if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && + (I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_STATE_ENABLED) == 0) + return; + + if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) { + DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); + i915_disable_vga(dev); + } +} + +static void intel_modeset_readout_hw_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_connector *connector; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + memset(&crtc->config, 0, sizeof(crtc->config)); + + crtc->active = dev_priv->display.get_pipe_config(crtc, + &crtc->config); + + crtc->base.enabled = crtc->active; + crtc->primary_enabled = crtc->active; + + DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", + crtc->base.base.id, + crtc->active ? "enabled" : "disabled"); + } + + /* FIXME: Smash this into the new shared dpll infrastructure. */ + if (HAS_DDI(dev)) + intel_ddi_setup_hw_pll_state(dev); + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + + pll->on = pll->get_hw_state(dev_priv, pll, &pll->hw_state); + pll->active = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) + pll->active++; + } + pll->refcount = pll->active; + + DRM_DEBUG_KMS("%s hw state readout: refcount %i, on %i\n", + pll->name, pll->refcount, pll->on); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + pipe = 0; + + if (encoder->get_hw_state(encoder, &pipe)) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + encoder->base.crtc = &crtc->base; + encoder->get_config(encoder, &crtc->config); + } else { + encoder->base.crtc = NULL; + } + + encoder->connectors_active = false; + DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base), + encoder->base.crtc ? "enabled" : "disabled", + pipe_name(pipe)); + } + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->get_hw_state(connector)) { + connector->base.dpms = DRM_MODE_DPMS_ON; + connector->encoder->connectors_active = true; + connector->base.encoder = &connector->encoder->base; + } else { + connector->base.dpms = DRM_MODE_DPMS_OFF; + connector->base.encoder = NULL; + } + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", + connector->base.base.id, + drm_get_connector_name(&connector->base), + connector->base.encoder ? "enabled" : "disabled"); + } +} + +/* Scan out the current hw modeset state, sanitizes it and maps it into the drm + * and i915 state tracking structures. */ +void intel_modeset_setup_hw_state(struct drm_device *dev, + bool force_restore) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + int i; + + intel_modeset_readout_hw_state(dev); + + /* + * Now that we have the config, copy it to each CRTC struct + * Note that this could go away if we move to using crtc_config + * checking everywhere. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (crtc->active && i915_fastboot) { + intel_crtc_mode_from_pipe_config(crtc, &crtc->config); + + DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", + crtc->base.base.id); + drm_mode_debug_printmodeline(&crtc->base.mode); + } + } + + /* HW state is read out, now we need to sanitize this mess. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + intel_sanitize_encoder(encoder); + } + + for_each_pipe(pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + intel_sanitize_crtc(crtc); + intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]"); + } + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + + if (!pll->on || pll->active) + continue; + + DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name); + + pll->disable(dev_priv, pll); + pll->on = false; + } + + if (HAS_PCH_SPLIT(dev)) + ilk_wm_get_hw_state(dev); + + if (force_restore) { + i915_redisable_vga(dev); + + /* + * We need to use raw interfaces for restoring state to avoid + * checking (bogus) intermediate states. + */ + for_each_pipe(pipe) { + struct drm_crtc *crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + + __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, + crtc->fb); + } + } else { + intel_modeset_update_staged_output_state(dev); + } + + intel_modeset_check_state(dev); +} + +void intel_modeset_gem_init(struct drm_device *dev) +{ + intel_modeset_init_hw(dev); + + intel_setup_overlay(dev); + + mutex_lock(&dev->mode_config.mutex); + drm_mode_config_reset(dev); + intel_modeset_setup_hw_state(dev, false); + mutex_unlock(&dev->mode_config.mutex); +} + +void intel_modeset_cleanup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + struct drm_connector *connector; + + /* + * Interrupts and polling as the first thing to avoid creating havoc. + * Too much stuff here (turning of rps, connectors, ...) would + * experience fancy races otherwise. + */ + drm_irq_uninstall(dev); + cancel_work_sync(&dev_priv->hotplug_work); + /* + * Due to the hpd irq storm handling the hotplug work can re-arm the + * poll handlers. Hence disable polling after hpd handling is shut down. + */ + drm_kms_helper_poll_fini(dev); + + mutex_lock(&dev->struct_mutex); + + intel_unregister_dsm_handler(); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + /* Skip inactive CRTCs */ + if (!crtc->fb) + continue; + + intel_increase_pllclock(crtc); + } + + intel_disable_fbc(dev); + + intel_disable_gt_powersave(dev); + + ironlake_teardown_rc6(dev); + + mutex_unlock(&dev->struct_mutex); + + /* flush any delayed tasks or pending work */ + flush_scheduled_work(); + + /* destroy the backlight and sysfs files before encoders/connectors */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + intel_panel_destroy_backlight(connector); + drm_sysfs_connector_remove(connector); + } + + drm_mode_config_cleanup(dev); + + intel_cleanup_overlay(dev); +} + +/* + * Return which encoder is currently attached for connector. + */ +struct drm_encoder *intel_best_encoder(struct drm_connector *connector) +{ + return &intel_attached_encoder(connector)->base; +} + +void intel_connector_attach_encoder(struct intel_connector *connector, + struct intel_encoder *encoder) +{ + connector->encoder = encoder; + drm_mode_connector_attach_encoder(&connector->base, + &encoder->base); +} + +/* + * set vga decode state - true == enable VGA decode + */ +int intel_modeset_vga_set_state(struct drm_device *dev, bool state) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned reg = INTEL_INFO(dev)->gen >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL; + u16 gmch_ctrl; + + pci_read_config_word(dev_priv->bridge_dev, reg, &gmch_ctrl); + if (state) + gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE; + else + gmch_ctrl |= INTEL_GMCH_VGA_DISABLE; + pci_write_config_word(dev_priv->bridge_dev, reg, gmch_ctrl); + return 0; +} + +struct intel_display_error_state { + + u32 power_well_driver; + + int num_transcoders; + + struct intel_cursor_error_state { + u32 control; + u32 position; + u32 base; + u32 size; + } cursor[I915_MAX_PIPES]; + + struct intel_pipe_error_state { + bool power_domain_on; + u32 source; + } pipe[I915_MAX_PIPES]; + + struct intel_plane_error_state { + u32 control; + u32 stride; + u32 size; + u32 pos; + u32 addr; + u32 surface; + u32 tile_offset; + } plane[I915_MAX_PIPES]; + + struct intel_transcoder_error_state { + bool power_domain_on; + enum transcoder cpu_transcoder; + + u32 conf; + + u32 htotal; + u32 hblank; + u32 hsync; + u32 vtotal; + u32 vblank; + u32 vsync; + } transcoder[4]; +}; + +struct intel_display_error_state * +intel_display_capture_error_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_display_error_state *error; + int transcoders[] = { + TRANSCODER_A, + TRANSCODER_B, + TRANSCODER_C, + TRANSCODER_EDP, + }; + int i; + + if (INTEL_INFO(dev)->num_pipes == 0) + return NULL; + + error = kzalloc(sizeof(*error), GFP_ATOMIC); + if (error == NULL) + return NULL; + + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER); + + for_each_pipe(i) { + error->pipe[i].power_domain_on = + intel_display_power_enabled_sw(dev, POWER_DOMAIN_PIPE(i)); + if (!error->pipe[i].power_domain_on) + continue; + + if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { + error->cursor[i].control = I915_READ(CURCNTR(i)); + error->cursor[i].position = I915_READ(CURPOS(i)); + error->cursor[i].base = I915_READ(CURBASE(i)); + } else { + error->cursor[i].control = I915_READ(CURCNTR_IVB(i)); + error->cursor[i].position = I915_READ(CURPOS_IVB(i)); + error->cursor[i].base = I915_READ(CURBASE_IVB(i)); + } + + error->plane[i].control = I915_READ(DSPCNTR(i)); + error->plane[i].stride = I915_READ(DSPSTRIDE(i)); + if (INTEL_INFO(dev)->gen <= 3) { + error->plane[i].size = I915_READ(DSPSIZE(i)); + error->plane[i].pos = I915_READ(DSPPOS(i)); + } + if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) + error->plane[i].addr = I915_READ(DSPADDR(i)); + if (INTEL_INFO(dev)->gen >= 4) { + error->plane[i].surface = I915_READ(DSPSURF(i)); + error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i)); + } + + error->pipe[i].source = I915_READ(PIPESRC(i)); + } + + error->num_transcoders = INTEL_INFO(dev)->num_pipes; + if (HAS_DDI(dev_priv->dev)) + error->num_transcoders++; /* Account for eDP. */ + + for (i = 0; i < error->num_transcoders; i++) { + enum transcoder cpu_transcoder = transcoders[i]; + + error->transcoder[i].power_domain_on = + intel_display_power_enabled_sw(dev, + POWER_DOMAIN_TRANSCODER(cpu_transcoder)); + if (!error->transcoder[i].power_domain_on) + continue; + + error->transcoder[i].cpu_transcoder = cpu_transcoder; + + error->transcoder[i].conf = I915_READ(PIPECONF(cpu_transcoder)); + error->transcoder[i].htotal = I915_READ(HTOTAL(cpu_transcoder)); + error->transcoder[i].hblank = I915_READ(HBLANK(cpu_transcoder)); + error->transcoder[i].hsync = I915_READ(HSYNC(cpu_transcoder)); + error->transcoder[i].vtotal = I915_READ(VTOTAL(cpu_transcoder)); + error->transcoder[i].vblank = I915_READ(VBLANK(cpu_transcoder)); + error->transcoder[i].vsync = I915_READ(VSYNC(cpu_transcoder)); + } + + return error; +} + +#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) + +void +intel_display_print_error_state(struct drm_i915_error_state_buf *m, + struct drm_device *dev, + struct intel_display_error_state *error) +{ + int i; + + if (!error) + return; + + err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + err_printf(m, "PWR_WELL_CTL2: %08x\n", + error->power_well_driver); + for_each_pipe(i) { + err_printf(m, "Pipe [%d]:\n", i); + err_printf(m, " Power: %s\n", + error->pipe[i].power_domain_on ? "on" : "off"); + err_printf(m, " SRC: %08x\n", error->pipe[i].source); + + err_printf(m, "Plane [%d]:\n", i); + err_printf(m, " CNTR: %08x\n", error->plane[i].control); + err_printf(m, " STRIDE: %08x\n", error->plane[i].stride); + if (INTEL_INFO(dev)->gen <= 3) { + err_printf(m, " SIZE: %08x\n", error->plane[i].size); + err_printf(m, " POS: %08x\n", error->plane[i].pos); + } + if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) + err_printf(m, " ADDR: %08x\n", error->plane[i].addr); + if (INTEL_INFO(dev)->gen >= 4) { + err_printf(m, " SURF: %08x\n", error->plane[i].surface); + err_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); + } + + err_printf(m, "Cursor [%d]:\n", i); + err_printf(m, " CNTR: %08x\n", error->cursor[i].control); + err_printf(m, " POS: %08x\n", error->cursor[i].position); + err_printf(m, " BASE: %08x\n", error->cursor[i].base); + } + + for (i = 0; i < error->num_transcoders; i++) { + err_printf(m, "CPU transcoder: %c\n", + transcoder_name(error->transcoder[i].cpu_transcoder)); + err_printf(m, " Power: %s\n", + error->transcoder[i].power_domain_on ? "on" : "off"); + err_printf(m, " CONF: %08x\n", error->transcoder[i].conf); + err_printf(m, " HTOTAL: %08x\n", error->transcoder[i].htotal); + err_printf(m, " HBLANK: %08x\n", error->transcoder[i].hblank); + err_printf(m, " HSYNC: %08x\n", error->transcoder[i].hsync); + err_printf(m, " VTOTAL: %08x\n", error->transcoder[i].vtotal); + err_printf(m, " VBLANK: %08x\n", error->transcoder[i].vblank); + err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync); + } +} --- linux-3.13.0.orig/ubuntu/i915/intel_ddi.c +++ linux-3.13.0/ubuntu/i915/intel_ddi.c @@ -0,0 +1,1638 @@ +/* + * Copyright © 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eugeni Dodonov + * + */ + +#include "i915_drv.h" +#include "intel_drv.h" + +/* HDMI/DVI modes ignore everything but the last 2 items. So we share + * them for both DP and FDI transports, allowing those ports to + * automatically adapt to HDMI connections as well + */ +static const u32 hsw_ddi_translations_dp[] = { + 0x00FFFFFF, 0x0006000E, /* DP parameters */ + 0x00D75FFF, 0x0005000A, + 0x00C30FFF, 0x00040006, + 0x80AAAFFF, 0x000B0000, + 0x00FFFFFF, 0x0005000A, + 0x00D75FFF, 0x000C0004, + 0x80C30FFF, 0x000B0000, + 0x00FFFFFF, 0x00040006, + 0x80D75FFF, 0x000B0000, +}; + +static const u32 hsw_ddi_translations_fdi[] = { + 0x00FFFFFF, 0x0007000E, /* FDI parameters */ + 0x00D75FFF, 0x000F000A, + 0x00C30FFF, 0x00060006, + 0x00AAAFFF, 0x001E0000, + 0x00FFFFFF, 0x000F000A, + 0x00D75FFF, 0x00160004, + 0x00C30FFF, 0x001E0000, + 0x00FFFFFF, 0x00060006, + 0x00D75FFF, 0x001E0000, +}; + +static const u32 hsw_ddi_translations_hdmi[] = { + /* Idx NT mV diff T mV diff db */ + 0x00FFFFFF, 0x0006000E, /* 0: 400 400 0 */ + 0x00E79FFF, 0x000E000C, /* 1: 400 500 2 */ + 0x00D75FFF, 0x0005000A, /* 2: 400 600 3.5 */ + 0x00FFFFFF, 0x0005000A, /* 3: 600 600 0 */ + 0x00E79FFF, 0x001D0007, /* 4: 600 750 2 */ + 0x00D75FFF, 0x000C0004, /* 5: 600 900 3.5 */ + 0x00FFFFFF, 0x00040006, /* 6: 800 800 0 */ + 0x80E79FFF, 0x00030002, /* 7: 800 1000 2 */ + 0x00FFFFFF, 0x00140005, /* 8: 850 850 0 */ + 0x00FFFFFF, 0x000C0004, /* 9: 900 900 0 */ + 0x00FFFFFF, 0x001C0003, /* 10: 950 950 0 */ + 0x80FFFFFF, 0x00030002, /* 11: 1000 1000 0 */ +}; + +static const u32 bdw_ddi_translations_edp[] = { + 0x00FFFFFF, 0x00000012, /* eDP parameters */ + 0x00EBAFFF, 0x00020011, + 0x00C71FFF, 0x0006000F, + 0x00FFFFFF, 0x00020011, + 0x00DB6FFF, 0x0005000F, + 0x00BEEFFF, 0x000A000C, + 0x00FFFFFF, 0x0005000F, + 0x00DB6FFF, 0x000A000C, + 0x00FFFFFF, 0x000A000C, + 0x00FFFFFF, 0x00140006 /* HDMI parameters 800mV 0dB*/ +}; + +static const u32 bdw_ddi_translations_dp[] = { + 0x00FFFFFF, 0x0007000E, /* DP parameters */ + 0x00D75FFF, 0x000E000A, + 0x00BEFFFF, 0x00140006, + 0x00FFFFFF, 0x000E000A, + 0x00D75FFF, 0x00180004, + 0x80CB2FFF, 0x001B0002, + 0x00F7DFFF, 0x00180004, + 0x80D75FFF, 0x001B0002, + 0x80FFFFFF, 0x001B0002, + 0x00FFFFFF, 0x00140006 /* HDMI parameters 800mV 0dB*/ +}; + +static const u32 bdw_ddi_translations_fdi[] = { + 0x00FFFFFF, 0x0001000E, /* FDI parameters */ + 0x00D75FFF, 0x0004000A, + 0x00C30FFF, 0x00070006, + 0x00AAAFFF, 0x000C0000, + 0x00FFFFFF, 0x0004000A, + 0x00D75FFF, 0x00090004, + 0x00C30FFF, 0x000C0000, + 0x00FFFFFF, 0x00070006, + 0x00D75FFF, 0x000C0000, + 0x00FFFFFF, 0x00140006 /* HDMI parameters 800mV 0dB*/ +}; + +enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || + type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(encoder); + return intel_dig_port->port; + + } else if (type == INTEL_OUTPUT_ANALOG) { + return PORT_E; + + } else { + DRM_ERROR("Invalid DDI encoder type %d\n", type); + BUG(); + } +} + +/* + * Starting with Haswell, DDI port buffers must be programmed with correct + * values in advance. The buffer values are different for FDI and DP modes, + * but the HDMI/DVI fields are shared among those. So we program the DDI + * in either FDI or DP modes only, as HDMI connections will work with both + * of those + */ +static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + int i; + int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift; + const u32 *ddi_translations_fdi; + const u32 *ddi_translations_dp; + const u32 *ddi_translations_edp; + const u32 *ddi_translations; + + if (IS_BROADWELL(dev)) { + ddi_translations_fdi = bdw_ddi_translations_fdi; + ddi_translations_dp = bdw_ddi_translations_dp; + ddi_translations_edp = bdw_ddi_translations_edp; + } else if (IS_HASWELL(dev)) { + ddi_translations_fdi = hsw_ddi_translations_fdi; + ddi_translations_dp = hsw_ddi_translations_dp; + ddi_translations_edp = hsw_ddi_translations_dp; + } else { + WARN(1, "ddi translation table missing\n"); + ddi_translations_edp = bdw_ddi_translations_dp; + ddi_translations_fdi = bdw_ddi_translations_fdi; + ddi_translations_dp = bdw_ddi_translations_dp; + } + + switch (port) { + case PORT_A: + ddi_translations = ddi_translations_edp; + break; + case PORT_B: + case PORT_C: + ddi_translations = ddi_translations_dp; + break; + case PORT_D: + if (intel_dp_is_edp(dev, PORT_D)) + ddi_translations = ddi_translations_edp; + else + ddi_translations = ddi_translations_dp; + break; + case PORT_E: + ddi_translations = ddi_translations_fdi; + break; + default: + BUG(); + } + + for (i = 0, reg = DDI_BUF_TRANS(port); + i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) { + I915_WRITE(reg, ddi_translations[i]); + reg += 4; + } + /* Entry 9 is for HDMI: */ + for (i = 0; i < 2; i++) { + I915_WRITE(reg, hsw_ddi_translations_hdmi[hdmi_level * 2 + i]); + reg += 4; + } +} + +/* Program DDI buffers translations for DP. By default, program ports A-D in DP + * mode and port E for FDI. + */ +void intel_prepare_ddi(struct drm_device *dev) +{ + int port; + + if (!HAS_DDI(dev)) + return; + + for (port = PORT_A; port <= PORT_E; port++) + intel_prepare_ddi_buffers(dev, port); +} + +static const long hsw_ddi_buf_ctl_values[] = { + DDI_BUF_EMP_400MV_0DB_HSW, + DDI_BUF_EMP_400MV_3_5DB_HSW, + DDI_BUF_EMP_400MV_6DB_HSW, + DDI_BUF_EMP_400MV_9_5DB_HSW, + DDI_BUF_EMP_600MV_0DB_HSW, + DDI_BUF_EMP_600MV_3_5DB_HSW, + DDI_BUF_EMP_600MV_6DB_HSW, + DDI_BUF_EMP_800MV_0DB_HSW, + DDI_BUF_EMP_800MV_3_5DB_HSW +}; + +static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, + enum port port) +{ + uint32_t reg = DDI_BUF_CTL(port); + int i; + + for (i = 0; i < 8; i++) { + udelay(1); + if (I915_READ(reg) & DDI_BUF_IS_IDLE) + return; + } + DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port)); +} + +/* Starting with Haswell, different DDI ports can work in FDI mode for + * connection to the PCH-located connectors. For this, it is necessary to train + * both the DDI port and PCH receiver for the desired DDI buffer settings. + * + * The recommended port to work in FDI mode is DDI E, which we use here. Also, + * please note that when FDI mode is active on DDI E, it shares 2 lines with + * DDI A (which is used for eDP) + */ + +void hsw_fdi_link_train(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 temp, i, rx_ctl_val; + + /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the + * mode set "sequence for CRT port" document: + * - TP1 to TP2 time with the default value + * - FDI delay to 90h + * + * WaFDIAutoLinkSetTimingOverrride:hsw + */ + I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) | + FDI_RX_PWRDN_LANE0_VAL(2) | + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + + /* Enable the PCH Receiver FDI PLL */ + rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | + FDI_RX_PLL_ENABLE | + FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + POSTING_READ(_FDI_RXA_CTL); + udelay(220); + + /* Switch from Rawclk to PCDclk */ + rx_ctl_val |= FDI_PCDCLK; + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + + /* Configure Port Clock Select */ + I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->ddi_pll_sel); + + /* Start the training iterating through available voltages and emphasis, + * testing each value twice. */ + for (i = 0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values) * 2; i++) { + /* Configure DP_TP_CTL with auto-training */ + I915_WRITE(DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_LINK_TRAIN_PAT1 | + DP_TP_CTL_ENABLE); + + /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. + * DDI E does not support port reversal, the functionality is + * achieved on the PCH side in FDI_RX_CTL, so no need to set the + * port reversal bit */ + I915_WRITE(DDI_BUF_CTL(PORT_E), + DDI_BUF_CTL_ENABLE | + ((intel_crtc->config.fdi_lanes - 1) << 1) | + hsw_ddi_buf_ctl_values[i / 2]); + POSTING_READ(DDI_BUF_CTL(PORT_E)); + + udelay(600); + + /* Program PCH FDI Receiver TU */ + I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64)); + + /* Enable PCH FDI Receiver with auto-training */ + rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + POSTING_READ(_FDI_RXA_CTL); + + /* Wait for FDI receiver lane calibration */ + udelay(30); + + /* Unset FDI_RX_MISC pwrdn lanes */ + temp = I915_READ(_FDI_RXA_MISC); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + I915_WRITE(_FDI_RXA_MISC, temp); + POSTING_READ(_FDI_RXA_MISC); + + /* Wait for FDI auto training time */ + udelay(5); + + temp = I915_READ(DP_TP_STATUS(PORT_E)); + if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { + DRM_DEBUG_KMS("FDI link training done on step %d\n", i); + + /* Enable normal pixel sending for FDI */ + I915_WRITE(DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_LINK_TRAIN_NORMAL | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_ENABLE); + + return; + } + + temp = I915_READ(DDI_BUF_CTL(PORT_E)); + temp &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(PORT_E), temp); + POSTING_READ(DDI_BUF_CTL(PORT_E)); + + /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ + temp = I915_READ(DP_TP_CTL(PORT_E)); + temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + temp |= DP_TP_CTL_LINK_TRAIN_PAT1; + I915_WRITE(DP_TP_CTL(PORT_E), temp); + POSTING_READ(DP_TP_CTL(PORT_E)); + + intel_wait_ddi_buf_idle(dev_priv, PORT_E); + + rx_ctl_val &= ~FDI_RX_ENABLE; + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + POSTING_READ(_FDI_RXA_CTL); + + /* Reset FDI_RX_MISC pwrdn lanes */ + temp = I915_READ(_FDI_RXA_MISC); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); + I915_WRITE(_FDI_RXA_MISC, temp); + POSTING_READ(_FDI_RXA_MISC); + } + + DRM_ERROR("FDI link training failed!\n"); +} + +static void intel_ddi_mode_set(struct intel_encoder *encoder) +{ + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + int port = intel_ddi_get_encoder_port(encoder); + int pipe = crtc->pipe; + int type = encoder->type; + struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; + + DRM_DEBUG_KMS("Preparing DDI mode on port %c, pipe %c\n", + port_name(port), pipe_name(pipe)); + + crtc->eld_vld = false; + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(&encoder->base); + + intel_dp->DP = intel_dig_port->saved_port_bits | + DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; + intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count); + + if (intel_dp->has_audio) { + DRM_DEBUG_DRIVER("DP audio on pipe %c on DDI\n", + pipe_name(crtc->pipe)); + + /* write eld */ + DRM_DEBUG_DRIVER("DP audio: write eld information\n"); + intel_write_eld(&encoder->base, adjusted_mode); + } + } else if (type == INTEL_OUTPUT_HDMI) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + + if (intel_hdmi->has_audio) { + /* Proper support for digital audio needs a new logic + * and a new set of registers, so we leave it for future + * patch bombing. + */ + DRM_DEBUG_DRIVER("HDMI audio on pipe %c on DDI\n", + pipe_name(crtc->pipe)); + + /* write eld */ + DRM_DEBUG_DRIVER("HDMI audio: write eld information\n"); + intel_write_eld(&encoder->base, adjusted_mode); + } + + intel_hdmi->set_infoframes(&encoder->base, adjusted_mode); + } +} + +static struct intel_encoder * +intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder, *ret = NULL; + int num_encoders = 0; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + ret = intel_encoder; + num_encoders++; + } + + if (num_encoders != 1) + WARN(1, "%d encoders on crtc for pipe %c\n", num_encoders, + pipe_name(intel_crtc->pipe)); + + BUG_ON(ret == NULL); + return ret; +} + +void intel_ddi_put_crtc_pll(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t val; + + switch (intel_crtc->ddi_pll_sel) { + case PORT_CLK_SEL_SPLL: + plls->spll_refcount--; + if (plls->spll_refcount == 0) { + DRM_DEBUG_KMS("Disabling SPLL\n"); + val = I915_READ(SPLL_CTL); + WARN_ON(!(val & SPLL_PLL_ENABLE)); + I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE); + POSTING_READ(SPLL_CTL); + } + break; + case PORT_CLK_SEL_WRPLL1: + plls->wrpll1_refcount--; + if (plls->wrpll1_refcount == 0) { + DRM_DEBUG_KMS("Disabling WRPLL 1\n"); + val = I915_READ(WRPLL_CTL1); + WARN_ON(!(val & WRPLL_PLL_ENABLE)); + I915_WRITE(WRPLL_CTL1, val & ~WRPLL_PLL_ENABLE); + POSTING_READ(WRPLL_CTL1); + } + break; + case PORT_CLK_SEL_WRPLL2: + plls->wrpll2_refcount--; + if (plls->wrpll2_refcount == 0) { + DRM_DEBUG_KMS("Disabling WRPLL 2\n"); + val = I915_READ(WRPLL_CTL2); + WARN_ON(!(val & WRPLL_PLL_ENABLE)); + I915_WRITE(WRPLL_CTL2, val & ~WRPLL_PLL_ENABLE); + POSTING_READ(WRPLL_CTL2); + } + break; + } + + WARN(plls->spll_refcount < 0, "Invalid SPLL refcount\n"); + WARN(plls->wrpll1_refcount < 0, "Invalid WRPLL1 refcount\n"); + WARN(plls->wrpll2_refcount < 0, "Invalid WRPLL2 refcount\n"); + + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE; +} + +#define LC_FREQ 2700 +#define LC_FREQ_2K (LC_FREQ * 2000) + +#define P_MIN 2 +#define P_MAX 64 +#define P_INC 2 + +/* Constraints for PLL good behavior */ +#define REF_MIN 48 +#define REF_MAX 400 +#define VCO_MIN 2400 +#define VCO_MAX 4800 + +#define ABS_DIFF(a, b) ((a > b) ? (a - b) : (b - a)) + +struct wrpll_rnp { + unsigned p, n2, r2; +}; + +static unsigned wrpll_get_budget_for_freq(int clock) +{ + unsigned budget; + + switch (clock) { + case 25175000: + case 25200000: + case 27000000: + case 27027000: + case 37762500: + case 37800000: + case 40500000: + case 40541000: + case 54000000: + case 54054000: + case 59341000: + case 59400000: + case 72000000: + case 74176000: + case 74250000: + case 81000000: + case 81081000: + case 89012000: + case 89100000: + case 108000000: + case 108108000: + case 111264000: + case 111375000: + case 148352000: + case 148500000: + case 162000000: + case 162162000: + case 222525000: + case 222750000: + case 296703000: + case 297000000: + budget = 0; + break; + case 233500000: + case 245250000: + case 247750000: + case 253250000: + case 298000000: + budget = 1500; + break; + case 169128000: + case 169500000: + case 179500000: + case 202000000: + budget = 2000; + break; + case 256250000: + case 262500000: + case 270000000: + case 272500000: + case 273750000: + case 280750000: + case 281250000: + case 286000000: + case 291750000: + budget = 4000; + break; + case 267250000: + case 268500000: + budget = 5000; + break; + default: + budget = 1000; + break; + } + + return budget; +} + +static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, + unsigned r2, unsigned n2, unsigned p, + struct wrpll_rnp *best) +{ + uint64_t a, b, c, d, diff, diff_best; + + /* No best (r,n,p) yet */ + if (best->p == 0) { + best->p = p; + best->n2 = n2; + best->r2 = r2; + return; + } + + /* + * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to + * freq2k. + * + * delta = 1e6 * + * abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) / + * freq2k; + * + * and we would like delta <= budget. + * + * If the discrepancy is above the PPM-based budget, always prefer to + * improve upon the previous solution. However, if you're within the + * budget, try to maximize Ref * VCO, that is N / (P * R^2). + */ + a = freq2k * budget * p * r2; + b = freq2k * budget * best->p * best->r2; + diff = ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2)); + diff_best = ABS_DIFF((freq2k * best->p * best->r2), + (LC_FREQ_2K * best->n2)); + c = 1000000 * diff; + d = 1000000 * diff_best; + + if (a < c && b < d) { + /* If both are above the budget, pick the closer */ + if (best->p * best->r2 * diff < p * r2 * diff_best) { + best->p = p; + best->n2 = n2; + best->r2 = r2; + } + } else if (a >= c && b < d) { + /* If A is below the threshold but B is above it? Update. */ + best->p = p; + best->n2 = n2; + best->r2 = r2; + } else if (a >= c && b >= d) { + /* Both are below the limit, so pick the higher n2/(r2*r2) */ + if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) { + best->p = p; + best->n2 = n2; + best->r2 = r2; + } + } + /* Otherwise a < c && b >= d, do nothing */ +} + +static void +intel_ddi_calculate_wrpll(int clock /* in Hz */, + unsigned *r2_out, unsigned *n2_out, unsigned *p_out) +{ + uint64_t freq2k; + unsigned p, n2, r2; + struct wrpll_rnp best = { 0, 0, 0 }; + unsigned budget; + + freq2k = clock / 100; + + budget = wrpll_get_budget_for_freq(clock); + + /* Special case handling for 540 pixel clock: bypass WR PLL entirely + * and directly pass the LC PLL to it. */ + if (freq2k == 5400000) { + *n2_out = 2; + *p_out = 1; + *r2_out = 2; + return; + } + + /* + * Ref = LC_FREQ / R, where Ref is the actual reference input seen by + * the WR PLL. + * + * We want R so that REF_MIN <= Ref <= REF_MAX. + * Injecting R2 = 2 * R gives: + * REF_MAX * r2 > LC_FREQ * 2 and + * REF_MIN * r2 < LC_FREQ * 2 + * + * Which means the desired boundaries for r2 are: + * LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN + * + */ + for (r2 = LC_FREQ * 2 / REF_MAX + 1; + r2 <= LC_FREQ * 2 / REF_MIN; + r2++) { + + /* + * VCO = N * Ref, that is: VCO = N * LC_FREQ / R + * + * Once again we want VCO_MIN <= VCO <= VCO_MAX. + * Injecting R2 = 2 * R and N2 = 2 * N, we get: + * VCO_MAX * r2 > n2 * LC_FREQ and + * VCO_MIN * r2 < n2 * LC_FREQ) + * + * Which means the desired boundaries for n2 are: + * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ + */ + for (n2 = VCO_MIN * r2 / LC_FREQ + 1; + n2 <= VCO_MAX * r2 / LC_FREQ; + n2++) { + + for (p = P_MIN; p <= P_MAX; p += P_INC) + wrpll_update_rnp(freq2k, budget, + r2, n2, p, &best); + } + } + + *n2_out = best.n2; + *p_out = best.p; + *r2_out = best.r2; +} + +/* + * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and + * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to + * steal the selected PLL. You need to call intel_ddi_pll_enable to actually + * enable the PLL. + */ +bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) +{ + struct drm_crtc *crtc = &intel_crtc->base; + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + int type = intel_encoder->type; + enum pipe pipe = intel_crtc->pipe; + int clock = intel_crtc->config.port_clock; + + intel_ddi_put_crtc_pll(crtc); + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + switch (intel_dp->link_bw) { + case DP_LINK_BW_1_62: + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810; + break; + case DP_LINK_BW_2_7: + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350; + break; + case DP_LINK_BW_5_4: + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700; + break; + default: + DRM_ERROR("Link bandwidth %d unsupported\n", + intel_dp->link_bw); + return false; + } + + } else if (type == INTEL_OUTPUT_HDMI) { + uint32_t reg, val; + unsigned p, n2, r2; + + intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + + val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | + WRPLL_DIVIDER_POST(p); + + if (val == I915_READ(WRPLL_CTL1)) { + DRM_DEBUG_KMS("Reusing WRPLL 1 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL1; + } else if (val == I915_READ(WRPLL_CTL2)) { + DRM_DEBUG_KMS("Reusing WRPLL 2 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL2; + } else if (plls->wrpll1_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL1; + } else if (plls->wrpll2_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL2; + } else { + DRM_ERROR("No WRPLLs available!\n"); + return false; + } + + DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, p, n2, r2); + + if (reg == WRPLL_CTL1) { + plls->wrpll1_refcount++; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; + } else { + plls->wrpll2_refcount++; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2; + } + + } else if (type == INTEL_OUTPUT_ANALOG) { + if (plls->spll_refcount == 0) { + DRM_DEBUG_KMS("Using SPLL on pipe %c\n", + pipe_name(pipe)); + plls->spll_refcount++; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; + } else { + DRM_ERROR("SPLL already in use\n"); + return false; + } + + } else { + WARN(1, "Invalid DDI encoder type %d\n", type); + return false; + } + + return true; +} + +/* + * To be called after intel_ddi_pll_select(). That one selects the PLL to be + * used, this one actually enables the PLL. + */ +void intel_ddi_pll_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + int clock = crtc->config.port_clock; + uint32_t reg, cur_val, new_val; + int refcount; + const char *pll_name; + uint32_t enable_bit = (1 << 31); + unsigned int p, n2, r2; + + BUILD_BUG_ON(enable_bit != SPLL_PLL_ENABLE); + BUILD_BUG_ON(enable_bit != WRPLL_PLL_ENABLE); + + switch (crtc->ddi_pll_sel) { + case PORT_CLK_SEL_LCPLL_2700: + case PORT_CLK_SEL_LCPLL_1350: + case PORT_CLK_SEL_LCPLL_810: + /* + * LCPLL should always be enabled at this point of the mode set + * sequence, so nothing to do. + */ + return; + + case PORT_CLK_SEL_SPLL: + pll_name = "SPLL"; + reg = SPLL_CTL; + refcount = plls->spll_refcount; + new_val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | + SPLL_PLL_SSC; + break; + + case PORT_CLK_SEL_WRPLL1: + case PORT_CLK_SEL_WRPLL2: + if (crtc->ddi_pll_sel == PORT_CLK_SEL_WRPLL1) { + pll_name = "WRPLL1"; + reg = WRPLL_CTL1; + refcount = plls->wrpll1_refcount; + } else { + pll_name = "WRPLL2"; + reg = WRPLL_CTL2; + refcount = plls->wrpll2_refcount; + } + + intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + + new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | + WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p); + + break; + + case PORT_CLK_SEL_NONE: + WARN(1, "Bad selected pll: PORT_CLK_SEL_NONE\n"); + return; + default: + WARN(1, "Bad selected pll: 0x%08x\n", crtc->ddi_pll_sel); + return; + } + + cur_val = I915_READ(reg); + + WARN(refcount < 1, "Bad %s refcount: %d\n", pll_name, refcount); + if (refcount == 1) { + WARN(cur_val & enable_bit, "%s already enabled\n", pll_name); + I915_WRITE(reg, new_val); + POSTING_READ(reg); + udelay(20); + } else { + WARN((cur_val & enable_bit) == 0, "%s disabled\n", pll_name); + } +} + +void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + int type = intel_encoder->type; + uint32_t temp; + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + + temp = TRANS_MSA_SYNC_CLK; + switch (intel_crtc->config.pipe_bpp) { + case 18: + temp |= TRANS_MSA_6_BPC; + break; + case 24: + temp |= TRANS_MSA_8_BPC; + break; + case 30: + temp |= TRANS_MSA_10_BPC; + break; + case 36: + temp |= TRANS_MSA_12_BPC; + break; + default: + BUG(); + } + I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp); + } +} + +void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_crtc->pipe; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + uint32_t temp; + + /* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */ + temp = TRANS_DDI_FUNC_ENABLE; + temp |= TRANS_DDI_SELECT_PORT(port); + + switch (intel_crtc->config.pipe_bpp) { + case 18: + temp |= TRANS_DDI_BPC_6; + break; + case 24: + temp |= TRANS_DDI_BPC_8; + break; + case 30: + temp |= TRANS_DDI_BPC_10; + break; + case 36: + temp |= TRANS_DDI_BPC_12; + break; + default: + BUG(); + } + + if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC) + temp |= TRANS_DDI_PVSYNC; + if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC) + temp |= TRANS_DDI_PHSYNC; + + if (cpu_transcoder == TRANSCODER_EDP) { + switch (pipe) { + case PIPE_A: + /* On Haswell, can only use the always-on power well for + * eDP when not using the panel fitter, and when not + * using motion blur mitigation (which we don't + * support). */ + if (IS_HASWELL(dev) && intel_crtc->config.pch_pfit.enabled) + temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; + else + temp |= TRANS_DDI_EDP_INPUT_A_ON; + break; + case PIPE_B: + temp |= TRANS_DDI_EDP_INPUT_B_ONOFF; + break; + case PIPE_C: + temp |= TRANS_DDI_EDP_INPUT_C_ONOFF; + break; + default: + BUG(); + break; + } + } + + if (type == INTEL_OUTPUT_HDMI) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + + if (intel_hdmi->has_hdmi_sink) + temp |= TRANS_DDI_MODE_SELECT_HDMI; + else + temp |= TRANS_DDI_MODE_SELECT_DVI; + + } else if (type == INTEL_OUTPUT_ANALOG) { + temp |= TRANS_DDI_MODE_SELECT_FDI; + temp |= (intel_crtc->config.fdi_lanes - 1) << 1; + + } else if (type == INTEL_OUTPUT_DISPLAYPORT || + type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + temp |= TRANS_DDI_MODE_SELECT_DP_SST; + + temp |= DDI_PORT_WIDTH(intel_dp->lane_count); + } else { + WARN(1, "Invalid encoder type %d for pipe %c\n", + intel_encoder->type, pipe_name(pipe)); + } + + I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); +} + +void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder) +{ + uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); + uint32_t val = I915_READ(reg); + + val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK); + val |= TRANS_DDI_PORT_NONE; + I915_WRITE(reg, val); +} + +bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) +{ + struct drm_device *dev = intel_connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder = intel_connector->encoder; + int type = intel_connector->base.connector_type; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + enum pipe pipe = 0; + enum transcoder cpu_transcoder; + uint32_t tmp; + + if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) + return false; + + if (port == PORT_A) + cpu_transcoder = TRANSCODER_EDP; + else + cpu_transcoder = (enum transcoder) pipe; + + tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); + + switch (tmp & TRANS_DDI_MODE_SELECT_MASK) { + case TRANS_DDI_MODE_SELECT_HDMI: + case TRANS_DDI_MODE_SELECT_DVI: + return (type == DRM_MODE_CONNECTOR_HDMIA); + + case TRANS_DDI_MODE_SELECT_DP_SST: + if (type == DRM_MODE_CONNECTOR_eDP) + return true; + case TRANS_DDI_MODE_SELECT_DP_MST: + return (type == DRM_MODE_CONNECTOR_DisplayPort); + + case TRANS_DDI_MODE_SELECT_FDI: + return (type == DRM_MODE_CONNECTOR_VGA); + + default: + return false; + } +} + +bool intel_ddi_get_hw_state(struct intel_encoder *encoder, + enum pipe *pipe) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum port port = intel_ddi_get_encoder_port(encoder); + u32 tmp; + int i; + + tmp = I915_READ(DDI_BUF_CTL(port)); + + if (!(tmp & DDI_BUF_CTL_ENABLE)) + return false; + + if (port == PORT_A) { + tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); + + switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { + case TRANS_DDI_EDP_INPUT_A_ON: + case TRANS_DDI_EDP_INPUT_A_ONOFF: + *pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + *pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + *pipe = PIPE_C; + break; + } + + return true; + } else { + for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) { + tmp = I915_READ(TRANS_DDI_FUNC_CTL(i)); + + if ((tmp & TRANS_DDI_PORT_MASK) + == TRANS_DDI_SELECT_PORT(port)) { + *pipe = i; + return true; + } + } + } + + DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port)); + + return false; +} + +static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + uint32_t temp, ret; + enum port port = I915_MAX_PORTS; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + int i; + + if (cpu_transcoder == TRANSCODER_EDP) { + port = PORT_A; + } else { + temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); + temp &= TRANS_DDI_PORT_MASK; + + for (i = PORT_B; i <= PORT_E; i++) + if (temp == TRANS_DDI_SELECT_PORT(i)) + port = i; + } + + if (port == I915_MAX_PORTS) { + WARN(1, "Pipe %c enabled on an unknown port\n", + pipe_name(pipe)); + ret = PORT_CLK_SEL_NONE; + } else { + ret = I915_READ(PORT_CLK_SEL(port)); + DRM_DEBUG_KMS("Pipe %c connected to port %c using clock " + "0x%08x\n", pipe_name(pipe), port_name(port), + ret); + } + + return ret; +} + +void intel_ddi_setup_hw_pll_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct intel_crtc *intel_crtc; + + dev_priv->ddi_plls.spll_refcount = 0; + dev_priv->ddi_plls.wrpll1_refcount = 0; + dev_priv->ddi_plls.wrpll2_refcount = 0; + + for_each_pipe(pipe) { + intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + + if (!intel_crtc->active) { + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE; + continue; + } + + intel_crtc->ddi_pll_sel = intel_ddi_get_crtc_pll(dev_priv, + pipe); + + switch (intel_crtc->ddi_pll_sel) { + case PORT_CLK_SEL_SPLL: + dev_priv->ddi_plls.spll_refcount++; + break; + case PORT_CLK_SEL_WRPLL1: + dev_priv->ddi_plls.wrpll1_refcount++; + break; + case PORT_CLK_SEL_WRPLL2: + dev_priv->ddi_plls.wrpll2_refcount++; + break; + } + } +} + +void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) +{ + struct drm_crtc *crtc = &intel_crtc->base; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + enum port port = intel_ddi_get_encoder_port(intel_encoder); + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + + if (cpu_transcoder != TRANSCODER_EDP) + I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), + TRANS_CLK_SEL_PORT(port)); +} + +void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) +{ + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + + if (cpu_transcoder != TRANSCODER_EDP) + I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), + TRANS_CLK_SEL_DISABLED); +} + +static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + ironlake_edp_panel_on(intel_dp); + } + + WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); + I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel); + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + intel_dp_start_link_train(intel_dp); + intel_dp_complete_link_train(intel_dp); + if (port != PORT_A) + intel_dp_stop_link_train(intel_dp); + } +} + +static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + uint32_t val; + bool wait = false; + + val = I915_READ(DDI_BUF_CTL(port)); + if (val & DDI_BUF_CTL_ENABLE) { + val &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), val); + wait = true; + } + + val = I915_READ(DP_TP_CTL(port)); + val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + val |= DP_TP_CTL_LINK_TRAIN_PAT1; + I915_WRITE(DP_TP_CTL(port), val); + + if (wait) + intel_wait_ddi_buf_idle(dev_priv, port); + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); + ironlake_edp_panel_vdd_on(intel_dp); + ironlake_edp_panel_off(intel_dp); + } + + I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); +} + +static void intel_enable_ddi(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + uint32_t tmp; + + if (type == INTEL_OUTPUT_HDMI) { + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(encoder); + + /* In HDMI/DVI mode, the port width, and swing/emphasis values + * are ignored so nothing special needs to be done besides + * enabling the port. + */ + I915_WRITE(DDI_BUF_CTL(port), + intel_dig_port->saved_port_bits | + DDI_BUF_CTL_ENABLE); + } else if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (port == PORT_A) + intel_dp_stop_link_train(intel_dp); + + ironlake_edp_backlight_on(intel_dp); + intel_edp_psr_enable(intel_dp); + } + + if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) { + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + } +} + +static void intel_disable_ddi(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int type = intel_encoder->type; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) { + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << + (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + } + + if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + intel_edp_psr_disable(intel_dp); + ironlake_edp_backlight_off(intel_dp); + } +} + +int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + uint32_t lcpll = I915_READ(LCPLL_CTL); + uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK; + + if (lcpll & LCPLL_CD_SOURCE_FCLK) { + return 800000; + } else if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) { + return 450000; + } else if (freq == LCPLL_CLK_FREQ_450) { + return 450000; + } else if (IS_HASWELL(dev)) { + if (IS_ULT(dev)) + return 337500; + else + return 540000; + } else { + if (freq == LCPLL_CLK_FREQ_54O_BDW) + return 540000; + else if (freq == LCPLL_CLK_FREQ_337_5_BDW) + return 337500; + else + return 675000; + } +} + +void intel_ddi_pll_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val = I915_READ(LCPLL_CTL); + + /* The LCPLL register should be turned on by the BIOS. For now let's + * just check its state and print errors in case something is wrong. + * Don't even try to turn it on. + */ + + DRM_DEBUG_KMS("CDCLK running at %dKHz\n", + intel_ddi_get_cdclk_freq(dev_priv)); + + if (val & LCPLL_CD_SOURCE_FCLK) + DRM_ERROR("CDCLK source is not LCPLL\n"); + + if (val & LCPLL_PLL_DISABLE) + DRM_ERROR("LCPLL is disabled\n"); +} + +void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) +{ + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_dp *intel_dp = &intel_dig_port->dp; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + enum port port = intel_dig_port->port; + uint32_t val; + bool wait = false; + + if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) { + val = I915_READ(DDI_BUF_CTL(port)); + if (val & DDI_BUF_CTL_ENABLE) { + val &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), val); + wait = true; + } + + val = I915_READ(DP_TP_CTL(port)); + val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + val |= DP_TP_CTL_LINK_TRAIN_PAT1; + I915_WRITE(DP_TP_CTL(port), val); + POSTING_READ(DP_TP_CTL(port)); + + if (wait) + intel_wait_ddi_buf_idle(dev_priv, port); + } + + val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST | + DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; + if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; + I915_WRITE(DP_TP_CTL(port), val); + POSTING_READ(DP_TP_CTL(port)); + + intel_dp->DP |= DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), intel_dp->DP); + POSTING_READ(DDI_BUF_CTL(port)); + + udelay(600); +} + +void intel_ddi_fdi_disable(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + uint32_t val; + + intel_ddi_post_disable(intel_encoder); + + val = I915_READ(_FDI_RXA_CTL); + val &= ~FDI_RX_ENABLE; + I915_WRITE(_FDI_RXA_CTL, val); + + val = I915_READ(_FDI_RXA_MISC); + val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); + I915_WRITE(_FDI_RXA_MISC, val); + + val = I915_READ(_FDI_RXA_CTL); + val &= ~FDI_PCDCLK; + I915_WRITE(_FDI_RXA_CTL, val); + + val = I915_READ(_FDI_RXA_CTL); + val &= ~FDI_RX_PLL_ENABLE; + I915_WRITE(_FDI_RXA_CTL, val); +} + +static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) + intel_dp_check_link_status(intel_dp); +} + +void intel_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + u32 temp, flags = 0; + + temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); + if (temp & TRANS_DDI_PHSYNC) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + if (temp & TRANS_DDI_PVSYNC) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; + + switch (temp & TRANS_DDI_BPC_MASK) { + case TRANS_DDI_BPC_6: + pipe_config->pipe_bpp = 18; + break; + case TRANS_DDI_BPC_8: + pipe_config->pipe_bpp = 24; + break; + case TRANS_DDI_BPC_10: + pipe_config->pipe_bpp = 30; + break; + case TRANS_DDI_BPC_12: + pipe_config->pipe_bpp = 36; + break; + default: + break; + } + + switch (temp & TRANS_DDI_MODE_SELECT_MASK) { + case TRANS_DDI_MODE_SELECT_HDMI: + case TRANS_DDI_MODE_SELECT_DVI: + case TRANS_DDI_MODE_SELECT_FDI: + break; + case TRANS_DDI_MODE_SELECT_DP_SST: + case TRANS_DDI_MODE_SELECT_DP_MST: + pipe_config->has_dp_encoder = true; + intel_dp_get_m_n(intel_crtc, pipe_config); + break; + default: + break; + } + + if (encoder->type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp_bpp && + pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) { + /* + * This is a big fat ugly hack. + * + * Some machines in UEFI boot mode provide us a VBT that has 18 + * bpp and 1.62 GHz link bandwidth for eDP, which for reasons + * unknown we fail to light up. Yet the same BIOS boots up with + * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as + * max, not what it tells us to use. + * + * Note: This will still be broken if the eDP panel is not lit + * up by the BIOS, and thus we can't get the mode at module + * load. + */ + DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n", + pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp); + dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp; + } +} + +static void intel_ddi_destroy(struct drm_encoder *encoder) +{ + /* HDMI has nothing special to destroy, so we can go with this. */ + intel_dp_encoder_destroy(encoder); +} + +static bool intel_ddi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + int type = encoder->type; + int port = intel_ddi_get_encoder_port(encoder); + + WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n"); + + if (port == PORT_A) + pipe_config->cpu_transcoder = TRANSCODER_EDP; + + if (type == INTEL_OUTPUT_HDMI) + return intel_hdmi_compute_config(encoder, pipe_config); + else + return intel_dp_compute_config(encoder, pipe_config); +} + +static const struct drm_encoder_funcs intel_ddi_funcs = { + .destroy = intel_ddi_destroy, +}; + +static struct intel_connector * +intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port) +{ + struct intel_connector *connector; + enum port port = intel_dig_port->port; + + connector = kzalloc(sizeof(*connector), GFP_KERNEL); + if (!connector) + return NULL; + + intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); + if (!intel_dp_init_connector(intel_dig_port, connector)) { + kfree(connector); + return NULL; + } + + return connector; +} + +static struct intel_connector * +intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port) +{ + struct intel_connector *connector; + enum port port = intel_dig_port->port; + + connector = kzalloc(sizeof(*connector), GFP_KERNEL); + if (!connector) + return NULL; + + intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); + intel_hdmi_init_connector(intel_dig_port, connector); + + return connector; +} + +void intel_ddi_init(struct drm_device *dev, enum port port) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port; + struct intel_encoder *intel_encoder; + struct drm_encoder *encoder; + struct intel_connector *hdmi_connector = NULL; + struct intel_connector *dp_connector = NULL; + bool init_hdmi, init_dp; + + init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi || + dev_priv->vbt.ddi_port_info[port].supports_hdmi); + init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp; + if (!init_dp && !init_hdmi) { + DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible\n", + port_name(port)); + init_hdmi = true; + init_dp = true; + } + + intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL); + if (!intel_dig_port) + return; + + intel_encoder = &intel_dig_port->base; + encoder = &intel_encoder->base; + + drm_encoder_init(dev, encoder, &intel_ddi_funcs, + DRM_MODE_ENCODER_TMDS); + + intel_encoder->compute_config = intel_ddi_compute_config; + intel_encoder->mode_set = intel_ddi_mode_set; + intel_encoder->enable = intel_enable_ddi; + intel_encoder->pre_enable = intel_ddi_pre_enable; + intel_encoder->disable = intel_disable_ddi; + intel_encoder->post_disable = intel_ddi_post_disable; + intel_encoder->get_hw_state = intel_ddi_get_hw_state; + intel_encoder->get_config = intel_ddi_get_config; + + intel_dig_port->port = port; + intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & + (DDI_BUF_PORT_REVERSAL | + DDI_A_4_LANES); + + intel_encoder->type = INTEL_OUTPUT_UNKNOWN; + intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + intel_encoder->cloneable = false; + intel_encoder->hot_plug = intel_ddi_hot_plug; + + if (init_dp) + dp_connector = intel_ddi_init_dp_connector(intel_dig_port); + + /* In theory we don't need the encoder->type check, but leave it just in + * case we have some really bad VBTs... */ + if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) + hdmi_connector = intel_ddi_init_hdmi_connector(intel_dig_port); + + if (!dp_connector && !hdmi_connector) { + drm_encoder_cleanup(encoder); + kfree(intel_dig_port); + } +} --- linux-3.13.0.orig/ubuntu/i915/i915_gem.c +++ linux-3.13.0/ubuntu/i915/i915_gem.c @@ -0,0 +1,5134 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include +#include +#include +#include "i915_drv.h" +#include "i915_trace.h" +#include "intel_drv.h" +#include +#include +#include +#include +#include + +static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); +static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj, + bool force); +static __must_check int +i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, + bool readonly); +static __must_check int +i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + unsigned alignment, + bool map_and_fenceable, + bool nonblocking); +static int i915_gem_phys_pwrite(struct drm_device *dev, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_pwrite *args, + struct drm_file *file); + +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj); +static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, + struct drm_i915_fence_reg *fence, + bool enable); + +static unsigned long i915_gem_inactive_count(struct shrinker *shrinker, + struct shrink_control *sc); +static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker, + struct shrink_control *sc); +static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target); +static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv); +static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); + +static bool cpu_cache_is_coherent(struct drm_device *dev, + enum i915_cache_level level) +{ + return HAS_LLC(dev) || level != I915_CACHE_NONE; +} + +static bool cpu_write_needs_clflush(struct drm_i915_gem_object *obj) +{ + if (!cpu_cache_is_coherent(obj->base.dev, obj->cache_level)) + return true; + + return obj->pin_display; +} + +static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) +{ + if (obj->tiling_mode) + i915_gem_release_mmap(obj); + + /* As we do not have an associated fence register, we will force + * a tiling change if we ever need to acquire one. + */ + obj->fence_dirty = false; + obj->fence_reg = I915_FENCE_REG_NONE; +} + +/* some bookkeeping */ +static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, + size_t size) +{ + spin_lock(&dev_priv->mm.object_stat_lock); + dev_priv->mm.object_count++; + dev_priv->mm.object_memory += size; + spin_unlock(&dev_priv->mm.object_stat_lock); +} + +static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, + size_t size) +{ + spin_lock(&dev_priv->mm.object_stat_lock); + dev_priv->mm.object_count--; + dev_priv->mm.object_memory -= size; + spin_unlock(&dev_priv->mm.object_stat_lock); +} + +static int +i915_gem_wait_for_error(struct i915_gpu_error *error) +{ + int ret; + +#define EXIT_COND (!i915_reset_in_progress(error) || \ + i915_terminally_wedged(error)) + if (EXIT_COND) + return 0; + + /* + * Only wait 10 seconds for the gpu reset to complete to avoid hanging + * userspace. If it takes that long something really bad is going on and + * we should simply try to bail out and fail as gracefully as possible. + */ + ret = wait_event_interruptible_timeout(error->reset_queue, + EXIT_COND, + 10*HZ); + if (ret == 0) { + DRM_ERROR("Timed out waiting for the gpu reset to complete\n"); + return -EIO; + } else if (ret < 0) { + return ret; + } +#undef EXIT_COND + + return 0; +} + +int i915_mutex_lock_interruptible(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + WARN_ON(i915_verify_lists(dev)); + return 0; +} + +static inline bool +i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) +{ + return i915_gem_obj_bound_any(obj) && !obj->active; +} + +int +i915_gem_init_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_init *args = data; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (args->gtt_start >= args->gtt_end || + (args->gtt_end | args->gtt_start) & (PAGE_SIZE - 1)) + return -EINVAL; + + /* GEM with user mode setting was never supported on ilk and later. */ + if (INTEL_INFO(dev)->gen >= 5) + return -ENODEV; + + mutex_lock(&dev->struct_mutex); + i915_gem_setup_global_gtt(dev, args->gtt_start, args->gtt_end, + args->gtt_end); + dev_priv->gtt.mappable_end = args->gtt_end; + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +int +i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_get_aperture *args = data; + struct drm_i915_gem_object *obj; + size_t pinned; + + pinned = 0; + mutex_lock(&dev->struct_mutex); + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) + if (obj->pin_count) + pinned += i915_gem_obj_ggtt_size(obj); + mutex_unlock(&dev->struct_mutex); + + args->aper_size = dev_priv->gtt.base.total; + args->aper_available_size = args->aper_size - pinned; + + return 0; +} + +void *i915_gem_object_alloc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return kmem_cache_zalloc(dev_priv->slab, GFP_KERNEL); +} + +void i915_gem_object_free(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + kmem_cache_free(dev_priv->slab, obj); +} + +static int +i915_gem_create(struct drm_file *file, + struct drm_device *dev, + uint64_t size, + uint32_t *handle_p) +{ + struct drm_i915_gem_object *obj; + int ret; + u32 handle; + + size = roundup(size, PAGE_SIZE); + if (size == 0) + return -EINVAL; + + /* Allocate the new object */ + obj = i915_gem_alloc_object(dev, size); + if (obj == NULL) + return -ENOMEM; + + ret = drm_gem_handle_create(file, &obj->base, &handle); + /* drop reference from allocate - handle holds it now */ + drm_gem_object_unreference_unlocked(&obj->base); + if (ret) + return ret; + + *handle_p = handle; + return 0; +} + +int +i915_gem_dumb_create(struct drm_file *file, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + /* have to work out size/pitch and return them */ + args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64); + args->size = args->pitch * args->height; + return i915_gem_create(file, dev, + args->size, &args->handle); +} + +/** + * Creates a new mm object and returns a handle to it. + */ +int +i915_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_create *args = data; + + return i915_gem_create(file, dev, + args->size, &args->handle); +} + +static inline int +__copy_to_user_swizzled(char __user *cpu_vaddr, + const char *gpu_vaddr, int gpu_offset, + int length) +{ + int ret, cpu_offset = 0; + + while (length > 0) { + int cacheline_end = ALIGN(gpu_offset + 1, 64); + int this_length = min(cacheline_end - gpu_offset, length); + int swizzled_gpu_offset = gpu_offset ^ 64; + + ret = __copy_to_user(cpu_vaddr + cpu_offset, + gpu_vaddr + swizzled_gpu_offset, + this_length); + if (ret) + return ret + length; + + cpu_offset += this_length; + gpu_offset += this_length; + length -= this_length; + } + + return 0; +} + +static inline int +__copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset, + const char __user *cpu_vaddr, + int length) +{ + int ret, cpu_offset = 0; + + while (length > 0) { + int cacheline_end = ALIGN(gpu_offset + 1, 64); + int this_length = min(cacheline_end - gpu_offset, length); + int swizzled_gpu_offset = gpu_offset ^ 64; + + ret = __copy_from_user(gpu_vaddr + swizzled_gpu_offset, + cpu_vaddr + cpu_offset, + this_length); + if (ret) + return ret + length; + + cpu_offset += this_length; + gpu_offset += this_length; + length -= this_length; + } + + return 0; +} + +/* Per-page copy function for the shmem pread fastpath. + * Flushes invalid cachelines before reading the target if + * needs_clflush is set. */ +static int +shmem_pread_fast(struct page *page, int shmem_page_offset, int page_length, + char __user *user_data, + bool page_do_bit17_swizzling, bool needs_clflush) +{ + char *vaddr; + int ret; + + if (unlikely(page_do_bit17_swizzling)) + return -EINVAL; + + vaddr = kmap_atomic(page); + if (needs_clflush) + drm_clflush_virt_range(vaddr + shmem_page_offset, + page_length); + ret = __copy_to_user_inatomic(user_data, + vaddr + shmem_page_offset, + page_length); + kunmap_atomic(vaddr); + + return ret ? -EFAULT : 0; +} + +static void +shmem_clflush_swizzled_range(char *addr, unsigned long length, + bool swizzled) +{ + if (unlikely(swizzled)) { + unsigned long start = (unsigned long) addr; + unsigned long end = (unsigned long) addr + length; + + /* For swizzling simply ensure that we always flush both + * channels. Lame, but simple and it works. Swizzled + * pwrite/pread is far from a hotpath - current userspace + * doesn't use it at all. */ + start = round_down(start, 128); + end = round_up(end, 128); + + drm_clflush_virt_range((void *)start, end - start); + } else { + drm_clflush_virt_range(addr, length); + } + +} + +/* Only difference to the fast-path function is that this can handle bit17 + * and uses non-atomic copy and kmap functions. */ +static int +shmem_pread_slow(struct page *page, int shmem_page_offset, int page_length, + char __user *user_data, + bool page_do_bit17_swizzling, bool needs_clflush) +{ + char *vaddr; + int ret; + + vaddr = kmap(page); + if (needs_clflush) + shmem_clflush_swizzled_range(vaddr + shmem_page_offset, + page_length, + page_do_bit17_swizzling); + + if (page_do_bit17_swizzling) + ret = __copy_to_user_swizzled(user_data, + vaddr, shmem_page_offset, + page_length); + else + ret = __copy_to_user(user_data, + vaddr + shmem_page_offset, + page_length); + kunmap(page); + + return ret ? - EFAULT : 0; +} + +static int +i915_gem_shmem_pread(struct drm_device *dev, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_pread *args, + struct drm_file *file) +{ + char __user *user_data; + ssize_t remain; + loff_t offset; + int shmem_page_offset, page_length, ret = 0; + int obj_do_bit17_swizzling, page_do_bit17_swizzling; + int prefaulted = 0; + int needs_clflush = 0; + struct sg_page_iter sg_iter; + + user_data = to_user_ptr(args->data_ptr); + remain = args->size; + + obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); + + if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) { + /* If we're not in the cpu read domain, set ourself into the gtt + * read domain and manually flush cachelines (if required). This + * optimizes for the case when the gpu will dirty the data + * anyway again before the next pread happens. */ + needs_clflush = !cpu_cache_is_coherent(dev, obj->cache_level); + ret = i915_gem_object_wait_rendering(obj, true); + if (ret) + return ret; + } + + ret = i915_gem_object_get_pages(obj); + if (ret) + return ret; + + i915_gem_object_pin_pages(obj); + + offset = args->offset; + + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, + offset >> PAGE_SHIFT) { + struct page *page = sg_page_iter_page(&sg_iter); + + if (remain <= 0) + break; + + /* Operation in this page + * + * shmem_page_offset = offset within page in shmem file + * page_length = bytes to copy for this page + */ + shmem_page_offset = offset_in_page(offset); + page_length = remain; + if ((shmem_page_offset + page_length) > PAGE_SIZE) + page_length = PAGE_SIZE - shmem_page_offset; + + page_do_bit17_swizzling = obj_do_bit17_swizzling && + (page_to_phys(page) & (1 << 17)) != 0; + + ret = shmem_pread_fast(page, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + needs_clflush); + if (ret == 0) + goto next_page; + + mutex_unlock(&dev->struct_mutex); + + if (likely(!i915_prefault_disable) && !prefaulted) { + ret = fault_in_multipages_writeable(user_data, remain); + /* Userspace is tricking us, but we've already clobbered + * its pages with the prefault and promised to write the + * data up to the first fault. Hence ignore any errors + * and just continue. */ + (void)ret; + prefaulted = 1; + } + + ret = shmem_pread_slow(page, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + needs_clflush); + + mutex_lock(&dev->struct_mutex); + +next_page: + mark_page_accessed(page); + + if (ret) + goto out; + + remain -= page_length; + user_data += page_length; + offset += page_length; + } + +out: + i915_gem_object_unpin_pages(obj); + + return ret; +} + +/** + * Reads data from the object referenced by handle. + * + * On error, the contents of *data are undefined. + */ +int +i915_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_pread *args = data; + struct drm_i915_gem_object *obj; + int ret = 0; + + if (args->size == 0) + return 0; + + if (!access_ok(VERIFY_WRITE, + to_user_ptr(args->data_ptr), + args->size)) + return -EFAULT; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + /* Bounds check source. */ + if (args->offset > obj->base.size || + args->size > obj->base.size - args->offset) { + ret = -EINVAL; + goto out; + } + + /* prime objects have no backing filp to GEM pread/pwrite + * pages from. + */ + if (!obj->base.filp) { + ret = -EINVAL; + goto out; + } + + trace_i915_gem_object_pread(obj, args->offset, args->size); + + ret = i915_gem_shmem_pread(dev, obj, args, file); + +out: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +/* This is the fast write path which cannot handle + * page faults in the source data + */ + +static inline int +fast_user_write(struct io_mapping *mapping, + loff_t page_base, int page_offset, + char __user *user_data, + int length) +{ + void __iomem *vaddr_atomic; + void *vaddr; + unsigned long unwritten; + + vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base); + /* We can use the cpu mem copy function because this is X86. */ + vaddr = (void __force*)vaddr_atomic + page_offset; + unwritten = __copy_from_user_inatomic_nocache(vaddr, + user_data, length); + io_mapping_unmap_atomic(vaddr_atomic); + return unwritten; +} + +/** + * This is the fast pwrite path, where we copy the data directly from the + * user into the GTT, uncached. + */ +static int +i915_gem_gtt_pwrite_fast(struct drm_device *dev, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_pwrite *args, + struct drm_file *file) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + ssize_t remain; + loff_t offset, page_base; + char __user *user_data; + int page_offset, page_length, ret; + + ret = i915_gem_obj_ggtt_pin(obj, 0, true, true); + if (ret) + goto out; + + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + goto out_unpin; + + ret = i915_gem_object_put_fence(obj); + if (ret) + goto out_unpin; + + user_data = to_user_ptr(args->data_ptr); + remain = args->size; + + offset = i915_gem_obj_ggtt_offset(obj) + args->offset; + + while (remain > 0) { + /* Operation in this page + * + * page_base = page offset within aperture + * page_offset = offset within page + * page_length = bytes to copy for this page + */ + page_base = offset & PAGE_MASK; + page_offset = offset_in_page(offset); + page_length = remain; + if ((page_offset + remain) > PAGE_SIZE) + page_length = PAGE_SIZE - page_offset; + + /* If we get a fault while copying data, then (presumably) our + * source page isn't available. Return the error and we'll + * retry in the slow path. + */ + if (fast_user_write(dev_priv->gtt.mappable, page_base, + page_offset, user_data, page_length)) { + ret = -EFAULT; + goto out_unpin; + } + + remain -= page_length; + user_data += page_length; + offset += page_length; + } + +out_unpin: + i915_gem_object_unpin(obj); +out: + return ret; +} + +/* Per-page copy function for the shmem pwrite fastpath. + * Flushes invalid cachelines before writing to the target if + * needs_clflush_before is set and flushes out any written cachelines after + * writing if needs_clflush is set. */ +static int +shmem_pwrite_fast(struct page *page, int shmem_page_offset, int page_length, + char __user *user_data, + bool page_do_bit17_swizzling, + bool needs_clflush_before, + bool needs_clflush_after) +{ + char *vaddr; + int ret; + + if (unlikely(page_do_bit17_swizzling)) + return -EINVAL; + + vaddr = kmap_atomic(page); + if (needs_clflush_before) + drm_clflush_virt_range(vaddr + shmem_page_offset, + page_length); + ret = __copy_from_user_inatomic_nocache(vaddr + shmem_page_offset, + user_data, + page_length); + if (needs_clflush_after) + drm_clflush_virt_range(vaddr + shmem_page_offset, + page_length); + kunmap_atomic(vaddr); + + return ret ? -EFAULT : 0; +} + +/* Only difference to the fast-path function is that this can handle bit17 + * and uses non-atomic copy and kmap functions. */ +static int +shmem_pwrite_slow(struct page *page, int shmem_page_offset, int page_length, + char __user *user_data, + bool page_do_bit17_swizzling, + bool needs_clflush_before, + bool needs_clflush_after) +{ + char *vaddr; + int ret; + + vaddr = kmap(page); + if (unlikely(needs_clflush_before || page_do_bit17_swizzling)) + shmem_clflush_swizzled_range(vaddr + shmem_page_offset, + page_length, + page_do_bit17_swizzling); + if (page_do_bit17_swizzling) + ret = __copy_from_user_swizzled(vaddr, shmem_page_offset, + user_data, + page_length); + else + ret = __copy_from_user(vaddr + shmem_page_offset, + user_data, + page_length); + if (needs_clflush_after) + shmem_clflush_swizzled_range(vaddr + shmem_page_offset, + page_length, + page_do_bit17_swizzling); + kunmap(page); + + return ret ? -EFAULT : 0; +} + +static int +i915_gem_shmem_pwrite(struct drm_device *dev, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_pwrite *args, + struct drm_file *file) +{ + ssize_t remain; + loff_t offset; + char __user *user_data; + int shmem_page_offset, page_length, ret = 0; + int obj_do_bit17_swizzling, page_do_bit17_swizzling; + int hit_slowpath = 0; + int needs_clflush_after = 0; + int needs_clflush_before = 0; + struct sg_page_iter sg_iter; + + user_data = to_user_ptr(args->data_ptr); + remain = args->size; + + obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); + + if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) { + /* If we're not in the cpu write domain, set ourself into the gtt + * write domain and manually flush cachelines (if required). This + * optimizes for the case when the gpu will use the data + * right away and we therefore have to clflush anyway. */ + needs_clflush_after = cpu_write_needs_clflush(obj); + ret = i915_gem_object_wait_rendering(obj, false); + if (ret) + return ret; + } + /* Same trick applies to invalidate partially written cachelines read + * before writing. */ + if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) + needs_clflush_before = + !cpu_cache_is_coherent(dev, obj->cache_level); + + ret = i915_gem_object_get_pages(obj); + if (ret) + return ret; + + i915_gem_object_pin_pages(obj); + + offset = args->offset; + obj->dirty = 1; + + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, + offset >> PAGE_SHIFT) { + struct page *page = sg_page_iter_page(&sg_iter); + int partial_cacheline_write; + + if (remain <= 0) + break; + + /* Operation in this page + * + * shmem_page_offset = offset within page in shmem file + * page_length = bytes to copy for this page + */ + shmem_page_offset = offset_in_page(offset); + + page_length = remain; + if ((shmem_page_offset + page_length) > PAGE_SIZE) + page_length = PAGE_SIZE - shmem_page_offset; + + /* If we don't overwrite a cacheline completely we need to be + * careful to have up-to-date data by first clflushing. Don't + * overcomplicate things and flush the entire patch. */ + partial_cacheline_write = needs_clflush_before && + ((shmem_page_offset | page_length) + & (boot_cpu_data.x86_clflush_size - 1)); + + page_do_bit17_swizzling = obj_do_bit17_swizzling && + (page_to_phys(page) & (1 << 17)) != 0; + + ret = shmem_pwrite_fast(page, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + partial_cacheline_write, + needs_clflush_after); + if (ret == 0) + goto next_page; + + hit_slowpath = 1; + mutex_unlock(&dev->struct_mutex); + ret = shmem_pwrite_slow(page, shmem_page_offset, page_length, + user_data, page_do_bit17_swizzling, + partial_cacheline_write, + needs_clflush_after); + + mutex_lock(&dev->struct_mutex); + +next_page: + set_page_dirty(page); + mark_page_accessed(page); + + if (ret) + goto out; + + remain -= page_length; + user_data += page_length; + offset += page_length; + } + +out: + i915_gem_object_unpin_pages(obj); + + if (hit_slowpath) { + /* + * Fixup: Flush cpu caches in case we didn't flush the dirty + * cachelines in-line while writing and the object moved + * out of the cpu write domain while we've dropped the lock. + */ + if (!needs_clflush_after && + obj->base.write_domain != I915_GEM_DOMAIN_CPU) { + if (i915_gem_clflush_object(obj, obj->pin_display)) + i915_gem_chipset_flush(dev); + } + } + + if (needs_clflush_after) + i915_gem_chipset_flush(dev); + + return ret; +} + +/** + * Writes data to the object referenced by handle. + * + * On error, the contents of the buffer that were to be modified are undefined. + */ +int +i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_pwrite *args = data; + struct drm_i915_gem_object *obj; + int ret; + + if (args->size == 0) + return 0; + + if (!access_ok(VERIFY_READ, + to_user_ptr(args->data_ptr), + args->size)) + return -EFAULT; + + if (likely(!i915_prefault_disable)) { + ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr), + args->size); + if (ret) + return -EFAULT; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + /* Bounds check destination. */ + if (args->offset > obj->base.size || + args->size > obj->base.size - args->offset) { + ret = -EINVAL; + goto out; + } + + /* prime objects have no backing filp to GEM pread/pwrite + * pages from. + */ + if (!obj->base.filp) { + ret = -EINVAL; + goto out; + } + + trace_i915_gem_object_pwrite(obj, args->offset, args->size); + + ret = -EFAULT; + /* We can only do the GTT pwrite on untiled buffers, as otherwise + * it would end up going through the fenced access, and we'll get + * different detiling behavior between reading and writing. + * pread/pwrite currently are reading and writing from the CPU + * perspective, requiring manual detiling by the client. + */ + if (obj->phys_obj) { + ret = i915_gem_phys_pwrite(dev, obj, args, file); + goto out; + } + + if (obj->tiling_mode == I915_TILING_NONE && + obj->base.write_domain != I915_GEM_DOMAIN_CPU && + cpu_write_needs_clflush(obj)) { + ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file); + /* Note that the gtt paths might fail with non-page-backed user + * pointers (e.g. gtt mappings when moving data between + * textures). Fallback to the shmem path in that case. */ + } + + if (ret == -EFAULT || ret == -ENOSPC) + ret = i915_gem_shmem_pwrite(dev, obj, args, file); + +out: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int +i915_gem_check_wedge(struct i915_gpu_error *error, + bool interruptible) +{ + if (i915_reset_in_progress(error)) { + /* Non-interruptible callers can't handle -EAGAIN, hence return + * -EIO unconditionally for these. */ + if (!interruptible) + return -EIO; + + /* Recovery complete, but the reset failed ... */ + if (i915_terminally_wedged(error)) + return -EIO; + + return -EAGAIN; + } + + return 0; +} + +/* + * Compare seqno against outstanding lazy request. Emit a request if they are + * equal. + */ +static int +i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno) +{ + int ret; + + BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex)); + + ret = 0; + if (seqno == ring->outstanding_lazy_seqno) + ret = i915_add_request(ring, NULL); + + return ret; +} + +static void fake_irq(unsigned long data) +{ + wake_up_process((struct task_struct *)data); +} + +static bool missed_irq(struct drm_i915_private *dev_priv, + struct intel_ring_buffer *ring) +{ + return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings); +} + +static bool can_wait_boost(struct drm_i915_file_private *file_priv) +{ + if (file_priv == NULL) + return true; + + return !atomic_xchg(&file_priv->rps_wait_boost, true); +} + +/** + * __wait_seqno - wait until execution of seqno has finished + * @ring: the ring expected to report seqno + * @seqno: duh! + * @reset_counter: reset sequence associated with the given seqno + * @interruptible: do an interruptible wait (normally yes) + * @timeout: in - how long to wait (NULL forever); out - how much time remaining + * + * Note: It is of utmost importance that the passed in seqno and reset_counter + * values have been read by the caller in an smp safe manner. Where read-side + * locks are involved, it is sufficient to read the reset_counter before + * unlocking the lock that protects the seqno. For lockless tricks, the + * reset_counter _must_ be read before, and an appropriate smp_rmb must be + * inserted. + * + * Returns 0 if the seqno was found within the alloted time. Else returns the + * errno with remaining time filled in timeout argument. + */ +static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, + unsigned reset_counter, + bool interruptible, + struct timespec *timeout, + struct drm_i915_file_private *file_priv) +{ + drm_i915_private_t *dev_priv = ring->dev->dev_private; + const bool irq_test_in_progress = + ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring); + struct timespec before, now; + DEFINE_WAIT(wait); + unsigned long timeout_expire; + int ret; + + WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n"); + + if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) + return 0; + + timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0; + + if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) { + gen6_rps_boost(dev_priv); + if (file_priv) + mod_delayed_work(dev_priv->wq, + &file_priv->mm.idle_work, + msecs_to_jiffies(100)); + } + + if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring))) + return -ENODEV; + + /* Record current time in case interrupted by signal, or wedged */ + trace_i915_gem_request_wait_begin(ring, seqno); + getrawmonotonic(&before); + for (;;) { + struct timer_list timer; + + prepare_to_wait(&ring->irq_queue, &wait, + interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + + /* We need to check whether any gpu reset happened in between + * the caller grabbing the seqno and now ... */ + if (reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) { + /* ... but upgrade the -EAGAIN to an -EIO if the gpu + * is truely gone. */ + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); + if (ret == 0) + ret = -EAGAIN; + break; + } + + if (i915_seqno_passed(ring->get_seqno(ring, false), seqno)) { + ret = 0; + break; + } + + if (interruptible && signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + if (timeout && time_after_eq(jiffies, timeout_expire)) { + ret = -ETIME; + break; + } + + timer.function = NULL; + if (timeout || missed_irq(dev_priv, ring)) { + unsigned long expire; + + setup_timer_on_stack(&timer, fake_irq, (unsigned long)current); + expire = missed_irq(dev_priv, ring) ? jiffies + 1 : timeout_expire; + mod_timer(&timer, expire); + } + + io_schedule(); + + if (timer.function) { + del_singleshot_timer_sync(&timer); + destroy_timer_on_stack(&timer); + } + } + getrawmonotonic(&now); + trace_i915_gem_request_wait_end(ring, seqno); + + if (!irq_test_in_progress) + ring->irq_put(ring); + + finish_wait(&ring->irq_queue, &wait); + + if (timeout) { + struct timespec sleep_time = timespec_sub(now, before); + *timeout = timespec_sub(*timeout, sleep_time); + if (!timespec_valid(timeout)) /* i.e. negative time remains */ + set_normalized_timespec(timeout, 0, 0); + } + + return ret; +} + +/** + * Waits for a sequence number to be signaled, and cleans up the + * request and object lists appropriately for that event. + */ +int +i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + bool interruptible = dev_priv->mm.interruptible; + int ret; + + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + BUG_ON(seqno == 0); + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); + if (ret) + return ret; + + ret = i915_gem_check_olr(ring, seqno); + if (ret) + return ret; + + return __wait_seqno(ring, seqno, + atomic_read(&dev_priv->gpu_error.reset_counter), + interruptible, NULL, NULL); +} + +static int +i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring) +{ + i915_gem_retire_requests_ring(ring); + + /* Manually manage the write flush as we may have not yet + * retired the buffer. + * + * Note that the last_write_seqno is always the earlier of + * the two (read/write) seqno, so if we haved successfully waited, + * we know we have passed the last write. + */ + obj->last_write_seqno = 0; + obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; + + return 0; +} + +/** + * Ensures that all rendering to the object has completed and the object is + * safe to unbind from the GTT or access from the CPU. + */ +static __must_check int +i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, + bool readonly) +{ + struct intel_ring_buffer *ring = obj->ring; + u32 seqno; + int ret; + + seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno; + if (seqno == 0) + return 0; + + ret = i915_wait_seqno(ring, seqno); + if (ret) + return ret; + + return i915_gem_object_wait_rendering__tail(obj, ring); +} + +/* A nonblocking variant of the above wait. This is a highly dangerous routine + * as the object state may change during this call. + */ +static __must_check int +i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, + struct drm_file *file, + bool readonly) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = obj->ring; + unsigned reset_counter; + u32 seqno; + int ret; + + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + BUG_ON(!dev_priv->mm.interruptible); + + seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno; + if (seqno == 0) + return 0; + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, true); + if (ret) + return ret; + + ret = i915_gem_check_olr(ring, seqno); + if (ret) + return ret; + + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + mutex_unlock(&dev->struct_mutex); + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL, file->driver_priv); + mutex_lock(&dev->struct_mutex); + if (ret) + return ret; + + return i915_gem_object_wait_rendering__tail(obj, ring); +} + +/** + * Called when user space prepares to use an object with the CPU, either + * through the mmap ioctl's mapping or a GTT mapping. + */ +int +i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_set_domain *args = data; + struct drm_i915_gem_object *obj; + uint32_t read_domains = args->read_domains; + uint32_t write_domain = args->write_domain; + int ret; + + /* Only handle setting domains to types used by the CPU. */ + if (write_domain & I915_GEM_GPU_DOMAINS) + return -EINVAL; + + if (read_domains & I915_GEM_GPU_DOMAINS) + return -EINVAL; + + /* Having something in the write domain implies it's in the read + * domain, and only that read domain. Enforce that in the request. + */ + if (write_domain != 0 && read_domains != write_domain) + return -EINVAL; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + /* Try to flush the object off the GPU without holding the lock. + * We will repeat the flush holding the lock in the normal manner + * to catch cases where we are gazumped. + */ + ret = i915_gem_object_wait_rendering__nonblocking(obj, file, !write_domain); + if (ret) + goto unref; + + if (read_domains & I915_GEM_DOMAIN_GTT) { + ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); + + /* Silently promote "you're not bound, there was nothing to do" + * to success, since the client was just asking us to + * make sure everything was done. + */ + if (ret == -EINVAL) + ret = 0; + } else { + ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); + } + +unref: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +/** + * Called when user space has done writes to this buffer + */ +int +i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_sw_finish *args = data; + struct drm_i915_gem_object *obj; + int ret = 0; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + /* Pinned buffers may be scanout, so flush the cache */ + if (obj->pin_display) + i915_gem_object_flush_cpu_write_domain(obj, true); + + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +/** + * Maps the contents of an object, returning the address it is mapped + * into. + * + * While the mapping holds a reference on the contents of the object, it doesn't + * imply a ref on the object itself. + */ +int +i915_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_mmap *args = data; + struct drm_gem_object *obj; + unsigned long addr; + + obj = drm_gem_object_lookup(dev, file, args->handle); + if (obj == NULL) + return -ENOENT; + + /* prime objects have no backing filp to GEM mmap + * pages from. + */ + if (!obj->filp) { + drm_gem_object_unreference_unlocked(obj); + return -EINVAL; + } + + addr = vm_mmap(obj->filp, 0, args->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + args->offset); + drm_gem_object_unreference_unlocked(obj); + if (IS_ERR((void *)addr)) + return addr; + + args->addr_ptr = (uint64_t) addr; + + return 0; +} + +/** + * i915_gem_fault - fault a page into the GTT + * vma: VMA in question + * vmf: fault info + * + * The fault handler is set up by drm_gem_mmap() when a object is GTT mapped + * from userspace. The fault handler takes care of binding the object to + * the GTT (if needed), allocating and programming a fence register (again, + * only if needed based on whether the old reg is still valid or the object + * is tiled) and inserting a new PTE into the faulting process. + * + * Note that the faulting process may involve evicting existing objects + * from the GTT and/or fence registers to make room. So performance may + * suffer if the GTT working set is large or there are few fence registers + * left. + */ +int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data); + struct drm_device *dev = obj->base.dev; + drm_i915_private_t *dev_priv = dev->dev_private; + pgoff_t page_offset; + unsigned long pfn; + int ret = 0; + bool write = !!(vmf->flags & FAULT_FLAG_WRITE); + + intel_runtime_pm_get(dev_priv); + + /* We don't use vmf->pgoff since that has the fake offset */ + page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> + PAGE_SHIFT; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto out; + + trace_i915_gem_object_fault(obj, page_offset, true, write); + + /* Access to snoopable pages through the GTT is incoherent. */ + if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(dev)) { + ret = -EINVAL; + goto unlock; + } + + /* Now bind it into the GTT if needed */ + ret = i915_gem_obj_ggtt_pin(obj, 0, true, false); + if (ret) + goto unlock; + + ret = i915_gem_object_set_to_gtt_domain(obj, write); + if (ret) + goto unpin; + + ret = i915_gem_object_get_fence(obj); + if (ret) + goto unpin; + + obj->fault_mappable = true; + + pfn = dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj); + pfn >>= PAGE_SHIFT; + pfn += page_offset; + + /* Finally, remap it using the new GTT offset */ + ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); +unpin: + i915_gem_object_unpin(obj); +unlock: + mutex_unlock(&dev->struct_mutex); +out: + switch (ret) { + case -EIO: + /* If this -EIO is due to a gpu hang, give the reset code a + * chance to clean up the mess. Otherwise return the proper + * SIGBUS. */ + if (i915_terminally_wedged(&dev_priv->gpu_error)) { + ret = VM_FAULT_SIGBUS; + break; + } + case -EAGAIN: + /* + * EAGAIN means the gpu is hung and we'll wait for the error + * handler to reset everything when re-faulting in + * i915_mutex_lock_interruptible. + */ + case 0: + case -ERESTARTSYS: + case -EINTR: + case -EBUSY: + /* + * EBUSY is ok: this just means that another thread + * already did the job. + */ + ret = VM_FAULT_NOPAGE; + break; + case -ENOMEM: + ret = VM_FAULT_OOM; + break; + case -ENOSPC: + ret = VM_FAULT_SIGBUS; + break; + default: + WARN_ONCE(ret, "unhandled error in i915_gem_fault: %i\n", ret); + ret = VM_FAULT_SIGBUS; + break; + } + + intel_runtime_pm_put(dev_priv); + return ret; +} + +void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv) +{ + struct i915_vma *vma; + + /* + * Only the global gtt is relevant for gtt memory mappings, so restrict + * list traversal to objects bound into the global address space. Note + * that the active list should be empty, but better safe than sorry. + */ + WARN_ON(!list_empty(&dev_priv->gtt.base.active_list)); + list_for_each_entry(vma, &dev_priv->gtt.base.active_list, mm_list) + i915_gem_release_mmap(vma->obj); + list_for_each_entry(vma, &dev_priv->gtt.base.inactive_list, mm_list) + i915_gem_release_mmap(vma->obj); +} + +/** + * i915_gem_release_mmap - remove physical page mappings + * @obj: obj in question + * + * Preserve the reservation of the mmapping with the DRM core code, but + * relinquish ownership of the pages back to the system. + * + * It is vital that we remove the page mapping if we have mapped a tiled + * object through the GTT and then lose the fence register due to + * resource pressure. Similarly if the object has been moved out of the + * aperture, than pages mapped into userspace must be revoked. Removing the + * mapping will then trigger a page fault on the next user access, allowing + * fixup by i915_gem_fault(). + */ +void +i915_gem_release_mmap(struct drm_i915_gem_object *obj) +{ + if (!obj->fault_mappable) + return; + + drm_vma_node_unmap(&obj->base.vma_node, obj->base.dev->dev_mapping); + obj->fault_mappable = false; +} + +uint32_t +i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) +{ + uint32_t gtt_size; + + if (INTEL_INFO(dev)->gen >= 4 || + tiling_mode == I915_TILING_NONE) + return size; + + /* Previous chips need a power-of-two fence region when tiling */ + if (INTEL_INFO(dev)->gen == 3) + gtt_size = 1024*1024; + else + gtt_size = 512*1024; + + while (gtt_size < size) + gtt_size <<= 1; + + return gtt_size; +} + +/** + * i915_gem_get_gtt_alignment - return required GTT alignment for an object + * @obj: object to check + * + * Return the required GTT alignment for an object, taking into account + * potential fence register mapping. + */ +uint32_t +i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, + int tiling_mode, bool fenced) +{ + /* + * Minimum alignment is 4k (GTT page size), but might be greater + * if a fence register is needed for the object. + */ + if (INTEL_INFO(dev)->gen >= 4 || (!fenced && IS_G33(dev)) || + tiling_mode == I915_TILING_NONE) + return 4096; + + /* + * Previous chips need to be aligned to the size of the smallest + * fence register that can contain the object. + */ + return i915_gem_get_gtt_size(dev, size, tiling_mode); +} + +static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + int ret; + + if (drm_vma_node_has_offset(&obj->base.vma_node)) + return 0; + + dev_priv->mm.shrinker_no_lock_stealing = true; + + ret = drm_gem_create_mmap_offset(&obj->base); + if (ret != -ENOSPC) + goto out; + + /* Badly fragmented mmap space? The only way we can recover + * space is by destroying unwanted objects. We can't randomly release + * mmap_offsets as userspace expects them to be persistent for the + * lifetime of the objects. The closest we can is to release the + * offsets on purgeable objects by truncating it and marking it purged, + * which prevents userspace from ever using that object again. + */ + i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT); + ret = drm_gem_create_mmap_offset(&obj->base); + if (ret != -ENOSPC) + goto out; + + i915_gem_shrink_all(dev_priv); + ret = drm_gem_create_mmap_offset(&obj->base); +out: + dev_priv->mm.shrinker_no_lock_stealing = false; + + return ret; +} + +static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj) +{ + drm_gem_free_mmap_offset(&obj->base); +} + +int +i915_gem_mmap_gtt(struct drm_file *file, + struct drm_device *dev, + uint32_t handle, + uint64_t *offset) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + if (obj->base.size > dev_priv->gtt.mappable_end) { + ret = -E2BIG; + goto out; + } + + if (obj->madv != I915_MADV_WILLNEED) { + DRM_ERROR("Attempting to mmap a purgeable buffer\n"); + ret = -EINVAL; + goto out; + } + + ret = i915_gem_object_create_mmap_offset(obj); + if (ret) + goto out; + + *offset = drm_vma_node_offset_addr(&obj->base.vma_node); + +out: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +/** + * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing + * @dev: DRM device + * @data: GTT mapping ioctl data + * @file: GEM object info + * + * Simply returns the fake offset to userspace so it can mmap it. + * The mmap call will end up in drm_gem_mmap(), which will set things + * up so we can get faults in the handler above. + * + * The fault handler will take care of binding the object into the GTT + * (since it may have been evicted to make room for something), allocating + * a fence register, and mapping the appropriate aperture address into + * userspace. + */ +int +i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_mmap_gtt *args = data; + + return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset); +} + +/* Immediately discard the backing storage */ +static void +i915_gem_object_truncate(struct drm_i915_gem_object *obj) +{ + struct inode *inode; + + i915_gem_object_free_mmap_offset(obj); + + if (obj->base.filp == NULL) + return; + + /* Our goal here is to return as much of the memory as + * is possible back to the system as we are called from OOM. + * To do this we must instruct the shmfs to drop all of its + * backing pages, *now*. + */ + inode = file_inode(obj->base.filp); + shmem_truncate_range(inode, 0, (loff_t)-1); + + obj->madv = __I915_MADV_PURGED; +} + +static inline int +i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) +{ + return obj->madv == I915_MADV_DONTNEED; +} + +static void +i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) +{ + struct sg_page_iter sg_iter; + int ret; + + BUG_ON(obj->madv == __I915_MADV_PURGED); + + ret = i915_gem_object_set_to_cpu_domain(obj, true); + if (ret) { + /* In the event of a disaster, abandon all caches and + * hope for the best. + */ + WARN_ON(ret != -EIO); + i915_gem_clflush_object(obj, true); + obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU; + } + + if (i915_gem_object_needs_bit17_swizzle(obj)) + i915_gem_object_save_bit_17_swizzle(obj); + + if (obj->madv == I915_MADV_DONTNEED) + obj->dirty = 0; + + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + struct page *page = sg_page_iter_page(&sg_iter); + + if (obj->dirty) + set_page_dirty(page); + + if (obj->madv == I915_MADV_WILLNEED) + mark_page_accessed(page); + + page_cache_release(page); + } + obj->dirty = 0; + + sg_free_table(obj->pages); + kfree(obj->pages); +} + +int +i915_gem_object_put_pages(struct drm_i915_gem_object *obj) +{ + const struct drm_i915_gem_object_ops *ops = obj->ops; + + if (obj->pages == NULL) + return 0; + + if (obj->pages_pin_count) + return -EBUSY; + + BUG_ON(i915_gem_obj_bound_any(obj)); + + /* ->put_pages might need to allocate memory for the bit17 swizzle + * array, hence protect them from being reaped by removing them from gtt + * lists early. */ + list_del(&obj->global_list); + + ops->put_pages(obj); + obj->pages = NULL; + + if (i915_gem_object_is_purgeable(obj)) + i915_gem_object_truncate(obj); + + return 0; +} + +static unsigned long +__i915_gem_shrink(struct drm_i915_private *dev_priv, long target, + bool purgeable_only) +{ + struct list_head still_bound_list; + struct drm_i915_gem_object *obj, *next; + unsigned long count = 0; + + list_for_each_entry_safe(obj, next, + &dev_priv->mm.unbound_list, + global_list) { + if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && + i915_gem_object_put_pages(obj) == 0) { + count += obj->base.size >> PAGE_SHIFT; + if (count >= target) + return count; + } + } + + /* + * As we may completely rewrite the bound list whilst unbinding + * (due to retiring requests) we have to strictly process only + * one element of the list at the time, and recheck the list + * on every iteration. + */ + INIT_LIST_HEAD(&still_bound_list); + while (count < target && !list_empty(&dev_priv->mm.bound_list)) { + struct i915_vma *vma, *v; + + obj = list_first_entry(&dev_priv->mm.bound_list, + typeof(*obj), global_list); + list_move_tail(&obj->global_list, &still_bound_list); + + if (!i915_gem_object_is_purgeable(obj) && purgeable_only) + continue; + + /* + * Hold a reference whilst we unbind this object, as we may + * end up waiting for and retiring requests. This might + * release the final reference (held by the active list) + * and result in the object being freed from under us. + * in this object being freed. + * + * Note 1: Shrinking the bound list is special since only active + * (and hence bound objects) can contain such limbo objects, so + * we don't need special tricks for shrinking the unbound list. + * The only other place where we have to be careful with active + * objects suddenly disappearing due to retiring requests is the + * eviction code. + * + * Note 2: Even though the bound list doesn't hold a reference + * to the object we can safely grab one here: The final object + * unreferencing and the bound_list are both protected by the + * dev->struct_mutex and so we won't ever be able to observe an + * object on the bound_list with a reference count equals 0. + */ + drm_gem_object_reference(&obj->base); + + list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link) + if (i915_vma_unbind(vma)) + break; + + if (i915_gem_object_put_pages(obj) == 0) + count += obj->base.size >> PAGE_SHIFT; + + drm_gem_object_unreference(&obj->base); + } + list_splice(&still_bound_list, &dev_priv->mm.bound_list); + + return count; +} + +static unsigned long +i915_gem_purge(struct drm_i915_private *dev_priv, long target) +{ + return __i915_gem_shrink(dev_priv, target, true); +} + +static unsigned long +i915_gem_shrink_all(struct drm_i915_private *dev_priv) +{ + struct drm_i915_gem_object *obj, *next; + long freed = 0; + + i915_gem_evict_everything(dev_priv->dev); + + list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, + global_list) { + if (i915_gem_object_put_pages(obj) == 0) + freed += obj->base.size >> PAGE_SHIFT; + } + return freed; +} + +static int +i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + int page_count, i; + struct address_space *mapping; + struct sg_table *st; + struct scatterlist *sg; + struct sg_page_iter sg_iter; + struct page *page; + unsigned long last_pfn = 0; /* suppress gcc warning */ + gfp_t gfp; + + /* Assert that the object is not currently in any GPU domain. As it + * wasn't in the GTT, there shouldn't be any way it could have been in + * a GPU cache + */ + BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); + BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) + return -ENOMEM; + + page_count = obj->base.size / PAGE_SIZE; + if (sg_alloc_table(st, page_count, GFP_KERNEL)) { + kfree(st); + return -ENOMEM; + } + + /* Get the list of pages out of our struct file. They'll be pinned + * at this point until we release them. + * + * Fail silently without starting the shrinker + */ + mapping = file_inode(obj->base.filp)->i_mapping; + gfp = mapping_gfp_mask(mapping); + gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; + gfp &= ~(__GFP_IO | __GFP_WAIT); + sg = st->sgl; + st->nents = 0; + for (i = 0; i < page_count; i++) { + page = shmem_read_mapping_page_gfp(mapping, i, gfp); + if (IS_ERR(page)) { + i915_gem_purge(dev_priv, page_count); + page = shmem_read_mapping_page_gfp(mapping, i, gfp); + } + if (IS_ERR(page)) { + /* We've tried hard to allocate the memory by reaping + * our own buffer, now let the real VM do its job and + * go down in flames if truly OOM. + */ + gfp &= ~(__GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD); + gfp |= __GFP_IO | __GFP_WAIT; + + i915_gem_shrink_all(dev_priv); + page = shmem_read_mapping_page_gfp(mapping, i, gfp); + if (IS_ERR(page)) + goto err_pages; + + gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; + gfp &= ~(__GFP_IO | __GFP_WAIT); + } +#ifdef CONFIG_SWIOTLB + if (swiotlb_nr_tbl()) { + st->nents++; + sg_set_page(sg, page, PAGE_SIZE, 0); + sg = sg_next(sg); + continue; + } +#endif + if (!i || page_to_pfn(page) != last_pfn + 1) { + if (i) + sg = sg_next(sg); + st->nents++; + sg_set_page(sg, page, PAGE_SIZE, 0); + } else { + sg->length += PAGE_SIZE; + } + last_pfn = page_to_pfn(page); + + /* Check that the i965g/gm workaround works. */ + WARN_ON((gfp & __GFP_DMA32) && (last_pfn >= 0x00100000UL)); + } +#ifdef CONFIG_SWIOTLB + if (!swiotlb_nr_tbl()) +#endif + sg_mark_end(sg); + obj->pages = st; + + if (i915_gem_object_needs_bit17_swizzle(obj)) + i915_gem_object_do_bit_17_swizzle(obj); + + return 0; + +err_pages: + sg_mark_end(sg); + for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) + page_cache_release(sg_page_iter_page(&sg_iter)); + sg_free_table(st); + kfree(st); + return PTR_ERR(page); +} + +/* Ensure that the associated pages are gathered from the backing storage + * and pinned into our object. i915_gem_object_get_pages() may be called + * multiple times before they are released by a single call to + * i915_gem_object_put_pages() - once the pages are no longer referenced + * either as a result of memory pressure (reaping pages under the shrinker) + * or as the object is itself released. + */ +int +i915_gem_object_get_pages(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + const struct drm_i915_gem_object_ops *ops = obj->ops; + int ret; + + if (obj->pages) + return 0; + + if (obj->madv != I915_MADV_WILLNEED) { + DRM_ERROR("Attempting to obtain a purgeable object\n"); + return -EINVAL; + } + + BUG_ON(obj->pages_pin_count); + + ret = ops->get_pages(obj); + if (ret) + return ret; + + list_add_tail(&obj->global_list, &dev_priv->mm.unbound_list); + return 0; +} + +static void +i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 seqno = intel_ring_get_seqno(ring); + + BUG_ON(ring == NULL); + if (obj->ring != ring && obj->last_write_seqno) { + /* Keep the seqno relative to the current ring */ + obj->last_write_seqno = seqno; + } + obj->ring = ring; + + /* Add a reference if we're newly entering the active list. */ + if (!obj->active) { + drm_gem_object_reference(&obj->base); + obj->active = 1; + } + + list_move_tail(&obj->ring_list, &ring->active_list); + + obj->last_read_seqno = seqno; + + if (obj->fenced_gpu_access) { + obj->last_fenced_seqno = seqno; + + /* Bump MRU to take account of the delayed flush */ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_fence_reg *reg; + + reg = &dev_priv->fence_regs[obj->fence_reg]; + list_move_tail(®->lru_list, + &dev_priv->mm.fence_list); + } + } +} + +void i915_vma_move_to_active(struct i915_vma *vma, + struct intel_ring_buffer *ring) +{ + list_move_tail(&vma->mm_list, &vma->vm->active_list); + return i915_gem_object_move_to_active(vma->obj, ring); +} + +static void +i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct i915_address_space *ggtt_vm = &dev_priv->gtt.base; + struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm); + + BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); + BUG_ON(!obj->active); + + list_move_tail(&vma->mm_list, &ggtt_vm->inactive_list); + + list_del_init(&obj->ring_list); + obj->ring = NULL; + + obj->last_read_seqno = 0; + obj->last_write_seqno = 0; + obj->base.write_domain = 0; + + obj->last_fenced_seqno = 0; + obj->fenced_gpu_access = false; + + obj->active = 0; + drm_gem_object_unreference(&obj->base); + + WARN_ON(i915_verify_lists(dev)); +} + +static int +i915_gem_init_seqno(struct drm_device *dev, u32 seqno) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int ret, i, j; + + /* Carefully retire all requests without writing to the rings */ + for_each_ring(ring, dev_priv, i) { + ret = intel_ring_idle(ring); + if (ret) + return ret; + } + i915_gem_retire_requests(dev); + + /* Finally reset hw state */ + for_each_ring(ring, dev_priv, i) { + intel_ring_init_seqno(ring, seqno); + + for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) + ring->sync_seqno[j] = 0; + } + + return 0; +} + +int i915_gem_set_seqno(struct drm_device *dev, u32 seqno) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (seqno == 0) + return -EINVAL; + + /* HWS page needs to be set less than what we + * will inject to ring + */ + ret = i915_gem_init_seqno(dev, seqno - 1); + if (ret) + return ret; + + /* Carefully set the last_seqno value so that wrap + * detection still works + */ + dev_priv->next_seqno = seqno; + dev_priv->last_seqno = seqno - 1; + if (dev_priv->last_seqno == 0) + dev_priv->last_seqno--; + + return 0; +} + +int +i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* reserve 0 for non-seqno */ + if (dev_priv->next_seqno == 0) { + int ret = i915_gem_init_seqno(dev, 0); + if (ret) + return ret; + + dev_priv->next_seqno = 1; + } + + *seqno = dev_priv->last_seqno = dev_priv->next_seqno++; + return 0; +} + +int __i915_add_request(struct intel_ring_buffer *ring, + struct drm_file *file, + struct drm_i915_gem_object *obj, + u32 *out_seqno) +{ + drm_i915_private_t *dev_priv = ring->dev->dev_private; + struct drm_i915_gem_request *request; + u32 request_ring_position, request_start; + int was_empty; + int ret; + + request_start = intel_ring_get_tail(ring); + /* + * Emit any outstanding flushes - execbuf can fail to emit the flush + * after having emitted the batchbuffer command. Hence we need to fix + * things up similar to emitting the lazy request. The difference here + * is that the flush _must_ happen before the next request, no matter + * what. + */ + ret = intel_ring_flush_all_caches(ring); + if (ret) + return ret; + + request = ring->preallocated_lazy_request; + if (WARN_ON(request == NULL)) + return -ENOMEM; + + /* Record the position of the start of the request so that + * should we detect the updated seqno part-way through the + * GPU processing the request, we never over-estimate the + * position of the head. + */ + request_ring_position = intel_ring_get_tail(ring); + + ret = ring->add_request(ring); + if (ret) + return ret; + + request->seqno = intel_ring_get_seqno(ring); + request->ring = ring; + request->head = request_start; + request->tail = request_ring_position; + + /* Whilst this request exists, batch_obj will be on the + * active_list, and so will hold the active reference. Only when this + * request is retired will the the batch_obj be moved onto the + * inactive_list and lose its active reference. Hence we do not need + * to explicitly hold another reference here. + */ + request->batch_obj = obj; + + /* Hold a reference to the current context so that we can inspect + * it later in case a hangcheck error event fires. + */ + request->ctx = ring->last_context; + if (request->ctx) + i915_gem_context_reference(request->ctx); + + request->emitted_jiffies = jiffies; + was_empty = list_empty(&ring->request_list); + list_add_tail(&request->list, &ring->request_list); + request->file_priv = NULL; + + if (file) { + struct drm_i915_file_private *file_priv = file->driver_priv; + + spin_lock(&file_priv->mm.lock); + request->file_priv = file_priv; + list_add_tail(&request->client_list, + &file_priv->mm.request_list); + spin_unlock(&file_priv->mm.lock); + } + + trace_i915_gem_request_add(ring, request->seqno); + ring->outstanding_lazy_seqno = 0; + ring->preallocated_lazy_request = NULL; + + if (!dev_priv->ums.mm_suspended) { + i915_queue_hangcheck(ring->dev); + + if (was_empty) { + cancel_delayed_work_sync(&dev_priv->mm.idle_work); + queue_delayed_work(dev_priv->wq, + &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); + intel_mark_busy(dev_priv->dev); + } + } + + if (out_seqno) + *out_seqno = request->seqno; + return 0; +} + +static inline void +i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) +{ + struct drm_i915_file_private *file_priv = request->file_priv; + + if (!file_priv) + return; + + spin_lock(&file_priv->mm.lock); + list_del(&request->client_list); + request->file_priv = NULL; + spin_unlock(&file_priv->mm.lock); +} + +static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj, + struct i915_address_space *vm) +{ + if (acthd >= i915_gem_obj_offset(obj, vm) && + acthd < i915_gem_obj_offset(obj, vm) + obj->base.size) + return true; + + return false; +} + +static bool i915_head_inside_request(const u32 acthd_unmasked, + const u32 request_start, + const u32 request_end) +{ + const u32 acthd = acthd_unmasked & HEAD_ADDR; + + if (request_start < request_end) { + if (acthd >= request_start && acthd < request_end) + return true; + } else if (request_start > request_end) { + if (acthd >= request_start || acthd < request_end) + return true; + } + + return false; +} + +static struct i915_address_space * +request_to_vm(struct drm_i915_gem_request *request) +{ + struct drm_i915_private *dev_priv = request->ring->dev->dev_private; + struct i915_address_space *vm; + + vm = &dev_priv->gtt.base; + + return vm; +} + +static bool i915_request_guilty(struct drm_i915_gem_request *request, + const u32 acthd, bool *inside) +{ + /* There is a possibility that unmasked head address + * pointing inside the ring, matches the batch_obj address range. + * However this is extremely unlikely. + */ + if (request->batch_obj) { + if (i915_head_inside_object(acthd, request->batch_obj, + request_to_vm(request))) { + *inside = true; + return true; + } + } + + if (i915_head_inside_request(acthd, request->head, request->tail)) { + *inside = false; + return true; + } + + return false; +} + +static bool i915_context_is_banned(const struct i915_ctx_hang_stats *hs) +{ + const unsigned long elapsed = get_seconds() - hs->guilty_ts; + + if (hs->banned) + return true; + + if (elapsed <= DRM_I915_CTX_BAN_PERIOD) { + DRM_ERROR("context hanging too fast, declaring banned!\n"); + return true; + } + + return false; +} + +static void i915_set_reset_status(struct intel_ring_buffer *ring, + struct drm_i915_gem_request *request, + u32 acthd) +{ + struct i915_ctx_hang_stats *hs = NULL; + bool inside, guilty; + unsigned long offset = 0; + + /* Innocent until proven guilty */ + guilty = false; + + if (request->batch_obj) + offset = i915_gem_obj_offset(request->batch_obj, + request_to_vm(request)); + + if (ring->hangcheck.action != HANGCHECK_WAIT && + i915_request_guilty(request, acthd, &inside)) { + DRM_DEBUG("%s hung %s bo (0x%lx ctx %d) at 0x%x\n", + ring->name, + inside ? "inside" : "flushing", + offset, + request->ctx ? request->ctx->id : 0, + acthd); + + guilty = true; + } + + /* If contexts are disabled or this is the default context, use + * file_priv->reset_state + */ + if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID) + hs = &request->ctx->hang_stats; + else if (request->file_priv) + hs = &request->file_priv->hang_stats; + + if (hs) { + if (guilty) { + hs->banned = i915_context_is_banned(hs); + hs->batch_active++; + hs->guilty_ts = get_seconds(); + } else { + hs->batch_pending++; + } + } +} + +static void i915_gem_free_request(struct drm_i915_gem_request *request) +{ + list_del(&request->list); + i915_gem_request_remove_from_client(request); + + if (request->ctx) + i915_gem_context_unreference(request->ctx); + + kfree(request); +} + +static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv, + struct intel_ring_buffer *ring) +{ + u32 completed_seqno = ring->get_seqno(ring, false); + u32 acthd = intel_ring_get_active_head(ring); + struct drm_i915_gem_request *request; + + list_for_each_entry(request, &ring->request_list, list) { + if (i915_seqno_passed(completed_seqno, request->seqno)) + continue; + + i915_set_reset_status(ring, request, acthd); + } +} + +static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, + struct intel_ring_buffer *ring) +{ + while (!list_empty(&ring->active_list)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&ring->active_list, + struct drm_i915_gem_object, + ring_list); + + i915_gem_object_move_to_inactive(obj); + } + + /* + * We must free the requests after all the corresponding objects have + * been moved off active lists. Which is the same order as the normal + * retire_requests function does. This is important if object hold + * implicit references on things like e.g. ppgtt address spaces through + * the request. + */ + while (!list_empty(&ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&ring->request_list, + struct drm_i915_gem_request, + list); + + i915_gem_free_request(request); + } +} + +void i915_gem_restore_fences(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->num_fence_regs; i++) { + struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; + + /* + * Commit delayed tiling changes if we have an object still + * attached to the fence, otherwise just clear the fence. + */ + if (reg->obj) { + i915_gem_object_update_fence(reg->obj, reg, + reg->obj->tiling_mode); + } else { + i915_gem_write_fence(dev, i, NULL); + } + } +} + +void i915_gem_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int i; + + /* + * Before we free the objects from the requests, we need to inspect + * them for finding the guilty party. As the requests only borrow + * their reference to the objects, the inspection must be done first. + */ + for_each_ring(ring, dev_priv, i) + i915_gem_reset_ring_status(dev_priv, ring); + + for_each_ring(ring, dev_priv, i) + i915_gem_reset_ring_cleanup(dev_priv, ring); + + i915_gem_cleanup_ringbuffer(dev); + + i915_gem_restore_fences(dev); +} + +/** + * This function clears the request list as sequence numbers are passed. + */ +void +i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) +{ + uint32_t seqno; + + if (list_empty(&ring->request_list)) + return; + + WARN_ON(i915_verify_lists(ring->dev)); + + seqno = ring->get_seqno(ring, true); + + while (!list_empty(&ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&ring->request_list, + struct drm_i915_gem_request, + list); + + if (!i915_seqno_passed(seqno, request->seqno)) + break; + + trace_i915_gem_request_retire(ring, request->seqno); + /* We know the GPU must have read the request to have + * sent us the seqno + interrupt, so use the position + * of tail of the request to update the last known position + * of the GPU head. + */ + ring->last_retired_head = request->tail; + + i915_gem_free_request(request); + } + + /* Move any buffers on the active list that are no longer referenced + * by the ringbuffer to the flushing/inactive lists as appropriate. + */ + while (!list_empty(&ring->active_list)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&ring->active_list, + struct drm_i915_gem_object, + ring_list); + + if (!i915_seqno_passed(seqno, obj->last_read_seqno)) + break; + + i915_gem_object_move_to_inactive(obj); + } + + if (unlikely(ring->trace_irq_seqno && + i915_seqno_passed(seqno, ring->trace_irq_seqno))) { + ring->irq_put(ring); + ring->trace_irq_seqno = 0; + } + + WARN_ON(i915_verify_lists(ring->dev)); +} + +bool +i915_gem_retire_requests(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + bool idle = true; + int i; + + for_each_ring(ring, dev_priv, i) { + i915_gem_retire_requests_ring(ring); + idle &= list_empty(&ring->request_list); + } + + if (idle) + mod_delayed_work(dev_priv->wq, + &dev_priv->mm.idle_work, + msecs_to_jiffies(100)); + + return idle; +} + +static void +i915_gem_retire_work_handler(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), mm.retire_work.work); + struct drm_device *dev = dev_priv->dev; + bool idle; + + /* Come back later if the device is busy... */ + idle = false; + if (mutex_trylock(&dev->struct_mutex)) { + idle = i915_gem_retire_requests(dev); + mutex_unlock(&dev->struct_mutex); + } + if (!idle) + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); +} + +static void +i915_gem_idle_work_handler(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), mm.idle_work.work); + + intel_mark_idle(dev_priv->dev); +} + +/** + * Ensures that an object will eventually get non-busy by flushing any required + * write domains, emitting any outstanding lazy request and retiring and + * completed requests. + */ +static int +i915_gem_object_flush_active(struct drm_i915_gem_object *obj) +{ + int ret; + + if (obj->active) { + ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno); + if (ret) + return ret; + + i915_gem_retire_requests_ring(obj->ring); + } + + return 0; +} + +/** + * i915_gem_wait_ioctl - implements DRM_IOCTL_I915_GEM_WAIT + * @DRM_IOCTL_ARGS: standard ioctl arguments + * + * Returns 0 if successful, else an error is returned with the remaining time in + * the timeout parameter. + * -ETIME: object is still busy after timeout + * -ERESTARTSYS: signal interrupted the wait + * -ENONENT: object doesn't exist + * Also possible, but rare: + * -EAGAIN: GPU wedged + * -ENOMEM: damn + * -ENODEV: Internal IRQ fail + * -E?: The add request failed + * + * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any + * non-zero timeout parameter the wait ioctl will wait for the given number of + * nanoseconds on an object becoming unbusy. Since the wait itself does so + * without holding struct_mutex the object may become re-busied before this + * function completes. A similar but shorter * race condition exists in the busy + * ioctl + */ +int +i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_gem_wait *args = data; + struct drm_i915_gem_object *obj; + struct intel_ring_buffer *ring = NULL; + struct timespec timeout_stack, *timeout = NULL; + unsigned reset_counter; + u32 seqno = 0; + int ret = 0; + + if (args->timeout_ns >= 0) { + timeout_stack = ns_to_timespec(args->timeout_ns); + timeout = &timeout_stack; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->bo_handle)); + if (&obj->base == NULL) { + mutex_unlock(&dev->struct_mutex); + return -ENOENT; + } + + /* Need to make sure the object gets inactive eventually. */ + ret = i915_gem_object_flush_active(obj); + if (ret) + goto out; + + if (obj->active) { + seqno = obj->last_read_seqno; + ring = obj->ring; + } + + if (seqno == 0) + goto out; + + /* Do this after OLR check to make sure we make forward progress polling + * on this IOCTL with a 0 timeout (like busy ioctl) + */ + if (!args->timeout_ns) { + ret = -ETIME; + goto out; + } + + drm_gem_object_unreference(&obj->base); + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + mutex_unlock(&dev->struct_mutex); + + ret = __wait_seqno(ring, seqno, reset_counter, true, timeout, file->driver_priv); + if (timeout) + args->timeout_ns = timespec_to_ns(timeout); + return ret; + +out: + drm_gem_object_unreference(&obj->base); + mutex_unlock(&dev->struct_mutex); + return ret; +} + +/** + * i915_gem_object_sync - sync an object to a ring. + * + * @obj: object which may be in use on another ring. + * @to: ring we wish to use the object on. May be NULL. + * + * This code is meant to abstract object synchronization with the GPU. + * Calling with NULL implies synchronizing the object with the CPU + * rather than a particular GPU ring. + * + * Returns 0 if successful, else propagates up the lower layer error. + */ +int +i915_gem_object_sync(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *to) +{ + struct intel_ring_buffer *from = obj->ring; + u32 seqno; + int ret, idx; + + if (from == NULL || to == from) + return 0; + + if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev)) + return i915_gem_object_wait_rendering(obj, false); + + idx = intel_ring_sync_index(from, to); + + seqno = obj->last_read_seqno; + if (seqno <= from->sync_seqno[idx]) + return 0; + + ret = i915_gem_check_olr(obj->ring, seqno); + if (ret) + return ret; + + trace_i915_gem_ring_sync_to(from, to, seqno); + ret = to->sync_to(to, from, seqno); + if (!ret) + /* We use last_read_seqno because sync_to() + * might have just caused seqno wrap under + * the radar. + */ + from->sync_seqno[idx] = obj->last_read_seqno; + + return ret; +} + +static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) +{ + u32 old_write_domain, old_read_domains; + + /* Force a pagefault for domain tracking on next user access */ + i915_gem_release_mmap(obj); + + if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) + return; + + /* Wait for any direct GTT access to complete */ + mb(); + + old_read_domains = obj->base.read_domains; + old_write_domain = obj->base.write_domain; + + obj->base.read_domains &= ~I915_GEM_DOMAIN_GTT; + obj->base.write_domain &= ~I915_GEM_DOMAIN_GTT; + + trace_i915_gem_object_change_domain(obj, + old_read_domains, + old_write_domain); +} + +int i915_vma_unbind(struct i915_vma *vma) +{ + struct drm_i915_gem_object *obj = vma->obj; + drm_i915_private_t *dev_priv = obj->base.dev->dev_private; + int ret; + + /* For now we only ever use 1 vma per object */ + WARN_ON(!list_is_singular(&obj->vma_list)); + + if (list_empty(&vma->vma_link)) + return 0; + + if (!drm_mm_node_allocated(&vma->node)) { + i915_gem_vma_destroy(vma); + + return 0; + } + + if (obj->pin_count) + return -EBUSY; + + BUG_ON(obj->pages == NULL); + + ret = i915_gem_object_finish_gpu(obj); + if (ret) + return ret; + /* Continue on if we fail due to EIO, the GPU is hung so we + * should be safe and we need to cleanup or else we might + * cause memory corruption through use-after-free. + */ + + i915_gem_object_finish_gtt(obj); + + /* release the fence reg _after_ flushing */ + ret = i915_gem_object_put_fence(obj); + if (ret) + return ret; + + trace_i915_vma_unbind(vma); + + if (obj->has_global_gtt_mapping) + i915_gem_gtt_unbind_object(obj); + if (obj->has_aliasing_ppgtt_mapping) { + i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj); + obj->has_aliasing_ppgtt_mapping = 0; + } + i915_gem_gtt_finish_object(obj); + + list_del(&vma->mm_list); + /* Avoid an unnecessary call to unbind on rebind. */ + if (i915_is_ggtt(vma->vm)) + obj->map_and_fenceable = true; + + drm_mm_remove_node(&vma->node); + i915_gem_vma_destroy(vma); + + /* Since the unbound list is global, only move to that list if + * no more VMAs exist. */ + if (list_empty(&obj->vma_list)) + list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list); + + /* And finally now the object is completely decoupled from this vma, + * we can drop its hold on the backing storage and allow it to be + * reaped by the shrinker. + */ + i915_gem_object_unpin_pages(obj); + + return 0; +} + +/** + * Unbinds an object from the global GTT aperture. + */ +int +i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct i915_address_space *ggtt = &dev_priv->gtt.base; + + if (!i915_gem_obj_ggtt_bound(obj)) + return 0; + + if (obj->pin_count) + return -EBUSY; + + BUG_ON(obj->pages == NULL); + + return i915_vma_unbind(i915_gem_obj_to_vma(obj, ggtt)); +} + +int i915_gpu_idle(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int ret, i; + + /* Flush everything onto the inactive list. */ + for_each_ring(ring, dev_priv, i) { + ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID); + if (ret) + return ret; + + ret = intel_ring_idle(ring); + if (ret) + return ret; + } + + return 0; +} + +static void i965_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int fence_reg; + int fence_pitch_shift; + + if (INTEL_INFO(dev)->gen >= 6) { + fence_reg = FENCE_REG_SANDYBRIDGE_0; + fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; + } else { + fence_reg = FENCE_REG_965_0; + fence_pitch_shift = I965_FENCE_PITCH_SHIFT; + } + + fence_reg += reg * 8; + + /* To w/a incoherency with non-atomic 64-bit register updates, + * we split the 64-bit update into two 32-bit writes. In order + * for a partial fence not to be evaluated between writes, we + * precede the update with write to turn off the fence register, + * and only enable the fence as the last step. + * + * For extra levels of paranoia, we make sure each step lands + * before applying the next step. + */ + I915_WRITE(fence_reg, 0); + POSTING_READ(fence_reg); + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + uint64_t val; + + val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) & + 0xfffff000) << 32; + val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000; + val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I965_FENCE_TILING_Y_SHIFT; + val |= I965_FENCE_REG_VALID; + + I915_WRITE(fence_reg + 4, val >> 32); + POSTING_READ(fence_reg + 4); + + I915_WRITE(fence_reg + 0, val); + POSTING_READ(fence_reg); + } else { + I915_WRITE(fence_reg + 4, 0); + POSTING_READ(fence_reg + 4); + } +} + +static void i915_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 val; + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + int pitch_val; + int tile_width; + + WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) || + (size & -size) != size || + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", + i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size); + + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) + tile_width = 128; + else + tile_width = 512; + + /* Note: pitch better be a power of two tile widths */ + pitch_val = obj->stride / tile_width; + pitch_val = ffs(pitch_val) - 1; + + val = i915_gem_obj_ggtt_offset(obj); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I915_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; + + if (reg < 8) + reg = FENCE_REG_830_0 + reg * 4; + else + reg = FENCE_REG_945_8 + (reg - 8) * 4; + + I915_WRITE(reg, val); + POSTING_READ(reg); +} + +static void i830_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t val; + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + uint32_t pitch_val; + + WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) || + (size & -size) != size || + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx not 512K or pot-size 0x%08x aligned\n", + i915_gem_obj_ggtt_offset(obj), size); + + pitch_val = obj->stride / 128; + pitch_val = ffs(pitch_val) - 1; + + val = i915_gem_obj_ggtt_offset(obj); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I830_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; + + I915_WRITE(FENCE_REG_830_0 + reg * 4, val); + POSTING_READ(FENCE_REG_830_0 + reg * 4); +} + +inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) +{ + return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; +} + +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Ensure that all CPU reads are completed before installing a fence + * and all writes before removing the fence. + */ + if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) + mb(); + + WARN(obj && (!obj->stride || !obj->tiling_mode), + "bogus fence setup with stride: 0x%x, tiling mode: %i\n", + obj->stride, obj->tiling_mode); + + switch (INTEL_INFO(dev)->gen) { + case 8: + case 7: + case 6: + case 5: + case 4: i965_write_fence_reg(dev, reg, obj); break; + case 3: i915_write_fence_reg(dev, reg, obj); break; + case 2: i830_write_fence_reg(dev, reg, obj); break; + default: BUG(); + } + + /* And similarly be paranoid that no direct access to this region + * is reordered to before the fence is installed. + */ + if (i915_gem_object_needs_mb(obj)) + mb(); +} + +static inline int fence_number(struct drm_i915_private *dev_priv, + struct drm_i915_fence_reg *fence) +{ + return fence - dev_priv->fence_regs; +} + +static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, + struct drm_i915_fence_reg *fence, + bool enable) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + int reg = fence_number(dev_priv, fence); + + i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + + if (enable) { + obj->fence_reg = reg; + fence->obj = obj; + list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); + } else { + obj->fence_reg = I915_FENCE_REG_NONE; + fence->obj = NULL; + list_del_init(&fence->lru_list); + } + obj->fence_dirty = false; +} + +static int +i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) +{ + if (obj->last_fenced_seqno) { + int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); + if (ret) + return ret; + + obj->last_fenced_seqno = 0; + } + + obj->fenced_gpu_access = false; + return 0; +} + +int +i915_gem_object_put_fence(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct drm_i915_fence_reg *fence; + int ret; + + ret = i915_gem_object_wait_fence(obj); + if (ret) + return ret; + + if (obj->fence_reg == I915_FENCE_REG_NONE) + return 0; + + fence = &dev_priv->fence_regs[obj->fence_reg]; + + i915_gem_object_fence_lost(obj); + i915_gem_object_update_fence(obj, fence, false); + + return 0; +} + +static struct drm_i915_fence_reg * +i915_find_fence_reg(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_fence_reg *reg, *avail; + int i; + + /* First try to find a free reg */ + avail = NULL; + for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { + reg = &dev_priv->fence_regs[i]; + if (!reg->obj) + return reg; + + if (!reg->pin_count) + avail = reg; + } + + if (avail == NULL) + goto deadlock; + + /* None available, try to steal one or wait for a user to finish */ + list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { + if (reg->pin_count) + continue; + + return reg; + } + +deadlock: + /* Wait for completion of pending flips which consume fences */ + if (intel_has_pending_fb_unpin(dev)) + return ERR_PTR(-EAGAIN); + + return ERR_PTR(-EDEADLK); +} + +/** + * i915_gem_object_get_fence - set up fencing for an object + * @obj: object to map through a fence reg + * + * When mapping objects through the GTT, userspace wants to be able to write + * to them without having to worry about swizzling if the object is tiled. + * This function walks the fence regs looking for a free one for @obj, + * stealing one if it can't find any. + * + * It then sets up the reg based on the object's properties: address, pitch + * and tiling format. + * + * For an untiled surface, this removes any existing fence. + */ +int +i915_gem_object_get_fence(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + bool enable = obj->tiling_mode != I915_TILING_NONE; + struct drm_i915_fence_reg *reg; + int ret; + + /* Have we updated the tiling parameters upon the object and so + * will need to serialise the write to the associated fence register? + */ + if (obj->fence_dirty) { + ret = i915_gem_object_wait_fence(obj); + if (ret) + return ret; + } + + /* Just update our place in the LRU if our fence is getting reused. */ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + reg = &dev_priv->fence_regs[obj->fence_reg]; + if (!obj->fence_dirty) { + list_move_tail(®->lru_list, + &dev_priv->mm.fence_list); + return 0; + } + } else if (enable) { + reg = i915_find_fence_reg(dev); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + if (reg->obj) { + struct drm_i915_gem_object *old = reg->obj; + + ret = i915_gem_object_wait_fence(old); + if (ret) + return ret; + + i915_gem_object_fence_lost(old); + } + } else + return 0; + + i915_gem_object_update_fence(obj, reg, enable); + + return 0; +} + +static bool i915_gem_valid_gtt_space(struct drm_device *dev, + struct drm_mm_node *gtt_space, + unsigned long cache_level) +{ + struct drm_mm_node *other; + + /* On non-LLC machines we have to be careful when putting differing + * types of snoopable memory together to avoid the prefetcher + * crossing memory domains and dying. + */ + if (HAS_LLC(dev)) + return true; + + if (!drm_mm_node_allocated(gtt_space)) + return true; + + if (list_empty(>t_space->node_list)) + return true; + + other = list_entry(gtt_space->node_list.prev, struct drm_mm_node, node_list); + if (other->allocated && !other->hole_follows && other->color != cache_level) + return false; + + other = list_entry(gtt_space->node_list.next, struct drm_mm_node, node_list); + if (other->allocated && !gtt_space->hole_follows && other->color != cache_level) + return false; + + return true; +} + +static void i915_gem_verify_gtt(struct drm_device *dev) +{ +#if WATCH_GTT + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + int err = 0; + + list_for_each_entry(obj, &dev_priv->mm.gtt_list, global_list) { + if (obj->gtt_space == NULL) { + printk(KERN_ERR "object found on GTT list with no space reserved\n"); + err++; + continue; + } + + if (obj->cache_level != obj->gtt_space->color) { + printk(KERN_ERR "object reserved space [%08lx, %08lx] with wrong color, cache_level=%x, color=%lx\n", + i915_gem_obj_ggtt_offset(obj), + i915_gem_obj_ggtt_offset(obj) + i915_gem_obj_ggtt_size(obj), + obj->cache_level, + obj->gtt_space->color); + err++; + continue; + } + + if (!i915_gem_valid_gtt_space(dev, + obj->gtt_space, + obj->cache_level)) { + printk(KERN_ERR "invalid GTT space found at [%08lx, %08lx] - color=%x\n", + i915_gem_obj_ggtt_offset(obj), + i915_gem_obj_ggtt_offset(obj) + i915_gem_obj_ggtt_size(obj), + obj->cache_level); + err++; + continue; + } + } + + WARN_ON(err); +#endif +} + +/** + * Finds free space in the GTT aperture and binds the object there. + */ +static int +i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + unsigned alignment, + bool map_and_fenceable, + bool nonblocking) +{ + struct drm_device *dev = obj->base.dev; + drm_i915_private_t *dev_priv = dev->dev_private; + u32 size, fence_size, fence_alignment, unfenced_alignment; + size_t gtt_max = + map_and_fenceable ? dev_priv->gtt.mappable_end : vm->total; + struct i915_vma *vma; + int ret; + + fence_size = i915_gem_get_gtt_size(dev, + obj->base.size, + obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode, true); + unfenced_alignment = + i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode, false); + + if (alignment == 0) + alignment = map_and_fenceable ? fence_alignment : + unfenced_alignment; + if (map_and_fenceable && alignment & (fence_alignment - 1)) { + DRM_ERROR("Invalid object alignment requested %u\n", alignment); + return -EINVAL; + } + + size = map_and_fenceable ? fence_size : obj->base.size; + + /* If the object is bigger than the entire aperture, reject it early + * before evicting everything in a vain attempt to find space. + */ + if (obj->base.size > gtt_max) { + DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n", + obj->base.size, + map_and_fenceable ? "mappable" : "total", + gtt_max); + return -E2BIG; + } + + ret = i915_gem_object_get_pages(obj); + if (ret) + return ret; + + i915_gem_object_pin_pages(obj); + + BUG_ON(!i915_is_ggtt(vm)); + + vma = i915_gem_obj_lookup_or_create_vma(obj, vm); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto err_unpin; + } + + /* For now we only ever use 1 vma per object */ + WARN_ON(!list_is_singular(&obj->vma_list)); + +search_free: + ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, + size, alignment, + obj->cache_level, 0, gtt_max, + DRM_MM_SEARCH_DEFAULT); + if (ret) { + ret = i915_gem_evict_something(dev, vm, size, alignment, + obj->cache_level, + map_and_fenceable, + nonblocking); + if (ret == 0) + goto search_free; + + goto err_free_vma; + } + if (WARN_ON(!i915_gem_valid_gtt_space(dev, &vma->node, + obj->cache_level))) { + ret = -EINVAL; + goto err_remove_node; + } + + ret = i915_gem_gtt_prepare_object(obj); + if (ret) + goto err_remove_node; + + list_move_tail(&obj->global_list, &dev_priv->mm.bound_list); + list_add_tail(&vma->mm_list, &vm->inactive_list); + + if (i915_is_ggtt(vm)) { + bool mappable, fenceable; + + fenceable = (vma->node.size == fence_size && + (vma->node.start & (fence_alignment - 1)) == 0); + + mappable = (vma->node.start + obj->base.size <= + dev_priv->gtt.mappable_end); + + obj->map_and_fenceable = mappable && fenceable; + } + + WARN_ON(map_and_fenceable && !obj->map_and_fenceable); + + trace_i915_vma_bind(vma, map_and_fenceable); + i915_gem_verify_gtt(dev); + return 0; + +err_remove_node: + drm_mm_remove_node(&vma->node); +err_free_vma: + i915_gem_vma_destroy(vma); +err_unpin: + i915_gem_object_unpin_pages(obj); + return ret; +} + +bool +i915_gem_clflush_object(struct drm_i915_gem_object *obj, + bool force) +{ + /* If we don't have a page list set up, then we're not pinned + * to GPU, and we can ignore the cache flush because it'll happen + * again at bind time. + */ + if (obj->pages == NULL) + return false; + + /* + * Stolen memory is always coherent with the GPU as it is explicitly + * marked as wc by the system, or the system is cache-coherent. + */ + if (obj->stolen) + return false; + + /* If the GPU is snooping the contents of the CPU cache, + * we do not need to manually clear the CPU cache lines. However, + * the caches are only snooped when the render cache is + * flushed/invalidated. As we always have to emit invalidations + * and flushes when moving into and out of the RENDER domain, correct + * snooping behaviour occurs naturally as the result of our domain + * tracking. + */ + if (!force && cpu_cache_is_coherent(obj->base.dev, obj->cache_level)) + return false; + + trace_i915_gem_object_clflush(obj); + drm_clflush_sg(obj->pages); + + return true; +} + +/** Flushes the GTT write domain for the object if it's dirty. */ +static void +i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) +{ + uint32_t old_write_domain; + + if (obj->base.write_domain != I915_GEM_DOMAIN_GTT) + return; + + /* No actual flushing is required for the GTT write domain. Writes + * to it immediately go to main memory as far as we know, so there's + * no chipset flush. It also doesn't land in render cache. + * + * However, we do have to enforce the order so that all writes through + * the GTT land before any writes to the device, such as updates to + * the GATT itself. + */ + wmb(); + + old_write_domain = obj->base.write_domain; + obj->base.write_domain = 0; + + trace_i915_gem_object_change_domain(obj, + obj->base.read_domains, + old_write_domain); +} + +/** Flushes the CPU write domain for the object if it's dirty. */ +static void +i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj, + bool force) +{ + uint32_t old_write_domain; + + if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) + return; + + if (i915_gem_clflush_object(obj, force)) + i915_gem_chipset_flush(obj->base.dev); + + old_write_domain = obj->base.write_domain; + obj->base.write_domain = 0; + + trace_i915_gem_object_change_domain(obj, + obj->base.read_domains, + old_write_domain); +} + +/** + * Moves a single object to the GTT read, and possibly write domain. + * + * This function returns when the move is complete, including waiting on + * flushes to occur. + */ +int +i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) +{ + drm_i915_private_t *dev_priv = obj->base.dev->dev_private; + uint32_t old_write_domain, old_read_domains; + int ret; + + /* Not valid to be called on unbound objects. */ + if (!i915_gem_obj_bound_any(obj)) + return -EINVAL; + + if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) + return 0; + + ret = i915_gem_object_wait_rendering(obj, !write); + if (ret) + return ret; + + i915_gem_object_flush_cpu_write_domain(obj, false); + + /* Serialise direct access to this object with the barriers for + * coherent writes from the GPU, by effectively invalidating the + * GTT domain upon first access. + */ + if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) + mb(); + + old_write_domain = obj->base.write_domain; + old_read_domains = obj->base.read_domains; + + /* It should now be out of any other write domains, and we can update + * the domain values for our changes. + */ + BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0); + obj->base.read_domains |= I915_GEM_DOMAIN_GTT; + if (write) { + obj->base.read_domains = I915_GEM_DOMAIN_GTT; + obj->base.write_domain = I915_GEM_DOMAIN_GTT; + obj->dirty = 1; + } + + trace_i915_gem_object_change_domain(obj, + old_read_domains, + old_write_domain); + + /* And bump the LRU for this access */ + if (i915_gem_object_is_inactive(obj)) { + struct i915_vma *vma = i915_gem_obj_to_ggtt(obj); + if (vma) + list_move_tail(&vma->mm_list, + &dev_priv->gtt.base.inactive_list); + + } + + return 0; +} + +int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, + enum i915_cache_level cache_level) +{ + struct drm_device *dev = obj->base.dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct i915_vma *vma; + int ret; + + if (obj->cache_level == cache_level) + return 0; + + if (obj->pin_count) { + DRM_DEBUG("can not change the cache level of pinned objects\n"); + return -EBUSY; + } + + list_for_each_entry(vma, &obj->vma_list, vma_link) { + if (!i915_gem_valid_gtt_space(dev, &vma->node, cache_level)) { + ret = i915_vma_unbind(vma); + if (ret) + return ret; + + break; + } + } + + if (i915_gem_obj_bound_any(obj)) { + ret = i915_gem_object_finish_gpu(obj); + if (ret) + return ret; + + i915_gem_object_finish_gtt(obj); + + /* Before SandyBridge, you could not use tiling or fence + * registers with snooped memory, so relinquish any fences + * currently pointing to our region in the aperture. + */ + if (INTEL_INFO(dev)->gen < 6) { + ret = i915_gem_object_put_fence(obj); + if (ret) + return ret; + } + + if (obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(obj, cache_level); + if (obj->has_aliasing_ppgtt_mapping) + i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, + obj, cache_level); + } + + list_for_each_entry(vma, &obj->vma_list, vma_link) + vma->node.color = cache_level; + obj->cache_level = cache_level; + + if (cpu_write_needs_clflush(obj)) { + u32 old_read_domains, old_write_domain; + + /* If we're coming from LLC cached, then we haven't + * actually been tracking whether the data is in the + * CPU cache or not, since we only allow one bit set + * in obj->write_domain and have been skipping the clflushes. + * Just set it to the CPU cache for now. + */ + WARN_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU); + + old_read_domains = obj->base.read_domains; + old_write_domain = obj->base.write_domain; + + obj->base.read_domains = I915_GEM_DOMAIN_CPU; + obj->base.write_domain = I915_GEM_DOMAIN_CPU; + + trace_i915_gem_object_change_domain(obj, + old_read_domains, + old_write_domain); + } + + i915_gem_verify_gtt(dev); + return 0; +} + +int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_caching *args = data; + struct drm_i915_gem_object *obj; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + switch (obj->cache_level) { + case I915_CACHE_LLC: + case I915_CACHE_L3_LLC: + args->caching = I915_CACHING_CACHED; + break; + + case I915_CACHE_WT: + args->caching = I915_CACHING_DISPLAY; + break; + + default: + args->caching = I915_CACHING_NONE; + break; + } + + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_caching *args = data; + struct drm_i915_gem_object *obj; + enum i915_cache_level level; + int ret; + + switch (args->caching) { + case I915_CACHING_NONE: + level = I915_CACHE_NONE; + break; + case I915_CACHING_CACHED: + level = I915_CACHE_LLC; + break; + case I915_CACHING_DISPLAY: + level = HAS_WT(dev) ? I915_CACHE_WT : I915_CACHE_NONE; + break; + default: + return -EINVAL; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + ret = i915_gem_object_set_cache_level(obj, level); + + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +static bool is_pin_display(struct drm_i915_gem_object *obj) +{ + /* There are 3 sources that pin objects: + * 1. The display engine (scanouts, sprites, cursors); + * 2. Reservations for execbuffer; + * 3. The user. + * + * We can ignore reservations as we hold the struct_mutex and + * are only called outside of the reservation path. The user + * can only increment pin_count once, and so if after + * subtracting the potential reference by the user, any pin_count + * remains, it must be due to another use by the display engine. + */ + return obj->pin_count - !!obj->user_pin_count; +} + +/* + * Prepare buffer for display plane (scanout, cursors, etc). + * Can be called from an uninterruptible phase (modesetting) and allows + * any flushes to be pipelined (for pageflips). + */ +int +i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, + u32 alignment, + struct intel_ring_buffer *pipelined) +{ + u32 old_read_domains, old_write_domain; + int ret; + + if (pipelined != obj->ring) { + ret = i915_gem_object_sync(obj, pipelined); + if (ret) + return ret; + } + + /* Mark the pin_display early so that we account for the + * display coherency whilst setting up the cache domains. + */ + obj->pin_display = true; + + /* The display engine is not coherent with the LLC cache on gen6. As + * a result, we make sure that the pinning that is about to occur is + * done with uncached PTEs. This is lowest common denominator for all + * chipsets. + * + * However for gen6+, we could do better by using the GFDT bit instead + * of uncaching, which would allow us to flush all the LLC-cached data + * with that bit in the PTE to main memory with just one PIPE_CONTROL. + */ + ret = i915_gem_object_set_cache_level(obj, + HAS_WT(obj->base.dev) ? I915_CACHE_WT : I915_CACHE_NONE); + if (ret) + goto err_unpin_display; + + /* As the user may map the buffer once pinned in the display plane + * (e.g. libkms for the bootup splash), we have to ensure that we + * always use map_and_fenceable for all scanout buffers. + */ + ret = i915_gem_obj_ggtt_pin(obj, alignment, true, false); + if (ret) + goto err_unpin_display; + + i915_gem_object_flush_cpu_write_domain(obj, true); + + old_write_domain = obj->base.write_domain; + old_read_domains = obj->base.read_domains; + + /* It should now be out of any other write domains, and we can update + * the domain values for our changes. + */ + obj->base.write_domain = 0; + obj->base.read_domains |= I915_GEM_DOMAIN_GTT; + + trace_i915_gem_object_change_domain(obj, + old_read_domains, + old_write_domain); + + return 0; + +err_unpin_display: + obj->pin_display = is_pin_display(obj); + return ret; +} + +void +i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj) +{ + i915_gem_object_unpin(obj); + obj->pin_display = is_pin_display(obj); +} + +int +i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj) +{ + int ret; + + if ((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) + return 0; + + ret = i915_gem_object_wait_rendering(obj, false); + if (ret) + return ret; + + /* Ensure that we invalidate the GPU's caches and TLBs. */ + obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; + return 0; +} + +/** + * Moves a single object to the CPU read, and possibly write domain. + * + * This function returns when the move is complete, including waiting on + * flushes to occur. + */ +int +i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) +{ + uint32_t old_write_domain, old_read_domains; + int ret; + + if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) + return 0; + + ret = i915_gem_object_wait_rendering(obj, !write); + if (ret) + return ret; + + i915_gem_object_flush_gtt_write_domain(obj); + + old_write_domain = obj->base.write_domain; + old_read_domains = obj->base.read_domains; + + /* Flush the CPU cache if it's still invalid. */ + if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) { + i915_gem_clflush_object(obj, false); + + obj->base.read_domains |= I915_GEM_DOMAIN_CPU; + } + + /* It should now be out of any other write domains, and we can update + * the domain values for our changes. + */ + BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) != 0); + + /* If we're writing through the CPU, then the GPU read domains will + * need to be invalidated at next use. + */ + if (write) { + obj->base.read_domains = I915_GEM_DOMAIN_CPU; + obj->base.write_domain = I915_GEM_DOMAIN_CPU; + } + + trace_i915_gem_object_change_domain(obj, + old_read_domains, + old_write_domain); + + return 0; +} + +/* Throttle our rendering by waiting until the ring has completed our requests + * emitted over 20 msec ago. + * + * Note that if we were to use the current jiffies each time around the loop, + * we wouldn't escape the function with any frames outstanding if the time to + * render a frame was over 20ms. + * + * This should get us reasonable parallelism between CPU and GPU but also + * relatively low latency when blocking on a particular request to finish. + */ +static int +i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_file_private *file_priv = file->driver_priv; + unsigned long recent_enough = jiffies - msecs_to_jiffies(20); + struct drm_i915_gem_request *request; + struct intel_ring_buffer *ring = NULL; + unsigned reset_counter; + u32 seqno = 0; + int ret; + + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); + if (ret) + return ret; + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, false); + if (ret) + return ret; + + spin_lock(&file_priv->mm.lock); + list_for_each_entry(request, &file_priv->mm.request_list, client_list) { + if (time_after_eq(request->emitted_jiffies, recent_enough)) + break; + + ring = request->ring; + seqno = request->seqno; + } + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + spin_unlock(&file_priv->mm.lock); + + if (seqno == 0) + return 0; + + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL, NULL); + if (ret == 0) + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); + + return ret; +} + +int +i915_gem_object_pin(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + uint32_t alignment, + bool map_and_fenceable, + bool nonblocking) +{ + struct i915_vma *vma; + int ret; + + if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) + return -EBUSY; + + WARN_ON(map_and_fenceable && !i915_is_ggtt(vm)); + + vma = i915_gem_obj_to_vma(obj, vm); + + if (vma) { + if ((alignment && + vma->node.start & (alignment - 1)) || + (map_and_fenceable && !obj->map_and_fenceable)) { + WARN(obj->pin_count, + "bo is already pinned with incorrect alignment:" + " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d," + " obj->map_and_fenceable=%d\n", + i915_gem_obj_offset(obj, vm), alignment, + map_and_fenceable, + obj->map_and_fenceable); + ret = i915_vma_unbind(vma); + if (ret) + return ret; + } + } + + if (!i915_gem_obj_bound(obj, vm)) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + + ret = i915_gem_object_bind_to_vm(obj, vm, alignment, + map_and_fenceable, + nonblocking); + if (ret) + return ret; + + if (!dev_priv->mm.aliasing_ppgtt) + i915_gem_gtt_bind_object(obj, obj->cache_level); + } + + if (!obj->has_global_gtt_mapping && map_and_fenceable) + i915_gem_gtt_bind_object(obj, obj->cache_level); + + obj->pin_count++; + obj->pin_mappable |= map_and_fenceable; + + return 0; +} + +void +i915_gem_object_unpin(struct drm_i915_gem_object *obj) +{ + BUG_ON(obj->pin_count == 0); + BUG_ON(!i915_gem_obj_bound_any(obj)); + + if (--obj->pin_count == 0) + obj->pin_mappable = false; +} + +int +i915_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_pin *args = data; + struct drm_i915_gem_object *obj; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + if (obj->madv != I915_MADV_WILLNEED) { + DRM_ERROR("Attempting to pin a purgeable buffer\n"); + ret = -EINVAL; + goto out; + } + + if (obj->pin_filp != NULL && obj->pin_filp != file) { + DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n", + args->handle); + ret = -EINVAL; + goto out; + } + + if (obj->user_pin_count == ULONG_MAX) { + ret = -EBUSY; + goto out; + } + + if (obj->user_pin_count == 0) { + ret = i915_gem_obj_ggtt_pin(obj, args->alignment, true, false); + if (ret) + goto out; + } + + obj->user_pin_count++; + obj->pin_filp = file; + + args->offset = i915_gem_obj_ggtt_offset(obj); +out: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int +i915_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_pin *args = data; + struct drm_i915_gem_object *obj; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + if (obj->pin_filp != file) { + DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", + args->handle); + ret = -EINVAL; + goto out; + } + obj->user_pin_count--; + if (obj->user_pin_count == 0) { + obj->pin_filp = NULL; + i915_gem_object_unpin(obj); + } + +out: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int +i915_gem_busy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_busy *args = data; + struct drm_i915_gem_object *obj; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + /* Count all active objects as busy, even if they are currently not used + * by the gpu. Users of this interface expect objects to eventually + * become non-busy without any further actions, therefore emit any + * necessary flushes here. + */ + ret = i915_gem_object_flush_active(obj); + + args->busy = obj->active; + if (obj->ring) { + BUILD_BUG_ON(I915_NUM_RINGS > 16); + args->busy |= intel_ring_flag(obj->ring) << 16; + } + + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int +i915_gem_throttle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return i915_gem_ring_throttle(dev, file_priv); +} + +int +i915_gem_madvise_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_i915_gem_madvise *args = data; + struct drm_i915_gem_object *obj; + int ret; + + switch (args->madv) { + case I915_MADV_DONTNEED: + case I915_MADV_WILLNEED: + break; + default: + return -EINVAL; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file_priv, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + if (obj->pin_count) { + ret = -EINVAL; + goto out; + } + + if (obj->madv != __I915_MADV_PURGED) + obj->madv = args->madv; + + /* if the object is no longer attached, discard its backing storage */ + if (i915_gem_object_is_purgeable(obj) && obj->pages == NULL) + i915_gem_object_truncate(obj); + + args->retained = obj->madv != __I915_MADV_PURGED; + +out: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +void i915_gem_object_init(struct drm_i915_gem_object *obj, + const struct drm_i915_gem_object_ops *ops) +{ + INIT_LIST_HEAD(&obj->global_list); + INIT_LIST_HEAD(&obj->ring_list); + INIT_LIST_HEAD(&obj->obj_exec_link); + INIT_LIST_HEAD(&obj->vma_list); + + obj->ops = ops; + + obj->fence_reg = I915_FENCE_REG_NONE; + obj->madv = I915_MADV_WILLNEED; + /* Avoid an unnecessary call to unbind on the first bind. */ + obj->map_and_fenceable = true; + + i915_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size); +} + +static const struct drm_i915_gem_object_ops i915_gem_object_ops = { + .get_pages = i915_gem_object_get_pages_gtt, + .put_pages = i915_gem_object_put_pages_gtt, +}; + +struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, + size_t size) +{ + struct drm_i915_gem_object *obj; + struct address_space *mapping; + gfp_t mask; + + obj = i915_gem_object_alloc(dev); + if (obj == NULL) + return NULL; + + if (drm_gem_object_init(dev, &obj->base, size) != 0) { + i915_gem_object_free(obj); + return NULL; + } + + mask = GFP_HIGHUSER | __GFP_RECLAIMABLE; + if (IS_CRESTLINE(dev) || IS_BROADWATER(dev)) { + /* 965gm cannot relocate objects above 4GiB. */ + mask &= ~__GFP_HIGHMEM; + mask |= __GFP_DMA32; + } + + mapping = file_inode(obj->base.filp)->i_mapping; + mapping_set_gfp_mask(mapping, mask); + + i915_gem_object_init(obj, &i915_gem_object_ops); + + obj->base.write_domain = I915_GEM_DOMAIN_CPU; + obj->base.read_domains = I915_GEM_DOMAIN_CPU; + + if (HAS_LLC(dev)) { + /* On some devices, we can have the GPU use the LLC (the CPU + * cache) for about a 10% performance improvement + * compared to uncached. Graphics requests other than + * display scanout are coherent with the CPU in + * accessing this cache. This means in this mode we + * don't need to clflush on the CPU side, and on the + * GPU side we only need to flush internal caches to + * get data visible to the CPU. + * + * However, we maintain the display planes as UC, and so + * need to rebind when first used as such. + */ + obj->cache_level = I915_CACHE_LLC; + } else + obj->cache_level = I915_CACHE_NONE; + + trace_i915_gem_object_create(obj); + + return obj; +} + +void i915_gem_free_object(struct drm_gem_object *gem_obj) +{ + struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); + struct drm_device *dev = obj->base.dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct i915_vma *vma, *next; + + intel_runtime_pm_get(dev_priv); + + trace_i915_gem_object_destroy(obj); + + if (obj->phys_obj) + i915_gem_detach_phys_object(dev, obj); + + obj->pin_count = 0; + /* NB: 0 or 1 elements */ + WARN_ON(!list_empty(&obj->vma_list) && + !list_is_singular(&obj->vma_list)); + list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) { + int ret = i915_vma_unbind(vma); + if (WARN_ON(ret == -ERESTARTSYS)) { + bool was_interruptible; + + was_interruptible = dev_priv->mm.interruptible; + dev_priv->mm.interruptible = false; + + WARN_ON(i915_vma_unbind(vma)); + + dev_priv->mm.interruptible = was_interruptible; + } + } + + /* Stolen objects don't hold a ref, but do hold pin count. Fix that up + * before progressing. */ + if (obj->stolen) + i915_gem_object_unpin_pages(obj); + + if (WARN_ON(obj->pages_pin_count)) + obj->pages_pin_count = 0; + i915_gem_object_put_pages(obj); + i915_gem_object_free_mmap_offset(obj); + i915_gem_object_release_stolen(obj); + + BUG_ON(obj->pages); + + if (obj->base.import_attach) + drm_prime_gem_destroy(&obj->base, NULL); + + drm_gem_object_release(&obj->base); + i915_gem_info_remove_obj(dev_priv, obj->base.size); + + kfree(obj->bit_17); + i915_gem_object_free(obj); + + intel_runtime_pm_put(dev_priv); +} + +struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, + struct i915_address_space *vm) +{ + struct i915_vma *vma; + list_for_each_entry(vma, &obj->vma_list, vma_link) + if (vma->vm == vm) + return vma; + + return NULL; +} + +static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, + struct i915_address_space *vm) +{ + struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); + if (vma == NULL) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&vma->vma_link); + INIT_LIST_HEAD(&vma->mm_list); + INIT_LIST_HEAD(&vma->exec_list); + vma->vm = vm; + vma->obj = obj; + + /* Keep GGTT vmas first to make debug easier */ + if (i915_is_ggtt(vm)) + list_add(&vma->vma_link, &obj->vma_list); + else + list_add_tail(&vma->vma_link, &obj->vma_list); + + return vma; +} + +struct i915_vma * +i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, + struct i915_address_space *vm) +{ + struct i915_vma *vma; + + vma = i915_gem_obj_to_vma(obj, vm); + if (!vma) + vma = __i915_gem_vma_create(obj, vm); + + return vma; +} + +void i915_gem_vma_destroy(struct i915_vma *vma) +{ + WARN_ON(vma->node.allocated); + + /* Keep the vma as a placeholder in the execbuffer reservation lists */ + if (!list_empty(&vma->exec_list)) + return; + + list_del(&vma->vma_link); + + kfree(vma); +} + +int +i915_gem_suspend(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret = 0; + + mutex_lock(&dev->struct_mutex); + if (dev_priv->ums.mm_suspended) + goto err; + + ret = i915_gpu_idle(dev); + if (ret) + goto err; + + i915_gem_retire_requests(dev); + + /* Under UMS, be paranoid and evict. */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_gem_evict_everything(dev); + + i915_kernel_lost_context(dev); + i915_gem_cleanup_ringbuffer(dev); + + /* Hack! Don't let anybody do execbuf while we don't control the chip. + * We need to replace this with a semaphore, or something. + * And not confound ums.mm_suspended! + */ + dev_priv->ums.mm_suspended = !drm_core_check_feature(dev, + DRIVER_MODESET); + mutex_unlock(&dev->struct_mutex); + + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); + cancel_delayed_work_sync(&dev_priv->mm.retire_work); + cancel_delayed_work_sync(&dev_priv->mm.idle_work); + + return 0; + +err: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int i915_gem_l3_remap(struct intel_ring_buffer *ring, int slice) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200); + u32 *remap_info = dev_priv->l3_parity.remap_info[slice]; + int i, ret; + + if (!HAS_L3_DPF(dev) || !remap_info) + return 0; + + ret = intel_ring_begin(ring, GEN7_L3LOG_SIZE / 4 * 3); + if (ret) + return ret; + + /* + * Note: We do not worry about the concurrent register cacheline hang + * here because no other code should access these registers other than + * at initialization time. + */ + for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) { + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, reg_base + i); + intel_ring_emit(ring, remap_info[i/4]); + } + + intel_ring_advance(ring); + + return ret; +} + +void i915_gem_init_swizzling(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (INTEL_INFO(dev)->gen < 5 || + dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_NONE) + return; + + I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) | + DISP_TILE_SURFACE_SWIZZLING); + + if (IS_GEN5(dev)) + return; + + I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL); + if (IS_GEN6(dev)) + I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB)); + else if (IS_GEN7(dev)) + I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); + else if (IS_GEN8(dev)) + I915_WRITE(GAMTARBMODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_BDW)); + else + BUG(); +} + +static bool +intel_enable_blt(struct drm_device *dev) +{ + if (!HAS_BLT(dev)) + return false; + + /* The blitter was dysfunctional on early prototypes */ + if (IS_GEN6(dev) && dev->pdev->revision < 8) { + DRM_INFO("BLT not supported on this pre-production hardware;" + " graphics performance will be degraded.\n"); + return false; + } + + return true; +} + +static int i915_gem_init_rings(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = intel_init_render_ring_buffer(dev); + if (ret) + return ret; + + if (HAS_BSD(dev)) { + ret = intel_init_bsd_ring_buffer(dev); + if (ret) + goto cleanup_render_ring; + } + + if (intel_enable_blt(dev)) { + ret = intel_init_blt_ring_buffer(dev); + if (ret) + goto cleanup_bsd_ring; + } + + if (HAS_VEBOX(dev)) { + ret = intel_init_vebox_ring_buffer(dev); + if (ret) + goto cleanup_blt_ring; + } + + + ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); + if (ret) + goto cleanup_vebox_ring; + + return 0; + +cleanup_vebox_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[VECS]); +cleanup_blt_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[BCS]); +cleanup_bsd_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); +cleanup_render_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); + + return ret; +} + +int +i915_gem_init_hw(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret, i; + + if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) + return -EIO; + + if (dev_priv->ellc_size) + I915_WRITE(HSW_IDICR, I915_READ(HSW_IDICR) | IDIHASHMSK(0xf)); + + if (IS_HASWELL(dev)) + I915_WRITE(MI_PREDICATE_RESULT_2, IS_HSW_GT3(dev) ? + LOWER_SLICE_ENABLED : LOWER_SLICE_DISABLED); + + if (HAS_PCH_NOP(dev)) { + u32 temp = I915_READ(GEN7_MSG_CTL); + temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK); + I915_WRITE(GEN7_MSG_CTL, temp); + } + + i915_gem_init_swizzling(dev); + + ret = i915_gem_init_rings(dev); + if (ret) + return ret; + + for (i = 0; i < NUM_L3_SLICES(dev); i++) + i915_gem_l3_remap(&dev_priv->ring[RCS], i); + + /* + * XXX: There was some w/a described somewhere suggesting loading + * contexts before PPGTT. + */ + ret = i915_gem_context_init(dev); + if (ret) { + i915_gem_cleanup_ringbuffer(dev); + DRM_ERROR("Context initialization failed %d\n", ret); + return ret; + } + + if (dev_priv->mm.aliasing_ppgtt) { + ret = dev_priv->mm.aliasing_ppgtt->enable(dev); + if (ret) { + i915_gem_cleanup_aliasing_ppgtt(dev); + DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); + } + } + + return 0; +} + +int i915_gem_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + mutex_lock(&dev->struct_mutex); + + if (IS_VALLEYVIEW(dev)) { + /* VLVA0 (potential hack), BIOS isn't actually waking us */ + I915_WRITE(VLV_GTLC_WAKE_CTRL, 1); + if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10)) + DRM_DEBUG_DRIVER("allow wake ack timed out\n"); + } + + i915_gem_init_global_gtt(dev); + + ret = i915_gem_init_hw(dev); + mutex_unlock(&dev->struct_mutex); + if (ret) { + i915_gem_cleanup_aliasing_ppgtt(dev); + return ret; + } + + /* Allow hardware batchbuffers unless told otherwise, but not for KMS. */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + dev_priv->dri1.allow_batchbuffer = 1; + return 0; +} + +void +i915_gem_cleanup_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int i; + + for_each_ring(ring, dev_priv, i) + intel_cleanup_ring_buffer(ring); +} + +int +i915_gem_entervt_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + if (i915_reset_in_progress(&dev_priv->gpu_error)) { + DRM_ERROR("Reenabling wedged hardware, good luck\n"); + atomic_set(&dev_priv->gpu_error.reset_counter, 0); + } + + mutex_lock(&dev->struct_mutex); + dev_priv->ums.mm_suspended = 0; + + ret = i915_gem_init_hw(dev); + if (ret != 0) { + mutex_unlock(&dev->struct_mutex); + return ret; + } + + BUG_ON(!list_empty(&dev_priv->gtt.base.active_list)); + mutex_unlock(&dev->struct_mutex); + + ret = drm_irq_install(dev); + if (ret) + goto cleanup_ringbuffer; + + return 0; + +cleanup_ringbuffer: + mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); + dev_priv->ums.mm_suspended = 1; + mutex_unlock(&dev->struct_mutex); + + return ret; +} + +int +i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + drm_irq_uninstall(dev); + + return i915_gem_suspend(dev); +} + +void +i915_gem_lastclose(struct drm_device *dev) +{ + int ret; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + ret = i915_gem_suspend(dev); + if (ret) + DRM_ERROR("failed to idle hardware: %d\n", ret); +} + +static void +init_ring_lists(struct intel_ring_buffer *ring) +{ + INIT_LIST_HEAD(&ring->active_list); + INIT_LIST_HEAD(&ring->request_list); +} + +static void i915_init_vm(struct drm_i915_private *dev_priv, + struct i915_address_space *vm) +{ + vm->dev = dev_priv->dev; + INIT_LIST_HEAD(&vm->active_list); + INIT_LIST_HEAD(&vm->inactive_list); + INIT_LIST_HEAD(&vm->global_link); + list_add(&vm->global_link, &dev_priv->vm_list); +} + +void +i915_gem_load(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int i; + + dev_priv->slab = + kmem_cache_create("i915_gem_object", + sizeof(struct drm_i915_gem_object), 0, + SLAB_HWCACHE_ALIGN, + NULL); + + INIT_LIST_HEAD(&dev_priv->vm_list); + i915_init_vm(dev_priv, &dev_priv->gtt.base); + + INIT_LIST_HEAD(&dev_priv->context_list); + INIT_LIST_HEAD(&dev_priv->mm.unbound_list); + INIT_LIST_HEAD(&dev_priv->mm.bound_list); + INIT_LIST_HEAD(&dev_priv->mm.fence_list); + for (i = 0; i < I915_NUM_RINGS; i++) + init_ring_lists(&dev_priv->ring[i]); + for (i = 0; i < I915_MAX_NUM_FENCES; i++) + INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); + INIT_DELAYED_WORK(&dev_priv->mm.retire_work, + i915_gem_retire_work_handler); + INIT_DELAYED_WORK(&dev_priv->mm.idle_work, + i915_gem_idle_work_handler); + init_waitqueue_head(&dev_priv->gpu_error.reset_queue); + + /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ + if (IS_GEN3(dev)) { + I915_WRITE(MI_ARB_STATE, + _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE)); + } + + dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL; + + /* Old X drivers will take 0-2 for front, back, depth buffers */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + dev_priv->fence_reg_start = 3; + + if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) + dev_priv->num_fence_regs = 32; + else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + dev_priv->num_fence_regs = 16; + else + dev_priv->num_fence_regs = 8; + + /* Initialize fence registers to zero */ + INIT_LIST_HEAD(&dev_priv->mm.fence_list); + i915_gem_restore_fences(dev); + + i915_gem_detect_bit_6_swizzle(dev); + init_waitqueue_head(&dev_priv->pending_flip_queue); + + dev_priv->mm.interruptible = true; + + dev_priv->mm.inactive_shrinker.scan_objects = i915_gem_inactive_scan; + dev_priv->mm.inactive_shrinker.count_objects = i915_gem_inactive_count; + dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS; + register_shrinker(&dev_priv->mm.inactive_shrinker); +} + +/* + * Create a physically contiguous memory object for this object + * e.g. for cursor + overlay regs + */ +static int i915_gem_init_phys_object(struct drm_device *dev, + int id, int size, int align) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_gem_phys_object *phys_obj; + int ret; + + if (dev_priv->mm.phys_objs[id - 1] || !size) + return 0; + + phys_obj = kzalloc(sizeof(*phys_obj), GFP_KERNEL); + if (!phys_obj) + return -ENOMEM; + + phys_obj->id = id; + + phys_obj->handle = drm_pci_alloc(dev, size, align); + if (!phys_obj->handle) { + ret = -ENOMEM; + goto kfree_obj; + } +#ifdef CONFIG_X86 + set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE); +#endif + + dev_priv->mm.phys_objs[id - 1] = phys_obj; + + return 0; +kfree_obj: + kfree(phys_obj); + return ret; +} + +static void i915_gem_free_phys_object(struct drm_device *dev, int id) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_gem_phys_object *phys_obj; + + if (!dev_priv->mm.phys_objs[id - 1]) + return; + + phys_obj = dev_priv->mm.phys_objs[id - 1]; + if (phys_obj->cur_obj) { + i915_gem_detach_phys_object(dev, phys_obj->cur_obj); + } + +#ifdef CONFIG_X86 + set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE); +#endif + drm_pci_free(dev, phys_obj->handle); + kfree(phys_obj); + dev_priv->mm.phys_objs[id - 1] = NULL; +} + +void i915_gem_free_all_phys_object(struct drm_device *dev) +{ + int i; + + for (i = I915_GEM_PHYS_CURSOR_0; i <= I915_MAX_PHYS_OBJECT; i++) + i915_gem_free_phys_object(dev, i); +} + +void i915_gem_detach_phys_object(struct drm_device *dev, + struct drm_i915_gem_object *obj) +{ + struct address_space *mapping = file_inode(obj->base.filp)->i_mapping; + char *vaddr; + int i; + int page_count; + + if (!obj->phys_obj) + return; + vaddr = obj->phys_obj->handle->vaddr; + + page_count = obj->base.size / PAGE_SIZE; + for (i = 0; i < page_count; i++) { + struct page *page = shmem_read_mapping_page(mapping, i); + if (!IS_ERR(page)) { + char *dst = kmap_atomic(page); + memcpy(dst, vaddr + i*PAGE_SIZE, PAGE_SIZE); + kunmap_atomic(dst); + + drm_clflush_pages(&page, 1); + + set_page_dirty(page); + mark_page_accessed(page); + page_cache_release(page); + } + } + i915_gem_chipset_flush(dev); + + obj->phys_obj->cur_obj = NULL; + obj->phys_obj = NULL; +} + +int +i915_gem_attach_phys_object(struct drm_device *dev, + struct drm_i915_gem_object *obj, + int id, + int align) +{ + struct address_space *mapping = file_inode(obj->base.filp)->i_mapping; + drm_i915_private_t *dev_priv = dev->dev_private; + int ret = 0; + int page_count; + int i; + + if (id > I915_MAX_PHYS_OBJECT) + return -EINVAL; + + if (obj->phys_obj) { + if (obj->phys_obj->id == id) + return 0; + i915_gem_detach_phys_object(dev, obj); + } + + /* create a new object */ + if (!dev_priv->mm.phys_objs[id - 1]) { + ret = i915_gem_init_phys_object(dev, id, + obj->base.size, align); + if (ret) { + DRM_ERROR("failed to init phys object %d size: %zu\n", + id, obj->base.size); + return ret; + } + } + + /* bind to the object */ + obj->phys_obj = dev_priv->mm.phys_objs[id - 1]; + obj->phys_obj->cur_obj = obj; + + page_count = obj->base.size / PAGE_SIZE; + + for (i = 0; i < page_count; i++) { + struct page *page; + char *dst, *src; + + page = shmem_read_mapping_page(mapping, i); + if (IS_ERR(page)) + return PTR_ERR(page); + + src = kmap_atomic(page); + dst = obj->phys_obj->handle->vaddr + (i * PAGE_SIZE); + memcpy(dst, src, PAGE_SIZE); + kunmap_atomic(src); + + mark_page_accessed(page); + page_cache_release(page); + } + + return 0; +} + +static int +i915_gem_phys_pwrite(struct drm_device *dev, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_pwrite *args, + struct drm_file *file_priv) +{ + void *vaddr = obj->phys_obj->handle->vaddr + args->offset; + char __user *user_data = to_user_ptr(args->data_ptr); + + if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { + unsigned long unwritten; + + /* The physical object once assigned is fixed for the lifetime + * of the obj, so we can safely drop the lock and continue + * to access vaddr. + */ + mutex_unlock(&dev->struct_mutex); + unwritten = copy_from_user(vaddr, user_data, args->size); + mutex_lock(&dev->struct_mutex); + if (unwritten) + return -EFAULT; + } + + i915_gem_chipset_flush(dev); + return 0; +} + +void i915_gem_release(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + + cancel_delayed_work_sync(&file_priv->mm.idle_work); + + /* Clean up our request list when the client is going away, so that + * later retire_requests won't dereference our soon-to-be-gone + * file_priv. + */ + spin_lock(&file_priv->mm.lock); + while (!list_empty(&file_priv->mm.request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&file_priv->mm.request_list, + struct drm_i915_gem_request, + client_list); + list_del(&request->client_list); + request->file_priv = NULL; + } + spin_unlock(&file_priv->mm.lock); +} + +static void +i915_gem_file_idle_work_handler(struct work_struct *work) +{ + struct drm_i915_file_private *file_priv = + container_of(work, typeof(*file_priv), mm.idle_work.work); + + atomic_set(&file_priv->rps_wait_boost, false); +} + +int i915_gem_open(struct drm_device *dev, struct drm_file *file) +{ + struct drm_i915_file_private *file_priv; + + DRM_DEBUG_DRIVER("\n"); + + file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); + if (!file_priv) + return -ENOMEM; + + file->driver_priv = file_priv; + file_priv->dev_priv = dev->dev_private; + + spin_lock_init(&file_priv->mm.lock); + INIT_LIST_HEAD(&file_priv->mm.request_list); + INIT_DELAYED_WORK(&file_priv->mm.idle_work, + i915_gem_file_idle_work_handler); + + idr_init(&file_priv->context_idr); + + return 0; +} + +static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) +{ + if (!mutex_is_locked(mutex)) + return false; + +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES) + return mutex->owner == task; +#else + /* Since UP may be pre-empted, we cannot assume that we own the lock */ + return false; +#endif +} + +static unsigned long +i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct drm_i915_private *dev_priv = + container_of(shrinker, + struct drm_i915_private, + mm.inactive_shrinker); + struct drm_device *dev = dev_priv->dev; + struct drm_i915_gem_object *obj; + bool unlock = true; + unsigned long count; + + if (!mutex_trylock(&dev->struct_mutex)) { + if (!mutex_is_locked_by(&dev->struct_mutex, current)) + return 0; + + if (dev_priv->mm.shrinker_no_lock_stealing) + return 0; + + unlock = false; + } + + count = 0; + list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) + if (obj->pages_pin_count == 0) + count += obj->base.size >> PAGE_SHIFT; + + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { + if (obj->active) + continue; + + if (obj->pin_count == 0 && obj->pages_pin_count == 0) + count += obj->base.size >> PAGE_SHIFT; + } + + if (unlock) + mutex_unlock(&dev->struct_mutex); + + return count; +} + +/* All the new VM stuff */ +unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, + struct i915_address_space *vm) +{ + struct drm_i915_private *dev_priv = o->base.dev->dev_private; + struct i915_vma *vma; + + if (vm == &dev_priv->mm.aliasing_ppgtt->base) + vm = &dev_priv->gtt.base; + + BUG_ON(list_empty(&o->vma_list)); + list_for_each_entry(vma, &o->vma_list, vma_link) { + if (vma->vm == vm) + return vma->node.start; + + } + return -1; +} + +bool i915_gem_obj_bound(struct drm_i915_gem_object *o, + struct i915_address_space *vm) +{ + struct i915_vma *vma; + + list_for_each_entry(vma, &o->vma_list, vma_link) + if (vma->vm == vm && drm_mm_node_allocated(&vma->node)) + return true; + + return false; +} + +bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o) +{ + struct i915_vma *vma; + + list_for_each_entry(vma, &o->vma_list, vma_link) + if (drm_mm_node_allocated(&vma->node)) + return true; + + return false; +} + +unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o, + struct i915_address_space *vm) +{ + struct drm_i915_private *dev_priv = o->base.dev->dev_private; + struct i915_vma *vma; + + if (vm == &dev_priv->mm.aliasing_ppgtt->base) + vm = &dev_priv->gtt.base; + + BUG_ON(list_empty(&o->vma_list)); + + list_for_each_entry(vma, &o->vma_list, vma_link) + if (vma->vm == vm) + return vma->node.size; + + return 0; +} + +static unsigned long +i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct drm_i915_private *dev_priv = + container_of(shrinker, + struct drm_i915_private, + mm.inactive_shrinker); + struct drm_device *dev = dev_priv->dev; + unsigned long freed; + bool unlock = true; + + if (!mutex_trylock(&dev->struct_mutex)) { + if (!mutex_is_locked_by(&dev->struct_mutex, current)) + return SHRINK_STOP; + + if (dev_priv->mm.shrinker_no_lock_stealing) + return SHRINK_STOP; + + unlock = false; + } + + freed = i915_gem_purge(dev_priv, sc->nr_to_scan); + if (freed < sc->nr_to_scan) + freed += __i915_gem_shrink(dev_priv, + sc->nr_to_scan - freed, + false); + if (freed < sc->nr_to_scan) + freed += i915_gem_shrink_all(dev_priv); + + if (unlock) + mutex_unlock(&dev->struct_mutex); + + return freed; +} + +struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj) +{ + struct i915_vma *vma; + + if (WARN_ON(list_empty(&obj->vma_list))) + return NULL; + + vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link); + if (WARN_ON(vma->vm != obj_to_ggtt(obj))) + return NULL; + + return vma; +} --- linux-3.13.0.orig/ubuntu/i915/dvo_ch7017.c +++ linux-3.13.0/ubuntu/i915/dvo_ch7017.c @@ -0,0 +1,414 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include "dvo.h" + +#define CH7017_TV_DISPLAY_MODE 0x00 +#define CH7017_FLICKER_FILTER 0x01 +#define CH7017_VIDEO_BANDWIDTH 0x02 +#define CH7017_TEXT_ENHANCEMENT 0x03 +#define CH7017_START_ACTIVE_VIDEO 0x04 +#define CH7017_HORIZONTAL_POSITION 0x05 +#define CH7017_VERTICAL_POSITION 0x06 +#define CH7017_BLACK_LEVEL 0x07 +#define CH7017_CONTRAST_ENHANCEMENT 0x08 +#define CH7017_TV_PLL 0x09 +#define CH7017_TV_PLL_M 0x0a +#define CH7017_TV_PLL_N 0x0b +#define CH7017_SUB_CARRIER_0 0x0c +#define CH7017_CIV_CONTROL 0x10 +#define CH7017_CIV_0 0x11 +#define CH7017_CHROMA_BOOST 0x14 +#define CH7017_CLOCK_MODE 0x1c +#define CH7017_INPUT_CLOCK 0x1d +#define CH7017_GPIO_CONTROL 0x1e +#define CH7017_INPUT_DATA_FORMAT 0x1f +#define CH7017_CONNECTION_DETECT 0x20 +#define CH7017_DAC_CONTROL 0x21 +#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 +#define CH7017_DEFEAT_VSYNC 0x47 +#define CH7017_TEST_PATTERN 0x48 + +#define CH7017_POWER_MANAGEMENT 0x49 +/** Enables the TV output path. */ +#define CH7017_TV_EN (1 << 0) +#define CH7017_DAC0_POWER_DOWN (1 << 1) +#define CH7017_DAC1_POWER_DOWN (1 << 2) +#define CH7017_DAC2_POWER_DOWN (1 << 3) +#define CH7017_DAC3_POWER_DOWN (1 << 4) +/** Powers down the TV out block, and DAC0-3 */ +#define CH7017_TV_POWER_DOWN_EN (1 << 5) + +#define CH7017_VERSION_ID 0x4a + +#define CH7017_DEVICE_ID 0x4b +#define CH7017_DEVICE_ID_VALUE 0x1b +#define CH7018_DEVICE_ID_VALUE 0x1a +#define CH7019_DEVICE_ID_VALUE 0x19 + +#define CH7017_XCLK_D2_ADJUST 0x53 +#define CH7017_UP_SCALER_COEFF_0 0x55 +#define CH7017_UP_SCALER_COEFF_1 0x56 +#define CH7017_UP_SCALER_COEFF_2 0x57 +#define CH7017_UP_SCALER_COEFF_3 0x58 +#define CH7017_UP_SCALER_COEFF_4 0x59 +#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a +#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b +#define CH7017_GPIO_INVERT 0x5c +#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d +#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e + +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f +/**< Low bits of horizontal active pixel input */ + +#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 +/** High bits of horizontal active pixel input */ +#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) +/** High bits of vertical active line output */ +#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) + +#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 +/**< Low bits of vertical active line output */ + +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 +/**< Low bits of horizontal active pixel output */ + +#define CH7017_LVDS_POWER_DOWN 0x63 +/** High bits of horizontal active pixel output */ +#define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) +/** Enables the LVDS power down state transition */ +#define CH7017_LVDS_POWER_DOWN_EN (1 << 6) +/** Enables the LVDS upscaler */ +#define CH7017_LVDS_UPSCALER_EN (1 << 7) +#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 + +#define CH7017_LVDS_ENCODING 0x64 +#define CH7017_LVDS_DITHER_2D (1 << 2) +#define CH7017_LVDS_DITHER_DIS (1 << 3) +#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) +#define CH7017_LVDS_24_BIT (1 << 5) + +#define CH7017_LVDS_ENCODING_2 0x65 + +#define CH7017_LVDS_PLL_CONTROL 0x66 +/** Enables the LVDS panel output path */ +#define CH7017_LVDS_PANEN (1 << 0) +/** Enables the LVDS panel backlight */ +#define CH7017_LVDS_BKLEN (1 << 3) + +#define CH7017_POWER_SEQUENCING_T1 0x67 +#define CH7017_POWER_SEQUENCING_T2 0x68 +#define CH7017_POWER_SEQUENCING_T3 0x69 +#define CH7017_POWER_SEQUENCING_T4 0x6a +#define CH7017_POWER_SEQUENCING_T5 0x6b +#define CH7017_GPIO_DRIVER_TYPE 0x6c +#define CH7017_GPIO_DATA 0x6d +#define CH7017_GPIO_DIRECTION_CONTROL 0x6e + +#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 +# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 +# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 +# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 + +#define CH7017_LVDS_PLL_VCO_CONTROL 0x72 +# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 +# define CH7017_LVDS_PLL_VCO_SHIFT 4 +# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 + +#define CH7017_OUTPUTS_ENABLE 0x73 +# define CH7017_CHARGE_PUMP_LOW 0x0 +# define CH7017_CHARGE_PUMP_HIGH 0x3 +# define CH7017_LVDS_CHANNEL_A (1 << 3) +# define CH7017_LVDS_CHANNEL_B (1 << 4) +# define CH7017_TV_DAC_A (1 << 5) +# define CH7017_TV_DAC_B (1 << 6) +# define CH7017_DDC_SELECT_DC2 (1 << 7) + +#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 +#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 +#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 + +#define CH7017_LVDS_CONTROL_2 0x78 +# define CH7017_LOOP_FILTER_SHIFT 5 +# define CH7017_PHASE_DETECTOR_SHIFT 0 + +#define CH7017_BANG_LIMIT_CONTROL 0x7f + +struct ch7017_priv { + uint8_t dummy; +}; + +static void ch7017_dump_regs(struct intel_dvo_device *dvo); +static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable); + +static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val) +{ + struct i2c_msg msgs[] = { + { + .addr = dvo->slave_addr, + .flags = 0, + .len = 1, + .buf = &addr, + }, + { + .addr = dvo->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = val, + } + }; + return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2; +} + +static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val) +{ + uint8_t buf[2] = { addr, val }; + struct i2c_msg msg = { + .addr = dvo->slave_addr, + .flags = 0, + .len = 2, + .buf = buf, + }; + return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1; +} + +/** Probes for a CH7017 on the given bus and slave address. */ +static bool ch7017_init(struct intel_dvo_device *dvo, + struct i2c_adapter *adapter) +{ + struct ch7017_priv *priv; + const char *str; + u8 val; + + priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); + if (priv == NULL) + return false; + + dvo->i2c_bus = adapter; + dvo->dev_priv = priv; + + if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) + goto fail; + + switch (val) { + case CH7017_DEVICE_ID_VALUE: + str = "ch7017"; + break; + case CH7018_DEVICE_ID_VALUE: + str = "ch7018"; + break; + case CH7019_DEVICE_ID_VALUE: + str = "ch7019"; + break; + default: + DRM_DEBUG_KMS("ch701x not detected, got %d: from %s " + "slave %d.\n", + val, adapter->name, dvo->slave_addr); + goto fail; + } + + DRM_DEBUG_KMS("%s detected on %s, addr %d\n", + str, adapter->name, dvo->slave_addr); + return true; + +fail: + kfree(priv); + return false; +} + +static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) +{ + return connector_status_connected; +} + +static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + if (mode->clock > 160000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void ch7017_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; + uint8_t outputs_enable, lvds_control_2, lvds_power_down; + uint8_t horizontal_active_pixel_input; + uint8_t horizontal_active_pixel_output, vertical_active_line_output; + uint8_t active_input_line_output; + + DRM_DEBUG_KMS("Registers before mode setting\n"); + ch7017_dump_regs(dvo); + + /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ + if (mode->clock < 100000) { + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | + (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_VCO_SHIFT) | + (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | + (0 << CH7017_PHASE_DETECTOR_SHIFT); + } else { + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | + (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); + lvds_pll_feedback_div = 35; + lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | + (0 << CH7017_PHASE_DETECTOR_SHIFT); + if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ + outputs_enable |= CH7017_LVDS_CHANNEL_B; + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_VCO_SHIFT) | + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + } else { + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (1 << CH7017_LVDS_PLL_VCO_SHIFT) | + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + } + } + + horizontal_active_pixel_input = mode->hdisplay & 0x00ff; + + vertical_active_line_output = mode->vdisplay & 0x00ff; + horizontal_active_pixel_output = mode->hdisplay & 0x00ff; + + active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | + (((mode->vdisplay & 0x0700) >> 8) << 3); + + lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | + (mode->hdisplay & 0x0700) >> 8; + + ch7017_dpms(dvo, false); + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, + horizontal_active_pixel_input); + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, + horizontal_active_pixel_output); + ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, + vertical_active_line_output); + ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, + active_input_line_output); + ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); + ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); + ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2); + ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable); + + /* Turn the LVDS back on with new settings. */ + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down); + + DRM_DEBUG_KMS("Registers after mode setting\n"); + ch7017_dump_regs(dvo); +} + +/* set the CH7017 power state */ +static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable) +{ + uint8_t val; + + ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); + + /* Turn off TV/VGA, and never turn it on since we don't support it. */ + ch7017_write(dvo, CH7017_POWER_MANAGEMENT, + CH7017_DAC0_POWER_DOWN | + CH7017_DAC1_POWER_DOWN | + CH7017_DAC2_POWER_DOWN | + CH7017_DAC3_POWER_DOWN | + CH7017_TV_POWER_DOWN_EN); + + if (enable) { + /* Turn on the LVDS */ + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, + val & ~CH7017_LVDS_POWER_DOWN_EN); + } else { + /* Turn off the LVDS */ + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, + val | CH7017_LVDS_POWER_DOWN_EN); + } + + /* XXX: Should actually wait for update power status somehow */ + msleep(20); +} + +static bool ch7017_get_hw_state(struct intel_dvo_device *dvo) +{ + uint8_t val; + + ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); + + if (val & CH7017_LVDS_POWER_DOWN_EN) + return false; + else + return true; +} + +static void ch7017_dump_regs(struct intel_dvo_device *dvo) +{ + uint8_t val; + +#define DUMP(reg) \ +do { \ + ch7017_read(dvo, reg, &val); \ + DRM_DEBUG_KMS(#reg ": %02x\n", val); \ +} while (0) + + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); + DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); + DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); + DUMP(CH7017_LVDS_PLL_VCO_CONTROL); + DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); + DUMP(CH7017_LVDS_CONTROL_2); + DUMP(CH7017_OUTPUTS_ENABLE); + DUMP(CH7017_LVDS_POWER_DOWN); +} + +static void ch7017_destroy(struct intel_dvo_device *dvo) +{ + struct ch7017_priv *priv = dvo->dev_priv; + + if (priv) { + kfree(priv); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops ch7017_ops = { + .init = ch7017_init, + .detect = ch7017_detect, + .mode_valid = ch7017_mode_valid, + .mode_set = ch7017_mode_set, + .dpms = ch7017_dpms, + .get_hw_state = ch7017_get_hw_state, + .dump_regs = ch7017_dump_regs, + .destroy = ch7017_destroy, +}; --- linux-3.13.0.orig/ubuntu/i915/intel_panel.c +++ linux-3.13.0/ubuntu/i915/intel_panel.c @@ -0,0 +1,1220 @@ +/* + * Copyright © 2006-2010 Intel Corporation + * Copyright (c) 2006 Dave Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Dave Airlie + * Jesse Barnes + * Chris Wilson + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include "intel_drv.h" + +#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ + +void +intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, + struct drm_display_mode *adjusted_mode) +{ + drm_mode_copy(adjusted_mode, fixed_mode); + + drm_mode_set_crtcinfo(adjusted_mode, 0); +} + +/* adjusted_mode has been preset to be the panel's fixed mode */ +void +intel_pch_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode) +{ + struct drm_display_mode *adjusted_mode; + int x, y, width, height; + + adjusted_mode = &pipe_config->adjusted_mode; + + x = y = width = height = 0; + + /* Native modes don't need fitting */ + if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && + adjusted_mode->vdisplay == pipe_config->pipe_src_h) + goto done; + + switch (fitting_mode) { + case DRM_MODE_SCALE_CENTER: + width = pipe_config->pipe_src_w; + height = pipe_config->pipe_src_h; + x = (adjusted_mode->hdisplay - width + 1)/2; + y = (adjusted_mode->vdisplay - height + 1)/2; + break; + + case DRM_MODE_SCALE_ASPECT: + /* Scale but preserve the aspect ratio */ + { + u32 scaled_width = adjusted_mode->hdisplay + * pipe_config->pipe_src_h; + u32 scaled_height = pipe_config->pipe_src_w + * adjusted_mode->vdisplay; + if (scaled_width > scaled_height) { /* pillar */ + width = scaled_height / pipe_config->pipe_src_h; + if (width & 1) + width++; + x = (adjusted_mode->hdisplay - width + 1) / 2; + y = 0; + height = adjusted_mode->vdisplay; + } else if (scaled_width < scaled_height) { /* letter */ + height = scaled_width / pipe_config->pipe_src_w; + if (height & 1) + height++; + y = (adjusted_mode->vdisplay - height + 1) / 2; + x = 0; + width = adjusted_mode->hdisplay; + } else { + x = y = 0; + width = adjusted_mode->hdisplay; + height = adjusted_mode->vdisplay; + } + } + break; + + case DRM_MODE_SCALE_FULLSCREEN: + x = y = 0; + width = adjusted_mode->hdisplay; + height = adjusted_mode->vdisplay; + break; + + default: + WARN(1, "bad panel fit mode: %d\n", fitting_mode); + return; + } + +done: + pipe_config->pch_pfit.pos = (x << 16) | y; + pipe_config->pch_pfit.size = (width << 16) | height; + pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; +} + +static void +centre_horizontally(struct drm_display_mode *mode, + int width) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the hsync and hblank widths constant */ + sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; + blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->hdisplay - width + 1) / 2; + border += border & 1; /* make the border even */ + + mode->crtc_hdisplay = width; + mode->crtc_hblank_start = width + border; + mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; + + mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; + mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; +} + +static void +centre_vertically(struct drm_display_mode *mode, + int height) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the vsync and vblank widths constant */ + sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; + blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->vdisplay - height + 1) / 2; + + mode->crtc_vdisplay = height; + mode->crtc_vblank_start = height + border; + mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; + + mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; + mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; +} + +static inline u32 panel_fitter_scaling(u32 source, u32 target) +{ + /* + * Floating point operation is not supported. So the FACTOR + * is defined, which can avoid the floating point computation + * when calculating the panel ratio. + */ +#define ACCURACY 12 +#define FACTOR (1 << ACCURACY) + u32 ratio = source * FACTOR / target; + return (FACTOR * ratio + FACTOR/2) / FACTOR; +} + +static void i965_scale_aspect(struct intel_crtc_config *pipe_config, + u32 *pfit_control) +{ + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + u32 scaled_width = adjusted_mode->hdisplay * + pipe_config->pipe_src_h; + u32 scaled_height = pipe_config->pipe_src_w * + adjusted_mode->vdisplay; + + /* 965+ is easy, it does everything in hw */ + if (scaled_width > scaled_height) + *pfit_control |= PFIT_ENABLE | + PFIT_SCALING_PILLAR; + else if (scaled_width < scaled_height) + *pfit_control |= PFIT_ENABLE | + PFIT_SCALING_LETTER; + else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w) + *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; +} + +static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config, + u32 *pfit_control, u32 *pfit_pgm_ratios, + u32 *border) +{ + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + u32 scaled_width = adjusted_mode->hdisplay * + pipe_config->pipe_src_h; + u32 scaled_height = pipe_config->pipe_src_w * + adjusted_mode->vdisplay; + u32 bits; + + /* + * For earlier chips we have to calculate the scaling + * ratio by hand and program it into the + * PFIT_PGM_RATIO register + */ + if (scaled_width > scaled_height) { /* pillar */ + centre_horizontally(adjusted_mode, + scaled_height / + pipe_config->pipe_src_h); + + *border = LVDS_BORDER_ENABLE; + if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) { + bits = panel_fitter_scaling(pipe_config->pipe_src_h, + adjusted_mode->vdisplay); + + *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + *pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else if (scaled_width < scaled_height) { /* letter */ + centre_vertically(adjusted_mode, + scaled_width / + pipe_config->pipe_src_w); + + *border = LVDS_BORDER_ENABLE; + if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) { + bits = panel_fitter_scaling(pipe_config->pipe_src_w, + adjusted_mode->hdisplay); + + *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + *pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else { + /* Aspects match, Let hw scale both directions */ + *pfit_control |= (PFIT_ENABLE | + VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } +} + +void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode) +{ + struct drm_device *dev = intel_crtc->base.dev; + u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; + struct drm_display_mode *adjusted_mode; + + adjusted_mode = &pipe_config->adjusted_mode; + + /* Native modes don't need fitting */ + if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && + adjusted_mode->vdisplay == pipe_config->pipe_src_h) + goto out; + + switch (fitting_mode) { + case DRM_MODE_SCALE_CENTER: + /* + * For centered modes, we have to calculate border widths & + * heights and modify the values programmed into the CRTC. + */ + centre_horizontally(adjusted_mode, pipe_config->pipe_src_w); + centre_vertically(adjusted_mode, pipe_config->pipe_src_h); + border = LVDS_BORDER_ENABLE; + break; + case DRM_MODE_SCALE_ASPECT: + /* Scale but preserve the aspect ratio */ + if (INTEL_INFO(dev)->gen >= 4) + i965_scale_aspect(pipe_config, &pfit_control); + else + i9xx_scale_aspect(pipe_config, &pfit_control, + &pfit_pgm_ratios, &border); + break; + case DRM_MODE_SCALE_FULLSCREEN: + /* + * Full scaling, even if it changes the aspect ratio. + * Fortunately this is all done for us in hw. + */ + if (pipe_config->pipe_src_h != adjusted_mode->vdisplay || + pipe_config->pipe_src_w != adjusted_mode->hdisplay) { + pfit_control |= PFIT_ENABLE; + if (INTEL_INFO(dev)->gen >= 4) + pfit_control |= PFIT_SCALING_AUTO; + else + pfit_control |= (VERT_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_AUTO_SCALE | + HORIZ_INTERP_BILINEAR); + } + break; + default: + WARN(1, "bad panel fit mode: %d\n", fitting_mode); + return; + } + + /* 965+ wants fuzzy fitting */ + /* FIXME: handle multiple panels by failing gracefully */ + if (INTEL_INFO(dev)->gen >= 4) + pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | + PFIT_FILTER_FUZZY); + +out: + if ((pfit_control & PFIT_ENABLE) == 0) { + pfit_control = 0; + pfit_pgm_ratios = 0; + } + + /* Make sure pre-965 set dither correctly for 18bpp panels. */ + if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + + pipe_config->gmch_pfit.control = pfit_control; + pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; + pipe_config->gmch_pfit.lvds_border_bits = border; +} + +static int i915_panel_invert_brightness; +MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " + "(-1 force normal, 0 machine defaults, 1 force inversion), please " + "report PCI device ID, subsystem vendor and subsystem device ID " + "to dri-devel@lists.freedesktop.org, if your machine needs it. " + "It will then be included in an upcoming module version."); +module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); +static u32 intel_panel_compute_brightness(struct intel_connector *connector, + u32 val) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + + WARN_ON(panel->backlight.max == 0); + + if (i915_panel_invert_brightness < 0) + return val; + + if (i915_panel_invert_brightness > 0 || + dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { + return panel->backlight.max - val; + } + + return val; +} + +static u32 bdw_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 pch_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 i9xx_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 val; + + val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + if (INTEL_INFO(dev)->gen < 4) + val >>= 1; + + if (panel->backlight.combination_mode) { + u8 lbpc; + + pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); + val *= lbpc; + } + + return val; +} + +static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 vlv_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + enum pipe pipe = intel_get_pipe_from_connector(connector); + + return _vlv_get_backlight(dev, pipe); +} + +static u32 intel_panel_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + + val = dev_priv->display.get_backlight(connector); + val = intel_panel_compute_brightness(connector, val); + + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); + + DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); + return val; +} + +static void bdw_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_PCH_CTL2, val | level); +} + +static void pch_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CPU_CTL, tmp | level); +} + +static void i9xx_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 tmp, mask; + + WARN_ON(panel->backlight.max == 0); + + if (panel->backlight.combination_mode) { + u8 lbpc; + + lbpc = level * 0xfe / panel->backlight.max + 1; + level /= lbpc; + pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); + } + + if (IS_GEN4(dev)) { + mask = BACKLIGHT_DUTY_CYCLE_MASK; + } else { + level <<= 1; + mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; + } + + tmp = I915_READ(BLC_PWM_CTL) & ~mask; + I915_WRITE(BLC_PWM_CTL, tmp | level); +} + +static void vlv_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); +} + +static void +intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); + + level = intel_panel_compute_brightness(connector, level); + dev_priv->display.set_backlight(connector, level); +} + +/* set backlight brightness to level in range [0..max] */ +void intel_panel_set_backlight(struct intel_connector *connector, u32 level, + u32 max) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 freq; + unsigned long flags; + + if (!panel->backlight.present || pipe == INVALID_PIPE) + return; + + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + + WARN_ON(panel->backlight.max == 0); + + /* scale to hardware max, but be careful to not overflow */ + freq = panel->backlight.max; + if (freq < max) + level = level * freq / max; + else + level = freq / max * level; + + panel->backlight.level = level; + if (panel->backlight.device) + panel->backlight.device->props.brightness = level; + + if (panel->backlight.enabled) + intel_panel_actually_set_backlight(connector, level); + + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); +} + +static void pch_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + intel_panel_actually_set_backlight(connector, 0); + + tmp = I915_READ(BLC_PWM_CPU_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); + + tmp = I915_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); +} + +static void i9xx_disable_backlight(struct intel_connector *connector) +{ + intel_panel_actually_set_backlight(connector, 0); +} + +static void i965_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + intel_panel_actually_set_backlight(connector, 0); + + tmp = I915_READ(BLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); +} + +static void vlv_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + intel_panel_actually_set_backlight(connector, 0); + + tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); +} + +void intel_panel_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + unsigned long flags; + + if (!panel->backlight.present || pipe == INVALID_PIPE) + return; + + /* + * Do not disable backlight on the vgaswitcheroo path. When switching + * away from i915, the other client may depend on i915 to handle the + * backlight. This will leave the backlight on unnecessarily when + * another client is not activated. + */ + if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { + DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); + return; + } + + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + + panel->backlight.enabled = false; + dev_priv->display.disable_backlight(connector); + + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); +} + +static void bdw_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 pch_ctl1, pch_ctl2; + + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { + DRM_DEBUG_KMS("pch backlight already enabled\n"); + pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + } + + pch_ctl2 = panel->backlight.max << 16; + I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); + + pch_ctl1 = 0; + if (panel->backlight.active_low_pwm) + pch_ctl1 |= BLM_PCH_POLARITY; + + /* BDW always uses the pch pwm controls. */ + pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; + + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + POSTING_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); + + /* This won't stick until the above enable. */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); +} + +static void pch_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + enum transcoder cpu_transcoder = + intel_pipe_to_cpu_transcoder(dev_priv, pipe); + u32 cpu_ctl2, pch_ctl1, pch_ctl2; + + cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); + if (cpu_ctl2 & BLM_PWM_ENABLE) { + WARN(1, "cpu backlight already enabled\n"); + cpu_ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); + } + + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { + DRM_DEBUG_KMS("pch backlight already enabled\n"); + pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + } + + if (cpu_transcoder == TRANSCODER_EDP) + cpu_ctl2 = BLM_TRANSCODER_EDP; + else + cpu_ctl2 = BLM_PIPE(cpu_transcoder); + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); + POSTING_READ(BLC_PWM_CPU_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); + + /* This won't stick until the above enable. */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); + + pch_ctl2 = panel->backlight.max << 16; + I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); + + pch_ctl1 = 0; + if (panel->backlight.active_low_pwm) + pch_ctl1 |= BLM_PCH_POLARITY; + + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + POSTING_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); +} + +static void i9xx_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 ctl, freq; + + ctl = I915_READ(BLC_PWM_CTL); + if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { + WARN(1, "backlight already enabled\n"); + I915_WRITE(BLC_PWM_CTL, 0); + } + + freq = panel->backlight.max; + if (panel->backlight.combination_mode) + freq /= 0xff; + + ctl = freq << 17; + if (panel->backlight.combination_mode) + ctl |= BLM_LEGACY_MODE; + if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm) + ctl |= BLM_POLARITY_PNV; + + I915_WRITE(BLC_PWM_CTL, ctl); + POSTING_READ(BLC_PWM_CTL); + + /* XXX: combine this into above write? */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); +} + +static void i965_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 ctl, ctl2, freq; + + ctl2 = I915_READ(BLC_PWM_CTL2); + if (ctl2 & BLM_PWM_ENABLE) { + WARN(1, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(BLC_PWM_CTL2, ctl2); + } + + freq = panel->backlight.max; + if (panel->backlight.combination_mode) + freq /= 0xff; + + ctl = freq << 16; + I915_WRITE(BLC_PWM_CTL, ctl); + + /* XXX: combine this into above write? */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); + + ctl2 = BLM_PIPE(pipe); + if (panel->backlight.combination_mode) + ctl2 |= BLM_COMBINATION_MODE; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + I915_WRITE(BLC_PWM_CTL2, ctl2); + POSTING_READ(BLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); +} + +static void vlv_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 ctl, ctl2; + + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + if (ctl2 & BLM_PWM_ENABLE) { + WARN(1, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); + } + + ctl = panel->backlight.max << 16; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl); + + /* XXX: combine this into above write? */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); + + ctl2 = 0; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); + POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); +} + +void intel_panel_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + unsigned long flags; + + if (!panel->backlight.present || pipe == INVALID_PIPE) + return; + + DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); + + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + + WARN_ON(panel->backlight.max == 0); + + if (panel->backlight.level == 0) { + panel->backlight.level = panel->backlight.max; + if (panel->backlight.device) + panel->backlight.device->props.brightness = + panel->backlight.level; + } + + dev_priv->display.enable_backlight(connector); + panel->backlight.enabled = true; + + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); +} + +enum drm_connector_status +intel_panel_detect(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Assume that the BIOS does not lie through the OpRegion... */ + if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) { + return ioread32(dev_priv->opregion.lid_state) & 0x1 ? + connector_status_connected : + connector_status_disconnected; + } + + switch (i915_panel_ignore_lid) { + case -2: + return connector_status_connected; + case -1: + return connector_status_disconnected; + default: + return connector_status_unknown; + } +} + +#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) +static int intel_backlight_device_update_status(struct backlight_device *bd) +{ + struct intel_connector *connector = bl_get_data(bd); + struct drm_device *dev = connector->base.dev; + + mutex_lock(&dev->mode_config.mutex); + DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", + bd->props.brightness, bd->props.max_brightness); + intel_panel_set_backlight(connector, bd->props.brightness, + bd->props.max_brightness); + mutex_unlock(&dev->mode_config.mutex); + return 0; +} + +static int intel_backlight_device_get_brightness(struct backlight_device *bd) +{ + struct intel_connector *connector = bl_get_data(bd); + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + intel_runtime_pm_get(dev_priv); + mutex_lock(&dev->mode_config.mutex); + ret = intel_panel_get_backlight(connector); + mutex_unlock(&dev->mode_config.mutex); + intel_runtime_pm_put(dev_priv); + + return ret; +} + +static const struct backlight_ops intel_backlight_device_ops = { + .update_status = intel_backlight_device_update_status, + .get_brightness = intel_backlight_device_get_brightness, +}; + +static int intel_backlight_device_register(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + struct backlight_properties props; + + if (WARN_ON(panel->backlight.device)) + return -ENODEV; + + BUG_ON(panel->backlight.max == 0); + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.brightness = panel->backlight.level; + props.max_brightness = panel->backlight.max; + + /* + * Note: using the same name independent of the connector prevents + * registration of multiple backlight devices in the driver. + */ + panel->backlight.device = + backlight_device_register("intel_backlight", + connector->base.kdev, + connector, + &intel_backlight_device_ops, &props); + + if (IS_ERR(panel->backlight.device)) { + DRM_ERROR("Failed to register backlight: %ld\n", + PTR_ERR(panel->backlight.device)); + panel->backlight.device = NULL; + return -ENODEV; + } + return 0; +} + +static void intel_backlight_device_unregister(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + if (panel->backlight.device) { + backlight_device_unregister(panel->backlight.device); + panel->backlight.device = NULL; + } +} +#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ +static int intel_backlight_device_register(struct intel_connector *connector) +{ + return 0; +} +static void intel_backlight_device_unregister(struct intel_connector *connector) +{ +} +#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ + +/* + * Note: The setup hooks can't assume pipe is set! + * + * XXX: Query mode clock or hardware clock and program PWM modulation frequency + * appropriately when it's 0. Use VBT and/or sane defaults. + */ +static int bdw_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 pch_ctl1, pch_ctl2, val; + + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; + + pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); + panel->backlight.max = pch_ctl2 >> 16; + if (!panel->backlight.max) + return -ENODEV; + + val = bdw_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) && + panel->backlight.level != 0; + + return 0; +} + +static int pch_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; + + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; + + pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); + panel->backlight.max = pch_ctl2 >> 16; + if (!panel->backlight.max) + return -ENODEV; + + val = pch_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); + panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && + (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0; + + return 0; +} + +static int i9xx_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 ctl, val; + + ctl = I915_READ(BLC_PWM_CTL); + + if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev)) + panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; + + if (IS_PINEVIEW(dev)) + panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; + + panel->backlight.max = ctl >> 17; + if (panel->backlight.combination_mode) + panel->backlight.max *= 0xff; + + if (!panel->backlight.max) + return -ENODEV; + + val = i9xx_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = panel->backlight.level != 0; + + return 0; +} + +static int i965_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 ctl, ctl2, val; + + ctl2 = I915_READ(BLC_PWM_CTL2); + panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = I915_READ(BLC_PWM_CTL); + panel->backlight.max = ctl >> 16; + if (panel->backlight.combination_mode) + panel->backlight.max *= 0xff; + + if (!panel->backlight.max) + return -ENODEV; + + val = i9xx_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && + panel->backlight.level != 0; + + return 0; +} + +static int vlv_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe; + u32 ctl, ctl2, val; + + for_each_pipe(pipe) { + u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); + + /* Skip if the modulation freq is already set */ + if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) + continue; + + cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | + cur_val); + } + + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); + panel->backlight.max = ctl >> 16; + if (!panel->backlight.max) + return -ENODEV; + + val = _vlv_get_backlight(dev, PIPE_A); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && + panel->backlight.level != 0; + + return 0; +} + +int intel_panel_setup_backlight(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_panel *panel = &intel_connector->panel; + unsigned long flags; + int ret; + + /* set level and max in panel struct */ + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + ret = dev_priv->display.setup_backlight(intel_connector); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); + + if (ret) { + DRM_DEBUG_KMS("failed to setup backlight for connector %s\n", + drm_get_connector_name(connector)); + return ret; + } + + intel_backlight_device_register(intel_connector); + + panel->backlight.present = true; + + DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, " + "sysfs interface %sregistered\n", + panel->backlight.enabled ? "enabled" : "disabled", + panel->backlight.level, panel->backlight.max, + panel->backlight.device ? "" : "not "); + + return 0; +} + +void intel_panel_destroy_backlight(struct drm_connector *connector) +{ + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_panel *panel = &intel_connector->panel; + + panel->backlight.present = false; + intel_backlight_device_unregister(intel_connector); +} + +/** + * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID + * @dev: drm device + * @fixed_mode : panel native mode + * @connector: LVDS/eDP connector + * + * Return downclock_avail + * Find the reduced downclock for LVDS/eDP in EDID. + */ +struct drm_display_mode * +intel_find_panel_downclock(struct drm_device *dev, + struct drm_display_mode *fixed_mode, + struct drm_connector *connector) +{ + struct drm_display_mode *scan, *tmp_mode; + int temp_downclock; + + temp_downclock = fixed_mode->clock; + tmp_mode = NULL; + + list_for_each_entry(scan, &connector->probed_modes, head) { + /* + * If one mode has the same resolution with the fixed_panel + * mode while they have the different refresh rate, it means + * that the reduced downclock is found. In such + * case we can set the different FPx0/1 to dynamically select + * between low and high frequency. + */ + if (scan->hdisplay == fixed_mode->hdisplay && + scan->hsync_start == fixed_mode->hsync_start && + scan->hsync_end == fixed_mode->hsync_end && + scan->htotal == fixed_mode->htotal && + scan->vdisplay == fixed_mode->vdisplay && + scan->vsync_start == fixed_mode->vsync_start && + scan->vsync_end == fixed_mode->vsync_end && + scan->vtotal == fixed_mode->vtotal) { + if (scan->clock < temp_downclock) { + /* + * The downclock is already found. But we + * expect to find the lower downclock. + */ + temp_downclock = scan->clock; + tmp_mode = scan; + } + } + } + + if (temp_downclock < fixed_mode->clock) + return drm_mode_duplicate(dev, tmp_mode); + else + return NULL; +} + +/* Set up chip specific backlight functions */ +void intel_panel_init_backlight_funcs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_BROADWELL(dev)) { + dev_priv->display.setup_backlight = bdw_setup_backlight; + dev_priv->display.enable_backlight = bdw_enable_backlight; + dev_priv->display.disable_backlight = pch_disable_backlight; + dev_priv->display.set_backlight = bdw_set_backlight; + dev_priv->display.get_backlight = bdw_get_backlight; + } else if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.setup_backlight = pch_setup_backlight; + dev_priv->display.enable_backlight = pch_enable_backlight; + dev_priv->display.disable_backlight = pch_disable_backlight; + dev_priv->display.set_backlight = pch_set_backlight; + dev_priv->display.get_backlight = pch_get_backlight; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.setup_backlight = vlv_setup_backlight; + dev_priv->display.enable_backlight = vlv_enable_backlight; + dev_priv->display.disable_backlight = vlv_disable_backlight; + dev_priv->display.set_backlight = vlv_set_backlight; + dev_priv->display.get_backlight = vlv_get_backlight; + } else if (IS_GEN4(dev)) { + dev_priv->display.setup_backlight = i965_setup_backlight; + dev_priv->display.enable_backlight = i965_enable_backlight; + dev_priv->display.disable_backlight = i965_disable_backlight; + dev_priv->display.set_backlight = i9xx_set_backlight; + dev_priv->display.get_backlight = i9xx_get_backlight; + } else { + dev_priv->display.setup_backlight = i9xx_setup_backlight; + dev_priv->display.enable_backlight = i9xx_enable_backlight; + dev_priv->display.disable_backlight = i9xx_disable_backlight; + dev_priv->display.set_backlight = i9xx_set_backlight; + dev_priv->display.get_backlight = i9xx_get_backlight; + } +} + +int intel_panel_init(struct intel_panel *panel, + struct drm_display_mode *fixed_mode) +{ + panel->fixed_mode = fixed_mode; + + return 0; +} + +void intel_panel_fini(struct intel_panel *panel) +{ + struct intel_connector *intel_connector = + container_of(panel, struct intel_connector, panel); + + if (panel->fixed_mode) + drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); + + if (panel->downclock_mode) + drm_mode_destroy(intel_connector->base.dev, + panel->downclock_mode); +} --- linux-3.13.0.orig/ubuntu/i915/i915_gem_stolen.c +++ linux-3.13.0/ubuntu/i915/i915_gem_stolen.c @@ -0,0 +1,464 @@ +/* + * Copyright © 2008-2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Chris Wilson + * + */ + +#include +#include +#include "i915_drv.h" + +/* + * The BIOS typically reserves some of the system's memory for the exclusive + * use of the integrated graphics. This memory is no longer available for + * use by the OS and so the user finds that his system has less memory + * available than he put in. We refer to this memory as stolen. + * + * The BIOS will allocate its framebuffer from the stolen memory. Our + * goal is try to reuse that object for our own fbcon which must always + * be available for panics. Anything else we can reuse the stolen memory + * for is a boon. + */ + +static unsigned long i915_stolen_to_physical(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct resource *r; + u32 base; + + /* Almost universally we can find the Graphics Base of Stolen Memory + * at offset 0x5c in the igfx configuration space. On a few (desktop) + * machines this is also mirrored in the bridge device at different + * locations, or in the MCHBAR. On gen2, the layout is again slightly + * different with the Graphics Segment immediately following Top of + * Memory (or Top of Usable DRAM). Note it appears that TOUD is only + * reported by 865g, so we just use the top of memory as determined + * by the e820 probe. + * + * XXX However gen2 requires an unavailable symbol. + */ + base = 0; + if (INTEL_INFO(dev)->gen >= 3) { + /* Read Graphics Base of Stolen Memory directly */ + pci_read_config_dword(dev->pdev, 0x5c, &base); + base &= ~((1<<20) - 1); + } else { /* GEN2 */ +#if 0 + /* Stolen is immediately above Top of Memory */ + base = max_low_pfn_mapped << PAGE_SHIFT; +#endif + } + + if (base == 0) + return 0; + + /* Verify that nothing else uses this physical address. Stolen + * memory should be reserved by the BIOS and hidden from the + * kernel. So if the region is already marked as busy, something + * is seriously wrong. + */ + r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size, + "Graphics Stolen Memory"); + if (r == NULL) { + /* + * One more attempt but this time requesting region from + * base + 1, as we have seen that this resolves the region + * conflict with the PCI Bus. + * This is a BIOS w/a: Some BIOS wrap stolen in the root + * PCI bus, but have an off-by-one error. Hence retry the + * reservation starting from 1 instead of 0. + */ + r = devm_request_mem_region(dev->dev, base + 1, + dev_priv->gtt.stolen_size - 1, + "Graphics Stolen Memory"); + if (r == NULL) { + DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n", + base, base + (uint32_t)dev_priv->gtt.stolen_size); + base = 0; + } + } + + return base; +} + +static int i915_setup_compression(struct drm_device *dev, int size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb); + int ret; + + compressed_fb = kzalloc(sizeof(*compressed_fb), GFP_KERNEL); + if (!compressed_fb) + goto err_llb; + + /* Try to over-allocate to reduce reallocations and fragmentation */ + ret = drm_mm_insert_node(&dev_priv->mm.stolen, compressed_fb, + size <<= 1, 4096, DRM_MM_SEARCH_DEFAULT); + if (ret) + ret = drm_mm_insert_node(&dev_priv->mm.stolen, compressed_fb, + size >>= 1, 4096, + DRM_MM_SEARCH_DEFAULT); + if (ret) + goto err_llb; + + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); + else if (IS_GM45(dev)) { + I915_WRITE(DPFC_CB_BASE, compressed_fb->start); + } else { + compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); + if (!compressed_llb) + goto err_fb; + + ret = drm_mm_insert_node(&dev_priv->mm.stolen, compressed_llb, + 4096, 4096, DRM_MM_SEARCH_DEFAULT); + if (ret) + goto err_fb; + + dev_priv->fbc.compressed_llb = compressed_llb; + + I915_WRITE(FBC_CFB_BASE, + dev_priv->mm.stolen_base + compressed_fb->start); + I915_WRITE(FBC_LL_BASE, + dev_priv->mm.stolen_base + compressed_llb->start); + } + + dev_priv->fbc.compressed_fb = compressed_fb; + dev_priv->fbc.size = size; + + DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", + size); + + return 0; + +err_fb: + kfree(compressed_llb); + drm_mm_remove_node(compressed_fb); +err_llb: + kfree(compressed_fb); + pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); + return -ENOSPC; +} + +int i915_gem_stolen_setup_compression(struct drm_device *dev, int size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return -ENODEV; + + if (size < dev_priv->fbc.size) + return 0; + + /* Release any current block */ + i915_gem_stolen_cleanup_compression(dev); + + return i915_setup_compression(dev, size); +} + +void i915_gem_stolen_cleanup_compression(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->fbc.size == 0) + return; + + if (dev_priv->fbc.compressed_fb) { + drm_mm_remove_node(dev_priv->fbc.compressed_fb); + kfree(dev_priv->fbc.compressed_fb); + } + + if (dev_priv->fbc.compressed_llb) { + drm_mm_remove_node(dev_priv->fbc.compressed_llb); + kfree(dev_priv->fbc.compressed_llb); + } + + dev_priv->fbc.size = 0; +} + +void i915_gem_cleanup_stolen(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return; + + i915_gem_stolen_cleanup_compression(dev); + drm_mm_takedown(&dev_priv->mm.stolen); +} + +int i915_gem_init_stolen(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int bios_reserved = 0; + +#ifdef CONFIG_INTEL_IOMMU + if (intel_iommu_gfx_mapped) { + DRM_INFO("DMAR active, disabling use of stolen memory\n"); + return 0; + } +#endif + + if (dev_priv->gtt.stolen_size == 0) + return 0; + + dev_priv->mm.stolen_base = i915_stolen_to_physical(dev); + if (dev_priv->mm.stolen_base == 0) + return 0; + + DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n", + dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base); + + if (IS_VALLEYVIEW(dev)) + bios_reserved = 1024*1024; /* top 1M on VLV/BYT */ + + if (WARN_ON(bios_reserved > dev_priv->gtt.stolen_size)) + return 0; + + /* Basic memrange allocator for stolen space */ + drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size - + bios_reserved); + + return 0; +} + +static struct sg_table * +i915_pages_create_for_stolen(struct drm_device *dev, + u32 offset, u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct sg_table *st; + struct scatterlist *sg; + + DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size); + BUG_ON(offset > dev_priv->gtt.stolen_size - size); + + /* We hide that we have no struct page backing our stolen object + * by wrapping the contiguous physical allocation with a fake + * dma mapping in a single scatterlist. + */ + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) + return NULL; + + if (sg_alloc_table(st, 1, GFP_KERNEL)) { + kfree(st); + return NULL; + } + + sg = st->sgl; + sg->offset = 0; + sg->length = size; + + sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset; + sg_dma_len(sg) = size; + + return st; +} + +static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj) +{ + BUG(); + return -EINVAL; +} + +static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj) +{ + /* Should only be called during free */ + sg_free_table(obj->pages); + kfree(obj->pages); +} + +static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = { + .get_pages = i915_gem_object_get_pages_stolen, + .put_pages = i915_gem_object_put_pages_stolen, +}; + +static struct drm_i915_gem_object * +_i915_gem_object_create_stolen(struct drm_device *dev, + struct drm_mm_node *stolen) +{ + struct drm_i915_gem_object *obj; + + obj = i915_gem_object_alloc(dev); + if (obj == NULL) + return NULL; + + drm_gem_private_object_init(dev, &obj->base, stolen->size); + i915_gem_object_init(obj, &i915_gem_object_stolen_ops); + + obj->pages = i915_pages_create_for_stolen(dev, + stolen->start, stolen->size); + if (obj->pages == NULL) + goto cleanup; + + obj->has_dma_mapping = true; + i915_gem_object_pin_pages(obj); + obj->stolen = stolen; + + obj->base.read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT; + obj->cache_level = HAS_LLC(dev) ? I915_CACHE_LLC : I915_CACHE_NONE; + + return obj; + +cleanup: + i915_gem_object_free(obj); + return NULL; +} + +struct drm_i915_gem_object * +i915_gem_object_create_stolen(struct drm_device *dev, u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + struct drm_mm_node *stolen; + int ret; + + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return NULL; + + DRM_DEBUG_KMS("creating stolen object: size=%x\n", size); + if (size == 0) + return NULL; + + stolen = kzalloc(sizeof(*stolen), GFP_KERNEL); + if (!stolen) + return NULL; + + ret = drm_mm_insert_node(&dev_priv->mm.stolen, stolen, size, + 4096, DRM_MM_SEARCH_DEFAULT); + if (ret) { + kfree(stolen); + return NULL; + } + + obj = _i915_gem_object_create_stolen(dev, stolen); + if (obj) + return obj; + + drm_mm_remove_node(stolen); + kfree(stolen); + return NULL; +} + +struct drm_i915_gem_object * +i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, + u32 stolen_offset, + u32 gtt_offset, + u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_address_space *ggtt = &dev_priv->gtt.base; + struct drm_i915_gem_object *obj; + struct drm_mm_node *stolen; + struct i915_vma *vma; + int ret; + + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return NULL; + + DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n", + stolen_offset, gtt_offset, size); + + /* KISS and expect everything to be page-aligned */ + BUG_ON(stolen_offset & 4095); + BUG_ON(size & 4095); + + if (WARN_ON(size == 0)) + return NULL; + + stolen = kzalloc(sizeof(*stolen), GFP_KERNEL); + if (!stolen) + return NULL; + + stolen->start = stolen_offset; + stolen->size = size; + ret = drm_mm_reserve_node(&dev_priv->mm.stolen, stolen); + if (ret) { + DRM_DEBUG_KMS("failed to allocate stolen space\n"); + kfree(stolen); + return NULL; + } + + obj = _i915_gem_object_create_stolen(dev, stolen); + if (obj == NULL) { + DRM_DEBUG_KMS("failed to allocate stolen object\n"); + drm_mm_remove_node(stolen); + kfree(stolen); + return NULL; + } + + /* Some objects just need physical mem from stolen space */ + if (gtt_offset == I915_GTT_OFFSET_NONE) + return obj; + + vma = i915_gem_obj_lookup_or_create_vma(obj, ggtt); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto err_out; + } + + /* To simplify the initialisation sequence between KMS and GTT, + * we allow construction of the stolen object prior to + * setting up the GTT space. The actual reservation will occur + * later. + */ + vma->node.start = gtt_offset; + vma->node.size = size; + if (drm_mm_initialized(&ggtt->mm)) { + ret = drm_mm_reserve_node(&ggtt->mm, &vma->node); + if (ret) { + DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); + goto err_vma; + } + } + + obj->has_global_gtt_mapping = 1; + + list_add_tail(&obj->global_list, &dev_priv->mm.bound_list); + list_add_tail(&vma->mm_list, &ggtt->inactive_list); + i915_gem_object_pin_pages(obj); + + return obj; + +err_vma: + i915_gem_vma_destroy(vma); +err_out: + drm_mm_remove_node(stolen); + kfree(stolen); + drm_gem_object_unreference(&obj->base); + return NULL; +} + +void +i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) +{ + if (obj->stolen) { + drm_mm_remove_node(obj->stolen); + kfree(obj->stolen); + obj->stolen = NULL; + } +} --- linux-3.13.0.orig/ubuntu/i915/intel_dvo.c +++ linux-3.13.0/ubuntu/i915/intel_dvo.c @@ -0,0 +1,566 @@ +/* + * Copyright 2006 Dave Airlie + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ +#include +#include +#include +#include +#include "intel_drv.h" +#include +#include "i915_drv.h" +#include "dvo.h" + +#define SIL164_ADDR 0x38 +#define CH7xxx_ADDR 0x76 +#define TFP410_ADDR 0x38 +#define NS2501_ADDR 0x38 + +static const struct intel_dvo_device intel_dvo_devices[] = { + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "sil164", + .dvo_reg = DVOC, + .slave_addr = SIL164_ADDR, + .dev_ops = &sil164_ops, + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "ch7xxx", + .dvo_reg = DVOC, + .slave_addr = CH7xxx_ADDR, + .dev_ops = &ch7xxx_ops, + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "ch7xxx", + .dvo_reg = DVOC, + .slave_addr = 0x75, /* For some ch7010 */ + .dev_ops = &ch7xxx_ops, + }, + { + .type = INTEL_DVO_CHIP_LVDS, + .name = "ivch", + .dvo_reg = DVOA, + .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */ + .dev_ops = &ivch_ops, + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "tfp410", + .dvo_reg = DVOC, + .slave_addr = TFP410_ADDR, + .dev_ops = &tfp410_ops, + }, + { + .type = INTEL_DVO_CHIP_LVDS, + .name = "ch7017", + .dvo_reg = DVOC, + .slave_addr = 0x75, + .gpio = GMBUS_PORT_DPB, + .dev_ops = &ch7017_ops, + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "ns2501", + .dvo_reg = DVOC, + .slave_addr = NS2501_ADDR, + .dev_ops = &ns2501_ops, + } +}; + +struct intel_dvo { + struct intel_encoder base; + + struct intel_dvo_device dev; + + struct drm_display_mode *panel_fixed_mode; + bool panel_wants_dither; +}; + +static struct intel_dvo *enc_to_dvo(struct intel_encoder *encoder) +{ + return container_of(encoder, struct intel_dvo, base); +} + +static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector) +{ + return enc_to_dvo(intel_attached_encoder(connector)); +} + +static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector) +{ + struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base); + + return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev); +} + +static bool intel_dvo_get_hw_state(struct intel_encoder *encoder, + enum pipe *pipe) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + u32 tmp; + + tmp = I915_READ(intel_dvo->dev.dvo_reg); + + if (!(tmp & DVO_ENABLE)) + return false; + + *pipe = PORT_TO_PIPE(tmp); + + return true; +} + +static void intel_dvo_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + u32 tmp, flags = 0; + + tmp = I915_READ(intel_dvo->dev.dvo_reg); + if (tmp & DVO_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + if (tmp & DVO_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; + + pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock; +} + +static void intel_disable_dvo(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + u32 dvo_reg = intel_dvo->dev.dvo_reg; + u32 temp = I915_READ(dvo_reg); + + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false); + I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); + I915_READ(dvo_reg); +} + +static void intel_enable_dvo(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + u32 dvo_reg = intel_dvo->dev.dvo_reg; + u32 temp = I915_READ(dvo_reg); + + I915_WRITE(dvo_reg, temp | DVO_ENABLE); + I915_READ(dvo_reg); + intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, + &crtc->config.requested_mode, + &crtc->config.adjusted_mode); + + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true); +} + +/* Special dpms function to support cloning between dvo/sdvo/crt. */ +static void intel_dvo_dpms(struct drm_connector *connector, int mode) +{ + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + struct drm_crtc *crtc; + struct intel_crtc_config *config; + + /* dvo supports only 2 dpms states. */ + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + if (mode == connector->dpms) + return; + + connector->dpms = mode; + + /* Only need to change hw state when actually enabled */ + crtc = intel_dvo->base.base.crtc; + if (!crtc) { + intel_dvo->base.connectors_active = false; + return; + } + + /* We call connector dpms manually below in case pipe dpms doesn't + * change due to cloning. */ + if (mode == DRM_MODE_DPMS_ON) { + config = &to_intel_crtc(crtc)->config; + + intel_dvo->base.connectors_active = true; + + intel_crtc_update_dpms(crtc); + + intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, + &config->requested_mode, + &config->adjusted_mode); + + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true); + } else { + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false); + + intel_dvo->base.connectors_active = false; + + intel_crtc_update_dpms(crtc); + } + + intel_modeset_check_state(connector->dev); +} + +static enum drm_mode_status +intel_dvo_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + /* XXX: Validate clock range */ + + if (intel_dvo->panel_fixed_mode) { + if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay) + return MODE_PANEL; + if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay) + return MODE_PANEL; + } + + return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); +} + +static bool intel_dvo_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + + /* If we have timings from the BIOS for the panel, put them in + * to the adjusted mode. The CRTC will be set up for this mode, + * with the panel scaling set up to source from the H/VDisplay + * of the original mode. + */ + if (intel_dvo->panel_fixed_mode != NULL) { +#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x + C(hdisplay); + C(hsync_start); + C(hsync_end); + C(htotal); + C(vdisplay); + C(vsync_start); + C(vsync_end); + C(vtotal); + C(clock); +#undef C + + drm_mode_set_crtcinfo(adjusted_mode, 0); + } + + return true; +} + +static void intel_dvo_mode_set(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; + struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + int pipe = crtc->pipe; + u32 dvo_val; + u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg; + + switch (dvo_reg) { + case DVOA: + default: + dvo_srcdim_reg = DVOA_SRCDIM; + break; + case DVOB: + dvo_srcdim_reg = DVOB_SRCDIM; + break; + case DVOC: + dvo_srcdim_reg = DVOC_SRCDIM; + break; + } + + /* Save the data order, since I don't know what it should be set to. */ + dvo_val = I915_READ(dvo_reg) & + (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG); + dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | + DVO_BLANK_ACTIVE_HIGH; + + if (pipe == 1) + dvo_val |= DVO_PIPE_B_SELECT; + dvo_val |= DVO_PIPE_STALL; + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + dvo_val |= DVO_HSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + dvo_val |= DVO_VSYNC_ACTIVE_HIGH; + + /*I915_WRITE(DVOB_SRCDIM, + (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ + I915_WRITE(dvo_srcdim_reg, + (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); + /*I915_WRITE(DVOB, dvo_val);*/ + I915_WRITE(dvo_reg, dvo_val); +} + +/** + * Detect the output connection on our DVO device. + * + * Unimplemented. + */ +static enum drm_connector_status +intel_dvo_detect(struct drm_connector *connector, bool force) +{ + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector)); + return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); +} + +static int intel_dvo_get_modes(struct drm_connector *connector) +{ + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + + /* We should probably have an i2c driver get_modes function for those + * devices which will have a fixed set of modes determined by the chip + * (TV-out, for example), but for now with just TMDS and LVDS, + * that's not the case. + */ + intel_ddc_get_modes(connector, + intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPC)); + if (!list_empty(&connector->probed_modes)) + return 1; + + if (intel_dvo->panel_fixed_mode != NULL) { + struct drm_display_mode *mode; + mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode); + if (mode) { + drm_mode_probed_add(connector, mode); + return 1; + } + } + + return 0; +} + +static void intel_dvo_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); + kfree(connector); +} + +static const struct drm_connector_funcs intel_dvo_connector_funcs = { + .dpms = intel_dvo_dpms, + .detect = intel_dvo_detect, + .destroy = intel_dvo_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, +}; + +static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { + .mode_valid = intel_dvo_mode_valid, + .get_modes = intel_dvo_get_modes, + .best_encoder = intel_best_encoder, +}; + +static void intel_dvo_enc_destroy(struct drm_encoder *encoder) +{ + struct intel_dvo *intel_dvo = enc_to_dvo(to_intel_encoder(encoder)); + + if (intel_dvo->dev.dev_ops->destroy) + intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev); + + kfree(intel_dvo->panel_fixed_mode); + + intel_encoder_destroy(encoder); +} + +static const struct drm_encoder_funcs intel_dvo_enc_funcs = { + .destroy = intel_dvo_enc_destroy, +}; + +/** + * Attempts to get a fixed panel timing for LVDS (currently only the i830). + * + * Other chips with DVO LVDS will need to extend this to deal with the LVDS + * chip being on DVOB/C and having multiple pipes. + */ +static struct drm_display_mode * +intel_dvo_get_current_mode(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg); + struct drm_display_mode *mode = NULL; + + /* If the DVO port is active, that'll be the LVDS, so we can pull out + * its timings to get how the BIOS set up the panel. + */ + if (dvo_val & DVO_ENABLE) { + struct drm_crtc *crtc; + int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0; + + crtc = intel_get_crtc_for_pipe(dev, pipe); + if (crtc) { + mode = intel_crtc_mode_get(dev, crtc); + if (mode) { + mode->type |= DRM_MODE_TYPE_PREFERRED; + if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) + mode->flags |= DRM_MODE_FLAG_PHSYNC; + if (dvo_val & DVO_VSYNC_ACTIVE_HIGH) + mode->flags |= DRM_MODE_FLAG_PVSYNC; + } + } + } + + return mode; +} + +void intel_dvo_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + struct intel_dvo *intel_dvo; + struct intel_connector *intel_connector; + int i; + int encoder_type = DRM_MODE_ENCODER_NONE; + + intel_dvo = kzalloc(sizeof(*intel_dvo), GFP_KERNEL); + if (!intel_dvo) + return; + + intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); + if (!intel_connector) { + kfree(intel_dvo); + return; + } + + intel_encoder = &intel_dvo->base; + drm_encoder_init(dev, &intel_encoder->base, + &intel_dvo_enc_funcs, encoder_type); + + intel_encoder->disable = intel_disable_dvo; + intel_encoder->enable = intel_enable_dvo; + intel_encoder->get_hw_state = intel_dvo_get_hw_state; + intel_encoder->get_config = intel_dvo_get_config; + intel_encoder->compute_config = intel_dvo_compute_config; + intel_encoder->mode_set = intel_dvo_mode_set; + intel_connector->get_hw_state = intel_dvo_connector_get_hw_state; + + /* Now, try to find a controller */ + for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { + struct drm_connector *connector = &intel_connector->base; + const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; + struct i2c_adapter *i2c; + int gpio; + bool dvoinit; + + /* Allow the I2C driver info to specify the GPIO to be used in + * special cases, but otherwise default to what's defined + * in the spec. + */ + if (intel_gmbus_is_port_valid(dvo->gpio)) + gpio = dvo->gpio; + else if (dvo->type == INTEL_DVO_CHIP_LVDS) + gpio = GMBUS_PORT_SSC; + else + gpio = GMBUS_PORT_DPB; + + /* Set up the I2C bus necessary for the chip we're probing. + * It appears that everything is on GPIOE except for panels + * on i830 laptops, which are on GPIOB (DVOA). + */ + i2c = intel_gmbus_get_adapter(dev_priv, gpio); + + intel_dvo->dev = *dvo; + + /* GMBUS NAK handling seems to be unstable, hence let the + * transmitter detection run in bit banging mode for now. + */ + intel_gmbus_force_bit(i2c, true); + + dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c); + + intel_gmbus_force_bit(i2c, false); + + if (!dvoinit) + continue; + + intel_encoder->type = INTEL_OUTPUT_DVO; + intel_encoder->crtc_mask = (1 << 0) | (1 << 1); + switch (dvo->type) { + case INTEL_DVO_CHIP_TMDS: + intel_encoder->cloneable = true; + drm_connector_init(dev, connector, + &intel_dvo_connector_funcs, + DRM_MODE_CONNECTOR_DVII); + encoder_type = DRM_MODE_ENCODER_TMDS; + break; + case INTEL_DVO_CHIP_LVDS: + intel_encoder->cloneable = false; + drm_connector_init(dev, connector, + &intel_dvo_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + encoder_type = DRM_MODE_ENCODER_LVDS; + break; + } + + drm_connector_helper_add(connector, + &intel_dvo_connector_helper_funcs); + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; + + intel_connector_attach_encoder(intel_connector, intel_encoder); + if (dvo->type == INTEL_DVO_CHIP_LVDS) { + /* For our LVDS chipsets, we should hopefully be able + * to dig the fixed panel mode out of the BIOS data. + * However, it's in a different format from the BIOS + * data on chipsets with integrated LVDS (stored in AIM + * headers, likely), so for now, just get the current + * mode being output through DVO. + */ + intel_dvo->panel_fixed_mode = + intel_dvo_get_current_mode(connector); + intel_dvo->panel_wants_dither = true; + } + + drm_sysfs_connector_add(connector); + return; + } + + drm_encoder_cleanup(&intel_encoder->base); + kfree(intel_dvo); + kfree(intel_connector); +} --- linux-3.13.0.orig/ubuntu/i915/i915_reg.h +++ linux-3.13.0/ubuntu/i915/i915_reg.h @@ -0,0 +1,5870 @@ +/* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _I915_REG_H_ +#define _I915_REG_H_ + +#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) +#define _PIPE_INC(pipe, base, inc) ((base) + (pipe)*(inc)) +#define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a))) + +#define _PORT(port, a, b) ((a) + (port)*((b)-(a))) + +#define _MASKED_BIT_ENABLE(a) (((a) << 16) | (a)) +#define _MASKED_BIT_DISABLE(a) ((a) << 16) + +/* PCI config space */ + +#define HPLLCC 0xc0 /* 855 only */ +#define GC_CLOCK_CONTROL_MASK (0xf << 0) +#define GC_CLOCK_133_200 (0 << 0) +#define GC_CLOCK_100_200 (1 << 0) +#define GC_CLOCK_100_133 (2 << 0) +#define GC_CLOCK_166_250 (3 << 0) +#define GCFGC2 0xda +#define GCFGC 0xf0 /* 915+ only */ +#define GC_LOW_FREQUENCY_ENABLE (1 << 7) +#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define GC_DISPLAY_CLOCK_333_MHZ (4 << 4) +#define GC_DISPLAY_CLOCK_267_MHZ_PNV (0 << 4) +#define GC_DISPLAY_CLOCK_333_MHZ_PNV (1 << 4) +#define GC_DISPLAY_CLOCK_444_MHZ_PNV (2 << 4) +#define GC_DISPLAY_CLOCK_200_MHZ_PNV (5 << 4) +#define GC_DISPLAY_CLOCK_133_MHZ_PNV (6 << 4) +#define GC_DISPLAY_CLOCK_167_MHZ_PNV (7 << 4) +#define GC_DISPLAY_CLOCK_MASK (7 << 4) +#define GM45_GC_RENDER_CLOCK_MASK (0xf << 0) +#define GM45_GC_RENDER_CLOCK_266_MHZ (8 << 0) +#define GM45_GC_RENDER_CLOCK_320_MHZ (9 << 0) +#define GM45_GC_RENDER_CLOCK_400_MHZ (0xb << 0) +#define GM45_GC_RENDER_CLOCK_533_MHZ (0xc << 0) +#define I965_GC_RENDER_CLOCK_MASK (0xf << 0) +#define I965_GC_RENDER_CLOCK_267_MHZ (2 << 0) +#define I965_GC_RENDER_CLOCK_333_MHZ (3 << 0) +#define I965_GC_RENDER_CLOCK_444_MHZ (4 << 0) +#define I965_GC_RENDER_CLOCK_533_MHZ (5 << 0) +#define I945_GC_RENDER_CLOCK_MASK (7 << 0) +#define I945_GC_RENDER_CLOCK_166_MHZ (0 << 0) +#define I945_GC_RENDER_CLOCK_200_MHZ (1 << 0) +#define I945_GC_RENDER_CLOCK_250_MHZ (3 << 0) +#define I945_GC_RENDER_CLOCK_400_MHZ (5 << 0) +#define I915_GC_RENDER_CLOCK_MASK (7 << 0) +#define I915_GC_RENDER_CLOCK_166_MHZ (0 << 0) +#define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0) +#define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0) +#define LBB 0xf4 + +/* Graphics reset regs */ +#define I965_GDRST 0xc0 /* PCI config register */ +#define ILK_GDSR 0x2ca4 /* MCHBAR offset */ +#define GRDOM_FULL (0<<2) +#define GRDOM_RENDER (1<<2) +#define GRDOM_MEDIA (3<<2) +#define GRDOM_MASK (3<<2) +#define GRDOM_RESET_ENABLE (1<<0) + +#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ +#define GEN6_MBC_SNPCR_SHIFT 21 +#define GEN6_MBC_SNPCR_MASK (3<<21) +#define GEN6_MBC_SNPCR_MAX (0<<21) +#define GEN6_MBC_SNPCR_MED (1<<21) +#define GEN6_MBC_SNPCR_LOW (2<<21) +#define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */ + +#define GEN6_MBCTL 0x0907c +#define GEN6_MBCTL_ENABLE_BOOT_FETCH (1 << 4) +#define GEN6_MBCTL_CTX_FETCH_NEEDED (1 << 3) +#define GEN6_MBCTL_BME_UPDATE_ENABLE (1 << 2) +#define GEN6_MBCTL_MAE_UPDATE_ENABLE (1 << 1) +#define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0) + +#define GEN6_GDRST 0x941c +#define GEN6_GRDOM_FULL (1 << 0) +#define GEN6_GRDOM_RENDER (1 << 1) +#define GEN6_GRDOM_MEDIA (1 << 2) +#define GEN6_GRDOM_BLT (1 << 3) + +#define RING_PP_DIR_BASE(ring) ((ring)->mmio_base+0x228) +#define RING_PP_DIR_BASE_READ(ring) ((ring)->mmio_base+0x518) +#define RING_PP_DIR_DCLV(ring) ((ring)->mmio_base+0x220) +#define PP_DIR_DCLV_2G 0xffffffff + +#define GEN8_RING_PDP_UDW(ring, n) ((ring)->mmio_base+0x270 + ((n) * 8 + 4)) +#define GEN8_RING_PDP_LDW(ring, n) ((ring)->mmio_base+0x270 + (n) * 8) + +#define GAM_ECOCHK 0x4090 +#define ECOCHK_SNB_BIT (1<<10) +#define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) +#define ECOCHK_PPGTT_CACHE64B (0x3<<3) +#define ECOCHK_PPGTT_CACHE4B (0x0<<3) +#define ECOCHK_PPGTT_GFDT_IVB (0x1<<4) +#define ECOCHK_PPGTT_LLC_IVB (0x1<<3) +#define ECOCHK_PPGTT_UC_HSW (0x1<<3) +#define ECOCHK_PPGTT_WT_HSW (0x2<<3) +#define ECOCHK_PPGTT_WB_HSW (0x3<<3) + +#define GAC_ECO_BITS 0x14090 +#define ECOBITS_SNB_BIT (1<<13) +#define ECOBITS_PPGTT_CACHE64B (3<<8) +#define ECOBITS_PPGTT_CACHE4B (0<<8) + +#define GAB_CTL 0x24000 +#define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8) + +/* VGA stuff */ + +#define VGA_ST01_MDA 0x3ba +#define VGA_ST01_CGA 0x3da + +#define VGA_MSR_WRITE 0x3c2 +#define VGA_MSR_READ 0x3cc +#define VGA_MSR_MEM_EN (1<<1) +#define VGA_MSR_CGA_MODE (1<<0) + +#define VGA_SR_INDEX 0x3c4 +#define SR01 1 +#define VGA_SR_DATA 0x3c5 + +#define VGA_AR_INDEX 0x3c0 +#define VGA_AR_VID_EN (1<<5) +#define VGA_AR_DATA_WRITE 0x3c0 +#define VGA_AR_DATA_READ 0x3c1 + +#define VGA_GR_INDEX 0x3ce +#define VGA_GR_DATA 0x3cf +/* GR05 */ +#define VGA_GR_MEM_READ_MODE_SHIFT 3 +#define VGA_GR_MEM_READ_MODE_PLANE 1 +/* GR06 */ +#define VGA_GR_MEM_MODE_MASK 0xc +#define VGA_GR_MEM_MODE_SHIFT 2 +#define VGA_GR_MEM_A0000_AFFFF 0 +#define VGA_GR_MEM_A0000_BFFFF 1 +#define VGA_GR_MEM_B0000_B7FFF 2 +#define VGA_GR_MEM_B0000_BFFFF 3 + +#define VGA_DACMASK 0x3c6 +#define VGA_DACRX 0x3c7 +#define VGA_DACWX 0x3c8 +#define VGA_DACDATA 0x3c9 + +#define VGA_CR_INDEX_MDA 0x3b4 +#define VGA_CR_DATA_MDA 0x3b5 +#define VGA_CR_INDEX_CGA 0x3d4 +#define VGA_CR_DATA_CGA 0x3d5 + +/* + * Memory interface instructions used by the kernel + */ +#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) + +#define MI_NOOP MI_INSTR(0, 0) +#define MI_USER_INTERRUPT MI_INSTR(0x02, 0) +#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0) +#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16) +#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) +#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) +#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) +#define MI_FLUSH MI_INSTR(0x04, 0) +#define MI_READ_FLUSH (1 << 0) +#define MI_EXE_FLUSH (1 << 1) +#define MI_NO_WRITE_FLUSH (1 << 2) +#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ +#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ +#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ +#define MI_REPORT_HEAD MI_INSTR(0x07, 0) +#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) +#define MI_ARB_ENABLE (1<<0) +#define MI_ARB_DISABLE (0<<0) +#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) +#define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) +#define MI_SUSPEND_FLUSH_EN (1<<0) +#define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) +#define MI_OVERLAY_CONTINUE (0x0<<21) +#define MI_OVERLAY_ON (0x1<<21) +#define MI_OVERLAY_OFF (0x2<<21) +#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) +#define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) +#define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) +#define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) +/* IVB has funny definitions for which plane to flip. */ +#define MI_DISPLAY_FLIP_IVB_PLANE_A (0 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_B (1 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_A (2 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_C (4 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19) +#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ +#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) +#define MI_SEMAPHORE_UPDATE (1<<21) +#define MI_SEMAPHORE_COMPARE (1<<20) +#define MI_SEMAPHORE_REGISTER (1<<18) +#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ +#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ +#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ +#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ +#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ +#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ +#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ +#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ +#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ +#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ +#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ +#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ +#define MI_SEMAPHORE_SYNC_INVALID (3<<16) +#define MI_SET_CONTEXT MI_INSTR(0x18, 0) +#define MI_MM_SPACE_GTT (1<<8) +#define MI_MM_SPACE_PHYSICAL (0<<8) +#define MI_SAVE_EXT_STATE_EN (1<<3) +#define MI_RESTORE_EXT_STATE_EN (1<<2) +#define MI_FORCE_RESTORE (1<<1) +#define MI_RESTORE_INHIBIT (1<<0) +#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) +#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ +#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) +#define MI_STORE_DWORD_INDEX_SHIFT 2 +/* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM: + * - Always issue a MI_NOOP _before_ the MI_LOAD_REGISTER_IMM - otherwise hw + * simply ignores the register load under certain conditions. + * - One can actually load arbitrary many arbitrary registers: Simply issue x + * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! + */ +#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) +#define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*x-1) +#define MI_SRM_LRM_GLOBAL_GTT (1<<22) +#define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ +#define MI_FLUSH_DW_STORE_INDEX (1<<21) +#define MI_INVALIDATE_TLB (1<<18) +#define MI_FLUSH_DW_OP_STOREDW (1<<14) +#define MI_INVALIDATE_BSD (1<<7) +#define MI_FLUSH_DW_USE_GTT (1<<2) +#define MI_FLUSH_DW_USE_PPGTT (0<<2) +#define MI_BATCH_BUFFER MI_INSTR(0x30, 1) +#define MI_BATCH_NON_SECURE (1) +/* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ +#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_PPGTT_HSW (1<<8) +#define MI_BATCH_NON_SECURE_HSW (1<<13) +#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) +#define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ +#define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) + + +#define MI_PREDICATE_RESULT_2 (0x2214) +#define LOWER_SLICE_ENABLED (1<<0) +#define LOWER_SLICE_DISABLED (0<<0) + +/* + * 3D instructions used by the kernel + */ +#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags)) + +#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) +#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) +#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) +#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) +#define BLT_DEPTH_8 (0<<24) +#define BLT_DEPTH_16_565 (1<<24) +#define BLT_DEPTH_16_1555 (2<<24) +#define BLT_DEPTH_32 (3<<24) +#define BLT_ROP_GXCOPY (0xcc<<16) +#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) /* 965+ only */ +#define XY_SRC_COPY_BLT_DST_TILED (1<<11) /* 965+ only */ +#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) +#define ASYNC_FLIP (1<<22) +#define DISPLAY_PLANE_A (0<<20) +#define DISPLAY_PLANE_B (1<<20) +#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2)) +#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ +#define PIPE_CONTROL_CS_STALL (1<<20) +#define PIPE_CONTROL_TLB_INVALIDATE (1<<18) +#define PIPE_CONTROL_QW_WRITE (1<<14) +#define PIPE_CONTROL_DEPTH_STALL (1<<13) +#define PIPE_CONTROL_WRITE_FLUSH (1<<12) +#define PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH (1<<12) /* gen6+ */ +#define PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE (1<<11) /* MBZ on Ironlake */ +#define PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE (1<<10) /* GM45+ only */ +#define PIPE_CONTROL_INDIRECT_STATE_DISABLE (1<<9) +#define PIPE_CONTROL_NOTIFY (1<<8) +#define PIPE_CONTROL_VF_CACHE_INVALIDATE (1<<4) +#define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1<<3) +#define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1<<2) +#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1) +#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1<<0) +#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ + + +/* + * Reset registers + */ +#define DEBUG_RESET_I830 0x6070 +#define DEBUG_RESET_FULL (1<<7) +#define DEBUG_RESET_RENDER (1<<8) +#define DEBUG_RESET_DISPLAY (1<<9) + +/* + * IOSF sideband + */ +#define VLV_IOSF_DOORBELL_REQ (VLV_DISPLAY_BASE + 0x2100) +#define IOSF_DEVFN_SHIFT 24 +#define IOSF_OPCODE_SHIFT 16 +#define IOSF_PORT_SHIFT 8 +#define IOSF_BYTE_ENABLES_SHIFT 4 +#define IOSF_BAR_SHIFT 1 +#define IOSF_SB_BUSY (1<<0) +#define IOSF_PORT_BUNIT 0x3 +#define IOSF_PORT_PUNIT 0x4 +#define IOSF_PORT_NC 0x11 +#define IOSF_PORT_DPIO 0x12 +#define IOSF_PORT_GPIO_NC 0x13 +#define IOSF_PORT_CCK 0x14 +#define IOSF_PORT_CCU 0xA9 +#define IOSF_PORT_GPS_CORE 0x48 +#define IOSF_PORT_FLISDSI 0x1B +#define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104) +#define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108) + +/* See configdb bunit SB addr map */ +#define BUNIT_REG_BISOC 0x11 + +#define PUNIT_OPCODE_REG_READ 6 +#define PUNIT_OPCODE_REG_WRITE 7 + +#define PUNIT_REG_DSPFREQ 0x36 +#define DSPFREQSTAT_SHIFT 30 +#define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) +#define DSPFREQGUAR_SHIFT 14 +#define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) +#define PUNIT_REG_PWRGT_CTRL 0x60 +#define PUNIT_REG_PWRGT_STATUS 0x61 +#define PUNIT_CLK_GATE 1 +#define PUNIT_PWR_RESET 2 +#define PUNIT_PWR_GATE 3 +#define RENDER_PWRGT (PUNIT_PWR_GATE << 0) +#define MEDIA_PWRGT (PUNIT_PWR_GATE << 2) +#define DISP2D_PWRGT (PUNIT_PWR_GATE << 6) + +#define PUNIT_REG_GPU_LFM 0xd3 +#define PUNIT_REG_GPU_FREQ_REQ 0xd4 +#define PUNIT_REG_GPU_FREQ_STS 0xd8 +#define GENFREQSTATUS (1<<0) +#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc + +#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */ +#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */ + +#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c +#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3 +#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800 +#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34 +#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007 +#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30 +#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 +#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 + +/* vlv2 north clock has */ +#define CCK_FUSE_REG 0x8 +#define CCK_FUSE_HPLL_FREQ_MASK 0x3 +#define CCK_REG_DSI_PLL_FUSE 0x44 +#define CCK_REG_DSI_PLL_CONTROL 0x48 +#define DSI_PLL_VCO_EN (1 << 31) +#define DSI_PLL_LDO_GATE (1 << 30) +#define DSI_PLL_P1_POST_DIV_SHIFT 17 +#define DSI_PLL_P1_POST_DIV_MASK (0x1ff << 17) +#define DSI_PLL_P2_MUX_DSI0_DIV2 (1 << 13) +#define DSI_PLL_P3_MUX_DSI1_DIV2 (1 << 12) +#define DSI_PLL_MUX_MASK (3 << 9) +#define DSI_PLL_MUX_DSI0_DSIPLL (0 << 10) +#define DSI_PLL_MUX_DSI0_CCK (1 << 10) +#define DSI_PLL_MUX_DSI1_DSIPLL (0 << 9) +#define DSI_PLL_MUX_DSI1_CCK (1 << 9) +#define DSI_PLL_CLK_GATE_MASK (0xf << 5) +#define DSI_PLL_CLK_GATE_DSI0_DSIPLL (1 << 8) +#define DSI_PLL_CLK_GATE_DSI1_DSIPLL (1 << 7) +#define DSI_PLL_CLK_GATE_DSI0_CCK (1 << 6) +#define DSI_PLL_CLK_GATE_DSI1_CCK (1 << 5) +#define DSI_PLL_LOCK (1 << 0) +#define CCK_REG_DSI_PLL_DIVIDER 0x4c +#define DSI_PLL_LFSR (1 << 31) +#define DSI_PLL_FRACTION_EN (1 << 30) +#define DSI_PLL_FRAC_COUNTER_SHIFT 27 +#define DSI_PLL_FRAC_COUNTER_MASK (7 << 27) +#define DSI_PLL_USYNC_CNT_SHIFT 18 +#define DSI_PLL_USYNC_CNT_MASK (0x1ff << 18) +#define DSI_PLL_N1_DIV_SHIFT 16 +#define DSI_PLL_N1_DIV_MASK (3 << 16) +#define DSI_PLL_M1_DIV_SHIFT 0 +#define DSI_PLL_M1_DIV_MASK (0x1ff << 0) +#define CCK_DISPLAY_CLOCK_CONTROL 0x6b + +/* + * DPIO - a special bus for various display related registers to hide behind + * + * DPIO is VLV only. + * + * Note: digital port B is DDI0, digital pot C is DDI1 + */ +#define DPIO_DEVFN 0 +#define DPIO_OPCODE_REG_WRITE 1 +#define DPIO_OPCODE_REG_READ 0 + +#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110) +#define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ +#define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ +#define DPIO_SFR_BYPASS (1<<1) +#define DPIO_CMNRST (1<<0) + +#define DPIO_PHY(pipe) ((pipe) >> 1) +#define DPIO_PHY_IOSF_PORT(phy) (dev_priv->dpio_phy_iosf_port[phy]) + +/* + * Per pipe/PLL DPIO regs + */ +#define _VLV_PLL_DW3_CH0 0x800c +#define DPIO_POST_DIV_SHIFT (28) /* 3 bits */ +#define DPIO_POST_DIV_DAC 0 +#define DPIO_POST_DIV_HDMIDP 1 /* DAC 225-400M rate */ +#define DPIO_POST_DIV_LVDS1 2 +#define DPIO_POST_DIV_LVDS2 3 +#define DPIO_K_SHIFT (24) /* 4 bits */ +#define DPIO_P1_SHIFT (21) /* 3 bits */ +#define DPIO_P2_SHIFT (16) /* 5 bits */ +#define DPIO_N_SHIFT (12) /* 4 bits */ +#define DPIO_ENABLE_CALIBRATION (1<<11) +#define DPIO_M1DIV_SHIFT (8) /* 3 bits */ +#define DPIO_M2DIV_MASK 0xff +#define _VLV_PLL_DW3_CH1 0x802c +#define VLV_PLL_DW3(ch) _PIPE(ch, _VLV_PLL_DW3_CH0, _VLV_PLL_DW3_CH1) + +#define _VLV_PLL_DW5_CH0 0x8014 +#define DPIO_REFSEL_OVERRIDE 27 +#define DPIO_PLL_MODESEL_SHIFT 24 /* 3 bits */ +#define DPIO_BIAS_CURRENT_CTL_SHIFT 21 /* 3 bits, always 0x7 */ +#define DPIO_PLL_REFCLK_SEL_SHIFT 16 /* 2 bits */ +#define DPIO_PLL_REFCLK_SEL_MASK 3 +#define DPIO_DRIVER_CTL_SHIFT 12 /* always set to 0x8 */ +#define DPIO_CLK_BIAS_CTL_SHIFT 8 /* always set to 0x5 */ +#define _VLV_PLL_DW5_CH1 0x8034 +#define VLV_PLL_DW5(ch) _PIPE(ch, _VLV_PLL_DW5_CH0, _VLV_PLL_DW5_CH1) + +#define _VLV_PLL_DW7_CH0 0x801c +#define _VLV_PLL_DW7_CH1 0x803c +#define VLV_PLL_DW7(ch) _PIPE(ch, _VLV_PLL_DW7_CH0, _VLV_PLL_DW7_CH1) + +#define _VLV_PLL_DW8_CH0 0x8040 +#define _VLV_PLL_DW8_CH1 0x8060 +#define VLV_PLL_DW8(ch) _PIPE(ch, _VLV_PLL_DW8_CH0, _VLV_PLL_DW8_CH1) + +#define VLV_PLL_DW9_BCAST 0xc044 +#define _VLV_PLL_DW9_CH0 0x8044 +#define _VLV_PLL_DW9_CH1 0x8064 +#define VLV_PLL_DW9(ch) _PIPE(ch, _VLV_PLL_DW9_CH0, _VLV_PLL_DW9_CH1) + +#define _VLV_PLL_DW10_CH0 0x8048 +#define _VLV_PLL_DW10_CH1 0x8068 +#define VLV_PLL_DW10(ch) _PIPE(ch, _VLV_PLL_DW10_CH0, _VLV_PLL_DW10_CH1) + +#define _VLV_PLL_DW11_CH0 0x804c +#define _VLV_PLL_DW11_CH1 0x806c +#define VLV_PLL_DW11(ch) _PIPE(ch, _VLV_PLL_DW11_CH0, _VLV_PLL_DW11_CH1) + +/* Spec for ref block start counts at DW10 */ +#define VLV_REF_DW13 0x80ac + +#define VLV_CMN_DW0 0x8100 + +/* + * Per DDI channel DPIO regs + */ + +#define _VLV_PCS_DW0_CH0 0x8200 +#define _VLV_PCS_DW0_CH1 0x8400 +#define DPIO_PCS_TX_LANE2_RESET (1<<16) +#define DPIO_PCS_TX_LANE1_RESET (1<<7) +#define VLV_PCS_DW0(ch) _PORT(ch, _VLV_PCS_DW0_CH0, _VLV_PCS_DW0_CH1) + +#define _VLV_PCS_DW1_CH0 0x8204 +#define _VLV_PCS_DW1_CH1 0x8404 +#define DPIO_PCS_CLK_CRI_RXEB_EIOS_EN (1<<22) +#define DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21) +#define DPIO_PCS_CLK_DATAWIDTH_SHIFT (6) +#define DPIO_PCS_CLK_SOFT_RESET (1<<5) +#define VLV_PCS_DW1(ch) _PORT(ch, _VLV_PCS_DW1_CH0, _VLV_PCS_DW1_CH1) + +#define _VLV_PCS_DW8_CH0 0x8220 +#define _VLV_PCS_DW8_CH1 0x8420 +#define VLV_PCS_DW8(ch) _PORT(ch, _VLV_PCS_DW8_CH0, _VLV_PCS_DW8_CH1) + +#define _VLV_PCS01_DW8_CH0 0x0220 +#define _VLV_PCS23_DW8_CH0 0x0420 +#define _VLV_PCS01_DW8_CH1 0x2620 +#define _VLV_PCS23_DW8_CH1 0x2820 +#define VLV_PCS01_DW8(port) _PORT(port, _VLV_PCS01_DW8_CH0, _VLV_PCS01_DW8_CH1) +#define VLV_PCS23_DW8(port) _PORT(port, _VLV_PCS23_DW8_CH0, _VLV_PCS23_DW8_CH1) + +#define _VLV_PCS_DW9_CH0 0x8224 +#define _VLV_PCS_DW9_CH1 0x8424 +#define VLV_PCS_DW9(ch) _PORT(ch, _VLV_PCS_DW9_CH0, _VLV_PCS_DW9_CH1) + +#define _VLV_PCS_DW11_CH0 0x822c +#define _VLV_PCS_DW11_CH1 0x842c +#define VLV_PCS_DW11(ch) _PORT(ch, _VLV_PCS_DW11_CH0, _VLV_PCS_DW11_CH1) + +#define _VLV_PCS_DW12_CH0 0x8230 +#define _VLV_PCS_DW12_CH1 0x8430 +#define VLV_PCS_DW12(ch) _PORT(ch, _VLV_PCS_DW12_CH0, _VLV_PCS_DW12_CH1) + +#define _VLV_PCS_DW14_CH0 0x8238 +#define _VLV_PCS_DW14_CH1 0x8438 +#define VLV_PCS_DW14(ch) _PORT(ch, _VLV_PCS_DW14_CH0, _VLV_PCS_DW14_CH1) + +#define _VLV_PCS_DW23_CH0 0x825c +#define _VLV_PCS_DW23_CH1 0x845c +#define VLV_PCS_DW23(ch) _PORT(ch, _VLV_PCS_DW23_CH0, _VLV_PCS_DW23_CH1) + +#define _VLV_TX_DW2_CH0 0x8288 +#define _VLV_TX_DW2_CH1 0x8488 +#define VLV_TX_DW2(ch) _PORT(ch, _VLV_TX_DW2_CH0, _VLV_TX_DW2_CH1) + +#define _VLV_TX_DW3_CH0 0x828c +#define _VLV_TX_DW3_CH1 0x848c +#define VLV_TX_DW3(ch) _PORT(ch, _VLV_TX_DW3_CH0, _VLV_TX_DW3_CH1) + +#define _VLV_TX_DW4_CH0 0x8290 +#define _VLV_TX_DW4_CH1 0x8490 +#define VLV_TX_DW4(ch) _PORT(ch, _VLV_TX_DW4_CH0, _VLV_TX_DW4_CH1) + +#define _VLV_TX3_DW4_CH0 0x690 +#define _VLV_TX3_DW4_CH1 0x2a90 +#define VLV_TX3_DW4(ch) _PORT(ch, _VLV_TX3_DW4_CH0, _VLV_TX3_DW4_CH1) + +#define _VLV_TX_DW5_CH0 0x8294 +#define _VLV_TX_DW5_CH1 0x8494 +#define DPIO_TX_OCALINIT_EN (1<<31) +#define VLV_TX_DW5(ch) _PORT(ch, _VLV_TX_DW5_CH0, _VLV_TX_DW5_CH1) + +#define _VLV_TX_DW11_CH0 0x82ac +#define _VLV_TX_DW11_CH1 0x84ac +#define VLV_TX_DW11(ch) _PORT(ch, _VLV_TX_DW11_CH0, _VLV_TX_DW11_CH1) + +#define _VLV_TX_DW14_CH0 0x82b8 +#define _VLV_TX_DW14_CH1 0x84b8 +#define VLV_TX_DW14(ch) _PORT(ch, _VLV_TX_DW14_CH0, _VLV_TX_DW14_CH1) + +/* + * Fence registers + */ +#define FENCE_REG_830_0 0x2000 +#define FENCE_REG_945_8 0x3000 +#define I830_FENCE_START_MASK 0x07f80000 +#define I830_FENCE_TILING_Y_SHIFT 12 +#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) +#define I830_FENCE_PITCH_SHIFT 4 +#define I830_FENCE_REG_VALID (1<<0) +#define I915_FENCE_MAX_PITCH_VAL 4 +#define I830_FENCE_MAX_PITCH_VAL 6 +#define I830_FENCE_MAX_SIZE_VAL (1<<8) + +#define I915_FENCE_START_MASK 0x0ff00000 +#define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8) + +#define FENCE_REG_965_0 0x03000 +#define I965_FENCE_PITCH_SHIFT 2 +#define I965_FENCE_TILING_Y_SHIFT 1 +#define I965_FENCE_REG_VALID (1<<0) +#define I965_FENCE_MAX_PITCH_VAL 0x0400 + +#define FENCE_REG_SANDYBRIDGE_0 0x100000 +#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32 +#define GEN7_FENCE_MAX_PITCH_VAL 0x0800 + +/* control register for cpu gtt access */ +#define TILECTL 0x101000 +#define TILECTL_SWZCTL (1 << 0) +#define TILECTL_TLB_PREFETCH_DIS (1 << 2) +#define TILECTL_BACKSNOOP_DIS (1 << 3) + +/* + * Instruction and interrupt control regs + */ +#define PGTBL_ER 0x02024 +#define RENDER_RING_BASE 0x02000 +#define BSD_RING_BASE 0x04000 +#define GEN6_BSD_RING_BASE 0x12000 +#define VEBOX_RING_BASE 0x1a000 +#define BLT_RING_BASE 0x22000 +#define RING_TAIL(base) ((base)+0x30) +#define RING_HEAD(base) ((base)+0x34) +#define RING_START(base) ((base)+0x38) +#define RING_CTL(base) ((base)+0x3c) +#define RING_SYNC_0(base) ((base)+0x40) +#define RING_SYNC_1(base) ((base)+0x44) +#define RING_SYNC_2(base) ((base)+0x48) +#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE)) +#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE)) +#define GEN6_RVESYNC (RING_SYNC_2(RENDER_RING_BASE)) +#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE)) +#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE)) +#define GEN6_VVESYNC (RING_SYNC_2(GEN6_BSD_RING_BASE)) +#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE)) +#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE)) +#define GEN6_BVESYNC (RING_SYNC_2(BLT_RING_BASE)) +#define GEN6_VEBSYNC (RING_SYNC_0(VEBOX_RING_BASE)) +#define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE)) +#define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE)) +#define GEN6_NOSYNC 0 +#define RING_MAX_IDLE(base) ((base)+0x54) +#define RING_HWS_PGA(base) ((base)+0x80) +#define RING_HWS_PGA_GEN6(base) ((base)+0x2080) +#define ARB_MODE 0x04030 +#define ARB_MODE_SWIZZLE_SNB (1<<4) +#define ARB_MODE_SWIZZLE_IVB (1<<5) +#define GAMTARBMODE 0x04a08 +#define ARB_MODE_BWGTLB_DISABLE (1<<9) +#define ARB_MODE_SWIZZLE_BDW (1<<1) +#define RENDER_HWS_PGA_GEN7 (0x04080) +#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id) +#define RING_FAULT_GTTSEL_MASK (1<<11) +#define RING_FAULT_SRCID(x) ((x >> 3) & 0xff) +#define RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3) +#define RING_FAULT_VALID (1<<0) +#define DONE_REG 0x40b0 +#define GEN8_PRIVATE_PAT 0x40e0 +#define BSD_HWS_PGA_GEN7 (0x04180) +#define BLT_HWS_PGA_GEN7 (0x04280) +#define VEBOX_HWS_PGA_GEN7 (0x04380) +#define RING_ACTHD(base) ((base)+0x74) +#define RING_NOPID(base) ((base)+0x94) +#define RING_IMR(base) ((base)+0xa8) +#define RING_TIMESTAMP(base) ((base)+0x358) +#define TAIL_ADDR 0x001FFFF8 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_NR_PAGES 0x001FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 +#define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */ +#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ +#define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */ +#if 0 +#define PRB0_TAIL 0x02030 +#define PRB0_HEAD 0x02034 +#define PRB0_START 0x02038 +#define PRB0_CTL 0x0203c +#define PRB1_TAIL 0x02040 /* 915+ only */ +#define PRB1_HEAD 0x02044 /* 915+ only */ +#define PRB1_START 0x02048 /* 915+ only */ +#define PRB1_CTL 0x0204c /* 915+ only */ +#endif +#define IPEIR_I965 0x02064 +#define IPEHR_I965 0x02068 +#define INSTDONE_I965 0x0206c +#define GEN7_INSTDONE_1 0x0206c +#define GEN7_SC_INSTDONE 0x07100 +#define GEN7_SAMPLER_INSTDONE 0x0e160 +#define GEN7_ROW_INSTDONE 0x0e164 +#define I915_NUM_INSTDONE_REG 4 +#define RING_IPEIR(base) ((base)+0x64) +#define RING_IPEHR(base) ((base)+0x68) +#define RING_INSTDONE(base) ((base)+0x6c) +#define RING_INSTPS(base) ((base)+0x70) +#define RING_DMA_FADD(base) ((base)+0x78) +#define RING_INSTPM(base) ((base)+0xc0) +#define INSTPS 0x02070 /* 965+ only */ +#define INSTDONE1 0x0207c /* 965+ only */ +#define ACTHD_I965 0x02074 +#define HWS_PGA 0x02080 +#define HWS_ADDRESS_MASK 0xfffff000 +#define HWS_START_ADDRESS_SHIFT 4 +#define PWRCTXA 0x2088 /* 965GM+ only */ +#define PWRCTX_EN (1<<0) +#define IPEIR 0x02088 +#define IPEHR 0x0208c +#define INSTDONE 0x02090 +#define NOPID 0x02094 +#define HWSTAM 0x02098 +#define DMA_FADD_I8XX 0x020d0 +#define RING_BBSTATE(base) ((base)+0x110) +#define RING_BBADDR(base) ((base)+0x140) +#define RING_BBADDR_UDW(base) ((base)+0x168) /* gen8+ */ + +#define ERROR_GEN6 0x040a0 +#define GEN7_ERR_INT 0x44040 +#define ERR_INT_POISON (1<<31) +#define ERR_INT_MMIO_UNCLAIMED (1<<13) +#define ERR_INT_PIPE_CRC_DONE_C (1<<8) +#define ERR_INT_FIFO_UNDERRUN_C (1<<6) +#define ERR_INT_PIPE_CRC_DONE_B (1<<5) +#define ERR_INT_FIFO_UNDERRUN_B (1<<3) +#define ERR_INT_PIPE_CRC_DONE_A (1<<2) +#define ERR_INT_PIPE_CRC_DONE(pipe) (1<<(2 + pipe*3)) +#define ERR_INT_FIFO_UNDERRUN_A (1<<0) +#define ERR_INT_FIFO_UNDERRUN(pipe) (1<<(pipe*3)) + +#define FPGA_DBG 0x42300 +#define FPGA_DBG_RM_NOCLAIM (1<<31) + +#define DERRMR 0x44050 +/* Note that HBLANK events are reserved on bdw+ */ +#define DERRMR_PIPEA_SCANLINE (1<<0) +#define DERRMR_PIPEA_PRI_FLIP_DONE (1<<1) +#define DERRMR_PIPEA_SPR_FLIP_DONE (1<<2) +#define DERRMR_PIPEA_VBLANK (1<<3) +#define DERRMR_PIPEA_HBLANK (1<<5) +#define DERRMR_PIPEB_SCANLINE (1<<8) +#define DERRMR_PIPEB_PRI_FLIP_DONE (1<<9) +#define DERRMR_PIPEB_SPR_FLIP_DONE (1<<10) +#define DERRMR_PIPEB_VBLANK (1<<11) +#define DERRMR_PIPEB_HBLANK (1<<13) +/* Note that PIPEC is not a simple translation of PIPEA/PIPEB */ +#define DERRMR_PIPEC_SCANLINE (1<<14) +#define DERRMR_PIPEC_PRI_FLIP_DONE (1<<15) +#define DERRMR_PIPEC_SPR_FLIP_DONE (1<<20) +#define DERRMR_PIPEC_VBLANK (1<<21) +#define DERRMR_PIPEC_HBLANK (1<<22) + + +/* GM45+ chicken bits -- debug workaround bits that may be required + * for various sorts of correct behavior. The top 16 bits of each are + * the enables for writing to the corresponding low bit. + */ +#define _3D_CHICKEN 0x02084 +#define _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB (1 << 10) +#define _3D_CHICKEN2 0x0208c +/* Disables pipelining of read flushes past the SF-WIZ interface. + * Required on all Ironlake steppings according to the B-Spec, but the + * particular danger of not doing so is not specified. + */ +# define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) +#define _3D_CHICKEN3 0x02090 +#define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10) +#define _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL (1 << 5) +#define _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x) ((x)<<1) + +#define MI_MODE 0x0209c +# define VS_TIMER_DISPATCH (1 << 6) +# define MI_FLUSH_ENABLE (1 << 12) +# define ASYNC_FLIP_PERF_DISABLE (1 << 14) + +#define GEN6_GT_MODE 0x20d0 +#define GEN6_GT_MODE_HI (1 << 9) +#define GEN6_TD_FOUR_ROW_DISPATCH_DISABLE (1 << 5) + +#define GFX_MODE 0x02520 +#define GFX_MODE_GEN7 0x0229c +#define RING_MODE_GEN7(ring) ((ring)->mmio_base+0x29c) +#define GFX_RUN_LIST_ENABLE (1<<15) +#define GFX_TLB_INVALIDATE_ALWAYS (1<<13) +#define GFX_SURFACE_FAULT_ENABLE (1<<12) +#define GFX_REPLAY_MODE (1<<11) +#define GFX_PSMI_GRANULARITY (1<<10) +#define GFX_PPGTT_ENABLE (1<<9) + +#define VLV_DISPLAY_BASE 0x180000 + +#define SCPD0 0x0209c /* 915+ only */ +#define IER 0x020a0 +#define IIR 0x020a4 +#define IMR 0x020a8 +#define ISR 0x020ac +#define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) +#define GCFG_DIS (1<<8) +#define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084) +#define VLV_IER (VLV_DISPLAY_BASE + 0x20a0) +#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) +#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8) +#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac) +#define VLV_PCBR (VLV_DISPLAY_BASE + 0x2120) +#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ +#define EIR 0x020b0 +#define EMR 0x020b4 +#define ESR 0x020b8 +#define GM45_ERROR_PAGE_TABLE (1<<5) +#define GM45_ERROR_MEM_PRIV (1<<4) +#define I915_ERROR_PAGE_TABLE (1<<4) +#define GM45_ERROR_CP_PRIV (1<<3) +#define I915_ERROR_MEMORY_REFRESH (1<<1) +#define I915_ERROR_INSTRUCTION (1<<0) +#define INSTPM 0x020c0 +#define INSTPM_SELF_EN (1<<12) /* 915GM only */ +#define INSTPM_AGPBUSY_DIS (1<<11) /* gen3: when disabled, pending interrupts + will not assert AGPBUSY# and will only + be delivered when out of C3. */ +#define INSTPM_FORCE_ORDERING (1<<7) /* GEN6+ */ +#define INSTPM_TLB_INVALIDATE (1<<9) +#define INSTPM_SYNC_FLUSH (1<<5) +#define ACTHD 0x020c8 +#define FW_BLC 0x020d8 +#define FW_BLC2 0x020dc +#define FW_BLC_SELF 0x020e0 /* 915+ only */ +#define FW_BLC_SELF_EN_MASK (1<<31) +#define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */ +#define FW_BLC_SELF_EN (1<<15) /* 945 only */ +#define MM_BURST_LENGTH 0x00700000 +#define MM_FIFO_WATERMARK 0x0001F000 +#define LM_BURST_LENGTH 0x00000700 +#define LM_FIFO_WATERMARK 0x0000001F +#define MI_ARB_STATE 0x020e4 /* 915+ only */ + +/* Make render/texture TLB fetches lower priorty than associated data + * fetches. This is not turned on by default + */ +#define MI_ARB_RENDER_TLB_LOW_PRIORITY (1 << 15) + +/* Isoch request wait on GTT enable (Display A/B/C streams). + * Make isoch requests stall on the TLB update. May cause + * display underruns (test mode only) + */ +#define MI_ARB_ISOCH_WAIT_GTT (1 << 14) + +/* Block grant count for isoch requests when block count is + * set to a finite value. + */ +#define MI_ARB_BLOCK_GRANT_MASK (3 << 12) +#define MI_ARB_BLOCK_GRANT_8 (0 << 12) /* for 3 display planes */ +#define MI_ARB_BLOCK_GRANT_4 (1 << 12) /* for 2 display planes */ +#define MI_ARB_BLOCK_GRANT_2 (2 << 12) /* for 1 display plane */ +#define MI_ARB_BLOCK_GRANT_0 (3 << 12) /* don't use */ + +/* Enable render writes to complete in C2/C3/C4 power states. + * If this isn't enabled, render writes are prevented in low + * power states. That seems bad to me. + */ +#define MI_ARB_C3_LP_WRITE_ENABLE (1 << 11) + +/* This acknowledges an async flip immediately instead + * of waiting for 2TLB fetches. + */ +#define MI_ARB_ASYNC_FLIP_ACK_IMMEDIATE (1 << 10) + +/* Enables non-sequential data reads through arbiter + */ +#define MI_ARB_DUAL_DATA_PHASE_DISABLE (1 << 9) + +/* Disable FSB snooping of cacheable write cycles from binner/render + * command stream + */ +#define MI_ARB_CACHE_SNOOP_DISABLE (1 << 8) + +/* Arbiter time slice for non-isoch streams */ +#define MI_ARB_TIME_SLICE_MASK (7 << 5) +#define MI_ARB_TIME_SLICE_1 (0 << 5) +#define MI_ARB_TIME_SLICE_2 (1 << 5) +#define MI_ARB_TIME_SLICE_4 (2 << 5) +#define MI_ARB_TIME_SLICE_6 (3 << 5) +#define MI_ARB_TIME_SLICE_8 (4 << 5) +#define MI_ARB_TIME_SLICE_10 (5 << 5) +#define MI_ARB_TIME_SLICE_14 (6 << 5) +#define MI_ARB_TIME_SLICE_16 (7 << 5) + +/* Low priority grace period page size */ +#define MI_ARB_LOW_PRIORITY_GRACE_4KB (0 << 4) /* default */ +#define MI_ARB_LOW_PRIORITY_GRACE_8KB (1 << 4) + +/* Disable display A/B trickle feed */ +#define MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE (1 << 2) + +/* Set display plane priority */ +#define MI_ARB_DISPLAY_PRIORITY_A_B (0 << 0) /* display A > display B */ +#define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */ + +#define CACHE_MODE_0 0x02120 /* 915+ only */ +#define CM0_PIPELINED_RENDER_FLUSH_DISABLE (1<<8) +#define CM0_IZ_OPT_DISABLE (1<<6) +#define CM0_ZR_OPT_DISABLE (1<<5) +#define CM0_STC_EVICT_DISABLE_LRA_SNB (1<<5) +#define CM0_DEPTH_EVICT_DISABLE (1<<4) +#define CM0_COLOR_EVICT_DISABLE (1<<3) +#define CM0_DEPTH_WRITE_DISABLE (1<<1) +#define CM0_RC_OP_FLUSH_DISABLE (1<<0) +#define GFX_FLSH_CNTL 0x02170 /* 915+ only */ +#define GFX_FLSH_CNTL_GEN6 0x101008 +#define GFX_FLSH_CNTL_EN (1<<0) +#define ECOSKPD 0x021d0 +#define ECO_GATING_CX_ONLY (1<<3) +#define ECO_FLIP_DONE (1<<0) + +#define CACHE_MODE_1 0x7004 /* IVB+ */ +#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6) + +#define GEN6_BLITTER_ECOSKPD 0x221d0 +#define GEN6_BLITTER_LOCK_SHIFT 16 +#define GEN6_BLITTER_FBC_NOTIFY (1<<3) + +#define GEN6_RC_SLEEP_PSMI_CONTROL 0x2050 +#define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12) + +#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 +#define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0) +#define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2) +#define GEN6_BSD_SLEEP_INDICATOR (1 << 3) +#define GEN6_BSD_GO_INDICATOR (1 << 4) + +/* On modern GEN architectures interrupt control consists of two sets + * of registers. The first set pertains to the ring generating the + * interrupt. The second control is for the functional block generating the + * interrupt. These are PM, GT, DE, etc. + * + * Luckily *knocks on wood* all the ring interrupt bits match up with the + * GT interrupt bits, so we don't need to duplicate the defines. + * + * These defines should cover us well from SNB->HSW with minor exceptions + * it can also work on ILK. + */ +#define GT_BLT_FLUSHDW_NOTIFY_INTERRUPT (1 << 26) +#define GT_BLT_CS_ERROR_INTERRUPT (1 << 25) +#define GT_BLT_USER_INTERRUPT (1 << 22) +#define GT_BSD_CS_ERROR_INTERRUPT (1 << 15) +#define GT_BSD_USER_INTERRUPT (1 << 12) +#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 (1 << 11) /* hsw+; rsvd on snb, ivb, vlv */ +#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT (1 << 5) /* !snb */ +#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT (1 << 4) +#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT (1 << 3) +#define GT_RENDER_SYNC_STATUS_INTERRUPT (1 << 2) +#define GT_RENDER_DEBUG_INTERRUPT (1 << 1) +#define GT_RENDER_USER_INTERRUPT (1 << 0) + +#define PM_VEBOX_CS_ERROR_INTERRUPT (1 << 12) /* hsw+ */ +#define PM_VEBOX_USER_INTERRUPT (1 << 10) /* hsw+ */ + +#define GT_PARITY_ERROR(dev) \ + (GT_RENDER_L3_PARITY_ERROR_INTERRUPT | \ + (IS_HASWELL(dev) ? GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 : 0)) + +/* These are all the "old" interrupts */ +#define ILK_BSD_USER_INTERRUPT (1<<5) +#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) +#define I915_DISPLAY_PORT_INTERRUPT (1<<17) +#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) +#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */ +#define I915_HWB_OOM_INTERRUPT (1<<13) +#define I915_SYNC_STATUS_INTERRUPT (1<<12) +#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) +#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) +#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) +#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) +#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) +#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) +#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) +#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) +#define I915_DEBUG_INTERRUPT (1<<2) +#define I915_USER_INTERRUPT (1<<1) +#define I915_ASLE_INTERRUPT (1<<0) +#define I915_BSD_USER_INTERRUPT (1 << 25) + +#define GEN6_BSD_RNCID 0x12198 + +#define GEN7_FF_THREAD_MODE 0x20a0 +#define GEN7_FF_SCHED_MASK 0x0077070 +#define GEN8_FF_DS_REF_CNT_FFME (1 << 19) +#define GEN7_FF_TS_SCHED_HS1 (0x5<<16) +#define GEN7_FF_TS_SCHED_HS0 (0x3<<16) +#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) +#define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_VS_REF_CNT_FFME (1 << 15) +#define GEN7_FF_VS_SCHED_HS1 (0x5<<12) +#define GEN7_FF_VS_SCHED_HS0 (0x3<<12) +#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ +#define GEN7_FF_VS_SCHED_HW (0x0<<12) +#define GEN7_FF_DS_SCHED_HS1 (0x5<<4) +#define GEN7_FF_DS_SCHED_HS0 (0x3<<4) +#define GEN7_FF_DS_SCHED_LOAD_BALANCE (0x1<<4) /* Default */ +#define GEN7_FF_DS_SCHED_HW (0x0<<4) + +/* + * Framebuffer compression (915+ only) + */ + +#define FBC_CFB_BASE 0x03200 /* 4k page aligned */ +#define FBC_LL_BASE 0x03204 /* 4k page aligned */ +#define FBC_CONTROL 0x03208 +#define FBC_CTL_EN (1<<31) +#define FBC_CTL_PERIODIC (1<<30) +#define FBC_CTL_INTERVAL_SHIFT (16) +#define FBC_CTL_UNCOMPRESSIBLE (1<<14) +#define FBC_CTL_C3_IDLE (1<<13) +#define FBC_CTL_STRIDE_SHIFT (5) +#define FBC_CTL_FENCENO_SHIFT (0) +#define FBC_COMMAND 0x0320c +#define FBC_CMD_COMPRESS (1<<0) +#define FBC_STATUS 0x03210 +#define FBC_STAT_COMPRESSING (1<<31) +#define FBC_STAT_COMPRESSED (1<<30) +#define FBC_STAT_MODIFIED (1<<29) +#define FBC_STAT_CURRENT_LINE_SHIFT (0) +#define FBC_CONTROL2 0x03214 +#define FBC_CTL_FENCE_DBL (0<<4) +#define FBC_CTL_IDLE_IMM (0<<2) +#define FBC_CTL_IDLE_FULL (1<<2) +#define FBC_CTL_IDLE_LINE (2<<2) +#define FBC_CTL_IDLE_DEBUG (3<<2) +#define FBC_CTL_CPU_FENCE (1<<1) +#define FBC_CTL_PLANEA (0<<0) +#define FBC_CTL_PLANEB (1<<0) +#define FBC_FENCE_OFF 0x0321b +#define FBC_TAG 0x03300 + +#define FBC_LL_SIZE (1536) + +/* Framebuffer compression for GM45+ */ +#define DPFC_CB_BASE 0x3200 +#define DPFC_CONTROL 0x3208 +#define DPFC_CTL_EN (1<<31) +#define DPFC_CTL_PLANEA (0<<30) +#define DPFC_CTL_PLANEB (1<<30) +#define IVB_DPFC_CTL_PLANE_SHIFT (29) +#define DPFC_CTL_FENCE_EN (1<<29) +#define IVB_DPFC_CTL_FENCE_EN (1<<28) +#define DPFC_CTL_PERSISTENT_MODE (1<<25) +#define DPFC_SR_EN (1<<10) +#define DPFC_CTL_LIMIT_1X (0<<6) +#define DPFC_CTL_LIMIT_2X (1<<6) +#define DPFC_CTL_LIMIT_4X (2<<6) +#define DPFC_RECOMP_CTL 0x320c +#define DPFC_RECOMP_STALL_EN (1<<27) +#define DPFC_RECOMP_STALL_WM_SHIFT (16) +#define DPFC_RECOMP_STALL_WM_MASK (0x07ff0000) +#define DPFC_RECOMP_TIMER_COUNT_SHIFT (0) +#define DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f) +#define DPFC_STATUS 0x3210 +#define DPFC_INVAL_SEG_SHIFT (16) +#define DPFC_INVAL_SEG_MASK (0x07ff0000) +#define DPFC_COMP_SEG_SHIFT (0) +#define DPFC_COMP_SEG_MASK (0x000003ff) +#define DPFC_STATUS2 0x3214 +#define DPFC_FENCE_YOFF 0x3218 +#define DPFC_CHICKEN 0x3224 +#define DPFC_HT_MODIFY (1<<31) + +/* Framebuffer compression for Ironlake */ +#define ILK_DPFC_CB_BASE 0x43200 +#define ILK_DPFC_CONTROL 0x43208 +/* The bit 28-8 is reserved */ +#define DPFC_RESERVED (0x1FFFFF00) +#define ILK_DPFC_RECOMP_CTL 0x4320c +#define ILK_DPFC_STATUS 0x43210 +#define ILK_DPFC_FENCE_YOFF 0x43218 +#define ILK_DPFC_CHICKEN 0x43224 +#define ILK_FBC_RT_BASE 0x2128 +#define ILK_FBC_RT_VALID (1<<0) +#define SNB_FBC_FRONT_BUFFER (1<<1) + +#define ILK_DISPLAY_CHICKEN1 0x42000 +#define ILK_FBCQ_DIS (1<<22) +#define ILK_PABSTRETCH_DIS (1<<21) + + +/* + * Framebuffer compression for Sandybridge + * + * The following two registers are of type GTTMMADR + */ +#define SNB_DPFC_CTL_SA 0x100100 +#define SNB_CPU_FENCE_ENABLE (1<<29) +#define DPFC_CPU_FENCE_OFFSET 0x100104 + +/* Framebuffer compression for Ivybridge */ +#define IVB_FBC_RT_BASE 0x7020 + +#define IPS_CTL 0x43408 +#define IPS_ENABLE (1 << 31) + +#define MSG_FBC_REND_STATE 0x50380 +#define FBC_REND_NUKE (1<<2) +#define FBC_REND_CACHE_CLEAN (1<<1) + +#define _HSW_PIPE_SLICE_CHICKEN_1_A 0x420B0 +#define _HSW_PIPE_SLICE_CHICKEN_1_B 0x420B4 +#define HSW_BYPASS_FBC_QUEUE (1<<22) +#define HSW_PIPE_SLICE_CHICKEN_1(pipe) _PIPE(pipe, + \ + _HSW_PIPE_SLICE_CHICKEN_1_A, + \ + _HSW_PIPE_SLICE_CHICKEN_1_B) + +/* + * GPIO regs + */ +#define GPIOA 0x5010 +#define GPIOB 0x5014 +#define GPIOC 0x5018 +#define GPIOD 0x501c +#define GPIOE 0x5020 +#define GPIOF 0x5024 +#define GPIOG 0x5028 +#define GPIOH 0x502c +# define GPIO_CLOCK_DIR_MASK (1 << 0) +# define GPIO_CLOCK_DIR_IN (0 << 1) +# define GPIO_CLOCK_DIR_OUT (1 << 1) +# define GPIO_CLOCK_VAL_MASK (1 << 2) +# define GPIO_CLOCK_VAL_OUT (1 << 3) +# define GPIO_CLOCK_VAL_IN (1 << 4) +# define GPIO_CLOCK_PULLUP_DISABLE (1 << 5) +# define GPIO_DATA_DIR_MASK (1 << 8) +# define GPIO_DATA_DIR_IN (0 << 9) +# define GPIO_DATA_DIR_OUT (1 << 9) +# define GPIO_DATA_VAL_MASK (1 << 10) +# define GPIO_DATA_VAL_OUT (1 << 11) +# define GPIO_DATA_VAL_IN (1 << 12) +# define GPIO_DATA_PULLUP_DISABLE (1 << 13) + +#define GMBUS0 0x5100 /* clock/port select */ +#define GMBUS_RATE_100KHZ (0<<8) +#define GMBUS_RATE_50KHZ (1<<8) +#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */ +#define GMBUS_RATE_1MHZ (3<<8) /* reserved on Pineview */ +#define GMBUS_HOLD_EXT (1<<7) /* 300ns hold time, rsvd on Pineview */ +#define GMBUS_PORT_DISABLED 0 +#define GMBUS_PORT_SSC 1 +#define GMBUS_PORT_VGADDC 2 +#define GMBUS_PORT_PANEL 3 +#define GMBUS_PORT_DPC 4 /* HDMIC */ +#define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */ +#define GMBUS_PORT_DPD 6 /* HDMID */ +#define GMBUS_PORT_RESERVED 7 /* 7 reserved */ +#define GMBUS_NUM_PORTS (GMBUS_PORT_DPD - GMBUS_PORT_SSC + 1) +#define GMBUS1 0x5104 /* command/status */ +#define GMBUS_SW_CLR_INT (1<<31) +#define GMBUS_SW_RDY (1<<30) +#define GMBUS_ENT (1<<29) /* enable timeout */ +#define GMBUS_CYCLE_NONE (0<<25) +#define GMBUS_CYCLE_WAIT (1<<25) +#define GMBUS_CYCLE_INDEX (2<<25) +#define GMBUS_CYCLE_STOP (4<<25) +#define GMBUS_BYTE_COUNT_SHIFT 16 +#define GMBUS_SLAVE_INDEX_SHIFT 8 +#define GMBUS_SLAVE_ADDR_SHIFT 1 +#define GMBUS_SLAVE_READ (1<<0) +#define GMBUS_SLAVE_WRITE (0<<0) +#define GMBUS2 0x5108 /* status */ +#define GMBUS_INUSE (1<<15) +#define GMBUS_HW_WAIT_PHASE (1<<14) +#define GMBUS_STALL_TIMEOUT (1<<13) +#define GMBUS_INT (1<<12) +#define GMBUS_HW_RDY (1<<11) +#define GMBUS_SATOER (1<<10) +#define GMBUS_ACTIVE (1<<9) +#define GMBUS3 0x510c /* data buffer bytes 3-0 */ +#define GMBUS4 0x5110 /* interrupt mask (Pineview+) */ +#define GMBUS_SLAVE_TIMEOUT_EN (1<<4) +#define GMBUS_NAK_EN (1<<3) +#define GMBUS_IDLE_EN (1<<2) +#define GMBUS_HW_WAIT_EN (1<<1) +#define GMBUS_HW_RDY_EN (1<<0) +#define GMBUS5 0x5120 /* byte index */ +#define GMBUS_2BYTE_INDEX_EN (1<<31) + +/* + * Clock control & power management + */ + +#define VGA0 0x6000 +#define VGA1 0x6004 +#define VGA_PD 0x6010 +#define VGA0_PD_P2_DIV_4 (1 << 7) +#define VGA0_PD_P1_DIV_2 (1 << 5) +#define VGA0_PD_P1_SHIFT 0 +#define VGA0_PD_P1_MASK (0x1f << 0) +#define VGA1_PD_P2_DIV_4 (1 << 15) +#define VGA1_PD_P1_DIV_2 (1 << 13) +#define VGA1_PD_P1_SHIFT 8 +#define VGA1_PD_P1_MASK (0x1f << 8) +#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014) +#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018) +#define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) +#define DPLL_VCO_ENABLE (1 << 31) +#define DPLL_SDVO_HIGH_SPEED (1 << 30) +#define DPLL_DVO_2X_MODE (1 << 30) +#define DPLL_EXT_BUFFER_ENABLE_VLV (1 << 30) +#define DPLL_SYNCLOCK_ENABLE (1 << 29) +#define DPLL_REFA_CLK_ENABLE_VLV (1 << 29) +#define DPLL_VGA_MODE_DIS (1 << 28) +#define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +#define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +#define DPLL_MODE_MASK (3 << 26) +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +#define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +#define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ +#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ +#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ +#define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ +#define DPLL_LOCK_VLV (1<<15) +#define DPLL_INTEGRATED_CRI_CLK_VLV (1<<14) +#define DPLL_INTEGRATED_CLOCK_VLV (1<<13) +#define DPLL_PORTC_READY_MASK (0xf << 4) +#define DPLL_PORTB_READY_MASK (0xf) + +#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +/* + * The i830 generation, in LVDS mode, defines P1 as the bit number set within + * this field (only one bit may be set). + */ +#define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +#define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +#define DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW 15 +/* i830, required in DVO non-gang */ +#define PLL_P2_DIVIDE_BY_4 (1 << 23) +#define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +#define PLL_REF_INPUT_DREFCLK (0 << 13) +#define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +#define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ +#define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +#define PLL_REF_INPUT_MASK (3 << 13) +#define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* Ironlake */ +# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT 9 +# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK (7 << 9) +# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x)-1) << 9) +# define DPLL_FPA1_P1_POST_DIV_SHIFT 0 +# define DPLL_FPA1_P1_POST_DIV_MASK 0xff + +/* + * Parallel to Serial Load Pulse phase selection. + * Selects the phase for the 10X DPLL clock for the PCIe + * digital display port. The range is 4 to 13; 10 or more + * is just a flip delay. The default is 6 + */ +#define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +#define DISPLAY_RATE_SELECT_FPA1 (1 << 8) +/* + * SDVO multiplier for 945G/GM. Not used on 965. + */ +#define SDVO_MULTIPLIER_MASK 0x000000ff +#define SDVO_MULTIPLIER_SHIFT_HIRES 4 +#define SDVO_MULTIPLIER_SHIFT_VGA 0 +#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */ +/* + * UDI pixel divider, controlling how many pixels are stuffed into a packet. + * + * Value is pixels minus 1. Must be set to 1 pixel for SDVO. + */ +#define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +#define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +#define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +#define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/* + * SDVO/UDI pixel multiplier. + * + * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus + * clock rate is 10 times the DPLL clock. At low resolution/refresh rate + * modes, the bus rate would be below the limits, so SDVO allows for stuffing + * dummy bytes in the datastream at an increased clock rate, with both sides of + * the link knowing how many bytes are fill. + * + * So, for a mode with a dotclock of 65Mhz, we would want to double the clock + * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be + * set to 130Mhz, and the SDVO multiplier set to 2x in this register and + * through an SDVO command. + * + * This register field has values of multiplication factor minus 1, with + * a maximum multiplier of 5 for SDVO. + */ +#define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +#define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/* + * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. + * This best be set to the default value (3) or the CRT won't work. No, + * I don't entirely understand what this does... + */ +#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */ +#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD) + +#define _FPA0 0x06040 +#define _FPA1 0x06044 +#define _FPB0 0x06048 +#define _FPB1 0x0604c +#define FP0(pipe) _PIPE(pipe, _FPA0, _FPB0) +#define FP1(pipe) _PIPE(pipe, _FPA1, _FPB1) +#define FP_N_DIV_MASK 0x003f0000 +#define FP_N_PINEVIEW_DIV_MASK 0x00ff0000 +#define FP_N_DIV_SHIFT 16 +#define FP_M1_DIV_MASK 0x00003f00 +#define FP_M1_DIV_SHIFT 8 +#define FP_M2_DIV_MASK 0x0000003f +#define FP_M2_PINEVIEW_DIV_MASK 0x000000ff +#define FP_M2_DIV_SHIFT 0 +#define DPLL_TEST 0x606c +#define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +#define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +#define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +#define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +#define DPLLB_TEST_N_BYPASS (1 << 19) +#define DPLLB_TEST_M_BYPASS (1 << 18) +#define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +#define DPLLA_TEST_N_BYPASS (1 << 3) +#define DPLLA_TEST_M_BYPASS (1 << 2) +#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) +#define D_STATE 0x6104 +#define DSTATE_GFX_RESET_I830 (1<<6) +#define DSTATE_PLL_D3_OFF (1<<3) +#define DSTATE_GFX_CLOCK_GATING (1<<1) +#define DSTATE_DOT_CLOCK_GATING (1<<0) +#define DSPCLK_GATE_D (dev_priv->info->display_mmio_offset + 0x6200) +# define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */ +# define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */ +# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */ +# define VRDUNIT_CLOCK_GATE_DISABLE (1 << 27) /* 965 */ +# define AUDUNIT_CLOCK_GATE_DISABLE (1 << 26) /* 965 */ +# define DPUNIT_A_CLOCK_GATE_DISABLE (1 << 25) /* 965 */ +# define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24) /* 965 */ +# define TVRUNIT_CLOCK_GATE_DISABLE (1 << 23) /* 915-945 */ +# define TVCUNIT_CLOCK_GATE_DISABLE (1 << 22) /* 915-945 */ +# define TVFUNIT_CLOCK_GATE_DISABLE (1 << 21) /* 915-945 */ +# define TVEUNIT_CLOCK_GATE_DISABLE (1 << 20) /* 915-945 */ +# define DVSUNIT_CLOCK_GATE_DISABLE (1 << 19) /* 915-945 */ +# define DSSUNIT_CLOCK_GATE_DISABLE (1 << 18) /* 915-945 */ +# define DDBUNIT_CLOCK_GATE_DISABLE (1 << 17) /* 915-945 */ +# define DPRUNIT_CLOCK_GATE_DISABLE (1 << 16) /* 915-945 */ +# define DPFUNIT_CLOCK_GATE_DISABLE (1 << 15) /* 915-945 */ +# define DPBMUNIT_CLOCK_GATE_DISABLE (1 << 14) /* 915-945 */ +# define DPLSUNIT_CLOCK_GATE_DISABLE (1 << 13) /* 915-945 */ +# define DPLUNIT_CLOCK_GATE_DISABLE (1 << 12) /* 915-945 */ +# define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11) +# define DPBUNIT_CLOCK_GATE_DISABLE (1 << 10) +# define DCUNIT_CLOCK_GATE_DISABLE (1 << 9) +# define DPUNIT_CLOCK_GATE_DISABLE (1 << 8) +# define VRUNIT_CLOCK_GATE_DISABLE (1 << 7) /* 915+: reserved */ +# define OVHUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 830-865 */ +# define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 915-945 */ +# define OVFUNIT_CLOCK_GATE_DISABLE (1 << 5) +# define OVBUNIT_CLOCK_GATE_DISABLE (1 << 4) +/** + * This bit must be set on the 830 to prevent hangs when turning off the + * overlay scaler. + */ +# define OVRUNIT_CLOCK_GATE_DISABLE (1 << 3) +# define OVCUNIT_CLOCK_GATE_DISABLE (1 << 2) +# define OVUUNIT_CLOCK_GATE_DISABLE (1 << 1) +# define ZVUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 830 */ +# define OVLUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 845,865 */ + +#define RENCLK_GATE_D1 0x6204 +# define BLITTER_CLOCK_GATE_DISABLE (1 << 13) /* 945GM only */ +# define MPEG_CLOCK_GATE_DISABLE (1 << 12) /* 945GM only */ +# define PC_FE_CLOCK_GATE_DISABLE (1 << 11) +# define PC_BE_CLOCK_GATE_DISABLE (1 << 10) +# define WINDOWER_CLOCK_GATE_DISABLE (1 << 9) +# define INTERPOLATOR_CLOCK_GATE_DISABLE (1 << 8) +# define COLOR_CALCULATOR_CLOCK_GATE_DISABLE (1 << 7) +# define MOTION_COMP_CLOCK_GATE_DISABLE (1 << 6) +# define MAG_CLOCK_GATE_DISABLE (1 << 5) +/** This bit must be unset on 855,865 */ +# define MECI_CLOCK_GATE_DISABLE (1 << 4) +# define DCMP_CLOCK_GATE_DISABLE (1 << 3) +# define MEC_CLOCK_GATE_DISABLE (1 << 2) +# define MECO_CLOCK_GATE_DISABLE (1 << 1) +/** This bit must be set on 855,865. */ +# define SV_CLOCK_GATE_DISABLE (1 << 0) +# define I915_MPEG_CLOCK_GATE_DISABLE (1 << 16) +# define I915_VLD_IP_PR_CLOCK_GATE_DISABLE (1 << 15) +# define I915_MOTION_COMP_CLOCK_GATE_DISABLE (1 << 14) +# define I915_BD_BF_CLOCK_GATE_DISABLE (1 << 13) +# define I915_SF_SE_CLOCK_GATE_DISABLE (1 << 12) +# define I915_WM_CLOCK_GATE_DISABLE (1 << 11) +# define I915_IZ_CLOCK_GATE_DISABLE (1 << 10) +# define I915_PI_CLOCK_GATE_DISABLE (1 << 9) +# define I915_DI_CLOCK_GATE_DISABLE (1 << 8) +# define I915_SH_SV_CLOCK_GATE_DISABLE (1 << 7) +# define I915_PL_DG_QC_FT_CLOCK_GATE_DISABLE (1 << 6) +# define I915_SC_CLOCK_GATE_DISABLE (1 << 5) +# define I915_FL_CLOCK_GATE_DISABLE (1 << 4) +# define I915_DM_CLOCK_GATE_DISABLE (1 << 3) +# define I915_PS_CLOCK_GATE_DISABLE (1 << 2) +# define I915_CC_CLOCK_GATE_DISABLE (1 << 1) +# define I915_BY_CLOCK_GATE_DISABLE (1 << 0) + +# define I965_RCZ_CLOCK_GATE_DISABLE (1 << 30) +/** This bit must always be set on 965G/965GM */ +# define I965_RCC_CLOCK_GATE_DISABLE (1 << 29) +# define I965_RCPB_CLOCK_GATE_DISABLE (1 << 28) +# define I965_DAP_CLOCK_GATE_DISABLE (1 << 27) +# define I965_ROC_CLOCK_GATE_DISABLE (1 << 26) +# define I965_GW_CLOCK_GATE_DISABLE (1 << 25) +# define I965_TD_CLOCK_GATE_DISABLE (1 << 24) +/** This bit must always be set on 965G */ +# define I965_ISC_CLOCK_GATE_DISABLE (1 << 23) +# define I965_IC_CLOCK_GATE_DISABLE (1 << 22) +# define I965_EU_CLOCK_GATE_DISABLE (1 << 21) +# define I965_IF_CLOCK_GATE_DISABLE (1 << 20) +# define I965_TC_CLOCK_GATE_DISABLE (1 << 19) +# define I965_SO_CLOCK_GATE_DISABLE (1 << 17) +# define I965_FBC_CLOCK_GATE_DISABLE (1 << 16) +# define I965_MARI_CLOCK_GATE_DISABLE (1 << 15) +# define I965_MASF_CLOCK_GATE_DISABLE (1 << 14) +# define I965_MAWB_CLOCK_GATE_DISABLE (1 << 13) +# define I965_EM_CLOCK_GATE_DISABLE (1 << 12) +# define I965_UC_CLOCK_GATE_DISABLE (1 << 11) +# define I965_SI_CLOCK_GATE_DISABLE (1 << 6) +# define I965_MT_CLOCK_GATE_DISABLE (1 << 5) +# define I965_PL_CLOCK_GATE_DISABLE (1 << 4) +# define I965_DG_CLOCK_GATE_DISABLE (1 << 3) +# define I965_QC_CLOCK_GATE_DISABLE (1 << 2) +# define I965_FT_CLOCK_GATE_DISABLE (1 << 1) +# define I965_DM_CLOCK_GATE_DISABLE (1 << 0) + +#define RENCLK_GATE_D2 0x6208 +#define VF_UNIT_CLOCK_GATE_DISABLE (1 << 9) +#define GS_UNIT_CLOCK_GATE_DISABLE (1 << 7) +#define CL_UNIT_CLOCK_GATE_DISABLE (1 << 6) +#define RAMCLK_GATE_D 0x6210 /* CRL only */ +#define DEUC 0x6214 /* CRL only */ + +#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500) +#define FW_CSPWRDWNEN (1<<15) + +#define MI_ARB_VLV (VLV_DISPLAY_BASE + 0x6504) + +#define CZCLK_CDCLK_FREQ_RATIO (VLV_DISPLAY_BASE + 0x6508) +#define CDCLK_FREQ_SHIFT 4 +#define CDCLK_FREQ_MASK (0x1f << CDCLK_FREQ_SHIFT) +#define CZCLK_FREQ_MASK 0xf +#define GMBUSFREQ_VLV (VLV_DISPLAY_BASE + 0x6510) + +/* + * Palette regs + */ + +#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000) +#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800) +#define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B) + +/* MCH MMIO space */ + +/* + * MCHBAR mirror. + * + * This mirrors the MCHBAR MMIO space whose location is determined by + * device 0 function 0's pci config register 0x44 or 0x48 and matches it in + * every way. It is not accessible from the CP register read instructions. + * + * Starting from Haswell, you can't write registers using the MCHBAR mirror, + * just read. + */ +#define MCHBAR_MIRROR_BASE 0x10000 + +#define MCHBAR_MIRROR_BASE_SNB 0x140000 + +/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ +#define DCLK (MCHBAR_MIRROR_BASE_SNB + 0x5e04) + +/** 915-945 and GM965 MCH register controlling DRAM channel access */ +#define DCC 0x10200 +#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) +#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0) +#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0) +#define DCC_ADDRESSING_MODE_MASK (3 << 0) +#define DCC_CHANNEL_XOR_DISABLE (1 << 10) +#define DCC_CHANNEL_XOR_BIT_17 (1 << 9) + +/** Pineview MCH register contains DDR3 setting */ +#define CSHRDDR3CTL 0x101a8 +#define CSHRDDR3CTL_DDR3 (1 << 2) + +/** 965 MCH register controlling DRAM channel configuration */ +#define C0DRB3 0x10206 +#define C1DRB3 0x10606 + +/** snb MCH registers for reading the DRAM channel configuration */ +#define MAD_DIMM_C0 (MCHBAR_MIRROR_BASE_SNB + 0x5004) +#define MAD_DIMM_C1 (MCHBAR_MIRROR_BASE_SNB + 0x5008) +#define MAD_DIMM_C2 (MCHBAR_MIRROR_BASE_SNB + 0x500C) +#define MAD_DIMM_ECC_MASK (0x3 << 24) +#define MAD_DIMM_ECC_OFF (0x0 << 24) +#define MAD_DIMM_ECC_IO_ON_LOGIC_OFF (0x1 << 24) +#define MAD_DIMM_ECC_IO_OFF_LOGIC_ON (0x2 << 24) +#define MAD_DIMM_ECC_ON (0x3 << 24) +#define MAD_DIMM_ENH_INTERLEAVE (0x1 << 22) +#define MAD_DIMM_RANK_INTERLEAVE (0x1 << 21) +#define MAD_DIMM_B_WIDTH_X16 (0x1 << 20) /* X8 chips if unset */ +#define MAD_DIMM_A_WIDTH_X16 (0x1 << 19) /* X8 chips if unset */ +#define MAD_DIMM_B_DUAL_RANK (0x1 << 18) +#define MAD_DIMM_A_DUAL_RANK (0x1 << 17) +#define MAD_DIMM_A_SELECT (0x1 << 16) +/* DIMM sizes are in multiples of 256mb. */ +#define MAD_DIMM_B_SIZE_SHIFT 8 +#define MAD_DIMM_B_SIZE_MASK (0xff << MAD_DIMM_B_SIZE_SHIFT) +#define MAD_DIMM_A_SIZE_SHIFT 0 +#define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT) + +/** snb MCH registers for priority tuning */ +#define MCH_SSKPD (MCHBAR_MIRROR_BASE_SNB + 0x5d10) +#define MCH_SSKPD_WM0_MASK 0x3f +#define MCH_SSKPD_WM0_VAL 0xc + +#define MCH_SECP_NRG_STTS (MCHBAR_MIRROR_BASE_SNB + 0x592c) + +/* Clocking configuration register */ +#define CLKCFG 0x10c00 +#define CLKCFG_FSB_400 (5 << 0) /* hrawclk 100 */ +#define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */ +#define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */ +#define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */ +#define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */ +#define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */ +/* Note, below two are guess */ +#define CLKCFG_FSB_1600 (4 << 0) /* hrawclk 400 */ +#define CLKCFG_FSB_1600_ALT (0 << 0) /* hrawclk 400 */ +#define CLKCFG_FSB_MASK (7 << 0) +#define CLKCFG_MEM_533 (1 << 4) +#define CLKCFG_MEM_667 (2 << 4) +#define CLKCFG_MEM_800 (3 << 4) +#define CLKCFG_MEM_MASK (7 << 4) + +#define TSC1 0x11001 +#define TSE (1<<0) +#define TR1 0x11006 +#define TSFS 0x11020 +#define TSFS_SLOPE_MASK 0x0000ff00 +#define TSFS_SLOPE_SHIFT 8 +#define TSFS_INTR_MASK 0x000000ff + +#define CRSTANDVID 0x11100 +#define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ +#define PXVFREQ_PX_MASK 0x7f000000 +#define PXVFREQ_PX_SHIFT 24 +#define VIDFREQ_BASE 0x11110 +#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */ +#define VIDFREQ2 0x11114 +#define VIDFREQ3 0x11118 +#define VIDFREQ4 0x1111c +#define VIDFREQ_P0_MASK 0x1f000000 +#define VIDFREQ_P0_SHIFT 24 +#define VIDFREQ_P0_CSCLK_MASK 0x00f00000 +#define VIDFREQ_P0_CSCLK_SHIFT 20 +#define VIDFREQ_P0_CRCLK_MASK 0x000f0000 +#define VIDFREQ_P0_CRCLK_SHIFT 16 +#define VIDFREQ_P1_MASK 0x00001f00 +#define VIDFREQ_P1_SHIFT 8 +#define VIDFREQ_P1_CSCLK_MASK 0x000000f0 +#define VIDFREQ_P1_CSCLK_SHIFT 4 +#define VIDFREQ_P1_CRCLK_MASK 0x0000000f +#define INTTOEXT_BASE_ILK 0x11300 +#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */ +#define INTTOEXT_MAP3_SHIFT 24 +#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT) +#define INTTOEXT_MAP2_SHIFT 16 +#define INTTOEXT_MAP2_MASK (0x1f << INTTOEXT_MAP2_SHIFT) +#define INTTOEXT_MAP1_SHIFT 8 +#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT) +#define INTTOEXT_MAP0_SHIFT 0 +#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT) +#define MEMSWCTL 0x11170 /* Ironlake only */ +#define MEMCTL_CMD_MASK 0xe000 +#define MEMCTL_CMD_SHIFT 13 +#define MEMCTL_CMD_RCLK_OFF 0 +#define MEMCTL_CMD_RCLK_ON 1 +#define MEMCTL_CMD_CHFREQ 2 +#define MEMCTL_CMD_CHVID 3 +#define MEMCTL_CMD_VMMOFF 4 +#define MEMCTL_CMD_VMMON 5 +#define MEMCTL_CMD_STS (1<<12) /* write 1 triggers command, clears + when command complete */ +#define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */ +#define MEMCTL_FREQ_SHIFT 8 +#define MEMCTL_SFCAVM (1<<7) +#define MEMCTL_TGT_VID_MASK 0x007f +#define MEMIHYST 0x1117c +#define MEMINTREN 0x11180 /* 16 bits */ +#define MEMINT_RSEXIT_EN (1<<8) +#define MEMINT_CX_SUPR_EN (1<<7) +#define MEMINT_CONT_BUSY_EN (1<<6) +#define MEMINT_AVG_BUSY_EN (1<<5) +#define MEMINT_EVAL_CHG_EN (1<<4) +#define MEMINT_MON_IDLE_EN (1<<3) +#define MEMINT_UP_EVAL_EN (1<<2) +#define MEMINT_DOWN_EVAL_EN (1<<1) +#define MEMINT_SW_CMD_EN (1<<0) +#define MEMINTRSTR 0x11182 /* 16 bits */ +#define MEM_RSEXIT_MASK 0xc000 +#define MEM_RSEXIT_SHIFT 14 +#define MEM_CONT_BUSY_MASK 0x3000 +#define MEM_CONT_BUSY_SHIFT 12 +#define MEM_AVG_BUSY_MASK 0x0c00 +#define MEM_AVG_BUSY_SHIFT 10 +#define MEM_EVAL_CHG_MASK 0x0300 +#define MEM_EVAL_BUSY_SHIFT 8 +#define MEM_MON_IDLE_MASK 0x00c0 +#define MEM_MON_IDLE_SHIFT 6 +#define MEM_UP_EVAL_MASK 0x0030 +#define MEM_UP_EVAL_SHIFT 4 +#define MEM_DOWN_EVAL_MASK 0x000c +#define MEM_DOWN_EVAL_SHIFT 2 +#define MEM_SW_CMD_MASK 0x0003 +#define MEM_INT_STEER_GFX 0 +#define MEM_INT_STEER_CMR 1 +#define MEM_INT_STEER_SMI 2 +#define MEM_INT_STEER_SCI 3 +#define MEMINTRSTS 0x11184 +#define MEMINT_RSEXIT (1<<7) +#define MEMINT_CONT_BUSY (1<<6) +#define MEMINT_AVG_BUSY (1<<5) +#define MEMINT_EVAL_CHG (1<<4) +#define MEMINT_MON_IDLE (1<<3) +#define MEMINT_UP_EVAL (1<<2) +#define MEMINT_DOWN_EVAL (1<<1) +#define MEMINT_SW_CMD (1<<0) +#define MEMMODECTL 0x11190 +#define MEMMODE_BOOST_EN (1<<31) +#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */ +#define MEMMODE_BOOST_FREQ_SHIFT 24 +#define MEMMODE_IDLE_MODE_MASK 0x00030000 +#define MEMMODE_IDLE_MODE_SHIFT 16 +#define MEMMODE_IDLE_MODE_EVAL 0 +#define MEMMODE_IDLE_MODE_CONT 1 +#define MEMMODE_HWIDLE_EN (1<<15) +#define MEMMODE_SWMODE_EN (1<<14) +#define MEMMODE_RCLK_GATE (1<<13) +#define MEMMODE_HW_UPDATE (1<<12) +#define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */ +#define MEMMODE_FSTART_SHIFT 8 +#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */ +#define MEMMODE_FMAX_SHIFT 4 +#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */ +#define RCBMAXAVG 0x1119c +#define MEMSWCTL2 0x1119e /* Cantiga only */ +#define SWMEMCMD_RENDER_OFF (0 << 13) +#define SWMEMCMD_RENDER_ON (1 << 13) +#define SWMEMCMD_SWFREQ (2 << 13) +#define SWMEMCMD_TARVID (3 << 13) +#define SWMEMCMD_VRM_OFF (4 << 13) +#define SWMEMCMD_VRM_ON (5 << 13) +#define CMDSTS (1<<12) +#define SFCAVM (1<<11) +#define SWFREQ_MASK 0x0380 /* P0-7 */ +#define SWFREQ_SHIFT 7 +#define TARVID_MASK 0x001f +#define MEMSTAT_CTG 0x111a0 +#define RCBMINAVG 0x111a0 +#define RCUPEI 0x111b0 +#define RCDNEI 0x111b4 +#define RSTDBYCTL 0x111b8 +#define RS1EN (1<<31) +#define RS2EN (1<<30) +#define RS3EN (1<<29) +#define D3RS3EN (1<<28) /* Display D3 imlies RS3 */ +#define SWPROMORSX (1<<27) /* RSx promotion timers ignored */ +#define RCWAKERW (1<<26) /* Resetwarn from PCH causes wakeup */ +#define DPRSLPVREN (1<<25) /* Fast voltage ramp enable */ +#define GFXTGHYST (1<<24) /* Hysteresis to allow trunk gating */ +#define RCX_SW_EXIT (1<<23) /* Leave RSx and prevent re-entry */ +#define RSX_STATUS_MASK (7<<20) +#define RSX_STATUS_ON (0<<20) +#define RSX_STATUS_RC1 (1<<20) +#define RSX_STATUS_RC1E (2<<20) +#define RSX_STATUS_RS1 (3<<20) +#define RSX_STATUS_RS2 (4<<20) /* aka rc6 */ +#define RSX_STATUS_RSVD (5<<20) /* deep rc6 unsupported on ilk */ +#define RSX_STATUS_RS3 (6<<20) /* rs3 unsupported on ilk */ +#define RSX_STATUS_RSVD2 (7<<20) +#define UWRCRSXE (1<<19) /* wake counter limit prevents rsx */ +#define RSCRP (1<<18) /* rs requests control on rs1/2 reqs */ +#define JRSC (1<<17) /* rsx coupled to cpu c-state */ +#define RS2INC0 (1<<16) /* allow rs2 in cpu c0 */ +#define RS1CONTSAV_MASK (3<<14) +#define RS1CONTSAV_NO_RS1 (0<<14) /* rs1 doesn't save/restore context */ +#define RS1CONTSAV_RSVD (1<<14) +#define RS1CONTSAV_SAVE_RS1 (2<<14) /* rs1 saves context */ +#define RS1CONTSAV_FULL_RS1 (3<<14) /* rs1 saves and restores context */ +#define NORMSLEXLAT_MASK (3<<12) +#define SLOW_RS123 (0<<12) +#define SLOW_RS23 (1<<12) +#define SLOW_RS3 (2<<12) +#define NORMAL_RS123 (3<<12) +#define RCMODE_TIMEOUT (1<<11) /* 0 is eval interval method */ +#define IMPROMOEN (1<<10) /* promo is immediate or delayed until next idle interval (only for timeout method above) */ +#define RCENTSYNC (1<<9) /* rs coupled to cpu c-state (3/6/7) */ +#define STATELOCK (1<<7) /* locked to rs_cstate if 0 */ +#define RS_CSTATE_MASK (3<<4) +#define RS_CSTATE_C367_RS1 (0<<4) +#define RS_CSTATE_C36_RS1_C7_RS2 (1<<4) +#define RS_CSTATE_RSVD (2<<4) +#define RS_CSTATE_C367_RS2 (3<<4) +#define REDSAVES (1<<3) /* no context save if was idle during rs0 */ +#define REDRESTORES (1<<2) /* no restore if was idle during rs0 */ +#define VIDCTL 0x111c0 +#define VIDSTS 0x111c8 +#define VIDSTART 0x111cc /* 8 bits */ +#define MEMSTAT_ILK 0x111f8 +#define MEMSTAT_VID_MASK 0x7f00 +#define MEMSTAT_VID_SHIFT 8 +#define MEMSTAT_PSTATE_MASK 0x00f8 +#define MEMSTAT_PSTATE_SHIFT 3 +#define MEMSTAT_MON_ACTV (1<<2) +#define MEMSTAT_SRC_CTL_MASK 0x0003 +#define MEMSTAT_SRC_CTL_CORE 0 +#define MEMSTAT_SRC_CTL_TRB 1 +#define MEMSTAT_SRC_CTL_THM 2 +#define MEMSTAT_SRC_CTL_STDBY 3 +#define RCPREVBSYTUPAVG 0x113b8 +#define RCPREVBSYTDNAVG 0x113bc +#define PMMISC 0x11214 +#define MCPPCE_EN (1<<0) /* enable PM_MSG from PCH->MPC */ +#define SDEW 0x1124c +#define CSIEW0 0x11250 +#define CSIEW1 0x11254 +#define CSIEW2 0x11258 +#define PEW 0x1125c +#define DEW 0x11270 +#define MCHAFE 0x112c0 +#define CSIEC 0x112e0 +#define DMIEC 0x112e4 +#define DDREC 0x112e8 +#define PEG0EC 0x112ec +#define PEG1EC 0x112f0 +#define GFXEC 0x112f4 +#define RPPREVBSYTUPAVG 0x113b8 +#define RPPREVBSYTDNAVG 0x113bc +#define ECR 0x11600 +#define ECR_GPFE (1<<31) +#define ECR_IMONE (1<<30) +#define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */ +#define OGW0 0x11608 +#define OGW1 0x1160c +#define EG0 0x11610 +#define EG1 0x11614 +#define EG2 0x11618 +#define EG3 0x1161c +#define EG4 0x11620 +#define EG5 0x11624 +#define EG6 0x11628 +#define EG7 0x1162c +#define PXW 0x11664 +#define PXWL 0x11680 +#define LCFUSE02 0x116c0 +#define LCFUSE_HIV_MASK 0x000000ff +#define CSIPLL0 0x12c10 +#define DDRMPLL1 0X12c20 +#define PEG_BAND_GAP_DATA 0x14d68 + +#define GEN6_GT_THREAD_STATUS_REG 0x13805c +#define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7 +#define GEN6_GT_THREAD_STATUS_CORE_MASK_HSW (0x7 | (0x07 << 16)) + +#define GEN6_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x5948) +#define GEN6_RP_STATE_LIMITS (MCHBAR_MIRROR_BASE_SNB + 0x5994) +#define GEN6_RP_STATE_CAP (MCHBAR_MIRROR_BASE_SNB + 0x5998) + +/* + * Logical Context regs + */ +#define CCID 0x2180 +#define CCID_EN (1<<0) +/* + * Notes on SNB/IVB/VLV context size: + * - Power context is saved elsewhere (LLC or stolen) + * - Ring/execlist context is saved on SNB, not on IVB + * - Extended context size already includes render context size + * - We always need to follow the extended context size. + * SNB BSpec has comments indicating that we should use the + * render context size instead if execlists are disabled, but + * based on empirical testing that's just nonsense. + * - Pipelined/VF state is saved on SNB/IVB respectively + * - GT1 size just indicates how much of render context + * doesn't need saving on GT1 + */ +#define CXT_SIZE 0x21a0 +#define GEN6_CXT_POWER_SIZE(cxt_reg) ((cxt_reg >> 24) & 0x3f) +#define GEN6_CXT_RING_SIZE(cxt_reg) ((cxt_reg >> 18) & 0x3f) +#define GEN6_CXT_RENDER_SIZE(cxt_reg) ((cxt_reg >> 12) & 0x3f) +#define GEN6_CXT_EXTENDED_SIZE(cxt_reg) ((cxt_reg >> 6) & 0x3f) +#define GEN6_CXT_PIPELINE_SIZE(cxt_reg) ((cxt_reg >> 0) & 0x3f) +#define GEN6_CXT_TOTAL_SIZE(cxt_reg) (GEN6_CXT_RING_SIZE(cxt_reg) + \ + GEN6_CXT_EXTENDED_SIZE(cxt_reg) + \ + GEN6_CXT_PIPELINE_SIZE(cxt_reg)) +#define GEN7_CXT_SIZE 0x21a8 +#define GEN7_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 25) & 0x7f) +#define GEN7_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 22) & 0x7) +#define GEN7_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 16) & 0x3f) +#define GEN7_CXT_EXTENDED_SIZE(ctx_reg) ((ctx_reg >> 9) & 0x7f) +#define GEN7_CXT_GT1_SIZE(ctx_reg) ((ctx_reg >> 6) & 0x7) +#define GEN7_CXT_VFSTATE_SIZE(ctx_reg) ((ctx_reg >> 0) & 0x3f) +#define GEN7_CXT_TOTAL_SIZE(ctx_reg) (GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \ + GEN7_CXT_VFSTATE_SIZE(ctx_reg)) +/* Haswell does have the CXT_SIZE register however it does not appear to be + * valid. Now, docs explain in dwords what is in the context object. The full + * size is 70720 bytes, however, the power context and execlist context will + * never be saved (power context is stored elsewhere, and execlists don't work + * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages. + */ +#define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE) +/* Same as Haswell, but 72064 bytes now. */ +#define GEN8_CXT_TOTAL_SIZE (18 * PAGE_SIZE) + + +#define VLV_CLK_CTL2 0x101104 +#define CLK_CTL2_CZCOUNT_30NS_SHIFT 28 + +/* + * Overlay regs + */ + +#define OVADD 0x30000 +#define DOVSTA 0x30008 +#define OC_BUF (0x3<<20) +#define OGAMC5 0x30010 +#define OGAMC4 0x30014 +#define OGAMC3 0x30018 +#define OGAMC2 0x3001c +#define OGAMC1 0x30020 +#define OGAMC0 0x30024 + +/* + * Display engine regs + */ + +/* Pipe A CRC regs */ +#define _PIPE_CRC_CTL_A (dev_priv->info->display_mmio_offset + 0x60050) +#define PIPE_CRC_ENABLE (1 << 31) +/* ivb+ source selection */ +#define PIPE_CRC_SOURCE_PRIMARY_IVB (0 << 29) +#define PIPE_CRC_SOURCE_SPRITE_IVB (1 << 29) +#define PIPE_CRC_SOURCE_PF_IVB (2 << 29) +/* ilk+ source selection */ +#define PIPE_CRC_SOURCE_PRIMARY_ILK (0 << 28) +#define PIPE_CRC_SOURCE_SPRITE_ILK (1 << 28) +#define PIPE_CRC_SOURCE_PIPE_ILK (2 << 28) +/* embedded DP port on the north display block, reserved on ivb */ +#define PIPE_CRC_SOURCE_PORT_A_ILK (4 << 28) +#define PIPE_CRC_SOURCE_FDI_ILK (5 << 28) /* reserved on ivb */ +/* vlv source selection */ +#define PIPE_CRC_SOURCE_PIPE_VLV (0 << 27) +#define PIPE_CRC_SOURCE_HDMIB_VLV (1 << 27) +#define PIPE_CRC_SOURCE_HDMIC_VLV (2 << 27) +/* with DP port the pipe source is invalid */ +#define PIPE_CRC_SOURCE_DP_D_VLV (3 << 27) +#define PIPE_CRC_SOURCE_DP_B_VLV (6 << 27) +#define PIPE_CRC_SOURCE_DP_C_VLV (7 << 27) +/* gen3+ source selection */ +#define PIPE_CRC_SOURCE_PIPE_I9XX (0 << 28) +#define PIPE_CRC_SOURCE_SDVOB_I9XX (1 << 28) +#define PIPE_CRC_SOURCE_SDVOC_I9XX (2 << 28) +/* with DP/TV port the pipe source is invalid */ +#define PIPE_CRC_SOURCE_DP_D_G4X (3 << 28) +#define PIPE_CRC_SOURCE_TV_PRE (4 << 28) +#define PIPE_CRC_SOURCE_TV_POST (5 << 28) +#define PIPE_CRC_SOURCE_DP_B_G4X (6 << 28) +#define PIPE_CRC_SOURCE_DP_C_G4X (7 << 28) +/* gen2 doesn't have source selection bits */ +#define PIPE_CRC_INCLUDE_BORDER_I8XX (1 << 30) + +#define _PIPE_CRC_RES_1_A_IVB 0x60064 +#define _PIPE_CRC_RES_2_A_IVB 0x60068 +#define _PIPE_CRC_RES_3_A_IVB 0x6006c +#define _PIPE_CRC_RES_4_A_IVB 0x60070 +#define _PIPE_CRC_RES_5_A_IVB 0x60074 + +#define _PIPE_CRC_RES_RED_A (dev_priv->info->display_mmio_offset + 0x60060) +#define _PIPE_CRC_RES_GREEN_A (dev_priv->info->display_mmio_offset + 0x60064) +#define _PIPE_CRC_RES_BLUE_A (dev_priv->info->display_mmio_offset + 0x60068) +#define _PIPE_CRC_RES_RES1_A_I915 (dev_priv->info->display_mmio_offset + 0x6006c) +#define _PIPE_CRC_RES_RES2_A_G4X (dev_priv->info->display_mmio_offset + 0x60080) + +/* Pipe B CRC regs */ +#define _PIPE_CRC_RES_1_B_IVB 0x61064 +#define _PIPE_CRC_RES_2_B_IVB 0x61068 +#define _PIPE_CRC_RES_3_B_IVB 0x6106c +#define _PIPE_CRC_RES_4_B_IVB 0x61070 +#define _PIPE_CRC_RES_5_B_IVB 0x61074 + +#define PIPE_CRC_CTL(pipe) _PIPE_INC(pipe, _PIPE_CRC_CTL_A, 0x01000) +#define PIPE_CRC_RES_1_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB) +#define PIPE_CRC_RES_2_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_2_A_IVB, _PIPE_CRC_RES_2_B_IVB) +#define PIPE_CRC_RES_3_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_3_A_IVB, _PIPE_CRC_RES_3_B_IVB) +#define PIPE_CRC_RES_4_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_4_A_IVB, _PIPE_CRC_RES_4_B_IVB) +#define PIPE_CRC_RES_5_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB) + +#define PIPE_CRC_RES_RED(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_RED_A, 0x01000) +#define PIPE_CRC_RES_GREEN(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_GREEN_A, 0x01000) +#define PIPE_CRC_RES_BLUE(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_BLUE_A, 0x01000) +#define PIPE_CRC_RES_RES1_I915(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_RES1_A_I915, 0x01000) +#define PIPE_CRC_RES_RES2_G4X(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_RES2_A_G4X, 0x01000) + +/* Pipe A timing regs */ +#define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000) +#define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004) +#define _HSYNC_A (dev_priv->info->display_mmio_offset + 0x60008) +#define _VTOTAL_A (dev_priv->info->display_mmio_offset + 0x6000c) +#define _VBLANK_A (dev_priv->info->display_mmio_offset + 0x60010) +#define _VSYNC_A (dev_priv->info->display_mmio_offset + 0x60014) +#define _PIPEASRC (dev_priv->info->display_mmio_offset + 0x6001c) +#define _BCLRPAT_A (dev_priv->info->display_mmio_offset + 0x60020) +#define _VSYNCSHIFT_A (dev_priv->info->display_mmio_offset + 0x60028) + +/* Pipe B timing regs */ +#define _HTOTAL_B (dev_priv->info->display_mmio_offset + 0x61000) +#define _HBLANK_B (dev_priv->info->display_mmio_offset + 0x61004) +#define _HSYNC_B (dev_priv->info->display_mmio_offset + 0x61008) +#define _VTOTAL_B (dev_priv->info->display_mmio_offset + 0x6100c) +#define _VBLANK_B (dev_priv->info->display_mmio_offset + 0x61010) +#define _VSYNC_B (dev_priv->info->display_mmio_offset + 0x61014) +#define _PIPEBSRC (dev_priv->info->display_mmio_offset + 0x6101c) +#define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020) +#define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028) + +#define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B) +#define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B) +#define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B) +#define VTOTAL(trans) _TRANSCODER(trans, _VTOTAL_A, _VTOTAL_B) +#define VBLANK(trans) _TRANSCODER(trans, _VBLANK_A, _VBLANK_B) +#define VSYNC(trans) _TRANSCODER(trans, _VSYNC_A, _VSYNC_B) +#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B) +#define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B) + +/* HSW+ eDP PSR registers */ +#define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800) +#define EDP_PSR_CTL(dev) (EDP_PSR_BASE(dev) + 0) +#define EDP_PSR_ENABLE (1<<31) +#define EDP_PSR_LINK_DISABLE (0<<27) +#define EDP_PSR_LINK_STANDBY (1<<27) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_MASK (3<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES (0<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES (1<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES (2<<25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES (3<<25) +#define EDP_PSR_MAX_SLEEP_TIME_SHIFT 20 +#define EDP_PSR_SKIP_AUX_EXIT (1<<12) +#define EDP_PSR_TP1_TP2_SEL (0<<11) +#define EDP_PSR_TP1_TP3_SEL (1<<11) +#define EDP_PSR_TP2_TP3_TIME_500us (0<<8) +#define EDP_PSR_TP2_TP3_TIME_100us (1<<8) +#define EDP_PSR_TP2_TP3_TIME_2500us (2<<8) +#define EDP_PSR_TP2_TP3_TIME_0us (3<<8) +#define EDP_PSR_TP1_TIME_500us (0<<4) +#define EDP_PSR_TP1_TIME_100us (1<<4) +#define EDP_PSR_TP1_TIME_2500us (2<<4) +#define EDP_PSR_TP1_TIME_0us (3<<4) +#define EDP_PSR_IDLE_FRAME_SHIFT 0 + +#define EDP_PSR_AUX_CTL(dev) (EDP_PSR_BASE(dev) + 0x10) +#define EDP_PSR_AUX_DATA1(dev) (EDP_PSR_BASE(dev) + 0x14) +#define EDP_PSR_DPCD_COMMAND 0x80060000 +#define EDP_PSR_AUX_DATA2(dev) (EDP_PSR_BASE(dev) + 0x18) +#define EDP_PSR_DPCD_NORMAL_OPERATION (1<<24) +#define EDP_PSR_AUX_DATA3(dev) (EDP_PSR_BASE(dev) + 0x1c) +#define EDP_PSR_AUX_DATA4(dev) (EDP_PSR_BASE(dev) + 0x20) +#define EDP_PSR_AUX_DATA5(dev) (EDP_PSR_BASE(dev) + 0x24) + +#define EDP_PSR_STATUS_CTL(dev) (EDP_PSR_BASE(dev) + 0x40) +#define EDP_PSR_STATUS_STATE_MASK (7<<29) +#define EDP_PSR_STATUS_STATE_IDLE (0<<29) +#define EDP_PSR_STATUS_STATE_SRDONACK (1<<29) +#define EDP_PSR_STATUS_STATE_SRDENT (2<<29) +#define EDP_PSR_STATUS_STATE_BUFOFF (3<<29) +#define EDP_PSR_STATUS_STATE_BUFON (4<<29) +#define EDP_PSR_STATUS_STATE_AUXACK (5<<29) +#define EDP_PSR_STATUS_STATE_SRDOFFACK (6<<29) +#define EDP_PSR_STATUS_LINK_MASK (3<<26) +#define EDP_PSR_STATUS_LINK_FULL_OFF (0<<26) +#define EDP_PSR_STATUS_LINK_FULL_ON (1<<26) +#define EDP_PSR_STATUS_LINK_STANDBY (2<<26) +#define EDP_PSR_STATUS_MAX_SLEEP_TIMER_SHIFT 20 +#define EDP_PSR_STATUS_MAX_SLEEP_TIMER_MASK 0x1f +#define EDP_PSR_STATUS_COUNT_SHIFT 16 +#define EDP_PSR_STATUS_COUNT_MASK 0xf +#define EDP_PSR_STATUS_AUX_ERROR (1<<15) +#define EDP_PSR_STATUS_AUX_SENDING (1<<12) +#define EDP_PSR_STATUS_SENDING_IDLE (1<<9) +#define EDP_PSR_STATUS_SENDING_TP2_TP3 (1<<8) +#define EDP_PSR_STATUS_SENDING_TP1 (1<<4) +#define EDP_PSR_STATUS_IDLE_MASK 0xf + +#define EDP_PSR_PERF_CNT(dev) (EDP_PSR_BASE(dev) + 0x44) +#define EDP_PSR_PERF_CNT_MASK 0xffffff + +#define EDP_PSR_DEBUG_CTL(dev) (EDP_PSR_BASE(dev) + 0x60) +#define EDP_PSR_DEBUG_MASK_LPSP (1<<27) +#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26) +#define EDP_PSR_DEBUG_MASK_HPD (1<<25) + +/* VGA port control */ +#define ADPA 0x61100 +#define PCH_ADPA 0xe1100 +#define VLV_ADPA (VLV_DISPLAY_BASE + ADPA) + +#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1<<30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1<<30) +#define ADPA_PIPE_SELECT(pipe) ((pipe) << 30) +/* CPT uses bits 29:30 for pch transcoder select */ +#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ +#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24) +#define ADPA_CRT_HOTPLUG_ENABLE (1<<23) +#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22) +#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22) +#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21) +#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21) +#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20) +#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20) +#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18) +#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17) +#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) +#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) +#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1<<10) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1<<11) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_LOW 0 +#define ADPA_DPMS_MASK (~(3<<10)) +#define ADPA_DPMS_ON (0<<10) +#define ADPA_DPMS_SUSPEND (1<<10) +#define ADPA_DPMS_STANDBY (2<<10) +#define ADPA_DPMS_OFF (3<<10) + + +/* Hotplug control (945+ only) */ +#define PORT_HOTPLUG_EN (dev_priv->info->display_mmio_offset + 0x61110) +#define PORTB_HOTPLUG_INT_EN (1 << 29) +#define PORTC_HOTPLUG_INT_EN (1 << 28) +#define PORTD_HOTPLUG_INT_EN (1 << 27) +#define SDVOB_HOTPLUG_INT_EN (1 << 26) +#define SDVOC_HOTPLUG_INT_EN (1 << 25) +#define TV_HOTPLUG_INT_EN (1 << 18) +#define CRT_HOTPLUG_INT_EN (1 << 9) +#define HOTPLUG_INT_EN_MASK (PORTB_HOTPLUG_INT_EN | \ + PORTC_HOTPLUG_INT_EN | \ + PORTD_HOTPLUG_INT_EN | \ + SDVOC_HOTPLUG_INT_EN | \ + SDVOB_HOTPLUG_INT_EN | \ + CRT_HOTPLUG_INT_EN) +#define CRT_HOTPLUG_FORCE_DETECT (1 << 3) +#define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8) +/* must use period 64 on GM45 according to docs */ +#define CRT_HOTPLUG_ACTIVATION_PERIOD_64 (1 << 8) +#define CRT_HOTPLUG_DAC_ON_TIME_2M (0 << 7) +#define CRT_HOTPLUG_DAC_ON_TIME_4M (1 << 7) +#define CRT_HOTPLUG_VOLTAGE_COMPARE_40 (0 << 5) +#define CRT_HOTPLUG_VOLTAGE_COMPARE_50 (1 << 5) +#define CRT_HOTPLUG_VOLTAGE_COMPARE_60 (2 << 5) +#define CRT_HOTPLUG_VOLTAGE_COMPARE_70 (3 << 5) +#define CRT_HOTPLUG_VOLTAGE_COMPARE_MASK (3 << 5) +#define CRT_HOTPLUG_DETECT_DELAY_1G (0 << 4) +#define CRT_HOTPLUG_DETECT_DELAY_2G (1 << 4) +#define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) +#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) + +#define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114) +/* + * HDMI/DP bits are gen4+ + * + * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused. + * Please check the detailed lore in the commit message for for experimental + * evidence. + */ +#define PORTD_HOTPLUG_LIVE_STATUS_G4X (1 << 29) +#define PORTC_HOTPLUG_LIVE_STATUS_G4X (1 << 28) +#define PORTB_HOTPLUG_LIVE_STATUS_G4X (1 << 27) +/* VLV DP/HDMI bits again match Bspec */ +#define PORTD_HOTPLUG_LIVE_STATUS_VLV (1 << 27) +#define PORTC_HOTPLUG_LIVE_STATUS_VLV (1 << 28) +#define PORTB_HOTPLUG_LIVE_STATUS_VLV (1 << 29) +#define PORTD_HOTPLUG_INT_STATUS (3 << 21) +#define PORTC_HOTPLUG_INT_STATUS (3 << 19) +#define PORTB_HOTPLUG_INT_STATUS (3 << 17) +/* CRT/TV common between gen3+ */ +#define CRT_HOTPLUG_INT_STATUS (1 << 11) +#define TV_HOTPLUG_INT_STATUS (1 << 10) +#define CRT_HOTPLUG_MONITOR_MASK (3 << 8) +#define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) +#define CRT_HOTPLUG_MONITOR_MONO (2 << 8) +#define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +#define DP_AUX_CHANNEL_D_INT_STATUS_G4X (1 << 6) +#define DP_AUX_CHANNEL_C_INT_STATUS_G4X (1 << 5) +#define DP_AUX_CHANNEL_B_INT_STATUS_G4X (1 << 4) +#define DP_AUX_CHANNEL_MASK_INT_STATUS_G4X (7 << 4) + +/* SDVO is different across gen3/4 */ +#define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3) +#define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2) +/* + * Bspec seems to be seriously misleaded about the SDVO hpd bits on i965g/gm, + * since reality corrobates that they're the same as on gen3. But keep these + * bits here (and the comment!) to help any other lost wanderers back onto the + * right tracks. + */ +#define SDVOC_HOTPLUG_INT_STATUS_I965 (3 << 4) +#define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2) +#define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) +#define SDVOB_HOTPLUG_INT_STATUS_I915 (1 << 6) +#define HOTPLUG_INT_STATUS_G4X (CRT_HOTPLUG_INT_STATUS | \ + SDVOB_HOTPLUG_INT_STATUS_G4X | \ + SDVOC_HOTPLUG_INT_STATUS_G4X | \ + PORTB_HOTPLUG_INT_STATUS | \ + PORTC_HOTPLUG_INT_STATUS | \ + PORTD_HOTPLUG_INT_STATUS) + +#define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \ + SDVOB_HOTPLUG_INT_STATUS_I915 | \ + SDVOC_HOTPLUG_INT_STATUS_I915 | \ + PORTB_HOTPLUG_INT_STATUS | \ + PORTC_HOTPLUG_INT_STATUS | \ + PORTD_HOTPLUG_INT_STATUS) + +/* SDVO and HDMI port control. + * The same register may be used for SDVO or HDMI */ +#define GEN3_SDVOB 0x61140 +#define GEN3_SDVOC 0x61160 +#define GEN4_HDMIB GEN3_SDVOB +#define GEN4_HDMIC GEN3_SDVOC +#define PCH_SDVOB 0xe1140 +#define PCH_HDMIB PCH_SDVOB +#define PCH_HDMIC 0xe1150 +#define PCH_HDMID 0xe1160 + +#define PORT_DFT_I9XX 0x61150 +#define DC_BALANCE_RESET (1 << 25) +#define PORT_DFT2_G4X 0x61154 +#define DC_BALANCE_RESET_VLV (1 << 31) +#define PIPE_SCRAMBLE_RESET_MASK (0x3 << 0) +#define PIPE_B_SCRAMBLE_RESET (1 << 1) +#define PIPE_A_SCRAMBLE_RESET (1 << 0) + +/* Gen 3 SDVO bits: */ +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_SEL(pipe) ((pipe) << 30) +#define SDVO_PIPE_SEL_MASK (1 << 30) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) +/** + * 915G/GM SDVO pixel multiplier. + * Programmed value is multiplier - 1, up to 5x. + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) /* Port C only */ +#define SDVO_BORDER_ENABLE (1 << 7) /* SDVO only */ +#define SDVOB_PCIE_CONCURRENCY (1 << 3) /* Port B only */ +#define SDVO_DETECTED (1 << 2) +/* Bits to be preserved when writing */ +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \ + SDVO_INTERRUPT_ENABLE) +#define SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE) + +/* Gen 4 SDVO/HDMI bits: */ +#define SDVO_COLOR_FORMAT_8bpc (0 << 26) +#define SDVO_COLOR_FORMAT_MASK (7 << 26) +#define SDVO_ENCODING_SDVO (0 << 10) +#define SDVO_ENCODING_HDMI (2 << 10) +#define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */ +#define HDMI_MODE_SELECT_DVI (0 << 9) /* HDMI only */ +#define HDMI_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */ +#define SDVO_AUDIO_ENABLE (1 << 6) +/* VSYNC/HSYNC bits new with 965, default is to be set */ +#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) + +/* Gen 5 (IBX) SDVO/HDMI bits: */ +#define HDMI_COLOR_FORMAT_12bpc (3 << 26) /* HDMI only */ +#define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */ + +/* Gen 6 (CPT) SDVO/HDMI bits: */ +#define SDVO_PIPE_SEL_CPT(pipe) ((pipe) << 29) +#define SDVO_PIPE_SEL_MASK_CPT (3 << 29) + + +/* DVO port control */ +#define DVOA 0x61120 +#define DVOB 0x61140 +#define DVOC 0x61160 +#define DVO_ENABLE (1 << 31) +#define DVO_PIPE_B_SELECT (1 << 30) +#define DVO_PIPE_STALL_UNUSED (0 << 28) +#define DVO_PIPE_STALL (1 << 28) +#define DVO_PIPE_STALL_TV (2 << 28) +#define DVO_PIPE_STALL_MASK (3 << 28) +#define DVO_USE_VGA_SYNC (1 << 15) +#define DVO_DATA_ORDER_I740 (0 << 14) +#define DVO_DATA_ORDER_FP (1 << 14) +#define DVO_VSYNC_DISABLE (1 << 11) +#define DVO_HSYNC_DISABLE (1 << 10) +#define DVO_VSYNC_TRISTATE (1 << 9) +#define DVO_HSYNC_TRISTATE (1 << 8) +#define DVO_BORDER_ENABLE (1 << 7) +#define DVO_DATA_ORDER_GBRG (1 << 6) +#define DVO_DATA_ORDER_RGGB (0 << 6) +#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6) +#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6) +#define DVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define DVO_HSYNC_ACTIVE_HIGH (1 << 3) +#define DVO_BLANK_ACTIVE_HIGH (1 << 2) +#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ +#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ +#define DVO_PRESERVE_MASK (0x7<<24) +#define DVOA_SRCDIM 0x61124 +#define DVOB_SRCDIM 0x61144 +#define DVOC_SRCDIM 0x61164 +#define DVO_SRCDIM_HORIZONTAL_SHIFT 12 +#define DVO_SRCDIM_VERTICAL_SHIFT 0 + +/* LVDS port control */ +#define LVDS 0x61180 +/* + * Enables the LVDS port. This bit must be set before DPLLs are enabled, as + * the DPLL semantics change when the LVDS is assigned to that pipe. + */ +#define LVDS_PORT_EN (1 << 31) +/* Selects pipe B for LVDS data. Must be set on pre-965. */ +#define LVDS_PIPEB_SELECT (1 << 30) +#define LVDS_PIPE_MASK (1 << 30) +#define LVDS_PIPE(pipe) ((pipe) << 30) +/* LVDS dithering flag on 965/g4x platform */ +#define LVDS_ENABLE_DITHER (1 << 25) +/* LVDS sync polarity flags. Set to invert (i.e. negative) */ +#define LVDS_VSYNC_POLARITY (1 << 21) +#define LVDS_HSYNC_POLARITY (1 << 20) + +/* Enable border for unscaled (or aspect-scaled) display */ +#define LVDS_BORDER_ENABLE (1 << 15) +/* + * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per + * pixel. + */ +#define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +#define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +#define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +/* + * Controls the A3 data pair, which contains the additional LSBs for 24 bit + * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be + * on. + */ +#define LVDS_A3_POWER_MASK (3 << 6) +#define LVDS_A3_POWER_DOWN (0 << 6) +#define LVDS_A3_POWER_UP (3 << 6) +/* + * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP + * is set. + */ +#define LVDS_CLKB_POWER_MASK (3 << 4) +#define LVDS_CLKB_POWER_DOWN (0 << 4) +#define LVDS_CLKB_POWER_UP (3 << 4) +/* + * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 + * setting for whether we are in dual-channel mode. The B3 pair will + * additionally only be powered up when LVDS_A3_POWER_UP is set. + */ +#define LVDS_B0B3_POWER_MASK (3 << 2) +#define LVDS_B0B3_POWER_DOWN (0 << 2) +#define LVDS_B0B3_POWER_UP (3 << 2) + +/* Video Data Island Packet control */ +#define VIDEO_DIP_DATA 0x61178 +/* Read the description of VIDEO_DIP_DATA (before Haswel) or VIDEO_DIP_ECC + * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte + * of the infoframe structure specified by CEA-861. */ +#define VIDEO_DIP_DATA_SIZE 32 +#define VIDEO_DIP_VSC_DATA_SIZE 36 +#define VIDEO_DIP_CTL 0x61170 +/* Pre HSW: */ +#define VIDEO_DIP_ENABLE (1 << 31) +#define VIDEO_DIP_PORT_B (1 << 29) +#define VIDEO_DIP_PORT_C (2 << 29) +#define VIDEO_DIP_PORT_D (3 << 29) +#define VIDEO_DIP_PORT_MASK (3 << 29) +#define VIDEO_DIP_ENABLE_GCP (1 << 25) +#define VIDEO_DIP_ENABLE_AVI (1 << 21) +#define VIDEO_DIP_ENABLE_VENDOR (2 << 21) +#define VIDEO_DIP_ENABLE_GAMUT (4 << 21) +#define VIDEO_DIP_ENABLE_SPD (8 << 21) +#define VIDEO_DIP_SELECT_AVI (0 << 19) +#define VIDEO_DIP_SELECT_VENDOR (1 << 19) +#define VIDEO_DIP_SELECT_SPD (3 << 19) +#define VIDEO_DIP_SELECT_MASK (3 << 19) +#define VIDEO_DIP_FREQ_ONCE (0 << 16) +#define VIDEO_DIP_FREQ_VSYNC (1 << 16) +#define VIDEO_DIP_FREQ_2VSYNC (2 << 16) +#define VIDEO_DIP_FREQ_MASK (3 << 16) +/* HSW and later: */ +#define VIDEO_DIP_ENABLE_VSC_HSW (1 << 20) +#define VIDEO_DIP_ENABLE_GCP_HSW (1 << 16) +#define VIDEO_DIP_ENABLE_AVI_HSW (1 << 12) +#define VIDEO_DIP_ENABLE_VS_HSW (1 << 8) +#define VIDEO_DIP_ENABLE_GMP_HSW (1 << 4) +#define VIDEO_DIP_ENABLE_SPD_HSW (1 << 0) + +/* Panel power sequencing */ +#define PP_STATUS 0x61200 +#define PP_ON (1 << 31) +/* + * Indicates that all dependencies of the panel are on: + * + * - PLL enabled + * - pipe enabled + * - LVDS/DVOB/DVOC on + */ +#define PP_READY (1 << 30) +#define PP_SEQUENCE_NONE (0 << 28) +#define PP_SEQUENCE_POWER_UP (1 << 28) +#define PP_SEQUENCE_POWER_DOWN (2 << 28) +#define PP_SEQUENCE_MASK (3 << 28) +#define PP_SEQUENCE_SHIFT 28 +#define PP_CYCLE_DELAY_ACTIVE (1 << 27) +#define PP_SEQUENCE_STATE_MASK 0x0000000f +#define PP_SEQUENCE_STATE_OFF_IDLE (0x0 << 0) +#define PP_SEQUENCE_STATE_OFF_S0_1 (0x1 << 0) +#define PP_SEQUENCE_STATE_OFF_S0_2 (0x2 << 0) +#define PP_SEQUENCE_STATE_OFF_S0_3 (0x3 << 0) +#define PP_SEQUENCE_STATE_ON_IDLE (0x8 << 0) +#define PP_SEQUENCE_STATE_ON_S1_0 (0x9 << 0) +#define PP_SEQUENCE_STATE_ON_S1_2 (0xa << 0) +#define PP_SEQUENCE_STATE_ON_S1_3 (0xb << 0) +#define PP_SEQUENCE_STATE_RESET (0xf << 0) +#define PP_CONTROL 0x61204 +#define POWER_TARGET_ON (1 << 0) +#define PP_ON_DELAYS 0x61208 +#define PP_OFF_DELAYS 0x6120c +#define PP_DIVISOR 0x61210 + +/* Panel fitting */ +#define PFIT_CONTROL (dev_priv->info->display_mmio_offset + 0x61230) +#define PFIT_ENABLE (1 << 31) +#define PFIT_PIPE_MASK (3 << 29) +#define PFIT_PIPE_SHIFT 29 +#define VERT_INTERP_DISABLE (0 << 10) +#define VERT_INTERP_BILINEAR (1 << 10) +#define VERT_INTERP_MASK (3 << 10) +#define VERT_AUTO_SCALE (1 << 9) +#define HORIZ_INTERP_DISABLE (0 << 6) +#define HORIZ_INTERP_BILINEAR (1 << 6) +#define HORIZ_INTERP_MASK (3 << 6) +#define HORIZ_AUTO_SCALE (1 << 5) +#define PANEL_8TO6_DITHER_ENABLE (1 << 3) +#define PFIT_FILTER_FUZZY (0 << 24) +#define PFIT_SCALING_AUTO (0 << 26) +#define PFIT_SCALING_PROGRAMMED (1 << 26) +#define PFIT_SCALING_PILLAR (2 << 26) +#define PFIT_SCALING_LETTER (3 << 26) +#define PFIT_PGM_RATIOS (dev_priv->info->display_mmio_offset + 0x61234) +/* Pre-965 */ +#define PFIT_VERT_SCALE_SHIFT 20 +#define PFIT_VERT_SCALE_MASK 0xfff00000 +#define PFIT_HORIZ_SCALE_SHIFT 4 +#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +/* 965+ */ +#define PFIT_VERT_SCALE_SHIFT_965 16 +#define PFIT_VERT_SCALE_MASK_965 0x1fff0000 +#define PFIT_HORIZ_SCALE_SHIFT_965 0 +#define PFIT_HORIZ_SCALE_MASK_965 0x00001fff + +#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) + +#define _VLV_BLC_PWM_CTL2_A (dev_priv->info->display_mmio_offset + 0x61250) +#define _VLV_BLC_PWM_CTL2_B (dev_priv->info->display_mmio_offset + 0x61350) +#define VLV_BLC_PWM_CTL2(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \ + _VLV_BLC_PWM_CTL2_B) + +#define _VLV_BLC_PWM_CTL_A (dev_priv->info->display_mmio_offset + 0x61254) +#define _VLV_BLC_PWM_CTL_B (dev_priv->info->display_mmio_offset + 0x61354) +#define VLV_BLC_PWM_CTL(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL_A, \ + _VLV_BLC_PWM_CTL_B) + +#define _VLV_BLC_HIST_CTL_A (dev_priv->info->display_mmio_offset + 0x61260) +#define _VLV_BLC_HIST_CTL_B (dev_priv->info->display_mmio_offset + 0x61360) +#define VLV_BLC_HIST_CTL(pipe) _PIPE(pipe, _VLV_BLC_HIST_CTL_A, \ + _VLV_BLC_HIST_CTL_B) + +/* Backlight control */ +#define BLC_PWM_CTL2 (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */ +#define BLM_PWM_ENABLE (1 << 31) +#define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */ +#define BLM_PIPE_SELECT (1 << 29) +#define BLM_PIPE_SELECT_IVB (3 << 29) +#define BLM_PIPE_A (0 << 29) +#define BLM_PIPE_B (1 << 29) +#define BLM_PIPE_C (2 << 29) /* ivb + */ +#define BLM_TRANSCODER_A BLM_PIPE_A /* hsw */ +#define BLM_TRANSCODER_B BLM_PIPE_B +#define BLM_TRANSCODER_C BLM_PIPE_C +#define BLM_TRANSCODER_EDP (3 << 29) +#define BLM_PIPE(pipe) ((pipe) << 29) +#define BLM_POLARITY_I965 (1 << 28) /* gen4 only */ +#define BLM_PHASE_IN_INTERUPT_STATUS (1 << 26) +#define BLM_PHASE_IN_ENABLE (1 << 25) +#define BLM_PHASE_IN_INTERUPT_ENABL (1 << 24) +#define BLM_PHASE_IN_TIME_BASE_SHIFT (16) +#define BLM_PHASE_IN_TIME_BASE_MASK (0xff << 16) +#define BLM_PHASE_IN_COUNT_SHIFT (8) +#define BLM_PHASE_IN_COUNT_MASK (0xff << 8) +#define BLM_PHASE_IN_INCR_SHIFT (0) +#define BLM_PHASE_IN_INCR_MASK (0xff << 0) +#define BLC_PWM_CTL (dev_priv->info->display_mmio_offset + 0x61254) +/* + * This is the most significant 15 bits of the number of backlight cycles in a + * complete cycle of the modulated backlight control. + * + * The actual value is this field multiplied by two. + */ +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) +#define BLM_LEGACY_MODE (1 << 16) /* gen2 only */ +/* + * This is the number of cycles out of the backlight modulation cycle for which + * the backlight is on. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. + */ +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) +#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe) +#define BLM_POLARITY_PNV (1 << 0) /* pnv only */ + +#define BLC_HIST_CTL (dev_priv->info->display_mmio_offset + 0x61260) + +/* New registers for PCH-split platforms. Safe where new bits show up, the + * register layout machtes with gen4 BLC_PWM_CTL[12]. */ +#define BLC_PWM_CPU_CTL2 0x48250 +#define BLC_PWM_CPU_CTL 0x48254 + +#define HSW_BLC_PWM2_CTL 0x48350 + +/* PCH CTL1 is totally different, all but the below bits are reserved. CTL2 is + * like the normal CTL from gen4 and earlier. Hooray for confusing naming. */ +#define BLC_PWM_PCH_CTL1 0xc8250 +#define BLM_PCH_PWM_ENABLE (1 << 31) +#define BLM_PCH_OVERRIDE_ENABLE (1 << 30) +#define BLM_PCH_POLARITY (1 << 29) +#define BLC_PWM_PCH_CTL2 0xc8254 + +#define UTIL_PIN_CTL 0x48400 +#define UTIL_PIN_ENABLE (1 << 31) + +#define PCH_GTC_CTL 0xe7000 +#define PCH_GTC_ENABLE (1 << 31) + +/* TV port control */ +#define TV_CTL 0x68000 +/** Enables the TV encoder */ +# define TV_ENC_ENABLE (1 << 31) +/** Sources the TV encoder input from pipe B instead of A. */ +# define TV_ENC_PIPEB_SELECT (1 << 30) +/** Outputs composite video (DAC A only) */ +# define TV_ENC_OUTPUT_COMPOSITE (0 << 28) +/** Outputs SVideo video (DAC B/C) */ +# define TV_ENC_OUTPUT_SVIDEO (1 << 28) +/** Outputs Component video (DAC A/B/C) */ +# define TV_ENC_OUTPUT_COMPONENT (2 << 28) +/** Outputs Composite and SVideo (DAC A/B/C) */ +# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE (3 << 28) +# define TV_TRILEVEL_SYNC (1 << 21) +/** Enables slow sync generation (945GM only) */ +# define TV_SLOW_SYNC (1 << 20) +/** Selects 4x oversampling for 480i and 576p */ +# define TV_OVERSAMPLE_4X (0 << 18) +/** Selects 2x oversampling for 720p and 1080i */ +# define TV_OVERSAMPLE_2X (1 << 18) +/** Selects no oversampling for 1080p */ +# define TV_OVERSAMPLE_NONE (2 << 18) +/** Selects 8x oversampling */ +# define TV_OVERSAMPLE_8X (3 << 18) +/** Selects progressive mode rather than interlaced */ +# define TV_PROGRESSIVE (1 << 17) +/** Sets the colorburst to PAL mode. Required for non-M PAL modes. */ +# define TV_PAL_BURST (1 << 16) +/** Field for setting delay of Y compared to C */ +# define TV_YC_SKEW_MASK (7 << 12) +/** Enables a fix for 480p/576p standard definition modes on the 915GM only */ +# define TV_ENC_SDP_FIX (1 << 11) +/** + * Enables a fix for the 915GM only. + * + * Not sure what it does. + */ +# define TV_ENC_C0_FIX (1 << 10) +/** Bits that must be preserved by software */ +# define TV_CTL_SAVE ((1 << 11) | (3 << 9) | (7 << 6) | 0xf) +# define TV_FUSE_STATE_MASK (3 << 4) +/** Read-only state that reports all features enabled */ +# define TV_FUSE_STATE_ENABLED (0 << 4) +/** Read-only state that reports that Macrovision is disabled in hardware*/ +# define TV_FUSE_STATE_NO_MACROVISION (1 << 4) +/** Read-only state that reports that TV-out is disabled in hardware. */ +# define TV_FUSE_STATE_DISABLED (2 << 4) +/** Normal operation */ +# define TV_TEST_MODE_NORMAL (0 << 0) +/** Encoder test pattern 1 - combo pattern */ +# define TV_TEST_MODE_PATTERN_1 (1 << 0) +/** Encoder test pattern 2 - full screen vertical 75% color bars */ +# define TV_TEST_MODE_PATTERN_2 (2 << 0) +/** Encoder test pattern 3 - full screen horizontal 75% color bars */ +# define TV_TEST_MODE_PATTERN_3 (3 << 0) +/** Encoder test pattern 4 - random noise */ +# define TV_TEST_MODE_PATTERN_4 (4 << 0) +/** Encoder test pattern 5 - linear color ramps */ +# define TV_TEST_MODE_PATTERN_5 (5 << 0) +/** + * This test mode forces the DACs to 50% of full output. + * + * This is used for load detection in combination with TVDAC_SENSE_MASK + */ +# define TV_TEST_MODE_MONITOR_DETECT (7 << 0) +# define TV_TEST_MODE_MASK (7 << 0) + +#define TV_DAC 0x68004 +# define TV_DAC_SAVE 0x00ffff00 +/** + * Reports that DAC state change logic has reported change (RO). + * + * This gets cleared when TV_DAC_STATE_EN is cleared +*/ +# define TVDAC_STATE_CHG (1 << 31) +# define TVDAC_SENSE_MASK (7 << 28) +/** Reports that DAC A voltage is above the detect threshold */ +# define TVDAC_A_SENSE (1 << 30) +/** Reports that DAC B voltage is above the detect threshold */ +# define TVDAC_B_SENSE (1 << 29) +/** Reports that DAC C voltage is above the detect threshold */ +# define TVDAC_C_SENSE (1 << 28) +/** + * Enables DAC state detection logic, for load-based TV detection. + * + * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set + * to off, for load detection to work. + */ +# define TVDAC_STATE_CHG_EN (1 << 27) +/** Sets the DAC A sense value to high */ +# define TVDAC_A_SENSE_CTL (1 << 26) +/** Sets the DAC B sense value to high */ +# define TVDAC_B_SENSE_CTL (1 << 25) +/** Sets the DAC C sense value to high */ +# define TVDAC_C_SENSE_CTL (1 << 24) +/** Overrides the ENC_ENABLE and DAC voltage levels */ +# define DAC_CTL_OVERRIDE (1 << 7) +/** Sets the slew rate. Must be preserved in software */ +# define ENC_TVDAC_SLEW_FAST (1 << 6) +# define DAC_A_1_3_V (0 << 4) +# define DAC_A_1_1_V (1 << 4) +# define DAC_A_0_7_V (2 << 4) +# define DAC_A_MASK (3 << 4) +# define DAC_B_1_3_V (0 << 2) +# define DAC_B_1_1_V (1 << 2) +# define DAC_B_0_7_V (2 << 2) +# define DAC_B_MASK (3 << 2) +# define DAC_C_1_3_V (0 << 0) +# define DAC_C_1_1_V (1 << 0) +# define DAC_C_0_7_V (2 << 0) +# define DAC_C_MASK (3 << 0) + +/** + * CSC coefficients are stored in a floating point format with 9 bits of + * mantissa and 2 or 3 bits of exponent. The exponent is represented as 2**-n, + * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with + * -1 (0x3) being the only legal negative value. + */ +#define TV_CSC_Y 0x68010 +# define TV_RY_MASK 0x07ff0000 +# define TV_RY_SHIFT 16 +# define TV_GY_MASK 0x00000fff +# define TV_GY_SHIFT 0 + +#define TV_CSC_Y2 0x68014 +# define TV_BY_MASK 0x07ff0000 +# define TV_BY_SHIFT 16 +/** + * Y attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AY_MASK 0x000003ff +# define TV_AY_SHIFT 0 + +#define TV_CSC_U 0x68018 +# define TV_RU_MASK 0x07ff0000 +# define TV_RU_SHIFT 16 +# define TV_GU_MASK 0x000007ff +# define TV_GU_SHIFT 0 + +#define TV_CSC_U2 0x6801c +# define TV_BU_MASK 0x07ff0000 +# define TV_BU_SHIFT 16 +/** + * U attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AU_MASK 0x000003ff +# define TV_AU_SHIFT 0 + +#define TV_CSC_V 0x68020 +# define TV_RV_MASK 0x0fff0000 +# define TV_RV_SHIFT 16 +# define TV_GV_MASK 0x000007ff +# define TV_GV_SHIFT 0 + +#define TV_CSC_V2 0x68024 +# define TV_BV_MASK 0x07ff0000 +# define TV_BV_SHIFT 16 +/** + * V attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AV_MASK 0x000007ff +# define TV_AV_SHIFT 0 + +#define TV_CLR_KNOBS 0x68028 +/** 2s-complement brightness adjustment */ +# define TV_BRIGHTNESS_MASK 0xff000000 +# define TV_BRIGHTNESS_SHIFT 24 +/** Contrast adjustment, as a 2.6 unsigned floating point number */ +# define TV_CONTRAST_MASK 0x00ff0000 +# define TV_CONTRAST_SHIFT 16 +/** Saturation adjustment, as a 2.6 unsigned floating point number */ +# define TV_SATURATION_MASK 0x0000ff00 +# define TV_SATURATION_SHIFT 8 +/** Hue adjustment, as an integer phase angle in degrees */ +# define TV_HUE_MASK 0x000000ff +# define TV_HUE_SHIFT 0 + +#define TV_CLR_LEVEL 0x6802c +/** Controls the DAC level for black */ +# define TV_BLACK_LEVEL_MASK 0x01ff0000 +# define TV_BLACK_LEVEL_SHIFT 16 +/** Controls the DAC level for blanking */ +# define TV_BLANK_LEVEL_MASK 0x000001ff +# define TV_BLANK_LEVEL_SHIFT 0 + +#define TV_H_CTL_1 0x68030 +/** Number of pixels in the hsync. */ +# define TV_HSYNC_END_MASK 0x1fff0000 +# define TV_HSYNC_END_SHIFT 16 +/** Total number of pixels minus one in the line (display and blanking). */ +# define TV_HTOTAL_MASK 0x00001fff +# define TV_HTOTAL_SHIFT 0 + +#define TV_H_CTL_2 0x68034 +/** Enables the colorburst (needed for non-component color) */ +# define TV_BURST_ENA (1 << 31) +/** Offset of the colorburst from the start of hsync, in pixels minus one. */ +# define TV_HBURST_START_SHIFT 16 +# define TV_HBURST_START_MASK 0x1fff0000 +/** Length of the colorburst */ +# define TV_HBURST_LEN_SHIFT 0 +# define TV_HBURST_LEN_MASK 0x0001fff + +#define TV_H_CTL_3 0x68038 +/** End of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_END_SHIFT 16 +# define TV_HBLANK_END_MASK 0x1fff0000 +/** Start of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_START_SHIFT 0 +# define TV_HBLANK_START_MASK 0x0001fff + +#define TV_V_CTL_1 0x6803c +/** XXX */ +# define TV_NBR_END_SHIFT 16 +# define TV_NBR_END_MASK 0x07ff0000 +/** XXX */ +# define TV_VI_END_F1_SHIFT 8 +# define TV_VI_END_F1_MASK 0x00003f00 +/** XXX */ +# define TV_VI_END_F2_SHIFT 0 +# define TV_VI_END_F2_MASK 0x0000003f + +#define TV_V_CTL_2 0x68040 +/** Length of vsync, in half lines */ +# define TV_VSYNC_LEN_MASK 0x07ff0000 +# define TV_VSYNC_LEN_SHIFT 16 +/** Offset of the start of vsync in field 1, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F1_MASK 0x00007f00 +# define TV_VSYNC_START_F1_SHIFT 8 +/** + * Offset of the start of vsync in field 2, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F2_MASK 0x0000007f +# define TV_VSYNC_START_F2_SHIFT 0 + +#define TV_V_CTL_3 0x68044 +/** Enables generation of the equalization signal */ +# define TV_EQUAL_ENA (1 << 31) +/** Length of vsync, in half lines */ +# define TV_VEQ_LEN_MASK 0x007f0000 +# define TV_VEQ_LEN_SHIFT 16 +/** Offset of the start of equalization in field 1, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F1_MASK 0x0007f00 +# define TV_VEQ_START_F1_SHIFT 8 +/** + * Offset of the start of equalization in field 2, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F2_MASK 0x000007f +# define TV_VEQ_START_F2_SHIFT 0 + +#define TV_V_CTL_4 0x68048 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F1_MASK 0x003f0000 +# define TV_VBURST_START_F1_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F1_MASK 0x000000ff +# define TV_VBURST_END_F1_SHIFT 0 + +#define TV_V_CTL_5 0x6804c +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F2_MASK 0x003f0000 +# define TV_VBURST_START_F2_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F2_MASK 0x000000ff +# define TV_VBURST_END_F2_SHIFT 0 + +#define TV_V_CTL_6 0x68050 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F3_MASK 0x003f0000 +# define TV_VBURST_START_F3_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F3_MASK 0x000000ff +# define TV_VBURST_END_F3_SHIFT 0 + +#define TV_V_CTL_7 0x68054 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F4_MASK 0x003f0000 +# define TV_VBURST_START_F4_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F4_MASK 0x000000ff +# define TV_VBURST_END_F4_SHIFT 0 + +#define TV_SC_CTL_1 0x68060 +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA1_EN (1 << 31) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA2_EN (1 << 30) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA3_EN (1 << 29) +/** Sets the subcarrier DDA to reset frequency every other field */ +# define TV_SC_RESET_EVERY_2 (0 << 24) +/** Sets the subcarrier DDA to reset frequency every fourth field */ +# define TV_SC_RESET_EVERY_4 (1 << 24) +/** Sets the subcarrier DDA to reset frequency every eighth field */ +# define TV_SC_RESET_EVERY_8 (2 << 24) +/** Sets the subcarrier DDA to never reset the frequency */ +# define TV_SC_RESET_NEVER (3 << 24) +/** Sets the peak amplitude of the colorburst.*/ +# define TV_BURST_LEVEL_MASK 0x00ff0000 +# define TV_BURST_LEVEL_SHIFT 16 +/** Sets the increment of the first subcarrier phase generation DDA */ +# define TV_SCDDA1_INC_MASK 0x00000fff +# define TV_SCDDA1_INC_SHIFT 0 + +#define TV_SC_CTL_2 0x68064 +/** Sets the rollover for the second subcarrier phase generation DDA */ +# define TV_SCDDA2_SIZE_MASK 0x7fff0000 +# define TV_SCDDA2_SIZE_SHIFT 16 +/** Sets the increent of the second subcarrier phase generation DDA */ +# define TV_SCDDA2_INC_MASK 0x00007fff +# define TV_SCDDA2_INC_SHIFT 0 + +#define TV_SC_CTL_3 0x68068 +/** Sets the rollover for the third subcarrier phase generation DDA */ +# define TV_SCDDA3_SIZE_MASK 0x7fff0000 +# define TV_SCDDA3_SIZE_SHIFT 16 +/** Sets the increent of the third subcarrier phase generation DDA */ +# define TV_SCDDA3_INC_MASK 0x00007fff +# define TV_SCDDA3_INC_SHIFT 0 + +#define TV_WIN_POS 0x68070 +/** X coordinate of the display from the start of horizontal active */ +# define TV_XPOS_MASK 0x1fff0000 +# define TV_XPOS_SHIFT 16 +/** Y coordinate of the display from the start of vertical active (NBR) */ +# define TV_YPOS_MASK 0x00000fff +# define TV_YPOS_SHIFT 0 + +#define TV_WIN_SIZE 0x68074 +/** Horizontal size of the display window, measured in pixels*/ +# define TV_XSIZE_MASK 0x1fff0000 +# define TV_XSIZE_SHIFT 16 +/** + * Vertical size of the display window, measured in pixels. + * + * Must be even for interlaced modes. + */ +# define TV_YSIZE_MASK 0x00000fff +# define TV_YSIZE_SHIFT 0 + +#define TV_FILTER_CTL_1 0x68080 +/** + * Enables automatic scaling calculation. + * + * If set, the rest of the registers are ignored, and the calculated values can + * be read back from the register. + */ +# define TV_AUTO_SCALE (1 << 31) +/** + * Disables the vertical filter. + * + * This is required on modes more than 1024 pixels wide */ +# define TV_V_FILTER_BYPASS (1 << 29) +/** Enables adaptive vertical filtering */ +# define TV_VADAPT (1 << 28) +# define TV_VADAPT_MODE_MASK (3 << 26) +/** Selects the least adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_LEAST (0 << 26) +/** Selects the moderately adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MODERATE (1 << 26) +/** Selects the most adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MOST (3 << 26) +/** + * Sets the horizontal scaling factor. + * + * This should be the fractional part of the horizontal scaling factor divided + * by the oversampling rate. TV_HSCALE should be less than 1, and set to: + * + * (src width - 1) / ((oversample * dest width) - 1) + */ +# define TV_HSCALE_FRAC_MASK 0x00003fff +# define TV_HSCALE_FRAC_SHIFT 0 + +#define TV_FILTER_CTL_2 0x68084 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1) + */ +# define TV_VSCALE_INT_MASK 0x00038000 +# define TV_VSCALE_INT_SHIFT 15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * \sa TV_VSCALE_INT_MASK + */ +# define TV_VSCALE_FRAC_MASK 0x00007fff +# define TV_VSCALE_FRAC_SHIFT 0 + +#define TV_FILTER_CTL_3 0x68088 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1)) + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + */ +# define TV_VSCALE_IP_INT_MASK 0x00038000 +# define TV_VSCALE_IP_INT_SHIFT 15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + * + * \sa TV_VSCALE_IP_INT_MASK + */ +# define TV_VSCALE_IP_FRAC_MASK 0x00007fff +# define TV_VSCALE_IP_FRAC_SHIFT 0 + +#define TV_CC_CONTROL 0x68090 +# define TV_CC_ENABLE (1 << 31) +/** + * Specifies which field to send the CC data in. + * + * CC data is usually sent in field 0. + */ +# define TV_CC_FID_MASK (1 << 27) +# define TV_CC_FID_SHIFT 27 +/** Sets the horizontal position of the CC data. Usually 135. */ +# define TV_CC_HOFF_MASK 0x03ff0000 +# define TV_CC_HOFF_SHIFT 16 +/** Sets the vertical position of the CC data. Usually 21 */ +# define TV_CC_LINE_MASK 0x0000003f +# define TV_CC_LINE_SHIFT 0 + +#define TV_CC_DATA 0x68094 +# define TV_CC_RDY (1 << 31) +/** Second word of CC data to be transmitted. */ +# define TV_CC_DATA_2_MASK 0x007f0000 +# define TV_CC_DATA_2_SHIFT 16 +/** First word of CC data to be transmitted. */ +# define TV_CC_DATA_1_MASK 0x0000007f +# define TV_CC_DATA_1_SHIFT 0 + +#define TV_H_LUMA_0 0x68100 +#define TV_H_LUMA_59 0x681ec +#define TV_H_CHROMA_0 0x68200 +#define TV_H_CHROMA_59 0x682ec +#define TV_V_LUMA_0 0x68300 +#define TV_V_LUMA_42 0x683a8 +#define TV_V_CHROMA_0 0x68400 +#define TV_V_CHROMA_42 0x684a8 + +/* Display Port */ +#define DP_A 0x64000 /* eDP */ +#define DP_B 0x64100 +#define DP_C 0x64200 +#define DP_D 0x64300 + +#define DP_PORT_EN (1 << 31) +#define DP_PIPEB_SELECT (1 << 30) +#define DP_PIPE_MASK (1 << 30) + +/* Link training mode - select a suitable mode for each stage */ +#define DP_LINK_TRAIN_PAT_1 (0 << 28) +#define DP_LINK_TRAIN_PAT_2 (1 << 28) +#define DP_LINK_TRAIN_PAT_IDLE (2 << 28) +#define DP_LINK_TRAIN_OFF (3 << 28) +#define DP_LINK_TRAIN_MASK (3 << 28) +#define DP_LINK_TRAIN_SHIFT 28 + +/* CPT Link training mode */ +#define DP_LINK_TRAIN_PAT_1_CPT (0 << 8) +#define DP_LINK_TRAIN_PAT_2_CPT (1 << 8) +#define DP_LINK_TRAIN_PAT_IDLE_CPT (2 << 8) +#define DP_LINK_TRAIN_OFF_CPT (3 << 8) +#define DP_LINK_TRAIN_MASK_CPT (7 << 8) +#define DP_LINK_TRAIN_SHIFT_CPT 8 + +/* Signal voltages. These are mostly controlled by the other end */ +#define DP_VOLTAGE_0_4 (0 << 25) +#define DP_VOLTAGE_0_6 (1 << 25) +#define DP_VOLTAGE_0_8 (2 << 25) +#define DP_VOLTAGE_1_2 (3 << 25) +#define DP_VOLTAGE_MASK (7 << 25) +#define DP_VOLTAGE_SHIFT 25 + +/* Signal pre-emphasis levels, like voltages, the other end tells us what + * they want + */ +#define DP_PRE_EMPHASIS_0 (0 << 22) +#define DP_PRE_EMPHASIS_3_5 (1 << 22) +#define DP_PRE_EMPHASIS_6 (2 << 22) +#define DP_PRE_EMPHASIS_9_5 (3 << 22) +#define DP_PRE_EMPHASIS_MASK (7 << 22) +#define DP_PRE_EMPHASIS_SHIFT 22 + +/* How many wires to use. I guess 3 was too hard */ +#define DP_PORT_WIDTH(width) (((width) - 1) << 19) +#define DP_PORT_WIDTH_MASK (7 << 19) + +/* Mystic DPCD version 1.1 special mode */ +#define DP_ENHANCED_FRAMING (1 << 18) + +/* eDP */ +#define DP_PLL_FREQ_270MHZ (0 << 16) +#define DP_PLL_FREQ_160MHZ (1 << 16) +#define DP_PLL_FREQ_MASK (3 << 16) + +/** locked once port is enabled */ +#define DP_PORT_REVERSAL (1 << 15) + +/* eDP */ +#define DP_PLL_ENABLE (1 << 14) + +/** sends the clock on lane 15 of the PEG for debug */ +#define DP_CLOCK_OUTPUT_ENABLE (1 << 13) + +#define DP_SCRAMBLING_DISABLE (1 << 12) +#define DP_SCRAMBLING_DISABLE_IRONLAKE (1 << 7) + +/** limit RGB values to avoid confusing TVs */ +#define DP_COLOR_RANGE_16_235 (1 << 8) + +/** Turn on the audio link */ +#define DP_AUDIO_OUTPUT_ENABLE (1 << 6) + +/** vs and hs sync polarity */ +#define DP_SYNC_VS_HIGH (1 << 4) +#define DP_SYNC_HS_HIGH (1 << 3) + +/** A fantasy */ +#define DP_DETECTED (1 << 2) + +/** The aux channel provides a way to talk to the + * signal sink for DDC etc. Max packet size supported + * is 20 bytes in each direction, hence the 5 fixed + * data registers + */ +#define DPA_AUX_CH_CTL 0x64010 +#define DPA_AUX_CH_DATA1 0x64014 +#define DPA_AUX_CH_DATA2 0x64018 +#define DPA_AUX_CH_DATA3 0x6401c +#define DPA_AUX_CH_DATA4 0x64020 +#define DPA_AUX_CH_DATA5 0x64024 + +#define DPB_AUX_CH_CTL 0x64110 +#define DPB_AUX_CH_DATA1 0x64114 +#define DPB_AUX_CH_DATA2 0x64118 +#define DPB_AUX_CH_DATA3 0x6411c +#define DPB_AUX_CH_DATA4 0x64120 +#define DPB_AUX_CH_DATA5 0x64124 + +#define DPC_AUX_CH_CTL 0x64210 +#define DPC_AUX_CH_DATA1 0x64214 +#define DPC_AUX_CH_DATA2 0x64218 +#define DPC_AUX_CH_DATA3 0x6421c +#define DPC_AUX_CH_DATA4 0x64220 +#define DPC_AUX_CH_DATA5 0x64224 + +#define DPD_AUX_CH_CTL 0x64310 +#define DPD_AUX_CH_DATA1 0x64314 +#define DPD_AUX_CH_DATA2 0x64318 +#define DPD_AUX_CH_DATA3 0x6431c +#define DPD_AUX_CH_DATA4 0x64320 +#define DPD_AUX_CH_DATA5 0x64324 + +#define DP_AUX_CH_CTL_SEND_BUSY (1 << 31) +#define DP_AUX_CH_CTL_DONE (1 << 30) +#define DP_AUX_CH_CTL_INTERRUPT (1 << 29) +#define DP_AUX_CH_CTL_TIME_OUT_ERROR (1 << 28) +#define DP_AUX_CH_CTL_TIME_OUT_400us (0 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_600us (1 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_800us (2 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_1600us (3 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_MASK (3 << 26) +#define DP_AUX_CH_CTL_RECEIVE_ERROR (1 << 25) +#define DP_AUX_CH_CTL_MESSAGE_SIZE_MASK (0x1f << 20) +#define DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT 20 +#define DP_AUX_CH_CTL_PRECHARGE_2US_MASK (0xf << 16) +#define DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT 16 +#define DP_AUX_CH_CTL_AUX_AKSV_SELECT (1 << 15) +#define DP_AUX_CH_CTL_MANCHESTER_TEST (1 << 14) +#define DP_AUX_CH_CTL_SYNC_TEST (1 << 13) +#define DP_AUX_CH_CTL_DEGLITCH_TEST (1 << 12) +#define DP_AUX_CH_CTL_PRECHARGE_TEST (1 << 11) +#define DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK (0x7ff) +#define DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT 0 + +/* + * Computing GMCH M and N values for the Display Port link + * + * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes + * + * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz) + * + * The GMCH value is used internally + * + * bytes_per_pixel is the number of bytes coming out of the plane, + * which is after the LUTs, so we want the bytes for our color format. + * For our current usage, this is always 3, one byte for R, G and B. + */ +#define _PIPEA_DATA_M_G4X 0x70050 +#define _PIPEB_DATA_M_G4X 0x71050 + +/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ +#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ +#define TU_SIZE_SHIFT 25 +#define TU_SIZE_MASK (0x3f << 25) + +#define DATA_LINK_M_N_MASK (0xffffff) +#define DATA_LINK_N_MAX (0x800000) + +#define _PIPEA_DATA_N_G4X 0x70054 +#define _PIPEB_DATA_N_G4X 0x71054 +#define PIPE_GMCH_DATA_N_MASK (0xffffff) + +/* + * Computing Link M and N values for the Display Port link + * + * Link M / N = pixel_clock / ls_clk + * + * (the DP spec calls pixel_clock the 'strm_clk') + * + * The Link value is transmitted in the Main Stream + * Attributes and VB-ID. + */ + +#define _PIPEA_LINK_M_G4X 0x70060 +#define _PIPEB_LINK_M_G4X 0x71060 +#define PIPEA_DP_LINK_M_MASK (0xffffff) + +#define _PIPEA_LINK_N_G4X 0x70064 +#define _PIPEB_LINK_N_G4X 0x71064 +#define PIPEA_DP_LINK_N_MASK (0xffffff) + +#define PIPE_DATA_M_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X) +#define PIPE_DATA_N_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X) +#define PIPE_LINK_M_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X) +#define PIPE_LINK_N_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X) + +/* Display & cursor control */ + +/* Pipe A */ +#define _PIPEADSL (dev_priv->info->display_mmio_offset + 0x70000) +#define DSL_LINEMASK_GEN2 0x00000fff +#define DSL_LINEMASK_GEN3 0x00001fff +#define _PIPEACONF (dev_priv->info->display_mmio_offset + 0x70008) +#define PIPECONF_ENABLE (1<<31) +#define PIPECONF_DISABLE 0 +#define PIPECONF_DOUBLE_WIDE (1<<30) +#define I965_PIPECONF_ACTIVE (1<<30) +#define PIPECONF_DSI_PLL_LOCKED (1<<29) /* vlv & pipe A only */ +#define PIPECONF_FRAME_START_DELAY_MASK (3<<27) +#define PIPECONF_SINGLE_WIDE 0 +#define PIPECONF_PIPE_UNLOCKED 0 +#define PIPECONF_PIPE_LOCKED (1<<25) +#define PIPECONF_PALETTE 0 +#define PIPECONF_GAMMA (1<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_INTERLACE_MASK (7 << 21) +#define PIPECONF_INTERLACE_MASK_HSW (3 << 21) +/* Note that pre-gen3 does not support interlaced display directly. Panel + * fitting must be disabled on pre-ilk for interlaced. */ +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_SYNC_SHIFT_PANEL (4 << 21) /* gen4 only */ +#define PIPECONF_INTERLACE_W_SYNC_SHIFT (5 << 21) /* gen4 only */ +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) /* gen3 only */ +/* Ironlake and later have a complete new set of values for interlaced. PFIT + * means panel fitter required, PF means progressive fetch, DBL means power + * saving pixel doubling. */ +#define PIPECONF_PFIT_PF_INTERLACED_ILK (1 << 21) +#define PIPECONF_INTERLACED_ILK (3 << 21) +#define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ +#define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ +#define PIPECONF_INTERLACE_MODE_MASK (7 << 21) +#define PIPECONF_CXSR_DOWNCLOCK (1<<16) +#define PIPECONF_COLOR_RANGE_SELECT (1 << 13) +#define PIPECONF_BPC_MASK (0x7 << 5) +#define PIPECONF_8BPC (0<<5) +#define PIPECONF_10BPC (1<<5) +#define PIPECONF_6BPC (2<<5) +#define PIPECONF_12BPC (3<<5) +#define PIPECONF_DITHER_EN (1<<4) +#define PIPECONF_DITHER_TYPE_MASK (0x0000000c) +#define PIPECONF_DITHER_TYPE_SP (0<<2) +#define PIPECONF_DITHER_TYPE_ST1 (1<<2) +#define PIPECONF_DITHER_TYPE_ST2 (2<<2) +#define PIPECONF_DITHER_TYPE_TEMP (3<<2) +#define _PIPEASTAT (dev_priv->info->display_mmio_offset + 0x70024) +#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) +#define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30) +#define PIPE_CRC_ERROR_ENABLE (1UL<<29) +#define PIPE_CRC_DONE_ENABLE (1UL<<28) +#define PIPE_GMBUS_EVENT_ENABLE (1UL<<27) +#define PLANE_FLIP_DONE_INT_EN_VLV (1UL<<26) +#define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) +#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) +#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) +#define PIPE_DPST_EVENT_ENABLE (1UL<<23) +#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<22) +#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) +#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) +#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) +#define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ +#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) +#define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) +#define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15) +#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<14) +#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) +#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) +#define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) +#define PLANE_FLIPDONE_INT_STATUS_VLV (1UL<<10) +#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) +#define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9) +#define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) +#define PIPE_DPST_EVENT_STATUS (1UL<<7) +#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) +#define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) +#define PIPE_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) +#define PIPE_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ +#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) +#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) + +#define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC) +#define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF) +#define PIPEDSL(pipe) _PIPE(pipe, _PIPEADSL, _PIPEBDSL) +#define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH) +#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) +#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT) + +#define _PIPE_MISC_A 0x70030 +#define _PIPE_MISC_B 0x71030 +#define PIPEMISC_DITHER_BPC_MASK (7<<5) +#define PIPEMISC_DITHER_8_BPC (0<<5) +#define PIPEMISC_DITHER_10_BPC (1<<5) +#define PIPEMISC_DITHER_6_BPC (2<<5) +#define PIPEMISC_DITHER_12_BPC (3<<5) +#define PIPEMISC_DITHER_ENABLE (1<<4) +#define PIPEMISC_DITHER_TYPE_MASK (3<<2) +#define PIPEMISC_DITHER_TYPE_SP (0<<2) +#define PIPEMISC(pipe) _PIPE(pipe, _PIPE_MISC_A, _PIPE_MISC_B) + +#define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028) +#define PIPEB_LINE_COMPARE_INT_EN (1<<29) +#define PIPEB_HLINE_INT_EN (1<<28) +#define PIPEB_VBLANK_INT_EN (1<<27) +#define SPRITED_FLIPDONE_INT_EN (1<<26) +#define SPRITEC_FLIPDONE_INT_EN (1<<25) +#define PLANEB_FLIPDONE_INT_EN (1<<24) +#define PIPEA_LINE_COMPARE_INT_EN (1<<21) +#define PIPEA_HLINE_INT_EN (1<<20) +#define PIPEA_VBLANK_INT_EN (1<<19) +#define SPRITEB_FLIPDONE_INT_EN (1<<18) +#define SPRITEA_FLIPDONE_INT_EN (1<<17) +#define PLANEA_FLIPDONE_INT_EN (1<<16) + +#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */ +#define CURSORB_INVALID_GTT_INT_EN (1<<23) +#define CURSORA_INVALID_GTT_INT_EN (1<<22) +#define SPRITED_INVALID_GTT_INT_EN (1<<21) +#define SPRITEC_INVALID_GTT_INT_EN (1<<20) +#define PLANEB_INVALID_GTT_INT_EN (1<<19) +#define SPRITEB_INVALID_GTT_INT_EN (1<<18) +#define SPRITEA_INVALID_GTT_INT_EN (1<<17) +#define PLANEA_INVALID_GTT_INT_EN (1<<16) +#define DPINVGTT_EN_MASK 0xff0000 +#define CURSORB_INVALID_GTT_STATUS (1<<7) +#define CURSORA_INVALID_GTT_STATUS (1<<6) +#define SPRITED_INVALID_GTT_STATUS (1<<5) +#define SPRITEC_INVALID_GTT_STATUS (1<<4) +#define PLANEB_INVALID_GTT_STATUS (1<<3) +#define SPRITEB_INVALID_GTT_STATUS (1<<2) +#define SPRITEA_INVALID_GTT_STATUS (1<<1) +#define PLANEA_INVALID_GTT_STATUS (1<<0) +#define DPINVGTT_STATUS_MASK 0xff + +#define DSPARB 0x70030 +#define DSPARB_CSTART_MASK (0x7f << 7) +#define DSPARB_CSTART_SHIFT 7 +#define DSPARB_BSTART_MASK (0x7f) +#define DSPARB_BSTART_SHIFT 0 +#define DSPARB_BEND_SHIFT 9 /* on 855 */ +#define DSPARB_AEND_SHIFT 0 + +#define DSPFW1 (dev_priv->info->display_mmio_offset + 0x70034) +#define DSPFW_SR_SHIFT 23 +#define DSPFW_SR_MASK (0x1ff<<23) +#define DSPFW_CURSORB_SHIFT 16 +#define DSPFW_CURSORB_MASK (0x3f<<16) +#define DSPFW_PLANEB_SHIFT 8 +#define DSPFW_PLANEB_MASK (0x7f<<8) +#define DSPFW_PLANEA_MASK (0x7f) +#define DSPFW2 (dev_priv->info->display_mmio_offset + 0x70038) +#define DSPFW_CURSORA_MASK 0x00003f00 +#define DSPFW_CURSORA_SHIFT 8 +#define DSPFW_PLANEC_MASK (0x7f) +#define DSPFW3 (dev_priv->info->display_mmio_offset + 0x7003c) +#define DSPFW_HPLL_SR_EN (1<<31) +#define DSPFW_CURSOR_SR_SHIFT 24 +#define PINEVIEW_SELF_REFRESH_EN (1<<30) +#define DSPFW_CURSOR_SR_MASK (0x3f<<24) +#define DSPFW_HPLL_CURSOR_SHIFT 16 +#define DSPFW_HPLL_CURSOR_MASK (0x3f<<16) +#define DSPFW_HPLL_SR_MASK (0x1ff) +#define DSPFW4 (dev_priv->info->display_mmio_offset + 0x70070) +#define DSPFW7 (dev_priv->info->display_mmio_offset + 0x7007c) + +/* drain latency register values*/ +#define DRAIN_LATENCY_PRECISION_32 32 +#define DRAIN_LATENCY_PRECISION_16 16 +#define VLV_DDL1 (VLV_DISPLAY_BASE + 0x70050) +#define DDL_CURSORA_PRECISION_32 (1<<31) +#define DDL_CURSORA_PRECISION_16 (0<<31) +#define DDL_CURSORA_SHIFT 24 +#define DDL_PLANEA_PRECISION_32 (1<<7) +#define DDL_PLANEA_PRECISION_16 (0<<7) +#define VLV_DDL2 (VLV_DISPLAY_BASE + 0x70054) +#define DDL_CURSORB_PRECISION_32 (1<<31) +#define DDL_CURSORB_PRECISION_16 (0<<31) +#define DDL_CURSORB_SHIFT 24 +#define DDL_PLANEB_PRECISION_32 (1<<7) +#define DDL_PLANEB_PRECISION_16 (0<<7) + +/* FIFO watermark sizes etc */ +#define G4X_FIFO_LINE_SIZE 64 +#define I915_FIFO_LINE_SIZE 64 +#define I830_FIFO_LINE_SIZE 32 + +#define VALLEYVIEW_FIFO_SIZE 255 +#define G4X_FIFO_SIZE 127 +#define I965_FIFO_SIZE 512 +#define I945_FIFO_SIZE 127 +#define I915_FIFO_SIZE 95 +#define I855GM_FIFO_SIZE 127 /* In cachelines */ +#define I830_FIFO_SIZE 95 + +#define VALLEYVIEW_MAX_WM 0xff +#define G4X_MAX_WM 0x3f +#define I915_MAX_WM 0x3f + +#define PINEVIEW_DISPLAY_FIFO 512 /* in 64byte unit */ +#define PINEVIEW_FIFO_LINE_SIZE 64 +#define PINEVIEW_MAX_WM 0x1ff +#define PINEVIEW_DFT_WM 0x3f +#define PINEVIEW_DFT_HPLLOFF_WM 0 +#define PINEVIEW_GUARD_WM 10 +#define PINEVIEW_CURSOR_FIFO 64 +#define PINEVIEW_CURSOR_MAX_WM 0x3f +#define PINEVIEW_CURSOR_DFT_WM 0 +#define PINEVIEW_CURSOR_GUARD_WM 5 + +#define VALLEYVIEW_CURSOR_MAX_WM 64 +#define I965_CURSOR_FIFO 64 +#define I965_CURSOR_MAX_WM 32 +#define I965_CURSOR_DFT_WM 8 + +/* define the Watermark register on Ironlake */ +#define WM0_PIPEA_ILK 0x45100 +#define WM0_PIPE_PLANE_MASK (0xffff<<16) +#define WM0_PIPE_PLANE_SHIFT 16 +#define WM0_PIPE_SPRITE_MASK (0xff<<8) +#define WM0_PIPE_SPRITE_SHIFT 8 +#define WM0_PIPE_CURSOR_MASK (0xff) + +#define WM0_PIPEB_ILK 0x45104 +#define WM0_PIPEC_IVB 0x45200 +#define WM1_LP_ILK 0x45108 +#define WM1_LP_SR_EN (1<<31) +#define WM1_LP_LATENCY_SHIFT 24 +#define WM1_LP_LATENCY_MASK (0x7f<<24) +#define WM1_LP_FBC_MASK (0xf<<20) +#define WM1_LP_FBC_SHIFT 20 +#define WM1_LP_FBC_SHIFT_BDW 19 +#define WM1_LP_SR_MASK (0x7ff<<8) +#define WM1_LP_SR_SHIFT 8 +#define WM1_LP_CURSOR_MASK (0xff) +#define WM2_LP_ILK 0x4510c +#define WM2_LP_EN (1<<31) +#define WM3_LP_ILK 0x45110 +#define WM3_LP_EN (1<<31) +#define WM1S_LP_ILK 0x45120 +#define WM2S_LP_IVB 0x45124 +#define WM3S_LP_IVB 0x45128 +#define WM1S_LP_EN (1<<31) + +#define HSW_WM_LP_VAL(lat, fbc, pri, cur) \ + (WM3_LP_EN | ((lat) << WM1_LP_LATENCY_SHIFT) | \ + ((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur)) + +/* Memory latency timer register */ +#define MLTR_ILK 0x11222 +#define MLTR_WM1_SHIFT 0 +#define MLTR_WM2_SHIFT 8 +/* the unit of memory self-refresh latency time is 0.5us */ +#define ILK_SRLT_MASK 0x3f + + +/* the address where we get all kinds of latency value */ +#define SSKPD 0x5d10 +#define SSKPD_WM_MASK 0x3f +#define SSKPD_WM0_SHIFT 0 +#define SSKPD_WM1_SHIFT 8 +#define SSKPD_WM2_SHIFT 16 +#define SSKPD_WM3_SHIFT 24 + +/* + * The two pipe frame counter registers are not synchronized, so + * reading a stable value is somewhat tricky. The following code + * should work: + * + * do { + * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> + * PIPE_FRAME_HIGH_SHIFT; + * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> + * PIPE_FRAME_LOW_SHIFT); + * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> + * PIPE_FRAME_HIGH_SHIFT); + * } while (high1 != high2); + * frame = (high1 << 8) | low1; + */ +#define _PIPEAFRAMEHIGH 0x70040 +#define PIPE_FRAME_HIGH_MASK 0x0000ffff +#define PIPE_FRAME_HIGH_SHIFT 0 +#define _PIPEAFRAMEPIXEL 0x70044 +#define PIPE_FRAME_LOW_MASK 0xff000000 +#define PIPE_FRAME_LOW_SHIFT 24 +#define PIPE_PIXEL_MASK 0x00ffffff +#define PIPE_PIXEL_SHIFT 0 +/* GM45+ just has to be different */ +#define _PIPEA_FRMCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x70040) +#define _PIPEA_FLIPCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x70044) +#define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45) + +/* Cursor A & B regs */ +#define _CURACNTR (dev_priv->info->display_mmio_offset + 0x70080) +/* Old style CUR*CNTR flags (desktop 8xx) */ +#define CURSOR_ENABLE 0x80000000 +#define CURSOR_GAMMA_ENABLE 0x40000000 +#define CURSOR_STRIDE_MASK 0x30000000 +#define CURSOR_PIPE_CSC_ENABLE (1<<24) +#define CURSOR_FORMAT_SHIFT 24 +#define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_3C (0x01 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_4C (0x02 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT) +/* New style CUR*CNTR flags */ +#define CURSOR_MODE 0x27 +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_PIPE_SELECT (1 << 28) +#define MCURSOR_PIPE_A 0x00 +#define MCURSOR_PIPE_B (1 << 28) +#define MCURSOR_GAMMA_ENABLE (1 << 26) +#define CURSOR_TRICKLE_FEED_DISABLE (1 << 14) +#define _CURABASE (dev_priv->info->display_mmio_offset + 0x70084) +#define _CURAPOS (dev_priv->info->display_mmio_offset + 0x70088) +#define CURSOR_POS_MASK 0x007FF +#define CURSOR_POS_SIGN 0x8000 +#define CURSOR_X_SHIFT 0 +#define CURSOR_Y_SHIFT 16 +#define CURSIZE 0x700a0 +#define _CURBCNTR (dev_priv->info->display_mmio_offset + 0x700c0) +#define _CURBBASE (dev_priv->info->display_mmio_offset + 0x700c4) +#define _CURBPOS (dev_priv->info->display_mmio_offset + 0x700c8) + +#define _CURBCNTR_IVB 0x71080 +#define _CURBBASE_IVB 0x71084 +#define _CURBPOS_IVB 0x71088 + +#define CURCNTR(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR) +#define CURBASE(pipe) _PIPE(pipe, _CURABASE, _CURBBASE) +#define CURPOS(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS) + +#define CURCNTR_IVB(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR_IVB) +#define CURBASE_IVB(pipe) _PIPE(pipe, _CURABASE, _CURBBASE_IVB) +#define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB) + +/* Display A control */ +#define _DSPACNTR (dev_priv->info->display_mmio_offset + 0x70180) +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_YUV422 (0x0<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_BGRA555 (0x3<<26) +#define DISPPLANE_BGRX555 (0x4<<26) +#define DISPPLANE_BGRX565 (0x5<<26) +#define DISPPLANE_BGRX888 (0x6<<26) +#define DISPPLANE_BGRA888 (0x7<<26) +#define DISPPLANE_RGBX101010 (0x8<<26) +#define DISPPLANE_RGBA101010 (0x9<<26) +#define DISPPLANE_BGRX101010 (0xa<<26) +#define DISPPLANE_RGBX161616 (0xc<<26) +#define DISPPLANE_RGBX888 (0xe<<26) +#define DISPPLANE_RGBA888 (0xf<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_PIPE_CSC_ENABLE (1<<24) +#define DISPPLANE_SEL_PIPE_SHIFT 24 +#define DISPPLANE_SEL_PIPE_MASK (3<info->display_mmio_offset + 0x70184) +#define _DSPASTRIDE (dev_priv->info->display_mmio_offset + 0x70188) +#define _DSPAPOS (dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */ +#define _DSPASIZE (dev_priv->info->display_mmio_offset + 0x70190) +#define _DSPASURF (dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */ +#define _DSPATILEOFF (dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */ +#define _DSPAOFFSET (dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */ +#define _DSPASURFLIVE (dev_priv->info->display_mmio_offset + 0x701AC) + +#define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR) +#define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR) +#define DSPSTRIDE(plane) _PIPE(plane, _DSPASTRIDE, _DSPBSTRIDE) +#define DSPPOS(plane) _PIPE(plane, _DSPAPOS, _DSPBPOS) +#define DSPSIZE(plane) _PIPE(plane, _DSPASIZE, _DSPBSIZE) +#define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF) +#define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF) +#define DSPLINOFF(plane) DSPADDR(plane) +#define DSPOFFSET(plane) _PIPE(plane, _DSPAOFFSET, _DSPBOFFSET) +#define DSPSURFLIVE(plane) _PIPE(plane, _DSPASURFLIVE, _DSPBSURFLIVE) + +/* Display/Sprite base address macros */ +#define DISP_BASEADDR_MASK (0xfffff000) +#define I915_LO_DISPBASE(val) (val & ~DISP_BASEADDR_MASK) +#define I915_HI_DISPBASE(val) (val & DISP_BASEADDR_MASK) + +/* VBIOS flags */ +#define SWF00 (dev_priv->info->display_mmio_offset + 0x71410) +#define SWF01 (dev_priv->info->display_mmio_offset + 0x71414) +#define SWF02 (dev_priv->info->display_mmio_offset + 0x71418) +#define SWF03 (dev_priv->info->display_mmio_offset + 0x7141c) +#define SWF04 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF05 (dev_priv->info->display_mmio_offset + 0x71424) +#define SWF06 (dev_priv->info->display_mmio_offset + 0x71428) +#define SWF10 (dev_priv->info->display_mmio_offset + 0x70410) +#define SWF11 (dev_priv->info->display_mmio_offset + 0x70414) +#define SWF14 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF30 (dev_priv->info->display_mmio_offset + 0x72414) +#define SWF31 (dev_priv->info->display_mmio_offset + 0x72418) +#define SWF32 (dev_priv->info->display_mmio_offset + 0x7241c) + +/* Pipe B */ +#define _PIPEBDSL (dev_priv->info->display_mmio_offset + 0x71000) +#define _PIPEBCONF (dev_priv->info->display_mmio_offset + 0x71008) +#define _PIPEBSTAT (dev_priv->info->display_mmio_offset + 0x71024) +#define _PIPEBFRAMEHIGH 0x71040 +#define _PIPEBFRAMEPIXEL 0x71044 +#define _PIPEB_FRMCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x71040) +#define _PIPEB_FLIPCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x71044) + + +/* Display B control */ +#define _DSPBCNTR (dev_priv->info->display_mmio_offset + 0x71180) +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) +#define _DSPBADDR (dev_priv->info->display_mmio_offset + 0x71184) +#define _DSPBSTRIDE (dev_priv->info->display_mmio_offset + 0x71188) +#define _DSPBPOS (dev_priv->info->display_mmio_offset + 0x7118C) +#define _DSPBSIZE (dev_priv->info->display_mmio_offset + 0x71190) +#define _DSPBSURF (dev_priv->info->display_mmio_offset + 0x7119C) +#define _DSPBTILEOFF (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBOFFSET (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBSURFLIVE (dev_priv->info->display_mmio_offset + 0x711AC) + +/* Sprite A control */ +#define _DVSACNTR 0x72180 +#define DVS_ENABLE (1<<31) +#define DVS_GAMMA_ENABLE (1<<30) +#define DVS_PIXFORMAT_MASK (3<<25) +#define DVS_FORMAT_YUV422 (0<<25) +#define DVS_FORMAT_RGBX101010 (1<<25) +#define DVS_FORMAT_RGBX888 (2<<25) +#define DVS_FORMAT_RGBX161616 (3<<25) +#define DVS_PIPE_CSC_ENABLE (1<<24) +#define DVS_SOURCE_KEY (1<<22) +#define DVS_RGB_ORDER_XBGR (1<<20) +#define DVS_YUV_BYTE_ORDER_MASK (3<<16) +#define DVS_YUV_ORDER_YUYV (0<<16) +#define DVS_YUV_ORDER_UYVY (1<<16) +#define DVS_YUV_ORDER_YVYU (2<<16) +#define DVS_YUV_ORDER_VYUY (3<<16) +#define DVS_DEST_KEY (1<<2) +#define DVS_TRICKLE_FEED_DISABLE (1<<14) +#define DVS_TILED (1<<10) +#define _DVSALINOFF 0x72184 +#define _DVSASTRIDE 0x72188 +#define _DVSAPOS 0x7218c +#define _DVSASIZE 0x72190 +#define _DVSAKEYVAL 0x72194 +#define _DVSAKEYMSK 0x72198 +#define _DVSASURF 0x7219c +#define _DVSAKEYMAXVAL 0x721a0 +#define _DVSATILEOFF 0x721a4 +#define _DVSASURFLIVE 0x721ac +#define _DVSASCALE 0x72204 +#define DVS_SCALE_ENABLE (1<<31) +#define DVS_FILTER_MASK (3<<29) +#define DVS_FILTER_MEDIUM (0<<29) +#define DVS_FILTER_ENHANCING (1<<29) +#define DVS_FILTER_SOFTENING (2<<29) +#define DVS_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */ +#define DVS_VERTICAL_OFFSET_ENABLE (1<<27) +#define _DVSAGAMC 0x72300 + +#define _DVSBCNTR 0x73180 +#define _DVSBLINOFF 0x73184 +#define _DVSBSTRIDE 0x73188 +#define _DVSBPOS 0x7318c +#define _DVSBSIZE 0x73190 +#define _DVSBKEYVAL 0x73194 +#define _DVSBKEYMSK 0x73198 +#define _DVSBSURF 0x7319c +#define _DVSBKEYMAXVAL 0x731a0 +#define _DVSBTILEOFF 0x731a4 +#define _DVSBSURFLIVE 0x731ac +#define _DVSBSCALE 0x73204 +#define _DVSBGAMC 0x73300 + +#define DVSCNTR(pipe) _PIPE(pipe, _DVSACNTR, _DVSBCNTR) +#define DVSLINOFF(pipe) _PIPE(pipe, _DVSALINOFF, _DVSBLINOFF) +#define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE) +#define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS) +#define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF) +#define DVSKEYMAX(pipe) _PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL) +#define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE) +#define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE) +#define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF) +#define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL) +#define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK) +#define DVSSURFLIVE(pipe) _PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE) + +#define _SPRA_CTL 0x70280 +#define SPRITE_ENABLE (1<<31) +#define SPRITE_GAMMA_ENABLE (1<<30) +#define SPRITE_PIXFORMAT_MASK (7<<25) +#define SPRITE_FORMAT_YUV422 (0<<25) +#define SPRITE_FORMAT_RGBX101010 (1<<25) +#define SPRITE_FORMAT_RGBX888 (2<<25) +#define SPRITE_FORMAT_RGBX161616 (3<<25) +#define SPRITE_FORMAT_YUV444 (4<<25) +#define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */ +#define SPRITE_PIPE_CSC_ENABLE (1<<24) +#define SPRITE_SOURCE_KEY (1<<22) +#define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ +#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) +#define SPRITE_YUV_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */ +#define SPRITE_YUV_BYTE_ORDER_MASK (3<<16) +#define SPRITE_YUV_ORDER_YUYV (0<<16) +#define SPRITE_YUV_ORDER_UYVY (1<<16) +#define SPRITE_YUV_ORDER_YVYU (2<<16) +#define SPRITE_YUV_ORDER_VYUY (3<<16) +#define SPRITE_TRICKLE_FEED_DISABLE (1<<14) +#define SPRITE_INT_GAMMA_ENABLE (1<<13) +#define SPRITE_TILED (1<<10) +#define SPRITE_DEST_KEY (1<<2) +#define _SPRA_LINOFF 0x70284 +#define _SPRA_STRIDE 0x70288 +#define _SPRA_POS 0x7028c +#define _SPRA_SIZE 0x70290 +#define _SPRA_KEYVAL 0x70294 +#define _SPRA_KEYMSK 0x70298 +#define _SPRA_SURF 0x7029c +#define _SPRA_KEYMAX 0x702a0 +#define _SPRA_TILEOFF 0x702a4 +#define _SPRA_OFFSET 0x702a4 +#define _SPRA_SURFLIVE 0x702ac +#define _SPRA_SCALE 0x70304 +#define SPRITE_SCALE_ENABLE (1<<31) +#define SPRITE_FILTER_MASK (3<<29) +#define SPRITE_FILTER_MEDIUM (0<<29) +#define SPRITE_FILTER_ENHANCING (1<<29) +#define SPRITE_FILTER_SOFTENING (2<<29) +#define SPRITE_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */ +#define SPRITE_VERTICAL_OFFSET_ENABLE (1<<27) +#define _SPRA_GAMC 0x70400 + +#define _SPRB_CTL 0x71280 +#define _SPRB_LINOFF 0x71284 +#define _SPRB_STRIDE 0x71288 +#define _SPRB_POS 0x7128c +#define _SPRB_SIZE 0x71290 +#define _SPRB_KEYVAL 0x71294 +#define _SPRB_KEYMSK 0x71298 +#define _SPRB_SURF 0x7129c +#define _SPRB_KEYMAX 0x712a0 +#define _SPRB_TILEOFF 0x712a4 +#define _SPRB_OFFSET 0x712a4 +#define _SPRB_SURFLIVE 0x712ac +#define _SPRB_SCALE 0x71304 +#define _SPRB_GAMC 0x71400 + +#define SPRCTL(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL) +#define SPRLINOFF(pipe) _PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF) +#define SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE) +#define SPRPOS(pipe) _PIPE(pipe, _SPRA_POS, _SPRB_POS) +#define SPRSIZE(pipe) _PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE) +#define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL) +#define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK) +#define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF) +#define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX) +#define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF) +#define SPROFFSET(pipe) _PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET) +#define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE) +#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) +#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) + +#define _SPACNTR (VLV_DISPLAY_BASE + 0x72180) +#define SP_ENABLE (1<<31) +#define SP_GAMMA_ENABLE (1<<30) +#define SP_PIXFORMAT_MASK (0xf<<26) +#define SP_FORMAT_YUV422 (0<<26) +#define SP_FORMAT_BGR565 (5<<26) +#define SP_FORMAT_BGRX8888 (6<<26) +#define SP_FORMAT_BGRA8888 (7<<26) +#define SP_FORMAT_RGBX1010102 (8<<26) +#define SP_FORMAT_RGBA1010102 (9<<26) +#define SP_FORMAT_RGBX8888 (0xe<<26) +#define SP_FORMAT_RGBA8888 (0xf<<26) +#define SP_SOURCE_KEY (1<<22) +#define SP_YUV_BYTE_ORDER_MASK (3<<16) +#define SP_YUV_ORDER_YUYV (0<<16) +#define SP_YUV_ORDER_UYVY (1<<16) +#define SP_YUV_ORDER_YVYU (2<<16) +#define SP_YUV_ORDER_VYUY (3<<16) +#define SP_TILED (1<<10) +#define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184) +#define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188) +#define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c) +#define _SPASIZE (VLV_DISPLAY_BASE + 0x72190) +#define _SPAKEYMINVAL (VLV_DISPLAY_BASE + 0x72194) +#define _SPAKEYMSK (VLV_DISPLAY_BASE + 0x72198) +#define _SPASURF (VLV_DISPLAY_BASE + 0x7219c) +#define _SPAKEYMAXVAL (VLV_DISPLAY_BASE + 0x721a0) +#define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4) +#define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8) +#define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4) + +#define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280) +#define _SPBLINOFF (VLV_DISPLAY_BASE + 0x72284) +#define _SPBSTRIDE (VLV_DISPLAY_BASE + 0x72288) +#define _SPBPOS (VLV_DISPLAY_BASE + 0x7228c) +#define _SPBSIZE (VLV_DISPLAY_BASE + 0x72290) +#define _SPBKEYMINVAL (VLV_DISPLAY_BASE + 0x72294) +#define _SPBKEYMSK (VLV_DISPLAY_BASE + 0x72298) +#define _SPBSURF (VLV_DISPLAY_BASE + 0x7229c) +#define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0) +#define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4) +#define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8) +#define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4) + +#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR) +#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF) +#define SPSTRIDE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASTRIDE, _SPBSTRIDE) +#define SPPOS(pipe, plane) _PIPE(pipe * 2 + plane, _SPAPOS, _SPBPOS) +#define SPSIZE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASIZE, _SPBSIZE) +#define SPKEYMINVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMINVAL, _SPBKEYMINVAL) +#define SPKEYMSK(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMSK, _SPBKEYMSK) +#define SPSURF(pipe, plane) _PIPE(pipe * 2 + plane, _SPASURF, _SPBSURF) +#define SPKEYMAXVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMAXVAL, _SPBKEYMAXVAL) +#define SPTILEOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPATILEOFF, _SPBTILEOFF) +#define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA) +#define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC) + +/* VBIOS regs */ +#define VGACNTRL 0x71400 +# define VGA_DISP_DISABLE (1 << 31) +# define VGA_2X_MODE (1 << 30) +# define VGA_PIPE_B_SELECT (1 << 29) + +#define VLV_VGACNTRL (VLV_DISPLAY_BASE + 0x71400) + +/* Ironlake */ + +#define CPU_VGACNTRL 0x41000 + +#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030 +#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4) +#define DIGITAL_PORTA_SHORT_PULSE_2MS (0 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_4_5MS (1 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_6MS (2 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_100MS (3 << 2) +#define DIGITAL_PORTA_NO_DETECT (0 << 0) +#define DIGITAL_PORTA_LONG_PULSE_DETECT_MASK (1 << 1) +#define DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK (1 << 0) + +/* refresh rate hardware control */ +#define RR_HW_CTL 0x45300 +#define RR_HW_LOW_POWER_FRAMES_MASK 0xff +#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00 + +#define FDI_PLL_BIOS_0 0x46000 +#define FDI_PLL_FB_CLOCK_MASK 0xff +#define FDI_PLL_BIOS_1 0x46004 +#define FDI_PLL_BIOS_2 0x46008 +#define DISPLAY_PORT_PLL_BIOS_0 0x4600c +#define DISPLAY_PORT_PLL_BIOS_1 0x46010 +#define DISPLAY_PORT_PLL_BIOS_2 0x46014 + +#define PCH_3DCGDIS0 0x46020 +# define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18) +# define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1) + +#define PCH_3DCGDIS1 0x46024 +# define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11) + +#define FDI_PLL_FREQ_CTL 0x46030 +#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) +#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 +#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff + + +#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) +#define PIPE_DATA_M1_OFFSET 0 +#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) +#define PIPE_DATA_N1_OFFSET 0 + +#define _PIPEA_DATA_M2 (dev_priv->info->display_mmio_offset + 0x60038) +#define PIPE_DATA_M2_OFFSET 0 +#define _PIPEA_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6003c) +#define PIPE_DATA_N2_OFFSET 0 + +#define _PIPEA_LINK_M1 (dev_priv->info->display_mmio_offset + 0x60040) +#define PIPE_LINK_M1_OFFSET 0 +#define _PIPEA_LINK_N1 (dev_priv->info->display_mmio_offset + 0x60044) +#define PIPE_LINK_N1_OFFSET 0 + +#define _PIPEA_LINK_M2 (dev_priv->info->display_mmio_offset + 0x60048) +#define PIPE_LINK_M2_OFFSET 0 +#define _PIPEA_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6004c) +#define PIPE_LINK_N2_OFFSET 0 + +/* PIPEB timing regs are same start from 0x61000 */ + +#define _PIPEB_DATA_M1 (dev_priv->info->display_mmio_offset + 0x61030) +#define _PIPEB_DATA_N1 (dev_priv->info->display_mmio_offset + 0x61034) + +#define _PIPEB_DATA_M2 (dev_priv->info->display_mmio_offset + 0x61038) +#define _PIPEB_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6103c) + +#define _PIPEB_LINK_M1 (dev_priv->info->display_mmio_offset + 0x61040) +#define _PIPEB_LINK_N1 (dev_priv->info->display_mmio_offset + 0x61044) + +#define _PIPEB_LINK_M2 (dev_priv->info->display_mmio_offset + 0x61048) +#define _PIPEB_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6104c) + +#define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1) +#define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1) +#define PIPE_DATA_M2(tran) _TRANSCODER(tran, _PIPEA_DATA_M2, _PIPEB_DATA_M2) +#define PIPE_DATA_N2(tran) _TRANSCODER(tran, _PIPEA_DATA_N2, _PIPEB_DATA_N2) +#define PIPE_LINK_M1(tran) _TRANSCODER(tran, _PIPEA_LINK_M1, _PIPEB_LINK_M1) +#define PIPE_LINK_N1(tran) _TRANSCODER(tran, _PIPEA_LINK_N1, _PIPEB_LINK_N1) +#define PIPE_LINK_M2(tran) _TRANSCODER(tran, _PIPEA_LINK_M2, _PIPEB_LINK_M2) +#define PIPE_LINK_N2(tran) _TRANSCODER(tran, _PIPEA_LINK_N2, _PIPEB_LINK_N2) + +/* CPU panel fitter */ +/* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */ +#define _PFA_CTL_1 0x68080 +#define _PFB_CTL_1 0x68880 +#define PF_ENABLE (1<<31) +#define PF_PIPE_SEL_MASK_IVB (3<<29) +#define PF_PIPE_SEL_IVB(pipe) ((pipe)<<29) +#define PF_FILTER_MASK (3<<23) +#define PF_FILTER_PROGRAMMED (0<<23) +#define PF_FILTER_MED_3x3 (1<<23) +#define PF_FILTER_EDGE_ENHANCE (2<<23) +#define PF_FILTER_EDGE_SOFTEN (3<<23) +#define _PFA_WIN_SZ 0x68074 +#define _PFB_WIN_SZ 0x68874 +#define _PFA_WIN_POS 0x68070 +#define _PFB_WIN_POS 0x68870 +#define _PFA_VSCALE 0x68084 +#define _PFB_VSCALE 0x68884 +#define _PFA_HSCALE 0x68090 +#define _PFB_HSCALE 0x68890 + +#define PF_CTL(pipe) _PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1) +#define PF_WIN_SZ(pipe) _PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ) +#define PF_WIN_POS(pipe) _PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS) +#define PF_VSCALE(pipe) _PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE) +#define PF_HSCALE(pipe) _PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE) + +/* legacy palette */ +#define _LGC_PALETTE_A 0x4a000 +#define _LGC_PALETTE_B 0x4a800 +#define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + +#define _GAMMA_MODE_A 0x4a480 +#define _GAMMA_MODE_B 0x4ac80 +#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) +#define GAMMA_MODE_MODE_MASK (3 << 0) +#define GAMMA_MODE_MODE_8BIT (0 << 0) +#define GAMMA_MODE_MODE_10BIT (1 << 0) +#define GAMMA_MODE_MODE_12BIT (2 << 0) +#define GAMMA_MODE_MODE_SPLIT (3 << 0) + +/* interrupts */ +#define DE_MASTER_IRQ_CONTROL (1 << 31) +#define DE_SPRITEB_FLIP_DONE (1 << 29) +#define DE_SPRITEA_FLIP_DONE (1 << 28) +#define DE_PLANEB_FLIP_DONE (1 << 27) +#define DE_PLANEA_FLIP_DONE (1 << 26) +#define DE_PLANE_FLIP_DONE(plane) (1 << (26 + (plane))) +#define DE_PCU_EVENT (1 << 25) +#define DE_GTT_FAULT (1 << 24) +#define DE_POISON (1 << 23) +#define DE_PERFORM_COUNTER (1 << 22) +#define DE_PCH_EVENT (1 << 21) +#define DE_AUX_CHANNEL_A (1 << 20) +#define DE_DP_A_HOTPLUG (1 << 19) +#define DE_GSE (1 << 18) +#define DE_PIPEB_VBLANK (1 << 15) +#define DE_PIPEB_EVEN_FIELD (1 << 14) +#define DE_PIPEB_ODD_FIELD (1 << 13) +#define DE_PIPEB_LINE_COMPARE (1 << 12) +#define DE_PIPEB_VSYNC (1 << 11) +#define DE_PIPEB_CRC_DONE (1 << 10) +#define DE_PIPEB_FIFO_UNDERRUN (1 << 8) +#define DE_PIPEA_VBLANK (1 << 7) +#define DE_PIPE_VBLANK(pipe) (1 << (7 + 8*(pipe))) +#define DE_PIPEA_EVEN_FIELD (1 << 6) +#define DE_PIPEA_ODD_FIELD (1 << 5) +#define DE_PIPEA_LINE_COMPARE (1 << 4) +#define DE_PIPEA_VSYNC (1 << 3) +#define DE_PIPEA_CRC_DONE (1 << 2) +#define DE_PIPE_CRC_DONE(pipe) (1 << (2 + 8*(pipe))) +#define DE_PIPEA_FIFO_UNDERRUN (1 << 0) +#define DE_PIPE_FIFO_UNDERRUN(pipe) (1 << (8*(pipe))) + +/* More Ivybridge lolz */ +#define DE_ERR_INT_IVB (1<<30) +#define DE_GSE_IVB (1<<29) +#define DE_PCH_EVENT_IVB (1<<28) +#define DE_DP_A_HOTPLUG_IVB (1<<27) +#define DE_AUX_CHANNEL_A_IVB (1<<26) +#define DE_SPRITEC_FLIP_DONE_IVB (1<<14) +#define DE_PLANEC_FLIP_DONE_IVB (1<<13) +#define DE_PIPEC_VBLANK_IVB (1<<10) +#define DE_SPRITEB_FLIP_DONE_IVB (1<<9) +#define DE_PLANEB_FLIP_DONE_IVB (1<<8) +#define DE_PIPEB_VBLANK_IVB (1<<5) +#define DE_SPRITEA_FLIP_DONE_IVB (1<<4) +#define DE_PLANEA_FLIP_DONE_IVB (1<<3) +#define DE_PLANE_FLIP_DONE_IVB(plane) (1<< (3 + 5*(plane))) +#define DE_PIPEA_VBLANK_IVB (1<<0) +#define DE_PIPE_VBLANK_IVB(pipe) (1 << (pipe * 5)) + +#define VLV_MASTER_IER 0x4400c /* Gunit master IER */ +#define MASTER_INTERRUPT_ENABLE (1<<31) + +#define DEISR 0x44000 +#define DEIMR 0x44004 +#define DEIIR 0x44008 +#define DEIER 0x4400c + +#define GTISR 0x44010 +#define GTIMR 0x44014 +#define GTIIR 0x44018 +#define GTIER 0x4401c + +#define GEN8_MASTER_IRQ 0x44200 +#define GEN8_MASTER_IRQ_CONTROL (1<<31) +#define GEN8_PCU_IRQ (1<<30) +#define GEN8_DE_PCH_IRQ (1<<23) +#define GEN8_DE_MISC_IRQ (1<<22) +#define GEN8_DE_PORT_IRQ (1<<20) +#define GEN8_DE_PIPE_C_IRQ (1<<18) +#define GEN8_DE_PIPE_B_IRQ (1<<17) +#define GEN8_DE_PIPE_A_IRQ (1<<16) +#define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+pipe)) +#define GEN8_GT_VECS_IRQ (1<<6) +#define GEN8_GT_VCS2_IRQ (1<<3) +#define GEN8_GT_VCS1_IRQ (1<<2) +#define GEN8_GT_BCS_IRQ (1<<1) +#define GEN8_GT_RCS_IRQ (1<<0) + +#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which))) +#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which))) +#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which))) +#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which))) + +#define GEN8_BCS_IRQ_SHIFT 16 +#define GEN8_RCS_IRQ_SHIFT 0 +#define GEN8_VCS2_IRQ_SHIFT 16 +#define GEN8_VCS1_IRQ_SHIFT 0 +#define GEN8_VECS_IRQ_SHIFT 0 + +#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe))) +#define GEN8_PIPE_FIFO_UNDERRUN (1 << 31) +#define GEN8_PIPE_CDCLK_CRC_ERROR (1 << 29) +#define GEN8_PIPE_CDCLK_CRC_DONE (1 << 28) +#define GEN8_PIPE_CURSOR_FAULT (1 << 10) +#define GEN8_PIPE_SPRITE_FAULT (1 << 9) +#define GEN8_PIPE_PRIMARY_FAULT (1 << 8) +#define GEN8_PIPE_SPRITE_FLIP_DONE (1 << 5) +#define GEN8_PIPE_FLIP_DONE (1 << 4) +#define GEN8_PIPE_SCAN_LINE_EVENT (1 << 2) +#define GEN8_PIPE_VSYNC (1 << 1) +#define GEN8_PIPE_VBLANK (1 << 0) +#define GEN8_DE_PIPE_IRQ_FAULT_ERRORS \ + (GEN8_PIPE_CURSOR_FAULT | \ + GEN8_PIPE_SPRITE_FAULT | \ + GEN8_PIPE_PRIMARY_FAULT) + +#define GEN8_DE_PORT_ISR 0x44440 +#define GEN8_DE_PORT_IMR 0x44444 +#define GEN8_DE_PORT_IIR 0x44448 +#define GEN8_DE_PORT_IER 0x4444c +#define GEN8_PORT_DP_A_HOTPLUG (1 << 3) +#define GEN8_AUX_CHANNEL_A (1 << 0) + +#define GEN8_DE_MISC_ISR 0x44460 +#define GEN8_DE_MISC_IMR 0x44464 +#define GEN8_DE_MISC_IIR 0x44468 +#define GEN8_DE_MISC_IER 0x4446c +#define GEN8_DE_MISC_GSE (1 << 27) + +#define GEN8_PCU_ISR 0x444e0 +#define GEN8_PCU_IMR 0x444e4 +#define GEN8_PCU_IIR 0x444e8 +#define GEN8_PCU_IER 0x444ec + +#define ILK_DISPLAY_CHICKEN2 0x42004 +/* Required on all Ironlake and Sandybridge according to the B-Spec. */ +#define ILK_ELPIN_409_SELECT (1 << 25) +#define ILK_DPARB_GATE (1<<22) +#define ILK_VSDPFD_FULL (1<<21) +#define ILK_DISPLAY_CHICKEN_FUSES 0x42014 +#define ILK_INTERNAL_GRAPHICS_DISABLE (1<<31) +#define ILK_INTERNAL_DISPLAY_DISABLE (1<<30) +#define ILK_DISPLAY_DEBUG_DISABLE (1<<29) +#define ILK_HDCP_DISABLE (1<<25) +#define ILK_eDP_A_DISABLE (1<<24) +#define ILK_DESKTOP (1<<23) + +#define ILK_DSPCLK_GATE_D 0x42020 +#define ILK_VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) +#define ILK_DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9) +#define ILK_DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8) +#define ILK_DPFDUNIT_CLOCK_GATE_ENABLE (1 << 7) +#define ILK_DPARBUNIT_CLOCK_GATE_ENABLE (1 << 5) + +#define IVB_CHICKEN3 0x4200c +# define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE (1 << 5) +# define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2) + +#define CHICKEN_PAR1_1 0x42080 +#define DPA_MASK_VBLANK_SRD (1 << 15) +#define FORCE_ARB_IDLE_PLANES (1 << 14) + +#define _CHICKEN_PIPESL_1_A 0x420b0 +#define _CHICKEN_PIPESL_1_B 0x420b4 +#define DPRS_MASK_VBLANK_SRD (1 << 0) +#define CHICKEN_PIPESL_1(pipe) _PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B) + +#define DISP_ARB_CTL 0x45000 +#define DISP_TILE_SURFACE_SWIZZLING (1<<13) +#define DISP_FBC_WM_DIS (1<<15) +#define DISP_ARB_CTL2 0x45004 +#define DISP_DATA_PARTITION_5_6 (1<<6) +#define GEN7_MSG_CTL 0x45010 +#define WAIT_FOR_PCH_RESET_ACK (1<<1) +#define WAIT_FOR_PCH_FLR_ACK (1<<0) + +/* GEN7 chicken */ +#define GEN7_COMMON_SLICE_CHICKEN1 0x7010 +# define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1<<10) | (1<<26)) +#define COMMON_SLICE_CHICKEN2 0x7014 +# define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0) + +#define GEN7_L3CNTLREG1 0xB01C +#define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C4FFF8C +#define GEN7_L3AGDIS (1<<19) + +#define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030 +#define GEN7_WA_L3_CHICKEN_MODE 0x20000000 + +#define GEN7_L3SQCREG4 0xb034 +#define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) + +/* GEN8 chicken */ +#define HDC_CHICKEN0 0x7300 +#define HDC_FORCE_NON_COHERENT (1<<4) + +/* WaCatErrorRejectionIssue */ +#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 +#define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) + +#define HSW_SCRATCH1 0xb038 +#define HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE (1<<27) + +#define HSW_FUSE_STRAP 0x42014 +#define HSW_CDCLK_LIMIT (1 << 24) + +/* PCH */ + +/* south display engine interrupt: IBX */ +#define SDE_AUDIO_POWER_D (1 << 27) +#define SDE_AUDIO_POWER_C (1 << 26) +#define SDE_AUDIO_POWER_B (1 << 25) +#define SDE_AUDIO_POWER_SHIFT (25) +#define SDE_AUDIO_POWER_MASK (7 << SDE_AUDIO_POWER_SHIFT) +#define SDE_GMBUS (1 << 24) +#define SDE_AUDIO_HDCP_TRANSB (1 << 23) +#define SDE_AUDIO_HDCP_TRANSA (1 << 22) +#define SDE_AUDIO_HDCP_MASK (3 << 22) +#define SDE_AUDIO_TRANSB (1 << 21) +#define SDE_AUDIO_TRANSA (1 << 20) +#define SDE_AUDIO_TRANS_MASK (3 << 20) +#define SDE_POISON (1 << 19) +/* 18 reserved */ +#define SDE_FDI_RXB (1 << 17) +#define SDE_FDI_RXA (1 << 16) +#define SDE_FDI_MASK (3 << 16) +#define SDE_AUXD (1 << 15) +#define SDE_AUXC (1 << 14) +#define SDE_AUXB (1 << 13) +#define SDE_AUX_MASK (7 << 13) +/* 12 reserved */ +#define SDE_CRT_HOTPLUG (1 << 11) +#define SDE_PORTD_HOTPLUG (1 << 10) +#define SDE_PORTC_HOTPLUG (1 << 9) +#define SDE_PORTB_HOTPLUG (1 << 8) +#define SDE_SDVOB_HOTPLUG (1 << 6) +#define SDE_HOTPLUG_MASK (SDE_CRT_HOTPLUG | \ + SDE_SDVOB_HOTPLUG | \ + SDE_PORTB_HOTPLUG | \ + SDE_PORTC_HOTPLUG | \ + SDE_PORTD_HOTPLUG) +#define SDE_TRANSB_CRC_DONE (1 << 5) +#define SDE_TRANSB_CRC_ERR (1 << 4) +#define SDE_TRANSB_FIFO_UNDER (1 << 3) +#define SDE_TRANSA_CRC_DONE (1 << 2) +#define SDE_TRANSA_CRC_ERR (1 << 1) +#define SDE_TRANSA_FIFO_UNDER (1 << 0) +#define SDE_TRANS_MASK (0x3f) + +/* south display engine interrupt: CPT/PPT */ +#define SDE_AUDIO_POWER_D_CPT (1 << 31) +#define SDE_AUDIO_POWER_C_CPT (1 << 30) +#define SDE_AUDIO_POWER_B_CPT (1 << 29) +#define SDE_AUDIO_POWER_SHIFT_CPT 29 +#define SDE_AUDIO_POWER_MASK_CPT (7 << 29) +#define SDE_AUXD_CPT (1 << 27) +#define SDE_AUXC_CPT (1 << 26) +#define SDE_AUXB_CPT (1 << 25) +#define SDE_AUX_MASK_CPT (7 << 25) +#define SDE_PORTD_HOTPLUG_CPT (1 << 23) +#define SDE_PORTC_HOTPLUG_CPT (1 << 22) +#define SDE_PORTB_HOTPLUG_CPT (1 << 21) +#define SDE_CRT_HOTPLUG_CPT (1 << 19) +#define SDE_SDVOB_HOTPLUG_CPT (1 << 18) +#define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \ + SDE_SDVOB_HOTPLUG_CPT | \ + SDE_PORTD_HOTPLUG_CPT | \ + SDE_PORTC_HOTPLUG_CPT | \ + SDE_PORTB_HOTPLUG_CPT) +#define SDE_GMBUS_CPT (1 << 17) +#define SDE_ERROR_CPT (1 << 16) +#define SDE_AUDIO_CP_REQ_C_CPT (1 << 10) +#define SDE_AUDIO_CP_CHG_C_CPT (1 << 9) +#define SDE_FDI_RXC_CPT (1 << 8) +#define SDE_AUDIO_CP_REQ_B_CPT (1 << 6) +#define SDE_AUDIO_CP_CHG_B_CPT (1 << 5) +#define SDE_FDI_RXB_CPT (1 << 4) +#define SDE_AUDIO_CP_REQ_A_CPT (1 << 2) +#define SDE_AUDIO_CP_CHG_A_CPT (1 << 1) +#define SDE_FDI_RXA_CPT (1 << 0) +#define SDE_AUDIO_CP_REQ_CPT (SDE_AUDIO_CP_REQ_C_CPT | \ + SDE_AUDIO_CP_REQ_B_CPT | \ + SDE_AUDIO_CP_REQ_A_CPT) +#define SDE_AUDIO_CP_CHG_CPT (SDE_AUDIO_CP_CHG_C_CPT | \ + SDE_AUDIO_CP_CHG_B_CPT | \ + SDE_AUDIO_CP_CHG_A_CPT) +#define SDE_FDI_MASK_CPT (SDE_FDI_RXC_CPT | \ + SDE_FDI_RXB_CPT | \ + SDE_FDI_RXA_CPT) + +#define SDEISR 0xc4000 +#define SDEIMR 0xc4004 +#define SDEIIR 0xc4008 +#define SDEIER 0xc400c + +#define SERR_INT 0xc4040 +#define SERR_INT_POISON (1<<31) +#define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6) +#define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3) +#define SERR_INT_TRANS_A_FIFO_UNDERRUN (1<<0) +#define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1<<(pipe*3)) + +/* digital port hotplug */ +#define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */ +#define PORTD_HOTPLUG_ENABLE (1 << 20) +#define PORTD_PULSE_DURATION_2ms (0) +#define PORTD_PULSE_DURATION_4_5ms (1 << 18) +#define PORTD_PULSE_DURATION_6ms (2 << 18) +#define PORTD_PULSE_DURATION_100ms (3 << 18) +#define PORTD_PULSE_DURATION_MASK (3 << 18) +#define PORTD_HOTPLUG_STATUS_MASK (0x3 << 16) +#define PORTD_HOTPLUG_NO_DETECT (0 << 16) +#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) +#define PORTD_HOTPLUG_LONG_DETECT (2 << 16) +#define PORTC_HOTPLUG_ENABLE (1 << 12) +#define PORTC_PULSE_DURATION_2ms (0) +#define PORTC_PULSE_DURATION_4_5ms (1 << 10) +#define PORTC_PULSE_DURATION_6ms (2 << 10) +#define PORTC_PULSE_DURATION_100ms (3 << 10) +#define PORTC_PULSE_DURATION_MASK (3 << 10) +#define PORTC_HOTPLUG_STATUS_MASK (0x3 << 8) +#define PORTC_HOTPLUG_NO_DETECT (0 << 8) +#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) +#define PORTC_HOTPLUG_LONG_DETECT (2 << 8) +#define PORTB_HOTPLUG_ENABLE (1 << 4) +#define PORTB_PULSE_DURATION_2ms (0) +#define PORTB_PULSE_DURATION_4_5ms (1 << 2) +#define PORTB_PULSE_DURATION_6ms (2 << 2) +#define PORTB_PULSE_DURATION_100ms (3 << 2) +#define PORTB_PULSE_DURATION_MASK (3 << 2) +#define PORTB_HOTPLUG_STATUS_MASK (0x3 << 0) +#define PORTB_HOTPLUG_NO_DETECT (0 << 0) +#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) +#define PORTB_HOTPLUG_LONG_DETECT (2 << 0) + +#define PCH_GPIOA 0xc5010 +#define PCH_GPIOB 0xc5014 +#define PCH_GPIOC 0xc5018 +#define PCH_GPIOD 0xc501c +#define PCH_GPIOE 0xc5020 +#define PCH_GPIOF 0xc5024 + +#define PCH_GMBUS0 0xc5100 +#define PCH_GMBUS1 0xc5104 +#define PCH_GMBUS2 0xc5108 +#define PCH_GMBUS3 0xc510c +#define PCH_GMBUS4 0xc5110 +#define PCH_GMBUS5 0xc5120 + +#define _PCH_DPLL_A 0xc6014 +#define _PCH_DPLL_B 0xc6018 +#define PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) + +#define _PCH_FPA0 0xc6040 +#define FP_CB_TUNE (0x3<<22) +#define _PCH_FPA1 0xc6044 +#define _PCH_FPB0 0xc6048 +#define _PCH_FPB1 0xc604c +#define PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0) +#define PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1) + +#define PCH_DPLL_TEST 0xc606c + +#define PCH_DREF_CONTROL 0xC6200 +#define DREF_CONTROL_MASK 0x7fc3 +#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13) +#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13) +#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13) +#define DREF_CPU_SOURCE_OUTPUT_MASK (3<<13) +#define DREF_SSC_SOURCE_DISABLE (0<<11) +#define DREF_SSC_SOURCE_ENABLE (2<<11) +#define DREF_SSC_SOURCE_MASK (3<<11) +#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9) +#define DREF_NONSPREAD_CK505_ENABLE (1<<9) +#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9) +#define DREF_NONSPREAD_SOURCE_MASK (3<<9) +#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7) +#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7) +#define DREF_SUPERSPREAD_SOURCE_MASK (3<<7) +#define DREF_SSC4_DOWNSPREAD (0<<6) +#define DREF_SSC4_CENTERSPREAD (1<<6) +#define DREF_SSC1_DISABLE (0<<1) +#define DREF_SSC1_ENABLE (1<<1) +#define DREF_SSC4_DISABLE (0) +#define DREF_SSC4_ENABLE (1) + +#define PCH_RAWCLK_FREQ 0xc6204 +#define FDL_TP1_TIMER_SHIFT 12 +#define FDL_TP1_TIMER_MASK (3<<12) +#define FDL_TP2_TIMER_SHIFT 10 +#define FDL_TP2_TIMER_MASK (3<<10) +#define RAWCLK_FREQ_MASK 0x3ff + +#define PCH_DPLL_TMR_CFG 0xc6208 + +#define PCH_SSC4_PARMS 0xc6210 +#define PCH_SSC4_AUX_PARMS 0xc6214 + +#define PCH_DPLL_SEL 0xc7000 +#define TRANS_DPLLB_SEL(pipe) (1 << (pipe * 4)) +#define TRANS_DPLLA_SEL(pipe) 0 +#define TRANS_DPLL_ENABLE(pipe) (1 << (pipe * 4 + 3)) + +/* transcoder */ + +#define _PCH_TRANS_HTOTAL_A 0xe0000 +#define TRANS_HTOTAL_SHIFT 16 +#define TRANS_HACTIVE_SHIFT 0 +#define _PCH_TRANS_HBLANK_A 0xe0004 +#define TRANS_HBLANK_END_SHIFT 16 +#define TRANS_HBLANK_START_SHIFT 0 +#define _PCH_TRANS_HSYNC_A 0xe0008 +#define TRANS_HSYNC_END_SHIFT 16 +#define TRANS_HSYNC_START_SHIFT 0 +#define _PCH_TRANS_VTOTAL_A 0xe000c +#define TRANS_VTOTAL_SHIFT 16 +#define TRANS_VACTIVE_SHIFT 0 +#define _PCH_TRANS_VBLANK_A 0xe0010 +#define TRANS_VBLANK_END_SHIFT 16 +#define TRANS_VBLANK_START_SHIFT 0 +#define _PCH_TRANS_VSYNC_A 0xe0014 +#define TRANS_VSYNC_END_SHIFT 16 +#define TRANS_VSYNC_START_SHIFT 0 +#define _PCH_TRANS_VSYNCSHIFT_A 0xe0028 + +#define _PCH_TRANSA_DATA_M1 0xe0030 +#define _PCH_TRANSA_DATA_N1 0xe0034 +#define _PCH_TRANSA_DATA_M2 0xe0038 +#define _PCH_TRANSA_DATA_N2 0xe003c +#define _PCH_TRANSA_LINK_M1 0xe0040 +#define _PCH_TRANSA_LINK_N1 0xe0044 +#define _PCH_TRANSA_LINK_M2 0xe0048 +#define _PCH_TRANSA_LINK_N2 0xe004c + +/* Per-transcoder DIP controls */ + +#define _VIDEO_DIP_CTL_A 0xe0200 +#define _VIDEO_DIP_DATA_A 0xe0208 +#define _VIDEO_DIP_GCP_A 0xe0210 + +#define _VIDEO_DIP_CTL_B 0xe1200 +#define _VIDEO_DIP_DATA_B 0xe1208 +#define _VIDEO_DIP_GCP_B 0xe1210 + +#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B) +#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) +#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) + +#define VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200) +#define VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210) + +#define VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170) +#define VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178) + +#define VLV_TVIDEO_DIP_CTL(pipe) \ + _PIPE(pipe, VLV_VIDEO_DIP_CTL_A, VLV_VIDEO_DIP_CTL_B) +#define VLV_TVIDEO_DIP_DATA(pipe) \ + _PIPE(pipe, VLV_VIDEO_DIP_DATA_A, VLV_VIDEO_DIP_DATA_B) +#define VLV_TVIDEO_DIP_GCP(pipe) \ + _PIPE(pipe, VLV_VIDEO_DIP_GDCP_PAYLOAD_A, VLV_VIDEO_DIP_GDCP_PAYLOAD_B) + +/* Haswell DIP controls */ +#define HSW_VIDEO_DIP_CTL_A 0x60200 +#define HSW_VIDEO_DIP_AVI_DATA_A 0x60220 +#define HSW_VIDEO_DIP_VS_DATA_A 0x60260 +#define HSW_VIDEO_DIP_SPD_DATA_A 0x602A0 +#define HSW_VIDEO_DIP_GMP_DATA_A 0x602E0 +#define HSW_VIDEO_DIP_VSC_DATA_A 0x60320 +#define HSW_VIDEO_DIP_AVI_ECC_A 0x60240 +#define HSW_VIDEO_DIP_VS_ECC_A 0x60280 +#define HSW_VIDEO_DIP_SPD_ECC_A 0x602C0 +#define HSW_VIDEO_DIP_GMP_ECC_A 0x60300 +#define HSW_VIDEO_DIP_VSC_ECC_A 0x60344 +#define HSW_VIDEO_DIP_GCP_A 0x60210 + +#define HSW_VIDEO_DIP_CTL_B 0x61200 +#define HSW_VIDEO_DIP_AVI_DATA_B 0x61220 +#define HSW_VIDEO_DIP_VS_DATA_B 0x61260 +#define HSW_VIDEO_DIP_SPD_DATA_B 0x612A0 +#define HSW_VIDEO_DIP_GMP_DATA_B 0x612E0 +#define HSW_VIDEO_DIP_VSC_DATA_B 0x61320 +#define HSW_VIDEO_DIP_BVI_ECC_B 0x61240 +#define HSW_VIDEO_DIP_VS_ECC_B 0x61280 +#define HSW_VIDEO_DIP_SPD_ECC_B 0x612C0 +#define HSW_VIDEO_DIP_GMP_ECC_B 0x61300 +#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344 +#define HSW_VIDEO_DIP_GCP_B 0x61210 + +#define HSW_TVIDEO_DIP_CTL(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) +#define HSW_TVIDEO_DIP_AVI_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) +#define HSW_TVIDEO_DIP_VS_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_VS_DATA_A, HSW_VIDEO_DIP_VS_DATA_B) +#define HSW_TVIDEO_DIP_SPD_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) +#define HSW_TVIDEO_DIP_GCP(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) +#define HSW_TVIDEO_DIP_VSC_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B) + +#define HSW_STEREO_3D_CTL_A 0x70020 +#define S3D_ENABLE (1<<31) +#define HSW_STEREO_3D_CTL_B 0x71020 + +#define HSW_STEREO_3D_CTL(trans) \ + _TRANSCODER(trans, HSW_STEREO_3D_CTL_A, HSW_STEREO_3D_CTL_A) + +#define _PCH_TRANS_HTOTAL_B 0xe1000 +#define _PCH_TRANS_HBLANK_B 0xe1004 +#define _PCH_TRANS_HSYNC_B 0xe1008 +#define _PCH_TRANS_VTOTAL_B 0xe100c +#define _PCH_TRANS_VBLANK_B 0xe1010 +#define _PCH_TRANS_VSYNC_B 0xe1014 +#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028 + +#define PCH_TRANS_HTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B) +#define PCH_TRANS_HBLANK(pipe) _PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B) +#define PCH_TRANS_HSYNC(pipe) _PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B) +#define PCH_TRANS_VTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B) +#define PCH_TRANS_VBLANK(pipe) _PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B) +#define PCH_TRANS_VSYNC(pipe) _PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B) +#define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \ + _PCH_TRANS_VSYNCSHIFT_B) + +#define _PCH_TRANSB_DATA_M1 0xe1030 +#define _PCH_TRANSB_DATA_N1 0xe1034 +#define _PCH_TRANSB_DATA_M2 0xe1038 +#define _PCH_TRANSB_DATA_N2 0xe103c +#define _PCH_TRANSB_LINK_M1 0xe1040 +#define _PCH_TRANSB_LINK_N1 0xe1044 +#define _PCH_TRANSB_LINK_M2 0xe1048 +#define _PCH_TRANSB_LINK_N2 0xe104c + +#define PCH_TRANS_DATA_M1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1) +#define PCH_TRANS_DATA_N1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1) +#define PCH_TRANS_DATA_M2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2) +#define PCH_TRANS_DATA_N2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2) +#define PCH_TRANS_LINK_M1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1) +#define PCH_TRANS_LINK_N1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1) +#define PCH_TRANS_LINK_M2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2) +#define PCH_TRANS_LINK_N2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2) + +#define _PCH_TRANSACONF 0xf0008 +#define _PCH_TRANSBCONF 0xf1008 +#define PCH_TRANSCONF(pipe) _PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF) +#define LPT_TRANSCONF _PCH_TRANSACONF /* lpt has only one transcoder */ +#define TRANS_DISABLE (0<<31) +#define TRANS_ENABLE (1<<31) +#define TRANS_STATE_MASK (1<<30) +#define TRANS_STATE_DISABLE (0<<30) +#define TRANS_STATE_ENABLE (1<<30) +#define TRANS_FSYNC_DELAY_HB1 (0<<27) +#define TRANS_FSYNC_DELAY_HB2 (1<<27) +#define TRANS_FSYNC_DELAY_HB3 (2<<27) +#define TRANS_FSYNC_DELAY_HB4 (3<<27) +#define TRANS_INTERLACE_MASK (7<<21) +#define TRANS_PROGRESSIVE (0<<21) +#define TRANS_INTERLACED (3<<21) +#define TRANS_LEGACY_INTERLACED_ILK (2<<21) +#define TRANS_8BPC (0<<5) +#define TRANS_10BPC (1<<5) +#define TRANS_6BPC (2<<5) +#define TRANS_12BPC (3<<5) + +#define _TRANSA_CHICKEN1 0xf0060 +#define _TRANSB_CHICKEN1 0xf1060 +#define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1) +#define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1<<4) +#define _TRANSA_CHICKEN2 0xf0064 +#define _TRANSB_CHICKEN2 0xf1064 +#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) +#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) +#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) +#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25) + +#define SOUTH_CHICKEN1 0xc2000 +#define FDIA_PHASE_SYNC_SHIFT_OVR 19 +#define FDIA_PHASE_SYNC_SHIFT_EN 18 +#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) +#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) +#define FDI_BC_BIFURCATION_SELECT (1 << 12) +#define SOUTH_CHICKEN2 0xc2004 +#define FDI_MPHY_IOSFSB_RESET_STATUS (1<<13) +#define FDI_MPHY_IOSFSB_RESET_CTL (1<<12) +#define DPLS_EDP_PPS_FIX_DIS (1<<0) + +#define _FDI_RXA_CHICKEN 0xc200c +#define _FDI_RXB_CHICKEN 0xc2010 +#define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1) +#define FDI_RX_PHASE_SYNC_POINTER_EN (1<<0) +#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN) + +#define SOUTH_DSPCLK_GATE_D 0xc2020 +#define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30) +#define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29) +#define PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14) +#define PCH_LP_PARTITION_LEVEL_DISABLE (1<<12) + +/* CPU: FDI_TX */ +#define _FDI_TXA_CTL 0x60100 +#define _FDI_TXB_CTL 0x61100 +#define FDI_TX_CTL(pipe) _PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL) +#define FDI_TX_DISABLE (0<<31) +#define FDI_TX_ENABLE (1<<31) +#define FDI_LINK_TRAIN_PATTERN_1 (0<<28) +#define FDI_LINK_TRAIN_PATTERN_2 (1<<28) +#define FDI_LINK_TRAIN_PATTERN_IDLE (2<<28) +#define FDI_LINK_TRAIN_NONE (3<<28) +#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2<<25) +#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3<<25) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3<<22) +/* ILK always use 400mV 0dB for voltage swing and pre-emphasis level. + SNB has different settings. */ +/* SNB A-stepping */ +#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38<<22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02<<22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22) +/* SNB B-stepping */ +#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x0<<22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a<<22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22) +#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f<<22) +#define FDI_DP_PORT_WIDTH_SHIFT 19 +#define FDI_DP_PORT_WIDTH_MASK (7 << FDI_DP_PORT_WIDTH_SHIFT) +#define FDI_DP_PORT_WIDTH(width) (((width) - 1) << FDI_DP_PORT_WIDTH_SHIFT) +#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) +/* Ironlake: hardwired to 1 */ +#define FDI_TX_PLL_ENABLE (1<<14) + +/* Ivybridge has different bits for lolz */ +#define FDI_LINK_TRAIN_PATTERN_1_IVB (0<<8) +#define FDI_LINK_TRAIN_PATTERN_2_IVB (1<<8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2<<8) +#define FDI_LINK_TRAIN_NONE_IVB (3<<8) + +/* both Tx and Rx */ +#define FDI_COMPOSITE_SYNC (1<<11) +#define FDI_LINK_TRAIN_AUTO (1<<10) +#define FDI_SCRAMBLING_ENABLE (0<<7) +#define FDI_SCRAMBLING_DISABLE (1<<7) + +/* FDI_RX, FDI_X is hard-wired to Transcoder_X */ +#define _FDI_RXA_CTL 0xf000c +#define _FDI_RXB_CTL 0xf100c +#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL) +#define FDI_RX_ENABLE (1<<31) +/* train, dp width same as FDI_TX */ +#define FDI_FS_ERRC_ENABLE (1<<27) +#define FDI_FE_ERRC_ENABLE (1<<26) +#define FDI_RX_POLARITY_REVERSED_LPT (1<<16) +#define FDI_8BPC (0<<16) +#define FDI_10BPC (1<<16) +#define FDI_6BPC (2<<16) +#define FDI_12BPC (3<<16) +#define FDI_RX_LINK_REVERSAL_OVERRIDE (1<<15) +#define FDI_DMI_LINK_REVERSE_MASK (1<<14) +#define FDI_RX_PLL_ENABLE (1<<13) +#define FDI_FS_ERR_CORRECT_ENABLE (1<<11) +#define FDI_FE_ERR_CORRECT_ENABLE (1<<10) +#define FDI_FS_ERR_REPORT_ENABLE (1<<9) +#define FDI_FE_ERR_REPORT_ENABLE (1<<8) +#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6) +#define FDI_PCDCLK (1<<4) +/* CPT */ +#define FDI_AUTO_TRAINING (1<<10) +#define FDI_LINK_TRAIN_PATTERN_1_CPT (0<<8) +#define FDI_LINK_TRAIN_PATTERN_2_CPT (1<<8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8) +#define FDI_LINK_TRAIN_NORMAL_CPT (3<<8) +#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8) + +#define _FDI_RXA_MISC 0xf0010 +#define _FDI_RXB_MISC 0xf1010 +#define FDI_RX_PWRDN_LANE1_MASK (3<<26) +#define FDI_RX_PWRDN_LANE1_VAL(x) ((x)<<26) +#define FDI_RX_PWRDN_LANE0_MASK (3<<24) +#define FDI_RX_PWRDN_LANE0_VAL(x) ((x)<<24) +#define FDI_RX_TP1_TO_TP2_48 (2<<20) +#define FDI_RX_TP1_TO_TP2_64 (3<<20) +#define FDI_RX_FDI_DELAY_90 (0x90<<0) +#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC) + +#define _FDI_RXA_TUSIZE1 0xf0030 +#define _FDI_RXA_TUSIZE2 0xf0038 +#define _FDI_RXB_TUSIZE1 0xf1030 +#define _FDI_RXB_TUSIZE2 0xf1038 +#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1) +#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2) + +/* FDI_RX interrupt register format */ +#define FDI_RX_INTER_LANE_ALIGN (1<<10) +#define FDI_RX_SYMBOL_LOCK (1<<9) /* train 2 */ +#define FDI_RX_BIT_LOCK (1<<8) /* train 1 */ +#define FDI_RX_TRAIN_PATTERN_2_FAIL (1<<7) +#define FDI_RX_FS_CODE_ERR (1<<6) +#define FDI_RX_FE_CODE_ERR (1<<5) +#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1<<4) +#define FDI_RX_HDCP_LINK_FAIL (1<<3) +#define FDI_RX_PIXEL_FIFO_OVERFLOW (1<<2) +#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1) +#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0) + +#define _FDI_RXA_IIR 0xf0014 +#define _FDI_RXA_IMR 0xf0018 +#define _FDI_RXB_IIR 0xf1014 +#define _FDI_RXB_IMR 0xf1018 +#define FDI_RX_IIR(pipe) _PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR) +#define FDI_RX_IMR(pipe) _PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR) + +#define FDI_PLL_CTL_1 0xfe000 +#define FDI_PLL_CTL_2 0xfe004 + +#define PCH_LVDS 0xe1180 +#define LVDS_DETECTED (1 << 1) + +/* vlv has 2 sets of panel control regs. */ +#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200) +#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204) +#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208) +#define PANEL_PORT_SELECT_DPB_VLV (1 << 30) +#define PANEL_PORT_SELECT_DPC_VLV (2 << 30) +#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c) +#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210) + +#define PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300) +#define PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304) +#define PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308) +#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) +#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) + +#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS) +#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL) +#define VLV_PIPE_PP_ON_DELAYS(pipe) \ + _PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS) +#define VLV_PIPE_PP_OFF_DELAYS(pipe) \ + _PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS) +#define VLV_PIPE_PP_DIVISOR(pipe) \ + _PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR) + +#define PCH_PP_STATUS 0xc7200 +#define PCH_PP_CONTROL 0xc7204 +#define PANEL_UNLOCK_REGS (0xabcd << 16) +#define PANEL_UNLOCK_MASK (0xffff << 16) +#define EDP_FORCE_VDD (1 << 3) +#define EDP_BLC_ENABLE (1 << 2) +#define PANEL_POWER_RESET (1 << 1) +#define PANEL_POWER_OFF (0 << 0) +#define PANEL_POWER_ON (1 << 0) +#define PCH_PP_ON_DELAYS 0xc7208 +#define PANEL_PORT_SELECT_MASK (3 << 30) +#define PANEL_PORT_SELECT_LVDS (0 << 30) +#define PANEL_PORT_SELECT_DPA (1 << 30) +#define PANEL_PORT_SELECT_DPC (2 << 30) +#define PANEL_PORT_SELECT_DPD (3 << 30) +#define PANEL_POWER_UP_DELAY_MASK (0x1fff0000) +#define PANEL_POWER_UP_DELAY_SHIFT 16 +#define PANEL_LIGHT_ON_DELAY_MASK (0x1fff) +#define PANEL_LIGHT_ON_DELAY_SHIFT 0 + +#define PCH_PP_OFF_DELAYS 0xc720c +#define PANEL_POWER_DOWN_DELAY_MASK (0x1fff0000) +#define PANEL_POWER_DOWN_DELAY_SHIFT 16 +#define PANEL_LIGHT_OFF_DELAY_MASK (0x1fff) +#define PANEL_LIGHT_OFF_DELAY_SHIFT 0 + +#define PCH_PP_DIVISOR 0xc7210 +#define PP_REFERENCE_DIVIDER_MASK (0xffffff00) +#define PP_REFERENCE_DIVIDER_SHIFT 8 +#define PANEL_POWER_CYCLE_DELAY_MASK (0x1f) +#define PANEL_POWER_CYCLE_DELAY_SHIFT 0 + +#define PCH_DP_B 0xe4100 +#define PCH_DPB_AUX_CH_CTL 0xe4110 +#define PCH_DPB_AUX_CH_DATA1 0xe4114 +#define PCH_DPB_AUX_CH_DATA2 0xe4118 +#define PCH_DPB_AUX_CH_DATA3 0xe411c +#define PCH_DPB_AUX_CH_DATA4 0xe4120 +#define PCH_DPB_AUX_CH_DATA5 0xe4124 + +#define PCH_DP_C 0xe4200 +#define PCH_DPC_AUX_CH_CTL 0xe4210 +#define PCH_DPC_AUX_CH_DATA1 0xe4214 +#define PCH_DPC_AUX_CH_DATA2 0xe4218 +#define PCH_DPC_AUX_CH_DATA3 0xe421c +#define PCH_DPC_AUX_CH_DATA4 0xe4220 +#define PCH_DPC_AUX_CH_DATA5 0xe4224 + +#define PCH_DP_D 0xe4300 +#define PCH_DPD_AUX_CH_CTL 0xe4310 +#define PCH_DPD_AUX_CH_DATA1 0xe4314 +#define PCH_DPD_AUX_CH_DATA2 0xe4318 +#define PCH_DPD_AUX_CH_DATA3 0xe431c +#define PCH_DPD_AUX_CH_DATA4 0xe4320 +#define PCH_DPD_AUX_CH_DATA5 0xe4324 + +/* CPT */ +#define PORT_TRANS_A_SEL_CPT 0 +#define PORT_TRANS_B_SEL_CPT (1<<29) +#define PORT_TRANS_C_SEL_CPT (2<<29) +#define PORT_TRANS_SEL_MASK (3<<29) +#define PORT_TRANS_SEL_CPT(pipe) ((pipe) << 29) +#define PORT_TO_PIPE(val) (((val) & (1<<30)) >> 30) +#define PORT_TO_PIPE_CPT(val) (((val) & PORT_TRANS_SEL_MASK) >> 29) + +#define TRANS_DP_CTL_A 0xe0300 +#define TRANS_DP_CTL_B 0xe1300 +#define TRANS_DP_CTL_C 0xe2300 +#define TRANS_DP_CTL(pipe) _PIPE(pipe, TRANS_DP_CTL_A, TRANS_DP_CTL_B) +#define TRANS_DP_OUTPUT_ENABLE (1<<31) +#define TRANS_DP_PORT_SEL_B (0<<29) +#define TRANS_DP_PORT_SEL_C (1<<29) +#define TRANS_DP_PORT_SEL_D (2<<29) +#define TRANS_DP_PORT_SEL_NONE (3<<29) +#define TRANS_DP_PORT_SEL_MASK (3<<29) +#define TRANS_DP_AUDIO_ONLY (1<<26) +#define TRANS_DP_ENH_FRAMING (1<<18) +#define TRANS_DP_8BPC (0<<9) +#define TRANS_DP_10BPC (1<<9) +#define TRANS_DP_6BPC (2<<9) +#define TRANS_DP_12BPC (3<<9) +#define TRANS_DP_BPC_MASK (3<<9) +#define TRANS_DP_VSYNC_ACTIVE_HIGH (1<<4) +#define TRANS_DP_VSYNC_ACTIVE_LOW 0 +#define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3) +#define TRANS_DP_HSYNC_ACTIVE_LOW 0 +#define TRANS_DP_SYNC_MASK (3<<3) + +/* SNB eDP training params */ +/* SNB A-stepping */ +#define EDP_LINK_TRAIN_400MV_0DB_SNB_A (0x38<<22) +#define EDP_LINK_TRAIN_400MV_6DB_SNB_A (0x02<<22) +#define EDP_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22) +#define EDP_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22) +/* SNB B-stepping */ +#define EDP_LINK_TRAIN_400_600MV_0DB_SNB_B (0x0<<22) +#define EDP_LINK_TRAIN_400MV_3_5DB_SNB_B (0x1<<22) +#define EDP_LINK_TRAIN_400_600MV_6DB_SNB_B (0x3a<<22) +#define EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B (0x39<<22) +#define EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B (0x38<<22) +#define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f<<22) + +/* IVB */ +#define EDP_LINK_TRAIN_400MV_0DB_IVB (0x24 <<22) +#define EDP_LINK_TRAIN_400MV_3_5DB_IVB (0x2a <<22) +#define EDP_LINK_TRAIN_400MV_6DB_IVB (0x2f <<22) +#define EDP_LINK_TRAIN_600MV_0DB_IVB (0x30 <<22) +#define EDP_LINK_TRAIN_600MV_3_5DB_IVB (0x36 <<22) +#define EDP_LINK_TRAIN_800MV_0DB_IVB (0x38 <<22) +#define EDP_LINK_TRAIN_800MV_3_5DB_IVB (0x3e <<22) + +/* legacy values */ +#define EDP_LINK_TRAIN_500MV_0DB_IVB (0x00 <<22) +#define EDP_LINK_TRAIN_1000MV_0DB_IVB (0x20 <<22) +#define EDP_LINK_TRAIN_500MV_3_5DB_IVB (0x02 <<22) +#define EDP_LINK_TRAIN_1000MV_3_5DB_IVB (0x22 <<22) +#define EDP_LINK_TRAIN_1000MV_6DB_IVB (0x23 <<22) + +#define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22) + +#define FORCEWAKE 0xA18C +#define FORCEWAKE_VLV 0x1300b0 +#define FORCEWAKE_ACK_VLV 0x1300b4 +#define FORCEWAKE_MEDIA_VLV 0x1300b8 +#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc +#define FORCEWAKE_ACK_HSW 0x130044 +#define FORCEWAKE_ACK 0x130090 +#define VLV_GTLC_WAKE_CTRL 0x130090 +#define VLV_GTLC_PW_STATUS 0x130094 +#define VLV_GTLC_PW_RENDER_STATUS_MASK 0x80 +#define VLV_GTLC_PW_MEDIA_STATUS_MASK 0x20 +#define FORCEWAKE_MT 0xa188 /* multi-threaded */ +#define FORCEWAKE_KERNEL 0x1 +#define FORCEWAKE_USER 0x2 +#define FORCEWAKE_MT_ACK 0x130040 +#define ECOBUS 0xa180 +#define FORCEWAKE_MT_ENABLE (1<<5) + +#define GTFIFODBG 0x120000 +#define GT_FIFO_SBDROPERR (1<<6) +#define GT_FIFO_BLOBDROPERR (1<<5) +#define GT_FIFO_SB_READ_ABORTERR (1<<4) +#define GT_FIFO_DROPERR (1<<3) +#define GT_FIFO_OVFERR (1<<2) +#define GT_FIFO_IAWRERR (1<<1) +#define GT_FIFO_IARDERR (1<<0) + +#define GTFIFOCTL 0x120008 +#define GT_FIFO_FREE_ENTRIES_MASK 0x7f +#define GT_FIFO_NUM_RESERVED_ENTRIES 20 + +#define HSW_IDICR 0x9008 +#define IDIHASHMSK(x) (((x) & 0x3f) << 16) +#define HSW_EDRAM_PRESENT 0x120010 + +#define GEN6_UCGCTL1 0x9400 +# define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) +# define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7) + +#define GEN6_UCGCTL2 0x9404 +# define GEN7_VDSUNIT_CLOCK_GATE_DISABLE (1 << 30) +# define GEN7_TDLUNIT_CLOCK_GATE_DISABLE (1 << 22) +# define GEN6_RCZUNIT_CLOCK_GATE_DISABLE (1 << 13) +# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) +# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11) + +#define GEN7_UCGCTL4 0x940c +#define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1<<25) + +#define GEN8_UCGCTL6 0x9430 +#define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1<<14) + +#define GEN6_RPNSWREQ 0xA008 +#define GEN6_TURBO_DISABLE (1<<31) +#define GEN6_FREQUENCY(x) ((x)<<25) +#define HSW_FREQUENCY(x) ((x)<<24) +#define GEN6_OFFSET(x) ((x)<<19) +#define GEN6_AGGRESSIVE_TURBO (0<<15) +#define GEN6_RC_VIDEO_FREQ 0xA00C +#define GEN6_RC_CONTROL 0xA090 +#define GEN6_RC_CTL_RC6pp_ENABLE (1<<16) +#define GEN6_RC_CTL_RC6p_ENABLE (1<<17) +#define GEN6_RC_CTL_RC6_ENABLE (1<<18) +#define GEN6_RC_CTL_RC1e_ENABLE (1<<20) +#define GEN6_RC_CTL_RC7_ENABLE (1<<22) +#define VLV_RC_CTL_CTX_RST_PARALLEL (1<<24) +#define GEN7_RC_CTL_TO_MODE (1<<28) +#define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) +#define GEN6_RC_CTL_HW_ENABLE (1<<31) +#define GEN6_RP_DOWN_TIMEOUT 0xA010 +#define GEN6_RP_INTERRUPT_LIMITS 0xA014 +#define GEN6_RPSTAT1 0xA01C +#define GEN6_CAGF_SHIFT 8 +#define HSW_CAGF_SHIFT 7 +#define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT) +#define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT) +#define GEN6_RP_CONTROL 0xA024 +#define GEN6_RP_MEDIA_TURBO (1<<11) +#define GEN6_RP_MEDIA_MODE_MASK (3<<9) +#define GEN6_RP_MEDIA_HW_TURBO_MODE (3<<9) +#define GEN6_RP_MEDIA_HW_NORMAL_MODE (2<<9) +#define GEN6_RP_MEDIA_HW_MODE (1<<9) +#define GEN6_RP_MEDIA_SW_MODE (0<<9) +#define GEN6_RP_MEDIA_IS_GFX (1<<8) +#define GEN6_RP_ENABLE (1<<7) +#define GEN6_RP_UP_IDLE_MIN (0x1<<3) +#define GEN6_RP_UP_BUSY_AVG (0x2<<3) +#define GEN6_RP_UP_BUSY_CONT (0x4<<3) +#define GEN6_RP_DOWN_IDLE_AVG (0x2<<0) +#define GEN6_RP_DOWN_IDLE_CONT (0x1<<0) +#define GEN6_RP_UP_THRESHOLD 0xA02C +#define GEN6_RP_DOWN_THRESHOLD 0xA030 +#define GEN6_RP_CUR_UP_EI 0xA050 +#define GEN6_CURICONT_MASK 0xffffff +#define GEN6_RP_CUR_UP 0xA054 +#define GEN6_CURBSYTAVG_MASK 0xffffff +#define GEN6_RP_PREV_UP 0xA058 +#define GEN6_RP_CUR_DOWN_EI 0xA05C +#define GEN6_CURIAVG_MASK 0xffffff +#define GEN6_RP_CUR_DOWN 0xA060 +#define GEN6_RP_PREV_DOWN 0xA064 +#define GEN6_RP_UP_EI 0xA068 +#define GEN6_RP_DOWN_EI 0xA06C +#define GEN6_RP_IDLE_HYSTERSIS 0xA070 +#define GEN6_RC_STATE 0xA094 +#define GEN6_RC1_WAKE_RATE_LIMIT 0xA098 +#define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C +#define GEN6_RC6pp_WAKE_RATE_LIMIT 0xA0A0 +#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8 +#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC +#define GEN6_RC_SLEEP 0xA0B0 +#define GEN6_RC1e_THRESHOLD 0xA0B4 +#define GEN6_RC6_THRESHOLD 0xA0B8 +#define GEN6_RC6p_THRESHOLD 0xA0BC +#define GEN6_RC6pp_THRESHOLD 0xA0C0 +#define GEN6_PMINTRMSK 0xA168 + +#define GEN6_PMISR 0x44020 +#define GEN6_PMIMR 0x44024 /* rps_lock */ +#define GEN6_PMIIR 0x44028 +#define GEN6_PMIER 0x4402C +#define GEN6_PM_MBOX_EVENT (1<<25) +#define GEN6_PM_THERMAL_EVENT (1<<24) +#define GEN6_PM_RP_DOWN_TIMEOUT (1<<6) +#define GEN6_PM_RP_UP_THRESHOLD (1<<5) +#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4) +#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) +#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) +#define GEN6_PM_RPS_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \ + GEN6_PM_RP_DOWN_THRESHOLD | \ + GEN6_PM_RP_DOWN_TIMEOUT) + +#define GEN6_GT_GFX_RC6_LOCKED 0x138104 +#define VLV_COUNTER_CONTROL 0x138104 +#define VLV_COUNT_RANGE_HIGH (1<<15) +#define VLV_MEDIA_RC6_COUNT_EN (1<<1) +#define VLV_RENDER_RC6_COUNT_EN (1<<0) +#define GEN6_GT_GFX_RC6 0x138108 +#define GEN6_GT_GFX_RC6p 0x13810C +#define GEN6_GT_GFX_RC6pp 0x138110 + +#define GEN6_PCODE_MAILBOX 0x138124 +#define GEN6_PCODE_READY (1<<31) +#define GEN6_READ_OC_PARAMS 0xc +#define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x8 +#define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 +#define GEN6_PCODE_WRITE_RC6VIDS 0x4 +#define GEN6_PCODE_READ_RC6VIDS 0x5 +#define GEN6_PCODE_READ_D_COMP 0x10 +#define GEN6_PCODE_WRITE_D_COMP 0x11 +#define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) +#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) +#define DISPLAY_IPS_CONTROL 0x19 +#define GEN6_PCODE_DATA 0x138128 +#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 +#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 + +#define GEN6_GT_CORE_STATUS 0x138060 +#define GEN6_CORE_CPD_STATE_MASK (7<<4) +#define GEN6_RCn_MASK 7 +#define GEN6_RC0 0 +#define GEN6_RC3 2 +#define GEN6_RC6 3 +#define GEN6_RC7 4 + +#define GEN7_MISCCPCTL (0x9424) +#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0) + +/* IVYBRIDGE DPF */ +#define GEN7_L3CDERRST1 0xB008 /* L3CD Error Status 1 */ +#define HSW_L3CDERRST11 0xB208 /* L3CD Error Status register 1 slice 1 */ +#define GEN7_L3CDERRST1_ROW_MASK (0x7ff<<14) +#define GEN7_PARITY_ERROR_VALID (1<<13) +#define GEN7_L3CDERRST1_BANK_MASK (3<<11) +#define GEN7_L3CDERRST1_SUBBANK_MASK (7<<8) +#define GEN7_PARITY_ERROR_ROW(reg) \ + ((reg & GEN7_L3CDERRST1_ROW_MASK) >> 14) +#define GEN7_PARITY_ERROR_BANK(reg) \ + ((reg & GEN7_L3CDERRST1_BANK_MASK) >> 11) +#define GEN7_PARITY_ERROR_SUBBANK(reg) \ + ((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8) +#define GEN7_L3CDERRST1_ENABLE (1<<7) + +#define GEN7_L3LOG_BASE 0xB070 +#define HSW_L3LOG_BASE_SLICE1 0xB270 +#define GEN7_L3LOG_SIZE 0x80 + +#define GEN7_HALF_SLICE_CHICKEN1 0xe100 /* IVB GT1 + VLV */ +#define GEN7_HALF_SLICE_CHICKEN1_GT2 0xf100 +#define GEN7_MAX_PS_THREAD_DEP (8<<12) +#define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1<<10) +#define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3) + +#define GEN8_ROW_CHICKEN 0xe4f0 +#define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE (1<<8) +#define STALL_DOP_GATING_DISABLE (1<<5) + +#define GEN7_ROW_CHICKEN2 0xe4f4 +#define GEN7_ROW_CHICKEN2_GT2 0xf4f4 +#define DOP_CLOCK_GATING_DISABLE (1<<0) + +#define HSW_ROW_CHICKEN3 0xe49c +#define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) + +#define HALF_SLICE_CHICKEN3 0xe184 +#define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8) +#define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1) + +#define G4X_AUD_VID_DID (dev_priv->info->display_mmio_offset + 0x62020) +#define INTEL_AUDIO_DEVCL 0x808629FB +#define INTEL_AUDIO_DEVBLC 0x80862801 +#define INTEL_AUDIO_DEVCTG 0x80862802 + +#define G4X_AUD_CNTL_ST 0x620B4 +#define G4X_ELDV_DEVCL_DEVBLC (1 << 13) +#define G4X_ELDV_DEVCTG (1 << 14) +#define G4X_ELD_ADDR (0xf << 5) +#define G4X_ELD_ACK (1 << 4) +#define G4X_HDMIW_HDMIEDID 0x6210C + +#define IBX_HDMIW_HDMIEDID_A 0xE2050 +#define IBX_HDMIW_HDMIEDID_B 0xE2150 +#define IBX_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ + IBX_HDMIW_HDMIEDID_A, \ + IBX_HDMIW_HDMIEDID_B) +#define IBX_AUD_CNTL_ST_A 0xE20B4 +#define IBX_AUD_CNTL_ST_B 0xE21B4 +#define IBX_AUD_CNTL_ST(pipe) _PIPE(pipe, \ + IBX_AUD_CNTL_ST_A, \ + IBX_AUD_CNTL_ST_B) +#define IBX_ELD_BUFFER_SIZE (0x1f << 10) +#define IBX_ELD_ADDRESS (0x1f << 5) +#define IBX_ELD_ACK (1 << 4) +#define IBX_AUD_CNTL_ST2 0xE20C0 +#define IBX_ELD_VALIDB (1 << 0) +#define IBX_CP_READYB (1 << 1) + +#define CPT_HDMIW_HDMIEDID_A 0xE5050 +#define CPT_HDMIW_HDMIEDID_B 0xE5150 +#define CPT_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ + CPT_HDMIW_HDMIEDID_A, \ + CPT_HDMIW_HDMIEDID_B) +#define CPT_AUD_CNTL_ST_A 0xE50B4 +#define CPT_AUD_CNTL_ST_B 0xE51B4 +#define CPT_AUD_CNTL_ST(pipe) _PIPE(pipe, \ + CPT_AUD_CNTL_ST_A, \ + CPT_AUD_CNTL_ST_B) +#define CPT_AUD_CNTRL_ST2 0xE50C0 + +#define VLV_HDMIW_HDMIEDID_A (VLV_DISPLAY_BASE + 0x62050) +#define VLV_HDMIW_HDMIEDID_B (VLV_DISPLAY_BASE + 0x62150) +#define VLV_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ + VLV_HDMIW_HDMIEDID_A, \ + VLV_HDMIW_HDMIEDID_B) +#define VLV_AUD_CNTL_ST_A (VLV_DISPLAY_BASE + 0x620B4) +#define VLV_AUD_CNTL_ST_B (VLV_DISPLAY_BASE + 0x621B4) +#define VLV_AUD_CNTL_ST(pipe) _PIPE(pipe, \ + VLV_AUD_CNTL_ST_A, \ + VLV_AUD_CNTL_ST_B) +#define VLV_AUD_CNTL_ST2 (VLV_DISPLAY_BASE + 0x620C0) + +/* These are the 4 32-bit write offset registers for each stream + * output buffer. It determines the offset from the + * 3DSTATE_SO_BUFFERs that the next streamed vertex output goes to. + */ +#define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4) + +#define IBX_AUD_CONFIG_A 0xe2000 +#define IBX_AUD_CONFIG_B 0xe2100 +#define IBX_AUD_CFG(pipe) _PIPE(pipe, \ + IBX_AUD_CONFIG_A, \ + IBX_AUD_CONFIG_B) +#define CPT_AUD_CONFIG_A 0xe5000 +#define CPT_AUD_CONFIG_B 0xe5100 +#define CPT_AUD_CFG(pipe) _PIPE(pipe, \ + CPT_AUD_CONFIG_A, \ + CPT_AUD_CONFIG_B) +#define VLV_AUD_CONFIG_A (VLV_DISPLAY_BASE + 0x62000) +#define VLV_AUD_CONFIG_B (VLV_DISPLAY_BASE + 0x62100) +#define VLV_AUD_CFG(pipe) _PIPE(pipe, \ + VLV_AUD_CONFIG_A, \ + VLV_AUD_CONFIG_B) + +#define AUD_CONFIG_N_VALUE_INDEX (1 << 29) +#define AUD_CONFIG_N_PROG_ENABLE (1 << 28) +#define AUD_CONFIG_UPPER_N_SHIFT 20 +#define AUD_CONFIG_UPPER_N_VALUE (0xff << 20) +#define AUD_CONFIG_LOWER_N_SHIFT 4 +#define AUD_CONFIG_LOWER_N_VALUE (0xfff << 4) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_SHIFT 16 +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK (0xf << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 (0 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 (1 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 (2 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 (3 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 (4 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 (5 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 (6 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 (7 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 (8 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 (9 << 16) +#define AUD_CONFIG_DISABLE_NCTS (1 << 3) + +/* HSW Audio */ +#define HSW_AUD_CONFIG_A 0x65000 /* Audio Configuration Transcoder A */ +#define HSW_AUD_CONFIG_B 0x65100 /* Audio Configuration Transcoder B */ +#define HSW_AUD_CFG(pipe) _PIPE(pipe, \ + HSW_AUD_CONFIG_A, \ + HSW_AUD_CONFIG_B) + +#define HSW_AUD_MISC_CTRL_A 0x65010 /* Audio Misc Control Convert 1 */ +#define HSW_AUD_MISC_CTRL_B 0x65110 /* Audio Misc Control Convert 2 */ +#define HSW_AUD_MISC_CTRL(pipe) _PIPE(pipe, \ + HSW_AUD_MISC_CTRL_A, \ + HSW_AUD_MISC_CTRL_B) + +#define HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4 /* Audio DIP and ELD Control State Transcoder A */ +#define HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4 /* Audio DIP and ELD Control State Transcoder B */ +#define HSW_AUD_DIP_ELD_CTRL(pipe) _PIPE(pipe, \ + HSW_AUD_DIP_ELD_CTRL_ST_A, \ + HSW_AUD_DIP_ELD_CTRL_ST_B) + +/* Audio Digital Converter */ +#define HSW_AUD_DIG_CNVT_1 0x65080 /* Audio Converter 1 */ +#define HSW_AUD_DIG_CNVT_2 0x65180 /* Audio Converter 1 */ +#define AUD_DIG_CNVT(pipe) _PIPE(pipe, \ + HSW_AUD_DIG_CNVT_1, \ + HSW_AUD_DIG_CNVT_2) +#define DIP_PORT_SEL_MASK 0x3 + +#define HSW_AUD_EDID_DATA_A 0x65050 +#define HSW_AUD_EDID_DATA_B 0x65150 +#define HSW_AUD_EDID_DATA(pipe) _PIPE(pipe, \ + HSW_AUD_EDID_DATA_A, \ + HSW_AUD_EDID_DATA_B) + +#define HSW_AUD_PIPE_CONV_CFG 0x6507c /* Audio pipe and converter configs */ +#define HSW_AUD_PIN_ELD_CP_VLD 0x650c0 /* Audio ELD and CP Ready Status */ +#define AUDIO_INACTIVE_C (1<<11) +#define AUDIO_INACTIVE_B (1<<7) +#define AUDIO_INACTIVE_A (1<<3) +#define AUDIO_OUTPUT_ENABLE_A (1<<2) +#define AUDIO_OUTPUT_ENABLE_B (1<<6) +#define AUDIO_OUTPUT_ENABLE_C (1<<10) +#define AUDIO_ELD_VALID_A (1<<0) +#define AUDIO_ELD_VALID_B (1<<4) +#define AUDIO_ELD_VALID_C (1<<8) +#define AUDIO_CP_READY_A (1<<1) +#define AUDIO_CP_READY_B (1<<5) +#define AUDIO_CP_READY_C (1<<9) + +/* HSW Power Wells */ +#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */ +#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */ +#define HSW_PWR_WELL_KVMR 0x45408 /* CTL3 */ +#define HSW_PWR_WELL_DEBUG 0x4540C /* CTL4 */ +#define HSW_PWR_WELL_ENABLE_REQUEST (1<<31) +#define HSW_PWR_WELL_STATE_ENABLED (1<<30) +#define HSW_PWR_WELL_CTL5 0x45410 +#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31) +#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20) +#define HSW_PWR_WELL_FORCE_ON (1<<19) +#define HSW_PWR_WELL_CTL6 0x45414 + +/* Per-pipe DDI Function Control */ +#define TRANS_DDI_FUNC_CTL_A 0x60400 +#define TRANS_DDI_FUNC_CTL_B 0x61400 +#define TRANS_DDI_FUNC_CTL_C 0x62400 +#define TRANS_DDI_FUNC_CTL_EDP 0x6F400 +#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER(tran, TRANS_DDI_FUNC_CTL_A, \ + TRANS_DDI_FUNC_CTL_B) +#define TRANS_DDI_FUNC_ENABLE (1<<31) +/* Those bits are ignored by pipe EDP since it can only connect to DDI A */ +#define TRANS_DDI_PORT_MASK (7<<28) +#define TRANS_DDI_SELECT_PORT(x) ((x)<<28) +#define TRANS_DDI_PORT_NONE (0<<28) +#define TRANS_DDI_MODE_SELECT_MASK (7<<24) +#define TRANS_DDI_MODE_SELECT_HDMI (0<<24) +#define TRANS_DDI_MODE_SELECT_DVI (1<<24) +#define TRANS_DDI_MODE_SELECT_DP_SST (2<<24) +#define TRANS_DDI_MODE_SELECT_DP_MST (3<<24) +#define TRANS_DDI_MODE_SELECT_FDI (4<<24) +#define TRANS_DDI_BPC_MASK (7<<20) +#define TRANS_DDI_BPC_8 (0<<20) +#define TRANS_DDI_BPC_10 (1<<20) +#define TRANS_DDI_BPC_6 (2<<20) +#define TRANS_DDI_BPC_12 (3<<20) +#define TRANS_DDI_PVSYNC (1<<17) +#define TRANS_DDI_PHSYNC (1<<16) +#define TRANS_DDI_EDP_INPUT_MASK (7<<12) +#define TRANS_DDI_EDP_INPUT_A_ON (0<<12) +#define TRANS_DDI_EDP_INPUT_A_ONOFF (4<<12) +#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12) +#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) +#define TRANS_DDI_BFI_ENABLE (1<<4) + +/* DisplayPort Transport Control */ +#define DP_TP_CTL_A 0x64040 +#define DP_TP_CTL_B 0x64140 +#define DP_TP_CTL(port) _PORT(port, DP_TP_CTL_A, DP_TP_CTL_B) +#define DP_TP_CTL_ENABLE (1<<31) +#define DP_TP_CTL_MODE_SST (0<<27) +#define DP_TP_CTL_MODE_MST (1<<27) +#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18) +#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15) +#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT3 (4<<8) +#define DP_TP_CTL_LINK_TRAIN_IDLE (2<<8) +#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8) +#define DP_TP_CTL_SCRAMBLE_DISABLE (1<<7) + +/* DisplayPort Transport Status */ +#define DP_TP_STATUS_A 0x64044 +#define DP_TP_STATUS_B 0x64144 +#define DP_TP_STATUS(port) _PORT(port, DP_TP_STATUS_A, DP_TP_STATUS_B) +#define DP_TP_STATUS_IDLE_DONE (1<<25) +#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12) + +/* DDI Buffer Control */ +#define DDI_BUF_CTL_A 0x64000 +#define DDI_BUF_CTL_B 0x64100 +#define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B) +#define DDI_BUF_CTL_ENABLE (1<<31) +/* Haswell */ +#define DDI_BUF_EMP_400MV_0DB_HSW (0<<24) /* Sel0 */ +#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */ +#define DDI_BUF_EMP_400MV_6DB_HSW (2<<24) /* Sel2 */ +#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */ +#define DDI_BUF_EMP_600MV_0DB_HSW (4<<24) /* Sel4 */ +#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */ +#define DDI_BUF_EMP_600MV_6DB_HSW (6<<24) /* Sel6 */ +#define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */ +#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */ +/* Broadwell */ +#define DDI_BUF_EMP_400MV_0DB_BDW (0<<24) /* Sel0 */ +#define DDI_BUF_EMP_400MV_3_5DB_BDW (1<<24) /* Sel1 */ +#define DDI_BUF_EMP_400MV_6DB_BDW (2<<24) /* Sel2 */ +#define DDI_BUF_EMP_600MV_0DB_BDW (3<<24) /* Sel3 */ +#define DDI_BUF_EMP_600MV_3_5DB_BDW (4<<24) /* Sel4 */ +#define DDI_BUF_EMP_600MV_6DB_BDW (5<<24) /* Sel5 */ +#define DDI_BUF_EMP_800MV_0DB_BDW (6<<24) /* Sel6 */ +#define DDI_BUF_EMP_800MV_3_5DB_BDW (7<<24) /* Sel7 */ +#define DDI_BUF_EMP_1200MV_0DB_BDW (8<<24) /* Sel8 */ +#define DDI_BUF_EMP_MASK (0xf<<24) +#define DDI_BUF_PORT_REVERSAL (1<<16) +#define DDI_BUF_IS_IDLE (1<<7) +#define DDI_A_4_LANES (1<<4) +#define DDI_PORT_WIDTH(width) (((width) - 1) << 1) +#define DDI_INIT_DISPLAY_DETECTED (1<<0) + +/* DDI Buffer Translations */ +#define DDI_BUF_TRANS_A 0x64E00 +#define DDI_BUF_TRANS_B 0x64E60 +#define DDI_BUF_TRANS(port) _PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + +/* Sideband Interface (SBI) is programmed indirectly, via + * SBI_ADDR, which contains the register offset; and SBI_DATA, + * which contains the payload */ +#define SBI_ADDR 0xC6000 +#define SBI_DATA 0xC6004 +#define SBI_CTL_STAT 0xC6008 +#define SBI_CTL_DEST_ICLK (0x0<<16) +#define SBI_CTL_DEST_MPHY (0x1<<16) +#define SBI_CTL_OP_IORD (0x2<<8) +#define SBI_CTL_OP_IOWR (0x3<<8) +#define SBI_CTL_OP_CRRD (0x6<<8) +#define SBI_CTL_OP_CRWR (0x7<<8) +#define SBI_RESPONSE_FAIL (0x1<<1) +#define SBI_RESPONSE_SUCCESS (0x0<<1) +#define SBI_BUSY (0x1<<0) +#define SBI_READY (0x0<<0) + +/* SBI offsets */ +#define SBI_SSCDIVINTPHASE6 0x0600 +#define SBI_SSCDIVINTPHASE_DIVSEL_MASK ((0x7f)<<1) +#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x)<<1) +#define SBI_SSCDIVINTPHASE_INCVAL_MASK ((0x7f)<<8) +#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x)<<8) +#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15) +#define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0) +#define SBI_SSCCTL 0x020c +#define SBI_SSCCTL6 0x060C +#define SBI_SSCCTL_PATHALT (1<<3) +#define SBI_SSCCTL_DISABLE (1<<0) +#define SBI_SSCAUXDIV6 0x0610 +#define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x)<<4) +#define SBI_DBUFF0 0x2a00 +#define SBI_GEN0 0x1f00 +#define SBI_GEN0_CFG_BUFFENABLE_DISABLE (1<<0) + +/* LPT PIXCLK_GATE */ +#define PIXCLK_GATE 0xC6020 +#define PIXCLK_GATE_UNGATE (1<<0) +#define PIXCLK_GATE_GATE (0<<0) + +/* SPLL */ +#define SPLL_CTL 0x46020 +#define SPLL_PLL_ENABLE (1<<31) +#define SPLL_PLL_SSC (1<<28) +#define SPLL_PLL_NON_SSC (2<<28) +#define SPLL_PLL_FREQ_810MHz (0<<26) +#define SPLL_PLL_FREQ_1350MHz (1<<26) + +/* WRPLL */ +#define WRPLL_CTL1 0x46040 +#define WRPLL_CTL2 0x46060 +#define WRPLL_PLL_ENABLE (1<<31) +#define WRPLL_PLL_SELECT_SSC (0x01<<28) +#define WRPLL_PLL_SELECT_NON_SSC (0x02<<28) +#define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28) +/* WRPLL divider programming */ +#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) +#define WRPLL_DIVIDER_POST(x) ((x)<<8) +#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16) + +/* Port clock selection */ +#define PORT_CLK_SEL_A 0x46100 +#define PORT_CLK_SEL_B 0x46104 +#define PORT_CLK_SEL(port) _PORT(port, PORT_CLK_SEL_A, PORT_CLK_SEL_B) +#define PORT_CLK_SEL_LCPLL_2700 (0<<29) +#define PORT_CLK_SEL_LCPLL_1350 (1<<29) +#define PORT_CLK_SEL_LCPLL_810 (2<<29) +#define PORT_CLK_SEL_SPLL (3<<29) +#define PORT_CLK_SEL_WRPLL1 (4<<29) +#define PORT_CLK_SEL_WRPLL2 (5<<29) +#define PORT_CLK_SEL_NONE (7<<29) + +/* Transcoder clock selection */ +#define TRANS_CLK_SEL_A 0x46140 +#define TRANS_CLK_SEL_B 0x46144 +#define TRANS_CLK_SEL(tran) _TRANSCODER(tran, TRANS_CLK_SEL_A, TRANS_CLK_SEL_B) +/* For each transcoder, we need to select the corresponding port clock */ +#define TRANS_CLK_SEL_DISABLED (0x0<<29) +#define TRANS_CLK_SEL_PORT(x) ((x+1)<<29) + +#define _TRANSA_MSA_MISC 0x60410 +#define _TRANSB_MSA_MISC 0x61410 +#define TRANS_MSA_MISC(tran) _TRANSCODER(tran, _TRANSA_MSA_MISC, \ + _TRANSB_MSA_MISC) +#define TRANS_MSA_SYNC_CLK (1<<0) +#define TRANS_MSA_6_BPC (0<<5) +#define TRANS_MSA_8_BPC (1<<5) +#define TRANS_MSA_10_BPC (2<<5) +#define TRANS_MSA_12_BPC (3<<5) +#define TRANS_MSA_16_BPC (4<<5) + +/* LCPLL Control */ +#define LCPLL_CTL 0x130040 +#define LCPLL_PLL_DISABLE (1<<31) +#define LCPLL_PLL_LOCK (1<<30) +#define LCPLL_CLK_FREQ_MASK (3<<26) +#define LCPLL_CLK_FREQ_450 (0<<26) +#define LCPLL_CLK_FREQ_54O_BDW (1<<26) +#define LCPLL_CLK_FREQ_337_5_BDW (2<<26) +#define LCPLL_CLK_FREQ_675_BDW (3<<26) +#define LCPLL_CD_CLOCK_DISABLE (1<<25) +#define LCPLL_CD2X_CLOCK_DISABLE (1<<23) +#define LCPLL_POWER_DOWN_ALLOW (1<<22) +#define LCPLL_CD_SOURCE_FCLK (1<<21) +#define LCPLL_CD_SOURCE_FCLK_DONE (1<<19) + +#define D_COMP (MCHBAR_MIRROR_BASE_SNB + 0x5F0C) +#define D_COMP_RCOMP_IN_PROGRESS (1<<9) +#define D_COMP_COMP_FORCE (1<<8) +#define D_COMP_COMP_DISABLE (1<<0) + +/* Pipe WM_LINETIME - watermark line time */ +#define PIPE_WM_LINETIME_A 0x45270 +#define PIPE_WM_LINETIME_B 0x45274 +#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, PIPE_WM_LINETIME_A, \ + PIPE_WM_LINETIME_B) +#define PIPE_WM_LINETIME_MASK (0x1ff) +#define PIPE_WM_LINETIME_TIME(x) ((x)) +#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16) +#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16) + +/* SFUSE_STRAP */ +#define SFUSE_STRAP 0xc2014 +#define SFUSE_STRAP_DDIB_DETECTED (1<<2) +#define SFUSE_STRAP_DDIC_DETECTED (1<<1) +#define SFUSE_STRAP_DDID_DETECTED (1<<0) + +#define WM_MISC 0x45260 +#define WM_MISC_DATA_PARTITION_5_6 (1 << 0) + +#define WM_DBG 0x45280 +#define WM_DBG_DISALLOW_MULTIPLE_LP (1<<0) +#define WM_DBG_DISALLOW_MAXFIFO (1<<1) +#define WM_DBG_DISALLOW_SPRITE (1<<2) + +/* pipe CSC */ +#define _PIPE_A_CSC_COEFF_RY_GY 0x49010 +#define _PIPE_A_CSC_COEFF_BY 0x49014 +#define _PIPE_A_CSC_COEFF_RU_GU 0x49018 +#define _PIPE_A_CSC_COEFF_BU 0x4901c +#define _PIPE_A_CSC_COEFF_RV_GV 0x49020 +#define _PIPE_A_CSC_COEFF_BV 0x49024 +#define _PIPE_A_CSC_MODE 0x49028 +#define CSC_BLACK_SCREEN_OFFSET (1 << 2) +#define CSC_POSITION_BEFORE_GAMMA (1 << 1) +#define CSC_MODE_YUV_TO_RGB (1 << 0) +#define _PIPE_A_CSC_PREOFF_HI 0x49030 +#define _PIPE_A_CSC_PREOFF_ME 0x49034 +#define _PIPE_A_CSC_PREOFF_LO 0x49038 +#define _PIPE_A_CSC_POSTOFF_HI 0x49040 +#define _PIPE_A_CSC_POSTOFF_ME 0x49044 +#define _PIPE_A_CSC_POSTOFF_LO 0x49048 + +#define _PIPE_B_CSC_COEFF_RY_GY 0x49110 +#define _PIPE_B_CSC_COEFF_BY 0x49114 +#define _PIPE_B_CSC_COEFF_RU_GU 0x49118 +#define _PIPE_B_CSC_COEFF_BU 0x4911c +#define _PIPE_B_CSC_COEFF_RV_GV 0x49120 +#define _PIPE_B_CSC_COEFF_BV 0x49124 +#define _PIPE_B_CSC_MODE 0x49128 +#define _PIPE_B_CSC_PREOFF_HI 0x49130 +#define _PIPE_B_CSC_PREOFF_ME 0x49134 +#define _PIPE_B_CSC_PREOFF_LO 0x49138 +#define _PIPE_B_CSC_POSTOFF_HI 0x49140 +#define _PIPE_B_CSC_POSTOFF_ME 0x49144 +#define _PIPE_B_CSC_POSTOFF_LO 0x49148 + +#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) +#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) +#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) +#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) +#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) +#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) +#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) +#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) +#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) +#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) +#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) + +/* VLV MIPI registers */ + +#define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190) +#define _MIPIB_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) +#define MIPI_PORT_CTRL(pipe) _PIPE(pipe, _MIPIA_PORT_CTRL, _MIPIB_PORT_CTRL) +#define DPI_ENABLE (1 << 31) /* A + B */ +#define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27 +#define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27) +#define DUAL_LINK_MODE_MASK (1 << 26) +#define DUAL_LINK_MODE_FRONT_BACK (0 << 26) +#define DUAL_LINK_MODE_PIXEL_ALTERNATIVE (1 << 26) +#define DITHERING_ENABLE (1 << 25) /* A + B */ +#define FLOPPED_HSTX (1 << 23) +#define DE_INVERT (1 << 19) /* XXX */ +#define MIPIA_FLISDSI_DELAY_COUNT_SHIFT 18 +#define MIPIA_FLISDSI_DELAY_COUNT_MASK (0xf << 18) +#define AFE_LATCHOUT (1 << 17) +#define LP_OUTPUT_HOLD (1 << 16) +#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_SHIFT 15 +#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_MASK (1 << 15) +#define MIPIB_MIPI4DPHY_DELAY_COUNT_SHIFT 11 +#define MIPIB_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 11) +#define CSB_SHIFT 9 +#define CSB_MASK (3 << 9) +#define CSB_20MHZ (0 << 9) +#define CSB_10MHZ (1 << 9) +#define CSB_40MHZ (2 << 9) +#define BANDGAP_MASK (1 << 8) +#define BANDGAP_PNW_CIRCUIT (0 << 8) +#define BANDGAP_LNC_CIRCUIT (1 << 8) +#define MIPIB_FLISDSI_DELAY_COUNT_LOW_SHIFT 5 +#define MIPIB_FLISDSI_DELAY_COUNT_LOW_MASK (7 << 5) +#define TEARING_EFFECT_DELAY (1 << 4) /* A + B */ +#define TEARING_EFFECT_SHIFT 2 /* A + B */ +#define TEARING_EFFECT_MASK (3 << 2) +#define TEARING_EFFECT_OFF (0 << 2) +#define TEARING_EFFECT_DSI (1 << 2) +#define TEARING_EFFECT_GPIO (2 << 2) +#define LANE_CONFIGURATION_SHIFT 0 +#define LANE_CONFIGURATION_MASK (3 << 0) +#define LANE_CONFIGURATION_4LANE (0 << 0) +#define LANE_CONFIGURATION_DUAL_LINK_A (1 << 0) +#define LANE_CONFIGURATION_DUAL_LINK_B (2 << 0) + +#define _MIPIA_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61194) +#define _MIPIB_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704) +#define MIPI_TEARING_CTRL(pipe) _PIPE(pipe, _MIPIA_TEARING_CTRL, _MIPIB_TEARING_CTRL) +#define TEARING_EFFECT_DELAY_SHIFT 0 +#define TEARING_EFFECT_DELAY_MASK (0xffff << 0) + +/* XXX: all bits reserved */ +#define _MIPIA_AUTOPWG (VLV_DISPLAY_BASE + 0x611a0) + +/* MIPI DSI Controller and D-PHY registers */ + +#define _MIPIA_DEVICE_READY (VLV_DISPLAY_BASE + 0xb000) +#define _MIPIB_DEVICE_READY (VLV_DISPLAY_BASE + 0xb800) +#define MIPI_DEVICE_READY(pipe) _PIPE(pipe, _MIPIA_DEVICE_READY, _MIPIB_DEVICE_READY) +#define BUS_POSSESSION (1 << 3) /* set to give bus to receiver */ +#define ULPS_STATE_MASK (3 << 1) +#define ULPS_STATE_ENTER (2 << 1) +#define ULPS_STATE_EXIT (1 << 1) +#define ULPS_STATE_NORMAL_OPERATION (0 << 1) +#define DEVICE_READY (1 << 0) + +#define _MIPIA_INTR_STAT (VLV_DISPLAY_BASE + 0xb004) +#define _MIPIB_INTR_STAT (VLV_DISPLAY_BASE + 0xb804) +#define MIPI_INTR_STAT(pipe) _PIPE(pipe, _MIPIA_INTR_STAT, _MIPIB_INTR_STAT) +#define _MIPIA_INTR_EN (VLV_DISPLAY_BASE + 0xb008) +#define _MIPIB_INTR_EN (VLV_DISPLAY_BASE + 0xb808) +#define MIPI_INTR_EN(pipe) _PIPE(pipe, _MIPIA_INTR_EN, _MIPIB_INTR_EN) +#define TEARING_EFFECT (1 << 31) +#define SPL_PKT_SENT_INTERRUPT (1 << 30) +#define GEN_READ_DATA_AVAIL (1 << 29) +#define LP_GENERIC_WR_FIFO_FULL (1 << 28) +#define HS_GENERIC_WR_FIFO_FULL (1 << 27) +#define RX_PROT_VIOLATION (1 << 26) +#define RX_INVALID_TX_LENGTH (1 << 25) +#define ACK_WITH_NO_ERROR (1 << 24) +#define TURN_AROUND_ACK_TIMEOUT (1 << 23) +#define LP_RX_TIMEOUT (1 << 22) +#define HS_TX_TIMEOUT (1 << 21) +#define DPI_FIFO_UNDERRUN (1 << 20) +#define LOW_CONTENTION (1 << 19) +#define HIGH_CONTENTION (1 << 18) +#define TXDSI_VC_ID_INVALID (1 << 17) +#define TXDSI_DATA_TYPE_NOT_RECOGNISED (1 << 16) +#define TXCHECKSUM_ERROR (1 << 15) +#define TXECC_MULTIBIT_ERROR (1 << 14) +#define TXECC_SINGLE_BIT_ERROR (1 << 13) +#define TXFALSE_CONTROL_ERROR (1 << 12) +#define RXDSI_VC_ID_INVALID (1 << 11) +#define RXDSI_DATA_TYPE_NOT_REGOGNISED (1 << 10) +#define RXCHECKSUM_ERROR (1 << 9) +#define RXECC_MULTIBIT_ERROR (1 << 8) +#define RXECC_SINGLE_BIT_ERROR (1 << 7) +#define RXFALSE_CONTROL_ERROR (1 << 6) +#define RXHS_RECEIVE_TIMEOUT_ERROR (1 << 5) +#define RX_LP_TX_SYNC_ERROR (1 << 4) +#define RXEXCAPE_MODE_ENTRY_ERROR (1 << 3) +#define RXEOT_SYNC_ERROR (1 << 2) +#define RXSOT_SYNC_ERROR (1 << 1) +#define RXSOT_ERROR (1 << 0) + +#define _MIPIA_DSI_FUNC_PRG (VLV_DISPLAY_BASE + 0xb00c) +#define _MIPIB_DSI_FUNC_PRG (VLV_DISPLAY_BASE + 0xb80c) +#define MIPI_DSI_FUNC_PRG(pipe) _PIPE(pipe, _MIPIA_DSI_FUNC_PRG, _MIPIB_DSI_FUNC_PRG) +#define CMD_MODE_DATA_WIDTH_MASK (7 << 13) +#define CMD_MODE_NOT_SUPPORTED (0 << 13) +#define CMD_MODE_DATA_WIDTH_16_BIT (1 << 13) +#define CMD_MODE_DATA_WIDTH_9_BIT (2 << 13) +#define CMD_MODE_DATA_WIDTH_8_BIT (3 << 13) +#define CMD_MODE_DATA_WIDTH_OPTION1 (4 << 13) +#define CMD_MODE_DATA_WIDTH_OPTION2 (5 << 13) +#define VID_MODE_FORMAT_MASK (0xf << 7) +#define VID_MODE_NOT_SUPPORTED (0 << 7) +#define VID_MODE_FORMAT_RGB565 (1 << 7) +#define VID_MODE_FORMAT_RGB666 (2 << 7) +#define VID_MODE_FORMAT_RGB666_LOOSE (3 << 7) +#define VID_MODE_FORMAT_RGB888 (4 << 7) +#define CMD_MODE_CHANNEL_NUMBER_SHIFT 5 +#define CMD_MODE_CHANNEL_NUMBER_MASK (3 << 5) +#define VID_MODE_CHANNEL_NUMBER_SHIFT 3 +#define VID_MODE_CHANNEL_NUMBER_MASK (3 << 3) +#define DATA_LANES_PRG_REG_SHIFT 0 +#define DATA_LANES_PRG_REG_MASK (7 << 0) + +#define _MIPIA_HS_TX_TIMEOUT (VLV_DISPLAY_BASE + 0xb010) +#define _MIPIB_HS_TX_TIMEOUT (VLV_DISPLAY_BASE + 0xb810) +#define MIPI_HS_TX_TIMEOUT(pipe) _PIPE(pipe, _MIPIA_HS_TX_TIMEOUT, _MIPIB_HS_TX_TIMEOUT) +#define HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK 0xffffff + +#define _MIPIA_LP_RX_TIMEOUT (VLV_DISPLAY_BASE + 0xb014) +#define _MIPIB_LP_RX_TIMEOUT (VLV_DISPLAY_BASE + 0xb814) +#define MIPI_LP_RX_TIMEOUT(pipe) _PIPE(pipe, _MIPIA_LP_RX_TIMEOUT, _MIPIB_LP_RX_TIMEOUT) +#define LOW_POWER_RX_TIMEOUT_COUNTER_MASK 0xffffff + +#define _MIPIA_TURN_AROUND_TIMEOUT (VLV_DISPLAY_BASE + 0xb018) +#define _MIPIB_TURN_AROUND_TIMEOUT (VLV_DISPLAY_BASE + 0xb818) +#define MIPI_TURN_AROUND_TIMEOUT(pipe) _PIPE(pipe, _MIPIA_TURN_AROUND_TIMEOUT, _MIPIB_TURN_AROUND_TIMEOUT) +#define TURN_AROUND_TIMEOUT_MASK 0x3f + +#define _MIPIA_DEVICE_RESET_TIMER (VLV_DISPLAY_BASE + 0xb01c) +#define _MIPIB_DEVICE_RESET_TIMER (VLV_DISPLAY_BASE + 0xb81c) +#define MIPI_DEVICE_RESET_TIMER(pipe) _PIPE(pipe, _MIPIA_DEVICE_RESET_TIMER, _MIPIB_DEVICE_RESET_TIMER) +#define DEVICE_RESET_TIMER_MASK 0xffff + +#define _MIPIA_DPI_RESOLUTION (VLV_DISPLAY_BASE + 0xb020) +#define _MIPIB_DPI_RESOLUTION (VLV_DISPLAY_BASE + 0xb820) +#define MIPI_DPI_RESOLUTION(pipe) _PIPE(pipe, _MIPIA_DPI_RESOLUTION, _MIPIB_DPI_RESOLUTION) +#define VERTICAL_ADDRESS_SHIFT 16 +#define VERTICAL_ADDRESS_MASK (0xffff << 16) +#define HORIZONTAL_ADDRESS_SHIFT 0 +#define HORIZONTAL_ADDRESS_MASK 0xffff + +#define _MIPIA_DBI_FIFO_THROTTLE (VLV_DISPLAY_BASE + 0xb024) +#define _MIPIB_DBI_FIFO_THROTTLE (VLV_DISPLAY_BASE + 0xb824) +#define MIPI_DBI_FIFO_THROTTLE(pipe) _PIPE(pipe, _MIPIA_DBI_FIFO_THROTTLE, _MIPIB_DBI_FIFO_THROTTLE) +#define DBI_FIFO_EMPTY_HALF (0 << 0) +#define DBI_FIFO_EMPTY_QUARTER (1 << 0) +#define DBI_FIFO_EMPTY_7_LOCATIONS (2 << 0) + +/* regs below are bits 15:0 */ +#define _MIPIA_HSYNC_PADDING_COUNT (VLV_DISPLAY_BASE + 0xb028) +#define _MIPIB_HSYNC_PADDING_COUNT (VLV_DISPLAY_BASE + 0xb828) +#define MIPI_HSYNC_PADDING_COUNT(pipe) _PIPE(pipe, _MIPIA_HSYNC_PADDING_COUNT, _MIPIB_HSYNC_PADDING_COUNT) + +#define _MIPIA_HBP_COUNT (VLV_DISPLAY_BASE + 0xb02c) +#define _MIPIB_HBP_COUNT (VLV_DISPLAY_BASE + 0xb82c) +#define MIPI_HBP_COUNT(pipe) _PIPE(pipe, _MIPIA_HBP_COUNT, _MIPIB_HBP_COUNT) + +#define _MIPIA_HFP_COUNT (VLV_DISPLAY_BASE + 0xb030) +#define _MIPIB_HFP_COUNT (VLV_DISPLAY_BASE + 0xb830) +#define MIPI_HFP_COUNT(pipe) _PIPE(pipe, _MIPIA_HFP_COUNT, _MIPIB_HFP_COUNT) + +#define _MIPIA_HACTIVE_AREA_COUNT (VLV_DISPLAY_BASE + 0xb034) +#define _MIPIB_HACTIVE_AREA_COUNT (VLV_DISPLAY_BASE + 0xb834) +#define MIPI_HACTIVE_AREA_COUNT(pipe) _PIPE(pipe, _MIPIA_HACTIVE_AREA_COUNT, _MIPIB_HACTIVE_AREA_COUNT) + +#define _MIPIA_VSYNC_PADDING_COUNT (VLV_DISPLAY_BASE + 0xb038) +#define _MIPIB_VSYNC_PADDING_COUNT (VLV_DISPLAY_BASE + 0xb838) +#define MIPI_VSYNC_PADDING_COUNT(pipe) _PIPE(pipe, _MIPIA_VSYNC_PADDING_COUNT, _MIPIB_VSYNC_PADDING_COUNT) + +#define _MIPIA_VBP_COUNT (VLV_DISPLAY_BASE + 0xb03c) +#define _MIPIB_VBP_COUNT (VLV_DISPLAY_BASE + 0xb83c) +#define MIPI_VBP_COUNT(pipe) _PIPE(pipe, _MIPIA_VBP_COUNT, _MIPIB_VBP_COUNT) + +#define _MIPIA_VFP_COUNT (VLV_DISPLAY_BASE + 0xb040) +#define _MIPIB_VFP_COUNT (VLV_DISPLAY_BASE + 0xb840) +#define MIPI_VFP_COUNT(pipe) _PIPE(pipe, _MIPIA_VFP_COUNT, _MIPIB_VFP_COUNT) + +#define _MIPIA_HIGH_LOW_SWITCH_COUNT (VLV_DISPLAY_BASE + 0xb044) +#define _MIPIB_HIGH_LOW_SWITCH_COUNT (VLV_DISPLAY_BASE + 0xb844) +#define MIPI_HIGH_LOW_SWITCH_COUNT(pipe) _PIPE(pipe, _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIB_HIGH_LOW_SWITCH_COUNT) +/* regs above are bits 15:0 */ + +#define _MIPIA_DPI_CONTROL (VLV_DISPLAY_BASE + 0xb048) +#define _MIPIB_DPI_CONTROL (VLV_DISPLAY_BASE + 0xb848) +#define MIPI_DPI_CONTROL(pipe) _PIPE(pipe, _MIPIA_DPI_CONTROL, _MIPIB_DPI_CONTROL) +#define DPI_LP_MODE (1 << 6) +#define BACKLIGHT_OFF (1 << 5) +#define BACKLIGHT_ON (1 << 4) +#define COLOR_MODE_OFF (1 << 3) +#define COLOR_MODE_ON (1 << 2) +#define TURN_ON (1 << 1) +#define SHUTDOWN (1 << 0) + +#define _MIPIA_DPI_DATA (VLV_DISPLAY_BASE + 0xb04c) +#define _MIPIB_DPI_DATA (VLV_DISPLAY_BASE + 0xb84c) +#define MIPI_DPI_DATA(pipe) _PIPE(pipe, _MIPIA_DPI_DATA, _MIPIB_DPI_DATA) +#define COMMAND_BYTE_SHIFT 0 +#define COMMAND_BYTE_MASK (0x3f << 0) + +#define _MIPIA_INIT_COUNT (VLV_DISPLAY_BASE + 0xb050) +#define _MIPIB_INIT_COUNT (VLV_DISPLAY_BASE + 0xb850) +#define MIPI_INIT_COUNT(pipe) _PIPE(pipe, _MIPIA_INIT_COUNT, _MIPIB_INIT_COUNT) +#define MASTER_INIT_TIMER_SHIFT 0 +#define MASTER_INIT_TIMER_MASK (0xffff << 0) + +#define _MIPIA_MAX_RETURN_PKT_SIZE (VLV_DISPLAY_BASE + 0xb054) +#define _MIPIB_MAX_RETURN_PKT_SIZE (VLV_DISPLAY_BASE + 0xb854) +#define MIPI_MAX_RETURN_PKT_SIZE(pipe) _PIPE(pipe, _MIPIA_MAX_RETURN_PKT_SIZE, _MIPIB_MAX_RETURN_PKT_SIZE) +#define MAX_RETURN_PKT_SIZE_SHIFT 0 +#define MAX_RETURN_PKT_SIZE_MASK (0x3ff << 0) + +#define _MIPIA_VIDEO_MODE_FORMAT (VLV_DISPLAY_BASE + 0xb058) +#define _MIPIB_VIDEO_MODE_FORMAT (VLV_DISPLAY_BASE + 0xb858) +#define MIPI_VIDEO_MODE_FORMAT(pipe) _PIPE(pipe, _MIPIA_VIDEO_MODE_FORMAT, _MIPIB_VIDEO_MODE_FORMAT) +#define RANDOM_DPI_DISPLAY_RESOLUTION (1 << 4) +#define DISABLE_VIDEO_BTA (1 << 3) +#define IP_TG_CONFIG (1 << 2) +#define VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE (1 << 0) +#define VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS (2 << 0) +#define VIDEO_MODE_BURST (3 << 0) + +#define _MIPIA_EOT_DISABLE (VLV_DISPLAY_BASE + 0xb05c) +#define _MIPIB_EOT_DISABLE (VLV_DISPLAY_BASE + 0xb85c) +#define MIPI_EOT_DISABLE(pipe) _PIPE(pipe, _MIPIA_EOT_DISABLE, _MIPIB_EOT_DISABLE) +#define LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 7) +#define HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 6) +#define LOW_CONTENTION_RECOVERY_DISABLE (1 << 5) +#define HIGH_CONTENTION_RECOVERY_DISABLE (1 << 4) +#define TXDSI_TYPE_NOT_RECOGNISED_ERROR_RECOVERY_DISABLE (1 << 3) +#define TXECC_MULTIBIT_ERROR_RECOVERY_DISABLE (1 << 2) +#define CLOCKSTOP (1 << 1) +#define EOT_DISABLE (1 << 0) + +#define _MIPIA_LP_BYTECLK (VLV_DISPLAY_BASE + 0xb060) +#define _MIPIB_LP_BYTECLK (VLV_DISPLAY_BASE + 0xb860) +#define MIPI_LP_BYTECLK(pipe) _PIPE(pipe, _MIPIA_LP_BYTECLK, _MIPIB_LP_BYTECLK) +#define LP_BYTECLK_SHIFT 0 +#define LP_BYTECLK_MASK (0xffff << 0) + +/* bits 31:0 */ +#define _MIPIA_LP_GEN_DATA (VLV_DISPLAY_BASE + 0xb064) +#define _MIPIB_LP_GEN_DATA (VLV_DISPLAY_BASE + 0xb864) +#define MIPI_LP_GEN_DATA(pipe) _PIPE(pipe, _MIPIA_LP_GEN_DATA, _MIPIB_LP_GEN_DATA) + +/* bits 31:0 */ +#define _MIPIA_HS_GEN_DATA (VLV_DISPLAY_BASE + 0xb068) +#define _MIPIB_HS_GEN_DATA (VLV_DISPLAY_BASE + 0xb868) +#define MIPI_HS_GEN_DATA(pipe) _PIPE(pipe, _MIPIA_HS_GEN_DATA, _MIPIB_HS_GEN_DATA) + +#define _MIPIA_LP_GEN_CTRL (VLV_DISPLAY_BASE + 0xb06c) +#define _MIPIB_LP_GEN_CTRL (VLV_DISPLAY_BASE + 0xb86c) +#define MIPI_LP_GEN_CTRL(pipe) _PIPE(pipe, _MIPIA_LP_GEN_CTRL, _MIPIB_LP_GEN_CTRL) +#define _MIPIA_HS_GEN_CTRL (VLV_DISPLAY_BASE + 0xb070) +#define _MIPIB_HS_GEN_CTRL (VLV_DISPLAY_BASE + 0xb870) +#define MIPI_HS_GEN_CTRL(pipe) _PIPE(pipe, _MIPIA_HS_GEN_CTRL, _MIPIB_HS_GEN_CTRL) +#define LONG_PACKET_WORD_COUNT_SHIFT 8 +#define LONG_PACKET_WORD_COUNT_MASK (0xffff << 8) +#define SHORT_PACKET_PARAM_SHIFT 8 +#define SHORT_PACKET_PARAM_MASK (0xffff << 8) +#define VIRTUAL_CHANNEL_SHIFT 6 +#define VIRTUAL_CHANNEL_MASK (3 << 6) +#define DATA_TYPE_SHIFT 0 +#define DATA_TYPE_MASK (3f << 0) +/* data type values, see include/video/mipi_display.h */ + +#define _MIPIA_GEN_FIFO_STAT (VLV_DISPLAY_BASE + 0xb074) +#define _MIPIB_GEN_FIFO_STAT (VLV_DISPLAY_BASE + 0xb874) +#define MIPI_GEN_FIFO_STAT(pipe) _PIPE(pipe, _MIPIA_GEN_FIFO_STAT, _MIPIB_GEN_FIFO_STAT) +#define DPI_FIFO_EMPTY (1 << 28) +#define DBI_FIFO_EMPTY (1 << 27) +#define LP_CTRL_FIFO_EMPTY (1 << 26) +#define LP_CTRL_FIFO_HALF_EMPTY (1 << 25) +#define LP_CTRL_FIFO_FULL (1 << 24) +#define HS_CTRL_FIFO_EMPTY (1 << 18) +#define HS_CTRL_FIFO_HALF_EMPTY (1 << 17) +#define HS_CTRL_FIFO_FULL (1 << 16) +#define LP_DATA_FIFO_EMPTY (1 << 10) +#define LP_DATA_FIFO_HALF_EMPTY (1 << 9) +#define LP_DATA_FIFO_FULL (1 << 8) +#define HS_DATA_FIFO_EMPTY (1 << 2) +#define HS_DATA_FIFO_HALF_EMPTY (1 << 1) +#define HS_DATA_FIFO_FULL (1 << 0) + +#define _MIPIA_HS_LS_DBI_ENABLE (VLV_DISPLAY_BASE + 0xb078) +#define _MIPIB_HS_LS_DBI_ENABLE (VLV_DISPLAY_BASE + 0xb878) +#define MIPI_HS_LP_DBI_ENABLE(pipe) _PIPE(pipe, _MIPIA_HS_LS_DBI_ENABLE, _MIPIB_HS_LS_DBI_ENABLE) +#define DBI_HS_LP_MODE_MASK (1 << 0) +#define DBI_LP_MODE (1 << 0) +#define DBI_HS_MODE (0 << 0) + +#define _MIPIA_DPHY_PARAM (VLV_DISPLAY_BASE + 0xb080) +#define _MIPIB_DPHY_PARAM (VLV_DISPLAY_BASE + 0xb880) +#define MIPI_DPHY_PARAM(pipe) _PIPE(pipe, _MIPIA_DPHY_PARAM, _MIPIB_DPHY_PARAM) +#define EXIT_ZERO_COUNT_SHIFT 24 +#define EXIT_ZERO_COUNT_MASK (0x3f << 24) +#define TRAIL_COUNT_SHIFT 16 +#define TRAIL_COUNT_MASK (0x1f << 16) +#define CLK_ZERO_COUNT_SHIFT 8 +#define CLK_ZERO_COUNT_MASK (0xff << 8) +#define PREPARE_COUNT_SHIFT 0 +#define PREPARE_COUNT_MASK (0x3f << 0) + +/* bits 31:0 */ +#define _MIPIA_DBI_BW_CTRL (VLV_DISPLAY_BASE + 0xb084) +#define _MIPIB_DBI_BW_CTRL (VLV_DISPLAY_BASE + 0xb884) +#define MIPI_DBI_BW_CTRL(pipe) _PIPE(pipe, _MIPIA_DBI_BW_CTRL, _MIPIB_DBI_BW_CTRL) + +#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (VLV_DISPLAY_BASE + 0xb088) +#define _MIPIB_CLK_LANE_SWITCH_TIME_CNT (VLV_DISPLAY_BASE + 0xb888) +#define MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe) _PIPE(pipe, _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIB_CLK_LANE_SWITCH_TIME_CNT) +#define LP_HS_SSW_CNT_SHIFT 16 +#define LP_HS_SSW_CNT_MASK (0xffff << 16) +#define HS_LP_PWR_SW_CNT_SHIFT 0 +#define HS_LP_PWR_SW_CNT_MASK (0xffff << 0) + +#define _MIPIA_STOP_STATE_STALL (VLV_DISPLAY_BASE + 0xb08c) +#define _MIPIB_STOP_STATE_STALL (VLV_DISPLAY_BASE + 0xb88c) +#define MIPI_STOP_STATE_STALL(pipe) _PIPE(pipe, _MIPIA_STOP_STATE_STALL, _MIPIB_STOP_STATE_STALL) +#define STOP_STATE_STALL_COUNTER_SHIFT 0 +#define STOP_STATE_STALL_COUNTER_MASK (0xff << 0) + +#define _MIPIA_INTR_STAT_REG_1 (VLV_DISPLAY_BASE + 0xb090) +#define _MIPIB_INTR_STAT_REG_1 (VLV_DISPLAY_BASE + 0xb890) +#define MIPI_INTR_STAT_REG_1(pipe) _PIPE(pipe, _MIPIA_INTR_STAT_REG_1, _MIPIB_INTR_STAT_REG_1) +#define _MIPIA_INTR_EN_REG_1 (VLV_DISPLAY_BASE + 0xb094) +#define _MIPIB_INTR_EN_REG_1 (VLV_DISPLAY_BASE + 0xb894) +#define MIPI_INTR_EN_REG_1(pipe) _PIPE(pipe, _MIPIA_INTR_EN_REG_1, _MIPIB_INTR_EN_REG_1) +#define RX_CONTENTION_DETECTED (1 << 0) + +/* XXX: only pipe A ?!? */ +#define MIPIA_DBI_TYPEC_CTRL (VLV_DISPLAY_BASE + 0xb100) +#define DBI_TYPEC_ENABLE (1 << 31) +#define DBI_TYPEC_WIP (1 << 30) +#define DBI_TYPEC_OPTION_SHIFT 28 +#define DBI_TYPEC_OPTION_MASK (3 << 28) +#define DBI_TYPEC_FREQ_SHIFT 24 +#define DBI_TYPEC_FREQ_MASK (0xf << 24) +#define DBI_TYPEC_OVERRIDE (1 << 8) +#define DBI_TYPEC_OVERRIDE_COUNTER_SHIFT 0 +#define DBI_TYPEC_OVERRIDE_COUNTER_MASK (0xff << 0) + + +/* MIPI adapter registers */ + +#define _MIPIA_CTRL (VLV_DISPLAY_BASE + 0xb104) +#define _MIPIB_CTRL (VLV_DISPLAY_BASE + 0xb904) +#define MIPI_CTRL(pipe) _PIPE(pipe, _MIPIA_CTRL, _MIPIB_CTRL) +#define ESCAPE_CLOCK_DIVIDER_SHIFT 5 /* A only */ +#define ESCAPE_CLOCK_DIVIDER_MASK (3 << 5) +#define ESCAPE_CLOCK_DIVIDER_1 (0 << 5) +#define ESCAPE_CLOCK_DIVIDER_2 (1 << 5) +#define ESCAPE_CLOCK_DIVIDER_4 (2 << 5) +#define READ_REQUEST_PRIORITY_SHIFT 3 +#define READ_REQUEST_PRIORITY_MASK (3 << 3) +#define READ_REQUEST_PRIORITY_LOW (0 << 3) +#define READ_REQUEST_PRIORITY_HIGH (3 << 3) +#define RGB_FLIP_TO_BGR (1 << 2) + +#define _MIPIA_DATA_ADDRESS (VLV_DISPLAY_BASE + 0xb108) +#define _MIPIB_DATA_ADDRESS (VLV_DISPLAY_BASE + 0xb908) +#define MIPI_DATA_ADDRESS(pipe) _PIPE(pipe, _MIPIA_DATA_ADDRESS, _MIPIB_DATA_ADDRESS) +#define DATA_MEM_ADDRESS_SHIFT 5 +#define DATA_MEM_ADDRESS_MASK (0x7ffffff << 5) +#define DATA_VALID (1 << 0) + +#define _MIPIA_DATA_LENGTH (VLV_DISPLAY_BASE + 0xb10c) +#define _MIPIB_DATA_LENGTH (VLV_DISPLAY_BASE + 0xb90c) +#define MIPI_DATA_LENGTH(pipe) _PIPE(pipe, _MIPIA_DATA_LENGTH, _MIPIB_DATA_LENGTH) +#define DATA_LENGTH_SHIFT 0 +#define DATA_LENGTH_MASK (0xfffff << 0) + +#define _MIPIA_COMMAND_ADDRESS (VLV_DISPLAY_BASE + 0xb110) +#define _MIPIB_COMMAND_ADDRESS (VLV_DISPLAY_BASE + 0xb910) +#define MIPI_COMMAND_ADDRESS(pipe) _PIPE(pipe, _MIPIA_COMMAND_ADDRESS, _MIPIB_COMMAND_ADDRESS) +#define COMMAND_MEM_ADDRESS_SHIFT 5 +#define COMMAND_MEM_ADDRESS_MASK (0x7ffffff << 5) +#define AUTO_PWG_ENABLE (1 << 2) +#define MEMORY_WRITE_DATA_FROM_PIPE_RENDERING (1 << 1) +#define COMMAND_VALID (1 << 0) + +#define _MIPIA_COMMAND_LENGTH (VLV_DISPLAY_BASE + 0xb114) +#define _MIPIB_COMMAND_LENGTH (VLV_DISPLAY_BASE + 0xb914) +#define MIPI_COMMAND_LENGTH(pipe) _PIPE(pipe, _MIPIA_COMMAND_LENGTH, _MIPIB_COMMAND_LENGTH) +#define COMMAND_LENGTH_SHIFT(n) (8 * (n)) /* n: 0...3 */ +#define COMMAND_LENGTH_MASK(n) (0xff << (8 * (n))) + +#define _MIPIA_READ_DATA_RETURN0 (VLV_DISPLAY_BASE + 0xb118) +#define _MIPIB_READ_DATA_RETURN0 (VLV_DISPLAY_BASE + 0xb918) +#define MIPI_READ_DATA_RETURN(pipe, n) \ + (_PIPE(pipe, _MIPIA_READ_DATA_RETURN0, _MIPIB_READ_DATA_RETURN0) + 4 * (n)) /* n: 0...7 */ + +#define _MIPIA_READ_DATA_VALID (VLV_DISPLAY_BASE + 0xb138) +#define _MIPIB_READ_DATA_VALID (VLV_DISPLAY_BASE + 0xb938) +#define MIPI_READ_DATA_VALID(pipe) _PIPE(pipe, _MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID) +#define READ_DATA_VALID(n) (1 << (n)) + +#endif /* _I915_REG_H_ */ --- linux-3.13.0.orig/ubuntu/i915/dvo_ivch.c +++ linux-3.13.0/ubuntu/i915/dvo_ivch.c @@ -0,0 +1,436 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include "dvo.h" + +/* + * register definitions for the i82807aa. + * + * Documentation on this chipset can be found in datasheet #29069001 at + * intel.com. + */ + +/* + * VCH Revision & GMBus Base Addr + */ +#define VR00 0x00 +# define VR00_BASE_ADDRESS_MASK 0x007f + +/* + * Functionality Enable + */ +#define VR01 0x01 + +/* + * Enable the panel fitter + */ +# define VR01_PANEL_FIT_ENABLE (1 << 3) +/* + * Enables the LCD display. + * + * This must not be set while VR01_DVO_BYPASS_ENABLE is set. + */ +# define VR01_LCD_ENABLE (1 << 2) +/** Enables the DVO repeater. */ +# define VR01_DVO_BYPASS_ENABLE (1 << 1) +/** Enables the DVO clock */ +# define VR01_DVO_ENABLE (1 << 0) + +/* + * LCD Interface Format + */ +#define VR10 0x10 +/** Enables LVDS output instead of CMOS */ +# define VR10_LVDS_ENABLE (1 << 4) +/** Enables 18-bit LVDS output. */ +# define VR10_INTERFACE_1X18 (0 << 2) +/** Enables 24-bit LVDS or CMOS output */ +# define VR10_INTERFACE_1X24 (1 << 2) +/** Enables 2x18-bit LVDS or CMOS output. */ +# define VR10_INTERFACE_2X18 (2 << 2) +/** Enables 2x24-bit LVDS output */ +# define VR10_INTERFACE_2X24 (3 << 2) + +/* + * VR20 LCD Horizontal Display Size + */ +#define VR20 0x20 + +/* + * LCD Vertical Display Size + */ +#define VR21 0x20 + +/* + * Panel power down status + */ +#define VR30 0x30 +/** Read only bit indicating that the panel is not in a safe poweroff state. */ +# define VR30_PANEL_ON (1 << 15) + +#define VR40 0x40 +# define VR40_STALL_ENABLE (1 << 13) +# define VR40_VERTICAL_INTERP_ENABLE (1 << 12) +# define VR40_ENHANCED_PANEL_FITTING (1 << 11) +# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10) +# define VR40_AUTO_RATIO_ENABLE (1 << 9) +# define VR40_CLOCK_GATING_ENABLE (1 << 8) + +/* + * Panel Fitting Vertical Ratio + * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2 + */ +#define VR41 0x41 + +/* + * Panel Fitting Horizontal Ratio + * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2 + */ +#define VR42 0x42 + +/* + * Horizontal Image Size + */ +#define VR43 0x43 + +/* VR80 GPIO 0 + */ +#define VR80 0x80 +#define VR81 0x81 +#define VR82 0x82 +#define VR83 0x83 +#define VR84 0x84 +#define VR85 0x85 +#define VR86 0x86 +#define VR87 0x87 + +/* VR88 GPIO 8 + */ +#define VR88 0x88 + +/* Graphics BIOS scratch 0 + */ +#define VR8E 0x8E +# define VR8E_PANEL_TYPE_MASK (0xf << 0) +# define VR8E_PANEL_INTERFACE_CMOS (0 << 4) +# define VR8E_PANEL_INTERFACE_LVDS (1 << 4) +# define VR8E_FORCE_DEFAULT_PANEL (1 << 5) + +/* Graphics BIOS scratch 1 + */ +#define VR8F 0x8F +# define VR8F_VCH_PRESENT (1 << 0) +# define VR8F_DISPLAY_CONN (1 << 1) +# define VR8F_POWER_MASK (0x3c) +# define VR8F_POWER_POS (2) + + +struct ivch_priv { + bool quiet; + + uint16_t width, height; +}; + + +static void ivch_dump_regs(struct intel_dvo_device *dvo); + +/** + * Reads a register on the ivch. + * + * Each of the 256 registers are 16 bits long. + */ +static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) +{ + struct ivch_priv *priv = dvo->dev_priv; + struct i2c_adapter *adapter = dvo->i2c_bus; + u8 out_buf[1]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = dvo->slave_addr, + .flags = I2C_M_RD, + .len = 0, + }, + { + .addr = 0, + .flags = I2C_M_NOSTART, + .len = 1, + .buf = out_buf, + }, + { + .addr = dvo->slave_addr, + .flags = I2C_M_RD | I2C_M_NOSTART, + .len = 2, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + + if (i2c_transfer(adapter, msgs, 3) == 3) { + *data = (in_buf[1] << 8) | in_buf[0]; + return true; + }; + + if (!priv->quiet) { + DRM_DEBUG_KMS("Unable to read register 0x%02x from " + "%s:%02x.\n", + addr, adapter->name, dvo->slave_addr); + } + return false; +} + +/** Writes a 16-bit register on the ivch */ +static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) +{ + struct ivch_priv *priv = dvo->dev_priv; + struct i2c_adapter *adapter = dvo->i2c_bus; + u8 out_buf[3]; + struct i2c_msg msg = { + .addr = dvo->slave_addr, + .flags = 0, + .len = 3, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = data & 0xff; + out_buf[2] = data >> 8; + + if (i2c_transfer(adapter, &msg, 1) == 1) + return true; + + if (!priv->quiet) { + DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", + addr, adapter->name, dvo->slave_addr); + } + + return false; +} + +/** Probes the given bus and slave address for an ivch */ +static bool ivch_init(struct intel_dvo_device *dvo, + struct i2c_adapter *adapter) +{ + struct ivch_priv *priv; + uint16_t temp; + + priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); + if (priv == NULL) + return false; + + dvo->i2c_bus = adapter; + dvo->dev_priv = priv; + priv->quiet = true; + + if (!ivch_read(dvo, VR00, &temp)) + goto out; + priv->quiet = false; + + /* Since the identification bits are probably zeroes, which doesn't seem + * very unique, check that the value in the base address field matches + * the address it's responding on. + */ + if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) { + DRM_DEBUG_KMS("ivch detect failed due to address mismatch " + "(%d vs %d)\n", + (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr); + goto out; + } + + ivch_read(dvo, VR20, &priv->width); + ivch_read(dvo, VR21, &priv->height); + + return true; + +out: + kfree(priv); + return false; +} + +static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo) +{ + return connector_status_connected; +} + +static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + if (mode->clock > 112000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +/** Sets the power state of the panel connected to the ivch */ +static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) +{ + int i; + uint16_t vr01, vr30, backlight; + + /* Set the new power state of the panel. */ + if (!ivch_read(dvo, VR01, &vr01)) + return; + + if (enable) + backlight = 1; + else + backlight = 0; + ivch_write(dvo, VR80, backlight); + + if (enable) + vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; + else + vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); + + ivch_write(dvo, VR01, vr01); + + /* Wait for the panel to make its state transition */ + for (i = 0; i < 100; i++) { + if (!ivch_read(dvo, VR30, &vr30)) + break; + + if (((vr30 & VR30_PANEL_ON) != 0) == enable) + break; + udelay(1000); + } + /* wait some more; vch may fail to resync sometimes without this */ + udelay(16 * 1000); +} + +static bool ivch_get_hw_state(struct intel_dvo_device *dvo) +{ + uint16_t vr01; + + /* Set the new power state of the panel. */ + if (!ivch_read(dvo, VR01, &vr01)) + return false; + + if (vr01 & VR01_LCD_ENABLE) + return true; + else + return false; +} + +static void ivch_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + uint16_t vr40 = 0; + uint16_t vr01; + + vr01 = 0; + vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | + VR40_HORIZONTAL_INTERP_ENABLE); + + if (mode->hdisplay != adjusted_mode->hdisplay || + mode->vdisplay != adjusted_mode->vdisplay) { + uint16_t x_ratio, y_ratio; + + vr01 |= VR01_PANEL_FIT_ENABLE; + vr40 |= VR40_CLOCK_GATING_ENABLE; + x_ratio = (((mode->hdisplay - 1) << 16) / + (adjusted_mode->hdisplay - 1)) >> 2; + y_ratio = (((mode->vdisplay - 1) << 16) / + (adjusted_mode->vdisplay - 1)) >> 2; + ivch_write(dvo, VR42, x_ratio); + ivch_write(dvo, VR41, y_ratio); + } else { + vr01 &= ~VR01_PANEL_FIT_ENABLE; + vr40 &= ~VR40_CLOCK_GATING_ENABLE; + } + vr40 &= ~VR40_AUTO_RATIO_ENABLE; + + ivch_write(dvo, VR01, vr01); + ivch_write(dvo, VR40, vr40); + + ivch_dump_regs(dvo); +} + +static void ivch_dump_regs(struct intel_dvo_device *dvo) +{ + uint16_t val; + + ivch_read(dvo, VR00, &val); + DRM_LOG_KMS("VR00: 0x%04x\n", val); + ivch_read(dvo, VR01, &val); + DRM_LOG_KMS("VR01: 0x%04x\n", val); + ivch_read(dvo, VR30, &val); + DRM_LOG_KMS("VR30: 0x%04x\n", val); + ivch_read(dvo, VR40, &val); + DRM_LOG_KMS("VR40: 0x%04x\n", val); + + /* GPIO registers */ + ivch_read(dvo, VR80, &val); + DRM_LOG_KMS("VR80: 0x%04x\n", val); + ivch_read(dvo, VR81, &val); + DRM_LOG_KMS("VR81: 0x%04x\n", val); + ivch_read(dvo, VR82, &val); + DRM_LOG_KMS("VR82: 0x%04x\n", val); + ivch_read(dvo, VR83, &val); + DRM_LOG_KMS("VR83: 0x%04x\n", val); + ivch_read(dvo, VR84, &val); + DRM_LOG_KMS("VR84: 0x%04x\n", val); + ivch_read(dvo, VR85, &val); + DRM_LOG_KMS("VR85: 0x%04x\n", val); + ivch_read(dvo, VR86, &val); + DRM_LOG_KMS("VR86: 0x%04x\n", val); + ivch_read(dvo, VR87, &val); + DRM_LOG_KMS("VR87: 0x%04x\n", val); + ivch_read(dvo, VR88, &val); + DRM_LOG_KMS("VR88: 0x%04x\n", val); + + /* Scratch register 0 - AIM Panel type */ + ivch_read(dvo, VR8E, &val); + DRM_LOG_KMS("VR8E: 0x%04x\n", val); + + /* Scratch register 1 - Status register */ + ivch_read(dvo, VR8F, &val); + DRM_LOG_KMS("VR8F: 0x%04x\n", val); +} + +static void ivch_destroy(struct intel_dvo_device *dvo) +{ + struct ivch_priv *priv = dvo->dev_priv; + + if (priv) { + kfree(priv); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops ivch_ops = { + .init = ivch_init, + .dpms = ivch_dpms, + .get_hw_state = ivch_get_hw_state, + .mode_valid = ivch_mode_valid, + .mode_set = ivch_mode_set, + .detect = ivch_detect, + .dump_regs = ivch_dump_regs, + .destroy = ivch_destroy, +}; --- linux-3.13.0.orig/ubuntu/i915/intel_dsi.h +++ linux-3.13.0/ubuntu/i915/intel_dsi.h @@ -0,0 +1,123 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef _INTEL_DSI_H +#define _INTEL_DSI_H + +#include +#include +#include "intel_drv.h" + +struct intel_dsi_device { + unsigned int panel_id; + const char *name; + int type; + const struct intel_dsi_dev_ops *dev_ops; + void *dev_priv; +}; + +struct intel_dsi_dev_ops { + bool (*init)(struct intel_dsi_device *dsi); + + void (*panel_reset)(struct intel_dsi_device *dsi); + + void (*disable_panel_power)(struct intel_dsi_device *dsi); + + /* one time programmable commands if needed */ + void (*send_otp_cmds)(struct intel_dsi_device *dsi); + + /* This callback must be able to assume DSI commands can be sent */ + void (*enable)(struct intel_dsi_device *dsi); + + /* This callback must be able to assume DSI commands can be sent */ + void (*disable)(struct intel_dsi_device *dsi); + + int (*mode_valid)(struct intel_dsi_device *dsi, + struct drm_display_mode *mode); + + bool (*mode_fixup)(struct intel_dsi_device *dsi, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + void (*mode_set)(struct intel_dsi_device *dsi, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + enum drm_connector_status (*detect)(struct intel_dsi_device *dsi); + + bool (*get_hw_state)(struct intel_dsi_device *dev); + + struct drm_display_mode *(*get_modes)(struct intel_dsi_device *dsi); + + void (*destroy) (struct intel_dsi_device *dsi); +}; + +struct intel_dsi { + struct intel_encoder base; + + struct intel_dsi_device dev; + + struct intel_connector *attached_connector; + + /* if true, use HS mode, otherwise LP */ + bool hs; + + /* virtual channel */ + int channel; + + /* number of DSI lanes */ + unsigned int lane_count; + + /* video mode pixel format for MIPI_DSI_FUNC_PRG register */ + u32 pixel_format; + + /* video mode format for MIPI_VIDEO_MODE_FORMAT register */ + u32 video_mode_format; + + /* eot for MIPI_EOT_DISABLE register */ + u32 eot_disable; + + u32 port_bits; + u32 bw_timer; + u32 dphy_reg; + u32 video_frmt_cfg_bits; + u16 lp_byte_clk; + + /* timeouts in byte clocks */ + u16 lp_rx_timeout; + u16 turn_arnd_val; + u16 rst_timer_val; + u16 hs_to_lp_count; + u16 clk_lp_to_hs_count; + u16 clk_hs_to_lp_count; +}; + +static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) +{ + return container_of(encoder, struct intel_dsi, base.base); +} + +extern void vlv_enable_dsi_pll(struct intel_encoder *encoder); +extern void vlv_disable_dsi_pll(struct intel_encoder *encoder); + +#endif /* _INTEL_DSI_H */ --- linux-3.13.0.orig/ubuntu/i915/intel_dsi_cmd.h +++ linux-3.13.0/ubuntu/i915/intel_dsi_cmd.h @@ -0,0 +1,109 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Jani Nikula + */ + +#ifndef _INTEL_DSI_DSI_H +#define _INTEL_DSI_DSI_H + +#include +#include +#include " + +start on runlevel [2345] +stop on runlevel [!2345] +console log + +pre-start script + if [ -e "/etc/default/hv-kvp-daemon-init" ]; then + . /etc/default/hv-kvp-daemon-init + fi + [ "$RUN_FCOPY_DAEMON" -eq 0 ] && { stop; exit 0; } + if [ -d /sys/class/dmi/id/. ]; then + read company +and others. + +This package was put together by the Ubuntu Kernel Team, from +sources retrieved from upstream linux git. +The sources may be found at most Linux ftp sites, including +ftp://ftp.kernel.org/pub/linux/kernel/ + +This package is currently maintained by the +Ubuntu Kernel Team + +Linux is copyrighted by Linus Torvalds and others. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 dated June, 1991. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Ubuntu Linux systems, the complete text of the GNU General +Public License v2 can be found in `/usr/share/common-licenses/GPL-2'. --- linux-3.13.0.orig/debian/control.stub +++ linux-3.13.0/debian/control.stub @@ -0,0 +1,975 @@ +Source: linux +Section: devel +Priority: optional +Maintainer: Ubuntu Kernel Team +Standards-Version: 3.9.4.0 +Build-Depends: debhelper (>= 5), cpio, module-init-tools, kernel-wedge (>= 2.24ubuntu1), makedumpfile [amd64 i386], libelf-dev, libnewt-dev, libiberty-dev, rsync, libdw-dev, libpci-dev, dpkg (>= 1.16.0~ubuntu4), pkg-config, flex, bison, libunwind8-dev, openssl, libaudit-dev, bc, python-dev, gawk, device-tree-compiler [powerpc], u-boot-tools [powerpc], libc6-dev-ppc64 [powerpc] +Build-Depends-Indep: xmlto, docbook-utils, ghostscript, transfig, bzip2, sharutils, asciidoc +Vcs-Git: http://kernel.ubuntu.com/git-repos/ubuntu/ubuntu-trusty.git +XS-Testsuite: autopkgtest +#XS-Testsuite-Depends: gcc-4.7 binutils + +Package: linux-source-3.13.0 +Architecture: all +Section: devel +Priority: optional +Provides: linux-source, linux-source-3 +Depends: ${misc:Depends}, binutils, bzip2, coreutils | fileutils (>= 4.0) +Recommends: libc-dev, gcc, make +Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev +Description: Linux kernel source for version 3.13.0 with Ubuntu patches + This package provides the source code for the Linux kernel version + 3.13.0. + . + This package is mainly meant for other packages to use, in order to build + custom flavours. + . + If you wish to use this package to create a custom Linux kernel, then it + is suggested that you investigate the package kernel-package, which has + been designed to ease the task of creating kernel image packages. + . + If you are simply trying to build third-party modules for your kernel, + you do not want this package. Install the appropriate linux-headers + package instead. + +Package: linux-doc +Architecture: all +Section: doc +Priority: optional +Depends: ${misc:Depends} +Conflicts: linux-doc-3 +Replaces: linux-doc-3 +Description: Linux kernel specific documentation for version 3.13.0 + This package provides the various documents in the 3.13.0 kernel + Documentation/ subdirectory. These document kernel subsystems, APIs, device + drivers, and so on. See + /usr/share/doc/linux-doc/00-INDEX for a list of what is + contained in each file. + +Package: linux-headers-3.13.0-22 +Architecture: all +Multi-Arch: foreign +Section: devel +Priority: optional +Depends: ${misc:Depends}, coreutils | fileutils (>= 4.0) +Description: Header files related to Linux kernel version 3.13.0 + This package provides kernel header files for version 3.13.0, for sites + that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details + +Package: linux-libc-dev +Architecture: i386 amd64 armhf arm64 x32 powerpc ppc64el +Depends: ${misc:Depends} +Conflicts: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), amd64-libs-dev (<= 1.1), linux-kernel-headers +Replaces: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), linux-kernel-headers, libdrm-dev +Provides: linux-kernel-headers +Multi-Arch: same +Description: Linux Kernel Headers for development + This package provides headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system + libraries. They are NOT meant to be used to build third-party modules for + your kernel. Use linux-headers-* packages for that. + +Package: linux-tools-common +Architecture: all +Multi-Arch: foreign +Section: kernel +Priority: optional +Depends: ${misc:Depends} +Replaces: linux-tools (<= 2.6.32-16.25) +Description: Linux kernel version specific tools for version 3.13.0 + This package provides the architecture independent parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version PGKVER. + +Package: linux-tools-3.13.0-22 +Architecture: i386 amd64 armhf arm64 powerpc ppc64el +Section: devel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-tools-common +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + You probabally want to install linux-tools-3.13.0-22-. + +Package: linux-cloud-tools-common +Architecture: all +Multi-Arch: foreign +Section: kernel +Priority: optional +Breaks: linux-tools-common (<< 3.13.0-8.28), hv-kvp-daemon-init (<< 3.13) +Replaces: linux-tools-common (<< 3.13.0-8.28), hv-kvp-daemon-init (<< 3.13) +Depends: ${misc:Depends} +Description: Linux kernel version specific cloud tools for version 3.13.0 + This package provides the architecture independent parts for kernel + version locked tools for cloud tools for version PGKVER. + +Package: linux-cloud-tools-3.13.0-22 +Architecture: i386 amd64 armhf +Section: devel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-cloud-tools-common +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud tools for version 3.13.0-22 on + 64 bit x86. + You probabally want to install linux-cloud-tools-3.13.0-22-. + + +Package: linux-image-3.13.0-22-generic +Architecture: i386 amd64 armhf arm64 ppc64el +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: grub-pc [i386 amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [i386 amd64 x32] | grub [i386 amd64 x32] | lilo (>= 19.1) [i386 amd64 x32] | flash-kernel [armhf arm64] | grub-ieee1275 [ppc64el] +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-generic +Description: Linux kernel image for version 3.13.0 on 64 bit x86 SMP + This package contains the Linux kernel image for version 3.13.0 on + 64 bit x86 SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + Geared toward desktop and server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-generic meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-generic +Architecture: i386 amd64 armhf arm64 ppc64el +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-generic, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 64 bit x86 SMP + This package contains the Linux kernel extra modules for version 3.13.0 on + 64 bit x86 SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + Geared toward desktop and server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-generic meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-generic +Architecture: i386 amd64 armhf arm64 ppc64el +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 64 bit x86 SMP + This package provides kernel header files for version 3.13.0 on + 64 bit x86 SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-generic-dbgsym +Architecture: i386 amd64 armhf arm64 ppc64el +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 64 bit x86 SMP + This package provides a kernel debug image for version 3.13.0 on + 64 bit x86 SMP. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-generic +Architecture: i386 amd64 armhf arm64 ppc64el +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-generic +Architecture: i386 amd64 armhf arm64 ppc64el +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-generic +XC-Package-Type: udeb +Section: debian-installer +Architecture: i386 amd64 armhf arm64 ppc64el +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + + +Package: linux-image-3.13.0-22-generic-lpae +Architecture: armhf +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: flash-kernel [armhf] +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-generic-lpae +Description: Linux kernel image for version 3.13.0 on 64 bit x86 SMP + This package contains the Linux kernel image for version 3.13.0 on + 64 bit x86 SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic LPAE processors. + . + Geared toward desktop and server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-generic-lpae meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-generic-lpae +Architecture: armhf +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-generic-lpae, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 64 bit x86 SMP + This package contains the Linux kernel extra modules for version 3.13.0 on + 64 bit x86 SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic LPAE processors. + . + Geared toward desktop and server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-generic-lpae meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-generic-lpae +Architecture: armhf +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 64 bit x86 SMP + This package provides kernel header files for version 3.13.0 on + 64 bit x86 SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-generic-lpae-dbgsym +Architecture: armhf +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 64 bit x86 SMP + This package provides a kernel debug image for version 3.13.0 on + 64 bit x86 SMP. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-generic-lpae +Architecture: armhf +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-generic-lpae +Architecture: armhf +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-generic-lpae +XC-Package-Type: udeb +Section: debian-installer +Architecture: armhf +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + + +Package: linux-image-3.13.0-22-lowlatency +Architecture: i386 amd64 +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: grub-pc [i386 amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [i386 amd64 x32] | grub [i386 amd64 x32] | lilo (>= 19.1) [i386 amd64 x32] | flash-kernel [armhf arm64] +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-lowlatency +Description: Linux kernel image for version 3.13.0 on 64 bit x86 SMP + This package contains the Linux kernel image for version 3.13.0 on + 64 bit x86 SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Lowlatency processors. + . + Geared toward desktop and server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-lowlatency meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-lowlatency +Architecture: i386 amd64 +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-lowlatency, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 64 bit x86 SMP + This package contains the Linux kernel extra modules for version 3.13.0 on + 64 bit x86 SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Lowlatency processors. + . + Geared toward desktop and server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-lowlatency meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-lowlatency +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 64 bit x86 SMP + This package provides kernel header files for version 3.13.0 on + 64 bit x86 SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-lowlatency-dbgsym +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 64 bit x86 SMP + This package provides a kernel debug image for version 3.13.0 on + 64 bit x86 SMP. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-lowlatency +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-lowlatency +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-lowlatency +XC-Package-Type: udeb +Section: debian-installer +Architecture: i386 amd64 +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + + +Package: linux-image-3.13.0-22-powerpc64-emb +Architecture: powerpc +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: grub-kexec +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-powerpc64-emb +Description: Linux kernel image for version 3.13.0 on 64-bit PowerPC SMP Book3E + This package contains the Linux kernel image for version 3.13.0 on + 64-bit PowerPC SMP Book3E. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit PowerPC SMP Book3E processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc64-emb meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-powerpc64-emb +Architecture: powerpc +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-powerpc64-emb, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 64-bit PowerPC SMP Book3E + This package contains the Linux kernel extra modules for version 3.13.0 on + 64-bit PowerPC SMP Book3E. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit PowerPC SMP Book3E processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc64-emb meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-powerpc64-emb +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 64-bit PowerPC SMP Book3E + This package provides kernel header files for version 3.13.0 on + 64-bit PowerPC SMP Book3E. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-powerpc64-emb-dbgsym +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 64-bit PowerPC SMP Book3E + This package provides a kernel debug image for version 3.13.0 on + 64-bit PowerPC SMP Book3E. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-powerpc64-emb +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-powerpc64-emb +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-powerpc64-emb +XC-Package-Type: udeb +Section: debian-installer +Architecture: powerpc +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + + +Package: linux-image-3.13.0-22-powerpc64-smp +Architecture: powerpc +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: yaboot +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-powerpc64-smp +Description: Linux kernel image for version 3.13.0 on 64-bit PowerPC SMP + This package contains the Linux kernel image for version 3.13.0 on + 64-bit PowerPC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit PowerPC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc64-smp meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-powerpc64-smp +Architecture: powerpc +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-powerpc64-smp, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 64-bit PowerPC SMP + This package contains the Linux kernel extra modules for version 3.13.0 on + 64-bit PowerPC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit PowerPC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc64-smp meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-powerpc64-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 64-bit PowerPC SMP + This package provides kernel header files for version 3.13.0 on + 64-bit PowerPC SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-powerpc64-smp-dbgsym +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 64-bit PowerPC SMP + This package provides a kernel debug image for version 3.13.0 on + 64-bit PowerPC SMP. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-powerpc64-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-powerpc64-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-powerpc64-smp +XC-Package-Type: udeb +Section: debian-installer +Architecture: powerpc +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + + +Package: linux-image-3.13.0-22-powerpc-e500 +Architecture: powerpc +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: grub-kexec +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-powerpc-e500 +Description: Linux kernel image for version 3.13.0 on 32-bit Freescale Power e500v1 and e500v2 + This package contains the Linux kernel image for version 3.13.0 on + 32-bit Freescale Power e500v1 and e500v2. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit Freescale Power e500v1 and e500v2 processors. + . + Geared toward server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc-e500 meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-powerpc-e500 +Architecture: powerpc +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-powerpc-e500, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 32-bit Freescale Power e500v1 and e500v2 + This package contains the Linux kernel extra modules for version 3.13.0 on + 32-bit Freescale Power e500v1 and e500v2. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit Freescale Power e500v1 and e500v2 processors. + . + Geared toward server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc-e500 meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-powerpc-e500 +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 32-bit Freescale Power e500v1 and e500v2 + This package provides kernel header files for version 3.13.0 on + 32-bit Freescale Power e500v1 and e500v2. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-powerpc-e500-dbgsym +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 32-bit Freescale Power e500v1 and e500v2 + This package provides a kernel debug image for version 3.13.0 on + 32-bit Freescale Power e500v1 and e500v2. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-powerpc-e500 +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-powerpc-e500 +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-powerpc-e500 +XC-Package-Type: udeb +Section: debian-installer +Architecture: powerpc +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + + +Package: linux-image-3.13.0-22-powerpc-e500mc +Architecture: powerpc +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: grub-kexec +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-powerpc-e500mc +Description: Linux kernel image for version 3.13.0 on 32-bit Freescale Power e500mc + This package contains the Linux kernel image for version 3.13.0 on + 32-bit Freescale Power e500mc. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit Freescale Power e500mc processors. + . + Geared toward server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc-e500mc meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-powerpc-e500mc +Architecture: powerpc +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-powerpc-e500mc, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 32-bit Freescale Power e500mc + This package contains the Linux kernel extra modules for version 3.13.0 on + 32-bit Freescale Power e500mc. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit Freescale Power e500mc processors. + . + Geared toward server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc-e500mc meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-powerpc-e500mc +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 32-bit Freescale Power e500mc + This package provides kernel header files for version 3.13.0 on + 32-bit Freescale Power e500mc. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-powerpc-e500mc-dbgsym +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 32-bit Freescale Power e500mc + This package provides a kernel debug image for version 3.13.0 on + 32-bit Freescale Power e500mc. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-powerpc-e500mc +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-powerpc-e500mc +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-powerpc-e500mc +XC-Package-Type: udeb +Section: debian-installer +Architecture: powerpc +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + + +Package: linux-image-3.13.0-22-powerpc-smp +Architecture: powerpc +Section: kernel +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-3.0, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: ${misc:Depends}, ${shlibs:Depends}, initramfs-tools (>= 0.36ubuntu6), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: yaboot +Suggests: fdutils, linux-doc-3.13.0 | linux-source-3.13.0, linux-tools, linux-headers-3.13.0-22-powerpc-smp +Description: Linux kernel image for version 3.13.0 on 32-bit PowerPC SMP + This package contains the Linux kernel image for version 3.13.0 on + 32-bit PowerPC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit PowerPC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc-smp meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-image-extra-3.13.0-22-powerpc-smp +Architecture: powerpc +Section: kernel +Priority: optional +Depends: ${misc:Depends}, ${shlibs:Depends}, linux-image-3.13.0-22-powerpc-smp, crda (>=1.1.1-1ubuntu2) | wireless-crda +Description: Linux kernel extra modules for version 3.13.0 on 32-bit PowerPC SMP + This package contains the Linux kernel extra modules for version 3.13.0 on + 32-bit PowerPC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit PowerPC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc-smp meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-3.13.0-22-powerpc-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-headers-3.13.0-22, ${shlibs:Depends} +Provides: linux-headers, linux-headers-3.0 +Description: Linux kernel headers for version 3.13.0 on 32-bit PowerPC SMP + This package provides kernel header files for version 3.13.0 on + 32-bit PowerPC SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-3.13.0-22/debian.README.gz for details. + +Package: linux-image-3.13.0-22-powerpc-smp-dbgsym +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends} +Provides: linux-debug +Description: Linux kernel debug image for version 3.13.0 on 32-bit PowerPC SMP + This package provides a kernel debug image for version 3.13.0 on + 32-bit PowerPC SMP. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-tools-3.13.0-22-powerpc-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-tools-3.13.0-22 +Description: Linux kernel version specific tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools (such as perf and x86_energy_perf_policy) for + version 3.13.0-22 on + 64 bit x86. + +Package: linux-cloud-tools-3.13.0-22-powerpc-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: ${misc:Depends}, linux-cloud-tools-3.13.0-22 +Description: Linux kernel version specific cloud tools for version 3.13.0-22 + This package provides the architecture dependant parts for kernel + version locked tools for cloud for version 3.13.0-22 on + 64 bit x86. + +Package: linux-udebs-powerpc-smp +XC-Package-Type: udeb +Section: debian-installer +Architecture: powerpc +Depends: ${udeb:Depends} +Description: Metapackage depending on kernel udebs + This package depends on the all udebs that the kernel build generated, + for easier version and migration tracking. + --- linux-3.13.0.orig/debian/linux-cloud-tools-common.hv-kvp-daemon.upstart +++ linux-3.13.0/debian/linux-cloud-tools-common.hv-kvp-daemon.upstart @@ -0,0 +1,22 @@ +# On Azure/Hyper-V systems start the hv_kvp_daemon +# +description "Hyper-V KVP Protocol Daemon" +author "Adam Conrad " + +start on runlevel [2345] +stop on runlevel [!2345] +console log + +pre-start script + if [ -e "/etc/default/hv-kvp-daemon-init" ]; then + . /etc/default/hv-kvp-daemon-init + fi + [ "$RUN_KVP_DAEMON" = 0 ] && { stop; exit 0; } + if [ -d /sys/class/dmi/id/. ]; then + read company ) { + chomp; + my ($junk, $alias, $module) = split; + + if (defined($map{$alias})) { + printf("%s %20s / %-20s : %s \n", ("$map{$alias}" eq "$module") + ? "INT" : " ", $map{$alias}, $module, $alias); + } else { + $map{$alias} = $module; + } +} + +exit(0); --- linux-3.13.0.orig/debian/commit-templates/config-updates +++ linux-3.13.0/debian/commit-templates/config-updates @@ -0,0 +1,15 @@ +# +# This template is used for commit messages that don't need to +# show up in debian/changelog. Administrative stuff like config +# updates, ABI bumps, etc. Setting 'Ignore: yes' prevents +# 'debian/rules insertchanges' from inserting this commit meesage +# as a changelog entry. +# +# Please give a one-line description of the config change followed +# by a detailed explanation if necessary + +UBUNTU: [Config] XXXX + +# BugLink: http://bugs.launchpad.net/bugs/ +# Ignore: yes +# Other text below here. --- linux-3.13.0.orig/debian/commit-templates/external-driver +++ linux-3.13.0/debian/commit-templates/external-driver @@ -0,0 +1,20 @@ +# Ubuntu external driver commit. +# +# NOTE: This gets reformatted for README.Ubuntu-External-Drivers and +# debian/changelog. +# +# This is only needed when a driver is added, updated or removed. It is +# not needed when patches or fixes are applied to the driver. If the +# driver is being removed, add the line: +# +# Removing: yes +# +# to the commit, and you can remove all other tags (except UBUNTU:). +# +UBUNTU: + +ExternalDriver: +Description: +Url: +Mask: +Version: --- linux-3.13.0.orig/debian/commit-templates/upstream-patch +++ linux-3.13.0/debian/commit-templates/upstream-patch @@ -0,0 +1,27 @@ +# Ubuntu commit template. +# +# NOTE: This gets reformatted for debian/changelog +# +# The initial UBUNTU is a flag that this is an Ubuntu commit. It will be +# referenced to the Author in the debian/changelog entry. +# +# The text following is the short message that will be placed in the +# changelog. Extra text on the following lines will be ignored, but left +# in the git commit. Lines with # will be ignored in the commit. +# +# OriginalAuthor allows for alternate attribution. +# +# OriginalLocation allows for a URL or description of where the patch came +# from. +# +# BugLink is a URL to a Malone bug. +# +# Ignore: yes will keep this commit from showing up in the changelog. +# +UBUNTU: [Upstream] + +# OriginalAuthor: +# OriginalLocation: +# BugLink: http://bugs.launchpad.net/bugs/ +# Ignore: yes +# Other text below here. --- linux-3.13.0.orig/debian/commit-templates/missing-modules +++ linux-3.13.0/debian/commit-templates/missing-modules @@ -0,0 +1,3 @@ +UBUNTU: build/modules: Add modules that have intentionally gone missing + +Ignore: yes --- linux-3.13.0.orig/debian/commit-templates/sauce-patch +++ linux-3.13.0/debian/commit-templates/sauce-patch @@ -0,0 +1,40 @@ +# Ubuntu commit template. +# +# NOTE: This gets reformatted for debian/changelog +# +# +# SAUCE refers to the fact that this patch might not go upstream, but we need to +# carry it to successive releases. In most cases you DONOT want to use this +# template. +# +# An example of a SAUCE patch is the ACPI DSDT-in-initramfs patch which has been +# refused upstream, but still provides useful functionality to users with broken +# BIOSes. +# +#------------------------------------------------------------------------- +# +# The initial UBUNTU is a flag that this is an Ubuntu commit. It will be +# referenced to the Author in the debian/changelog entry. +# +# The text following is the short message that will be placed in the +# changelog. Extra text on the following lines will be ignored, but left +# in the git commit. Lines with # will be ignored in the commit. +# +# OriginalAuthor allows for alternate attribution. +# +# OriginalLocation allows for a URL or description of where the patch came +# from. +# +# BugLink is a URL to a Malone bug. +# +# Ignore: yes will keep this commit from showing up in the changelog. +# +UBUNTU: SAUCE: + + + +# OriginalAuthor: +# OriginalLocation: +# BugLink: http://bugs.launchpad.net/bugs/ +# Ignore: yes +# Other text below here. --- linux-3.13.0.orig/debian/commit-templates/newrelease +++ linux-3.13.0/debian/commit-templates/newrelease @@ -0,0 +1,3 @@ +UBUNTU: Start new release + +Ignore: yes --- linux-3.13.0.orig/debian/commit-templates/bumpabi +++ linux-3.13.0/debian/commit-templates/bumpabi @@ -0,0 +1,3 @@ +UBUNTU: Bump ABI + +Ignore: yes --- linux-3.13.0.orig/debian/tools/generic +++ linux-3.13.0/debian/tools/generic @@ -0,0 +1,60 @@ +#!/bin/bash +full_version=`uname -r` + +# First check for a fully qualified version. +this="/usr/lib/linux-tools/$full_version/`basename $0`" +if [ -f "$this" ]; then + exec "$this" "$@" +fi + +# Removing flavour from version i.e. generic or server. +flavour_abi=${full_version#*-} +flavour=${flavour_abi#*-} +version=${full_version%-$flavour} +this="$0_$version" +if [ -f "$this" ]; then + exec "$this" "$@" +fi + +# Before saucy kernels we had no flavour linkage. +if dpkg --compare-versions "$version" lt "3.11.0"; then + flavour='' +else + flavour="-$flavour" +fi +# Hint at the cloud tools if they exist (trusty and later) +if dpkg --compare-versions "$version" ge "3.13.0"; then + cld="" +else + cld=":" +fi +# Work out if this is an LTS backport or not. +codename=`lsb_release -cs` +case "$codename" in +precise) base='3.2.0-9999' ;; +trusty) base='3.13.0-9999' ;; +*) base='' ;; +esac +std="" +lts=":" +if [ "$base" != "" ]; then + if dpkg --compare-versions "$version" gt "$base"; then + std=":" + lts="" + fi +fi + +# Give them a hint as to what to install. + echo "WARNING: `basename $0` not found for kernel $version" >&2 + echo "" >&2 + echo " You may need to install the following packages for this specific kernel:" >&2 + echo " linux-tools-$version$flavour" >&2 +$cld echo " linux-cloud-tools-$version$flavour" >&2 + echo "" >&2 + echo " You may also want to install one of the following packages to keep up to date:" >&2 +$std echo " linux-tools$flavour" >&2 +$std $cld echo " linux-cloud-tools$flavour" >&2 +$lts echo " linux-tools$flavour-lts-" >&2 +$lts $cld echo " linux-cloud-tools$flavour-lts-" >&2 + +exit 2 --- linux-3.13.0.orig/debian/control-scripts/postrm +++ linux-3.13.0/debian/control-scripts/postrm @@ -0,0 +1,361 @@ +#! /usr/bin/perl +# -*- Mode: Cperl -*- +# image.postrm --- +# Author : Manoj Srivastava ( srivasta@glaurung.green-gryphon.com ) +# Created On : Sat May 15 11:05:13 1999 +# Created On Node : glaurung.green-gryphon.com +# Last Modified By : Manoj Srivastava +# Last Modified On : Wed Sep 13 11:26:19 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 57 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# $Id: image.postrm,v 1.31 2003/10/07 16:24:20 srivasta Exp $ +# + + +# +#use strict; #for debugging +use Cwd 'abs_path'; + +$|=1; + +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlink = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, or nettrom +my $image_dir = "/boot"; # where the image is located +my $clobber_modules = ''; # target machine defined +my $initrd = "YES"; # initrd kernel +my $do_initrd = ''; # Normally, we don't +my $warn_initrd = 'YES'; # Normally we do +my $use_hard_links = ''; # hardlinks do not work across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $relink_build_link = 'YES'; # There is no harm in checking the link +my $force_build_link = ''; # we shall not create a dangling link +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; +my $package_name = "linux-image-$version"; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; + + +# This should not point to /tmp, because of security risks. +my $temp_file_name = "/var/log/$loader" . "_log.$$"; + +#known variables +my @boilerplate = (); +my @silotemplate = (); +my @quiktemplate = (); +my @palotemplate = (); +my @vmelilotemplate = (); +my $bootdevice = ''; +my $rootdevice = ''; +my $rootdisk = ''; +my $rootpartition = ''; +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $CONF_LOC = '/etc/kernel-img.conf'; +my $relative_links = ''; +my $silent_modules = ''; +my $silent_loader = ''; +my $warn_reboot = 'Yes'; # Warn that we are installing a version of + # the kernel we are running + +chdir('/') or die "could not chdir to /:$!\n"; +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlinks\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $clobber_modules = '' if /^\s*clobber_modules\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $do_initrd = '' if /^\s*do_initrd\s*=\s*(no|false|0)\s*$/ig; + $warn_initrd = '' if /^\s*warn_initrd\s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_modules = '' if /^\s*silent_modules\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + $relink_build_link = '' if /^\s*relink_build_link\s*=\s*(no|false|0)\s*$/ig; + $force_build_link = '' if /^\s*force_build_link\s*=\s*(no|false|0)\s*$/ig; + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $clobber_modules = "Yes" if /^\s*clobber_modules\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $do_initrd = "Yes" if /^\s*do_initrd\s*=\s*(yes|true|1)\s*$/ig; + $warn_initrd = "Yes" if /^\s*warn_initrd\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_modules = 'Yes' if /^\s*silent_modules\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + $relink_build_link = 'Yes' if /^\s*relink_build_link\s*=\s*(yes|true|1)\s*$/ig; + $force_build_link = 'Yes' if /^\s*force_build_link\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + } +} + +if ($link_in_boot) { + $image_dest = "/$image_dir/"; + $image_dest =~ s|^/*|/|o; +} + +$image_dest = "$image_dest/"; +$image_dest =~ s|/+$|/|o; + +# The destdir may be gone by now. +if (-d "$image_dest") { + chdir("$image_dest") or die "could not chdir to $image_dest:$!\n"; +} + +# Paranoid check to make sure that the correct value is put in there +if (! $kimage) {$kimage = "vmlinuz"} # Hmm. empty +elsif ($kimage =~ m/^b?uImage$/o) {$kimage = "vmlinuz"} # these produce vmlinuz +elsif ($kimage =~ m/^b?zImage$/o) {$kimage = "vmlinuz"} # these produce vmlinuz +elsif ($kimage =~ m/^[iI]mage$/o) { my $nop = $kimage;} +elsif ($kimage =~ m/^vmlinux$/o) { my $nop = $kimage;} +else {$kimage = "vmlinuz"} # default + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +sub remove_sym_link { + my $bad_image = $_[0]; + + warn "Removing symbolic link $bad_image \n"; + if ($loader =~ /lilo/i) + { + warn "Unless you used the optional flag in lilo, \n"; + } + warn " you may need to re-run your boot loader" . ($loader ? "[$loader]":"") + . "\n"; + # Remove the dangling link + unlink "$bad_image"; +} + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +sub CanonicalizePath { + my $path = join '/', @_; + my @work = split '/', $path; + my @out; + my $is_absolute; + + if (@work && $work[0] eq "") { $is_absolute = 1; shift @work; } + + while (@work) { + my $seg = shift @work; + if ($seg eq "." || $seg eq "") { + } elsif ($seg eq "..") { + if (@out && $out[-1] ne "..") { + pop @out; + } else { + # Leading "..", or "../..", etc. + push @out, $seg; + } + } else { + push @out, $seg; + } + } + + unshift @out, "" if $is_absolute; + return join('/', @out); +} + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +# This removes dangling symlinks. What do we do about hard links? Surely a +# something with the nane $image_dest . "$kimage" ought not to be left behind? +sub image_magic { + my $kimage = $_[0]; + my $image_dest = $_[1]; + + if (-l "$kimage") { + # There is a symbolic link + my $force_move = 0; + my $vmlinuz_target = readlink "$kimage"; + my $real_target = ''; + $real_target = abs_path($vmlinuz_target) if defined ($vmlinuz_target); + if (!defined($vmlinuz_target) || ! -f "$real_target") { + # what, a dangling symlink? + warn "The link " . $image_dest . "$kimage is a damaged link\n"; + # Remove the dangling link + &remove_sym_link("$kimage"); + } + else { + my $canonical_target = CanonicalizePath("$vmlinuz_target"); + if (! -e $canonical_target) { + warn "The link " . $image_dest . "$kimage is a dangling link\n"; + &remove_sym_link("$kimage"); + } + } + } +} + +# set the env var stem +$ENV{'STEM'} = "linux"; + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + warn "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + warn "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + +my $options; +for (@ARGV) { + s,','\\'',g; + $options .= " '$_'"; +} +$ENV{'DEB_MAINT_PARAMS'}="$options"; + +## Run user hook script here, if any +if ($postrm_hook) { + &run_hook("postrm", $postrm_hook); +} +if (-d "/etc/kernel/postrm.d") { + warn "Examining /etc/kernel/postrm.d .\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postrm.d") && + die "Failed to process /etc/kernel/postrm.d"; +} +if (-d "/etc/kernel/postrm.d/$version") { + warn "Examining /etc/kernel/postrm.d/$version .\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postrm.d/$version") && + die "Failed to process /etc/kernel/postrm.d/$version"; +} + +# check and remove damaged and dangling symlinks +if ($ARGV[0] !~ /upgrade/) { + system("$ramdisk -d -k " . $version . " > /dev/null 2>&1"); + if (-f $realimageloc . "initrd.img-$version.bak") { + unlink $realimageloc . "initrd.img-$version.bak"; + } + image_magic($kimage, $image_dest); + image_magic($kimage . ".old", $image_dest); + image_magic("initrd.img", $image_dest) if $initrd; + image_magic("initrd.img.old", $image_dest) if $initrd; +} + +exit 0; + +__END__ + + + + + + --- linux-3.13.0.orig/debian/control-scripts/prerm +++ linux-3.13.0/debian/control-scripts/prerm @@ -0,0 +1,312 @@ +#! /usr/bin/perl +# -*- Mode: Perl -*- +# image.prerm --- +# Author : root ( root@melkor.pilgrim.umass.edu ) +# Created On : Fri May 17 03:28:59 1996 +# Created On Node : melkor.pilgrim.umass.edu +# Last Modified By : Manoj Srivastava +# Last Modified On : Sat Aug 5 13:14:17 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 85 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# +# $Id: image.prerm,v 1.22 2003/10/07 16:24:20 srivasta Exp $ +# +# +#use strict; + +$|=1; +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlinks = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, or nettrom +my $image_dir = "/boot"; # where the image is located +my $clobber_modules = ''; # target machine defined +my $initrd = "YES"; # initrd kernel +my $use_hard_links = ''; # hardlinks do not wirk across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $relink_build_link = 'YES'; # There is no harm in checking the link +my $force_build_link = ''; # There is no harm in checking the link +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; +my $package_name = "linux-image-$version"; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; + + +# This should not point to /tmp, because of security risks. +my $temp_file_name = "/var/log/$loader" . "_log.$$"; + +#known variables +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $CONF_LOC = '/etc/kernel-img.conf'; +my $relative_links = ''; +my $silent_loader = ''; +my $warn_reboot = 'Yes'; # Warn that we are installing a version of + # the kernel we are running + +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + +my $DEBUG = 0; + +# Variables used +my $image=''; +my $ret=0; +my $seen=''; +my $answer=''; +my $running = ''; +my $WouldInvalidate = 0; + +if ($ARGV[0] && ($ARGV[0] =~ /remove/ || $ARGV[0] =~ /upgrade/)) { + if (-l "/usr/doc/linux-image-$version") { + unlink "/usr/doc/linux-image-$version"; + } +} + +# Ignore all invocations uxcept when called on to remove +exit 0 unless ($ARGV[0] && $ARGV[0] =~ /remove/) ; + +# Paranoid check to make sure that the correct value is put in there +if (! $kimage) { $kimage = "vmlinuz";} # Hmm. empty +elsif ($kimage =~ m/^b?uImage$/o) { $kimage = "vmlinuz";} # these produce vmlinuz +elsif ($kimage =~ m/^b?zImage$/o) { $kimage = "vmlinuz";} # these produce vmlinuz +elsif ($kimage =~ m/^[iI]mage$/o) { my $nop = $kimage; } +elsif ($kimage =~ m/^vmlinux$/o) { my $nop = $kimage; } +else { $kimage = "vmlinuz";} # Default + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlinks\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $clobber_modules = '' if /^\s*clobber_modules\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $do_initrd = '' if /^\s*do_initrd\s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + $relink_build_link = '' if /^\s*relink_build_link\s*=\s*(no|false|0)\s*$/ig; + $force_build_link = '' if /^\s*force_build_link\s*=\s*(no|false|0)\s*$/ig; + + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $clobber_modules = "Yes" if /^\s*clobber_modules\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $do_initrd = "Yes" if /^\s*do_initrd\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + $relink_build_link = 'Yes' if /^\s*relink_build_link\s*=\s*(yes|true|1)\s*$/ig; + $force_build_link = 'Yes' if /^\s*force_build_link\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + } +} + + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + +#check to see if we are trying to remove a running kernel +# if so we abort right now. +chop($running=`uname -r`); +if ($running eq $version) { + print STDERR "WARN: Proceeding with removing running kernel image.\n"; +} + +#Now, they have an alternate kernel which they are currently running + +# This is just us being nice to lilo users. + +chdir("/") or die "could not chdir to /:$!\n"; + +if (-f "/etc/$loader.conf") { #I know, could be a link, but .. + open (LILO, "/etc/$loader.conf") || &success(); # this is not critical + while () { + chop; + s/\#.*//; # nix the comments + next unless /^\s*image\s*=\s(\S+)/o; + $image = $1; + if ($image && -e $image) { + while (defined($image) && -l $image) { + $image = readlink ($image); + } + if (defined($image) && -e $image) { + $WouldInvalidate |= $image =~ /$kimage-$version/; + } + else { + &success(); # invalid $loader.conf file + } + } + else { + &success(); # invalid $loader.conf file + } + } + close (LILO); + if ($WouldInvalidate) { + print STFERR "WARN: Proceeding with removing running kernel image.\n"; + &success(); + } +} + + +# set the env var stem +$ENV{'STEM'} = "linux"; + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + + +my $options; +for (@ARGV) { + s,','\\'',g; + $options .= " '$_'"; +} +$ENV{'DEB_MAINT_PARAMS'}="$options"; + +## Run user hook script here, if any +if (-x "$prerm_hook") { + &run_hook("prerm", $prerm_hook); +} +if (-d "/etc/kernel/prerm.d") { + print STDERR "Examining /etc/kernel/prerm.d.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version /etc/kernel/prerm.d") && + die "Failed to process /etc/kernel/prerm.d"; +} +if (-d "/etc/kernel/prerm.d/$version") { + print STDERR "Examining /etc/kernel/prerm.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version" . + " --arg=$realimageloc$kimage-$version " . + "/etc/kernel/prerm.d/$version") && + die "Failed to process /etc/kernel/prerm.d/$version"; +} + +sub success () { + # NOTE: need to keep this list in sync with rules.d/2-binary-arch.mk + my %files_to_keep = ( + 'modules.builtin' => 1, + 'modules.order' => 1, + ); + my $short; + for my $file () { + $short = $file; $short =~ s,.*/,,; + if (!defined $files_to_keep{$short}) { + unlink "$file"; + } + } + exit 0; +} + + + +&success(); +exit 0; +__END__ + + + + + --- linux-3.13.0.orig/debian/control-scripts/postinst +++ linux-3.13.0/debian/control-scripts/postinst @@ -0,0 +1,1110 @@ +#! /usr/bin/perl +# OriginalAuthor : Manoj Srivastava ( srivasta@pilgrim.umass.edu ) +# +# Customized for Ubuntu by: Ben Collins + +#use strict; #for debugging +use Cwd 'abs_path'; + +$|=1; + +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlink = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, nettrom, arcboot or delo +my $image_dir = "/boot"; # where the image is located +my $clobber_modules = ''; # target machine defined +my $relative_links = ""; # target machine defined +my $initrd = "YES"; # initrd kernel +my $do_initrd = ''; # Normally we do not +my $use_hard_links = ''; # hardlinks do not work across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; # List of tools to create initial ram fs. +my $notifier = "/usr/share/update-notifier/notify-reboot-required"; +my $package_name = "linux-image-$version"; +my $explicit_do_loader = 'Yes'; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; +$Loader = "ARCBOOT" if $loader =~ /^arcboot/io; +$Loader = "DELO" if $loader =~ /^delo/io; + +# This should not point to /tmp, because of security risks. +my $temp_file_name = "/var/log/$loader" . "_log.$$"; + +#known variables +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $silent_modules = ''; +my $silent_loader = ''; +my $warn_reboot = 'Yes'; # Warn that we are installing a version of + # the kernel we are running + +my $modules_base = '/lib/modules'; +my $CONF_LOC = '/etc/kernel-img.conf'; + +# Ignore all invocations except when called on to configure. +exit 0 unless $ARGV[0] =~ /configure/; + +my $DEBUG = 0; + +# Do some preliminary sanity checks here to ensure we actually have an +# valid image dir +chdir('/') or die "could not chdir to /:$!\n"; +die "Internal Error: ($image_dir) is not a directory!\n" + unless -d $image_dir; + +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; +die "Internal Error: ($realimageloc) is not a directory!\n" + unless -d $realimageloc; + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlink\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $clobber_modules = '' if /^\s*clobber_modules\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $explicit_do_loader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $do_initrd = '' if /^\s*do_initrd\s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_modules = '' if /^\s*silent_modules\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $clobber_modules = "Yes" if /^\s*clobber_modules\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $explicit_do_loader = "YES" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $do_initrd = "Yes" if /^\s*do_initrd\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_modules = 'Yes' if /^\s*silent_modules\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + } +} + + + +# For some versions of kernel-package, we had this warning in the +# postinst, but the rules did not really interpolate the value in. +# Here is a sanity check. +my $pattern = "=" . "I"; +$initrd=~ s/^$pattern$//; + +if ($link_in_boot) { + $image_dest = "/$image_dir/"; # same as realimageloc +} + +# Tack on at least one trainling / +$image_dest = "$image_dest/"; +$image_dest =~ s|^/*|/|o; +$image_dest =~ s|/+$|/|o; + +if (! -d "$image_dest") { + die "Expected Image Destination dir ($image_dest) to be a valid directory!\n"; +} + +# sanity +if (!($do_bootfloppy || $do_bootloader)) { + $do_boot_enable = ''; +} +if ($do_symlink && $no_symlink) { + warn "Both do_symlinks and no_symlinks options enabled; disabling no_symlinks\n"; + $no_symlink = 0; +} + +# most of our work is done in $image_dest (nominally /) +chdir("$image_dest") or die "could not chdir to $image_dest:$!\n"; + +# Paranoid check to make sure that the correct value is put in there +if (! $kimage) { $kimage = "vmlinuz"; } # Hmm. empty +elsif ($kimage =~ m/^b?uImage$/o) { $kimage = "vmlinuz"; } # these produce vmlinuz +elsif ($kimage =~ m/^b?zImage$/o) { $kimage = "vmlinuz"; } # these produce vmlinuz +elsif ($kimage =~ m/^[iI]mage$/o) { my $nop = $kimage; } +elsif ($kimage =~ m/^vmlinux$/o) { my $nop = $kimage; } +else { $kimage = "vmlinuz"; } # Default + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + + +die "Internal Error: Could not find image (" . $realimageloc + . "$kimage-$version)\n" unless -e $realimageloc + . "$kimage-$version"; + +# search for the boot loader in the path +my $loader_exec; +($loader_exec = $loader) =~ s|.*/||; +my ($loaderloc) = grep -x, map "$_/$loader_exec", + map { length($_) ? $_ : "." } split /:/, $ENV{PATH}; + + +###################################################################### +###################################################################### +########### Test whether a relative symlinkwould be OK ####### +###################################################################### +###################################################################### +sub test_relative { + my %params = @_; + my $cwd; + + die "Internal Error: Missing Required paramater 'Old Dir' " + unless $params{'Old Dir'}; + die "Internal Error: Missing Required paramater New Dir' " + unless $params{'New Dir'}; + + + die "Internal Error: No such dir $params{'Old Dir'} " + unless -d $params{'Old Dir'}; + die "Internal Error: No such dir $params{'New Dir'} " + unless -d $params{'New Dir'}; + + # If the caller specified a test file, and it does not exist try and find + # another file to use in its stead. As we are installing kernels we can + # use any versioned file from this kernel which should be in the same place. + if (defined $params{'Test File'} and + ! -f $params{'Old Dir'} . '/' . $params{'Test File'}) { + + my @possible = glob($params{'Old Dir'} . "/*$version*"); + if ($#possible >= 0) { + $params{'Test File'} = `basename "$possible[0]"`; + chomp($params{'Test File'}); + warn "Test relative: selected $params{'Test File'}" + if $DEBUG; + } + } + + warn "Test relative: testing $params{'Old Dir'} -> $params{'New Dir'}" + if $DEBUG; + chomp($cwd = `pwd`); + chdir ($params{'New Dir'}) or die "Could not chdir to $params{'New Dir'}:$!"; + my $ok = 0; + $params{'Old Dir'} =~ s|^/*||o; + if (-d $params{'Old Dir'} ) { + if (defined $params{'Test File'}) { + if (-e $params{'Old Dir'} . $params{'Test File'}) { + $ok = 1; + } + } else { + $ok = 1; # well, backward compatibility + } + } + chdir ($cwd) or die "Could not chdir to $params{'New Dir'}:$!"; + return $ok; +} + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +# sub CanonicalizePath { +# my $path = join '/', @_; +# my @work = split '/', $path; +# my @out; +# my $is_absolute; + +# if (@work && $work[0] eq "") { +# $is_absolute = 1; shift @work; +# } + +# while (@work) { +# my $seg = shift @work; +# if ($seg eq "." || $seg eq "") { +# } +# elsif ($seg eq "..") { +# if (@out && $out[-1] ne "..") { +# pop @out; +# } +# else { +# # Leading "..", or "../..", etc. +# push @out, $seg; +# } +# } +# else { +# push @out, $seg; +# } +# } + +# unshift @out, "" if $is_absolute; +# return join('/', @out); +# } +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### + +sub spath { + my %params = @_; + + die "Missing Required paramater 'Old'" unless $params{'Old'}; + die "Missing Required paramater 'New'" unless $params{'New'}; + + my @olddir = split '/', `readlink -q -m $params{'Old'}`; + my @newdir = split '/', `readlink -q -m $params{'New'}`; + my @outdir = @olddir; + + my $out = ''; + my $i; + for ($i = 0; $i <= $#olddir && $i <= $#newdir; $i++) { + $out++ if ($olddir[$i] ne $newdir[$i]); + shift @outdir unless $out; + unshift @outdir, ".." if $out; + } + if ($#newdir > $#olddir) { + for ($i=0; $i < $#newdir; $i++) { + unshift @outdir, ".."; + } + } + return join ('/', @outdir); +} +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### + + +# This routine actually moves the kernel image +# From: $realimageloc/$kimage-$version (/boot/vmlinuz-2.6.12) +# To: $image_dest/$kimage-$version (/vmlinuz-2.6.12) +# Note that the image is moved to a versioned destination, but ordinary +# symlinks we create otherwise are not normally versioned +sub really_move_image { + my $src_dir = $_[0]; + my $target = $_[1]; + my $dest_dir = $_[2]; + + warn "Really move image: src_dir=$src_dir, target=$target,\n destdir=$dest_dir" + if $DEBUG; + if (-e "$target") { + # we should be in dir $dest_dir == $image_dest /, normally + rename("$target", "$target.$$") || + die "failed to move " . $dest_dir . "$target:$!"; + warn "mv $target $target.$$" if $DEBUG; + } + warn "mv -f $src_dir$target $target" if $DEBUG; + my $ret = system("mv -f " . $src_dir . "$target " . + " $target"); + if ($ret) { + die("Failed to move " . $src_dir . "$target to " + . $dest_dir . "$target"); + } + # Ok, now we may clobber the previous .old files + if (-e "$target.$$") { + rename("$target.$$", "$target.old") || + die "failed to move " . $dest_dir . "$target:$!"; + warn "mv $target.$$ $target " if $DEBUG; + } +} + +# Normally called after really_move_image; and only called if we asked for +# reversed link this routine reverses the symbolic link that is notmally +# created. Since the real kernel image has been moved over to +# $image_dest/$kimage-$version. So, this routine links +# From: $image_dest/$kimage-$version (/vmlinuz-2.6.12) +# To: $realimageloc/$kimage-$version (/boot/vmlinuz-2.6.12) +sub really_reverse_link { + my $src_dir = $_[0]; + my $link_name = $_[1]; + my $dest_dir = $_[2]; + warn "Really reverse link: src_dir=$src_dir, link name=$link_name\n" . + "\tdestdir=$dest_dir" if $DEBUG; + + my $Old = $dest_dir; + if (test_relative ('Old Dir' => $Old, 'New Dir' => $src_dir, + 'Test File' => "$link_name")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$src_dir" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + if ($use_hard_links =~ m/YES/i) { + link($Old . "$link_name", $src_dir . "$link_name") || + die("Failed to link " . $dest_dir . "$link_name to " . $src_dir . + "$link_name:$!"); + warn "ln " . $Old . "$link_name " . $src_dir . "$link_name" if $DEBUG; + } + else { + symlink($Old . "$link_name", $src_dir . "$link_name") || + die("Failed to symbolic-link " . $dest_dir . "$link_name to " . $src_dir + . "$link_name:$!"); + warn "ln -s " . $Old . "$link_name " . $src_dir . "$link_name" if $DEBUG; + } +} + +# This routine is invoked if there is a symbolic link in place +# in $image_dest/$kimage -- so a symlink exists in the destination. +# What we are trying to determine is if we need to move the symbolic link over +# to the the .old location +sub move_p { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + my $force_move = 0; + warn "Move?: kimage=$kimage, image_dest=$image_dest, \n" . + "\timage_name=$image_name, src_dir=$src_dir" if $DEBUG; + + if ($no_symlink || $reverse_symlink) { + # we do not want links, yet we have a symbolic link here! + warn "found a symbolic link in " . $image_dest . "$kimage \n" . + "even though no_symlink is defined\n" if $no_symlink; + warn "found a symbolic link in " . $image_dest . "$kimage \n" . + "even though reverse_symlink is defined\n" if $reverse_symlink; + # make sure we change this state of affairs + $force_move = 1; + return $force_move; + } + + warn "DEBUG: OK. We found symlink, and we should have a symlink here.\n" + if $DEBUG; + my $vmlinuz_target = readlink "$kimage"; + my $real_target = ''; + my $target = `readlink -q -m "${realimageloc}${kimage}-${version}"`; + $real_target = abs_path($vmlinuz_target) if defined($vmlinuz_target); + + if (!defined($vmlinuz_target) || ! -f "$real_target") { + # what, a dangling symlink? + warn "The link " . $image_dest . "$kimage is a dangling link" . + "to $real_target\n"; + $force_move = 1; + return $force_move; + } + + + warn "DEBUG: The link $kimage points to ($vmlinuz_target)\n" if $DEBUG; + warn "DEBUG: ($vmlinuz_target) is really ($real_target)\n" if $DEBUG; + my $cwd; + chomp ($cwd=`pwd`); + if ($vmlinuz_target !~ m|^/|o) { + $vmlinuz_target = $cwd . "/" . $vmlinuz_target; + $vmlinuz_target =~ s|/+|/|o; + } + $vmlinuz_target = `readlink -q -m $vmlinuz_target`; + + if ("$vmlinuz_target" ne "$target") { + warn "DEBUG: We need to handle this.\n" if $DEBUG; + if ($minimal_swap) { + warn "DEBUG: Minimal swap.\n" if $DEBUG; + if (-l "$kimage.old") { + warn "DEBUG: There is an old link at $kimage.old\n" if $DEBUG; + my $old_target = readlink "$kimage.old"; + my $real_old_target = ''; + $real_old_target=abs_path($old_target) if defined ($old_target); + + if ($real_old_target && -f "$real_old_target") { + if ($old_target !~ m|^/|o) { + $old_target = $cwd . "/" . $old_target; + $old_target =~ s|/+|/|o; + } + $old_target = `readlink -q -m $old_target`; + if ("$old_target" ne "$target") { + $force_move = 1; + warn "DEBUG: Old link ($old_target) does not point to us ($target)\n" + if $DEBUG; + } + else { # The .old points to the current + warn "$kimage.old --> $target -- doing nothing"; + $force_move = 0; + } + } + else { + warn "DEBUG: Well, the old link does not exist -- so we move\n" + if $DEBUG; + $force_move = 1; + } + } + else { + warn "DEBUG: No .old link -- OK to move\n" + if $DEBUG; + $force_move = 1; + } + } + else { + warn "DEBUG: ok, minimal swap is no-- so we move.\n" + if $DEBUG; + $force_move = 1; + } + } + else { # already have proper link + warn "$kimage($vmlinuz_target) points to $target ($real_target) -- doing nothing"; + $force_move = 0; + } + return $force_move; +} + + +# This routine moves the symbolic link around (/vmlinuz -> /vmlinuz.old) +# It pays attention to whether we should the fact whether we should be using +# hard links or not. +sub really_move_link { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + warn "really_move_link: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + # don't clobber $kimage.old quite yet + rename("$kimage", "$kimage.$$") || + die "failed to move " . $image_dest . "$kimage:$!"; + warn "mv $kimage $kimage.$$" if $DEBUG; + my $Old = $src_dir; + my $cwd; + + chomp($cwd=`pwd`); + if (test_relative ('Old Dir' => $Old, 'New Dir' => $cwd, + 'Test File' => "$image_name")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$cwd" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + if ($use_hard_links =~ m/YES/i) { + warn "ln ${Old}${image_name} $kimage" if $DEBUG; + if (! link("${Old}${image_name}", "$kimage")) { + rename("$kimage.$$", "$kimage"); + die("Failed to link ${Old}${image_name} to " . + "${image_dest}${kimage}:$!"); + } + } + else { + warn "ln -s ${Old}${image_name} $kimage" if $DEBUG; + if (! symlink("${Old}${image_name}", "$kimage")) { + rename("$kimage.$$", "$kimage"); + die("Failed to symbolic-link ${Old}${image_name} to " . + "${image_dest}${kimage}:$!"); + } + } + + # Ok, now we may clobber the previous .old file + if (-l "$kimage.old" || ! -e "$kimage.old" ) { + rename("$kimage.$$", "$kimage.old"); + warn "mv $kimage.$$ $kimage.old" if $DEBUG; + } + else { + warn "$kimage.old is not a symlink, not clobbering\n"; + warn "rm $kimage.$$"; + unlink "$kimage.$$" if $DEBUG; + } +} + +# This routine handles a request to do symlinks, but there is no +# symlink file already there. Either we are supposed to use copy, or we are +# installing on a pristine system, or the user does not want symbolic links at +# all. We use a configuration file to tell the last two cases apart, creating +# a config file if needed. +sub handle_missing_link { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + warn "handle_missing_link: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + if ($no_symlink) { + warn "cp -a --backup=t $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("cp -a --backup=t " . $realimageloc . + "$image_name " . " $kimage"); + if ($ret) { + die("Failed to copy " . $realimageloc . "$image_name to " + . $image_dest . "$kimage"); + } + } + elsif ($reverse_symlink) { + warn "mv -f $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("mv -f " . $realimageloc . "$image_name " + . "$kimage"); + if ($ret) { + die("Failed to move " . $realimageloc . "$image_name to " + . $image_dest . "$kimage"); + } + } + else { + if (! $have_conffile) { + my $ret; + my $answer=''; + $do_symlink = "Yes"; + + if (open(CONF, ">$CONF_LOC")) { + print CONF "# Kernel Image management overrides\n"; + print CONF "# See kernel-img.conf(5) for details\n"; + if ($loader =~ /palo/i) { + print CONF "link_in_boot = Yes\n"; + print CONF "do_symlinks = Yes\n"; + print CONF "relative_links = Yes\n"; + print CONF "do_bootloader = No\n"; + } else { + print CONF "do_symlinks = $do_symlink\n"; + } + close CONF; + } + $have_conffile = "Yes"; + } + } + + if (! $no_symlink && $do_symlink =~ /Yes/i) { + my $Old = $realimageloc; + my $New = $image_dest; + my $Name = "$image_name"; + my $Link_Dest = "$kimage"; + + if ($reverse_symlink) { + $Old = $image_dest; + $New = $realimageloc; + $Name = "$kimage"; + $Link_Dest = $realimageloc . "$image_name"; + } + if (test_relative ('Old Dir' => $Old, + 'New Dir' => $New, + 'Test File' => $Name)) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$New" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + symlink($Old . "$Name", "$Link_Dest") || + die("Failed to symbolic-link ${Old}$Name to $Link_Dest:$!"); + warn "ln -s ${Old}$Name $Link_Dest" if $DEBUG; + + } +} + +# This routine handles the rest of the cases, where the user has requested +# non-traditional handling, like using cp, or reverse symlinks, or hard links. +sub handle_non_symlinks { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + warn "handle_non_link: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + # Save the current image. We do this in all four cases + rename("$kimage", "$kimage.$$") || + die "failed to move " . $image_dest . "$kimage:$!"; + warn "mv $kimage $kimage.$$" if $DEBUG; + + ##,#### + # case One + #`#### + if ($no_symlink) { + # Maybe /$image_dest is on a dos system? + warn "cp -a --backup=t $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("cp -a --backup=t " . $realimageloc + . "$image_name " . "$kimage"); + if ($ret) { + if (-e "$kimage.$$") { + rename("$kimage.$$", "$kimage"); + warn "mv $kimage.$$ $kimage" if $DEBUG; + } + die("Failed to copy " . $realimageloc . "$image_name to " + . $image_dest . "$kimage"); + } + } + ##,#### + # case Two + #`#### + elsif ($reverse_symlink) { # Maybe /$image_dest is on a dos system? + warn "mv -f $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("mv -f " . $realimageloc . "$image_name " + . $image_dest . "$kimage"); + if ($ret) { + if (-e "$kimage.$$") { + rename("$kimage.$$", "$kimage"); + warn "mv $kimage.$$ $kimage" if $DEBUG; + } + die("Failed to move " . $realimageloc . "$image_name to " + . $image_dest . "$kimage"); + } + my $Old = $image_dest; + if (test_relative ('Old Dir' => $Old, 'New Dir' => $realimageloc, + 'Test File' => "$kimage")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$realimageloc" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + if ($use_hard_links =~ m/YES/i) { + warn "ln " . $Old . "$kimage " . $realimageloc . "$image_name" if $DEBUG; + if (! link($Old . "$kimage", $realimageloc . "$image_name")) { + warn "Could not link " . $image_dest . + "$kimage to $image_name :$!"; + } + } + else { + warn "ln -s " . $Old . "$kimage " . $realimageloc . "$image_name" if $DEBUG; + if (! symlink($Old . "$kimage", $realimageloc . "$image_name")) { + warn "Could not symlink " . $image_dest . + "$kimage to $image_name :$!"; + } + } + } + ##,#### + # case Three + #`#### + elsif ($use_hard_links =~ m/YES/i ) { + # Ok then. this ought to be a hard link, and hence fair game + # don't clobber $kimage.old quite yet + my $Old = $realimageloc; + my $cwd; + chomp($cwd=`pwd`); + if (test_relative ('Old Dir' => $Old, 'New Dir' => $cwd, + 'Test File' => "$image_name")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$cwd" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + warn "ln " . $Old . "$image_name " . "$kimage" if $DEBUG; + if (! link($Old . "$image_name", "$kimage")) { + warn "mv $kimage.$$ $kimage" if $DEBUG; + rename("$kimage.$$", "$kimage"); + die("Failed to link " . $realimageloc . "$image_name to " + . $image_dest . "$kimage"); + } + } + ##,#### + # case Four + #`#### + else { + # We just use cp + warn "cp -a --backup=t $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("cp -a --backup=t " . $realimageloc + . "$image_name " . "$kimage"); + if ($ret) { + if (-e "$kimage.$$") { + warn "mv $kimage.$$ $kimage" if $DEBUG; + rename("$kimage.$$", "$kimage"); + } + die("Failed to copy " . $realimageloc . "$image_name to " + . $image_dest . "$kimage"); + } + } + # Ok, now we may clobber the previous .old file + warn "mv $kimage.$$ $kimage.old if -e $kimage.$$" if $DEBUG; + rename("$kimage.$$", "$kimage.old") if -e "$kimage.$$"; +} + +# This routine is responsible for setting up the symbolic links +# So, the actual kernel image lives in +# $realimageloc/$image_name (/boot/vmlinuz-2.6.12). +# This routine creates symbolic links in $image_dest/$kimage (/vmlinuz) +sub image_magic { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = "$kimage-$version"; + my $src_dir = $realimageloc; + warn "image_magic: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + # Well, in any case, if the destination (the symlink we are trying + # to create) is a directory, we should do nothing, except throw a + # diagnostic. + if (-d "$kimage" ) { + die ("Hmm. $kimage is a directory, which I did not expect. I am\n" . + "trying to create a symbolic link with that name linked to \n" . + "$image_dest . Since a directory exists here, my assumptions \n" . + "are way off, and I am aborting.\n" ); + exit (3); + } + + if ($move_image) { # Maybe $image_dest is in on dos, or something? + # source dir, link name, dest dir + really_move_image( $realimageloc, $image_name, $image_dest); + really_reverse_link($realimageloc, $image_name, $image_dest) + if $reverse_symlink; + return; + } + + if (-l "$kimage") { # There is a symbolic link + warn "DEBUG: There is a symlink for $kimage\n" if $DEBUG; + my $force_move = move_p($kimage, $image_dest, $image_name, $src_dir); + + if ($force_move) { + really_move_link($kimage, $image_dest, $image_name, $src_dir); + } + } + elsif (! -e "$kimage") { + # Hmm. Pristine system? How can that be? Installing from scratch? + # Or maybe the user does not want a symbolic link here. + # Possibly they do not want a link here. (we should be in / + # here[$image_dest, really] + handle_missing_link($kimage, $image_dest, $image_name, $src_dir); + } + elsif (-e "$kimage" ) { + # OK, $kimage exists -- but is not a link + handle_non_symlinks($kimage, $image_dest, $image_name, $src_dir); + } +} + +###################################################################### +###################################################################### +###################################################################### +###################################################################### + +# We may not have any modules installed +if ( -d "$modules_base/$version" ) { + print STDERR "Running depmod.\n"; + my $ret = system("depmod -a $version"); + if ($ret) { + print STDERR "Failed to run depmod\n"; + exit(1); + } +} + + + +sub find_initrd_tool { + my $hostversion = shift; + my $version = shift; + print STDERR "Finding valid ramdisk creators.\n"; + my @ramdisks = + grep { + my $args = + "$_ " . + "--supported-host-version=$hostversion " . + "--supported-target-version=$version " . + "1>/dev/null 2>&1" + ; + system($args) == 0; + } + split (/[:,\s]+/, $ramdisk); +} + +# The initrd symlink should probably be in the same dir that the +# symlinks are in +if ($initrd) { + my $success = 0; + + # Update-initramfs is called slightly different than mkinitrd and + # mkinitramfs. XXX It should really be made compatible with this stuff + # some how. + my $upgrading = 1; + if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m//og) { + $upgrading = 0; + } + my $ret = system("$ramdisk " . ($upgrading ? "-u" : "-c") . " -k " . $version . " >&2"); + $success = 1 unless $ret; + die "Failed to create initrd image.\n" unless $success; + if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m//og) { + image_magic("initrd.img", $image_dest); + } + else { + if (! -e "initrd.img") { + handle_missing_link("initrd.img", $image_dest, "initrd.img-$version", + $realimageloc); + } + else { + print STDERR + "Not updating initrd symbolic links since we are being updated/reinstalled \n"; + print STDERR + "($ARGV[1] was configured last, according to dpkg)\n"; + } + } + + if ($initrd && -l "initrd" ) { + unlink "initrd"; + } + + if ($initrd && -l "$image_dir/initrd" && ! $link_in_boot) { + unlink "$image_dir/initrd"; + } +} +else { # Not making an initrd emage + if (-l "initrd.img") { + # Ooh, last image was an initrd image? in any case, we should move it. + my $target = readlink "initrd.img"; + my $real_target = ''; + $real_target = abs_path($target) if defined ($target); + + if (!defined($target) || ! -f "$real_target") { + # Eh. dangling link. can safely be removed. + unlink("initrd.img"); + } else { + if (-l "initrd.img.old" || ! -e "initrd.img.old" ) { + rename("initrd.img", "initrd.img.old"); + } else { + warn "initrd.img.old is not a symlink, not clobbering\n"; + unlink("initrd.img"); + } + } + } +} + +# Warn of a reboot +if (-x $notifier) { + system($notifier); +} + +# Let programs know not to hibernate if the kernel that would be used for +# resume-from-hibernate is likely to differ from the currently running kernel. +system("mountpoint -q /var/run"); +if ($? eq 0) { + system("touch /var/run/do-not-hibernate"); +} + +# Only change the symlinks if we are not being upgraded +if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m//og) { + image_magic($kimage, $image_dest); +} +else { + if (! -e "$kimage") { + handle_missing_link($kimage, $image_dest, "$kimage-$version", + $realimageloc); + } + else { + print STDERR + "Not updating image symbolic links since we are being updated/reinstalled \n"; + print STDERR + "($ARGV[1] was configured last, according to dpkg)\n"; + } +} + +# We used to have System.* files in / +if (-e "/System.map" || -e "/System.old") { + unlink '/System.map' if -e '/System.map'; + unlink '/System.old' if -e '/System.old'; +} + +# creating some info about kernel and initrd +if ($DEBUG) { + my $ksize=sprintf("%.0f",(stat($realimageloc . + "$kimage-$version"))[7]/1024)."kB"; + my $initrdsize=''; + if ($initrd) { + $initrdsize=sprintf("%.0f",(stat($realimageloc . + "initrd.img-$version"))[7]/1024)."kB"; + } + + print STDERR <<"EOMSG"; +A new kernel image has been installed at $realimageloc$kimage-$version + (Size: $ksize) + +Symbolic links, unless otherwise specified, can be found in $image_dest + +EOMSG + ; + + if ($initrd) { + print STDERR <<"EOMSGA"; + + Initial rootdisk image: ${realimageloc}initrd.img-$version (Size: $initrdsize) +EOMSGA + ; + } +} + +# set the env var stem +$ENV{'STEM'} = "linux"; +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + +my $options; +for (@ARGV) { + s,','\\'',g; + $options .= " '$_'"; +} +$ENV{'DEB_MAINT_PARAMS'}="$options"; + +## Run user hook script here, if any +if ($postinst_hook) { + &run_hook("postinst", $postinst_hook); +} + +if (-d "/etc/kernel/postinst.d") { + print STDERR "Examining /etc/kernel/postinst.d.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postinst.d") && + die "Failed to process /etc/kernel/postinst.d"; +} + +if (-d "/etc/kernel/postinst.d/$version") { + print STDERR "Examining /etc/kernel/postinst.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postinst.d/$version") && + die "Failed to process /etc/kernel/postinst.d/$version"; +} + +LOADER: { + last unless $do_boot_enable; # Exit if explicitly asked to + + last if $loader =~ /silo/i; # SILO does not have to be executed. + last if $loader =~ /yaboot/i; # yaboot does not have to be executed. + last if $loader =~ /milo/i; # MILO does not have to be executed. + last if $loader =~ /nettrom/i; # NETTROM does not have to be executed. + last if $loader =~ /arcboot/i; # ARCBOOT does not have to be executed. + last if $loader =~ /delo/i; # DELO does not have to be executed. + last if $loader =~ /quik/i; # maintainer asked quik invocation to be ignored + + last unless $loaderloc; + last unless -x $loaderloc; + last unless $do_bootloader; + + if (-T "/etc/$loader.conf") { + # Trust and use the existing lilo.conf. + print STDERR "You already have a $Loader configuration in /etc/$loader.conf\n"; + my $ret = &run_lilo(); + exit $ret if $ret; + } +} + + +sub run_lilo (){ + my $ret; + # Try and figure out if the user really wants lilo to be run -- + # since the default is to run the boot laoder, which is ! grub -- but + # the user may be using grub now, and not changed the default. + + # So, if the user has explicitly asked for the loader to be run, or + # if there is no postinst hook, or if there is no grub installed -- + # we are OK. Or else, we ask. + if ($explicit_do_loader || (! ($postinst_hook && -x '/usr/sbin/grub'))) { + print STDERR "Running boot loader as requested\n"; + } else { + print STDERR "Ok, not running $loader\n"; + } + if ($loader =~ /^lilo/io or $loader =~ /vmelilo/io) { + print STDERR "Testing $loader.conf ... \n"; + unlink $temp_file_name; # security + $ret = system("$loaderloc -t >$temp_file_name 2>&1"); + if ($ret) { + print STDERR "Boot loader test failed\n"; + return $ret; + } + unlink "$temp_file_name"; + print STDERR "Testing successful.\n"; + print STDERR "Installing the "; + print STDERR "partition " if $loader =~ /^lilo/io; + print STDERR "boot sector... \n"; + } + + print STDERR "Running $loaderloc ... \n"; + if ($loader =~ /^elilo/io) { + $ret = system("$loaderloc 2>&1 | tee $temp_file_name"); + } else { + $ret = system("$loaderloc >$temp_file_name 2>&1"); + } + if ($ret) { + print STDERR "Boot loader failed to run\n"; + return $ret; + } + unlink $temp_file_name; + print STDERR "Installation successful.\n"; + return 0; +} + +exit 0; + +__END__ + --- linux-3.13.0.orig/debian/control-scripts/headers-postinst +++ linux-3.13.0/debian/control-scripts/headers-postinst @@ -0,0 +1,126 @@ +#!/usr/bin/perl +# -*- Mode: Cperl -*- +# debian.postinst --- +# Author : Manoj Srivastava ( srivasta@pilgrim.umass.edu ) +# Created On : Sat Apr 27 05:42:43 1996 +# Created On Node : melkor.pilgrim.umass.edu +# Last Modified By : Manoj Srivastava +# Last Modified On : Sat Aug 5 13:20:22 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 45 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# +# +# arch-tag: 1c716174-2f0a-476d-a626-a1322e62503a +# + + +$|=1; + +# Predefined values: +my $version = "=V"; +my $kimage = "=K"; +my $package_name = "linux-image-$version"; + + +# Ignore all invocations uxcept when called on to configure. +exit 0 unless ($ARGV[0] && $ARGV[0] =~ /configure/); + +#known variables +my $image_dest = "/"; +my $realimageloc = "/boot/"; +my $silent_modules = ''; +my $modules_base = '/lib/modules'; +my $CONF_LOC = '/etc/kernel-img.conf'; +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + +chdir '/usr/src' or die "Could not chdir to /usr/src:$!"; + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $header_postinst_hook = "$1" if /^\s*header_postinst_hook\s*=\s*(\S+)/ig; + } + close CONF; + } +} + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + +## Run user hook script here, if any +if (-x "$header_postinst_hook") { + &run_hook("postinst", $header_postinst_hook); +} + +if (-d "/etc/kernel/header_postinst.d") { + print STDERR "Examining /etc/kernel/header_postinst.d.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/header_postinst.d") && + die "Failed to process /etc/kernel/header_postinst.d"; +} + +if (-d "/etc/kernel/header_postinst.d/$version") { + print STDERR "Examining /etc/kernel/header_postinst.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/header_postinst.d/$version") && + die "Failed to process /etc/kernel/header_postinst.d/$version"; +} + +exit 0; + +__END__ --- linux-3.13.0.orig/debian/control-scripts/preinst +++ linux-3.13.0/debian/control-scripts/preinst @@ -0,0 +1,315 @@ +#! /usr/bin/perl +# -*- Mode: Cperl -*- +# image.preinst --- +# Author : Manoj Srivastava ( srivasta@tiamat.datasync.com ) +# Created On : Sun Jun 14 03:38:02 1998 +# Created On Node : tiamat.datasync.com +# Last Modified By : Manoj Srivastava +# Last Modified On : Sun Sep 24 14:04:42 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 99 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# + +# +#use strict; #for debugging + +use Debconf::Client::ConfModule qw(:all); +version('2.0'); +my $capb=capb("backup"); + +$|=1; + +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlink = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, nettrom + # or elilo +my $image_dir = "/boot"; # where the image is located +my $initrd = "YES"; # initrd kernel +my $use_hard_links = ''; # hardlinks do not wirk across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $relink_src_link = 'YES'; # There is no harm in checking the link +my $relink_build_link = 'YES'; # There is no harm in checking the link +my $force_build_link = ''; # There is no harm in checking the link +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; # List of tools to create initial ram fs. +my $package_name = "linux-image-$version"; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; + + +#known variables +my @boilerplate = (); +my @silotemplate = (); +my @quiktemplate = (); +my @palotemplate = (); +my @vmelilotemplate = (); +my $bootdevice = ''; +my $rootdevice = ''; +my $rootdisk = ''; +my $rootpartition = ''; +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $CONF_LOC = '/etc/kernel-img.conf'; +my $relative_links = ''; +my $silent_loader = ''; +my $warn_reboot = ''; # Warn that we are installing a version of + # the kernel we are running + +my $modules_base = '/lib/modules'; + +die "Pre inst Internal error. Aborting." unless $version; + +exit 0 if $ARGV[0] =~ /abort-upgrade/; +exit 1 unless $ARGV[0] =~ /(install|upgrade)/; + +$arch = `uname -i`; +if ($arch =~ m/86/) { + system ("grep -q ' pae ' /proc/cpuinfo"); + if ($?) { + print STDERR "This kernel does not support a non-PAE CPU.\n"; + exit 1; + } +} + +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlinks\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + $relink_src_link = '' if /^\s*relink_src_link\s*=\s*(no|false|0)\s*$/ig; + $relink_build_link = '' if /^\s*relink_build_link\s*=\s*(no|false|0)\s*$/ig; + $force_build_link = '' if /^\s*force_build_link\s*=\s*(no|false|0)\s*$/ig; + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + $relink_src_link = 'Yes' if /^\s*relink_src_link\s*=\s*(yes|true|1)\s*$/ig; + $relink_build_link = 'Yes' if /^\s*relink_build_link\s*=\s*(yes|true|1)\s*$/ig; + $force_build_link = 'Yes' if /^\s*force_build_link\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + $have_conffile = "Yes"; # stop perl complaining + } +} + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + +# About to upgrade this package from version $2 TO THIS VERSION. +# "prerm upgrade" has already been called for the old version of +# this package. + +sub find_initrd_tool { + my $hostversion = shift; + my $version = shift; + my @ramdisks = + grep { + my $args = + "$_ " . + "--supported-host-version=$hostversion " . + "--supported-target-version=$version " . + "1>/dev/null 2>&1" + ; + system($args) == 0; + } + split (/[:,\s]+/, $ramdisk); +} + +sub check { + my $version = shift; + my $lib_modules="$modules_base/$version"; + my $message = ''; + + if (-d "$lib_modules") { + opendir(DIR, $lib_modules) || die "can’t opendir $lib_modules: $!"; + my @children = readdir(DIR); + if ($#children > 1) { + my @dirs = grep { -d "$lib_modules/$_" } @children; + if ($#dirs > 1) { # we have subdirs + my $dir_message=''; + for my $dir (@dirs) { + if ($dir =~/kernel$/) { + $dir_message="An older install was detected.\n"; + } + else { + $dir_message="Module sub-directories were detected.\n" + unless $dir_message; + } + } + $message += $dir_message if $dir_message; + } + + my @links = grep { -l "$lib_modules/$_" } @children; + if ($#links > -1) { + my $links_message = ''; + for my $link (@links) { + next if ($link =~ /^build$/); + next if ($link =~ /^source$/); + $links_message = "Symbolic links were detected in $modules_base/$version.\n"; + } + $message += $links_message if $links_message; + } + my @files = grep { -f "$lib_modules/$_" } @children; + $message += "Additional files also exist in $modules_base/$version.\n" + if ($#files > -1); + } + } + else { $message .= "$lib_modules does not exist. ";} + return $message; +} + +if (-d "$modules_base/$version") { + my $errors=check($version); + warn "Info:\n$errors\n" if $errors; +} + +# set the env var stem +$ENV{'STEM'} = "linux"; + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + + +my $options; +for (@ARGV) { + s,','\\'',g; + $options .= " '$_'"; +} +$ENV{'DEB_MAINT_PARAMS'}="$options"; + +## Run user hook script here, if any +if (-x "$preinst_hook") { + &run_hook("preinst", $preinst_hook); +} +if (-d "/etc/kernel/preinst.d") { + print STDERR "Examining /etc/kernel/preinst.d/\n"; + system ("run-parts --verbose --exit-on-error --arg=$version" . + " --arg=$realimageloc$kimage-$version" . + " /etc/kernel/preinst.d") && + die "Failed to process /etc/kernel/preinst.d"; +} +if (-d "/etc/kernel/preinst.d/$version") { + print STDERR "Examining /etc/kernel/preinst.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version" . + " --arg=$realimageloc$kimage-$version" . + " /etc/kernel/preinst.d/$version") && + die "Failed to process /etc/kernel/preinst.d/$version"; +} +print STDERR "Done.\n"; + +exit 0; + +__END__ + + --- linux-3.13.0.orig/debian/rules.d/1-maintainer.mk +++ linux-3.13.0/debian/rules.d/1-maintainer.mk @@ -0,0 +1,127 @@ +# The following targets are for the maintainer only! do not run if you don't +# know what they do. + +.PHONY: printenv updateconfigs printchanges insertchanges startnewrelease diffupstream help updateportsconfigs editportsconfigs + +help: + @echo "These are the targets in addition to the normal $(DEBIAN) ones:" + @echo + @echo " printenv : Print some variables used in the build" + @echo + @echo " updateconfigs : Update core arch configs" + @echo + @echo " editconfigs : Update core arch configs interractively" + @echo " genconfigs : Generate core arch configs in CONFIGS/*" + @echo + @echo " updateportsconfigs : Update ports arch configs" + @echo + @echo " editportsconfigs : Update ports arch configs interactivly" + @echo " genportconfigs : Generate ports arch configs in CONFIGS/*" + @echo + @echo " printchanges : Print the current changelog entries (from git)" + @echo + @echo " insertchanges : Insert current changelog entries (from git)" + @echo + @echo " startnewrelease : Start a new changelog set" + @echo + @echo " diffupstream : Diff stock kernel code against upstream (git)" + @echo + @echo " help : If you are kernel hacking, you need the professional" + @echo " version of this" + @echo + @echo "Environment variables:" + @echo + @echo " NOKERNLOG : Do not add upstream kernel commits to changelog" + @echo " CONCURRENCY_LEVEL=X" + @echo " : Use -jX for kernel compile" + @echo " PRINTSHAS : Include SHAs for commits in changelog" + +printdebian: + @echo "$(DEBIAN)" + +updateconfigs defaultconfigs editconfigs genconfigs dumpconfigs: + dh_testdir; + $(SHELL) $(DROOT)/scripts/misc/kernelconfig $@ + rm -rf build + +updateportsconfigs defaultportsconfigs editportsconfigs genportsconfigs askconfigs: + dh_testdir; + $(SHELL) $(DROOT)/scripts/misc/kernelconfig $@ ports + rm -rf build + +printenv: + dh_testdir + @echo "src package name = $(src_pkg_name)" + @echo "release = $(release)" + @echo "revisions = $(revisions)" + @echo "revision = $(revision)" + @echo "uploadnum = $(uploadnum)" + @echo "prev_revisions = $(prev_revisions)" + @echo "prev_revision = $(prev_revision)" + @echo "abinum = $(abinum)" + @echo "gitver = $(gitver)" + @echo "flavours = $(flavours)" + @echo "skipabi = $(skipabi)" + @echo "skipmodule = $(skipmodule)" + @echo "skipdbg = $(skipdbg)" + @echo "ubuntu_log_opts = $(ubuntu_log_opts)" + @echo "CONCURRENCY_LEVEL = $(CONCURRENCY_LEVEL)" + @echo "bin package name = $(bin_pkg_name)" + @echo "hdr package name = $(hdrs_pkg_name)" + @echo "doc package name = $(doc_pkg_name)" + @echo "do_doc_package = $(do_doc_package)" + @echo "do_doc_package_content = $(do_doc_package_content)" + @echo "do_source_package = $(do_source_package)" + @echo "do_source_package_content = $(do_source_package_content)" + @echo "do_libc_dev_package = $(do_libc_dev_package)" + @echo "do_flavour_image_package = $(do_flavour_image_package)" + @echo "do_flavour_header_package = $(do_flavour_header_package)" + @echo "do_common_headers_indep = $(do_common_headers_indep)" + @echo "do_full_source = $(do_full_source)" + @echo "do_tools = $(do_tools)" + @echo "do_any_tools = $(do_any_tools)" + @echo "do_linux_tools = $(do_linux_tools)" + @echo " do_tools_cpupower = $(do_tools_cpupower)" + @echo " do_tools_perf = $(do_tools_perf)" + @echo " do_tools_x86 = $(do_tools_x86)" + @echo "do_cloud_tools = $(do_cloud_tools)" + @echo " do_tools_hyperv = $(do_tools_hyperv)" + @echo "full_build = $(full_build)" + @echo "libc_dev_version = $(libc_dev_version)" + @echo "DEB_HOST_GNU_TYPE = $(DEB_HOST_GNU_TYPE)" + @echo "DEB_BUILD_GNU_TYPE = $(DEB_BUILD_GNU_TYPE)" + @echo "DEB_HOST_ARCH = $(DEB_HOST_ARCH)" + @echo "DEB_BUILD_ARCH = $(DEB_BUILD_ARCH)" + @echo "arch = $(arch)" + @echo "kmake = $(kmake)" + +printchanges: + @baseCommit=$$(git log --pretty=format:'%H %s' | \ + gawk '/UBUNTU: '".*Ubuntu-$(prev_fullver)"'$$/ { print $$1; exit }'); \ + git log "$$baseCommit"..HEAD | \ + perl -w -f $(DROOT)/scripts/misc/git-ubuntu-log $(ubuntu_log_opts) + +insertchanges: + @perl -w -f $(DROOT)/scripts/misc/insert-changes.pl $(DROOT) $(DEBIAN) + +diffupstream: + @git diff-tree -p refs/remotes/linux-2.6/master..HEAD $(shell ls | grep -vE '^(ubuntu|$(DEBIAN)|\.git.*)') + +startnewrelease: + dh_testdir + @nextminor=$(shell expr `echo $(revision) | gawk -F. '{print $$2}'` + 1); \ + nextmajor=$(shell expr `echo $(revision) | awk -F. '{print $$1}'` + 1); \ + now="$(shell date -R)"; \ + echo "Creating new changelog set for $(release)-$$nextmajor.$$nextminor..."; \ + echo -e "$(src_pkg_name) ($(release)-$$nextmajor.$$nextminor) UNRELEASED; urgency=low\n" > $(DEBIAN)/changelog.new; \ + echo " CHANGELOG: Do not edit directly. Autogenerated at release." >> \ + $(DEBIAN)/changelog.new; \ + echo " CHANGELOG: Use the printchanges target to see the curent changes." \ + >> $(DEBIAN)/changelog.new; \ + echo " CHANGELOG: Use the insertchanges target to create the final log." \ + >> $(DEBIAN)/changelog.new; \ + echo -e "\n -- $$DEBFULLNAME <$$DEBEMAIL> $$now\n" >> \ + $(DEBIAN)/changelog.new ; \ + cat $(DEBIAN)/changelog >> $(DEBIAN)/changelog.new; \ + mv $(DEBIAN)/changelog.new $(DEBIAN)/changelog + --- linux-3.13.0.orig/debian/rules.d/2-binary-arch.mk +++ linux-3.13.0/debian/rules.d/2-binary-arch.mk @@ -0,0 +1,636 @@ +# We don't want make removing intermediary stamps +.SECONDARY : + +# Prepare the out-of-tree build directory +ifeq ($(do_full_source),true) +build_cd = cd $(builddir)/build-$*; # +build_O = +else +build_cd = +build_O = O=$(builddir)/build-$* +endif + +# Typically supplied from the arch makefile, e.g., debian.master/control.d/armhf.mk +ifneq ($(gcc),) +kmake += CC=$(CROSS_COMPILE)$(gcc) +endif + +$(stampdir)/stamp-prepare-%: config-prepare-check-% + @echo Debug: $@ + @touch $@ +$(stampdir)/stamp-prepare-tree-%: target_flavour = $* +$(stampdir)/stamp-prepare-tree-%: $(commonconfdir)/config.common.$(family) $(archconfdir)/config.common.$(arch) $(archconfdir)/config.flavour.% + @echo Debug: $@ + install -d $(builddir)/build-$* + touch $(builddir)/build-$*/ubuntu-build + [ "$(do_full_source)" != 'true' ] && true || \ + rsync -a --exclude debian --exclude debian.master --exclude $(DEBIAN) * $(builddir)/build-$* + cat $^ | sed -e 's/.*CONFIG_VERSION_SIGNATURE.*/CONFIG_VERSION_SIGNATURE="Ubuntu $(release)-$(revision)-$* $(raw_kernelversion)"/' > $(builddir)/build-$*/.config + find $(builddir)/build-$* -name "*.ko" | xargs rm -f + $(build_cd) $(kmake) $(build_O) -j1 silentoldconfig prepare scripts + touch $@ + +# Used by developers as a shortcut to prepare a tree for compilation. +prepare-%: $(stampdir)/stamp-prepare-% + @echo Debug: $@ +# Used by developers to allow efficient pre-building without fakeroot. +build-%: $(stampdir)/stamp-build-% + @echo Debug: $@ + +# Do the actual build, including image and modules +$(stampdir)/stamp-build-%: target_flavour = $* +$(stampdir)/stamp-build-%: bldimg = $(call custom_override,build_image,$*) +$(stampdir)/stamp-build-%: dtb_target = $(dtb_files_$*) +$(stampdir)/stamp-build-%: $(stampdir)/stamp-prepare-% + @echo Debug: $@ build_image $(build_image) bldimg $(bldimg) + $(build_cd) $(kmake) $(build_O) $(conc_level) $(bldimg) modules $(dtb_target) + @touch $@ + +# Install the finished build +install-%: pkgdir = $(CURDIR)/debian/$(bin_pkg_name)-$* +install-%: pkgdir_ex = $(CURDIR)/debian/$(extra_pkg_name)-$* +install-%: bindoc = $(pkgdir)/usr/share/doc/$(bin_pkg_name)-$* +install-%: dbgpkgdir = $(CURDIR)/debian/$(bin_pkg_name)-$*-dbgsym +install-%: signed = $(CURDIR)/debian/$(bin_pkg_name)-signed +install-%: toolspkgdir = $(CURDIR)/debian/$(tools_flavour_pkg_name)-$* +install-%: cloudpkgdir = $(CURDIR)/debian/$(cloud_flavour_pkg_name)-$* +install-%: basepkg = $(hdrs_pkg_name) +install-%: indeppkg = $(indep_hdrs_pkg_name) +install-%: kernfile = $(call custom_override,kernel_file,$*) +install-%: instfile = $(call custom_override,install_file,$*) +install-%: hdrdir = $(CURDIR)/debian/$(basepkg)-$*/usr/src/$(basepkg)-$* +install-%: target_flavour = $* +install-%: dtb_files = $(dtb_files_$*) +install-%: CONFIG_MODULE_SIG_HASH=sha512 +install-%: MODSECKEY=$(builddir)/build-$*/signing_key.priv +install-%: MODPUBKEY=$(builddir)/build-$*/signing_key.x509 +install-%: checks-% + @echo Debug: $@ kernel_file $(kernel_file) kernfile $(kernfile) install_file $(install_file) instfile $(instfile) + dh_testdir + dh_testroot + dh_clean -k -p$(bin_pkg_name)-$* + dh_clean -k -p$(hdrs_pkg_name)-$* +ifneq ($(skipdbg),true) + dh_clean -k -p$(dbg_pkg_name)-$* +endif + + # The main image + # compress_file logic required because not all architectures + # generate a zImage automatically out of the box +ifeq ($(compress_file),) + install -m600 -D $(builddir)/build-$*/$(kernfile) \ + $(pkgdir)/boot/$(instfile)-$(abi_release)-$* +else + install -d $(pkgdir)/boot + gzip -c9v $(builddir)/build-$*/$(kernfile) > \ + $(pkgdir)/boot/$(instfile)-$(abi_release)-$* + chmod 600 $(pkgdir)/boot/$(instfile)-$(abi_release)-$* +endif + +ifeq ($(uefi_signed),true) + install -d $(signed)/$(release)-$(revision) + # Check to see if this supports handoff, if not do not sign it. + # Check the identification area magic and version >= 0x020b + handoff=`dd if="$(pkgdir)/boot/$(instfile)-$(abi_release)-$*" bs=1 skip=514 count=6 2>/dev/null | od -s | gawk '($$1 == 0 && $$2 == 25672 && $$3 == 21362 && $$4 >= 523) { print "GOOD" }'`; \ + if [ "$$handoff" = "GOOD" ]; then \ + cp -p $(pkgdir)/boot/$(instfile)-$(abi_release)-$* \ + $(signed)/$(release)-$(revision)/$(instfile)-$(abi_release)-$*.efi; \ + fi +endif + + install -m644 $(builddir)/build-$*/.config \ + $(pkgdir)/boot/config-$(abi_release)-$* + install -m644 $(abidir)/$* \ + $(pkgdir)/boot/abi-$(abi_release)-$* + install -m600 $(builddir)/build-$*/System.map \ + $(pkgdir)/boot/System.map-$(abi_release)-$* + if [ "$(dtb_files)" ]; then \ + install -d $(pkgdir)/lib/firmware/$(abi_release)-$*/device-tree; \ + for dtb_file in $(dtb_files); do \ + install -m644 $(builddir)/build-$*/arch/$(build_arch)/boot/dts/$$dtb_file \ + $(pkgdir)/lib/firmware/$(abi_release)-$*/device-tree/$$dtb_file; \ + done \ + fi +ifeq ($(no_dumpfile),) + makedumpfile -g $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* \ + -x $(builddir)/build-$*/vmlinux + chmod 0600 $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* +endif + + $(build_cd) $(kmake) $(build_O) $(conc_level) modules_install \ + INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$(pkgdir)/ \ + INSTALL_FW_PATH=$(pkgdir)/lib/firmware/$(abi_release)-$* + +ifeq ($(do_extras_package),true) + # + # Remove all modules not in the inclusion list. + # + if [ -f $(DEBIAN)/control.d/$(target_flavour).inclusion-list ] ; then \ + mkdir -p $(pkgdir_ex)/lib/modules/$(abi_release)-$*; \ + mv $(pkgdir)/lib/modules/$(abi_release)-$*/kernel \ + $(pkgdir_ex)/lib/modules/$(abi_release)-$*/kernel; \ + $(SHELL) $(DROOT)/scripts/module-inclusion --master \ + $(pkgdir_ex)/lib/modules/$(abi_release)-$*/kernel \ + $(pkgdir)/lib/modules/$(abi_release)-$*/kernel \ + $(DEBIAN)/control.d/$(target_flavour).inclusion-list 2>&1 | \ + tee $(target_flavour).inclusion-list.log; \ + /sbin/depmod -b $(pkgdir) -ea -F $(pkgdir)/boot/System.map-$(abi_release)-$* \ + $(abi_release)-$* 2>&1 |tee $(target_flavour).depmod.log; \ + if [ `grep -c 'unknown symbol' $(target_flavour).depmod.log` -gt 0 ]; then \ + echo "EE: Unresolved module dependencies in base package!"; \ + exit 1; \ + fi \ + fi +endif + +ifeq ($(no_dumpfile),) + makedumpfile -g $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* \ + -x $(builddir)/build-$*/vmlinux + chmod 0600 $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* +endif + rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/build + rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/source + + # Some initramfs-tools specific modules + install -d $(pkgdir)/lib/modules/$(abi_release)-$*/initrd + if [ -f $(pkgdir)/lib/modules/$(abi_release)-$*/kernel/drivers/video/vesafb.ko ]; then\ + ln -f $(pkgdir)/lib/modules/$(abi_release)-$*/kernel/drivers/video/vesafb.ko \ + $(pkgdir)/lib/modules/$(abi_release)-$*/initrd/; \ + fi + + # Now the image scripts + install -d $(pkgdir)/DEBIAN + for script in postinst postrm preinst prerm; do \ + sed -e 's/=V/$(abi_release)-$*/g' -e 's/=K/$(instfile)/g' \ + -e 's/=L/$(loader)/g' -e 's@=B@$(build_arch)@g' \ + $(DROOT)/control-scripts/$$script > $(pkgdir)/DEBIAN/$$script; \ + chmod 755 $(pkgdir)/DEBIAN/$$script; \ + done +ifeq ($(do_extras_package),true) + # Install the postinit/postrm scripts in the extras package. + if [ -f $(DEBIAN)/control.d/$(target_flavour).inclusion-list ] ; then \ + install -d $(pkgdir_ex)/DEBIAN; \ + for script in postinst postrm ; do \ + sed -e 's/=V/$(abi_release)-$*/g' -e 's/=K/$(instfile)/g' \ + -e 's/=L/$(loader)/g' -e 's@=B@$(build_arch)@g' \ + debian/control-scripts/$$script > $(pkgdir_ex)/DEBIAN/$$script; \ + chmod 755 $(pkgdir_ex)/DEBIAN/$$script; \ + done; \ + fi +endif + + # Install the full changelog. +ifeq ($(do_doc_package),true) + install -d $(bindoc) + cat $(DEBIAN)/changelog $(DEBIAN)/changelog.historical | \ + gzip -9 >$(bindoc)/changelog.Debian.old.gz + chmod 644 $(bindoc)/changelog.Debian.old.gz +endif + +ifneq ($(skipsub),true) + for sub in $($(*)_sub); do \ + if ! (TO=$$sub FROM=$* ABI_RELEASE=$(abi_release) $(SHELL) \ + $(DROOT)/scripts/sub-flavour); then exit 1; fi; \ + /sbin/depmod -b debian/$(bin_pkg_name)-$$sub \ + -ea -F debian/$(bin_pkg_name)-$$sub/boot/System.map-$(abi_release)-$* \ + $(abi_release)-$*; \ + install -d debian/$(bin_pkg_name)-$$sub/DEBIAN; \ + for script in postinst postrm preinst prerm; do \ + sed -e 's/=V/$(abi_release)-$*/g' \ + -e 's/=K/$(instfile)/g' \ + -e 's/=L/$(loader)/g' \ + -e 's@=B@$(build_arch)@g' \ + $(DROOT)/control-scripts/$$script > \ + debian/$(bin_pkg_name)-$$sub/DEBIAN/$$script;\ + chmod 755 debian/$(bin_pkg_name)-$$sub/DEBIAN/$$script;\ + done; \ + done +endif + +ifneq ($(skipdbg),true) + # Debug image is simple + install -m644 -D $(builddir)/build-$*/vmlinux \ + $(dbgpkgdir)/usr/lib/debug/boot/vmlinux-$(abi_release)-$* + $(build_cd) $(kmake) $(build_O) modules_install \ + INSTALL_MOD_PATH=$(dbgpkgdir)/usr/lib/debug + # Add .gnu_debuglink sections to each stripped .ko + # pointing to unstripped verson + find $(pkgdir) -name '*.ko' | sed 's|$(pkgdir)||'| while read module ; do \ + if [[ -f "$(dbgpkgdir)/usr/lib/debug/$$module" ]] ; then \ + $(CROSS_COMPILE)objcopy \ + --add-gnu-debuglink=$(dbgpkgdir)/usr/lib/debug/$$module \ + $(pkgdir)/$$module; \ + scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODSECKEY) $(MODPUBKEY) \ + $(pkgdir)/$$module; \ + fi; \ + done + rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/build + rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/source + rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/modules.* + rm -fr $(dbgpkgdir)/usr/lib/debug/lib/firmware +endif + + # The flavour specific headers image + # TODO: Would be nice if we didn't have to dupe the original builddir + install -d -m755 $(hdrdir) + cat $(builddir)/build-$*/.config | \ + sed -e 's/.*CONFIG_DEBUG_INFO=.*/# CONFIG_DEBUG_INFO is not set/g' > \ + $(hdrdir)/.config + chmod 644 $(hdrdir)/.config + $(kmake) O=$(hdrdir) -j1 silentoldconfig prepare scripts + # We'll symlink this stuff + rm -f $(hdrdir)/Makefile + rm -rf $(hdrdir)/include2 $(hdrdir)/source + # Copy over the compilation version. + cp "$(builddir)/build-$*/include/generated/compile.h" \ + "$(hdrdir)/include/generated/compile.h" + # powerpc seems to need some .o files for external module linking. Add them in. +ifeq ($(arch),powerpc) + mkdir -p $(hdrdir)/arch/powerpc/lib + cp $(builddir)/build-$*/arch/powerpc/lib/*.o $(hdrdir)/arch/powerpc/lib +endif + # Script to symlink everything up + $(SHELL) $(DROOT)/scripts/link-headers "$(hdrdir)" "$(indeppkg)" "$*" + # The build symlink + install -d debian/$(basepkg)-$*/lib/modules/$(abi_release)-$* + ln -s /usr/src/$(basepkg)-$* \ + debian/$(basepkg)-$*/lib/modules/$(abi_release)-$*/build + # And finally the symvers + install -m644 $(builddir)/build-$*/Module.symvers \ + $(hdrdir)/Module.symvers + + # Now the header scripts + install -d $(CURDIR)/debian/$(basepkg)-$*/DEBIAN + for script in postinst; do \ + sed -e 's/=V/$(abi_release)-$*/g' -e 's/=K/$(instfile)/g' \ + $(DROOT)/control-scripts/headers-$$script > \ + $(CURDIR)/debian/$(basepkg)-$*/DEBIAN/$$script; \ + chmod 755 $(CURDIR)/debian/$(basepkg)-$*/DEBIAN/$$script; \ + done + + # At the end of the package prep, call the tests + DPKG_ARCH="$(arch)" KERN_ARCH="$(build_arch)" FLAVOUR="$*" \ + VERSION="$(abi_release)" REVISION="$(revision)" \ + PREV_REVISION="$(prev_revision)" ABI_NUM="$(abinum)" \ + PREV_ABI_NUM="$(prev_abinum)" BUILD_DIR="$(builddir)/build-$*" \ + INSTALL_DIR="$(pkgdir)" SOURCE_DIR="$(CURDIR)" \ + run-parts -v $(DROOT)/tests-build + + # + # Remove files which are generated at installation by postinst, + # except for modules.order and modules.builtin + # + # NOTE: need to keep this list in sync with postrm + # + mkdir $(pkgdir)/lib/modules/$(abi_release)-$*/_ + mv $(pkgdir)/lib/modules/$(abi_release)-$*/modules.order \ + $(pkgdir)/lib/modules/$(abi_release)-$*/_ + if [ -f $(pkgdir)/lib/modules/$(abi_release)-$*/modules.builtin ] ; then \ + mv $(pkgdir)/lib/modules/$(abi_release)-$*/modules.builtin \ + $(pkgdir)/lib/modules/$(abi_release)-$*/_; \ + fi + rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/modules.* + mv $(pkgdir)/lib/modules/$(abi_release)-$*/_/* \ + $(pkgdir)/lib/modules/$(abi_release)-$* + rmdir $(pkgdir)/lib/modules/$(abi_release)-$*/_ + +ifeq ($(do_linux_tools),true) + # Create the linux-tools tool links + install -d $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$* +ifeq ($(do_tools_cpupower),true) + ln -s ../../$(src_pkg_name)-tools-$(abi_release)/cpupower $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$* +endif +ifeq ($(do_tools_perf),true) + ln -s ../../$(src_pkg_name)-tools-$(abi_release)/perf $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$* +endif +ifeq ($(do_tools_x86),true) + ln -s ../../$(src_pkg_name)-tools-$(abi_release)/x86_energy_perf_policy $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$* + ln -s ../../$(src_pkg_name)-tools-$(abi_release)/turbostat $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$* +endif +endif +ifeq ($(do_cloud_tools),true) +ifeq ($(do_tools_hyperv),true) + # Create the linux-hyperv tool links + install -d $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$* + ln -s ../../$(src_pkg_name)-tools-$(abi_release)/hv_kvp_daemon $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$* + ln -s ../../$(src_pkg_name)-tools-$(abi_release)/hv_vss_daemon $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$* + ln -s ../../$(src_pkg_name)-tools-$(abi_release)/hv_fcopy_daemon $(cloudpkgdir)/usr/lib/linux-tools/$(abi_release)-$* +endif +endif + +headers_tmp := $(CURDIR)/debian/tmp-headers +headers_dir := $(CURDIR)/debian/linux-libc-dev + +hmake := $(MAKE) -C $(CURDIR) O=$(headers_tmp) \ + KERNELVERSION=$(abi_release) INSTALL_HDR_PATH=$(headers_tmp)/install \ + SHELL="$(SHELL)" ARCH=$(header_arch) + +install-arch-headers: + @echo Debug: $@ + dh_testdir + dh_testroot + dh_clean -k -plinux-libc-dev + + rm -rf $(headers_tmp) + install -d $(headers_tmp) $(headers_dir)/usr/include/ + + $(hmake) $(defconfig) + mv $(headers_tmp)/.config $(headers_tmp)/.config.old + sed -e 's/^# \(CONFIG_MODVERSIONS\) is not set$$/\1=y/' \ + -e 's/.*CONFIG_LOCALVERSION_AUTO.*/# CONFIG_LOCALVERSION_AUTO is not set/' \ + $(headers_tmp)/.config.old > $(headers_tmp)/.config + $(hmake) silentoldconfig + $(hmake) headers_install + + ( cd $(headers_tmp)/install/include/ && \ + find . -name '.' -o -name '.*' -prune -o -print | \ + cpio -pvd --preserve-modification-time \ + $(headers_dir)/usr/include/ ) + mkdir $(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH) + mv $(headers_dir)/usr/include/asm $(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH)/ + + rm -rf $(headers_tmp) + +binary-arch-headers: install-arch-headers + @echo Debug: $@ + dh_testdir + dh_testroot +ifeq ($(do_libc_dev_package),true) +ifneq ($(DEBIAN),debian.master) + echo "non-master branch building linux-libc-dev, aborting" + exit 1 +endif + dh_installchangelogs -plinux-libc-dev + dh_installdocs -plinux-libc-dev + dh_compress -plinux-libc-dev + dh_fixperms -plinux-libc-dev + dh_installdeb -plinux-libc-dev + $(lockme) dh_gencontrol -plinux-libc-dev -- $(libc_dev_version) + dh_md5sums -plinux-libc-dev + dh_builddeb -plinux-libc-dev +endif + +binary-%: pkgimg = $(bin_pkg_name)-$* +binary-%: pkgimg_ex = $(extra_pkg_name)-$* +binary-%: pkghdr = $(hdrs_pkg_name)-$* +binary-%: dbgpkg = $(bin_pkg_name)-$*-dbgsym +binary-%: dbgpkgdir = $(CURDIR)/debian/$(bin_pkg_name)-$*-dbgsym +binary-%: pkgtools = $(tools_flavour_pkg_name)-$* +binary-%: pkgcloud = $(cloud_flavour_pkg_name)-$* +binary-%: target_flavour = $* +binary-%: install-% + @echo Debug: $@ + dh_testdir + dh_testroot + + dh_installchangelogs -p$(pkgimg) + dh_installdocs -p$(pkgimg) + dh_compress -p$(pkgimg) + dh_fixperms -p$(pkgimg) -X/boot/ + dh_installdeb -p$(pkgimg) + dh_shlibdeps -p$(pkgimg) + $(lockme) dh_gencontrol -p$(pkgimg) + dh_md5sums -p$(pkgimg) + dh_builddeb -p$(pkgimg) -- -Zbzip2 -z9 + +ifeq ($(do_extras_package),true) + if [ -f $(DEBIAN)/control.d/$(target_flavour).inclusion-list ] ; then \ + dh_installchangelogs -p$(pkgimg_ex); \ + dh_installdocs -p$(pkgimg_ex); \ + dh_compress -p$(pkgimg_ex); \ + dh_fixperms -p$(pkgimg_ex) -X/boot/; \ + dh_installdeb -p$(pkgimg_ex); \ + dh_shlibdeps -p$(pkgimg_ex); \ + $(lockme) dh_gencontrol -p$(pkgimg_ex); \ + dh_md5sums -p$(pkgimg_ex); \ + dh_builddeb -p$(pkgimg_ex) -- -Zbzip2 -z9; \ + fi +endif + + dh_installchangelogs -p$(pkghdr) + dh_installdocs -p$(pkghdr) + dh_compress -p$(pkghdr) + dh_fixperms -p$(pkghdr) + dh_shlibdeps -p$(pkghdr) + dh_installdeb -p$(pkghdr) + $(lockme) dh_gencontrol -p$(pkghdr) + dh_md5sums -p$(pkghdr) + dh_builddeb -p$(pkghdr) + +ifneq ($(skipsub),true) + @set -e; for sub in $($(*)_sub); do \ + pkg=$(bin_pkg_name)-$$sub; \ + dh_installchangelogs -p$$pkg; \ + dh_installdocs -p$$pkg; \ + dh_compress -p$$pkg; \ + dh_fixperms -p$$pkg -X/boot/; \ + dh_shlibdeps -p$$pkg; \ + dh_installdeb -p$$pkg; \ + $(lockme) dh_gencontrol -p$$pkg; \ + dh_md5sums -p$$pkg; \ + dh_builddeb -p$$pkg; \ + done +endif + +ifneq ($(skipdbg),true) + dh_installchangelogs -p$(dbgpkg) + dh_installdocs -p$(dbgpkg) + dh_compress -p$(dbgpkg) + dh_fixperms -p$(dbgpkg) + dh_installdeb -p$(dbgpkg) + $(lockme) dh_gencontrol -p$(dbgpkg) + dh_md5sums -p$(dbgpkg) + dh_builddeb -p$(dbgpkg) + + # Hokay...here's where we do a little twiddling... + # Renaming the debug package prevents it from getting into + # the primary archive, and therefore prevents this very large + # package from being mirrored. It is instead, through some + # archive admin hackery, copied to http://ddebs.ubuntu.com. + # + mv ../$(dbgpkg)_$(release)-$(revision)_$(arch).deb \ + ../$(dbgpkg)_$(release)-$(revision)_$(arch).ddeb + set -e; \ + ( \ + $(lockme_cmd) 9 || exit 1; \ + if grep -qs '^Build-Debug-Symbols: yes$$' /CurrentlyBuilding; then \ + sed -i '/^$(dbgpkg)_/s/\.deb /.ddeb /' debian/files; \ + else \ + grep -v '^$(dbgpkg)_.*$$' debian/files > debian/files.new; \ + mv debian/files.new debian/files; \ + fi; \ + ) 9>$(lockme_file) + # Now, the package wont get into the archive, but it will get put + # into the debug system. +endif + +ifeq ($(do_linux_tools),true) + dh_installchangelogs -p$(pkgtools) + dh_installdocs -p$(pkgtools) + dh_compress -p$(pkgtools) + dh_fixperms -p$(pkgtools) + dh_shlibdeps -p$(pkgtools) + dh_installdeb -p$(pkgtools) + $(lockme) dh_gencontrol -p$(pkgtools) + dh_md5sums -p$(pkgtools) + dh_builddeb -p$(pkgtools) +endif +ifeq ($(do_cloud_tools),true) + dh_installchangelogs -p$(pkgcloud) + dh_installdocs -p$(pkgcloud) + dh_compress -p$(pkgcloud) + dh_fixperms -p$(pkgcloud) + dh_shlibdeps -p$(pkgcloud) + dh_installdeb -p$(pkgcloud) + $(lockme) dh_gencontrol -p$(pkgcloud) + dh_md5sums -p$(pkgcloud) + dh_builddeb -p$(pkgcloud) +endif + +ifneq ($(full_build),false) + # Clean out this flavours build directory. + rm -rf $(builddir)/build-$* + # Clean out the debugging package source directory. + rm -rf $(dbgpkgdir) +endif + +# +# per-architecture packages +# +builddirpa = $(builddir)/tools-perarch + +$(stampdir)/stamp-prepare-perarch: + @echo Debug: $@ +ifeq ($(do_any_tools),true) + rm -rf $(builddirpa) + install -d $(builddirpa) + for i in *; do ln -s $(CURDIR)/$$i $(builddirpa); done + rm $(builddirpa)/tools + rsync -a tools/ $(builddirpa)/tools/ +endif + touch $@ + +$(stampdir)/stamp-build-perarch: $(stampdir)/stamp-prepare-perarch install-arch-headers + @echo Debug: $@ +ifeq ($(do_linux_tools),true) +ifeq ($(do_tools_cpupower),true) + # Allow for multiple installed versions of cpupower and libcpupower.so: + # Override LIB_MIN in order to to generate a versioned .so named + # libcpupower.so.$(abi_release) and link cpupower with that. + make -C $(builddirpa)/tools/power/cpupower \ + CROSS_COMPILE=$(CROSS_COMPILE) \ + LIB_MIN=$(abi_release) CPUFREQ_BENCH=false +endif +ifeq ($(do_tools_perf),true) + cd $(builddirpa)/tools/perf && \ + make prefix=/usr HAVE_CPLUS_DEMANGLE=1 CROSS_COMPILE=$(CROSS_COMPILE) NO_LIBPYTHON=1 NO_LIBPERL=1 PYTHON=python2.7 +endif +ifeq ($(do_tools_x86),true) + cd $(builddirpa)/tools/power/x86/x86_energy_perf_policy && make CROSS_COMPILE=$(CROSS_COMPILE) + cd $(builddirpa)/tools/power/x86/turbostat && make CROSS_COMPILE=$(CROSS_COMPILE) +endif +endif +ifeq ($(do_cloud_tools),true) +ifeq ($(do_tools_hyperv),true) + cd $(builddirpa)/tools/hv && make CFLAGS="-I$(headers_dir)/usr/include -I$(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH)" CROSS_COMPILE=$(CROSS_COMPILE) hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon +endif +endif + @touch $@ + +install-perarch: toolspkgdir = $(CURDIR)/debian/$(tools_pkg_name) +install-perarch: cloudpkgdir = $(CURDIR)/debian/$(cloud_pkg_name) +install-perarch: $(stampdir)/stamp-build-perarch + @echo Debug: $@ + # Add the tools. +ifeq ($(do_linux_tools),true) + install -d $(toolspkgdir)/usr/lib + install -d $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) + +ifeq ($(do_tools_cpupower),true) + install -m755 $(builddirpa)/tools/power/cpupower/cpupower \ + $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) + # Install only the full versioned libcpupower.so.$(abi_release), not + # the usual symlinks to it. + install -m644 $(builddirpa)/tools/power/cpupower/libcpupower.so.$(abi_release) \ + $(toolspkgdir)/usr/lib/ +endif +ifeq ($(do_tools_perf),true) + install -m755 $(builddirpa)/tools/perf/perf $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) +endif +ifeq ($(do_tools_x86),true) + install -m755 $(builddirpa)/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy \ + $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) + install -m755 $(builddirpa)/tools/power/x86/turbostat/turbostat \ + $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) +endif +endif +ifeq ($(do_cloud_tools),true) +ifeq ($(do_tools_hyperv),true) + install -d $(cloudpkgdir)/usr/lib + install -d $(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) + install -m755 $(builddirpa)/tools/hv/hv_kvp_daemon \ + $(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) + install -m755 $(builddirpa)/tools/hv/hv_vss_daemon \ + $(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) + install -m755 $(builddirpa)/tools/hv/hv_fcopy_daemon \ + $(cloudpkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release) +endif +endif + +binary-perarch: toolspkg = $(tools_pkg_name) +binary-perarch: cloudpkg = $(cloud_pkg_name) +binary-perarch: install-perarch + @echo Debug: $@ +ifeq ($(do_linux_tools),true) + dh_strip -p$(toolspkg) + dh_installchangelogs -p$(toolspkg) + dh_installdocs -p$(toolspkg) + dh_compress -p$(toolspkg) + dh_fixperms -p$(toolspkg) + dh_shlibdeps -p$(toolspkg) + dh_installdeb -p$(toolspkg) + $(lockme) dh_gencontrol -p$(toolspkg) + dh_md5sums -p$(toolspkg) + dh_builddeb -p$(toolspkg) +endif +ifeq ($(do_cloud_tools),true) + dh_strip -p$(cloudpkg) + dh_installchangelogs -p$(cloudpkg) + dh_installdocs -p$(cloudpkg) + dh_compress -p$(cloudpkg) + dh_fixperms -p$(cloudpkg) + dh_shlibdeps -p$(cloudpkg) + dh_installdeb -p$(cloudpkg) + $(lockme) dh_gencontrol -p$(cloudpkg) + dh_md5sums -p$(cloudpkg) + dh_builddeb -p$(cloudpkg) +endif + +binary-debs: signed = $(CURDIR)/debian/$(bin_pkg_name)-signed +binary-debs: signedv = $(CURDIR)/debian/$(bin_pkg_name)-signed/$(release)-$(revision) +binary-debs: signed_tar = $(src_pkg_name)_$(release)-$(revision)_$(arch).tar.gz +binary-debs: binary-perarch $(addprefix binary-,$(flavours)) + @echo Debug: $@ +ifeq ($(uefi_signed),true) + echo $(release)-$(revision) > $(signedv)/version + cd $(signedv) && ls *.efi >flavours + cd $(signed) && tar czvf ../../../$(signed_tar) . + dpkg-distaddfile $(signed_tar) raw-uefi - +endif + +build-arch-deps-$(do_flavour_image_package) += $(addprefix $(stampdir)/stamp-build-,$(flavours)) +build-arch: $(build-arch-deps-true) + @echo Debug: $@ + +ifeq ($(AUTOBUILD),) +binary-arch-deps-$(do_flavour_image_package) += binary-udebs +else +binary-arch-deps-$(do_flavour_image_package) = binary-debs +endif +binary-arch-deps-$(do_libc_dev_package) += binary-arch-headers +ifneq ($(do_common_headers_indep),true) +binary-arch-deps-$(do_flavour_header_package) += binary-headers +endif +binary-arch: $(binary-arch-deps-true) + @echo Debug: $@ + --- linux-3.13.0.orig/debian/rules.d/4-checks.mk +++ linux-3.13.0/debian/rules.d/4-checks.mk @@ -0,0 +1,27 @@ +# Check ABI for package against last release (if not same abinum) +abi-check-%: $(stampdir)/stamp-build-% + @echo Debug: $@ + install -d $(abidir) + sed -e 's/^\(.\+\)[[:space:]]\+\(.\+\)[[:space:]]\(.\+\)$$/\3 \2 \1/' \ + $(builddir)/build-$*/Module.symvers | sort > $(abidir)/$* + @perl -f $(DROOT)/scripts/abi-check "$*" "$(prev_abinum)" "$(abinum)" \ + "$(prev_abidir)" "$(abidir)" "$(skipabi)" + +# Check the module list against the last release (always) +module-check-%: $(stampdir)/stamp-build-% + @echo Debug: $@ + install -d $(abidir) + find $(builddir)/build-$*/ -name \*.ko | \ + sed -e 's/.*\/\([^\/]*\)\.ko/\1/' | sort > $(abidir)/$*.modules + @perl -f $(DROOT)/scripts/module-check "$*" \ + "$(prev_abidir)" "$(abidir)" $(skipmodule) + +checks-%: module-check-% abi-check-% + @echo Debug: $@ + +# Check the config against the known options list. +config-prepare-check-%: $(stampdir)/stamp-prepare-tree-% + @echo Debug: $@ + @perl -f $(DROOT)/scripts/config-check \ + $(builddir)/build-$*/.config "$(arch)" "$*" "$(sharedconfdir)" "$(skipconfig)" + --- linux-3.13.0.orig/debian/rules.d/3-binary-indep.mk +++ linux-3.13.0/debian/rules.d/3-binary-indep.mk @@ -0,0 +1,163 @@ +build-indep: + @echo Debug: $@ + +# The binary-indep dependency chain is: +# +# install-headers <- install-doc <- install-source <- install-tools <- install-indep <- binary-indep +# install-headers <- binary-headers +# +indep_hdrpkg = $(indep_hdrs_pkg_name) +indep_hdrdir = $(CURDIR)/debian/$(indep_hdrpkg)/usr/src/$(indep_hdrpkg) +install-headers: + @echo Debug: $@ + dh_testdir + dh_testroot + dh_prep + +ifeq ($(do_flavour_header_package),true) + install -d $(indep_hdrdir) + find . -path './debian' -prune -o -path './$(DEBIAN)' -prune \ + -o -path './include/*' -prune \ + -o -path './scripts/*' -prune -o -type f \ + \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) \ + -print | cpio -pd --preserve-modification-time $(indep_hdrdir) + cp -a scripts include $(indep_hdrdir) + (find arch -name include -type d -print | \ + xargs -n1 -i: find : -type f) | \ + cpio -pd --preserve-modification-time $(indep_hdrdir) +endif + +docpkg = $(doc_pkg_name) +docdir = $(CURDIR)/debian/$(docpkg)/usr/share/doc/$(docpkg) +install-doc: install-headers + @echo Debug: $@ +ifeq ($(do_doc_package),true) + dh_testdir + dh_testroot + + install -d $(docdir) +ifeq ($(do_doc_package_content),true) + # First the html docs. We skip these for autobuilds + if [ -z "$(AUTOBUILD)" ]; then \ + install -d $(docdir)/$(doc_pkg_name)-tmp; \ + $(kmake) O=$(docdir)/$(doc_pkg_name)-tmp htmldocs; \ + mv $(docdir)/$(doc_pkg_name)-tmp/Documentation/DocBook \ + $(docdir)/html; \ + rm -rf $(docdir)/$(doc_pkg_name)-tmp; \ + fi +endif + # Copy the rest + cp -a Documentation/* $(docdir) + rm -rf $(docdir)/DocBook + find $(docdir) -name .gitignore | xargs rm -f +endif + +srcpkg = $(src_pkg_name)-source-$(release) +srcdir = $(CURDIR)/debian/$(srcpkg)/usr/src/$(srcpkg) +balldir = $(CURDIR)/debian/$(srcpkg)/usr/src/$(srcpkg)/$(srcpkg) +install-source: install-doc + @echo Debug: $@ +ifeq ($(do_source_package),true) + + install -d $(srcdir) +ifeq ($(do_source_package_content),true) + find . -path './debian' -prune -o -path './$(DEBIAN)' -prune -o \ + -path './.*' -prune -o -print | \ + cpio -pd --preserve-modification-time $(balldir) + (cd $(srcdir); tar cf - $(srcpkg)) | bzip2 -9c > \ + $(srcdir)/$(srcpkg).tar.bz2 + rm -rf $(balldir) + find './debian' './$(DEBIAN)' \ + -path './debian/linux-*' -prune -o \ + -path './debian/$(src_pkg_name)-*' -prune -o \ + -path './debian/build' -prune -o \ + -path './debian/files' -prune -o \ + -path './debian/stamps' -prune -o \ + -path './debian/tmp' -prune -o \ + -print | \ + cpio -pd --preserve-modification-time $(srcdir) + ln -s $(srcpkg)/$(srcpkg).tar.bz2 $(srcdir)/.. +endif +endif + +install-tools: toolspkg = $(tools_common_pkg_name) +install-tools: toolsbin = $(CURDIR)/debian/$(toolspkg)/usr/bin +install-tools: toolssbin = $(CURDIR)/debian/$(toolspkg)/usr/sbin +install-tools: toolsman = $(CURDIR)/debian/$(toolspkg)/usr/share/man +install-tools: cloudpkg = $(cloud_common_pkg_name) +install-tools: cloudbin = $(CURDIR)/debian/$(cloudpkg)/usr/bin +install-tools: cloudsbin = $(CURDIR)/debian/$(cloudpkg)/usr/sbin +install-tools: cloudman = $(CURDIR)/debian/$(cloudpkg)/usr/share/man +install-tools: install-source $(stampdir)/stamp-build-perarch + @echo Debug: $@ + + rm -rf $(builddir)/tools + install -d $(builddir)/tools + for i in *; do ln -s $(CURDIR)/$$i $(builddir)/tools/; done + rm $(builddir)/tools/tools + rsync -a tools/ $(builddir)/tools/tools/ + + install -d $(toolsbin) + install -d $(toolsman)/man1 + + install -m755 debian/tools/generic $(toolsbin)/cpupower + install -m644 $(CURDIR)/tools/power/cpupower/man/*.1 $(toolsman)/man1/ + + install -m755 debian/tools/generic $(toolsbin)/perf + + install -m755 debian/tools/generic $(toolsbin)/x86_energy_perf_policy + install -m755 debian/tools/generic $(toolsbin)/turbostat + + cd $(builddir)/tools/tools/perf && make man + install -m644 $(builddir)/tools/tools/perf/Documentation/*.1 \ + $(toolsman)/man1 + + install -d $(toolsman)/man8 + install -m644 $(CURDIR)/tools/power/x86/x86_energy_perf_policy/*.8 $(toolsman)/man8 + install -m644 $(CURDIR)/tools/power/x86/turbostat/*.8 $(toolsman)/man8 + + install -d $(cloudsbin) + install -m755 debian/tools/generic $(cloudsbin)/hv_kvp_daemon + install -m755 debian/tools/generic $(cloudsbin)/hv_vss_daemon + install -m755 debian/tools/generic $(cloudsbin)/hv_fcopy_daemon + install -m755 debian/cloud-tools/hv_get_dhcp_info $(cloudsbin) + install -m755 debian/cloud-tools/hv_get_dns_info $(cloudsbin) + install -m755 debian/cloud-tools/hv_set_ifconfig $(cloudsbin) + + install -d $(cloudman)/man8 + install -m644 $(CURDIR)/tools/hv/*.8 $(cloudman)/man8 + + dh_installinit -p$(cloudpkg) --name hv-kvp-daemon + dh_installinit -p$(cloudpkg) --name hv-vss-daemon + dh_installinit -p$(cloudpkg) --name hv-fcopy-daemon + + + +install-indep: install-tools + @echo Debug: $@ + +# This is just to make it easy to call manually. Normally done in +# binary-indep target during builds. +binary-headers: install-headers + @echo Debug: $@ + dh_installchangelogs -p$(indep_hdrpkg) + dh_installdocs -p$(indep_hdrpkg) + dh_compress -p$(indep_hdrpkg) + dh_fixperms -p$(indep_hdrpkg) + dh_installdeb -p$(indep_hdrpkg) + $(lockme) dh_gencontrol -p$(indep_hdrpkg) + dh_md5sums -p$(indep_hdrpkg) + dh_builddeb -p$(indep_hdrpkg) + +binary-indep: install-indep + @echo Debug: $@ + + dh_installchangelogs -i + dh_installdocs -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + $(lockme) dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i --- linux-3.13.0.orig/debian/rules.d/0-common-vars.mk +++ linux-3.13.0/debian/rules.d/0-common-vars.mk @@ -0,0 +1,235 @@ +# +# The source package name will be the first token from $(DEBIAN)/changelog +# +src_pkg_name=$(shell sed -n '1s/^\(.*\) (.*).*$$/\1/p' $(DEBIAN)/changelog) + +# Get some version info +release := $(shell sed -n '1s/^$(src_pkg_name).*(\(.*\)-.*).*$$/\1/p' $(DEBIAN)/changelog) +revisions := $(shell sed -n 's/^$(src_pkg_name)\ .*($(release)-\(.*\)).*$$/\1/p' $(DEBIAN)/changelog | tac) +revision ?= $(word $(words $(revisions)),$(revisions)) +prev_revisions := $(filter-out $(revision),0.0 $(revisions)) +prev_revision := $(word $(words $(prev_revisions)),$(prev_revisions)) + +prev_fullver ?= $(shell dpkg-parsechangelog -l$(DEBIAN)/changelog -o1 -c1 | sed -ne 's/^Version: *//p') + +family=ubuntu + +# This is an internally used mechanism for the daily kernel builds. It +# creates packages whose ABI is suffixed with a minimal representation of +# the current git HEAD sha. If .git/HEAD is not present, then it uses the +# uuidgen program, +# +# AUTOBUILD can also be used by anyone wanting to build a custom kernel +# image, or rebuild the entire set of Ubuntu packages using custom patches +# or configs. +AUTOBUILD= + +ifneq ($(AUTOBUILD),) +skipabi = true +skipmodule = true +skipdbg = true +gitver=$(shell if test -f .git/HEAD; then cat .git/HEAD; else uuidgen; fi) +gitverpre=$(shell echo $(gitver) | cut -b -3) +gitverpost=$(shell echo $(gitver) | cut -b 38-40) +abi_suffix = -$(gitverpre)$(gitverpost) +endif + +ifneq ($(NOKERNLOG),) +ubuntu_log_opts += --no-kern-log +endif +ifneq ($(PRINTSHAS),) +ubuntu_log_opts += --print-shas +endif + +# Get the kernels own extra version to be added to the release signature. +raw_kernelversion=$(shell make kernelversion) + +# +# full_build -- are we doing a full buildd style build +# +ifeq ($(wildcard /CurrentlyBuilding),) +full_build?=false +else +full_build?=true +endif + +# +# The debug packages are ginormous, so you probably want to skip +# building them (as a developer). +# +ifeq ($(full_build),false) +skipdbg=true +endif + +abinum := $(shell echo $(revision) | sed -e 's/\..*//')$(abi_suffix) +prev_abinum := $(shell echo $(prev_revision) | sed -e 's/\..*//')$(abi_suffix) +abi_release := $(release)-$(abinum) + +uploadnum := $(shell echo $(revision) | sed -e 's/.*\.//') +ifneq ($(full_build),false) + uploadnum := $(uploadnum)-Ubuntu +endif + +# XXX: linux-libc-dev got bumped to -803.N inadvertantly by a ti-omap4 upload +# shift our version higher for this package only. Ensure this only +# occurs for the v2.6.35 kernel so that we do not propogate this into +# any other series. +raw_uploadnum := $(shell echo $(revision) | sed -e 's/.*\.//') +libc_dev_version := +ifeq ($(DEBIAN),debian.master) +ifeq ($(release),2.6.35) +libc_dev_version := -v$(release)-$(shell expr "$(abinum)" + 1000).$(raw_uploadnum) +endif +endif + +DEB_HOST_MULTIARCH = $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) +DEB_HOST_GNU_TYPE = $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE = $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_HOST_ARCH = $(shell dpkg-architecture -qDEB_HOST_ARCH) +DEB_BUILD_ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH) + +# +# Detect invocations of the form 'fakeroot debian/rules binary arch=armhf' +# within an x86'en schroot. This only gets you part of the way since the +# packaging phase fails, but you can at least compile the kernel quickly. +# +arch := $(DEB_HOST_ARCH) +ifneq ($(arch),$(DEB_HOST_ARCH)) + CROSS_COMPILE ?= $(shell dpkg-architecture -a$(arch) -qDEB_HOST_GNU_TYPE -f 2>/dev/null)- +endif + +# +# Detect invocations of the form 'dpkg-buildpackage -B -aarmhf' within +# an x86'en schroot. This is the only way to build all of the packages +# (except for tools). +# +ifneq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) + CROSS_COMPILE ?= $(DEB_HOST_GNU_TYPE)- +endif + +abidir := $(CURDIR)/$(DEBIAN)/abi/$(release)-$(revision)/$(arch) +prev_abidir := $(CURDIR)/$(DEBIAN)/abi/$(release)-$(prev_revision)/$(arch) +commonconfdir := $(CURDIR)/$(DEBIAN)/config +archconfdir := $(CURDIR)/$(DEBIAN)/config/$(arch) +sharedconfdir := $(CURDIR)/debian.master/config +builddir := $(CURDIR)/debian/build +stampdir := $(CURDIR)/debian/stamps + +# +# The binary package name always starts with linux-image-$KVER-$ABI.$UPLOAD_NUM. There +# are places that you'll find linux-image hard coded, but I guess thats OK since the +# assumption that the binary package always starts with linux-image will never change. +# +bin_pkg_name=linux-image-$(abi_release) +extra_pkg_name=linux-image-extra-$(abi_release) +hdrs_pkg_name=linux-headers-$(abi_release) +indep_hdrs_pkg_name=linux-headers-$(abi_release) + +# +# The generation of content in the doc package depends on both 'AUTOBUILD=' and +# 'do_doc_package_content=true'. There are usually build errors during the development +# cycle, so its OK to leave 'do_doc_package_content=false' until those build +# failures get sorted out. Finally, the doc package doesn't really need to be built +# for developer testing (its kind of slow), so only do it if on a buildd. +do_doc_package=true +do_doc_package_content=true +ifeq ($(full_build),false) +do_doc_package_content=false +endif +doc_pkg_name=$(src_pkg_name)-doc + +# +# Similarly with the linux-source package, you need not build it as a developer. Its +# somewhat I/O intensive and utterly useless. +# +do_source_package=true +do_source_package_content=true +ifeq ($(full_build),false) +do_source_package_content=false +endif + +# linux-libc-dev may not be needed, default to building it. +do_libc_dev_package=true + +# common headers normally is built as an indep package, but may be arch +do_common_headers_indep=true + +# add a 'full source' mode +do_full_source=false + +# build tools +ifneq ($(wildcard $(CURDIR)/tools),) + ifeq ($(do_tools),) + ifneq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) + do_tools=false + endif + endif + do_tools?=true +else + do_tools?=false +endif +tools_pkg_name=$(src_pkg_name)-tools-$(abi_release) +tools_common_pkg_name=$(src_pkg_name)-tools-common +tools_flavour_pkg_name=linux-tools-$(abi_release) +cloud_pkg_name=$(src_pkg_name)-cloud-tools-$(abi_release) +cloud_common_pkg_name=$(src_pkg_name)-cloud-tools-common +cloud_flavour_pkg_name=linux-cloud-tools-$(abi_release) + +# The general flavour specific image package. +do_flavour_image_package=true + +# The general flavour specific header package. +do_flavour_header_package=true + +# Support parallel= in DEB_BUILD_OPTIONS (see #209008) +# +# These 2 environment variables set the -j value of the kernel build. For example, +# CONCURRENCY_LEVEL=16 fakeroot $(DEBIAN)/rules binary-debs +# or +# DEB_BUILD_OPTIONS=parallel=16 fakeroot $(DEBIAN)/rules binary-debs +# +# The default is to use the number of CPUs. +# +COMMA=, +DEB_BUILD_OPTIONS_PARA = $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) +ifneq (,$(DEB_BUILD_OPTIONS_PARA)) + CONCURRENCY_LEVEL := $(DEB_BUILD_OPTIONS_PARA) +endif + +ifeq ($(CONCURRENCY_LEVEL),) + # Check the environment + CONCURRENCY_LEVEL := $(shell echo $$CONCURRENCY_LEVEL) + # No? Then build with the number of CPUs on the host. + ifeq ($(CONCURRENCY_LEVEL),) + CONCURRENCY_LEVEL := $(shell expr `getconf _NPROCESSORS_ONLN` \* 1) + endif + # Oh hell, give 'em one + ifeq ($(CONCURRENCY_LEVEL),) + CONCURRENCY_LEVEL := 1 + endif +endif + +conc_level = -j$(CONCURRENCY_LEVEL) + +# target_flavour is filled in for each step +kmake = make ARCH=$(build_arch) \ + CROSS_COMPILE=$(CROSS_COMPILE) \ + KERNELVERSION=$(abi_release)-$(target_flavour) \ + CONFIG_DEBUG_SECTION_MISMATCH=y \ + KBUILD_BUILD_VERSION="$(uploadnum)" \ + LOCALVERSION= localver-extra= \ + CFLAGS_MODULE="-DPKG_ABI=$(abinum)" +ifneq ($(LOCAL_ENV_CC),) +kmake += CC=$(LOCAL_ENV_CC) DISTCC_HOSTS=$(LOCAL_ENV_DISTCC_HOSTS) +endif + +# Locking is required in parallel builds to prevent loss of contents +# of the debian/files. +lockme_file = $(CURDIR)/debian/.LOCK +lockme_cmd = flock -w 60 +lockme = $(lockme_cmd) $(lockme_file) + +# Checks if a var is overriden by the custom rules. Called with var and +# flavour as arguments. +custom_override = \ + $(shell if [ -n "$($(1)_$(2))" ]; then echo "$($(1)_$(2))"; else echo "$($(1))"; fi) --- linux-3.13.0.orig/debian/rules.d/5-udebs.mk +++ linux-3.13.0/debian/rules.d/5-udebs.mk @@ -0,0 +1,74 @@ +# Do udebs if not disabled in the arch-specific makefile +binary-udebs: binary-debs + @echo Debug: $@ +ifeq ($(disable_d_i),) + @$(MAKE) --no-print-directory -f $(DROOT)/rules DEBIAN=$(DEBIAN) \ + do-binary-udebs +endif + +do-binary-udebs: debian/control + @echo Debug: $@ + dh_testdir + dh_testroot + + # unpack the kernels into a temporary directory + mkdir -p debian/d-i-${arch} + + imagelist=$$(cat $(builddir)/kernel-versions | grep ^${arch} | gawk '{print $$4}') && \ + for i in $$imagelist; do \ + dpkg -x $$(ls ../linux-image-$$i\_$(release)-$(revision)_${arch}.deb) \ + debian/d-i-${arch}; \ + if [ -f ../linux-image-extra-$$i\_$(release)-$(revision)_${arch}.deb ] ; then \ + dpkg -x ../linux-image-extra-$$i\_$(release)-$(revision)_${arch}.deb \ + debian/d-i-${arch}; \ + fi; \ + /sbin/depmod -b debian/d-i-${arch} $$i; \ + done + + # kernel-wedge will error if no modules unless this is touched + touch $(CURDIR)/debian/build/no-modules + + touch ignore-dups + export SOURCEDIR=$(CURDIR)/debian/d-i-${arch} && \ + cd $(builddir) && \ + kernel-wedge install-files && \ + kernel-wedge check + + # Build just the udebs + dilist=$$(dh_listpackages -s | grep "\-di$$") && \ + [ -z "$dilist" ] || \ + for i in $$dilist; do \ + dh_fixperms -p$$i; \ + $(lockme) dh_gencontrol -p$$i; \ + dh_builddeb -p$$i; \ + done + + # Generate the meta-udeb dependancy lists. + @gawk ' \ + /^Package:/ { \ + package=$$2; flavour=""; parch="" } \ + (/Package-Type: udeb/ && package !~ /^'$(src_pkg_name)'-udebs-/) { \ + match(package, "'$(release)'-'$(abinum)'-(.*)-di", bits); \ + flavour = bits[1]; \ + } \ + (/^Architecture:/ && $$0 " " ~ / '$(arch)'/) { \ + parch=$$0; \ + } \ + (flavour != "" && parch != "") { \ + udebs[flavour] = udebs[flavour] package ", "; \ + flavour=""; parch=""; \ + } \ + END { \ + for (flavour in udebs) { \ + package="'$(src_pkg_name)'-udebs-" flavour; \ + file="debian/" package ".substvars"; \ + print("udeb:Depends=" udebs[flavour]) > file; \ + metas="'$(builddir)'/udeb-meta-packages"; \ + print(package) >metas \ + } \ + } \ + ' <$(CURDIR)/debian/control + @while read i; do \ + $(lockme) dh_gencontrol -p$$i; \ + dh_builddeb -p$$i; \ + done <$(builddir)/udeb-meta-packages --- linux-3.13.0.orig/debian/stamps/keep-dir +++ linux-3.13.0/debian/stamps/keep-dir @@ -0,0 +1 @@ +Place holder --- linux-3.13.0.orig/debian/docs/README.inclusion-list +++ linux-3.13.0/debian/docs/README.inclusion-list @@ -0,0 +1,51 @@ +This README describes the reason for, and the use of, module +inclusion lists. + +The original Hardy release had the notion of sub-flavours, +e.g., a flavour that was constructed as a subset of an existing flavour. +For example, the virtual flavour was extracted from the server flavour using +a subset of the server flavour modules. However, there were some difficult +mainteneance issues with regard to packaging, make rules, and scripts. This +re-implementation of the sub-flavours philosophy is hopefully simpler, +and retrofitable to all releases. + +A module inclusion list looks at the problem of of constructing a package +from the perspective of what modules do we _want_ in the package, as opposed +to what modules we _don't_ want. As the kernel matures, more and more devices are added +which makes the problem of configuration maintenance a real pain in the ass. +If we took the approach of disabling all of the config options that we don't want, +then the differences between flavours will quickly become quite large, making +it difficult to quickly compare the individual flavour configs. Each time a +new config option is added then we also have to make a decision about disabling in +order to continue to keep the minimal number of modules. + +A module inclusion list is applied on a per-flavour basis. For example, +debian./control.d/${flavour}.inclusion-list. For example, the +config for virtual is very close to server and generic, but the inclusion list +causes the virtual package to be constructed with _only_ the modules described +in the inclusion list. + +The inclusion list format is a simple bash regular expression list of files. For example, + +arch/*/{crypto,kernel,oprofile} +drivers/acpi/* +drivers/ata/ahci.ko + +These 3 regular expression forms are suitable for expansion by bash and as inputs to 'find'. +See debian/scripts/module-inclusion for details. + +There are 2 log files created as a side effect of the application of the module +inclusion list; $(flavour).inclusion-list.log and $(flavour).depmod.log. + +$(flavour).inclusion-list.log : This log is created while the inclusion list +modules are being copied. If any are missing, then those warnings go in this log. +While its not considered a fatal error, you should endevour to correct your inclusion +list such that there are no missing modules. + +$(flavour).depmod.log : The log is created as a result of running depmod on the +resulting set of modules. If there are missing symbols then you'll find that information +here. Again, you should modify your inclusion list such that there are no missing +symbols. + +Tim Gardner +June 2, 2010 --- linux-3.13.0.orig/debian/tests/rebuild +++ linux-3.13.0/debian/tests/rebuild @@ -0,0 +1 @@ +#!/bin/true --- linux-3.13.0.orig/debian/tests/control +++ linux-3.13.0/debian/tests/control @@ -0,0 +1,3 @@ +Tests: rebuild +Depends: build-essential +Restrictions: build-needed --- linux-3.13.0.orig/debian/scripts/module-check +++ linux-3.13.0/debian/scripts/module-check @@ -0,0 +1,120 @@ +#!/usr/bin/perl -w + +$flavour = shift; +$prev_abidir = shift; +$abidir = shift; +$skipmodule = shift; + +print "II: Checking modules for $flavour..."; + +if (-f "$prev_abidir/ignore.modules" + or -f "$prev_abidir/$flavour.ignore.modules") { + print "explicitly ignoring modules\n"; + exit(0); +} + +if (not -f "$abidir/$flavour.modules" or not -f + "$prev_abidir/$flavour.modules") { + print "previous or current modules file missing!\n"; + print " $abidir/$flavour.modules\n"; + print " $prev_abidir/$flavour.modules\n"; + if (defined($skipmodule)) { + exit(0); + } else { + exit(1); + } +} + +print "\n"; + +my %modules; +my %modules_ignore; +my $missing = 0; +my $new = 0; +my $errors = 0; + +# See if we have any ignores +if (-f "$prev_abidir/../modules.ignore") { + my $ignore = 0; + open(IGNORE, "< $prev_abidir/../modules.ignore") or + die "Could not open $prev_abidir/../modules.ignore"; + print " reading modules to ignore..."; + while () { + chomp; + next if /\s*#/; + $modules_ignore{$_} = 1; + $ignore++; + } + close(IGNORE); + print "read $ignore modules.\n"; +} + +# Read new modules first +print " reading new modules..."; +$new_count = 0; +open(NEW, "< $abidir/$flavour.modules") or + die "Could not open $abidir/$flavour.modules"; +while () { + chomp; + $modules{$_} = 1; + $new_count++; +} +close(NEW); +print "read $new_count modules.\n"; + +# Now the old modules, checking for missing ones +print " reading old modules..."; +$old_count = 0; +open(OLD, "< $prev_abidir/$flavour.modules") or + die "Could not open $prev_abidir/$flavour.modules"; +while () { + chomp; + if (not defined($modules{$_})) { + print "\n" if not $missing; + $missing++; + if (not defined($modules_ignore{$_})) { + print " MISS: $_\n"; + $errors++; + } else { + print " MISS: $_ (ignored)\n"; + } + } else { + $modules{$_}++; + } + $old_count++; +} +close(OLD); +# Check for new modules +foreach $mod (keys(%modules)) { + if ($modules{$mod} < 2) { + print "\n" if not $missing and not $new; + print " NEW : $mod\n"; + $new++; + } +} +if ($new or $missing) { + print " read $old_count modules : new($new) missing($missing)\n"; +} else { + print "read $old_count modules.\n"; +} + + +# Let's see where we stand... +if ($errors) { + if (defined($skipmodule)) { + print "WW: Explicitly asked to ignore failures (probably not good)\n"; + } else { + print "EE: Missing modules (start begging for mercy)\n"; + exit 1 + } +} + +if ($new) { + print "II: New modules (you've been busy, wipe the poop off your nose)\n"; +} else { + print "II: No new modules (hope you're happy, slacker)\n"; +} + +print "II: Done\n"; + +exit(0); --- linux-3.13.0.orig/debian/scripts/link-headers +++ linux-3.13.0/debian/scripts/link-headers @@ -0,0 +1,42 @@ +#!/bin/bash -e + +. debian/debian.env + +hdrdir="$1" +symdir="$2" +flavour="$3" + +echo "Symlinking and copying headers for $flavour..." + +excludes="( -path ./debian -prune -o -path ./${DEBIAN} -prune -o -path ./.git ) -prune -o" + +( +find . $excludes -type f \ + \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) -print +find ./include ./scripts -name .gitignore -prune -o -type f -print +find ./include -mindepth 1 -maxdepth 1 $excludes -type d -print +) | ( +while read file; do + dir=$file + lastdir=$file + + if [ -e "$hdrdir/$file" -o -L "$hdrdir/$file" ]; then + continue + fi + + while [ ! -e "$hdrdir/$dir" -a ! -L "$hdrdir/$dir" ]; do + lastdir=$dir + dir=`dirname $dir` + done + # If the last item to exist is a symlink we assume all is good + if [ ! -L "$hdrdir/$dir" ]; then + # Turns things like "./foo" into "../" + deref="`echo -n $lastdir | sed -e 's/^\.//' -e's,/[^/]*,../,g'`" + item="`echo -n $lastdir | sed -e 's/^\.\///'`" + ln -s $deref$symdir/$item $hdrdir/$item + fi +done +) + +exit --- linux-3.13.0.orig/debian/scripts/module-inclusion +++ linux-3.13.0/debian/scripts/module-inclusion @@ -0,0 +1,60 @@ +#!/bin/bash + +# +# Build a new directory of modules based on an inclusion list. +# The includsion list format must be a bash regular expression. +# +# usage: $0 ROOT INCLUSION_LIST +# example: $0 debian/build/build-virtual \ +# debian/build/build-virtual-ALL debian/build/build-virtual \ +# debian.master/control.d/virtual.inclusion-list +master=0 +if [ "$1" = "--master" ]; then + master=1 + shift +fi + +ROOT=$1 +NROOT=$2 +ILIST=$3 + +# +# Prep a destination directory. +# +mkdir -p ${NROOT} + +# Copy over the framework... +if [ "$master" -eq 1 ]; then + (cd ${ROOT}; find . ! -name "*.ko" -type f) | \ + while read f + do + mkdir -p ${NROOT}/`dirname $f` + mv ${ROOT}/$f ${NROOT}/$f + done +fi + +cat ${ILIST} |while read i +do + # + # 'find' blurts a warning if it cannot find any ko files. + # + if echo "$i" | grep '\*' > /dev/null + then + (cd ${ROOT}; eval find "${i}" -name "*.ko") |while read f + do + mkdir -p ${NROOT}/`dirname $f` + mv ${ROOT}/$f ${NROOT}/$f + done + else + if [ -f "${ROOT}/$i" ] + then + mkdir -p ${NROOT}/`dirname $i` + mv ${ROOT}/$i ${NROOT}/$i + else + echo Warning: Could not find ${ROOT}/$i + fi + fi + +done + +exit 0 --- linux-3.13.0.orig/debian/scripts/control-create +++ linux-3.13.0/debian/scripts/control-create @@ -0,0 +1,25 @@ +#!/bin/bash + +. debian/debian.env + +vars=$1 + +. $vars + +if [ "$is_sub" = "" ]; then + flavour=$(basename $vars | sed 's/.*\.//') + stub=${DEBIAN}/control.d/flavour-control.stub +else + flavour=$(basename $vars .vars) + stub=${DEBIAN}/sub-flavours/control.stub +fi + +cat $stub | grep -v '^#' | sed \ + -e "s#FLAVOUR#$flavour#g" \ + -e "s#DESC#$desc#g" \ + -e "s#ARCH#$arch#g" \ + -e "s#SUPPORTED#$supported#g" \ + -e "s#TARGET#$target#g" \ + -e "s#BOOTLOADER#$bootloader#g" \ + -e "s#=PROVIDES=#$provides#g" \ + -e "s#=CONFLICTS=#$conflicts#g" --- linux-3.13.0.orig/debian/scripts/config-check +++ linux-3.13.0/debian/scripts/config-check @@ -0,0 +1,413 @@ +#!/usr/bin/perl +# +# check-config -- check the current config for issues +# +use strict; + +my $P = 'check-config'; + +my $test = -1; +if ($ARGV[0] eq '--test') { + $test = $ARGV[1] + 0; +} elsif ($#ARGV != 4) { + die "Usage: $P \n"; +} + +my ($config, $arch, $flavour, $commonconfig, $warn_only) = @ARGV; + +my $checks = "$commonconfig/enforce"; +my %values = (); + +# If we are in overridden then still perform the checks and emit the messages +# but do not return failure. Those items marked FATAL will alway trigger +# failure. +my $fail_exit = 1; +$fail_exit = 0 if ($warn_only eq 'true' || $warn_only eq '1'); +my $exit_val = 0; + +# Predicate execution engine. +sub pred_first { + my ($rest) = @_; + my $depth = 0; + my $off; + my $char; + my $pred; + + for ($off = 0; $off <= length($rest); $off++) { + $char = substr($rest, $off, 1); + if ($char eq '(') { + $depth++; + } elsif ($char eq ')') { + $depth--; + } elsif ($depth == 0 && $char eq '&') { + last; + } elsif ($depth == 0 && $char eq '|') { + last; + } + } + if ($depth > 0) { + die "$P: $rest: missing close parenthesis ')'\n"; + } elsif ($depth < 0) { + die "$P: $rest: missing open parenthesis '('\n"; + } + + ($pred, $rest) = (substr($rest, 0, $off), substr($rest, $off + 1)); + + $pred =~ s/^\s*//; + $pred =~ s/\s*$//; + + #print "pred<$pred> rest<$rest> char<$char>\n"; + ($pred, $rest, $char); +} + +sub pred_do { + my ($pred) = @_; + my (@a) = split(' ', $pred); + my $possible; + + if ($a[0] eq 'arch') { + die "$P: $pred: malformed -- $pred \n" if ($#a < 1); + for $possible (@a[1..$#a]) { + #print " *** ARCH<$flavour ?? $possible>\n"; + return 1 if ($arch eq $possible); + } + return 0; + } elsif ($a[0] eq 'flavour') { + die "$P: $pred: malformed -- $pred \n" if ($#a < 1); + for $possible (@a[1..$#a]) { + #print " *** FLAVOUR<$flavour ?? $possible>\n"; + return 1 if ($flavour eq $possible); + } + return 0; + } elsif ($a[0] eq 'value') { + die "$P: $pred: malformed -- $pred \n" if ($#a != 2); + #print " *** CHECK<$a[1] $a[2] ?? " . $values{$a[1]} . ">\n"; + return ($values{$a[1]} eq $a[2]); + } elsif ($a[0] eq 'exists') { + die "$P: $pred: malformed -- $pred \n" if ($#a != 1); + return (defined $values{$a[1]}); + } else { + die "$P: $pred: unknown predicate\n"; + } + return 1; +} +sub pred_exec { + my ($rest) = @_; + my $pred; + my $cut = 0; + my $res; + my $sep; + + #print "pred_exec<$rest>\n"; + + ($pred, $rest, $sep) = pred_first($rest); + + # Leading ! implies inversion. + if ($pred =~ /^\s*!\s*(.*)$/) { + #print " invert<$1>\n"; + ($cut, $res) = pred_exec($1); + $res = !$res; + + # Leading / implies a CUT operation. + } elsif ($pred =~ /^\s*\/\s*(.*)$/) { + #print " cut<$1>\n"; + ($cut, $res) = pred_exec($1); + $cut = 1; + + # Recurse left for complex expressions. + } elsif ($pred =~ /^\s*\((.*)\)\s*$/) { + #print " left<$1>\n"; + ($cut, $res) = pred_exec($1); + + # Check for common syntax issues. + } elsif ($pred eq '') { + if ($sep eq '&' || $sep eq '|') { + die "$P: $pred$rest: malformed binary operator\n"; + } else { + die "$P: $pred$rest: syntax error\n"; + } + + # A predicate, execute it. + } else { + #print " DO<$pred> sep<$sep>\n"; + $res = pred_do($pred); + } + + #print " pre-return res<$res> sep<$sep>\n"; + if ($sep eq '') { + # + + # Recurse right for binary operators -- note these are lazy. + } elsif ($sep eq '&' || $sep eq '|') { + #print " right<$rest> ? sep<$sep> res<$res>\n"; + if ($rest =~ /^\s*($|\||\&)/) { + die "$P: $pred$rest: malformed binary operator\n"; + } + if ($cut == 0 && (($res && $sep eq '&') || (!$res && $sep eq '|'))) { + #print " right<$rest>\n"; + ($cut, $res) = pred_exec($rest); + } + + } else { + die "$P: $pred$rest: malformed predicate\n"; + } + #warn " return cut<$cut> res<$res> sep<$sep>\n"; + return ($cut, $res); +} + +# +# PREDICATE TESTS +# +my $test_total = 1; +my $test_good = 0; +sub pred_test { + my ($pred, $eres, $eerr) = @_; + my ($cut, $res, $err, $fail); + + $test_total++; + if ($test != 0 && $test != $test_total - 1) { + return; + } + + eval { + ($cut, $res) = pred_exec($pred); + }; + $err = $@; + chomp($err); + + $res = !!$res; + $eres = !!$eres; + + $fail = ''; + if (defined $eres && $res != $eres) { + $fail = "result missmatch, expected $eres returned $res"; + } + if (defined $eerr && $err eq '') { + $fail = "error missmatch, expected '$eerr' returned success"; + } elsif (defined $eerr && $err !~ /$eerr/) { + $fail = "error missmatch, expected '$eerr' returned '$err'"; + } elsif (!defined $eerr && $err ne '') { + $fail = "error missmatch, expected success returned '$err'"; + } + + if ($fail eq '') { + $test_good++; + } else { + print "$pred: $test_total: FAIL: $fail\n"; + } + #print "TEST<$pred> eres<$eres> eerr<$eerr> res<$res> err<$err>\n"; +} +if ($test >= 0) { + $arch = 'MYARCH'; + $flavour = 'MYFLAVOUR'; + %values = ( 'ENABLED' => 'y', 'DISABLED' => 'n' ); + + # Errors. + my $eunkn = 'unknown predicate'; + my $epred = 'malformed'; + my $eclose = 'missing close parenthesis'; + my $eopen = 'missing open parenthesis'; + my $ebinary = 'malformed binary operator'; + + # Basic predicate tests. + print "TEST: $test_total: basic predicate tests ...\n"; + + pred_test('nosuchcommand', undef, $eunkn); + pred_test('arch', undef, $epred); + pred_test('arch MYARCH', 1, undef); + pred_test('arch MYARCH NOTMYARCH', 1, undef); + pred_test('arch NOTMYARCH MYARCH', 1, undef); + pred_test('arch NOTMYARCH NOTMYARCH MYARCH', 1, undef); + pred_test('arch NOTMYARCH MYARCH NOTMYARCH', 1, undef); + pred_test('arch NOTMYARCH', 0, undef); + + pred_test('flavour', undef, $epred); + pred_test('flavour MYFLAVOUR', 1, undef); + pred_test('flavour NOTMYFLAVOUR MYFLAVOUR', 1, undef); + pred_test('flavour NOTMYFLAVOUR NOTMYFLAVOUR MYFLAVOUR', 1, undef); + pred_test('flavour NOTMYFLAVOUR MYFLAVOUR NOTMYFLAVOUR', 1, undef); + pred_test('flavour NOTMYFLAVOUR', 0, undef); + + pred_test('value', undef, $epred); + pred_test('value ENABLED', undef, $epred); + pred_test('value ENABLED ENABLED ENABLED', undef, $epred); + pred_test('value ENABLED y', 1, undef); + pred_test('value ENABLED n', 0, undef); + pred_test('value DISABLED n', 1, undef); + pred_test('value DISABLED y', 0, undef); + + pred_test('exists', undef, $epred); + pred_test('exists ENABLED ENABLED', undef, $epred); + pred_test('exists ENABLED', 1, undef); + pred_test('exists DISABLED', 1, undef); + pred_test('exists MISSING', 0, undef); + + print "TEST: $test_total: inversion tests ...\n"; + pred_test('!exists ENABLED', 0, undef); + pred_test('!exists MISSING', 1, undef); + pred_test('!!exists ENABLED', 1, undef); + pred_test('!!exists MISSING', 0, undef); + pred_test('!!!exists ENABLED', 0, undef); + pred_test('!!!exists MISSING', 1, undef); + + print "TEST: $test_total: parentheses tests ...\n"; + pred_test('(exists ENABLED)', 1, undef); + pred_test('((exists ENABLED))', 1, undef); + pred_test('(((exists ENABLED)))', 1, undef); + pred_test('(exists MISSING)', 0, undef); + pred_test('((exists MISSING))', 0, undef); + pred_test('(((exists MISSING)))', 0, undef); + + pred_test('(!exists ENABLED)', 0, undef); + pred_test('((!exists ENABLED))', 0, undef); + pred_test('(((!exists ENABLED)))', 0, undef); + pred_test('(!exists MISSING)', 1, undef); + pred_test('((!exists MISSING))', 1, undef); + pred_test('(((!exists MISSING)))', 1, undef); + + pred_test('((!(exists ENABLED)))', 0, undef); + pred_test('((!(exists MISSING)))', 1, undef); + pred_test('(!((exists ENABLED)))', 0, undef); + pred_test('(!((exists MISSING)))', 1, undef); + pred_test('!(((exists ENABLED)))', 0, undef); + pred_test('!(((exists MISSING)))', 1, undef); + pred_test('!((!(exists ENABLED)))', 1, undef); + pred_test('!((!(exists MISSING)))', 0, undef); + pred_test('!(!(!(exists ENABLED)))', 0, undef); + pred_test('!(!(!(exists MISSING)))', 1, undef); + + pred_test('(', undef, $eclose); + pred_test('()(', undef, $eclose); + pred_test('(())(', undef, $eclose); + pred_test('((()))(', undef, $eclose); + pred_test('(()', undef, $eclose); + pred_test('((())', undef, $eclose); + pred_test('(((()))', undef, $eclose); + pred_test('(()()', undef, $eclose); + pred_test('((())()', undef, $eclose); + + pred_test(')', undef, $eopen); + pred_test('())', undef, $eopen); + pred_test('(()))', undef, $eopen); + pred_test('((())))', undef, $eopen); + + print "TEST: $test_total: binary and tests ...\n"; + + pred_test('exists ENABLED &', undef, $ebinary); + pred_test('& exists ENABLED', undef, $ebinary); + pred_test('exists ENABLED & & exists ENABLED', undef, $ebinary); + + pred_test('exists MISSING & exists MISSING', 0, undef); + pred_test('exists MISSING & exists ENABLED', 0, undef); + pred_test('exists ENABLED & exists MISSING', 0, undef); + pred_test('exists ENABLED & exists ENABLED', 1, undef); + + pred_test('exists MISSING & exists MISSING & exists MISSING', 0, undef); + pred_test('exists MISSING & exists MISSING & exists ENABLED', 0, undef); + pred_test('exists MISSING & exists ENABLED & exists MISSING', 0, undef); + pred_test('exists MISSING & exists ENABLED & exists ENABLED', 0, undef); + pred_test('exists ENABLED & exists MISSING & exists MISSING', 0, undef); + pred_test('exists ENABLED & exists MISSING & exists ENABLED', 0, undef); + pred_test('exists ENABLED & exists ENABLED & exists MISSING', 0, undef); + pred_test('exists ENABLED & exists ENABLED & exists ENABLED', 1, undef); + + print "TEST: $test_total: binary or tests ...\n"; + + pred_test('exists ENABLED |', undef, $ebinary); + pred_test('| exists ENABLED', undef, $ebinary); + pred_test('exists ENABLED | | exists ENABLED', undef, $ebinary); + + pred_test('exists MISSING | exists MISSING', 0, undef); + pred_test('exists MISSING | exists ENABLED', 1, undef); + pred_test('exists ENABLED | exists MISSING', 1, undef); + pred_test('exists ENABLED | exists ENABLED', 1, undef); + + pred_test('exists MISSING | exists MISSING | exists MISSING', 0, undef); + pred_test('exists MISSING | exists MISSING | exists ENABLED', 1, undef); + pred_test('exists MISSING | exists ENABLED | exists MISSING', 1, undef); + pred_test('exists MISSING | exists ENABLED | exists ENABLED', 1, undef); + pred_test('exists ENABLED | exists MISSING | exists MISSING', 1, undef); + pred_test('exists ENABLED | exists MISSING | exists ENABLED', 1, undef); + pred_test('exists ENABLED | exists ENABLED | exists MISSING', 1, undef); + pred_test('exists ENABLED | exists ENABLED | exists ENABLED', 1, undef); + + print "TEST: $test_total: binary or/and combination tests ...\n"; + + pred_test('exists MISSING | exists MISSING & exists MISSING', 0, undef); + pred_test('exists MISSING | exists MISSING & exists ENABLED', 0, undef); + pred_test('exists MISSING | exists ENABLED & exists MISSING', 0, undef); + pred_test('exists MISSING | exists ENABLED & exists ENABLED', 1, undef); + pred_test('exists ENABLED | exists MISSING & exists MISSING', 1, undef); + pred_test('exists ENABLED | exists MISSING & exists ENABLED', 1, undef); + pred_test('exists ENABLED | exists ENABLED & exists MISSING', 1, undef); + pred_test('exists ENABLED | exists ENABLED & exists ENABLED', 1, undef); + + print "TEST: $test_total: binary and/or combination tests ...\n"; + + pred_test('exists MISSING & exists MISSING | exists MISSING', 0, undef); + pred_test('exists MISSING & exists MISSING | exists ENABLED', 0, undef); + pred_test('exists MISSING & exists ENABLED | exists MISSING', 0, undef); + pred_test('exists MISSING & exists ENABLED | exists ENABLED', 0, undef); + pred_test('exists ENABLED & exists MISSING | exists MISSING', 0, undef); + pred_test('exists ENABLED & exists MISSING | exists ENABLED', 1, undef); + pred_test('exists ENABLED & exists ENABLED | exists MISSING', 1, undef); + pred_test('exists ENABLED & exists ENABLED | exists ENABLED', 1, undef); + + print "TEST: $test_total: cut tests ...\n"; + pred_test('(arch MYARCH & exists MISSING) | exists ENABLED', 1, undef); + pred_test('(arch MYARCH &/ exists MISSING) | exists ENABLED', 0, undef); + + $test_total--; + print "TEST: $test_good/$test_total succeeded\n"; + + exit $exit_val; +} + +# Load up the current configuration values -- FATAL if this fails +print "$P: $config: loading config\n"; +open(CONFIG, "<$config") || die "$P: $config: open failed -- $! -- aborting\n"; +while () { + # Pull out values. + /^#*\s*(CONFIG_\w+)[\s=](.*)$/ or next; + if ($2 eq 'is not set') { + $values{$1} = 'n'; + } else { + $values{$1} = $2; + } +} +close(CONFIG); + +# FATAL: Check if we have an enforcement list. +my $pass = 0; +my $total = 0; +my $line = ''; +print "$P: $checks: loading checks\n"; +open(CHECKS, "<$checks") || die "$P: $checks: open failed -- $! -- aborting\n"; +while () { + /^#/ && next; + chomp; + + $line .= $_; + if ($line =~ /\\$/) { + chop($line); + $line .= " "; + next; + } + $line =~ /^\s*$/ && next; + + #print "CHECK: <$line>\n"; + $total++; + my (undef, $result) = pred_exec($line); + if (!$result) { + print "$P: FAIL: $line\n"; + $exit_val = $fail_exit; + } else { + $pass++; + } + + $line = ''; +} +close(CHECKS); + +print "$P: $pass/$total checks passed -- exit $exit_val\n"; +exit $exit_val; --- linux-3.13.0.orig/debian/scripts/sub-flavour +++ linux-3.13.0/debian/scripts/sub-flavour @@ -0,0 +1,69 @@ +#!/bin/bash + +. debian/debian.env + +echo "SUB_PROCESS $FROM => $TO" + +export from_pkg="linux-image-$ABI_RELEASE-$FROM" +export to_pkg="linux-image-$ABI_RELEASE-$TO" + +from_moddir="debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM" +to_moddir="debian/$to_pkg/lib/modules/$ABI_RELEASE-$FROM" + +install -d "debian/$to_pkg/boot" +install -m644 debian/$from_pkg/boot/config-$ABI_RELEASE-$FROM \ + debian/$to_pkg/boot/ +install -m600 debian/$from_pkg/boot/{vmlinuz,System.map}-$ABI_RELEASE-$FROM \ + debian/$to_pkg/boot/ + +# +# Print some warnings if there are files in the sub-flavours list +# that do not actually exist. +# +cat ${DEBIAN}/sub-flavours/$TO.list | while read line +do +( + cd debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM/kernel; + # + # If its a wildcard, then check that there are files that match. + # + if echo "$line" | grep '\*' > /dev/null + then + if [ `eval find "$line" -name '*.ko' 2>/dev/null|wc -l` -lt 1 ] + then + echo SUB_INST Warning - No files in $line + fi + # + # Else it should be a single file reference. + # + elif [ ! -f "$line" ] + then + echo SUB_INST Warning - could not find "$line" + fi +) +done + +cat ${DEBIAN}/sub-flavours/$TO.list | while read line; do + ( + cd debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM/kernel; + if echo "$line" | grep '\*' > /dev/null + then + eval find "$line" -name '*.ko' 2>/dev/null || true + elif [ -f "$line" ] + then + echo "$line" + fi + ); +done | while read mod; do + echo "SUB_INST checking: $mod" + fromdir="/lib/modules/$ABI_RELEASE-$FROM/" + egrep "^($fromdir)?kernel/$mod:" \ + $from_moddir/modules.dep | sed -e "s|^$fromdir||" -e 's/://' -e 's/ /\n/g' | \ + while read m; do + m="${fromdir}$m" + test -f debian/$to_pkg/$m && continue + echo "SUB_INST installing: $m" + install -D -m644 debian/$from_pkg/$m \ + debian/$to_pkg/$m + done +done --- linux-3.13.0.orig/debian/scripts/abi-check +++ linux-3.13.0/debian/scripts/abi-check @@ -0,0 +1,210 @@ +#!/usr/bin/perl -w + +my $flavour = shift; +my $prev_abinum = shift; +my $abinum = shift; +my $prev_abidir = shift; +my $abidir = shift; +my $skipabi = shift; + +my $fail_exit = 1; +my $EE = "EE:"; +my $errors = 0; +my $abiskip = 0; + +my $count; + +print "II: Checking ABI for $flavour...\n"; + +if (-f "$prev_abidir/ignore" + or -f "$prev_abidir/$flavour.ignore" or "$skipabi" eq "true") { + print "WW: Explicitly asked to ignore ABI, running in no-fail mode\n"; + $fail_exit = 0; + $abiskip = 1; + $EE = "WW:"; +} + +if ($prev_abinum != $abinum) { + print "II: Different ABI's, running in no-fail mode\n"; + $fail_exit = 0; + $EE = "WW:"; +} + +if (not -f "$abidir/$flavour" or not -f "$prev_abidir/$flavour") { + print "EE: Previous or current ABI file missing!\n"; + print " $abidir/$flavour\n" if not -f "$abidir/$flavour"; + print " $prev_abidir/$flavour\n" if not -f "$prev_abidir/$flavour"; + + # Exit if the ABI files are missing, but return status based on whether + # skip ABI was indicated. + if ("$abiskip" eq "1") { + exit(0); + } else { + exit(1); + } +} + +my %symbols; +my %symbols_ignore; +my %modules_ignore; +my %module_syms; + +# See if we have any ignores +my $ignore = 0; +print " Reading symbols/modules to ignore..."; + +for $file ("$prev_abidir/../blacklist", "$prev_abidir/../../perm-blacklist") { + if (-f $file) { + open(IGNORE, "< $file") or + die "Could not open $file"; + while () { + chomp; + if ($_ =~ m/M: (.*)/) { + $modules_ignore{$1} = 1; + } else { + $symbols_ignore{$_} = 1; + } + $ignore++; + } + close(IGNORE); + } +} +print "read $ignore symbols/modules.\n"; + +sub is_ignored($$) { + my ($mod, $sym) = @_; + + die "Missing module name in is_ignored()" if not defined($mod); + die "Missing symbol name in is_ignored()" if not defined($sym); + + if (defined($symbols_ignore{$sym}) or defined($modules_ignore{$mod})) { + return 1; + } + return 0; +} + +# Read new syms first +print " Reading new symbols ($abinum)..."; +$count = 0; +open(NEW, "< $abidir/$flavour") or + die "Could not open $abidir/$flavour"; +while () { + chomp; + m/^(\S+)\s(.+)\s(0x[0-9a-f]+)\s(.+)$/; + $symbols{$4}{'type'} = $1; + $symbols{$4}{'loc'} = $2; + $symbols{$4}{'hash'} = $3; + $module_syms{$2} = 0; + $count++; +} +close(NEW); +print "read $count symbols.\n"; + +# Now the old symbols, checking for missing ones +print " Reading old symbols ($prev_abinum)..."; +$count = 0; +open(OLD, "< $prev_abidir/$flavour") or + die "Could not open $prev_abidir/$flavour"; +while () { + chomp; + m/^(\S+)\s(.+)\s(0x[0-9a-f]+)\s(.+)$/; + $symbols{$4}{'old_type'} = $1; + $symbols{$4}{'old_loc'} = $2; + $symbols{$4}{'old_hash'} = $3; + $count++; +} +close(OLD); + +print "read $count symbols.\n"; + +print "II: Checking for missing symbols in new ABI..."; +$count = 0; +foreach $sym (keys(%symbols)) { + if (!defined($symbols{$sym}{'type'})) { + print "\n" if not $count; + printf(" MISS : %s%s\n", $sym, + is_ignored($symbols{$sym}{'old_loc'}, $sym) ? " (ignored)" : ""); + $count++ if !is_ignored($symbols{$sym}{'old_loc'}, $sym); + } +} +print " " if $count; +print "found $count missing symbols\n"; +if ($count) { + print "$EE Symbols gone missing (what did you do!?!)\n"; + $errors++; +} + + +print "II: Checking for new symbols in new ABI..."; +$count = 0; +foreach $sym (keys(%symbols)) { + if (!defined($symbols{$sym}{'old_type'})) { + print "\n" if not $count; + print " NEW : $sym\n"; + $count++; + } +} +print " " if $count; +print "found $count new symbols\n"; +if ($count and $prev_abinum == $abinum) { + print "WW: Found new symbols within same ABI. Not recommended\n"; +} + +print "II: Checking for changes to ABI...\n"; +$count = 0; +my $moved = 0; +my $changed_type = 0; +my $changed_hash = 0; +foreach $sym (keys(%symbols)) { + if (!defined($symbols{$sym}{'old_type'}) or + !defined($symbols{$sym}{'type'})) { + next; + } + + # Changes in location don't hurt us, but log it anyway + if ($symbols{$sym}{'loc'} ne $symbols{$sym}{'old_loc'}) { + printf(" MOVE : %-40s : %s => %s\n", $sym, $symbols{$sym}{'old_loc'}, + $symbols{$sym}{'loc'}); + $moved++; + } + + # Changes to export type are only bad if new type isn't + # EXPORT_SYMBOL. Changing things to GPL are bad. + if ($symbols{$sym}{'type'} ne $symbols{$sym}{'old_type'}) { + printf(" TYPE : %-40s : %s => %s%s\n", $sym, $symbols{$sym}{'old_type'}. + $symbols{$sym}{'type'}, is_ignored($symbols{$sym}{'loc'}, $sym) + ? " (ignored)" : ""); + $changed_type++ if $symbols{$sym}{'type'} ne "EXPORT_SYMBOL" + and !is_ignored($symbols{$sym}{'loc'}, $sym); + } + + # Changes to the hash are always bad + if ($symbols{$sym}{'hash'} ne $symbols{$sym}{'old_hash'}) { + printf(" HASH : %-40s : %s => %s%s\n", $sym, $symbols{$sym}{'old_hash'}, + $symbols{$sym}{'hash'}, is_ignored($symbols{$sym}{'loc'}, $sym) + ? " (ignored)" : ""); + $changed_hash++ if !is_ignored($symbols{$sym}{'loc'}, $sym); + $module_syms{$symbols{$sym}{'loc'}}++; + } +} + +print "WW: $moved symbols changed location\n" if $moved; +print "$EE $changed_type symbols changed export type and weren't ignored\n" if $changed_type; +print "$EE $changed_hash symbols changed hash and weren't ignored\n" if $changed_hash; + +$errors++ if $changed_hash or $changed_type; +if ($changed_hash) { + print "II: Module hash change summary...\n"; + foreach $mod (sort { $module_syms{$b} <=> $module_syms{$a} } keys %module_syms) { + next if ! $module_syms{$mod}; + printf(" %-40s: %d\n", $mod, $module_syms{$mod}); + } +} + +print "II: Done\n"; + +if ($errors) { + exit($fail_exit); +} else { + exit(0); +} --- linux-3.13.0.orig/debian/scripts/misc/retag +++ linux-3.13.0/debian/scripts/misc/retag @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w + +open(TAGS, "git tag -l |") or die "Could not get list of tags"; +@tags = ; +close(TAGS); + +open(LOGS, "git log --pretty=short |") or die "ERROR: Calling git log"; +my $commit = ""; + +while () { + my $origtag; + + if (m|^commit (.*)$|) { + $commit = $1; + next; + } + + m|\s*UBUNTU: (Ubuntu-2\.6\..*)| or next; + + $tag = $1; + + ($origtag) = grep(/^$tag.orig$/, @tags); + + if (!defined($origtag)) { + print "I: Adding original tag for $tag\n"; + system("git tag -m $tag $tag.orig $tag"); + } + + print "I: Tagging $tag => $commit\n"; + + system("git tag -f -m $tag $tag $commit"); +} + +close(LOGS); --- linux-3.13.0.orig/debian/scripts/misc/fw-to-ihex.sh +++ linux-3.13.0/debian/scripts/misc/fw-to-ihex.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +F=$1 +if [ "$F" = "" ] +then + echo You must supply a firmware file. + exit 1 +fi + +echo "unsigned char d[] = {" > $F.c +hexdump -v -e '"\t" 8/1 "0x%02x, " "\n"' $F >> $F.c +echo "};" >> $F.c +sed -i 's/0x .*$//' $F.c + +O="`dirname $F`/`basename $F`.o" +gcc -o $O -c $F.c +objcopy -Oihex $F.o $F.ihex + --- linux-3.13.0.orig/debian/scripts/misc/insert-mainline-changes +++ linux-3.13.0/debian/scripts/misc/insert-mainline-changes @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +if ($#ARGV != 2) { + warn "Usage: $0 \n"; + die " $0 debian.master/changelog v3.2.3 v3.2.2..v3.2.3\n"; +} +my ($changelog, $to, $range) = @ARGV; + +my @changes = (); + +push(@changes, "\n"); +push(@changes, " [ Upstream Kernel Changes ]\n\n"); +push(@changes, " * rebase to $to\n"); + +open(LOG, "git log '$range'|") || die "$0: git log failed: - $!\n"; +while () { + if (m@BugLink: .*launchpad.net/.*/([0-9]+)\s$@) { + push(@changes, " - LP: #$1\n"); + } +} +close(LOG); + +open(CHANGELOG, "< $changelog") or die "Cannot open changelog"; +open(NEW, "> $changelog.new") or die "Cannot open new changelog"; + +$printed = 3; +while () { + if (/^ CHANGELOG: /) { + $printed--; + print NEW; + if ($printed == 0) { + print NEW @changes; + } + next; + } + print NEW; +} + +close(NEW); +close(CHANGELOG); + +rename("$changelog.new", "$changelog"); --- linux-3.13.0.orig/debian/scripts/misc/insert-ubuntu-changes +++ linux-3.13.0/debian/scripts/misc/insert-ubuntu-changes @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +if ($#ARGV != 2) { + die "Usage: $0 \n"; +} +my ($changelog, $end, $start) = @ARGV; + +$end =~ s/.*\.//; +$start =~ s/.*\.//; + +my @changes = (); +my $output = 0; +open(CHG, ") { + if (/^\S+\s+\((.*\.(\d+))\)/) { + if ($2 <= $end) { + last; + } + if ($2 == $start) { + $output = 1; + } + if ($output) { + push(@changes, "\n [ Ubuntu: $1 ]\n\n"); + next; + } + } + next if ($output == 0); + + next if (/^\s*$/); + next if (/^\s--/); + next if (/^\s\s[^\*\s]/); + + push(@changes, $_); +} +close(CHG); + +open(CHANGELOG, "< $changelog") or die "Cannot open changelog"; +open(NEW, "> $changelog.new") or die "Cannot open new changelog"; + +$printed = 3; +while () { + if (/^ CHANGELOG: /) { + $printed--; + print NEW; + if ($printed == 0) { + print NEW @changes; + } + next; + } + print NEW; +} + +close(NEW); +close(CHANGELOG); + +rename("$changelog.new", "$changelog"); --- linux-3.13.0.orig/debian/scripts/misc/find-obsolete-firmware +++ linux-3.13.0/debian/scripts/misc/find-obsolete-firmware @@ -0,0 +1,91 @@ +#!/bin/bash +# +# Find all duplicate or obsolete firmware that is being carried +# in the kernel firmware directory. Compare these files against +# the linux-firmware package for the approriate release. For example, +# assuming this is raring, then compare the kernel firmware files +# against the raring branch of linux-firmware. +# +# Example: $0 ~/ubuntu/linux-firmware-raring + +USEAGE="$0 LINUX-FIRMWARE" + +. debian/debian.env + +NFWINFO="`find $DEBIAN -name fwinfo|wc -l`" +if [ ! "$NFWINFO" = "1" ] +then + echo Your repo is hosed. There can only be one fwinfo file. + find $DEBIAN -name fwinfo + exit 1 +fi + +FWINFO="`pwd`/`find $DEBIAN -name fwinfo`" + +if [ "$1" = "" ] +then + echo $USEAGE + exit 1 +fi +FW="$1" + +if [ ! -f $FW/WHENCE ] +then + echo Bogus linux-firmware directory + exit 1 +fi +if ! egrep -q "^firmware:" $FWINFO +then + echo Bogus firmware info file + exit 1 +fi + +# +# Prepare the tree and make firmware. +# +TEE="tee -a" +LO=`pwd`/firmware.txt +LF=`pwd`/lib/firmware +rm -rf debian/build $LF $LO +fakeroot debian/rules clean prepare-generic +cp debian/build/build-generic/.config . +mkdir -p $LF +make firmware_install INSTALL_MOD_PATH=`pwd` + +(cd $LF +find . -type f | while read f +do + BN="`basename $f`" + + if ! grep -q $BN $FWINFO + then + echo "Unused firmware: $f" | $TEE $LO + else + if [ -f $FW/$f ] + then + if ! cmp $FW/$f $f + then + echo "$f differs" | $TEE $LO + else + echo "$f is duplicated" | $TEE $LO + fi + else + echo "$f does not exist in $FW" | $TEE $LO + fi + fi +done) + +# +# Check for firmware files referenced by the kernel +# that do not exist in either location. +# +cat $FWINFO | while read fwi f +do + if [ -s lib/firmware/$f ] || [ -s $FW/$f ] + then + continue + else + echo "Missing firmware $f" | $TEE $LO + fi +done + --- linux-3.13.0.orig/debian/scripts/misc/getabis +++ linux-3.13.0/debian/scripts/misc/getabis @@ -0,0 +1,130 @@ +#!/bin/bash + +if [ "$#" != "2" ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi + +if [ "$DEBIAN" = "" ]; then + . debian/debian.env +fi + +ver=$1 +revision=$2 +abi=$(echo $revision | gawk -F. '{print $1}') + +verabi=$ver-$abi +verfull=$ver-$revision + +WGET="wget --tries=1 --timeout=10 --quiet -c" + +abidir="`pwd`/$DEBIAN/abi/$verfull" +tmpdir="`pwd`/abi-tmp-$verfull" +origdir="`pwd`" +fwinfo=$abidir/fwinfo + +test -d $tmpdir || mkdir $tmpdir + +package_prefixes() { + __package_prefixes="$@" +} + +getall() { + arch=$1 + shift + + mkdir -p $abidir/$arch + + for sub in $@; do + if [ -f $abidir/$arch/$sub ]; then + echo "Exists: $sub" + continue + fi + echo -n "Fetching $sub($arch)..." + prefixes="" + filenames="" + cd $tmpdir + for prefix in $__package_prefixes + do + filename=${prefix}-${verabi}-${sub}_${verfull}_${arch}.deb + for r in "${repo_list[@]}" + do + if ! [ -f $filename ]; then + $WGET $r/$filename + fi + if [ -f $filename ]; then + prefixes="$prefixes $prefix" + filenames="$filenames $filename" + break + fi + done + done + if [ "$filenames" != "" ]; then + echo -n "extracting$prefixes..." + for filename in $filenames + do + dpkg-deb --extract $filename tmp + done + find tmp -name "*.ko" | while read f; do + modinfo $f | grep ^firmware >> $fwinfo + done + if [ -f tmp/boot/abi-* ]; then + mv tmp/boot/abi-* $abidir/$arch/$sub + else + echo -n "NO ABI FILE..." + fi + (cd tmp; find lib/modules/$verabi-$sub/kernel -name '*.ko') | \ + sed -e 's/.*\/\([^\/]*\)\.ko/\1/' | sort > \ + $abidir/$arch/$sub.modules + ( + cd tmp; + # Prevent exposing some errors when called by python scripts. SIGPIPE seems to get + # exposed when using the `find ...` form of the command. + ko=$(find lib/modules/$verabi-$sub/kernel \ + -name '*.ko' | head -1) + readelf -p .comment "$ko" | gawk ' + ($1 == "[") { + printf("%s", $3); + for (n=4; n<=NF; n++) { + printf(" %s", $n); + } + print "" + }' | sort -u >$abidir/$arch/$sub.compiler + version=`cat $abidir/$arch/$sub.compiler` + echo -n "$version..." + ) + rm -rf tmp $filenames + echo "done." + else + echo "FAILED." + fi + cd $origdir + done +} + +# MAIN + +# Setup abi directory +mkdir -p $abidir +echo $abi > $abidir/abiname + +# NOTE: The flavours are hardcoded, because they may have changed from the +# current build. + +__package_prefixes="linux-image" + +. $DEBIAN/etc/getabis + +compilers=`cat $abidir/*/*.compiler | sort -u | wc -l` +if [ "$compilers" != 1 ]; then + echo "WARNING: inconsistant compiler versions detected" 1>&2 +fi + +sort < $fwinfo | uniq > fwinfo.tmp +mv fwinfo.tmp $fwinfo + +rmdir $tmpdir + +# Add the new ABI directory, remove the old +git add $abidir +find $DEBIAN/abi/* -maxdepth 0 -type d | grep -v $verfull | while read f; do git rm -r $f;done --- linux-3.13.0.orig/debian/scripts/misc/kernelconfig +++ linux-3.13.0/debian/scripts/misc/kernelconfig @@ -0,0 +1,172 @@ +#!/bin/bash + +. debian/debian.env + +# Script to merge all configs and run 'make silentoldconfig' on it to wade out bad juju. +# Then split the configs into distro-commmon and flavour-specific parts + +# We have to be in the top level kernel source directory +if [ ! -f MAINTAINERS ] || [ ! -f Makefile ]; then + echo "This does not appear to be the kernel source directory." 1>&2 + exit 1 +fi + +mode=${1:?"Usage: $0 [oldconfig|editconfig]"} +yes=0 +case "$mode" in + update*configs) mode='silentoldconfig' ;; + default*configs) mode='oldconfig'; yes=1 ;; + edit*configs) ;; # All is good + gen*configs) mode='genconfigs' ;; # All is good + dump*configs) mode='config'; yes=1 ;; + *) echo "$0 called with invalid mode" 1>&2 + exit 1 ;; +esac +kerneldir="`pwd`" +confdir="$kerneldir/${DEBIAN}/config" +sharedconfdir="$kerneldir/debian.master/config" +variant="$2" + +. $DEBIAN/etc/kernelconfig + +bindir="`pwd`/${DROOT}/scripts/misc" +common_conf="$confdir/config.common.$family" +tmpdir=`mktemp -d` +mkdir "$tmpdir/CONFIGS" + +if [ "$mode" = "genconfigs" ]; then + keep=1 + mode="oldconfig" + test -d CONFIGS || mkdir CONFIGS +fi + +for arch in $archs; do + rm -rf build + mkdir build + + # Map debian archs to kernel archs + case "$arch" in + ppc64|ppc64el) kernarch="powerpc" ;; + amd64) kernarch="x86_64" ;; + lpia) kernarch="x86" ;; + sparc) kernarch="sparc64" ;; + armel|armhf) kernarch="arm" ;; + *) kernarch="$arch" ;; + esac + + archconfdir=$confdir/$arch + flavourconfigs=$(cd $archconfdir && ls config.flavour.*) + + # Merge configs + # We merge config.common.ubuntu + config.common. + + # config.flavour. + + for config in $flavourconfigs; do + fullconf="$tmpdir/$arch-$config-full" + case $config in + *) + : >"$fullconf" + if [ -f $common_conf ]; then + cat $common_conf >> "$fullconf" + fi + if [ -f $archconfdir/config.common.$arch ]; then + cat $archconfdir/config.common.$arch >> "$fullconf" + fi + cat "$archconfdir/$config" >>"$fullconf" + if [ -f $confdir/OVERRIDES ]; then + cat $confdir/OVERRIDES >> "$fullconf" + fi + ;; + esac + done + + for config in $flavourconfigs; do + if [ -f $archconfdir/$config ]; then + fullconf="$tmpdir/$arch-$config-full" + cat "$fullconf" > build/.config + # Call oldconfig or menuconfig + case "$mode" in + editconfigs) + # Interactively edit config parameters + while : ; do + echo -n "Do you want to edit config: $arch/$config? [Y/n] " + read choice + + case "$choice" in + y* | Y* | "" ) + make O=`pwd`/build ARCH=$kernarch menuconfig + break ;; + n* | N* ) + break ;; + *) + echo "Entry not valid" + esac + done + ;; + *) + echo "* Run $mode (yes=$yes) on $arch/$config ..." + if [ "$yes" -eq 1 ]; then + yes "" | make O=`pwd`/build ARCH=$kernarch "$mode" + else + make O=`pwd`/build ARCH=$kernarch "$mode" + fi ;; + esac + cat build/.config > $archconfdir/$config + cat build/.config > "$tmpdir/CONFIGS/$arch-$config" + if [ "$keep" = "1" ]; then + cat build/.config > CONFIGS/$arch-$config + fi + else + echo "!! Config not found $archconfdir/$config..." + fi + done + + echo "Running splitconfig.pl for $arch" + echo + + # Can we make this more robust by avoiding $tmpdir completely? + # This approach was used for now because I didn't want to change + # splitconfig.pl + (cd $archconfdir; $bindir/splitconfig.pl config.flavour.*; mv config.common \ + config.common.$arch; cp config.common.$arch $tmpdir) +done + +rm -f $common_conf + +# Now run splitconfig.pl on all the config.common. copied to +# $tmpdir +(cd $tmpdir; $bindir/splitconfig.pl *) +( + cd $confdir; + rm -f *-full + grep -v 'is UNMERGABLE' <$tmpdir/config.common >$common_conf + for arch in $archs; do + grep -v 'is UNMERGABLE' <$tmpdir/config.common.$arch \ + >$arch/config.common.$arch + done +) + +echo "" +echo "Running config-check for all configurations ..." +echo "" +fail=0 +for arch in $archs; do + archconfdir=$confdir/$arch + flavourconfigs=$(cd $archconfdir && ls config.flavour.*) + for config in $flavourconfigs; do + flavour="${config##*.}" + if [ -f $archconfdir/$config ]; then + fullconf="$tmpdir/CONFIGS/$arch-$config" + "$bindir/../config-check" "$fullconf" "$arch" "$flavour" "$sharedconfdir" "0" || let "fail=$fail+1" + fi + done +done + +if [ "$fail" != 0 ]; then + echo "" + echo "*** ERROR: $fail config-check failures detected" + echo "" +fi + +rm -rf build + --- linux-3.13.0.orig/debian/scripts/misc/get-firmware +++ linux-3.13.0/debian/scripts/misc/get-firmware @@ -0,0 +1,62 @@ +#!/bin/bash +# +# Find all files in linux-firmware that are new or different since the previous release +# and copy them into the kernel firmware directory. You should only do this on the +# backport branch since it would be redundant on the released kernel. It assumed you've +# unpacked linux-firmware from each release into separate directories. +# +# Example: $0 ~/ubuntu/linux-firmware-precise ~/ubuntu/linux-firmware-quantal + +if [ "$1" = "" ] || [ "$2" = "" ] || [ ! -f $1/WHENCE ] || [ ! -f $2/WHENCE ] +then + echo You must supply 2 firmware directories. + exit 1 +fi + +if [ ! -f debian/debian.env ] +then + echo You must run this script from the root of the repo + exit 1 +fi +. debian/debian.env + +NFWINFO="`find $DEBIAN -name fwinfo|wc -l`" +if [ ! "$NFWINFO" = "1" ] +then + echo Your repo is hosed. There can only be one fwinfo file. + find $DEBIAN -name fwinfo + exit 1 +fi + +FWINFO="`pwd`/`find $DEBIAN -name fwinfo`" + +CDIR=`pwd` +OFW=$1 +NFW=$2 + +cd $NFW +# +# Find all files in $NFW that are new or different from $1 +# +(find . -type f | egrep -v "debian|git|LICEN|WHEN|READ|Make|configure" | sed 's;\./;;' | \ +while read f +do + if grep -q $f $FWINFO + then + if [ ! -f $OFW/$f ] + then + echo $f + elif ! cmp $f $OFW/$f > /dev/null + then + echo $f + fi + fi +done) |\ +while read f +do + mkdir -p $CDIR/firmware/`dirname $f` + if [ ! -f $CDIR/firmware/`dirname $f`/`basename $f`.ihex ] + then + cp -v $f $CDIR/firmware/`dirname $f` + fi +done --- linux-3.13.0.orig/debian/scripts/misc/splitconfig.pl +++ linux-3.13.0/debian/scripts/misc/splitconfig.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl -w + +%allconfigs = (); +%common = (); + +print "Reading config's ...\n"; + +for $config (@ARGV) { + # Only config.* + next if $config !~ /^config\..*/; + # Nothing that is disabled, or remnant + next if $config =~ /.*\.(default|disabled|stub)$/; + + %{$allconfigs{$config}} = (); + + print " processing $config ... "; + + open(CONFIG, "< $config"); + + while () { + # Skip comments + /^#*\s*CONFIG_(\w+)[\s=](.*)$/ or next; + + ${$allconfigs{$config}}{$1} = $2; + + $common{$1} = $2; + } + + close(CONFIG); + + print "done.\n"; +} + +print "\n"; + +print "Merging lists ... \n"; + +# %options - pointer to flavour config inside the allconfigs array +for $config (keys(%allconfigs)) { + my %options = %{$allconfigs{$config}}; + + print " processing $config ... "; + + for $key (keys(%common)) { + next if not defined $common{$key}; + + # If we don't have the common option, then it isn't + # common. If we do have that option, it must have the same + # value. EXCEPT where this file does not have a value at all + # which may safely be merged with any other value; the value + # will be elided during recombination of the parts. + if (!defined($options{$key})) { + # Its ok really ... let it merge + } elsif (not defined($options{$key})) { + undef $common{$key}; + } elsif ($common{$key} ne $options{$key}) { + undef $common{$key}; + } + } + + print "done.\n"; +} + +print "\n"; + +print "Creating common config ... "; + +open(COMMON, "> config.common"); +print COMMON "#\n# Common config options automatically generated by splitconfig.pl\n#\n"; + +for $key (sort(keys(%common))) { + if (not defined $common{$key}) { + print COMMON "# CONFIG_$key is UNMERGABLE\n"; + } elsif ($common{$key} eq "is not set") { + print COMMON "# CONFIG_$key is not set\n"; + } else { + print COMMON "CONFIG_$key=$common{$key}\n"; + } +} +close(COMMON); + +print "done.\n\n"; + +print "Creating stub configs ...\n"; + +for $config (keys(%allconfigs)) { + my %options = %{$allconfigs{$config}}; + + print " processing $config ... "; + + open(STUB, "> $config"); + print STUB "#\n# Config options for $config automatically generated by splitconfig.pl\n#\n"; + + for $key (sort(keys(%options))) { + next if defined $common{$key}; + + if ($options{$key} =~ /^is /) { + print STUB "# CONFIG_$key $options{$key}\n"; + } else { + print STUB "CONFIG_$key=$options{$key}\n"; + } + } + + close(STUB); + + print "done.\n"; +} --- linux-3.13.0.orig/debian/scripts/misc/insert-changes.pl +++ linux-3.13.0/debian/scripts/misc/insert-changes.pl @@ -0,0 +1,36 @@ +#!/usr/bin/perl -w + +my $debian; +$droot = $ARGV[0] if (defined $ARGV[0]); +$droot = 'debian' if (!defined $droot); +$debian = $ARGV[1] if (defined $ARGV[1]); +$debian = 'debian.master' if (!defined $debian); + +system("make -s -f $droot/rules printchanges > $debian/changes"); + +open(CHANGELOG, "< $debian/changelog") or die "Cannot open changelog"; +open(CHANGES, "< $debian/changes") or die "Cannot open new changes"; +open(NEW, "> $debian/changelog.new") or die "Cannot open new changelog"; + +$printed = 0; + +while () { + if (/^ CHANGELOG: /) { + next if $printed; + + while () { + print NEW; + } + + $printed = 1; + } else { + print NEW; + } +} + +close(NEW); +close(CHANGES); +close(CHANGELOG); + +rename("$debian/changelog.new", "$debian/changelog"); +unlink("$debian/changes"); --- linux-3.13.0.orig/debian/scripts/misc/git-ubuntu-log +++ linux-3.13.0/debian/scripts/misc/git-ubuntu-log @@ -0,0 +1,232 @@ +#!/usr/bin/perl -w + +use strict; +use Text::Wrap; + +my $kernel_auth = "Upstream Kernel Changes"; + +my (%map, @reverts); +my $pstate = 1; +my $no_kern_log = 0; +my $print_shas = 0; +my $first_print = 1; + +while (@ARGV) { + my $opt = $ARGV[0]; + shift; + if ($opt eq "--no-kern-log") { + $no_kern_log = 1; + } elsif ($opt eq "--print-shas") { + $print_shas = 1; + } else { + print STDERR "Unknown options: $opt\n"; + exit(1); + } +} + +sub check_reverts($) { + my ($entry) = @_; + my ($check); + + foreach $check (reverse @reverts) { + my $desc = "Revert \"" . $entry->{'desc'} . "\""; + if ($check->{'desc'} eq $desc) { + @reverts = grep($_->{'desc'} ne $desc, @reverts); + return 1; + } + } + + return 0; +} + +sub add_entry($) { + my ($entry) = @_; + my $key = $entry->{'author'}; + + # store description in array, in email->{desc list} map + if (exists $map{$key}) { + # grab ref + my $obj = $map{$key}; + + # add desc to array + push(@$obj, $entry); + } else { + # create new array, containing 1 item + my @arr = ($entry); + + # store ref to array + $map{$key} = \@arr; + } +} + +sub shortlog_entry($$$$$) { + my ($name, $desc, $bug, $cve, $commit) = @_; + my $entry; + + $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g; + $desc =~ s#\[PATCH\] ##g; + + $desc =~ s#^\s*##g; + $desc =~ s# *UBUNTU: ##g; + + $entry->{'desc'} = $desc; + if ($bug ne '') { + $entry->{'bugno'} = $bug; + } + $entry->{'cve'} = $cve; + $entry->{'commit'} = $commit; + $entry->{'author'} = $name; + + if ($desc =~ /^Revert "/) { + push(@reverts, $entry); + return; + } + + return if check_reverts($entry); + + add_entry($entry); +} + +# sort comparison function +sub by_name($$) { + my ($a, $b) = @_; + + uc($a) cmp uc($b); +} + +sub shortlog_output { + my ($obj, $key, $entry); + + foreach $key (sort by_name keys %map) { + next if $key eq $kernel_auth and $no_kern_log; + + print "\n" unless $first_print; + $first_print = 0; + + # output author + printf " [ %s ]\n\n", $key; + + # output author's 1-line summaries + $obj = $map{$key}; + foreach $entry (reverse @$obj) { + print wrap(" * ", " ", $entry->{'desc'}) . "\n"; + # For non upstream changes, add other info. + if ($key ne $kernel_auth) { + if ($print_shas) { + print " - GIT-SHA " . $entry->{'commit'} . + "\n"; + } + } + if (defined($entry->{'bugno'})) { + print " - LP: #" . $entry->{'bugno'} . "\n"; + } + if (defined($entry->{'cve'})) { + print " - " . $entry->{'cve'} . "\n"; + } + } + } +} + +sub changelog_input { + my ($author, $desc, $commit, $entry, $cve); + + while () { + # get commit + if ($pstate == 1) { + next unless /^commit (.*)/; + + $commit = $1; + + $pstate++; + } + + # get author and email + elsif ($pstate == 2) { + my ($email); + + next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/; + + $author = $1; + $email = $2; + $desc = undef; + $cve = undef; + + # cset author fixups + if (!$author) { + $author = $email; + } + $pstate++; + } + + # skip to blank line + elsif ($pstate == 3) { + next unless /^\s*$/; + $pstate++; + } + + # skip to non-blank line + elsif ($pstate == 4) { + next unless /^\s*?(.*)/; + my $ignore = 0; + my $do_ignore = 0; + my $bug = undef; + my %bugz = (); + my $k; + + # skip lines that are obviously not + # a 1-line cset description + next if /^\s*From: /; + + chomp; + $desc = $1; + + if ($desc =~ /^ *(Revert "|)UBUNTU:/) { + $do_ignore = 1; + } else { + $do_ignore = 0; + $author = $kernel_auth; + $ignore = 1 if $desc =~ /Merge /; + } + while () { + $ignore = 1 if ($do_ignore && /^ *Ignore: yes/i); + if (/^ *Bug: *(#|)([0-9#,\s]*)\s*$/i) { + foreach $k (split('(,|\s)\s*(#|)', $2)) { + $bugz{$k} = 1 if (($k ne '') and ($k =~ /[0-9]+/)); + } + } + elsif (/^ *BugLink: *http.*:\/\/.*\/([0-9]+)/i) { + $bugz{$1} = 1; + } + elsif (/^ *(CVE-.*)/) { + $cve = $1 + } + last if /^commit /; + } + + $bug = join(", #", sort keys(%bugz)); + if (!$ignore) { + &shortlog_entry($author, $desc, $bug, + $cve, $commit, 0); + } + + $pstate = 1; + if ($_ && /^commit (.*)/) { + $commit = $1; + $pstate++; + } + } + + else { + die "invalid parse state $pstate"; + } + } + + foreach $entry (@reverts) { + add_entry($entry); + } +} + +&changelog_input; +&shortlog_output; + +exit(0); --- linux-3.13.0.orig/debian/cloud-tools/hv_get_dhcp_info +++ linux-3.13.0/debian/cloud-tools/hv_get_dhcp_info @@ -0,0 +1,55 @@ +#!/bin/bash + +# This example script retrieves the DHCP state of a given interface. +# In the interest of keeping the KVP daemon code free of distro specific +# information; the kvp daemon code invokes this external script to gather +# DHCP setting for the specific interface. +# +# Input: Name of the interface +# +# Output: The script prints the string "Enabled" to stdout to indicate +# that DHCP is enabled on the interface. If DHCP is not enabled, +# the script prints the string "Disabled" to stdout. +# +# Each Distro is expected to implement this script in a distro specific +# fashion. + +#set -x + +IF_FILE="/etc/network/interfaces" +NMCMD="nmcli" + +function checknetworkmanager { + #Assumes if $NMCMD exists, inteface exists and interface is not + # in $IF_FILE then dhcp is being used by NM + if hash $NMCMD >/dev/null 2>&1 ; then + if $NMCMD dev status |grep -q $1 ; then + echo "Enabled" + else + echo "Disabled" + fi + else + #Give up + echo "Disabled" + fi +} + +if [ -z $1 ] ; then echo "Disabled"; exit; fi + +if [ -e $IF_FILE ]; then + if grep -v -e "^#" $IF_FILE|grep -q $1 ; then + #interface exists so + if grep -q -e $1\.\*dhcp $IF_FILE; then + echo "Enabled"; exit; + else + echo "Disabled"; exit; + fi + else + checknetworkmanager $1 + exit + fi +else + checknetworkmanager $1 + exit +fi + --- linux-3.13.0.orig/debian/cloud-tools/hv_set_ifconfig +++ linux-3.13.0/debian/cloud-tools/hv_set_ifconfig @@ -0,0 +1,224 @@ +#! /usr/bin/env python + +# set interfaces in hv_kvp_daemon style +import fileinput +import sys +import errno +import os +import shutil +import tempfile +import subprocess + +if_filename="/etc/network/interfaces" + +'''Get quiet''' +sys.stdout = open(os.devnull, 'w') +sys.stderr = open(os.devnull, 'w') + +try: + if_file=open(if_filename,"r+") +except IOError as e: + exit(e.errno) +else: + if_file.close() + + +def kvp_dict(file): + return dict(line.strip().split("=") for line in file) + + +#setting the hwaddress to something azure is not expecting is fatal networking + +if len(sys.argv) != 2 : + exit(errno.EINVAL) + +kvp=dict(line.strip().split("=") for line in fileinput.input()) + +if not "HWADDR" in kvp : + exit(errno.EPROTO) + +if not "DEVICE" in kvp : + exit(1) + +output=[] +basename=kvp["DEVICE"] + +if "DHCP" in kvp and kvp["DHCP"]=="yes" : + output += ["auto " + basename] + output += ["iface " + basename + " inet dhcp"] + output += [""] +else: + ''' Matchup the interface specific lines ''' + + '''DNS entries will go with the first interface + and there can be a max of three''' + autolist=[] + dns=[] + if "DNS1" in kvp : + dns+=[kvp["DNS1"]] + if "DNS2" in kvp : + dns+=[kvp["DNS2"]] + if "DNS3" in kvp : + dns+=[kvp["DNS3"]] + + + ''' + No real max for the number of interface + aliases ... + only required is the address (but mate everything up that comes in. ''' + + '''ipv4 first''' + + v4names=[name for name in kvp.keys() if name.startswith("IPADDR")] + v4names.sort() + + v6names=[name for name in kvp.keys() if name.startswith("IPV6ADDR")] + v6names.sort() + + '''IPV6 requires a netmask''' + '''If an ipv6 exists, you'll want to turn off /proc/sys/net/ipv6/conf/all/autoconf with + up echo 0 > /proc/sys/net/ipv6/conf/all/autoconf''' + + '''Counter needs to increment as soon as any interface is set.''' + + + if_count=0 + + for v4 in v4names: + ifname=basename + suffix="" + if if_count : + ifname+=":" + str(if_count) + suffix="_"+str(if_count) + if not ifname in autolist: + autolist += [ifname] + output += [ "iface " + ifname + " inet static"] + output += [ "\t" + "address " + kvp[v4]] + if "NETMASK"+suffix in kvp.keys(): + output += ["\tnetmask " + kvp["NETMASK"+suffix]] + if "GATEWAY"+suffix in kvp.keys(): + output += ["\tgateway " + kvp["GATEWAY"+suffix]] + if not if_count : + output += ["\tdns-nameservers " + ' '.join(dns)] + output += [""] + if_count+=1 + + if6_count=0 + if6_used=0 + for v6 in v6names: + ifname=basename + suffix="" + if if6_used : + ifname+=":" + str(if6_used) + if if6_count : + suffix="_" + str(if6_count) + if not ifname in autolist: + autolist += [ifname] + if "IPV6NETMASK"+suffix in kvp.keys(): + output += [ "iface " + ifname + " inet6 static"] + output += [ "\taddress " + kvp[v6]] + output += [ "\tnetmask " + kvp["IPV6NETMASK"+suffix]] + if "IPV6_DEFAULTGW"+suffix in kvp.keys(): + output += [ "\tgateway " + kvp["IPV6_DEFAULTGW"+suffix] ] + if not if_count : + output += ["\tdns-nameservers " + ' '.join(dns)] + output += [""] + if_count += 1 + if6_used += 1 + if6_count += 1 + + output = ["auto "+" ".join(autolist)] + output +output=["# The following stanza(s) added by hv_set_ifconfig"] + output +output+=["#End of hv_set_ifconfig stanzas"] +print "===================================" +print output +print "===================================" + + +''' Time to clean out the existing interface file''' + +f=open(if_filename,"r") +flines=f.readlines() +f.close() +newfile=[] +pitchstanza=0 +inastanza=0 +stanza=[] +for line in flines: + if line.startswith("auto"): + if inastanza: + if not pitchstanza: + newfile.extend(stanza) + stanza=[] + inastanza=0 + newline="" + autoline=line.strip().split(" ") + for word in autoline: + if (not word == basename) and (not word.startswith(basename+":")): + newline+=word + " " + newline = newline.strip() + if not newline == "auto": + newfile += [newline.strip()] + elif line.startswith(("iface","mapping","source")): + '''Read a stanza''' + '''A Stanza can also start with allow- ie allow-hotplug''' + if inastanza: + if not pitchstanza: + newfile.extend(stanza) + stanza=[] + inastanza=1 + pitchstanza=0 + autoline=line.strip().split(" ") + for word in autoline: + if (word == basename) or (word.startswith(basename+":")): + pitchstanza=1 + if not pitchstanza: + stanza+=[line.strip()] + else: + if inastanza: + if not pitchstanza: + stanza+=[line.strip()] + else: + if not pitchstanza: + newfile += [line.strip()] + + +for line in newfile: + print line +for line in output: + print line + + +fd, path = tempfile.mkstemp() +for line in newfile: + os.write(fd,line) + os.write(fd,"\n") +for line in output: + os.write(fd,line) + os.write(fd,"\n") +os.close(fd) + +shutil.copy(path,if_filename) +os.chmod(if_filename,0644) +#print "TMPFILE is at: " + path +#print "Copied file is at: " + if_filename + + +try: + retcode = subprocess.call("ifdown "+basename , shell=True) + if retcode < 0: + print >>sys.stderr, "Child was terminated by signal", -retcode + else: + print >>sys.stderr, "Child returned", retcode +except OSError as e: + print >>sys.stderr, "Execution failed:", e + +try: + retcode = subprocess.call("ifup "+basename , shell=True) + if retcode < 0: + print >>sys.stderr, "Child was terminated by signal", -retcode + else: + print >>sys.stderr, "Child returned", retcode +except OSError as e: + print >>sys.stderr, "Execution failed:", e + + --- linux-3.13.0.orig/debian/cloud-tools/hv_get_dns_info +++ linux-3.13.0/debian/cloud-tools/hv_get_dns_info @@ -0,0 +1,13 @@ +#!/bin/bash + +# This example script parses /etc/resolv.conf to retrive DNS information. +# In the interest of keeping the KVP daemon code free of distro specific +# information; the kvp daemon code invokes this external script to gather +# DNS information. +# This script is expected to print the nameserver values to stdout. +# Each Distro is expected to implement this script in a distro specific +# fashion. For instance on Distros that ship with Network Manager enabled, +# this script can be based on the Network Manager APIs for retrieving DNS +# entries. + +cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }' --- linux-3.13.0.orig/arch/alpha/lib/csum_partial_copy.c +++ linux-3.13.0/arch/alpha/lib/csum_partial_copy.c @@ -378,6 +378,11 @@ __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) { - return csum_partial_copy_from_user((__force const void __user *)src, - dst, len, sum, NULL); + __wsum checksum; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + checksum = csum_partial_copy_from_user((__force const void __user *)src, + dst, len, sum, NULL); + set_fs(oldfs); + return checksum; } --- linux-3.13.0.orig/arch/xtensa/platforms/xtfpga/setup.c +++ linux-3.13.0/arch/xtensa/platforms/xtfpga/setup.c @@ -194,7 +194,7 @@ * Ethernet -- OpenCores Ethernet MAC (ethoc driver) */ -static struct resource ethoc_res[] __initdata = { +static struct resource ethoc_res[] = { [0] = { /* register space */ .start = OETH_REGS_PADDR, .end = OETH_REGS_PADDR + OETH_REGS_SIZE - 1, @@ -212,7 +212,7 @@ }, }; -static struct ethoc_platform_data ethoc_pdata __initdata = { +static struct ethoc_platform_data ethoc_pdata = { /* * The MAC address for these boards is 00:50:c2:13:6f:xx. * The last byte (here as zero) is read from the DIP switches on the @@ -222,7 +222,7 @@ .phy_id = -1, }; -static struct platform_device ethoc_device __initdata = { +static struct platform_device ethoc_device = { .name = "ethoc", .id = -1, .num_resources = ARRAY_SIZE(ethoc_res), @@ -236,13 +236,13 @@ * UART */ -static struct resource serial_resource __initdata = { +static struct resource serial_resource = { .start = DUART16552_PADDR, .end = DUART16552_PADDR + 0x1f, .flags = IORESOURCE_MEM, }; -static struct plat_serial8250_port serial_platform_data[] __initdata = { +static struct plat_serial8250_port serial_platform_data[] = { [0] = { .mapbase = DUART16552_PADDR, .irq = DUART16552_INTNUM, @@ -255,7 +255,7 @@ { }, }; -static struct platform_device xtavnet_uart __initdata = { +static struct platform_device xtavnet_uart = { .name = "serial8250", .id = PLAT8250_DEV_PLATFORM, .dev = { --- linux-3.13.0.orig/arch/xtensa/kernel/entry.S +++ linux-3.13.0/arch/xtensa/kernel/entry.S @@ -1117,6 +1117,13 @@ * We basically restore WINDOWBASE and WINDOWSTART to the condition when * we entered the spill routine and jump to the user exception handler. * + * Note that we only need to restore the bits in windowstart that have not + * been spilled yet by the _spill_register routine. Luckily, a3 contains a + * rotated windowstart with only those bits set for frames that haven't been + * spilled yet. Because a3 is rotated such that bit 0 represents the register + * frame for the current windowbase - 1, we need to rotate a3 left by the + * value of the current windowbase + 1 and move it to windowstart. + * * a0: value of depc, original value in depc * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE * a3: exctable, original value in excsave1 @@ -1131,10 +1138,15 @@ /* We need to make sure the current registers (a0-a3) are preserved. * To do this, we simply set the bit for the current window frame * in WS, so that the exception handlers save them to the task stack. + * + * Note: we use a3 to set the windowbase, so we take a special care + * of it, saving it in the original _spill_registers frame across + * the exception handler call. */ xsr a3, excsave1 # get spill-mask slli a3, a3, 1 # shift left by one + addi a3, a3, 1 # set the bit for the current window frame slli a2, a3, 32-WSBITS src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy...... @@ -1794,6 +1806,43 @@ ENDPROC(system_call) +/* + * Spill live registers on the kernel stack macro. + * + * Entry condition: ps.woe is set, ps.excm is cleared + * Exit condition: windowstart has single bit set + * May clobber: a12, a13 + */ + .macro spill_registers_kernel + +#if XCHAL_NUM_AREGS > 16 + call12 1f + _j 2f + retw + .align 4 +1: + _entry a1, 48 + addi a12, a0, 3 +#if XCHAL_NUM_AREGS > 32 + .rept (XCHAL_NUM_AREGS - 32) / 12 + _entry a1, 48 + mov a12, a0 + .endr +#endif + _entry a1, 48 +#if XCHAL_NUM_AREGS % 12 == 0 + mov a8, a8 +#elif XCHAL_NUM_AREGS % 12 == 4 + mov a12, a12 +#elif XCHAL_NUM_AREGS % 12 == 8 + mov a4, a4 +#endif + retw +2: +#else + mov a12, a12 +#endif + .endm /* * Task switch. @@ -1806,21 +1855,20 @@ entry a1, 16 - mov a12, a2 # preserve 'prev' (a2) - mov a13, a3 # and 'next' (a3) + mov a10, a2 # preserve 'prev' (a2) + mov a11, a3 # and 'next' (a3) l32i a4, a2, TASK_THREAD_INFO l32i a5, a3, TASK_THREAD_INFO - save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER + save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER - s32i a0, a12, THREAD_RA # save return address - s32i a1, a12, THREAD_SP # save stack pointer + s32i a0, a10, THREAD_RA # save return address + s32i a1, a10, THREAD_SP # save stack pointer /* Disable ints while we manipulate the stack pointer. */ - movi a14, (1 << PS_EXCM_BIT) | LOCKLEVEL - xsr a14, ps + rsil a14, LOCKLEVEL rsr a3, excsave1 rsync s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */ @@ -1835,7 +1883,7 @@ /* Flush register file. */ - call0 _spill_registers # destroys a3, a4, and SAR + spill_registers_kernel /* Set kernel stack (and leave critical section) * Note: It's save to set it here. The stack will not be overwritten @@ -1851,13 +1899,13 @@ /* restore context of the task 'next' */ - l32i a0, a13, THREAD_RA # restore return address - l32i a1, a13, THREAD_SP # restore stack pointer + l32i a0, a11, THREAD_RA # restore return address + l32i a1, a11, THREAD_SP # restore stack pointer - load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER + load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER wsr a14, ps - mov a2, a12 # return 'prev' + mov a2, a10 # return 'prev' rsync retw --- linux-3.13.0.orig/arch/xtensa/include/asm/traps.h +++ linux-3.13.0/arch/xtensa/include/asm/traps.h @@ -22,25 +22,37 @@ static inline void spill_registers(void) { - +#if XCHAL_NUM_AREGS > 16 __asm__ __volatile__ ( - "movi a14, "__stringify((1 << PS_EXCM_BIT) | LOCKLEVEL)"\n\t" - "mov a12, a0\n\t" - "rsr a13, sar\n\t" - "xsr a14, ps\n\t" - "movi a0, _spill_registers\n\t" - "rsync\n\t" - "callx0 a0\n\t" - "mov a0, a12\n\t" - "wsr a13, sar\n\t" - "wsr a14, ps\n\t" - : : -#if defined(CONFIG_FRAME_POINTER) - : "a2", "a3", "a4", "a11", "a12", "a13", "a14", "a15", + " call12 1f\n" + " _j 2f\n" + " retw\n" + " .align 4\n" + "1:\n" + " _entry a1, 48\n" + " addi a12, a0, 3\n" +#if XCHAL_NUM_AREGS > 32 + " .rept (" __stringify(XCHAL_NUM_AREGS) " - 32) / 12\n" + " _entry a1, 48\n" + " mov a12, a0\n" + " .endr\n" +#endif + " _entry a1, 48\n" +#if XCHAL_NUM_AREGS % 12 == 0 + " mov a8, a8\n" +#elif XCHAL_NUM_AREGS % 12 == 4 + " mov a12, a12\n" +#elif XCHAL_NUM_AREGS % 12 == 8 + " mov a4, a4\n" +#endif + " retw\n" + "2:\n" + : : : "a12", "a13", "memory"); #else - : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", + __asm__ __volatile__ ( + " mov a12, a12\n" + : : : "memory"); #endif - "memory"); } #endif /* _XTENSA_TRAPS_H */ --- linux-3.13.0.orig/arch/tile/include/asm/compat.h +++ linux-3.13.0/arch/tile/include/asm/compat.h @@ -281,7 +281,6 @@ u32 dummy, u32 low, u32 high); long compat_sys_pwrite64(unsigned int fd, char __user *ubuf, size_t count, u32 dummy, u32 low, u32 high); -long compat_sys_lookup_dcookie(u32 low, u32 high, char __user *buf, size_t len); long compat_sys_sync_file_range2(int fd, unsigned int flags, u32 offset_lo, u32 offset_hi, u32 nbytes_lo, u32 nbytes_hi); --- linux-3.13.0.orig/arch/arm/Kconfig +++ linux-3.13.0/arch/arm/Kconfig @@ -1543,6 +1543,7 @@ choice prompt "Memory split" + depends on MMU default VMSPLIT_3G help Select the desired split between kernel and user memory. @@ -1560,6 +1561,7 @@ config PAGE_OFFSET hex + default PHYS_OFFSET if !MMU default 0x40000000 if VMSPLIT_1G default 0x80000000 if VMSPLIT_2G default 0xC0000000 @@ -2261,6 +2263,8 @@ source "drivers/Kconfig" +source "ubuntu/Kconfig" + source "fs/Kconfig" source "arch/arm/Kconfig.debug" --- linux-3.13.0.orig/arch/arm/mach-omap2/omap_hwmod_common_data.c +++ linux-3.13.0/arch/arm/mach-omap2/omap_hwmod_common_data.c @@ -59,6 +59,16 @@ .sidle_shift = SYSC_TYPE3_SIDLEMODE_SHIFT, }; +/** + * struct omap_hwmod_sysc_type4 - TYPE4 sysconfig scheme. + * Used by some IPs on AM33xx + */ +struct omap_hwmod_sysc_fields omap_hwmod_sysc_type4 = { + .sidle_shift = SYSC_TYPE4_SIDLEMODE_SHIFT, + .srst_shift = SYSC_TYPE4_SOFTRESET_SHIFT, + .autoidle_shift = SYSC_TYPE4_AUTOIDLE_SHIFT, +}; + struct omap_dss_dispc_dev_attr omap2_3_dss_dispc_dev_attr = { .manager_count = 2, .has_framedonetv_irq = 0 --- linux-3.13.0.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ linux-3.13.0/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -271,6 +271,9 @@ else omap_pm_ops.finish_suspend(save_state); + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu) + gic_dist_enable(); + /* * Restore the CPUx power state to ON otherwise CPUx * power domain can transitions to programmed low power --- linux-3.13.0.orig/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c +++ linux-3.13.0/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c @@ -209,6 +209,7 @@ .sysc_offs = 0x84, .syss_offs = 0x88, .sysc_flags = SYSS_HAS_RESET_STATUS, + .sysc_fields = &omap_hwmod_sysc_type4, }; static struct omap_hwmod_class am33xx_aes0_hwmod_class = { --- linux-3.13.0.orig/arch/arm/mach-omap2/omap_hwmod.h +++ linux-3.13.0/arch/arm/mach-omap2/omap_hwmod.h @@ -41,6 +41,7 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type1; extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2; extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type3; +extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type4; /* * OCP SYSCONFIG bit shifts/masks TYPE1. These are for IPs compliant @@ -81,6 +82,16 @@ #define SYSC_TYPE3_MIDLEMODE_SHIFT 2 #define SYSC_TYPE3_MIDLEMODE_MASK (0x3 << SYSC_TYPE3_MIDLEMODE_SHIFT) +/* + * OCP SYSCONFIG bit shifts/masks TYPE4. + */ +#define SYSC_TYPE4_SIDLEMODE_SHIFT 2 +#define SYSC_TYPE4_SIDLEMODE_MASK (0x3 << SYSC_TYPE4_SIDLEMODE_SHIFT) +#define SYSC_TYPE4_SOFTRESET_SHIFT 1 +#define SYSC_TYPE4_SOFTRESET_MASK (1 << SYSC_TYPE4_SOFTRESET_SHIFT) +#define SYSC_TYPE4_AUTOIDLE_SHIFT 0 +#define SYSC_TYPE4_AUTOIDLE_MASK (1 << SYSC_TYPE4_AUTOIDLE_SHIFT) + /* OCP SYSSTATUS bit shifts/masks */ #define SYSS_RESETDONE_SHIFT 0 #define SYSS_RESETDONE_MASK (1 << SYSS_RESETDONE_SHIFT) --- linux-3.13.0.orig/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ linux-3.13.0/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -4783,6 +4783,59 @@ .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* + Crypto modules AES0/1 belong to: + PD_L4_PER power domain + CD_L4_SEC clock domain + On the L3, the AES modules are mapped to + L3_CLK2: Peripherals and multimedia sub clock domain +*/ + +static struct omap_hwmod_class_sysconfig omap4_aes1_sysc = { + .rev_offs = 0x80, + .sysc_offs = 0x84, + .syss_offs = 0x88, + .sysc_flags = SYSS_HAS_RESET_STATUS, + .sysc_fields = &omap_hwmod_sysc_type4, +}; + +static struct omap_hwmod_class omap4_aes1_hwmod_class = { + .name = "aes1", + .sysc = &omap4_aes1_sysc, +}; + +static struct omap_hwmod omap4_aes1_hwmod = { + .name = "aes", + .class = &omap4_aes1_hwmod_class, + .clkdm_name = "l4_secure_clkdm", + .main_clk = "aes1_fck", + .prcm = { + .omap4 = { + .clkctrl_offs = OMAP4_CM_L4SEC_AES1_CLKCTRL_OFFSET, + .context_offs = OMAP4_RM_L4SEC_AES1_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + +/* l3_main_2 -> aes1 */ +static struct omap_hwmod_addr_space omap4_aes1_addrs[] = { + { + .pa_start = 0x4B500000, + .pa_end = 0x4B500000 + SZ_1M - 1, + .flags = ADDR_TYPE_RT + }, + { } +}; + +static struct omap_hwmod_ocp_if omap4_l3_main_2__aes1 = { + .master = &omap44xx_l3_main_2_hwmod, + .slave = &omap4_aes1_hwmod, + .clk = "aes1_fck", + .addr = omap4_aes1_addrs, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = { &omap44xx_l3_main_1__dmm, &omap44xx_mpu__dmm, @@ -4937,6 +4990,7 @@ &omap44xx_l4_abe__wd_timer3_dma, &omap44xx_mpu__emif1, &omap44xx_mpu__emif2, + &omap4_l3_main_2__aes1, NULL, }; --- linux-3.13.0.orig/arch/arm/mach-omap2/cpuidle44xx.c +++ linux-3.13.0/arch/arm/mach-omap2/cpuidle44xx.c @@ -80,6 +80,7 @@ int index) { struct idle_statedata *cx = state_ptr + index; + u32 mpuss_can_lose_context = 0; /* * CPU0 has to wait and stay ON until CPU1 is OFF state. @@ -104,6 +105,9 @@ } } + mpuss_can_lose_context = (cx->mpu_state == PWRDM_POWER_RET) && + (cx->mpu_logic_state == PWRDM_POWER_OFF); + /* * Call idle CPU PM enter notifier chain so that * VFP and per CPU interrupt context is saved. @@ -118,9 +122,8 @@ * Call idle CPU cluster PM enter notifier chain * to save GIC and wakeupgen context. */ - if ((cx->mpu_state == PWRDM_POWER_RET) && - (cx->mpu_logic_state == PWRDM_POWER_OFF)) - cpu_cluster_pm_enter(); + if (mpuss_can_lose_context) + cpu_cluster_pm_enter(); } omap4_enter_lowpower(dev->cpu, cx->cpu_state); @@ -128,9 +131,23 @@ /* Wakeup CPU1 only if it is not offlined */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { + + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && + mpuss_can_lose_context) + gic_dist_disable(); + clkdm_wakeup(cpu_clkdm[1]); omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON); clkdm_allow_idle(cpu_clkdm[1]); + + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && + mpuss_can_lose_context) { + while (gic_dist_disabled()) { + udelay(1); + cpu_relax(); + } + gic_timer_retrigger(); + } } /* @@ -143,8 +160,7 @@ * Call idle CPU cluster PM exit notifier chain * to restore GIC and wakeupgen context. */ - if (dev->cpu == 0 && (cx->mpu_state == PWRDM_POWER_RET) && - (cx->mpu_logic_state == PWRDM_POWER_OFF)) + if (dev->cpu == 0 && mpuss_can_lose_context) cpu_cluster_pm_exit(); fail: --- linux-3.13.0.orig/arch/arm/mach-omap2/common.h +++ linux-3.13.0/arch/arm/mach-omap2/common.h @@ -236,6 +236,7 @@ extern void __init gic_init_irq(void); extern void gic_dist_disable(void); +extern void gic_dist_enable(void); extern bool gic_dist_disabled(void); extern void gic_timer_retrigger(void); extern void omap_smc1(u32 fn, u32 arg); --- linux-3.13.0.orig/arch/arm/mach-omap2/omap4-common.c +++ linux-3.13.0/arch/arm/mach-omap2/omap4-common.c @@ -127,6 +127,12 @@ __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL); } +void gic_dist_enable(void) +{ + if (gic_dist_base_addr) + __raw_writel(0x1, gic_dist_base_addr + GIC_DIST_CTRL); +} + bool gic_dist_disabled(void) { return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1); --- linux-3.13.0.orig/arch/arm/mach-omap2/gpmc.c +++ linux-3.13.0/arch/arm/mach-omap2/gpmc.c @@ -1339,7 +1339,7 @@ of_property_read_bool(np, "gpmc,time-para-granularity"); } -#ifdef CONFIG_MTD_NAND +#if IS_ENABLED(CONFIG_MTD_NAND) static const char * const nand_xfer_types[] = { [NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled", @@ -1429,7 +1429,7 @@ } #endif -#ifdef CONFIG_MTD_ONENAND +#if IS_ENABLED(CONFIG_MTD_ONENAND) static int gpmc_probe_onenand_child(struct platform_device *pdev, struct device_node *child) { --- linux-3.13.0.orig/arch/arm/boot/dts/armada-370-xp.dtsi +++ linux-3.13.0/arch/arm/boot/dts/armada-370-xp.dtsi @@ -152,7 +152,7 @@ }; sata@a0000 { - compatible = "marvell,orion-sata"; + compatible = "marvell,armada-370-sata"; reg = <0xa0000 0x5000>; interrupts = <55>; clocks = <&gateclk 15>, <&gateclk 30>; --- linux-3.13.0.orig/arch/arm/boot/dts/at91sam9g45.dtsi +++ linux-3.13.0/arch/arm/boot/dts/at91sam9g45.dtsi @@ -618,6 +618,7 @@ compatible = "atmel,hsmci"; reg = <0xfff80000 0x600>; interrupts = <11 IRQ_TYPE_LEVEL_HIGH 0>; + pinctrl-names = "default"; dmas = <&dma 1 AT91_DMA_CFG_PER_ID(0)>; dma-names = "rxtx"; #address-cells = <1>; @@ -629,6 +630,7 @@ compatible = "atmel,hsmci"; reg = <0xfffd0000 0x600>; interrupts = <29 IRQ_TYPE_LEVEL_HIGH 0>; + pinctrl-names = "default"; dmas = <&dma 1 AT91_DMA_CFG_PER_ID(13)>; dma-names = "rxtx"; #address-cells = <1>; --- linux-3.13.0.orig/arch/arm/boot/compressed/Makefile +++ linux-3.13.0/arch/arm/boot/compressed/Makefile @@ -3,6 +3,7 @@ # # create a compressed vmlinuz image from the original vmlinux # +KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS)) -fno-stack-protector OBJS = --- linux-3.13.0.orig/arch/arm/plat-orion/irq.c +++ linux-3.13.0/arch/arm/plat-orion/irq.c @@ -15,8 +15,51 @@ #include #include #include +#include #include #include +#include + +#ifdef CONFIG_MULTI_IRQ_HANDLER +/* + * Compiling with both non-DT and DT support enabled, will + * break asm irq handler used by non-DT boards. Therefore, + * we provide a C-style irq handler even for non-DT boards, + * if MULTI_IRQ_HANDLER is set. + * + * Notes: + * - this is prepared for Kirkwood and Dove only, update + * accordingly if you add Orion5x or MV78x00. + * - Orion5x uses different macro names and has only one + * set of CAUSE/MASK registers. + * - MV78x00 uses the same macro names but has a third + * set of CAUSE/MASK registers. + * + */ + +static void __iomem *orion_irq_base = IRQ_VIRT_BASE; + +asmlinkage void +__exception_irq_entry orion_legacy_handle_irq(struct pt_regs *regs) +{ + u32 stat; + + stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_LOW_OFF); + stat &= readl_relaxed(orion_irq_base + IRQ_MASK_LOW_OFF); + if (stat) { + unsigned int hwirq = __fls(stat); + handle_IRQ(hwirq, regs); + return; + } + stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_HIGH_OFF); + stat &= readl_relaxed(orion_irq_base + IRQ_MASK_HIGH_OFF); + if (stat) { + unsigned int hwirq = 32 + __fls(stat); + handle_IRQ(hwirq, regs); + return; + } +} +#endif void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) { @@ -35,6 +78,10 @@ ct->chip.irq_unmask = irq_gc_mask_set_bit; irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); + +#ifdef CONFIG_MULTI_IRQ_HANDLER + set_handle_irq(orion_legacy_handle_irq); +#endif } #ifdef CONFIG_OF --- linux-3.13.0.orig/arch/arm/mach-at91/sam9_smc.c +++ linux-3.13.0/arch/arm/mach-at91/sam9_smc.c @@ -101,7 +101,7 @@ /* Pulse register */ val = __raw_readl(base + AT91_SMC_PULSE); - config->nwe_setup = val & AT91_SMC_NWEPULSE; + config->nwe_pulse = val & AT91_SMC_NWEPULSE; config->ncs_write_pulse = (val & AT91_SMC_NCS_WRPULSE) >> 8; config->nrd_pulse = (val & AT91_SMC_NRDPULSE) >> 16; config->ncs_read_pulse = (val & AT91_SMC_NCS_RDPULSE) >> 24; --- linux-3.13.0.orig/arch/arm/mach-tegra/tegra.c +++ linux-3.13.0/arch/arm/mach-tegra/tegra.c @@ -74,10 +74,20 @@ static void __init tegra_init_cache(void) { #ifdef CONFIG_CACHE_L2X0 + static const struct of_device_id pl310_ids[] __initconst = { + { .compatible = "arm,pl310-cache", }, + {} + }; + + struct device_node *np; int ret; void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; u32 aux_ctrl, cache_type; + np = of_find_matching_node(NULL, pl310_ids); + if (!np) + return; + cache_type = readl(p + L2X0_CACHE_TYPE); aux_ctrl = (cache_type & 0x700) << (17-8); aux_ctrl |= 0x7C400001; --- linux-3.13.0.orig/arch/arm/mach-pxa/am300epd.c +++ linux-3.13.0/arch/arm/mach-pxa/am300epd.c @@ -30,6 +30,7 @@ #include #include +#include #include #include "generic.h" --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/spitz.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/spitz.h @@ -15,8 +15,8 @@ #define __ASM_ARCH_SPITZ_H 1 #endif +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO, PXA_GPIO_TO_IRQ */ #include -#include /* Spitz/Akita GPIOs */ --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/idp.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/idp.h @@ -23,6 +23,7 @@ * IDP hardware. */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ #define IDP_FLASH_PHYS (PXA_CS0_PHYS) #define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/trizeps4.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/trizeps4.h @@ -10,6 +10,8 @@ #ifndef _TRIPEPS4_H_ #define _TRIPEPS4_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* physical memory regions */ #define TRIZEPS4_FLASH_PHYS (PXA_CS0_PHYS) /* Flash region */ #define TRIZEPS4_DISK_PHYS (PXA_CS1_PHYS) /* Disk On Chip region */ --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/gumstix.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/gumstix.h @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* BTRESET - Reset line to Bluetooth module, active low signal. */ #define GPIO_GUMSTIX_BTRESET 7 --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/pcm027.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/pcm027.h @@ -23,6 +23,8 @@ * Definitions of CPU card resources only */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* phyCORE-PXA270 (PCM027) Interrupts */ #define PCM027_IRQ(x) (IRQ_BOARD_START + (x)) #define PCM027_BTDET_IRQ PCM027_IRQ(0) --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h @@ -20,6 +20,7 @@ */ #include +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* * definitions relevant only when the PCM-990 --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/palmtc.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/palmtc.h @@ -16,6 +16,8 @@ #ifndef _INCLUDE_PALMTC_H_ #define _INCLUDE_PALMTC_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/csb726.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/csb726.h @@ -11,6 +11,8 @@ #ifndef CSB726_H #define CSB726_H +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + #define CSB726_GPIO_IRQ_LAN 52 #define CSB726_GPIO_IRQ_SM501 53 #define CSB726_GPIO_MMC_DETECT 100 --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/balloon3.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/balloon3.h @@ -14,6 +14,8 @@ #ifndef ASM_ARCH_BALLOON3_H #define ASM_ARCH_BALLOON3_H +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ + enum balloon3_features { BALLOON3_FEATURE_OHCI, BALLOON3_FEATURE_MMC, --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/palmtx.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/palmtx.h @@ -16,6 +16,8 @@ #ifndef _INCLUDE_PALMTX_H_ #define _INCLUDE_PALMTX_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/palmt5.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/palmt5.h @@ -15,6 +15,8 @@ #ifndef _INCLUDE_PALMT5_H_ #define _INCLUDE_PALMT5_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/palmld.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/palmld.h @@ -13,6 +13,8 @@ #ifndef _INCLUDE_PALMLD_H_ #define _INCLUDE_PALMLD_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/tosa.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/tosa.h @@ -13,6 +13,8 @@ #ifndef _ASM_ARCH_TOSA_H_ #define _ASM_ARCH_TOSA_H_ 1 +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ + /* TOSA Chip selects */ #define TOSA_LCDC_PHYS PXA_CS4_PHYS /* Internel Scoop */ --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/corgi.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/corgi.h @@ -13,6 +13,7 @@ #ifndef __ASM_ARCH_CORGI_H #define __ASM_ARCH_CORGI_H 1 +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ /* * Corgi (Non Standard) GPIO Definitions --- linux-3.13.0.orig/arch/arm/mach-pxa/include/mach/poodle.h +++ linux-3.13.0/arch/arm/mach-pxa/include/mach/poodle.h @@ -15,6 +15,8 @@ #ifndef __ASM_ARCH_POODLE_H #define __ASM_ARCH_POODLE_H 1 +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* * GPIOs */ --- linux-3.13.0.orig/arch/arm/mach-highbank/Makefile +++ linux-3.13.0/arch/arm/mach-highbank/Makefile @@ -1,3 +1,5 @@ +KBUILD_CFLAGS += -I$(srctree)/arch/arm/mach-highbank/include + obj-y := highbank.o system.o smc.o plus_sec := $(call as-instr,.arch_extension sec,+sec) --- linux-3.13.0.orig/arch/arm/mach-sa1100/include/mach/collie.h +++ linux-3.13.0/arch/arm/mach-sa1100/include/mach/collie.h @@ -13,6 +13,8 @@ #ifndef __ASM_ARCH_COLLIE_H #define __ASM_ARCH_COLLIE_H +#include "hardware.h" /* Gives GPIO_MAX */ + extern void locomolcd_power(int on); #define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1) --- linux-3.13.0.orig/arch/arm/kvm/mmu.c +++ linux-3.13.0/arch/arm/kvm/mmu.c @@ -145,7 +145,7 @@ pgd = pgdp + pgd_index(addr); pud = pud_offset(pgd, addr); if (pud_none(*pud)) { - addr = pud_addr_end(addr, end); + addr = kvm_pud_addr_end(addr, end); continue; } @@ -155,13 +155,13 @@ * move on. */ clear_pud_entry(kvm, pud, addr); - addr = pud_addr_end(addr, end); + addr = kvm_pud_addr_end(addr, end); continue; } pmd = pmd_offset(pud, addr); if (pmd_none(*pmd)) { - addr = pmd_addr_end(addr, end); + addr = kvm_pmd_addr_end(addr, end); continue; } @@ -176,10 +176,10 @@ */ if (kvm_pmd_huge(*pmd) || page_empty(pte)) { clear_pmd_entry(kvm, pmd, addr); - next = pmd_addr_end(addr, end); + next = kvm_pmd_addr_end(addr, end); if (page_empty(pmd) && !page_empty(pud)) { clear_pud_entry(kvm, pud, addr); - next = pud_addr_end(addr, end); + next = kvm_pud_addr_end(addr, end); } } @@ -187,6 +187,99 @@ } } +static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd, + phys_addr_t addr, phys_addr_t end) +{ + pte_t *pte; + + pte = pte_offset_kernel(pmd, addr); + do { + if (!pte_none(*pte)) { + hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT); + kvm_flush_dcache_to_poc((void*)hva, PAGE_SIZE); + } + } while (pte++, addr += PAGE_SIZE, addr != end); +} + +static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud, + phys_addr_t addr, phys_addr_t end) +{ + pmd_t *pmd; + phys_addr_t next; + + pmd = pmd_offset(pud, addr); + do { + next = kvm_pmd_addr_end(addr, end); + if (!pmd_none(*pmd)) { + if (kvm_pmd_huge(*pmd)) { + hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT); + kvm_flush_dcache_to_poc((void*)hva, PMD_SIZE); + } else { + stage2_flush_ptes(kvm, pmd, addr, next); + } + } + } while (pmd++, addr = next, addr != end); +} + +static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd, + phys_addr_t addr, phys_addr_t end) +{ + pud_t *pud; + phys_addr_t next; + + pud = pud_offset(pgd, addr); + do { + next = kvm_pud_addr_end(addr, end); + if (!pud_none(*pud)) { + if (pud_huge(*pud)) { + hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT); + kvm_flush_dcache_to_poc((void*)hva, PUD_SIZE); + } else { + stage2_flush_pmds(kvm, pud, addr, next); + } + } + } while (pud++, addr = next, addr != end); +} + +static void stage2_flush_memslot(struct kvm *kvm, + struct kvm_memory_slot *memslot) +{ + phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT; + phys_addr_t end = addr + PAGE_SIZE * memslot->npages; + phys_addr_t next; + pgd_t *pgd; + + pgd = kvm->arch.pgd + pgd_index(addr); + do { + next = kvm_pgd_addr_end(addr, end); + stage2_flush_puds(kvm, pgd, addr, next); + } while (pgd++, addr = next, addr != end); +} + +/** + * stage2_flush_vm - Invalidate cache for pages mapped in stage 2 + * @kvm: The struct kvm pointer + * + * Go through the stage 2 page tables and invalidate any cache lines + * backing memory already mapped to the VM. + */ +void stage2_flush_vm(struct kvm *kvm) +{ + struct kvm_memslots *slots; + struct kvm_memory_slot *memslot; + int idx; + + idx = srcu_read_lock(&kvm->srcu); + spin_lock(&kvm->mmu_lock); + + slots = kvm_memslots(kvm); + kvm_for_each_memslot(memslot, slots) + stage2_flush_memslot(kvm, memslot); + + spin_unlock(&kvm->mmu_lock); + srcu_read_unlock(&kvm->srcu, idx); +} + /** * free_boot_hyp_pgd - free HYP boot page tables * @@ -713,7 +806,7 @@ kvm_set_s2pmd_writable(&new_pmd); kvm_set_pfn_dirty(pfn); } - coherent_icache_guest_page(kvm, hva & PMD_MASK, PMD_SIZE); + coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE); ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd); } else { pte_t new_pte = pfn_pte(pfn, PAGE_S2); @@ -721,7 +814,7 @@ kvm_set_s2pte_writable(&new_pte); kvm_set_pfn_dirty(pfn); } - coherent_icache_guest_page(kvm, hva, PAGE_SIZE); + coherent_cache_guest_page(vcpu, hva, PAGE_SIZE); ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, false); } --- linux-3.13.0.orig/arch/arm/include/asm/cacheflush.h +++ linux-3.13.0/arch/arm/include/asm/cacheflush.h @@ -212,6 +212,7 @@ static inline void __flush_icache_all(void) { __flush_icache_preferred(); + dsb(); } /* --- linux-3.13.0.orig/arch/arm/include/asm/kvm_mmu.h +++ linux-3.13.0/arch/arm/include/asm/kvm_mmu.h @@ -114,11 +114,34 @@ pmd_val(*pmd) |= L_PMD_S2_RDWR; } +/* Open coded p*d_addr_end that can deal with 64bit addresses */ +#define kvm_pgd_addr_end(addr, end) \ +({ u64 __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \ + (__boundary - 1 < (end) - 1)? __boundary: (end); \ +}) + +#define kvm_pud_addr_end(addr,end) (end) + +#define kvm_pmd_addr_end(addr, end) \ +({ u64 __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \ + (__boundary - 1 < (end) - 1)? __boundary: (end); \ +}) + struct kvm; -static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva, - unsigned long size) +#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l)) + +static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu) { + return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101; +} + +static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, + unsigned long size) +{ + if (!vcpu_has_cache_enabled(vcpu)) + kvm_flush_dcache_to_poc((void *)hva, size); + /* * If we are going to insert an instruction page and the icache is * either VIPT or PIPT, there is a potential problem where the host @@ -139,7 +162,7 @@ } } -#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l)) +void stage2_flush_vm(struct kvm *kvm); #endif /* !__ASSEMBLY__ */ --- linux-3.13.0.orig/arch/arm/include/asm/spinlock.h +++ linux-3.13.0/arch/arm/include/asm/spinlock.h @@ -37,18 +37,9 @@ static inline void dsb_sev(void) { -#if __LINUX_ARM_ARCH__ >= 7 - __asm__ __volatile__ ( - "dsb ishst\n" - SEV - ); -#else - __asm__ __volatile__ ( - "mcr p15, 0, %0, c7, c10, 4\n" - SEV - : : "r" (0) - ); -#endif + + dsb(ishst); + __asm__(SEV); } /* --- linux-3.13.0.orig/arch/arm/include/asm/pgtable-3level.h +++ linux-3.13.0/arch/arm/include/asm/pgtable-3level.h @@ -120,13 +120,16 @@ /* * 2nd stage PTE definitions for LPAE. */ -#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x5) << 2) /* MemAttr[3:0] */ -#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */ -#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */ -#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */ -#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */ +#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x0) << 2) /* strongly ordered */ +#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* normal inner write-through */ +#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* normal inner write-back */ +#define L_PTE_S2_MT_DEV_SHARED (_AT(pteval_t, 0x1) << 2) /* device */ +#define L_PTE_S2_MT_MASK (_AT(pteval_t, 0xf) << 2) -#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */ +#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */ +#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */ + +#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */ /* * Hyp-mode PL2 PTE definitions for LPAE. --- linux-3.13.0.orig/arch/arm/include/asm/memory.h +++ linux-3.13.0/arch/arm/include/asm/memory.h @@ -30,14 +30,15 @@ */ #define UL(x) _AC(x, UL) +/* PAGE_OFFSET - the virtual address of the start of the kernel image */ +#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET) + #ifdef CONFIG_MMU /* - * PAGE_OFFSET - the virtual address of the start of the kernel image * TASK_SIZE - the maximum size of a user space task. * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area */ -#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET) #define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M)) #define TASK_UNMAPPED_BASE ALIGN(TASK_SIZE / 3, SZ_16M) @@ -104,10 +105,6 @@ #define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE) #endif -#ifndef PAGE_OFFSET -#define PAGE_OFFSET PLAT_PHYS_OFFSET -#endif - /* * The module can be at any place in ram in nommu mode. */ --- linux-3.13.0.orig/arch/arm/mm/mmu.c +++ linux-3.13.0/arch/arm/mm/mmu.c @@ -231,12 +231,16 @@ #endif /* ifdef CONFIG_CPU_CP15 / else */ #define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN +#define PROT_PTE_S2_DEVICE PROT_PTE_DEVICE #define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_AP_WRITE static struct mem_type mem_types[] = { [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED, + .prot_pte_s2 = s2_policy(PROT_PTE_S2_DEVICE) | + s2_policy(L_PTE_S2_MT_DEV_SHARED) | + L_PTE_SHARED, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_S, .domain = DOMAIN_IO, @@ -458,7 +462,8 @@ cp = &cache_policies[cachepolicy]; vecs_pgprot = kern_pgprot = user_pgprot = cp->pte; s2_pgprot = cp->pte_s2; - hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte; + hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte; + s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2; /* * ARMv6 and above have extended page tables. --- linux-3.13.0.orig/arch/arm/mm/dma-mapping.c +++ linux-3.13.0/arch/arm/mm/dma-mapping.c @@ -1358,7 +1358,7 @@ *handle = DMA_ERROR_CODE; size = PAGE_ALIGN(size); - if (gfp & GFP_ATOMIC) + if (!(gfp & __GFP_WAIT)) return __iommu_alloc_atomic(dev, size, handle); /* --- linux-3.13.0.orig/arch/arm/mm/proc-v7.S +++ linux-3.13.0/arch/arm/mm/proc-v7.S @@ -351,7 +351,6 @@ 4: mov r10, #0 mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate - dsb #ifdef CONFIG_MMU mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs v7_ttb_setup r10, r4, r8, r5 @ TTBCR, TTBRx setup @@ -360,6 +359,7 @@ mcr p15, 0, r5, c10, c2, 0 @ write PRRR mcr p15, 0, r6, c10, c2, 1 @ write NMRR #endif + dsb @ Complete invalidations #ifndef CONFIG_ARM_THUMBEE mrc p15, 0, r0, c0, c1, 0 @ read ID_PFR0 for ThumbEE and r0, r0, #(0xf << 12) @ ThumbEE enabled field --- linux-3.13.0.orig/arch/arm/mm/proc-v6.S +++ linux-3.13.0/arch/arm/mm/proc-v6.S @@ -208,7 +208,6 @@ mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer #ifdef CONFIG_MMU mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r0, c2, c0, 2 @ TTB control register @@ -218,6 +217,8 @@ ALT_UP(orr r8, r8, #TTB_FLAGS_UP) mcr p15, 0, r8, c2, c0, 1 @ load TTB1 #endif /* CONFIG_MMU */ + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer and + @ complete invalidations adr r5, v6_crval ldmia r5, {r5, r6} ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables --- linux-3.13.0.orig/arch/arm/mm/mm.h +++ linux-3.13.0/arch/arm/mm/mm.h @@ -38,6 +38,7 @@ struct mem_type { pteval_t prot_pte; + pteval_t prot_pte_s2; pmdval_t prot_l1; pmdval_t prot_sect; unsigned int domain; --- linux-3.13.0.orig/arch/arm/mm/init.c +++ linux-3.13.0/arch/arm/mm/init.c @@ -345,10 +345,11 @@ #endif #ifdef CONFIG_BLK_DEV_INITRD /* FDT scan will populate initrd_start */ - if (initrd_start) { + if (initrd_start && !phys_initrd_size) { phys_initrd_start = __virt_to_phys(initrd_start); phys_initrd_size = initrd_end - initrd_start; } + initrd_start = initrd_end = 0; if (phys_initrd_size && !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) { pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n", --- linux-3.13.0.orig/arch/arm/mach-imx/clk-imx6sl.c +++ linux-3.13.0/arch/arm/mach-imx/clk-imx6sl.c @@ -261,6 +261,9 @@ clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); } + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt"); base = of_iomap(np, 0); WARN_ON(!base); --- linux-3.13.0.orig/arch/arm/mach-imx/pm-imx6q.c +++ linux-3.13.0/arch/arm/mach-imx/pm-imx6q.c @@ -228,8 +228,6 @@ regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT, IMX6Q_GPR1_GINT); - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); suspend_set_ops(&imx6q_pm_ops); } --- linux-3.13.0.orig/arch/arm/mach-imx/Makefile +++ linux-3.13.0/arch/arm/mach-imx/Makefile @@ -100,11 +100,9 @@ obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o -ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o # i.MX6SL reuses i.MX6Q code obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o -endif # i.MX5 based machines obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o --- linux-3.13.0.orig/arch/arm/mach-imx/clk-imx6q.c +++ linux-3.13.0/arch/arm/mach-imx/clk-imx6q.c @@ -479,6 +479,9 @@ if (IS_ENABLED(CONFIG_PCI_IMX6)) clk_set_parent(clk[lvds1_sel], clk[sata_ref]); + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); base = of_iomap(np, 0); WARN_ON(!base); --- linux-3.13.0.orig/arch/arm/mach-imx/common.h +++ linux-3.13.0/arch/arm/mach-imx/common.h @@ -143,13 +143,11 @@ void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); -#ifdef CONFIG_PM void imx6q_pm_init(void); void imx6q_pm_set_ccm_base(void __iomem *base); +#ifdef CONFIG_PM void imx5_pm_init(void); #else -static inline void imx6q_pm_init(void) {} -static inline void imx6q_pm_set_ccm_base(void __iomem *base) {} static inline void imx5_pm_init(void) {} #endif --- linux-3.13.0.orig/arch/arm/mach-mvebu/armada-370-xp.c +++ linux-3.13.0/arch/arm/mach-mvebu/armada-370-xp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include "armada-370-xp.h" #include "common.h" #include "coherency.h" +#include "mvebu-soc-id.h" static void __init armada_370_xp_map_io(void) { @@ -45,8 +47,38 @@ #endif } +static void __init i2c_quirk(void) +{ + struct device_node *np; + u32 dev, rev; + + /* + * Only revisons more recent than A0 support the offload + * mechanism. We can exit only if we are sure that we can + * get the SoC revision and it is more recent than A0. + */ + if (mvebu_get_soc_id(&rev, &dev) == 0 && dev > MV78XX0_A0_REV) + return; + + for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") { + struct property *new_compat; + + new_compat = kzalloc(sizeof(*new_compat), GFP_KERNEL); + + new_compat->name = kstrdup("compatible", GFP_KERNEL); + new_compat->length = sizeof("marvell,mv78230-a0-i2c"); + new_compat->value = kstrdup("marvell,mv78230-a0-i2c", + GFP_KERNEL); + + of_update_property(np, new_compat); + } + return; +} + static void __init armada_370_xp_dt_init(void) { + if (of_machine_is_compatible("plathome,openblocks-ax3-4")) + i2c_quirk(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } --- linux-3.13.0.orig/arch/arm/mach-mvebu/Makefile +++ linux-3.13.0/arch/arm/mach-mvebu/Makefile @@ -3,7 +3,7 @@ AFLAGS_coherency_ll.o := -Wa,-march=armv7-a -obj-y += system-controller.o +obj-y += system-controller.o mvebu-soc-id.o obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o --- linux-3.13.0.orig/arch/arm/mach-mvebu/mvebu-soc-id.c +++ linux-3.13.0/arch/arm/mach-mvebu/mvebu-soc-id.c @@ -0,0 +1,119 @@ +/* + * ID and revision information for mvebu SoCs + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * All the mvebu SoCs have information related to their variant and + * revision that can be read from the PCI control register. This is + * done before the PCI initialization to avoid any conflict. Once the + * ID and revision are retrieved, the mapping is freed. + */ + +#define pr_fmt(fmt) "mvebu-soc-id: " fmt + +#include +#include +#include +#include +#include +#include +#include "mvebu-soc-id.h" + +#define PCIE_DEV_ID_OFF 0x0 +#define PCIE_DEV_REV_OFF 0x8 + +#define SOC_ID_MASK 0xFFFF0000 +#define SOC_REV_MASK 0xFF + +static u32 soc_dev_id; +static u32 soc_rev; +static bool is_id_valid; + +static const struct of_device_id mvebu_pcie_of_match_table[] = { + { .compatible = "marvell,armada-xp-pcie", }, + { .compatible = "marvell,armada-370-pcie", }, + {}, +}; + +int mvebu_get_soc_id(u32 *dev, u32 *rev) +{ + if (is_id_valid) { + *dev = soc_dev_id; + *rev = soc_rev; + return 0; + } else + return -1; +} + +static int __init mvebu_soc_id_init(void) +{ + struct device_node *np; + int ret = 0; + void __iomem *pci_base; + struct clk *clk; + struct device_node *child; + + np = of_find_matching_node(NULL, mvebu_pcie_of_match_table); + if (!np) + return ret; + + /* + * ID and revision are available from any port, so we + * just pick the first one + */ + child = of_get_next_child(np, NULL); + if (child == NULL) { + pr_err("cannot get pci node\n"); + ret = -ENOMEM; + goto clk_err; + } + + clk = of_clk_get_by_name(child, NULL); + if (IS_ERR(clk)) { + pr_err("cannot get clock\n"); + ret = -ENOMEM; + goto clk_err; + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("cannot enable clock\n"); + goto clk_err; + } + + pci_base = of_iomap(child, 0); + if (pci_base == NULL) { + pr_err("cannot map registers\n"); + ret = -ENOMEM; + goto res_ioremap; + } + + /* SoC ID */ + soc_dev_id = readl(pci_base + PCIE_DEV_ID_OFF) >> 16; + + /* SoC revision */ + soc_rev = readl(pci_base + PCIE_DEV_REV_OFF) & SOC_REV_MASK; + + is_id_valid = true; + + pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev); + + iounmap(pci_base); + +res_ioremap: + clk_disable_unprepare(clk); + +clk_err: + of_node_put(child); + of_node_put(np); + + return ret; +} +core_initcall(mvebu_soc_id_init); + --- linux-3.13.0.orig/arch/arm/mach-mvebu/mvebu-soc-id.h +++ linux-3.13.0/arch/arm/mach-mvebu/mvebu-soc-id.h @@ -0,0 +1,32 @@ +/* + * Marvell EBU SoC ID and revision definitions. + * + * Copyright (C) 2014 Marvell Semiconductor + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __LINUX_MVEBU_SOC_ID_H +#define __LINUX_MVEBU_SOC_ID_H + +/* Armada XP ID */ +#define MV78230_DEV_ID 0x7823 +#define MV78260_DEV_ID 0x7826 +#define MV78460_DEV_ID 0x7846 + +/* Armada XP Revision */ +#define MV78XX0_A0_REV 0x1 +#define MV78XX0_B0_REV 0x2 + +#ifdef CONFIG_ARCH_MVEBU +int mvebu_get_soc_id(u32 *dev, u32 *rev); +#else +static inline int mvebu_get_soc_id(u32 *dev, u32 *rev) +{ + return -1; +} +#endif + +#endif /* __LINUX_MVEBU_SOC_ID_H */ --- linux-3.13.0.orig/arch/sh/kernel/kgdb.c +++ linux-3.13.0/arch/sh/kernel/kgdb.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include --- linux-3.13.0.orig/arch/mips/include/asm/syscall.h +++ linux-3.13.0/arch/mips/include/asm/syscall.h @@ -29,7 +29,7 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg, struct task_struct *task, struct pt_regs *regs, unsigned int n) { - unsigned long usp = regs->regs[29]; + unsigned long usp __maybe_unused = regs->regs[29]; switch (n) { case 0: case 1: case 2: case 3: --- linux-3.13.0.orig/arch/mips/include/asm/mipsregs.h +++ linux-3.13.0/arch/mips/include/asm/mipsregs.h @@ -14,6 +14,7 @@ #define _ASM_MIPSREGS_H #include +#include #include #include --- linux-3.13.0.orig/arch/avr32/Makefile +++ linux-3.13.0/arch/avr32/Makefile @@ -11,7 +11,7 @@ KBUILD_DEFCONFIG := atstk1002_defconfig -KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic +KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic -D__linux__ KBUILD_AFLAGS += -mrelax -mno-pic KBUILD_CFLAGS_MODULE += -mno-relax LDFLAGS_vmlinux += --relax --- linux-3.13.0.orig/arch/avr32/boards/mimc200/fram.c +++ linux-3.13.0/arch/avr32/boards/mimc200/fram.c @@ -11,6 +11,7 @@ #define FRAM_VERSION "1.0" #include +#include #include #include #include --- linux-3.13.0.orig/arch/x86/Kconfig +++ linux-3.13.0/arch/x86/Kconfig @@ -2397,6 +2397,8 @@ source "drivers/Kconfig" +source "ubuntu/Kconfig" + source "drivers/firmware/Kconfig" source "fs/Kconfig" --- linux-3.13.0.orig/arch/x86/boot/video.h +++ linux-3.13.0/arch/x86/boot/video.h @@ -80,7 +80,7 @@ u16 xmode_n; /* Size of unprobed mode range */ }; -#define __videocard struct card_info __attribute__((section(".videocards"))) +#define __videocard struct card_info __attribute__((used,section(".videocards"))) extern struct card_info video_cards[], video_cards_end[]; int mode_defined(u16 mode); /* video.c */ --- linux-3.13.0.orig/arch/x86/boot/cpucheck.c +++ linux-3.13.0/arch/x86/boot/cpucheck.c @@ -69,6 +69,13 @@ cpu_vendor[2] == A32('M', 'x', '8', '6'); } +static int is_intel(void) +{ + return cpu_vendor[0] == A32('G', 'e', 'n', 'u') && + cpu_vendor[1] == A32('i', 'n', 'e', 'I') && + cpu_vendor[2] == A32('n', 't', 'e', 'l'); +} + static int has_fpu(void) { u16 fcw = -1, fsw = -1; @@ -239,6 +246,24 @@ asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); err = check_flags(); + } else if (err == 0x01 && + !(err_flags[0] & ~(1 << X86_FEATURE_PAE)) && + is_intel() && cpu.level == 6 && + (cpu.model == 9 || cpu.model == 13)) { + /* PAE is disabled on this Pentium M but can be forced */ + if (cmdline_find_option_bool("forcepae")) { + puts("WARNING: Forcing PAE in CPU flags\n"); + set_bit(X86_FEATURE_PAE, cpu.flags); + err = check_flags(); + } + else { + puts("ERROR: PAE is disabled on this Pentium M\n" + "(PAE can potentially be enabled with " + "kernel parameter\n" + "\"forcepae\" - this is unsupported, may " + "cause unknown\n" + "problems, and will taint the kernel)\n"); + } } if (err_flags_ptr) --- linux-3.13.0.orig/arch/x86/xen/platform-pci-unplug.c +++ linux-3.13.0/arch/x86/xen/platform-pci-unplug.c @@ -69,6 +69,80 @@ return 0; } +bool xen_has_pv_devices() +{ + if (!xen_domain()) + return false; + + /* PV domains always have them. */ + if (xen_pv_domain()) + return true; + + /* And user has xen_platform_pci=0 set in guest config as + * driver did not modify the value. */ + if (xen_platform_pci_unplug == 0) + return false; + + if (xen_platform_pci_unplug & XEN_UNPLUG_NEVER) + return false; + + if (xen_platform_pci_unplug & XEN_UNPLUG_ALL) + return true; + + /* This is an odd one - we are going to run legacy + * and PV drivers at the same time. */ + if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY) + return true; + + /* And the caller has to follow with xen_pv_{disk,nic}_devices + * to be certain which driver can load. */ + return false; +} +EXPORT_SYMBOL_GPL(xen_has_pv_devices); + +static bool __xen_has_pv_device(int state) +{ + /* HVM domains might or might not */ + if (xen_hvm_domain() && (xen_platform_pci_unplug & state)) + return true; + + return xen_has_pv_devices(); +} + +bool xen_has_pv_nic_devices(void) +{ + return __xen_has_pv_device(XEN_UNPLUG_ALL_NICS | XEN_UNPLUG_ALL); +} +EXPORT_SYMBOL_GPL(xen_has_pv_nic_devices); + +bool xen_has_pv_disk_devices(void) +{ + return __xen_has_pv_device(XEN_UNPLUG_ALL_IDE_DISKS | + XEN_UNPLUG_AUX_IDE_DISKS | XEN_UNPLUG_ALL); +} +EXPORT_SYMBOL_GPL(xen_has_pv_disk_devices); + +/* + * This one is odd - it determines whether you want to run PV _and_ + * legacy (IDE) drivers together. This combination is only possible + * under HVM. + */ +bool xen_has_pv_and_legacy_disk_devices(void) +{ + if (!xen_domain()) + return false; + + /* N.B. This is only ever used in HVM mode */ + if (xen_pv_domain()) + return false; + + if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(xen_has_pv_and_legacy_disk_devices); + void xen_unplug_emulated_devices(void) { int r; --- linux-3.13.0.orig/arch/x86/xen/mmu.c +++ linux-3.13.0/arch/x86/xen/mmu.c @@ -365,7 +365,7 @@ /* Assume pteval_t is equivalent to all the other *val_t types. */ static pteval_t pte_mfn_to_pfn(pteval_t val) { - if (val & _PAGE_PRESENT) { + if (pteval_present(val)) { unsigned long mfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; unsigned long pfn = mfn_to_pfn(mfn); @@ -381,7 +381,7 @@ static pteval_t pte_pfn_to_mfn(pteval_t val) { - if (val & _PAGE_PRESENT) { + if (pteval_present(val)) { unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; pteval_t flags = val & PTE_FLAGS_MASK; unsigned long mfn; --- linux-3.13.0.orig/arch/x86/platform/efi/efi_32.c +++ linux-3.13.0/arch/x86/platform/efi/efi_32.c @@ -37,9 +37,16 @@ * claim EFI runtime service handler exclusively and to duplicate a memory in * low memory space say 0 - 3G. */ - static unsigned long efi_rt_eflags; +void efi_sync_low_kernel_mappings(void) {} +void efi_setup_page_tables(void) {} + +void __init efi_map_region(efi_memory_desc_t *md) +{ + old_map_region(md); +} + void efi_call_phys_prelog(void) { struct desc_ptr gdt_descr; --- linux-3.13.0.orig/arch/x86/platform/efi/efi_stub_64.S +++ linux-3.13.0/arch/x86/platform/efi/efi_stub_64.S @@ -34,10 +34,47 @@ mov %rsi, %cr0; \ mov (%rsp), %rsp + /* stolen from gcc */ + .macro FLUSH_TLB_ALL + movq %r15, efi_scratch(%rip) + movq %r14, efi_scratch+8(%rip) + movq %cr4, %r15 + movq %r15, %r14 + andb $0x7f, %r14b + movq %r14, %cr4 + movq %r15, %cr4 + movq efi_scratch+8(%rip), %r14 + movq efi_scratch(%rip), %r15 + .endm + + .macro SWITCH_PGT + cmpb $0, efi_scratch+24(%rip) + je 1f + movq %r15, efi_scratch(%rip) # r15 + # save previous CR3 + movq %cr3, %r15 + movq %r15, efi_scratch+8(%rip) # prev_cr3 + movq efi_scratch+16(%rip), %r15 # EFI pgt + movq %r15, %cr3 + 1: + .endm + + .macro RESTORE_PGT + cmpb $0, efi_scratch+24(%rip) + je 2f + movq efi_scratch+8(%rip), %r15 + movq %r15, %cr3 + movq efi_scratch(%rip), %r15 + FLUSH_TLB_ALL + 2: + .endm + ENTRY(efi_call0) SAVE_XMM subq $32, %rsp + SWITCH_PGT call *%rdi + RESTORE_PGT addq $32, %rsp RESTORE_XMM ret @@ -47,7 +84,9 @@ SAVE_XMM subq $32, %rsp mov %rsi, %rcx + SWITCH_PGT call *%rdi + RESTORE_PGT addq $32, %rsp RESTORE_XMM ret @@ -57,7 +96,9 @@ SAVE_XMM subq $32, %rsp mov %rsi, %rcx + SWITCH_PGT call *%rdi + RESTORE_PGT addq $32, %rsp RESTORE_XMM ret @@ -68,7 +109,9 @@ subq $32, %rsp mov %rcx, %r8 mov %rsi, %rcx + SWITCH_PGT call *%rdi + RESTORE_PGT addq $32, %rsp RESTORE_XMM ret @@ -80,7 +123,9 @@ mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx + SWITCH_PGT call *%rdi + RESTORE_PGT addq $32, %rsp RESTORE_XMM ret @@ -93,7 +138,9 @@ mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx + SWITCH_PGT call *%rdi + RESTORE_PGT addq $48, %rsp RESTORE_XMM ret @@ -109,8 +156,15 @@ mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx + SWITCH_PGT call *%rdi + RESTORE_PGT addq $48, %rsp RESTORE_XMM ret ENDPROC(efi_call6) + + .data +ENTRY(efi_scratch) + .fill 3,8,0 + .byte 0 --- linux-3.13.0.orig/arch/x86/platform/efi/efi.c +++ linux-3.13.0/arch/x86/platform/efi/efi.c @@ -12,6 +12,8 @@ * Bibo Mao * Chandramouli Narayanan * Huang Ying + * Copyright (C) 2013 SuSE Labs + * Borislav Petkov - runtime services VA mapping * * Copied from efi_32.c to eliminate the duplicated code between EFI * 32/64 support code. --ying 2007-10-26 @@ -436,7 +438,7 @@ * - Not within any part of the kernel * - Not the bios reserved area */ - if ((start+size >= __pa_symbol(_text) + if ((start + size > __pa_symbol(_text) && start <= __pa_symbol(_end)) || !e820_all_mapped(start, start+size, E820_RAM) || memblock_is_region_reserved(start, size)) { @@ -741,21 +743,56 @@ set_memory_uc(addr, npages); } +void __init old_map_region(efi_memory_desc_t *md) +{ + u64 start_pfn, end_pfn, end; + unsigned long size; + void *va; + + start_pfn = PFN_DOWN(md->phys_addr); + size = md->num_pages << PAGE_SHIFT; + end = md->phys_addr + size; + end_pfn = PFN_UP(end); + + if (pfn_range_is_mapped(start_pfn, end_pfn)) { + va = __va(md->phys_addr); + + if (!(md->attribute & EFI_MEMORY_WB)) + efi_memory_uc((u64)(unsigned long)va, size); + } else + va = efi_ioremap(md->phys_addr, size, + md->type, md->attribute); + + md->virt_addr = (u64) (unsigned long) va; + if (!va) + pr_err("ioremap of 0x%llX failed!\n", + (unsigned long long)md->phys_addr); +} + /* * This function will switch the EFI runtime services to virtual mode. - * Essentially, look through the EFI memmap and map every region that - * has the runtime attribute bit set in its memory descriptor and update - * that memory descriptor with the virtual address obtained from ioremap(). - * This enables the runtime services to be called without having to + * Essentially, we look through the EFI memmap and map every region that + * has the runtime attribute bit set in its memory descriptor into the + * ->trampoline_pgd page table using a top-down VA allocation scheme. + * + * The old method which used to update that memory descriptor with the + * virtual address obtained from ioremap() is still supported when the + * kernel is booted with efi=old_map on its command line. Same old + * method enabled the runtime services to be called without having to * thunk back into physical mode for every invocation. + * + * The new method does a pagetable switch in a preemption-safe manner + * so that we're in a different address space when calling a runtime + * function. For function arguments passing we do copy the PGDs of the + * kernel page table into ->trampoline_pgd prior to each call. */ void __init efi_enter_virtual_mode(void) { efi_memory_desc_t *md, *prev_md = NULL; - efi_status_t status; + void *p, *new_memmap = NULL; unsigned long size; - u64 end, systab, start_pfn, end_pfn; - void *p, *va, *new_memmap = NULL; + efi_status_t status; + u64 end, systab; int count = 0; efi.systab = NULL; @@ -764,7 +801,6 @@ * We don't do virtual mode, since we don't do runtime services, on * non-native EFI */ - if (!efi_is_native()) { efi_unmap_memmap(); return; @@ -795,6 +831,7 @@ continue; } prev_md = md; + } for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { @@ -807,36 +844,24 @@ continue; } + efi_map_region(md); + size = md->num_pages << EFI_PAGE_SHIFT; end = md->phys_addr + size; - start_pfn = PFN_DOWN(md->phys_addr); - end_pfn = PFN_UP(end); - if (pfn_range_is_mapped(start_pfn, end_pfn)) { - va = __va(md->phys_addr); - - if (!(md->attribute & EFI_MEMORY_WB)) - efi_memory_uc((u64)(unsigned long)va, size); - } else - va = efi_ioremap(md->phys_addr, size, - md->type, md->attribute); - - md->virt_addr = (u64) (unsigned long) va; - - if (!va) { - pr_err("ioremap of 0x%llX failed!\n", - (unsigned long long)md->phys_addr); - continue; - } - systab = (u64) (unsigned long) efi_phys.systab; if (md->phys_addr <= systab && systab < end) { systab += md->virt_addr - md->phys_addr; + efi.systab = (efi_system_table_t *) (unsigned long) systab; } + new_memmap = krealloc(new_memmap, (count + 1) * memmap.desc_size, GFP_KERNEL); + if (!new_memmap) + goto err_out; + memcpy(new_memmap + (count * memmap.desc_size), md, memmap.desc_size); count++; @@ -844,6 +869,9 @@ BUG_ON(!efi.systab); + efi_setup_page_tables(); + efi_sync_low_kernel_mappings(); + status = phys_efi_set_virtual_address_map( memmap.desc_size * count, memmap.desc_size, @@ -876,7 +904,8 @@ efi.query_variable_info = virt_efi_query_variable_info; efi.update_capsule = virt_efi_update_capsule; efi.query_capsule_caps = virt_efi_query_capsule_caps; - if (__supported_pte_mask & _PAGE_NX) + + if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX)) runtime_code_page_mkexec(); kfree(new_memmap); @@ -887,6 +916,11 @@ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); + + return; + + err_out: + pr_err("Error reallocating memory, EFI runtime non-functional!\n"); } /* @@ -1006,3 +1040,15 @@ return EFI_SUCCESS; } EXPORT_SYMBOL_GPL(efi_query_variable_store); + +static int __init parse_efi_cmdline(char *str) +{ + if (*str == '=') + str++; + + if (!strncmp(str, "old_map", 7)) + set_bit(EFI_OLD_MEMMAP, &x86_efi_facility); + + return 0; +} +early_param("efi", parse_efi_cmdline); --- linux-3.13.0.orig/arch/x86/platform/efi/efi_64.c +++ linux-3.13.0/arch/x86/platform/efi/efi_64.c @@ -38,10 +38,28 @@ #include #include #include +#include static pgd_t *save_pgd __initdata; static unsigned long efi_flags __initdata; +/* + * We allocate runtime services regions bottom-up, starting from -4G, i.e. + * 0xffff_ffff_0000_0000 and limit EFI VA mapping space to 64G. + */ +static u64 efi_va = -4 * (1UL << 30); +#define EFI_VA_END (-68 * (1UL << 30)) + +/* + * Scratch space used for switching the pagetable in the EFI stub + */ +struct efi_scratch { + u64 r15; + u64 prev_cr3; + pgd_t *efi_pgt; + bool use_pgd; +}; + static void __init early_code_mapping_set_exec(int executable) { efi_memory_desc_t *md; @@ -65,6 +83,9 @@ int pgd; int n_pgds; + if (!efi_enabled(EFI_OLD_MEMMAP)) + return; + early_code_mapping_set_exec(1); local_irq_save(efi_flags); @@ -86,6 +107,10 @@ */ int pgd; int n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE); + + if (!efi_enabled(EFI_OLD_MEMMAP)) + return; + for (pgd = 0; pgd < n_pgds; pgd++) set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]); kfree(save_pgd); @@ -94,6 +119,90 @@ early_code_mapping_set_exec(0); } +/* + * Add low kernel mappings for passing arguments to EFI functions. + */ +void efi_sync_low_kernel_mappings(void) +{ + unsigned num_pgds; + pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd); + + if (efi_enabled(EFI_OLD_MEMMAP)) + return; + + num_pgds = pgd_index(MODULES_END - 1) - pgd_index(PAGE_OFFSET); + + memcpy(pgd + pgd_index(PAGE_OFFSET), + init_mm.pgd + pgd_index(PAGE_OFFSET), + sizeof(pgd_t) * num_pgds); +} + +void efi_setup_page_tables(void) +{ + efi_scratch.efi_pgt = (pgd_t *)(unsigned long)real_mode_header->trampoline_pgd; + + if (!efi_enabled(EFI_OLD_MEMMAP)) + efi_scratch.use_pgd = true; +} + +static void __init __map_region(efi_memory_desc_t *md, u64 va) +{ + pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd); + unsigned long pf = 0, size; + u64 end; + + if (!(md->attribute & EFI_MEMORY_WB)) + pf |= _PAGE_PCD; + + size = md->num_pages << PAGE_SHIFT; + end = va + size; + + if (kernel_map_pages_in_pgd(pgd, md->phys_addr, va, md->num_pages, pf)) + pr_warn("Error mapping PA 0x%llx -> VA 0x%llx!\n", + md->phys_addr, va); +} + +void __init efi_map_region(efi_memory_desc_t *md) +{ + unsigned long size = md->num_pages << PAGE_SHIFT; + u64 pa = md->phys_addr; + + if (efi_enabled(EFI_OLD_MEMMAP)) + return old_map_region(md); + + /* + * Make sure the 1:1 mappings are present as a catch-all for b0rked + * firmware which doesn't update all internal pointers after switching + * to virtual mode and would otherwise crap on us. + */ + __map_region(md, md->phys_addr); + + efi_va -= size; + + /* Is PA 2M-aligned? */ + if (!(pa & (PMD_SIZE - 1))) { + efi_va &= PMD_MASK; + } else { + u64 pa_offset = pa & (PMD_SIZE - 1); + u64 prev_va = efi_va; + + /* get us the same offset within this 2M page */ + efi_va = (efi_va & PMD_MASK) + pa_offset; + + if (efi_va > prev_va) + efi_va -= PMD_SIZE; + } + + if (efi_va < EFI_VA_END) { + pr_warn(FW_WARN "VA address range overflow!\n"); + return; + } + + /* Do the VA map */ + __map_region(md, efi_va); + md->virt_addr = efi_va; +} + void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, u32 type, u64 attribute) { --- linux-3.13.0.orig/arch/x86/net/bpf_jit.S +++ linux-3.13.0/arch/x86/net/bpf_jit.S @@ -140,7 +140,7 @@ push %r9; \ push SKBDATA; \ /* rsi already has offset */ \ - mov $SIZE,%ecx; /* size */ \ + mov $SIZE,%edx; /* size */ \ call bpf_internal_load_pointer_neg_helper; \ test %rax,%rax; \ pop SKBDATA; \ --- linux-3.13.0.orig/arch/x86/kvm/i8254.c +++ linux-3.13.0/arch/x86/kvm/i8254.c @@ -37,6 +37,7 @@ #include "irq.h" #include "i8254.h" +#include "x86.h" #ifndef CONFIG_X86_64 #define mod_64(x, y) ((x) - (y) * div64_u64(x, y)) @@ -349,6 +350,23 @@ atomic_set(&ps->pending, 0); ps->irq_ack = 1; + /* + * Do not allow the guest to program periodic timers with small + * interval, since the hrtimers are not throttled by the host + * scheduler. + */ + if (ps->is_periodic) { + s64 min_period = min_timer_period_us * 1000LL; + + if (ps->period < min_period) { + pr_info_ratelimited( + "kvm: requested %lld ns " + "i8254 timer period limited to %lld ns\n", + ps->period, min_period); + ps->period = min_period; + } + } + hrtimer_start(&ps->timer, ktime_add_ns(ktime_get(), interval), HRTIMER_MODE_ABS); } --- linux-3.13.0.orig/arch/x86/kvm/lapic.c +++ linux-3.13.0/arch/x86/kvm/lapic.c @@ -71,9 +71,6 @@ #define VEC_POS(v) ((v) & (32 - 1)) #define REG_POS(v) (((v) >> 5) << 4) -static unsigned int min_timer_period_us = 500; -module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR); - static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) { *((u32 *) (apic->regs + reg_off)) = val; --- linux-3.13.0.orig/arch/x86/kvm/paging_tmpl.h +++ linux-3.13.0/arch/x86/kvm/paging_tmpl.h @@ -569,6 +569,9 @@ if (FNAME(gpte_changed)(vcpu, gw, top_level)) goto out_gpte_changed; + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + goto out_gpte_changed; + for (shadow_walk_init(&it, vcpu, addr); shadow_walk_okay(&it) && it.level > gw->level; shadow_walk_next(&it)) { @@ -820,6 +823,11 @@ */ mmu_topup_memory_caches(vcpu); + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) { + WARN_ON(1); + return; + } + spin_lock(&vcpu->kvm->mmu_lock); for_each_shadow_entry(vcpu, gva, iterator) { level = iterator.level; --- linux-3.13.0.orig/arch/x86/kvm/mmu.c +++ linux-3.13.0/arch/x86/kvm/mmu.c @@ -2659,6 +2659,9 @@ int emulate = 0; gfn_t pseudo_gfn; + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + return 0; + for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) { if (iterator.level == level) { mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, @@ -2829,6 +2832,9 @@ bool ret = false; u64 spte = 0ull; + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + return false; + if (!page_fault_can_be_fast(error_code)) return false; @@ -3224,6 +3230,9 @@ struct kvm_shadow_walk_iterator iterator; u64 spte = 0ull; + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + return spte; + walk_shadow_page_lockless_begin(vcpu); for_each_shadow_entry_lockless(vcpu, addr, iterator, spte) if (!is_shadow_present_pte(spte)) @@ -4510,6 +4519,9 @@ u64 spte; int nr_sptes = 0; + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + return nr_sptes; + walk_shadow_page_lockless_begin(vcpu); for_each_shadow_entry_lockless(vcpu, addr, iterator, spte) { sptes[iterator.level-1] = spte; --- linux-3.13.0.orig/arch/x86/kvm/vmx.c +++ linux-3.13.0/arch/x86/kvm/vmx.c @@ -6644,7 +6644,7 @@ else if (is_page_fault(intr_info)) return enable_ept; else if (is_no_device(intr_info) && - !(nested_read_cr0(vmcs12) & X86_CR0_TS)) + !(vmcs12->guest_cr0 & X86_CR0_TS)) return 0; return vmcs12->exception_bitmap & (1u << (intr_info & INTR_INFO_VECTOR_MASK)); @@ -7332,8 +7332,8 @@ struct vcpu_vmx *vmx = to_vmx(vcpu); free_vpid(vmx); - free_nested(vmx); free_loaded_vmcs(vmx->loaded_vmcs); + free_nested(vmx); kfree(vmx->guest_msrs); kvm_vcpu_uninit(vcpu); kmem_cache_free(kvm_vcpu_cache, vmx); --- linux-3.13.0.orig/arch/x86/kvm/svm.c +++ linux-3.13.0/arch/x86/kvm/svm.c @@ -2989,10 +2989,8 @@ u8 cr8_prev = kvm_get_cr8(&svm->vcpu); /* instruction emulation calls kvm_set_cr8() */ r = cr_interception(svm); - if (irqchip_in_kernel(svm->vcpu.kvm)) { - clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); + if (irqchip_in_kernel(svm->vcpu.kvm)) return r; - } if (cr8_prev <= kvm_get_cr8(&svm->vcpu)) return r; kvm_run->exit_reason = KVM_EXIT_SET_TPR; @@ -3554,6 +3552,8 @@ if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK)) return; + clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); + if (irr == -1) return; --- linux-3.13.0.orig/arch/x86/kvm/x86.c +++ linux-3.13.0/arch/x86/kvm/x86.c @@ -94,6 +94,9 @@ static bool ignore_msrs = 0; module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR); +unsigned int min_timer_period_us = 500; +module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR); + bool kvm_has_tsc_control; EXPORT_SYMBOL_GPL(kvm_has_tsc_control); u32 kvm_max_guest_tsc_khz; @@ -5499,7 +5502,7 @@ goto out; } if (ops->disabled_by_bios()) { - printk(KERN_ERR "kvm: disabled by bios\n"); + printk(KERN_WARNING "kvm: disabled by bios\n"); r = -EOPNOTSUPP; goto out; } @@ -6089,6 +6092,20 @@ } if (need_resched()) { srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx); +#ifdef CONFIG_X86_32 + /* + * This is a hack around a current bug on i386 + * that causes TIF_NEED_RESCHED not being propagated + * into the per-cpu counter. This causes cond_resched() + * which is what kvm_resched() calls to exit without + * actually rescheduling. We continue immediately with + * the loop but vcpu_enter_guest checks for the process + * flag and immediately exits and this loops busily + * runs forever. + */ + if (tif_need_resched()) + set_preempt_need_resched(); +#endif kvm_resched(vcpu); vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); } @@ -6160,7 +6177,7 @@ frag->len -= len; } - if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) { + if (vcpu->mmio_cur_fragment >= vcpu->mmio_nr_fragments) { vcpu->mmio_needed = 0; /* FIXME: return into emulator if single-stepping. */ --- linux-3.13.0.orig/arch/x86/kvm/x86.h +++ linux-3.13.0/arch/x86/kvm/x86.h @@ -125,5 +125,7 @@ #define KVM_SUPPORTED_XCR0 (XSTATE_FP | XSTATE_SSE | XSTATE_YMM) extern u64 host_xcr0; +extern unsigned int min_timer_period_us; + extern struct static_key kvm_no_apic_vcpu; #endif --- linux-3.13.0.orig/arch/x86/kernel/i387.c +++ linux-3.13.0/arch/x86/kernel/i387.c @@ -86,10 +86,19 @@ void __kernel_fpu_end(void) { - if (use_eager_fpu()) - math_state_restore(); - else + if (use_eager_fpu()) { + /* + * For eager fpu, most the time, tsk_used_math() is true. + * Restore the user math as we are done with the kernel usage. + * At few instances during thread exit, signal handling etc, + * tsk_used_math() is false. Those few places will take proper + * actions, so we don't need to restore the math here. + */ + if (likely(tsk_used_math(current))) + math_state_restore(); + } else { stts(); + } } EXPORT_SYMBOL(__kernel_fpu_end); --- linux-3.13.0.orig/arch/x86/kernel/pci-dma.c +++ linux-3.13.0/arch/x86/kernel/pci-dma.c @@ -100,8 +100,10 @@ flag |= __GFP_ZERO; again: page = NULL; - if (!(flag & GFP_ATOMIC)) + /* CMA can be used only in the context which permits sleeping */ + if (flag & __GFP_WAIT) page = dma_alloc_from_contiguous(dev, count, get_order(size)); + /* fallback */ if (!page) page = alloc_pages_node(dev_to_node(dev), flag, get_order(size)); if (!page) --- linux-3.13.0.orig/arch/x86/kernel/head_64.S +++ linux-3.13.0/arch/x86/kernel/head_64.S @@ -343,6 +343,9 @@ ENTRY(early_idt_handler) cld + cmpl $2,(%rsp) # X86_TRAP_NMI + je is_nmi # Ignore NMI + cmpl $2,early_recursion_flag(%rip) jz 1f incl early_recursion_flag(%rip) @@ -405,8 +408,9 @@ popq %rdx popq %rcx popq %rax - addq $16,%rsp # drop vector number and error code decl early_recursion_flag(%rip) +is_nmi: + addq $16,%rsp # drop vector number and error code INTERRUPT_RETURN ENDPROC(early_idt_handler) --- linux-3.13.0.orig/arch/x86/kernel/reboot.c +++ linux-3.13.0/arch/x86/kernel/reboot.c @@ -385,7 +385,46 @@ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), }, }, - + { /* Handle problems with rebooting on the Latitude E6520. */ + .callback = set_pci_reboot, + .ident = "Dell Latitude E6520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6520"), + }, + }, + { /* Handle problems with rebooting on the OptiPlex 790. */ + .callback = set_pci_reboot, + .ident = "Dell OptiPlex 790", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 790"), + }, + }, + { /* Handle problems with rebooting on the OptiPlex 990. */ + .callback = set_pci_reboot, + .ident = "Dell OptiPlex 990", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), + }, + }, + { /* Handle problems with rebooting on the Latitude E6220. */ + .callback = set_pci_reboot, + .ident = "Dell Latitude E6220", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6220"), + }, + }, + { /* Handle problems with rebooting on the OptiPlex 390. */ + .callback = set_pci_reboot, + .ident = "Dell OptiPlex 390", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 390"), + }, + }, { } }; --- linux-3.13.0.orig/arch/x86/kernel/head_32.S +++ linux-3.13.0/arch/x86/kernel/head_32.S @@ -544,6 +544,10 @@ /* This is global to keep gas from relaxing the jumps */ ENTRY(early_idt_handler) cld + + cmpl $2,(%esp) # X86_TRAP_NMI + je is_nmi # Ignore NMI + cmpl $2,%ss:early_recursion_flag je hlt_loop incl %ss:early_recursion_flag @@ -594,8 +598,9 @@ pop %edx pop %ecx pop %eax - addl $8,%esp /* drop vector number and error code */ decl %ss:early_recursion_flag +is_nmi: + addl $8,%esp /* drop vector number and error code */ iret ENDPROC(early_idt_handler) --- linux-3.13.0.orig/arch/x86/kernel/ftrace.c +++ linux-3.13.0/arch/x86/kernel/ftrace.c @@ -77,8 +77,7 @@ return addr >= start && addr < end; } -static int -do_ftrace_mod_code(unsigned long ip, const void *new_code) +static unsigned long text_ip_addr(unsigned long ip) { /* * On x86_64, kernel text mappings are mapped read-only with @@ -91,7 +90,7 @@ if (within(ip, (unsigned long)_text, (unsigned long)_etext)) ip = (unsigned long)__va(__pa_symbol(ip)); - return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE); + return ip; } static const unsigned char *ftrace_nop_replace(void) @@ -123,8 +122,10 @@ if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) return -EINVAL; + ip = text_ip_addr(ip); + /* replace the text with the new text */ - if (do_ftrace_mod_code(ip, new_code)) + if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) return -EPERM; sync_core(); @@ -221,37 +222,51 @@ return -EINVAL; } -int ftrace_update_ftrace_func(ftrace_func_t func) +static unsigned long ftrace_update_func; + +static int update_ftrace_func(unsigned long ip, void *new) { - unsigned long ip = (unsigned long)(&ftrace_call); - unsigned char old[MCOUNT_INSN_SIZE], *new; + unsigned char old[MCOUNT_INSN_SIZE]; int ret; - memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); - new = ftrace_call_replace(ip, (unsigned long)func); + memcpy(old, (void *)ip, MCOUNT_INSN_SIZE); + + ftrace_update_func = ip; + /* Make sure the breakpoints see the ftrace_update_func update */ + smp_wmb(); /* See comment above by declaration of modifying_ftrace_code */ atomic_inc(&modifying_ftrace_code); ret = ftrace_modify_code(ip, old, new); + atomic_dec(&modifying_ftrace_code); + + return ret; +} + +int ftrace_update_ftrace_func(ftrace_func_t func) +{ + unsigned long ip = (unsigned long)(&ftrace_call); + unsigned char *new; + int ret; + + new = ftrace_call_replace(ip, (unsigned long)func); + ret = update_ftrace_func(ip, new); + /* Also update the regs callback function */ if (!ret) { ip = (unsigned long)(&ftrace_regs_call); - memcpy(old, &ftrace_regs_call, MCOUNT_INSN_SIZE); new = ftrace_call_replace(ip, (unsigned long)func); - ret = ftrace_modify_code(ip, old, new); + ret = update_ftrace_func(ip, new); } - atomic_dec(&modifying_ftrace_code); - return ret; } static int is_ftrace_caller(unsigned long ip) { - if (ip == (unsigned long)(&ftrace_call) || - ip == (unsigned long)(&ftrace_regs_call)) + if (ip == ftrace_update_func) return 1; return 0; @@ -677,45 +692,41 @@ #ifdef CONFIG_DYNAMIC_FTRACE extern void ftrace_graph_call(void); -static int ftrace_mod_jmp(unsigned long ip, - int old_offset, int new_offset) +static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr) { - unsigned char code[MCOUNT_INSN_SIZE]; + static union ftrace_code_union calc; - if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) - return -EFAULT; + /* Jmp not a call (ignore the .e8) */ + calc.e8 = 0xe9; + calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr); - if (code[0] != 0xe9 || old_offset != *(int *)(&code[1])) - return -EINVAL; + /* + * ftrace external locks synchronize the access to the static variable. + */ + return calc.code; +} - *(int *)(&code[1]) = new_offset; +static int ftrace_mod_jmp(unsigned long ip, void *func) +{ + unsigned char *new; - if (do_ftrace_mod_code(ip, &code)) - return -EPERM; + new = ftrace_jmp_replace(ip, (unsigned long)func); - return 0; + return update_ftrace_func(ip, new); } int ftrace_enable_ftrace_graph_caller(void) { unsigned long ip = (unsigned long)(&ftrace_graph_call); - int old_offset, new_offset; - - old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); - new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); - return ftrace_mod_jmp(ip, old_offset, new_offset); + return ftrace_mod_jmp(ip, &ftrace_graph_caller); } int ftrace_disable_ftrace_graph_caller(void) { unsigned long ip = (unsigned long)(&ftrace_graph_call); - int old_offset, new_offset; - - old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); - new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); - return ftrace_mod_jmp(ip, old_offset, new_offset); + return ftrace_mod_jmp(ip, &ftrace_stub); } #endif /* !CONFIG_DYNAMIC_FTRACE */ --- linux-3.13.0.orig/arch/x86/kernel/quirks.c +++ linux-3.13.0/arch/x86/kernel/quirks.c @@ -529,7 +529,7 @@ return; pci_read_config_dword(nb_ht, 0x60, &val); - node = val & 7; + node = pcibus_to_node(dev->bus) | (val & 7); /* * Some hardware may return an invalid node ID, * so check it first: --- linux-3.13.0.orig/arch/x86/kernel/kvm.c +++ linux-3.13.0/arch/x86/kernel/kvm.c @@ -500,6 +500,38 @@ #endif } +static noinline uint32_t __kvm_cpuid_base(void) +{ + if (boot_cpu_data.cpuid_level < 0) + return 0; /* So we don't blow up on old processors */ + + if (cpu_has_hypervisor) + return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0); + + return 0; +} + +static inline uint32_t kvm_cpuid_base(void) +{ + static int kvm_cpuid_base = -1; + + if (kvm_cpuid_base == -1) + kvm_cpuid_base = __kvm_cpuid_base(); + + return kvm_cpuid_base; +} + +bool kvm_para_available(void) +{ + return kvm_cpuid_base() != 0; +} +EXPORT_SYMBOL_GPL(kvm_para_available); + +unsigned int kvm_arch_para_features(void) +{ + return cpuid_eax(kvm_cpuid_base() | KVM_CPUID_FEATURES); +} + static uint32_t __init kvm_detect(void) { return kvm_cpuid_base(); --- linux-3.13.0.orig/arch/x86/kernel/cpu/mshyperv.c +++ linux-3.13.0/arch/x86/kernel/cpu/mshyperv.c @@ -26,6 +26,7 @@ #include #include #include +#include struct ms_hyperv_info ms_hyperv; EXPORT_SYMBOL_GPL(ms_hyperv); @@ -105,6 +106,11 @@ if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); + +#ifdef CONFIG_X86_IO_APIC + no_timer_check = 1; +#endif + } const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { --- linux-3.13.0.orig/arch/x86/kernel/cpu/intel.c +++ linux-3.13.0/arch/x86/kernel/cpu/intel.c @@ -196,6 +196,14 @@ } } +static int forcepae; +static int __init forcepae_setup(char *__unused) +{ + forcepae = 1; + return 1; +} +__setup("forcepae", forcepae_setup); + static void intel_workarounds(struct cpuinfo_x86 *c) { unsigned long lo, hi; @@ -226,6 +234,17 @@ clear_cpu_cap(c, X86_FEATURE_SEP); /* + * PAE CPUID issue: many Pentium M report no PAE but may have a + * functionally usable PAE implementation. + * Forcefully enable PAE if kernel parameter "forcepae" is present. + */ + if (forcepae) { + printk(KERN_WARNING "PAE forced!\n"); + set_cpu_cap(c, X86_FEATURE_PAE); + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE); + } + + /* * P4 Xeon errata 037 workaround. * Hardware prefetcher may cause stale data to be loaded into the cache. */ @@ -628,7 +647,7 @@ tlb_flushall_shift = 5; break; case 0x63a: /* Ivybridge */ - tlb_flushall_shift = 1; + tlb_flushall_shift = 2; break; default: tlb_flushall_shift = 6; --- linux-3.13.0.orig/arch/x86/kernel/cpu/perf_event.c +++ linux-3.13.0/arch/x86/kernel/cpu/perf_event.c @@ -1192,6 +1192,9 @@ for (i = 0; i < cpuc->n_events; i++) { if (event == cpuc->event_list[i]) { + if (i >= cpuc->n_events - cpuc->n_added) + --cpuc->n_added; + if (x86_pmu.put_event_constraints) x86_pmu.put_event_constraints(cpuc, event); --- linux-3.13.0.orig/arch/x86/kernel/cpu/common.c +++ linux-3.13.0/arch/x86/kernel/cpu/common.c @@ -284,8 +284,13 @@ raw_local_save_flags(eflags); BUG_ON(eflags & X86_EFLAGS_AC); - if (cpu_has(c, X86_FEATURE_SMAP)) + if (cpu_has(c, X86_FEATURE_SMAP)) { +#ifdef CONFIG_X86_SMAP set_in_cr4(X86_CR4_SMAP); +#else + clear_in_cr4(X86_CR4_SMAP); +#endif + } } /* --- linux-3.13.0.orig/arch/x86/kernel/cpu/amd.c +++ linux-3.13.0/arch/x86/kernel/cpu/amd.c @@ -219,7 +219,7 @@ */ WARN_ONCE(1, "WARNING: This combination of AMD" " processors is not suitable for SMP.\n"); - add_taint(TAINT_UNSAFE_SMP, LOCKDEP_NOW_UNRELIABLE); + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE); } static void init_amd_k7(struct cpuinfo_x86 *c) @@ -508,6 +508,16 @@ set_cpu_cap(c, X86_FEATURE_EXTD_APICID); } #endif + + /* F16h erratum 793, CVE-2013-6885 */ + if (c->x86 == 0x16 && c->x86_model <= 0xf) { + u64 val; + + rdmsrl(MSR_AMD64_LS_CFG, val); + if (!(val & BIT(15))) + wrmsrl(MSR_AMD64_LS_CFG, val | BIT(15)); + } + } static const int amd_erratum_383[]; --- linux-3.13.0.orig/arch/x86/include/uapi/asm/msr-index.h +++ linux-3.13.0/arch/x86/include/uapi/asm/msr-index.h @@ -184,6 +184,7 @@ #define MSR_AMD64_PATCH_LOADER 0xc0010020 #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 #define MSR_AMD64_OSVW_STATUS 0xc0010141 +#define MSR_AMD64_LS_CFG 0xc0011020 #define MSR_AMD64_DC_CFG 0xc0011022 #define MSR_AMD64_BU_CFG2 0xc001102a #define MSR_AMD64_IBSFETCHCTL 0xc0011030 --- linux-3.13.0.orig/arch/x86/include/asm/dma-mapping.h +++ linux-3.13.0/arch/x86/include/asm/dma-mapping.h @@ -163,8 +163,6 @@ { struct dma_map_ops *ops = get_dma_ops(dev); - WARN_ON(irqs_disabled()); /* for portability */ - if (dma_release_from_coherent(dev, get_order(size), vaddr)) return; --- linux-3.13.0.orig/arch/x86/include/asm/pgtable.h +++ linux-3.13.0/arch/x86/include/asm/pgtable.h @@ -445,10 +445,20 @@ return a.pte == b.pte; } +static inline int pteval_present(pteval_t pteval) +{ + /* + * Yes Linus, _PAGE_PROTNONE == _PAGE_NUMA. Expressing it this + * way clearly states that the intent is that protnone and numa + * hinting ptes are considered present for the purposes of + * pagetable operations like zapping, protection changes, gup etc. + */ + return pteval & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_NUMA); +} + static inline int pte_present(pte_t a) { - return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE | - _PAGE_NUMA); + return pteval_present(pte_flags(a)); } #define pte_accessible pte_accessible --- linux-3.13.0.orig/arch/x86/include/asm/pgtable_types.h +++ linux-3.13.0/arch/x86/include/asm/pgtable_types.h @@ -121,7 +121,8 @@ /* Set of bits not changed in pte_modify */ #define _PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ - _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY) + _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_SOFT_DIRTY) #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE) #define _PAGE_CACHE_MASK (_PAGE_PCD | _PAGE_PWT) @@ -382,7 +383,8 @@ */ extern pte_t *lookup_address(unsigned long address, unsigned int *level); extern phys_addr_t slow_virt_to_phys(void *__address); - +extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, + unsigned numpages, unsigned long page_flags); #endif /* !__ASSEMBLY__ */ #endif /* _ASM_X86_PGTABLE_DEFS_H */ --- linux-3.13.0.orig/arch/x86/include/asm/kvm_para.h +++ linux-3.13.0/arch/x86/include/asm/kvm_para.h @@ -85,28 +85,9 @@ return ret; } -static inline uint32_t kvm_cpuid_base(void) -{ - if (boot_cpu_data.cpuid_level < 0) - return 0; /* So we don't blow up on old processors */ - - if (cpu_has_hypervisor) - return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0); - - return 0; -} - -static inline bool kvm_para_available(void) -{ - return kvm_cpuid_base() != 0; -} - -static inline unsigned int kvm_arch_para_features(void) -{ - return cpuid_eax(KVM_CPUID_FEATURES); -} - #ifdef CONFIG_KVM_GUEST +bool kvm_para_available(void); +unsigned int kvm_arch_para_features(void); void __init kvm_guest_init(void); void kvm_async_pf_task_wait(u32 token); void kvm_async_pf_task_wake(u32 token); @@ -126,6 +107,16 @@ #define kvm_async_pf_task_wait(T) do {} while(0) #define kvm_async_pf_task_wake(T) do {} while(0) +static inline bool kvm_para_available(void) +{ + return 0; +} + +static inline unsigned int kvm_arch_para_features(void) +{ + return 0; +} + static inline u32 kvm_read_and_reset_pf_reason(void) { return 0; --- linux-3.13.0.orig/arch/x86/include/asm/efi.h +++ linux-3.13.0/arch/x86/include/asm/efi.h @@ -1,6 +1,24 @@ #ifndef _ASM_X86_EFI_H #define _ASM_X86_EFI_H +/* + * We map the EFI regions needed for runtime services non-contiguously, + * with preserved alignment on virtual addresses starting from -4G down + * for a total max space of 64G. This way, we provide for stable runtime + * services addresses across kernels so that a kexec'd kernel can still + * use them. + * + * This is the main reason why we're doing stable VA mappings for RT + * services. + * + * This flag is used in conjuction with a chicken bit called + * "efi=old_map" which can be used as a fallback to the old runtime + * services mapping method in case there's some b0rkage with a + * particular EFI implementation (haha, it is hard to hold up the + * sarcasm here...). + */ +#define EFI_OLD_MEMMAP EFI_ARCH_1 + #ifdef CONFIG_X86_32 #define EFI_LOADER_SIGNATURE "EL32" @@ -69,24 +87,31 @@ efi_call6((f), (u64)(a1), (u64)(a2), (u64)(a3), \ (u64)(a4), (u64)(a5), (u64)(a6)) +#define _efi_call_virtX(x, f, ...) \ +({ \ + efi_status_t __s; \ + \ + efi_sync_low_kernel_mappings(); \ + preempt_disable(); \ + __s = efi_call##x((void *)efi.systab->runtime->f, __VA_ARGS__); \ + preempt_enable(); \ + __s; \ +}) + #define efi_call_virt0(f) \ - efi_call0((efi.systab->runtime->f)) -#define efi_call_virt1(f, a1) \ - efi_call1((efi.systab->runtime->f), (u64)(a1)) -#define efi_call_virt2(f, a1, a2) \ - efi_call2((efi.systab->runtime->f), (u64)(a1), (u64)(a2)) -#define efi_call_virt3(f, a1, a2, a3) \ - efi_call3((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ - (u64)(a3)) -#define efi_call_virt4(f, a1, a2, a3, a4) \ - efi_call4((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ - (u64)(a3), (u64)(a4)) -#define efi_call_virt5(f, a1, a2, a3, a4, a5) \ - efi_call5((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ - (u64)(a3), (u64)(a4), (u64)(a5)) -#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ - efi_call6((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ - (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6)) + _efi_call_virtX(0, f) +#define efi_call_virt1(f, a1) \ + _efi_call_virtX(1, f, (u64)(a1)) +#define efi_call_virt2(f, a1, a2) \ + _efi_call_virtX(2, f, (u64)(a1), (u64)(a2)) +#define efi_call_virt3(f, a1, a2, a3) \ + _efi_call_virtX(3, f, (u64)(a1), (u64)(a2), (u64)(a3)) +#define efi_call_virt4(f, a1, a2, a3, a4) \ + _efi_call_virtX(4, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4)) +#define efi_call_virt5(f, a1, a2, a3, a4, a5) \ + _efi_call_virtX(5, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5)) +#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ + _efi_call_virtX(6, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6)) extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, u32 type, u64 attribute); @@ -95,12 +120,17 @@ extern int add_efi_memmap; extern unsigned long x86_efi_facility; +extern struct efi_scratch efi_scratch; extern void efi_set_executable(efi_memory_desc_t *md, bool executable); extern int efi_memblock_x86_reserve_range(void); extern void efi_call_phys_prelog(void); extern void efi_call_phys_epilog(void); extern void efi_unmap_memmap(void); extern void efi_memory_uc(u64 addr, unsigned long size); +extern void __init efi_map_region(efi_memory_desc_t *md); +extern void efi_sync_low_kernel_mappings(void); +extern void efi_setup_page_tables(void); +extern void __init old_map_region(efi_memory_desc_t *md); #ifdef CONFIG_EFI --- linux-3.13.0.orig/arch/x86/mm/fault.c +++ linux-3.13.0/arch/x86/mm/fault.c @@ -1001,6 +1001,12 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs) { + if (!IS_ENABLED(CONFIG_X86_SMAP)) + return false; + + if (!static_cpu_has(X86_FEATURE_SMAP)) + return false; + if (error_code & PF_USER) return false; @@ -1087,11 +1093,9 @@ if (unlikely(error_code & PF_RSVD)) pgtable_bad(regs, error_code, address); - if (static_cpu_has(X86_FEATURE_SMAP)) { - if (unlikely(smap_violation(error_code, regs))) { - bad_area_nosemaphore(regs, error_code, address); - return; - } + if (unlikely(smap_violation(error_code, regs))) { + bad_area_nosemaphore(regs, error_code, address); + return; } /* --- linux-3.13.0.orig/arch/x86/mm/pageattr.c +++ linux-3.13.0/arch/x86/mm/pageattr.c @@ -30,6 +30,7 @@ */ struct cpa_data { unsigned long *vaddr; + pgd_t *pgd; pgprot_t mask_set; pgprot_t mask_clr; int numpages; @@ -322,17 +323,9 @@ return prot; } -/* - * Lookup the page table entry for a virtual address. Return a pointer - * to the entry and the level of the mapping. - * - * Note: We return pud and pmd either when the entry is marked large - * or when the present bit is not set. Otherwise we would return a - * pointer to a nonexisting mapping. - */ -pte_t *lookup_address(unsigned long address, unsigned int *level) +static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + unsigned int *level) { - pgd_t *pgd = pgd_offset_k(address); pud_t *pud; pmd_t *pmd; @@ -361,8 +354,31 @@ return pte_offset_kernel(pmd, address); } + +/* + * Lookup the page table entry for a virtual address. Return a pointer + * to the entry and the level of the mapping. + * + * Note: We return pud and pmd either when the entry is marked large + * or when the present bit is not set. Otherwise we would return a + * pointer to a nonexisting mapping. + */ +pte_t *lookup_address(unsigned long address, unsigned int *level) +{ + return __lookup_address_in_pgd(pgd_offset_k(address), address, level); +} EXPORT_SYMBOL_GPL(lookup_address); +static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address, + unsigned int *level) +{ + if (cpa->pgd) + return __lookup_address_in_pgd(cpa->pgd + pgd_index(address), + address, level); + + return lookup_address(address, level); +} + /* * This is necessary because __pa() does not work on some * kinds of memory, like vmalloc() or the alloc_remap() @@ -437,7 +453,7 @@ * Check for races, another CPU might have split this page * up already: */ - tmp = lookup_address(address, &level); + tmp = _lookup_address_cpa(cpa, address, &level); if (tmp != kpte) goto out_unlock; @@ -543,7 +559,8 @@ } static int -__split_large_page(pte_t *kpte, unsigned long address, struct page *base) +__split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, + struct page *base) { pte_t *pbase = (pte_t *)page_address(base); unsigned long pfn, pfninc = 1; @@ -556,7 +573,7 @@ * Check for races, another CPU might have split this page * up for us already: */ - tmp = lookup_address(address, &level); + tmp = _lookup_address_cpa(cpa, address, &level); if (tmp != kpte) { spin_unlock(&pgd_lock); return 1; @@ -632,7 +649,8 @@ return 0; } -static int split_large_page(pte_t *kpte, unsigned long address) +static int split_large_page(struct cpa_data *cpa, pte_t *kpte, + unsigned long address) { struct page *base; @@ -644,15 +662,390 @@ if (!base) return -ENOMEM; - if (__split_large_page(kpte, address, base)) + if (__split_large_page(cpa, kpte, address, base)) __free_page(base); return 0; } +static bool try_to_free_pte_page(pte_t *pte) +{ + int i; + + for (i = 0; i < PTRS_PER_PTE; i++) + if (!pte_none(pte[i])) + return false; + + free_page((unsigned long)pte); + return true; +} + +static bool try_to_free_pmd_page(pmd_t *pmd) +{ + int i; + + for (i = 0; i < PTRS_PER_PMD; i++) + if (!pmd_none(pmd[i])) + return false; + + free_page((unsigned long)pmd); + return true; +} + +static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end) +{ + pte_t *pte = pte_offset_kernel(pmd, start); + + while (start < end) { + set_pte(pte, __pte(0)); + + start += PAGE_SIZE; + pte++; + } + + if (try_to_free_pte_page((pte_t *)pmd_page_vaddr(*pmd))) { + pmd_clear(pmd); + return true; + } + return false; +} + +static void __unmap_pmd_range(pud_t *pud, pmd_t *pmd, + unsigned long start, unsigned long end) +{ + if (unmap_pte_range(pmd, start, end)) + if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) + pud_clear(pud); +} + +static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end) +{ + pmd_t *pmd = pmd_offset(pud, start); + + /* + * Not on a 2MB page boundary? + */ + if (start & (PMD_SIZE - 1)) { + unsigned long next_page = (start + PMD_SIZE) & PMD_MASK; + unsigned long pre_end = min_t(unsigned long, end, next_page); + + __unmap_pmd_range(pud, pmd, start, pre_end); + + start = pre_end; + pmd++; + } + + /* + * Try to unmap in 2M chunks. + */ + while (end - start >= PMD_SIZE) { + if (pmd_large(*pmd)) + pmd_clear(pmd); + else + __unmap_pmd_range(pud, pmd, start, start + PMD_SIZE); + + start += PMD_SIZE; + pmd++; + } + + /* + * 4K leftovers? + */ + if (start < end) + return __unmap_pmd_range(pud, pmd, start, end); + + /* + * Try again to free the PMD page if haven't succeeded above. + */ + if (!pud_none(*pud)) + if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) + pud_clear(pud); +} + +static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) +{ + pud_t *pud = pud_offset(pgd, start); + + /* + * Not on a GB page boundary? + */ + if (start & (PUD_SIZE - 1)) { + unsigned long next_page = (start + PUD_SIZE) & PUD_MASK; + unsigned long pre_end = min_t(unsigned long, end, next_page); + + unmap_pmd_range(pud, start, pre_end); + + start = pre_end; + pud++; + } + + /* + * Try to unmap in 1G chunks? + */ + while (end - start >= PUD_SIZE) { + + if (pud_large(*pud)) + pud_clear(pud); + else + unmap_pmd_range(pud, start, start + PUD_SIZE); + + start += PUD_SIZE; + pud++; + } + + /* + * 2M leftovers? + */ + if (start < end) + unmap_pmd_range(pud, start, end); + + /* + * No need to try to free the PUD page because we'll free it in + * populate_pgd's error path + */ +} + +static int alloc_pte_page(pmd_t *pmd) +{ + pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK); + if (!pte) + return -1; + + set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE)); + return 0; +} + +static int alloc_pmd_page(pud_t *pud) +{ + pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK); + if (!pmd) + return -1; + + set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); + return 0; +} + +static void populate_pte(struct cpa_data *cpa, + unsigned long start, unsigned long end, + unsigned num_pages, pmd_t *pmd, pgprot_t pgprot) +{ + pte_t *pte; + + pte = pte_offset_kernel(pmd, start); + + while (num_pages-- && start < end) { + + /* deal with the NX bit */ + if (!(pgprot_val(pgprot) & _PAGE_NX)) + cpa->pfn &= ~_PAGE_NX; + + set_pte(pte, pfn_pte(cpa->pfn >> PAGE_SHIFT, pgprot)); + + start += PAGE_SIZE; + cpa->pfn += PAGE_SIZE; + pte++; + } +} + +static int populate_pmd(struct cpa_data *cpa, + unsigned long start, unsigned long end, + unsigned num_pages, pud_t *pud, pgprot_t pgprot) +{ + unsigned int cur_pages = 0; + pmd_t *pmd; + + /* + * Not on a 2M boundary? + */ + if (start & (PMD_SIZE - 1)) { + unsigned long pre_end = start + (num_pages << PAGE_SHIFT); + unsigned long next_page = (start + PMD_SIZE) & PMD_MASK; + + pre_end = min_t(unsigned long, pre_end, next_page); + cur_pages = (pre_end - start) >> PAGE_SHIFT; + cur_pages = min_t(unsigned int, num_pages, cur_pages); + + /* + * Need a PTE page? + */ + pmd = pmd_offset(pud, start); + if (pmd_none(*pmd)) + if (alloc_pte_page(pmd)) + return -1; + + populate_pte(cpa, start, pre_end, cur_pages, pmd, pgprot); + + start = pre_end; + } + + /* + * We mapped them all? + */ + if (num_pages == cur_pages) + return cur_pages; + + while (end - start >= PMD_SIZE) { + + /* + * We cannot use a 1G page so allocate a PMD page if needed. + */ + if (pud_none(*pud)) + if (alloc_pmd_page(pud)) + return -1; + + pmd = pmd_offset(pud, start); + + set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot))); + + start += PMD_SIZE; + cpa->pfn += PMD_SIZE; + cur_pages += PMD_SIZE >> PAGE_SHIFT; + } + + /* + * Map trailing 4K pages. + */ + if (start < end) { + pmd = pmd_offset(pud, start); + if (pmd_none(*pmd)) + if (alloc_pte_page(pmd)) + return -1; + + populate_pte(cpa, start, end, num_pages - cur_pages, + pmd, pgprot); + } + return num_pages; +} + +static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd, + pgprot_t pgprot) +{ + pud_t *pud; + unsigned long end; + int cur_pages = 0; + + end = start + (cpa->numpages << PAGE_SHIFT); + + /* + * Not on a Gb page boundary? => map everything up to it with + * smaller pages. + */ + if (start & (PUD_SIZE - 1)) { + unsigned long pre_end; + unsigned long next_page = (start + PUD_SIZE) & PUD_MASK; + + pre_end = min_t(unsigned long, end, next_page); + cur_pages = (pre_end - start) >> PAGE_SHIFT; + cur_pages = min_t(int, (int)cpa->numpages, cur_pages); + + pud = pud_offset(pgd, start); + + /* + * Need a PMD page? + */ + if (pud_none(*pud)) + if (alloc_pmd_page(pud)) + return -1; + + cur_pages = populate_pmd(cpa, start, pre_end, cur_pages, + pud, pgprot); + if (cur_pages < 0) + return cur_pages; + + start = pre_end; + } + + /* We mapped them all? */ + if (cpa->numpages == cur_pages) + return cur_pages; + + pud = pud_offset(pgd, start); + + /* + * Map everything starting from the Gb boundary, possibly with 1G pages + */ + while (end - start >= PUD_SIZE) { + set_pud(pud, __pud(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot))); + + start += PUD_SIZE; + cpa->pfn += PUD_SIZE; + cur_pages += PUD_SIZE >> PAGE_SHIFT; + pud++; + } + + /* Map trailing leftover */ + if (start < end) { + int tmp; + + pud = pud_offset(pgd, start); + if (pud_none(*pud)) + if (alloc_pmd_page(pud)) + return -1; + + tmp = populate_pmd(cpa, start, end, cpa->numpages - cur_pages, + pud, pgprot); + if (tmp < 0) + return cur_pages; + + cur_pages += tmp; + } + return cur_pages; +} + +/* + * Restrictions for kernel page table do not necessarily apply when mapping in + * an alternate PGD. + */ +static int populate_pgd(struct cpa_data *cpa, unsigned long addr) +{ + pgprot_t pgprot = __pgprot(_KERNPG_TABLE); + bool allocd_pgd = false; + pgd_t *pgd_entry; + pud_t *pud = NULL; /* shut up gcc */ + int ret; + + pgd_entry = cpa->pgd + pgd_index(addr); + + /* + * Allocate a PUD page and hand it down for mapping. + */ + if (pgd_none(*pgd_entry)) { + pud = (pud_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK); + if (!pud) + return -1; + + set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE)); + allocd_pgd = true; + } + + pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr); + pgprot_val(pgprot) |= pgprot_val(cpa->mask_set); + + ret = populate_pud(cpa, addr, pgd_entry, pgprot); + if (ret < 0) { + unmap_pud_range(pgd_entry, addr, + addr + (cpa->numpages << PAGE_SHIFT)); + + if (allocd_pgd) { + /* + * If I allocated this PUD page, I can just as well + * free it in this error path. + */ + pgd_clear(pgd_entry); + free_page((unsigned long)pud); + } + return ret; + } + cpa->numpages = ret; + return 0; +} + static int __cpa_process_fault(struct cpa_data *cpa, unsigned long vaddr, int primary) { + if (cpa->pgd) + return populate_pgd(cpa, vaddr); + /* * Ignore all non primary paths. */ @@ -697,7 +1090,7 @@ else address = *cpa->vaddr; repeat: - kpte = lookup_address(address, &level); + kpte = _lookup_address_cpa(cpa, address, &level); if (!kpte) return __cpa_process_fault(cpa, address, primary); @@ -761,7 +1154,7 @@ /* * We have to split the large page: */ - err = split_large_page(kpte, address); + err = split_large_page(cpa, kpte, address); if (!err) { /* * Do a global flush tlb after splitting the large page @@ -910,6 +1303,8 @@ int ret, cache, checkalias; unsigned long baddr = 0; + memset(&cpa, 0, sizeof(cpa)); + /* * Check, if we are requested to change a not supported * feature: @@ -1356,6 +1751,7 @@ { unsigned long tempaddr = (unsigned long) page_address(page); struct cpa_data cpa = { .vaddr = &tempaddr, + .pgd = NULL, .numpages = numpages, .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW), .mask_clr = __pgprot(0), @@ -1374,6 +1770,7 @@ { unsigned long tempaddr = (unsigned long) page_address(page); struct cpa_data cpa = { .vaddr = &tempaddr, + .pgd = NULL, .numpages = numpages, .mask_set = __pgprot(0), .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW), @@ -1434,6 +1831,36 @@ #endif /* CONFIG_DEBUG_PAGEALLOC */ +int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, + unsigned numpages, unsigned long page_flags) +{ + int retval = -EINVAL; + + struct cpa_data cpa = { + .vaddr = &address, + .pfn = pfn, + .pgd = pgd, + .numpages = numpages, + .mask_set = __pgprot(0), + .mask_clr = __pgprot(0), + .flags = 0, + }; + + if (!(__supported_pte_mask & _PAGE_NX)) + goto out; + + if (!(page_flags & _PAGE_NX)) + cpa.mask_clr = __pgprot(_PAGE_NX); + + cpa.mask_set = __pgprot(_PAGE_PRESENT | page_flags); + + retval = __change_page_attr_set_clr(&cpa, 0); + __flush_tlb_all(); + +out: + return retval; +} + /* * The testcases use internal knowledge of the implementation that shouldn't * be exposed to the rest of the kernel. Include these directly here. --- linux-3.13.0.orig/arch/arc/mm/cache_arc700.c +++ linux-3.13.0/arch/arc/mm/cache_arc700.c @@ -282,7 +282,7 @@ #else /* if V-P const for loop, PTAG can be written once outside loop */ if (full_page_op) - write_aux_reg(ARC_REG_DC_PTAG, paddr); + write_aux_reg(aux_tag, paddr); #endif while (num_lines-- > 0) { @@ -296,7 +296,7 @@ write_aux_reg(aux_cmd, vaddr); vaddr += L1_CACHE_BYTES; #else - write_aux_reg(aux, paddr); + write_aux_reg(aux_cmd, paddr); paddr += L1_CACHE_BYTES; #endif } --- linux-3.13.0.orig/arch/s390/crypto/des_s390.c +++ linux-3.13.0/arch/s390/crypto/des_s390.c @@ -25,6 +25,7 @@ #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) static u8 *ctrblk; +static DEFINE_SPINLOCK(ctrblk_lock); struct s390_des_ctx { u8 iv[DES_BLOCK_SIZE]; @@ -105,29 +106,35 @@ } static int cbc_desall_crypt(struct blkcipher_desc *desc, long func, - u8 *iv, struct blkcipher_walk *walk) + struct blkcipher_walk *walk) { + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); int ret = blkcipher_walk_virt(desc, walk); unsigned int nbytes = walk->nbytes; + struct { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES3_KEY_SIZE]; + } param; if (!nbytes) goto out; - memcpy(iv, walk->iv, DES_BLOCK_SIZE); + memcpy(param.iv, walk->iv, DES_BLOCK_SIZE); + memcpy(param.key, ctx->key, DES3_KEY_SIZE); do { /* only use complete blocks */ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); u8 *out = walk->dst.virt.addr; u8 *in = walk->src.virt.addr; - ret = crypt_s390_kmc(func, iv, out, in, n); + ret = crypt_s390_kmc(func, ¶m, out, in, n); if (ret < 0 || ret != n) return -EIO; nbytes &= DES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, walk, nbytes); } while ((nbytes = walk->nbytes)); - memcpy(walk->iv, iv, DES_BLOCK_SIZE); + memcpy(walk->iv, param.iv, DES_BLOCK_SIZE); out: return ret; @@ -179,22 +186,20 @@ struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, &walk); } static int cbc_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, &walk); } static struct crypto_alg cbc_des_alg = { @@ -327,22 +332,20 @@ struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, &walk); } static int cbc_des3_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, ctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, &walk); } static struct crypto_alg cbc_des3_alg = { @@ -366,54 +369,80 @@ } }; +static unsigned int __ctrblk_init(u8 *ctrptr, unsigned int nbytes) +{ + unsigned int i, n; + + /* align to block size, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(DES_BLOCK_SIZE - 1); + for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { + memcpy(ctrptr + i, ctrptr + i - DES_BLOCK_SIZE, DES_BLOCK_SIZE); + crypto_inc(ctrptr + i, DES_BLOCK_SIZE); + } + return n; +} + static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, - struct s390_des_ctx *ctx, struct blkcipher_walk *walk) + struct s390_des_ctx *ctx, + struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); - unsigned int i, n, nbytes; - u8 buf[DES_BLOCK_SIZE]; - u8 *out, *in; + unsigned int n, nbytes; + u8 buf[DES_BLOCK_SIZE], ctrbuf[DES_BLOCK_SIZE]; + u8 *out, *in, *ctrptr = ctrbuf; + + if (!walk->nbytes) + return ret; - memcpy(ctrblk, walk->iv, DES_BLOCK_SIZE); + if (spin_trylock(&ctrblk_lock)) + ctrptr = ctrblk; + + memcpy(ctrptr, walk->iv, DES_BLOCK_SIZE); while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { out = walk->dst.virt.addr; in = walk->src.virt.addr; while (nbytes >= DES_BLOCK_SIZE) { - /* align to block size, max. PAGE_SIZE */ - n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : - nbytes & ~(DES_BLOCK_SIZE - 1); - for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { - memcpy(ctrblk + i, ctrblk + i - DES_BLOCK_SIZE, - DES_BLOCK_SIZE); - crypto_inc(ctrblk + i, DES_BLOCK_SIZE); - } - ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrblk); - if (ret < 0 || ret != n) + if (ctrptr == ctrblk) + n = __ctrblk_init(ctrptr, nbytes); + else + n = DES_BLOCK_SIZE; + ret = crypt_s390_kmctr(func, ctx->key, out, in, + n, ctrptr); + if (ret < 0 || ret != n) { + if (ctrptr == ctrblk) + spin_unlock(&ctrblk_lock); return -EIO; + } if (n > DES_BLOCK_SIZE) - memcpy(ctrblk, ctrblk + n - DES_BLOCK_SIZE, + memcpy(ctrptr, ctrptr + n - DES_BLOCK_SIZE, DES_BLOCK_SIZE); - crypto_inc(ctrblk, DES_BLOCK_SIZE); + crypto_inc(ctrptr, DES_BLOCK_SIZE); out += n; in += n; nbytes -= n; } ret = blkcipher_walk_done(desc, walk, nbytes); } - + if (ctrptr == ctrblk) { + if (nbytes) + memcpy(ctrbuf, ctrptr, DES_BLOCK_SIZE); + else + memcpy(walk->iv, ctrptr, DES_BLOCK_SIZE); + spin_unlock(&ctrblk_lock); + } /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { out = walk->dst.virt.addr; in = walk->src.virt.addr; ret = crypt_s390_kmctr(func, ctx->key, buf, in, - DES_BLOCK_SIZE, ctrblk); + DES_BLOCK_SIZE, ctrbuf); if (ret < 0 || ret != DES_BLOCK_SIZE) return -EIO; memcpy(out, buf, nbytes); - crypto_inc(ctrblk, DES_BLOCK_SIZE); + crypto_inc(ctrbuf, DES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, 0); + memcpy(walk->iv, ctrbuf, DES_BLOCK_SIZE); } - memcpy(walk->iv, ctrblk, DES_BLOCK_SIZE); return ret; } --- linux-3.13.0.orig/arch/s390/crypto/aes_s390.c +++ linux-3.13.0/arch/s390/crypto/aes_s390.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "crypt_s390.h" #define AES_KEYLEN_128 1 @@ -32,6 +33,7 @@ #define AES_KEYLEN_256 4 static u8 *ctrblk; +static DEFINE_SPINLOCK(ctrblk_lock); static char keylen_flag; struct s390_aes_ctx { @@ -758,43 +760,67 @@ return aes_set_key(tfm, in_key, key_len); } +static unsigned int __ctrblk_init(u8 *ctrptr, unsigned int nbytes) +{ + unsigned int i, n; + + /* only use complete blocks, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1); + for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { + memcpy(ctrptr + i, ctrptr + i - AES_BLOCK_SIZE, + AES_BLOCK_SIZE); + crypto_inc(ctrptr + i, AES_BLOCK_SIZE); + } + return n; +} + static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, struct s390_aes_ctx *sctx, struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE); - unsigned int i, n, nbytes; - u8 buf[AES_BLOCK_SIZE]; - u8 *out, *in; + unsigned int n, nbytes; + u8 buf[AES_BLOCK_SIZE], ctrbuf[AES_BLOCK_SIZE]; + u8 *out, *in, *ctrptr = ctrbuf; if (!walk->nbytes) return ret; - memcpy(ctrblk, walk->iv, AES_BLOCK_SIZE); + if (spin_trylock(&ctrblk_lock)) + ctrptr = ctrblk; + + memcpy(ctrptr, walk->iv, AES_BLOCK_SIZE); while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) { out = walk->dst.virt.addr; in = walk->src.virt.addr; while (nbytes >= AES_BLOCK_SIZE) { - /* only use complete blocks, max. PAGE_SIZE */ - n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : - nbytes & ~(AES_BLOCK_SIZE - 1); - for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { - memcpy(ctrblk + i, ctrblk + i - AES_BLOCK_SIZE, - AES_BLOCK_SIZE); - crypto_inc(ctrblk + i, AES_BLOCK_SIZE); - } - ret = crypt_s390_kmctr(func, sctx->key, out, in, n, ctrblk); - if (ret < 0 || ret != n) + if (ctrptr == ctrblk) + n = __ctrblk_init(ctrptr, nbytes); + else + n = AES_BLOCK_SIZE; + ret = crypt_s390_kmctr(func, sctx->key, out, in, + n, ctrptr); + if (ret < 0 || ret != n) { + if (ctrptr == ctrblk) + spin_unlock(&ctrblk_lock); return -EIO; + } if (n > AES_BLOCK_SIZE) - memcpy(ctrblk, ctrblk + n - AES_BLOCK_SIZE, + memcpy(ctrptr, ctrptr + n - AES_BLOCK_SIZE, AES_BLOCK_SIZE); - crypto_inc(ctrblk, AES_BLOCK_SIZE); + crypto_inc(ctrptr, AES_BLOCK_SIZE); out += n; in += n; nbytes -= n; } ret = blkcipher_walk_done(desc, walk, nbytes); } + if (ctrptr == ctrblk) { + if (nbytes) + memcpy(ctrbuf, ctrptr, AES_BLOCK_SIZE); + else + memcpy(walk->iv, ctrptr, AES_BLOCK_SIZE); + spin_unlock(&ctrblk_lock); + } /* * final block may be < AES_BLOCK_SIZE, copy only nbytes */ @@ -802,14 +828,15 @@ out = walk->dst.virt.addr; in = walk->src.virt.addr; ret = crypt_s390_kmctr(func, sctx->key, buf, in, - AES_BLOCK_SIZE, ctrblk); + AES_BLOCK_SIZE, ctrbuf); if (ret < 0 || ret != AES_BLOCK_SIZE) return -EIO; memcpy(out, buf, nbytes); - crypto_inc(ctrblk, AES_BLOCK_SIZE); + crypto_inc(ctrbuf, AES_BLOCK_SIZE); ret = blkcipher_walk_done(desc, walk, 0); + memcpy(walk->iv, ctrbuf, AES_BLOCK_SIZE); } - memcpy(walk->iv, ctrblk, AES_BLOCK_SIZE); + return ret; } --- linux-3.13.0.orig/arch/s390/kvm/diag.c +++ linux-3.13.0/arch/s390/kvm/diag.c @@ -121,7 +121,7 @@ * - gpr 4 contains the index on the bus (optionally) */ ret = kvm_io_bus_write_cookie(vcpu->kvm, KVM_VIRTIO_CCW_NOTIFY_BUS, - vcpu->run->s.regs.gprs[2], + vcpu->run->s.regs.gprs[2] & 0xffffffff, 8, &vcpu->run->s.regs.gprs[3], vcpu->run->s.regs.gprs[4]); @@ -137,7 +137,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) { - int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; + int code = kvm_s390_get_base_disp_rs(vcpu) & 0xffff; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); --- linux-3.13.0.orig/arch/s390/kvm/kvm-s390.h +++ linux-3.13.0/arch/s390/kvm/kvm-s390.h @@ -150,8 +150,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); /* implemented in kvm-s390.c */ -int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, - unsigned long addr); +int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr); +int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr); void s390_vcpu_block(struct kvm_vcpu *vcpu); void s390_vcpu_unblock(struct kvm_vcpu *vcpu); void exit_sie(struct kvm_vcpu *vcpu); --- linux-3.13.0.orig/arch/s390/kvm/kvm-s390.c +++ linux-3.13.0/arch/s390/kvm/kvm-s390.c @@ -885,7 +885,7 @@ * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit * KVM_S390_STORE_STATUS_PREFIXED: -> prefix */ -int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) +int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr) { unsigned char archmode = 1; int prefix; @@ -903,15 +903,6 @@ } else prefix = 0; - /* - * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy - * copying in vcpu load/put. Lets update our copies before we save - * it into the save area - */ - save_fp_ctl(&vcpu->arch.guest_fpregs.fpc); - save_fp_regs(vcpu->arch.guest_fpregs.fprs); - save_access_regs(vcpu->run->s.regs.acrs); - if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs), vcpu->arch.guest_fpregs.fprs, 128, prefix)) return -EFAULT; @@ -956,6 +947,20 @@ return 0; } +int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) +{ + /* + * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy + * copying in vcpu load/put. Lets update our copies before we save + * it into the save area + */ + save_fp_ctl(&vcpu->arch.guest_fpregs.fpc); + save_fp_regs(vcpu->arch.guest_fpregs.fprs); + save_access_regs(vcpu->run->s.regs.acrs); + + return kvm_s390_store_status_unloaded(vcpu, addr); +} + static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, struct kvm_enable_cap *cap) { --- linux-3.13.0.orig/arch/s390/kvm/sigp.c +++ linux-3.13.0/arch/s390/kvm/sigp.c @@ -130,6 +130,7 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action) { struct kvm_s390_interrupt_info *inti; + int rc = SIGP_CC_ORDER_CODE_ACCEPTED; inti = kzalloc(sizeof(*inti), GFP_ATOMIC); if (!inti) @@ -139,6 +140,8 @@ spin_lock_bh(&li->lock); if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) { kfree(inti); + if ((action & ACTION_STORE_ON_STOP) != 0) + rc = -ESHUTDOWN; goto out; } list_add_tail(&inti->list, &li->list); @@ -150,7 +153,7 @@ out: spin_unlock_bh(&li->lock); - return SIGP_CC_ORDER_CODE_ACCEPTED; + return rc; } static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action) @@ -174,6 +177,16 @@ unlock: spin_unlock(&fi->lock); VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); + + if ((action & ACTION_STORE_ON_STOP) != 0 && rc == -ESHUTDOWN) { + /* If the CPU has already been stopped, we still have + * to save the status when doing stop-and-store. This + * has to be done after unlocking all spinlocks. */ + struct kvm_vcpu *dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); + rc = kvm_s390_store_status_unloaded(dst_vcpu, + KVM_S390_STORE_STATUS_NOADDR); + } + return rc; } --- linux-3.13.0.orig/arch/s390/kernel/head64.S +++ linux-3.13.0/arch/s390/kernel/head64.S @@ -59,7 +59,7 @@ .quad 0 # cr12: tracing off .quad 0 # cr13: home space segment table .quad 0xc0000000 # cr14: machine check handling off - .quad 0 # cr15: linkage stack operations + .quad .Llinkage_stack # cr15: linkage stack operations .Lpcmsk:.quad 0x0000000180000000 .L4malign:.quad 0xffffffffffc00000 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 @@ -67,12 +67,15 @@ .Lparmaddr: .quad PARMAREA .align 64 -.Lduct: .long 0,0,0,0,.Lduald,0,0,0 +.Lduct: .long 0,.Laste,.Laste,0,.Lduald,0,0,0 .long 0,0,0,0,0,0,0,0 +.Laste: .quad 0,0xffffffffffffffff,0,0,0,0,0,0 .align 128 .Lduald:.rept 8 .long 0x80000000,0,0,0 # invalid access-list entries .endr +.Llinkage_stack: + .long 0,0,0x89000000,0,0,0,0x8a000000,0 ENTRY(_ehead) --- linux-3.13.0.orig/arch/s390/include/uapi/asm/statfs.h +++ linux-3.13.0/arch/s390/include/uapi/asm/statfs.h @@ -35,11 +35,11 @@ struct statfs64 { unsigned int f_type; unsigned int f_bsize; - unsigned long f_blocks; - unsigned long f_bfree; - unsigned long f_bavail; - unsigned long f_files; - unsigned long f_ffree; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_bavail; + unsigned long long f_files; + unsigned long long f_ffree; __kernel_fsid_t f_fsid; unsigned int f_namelen; unsigned int f_frsize; --- linux-3.13.0.orig/arch/s390/include/asm/compat.h +++ linux-3.13.0/arch/s390/include/asm/compat.h @@ -38,7 +38,8 @@ #define PSW32_USER_BITS (PSW32_MASK_DAT | PSW32_MASK_IO | PSW32_MASK_EXT | \ PSW32_DEFAULT_KEY | PSW32_MASK_BASE | \ - PSW32_MASK_MCHECK | PSW32_MASK_PSTATE | PSW32_ASC_HOME) + PSW32_MASK_MCHECK | PSW32_MASK_PSTATE | \ + PSW32_ASC_PRIMARY) #define COMPAT_USER_HZ 100 #define COMPAT_UTS_MACHINE "s390\0\0\0\0" --- linux-3.13.0.orig/arch/s390/mm/page-states.c +++ linux-3.13.0/arch/s390/mm/page-states.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #define ESSA_SET_STABLE 1 #define ESSA_SET_UNUSED 2 @@ -41,6 +43,14 @@ if (!cmma_flag) return; + /* + * Disable CMM for dump, otherwise the tprot based memory + * detection can fail because of unstable pages. + */ + if (OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP) { + cmma_flag = 0; + return; + } asm volatile( " .insn rrf,0xb9ab0000,%1,%1,0,0\n" "0: la %0,0\n" --- linux-3.13.0.orig/arch/powerpc/Makefile +++ linux-3.13.0/arch/powerpc/Makefile @@ -225,7 +225,7 @@ all: zImage # With make 3.82 we cannot mix normal and wildcard targets -BOOT_TARGETS1 := zImage zImage.initrd uImage +BOOT_TARGETS1 := zImage zImage.initrd uImage vmlinux.strip BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.% uImage.% PHONY += $(BOOT_TARGETS1) $(BOOT_TARGETS2) --- linux-3.13.0.orig/arch/powerpc/Kconfig +++ linux-3.13.0/arch/powerpc/Kconfig @@ -381,7 +381,7 @@ config KEXEC bool "kexec system call" - depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) + depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) || PPC_BOOK3E help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot @@ -735,6 +735,16 @@ help Freescale General-purpose Timers support +config HAS_FSL_QBMAN + bool "Datapath Acceleration Queue and Buffer management" + help + Datapath Acceleration Queue and Buffer management + +config HAS_FSL_PME + bool + depends on HAS_FSL_QBMAN + default n + # Yes MCA RS/6000s exist but Linux-PPC does not currently support any config MCA bool @@ -1020,6 +1030,8 @@ source "drivers/Kconfig" +source "ubuntu/Kconfig" + source "fs/Kconfig" source "arch/powerpc/sysdev/qe_lib/Kconfig" --- linux-3.13.0.orig/arch/powerpc/xmon/xmon.c +++ linux-3.13.0/arch/powerpc/xmon/xmon.c @@ -171,7 +171,11 @@ #define REG "%.8lx" #endif +#ifdef __LITTLE_ENDIAN__ +#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0]) +#else #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) +#endif #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ || ('a' <= (c) && (c) <= 'f') \ @@ -2051,6 +2055,10 @@ DUMP(p, stab_addr, "lx"); #endif DUMP(p, emergency_sp, "p"); +#ifdef CONFIG_PPC_BOOK3S_64 + DUMP(p, mc_emergency_sp, "p"); + DUMP(p, in_mce, "x"); +#endif DUMP(p, data_offset, "lx"); DUMP(p, hw_cpu_id, "x"); DUMP(p, cpu_start, "x"); --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/opal-wrappers.S +++ linux-3.13.0/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -123,6 +123,7 @@ OPAL_CALL(opal_lpc_read, OPAL_LPC_READ); OPAL_CALL(opal_lpc_write, OPAL_LPC_WRITE); OPAL_CALL(opal_return_cpu, OPAL_RETURN_CPU); +OPAL_CALL(opal_reinit_cpus, OPAL_REINIT_CPUS); OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE); OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE); OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE); --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/opal-xscom.c +++ linux-3.13.0/arch/powerpc/platforms/powernv/opal-xscom.c @@ -71,11 +71,11 @@ } } -static u64 opal_scom_unmangle(u64 reg) +static u64 opal_scom_unmangle(u64 addr) { /* * XSCOM indirect addresses have the top bit set. Additionally - * the reset of the top 3 nibbles is always 0. + * the rest of the top 3 nibbles is always 0. * * Because the debugfs interface uses signed offsets and shifts * the address left by 3, we basically cannot use the top 4 bits @@ -86,10 +86,13 @@ * conversion here. To leave room for further xscom address * expansion, we only clear out the top byte * + * For in-kernel use, we also support the real indirect bit, so + * we test for any of the top 5 bits + * */ - if (reg & (1ull << 59)) - reg = (reg & ~(0xffull << 56)) | (1ull << 63); - return reg; + if (addr & (0x1full << 59)) + addr = (addr & ~(0xffull << 56)) | (1ull << 63); + return addr; } static int opal_scom_read(scom_map_t map, u64 reg, u64 *value) @@ -98,8 +101,8 @@ int64_t rc; __be64 v; - reg = opal_scom_unmangle(reg); - rc = opal_xscom_read(m->chip, m->addr + reg, (__be64 *)__pa(&v)); + reg = opal_scom_unmangle(m->addr + reg); + rc = opal_xscom_read(m->chip, reg, (__be64 *)__pa(&v)); *value = be64_to_cpu(v); return opal_xscom_err_xlate(rc); } @@ -109,8 +112,8 @@ struct opal_scom_map *m = map; int64_t rc; - reg = opal_scom_unmangle(reg); - rc = opal_xscom_write(m->chip, m->addr + reg, value); + reg = opal_scom_unmangle(m->addr + reg); + rc = opal_xscom_write(m->chip, reg, value); return opal_xscom_err_xlate(rc); } --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/pci.h +++ linux-3.13.0/arch/powerpc/platforms/powernv/pci.h @@ -54,7 +54,9 @@ struct iommu_table tce32_table; phys_addr_t tce_inval_reg_phys; - /* XXX TODO: Add support for additional 64-bit iommus */ + /* 64-bit TCE bypass region */ + bool tce_bypass_enabled; + uint64_t tce_bypass_base; /* MSIs. MVE index is identical for for 32 and 64 bit MSI * and -1 if not supported. (It's actually identical to the @@ -113,6 +115,8 @@ unsigned int hwirq, unsigned int virq, unsigned int is_64, struct msi_msg *msg); void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev); + int (*dma_set_mask)(struct pnv_phb *phb, struct pci_dev *pdev, + u64 dma_mask); void (*fixup_phb)(struct pci_controller *hose); u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn); void (*shutdown)(struct pnv_phb *phb); @@ -177,6 +181,7 @@ unsigned char blob[PNV_PCI_DIAG_BUF_SIZE]; struct OpalIoP7IOCPhbErrorData p7ioc; struct OpalIoP7IOCErrorData hub_diag; + struct OpalIoPhb3ErrorData phb3; } diag; }; @@ -186,6 +191,8 @@ extern struct pnv_eeh_ops ioda_eeh_ops; #endif +void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, + unsigned char *log_buff); int pnv_pci_cfg_read(struct device_node *dn, int where, int size, u32 *val); int pnv_pci_cfg_write(struct device_node *dn, --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/pci.c +++ linux-3.13.0/arch/powerpc/platforms/powernv/pci.c @@ -124,77 +124,187 @@ } #endif /* CONFIG_PCI_MSI */ -static void pnv_pci_dump_p7ioc_diag_data(struct pnv_phb *phb) +static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose, + struct OpalIoPhbErrorCommon *common) { - struct OpalIoP7IOCPhbErrorData *data = &phb->diag.p7ioc; + struct OpalIoP7IOCPhbErrorData *data; int i; - pr_info("PHB %d diagnostic data:\n", phb->hose->global_number); + data = (struct OpalIoP7IOCPhbErrorData *)common; + pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n", + hose->global_number, common->version); + + if (data->brdgCtl) + pr_info(" brdgCtl: %08x\n", + data->brdgCtl); + if (data->portStatusReg || data->rootCmplxStatus || + data->busAgentStatus) + pr_info(" UtlSts: %08x %08x %08x\n", + data->portStatusReg, data->rootCmplxStatus, + data->busAgentStatus); + if (data->deviceStatus || data->slotStatus || + data->linkStatus || data->devCmdStatus || + data->devSecStatus) + pr_info(" RootSts: %08x %08x %08x %08x %08x\n", + data->deviceStatus, data->slotStatus, + data->linkStatus, data->devCmdStatus, + data->devSecStatus); + if (data->rootErrorStatus || data->uncorrErrorStatus || + data->corrErrorStatus) + pr_info(" RootErrSts: %08x %08x %08x\n", + data->rootErrorStatus, data->uncorrErrorStatus, + data->corrErrorStatus); + if (data->tlpHdr1 || data->tlpHdr2 || + data->tlpHdr3 || data->tlpHdr4) + pr_info(" RootErrLog: %08x %08x %08x %08x\n", + data->tlpHdr1, data->tlpHdr2, + data->tlpHdr3, data->tlpHdr4); + if (data->sourceId || data->errorClass || + data->correlator) + pr_info(" RootErrLog1: %08x %016llx %016llx\n", + data->sourceId, data->errorClass, + data->correlator); + if (data->p7iocPlssr || data->p7iocCsr) + pr_info(" PhbSts: %016llx %016llx\n", + data->p7iocPlssr, data->p7iocCsr); + if (data->lemFir || data->lemErrorMask || + data->lemWOF) + pr_info(" Lem: %016llx %016llx %016llx\n", + data->lemFir, data->lemErrorMask, + data->lemWOF); + if (data->phbErrorStatus || data->phbFirstErrorStatus || + data->phbErrorLog0 || data->phbErrorLog1) + pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n", + data->phbErrorStatus, data->phbFirstErrorStatus, + data->phbErrorLog0, data->phbErrorLog1); + if (data->mmioErrorStatus || data->mmioFirstErrorStatus || + data->mmioErrorLog0 || data->mmioErrorLog1) + pr_info(" OutErr: %016llx %016llx %016llx %016llx\n", + data->mmioErrorStatus, data->mmioFirstErrorStatus, + data->mmioErrorLog0, data->mmioErrorLog1); + if (data->dma0ErrorStatus || data->dma0FirstErrorStatus || + data->dma0ErrorLog0 || data->dma0ErrorLog1) + pr_info(" InAErr: %016llx %016llx %016llx %016llx\n", + data->dma0ErrorStatus, data->dma0FirstErrorStatus, + data->dma0ErrorLog0, data->dma0ErrorLog1); + if (data->dma1ErrorStatus || data->dma1FirstErrorStatus || + data->dma1ErrorLog0 || data->dma1ErrorLog1) + pr_info(" InBErr: %016llx %016llx %016llx %016llx\n", + data->dma1ErrorStatus, data->dma1FirstErrorStatus, + data->dma1ErrorLog0, data->dma1ErrorLog1); - pr_info(" brdgCtl = 0x%08x\n", data->brdgCtl); + for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { + if ((data->pestA[i] >> 63) == 0 && + (data->pestB[i] >> 63) == 0) + continue; - pr_info(" portStatusReg = 0x%08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus = 0x%08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus = 0x%08x\n", data->busAgentStatus); - - pr_info(" deviceStatus = 0x%08x\n", data->deviceStatus); - pr_info(" slotStatus = 0x%08x\n", data->slotStatus); - pr_info(" linkStatus = 0x%08x\n", data->linkStatus); - pr_info(" devCmdStatus = 0x%08x\n", data->devCmdStatus); - pr_info(" devSecStatus = 0x%08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus = 0x%08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus = 0x%08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus = 0x%08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1 = 0x%08x\n", data->tlpHdr1); - pr_info(" tlpHdr2 = 0x%08x\n", data->tlpHdr2); - pr_info(" tlpHdr3 = 0x%08x\n", data->tlpHdr3); - pr_info(" tlpHdr4 = 0x%08x\n", data->tlpHdr4); - pr_info(" sourceId = 0x%08x\n", data->sourceId); - - pr_info(" errorClass = 0x%016llx\n", data->errorClass); - pr_info(" correlator = 0x%016llx\n", data->correlator); - - pr_info(" p7iocPlssr = 0x%016llx\n", data->p7iocPlssr); - pr_info(" p7iocCsr = 0x%016llx\n", data->p7iocCsr); - pr_info(" lemFir = 0x%016llx\n", data->lemFir); - pr_info(" lemErrorMask = 0x%016llx\n", data->lemErrorMask); - pr_info(" lemWOF = 0x%016llx\n", data->lemWOF); - pr_info(" phbErrorStatus = 0x%016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus = 0x%016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0 = 0x%016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1 = 0x%016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus = 0x%016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus = 0x%016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0 = 0x%016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1 = 0x%016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus = 0x%016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus = 0x%016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0 = 0x%016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1 = 0x%016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus = 0x%016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus = 0x%016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0 = 0x%016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1 = 0x%016llx\n", data->dma1ErrorLog1); + pr_info(" PE[%3d] A/B: %016llx %016llx\n", + i, data->pestA[i], data->pestB[i]); + } +} - for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { +static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose, + struct OpalIoPhbErrorCommon *common) +{ + struct OpalIoPhb3ErrorData *data; + int i; + + data = (struct OpalIoPhb3ErrorData*)common; + pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n", + hose->global_number, common->version); + if (data->brdgCtl) + pr_info(" brdgCtl: %08x\n", + data->brdgCtl); + if (data->portStatusReg || data->rootCmplxStatus || + data->busAgentStatus) + pr_info(" UtlSts: %08x %08x %08x\n", + data->portStatusReg, data->rootCmplxStatus, + data->busAgentStatus); + if (data->deviceStatus || data->slotStatus || + data->linkStatus || data->devCmdStatus || + data->devSecStatus) + pr_info(" RootSts: %08x %08x %08x %08x %08x\n", + data->deviceStatus, data->slotStatus, + data->linkStatus, data->devCmdStatus, + data->devSecStatus); + if (data->rootErrorStatus || data->uncorrErrorStatus || + data->corrErrorStatus) + pr_info(" RootErrSts: %08x %08x %08x\n", + data->rootErrorStatus, data->uncorrErrorStatus, + data->corrErrorStatus); + if (data->tlpHdr1 || data->tlpHdr2 || + data->tlpHdr3 || data->tlpHdr4) + pr_info(" RootErrLog: %08x %08x %08x %08x\n", + data->tlpHdr1, data->tlpHdr2, + data->tlpHdr3, data->tlpHdr4); + if (data->sourceId || data->errorClass || + data->correlator) + pr_info(" RootErrLog1: %08x %016llx %016llx\n", + data->sourceId, data->errorClass, + data->correlator); + if (data->nFir || data->nFirMask || + data->nFirWOF) + pr_info(" nFir: %016llx %016llx %016llx\n", + data->nFir, data->nFirMask, + data->nFirWOF); + if (data->phbPlssr || data->phbCsr) + pr_info(" PhbSts: %016llx %016llx\n", + data->phbPlssr, data->phbCsr); + if (data->lemFir || data->lemErrorMask || + data->lemWOF) + pr_info(" Lem: %016llx %016llx %016llx\n", + data->lemFir, data->lemErrorMask, + data->lemWOF); + if (data->phbErrorStatus || data->phbFirstErrorStatus || + data->phbErrorLog0 || data->phbErrorLog1) + pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n", + data->phbErrorStatus, data->phbFirstErrorStatus, + data->phbErrorLog0, data->phbErrorLog1); + if (data->mmioErrorStatus || data->mmioFirstErrorStatus || + data->mmioErrorLog0 || data->mmioErrorLog1) + pr_info(" OutErr: %016llx %016llx %016llx %016llx\n", + data->mmioErrorStatus, data->mmioFirstErrorStatus, + data->mmioErrorLog0, data->mmioErrorLog1); + if (data->dma0ErrorStatus || data->dma0FirstErrorStatus || + data->dma0ErrorLog0 || data->dma0ErrorLog1) + pr_info(" InAErr: %016llx %016llx %016llx %016llx\n", + data->dma0ErrorStatus, data->dma0FirstErrorStatus, + data->dma0ErrorLog0, data->dma0ErrorLog1); + if (data->dma1ErrorStatus || data->dma1FirstErrorStatus || + data->dma1ErrorLog0 || data->dma1ErrorLog1) + pr_info(" InBErr: %016llx %016llx %016llx %016llx\n", + data->dma1ErrorStatus, data->dma1FirstErrorStatus, + data->dma1ErrorLog0, data->dma1ErrorLog1); + + for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) { if ((data->pestA[i] >> 63) == 0 && (data->pestB[i] >> 63) == 0) continue; - pr_info(" PE[%3d] PESTA = 0x%016llx\n", i, data->pestA[i]); - pr_info(" PESTB = 0x%016llx\n", data->pestB[i]); + + pr_info(" PE[%3d] A/B: %016llx %016llx\n", + i, data->pestA[i], data->pestB[i]); } } -static void pnv_pci_dump_phb_diag_data(struct pnv_phb *phb) +void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, + unsigned char *log_buff) { - switch(phb->model) { - case PNV_PHB_MODEL_P7IOC: - pnv_pci_dump_p7ioc_diag_data(phb); + struct OpalIoPhbErrorCommon *common; + + if (!hose || !log_buff) + return; + + common = (struct OpalIoPhbErrorCommon *)log_buff; + switch (common->ioType) { + case OPAL_PHB_ERROR_DATA_TYPE_P7IOC: + pnv_pci_dump_p7ioc_diag_data(hose, common); + break; + case OPAL_PHB_ERROR_DATA_TYPE_PHB3: + pnv_pci_dump_phb3_diag_data(hose, common); break; default: - pr_warning("PCI %d: Can't decode this PHB diag data\n", - phb->hose->global_number); + pr_warn("%s: Unrecognized ioType %d\n", + __func__, common->ioType); } } @@ -222,7 +332,7 @@ * with the normal errors generated when probing empty slots */ if (has_diag) - pnv_pci_dump_phb_diag_data(phb); + pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob); else pr_warning("PCI %d: No diag data available\n", phb->hose->global_number); @@ -553,6 +663,16 @@ pnv_pci_dma_fallback_setup(hose, pdev); } +int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) +{ + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct pnv_phb *phb = hose->private_data; + + if (phb && phb->dma_set_mask) + return phb->dma_set_mask(phb, pdev, dma_mask); + return __dma_set_mask(&pdev->dev, dma_mask); +} + void pnv_pci_shutdown(void) { struct pci_controller *hose; --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/opal.c +++ linux-3.13.0/arch/powerpc/platforms/powernv/opal.c @@ -18,9 +18,12 @@ #include #include #include +#include #include +#include #include #include +#include #include "powernv.h" @@ -30,8 +33,18 @@ struct opal { u64 base; u64 entry; + u64 size; } opal; +struct mcheck_recoverable_range { + u64 start_addr; + u64 end_addr; + u64 recover_addr; +}; + +static struct mcheck_recoverable_range *mc_recoverable_range; +static int mc_recoverable_range_len; + static struct device_node *opal_node; static DEFINE_SPINLOCK(opal_write_lock); extern u64 opal_mc_secondary_handler[]; @@ -42,28 +55,47 @@ static uint64_t last_notified_mask = 0x0ul; static atomic_t opal_notifier_hold = ATOMIC_INIT(0); +static void opal_reinit_cores(void) +{ + /* Do the actual re-init, This will clobber all FPRs, VRs, etc... + * + * It will preserve non volatile GPRs and HSPRG0/1. It will + * also restore HIDs and other SPRs to their original value + * but it might clobber a bunch. + */ +#ifdef __BIG_ENDIAN__ + opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_BE); +#else + opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_LE); +#endif +} + int __init early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data) { - const void *basep, *entryp; - unsigned long basesz, entrysz; + const void *basep, *entryp, *sizep; + unsigned long basesz, entrysz, runtimesz; if (depth != 1 || strcmp(uname, "ibm,opal") != 0) return 0; basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz); entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz); + sizep = of_get_flat_dt_prop(node, "opal-runtime-size", &runtimesz); - if (!basep || !entryp) + if (!basep || !entryp || !sizep) return 1; opal.base = of_read_number(basep, basesz/4); opal.entry = of_read_number(entryp, entrysz/4); + opal.size = of_read_number(sizep, runtimesz/4); pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n", opal.base, basep, basesz); pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n", opal.entry, entryp, entrysz); + pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%ld)\n", + opal.size, sizep, runtimesz); powerpc_firmware_features |= FW_FEATURE_OPAL; if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) { @@ -77,6 +109,72 @@ printk("OPAL V1 detected !\n"); } + /* Reinit all cores with the right endian */ + opal_reinit_cores(); + + /* Restore some bits */ + if (cur_cpu_spec->cpu_restore) + cur_cpu_spec->cpu_restore(); + + return 1; +} + +int __init early_init_dt_scan_recoverable_ranges(unsigned long node, + const char *uname, int depth, void *data) +{ + unsigned long i, psize, size; + const __be32 *prop; + + if (depth != 1 || strcmp(uname, "ibm,opal") != 0) + return 0; + + prop = of_get_flat_dt_prop(node, "mcheck-recoverable-ranges", &psize); + + if (!prop) + return 1; + + pr_debug("Found machine check recoverable ranges.\n"); + + /* + * Calculate number of available entries. + * + * Each recoverable address range entry is (start address, len, + * recovery address), 2 cells each for start and recovery address, + * 1 cell for len, totalling 5 cells per entry. + */ + mc_recoverable_range_len = psize / (sizeof(*prop) * 5); + + /* Sanity check */ + if (!mc_recoverable_range_len) + return 1; + + /* Size required to hold all the entries. */ + size = mc_recoverable_range_len * + sizeof(struct mcheck_recoverable_range); + + /* + * Allocate a buffer to hold the MC recoverable ranges. We would be + * accessing them in real mode, hence it needs to be within + * RMO region. + */ + mc_recoverable_range =__va(memblock_alloc_base(size, __alignof__(u64), + ppc64_rma_size)); + memset(mc_recoverable_range, 0, size); + + for (i = 0; i < mc_recoverable_range_len; i++) { + mc_recoverable_range[i].start_addr = + of_read_number(prop + (i * 5) + 0, 2); + mc_recoverable_range[i].end_addr = + mc_recoverable_range[i].start_addr + + of_read_number(prop + (i * 5) + 2, 1); + mc_recoverable_range[i].recover_addr = + of_read_number(prop + (i * 5) + 3, 2); + + pr_debug("Machine check recoverable range: %llx..%llx: %llx\n", + mc_recoverable_range[i].start_addr, + mc_recoverable_range[i].end_addr, + mc_recoverable_range[i].recover_addr); + } return 1; } @@ -88,14 +186,10 @@ if (!(powerpc_firmware_features & FW_FEATURE_OPAL)) return -ENODEV; - /* Hookup some exception handlers. We use the fwnmi area at 0x7000 - * to provide the glue space to OPAL + /* Hookup some exception handlers except machine check. We use the + * fwnmi area at 0x7000 to provide the glue space to OPAL */ glue = 0x7000; - opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER, - __pa(opal_mc_secondary_handler[0]), - glue); - glue += 128; opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 0, glue); glue += 128; @@ -254,119 +348,94 @@ return written; } +static int opal_recover_mce(struct pt_regs *regs, + struct machine_check_event *evt) +{ + int recovered = 0; + uint64_t ea = get_mce_fault_addr(evt); + + if (!(regs->msr & MSR_RI)) { + /* If MSR_RI isn't set, we cannot recover */ + recovered = 0; + } else if (evt->disposition == MCE_DISPOSITION_RECOVERED) { + /* Platform corrected itself */ + recovered = 1; + } else if (ea && !is_kernel_addr(ea)) { + /* + * Faulting address is not in kernel text. We should be fine. + * We need to find which process uses this address. + * For now, kill the task if we have received exception when + * in userspace. + * + * TODO: Queue up this address for hwpoisioning later. + */ + if (user_mode(regs) && !is_global_init(current)) { + _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); + recovered = 1; + } else + recovered = 0; + } else if (user_mode(regs) && !is_global_init(current) && + evt->severity == MCE_SEV_ERROR_SYNC) { + /* + * If we have received a synchronous error when in userspace + * kill the task. + */ + _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); + recovered = 1; + } + return recovered; +} + int opal_machine_check(struct pt_regs *regs) { - struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt; - struct opal_machine_check_event evt; - const char *level, *sevstr, *subtype; - static const char *opal_mc_ue_types[] = { - "Indeterminate", - "Instruction fetch", - "Page table walk ifetch", - "Load/Store", - "Page table walk Load/Store", - }; - static const char *opal_mc_slb_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - static const char *opal_mc_erat_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - static const char *opal_mc_tlb_types[] = { - "Indeterminate", - "Parity", - "Multihit", - }; - - /* Copy the event structure and release the original */ - evt = *opal_evt; - opal_evt->in_use = 0; + struct machine_check_event evt; + + if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) + return 0; /* Print things out */ - if (evt.version != OpalMCE_V1) { + if (evt.version != MCE_V1) { pr_err("Machine Check Exception, Unknown event version %d !\n", evt.version); return 0; } - switch(evt.severity) { - case OpalMCE_SEV_NO_ERROR: - level = KERN_INFO; - sevstr = "Harmless"; - break; - case OpalMCE_SEV_WARNING: - level = KERN_WARNING; - sevstr = ""; - break; - case OpalMCE_SEV_ERROR_SYNC: - level = KERN_ERR; - sevstr = "Severe"; - break; - case OpalMCE_SEV_FATAL: - default: - level = KERN_ERR; - sevstr = "Fatal"; - break; - } + machine_check_print_event_info(&evt); - printk("%s%s Machine check interrupt [%s]\n", level, sevstr, - evt.disposition == OpalMCE_DISPOSITION_RECOVERED ? - "Recovered" : "[Not recovered"); - printk("%s Initiator: %s\n", level, - evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown"); - switch(evt.error_type) { - case OpalMCE_ERROR_TYPE_UE: - subtype = evt.u.ue_error.ue_error_type < - ARRAY_SIZE(opal_mc_ue_types) ? - opal_mc_ue_types[evt.u.ue_error.ue_error_type] - : "Unknown"; - printk("%s Error type: UE [%s]\n", level, subtype); - if (evt.u.ue_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.ue_error.effective_address); - if (evt.u.ue_error.physical_address_provided) - printk("%s Physial address: %016llx\n", - level, evt.u.ue_error.physical_address); - break; - case OpalMCE_ERROR_TYPE_SLB: - subtype = evt.u.slb_error.slb_error_type < - ARRAY_SIZE(opal_mc_slb_types) ? - opal_mc_slb_types[evt.u.slb_error.slb_error_type] - : "Unknown"; - printk("%s Error type: SLB [%s]\n", level, subtype); - if (evt.u.slb_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.slb_error.effective_address); - break; - case OpalMCE_ERROR_TYPE_ERAT: - subtype = evt.u.erat_error.erat_error_type < - ARRAY_SIZE(opal_mc_erat_types) ? - opal_mc_erat_types[evt.u.erat_error.erat_error_type] - : "Unknown"; - printk("%s Error type: ERAT [%s]\n", level, subtype); - if (evt.u.erat_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.erat_error.effective_address); - break; - case OpalMCE_ERROR_TYPE_TLB: - subtype = evt.u.tlb_error.tlb_error_type < - ARRAY_SIZE(opal_mc_tlb_types) ? - opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type] - : "Unknown"; - printk("%s Error type: TLB [%s]\n", level, subtype); - if (evt.u.tlb_error.effective_address_provided) - printk("%s Effective address: %016llx\n", - level, evt.u.tlb_error.effective_address); - break; - default: - case OpalMCE_ERROR_TYPE_UNKNOWN: - printk("%s Error type: Unknown\n", level); - break; - } - return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1; + if (opal_recover_mce(regs, &evt)) + return 1; + return 0; +} + +static uint64_t find_recovery_address(uint64_t nip) +{ + int i; + + for (i = 0; i < mc_recoverable_range_len; i++) + if ((nip >= mc_recoverable_range[i].start_addr) && + (nip < mc_recoverable_range[i].end_addr)) + return mc_recoverable_range[i].recover_addr; + return 0; +} + +bool opal_mce_check_early_recovery(struct pt_regs *regs) +{ + uint64_t recover_addr = 0; + + if (!opal.base || !opal.size) + goto out; + + if ((regs->nip >= opal.base) && + (regs->nip <= (opal.base + opal.size))) + recover_addr = find_recovery_address(regs->nip); + + /* + * Setup regs->nip to rfi into fixup address. + */ + if (recover_addr) + regs->nip = recover_addr; + +out: + return !!recover_addr; } static irqreturn_t opal_interrupt(int irq, void *data) --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/setup.c +++ linux-3.13.0/arch/powerpc/platforms/powernv/setup.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -140,6 +141,13 @@ { } +static int pnv_dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (dev_is_pci(dev)) + return pnv_pci_dma_set_mask(to_pci_dev(dev), dma_mask); + return __dma_set_mask(dev, dma_mask); +} + static void pnv_shutdown(void) { /* Let the PCI code clear up IODA tables */ @@ -177,6 +185,7 @@ ppc_md.power_off = pnv_power_off; ppc_md.halt = pnv_halt; ppc_md.machine_check_exception = opal_machine_check; + ppc_md.mce_check_early_recovery = opal_mce_check_early_recovery; } #ifdef CONFIG_PPC_POWERNV_RTAS @@ -225,6 +234,7 @@ .machine_shutdown = pnv_shutdown, .power_save = power7_idle, .calibrate_decr = generic_calibrate_decr, + .dma_set_mask = pnv_dma_set_mask, #ifdef CONFIG_KEXEC .kexec_cpu_down = pnv_kexec_cpu_down, #endif --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/eeh-ioda.c +++ linux-3.13.0/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -114,6 +114,7 @@ ioda_eeh_inbB_dbgfs_set, "0x%llx\n"); #endif /* CONFIG_DEBUG_FS */ + /** * ioda_eeh_post_init - Chip dependent post initialization * @hose: PCI controller @@ -221,6 +222,22 @@ return ret; } +static void ioda_eeh_phb_diag(struct pci_controller *hose) +{ + struct pnv_phb *phb = hose->private_data; + long rc; + + rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, + PNV_PCI_DIAG_BUF_SIZE); + if (rc != OPAL_SUCCESS) { + pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n", + __func__, hose->global_number, rc); + return; + } + + pnv_pci_dump_phb_diag_data(hose, phb->diag.blob); +} + /** * ioda_eeh_get_state - Retrieve the state of PE * @pe: EEH PE @@ -272,6 +289,9 @@ result |= EEH_STATE_DMA_ACTIVE; result |= EEH_STATE_MMIO_ENABLED; result |= EEH_STATE_DMA_ENABLED; + } else if (!(pe->state & EEH_PE_ISOLATED)) { + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + ioda_eeh_phb_diag(hose); } return result; @@ -315,6 +335,15 @@ __func__, fstate, hose->global_number, pe_no); } + /* Dump PHB diag-data for frozen PE */ + if (result != EEH_STATE_NOT_SUPPORT && + (result & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) != + (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) && + !(pe->state & EEH_PE_ISOLATED)) { + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + ioda_eeh_phb_diag(hose); + } + return result; } @@ -490,8 +519,7 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) { struct pci_controller *hose = pe->phb; - struct eeh_dev *edev; - struct pci_dev *dev; + struct pci_bus *bus; int ret; /* @@ -520,76 +548,17 @@ if (pe->type & EEH_PE_PHB) { ret = ioda_eeh_phb_reset(hose, option); } else { - if (pe->type & EEH_PE_DEVICE) { - /* - * If it's device PE, we didn't refer to the parent - * PCI bus yet. So we have to figure it out indirectly. - */ - edev = list_first_entry(&pe->edevs, - struct eeh_dev, list); - dev = eeh_dev_to_pci_dev(edev); - dev = dev->bus->self; - } else { - /* - * If it's bus PE, the parent PCI bus is already there - * and just pick it up. - */ - dev = pe->bus->self; - } - - /* - * Do reset based on the fact that the direct upstream bridge - * is root bridge (port) or not. - */ - if (dev->bus->number == 0) + bus = eeh_pe_bus_get(pe); + if (pci_is_root_bus(bus)) ret = ioda_eeh_root_reset(hose, option); else - ret = ioda_eeh_bridge_reset(hose, dev, option); + ret = ioda_eeh_bridge_reset(hose, bus->self, option); } return ret; } /** - * ioda_eeh_get_log - Retrieve error log - * @pe: EEH PE - * @severity: Severity level of the log - * @drv_log: buffer to store the log - * @len: space of the log buffer - * - * The function is used to retrieve error log from P7IOC. - */ -static int ioda_eeh_get_log(struct eeh_pe *pe, int severity, - char *drv_log, unsigned long len) -{ - s64 ret; - unsigned long flags; - struct pci_controller *hose = pe->phb; - struct pnv_phb *phb = hose->private_data; - - spin_lock_irqsave(&phb->lock, flags); - - ret = opal_pci_get_phb_diag_data2(phb->opal_id, - phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE); - if (ret) { - spin_unlock_irqrestore(&phb->lock, flags); - pr_warning("%s: Can't get log for PHB#%x-PE#%x (%lld)\n", - __func__, hose->global_number, pe->addr, ret); - return -EIO; - } - - /* - * FIXME: We probably need log the error in somewhere. - * Lets make it up in future. - */ - /* pr_info("%s", phb->diag.blob); */ - - spin_unlock_irqrestore(&phb->lock, flags); - - return 0; -} - -/** * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE * @pe: EEH PE * @@ -670,167 +639,6 @@ } } -static void ioda_eeh_p7ioc_phb_diag(struct pci_controller *hose, - struct OpalIoPhbErrorCommon *common) -{ - struct OpalIoP7IOCPhbErrorData *data; - int i; - - data = (struct OpalIoP7IOCPhbErrorData *)common; - - pr_info("P7IOC PHB#%x Diag-data (Version: %d)\n\n", - hose->global_number, common->version); - - pr_info(" brdgCtl: %08x\n", data->brdgCtl); - - pr_info(" portStatusReg: %08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); - - pr_info(" deviceStatus: %08x\n", data->deviceStatus); - pr_info(" slotStatus: %08x\n", data->slotStatus); - pr_info(" linkStatus: %08x\n", data->linkStatus); - pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); - pr_info(" devSecStatus: %08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); - pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); - pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); - pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); - pr_info(" sourceId: %08x\n", data->sourceId); - - pr_info(" errorClass: %016llx\n", data->errorClass); - pr_info(" correlator: %016llx\n", data->correlator); - pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr); - pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr); - pr_info(" lemFir: %016llx\n", data->lemFir); - pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); - pr_info(" lemWOF: %016llx\n", data->lemWOF); - pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); - - for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { - if ((data->pestA[i] >> 63) == 0 && - (data->pestB[i] >> 63) == 0) - continue; - - pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); - pr_info(" PESTB: %016llx\n", data->pestB[i]); - } -} - -static void ioda_eeh_phb3_phb_diag(struct pci_controller *hose, - struct OpalIoPhbErrorCommon *common) -{ - struct OpalIoPhb3ErrorData *data; - int i; - - data = (struct OpalIoPhb3ErrorData*)common; - pr_info("PHB3 PHB#%x Diag-data (Version: %d)\n\n", - hose->global_number, common->version); - - pr_info(" brdgCtl: %08x\n", data->brdgCtl); - - pr_info(" portStatusReg: %08x\n", data->portStatusReg); - pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus); - pr_info(" busAgentStatus: %08x\n", data->busAgentStatus); - - pr_info(" deviceStatus: %08x\n", data->deviceStatus); - pr_info(" slotStatus: %08x\n", data->slotStatus); - pr_info(" linkStatus: %08x\n", data->linkStatus); - pr_info(" devCmdStatus: %08x\n", data->devCmdStatus); - pr_info(" devSecStatus: %08x\n", data->devSecStatus); - - pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus); - pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus); - pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus); - pr_info(" tlpHdr1: %08x\n", data->tlpHdr1); - pr_info(" tlpHdr2: %08x\n", data->tlpHdr2); - pr_info(" tlpHdr3: %08x\n", data->tlpHdr3); - pr_info(" tlpHdr4: %08x\n", data->tlpHdr4); - pr_info(" sourceId: %08x\n", data->sourceId); - pr_info(" errorClass: %016llx\n", data->errorClass); - pr_info(" correlator: %016llx\n", data->correlator); - pr_info(" nFir: %016llx\n", data->nFir); - pr_info(" nFirMask: %016llx\n", data->nFirMask); - pr_info(" nFirWOF: %016llx\n", data->nFirWOF); - pr_info(" PhbPlssr: %016llx\n", data->phbPlssr); - pr_info(" PhbCsr: %016llx\n", data->phbCsr); - pr_info(" lemFir: %016llx\n", data->lemFir); - pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask); - pr_info(" lemWOF: %016llx\n", data->lemWOF); - pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus); - pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus); - pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0); - pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1); - pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus); - pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus); - pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0); - pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1); - pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus); - pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus); - pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0); - pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1); - pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus); - pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus); - pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0); - pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1); - - for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) { - if ((data->pestA[i] >> 63) == 0 && - (data->pestB[i] >> 63) == 0) - continue; - - pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]); - pr_info(" PESTB: %016llx\n", data->pestB[i]); - } -} - -static void ioda_eeh_phb_diag(struct pci_controller *hose) -{ - struct pnv_phb *phb = hose->private_data; - struct OpalIoPhbErrorCommon *common; - long rc; - - rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, - PNV_PCI_DIAG_BUF_SIZE); - if (rc != OPAL_SUCCESS) { - pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n", - __func__, hose->global_number, rc); - return; - } - - common = (struct OpalIoPhbErrorCommon *)phb->diag.blob; - switch (common->ioType) { - case OPAL_PHB_ERROR_DATA_TYPE_P7IOC: - ioda_eeh_p7ioc_phb_diag(hose, common); - break; - case OPAL_PHB_ERROR_DATA_TYPE_PHB3: - ioda_eeh_phb3_phb_diag(hose, common); - break; - default: - pr_warning("%s: Unrecognized I/O chip %d\n", - __func__, common->ioType); - } -} - static int ioda_eeh_get_phb_pe(struct pci_controller *hose, struct eeh_pe **pe) { @@ -884,12 +692,12 @@ */ static int ioda_eeh_next_error(struct eeh_pe **pe) { - struct pci_controller *hose, *tmp; + struct pci_controller *hose; struct pnv_phb *phb; u64 frozen_pe_no; u16 err_type, severity; long rc; - int ret = 1; + int ret = EEH_NEXT_ERR_NONE; /* * While running here, it's safe to purge the event queue. @@ -899,7 +707,7 @@ eeh_remove_event(NULL); opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + list_for_each_entry(hose, &hose_list, list_node) { /* * If the subordinate PCI buses of the PHB has been * removed, we needn't take care of it any more. @@ -938,19 +746,19 @@ switch (err_type) { case OPAL_EEH_IOC_ERROR: if (severity == OPAL_EEH_SEV_IOC_DEAD) { - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { + list_for_each_entry(hose, &hose_list, + list_node) { phb = hose->private_data; phb->eeh_state |= PNV_EEH_STATE_REMOVED; } pr_err("EEH: dead IOC detected\n"); - ret = 4; - goto out; + ret = EEH_NEXT_ERR_DEAD_IOC; } else if (severity == OPAL_EEH_SEV_INF) { pr_info("EEH: IOC informative error " "detected\n"); ioda_eeh_hub_diag(hose); + ret = EEH_NEXT_ERR_NONE; } break; @@ -962,21 +770,20 @@ pr_err("EEH: dead PHB#%x detected\n", hose->global_number); phb->eeh_state |= PNV_EEH_STATE_REMOVED; - ret = 3; - goto out; + ret = EEH_NEXT_ERR_DEAD_PHB; } else if (severity == OPAL_EEH_SEV_PHB_FENCED) { if (ioda_eeh_get_phb_pe(hose, pe)) break; pr_err("EEH: fenced PHB#%x detected\n", hose->global_number); - ret = 2; - goto out; + ret = EEH_NEXT_ERR_FENCED_PHB; } else if (severity == OPAL_EEH_SEV_INF) { pr_info("EEH: PHB#%x informative error " "detected\n", hose->global_number); ioda_eeh_phb_diag(hose); + ret = EEH_NEXT_ERR_NONE; } break; @@ -986,13 +793,37 @@ pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", (*pe)->addr, (*pe)->phb->global_number); - ret = 1; - goto out; + ret = EEH_NEXT_ERR_FROZEN_PE; + break; + default: + pr_warn("%s: Unexpected error type %d\n", + __func__, err_type); + } + + /* + * EEH core will try recover from fenced PHB or + * frozen PE. In the time for frozen PE, EEH core + * enable IO path for that before collecting logs, + * but it ruins the site. So we have to dump the + * log in advance here. + */ + if ((ret == EEH_NEXT_ERR_FROZEN_PE || + ret == EEH_NEXT_ERR_FENCED_PHB) && + !((*pe)->state & EEH_PE_ISOLATED)) { + eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); + ioda_eeh_phb_diag(hose); } + + /* + * If we have no errors on the specific PHB or only + * informative error there, we continue poking it. + * Otherwise, we need actions to be taken by upper + * layer. + */ + if (ret > EEH_NEXT_ERR_INF) + break; } - ret = 0; -out: return ret; } @@ -1001,7 +832,6 @@ .set_option = ioda_eeh_set_option, .get_state = ioda_eeh_get_state, .reset = ioda_eeh_reset, - .get_log = ioda_eeh_get_log, .configure_bridge = ioda_eeh_configure_bridge, .next_error = ioda_eeh_next_error }; --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/powernv.h +++ linux-3.13.0/arch/powerpc/platforms/powernv/powernv.h @@ -7,12 +7,20 @@ static inline void pnv_smp_init(void) { } #endif +struct pci_dev; + #ifdef CONFIG_PCI extern void pnv_pci_init(void); extern void pnv_pci_shutdown(void); +extern int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask); #else static inline void pnv_pci_init(void) { } static inline void pnv_pci_shutdown(void) { } + +static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) +{ + return -ENODEV; +} #endif extern void pnv_lpc_init(void); --- linux-3.13.0.orig/arch/powerpc/platforms/powernv/pci-ioda.c +++ linux-3.13.0/arch/powerpc/platforms/powernv/pci-ioda.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -460,9 +461,39 @@ return; pe = &phb->ioda.pe_array[pdn->pe_number]; + WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops); set_iommu_table_base(&pdev->dev, &pe->tce32_table); } +static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb, + struct pci_dev *pdev, u64 dma_mask) +{ + struct pci_dn *pdn = pci_get_pdn(pdev); + struct pnv_ioda_pe *pe; + uint64_t top; + bool bypass = false; + + if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE)) + return -ENODEV;; + + pe = &phb->ioda.pe_array[pdn->pe_number]; + if (pe->tce_bypass_enabled) { + top = pe->tce_bypass_base + memblock_end_of_DRAM() - 1; + bypass = (dma_mask >= top); + } + + if (bypass) { + dev_info(&pdev->dev, "Using 64-bit DMA iommu bypass\n"); + set_dma_ops(&pdev->dev, &dma_direct_ops); + set_dma_offset(&pdev->dev, pe->tce_bypass_base); + } else { + dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n"); + set_dma_ops(&pdev->dev, &dma_iommu_ops); + set_iommu_table_base(&pdev->dev, &pe->tce32_table); + } + return 0; +} + static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) { struct pci_dev *dev; @@ -657,6 +688,56 @@ __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs)); } +static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable) +{ + struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe, + tce32_table); + uint16_t window_id = (pe->pe_number << 1 ) + 1; + int64_t rc; + + pe_info(pe, "%sabling 64-bit DMA bypass\n", enable ? "En" : "Dis"); + if (enable) { + phys_addr_t top = memblock_end_of_DRAM(); + + top = roundup_pow_of_two(top); + rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id, + pe->pe_number, + window_id, + pe->tce_bypass_base, + top); + } else { + rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id, + pe->pe_number, + window_id, + pe->tce_bypass_base, + 0); + + /* + * We might want to reset the DMA ops of all devices on + * this PE. However in theory, that shouldn't be necessary + * as this is used for VFIO/KVM pass-through and the device + * hasn't yet been returned to its kernel driver + */ + } + if (rc) + pe_err(pe, "OPAL error %lld configuring bypass window\n", rc); + else + pe->tce_bypass_enabled = enable; +} + +static void pnv_pci_ioda2_setup_bypass_pe(struct pnv_phb *phb, + struct pnv_ioda_pe *pe) +{ + /* TVE #1 is selected by PCI address bit 59 */ + pe->tce_bypass_base = 1ull << 59; + + /* Install set_bypass callback for VFIO */ + pe->tce32_table.set_bypass = pnv_pci_ioda2_set_bypass; + + /* Enable bypass by default */ + pnv_pci_ioda2_set_bypass(&pe->tce32_table, true); +} + static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe) { @@ -727,6 +808,8 @@ else pnv_ioda_setup_bus_dma(pe, pe->pbus); + /* Also create a bypass window */ + pnv_pci_ioda2_setup_bypass_pe(phb, pe); return; fail: if (pe->tce32_seg >= 0) @@ -1287,6 +1370,7 @@ /* Setup TCEs */ phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup; + phb->dma_set_mask = pnv_pci_ioda_dma_set_mask; /* Setup shutdown function for kexec */ phb->shutdown = pnv_pci_ioda_shutdown; --- linux-3.13.0.orig/arch/powerpc/platforms/85xx/smp.c +++ linux-3.13.0/arch/powerpc/platforms/85xx/smp.c @@ -176,6 +176,9 @@ int hw_cpu = get_hard_smp_processor_id(nr); int ioremappable; int ret = 0; +#ifdef CONFIG_PPC64 + unsigned long *ptr = NULL; +#endif WARN_ON(nr < 0 || nr >= NR_CPUS); WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS); @@ -264,11 +267,18 @@ #else smp_generic_kick_cpu(nr); - flush_spin_table(spin_table); - out_be32(&spin_table->pir, hw_cpu); - out_be64((u64 *)(&spin_table->addr_h), - __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); - flush_spin_table(spin_table); + ptr = (unsigned long *)((unsigned long)&__run_at_kexec); + /* We shouldn't access spin_table from the bootloader to up any + * secondary cpu for kexec kernel, and kexec kernel already + * know how to jump to generic_secondary_smp_init. + */ + if (!*ptr) { + flush_spin_table(spin_table); + out_be32(&spin_table->pir, hw_cpu); + out_be64((u64 *)(&spin_table->addr_h), + __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); + flush_spin_table(spin_table); + } #endif local_irq_restore(flags); @@ -293,6 +303,7 @@ }; #ifdef CONFIG_KEXEC +#ifdef CONFIG_PPC32 atomic_t kexec_down_cpus = ATOMIC_INIT(0); void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary) @@ -311,6 +322,14 @@ if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0,1); } +#else +void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary) +{ + local_irq_disable(); + hard_irq_disable(); + mpic_teardown_this_cpu(secondary); +} +#endif static void map_and_flush(unsigned long paddr) { @@ -362,11 +381,14 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image) { +#ifdef CONFIG_PPC32 int timeout = INT_MAX; int i, num_cpus = num_present_cpus(); +#endif mpc85xx_smp_flush_dcache_kexec(image); +#ifdef CONFIG_PPC32 if (image->type == KEXEC_TYPE_DEFAULT) smp_call_function(mpc85xx_smp_kexec_down, NULL, 0); @@ -384,6 +406,7 @@ if ( i == smp_processor_id() ) continue; mpic_reset_core(i); } +#endif default_machine_kexec(image); } --- linux-3.13.0.orig/arch/powerpc/platforms/85xx/corenet_generic.c +++ linux-3.13.0/arch/powerpc/platforms/85xx/corenet_generic.c @@ -64,6 +64,9 @@ .compatible = "simple-bus" }, { + .compatible = "fsl,dpaa" + }, + { .compatible = "fsl,srio", }, { @@ -96,6 +99,32 @@ return of_platform_bus_probe(NULL, of_device_ids, NULL); } +/* Early setup is required for large chunks of contiguous (and coarsely-aligned) + * memory. The following shoe-horns Qman/Bman "init_early" calls into the + * platform setup to let them parse their CCSR nodes early on. */ +#ifdef CONFIG_FSL_QMAN_CONFIG +void __init qman_init_early(void); +#endif +#ifdef CONFIG_FSL_BMAN_CONFIG +void __init bman_init_early(void); +#endif +#ifdef CONFIG_FSL_PME2_CTRL +void __init pme2_init_early(void); +#endif + +__init void corenet_ds_init_early(void) +{ +#ifdef CONFIG_FSL_QMAN_CONFIG + qman_init_early(); +#endif +#ifdef CONFIG_FSL_BMAN_CONFIG + bman_init_early(); +#endif +#ifdef CONFIG_FSL_PME2_CTRL + pme2_init_early(); +#endif +} + static const char * const boards[] __initconst = { "fsl,P2041RDB", "fsl,P3041DS", @@ -103,6 +132,7 @@ "fsl,P5020DS", "fsl,P5040DS", "fsl,T4240QDS", + "fsl,T4240RDB", "fsl,B4860QDS", "fsl,B4420QDS", "fsl,B4220QDS", @@ -116,6 +146,7 @@ "fsl,P5020DS-hv", "fsl,P5040DS-hv", "fsl,T4240QDS-hv", + "fsl,T4240RDB-hv", "fsl,B4860QDS-hv", "fsl,B4420QDS-hv", "fsl,B4220QDS-hv", @@ -173,6 +204,7 @@ #else .power_save = e500_idle, #endif + .init_early = corenet_ds_init_early, }; machine_arch_initcall(corenet_generic, corenet_gen_publish_devices); --- linux-3.13.0.orig/arch/powerpc/platforms/85xx/Kconfig +++ linux-3.13.0/arch/powerpc/platforms/85xx/Kconfig @@ -253,6 +253,8 @@ select ARCH_REQUIRE_GPIOLIB select GPIO_MPC8XXX select HAS_RAPIDIO + select HAS_FSL_QBMAN + select HAS_FSL_PME select PPC_EPAPR_HV_PIC help This option enables support for the FSL CoreNet based boards. --- linux-3.13.0.orig/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ linux-3.13.0/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -35,12 +35,7 @@ #include "offline_states.h" /* This version can't take the spinlock, because it never returns */ -static struct rtas_args rtas_stop_self_args = { - .token = RTAS_UNKNOWN_SERVICE, - .nargs = 0, - .nret = 1, - .rets = &rtas_stop_self_args.args[0], -}; +static int rtas_stop_self_token = RTAS_UNKNOWN_SERVICE; static DEFINE_PER_CPU(enum cpu_state_vals, preferred_offline_state) = CPU_STATE_OFFLINE; @@ -93,15 +88,20 @@ static void rtas_stop_self(void) { - struct rtas_args *args = &rtas_stop_self_args; + struct rtas_args args = { + .token = cpu_to_be32(rtas_stop_self_token), + .nargs = 0, + .nret = 1, + .rets = &args.args[0], + }; local_irq_disable(); - BUG_ON(args->token == RTAS_UNKNOWN_SERVICE); + BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE); printk("cpu %u (hwid %u) Ready to die...\n", smp_processor_id(), hard_smp_processor_id()); - enter_rtas(__pa(args)); + enter_rtas(__pa(&args)); panic("Alas, I survived.\n"); } @@ -392,10 +392,10 @@ } } - rtas_stop_self_args.token = rtas_token("stop-self"); + rtas_stop_self_token = rtas_token("stop-self"); qcss_tok = rtas_token("query-cpu-stopped-state"); - if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE || + if (rtas_stop_self_token == RTAS_UNKNOWN_SERVICE || qcss_tok == RTAS_UNKNOWN_SERVICE) { printk(KERN_INFO "CPU Hotplug not supported by firmware " "- disabling.\n"); --- linux-3.13.0.orig/arch/powerpc/kvm/book3s_segment.S +++ linux-3.13.0/arch/powerpc/kvm/book3s_segment.S @@ -289,6 +289,15 @@ #endif stw r0, SVCPU_LAST_INST(r13) +#ifdef CONFIG_PPC64 + andi. r9, r4, MSR_LE + beq no_ld_last_inst + + /* swap and store the result */ + addi r9, r13, SVCPU_LAST_INST + stwbrx r0, 0, r9 +#endif + no_ld_last_inst: /* Unset guest mode */ --- linux-3.13.0.orig/arch/powerpc/kvm/emulate.c +++ linux-3.13.0/arch/powerpc/kvm/emulate.c @@ -219,7 +219,6 @@ * lmw * stmw * - * XXX is_bigendian should depend on MMU mapping or MSR[LE] */ /* XXX Should probably auto-generate instruction decoding for a particular core * from opcode tables in the future. */ --- linux-3.13.0.orig/arch/powerpc/kvm/e500_mmu.c +++ linux-3.13.0/arch/powerpc/kvm/e500_mmu.c @@ -127,7 +127,7 @@ } static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, - unsigned int eaddr, int as) + gva_t eaddr, int as) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); unsigned int victim, tsized; --- linux-3.13.0.orig/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ linux-3.13.0/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -262,7 +262,7 @@ static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu) { - kvmppc_set_msr(vcpu, MSR_SF | MSR_ME); + kvmppc_set_msr(vcpu, vcpu->arch.intr_msr); } /* @@ -544,7 +544,7 @@ * If we fail, we just return to the guest and try executing it again. */ if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) { - ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false); + ret = kvmppc_ld32(vcpu, &srr0, &last_inst, false); if (ret != EMULATE_DONE || last_inst == KVM_INST_FETCH_FAILED) return RESUME_GUEST; vcpu->arch.last_inst = last_inst; --- linux-3.13.0.orig/arch/powerpc/kvm/book3s_hv.c +++ linux-3.13.0/arch/powerpc/kvm/book3s_hv.c @@ -85,10 +85,13 @@ /* CPU points to the first thread of the core */ if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) { +#ifdef CONFIG_KVM_XICS int real_cpu = cpu + vcpu->arch.ptid; if (paca[real_cpu].kvm_hstate.xics_phys) xics_wake_cpu(real_cpu); - else if (cpu_online(cpu)) + else +#endif + if (cpu_online(cpu)) smp_send_reschedule(cpu); } put_cpu(); @@ -537,6 +540,48 @@ vcpu->arch.dtl.dirty = true; } +static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, + unsigned long resource, unsigned long value1, + unsigned long value2) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_vcpu *v; + int n; + + switch (resource) { + case H_SET_MODE_RESOURCE_LE: + if (value1) + return H_P3; + if (value2) + return H_P4; + + switch (mflags) { + case 0: + mutex_lock(&kvm->lock); + kvm->arch.lpcr &= ~LPCR_ILE; + kvm_for_each_vcpu(n, v, kvm) + v->arch.intr_msr &= ~MSR_LE; + mutex_unlock(&kvm->lock); + kick_all_cpus_sync(); + return H_SUCCESS; + + case 1: + mutex_lock(&kvm->lock); + kvm->arch.lpcr |= LPCR_ILE; + kvm_for_each_vcpu(n, v, kvm) + v->arch.intr_msr |= MSR_LE; + mutex_unlock(&kvm->lock); + kick_all_cpus_sync(); + return H_SUCCESS; + + default: + return H_UNSUPPORTED_FLAG_START; + } + default: + return H_P2; + } +} + int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) { unsigned long req = kvmppc_get_gpr(vcpu, 3); @@ -602,6 +647,12 @@ /* Send the error out to userspace via KVM_RUN */ return rc; + case H_SET_MODE: + ret = kvmppc_h_set_mode(vcpu, kvmppc_get_gpr(vcpu, 4), + kvmppc_get_gpr(vcpu, 5), + kvmppc_get_gpr(vcpu, 6), + kvmppc_get_gpr(vcpu, 7)); + break; case H_XIRR: case H_CPPR: @@ -1017,6 +1068,7 @@ spin_lock_init(&vcpu->arch.vpa_update_lock); spin_lock_init(&vcpu->arch.tbacct_lock); vcpu->arch.busy_preempt = TB_NIL; + vcpu->arch.intr_msr = MSR_SF | MSR_ME; kvmppc_mmu_book3s_hv_init(vcpu); @@ -1189,7 +1241,9 @@ smp_wmb(); #if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP) if (vcpu->arch.ptid) { +#ifdef CONFIG_KVM_XICS xics_wake_cpu(cpu); +#endif ++vc->n_woken; } #endif --- linux-3.13.0.orig/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ linux-3.13.0/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -676,8 +676,7 @@ 12: mr r6,r10 mr r10,r0 mr r7,r11 - li r11,(MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11,r11,63 + ld r11,VCPU_INTR_MSR(r4) b 5f 11: beq 5f mfspr r0,SPRN_DEC @@ -896,8 +895,7 @@ mtspr SPRN_SRR0, r10 mtspr SPRN_SRR1, r11 li r10, BOOK3S_INTERRUPT_EXTERNAL - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 + ld r11,VCPU_INTR_MSR(r9) 2: mr r4, r9 mtspr SPRN_LPCR, r8 b fast_guest_return @@ -1386,8 +1384,7 @@ mtspr SPRN_SRR0, r10 mtspr SPRN_SRR1, r11 li r10, BOOK3S_INTERRUPT_DATA_STORAGE - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 + ld r11,VCPU_INTR_MSR(r9) fast_interrupt_c_return: 6: ld r7, VCPU_CTR(r9) lwz r8, VCPU_XER(r9) @@ -1415,10 +1412,19 @@ lwz r8, 0(r10) mtmsrd r3 + andi. r0, r11, MSR_LE + /* Store the result */ stw r8, VCPU_LAST_INST(r9) + beq after_inst_store + + /* Swap and store the result */ + addi r4, r9, VCPU_LAST_INST + stwbrx r8, 0, r4 + /* Unset guest mode. */ +after_inst_store: li r0, KVM_GUEST_MODE_HOST_HV stb r0, HSTATE_IN_GUEST(r13) b guest_exit_cont @@ -1456,8 +1462,7 @@ 1: mtspr SPRN_SRR0, r10 mtspr SPRN_SRR1, r11 li r10, BOOK3S_INTERRUPT_INST_STORAGE - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 + ld r11,VCPU_INTR_MSR(r9) b fast_interrupt_c_return 3: ld r6, VCPU_KVM(r9) /* not relocated, use VRMA */ @@ -1783,8 +1788,7 @@ beq mc_cont /* If not, deliver a machine check. SRR0/1 are already set */ li r10, BOOK3S_INTERRUPT_MACHINE_CHECK - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 + ld r11,VCPU_INTR_MSR(r9) b fast_interrupt_c_return /* --- linux-3.13.0.orig/arch/powerpc/kvm/powerpc.c +++ linux-3.13.0/arch/powerpc/kvm/powerpc.c @@ -673,9 +673,13 @@ } int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, int is_bigendian) + unsigned int rt, unsigned int bytes, int not_reverse) { int idx, ret; + int is_bigendian = not_reverse; + + if (!kvmppc_is_bigendian(vcpu)) + is_bigendian = !not_reverse; if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, @@ -711,21 +715,25 @@ /* Same as above, but sign extends */ int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, int is_bigendian) + unsigned int rt, unsigned int bytes, int not_reverse) { int r; vcpu->arch.mmio_sign_extend = 1; - r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian); + r = kvmppc_handle_load(run, vcpu, rt, bytes, not_reverse); return r; } int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, - u64 val, unsigned int bytes, int is_bigendian) + u64 val, unsigned int bytes, int not_reverse) { void *data = run->mmio.data; int idx, ret; + int is_bigendian = not_reverse; + + if (!kvmppc_is_bigendian(vcpu)) + is_bigendian = !not_reverse; if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, --- linux-3.13.0.orig/arch/powerpc/kvm/book3s_hv_ras.c +++ linux-3.13.0/arch/powerpc/kvm/book3s_hv_ras.c @@ -12,6 +12,7 @@ #include #include #include +#include /* SRR1 bits for machine check on POWER7 */ #define SRR1_MC_LDSTERR (1ul << (63-42)) @@ -58,18 +59,6 @@ } } -/* POWER7 TLB flush */ -static void flush_tlb_power7(struct kvm_vcpu *vcpu) -{ - unsigned long i, rb; - - rb = TLBIEL_INVAL_SET_LPID; - for (i = 0; i < POWER7_TLB_SETS; ++i) { - asm volatile("tlbiel %0" : : "r" (rb)); - rb += 1 << TLBIEL_INVAL_SET_SHIFT; - } -} - /* * On POWER7, see if we can handle a machine check that occurred inside * the guest in real mode, without switching to the host partition. @@ -79,9 +68,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) { unsigned long srr1 = vcpu->arch.shregs.msr; -#ifdef CONFIG_PPC_POWERNV - struct opal_machine_check_event *opal_evt; -#endif + struct machine_check_event mce_evt; long handled = 1; if (srr1 & SRR1_MC_LDSTERR) { @@ -96,7 +83,8 @@ DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI); } if (dsisr & DSISR_MC_TLB_MULTI) { - flush_tlb_power7(vcpu); + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); dsisr &= ~DSISR_MC_TLB_MULTI; } /* Any other errors we don't understand? */ @@ -113,28 +101,38 @@ reload_slb(vcpu); break; case SRR1_MC_IFETCH_TLBMULTI: - flush_tlb_power7(vcpu); + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); break; default: handled = 0; } -#ifdef CONFIG_PPC_POWERNV /* - * See if OPAL has already handled the condition. - * We assume that if the condition is recovered then OPAL + * See if we have already handled the condition in the linux host. + * We assume that if the condition is recovered then linux host * will have generated an error log event that we will pick * up and log later. + * Don't release mce event now. In case if condition is not + * recovered we do guest exit and go back to linux host machine + * check handler. Hence we need make sure that current mce event + * is available for linux host to consume. */ - opal_evt = local_paca->opal_mc_evt; - if (opal_evt->version == OpalMCE_V1 && - (opal_evt->severity == OpalMCE_SEV_NO_ERROR || - opal_evt->disposition == OpalMCE_DISPOSITION_RECOVERED)) + if (!get_mce_event(&mce_evt, MCE_EVENT_DONTRELEASE)) + goto out; + + if (mce_evt.version == MCE_V1 && + (mce_evt.severity == MCE_SEV_NO_ERROR || + mce_evt.disposition == MCE_DISPOSITION_RECOVERED)) handled = 1; +out: + /* + * If we have handled the error, then release the mce event because + * we will be delivering machine check to guest. + */ if (handled) - opal_evt->in_use = 0; -#endif + release_mce_event(); return handled; } --- linux-3.13.0.orig/arch/powerpc/kvm/book3s_pr.c +++ linux-3.13.0/arch/powerpc/kvm/book3s_pr.c @@ -627,7 +627,7 @@ u32 last_inst = kvmppc_get_last_inst(vcpu); int ret; - ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false); + ret = kvmppc_ld32(vcpu, &srr0, &last_inst, false); if (ret == -ENOENT) { ulong msr = vcpu->arch.shared->msr; --- linux-3.13.0.orig/arch/powerpc/kernel/cacheinfo.c +++ linux-3.13.0/arch/powerpc/kernel/cacheinfo.c @@ -794,6 +794,9 @@ { remove_index_dirs(cache_dir); + /* Remove cache dir from sysfs */ + kobject_del(cache_dir->kobj); + kobject_put(cache_dir->kobj); kfree(cache_dir); --- linux-3.13.0.orig/arch/powerpc/kernel/signal.c +++ linux-3.13.0/arch/powerpc/kernel/signal.c @@ -203,8 +203,7 @@ #ifdef CONFIG_PPC_TRANSACTIONAL_MEM if (MSR_TM_ACTIVE(regs->msr)) { - tm_enable(); - tm_reclaim(¤t->thread, regs->msr, TM_CAUSE_SIGNAL); + tm_reclaim_current(TM_CAUSE_SIGNAL); if (MSR_TM_TRANSACTIONAL(regs->msr)) return current->thread.ckpt_regs.gpr[1]; } --- linux-3.13.0.orig/arch/powerpc/kernel/eeh_driver.c +++ linux-3.13.0/arch/powerpc/kernel/eeh_driver.c @@ -626,84 +626,90 @@ { struct eeh_pe *pe, *phb_pe; struct pci_bus *bus; - struct pci_controller *hose, *tmp; + struct pci_controller *hose; unsigned long flags; - int rc = 0; + int rc; - /* - * The return value from next_error() has been classified as follows. - * It might be good to enumerate them. However, next_error() is only - * supported by PowerNV platform for now. So it would be fine to use - * integer directly: - * - * 4 - Dead IOC 3 - Dead PHB - * 2 - Fenced PHB 1 - Frozen PE - * 0 - No error found - * - */ - rc = eeh_ops->next_error(&pe); - if (rc <= 0) - return; - - switch (rc) { - case 4: - /* Mark all PHBs in dead state */ - eeh_serialize_lock(&flags); - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe) continue; - eeh_pe_state_mark(phb_pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + do { + rc = eeh_ops->next_error(&pe); + + switch (rc) { + case EEH_NEXT_ERR_DEAD_IOC: + /* Mark all PHBs in dead state */ + eeh_serialize_lock(&flags); + + /* Purge all events */ + eeh_remove_event(NULL); + + list_for_each_entry(hose, &hose_list, list_node) { + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe) continue; + + eeh_pe_state_mark(phb_pe, + EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + } + + eeh_serialize_unlock(flags); + + break; + case EEH_NEXT_ERR_FROZEN_PE: + case EEH_NEXT_ERR_FENCED_PHB: + case EEH_NEXT_ERR_DEAD_PHB: + /* Mark the PE in fenced state */ + eeh_serialize_lock(&flags); + + /* Purge all events of the PHB */ + eeh_remove_event(pe); + + if (rc == EEH_NEXT_ERR_DEAD_PHB) + eeh_pe_state_mark(pe, + EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); + else + eeh_pe_state_mark(pe, + EEH_PE_ISOLATED | EEH_PE_RECOVERING); + + eeh_serialize_unlock(flags); + + break; + case EEH_NEXT_ERR_NONE: + return; + default: + pr_warn("%s: Invalid value %d from next_error()\n", + __func__, rc); + return; } - eeh_serialize_unlock(flags); - /* Purge all events */ - eeh_remove_event(NULL); - break; - case 3: - case 2: - case 1: - /* Mark the PE in fenced state */ - eeh_serialize_lock(&flags); - if (rc == 3) - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_PHB_DEAD); - else - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_RECOVERING); - eeh_serialize_unlock(flags); - - /* Purge all events of the PHB */ - eeh_remove_event(pe); - break; - default: - pr_err("%s: Invalid value %d from next_error()\n", - __func__, rc); - return; - } - - /* - * For fenced PHB and frozen PE, it's handled as normal - * event. We have to remove the affected PHBs for dead - * PHB and IOC - */ - if (rc == 2 || rc == 1) - eeh_handle_normal_event(pe); - else { - list_for_each_entry_safe(hose, tmp, - &hose_list, list_node) { - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe || !(phb_pe->state & EEH_PE_PHB_DEAD)) - continue; - - bus = eeh_pe_bus_get(phb_pe); - /* Notify all devices that they're about to go down. */ - eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); - pcibios_remove_pci_devices(bus); + /* + * For fenced PHB and frozen PE, it's handled as normal + * event. We have to remove the affected PHBs for dead + * PHB and IOC + */ + if (rc == EEH_NEXT_ERR_FROZEN_PE || + rc == EEH_NEXT_ERR_FENCED_PHB) { + eeh_handle_normal_event(pe); + } else { + list_for_each_entry(hose, &hose_list, list_node) { + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe || + !(phb_pe->state & EEH_PE_PHB_DEAD)) + continue; + + /* Notify all devices to be down */ + bus = eeh_pe_bus_get(phb_pe); + eeh_pe_dev_traverse(pe, + eeh_report_failure, NULL); + pcibios_remove_pci_devices(bus); + } } - } + + /* + * If we have detected dead IOC, we needn't proceed + * any more since all PHBs would have been removed + */ + if (rc == EEH_NEXT_ERR_DEAD_IOC) + break; + } while (rc != EEH_NEXT_ERR_NONE); } /** --- linux-3.13.0.orig/arch/powerpc/kernel/exceptions-64e.S +++ linux-3.13.0/arch/powerpc/kernel/exceptions-64e.S @@ -309,8 +309,8 @@ EXCEPTION_STUB(0x300, hypercall) EXCEPTION_STUB(0x320, ehpriv) - .globl interrupt_end_book3e -interrupt_end_book3e: + .globl __end_interrupts +__end_interrupts: /* Critical Input Interrupt */ START_EXCEPTION(critical_input); @@ -494,7 +494,7 @@ beq+ 1f LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) - LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e) + LOAD_REG_IMMEDIATE(r15,__end_interrupts) cmpld cr0,r10,r14 cmpld cr1,r10,r15 blt+ cr0,1f @@ -560,7 +560,7 @@ beq+ 1f LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) - LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e) + LOAD_REG_IMMEDIATE(r15,__end_interrupts) cmpld cr0,r10,r14 cmpld cr1,r10,r15 blt+ cr0,1f @@ -1099,7 +1099,15 @@ * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping */ /* Now we branch the new virtual address mapped by this entry */ +#ifdef CONFIG_RELOCATABLE + /* We have to find out address from lr. */ + bl 1f /* Find our address */ +1: mflr r6 + addi r6,r6,(2f - 1b) + tovirt(r6,r6) +#else LOAD_REG_IMMEDIATE(r6,2f) +#endif lis r7,MSR_KERNEL@h ori r7,r7,MSR_KERNEL@l mtspr SPRN_SRR0,r6 @@ -1350,9 +1358,17 @@ mflr r28 b 3b -_STATIC(init_core_book3e) +_GLOBAL(init_core_book3e) /* Establish the interrupt vector base */ +#ifdef CONFIG_RELOCATABLE +/* In relocatable case the value of the constant expression 'expr' is only + * offset. So instead, we should loads the address of label 'name'. + */ + tovirt(r2,r2) + LOAD_REG_ADDR(r3, interrupt_base_book3e) +#else LOAD_REG_IMMEDIATE(r3, interrupt_base_book3e) +#endif mtspr SPRN_IVPR,r3 sync blr --- linux-3.13.0.orig/arch/powerpc/kernel/signal_64.c +++ linux-3.13.0/arch/powerpc/kernel/signal_64.c @@ -65,8 +65,8 @@ struct siginfo __user *pinfo; void __user *puc; struct siginfo info; - /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */ - char abigap[288]; + /* New 64 bit little-endian ABI allows redzone of 512 bytes below sp */ + char abigap[USER_REDZONE_SIZE]; } __attribute__ ((aligned (16))); static const char fmt32[] = KERN_INFO \ @@ -192,6 +192,13 @@ BUG_ON(!MSR_TM_ACTIVE(regs->msr)); + /* Remove TM bits from thread's MSR. The MSR in the sigcontext + * just indicates to userland that we were doing a transaction, but we + * don't want to return in transactional state. This also ensures + * that flush_fp_to_thread won't set TIF_RESTORE_TM again. + */ + regs->msr &= ~MSR_TS_MASK; + flush_fp_to_thread(current); #ifdef CONFIG_ALTIVEC @@ -749,13 +756,6 @@ /* Make sure signal handler doesn't get spurious FP exceptions */ current->thread.fp_state.fpscr = 0; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif /* Set up to return from userspace. */ if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { --- linux-3.13.0.orig/arch/powerpc/kernel/rtas.c +++ linux-3.13.0/arch/powerpc/kernel/rtas.c @@ -1013,12 +1013,13 @@ return NULL; } +/* We assume to be passed big endian arguments */ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { struct rtas_args args; unsigned long flags; char *buff_copy, *errbuf = NULL; - int nargs; + int nargs, nret, token; int rc; if (!capable(CAP_SYS_ADMIN)) @@ -1027,10 +1028,13 @@ if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; - nargs = args.nargs; + nargs = be32_to_cpu(args.nargs); + nret = be32_to_cpu(args.nret); + token = be32_to_cpu(args.token); + if (nargs > ARRAY_SIZE(args.args) - || args.nret > ARRAY_SIZE(args.args) - || nargs + args.nret > ARRAY_SIZE(args.args)) + || nret > ARRAY_SIZE(args.args) + || nargs + nret > ARRAY_SIZE(args.args)) return -EINVAL; /* Copy in args. */ @@ -1038,14 +1042,14 @@ nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; - if (args.token == RTAS_UNKNOWN_SERVICE) + if (token == RTAS_UNKNOWN_SERVICE) return -EINVAL; args.rets = &args.args[nargs]; - memset(args.rets, 0, args.nret * sizeof(rtas_arg_t)); + memset(args.rets, 0, nret * sizeof(rtas_arg_t)); /* Need to handle ibm,suspend_me call specially */ - if (args.token == ibm_suspend_me_token) { + if (token == ibm_suspend_me_token) { rc = rtas_ibm_suspend_me(&args); if (rc) return rc; @@ -1062,7 +1066,7 @@ /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ - if (args.rets[0] == -1) + if (be32_to_cpu(args.rets[0]) == -1) errbuf = __fetch_rtas_last_error(buff_copy); unlock_rtas(flags); @@ -1077,7 +1081,7 @@ /* Copy out args. */ if (copy_to_user(uargs->args + nargs, args.args + nargs, - args.nret * sizeof(rtas_arg_t)) != 0) + nret * sizeof(rtas_arg_t)) != 0) return -EFAULT; return 0; --- linux-3.13.0.orig/arch/powerpc/kernel/mce_power.c +++ linux-3.13.0/arch/powerpc/kernel/mce_power.c @@ -0,0 +1,313 @@ +/* + * Machine check exception handling CPU-side for power7 and power8 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar + */ + +#undef DEBUG +#define pr_fmt(fmt) "mce_power: " fmt + +#include +#include +#include +#include +#include + +/* flush SLBs and reload */ +static void flush_and_reload_slb(void) +{ + struct slb_shadow *slb; + unsigned long i, n; + + /* Invalidate all SLBs */ + asm volatile("slbmte %0,%0; slbia" : : "r" (0)); + +#ifdef CONFIG_KVM_BOOK3S_HANDLER + /* + * If machine check is hit when in guest or in transition, we will + * only flush the SLBs and continue. + */ + if (get_paca()->kvm_hstate.in_guest) + return; +#endif + + /* For host kernel, reload the SLBs from shadow SLB buffer. */ + slb = get_slb_shadow(); + if (!slb) + return; + + n = min_t(u32, be32_to_cpu(slb->persistent), SLB_MIN_SIZE); + + /* Load up the SLB entries from shadow SLB */ + for (i = 0; i < n; i++) { + unsigned long rb = be64_to_cpu(slb->save_area[i].esid); + unsigned long rs = be64_to_cpu(slb->save_area[i].vsid); + + rb = (rb & ~0xFFFul) | i; + asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb)); + } +} + +static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) +{ + long handled = 1; + + /* + * flush and reload SLBs for SLB errors and flush TLBs for TLB errors. + * reset the error bits whenever we handle them so that at the end + * we can check whether we handled all of them or not. + * */ + if (dsisr & slb_error_bits) { + flush_and_reload_slb(); + /* reset error bits */ + dsisr &= ~(slb_error_bits); + } + if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); + /* reset error bits */ + dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; + } + /* Any other errors we don't understand? */ + if (dsisr & 0xffffffffUL) + handled = 0; + + return handled; +} + +static long mce_handle_derror_p7(uint64_t dsisr) +{ + return mce_handle_derror(dsisr, P7_DSISR_MC_SLB_ERRORS); +} + +static long mce_handle_common_ierror(uint64_t srr1) +{ + long handled = 0; + + switch (P7_SRR1_MC_IFETCH(srr1)) { + case 0: + break; + case P7_SRR1_MC_IFETCH_SLB_PARITY: + case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: + /* flush and reload SLBs for SLB errors. */ + flush_and_reload_slb(); + handled = 1; + break; + case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: + if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { + cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); + handled = 1; + } + break; + default: + break; + } + + return handled; +} + +static long mce_handle_ierror_p7(uint64_t srr1) +{ + long handled = 0; + + handled = mce_handle_common_ierror(srr1); + + if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { + flush_and_reload_slb(); + handled = 1; + } + return handled; +} + +static void mce_get_common_ierror(struct mce_error_info *mce_err, uint64_t srr1) +{ + switch (P7_SRR1_MC_IFETCH(srr1)) { + case P7_SRR1_MC_IFETCH_SLB_PARITY: + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; + break; + case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; + break; + case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: + mce_err->error_type = MCE_ERROR_TYPE_TLB; + mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; + break; + case P7_SRR1_MC_IFETCH_UE: + case P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL: + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH; + break; + case P7_SRR1_MC_IFETCH_UE_TLB_RELOAD: + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = + MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH; + break; + } +} + +static void mce_get_ierror_p7(struct mce_error_info *mce_err, uint64_t srr1) +{ + mce_get_common_ierror(mce_err, srr1); + if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; + } +} + +static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr) +{ + if (dsisr & P7_DSISR_MC_UE) { + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE; + } else if (dsisr & P7_DSISR_MC_UE_TABLEWALK) { + mce_err->error_type = MCE_ERROR_TYPE_UE; + mce_err->u.ue_error_type = + MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE; + } else if (dsisr & P7_DSISR_MC_ERAT_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_PARITY_MFSLB) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; + } else if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { + mce_err->error_type = MCE_ERROR_TYPE_TLB; + mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; + } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT_PARITY) { + mce_err->error_type = MCE_ERROR_TYPE_SLB; + mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; + } +} + +static long mce_handle_ue_error(struct pt_regs *regs) +{ + long handled = 0; + + /* + * On specific SCOM read via MMIO we may get a machine check + * exception with SRR0 pointing inside opal. If that is the + * case OPAL may have recovery address to re-read SCOM data in + * different way and hence we can recover from this MC. + */ + + if (ppc_md.mce_check_early_recovery) { + if (ppc_md.mce_check_early_recovery(regs)) + handled = 1; + } + return handled; +} + +long __machine_check_early_realmode_p7(struct pt_regs *regs) +{ + uint64_t srr1, nip, addr; + long handled = 1; + struct mce_error_info mce_error_info = { 0 }; + + srr1 = regs->msr; + nip = regs->nip; + + /* + * Handle memory errors depending whether this was a load/store or + * ifetch exception. Also, populate the mce error_type and + * type-specific error_type from either SRR1 or DSISR, depending + * whether this was a load/store or ifetch exception + */ + if (P7_SRR1_MC_LOADSTORE(srr1)) { + handled = mce_handle_derror_p7(regs->dsisr); + mce_get_derror_p7(&mce_error_info, regs->dsisr); + addr = regs->dar; + } else { + handled = mce_handle_ierror_p7(srr1); + mce_get_ierror_p7(&mce_error_info, srr1); + addr = regs->nip; + } + + /* Handle UE error. */ + if (mce_error_info.error_type == MCE_ERROR_TYPE_UE) + handled = mce_handle_ue_error(regs); + + save_mce_event(regs, handled, &mce_error_info, nip, addr); + return handled; +} + +static void mce_get_ierror_p8(struct mce_error_info *mce_err, uint64_t srr1) +{ + mce_get_common_ierror(mce_err, srr1); + if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } +} + +static void mce_get_derror_p8(struct mce_error_info *mce_err, uint64_t dsisr) +{ + mce_get_derror_p7(mce_err, dsisr); + if (dsisr & P8_DSISR_MC_ERAT_MULTIHIT_SEC) { + mce_err->error_type = MCE_ERROR_TYPE_ERAT; + mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; + } +} + +static long mce_handle_ierror_p8(uint64_t srr1) +{ + long handled = 0; + + handled = mce_handle_common_ierror(srr1); + + if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { + flush_and_reload_slb(); + handled = 1; + } + return handled; +} + +static long mce_handle_derror_p8(uint64_t dsisr) +{ + return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS); +} + +long __machine_check_early_realmode_p8(struct pt_regs *regs) +{ + uint64_t srr1, nip, addr; + long handled = 1; + struct mce_error_info mce_error_info = { 0 }; + + srr1 = regs->msr; + nip = regs->nip; + + if (P7_SRR1_MC_LOADSTORE(srr1)) { + handled = mce_handle_derror_p8(regs->dsisr); + mce_get_derror_p8(&mce_error_info, regs->dsisr); + addr = regs->dar; + } else { + handled = mce_handle_ierror_p8(srr1); + mce_get_ierror_p8(&mce_error_info, srr1); + addr = regs->nip; + } + + /* Handle UE error. */ + if (mce_error_info.error_type == MCE_ERROR_TYPE_UE) + handled = mce_handle_ue_error(regs); + + save_mce_event(regs, handled, &mce_error_info, nip, addr); + return handled; +} --- linux-3.13.0.orig/arch/powerpc/kernel/idle_power7.S +++ linux-3.13.0/arch/powerpc/kernel/idle_power7.S @@ -84,6 +84,7 @@ std r9,_MSR(r1) std r1,PACAR1(r13) +_GLOBAL(power7_enter_nap_mode) #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE /* Tell KVM we're napping */ li r4,KVM_HWTHREAD_IN_NAP --- linux-3.13.0.orig/arch/powerpc/kernel/cpu_setup_power.S +++ linux-3.13.0/arch/powerpc/kernel/cpu_setup_power.S @@ -29,7 +29,7 @@ mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR bl __init_LPCR - bl __init_TLB + bl __init_tlb_power7 mtlr r11 blr @@ -42,7 +42,7 @@ mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR bl __init_LPCR - bl __init_TLB + bl __init_tlb_power7 mtlr r11 blr @@ -59,7 +59,7 @@ oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_HFSCR - bl __init_TLB + bl __init_tlb_power8 bl __init_PMU_HV mtlr r11 blr @@ -78,7 +78,7 @@ oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_HFSCR - bl __init_TLB + bl __init_tlb_power8 bl __init_PMU_HV mtlr r11 blr @@ -134,15 +134,31 @@ mtspr SPRN_HFSCR,r3 blr -__init_TLB: - /* - * Clear the TLB using the "IS 3" form of tlbiel instruction - * (invalidate by congruence class). P7 has 128 CCs, P8 has 512 - * so we just always do 512 - */ +/* + * Clear the TLB using the specified IS form of tlbiel instruction + * (invalidate by congruence class). P7 has 128 CCs., P8 has 512. + * + * r3 = IS field + */ +__init_tlb_power7: + li r3,0xc00 /* IS field = 0b11 */ +_GLOBAL(__flush_tlb_power7) + li r6,128 + mtctr r6 + mr r7,r3 /* IS field */ + ptesync +2: tlbiel r7 + addi r7,r7,0x1000 + bdnz 2b + ptesync +1: blr + +__init_tlb_power8: + li r3,0xc00 /* IS field = 0b11 */ +_GLOBAL(__flush_tlb_power8) li r6,512 mtctr r6 - li r7,0xc00 /* IS field = 0b11 */ + mr r7,r3 /* IS field */ ptesync 2: tlbiel r7 addi r7,r7,0x1000 --- linux-3.13.0.orig/arch/powerpc/kernel/head_64.S +++ linux-3.13.0/arch/powerpc/kernel/head_64.S @@ -91,6 +91,10 @@ __secondary_hold_acknowledge: .llong 0x0 + .globl __run_at_kexec +__run_at_kexec: + .llong 0x0 /* Flag for the secondary kernel from kexec. */ + #ifdef CONFIG_RELOCATABLE /* This flag is set to 1 by a loader if the kernel should run * at the loaded address instead of the linked address. This @@ -126,6 +130,10 @@ /* Grab our physical cpu number */ mr r24,r3 /* stash r4 for book3e */ +#ifdef CONFIG_PPC_FSL_BOOK3E + /* we need to setup initial TLB entry. */ + li r4,0 +#endif mr r25,r4 /* Tell the master cpu we're here */ @@ -418,12 +426,31 @@ /* process relocations for the final address of the kernel */ lis r25,PAGE_OFFSET@highest /* compute virtual base of kernel */ sldi r25,r25,32 +#if defined(CONFIG_PPC_BOOK3E) + tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */ +#endif +#if defined(CONFIG_KEXEC) || defined(CONFIG_CRASH_DUMP) + /* If relocated we need to restore this flag on that relocated address. */ + ld r7,__run_at_kexec-_stext(r26) + std r7,__run_at_kexec-_stext(r26) +#endif + lwz r7,__run_at_load-_stext(r26) +#if defined(CONFIG_PPC_BOOK3E) + tophys(r26,r26) /* Restore for the remains. */ +#endif cmplwi cr0,r7,1 /* flagged to stay where we are ? */ bne 1f add r25,r25,r26 1: mr r3,r25 bl .relocate +#if defined(CONFIG_PPC_BOOK3E) + /* In relocatable case we always have to load the address of label 'name' + * to set IVPR. So after .relocate we have to update IVPR with current + * address of label. + */ + bl .init_core_book3e +#endif #endif /* @@ -438,12 +465,12 @@ tovirt(r3,r3) /* on booke, we already run at PAGE_OFFSET */ #endif mr. r4,r26 /* In some cases the loader may */ +#if defined(CONFIG_PPC_BOOK3E) + tovirt(r4,r4) +#endif beq 9f /* have already put us at zero */ li r6,0x100 /* Start offset, the first 0x100 */ /* bytes were copied earlier. */ -#ifdef CONFIG_PPC_BOOK3E - tovirt(r6,r6) /* on booke, we already run at PAGE_OFFSET */ -#endif #ifdef CONFIG_RELOCATABLE /* @@ -451,12 +478,24 @@ * variable __run_at_load, if it is set the kernel is treated as relocatable * kernel, otherwise it will be moved to PHYSICAL_START */ +#if defined(CONFIG_PPC_BOOK3E) + tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */ +#endif lwz r7,__run_at_load-_stext(r26) +#if defined(CONFIG_PPC_BOOK3E) + tophys(r26,r26) /* Restore for the remains. */ +#endif cmplwi cr0,r7,1 bne 3f +#ifdef CONFIG_PPC_BOOK3E + LOAD_REG_ADDR(r5, __end_interrupts) + LOAD_REG_ADDR(r11, _stext) + sub r5,r5,r11 +#else /* just copy interrupts */ LOAD_REG_IMMEDIATE(r5, __end_interrupts - _stext) +#endif b 5f 3: #endif @@ -475,6 +514,9 @@ p_end: .llong _end - _stext 4: /* Now copy the rest of the kernel up to _end */ +#if defined(CONFIG_PPC_BOOK3E) + tovirt(r26,r26) +#endif addis r5,r26,(p_end - _stext)@ha ld r5,(p_end - _stext)@l(r5) /* get _end */ 5: bl .copy_and_flush /* copy the rest */ --- linux-3.13.0.orig/arch/powerpc/kernel/vector.S +++ linux-3.13.0/arch/powerpc/kernel/vector.S @@ -37,6 +37,16 @@ #endif /* + * Enable use of VMX/Altivec for the caller. + */ +_GLOBAL(vec_enable) + mfmsr r3 + oris r3,r3,MSR_VEC@h + MTMSRD(r3) + isync + blr + +/* * Load state from memory into VMX registers including VSCR. * Assumes the caller has enabled VMX in the MSR. */ --- linux-3.13.0.orig/arch/powerpc/kernel/exceptions-64s.S +++ linux-3.13.0/arch/powerpc/kernel/exceptions-64s.S @@ -155,8 +155,35 @@ */ HMT_MEDIUM_PPR_DISCARD SET_SCRATCH0(r13) /* save r13 */ +#ifdef CONFIG_PPC_P7_NAP +BEGIN_FTR_SECTION + /* Running native on arch 2.06 or later, check if we are + * waking up from nap. We only handle no state loss and + * supervisor state loss. We do -not- handle hypervisor + * state loss at this time. + */ + mfspr r13,SPRN_SRR1 + rlwinm. r13,r13,47-31,30,31 + OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR) + beq 9f + + mfspr r13,SPRN_SRR1 + rlwinm. r13,r13,47-31,30,31 + /* waking up from powersave (nap) state */ + cmpwi cr1,r13,2 + /* Total loss of HV state is fatal. let's just stay stuck here */ + OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR) + bgt cr1,. +9: + OPT_SET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR) +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) +#endif /* CONFIG_PPC_P7_NAP */ EXCEPTION_PROLOG_0(PACA_EXMC) +BEGIN_FTR_SECTION + b machine_check_pSeries_early +FTR_SECTION_ELSE b machine_check_pSeries_0 +ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) . = 0x300 .globl data_access_pSeries @@ -405,6 +432,64 @@ .align 7 /* moved from 0x200 */ +machine_check_pSeries_early: +BEGIN_FTR_SECTION + EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) + /* + * Register contents: + * R13 = PACA + * R9 = CR + * Original R9 to R13 is saved on PACA_EXMC + * + * Switch to mc_emergency stack and handle re-entrancy (though we + * currently don't test for overflow). Save MCE registers srr1, + * srr0, dar and dsisr and then set ME=1 + * + * We use paca->in_mce to check whether this is the first entry or + * nested machine check. We increment paca->in_mce to track nested + * machine checks. + * + * If this is the first entry then set stack pointer to + * paca->mc_emergency_sp, otherwise r1 is already pointing to + * stack frame on mc_emergency stack. + * + * NOTE: We are here with MSR_ME=0 (off), which means we risk a + * checkstop if we get another machine check exception before we do + * rfid with MSR_ME=1. + */ + mr r11,r1 /* Save r1 */ + lhz r10,PACA_IN_MCE(r13) + cmpwi r10,0 /* Are we in nested machine check */ + bne 0f /* Yes, we are. */ + /* First machine check entry */ + ld r1,PACAMCEMERGSP(r13) /* Use MC emergency stack */ +0: subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ + addi r10,r10,1 /* increment paca->in_mce */ + sth r10,PACA_IN_MCE(r13) + std r11,GPR1(r1) /* Save r1 on the stack. */ + std r11,0(r1) /* make stack chain pointer */ + mfspr r11,SPRN_SRR0 /* Save SRR0 */ + std r11,_NIP(r1) + mfspr r11,SPRN_SRR1 /* Save SRR1 */ + std r11,_MSR(r1) + mfspr r11,SPRN_DAR /* Save DAR */ + std r11,_DAR(r1) + mfspr r11,SPRN_DSISR /* Save DSISR */ + std r11,_DSISR(r1) + std r9,_CCR(r1) /* Save CR in stackframe */ + /* Save r9 through r13 from EXMC save area to stack frame. */ + EXCEPTION_PROLOG_COMMON_2(PACA_EXMC) + mfmsr r11 /* get MSR value */ + ori r11,r11,MSR_ME /* turn on ME bit */ + ori r11,r11,MSR_RI /* turn on RI bit */ + ld r12,PACAKBASE(r13) /* get high part of &label */ + LOAD_HANDLER(r12, machine_check_handle_early) + mtspr SPRN_SRR0,r12 + mtspr SPRN_SRR1,r11 + rfid + b . /* prevent speculative execution */ +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) + machine_check_pSeries: .globl machine_check_fwnmi machine_check_fwnmi: @@ -688,30 +773,6 @@ STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) - /* - * Machine check is different because we use a different - * save area: PACA_EXMC instead of PACA_EXGEN. - */ - .align 7 - .globl machine_check_common -machine_check_common: - - mfspr r10,SPRN_DAR - std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,SPRN_DSISR - stw r10,PACA_EXGEN+EX_DSISR(r13) - EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) - FINISH_NAP - DISABLE_INTS - ld r3,PACA_EXGEN+EX_DAR(r13) - lwz r4,PACA_EXGEN+EX_DSISR(r13) - std r3,_DAR(r1) - std r4,_DSISR(r1) - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .machine_check_exception - b .ret_from_except - STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt) @@ -1080,6 +1141,30 @@ #endif /* __DISABLED__ */ + /* + * Machine check is different because we use a different + * save area: PACA_EXMC instead of PACA_EXGEN. + */ + .align 7 + .globl machine_check_common +machine_check_common: + + mfspr r10,SPRN_DAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,SPRN_DSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) + FINISH_NAP + DISABLE_INTS + ld r3,PACA_EXGEN+EX_DAR(r13) + lwz r4,PACA_EXGEN+EX_DSISR(r13) + std r3,_DAR(r1) + std r4,_DSISR(r1) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .machine_check_exception + b .ret_from_except + .align 7 .globl alignment_common alignment_common: @@ -1263,6 +1348,120 @@ #endif /* CONFIG_PPC_POWERNV */ +#define MACHINE_CHECK_HANDLER_WINDUP \ + /* Clear MSR_RI before setting SRR0 and SRR1. */\ + li r0,MSR_RI; \ + mfmsr r9; /* get MSR value */ \ + andc r9,r9,r0; \ + mtmsrd r9,1; /* Clear MSR_RI */ \ + /* Move original SRR0 and SRR1 into the respective regs */ \ + ld r9,_MSR(r1); \ + mtspr SPRN_SRR1,r9; \ + ld r3,_NIP(r1); \ + mtspr SPRN_SRR0,r3; \ + ld r9,_CTR(r1); \ + mtctr r9; \ + ld r9,_XER(r1); \ + mtxer r9; \ + ld r9,_LINK(r1); \ + mtlr r9; \ + REST_GPR(0, r1); \ + REST_8GPRS(2, r1); \ + REST_GPR(10, r1); \ + ld r11,_CCR(r1); \ + mtcr r11; \ + /* Decrement paca->in_mce. */ \ + lhz r12,PACA_IN_MCE(r13); \ + subi r12,r12,1; \ + sth r12,PACA_IN_MCE(r13); \ + REST_GPR(11, r1); \ + REST_2GPRS(12, r1); \ + /* restore original r1. */ \ + ld r1,GPR1(r1) + + /* + * Handle machine check early in real mode. We come here with + * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack. + */ + .align 7 + .globl machine_check_handle_early +machine_check_handle_early: + std r0,GPR0(r1) /* Save r0 */ + EXCEPTION_PROLOG_COMMON_3(0x200) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .machine_check_early + ld r12,_MSR(r1) +#ifdef CONFIG_PPC_P7_NAP + /* + * Check if thread was in power saving mode. We come here when any + * of the following is true: + * a. thread wasn't in power saving mode + * b. thread was in power saving mode with no state loss or + * supervisor state loss + * + * Go back to nap again if (b) is true. + */ + rlwinm. r11,r12,47-31,30,31 /* Was it in power saving mode? */ + beq 4f /* No, it wasn;t */ + /* Thread was in power saving mode. Go back to nap again. */ + cmpwi r11,2 + bne 3f + /* Supervisor state loss */ + li r0,1 + stb r0,PACA_NAPSTATELOST(r13) +3: bl .machine_check_queue_event + MACHINE_CHECK_HANDLER_WINDUP + GET_PACA(r13) + ld r1,PACAR1(r13) + b .power7_enter_nap_mode +4: +#endif + /* + * Check if we are coming from hypervisor userspace. If yes then we + * continue in host kernel in V mode to deliver the MC event. + */ + rldicl. r11,r12,4,63 /* See if MC hit while in HV mode. */ + beq 5f + andi. r11,r12,MSR_PR /* See if coming from user. */ + bne 9f /* continue in V mode if we are. */ + +5: +#ifdef CONFIG_KVM_BOOK3S_64_HV + /* + * We are coming from kernel context. Check if we are coming from + * guest. if yes, then we can continue. We will fall through + * do_kvm_200->kvmppc_interrupt to deliver the MC event to guest. + */ + lbz r11,HSTATE_IN_GUEST(r13) + cmpwi r11,0 /* Check if coming from guest */ + bne 9f /* continue if we are. */ +#endif + /* + * At this point we are not sure about what context we come from. + * Queue up the MCE event and return from the interrupt. + * But before that, check if this is an un-recoverable exception. + * If yes, then stay on emergency stack and panic. + */ + andi. r11,r12,MSR_RI + bne 2f +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b +2: + /* + * Return from MC interrupt. + * Queue up the MCE event so that we can log it later, while + * returning from kernel or opal call. + */ + bl .machine_check_queue_event + MACHINE_CHECK_HANDLER_WINDUP + rfid +9: + /* Deliver the machine check to host kernel in V mode. */ + MACHINE_CHECK_HANDLER_WINDUP + b machine_check_pSeries + /* * r13 points to the PACA, r9 contains the saved CR, * r12 contain the saved SRR1, SRR0 is still ready for return --- linux-3.13.0.orig/arch/powerpc/kernel/reloc_64.S +++ linux-3.13.0/arch/powerpc/kernel/reloc_64.S @@ -81,6 +81,7 @@ 6: blr +.balign 8 p_dyn: .llong __dynamic_start - 0b p_rela: .llong __rela_dyn_start - 0b p_st: .llong _stext - 0b --- linux-3.13.0.orig/arch/powerpc/kernel/asm-offsets.c +++ linux-3.13.0/arch/powerpc/kernel/asm-offsets.c @@ -232,6 +232,10 @@ DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx)); #endif /* CONFIG_PPC_STD_MMU_64 */ DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); +#ifdef CONFIG_PPC_BOOK3S_64 + DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp)); + DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce)); +#endif DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state)); DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime)); @@ -484,6 +488,7 @@ DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar)); DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr)); DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty)); + DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr)); #endif #ifdef CONFIG_PPC_BOOK3S DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id)); --- linux-3.13.0.orig/arch/powerpc/kernel/misc_32.S +++ linux-3.13.0/arch/powerpc/kernel/misc_32.S @@ -57,11 +57,14 @@ mtlr r0 blr +/* + * void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp); + */ _GLOBAL(call_do_irq) mflr r0 stw r0,4(r1) lwz r10,THREAD+KSP_LIMIT(r2) - addi r11,r3,THREAD_INFO_GAP + addi r11,r4,THREAD_INFO_GAP stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) mr r1,r4 stw r10,8(r1) --- linux-3.13.0.orig/arch/powerpc/kernel/machine_kexec_64.c +++ linux-3.13.0/arch/powerpc/kernel/machine_kexec_64.c @@ -30,72 +30,6 @@ #include #include -int default_machine_kexec_prepare(struct kimage *image) -{ - int i; - unsigned long begin, end; /* limits of segment */ - unsigned long low, high; /* limits of blocked memory range */ - struct device_node *node; - const unsigned long *basep; - const unsigned int *sizep; - - if (!ppc_md.hpte_clear_all) - return -ENOENT; - - /* - * Since we use the kernel fault handlers and paging code to - * handle the virtual mode, we must make sure no destination - * overlaps kernel static data or bss. - */ - for (i = 0; i < image->nr_segments; i++) - if (image->segment[i].mem < __pa(_end)) - return -ETXTBSY; - - /* - * For non-LPAR, we absolutely can not overwrite the mmu hash - * table, since we are still using the bolted entries in it to - * do the copy. Check that here. - * - * It is safe if the end is below the start of the blocked - * region (end <= low), or if the beginning is after the - * end of the blocked region (begin >= high). Use the - * boolean identity !(a || b) === (!a && !b). - */ - if (htab_address) { - low = __pa(htab_address); - high = low + htab_size_bytes; - - for (i = 0; i < image->nr_segments; i++) { - begin = image->segment[i].mem; - end = begin + image->segment[i].memsz; - - if ((begin < high) && (end > low)) - return -ETXTBSY; - } - } - - /* We also should not overwrite the tce tables */ - for_each_node_by_type(node, "pci") { - basep = of_get_property(node, "linux,tce-base", NULL); - sizep = of_get_property(node, "linux,tce-size", NULL); - if (basep == NULL || sizep == NULL) - continue; - - low = *basep; - high = low + (*sizep); - - for (i = 0; i < image->nr_segments; i++) { - begin = image->segment[i].mem; - end = begin + image->segment[i].memsz; - - if ((begin < high) && (end > low)) - return -ETXTBSY; - } - } - - return 0; -} - #define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) static void copy_segments(unsigned long ind) @@ -367,8 +301,90 @@ /* NOTREACHED */ } +#ifdef CONFIG_PPC_BOOK3E +int default_machine_kexec_prepare(struct kimage *image) +{ + int i; + /* + * Since we use the kernel fault handlers and paging code to + * handle the virtual mode, we must make sure no destination + * overlaps kernel static data or bss. + */ + for (i = 0; i < image->nr_segments; i++) + if (image->segment[i].mem < __pa(_end)) + return -ETXTBSY; + return 0; +} +#else /* CONFIG_PPC_BOOK3E */ +int default_machine_kexec_prepare(struct kimage *image) +{ + int i; + unsigned long begin, end; /* limits of segment */ + unsigned long low, high; /* limits of blocked memory range */ + struct device_node *node; + const unsigned long *basep; + const unsigned int *sizep; + + if (!ppc_md.hpte_clear_all) + return -ENOENT; + + /* + * Since we use the kernel fault handlers and paging code to + * handle the virtual mode, we must make sure no destination + * overlaps kernel static data or bss. + */ + for (i = 0; i < image->nr_segments; i++) + if (image->segment[i].mem < __pa(_end)) + return -ETXTBSY; + + /* + * For non-LPAR, we absolutely can not overwrite the mmu hash + * table, since we are still using the bolted entries in it to + * do the copy. Check that here. + * + * It is safe if the end is below the start of the blocked + * region (end <= low), or if the beginning is after the + * end of the blocked region (begin >= high). Use the + * boolean identity !(a || b) === (!a && !b). + */ + if (htab_address) { + low = __pa(htab_address); + high = low + htab_size_bytes; + + for (i = 0; i < image->nr_segments; i++) { + begin = image->segment[i].mem; + end = begin + image->segment[i].memsz; + + if ((begin < high) && (end > low)) + return -ETXTBSY; + } + } + + /* We also should not overwrite the tce tables */ + for_each_node_by_type(node, "pci") { + basep = of_get_property(node, "linux,tce-base", NULL); + sizep = of_get_property(node, "linux,tce-size", NULL); + if (basep == NULL || sizep == NULL) + continue; + + low = *basep; + high = low + (*sizep); + + for (i = 0; i < image->nr_segments; i++) { + begin = image->segment[i].mem; + end = begin + image->segment[i].memsz; + + if ((begin < high) && (end > low)) + return -ETXTBSY; + } + } + + return 0; +} + /* Values we need to export to the second kernel via the device tree. */ static unsigned long htab_base; +static unsigned long htab_size; static struct property htab_base_prop = { .name = "linux,htab-base", @@ -379,7 +395,7 @@ static struct property htab_size_prop = { .name = "linux,htab-size", .length = sizeof(unsigned long), - .value = &htab_size_bytes, + .value = &htab_size, }; static int __init export_htab_values(void) @@ -403,11 +419,13 @@ if (prop) of_remove_property(node, prop); - htab_base = __pa(htab_address); + htab_base = cpu_to_be64(__pa(htab_address)); of_add_property(node, &htab_base_prop); + htab_size = cpu_to_be64(htab_size_bytes); of_add_property(node, &htab_size_prop); of_node_put(node); return 0; } late_initcall(export_htab_values); +#endif /* !CONFIG_PPC_BOOK3E */ --- linux-3.13.0.orig/arch/powerpc/kernel/signal_32.c +++ linux-3.13.0/arch/powerpc/kernel/signal_32.c @@ -519,6 +519,13 @@ { unsigned long msr = regs->msr; + /* Remove TM bits from thread's MSR. The MSR in the sigcontext + * just indicates to userland that we were doing a transaction, but we + * don't want to return in transactional state. This also ensures + * that flush_fp_to_thread won't set TIF_RESTORE_TM again. + */ + regs->msr &= ~MSR_TS_MASK; + /* Make sure floating point registers are stored in regs */ flush_fp_to_thread(current); @@ -1056,13 +1063,6 @@ /* enter the signal handler in native-endian mode */ regs->msr &= ~MSR_LE; regs->msr |= (MSR_KERNEL & MSR_LE); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif return 1; badframe: @@ -1484,13 +1484,6 @@ regs->nip = (unsigned long) ka->sa.sa_handler; /* enter the signal handler in big-endian mode */ regs->msr &= ~MSR_LE; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* Remove TM bits from thread's MSR. The MSR in the sigcontext - * just indicates to userland that we were doing a transaction, but we - * don't want to return in transactional state: - */ - regs->msr &= ~MSR_TS_MASK; -#endif return 1; badframe: --- linux-3.13.0.orig/arch/powerpc/kernel/machine_kexec.c +++ linux-3.13.0/arch/powerpc/kernel/machine_kexec.c @@ -196,7 +196,9 @@ /* Values we need to export to the second kernel via the device tree. */ static phys_addr_t kernel_end; +static phys_addr_t crashk_base; static phys_addr_t crashk_size; +static unsigned long long mem_limit; static struct property kernel_end_prop = { .name = "linux,kernel-end", @@ -207,7 +209,7 @@ static struct property crashk_base_prop = { .name = "linux,crashkernel-base", .length = sizeof(phys_addr_t), - .value = &crashk_res.start, + .value = &crashk_base }; static struct property crashk_size_prop = { @@ -219,9 +221,11 @@ static struct property memory_limit_prop = { .name = "linux,memory-limit", .length = sizeof(unsigned long long), - .value = &memory_limit, + .value = &mem_limit, }; +#define cpu_to_be_ulong __PASTE(cpu_to_be, BITS_PER_LONG) + static void __init export_crashk_values(struct device_node *node) { struct property *prop; @@ -237,8 +241,9 @@ of_remove_property(node, prop); if (crashk_res.start != 0) { + crashk_base = cpu_to_be_ulong(crashk_res.start), of_add_property(node, &crashk_base_prop); - crashk_size = resource_size(&crashk_res); + crashk_size = cpu_to_be_ulong(resource_size(&crashk_res)); of_add_property(node, &crashk_size_prop); } @@ -246,6 +251,7 @@ * memory_limit is required by the kexec-tools to limit the * crash regions to the actual memory used. */ + mem_limit = cpu_to_be_ulong(memory_limit); of_update_property(node, &memory_limit_prop); } @@ -264,7 +270,7 @@ of_remove_property(node, prop); /* information needed by userspace when using default_machine_kexec */ - kernel_end = __pa(_end); + kernel_end = cpu_to_be_ulong(__pa(_end)); of_add_property(node, &kernel_end_prop); export_crashk_values(node); --- linux-3.13.0.orig/arch/powerpc/kernel/setup_64.c +++ linux-3.13.0/arch/powerpc/kernel/setup_64.c @@ -544,7 +544,8 @@ /* * Stack space used when we detect a bad kernel stack pointer, and - * early in SMP boots before relocation is enabled. + * early in SMP boots before relocation is enabled. Exclusive emergency + * stack for machine checks. */ static void __init emergency_stack_init(void) { @@ -567,6 +568,13 @@ sp = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit); sp += THREAD_SIZE; paca[i].emergency_sp = __va(sp); + +#ifdef CONFIG_PPC_BOOK3S_64 + /* emergency stack for machine check exception handling. */ + sp = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit); + sp += THREAD_SIZE; + paca[i].mc_emergency_sp = __va(sp); +#endif } } --- linux-3.13.0.orig/arch/powerpc/kernel/traps.c +++ linux-3.13.0/arch/powerpc/kernel/traps.c @@ -285,6 +285,21 @@ /* What should we do here? We could issue a shutdown or hard reset. */ } + +/* + * This function is called in real mode. Strictly no printk's please. + * + * regs->nip and regs->msr contains srr0 and ssr1. + */ +long machine_check_early(struct pt_regs *regs) +{ + long handled = 0; + + if (cur_cpu_spec && cur_cpu_spec->machine_check_early) + handled = cur_cpu_spec->machine_check_early(regs); + return handled; +} + #endif /* @@ -1384,7 +1399,6 @@ TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); /* We can only have got here if the task started using FP after * beginning the transaction. So, the transactional regs are just a @@ -1393,8 +1407,7 @@ * transaction, and probably retry but now with FP enabled. So the * checkpointed FP registers need to be loaded. */ - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); /* Reclaim didn't save out any FPRs to transact_fprs. */ /* Enable FP for the task: */ @@ -1403,11 +1416,19 @@ /* This loads and recheckpoints the FP registers from * thread.fpr[]. They will remain in registers after the * checkpoint so we don't need to reload them after. + * If VMX is in use, the VRs now hold checkpointed values, + * so we don't want to load the VRs from the thread_struct. */ - tm_recheckpoint(¤t->thread, regs->msr); + tm_recheckpoint(¤t->thread, MSR_FP); + + /* If VMX is in use, get the transactional values back */ + if (regs->msr & MSR_VEC) { + do_load_up_transact_altivec(¤t->thread); + /* At this point all the VSX state is loaded, so enable it */ + regs->msr |= MSR_VSX; + } } -#ifdef CONFIG_ALTIVEC void altivec_unavailable_tm(struct pt_regs *regs) { /* See the comments in fp_unavailable_tm(). This function operates @@ -1417,18 +1438,21 @@ TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx," "MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); regs->msr |= MSR_VEC; - tm_recheckpoint(¤t->thread, regs->msr); + tm_recheckpoint(¤t->thread, MSR_VEC); current->thread.used_vr = 1; + + if (regs->msr & MSR_FP) { + do_load_up_transact_fpu(¤t->thread); + regs->msr |= MSR_VSX; + } } -#endif -#ifdef CONFIG_VSX void vsx_unavailable_tm(struct pt_regs *regs) { + unsigned long orig_msr = regs->msr; + /* See the comments in fp_unavailable_tm(). This works similarly, * though we're loading both FP and VEC registers in here. * @@ -1440,18 +1464,30 @@ "MSR=%lx\n", regs->nip, regs->msr); - tm_enable(); + current->thread.used_vsr = 1; + + /* If FP and VMX are already loaded, we have all the state we need */ + if ((orig_msr & (MSR_FP | MSR_VEC)) == (MSR_FP | MSR_VEC)) { + regs->msr |= MSR_VSX; + return; + } + /* This reclaims FP and/or VR regs if they're already enabled */ - tm_reclaim(¤t->thread, current->thread.regs->msr, - TM_CAUSE_FAC_UNAV); + tm_reclaim_current(TM_CAUSE_FAC_UNAV); regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode | MSR_VSX; - /* This loads & recheckpoints FP and VRs. */ - tm_recheckpoint(¤t->thread, regs->msr); - current->thread.used_vsr = 1; + + /* This loads & recheckpoints FP and VRs; but we have + * to be sure not to overwrite previously-valid state. + */ + tm_recheckpoint(¤t->thread, regs->msr & ~orig_msr); + + if (orig_msr & MSR_FP) + do_load_up_transact_fpu(¤t->thread); + if (orig_msr & MSR_VEC) + do_load_up_transact_altivec(¤t->thread); } -#endif #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ void performance_monitor_exception(struct pt_regs *regs) --- linux-3.13.0.orig/arch/powerpc/kernel/misc_64.S +++ linux-3.13.0/arch/powerpc/kernel/misc_64.S @@ -481,6 +481,49 @@ #ifdef CONFIG_KEXEC +#ifdef CONFIG_PPC_BOOK3E +/* BOOK3E have no a real MMU mode so we have to setup the initial TLB + * for a core to map v:0 to p:0 as 1:1. This current implementation + * assume that 1G is enough for kexec. + */ +#include +kexec_create_tlb: + /* Invalidate all TLBs to avoid any TLB conflict. */ + PPC_TLBILX_ALL(0,R0) + sync + isync + + mfspr r10,SPRN_TLB1CFG + andi. r10,r10,TLBnCFG_N_ENTRY /* Extract # entries */ + subi r10,r10,1 /* Often its always safe to use last */ + lis r9,MAS0_TLBSEL(1)@h + rlwimi r9,r10,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r9) */ + +/* Setup a temp mapping v:0 to p:0 as 1:1 and return to it. + */ +#ifdef CONFIG_SMP +#define M_IF_SMP MAS2_M +#else +#define M_IF_SMP 0 +#endif + mtspr SPRN_MAS0,r9 + + lis r9,(MAS1_VALID|MAS1_IPROT)@h + ori r9,r9,(MAS1_TSIZE(BOOK3E_PAGESZ_1GB))@l + mtspr SPRN_MAS1,r9 + + LOAD_REG_IMMEDIATE(r9, 0x0 | M_IF_SMP) + mtspr SPRN_MAS2,r9 + + LOAD_REG_IMMEDIATE(r9, 0x0 | MAS3_SR | MAS3_SW | MAS3_SX) + mtspr SPRN_MAS3,r9 + li r9,0 + mtspr SPRN_MAS7,r9 + + tlbwe + isync + blr +#endif /* kexec_smp_wait(void) * @@ -494,6 +537,10 @@ */ _GLOBAL(kexec_smp_wait) lhz r3,PACAHWCPUID(r13) +#ifdef CONFIG_PPC_BOOK3E + /* Create a 1:1 mapping. */ + bl kexec_create_tlb +#endif bl real_mode li r4,KEXEC_STATE_REAL_MODE @@ -510,6 +557,7 @@ * don't overwrite r3 here, it is live for kexec_wait above. */ real_mode: /* assume normal blr return */ +#ifndef CONFIG_PPC_BOOK3E 1: li r9,MSR_RI li r10,MSR_DR|MSR_IR mflr r11 /* return address to SRR0 */ @@ -521,7 +569,10 @@ mtspr SPRN_SRR1,r10 mtspr SPRN_SRR0,r11 rfid - +#else + /* the real mode is nothing for book3e. */ + blr +#endif /* * kexec_sequence(newstack, start, image, control, clear_all()) @@ -564,9 +615,15 @@ lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ /* disable interrupts, we are overwriting kernel data next */ +#ifndef CONFIG_PPC_BOOK3E mfmsr r3 rlwinm r3,r3,0,17,15 mtmsrd r3,1 +#else + wrteei 0 + /* Create a 1:1 mapping. */ + bl kexec_create_tlb +#endif /* copy dest pages, flush whole dest image */ mr r3,r29 @@ -583,15 +640,23 @@ bl .copy_and_flush /* (dest, src, copy limit, start offset) */ 1: /* assume normal blr return */ + /* notify we're going into kexec kernel for SMP. */ + LOAD_REG_ADDR(r3,__run_at_kexec) + li r4,1 + std r4,0(r3) + sync + /* release other cpus to the new kernel secondary start at 0x60 */ mflr r5 li r6,1 stw r6,kexec_flag-1b(5) +#ifndef CONFIG_PPC_BOOK3E /* clear out hardware hash page table and tlb */ ld r5,0(r27) /* deref function descriptor */ mtctr r5 bctrl /* ppc_md.hpte_clear_all(void); */ +#endif /* * kexec image calling is: --- linux-3.13.0.orig/arch/powerpc/kernel/dma.c +++ linux-3.13.0/arch/powerpc/kernel/dma.c @@ -191,12 +191,10 @@ #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) -int dma_set_mask(struct device *dev, u64 dma_mask) +int __dma_set_mask(struct device *dev, u64 dma_mask) { struct dma_map_ops *dma_ops = get_dma_ops(dev); - if (ppc_md.dma_set_mask) - return ppc_md.dma_set_mask(dev, dma_mask); if ((dma_ops != NULL) && (dma_ops->set_dma_mask != NULL)) return dma_ops->set_dma_mask(dev, dma_mask); if (!dev->dma_mask || !dma_supported(dev, dma_mask)) @@ -204,6 +202,12 @@ *dev->dma_mask = dma_mask; return 0; } +int dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (ppc_md.dma_set_mask) + return ppc_md.dma_set_mask(dev, dma_mask); + return __dma_set_mask(dev, dma_mask); +} EXPORT_SYMBOL(dma_set_mask); u64 dma_get_required_mask(struct device *dev) --- linux-3.13.0.orig/arch/powerpc/kernel/Makefile +++ linux-3.13.0/arch/powerpc/kernel/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o +obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC_A2) += cpu_setup_a2.o --- linux-3.13.0.orig/arch/powerpc/kernel/prom.c +++ linux-3.13.0/arch/powerpc/kernel/prom.c @@ -737,6 +737,11 @@ spinning_secondaries = boot_cpu_count - 1; #endif +#ifdef CONFIG_PPC_POWERNV + /* Scan and build the list of machine check recoverable ranges */ + of_scan_flat_dt(early_init_dt_scan_recoverable_ranges, NULL); +#endif + DBG(" <- early_init_devtree()\n"); } --- linux-3.13.0.orig/arch/powerpc/kernel/mce.c +++ linux-3.13.0/arch/powerpc/kernel/mce.c @@ -0,0 +1,352 @@ +/* + * Machine check exception handling. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar + */ + +#undef DEBUG +#define pr_fmt(fmt) "mce: " fmt + +#include +#include +#include +#include +#include +#include + +static DEFINE_PER_CPU(int, mce_nest_count); +static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event); + +/* Queue for delayed MCE events. */ +static DEFINE_PER_CPU(int, mce_queue_count); +static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event_queue); + +static void machine_check_process_queued_event(struct irq_work *work); +struct irq_work mce_event_process_work = { + .func = machine_check_process_queued_event, +}; + +static void mce_set_error_info(struct machine_check_event *mce, + struct mce_error_info *mce_err) +{ + mce->error_type = mce_err->error_type; + switch (mce_err->error_type) { + case MCE_ERROR_TYPE_UE: + mce->u.ue_error.ue_error_type = mce_err->u.ue_error_type; + break; + case MCE_ERROR_TYPE_SLB: + mce->u.slb_error.slb_error_type = mce_err->u.slb_error_type; + break; + case MCE_ERROR_TYPE_ERAT: + mce->u.erat_error.erat_error_type = mce_err->u.erat_error_type; + break; + case MCE_ERROR_TYPE_TLB: + mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type; + break; + case MCE_ERROR_TYPE_UNKNOWN: + default: + break; + } +} + +/* + * Decode and save high level MCE information into per cpu buffer which + * is an array of machine_check_event structure. + */ +void save_mce_event(struct pt_regs *regs, long handled, + struct mce_error_info *mce_err, + uint64_t nip, uint64_t addr) +{ + uint64_t srr1; + int index = __get_cpu_var(mce_nest_count)++; + struct machine_check_event *mce = &__get_cpu_var(mce_event[index]); + + /* + * Return if we don't have enough space to log mce event. + * mce_nest_count may go beyond MAX_MC_EVT but that's ok, + * the check below will stop buffer overrun. + */ + if (index >= MAX_MC_EVT) + return; + + /* Populate generic machine check info */ + mce->version = MCE_V1; + mce->srr0 = nip; + mce->srr1 = regs->msr; + mce->gpr3 = regs->gpr[3]; + mce->in_use = 1; + + mce->initiator = MCE_INITIATOR_CPU; + if (handled) + mce->disposition = MCE_DISPOSITION_RECOVERED; + else + mce->disposition = MCE_DISPOSITION_NOT_RECOVERED; + mce->severity = MCE_SEV_ERROR_SYNC; + + srr1 = regs->msr; + + /* + * Populate the mce error_type and type-specific error_type. + */ + mce_set_error_info(mce, mce_err); + + if (!addr) + return; + + if (mce->error_type == MCE_ERROR_TYPE_TLB) { + mce->u.tlb_error.effective_address_provided = true; + mce->u.tlb_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_SLB) { + mce->u.slb_error.effective_address_provided = true; + mce->u.slb_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_ERAT) { + mce->u.erat_error.effective_address_provided = true; + mce->u.erat_error.effective_address = addr; + } else if (mce->error_type == MCE_ERROR_TYPE_UE) { + mce->u.ue_error.effective_address_provided = true; + mce->u.ue_error.effective_address = addr; + } + return; +} + +/* + * get_mce_event: + * mce Pointer to machine_check_event structure to be filled. + * release Flag to indicate whether to free the event slot or not. + * 0 <= do not release the mce event. Caller will invoke + * release_mce_event() once event has been consumed. + * 1 <= release the slot. + * + * return 1 = success + * 0 = failure + * + * get_mce_event() will be called by platform specific machine check + * handle routine and in KVM. + * When we call get_mce_event(), we are still in interrupt context and + * preemption will not be scheduled until ret_from_expect() routine + * is called. + */ +int get_mce_event(struct machine_check_event *mce, bool release) +{ + int index = __get_cpu_var(mce_nest_count) - 1; + struct machine_check_event *mc_evt; + int ret = 0; + + /* Sanity check */ + if (index < 0) + return ret; + + /* Check if we have MCE info to process. */ + if (index < MAX_MC_EVT) { + mc_evt = &__get_cpu_var(mce_event[index]); + /* Copy the event structure and release the original */ + if (mce) + *mce = *mc_evt; + if (release) + mc_evt->in_use = 0; + ret = 1; + } + /* Decrement the count to free the slot. */ + if (release) + __get_cpu_var(mce_nest_count)--; + + return ret; +} + +void release_mce_event(void) +{ + get_mce_event(NULL, true); +} + +/* + * Queue up the MCE event which then can be handled later. + */ +void machine_check_queue_event(void) +{ + int index; + struct machine_check_event evt; + + if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) + return; + + index = __get_cpu_var(mce_queue_count)++; + /* If queue is full, just return for now. */ + if (index >= MAX_MC_EVT) { + __get_cpu_var(mce_queue_count)--; + return; + } + __get_cpu_var(mce_event_queue[index]) = evt; + + /* Queue irq work to process this event later. */ + irq_work_queue(&mce_event_process_work); +} + +/* + * process pending MCE event from the mce event queue. This function will be + * called during syscall exit. + */ +static void machine_check_process_queued_event(struct irq_work *work) +{ + int index; + + /* + * For now just print it to console. + * TODO: log this error event to FSP or nvram. + */ + while (__get_cpu_var(mce_queue_count) > 0) { + index = __get_cpu_var(mce_queue_count) - 1; + machine_check_print_event_info( + &__get_cpu_var(mce_event_queue[index])); + __get_cpu_var(mce_queue_count)--; + } +} + +void machine_check_print_event_info(struct machine_check_event *evt) +{ + const char *level, *sevstr, *subtype; + static const char *mc_ue_types[] = { + "Indeterminate", + "Instruction fetch", + "Page table walk ifetch", + "Load/Store", + "Page table walk Load/Store", + }; + static const char *mc_slb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *mc_erat_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *mc_tlb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + + /* Print things out */ + if (evt->version != MCE_V1) { + pr_err("Machine Check Exception, Unknown event version %d !\n", + evt->version); + return; + } + switch (evt->severity) { + case MCE_SEV_NO_ERROR: + level = KERN_INFO; + sevstr = "Harmless"; + break; + case MCE_SEV_WARNING: + level = KERN_WARNING; + sevstr = ""; + break; + case MCE_SEV_ERROR_SYNC: + level = KERN_ERR; + sevstr = "Severe"; + break; + case MCE_SEV_FATAL: + default: + level = KERN_ERR; + sevstr = "Fatal"; + break; + } + + printk("%s%s Machine check interrupt [%s]\n", level, sevstr, + evt->disposition == MCE_DISPOSITION_RECOVERED ? + "Recovered" : "[Not recovered"); + printk("%s Initiator: %s\n", level, + evt->initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown"); + switch (evt->error_type) { + case MCE_ERROR_TYPE_UE: + subtype = evt->u.ue_error.ue_error_type < + ARRAY_SIZE(mc_ue_types) ? + mc_ue_types[evt->u.ue_error.ue_error_type] + : "Unknown"; + printk("%s Error type: UE [%s]\n", level, subtype); + if (evt->u.ue_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.ue_error.effective_address); + if (evt->u.ue_error.physical_address_provided) + printk("%s Physial address: %016llx\n", + level, evt->u.ue_error.physical_address); + break; + case MCE_ERROR_TYPE_SLB: + subtype = evt->u.slb_error.slb_error_type < + ARRAY_SIZE(mc_slb_types) ? + mc_slb_types[evt->u.slb_error.slb_error_type] + : "Unknown"; + printk("%s Error type: SLB [%s]\n", level, subtype); + if (evt->u.slb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.slb_error.effective_address); + break; + case MCE_ERROR_TYPE_ERAT: + subtype = evt->u.erat_error.erat_error_type < + ARRAY_SIZE(mc_erat_types) ? + mc_erat_types[evt->u.erat_error.erat_error_type] + : "Unknown"; + printk("%s Error type: ERAT [%s]\n", level, subtype); + if (evt->u.erat_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.erat_error.effective_address); + break; + case MCE_ERROR_TYPE_TLB: + subtype = evt->u.tlb_error.tlb_error_type < + ARRAY_SIZE(mc_tlb_types) ? + mc_tlb_types[evt->u.tlb_error.tlb_error_type] + : "Unknown"; + printk("%s Error type: TLB [%s]\n", level, subtype); + if (evt->u.tlb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt->u.tlb_error.effective_address); + break; + default: + case MCE_ERROR_TYPE_UNKNOWN: + printk("%s Error type: Unknown\n", level); + break; + } +} + +uint64_t get_mce_fault_addr(struct machine_check_event *evt) +{ + switch (evt->error_type) { + case MCE_ERROR_TYPE_UE: + if (evt->u.ue_error.effective_address_provided) + return evt->u.ue_error.effective_address; + break; + case MCE_ERROR_TYPE_SLB: + if (evt->u.slb_error.effective_address_provided) + return evt->u.slb_error.effective_address; + break; + case MCE_ERROR_TYPE_ERAT: + if (evt->u.erat_error.effective_address_provided) + return evt->u.erat_error.effective_address; + break; + case MCE_ERROR_TYPE_TLB: + if (evt->u.tlb_error.effective_address_provided) + return evt->u.tlb_error.effective_address; + break; + default: + case MCE_ERROR_TYPE_UNKNOWN: + break; + } + return 0; +} +EXPORT_SYMBOL(get_mce_fault_addr); --- linux-3.13.0.orig/arch/powerpc/kernel/pci-common.c +++ linux-3.13.0/arch/powerpc/kernel/pci-common.c @@ -1483,9 +1483,15 @@ return pci_enable_resources(dev, mask); } +/* Before assuming too much here, take care to realize that we need sign + * extension from 32-bit pointers to 64-bit resource addresses to work. + */ resource_size_t pcibios_io_space_offset(struct pci_controller *hose) { - return (unsigned long) hose->io_base_virt - _IO_BASE; + long vbase = (long)hose->io_base_virt; + long io_base = _IO_BASE; + + return (resource_size_t)(vbase - io_base); } static void pcibios_setup_phb_resources(struct pci_controller *hose, --- linux-3.13.0.orig/arch/powerpc/kernel/entry_64.S +++ linux-3.13.0/arch/powerpc/kernel/entry_64.S @@ -664,8 +664,16 @@ bl .restore_interrupts SCHEDULE_USER b .ret_from_except_lite - -2: bl .save_nvgprs +2: +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + andi. r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM + bne 3f /* only restore TM if nothing else to do */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .restore_tm_state + b restore +3: +#endif + bl .save_nvgprs bl .restore_interrupts addi r3,r1,STACK_FRAME_OVERHEAD bl .do_notify_resume --- linux-3.13.0.orig/arch/powerpc/kernel/iommu.c +++ linux-3.13.0/arch/powerpc/kernel/iommu.c @@ -1088,6 +1088,14 @@ memset(tbl->it_map, 0xff, sz); iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size); + /* + * Disable iommu bypass, otherwise the user can DMA to all of + * our physical memory via the bypass window instead of just + * the pages that has been explicitly mapped into the iommu + */ + if (tbl->set_bypass) + tbl->set_bypass(tbl, false); + return 0; } EXPORT_SYMBOL_GPL(iommu_take_ownership); @@ -1102,6 +1110,10 @@ /* Restore bit#0 set by iommu_init_table() */ if (tbl->it_offset == 0) set_bit(0, tbl->it_map); + + /* The kernel owns the device now, we can restore the iommu bypass */ + if (tbl->set_bypass) + tbl->set_bypass(tbl, true); } EXPORT_SYMBOL_GPL(iommu_release_ownership); --- linux-3.13.0.orig/arch/powerpc/kernel/process.c +++ linux-3.13.0/arch/powerpc/kernel/process.c @@ -74,6 +74,48 @@ struct task_struct *last_task_used_spe = NULL; #endif +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +void giveup_fpu_maybe_transactional(struct task_struct *tsk) +{ + /* + * If we are saving the current thread's registers, and the + * thread is in a transactional state, set the TIF_RESTORE_TM + * bit so that we know to restore the registers before + * returning to userspace. + */ + if (tsk == current && tsk->thread.regs && + MSR_TM_ACTIVE(tsk->thread.regs->msr) && + !test_thread_flag(TIF_RESTORE_TM)) { + tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + set_thread_flag(TIF_RESTORE_TM); + } + + giveup_fpu(tsk); +} + +void giveup_altivec_maybe_transactional(struct task_struct *tsk) +{ + /* + * If we are saving the current thread's registers, and the + * thread is in a transactional state, set the TIF_RESTORE_TM + * bit so that we know to restore the registers before + * returning to userspace. + */ + if (tsk == current && tsk->thread.regs && + MSR_TM_ACTIVE(tsk->thread.regs->msr) && + !test_thread_flag(TIF_RESTORE_TM)) { + tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + set_thread_flag(TIF_RESTORE_TM); + } + + giveup_altivec(tsk); +} + +#else +#define giveup_fpu_maybe_transactional(tsk) giveup_fpu(tsk) +#define giveup_altivec_maybe_transactional(tsk) giveup_altivec(tsk) +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ + #ifdef CONFIG_PPC_FPU /* * Make sure the floating-point register state in the @@ -102,13 +144,13 @@ */ BUG_ON(tsk != current); #endif - giveup_fpu(tsk); + giveup_fpu_maybe_transactional(tsk); } preempt_enable(); } } EXPORT_SYMBOL_GPL(flush_fp_to_thread); -#endif +#endif /* CONFIG_PPC_FPU */ void enable_kernel_fp(void) { @@ -116,11 +158,11 @@ #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) - giveup_fpu(current); + giveup_fpu_maybe_transactional(current); else giveup_fpu(NULL); /* just enables FP for kernel */ #else - giveup_fpu(last_task_used_math); + giveup_fpu_maybe_transactional(last_task_used_math); #endif /* CONFIG_SMP */ } EXPORT_SYMBOL(enable_kernel_fp); @@ -132,11 +174,11 @@ #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) - giveup_altivec(current); + giveup_altivec_maybe_transactional(current); else giveup_altivec_notask(); #else - giveup_altivec(last_task_used_altivec); + giveup_altivec_maybe_transactional(last_task_used_altivec); #endif /* CONFIG_SMP */ } EXPORT_SYMBOL(enable_kernel_altivec); @@ -153,7 +195,7 @@ #ifdef CONFIG_SMP BUG_ON(tsk != current); #endif - giveup_altivec(tsk); + giveup_altivec_maybe_transactional(tsk); } preempt_enable(); } @@ -182,8 +224,8 @@ void giveup_vsx(struct task_struct *tsk) { - giveup_fpu(tsk); - giveup_altivec(tsk); + giveup_fpu_maybe_transactional(tsk); + giveup_altivec_maybe_transactional(tsk); __giveup_vsx(tsk); } @@ -479,7 +521,48 @@ return false; return true; } + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM +static void tm_reclaim_thread(struct thread_struct *thr, + struct thread_info *ti, uint8_t cause) +{ + unsigned long msr_diff = 0; + + /* + * If FP/VSX registers have been already saved to the + * thread_struct, move them to the transact_fp array. + * We clear the TIF_RESTORE_TM bit since after the reclaim + * the thread will no longer be transactional. + */ + if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) { + msr_diff = thr->tm_orig_msr & ~thr->regs->msr; + if (msr_diff & MSR_FP) + memcpy(&thr->transact_fp, &thr->fp_state, + sizeof(struct thread_fp_state)); + if (msr_diff & MSR_VEC) + memcpy(&thr->transact_vr, &thr->vr_state, + sizeof(struct thread_vr_state)); + clear_ti_thread_flag(ti, TIF_RESTORE_TM); + msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; + } + + tm_reclaim(thr, thr->regs->msr, cause); + + /* Having done the reclaim, we now have the checkpointed + * FP/VSX values in the registers. These might be valid + * even if we have previously called enable_kernel_fp() or + * flush_fp_to_thread(), so update thr->regs->msr to + * indicate their current validity. + */ + thr->regs->msr |= msr_diff; +} + +void tm_reclaim_current(uint8_t cause) +{ + tm_enable(); + tm_reclaim_thread(¤t->thread, current_thread_info(), cause); +} + static inline void tm_reclaim_task(struct task_struct *tsk) { /* We have to work out if we're switching from/to a task that's in the @@ -502,9 +585,11 @@ /* Stash the original thread MSR, as giveup_fpu et al will * modify it. We hold onto it to see whether the task used - * FP & vector regs. + * FP & vector regs. If the TIF_RESTORE_TM flag is set, + * tm_orig_msr is already set. */ - thr->tm_orig_msr = thr->regs->msr; + if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM)) + thr->tm_orig_msr = thr->regs->msr; TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " "ccr=%lx, msr=%lx, trap=%lx)\n", @@ -512,7 +597,7 @@ thr->regs->ccr, thr->regs->msr, thr->regs->trap); - tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED); + tm_reclaim_thread(thr, task_thread_info(tsk), TM_CAUSE_RESCHED); TM_DEBUG("--- tm_reclaim on pid %d complete\n", tsk->pid); @@ -588,6 +673,43 @@ tm_reclaim_task(prev); } } + +/* + * This is called if we are on the way out to userspace and the + * TIF_RESTORE_TM flag is set. It checks if we need to reload + * FP and/or vector state and does so if necessary. + * If userspace is inside a transaction (whether active or + * suspended) and FP/VMX/VSX instructions have ever been enabled + * inside that transaction, then we have to keep them enabled + * and keep the FP/VMX/VSX state loaded while ever the transaction + * continues. The reason is that if we didn't, and subsequently + * got a FP/VMX/VSX unavailable interrupt inside a transaction, + * we don't know whether it's the same transaction, and thus we + * don't know which of the checkpointed state and the transactional + * state to use. + */ +void restore_tm_state(struct pt_regs *regs) +{ + unsigned long msr_diff; + + clear_thread_flag(TIF_RESTORE_TM); + if (!MSR_TM_ACTIVE(regs->msr)) + return; + + msr_diff = current->thread.tm_orig_msr & ~regs->msr; + msr_diff &= MSR_FP | MSR_VEC | MSR_VSX; + if (msr_diff & MSR_FP) { + fp_enable(); + load_fp_state(¤t->thread.fp_state); + regs->msr |= current->thread.fpexc_mode; + } + if (msr_diff & MSR_VEC) { + vec_enable(); + load_vr_state(¤t->thread.vr_state); + } + regs->msr |= msr_diff; +} + #else #define tm_recheckpoint_new_task(new) #define __switch_to_tm(prev) @@ -927,6 +1049,15 @@ flush_altivec_to_thread(src); flush_vsx_to_thread(src); flush_spe_to_thread(src); + /* + * Flush TM state out so we can copy it. __switch_to_tm() does this + * flush but it removes the checkpointed state from the current CPU and + * transitions the CPU out of TM mode. Hence we need to call + * tm_recheckpoint_new_task() (on the same task) to restore the + * checkpointed state back and the TM mode. + */ + __switch_to_tm(src); + tm_recheckpoint_new_task(src); *dst = *src; --- linux-3.13.0.orig/arch/powerpc/kernel/cputable.c +++ linux-3.13.0/arch/powerpc/kernel/cputable.c @@ -71,6 +71,10 @@ extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_power8(void); extern void __restore_cpu_a2(void); +extern void __flush_tlb_power7(unsigned long inval_selector); +extern void __flush_tlb_power8(unsigned long inval_selector); +extern long __machine_check_early_realmode_p7(struct pt_regs *regs); +extern long __machine_check_early_realmode_p8(struct pt_regs *regs); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_E500) extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); @@ -440,6 +444,8 @@ .oprofile_cpu_type = "ppc64/ibm-compat-v1", .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7", }, { /* 2.07-compliant processor, i.e. Power8 "architected" mode */ @@ -456,6 +462,8 @@ .oprofile_cpu_type = "ppc64/ibm-compat-v1", .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Power7 */ @@ -474,6 +482,8 @@ .oprofile_type = PPC_OPROFILE_POWER4, .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7", }, { /* Power7+ */ @@ -492,6 +502,8 @@ .oprofile_type = PPC_OPROFILE_POWER4, .cpu_setup = __setup_cpu_power7, .cpu_restore = __restore_cpu_power7, + .flush_tlb = __flush_tlb_power7, + .machine_check_early = __machine_check_early_realmode_p7, .platform = "power7+", }, { /* Power8E */ @@ -510,6 +522,8 @@ .oprofile_type = PPC_OPROFILE_INVALID, .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Power8 */ @@ -528,6 +542,8 @@ .oprofile_type = PPC_OPROFILE_INVALID, .cpu_setup = __setup_cpu_power8, .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, { /* Cell Broadband Engine */ --- linux-3.13.0.orig/arch/powerpc/kernel/fpu.S +++ linux-3.13.0/arch/powerpc/kernel/fpu.S @@ -81,6 +81,22 @@ #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ /* + * Enable use of the FPU, and VSX if possible, for the caller. + */ +_GLOBAL(fp_enable) + mfmsr r3 + ori r3,r3,MSR_FP +#ifdef CONFIG_VSX +BEGIN_FTR_SECTION + oris r3,r3,MSR_VSX@h +END_FTR_SECTION_IFSET(CPU_FTR_VSX) +#endif + SYNC + MTMSRD(r3) + isync /* (not necessary for arch 2.02 and later) */ + blr + +/* * Load state from memory into FP registers including FPSCR. * Assumes the caller has enabled FP in the MSR. */ --- linux-3.13.0.orig/arch/powerpc/kernel/crash_dump.c +++ linux-3.13.0/arch/powerpc/kernel/crash_dump.c @@ -98,17 +98,19 @@ size_t csize, unsigned long offset, int userbuf) { void *vaddr; + phys_addr_t paddr; if (!csize) return 0; csize = min_t(size_t, csize, PAGE_SIZE); + paddr = pfn << PAGE_SHIFT; - if ((min_low_pfn < pfn) && (pfn < max_pfn)) { - vaddr = __va(pfn << PAGE_SHIFT); + if (memblock_is_region_memory(paddr, csize)) { + vaddr = __va(paddr); csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); } else { - vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0); + vaddr = __ioremap(paddr, PAGE_SIZE, 0); csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); iounmap(vaddr); } --- linux-3.13.0.orig/arch/powerpc/include/asm/dma-mapping.h +++ linux-3.13.0/arch/powerpc/include/asm/dma-mapping.h @@ -134,6 +134,7 @@ } extern int dma_set_mask(struct device *dev, u64 dma_mask); +extern int __dma_set_mask(struct device *dev, u64 dma_mask); #define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) --- linux-3.13.0.orig/arch/powerpc/include/asm/mce.h +++ linux-3.13.0/arch/powerpc/include/asm/mce.h @@ -0,0 +1,198 @@ +/* + * Machine check exception header file. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2013 IBM Corporation + * Author: Mahesh Salgaonkar + */ + +#ifndef __ASM_PPC64_MCE_H__ +#define __ASM_PPC64_MCE_H__ + +#include + +/* + * Machine Check bits on power7 and power8 + */ +#define P7_SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42)) /* P8 too */ + +/* SRR1 bits for machine check (On Power7 and Power8) */ +#define P7_SRR1_MC_IFETCH(srr1) ((srr1) & PPC_BITMASK(43, 45)) /* P8 too */ + +#define P7_SRR1_MC_IFETCH_UE (0x1 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_PARITY (0x2 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT (0x3 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_SLB_BOTH (0x4 << PPC_BITLSHIFT(45)) +#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT (0x5 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD (0x6 << PPC_BITLSHIFT(45)) /* P8 too */ +#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL (0x7 << PPC_BITLSHIFT(45)) + +/* SRR1 bits for machine check (On Power8) */ +#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT (0x4 << PPC_BITLSHIFT(45)) + +/* DSISR bits for machine check (On Power7 and Power8) */ +#define P7_DSISR_MC_UE (PPC_BIT(48)) /* P8 too */ +#define P7_DSISR_MC_UE_TABLEWALK (PPC_BIT(49)) /* P8 too */ +#define P7_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52)) /* P8 too */ +#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53)) /* P8 too */ +#define P7_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55)) /* P8 too */ +#define P7_DSISR_MC_SLB_MULTIHIT (PPC_BIT(56)) /* P8 too */ +#define P7_DSISR_MC_SLB_MULTIHIT_PARITY (PPC_BIT(57)) /* P8 too */ + +/* + * DSISR bits for machine check (Power8) in addition to above. + * Secondary DERAT Multihit + */ +#define P8_DSISR_MC_ERAT_MULTIHIT_SEC (PPC_BIT(54)) + +/* SLB error bits */ +#define P7_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_ERAT_MULTIHIT | \ + P7_DSISR_MC_SLB_PARITY_MFSLB | \ + P7_DSISR_MC_SLB_MULTIHIT | \ + P7_DSISR_MC_SLB_MULTIHIT_PARITY) + +#define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \ + P8_DSISR_MC_ERAT_MULTIHIT_SEC) +enum MCE_Version { + MCE_V1 = 1, +}; + +enum MCE_Severity { + MCE_SEV_NO_ERROR = 0, + MCE_SEV_WARNING = 1, + MCE_SEV_ERROR_SYNC = 2, + MCE_SEV_FATAL = 3, +}; + +enum MCE_Disposition { + MCE_DISPOSITION_RECOVERED = 0, + MCE_DISPOSITION_NOT_RECOVERED = 1, +}; + +enum MCE_Initiator { + MCE_INITIATOR_UNKNOWN = 0, + MCE_INITIATOR_CPU = 1, +}; + +enum MCE_ErrorType { + MCE_ERROR_TYPE_UNKNOWN = 0, + MCE_ERROR_TYPE_UE = 1, + MCE_ERROR_TYPE_SLB = 2, + MCE_ERROR_TYPE_ERAT = 3, + MCE_ERROR_TYPE_TLB = 4, +}; + +enum MCE_UeErrorType { + MCE_UE_ERROR_INDETERMINATE = 0, + MCE_UE_ERROR_IFETCH = 1, + MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH = 2, + MCE_UE_ERROR_LOAD_STORE = 3, + MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 4, +}; + +enum MCE_SlbErrorType { + MCE_SLB_ERROR_INDETERMINATE = 0, + MCE_SLB_ERROR_PARITY = 1, + MCE_SLB_ERROR_MULTIHIT = 2, +}; + +enum MCE_EratErrorType { + MCE_ERAT_ERROR_INDETERMINATE = 0, + MCE_ERAT_ERROR_PARITY = 1, + MCE_ERAT_ERROR_MULTIHIT = 2, +}; + +enum MCE_TlbErrorType { + MCE_TLB_ERROR_INDETERMINATE = 0, + MCE_TLB_ERROR_PARITY = 1, + MCE_TLB_ERROR_MULTIHIT = 2, +}; + +struct machine_check_event { + enum MCE_Version version:8; /* 0x00 */ + uint8_t in_use; /* 0x01 */ + enum MCE_Severity severity:8; /* 0x02 */ + enum MCE_Initiator initiator:8; /* 0x03 */ + enum MCE_ErrorType error_type:8; /* 0x04 */ + enum MCE_Disposition disposition:8; /* 0x05 */ + uint8_t reserved_1[2]; /* 0x06 */ + uint64_t gpr3; /* 0x08 */ + uint64_t srr0; /* 0x10 */ + uint64_t srr1; /* 0x18 */ + union { /* 0x20 */ + struct { + enum MCE_UeErrorType ue_error_type:8; + uint8_t effective_address_provided; + uint8_t physical_address_provided; + uint8_t reserved_1[5]; + uint64_t effective_address; + uint64_t physical_address; + uint8_t reserved_2[8]; + } ue_error; + + struct { + enum MCE_SlbErrorType slb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } slb_error; + + struct { + enum MCE_EratErrorType erat_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } erat_error; + + struct { + enum MCE_TlbErrorType tlb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } tlb_error; + } u; +}; + +struct mce_error_info { + enum MCE_ErrorType error_type:8; + union { + enum MCE_UeErrorType ue_error_type:8; + enum MCE_SlbErrorType slb_error_type:8; + enum MCE_EratErrorType erat_error_type:8; + enum MCE_TlbErrorType tlb_error_type:8; + } u; + uint8_t reserved[2]; +}; + +#define MAX_MC_EVT 100 + +/* Release flags for get_mce_event() */ +#define MCE_EVENT_RELEASE true +#define MCE_EVENT_DONTRELEASE false + +extern void save_mce_event(struct pt_regs *regs, long handled, + struct mce_error_info *mce_err, uint64_t nip, + uint64_t addr); +extern int get_mce_event(struct machine_check_event *mce, bool release); +extern void release_mce_event(void); +extern void machine_check_queue_event(void); +extern void machine_check_print_event_info(struct machine_check_event *evt); +extern uint64_t get_mce_fault_addr(struct machine_check_event *evt); + +#endif /* __ASM_PPC64_MCE_H__ */ --- linux-3.13.0.orig/arch/powerpc/include/asm/kvm_booke.h +++ linux-3.13.0/arch/powerpc/include/asm/kvm_booke.h @@ -98,6 +98,11 @@ return vcpu->arch.pc; } +static inline bool kvmppc_is_bigendian(struct kvm_vcpu *vcpu) +{ + return 1; +} + static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu) { return vcpu->arch.fault_dear; --- linux-3.13.0.orig/arch/powerpc/include/asm/iommu.h +++ linux-3.13.0/arch/powerpc/include/asm/iommu.h @@ -79,6 +79,7 @@ #ifdef CONFIG_IOMMU_API struct iommu_group *it_group; #endif + void (*set_bypass)(struct iommu_table *tbl, bool enable); }; struct scatterlist; --- linux-3.13.0.orig/arch/powerpc/include/asm/cputable.h +++ linux-3.13.0/arch/powerpc/include/asm/cputable.h @@ -90,6 +90,18 @@ * if the error is fatal, 1 if it was fully recovered and 0 to * pass up (not CPU originated) */ int (*machine_check)(struct pt_regs *regs); + + /* + * Processor specific early machine check handler which is + * called in real mode to handle SLB and TLB errors. + */ + long (*machine_check_early)(struct pt_regs *regs); + + /* + * Processor specific routine to flush tlbs. + */ + void (*flush_tlb)(unsigned long inval_selector); + }; extern struct cpu_spec *cur_cpu_spec; --- linux-3.13.0.orig/arch/powerpc/include/asm/opal.h +++ linux-3.13.0/arch/powerpc/include/asm/opal.h @@ -129,6 +129,7 @@ #define OPAL_LPC_READ 67 #define OPAL_LPC_WRITE 68 #define OPAL_RETURN_CPU 69 +#define OPAL_REINIT_CPUS 70 #define OPAL_FLASH_VALIDATE 76 #define OPAL_FLASH_MANAGE 77 #define OPAL_FLASH_UPDATE 78 @@ -599,6 +600,11 @@ uint64_t pestB[OPAL_PHB3_NUM_PEST_REGS]; }; +enum { + OPAL_REINIT_CPUS_HILE_BE = (1 << 0), + OPAL_REINIT_CPUS_HILE_LE = (1 << 1), +}; + typedef struct oppanel_line { const char * line; uint64_t line_len; @@ -719,9 +725,10 @@ uint16_t *pci_error_type, uint16_t *severity); int64_t opal_pci_poll(uint64_t phb_id); int64_t opal_return_cpu(void); +int64_t opal_reinit_cpus(uint64_t flags); -int64_t opal_xscom_read(uint32_t gcid, uint32_t pcb_addr, __be64 *val); -int64_t opal_xscom_write(uint32_t gcid, uint32_t pcb_addr, uint64_t val); +int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val); +int64_t opal_xscom_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val); int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type, uint32_t addr, uint32_t data, uint32_t sz); @@ -733,6 +740,8 @@ /* Internal functions */ extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data); +extern int early_init_dt_scan_recoverable_ranges(unsigned long node, + const char *uname, int depth, void *data); extern int opal_get_chars(uint32_t vtermno, char *buf, int count); extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); @@ -761,6 +770,7 @@ extern void opal_flash_init(void); extern int opal_machine_check(struct pt_regs *regs); +extern bool opal_mce_check_early_recovery(struct pt_regs *regs); extern void opal_shutdown(void); --- linux-3.13.0.orig/arch/powerpc/include/asm/exception-64s.h +++ linux-3.13.0/arch/powerpc/include/asm/exception-64s.h @@ -147,6 +147,14 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) /* + * Set an SPR from a register if the CPU has the given feature + */ +#define OPT_SET_SPR(ra, spr, ftr) \ +BEGIN_FTR_SECTION_NESTED(943) \ + mtspr spr,ra; \ +END_FTR_SECTION_NESTED(ftr,ftr,943) + +/* * Save a register to the PACA if the CPU has the given feature */ #define OPT_SAVE_REG_TO_PACA(offset, ra, ftr) \ @@ -301,9 +309,12 @@ beq 4f; /* if from kernel mode */ \ ACCOUNT_CPU_USER_ENTRY(r9, r10); \ SAVE_PPR(area, r9, r10); \ -4: std r2,GPR2(r1); /* save r2 in stackframe */ \ - SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ - SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ +4: EXCEPTION_PROLOG_COMMON_2(area) \ + EXCEPTION_PROLOG_COMMON_3(n) \ + ACCOUNT_STOLEN_TIME + +/* Save original regs values from save area to stack frame. */ +#define EXCEPTION_PROLOG_COMMON_2(area) \ ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ ld r10,area+EX_R10(r13); \ std r9,GPR9(r1); \ @@ -318,11 +329,16 @@ ld r10,area+EX_CFAR(r13); \ std r10,ORIG_GPR3(r1); \ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ + GET_CTR(r10, area); \ + std r10,_CTR(r1); + +#define EXCEPTION_PROLOG_COMMON_3(n) \ + std r2,GPR2(r1); /* save r2 in stackframe */ \ + SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ + SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ mflr r9; /* Get LR, later save to stack */ \ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ std r9,_LINK(r1); \ - GET_CTR(r10, area); \ - std r10,_CTR(r1); \ lbz r10,PACASOFTIRQEN(r13); \ mfspr r11,SPRN_XER; /* save XER in stackframe */ \ std r10,SOFTE(r1); \ @@ -332,8 +348,7 @@ li r10,0; \ ld r11,exception_marker@toc(r2); \ std r10,RESULT(r1); /* clear regs->result */ \ - std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \ - ACCOUNT_STOLEN_TIME + std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ /* * Exception vectors. --- linux-3.13.0.orig/arch/powerpc/include/asm/machdep.h +++ linux-3.13.0/arch/powerpc/include/asm/machdep.h @@ -170,6 +170,9 @@ int (*system_reset_exception)(struct pt_regs *regs); int (*machine_check_exception)(struct pt_regs *regs); + /* Called during machine check exception to retrive fixup address. */ + bool (*mce_check_early_recovery)(struct pt_regs *regs); + /* Motherboard/chipset features. This is a kind of general purpose * hook used to control some machine specific features (like reset * lines, chip power control, etc...). --- linux-3.13.0.orig/arch/powerpc/include/asm/kvm_ppc.h +++ linux-3.13.0/arch/powerpc/include/asm/kvm_ppc.h @@ -53,13 +53,13 @@ extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, - int is_bigendian); + unsigned int rt, unsigned int bytes, + int not_reverse); extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, - int is_bigendian); + unsigned int rt, unsigned int bytes, + int not_reverse); extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, - u64 val, unsigned int bytes, int is_bigendian); + u64 val, unsigned int bytes, int not_reverse); extern int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu); --- linux-3.13.0.orig/arch/powerpc/include/asm/eeh.h +++ linux-3.13.0/arch/powerpc/include/asm/eeh.h @@ -117,6 +117,16 @@ return edev ? edev->pdev : NULL; } +/* Return values from eeh_ops::next_error */ +enum { + EEH_NEXT_ERR_NONE = 0, + EEH_NEXT_ERR_INF, + EEH_NEXT_ERR_FROZEN_PE, + EEH_NEXT_ERR_FENCED_PHB, + EEH_NEXT_ERR_DEAD_PHB, + EEH_NEXT_ERR_DEAD_IOC +}; + /* * The struct is used to trace the registered EEH operation * callback functions. Actually, those operation callback --- linux-3.13.0.orig/arch/powerpc/include/asm/topology.h +++ linux-3.13.0/arch/powerpc/include/asm/topology.h @@ -22,7 +22,15 @@ static inline int cpu_to_node(int cpu) { - return numa_cpu_lookup_table[cpu]; + int nid; + + nid = numa_cpu_lookup_table[cpu]; + + /* + * During early boot, the numa-cpu lookup table might not have been + * setup for all CPUs yet. In such cases, default to node 0. + */ + return (nid < 0) ? 0 : nid; } #define parent_node(node) (node) --- linux-3.13.0.orig/arch/powerpc/include/asm/paca.h +++ linux-3.13.0/arch/powerpc/include/asm/paca.h @@ -152,6 +152,15 @@ */ struct opal_machine_check_event *opal_mc_evt; #endif +#ifdef CONFIG_PPC_BOOK3S_64 + /* Exclusive emergency stack pointer for machine check exception. */ + void *mc_emergency_sp; + /* + * Flag to check whether we are in machine check early handler + * and already using emergency stack. + */ + u16 in_mce; +#endif /* Stuff for accurate time accounting */ u64 user_time; /* accumulated usermode TB ticks */ --- linux-3.13.0.orig/arch/powerpc/include/asm/hvcall.h +++ linux-3.13.0/arch/powerpc/include/asm/hvcall.h @@ -274,6 +274,12 @@ /* Platform specific hcalls, used by KVM */ #define H_RTAS 0xf000 +/* Values for 2nd argument to H_SET_MODE */ +#define H_SET_MODE_RESOURCE_SET_CIABR 1 +#define H_SET_MODE_RESOURCE_SET_DAWR 2 +#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3 +#define H_SET_MODE_RESOURCE_LE 4 + #ifndef __ASSEMBLY__ /** --- linux-3.13.0.orig/arch/powerpc/include/asm/kvm_book3s.h +++ linux-3.13.0/arch/powerpc/include/asm/kvm_book3s.h @@ -271,6 +271,29 @@ return vcpu->arch.pc; } +static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.shared->msr & MSR_LE; +} + +static inline bool kvmppc_is_bigendian(struct kvm_vcpu *vcpu) +{ + return !kvmppc_need_byteswap(vcpu); +} + +static inline int kvmppc_ld32(struct kvm_vcpu *vcpu, ulong *eaddr, + u32 *ptr, bool data) +{ + int ret; + + ret = kvmppc_ld(vcpu, eaddr, sizeof(u32), ptr, data); + + if (kvmppc_need_byteswap(vcpu)) + *ptr = swab32(*ptr); + + return ret; +} + static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) { ulong pc = kvmppc_get_pc(vcpu); @@ -278,7 +301,7 @@ /* Load the instruction manually if it failed to do so in the * exit path */ if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) - kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false); + kvmppc_ld32(vcpu, &pc, &vcpu->arch.last_inst, false); return vcpu->arch.last_inst; } @@ -295,7 +318,7 @@ /* Load the instruction manually if it failed to do so in the * exit path */ if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) - kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false); + kvmppc_ld32(vcpu, &pc, &vcpu->arch.last_inst, false); return vcpu->arch.last_inst; } --- linux-3.13.0.orig/arch/powerpc/include/asm/processor.h +++ linux-3.13.0/arch/powerpc/include/asm/processor.h @@ -373,6 +373,8 @@ extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); +extern void fp_enable(void); +extern void vec_enable(void); extern void load_fp_state(struct thread_fp_state *fp); extern void store_fp_state(struct thread_fp_state *fp); extern void load_vr_state(struct thread_vr_state *vr); --- linux-3.13.0.orig/arch/powerpc/include/asm/thread_info.h +++ linux-3.13.0/arch/powerpc/include/asm/thread_info.h @@ -91,8 +91,7 @@ #define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_32BIT 4 /* 32 bit binary */ -#define TIF_PERFMON_WORK 5 /* work for pfm_handle_work() */ -#define TIF_PERFMON_CTXSW 6 /* perfmon needs ctxsw calls */ +#define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SINGLESTEP 8 /* singlestepping active */ #define TIF_NOHZ 9 /* in adaptive nohz mode */ @@ -115,8 +114,7 @@ #define _TIF_NEED_RESCHED (1< #include +/* PPC bit number conversion */ +#define PPC_BITLSHIFT(be) (BITS_PER_LONG - 1 - (be)) +#define PPC_BIT(bit) (1UL << PPC_BITLSHIFT(bit)) +#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) + /* * clear_bit doesn't imply a memory barrier */ --- linux-3.13.0.orig/arch/powerpc/include/asm/page.h +++ linux-3.13.0/arch/powerpc/include/asm/page.h @@ -112,6 +112,8 @@ /* See Description below for VIRT_PHYS_OFFSET */ #ifdef CONFIG_RELOCATABLE_PPC32 #define VIRT_PHYS_OFFSET virt_phys_offset +#elif defined(CONFIG_PPC_BOOK3E_64) +#define VIRT_PHYS_OFFSET (KERNELBASE - MEMORY_START) #else #define VIRT_PHYS_OFFSET (KERNELBASE - PHYSICAL_START) #endif --- linux-3.13.0.orig/arch/powerpc/include/asm/exception-64e.h +++ linux-3.13.0/arch/powerpc/include/asm/exception-64e.h @@ -214,10 +214,21 @@ #define TLB_MISS_STATS_SAVE_INFO_BOLTED #endif +#ifndef CONFIG_RELOCATABLE #define SET_IVOR(vector_number, vector_offset) \ li r3,vector_offset@l; \ ori r3,r3,interrupt_base_book3e@l; \ mtspr SPRN_IVOR##vector_number,r3; +#else /* !CONFIG_RELOCATABLE */ +/* In relocatable case the value of the constant expression 'expr' is only + * offset. So instead, we should loads the address of label 'name'. + */ +#define SET_IVOR(vector_number, vector_offset) \ + LOAD_REG_ADDR(r3,interrupt_base_book3e);\ + rlwinm r3,r3,0,15,0; \ + ori r3,r3,vector_offset@l; \ + mtspr SPRN_IVOR##vector_number,r3; +#endif /* CONFIG_RELOCATABLE */ #endif /* _ASM_POWERPC_EXCEPTION_64E_H */ --- linux-3.13.0.orig/arch/powerpc/include/asm/compat.h +++ linux-3.13.0/arch/powerpc/include/asm/compat.h @@ -200,10 +200,11 @@ /* * We can't access below the stack pointer in the 32bit ABI and - * can access 288 bytes in the 64bit ABI + * can access 288 bytes in the 64bit big-endian ABI, + * or 512 bytes with the new ELFv2 little-endian ABI. */ if (!is_32bit_task()) - usp -= 288; + usp -= USER_REDZONE_SIZE; return (void __user *) (usp - len); } --- linux-3.13.0.orig/arch/powerpc/include/asm/ptrace.h +++ linux-3.13.0/arch/powerpc/include/asm/ptrace.h @@ -28,11 +28,23 @@ #ifdef __powerpc64__ +/* + * Size of redzone that userspace is allowed to use below the stack + * pointer. This is 288 in the 64-bit big-endian ELF ABI, and 512 in + * the new ELFv2 little-endian ABI, so we allow the larger amount. + * + * For kernel code we allow a 288-byte redzone, in order to conserve + * kernel stack space; gcc currently only uses 288 bytes, and will + * hopefully allow explicit control of the redzone size in future. + */ +#define USER_REDZONE_SIZE 512 +#define KERNEL_REDZONE_SIZE 288 + #define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ #define STACK_FRAME_LR_SAVE 2 /* Location of LR in stack frame */ #define STACK_FRAME_REGS_MARKER ASM_CONST(0x7265677368657265) #define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \ - STACK_FRAME_OVERHEAD + 288) + STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE) #define STACK_FRAME_MARKER 12 /* Size of dummy stack frame allocated when calling signal handler. */ @@ -41,6 +53,8 @@ #else /* __powerpc64__ */ +#define USER_REDZONE_SIZE 0 +#define KERNEL_REDZONE_SIZE 0 #define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */ #define STACK_FRAME_LR_SAVE 1 /* Location of LR in stack frame */ #define STACK_FRAME_REGS_MARKER ASM_CONST(0x72656773) --- linux-3.13.0.orig/arch/powerpc/include/asm/tm.h +++ linux-3.13.0/arch/powerpc/include/asm/tm.h @@ -15,6 +15,7 @@ extern void tm_enable(void); extern void tm_reclaim(struct thread_struct *thread, unsigned long orig_msr, uint8_t cause); +extern void tm_reclaim_current(uint8_t cause); extern void tm_recheckpoint(struct thread_struct *thread, unsigned long orig_msr); extern void tm_abort(uint8_t cause); --- linux-3.13.0.orig/arch/powerpc/include/asm/pgtable-ppc64.h +++ linux-3.13.0/arch/powerpc/include/asm/pgtable-ppc64.h @@ -558,5 +558,19 @@ #define __HAVE_ARCH_PMDP_INVALIDATE extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); + +#define pmd_move_must_withdraw pmd_move_must_withdraw +struct spinlock; +static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, + struct spinlock *old_pmd_ptl) +{ + /* + * Archs like ppc64 use pgtable to store per pmd + * specific information. So when we switch the pmd, + * we should also withdraw and deposit the pgtable + */ + return true; +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ --- linux-3.13.0.orig/arch/powerpc/mm/numa.c +++ linux-3.13.0/arch/powerpc/mm/numa.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -152,9 +154,22 @@ } } -static void map_cpu_to_node(int cpu, int node) +static void reset_numa_cpu_lookup_table(void) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) + numa_cpu_lookup_table[cpu] = -1; +} + +static void update_numa_cpu_lookup_table(unsigned int cpu, int node) { numa_cpu_lookup_table[cpu] = node; +} + +static void map_cpu_to_node(int cpu, int node) +{ + update_numa_cpu_lookup_table(cpu, node); dbg("adding cpu %d to node %d\n", cpu, node); @@ -522,11 +537,24 @@ */ static int numa_setup_cpu(unsigned long lcpu) { - int nid = 0; - struct device_node *cpu = of_get_cpu_node(lcpu, NULL); + int nid; + struct device_node *cpu; + + /* + * If a valid cpu-to-node mapping is already available, use it + * directly instead of querying the firmware, since it represents + * the most recent mapping notified to us by the platform (eg: VPHN). + */ + if ((nid = numa_cpu_lookup_table[lcpu]) >= 0) { + map_cpu_to_node(lcpu, nid); + return nid; + } + + cpu = of_get_cpu_node(lcpu, NULL); if (!cpu) { WARN_ON(1); + nid = 0; goto out; } @@ -1067,6 +1095,7 @@ */ setup_node_to_cpumask_map(); + reset_numa_cpu_lookup_table(); register_cpu_notifier(&ppc64_numa_nb); cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE, (void *)(unsigned long)boot_cpuid); @@ -1445,6 +1474,33 @@ return 0; } +static int update_lookup_table(void *data) +{ + struct topology_update_data *update; + + if (!data) + return -EINVAL; + + /* + * Upon topology update, the numa-cpu lookup table needs to be updated + * for all threads in the core, including offline CPUs, to ensure that + * future hotplug operations respect the cpu-to-node associativity + * properly. + */ + for (update = data; update; update = update->next) { + int nid, base, j; + + nid = update->new_nid; + base = cpu_first_thread_sibling(update->cpu); + + for (j = 0; j < threads_per_core; j++) { + update_numa_cpu_lookup_table(base + j, nid); + } + } + + return 0; +} + /* * Update the node maps and sysfs entries for each cpu whose home node * has changed. Returns 1 when the topology has changed, and 0 otherwise. @@ -1513,6 +1569,14 @@ stop_machine(update_cpu_topology, &updates[0], &updated_cpus); + /* + * Update the numa-cpu lookup table with the new mappings, even for + * offline CPUs. It is best to perform this update from the stop- + * machine context. + */ + stop_machine(update_lookup_table, &updates[0], + cpumask_of(raw_smp_processor_id())); + for (ud = &updates[0]; ud; ud = ud->next) { unregister_cpu_under_node(ud->cpu, ud->old_nid); register_cpu_under_node(ud->cpu, ud->new_nid); --- linux-3.13.0.orig/arch/parisc/kernel/cache.c +++ linux-3.13.0/arch/parisc/kernel/cache.c @@ -388,6 +388,20 @@ } EXPORT_SYMBOL(flush_kernel_dcache_page_addr); +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg) +{ + /* Copy using kernel mapping. No coherency is needed (all in + kunmap) for the `to' page. However, the `from' page needs to + be flushed through a mapping equivalent to the user mapping + before it can be accessed through the kernel mapping. */ + preempt_disable(); + flush_dcache_page_asm(__pa(vfrom), vaddr); + preempt_enable(); + copy_page_asm(vto, vfrom); +} +EXPORT_SYMBOL(copy_user_page); + void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) { unsigned long flags; --- linux-3.13.0.orig/arch/parisc/include/asm/cacheflush.h +++ linux-3.13.0/arch/parisc/include/asm/cacheflush.h @@ -132,7 +132,6 @@ static inline void *kmap(struct page *page) { might_sleep(); - flush_dcache_page(page); return page_address(page); } @@ -144,7 +143,6 @@ static inline void *kmap_atomic(struct page *page) { pagefault_disable(); - flush_dcache_page(page); return page_address(page); } --- linux-3.13.0.orig/arch/parisc/include/asm/page.h +++ linux-3.13.0/arch/parisc/include/asm/page.h @@ -29,7 +29,8 @@ void clear_page_asm(void *page); void copy_page_asm(void *to, void *from); #define clear_user_page(vto, vaddr, page) clear_page_asm(vto) -#define copy_user_page(vto, vfrom, vaddr, page) copy_page_asm(vto, vfrom) +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg); /* #define CONFIG_PARISC_TMPALIAS */ --- linux-3.13.0.orig/arch/arm64/Kconfig +++ linux-3.13.0/arch/arm64/Kconfig @@ -113,6 +113,8 @@ Express). config ARCH_XGENE + select PCI + select PCI_DOMAINS bool "AppliedMicro X-Gene SOC Family" help This enables support for AppliedMicro X-Gene SOC Family @@ -124,6 +126,23 @@ config ARM_AMBA bool +config PCI + bool "PCI support" + help + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside + your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or + VESA. If you have PCI, say Y, otherwise N. + +config PCI_DOMAINS + bool + depends on PCI + +config PCI_SYSCALL + def_bool PCI + +source "drivers/pci/Kconfig" +source "drivers/pci/pcie/Kconfig" endmenu menu "Kernel Features" --- linux-3.13.0.orig/arch/arm64/boot/dts/apm-storm.dtsi +++ linux-3.13.0/arch/arm64/boot/dts/apm-storm.dtsi @@ -103,6 +103,11 @@ #size-cells = <2>; ranges; + scu: system-clk-controller@17000000 { + compatible = "apm,xgene-scu","syscon"; + reg = <0x0 0x17000000 0x0 0x400>; + }; + clocks { #address-cells = <2>; #size-cells = <2>; @@ -118,7 +123,7 @@ compatible = "apm,xgene-pcppll-clock"; #clock-cells = <1>; clocks = <&refclk 0>; - clock-names = "pcppll"; + clock-names = "refclk"; reg = <0x0 0x17000100 0x0 0x1000>; clock-output-names = "pcppll"; type = <0>; @@ -128,7 +133,7 @@ compatible = "apm,xgene-socpll-clock"; #clock-cells = <1>; clocks = <&refclk 0>; - clock-names = "socpll"; + clock-names = "refclk"; reg = <0x0 0x17000120 0x0 0x1000>; clock-output-names = "socpll"; type = <1>; @@ -141,17 +146,22 @@ clock-names = "socplldiv2"; clock-mult = <1>; clock-div = <2>; - clock-output-names = "socplldiv2"; + clock-output-names = "socpll"; }; qmlclk: qmlclk { compatible = "apm,xgene-device-clock"; #clock-cells = <1>; clocks = <&socplldiv2 0>; - clock-names = "qmlclk"; + clock-names = "socplldiv2"; reg = <0x0 0x1703C000 0x0 0x1000>; reg-names = "csr-reg"; clock-output-names = "qmlclk"; + status = "ok"; + csr-offset = <0x0>; + csr-mask = <0x3>; + enable-offset = <0x8>; + enable-mask = <0x3>; }; ethclk: ethclk { @@ -176,8 +186,267 @@ reg-names = "csr-reg"; clock-output-names = "eth8clk"; }; + + sataphy1clk: sataphy1clk@1f21c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f21c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "sataphy1clk"; + status = "disabled"; + csr-offset = <0x4>; + csr-mask = <0x00>; + enable-offset = <0x0>; + enable-mask = <0x06>; + }; + + sataphy2clk: sataphy1clk@1f22c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f22c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "sataphy2clk"; + status = "ok"; + csr-offset = <0x4>; + csr-mask = <0x3a>; + enable-offset = <0x0>; + enable-mask = <0x06>; + }; + + sataphy3clk: sataphy1clk@1f23c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f23c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "sataphy3clk"; + status = "ok"; + csr-offset = <0x4>; + csr-mask = <0x3a>; + enable-offset = <0x0>; + enable-mask = <0x06>; + }; + + sata01clk: sata01clk@1f21c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f21c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "sata01clk"; + csr-offset = <0x4>; + csr-mask = <0x05>; + enable-offset = <0x0>; + enable-mask = <0x39>; + }; + + sata23clk: sata23clk@1f22c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f22c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "sata23clk"; + csr-offset = <0x4>; + csr-mask = <0x05>; + enable-offset = <0x0>; + enable-mask = <0x39>; + }; + + sata45clk: sata45clk@1f23c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f23c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "sata45clk"; + csr-offset = <0x4>; + csr-mask = <0x05>; + enable-offset = <0x0>; + enable-mask = <0x39>; + }; + + rtcclk: rtcclk@17000000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + clock-names = "socplldiv2"; + reg = <0x0 0x17000000 0x0 0x2000>; + reg-names = "csr-reg"; + csr-offset = <0xc>; + csr-mask = <0x2>; + enable-offset = <0x10>; + enable-mask = <0x2>; + clock-output-names = "rtcclk"; + }; + + pcie0clk: pcie0clk@1f2bc000 { + status = "disabled"; + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f2bc000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "pcie0clk"; + }; + + pcie1clk: pcie1clk@1f2cc000 { + status = "disabled"; + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f2cc000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "pcie1clk"; + }; + + pcie2clk: pcie2clk@1f2dc000 { + status = "disabled"; + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f2dc000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "pcie2clk"; + }; + + pcie3clk: pcie3clk@1f50c000 { + status = "disabled"; + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f50c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "pcie3clk"; + }; + + pcie4clk: pcie4clk@1f51c000 { + status = "disabled"; + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f51c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "pcie4clk"; + }; + }; + + pcie0: pcie@1f2b0000 { + status = "disabled"; + device_type = "pci"; + compatible = "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */ + 0xe0 0xd0000000 0x0 0x00200000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x00 0x00000000 0xe0 0x00000000 0x00 0x00010000 /* io */ + 0x02000000 0x00 0x10000000 0xe0 0x10000000 0x00 0x80000000>; /* mem */ + dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>; + clocks = <&pcie0clk 0>; + }; + + pcie1: pcie@1f2c0000 { + status = "disabled"; + device_type = "pci"; + compatible = "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f2c0000 0x0 0x00010000 /* Controller registers */ + 0xd0 0xd0000000 0x0 0x00200000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x0 0x00000000 0xd0 0x00000000 0x00 0x00010000 /* io */ + 0x02000000 0x0 0x10000000 0xd0 0x10000000 0x00 0x80000000>; /* mem */ + dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>; + clocks = <&pcie1clk 0>; }; + pcie2: pcie@1f2d0000 { + status = "disabled"; + device_type = "pci"; + compatible = "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f2d0000 0x0 0x00010000 /* Controller registers */ + 0x90 0xd0000000 0x0 0x00200000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x0 0x00000000 0x90 0x00000000 0x0 0x00010000 /* io */ + 0x02000000 0x0 0x10000000 0x90 0x10000000 0x0 0x80000000>; /* mem */ + dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>; + clocks = <&pcie2clk 0>; + }; + + pcie3: pcie@1f500000 { + status = "disabled"; + device_type = "pci"; + compatible = "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f500000 0x0 0x00010000 /* Controller registers */ + 0xa0 0xd0000000 0x0 0x00200000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x0 0x00000000 0xa0 0x00000000 0x0 0x00010000 /* mem */ + 0x02000000 0x0 0x10000000 0xa0 0x10000000 0x0 0x80000000>; /* io */ + dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>; + clocks = <&pcie3clk 0>; + }; + + pcie4: pcie@1f510000 { + status = "disabled"; + device_type = "pci"; + compatible = "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f510000 0x0 0x00010000 /* Controller registers */ + 0xc0 0xd0000000 0x0 0x00200000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x0 0x00000000 0xc0 0x00000000 0x0 0x00010000 /* io */ + 0x02000000 0x0 0x10000000 0xc0 0x10000000 0x0 0x80000000>; /* mem */ + dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>; + clocks = <&pcie4clk 0>; + }; + + rtc: rtc@10510000 { + device_type = "rtc"; + compatible = "apm,xgene-rtc"; + reg = <0x0 0x10510000 0x0 0x400>; + interrupts = <0x0 0x46 0x4>; + #clock-cells = <1>; + clocks = <&rtcclk 0>; + }; + serial0: serial@1c020000 { device_type = "serial"; compatible = "ns16550"; @@ -187,5 +456,124 @@ interrupt-parent = <&gic>; interrupts = <0x0 0x4c 0x4>; }; + + serial1: serial@1c021000 { + status = "disabled"; + device_type = "serial"; + compatible = "ns16550a"; + reg = <0x0 0x1c021000 0x0 0x1000>; + reg-shift = <2>; + clock-frequency = <10000000>; /* Updated by bootloader */ + interrupt-parent = <&gic>; + interrupts = <0x0 0x4d 0x4>; + }; + + reboot@17000014 { + compatible = "syscon-reboot"; + regmap = <&scu>; + offset = <0x14>; + mask = <0x1>; + }; + + phy1: phy@1f21a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f21a000 0x0 0x100>; + #phy-cells = <1>; + clocks = <&sataphy1clk 0>; + status = "disabled"; + apm,tx-boost-gain = <30 30 30 30 30 30>; + apm,tx-eye-tuning = <2 10 10 2 10 10>; + }; + + phy2: phy@1f22a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f22a000 0x0 0x100>; + #phy-cells = <1>; + clocks = <&sataphy2clk 0>; + status = "ok"; + apm,tx-boost-gain = <30 30 30 30 30 30>; + apm,tx-eye-tuning = <1 10 10 2 10 10>; + }; + + phy3: phy@1f23a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f23a000 0x0 0x100>; + #phy-cells = <1>; + clocks = <&sataphy3clk 0>; + status = "ok"; + apm,tx-boost-gain = <31 31 31 31 31 31>; + apm,tx-eye-tuning = <2 10 10 2 10 10>; + }; + + sata1: sata@1a000000 { + compatible = "apm,xgene-ahci"; + reg = <0x0 0x1a000000 0x0 0x1000>, + <0x0 0x1f210000 0x0 0x1000>, + <0x0 0x1f21d000 0x0 0x1000>, + <0x0 0x1f21e000 0x0 0x1000>, + <0x0 0x1f217000 0x0 0x1000>; + interrupts = <0x0 0x86 0x4>; + status = "disabled"; + clocks = <&sata01clk 0>; + phys = <&phy1 0>; + phy-names = "sata-phy"; + }; + + sata2: sata@1a400000 { + compatible = "apm,xgene-ahci"; + reg = <0x0 0x1a400000 0x0 0x1000>, + <0x0 0x1f220000 0x0 0x1000>, + <0x0 0x1f22d000 0x0 0x1000>, + <0x0 0x1f22e000 0x0 0x1000>, + <0x0 0x1f227000 0x0 0x1000>; + interrupts = <0x0 0x87 0x4>; + status = "ok"; + clocks = <&sata23clk 0>; + phys = <&phy2 0>; + phy-names = "sata-phy"; + }; + + sata3: sata@1a800000 { + compatible = "apm,xgene-ahci"; + reg = <0x0 0x1a800000 0x0 0x1000>, + <0x0 0x1f230000 0x0 0x1000>, + <0x0 0x1f23d000 0x0 0x1000>, + <0x0 0x1f23e000 0x0 0x1000>; + interrupts = <0x0 0x88 0x4>; + status = "ok"; + clocks = <&sata45clk 0>; + phys = <&phy3 0>; + phy-names = "sata-phy"; + }; + + qmlite: qmtm@17030000 { + compatible = "apm,xgene-qmtm-lite"; + reg = <0x0 0x17030000 0x0 0x10000>, + <0x0 0x10000000 0x0 0x400000>; + slave-name = "CPU_QMTM3"; + interrupts = <0x0 0x40 0x4>, + <0x0 0x3c 0x4>; + status = "ok"; + #clock-cells = <1>; + clocks = <&qmlclk 0>; + }; + + menet: ethernet@17020000 { + compatible = "apm,xgene-enet"; + status = "disabled"; + reg = <0x0 0x17020000 0x0 0x30>, + <0x0 0x17020000 0x0 0x10000>, + <0x0 0x17020000 0x0 0x20>; + slave-name = "RGMII"; + interrupts = <0x0 0x38 0x4>, + <0x0 0x39 0x4>, + <0x0 0x3a 0x4>; + #clock-cells = <1>; + clocks = <ð8clk 0>; + local-mac-address = <0x0 0x11 0x3a 0x8a 0x5a 0x78>; + max-frame-size = <0x233a>; + phyid = <3>; + phy-mode = "rgmii"; + }; }; }; --- linux-3.13.0.orig/arch/arm64/boot/dts/apm-mustang.dts +++ linux-3.13.0/arch/arm64/boot/dts/apm-mustang.dts @@ -17,6 +17,10 @@ model = "APM X-Gene Mustang board"; compatible = "apm,mustang", "apm,xgene-storm"; + aliases { + ethernet0 = &menet; + }; + chosen { }; memory { @@ -24,3 +28,15 @@ reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */ }; }; + +&menet { + status = "ok"; +}; + +&pcie0clk { + status = "ok"; +}; + +&pcie0 { + status = "ok"; +}; --- linux-3.13.0.orig/arch/arm64/kvm/sys_regs.h +++ linux-3.13.0/arch/arm64/kvm/sys_regs.h @@ -30,6 +30,8 @@ u8 Op2; u8 Rt; bool is_write; + bool is_aarch32; + bool is_32bit; /* Only valid if is_aarch32 is true */ }; struct sys_reg_desc { --- linux-3.13.0.orig/arch/arm64/kvm/handle_exit.c +++ linux-3.13.0/arch/arm64/kvm/handle_exit.c @@ -39,9 +39,6 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) { - if (kvm_psci_call(vcpu)) - return 1; - kvm_inject_undefined(vcpu); return 1; } --- linux-3.13.0.orig/arch/arm64/kvm/guest.c +++ linux-3.13.0/arch/arm64/kvm/guest.c @@ -207,20 +207,26 @@ unsigned long implementor = read_cpuid_implementor(); unsigned long part_number = read_cpuid_part_number(); - if (implementor != ARM_CPU_IMP_ARM) - return -EINVAL; + switch (implementor) { + case ARM_CPU_IMP_ARM: + switch (part_number) { + case ARM_CPU_PART_AEM_V8: + return KVM_ARM_TARGET_AEM_V8; + case ARM_CPU_PART_FOUNDATION: + return KVM_ARM_TARGET_FOUNDATION_V8; + case ARM_CPU_PART_CORTEX_A57: + return KVM_ARM_TARGET_CORTEX_A57; + }; + break; + case ARM_CPU_IMP_APM: + switch (part_number) { + case APM_CPU_PART_POTENZA: + return KVM_ARM_TARGET_XGENE_POTENZA; + }; + break; + }; - switch (part_number) { - case ARM_CPU_PART_AEM_V8: - return KVM_ARM_TARGET_AEM_V8; - case ARM_CPU_PART_FOUNDATION: - return KVM_ARM_TARGET_FOUNDATION_V8; - case ARM_CPU_PART_CORTEX_A57: - /* Currently handled by the generic backend */ - return KVM_ARM_TARGET_CORTEX_A57; - default: - return -EINVAL; - } + return -EINVAL; } int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, --- linux-3.13.0.orig/arch/arm64/kvm/sys_regs.c +++ linux-3.13.0/arch/arm64/kvm/sys_regs.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,48 @@ } /* + * Generic accessor for VM registers. Only called as long as HCR_TVM + * is set. + */ +static bool access_vm_reg(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + unsigned long val; + + BUG_ON(!p->is_write); + + val = *vcpu_reg(vcpu, p->Rt); + if (!p->is_aarch32) { + vcpu_sys_reg(vcpu, r->reg) = val; + } else { + vcpu_cp15(vcpu, r->reg) = val & 0xffffffffUL; + if (!p->is_32bit) + vcpu_cp15(vcpu, r->reg + 1) = val >> 32; + } + return true; +} + +/* + * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set. If the + * guest enables the MMU, we stop trapping the VM sys_regs and leave + * it in complete control of the caches. + */ +static bool access_sctlr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + access_vm_reg(vcpu, p, r); + + if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */ + vcpu->arch.hcr_el2 &= ~HCR_TVM; + stage2_flush_vm(vcpu->kvm); + } + + return true; +} + +/* * We could trap ID_DFR0 and tell the guest we don't support performance * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was * NAKed, so it will read the PMCR anyway. @@ -185,32 +228,32 @@ NULL, reset_mpidr, MPIDR_EL1 }, /* SCTLR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000), - NULL, reset_val, SCTLR_EL1, 0x00C50078 }, + access_sctlr, reset_val, SCTLR_EL1, 0x00C50078 }, /* CPACR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010), NULL, reset_val, CPACR_EL1, 0 }, /* TTBR0_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000), - NULL, reset_unknown, TTBR0_EL1 }, + access_vm_reg, reset_unknown, TTBR0_EL1 }, /* TTBR1_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001), - NULL, reset_unknown, TTBR1_EL1 }, + access_vm_reg, reset_unknown, TTBR1_EL1 }, /* TCR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010), - NULL, reset_val, TCR_EL1, 0 }, + access_vm_reg, reset_val, TCR_EL1, 0 }, /* AFSR0_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000), - NULL, reset_unknown, AFSR0_EL1 }, + access_vm_reg, reset_unknown, AFSR0_EL1 }, /* AFSR1_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001), - NULL, reset_unknown, AFSR1_EL1 }, + access_vm_reg, reset_unknown, AFSR1_EL1 }, /* ESR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000), - NULL, reset_unknown, ESR_EL1 }, + access_vm_reg, reset_unknown, ESR_EL1 }, /* FAR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000), - NULL, reset_unknown, FAR_EL1 }, + access_vm_reg, reset_unknown, FAR_EL1 }, /* PAR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000), NULL, reset_unknown, PAR_EL1 }, @@ -224,17 +267,17 @@ /* MAIR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000), - NULL, reset_unknown, MAIR_EL1 }, + access_vm_reg, reset_unknown, MAIR_EL1 }, /* AMAIR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000), - NULL, reset_amair_el1, AMAIR_EL1 }, + access_vm_reg, reset_amair_el1, AMAIR_EL1 }, /* VBAR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000), NULL, reset_val, VBAR_EL1, 0 }, /* CONTEXTIDR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001), - NULL, reset_val, CONTEXTIDR_EL1, 0 }, + access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 }, /* TPIDR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100), NULL, reset_unknown, TPIDR_EL1 }, @@ -305,14 +348,32 @@ NULL, reset_val, FPEXC32_EL2, 0x70 }, }; -/* Trapped cp15 registers */ +/* + * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding, + * depending on the way they are accessed (as a 32bit or a 64bit + * register). + */ static const struct sys_reg_desc cp15_regs[] = { + { Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 }, + { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR }, + { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 }, + { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 }, + { Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR }, + { Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, c3_DACR }, + { Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, c5_DFSR }, + { Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, c5_IFSR }, + { Op1( 0), CRn( 5), CRm( 1), Op2( 0), access_vm_reg, NULL, c5_ADFSR }, + { Op1( 0), CRn( 5), CRm( 1), Op2( 1), access_vm_reg, NULL, c5_AIFSR }, + { Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, c6_DFAR }, + { Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, c6_IFAR }, + /* * DC{C,I,CI}SW operations: */ { Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw }, { Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw }, { Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw }, + { Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake }, { Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake }, { Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake }, @@ -326,6 +387,14 @@ { Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake }, { Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake }, { Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake }, + + { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR }, + { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR }, + { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 }, + { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 }, + { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID }, + + { Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 }, }; /* Target specific emulation tables */ @@ -437,6 +506,8 @@ u32 hsr = kvm_vcpu_get_hsr(vcpu); int Rt2 = (hsr >> 10) & 0xf; + params.is_aarch32 = true; + params.is_32bit = false; params.CRm = (hsr >> 1) & 0xf; params.Rt = (hsr >> 5) & 0xf; params.is_write = ((hsr & 1) == 0); @@ -480,6 +551,8 @@ struct sys_reg_params params; u32 hsr = kvm_vcpu_get_hsr(vcpu); + params.is_aarch32 = true; + params.is_32bit = true; params.CRm = (hsr >> 1) & 0xf; params.Rt = (hsr >> 5) & 0xf; params.is_write = ((hsr & 1) == 0); @@ -549,6 +622,8 @@ struct sys_reg_params params; unsigned long esr = kvm_vcpu_get_hsr(vcpu); + params.is_aarch32 = false; + params.is_32bit = false; params.Op0 = (esr >> 20) & 3; params.Op1 = (esr >> 14) & 0x7; params.CRn = (esr >> 10) & 0xf; --- linux-3.13.0.orig/arch/arm64/kvm/Kconfig +++ linux-3.13.0/arch/arm64/kvm/Kconfig @@ -36,6 +36,17 @@ ---help--- Provides host support for ARM processors. +config KVM_ARM_MAX_VCPUS + int "Number maximum supported virtual CPUs per VM" + depends on KVM_ARM_HOST + default 4 + help + Static number of max supported virtual CPUs per VM. + + If you choose a high number, the vcpu structures will be quite + large, so only choose a reasonable number that you expect to + actually use. + config KVM_ARM_VGIC bool depends on KVM_ARM_HOST && OF --- linux-3.13.0.orig/arch/arm64/kvm/sys_regs_generic_v8.c +++ linux-3.13.0/arch/arm64/kvm/sys_regs_generic_v8.c @@ -90,6 +90,9 @@ &genericv8_target_table); kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A57, &genericv8_target_table); + kvm_register_target_sys_reg_table(KVM_ARM_TARGET_XGENE_POTENZA, + &genericv8_target_table); + return 0; } late_initcall(sys_reg_genericv8_init); --- linux-3.13.0.orig/arch/arm64/kernel/vdso.c +++ linux-3.13.0/arch/arm64/kernel/vdso.c @@ -238,6 +238,8 @@ vdso_data->use_syscall = use_syscall; vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec; vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec; + vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; + vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; if (!use_syscall) { vdso_data->cs_cycle_last = tk->clock->cycle_last; @@ -245,8 +247,6 @@ vdso_data->xtime_clock_nsec = tk->xtime_nsec; vdso_data->cs_mult = tk->mult; vdso_data->cs_shift = tk->shift; - vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; - vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; } smp_wmb(); --- linux-3.13.0.orig/arch/arm64/kernel/pcibios.c +++ linux-3.13.0/arch/arm64/kernel/pcibios.c @@ -0,0 +1,689 @@ +/* + * Based on linux/arch/arm/kernel/bios32.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include +#include +#include +#include +#include + +static int debug_pci; + +/* + * We can't use pci_find_device() here since we are + * called from interrupt context. + */ +static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, + int warn) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 status; + + /* + * ignore host bridge - we handle + * that separately + */ + if (dev->bus->number == 0 && dev->devfn == 0) + continue; + + pci_read_config_word(dev, PCI_STATUS, &status); + if (status == 0xffff) + continue; + + if ((status & status_mask) == 0) + continue; + + /* clear the status errors */ + pci_write_config_word(dev, PCI_STATUS, status & status_mask); + + if (warn) + printk("(%s: %04X) ", pci_name(dev), status); + } + + list_for_each_entry(dev, &bus->devices, bus_list) + if (dev->subordinate) + pcibios_bus_report_status(dev->subordinate, status_mask, warn); +} + +void pcibios_report_status(u_int status_mask, int warn) +{ + struct list_head *l; + + list_for_each(l, &pci_root_buses) { + struct pci_bus *bus = pci_bus_b(l); + + pcibios_bus_report_status(bus, status_mask, warn); + } +} + +/* + * We don't use this to fix the device, but initialisation of it. + * It's not the correct use for this, but it works. + * Note that the arbiter/ISA bridge appears to be buggy, specifically in + * the following area: + * 1. park on CPU + * 2. ISA bridge ping-pong + * 3. ISA bridge master handling of target RETRY + * + * Bug 3 is responsible for the sound DMA grinding to a halt. We now + * live with bug 2. + */ +static void pci_fixup_83c553(struct pci_dev *dev) +{ + /* + * Set memory region to start at address 0, and enable IO + */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_SPACE_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_IO); + + dev->resource[0].end -= dev->resource[0].start; + dev->resource[0].start = 0; + + /* + * All memory requests from ISA to be channelled to PCI + */ + pci_write_config_byte(dev, 0x48, 0xff); + + /* + * Enable ping-pong on bus master to ISA bridge transactions. + * This improves the sound DMA substantially. The fixed + * priority arbiter also helps (see below). + */ + pci_write_config_byte(dev, 0x42, 0x01); + + /* + * Enable PCI retry + */ + pci_write_config_byte(dev, 0x40, 0x22); + + /* + * We used to set the arbiter to "park on last master" (bit + * 1 set), but unfortunately the CyberPro does not park the + * bus. We must therefore park on CPU. Unfortunately, this + * may trigger yet another bug in the 553. + */ + pci_write_config_byte(dev, 0x83, 0x02); + + /* + * Make the ISA DMA request lowest priority, and disable + * rotating priorities completely. + */ + pci_write_config_byte(dev, 0x80, 0x11); + pci_write_config_byte(dev, 0x81, 0x00); + + /* + * Route INTA input to IRQ 11, and set IRQ11 to be level + * sensitive. + */ + pci_write_config_word(dev, 0x44, 0xb000); + outb(0x08, 0x4d1); +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, + pci_fixup_83c553); + +static void pci_fixup_unassign(struct pci_dev *dev) +{ + dev->resource[0].end -= dev->resource[0].start; + dev->resource[0].start = 0; +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F, + pci_fixup_unassign); + +/* + * Prevent the PCI layer from seeing the resources allocated to this device + * if it is the host bridge by marking it as such. These resources are of + * no consequence to the PCI layer (they are handled elsewhere). + */ +static void pci_fixup_dec21285(struct pci_dev *dev) +{ + int i; + + if (dev->devfn == 0) { + dev->class &= 0xff; + dev->class |= PCI_CLASS_BRIDGE_HOST << 8; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, + pci_fixup_dec21285); + +/* + * PCI IDE controllers use non-standard I/O port decoding, respect it. + */ +static void pci_fixup_ide_bases(struct pci_dev *dev) +{ + struct resource *r; + int i; + + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + return; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + r = dev->resource + i; + if ((r->start & ~0x80) == 0x374) { + r->start |= 2; + r->end = r->start; + } + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); + +/* + * Put the DEC21142 to sleep + */ +static void pci_fixup_dec21142(struct pci_dev *dev) +{ + pci_write_config_dword(dev, 0x40, 0x80000000); +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, + pci_fixup_dec21142); + +/* + * The CY82C693 needs some rather major fixups to ensure that it does + * the right thing. Idea from the Alpha people, with a few additions. + * + * We ensure that the IDE base registers are set to 1f0/3f4 for the + * primary bus, and 170/374 for the secondary bus. Also, hide them + * from the PCI subsystem view as well so we won't try to perform + * our own auto-configuration on them. + * + * In addition, we ensure that the PCI IDE interrupts are routed to + * IRQ 14 and IRQ 15 respectively. + * + * The above gets us to a point where the IDE on this device is + * functional. However, The CY82C693U _does not work_ in bus + * master mode without locking the PCI bus solid. + */ +static void pci_fixup_cy82c693(struct pci_dev *dev) +{ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u32 base0, base1; + + if (dev->class & 0x80) { /* primary */ + base0 = 0x1f0; + base1 = 0x3f4; + } else { /* secondary */ + base0 = 0x170; + base1 = 0x374; + } + + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + base0 | PCI_BASE_ADDRESS_SPACE_IO); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, + base1 | PCI_BASE_ADDRESS_SPACE_IO); + + dev->resource[0].start = 0; + dev->resource[0].end = 0; + dev->resource[0].flags = 0; + + dev->resource[1].start = 0; + dev->resource[1].end = 0; + dev->resource[1].flags = 0; + } else if (PCI_FUNC(dev->devfn) == 0) { + /* + * Setup IDE IRQ routing. + */ + pci_write_config_byte(dev, 0x4b, 14); + pci_write_config_byte(dev, 0x4c, 15); + + /* + * Disable FREQACK handshake, enable USB. + */ + pci_write_config_byte(dev, 0x4d, 0x41); + + /* + * Enable PCI retry, and PCI post-write buffer. + */ + pci_write_config_byte(dev, 0x44, 0x17); + + /* + * Enable ISA master and DMA post write buffering. + */ + pci_write_config_byte(dev, 0x45, 0x03); + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, + pci_fixup_cy82c693); + +static void pci_fixup_it8152(struct pci_dev *dev) +{ + int i; + /* fixup for ITE 8152 devices */ + /* FIXME: add defines for class 0x68000 and 0x80103 */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST || + dev->class == 0x68000 || dev->class == 0x80103) { + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8152, + pci_fixup_it8152); + +/* + * If the bus contains any of these devices, then we must not turn on + * parity checking of any kind. Currently this is CyberPro 20x0 only. + */ +static inline int pdev_bad_for_parity(struct pci_dev *dev) +{ + return ((dev->vendor == PCI_VENDOR_ID_INTERG && + (dev->device == PCI_DEVICE_ID_INTERG_2000 || + dev->device == PCI_DEVICE_ID_INTERG_2010)) || + (dev->vendor == PCI_VENDOR_ID_ITE && + dev->device == PCI_DEVICE_ID_ITE_8152)); + +} + +/* + * pcibios_fixup_bus - Called after each bus is probed, + * but before its children are examined. + */ +void pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev; + u16 features = + PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK; + + /* + * Walk the devices on this bus, working out what we can + * and can't support. + */ + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 status; + + pci_read_config_word(dev, PCI_STATUS, &status); + + /* + * If any device on this bus does not support fast back + * to back transfers, then the bus as a whole is not able + * to support them. Having fast back to back transfers + * on saves us one PCI cycle per transaction. + */ + if (!(status & PCI_STATUS_FAST_BACK)) + features &= ~PCI_COMMAND_FAST_BACK; + + if (pdev_bad_for_parity(dev)) + features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_PCI: + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status); + status |= + PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_MASTER_ABORT; + status &= + ~(PCI_BRIDGE_CTL_BUS_RESET | + PCI_BRIDGE_CTL_FAST_BACK); + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status); + break; + + case PCI_CLASS_BRIDGE_CARDBUS: + pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL, + &status); + status |= + PCI_CB_BRIDGE_CTL_PARITY | + PCI_CB_BRIDGE_CTL_MASTER_ABORT; + pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL, + status); + break; + } + } + + /* + * Now walk the devices again, this time setting them up. + */ + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 cmd; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= features; + pci_write_config_word(dev, PCI_COMMAND, cmd); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + L1_CACHE_BYTES >> 2); + } + + /* + * Propagate the flags to the PCI bridge. + */ + if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + if (features & PCI_COMMAND_FAST_BACK) + bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK; + if (features & PCI_COMMAND_PARITY) + bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY; + } + + /* + * Report what we did for this bus + */ + printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", + bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); +} +EXPORT_SYMBOL(pcibios_fixup_bus); + +void pcibios_add_bus(struct pci_bus *bus) +{ + struct pci_sys_data *sys = bus->sysdata; + if (sys->add_bus) + sys->add_bus(bus); +} + +void pcibios_remove_bus(struct pci_bus *bus) +{ + struct pci_sys_data *sys = bus->sysdata; + if (sys->remove_bus) + sys->remove_bus(bus); +} + +/* + * Swizzle the device pin each time we cross a bridge. If a platform does + * not provide a swizzle function, we perform the standard PCI swizzling. + * + * The default swizzling walks up the bus tree one level at a time, applying + * the standard swizzle function at each step, stopping when it finds the PCI + * root bus. This will return the slot number of the bridge device on the + * root bus and the interrupt pin on that device which should correspond + * with the downstream device interrupt. + * + * Platforms may override this, in which case the slot and pin returned + * depend entirely on the platform code. However, please note that the + * PCI standard swizzle is implemented on plug-in cards and Cardbus based + * PCI extenders, so it can not be ignored. + */ +static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin) +{ + struct pci_sys_data *sys = dev->sysdata; + int slot, oldpin = *pin; + + if (sys->swizzle) + slot = sys->swizzle(dev, pin); + else + slot = pci_common_swizzle(dev, pin); + + if (debug_pci) + printk("PCI: %s swizzling pin %d => pin %d slot %d\n", + pci_name(dev), oldpin, *pin, slot); + + return slot; +} + +/* + * Map a slot/pin to an IRQ. + */ +static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + struct pci_sys_data *sys = dev->sysdata; + int irq = -1; + + if (sys->map_irq) + irq = sys->map_irq(dev, slot, pin); + + if (debug_pci) + printk("PCI: %s mapping slot %d pin %d => irq %d\n", + pci_name(dev), slot, pin, irq); + + return irq; +} + +static int pcibios_init_resources(int busnr, struct pci_sys_data *sys) +{ + int ret; + struct pci_host_bridge_window *window; + + if (list_empty(&sys->resources)) { + pci_add_resource_offset(&sys->resources, + &iomem_resource, sys->mem_offset); + } + + list_for_each_entry(window, &sys->resources, list) { + if (resource_type(window->res) == IORESOURCE_IO) + return 0; + } + + sys->io_res.start = (busnr * SZ_64K) ? : pcibios_min_io; + sys->io_res.end = (busnr + 1) * SZ_64K - 1; + sys->io_res.flags = IORESOURCE_IO; + sys->io_res.name = sys->io_res_name; + sprintf(sys->io_res_name, "PCI%d I/O", busnr); + + ret = request_resource(&ioport_resource, &sys->io_res); + if (ret) { + pr_err("PCI: unable to allocate I/O port region (%d)\n", ret); + return ret; + } + pci_add_resource_offset(&sys->resources, &sys->io_res, sys->io_offset); + + return 0; +} + +static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, + struct list_head *head) +{ + struct pci_sys_data *sys = NULL; + int ret; + int nr, busnr; + + for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { + sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL); + if (!sys) + panic("PCI: unable to allocate sys data!"); + +#ifdef CONFIG_PCI_DOMAINS + sys->domain = hw->domain; +#endif + sys->busnr = busnr; + sys->swizzle = hw->swizzle; + sys->map_irq = hw->map_irq; + sys->align_resource = hw->align_resource; + sys->add_bus = hw->add_bus; + sys->remove_bus = hw->remove_bus; + INIT_LIST_HEAD(&sys->resources); + + if (hw->private_data) + sys->private_data = hw->private_data[nr]; + + ret = hw->setup(nr, sys); + + if (ret > 0) { + ret = pcibios_init_resources(nr, sys); + if (ret) { + kfree(sys); + break; + } + + if (hw->scan) + sys->bus = hw->scan(nr, sys); + else + sys->bus = pci_scan_root_bus(parent, sys->busnr, + hw->ops, sys, + &sys->resources); + + if (!sys->bus) + panic("PCI: unable to scan bus!"); + + busnr = sys->bus->busn_res.end + 1; + + list_add(&sys->node, head); + } else { + kfree(sys); + if (ret < 0) + break; + } + } +} + +void pci_common_init_dev(struct device *parent, struct hw_pci *hw) +{ + struct pci_sys_data *sys; + LIST_HEAD(head); + + pci_add_flags(PCI_REASSIGN_ALL_RSRC); + if (hw->preinit) + hw->preinit(); + pcibios_init_hw(parent, hw, &head); + if (hw->postinit) + hw->postinit(); + + pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); + + list_for_each_entry(sys, &head, node) { + struct pci_bus *bus = sys->bus; + + if (!pci_has_flag(PCI_PROBE_ONLY)) { + /* + * Size the bridge windows. + */ + pci_bus_size_bridges(bus); + + /* + * Assign resources. + */ + pci_bus_assign_resources(bus); + } + + /* + * Tell drivers about devices found. + */ + pci_bus_add_devices(bus); + } +} + +#ifndef CONFIG_PCI_HOST_ITE8152 +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} +#endif + +char *__init pcibios_setup(char *str) +{ + if (!strcmp(str, "debug")) { + debug_pci = 1; + return NULL; + } else if (!strcmp(str, "firmware")) { + pci_add_flags(PCI_PROBE_ONLY); + return NULL; + } + return str; +} + +/* + * From arch/i386/kernel/pci-i386.c: + * + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might be mirrored at 0x0100-0x03ff.. + */ +resource_size_t pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, + resource_size_t align) +{ + struct pci_dev *dev = data; + struct pci_sys_data *sys = dev->sysdata; + resource_size_t start = res->start; + + if (res->flags & IORESOURCE_IO && start & 0x300) + start = (start + 0x3ff) & ~0x3ff; + + start = (start + align - 1) & ~(align - 1); + + if (sys->align_resource) + return sys->align_resource(dev, res, start, size, align); + + return start; +} + +/** + * pcibios_enable_device - Enable I/O and memory. + * @dev: PCI device to be enabled + */ +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1 << idx))) + continue; + + r = dev->resource + idx; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because" + " of resource collisions\n", pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + + /* + * Bridges (eg, cardbus bridges) need to be fully enabled + */ + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + + if (cmd != old_cmd) { + printk("PCI: enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + struct pci_sys_data *root = dev->sysdata; + unsigned long phys; + + if (mmap_state == pci_mmap_io) + return -EINVAL; + else + phys = vma->vm_pgoff + (root->mem_offset >> PAGE_SHIFT); + + /* + * Mark this as IO + */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_pfn_range(vma, vma->vm_start, phys, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} --- linux-3.13.0.orig/arch/arm64/kernel/Makefile +++ linux-3.13.0/arch/arm64/kernel/Makefile @@ -19,6 +19,7 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_PCI) += pcibios.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) head-y := head.o --- linux-3.13.0.orig/arch/arm64/kernel/kuser32.S +++ linux-3.13.0/arch/arm64/kernel/kuser32.S @@ -38,12 +38,13 @@ .inst 0xe92d00f0 // push {r4, r5, r6, r7} .inst 0xe1c040d0 // ldrd r4, r5, [r0] .inst 0xe1c160d0 // ldrd r6, r7, [r1] - .inst 0xe1b20e9f // 1: ldaexd r0, r1, [r2] + .inst 0xe1b20f9f // 1: ldrexd r0, r1, [r2] .inst 0xe0303004 // eors r3, r0, r4 .inst 0x00313005 // eoreqs r3, r1, r5 .inst 0x01a23e96 // stlexdeq r3, r6, [r2] .inst 0x03330001 // teqeq r3, #1 .inst 0x0afffff9 // beq 1b + .inst 0xf57ff05b // dmb ish .inst 0xe2730000 // rsbs r0, r3, #0 .inst 0xe8bd00f0 // pop {r4, r5, r6, r7} .inst 0xe12fff1e // bx lr @@ -55,11 +56,12 @@ .align 5 __kuser_cmpxchg: // 0xffff0fc0 - .inst 0xe1923e9f // 1: ldaex r3, [r2] + .inst 0xe1923f9f // 1: ldrex r3, [r2] .inst 0xe0533000 // subs r3, r3, r0 .inst 0x01823e91 // stlexeq r3, r1, [r2] .inst 0x03330001 // teqeq r3, #1 .inst 0x0afffffa // beq 1b + .inst 0xf57ff05b // dmb ish .inst 0xe2730000 // rsbs r0, r3, #0 .inst 0xe12fff1e // bx lr --- linux-3.13.0.orig/arch/arm64/kernel/stacktrace.c +++ linux-3.13.0/arch/arm64/kernel/stacktrace.c @@ -48,7 +48,11 @@ frame->sp = fp + 0x10; frame->fp = *(unsigned long *)(fp); - frame->pc = *(unsigned long *)(fp + 8); + /* + * -4 here because we care about the PC at time of bl, + * not where the return will go. + */ + frame->pc = *(unsigned long *)(fp + 8) - 4; return 0; } --- linux-3.13.0.orig/arch/arm64/kernel/vdso/Makefile +++ linux-3.13.0/arch/arm64/kernel/vdso/Makefile @@ -48,7 +48,7 @@ # Actual build commands quiet_cmd_vdsold = VDSOL $@ - cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@ + cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@ quiet_cmd_vdsoas = VDSOA $@ cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< --- linux-3.13.0.orig/arch/arm64/kernel/vdso/gettimeofday.S +++ linux-3.13.0/arch/arm64/kernel/vdso/gettimeofday.S @@ -103,6 +103,8 @@ bl __do_get_tspec seqcnt_check w9, 1b + mov x30, x2 + cmp w0, #CLOCK_MONOTONIC b.ne 6f @@ -118,6 +120,9 @@ ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne b.ne 8f + /* xtime_coarse_nsec is already right-shifted */ + mov x12, #0 + /* Get coarse timespec. */ adr vdso_data, _vdso_data 3: seqcnt_acquire @@ -156,7 +161,7 @@ lsr x11, x11, x12 stp x10, x11, [x1, #TSPEC_TV_SEC] mov x0, xzr - ret x2 + ret 7: mov x30, x2 8: /* Syscall fallback. */ --- linux-3.13.0.orig/arch/arm64/include/uapi/asm/kvm.h +++ linux-3.13.0/arch/arm64/include/uapi/asm/kvm.h @@ -55,8 +55,9 @@ #define KVM_ARM_TARGET_AEM_V8 0 #define KVM_ARM_TARGET_FOUNDATION_V8 1 #define KVM_ARM_TARGET_CORTEX_A57 2 +#define KVM_ARM_TARGET_XGENE_POTENZA 3 -#define KVM_ARM_NUM_TARGETS 3 +#define KVM_ARM_NUM_TARGETS 4 /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ #define KVM_ARM_DEVICE_TYPE_SHIFT 0 --- linux-3.13.0.orig/arch/arm64/include/asm/dma-mapping.h +++ linux-3.13.0/arch/arm64/include/asm/dma-mapping.h @@ -26,8 +26,6 @@ #include #include -#define ARCH_HAS_DMA_GET_REQUIRED_MASK - #define DMA_ERROR_CODE (~(dma_addr_t)0) extern struct dma_map_ops *dma_ops; --- linux-3.13.0.orig/arch/arm64/include/asm/dma.h +++ linux-3.13.0/arch/arm64/include/asm/dma.h @@ -0,0 +1,18 @@ +/* + * Based on linux/arch/arm/include/asm/dma.h + */ +#ifndef __ASM_ARM_DMA_H +#define __ASM_ARM_DMA_H + +/* + * This is the maximum virtual address which can be DMA'd from. + */ +#define MAX_DMA_ADDRESS (~0ULL) + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* __ASM_ARM_DMA_H */ --- linux-3.13.0.orig/arch/arm64/include/asm/cacheflush.h +++ linux-3.13.0/arch/arm64/include/asm/cacheflush.h @@ -116,6 +116,7 @@ static inline void __flush_icache_all(void) { asm("ic ialluis"); + dsb(); } #define flush_dcache_mmap_lock(mapping) \ --- linux-3.13.0.orig/arch/arm64/include/asm/atomic.h +++ linux-3.13.0/arch/arm64/include/asm/atomic.h @@ -64,7 +64,7 @@ int result; asm volatile("// atomic_add_return\n" -"1: ldaxr %w0, %2\n" +"1: ldxr %w0, %2\n" " add %w0, %w0, %w3\n" " stlxr %w1, %w0, %2\n" " cbnz %w1, 1b" @@ -72,6 +72,7 @@ : "Ir" (i) : "cc", "memory"); + smp_mb(); return result; } @@ -96,7 +97,7 @@ int result; asm volatile("// atomic_sub_return\n" -"1: ldaxr %w0, %2\n" +"1: ldxr %w0, %2\n" " sub %w0, %w0, %w3\n" " stlxr %w1, %w0, %2\n" " cbnz %w1, 1b" @@ -104,6 +105,7 @@ : "Ir" (i) : "cc", "memory"); + smp_mb(); return result; } @@ -112,17 +114,20 @@ unsigned long tmp; int oldval; + smp_mb(); + asm volatile("// atomic_cmpxchg\n" -"1: ldaxr %w1, %2\n" +"1: ldxr %w1, %2\n" " cmp %w1, %w3\n" " b.ne 2f\n" -" stlxr %w0, %w4, %2\n" +" stxr %w0, %w4, %2\n" " cbnz %w0, 1b\n" "2:" : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter) : "Ir" (old), "r" (new) : "cc", "memory"); + smp_mb(); return oldval; } @@ -183,7 +188,7 @@ unsigned long tmp; asm volatile("// atomic64_add_return\n" -"1: ldaxr %0, %2\n" +"1: ldxr %0, %2\n" " add %0, %0, %3\n" " stlxr %w1, %0, %2\n" " cbnz %w1, 1b" @@ -191,6 +196,7 @@ : "Ir" (i) : "cc", "memory"); + smp_mb(); return result; } @@ -215,7 +221,7 @@ unsigned long tmp; asm volatile("// atomic64_sub_return\n" -"1: ldaxr %0, %2\n" +"1: ldxr %0, %2\n" " sub %0, %0, %3\n" " stlxr %w1, %0, %2\n" " cbnz %w1, 1b" @@ -223,6 +229,7 @@ : "Ir" (i) : "cc", "memory"); + smp_mb(); return result; } @@ -231,17 +238,20 @@ long oldval; unsigned long res; + smp_mb(); + asm volatile("// atomic64_cmpxchg\n" -"1: ldaxr %1, %2\n" +"1: ldxr %1, %2\n" " cmp %1, %3\n" " b.ne 2f\n" -" stlxr %w0, %4, %2\n" +" stxr %w0, %4, %2\n" " cbnz %w0, 1b\n" "2:" : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter) : "Ir" (old), "r" (new) : "cc", "memory"); + smp_mb(); return oldval; } @@ -253,11 +263,12 @@ unsigned long tmp; asm volatile("// atomic64_dec_if_positive\n" -"1: ldaxr %0, %2\n" +"1: ldxr %0, %2\n" " subs %0, %0, #1\n" " b.mi 2f\n" " stlxr %w1, %0, %2\n" " cbnz %w1, 1b\n" +" dmb ish\n" "2:" : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) : --- linux-3.13.0.orig/arch/arm64/include/asm/pgtable.h +++ linux-3.13.0/arch/arm64/include/asm/pgtable.h @@ -136,10 +136,10 @@ /* * The following only work if pte_present(). Undefined behaviour otherwise. */ -#define pte_present(pte) (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) -#define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) -#define pte_young(pte) (pte_val(pte) & PTE_AF) -#define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) +#define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))) +#define pte_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY)) +#define pte_young(pte) (!!(pte_val(pte) & PTE_AF)) +#define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL)) #define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) --- linux-3.13.0.orig/arch/arm64/include/asm/kvm_mmu.h +++ linux-3.13.0/arch/arm64/include/asm/kvm_mmu.h @@ -106,7 +106,6 @@ return true; } -static inline void kvm_clean_dcache_area(void *addr, size_t size) {} static inline void kvm_clean_pgd(pgd_t *pgd) {} static inline void kvm_clean_pmd_entry(pmd_t *pmd) {} static inline void kvm_clean_pte(pte_t *pte) {} @@ -122,11 +121,25 @@ pmd_val(*pmd) |= PMD_S2_RDWR; } +#define kvm_pgd_addr_end(addr, end) pgd_addr_end(addr, end) +#define kvm_pud_addr_end(addr, end) pud_addr_end(addr, end) +#define kvm_pmd_addr_end(addr, end) pmd_addr_end(addr, end) + struct kvm; -static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva, - unsigned long size) +#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l)) + +static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu) +{ + return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101; +} + +static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, + unsigned long size) { + if (!vcpu_has_cache_enabled(vcpu)) + kvm_flush_dcache_to_poc((void *)hva, size); + if (!icache_is_aliasing()) { /* PIPT */ flush_icache_range(hva, hva + size); } else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */ @@ -135,7 +148,7 @@ } } -#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l)) +void stage2_flush_vm(struct kvm *kvm); #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ --- linux-3.13.0.orig/arch/arm64/include/asm/kvm_arm.h +++ linux-3.13.0/arch/arm64/include/asm/kvm_arm.h @@ -62,6 +62,7 @@ * RW: 64bit by default, can be overriden for 32bit VMs * TAC: Trap ACTLR * TSC: Trap SMC + * TVM: Trap VM ops (until M+C set in SCTLR_EL1) * TSW: Trap cache operations by set/way * TWE: Trap WFE * TWI: Trap WFI @@ -74,7 +75,7 @@ * SWIO: Turn set/way invalidates into set/way clean+invalidate */ #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \ - HCR_BSU_IS | HCR_FB | HCR_TAC | \ + HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \ HCR_AMO | HCR_IMO | HCR_FMO | \ HCR_SWIO | HCR_TIDCP | HCR_RW) #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) --- linux-3.13.0.orig/arch/arm64/include/asm/pcibios.h +++ linux-3.13.0/arch/arm64/include/asm/pcibios.h @@ -0,0 +1,98 @@ +/* + * Based on arch/arm/include/asm/mach/pci.h + * + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_PCIBIOS_H +#define __ASM_PCIBIOS_H + +#include + +struct pci_sys_data; +struct pci_ops; +struct pci_bus; +struct device; + +struct hw_pci { +#ifdef CONFIG_PCI_DOMAINS + int domain; +#endif + struct pci_ops *ops; + int nr_controllers; + void **private_data; + int (*setup) (int nr, struct pci_sys_data *); + struct pci_bus *(*scan) (int nr, struct pci_sys_data *); + void (*preinit) (void); + void (*postinit) (void); + u8(*swizzle) (struct pci_dev *dev, u8 *pin); + int (*map_irq) (const struct pci_dev *dev, u8 slot, u8 pin); + resource_size_t(*align_resource) (struct pci_dev *dev, + const struct resource *res, + resource_size_t start, + resource_size_t size, + resource_size_t align); + void (*add_bus) (struct pci_bus *bus); + void (*remove_bus) (struct pci_bus *bus); +}; + +/* + * Per-controller structure + */ +struct pci_sys_data { +#ifdef CONFIG_PCI_DOMAINS + int domain; +#endif + struct list_head node; + int busnr; /* primary bus number */ + u64 mem_offset; /* bus->cpu memory mapping offset */ + unsigned long io_offset; /* bus->cpu IO mapping offset */ + struct pci_bus *bus; /* PCI bus */ + struct list_head resources; /* root bus resources (apertures) */ + struct resource io_res; + char io_res_name[12]; + /* Bridge swizzling */ + u8(*swizzle) (struct pci_dev *, u8 *); + /* IRQ mapping */ + int (*map_irq) (const struct pci_dev *, u8, u8); + /* Resource alignement requirements */ + resource_size_t(*align_resource) (struct pci_dev *dev, + const struct resource *res, + resource_size_t start, + resource_size_t size, + resource_size_t align); + void (*add_bus) (struct pci_bus *bus); + void (*remove_bus) (struct pci_bus *bus); + void *private_data; /* platform controller private data */ +}; + +/* + * Call this with your hw_pci struct to initialise the PCI system. + */ +void pci_common_init_dev(struct device *, struct hw_pci *); + +/* + * Compatibility wrapper for older platforms that do not care about + * passing the parent device. + */ +static inline void pci_common_init(struct hw_pci *hw) +{ + pci_common_init_dev(NULL, hw); +} + +/* + * Setup early fixed I/O mapping. + */ +#if defined(CONFIG_PCI) +extern void pci_map_io_early(unsigned long pfn); +#else +static inline void pci_map_io_early(unsigned long pfn) +{ +} +#endif + +#endif /* __ASM_PCIBIOS_H */ --- linux-3.13.0.orig/arch/arm64/include/asm/cmpxchg.h +++ linux-3.13.0/arch/arm64/include/asm/cmpxchg.h @@ -29,7 +29,7 @@ switch (size) { case 1: asm volatile("// __xchg1\n" - "1: ldaxrb %w0, %2\n" + "1: ldxrb %w0, %2\n" " stlxrb %w1, %w3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr) @@ -38,7 +38,7 @@ break; case 2: asm volatile("// __xchg2\n" - "1: ldaxrh %w0, %2\n" + "1: ldxrh %w0, %2\n" " stlxrh %w1, %w3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr) @@ -47,7 +47,7 @@ break; case 4: asm volatile("// __xchg4\n" - "1: ldaxr %w0, %2\n" + "1: ldxr %w0, %2\n" " stlxr %w1, %w3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr) @@ -56,7 +56,7 @@ break; case 8: asm volatile("// __xchg8\n" - "1: ldaxr %0, %2\n" + "1: ldxr %0, %2\n" " stlxr %w1, %3, %2\n" " cbnz %w1, 1b\n" : "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr) @@ -67,6 +67,7 @@ BUILD_BUG(); } + smp_mb(); return ret; } --- linux-3.13.0.orig/arch/arm64/include/asm/pci.h +++ linux-3.13.0/arch/arm64/include/asm/pci.h @@ -0,0 +1,74 @@ +/* + * Based on arch/arm/include/asm/pci.h + */ +#ifndef ASMARM_PCI_H +#define ASMARM_PCI_H + +#ifdef __KERNEL__ +#include +#include + +#include /* for pci_sys_data */ + +extern unsigned long pcibios_min_io; +#define PCIBIOS_MIN_IO pcibios_min_io +extern unsigned long pcibios_min_mem; +#define PCIBIOS_MIN_MEM pcibios_min_mem + +static inline int pcibios_assign_all_busses(void) +{ + return pci_has_flag(PCI_REASSIGN_ALL_RSRC); +} + +#ifdef CONFIG_PCI_DOMAINS +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sys_data *root = bus->sysdata; + + return root->domain; +} + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} +#endif /* CONFIG_PCI_DOMAINS */ + +static inline void pcibios_penalize_isa_irq(int irq, int active) +{ + /* We don't do dynamic PCI IRQ allocation */ +} + +/* + * The PCI address space does equal the physical memory address space. + * The networking and block device layers use this boolean for bounce + * buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (1) + +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + +#define HAVE_PCI_MMAP +extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, + int write_combine); + +/* + * Dummy implementation; always return 0. + */ +static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) +{ + return 0; +} + +#endif /* __KERNEL__ */ + +#endif --- linux-3.13.0.orig/arch/arm64/include/asm/kvm_asm.h +++ linux-3.13.0/arch/arm64/include/asm/kvm_asm.h @@ -79,7 +79,8 @@ #define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */ #define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */ #define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */ -#define c10_AMAIR (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */ +#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */ +#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */ #define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */ #define NR_CP15_REGS (NR_SYS_REGS * 2) --- linux-3.13.0.orig/arch/arm64/include/asm/kvm_host.h +++ linux-3.13.0/arch/arm64/include/asm/kvm_host.h @@ -26,7 +26,12 @@ #include #include -#define KVM_MAX_VCPUS 4 +#if defined(CONFIG_KVM_ARM_MAX_VCPUS) +#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS +#else +#define KVM_MAX_VCPUS 0 +#endif + #define KVM_USER_MEM_SLOTS 32 #define KVM_PRIVATE_MEM_SLOTS 4 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 --- linux-3.13.0.orig/arch/arm64/include/asm/io.h +++ linux-3.13.0/arch/arm64/include/asm/io.h @@ -118,10 +118,27 @@ #define writeq(v,c) ({ __iowmb(); writeq_relaxed((v),(c)); }) /* + * A typesafe __io() helper + */ +static inline void __iomem *__typesafe_io(unsigned long addr) +{ + return (void __iomem *)addr; +} + +/* * I/O port access primitives. */ -#define IO_SPACE_LIMIT 0xffff #define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_2M)) +#if defined(CONFIG_PCI) +#define IO_SPACE_LIMIT ((resource_size_t)0xffffffff) +#define __io(a) __typesafe_io((unsigned long)PCI_IOBASE + \ + ((a) & IO_SPACE_LIMIT)) +#else +#define __io(a) __typesafe_io((a) & IO_SPACE_LIMIT) +#endif +extern void __iomem *ioport_map(unsigned long port, unsigned int nr); +extern void ioport_unmap(void __iomem *addr); +extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr); static inline u8 inb(unsigned long addr) { --- linux-3.13.0.orig/arch/arm64/include/asm/futex.h +++ linux-3.13.0/arch/arm64/include/asm/futex.h @@ -24,10 +24,11 @@ #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \ asm volatile( \ -"1: ldaxr %w1, %2\n" \ +"1: ldxr %w1, %2\n" \ insn "\n" \ "2: stlxr %w3, %w0, %2\n" \ " cbnz %w3, 1b\n" \ +" dmb ish\n" \ "3:\n" \ " .pushsection .fixup,\"ax\"\n" \ "4: mov %w0, %w5\n" \ @@ -110,11 +111,12 @@ return -EFAULT; asm volatile("// futex_atomic_cmpxchg_inatomic\n" -"1: ldaxr %w1, %2\n" +"1: ldxr %w1, %2\n" " sub %w3, %w1, %w4\n" " cbnz %w3, 3f\n" "2: stlxr %w3, %w5, %2\n" " cbnz %w3, 1b\n" +" dmb ish\n" "3:\n" " .pushsection .fixup,\"ax\"\n" "4: mov %w0, %w6\n" --- linux-3.13.0.orig/arch/arm64/mm/mmu.c +++ linux-3.13.0/arch/arm64/mm/mmu.c @@ -203,10 +203,18 @@ do { next = pmd_addr_end(addr, end); /* try section mapping first */ - if (((addr | next | phys) & ~SECTION_MASK) == 0) + if (((addr | next | phys) & ~SECTION_MASK) == 0) { + pmd_t old_pmd =*pmd; set_pmd(pmd, __pmd(phys | prot_sect_kernel)); - else + /* + * Check for previous table entries created during + * boot (__create_page_tables) and flush them. + */ + if (!pmd_none(old_pmd)) + flush_tlb_all(); + } else { alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys)); + } phys += next - addr; } while (pmd++, addr = next, addr != end); } --- linux-3.13.0.orig/arch/arm64/mm/iomap.c +++ linux-3.13.0/arch/arm64/mm/iomap.c @@ -0,0 +1,31 @@ +/* + * Based on linux/arch/arm/mm/iomap.c + * + * Map IO port and PCI memory spaces so that {read,write}[bwl] can + * be used to access this memory. + */ +#include +#include +#include +#include + +#ifdef __io +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return __io(port); +} +EXPORT_SYMBOL(ioport_map); + +void ioport_unmap(void __iomem *addr) +{ +} +EXPORT_SYMBOL(ioport_unmap); +#endif + +#ifdef CONFIG_PCI +unsigned long pcibios_min_io = 0x1000; +EXPORT_SYMBOL(pcibios_min_io); + +unsigned long pcibios_min_mem = 0x01000000; +EXPORT_SYMBOL(pcibios_min_mem); +#endif --- linux-3.13.0.orig/arch/arm64/mm/Makefile +++ linux-3.13.0/arch/arm64/mm/Makefile @@ -1,5 +1,5 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ cache.o copypage.o flush.o \ - ioremap.o mmap.o pgd.o mmu.o \ + ioremap.o iomap.o mmap.o pgd.o mmu.o \ context.o tlb.o proc.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o --- linux-3.13.0.orig/arch/arm64/mm/ioremap.c +++ linux-3.13.0/arch/arm64/mm/ioremap.c @@ -98,3 +98,17 @@ __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_cache); + +#ifdef CONFIG_PCI +int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr) +{ + BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT); + + return ioremap_page_range((unsigned long)PCI_IOBASE + offset, + (unsigned long)PCI_IOBASE + offset + SZ_64K, + phys_addr, + __pgprot(PROT_NORMAL_NC)); +} +EXPORT_SYMBOL_GPL(pci_ioremap_io); +#endif + --- linux-3.13.0.orig/arch/arm64/mm/copypage.c +++ linux-3.13.0/arch/arm64/mm/copypage.c @@ -32,3 +32,4 @@ { clear_page(kaddr); } +EXPORT_SYMBOL(__cpu_clear_user_page); --- linux-3.13.0.orig/arch/arm64/lib/bitops.S +++ linux-3.13.0/arch/arm64/lib/bitops.S @@ -46,11 +46,12 @@ mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset lsl x4, x2, x3 // Create mask -1: ldaxr x2, [x1] +1: ldxr x2, [x1] lsr x0, x2, x3 // Save old value of bit \instr x2, x2, x4 // toggle bit stlxr w5, x2, [x1] cbnz w5, 1b + dmb ish and x0, x0, #1 3: ret ENDPROC(\name ) --- linux-3.13.0.orig/ipc/msg.c +++ linux-3.13.0/ipc/msg.c @@ -885,6 +885,8 @@ return -EINVAL; if (msgflg & MSG_COPY) { + if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT)) + return -EINVAL; copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax)); if (IS_ERR(copy)) return PTR_ERR(copy); --- linux-3.13.0.orig/ipc/mqueue.c +++ linux-3.13.0/ipc/mqueue.c @@ -433,9 +433,9 @@ error = -EACCES; goto out_unlock; } - if (ipc_ns->mq_queues_count >= HARD_QUEUESMAX || - (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && - !capable(CAP_SYS_RESOURCE))) { + + if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && + !capable(CAP_SYS_RESOURCE)) { error = -ENOSPC; goto out_unlock; } --- linux-3.13.0.orig/ipc/sem.c +++ linux-3.13.0/ipc/sem.c @@ -1947,6 +1947,14 @@ error = get_queue_result(&queue); /* + * wake_up_sem_queue_do operates on queue without locking, so we + * need a barrier here to order our read of queue.status and the + * subsequent reuse of queue (queue is on the stack so will be + * most likely reused in the next function call). + */ + smp_mb(); + + /* * Array removed? If yes, leave without sem_unlock(). */ if (IS_ERR(sma)) { --- linux-3.13.0.orig/ipc/mq_sysctl.c +++ linux-3.13.0/ipc/mq_sysctl.c @@ -22,6 +22,16 @@ return which; } +static int proc_mq_dointvec(ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table mq_table; + memcpy(&mq_table, table, sizeof(mq_table)); + mq_table.data = get_mq(table); + + return proc_dointvec(&mq_table, write, buffer, lenp, ppos); +} + static int proc_mq_dointvec_minmax(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -33,12 +43,10 @@ lenp, ppos); } #else +#define proc_mq_dointvec NULL #define proc_mq_dointvec_minmax NULL #endif -static int msg_queues_limit_min = MIN_QUEUESMAX; -static int msg_queues_limit_max = HARD_QUEUESMAX; - static int msg_max_limit_min = MIN_MSGMAX; static int msg_max_limit_max = HARD_MSGMAX; @@ -51,9 +59,7 @@ .data = &init_ipc_ns.mq_queues_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_mq_dointvec_minmax, - .extra1 = &msg_queues_limit_min, - .extra2 = &msg_queues_limit_max, + .proc_handler = proc_mq_dointvec, }, { .procname = "msg_max", --- linux-3.13.0.orig/init/noinitramfs.c +++ linux-3.13.0/init/noinitramfs.c @@ -22,6 +22,8 @@ #include #include +LIST_HEAD(populate_rootfs_domain); + /* * Create a simple rootfs that is similar to the default initramfs */ --- linux-3.13.0.orig/init/version.c +++ linux-3.13.0/init/version.c @@ -42,7 +42,11 @@ /* FIXED STRINGS! Don't touch! */ const char linux_banner[] = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" - LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; + LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION +#ifdef CONFIG_VERSION_SIGNATURE + " (" CONFIG_VERSION_SIGNATURE ")" +#endif + "\n"; const char linux_proc_banner[] = "%s version %s" --- linux-3.13.0.orig/init/Kconfig +++ linux-3.13.0/init/Kconfig @@ -208,6 +208,15 @@ but you may wish to use a different default here to make a minimal system more usable with less configuration. +config VERSION_SIGNATURE + string "Arbitrary version signature" + help + This string will be created in a file, /proc/version_signature. It + is useful in determining arbitrary data about your kernel. For instance, + if you have several kernels of the same version, but need to keep track + of a revision of the same kernel, but not affect it's ability to load + compatible modules, this is the easiest way to do that. + config SWAP bool "Support for paging of anonymous memory (swap)" depends on MMU && BLOCK --- linux-3.13.0.orig/init/main.c +++ linux-3.13.0/init/main.c @@ -215,7 +215,7 @@ static int __init quiet_kernel(char *str) { - console_loglevel = 4; + console_loglevel = 2; return 0; } --- linux-3.13.0.orig/fs/sync.c +++ linux-3.13.0/fs/sync.c @@ -27,11 +27,10 @@ * wait == 1 case since in that case write_inode() functions do * sync_dirty_buffer() and thus effectively write one block at a time. */ -static int __sync_filesystem(struct super_block *sb, int wait, - unsigned long start) +static int __sync_filesystem(struct super_block *sb, int wait) { if (wait) - sync_inodes_sb(sb, start); + sync_inodes_sb(sb); else writeback_inodes_sb(sb, WB_REASON_SYNC); @@ -48,7 +47,6 @@ int sync_filesystem(struct super_block *sb) { int ret; - unsigned long start = jiffies; /* * We need to be protected against the filesystem going from @@ -62,17 +60,17 @@ if (sb->s_flags & MS_RDONLY) return 0; - ret = __sync_filesystem(sb, 0, start); + ret = __sync_filesystem(sb, 0); if (ret < 0) return ret; - return __sync_filesystem(sb, 1, start); + return __sync_filesystem(sb, 1); } EXPORT_SYMBOL_GPL(sync_filesystem); static void sync_inodes_one_sb(struct super_block *sb, void *arg) { if (!(sb->s_flags & MS_RDONLY)) - sync_inodes_sb(sb, *((unsigned long *)arg)); + sync_inodes_sb(sb); } static void sync_fs_one_sb(struct super_block *sb, void *arg) @@ -104,10 +102,9 @@ SYSCALL_DEFINE0(sync) { int nowait = 0, wait = 1; - unsigned long start = jiffies; wakeup_flusher_threads(0, WB_REASON_SYNC); - iterate_supers(sync_inodes_one_sb, &start); + iterate_supers(sync_inodes_one_sb, NULL); iterate_supers(sync_fs_one_sb, &nowait); iterate_supers(sync_fs_one_sb, &wait); iterate_bdevs(fdatawrite_one_bdev, NULL); --- linux-3.13.0.orig/fs/internal.h +++ linux-3.13.0/fs/internal.h @@ -42,7 +42,6 @@ /* * namei.c */ -extern int __inode_permission(struct inode *, int); extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *); extern int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct path *); @@ -135,12 +134,6 @@ extern int rw_verify_area(int, struct file *, const loff_t *, size_t); /* - * splice.c - */ -extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, - loff_t *opos, size_t len, unsigned int flags); - -/* * pipe.c */ extern const struct file_operations pipefifo_fops; --- linux-3.13.0.orig/fs/buffer.c +++ linux-3.13.0/fs/buffer.c @@ -654,14 +654,16 @@ static void __set_page_dirty(struct page *page, struct address_space *mapping, int warn) { - spin_lock_irq(&mapping->tree_lock); + unsigned long flags; + + spin_lock_irqsave(&mapping->tree_lock, flags); if (page->mapping) { /* Race with truncate? */ WARN_ON_ONCE(warn && !PageUptodate(page)); account_page_dirtied(page, mapping); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } - spin_unlock_irq(&mapping->tree_lock); + spin_unlock_irqrestore(&mapping->tree_lock, flags); __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } @@ -2446,7 +2448,7 @@ * Update file times before taking page lock. We may end up failing the * fault so this update may be superfluous but who really cares... */ - file_update_time(vma->vm_file); + vma_file_update_time(vma); ret = __block_page_mkwrite(vma, vmf, get_block); sb_end_pagefault(sb); --- linux-3.13.0.orig/fs/dcache.c +++ linux-3.13.0/fs/dcache.c @@ -3135,7 +3135,6 @@ read_seqbegin_or_lock(&rename_lock, &seq); while (!IS_ROOT(dentry)) { struct dentry *parent = dentry->d_parent; - int error; prefetch(parent); error = prepend_name(&end, &len, &dentry->d_name); --- linux-3.13.0.orig/fs/namei.c +++ linux-3.13.0/fs/namei.c @@ -402,6 +402,7 @@ return security_inode_permission(inode, mask); } +EXPORT_SYMBOL(__inode_permission); /** * sb_permission - Check superblock-level permissions @@ -689,8 +690,8 @@ path_put(link); } -int sysctl_protected_symlinks __read_mostly = 0; -int sysctl_protected_hardlinks __read_mostly = 0; +int sysctl_protected_symlinks __read_mostly = 1; +int sysctl_protected_hardlinks __read_mostly = 1; /** * may_follow_link - Check symlink following for unsafe situations @@ -3027,9 +3028,12 @@ error = may_open(&nd->path, acc_mode, open_flag); if (error) goto out; - file->f_path.mnt = nd->path.mnt; - error = finish_open(file, nd->path.dentry, NULL, opened); - if (error) { + + BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ + error = vfs_open(&nd->path, file, current_cred()); + if (!error) { + *opened |= FILE_OPENED; + } else { if (error == -EOPENSTALE) goto stale_open; goto out; @@ -3945,10 +3949,13 @@ done_path_create(&new_path, new_dentry); if (delegated_inode) { error = break_deleg_wait(&delegated_inode); - if (!error) + if (!error) { + path_put(&old_path); goto retry; + } } if (retry_estale(error, how)) { + path_put(&old_path); how |= LOOKUP_REVAL; goto retry; } --- linux-3.13.0.orig/fs/exec.c +++ linux-3.13.0/fs/exec.c @@ -56,6 +56,8 @@ #include #include +#include + #include #include #include @@ -774,6 +776,8 @@ fsnotify_open(file); + trace_open_exec(name); + err = deny_write_access(file); if (err) goto exit; --- linux-3.13.0.orig/fs/bio-integrity.c +++ linux-3.13.0/fs/bio-integrity.c @@ -114,6 +114,14 @@ } EXPORT_SYMBOL(bio_integrity_free); +static inline unsigned int bip_integrity_vecs(struct bio_integrity_payload *bip) +{ + if (bip->bip_slab == BIO_POOL_NONE) + return BIP_INLINE_VECS; + + return bvec_nr_vecs(bip->bip_slab); +} + /** * bio_integrity_add_page - Attach integrity metadata * @bio: bio to update @@ -129,7 +137,7 @@ struct bio_integrity_payload *bip = bio->bi_integrity; struct bio_vec *iv; - if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_slab)) { + if (bip->bip_vcnt >= bip_integrity_vecs(bip)) { printk(KERN_ERR "%s: bip_vec full\n", __func__); return 0; } @@ -450,7 +458,7 @@ bix.disk_name = bio->bi_bdev->bd_disk->disk_name; bix.sector_size = bi->sector_size; - bio_for_each_segment(bv, bio, i) { + bio_for_each_segment_all(bv, bio, i) { void *kaddr = kmap_atomic(bv->bv_page); bix.data_buf = kaddr + bv->bv_offset; bix.data_size = bv->bv_len; --- linux-3.13.0.orig/fs/splice.c +++ linux-3.13.0/fs/splice.c @@ -555,6 +555,24 @@ .get = generic_pipe_buf_get, }; +static int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) +{ + return 1; +} + +/* Pipe buffer operations for a socket and similar. */ +const struct pipe_buf_operations nosteal_pipe_buf_ops = { + .can_merge = 0, + .map = generic_pipe_buf_map, + .unmap = generic_pipe_buf_unmap, + .confirm = generic_pipe_buf_confirm, + .release = generic_pipe_buf_release, + .steal = generic_pipe_buf_nosteal, + .get = generic_pipe_buf_get, +}; +EXPORT_SYMBOL(nosteal_pipe_buf_ops); + static ssize_t kernel_readv(struct file *file, const struct iovec *vec, unsigned long vlen, loff_t offset) { @@ -1093,8 +1111,8 @@ /* * Attempt to initiate a splice from pipe to file. */ -static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags) +long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) { ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); @@ -1106,13 +1124,14 @@ return splice_write(pipe, out, ppos, len, flags); } +EXPORT_SYMBOL(do_splice_from); /* * Attempt to initiate a splice from a file to a pipe. */ -static long do_splice_to(struct file *in, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) +long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) { ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); @@ -1132,6 +1151,7 @@ return splice_read(in, ppos, pipe, len, flags); } +EXPORT_SYMBOL(do_splice_to); /** * splice_direct_to_actor - splices data directly between two non-pipes @@ -1309,6 +1329,7 @@ return ret; } +EXPORT_SYMBOL(do_splice_direct); static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, struct pipe_inode_info *opipe, --- linux-3.13.0.orig/fs/Makefile +++ linux-3.13.0/fs/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_AUTOFS4_FS) += autofs4/ obj-$(CONFIG_ADFS_FS) += adfs/ obj-$(CONFIG_FUSE_FS) += fuse/ +obj-$(CONFIG_OVERLAYFS_FS) += overlayfs/ obj-$(CONFIG_UDF_FS) += udf/ obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ obj-$(CONFIG_OMFS_FS) += omfs/ --- linux-3.13.0.orig/fs/namespace.c +++ linux-3.13.0/fs/namespace.c @@ -425,6 +425,7 @@ mnt_dec_writers(real_mount(mnt)); preempt_enable(); } +EXPORT_SYMBOL_GPL(__mnt_drop_write); /** * mnt_drop_write - give up write access to a mount @@ -1495,6 +1496,33 @@ namespace_unlock(); } +/** + * clone_private_mount - create a private clone of a path + * + * This creates a new vfsmount, which will be the clone of @path. The new will + * not be attached anywhere in the namespace and will be private (i.e. changes + * to the originating mount won't be propagated into this). + * + * Release with mntput(). + */ +struct vfsmount *clone_private_mount(struct path *path) +{ + struct mount *old_mnt = real_mount(path->mnt); + struct mount *new_mnt; + + if (IS_MNT_UNBINDABLE(old_mnt)) + return ERR_PTR(-EINVAL); + + down_read(&namespace_sem); + new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); + up_read(&namespace_sem); + if (IS_ERR(new_mnt)) + return ERR_CAST(new_mnt); + + return &new_mnt->mnt; +} +EXPORT_SYMBOL_GPL(clone_private_mount); + int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, struct vfsmount *root) { @@ -1509,6 +1537,7 @@ } return 0; } +EXPORT_SYMBOL(iterate_mounts); static void cleanup_group_ids(struct mount *mnt, struct mount *end) { --- linux-3.13.0.orig/fs/mount.h +++ linux-3.13.0/fs/mount.h @@ -74,7 +74,7 @@ static inline int is_mounted(struct vfsmount *mnt) { /* neither detached nor internal? */ - return !IS_ERR_OR_NULL(real_mount(mnt)); + return !IS_ERR_OR_NULL(real_mount(mnt)->mnt_ns); } extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *); --- linux-3.13.0.orig/fs/fs-writeback.c +++ linux-3.13.0/fs/fs-writeback.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "internal.h" /* @@ -40,18 +41,13 @@ struct wb_writeback_work { long nr_pages; struct super_block *sb; - /* - * Write only inodes dirtied before this time. Don't forget to set - * older_than_this_is_set when you set this. - */ - unsigned long older_than_this; + unsigned long *older_than_this; enum writeback_sync_modes sync_mode; unsigned int tagged_writepages:1; unsigned int for_kupdate:1; unsigned int range_cyclic:1; unsigned int for_background:1; unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ - unsigned int older_than_this_is_set:1; enum wb_reason reason; /* why was writeback initiated? */ struct list_head list; /* pending work list */ @@ -252,10 +248,10 @@ int do_sb_sort = 0; int moved = 0; - WARN_ON_ONCE(!work->older_than_this_is_set); while (!list_empty(delaying_queue)) { inode = wb_inode(delaying_queue->prev); - if (inode_dirtied_after(inode, work->older_than_this)) + if (work->older_than_this && + inode_dirtied_after(inode, *work->older_than_this)) break; list_move(&inode->i_wb_list, &tmp); moved++; @@ -742,8 +738,6 @@ .sync_mode = WB_SYNC_NONE, .range_cyclic = 1, .reason = reason, - .older_than_this = jiffies, - .older_than_this_is_set = 1, }; spin_lock(&wb->list_lock); @@ -802,13 +796,12 @@ { unsigned long wb_start = jiffies; long nr_pages = work->nr_pages; + unsigned long oldest_jif; struct inode *inode; long progress; - if (!work->older_than_this_is_set) { - work->older_than_this = jiffies; - work->older_than_this_is_set = 1; - } + oldest_jif = jiffies; + work->older_than_this = &oldest_jif; spin_lock(&wb->list_lock); for (;;) { @@ -842,10 +835,10 @@ * safe. */ if (work->for_kupdate) { - work->older_than_this = jiffies - + oldest_jif = jiffies - msecs_to_jiffies(dirty_expire_interval * 10); } else if (work->for_background) - work->older_than_this = jiffies; + oldest_jif = jiffies; trace_writeback_start(wb->bdi, work); if (list_empty(&wb->b_io)) @@ -1149,6 +1142,8 @@ if ((inode->i_state & flags) == flags) return; + trace_dirty_inode(inode, current); + if (unlikely(block_dump)) block_dump___mark_inode_dirty(inode); @@ -1357,21 +1352,18 @@ /** * sync_inodes_sb - sync sb inode pages - * @sb: the superblock - * @older_than_this: timestamp + * @sb: the superblock * * This function writes and waits on any dirty inode belonging to this - * superblock that has been dirtied before given timestamp. + * super_block. */ -void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this) +void sync_inodes_sb(struct super_block *sb) { DECLARE_COMPLETION_ONSTACK(done); struct wb_writeback_work work = { .sb = sb, .sync_mode = WB_SYNC_ALL, .nr_pages = LONG_MAX, - .older_than_this = older_than_this, - .older_than_this_is_set = 1, .range_cyclic = 0, .done = &done, .reason = WB_REASON_SYNC, --- linux-3.13.0.orig/fs/Kconfig +++ linux-3.13.0/fs/Kconfig @@ -67,6 +67,7 @@ source "fs/autofs4/Kconfig" source "fs/fuse/Kconfig" +source "fs/overlayfs/Kconfig" config GENERIC_ACL bool --- linux-3.13.0.orig/fs/file.c +++ linux-3.13.0/fs/file.c @@ -34,7 +34,7 @@ * vmalloc() if the allocation size will be considered "large" by the VM. */ if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { - void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN); + void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY); if (data != NULL) return data; } --- linux-3.13.0.orig/fs/inode.c +++ linux-3.13.0/fs/inode.c @@ -57,6 +57,7 @@ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock); +EXPORT_SYMBOL(inode_sb_list_lock); /* * Empty aops. Can be used for the cases where the user does not @@ -1497,7 +1498,7 @@ * This does the actual work of updating an inodes time or version. Must have * had called mnt_want_write() before calling this. */ -static int update_time(struct inode *inode, struct timespec *time, int flags) +int update_time(struct inode *inode, struct timespec *time, int flags) { if (inode->i_op->update_time) return inode->i_op->update_time(inode, time, flags); @@ -1513,6 +1514,7 @@ mark_inode_dirty_sync(inode); return 0; } +EXPORT_SYMBOL(update_time); /** * touch_atime - update the access time @@ -1899,3 +1901,7 @@ wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); } EXPORT_SYMBOL(inode_dio_done); + +#define CREATE_TRACE_POINTS +#include + --- linux-3.13.0.orig/fs/attr.c +++ linux-3.13.0/fs/attr.c @@ -202,11 +202,6 @@ return -EPERM; } - if ((ia_valid & ATTR_SIZE) && IS_I_VERSION(inode)) { - if (attr->ia_size != inode->i_size) - inode_inc_iversion(inode); - } - if ((ia_valid & ATTR_MODE)) { umode_t amode = attr->ia_mode; /* Flag setting protected by i_mutex */ --- linux-3.13.0.orig/fs/open.c +++ linux-3.13.0/fs/open.c @@ -34,6 +34,9 @@ #include "internal.h" +#define CREATE_TRACE_POINTS +#include + int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp) { @@ -62,6 +65,7 @@ mutex_unlock(&dentry->d_inode->i_mutex); return ret; } +EXPORT_SYMBOL(do_truncate); long vfs_truncate(struct path *path, loff_t length) { @@ -830,8 +834,7 @@ f = get_empty_filp(); if (!IS_ERR(f)) { f->f_flags = flags; - f->f_path = *path; - error = do_dentry_open(f, NULL, cred); + error = vfs_open(path, f, cred); if (!error) { /* from now on we need fput() to dispose of f */ error = open_check_o_direct(f); @@ -848,6 +851,26 @@ } EXPORT_SYMBOL(dentry_open); +/** + * vfs_open - open the file at the given path + * @path: path to open + * @filp: newly allocated file with f_flag initialized + * @cred: credentials to use + */ +int vfs_open(const struct path *path, struct file *filp, + const struct cred *cred) +{ + struct inode *inode = path->dentry->d_inode; + + if (inode->i_op->dentry_open) + return inode->i_op->dentry_open(path->dentry, filp, cred); + else { + filp->f_path = *path; + return do_dentry_open(filp, NULL, cred); + } +} +EXPORT_SYMBOL(vfs_open); + static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) { int lookup_flags = 0; @@ -990,6 +1013,7 @@ } else { fsnotify_open(f); fd_install(fd, f); + trace_do_sys_open(tmp->name, flags, mode); } } putname(tmp); --- linux-3.13.0.orig/fs/read_write.c +++ linux-3.13.0/fs/read_write.c @@ -968,9 +968,9 @@ return ret; } -COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, +COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd, const struct compat_iovec __user *,vec, - unsigned long, vlen) + compat_ulong_t, vlen) { struct fd f = fdget(fd); ssize_t ret; @@ -1005,9 +1005,9 @@ return ret; } -COMPAT_SYSCALL_DEFINE5(preadv, unsigned long, fd, +COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd, const struct compat_iovec __user *,vec, - unsigned long, vlen, u32, pos_low, u32, pos_high) + compat_ulong_t, vlen, u32, pos_low, u32, pos_high) { loff_t pos = ((loff_t)pos_high << 32) | pos_low; return compat_sys_preadv64(fd, vec, vlen, pos); @@ -1035,9 +1035,9 @@ return ret; } -COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd, +COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd, const struct compat_iovec __user *, vec, - unsigned long, vlen) + compat_ulong_t, vlen) { struct fd f = fdget(fd); ssize_t ret; @@ -1072,9 +1072,9 @@ return ret; } -COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd, +COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd, const struct compat_iovec __user *,vec, - unsigned long, vlen, u32, pos_low, u32, pos_high) + compat_ulong_t, vlen, u32, pos_low, u32, pos_high) { loff_t pos = ((loff_t)pos_high << 32) | pos_low; return compat_sys_pwritev64(fd, vec, vlen, pos); --- linux-3.13.0.orig/fs/dcookies.c +++ linux-3.13.0/fs/dcookies.c @@ -204,7 +204,7 @@ } #ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, size_t, len) +COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len) { #ifdef __BIG_ENDIAN return sys_lookup_dcookie(((u64)w0 << 32) | w1, buf, len); --- linux-3.13.0.orig/fs/btrfs/ctree.c +++ linux-3.13.0/fs/btrfs/ctree.c @@ -39,7 +39,7 @@ struct extent_buffer *src_buf); static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, int level, int slot); -static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, +static int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb); static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); @@ -475,6 +475,8 @@ * the index is the shifted logical of the *new* root node for root replace * operations, or the shifted logical of the affected block for all other * operations. + * + * Note: must be called with write lock (tree_mod_log_write_lock). */ static noinline int __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm) @@ -483,24 +485,9 @@ struct rb_node **new; struct rb_node *parent = NULL; struct tree_mod_elem *cur; - int ret = 0; BUG_ON(!tm); - tree_mod_log_write_lock(fs_info); - if (list_empty(&fs_info->tree_mod_seq_list)) { - tree_mod_log_write_unlock(fs_info); - /* - * Ok we no longer care about logging modifications, free up tm - * and return 0. Any callers shouldn't be using tm after - * calling tree_mod_log_insert, but if they do we can just - * change this to return a special error code to let the callers - * do their own thing. - */ - kfree(tm); - return 0; - } - spin_lock(&fs_info->tree_mod_seq_lock); tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info); spin_unlock(&fs_info->tree_mod_seq_lock); @@ -518,18 +505,13 @@ new = &((*new)->rb_left); else if (cur->seq > tm->seq) new = &((*new)->rb_right); - else { - ret = -EEXIST; - kfree(tm); - goto out; - } + else + return -EEXIST; } rb_link_node(&tm->node, parent, new); rb_insert_color(&tm->node, tm_root); -out: - tree_mod_log_write_unlock(fs_info); - return ret; + return 0; } /* @@ -545,19 +527,38 @@ return 1; if (eb && btrfs_header_level(eb) == 0) return 1; + + tree_mod_log_write_lock(fs_info); + if (list_empty(&(fs_info)->tree_mod_seq_list)) { + tree_mod_log_write_unlock(fs_info); + return 1; + } + return 0; } -static inline int -__tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, int slot, - enum mod_log_op op, gfp_t flags) +/* Similar to tree_mod_dont_log, but doesn't acquire any locks. */ +static inline int tree_mod_need_log(const struct btrfs_fs_info *fs_info, + struct extent_buffer *eb) +{ + smp_mb(); + if (list_empty(&(fs_info)->tree_mod_seq_list)) + return 0; + if (eb && btrfs_header_level(eb) == 0) + return 0; + + return 1; +} + +static struct tree_mod_elem * +alloc_tree_mod_elem(struct extent_buffer *eb, int slot, + enum mod_log_op op, gfp_t flags) { struct tree_mod_elem *tm; tm = kzalloc(sizeof(*tm), flags); if (!tm) - return -ENOMEM; + return NULL; tm->index = eb->start >> PAGE_CACHE_SHIFT; if (op != MOD_LOG_KEY_ADD) { @@ -567,8 +568,9 @@ tm->op = op; tm->slot = slot; tm->generation = btrfs_node_ptr_generation(eb, slot); + RB_CLEAR_NODE(&tm->node); - return __tree_mod_log_insert(fs_info, tm); + return tm; } static noinline int @@ -576,10 +578,27 @@ struct extent_buffer *eb, int slot, enum mod_log_op op, gfp_t flags) { - if (tree_mod_dont_log(fs_info, eb)) + struct tree_mod_elem *tm; + int ret; + + if (!tree_mod_need_log(fs_info, eb)) + return 0; + + tm = alloc_tree_mod_elem(eb, slot, op, flags); + if (!tm) + return -ENOMEM; + + if (tree_mod_dont_log(fs_info, eb)) { + kfree(tm); return 0; + } - return __tree_mod_log_insert_key(fs_info, eb, slot, op, flags); + ret = __tree_mod_log_insert(fs_info, tm); + tree_mod_log_write_unlock(fs_info); + if (ret) + kfree(tm); + + return ret; } static noinline int @@ -587,53 +606,95 @@ struct extent_buffer *eb, int dst_slot, int src_slot, int nr_items, gfp_t flags) { - struct tree_mod_elem *tm; - int ret; + struct tree_mod_elem *tm = NULL; + struct tree_mod_elem **tm_list = NULL; + int ret = 0; int i; + int locked = 0; - if (tree_mod_dont_log(fs_info, eb)) + if (!tree_mod_need_log(fs_info, eb)) return 0; + tm_list = kzalloc(nr_items * sizeof(struct tree_mod_elem *), flags); + if (!tm_list) + return -ENOMEM; + + tm = kzalloc(sizeof(*tm), flags); + if (!tm) { + ret = -ENOMEM; + goto free_tms; + } + + tm->index = eb->start >> PAGE_CACHE_SHIFT; + tm->slot = src_slot; + tm->move.dst_slot = dst_slot; + tm->move.nr_items = nr_items; + tm->op = MOD_LOG_MOVE_KEYS; + + for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { + tm_list[i] = alloc_tree_mod_elem(eb, i + dst_slot, + MOD_LOG_KEY_REMOVE_WHILE_MOVING, flags); + if (!tm_list[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + + if (tree_mod_dont_log(fs_info, eb)) + goto free_tms; + locked = 1; + /* * When we override something during the move, we log these removals. * This can only happen when we move towards the beginning of the * buffer, i.e. dst_slot < src_slot. */ for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { - ret = __tree_mod_log_insert_key(fs_info, eb, i + dst_slot, - MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS); - BUG_ON(ret < 0); + ret = __tree_mod_log_insert(fs_info, tm_list[i]); + if (ret) + goto free_tms; } - tm = kzalloc(sizeof(*tm), flags); - if (!tm) - return -ENOMEM; + ret = __tree_mod_log_insert(fs_info, tm); + if (ret) + goto free_tms; + tree_mod_log_write_unlock(fs_info); + kfree(tm_list); - tm->index = eb->start >> PAGE_CACHE_SHIFT; - tm->slot = src_slot; - tm->move.dst_slot = dst_slot; - tm->move.nr_items = nr_items; - tm->op = MOD_LOG_MOVE_KEYS; + return 0; +free_tms: + for (i = 0; i < nr_items; i++) { + if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) + rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log); + kfree(tm_list[i]); + } + if (locked) + tree_mod_log_write_unlock(fs_info); + kfree(tm_list); + kfree(tm); - return __tree_mod_log_insert(fs_info, tm); + return ret; } -static inline void -__tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) +static inline int +__tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, + struct tree_mod_elem **tm_list, + int nritems) { - int i; - u32 nritems; + int i, j; int ret; - if (btrfs_header_level(eb) == 0) - return; - - nritems = btrfs_header_nritems(eb); for (i = nritems - 1; i >= 0; i--) { - ret = __tree_mod_log_insert_key(fs_info, eb, i, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); - BUG_ON(ret < 0); + ret = __tree_mod_log_insert(fs_info, tm_list[i]); + if (ret) { + for (j = nritems - 1; j > i; j--) + rb_erase(&tm_list[j]->node, + &fs_info->tree_mod_log); + return ret; + } } + + return 0; } static noinline int @@ -642,17 +703,38 @@ struct extent_buffer *new_root, gfp_t flags, int log_removal) { - struct tree_mod_elem *tm; + struct tree_mod_elem *tm = NULL; + struct tree_mod_elem **tm_list = NULL; + int nritems = 0; + int ret = 0; + int i; - if (tree_mod_dont_log(fs_info, NULL)) + if (!tree_mod_need_log(fs_info, NULL)) return 0; - if (log_removal) - __tree_mod_log_free_eb(fs_info, old_root); + if (log_removal && btrfs_header_level(old_root) > 0) { + nritems = btrfs_header_nritems(old_root); + tm_list = kzalloc(nritems * sizeof(struct tree_mod_elem *), + flags); + if (!tm_list) { + ret = -ENOMEM; + goto free_tms; + } + for (i = 0; i < nritems; i++) { + tm_list[i] = alloc_tree_mod_elem(old_root, i, + MOD_LOG_KEY_REMOVE_WHILE_FREEING, flags); + if (!tm_list[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + } tm = kzalloc(sizeof(*tm), flags); - if (!tm) - return -ENOMEM; + if (!tm) { + ret = -ENOMEM; + goto free_tms; + } tm->index = new_root->start >> PAGE_CACHE_SHIFT; tm->old_root.logical = old_root->start; @@ -660,7 +742,30 @@ tm->generation = btrfs_header_generation(old_root); tm->op = MOD_LOG_ROOT_REPLACE; - return __tree_mod_log_insert(fs_info, tm); + if (tree_mod_dont_log(fs_info, NULL)) + goto free_tms; + + if (tm_list) + ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems); + if (!ret) + ret = __tree_mod_log_insert(fs_info, tm); + + tree_mod_log_write_unlock(fs_info); + if (ret) + goto free_tms; + kfree(tm_list); + + return ret; + +free_tms: + if (tm_list) { + for (i = 0; i < nritems; i++) + kfree(tm_list[i]); + kfree(tm_list); + } + kfree(tm); + + return ret; } static struct tree_mod_elem * @@ -729,31 +834,75 @@ return __tree_mod_log_search(fs_info, start, min_seq, 0); } -static noinline void +static noinline int tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, struct extent_buffer *src, unsigned long dst_offset, unsigned long src_offset, int nr_items) { - int ret; + int ret = 0; + struct tree_mod_elem **tm_list = NULL; + struct tree_mod_elem **tm_list_add, **tm_list_rem; int i; + int locked = 0; - if (tree_mod_dont_log(fs_info, NULL)) - return; + if (!tree_mod_need_log(fs_info, NULL)) + return 0; if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0) - return; + return 0; + + tm_list = kzalloc(nr_items * 2 * sizeof(struct tree_mod_elem *), + GFP_NOFS); + if (!tm_list) + return -ENOMEM; + tm_list_add = tm_list; + tm_list_rem = tm_list + nr_items; for (i = 0; i < nr_items; i++) { - ret = __tree_mod_log_insert_key(fs_info, src, - i + src_offset, - MOD_LOG_KEY_REMOVE, GFP_NOFS); - BUG_ON(ret < 0); - ret = __tree_mod_log_insert_key(fs_info, dst, - i + dst_offset, - MOD_LOG_KEY_ADD, - GFP_NOFS); - BUG_ON(ret < 0); + tm_list_rem[i] = alloc_tree_mod_elem(src, i + src_offset, + MOD_LOG_KEY_REMOVE, GFP_NOFS); + if (!tm_list_rem[i]) { + ret = -ENOMEM; + goto free_tms; + } + + tm_list_add[i] = alloc_tree_mod_elem(dst, i + dst_offset, + MOD_LOG_KEY_ADD, GFP_NOFS); + if (!tm_list_add[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + + if (tree_mod_dont_log(fs_info, NULL)) + goto free_tms; + locked = 1; + + for (i = 0; i < nr_items; i++) { + ret = __tree_mod_log_insert(fs_info, tm_list_rem[i]); + if (ret) + goto free_tms; + ret = __tree_mod_log_insert(fs_info, tm_list_add[i]); + if (ret) + goto free_tms; } + + tree_mod_log_write_unlock(fs_info); + kfree(tm_list); + + return 0; + +free_tms: + for (i = 0; i < nr_items * 2; i++) { + if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) + rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log); + kfree(tm_list[i]); + } + if (locked) + tree_mod_log_write_unlock(fs_info); + kfree(tm_list); + + return ret; } static inline void @@ -772,18 +921,58 @@ { int ret; - ret = __tree_mod_log_insert_key(fs_info, eb, slot, + ret = tree_mod_log_insert_key(fs_info, eb, slot, MOD_LOG_KEY_REPLACE, atomic ? GFP_ATOMIC : GFP_NOFS); BUG_ON(ret < 0); } -static noinline void +static noinline int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) { + struct tree_mod_elem **tm_list = NULL; + int nritems = 0; + int i; + int ret = 0; + + if (btrfs_header_level(eb) == 0) + return 0; + + if (!tree_mod_need_log(fs_info, NULL)) + return 0; + + nritems = btrfs_header_nritems(eb); + tm_list = kzalloc(nritems * sizeof(struct tree_mod_elem *), + GFP_NOFS); + if (!tm_list) + return -ENOMEM; + + for (i = 0; i < nritems; i++) { + tm_list[i] = alloc_tree_mod_elem(eb, i, + MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); + if (!tm_list[i]) { + ret = -ENOMEM; + goto free_tms; + } + } + if (tree_mod_dont_log(fs_info, eb)) - return; - __tree_mod_log_free_eb(fs_info, eb); + goto free_tms; + + ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems); + tree_mod_log_write_unlock(fs_info); + if (ret) + goto free_tms; + kfree(tm_list); + + return 0; + +free_tms: + for (i = 0; i < nritems; i++) + kfree(tm_list[i]); + kfree(tm_list); + + return ret; } static noinline void @@ -1041,8 +1230,13 @@ btrfs_set_node_ptr_generation(parent, parent_slot, trans->transid); btrfs_mark_buffer_dirty(parent); - if (last_ref) - tree_mod_log_free_eb(root->fs_info, buf); + if (last_ref) { + ret = tree_mod_log_free_eb(root->fs_info, buf); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + return ret; + } + } btrfs_free_tree_block(trans, root, buf, parent_start, last_ref); } @@ -3022,8 +3216,12 @@ } else push_items = min(src_nritems - 8, push_items); - tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0, - push_items); + ret = tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0, + push_items); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + return ret; + } copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(dst_nritems), btrfs_node_key_ptr_offset(0), @@ -3093,8 +3291,12 @@ (dst_nritems) * sizeof(struct btrfs_key_ptr)); - tree_mod_log_eb_copy(root->fs_info, dst, src, 0, - src_nritems - push_items, push_items); + ret = tree_mod_log_eb_copy(root->fs_info, dst, src, 0, + src_nritems - push_items, push_items); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + return ret; + } copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(src_nritems - push_items), @@ -3295,7 +3497,12 @@ btrfs_header_chunk_tree_uuid(split), BTRFS_UUID_SIZE); - tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid); + ret = tree_mod_log_eb_copy(root->fs_info, split, c, 0, + mid, c_nritems - mid); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + return ret; + } copy_extent_buffer(split, c, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(mid), --- linux-3.13.0.orig/fs/btrfs/extent-tree.c +++ linux-3.13.0/fs/btrfs/extent-tree.c @@ -7779,7 +7779,7 @@ */ if (!for_reloc && root_dropped == false) btrfs_add_dead_root(root); - if (err) + if (err && err != -EAGAIN) btrfs_std_error(root->fs_info, err); return err; } --- linux-3.13.0.orig/fs/btrfs/compression.c +++ linux-3.13.0/fs/btrfs/compression.c @@ -1011,6 +1011,8 @@ bytes = min(bytes, working_bytes); kaddr = kmap_atomic(page_out); memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); + if (*pg_index == (vcnt - 1) && *pg_offset == 0) + memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); kunmap_atomic(kaddr); flush_dcache_page(page_out); --- linux-3.13.0.orig/fs/btrfs/ioctl.c +++ linux-3.13.0/fs/btrfs/ioctl.c @@ -1545,6 +1545,12 @@ printk(KERN_INFO "btrfs: Snapshot src from " "another FS\n"); ret = -EINVAL; + } else if (!inode_owner_or_capable(src_inode)) { + /* + * Subvolume creation is not restricted, but snapshots + * are limited to own subvolumes only + */ + ret = -EPERM; } else { ret = btrfs_mksubvol(&file->f_path, name, namelen, BTRFS_I(src_inode)->root, --- linux-3.13.0.orig/fs/btrfs/inode.c +++ linux-3.13.0/fs/btrfs/inode.c @@ -60,7 +60,7 @@ #include "hash.h" struct btrfs_iget_args { - u64 ino; + struct btrfs_key *location; struct btrfs_root *root; }; @@ -2610,7 +2610,7 @@ EXTENT_DEFRAG, 1, cached_state); if (ret) { u64 last_snapshot = btrfs_root_last_snapshot(&root->root_item); - if (last_snapshot >= BTRFS_I(inode)->generation) + if (0 && last_snapshot >= BTRFS_I(inode)->generation) /* the inode is shared */ new = record_old_file_extents(inode, ordered_extent); @@ -4354,8 +4354,12 @@ * these flags set. For all other operations the VFS set these flags * explicitly if it wants a timestamp update. */ - if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) - inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); + if (newsize != oldsize) { + inode_inc_iversion(inode); + if (!(mask & (ATTR_CTIME | ATTR_MTIME))) + inode->i_ctime = inode->i_mtime = + current_fs_time(inode->i_sb); + } if (newsize > oldsize) { truncate_pagecache(inode, newsize); @@ -4818,7 +4822,9 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p) { struct btrfs_iget_args *args = p; - inode->i_ino = args->ino; + inode->i_ino = args->location->objectid; + memcpy(&BTRFS_I(inode)->location, args->location, + sizeof(*args->location)); BTRFS_I(inode)->root = args->root; return 0; } @@ -4826,19 +4832,19 @@ static int btrfs_find_actor(struct inode *inode, void *opaque) { struct btrfs_iget_args *args = opaque; - return args->ino == btrfs_ino(inode) && + return args->location->objectid == BTRFS_I(inode)->location.objectid && args->root == BTRFS_I(inode)->root; } static struct inode *btrfs_iget_locked(struct super_block *s, - u64 objectid, + struct btrfs_key *location, struct btrfs_root *root) { struct inode *inode; struct btrfs_iget_args args; - unsigned long hashval = btrfs_inode_hash(objectid, root); + unsigned long hashval = btrfs_inode_hash(location->objectid, root); - args.ino = objectid; + args.location = location; args.root = root; inode = iget5_locked(s, hashval, btrfs_find_actor, @@ -4855,13 +4861,11 @@ { struct inode *inode; - inode = btrfs_iget_locked(s, location->objectid, root); + inode = btrfs_iget_locked(s, location, root); if (!inode) return ERR_PTR(-ENOMEM); if (inode->i_state & I_NEW) { - BTRFS_I(inode)->root = root; - memcpy(&BTRFS_I(inode)->location, location, sizeof(*location)); btrfs_read_locked_inode(inode); if (!is_bad_inode(inode)) { inode_tree_add(inode); --- linux-3.13.0.orig/fs/xfs/xfs_super.c +++ linux-3.13.0/fs/xfs/xfs_super.c @@ -913,7 +913,7 @@ struct super_block *sb = mp->m_super; if (down_read_trylock(&sb->s_umount)) { - sync_inodes_sb(sb, jiffies); + sync_inodes_sb(sb); up_read(&sb->s_umount); } } --- linux-3.13.0.orig/fs/ext4/ext4.h +++ linux-3.13.0/fs/ext4/ext4.h @@ -771,6 +771,8 @@ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \ (einode)->xtime.tv_sec = \ (signed)le32_to_cpu((raw_inode)->xtime); \ + else \ + (einode)->xtime.tv_sec = 0; \ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \ ext4_decode_extra_time(&(einode)->xtime, \ raw_inode->xtime ## _extra); \ --- linux-3.13.0.orig/fs/ext4/inline.c +++ linux-3.13.0/fs/ext4/inline.c @@ -1924,9 +1924,11 @@ } /* Clear the content within i_blocks. */ - if (i_size < EXT4_MIN_INLINE_DATA_SIZE) - memset(ext4_raw_inode(&is.iloc)->i_block + i_size, 0, - EXT4_MIN_INLINE_DATA_SIZE - i_size); + if (i_size < EXT4_MIN_INLINE_DATA_SIZE) { + void *p = (void *) ext4_raw_inode(&is.iloc)->i_block; + memset(p + i_size, 0, + EXT4_MIN_INLINE_DATA_SIZE - i_size); + } EXT4_I(inode)->i_inline_size = i_size < EXT4_MIN_INLINE_DATA_SIZE ? --- linux-3.13.0.orig/fs/ext4/resize.c +++ linux-3.13.0/fs/ext4/resize.c @@ -243,6 +243,7 @@ ext4_group_t group; ext4_group_t last_group; unsigned overhead; + __u16 uninit_mask = (flexbg_size > 1) ? ~EXT4_BG_BLOCK_UNINIT : ~0; BUG_ON(flex_gd->count == 0 || group_data == NULL); @@ -266,7 +267,7 @@ src_group++; for (; src_group <= last_group; src_group++) { overhead = ext4_group_overhead_blocks(sb, src_group); - if (overhead != 0) + if (overhead == 0) last_blk += group_data[src_group - group].blocks_count; else break; @@ -280,8 +281,7 @@ group = ext4_get_group_number(sb, start_blk - 1); group -= group_data[0].group; group_data[group].free_blocks_count--; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + flex_gd->bg_flags[group] &= uninit_mask; } /* Allocate inode bitmaps */ @@ -292,22 +292,30 @@ group = ext4_get_group_number(sb, start_blk - 1); group -= group_data[0].group; group_data[group].free_blocks_count--; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + flex_gd->bg_flags[group] &= uninit_mask; } /* Allocate inode tables */ for (; it_index < flex_gd->count; it_index++) { - if (start_blk + EXT4_SB(sb)->s_itb_per_group > last_blk) + unsigned int itb = EXT4_SB(sb)->s_itb_per_group; + ext4_fsblk_t next_group_start; + + if (start_blk + itb > last_blk) goto next_group; group_data[it_index].inode_table = start_blk; - group = ext4_get_group_number(sb, start_blk - 1); + group = ext4_get_group_number(sb, start_blk); + next_group_start = ext4_group_first_block_no(sb, group + 1); group -= group_data[0].group; - group_data[group].free_blocks_count -= - EXT4_SB(sb)->s_itb_per_group; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + if (start_blk + itb > next_group_start) { + flex_gd->bg_flags[group + 1] &= uninit_mask; + overhead = start_blk + itb - next_group_start; + group_data[group + 1].free_blocks_count -= overhead; + itb -= overhead; + } + + group_data[group].free_blocks_count -= itb; + flex_gd->bg_flags[group] &= uninit_mask; start_blk += EXT4_SB(sb)->s_itb_per_group; } @@ -401,7 +409,7 @@ start = ext4_group_first_block_no(sb, group); group -= flex_gd->groups[0].group; - count2 = sb->s_blocksize * 8 - (block - start); + count2 = EXT4_BLOCKS_PER_GROUP(sb) - (block - start); if (count2 > count) count2 = count; @@ -620,7 +628,7 @@ if (err) goto out; count = group_table_count[j]; - start = group_data[i].block_bitmap; + start = (&group_data[i].block_bitmap)[j]; block = start; } --- linux-3.13.0.orig/fs/ext4/ioctl.c +++ linux-3.13.0/fs/ext4/ioctl.c @@ -144,7 +144,7 @@ handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); if (IS_ERR(handle)) { err = -EINVAL; - goto swap_boot_out; + goto journal_err_out; } /* Protect extent tree against block allocations via delalloc */ @@ -202,6 +202,7 @@ ext4_double_up_write_data_sem(inode, inode_bl); +journal_err_out: ext4_inode_resume_unlocked_dio(inode); ext4_inode_resume_unlocked_dio(inode_bl); --- linux-3.13.0.orig/fs/ext4/inode.c +++ linux-3.13.0/fs/ext4/inode.c @@ -4586,6 +4586,10 @@ if (attr->ia_size > sbi->s_bitmap_maxbytes) return -EFBIG; } + + if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size) + inode_inc_iversion(inode); + if (S_ISREG(inode->i_mode) && (attr->ia_size < inode->i_size)) { if (ext4_should_order_data(inode)) { --- linux-3.13.0.orig/fs/ext4/super.c +++ linux-3.13.0/fs/ext4/super.c @@ -3695,16 +3695,22 @@ for (i = 0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; - i = le32_to_cpu(es->s_flags); - if (i & EXT2_FLAGS_UNSIGNED_HASH) - sbi->s_hash_unsigned = 3; - else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { + if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) { + i = le32_to_cpu(es->s_flags); + if (i & EXT2_FLAGS_UNSIGNED_HASH) + sbi->s_hash_unsigned = 3; + else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { #ifdef __CHAR_UNSIGNED__ - es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); - sbi->s_hash_unsigned = 3; + if (!(sb->s_flags & MS_RDONLY)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); + sbi->s_hash_unsigned = 3; #else - es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); + if (!(sb->s_flags & MS_RDONLY)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); #endif + } } /* Handle clustersize */ --- linux-3.13.0.orig/fs/ext4/extents.c +++ linux-3.13.0/fs/ext4/extents.c @@ -3906,6 +3906,7 @@ } else err = ret; map->m_flags |= EXT4_MAP_MAPPED; + map->m_pblk = newblock; if (allocated > map->m_len) allocated = map->m_len; map->m_len = allocated; --- linux-3.13.0.orig/fs/cifs/smb2pdu.c +++ linux-3.13.0/fs/cifs/smb2pdu.c @@ -413,7 +413,9 @@ /* SMB2 only has an extended negflavor */ server->negflavor = CIFS_NEGFLAVOR_EXTENDED; - server->maxBuf = le32_to_cpu(rsp->MaxTransactSize); + /* set it to the maximum buffer size value we can send with 1 credit */ + server->maxBuf = min_t(unsigned int, le32_to_cpu(rsp->MaxTransactSize), + SMB2_MAX_BUFFER_SIZE); server->max_read = le32_to_cpu(rsp->MaxReadSize); server->max_write = le32_to_cpu(rsp->MaxWriteSize); /* BB Do we need to validate the SecurityMode? */ --- linux-3.13.0.orig/fs/cifs/smb1ops.c +++ linux-3.13.0/fs/cifs/smb1ops.c @@ -1011,6 +1011,14 @@ .push_mand_locks = cifs_push_mandatory_locks, .query_mf_symlink = open_query_close_cifs_symlink, .is_read_op = cifs_is_read_op, +#ifdef CONFIG_CIFS_XATTR + .query_all_EAs = CIFSSMBQAllEAs, + .set_EA = CIFSSMBSetEA, +#endif /* CIFS_XATTR */ +#ifdef CONFIG_CIFS_ACL + .get_acl = get_cifs_acl, + .set_acl = set_cifs_acl, +#endif /* CIFS_ACL */ }; struct smb_version_values smb1_values = { --- linux-3.13.0.orig/fs/cifs/cifsglob.h +++ linux-3.13.0/fs/cifs/cifsglob.h @@ -385,6 +385,16 @@ struct cifsFileInfo *target_file, u64 src_off, u64 len, u64 dest_off); int (*validate_negotiate)(const unsigned int, struct cifs_tcon *); + ssize_t (*query_all_EAs)(const unsigned int, struct cifs_tcon *, + const unsigned char *, const unsigned char *, char *, + size_t, const struct nls_table *, int); + int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *, + const char *, const void *, const __u16, + const struct nls_table *, int); + struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *, + const char *, u32 *); + int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, + int); }; struct smb_version_values { --- linux-3.13.0.orig/fs/cifs/smb2ops.c +++ linux-3.13.0/fs/cifs/smb2ops.c @@ -182,11 +182,8 @@ /* start with specified wsize, or default */ wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; wsize = min_t(unsigned int, wsize, server->max_write); - /* - * limit write size to 2 ** 16, because we don't support multicredit - * requests now. - */ - wsize = min_t(unsigned int, wsize, 2 << 15); + /* set it to the maximum buffer size value we can send with 1 credit */ + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); return wsize; } @@ -200,11 +197,8 @@ /* start with specified rsize, or default */ rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; rsize = min_t(unsigned int, rsize, server->max_read); - /* - * limit write size to 2 ** 16, because we don't support multicredit - * requests now. - */ - rsize = min_t(unsigned int, rsize, 2 << 15); + /* set it to the maximum buffer size value we can send with 1 credit */ + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); return rsize; } --- linux-3.13.0.orig/fs/cifs/cifsacl.c +++ linux-3.13.0/fs/cifs/cifsacl.c @@ -1027,15 +1027,30 @@ __u32 secdesclen = 0; struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + struct cifs_tcon *tcon; + + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); cifs_dbg(NOISY, "set ACL from mode for %s\n", path); /* Get the security descriptor */ - pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen); + + if (tcon->ses->server->ops->get_acl == NULL) { + cifs_put_tlink(tlink); + return -EOPNOTSUPP; + } + + pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path, + &secdesclen); if (IS_ERR(pntsd)) { rc = PTR_ERR(pntsd); cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); - goto out; + cifs_put_tlink(tlink); + return rc; } /* @@ -1048,6 +1063,7 @@ pnntsd = kmalloc(secdesclen, GFP_KERNEL); if (!pnntsd) { kfree(pntsd); + cifs_put_tlink(tlink); return -ENOMEM; } @@ -1056,14 +1072,18 @@ cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); + if (tcon->ses->server->ops->set_acl == NULL) + rc = -EOPNOTSUPP; + if (!rc) { /* Set the security descriptor */ - rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag); + rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode, + path, aclflag); cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); } + cifs_put_tlink(tlink); kfree(pnntsd); kfree(pntsd); -out: return rc; } --- linux-3.13.0.orig/fs/cifs/xattr.c +++ linux-3.13.0/fs/cifs/xattr.c @@ -82,9 +82,11 @@ goto remove_ea_exit; ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ - rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL, - (__u16)0, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->set_EA) + rc = pTcon->ses->server->ops->set_EA(xid, pTcon, + full_path, ea_name, NULL, (__u16)0, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } remove_ea_exit: kfree(full_path); @@ -149,18 +151,22 @@ cifs_dbg(FYI, "attempt to set cifs inode metadata\n"); ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ - rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, - (__u16)value_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->set_EA) + rc = pTcon->ses->server->ops->set_EA(xid, pTcon, + full_path, ea_name, ea_value, (__u16)value_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto set_ea_exit; ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ - rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, - (__u16)value_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->set_EA) + rc = pTcon->ses->server->ops->set_EA(xid, pTcon, + full_path, ea_name, ea_value, (__u16)value_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, strlen(CIFS_XATTR_CIFS_ACL)) == 0) { #ifdef CONFIG_CIFS_ACL @@ -170,8 +176,12 @@ rc = -ENOMEM; } else { memcpy(pacl, ea_value, value_size); - rc = set_cifs_acl(pacl, value_size, - direntry->d_inode, full_path, CIFS_ACL_DACL); + if (pTcon->ses->server->ops->set_acl) + rc = pTcon->ses->server->ops->set_acl(pacl, + value_size, direntry->d_inode, + full_path, CIFS_ACL_DACL); + else + rc = -EOPNOTSUPP; if (rc == 0) /* force revalidate of the inode */ CIFS_I(direntry->d_inode)->time = 0; kfree(pacl); @@ -272,17 +282,21 @@ /* revalidate/getattr then populate from inode */ } /* BB add else when above is implemented */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ - rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, - buf_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->query_all_EAs) + rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, + full_path, ea_name, ea_value, buf_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto get_ea_exit; ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ - rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, - buf_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->query_all_EAs) + rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, + full_path, ea_name, ea_value, buf_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { #ifdef CONFIG_CIFS_POSIX @@ -313,8 +327,11 @@ u32 acllen; struct cifs_ntsd *pacl; - pacl = get_cifs_acl(cifs_sb, direntry->d_inode, - full_path, &acllen); + if (pTcon->ses->server->ops->get_acl == NULL) + goto get_ea_exit; /* rc already EOPNOTSUPP */ + + pacl = pTcon->ses->server->ops->get_acl(cifs_sb, + direntry->d_inode, full_path, &acllen); if (IS_ERR(pacl)) { rc = PTR_ERR(pacl); cifs_dbg(VFS, "%s: error %zd getting sec desc\n", @@ -400,11 +417,12 @@ /* if proc/fs/cifs/streamstoxattr is set then search server for EAs or streams to returns as xattrs */ - rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data, - buf_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->query_all_EAs) + rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, + full_path, NULL, data, buf_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); list_ea_exit: kfree(full_path); free_xid(xid); --- linux-3.13.0.orig/fs/cifs/file.c +++ linux-3.13.0/fs/cifs/file.c @@ -2381,7 +2381,7 @@ unsigned long nr_segs, loff_t *poffset) { unsigned long nr_pages, i; - size_t copied, len, cur_len; + size_t bytes, copied, len, cur_len; ssize_t total_written = 0; loff_t offset; struct iov_iter it; @@ -2436,14 +2436,45 @@ save_len = cur_len; for (i = 0; i < nr_pages; i++) { - copied = min_t(const size_t, cur_len, PAGE_SIZE); + bytes = min_t(const size_t, cur_len, PAGE_SIZE); copied = iov_iter_copy_from_user(wdata->pages[i], &it, - 0, copied); + 0, bytes); cur_len -= copied; iov_iter_advance(&it, copied); + /* + * If we didn't copy as much as we expected, then that + * may mean we trod into an unmapped area. Stop copying + * at that point. On the next pass through the big + * loop, we'll likely end up getting a zero-length + * write and bailing out of it. + */ + if (copied < bytes) + break; } cur_len = save_len - cur_len; + /* + * If we have no data to send, then that probably means that + * the copy above failed altogether. That's most likely because + * the address in the iovec was bogus. Set the rc to -EFAULT, + * free anything we allocated and bail out. + */ + if (!cur_len) { + for (i = 0; i < nr_pages; i++) + put_page(wdata->pages[i]); + kfree(wdata); + rc = -EFAULT; + break; + } + + /* + * i + 1 now represents the number of pages we actually used in + * the copy phase above. Bring nr_pages down to that, and free + * any pages that we didn't use. + */ + for ( ; nr_pages > i + 1; nr_pages--) + put_page(wdata->pages[nr_pages - 1]); + wdata->sync_mode = WB_SYNC_ALL; wdata->nr_pages = nr_pages; wdata->offset = (__u64)offset; --- linux-3.13.0.orig/fs/cifs/inode.c +++ linux-3.13.0/fs/cifs/inode.c @@ -518,10 +518,15 @@ return PTR_ERR(tlink); tcon = tlink_tcon(tlink); - rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS", - ea_value, 4 /* size of buf */, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + if (tcon->ses->server->ops->query_all_EAs == NULL) { + cifs_put_tlink(tlink); + return -EOPNOTSUPP; + } + + rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path, + "SETFILEBITS", ea_value, 4 /* size of buf */, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_put_tlink(tlink); if (rc < 0) return (int)rc; --- linux-3.13.0.orig/fs/cifs/smb2glob.h +++ linux-3.13.0/fs/cifs/smb2glob.h @@ -57,4 +57,7 @@ #define SMB2_CMACAES_SIZE (16) #define SMB3_SIGNKEY_SIZE (16) +/* Maximum buffer size value we can send with 1 credit */ +#define SMB2_MAX_BUFFER_SIZE 65536 + #endif /* _SMB2_GLOB_H */ --- linux-3.13.0.orig/fs/notify/mark.c +++ linux-3.13.0/fs/notify/mark.c @@ -109,6 +109,7 @@ mark->free_mark(mark); } } +EXPORT_SYMBOL(fsnotify_put_mark); /* * Any time a mark is getting freed we end up here. @@ -191,6 +192,7 @@ fsnotify_destroy_mark_locked(mark, group); mutex_unlock(&group->mark_mutex); } +EXPORT_SYMBOL(fsnotify_destroy_mark); void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) { @@ -275,6 +277,7 @@ return ret; } +EXPORT_SYMBOL(fsnotify_add_mark); int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, struct inode *inode, struct vfsmount *mnt, int allow_dups) @@ -336,6 +339,7 @@ atomic_set(&mark->refcnt, 1); mark->free_mark = free_mark; } +EXPORT_SYMBOL(fsnotify_init_mark); static int fsnotify_mark_destroy(void *ignored) { --- linux-3.13.0.orig/fs/notify/group.c +++ linux-3.13.0/fs/notify/group.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "fsnotify.h" @@ -65,6 +66,7 @@ { atomic_inc(&group->refcnt); } +EXPORT_SYMBOL(fsnotify_get_group); /* * Drop a reference to a group. Free it if it's through. @@ -74,6 +76,7 @@ if (atomic_dec_and_test(&group->refcnt)) fsnotify_final_destroy_group(group); } +EXPORT_SYMBOL(fsnotify_put_group); /* * Create a new fsnotify_group and hold a reference for the group returned. @@ -102,6 +105,7 @@ return group; } +EXPORT_SYMBOL(fsnotify_alloc_group); int fsnotify_fasync(int fd, struct file *file, int on) { --- linux-3.13.0.orig/fs/notify/fanotify/fanotify_user.c +++ linux-3.13.0/fs/notify/fanotify/fanotify_user.c @@ -888,9 +888,9 @@ { return sys_fanotify_mark(fanotify_fd, flags, #ifdef __BIG_ENDIAN - ((__u64)mask1 << 32) | mask0, -#else ((__u64)mask0 << 32) | mask1, +#else + ((__u64)mask1 << 32) | mask0, #endif dfd, pathname); } --- linux-3.13.0.orig/fs/ocfs2/quota_local.c +++ linux-3.13.0/fs/ocfs2/quota_local.c @@ -1303,10 +1303,6 @@ ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh); out: - /* Clear the read bit so that next time someone uses this - * dquot he reads fresh info from disk and allocates local - * dquot structure */ - clear_bit(DQ_READ_B, &dquot->dq_flags); return status; } --- linux-3.13.0.orig/fs/ocfs2/quota_global.c +++ linux-3.13.0/fs/ocfs2/quota_global.c @@ -717,6 +717,12 @@ */ if (status < 0) mlog_errno(status); + /* + * Clear dq_off so that we search for the structure in quota file next + * time we acquire it. The structure might be deleted and reallocated + * elsewhere by another node while our dquot structure is on freelist. + */ + dquot->dq_off = 0; clear_bit(DQ_ACTIVE_B, &dquot->dq_flags); out_trans: ocfs2_commit_trans(osb, handle); @@ -756,16 +762,17 @@ status = ocfs2_lock_global_qf(info, 1); if (status < 0) goto out; - if (!test_bit(DQ_READ_B, &dquot->dq_flags)) { - status = ocfs2_qinfo_lock(info, 0); - if (status < 0) - goto out_dq; - status = qtree_read_dquot(&info->dqi_gi, dquot); - ocfs2_qinfo_unlock(info, 0); - if (status < 0) - goto out_dq; - } - set_bit(DQ_READ_B, &dquot->dq_flags); + status = ocfs2_qinfo_lock(info, 0); + if (status < 0) + goto out_dq; + /* + * We always want to read dquot structure from disk because we don't + * know what happened with it while it was on freelist. + */ + status = qtree_read_dquot(&info->dqi_gi, dquot); + ocfs2_qinfo_unlock(info, 0); + if (status < 0) + goto out_dq; OCFS2_DQUOT(dquot)->dq_use_count++; OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace; --- linux-3.13.0.orig/fs/ocfs2/file.c +++ linux-3.13.0/fs/ocfs2/file.c @@ -2370,8 +2370,8 @@ if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || ((file->f_flags & O_DIRECT) && !direct_io)) { - ret = filemap_fdatawrite_range(file->f_mapping, pos, - pos + count - 1); + ret = filemap_fdatawrite_range(file->f_mapping, *ppos, + *ppos + count - 1); if (ret < 0) written = ret; @@ -2384,8 +2384,8 @@ } if (!ret) - ret = filemap_fdatawait_range(file->f_mapping, pos, - pos + count - 1); + ret = filemap_fdatawait_range(file->f_mapping, *ppos, + *ppos + count - 1); } /* --- linux-3.13.0.orig/fs/nfs/internal.h +++ linux-3.13.0/fs/nfs/internal.h @@ -176,7 +176,8 @@ extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, struct nfs_fh *); extern int nfs4_update_server(struct nfs_server *server, const char *hostname, - struct sockaddr *sap, size_t salen); + struct sockaddr *sap, size_t salen, + struct net *net); extern void nfs_free_server(struct nfs_server *server); extern struct nfs_server *nfs_clone_server(struct nfs_server *, struct nfs_fh *, @@ -279,9 +280,18 @@ } return; } + +static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) +{ + if (nfs_server_capable(&nfsi->vfs_inode, NFS_CAP_SECURITY_LABEL)) + nfsi->cache_validity |= NFS_INO_INVALID_LABEL; +} #else static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; } static inline void nfs4_label_free(void *label) {} +static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) +{ +} #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ /* proc.c */ --- linux-3.13.0.orig/fs/nfs/delegation.c +++ linux-3.13.0/fs/nfs/delegation.c @@ -659,16 +659,19 @@ rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); + if (delegation == NULL) + goto out_enoent; - if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) { - rcu_read_unlock(); - return -ENOENT; - } + if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) + goto out_enoent; nfs_mark_return_delegation(server, delegation); rcu_read_unlock(); nfs_delegation_run_state_manager(clp); return 0; +out_enoent: + rcu_read_unlock(); + return -ENOENT; } static struct inode * --- linux-3.13.0.orig/fs/nfs/nfs4session.c +++ linux-3.13.0/fs/nfs/nfs4session.c @@ -231,14 +231,23 @@ return ret; } +/* + * nfs4_release_slot_table - release all slot table entries + */ +static void nfs4_release_slot_table(struct nfs4_slot_table *tbl) +{ + nfs4_shrink_slot_table(tbl, 0); +} + /** - * nfs4_release_slot_table - release resources attached to a slot table + * nfs4_shutdown_slot_table - release resources attached to a slot table * @tbl: slot table to shut down * */ -void nfs4_release_slot_table(struct nfs4_slot_table *tbl) +void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl) { - nfs4_shrink_slot_table(tbl, 0); + nfs4_release_slot_table(tbl); + rpc_destroy_wait_queue(&tbl->slot_tbl_waitq); } /** @@ -422,7 +431,7 @@ spin_unlock(&tbl->slot_tbl_lock); } -static void nfs4_destroy_session_slot_tables(struct nfs4_session *session) +static void nfs4_release_session_slot_tables(struct nfs4_session *session) { nfs4_release_slot_table(&session->fc_slot_table); nfs4_release_slot_table(&session->bc_slot_table); @@ -450,7 +459,7 @@ if (status && tbl->slots == NULL) /* Fore and back channel share a connection so get * both slot tables or neither */ - nfs4_destroy_session_slot_tables(ses); + nfs4_release_session_slot_tables(ses); return status; } @@ -470,6 +479,12 @@ return session; } +static void nfs4_destroy_session_slot_tables(struct nfs4_session *session) +{ + nfs4_shutdown_slot_table(&session->fc_slot_table); + nfs4_shutdown_slot_table(&session->bc_slot_table); +} + void nfs4_destroy_session(struct nfs4_session *session) { struct rpc_xprt *xprt; --- linux-3.13.0.orig/fs/nfs/nfs4xdr.c +++ linux-3.13.0/fs/nfs/nfs4xdr.c @@ -3097,7 +3097,8 @@ return -EIO; } -static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected, + int *nfs_retval) { __be32 *p; uint32_t opnum; @@ -3107,19 +3108,32 @@ if (unlikely(!p)) goto out_overflow; opnum = be32_to_cpup(p++); - if (opnum != expected) { - dprintk("nfs: Server returned operation" - " %d but we issued a request for %d\n", - opnum, expected); - return -EIO; - } + if (unlikely(opnum != expected)) + goto out_bad_operation; nfserr = be32_to_cpup(p); - if (nfserr != NFS_OK) - return nfs4_stat_to_errno(nfserr); - return 0; + if (nfserr == NFS_OK) + *nfs_retval = 0; + else + *nfs_retval = nfs4_stat_to_errno(nfserr); + return true; +out_bad_operation: + dprintk("nfs: Server returned operation" + " %d but we issued a request for %d\n", + opnum, expected); + *nfs_retval = -EREMOTEIO; + return false; out_overflow: print_overflow_msg(__func__, xdr); - return -EIO; + *nfs_retval = -EIO; + return false; +} + +static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +{ + int retval; + + __decode_op_hdr(xdr, expected, &retval); + return retval; } /* Dummy routine */ @@ -5001,11 +5015,12 @@ uint32_t savewords, bmlen, i; int status; - status = decode_op_hdr(xdr, OP_OPEN); - if (status != -EIO) - nfs_increment_open_seqid(status, res->seqid); - if (!status) - status = decode_stateid(xdr, &res->stateid); + if (!__decode_op_hdr(xdr, OP_OPEN, &status)) + return status; + nfs_increment_open_seqid(status, res->seqid); + if (status) + return status; + status = decode_stateid(xdr, &res->stateid); if (unlikely(status)) return status; --- linux-3.13.0.orig/fs/nfs/nfs4state.c +++ linux-3.13.0/fs/nfs/nfs4state.c @@ -1015,8 +1015,11 @@ if (ret == -EIO) /* A lost lock - don't even consider delegations */ goto out; - if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) + /* returns true if delegation stateid found and copied */ + if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) { + ret = 0; goto out; + } if (ret != -ENOENT) /* nfs4_copy_delegation_stateid() didn't over-write * dst, so it still has the lock stateid which we now --- linux-3.13.0.orig/fs/nfs/dir.c +++ linux-3.13.0/fs/nfs/dir.c @@ -1837,6 +1837,11 @@ GFP_KERNEL)) { SetPageUptodate(page); unlock_page(page); + /* + * add_to_page_cache_lru() grabs an extra page refcount. + * Drop it here to avoid leaking this page later. + */ + page_cache_release(page); } else __free_page(page); --- linux-3.13.0.orig/fs/nfs/nfs4proc.c +++ linux-3.13.0/fs/nfs/nfs4proc.c @@ -539,7 +539,7 @@ struct nfs4_slot *slot = res->sr_slot; struct nfs4_slot_table *tbl; - if (!RPC_WAS_SENT(task)) + if (slot == NULL) goto out; tbl = slot->table; @@ -1622,15 +1622,15 @@ { struct nfs4_opendata *data = calldata; - nfs40_setup_sequence(data->o_arg.server, &data->o_arg.seq_args, - &data->o_res.seq_res, task); + nfs40_setup_sequence(data->o_arg.server, &data->c_arg.seq_args, + &data->c_res.seq_res, task); } static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) { struct nfs4_opendata *data = calldata; - nfs40_sequence_done(task, &data->o_res.seq_res); + nfs40_sequence_done(task, &data->c_res.seq_res); data->rpc_status = task->tk_status; if (data->rpc_status == 0) { @@ -1688,7 +1688,7 @@ }; int status; - nfs4_init_sequence(&data->o_arg.seq_args, &data->o_res.seq_res, 1); + nfs4_init_sequence(&data->c_arg.seq_args, &data->c_res.seq_res, 1); kref_get(&data->kref); data->rpc_done = 0; data->rpc_status = 0; @@ -4012,8 +4012,9 @@ { nfs4_stateid current_stateid; - if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode)) - return false; + /* If the current stateid represents a lost lock, then exit */ + if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode) == -EIO) + return true; return nfs4_stateid_match(stateid, ¤t_stateid); } @@ -5831,8 +5832,7 @@ struct nfs4_lock_state *lsp; struct nfs_server *server; struct nfs_release_lockowner_args args; - struct nfs4_sequence_args seq_args; - struct nfs4_sequence_res seq_res; + struct nfs_release_lockowner_res res; unsigned long timestamp; }; @@ -5840,7 +5840,7 @@ { struct nfs_release_lockowner_data *data = calldata; nfs40_setup_sequence(data->server, - &data->seq_args, &data->seq_res, task); + &data->args.seq_args, &data->res.seq_res, task); data->timestamp = jiffies; } @@ -5849,7 +5849,7 @@ struct nfs_release_lockowner_data *data = calldata; struct nfs_server *server = data->server; - nfs40_sequence_done(task, &data->seq_res); + nfs40_sequence_done(task, &data->res.seq_res); switch (task->tk_status) { case 0: @@ -5890,7 +5890,6 @@ data = kmalloc(sizeof(*data), GFP_NOFS); if (!data) return -ENOMEM; - nfs4_init_sequence(&data->seq_args, &data->seq_res, 0); data->lsp = lsp; data->server = server; data->args.lock_owner.clientid = server->nfs_client->cl_clientid; @@ -5898,6 +5897,8 @@ data->args.lock_owner.s_dev = server->s_dev; msg.rpc_argp = &data->args; + msg.rpc_resp = &data->res; + nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data); return 0; } @@ -7409,9 +7410,9 @@ struct nfs_server *server = NFS_SERVER(inode); struct pnfs_layout_hdr *lo; struct nfs4_state *state = NULL; - unsigned long timeo, giveup; + unsigned long timeo, now, giveup; - dprintk("--> %s\n", __func__); + dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status); if (!nfs41_sequence_done(task, &lgp->res.seq_res)) goto out; @@ -7419,12 +7420,38 @@ switch (task->tk_status) { case 0: goto out; + /* + * NFS4ERR_LAYOUTTRYLATER is a conflict with another client + * (or clients) writing to the same RAID stripe + */ case -NFS4ERR_LAYOUTTRYLATER: + /* + * NFS4ERR_RECALLCONFLICT is when conflict with self (must recall + * existing layout before getting a new one). + */ case -NFS4ERR_RECALLCONFLICT: timeo = rpc_get_timeout(task->tk_client); giveup = lgp->args.timestamp + timeo; - if (time_after(giveup, jiffies)) - task->tk_status = -NFS4ERR_DELAY; + now = jiffies; + if (time_after(giveup, now)) { + unsigned long delay; + + /* Delay for: + * - Not less then NFS4_POLL_RETRY_MIN. + * - One last time a jiffie before we give up + * - exponential backoff (time_now minus start_attempt) + */ + delay = max_t(unsigned long, NFS4_POLL_RETRY_MIN, + min((giveup - now - 1), + now - lgp->args.timestamp)); + + dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n", + __func__, delay); + rpc_delay(task, delay); + task->tk_status = 0; + rpc_restart_call_prepare(task); + goto out; /* Do not call nfs4_async_handle_error() */ + } break; case -NFS4ERR_EXPIRED: case -NFS4ERR_BAD_STATEID: @@ -7920,7 +7947,7 @@ switch (err) { case 0: case -NFS4ERR_WRONGSEC: - case -NFS4ERR_NOTSUPP: + case -ENOTSUPP: goto out; default: err = nfs4_handle_exception(server, err, &exception); @@ -7954,7 +7981,7 @@ * Fall back on "guess and check" method if * the server doesn't support SECINFO_NO_NAME */ - if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) { + if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) { err = nfs4_find_root_sec(server, fhandle, info); goto out_freepage; } --- linux-3.13.0.orig/fs/nfs/nfs4namespace.c +++ linux-3.13.0/fs/nfs/nfs4namespace.c @@ -121,9 +121,8 @@ } static size_t nfs_parse_server_name(char *string, size_t len, - struct sockaddr *sa, size_t salen, struct nfs_server *server) + struct sockaddr *sa, size_t salen, struct net *net) { - struct net *net = rpc_net_ns(server->client); ssize_t ret; ret = rpc_pton(net, string, len, sa, salen); @@ -223,6 +222,7 @@ const struct nfs4_fs_location *location) { const size_t addr_bufsize = sizeof(struct sockaddr_storage); + struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client); struct vfsmount *mnt = ERR_PTR(-ENOENT); char *mnt_path; unsigned int maxbuflen; @@ -248,8 +248,7 @@ continue; mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, - mountdata->addr, addr_bufsize, - NFS_SB(mountdata->sb)); + mountdata->addr, addr_bufsize, net); if (mountdata->addrlen == 0) continue; @@ -419,6 +418,7 @@ const struct nfs4_fs_location *location) { const size_t addr_bufsize = sizeof(struct sockaddr_storage); + struct net *net = rpc_net_ns(server->client); struct sockaddr *sap; unsigned int s; size_t salen; @@ -440,7 +440,7 @@ continue; salen = nfs_parse_server_name(buf->data, buf->len, - sap, addr_bufsize, server); + sap, addr_bufsize, net); if (salen == 0) continue; rpc_set_port(sap, NFS_PORT); @@ -450,7 +450,7 @@ if (hostname == NULL) break; - error = nfs4_update_server(server, hostname, sap, salen); + error = nfs4_update_server(server, hostname, sap, salen, net); kfree(hostname); if (error == 0) break; --- linux-3.13.0.orig/fs/nfs/inode.c +++ linux-3.13.0/fs/nfs/inode.c @@ -164,17 +164,16 @@ if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { nfs_fscache_invalidate(inode); nfsi->cache_validity |= NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_LABEL | NFS_INO_INVALID_DATA | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | NFS_INO_REVAL_PAGECACHE; } else nfsi->cache_validity |= NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_LABEL | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | NFS_INO_REVAL_PAGECACHE; + nfs_zap_label_cache_locked(nfsi); } void nfs_zap_caches(struct inode *inode) @@ -266,6 +265,13 @@ } #ifdef CONFIG_NFS_V4_SECURITY_LABEL +static void nfs_clear_label_invalid(struct inode *inode) +{ + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL; + spin_unlock(&inode->i_lock); +} + void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) { @@ -283,6 +289,7 @@ __func__, (char *)label->label, label->len, error); + nfs_clear_label_invalid(inode); } } @@ -1597,7 +1604,7 @@ inode->i_blocks = fattr->du.nfs2.blocks; /* Update attrtimeo value if we're out of the unstable period */ - if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) { + if (invalid & NFS_INO_INVALID_ATTR) { nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo_timestamp = now; @@ -1610,7 +1617,6 @@ } } invalid &= ~NFS_INO_INVALID_ATTR; - invalid &= ~NFS_INO_INVALID_LABEL; /* Don't invalidate the data if we were to blame */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) --- linux-3.13.0.orig/fs/nfs/write.c +++ linux-3.13.0/fs/nfs/write.c @@ -922,19 +922,20 @@ * extend the write to cover the entire page in order to avoid fragmentation * inefficiencies. * - * If the file is opened for synchronous writes or if we have a write delegation - * from the server then we can just skip the rest of the checks. + * If the file is opened for synchronous writes then we can just skip the rest + * of the checks. */ static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode) { if (file->f_flags & O_DSYNC) return 0; + if (!nfs_write_pageuptodate(page, inode)) + return 0; if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) return 1; - if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL || - (inode->i_flock->fl_start == 0 && + if (inode->i_flock == NULL || (inode->i_flock->fl_start == 0 && inode->i_flock->fl_end == OFFSET_MAX && - inode->i_flock->fl_type != F_RDLCK))) + inode->i_flock->fl_type != F_RDLCK)) return 1; return 0; } --- linux-3.13.0.orig/fs/nfs/nfs4session.h +++ linux-3.13.0/fs/nfs/nfs4session.h @@ -74,7 +74,7 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, unsigned int max_reqs, const char *queue); -extern void nfs4_release_slot_table(struct nfs4_slot_table *tbl); +extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); --- linux-3.13.0.orig/fs/nfs/nfs4client.c +++ linux-3.13.0/fs/nfs/nfs4client.c @@ -169,7 +169,7 @@ void nfs40_shutdown_client(struct nfs_client *clp) { if (clp->cl_slot_tbl) { - nfs4_release_slot_table(clp->cl_slot_tbl); + nfs4_shutdown_slot_table(clp->cl_slot_tbl); kfree(clp->cl_slot_tbl); } } @@ -409,13 +409,11 @@ error = nfs4_discover_server_trunking(clp, &old); if (error < 0) goto error; - nfs_put_client(clp); - if (clp != old) { - clp->cl_preserve_clid = true; - clp = old; - } - return clp; + if (clp != old) + clp->cl_preserve_clid = true; + nfs_put_client(clp); + return old; error: nfs_mark_client_ready(clp, error); @@ -493,9 +491,10 @@ prev = pos; status = nfs_wait_client_init_complete(pos); - spin_lock(&nn->nfs_client_lock); if (status < 0) - continue; + goto out; + status = -NFS4ERR_STALE_CLIENTID; + spin_lock(&nn->nfs_client_lock); } if (pos->cl_cons_state != NFS_CS_READY) continue; @@ -633,7 +632,8 @@ } spin_lock(&nn->nfs_client_lock); if (status < 0) - continue; + break; + status = -NFS4ERR_STALE_CLIENTID; } if (pos->cl_cons_state != NFS_CS_READY) continue; @@ -1133,6 +1133,7 @@ * @hostname: new end-point's hostname * @sap: new end-point's socket address * @salen: size of "sap" + * @net: net namespace * * The nfs_server must be quiescent before this function is invoked. * Either its session is drained (NFSv4.1+), or its transport is @@ -1141,13 +1142,13 @@ * Returns zero on success, or a negative errno value. */ int nfs4_update_server(struct nfs_server *server, const char *hostname, - struct sockaddr *sap, size_t salen) + struct sockaddr *sap, size_t salen, struct net *net) { struct nfs_client *clp = server->nfs_client; struct rpc_clnt *clnt = server->client; struct xprt_create xargs = { .ident = clp->cl_proto, - .net = &init_net, + .net = net, .dstaddr = sap, .addrlen = salen, .servername = hostname, @@ -1187,7 +1188,7 @@ error = nfs4_set_client(server, hostname, sap, salen, buf, clp->cl_rpcclient->cl_auth->au_flavor, clp->cl_proto, clnt->cl_timeout, - clp->cl_minorversion, clp->cl_net); + clp->cl_minorversion, net); nfs_put_client(clp); if (error != 0) { nfs_server_insert_lists(server); --- linux-3.13.0.orig/fs/jbd2/transaction.c +++ linux-3.13.0/fs/jbd2/transaction.c @@ -514,11 +514,13 @@ * similarly constrained call sites */ ret = start_this_handle(journal, handle, GFP_NOFS); - if (ret < 0) + if (ret < 0) { jbd2_journal_free_reserved(handle); + return ret; + } handle->h_type = type; handle->h_line_no = line_no; - return ret; + return 0; } EXPORT_SYMBOL(jbd2_journal_start_reserved); --- linux-3.13.0.orig/fs/quota/dquot.c +++ linux-3.13.0/fs/quota/dquot.c @@ -581,9 +581,17 @@ dqstats_inc(DQST_LOOKUPS); dqput(old_dquot); old_dquot = dquot; - ret = fn(dquot, priv); - if (ret < 0) - goto out; + /* + * ->release_dquot() can be racing with us. Our reference + * protects us from new calls to it so just wait for any + * outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { + ret = fn(dquot, priv); + if (ret < 0) + goto out; + } spin_lock(&dq_list_lock); /* We are safe to continue now because our dquot could not * be moved out of the inuse list while we hold the reference */ --- linux-3.13.0.orig/fs/overlayfs/readdir.c +++ linux-3.13.0/fs/overlayfs/readdir.c @@ -0,0 +1,553 @@ +/* + * + * Copyright (C) 2011 Novell Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "overlayfs.h" + +struct ovl_cache_entry { + const char *name; + unsigned int len; + unsigned int type; + u64 ino; + bool is_whiteout; + struct list_head l_node; + struct rb_node node; +}; + +struct ovl_readdir_data { + struct dir_context ctx; + bool is_merge; + struct rb_root *root; + struct list_head *list; + struct list_head *middle; + struct dentry *dir; + int count; + int err; +}; + +struct ovl_dir_file { + bool is_real; + bool is_cached; + struct list_head cursor; + u64 cache_version; + struct list_head cache; + struct file *realfile; +}; + +static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n) +{ + return container_of(n, struct ovl_cache_entry, node); +} + +static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root, + const char *name, int len) +{ + struct rb_node *node = root->rb_node; + int cmp; + + while (node) { + struct ovl_cache_entry *p = ovl_cache_entry_from_node(node); + + cmp = strncmp(name, p->name, len); + if (cmp > 0) + node = p->node.rb_right; + else if (cmp < 0 || len < p->len) + node = p->node.rb_left; + else + return p; + } + + return NULL; +} + +static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, + u64 ino, unsigned int d_type) +{ + struct ovl_cache_entry *p; + + p = kmalloc(sizeof(*p) + len + 1, GFP_KERNEL); + if (p) { + char *name_copy = (char *) (p + 1); + memcpy(name_copy, name, len); + name_copy[len] = '\0'; + p->name = name_copy; + p->len = len; + p->type = d_type; + p->ino = ino; + p->is_whiteout = false; + } + + return p; +} + +static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, + const char *name, int len, u64 ino, + unsigned int d_type) +{ + struct rb_node **newp = &rdd->root->rb_node; + struct rb_node *parent = NULL; + struct ovl_cache_entry *p; + + while (*newp) { + int cmp; + struct ovl_cache_entry *tmp; + + parent = *newp; + tmp = ovl_cache_entry_from_node(*newp); + cmp = strncmp(name, tmp->name, len); + if (cmp > 0) + newp = &tmp->node.rb_right; + else if (cmp < 0 || len < tmp->len) + newp = &tmp->node.rb_left; + else + return 0; + } + + p = ovl_cache_entry_new(name, len, ino, d_type); + if (p == NULL) + return -ENOMEM; + + list_add_tail(&p->l_node, rdd->list); + rb_link_node(&p->node, parent, newp); + rb_insert_color(&p->node, rdd->root); + + return 0; +} + +static int ovl_fill_lower(struct ovl_readdir_data *rdd, + const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct ovl_cache_entry *p; + + p = ovl_cache_entry_find(rdd->root, name, namelen); + if (p) { + list_move_tail(&p->l_node, rdd->middle); + } else { + p = ovl_cache_entry_new(name, namelen, ino, d_type); + if (p == NULL) + rdd->err = -ENOMEM; + else + list_add_tail(&p->l_node, rdd->middle); + } + + return rdd->err; +} + +static void ovl_cache_free(struct list_head *list) +{ + struct ovl_cache_entry *p; + struct ovl_cache_entry *n; + + list_for_each_entry_safe(p, n, list, l_node) + kfree(p); + + INIT_LIST_HEAD(list); +} + +static int ovl_fill_merge(void *buf, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct ovl_readdir_data *rdd = buf; + + rdd->count++; + if (!rdd->is_merge) + return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); + else + return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); +} + +static inline int ovl_dir_read(struct path *realpath, + struct ovl_readdir_data *rdd) +{ + struct file *realfile; + int err; + + realfile = ovl_path_open(realpath, O_RDONLY | O_DIRECTORY); + if (IS_ERR(realfile)) + return PTR_ERR(realfile); + + rdd->ctx.pos = 0; + do { + rdd->count = 0; + rdd->err = 0; + err = iterate_dir(realfile, &rdd->ctx); + if (err >= 0) + err = rdd->err; + } while (!err && rdd->count); + fput(realfile); + + return 0; +} + +static void ovl_dir_reset(struct file *file) +{ + struct ovl_dir_file *od = file->private_data; + enum ovl_path_type type = ovl_path_type(file->f_path.dentry); + + if (ovl_dentry_version_get(file->f_path.dentry) != od->cache_version) { + list_del_init(&od->cursor); + ovl_cache_free(&od->cache); + od->is_cached = false; + } + WARN_ON(!od->is_real && type != OVL_PATH_MERGE); + if (od->is_real && type == OVL_PATH_MERGE) { + fput(od->realfile); + od->realfile = NULL; + od->is_real = false; + } +} + +static int ovl_dir_mark_whiteouts(struct ovl_readdir_data *rdd) +{ + struct ovl_cache_entry *p; + struct dentry *dentry; + const struct cred *old_cred; + struct cred *override_cred; + + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) { + ovl_cache_free(rdd->list); + return -ENOMEM; + } + + old_cred = override_creds(override_cred); + + mutex_lock(&rdd->dir->d_inode->i_mutex); + list_for_each_entry(p, rdd->list, l_node) { + if (p->type != DT_LNK) + continue; + + dentry = lookup_one_len(p->name, rdd->dir, p->len); + if (IS_ERR(dentry)) + continue; + + p->is_whiteout = ovl_is_whiteout(dentry); + dput(dentry); + } + mutex_unlock(&rdd->dir->d_inode->i_mutex); + + revert_creds(old_cred); + put_cred(override_cred); + + return 0; +} + +static inline int ovl_dir_read_merged(struct path *upperpath, + struct path *lowerpath, + struct list_head *list) +{ + int err; + struct rb_root root = RB_ROOT; + struct list_head middle; + struct ovl_readdir_data rdd = { + .ctx.actor = ovl_fill_merge, + .list = list, + .root = &root, + .is_merge = false, + }; + + if (upperpath->dentry) { + rdd.dir = upperpath->dentry; + err = ovl_dir_read(upperpath, &rdd); + if (err) + goto out; + + err = ovl_dir_mark_whiteouts(&rdd); + if (err) + goto out; + } + /* + * Insert lowerpath entries before upperpath ones, this allows + * offsets to be reasonably constant + */ + list_add(&middle, rdd.list); + rdd.middle = &middle; + rdd.is_merge = true; + err = ovl_dir_read(lowerpath, &rdd); + list_del(&middle); +out: + return err; +} + +static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) +{ + struct list_head *l; + loff_t off; + + l = od->cache.next; + for (off = 0; off < pos; off++) { + if (l == &od->cache) + break; + l = l->next; + } + list_move_tail(&od->cursor, l); +} + +static int ovl_iterate(struct file *file, struct dir_context *ctx) +{ + struct ovl_dir_file *od = file->private_data; + int res; + + if (!ctx->pos) + ovl_dir_reset(file); + + if (od->is_real) { + res = iterate_dir(od->realfile, ctx); + + return res; + } + + if (!od->is_cached) { + struct path lowerpath; + struct path upperpath; + + ovl_path_lower(file->f_path.dentry, &lowerpath); + ovl_path_upper(file->f_path.dentry, &upperpath); + + res = ovl_dir_read_merged(&upperpath, &lowerpath, &od->cache); + if (res) { + ovl_cache_free(&od->cache); + return res; + } + + od->cache_version = ovl_dentry_version_get(file->f_path.dentry); + od->is_cached = true; + + ovl_seek_cursor(od, ctx->pos); + } + + while (od->cursor.next != &od->cache) { + struct ovl_cache_entry *p; + + p = list_entry(od->cursor.next, struct ovl_cache_entry, l_node); + if (!p->is_whiteout) { + if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) + break; + } + ctx->pos++; + list_move(&od->cursor, &p->l_node); + } + + return 0; +} + +static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t res; + struct ovl_dir_file *od = file->private_data; + + mutex_lock(&file_inode(file)->i_mutex); + if (!file->f_pos) + ovl_dir_reset(file); + + if (od->is_real) { + res = vfs_llseek(od->realfile, offset, origin); + file->f_pos = od->realfile->f_pos; + } else { + res = -EINVAL; + + switch (origin) { + case SEEK_CUR: + offset += file->f_pos; + break; + case SEEK_SET: + break; + default: + goto out_unlock; + } + if (offset < 0) + goto out_unlock; + + if (offset != file->f_pos) { + file->f_pos = offset; + if (od->is_cached) + ovl_seek_cursor(od, offset); + } + res = offset; + } +out_unlock: + mutex_unlock(&file_inode(file)->i_mutex); + + return res; +} + +static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, + int datasync) +{ + struct ovl_dir_file *od = file->private_data; + + /* May need to reopen directory if it got copied up */ + if (!od->realfile) { + struct path upperpath; + + ovl_path_upper(file->f_path.dentry, &upperpath); + od->realfile = ovl_path_open(&upperpath, O_RDONLY); + if (IS_ERR(od->realfile)) + return PTR_ERR(od->realfile); + } + + return vfs_fsync_range(od->realfile, start, end, datasync); +} + +static int ovl_dir_release(struct inode *inode, struct file *file) +{ + struct ovl_dir_file *od = file->private_data; + + list_del(&od->cursor); + ovl_cache_free(&od->cache); + if (od->realfile) + fput(od->realfile); + kfree(od); + + return 0; +} + +static int ovl_dir_open(struct inode *inode, struct file *file) +{ + struct path realpath; + struct file *realfile; + struct ovl_dir_file *od; + enum ovl_path_type type; + + od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL); + if (!od) + return -ENOMEM; + + type = ovl_path_real(file->f_path.dentry, &realpath); + realfile = ovl_path_open(&realpath, file->f_flags); + if (IS_ERR(realfile)) { + kfree(od); + return PTR_ERR(realfile); + } + INIT_LIST_HEAD(&od->cache); + INIT_LIST_HEAD(&od->cursor); + od->is_cached = false; + od->realfile = realfile; + od->is_real = (type != OVL_PATH_MERGE); + file->private_data = od; + + return 0; +} + +const struct file_operations ovl_dir_operations = { + .read = generic_read_dir, + .open = ovl_dir_open, + .iterate = ovl_iterate, + .llseek = ovl_dir_llseek, + .fsync = ovl_dir_fsync, + .release = ovl_dir_release, +}; + +static int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) +{ + int err; + struct path lowerpath; + struct path upperpath; + struct ovl_cache_entry *p; + + ovl_path_upper(dentry, &upperpath); + ovl_path_lower(dentry, &lowerpath); + + err = ovl_dir_read_merged(&upperpath, &lowerpath, list); + if (err) + return err; + + err = 0; + + list_for_each_entry(p, list, l_node) { + if (p->is_whiteout) + continue; + + if (p->name[0] == '.') { + if (p->len == 1) + continue; + if (p->len == 2 && p->name[1] == '.') + continue; + } + err = -ENOTEMPTY; + break; + } + + return err; +} + +static int ovl_remove_whiteouts(struct dentry *dir, struct list_head *list) +{ + struct path upperpath; + struct dentry *upperdir; + struct ovl_cache_entry *p; + const struct cred *old_cred; + struct cred *override_cred; + int err; + + ovl_path_upper(dir, &upperpath); + upperdir = upperpath.dentry; + + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) + return -ENOMEM; + + old_cred = override_creds(override_cred); + + err = vfs_setxattr(upperdir, ovl_opaque_xattr, "y", 1, 0); + if (err) + goto out_revert_creds; + + mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); + list_for_each_entry(p, list, l_node) { + struct dentry *dentry; + int ret; + + if (!p->is_whiteout) + continue; + + dentry = lookup_one_len(p->name, upperdir, p->len); + if (IS_ERR(dentry)) { + pr_warn( + "overlayfs: failed to lookup whiteout %.*s: %li\n", + p->len, p->name, PTR_ERR(dentry)); + continue; + } + ret = vfs_unlink(upperdir->d_inode, dentry, NULL); + dput(dentry); + if (ret) + pr_warn( + "overlayfs: failed to unlink whiteout %.*s: %i\n", + p->len, p->name, ret); + } + mutex_unlock(&upperdir->d_inode->i_mutex); + +out_revert_creds: + revert_creds(old_cred); + put_cred(override_cred); + + return err; +} + +int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type) +{ + int err; + LIST_HEAD(list); + + err = ovl_check_empty_dir(dentry, &list); + if (!err && type == OVL_PATH_MERGE) + err = ovl_remove_whiteouts(dentry, &list); + + ovl_cache_free(&list); + + return err; +} --- linux-3.13.0.orig/fs/overlayfs/dir.c +++ linux-3.13.0/fs/overlayfs/dir.c @@ -0,0 +1,592 @@ +/* + * + * Copyright (C) 2011 Novell Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include "overlayfs.h" + +static const char *ovl_whiteout_symlink = "(overlay-whiteout)"; + +static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) +{ + int err; + struct dentry *newdentry; + const struct cred *old_cred; + struct cred *override_cred; + + /* FIXME: recheck lower dentry to see if whiteout is really needed */ + + err = -ENOMEM; + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) + goto out; + + override_cred->fsuid = make_kuid(current_user_ns(), 0); + if (!uid_valid(override_cred->fsuid)) + override_cred->fsuid = GLOBAL_ROOT_UID; + override_cred->fsgid = make_kgid(current_user_ns(), 0); + if (!gid_valid(override_cred->fsgid)) + override_cred->fsgid = GLOBAL_ROOT_GID; + old_cred = override_creds(override_cred); + + newdentry = lookup_one_len(dentry->d_name.name, upperdir, + dentry->d_name.len); + err = PTR_ERR(newdentry); + if (IS_ERR(newdentry)) + goto out_put_cred; + + /* Just been removed within the same locked region */ + WARN_ON(newdentry->d_inode); + + err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink); + if (err) + goto out_dput; + + ovl_dentry_version_inc(dentry->d_parent); + + err = vfs_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0); + if (err) + vfs_unlink(upperdir->d_inode, newdentry, NULL); + +out_dput: + dput(newdentry); +out_put_cred: + revert_creds(old_cred); + put_cred(override_cred); +out: + if (err) { + /* + * There's no way to recover from failure to whiteout. + * What should we do? Log a big fat error and... ? + */ + pr_err("overlayfs: ERROR - failed to whiteout '%s'\n", + dentry->d_name.name); + } + + return err; +} + +static struct dentry *ovl_lookup_create(struct dentry *upperdir, + struct dentry *template) +{ + int err; + struct dentry *newdentry; + struct qstr *name = &template->d_name; + + newdentry = lookup_one_len(name->name, upperdir, name->len); + if (IS_ERR(newdentry)) + return newdentry; + + if (newdentry->d_inode) { + const struct cred *old_cred; + struct cred *override_cred; + + /* No need to check whiteout if lower parent is non-existent */ + err = -EEXIST; + if (!ovl_dentry_lower(template->d_parent)) + goto out_dput; + + if (!S_ISLNK(newdentry->d_inode->i_mode)) + goto out_dput; + + err = -ENOMEM; + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) + goto out_dput; + + old_cred = override_creds(override_cred); + + err = -EEXIST; + if (ovl_is_whiteout(newdentry)) + err = vfs_unlink(upperdir->d_inode, newdentry, NULL); + + revert_creds(old_cred); + put_cred(override_cred); + if (err) + goto out_dput; + + dput(newdentry); + newdentry = lookup_one_len(name->name, upperdir, name->len); + if (IS_ERR(newdentry)) { + ovl_whiteout(upperdir, template); + return newdentry; + } + + /* + * Whiteout just been successfully removed, parent + * i_mutex is still held, there's no way the lookup + * could return positive. + */ + WARN_ON(newdentry->d_inode); + } + + return newdentry; + +out_dput: + dput(newdentry); + return ERR_PTR(err); +} + +struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry, + struct kstat *stat, const char *link) +{ + int err; + struct dentry *newdentry; + struct inode *dir = upperdir->d_inode; + + newdentry = ovl_lookup_create(upperdir, dentry); + if (IS_ERR(newdentry)) + goto out; + + switch (stat->mode & S_IFMT) { + case S_IFREG: + err = vfs_create(dir, newdentry, stat->mode, NULL); + break; + + case S_IFDIR: + err = vfs_mkdir(dir, newdentry, stat->mode); + break; + + case S_IFCHR: + case S_IFBLK: + case S_IFIFO: + case S_IFSOCK: + err = vfs_mknod(dir, newdentry, stat->mode, stat->rdev); + break; + + case S_IFLNK: + err = vfs_symlink(dir, newdentry, link); + break; + + default: + err = -EPERM; + } + if (err) { + if (ovl_dentry_is_opaque(dentry)) + ovl_whiteout(upperdir, dentry); + dput(newdentry); + newdentry = ERR_PTR(err); + } else if (WARN_ON(!newdentry->d_inode)) { + /* + * Not quite sure if non-instantiated dentry is legal or not. + * VFS doesn't seem to care so check and warn here. + */ + dput(newdentry); + newdentry = ERR_PTR(-ENOENT); + } + +out: + return newdentry; + +} + +static int ovl_set_opaque(struct dentry *upperdentry) +{ + int err; + const struct cred *old_cred; + struct cred *override_cred; + + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) + return -ENOMEM; + + old_cred = override_creds(override_cred); + err = vfs_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0); + revert_creds(old_cred); + put_cred(override_cred); + + return err; +} + +static int ovl_remove_opaque(struct dentry *upperdentry) +{ + int err; + const struct cred *old_cred; + struct cred *override_cred; + + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) + return -ENOMEM; + + old_cred = override_creds(override_cred); + err = vfs_removexattr(upperdentry, ovl_opaque_xattr); + revert_creds(old_cred); + put_cred(override_cred); + + return err; +} + +static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + int err; + enum ovl_path_type type; + struct path realpath; + + type = ovl_path_real(dentry, &realpath); + err = vfs_getattr(&realpath, stat); + if (err) + return err; + + stat->dev = dentry->d_sb->s_dev; + stat->ino = dentry->d_inode->i_ino; + + /* + * It's probably not worth it to count subdirs to get the + * correct link count. nlink=1 seems to pacify 'find' and + * other utilities. + */ + if (type == OVL_PATH_MERGE) + stat->nlink = 1; + + return 0; +} + +static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev, + const char *link) +{ + int err; + struct dentry *newdentry; + struct dentry *upperdir; + struct inode *inode; + struct kstat stat = { + .mode = mode, + .rdev = rdev, + }; + + err = -ENOMEM; + inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata); + if (!inode) + goto out; + + err = ovl_copy_up(dentry->d_parent); + if (err) + goto out_iput; + + upperdir = ovl_dentry_upper(dentry->d_parent); + mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); + + newdentry = ovl_upper_create(upperdir, dentry, &stat, link); + err = PTR_ERR(newdentry); + if (IS_ERR(newdentry)) + goto out_unlock; + + ovl_dentry_version_inc(dentry->d_parent); + if (ovl_dentry_is_opaque(dentry) && S_ISDIR(mode)) { + err = ovl_set_opaque(newdentry); + if (err) { + vfs_rmdir(upperdir->d_inode, newdentry); + ovl_whiteout(upperdir, dentry); + goto out_dput; + } + } + ovl_dentry_update(dentry, newdentry); + ovl_copyattr(newdentry->d_inode, inode); + d_instantiate(dentry, inode); + inode = NULL; + newdentry = NULL; + err = 0; + +out_dput: + dput(newdentry); +out_unlock: + mutex_unlock(&upperdir->d_inode->i_mutex); +out_iput: + iput(inode); +out: + return err; +} + +static int ovl_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) +{ + return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL); +} + +static int ovl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); +} + +static int ovl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + dev_t rdev) +{ + return ovl_create_object(dentry, mode, rdev, NULL); +} + +static int ovl_symlink(struct inode *dir, struct dentry *dentry, + const char *link) +{ + return ovl_create_object(dentry, S_IFLNK, 0, link); +} + +static int ovl_do_remove(struct dentry *dentry, bool is_dir) +{ + int err; + enum ovl_path_type type; + struct path realpath; + struct dentry *upperdir; + + err = ovl_copy_up(dentry->d_parent); + if (err) + return err; + + upperdir = ovl_dentry_upper(dentry->d_parent); + mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); + type = ovl_path_real(dentry, &realpath); + if (type != OVL_PATH_LOWER) { + err = -ESTALE; + if (realpath.dentry->d_parent != upperdir) + goto out_d_drop; + + /* FIXME: create whiteout up front and rename to target */ + + if (is_dir) + err = vfs_rmdir(upperdir->d_inode, realpath.dentry); + else + err = vfs_unlink(upperdir->d_inode, realpath.dentry, NULL); + if (err) + goto out_d_drop; + + ovl_dentry_version_inc(dentry->d_parent); + } + + if (type != OVL_PATH_UPPER || ovl_dentry_is_opaque(dentry)) + err = ovl_whiteout(upperdir, dentry); + + /* + * Keeping this dentry hashed would mean having to release + * upperpath/lowerpath, which could only be done if we are the + * sole user of this dentry. Too tricky... Just unhash for + * now. + */ +out_d_drop: + d_drop(dentry); + mutex_unlock(&upperdir->d_inode->i_mutex); + + return err; +} + +static int ovl_unlink(struct inode *dir, struct dentry *dentry) +{ + return ovl_do_remove(dentry, false); +} + + +static int ovl_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err; + enum ovl_path_type type; + + type = ovl_path_type(dentry); + if (type != OVL_PATH_UPPER) { + err = ovl_check_empty_and_clear(dentry, type); + if (err) + return err; + } + + return ovl_do_remove(dentry, true); +} + +static int ovl_link(struct dentry *old, struct inode *newdir, + struct dentry *new) +{ + int err; + struct dentry *olddentry; + struct dentry *newdentry; + struct dentry *upperdir; + struct inode *newinode; + + err = ovl_copy_up(old); + if (err) + goto out; + + err = ovl_copy_up(new->d_parent); + if (err) + goto out; + + upperdir = ovl_dentry_upper(new->d_parent); + mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); + newdentry = ovl_lookup_create(upperdir, new); + err = PTR_ERR(newdentry); + if (IS_ERR(newdentry)) + goto out_unlock; + + olddentry = ovl_dentry_upper(old); + err = vfs_link(olddentry, upperdir->d_inode, newdentry, NULL); + if (!err) { + if (WARN_ON(!newdentry->d_inode)) { + dput(newdentry); + err = -ENOENT; + goto out_unlock; + } + newinode = ovl_new_inode(old->d_sb, newdentry->d_inode->i_mode, + new->d_fsdata); + if (!newinode) { + err = -ENOMEM; + goto link_fail; + } + ovl_copyattr(upperdir->d_inode, newinode); + + ovl_dentry_version_inc(new->d_parent); + ovl_dentry_update(new, newdentry); + + d_instantiate(new, newinode); + } else { +link_fail: + if (ovl_dentry_is_opaque(new)) + ovl_whiteout(upperdir, new); + dput(newdentry); + } +out_unlock: + mutex_unlock(&upperdir->d_inode->i_mutex); +out: + return err; +} + +static int ovl_rename(struct inode *olddir, struct dentry *old, + struct inode *newdir, struct dentry *new) +{ + int err; + enum ovl_path_type old_type; + enum ovl_path_type new_type; + struct dentry *old_upperdir; + struct dentry *new_upperdir; + struct dentry *olddentry; + struct dentry *newdentry; + struct dentry *trap; + bool old_opaque; + bool new_opaque; + bool new_create = false; + bool is_dir = S_ISDIR(old->d_inode->i_mode); + + /* Don't copy up directory trees */ + old_type = ovl_path_type(old); + if (old_type != OVL_PATH_UPPER && is_dir) + return -EXDEV; + + if (new->d_inode) { + new_type = ovl_path_type(new); + + if (new_type == OVL_PATH_LOWER && old_type == OVL_PATH_LOWER) { + if (ovl_dentry_lower(old)->d_inode == + ovl_dentry_lower(new)->d_inode) + return 0; + } + if (new_type != OVL_PATH_LOWER && old_type != OVL_PATH_LOWER) { + if (ovl_dentry_upper(old)->d_inode == + ovl_dentry_upper(new)->d_inode) + return 0; + } + + if (new_type != OVL_PATH_UPPER && + S_ISDIR(new->d_inode->i_mode)) { + err = ovl_check_empty_and_clear(new, new_type); + if (err) + return err; + } + } else { + new_type = OVL_PATH_UPPER; + } + + err = ovl_copy_up(old); + if (err) + return err; + + err = ovl_copy_up(new->d_parent); + if (err) + return err; + + old_upperdir = ovl_dentry_upper(old->d_parent); + new_upperdir = ovl_dentry_upper(new->d_parent); + + trap = lock_rename(new_upperdir, old_upperdir); + + olddentry = ovl_dentry_upper(old); + newdentry = ovl_dentry_upper(new); + if (newdentry) { + dget(newdentry); + } else { + new_create = true; + newdentry = ovl_lookup_create(new_upperdir, new); + err = PTR_ERR(newdentry); + if (IS_ERR(newdentry)) + goto out_unlock; + } + + err = -ESTALE; + if (olddentry->d_parent != old_upperdir) + goto out_dput; + if (newdentry->d_parent != new_upperdir) + goto out_dput; + if (olddentry == trap) + goto out_dput; + if (newdentry == trap) + goto out_dput; + + old_opaque = ovl_dentry_is_opaque(old); + new_opaque = ovl_dentry_is_opaque(new) || new_type != OVL_PATH_UPPER; + + if (is_dir && !old_opaque && new_opaque) { + err = ovl_set_opaque(olddentry); + if (err) + goto out_dput; + } + + err = vfs_rename(old_upperdir->d_inode, olddentry, + new_upperdir->d_inode, newdentry, NULL); + + if (err) { + if (new_create && ovl_dentry_is_opaque(new)) + ovl_whiteout(new_upperdir, new); + if (is_dir && !old_opaque && new_opaque) + ovl_remove_opaque(olddentry); + goto out_dput; + } + + if (old_type != OVL_PATH_UPPER || old_opaque) + err = ovl_whiteout(old_upperdir, old); + if (is_dir && old_opaque && !new_opaque) + ovl_remove_opaque(olddentry); + + if (old_opaque != new_opaque) + ovl_dentry_set_opaque(old, new_opaque); + + ovl_dentry_version_inc(old->d_parent); + ovl_dentry_version_inc(new->d_parent); + +out_dput: + dput(newdentry); +out_unlock: + unlock_rename(new_upperdir, old_upperdir); + return err; +} + +const struct inode_operations ovl_dir_inode_operations = { + .lookup = ovl_lookup, + .mkdir = ovl_mkdir, + .symlink = ovl_symlink, + .unlink = ovl_unlink, + .rmdir = ovl_rmdir, + .rename = ovl_rename, + .link = ovl_link, + .setattr = ovl_setattr, + .create = ovl_create, + .mknod = ovl_mknod, + .permission = ovl_permission, + .getattr = ovl_dir_getattr, + .setxattr = ovl_setxattr, + .getxattr = ovl_getxattr, + .listxattr = ovl_listxattr, + .removexattr = ovl_removexattr, +}; --- linux-3.13.0.orig/fs/overlayfs/overlayfs.h +++ linux-3.13.0/fs/overlayfs/overlayfs.h @@ -0,0 +1,70 @@ +/* + * + * Copyright (C) 2011 Novell Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +struct ovl_entry; + +enum ovl_path_type { + OVL_PATH_UPPER, + OVL_PATH_MERGE, + OVL_PATH_LOWER, +}; + +extern const char *ovl_opaque_xattr; +extern const char *ovl_whiteout_xattr; +extern const struct dentry_operations ovl_dentry_operations; + +enum ovl_path_type ovl_path_type(struct dentry *dentry); +u64 ovl_dentry_version_get(struct dentry *dentry); +void ovl_dentry_version_inc(struct dentry *dentry); +void ovl_path_upper(struct dentry *dentry, struct path *path); +void ovl_path_lower(struct dentry *dentry, struct path *path); +enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path); +struct dentry *ovl_dentry_upper(struct dentry *dentry); +struct dentry *ovl_dentry_lower(struct dentry *dentry); +struct dentry *ovl_dentry_real(struct dentry *dentry); +struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper); +bool ovl_dentry_is_opaque(struct dentry *dentry); +void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque); +bool ovl_is_whiteout(struct dentry *dentry); +void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); +struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags); +struct file *ovl_path_open(struct path *path, int flags); + +struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry, + struct kstat *stat, const char *link); + +/* readdir.c */ +extern const struct file_operations ovl_dir_operations; +int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type); + +/* inode.c */ +int ovl_setattr(struct dentry *dentry, struct iattr *attr); +int ovl_permission(struct inode *inode, int mask); +int ovl_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags); +ssize_t ovl_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size); +ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); +int ovl_removexattr(struct dentry *dentry, const char *name); + +struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, + struct ovl_entry *oe); +static inline void ovl_copyattr(struct inode *from, struct inode *to) +{ + to->i_uid = from->i_uid; + to->i_gid = from->i_gid; +} + +/* dir.c */ +extern const struct inode_operations ovl_dir_inode_operations; + +/* copy_up.c */ +int ovl_copy_up(struct dentry *dentry); +int ovl_copy_up_truncate(struct dentry *dentry, loff_t size); --- linux-3.13.0.orig/fs/overlayfs/Makefile +++ linux-3.13.0/fs/overlayfs/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the overlay filesystem. +# + +obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o + +overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o --- linux-3.13.0.orig/fs/overlayfs/copy_up.c +++ linux-3.13.0/fs/overlayfs/copy_up.c @@ -0,0 +1,376 @@ +/* + * + * Copyright (C) 2011 Novell Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "overlayfs.h" + +#define OVL_COPY_UP_CHUNK_SIZE (1 << 20) + +static int ovl_copy_up_xattr(struct dentry *old, struct dentry *new) +{ + ssize_t list_size, size; + char *buf, *name, *value; + int error; + + if (!old->d_inode->i_op->getxattr || + !new->d_inode->i_op->getxattr) + return 0; + + list_size = vfs_listxattr(old, NULL, 0); + if (list_size <= 0) { + if (list_size == -EOPNOTSUPP) + return 0; + return list_size; + } + + buf = kzalloc(list_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + error = -ENOMEM; + value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL); + if (!value) + goto out; + + list_size = vfs_listxattr(old, buf, list_size); + if (list_size <= 0) { + error = list_size; + goto out_free_value; + } + + for (name = buf; name < (buf + list_size); name += strlen(name) + 1) { + size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX); + if (size <= 0) { + error = size; + goto out_free_value; + } + error = vfs_setxattr(new, name, value, size, 0); + if (error) + goto out_free_value; + } + +out_free_value: + kfree(value); +out: + kfree(buf); + return error; +} + +static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len) +{ + struct file *old_file; + struct file *new_file; + loff_t old_pos = 0; + loff_t new_pos = 0; + int error = 0; + + if (len == 0) + return 0; + + old_file = ovl_path_open(old, O_RDONLY); + if (IS_ERR(old_file)) + return PTR_ERR(old_file); + + new_file = ovl_path_open(new, O_WRONLY); + if (IS_ERR(new_file)) { + error = PTR_ERR(new_file); + goto out_fput; + } + + /* FIXME: copy up sparse files efficiently */ + while (len) { + size_t this_len = OVL_COPY_UP_CHUNK_SIZE; + long bytes; + + if (len < this_len) + this_len = len; + + if (signal_pending_state(TASK_KILLABLE, current)) { + error = -EINTR; + break; + } + + bytes = do_splice_direct(old_file, &old_pos, + new_file, &new_pos, + this_len, SPLICE_F_MOVE); + if (bytes <= 0) { + error = bytes; + break; + } + WARN_ON(old_pos != new_pos); + + len -= bytes; + } + + fput(new_file); +out_fput: + fput(old_file); + return error; +} + +static char *ovl_read_symlink(struct dentry *realdentry) +{ + int res; + char *buf; + struct inode *inode = realdentry->d_inode; + mm_segment_t old_fs; + + res = -EINVAL; + if (!inode->i_op->readlink) + goto err; + + res = -ENOMEM; + buf = (char *) __get_free_page(GFP_KERNEL); + if (!buf) + goto err; + + old_fs = get_fs(); + set_fs(get_ds()); + /* The cast to a user pointer is valid due to the set_fs() */ + res = inode->i_op->readlink(realdentry, + (char __user *)buf, PAGE_SIZE - 1); + set_fs(old_fs); + if (res < 0) { + free_page((unsigned long) buf); + goto err; + } + buf[res] = '\0'; + + return buf; + +err: + return ERR_PTR(res); +} + +static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) +{ + struct iattr attr = { + .ia_valid = + ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SET | ATTR_MTIME_SET, + .ia_atime = stat->atime, + .ia_mtime = stat->mtime, + }; + + return notify_change(upperdentry, &attr, NULL); +} + +static int ovl_set_mode(struct dentry *upperdentry, umode_t mode) +{ + struct iattr attr = { + .ia_valid = ATTR_MODE, + .ia_mode = mode, + }; + + return notify_change(upperdentry, &attr, NULL); +} + +static int ovl_copy_up_locked(struct dentry *upperdir, struct dentry *dentry, + struct path *lowerpath, struct kstat *stat, + const char *link) +{ + int err; + struct path newpath; + umode_t mode = stat->mode; + + /* Can't properly set mode on creation because of the umask */ + stat->mode &= S_IFMT; + + ovl_path_upper(dentry, &newpath); + WARN_ON(newpath.dentry); + newpath.dentry = ovl_upper_create(upperdir, dentry, stat, link); + if (IS_ERR(newpath.dentry)) + return PTR_ERR(newpath.dentry); + + if (S_ISREG(stat->mode)) { + err = ovl_copy_up_data(lowerpath, &newpath, stat->size); + if (err) + goto err_remove; + } + + err = ovl_copy_up_xattr(lowerpath->dentry, newpath.dentry); + if (err) + goto err_remove; + + mutex_lock(&newpath.dentry->d_inode->i_mutex); + if (!S_ISLNK(stat->mode)) + err = ovl_set_mode(newpath.dentry, mode); + if (!err) + err = ovl_set_timestamps(newpath.dentry, stat); + mutex_unlock(&newpath.dentry->d_inode->i_mutex); + if (err) + goto err_remove; + + ovl_dentry_update(dentry, newpath.dentry); + + /* + * Easiest way to get rid of the lower dentry reference is to + * drop this dentry. This is neither needed nor possible for + * directories. + */ + if (!S_ISDIR(stat->mode)) + d_drop(dentry); + + return 0; + +err_remove: + if (S_ISDIR(stat->mode)) + vfs_rmdir(upperdir->d_inode, newpath.dentry); + else + vfs_unlink(upperdir->d_inode, newpath.dentry, NULL); + + dput(newpath.dentry); + + return err; +} + +/* + * Copy up a single dentry + * + * Directory renames only allowed on "pure upper" (already created on + * upper filesystem, never copied up). Directories which are on lower or + * are merged may not be renamed. For these -EXDEV is returned and + * userspace has to deal with it. This means, when copying up a + * directory we can rely on it and ancestors being stable. + * + * Non-directory renames start with copy up of source if necessary. The + * actual rename will only proceed once the copy up was successful. Copy + * up uses upper parent i_mutex for exclusion. Since rename can change + * d_parent it is possible that the copy up will lock the old parent. At + * that point the file will have already been copied up anyway. + */ +static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, + struct path *lowerpath, struct kstat *stat) +{ + int err; + struct kstat pstat; + struct path parentpath; + struct dentry *upperdir; + const struct cred *old_cred; + struct cred *override_cred; + char *link = NULL; + + ovl_path_upper(parent, &parentpath); + upperdir = parentpath.dentry; + + err = vfs_getattr(&parentpath, &pstat); + if (err) + return err; + + if (S_ISLNK(stat->mode)) { + link = ovl_read_symlink(lowerpath->dentry); + if (IS_ERR(link)) + return PTR_ERR(link); + } + + err = -ENOMEM; + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) + goto out_free_link; + + override_cred->fsuid = stat->uid; + override_cred->fsgid = stat->gid; + old_cred = override_creds(override_cred); + + mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); + if (ovl_path_type(dentry) != OVL_PATH_LOWER) { + err = 0; + } else { + err = ovl_copy_up_locked(upperdir, dentry, lowerpath, + stat, link); + if (!err) { + /* Restore timestamps on parent (best effort) */ + ovl_set_timestamps(upperdir, &pstat); + } + } + + mutex_unlock(&upperdir->d_inode->i_mutex); + + revert_creds(old_cred); + put_cred(override_cred); + +out_free_link: + if (link) + free_page((unsigned long) link); + + return err; +} + +int ovl_copy_up(struct dentry *dentry) +{ + int err; + + err = 0; + while (!err) { + struct dentry *next; + struct dentry *parent; + struct path lowerpath; + struct kstat stat; + enum ovl_path_type type = ovl_path_type(dentry); + + if (type != OVL_PATH_LOWER) + break; + + next = dget(dentry); + /* find the topmost dentry not yet copied up */ + for (;;) { + parent = dget_parent(next); + + type = ovl_path_type(parent); + if (type != OVL_PATH_LOWER) + break; + + dput(next); + next = parent; + } + + ovl_path_lower(next, &lowerpath); + err = vfs_getattr(&lowerpath, &stat); + if (!err) + err = ovl_copy_up_one(parent, next, &lowerpath, &stat); + + dput(parent); + dput(next); + } + + return err; +} + +/* Optimize by not copying up the file first and truncating later */ +int ovl_copy_up_truncate(struct dentry *dentry, loff_t size) +{ + int err; + struct kstat stat; + struct path lowerpath; + struct dentry *parent = dget_parent(dentry); + + err = ovl_copy_up(parent); + if (err) + goto out_dput_parent; + + ovl_path_lower(dentry, &lowerpath); + err = vfs_getattr(&lowerpath, &stat); + if (err) + goto out_dput_parent; + + if (size < stat.size) + stat.size = size; + + err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat); + +out_dput_parent: + dput(parent); + return err; +} --- linux-3.13.0.orig/fs/overlayfs/Kconfig +++ linux-3.13.0/fs/overlayfs/Kconfig @@ -0,0 +1,10 @@ +config OVERLAYFS_FS + tristate "Overlay filesystem support" + help + An overlay filesystem combines two filesystems - an 'upper' filesystem + and a 'lower' filesystem. When a name exists in both filesystems, the + object in the 'upper' filesystem is visible while the object in the + 'lower' filesystem is either hidden or, in the case of directories, + merged with the 'upper' object. + + For more information see Documentation/filesystems/overlayfs.txt --- linux-3.13.0.orig/fs/overlayfs/inode.c +++ linux-3.13.0/fs/overlayfs/inode.c @@ -0,0 +1,372 @@ +/* + * + * Copyright (C) 2011 Novell Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include "overlayfs.h" + +int ovl_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct dentry *upperdentry; + int err; + + if ((attr->ia_valid & ATTR_SIZE) && !ovl_dentry_upper(dentry)) + err = ovl_copy_up_truncate(dentry, attr->ia_size); + else + err = ovl_copy_up(dentry); + if (err) + return err; + + upperdentry = ovl_dentry_upper(dentry); + + if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) + attr->ia_valid &= ~ATTR_MODE; + + mutex_lock(&upperdentry->d_inode->i_mutex); + err = notify_change(upperdentry, attr, NULL); + if (!err) + ovl_copyattr(upperdentry->d_inode, dentry->d_inode); + mutex_unlock(&upperdentry->d_inode->i_mutex); + + return err; +} + +static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct path realpath; + + ovl_path_real(dentry, &realpath); + return vfs_getattr(&realpath, stat); +} + +int ovl_permission(struct inode *inode, int mask) +{ + struct ovl_entry *oe; + struct dentry *alias = NULL; + struct inode *realinode; + struct dentry *realdentry; + bool is_upper; + int err; + + if (S_ISDIR(inode->i_mode)) { + oe = inode->i_private; + } else if (mask & MAY_NOT_BLOCK) { + return -ECHILD; + } else { + /* + * For non-directories find an alias and get the info + * from there. + */ + alias = d_find_any_alias(inode); + if (WARN_ON(!alias)) + return -ENOENT; + + oe = alias->d_fsdata; + } + + realdentry = ovl_entry_real(oe, &is_upper); + + /* Careful in RCU walk mode */ + realinode = ACCESS_ONCE(realdentry->d_inode); + if (!realinode) { + WARN_ON(!(mask & MAY_NOT_BLOCK)); + err = -ENOENT; + goto out_dput; + } + + if (mask & MAY_WRITE) { + umode_t mode = realinode->i_mode; + + /* + * Writes will always be redirected to upper layer, so + * ignore lower layer being read-only. + * + * If the overlay itself is read-only then proceed + * with the permission check, don't return EROFS. + * This will only happen if this is the lower layer of + * another overlayfs. + * + * If upper fs becomes read-only after the overlay was + * constructed return EROFS to prevent modification of + * upper layer. + */ + err = -EROFS; + if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + goto out_dput; + } + + err = __inode_permission(realinode, mask); +out_dput: + dput(alias); + return err; +} + + +struct ovl_link_data { + struct dentry *realdentry; + void *cookie; +}; + +static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + void *ret; + struct dentry *realdentry; + struct inode *realinode; + + realdentry = ovl_dentry_real(dentry); + realinode = realdentry->d_inode; + + if (WARN_ON(!realinode->i_op->follow_link)) + return ERR_PTR(-EPERM); + + ret = realinode->i_op->follow_link(realdentry, nd); + if (IS_ERR(ret)) + return ret; + + if (realinode->i_op->put_link) { + struct ovl_link_data *data; + + data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL); + if (!data) { + realinode->i_op->put_link(realdentry, nd, ret); + return ERR_PTR(-ENOMEM); + } + data->realdentry = realdentry; + data->cookie = ret; + + return data; + } else { + return NULL; + } +} + +static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c) +{ + struct inode *realinode; + struct ovl_link_data *data = c; + + if (!data) + return; + + realinode = data->realdentry->d_inode; + realinode->i_op->put_link(data->realdentry, nd, data->cookie); + kfree(data); +} + +static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz) +{ + struct path realpath; + struct inode *realinode; + + ovl_path_real(dentry, &realpath); + realinode = realpath.dentry->d_inode; + + if (!realinode->i_op->readlink) + return -EINVAL; + + touch_atime(&realpath); + + return realinode->i_op->readlink(realpath.dentry, buf, bufsiz); +} + + +static bool ovl_is_private_xattr(const char *name) +{ + return strncmp(name, "trusted.overlay.", 14) == 0; +} + +int ovl_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + int err; + struct dentry *upperdentry; + + if (ovl_is_private_xattr(name)) + return -EPERM; + + err = ovl_copy_up(dentry); + if (err) + return err; + + upperdentry = ovl_dentry_upper(dentry); + return vfs_setxattr(upperdentry, name, value, size, flags); +} + +ssize_t ovl_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size) +{ + if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && + ovl_is_private_xattr(name)) + return -ENODATA; + + return vfs_getxattr(ovl_dentry_real(dentry), name, value, size); +} + +ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) +{ + ssize_t res; + int off; + + res = vfs_listxattr(ovl_dentry_real(dentry), list, size); + if (res <= 0 || size == 0) + return res; + + if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE) + return res; + + /* filter out private xattrs */ + for (off = 0; off < res;) { + char *s = list + off; + size_t slen = strlen(s) + 1; + + BUG_ON(off + slen > res); + + if (ovl_is_private_xattr(s)) { + res -= slen; + memmove(s, s + slen, res - off); + } else { + off += slen; + } + } + + return res; +} + +int ovl_removexattr(struct dentry *dentry, const char *name) +{ + int err; + struct path realpath; + enum ovl_path_type type; + + if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && + ovl_is_private_xattr(name)) + return -ENODATA; + + type = ovl_path_real(dentry, &realpath); + if (type == OVL_PATH_LOWER) { + err = vfs_getxattr(realpath.dentry, name, NULL, 0); + if (err < 0) + return err; + + err = ovl_copy_up(dentry); + if (err) + return err; + + ovl_path_upper(dentry, &realpath); + } + + return vfs_removexattr(realpath.dentry, name); +} + +static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, + struct dentry *realdentry) +{ + if (type != OVL_PATH_LOWER) + return false; + + if (special_file(realdentry->d_inode->i_mode)) + return false; + + if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC)) + return false; + + return true; +} + +static int ovl_dentry_open(struct dentry *dentry, struct file *file, + const struct cred *cred) +{ + int err; + struct path realpath; + enum ovl_path_type type; + + type = ovl_path_real(dentry, &realpath); + if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) { + if (file->f_flags & O_TRUNC) + err = ovl_copy_up_truncate(dentry, 0); + else + err = ovl_copy_up(dentry); + if (err) + return err; + + ovl_path_upper(dentry, &realpath); + } + + return vfs_open(&realpath, file, cred); +} + +static const struct inode_operations ovl_file_inode_operations = { + .setattr = ovl_setattr, + .permission = ovl_permission, + .getattr = ovl_getattr, + .setxattr = ovl_setxattr, + .getxattr = ovl_getxattr, + .listxattr = ovl_listxattr, + .removexattr = ovl_removexattr, + .dentry_open = ovl_dentry_open, +}; + +static const struct inode_operations ovl_symlink_inode_operations = { + .setattr = ovl_setattr, + .follow_link = ovl_follow_link, + .put_link = ovl_put_link, + .readlink = ovl_readlink, + .getattr = ovl_getattr, + .setxattr = ovl_setxattr, + .getxattr = ovl_getxattr, + .listxattr = ovl_listxattr, + .removexattr = ovl_removexattr, +}; + +struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, + struct ovl_entry *oe) +{ + struct inode *inode; + + inode = new_inode(sb); + if (!inode) + return NULL; + + mode &= S_IFMT; + + inode->i_ino = get_next_ino(); + inode->i_mode = mode; + inode->i_flags |= S_NOATIME | S_NOCMTIME; + + switch (mode) { + case S_IFDIR: + inode->i_private = oe; + inode->i_op = &ovl_dir_inode_operations; + inode->i_fop = &ovl_dir_operations; + break; + + case S_IFLNK: + inode->i_op = &ovl_symlink_inode_operations; + break; + + case S_IFREG: + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + inode->i_op = &ovl_file_inode_operations; + break; + + default: + WARN(1, "illegal file type: %i\n", mode); + iput(inode); + inode = NULL; + } + + return inode; + +} --- linux-3.13.0.orig/fs/overlayfs/super.c +++ linux-3.13.0/fs/overlayfs/super.c @@ -0,0 +1,684 @@ +/* + * + * Copyright (C) 2011 Novell Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "overlayfs.h" + +MODULE_AUTHOR("Miklos Szeredi "); +MODULE_DESCRIPTION("Overlay filesystem"); +MODULE_LICENSE("GPL"); + +#define OVERLAYFS_SUPER_MAGIC 0x794c764f + +struct ovl_config { + char *lowerdir; + char *upperdir; +}; + +/* private information held for overlayfs's superblock */ +struct ovl_fs { + struct vfsmount *upper_mnt; + struct vfsmount *lower_mnt; + long lower_namelen; + /* pathnames of lower and upper dirs, for show_options */ + struct ovl_config config; +}; + +/* private information held for every overlayfs dentry */ +struct ovl_entry { + /* + * Keep "double reference" on upper dentries, so that + * d_delete() doesn't think it's OK to reset d_inode to NULL. + */ + struct dentry *__upperdentry; + struct dentry *lowerdentry; + union { + struct { + u64 version; + bool opaque; + }; + struct rcu_head rcu; + }; +}; + +const char *ovl_whiteout_xattr = "trusted.overlay.whiteout"; +const char *ovl_opaque_xattr = "trusted.overlay.opaque"; + + +enum ovl_path_type ovl_path_type(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + + if (oe->__upperdentry) { + if (oe->lowerdentry && S_ISDIR(dentry->d_inode->i_mode)) + return OVL_PATH_MERGE; + else + return OVL_PATH_UPPER; + } else { + return OVL_PATH_LOWER; + } +} + +static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe) +{ + struct dentry *upperdentry = ACCESS_ONCE(oe->__upperdentry); + smp_read_barrier_depends(); + return upperdentry; +} + +void ovl_path_upper(struct dentry *dentry, struct path *path) +{ + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + struct ovl_entry *oe = dentry->d_fsdata; + + path->mnt = ofs->upper_mnt; + path->dentry = ovl_upperdentry_dereference(oe); +} + +void ovl_path_lower(struct dentry *dentry, struct path *path) +{ + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + struct ovl_entry *oe = dentry->d_fsdata; + + path->mnt = ofs->lower_mnt; + path->dentry = oe->lowerdentry; +} + +enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) +{ + + enum ovl_path_type type = ovl_path_type(dentry); + + if (type == OVL_PATH_LOWER) + ovl_path_lower(dentry, path); + else + ovl_path_upper(dentry, path); + + return type; +} + +struct dentry *ovl_dentry_upper(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + + return ovl_upperdentry_dereference(oe); +} + +struct dentry *ovl_dentry_lower(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + + return oe->lowerdentry; +} + +struct dentry *ovl_dentry_real(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + struct dentry *realdentry; + + realdentry = ovl_upperdentry_dereference(oe); + if (!realdentry) + realdentry = oe->lowerdentry; + + return realdentry; +} + +struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper) +{ + struct dentry *realdentry; + + realdentry = ovl_upperdentry_dereference(oe); + if (realdentry) { + *is_upper = true; + } else { + realdentry = oe->lowerdentry; + *is_upper = false; + } + return realdentry; +} + +bool ovl_dentry_is_opaque(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + return oe->opaque; +} + +void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque) +{ + struct ovl_entry *oe = dentry->d_fsdata; + oe->opaque = opaque; +} + +void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + + WARN_ON(!mutex_is_locked(&upperdentry->d_parent->d_inode->i_mutex)); + WARN_ON(oe->__upperdentry); + BUG_ON(!upperdentry->d_inode); + smp_wmb(); + oe->__upperdentry = dget(upperdentry); +} + +void ovl_dentry_version_inc(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + + WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); + oe->version++; +} + +u64 ovl_dentry_version_get(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + + WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); + return oe->version; +} + +bool ovl_is_whiteout(struct dentry *dentry) +{ + int res; + char val; + + if (!dentry) + return false; + if (!dentry->d_inode) + return false; + if (!S_ISLNK(dentry->d_inode->i_mode)) + return false; + + res = vfs_getxattr(dentry, ovl_whiteout_xattr, &val, 1); + if (res == 1 && val == 'y') + return true; + + return false; +} + +static bool ovl_is_opaquedir(struct dentry *dentry) +{ + int res; + char val; + + if (!S_ISDIR(dentry->d_inode->i_mode)) + return false; + + res = vfs_getxattr(dentry, ovl_opaque_xattr, &val, 1); + if (res == 1 && val == 'y') + return true; + + return false; +} + +static void ovl_entry_free(struct rcu_head *head) +{ + struct ovl_entry *oe = container_of(head, struct ovl_entry, rcu); + kfree(oe); +} + +static void ovl_dentry_release(struct dentry *dentry) +{ + struct ovl_entry *oe = dentry->d_fsdata; + + if (oe) { + dput(oe->__upperdentry); + dput(oe->__upperdentry); + dput(oe->lowerdentry); + call_rcu(&oe->rcu, ovl_entry_free); + } +} + +const struct dentry_operations ovl_dentry_operations = { + .d_release = ovl_dentry_release, +}; + +static struct ovl_entry *ovl_alloc_entry(void) +{ + return kzalloc(sizeof(struct ovl_entry), GFP_KERNEL); +} + +static inline struct dentry *ovl_lookup_real(struct dentry *dir, + struct qstr *name) +{ + struct dentry *dentry; + + mutex_lock(&dir->d_inode->i_mutex); + dentry = lookup_one_len(name->name, dir, name->len); + mutex_unlock(&dir->d_inode->i_mutex); + + if (IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -ENOENT) + dentry = NULL; + } else if (!dentry->d_inode) { + dput(dentry); + dentry = NULL; + } + return dentry; +} + +static int ovl_do_lookup(struct dentry *dentry) +{ + struct ovl_entry *oe; + struct dentry *upperdir; + struct dentry *lowerdir; + struct dentry *upperdentry = NULL; + struct dentry *lowerdentry = NULL; + struct inode *inode = NULL; + int err; + + err = -ENOMEM; + oe = ovl_alloc_entry(); + if (!oe) + goto out; + + upperdir = ovl_dentry_upper(dentry->d_parent); + lowerdir = ovl_dentry_lower(dentry->d_parent); + + if (upperdir) { + upperdentry = ovl_lookup_real(upperdir, &dentry->d_name); + err = PTR_ERR(upperdentry); + if (IS_ERR(upperdentry)) + goto out_put_dir; + + if (lowerdir && upperdentry && + (S_ISLNK(upperdentry->d_inode->i_mode) || + S_ISDIR(upperdentry->d_inode->i_mode))) { + const struct cred *old_cred; + struct cred *override_cred; + + err = -ENOMEM; + override_cred = prepare_kernel_cred(NULL); + if (!override_cred) + goto out_dput_upper; + + old_cred = override_creds(override_cred); + + if (ovl_is_opaquedir(upperdentry)) { + oe->opaque = true; + } else if (ovl_is_whiteout(upperdentry)) { + dput(upperdentry); + upperdentry = NULL; + oe->opaque = true; + } + revert_creds(old_cred); + put_cred(override_cred); + } + } + if (lowerdir && !oe->opaque) { + lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name); + err = PTR_ERR(lowerdentry); + if (IS_ERR(lowerdentry)) + goto out_dput_upper; + } + + if (lowerdentry && upperdentry && + (!S_ISDIR(upperdentry->d_inode->i_mode) || + !S_ISDIR(lowerdentry->d_inode->i_mode))) { + dput(lowerdentry); + lowerdentry = NULL; + oe->opaque = true; + } + + if (lowerdentry || upperdentry) { + struct dentry *realdentry; + + realdentry = upperdentry ? upperdentry : lowerdentry; + err = -ENOMEM; + inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, + oe); + if (!inode) + goto out_dput; + ovl_copyattr(realdentry->d_inode, inode); + } + + if (upperdentry) + oe->__upperdentry = dget(upperdentry); + + if (lowerdentry) + oe->lowerdentry = lowerdentry; + + dentry->d_fsdata = oe; + dentry->d_op = &ovl_dentry_operations; + d_add(dentry, inode); + + return 0; + +out_dput: + dput(lowerdentry); +out_dput_upper: + dput(upperdentry); +out_put_dir: + kfree(oe); +out: + return err; +} + +struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + int err = ovl_do_lookup(dentry); + + if (err) + return ERR_PTR(err); + + return NULL; +} + +struct file *ovl_path_open(struct path *path, int flags) +{ + return dentry_open(path, flags, current_cred()); +} + +static void ovl_put_super(struct super_block *sb) +{ + struct ovl_fs *ufs = sb->s_fs_info; + + if (!(sb->s_flags & MS_RDONLY)) + mnt_drop_write(ufs->upper_mnt); + + mntput(ufs->upper_mnt); + mntput(ufs->lower_mnt); + + kfree(ufs->config.lowerdir); + kfree(ufs->config.upperdir); + kfree(ufs); +} + +static int ovl_remount_fs(struct super_block *sb, int *flagsp, char *data) +{ + int flags = *flagsp; + struct ovl_fs *ufs = sb->s_fs_info; + + /* When remounting rw or ro, we need to adjust the write access to the + * upper fs. + */ + if (((flags ^ sb->s_flags) & MS_RDONLY) == 0) + /* No change to readonly status */ + return 0; + + if (flags & MS_RDONLY) { + mnt_drop_write(ufs->upper_mnt); + return 0; + } else + return mnt_want_write(ufs->upper_mnt); +} + +/** + * ovl_statfs + * @sb: The overlayfs super block + * @buf: The struct kstatfs to fill in with stats + * + * Get the filesystem statistics. As writes always target the upper layer + * filesystem pass the statfs to the same filesystem. + */ +static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + struct dentry *root_dentry = dentry->d_sb->s_root; + struct path path; + int err; + + ovl_path_upper(root_dentry, &path); + + err = vfs_statfs(&path, buf); + if (!err) { + buf->f_namelen = max(buf->f_namelen, ofs->lower_namelen); + buf->f_type = OVERLAYFS_SUPER_MAGIC; + } + + return err; +} + +/** + * ovl_show_options + * + * Prints the mount options for a given superblock. + * Returns zero; does not fail. + */ +static int ovl_show_options(struct seq_file *m, struct dentry *dentry) +{ + struct super_block *sb = dentry->d_sb; + struct ovl_fs *ufs = sb->s_fs_info; + + seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); + seq_printf(m, ",upperdir=%s", ufs->config.upperdir); + return 0; +} + +static const struct super_operations ovl_super_operations = { + .put_super = ovl_put_super, + .remount_fs = ovl_remount_fs, + .statfs = ovl_statfs, + .show_options = ovl_show_options, +}; + +enum { + OPT_LOWERDIR, + OPT_UPPERDIR, + OPT_ERR, +}; + +static const match_table_t ovl_tokens = { + {OPT_LOWERDIR, "lowerdir=%s"}, + {OPT_UPPERDIR, "upperdir=%s"}, + {OPT_ERR, NULL} +}; + +static int ovl_parse_opt(char *opt, struct ovl_config *config) +{ + char *p; + + config->upperdir = NULL; + config->lowerdir = NULL; + + while ((p = strsep(&opt, ",")) != NULL) { + int token; + substring_t args[MAX_OPT_ARGS]; + + if (!*p) + continue; + + token = match_token(p, ovl_tokens, args); + switch (token) { + case OPT_UPPERDIR: + kfree(config->upperdir); + config->upperdir = match_strdup(&args[0]); + if (!config->upperdir) + return -ENOMEM; + break; + + case OPT_LOWERDIR: + kfree(config->lowerdir); + config->lowerdir = match_strdup(&args[0]); + if (!config->lowerdir) + return -ENOMEM; + break; + + default: + return -EINVAL; + } + } + return 0; +} + +static int ovl_fill_super(struct super_block *sb, void *data, int silent) +{ + struct path lowerpath; + struct path upperpath; + struct inode *root_inode; + struct dentry *root_dentry; + struct ovl_entry *oe; + struct ovl_fs *ufs; + struct kstatfs statfs; + int err; + + err = -ENOMEM; + ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); + if (!ufs) + goto out; + + err = ovl_parse_opt((char *) data, &ufs->config); + if (err) + goto out_free_ufs; + + err = -EINVAL; + if (!ufs->config.upperdir || !ufs->config.lowerdir) { + pr_err("overlayfs: missing upperdir or lowerdir\n"); + goto out_free_config; + } + + oe = ovl_alloc_entry(); + if (oe == NULL) + goto out_free_config; + + err = kern_path(ufs->config.upperdir, LOOKUP_FOLLOW, &upperpath); + if (err) + goto out_free_oe; + + err = kern_path(ufs->config.lowerdir, LOOKUP_FOLLOW, &lowerpath); + if (err) + goto out_put_upperpath; + + err = -ENOTDIR; + if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || + !S_ISDIR(lowerpath.dentry->d_inode->i_mode)) + goto out_put_lowerpath; + + err = vfs_statfs(&lowerpath, &statfs); + if (err) { + pr_err("overlayfs: statfs failed on lowerpath\n"); + goto out_put_lowerpath; + } + ufs->lower_namelen = statfs.f_namelen; + + sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, + lowerpath.mnt->mnt_sb->s_stack_depth) + 1; + + err = -EINVAL; + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("overlayfs: maximum fs stacking depth exceeded\n"); + goto out_put_lowerpath; + } + + + ufs->upper_mnt = clone_private_mount(&upperpath); + err = PTR_ERR(ufs->upper_mnt); + if (IS_ERR(ufs->upper_mnt)) { + pr_err("overlayfs: failed to clone upperpath\n"); + goto out_put_lowerpath; + } + + ufs->lower_mnt = clone_private_mount(&lowerpath); + err = PTR_ERR(ufs->lower_mnt); + if (IS_ERR(ufs->lower_mnt)) { + pr_err("overlayfs: failed to clone lowerpath\n"); + goto out_put_upper_mnt; + } + + /* + * Make lower_mnt R/O. That way fchmod/fchown on lower file + * will fail instead of modifying lower fs. + */ + ufs->lower_mnt->mnt_flags |= MNT_READONLY; + + /* If the upper fs is r/o, we mark overlayfs r/o too */ + if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) + sb->s_flags |= MS_RDONLY; + + if (!(sb->s_flags & MS_RDONLY)) { + err = mnt_want_write(ufs->upper_mnt); + if (err) + goto out_put_lower_mnt; + } + + err = -ENOMEM; + root_inode = ovl_new_inode(sb, S_IFDIR, oe); + if (!root_inode) + goto out_drop_write; + + root_dentry = d_make_root(root_inode); + if (!root_dentry) + goto out_drop_write; + + mntput(upperpath.mnt); + mntput(lowerpath.mnt); + + oe->__upperdentry = dget(upperpath.dentry); + oe->lowerdentry = lowerpath.dentry; + + root_dentry->d_fsdata = oe; + root_dentry->d_op = &ovl_dentry_operations; + + sb->s_magic = OVERLAYFS_SUPER_MAGIC; + sb->s_op = &ovl_super_operations; + sb->s_root = root_dentry; + sb->s_fs_info = ufs; + + return 0; + +out_drop_write: + if (!(sb->s_flags & MS_RDONLY)) + mnt_drop_write(ufs->upper_mnt); +out_put_lower_mnt: + mntput(ufs->lower_mnt); +out_put_upper_mnt: + mntput(ufs->upper_mnt); +out_put_lowerpath: + path_put(&lowerpath); +out_put_upperpath: + path_put(&upperpath); +out_free_oe: + kfree(oe); +out_free_config: + kfree(ufs->config.lowerdir); + kfree(ufs->config.upperdir); +out_free_ufs: + kfree(ufs); +out: + return err; +} + +static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) +{ + return mount_nodev(fs_type, flags, raw_data, ovl_fill_super); +} + +static struct file_system_type ovl_fs_type = { + .owner = THIS_MODULE, + .name = "overlayfs", + .mount = ovl_mount, + .kill_sb = kill_anon_super, + .fs_flags = FS_USERNS_MOUNT, +}; +MODULE_ALIAS_FS("overlayfs"); + +static int __init ovl_init(void) +{ + return register_filesystem(&ovl_fs_type); +} + +static void __exit ovl_exit(void) +{ + unregister_filesystem(&ovl_fs_type); +} + +module_init(ovl_init); +module_exit(ovl_exit); --- linux-3.13.0.orig/fs/hpfs/alloc.c +++ linux-3.13.0/fs/hpfs/alloc.c @@ -8,6 +8,58 @@ #include "hpfs_fn.h" +static void hpfs_claim_alloc(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free != (unsigned)-1) { + if (unlikely(!sbi->sb_n_free)) { + hpfs_error(s, "free count underflow, allocating sector %08x", sec); + sbi->sb_n_free = -1; + return; + } + sbi->sb_n_free--; + } +} + +static void hpfs_claim_free(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free != (unsigned)-1) { + if (unlikely(sbi->sb_n_free >= sbi->sb_fs_size)) { + hpfs_error(s, "free count overflow, freeing sector %08x", sec); + sbi->sb_n_free = -1; + return; + } + sbi->sb_n_free++; + } +} + +static void hpfs_claim_dirband_alloc(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free_dnodes != (unsigned)-1) { + if (unlikely(!sbi->sb_n_free_dnodes)) { + hpfs_error(s, "dirband free count underflow, allocating sector %08x", sec); + sbi->sb_n_free_dnodes = -1; + return; + } + sbi->sb_n_free_dnodes--; + } +} + +static void hpfs_claim_dirband_free(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free_dnodes != (unsigned)-1) { + if (unlikely(sbi->sb_n_free_dnodes >= sbi->sb_dirband_size / 4)) { + hpfs_error(s, "dirband free count overflow, freeing sector %08x", sec); + sbi->sb_n_free_dnodes = -1; + return; + } + sbi->sb_n_free_dnodes++; + } +} + /* * Check if a sector is allocated in bitmap * This is really slow. Turned on only if chk==2 @@ -203,9 +255,15 @@ } sec = 0; ret: + if (sec) { + i = 0; + do + hpfs_claim_alloc(s, sec + i); + while (unlikely(++i < n)); + } if (sec && f_p) { for (i = 0; i < forward; i++) { - if (!hpfs_alloc_if_possible(s, sec + i + 1)) { + if (!hpfs_alloc_if_possible(s, sec + n + i)) { hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i); sec = 0; break; @@ -228,6 +286,7 @@ nr >>= 2; sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0); if (!sec) return 0; + hpfs_claim_dirband_alloc(s, sec); return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start; } @@ -242,6 +301,7 @@ bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f))); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); + hpfs_claim_alloc(s, sec); return 1; } hpfs_brelse4(&qbh); @@ -275,6 +335,7 @@ return; } bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f)); + hpfs_claim_free(s, sec); if (!--n) { hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); @@ -359,6 +420,7 @@ bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f)); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); + hpfs_claim_dirband_free(s, dno); } } @@ -366,7 +428,7 @@ dnode_secno *dno, struct quad_buffer_head *qbh) { struct dnode *d; - if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) { + if (hpfs_get_free_dnodes(s) > FREE_DNODES_ADD) { if (!(*dno = alloc_in_dirband(s, near))) if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL; } else { --- linux-3.13.0.orig/fs/hpfs/hpfs_fn.h +++ linux-3.13.0/fs/hpfs/hpfs_fn.h @@ -312,7 +312,7 @@ __printf(2, 3) void hpfs_error(struct super_block *, const char *, ...); int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); -unsigned hpfs_count_one_bitmap(struct super_block *, secno); +unsigned hpfs_get_free_dnodes(struct super_block *); /* * local time (HPFS) to GMT (Unix) --- linux-3.13.0.orig/fs/hpfs/super.c +++ linux-3.13.0/fs/hpfs/super.c @@ -121,7 +121,7 @@ call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi); } -unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) +static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) { struct quad_buffer_head qbh; unsigned long *bits; @@ -129,7 +129,7 @@ bits = hpfs_map_4sectors(s, secno, &qbh, 0); if (!bits) - return 0; + return (unsigned)-1; count = bitmap_weight(bits, 2048 * BITS_PER_BYTE); hpfs_brelse4(&qbh); return count; @@ -144,30 +144,45 @@ hpfs_prefetch_bitmap(s, n); } for (n = 0; n < n_bands; n++) { + unsigned c; hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD); - count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); + c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); + if (c != (unsigned)-1) + count += c; } return count; } +unsigned hpfs_get_free_dnodes(struct super_block *s) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free_dnodes == (unsigned)-1) { + unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap); + if (c == (unsigned)-1) + return 0; + sbi->sb_n_free_dnodes = c; + } + return sbi->sb_n_free_dnodes; +} + static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *s = dentry->d_sb; struct hpfs_sb_info *sbi = hpfs_sb(s); u64 id = huge_encode_dev(s->s_bdev->bd_dev); + hpfs_lock(s); - /*if (sbi->sb_n_free == -1) {*/ + if (sbi->sb_n_free == (unsigned)-1) sbi->sb_n_free = count_bitmaps(s); - sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap); - /*}*/ + buf->f_type = s->s_magic; buf->f_bsize = 512; buf->f_blocks = sbi->sb_fs_size; buf->f_bfree = sbi->sb_n_free; buf->f_bavail = sbi->sb_n_free; buf->f_files = sbi->sb_dirband_size / 4; - buf->f_ffree = sbi->sb_n_free_dnodes; + buf->f_ffree = hpfs_get_free_dnodes(s); buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[1] = (u32)(id >> 32); buf->f_namelen = 254; --- linux-3.13.0.orig/fs/exofs/ore.c +++ linux-3.13.0/fs/exofs/ore.c @@ -103,7 +103,7 @@ layout->max_io_length = (BIO_MAX_PAGES_KMALLOC * PAGE_SIZE - layout->stripe_unit) * - layout->group_width; + (layout->group_width - layout->parity); if (layout->parity) { unsigned stripe_length = (layout->group_width - layout->parity) * @@ -286,7 +286,8 @@ if (length) { ore_calc_stripe_info(layout, offset, length, &ios->si); ios->length = ios->si.length; - ios->nr_pages = (ios->length + PAGE_SIZE - 1) / PAGE_SIZE; + ios->nr_pages = ((ios->offset & (PAGE_SIZE - 1)) + + ios->length + PAGE_SIZE - 1) / PAGE_SIZE; if (layout->parity) _ore_post_alloc_raid_stuff(ios); } @@ -536,6 +537,7 @@ u64 H = LmodS - G * T; u32 N = div_u64(H, U); + u32 Nlast; /* "H - (N * U)" is just "H % U" so it's bound to u32 */ u32 C = (u32)(H - (N * U)) / stripe_unit + G * group_width; @@ -568,6 +570,10 @@ si->length = T - H; if (si->length > length) si->length = length; + + Nlast = div_u64(H + si->length + U - 1, U); + si->maxdevUnits = Nlast - N; + si->M = M; } EXPORT_SYMBOL(ore_calc_stripe_info); @@ -583,13 +589,16 @@ int ret; if (per_dev->bio == NULL) { - unsigned pages_in_stripe = ios->layout->group_width * - (ios->layout->stripe_unit / PAGE_SIZE); - unsigned nr_pages = ios->nr_pages * ios->layout->group_width / - (ios->layout->group_width - - ios->layout->parity); - unsigned bio_size = (nr_pages + pages_in_stripe) / - ios->layout->group_width; + unsigned bio_size; + + if (!ios->reading) { + bio_size = ios->si.maxdevUnits; + } else { + bio_size = (ios->si.maxdevUnits + 1) * + (ios->layout->group_width - ios->layout->parity) / + ios->layout->group_width; + } + bio_size *= (ios->layout->stripe_unit / PAGE_SIZE); per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size); if (unlikely(!per_dev->bio)) { @@ -609,8 +618,12 @@ added_len = bio_add_pc_page(q, per_dev->bio, pages[pg], pglen, pgbase); if (unlikely(pglen != added_len)) { - ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=%u\n", - per_dev->bio->bi_vcnt); + /* If bi_vcnt == bi_max then this is a SW BUG */ + ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=0x%x " + "bi_max=0x%x BIO_MAX=0x%x cur_len=0x%x\n", + per_dev->bio->bi_vcnt, + per_dev->bio->bi_max_vecs, + BIO_MAX_PAGES_KMALLOC, cur_len); ret = -ENOMEM; goto out; } @@ -1098,7 +1111,7 @@ size_attr->attr = g_attr_logical_length; size_attr->attr.val_ptr = &size_attr->newsize; - ORE_DBGMSG("trunc(0x%llx) obj_offset=0x%llx dev=%d\n", + ORE_DBGMSG2("trunc(0x%llx) obj_offset=0x%llx dev=%d\n", _LLU(oc->comps->obj.id), _LLU(obj_size), i); ret = _truncate_mirrors(ios, i * ios->layout->mirrors_p1, &size_attr->attr); --- linux-3.13.0.orig/fs/fuse/dev.c +++ linux-3.13.0/fs/fuse/dev.c @@ -1296,22 +1296,6 @@ return fuse_dev_do_read(fc, file, &cs, iov_length(iov, nr_segs)); } -static int fuse_dev_pipe_buf_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - return 1; -} - -static const struct pipe_buf_operations fuse_dev_pipe_buf_ops = { - .can_merge = 0, - .map = generic_pipe_buf_map, - .unmap = generic_pipe_buf_unmap, - .confirm = generic_pipe_buf_confirm, - .release = generic_pipe_buf_release, - .steal = fuse_dev_pipe_buf_steal, - .get = generic_pipe_buf_get, -}; - static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) @@ -1358,7 +1342,11 @@ buf->page = bufs[page_nr].page; buf->offset = bufs[page_nr].offset; buf->len = bufs[page_nr].len; - buf->ops = &fuse_dev_pipe_buf_ops; + /* + * Need to be careful about this. Having buf->ops in module + * code can Oops if the buffer persists after module unload. + */ + buf->ops = &nosteal_pipe_buf_ops; pipe->nrbufs++; page_nr++; --- linux-3.13.0.orig/fs/gfs2/inode.c +++ linux-3.13.0/fs/gfs2/inode.c @@ -1607,10 +1607,22 @@ if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid)) ogid = ngid = NO_GID_QUOTA_CHANGE; - error = gfs2_quota_lock(ip, nuid, ngid); + error = get_write_access(inode); if (error) return error; + error = gfs2_rs_alloc(ip); + if (error) + goto out; + + error = gfs2_rindex_update(sdp); + if (error) + goto out; + + error = gfs2_quota_lock(ip, nuid, ngid); + if (error) + goto out; + if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) || !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) { error = gfs2_quota_check(ip, nuid, ngid); @@ -1637,6 +1649,8 @@ gfs2_trans_end(sdp); out_gunlock_q: gfs2_quota_unlock(ip); +out: + put_write_access(inode); return error; } --- linux-3.13.0.orig/fs/lockd/svclock.c +++ linux-3.13.0/fs/lockd/svclock.c @@ -779,6 +779,7 @@ struct nlm_file *file = block->b_file; struct nlm_lock *lock = &block->b_call->a_args.lock; int error; + loff_t fl_start, fl_end; dprintk("lockd: grant blocked lock %p\n", block); @@ -796,9 +797,16 @@ } /* Try the lock operation again */ + /* vfs_lock_file() can mangle fl_start and fl_end, but we need + * them unchanged for the GRANT_MSG + */ lock->fl.fl_flags |= FL_SLEEP; + fl_start = lock->fl.fl_start; + fl_end = lock->fl.fl_end; error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); lock->fl.fl_flags &= ~FL_SLEEP; + lock->fl.fl_start = fl_start; + lock->fl.fl_end = fl_end; switch (error) { case 0: --- linux-3.13.0.orig/fs/proc/nommu.c +++ linux-3.13.0/fs/proc/nommu.c @@ -45,7 +45,9 @@ file = region->vm_file; if (file) { - struct inode *inode = file_inode(region->vm_file); + struct inode *inode; + file = vmr_pr_or_file(region); + inode = file_inode(file); dev = inode->i_sb->s_dev; ino = inode->i_ino; } --- linux-3.13.0.orig/fs/proc/version_signature.c +++ linux-3.13.0/fs/proc/version_signature.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include + +static int version_signature_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%s\n", CONFIG_VERSION_SIGNATURE); + return 0; +} + +static int version_signature_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, version_signature_proc_show, NULL); +} + +static const struct file_operations version_signature_proc_fops = { + .open = version_signature_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init proc_version_signature_init(void) +{ + proc_create("version_signature", 0, NULL, &version_signature_proc_fops); + return 0; +} +module_init(proc_version_signature_init); --- linux-3.13.0.orig/fs/proc/proc_devtree.c +++ linux-3.13.0/fs/proc/proc_devtree.c @@ -232,6 +232,7 @@ return; root = of_find_node_by_path("/"); if (root == NULL) { + remove_proc_entry("device-tree", NULL); pr_debug("/proc/device-tree: can't find root\n"); return; } --- linux-3.13.0.orig/fs/proc/task_nommu.c +++ linux-3.13.0/fs/proc/task_nommu.c @@ -141,7 +141,9 @@ file = vma->vm_file; if (file) { - struct inode *inode = file_inode(vma->vm_file); + struct inode *inode; + file = vma_pr_or_file(file); + inode = file_inode(file); dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; --- linux-3.13.0.orig/fs/proc/task_mmu.c +++ linux-3.13.0/fs/proc/task_mmu.c @@ -264,7 +264,9 @@ const char *name = NULL; if (file) { - struct inode *inode = file_inode(vma->vm_file); + struct inode *inode; + file = vma_pr_or_file(vma); + inode = file_inode(file); dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; @@ -1407,6 +1409,7 @@ seq_printf(m, "%08lx %s", vma->vm_start, buffer); if (file) { + file = vma_pr_or_file(vma); seq_printf(m, " file="); seq_path(m, &file->f_path, "\n\t= "); } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { --- linux-3.13.0.orig/fs/proc/Makefile +++ linux-3.13.0/fs/proc/Makefile @@ -30,3 +30,4 @@ proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o proc-$(CONFIG_PRINTK) += kmsg.o proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o +proc-y += version_signature.o --- linux-3.13.0.orig/fs/proc/base.c +++ linux-3.13.0/fs/proc/base.c @@ -1819,6 +1819,7 @@ if (rc) goto out_mmput; + rc = -ENOENT; down_read(&mm->mmap_sem); vma = find_exact_vma(mm, vm_start, vm_end); if (vma && vma->vm_file) { --- linux-3.13.0.orig/fs/ecryptfs/main.c +++ linux-3.13.0/fs/ecryptfs/main.c @@ -566,6 +566,13 @@ s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("eCryptfs: maximum fs stacking depth exceeded\n"); + goto out_free; + } inode = ecryptfs_get_inode(path.dentry->d_inode, s); rc = PTR_ERR(inode); --- linux-3.13.0.orig/kernel/audit.c +++ linux-3.13.0/kernel/audit.c @@ -102,7 +102,8 @@ /* Number of outstanding audit_buffers allowed. */ static int audit_backlog_limit = 64; -static int audit_backlog_wait_time = 60 * HZ; +#define AUDIT_BACKLOG_WAIT_TIME (60 * HZ) +static int audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME; static int audit_backlog_wait_overflow = 0; /* The identity of the user shutting down the audit system. */ @@ -1239,6 +1240,8 @@ return NULL; } + audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME; + ab = audit_buffer_alloc(ctx, gfp_mask, type); if (!ab) { audit_log_lost("out of memory in audit_log_start"); --- linux-3.13.0.orig/kernel/kexec.c +++ linux-3.13.0/kernel/kexec.c @@ -932,6 +932,7 @@ */ struct kimage *kexec_image; struct kimage *kexec_crash_image; +int kexec_load_disabled; static DEFINE_MUTEX(kexec_mutex); @@ -942,7 +943,7 @@ int result; /* We only trust the superuser with rebooting the system. */ - if (!capable(CAP_SYS_BOOT)) + if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) return -EPERM; /* --- linux-3.13.0.orig/kernel/module.c +++ linux-3.13.0/kernel/module.c @@ -1017,7 +1017,7 @@ buf[l++] = 'C'; /* * TAINT_FORCED_RMMOD: could be added. - * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't + * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't * apply to modules. */ return l; --- linux-3.13.0.orig/kernel/fork.c +++ linux-3.13.0/kernel/fork.c @@ -412,7 +412,7 @@ struct inode *inode = file_inode(file); struct address_space *mapping = file->f_mapping; - get_file(file); + vma_get_file(tmp); if (tmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); mutex_lock(&mapping->i_mmap_mutex); --- linux-3.13.0.orig/kernel/panic.c +++ linux-3.13.0/kernel/panic.c @@ -199,7 +199,7 @@ static const struct tnt tnts[] = { { TAINT_PROPRIETARY_MODULE, 'P', 'G' }, { TAINT_FORCED_MODULE, 'F', ' ' }, - { TAINT_UNSAFE_SMP, 'S', ' ' }, + { TAINT_CPU_OUT_OF_SPEC, 'S', ' ' }, { TAINT_FORCED_RMMOD, 'R', ' ' }, { TAINT_MACHINE_CHECK, 'M', ' ' }, { TAINT_BAD_PAGE, 'B', ' ' }, --- linux-3.13.0.orig/kernel/kthread.c +++ linux-3.13.0/kernel/kthread.c @@ -292,6 +292,17 @@ * new kernel thread. */ if (unlikely(wait_for_completion_killable(&done))) { + int i = 0; + + /* + * I got SIGKILL, but wait for 10 more seconds for completion + * unless chosen by the OOM killer. This delay is there as a + * workaround for boot failure caused by SIGKILL upon device + * driver initialization timeout. + */ + while (i++ < 10 && !test_tsk_thread_flag(current, TIF_MEMDIE)) + if (wait_for_completion_timeout(&done, HZ)) + goto ready; /* * If I was SIGKILLed before kthreadd (or new kernel thread) * calls complete(), leave the cleanup of this structure to @@ -305,6 +316,7 @@ */ wait_for_completion(&done); } +ready: task = create->result; if (!IS_ERR(task)) { static const struct sched_param param = { .sched_priority = 0 }; --- linux-3.13.0.orig/kernel/sysctl.c +++ linux-3.13.0/kernel/sysctl.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -398,6 +399,15 @@ .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "numa_balancing", + .data = NULL, /* filled in by handler */ + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sysctl_numa_balancing, + .extra1 = &zero, + .extra2 = &one, + }, #endif /* CONFIG_NUMA_BALANCING */ #endif /* CONFIG_SCHED_DEBUG */ { @@ -614,6 +624,18 @@ .proc_handler = proc_dointvec, }, #endif +#ifdef CONFIG_KEXEC + { + .procname = "kexec_load_disabled", + .data = &kexec_load_disabled, + .maxlen = sizeof(int), + .mode = 0644, + /* only handle a transition from default "0" to "1" */ + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, + .extra2 = &one, + }, +#endif #ifdef CONFIG_MODULES { .procname = "modprobe", --- linux-3.13.0.orig/kernel/stop_machine.c +++ linux-3.13.0/kernel/stop_machine.c @@ -293,7 +293,7 @@ */ smp_call_function_single(min(cpu1, cpu2), &irq_cpu_stop_queue_work, - &call_args, 0); + &call_args, 1); lg_local_unlock(&stop_cpus_lock); preempt_enable(); --- linux-3.13.0.orig/kernel/auditsc.c +++ linux-3.13.0/kernel/auditsc.c @@ -1971,6 +1971,9 @@ struct audit_buffer *ab; uid_t uid, ologinuid, nloginuid; + if (!audit_enabled) + return; + uid = from_kuid(&init_user_ns, task_uid(current)); ologinuid = from_kuid(&init_user_ns, koldloginuid); nloginuid = from_kuid(&init_user_ns, kloginuid), --- linux-3.13.0.orig/kernel/workqueue.c +++ linux-3.13.0/kernel/workqueue.c @@ -1851,6 +1851,12 @@ if (worker->flags & WORKER_IDLE) pool->nr_idle--; + /* + * Once WORKER_DIE is set, the kworker may destroy itself at any + * point. Pin to ensure the task stays until we're done with it. + */ + get_task_struct(worker->task); + list_del_init(&worker->entry); worker->flags |= WORKER_DIE; @@ -1859,6 +1865,7 @@ spin_unlock_irq(&pool->lock); kthread_stop(worker->task); + put_task_struct(worker->task); kfree(worker); spin_lock_irq(&pool->lock); --- linux-3.13.0.orig/kernel/cpuset.c +++ linux-3.13.0/kernel/cpuset.c @@ -974,12 +974,6 @@ * Temporarilly set tasks mems_allowed to target nodes of migration, * so that the migration code can allocate pages on these nodes. * - * Call holding cpuset_mutex, so current's cpuset won't change - * during this call, as manage_mutex holds off any cpuset_attach() - * calls. Therefore we don't need to take task_lock around the - * call to guarantee_online_mems(), as we know no one is changing - * our task's cpuset. - * * While the mm_struct we are migrating is typically from some * other task, the task_struct mems_allowed that we are hacking * is for our current task, which must allocate new pages for that @@ -996,8 +990,10 @@ do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL); + rcu_read_lock(); mems_cs = effective_nodemask_cpuset(task_cs(tsk)); guarantee_online_mems(mems_cs, &tsk->mems_allowed); + rcu_read_unlock(); } /* @@ -2511,9 +2507,9 @@ task_lock(current); cs = nearest_hardwall_ancestor(task_cs(current)); + allowed = node_isset(node, cs->mems_allowed); task_unlock(current); - allowed = node_isset(node, cs->mems_allowed); mutex_unlock(&callback_mutex); return allowed; } --- linux-3.13.0.orig/kernel/cgroup.c +++ linux-3.13.0/kernel/cgroup.c @@ -1580,10 +1580,10 @@ mutex_lock(&cgroup_mutex); mutex_lock(&cgroup_root_mutex); - root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp, - 0, 1, GFP_KERNEL); - if (root_cgrp->id < 0) + ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL); + if (ret < 0) goto unlock_drop; + root_cgrp->id = ret; /* Check for name clashes with existing mounts */ ret = -EBUSY; @@ -2845,10 +2845,7 @@ */ update_before = cgroup_serial_nr_next; - mutex_unlock(&cgroup_mutex); - /* add/rm files for all cgroups created before */ - rcu_read_lock(); css_for_each_descendant_pre(css, cgroup_css(root, ss)) { struct cgroup *cgrp = css->cgroup; @@ -2857,23 +2854,19 @@ inode = cgrp->dentry->d_inode; dget(cgrp->dentry); - rcu_read_unlock(); - dput(prev); prev = cgrp->dentry; + mutex_unlock(&cgroup_mutex); mutex_lock(&inode->i_mutex); mutex_lock(&cgroup_mutex); if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) ret = cgroup_addrm_files(cgrp, cfts, is_add); - mutex_unlock(&cgroup_mutex); mutex_unlock(&inode->i_mutex); - - rcu_read_lock(); if (ret) break; } - rcu_read_unlock(); + mutex_unlock(&cgroup_mutex); dput(prev); deactivate_super(sb); return ret; @@ -2992,9 +2985,14 @@ * We should check if the process is exiting, otherwise * it will race with cgroup_exit() in that the list * entry won't be deleted though the process has exited. + * Do it while holding siglock so that we don't end up + * racing against cgroup_exit(). */ + spin_lock_irq(&p->sighand->siglock); if (!(p->flags & PF_EXITING) && list_empty(&p->cg_list)) list_add(&p->cg_list, &task_css_set(p)->tasks); + spin_unlock_irq(&p->sighand->siglock); + task_unlock(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); @@ -4348,7 +4346,7 @@ struct cgroup *cgrp; struct cgroup_name *name; struct cgroupfs_root *root = parent->root; - int err = 0; + int err; struct cgroup_subsys *ss; struct super_block *sb = root->sb; @@ -4358,8 +4356,10 @@ return -ENOMEM; name = cgroup_alloc_name(dentry); - if (!name) + if (!name) { + err = -ENOMEM; goto err_free_cgrp; + } rcu_assign_pointer(cgrp->name, name); /* @@ -4367,8 +4367,10 @@ * a half-baked cgroup. */ cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); - if (cgrp->id < 0) + if (cgrp->id < 0) { + err = -ENOMEM; goto err_free_name; + } /* * Only live parents can have children. Note that the liveliness --- linux-3.13.0.orig/kernel/tracepoint.c +++ linux-3.13.0/kernel/tracepoint.c @@ -631,6 +631,11 @@ EXPORT_SYMBOL_GPL(tracepoint_iter_reset); #ifdef CONFIG_MODULES +bool trace_module_has_bad_taint(struct module *mod) +{ + return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)); +} + static int tracepoint_module_coming(struct module *mod) { struct tp_module *tp_mod, *iter; @@ -641,7 +646,7 @@ * module headers (for forced load), to make sure we don't cause a crash. * Staging and out-of-tree GPL modules are fine. */ - if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP))) + if (trace_module_has_bad_taint(mod)) return 0; mutex_lock(&tracepoints_mutex); tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL); --- linux-3.13.0.orig/kernel/irq/manage.c +++ linux-3.13.0/kernel/irq/manage.c @@ -22,14 +22,20 @@ #include "internals.h" #ifdef CONFIG_IRQ_FORCED_THREADING -__read_mostly bool force_irqthreads; +__read_mostly bool force_irqthreads = IS_ENABLED(CONFIG_IRQ_FORCED_THREADING_DEFAULT); static int __init setup_forced_irqthreads(char *arg) { force_irqthreads = true; return 0; } +static int __init setup_no_irqthreads(char *arg) +{ + force_irqthreads = false; + return 0; +} early_param("threadirqs", setup_forced_irqthreads); +early_param("nothreadirqs", setup_no_irqthreads); #endif /** @@ -802,8 +808,7 @@ static void wake_threads_waitq(struct irq_desc *desc) { - if (atomic_dec_and_test(&desc->threads_active) && - waitqueue_active(&desc->wait_for_threads)) + if (atomic_dec_and_test(&desc->threads_active)) wake_up(&desc->wait_for_threads); } --- linux-3.13.0.orig/kernel/irq/Kconfig +++ linux-3.13.0/kernel/irq/Kconfig @@ -40,6 +40,7 @@ # Generic configurable interrupt chip implementation config GENERIC_IRQ_CHIP bool + select IRQ_DOMAIN # Generic irq_domain hw <--> linux irq number translation config IRQ_DOMAIN @@ -59,6 +60,10 @@ config IRQ_FORCED_THREADING bool +config IRQ_FORCED_THREADING_DEFAULT + bool "Use IRQ threading by default" + depends on IRQ_FORCED_THREADING + config SPARSE_IRQ bool "Support sparse irq numbering" if MAY_HAVE_SPARSE_IRQ ---help--- --- linux-3.13.0.orig/kernel/irq/irqdesc.c +++ linux-3.13.0/kernel/irq/irqdesc.c @@ -274,6 +274,7 @@ { return (irq < NR_IRQS) ? irq_desc + irq : NULL; } +EXPORT_SYMBOL(irq_to_desc); static void free_desc(unsigned int irq) { --- linux-3.13.0.orig/kernel/time/timekeeping.c +++ linux-3.13.0/kernel/time/timekeeping.c @@ -77,7 +77,7 @@ tk->wall_to_monotonic = wtm; set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec); tk->offs_real = timespec_to_ktime(tmp); - tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tk->tai_offset, 0)); + tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tk->tai_offset, 0)); } static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) @@ -595,7 +595,7 @@ static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) { tk->tai_offset = tai_offset; - tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tai_offset, 0)); + tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tai_offset, 0)); } /** @@ -610,6 +610,7 @@ raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&timekeeper_seq); __timekeeping_set_tai_offset(tk, tai_offset); + timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); clock_was_set(); @@ -1023,6 +1024,8 @@ timekeeping_suspend_time = timespec_add(timekeeping_suspend_time, delta_delta); } + + timekeeping_update(tk, TK_MIRROR); write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); @@ -1255,7 +1258,7 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) { u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; - unsigned int action = 0; + unsigned int clock_set = 0; while (tk->xtime_nsec >= nsecps) { int leap; @@ -1277,11 +1280,10 @@ __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); - clock_was_set_delayed(); - action = TK_CLOCK_WAS_SET; + clock_set = TK_CLOCK_WAS_SET; } } - return action; + return clock_set; } /** @@ -1294,7 +1296,8 @@ * Returns the unconsumed cycles. */ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, - u32 shift) + u32 shift, + unsigned int *clock_set) { cycle_t interval = tk->cycle_interval << shift; u64 raw_nsecs; @@ -1308,7 +1311,7 @@ tk->cycle_last += interval; tk->xtime_nsec += tk->xtime_interval << shift; - accumulate_nsecs_to_secs(tk); + *clock_set |= accumulate_nsecs_to_secs(tk); /* Accumulate raw time */ raw_nsecs = (u64)tk->raw_interval << shift; @@ -1366,7 +1369,7 @@ struct timekeeper *tk = &shadow_timekeeper; cycle_t offset; int shift = 0, maxshift; - unsigned int action; + unsigned int clock_set = 0; unsigned long flags; raw_spin_lock_irqsave(&timekeeper_lock, flags); @@ -1401,7 +1404,8 @@ maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1; shift = min(shift, maxshift); while (offset >= tk->cycle_interval) { - offset = logarithmic_accumulation(tk, offset, shift); + offset = logarithmic_accumulation(tk, offset, shift, + &clock_set); if (offset < tk->cycle_interval<cycle_last with the new value */ @@ -1435,10 +1439,23 @@ * updating. */ memcpy(real_tk, tk, sizeof(*tk)); - timekeeping_update(real_tk, action); + timekeeping_update(real_tk, clock_set); write_seqcount_end(&timekeeper_seq); out: raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + if (clock_set) { + /* + * XXX - I'd rather we just call clock_was_set(), but + * since we're currently holding the jiffies lock, calling + * clock_was_set would trigger an ipi which would then grab + * the jiffies lock and we'd deadlock. :( + * The right solution should probably be droping + * the jiffies lock before calling update_wall_time + * but that requires some rework of the tick sched + * code. + */ + clock_was_set_delayed(); + } } /** @@ -1698,12 +1715,14 @@ if (tai != orig_tai) { __timekeeping_set_tai_offset(tk, tai); - update_pvclock_gtod(tk, true); - clock_was_set_delayed(); + timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); } write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + if (tai != orig_tai) + clock_was_set(); + ntp_notify_cmos_timer(); return ret; --- linux-3.13.0.orig/kernel/time/tick-broadcast.c +++ linux-3.13.0/kernel/time/tick-broadcast.c @@ -756,6 +756,7 @@ static void tick_broadcast_clear_oneshot(int cpu) { cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask); + cpumask_clear_cpu(cpu, tick_broadcast_pending_mask); } static void tick_broadcast_init_next_event(struct cpumask *mask, --- linux-3.13.0.orig/kernel/time/jiffies.c +++ linux-3.13.0/kernel/time/jiffies.c @@ -51,7 +51,13 @@ * HZ shrinks, so values greater than 8 overflow 32bits when * HZ=100. */ +#if HZ < 34 +#define JIFFIES_SHIFT 6 +#elif HZ < 67 +#define JIFFIES_SHIFT 7 +#else #define JIFFIES_SHIFT 8 +#endif static cycle_t jiffies_read(struct clocksource *cs) { --- linux-3.13.0.orig/kernel/trace/trace_export.c +++ linux-3.13.0/kernel/trace/trace_export.c @@ -95,15 +95,12 @@ #undef __array #define __array(type, item, len) \ do { \ + char *type_str = #type"["__stringify(len)"]"; \ BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \ - mutex_lock(&event_storage_mutex); \ - snprintf(event_storage, sizeof(event_storage), \ - "%s[%d]", #type, len); \ - ret = trace_define_field(event_call, event_storage, #item, \ + ret = trace_define_field(event_call, type_str, #item, \ offsetof(typeof(field), item), \ sizeof(field.item), \ is_signed_type(type), filter_type); \ - mutex_unlock(&event_storage_mutex); \ if (ret) \ return ret; \ } while (0); --- linux-3.13.0.orig/kernel/trace/trace_events.c +++ linux-3.13.0/kernel/trace/trace_events.c @@ -27,12 +27,6 @@ DEFINE_MUTEX(event_mutex); -DEFINE_MUTEX(event_storage_mutex); -EXPORT_SYMBOL_GPL(event_storage_mutex); - -char event_storage[EVENT_STORAGE_SIZE]; -EXPORT_SYMBOL_GPL(event_storage); - LIST_HEAD(ftrace_events); static LIST_HEAD(ftrace_common_fields); @@ -1771,6 +1765,16 @@ { struct ftrace_event_call **call, **start, **end; + if (!mod->num_trace_events) + return; + + /* Don't add infrastructure for mods without tracepoints */ + if (trace_module_has_bad_taint(mod)) { + pr_err("%s: module has bad taint, not creating trace events\n", + mod->name); + return; + } + start = mod->trace_events; end = mod->trace_events + mod->num_trace_events; --- linux-3.13.0.orig/kernel/trace/ring_buffer.c +++ linux-3.13.0/kernel/trace/ring_buffer.c @@ -2397,6 +2397,13 @@ write &= RB_WRITE_MASK; tail = write - length; + /* + * If this is the first commit on the page, then it has the same + * timestamp as the page itself. + */ + if (!tail) + delta = 0; + /* See if we shot pass the end of this buffer page */ if (unlikely(write > BUF_PAGE_SIZE)) return rb_move_tail(cpu_buffer, length, tail, --- linux-3.13.0.orig/kernel/trace/ftrace.c +++ linux-3.13.0/kernel/trace/ftrace.c @@ -85,6 +85,8 @@ /* Current function tracing op */ struct ftrace_ops *function_trace_op __read_mostly = &ftrace_list_end; +/* What to set function_trace_op to */ +static struct ftrace_ops *set_function_trace_op; /* List for set_ftrace_pid's pids. */ LIST_HEAD(ftrace_pids); @@ -278,6 +280,29 @@ global_ops.func = func; } +static void ftrace_sync(struct work_struct *work) +{ + /* + * This function is just a stub to implement a hard force + * of synchronize_sched(). This requires synchronizing + * tasks even in userspace and idle. + * + * Yes, function tracing is rude. + */ +} + +static void ftrace_sync_ipi(void *data) +{ + /* Probably not needed, but do it anyway */ + smp_rmb(); +} + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +static void update_function_graph_func(void); +#else +static inline void update_function_graph_func(void) { } +#endif + static void update_ftrace_function(void) { ftrace_func_t func; @@ -296,16 +321,61 @@ !FTRACE_FORCE_LIST_FUNC)) { /* Set the ftrace_ops that the arch callback uses */ if (ftrace_ops_list == &global_ops) - function_trace_op = ftrace_global_list; + set_function_trace_op = ftrace_global_list; else - function_trace_op = ftrace_ops_list; + set_function_trace_op = ftrace_ops_list; func = ftrace_ops_list->func; } else { /* Just use the default ftrace_ops */ - function_trace_op = &ftrace_list_end; + set_function_trace_op = &ftrace_list_end; func = ftrace_ops_list_func; } + /* If there's no change, then do nothing more here */ + if (ftrace_trace_function == func) + return; + + update_function_graph_func(); + + /* + * If we are using the list function, it doesn't care + * about the function_trace_ops. + */ + if (func == ftrace_ops_list_func) { + ftrace_trace_function = func; + /* + * Don't even bother setting function_trace_ops, + * it would be racy to do so anyway. + */ + return; + } + +#ifndef CONFIG_DYNAMIC_FTRACE + /* + * For static tracing, we need to be a bit more careful. + * The function change takes affect immediately. Thus, + * we need to coorditate the setting of the function_trace_ops + * with the setting of the ftrace_trace_function. + * + * Set the function to the list ops, which will call the + * function we want, albeit indirectly, but it handles the + * ftrace_ops and doesn't depend on function_trace_op. + */ + ftrace_trace_function = ftrace_ops_list_func; + /* + * Make sure all CPUs see this. Yes this is slow, but static + * tracing is slow and nasty to have enabled. + */ + schedule_on_each_cpu(ftrace_sync); + /* Now all cpus are using the list ops. */ + function_trace_op = set_function_trace_op; + /* Make sure the function_trace_op is visible on all CPUs */ + smp_wmb(); + /* Nasty way to force a rmb on all cpus */ + smp_call_function(ftrace_sync_ipi, NULL, 1); + /* OK, we are all set to update the ftrace_trace_function now! */ +#endif /* !CONFIG_DYNAMIC_FTRACE */ + ftrace_trace_function = func; } @@ -410,17 +480,6 @@ return 0; } -static void ftrace_sync(struct work_struct *work) -{ - /* - * This function is just a stub to implement a hard force - * of synchronize_sched(). This requires synchronizing - * tasks even in userspace and idle. - * - * Yes, function tracing is rude. - */ -} - static int __unregister_ftrace_function(struct ftrace_ops *ops) { int ret; @@ -439,20 +498,6 @@ } else if (ops->flags & FTRACE_OPS_FL_CONTROL) { ret = remove_ftrace_list_ops(&ftrace_control_list, &control_ops, ops); - if (!ret) { - /* - * The ftrace_ops is now removed from the list, - * so there'll be no new users. We must ensure - * all current users are done before we free - * the control data. - * Note synchronize_sched() is not enough, as we - * use preempt_disable() to do RCU, but the function - * tracer can be called where RCU is not active - * (before user_exit()). - */ - schedule_on_each_cpu(ftrace_sync); - control_ops_free(ops); - } } else ret = remove_ftrace_ops(&ftrace_ops_list, ops); @@ -462,17 +507,6 @@ if (ftrace_enabled) update_ftrace_function(); - /* - * Dynamic ops may be freed, we must make sure that all - * callers are done before leaving this function. - * - * Again, normal synchronize_sched() is not good enough. - * We need to do a hard force of sched synchronization. - */ - if (ops->flags & FTRACE_OPS_FL_DYNAMIC) - schedule_on_each_cpu(ftrace_sync); - - return 0; } @@ -1992,8 +2026,14 @@ else if (command & FTRACE_DISABLE_CALLS) ftrace_replace_code(0); - if (update && ftrace_trace_function != ftrace_ops_list_func) + if (update && ftrace_trace_function != ftrace_ops_list_func) { + function_trace_op = set_function_trace_op; + smp_wmb(); + /* If irqs are disabled, we are in stop machine */ + if (!irqs_disabled()) + smp_call_function(ftrace_sync_ipi, NULL, 1); ftrace_update_ftrace_func(ftrace_trace_function); + } if (command & FTRACE_START_FUNC_RET) ftrace_enable_ftrace_graph_caller(); @@ -2156,10 +2196,41 @@ command |= FTRACE_UPDATE_TRACE_FUNC; } - if (!command || !ftrace_enabled) + if (!command || !ftrace_enabled) { + /* + * If these are control ops, they still need their + * per_cpu field freed. Since, function tracing is + * not currently active, we can just free them + * without synchronizing all CPUs. + */ + if (ops->flags & FTRACE_OPS_FL_CONTROL) + control_ops_free(ops); return 0; + } ftrace_run_update_code(command); + + /* + * Dynamic ops may be freed, we must make sure that all + * callers are done before leaving this function. + * The same goes for freeing the per_cpu data of the control + * ops. + * + * Again, normal synchronize_sched() is not good enough. + * We need to do a hard force of sched synchronization. + * This is because we use preempt_disable() to do RCU, but + * the function tracers can be called where RCU is not watching + * (like before user_exit()). We can not rely on the RCU + * infrastructure to do the synchronization, thus we must do it + * ourselves. + */ + if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_CONTROL)) { + schedule_on_each_cpu(ftrace_sync); + + if (ops->flags & FTRACE_OPS_FL_CONTROL) + control_ops_free(ops); + } + return 0; } @@ -4862,6 +4933,7 @@ trace_func_graph_ret_t ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub; +static trace_func_graph_ent_t __ftrace_graph_entry = ftrace_graph_entry_stub; /* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */ static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list) @@ -5003,6 +5075,30 @@ FTRACE_OPS_FL_RECURSION_SAFE, }; +static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace) +{ + if (!ftrace_ops_test(&global_ops, trace->func, NULL)) + return 0; + return __ftrace_graph_entry(trace); +} + +/* + * The function graph tracer should only trace the functions defined + * by set_ftrace_filter and set_ftrace_notrace. If another function + * tracer ops is registered, the graph tracer requires testing the + * function against the global ops, and not just trace any function + * that any ftrace_ops registered. + */ +static void update_function_graph_func(void) +{ + if (ftrace_ops_list == &ftrace_list_end || + (ftrace_ops_list == &global_ops && + global_ops.next == &ftrace_list_end)) + ftrace_graph_entry = __ftrace_graph_entry; + else + ftrace_graph_entry = ftrace_graph_entry_test; +} + int register_ftrace_graph(trace_func_graph_ret_t retfunc, trace_func_graph_ent_t entryfunc) { @@ -5027,7 +5123,16 @@ } ftrace_graph_return = retfunc; - ftrace_graph_entry = entryfunc; + + /* + * Update the indirect function to the entryfunc, and the + * function that gets called to the entry_test first. Then + * call the update fgraph entry function to determine if + * the entryfunc should be called directly or not. + */ + __ftrace_graph_entry = entryfunc; + ftrace_graph_entry = ftrace_graph_entry_test; + update_function_graph_func(); ret = ftrace_startup(&fgraph_ops, FTRACE_START_FUNC_RET); @@ -5046,6 +5151,7 @@ ftrace_graph_active--; ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; ftrace_graph_entry = ftrace_graph_entry_stub; + __ftrace_graph_entry = ftrace_graph_entry_stub; ftrace_shutdown(&fgraph_ops, FTRACE_STOP_FUNC_RET); unregister_pm_notifier(&ftrace_suspend_notifier); unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); --- linux-3.13.0.orig/kernel/trace/trace.c +++ linux-3.13.0/kernel/trace/trace.c @@ -455,6 +455,9 @@ unsigned long irq_flags; int alloc; + if (unlikely(tracing_selftest_running || tracing_disabled)) + return 0; + alloc = sizeof(*entry) + size + 2; /* possible \n added */ local_save_flags(irq_flags); @@ -495,6 +498,9 @@ unsigned long irq_flags; int size = sizeof(struct bputs_entry); + if (unlikely(tracing_selftest_running || tracing_disabled)) + return 0; + local_save_flags(irq_flags); buffer = global_trace.trace_buffer.buffer; event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size, @@ -5883,6 +5889,8 @@ rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0; + buf->tr = tr; + buf->buffer = ring_buffer_alloc(size, rb_flags); if (!buf->buffer) return -ENOMEM; --- linux-3.13.0.orig/kernel/events/core.c +++ linux-3.13.0/kernel/events/core.c @@ -7833,14 +7833,14 @@ static void __perf_event_exit_context(void *__info) { struct perf_event_context *ctx = __info; - struct perf_event *event, *tmp; + struct perf_event *event; perf_pmu_rotate_stop(ctx->pmu); - list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry) - __perf_remove_from_context(event); - list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry) + rcu_read_lock(); + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) __perf_remove_from_context(event); + rcu_read_unlock(); } static void perf_event_exit_cpu_context(int cpu) @@ -7864,11 +7864,11 @@ { struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); + perf_event_exit_cpu_context(cpu); + mutex_lock(&swhash->hlist_mutex); swevent_hlist_release(swhash); mutex_unlock(&swhash->hlist_mutex); - - perf_event_exit_cpu_context(cpu); } #else static inline void perf_event_exit_cpu(int cpu) { } --- linux-3.13.0.orig/kernel/printk/printk.c +++ linux-3.13.0/kernel/printk/printk.c @@ -1080,7 +1080,6 @@ next_seq = log_next_seq; len = 0; - prev = 0; while (len >= 0 && seq < next_seq) { struct printk_log *msg = log_from_idx(idx); int textlen; @@ -2789,7 +2788,6 @@ next_idx = idx; l = 0; - prev = 0; while (seq < dumper->next_seq) { struct printk_log *msg = log_from_idx(idx); --- linux-3.13.0.orig/kernel/sched/core.c +++ linux-3.13.0/kernel/sched/core.c @@ -1763,7 +1763,29 @@ numabalancing_enabled = enabled; } #endif /* CONFIG_SCHED_DEBUG */ -#endif /* CONFIG_NUMA_BALANCING */ + +#ifdef CONFIG_PROC_SYSCTL +int sysctl_numa_balancing(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table t; + int err; + int state = numabalancing_enabled; + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + t = *table; + t.data = &state; + err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); + if (err < 0) + return err; + if (write) + set_numabalancing_state(state); + return err; +} +#endif +#endif /* * fork()/clone()-time setup: --- linux-3.13.0.orig/kernel/sched/fair.c +++ linux-3.13.0/kernel/sched/fair.c @@ -7012,15 +7012,15 @@ struct cfs_rq *cfs_rq = cfs_rq_of(se); /* - * Ensure the task's vruntime is normalized, so that when its + * Ensure the task's vruntime is normalized, so that when it's * switched back to the fair class the enqueue_entity(.flags=0) will * do the right thing. * - * If it was on_rq, then the dequeue_entity(.flags=0) will already - * have normalized the vruntime, if it was !on_rq, then only when + * If it's on_rq, then the dequeue_entity(.flags=0) will already + * have normalized the vruntime, if it's !on_rq, then only when * the task is sleeping will it still have non-normalized vruntime. */ - if (!se->on_rq && p->state != TASK_RUNNING) { + if (!p->on_rq && p->state != TASK_RUNNING) { /* * Fix up our vruntime so that the current sleep doesn't * cause 'unlimited' sleep bonus. --- linux-3.13.0.orig/include/uapi/drm/i915_drm.h +++ linux-3.13.0/include/uapi/drm/i915_drm.h @@ -222,6 +222,7 @@ #define DRM_I915_GEM_SET_CACHING 0x2f #define DRM_I915_GEM_GET_CACHING 0x30 #define DRM_I915_REG_READ 0x31 +#define DRM_I915_GET_RESET_STATS 0x32 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -271,6 +272,7 @@ #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) #define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) +#define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -1030,4 +1032,21 @@ __u64 offset; __u64 val; /* Return value */ }; + +struct drm_i915_reset_stats { + __u32 ctx_id; + __u32 flags; + + /* All resets since boot/module reload, for all contexts */ + __u32 reset_count; + + /* Number of batches lost when active in GPU, for this context */ + __u32 batch_active; + + /* Number of batches lost pending for execution, for this context */ + __u32 batch_pending; + + __u32 pad; +}; + #endif /* _UAPI_I915_DRM_H_ */ --- linux-3.13.0.orig/include/uapi/drm/vmwgfx_drm.h +++ linux-3.13.0/include/uapi/drm/vmwgfx_drm.h @@ -28,6 +28,10 @@ #ifndef __VMWGFX_DRM_H__ #define __VMWGFX_DRM_H__ +#ifndef __KERNEL__ +#include +#endif + #define DRM_VMW_MAX_SURFACE_FACES 6 #define DRM_VMW_MAX_MIP_LEVELS 24 @@ -55,6 +59,11 @@ #define DRM_VMW_PRESENT 18 #define DRM_VMW_PRESENT_READBACK 19 #define DRM_VMW_UPDATE_LAYOUT 20 +#define DRM_VMW_CREATE_SHADER 21 +#define DRM_VMW_UNREF_SHADER 22 +#define DRM_VMW_GB_SURFACE_CREATE 23 +#define DRM_VMW_GB_SURFACE_REF 24 +#define DRM_VMW_SYNCCPU 25 /*************************************************************************/ /** @@ -76,6 +85,9 @@ #define DRM_VMW_PARAM_MAX_FB_SIZE 5 #define DRM_VMW_PARAM_FIFO_HW_VERSION 6 #define DRM_VMW_PARAM_MAX_SURF_MEMORY 7 +#define DRM_VMW_PARAM_3D_CAPS_SIZE 8 +#define DRM_VMW_PARAM_MAX_MOB_MEMORY 9 +#define DRM_VMW_PARAM_MAX_MOB_SIZE 10 /** * struct drm_vmw_getparam_arg @@ -788,4 +800,253 @@ uint64_t rects; }; + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_SHADER - Create shader + * + * Creates a shader and optionally binds it to a dma buffer containing + * the shader byte-code. + */ + +/** + * enum drm_vmw_shader_type - Shader types + */ +enum drm_vmw_shader_type { + drm_vmw_shader_type_vs = 0, + drm_vmw_shader_type_ps, + drm_vmw_shader_type_gs +}; + + +/** + * struct drm_vmw_shader_create_arg + * + * @shader_type: Shader type of the shader to create. + * @size: Size of the byte-code in bytes. + * where the shader byte-code starts + * @buffer_handle: Buffer handle identifying the buffer containing the + * shader byte-code + * @shader_handle: On successful completion contains a handle that + * can be used to subsequently identify the shader. + * @offset: Offset in bytes into the buffer given by @buffer_handle, + * + * Input / Output argument to the DRM_VMW_CREATE_SHADER Ioctl. + */ +struct drm_vmw_shader_create_arg { + enum drm_vmw_shader_type shader_type; + uint32_t size; + uint32_t buffer_handle; + uint32_t shader_handle; + uint64_t offset; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_SHADER - Unreferences a shader + * + * Destroys a user-space reference to a shader, optionally destroying + * it. + */ + +/** + * struct drm_vmw_shader_arg + * + * @handle: Handle identifying the shader to destroy. + * + * Input argument to the DRM_VMW_UNREF_SHADER ioctl. + */ +struct drm_vmw_shader_arg { + uint32_t handle; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_CREATE - Create a host guest-backed surface. + * + * Allocates a surface handle and queues a create surface command + * for the host on the first use of the surface. The surface ID can + * be used as the surface ID in commands referencing the surface. + */ + +/** + * enum drm_vmw_surface_flags + * + * @drm_vmw_surface_flag_shareable: Whether the surface is shareable + * @drm_vmw_surface_flag_scanout: Whether the surface is a scanout + * surface. + * @drm_vmw_surface_flag_create_buffer: Create a backup buffer if none is + * given. + */ +enum drm_vmw_surface_flags { + drm_vmw_surface_flag_shareable = (1 << 0), + drm_vmw_surface_flag_scanout = (1 << 1), + drm_vmw_surface_flag_create_buffer = (1 << 2) +}; + +/** + * struct drm_vmw_gb_surface_create_req + * + * @svga3d_flags: SVGA3d surface flags for the device. + * @format: SVGA3d format. + * @mip_level: Number of mip levels for all faces. + * @drm_surface_flags Flags as described above. + * @multisample_count Future use. Set to 0. + * @autogen_filter Future use. Set to 0. + * @buffer_handle Buffer handle of backup buffer. SVGA3D_INVALID_ID + * if none. + * @base_size Size of the base mip level for all faces. + * + * Input argument to the DRM_VMW_GB_SURFACE_CREATE Ioctl. + * Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl. + */ +struct drm_vmw_gb_surface_create_req { + uint32_t svga3d_flags; + uint32_t format; + uint32_t mip_levels; + enum drm_vmw_surface_flags drm_surface_flags; + uint32_t multisample_count; + uint32_t autogen_filter; + uint32_t buffer_handle; + uint32_t pad64; + struct drm_vmw_size base_size; +}; + +/** + * struct drm_vmw_gb_surface_create_rep + * + * @handle: Surface handle. + * @backup_size: Size of backup buffers for this surface. + * @buffer_handle: Handle of backup buffer. SVGA3D_INVALID_ID if none. + * @buffer_size: Actual size of the buffer identified by + * @buffer_handle + * @buffer_map_handle: Offset into device address space for the buffer + * identified by @buffer_handle. + * + * Part of output argument for the DRM_VMW_GB_SURFACE_REF ioctl. + * Output argument for the DRM_VMW_GB_SURFACE_CREATE ioctl. + */ +struct drm_vmw_gb_surface_create_rep { + uint32_t handle; + uint32_t backup_size; + uint32_t buffer_handle; + uint32_t buffer_size; + uint64_t buffer_map_handle; +}; + +/** + * union drm_vmw_gb_surface_create_arg + * + * @req: Input argument as described above. + * @rep: Output argument as described above. + * + * Argument to the DRM_VMW_GB_SURFACE_CREATE ioctl. + */ +union drm_vmw_gb_surface_create_arg { + struct drm_vmw_gb_surface_create_rep rep; + struct drm_vmw_gb_surface_create_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_REF - Reference a host surface. + * + * Puts a reference on a host surface with a given handle, as previously + * returned by the DRM_VMW_GB_SURFACE_CREATE ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface handle in + * the command stream. + * + * On successful return, the Ioctl returns the surface information given + * to and returned from the DRM_VMW_GB_SURFACE_CREATE ioctl. + */ + +/** + * struct drm_vmw_gb_surface_reference_arg + * + * @creq: The data used as input when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_req" + * @crep: Additional data output when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_rep" + * + * Output Argument to the DRM_VMW_GB_SURFACE_REF ioctl. + */ +struct drm_vmw_gb_surface_ref_rep { + struct drm_vmw_gb_surface_create_req creq; + struct drm_vmw_gb_surface_create_rep crep; +}; + +/** + * union drm_vmw_gb_surface_reference_arg + * + * @req: Input data as described above at "struct drm_vmw_surface_arg" + * @rep: Output data as described above at "struct drm_vmw_gb_surface_ref_rep" + * + * Argument to the DRM_VMW_GB_SURFACE_REF Ioctl. + */ +union drm_vmw_gb_surface_reference_arg { + struct drm_vmw_gb_surface_ref_rep rep; + struct drm_vmw_surface_arg req; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_SYNCCPU - Sync a DMA buffer / MOB for CPU access. + * + * Idles any previously submitted GPU operations on the buffer and + * by default blocks command submissions that reference the buffer. + * If the file descriptor used to grab a blocking CPU sync is closed, the + * cpu sync is released. + * The flags argument indicates how the grab / release operation should be + * performed: + */ + +/** + * enum drm_vmw_synccpu_flags - Synccpu flags: + * + * @drm_vmw_synccpu_read: Sync for read. If sync is done for read only, it's a + * hint to the kernel to allow command submissions that references the buffer + * for read-only. + * @drm_vmw_synccpu_write: Sync for write. Block all command submissions + * referencing this buffer. + * @drm_vmw_synccpu_dontblock: Dont wait for GPU idle, but rather return + * -EBUSY should the buffer be busy. + * @drm_vmw_synccpu_allow_cs: Allow command submission that touches the buffer + * while the buffer is synced for CPU. This is similar to the GEM bo idle + * behavior. + */ +enum drm_vmw_synccpu_flags { + drm_vmw_synccpu_read = (1 << 0), + drm_vmw_synccpu_write = (1 << 1), + drm_vmw_synccpu_dontblock = (1 << 2), + drm_vmw_synccpu_allow_cs = (1 << 3) +}; + +/** + * enum drm_vmw_synccpu_op - Synccpu operations: + * + * @drm_vmw_synccpu_grab: Grab the buffer for CPU operations + * @drm_vmw_synccpu_release: Release a previous grab. + */ +enum drm_vmw_synccpu_op { + drm_vmw_synccpu_grab, + drm_vmw_synccpu_release +}; + +/** + * struct drm_vmw_synccpu_arg + * + * @op: The synccpu operation as described above. + * @handle: Handle identifying the buffer object. + * @flags: Flags as described above. + */ +struct drm_vmw_synccpu_arg { + enum drm_vmw_synccpu_op op; + enum drm_vmw_synccpu_flags flags; + uint32_t handle; + uint32_t pad64; +}; + #endif --- linux-3.13.0.orig/include/uapi/linux/hyperv.h +++ linux-3.13.0/include/uapi/linux/hyperv.h @@ -0,0 +1,390 @@ +/* + * + * Copyright (c) 2011, Microsoft Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Authors: + * Haiyang Zhang + * Hank Janssen + * K. Y. Srinivasan + * + */ + +#ifndef _UAPI_HYPERV_H +#define _UAPI_HYPERV_H + +#include + +/* + * Framework version for util services. + */ +#define UTIL_FW_MINOR 0 + +#define UTIL_WS2K8_FW_MAJOR 1 +#define UTIL_WS2K8_FW_VERSION (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR) + +#define UTIL_FW_MAJOR 3 +#define UTIL_FW_VERSION (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR) + + +/* + * Implementation of host controlled snapshot of the guest. + */ + +#define VSS_OP_REGISTER 128 + +enum hv_vss_op { + VSS_OP_CREATE = 0, + VSS_OP_DELETE, + VSS_OP_HOT_BACKUP, + VSS_OP_GET_DM_INFO, + VSS_OP_BU_COMPLETE, + /* + * Following operations are only supported with IC version >= 5.0 + */ + VSS_OP_FREEZE, /* Freeze the file systems in the VM */ + VSS_OP_THAW, /* Unfreeze the file systems */ + VSS_OP_AUTO_RECOVER, + VSS_OP_COUNT /* Number of operations, must be last */ +}; + + +/* + * Header for all VSS messages. + */ +struct hv_vss_hdr { + __u8 operation; + __u8 reserved[7]; +} __attribute__((packed)); + + +/* + * Flag values for the hv_vss_check_feature. Linux supports only + * one value. + */ +#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005 + +struct hv_vss_check_feature { + __u32 flags; +} __attribute__((packed)); + +struct hv_vss_check_dm_info { + __u32 flags; +} __attribute__((packed)); + +struct hv_vss_msg { + union { + struct hv_vss_hdr vss_hdr; + int error; + }; + union { + struct hv_vss_check_feature vss_cf; + struct hv_vss_check_dm_info dm_info; + }; +} __attribute__((packed)); + +/* + * Implementation of a host to guest copy facility. + */ + +#define FCOPY_VERSION_0 0 +#define FCOPY_CURRENT_VERSION FCOPY_VERSION_0 +#define W_MAX_PATH 260 + +enum hv_fcopy_op { + START_FILE_COPY = 0, + WRITE_TO_FILE, + COMPLETE_FCOPY, + CANCEL_FCOPY, +}; + +struct hv_fcopy_hdr { + __u32 operation; + uuid_le service_id0; /* currently unused */ + uuid_le service_id1; /* currently unused */ +} __attribute__((packed)); + +#define OVER_WRITE 0x1 +#define CREATE_PATH 0x2 + +struct hv_start_fcopy { + struct hv_fcopy_hdr hdr; + __u16 file_name[W_MAX_PATH]; + __u16 path_name[W_MAX_PATH]; + __u32 copy_flags; + __u64 file_size; +} __attribute__((packed)); + +/* + * The file is chunked into fragments. + */ +#define DATA_FRAGMENT (6 * 1024) + +struct hv_do_fcopy { + struct hv_fcopy_hdr hdr; + __u64 offset; + __u32 size; + __u8 data[DATA_FRAGMENT]; +}; + +/* + * An implementation of HyperV key value pair (KVP) functionality for Linux. + * + * + * Copyright (C) 2010, Novell, Inc. + * Author : K. Y. Srinivasan + * + */ + +/* + * Maximum value size - used for both key names and value data, and includes + * any applicable NULL terminators. + * + * Note: This limit is somewhat arbitrary, but falls easily within what is + * supported for all native guests (back to Win 2000) and what is reasonable + * for the IC KVP exchange functionality. Note that Windows Me/98/95 are + * limited to 255 character key names. + * + * MSDN recommends not storing data values larger than 2048 bytes in the + * registry. + * + * Note: This value is used in defining the KVP exchange message - this value + * cannot be modified without affecting the message size and compatibility. + */ + +/* + * bytes, including any null terminators + */ +#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048) + + +/* + * Maximum key size - the registry limit for the length of an entry name + * is 256 characters, including the null terminator + */ + +#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512) + +/* + * In Linux, we implement the KVP functionality in two components: + * 1) The kernel component which is packaged as part of the hv_utils driver + * is responsible for communicating with the host and responsible for + * implementing the host/guest protocol. 2) A user level daemon that is + * responsible for data gathering. + * + * Host/Guest Protocol: The host iterates over an index and expects the guest + * to assign a key name to the index and also return the value corresponding to + * the key. The host will have atmost one KVP transaction outstanding at any + * given point in time. The host side iteration stops when the guest returns + * an error. Microsoft has specified the following mapping of key names to + * host specified index: + * + * Index Key Name + * 0 FullyQualifiedDomainName + * 1 IntegrationServicesVersion + * 2 NetworkAddressIPv4 + * 3 NetworkAddressIPv6 + * 4 OSBuildNumber + * 5 OSName + * 6 OSMajorVersion + * 7 OSMinorVersion + * 8 OSVersion + * 9 ProcessorArchitecture + * + * The Windows host expects the Key Name and Key Value to be encoded in utf16. + * + * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the + * data gathering functionality in a user mode daemon. The user level daemon + * is also responsible for binding the key name to the index as well. The + * kernel and user-level daemon communicate using a connector channel. + * + * The user mode component first registers with the + * the kernel component. Subsequently, the kernel component requests, data + * for the specified keys. In response to this message the user mode component + * fills in the value corresponding to the specified key. We overload the + * sequence field in the cn_msg header to define our KVP message types. + * + * + * The kernel component simply acts as a conduit for communication between the + * Windows host and the user-level daemon. The kernel component passes up the + * index received from the Host to the user-level daemon. If the index is + * valid (supported), the corresponding key as well as its + * value (both are strings) is returned. If the index is invalid + * (not supported), a NULL key string is returned. + */ + + +/* + * Registry value types. + */ + +#define REG_SZ 1 +#define REG_U32 4 +#define REG_U64 8 + +/* + * As we look at expanding the KVP functionality to include + * IP injection functionality, we need to maintain binary + * compatibility with older daemons. + * + * The KVP opcodes are defined by the host and it was unfortunate + * that I chose to treat the registration operation as part of the + * KVP operations defined by the host. + * Here is the level of compatibility + * (between the user level daemon and the kernel KVP driver) that we + * will implement: + * + * An older daemon will always be supported on a newer driver. + * A given user level daemon will require a minimal version of the + * kernel driver. + * If we cannot handle the version differences, we will fail gracefully + * (this can happen when we have a user level daemon that is more + * advanced than the KVP driver. + * + * We will use values used in this handshake for determining if we have + * workable user level daemon and the kernel driver. We begin by taking the + * registration opcode out of the KVP opcode namespace. We will however, + * maintain compatibility with the existing user-level daemon code. + */ + +/* + * Daemon code not supporting IP injection (legacy daemon). + */ + +#define KVP_OP_REGISTER 4 + +/* + * Daemon code supporting IP injection. + * The KVP opcode field is used to communicate the + * registration information; so define a namespace that + * will be distinct from the host defined KVP opcode. + */ + +#define KVP_OP_REGISTER1 100 + +enum hv_kvp_exchg_op { + KVP_OP_GET = 0, + KVP_OP_SET, + KVP_OP_DELETE, + KVP_OP_ENUMERATE, + KVP_OP_GET_IP_INFO, + KVP_OP_SET_IP_INFO, + KVP_OP_COUNT /* Number of operations, must be last. */ +}; + +enum hv_kvp_exchg_pool { + KVP_POOL_EXTERNAL = 0, + KVP_POOL_GUEST, + KVP_POOL_AUTO, + KVP_POOL_AUTO_EXTERNAL, + KVP_POOL_AUTO_INTERNAL, + KVP_POOL_COUNT /* Number of pools, must be last. */ +}; + +/* + * Some Hyper-V status codes. + */ + +#define HV_S_OK 0x00000000 +#define HV_E_FAIL 0x80004005 +#define HV_S_CONT 0x80070103 +#define HV_ERROR_NOT_SUPPORTED 0x80070032 +#define HV_ERROR_MACHINE_LOCKED 0x800704F7 +#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F +#define HV_INVALIDARG 0x80070057 +#define HV_GUID_NOTFOUND 0x80041002 + +#define ADDR_FAMILY_NONE 0x00 +#define ADDR_FAMILY_IPV4 0x01 +#define ADDR_FAMILY_IPV6 0x02 + +#define MAX_ADAPTER_ID_SIZE 128 +#define MAX_IP_ADDR_SIZE 1024 +#define MAX_GATEWAY_SIZE 512 + + +struct hv_kvp_ipaddr_value { + __u16 adapter_id[MAX_ADAPTER_ID_SIZE]; + __u8 addr_family; + __u8 dhcp_enabled; + __u16 ip_addr[MAX_IP_ADDR_SIZE]; + __u16 sub_net[MAX_IP_ADDR_SIZE]; + __u16 gate_way[MAX_GATEWAY_SIZE]; + __u16 dns_addr[MAX_IP_ADDR_SIZE]; +} __attribute__((packed)); + + +struct hv_kvp_hdr { + __u8 operation; + __u8 pool; + __u16 pad; +} __attribute__((packed)); + +struct hv_kvp_exchg_msg_value { + __u32 value_type; + __u32 key_size; + __u32 value_size; + __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; + union { + __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; + __u32 value_u32; + __u64 value_u64; + }; +} __attribute__((packed)); + +struct hv_kvp_msg_enumerate { + __u32 index; + struct hv_kvp_exchg_msg_value data; +} __attribute__((packed)); + +struct hv_kvp_msg_get { + struct hv_kvp_exchg_msg_value data; +}; + +struct hv_kvp_msg_set { + struct hv_kvp_exchg_msg_value data; +}; + +struct hv_kvp_msg_delete { + __u32 key_size; + __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; +}; + +struct hv_kvp_register { + __u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; +}; + +struct hv_kvp_msg { + union { + struct hv_kvp_hdr kvp_hdr; + int error; + }; + union { + struct hv_kvp_msg_get kvp_get; + struct hv_kvp_msg_set kvp_set; + struct hv_kvp_msg_delete kvp_delete; + struct hv_kvp_msg_enumerate kvp_enum_data; + struct hv_kvp_ipaddr_value kvp_ip_val; + struct hv_kvp_register kvp_register; + } body; +} __attribute__((packed)); + +struct hv_kvp_ip_msg { + __u8 operation; + __u8 pool; + struct hv_kvp_ipaddr_value kvp_ip_val; +} __attribute__((packed)); + +#endif /* _UAPI_HYPERV_H */ --- linux-3.13.0.orig/include/uapi/linux/Kbuild +++ linux-3.13.0/include/uapi/linux/Kbuild @@ -139,6 +139,7 @@ header-y += hiddev.h header-y += hidraw.h header-y += hpet.h +header-y += hyperv.h header-y += hysdn_if.h header-y += i2c-dev.h header-y += i2c.h --- linux-3.13.0.orig/include/uapi/linux/nvme.h +++ linux-3.13.0/include/uapi/linux/nvme.h @@ -350,6 +350,16 @@ __u32 rsvd11[5]; }; +struct nvme_abort_cmd { + __u8 opcode; + __u8 flags; + __u16 command_id; + __u32 rsvd1[9]; + __le16 sqid; + __u16 cid; + __u32 rsvd11[5]; +}; + struct nvme_download_firmware { __u8 opcode; __u8 flags; @@ -384,6 +394,7 @@ struct nvme_download_firmware dlfw; struct nvme_format_cmd format; struct nvme_dsm_cmd dsm; + struct nvme_abort_cmd abort; }; }; --- linux-3.13.0.orig/include/uapi/linux/mic_ioctl.h +++ linux-3.13.0/include/uapi/linux/mic_ioctl.h @@ -39,7 +39,7 @@ #else struct iovec *iov; #endif - int iovcnt; + __u32 iovcnt; __u8 vr_idx; __u8 update_used; __u32 out_len; --- linux-3.13.0.orig/include/uapi/linux/fmd/Kbuild +++ linux-3.13.0/include/uapi/linux/fmd/Kbuild @@ -0,0 +1,5 @@ +header-y += integrations/ +header-y += Peripherals/ + +header-y += ioctls.h +header-y += net_ioctls.h --- linux-3.13.0.orig/include/uapi/linux/fmd/integrations/Kbuild +++ linux-3.13.0/include/uapi/linux/fmd/integrations/Kbuild @@ -0,0 +1 @@ +header-y += integration_ioctls.h --- linux-3.13.0.orig/include/uapi/linux/fmd/Peripherals/Kbuild +++ linux-3.13.0/include/uapi/linux/fmd/Peripherals/Kbuild @@ -0,0 +1,4 @@ +header-y += fm_ioctls.h +header-y += fm_port_ioctls.h +header-y += fm_pcd_ioctls.h +header-y += fm_test_ioctls.h --- linux-3.13.0.orig/include/drm/drmP.h +++ linux-3.13.0/include/drm/drmP.h @@ -183,6 +183,9 @@ #define DRM_INFO(fmt, ...) \ printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__) +#define DRM_INFO_ONCE(fmt, ...) \ + printk_once(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__) + /** * Debug output. * @@ -841,6 +844,7 @@ * * \param dev DRM device. * \param crtc Id of the crtc to query. + * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). * \param *vpos Target location for current vertical scanout position. * \param *hpos Target location for current horizontal scanout position. * \param *stime Target location for timestamp taken immediately before @@ -863,6 +867,7 @@ * */ int (*get_scanout_position) (struct drm_device *dev, int crtc, + unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime); @@ -1398,8 +1403,10 @@ int crtc, int *max_error, struct timeval *vblank_time, unsigned flags, - struct drm_crtc *refcrtc); -extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); + const struct drm_crtc *refcrtc, + const struct drm_display_mode *mode); +extern void drm_calc_timestamping_constants(struct drm_crtc *crtc, + const struct drm_display_mode *mode); extern bool drm_mode_parse_command_line_for_connector(const char *mode_option, --- linux-3.13.0.orig/include/drm/drm_crtc.h +++ linux-3.13.0/include/drm/drm_crtc.h @@ -929,6 +929,19 @@ struct drm_crtc *crtc, const struct drm_crtc_funcs *funcs); extern void drm_crtc_cleanup(struct drm_crtc *crtc); +extern unsigned int drm_crtc_index(struct drm_crtc *crtc); + +/** + * drm_crtc_mask - find the mask of a registered CRTC + * @crtc: CRTC to find mask for + * + * Given a registered CRTC, return the mask bit of that CRTC for an + * encoder's possible_crtcs field. + */ +static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc) +{ + return 1 << drm_crtc_index(crtc); +} extern void drm_connector_ida_init(void); extern void drm_connector_ida_destroy(void); @@ -950,6 +963,19 @@ const struct drm_encoder_funcs *funcs, int encoder_type); +/** + * drm_encoder_crtc_ok - can a given crtc drive a given encoder? + * @encoder: encoder to test + * @crtc: crtc to test + * + * Return false if @encoder can't be driven by @crtc, true otherwise. + */ +static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder, + struct drm_crtc *crtc) +{ + return !!(encoder->possible_crtcs & drm_crtc_mask(crtc)); +} + extern int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, unsigned long possible_crtcs, --- linux-3.13.0.orig/include/drm/drm_dp_helper.h +++ linux-3.13.0/include/drm/drm_dp_helper.h @@ -58,6 +58,23 @@ #define AUX_I2C_REPLY_DEFER (0x2 << 6) #define AUX_I2C_REPLY_MASK (0x3 << 6) +#define DP_AUX_I2C_WRITE 0x0 +#define DP_AUX_I2C_READ 0x1 +#define DP_AUX_I2C_STATUS 0x2 +#define DP_AUX_I2C_MOT 0x4 +#define DP_AUX_NATIVE_WRITE 0x8 +#define DP_AUX_NATIVE_READ 0x9 + +#define DP_AUX_NATIVE_REPLY_ACK (0x0 << 0) +#define DP_AUX_NATIVE_REPLY_NACK (0x1 << 0) +#define DP_AUX_NATIVE_REPLY_DEFER (0x2 << 0) +#define DP_AUX_NATIVE_REPLY_MASK (0x3 << 0) + +#define DP_AUX_I2C_REPLY_ACK (0x0 << 2) +#define DP_AUX_I2C_REPLY_NACK (0x1 << 2) +#define DP_AUX_I2C_REPLY_DEFER (0x2 << 2) +#define DP_AUX_I2C_REPLY_MASK (0x3 << 2) + /* AUX CH addresses */ /* DPCD */ #define DP_DPCD_REV 0x000 --- linux-3.13.0.orig/include/drm/i915_drm_bdw.h +++ linux-3.13.0/include/drm/i915_drm_bdw.h @@ -0,0 +1,35 @@ +/* + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef _I915_DRM_BDW_H_ +#define _I915_DRM_BDW_H_ + +/* For use by IPS driver */ +extern unsigned long i915_bdw_read_mch_val(void); +extern bool i915_bdw_gpu_raise(void); +extern bool i915_bdw_gpu_lower(void); +extern bool i915_bdw_gpu_busy(void); +extern bool i915_bdw_gpu_turbo_disable(void); +#endif /* _I915_DRM_BDW_H_ */ --- linux-3.13.0.orig/include/drm/ttm/ttm_object.h +++ linux-3.13.0/include/drm/ttm/ttm_object.h @@ -190,14 +190,26 @@ * @key: Hash key * * Looks up a struct ttm_base_object with the key @key. - * Also verifies that the object is visible to the application, by - * comparing the @tfile argument and checking the object shareable flag. */ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, uint32_t key); /** + * ttm_base_object_lookup_for_ref + * + * @tdev: Pointer to a struct ttm_object_device. + * @key: Hash key + * + * Looks up a struct ttm_base_object with the key @key. + * This function should only be used when the struct tfile associated with the + * caller doesn't yet have a reference to the base object. + */ + +extern struct ttm_base_object * +ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key); + +/** * ttm_base_object_unref * * @p_base: Pointer to a pointer referencing a struct ttm_base_object. @@ -218,6 +230,8 @@ * @existed: Upon completion, indicates that an identical reference object * already existed, and the refcount was upped on that object instead. * + * Checks that the base object is shareable and adds a ref object to it. + * * Adding a ref object to a base object is basically like referencing the * base object, but a user-space application holds the reference. When the * file corresponding to @tfile is closed, all its reference objects are --- linux-3.13.0.orig/include/xen/platform_pci.h +++ linux-3.13.0/include/xen/platform_pci.h @@ -48,4 +48,27 @@ extern int xen_platform_pci_unplug; +#if defined(CONFIG_XEN_PVHVM) +extern bool xen_has_pv_devices(void); +extern bool xen_has_pv_disk_devices(void); +extern bool xen_has_pv_nic_devices(void); +extern bool xen_has_pv_and_legacy_disk_devices(void); +#else +static inline bool xen_has_pv_devices(void) +{ + return IS_ENABLED(CONFIG_XEN); +} +static inline bool xen_has_pv_disk_devices(void) +{ + return IS_ENABLED(CONFIG_XEN); +} +static inline bool xen_has_pv_nic_devices(void) +{ + return IS_ENABLED(CONFIG_XEN); +} +static inline bool xen_has_pv_and_legacy_disk_devices(void) +{ + return false; +} +#endif #endif /* _XEN_PLATFORM_PCI_H */ --- linux-3.13.0.orig/include/trace/ftrace.h +++ linux-3.13.0/include/trace/ftrace.h @@ -310,15 +310,12 @@ #undef __array #define __array(type, item, len) \ do { \ - mutex_lock(&event_storage_mutex); \ + char *type_str = #type"["__stringify(len)"]"; \ BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \ - snprintf(event_storage, sizeof(event_storage), \ - "%s[%d]", #type, len); \ - ret = trace_define_field(event_call, event_storage, #item, \ + ret = trace_define_field(event_call, type_str, #item, \ offsetof(typeof(field), item), \ sizeof(field.item), \ is_signed_type(type), FILTER_OTHER); \ - mutex_unlock(&event_storage_mutex); \ if (ret) \ return ret; \ } while (0); --- linux-3.13.0.orig/include/trace/events/vfs.h +++ linux-3.13.0/include/trace/events/vfs.h @@ -0,0 +1,55 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM vfs + +#include + +#if !defined(_TRACE_VFS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_VFS_H + +/* + * Tracepoint for dirtying an inode: + */ +TRACE_EVENT(dirty_inode, + + TP_PROTO(struct inode *inode, struct task_struct *task), + + TP_ARGS(inode, task), + + TP_STRUCT__entry( + __array( char, comm, TASK_COMM_LEN ) + __field( pid_t, pid ) + __array( char, dev, 16 ) + __array( char, file, 32 ) + ), + + TP_fast_assign( + if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { + struct dentry *dentry; + const char *name = "?"; + + dentry = d_find_alias(inode); + if (dentry) { + spin_lock(&dentry->d_lock); + name = (const char *) dentry->d_name.name; + } + + memcpy(__entry->comm, task->comm, TASK_COMM_LEN); + __entry->pid = task->pid; + strlcpy(__entry->file, name, 32); + strlcpy(__entry->dev, inode->i_sb->s_id, 16); + + if (dentry) { + spin_unlock(&dentry->d_lock); + dput(dentry); + } + } + ), + + TP_printk("task=%i (%s) file=%s dev=%s", + __entry->pid, __entry->comm, __entry->file, __entry->dev) +); + +#endif /* _TRACE_VFS_H */ + +/* This part must be outside protection */ +#include --- linux-3.13.0.orig/include/trace/events/power.h +++ linux-3.13.0/include/trace/events/power.h @@ -35,6 +35,59 @@ TP_ARGS(state, cpu_id) ); +TRACE_EVENT(pstate_sample, + + TP_PROTO(u32 core_busy, + u32 scaled_busy, + u32 state, + u64 mperf, + u64 aperf, + u32 energy, + u32 freq + ), + + TP_ARGS(core_busy, + scaled_busy, + state, + mperf, + aperf, + energy, + freq + ), + + TP_STRUCT__entry( + __field(u32, core_busy) + __field(u32, scaled_busy) + __field(u32, state) + __field(u64, mperf) + __field(u64, aperf) + __field(u32, energy) + __field(u32, freq) + + ), + + TP_fast_assign( + __entry->core_busy = core_busy; + __entry->scaled_busy = scaled_busy; + __entry->state = state; + __entry->mperf = mperf; + __entry->aperf = aperf; + __entry->energy = energy; + __entry->freq = freq; + ), + + TP_printk("core_busy=%lu scaled=%lu state=%lu mperf=%llu aperf=%llu energy=%lu freq=%lu ", + (unsigned long)__entry->core_busy, + (unsigned long)__entry->scaled_busy, + (unsigned long)__entry->state, + (unsigned long long)__entry->mperf, + (unsigned long long)__entry->aperf, + (unsigned long)__entry->energy, + (unsigned long)__entry->freq + ) + +); + /* This file can get included multiple times, TRACE_HEADER_MULTI_READ at top */ #ifndef _PWR_EVENT_AVOID_DOUBLE_DEFINING #define _PWR_EVENT_AVOID_DOUBLE_DEFINING --- linux-3.13.0.orig/include/trace/events/writeback.h +++ linux-3.13.0/include/trace/events/writeback.h @@ -287,11 +287,11 @@ __field(int, reason) ), TP_fast_assign( - unsigned long older_than_this = work->older_than_this; + unsigned long *older_than_this = work->older_than_this; strncpy(__entry->name, dev_name(wb->bdi->dev), 32); - __entry->older = older_than_this; + __entry->older = older_than_this ? *older_than_this : 0; __entry->age = older_than_this ? - (jiffies - older_than_this) * 1000 / HZ : -1; + (jiffies - *older_than_this) * 1000 / HZ : -1; __entry->moved = moved; __entry->reason = work->reason; ), --- linux-3.13.0.orig/include/trace/events/fs.h +++ linux-3.13.0/include/trace/events/fs.h @@ -0,0 +1,53 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM fs + +#if !defined(_TRACE_FS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_FS_H + +#include +#include + +TRACE_EVENT(do_sys_open, + + TP_PROTO(const char *filename, int flags, int mode), + + TP_ARGS(filename, flags, mode), + + TP_STRUCT__entry( + __string( filename, filename ) + __field( int, flags ) + __field( int, mode ) + ), + + TP_fast_assign( + __assign_str(filename, filename); + __entry->flags = flags; + __entry->mode = mode; + ), + + TP_printk("\"%s\" %x %o", + __get_str(filename), __entry->flags, __entry->mode) +); + +TRACE_EVENT(open_exec, + + TP_PROTO(const char *filename), + + TP_ARGS(filename), + + TP_STRUCT__entry( + __string( filename, filename ) + ), + + TP_fast_assign( + __assign_str(filename, filename); + ), + + TP_printk("\"%s\"", + __get_str(filename)) +); + +#endif /* _TRACE_FS_H */ + +/* This part must be outside protection */ +#include --- linux-3.13.0.orig/include/net/ping.h +++ linux-3.13.0/include/net/ping.h @@ -33,8 +33,12 @@ struct pingv6_ops { int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len, int *addr_len); - int (*ip6_datagram_recv_ctl)(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb); + void (*ip6_datagram_recv_common_ctl)(struct sock *sk, + struct msghdr *msg, + struct sk_buff *skb); + void (*ip6_datagram_recv_specific_ctl)(struct sock *sk, + struct msghdr *msg, + struct sk_buff *skb); int (*icmpv6_err_convert)(u8 type, u8 code, int *err); void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err, __be16 port, u32 info, u8 *payload); --- linux-3.13.0.orig/include/net/ip.h +++ linux-3.13.0/include/net/ip.h @@ -63,6 +63,7 @@ }; #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) +#define PKTINFO_SKB_CB(skb) ((struct in_pktinfo *)((skb)->cb)) struct ip_ra_chain { struct ip_ra_chain __rcu *next; @@ -461,7 +462,8 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb); void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); -int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc); +int ip_cmsg_send(struct net *net, struct msghdr *msg, + struct ipcm_cookie *ipc, bool allow_ipv6); int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen); int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, --- linux-3.13.0.orig/include/net/tcp.h +++ linux-3.13.0/include/net/tcp.h @@ -1312,7 +1312,8 @@ /* Fast Open cookie. Size 0 means a cookie request */ struct tcp_fastopen_cookie cookie; struct msghdr *data; /* data in MSG_FASTOPEN */ - u16 copied; /* queued in tcp_connect() */ + size_t size; + int copied; /* queued in tcp_connect() */ }; void tcp_free_fastopen_req(struct tcp_sock *tp); --- linux-3.13.0.orig/include/net/transp_v6.h +++ linux-3.13.0/include/net/transp_v6.h @@ -32,8 +32,13 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb); +/* this does all the common and the specific ctl work */ +void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, + struct sk_buff *skb); +void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg, + struct sk_buff *skb); +void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, + struct sk_buff *skb); int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg, struct flowi6 *fl6, struct ipv6_txoptions *opt, --- linux-3.13.0.orig/include/asm-generic/pgtable.h +++ linux-3.13.0/include/asm-generic/pgtable.h @@ -558,6 +558,18 @@ } #endif +#ifndef pmd_move_must_withdraw +static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl, + spinlock_t *old_pmd_ptl) +{ + /* + * With split pmd lock we also need to move preallocated + * PTE page table if new_pmd is on different PMD page table. + */ + return new_pmd_ptl != old_pmd_ptl; +} +#endif + /* * This function is meant to be used by sites walking pagetables with * the mmap_sem hold in read mode to protect against MADV_DONTNEED and --- linux-3.13.0.orig/include/linux/kernel.h +++ linux-3.13.0/include/linux/kernel.h @@ -417,7 +417,7 @@ #define TAINT_PROPRIETARY_MODULE 0 #define TAINT_FORCED_MODULE 1 -#define TAINT_UNSAFE_SMP 2 +#define TAINT_CPU_OUT_OF_SPEC 2 #define TAINT_FORCED_RMMOD 3 #define TAINT_MACHINE_CHECK 4 #define TAINT_BAD_PAGE 5 --- linux-3.13.0.orig/include/linux/ftrace_event.h +++ linux-3.13.0/include/linux/ftrace_event.h @@ -356,10 +356,6 @@ FILTER_TRACE_FN, }; -#define EVENT_STORAGE_SIZE 128 -extern struct mutex event_storage_mutex; -extern char event_storage[EVENT_STORAGE_SIZE]; - extern int trace_event_raw_init(struct ftrace_event_call *call); extern int trace_define_field(struct ftrace_event_call *call, const char *type, const char *name, int offset, int size, --- linux-3.13.0.orig/include/linux/of_mdio.h +++ linux-3.13.0/include/linux/of_mdio.h @@ -22,6 +22,9 @@ extern struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, void (*hndlr)(struct net_device *), phy_interface_t iface); +extern struct phy_device *of_phy_attach(struct net_device *dev, + struct device_node *phy_np, u32 flags, + phy_interface_t iface); extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np); --- linux-3.13.0.orig/include/linux/export.h +++ linux-3.13.0/include/linux/export.h @@ -59,6 +59,7 @@ static const char __kstrtab_##sym[] \ __attribute__((section("__ksymtab_strings"), aligned(1))) \ = VMLINUX_SYMBOL_STR(sym); \ + extern const struct kernel_symbol __ksymtab_##sym; \ __visible const struct kernel_symbol __ksymtab_##sym \ __used \ __attribute__((section("___ksymtab" sec "+" #sym), unused)) \ --- linux-3.13.0.orig/include/linux/page-flags.h +++ linux-3.13.0/include/linux/page-flags.h @@ -109,6 +109,7 @@ #ifdef CONFIG_TRANSPARENT_HUGEPAGE PG_compound_lock, #endif + PG_readaheadunused, /* user oriented readahead as yet unused*/ __NR_PAGEFLAGS, /* Filesystems */ @@ -232,6 +233,8 @@ PAGEFLAG(Reclaim, reclaim) TESTCLEARFLAG(Reclaim, reclaim) PAGEFLAG(Readahead, reclaim) /* Reminder to do async read-ahead */ +PAGEFLAG(ReadaheadUnused, readaheadunused) + #ifdef CONFIG_HIGHMEM /* * Must use a macro here due to header dependency issues. page_zone() is not --- linux-3.13.0.orig/include/linux/netdevice.h +++ linux-3.13.0/include/linux/netdevice.h @@ -2984,7 +2984,12 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev, struct net_device *dev); -netdev_features_t netif_skb_features(struct sk_buff *skb); +netdev_features_t netif_skb_dev_features(struct sk_buff *skb, + const struct net_device *dev); +static inline netdev_features_t netif_skb_features(struct sk_buff *skb) +{ + return netif_skb_dev_features(skb, skb->dev); +} static inline bool net_gso_ok(netdev_features_t features, int gso_type) { --- linux-3.13.0.orig/include/linux/kexec.h +++ linux-3.13.0/include/linux/kexec.h @@ -170,6 +170,7 @@ extern struct kimage *kexec_image; extern struct kimage *kexec_crash_image; +extern int kexec_load_disabled; #ifndef kexec_flush_icache_page #define kexec_flush_icache_page(page) --- linux-3.13.0.orig/include/linux/splice.h +++ linux-3.13.0/include/linux/splice.h @@ -92,4 +92,10 @@ extern void spd_release_page(struct splice_pipe_desc *, unsigned int); extern const struct pipe_buf_operations page_cache_pipe_buf_ops; + +extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); +extern long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); #endif --- linux-3.13.0.orig/include/linux/skbuff.h +++ linux-3.13.0/include/linux/skbuff.h @@ -2371,6 +2371,7 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); void skb_scrub_packet(struct sk_buff *skb, bool xnet); +unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); struct skb_checksum_ops { @@ -2810,5 +2811,22 @@ { return !skb->head_frag || skb_cloned(skb); } + +/** + * skb_gso_network_seglen - Return length of individual segments of a gso packet + * + * @skb: GSO skb + * + * skb_gso_network_seglen is used to determine the real size of the + * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). + * + * The MAC/L2 header is not accounted for. + */ +static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) +{ + unsigned int hdr_len = skb_transport_header(skb) - + skb_network_header(skb); + return hdr_len + skb_gso_transport_seglen(skb); +} #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ --- linux-3.13.0.orig/include/linux/ipc_namespace.h +++ linux-3.13.0/include/linux/ipc_namespace.h @@ -119,9 +119,7 @@ * the new maximum will handle anyone else. I may have to revisit this * in the future. */ -#define MIN_QUEUESMAX 1 #define DFLT_QUEUESMAX 256 -#define HARD_QUEUESMAX 1024 #define MIN_MSGMAX 1 #define DFLT_MSG 10U #define DFLT_MSGMAX 10 --- linux-3.13.0.orig/include/linux/vmstat.h +++ linux-3.13.0/include/linux/vmstat.h @@ -142,8 +142,6 @@ return x; } -extern unsigned long global_reclaimable_pages(void); - #ifdef CONFIG_NUMA /* * Determine the per node value of a stat item. This function --- linux-3.13.0.orig/include/linux/usb.h +++ linux-3.13.0/include/linux/usb.h @@ -1264,8 +1264,6 @@ * @sg: scatter gather buffer list, the buffer size of each element in * the list (except the last) must be divisible by the endpoint's * max packet size if no_sg_constraint isn't set in 'struct usb_bus' - * (FIXME: scatter-gather under xHCI is broken for periodic transfers. - * Do not use urb->sg for interrupt endpoints for now, only bulk.) * @num_mapped_sgs: (internal) number of mapped sg entries * @num_sgs: number of entries in the sg list * @transfer_buffer_length: How big is transfer_buffer. The transfer may --- linux-3.13.0.orig/include/linux/compiler-gcc4.h +++ linux-3.13.0/include/linux/compiler-gcc4.h @@ -75,11 +75,7 @@ * * (asm goto is automatically volatile - the naming reflects this.) */ -#if GCC_VERSION <= 40801 -# define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) -#else -# define asm_volatile_goto(x...) do { asm goto(x); } while (0) -#endif +#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) #ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP #if GCC_VERSION >= 40400 --- linux-3.13.0.orig/include/linux/firewire.h +++ linux-3.13.0/include/linux/firewire.h @@ -200,6 +200,7 @@ unsigned irmc:1; unsigned bc_implemented:2; + work_func_t workfn; struct delayed_work work; struct fw_attribute_group attribute_group; }; --- linux-3.13.0.orig/include/linux/tracepoint.h +++ linux-3.13.0/include/linux/tracepoint.h @@ -60,6 +60,12 @@ unsigned int num_tracepoints; struct tracepoint * const *tracepoints_ptrs; }; +bool trace_module_has_bad_taint(struct module *mod); +#else +static inline bool trace_module_has_bad_taint(struct module *mod) +{ + return false; +} #endif /* CONFIG_MODULES */ struct tracepoint_iter { --- linux-3.13.0.orig/include/linux/ahci_platform.h +++ linux-3.13.0/include/linux/ahci_platform.h @@ -19,7 +19,15 @@ struct device; struct ata_port_info; +struct ahci_host_priv; +struct platform_device; +/* + * Note ahci_platform_data is deprecated, it is only kept around for use + * by the old da850 and spear13xx ahci code. + * New drivers should instead declare their own platform_driver struct, and + * use ahci_platform* functions in their own probe, suspend and resume methods. + */ struct ahci_platform_data { int (*init)(struct device *dev, void __iomem *addr); void (*exit)(struct device *dev); @@ -30,4 +38,21 @@ unsigned int mask_port_map; }; +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv); +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv); +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv); +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv); +struct ahci_host_priv *ahci_platform_get_resources( + struct platform_device *pdev); +int ahci_platform_init_host(struct platform_device *pdev, + struct ahci_host_priv *hpriv, + const struct ata_port_info *pi_template, + unsigned int force_port_map, + unsigned int mask_port_map); + +int ahci_platform_suspend_host(struct device *dev); +int ahci_platform_resume_host(struct device *dev); +int ahci_platform_suspend(struct device *dev); +int ahci_platform_resume(struct device *dev); + #endif /* _AHCI_PLATFORM_H */ --- linux-3.13.0.orig/include/linux/fsl_pme.h +++ linux-3.13.0/include/linux/fsl_pme.h @@ -0,0 +1,795 @@ +/* Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FSL_PME_H +#define FSL_PME_H + +/* pme_fd_res_status() returns this enum */ +enum pme_status { + pme_status_ok = 0x00, + pme_status_kes_ccl = 0x40, /* KES Confidence Collision Limit */ + pme_status_kes_cme = 0x41, /* KES Confidence Mask Error */ + pme_status_dxe_ire = 0x48, /* DXE Invalid Repeat Error */ + pme_status_dxe_tlse = 0x49, /* DXE Test Line Syntax Error */ + pme_status_dxe_ile = 0x4b, /* DXE Instruction Limit Error */ + pme_status_dxe_pdsrsore = 0x4c, /* DXE PDSR Space Out Range Error */ + pme_status_dxe_soe = 0x4d, /* DXE Stack Overflow Error */ + pme_status_dxe_alse = 0x4e, /* DXE Alternate Link Same Error */ + pme_status_dxe_slse = 0x4f, /* DXE Subsequent Link Same Error */ + pme_status_dxe_slre = 0x50, /* DXE Subsequent Link Reverse Error */ + pme_status_dxe_itlb = 0x51, /* DXE Invalid Test Line Branch */ + pme_status_dxe_cle = 0x52, /* DXE Compare Limit Exceeded */ + pme_status_dxe_mle = 0x53, /* DXE Match Limit Exceeded */ + pme_status_sre_irhbni = 0x59, /* SRE Invalid Reaction Head Block */ + /* Number Instructions */ + pme_status_sre_rl = 0x5a, /* SRE Reaction Limit */ + pme_status_sre_pdsrsore = 0x5b, /* SRE PDSR Space Out Range Error */ + pme_status_sre_score = 0x5c, /* SRE Session Context Out Range Error */ + pme_status_sre_ctore = 0x5d, /* SRE Context Table Out Range Error */ + pme_status_sre_il = 0x5e, /* SRE Instruction Limit */ + pme_status_sre_iij = 0x5f, /* SRE Invalid Instruction Jump */ + pme_status_sre_ise = 0x60, /* SRE Instruction Syntax Error */ + pme_status_pmfa_pmtcce = 0x80, /* PMFA PCTCC Error */ + pme_status_pmfa_fcwe = 0x90, /* PMFA Flow Context Write Command Error */ + pme_status_pmfa_fcre = 0x91, /* PMFA Flow Context Read Command Error */ + pme_status_pmfa_ume = 0x93, /* PMFA Unrecognized Mode Error */ + pme_status_pmfa_uce = 0x94, /* PMFA Unrecognized Command Error */ + pme_status_pmfa_ufe = 0x95, /* PMFA Unrecognized Frame Error */ + pme_status_sre_csmre = 0xc0, /* SRE Context System Memory Read Error */ + pme_status_sre_ismre = 0xc1, /* SRE Instruction System Memory Read */ + /* Error */ + pme_status_dxe_smre = 0xc2, /* DXE System Memory Read Error */ + pme_status_pmfa_pmtccsmre = 0xc4, /* PMFA PMTCC System Memory Read */ + /* Error */ + pme_status_pmfa_csmre = 0xc5, /* PMFA Context System Memory Read */ + /* Error */ + pme_status_pmfa_dsmre = 0xc6, /* PMFA Data System Memory Read Error */ + pme_status_kes_cmecce = 0xd2, /* KES Confidence Memory ECC Error */ + pme_status_kes_2btmecce = 0xd4, /*KES 2-Byte Trigger Memory ECC Error */ + pme_status_kes_vltmecce = 0xd5, /*KES Variable Length Trigger Memory */ + /* ECC Error */ + pme_status_pmfa_cmecce = 0xd7, /* PMFA Confidence Memory ECC Error */ + pme_status_pmfa_2btmecce = 0xd9, /* PMFA 2-Byte Trigger Memory ECC */ + /* Error */ + pme_status_pmfa_vltmecce = 0xda, /* PMFA Variable Length Trigger */ + /* Memory ECC Error */ + pme_status_dxe_iemce = 0xdb, /* DXE Internal Examination Memory */ + /* Collision Error */ + pme_status_dxe_iemecce = 0xdc, /* DXE Internal Examination Memory */ + /* ECC Error */ + pme_status_dxe_icmecce = 0xdd, /* DXE Internal Context Memory ECC */ + /* Error */ + pme_status_sre_ctsmwe = 0xe0, /* SRE Context Table System Memory */ + /* Write Error */ + pme_status_pmfa_pmtccsmwe = 0xe7, /* PMFA PMTCC System Memory Write */ + /* Error */ + pme_status_pmfa_csmwe = 0xe8, /* PMFA Context System Memory Write */ + /* Error */ + pme_status_pmfa_dsmwe = 0xe9, /* PMFA Data System Memory Write Error */ +}; + +/* pme_fd_res_flags() returns these flags */ +#define PME_STATUS_UNRELIABLE 0x80 +#define PME_STATUS_TRUNCATED 0x10 +#define PME_STATUS_MASK 0x90 + +/**************/ +/* USER SPACE */ +/**************/ + +#define PME_IOCTL_MAGIC 'p' + +/* Wrapper for a pointer and size. */ +struct pme_buffer { + void __user *data; + size_t size; +}; + +/***************/ +/* SCAN DEVICE */ +/***************/ +/* The /dev/pme_scan device creates a file-descriptor that uses scheduled FQs + * serviced by PME's datapath portal. This can only be used for scanning. */ +#define PME_DEV_SCAN_NODE "pme_scan" +#define PME_DEV_SCAN_PATH "/dev/" PME_DEV_SCAN_NODE + +/* ioctls for 'scan' device */ +#define PMEIO_SETSCAN _IOW(PME_IOCTL_MAGIC, 0x06, struct pme_scan_params) +#define PMEIO_GETSCAN _IOR(PME_IOCTL_MAGIC, 0x07, struct pme_scan_params) +#define PMEIO_RESETSEQ _IO(PME_IOCTL_MAGIC, 0x08) +#define PMEIO_RESETRES _IO(PME_IOCTL_MAGIC, 0x09) +#define PMEIO_SCAN_W1 _IOW(PME_IOCTL_MAGIC, 0x0a, struct pme_scan_cmd) +#define PMEIO_SCAN_Wn _IOWR(PME_IOCTL_MAGIC, 0x0b, struct pme_scan_cmds) +#define PMEIO_SCAN_R1 _IOR(PME_IOCTL_MAGIC, 0x0c, struct pme_scan_result) +#define PMEIO_SCAN_Rn _IOWR(PME_IOCTL_MAGIC, 0x0d, struct pme_scan_results) +#define PMEIO_SCAN _IOWR(PME_IOCTL_MAGIC, 0x0e, struct pme_scan) +/* The release_bufs ioctl takes as parameter a (void *) */ +#define PMEIO_RELEASE_BUFS _IOW(PME_IOCTL_MAGIC, 0x0f, void *) + +/* Parameters for PMEIO_SETSCAN and PMEIO_GETSCAN ioctl()s. This doesn't cover + * "sequence" fields ('soc' and 'seqnum'), they can only be influenced by flags + * passed to scan operations, or by PMEIO_RESETSEQ ioctl()s. */ +struct pme_scan_params { + __u32 flags; /* PME_SCAN_PARAMS_*** bitmask */ + struct pme_scan_params_residue { + __u8 enable; /* boolean, residue enable */ + __u8 length; /* read-only for GETSCAN, ignored for SETSCAN */ + } residue; + struct pme_scan_params_sre { + __u32 sessionid; /* 27-bit */ + __u8 verbose; /* 0-3 */ + __u8 esee; /* boolean, End Of Sui Event Enable */ + } sre; + struct pme_scan_params_dxe { + __u16 clim; /* compare limit */ + __u16 mlim; /* match limit */ + } dxe; + struct pme_scan_params_pattern { + __u8 set; + __u16 subset; + } pattern; +}; +#define PME_SCAN_PARAMS_RESIDUE 0x00000001 +#define PME_SCAN_PARAMS_SRE 0x00000002 +#define PME_SCAN_PARAMS_DXE 0x00000004 +#define PME_SCAN_PARAMS_PATTERN 0x00000008 + +/* argument to PMEIO_SCAN_W1 ioctl */ +struct pme_scan_cmd { + __u32 flags; /* PME_SCAN_CMD_*** bitmask */ + void *opaque; /* value carried through in the pme_scan_result */ + struct pme_buffer input; + struct pme_buffer output; /* ignored for 'RES_BMAN' output */ +}; + +#define PME_SCAN_CMD_RES_BMAN 0x00000001 /* use Bman for output */ +#define PME_SCAN_CMD_STARTRESET 0x00000002 +#define PME_SCAN_CMD_END 0x00000004 + +/* argument to PMEIO_SCAN_Wn ioctl + * 'num' indicates how many 'cmds' are present on input and is updated on the + * response to indicate how many were sent. */ +struct pme_scan_cmds { + unsigned num; + struct pme_scan_cmd __user *cmds; +}; + +/* argument to PMEIO_SCAN_R1 ioctl. The ioctl doesn't read any of these + * fields, they are only written to. If the output comes from BMAN buffer + * then 'flags' will have PME_SCAN_RESULT_BMAN set. */ +struct pme_scan_result { + __u8 flags; /* PME_SCAN_RESULT_*** bitmask */ + enum pme_status status; + struct pme_buffer output; + void *opaque; /* value carried from the pme_scan_cmd */ +}; +#define PME_SCAN_RESULT_UNRELIABLE PME_STATUS_UNRELIABLE +#define PME_SCAN_RESULT_TRUNCATED PME_STATUS_TRUNCATED +#define PME_SCAN_RESULT_BMAN 0x01 + +/* argument to PMEIO_SCAN_Rn ioctl. + * 'num' indicates how many 'cmds' are present on input and is updated on the + * response to indicate how many were retrieved. */ +struct pme_scan_results { + unsigned num; + struct pme_scan_result *results; +}; + +/* argument to PMEIO_SCANWR ioctl. */ +struct pme_scan { + struct pme_scan_cmd cmd; + struct pme_scan_result result; +}; + +/*************/ +/* DB DEVICE */ +/*************/ +/* The /dev/pme_db device creates a file-descriptor that uses parked FQs + * serviced by the PME's EFQC (Exclusive Frame Queue Control) mechanism. This is + * usually for PMTCC commands for programming the database, though can also be + * used for high-priority scanning. This device would typically require root + * perms. The EFQC exclusivity is reference-counted, so by default is asserted + * on-demand and released when processing quiesces for the context, but + * exclusivity can be maintained across inter-frame gaps using the INC and DEC + * ioctls, which provide supplementary increments and decrements of the + * reference count. */ +#define PME_DEV_DB_NODE "pme_db" +#define PME_DEV_DB_PATH "/dev/" PME_DEV_DB_NODE + +/* ioctls for 'db' device */ +#define PMEIO_EXL_INC _IO(PME_IOCTL_MAGIC, 0x00) +#define PMEIO_EXL_DEC _IO(PME_IOCTL_MAGIC, 0x01) +#define PMEIO_EXL_GET _IOR(PME_IOCTL_MAGIC, 0x02, int) +#define PMEIO_PMTCC _IOWR(PME_IOCTL_MAGIC, 0x03, struct pme_db) +#define PMEIO_SRE_RESET _IOR(PME_IOCTL_MAGIC, 0x04, struct pme_db_sre_reset) +#define PMEIO_NOP _IO(PME_IOCTL_MAGIC, 0x05) + +/* Database structures */ +#define PME_DB_RESULT_UNRELIABLE PME_STATUS_UNRELIABLE +#define PME_DB_RESULT_TRUNCATED PME_STATUS_TRUNCATED + +struct pme_db { + struct pme_buffer input; + struct pme_buffer output; + __u8 flags; /* PME_DB_RESULT_*** bitmask */ + enum pme_status status; +}; + +/* This is related to the sre_reset ioctl */ +#define PME_SRE_RULE_VECTOR_SIZE 8 +struct pme_db_sre_reset { + __u32 rule_vector[PME_SRE_RULE_VECTOR_SIZE]; + __u32 rule_index; + __u16 rule_increment; + __u32 rule_repetitions; + __u16 rule_reset_interval; + __u8 rule_reset_priority; +}; + +/****************/ +/* KERNEL SPACE */ +/****************/ + +#ifdef __KERNEL__ + +#include +#include + +/* "struct pme_hw_flow" represents a flow-context resource for h/w, whereas + * "struct pme_flow" (below) is the s/w type used to provide (and receive) + * parameters to(/from) the h/w resource. */ +struct pme_hw_flow; + +/* "struct pme_hw_residue" represents a residue resource for h/w. */ +struct pme_hw_residue; + +/* This is the pme_flow structure type, used for querying or updating a PME flow + * context */ +struct pme_flow { + u8 sos:1; + u8 __reserved1:1; + u8 srvm:2; + u8 esee:1; + u8 __reserved2:3; + u8 ren:1; + u8 rlen:7; + /* Sequence Number (48-bit) */ + u16 seqnum_hi; + u32 seqnum_lo; + u32 __reserved3; + u32 sessionid:27; + u32 __reserved4:5; + u16 __reserved5; + /* Residue pointer (48-bit), ignored if ren==0 */ + u16 rptr_hi; + u32 rptr_lo; + u16 clim; + u16 mlim; + u32 __reserved6; +} __packed; +static inline u64 pme_flow_seqnum_get64(const struct pme_flow *p) +{ + return ((u64)p->seqnum_hi << 32) | (u64)p->seqnum_lo; +} +static inline u64 pme_flow_rptr_get64(const struct pme_flow *p) +{ + return ((u64)p->rptr_hi << 32) | (u64)p->rptr_lo; +} +/* Macro, so we compile better if 'v' isn't always 64-bit */ +#define pme_flow_seqnum_set64(p, v) \ + do { \ + struct pme_flow *__p931 = (p); \ + __p931->seqnum_hi = upper_32_bits(v); \ + __p931->seqnum_lo = lower_32_bits(v); \ + } while (0) +#define pme_flow_rptr_set64(p, v) \ + do { \ + struct pme_flow *__p931 = (p); \ + __p931->rptr_hi = upper_32_bits(v); \ + __p931->rptr_lo = lower_32_bits(v); \ + } while (0) + +/* pme_ctx_ctrl_update_flow(), pme_fd_cmd_fcw() and pme_scan_params::flags + * use these; */ +#define PME_CMD_FCW_RES 0x80 /* "Residue": ren, rlen */ +#define PME_CMD_FCW_SEQ 0x40 /* "Sequence": sos, sequnum */ +#define PME_CMD_FCW_SRE 0x20 /* "Stateful Rule": srvm, esee, sessionid */ +#define PME_CMD_FCW_DXE 0x10 /* "Data Examination": clim, mlim */ +#define PME_CMD_FCW_ALL 0xf0 + +/* pme_ctx_scan() and pme_fd_cmd_scan() use these; */ +#define PME_CMD_SCAN_SRVM(n) ((n) << 3) /* n in [0..3] */ +#define PME_CMD_SCAN_FLUSH 0x04 +#define PME_CMD_SCAN_SR 0x02 /* aka "Start of Flow or Reset */ +#define PME_CMD_SCAN_E 0x01 /* aka "End of Flow */ + +/***********************/ +/* low-level functions */ +/***********************/ + +/* (De)Allocate PME hardware resources */ +struct pme_hw_residue *pme_hw_residue_new(void); +void pme_hw_residue_free(struct pme_hw_residue *); +struct pme_hw_flow *pme_hw_flow_new(void); +void pme_hw_flow_free(struct pme_hw_flow *); + +/* Initialise a flow context to known default values */ +void pme_sw_flow_init(struct pme_flow *); + +/* Fill in an "Initialise FQ" management command for a PME input FQ. NB, the + * caller is responsible for setting the following fields, they will not be set + * by the API; + * - initfq->fqid, the frame queue to be initialised + * - initfq->count, should most likely be zero. A count of 0 initialises 1 FQ, + * a count of 1 initialises 2 FQs, etc/ + * The 'qos' parameter indicates which workqueue in the PME channel the + * FQ should schedule to for regular scanning (0..7). If 'flow' is non-NULL the + * FQ is configured for Flow Mode, otherwise it is configured for Direct Action + * Mode. 'bpid' is the buffer pool ID to use when Bman-based output is + * produced, and 'rfqid' is the frame queue ID to enqueue output frames to. + * Following this api, when calling qm_mc_commit(), use QM_MCC_VERB_INITFQ_SCHED + * for regular PMEscanning or QM_MCC_VERB_INITFQ_PARK for exclusive PME + * processing (usually PMTCC).*/ +void pme_initfq(struct qm_mcc_initfq *initfq, struct pme_hw_flow *flow, u8 qos, + u8 rbpid, u32 rfqid); + +/* Given a dequeued frame from PME, return status/flags */ +static inline enum pme_status pme_fd_res_status(const struct qm_fd *fd) +{ + return (enum pme_status)(fd->status >> 24); +} +static inline u8 pme_fd_res_flags(const struct qm_fd *fd) +{ + return (fd->status >> 16) & PME_STATUS_MASK; +} + +/* Fill in a frame descriptor for a NOP command. */ +void pme_fd_cmd_nop(struct qm_fd *fd); + +/* Fill in a frame descriptor for a Flow Context Write command. NB, the caller + * is responsible for setting all the relevant fields in 'flow', only the + * following fields are set by the API; + * - flow->rptr_hi + * - flow->rptr_lo + * The fields in 'flow' are divided into 4 groups, 'flags' indicates which of + * them should be written to the h/w flow context using PME_CMD_FCW_*** defines. + * 'residue' should be non-NULL iff flow->ren is non-zero and PME_CMD_FCW_RES is + * set. */ +void pme_fd_cmd_fcw(struct qm_fd *fd, u8 flags, struct pme_flow *flow, + struct pme_hw_residue *residue); + +/* Fill in a frame descriptor for a Flow Context Read command. */ +void pme_fd_cmd_fcr(struct qm_fd *fd, struct pme_flow *flow); + +/* Modify a frame descriptor for a PMTCC command (only modifies 'cmd' field) */ +void pme_fd_cmd_pmtcc(struct qm_fd *fd); + +/* Modify a frame descriptor for a Scan command (only modifies 'cmd' field). + * 'flags' are chosen from PME_CMD_SCAN_*** symbols. NB, the use of the + * intermediary representation (and PME_SCAN_ARGS) improves performance - ie. + * if the scan params are essentially constant, this compacts them for storage + * into the same format used in the interface to h/w. So it reduces parameter + * passing, stack-use, and encoding time. */ +#define PME_SCAN_ARGS(flags, set, subset) \ +({ \ + u8 __flags461 = (flags); \ + u8 __set461 = (set); \ + u16 __subset461 = (subset); \ + u32 __res461 = ((u32)__flags461 << 24) | \ + ((u32)__set461 << 16) | \ + (u32)__subset461; \ + __res461; \ +}) +void pme_fd_cmd_scan(struct qm_fd *fd, u32 args); + +/* convert pointer to physical address for use by PME */ +dma_addr_t pme_map(void *ptr); +int pme_map_error(dma_addr_t dma_addr); + +enum pme_cmd_type { + pme_cmd_nop = 0x7, + pme_cmd_flow_read = 0x5, /* aka FCR */ + pme_cmd_flow_write = 0x4, /* aka FCW */ + pme_cmd_pmtcc = 0x1, + pme_cmd_scan = 0 +}; + +/************************/ +/* high-level functions */ +/************************/ + +/* predeclaration of a private structure" */ +struct pme_ctx; +struct pme_nostash; + +/* Calls to pme_ctx_scan() and pme_ctx_pmtcc() provide these, and they are + * provided back in the completion callback. You can embed this within a larger + * structure in order to maintain per-command data of your own. The fields are + * owned by the driver until the callback is invoked, so for example do not link + * this token into a list while the command is in-flight! */ +struct pme_ctx_token { + u32 blob[4]; + struct list_head node; + enum pme_cmd_type cmd_type:8; + u8 is_disable_flush; +}; + +struct pme_ctx_ctrl_token { + void (*cb)(struct pme_ctx *, const struct qm_fd *, + struct pme_ctx_ctrl_token *); + void (*ern_cb)(struct pme_ctx *, const struct qm_mr_entry *, + struct pme_ctx_ctrl_token *); + /* don't touch the rest */ + struct pme_hw_flow *internal_flow_ptr; + struct pme_flow *usr_flow_ptr; + struct pme_ctx_token base_token; +}; + +/* Scan results invoke a user-provided callback of this type */ +typedef void (*pme_scan_cb)(struct pme_ctx *, const struct qm_fd *, + struct pme_ctx_token *); +/* Enqueue rejections may happen before order-restoration or after (eg. if due + * to congestion or tail-drop). Use * 'rc' code of the 'mr_entry' to + * determine. */ +typedef void (*pme_scan_ern_cb)(struct pme_ctx *, const struct qm_mr_entry *, + struct pme_ctx_token *); + +/* PME "association" - ie. connects two frame-queues, with or without a PME flow + * (if not, direct action mode), and manages mux/demux of scans and flow-context + * updates. To allow state used by your callback to be stashed, as well as + * optimising the PME driver and the Qman driver beneath it, embed this + * structure as the first field in your own context structure. */ +struct pme_ctx { + struct qman_fq fq; + /* IMPORTANT: Set (only) these two fields prior to calling * + * pme_ctx_init(). 'ern_cb' can be NULL if you know you will not + * receive enqueue rejections. */ + pme_scan_cb cb; + pme_scan_ern_cb ern_cb; + /* These fields should not be manipulated directly. Also the structure + * may change and/or grow, so avoid making any alignment or size + * assumptions. */ + atomic_t refs; + volatile u32 flags; + spinlock_t lock; + wait_queue_head_t queue; + struct list_head tokens; + /* TODO: the following "slow-path" values should be bundled into a + * secondary structure so that sizeof(struct pme_ctx) is minimised (for + * stashing of caller-side fast-path state). */ + struct pme_hw_flow *hw_flow; + struct pme_hw_residue *hw_residue; + struct qm_fqd_stashing stashing; + struct qm_fd update_fd; + struct pme_nostash *us_data; +}; + +/* Flags for pme_ctx_init() */ +#define PME_CTX_FLAG_LOCKED 0x00000001 /* use QMAN_FQ_FLAG_LOCKED */ +#define PME_CTX_FLAG_EXCLUSIVE 0x00000002 /* unscheduled, exclusive mode */ +#define PME_CTX_FLAG_PMTCC 0x00000004 /* PMTCC rather than scanning */ +#define PME_CTX_FLAG_DIRECT 0x00000008 /* Direct Action mode (not Flow) */ +#define PME_CTX_FLAG_LOCAL 0x00000020 /* Ignore dest, use cpu portal */ + +/* Flags for operations */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT +#define PME_CTX_OP_WAIT QMAN_ENQUEUE_FLAG_WAIT +#define PME_CTX_OP_WAIT_INT QMAN_ENQUEUE_FLAG_WAIT_INT +#endif +#define PME_CTX_OP_RESETRESLEN 0x00000001 /* no en/disable, just set len */ +/* Note that pme_ctx_ctrl_update_flow() also uses PME_CMD_FCW flags, so they + * mustn't conflict with PME_CTX_OP_***. + * Also, the above are defined to match QMAN_ENQUEUE values for optimisation + * purposes (ie. fast-path operations that don't _WAIT will not incur PME->QMAN + * flag conversion overheads). */ + +/** + * pme_ctx_init - Initialise a PME context + * @ctx: the context structure to initialise + * @flags: bit-mask of PME_CTX_FLAG_*** options + * @bpid: buffer pool ID used for any Bman-generated output + * @qosin: workqueue priority on the PME channel (0-7) + * @qosout: workqueue priority on the result channel (0-7) + * @dest: channel to receive results from PME + * @stashing: desired dequeue stashing behaviour + * + * This creates and initialises a PME context, composed of two FQs, an optional + * flow-context, and scheduling parameters for the datapath. The ctx->cb and + * ctx->pool fields must have been initialised prior to calling this api. The + * initialised context is left 'disabled', meaning that the FQ towards PME is + * Parked and no operations are possible. If PME_CTX_INIT_EXCLUSIVE is specified + * in @flags, then the input FQ is not scheduled, otherwise enabling the context + * will schedule the FQ to PME. Exclusive access is only available if the driver + * is built with control functionality and if the operating system has access to + * PME's CCSR map. @qosin applies if EXCLUSIVE is not set, and indicates which + * of the PME's 8 prioritised workqueues the FQ should schedule to. @dest + * indicates the channel that should receive results from PME, unless + * PME_CTX_FLAG_LOCAL is set in which case this parameter is ignored and the + * dedicated portal channel for the current cpu will be used instead. @qosout + * indicates which of the 8 prioritised workqueus the FQ should schedule to on + * the s/w portal. @stashing configures whether FQ context, frame data, and/or + * frame annotation should be stashed into cpu cache when dequeuing output, and + * if so, how many cachelines. For the FQ context part, set the number of + * cachelines to cover; 1. sizeof(struct qman_fq_base), to accelerate only Qman + * driver processing, 2. sizeof(struct pme_ctx), to accelerate Qman and PME + * driver processing, or 3. sizeof(), where is the + * caller's structure of which the pme_ctx is the first member - this will allow + * callbacks to operate on state which has a high probability of already being + * in-cache. + * Returns 0 on success. + */ +int pme_ctx_init(struct pme_ctx *ctx, u32 flags, u32 bpid, u8 qosin, + u8 qosout, enum qm_channel dest, + const struct qm_fqd_stashing *stashing); + +/* Cleanup allocated resources */ +void pme_ctx_finish(struct pme_ctx *ctx); + +/* enable a context */ +int pme_ctx_enable(struct pme_ctx *ctx); + +/* disable a context + * If it returns zero, the context is disabled. + * If it returns +1, the context is disabling and the token's completion + * callback will be invoked when disabling is complete. + * Returns -EBUSY on error, in which case the context remains enabled. + * If the PME_CTX_OP_WAIT flag is specified, it should only fail if + * PME_CTX_OP_WAIT_INT is also specified and a signal is pending. */ +int pme_ctx_disable(struct pme_ctx *ctx, u32 flags, + struct pme_ctx_ctrl_token *token); + +/* query whether a context is disabled. Returns > 0 if the ctx is disabled. */ +int pme_ctx_is_disabled(struct pme_ctx *ctx); + +/* query whether a context is in an error state. */ +int pme_ctx_is_dead(struct pme_ctx *ctx); + +/* A pre-condition for the following APIs is the ctx must be disabled + * dest maybe ignored if the flags parameter indicated LOCAL during the + * corresponding pme_ctx_init. + */ +int pme_ctx_reconfigure_tx(struct pme_ctx *ctx, u32 bpid, u8 qosin); +int pme_ctx_reconfigure_rx(struct pme_ctx *ctx, u8 qosout, + enum qm_channel dest, const struct qm_fqd_stashing *stashing); + +/* Precondition: pme_ctx must be enabled + * if PME_CTX_OP_WAIT is specified, it'll wait (if it has to) to start the ctrl + * command but never waits for it to complete. The callback serves that purpose. + * NB: 'params' may be modified by this call. For instance if + * PME_CTX_OP_RESETRESLEN was specified and residue is enabled, then the + * params->ren will be set to 1 (in order not to disabled residue). + * NB: _update() will overwrite the 'params->rptr_[hi/low]' fields since the + * residue resource is managed by this layer. + */ +int pme_ctx_ctrl_update_flow(struct pme_ctx *ctx, u32 flags, + struct pme_flow *params, struct pme_ctx_ctrl_token *token); +int pme_ctx_ctrl_read_flow(struct pme_ctx *ctx, u32 flags, + struct pme_flow *params, struct pme_ctx_ctrl_token *token); +int pme_ctx_ctrl_nop(struct pme_ctx *ctx, u32 flags, + struct pme_ctx_ctrl_token *token); + +/* if PME_CTX_OP_WAIT is specified, it'll wait (if it has to) to start the scan + * but never waits for it to complete. The scan callback serves that purpose. + * 'fd' is modified by both these calls, but only the 'cmd' field. The 'args' + * parameters is produced by the PME_SCAN_ARGS() inline function. */ +int pme_ctx_scan(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, u32 args, + struct pme_ctx_token *token); +int pme_ctx_pmtcc(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, + struct pme_ctx_token *token); + +/* This is extends pme_ctx_scan() to provide ORP support. 'orp_fq' represents + * the FQD that is used as the ORP and 'seqnum' is the sequence number to use + * for order restoration, these are usually the FQ the frame was dequeued from + * and the sequence number of that dequeued frame (respectively). */ +int pme_ctx_scan_orp(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, u32 args, + struct pme_ctx_token *token, struct qman_fq *orp_fq, u16 seqnum); + +/* Precondition: must be PME_CTX_FLAG_EXCLUSIVE */ +int pme_ctx_exclusive_inc(struct pme_ctx *ctx, u32 flags); +void pme_ctx_exclusive_dec(struct pme_ctx *ctx); + +/* Does pme have access to ccsr */ +int pme2_have_control(void); + +/**************************/ +/* control-plane only API */ +/**************************/ +#ifdef CONFIG_FSL_PME2_CTRL + +/* Attributes for pme_reg_[set|get]() */ +enum pme_attr { + pme_attr_efqc_int, + pme_attr_sw_db, + pme_attr_dmcr, + pme_attr_smcr, + pme_attr_famcr, + pme_attr_kvlts, + pme_attr_max_chain_length, + pme_attr_pattern_range_counter_idx, + pme_attr_pattern_range_counter_mask, + pme_attr_max_allowed_test_line_per_pattern, + pme_attr_max_pdsr_index, + pme_attr_max_pattern_matches_per_sui, + pme_attr_max_pattern_evaluations_per_sui, + pme_attr_report_length_limit, + pme_attr_end_of_simple_sui_report, + pme_attr_aim, + pme_attr_sre_context_size, + pme_attr_sre_rule_num, + pme_attr_sre_session_ctx_num, + pme_attr_end_of_sui_reaction_ptr, + pme_attr_sre_pscl, + pme_attr_sre_max_block_num, + pme_attr_sre_max_instruction_limit, + pme_attr_sre_max_index_size, + pme_attr_sre_max_offset_ctrl, + pme_attr_src_id, + pme_attr_liodnr, + pme_attr_rev1, + pme_attr_rev2, + pme_attr_srrv0, + pme_attr_srrv1, + pme_attr_srrv2, + pme_attr_srrv3, + pme_attr_srrv4, + pme_attr_srrv5, + pme_attr_srrv6, + pme_attr_srrv7, + pme_attr_srrfi, + pme_attr_srri, + pme_attr_srrwc, + pme_attr_srrr, + pme_attr_trunci, + pme_attr_rbc, + pme_attr_tbt0ecc1ec, + pme_attr_tbt1ecc1ec, + pme_attr_vlt0ecc1ec, + pme_attr_vlt1ecc1ec, + pme_attr_cmecc1ec, + pme_attr_dxcmecc1ec, + pme_attr_dxemecc1ec, + pme_attr_stnib, + pme_attr_stnis, + pme_attr_stnth1, + pme_attr_stnth2, + pme_attr_stnthv, + pme_attr_stnths, + pme_attr_stnch, + pme_attr_stnpm, + pme_attr_stns1m, + pme_attr_stnpmr, + pme_attr_stndsr, + pme_attr_stnesr, + pme_attr_stns1r, + pme_attr_stnob, + pme_attr_mia_byc, + pme_attr_mia_blc, + pme_attr_isr, + pme_attr_tbt0ecc1th, + pme_attr_tbt1ecc1th, + pme_attr_vlt0ecc1th, + pme_attr_vlt1ecc1th, + pme_attr_cmecc1th, + pme_attr_dxcmecc1th, + pme_attr_dxemecc1th, + pme_attr_esr, + pme_attr_ecr0, + pme_attr_ecr1, + pme_attr_pmstat, + pme_attr_pmtr, + pme_attr_pehd, + pme_attr_ecc1bes, + pme_attr_ecc2bes, + pme_attr_eccaddr, + pme_attr_ecccode, + pme_attr_miace, + pme_attr_miacr, + pme_attr_cdcr, + pme_attr_faconf, + pme_attr_ier, + pme_attr_isdr, + pme_attr_iir, + pme_attr_pdsrbah, + pme_attr_pdsrbal, + pme_attr_scbarh, + pme_attr_scbarl, + pme_attr_bsc_first, /* create 64-wide space for bsc */ + pme_attr_bsc_last = pme_attr_bsc_first + 63, +}; + +#define pme_attr_bsc(n) (pme_attr_bsc_first + (n)) +/* Get/set driver attributes */ +int pme_attr_set(enum pme_attr attr, u32 val); +int pme_attr_get(enum pme_attr attr, u32 *val); +int pme_stat_get(enum pme_attr stat, u64 *value, int reset); +#endif /* defined(CONFIG_FSL_PME2_CTRL) */ + +#ifdef CONFIG_COMPAT +#include + +struct compat_pme_buffer { + compat_uptr_t data; + compat_size_t size; +}; + +struct compat_pme_scan_cmd { + __u32 flags; /* PME_SCAN_CMD_*** bitmask */ + compat_uptr_t opaque; + struct compat_pme_buffer input; + struct compat_pme_buffer output; +}; +#define PMEIO_SCAN_W132 _IOW(PME_IOCTL_MAGIC, 0x0a, struct compat_pme_scan_cmd) + +struct compat_pme_scan_cmds { + compat_uint_t num; + compat_uptr_t cmds; +}; +#define PMEIO_SCAN_Wn32 _IOWR(PME_IOCTL_MAGIC, 0x0b, \ + struct compat_pme_scan_cmds) + + +struct compat_pme_scan_result { + __u8 flags; /* PME_SCAN_RESULT_*** bitmask */ + enum pme_status status; + struct compat_pme_buffer output; + compat_uptr_t opaque; /* value carried from the pme_scan_cmd */ +}; +#define PMEIO_SCAN_R132 _IOR(PME_IOCTL_MAGIC, 0x0c, \ + struct compat_pme_scan_result) + + +struct compat_pme_scan_results { + compat_uint_t num; + compat_uptr_t results; +}; +#define PMEIO_SCAN_Rn32 _IOWR(PME_IOCTL_MAGIC, 0x0d, \ + struct compat_pme_scan_results) + + +struct compat_pme_scan { + struct compat_pme_scan_cmd cmd; + struct compat_pme_scan_result result; +}; +#define PMEIO_SCAN32 _IOWR(PME_IOCTL_MAGIC, 0x0e, struct compat_pme_scan) + +struct compat_pme_db { + struct compat_pme_buffer input; + struct compat_pme_buffer output; + __u8 flags; /* PME_DB_RESULT_*** bitmask */ + enum pme_status status; +}; +#define PMEIO_PMTCC32 _IOWR(PME_IOCTL_MAGIC, 0x03, struct compat_pme_db) + +#endif /* CONFIG_COMPAT */ + +#endif /* __KERNEL__ */ + +#endif /* FSL_PME_H */ --- linux-3.13.0.orig/include/linux/hyperv.h +++ linux-3.13.0/include/linux/hyperv.h @@ -25,328 +25,11 @@ #ifndef _HYPERV_H #define _HYPERV_H -#include - -/* - * Framework version for util services. - */ -#define UTIL_FW_MINOR 0 - -#define UTIL_WS2K8_FW_MAJOR 1 -#define UTIL_WS2K8_FW_VERSION (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR) - -#define UTIL_FW_MAJOR 3 -#define UTIL_FW_VERSION (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR) - +#include -/* - * Implementation of host controlled snapshot of the guest. - */ - -#define VSS_OP_REGISTER 128 - -enum hv_vss_op { - VSS_OP_CREATE = 0, - VSS_OP_DELETE, - VSS_OP_HOT_BACKUP, - VSS_OP_GET_DM_INFO, - VSS_OP_BU_COMPLETE, - /* - * Following operations are only supported with IC version >= 5.0 - */ - VSS_OP_FREEZE, /* Freeze the file systems in the VM */ - VSS_OP_THAW, /* Unfreeze the file systems */ - VSS_OP_AUTO_RECOVER, - VSS_OP_COUNT /* Number of operations, must be last */ -}; - - -/* - * Header for all VSS messages. - */ -struct hv_vss_hdr { - __u8 operation; - __u8 reserved[7]; -} __attribute__((packed)); - - -/* - * Flag values for the hv_vss_check_feature. Linux supports only - * one value. - */ -#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005 - -struct hv_vss_check_feature { - __u32 flags; -} __attribute__((packed)); - -struct hv_vss_check_dm_info { - __u32 flags; -} __attribute__((packed)); - -struct hv_vss_msg { - union { - struct hv_vss_hdr vss_hdr; - int error; - }; - union { - struct hv_vss_check_feature vss_cf; - struct hv_vss_check_dm_info dm_info; - }; -} __attribute__((packed)); - -/* - * An implementation of HyperV key value pair (KVP) functionality for Linux. - * - * - * Copyright (C) 2010, Novell, Inc. - * Author : K. Y. Srinivasan - * - */ - -/* - * Maximum value size - used for both key names and value data, and includes - * any applicable NULL terminators. - * - * Note: This limit is somewhat arbitrary, but falls easily within what is - * supported for all native guests (back to Win 2000) and what is reasonable - * for the IC KVP exchange functionality. Note that Windows Me/98/95 are - * limited to 255 character key names. - * - * MSDN recommends not storing data values larger than 2048 bytes in the - * registry. - * - * Note: This value is used in defining the KVP exchange message - this value - * cannot be modified without affecting the message size and compatibility. - */ - -/* - * bytes, including any null terminators - */ -#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048) - - -/* - * Maximum key size - the registry limit for the length of an entry name - * is 256 characters, including the null terminator - */ - -#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512) - -/* - * In Linux, we implement the KVP functionality in two components: - * 1) The kernel component which is packaged as part of the hv_utils driver - * is responsible for communicating with the host and responsible for - * implementing the host/guest protocol. 2) A user level daemon that is - * responsible for data gathering. - * - * Host/Guest Protocol: The host iterates over an index and expects the guest - * to assign a key name to the index and also return the value corresponding to - * the key. The host will have atmost one KVP transaction outstanding at any - * given point in time. The host side iteration stops when the guest returns - * an error. Microsoft has specified the following mapping of key names to - * host specified index: - * - * Index Key Name - * 0 FullyQualifiedDomainName - * 1 IntegrationServicesVersion - * 2 NetworkAddressIPv4 - * 3 NetworkAddressIPv6 - * 4 OSBuildNumber - * 5 OSName - * 6 OSMajorVersion - * 7 OSMinorVersion - * 8 OSVersion - * 9 ProcessorArchitecture - * - * The Windows host expects the Key Name and Key Value to be encoded in utf16. - * - * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the - * data gathering functionality in a user mode daemon. The user level daemon - * is also responsible for binding the key name to the index as well. The - * kernel and user-level daemon communicate using a connector channel. - * - * The user mode component first registers with the - * the kernel component. Subsequently, the kernel component requests, data - * for the specified keys. In response to this message the user mode component - * fills in the value corresponding to the specified key. We overload the - * sequence field in the cn_msg header to define our KVP message types. - * - * - * The kernel component simply acts as a conduit for communication between the - * Windows host and the user-level daemon. The kernel component passes up the - * index received from the Host to the user-level daemon. If the index is - * valid (supported), the corresponding key as well as its - * value (both are strings) is returned. If the index is invalid - * (not supported), a NULL key string is returned. - */ - - -/* - * Registry value types. - */ - -#define REG_SZ 1 -#define REG_U32 4 -#define REG_U64 8 - -/* - * As we look at expanding the KVP functionality to include - * IP injection functionality, we need to maintain binary - * compatibility with older daemons. - * - * The KVP opcodes are defined by the host and it was unfortunate - * that I chose to treat the registration operation as part of the - * KVP operations defined by the host. - * Here is the level of compatibility - * (between the user level daemon and the kernel KVP driver) that we - * will implement: - * - * An older daemon will always be supported on a newer driver. - * A given user level daemon will require a minimal version of the - * kernel driver. - * If we cannot handle the version differences, we will fail gracefully - * (this can happen when we have a user level daemon that is more - * advanced than the KVP driver. - * - * We will use values used in this handshake for determining if we have - * workable user level daemon and the kernel driver. We begin by taking the - * registration opcode out of the KVP opcode namespace. We will however, - * maintain compatibility with the existing user-level daemon code. - */ - -/* - * Daemon code not supporting IP injection (legacy daemon). - */ - -#define KVP_OP_REGISTER 4 - -/* - * Daemon code supporting IP injection. - * The KVP opcode field is used to communicate the - * registration information; so define a namespace that - * will be distinct from the host defined KVP opcode. - */ - -#define KVP_OP_REGISTER1 100 - -enum hv_kvp_exchg_op { - KVP_OP_GET = 0, - KVP_OP_SET, - KVP_OP_DELETE, - KVP_OP_ENUMERATE, - KVP_OP_GET_IP_INFO, - KVP_OP_SET_IP_INFO, - KVP_OP_COUNT /* Number of operations, must be last. */ -}; - -enum hv_kvp_exchg_pool { - KVP_POOL_EXTERNAL = 0, - KVP_POOL_GUEST, - KVP_POOL_AUTO, - KVP_POOL_AUTO_EXTERNAL, - KVP_POOL_AUTO_INTERNAL, - KVP_POOL_COUNT /* Number of pools, must be last. */ -}; - -/* - * Some Hyper-V status codes. - */ - -#define HV_S_OK 0x00000000 -#define HV_E_FAIL 0x80004005 -#define HV_S_CONT 0x80070103 -#define HV_ERROR_NOT_SUPPORTED 0x80070032 -#define HV_ERROR_MACHINE_LOCKED 0x800704F7 -#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F -#define HV_INVALIDARG 0x80070057 -#define HV_GUID_NOTFOUND 0x80041002 - -#define ADDR_FAMILY_NONE 0x00 -#define ADDR_FAMILY_IPV4 0x01 -#define ADDR_FAMILY_IPV6 0x02 - -#define MAX_ADAPTER_ID_SIZE 128 -#define MAX_IP_ADDR_SIZE 1024 -#define MAX_GATEWAY_SIZE 512 - - -struct hv_kvp_ipaddr_value { - __u16 adapter_id[MAX_ADAPTER_ID_SIZE]; - __u8 addr_family; - __u8 dhcp_enabled; - __u16 ip_addr[MAX_IP_ADDR_SIZE]; - __u16 sub_net[MAX_IP_ADDR_SIZE]; - __u16 gate_way[MAX_GATEWAY_SIZE]; - __u16 dns_addr[MAX_IP_ADDR_SIZE]; -} __attribute__((packed)); - - -struct hv_kvp_hdr { - __u8 operation; - __u8 pool; - __u16 pad; -} __attribute__((packed)); - -struct hv_kvp_exchg_msg_value { - __u32 value_type; - __u32 key_size; - __u32 value_size; - __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; - union { - __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; - __u32 value_u32; - __u64 value_u64; - }; -} __attribute__((packed)); - -struct hv_kvp_msg_enumerate { - __u32 index; - struct hv_kvp_exchg_msg_value data; -} __attribute__((packed)); - -struct hv_kvp_msg_get { - struct hv_kvp_exchg_msg_value data; -}; - -struct hv_kvp_msg_set { - struct hv_kvp_exchg_msg_value data; -}; - -struct hv_kvp_msg_delete { - __u32 key_size; - __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; -}; - -struct hv_kvp_register { - __u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; -}; - -struct hv_kvp_msg { - union { - struct hv_kvp_hdr kvp_hdr; - int error; - }; - union { - struct hv_kvp_msg_get kvp_get; - struct hv_kvp_msg_set kvp_set; - struct hv_kvp_msg_delete kvp_delete; - struct hv_kvp_msg_enumerate kvp_enum_data; - struct hv_kvp_ipaddr_value kvp_ip_val; - struct hv_kvp_register kvp_register; - } body; -} __attribute__((packed)); - -struct hv_kvp_ip_msg { - __u8 operation; - __u8 pool; - struct hv_kvp_ipaddr_value kvp_ip_val; -} __attribute__((packed)); - -#ifdef __KERNEL__ +#include #include #include -#include #include #include #include @@ -875,7 +558,7 @@ struct vmbus_channel_initiate_contact { struct vmbus_channel_message_header header; u32 vmbus_version_requested; - u32 padding2; + u32 target_vcpu; /* The VCPU the host should respond to */ u64 interrupt_page; u64 monitor_page1; u64 monitor_page2; @@ -1352,6 +1035,17 @@ } /* + * Guest File Copy Service + * {34D14BE3-DEE4-41c8-9AE7-6B174977C192} + */ + +#define HV_FCOPY_GUID \ + .guid = { \ + 0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \ + 0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \ + } + +/* * Common header for Hyper-V ICs */ @@ -1459,11 +1153,12 @@ void hv_vss_deinit(void); void hv_vss_onchannelcallback(void *); +extern struct resource hyperv_mmio; + /* * Negotiated version with the Host. */ extern __u32 vmbus_proto_version; -#endif /* __KERNEL__ */ #endif /* _HYPERV_H */ --- linux-3.13.0.orig/include/linux/libata.h +++ linux-3.13.0/include/linux/libata.h @@ -419,6 +419,8 @@ ATA_HORKAGE_MAX_SEC_LBA48 = (1 << 17), /* Set max sects to 65535 */ ATA_HORKAGE_ATAPI_DMADIR = (1 << 18), /* device requires dmadir */ ATA_HORKAGE_NO_NCQ_TRIM = (1 << 19), /* don't use queued TRIM */ + ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */ + ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ --- linux-3.13.0.orig/include/linux/audit.h +++ linux-3.13.0/include/linux/audit.h @@ -137,7 +137,7 @@ { if (unlikely(current->audit_context)) { int success = is_syscall_success(pt_regs); - int return_code = regs_return_value(pt_regs); + long return_code = regs_return_value(pt_regs); __audit_syscall_exit(success, return_code); } --- linux-3.13.0.orig/include/linux/mount.h +++ linux-3.13.0/include/linux/mount.h @@ -71,6 +71,9 @@ extern void mnt_unpin(struct vfsmount *mnt); extern int __mnt_is_readonly(struct vfsmount *mnt); +struct path; +extern struct vfsmount *clone_private_mount(struct path *path); + struct file_system_type; extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, int flags, const char *name, --- linux-3.13.0.orig/include/linux/Kbuild +++ linux-3.13.0/include/linux/Kbuild @@ -0,0 +1 @@ +header-y += fmd/ --- linux-3.13.0.orig/include/linux/fsl_bman.h +++ linux-3.13.0/include/linux/fsl_bman.h @@ -0,0 +1,471 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FSL_BMAN_H +#define FSL_BMAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Last updated for v00.79 of the BG */ + +/* Portal processing (interrupt) sources */ +#define BM_PIRQ_RCRI 0x00000002 /* RCR Ring (below threshold) */ +#define BM_PIRQ_BSCN 0x00000001 /* Buffer depletion State Change */ + +/* This wrapper represents a bit-array for the depletion state of the 64 Bman + * buffer pools. */ +struct bman_depletion { + u32 __state[2]; +}; +#define BMAN_DEPLETION_EMPTY { { 0x00000000, 0x00000000 } } +#define BMAN_DEPLETION_FULL { { 0xffffffff, 0xffffffff } } +#define __bmdep_word(x) ((x) >> 5) +#define __bmdep_shift(x) ((x) & 0x1f) +#define __bmdep_bit(x) (0x80000000 >> __bmdep_shift(x)) +static inline void bman_depletion_init(struct bman_depletion *c) +{ + c->__state[0] = c->__state[1] = 0; +} +static inline void bman_depletion_fill(struct bman_depletion *c) +{ + c->__state[0] = c->__state[1] = ~0; +} +static inline int bman_depletion_get(const struct bman_depletion *c, u8 bpid) +{ + return c->__state[__bmdep_word(bpid)] & __bmdep_bit(bpid); +} +static inline void bman_depletion_set(struct bman_depletion *c, u8 bpid) +{ + c->__state[__bmdep_word(bpid)] |= __bmdep_bit(bpid); +} +static inline void bman_depletion_unset(struct bman_depletion *c, u8 bpid) +{ + c->__state[__bmdep_word(bpid)] &= ~__bmdep_bit(bpid); +} + +/* ------------------------------------------------------- */ +/* --- Bman data structures (and associated constants) --- */ + +/* Represents s/w corenet portal mapped data structures */ +struct bm_rcr_entry; /* RCR (Release Command Ring) entries */ +struct bm_mc_command; /* MC (Management Command) command */ +struct bm_mc_result; /* MC result */ + +/* Code-reduction, define a wrapper for 48-bit buffers. In cases where a buffer + * pool id specific to this buffer is needed (BM_RCR_VERB_CMD_BPID_MULTI, + * BM_MCC_VERB_ACQUIRE), the 'bpid' field is used. */ +struct bm_buffer { + union { + struct { + u8 __reserved1; + u8 bpid; + u16 hi; /* High 16-bits of 48-bit address */ + u32 lo; /* Low 32-bits of 48-bit address */ + }; + struct { + u64 __notaddress:16; + u64 addr:48; + }; + }; +} __attribute__((aligned(8))); +static inline u64 bm_buffer_get64(const struct bm_buffer *buf) +{ + return buf->addr; +} +static inline dma_addr_t bm_buf_addr(const struct bm_buffer *buf) +{ + return (dma_addr_t)buf->addr; +} +/* Macro, so we compile better if 'v' isn't always 64-bit */ +/* Note: this first version is causing a noticable performance degradation, + * which needs analysis, so leaving it commented out for now. The second version + * achieves optimal performance. */ +#if 0 +#define bm_buffer_set64(buf, v) \ + do { \ + struct bm_buffer *__buf931 = (buf); \ + __buf931->addr = v; \ + } while (0) +#else +#define bm_buffer_set64(buf, v) \ + do { \ + struct bm_buffer *__buf931 = (buf); \ + __buf931->hi = upper_32_bits(v); \ + __buf931->lo = lower_32_bits(v); \ + } while (0) +#endif + +/* See 1.5.3.5.4: "Release Command" */ +struct bm_rcr_entry { + union { + struct { + u8 __dont_write_directly__verb; + u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */ + u8 __reserved1[62]; + }; + struct bm_buffer bufs[8]; + }; +} __packed; +#define BM_RCR_VERB_VBIT 0x80 +#define BM_RCR_VERB_CMD_MASK 0x70 /* one of two values; */ +#define BM_RCR_VERB_CMD_BPID_SINGLE 0x20 +#define BM_RCR_VERB_CMD_BPID_MULTI 0x30 +#define BM_RCR_VERB_BUFCOUNT_MASK 0x0f /* values 1..8 */ + +/* See 1.5.3.1: "Acquire Command" */ +/* See 1.5.3.2: "Query Command" */ +struct bm_mcc_acquire { + u8 bpid; + u8 __reserved1[62]; +} __packed; +struct bm_mcc_query { + u8 __reserved2[63]; +} __packed; +struct bm_mc_command { + u8 __dont_write_directly__verb; + union { + struct bm_mcc_acquire acquire; + struct bm_mcc_query query; + }; +} __packed; +#define BM_MCC_VERB_VBIT 0x80 +#define BM_MCC_VERB_CMD_MASK 0x70 /* where the verb contains; */ +#define BM_MCC_VERB_CMD_ACQUIRE 0x10 +#define BM_MCC_VERB_CMD_QUERY 0x40 +#define BM_MCC_VERB_ACQUIRE_BUFCOUNT 0x0f /* values 1..8 go here */ + +/* See 1.5.3.3: "Acquire Reponse" */ +/* See 1.5.3.4: "Query Reponse" */ +struct bm_pool_state { + u8 __reserved1[32]; + /* "availability state" and "depletion state" */ + struct { + u8 __reserved1[8]; + /* Access using bman_depletion_***() */ + struct bman_depletion state; + } as, ds; +}; +struct bm_mc_result { + union { + struct { + u8 verb; + u8 __reserved1[63]; + }; + union { + struct { + u8 __reserved1; + u8 bpid; + u8 __reserved2[62]; + }; + struct bm_buffer bufs[8]; + } acquire; + struct bm_pool_state query; + }; +} __packed; +#define BM_MCR_VERB_VBIT 0x80 +#define BM_MCR_VERB_CMD_MASK BM_MCC_VERB_CMD_MASK +#define BM_MCR_VERB_CMD_ACQUIRE BM_MCC_VERB_CMD_ACQUIRE +#define BM_MCR_VERB_CMD_QUERY BM_MCC_VERB_CMD_QUERY +#define BM_MCR_VERB_CMD_ERR_INVALID 0x60 +#define BM_MCR_VERB_CMD_ERR_ECC 0x70 +#define BM_MCR_VERB_ACQUIRE_BUFCOUNT BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */ +/* Determine the "availability state" of pool 'p' from a query result 'r' */ +#define BM_MCR_QUERY_AVAILABILITY(r,p) bman_depletion_get(&r->query.as.state,p) +/* Determine the "depletion state" of pool 'p' from a query result 'r' */ +#define BM_MCR_QUERY_DEPLETION(r,p) bman_depletion_get(&r->query.ds.state,p) + +/*******************************************************************/ +/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */ +/*******************************************************************/ + + /* Portal and Buffer Pools */ + /* ----------------------- */ +/* Represents a managed portal */ +struct bman_portal; + +/* This object type represents Bman buffer pools. */ +struct bman_pool; + +struct bman_portal_config { + /* This is used for any "core-affine" portals, ie. default portals + * associated to the corresponding cpu. -1 implies that there is no core + * affinity configured. */ + int cpu; + /* portal interrupt line */ + int irq; + /* the unique index of this portal */ + u32 index; + /* Is this portal shared? (If so, it has coarser locking and demuxes + * processing on behalf of other CPUs.) */ + int is_shared; + /* These are the buffer pool IDs that may be used via this portal. */ + struct bman_depletion mask; +}; + +/* This callback type is used when handling pool depletion entry/exit. The + * 'cb_ctx' value is the opaque value associated with the pool object in + * bman_new_pool(). 'depleted' is non-zero on depletion-entry, and zero on + * depletion-exit. */ +typedef void (*bman_cb_depletion)(struct bman_portal *bm, + struct bman_pool *pool, void *cb_ctx, int depleted); + +/* This struct specifies parameters for a bman_pool object. */ +struct bman_pool_params { + /* index of the buffer pool to encapsulate (0-63), ignored if + * BMAN_POOL_FLAG_DYNAMIC_BPID is set. */ + u32 bpid; + /* bit-mask of BMAN_POOL_FLAG_*** options */ + u32 flags; + /* depletion-entry/exit callback, if BMAN_POOL_FLAG_DEPLETION is set */ + bman_cb_depletion cb; + /* opaque user value passed as a parameter to 'cb' */ + void *cb_ctx; + /* depletion-entry/exit thresholds, if BMAN_POOL_FLAG_THRESH is set. NB: + * this is only allowed if BMAN_POOL_FLAG_DYNAMIC_BPID is used *and* + * when run in the control plane (which controls Bman CCSR). This array + * matches the definition of bm_pool_set(). */ + u32 thresholds[4]; +}; + +/* Flags to bman_new_pool() */ +#define BMAN_POOL_FLAG_NO_RELEASE 0x00000001 /* can't release to pool */ +#define BMAN_POOL_FLAG_ONLY_RELEASE 0x00000002 /* can only release to pool */ +#define BMAN_POOL_FLAG_DEPLETION 0x00000004 /* track depletion entry/exit */ +#define BMAN_POOL_FLAG_DYNAMIC_BPID 0x00000008 /* (de)allocate bpid */ +#define BMAN_POOL_FLAG_THRESH 0x00000010 /* set depletion thresholds */ +#define BMAN_POOL_FLAG_STOCKPILE 0x00000020 /* stockpile to reduce hw ops */ + +/* Flags to bman_release() */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT +#define BMAN_RELEASE_FLAG_WAIT 0x00000001 /* wait if RCR is full */ +#define BMAN_RELEASE_FLAG_WAIT_INT 0x00000002 /* if we wait, interruptible? */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC +#define BMAN_RELEASE_FLAG_WAIT_SYNC 0x00000004 /* if wait, until consumed? */ +#endif +#endif +#define BMAN_RELEASE_FLAG_NOW 0x00000008 /* issue immediate release */ + +/* Flags to bman_acquire() */ +#define BMAN_ACQUIRE_FLAG_STOCKPILE 0x00000001 /* no hw op, stockpile only */ + + /* Portal Management */ + /* ----------------- */ +/** + * bman_get_portal_config - get portal configuration settings + * + * This returns a read-only view of the current cpu's affine portal settings. + */ +const struct bman_portal_config *bman_get_portal_config(void); + +/** + * bman_irqsource_get - return the portal work that is interrupt-driven + * + * Returns a bitmask of BM_PIRQ_**I processing sources that are currently + * enabled for interrupt handling on the current cpu's affine portal. These + * sources will trigger the portal interrupt and the interrupt handler (or a + * tasklet/bottom-half it defers to) will perform the corresponding processing + * work. The bman_poll_***() functions will only process sources that are not in + * this bitmask. If the current CPU is sharing a portal hosted on another CPU, + * this always returns zero. + */ +u32 bman_irqsource_get(void); + +/** + * bman_irqsource_add - add processing sources to be interrupt-driven + * @bits: bitmask of BM_PIRQ_**I processing sources + * + * Adds processing sources that should be interrupt-driven (rather than + * processed via bman_poll_***() functions). Returns zero for success, or + * -EINVAL if the current CPU is sharing a portal hosted on another CPU. */ +int bman_irqsource_add(u32 bits); + +/** + * bman_irqsource_remove - remove processing sources from being interrupt-driven + * @bits: bitmask of BM_PIRQ_**I processing sources + * + * Removes processing sources from being interrupt-driven, so that they will + * instead be processed via bman_poll_***() functions. Returns zero for success, + * or -EINVAL if the current CPU is sharing a portal hosted on another CPU. */ +int bman_irqsource_remove(u32 bits); + +/** + * bman_affine_cpus - return a mask of cpus that have affine portals + */ +const cpumask_t *bman_affine_cpus(void); + +/** + * bman_poll_slow - process anything that isn't interrupt-driven. + * + * This function does any portal processing that isn't interrupt-driven. If the + * current CPU is sharing a portal hosted on another CPU, this function will + * return -EINVAL, otherwise the return value is a bitmask of BM_PIRQ_* sources + * indicating what interrupt sources were actually processed by the call. + * + * NB, unlike the legacy wrapper bman_poll(), this function will + * deterministically check for the presence of portal processing work and do it, + * which implies some latency even if there's nothing to do. The bman_poll() + * wrapper on the other hand (like the qman_poll() wrapper) attenuates this by + * checking for (and doing) portal processing infrequently. Ie. such that + * qman_poll() and bman_poll() can be called from core-processing loops. Use + * bman_poll_slow() when you yourself are deciding when to incur the overhead of + * processing. + */ +u32 bman_poll_slow(void); + +/** + * bman_poll - process anything that isn't interrupt-driven. + * + * Dispatcher logic on a cpu can use this to trigger any maintenance of the + * affine portal. This function does whatever processing is not triggered by + * interrupts. This is a legacy wrapper that can be used in core-processing + * loops but mitigates the performance overhead of portal processing by + * adaptively bypassing true portal processing most of the time. (Processing is + * done once every 10 calls if the previous processing revealed that work needed + * to be done, or once very 1000 calls if the previous processing revealed no + * work needed doing.) If you wish to control this yourself, call + * bman_poll_slow() instead, which always checks for portal processing work. + */ +void bman_poll(void); + +/** + * bman_recovery_cleanup_bpid - in recovery mode, cleanup a buffer pool + */ +int bman_recovery_cleanup_bpid(u32 bpid); + +/** + * bman_recovery_exit - leave recovery mode + */ +int bman_recovery_exit(void); + +/** + * bman_rcr_is_empty - Determine if portal's RCR is empty + * + * For use in situations where a cpu-affine caller needs to determine when all + * releases for the local portal have been processed by Bman but can't use the + * BMAN_RELEASE_FLAG_WAIT_SYNC flag to do this from the final bman_release(). + * The function forces tracking of RCR consumption (which normally doesn't + * happen until release processing needs to find space to put new release + * commands), and returns zero if the ring still has unprocessed entries, + * non-zero if it is empty. + */ +int bman_rcr_is_empty(void); + + + /* Pool management */ + /* --------------- */ +/** + * bman_new_pool - Allocates a Buffer Pool object + * @params: parameters specifying the buffer pool ID and behaviour + * + * Creates a pool object for the given @params. A portal and the depletion + * callback field of @params are only used if the BMAN_POOL_FLAG_DEPLETION flag + * is set. NB, the fields from @params are copied into the new pool object, so + * the structure provided by the caller can be released or reused after the + * function returns. + */ +struct bman_pool *bman_new_pool(const struct bman_pool_params *params); + +/** + * bman_free_pool - Deallocates a Buffer Pool object + * @pool: the pool object to release + * + */ +void bman_free_pool(struct bman_pool *pool); + +/** + * bman_get_params - Returns a pool object's parameters. + * @pool: the pool object + * + * The returned pointer refers to state within the pool object so must not be + * modified and can no longer be read once the pool object is destroyed. + */ +const struct bman_pool_params *bman_get_params(const struct bman_pool *pool); + +/** + * bman_release - Release buffer(s) to the buffer pool + * @pool: the buffer pool object to release to + * @bufs: an array of buffers to release + * @num: the number of buffers in @bufs (1-8) + * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options + * + * Adds the given buffers to RCR entries. If the portal @p was created with the + * "COMPACT" flag, then it will be using a compaction algorithm to improve + * utilisation of RCR. As such, these buffers may join an existing ring entry + * and/or it may not be issued right away so as to allow future releases to join + * the same ring entry. Use the BMAN_RELEASE_FLAG_NOW flag to override this + * behaviour by committing the RCR entry (or entries) right away. If the RCR + * ring is full, the function will return -EBUSY unless BMAN_RELEASE_FLAG_WAIT + * is selected, in which case it will sleep waiting for space to become + * available in RCR. If the function receives a signal before such time (and + * BMAN_RELEASE_FLAG_WAIT_INT is set), the function returns -EINTR. Otherwise, + * it returns zero. + */ +int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num, + u32 flags); + +/** + * bman_acquire - Acquire buffer(s) from a buffer pool + * @pool: the buffer pool object to acquire from + * @bufs: array for storing the acquired buffers + * @num: the number of buffers desired (@bufs is at least this big) + * + * Issues an "Acquire" command via the portal's management command interface. + * The return value will be the number of buffers obtained from the pool, or a + * negative error code if a h/w error or pool starvation was encountered. + */ +int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num, + u32 flags); + +/** + * bman_flush_stockpile - Flush stockpile buffer(s) to the buffer pool + * @pool: the buffer pool object the stockpile belongs + * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options + * + * Adds stockpile buffers to RCR entries until the stockpile is empty. + * The return value will be a negative error code if a h/w error occured. + * If BMAN_RELEASE_FLAG_NOW flag is passed and RCR ring is full, + * -EAGAIN will be returned. + */ +int bman_flush_stockpile(struct bman_pool *pool, u32 flags); + +/** + * bman_query_pools - Query all buffer pool states + * @state: storage for the queried availability and depletion states + */ +int bman_query_pools(struct bm_pool_state *state); + +#ifdef __cplusplus +} +#endif + +#endif /* FSL_BMAN_H */ --- linux-3.13.0.orig/include/linux/writeback.h +++ linux-3.13.0/include/linux/writeback.h @@ -97,7 +97,7 @@ int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason); int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr, enum wb_reason reason); -void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this); +void sync_inodes_sb(struct super_block *); void wakeup_flusher_threads(long nr_pages, enum wb_reason reason); void inode_wait_for_writeback(struct inode *inode); --- linux-3.13.0.orig/include/linux/percpu_ida.h +++ linux-3.13.0/include/linux/percpu_ida.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -61,7 +62,7 @@ /* Max size of percpu freelist, */ #define IDA_DEFAULT_PCPU_SIZE ((IDA_DEFAULT_PCPU_BATCH_MOVE * 3) / 2) -int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp); +int percpu_ida_alloc(struct percpu_ida *pool, int state); void percpu_ida_free(struct percpu_ida *pool, unsigned tag); void percpu_ida_destroy(struct percpu_ida *pool); --- linux-3.13.0.orig/include/linux/mm_types.h +++ linux-3.13.0/include/linux/mm_types.h @@ -231,6 +231,7 @@ unsigned long vm_top; /* region allocated to here */ unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ struct file *vm_file; /* the backing file or NULL */ + struct file *vm_prfile; /* the virtual backing file or NULL */ int vm_usage; /* region usage count (access under nommu_region_sem) */ bool vm_icache_flushed : 1; /* true if the icache has been flushed for @@ -299,6 +300,7 @@ unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */ struct file * vm_file; /* File we map to (can be NULL). */ + struct file *vm_prfile; /* shadow of vm_file */ void * vm_private_data; /* was vm_pte (shared mem) */ #ifndef CONFIG_MMU --- linux-3.13.0.orig/include/linux/fsl_qman.h +++ linux-3.13.0/include/linux/fsl_qman.h @@ -0,0 +1,1761 @@ +/* Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FSL_QMAN_H +#define FSL_QMAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Last updated for v00.800 of the BG */ + +/* Hardware constants */ +enum qm_channel { + qm_channel_swportal0 = 0, qm_channel_swportal1, qm_channel_swportal2, + qm_channel_swportal3, qm_channel_swportal4, qm_channel_swportal5, + qm_channel_swportal6, qm_channel_swportal7, qm_channel_swportal8, + qm_channel_swportal9, + qm_channel_pool1 = 0x21, qm_channel_pool2, qm_channel_pool3, + qm_channel_pool4, qm_channel_pool5, qm_channel_pool6, + qm_channel_pool7, qm_channel_pool8, qm_channel_pool9, + qm_channel_pool10, qm_channel_pool11, qm_channel_pool12, + qm_channel_pool13, qm_channel_pool14, qm_channel_pool15, + qm_channel_fman0_sp0 = 0x40, qm_channel_fman0_sp1, qm_channel_fman0_sp2, + qm_channel_fman0_sp3, qm_channel_fman0_sp4, qm_channel_fman0_sp5, + qm_channel_fman0_sp6, qm_channel_fman0_sp7, qm_channel_fman0_sp8, + qm_channel_fman0_sp9, qm_channel_fman0_sp10, qm_channel_fman0_sp11, + qm_channel_fman1_sp0 = 0x60, qm_channel_fman1_sp1, qm_channel_fman1_sp2, + qm_channel_fman1_sp3, qm_channel_fman1_sp4, qm_channel_fman1_sp5, + qm_channel_fman1_sp6, qm_channel_fman1_sp7, qm_channel_fman1_sp8, + qm_channel_fman1_sp9, qm_channel_fman1_sp10, qm_channel_fman1_sp11, + qm_channel_caam = 0x80, + qm_channel_pme = 0xa0, +}; +enum qm_dc_portal { + qm_dc_portal_fman0 = 0, + qm_dc_portal_fman1 = 1, + qm_dc_portal_caam = 2, + qm_dc_portal_pme = 3 +}; + +/* Portal processing (interrupt) sources */ +#define QM_PIRQ_CSCI 0x00100000 /* Congestion State Change */ +#define QM_PIRQ_EQCI 0x00080000 /* Enqueue Command Committed */ +#define QM_PIRQ_EQRI 0x00040000 /* EQCR Ring (below threshold) */ +#define QM_PIRQ_DQRI 0x00020000 /* DQRR Ring (non-empty) */ +#define QM_PIRQ_MRI 0x00010000 /* MR Ring (non-empty) */ +/* This mask contains all the interrupt sources that need handling except DQRI, + * ie. that if present should trigger slow-path processing. */ +#define QM_PIRQ_SLOW (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | \ + QM_PIRQ_MRI) + + +/* ------------------------ */ +/* --- FQ allocator API --- */ + +/* Flags to qm_fq_free_flags() */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT +#define QM_FQ_FREE_WAIT 0x00000001 /* wait if RCR is full */ +#define QM_FQ_FREE_WAIT_INT 0x00000002 /* if wait, interruptible? */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC +#define QM_FQ_FREE_WAIT_SYNC 0x00000004 /* if wait, until consumed? */ +#endif +#endif + +/* Allocate an unused FQID from the FQ allocator, returns zero for failure */ +u32 qm_fq_new(void); +/* Release a FQID back to the FQ allocator */ +int qm_fq_free_flags(u32 fqid, u32 flags); +#ifdef CONFIG_FSL_DPA_CAN_WAIT +static inline void qm_fq_free(u32 fqid) +{ + if (qm_fq_free_flags(fqid, QM_FQ_FREE_WAIT)) + BUG(); +} +#else +#define qm_fq_free(fqid) qm_fq_free_flags(fqid, 0) +#endif + +/* For qman_static_dequeue_*** APIs */ +#define QM_SDQCR_CHANNELS_POOL_MASK 0x00007fff +/* for n in [1,15] */ +#define QM_SDQCR_CHANNELS_POOL(n) (0x00008000 >> (n)) +/* for conversion from n of type "enum qm_channel" */ +#define QM_SDQCR_CHANNELS_POOL_CONV(c) \ + QM_SDQCR_CHANNELS_POOL((c) + 1 - qm_channel_pool1) + +/* For qman_volatile_dequeue(); Choose one PRECEDENCE. EXACT is optional. Use + * NUMFRAMES(n) (6-bit) or NUMFRAMES_TILLEMPTY to fill in the frame-count. Use + * FQID(n) to fill in the frame queue ID. */ +#define QM_VDQCR_PRECEDENCE_VDQCR 0x0 +#define QM_VDQCR_PRECEDENCE_SDQCR 0x80000000 +#define QM_VDQCR_EXACT 0x40000000 +#define QM_VDQCR_NUMFRAMES_MASK 0x3f000000 +#define QM_VDQCR_NUMFRAMES_SET(n) (((n) & 0x3f) << 24) +#define QM_VDQCR_NUMFRAMES_GET(n) (((n) >> 24) & 0x3f) +#define QM_VDQCR_NUMFRAMES_TILLEMPTY QM_VDQCR_NUMFRAMES_SET(0) + + +/* ------------------------------------------------------- */ +/* --- Qman data structures (and associated constants) --- */ + +/* Represents s/w corenet portal mapped data structures */ +struct qm_eqcr_entry; /* EQCR (EnQueue Command Ring) entries */ +struct qm_dqrr_entry; /* DQRR (DeQueue Response Ring) entries */ +struct qm_mr_entry; /* MR (Message Ring) entries */ +struct qm_mc_command; /* MC (Management Command) command */ +struct qm_mc_result; /* MC result */ + +/* See David Lapp's "Frame formats" document, "dpateam", Jan 07, 2008 */ +#define QM_FD_FORMAT_SG 0x4 +#define QM_FD_FORMAT_LONG 0x2 +#define QM_FD_FORMAT_COMPOUND 0x1 +enum qm_fd_format { + /* 'contig' implies a contiguous buffer, whereas 'sg' implies a + * scatter-gather table. 'big' implies a 29-bit length with no offset + * field, otherwise length is 20-bit and offset is 9-bit. 'compound' + * implies a s/g-like table, where each entry itself represents a frame + * (contiguous or scatter-gather) and the 29-bit "length" is + * interpreted purely for congestion calculations, ie. a "congestion + * weight". */ + qm_fd_contig = 0, + qm_fd_contig_big = QM_FD_FORMAT_LONG, + qm_fd_sg = QM_FD_FORMAT_SG, + qm_fd_sg_big = QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG, + qm_fd_compound = QM_FD_FORMAT_COMPOUND +}; + +/* Capitalised versions are un-typed but can be used in static expressions */ +#define QM_FD_CONTIG 0 +#define QM_FD_CONTIG_BIG QM_FD_FORMAT_LONG +#define QM_FD_SG QM_FD_FORMAT_SG +#define QM_FD_SG_BIG (QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG) +#define QM_FD_COMPOUND QM_FD_FORMAT_COMPOUND + +/* See 1.5.1.1: "Frame Descriptor (FD)" */ +struct qm_fd { + union { + struct { + u8 dd:2; /* dynamic debug */ + u8 liodn_offset:6; + u8 bpid:8; /* Buffer Pool ID */ + u8 eliodn_offset:4; + u8 __reserved:4; + u8 addr_hi; /* high 8-bits of 40-bit address */ + u32 addr_lo; /* low 32-bits of 40-bit address */ + }; + struct { + u64 __notaddress:24; + /* More efficient address accessor */ + u64 addr:40; + }; + u64 opaque_addr; + }; + /* The 'format' field indicates the interpretation of the remaining 29 + * bits of the 32-bit word. For packing reasons, it is duplicated in the + * other union elements. Note, union'd structs are difficult to use with + * static initialisation under gcc, in which case use the "opaque" form + * with one of the macros. */ + union { + /* For easier/faster copying of this part of the fd (eg. from a + * DQRR entry to an EQCR entry) copy 'opaque' */ + u32 opaque; + /* If 'format' is _contig or _sg, 20b length and 9b offset */ + struct { + enum qm_fd_format format:3; + u16 offset:9; + u32 length20:20; + }; + /* If 'format' is _contig_big or _sg_big, 29b length */ + struct { + enum qm_fd_format _format1:3; + u32 length29:29; + }; + /* If 'format' is _compound, 29b "congestion weight" */ + struct { + enum qm_fd_format _format2:3; + u32 cong_weight:29; + }; + }; + union { + u32 cmd; + u32 status; + }; +} __attribute__((aligned(8))); +#define QM_FD_DD_NULL 0x00 +#define QM_FD_PID_MASK 0x3f +static inline u64 qm_fd_addr_get64(const struct qm_fd *fd) +{ + return fd->addr; +} + +static inline dma_addr_t qm_fd_addr(const struct qm_fd *fd) +{ + return (dma_addr_t)fd->addr; +} +/* Macro, so we compile better if 'v' isn't always 64-bit */ +#define qm_fd_addr_set64(fd, v) \ + do { \ + struct qm_fd *__fd931 = (fd); \ + __fd931->addr = v; \ + } while (0) + +/* For static initialisation of FDs (which is complicated by the use of unions + * in "struct qm_fd"), use the following macros. Note that; + * - 'dd', 'pid' and 'bpid' are ignored because there's no static initialisation + * use-case), + * - use capitalised QM_FD_*** formats for static initialisation. + */ +#define QM_FD_FMT_20(cmd, addr_hi, addr_lo, fmt, off, len) \ + { 0, 0, 0, 0, 0, addr_hi, addr_lo, \ + { (((fmt)&0x7) << 29) | (((off)&0x1ff) << 20) | ((len)&0xfffff) }, \ + { cmd } } +#define QM_FD_FMT_29(cmd, addr_hi, addr_lo, fmt, len) \ + { 0, 0, 0, 0, 0, addr_hi, addr_lo, \ + { (((fmt)&0x7) << 29) | ((len)&0x1fffffff) }, \ + { cmd } } + +/* See 2.2.1.3 Multi-Core Datapath Acceleration Architecture */ +struct qm_sg_entry { + union { + struct { + u8 __reserved1[3]; + u8 addr_hi; /* high 8-bits of 40-bit address */ + u32 addr_lo; /* low 32-bits of 40-bit address */ + }; + struct { + u64 __notaddress:24; + u64 addr:40; + }; + }; + u32 extension:1; /* Extension bit */ + u32 final:1; /* Final bit */ + u32 length:30; + u8 __reserved2; + u8 bpid; + u16 __reserved3:3; + u16 offset:13; +} __packed; +static inline u64 qm_sg_entry_get64(const struct qm_sg_entry *sg) +{ + return sg->addr; +} +static inline dma_addr_t qm_sg_addr(const struct qm_sg_entry *sg) +{ + return (dma_addr_t)sg->addr; +} +/* Macro, so we compile better if 'v' isn't always 64-bit */ +#define qm_sg_entry_set64(sg, v) \ + do { \ + struct qm_sg_entry *__sg931 = (sg); \ + __sg931->addr = v; \ + } while (0) + +/* See 1.5.8.1: "Enqueue Command" */ +struct qm_eqcr_entry { + u8 __dont_write_directly__verb; + u8 dca; + u16 seqnum; + u32 orp; /* 24-bit */ + u32 fqid; /* 24-bit */ + u32 tag; + struct qm_fd fd; + u8 __reserved3[32]; +} __packed; +#define QM_EQCR_VERB_VBIT 0x80 +#define QM_EQCR_VERB_CMD_MASK 0x61 /* but only one value; */ +#define QM_EQCR_VERB_CMD_ENQUEUE 0x01 +#define QM_EQCR_VERB_COLOUR_MASK 0x18 /* 4 possible values; */ +#define QM_EQCR_VERB_COLOUR_GREEN 0x00 +#define QM_EQCR_VERB_COLOUR_YELLOW 0x08 +#define QM_EQCR_VERB_COLOUR_RED 0x10 +#define QM_EQCR_VERB_COLOUR_OVERRIDE 0x18 +#define QM_EQCR_VERB_INTERRUPT 0x04 /* on command consumption */ +#define QM_EQCR_VERB_ORP 0x02 /* enable order restoration */ +#define QM_EQCR_DCA_ENABLE 0x80 +#define QM_EQCR_DCA_PARK 0x40 +#define QM_EQCR_DCA_IDXMASK 0x0f /* "DQRR::idx" goes here */ +#define QM_EQCR_SEQNUM_NESN 0x8000 /* Advance NESN */ +#define QM_EQCR_SEQNUM_NLIS 0x4000 /* More fragments to come */ +#define QM_EQCR_SEQNUM_SEQMASK 0x3fff /* sequence number goes here */ +#define QM_EQCR_FQID_NULL 0 /* eg. for an ORP seqnum hole */ + +/* See 1.5.8.2: "Frame Dequeue Response" */ +struct qm_dqrr_entry { + u8 verb; + u8 stat; + u16 seqnum; /* 15-bit */ + u8 tok; + u8 __reserved2[3]; + u32 fqid; /* 24-bit */ + u32 contextB; + struct qm_fd fd; + u8 __reserved4[32]; +}; +#define QM_DQRR_VERB_VBIT 0x80 +#define QM_DQRR_VERB_MASK 0x7f /* where the verb contains; */ +#define QM_DQRR_VERB_FRAME_DEQUEUE 0x60 /* "this format" */ +#define QM_DQRR_STAT_FQ_EMPTY 0x80 /* FQ empty */ +#define QM_DQRR_STAT_FQ_HELDACTIVE 0x40 /* FQ held active */ +#define QM_DQRR_STAT_FQ_FORCEELIGIBLE 0x20 /* FQ was force-eligible'd */ +#define QM_DQRR_STAT_FD_VALID 0x10 /* has a non-NULL FD */ +#define QM_DQRR_STAT_UNSCHEDULED 0x02 /* Unscheduled dequeue */ +#define QM_DQRR_STAT_DQCR_EXPIRED 0x01 /* VDQCR or PDQCR expired*/ + +/* See 1.5.8.3: "ERN Message Response" */ +/* See 1.5.8.4: "FQ State Change Notification" */ +struct qm_mr_entry { + u8 verb; + union { + struct { + u8 dca; + u16 seqnum; + u8 rc; /* Rejection Code */ + u32 orp:24; + u32 fqid; /* 24-bit */ + u32 tag; + struct qm_fd fd; + } __packed ern; + struct { + u8 colour:2; /* See QM_MR_DCERN_COLOUR_* */ + u8 __reserved1:4; + enum qm_dc_portal portal:2; + u16 __reserved2; + u8 rc; /* Rejection Code */ + u32 __reserved3:24; + u32 fqid; /* 24-bit */ + u32 tag; + struct qm_fd fd; + } __packed dcern; + struct { + u8 fqs; /* Frame Queue Status */ + u8 __reserved1[6]; + u32 fqid; /* 24-bit */ + u32 contextB; + u8 __reserved2[16]; + } __packed fq; /* FQRN/FQRNI/FQRL/FQPN */ + }; + u8 __reserved2[32]; +} __packed; +#define QM_MR_VERB_VBIT 0x80 +/* The "ern" VERB bits match QM_EQCR_VERB_*** so aren't reproduced here. ERNs + * originating from direct-connect portals ("dcern") use 0x20 as a verb which + * would be invalid as a s/w enqueue verb. A s/w ERN can be distinguished from + * the other MR types by noting if the 0x20 bit is unset. */ +#define QM_MR_VERB_TYPE_MASK 0x27 +#define QM_MR_VERB_DC_ERN 0x20 +#define QM_MR_VERB_FQRN 0x21 +#define QM_MR_VERB_FQRNI 0x22 +#define QM_MR_VERB_FQRL 0x23 +#define QM_MR_VERB_FQPN 0x24 +#define QM_MR_RC_MASK 0xf0 /* contains one of; */ +#define QM_MR_RC_CGR_TAILDROP 0x00 +#define QM_MR_RC_WRED 0x10 +#define QM_MR_RC_ERROR 0x20 +#define QM_MR_RC_ORPWINDOW_EARLY 0x30 +#define QM_MR_RC_ORPWINDOW_LATE 0x40 +#define QM_MR_RC_FQ_TAILDROP 0x50 +#define QM_MR_RC_ORPWINDOW_RETIRED 0x60 +#define QM_MR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */ +#define QM_MR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */ +#define QM_MR_DCERN_COLOUR_GREEN 0x00 +#define QM_MR_DCERN_COLOUR_YELLOW 0x01 +#define QM_MR_DCERN_COLOUR_RED 0x02 +#define QM_MR_DCERN_COLOUR_OVERRIDE 0x03 + +/* An identical structure of FQD fields is present in the "Init FQ" command and + * the "Query FQ" result, it's suctioned out into the "struct qm_fqd" type. + * Within that, the 'stashing' and 'taildrop' pieces are also factored out, the + * latter has two inlines to assist with converting to/from the mant+exp + * representation. */ +struct qm_fqd_stashing { + /* See QM_STASHING_EXCL_<...> */ + u8 exclusive; + u8 __reserved1:2; + /* Numbers of cachelines */ + u8 annotation_cl:2; + u8 data_cl:2; + u8 context_cl:2; +} __packed; +struct qm_fqd_taildrop { + u16 __reserved1:3; + u16 mant:8; + u16 exp:5; +} __packed; +struct qm_fqd_oac { + /* See QM_OAC_<...> */ + u8 oac:2; /* "Overhead Accounting Control" */ + u8 __reserved1:6; + /* Two's-complement value (-128 to +127) */ + signed char oal; /* "Overhead Accounting Length" */ +} __packed; +struct qm_fqd { + union { + u8 orpc; + struct { + u8 __reserved1:2; + u8 orprws:3; + u8 oa:1; + u8 olws:2; + } __packed; + }; + u8 cgid; + u16 fq_ctrl; /* See QM_FQCTRL_<...> */ + union { + u16 dest_wq; + struct { + u16 channel:13; /* enum qm_channel */ + u16 wq:3; + } __packed dest; + }; + u16 __reserved2:1; + u16 ics_cred:15; + /* For "Initialize Frame Queue" commands, the write-enable mask + * determines whether 'td' or 'oac_init' is observed. For query + * commands, this field is always 'td', and 'oac_query' (below) reflects + * the Overhead ACcounting values. */ + union { + struct qm_fqd_taildrop td; + struct qm_fqd_oac oac_init; + }; + u32 context_b; + union { + /* Treat it as 64-bit opaque */ + u64 opaque; + struct { + u32 hi; + u32 lo; + }; + /* Treat it as s/w portal stashing config */ + /* See 1.5.6.7.1: "FQD Context_A field used for [...] */ + struct { + struct qm_fqd_stashing stashing; + /* 48-bit address of FQ context to + * stash, must be cacheline-aligned */ + u16 context_hi; + u32 context_lo; + } __packed; + } context_a; + struct qm_fqd_oac oac_query; +} __packed; +/* 64-bit converters for context_hi/lo */ +static inline u64 qm_fqd_stashing_get64(const struct qm_fqd *fqd) +{ + return ((u64)fqd->context_a.context_hi << 32) | + (u64)fqd->context_a.context_lo; +} +static inline dma_addr_t qm_fqd_stashing_addr(const struct qm_fqd *fqd) +{ + return (dma_addr_t)qm_fqd_stashing_get64(fqd); +} +static inline u64 qm_fqd_context_a_get64(const struct qm_fqd *fqd) +{ + return ((u64)fqd->context_a.hi << 32) | + (u64)fqd->context_a.lo; +} +/* Macro, so we compile better when 'v' isn't necessarily 64-bit */ +#define qm_fqd_stashing_set64(fqd, v) \ + do { \ + struct qm_fqd *__fqd931 = (fqd); \ + __fqd931->context_a.context_hi = upper_32_bits(v); \ + __fqd931->context_a.context_lo = lower_32_bits(v); \ + } while (0) +#define qm_fqd_context_a_set64(fqd, v) \ + do { \ + struct qm_fqd *__fqd931 = (fqd); \ + __fqd931->context_a.hi = upper_32_bits(v); \ + __fqd931->context_a.lo = lower_32_bits(v); \ + } while (0) +/* convert a threshold value into mant+exp representation */ +static inline int qm_fqd_taildrop_set(struct qm_fqd_taildrop *td, u32 val, + int roundup) +{ + u32 e = 0; + int oddbit = 0; + if (val > 0xe0000000) + return -ERANGE; + while (val > 0xff) { + oddbit = val & 1; + val >>= 1; + e++; + if (roundup && oddbit) + val++; + } + td->exp = e; + td->mant = val; + return 0; +} +/* and the other direction */ +static inline u32 qm_fqd_taildrop_get(const struct qm_fqd_taildrop *td) +{ + return (u32)td->mant << td->exp; +} + +/* See 1.5.2.2: "Frame Queue Descriptor (FQD)" */ +/* Frame Queue Descriptor (FQD) field 'fq_ctrl' uses these constants */ +#define QM_FQCTRL_MASK 0x07ff /* 'fq_ctrl' flags; */ +#define QM_FQCTRL_CGE 0x0400 /* Congestion Group Enable */ +#define QM_FQCTRL_TDE 0x0200 /* Tail-Drop Enable */ +#define QM_FQCTRL_ORP 0x0100 /* ORP Enable */ +#define QM_FQCTRL_CTXASTASHING 0x0080 /* Context-A stashing */ +#define QM_FQCTRL_CPCSTASH 0x0040 /* CPC Stash Enable */ +#define QM_FQCTRL_FORCESFDR 0x0008 /* High-priority SFDRs */ +#define QM_FQCTRL_AVOIDBLOCK 0x0004 /* Don't block active */ +#define QM_FQCTRL_HOLDACTIVE 0x0002 /* Hold active in portal */ +#define QM_FQCTRL_PREFERINCACHE 0x0001 /* Aggressively cache FQD */ +#define QM_FQCTRL_LOCKINCACHE QM_FQCTRL_PREFERINCACHE /* older naming */ + +/* See 1.5.6.7.1: "FQD Context_A field used for [...] */ +/* Frame Queue Descriptor (FQD) field 'CONTEXT_A' uses these constants */ +#define QM_STASHING_EXCL_ANNOTATION 0x04 +#define QM_STASHING_EXCL_DATA 0x02 +#define QM_STASHING_EXCL_CTX 0x01 + +/* See 1.5.5.3: "Intra Class Scheduling" */ +/* FQD field 'OAC' (Overhead ACcounting) uses these constants */ +#define QM_OAC_ICS 0x2 /* Accounting for Intra-Class Scheduling */ +#define QM_OAC_CG 0x1 /* Accounting for Congestion Groups */ + +/* See 1.5.8.4: "FQ State Change Notification" */ +/* This struct represents the 32-bit "WR_PARM_[GYR]" parameters in CGR fields + * and associated commands/responses. The WRED parameters are calculated from + * these fields as follows; + * MaxTH = MA * (2 ^ Mn) + * Slope = SA / (2 ^ Sn) + * MaxP = 4 * (Pn + 1) + */ +struct qm_cgr_wr_parm { + union { + u32 word; + struct { + u32 MA:8; + u32 Mn:5; + u32 SA:7; /* must be between 64-127 */ + u32 Sn:6; + u32 Pn:6; + } __packed; + }; +} __packed; +/* This struct represents the 13-bit "CS_THRES" CGR field. In the corresponding + * management commands, this is padded to a 16-bit structure field, so that's + * how we represent it here. The congestion state threshold is calculated from + * these fields as follows; + * CS threshold = TA * (2 ^ Tn) + */ +struct qm_cgr_cs_thres { + u16 __reserved:3; + u16 TA:8; + u16 Tn:5; +} __packed; +/* This identical structure of CGR fields is present in the "Init/Modify CGR" + * commands and the "Query CGR" result. It's suctioned out here into its own + * struct. */ +struct __qm_mc_cgr { + struct qm_cgr_wr_parm wr_parm_g; + struct qm_cgr_wr_parm wr_parm_y; + struct qm_cgr_wr_parm wr_parm_r; + u8 wr_en_g; /* boolean, use QM_CGR_EN */ + u8 wr_en_y; /* boolean, use QM_CGR_EN */ + u8 wr_en_r; /* boolean, use QM_CGR_EN */ + u8 cscn_en; /* boolean, use QM_CGR_EN */ + u32 cscn_targ; /* use QM_CGR_TARG_* */ + u8 cstd_en; /* boolean, use QM_CGR_EN */ + u8 cs; /* boolean, only used in query response */ + struct qm_cgr_cs_thres cs_thres; /* use qm_cgr_cs_thres_set64() */ + u8 mode; /* QMAN_CGR_MODE_FRAME not supported in rev1.0 */ +} __packed; +#define QM_CGR_EN 0x01 /* For wr_en_*, cscn_en, cstd_en */ +#define QM_CGR_TARG_PORTAL(n) (0x80000000 >> (n)) /* s/w portal, 0-9 */ +#define QM_CGR_TARG_FMAN0 0x00200000 /* direct-connect portal: fman0 */ +#define QM_CGR_TARG_FMAN1 0x00100000 /* : fman1 */ +/* Convert CGR thresholds to/from "cs_thres" format */ +static inline u64 qm_cgr_cs_thres_get64(const struct qm_cgr_cs_thres *th) +{ + return (u64)th->TA << th->Tn; +} +static inline int qm_cgr_cs_thres_set64(struct qm_cgr_cs_thres *th, u64 val, + int roundup) +{ + u32 e = 0; + int oddbit = 0; + while (val > 0xff) { + oddbit = val & 1; + val >>= 1; + e++; + if (roundup && oddbit) + val++; + } + th->Tn = e; + th->TA = val; + return 0; +} + +/* See 1.5.8.5.1: "Initialize FQ" */ +/* See 1.5.8.5.2: "Query FQ" */ +/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */ +/* See 1.5.8.5.4: "Alter FQ State Commands " */ +/* See 1.5.8.6.1: "Initialize/Modify CGR" */ +/* See 1.5.8.6.2: "CGR Test Write" */ +/* See 1.5.8.6.3: "Query CGR" */ +/* See 1.5.8.6.4: "Query Congestion Group State" */ +struct qm_mcc_initfq { + u8 __reserved1; + u16 we_mask; /* Write Enable Mask */ + u32 fqid; /* 24-bit */ + u16 count; /* Initialises 'count+1' FQDs */ + struct qm_fqd fqd; /* the FQD fields go here */ + u8 __reserved3[30]; +} __packed; +struct qm_mcc_queryfq { + u8 __reserved1[3]; + u32 fqid; /* 24-bit */ + u8 __reserved2[56]; +} __packed; +struct qm_mcc_queryfq_np { + u8 __reserved1[3]; + u32 fqid; /* 24-bit */ + u8 __reserved2[56]; +} __packed; +struct qm_mcc_alterfq { + u8 __reserved1[3]; + u32 fqid; /* 24-bit */ + u8 __reserved2[56]; +} __packed; +struct qm_mcc_initcgr { + u8 __reserved1; + u16 we_mask; /* Write Enable Mask */ + struct __qm_mc_cgr cgr; /* CGR fields */ + u8 __reserved2[2]; + u8 cgid; + u8 __reserved4[32]; +} __packed; +struct qm_mcc_cgrtestwrite { + u8 __reserved1[2]; + u8 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */ + u32 i_bcnt_lo; /* low 32-bits of 40-bit */ + u8 __reserved2[23]; + u8 cgid; + u8 __reserved3[32]; +} __packed; +struct qm_mcc_querycgr { + u8 __reserved1[30]; + u8 cgid; + u8 __reserved2[32]; +} __packed; +struct qm_mcc_querycongestion { + u8 __reserved[63]; +} __packed; +struct qm_mcc_querywq { + u8 __reserved; + /* select channel if verb != QUERYWQ_DEDICATED */ + union { + u16 channel_wq; /* ignores wq (3 lsbits) */ + struct { + u16 id:13; /* enum qm_channel */ + u16 __reserved1:3; + } __packed channel; + }; + u8 __reserved2[60]; +} __packed; +struct qm_mc_command { + u8 __dont_write_directly__verb; + union { + struct qm_mcc_initfq initfq; + struct qm_mcc_queryfq queryfq; + struct qm_mcc_queryfq_np queryfq_np; + struct qm_mcc_alterfq alterfq; + struct qm_mcc_initcgr initcgr; + struct qm_mcc_cgrtestwrite cgrtestwrite; + struct qm_mcc_querycgr querycgr; + struct qm_mcc_querycongestion querycongestion; + struct qm_mcc_querywq querywq; + }; +} __packed; +#define QM_MCC_VERB_VBIT 0x80 +#define QM_MCC_VERB_MASK 0x7f /* where the verb contains; */ +#define QM_MCC_VERB_INITFQ_PARKED 0x40 +#define QM_MCC_VERB_INITFQ_SCHED 0x41 +#define QM_MCC_VERB_QUERYFQ 0x44 +#define QM_MCC_VERB_QUERYFQ_NP 0x45 /* "non-programmable" fields */ +#define QM_MCC_VERB_QUERYWQ 0x46 +#define QM_MCC_VERB_QUERYWQ_DEDICATED 0x47 +#define QM_MCC_VERB_ALTER_SCHED 0x48 /* Schedule FQ */ +#define QM_MCC_VERB_ALTER_FE 0x49 /* Force Eligible FQ */ +#define QM_MCC_VERB_ALTER_RETIRE 0x4a /* Retire FQ */ +#define QM_MCC_VERB_ALTER_OOS 0x4b /* Take FQ out of service */ +#define QM_MCC_VERB_INITCGR 0x50 +#define QM_MCC_VERB_MODIFYCGR 0x51 +#define QM_MCC_VERB_CGRTESTWRITE 0x52 +#define QM_MCC_VERB_QUERYCGR 0x58 +#define QM_MCC_VERB_QUERYCONGESTION 0x59 +/* INITFQ-specific flags */ +#define QM_INITFQ_WE_MASK 0x01ff /* 'Write Enable' flags; */ +#define QM_INITFQ_WE_OAC 0x0100 +#define QM_INITFQ_WE_ORPC 0x0080 +#define QM_INITFQ_WE_CGID 0x0040 +#define QM_INITFQ_WE_FQCTRL 0x0020 +#define QM_INITFQ_WE_DESTWQ 0x0010 +#define QM_INITFQ_WE_ICSCRED 0x0008 +#define QM_INITFQ_WE_TDTHRESH 0x0004 +#define QM_INITFQ_WE_CONTEXTB 0x0002 +#define QM_INITFQ_WE_CONTEXTA 0x0001 +/* INITCGR/MODIFYCGR-specific flags */ +#define QM_CGR_WE_MASK 0x07ff /* 'Write Enable Mask'; */ +#define QM_CGR_WE_WR_PARM_G 0x0400 +#define QM_CGR_WE_WR_PARM_Y 0x0200 +#define QM_CGR_WE_WR_PARM_R 0x0100 +#define QM_CGR_WE_WR_EN_G 0x0080 +#define QM_CGR_WE_WR_EN_Y 0x0040 +#define QM_CGR_WE_WR_EN_R 0x0020 +#define QM_CGR_WE_CSCN_EN 0x0010 +#define QM_CGR_WE_CSCN_TARG 0x0008 +#define QM_CGR_WE_CSTD_EN 0x0004 +#define QM_CGR_WE_CS_THRES 0x0002 +#define QM_CGR_WE_MODE 0x0001 + +/* See 1.5.8.5.1: "Initialize FQ" */ +/* See 1.5.8.5.2: "Query FQ" */ +/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */ +/* See 1.5.8.5.4: "Alter FQ State Commands " */ +/* See 1.5.8.6.1: "Initialize/Modify CGR" */ +/* See 1.5.8.6.2: "CGR Test Write" */ +/* See 1.5.8.6.3: "Query CGR" */ +/* See 1.5.8.6.4: "Query Congestion Group State" */ +struct qm_mcr_initfq { + u8 __reserved1[62]; +} __packed; +struct qm_mcr_queryfq { + u8 __reserved1[8]; + struct qm_fqd fqd; /* the FQD fields are here */ + u8 __reserved2[30]; +} __packed; +struct qm_mcr_queryfq_np { + u8 __reserved1; + u8 state; /* QM_MCR_NP_STATE_*** */ + u8 __reserved2; + u32 fqd_link:24; + u16 __reserved3:2; + u16 odp_seq:14; + u16 __reserved4:2; + u16 orp_nesn:14; + u16 __reserved5:1; + u16 orp_ea_hseq:15; + u16 __reserved6:1; + u16 orp_ea_tseq:15; + u8 __reserved7; + u32 orp_ea_hptr:24; + u8 __reserved8; + u32 orp_ea_tptr:24; + u8 __reserved9; + u32 pfdr_hptr:24; + u8 __reserved10; + u32 pfdr_tptr:24; + u8 __reserved11[5]; + u8 __reserved12:7; + u8 is:1; + u16 ics_surp; + u32 byte_cnt; + u8 __reserved13; + u32 frm_cnt:24; + u32 __reserved14; + u16 ra1_sfdr; /* QM_MCR_NP_RA1_*** */ + u16 ra2_sfdr; /* QM_MCR_NP_RA2_*** */ + u16 __reserved15; + u16 od1_sfdr; /* QM_MCR_NP_OD1_*** */ + u16 od2_sfdr; /* QM_MCR_NP_OD2_*** */ + u16 od3_sfdr; /* QM_MCR_NP_OD3_*** */ +} __packed; +struct qm_mcr_alterfq { + u8 fqs; /* Frame Queue Status */ + u8 __reserved1[61]; +} __packed; +struct qm_mcr_initcgr { + u8 __reserved1[62]; +} __packed; +struct qm_mcr_cgrtestwrite { + u16 __reserved1; + struct __qm_mc_cgr cgr; /* CGR fields */ + u8 __reserved2[3]; + u32 __reserved3:24; + u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */ + u32 i_bcnt_lo; /* low 32-bits of 40-bit */ + u32 __reserved4:24; + u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */ + u32 a_bcnt_lo; /* low 32-bits of 40-bit */ + u16 lgt; /* Last Group Tick */ + u16 wr_prob_g; + u16 wr_prob_y; + u16 wr_prob_r; + u8 __reserved5[8]; +} __packed; +struct qm_mcr_querycgr { + u16 __reserved1; + struct __qm_mc_cgr cgr; /* CGR fields */ + u8 __reserved2[3]; + u32 __reserved3:24; + u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */ + u32 i_bcnt_lo; /* low 32-bits of 40-bit */ + u32 __reserved4:24; + u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */ + u32 a_bcnt_lo; /* low 32-bits of 40-bit */ + u8 __reserved5[16]; +} __packed; +static inline u64 qm_mcr_querycgr_i_get64(const struct qm_mcr_querycgr *q) +{ + return ((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo; +} +static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q) +{ + return ((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo; +} +static inline u64 qm_mcr_cgrtestwrite_i_get64( + const struct qm_mcr_cgrtestwrite *q) +{ + return ((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo; +} +static inline u64 qm_mcr_cgrtestwrite_a_get64( + const struct qm_mcr_cgrtestwrite *q) +{ + return ((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo; +} +/* Macro, so we compile better if 'v' isn't always 64-bit */ +#define qm_mcr_querycgr_i_set64(q, v) \ + do { \ + struct qm_mcr_querycgr *__q931 = (fd); \ + __q931->i_bcnt_hi = upper_32_bits(v); \ + __q931->i_bcnt_lo = lower_32_bits(v); \ + } while (0) +#define qm_mcr_querycgr_a_set64(q, v) \ + do { \ + struct qm_mcr_querycgr *__q931 = (fd); \ + __q931->a_bcnt_hi = upper_32_bits(v); \ + __q931->a_bcnt_lo = lower_32_bits(v); \ + } while (0) +struct __qm_mcr_querycongestion { + u32 __state[8]; +}; +struct qm_mcr_querycongestion { + u8 __reserved[30]; + /* Access this struct using QM_MCR_QUERYCONGESTION() */ + struct __qm_mcr_querycongestion state; +} __packed; +struct qm_mcr_querywq { + union { + u16 channel_wq; /* ignores wq (3 lsbits) */ + struct { + u16 id:13; /* enum qm_channel */ + u16 __reserved:3; + } __packed channel; + }; + u8 __reserved[28]; + u32 wq_len[8]; +} __packed; +struct qm_mc_result { + u8 verb; + u8 result; + union { + struct qm_mcr_initfq initfq; + struct qm_mcr_queryfq queryfq; + struct qm_mcr_queryfq_np queryfq_np; + struct qm_mcr_alterfq alterfq; + struct qm_mcr_initcgr initcgr; + struct qm_mcr_cgrtestwrite cgrtestwrite; + struct qm_mcr_querycgr querycgr; + struct qm_mcr_querycongestion querycongestion; + struct qm_mcr_querywq querywq; + }; +} __packed; +#define QM_MCR_VERB_RRID 0x80 +#define QM_MCR_VERB_MASK QM_MCC_VERB_MASK +#define QM_MCR_VERB_INITFQ_PARKED QM_MCC_VERB_INITFQ_PARKED +#define QM_MCR_VERB_INITFQ_SCHED QM_MCC_VERB_INITFQ_SCHED +#define QM_MCR_VERB_QUERYFQ QM_MCC_VERB_QUERYFQ +#define QM_MCR_VERB_QUERYFQ_NP QM_MCC_VERB_QUERYFQ_NP +#define QM_MCR_VERB_QUERYWQ QM_MCC_VERB_QUERYWQ +#define QM_MCR_VERB_QUERYWQ_DEDICATED QM_MCC_VERB_QUERYWQ_DEDICATED +#define QM_MCR_VERB_ALTER_SCHED QM_MCC_VERB_ALTER_SCHED +#define QM_MCR_VERB_ALTER_FE QM_MCC_VERB_ALTER_FE +#define QM_MCR_VERB_ALTER_RETIRE QM_MCC_VERB_ALTER_RETIRE +#define QM_MCR_VERB_ALTER_OOS QM_MCC_VERB_ALTER_OOS +#define QM_MCR_RESULT_NULL 0x00 +#define QM_MCR_RESULT_OK 0xf0 +#define QM_MCR_RESULT_ERR_FQID 0xf1 +#define QM_MCR_RESULT_ERR_FQSTATE 0xf2 +#define QM_MCR_RESULT_ERR_NOTEMPTY 0xf3 /* OOS fails if FQ is !empty */ +#define QM_MCR_RESULT_ERR_BADCHANNEL 0xf4 +#define QM_MCR_RESULT_PENDING 0xf8 +#define QM_MCR_RESULT_ERR_BADCOMMAND 0xff +#define QM_MCR_NP_STATE_FE 0x10 +#define QM_MCR_NP_STATE_R 0x08 +#define QM_MCR_NP_STATE_MASK 0x07 /* Reads FQD::STATE; */ +#define QM_MCR_NP_STATE_OOS 0x00 +#define QM_MCR_NP_STATE_RETIRED 0x01 +#define QM_MCR_NP_STATE_TEN_SCHED 0x02 +#define QM_MCR_NP_STATE_TRU_SCHED 0x03 +#define QM_MCR_NP_STATE_PARKED 0x04 +#define QM_MCR_NP_STATE_ACTIVE 0x05 +#define QM_MCR_NP_PTR_MASK 0x07ff /* for RA[12] & OD[123] */ +#define QM_MCR_NP_RA1_NRA(v) (((v) >> 14) & 0x3) /* FQD::NRA */ +#define QM_MCR_NP_RA2_IT(v) (((v) >> 14) & 0x1) /* FQD::IT */ +#define QM_MCR_NP_OD1_NOD(v) (((v) >> 14) & 0x3) /* FQD::NOD */ +#define QM_MCR_NP_OD3_NPC(v) (((v) >> 14) & 0x3) /* FQD::NPC */ +#define QM_MCR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */ +#define QM_MCR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */ +/* This extracts the state for congestion group 'n' from a query response. + * Eg. + * u8 cgr = [...]; + * struct qm_mc_result *res = [...]; + * printf("congestion group %d congestion state: %d\n", cgr, + * QM_MCR_QUERYCONGESTION(&res->querycongestion.state, cgr)); + */ +#define __CGR_WORD(num) (num >> 5) +#define __CGR_SHIFT(num) (num & 0x1f) +#define __CGR_NUM (sizeof(struct __qm_mcr_querycongestion) << 3) +static inline int QM_MCR_QUERYCONGESTION(struct __qm_mcr_querycongestion *p, + u8 cgr) +{ + return p->__state[__CGR_WORD(cgr)] & (0x80000000 >> __CGR_SHIFT(cgr)); +} + + +/*********************/ +/* Utility interface */ +/*********************/ + +/* Represents an allocator over a range of FQIDs. NB, accesses are not locked, + * spinlock them yourself if needed. */ +struct qman_fqid_pool; + +/* Create/destroy a FQID pool, num must be a multiple of 32. NB, _destroy() + * always succeeds, but returns non-zero if there were "leaked" FQID + * allocations. */ +struct qman_fqid_pool *qman_fqid_pool_create(u32 fqid_start, u32 num); +int qman_fqid_pool_destroy(struct qman_fqid_pool *pool); +/* Alloc/free a FQID from the range. _alloc() returns zero for success. */ +int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid); +void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid); +u32 qman_fqid_pool_used(struct qman_fqid_pool *pool); + +/*******************************************************************/ +/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */ +/*******************************************************************/ + + /* Portal and Frame Queues */ + /* ----------------------- */ +/* Represents a managed portal */ +struct qman_portal; + +/* This object type represents Qman frame queue descriptors (FQD), it is + * cacheline-aligned, and initialised by qman_create_fq(). The structure is + * defined further down. */ +struct qman_fq; + +/* This object type represents a Qman congestion group, it is defined further + * down. */ +struct qman_cgr; + +struct qman_portal_config { + /* If the caller enables DQRR stashing (and thus wishes to operate the + * portal from only one cpu), this is the logical CPU that the portal + * will stash to. Whether stashing is enabled or not, this setting is + * also used for any "core-affine" portals, ie. default portals + * associated to the corresponding cpu. -1 implies that there is no core + * affinity configured. */ + int cpu; + /* portal interrupt line */ + int irq; + /* the unique index of this portal */ + u32 index; + /* Is this portal shared? (If so, it has coarser locking and demuxes + * processing on behalf of other CPUs.) */ + int is_shared; + /* The portal's dedicated channel id, use this value for initialising + * frame queues to target this portal when scheduled. */ + enum qm_channel channel; + /* A mask of which pool channels this portal has dequeue access to + * (using QM_SDQCR_CHANNELS_POOL(n) for the bitmask) */ + u32 pools; + /* Is stashing available? (Depends on PAMU config) */ + int has_stashing; +}; + +/* This enum, and the callback type that returns it, are used when handling + * dequeued frames via DQRR. Note that for "null" callbacks registered with the + * portal object (for handling dequeues that do not demux because contextB is + * NULL), the return value *MUST* be qman_cb_dqrr_consume. */ +enum qman_cb_dqrr_result { + /* DQRR entry can be consumed */ + qman_cb_dqrr_consume, + /* Like _consume, but requests parking - FQ must be held-active */ + qman_cb_dqrr_park, + /* Does not consume, for DCA mode only. This allows out-of-order + * consumes by explicit calls to qman_dca() and/or the use of implicit + * DCA via EQCR entries. */ + qman_cb_dqrr_defer, + /* Stop processing without consuming this ring entry. Exits the current + * qman_poll_dqrr() or interrupt-handling, as appropriate. If within an + * interrupt handler, the callback would typically call + * qman_irqsource_remove(QM_PIRQ_DQRI) before returning this value, + * otherwise the interrupt will reassert immediately. */ + qman_cb_dqrr_stop, + /* Like qman_cb_dqrr_stop, but consumes the current entry. */ + qman_cb_dqrr_consume_stop +}; +typedef enum qman_cb_dqrr_result (*qman_cb_dqrr)(struct qman_portal *qm, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr); + +/* This callback type is used when handling ERNs, FQRNs and FQRLs via MR. They + * are always consumed after the callback returns. */ +typedef void (*qman_cb_mr)(struct qman_portal *qm, struct qman_fq *fq, + const struct qm_mr_entry *msg); + +/* s/w-visible states. Ie. tentatively scheduled + truly scheduled + active + + * held-active + held-suspended are just "sched". Things like "retired" will not + * be assumed until it is complete (ie. QMAN_FQ_STATE_CHANGING is set until + * then, to indicate it's completing and to gate attempts to retry the retire + * command). Note, park commands do not set QMAN_FQ_STATE_CHANGING because it's + * technically impossible in the case of enqueue DCAs (which refer to DQRR ring + * index rather than the FQ that ring entry corresponds to), so repeated park + * commands are allowed (if you're silly enough to try) but won't change FQ + * state, and the resulting park notifications move FQs from "sched" to + * "parked". */ +enum qman_fq_state { + qman_fq_state_oos, + qman_fq_state_parked, + qman_fq_state_sched, + qman_fq_state_retired +}; + +/* Frame queue objects (struct qman_fq) are stored within memory passed to + * qman_create_fq(), as this allows stashing of caller-provided demux callback + * pointers at no extra cost to stashing of (driver-internal) FQ state. If the + * caller wishes to add per-FQ state and have it benefit from dequeue-stashing, + * they should; + * + * (a) extend the qman_fq structure with their state; eg. + * + * // myfq is allocated and driver_fq callbacks filled in; + * struct my_fq { + * struct qman_fq base; + * int an_extra_field; + * [ ... add other fields to be associated with each FQ ...] + * } *myfq = some_my_fq_allocator(); + * struct qman_fq *fq = qman_create_fq(fqid, flags, &myfq->base); + * + * // in a dequeue callback, access extra fields from 'fq' via a cast; + * struct my_fq *myfq = (struct my_fq *)fq; + * do_something_with(myfq->an_extra_field); + * [...] + * + * (b) when and if configuring the FQ for context stashing, specify how ever + * many cachelines are required to stash 'struct my_fq', to accelerate not + * only the Qman driver but the callback as well. + */ + +struct qman_fq_cb { + qman_cb_dqrr dqrr; /* for dequeued frames */ + qman_cb_mr ern; /* for s/w ERNs */ + qman_cb_mr dc_ern; /* for diverted h/w ERNs */ + qman_cb_mr fqs; /* frame-queue state changes*/ +}; + +struct qman_fq { + /* Caller of qman_create_fq() provides these demux callbacks */ + struct qman_fq_cb cb; + /* These are internal to the driver, don't touch. In particular, they + * may change, be removed, or extended (so you shouldn't rely on + * sizeof(qman_fq) being a constant). */ + spinlock_t fqlock; + u32 fqid; + volatile unsigned long flags; + enum qman_fq_state state; + int cgr_groupid; + struct rb_node node; +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP + u32 key; +#endif +}; + +/* This callback type is used when handling congestion group entry/exit. + * 'congested' is non-zero on congestion-entry, and zero on congestion-exit. */ +typedef void (*qman_cb_cgr)(struct qman_portal *qm, + struct qman_cgr *cgr, int congested); + +struct qman_cgr { + /* Set these prior to qman_create_cgr() */ + u32 cgrid; /* 0..255, but u32 to allow specials like -1, 256, etc.*/ + qman_cb_cgr cb; + /* These are private to the driver */ + enum qm_channel chan; /* portal channel this object is created on */ + struct list_head node; +}; + +/* Flags to qman_create_fq() */ +#define QMAN_FQ_FLAG_NO_ENQUEUE 0x00000001 /* can't enqueue */ +#define QMAN_FQ_FLAG_NO_MODIFY 0x00000002 /* can only enqueue */ +#define QMAN_FQ_FLAG_TO_DCPORTAL 0x00000004 /* consumed by CAAM/PME/Fman */ +#define QMAN_FQ_FLAG_LOCKED 0x00000008 /* multi-core locking */ +#define QMAN_FQ_FLAG_AS_IS 0x00000010 /* query h/w state */ +#define QMAN_FQ_FLAG_DYNAMIC_FQID 0x00000020 /* (de)allocate fqid */ + +/* Flags to qman_destroy_fq() */ +#define QMAN_FQ_DESTROY_PARKED 0x00000001 /* FQ can be parked or OOS */ + +/* Flags from qman_fq_state() */ +#define QMAN_FQ_STATE_CHANGING 0x80000000 /* 'state' is changing */ +#define QMAN_FQ_STATE_NE 0x40000000 /* retired FQ isn't empty */ +#define QMAN_FQ_STATE_ORL 0x20000000 /* retired FQ has ORL */ +#define QMAN_FQ_STATE_BLOCKOOS 0xe0000000 /* if any are set, no OOS */ +#define QMAN_FQ_STATE_CGR_EN 0x10000000 /* CGR enabled */ +#define QMAN_FQ_STATE_VDQCR 0x08000000 /* being volatile dequeued */ + +/* Flags to qman_init_fq() */ +#define QMAN_INITFQ_FLAG_SCHED 0x00000001 /* schedule rather than park */ +#define QMAN_INITFQ_FLAG_NULL 0x00000002 /* zero 'contextB', no demux */ +#define QMAN_INITFQ_FLAG_LOCAL 0x00000004 /* set dest portal */ + +/* Flags to qman_volatile_dequeue() */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT +#define QMAN_VOLATILE_FLAG_WAIT 0x00000001 /* wait if VDQCR is in use */ +#define QMAN_VOLATILE_FLAG_WAIT_INT 0x00000002 /* if wait, interruptible? */ +#define QMAN_VOLATILE_FLAG_FINISH 0x00000004 /* wait till VDQCR completes */ +#endif + +/* Flags to qman_enqueue(). NB, the strange numbering is to align with hardware, + * bit-wise. (NB: the PME API is sensitive to these precise numberings too, so + * any change here should be audited in PME.) */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT +#define QMAN_ENQUEUE_FLAG_WAIT 0x00010000 /* wait if EQCR is full */ +#define QMAN_ENQUEUE_FLAG_WAIT_INT 0x00020000 /* if wait, interruptible? */ +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC +#define QMAN_ENQUEUE_FLAG_WAIT_SYNC 0x00000004 /* if wait, until consumed? */ +#endif +#endif +#define QMAN_ENQUEUE_FLAG_WATCH_CGR 0x00080000 /* watch congestion state */ +#define QMAN_ENQUEUE_FLAG_DCA 0x00008000 /* perform enqueue-DCA */ +#define QMAN_ENQUEUE_FLAG_DCA_PARK 0x00004000 /* If DCA, requests park */ +#define QMAN_ENQUEUE_FLAG_DCA_PTR(p) /* If DCA, p is DQRR entry */ \ + (((u32)(p) << 2) & 0x00000f00) +#define QMAN_ENQUEUE_FLAG_C_GREEN 0x00000000 /* choose one C_*** flag */ +#define QMAN_ENQUEUE_FLAG_C_YELLOW 0x00000008 +#define QMAN_ENQUEUE_FLAG_C_RED 0x00000010 +#define QMAN_ENQUEUE_FLAG_C_OVERRIDE 0x00000018 +/* For the ORP-specific qman_enqueue_orp() variant; + * - this flag indicates "Not Last In Sequence", ie. all but the final fragment + * of a frame. */ +#define QMAN_ENQUEUE_FLAG_NLIS 0x01000000 +/* - this flag performs no enqueue but fills in an ORP sequence number that + * would otherwise block it (eg. if a frame has been dropped). */ +#define QMAN_ENQUEUE_FLAG_HOLE 0x02000000 +/* - this flag performs no enqueue but advances NESN to the given sequence + * number. */ +#define QMAN_ENQUEUE_FLAG_NESN 0x04000000 + +/* Flags to qman_modify_cgr() */ +#define QMAN_CGR_FLAG_USE_INIT 0x00000001 +#define QMAN_CGR_MODE_FRAME 0x00000001 + + /* Portal Management */ + /* ----------------- */ +/** + * qman_get_portal_config - get portal configuration settings + * + * This returns a read-only view of the current cpu's affine portal settings. + */ +const struct qman_portal_config *qman_get_portal_config(void); + +#ifdef CONFIG_FSL_QMAN_NULL_FQ_DEMUX +/** + * qman_get_null_cb - get callbacks currently used for "null" frame queues + * + * Copies the callbacks used for the affine portal of the current cpu. + */ +void qman_get_null_cb(struct qman_fq_cb *null_cb); + +/** + * qman_set_null_cb - set callbacks to use for "null" frame queues + * + * Sets the callbacks to use for the affine portal of the current cpu, whenever + * a DQRR or MR entry refers to a "null" FQ object. (Eg. zero-conf messaging.) + */ +void qman_set_null_cb(const struct qman_fq_cb *null_cb); +#endif + +/** + * qman_irqsource_get - return the portal work that is interrupt-driven + * + * Returns a bitmask of QM_PIRQ_**I processing sources that are currently + * enabled for interrupt handling on the current cpu's affine portal. These + * sources will trigger the portal interrupt and the interrupt handler (or a + * tasklet/bottom-half it defers to) will perform the corresponding processing + * work. The qman_poll_***() functions will only process sources that are not in + * this bitmask. If the current CPU is sharing a portal hosted on another CPU, + * this always returns zero. + */ +u32 qman_irqsource_get(void); + +/** + * qman_irqsource_add - add processing sources to be interrupt-driven + * @bits: bitmask of QM_PIRQ_**I processing sources + * + * Adds processing sources that should be interrupt-driven (rather than + * processed via qman_poll_***() functions). Returns zero for success, or + * -EINVAL if the current CPU is sharing a portal hosted on another CPU. + */ +int qman_irqsource_add(u32 bits); + +/** + * qman_irqsource_remove - remove processing sources from being interrupt-driven + * @bits: bitmask of QM_PIRQ_**I processing sources + * + * Removes processing sources from being interrupt-driven, so that they will + * instead be processed via qman_poll_***() functions. Returns zero for success, + * or -EINVAL if the current CPU is sharing a portal hosted on another CPU. + */ +int qman_irqsource_remove(u32 bits); + +/** + * qman_affine_cpus - return a mask of cpus that have affine portals + */ +const cpumask_t *qman_affine_cpus(void); + +/** + * qman_poll_dqrr - process DQRR (fast-path) entries + * @limit: the maximum number of DQRR entries to process + * + * Use of this function requires that DQRR processing not be interrupt-driven. + * Ie. the value returned by qman_irqsource_get() should not include + * QM_PIRQ_DQRI. If the current CPU is sharing a portal hosted on another CPU, + * this function will return -EINVAL, otherwise the return value is >=0 and + * represents the number of DQRR entries processed. + */ +int qman_poll_dqrr(unsigned int limit); + +/** + * qman_poll_slow - process anything (except DQRR) that isn't interrupt-driven. + * + * This function does any portal processing that isn't interrupt-driven. If the + * current CPU is sharing a portal hosted on another CPU, this function will + * return (u32)-1, otherwise the return value is a bitmask of QM_PIRQ_* sources + * indicating what interrupt sources were actually processed by the call. + */ +u32 qman_poll_slow(void); + +/** + * qman_poll - legacey wrapper for qman_poll_dqrr() and qman_poll_slow() + * + * Dispatcher logic on a cpu can use this to trigger any maintenance of the + * affine portal. There are two classes of portal processing in question; + * fast-path (which involves demuxing dequeue ring (DQRR) entries and tracking + * enqueue ring (EQCR) consumption), and slow-path (which involves EQCR + * thresholds, congestion state changes, etc). This function does whatever + * processing is not triggered by interrupts. + * + * Note, if DQRR and some slow-path processing are poll-driven (rather than + * interrupt-driven) then this function uses a heuristic to determine how often + * to run slow-path processing - as slow-path processing introduces at least a + * minimum latency each time it is run, whereas fast-path (DQRR) processing is + * close to zero-cost if there is no work to be done. Applications can tune this + * behaviour themselves by using qman_poll_dqrr() and qman_poll_slow() directly + * rather than going via this wrapper. + */ +void qman_poll(void); + +/** + * qman_recovery_cleanup_fq - in recovery mode, cleanup a FQ of unknown state + */ +int qman_recovery_cleanup_fq(u32 fqid); + +/** + * qman_recovery_exit - leave recovery mode + */ +int qman_recovery_exit(void); + +/** + * qman_stop_dequeues - Stop h/w dequeuing to the s/w portal + * + * Disables DQRR processing of the portal. This is reference-counted, so + * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to + * truly re-enable dequeuing. + */ +void qman_stop_dequeues(void); + +/** + * qman_start_dequeues - (Re)start h/w dequeuing to the s/w portal + * + * Enables DQRR processing of the portal. This is reference-counted, so + * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to + * truly re-enable dequeuing. + */ +void qman_start_dequeues(void); + +/** + * qman_static_dequeue_add - Add pool channels to the portal SDQCR + * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n) + * + * Adds a set of pool channels to the portal's static dequeue command register + * (SDQCR). The requested pools are limited to those the portal has dequeue + * access to. + */ +void qman_static_dequeue_add(u32 pools); + +/** + * qman_static_dequeue_del - Remove pool channels from the portal SDQCR + * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n) + * + * Removes a set of pool channels from the portal's static dequeue command + * register (SDQCR). The requested pools are limited to those the portal has + * dequeue access to. + */ +void qman_static_dequeue_del(u32 pools); + +/** + * qman_static_dequeue_get - return the portal's current SDQCR + * + * Returns the portal's current static dequeue command register (SDQCR). The + * entire register is returned, so if only the currently-enabled pool channels + * are desired, mask the return value with QM_SDQCR_CHANNELS_POOL_MASK. + */ +u32 qman_static_dequeue_get(void); + +/** + * qman_dca - Perform a Discrete Consumption Acknowledgement + * @dq: the DQRR entry to be consumed + * @park_request: indicates whether the held-active @fq should be parked + * + * Only allowed in DCA-mode portals, for DQRR entries whose handler callback had + * previously returned 'qman_cb_dqrr_defer'. NB, as with the other APIs, this + * does not take a 'portal' argument but implies the core affine portal from the + * cpu that is currently executing the function. For reasons of locking, this + * function must be called from the same CPU as that which processed the DQRR + * entry in the first place. + */ +void qman_dca(struct qm_dqrr_entry *dq, int park_request); + +/** + * qman_eqcr_is_empty - Determine if portal's EQCR is empty + * + * For use in situations where a cpu-affine caller needs to determine when all + * enqueues for the local portal have been processed by Qman but can't use the + * QMAN_ENQUEUE_FLAG_WAIT_SYNC flag to do this from the final qman_enqueue(). + * The function forces tracking of EQCR consumption (which normally doesn't + * happen until enqueue processing needs to find space to put new enqueue + * commands), and returns zero if the ring still has unprocessed entries, + * non-zero if it is empty. + */ +int qman_eqcr_is_empty(void); + + /* FQ management */ + /* ------------- */ +/** + * qman_create_fq - Allocates a FQ + * @fqid: the index of the FQD to encapsulate, must be "Out of Service" + * @flags: bit-mask of QMAN_FQ_FLAG_*** options + * @fq: memory for storing the 'fq', with callbacks filled in + * + * Creates a frame queue object for the given @fqid, unless the + * QMAN_FQ_FLAG_DYNAMIC_FQID flag is set in @flags, in which case a FQID is + * dynamically allocated (or the function fails if none are available). Once + * created, the caller should not touch the memory at 'fq' except as extended to + * adjacent memory for user-defined fields (see the definition of "struct + * qman_fq" for more info). NO_MODIFY is only intended for enqueuing to + * pre-existing frame-queues that aren't to be otherwise interfered with, it + * prevents all other modifications to the frame queue. The TO_DCPORTAL flag + * causes the driver to honour any contextB modifications requested in the + * qm_init_fq() API, as this indicates the frame queue will be consumed by a + * direct-connect portal (PME, CAAM, or Fman). When frame queues are consumed by + * software portals, the contextB field is controlled by the driver and can't be + * modified by the caller. If the AS_IS flag is specified, management commands + * will be used on portal @p to query state for frame queue @fqid and construct + * a frame queue object based on that, rather than assuming/requiring that it be + * Out of Service. + */ +int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq); + +/** + * qman_destroy_fq - Deallocates a FQ + * @fq: the frame queue object to release + * @flags: bit-mask of QMAN_FQ_FREE_*** options + * + * The memory for this frame queue object ('fq' provided in qman_create_fq()) is + * not deallocated but the caller regains ownership, to do with as desired. The + * FQ must be in the 'out-of-service' state unless the QMAN_FQ_FREE_PARKED flag + * is specified, in which case it may also be in the 'parked' state. + */ +void qman_destroy_fq(struct qman_fq *fq, u32 flags); + +/** + * qman_fq_fqid - Queries the frame queue ID of a FQ object + * @fq: the frame queue object to query + */ +u32 qman_fq_fqid(struct qman_fq *fq); + +/** + * qman_fq_state - Queries the state of a FQ object + * @fq: the frame queue object to query + * @state: pointer to state enum to return the FQ scheduling state + * @flags: pointer to state flags to receive QMAN_FQ_STATE_*** bitmask + * + * Queries the state of the FQ object, without performing any h/w commands. + * This captures the state, as seen by the driver, at the time the function + * executes. + */ +void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags); + +/** + * qman_init_fq - Initialises FQ fields, leaves the FQ "parked" or "scheduled" + * @fq: the frame queue object to modify, must be 'parked' or new. + * @flags: bit-mask of QMAN_INITFQ_FLAG_*** options + * @opts: the FQ-modification settings, as defined in the low-level API + * + * The @opts parameter comes from the low-level portal API. Select + * QMAN_INITFQ_FLAG_SCHED in @flags to cause the frame queue to be scheduled + * rather than parked. Select QMAN_INITFQ_FLAG_NULL in @flags to configure a + * frame queue that will not demux to a 'struct qman_fq' object when dequeued + * frames or messages arrive at a software portal, but which will instead + * trigger the portal's 'null_cb' callbacks (see qman_create_portal()). NB, + * @opts can be NULL. + * + * Note that some fields and options within @opts may be ignored or overwritten + * by the driver; + * 1. the 'count' and 'fqid' fields are always ignored (this operation only + * affects one frame queue: @fq). + * 2. the QM_INITFQ_WE_CONTEXTB option of the 'we_mask' field and the associated + * 'fqd' structure's 'context_b' field are sometimes overwritten; + * - if @flags contains QMAN_INITFQ_FLAG_NULL, then context_b is initialised + * to zero by the driver, + * - if @fq was not created with QMAN_FQ_FLAG_TO_DCPORTAL, then context_b is + * initialised to a value used by the driver for demux. + * - if context_b is initialised for demux, so is context_a in case stashing + * is requested (see item 4). + * (So caller control of context_b is only possible for TO_DCPORTAL frame queue + * objects.) + * 3. if @flags contains QMAN_INITFQ_FLAG_LOCAL, the 'fqd' structure's + * 'dest::channel' field will be overwritten to match the portal used to issue + * the command. If the WE_DESTWQ write-enable bit had already been set by the + * caller, the channel workqueue will be left as-is, otherwise the write-enable + * bit is set and the workqueue is set to a default of 4. If the "LOCAL" flag + * isn't set, the destination channel/workqueue fields and the write-enable bit + * are left as-is. + * 4. if the driver overwrites context_a/b for demux, then if + * QM_INITFQ_WE_CONTEXTA is set, the driver will only overwrite + * context_a.address fields and will leave the stashing fields provided by the + * user alone, otherwise it will zero out the context_a.stashing fields. + */ +int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts); + +/** + * qman_schedule_fq - Schedules a FQ + * @fq: the frame queue object to schedule, must be 'parked' + * + * Schedules the frame queue, which must be Parked, which takes it to + * Tentatively-Scheduled or Truly-Scheduled depending on its fill-level. + */ +int qman_schedule_fq(struct qman_fq *fq); + +/** + * qman_retire_fq - Retires a FQ + * @fq: the frame queue object to retire + * @flags: FQ flags (as per qman_fq_state) if retirement completes immediately + * + * Retires the frame queue. This returns zero if it succeeds immediately, +1 if + * the retirement was started asynchronously, otherwise it returns negative for + * failure. When this function returns zero, @flags is set to indicate whether + * the retired FQ is empty and/or whether it has any ORL fragments (to show up + * as ERNs). Otherwise the corresponding flags will be known when a subsequent + * FQRN message shows up on the portal's message ring. + * + * NB, if the retirement is asynchronous (the FQ was in the Truly Scheduled or + * Active state), the completion will be via the message ring as a FQRN - but + * the corresponding callback may occur before this function returns!! Ie. the + * caller should be prepared to accept the callback as the function is called, + * not only once it has returned. + */ +int qman_retire_fq(struct qman_fq *fq, u32 *flags); + +/** + * qman_oos_fq - Puts a FQ "out of service" + * @fq: the frame queue object to be put out-of-service, must be 'retired' + * + * The frame queue must be retired and empty, and if any order restoration list + * was released as ERNs at the time of retirement, they must all be consumed. + */ +int qman_oos_fq(struct qman_fq *fq); + +/** + * qman_query_fq - Queries FQD fields (via h/w query command) + * @fq: the frame queue object to be queried + * @fqd: storage for the queried FQD fields + */ +int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd); + +/** + * qman_query_fq_np - Queries non-programmable FQD fields + * @fq: the frame queue object to be queried + * @np: storage for the queried FQD fields + */ +int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np); + +/** + * qman_query_wq - Queries work queue lengths + * @query_dedicated: If non-zero, query length of WQs in the channel dedicated + * to this software portal. Otherwise, query length of WQs in a + * channel specified in wq. + * @wq: storage for the queried WQs lengths. Also specified the channel to + * to query if query_dedicated is zero. + */ +int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq); + +/** + * qman_volatile_dequeue - Issue a volatile dequeue command + * @fq: the frame queue object to dequeue from (or NULL) + * @flags: a bit-mask of QMAN_VOLATILE_FLAG_*** options + * @vdqcr: bit mask of QM_VDQCR_*** options, as per qm_dqrr_vdqcr_set() + * + * Attempts to lock access to the portal's VDQCR volatile dequeue functionality. + * The function will block and sleep if QMAN_VOLATILE_FLAG_WAIT is specified and + * the VDQCR is already in use, otherwise returns non-zero for failure. If + * QMAN_VOLATILE_FLAG_FINISH is specified, the function will only return once + * the VDQCR command has finished executing (ie. once the callback for the last + * DQRR entry resulting from the VDQCR command has been called). If not using + * the FINISH flag, completion can be determined either by detecting the + * presence of the QM_DQRR_STAT_UNSCHEDULED and QM_DQRR_STAT_DQCR_EXPIRED bits + * in the "stat" field of the "struct qm_dqrr_entry" passed to the FQ's dequeue + * callback, or by waiting for the QMAN_FQ_STATE_VDQCR bit to disappear from the + * "flags" retrieved from qman_fq_state(). If @fq is non-NULL, the corresponding + * FQID will be substituted in to the VDQCR command, otherwise it is assumed + * that @vdqcr already contains the FQID to dequeue from. + */ +int qman_volatile_dequeue(struct qman_fq *fq, u32 flags, u32 vdqcr); + +/** + * qman_enqueue - Enqueue a frame to a frame queue + * @fq: the frame queue object to enqueue to + * @fd: a descriptor of the frame to be enqueued + * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options + * + * Fills an entry in the EQCR of portal @qm to enqueue the frame described by + * @fd. The descriptor details are copied from @fd to the EQCR entry, the 'pid' + * field is ignored. The return value is non-zero on error, such as ring full + * (and FLAG_WAIT not specified), congestion avoidance (FLAG_WATCH_CGR + * specified), etc. If the ring is full and FLAG_WAIT is specified, this + * function will block. If FLAG_INTERRUPT is set, the EQCI bit of the portal + * interrupt will assert when Qman consumes the EQCR entry (subject to "status + * disable", "enable", and "inhibit" registers). If FLAG_DCA is set, Qman will + * perform an implied "discrete consumption acknowledgement" on the dequeue + * ring's (DQRR) entry, at the ring index specified by the FLAG_DCA_IDX(x) + * macro. (As an alternative to issuing explicit DCA actions on DQRR entries, + * this implicit DCA can delay the release of a "held active" frame queue + * corresponding to a DQRR entry until Qman consumes the EQCR entry - providing + * order-preservation semantics in packet-forwarding scenarios.) If FLAG_DCA is + * set, then FLAG_DCA_PARK can also be set to imply that the DQRR consumption + * acknowledgement should "park request" the "held active" frame queue. Ie. + * when the portal eventually releases that frame queue, it will be left in the + * Parked state rather than Tentatively Scheduled or Truly Scheduled. If the + * portal is watching congestion groups, the QMAN_ENQUEUE_FLAG_WATCH_CGR flag + * is requested, and the FQ is a member of a congestion group, then this + * function returns -EAGAIN if the congestion group is currently congested. + * Note, this does not eliminate ERNs, as the async interface means we can be + * sending enqueue commands to an un-congested FQ that becomes congested before + * the enqueue commands are processed, but it does minimise needless thrashing + * of an already busy hardware resource by throttling many of the to-be-dropped + * enqueues "at the source". + */ +int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags); + +/** + * qman_enqueue_orp - Enqueue a frame to a frame queue using an ORP + * @fq: the frame queue object to enqueue to + * @fd: a descriptor of the frame to be enqueued + * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options + * @orp: the frame queue object used as an order restoration point. + * @orp_seqnum: the sequence number of this frame in the order restoration path + * + * Similar to qman_enqueue(), but with the addition of an Order Restoration + * Point (@orp) and corresponding sequence number (@orp_seqnum) for this + * enqueue operation to employ order restoration. Each frame queue object acts + * as an Order Definition Point (ODP) by providing each frame dequeued from it + * with an incrementing sequence number, this value is generally ignored unless + * that sequence of dequeued frames will need order restoration later. Each + * frame queue object also encapsulates an Order Restoration Point (ORP), which + * is a re-assembly context for re-ordering frames relative to their sequence + * numbers as they are enqueued. The ORP does not have to be within the frame + * queue that receives the enqueued frame, in fact it is usually the frame + * queue from which the frames were originally dequeued. For the purposes of + * order restoration, multiple frames (or "fragments") can be enqueued for a + * single sequence number by setting the QMAN_ENQUEUE_FLAG_NLIS flag for all + * enqueues except the final fragment of a given sequence number. Ordering + * between sequence numbers is guaranteed, even if fragments of different + * sequence numbers are interlaced with one another. Fragments of the same + * sequence number will retain the order in which they are enqueued. If no + * enqueue is to performed, QMAN_ENQUEUE_FLAG_HOLE indicates that the given + * sequence number is to be "skipped" by the ORP logic (eg. if a frame has been + * dropped from a sequence), or QMAN_ENQUEUE_FLAG_NESN indicates that the given + * sequence number should become the ORP's "Next Expected Sequence Number". + * + * Side note: a frame queue object can be used purely as an ORP, without + * carrying any frames at all. Care should be taken not to deallocate a frame + * queue object that is being actively used as an ORP, as a future allocation + * of the frame queue object may start using the internal ORP before the + * previous use has finished. + */ +int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags, + struct qman_fq *orp, u16 orp_seqnum); + +/** + * qman_alloc_fqid_range - Allocate a contiguous range of FQIDs + * @result: is set by the API to the base FQID of the allocated range + * @count: the number of FQIDs required + * @align: required alignment of the allocated range + * @partial: non-zero if the API can return fewer than @count FQIDs + + * Returns the number of frame queues allocated, or a negative error code. If + * @partial is non zero, the allocation request may return a smaller range of + * FQs than requested (though alignment will be as requested). If @partial is + * zero, the return value will either be 'count' or negative. + */ +int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial); +static inline int qman_alloc_fqid(u32 *result) +{ + return qman_alloc_fqid_range(result, 1, 0, 0); +} + +/** + * qman_release_fqid_range - Release the specified range of frame queue IDs + * @fqid: the base FQID of the range to deallocate + * @count: the number of FQIDs in the range + * + * This function can also be used to seed the allocator with ranges of FQIDs + * that it can subsequently use. Returns zero for success. + */ +void qman_release_fqid_range(u32 fqid, unsigned int count); +static inline void qman_release_fqid(u32 fqid) +{ + qman_release_fqid_range(fqid, 1); +} + + /* CGR management */ + /* -------------- */ +/** + * qman_create_cgr - Register a congestion group object + * @cgr: the 'cgr' object, with fields filled in + * @flags: QMAN_CGR_FLAG_* values + * @opts: optional state of CGR settings + * + * Registers this object to receiving congestion entry/exit callbacks on the + * portal affine to the cpu portal on which this API is executed. If opts is + * NULL then only the callback (cgr->cb) function is registered. If @flags + * contains QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset + * any unspecified parameters) will be used rather than a modify hw hardware + * (which only modifies the specified parameters). + */ +int qman_create_cgr(struct qman_cgr *cgr, u32 flags, + struct qm_mcc_initcgr *opts); + +/** + * qman_delete_cgr - Deregisters a congestion group object + * @cgr: the 'cgr' object to deregister + * + * "Unplugs" this CGR object from the portal affine to the cpu on which this API + * is executed. This must be excuted on the same affine portal on which it was + * created. + */ +int qman_delete_cgr(struct qman_cgr *cgr); + +/** + * qman_modify_cgr - Modify CGR fields + * @cgr: the 'cgr' object to modify + * @flags: QMAN_CGR_FLAG_* values + * @opts: the CGR-modification settings + * + * The @opts parameter comes from the low-level portal API, and can be NULL. + * Note that some fields and options within @opts may be ignored or overwritten + * by the driver, in particular the 'cgrid' field is ignored (this operation + * only affects the given CGR object). If @flags contains + * QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset any + * unspecified parameters) will be used rather than a modify hw hardware (which + * only modifies the specified parameters). + */ +int qman_modify_cgr(struct qman_cgr *cgr, u32 flags, + struct qm_mcc_initcgr *opts); + +/** +* qman_query_cgr - Queries CGR fields +* @cgr: the 'cgr' object to query +* @result: storage for the queried congestion group record +*/ +int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *result); + +/** + * qman_query_congestion - Queries the state of all congestion groups + * @congestion: storage for the queried state of all congestion groups + */ +int qman_query_congestion(struct qm_mcr_querycongestion *congestion); + + /* Helpers */ + /* ------- */ +/** + * qman_poll_fq_for_init - Check if an FQ has been initialised from OOS + * @fqid: the FQID that will be initialised by other s/w + * + * In many situations, a FQID is provided for communication between s/w + * entities, and whilst the consumer is responsible for initialising and + * scheduling the FQ, the producer(s) generally create a wrapper FQ object using + * and only call qman_enqueue() (no FQ initialisation, scheduling, etc). Ie; + * qman_create_fq(..., QMAN_FQ_FLAG_NO_MODIFY, ...); + * However, data can not be enqueued to the FQ until it is initialised out of + * the OOS state - this function polls for that condition. It is particularly + * useful for users of IPC functions - each endpoint's Rx FQ is the other + * endpoint's Tx FQ, so each side can initialise and schedule their Rx FQ object + * and then use this API on the (NO_MODIFY) Tx FQ object in order to + * synchronise. The function returns zero for success, +1 if the FQ is still in + * the OOS state, or negative if there was an error. + */ +static inline int qman_poll_fq_for_init(struct qman_fq *fq) +{ + struct qm_mcr_queryfq_np np; + int err; + err = qman_query_fq_np(fq, &np); + if (err) + return err; + if ((np.state & QM_MCR_NP_STATE_MASK) == QM_MCR_NP_STATE_OOS) + return 1; + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* FSL_QMAN_H */ + --- linux-3.13.0.orig/include/linux/ipv6.h +++ linux-3.13.0/include/linux/ipv6.h @@ -283,6 +283,8 @@ #define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only) #define ipv6_only_sock(sk) ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk)) +#define ipv6_sk_rxinfo(sk) ((sk)->sk_family == PF_INET6 && \ + inet6_sk(sk)->rxopt.bits.rxinfo) static inline const struct in6_addr *inet6_rcv_saddr(const struct sock *sk) { @@ -299,6 +301,7 @@ #else #define __ipv6_only_sock(sk) 0 #define ipv6_only_sock(sk) 0 +#define ipv6_sk_rxinfo(sk) 0 static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) { --- linux-3.13.0.orig/include/linux/efi.h +++ linux-3.13.0/include/linux/efi.h @@ -653,6 +653,7 @@ #define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */ #define EFI_MEMMAP 4 /* Can we use EFI memory map? */ #define EFI_64BIT 5 /* Is the firmware 64-bit? */ +#define EFI_ARCH_1 6 /* First arch-specific bit */ #ifdef CONFIG_EFI # ifdef CONFIG_X86 --- linux-3.13.0.orig/include/linux/mm.h +++ linux-3.13.0/include/linux/mm.h @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include struct mempolicy; struct anon_vma; @@ -165,7 +168,7 @@ * Special vmas that are non-mergable, non-mlock()able. * Note: mm/huge_memory.c VM_NO_THP depends on this definition. */ -#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP) +#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP) /* * mapping from the currently active vm_flags protection bits (the @@ -846,11 +849,14 @@ #endif #if defined(WANT_PAGE_VIRTUAL) -#define page_address(page) ((page)->virtual) -#define set_page_address(page, address) \ - do { \ - (page)->virtual = (address); \ - } while(0) +static inline void *page_address(const struct page *page) +{ + return page->virtual; +} +static inline void set_page_address(struct page *page, void *address) +{ + page->virtual = address; +} #define page_address_init() do { } while(0) #endif @@ -1101,6 +1107,87 @@ } #endif +/* + * Mainly for aufs which mmap(2) diffrent file and wants to print different path + * in /proc/PID/maps. + */ +/* #define AUFS_DEBUG_MMAP */ +static inline void aufs_trace(struct file *f, struct file *pr, + const char func[], int line, const char func2[]) +{ +#ifdef AUFS_DEBUG_MMAP + if (pr) + pr_info("%s:%d: %s, %p\n", func, line, func2, + f ? (char *)f->f_dentry->d_name.name : "(null)"); +#endif +} + +static inline struct file *vmr_do_pr_or_file(struct vm_region *region, + const char func[], int line) +{ + struct file *f = region->vm_file, *pr = region->vm_prfile; + aufs_trace(f, pr, func, line, __func__); + return (f && pr) ? pr : f; +} + +static inline void vmr_do_fput(struct vm_region *region, + const char func[], int line) +{ + struct file *f = region->vm_file, *pr = region->vm_prfile; + aufs_trace(f, pr, func, line, __func__); + fput(f); + if (f && pr) + fput(pr); +} + +static inline void vma_do_file_update_time(struct vm_area_struct *vma, + const char func[], int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + aufs_trace(f, pr, func, line, __func__); + file_update_time(f); + if (f && pr) + file_update_time(pr); +} + +static inline struct file *vma_do_pr_or_file(struct vm_area_struct *vma, + const char func[], int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + aufs_trace(f, pr, func, line, __func__); + return (f && pr) ? pr : f; +} + +static inline void vma_do_get_file(struct vm_area_struct *vma, + const char func[], int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + aufs_trace(f, pr, func, line, __func__); + get_file(f); + if (f && pr) + get_file(pr); +} + +static inline void vma_do_fput(struct vm_area_struct *vma, + const char func[], int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + aufs_trace(f, pr, func, line, __func__); + fput(f); + if (f && pr) + fput(pr); +} + +#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ + __LINE__) +#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) +#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ + __LINE__) +#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ + __LINE__) +#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) +#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, int write); --- linux-3.13.0.orig/include/linux/fs.h +++ linux-3.13.0/include/linux/fs.h @@ -246,6 +246,12 @@ */ #include +/* + * Maximum number of layers of fs stack. Needs to be limited to + * prevent kernel stack overflow + */ +#define FILESYSTEM_MAX_STACK_DEPTH 2 + /** * enum positive_aop_returns - aop return codes with specific semantics * @@ -1325,6 +1331,11 @@ struct list_lru s_dentry_lru ____cacheline_aligned_in_smp; struct list_lru s_inode_lru ____cacheline_aligned_in_smp; struct rcu_head rcu; + + /* + * Indicates how deep in a filesystem stack this SB is + */ + int s_stack_depth; }; extern struct timespec current_fs_time(struct super_block *sb); @@ -1580,6 +1591,7 @@ struct file *, unsigned open_flag, umode_t create_mode, int *opened); int (*tmpfile) (struct inode *, struct dentry *, umode_t); + int (*dentry_open)(struct dentry *, struct file *, const struct cred *); } ____cacheline_aligned; ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, @@ -2074,6 +2086,7 @@ extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int); +extern int vfs_open(const struct path *, struct file *, const struct cred *); extern struct file * dentry_open(const struct path *, int, const struct cred *); extern int filp_close(struct file *, fl_owner_t id); @@ -2280,6 +2293,7 @@ #endif extern int notify_change(struct dentry *, struct iattr *, struct inode **); extern int inode_permission(struct inode *, int); +extern int __inode_permission(struct inode *, int); extern int generic_permission(struct inode *, int); static inline bool execute_ok(struct inode *inode) @@ -2488,6 +2502,9 @@ struct file *, loff_t *, size_t, unsigned int); extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, loff_t *, size_t len, unsigned int flags); +extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, + loff_t *opos, size_t len, unsigned int flags); + extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); @@ -2657,6 +2674,7 @@ extern int inode_newsize_ok(const struct inode *, loff_t offset); extern void setattr_copy(struct inode *inode, const struct iattr *attr); +extern int update_time(struct inode *, struct timespec *, int); extern int file_update_time(struct file *file); extern int generic_show_options(struct seq_file *m, struct dentry *root); --- linux-3.13.0.orig/include/linux/compat.h +++ linux-3.13.0/include/linux/compat.h @@ -327,16 +327,16 @@ u32 arg2, u32 arg3, u32 arg4, u32 arg5); asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32); -asmlinkage ssize_t compat_sys_readv(unsigned long fd, - const struct compat_iovec __user *vec, unsigned long vlen); -asmlinkage ssize_t compat_sys_writev(unsigned long fd, - const struct compat_iovec __user *vec, unsigned long vlen); -asmlinkage ssize_t compat_sys_preadv(unsigned long fd, +asmlinkage ssize_t compat_sys_readv(compat_ulong_t fd, + const struct compat_iovec __user *vec, compat_ulong_t vlen); +asmlinkage ssize_t compat_sys_writev(compat_ulong_t fd, + const struct compat_iovec __user *vec, compat_ulong_t vlen); +asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd, const struct compat_iovec __user *vec, - unsigned long vlen, u32 pos_low, u32 pos_high); -asmlinkage ssize_t compat_sys_pwritev(unsigned long fd, + compat_ulong_t vlen, u32 pos_low, u32 pos_high); +asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd, const struct compat_iovec __user *vec, - unsigned long vlen, u32 pos_low, u32 pos_high); + compat_ulong_t vlen, u32 pos_low, u32 pos_high); asmlinkage long comat_sys_lseek(unsigned int, compat_off_t, unsigned int); asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv, @@ -422,7 +422,7 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, compat_long_t addr, compat_long_t data); -asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, size_t); +asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t); /* * epoll (fs/eventpoll.c) compat bits follow ... */ --- linux-3.13.0.orig/include/linux/nfs_xdr.h +++ linux-3.13.0/include/linux/nfs_xdr.h @@ -379,12 +379,14 @@ * Arguments to the open_confirm call. */ struct nfs_open_confirmargs { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; nfs4_stateid * stateid; struct nfs_seqid * seqid; }; struct nfs_open_confirmres { + struct nfs4_sequence_res seq_res; nfs4_stateid stateid; struct nfs_seqid * seqid; }; @@ -465,9 +467,14 @@ }; struct nfs_release_lockowner_args { + struct nfs4_sequence_args seq_args; struct nfs_lowner lock_owner; }; +struct nfs_release_lockowner_res { + struct nfs4_sequence_res seq_res; +}; + struct nfs4_delegreturnargs { struct nfs4_sequence_args seq_args; const struct nfs_fh *fhandle; --- linux-3.13.0.orig/include/linux/netdev_features.h +++ linux-3.13.0/include/linux/netdev_features.h @@ -63,6 +63,7 @@ NETIF_F_HW_VLAN_STAG_RX_BIT, /* Receive VLAN STAG HW acceleration */ NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */ NETIF_F_HW_L2FW_DOFFLOAD_BIT, /* Allow L2 Forwarding in Hardware */ + NETIF_F_HW_QDISC_BIT, /* Supports hardware Qdisc */ /* * Add your fresh new feature above and remember to update @@ -90,6 +91,7 @@ #define NETIF_F_HW_VLAN_CTAG_FILTER __NETIF_F(HW_VLAN_CTAG_FILTER) #define NETIF_F_HW_VLAN_CTAG_RX __NETIF_F(HW_VLAN_CTAG_RX) #define NETIF_F_HW_VLAN_CTAG_TX __NETIF_F(HW_VLAN_CTAG_TX) +#define NETIF_F_HW_QDISC __NETIF_F(HW_QDISC) #define NETIF_F_IP_CSUM __NETIF_F(IP_CSUM) #define NETIF_F_IPV6_CSUM __NETIF_F(IPV6_CSUM) #define NETIF_F_LLTX __NETIF_F(LLTX) --- linux-3.13.0.orig/include/linux/nvme.h +++ linux-3.13.0/include/linux/nvme.h @@ -80,13 +80,14 @@ struct dma_pool *prp_small_pool; int instance; int queue_count; - int db_stride; + u32 db_stride; u32 ctrl_config; struct msix_entry *entry; struct nvme_bar __iomem *bar; struct list_head namespaces; struct kref kref; struct miscdevice miscdev; + struct work_struct reset_work; char name[12]; char serial[20]; char model[40]; @@ -94,6 +95,8 @@ u32 max_hw_sectors; u32 stripe_size; u16 oncs; + u16 abort_limit; + u8 initialized; }; /* @@ -165,6 +168,7 @@ struct sg_io_hdr; int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr); +int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg); int nvme_sg_get_version_num(int __user *ip); #endif /* _LINUX_NVME_H */ --- linux-3.13.0.orig/include/linux/pipe_fs_i.h +++ linux-3.13.0/include/linux/pipe_fs_i.h @@ -157,6 +157,8 @@ int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *); void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *); +extern const struct pipe_buf_operations nosteal_pipe_buf_ops; + /* for F_SETPIPE_SZ and F_GETPIPE_SZ */ long pipe_fcntl(struct file *, unsigned int, unsigned long arg); struct pipe_inode_info *get_pipe_info(struct file *file); --- linux-3.13.0.orig/include/linux/phy.h +++ linux-3.13.0/include/linux/phy.h @@ -66,6 +66,7 @@ PHY_INTERFACE_MODE_RGMII_TXID, PHY_INTERFACE_MODE_RTBI, PHY_INTERFACE_MODE_SMII, + PHY_INTERFACE_MODE_XGMII, } phy_interface_t; @@ -498,6 +499,21 @@ } /** + * phy_read_mmd - Convenience function for reading a register + * from an MMD on a given PHY. + * @phydev: The phy_device struct + * @devad: The MMD to read from + * @regnum: The register on the MMD to read + * + * Same rules as for phy_read(); + */ +static inline int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) +{ + return mdiobus_read(phydev->bus, phydev->addr, + MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff)); +} + +/** * phy_write - Convenience function for writing a given PHY register * @phydev: the phy_device struct * @regnum: register number to write @@ -533,6 +549,24 @@ return phydev->is_internal; } +/** + * phy_write_mmd - Convenience function for writing a register + * on an MMD on a given PHY. + * @phydev: The phy_device struct + * @devad: The MMD to read from + * @regnum: The register on the MMD to read + * @val: value to write to @regnum + * + * Same rules as for phy_write(); + */ +static inline int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, + u16 val) +{ + regnum = MII_ADDR_C45 | ((devad & 0x1f) << 16) | (regnum & 0xffff); + + return mdiobus_write(phydev->bus, phydev->addr, regnum, val); +} + struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids); struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45); @@ -540,6 +574,8 @@ int phy_init_hw(struct phy_device *phydev); struct phy_device * phy_attach(struct net_device *dev, const char *bus_id, phy_interface_t interface); +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + u32 flags, phy_interface_t interface); struct phy_device *phy_find_first(struct mii_bus *bus); int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, void (*handler)(struct net_device *), --- linux-3.13.0.orig/include/linux/fmd/ioctls.h +++ linux-3.13.0/include/linux/fmd/ioctls.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File ioctls.h + + @Description Structures and definitions for Command Relay Ioctls +*//***************************************************************************/ + +#ifndef __IOCTLS_H__ +#define __IOCTLS_H__ + +#include + +#include "integration_ioctls.h" + + +/**************************************************************************//** + @Group lnx_ioctl_ncsw_grp NetCommSw Linux User-Space (IOCTL) API + @{ +*//***************************************************************************/ + +#define NCSW_IOC_TYPE_BASE 0xe0 /**< defines the IOCTL type for all + the NCSW Linux module commands */ + + +/**************************************************************************//** + @Description IOCTL Memory allocation types. +*//***************************************************************************/ +typedef enum ioc_mem_type { + e_IOC_MEM_INVALID = 0x00000000, /**< Invalid memory type (error) */ + e_IOC_MEM_CACHABLE_SYS = 0x00000001, /**< Primary DDR, cacheable segment */ + e_IOC_MEM_NOCACHE_SYS = 0x00000004, /**< Primary DDR, non-cacheable segment */ + e_IOC_MEM_SECONDARY = 0x00000002, /**< Either secondary DDR or SDRAM */ + e_IOC_MEM_PRAM = 0x00000008 /**< Multi-user RAM identifier */ +} ioc_mem_type; + +/**************************************************************************//** + @Description Enumeration (bit flags) of communication modes (Transmit, + receive or both). +*//***************************************************************************/ +typedef enum ioc_comm_mode { + e_IOC_COMM_MODE_NONE = 0 /**< No transmit/receive communication */ + , e_IOC_COMM_MODE_RX = 1 /**< Only receive communication */ + , e_IOC_COMM_MODE_TX = 2 /**< Only transmit communication */ + , e_IOC_COMM_MODE_RX_AND_TX = 3 /**< Both transmit and receive communication */ +} ioc_comm_mode; + +/**************************************************************************//** + @Description General Diagnostic Mode +*//***************************************************************************/ +typedef enum ioc_diag_mode +{ + e_IOC_DIAG_MODE_NONE = 0, + e_IOC_DIAG_MODE_CTRL_LOOPBACK, /**< loopback in the controller; E.g. MAC, TDM, etc. */ + e_IOC_DIAG_MODE_CHIP_LOOPBACK, /**< loopback in the chip but not in controller; + E.g. IO-pins, SerDes, etc. */ + e_IOC_DIAG_MODE_PHY_LOOPBACK, /**< loopback in the external PHY */ + e_IOC_DIAG_MODE_LINE_LOOPBACK, /**< loopback in the external line */ + e_IOC_DIAG_MODE_CTRL_ECHO, /**< */ + e_IOC_DIAG_MODE_PHY_ECHO /**< */ +} ioc_diag_mode; + +/** @} */ /* end of lnx_ioctl_ncsw_grp */ + + +#endif /* __IOCTLS_H__ */ --- linux-3.13.0.orig/include/linux/fmd/net_ioctls.h +++ linux-3.13.0/include/linux/fmd/net_ioctls.h @@ -0,0 +1,383 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File net_ioctls.h + + @Description This file contains common and general netcomm headers definitions. +*//***************************************************************************/ +#ifndef __NET_IOCTLS_H +#define __NET_IOCTLS_H + +#include "ioctls.h" + + +typedef uint8_t ioc_header_field_ppp_t; + +#define IOC_NET_HEADER_FIELD_PPP_PID (1) +#define IOC_NET_HEADER_FIELD_PPP_COMPRESSED (IOC_NET_HEADER_FIELD_PPP_PID << 1) +#define IOC_NET_HEADER_FIELD_PPP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPP_PID << 2) - 1) + + +typedef uint8_t ioc_header_field_pppoe_t; + +#define IOC_NET_HEADER_FIELD_PPPoE_VER (1) +#define IOC_NET_HEADER_FIELD_PPPoE_TYPE (IOC_NET_HEADER_FIELD_PPPoE_VER << 1) +#define IOC_NET_HEADER_FIELD_PPPoE_CODE (IOC_NET_HEADER_FIELD_PPPoE_VER << 2) +#define IOC_NET_HEADER_FIELD_PPPoE_SID (IOC_NET_HEADER_FIELD_PPPoE_VER << 3) +#define IOC_NET_HEADER_FIELD_PPPoE_LEN (IOC_NET_HEADER_FIELD_PPPoE_VER << 4) +#define IOC_NET_HEADER_FIELD_PPPoE_SESSION (IOC_NET_HEADER_FIELD_PPPoE_VER << 5) +#define IOC_NET_HEADER_FIELD_PPPoE_PID (IOC_NET_HEADER_FIELD_PPPoE_VER << 6) +#define IOC_NET_HEADER_FIELD_PPPoE_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPPoE_VER << 7) - 1) + +#define IOC_NET_HEADER_FIELD_PPPMUX_PID (1) +#define IOC_NET_HEADER_FIELD_PPPMUX_CKSUM (IOC_NET_HEADER_FIELD_PPPMUX_PID << 1) +#define IOC_NET_HEADER_FIELD_PPPMUX_COMPRESSED (IOC_NET_HEADER_FIELD_PPPMUX_PID << 2) +#define IOC_NET_HEADER_FIELD_PPPMUX_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPPMUX_PID << 3) - 1) + +#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF (1) +#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1) +#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2) +#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3) +#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4) +#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1) + + +typedef uint8_t ioc_header_field_eth_t; + +#define IOC_NET_HEADER_FIELD_ETH_DA (1) +#define IOC_NET_HEADER_FIELD_ETH_SA (IOC_NET_HEADER_FIELD_ETH_DA << 1) +#define IOC_NET_HEADER_FIELD_ETH_LENGTH (IOC_NET_HEADER_FIELD_ETH_DA << 2) +#define IOC_NET_HEADER_FIELD_ETH_TYPE (IOC_NET_HEADER_FIELD_ETH_DA << 3) +#define IOC_NET_HEADER_FIELD_ETH_FINAL_CKSUM (IOC_NET_HEADER_FIELD_ETH_DA << 4) +#define IOC_NET_HEADER_FIELD_ETH_PADDING (IOC_NET_HEADER_FIELD_ETH_DA << 5) +#define IOC_NET_HEADER_FIELD_ETH_ALL_FIELDS ((IOC_NET_HEADER_FIELD_ETH_DA << 6) - 1) + + +typedef uint16_t ioc_header_field_ipv4_t; + +#define IOC_NET_HEADER_FIELD_IPv4_VER (1) +#define IOC_NET_HEADER_FIELD_IPv4_HDR_LEN (IOC_NET_HEADER_FIELD_IPv4_VER << 1) +#define IOC_NET_HEADER_FIELD_IPv4_TOS (IOC_NET_HEADER_FIELD_IPv4_VER << 2) +#define IOC_NET_HEADER_FIELD_IPv4_TOTAL_LEN (IOC_NET_HEADER_FIELD_IPv4_VER << 3) +#define IOC_NET_HEADER_FIELD_IPv4_ID (IOC_NET_HEADER_FIELD_IPv4_VER << 4) +#define IOC_NET_HEADER_FIELD_IPv4_FLAG_D (IOC_NET_HEADER_FIELD_IPv4_VER << 5) +#define IOC_NET_HEADER_FIELD_IPv4_FLAG_M (IOC_NET_HEADER_FIELD_IPv4_VER << 6) +#define IOC_NET_HEADER_FIELD_IPv4_OFFSET (IOC_NET_HEADER_FIELD_IPv4_VER << 7) +#define IOC_NET_HEADER_FIELD_IPv4_TTL (IOC_NET_HEADER_FIELD_IPv4_VER << 8) +#define IOC_NET_HEADER_FIELD_IPv4_PROTO (IOC_NET_HEADER_FIELD_IPv4_VER << 9) +#define IOC_NET_HEADER_FIELD_IPv4_CKSUM (IOC_NET_HEADER_FIELD_IPv4_VER << 10) +#define IOC_NET_HEADER_FIELD_IPv4_SRC_IP (IOC_NET_HEADER_FIELD_IPv4_VER << 11) +#define IOC_NET_HEADER_FIELD_IPv4_DST_IP (IOC_NET_HEADER_FIELD_IPv4_VER << 12) +#define IOC_NET_HEADER_FIELD_IPv4_OPTS (IOC_NET_HEADER_FIELD_IPv4_VER << 13) +#define IOC_NET_HEADER_FIELD_IPv4_OPTS_COUNT (IOC_NET_HEADER_FIELD_IPv4_VER << 14) +#define IOC_NET_HEADER_FIELD_IPv4_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPv4_VER << 15) - 1) + + +typedef uint8_t ioc_header_field_ipv6_t; + +#define IOC_NET_HEADER_FIELD_IPv6_VER (1) +#define IOC_NET_HEADER_FIELD_IPv6_TC (IOC_NET_HEADER_FIELD_IPv6_VER << 1) +#define IOC_NET_HEADER_FIELD_IPv6_SRC_IP (IOC_NET_HEADER_FIELD_IPv6_VER << 2) +#define IOC_NET_HEADER_FIELD_IPv6_DST_IP (IOC_NET_HEADER_FIELD_IPv6_VER << 3) +#define IOC_NET_HEADER_FIELD_IPv6_NEXT_HDR (IOC_NET_HEADER_FIELD_IPv6_VER << 4) +#define IOC_NET_HEADER_FIELD_IPv6_FL (IOC_NET_HEADER_FIELD_IPv6_VER << 5) +#define IOC_NET_HEADER_FIELD_IPv6_HOP_LIMIT (IOC_NET_HEADER_FIELD_IPv6_VER << 6) +#define IOC_NET_HEADER_FIELD_IPv6_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPv6_VER << 7) - 1) + +#define IOC_NET_HEADER_FIELD_ICMP_TYPE (1) +#define IOC_NET_HEADER_FIELD_ICMP_CODE (IOC_NET_HEADER_FIELD_ICMP_TYPE << 1) +#define IOC_NET_HEADER_FIELD_ICMP_CKSUM (IOC_NET_HEADER_FIELD_ICMP_TYPE << 2) +#define IOC_NET_HEADER_FIELD_ICMP_ID (IOC_NET_HEADER_FIELD_ICMP_TYPE << 3) +#define IOC_NET_HEADER_FIELD_ICMP_SQ_NUM (IOC_NET_HEADER_FIELD_ICMP_TYPE << 4) +#define IOC_NET_HEADER_FIELD_ICMP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_ICMP_TYPE << 5) - 1) + +#define IOC_NET_HEADER_FIELD_IGMP_VERSION (1) +#define IOC_NET_HEADER_FIELD_IGMP_TYPE (IOC_NET_HEADER_FIELD_IGMP_VERSION << 1) +#define IOC_NET_HEADER_FIELD_IGMP_CKSUM (IOC_NET_HEADER_FIELD_IGMP_VERSION << 2) +#define IOC_NET_HEADER_FIELD_IGMP_DATA (IOC_NET_HEADER_FIELD_IGMP_VERSION << 3) +#define IOC_NET_HEADER_FIELD_IGMP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IGMP_VERSION << 4) - 1) + + +typedef uint16_t ioc_header_field_tcp_t; + +#define IOC_NET_HEADER_FIELD_TCP_PORT_SRC (1) +#define IOC_NET_HEADER_FIELD_TCP_PORT_DST (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 1) +#define IOC_NET_HEADER_FIELD_TCP_SEQ (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 2) +#define IOC_NET_HEADER_FIELD_TCP_ACK (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 3) +#define IOC_NET_HEADER_FIELD_TCP_OFFSET (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 4) +#define IOC_NET_HEADER_FIELD_TCP_FLAGS (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 5) +#define IOC_NET_HEADER_FIELD_TCP_WINDOW (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 6) +#define IOC_NET_HEADER_FIELD_TCP_CKSUM (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 7) +#define IOC_NET_HEADER_FIELD_TCP_URGPTR (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 8) +#define IOC_NET_HEADER_FIELD_TCP_OPTS (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 9) +#define IOC_NET_HEADER_FIELD_TCP_OPTS_COUNT (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 10) +#define IOC_NET_HEADER_FIELD_TCP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1) + + +typedef uint8_t ioc_header_field_sctp_t; + +#define IOC_NET_HEADER_FIELD_SCTP_PORT_SRC (1) +#define IOC_NET_HEADER_FIELD_SCTP_PORT_DST (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 1) +#define IOC_NET_HEADER_FIELD_SCTP_VER_TAG (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 2) +#define IOC_NET_HEADER_FIELD_SCTP_CKSUM (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 3) +#define IOC_NET_HEADER_FIELD_SCTP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1) + + +typedef uint8_t ioc_header_field_dccp_t; + +#define IOC_NET_HEADER_FIELD_DCCP_PORT_SRC (1) +#define IOC_NET_HEADER_FIELD_DCCP_PORT_DST (IOC_NET_HEADER_FIELD_DCCP_PORT_SRC << 1) +#define IOC_NET_HEADER_FIELD_DCCP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1) + + +typedef uint8_t ioc_header_field_udp_t; + +#define IOC_NET_HEADER_FIELD_UDP_PORT_SRC (1) +#define IOC_NET_HEADER_FIELD_UDP_PORT_DST (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 1) +#define IOC_NET_HEADER_FIELD_UDP_LEN (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 2) +#define IOC_NET_HEADER_FIELD_UDP_CKSUM (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 3) +#define IOC_NET_HEADER_FIELD_UDP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1) + +typedef uint8_t ioc_header_field_udp_encap_esp_t; + +#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC (1) +#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1) +#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2) +#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3) +#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4) +#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5) +#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS ((NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1) + +#define IOC_NET_HEADER_FIELD_IPHC_CID (1) +#define IOC_NET_HEADER_FIELD_IPHC_CID_TYPE (IOC_NET_HEADER_FIELD_IPHC_CID << 1) +#define IOC_NET_HEADER_FIELD_IPHC_HCINDEX (IOC_NET_HEADER_FIELD_IPHC_CID << 2) +#define IOC_NET_HEADER_FIELD_IPHC_GEN (IOC_NET_HEADER_FIELD_IPHC_CID << 3) +#define IOC_NET_HEADER_FIELD_IPHC_D_BIT (IOC_NET_HEADER_FIELD_IPHC_CID << 4) +#define IOC_NET_HEADER_FIELD_IPHC_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPHC_CID << 5) - 1) + +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE (1) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_END (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9) +#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS ((IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1) + +#define IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT (1) +#define IOC_NET_HEADER_FIELD_L2TPv2_LENGTH_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 1) +#define IOC_NET_HEADER_FIELD_L2TPv2_SEQUENCE_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 2) +#define IOC_NET_HEADER_FIELD_L2TPv2_OFFSET_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 3) +#define IOC_NET_HEADER_FIELD_L2TPv2_PRIORITY_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 4) +#define IOC_NET_HEADER_FIELD_L2TPv2_VERSION (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 5) +#define IOC_NET_HEADER_FIELD_L2TPv2_LEN (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 6) +#define IOC_NET_HEADER_FIELD_L2TPv2_TUNNEL_ID (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 7) +#define IOC_NET_HEADER_FIELD_L2TPv2_SESSION_ID (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 8) +#define IOC_NET_HEADER_FIELD_L2TPv2_NS (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 9) +#define IOC_NET_HEADER_FIELD_L2TPv2_NR (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 10) +#define IOC_NET_HEADER_FIELD_L2TPv2_OFFSET_SIZE (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 11) +#define IOC_NET_HEADER_FIELD_L2TPv2_FIRST_BYTE (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 12) +#define IOC_NET_HEADER_FIELD_L2TPv2_ALL_FIELDS ((IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 13) - 1) + +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT (1) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH_BIT (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 1) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_SEQUENCE_BIT (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 2) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_VERSION (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 3) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 4) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_CONTROL (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 5) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_SENT (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 6) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_RECV (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 7) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_FIRST_BYTE (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 8) +#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS ((IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 9) - 1) + +#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT (1) +#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_VERSION (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 1) +#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_ID (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 2) +#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_COOKIE (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 3) +#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS ((IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 4) - 1) + + +typedef uint8_t ioc_header_field_vlan_t; + +#define IOC_NET_HEADER_FIELD_VLAN_VPRI (1) +#define IOC_NET_HEADER_FIELD_VLAN_CFI (IOC_NET_HEADER_FIELD_VLAN_VPRI << 1) +#define IOC_NET_HEADER_FIELD_VLAN_VID (IOC_NET_HEADER_FIELD_VLAN_VPRI << 2) +#define IOC_NET_HEADER_FIELD_VLAN_LENGTH (IOC_NET_HEADER_FIELD_VLAN_VPRI << 3) +#define IOC_NET_HEADER_FIELD_VLAN_TYPE (IOC_NET_HEADER_FIELD_VLAN_VPRI << 4) +#define IOC_NET_HEADER_FIELD_VLAN_ALL_FIELDS ((IOC_NET_HEADER_FIELD_VLAN_VPRI << 5) - 1) + + +typedef uint8_t ioc_header_field_llc_t; + +#define IOC_NET_HEADER_FIELD_LLC_DSAP (1) +#define IOC_NET_HEADER_FIELD_LLC_SSAP (IOC_NET_HEADER_FIELD_LLC_DSAP << 1) +#define IOC_NET_HEADER_FIELD_LLC_CTRL (IOC_NET_HEADER_FIELD_LLC_DSAP << 2) +#define IOC_NET_HEADER_FIELD_LLC_ALL_FIELDS ((IOC_NET_HEADER_FIELD_LLC_DSAP << 3) - 1) + +#define IOC_NET_HEADER_FIELD_NLPID_NLPID (1) +#define IOC_NET_HEADER_FIELD_NLPID_ALL_FIELDS ((IOC_NET_HEADER_FIELD_NLPID_NLPID << 1) - 1) + + +typedef uint8_t ioc_header_field_snap_t; + +#define IOC_NET_HEADER_FIELD_SNAP_OUI (1) +#define IOC_NET_HEADER_FIELD_SNAP_PID (IOC_NET_HEADER_FIELD_SNAP_OUI << 1) +#define IOC_NET_HEADER_FIELD_SNAP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_SNAP_OUI << 2) - 1) + + +typedef uint8_t ioc_header_field_llc_snap_t; + +#define IOC_NET_HEADER_FIELD_LLC_SNAP_TYPE (1) +#define IOC_NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1) + +#define IOC_NET_HEADER_FIELD_ARP_HTYPE (1) +#define IOC_NET_HEADER_FIELD_ARP_PTYPE (IOC_NET_HEADER_FIELD_ARP_HTYPE << 1) +#define IOC_NET_HEADER_FIELD_ARP_HLEN (IOC_NET_HEADER_FIELD_ARP_HTYPE << 2) +#define IOC_NET_HEADER_FIELD_ARP_PLEN (IOC_NET_HEADER_FIELD_ARP_HTYPE << 3) +#define IOC_NET_HEADER_FIELD_ARP_OPER (IOC_NET_HEADER_FIELD_ARP_HTYPE << 4) +#define IOC_NET_HEADER_FIELD_ARP_SHA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 5) +#define IOC_NET_HEADER_FIELD_ARP_SPA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 6) +#define IOC_NET_HEADER_FIELD_ARP_THA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 7) +#define IOC_NET_HEADER_FIELD_ARP_TPA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 8) +#define IOC_NET_HEADER_FIELD_ARP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_ARP_HTYPE << 9) - 1) + +#define IOC_NET_HEADER_FIELD_RFC2684_LLC (1) +#define IOC_NET_HEADER_FIELD_RFC2684_NLPID (IOC_NET_HEADER_FIELD_RFC2684_LLC << 1) +#define IOC_NET_HEADER_FIELD_RFC2684_OUI (IOC_NET_HEADER_FIELD_RFC2684_LLC << 2) +#define IOC_NET_HEADER_FIELD_RFC2684_PID (IOC_NET_HEADER_FIELD_RFC2684_LLC << 3) +#define IOC_NET_HEADER_FIELD_RFC2684_VPN_OUI (IOC_NET_HEADER_FIELD_RFC2684_LLC << 4) +#define IOC_NET_HEADER_FIELD_RFC2684_VPN_IDX (IOC_NET_HEADER_FIELD_RFC2684_LLC << 5) +#define IOC_NET_HEADER_FIELD_RFC2684_ALL_FIELDS ((IOC_NET_HEADER_FIELD_RFC2684_LLC << 6) - 1) + +#define IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT (1) +#define IOC_NET_HEADER_FIELD_USER_DEFINED_PCDID (IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1) +#define IOC_NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS ((IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1) + +#define IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER (1) +#define IOC_NET_HEADER_FIELD_PAYLOAD_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 1) +#define IOC_NET_HEADER_FIELD_MAX_FRM_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 2) +#define IOC_NET_HEADER_FIELD_MIN_FRM_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 3) +#define IOC_NET_HEADER_FIELD_PAYLOAD_TYPE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 4) +#define IOC_NET_HEADER_FIELD_FRAME_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 5) +#define IOC_NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1) + + +typedef uint8_t ioc_header_field_gre_t; + +#define IOC_NET_HEADER_FIELD_GRE_TYPE (1) +#define IOC_NET_HEADER_FIELD_GRE_ALL_FIELDS ((IOC_NET_HEADER_FIELD_GRE_TYPE << 1) - 1) + + +typedef uint8_t ioc_header_field_minencap_t; + +#define IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP (1) +#define IOC_NET_HEADER_FIELD_MINENCAP_DST_IP (IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 1) +#define IOC_NET_HEADER_FIELD_MINENCAP_TYPE (IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 2) +#define IOC_NET_HEADER_FIELD_MINENCAP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1) + + +typedef uint8_t ioc_header_field_ipsec_ah_t; + +#define IOC_NET_HEADER_FIELD_IPSEC_AH_SPI (1) +#define IOC_NET_HEADER_FIELD_IPSEC_AH_NH (IOC_NET_HEADER_FIELD_IPSEC_AH_SPI << 1) +#define IOC_NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1) + + +typedef uint8_t ioc_header_field_ipsec_esp_t; + +#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI (1) +#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM (IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI << 1) +#define IOC_NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1) + + +typedef uint8_t ioc_header_field_mpls_t; + +#define IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK (1) +#define IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS ((IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1) + + +typedef uint8_t ioc_header_field_macsec_t; + +#define IOC_NET_HEADER_FIELD_MACSEC_SECTAG (1) +#define IOC_NET_HEADER_FIELD_MACSEC_ALL_FIELDS ((IOC_NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1) + +typedef enum { + e_IOC_NET_HEADER_TYPE_NONE = 0, + e_IOC_NET_HEADER_TYPE_PAYLOAD, + e_IOC_NET_HEADER_TYPE_ETH, + e_IOC_NET_HEADER_TYPE_VLAN, + e_IOC_NET_HEADER_TYPE_IPv4, + e_IOC_NET_HEADER_TYPE_IPv6, + e_IOC_NET_HEADER_TYPE_TCP, + e_IOC_NET_HEADER_TYPE_UDP, + e_IOC_NET_HEADER_TYPE_IPHC, + e_IOC_NET_HEADER_TYPE_SCTP, + e_IOC_NET_HEADER_TYPE_SCTP_CHUNK_DATA, + e_IOC_NET_HEADER_TYPE_PPPoE, + e_IOC_NET_HEADER_TYPE_PPP, + e_IOC_NET_HEADER_TYPE_PPPMUX, + e_IOC_NET_HEADER_TYPE_PPPMUX_SUBFRAME, + e_IOC_NET_HEADER_TYPE_L2TPv2, + e_IOC_NET_HEADER_TYPE_L2TPv3_CTRL, + e_IOC_NET_HEADER_TYPE_L2TPv3_SESS, + e_IOC_NET_HEADER_TYPE_LLC, + e_IOC_NET_HEADER_TYPE_LLC_SNAP, + e_IOC_NET_HEADER_TYPE_NLPID, + e_IOC_NET_HEADER_TYPE_SNAP, + e_IOC_NET_HEADER_TYPE_MPLS, + e_IOC_NET_HEADER_TYPE_IPSEC_AH, + e_IOC_NET_HEADER_TYPE_IPSEC_ESP, + e_IOC_NET_HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */ + e_IOC_NET_HEADER_TYPE_MACSEC, /* moved */ + e_IOC_NET_HEADER_TYPE_GRE, + e_IOC_NET_HEADER_TYPE_MINENCAP, + e_IOC_NET_HEADER_TYPE_DCCP, + e_IOC_NET_HEADER_TYPE_ICMP, + e_IOC_NET_HEADER_TYPE_IGMP, + e_IOC_NET_HEADER_TYPE_ARP, + e_IOC_NET_HEADER_TYPE_CAPWAP, /* new */ + e_IOC_NET_HEADER_TYPE_CAPWAP_DTLS, /* new */ + e_IOC_NET_HEADER_TYPE_RFC2684, + e_IOC_NET_HEADER_TYPE_USER_DEFINED_L2, + e_IOC_NET_HEADER_TYPE_USER_DEFINED_L3, + e_IOC_NET_HEADER_TYPE_USER_DEFINED_L4, + e_IOC_NET_HEADER_TYPE_USER_DEFINED_SHIM1, + e_IOC_NET_HEADER_TYPE_USER_DEFINED_SHIM2, + e_IOC_NET_MAX_HEADER_TYPE_COUNT +} ioc_net_header_type; + + +#endif /* __NET_IOCTLS_H */ --- linux-3.13.0.orig/include/linux/fmd/integrations/integration_ioctls.h +++ linux-3.13.0/include/linux/fmd/integrations/integration_ioctls.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File integration_ioctls.h + + @Description External header file for Integration unit routines. +*//***************************************************************************/ + +#ifndef __INTG_IOCTLS_H +#define __INTG_IOCTLS_H + + +#define FM_IOC_TYPE_BASE (NCSW_IOC_TYPE_BASE+1) +#define FMT_IOC_TYPE_BASE (NCSW_IOC_TYPE_BASE+3) + + +#endif /* __INTG_IOCTLS_H */ --- linux-3.13.0.orig/include/linux/fmd/Peripherals/fm_test_ioctls.h +++ linux-3.13.0/include/linux/fmd/Peripherals/fm_test_ioctls.h @@ -0,0 +1,208 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_test_ioctls.h + + @Description FM Char device ioctls +*//***************************************************************************/ +#ifndef __FM_TEST_IOCTLS_H +#define __FM_TEST_IOCTLS_H + +#include "ioctls.h" + + +/**************************************************************************//** + @Group lnx_ioctl_FMT_grp Frame Manager Test Linux IOCTL API + + @Description FM-Test Linux ioctls definitions and enums + + @{ +*//***************************************************************************/ + +#define IOC_FMT_MAX_NUM_OF_PORTS 26 + +/**************************************************************************//** + @Collection TEST Parameters +*//***************************************************************************/ +/**************************************************************************//** + @Description: Name of the FM-Test chardev +*//***************************************************************************/ +#define DEV_FM_TEST_NAME "fm-test-port" + +#define DEV_FM_TEST_PORTS_MINOR_BASE 0 +#define DEV_FM_TEST_MAX_MINORS (DEV_FM_TEST_PORTS_MINOR_BASE + IOC_FMT_MAX_NUM_OF_PORTS) + +#define FMT_PORT_IOC_NUM(n) n +/* @} */ + +/**************************************************************************//** + @Group lnx_ioctl_FMT_lib_grp FM-Test library + + @Description TODO + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description TODO +*//***************************************************************************/ +typedef uint8_t ioc_fmt_xxx_t; + +#define FM_PRS_MAX 32 +#define FM_TIME_STAMP_MAX 8 + +/**************************************************************************//** + @Description FM Port buffer content description +*//***************************************************************************/ +typedef struct ioc_fmt_buff_context_t { + void *p_user_priv; + uint8_t fm_prs_res[FM_PRS_MAX]; + uint8_t fm_time_stamp[FM_TIME_STAMP_MAX]; +} ioc_fmt_buff_context_t; + +#if defined(__KERNEL__) && defined(CONFIG_COMPAT) +typedef struct ioc_fmt_compat_buff_context_t { + compat_uptr_t p_user_priv; + uint8_t fm_prs_res[FM_PRS_MAX]; + uint8_t fm_time_stamp[FM_TIME_STAMP_MAX]; +} ioc_fmt_compat_buff_context_t; +#endif + +/**************************************************************************//** + @Description Buffer descriptor +*//***************************************************************************/ +typedef struct ioc_fmt_buff_desc_t { + uint32_t qid; + void *p_data; + uint32_t size; + uint32_t status; + ioc_fmt_buff_context_t buff_context; +} ioc_fmt_buff_desc_t; + +#if defined(__KERNEL__) && defined(CONFIG_COMPAT) +typedef struct ioc_fmt_compat_buff_desc_t { + uint32_t qid; + compat_uptr_t p_data; + uint32_t size; + uint32_t status; + ioc_fmt_compat_buff_context_t buff_context; +} ioc_fmt_compat_buff_desc_t; +#endif + +/**************************************************************************//** + @Group lnx_ioctl_FMT_runtime_control_grp FM-Test Runtime Control Unit + + @Description TODO + @{ +*//***************************************************************************/ + +/** @} */ /* end of lnx_ioctl_FMT_runtime_control_grp group */ + + +/**************************************************************************//** + @Group lnx_ioctl_FMTP_lib_grp FM-Port-Test library + + @Description TODO + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description FM-Test FM port type +*//***************************************************************************/ +typedef enum ioc_fmt_port_type { + e_IOC_FMT_PORT_T_RXTX, /**< Standard port */ + e_IOC_FMT_PORT_T_OP, /**< Offline-parsing port */ +} ioc_fmt_port_type; + +/**************************************************************************//** + @Description TODO +*//***************************************************************************/ +typedef struct ioc_fmt_port_param_t { + uint8_t fm_id; + ioc_fmt_port_type fm_port_type; + uint8_t fm_port_id; + uint32_t num_tx_queues; +} ioc_fmt_port_param_t; + + +/**************************************************************************//** + @Function FMT_PORT_IOC_INIT + + @Description TODO + + @Param[in] ioc_fmt_port_param_t TODO + + @Cautions Allowed only after the FM equivalent port is already initialized. +*//***************************************************************************/ +#define FMT_PORT_IOC_INIT _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(0), ioc_fmt_port_param_t) + +/**************************************************************************//** + @Function FMT_PORT_IOC_SET_DIAG_MODE + + @Description TODO + + @Param[in] ioc_diag_mode TODO + + @Cautions Allowed only following FMT_PORT_IOC_INIT(). +*//***************************************************************************/ +#define FMT_PORT_IOC_SET_DIAG_MODE _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(1), ioc_diag_mode) + +/**************************************************************************//** + @Function FMT_PORT_IOC_SET_IP_HEADER_MANIP + + @Description Set IP header manipulations for this port. + + @Param[in] int 1 to enable; 0 to disable + + @Cautions Allowed only following FMT_PORT_IOC_INIT(). +*//***************************************************************************/ +#define FMT_PORT_IOC_SET_IP_HEADER_MANIP _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(2), int) + +/**************************************************************************//** + @Function FMT_PORT_IOC_SET_DPAECHO_MODE + + @Description Set DPA in echo mode - all frame are sent back. + + @Param[in] int 1 to enable; 0 to disable + + @Cautions Allowed only following FMT_PORT_IOC_INIT(). +*//***************************************************************************/ +#define FMT_PORT_IOC_SET_DPAECHO_MODE _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(3), int) + +/** @} */ /* end of lnx_ioctl_FMTP_lib_grp group */ +/** @} */ /* end of lnx_ioctl_FMT_lib_grp group */ +/** @} */ /* end of lnx_ioctl_FMT_grp */ + + +#endif /* __FM_TEST_IOCTLS_H */ --- linux-3.13.0.orig/include/linux/fmd/Peripherals/fm_ioctls.h +++ linux-3.13.0/include/linux/fmd/Peripherals/fm_ioctls.h @@ -0,0 +1,322 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_ioctls.h + + @Description FM Char device ioctls +*//***************************************************************************/ +#ifndef __FM_IOCTLS_H +#define __FM_IOCTLS_H + + +/**************************************************************************//** + @Group lnx_ioctl_FM_grp Frame Manager Linux IOCTL API + + @Description FM Linux ioctls definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection FM IOCTL device ('/dev') definitions +*//***************************************************************************/ +#define DEV_FM_NAME "fm" /**< Name of the FM chardev */ + +#define DEV_FM_MINOR_BASE 0 +#define DEV_FM_PCD_MINOR_BASE (DEV_FM_MINOR_BASE + 1) /*/dev/fmx-pcd */ +#define DEV_FM_OH_PORTS_MINOR_BASE (DEV_FM_PCD_MINOR_BASE + 1) /*/dev/fmx-port-ohy */ +#define DEV_FM_RX_PORTS_MINOR_BASE (DEV_FM_OH_PORTS_MINOR_BASE + FM_MAX_NUM_OF_OH_PORTS) /*/dev/fmx-port-rxy */ +#define DEV_FM_TX_PORTS_MINOR_BASE (DEV_FM_RX_PORTS_MINOR_BASE + FM_MAX_NUM_OF_RX_PORTS) /*/dev/fmx-port-txy */ +#define DEV_FM_MAX_MINORS (DEV_FM_TX_PORTS_MINOR_BASE + FM_MAX_NUM_OF_TX_PORTS) + + +#define FM_IOC_NUM(n) n +#define FM_PCD_IOC_NUM(n) (n+20) +#define FM_PORT_IOC_NUM(n) (n+50) +/* @} */ + +#define IOC_FM_MAX_NUM_OF_PORTS 64 + +/**************************************************************************//** + @Collection FM Frame error +*//***************************************************************************/ +typedef uint32_t ioc_fm_port_frame_err_select_t; /**< typedef for defining Frame Descriptor errors */ + +#define IOC_FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT 0x04000000 /**< Offline parsing only! Unsupported Format */ +#define IOC_FM_PORT_FRM_ERR_LENGTH 0x02000000 /**< Offline parsing only! Length Error */ +#define IOC_FM_PORT_FRM_ERR_DMA 0x01000000 /**< DMA Data error */ +#ifdef FM_CAPWAP_SUPPORT +#define IOC_FM_PORT_FRM_ERR_NON_FM 0x00400000 /**< non FMan error; probably come from SEC chained to FM */ +#endif /* FM_CAPWAP_SUPPORT */ +#define IOC_FM_PORT_FRM_ERR_PHYSICAL 0x00080000 /**< Rx FIFO overflow, FCS error, code error, running disparity + error (SGMII and TBI modes), FIFO parity error. PHY + Sequence error, PHY error control character detected. */ +#define IOC_FM_PORT_FRM_ERR_SIZE 0x00040000 /**< Frame too long OR Frame size exceeds max_length_frame */ +#define IOC_FM_PORT_FRM_ERR_CLS_DISCARD 0x00020000 /**< classification discard */ +#define IOC_FM_PORT_FRM_ERR_EXTRACTION 0x00008000 /**< Extract Out of Frame */ +#define IOC_FM_PORT_FRM_ERR_NO_SCHEME 0x00004000 /**< No Scheme Selected */ +#define IOC_FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW 0x00002000 /**< No Scheme Selected */ +#define IOC_FM_PORT_FRM_ERR_COLOR_YELLOW 0x00000400 /**< */ +#define IOC_FM_PORT_FRM_ERR_COLOR_RED 0x00000800 /**< */ +#define IOC_FM_PORT_FRM_ERR_ILL_PLCR 0x00000200 /**< Illegal Policer Profile selected */ +#define IOC_FM_PORT_FRM_ERR_PLCR_FRAME_LEN 0x00000100 /**< Illegal Policer Profile selected */ +#define IOC_FM_PORT_FRM_ERR_PRS_TIMEOUT 0x00000080 /**< Parser Time out Exceed */ +#define IOC_FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT 0x00000040 /**< Invalid Soft Parser instruction */ +#define IOC_FM_PORT_FRM_ERR_PRS_HDR_ERR 0x00000020 /**< Header error was identified during parsing */ +#define IOC_FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED 0x00000008 /**< Frame parsed beyind 256 first bytes */ +#define IOC_FM_PORT_FRM_ERR_PROCESS_TIMEOUT 0x00000001 /**< FPT Frame Processing Timeout Exceeded */ +/* @} */ + + +/**************************************************************************//** + @Description enum for defining port types + (must match enum e_FmPortType defined in fm_ext.h) +*//***************************************************************************/ +typedef enum ioc_fm_port_type { + e_IOC_FM_PORT_TYPE_OFFLINE_PARSING, /**< Offline parsing port (id's: 0-6, share id's with + host command, so must have exclusive id) */ + e_IOC_FM_PORT_TYPE_HOST_COMMAND, /**< Host command port (id's: 0-6, share id's with + offline parsing ports, so must have exclusive id) */ + e_IOC_FM_PORT_TYPE_RX, /**< 1G Rx port (id's: 0-3) */ + e_IOC_FM_PORT_TYPE_RX_10G, /**< 10G Rx port (id's: 0) */ + e_IOC_FM_PORT_TYPE_TX, /**< 1G Tx port (id's: 0-3) */ + e_IOC_FM_PORT_TYPE_TX_10G, /**< 10G Tx port (id's: 0) */ + e_IOC_FM_PORT_TYPE_DUMMY +} ioc_fm_port_type; + + +/**************************************************************************//** + @Group lnx_ioctl_FM_lib_grp FM library + + @Description FM API functions, definitions and enums + The FM module is the main driver module and is a mandatory module + for FM driver users. Before any further module initialization, + this module must be initialized. + The FM is a "single-tone" module. It is responsible of the common + HW modules: FPM, DMA, common QMI, common BMI initializations and + run-time control routines. This module must be initialized always + when working with any of the FM modules. + NOTE - We assumes that the FML will be initialize only by core No. 0! + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description FM Exceptions +*//***************************************************************************/ +typedef enum ioc_fm_exceptions { + e_IOC_FM_EX_DMA_BUS_ERROR, /**< DMA bus error. */ + e_IOC_FM_EX_DMA_READ_ECC, /**< Read Buffer ECC error */ + e_IOC_FM_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC error on system side */ + e_IOC_FM_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side */ + e_IOC_FM_EX_FPM_STALL_ON_TASKS , /**< Stall of tasks on FPM */ + e_IOC_FM_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */ + e_IOC_FM_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */ + e_IOC_FM_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */ + e_IOC_FM_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occured on QMI */ + e_IOC_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< Dequeu from unknown port id */ + e_IOC_FM_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */ + e_IOC_FM_EX_BMI_PIPELINE_ECC, /**< Pipeline Table ECC Error */ + e_IOC_FM_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics Count RAM ECC Error Enable */ + e_IOC_FM_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */ + e_IOC_FM_EX_IRAM_ECC, /**< Double bit ECC occured on IRAM*/ + e_IOC_FM_EX_MURAM_ECC /**< Double bit ECC occured on MURAM*/ +} ioc_fm_exceptions; + + +/**************************************************************************//** + @Group lnx_ioctl_FM_runtime_control_grp FM Runtime Control Unit + + @Description FM Runtime control unit API functions, definitions and enums. + The FM driver provides a set of control routines for each module. + These routines may only be called after the module was fully + initialized (both configuration and initialization routines were + called). They are typically used to get information from hardware + (status, counters/statistics, revision etc.), to modify a current + state or to force/enable a required action. Run-time control may + be called whenever necessary and as many times as needed. + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection General FM defines. + *//***************************************************************************/ +#define IOC_FM_MAX_NUM_OF_VALID_PORTS (FM_MAX_NUM_OF_OH_PORTS + \ + FM_MAX_NUM_OF_1G_RX_PORTS + \ + FM_MAX_NUM_OF_10G_RX_PORTS + \ + FM_MAX_NUM_OF_1G_TX_PORTS + \ + FM_MAX_NUM_OF_10G_TX_PORTS) +/* @} */ + +/**************************************************************************//** + @Description Structure for Port bandwidth requirement. Port is identified + by type and relative id. + (must be identical to t_FmPortBandwidth defined in fm_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_bandwidth_t { + ioc_fm_port_type type; /**< FM port type */ + uint8_t relativePortId; /**< Type relative port id */ + uint8_t bandwidth; /**< bandwidth - (in term of percents) */ +} ioc_fm_port_bandwidth_t; + +/**************************************************************************//** + @Description A Structure containing an array of Port bandwidth requirements. + The user should state the ports requiring bandwidth in terms of + percentage - i.e. all port's bandwidths in the array must add + up to 100. + (must be identical to t_FmPortsBandwidthParams defined in fm_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_bandwidth_params { + uint8_t numOfPorts; + /**< num of ports listed in the array below */ +/*TODO:Andy64 BUG*/ + ioc_fm_port_bandwidth_t portsBandwidths[IOC_FM_MAX_NUM_OF_VALID_PORTS]; + /**< for each port, it's bandwidth (all port's + bandwidths must add up to 100.*/ +} ioc_fm_port_bandwidth_params; + +/**************************************************************************//** + @Description enum for defining FM counters +*//***************************************************************************/ +typedef enum ioc_fm_counters { + e_IOC_FM_COUNTERS_ENQ_TOTAL_FRAME, /**< QMI total enqueued frames counter */ + e_IOC_FM_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI total dequeued frames counter */ + e_IOC_FM_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */ + e_IOC_FM_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */ + e_IOC_FM_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */ + e_IOC_FM_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */ + e_IOC_FM_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI dequeue from default queue counter */ + e_IOC_FM_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI dequeue from FQ context counter */ + e_IOC_FM_COUNTERS_DEQ_FROM_FD, /**< QMI dequeue from FD command field counter */ + e_IOC_FM_COUNTERS_DEQ_CONFIRM, /**< QMI dequeue confirm counter */ + e_IOC_FM_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT, /**< DMA semaphor reject due to full entry counter */ + e_IOC_FM_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT, /**< DMA semaphor reject due to full CAM queue counter */ + e_IOC_FM_COUNTERS_SEMAPHOR_SYNC_REJECT /**< DMA semaphor reject due to sync counter */ +} ioc_fm_counters; + +typedef struct ioc_fm_obj_t { + void *obj; +} ioc_fm_obj_t; + +/**************************************************************************//** + @Description structure for returning revision information +*//***************************************************************************/ +typedef struct ioc_fm_revision_info_t { + uint8_t major; /**< Major revision */ + uint8_t minor; /**< Minor revision */ +} ioc_fm_revision_info_t; + +/**************************************************************************//** + @Description structure for FM counters +*//***************************************************************************/ +typedef struct ioc_fm_counters_params_t { + ioc_fm_counters cnt; /**< The requested counter */ + uint32_t val; /**< The requested value to get/set from/into the counter */ +} ioc_fm_counters_params_t; + +/**************************************************************************//** + @Function FM_IOC_SET_PORTS_BANDWIDTH + + @Description Sets relative weights between ports when accessing common resources. + + @Param[in] ioc_fm_port_bandwidth_params Port bandwidth percentages, + their sum must equal 100. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +#define FM_IOC_SET_PORTS_BANDWIDTH _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(2), ioc_fm_port_bandwidth_params) + +/**************************************************************************//** + @Function FM_IOC_GET_REVISION + + @Description Returns the FM revision + + @Param[out] ioc_fm_revision_info_t A structure of revision information parameters. + + @Return None. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +#define FM_IOC_GET_REVISION _IOR(FM_IOC_TYPE_BASE, FM_IOC_NUM(3), ioc_fm_revision_info_t) + +/**************************************************************************//** + @Function FM_IOC_GET_COUNTER + + @Description Reads one of the FM counters. + + @Param[in,out] ioc_fm_counters_params_t The requested counter parameters. + + @Return Counter's current value. + + @Cautions Allowed only following FM_Init(). + Note that it is user's responsibilty to call this routine only + for enabled counters, and there will be no indication if a + disabled counter is accessed. +*//***************************************************************************/ +#define FM_IOC_GET_COUNTER _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(4), ioc_fm_counters_params_t) + +/**************************************************************************//** + @Function FM_IOC_SET_COUNTER + + @Description Sets a value to an enabled counter. Use "0" to reset the counter. + + @Param[in] ioc_fm_counters_params_t The requested counter parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +#define FM_IOC_SET_COUNTER _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(5), ioc_fm_counters_params_t) + +/**************************************************************************//** + @Function FM_IOC_FORCE_INTR + + @Description Causes an interrupt event on the requested source. + + @Param[in] ioc_fm_exceptions An exception to be forced. + + @Return E_OK on success; Error code if the exception is not enabled, + or is not able to create interrupt. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +#define FM_IOC_FORCE_INTR _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(6), ioc_fm_exceptions) + +/** @} */ /* end of lnx_ioctl_FM_runtime_control_grp group */ +/** @} */ /* end of lnx_ioctl_FM_lib_grp group */ +/** @} */ /* end of lnx_ioctl_FM_grp */ + + +#endif /* __FM_IOCTLS_H */ --- linux-3.13.0.orig/include/linux/fmd/Peripherals/fm_pcd_ioctls.h +++ linux-3.13.0/include/linux/fmd/Peripherals/fm_pcd_ioctls.h @@ -0,0 +1,1538 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_pcd_ioctls.h + + @Description FM PCD ... +*//***************************************************************************/ +#ifndef __FM_PCD_IOCTLS_H +#define __FM_PCD_IOCTLS_H + +#include "net_ioctls.h" +#include "fm_ioctls.h" + + +/**************************************************************************//** + @Group lnx_ioctl_FM_grp Frame Manager Linux IOCTL API + + @Description FM Linux ioctls definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group lnx_ioctl_FM_PCD_grp FM PCD + + @Description FM PCD API functions, definitions and enums + + The FM PCD module is responsible for the initialization of all + global classifying FM modules. This includes the parser general and + common registers, the key generator global and common registers, + and the Policer global and common registers. + In addition, the FM PCD SW module will initialize all required + key generator schemes, coarse classification flows, and Policer + profiles. When An FM module is configured to work with one of these + entities, it will register to it using the FM PORT API. The PCD + module will manage the PCD resources - i.e. resource management of + Keygen schemes, etc. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection General PCD defines +*//***************************************************************************/ +#define IOC_FM_PCD_MAX_NUM_OF_PRIVATE_HDRS 2 /**< Number of units/headers saved for user */ + +#define IOC_FM_PCD_PRS_NUM_OF_HDRS 16 /**< Number of headers supported by HW parser */ + +#ifdef CONFIG_FMAN_P1023 +#define IOC_FM_PCD_KG_NUM_OF_SCHEMES 16 /**< Total number of KG schemes */ +#else +#define IOC_FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */ +#endif +#define IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS (32 - IOC_FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) + /**< Maximum number of netenv distinction units */ +#ifdef CONFIG_FMAN_P1023 +#define IOC_FM_PCD_MAX_NUM_OF_OPTIONS 7 /**< Maximum number of netenv distinction units options */ +#else +#define IOC_FM_PCD_MAX_NUM_OF_OPTIONS 8 /**< Maximum number of netenv distinction units options */ +#endif +#define IOC_FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS 4 /**< Maximum number of interchangeable headers in a distinction unit */ +#define IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS 8 /**< Total number of generic KG registers */ +#define IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY 35 /**< Max number allowed on any configuration. + For reason of HW implemetation, in most + cases less than this will be allowed. The + driver will return error in initialization + time if resource is overused. */ +#ifdef CONFIG_FMAN_P1023 +#define IOC_FM_PCD_MAX_NUM_OF_CLS_PLANS 128 /**< Number of classification plan entries. */ +#else +#define IOC_FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */ +#endif +#define IOC_FM_PCD_KG_NUM_OF_EXTRACT_MASKS 4 /**< Total number of masks allowed on KG extractions. */ +#define IOC_FM_PCD_KG_NUM_OF_DEFAULT_GROUPS 16 /**< Number of default value logical groups */ + +#define IOC_FM_PCD_PRS_NUM_OF_LABELS 32 /**< Max number of SW parser label */ +/* @} */ + +/**************************************************************************//** + @Group lnx_ioctl_FM_PCD_Runtime_grp FM PCD Runtime Unit + + @Description FM PCD Runtime Unit + + The runtime control allows creation of PCD infrastructure modules + such as Network Environment Characteristics, Classification Plan + Groups and Coarse Classification Trees. + It also allows on-the-fly initialization, modification and removal + of PCD modules such as Keygen schemes, coarse classification nodes + and Policer profiles. + + + In order to explain the programming model of the PCD driver interface + a few terms should be explained, and will be used below. + * Distinction Header - One of the 16 protocols supported by the FM parser, + or one of the shim headers (1-3). May be a header with a special + option (see below). + * Interchangeable Headers Group- This is a group of Headers recognized + by either one of them. For example, if in a specific context the user + chooses to treat IPv4 and IPV6 in the same way, they may create an + Interchangable Headers Unit consisting of these 2 headers. + * A Distinction Unit - a Distinction Header or an Interchangeable Headers + Group. + * Header with special option - applies to ethernet, mpls, vlan, ipv4 and + ipv6, includes multicast, broadcast and other protocol specific options. + In terms of hardware it relates to the options available in the classification + plan. + * Network Environment Characteristics - a set of Distinction Units that define + the total recognizable header selection for a certain environment. This is + NOT the list of all headers that will ever appear in a flow, but rather + everything that needs distinction in a flow, where distinction is made by keygen + schemes and coarse classification action descriptors. + + The PCD runtime modules initialization is done in stages. The first stage after + initializing the PCD module itself is to establish a Network Flows Environment + Definition. The application may choose to establish one or more such environments. + Later, when needed, the application will have to state, for some of its modules, + to which single environment it belongs. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description PCD counters + (must match enum e_FmPcdCounters defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef enum ioc_fm_pcd_counters { + e_IOC_FM_PCD_KG_COUNTERS_TOTAL, /**< Policer counter */ + e_IOC_FM_PCD_PLCR_COUNTERS_YELLOW, /**< Policer counter */ + e_IOC_FM_PCD_PLCR_COUNTERS_RED, /**< Policer counter */ + e_IOC_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, /**< Policer counter */ + e_IOC_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, /**< Policer counter */ + e_IOC_FM_PCD_PLCR_COUNTERS_TOTAL, /**< Policer counter */ + e_IOC_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, /**< Policer counter */ + e_IOC_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, /**< Parser counter */ + e_IOC_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, /**< MURAM counter */ + e_IOC_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, /**< MURAM counter */ + e_IOC_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, /**< MURAM counter */ + e_IOC_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, /**< MURAM counter */ + e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES /**< FPM counter */ +} ioc_fm_pcd_counters; + +/**************************************************************************//** + @Description PCD interrupts + (must match enum e_FmPcdExceptions defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef enum ioc_fm_pcd_exceptions { + e_IOC_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, /**< Keygen ECC error */ + e_IOC_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, /**< Read Buffer ECC error */ + e_IOC_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, /**< Write Buffer ECC error on system side */ + e_IOC_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, /**< Write Buffer ECC error on FM side */ + e_IOC_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, /**< Self init complete */ + e_IOC_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, /**< Atomic action complete */ + e_IOC_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, /**< Parser ECC error */ + e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC /**< Parser single ECC */ +} ioc_fm_pcd_exceptions; + +/**************************************************************************//** + @Description structure for FM counters +*//***************************************************************************/ +typedef struct ioc_fm_pcd_counters_params_t { + ioc_fm_pcd_counters cnt; /**< The requested counter */ + uint32_t val; /**< The requested value to get/set from/into the counter */ +} ioc_fm_pcd_counters_params_t; + +/**************************************************************************//** + @Description structure for FM exception definitios +*//***************************************************************************/ +typedef struct ioc_fm_pcd_exception_params_t { + ioc_fm_pcd_exceptions exception; /**< The requested exception */ + bool enable; /**< TRUE to enable interrupt, FALSE to mask it. */ +} ioc_fm_pcd_exception_params_t; + +/**************************************************************************//** + @Description A structure for sw parser labels + (must be identical to struct t_FmPcdPrsLabelParams defined in fm_pcd_ext.h) + *//***************************************************************************/ +typedef struct ioc_fm_pcd_prs_label_params_t { + uint32_t instruction_offset; /**< SW parser label instruction offset (2 bytes + resolution), relative to Parser RAM. */ + ioc_net_header_type hdr; /**< The existance of this header will envoke + the sw parser code. */ + uint8_t index_per_hdr; /**< Normally 0, if more than one sw parser + attachments for the same header, use this + index to distinguish between them. */ +} ioc_fm_pcd_prs_label_params_t; + +/**************************************************************************//** + @Description A structure for sw parser + (must be identical to struct t_FmPcdPrsSwParams defined in fm_pcd_ext.h) + *//***************************************************************************/ +typedef struct ioc_fm_pcd_prs_sw_params_t { + bool override; /**< FALSE to invoke a check that nothing else + was loaded to this address, including + internal patched. + TRUE to override any existing code.*/ + uint32_t size; /**< SW parser code size */ + uint16_t base; /**< SW parser base (in instruction counts! + muat be larger than 0x20)*/ + uint8_t *p_code; /**< SW parser code */ + uint32_t sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS]; + /**< SW parser data (parameters) */ + uint8_t num_of_labels; /**< Number of labels for SW parser. */ + ioc_fm_pcd_prs_label_params_t labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS]; + /**< SW parser labels table, containing n + umOfLabels entries */ +} ioc_fm_pcd_prs_sw_params_t; + +/**************************************************************************//** + @Description A structure to set the a KeyGen default value + *//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_dflt_value_params_t { + uint8_t valueId; /**< 0,1 - one of 2 global default values */ + uint32_t value; /**< The requested default value */ +} ioc_fm_pcd_kg_dflt_value_params_t; + + +/**************************************************************************//** + @Function FM_PCD_IOC_ENABLE + + @Description This routine should be called after PCD is initialized for enabling all + PCD engines according to their existing configuration. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init() and when PCD is disabled. +*//***************************************************************************/ +#define FM_PCD_IOC_ENABLE _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(1)) + +/**************************************************************************//** + @Function FM_PCD_IOC_DISABLE + + @Description This routine may be called when PCD is enabled in order to + disable all PCD engines. It may be called + only when none of the ports in the system are using the PCD. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init() and when PCD is enabled. +*//***************************************************************************/ +#define FM_PCD_IOC_DISABLE _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(2)) + + /**************************************************************************//** + @Function FM_PCD_IOC_PRS_LOAD_SW + + @Description This routine may be called only when all ports in the + system are actively using the classification plan scheme. + In such cases it is recommended in order to save resources. + The driver automatically saves 8 classification plans for + ports that do NOT use the classification plan mechanism, to + avoid this (in order to save those entries) this routine may + be called. + + @Param[in] ioc_fm_pcd_prs_sw_params_t A pointer to the image of the software parser code. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init() and when PCD is disabled. +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_PRS_LOAD_SW_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(3), ioc_compat_fm_pcd_prs_sw_params_t) +#endif +#define FM_PCD_IOC_PRS_LOAD_SW _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(3), ioc_fm_pcd_prs_sw_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_KG_SET_DFLT_VALUE + + @Description Calling this routine sets a global default value to be used + by the keygen when parser does not recognize a required + field/header. + By default default values are 0. + + @Param[in] ioc_fm_pcd_kg_dflt_value_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init() and when PCD is disabled. +*//***************************************************************************/ +#define FM_PCD_IOC_KG_SET_DFLT_VALUE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(6), ioc_fm_pcd_kg_dflt_value_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING + + @Description Calling this routine allows the keygen to access data past + the parser finishing point. + + @Param[in] uint8_t payload-offset; the number of bytes beyond the parser location. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init() and when PCD is disabled. + +*//***************************************************************************/ +#define FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(7), uint8_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_SET_EXCEPTION + + @Description Calling this routine enables/disables PCD interrupts. + + @Param[in] h_FmPcd FM PCD module descriptor. + @Param[in] ioc_fm_pcd_exception_params_t The exception to be selected. + @Param[in] enable TRUE to enable interrupt, FALSE to mask it. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init(). +*//***************************************************************************/ +#define FM_PCD_IOC_SET_EXCEPTION _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(8), ioc_fm_pcd_exception_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_GET_COUNTER + + @Description Reads one of the FM PCD counters. + + @Param[in,out] ioc_fm_pcd_counters_params_t The requested counter parameters. + + @Return Counter's current value. + + @Cautions Allowed only following FM_PCD_Init(). + Note that it is user's responsibilty to call this routine only + for enabled counters, and there will be no indication if a + disabled counter is accessed. +*//***************************************************************************/ +#define FM_PCD_IOC_GET_COUNTER _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(9), ioc_fm_pcd_counters_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_SET_COUNTER + + @Description Sets a value to an enabled counter. Use "0" to reset the counter. + + @Param[in] ioc_fm_pcd_counters_params_t The requested counter parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init(). +*//***************************************************************************/ +#define FM_PCD_IOC_SET_COUNTER _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(10), ioc_fm_pcd_counters_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_FORCE_INTR + + @Description Causes an interrupt event on the requested source. + + @Param[in] ioc_fm_pcd_exceptions An exception to be forced. + + @Return E_OK on success; Error code if the exception is not enabled, + or is not able to create interrupt. + + @Cautions Allowed only following PCD_Init(). +*//***************************************************************************/ +#define FM_PCD_IOC_FORCE_INTR _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(11), ioc_fm_pcd_exceptions) + +/**************************************************************************//** + @Collection Definitions of coarse classification + parameters as required by keygen (when coarse classification + is the next engine after this scheme). +*//***************************************************************************/ +#define IOC_FM_PCD_MAX_NUM_OF_CC_NODES 255 +#define IOC_FM_PCD_MAX_NUM_OF_CC_TREES 8 +#define IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS 16 +#define IOC_FM_PCD_MAX_NUM_OF_CC_UNITS 4 +#define IOC_FM_PCD_MAX_NUM_OF_KEYS 256 +#define IOC_FM_PCD_MAX_SIZE_OF_KEY 56 +#define IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP 16 +/* @} */ + +/**************************************************************************//** + @Collection A set of definitions to allow protocol + special option description. +*//***************************************************************************/ +typedef uint32_t ioc_protocol_opt_t; /**< A general type to define a protocol option. */ + +typedef ioc_protocol_opt_t ioc_eth_protocol_opt_t; /**< Ethernet protocol options. */ +#define IOC_ETH_BROADCAST 0x80000000 /**< Ethernet Broadcast. */ +#define IOC_ETH_MULTICAST 0x40000000 /**< Ethernet Multicast. */ + +typedef ioc_protocol_opt_t ioc_vlan_protocol_opt_t; /**< Vlan protocol options. */ +#define IOC_VLAN_STACKED 0x20000000 /**< Vlan Stacked. */ + +typedef ioc_protocol_opt_t ioc_mpls_protocol_opt_t; /**< MPLS protocol options. */ +#define IOC_MPLS_STACKED 0x10000000 /**< MPLS Stacked. */ + +typedef ioc_protocol_opt_t ioc_ipv4_protocol_opt_t; /**< IPv4 protocol options. */ +#define IOC_IPV4_BROADCAST_1 0x08000000 /**< IPv4 Broadcast. */ +#define IOC_IPV4_MULTICAST_1 0x04000000 /**< IPv4 Multicast. */ +#define IOC_IPV4_UNICAST_2 0x02000000 /**< Tunneled IPv4 - Unicast. */ +#define IOC_IPV4_MULTICAST_BROADCAST_2 0x01000000 /**< Tunneled IPv4 - Broadcast/Multicast. */ + +typedef ioc_protocol_opt_t ioc_ipv6_protocol_opt_t; /**< IPv6 protocol options. */ +#define IOC_IPV6_MULTICAST_1 0x00800000 /**< IPv6 Multicast. */ +#define IOC_IPV6_UNICAST_2 0x00400000 /**< Tunneled IPv6 - Unicast. */ +#define IOC_IPV6_MULTICAST_2 0x00200000 /**< Tunneled IPv6 - Multicast. */ +/* @} */ + +/**************************************************************************//** + @Description All PCD engines + (must match enum e_FmPcdEngine defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef enum ioc_fm_pcd_engine { + e_IOC_FM_PCD_INVALID = 0, /**< Invalid PCD engine indicated*/ + e_IOC_FM_PCD_DONE, /**< No PCD Engine indicated */ + e_IOC_FM_PCD_KG, /**< Keygen indicated */ + e_IOC_FM_PCD_CC, /**< Coarse classification indicated */ + e_IOC_FM_PCD_PLCR, /**< Policer indicated */ + e_IOC_FM_PCD_PRS /**< Parser indicated */ +} ioc_fm_pcd_engine; + +/**************************************************************************//** + @Description An enum for selecting extraction by header types + (must match enum e_FmPcdExtractByHdrType defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef enum ioc_fm_pcd_extract_by_hdr_type { + e_IOC_FM_PCD_EXTRACT_FROM_HDR, /**< Extract bytes from header */ + e_IOC_FM_PCD_EXTRACT_FROM_FIELD, /**< Extract bytes from header field */ + e_IOC_FM_PCD_EXTRACT_FULL_FIELD /**< Extract a full field */ +} ioc_fm_pcd_extract_by_hdr_type; + +/**************************************************************************//** + @Description An enum for selecting extraction source + (when it is not the header) + (must match enum e_FmPcdExtractFrom defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef enum ioc_fm_pcd_extract_from { + e_IOC_FM_PCD_EXTRACT_FROM_FRAME_START, /**< KG & CC: Extract from beginning of frame */ + e_IOC_FM_PCD_EXTRACT_FROM_DFLT_VALUE, /**< KG only: Extract from a default value */ + e_IOC_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE, /**< KG only: Extract from the point where parsing had finished */ + e_IOC_FM_PCD_EXTRACT_FROM_KEY, /**< CC only: Field where saved KEY */ + e_IOC_FM_PCD_EXTRACT_FROM_HASH, /**< CC only: Field where saved HASH */ + e_IOC_FM_PCD_EXTRACT_FROM_PARSE_RESULT, /**< KG & CC: Extract from the parser result */ + e_IOC_FM_PCD_EXTRACT_FROM_ENQ_FQID, /**< KG & CC: Extract from enqueue FQID */ + e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID /**< CC only: Field where saved Dequeue FQID */ +} ioc_fm_pcd_extract_from; + +/**************************************************************************//** + @Description An enum for selecting extraction type +*//***************************************************************************/ +typedef enum ioc_fm_pcd_extract_type { + e_IOC_FM_PCD_EXTRACT_BY_HDR, /**< Extract according to header */ + e_IOC_FM_PCD_EXTRACT_NON_HDR, /**< Extract from data that is not the header */ + e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO /**< Extract private info as specified by user */ +} ioc_fm_pcd_extract_type; + +/**************************************************************************//** + @Description An enum for selecting a default +*//***************************************************************************/ +typedef enum ioc_fm_pcd_kg_extract_dflt_select { + e_IOC_FM_PCD_KG_DFLT_GBL_0, /**< Default selection is KG register 0 */ + e_IOC_FM_PCD_KG_DFLT_GBL_1, /**< Default selection is KG register 1 */ + e_IOC_FM_PCD_KG_DFLT_PRIVATE_0, /**< Default selection is a per scheme register 0 */ + e_IOC_FM_PCD_KG_DFLT_PRIVATE_1, /**< Default selection is a per scheme register 1 */ + e_IOC_FM_PCD_KG_DFLT_ILLEGAL /**< Illegal selection */ +} ioc_fm_pcd_kg_extract_dflt_select; + +/**************************************************************************//** + @Description An enum defining all default groups - + each group shares a default value, one of 4 user + initialized values. +*//***************************************************************************/ +typedef enum ioc_fm_pcd_kg_known_fields_dflt_types { + e_IOC_FM_PCD_KG_MAC_ADDR, /**< MAC Address */ + e_IOC_FM_PCD_KG_TCI, /**< TCI field */ + e_IOC_FM_PCD_KG_ENET_TYPE, /**< ENET Type */ + e_IOC_FM_PCD_KG_PPP_SESSION_ID, /**< PPP Session id */ + e_IOC_FM_PCD_KG_PPP_PROTOCOL_ID, /**< PPP Protocol id */ + e_IOC_FM_PCD_KG_MPLS_LABEL, /**< MPLS label */ + e_IOC_FM_PCD_KG_IP_ADDR, /**< IP addr */ + e_IOC_FM_PCD_KG_PROTOCOL_TYPE, /**< Protocol type */ + e_IOC_FM_PCD_KG_IP_TOS_TC, /**< TOS or TC */ + e_IOC_FM_PCD_KG_IPV6_FLOW_LABEL, /**< IPV6 flow label */ + e_IOC_FM_PCD_KG_IPSEC_SPI, /**< IPSEC SPI */ + e_IOC_FM_PCD_KG_L4_PORT, /**< L4 Port */ + e_IOC_FM_PCD_KG_TCP_FLAG, /**< TCP Flag */ + e_IOC_FM_PCD_KG_GENERIC_FROM_DATA, /**< grouping implemented by sw, + any data extraction that is not the full + field described above */ + e_IOC_FM_PCD_KG_GENERIC_FROM_DATA_NO_V, /**< grouping implemented by sw, + any data extraction without validation */ + e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA /**< grouping implemented by sw, + extraction from parser result or + direct use of default value */ +} ioc_fm_pcd_kg_known_fields_dflt_types; + +/**************************************************************************//** + @Description enum for defining header index when headers may repeat +*//***************************************************************************/ +typedef enum ioc_fm_pcd_hdr_index { + e_IOC_FM_PCD_HDR_INDEX_NONE = 0, /**< used when multiple headers not used, also + to specify regular IP (not tunneled). */ + e_IOC_FM_PCD_HDR_INDEX_1, /**< may be used for VLAN, MPLS, tunneled IP */ + e_IOC_FM_PCD_HDR_INDEX_2, /**< may be used for MPLS, tunneled IP */ + e_IOC_FM_PCD_HDR_INDEX_3, /**< may be used for MPLS */ + e_IOC_FM_PCD_HDR_INDEX_LAST = 0xFF /**< may be used for VLAN, MPLS */ +} ioc_fm_pcd_hdr_index; + +/**************************************************************************//** + @Description A structure for selcting the policer profile functional type +*//***************************************************************************/ +typedef enum ioc_fm_pcd_profile_type_selection { + e_IOC_FM_PCD_PLCR_PORT_PRIVATE, /**< Port dedicated profile */ + e_IOC_FM_PCD_PLCR_SHARED /**< Shared profile (shared within partition) */ +} ioc_fm_pcd_profile_type_selection; + +/**************************************************************************//** + @Description A structure for selcting the policer profile algorithem +*//***************************************************************************/ +typedef enum ioc_fm_pcd_plcr_algorithm_selection { + e_IOC_FM_PCD_PLCR_PASS_THROUGH, /**< Policer pass through */ + e_IOC_FM_PCD_PLCR_RFC_2698, /**< Policer algorythm RFC 2698 */ + e_IOC_FM_PCD_PLCR_RFC_4115 /**< Policer algorythm RFC 4115 */ +} ioc_fm_pcd_plcr_algorithm_selection; + +/**************************************************************************//** + @Description A structure for selcting the policer profile color mode +*//***************************************************************************/ +typedef enum ioc_fm_pcd_plcr_color_mode { + e_IOC_FM_PCD_PLCR_COLOR_BLIND, /**< Color blind */ + e_IOC_FM_PCD_PLCR_COLOR_AWARE /**< Color aware */ +} ioc_fm_pcd_plcr_color_mode; + +/**************************************************************************//** + @Description A structure for selcting the policer profile color functional mode +*//***************************************************************************/ +typedef enum ioc_fm_pcd_plcr_color { + e_IOC_FM_PCD_PLCR_GREEN, /**< Green */ + e_IOC_FM_PCD_PLCR_YELLOW, /**< Yellow */ + e_IOC_FM_PCD_PLCR_RED, /**< Red */ + e_IOC_FM_PCD_PLCR_OVERRIDE /**< Color override */ +} ioc_fm_pcd_plcr_color; + +/**************************************************************************//** + @Description A structure for selcting the policer profile packet frame length selector +*//***************************************************************************/ +typedef enum ioc_fm_pcd_plcr_frame_length_select { + e_IOC_FM_PCD_PLCR_L2_FRM_LEN, /**< L2 frame length */ + e_IOC_FM_PCD_PLCR_L3_FRM_LEN, /**< L3 frame length */ + e_IOC_FM_PCD_PLCR_L4_FRM_LEN, /**< L4 frame length */ + e_IOC_FM_PCD_PLCR_FULL_FRM_LEN /**< Full frame length */ +} ioc_fm_pcd_plcr_frame_length_select; + +/**************************************************************************//** + @Description An enum for selecting rollback frame +*//***************************************************************************/ +typedef enum ioc_fm_pcd_plcr_roll_back_frame_select { + e_IOC_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN, /**< Rollback L2 frame length */ + e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN /**< Rollback Full frame length */ +} ioc_fm_pcd_plcr_roll_back_frame_select; + +/**************************************************************************//** + @Description A structure for selcting the policer profile packet or byte mode +*//***************************************************************************/ +typedef enum ioc_fm_pcd_plcr_rate_mode { + e_IOC_FM_PCD_PLCR_BYTE_MODE, /**< Byte mode */ + e_IOC_FM_PCD_PLCR_PACKET_MODE /**< Packet mode */ +} ioc_fm_pcd_plcr_rate_mode; + +/**************************************************************************//** + @Description An enum for defining action of frame +*//***************************************************************************/ +typedef enum ioc_fm_pcd_done_action { + e_IOC_FM_PCD_ENQ_FRAME = 0, /**< Enqueue frame */ + e_IOC_FM_PCD_DROP_FRAME /**< Drop frame */ +} ioc_fm_pcd_done_action; + +/**************************************************************************//** + @Description A structure for selcting the policer counter +*//***************************************************************************/ +typedef enum ioc_fm_pcd_plcr_profile_counters { + e_IOC_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER, /**< Green packets counter */ + e_IOC_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER, /**< Yellow packets counter */ + e_IOC_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER, /**< Red packets counter */ + e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER, /**< Recolored yellow packets counter */ + e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER /**< Recolored red packets counter */ +} ioc_fm_pcd_plcr_profile_counters; + +/**************************************************************************//** + @Description A structure for selecting action +*//***************************************************************************/ +typedef enum ioc_fm_pcd_action { + e_IOC_FM_PCD_ACTION_NONE, /**< NONE */ + e_IOC_FM_PCD_ACTION_EXACT_MATCH, /**< Exact match on the selected extraction*/ + e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP /**< Indexed lookup on the selected extraction*/ +} ioc_fm_pcd_action; + +/**************************************************************************//** + @Description A type used for returning the order of the key extraction. + each value in this array represents the index of the extraction + command as defined by the user in the initialization extraction array. + The valid size of this array is the user define number of extractions + required (also marked by the second '0' in this array). +*//***************************************************************************/ +typedef uint8_t ioc_fm_pcd_kg_key_order_t [IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; + +/**************************************************************************//** + @Description A Union of protocol dependent special options +*//***************************************************************************/ +typedef union ioc_fm_pcd_hdr_protocol_opt_u { + ioc_eth_protocol_opt_t eth_opt; /**< Ethernet options */ + ioc_vlan_protocol_opt_t vlan_opt; /**< Vlan options */ + ioc_mpls_protocol_opt_t mpls_opt; /**< MPLS options */ + ioc_ipv4_protocol_opt_t ipv4_opt; /**< IPv4 options */ + ioc_ipv6_protocol_opt_t ipv6_opt; /**< IPv6 options */ +} ioc_fm_pcd_hdr_protocol_opt_u; + +/**************************************************************************//** + @Description A union holding all known protocol fields +*//***************************************************************************/ +typedef union ioc_fm_pcd_fields_u { + ioc_header_field_eth_t eth; /**< eth */ + ioc_header_field_vlan_t vlan; /**< vlan */ + ioc_header_field_llc_snap_t llc_snap; /**< llcSnap */ + ioc_header_field_pppoe_t pppoe; /**< pppoe */ + ioc_header_field_mpls_t mpls; /**< mpls */ + ioc_header_field_ipv4_t ipv4; /**< ipv4 */ + ioc_header_field_ipv6_t ipv6; /**< ipv6 */ + ioc_header_field_udp_t udp; /**< udp */ + ioc_header_field_tcp_t tcp; /**< tcp */ + ioc_header_field_sctp_t sctp; /**< sctp */ + ioc_header_field_dccp_t dccp; /**< dccp */ + ioc_header_field_gre_t gre; /**< gre */ + ioc_header_field_minencap_t minencap; /**< minencap */ + ioc_header_field_ipsec_ah_t ipsec_ah; /**< ipsecAh */ + ioc_header_field_ipsec_esp_t ipsec_esp; /**< ipsecEsp */ +} ioc_fm_pcd_fields_u; + +/**************************************************************************//** + @Description structure for defining header extraction for key generation +*//***************************************************************************/ +typedef struct ioc_fm_pcd_from_hdr_t { + uint8_t size; /**< Size in byte */ + uint8_t offset; /**< Byte offset */ +} ioc_fm_pcd_from_hdr_t; + +/**************************************************************************//** + @Description structure for defining field extraction for key generation +*//***************************************************************************/ +typedef struct ioc_fm_pcd_from_field_t { + ioc_fm_pcd_fields_u field; /**< Field selection */ + uint8_t size; /**< Size in byte */ + uint8_t offset; /**< Byte offset */ +} ioc_fm_pcd_from_field_t; + +/**************************************************************************//** + @Description A structure of parameters used to define a single network + environment unit. + A unit should be defined if it will later be used by one or + more PCD engines to distinguich between flows. +*//***************************************************************************/ +typedef struct ioc_fm_pcd_distinction_unit_t { + struct { + ioc_net_header_type hdr; /**< One of the headers supported by the FM */ + ioc_fm_pcd_hdr_protocol_opt_u opt; /**< only one option !! */ + } hdrs[IOC_FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS]; +} ioc_fm_pcd_distinction_unit_t; + +/**************************************************************************//** + @Description A structure of parameters used to define the different + units supported by a specific PCD Network Environment + Characteristics module. Each unit represent + a protocol or a group of protocols that may be used later + by the different PCD engines to distinguish between flows. + (must match struct t_FmPcdNetEnvParams defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_net_env_params_t { + uint8_t num_of_distinction_units; /**< Number of different units to be identified */ + ioc_fm_pcd_distinction_unit_t units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + /**< An array of numOfDistinctionUnits of the + different units to be identified */ + void *id; /**< output parameter; Returns the net-env Id to be used */ +} ioc_fm_pcd_net_env_params_t; + + +/**************************************************************************//** + @Description structure for defining a single extraction action + when creating a key +*//***************************************************************************/ +typedef struct ioc_fm_pcd_extract_entry_t { + ioc_fm_pcd_extract_type type; /**< Extraction type select */ + union { + struct { /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_BY_HDR */ + ioc_net_header_type hdr; /**< Header selection */ + bool ignore_protocol_validation; /**< Ignore protocol validation */ + ioc_fm_pcd_hdr_index hdr_index; /**< Relevant only for MPLS, VLAN and tunneled + IP. Otherwise should be cleared.*/ + ioc_fm_pcd_extract_by_hdr_type type; /**< Header extraction type select */ + union { + ioc_fm_pcd_from_hdr_t from_hdr; /**< Extract bytes from header parameters */ + ioc_fm_pcd_from_field_t from_field; /**< Extract bytes from field parameters*/ + ioc_fm_pcd_fields_u full_field; /**< Extract full filed parameters*/ + } extract_by_hdr_type; + } extract_by_hdr; + struct{ /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_NON_HDR */ + ioc_fm_pcd_extract_from src; /**< Non-header extraction source */ + ioc_fm_pcd_action action; /**< Relevant for CC Only */ + uint16_t ic_indx_mask; /**< Relevant only for CC where + action=e_FM_PCD_ACTION_INDEXED_LOOKUP */ + uint8_t offset; /**< Byte offset */ + uint8_t size; /**< Size in byte */ + } extract_non_hdr; + } extract_params; +} ioc_fm_pcd_extract_entry_t; + +/**************************************************************************//** + @Description A structure for defining masks for each extracted + field in the key. +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_extract_mask_t { + uint8_t extract_array_index; /**< Index in the extraction array, as initialized by user */ + uint8_t offset; /**< Byte offset */ + uint8_t mask; /**< A byte mask (selected bits will be ignored) */ +} ioc_fm_pcd_kg_extract_mask_t; + +/**************************************************************************//** + @Description A structure for defining default selection per groups + of fields +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_extract_dflt_t { + ioc_fm_pcd_kg_known_fields_dflt_types type; /**< Default type select*/ + ioc_fm_pcd_kg_extract_dflt_select dflt_select; /**< Default register select */ +} ioc_fm_pcd_kg_extract_dflt_t; + +/**************************************************************************//** + @Description A structure for defining all parameters needed for + generation a key and using a hash function +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_key_extract_and_hash_params_t { + uint32_t private_dflt0; /**< Scheme default register 0 */ + uint32_t private_dflt1; /**< Scheme default register 1 */ + uint8_t num_of_used_extracts; /**< defines the valid size of the following array */ + ioc_fm_pcd_extract_entry_t extract_array [IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; + uint8_t num_of_used_dflt; /**< defines the valid size of the following array */ + ioc_fm_pcd_kg_extract_dflt_t dflts[IOC_FM_PCD_KG_NUM_OF_DEFAULT_GROUPS]; + uint8_t num_of_used_masks; /**< defines the valid size of the following array */ + ioc_fm_pcd_kg_extract_mask_t masks[IOC_FM_PCD_KG_NUM_OF_EXTRACT_MASKS]; + uint8_t hash_shift; /**< Select the 24 bits out of the 64 hash result */ + uint32_t hash_distribution_num_of_fqids; /**< must be > 1 and a power of 2. Represents the range + of queues for the key and hash functionality */ + uint8_t hash_distribution_fqids_shift; /**< selects the FQID bits that will be effected by the hash */ + bool symmetric_hash; /**< TRUE to generate the same hash for frames with swapped source and + destination fields on all layers; If TRUE, driver will check that for + all layers, if SRC extraction is selected, DST extraction must also be + selected, and vice versa. */ +} ioc_fm_pcd_kg_key_extract_and_hash_params_t; + +/**************************************************************************//** + @Description A structure of parameters for defining a single + Qid mask (extracted OR). +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_extracted_or_params_t { + ioc_fm_pcd_extract_type type; /**< Extraction type select */ + union{ + struct{ /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_BY_HDR */ + ioc_net_header_type hdr; + ioc_fm_pcd_hdr_index hdr_index; /**< Relevant only for MPLS, VLAN and tunneled + IP. Otherwise should be cleared.*/ + bool ignore_protocol_validation; + } extract_by_hdr; + ioc_fm_pcd_extract_from src; /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_NON_HDR */ + } extract_params; + uint8_t extraction_offset; /**< Offset for extraction */ + ioc_fm_pcd_kg_extract_dflt_select dflt_value; /**< Select register from which extraction is taken if + field not found */ + uint8_t mask; /**< Mask LSB byte of extraction (specified bits are ignored) */ + uint8_t bit_offset_in_fqid; /**< out of 24 bits Qid (max offset = 16) */ +} ioc_fm_pcd_kg_extracted_or_params_t; + +/**************************************************************************//** + @Description A structure for configuring scheme counter +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_scheme_counter_t { + bool update; /**< FALSE to keep the current counter state + and continue from that point, TRUE to update/reset + the counter when the scheme is written. */ + uint32_t value; /**< If update=TRUE, this value will be written into the + counter. clear this field to reset the counter. */ +} ioc_fm_pcd_kg_scheme_counter_t; + +/**************************************************************************//** + @Description A structure for defining policer profile + parameters as required by keygen (when policer + is the next engine after this scheme). +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_plcr_profile_t { + bool shared_profile; /**< TRUE if this profile is shared between ports + (i.e. managed by master partition) May not be TRUE + if profile is after Coarse Classification*/ + bool direct; /**< if TRUE, directRelativeProfileId only selects the profile + id, if FALSE fqidOffsetRelativeProfileIdBase is used + together with fqidOffsetShift and numOfProfiles + parameters, to define a range of profiles from + which the keygen result will determine the + destination policer profile. */ + union{ + uint16_t direct_relative_profile_id; /**< Used if 'direct' is TRUE, to select policer profile. + This parameter should + indicate the policer profile offset within the port's + policer profiles or SHARED window. */ + struct { + uint8_t fqid_offset_shift; /**< shift of KG results without the qid base */ + uint8_t fqid_offset_relative_profile_id_base;/**< OR of KG results without the qid base + This parameter should + indicate the policer profile offset within the port's + policer profiles windowor SHARED window depends on sharedProfile */ + uint8_t num_of_profiles; /**< Range of profiles starting at base */ + } indirect_profile_id; + } profile_select; +} ioc_fm_pcd_kg_plcr_profile_t; + +/**************************************************************************//** + @Description A structure for CC parameters if CC is the next engine after KG +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_cc_t { + void *tree_id; /**< CC Tree id */ + uint8_t grp_id; /**< CC group id within the CC tree */ + bool plcr_next; /**< TRUE if after CC, in case of data frame, + policing is required. */ + bool bypass_plcr_profile_generation; + /**< TRUE to bypass keygen policer profile + generation (profile selected is the one selected at + port initialization). */ + ioc_fm_pcd_kg_plcr_profile_t plcr_profile; /**< only if plcrNext=TRUE */ +} ioc_fm_pcd_kg_cc_t; + +/**************************************************************************//** + @Description A structure for initializing a keygen single scheme + (must match struct t_FmPcdKgSchemeParams defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_scheme_params_t { + bool modify; /**< enables changing an existing scheme */ + union + { + uint8_t relative_scheme_id; + /**< if modify=FALSE:Partition relative scheme id */ + void *scheme_id; /**< if modify=TRUE: a handle of the existing scheme */ + } scm_id; + bool always_direct; /**< This scheme is reached only directly, i.e. + no need for match vector. Keygen will ignore + it when matching */ + struct /**< HL Relevant only if alwaysDirect = FALSE */ + { + void *net_env_id; /**< Network environment id */ + uint8_t num_of_distinction_units; + /**< Number of netenv units listed in unit_ids array */ + uint8_t unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + /**< Indexes as passed to SetNetEnvCharacteristics array*/ + } netEnvParams; + bool use_hash; /**< use the KG Hash functionality */ + ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params; + /**< used only if useHash = TRUE */ + bool bypass_fqid_generation; + /**< Normally - FALSE, TRUE to avoid FQID update in the IC; + In such a case FQID after KG will be the default FQID + defined for the relevant port, or the FQID defined by CC + in cases where CC was the previous engine. */ + uint32_t base_fqid; /**< Base FQID */ + uint8_t numOfUsedExtractedOrs; + /**< Number of Fqid masks listed in extractedOrs array*/ + ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS]; + /**< IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS + registers are shared between qidMasks + functionality and some of the extraction + actions; Normally only some will be used + for qidMask. Driver will return error if + resource is full at initialization time. */ + ioc_fm_pcd_engine next_engine; /**< may be BMI, PLCR or CC */ + union{ /**< depends on nextEngine */ + ioc_fm_pcd_done_action done_action; /**< Used when next engine is BMI (done) */ + ioc_fm_pcd_kg_plcr_profile_t plcr_profile; /**< Used when next engine is PLCR */ + ioc_fm_pcd_kg_cc_t cc; /**< Used when next engine is CC */ + } kg_next_engine_params; + ioc_fm_pcd_kg_scheme_counter_t scheme_counter; /**< A structure of parameters for updating + the scheme counter */ + void *id; /**< Returns the scheme Id to be used */ +} ioc_fm_pcd_kg_scheme_params_t; + +/**************************************************************************//** + @Description A structure for defining CC params when CC is the + next engine after a CC node +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_next_cc_params_t { + void *cc_node_id; /**< Id of the next CC node */ +} ioc_fm_pcd_cc_next_cc_params_t; + +/**************************************************************************//** + @Description A structure for defining PLCR params when PLCR is the + next engine after a CC node +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_next_plcr_params_t { + bool override_params; /**< TRUE if CC override previously decided parameters*/ + bool shared_profile; /**< Relevant only if overrideParams=TRUE: + TRUE if this profile is shared between ports */ + uint16_t new_relative_profileId; /**< Relevant only if overrideParams=TRUE: + (otherwise profile id + is taken from keygen); + This parameter should + indicate the policer profile offset within the port's + policer profiles or from SHARED window.*/ + uint32_t new_fqid; /**< Relevant only if overrideParams=TRUE: + FQID for enquing the frame; + In earlier chips if policer next engine is KEYGEN, + this parameter can be 0, because the KEYGEN always decides + the enqueue FQID.*/ + bool statistics_en; /**< In the case of TRUE Statistic counter is + incremented for each received frame passed through + this Coarse Classification entry.*/ +} ioc_fm_pcd_cc_next_plcr_params_t; + +/**************************************************************************//** + @Description A structure for defining enqueue params when BMI is the + next engine after a CC node +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_next_enqueue_params_t { + ioc_fm_pcd_done_action action; /**< Action - when next engine is BMI (done) */ + bool override_fqid; /**< TRUE if CC override previously decided Fqid(by Keygen), + relevant if action = e_FM_PCD_ENQ_FRAME*/ + uint32_t new_fqid; /**< Valid if overrideFqid=TRUE, FQID for enquing the frame + (otherwise FQID is taken from keygen), + relevant if action = e_FM_PCD_ENQ_FRAME*/ + bool statistics_en; /**< In the case of TRUE Statistic counter is + incremented for each received frame passed through + this Coarse Classification entry.*/ +} ioc_fm_pcd_cc_next_enqueue_params_t; + +/**************************************************************************//** + @Description A structure for defining KG params when KG is the + next engine after a CC node +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_next_kg_params_t { + bool override_fqid; /**< TRUE if CC override previously decided Fqid (by keygen), + Note - this parameters unrelevant for earlier chips*/ + uint32_t new_fqid; /**< Valid if overrideFqid=TRUE, FQID for enquing the frame + (otherwise FQID is taken from keygen), + Note - this parameters unrelevant for earlier chips*/ + void *p_direct_scheme; /**< Direct scheme handle to go to. */ + bool statistics_en; /**< In the case of TRUE Statistic counter is + incremented for each received frame passed through + this Coarse Classification entry.*/ +} ioc_fm_pcd_cc_next_kg_params_t; + +/**************************************************************************//** + @Description A structure for defining next engine params after a CC node. + (must match struct t_FmPcdCcNextEngineParams defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_next_engine_params_t { + ioc_fm_pcd_engine next_engine; /**< user has to init parameters according + to nextEngine definition */ + union { + ioc_fm_pcd_cc_next_cc_params_t cc_params; /**< Parameters in case next engine is CC */ + ioc_fm_pcd_cc_next_plcr_params_t plcr_params; /**< Parameters in case next engine is PLCR */ + ioc_fm_pcd_cc_next_enqueue_params_t enqueue_params; /**< Parameters in case next engine is BMI */ + ioc_fm_pcd_cc_next_kg_params_t kg_params; /**< Parameters in case next engine is KG */ + } params; +#if defined(FM_CAPWAP_SUPPORT) + void *p_manip; /**< Handler to headerManip. + Relevant if next engine of the type result + (e_FM_PCD_PLCR, e_FM_PCD_KG, e_FM_PCD_DONE) */ +#endif /* defined(FM_CAPWAP_SUPPORT) */ +} ioc_fm_pcd_cc_next_engine_params_t; + +/**************************************************************************//** + @Description A structure for defining a single CC Key parameters +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_key_params_t { + uint8_t *p_key; /**< pointer to the key of the size defined in keySize */ + uint8_t *p_mask;/**< pointer to the Mask per key of the size defined + in keySize. p_Key and p_Mask (if defined) has to be + of the same size defined in the keySize */ + ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params; + /**< parameters for the next for the defined Key in + the p_Key */ + +} ioc_fm_pcd_cc_key_params_t; + +/**************************************************************************//** + @Description A structure for defining CC Keys parameters +*//***************************************************************************/ +typedef struct ioc_keys_params_t { + uint8_t num_of_keys; /**< num Of relevant Keys */ + uint8_t key_size; /**< size of the key - in the case of the extraction of + the type FULL_FIELD keySize has to be as standard size of the relevant + key. In the another type of extraction keySize has to be as size of extraction. */ + ioc_fm_pcd_cc_key_params_t key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS]; + /**< it's array with numOfKeys entries each entry in + the array of the type ioc_fm_pcd_cc_key_params_t */ + ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; + /**< parameters for the next step of + unfound (or undefined) key */ +} ioc_keys_params_t; + +/**************************************************************************//** + @Description A structure for defining the CC node params +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_node_params_t { + ioc_fm_pcd_extract_entry_t extract_cc_params; /**< params which defines extraction parameters */ + ioc_keys_params_t keys_params; /**< params which defines Keys parameters of the + extraction defined in extractParams */ + void *id; /**< output parameter; Returns the CC node Id to be used */ +} ioc_fm_pcd_cc_node_params_t; + +/**************************************************************************//** + @Description A structure for defining each CC tree group in term of + NetEnv units and the action to be taken in each case. + the unit_ids list must be in order from lower to higher indexes. + + ioc_fm_pcd_cc_next_engine_params_t is a list of 2^num_of_distinction_units + structures where each defines the next action to be taken for + each units combination. for example: + num_of_distinction_units = 2 + unit_ids = {1,3} + next_engine_per_entries_in_grp[0] = ioc_fm_pcd_cc_next_engine_params_t for the case that + unit 1 - not found; unit 3 - not found; + next_engine_per_entries_in_grp[1] = ioc_fm_pcd_cc_next_engine_params_t for the case that + unit 1 - not found; unit 3 - found; + next_engine_per_entries_in_grp[2] = ioc_fm_pcd_cc_next_engine_params_t for the case that + unit 1 - found; unit 3 - not found; + next_engine_per_entries_in_grp[3] = ioc_fm_pcd_cc_next_engine_params_t for the case that + unit 1 - found; unit 3 - found; +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_grp_params_t { + uint8_t num_of_distinction_units; /**< up to 4 */ + uint8_t unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS]; + /**< Indexes of the units as defined in + FM_PCD_SetNetEnvCharacteristics */ + ioc_fm_pcd_cc_next_engine_params_t next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP]; + /**< Max size is 16 - if only one group used */ +} ioc_fm_pcd_cc_grp_params_t; + +/**************************************************************************//** + @Description A structure for defining the CC tree groups + (must match struct t_FmPcdCcTreeParams defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_tree_params_t { + void *net_env_id; /**< Id of the Network environment as returned + by FM_PCD_SetNetEnvCharacteristics */ + uint8_t num_of_groups; /**< Number of CC groups within the CC tree */ + ioc_fm_pcd_cc_grp_params_t fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS]; + /**< Parameters for each group. */ + void *id; /**< output parameter; Returns the tree Id to be used */ +} ioc_fm_pcd_cc_tree_params_t; + +/**************************************************************************//** + @Description A structure for defining parameters for byte rate +*//***************************************************************************/ +typedef struct ioc_fm_pcd_plcr_byte_rate_mode_param_t { + ioc_fm_pcd_plcr_frame_length_select frame_length_selection; /**< Frame length selection */ + ioc_fm_pcd_plcr_roll_back_frame_select roll_back_frame_selection; /**< relevant option only e_IOC_FM_PCD_PLCR_L2_FRM_LEN, + e_IOC_FM_PCD_PLCR_FULL_FRM_LEN */ +} ioc_fm_pcd_plcr_byte_rate_mode_param_t; + +/**************************************************************************//** + @Description A structure for selcting the policer profile RFC 2698 or + RFC 4115 parameters +*//***************************************************************************/ +typedef struct ioc_fm_pcd_plcr_non_passthrough_alg_param_t { + ioc_fm_pcd_plcr_rate_mode rate_mode; /**< Byte / Packet */ + ioc_fm_pcd_plcr_byte_rate_mode_param_t byte_mode_param; /**< Valid for Byte NULL for Packet */ + uint32_t comitted_info_rate; /**< KBits/Sec or Packets/Sec */ + uint32_t comitted_burst_size; /**< KBits or Packets */ + uint32_t peak_or_accessive_info_rate; /**< KBits/Sec or Packets/Sec */ + uint32_t peak_or_accessive_burst_size; /**< KBits or Packets */ +} ioc_fm_pcd_plcr_non_passthrough_alg_param_t; + +/**************************************************************************//** + @Description A union for defining Policer next engine parameters +*//***************************************************************************/ +typedef union ioc_fm_pcd_plcr_next_engine_params_u { + ioc_fm_pcd_done_action action; /**< Action - when next engine is BMI (done) */ + void *p_profile; /**< Policer profile handle - used when next engine + is PLCR, must be a SHARED profile */ + void *p_direct_scheme; /**< Direct scheme select - when next engine is Keygen */ +} ioc_fm_pcd_plcr_next_engine_params_u; + +typedef struct fm_pcd_port_params_t { + ioc_fm_port_type port_type; /**< Type of port for this profile */ + uint8_t port_id; /**< FM-Port id of port for this profile */ +} fm_pcd_port_params_t; + +/**************************************************************************//** + @Description A structure for selcting the policer profile entry parameters + (must match struct t_FmPcdPlcrProfileParams defined in fm_pcd_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_plcr_profile_params_t { + bool modify; /**< TRUE to change an existing profile */ + union { + struct { + ioc_fm_pcd_profile_type_selection profile_type; /**< Type of policer profile */ + void *p_port; /**< Type of policer profile */ + uint16_t relative_profile_id; /**< Profile id - relative to shared group or to port */ + } new_params; + void *p_profile; /**< A handle to a profile - use it when modify=TRUE */ + } profile_select; + ioc_fm_pcd_plcr_algorithm_selection alg_selection; /**< Profile Algoritem PASS_THROUGH, RFC_2698, RFC_4115 */ + ioc_fm_pcd_plcr_color_mode color_mode; /**< COLOR_BLIND, COLOR_AWARE */ + + union { + ioc_fm_pcd_plcr_color dflt_color; /**< For Color-Blind Pass-Through mode. the policer will re-color + any incoming packet with the deflt value. */ + ioc_fm_pcd_plcr_color override; /**< For Color-Aware modes. The profile response to a + pre-color value of 2'b11. */ + } color; + + ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param; /**< RFC2698 or RFC4115 params */ + + ioc_fm_pcd_engine next_engine_on_green; /**< Green next engine type */ + ioc_fm_pcd_plcr_next_engine_params_u params_on_green; /**< Green next engine params */ + + ioc_fm_pcd_engine next_engine_on_yellow; /**< Yellow next engine type */ + ioc_fm_pcd_plcr_next_engine_params_u params_on_yellow; /**< Yellow next engine params */ + + ioc_fm_pcd_engine next_engine_on_red; /**< Red next engine type */ + ioc_fm_pcd_plcr_next_engine_params_u params_on_red; /**< Red next engine params */ + + bool trap_profile_on_flow_A; /**< Trap on flow A */ + bool trap_profile_on_flow_B; /**< Trap on flow B */ + bool trap_profile_on_flow_C; /**< Trap on flow C */ + void *id; /**< output parameter; Returns the profile Id to be used */ +} ioc_fm_pcd_plcr_profile_params_t; + +/**************************************************************************//** + @Description A structure for modifying CC tree next engine +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_tree_modify_next_engine_params_t { + void *id; /**< CC tree Id to be used */ + uint8_t grp_indx; /**< A Group index in the tree */ + uint8_t indx; /**< Entry index in the group defined by grpId */ + ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params; + /**< parameters for the next for the defined Key in the p_Key */ +} ioc_fm_pcd_cc_tree_modify_next_engine_params_t; + +/**************************************************************************//** + @Description A structure for modifying CC node next engine +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_node_modify_next_engine_params_t { + void *id; /**< CC node Id to be used */ + uint8_t key_indx; /**< Key index for Next Engine Params modifications; + NOTE: This parameter is IGNORED for miss-key! */ + uint8_t key_size; /**< Key size of added key */ + ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params; + /**< parameters for the next for the defined Key in the p_Key */ +} ioc_fm_pcd_cc_node_modify_next_engine_params_t; + +/**************************************************************************//** + @Description A structure for modifying CC node key and next engine +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t { + void *id; /**< CC node Id to be used */ + uint8_t key_indx; /**< Key index for Next Engine Params modifications; + NOTE: This parameter is IGNORED for miss-key! */ + uint8_t key_size; /**< Key size of added key */ + ioc_fm_pcd_cc_key_params_t key_params; /**< it's array with numOfKeys entries each entry in + the array of the type ioc_fm_pcd_cc_key_params_t */ +} ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t; + +/**************************************************************************//** + @Description A structure for remove CC node key +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_node_remove_key_params_t { + void *id; /**< CC node Id to be used */ + uint8_t key_indx; /**< Key index for Next Engine Params modifications; + NOTE: This parameter is IGNORED for miss-key! */ +} ioc_fm_pcd_cc_node_remove_key_params_t; + +/**************************************************************************//** + @Description A structure for modifying CC node key +*//***************************************************************************/ +typedef struct ioc_fm_pcd_cc_node_modify_key_params_t { + void *id; /**< CC node Id to be used */ + uint8_t key_indx; /**< Key index for Next Engine Params modifications; + NOTE: This parameter is IGNORED for miss-key! */ + uint8_t key_size; /**< Key size of added key */ + uint8_t *p_key; /**< pointer to the key of the size defined in keySize */ + uint8_t *p_mask; /**< pointer to the Mask per key of the size defined + in keySize. p_Key and p_Mask (if defined) has to be + of the same size defined in the keySize */ +} ioc_fm_pcd_cc_node_modify_key_params_t; + + +/**************************************************************************//** + @Function FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS + + @Description Define a set of Network Environment Charecteristics. + When setting an environment it is important to understand its + application. It is not meant to describe the flows that will run + on the ports using this environment, but what the user means TO DO + with the PCD mechanisms in order to parse-classify-distribute those + frames. + By specifying a distinction unit, the user means it would use that option + for distinction between frames at either a keygen scheme keygen or a coarse + classification action descriptor. Using interchangeable headers to define a + unit means that the user is indifferent to which of the interchangeable + headers is present in the frame, and they want the distinction to be based + on the presence of either one of them. + Depending on context, there are limitations to the use of environments. A + port using the PCD functionality is bound to an environment. Some or even + all ports may share an environment but also an environment per port is + possible. When initializing a scheme, a classification plan group (see below), + or a coarse classification tree, one of the initialized environments must be + stated and related to. When a port is bound to a scheme, a classification + plan group, or a coarse classification tree, it MUST be bound to the same + environment. + The different PCD modules, may relate (for flows definition) ONLY on + distinction units as defined by their environment. When initializing a + scheme for example, it may not choose to select IPV4 as a match for + recognizing flows unless it was defined in the relating environment. In + fact, to guide the user through the configuration of the PCD, each module's + characterization in terms of flows is not done using protocol names, but using + environment indexes. + In terms of HW implementation, the list of distinction units sets the LCV vectors + and later used for match vector, classification plan vectors and coarse classification + indexing. + + @Param[in,out] ioc_fm_pcd_net_env_params_t An structure defining the distiction units for this configuration. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(20), ioc_compat_fm_pcd_net_env_params_t) +#endif +#define FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(20), ioc_fm_pcd_net_env_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS + + @Description Deletes a set of Network Environment Charecteristics. + + @Param[in] ioc_fm_obj_t An id of a Network environment object. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(21), ioc_compat_fm_obj_t) +#endif +#define FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(21), ioc_fm_obj_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_KG_SET_SCHEME + + @Description Initializing or modifying and enabling a scheme for the keygen. + This routine should be called for adding or modifying a scheme. + When a scheme needs modifying, the API requires that it will be + rewritten. In such a case 'override' should be TRUE. If the + routine is called for a valid scheme and 'override' is FALSE, + it will return error. + + @Param[in] ioc_fm_pcd_kg_scheme_params_t A structure of parameters for defining the scheme + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_KG_SET_SCHEME_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(24), ioc_compat_fm_pcd_kg_scheme_params_t) +#endif +#define FM_PCD_IOC_KG_SET_SCHEME _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(24), ioc_fm_pcd_kg_scheme_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_KG_DEL_SCHEME + + @Description Deleting an initialized scheme. + + @Param[in] ioc_fm_obj_t scheme id as initalized by application at FM_PCD_IOC_KG_SET_SCHEME + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_KG_DEL_SCHEME_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(25), ioc_compat_fm_obj_t) +#endif +#define FM_PCD_IOC_KG_DEL_SCHEME _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(25), ioc_fm_obj_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_BUILD_TREE + + @Description This routine must be called to define a complete coarse + classification tree. This is the way to define coarse + classification to a certain flow - the keygen schemes + may point only to trees defined in this way. + + @Param[in,out] ioc_fm_pcd_cc_tree_params_t A structure of parameters to define the tree. + + @Return 0 on success; Error code if the exception is not enabled, + or is not able to create interrupt. + + @Cautions Allowed only following PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +//#define FM_PCD_IOC_CC_BUILD_TREE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), ioc_compat_fm_pcd_cc_tree_params_t) +#define FM_PCD_IOC_CC_BUILD_TREE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), compat_uptr_t) +#endif +//#define FM_PCD_IOC_CC_BUILD_TREE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), ioc_fm_pcd_cc_tree_params_t) +#define FM_PCD_IOC_CC_BUILD_TREE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), void *) /* workaround ...*/ + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_DELETE_TREE + + @Description Deleting an built tree. + + @Param[in] ioc_fm_obj_t An id of a CC-tree. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_DELETE_TREE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(27), ioc_compat_fm_obj_t) +#endif +#define FM_PCD_IOC_CC_DELETE_TREE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(27), ioc_fm_obj_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_SET_NODE + + @Description This routine should be called for each CC (coarse classification) + node. The whole CC tree should be built bottom up so that each + node points to already defined nodes. p_NodeId returns the node + Id to be used by other nodes. + + @Param[in,out] ioc_fm_pcd_cc_node_params_t A structure for defining the CC node params + + @Return 0 on success; Error code if the exception is not enabled, + or is not able to create interrupt. + + @Cautions Allowed only following PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_SET_NODE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(28), compat_uptr_t) +#endif +#define FM_PCD_IOC_CC_SET_NODE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(28), void *) /* workaround ...*/ + +/**************************************************************************//** + @Function FM_PCD_CcDeleteNode + + @Description Deleting an built node. + + @Param[in] ioc_fm_obj_t An id of a CC-node. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_DELETE_NODE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(29), ioc_compat_fm_obj_t) +#endif +#define FM_PCD_IOC_CC_DELETE_NODE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(29), ioc_fm_obj_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE + + @Description Modify the Next Engine Parameters in the entry of the tree. + + @Param[in] ioc_fm_pcd_cc_tree_modify_next_engine_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcBuildTree(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(30), ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t) +#endif +#define FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(30), ioc_fm_pcd_cc_tree_modify_next_engine_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE + + @Description Modify the Next Engine Parameters in the relevant key entry of the node. + + @Param[in] ioc_fm_pcd_cc_node_modify_next_engine_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(31), ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t) +#endif +#define FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(31), ioc_fm_pcd_cc_node_modify_next_engine_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE + + @Description Modify the Next Engine Parameters of the Miss key case of the node. + + @Param[in] ioc_fm_pcd_cc_node_modify_next_engine_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(32), ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t) +#endif +#define FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(32), ioc_fm_pcd_cc_node_modify_next_engine_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_NODE_REMOVE_KEY + + @Description Remove the key (include Next Engine Parameters of this key) defined by the index of the relevant node . + + @Param[in] ioc_fm_pcd_cc_node_remove_key_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevnt node but also + the node that points to this node +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_NODE_REMOVE_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(33), ioc_compat_fm_pcd_cc_node_remove_key_params_t) +#endif +#define FM_PCD_IOC_CC_NODE_REMOVE_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(33), ioc_fm_pcd_cc_node_remove_key_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_NODE_ADD_KEY + + @Description Add the key(include Next Engine Parameters of this key)in the index defined by the keyIndex . + + @Param[in] ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevnt node but also + the node that points to this node +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_NODE_ADD_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(34), ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t) +#endif +#define FM_PCD_IOC_CC_NODE_ADD_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(34), ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE + + @Description Modify the key and Next Engine Parameters of this key in the index defined by the keyIndex . + + @Param[in] ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevnt node but also + the node that points to this node +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(35), ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t) +#endif +#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(35), ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_CC_NODE_MODIFY_KEY + + @Description Modify the key in the index defined by the keyIndex . + + @Param[in] ioc_fm_pcd_cc_node_modify_key_params_t A pointer to a structure with the relevant parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_CcSetNode() not only of the relevant node but also + the node that points to this node +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(36), ioc_compat_fm_pcd_cc_node_modify_key_params_t) +#endif +#define FM_PCD_IOC_CC_NODE_MODIFY_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(36), ioc_fm_pcd_cc_node_modify_key_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_PLCR_SET_PROFILE + + @Description Sets a profile entry in the policer profile table. + The routine overrides any existing value. + + @Param[in,out] ioc_fm_pcd_plcr_profile_params_t A structure of parameters for defining a + policer profile entry. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_PLCR_SET_PROFILE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_compat_fm_pcd_plcr_profile_params_t) +#endif +#define FM_PCD_IOC_PLCR_SET_PROFILE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_fm_pcd_plcr_profile_params_t) + +/**************************************************************************//** + @Function FM_PCD_IOC_PLCR_DEL_PROFILE + + @Description Delete a profile entry in the policer profile table. + The routine set entry to invalid. + + @Param[in] ioc_fm_obj_t an id of a policer-profile. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PCD_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PCD_IOC_PLCR_DEL_PROFILE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(38), ioc_compat_fm_obj_t) +#endif +#define FM_PCD_IOC_PLCR_DEL_PROFILE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(38), ioc_fm_obj_t) + +#endif /* __FM_PCD_IOCTLS_H */ +/** @} */ /* end of lnx_ioctl_FM_PCD_Runtime_grp group */ +/** @} */ /* end of lnx_ioctl_FM_PCD_grp group */ +/** @} */ /* end of lnx_ioctl_FM_grp group */ --- linux-3.13.0.orig/include/linux/fmd/Peripherals/fm_port_ioctls.h +++ linux-3.13.0/include/linux/fmd/Peripherals/fm_port_ioctls.h @@ -0,0 +1,683 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_port_ioctls.h + + @Description FM Port routines +*//***************************************************************************/ +#ifndef __FM_PORT_IOCTLS_H +#define __FM_PORT_IOCTLS_H + +#include "net_ioctls.h" +#include "fm_ioctls.h" +#include "fm_pcd_ioctls.h" + + +/**************************************************************************//** + @Group lnx_ioctl_FM_grp Frame Manager Linux IOCTL API + + @Description FM Linux ioctls definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group lnx_ioctl_FM_PORT_grp FM Port + + @Description FM Port API + + The FM uses a general module called "port" to represent a Tx port + (MAC), an Rx port (MAC), offline parsing flow or host command + flow. There may be up to 17 (may change) ports in an FM - 5 Tx + ports (4 for the 1G MACs, 1 for the 10G MAC), 5 Rx Ports, and 7 + Host command/Offline parsing ports. The SW driver manages these + ports as sub-modules of the FM, i.e. after an FM is initialized, + its ports may be initialized and operated upon. + The port is initialized aware of its type, but other functions on + a port may be indifferent to its type. When necessary, the driver + verifies coherency and returns error if applicable. + On initialization, user specifies the port type and it's index + (relative to the port's type). Host command and Offline parsing + ports share the same id range, I.e user may not initialized host + command port 0 and offline parsing port 0. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group lnx_ioctl_FM_PORT_runtime_control_grp FM Port Runtime Control Unit + + @Description FM Port Runtime control unit API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection General FM Port defines +*//***************************************************************************/ +#ifdef CONFIG_FMAN_P1023 +#define IOC_FM_PORT_NUM_OF_CONGESTION_GRPS 32 /**< Total number of congestion groups in QM */ +#else +#define IOC_FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */ +#endif +/* @} */ + + +/**************************************************************************//** + @Description struct for defining port PCD modes + (must match enum e_FmPortPcdSupport defined in fm_port_ext.h) +*//***************************************************************************/ +typedef enum ioc_fm_port_pcd_support { + e_IOC_FM_PORT_PCD_SUPPORT_NONE = 0, /**< BMI to BMI, PCD is not used */ + e_IOC_FM_PORT_PCD_SUPPORT_PRS_ONLY, /**< Use only Parser */ + e_IOC_FM_PORT_PCD_SUPPORT_PLCR_ONLY, /**< Use only Policer */ + e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR, /**< Use Parser and Policer */ + e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG, /**< Use Parser and Keygen */ + e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC, /**< Use Parser, Keygen and Coarse Classification */ + e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR, /**< Use all PCD engines */ + e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR, /**< Use Parser, Keygen and Policer */ +#ifdef FM_CAPWAP_SUPPORT + e_IOC_FM_PORT_PCD_SUPPORT_CC_ONLY, /**< Use only Coarse Classification */ + e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG, /**< Use Coarse Classification,and Keygen */ + e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR /**< Use Coarse Classification, Keygen and Policer */ +#endif +} ioc_fm_port_pcd_support; + +/**************************************************************************//** + @Description enum for defining FM Port counters + (must match enum e_FmPortCounters defined in fm_port_ext.h) +*//***************************************************************************/ +typedef enum fm_port_counters { + e_IOC_FM_PORT_COUNTERS_CYCLE, /**< BMI performance counter */ + e_IOC_FM_PORT_COUNTERS_TASK_UTIL, /**< BMI performance counter */ + e_IOC_FM_PORT_COUNTERS_QUEUE_UTIL, /**< BMI performance counter */ + e_IOC_FM_PORT_COUNTERS_DMA_UTIL, /**< BMI performance counter */ + e_IOC_FM_PORT_COUNTERS_FIFO_UTIL, /**< BMI performance counter */ + e_IOC_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION, /**< BMI Rx only performance counter */ + e_IOC_FM_PORT_COUNTERS_FRAME, /**< BMI statistics counter */ + e_IOC_FM_PORT_COUNTERS_DISCARD_FRAME, /**< BMI statistics counter */ + e_IOC_FM_PORT_COUNTERS_DEALLOC_BUF, /**< BMI deallocate buffer statistics counter */ + e_IOC_FM_PORT_COUNTERS_RX_BAD_FRAME, /**< BMI Rx only statistics counter */ + e_IOC_FM_PORT_COUNTERS_RX_LARGE_FRAME, /**< BMI Rx only statistics counter */ + e_IOC_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, /**< BMI Rx only statistics counter */ + e_IOC_FM_PORT_COUNTERS_RX_FILTER_FRAME, /**< BMI Rx & OP only statistics counter */ + e_IOC_FM_PORT_COUNTERS_RX_LIST_DMA_ERR, /**< BMI Rx, OP & HC only statistics counter */ + e_IOC_FM_PORT_COUNTERS_WRED_DISCARD, /**< BMI OP & HC only statistics counter */ + e_IOC_FM_PORT_COUNTERS_LENGTH_ERR, /**< BMI non-Rx statistics counter */ + e_IOC_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, /**< BMI non-Rx statistics counter */ + e_IOC_FM_PORT_COUNTERS_DEQ_TOTAL, /**< QMI counter */ + e_IOC_FM_PORT_COUNTERS_ENQ_TOTAL, /**< QMI counter */ + e_IOC_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI counter */ + e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM /**< QMI counter */ +} fm_port_counters; + +/**************************************************************************//** + @Description Structure for Port id parameters. + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. +*//***************************************************************************/ +typedef struct ioc_fm_port_congestion_groups_t { + uint16_t num_of_congestion_grps_to_consider; /**< Size of congestion_grps_to_consider array */ + uint8_t congestion_grps_to_consider [IOC_FM_PORT_NUM_OF_CONGESTION_GRPS]; /**< list of congestion groups */ +} ioc_fm_port_congestion_groups_t; + +/**************************************************************************//** + @Description struct for defining Dual Tx rate limiting scale + (identical to e_FmPortDualRateLimiterScaleDown defined in fm_port_ext.h) +*//***************************************************************************/ +typedef enum fm_port_dual_rate_limiter_scale_down { + e_IOC_FM_PORT_DUAL_RATE_LIMITER_NONE = 0, /**< Use only single rate limiter */ + e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2, /**< Divide high rate limiter by 2 */ + e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4, /**< Divide high rate limiter by 4 */ + e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 /**< Divide high rate limiter by 8 */ +} fm_port_dual_rate_limiter_scale_down; + +/**************************************************************************//** + @Description struct for defining Tx rate limiting + (identical to t_FmPortRateLimit defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_rate_limit { + uint16_t max_burst_size; /**< in KBytes for Tx ports, in frames + for offline parsing ports. (note that + for early chips burst size is + rounded up to a multiply of 1000 frames).*/ + uint32_t rate_limit; /**< in Kb/sec for Tx ports, in frame/sec for + offline parsing ports. Rate limit refers to + data rate (rather than line rate). */ + fm_port_dual_rate_limiter_scale_down rate_limit_divider; /**< For offline parsing ports only. Not-valid + for some earlier chip revisions */ +} ioc_fm_port_rate_limit_t; + + +/**************************************************************************//** + @Function FM_PORT_IOC_DISABLE + + @Description Gracefully disable an FM port. The port will not start new tasks after all + tasks associated with the port are terminated. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). + This is a blocking routine, it returns after port is + gracefully stopped, i.e. the port will not except new frames, + but it will finish all frames or tasks which were already began +*//***************************************************************************/ +#define FM_PORT_IOC_DISABLE _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(1)) + +/**************************************************************************//** + @Function FM_PORT_IOC_ENABLE + + @Description A runtime routine provided to allow disable/enable of port. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_ENABLE _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(2)) + +/**************************************************************************//** + @Function FM_PORT_IOC_SET_RATE_LIMIT + + @Description Calling this routine enables rate limit algorithm. + By default, this functionality is disabled. + Note that rate-limit mechanism uses the FM time stamp. + The selected rate limit specified here would be + rounded to the nearest power of 2 multiplication + (i.e. up to twice the required rate). + + May be used for Tx and offline parsing ports only + + @Param[in] ioc_fm_port_rate_limit A structure of rate limit parameters + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_SET_RATE_LIMIT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(3), ioc_fm_port_rate_limit_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_REMOVE_RATE_LIMIT + + @Description Calling this routine disables the previously enabled rate limit. + + May be used for Tx and offline parsing ports only + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_REMOVE_RATE_LIMIT _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(5)) + +/**************************************************************************//** + @Function FM_PORT_IOC_SET_ERRORS_ROUTE + + @Description Errors selected for this routine will cause a frame with that error + to be enqueued to error queue. + Errors not selected for this routine will cause a frame with that error + to be enqueued to the one of the other port queues. + By default all errors are defined to be enqueued to error queue. + Errors that were configured to be discarded (at initialization) + may not be selected here. + + May be used for Rx and offline parsing ports only + + @Param[in] ioc_fm_port_frame_err_select_t A list of errors to enqueue to error queue + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_SET_ERRORS_ROUTE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(4), ioc_fm_port_frame_err_select_t) + +/**************************************************************************//** + @Group lnx_ioctl_FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime Control Unit + + @Description FM Port PCD Runtime control unit API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Description A structure of scheme parameters + (must match struct t_FmPcdKgSchemeSelect defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_kg_scheme_select_t { + bool direct; /**< TRUE to use 'scheme_id' directly, FALSE to use LCV.*/ + void *scheme_id; /**< Relevant for 'direct'=TRUE only. + 'scheme_id' selects the scheme after parser. */ +} ioc_fm_pcd_kg_scheme_select_t; + +/**************************************************************************//** + @Description A structure for defining the Parser starting point + (must match struct t_FmPcdPrsStart defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_prs_start_t { + uint8_t parsing_offset; /**< Number of bytes from begining of packet to + start parsing */ + ioc_net_header_type first_prs_hdr; /**< The type of the first header axpected at + 'parsing_offset' */ +} ioc_fm_pcd_prs_start_t; + +/**************************************************************************//** + @Description Scheme IDs structure + (must match struct t_FmPcdPortSchemesParams defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_port_schemes_params_t { + uint8_t num_of_schemes; /**< Number of schemes for port to be bound to. */ + void *scheme_ids [IOC_FM_PCD_KG_NUM_OF_SCHEMES]; + /**< Array of 'num_of_schemes' schemes for the + port to be bound to */ +} ioc_fm_pcd_port_schemes_params_t; + +/**************************************************************************//** + @Description Union for defining port protocol parameters for parser + (must match union u_FmPcdHdrPrsOpts defined in fm_port_ext.h) +*//***************************************************************************/ +typedef union ioc_fm_pcd_hdr_prs_opts_u { + /* MPLS */ + struct { + bool label_interpretation_enable;/**< When this bit is set, the last MPLS label will be + interpreted as described in HW spec table. When the bit + is cleared, the parser will advance to MPLS next parse */ + ioc_net_header_type next_parse; /**< must be equal or higher than IPv4 */ + } mpls_prs_options; + /* VLAN */ + struct { + uint16_t tag_protocol_id1; /**< User defined Tag Protocol Identifier, to be recognized + on VLAN TAG on top of 0x8100 and 0x88A8 */ + uint16_t tag_protocol_id2; /**< User defined Tag Protocol Identifier, to be recognized + on VLAN TAG on top of 0x8100 and 0x88A8 */ + } vlan_prs_options; + /* IPV6 */ + struct { + bool routing_hdr_disable; /**< Disable routing header */ + } ipv6_prs_options; + + /* UDP */ + struct { + bool pad_ignore_checksum; /**< TRUE to ignore pad in checksum */ + } udp_prs_options; + + /* TCP */ + struct { + bool pad_ignore_checksum; /**< TRUE to ignore pad in checksum */ + } tcp_prs_options; +} ioc_fm_pcd_hdr_prs_opts_u; + + +/**************************************************************************//** + @Description A structure for defining each header for the parser + (must match struct t_FmPcdPrsAdditionalHdrParams defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_pcd_prs_additional_hdr_params_t { + ioc_net_header_type hdr; /**< Selected header */ + bool err_disable; /**< TRUE to disable error indication */ + bool soft_prs_enable; /**< Enable jump to SW parser when this + header is recognized by the HW parser. */ + uint8_t index_per_hdr; /**< Normally 0, if more than one sw parser + attachments exists for the same header, + (in the main sw parser code) use this + index to distinguish between them. */ + bool use_prs_opts; /**< TRUE to use parser options. */ + ioc_fm_pcd_hdr_prs_opts_u prs_opts; /**< A unuion according to header type, + defining the parser options selected.*/ +} ioc_fm_pcd_prs_additional_hdr_params_t; + +/**************************************************************************//** + @Description struct for defining port PCD parameters + (must match t_FmPortPcdPrsParams defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_pcd_prs_params_t { + uint8_t prs_res_priv_info; /**< The private info provides a method of inserting + port information into the parser result. This information + may be extracted by Keygen and be used for frames + distribution when a per-port distinction is required, + it may also be used as a port logical id for analyazing + incoming frames. */ + uint8_t parsing_offset; /**< Number of bytes from begining of packet to + start parsing */ + ioc_net_header_type first_prs_hdr; /**< The type of the first header axpected at + 'parsingOffset' */ + bool includeInPrsStatistics; /**< TRUE to include this port in the parser statistics; + NOTE: this field is not valid when the FN is in "guest" mode. */ + uint8_t num_of_hdrs_with_additional_params; + /**< Normally 0, some headers may get + special parameters */ + ioc_fm_pcd_prs_additional_hdr_params_t additional_params[IOC_FM_PCD_PRS_NUM_OF_HDRS]; + /**< A structure of additional parameters + for each header that requires them */ + bool set_vlan_tpid1; /**< TRUE to configure user selection of Ethertype to + indicate a VLAN tag (in addition to the TPID values + 0x8100 and 0x88A8). */ + uint16_t vlan_tpid1; /**< extra tag to use if setVlanTpid1=TRUE. */ + bool set_vlan_tpid2; /**< TRUE to configure user selection of Ethertype to + indicate a VLAN tag (in addition to the TPID values + 0x8100 and 0x88A8). */ + uint16_t vlan_tpid2; /**< extra tag to use if setVlanTpid1=TRUE. */ +} ioc_fm_port_pcd_prs_params_t; + +/**************************************************************************//** + @Description struct for defining coarse alassification parameters + (must match t_FmPortPcdCcParams defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_pcd_cc_params_t { + void *cc_tree_id; /**< CC tree id */ +} ioc_fm_port_pcd_cc_params_t; + +/**************************************************************************//** + @Description struct for defining keygen parameters + (must match t_FmPortPcdKgParams defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_pcd_kg_params_t { + uint8_t num_of_schemes; /**< Number of schemes for port to be bound to. */ + void *schemes_ids[IOC_FM_PCD_KG_NUM_OF_SCHEMES]; + /**< Array of 'numOfSchemes' schemes for the + port to be bound to */ + bool direct_scheme; /**< TRUE for going from parser to a specific scheme, + regardless of parser result */ + void *direct_scheme_id; /**< relevant only if direct == TRUE */ +} ioc_fm_port_pcd_kg_params_t; + +/**************************************************************************//** + @Description struct for defining policer parameters + (must match t_FmPortPcdPlcrParams defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_pcd_plcr_params_t { + void *plcr_profile_id; /**< relevant only if + e_IOC_FM_PCD_SUPPORT_PLCR_ONLY or + e_IOC_FM_PCD_SUPPORT_PRS_AND_PLCR were selected */ +} ioc_fm_port_pcd_plcr_params_t; + +/**************************************************************************//** + @Description struct for defining port PCD parameters + (must match struct t_FmPortPcdParams defined in fm_port_ext.h) +*//***************************************************************************/ +typedef struct ioc_fm_port_pcd_params_t { + ioc_fm_port_pcd_support pcd_support; /**< Relevant for Rx and offline ports only. + Describes the active PCD engines for this port. */ + void *net_env_id; /**< HL Unused in PLCR only mode */ + ioc_fm_port_pcd_prs_params_t *p_prs_params; /**< Parser parameters for this port */ + ioc_fm_port_pcd_cc_params_t *p_cc_params; /**< Coarse classification parameters for this port */ + ioc_fm_port_pcd_kg_params_t *p_kg_params; /**< Keygen parameters for this port */ + ioc_fm_port_pcd_plcr_params_t *p_plcr_params; /**< Policer parameters for this port */ +} ioc_fm_port_pcd_params_t; + +/**************************************************************************//** + @Description FQID parameters structure +*//***************************************************************************/ +typedef struct ioc_fm_port_pcd_fqids_params_t { + uint32_t num_fqids; /**< Number of fqids to be allocated for the port */ + uint8_t alignment; /**< Alignment required for this port */ + uint32_t base_fqid; /**< output parameter - the base fqid */ +} ioc_fm_port_pcd_fqids_params_t; + + +/**************************************************************************//** + @Function FM_PORT_IOC_ALLOC_PCD_FQIDS + + @Description Allocates FQID's + + May be used for Rx and offline parsing ports only + + @Param[in,out] ioc_fm_port_pcd_fqids_params_t Parameters for allocating FQID's + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_ALLOC_PCD_FQIDS _IOWR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(19), ioc_fm_port_pcd_fqids_params_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_FREE_PCD_FQIDS + + @Description Frees previously-allocated FQIDs + + May be used for Rx and offline parsing ports only + + @Param[in] uint32_t Base FQID of previously allocated range. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_FREE_PCD_FQIDS _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(19), uint32_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_SET_PCD + + @Description Calling this routine defines the port's PCD configuration. + It changes it from its default configuration which is PCD + disabled (BMI to BMI) and configures it according to the passed + parameters. + + May be used for Rx and offline parsing ports only + + @Param[in] ioc_fm_port_pcd_params_t A Structure of parameters defining the port's PCD + configuration. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PORT_IOC_SET_PCD_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(20), ioc_compat_fm_port_pcd_params_t) +#endif +#define FM_PORT_IOC_SET_PCD _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(20), ioc_fm_port_pcd_params_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_DELETE_PCD + + @Description Calling this routine releases the port's PCD configuration. + The port returns to its default configuration which is PCD + disabled (BMI to BMI) and all PCD configuration is removed. + + May be used for Rx and offline parsing ports which are + in PCD mode only + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_DELETE_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(21)) + +/**************************************************************************//** + @Function FM_PORT_IOC_DETACH_PCD + + @Description Calling this routine detaches the port from its PCD functionality. + The port returns to its default flow which is BMI to BMI. + + May be used for Rx and offline parsing ports which are + in PCD mode only + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_DETACH_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(22)) + +/**************************************************************************//** + @Function FM_PORT_IOC_ATTACH_PCD + + @Description This routine may be called after FM_PORT_DetachPCD was called, + to return to the originally configured PCD support flow. + The couple of routines are used to allow PCD configuration changes + that demand that PCD will not be used while changes take place. + + May be used for Rx and offline parsing ports which are + in PCD mode only + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_ATTACH_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(23)) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES + + @Description This routine may be called only for ports that use the Policer in + order to allocate private policer profiles. + + @Param[in] uint16_t The number of required policer profiles + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(), and before FM_PORT_SetPCD(). +*//***************************************************************************/ +#define FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(24), uint16_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_PLCR_FREE_PROFILES + + @Description This routine should be called for freeing private policer profiles. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(), and before FM_PORT_SetPCD(). +*//***************************************************************************/ +#define FM_PORT_IOC_PCD_PLCR_FREE_PROFILES _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(25)) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME + + @Description This routine may be called only for ports that use the keygen in + order to change the initial scheme frame should be routed to. + The change may be of a scheme id (in case of direct mode), + from direct to indirect, or from indirect to direct - specifying the scheme id. + + @Param[in] ioc_fm_pcd_kg_scheme_select_t A structure of parameters for defining whether + a scheme is direct/indirect, and if direct - scheme id. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(26), ioc_compat_fm_pcd_kg_scheme_select_t) +#endif +#define FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(26), ioc_fm_pcd_kg_scheme_select_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE + + @Description This routine may be called for ports with flows e_IOC_FM_PCD_SUPPORT_PLCR_ONLY or + e_IOC_FM_PCD_SUPPORT_PRS_AND_PLCR only, to change the initial Policer profile frame + should be routed to. The change may be of a profile and/or absolute/direct mode + selection. + + @Param[in] ioc_fm_obj_t Policer profile Id as returned from FM_PCD_PlcrSetProfile. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(27), ioc_compat_fm_obj_t) +#endif +#define FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(27), ioc_fm_obj_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_CC_MODIFY_TREE + + @Description This routine may be called to change this port connection to + a pre-initializes coarse classification Tree. + + @Param[in] ioc_fm_obj_t Id of new coarse classification tree selected for this port. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(28), ioc_compat_fm_obj_t) +#endif +#define FM_PORT_IOC_PCD_CC_MODIFY_TREE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(28), ioc_fm_obj_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_KG_BIND_SCHEMES + + @Description These routines may be called for modifying the binding of ports + to schemes. The scheme itself is not added, + just this specific port starts using it. + + @Param[in] ioc_fm_pcd_port_schemes_params_t Schemes parameters structre + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(30), ioc_compat_fm_pcd_port_schemes_params_t) +#endif +#define FM_PORT_IOC_PCD_KG_BIND_SCHEMES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(30), ioc_fm_pcd_port_schemes_params_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES + + @Description These routines may be called for modifying the binding of ports + to schemes. The scheme itself is not removed or invalidated, + just this specific port stops using it. + + @Param[in] ioc_fm_pcd_port_schemes_params_t Schemes parameters structre + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#if defined(CONFIG_COMPAT) +#define FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(31), ioc_compat_fm_pcd_port_schemes_params_t) +#endif +#define FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(31), ioc_fm_pcd_port_schemes_params_t) + +/**************************************************************************//** + @Function FM_PORT_IOC_PCD_PRS_MODIFY_START_OFFSET + + @Description Runtime change of the parser start offset within the header. + + @Param[in] ioc_fm_pcd_prs_start_t A structure of parameters for defining the + start point for the parser. + + @Return 0 on success; Error code otherwise. + + @Cautions Allowed only following FM_PORT_Init(). +*//***************************************************************************/ +#define FM_PORT_IOC_PCD_PRS_MODIFY_START_OFFSET _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(32), ioc_fm_pcd_prs_start_t) + +/** @} */ /* end of lnx_ioctl_FM_PORT_pcd_runtime_control_grp group */ +/** @} */ /* end of lnx_ioctl_FM_PORT_runtime_control_grp group */ +/** @} */ /* end of lnx_ioctl_FM_PORT_grp group */ +/** @} */ /* end of lnx_ioctl_FM_grp group */ + + +#endif /* __FM_PORT_IOCTLS_H */ --- linux-3.13.0.orig/include/linux/usb/chipidea.h +++ linux-3.13.0/include/linux/usb/chipidea.h @@ -24,6 +24,7 @@ * but otg is not supported (no register otgsc). */ #define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) +#define CI_HDRC_IMX28_WRITE_FIX BIT(5) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 --- linux-3.13.0.orig/include/linux/ceph/messenger.h +++ linux-3.13.0/include/linux/ceph/messenger.h @@ -157,7 +157,7 @@ bool front_is_vmalloc; bool more_to_follow; bool needs_out_seq; - int front_max; + int front_alloc_len; unsigned long ack_stamp; /* tx: when we were acked */ struct ceph_msgpool *pool; --- linux-3.13.0.orig/include/linux/ceph/osd_client.h +++ linux-3.13.0/include/linux/ceph/osd_client.h @@ -138,6 +138,7 @@ __le64 *r_request_pool; void *r_request_pgid; __le32 *r_request_attempts; + bool r_paused; struct ceph_eversion *r_request_reassert_version; int r_result; --- linux-3.13.0.orig/include/linux/can/skb.h +++ linux-3.13.0/include/linux/can/skb.h @@ -11,7 +11,9 @@ #define CAN_SKB_H #include +#include #include +#include /* * The struct can_skb_priv is used to transport additional information along @@ -42,4 +44,40 @@ skb_reserve(skb, sizeof(struct can_skb_priv)); } +static inline void can_skb_destructor(struct sk_buff *skb) +{ + sock_put(skb->sk); +} + +static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk) +{ + if (sk) { + sock_hold(sk); + skb->destructor = can_skb_destructor; + skb->sk = sk; + } +} + +/* + * returns an unshared skb owned by the original sock to be echo'ed back + */ +static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb) +{ + if (skb_shared(skb)) { + struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); + + if (likely(nskb)) { + can_skb_set_owner(nskb, skb->sk); + consume_skb(skb); + return nskb; + } else { + kfree_skb(skb); + return NULL; + } + } + + /* we can assume to have an unshared skb with proper owner */ + return skb; +} + #endif /* CAN_SKB_H */ --- linux-3.13.0.orig/include/linux/sched/sysctl.h +++ linux-3.13.0/include/linux/sched/sysctl.h @@ -100,4 +100,8 @@ void __user *buffer, size_t *lenp, loff_t *ppos); +extern int sysctl_numa_balancing(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos); + #endif /* _SCHED_SYSCTL_H */ --- linux-3.13.0.orig/include/linux/mmc/sdhci.h +++ linux-3.13.0/include/linux/mmc/sdhci.h @@ -98,6 +98,8 @@ #define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4) /* Controller has a non-standard host control register */ #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5) +/* Controller does not support HS200 */ +#define SDHCI_QUIRK2_BROKEN_HS200 (1<<6) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ --- linux-3.13.0.orig/include/scsi/scsi_device.h +++ linux-3.13.0/include/scsi/scsi_device.h @@ -257,7 +257,7 @@ struct list_head siblings; struct list_head devices; struct device dev; - unsigned int reap_ref; /* protected by the host lock */ + struct kref reap_ref; /* last put renders target invisible */ unsigned int channel; unsigned int id; /* target id ... replace * scsi_device.id eventually */ @@ -284,7 +284,6 @@ #define SCSI_DEFAULT_TARGET_BLOCKED 3 char scsi_level; - struct execute_work ew; enum scsi_target_state state; void *hostdata; /* available to low-level driver */ unsigned long starget_data[0]; /* for the transport */ --- linux-3.13.0.orig/include/scsi/osd_ore.h +++ linux-3.13.0/include/scsi/osd_ore.h @@ -102,6 +102,7 @@ unsigned unit_off; unsigned cur_pg; unsigned cur_comp; + unsigned maxdevUnits; }; struct ore_io_state; --- linux-3.13.0.orig/include/misc/xgene/xgene_qmtm.h +++ linux-3.13.0/include/misc/xgene/xgene_qmtm.h @@ -0,0 +1,373 @@ +/* + * AppliedMicro X-Gene SOC Queue Manager/Traffic Manager driver + * + * Copyright (c) 2013 Applied Micro Circuits Corporation. + * Author: Ravi Patel + * Keyur Chudgar + * Fushen Chen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __XGENE_QMTM_H__ +#define __XGENE_QMTM_H__ + +/* QMTM Queue types */ +enum xgene_qmtm_qtype { + QTYPE_DISABLED, /* Queue Type is un-configured or disabled */ + QTYPE_PQ, /* Queue Type is Physical Work Queue */ + QTYPE_FP, /* Queue Type is Free Pool Queue */ + QTYPE_VQ, /* Queue Type is Virtual Queue */ + QTYPE_MAX, +}; + +/* QMTM Queue possible sizes */ +enum xgene_qmtm_qsize { + QSIZE_512B, + QSIZE_2KB, + QSIZE_16KB, + QSIZE_64KB, + QSIZE_512KB, + QSIZE_MAX, +}; + +/* QMTM Queue Access Method */ +enum xgene_qmtm_qaccess { + QACCESS_ALT, /* Alternate enq/deq */ + QACCESS_QMI, /* Access using QMI interface */ + QACCESS_MBOX, /* Access using mailboxes */ + QACCESS_MAX, +}; + +/* QMTM Data Length encoded as per QM message format */ +enum xgene_qmtm_data_len { + DATA_LEN_256B = 0x0100, + DATA_LEN_1K = 0x0400, + DATA_LEN_2K = 0x0800, + DATA_LEN_4K = 0x1000, + DATA_LEN_16K = 0x4000, +}; + +enum xgene_qmtm_mask_len { + MASK_LEN_256B = (DATA_LEN_256B - 1), + MASK_LEN_1K = (DATA_LEN_1K - 1), + MASK_LEN_2K = (DATA_LEN_2K - 1), + MASK_LEN_4K = (DATA_LEN_4K - 1), + MASK_LEN_16K = (DATA_LEN_16K - 1), +}; + +/* QMTM Buffer Length encoded as per QM message format */ +enum xgene_qmtm_buf_len { + BUF_LEN_256B = 0x7000, + BUF_LEN_1K = 0x6000, + BUF_LEN_2K = 0x5000, + BUF_LEN_4K = 0x4000, + BUF_LEN_16K = 0x0000, +}; + +/* QMTM messaging structures */ +/* 16 byte QMTM message format */ +struct xgene_qmtm_msg16 { +#ifdef CONFIG_CPU_BIG_ENDIAN + /* memory word 0 (bit 31:0) */ + u32 UserInfo; + + /* memory word 1 (bit 63:32) */ + u32 HL:1; + u32 LErr:3; + u32 RType:4; + u32 IN:1; + u32 Rv:1; + u32 HB:1; + u32 PB:1; + u32 LL:1; + u32 NV:1; + u32 LEI:2; + u32 ELErr:2; + u32 Rv2:2; + u32 FPQNum:12; + + /* memory word 2 (bit 95:64) */ + u32 DataAddrL; /* split 10/32 */ + + /* memory word 3 (bit 127:96) */ + u32 C:1; + u32 BufDataLen:15; + u32 Rv6:6; + u32 DataAddrH:10; /* split 10/32 */ +#else + /* memory word 0 (bit 31:0) */ + u32 UserInfo; + + /* memory word 1 (bit 63:32) */ + u32 FPQNum:12; + u32 Rv2:2; + u32 ELErr:2; + u32 LEI:2; + u32 NV:1; + u32 LL:1; + u32 PB:1; + u32 HB:1; + u32 Rv:1; + u32 IN:1; + u32 RType:4; + u32 LErr:3; + u32 HL:1; + + /* memory word 2 (bit 95:64) */ + u32 DataAddrL; /* split 10/32 */ + + /* memory word 3 (bit 127:96) */ + u32 DataAddrH:10; /* split 10/32 */ + u32 Rv6:6; + u32 BufDataLen:15; + u32 C:1; +#endif +} __packed; + +/* Upper 16 byte portion of 32 byte of QMTM message format */ +struct xgene_qmtm_msg_up16 { +#ifdef CONFIG_CPU_BIG_ENDIAN + /* memory word 4 (bit 159:128) */ + u32 H0Info_msbL; /* split 16/32 */ + + /* memory word 5 (bit 191:160) */ + u32 HR:1; + u32 Rv0:1; + u32 DR:1; + u32 Rv1:1; + u32 TotDataLengthLinkListLSBs:12; + u16 H0Info_msbH; /* split 16/32 */ + + /* memory word 6 (bit 223:192) */ + u32 H0Info_lsbL; /* split 16/32 */ + + /* memory word 7 (bit 255:224) */ + u32 H0FPSel:4; + u32 H0Enq_Num:12; + u16 H0Info_lsbH; /* split 16/32 */ +#else + /* memory word 4 (bit 159:128) */ + u32 H0Info_msbL; /* split 16/32 */ + + /* memory word 5 (bit 191:160) */ + u16 H0Info_msbH; /* split 16/32 */ + u32 TotDataLengthLinkListLSBs:12; + u32 Rv1:1; + u32 DR:1; + u32 Rv0:1; + u32 HR:1; + + /* memory word 6 (bit 223:192) */ + u32 H0Info_lsbL; /* split 16/32 */ + + /* memory word 7 (bit 255:224) */ + u16 H0Info_lsbH; /* split 16/32 */ + u32 H0Enq_Num:12; + u32 H0FPSel:4; +#endif +} __packed; + +/* 8 byte portion of QMTM extended (64B) message format */ +struct xgene_qmtm_msg_ext8 { +#ifdef CONFIG_CPU_BIG_ENDIAN + u32 NxtDataAddrL; + u32 Rv1:1; + u32 NxtBufDataLength:15; + u32 NxtFPQNum:4; + u32 Rv2:2; + u32 NxtDataAddrH:10; +#else + u32 NxtDataAddrL; + u32 NxtDataAddrH:10; + u32 Rv2:2; + u32 NxtFPQNum:4; + u32 NxtBufDataLength:15; + u32 Rv1:1; +#endif +} __packed; + +/* 8 byte Link list portion of QMTM extended (64B) message format */ +struct xgene_qmtm_msg_ll8 { +#ifdef CONFIG_CPU_BIG_ENDIAN + u32 NxtDataPtrL; + u8 TotDataLengthLinkListMSBs; + u8 NxtLinkListength; + u32 NxtFPQNum:4; + u32 Rv2:2; + u32 NxtDataPtrH:10; +#else + u32 NxtDataPtrL; + u32 NxtDataPtrH:10; + u32 Rv2:2; + u32 NxtFPQNum:4; + u8 NxtLinkListength; + u8 TotDataLengthLinkListMSBs; +#endif +} __packed; + +/* This structure represents 32 byte QMTM message format */ +struct xgene_qmtm_msg32 { + struct xgene_qmtm_msg16 msg16; + struct xgene_qmtm_msg_up16 msgup16; +} __packed; + + /* 32 byte of QMTM extended (64B) message format */ +struct xgene_qmtm_msg_ext32 { + struct xgene_qmtm_msg_ext8 msg8_2; + struct xgene_qmtm_msg_ext8 msg8_1; + union { + struct xgene_qmtm_msg_ext8 msg8_4; + struct xgene_qmtm_msg_ll8 msg8_ll; + }; + struct xgene_qmtm_msg_ext8 msg8_3; +} __packed; + +/* 64 byte QMTM message format */ +struct xgene_qmtm_msg64 { + struct xgene_qmtm_msg32 msg32_1; + struct xgene_qmtm_msg_ext32 msg32_2; +} __packed; + +#ifdef CONFIG_CPU_BIG_ENDIAN +#define xgene_qmtm_msg_le32(word, words) \ + do { \ + int w; \ + for (w = 0; w < words; w++) \ + *(word + w)= cpu_to_le32(*(word + w)); \ + } while (0); +#else +#define xgene_qmtm_msg_le32(word, words) \ + do {} while (0); +#endif + +/* Empty Slot Soft Signature */ +#define EMPTY_SLOT_INDEX 7 +#define EMPTY_SLOT 0x22222222 + +/* Destination QM, 2 MSb in work queue, dstqid */ +#define QMTM_QUEUE_ID(qm, qid) (((u16)(qm) << 10) | qid) + +/* QMTM Slave Device Information */ +struct xgene_qmtm_sdev { + u8 qmtm_ip; + u8 slave; + u8 wq_pbn_start; + u8 wq_pbn_count; + u8 fq_pbn_start; + u8 fq_pbn_count; + u16 slave_id; /* slave id see xgene_qmtm_slave_id */ + u32 wq_pbn_pool; /* Bit mask indicates in use WQ PBN */ + u32 fq_pbn_pool; /* Bit mask indicates in use FP PBN */ + char *name; + char *compatible; + struct xgene_qmtm *qmtm; + struct xgene_qmtm_sdev *idev; +}; + +/* QMTM Queue Information structure */ +/* Per queue descriptor */ +struct xgene_qmtm_qdesc { + u16 qhead; + u16 qtail; + u16 count; + u16 irq; + void *command; + union { + void *qvaddr; + struct xgene_qmtm_msg16 *msg16; + struct xgene_qmtm_msg32 *msg32; + }; +}; + +/* Per queue state database */ +struct xgene_qmtm_qinfo { + u8 slave; + u8 qtype; + u8 qsize; + u8 qaccess; + u8 flags; + u8 qmtm_ip; + u8 slave_id; + u8 pbn; + u16 queue_id; + u16 nummsgs; + u32 pbm_state; + u64 qpaddr; + void *qfabric; + u32 qstate[6]; + struct xgene_qmtm_qdesc *qdesc; + struct xgene_qmtm_sdev *sdev; + struct xgene_qmtm *qmtm; +}; + +/* QMTM Queue Information flags */ +#define XGENE_SLAVE_PB_CONFIGURE 0x01 +#define XGENE_SLAVE_Q_ADDR_ALLOC 0x02 +#define XGENE_SLAVE_DEFAULT_FLAGS (XGENE_SLAVE_PB_CONFIGURE | \ + XGENE_SLAVE_Q_ADDR_ALLOC) + +static inline u16 xgene_qmtm_encode_bufdatalen(u32 len) +{ + if (len <= DATA_LEN_256B) + return BUF_LEN_256B | (len & MASK_LEN_256B); + else if (len <= DATA_LEN_1K) + return BUF_LEN_1K | (len & MASK_LEN_1K); + else if (len <= DATA_LEN_2K) + return BUF_LEN_2K | (len & MASK_LEN_2K); + else if (len <= DATA_LEN_4K) + return BUF_LEN_4K | (len & MASK_LEN_4K); + else if (len < DATA_LEN_16K) + return BUF_LEN_16K | (len & MASK_LEN_16K); + else + return BUF_LEN_16K; +} + +static inline u16 xgene_qmtm_encode_datalen(u32 len) +{ + return len & MASK_LEN_16K; +} + +static inline u32 xgene_qmtm_decode_datalen(u16 bufdatalen) +{ + switch (bufdatalen & BUF_LEN_256B) { + case BUF_LEN_256B: + return bufdatalen & MASK_LEN_256B ? : DATA_LEN_256B; + case BUF_LEN_1K: + return bufdatalen & MASK_LEN_1K ? : DATA_LEN_1K; + case BUF_LEN_2K: + return bufdatalen & MASK_LEN_2K ? : DATA_LEN_2K; + case BUF_LEN_4K: + return bufdatalen & MASK_LEN_4K ? : DATA_LEN_4K; + default: + return bufdatalen & MASK_LEN_16K ? : DATA_LEN_16K; + }; +} + +struct xgene_qmtm_sdev *xgene_qmtm_get_sdev(char *name); + +int xgene_qmtm_set_qinfo(struct xgene_qmtm_qinfo *qinfo); + +void xgene_qmtm_clr_qinfo(struct xgene_qmtm_qinfo *qinfo); + +void xgene_qmtm_read_qstate(struct xgene_qmtm_qinfo *qinfo); + +void xgene_qmtm_fp_dealloc_msg(struct xgene_qmtm_qdesc *qdesc, + struct xgene_qmtm_msg16 *msg); + +void xgene_qmtm_enqueue_msg(struct xgene_qmtm_qdesc *qdesc, + struct xgene_qmtm_msg64 *msg); + +int xgene_qmtm_dequeue_msg(struct xgene_qmtm_qdesc *qdesc, + struct xgene_qmtm_msg64 *msg); + +int xgene_qmtm_intr_coalesce(struct xgene_qmtm_qinfo *qinfo, u8 tap); + +#endif /* __XGENE_QMTM_H__ */ --- linux-3.13.0.orig/include/target/target_core_base.h +++ linux-3.13.0/include/target/target_core_base.h @@ -497,7 +497,7 @@ void *priv; /* Used for lun->lun_ref counting */ - bool lun_ref_active; + int lun_ref_active; }; struct se_ua { --- linux-3.13.0.orig/include/target/iscsi/iscsi_transport.h +++ linux-3.13.0/include/target/iscsi/iscsi_transport.h @@ -12,6 +12,7 @@ int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *); int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *); void (*iscsit_free_np)(struct iscsi_np *); + void (*iscsit_wait_conn)(struct iscsi_conn *); void (*iscsit_free_conn)(struct iscsi_conn *); int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *); int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32); --- linux-3.13.0.orig/firmware/WHENCE +++ linux-3.13.0/firmware/WHENCE @@ -629,16 +629,6 @@ -------------------------------------------------------------------------- -Driver: MYRI_SBUS - MyriCOM Gigabit Ethernet - -File: myricom/lanai.bin - -Licence: Unknown - -Found in hex form in kernel source. - --------------------------------------------------------------------------- - Driver: bnx2x: Broadcom Everest File: bnx2x/bnx2x-e1-6.2.9.0.fw --- linux-3.13.0.orig/firmware/Makefile +++ linux-3.13.0/firmware/Makefile @@ -20,80 +20,32 @@ # accurate. In the latter case it doesn't matter -- it'll use $(fw-shipped-all). # But be aware that the config file might not be included at all. -ifdef CONFIG_ACENIC_OMIT_TIGON_I -acenic-objs := acenic/tg2.bin -fw-shipped- += acenic/tg1.bin -else -acenic-objs := acenic/tg1.bin acenic/tg2.bin -endif -fw-shipped-$(CONFIG_ACENIC) += $(acenic-objs) -fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \ - adaptec/starfire_tx.bin -fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin -fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw -fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-6.2.9.0.fw \ - bnx2x/bnx2x-e1h-6.2.9.0.fw \ - bnx2x/bnx2x-e2-6.2.9.0.fw -fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \ - bnx2/bnx2-rv2p-09-6.0.17.fw \ - bnx2/bnx2-rv2p-09ax-6.0.17.fw \ - bnx2/bnx2-mips-06-6.2.1.fw \ - bnx2/bnx2-rv2p-06-6.0.15.fw -fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin -fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ - cxgb3/t3c_psram-1.1.0.bin \ - cxgb3/ael2005_opt_edc.bin \ - cxgb3/ael2005_twx_edc.bin \ - cxgb3/ael2020_twx_edc.bin -fw-shipped-$(CONFIG_DRM_MGA) += matrox/g200_warp.fw matrox/g400_warp.fw -fw-shipped-$(CONFIG_DRM_R128) += r128/r128_cce.bin -fw-shipped-$(CONFIG_DRM_RADEON) += radeon/R100_cp.bin radeon/R200_cp.bin \ - radeon/R300_cp.bin radeon/R420_cp.bin \ - radeon/RS690_cp.bin radeon/RS600_cp.bin \ - radeon/R520_cp.bin \ - radeon/R600_pfp.bin radeon/R600_me.bin \ - radeon/RV610_pfp.bin radeon/RV610_me.bin \ - radeon/RV630_pfp.bin radeon/RV630_me.bin \ - radeon/RV620_pfp.bin radeon/RV620_me.bin \ - radeon/RV635_pfp.bin radeon/RV635_me.bin \ - radeon/RV670_pfp.bin radeon/RV670_me.bin \ - radeon/RS780_pfp.bin radeon/RS780_me.bin \ - radeon/RV770_pfp.bin radeon/RV770_me.bin \ - radeon/RV730_pfp.bin radeon/RV730_me.bin \ - radeon/RV710_pfp.bin radeon/RV710_me.bin -fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin -fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin +fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-7.8.17.0.fw \ + bnx2x/bnx2x-e1h-7.8.17.0.fw \ + bnx2x/bnx2x-e2-7.8.17.0.fw +fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1b.fw \ + bnx2/bnx2-rv2p-06-6.0.15.fw \ + bnx2/bnx2-mips-06-6.2.3.fw \ + bnx2/bnx2-rv2p-09-6.0.17.fw \ + bnx2/bnx2-rv2p-09ax-6.0.17.fw fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \ e100/d102e_ucode.bin -fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin -fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis cis/PCMLM28.cis \ - cis/DP83903.cis cis/NE2K.cis \ - cis/tamarack.cis cis/PE-200.cis \ - cis/PE520.cis -fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis -fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis -fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \ - cis/COMpad2.cis cis/COMpad4.cis \ - cis/SW_555_SER.cis cis/SW_7xx_SER.cis \ - cis/SW_8xx_SER.cis -fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin -fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ - advansys/3550.bin advansys/38C0800.bin +fw-shipped-$(CONFIG_PCMCIA_PCNET) += + +fw-shipped-$(CONFIG_PCMCIA_3C589) += +fw-shipped-$(CONFIG_PCMCIA_3C574) += +fw-shipped-$(CONFIG_SERIAL_8250_CS) += + fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \ qlogic/12160.bin fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin fw-shipped-$(CONFIG_INFINIBAND_QIB) += qlogic/sd7220.fw fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp -fw-shipped-$(CONFIG_SND_MAESTRO3) += ess/maestro3_assp_kernel.fw \ - ess/maestro3_assp_minisrc.fw fw-shipped-$(CONFIG_SND_SB16_CSP) += sb16/mulaw_main.csp sb16/alaw_main.csp \ sb16/ima_adpcm_init.csp \ sb16/ima_adpcm_playback.csp \ sb16/ima_adpcm_capture.csp -fw-shipped-$(CONFIG_SND_YMFPCI) += yamaha/ds1_ctrl.fw yamaha/ds1_dsp.fw \ - yamaha/ds1e_ctrl.fw fw-shipped-$(CONFIG_SND_WAVEFRONT) += yamaha/yss225_registers.bin -fw-shipped-$(CONFIG_TEHUTI) += tehuti/bdx.bin fw-shipped-$(CONFIG_TIGON3) += tigon/tg3.bin tigon/tg3_tso.bin \ tigon/tg3_tso5.bin fw-shipped-$(CONFIG_TYPHOON) += 3com/typhoon.bin @@ -101,40 +53,8 @@ emi26/bitstream.fw fw-shipped-$(CONFIG_USB_EMI62) += emi62/loader.fw emi62/bitstream.fw \ emi62/spdif.fw emi62/midi.fw -fw-shipped-$(CONFIG_USB_KAWETH) += kaweth/new_code.bin kaweth/trigger_code.bin \ - kaweth/new_code_fix.bin \ - kaweth/trigger_code_fix.bin -ifdef CONFIG_FIRMWARE_IN_KERNEL -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_MPR) += keyspan/mpr.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA18X) += keyspan/usa18x.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19) += keyspan/usa19.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19QI) += keyspan/usa19qi.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19QW) += keyspan/usa19qw.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19W) += keyspan/usa19w.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28) += keyspan/usa28.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28XA) += keyspan/usa28xa.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28XB) += keyspan/usa28xb.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28X) += keyspan/usa28x.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49W) += keyspan/usa49w.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49WLC) += keyspan/usa49wlc.fw -else -fw-shipped- += keyspan/mpr.fw keyspan/usa18x.fw keyspan/usa19.fw \ - keyspan/usa19qi.fw keyspan/usa19qw.fw keyspan/usa19w.fw \ - keyspan/usa28.fw keyspan/usa28xa.fw keyspan/usa28xb.fw \ - keyspan/usa28x.fw keyspan/usa49w.fw keyspan/usa49wlc.fw -endif -fw-shipped-$(CONFIG_USB_SERIAL_TI) += ti_3410.fw ti_5052.fw \ - mts_cdma.fw mts_gsm.fw mts_edge.fw -fw-shipped-$(CONFIG_USB_SERIAL_EDGEPORT) += edgeport/boot.fw edgeport/boot2.fw \ - edgeport/down.fw edgeport/down2.fw -fw-shipped-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += edgeport/down3.bin fw-shipped-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat_loader.fw whiteheat.fw \ # whiteheat_loader_debug.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda/keyspan_pda.fw -fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw -fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw -fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin -fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-) --- linux-3.13.0.orig/firmware/bnx2/bnx2-mips-06-6.2.3.fw.ihex +++ linux-3.13.0/firmware/bnx2/bnx2-mips-06-6.2.3.fw.ihex @@ -0,0 +1,5804 @@ +:10000000080001180800000000004A68000000C84D +:1000100000000000000000000000000008004A6826 +:100020000000001400004B30080000A00800000091 +:100030000000569400004B44080058200000008443 +:100040000000A1D808005694000001580000A25CEE +:100050000800321008000000000072F00000A3B495 +:10006000000000000000000000000000080072F026 +:1000700000000024000116A40800049008000400F9 +:10008000000017D4000116C80000000000000000A6 +:100090000000000000000000000000000000000060 +:1000A000080000A80800000000003BFC00012E9C96 +:1000B0000000000000000000000000000000000040 +:1000C00000000000000000000A00004600000000E0 +:1000D000000000000000000D636F6D362E322E33DD +:1000E0000000000006020302000000000000000300 +:1000F000000000C800000032000000030000000003 +:1001000000000000000000000000000000000000EF +:1001100000000010000001360000EA600000000549 +:1001200000000000000000000000000000000008C7 +:1001300000000000000000000000000000000000BF +:1001400000000000000000000000000000000000AF +:10015000000000000000000000000000000000009F +:10016000000000020000000000000000000000008D +:10017000000000000000000000000000000000007F +:10018000000000000000000000000010000000005F +:10019000000000000000000000000000000000005F +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000000000000000000000000000000002F +:1001D000000000000000000000000000000000001F +:1001E0000000000010000003000000000000000DEF +:1001F0000000000D3C02080024424AA03C03080015 +:1002000024634B9CAC4000000043202B1480FFFD76 +:10021000244200043C1D080037BD7FFC03A0F021F0 +:100220003C100800261001183C1C0800279C4AA01E +:100230000E000168000000000000000D27470100CB +:1002400090E3000B2402001A94E5000814620028D1 +:10025000000020218CE200003C0308008C63004475 +:1002600094E60014000211C20002104030A4000203 +:10027000005A10212463000130A50004A446008028 +:100280003C010800AC23004410A000190004202BFE +:100290008F4202B804410008240400013C02080017 +:1002A0008C420060244200013C010800AC22006046 +:1002B00003E00008008010218CE2002094E3001687 +:1002C00000002021AF4202808CE20004A743028498 +:1002D000AF4202883C021000AF4202B83C02080064 +:1002E0008C42005C244200013C010800AC22005C0E +:1002F00003E00008008010212747010090E3000B75 +:100300002402000394E50008146200280000202164 +:100310008CE200003C0308008C63004494E6001467 +:10032000000211C20002104030A40002005A102145 +:100330002463000130A50004A44600803C010800AD +:10034000AC23004410A000190004202B8F4202B8F7 +:1003500004410008240400013C0208008C420060B3 +:10036000244200013C010800AC22006003E00008C8 +:10037000008010218CE2002094E300160000202170 +:10038000AF4202808CE20004A7430284AF4202889D +:100390003C021000AF4202B83C0208008C42005CF4 +:1003A000244200013C010800AC22005C03E000088C +:1003B000008010218F4301002402010050620003DD +:1003C000000311C20000000D000311C20002104022 +:1003D000005A1021A440008003E000080000102112 +:1003E0009362000003E00008AF80000003E0000813 +:1003F0000000102103E00008000010212402010089 +:1004000014820008000000003C0208008C4200FC3E +:10041000244200013C010800AC2200FC0A0000DD7F +:1004200030A200203C0208008C42008424420001DB +:100430003C010800AC22008430A2002010400008DB +:1004400030A300103C0208008C4201082442000145 +:100450003C010800AC22010803E000080000000095 +:1004600010600008000000003C0208008C420104FB +:10047000244200013C010800AC22010403E0000812 +:10048000000000003C0208008C42010024420001F0 +:100490003C010800AC22010003E00008000000005D +:1004A00027BDFFE8AFBF0010274401009483000878 +:1004B000306200041040001B306600028F4202B818 +:1004C00004410008240500013C0208008C42006041 +:1004D000244200013C010800AC2200600A0001290E +:1004E0008FBF00108C82002094830016000028210A +:1004F000AF4202808C820004A7430284AF4202888C +:100500003C021000AF4202B83C0208008C42005C82 +:10051000244200013C010800AC22005C0A000129D1 +:100520008FBF001010C00006006028218F4401001A +:100530000E0000CD000000000A0001282405000183 +:100540008F8200088F4301045043000700002821D8 +:100550008F4401000E0000CD000000008F42010416 +:10056000AF820008000028218FBF001000A01021DA +:1005700003E0000827BD001827BDFFE8AFBF001447 +:10058000AFB00010974201083043700024022000F1 +:100590001062000B286220011440002F000010217F +:1005A00024024000106200250000000024026000C8 +:1005B00010620026000010210A0001658FBF0014A0 +:1005C00027500100920200091040001A2403000184 +:1005D0003C0208008C420020104000160000182148 +:1005E0000E00049300000000960300083C0608007B +:1005F00094C64B5E8E0400188F8200209605000C76 +:1006000000031C0000661825AC440000AC45000443 +:1006100024040001AC400008AC40000CAC400010C9 +:10062000AC400014AC4000180E0004B8AC43001CF1 +:10063000000018210A000164006010210E0003254B +:10064000000000000A000164000010210E000EE905 +:1006500000000000000010218FBF00148FB00010B8 +:1006600003E0000827BD001827BDFFE0AFB2001867 +:100670003C036010AFBF001CAFB10014AFB000105E +:100680008C6450002402FF7F3C1A800000822024EA +:100690003484380C24020037AC6450003C1208004B +:1006A00026524AD8AF42000824020C80AF420024F0 +:1006B0003C1B80083C06080024C60324024010218D +:1006C0002404001D2484FFFFAC4600000481FFFDCC +:1006D000244200043C020800244204B03C0108000B +:1006E000AC224AE03C020800244202303C010800EF +:1006F000AC224AE43C020800244201743C03080096 +:100700002463032C3C040800248403D83C0508001F +:1007100024A538F03C010800AC224B403C02080004 +:10072000244202EC3C010800AC264B243C010800AA +:10073000AC254B343C010800AC234B3C3C01080089 +:10074000AC244B443C010800AC224B483C0108005F +:10075000AC234ADC3C010800AC204AE83C0108001C +:10076000AC204AEC3C010800AC204AF03C010800F7 +:10077000AC204AF43C010800AC204AF83C010800D7 +:10078000AC204AFC3C010800AC204B003C010800B6 +:10079000AC244B043C010800AC204B083C01080091 +:1007A000AC204B0C3C010800AC204B103C01080075 +:1007B000AC204B143C010800AC204B183C01080055 +:1007C000AC264B1C3C010800AC264B203C01080029 +:1007D000AC254B303C010800AC234B380E000623FF +:1007E000000000003C028000344200708C42000097 +:1007F000AF8200143C0308008C6300208F82000449 +:10080000104300043C0280000E00045BAF83000430 +:100810003C028000344600703C0308008C6300A05A +:100820003C0208008C4200A4104300048F84001492 +:100830003C010800AC2300A4A743009E8CCA000022 +:100840003C0308008C6300BC3C0208008C4200B8EA +:100850000144202300641821000040210064202B63 +:1008600000481021004410213C010800AC2300BCCA +:100870003C010800AC2200B88F5100003222000772 +:100880001040FFDCAF8A00148CC600003C05080055 +:100890008CA500BC3C0408008C8400B800CA30233E +:1008A00000A628210000102100A6302B0082202164 +:1008B00000862021322700013C010800AC2500BC45 +:1008C0003C010800AC2400B810E0001F32220002F6 +:1008D0008F420100AF4200208F420104AF4200A8C6 +:1008E0009342010B0E0000C6305000FF2E02001E86 +:1008F00054400004001010800E0000C90A000213CA +:1009000000000000005210218C4200000040F80955 +:1009100000000000104000053C0240008F4301042D +:100920003C026020AC4300143C024000AF4201385E +:100930003C0208008C420034244200013C010800C3 +:10094000AC220034322200021040000E3222000499 +:100950008F4201400E0000C6AF4200200E000295FB +:10096000000000003C024000AF4201783C02080059 +:100970008C420038244200013C010800AC220038BF +:10098000322200041040FF983C0280008F42018018 +:100990000E0000C6AF4200208F43018024020F00EA +:1009A00014620005000000008F420188A742009CED +:1009B0000A0002483C0240009362000024030050F9 +:1009C000304200FF144300083C0240000E00027B4E +:1009D00000000000544000043C0240000E000D7571 +:1009E000000000003C024000AF4201B83C02080099 +:1009F0008C42003C244200013C010800AC22003C37 +:100A00000A0001C83C0280003C0290003442000110 +:100A100000822025AF4400208F4200200440FFFECA +:100A20000000000003E00008000000003C0280001D +:100A3000344200010082202503E00008AF4400207A +:100A400027BDFFE0AFB10014AFB0001000808821D7 +:100A5000AFBF00180E00025030B000FF9362007D5F +:100A60000220202102028025A370007D8F70007477 +:100A70003C0280000E000259020280241600000988 +:100A80008FBF00188F4201F80440FFFE24020002CD +:100A9000AF5101C0A34201C43C021000AF4201F8B3 +:100AA0008FBF00188FB100148FB0001003E0000852 +:100AB00027BD002027BDFFE8AFBF0010974201848B +:100AC0008F440188304202001040000500002821B8 +:100AD0000E000FAA000000000A00028D240500018C +:100AE0003C02FF0004800005008218243C02040040 +:100AF000506200019362003E240500018FBF001088 +:100B000000A0102103E0000827BD0018A360002208 +:100B10008F4401400A00025E2405000127BDFFE862 +:100B2000AFBF0014AFB0001093620000304400FF6C +:100B300038830020388200300003182B0002102B6D +:100B40000062182410600003240200501482008008 +:100B50008FBF001493620005304200011040007CFA +:100B60008FBF0014934201482443FFFF2C6200050D +:100B7000104000788FB00010000310803C03080084 +:100B800024634A68004310218C42000000400008A2 +:100B9000000000000E0002508F4401408F70000CD6 +:100BA0008F4201441602000224020001AF62000CD1 +:100BB0000E0002598F4401408F420144145000043A +:100BC0008FBF00148FB000100A000F2027BD00183F +:100BD0008F62000C0A0003040000000097620010FE +:100BE0008F4301443042FFFF1462001A00000000EE +:100BF00024020001A76200108F4202380443001053 +:100C00008F4201403C02003F3446F0003C0560004A +:100C10003C04FFC08CA22BBC0044182400461024C6 +:100C20000002130200031D82106200390000000060 +:100C30008F4202380440FFF7000000008F4201405D +:100C4000AF4202003C021000AF4202380A00032209 +:100C50008FBF0014976200100A0003040000000018 +:100C60000E0002508F440140976200128F430144EE +:100C70003050FFFF1603000224020001A762001299 +:100C80000E0002598F4401408F42014416020004B5 +:100C90008FBF00148FB000100A00029127BD00180A +:100CA000976200120A00030400000000976200141B +:100CB0008F4301443042FFFF14620006240200010A +:100CC0008FBF00148FB00010A76200140A00124AF0 +:100CD00027BD0018976200141440001D8FBF001438 +:100CE0000A00031C00000000976200168F430144B5 +:100CF0003042FFFF1462000B240200018FBF00147A +:100D00008FB00010A76200160A000B1227BD001852 +:100D10009742007824420004A76200100A000322D0 +:100D20008FBF001497620016240300013042FFFFBA +:100D3000144300078FBF00143C0208008C4200706F +:100D4000244200013C010800AC2200708FBF001457 +:100D50008FB0001003E0000827BD001827BDFFE892 +:100D6000AFBF0014AFB000108F50010093620000BD +:100D700093430109304400FF2402001F106200A5C4 +:100D80002862002010400018240200382862000A5F +:100D90001040000C2402000B286200081040002CB8 +:100DA00000000000046000E52862000214400028F2 +:100DB00024020006106200268FBF00140A00041FE0 +:100DC0008FB000101062005E2862000B144000DC3F +:100DD0008FBF00142402000E106200738FB0001049 +:100DE0000A00041F00000000106200C028620039E1 +:100DF0001040000A2402008024020036106200CA5B +:100E000028620037104000B424020035106200C18F +:100E10008FBF00140A00041F8FB000101062002B57 +:100E20002862008110400006240200C82402003914 +:100E3000106200B48FBF00140A00041F8FB00010AE +:100E4000106200998FBF00140A00041F8FB00010B9 +:100E50003C0208008C420020104000B98FBF0014F3 +:100E60000E000493000000008F4201008F830020D9 +:100E70009745010C97460108AC6200008F420104BF +:100E80003C04080094844B5E00052C00AC62000416 +:100E90008F4201180006340000C43025AC620008FF +:100EA0008F42011C24040001AC62000C9342010A31 +:100EB00000A22825AC650010AC600014AC600018DE +:100EC000AC66001C0A0003F58FBF00143C0208004A +:100ED0008C4200201040009A8FBF00140E00049333 +:100EE00000000000974401083C03080094634B5E37 +:100EF0009745010C000422029746010E8F820020C4 +:100F0000000426000083202500052C003C030080FF +:100F100000A6282500832025AC400000AC4000043A +:100F2000AC400008AC40000CAC450010AC400014D4 +:100F3000AC400018AC44001C0A0003F42404000177 +:100F40009742010C14400015000000009362000558 +:100F50003042001014400011000000000E0002504A +:100F6000020020219362000502002021344200107B +:100F70000E000259A36200059362000024030020C2 +:100F8000304200FF1043006D020020218FBF00148B +:100F90008FB000100A000FC027BD00180000000D20 +:100FA0000A00041E8FBF00143C0208008C4200207F +:100FB000104000638FBF00140E0004930000000077 +:100FC0008F4201048F8300209744010C3C050800E8 +:100FD00094A54B5EAC6200009762002C00042400D4 +:100FE0003042FFFF008220253C02400E00A228254F +:100FF000AC640004AC600008AC60000CAC60001095 +:10100000AC600014AC600018AC65001C0A0003F46E +:10101000240400010E00025002002021A7600008F5 +:101020000E00025902002021020020210E00025E63 +:10103000240500013C0208008C42002010400040C2 +:101040008FBF00140E000493000000009742010CB3 +:101050008F8300203C05080094A54B5E000214001D +:10106000AC700000AC620004AC6000088F64004CFF +:101070003C02401F00A22825AC64000C8F62005087 +:1010800024040001AC6200108F620054AC620014B2 +:10109000AC600018AC65001C8FBF00148FB000104E +:1010A0000A0004B827BD0018240200205082002541 +:1010B0008FB000100E000F0A020020211040002007 +:1010C0008FBF0014020020218FB0001000002821E3 +:1010D0000A00025E27BD0018020020218FBF001405 +:1010E0008FB000100A00058027BD00189745010C3D +:1010F000020020218FBF00148FB000100A0005A04D +:1011000027BD0018020020218FB000100A0005C57D +:1011100027BD00189345010D020020218FB000105B +:101120000A00060F27BD0018020020218FBF0014FF +:101130008FB000100A0005EB27BD00188FBF001408 +:101140008FB0001003E0000827BD00188F4202781E +:101150000440FFFE2402000234840080AF440240B9 +:10116000A34202443C02100003E00008AF420278B0 +:101170003C04080094844B6A3C0208008C424B7487 +:101180003083FFFF000318C000431021AF42003C32 +:101190003C0208008C424B70AF4200383C020050C9 +:1011A00034420008AF4200300000000000000000A0 +:1011B000000000008F420000304200201040FFFD80 +:1011C000000000008F4204003C010800AC224B608C +:1011D0008F4204043C010800AC224B643C02002016 +:1011E000AF420030000000003C02080094424B680F +:1011F0003C03080094634B6C3C05080094A54B6EBF +:1012000024840001004310213083FFFF3C010800CB +:10121000A4224B683C010800A4244B6A1465000317 +:10122000000000003C010800A4204B6A03E0000815 +:10123000000000003C05000A27BDFFE80345282107 +:101240003C04080024844B50AFBF00100E00051D65 +:101250002406000A3C02080094424B523C0308005A +:1012600094634B6E3042000F244200030043180485 +:1012700024027FFF0043102B10400002AF83001CAC +:101280000000000D0E00042A000000003C020800CF +:1012900094424B5A8FBF001027BD001803E000088E +:1012A000A74200A23C02000A034210219443000618 +:1012B0003C02080094424B5A3C010800A4234B56C0 +:1012C000004310238F83001C00021400000214034B +:1012D0000043102B03E000083842000127BDFFE85F +:1012E000AFBF00103C02000A0342102194420006E6 +:1012F0003C010800A4224B560E00047700000000B9 +:101300005440FFF93C02000A8FBF001003E00008C0 +:1013100027BD001827BDFFE8AFBF00100E000477FF +:101320000000000010400003000000000E000485D3 +:10133000000000003C0208008C424B608FBF001090 +:1013400027430400AF4200383C0208008C424B6443 +:1013500027BD0018AF830020AF42003C3C020005CF +:10136000AF42003003E00008AF8000188F82001801 +:101370003C0300060002114000431025AF4200303C +:101380000000000000000000000000008F4200008C +:10139000304200101040FFFD27420400AF820020C1 +:1013A00003E00008AF8000183C0608008CC64B64C0 +:1013B0008F8500188F8300203C02080094424B5A0E +:1013C00027BDFFE024A50001246300202442000182 +:1013D00024C70020AFB10014AFB00010AFBF001899 +:1013E000AF850018AF8300203C010800A4224B5AAF +:1013F000309000FF3C010800AC274B6404C100089A +:101400000000882104E00006000000003C02080003 +:101410008C424B60244200013C010800AC224B602E +:101420003C02080094424B5A3C03080094634B680A +:101430000010202B004310262C42000100441025F0 +:10144000144000048F830018240200101462000F5F +:10145000000000000E0004A9241100013C03080054 +:1014600094634B5A3C02080094424B681462000398 +:10147000000000000E00042A000000001600000317 +:10148000000000000E000493000000003C03080070 +:1014900094634B5E3C02080094424B5C2463000161 +:1014A0003064FFFF3C010800A4234B5E148200035C +:1014B000000000003C010800A4204B5E1200000662 +:1014C000000000003C02080094424B5AA74200A2D0 +:1014D0000A00050B022010210E0004770000000016 +:1014E00010400004022010210E00048500000000BE +:1014F000022010218FBF00188FB100148FB0001090 +:1015000003E0000827BD00203084FFFF30A5FFFF67 +:101510000000182110800007000000003082000148 +:101520001040000200042042006518210A00051343 +:101530000005284003E000080060102110C00006EC +:1015400024C6FFFF8CA2000024A50004AC8200008A +:101550000A00051D2484000403E0000800000000C8 +:1015600010A0000824A3FFFFAC86000000000000CC +:10157000000000002402FFFF2463FFFF1462FFFA53 +:101580002484000403E0000800000000240200019D +:10159000AF62000CA7620010A7620012A7620014DD +:1015A00003E00008A76200163082007F034210218A +:1015B0003C08000E004818213C0208008C42002024 +:1015C00027BDFFD82407FF80AFB3001CAFB20018BF +:1015D000AFB10014AFB00010AFBF00200080802179 +:1015E00030B100FF0087202430D200FF1040002FD0 +:1015F00000009821AF44002C9062000024030050AA +:10160000304200FF1443000E000000003C020800BE +:101610008C4200E00202102100471024AF42002C4F +:101620003C0208008C4200E0020210213042007FA0 +:101630000342102100481021944200D43053FFFF90 +:101640000E000493000000003C02080094424B5E30 +:101650008F8300200011340000C2302500122C00BE +:101660003C02400000C2302534A50001AC700000EF +:101670008FBF0020AC6000048FB20018AC7300086C +:101680008FB10014AC60000C8FB3001CAC6500106F +:101690008FB00010AC60001424040001AC6000188E +:1016A00027BD00280A0004B8AC66001C8FBF0020CC +:1016B0008FB3001C8FB200188FB100148FB00010D0 +:1016C00003E0000827BD00289343010F2402001007 +:1016D0001062000E2865001110A0000724020012FD +:1016E000240200082405003A1062000600003021A0 +:1016F00003E0000800000000240500351462FFFC30 +:10170000000030210A000538000000008F420074FC +:1017100024420FA003E00008AF62000C27BDFFE8E1 +:10172000AFBF00100E00025E240500018FBF001045 +:1017300024020001A762001227BD00182402000144 +:1017400003E00008A360002227BDFFE0AFB1001452 +:10175000AFB00010AFBF001830B1FFFF0E00025055 +:10176000008080219362003F24030004304200FF88 +:101770001443000C02002021122000082402000A59 +:101780000E00053100000000936200052403FFFEF7 +:1017900000431024A362000524020012A362003F4C +:1017A000020020210E000259A360008116200003D0 +:1017B000020020210E0005950000000002002021FB +:1017C000322600FF8FBF00188FB100148FB00010B9 +:1017D000240500380A00053827BD002027BDFFE09A +:1017E000AFBF001CAFB20018AFB10014AFB0001013 +:1017F0000E000250008080210E0005310000000024 +:101800009362003F24120018305100FF123200038F +:101810000200202124020012A362003F936200050F +:101820002403FFFE004310240E000259A3620005AA +:10183000020020212405002016320007000030217C +:101840008FBF001C8FB200188FB100148FB0001032 +:101850000A00025E27BD00208FBF001C8FB2001857 +:101860008FB100148FB00010240500390A0005382C +:1018700027BD002027BDFFE8AFB00010AFBF0014A8 +:101880009742010C2405003600808021144000108E +:10189000304600FF0E00025000000000240200123B +:1018A000A362003F93620005344200100E00053130 +:1018B000A36200050E00025902002021020020212F +:1018C0000E00025E240500200A000604000000004D +:1018D0000E000538000000000E000250020020211A +:1018E000936200232403FF9F020020210043102461 +:1018F0008FBF00148FB00010A36200230A000259AA +:1019000027BD001827BDFFE0AFBF0018AFB100141E +:10191000AFB0001030B100FF0E00025000808021F7 +:10192000240200120E000531A362003F0E0002598E +:101930000200202102002021022030218FBF001848 +:101940008FB100148FB00010240500350A0005384F +:1019500027BD0020A380002C03E00008A380002DF9 +:101960008F4202780440FFFE8F820034AF42024073 +:1019700024020002A34202443C02100003E00008DB +:10198000AF4202783C0360008C6254003042000891 +:101990001440FFFD000000008C625408AF82000C70 +:1019A00024020052AC605408AC645430AC6254342D +:1019B0002402000803E00008AC6254003C0260000E +:1019C0008C42540030420008104000053C03600087 +:1019D0008C625400304200081440FFFD00000000FB +:1019E0008F83000C3C02600003E00008AC43540805 +:1019F00090A3000024020005008040213063003FD6 +:101A000000004821146200050000502190A2001C33 +:101A100094A3001E304900FF306AFFFFAD00000CA8 +:101A2000AD000010AD000024950200148D05001CCF +:101A30008D0400183042FFFF0049102300021100FE +:101A4000000237C3004038210086202300A2102B5B +:101A50000082202300A72823AD05001CAD04001838 +:101A6000A5090014A5090020A50A001603E0000836 +:101A7000A50A00228F4201F80440FFFE2402000262 +:101A8000AF4401C0A34201C43C02100003E00008BF +:101A9000AF4201F83C0208008C4200B427BDFFE8C9 +:101AA000AFBF001424420001AFB000103C01080099 +:101AB000AC2200B48F4300243C02001F30AA00FF78 +:101AC0003442FF8030D800FF006280240080F8217B +:101AD00030EF00FF1158003B01405821240CFF80DB +:101AE0003C19000A3163007F000310C00003194055 +:101AF000006218213C0208008C4200DC25680001CD +:101B0000310D007F03E21021004310213043007F9C +:101B100003431821004C102400794821AF420024CF +:101B20008D220024016C1824006C7026AD22000C5C +:101B30008D220024310800FFAD22001095220014F0 +:101B4000952300208D27001C3042FFFF3063FFFFEC +:101B50008D2600180043102300021100000227C345 +:101B60000040282100C4302300E2102B00C23023A3 +:101B700000E53823AD27001CAD2600189522002073 +:101B8000A522001495220022154B000AA52200165A +:101B90008D2300248D220008254600013145008058 +:101BA0001462000430C4007F108F000238AA008045 +:101BB00000C0502151AF000131C800FF1518FFC906 +:101BC000010058218F8400343082007F03421821A5 +:101BD0003C02000A006218212402FF8000822024B7 +:101BE000AF440024A06A0079A06A00838C62005090 +:101BF0008F840034AC6200708C6500743C027FFFFF +:101C00003442FFFF00A228240E00066BAC6500746E +:101C1000AF5000248FBF00148FB0001003E0000805 +:101C200027BD001827BDFFC0AFBE0038AFB70034D6 +:101C3000AFB5002CAFB20020AFB1001CAFB00018A0 +:101C4000AFBF003CAFB60030AFB40028AFB3002444 +:101C50008F4500248F4600288F43002C3C02001F34 +:101C60003442FF800062182400C230240080A82182 +:101C7000AFA3001400A2F0240E00062FAFA60010A0 +:101C80003C0208008C4200E02410FF8003608821A1 +:101C900002A2102100501024AF4200243C02080090 +:101CA0008C4200E002A210213042007F0342182142 +:101CB0003C02000A00629021924200D293630084A9 +:101CC000305700FF306300FF24020001106200342F +:101CD000036020212402000214620036000000008C +:101CE0000E001216024028219223008392220083C4 +:101CF0003063007F3042007F000210C000031940B3 +:101D0000006218213C0208008C4200DC02A2102173 +:101D10000043382100F01024AF42002892250078BB +:101D20009224008330E2007F034218213C02000C21 +:101D300014850007006280212402FFFFA24200F107 +:101D40002402FFFFA64200F20A0007272402FFFF39 +:101D500096020020A24200F196020022A64200F262 +:101D60008E020024AE4200F492220083A24200F0D0 +:101D70008E4200C8AE4200FC8E4200C4AE4200F863 +:101D80008E220050AE4201008E4200CCAE420104D1 +:101D9000922200853042003F0A0007823442004010 +:101DA0000E00123902402821922200850A00078283 +:101DB0003042003F936200852403FFDF3042003F42 +:101DC000A36200859362008500431024A36200850E +:101DD0009363008393620078307400FF304200FF09 +:101DE00010540036240AFF803C0C000C3283007F24 +:101DF000000310C000031940006218213C020800D3 +:101E00008C4200DC268800013109007F02A21021EB +:101E10000043382130E2007F0342182100EA1024F9 +:101E2000AF420028006C80218E020024028A182410 +:101E3000006A5826AE02000C8E020024310800FF12 +:101E4000AE02001096020014960300208E07001CBC +:101E50003042FFFF3063FFFF8E060018004310235F +:101E600000021100000227C30040282100C43023D3 +:101E700000E2102B00C2302300E53823AE07001C1F +:101E8000AE06001896020020A60200149602002258 +:101E9000A602001692220079304200FF105400077B +:101EA0000000000051370001316800FF92220078E5 +:101EB000304200FF1448FFCD0100A0219222008390 +:101EC000A22200798E2200500A0007E2AE220070A2 +:101ED000A22200858E22004C2405FF80AE42010C18 +:101EE0009222008534420020A2220085924200D135 +:101EF0003C0308008C6300DC305400FF3C02080007 +:101F00008C4200E400143140001420C002A31821C8 +:101F100000C4202102A210210064382100461021B3 +:101F20000045182400E52824AF450028AF43002CC5 +:101F30003042007F924400D030E3007F03422821EA +:101F4000034318213C02000C006280213C02000E79 +:101F5000309600FF00A298211296002A000000008F +:101F60008E02000C02002021026028211040002572 +:101F7000261000280E00064A000000009262000DA4 +:101F800026830001307400FF3042007FA262000D02 +:101F90002404FF801697FFF0267300203C020800FF +:101FA0008C4200DC0000A02102A210210044102479 +:101FB000AF4200283C0208008C4200E43C030800C9 +:101FC0008C6300DC02A2102100441024AF42002CDC +:101FD0003C0208008C4200E402A318213063007F19 +:101FE00002A210213042007F034220210343182126 +:101FF0003C02000C006280213C02000E0A0007A493 +:10200000008298218E4200D8AE2200508E4200D825 +:10201000AE22007092250083924600D19223008365 +:10202000924400D12402FF8000A228243063007F64 +:10203000308400FF00A628250064182A10600002E2 +:1020400030A500FF38A50080A2250083A2250079D5 +:102050000E00063D000000009222007E02A020211A +:10206000A222007A8E2300743C027FFF3442FFFFDD +:10207000006218240E00066BAE2300748FA20010BD +:10208000AF5E00248FBF003CAF4200288FBE0038F7 +:102090008FA200148FB700348FB600308FB5002C9C +:1020A0008FB400288FB300248FB200208FB1001CA2 +:1020B0008FB0001827BD004003E00008AF42002C9D +:1020C00090A2000024420001A0A200003C030800EE +:1020D0008C6300F4304200FF1443000F0080302175 +:1020E000A0A000003C0208008C4200E48F84003471 +:1020F000008220213082007F034218213C02000C24 +:10210000006218212402FF8000822024ACC300005A +:1021100003E00008AF4400288C8200002442002025 +:1021200003E00008AC82000094C200003C080800F4 +:10213000950800CA30E7FFFF008048210102102106 +:10214000A4C2000094C200003042FFFF00E2102B46 +:1021500054400001A4C7000094A200003C03080002 +:102160008C6300CC24420001A4A2000094A20000D1 +:102170003042FFFF544300078F8600280107102BD1 +:10218000A4A000005440000101003821A4C70000B1 +:102190008F8600288CC4001CAF44003C94A2000031 +:1021A0008F43003C3042FFFF000210C00062182144 +:1021B000AF43003C8F42003C008220231880000483 +:1021C000000000008CC200180A00084324420001ED +:1021D0008CC20018AF4200383C020050344200105C +:1021E000AF420030000000000000000000000000CE +:1021F0008F420000304200201040FFFD0000000030 +:102200008F420404AD2200048F420400AD2200007E +:102210003C020020AF42003003E000080000000054 +:1022200027BDFFE0AFB20018AFB10014AFB000108F +:10223000AFBF001C94C2000000C080213C12080007 +:10224000965200C624420001A60200009603000038 +:1022500094E2000000E03021144300058FB100300B +:102260000E000818024038210A000875000000001E +:102270008C8300048C820004244200400461000727 +:10228000AC8200048C8200040440000400000000C2 +:102290008C82000024420001AC8200009602000003 +:1022A0003042FFFF50520001A600000096220000BD +:1022B00024420001A62200008F82002896230000FD +:1022C00094420016144300048FBF001C2402000136 +:1022D000A62200008FBF001C8FB200188FB100141F +:1022E0008FB0001003E0000827BD00208F89002870 +:1022F00027BDFFE0AFBF00188D220028274804004B +:1023000030E700FFAF4200388D22002CAF8800304C +:10231000AF42003C3C020005AF420030000000002C +:1023200000000000000000000000000000000000AD +:10233000000000008C82000C8C82000CAD020000BA +:102340008C820010AD0200048C820018AD020008DF +:102350008C82001CAD02000C8CA20014AD02001097 +:102360008C820020AD02001490820005304200FFF4 +:1023700000021200AD0200188CA20018AD02001C71 +:102380008CA2000CAD0200208CA20010AD02002433 +:102390008CA2001CAD0200288CA20020AD02002CF3 +:1023A000AD060030AD000034978300263402FFFFF5 +:1023B00014620002006020213404FFFF10E00011CD +:1023C000AD04003895230036952400362402000120 +:1023D0003063FFFF000318C20069182190650040B8 +:1023E000308400070082100400451025A0620040E0 +:1023F0008F820028944200563042FFFF0A0008DC1A +:10240000AD02003C952300369524003624020001DD +:102410003063FFFF000318C2006918219065004077 +:1024200030840007008210040002102700451024A9 +:10243000A0620040AD00003C000000000000000071 +:10244000000000003C02000634420040AF42003071 +:102450000000000000000000000000008F420000AB +:10246000304200101040FFFD8F860028AF880030FA +:1024700024C2005624C7003C24C4002824C50032CE +:1024800024C600360E000856AFA200108FBF0018F9 +:1024900003E0000827BD00208F8300243C060800CD +:1024A0008CC600E88F82003430633FFF0003198040 +:1024B00000461021004310212403FF803046007F96 +:1024C00000431024AF420028034618213C02000CB0 +:1024D0000062302190C2000D30A500FF00003821BD +:1024E00034420010A0C2000D8F8900288F8A00247A +:1024F00095230036000A13823048000324020001AD +:10250000A4C3000E1102000B2902000210400005B6 +:10251000240200021100000C240300010A0009201B +:102520000000182111020006000000000A00092026 +:10253000000018218CC2002C0A000920244300014D +:102540008CC20014244300018CC200180043102BDD +:1025500050400009240700012402002714A20003B0 +:10256000000000000A00092C240700019522003E0B +:1025700024420001A522003E000A138230430003DA +:102580002C62000210400009008028211460000421 +:102590000000000094C200360A00093C3046FFFFEC +:1025A0008CC600380A00093C008028210000302138 +:1025B0003C04080024844B780A00088900000000CD +:1025C000274901008D22000C9523000601202021BF +:1025D000000216023046003F3063FFFF240200274E +:1025E00000C0282128C7002810C2000EAF83002495 +:1025F00010E00008240200312402002110C200096A +:102600002402002510C200079382002D0A00095BF6 +:102610000000000010C200059382002D0A00095B33 +:10262000000000000A0008F4000000000A0006266E +:102630000000000095230006912400058D25000C64 +:102640008D2600108D2700188D28001C8D29002054 +:10265000244200013C010800A4234B7E3C010800F9 +:10266000A0244B7D3C010800AC254B843C010800B4 +:10267000AC264B883C010800AC274B903C0108007D +:10268000AC284B943C010800AC294B9803E00008AF +:10269000A382002D8F87002827BDFFC0AFB3003471 +:1026A000AFB20030AFB1002CAFB00028AFBF0038E0 +:1026B0003C0208008C4200D094E3003030B0FFFFB1 +:1026C000005010073045FFFF3063FFFF00C0982126 +:1026D000A7A200103C110800963100C614A3000602 +:1026E0003092FFFF8CE2002424420030AF42003CD5 +:1026F0000A0009948CE2002094E200323042FFFF8D +:1027000054A2000827A400188CE2002C24420030B8 +:10271000AF42003C8CE20028AF4200380A0009A218 +:102720008F84002827A5001027A60020022038212A +:102730000E000818A7A000208FA200182442003025 +:10274000AF4200388FA2001CAF42003C8F840028AB +:102750003C020005AF42003094820034274304005D +:102760003042FFFF0202102B14400007AF830030FD +:1027700094820054948300340202102100431023F9 +:102780000A0009B63043FFFF94830054948200345A +:102790000223182100501023006218233063FFFF2A +:1027A000948200163042FFFF144300030000000033 +:1027B0000A0009C424030001948200163042FFFF7E +:1027C0000043102B104000058F82003094820016C9 +:1027D000006210233043FFFF8F820030AC530000B3 +:1027E000AC400004AC520008AC43000C3C020006B4 +:1027F00034420010AF420030000000000000000032 +:10280000000000008F420000304200101040FFFD29 +:10281000001018C2006418219065004032040007BF +:10282000240200018FBF00388FB300348FB2003014 +:102830008FB1002C8FB000280082100400451025B5 +:1028400027BD004003E00008A062004027BDFFA8AC +:10285000AFB60050AFB5004CAFB40048AFB30044C2 +:10286000AFB1003CAFBF0054AFB20040AFB00038D2 +:102870008C9000003C0208008C4200E88F860034F7 +:10288000960300022413FF8000C2302130633FFF13 +:102890000003198000C3382100F3102490B2000017 +:1028A000AF42002C9203000230E2007F034230214D +:1028B0003C02000E00C28821306300C024020040A8 +:1028C0000080A82100A0B021146200260000A021F1 +:1028D0008E3400388E2200181440000224020001B9 +:1028E000AE2200189202000D304200201440001564 +:1028F0008F8200343C0308008C6300DC001238C077 +:10290000001231400043102100C730210046382119 +:1029100030E300073C02008030E6007800C230253A +:102920000343182100F31024AF4208002463090078 +:10293000AF4608108E2200188C6300080043102157 +:10294000AE2200188E22002C8E2300182442000193 +:102950000062182B1060003D000000000A000A7899 +:1029600000000000920300022402FFC00043102474 +:10297000304200FF1440000524020001AE2200187E +:10298000962200360A000A613054FFFF8E2200149E +:1029900024420001AE22001892020000000216003C +:1029A0000002160304410029000000009602000204 +:1029B00027A4001000802821A7A20016960200027A +:1029C00024070001000030213042FFFFAF820024C5 +:1029D0000E000889AFA0001C960300023C0408000A +:1029E0008C8400E88F82003430633FFF000319803D +:1029F00000441021004310213043007F3C05000CAF +:102A00000053102403431821AF4200280065182109 +:102A10009062000D001221403042007FA062000D44 +:102A20003C0308008C6300E48F82003400431021D3 +:102A30000044382130E2007F03421021004510217C +:102A400000F31824AF430028AEA200009222000D2C +:102A5000304200101040001302A020218F83002874 +:102A60008EA40000028030219462003E2442FFFFC9 +:102A7000A462003E948400029625000E3084FFFF7D +:102A80000E00097330A5FFFF8F82002894430034A5 +:102A90009622000E1443000302A02021240200010C +:102AA000A382002C02C028210E0007FE00000000B7 +:102AB0008FBF00548FB600508FB5004C8FB40048C4 +:102AC0008FB300448FB200408FB1003C8FB000380C +:102AD00003E0000827BD00588F82002827BDFFD0E3 +:102AE000AFB40028AFB20020AFBF002CAFB30024BA +:102AF000AFB1001CAFB00018904400D0904300D19B +:102B00000000A021309200FFA3A30010306300FF5B +:102B10008C5100D88C5300DC1072002B2402000171 +:102B20003C0308008C6300E493A400108F820034FF +:102B30002406FF800004214000431021004410219E +:102B40003043007F00461024AF4200280343182181 +:102B50003C02000C006218218C62000427A40014BF +:102B600027A50010022280210270102304400015C6 +:102B7000AFA300149062000D00C21024304200FF89 +:102B800014400007020088219062000D344200408A +:102B90000E0007FEA062000D0A000ABD93A20010FD +:102BA0000E0009E1241400018F830028AC7000D8C6 +:102BB00093A20010A06200D193A200101452FFD87B +:102BC0000000000024020001168200048FBF002CC8 +:102BD0000E000626000000008FBF002C8FB40028D6 +:102BE0008FB300248FB200208FB1001C8FB000186B +:102BF00003E0000827BD003027BDFFD8AFB3001C9D +:102C0000AFB20018AFB10014AFB00010AFBF0020DA +:102C10000080982100E0802130B1FFFF0E00049376 +:102C200030D200FF000000000000000000000000A3 +:102C30008F820020AC510000AC520004AC5300085D +:102C4000AC40000CAC400010AC400014AC4000188C +:102C50003C03080094634B5E02038025AC50001CCB +:102C6000000000000000000000000000240400013B +:102C70008FBF00208FB3001C8FB200188FB10014DB +:102C80008FB000100A0004B827BD002827BDFFE858 +:102C9000AFB00010AFBF001430A5FFFF30C600FF7B +:102CA0000080802124020C80AF420024000000003C +:102CB0000000000000000000000000000000000014 +:102CC0000E000ACC000000003C040800248400E050 +:102CD0008C8200002403FF808FBF001402021021A9 +:102CE00000431024AF4200248C8200003C03000A01 +:102CF000020280213210007F035010218FB000109B +:102D00000043102127BD001803E00008AF8200280F +:102D100027BDFFE8AFBF00108F4401403C0308000F +:102D20008C6300E02402FF80AF840034008318210C +:102D300000621024AF4200243C02000803424021FC +:102D4000950500023063007F3C02000A034318210E +:102D50000062182130A5FFFF3402FFFF0000302180 +:102D60003C07602010A20006AF8300282402FFFF6A +:102D7000A5020002946500D40E000AF130A5FFFF01 +:102D80008FBF001024020C8027BD001803E000084C +:102D9000AF4200243C020008034240219502000299 +:102DA0003C0A0800954A00C63046FFFF14C00007E1 +:102DB0003402FFFF8F8200288F8400343C0760209C +:102DC000944500D40A000B5A30A5FFFF10C200241E +:102DD0008F87002894E2005494E400163045FFFFEA +:102DE00000A6102300A6182B3089FFFF10600004F6 +:102DF0003044FFFF00C51023012210233044FFFFA1 +:102E0000008A102B1040000C012A1023240200011C +:102E1000A50200162402FFFFA502000294E500D4DB +:102E20008F8400340000302130A5FFFF3C07602074 +:102E30000A000AF1000000000044102A10400008B7 +:102E4000000000009502001630420001104000040E +:102E5000000000009742007E24420014A5020016E4 +:102E600003E00008000000008F84002827BDFFE079 +:102E7000AFBF0018948200349483003E1060001AA3 +:102E80003048FFFF9383002C2402000114620027C6 +:102E90008FBF00188F820028000818C23108000771 +:102EA000006218212447003A244900542444002099 +:102EB000244500302446003490620040304200FF38 +:102EC0000102100730420001104000168FBF0018A9 +:102ED0000E000856AFA900108F82002894420034DB +:102EE0000A000B733048FFFF94830036948200344D +:102EF0001043000E8FBF001894820036A482003465 +:102F000094820056A48200548C82002CAC8200244F +:102F100094820032A48200309482003CA482003A61 +:102F20008FBF00180A000B3327BD002003E0000804 +:102F300027BD002027BDFFE8AFBF00108F4A01006A +:102F40003C0508008CA500E03C02080090424B8440 +:102F50003C0C0800958C4B7E01452821304B003FEE +:102F600030A2007F03424021396900323C02000A4E +:102F70003963003F2C630001010240212D2900012B +:102F80002402FF8000A2282401234825AF8A0034B0 +:102F900000801821AF450024000030210080282146 +:102FA00024070001AF8800283C04080024844B78E3 +:102FB000AF8C002415200007A380002D24020020E0 +:102FC0005562000F006020213402FFFF5582000C83 +:102FD000006020212402002015620005000000008E +:102FE0008C6300142402FFFF106200070000000041 +:102FF0000E000889000000000A000BD0000000004D +:103000000E0008F4016028210E000B68000000008B +:103010008FBF001024020C8027BD001803E00008B9 +:10302000AF4200243C0208008C4200E027BDFFA014 +:10303000AFB1003C008210212411FF80AFBE0058C8 +:10304000AFB70054AFB20040AFB00038AFBF005CC4 +:10305000AFB60050AFB5004CAFB40048AFB30044BA +:10306000005110248F4800248F4900288F470028E2 +:10307000AF4200243C0208008C4200E00080902116 +:1030800024060006008210213042007F03421821EE +:103090003C02000A006280213C02001F3442FF8093 +:1030A00000E2382427A40010260500F00122F024B5 +:1030B0000102B8240E00051DAFA700308FA2001832 +:1030C000AE0200C48FA2001CAE0200C88FA2002472 +:1030D000AE0200CC93A40010920300D12402FF8022 +:1030E0000082102400431025304900FF3083007F08 +:1030F0003122007F0062102A10400004000310C03B +:1031000001311026304900FF000310C000031940B0 +:10311000006218213C0208008C4200DC920400D2BC +:10312000024210210043102100511024AF42002818 +:1031300093A300103063007F000310C00003194008 +:10314000006218213C0208008C4200DC024210217F +:10315000004310213042007F034218213C02000C42 +:10316000006240218FA300142402FFFF1062003090 +:10317000309500FF93A2001195030014304400FF26 +:103180003063FFFF0064182B1060000D000000008A +:10319000950400148D07001C8D0600183084FFFF75 +:1031A00000442023000421000000102100E4382105 +:1031B00000E4202B00C230210A000C4A00C4302158 +:1031C000950400148D07001C8D0600183084FFFF45 +:1031D000008220230004210000001021008018211B +:1031E00000C2302300E4202B00C4302300E3382346 +:1031F000AD07001CAD06001893A20011A502001433 +:1032000097A20012A50200168FA20014AD020010B2 +:103210008FA20014AD02000C93A20011A5020020A1 +:1032200097A20012A50200228FA20014AD02002472 +:103230002406FF80024610243256007FAF4200244D +:10324000035618213C02000A006280218E02004CC5 +:103250008FA200203124007F000428C0AE0200505D +:103260008FA200200004214000852821AE020070BA +:1032700093A2001001208821A202008393A20010D3 +:10328000A2020079920200853042003FA20200852E +:103290003C0208008C4200DC024210210045102153 +:1032A00000461024AF42002C3C0208008C4200E48F +:1032B0003C0308008C6300DC024210210044102112 +:1032C00000461024AF4200283C0208008C4200E473 +:1032D00002431821006518210242102100441021E8 +:1032E0003042007F3063007F93A50010034220210D +:1032F000034318213C02000E006240213C02000CF6 +:1033000010B1008C008248213233007F1660001912 +:103310002404FF803C0208008C4200DC02421021A1 +:1033200000441024AF42002C3C0208008C4200E410 +:103330003C0308008C6300DC02421021004410248E +:10334000AF4200283C0208008C4200E402431821EE +:103350003063007F024210213042007F034220216F +:10336000034318213C02000E006240213C02000C85 +:10337000008248219124000D2414FF8000001021B8 +:1033800000942025A124000D950400029505001449 +:103390008D07001C3084FFFF30A5FFFF8D0600184D +:1033A000008520230004210000E4382100C23021E0 +:1033B00000E4202B00C43021AD07001CAD0600182E +:1033C00095020002A5020014A50000168D02000857 +:1033D000AD0200108D020008AD02000C9502000243 +:1033E000A5020020A50000228D020008AD020024E5 +:1033F0009122000D30420040104000422622000180 +:103400003C0208008C4200E0A3B300283C10000AF4 +:103410000242102100541024AF4200243C02080054 +:103420008C4200E0A380002C27A4002C0242102133 +:103430003042007F03421821007018218C6200D8AE +:103440008D26000427A50028AFA9002C00461021D6 +:10345000AC6200D80E0009E1AF83002893A30028D6 +:103460008F8200280E000626A04300D10E000B68B4 +:103470000000000002541024AF4200243C02080067 +:103480008C4200DC00132940001320C000A420213E +:10349000024210210044102100541024AF42002C9D +:1034A0003C0208008C4200E43C0308008C6300DC12 +:1034B00003563021024210210045102100541024EF +:1034C000AF4200283C0208008C4200E4024318216D +:1034D0000064182102421021004510213042007F73 +:1034E0003063007F03422021034318213C02000E79 +:1034F000006240213C02000C00D080210082482163 +:10350000262200013043007F14750005304400FF7F +:103510002403FF800223102400431026304400FFC0 +:1035200093A2001000808821250800281444FF760B +:103530002529002093A400108FA300142402FFFF6C +:103540001062000A308900FF2482000124830001F8 +:103550003042007F14550005306900FF2403FF80CE +:103560000083102400431026304900FF92020078A7 +:10357000305300FF11330032012088213C02080043 +:103580008C4200DC3225007F000520C00005294068 +:1035900000A42021024210212406FF8000441021B3 +:1035A00000461024AF42002C3C0308008C6300DC72 +:1035B0003C0208008C4200E4024318210242102120 +:1035C0000045102100641821004610243063007F5C +:1035D000AF420028034318213C02000E0062402144 +:1035E0003C0208008C4200E48D06000C0100202102 +:1035F00002421021004510213042007F0342182171 +:103600003C02000C0062482110C0000D012028215E +:103610000E00064A000000002402FF800222182447 +:1036200026240001006228263082007F1455000203 +:10363000308300FF30A300FF1473FFD000608821A7 +:103640008E0300743C027FFF3442FFFF00621824A7 +:10365000AE0300740E00066B02402021AF57002419 +:103660008FA20030AF5E00288FBF005C8FBE005875 +:103670008FB700548FB600508FB5004C8FB4004800 +:103680008FB300448FB200408FB1003C8FB0003840 +:1036900027BD006003E00008AF42002C27BDFFD823 +:1036A000AFB1001CAFBF0020AFB000182751018898 +:1036B000922200032408FF803C03000A3047007F69 +:1036C000A3A700108F4601803C0208008C4200E056 +:1036D000AF86003400C2282100A81024AF42002485 +:1036E0009224000030A2007F0342102100431021E9 +:1036F000AF8200283084007F24020002148200255B +:10370000000719403C0208008C4200E400C210216E +:103710000043282130A2007F0342182100A8102472 +:10372000AF4200283C02000C006218219062000D9C +:10373000AFA3001400481025A062000D8FA3001451 +:103740009062000D304200405040006A8FBF002060 +:103750008F860028A380002C27A400148CC200D8D8 +:103760008C63000427A50010004310210E0009E11E +:10377000ACC200D893A300108F8200280E0006264A +:10378000A04300D10E000B68000000000A000E0BE1 +:103790008FBF00200E00062F00C020210E00063D26 +:1037A000000000003C020008034280219223000137 +:1037B0009202007B1443004F8FBF00209222000032 +:1037C0003044007F24020004108200172882000584 +:1037D00010400006240200052402000310820007A6 +:1037E0008FB1001C0A000E0C0000000010820012B5 +:1037F0008FBF00200A000E0C8FB1001C92050083C1 +:10380000920600788E0700748F84003430A500FF84 +:1038100000073E0230C600FF0E00067330E7007F4F +:103820000A000E0B8FBF00200E000BD78F840034D0 +:103830000A000E0B8FBF002024020C80AF42002430 +:103840009202003E30420040104000200000000084 +:103850009202003E00021600000216030441000618 +:10386000000000008F8400340E0005A024050093A2 +:103870000A000E0B8FBF00209202003F24030018A5 +:10388000304200FF1443000C8F84003424050039BB +:103890000E000538000030210E0002508F840034E5 +:1038A00024020012A202003F0E0002598F8400344D +:1038B0000A000E0B8FBF0020240500360E000538CD +:1038C000000030210A000E0B8FBF00200E000250B6 +:1038D0008F8400349202000534420020A2020005C9 +:1038E0000E0002598F8400340E000FC08F84003404 +:1038F0008FBF00208FB1001C8FB0001824020C80F5 +:1039000027BD002803E00008AF42002427BDFFE8E0 +:10391000AFB00010AFBF001427430100946200084D +:103920000002140000021403044100020000802180 +:103930002410000194620008304200801040001AF8 +:10394000020010219462000830422000104000164E +:10395000020010218C6300183C021C2D344219ED2A +:10396000240600061062000F3C0760213C0208009C +:103970008C4200D4104000078F8200288F830028DB +:10398000906200623042000F34420040A062006248 +:103990008F8200288F840034944500D40E000AF1F1 +:1039A00030A5FFFF020010218FBF00148FB0001060 +:1039B00003E0000827BD001827BDFFE0AFB10014E9 +:1039C000AFB00010A380002CAFBF00188F450100DE +:1039D0003C0308008C6300E02402FF80AF850034C4 +:1039E00000A318213064007F0344202100621824C2 +:1039F0003C02000A00822021AF430024275001002E +:103A00008E0200148C8300DCAF8400280043102356 +:103A100018400004000088218E0200140E000A8461 +:103A2000AC8200DC9202000B24030002304200FF53 +:103A30001443002F0000000096020008304300FFEE +:103A40002402008214620005240200840E00093E54 +:103A5000000000000A000E97000000001462000938 +:103A6000240200818F8200288F8400343C0760216B +:103A7000944500D49206000530A5FFFF0A000E868B +:103A800030C600FF14620027000000009202000A06 +:103A9000304300FF306200201040000430620040DC +:103AA0008F8400340A000E82240600401040000477 +:103AB000000316008F8400340A000E8224060041A1 +:103AC00000021603044100178F84003424060042CC +:103AD0008F8200283C076019944500D430A5FFFF71 +:103AE0000E000AF1000000000A000E97000000001E +:103AF0009202000B24030016304200FF1043000620 +:103B0000000000009202000B24030017304200FF67 +:103B100014430004000000000E000E11000000001D +:103B2000004088210E000B68000000009202000A8D +:103B3000304200081040000624020C808F850028C7 +:103B40003C0400080E0011EE0344202124020C80E6 +:103B5000AF4200248FBF0018022010218FB0001048 +:103B60008FB1001403E0000827BD002027BDFFE847 +:103B7000AFBF0014AFB000108F5000243C0308000A +:103B80008C6300E08F4501002402FF8000A3182110 +:103B90003064007F03442021006218243C02000AA4 +:103BA00000822021AF850034AF4300249082006260 +:103BB000AF8400283042000F34420050A0820062DF +:103BC0003C02001F3442FF800E00062602028024C1 +:103BD000AF5000248FBF00148FB0001003E0000826 +:103BE00027BD00183C0208008C4200201040001D38 +:103BF0002745010090A300093C0200080342202150 +:103C000024020018546200033C0200080A000ED887 +:103C10002402000803422021240200161462000539 +:103C20002402001724020012A082003F0A000EE2C4 +:103C300094A700085462000694A700089362000548 +:103C40002403FFFE00431024A362000594A700088C +:103C500090A6001B8CA4000094A500060A000ACCC4 +:103C600000073C0003E000080000000027440100BA +:103C700094820008304500FF38A3008238A20084F7 +:103C80002C6300012C420001006218251060000620 +:103C9000240200839382002D1040000D00000000DC +:103CA0000A000B9B0000000014A2000524A2FF8064 +:103CB0008F4301043C02602003E00008AC43001481 +:103CC000304200FF2C420002104000032402002278 +:103CD0000A000E3C0000000014A2000300000000D7 +:103CE0000A000EA9000000000A000EC70000000034 +:103CF0009363007E9362007A144300090000202140 +:103D00009362000024030050304200FF144300047B +:103D1000240400019362007E24420001A362007E1D +:103D200003E00008008010218F4201F80440FFFEEC +:103D300024020002AF4401C0A34201C43C021000AF +:103D400003E00008AF4201F827BDFFE8AFBF001055 +:103D50009362003F2403000A304200FF14430046F0 +:103D6000000000008F6300548F62004C1062007DE1 +:103D7000036030219362000024030050304200FFB2 +:103D80001443002F000000008F4401403C02080053 +:103D90008C4200E02403FF800082102100431024A5 +:103DA000AF4200243C0208008C4200E08F650054C2 +:103DB0003C03000A008220213084007F034410214C +:103DC00000431021AC4501089762003C8F63004C12 +:103DD0003042FFFF0002104000621821AF63005C18 +:103DE0008F6300548F64004C9762003C006418237A +:103DF0003042FFFF00031843000210400043102A26 +:103E000010400006000000008F6200548F63004CD9 +:103E1000004310230A000F58000210439762003C31 +:103E20003042FFFF00021040ACC2006424020001D7 +:103E3000A0C0007CA0C2008424020C80AF420024F9 +:103E40000E000F0A8F440140104000478FBF001042 +:103E50008F4301408F4201F80440FFFE240200021C +:103E6000AF4301C0A34201C43C021000AF4201F8BD +:103E70000A000FA88FBF00109362003F24030010B8 +:103E8000304200FF14430004000000008F44014052 +:103E90000A000F94000028219362003F24030016BB +:103EA000304200FF1443000424020014A362003FC8 +:103EB0000A000FA2000000008F62004C8F630050C8 +:103EC00000431023044100288FBF0010936200813B +:103ED00024420001A3620081936200812C4200040D +:103EE00014400010000000009362003F240300040F +:103EF000304200FF14430006000000008F440140E0 +:103F00008FBF0010240500930A0005A027BD0018EC +:103F10008F440140240500938FBF00100A00060F54 +:103F200027BD00188F4401400E0002500000000021 +:103F30008F6200542442FFFFAF6200548F62005032 +:103F40002442FFFFAF6200500E0002598F4401402F +:103F50008F4401408FBF0010240500040A00025E58 +:103F600027BD00188FBF001003E0000827BD001810 +:103F70008F4201889363007E00021402304400FFE8 +:103F8000306300FF1464000D0000000093620080A5 +:103F9000304200FF1044000900000000A3640080CC +:103FA0009362000024030050304200FF14430004D9 +:103FB000000000000A0006D78F440180A36400803F +:103FC00003E000080000000027BDFFE8AFB00010CC +:103FD000AFBF00149362000524030030304200306C +:103FE00014430089008080213C0208008C4200209C +:103FF00010400080020020210E0004930000000009 +:104000008F850020ACB000009362003E9363003FB8 +:10401000304200FF00021200306300FF0043102511 +:10402000ACA2000493620082000216000002160394 +:1040300004410005000000003C0308008C630048B8 +:104040000A000FE6000000009362003E304200408C +:10405000144000030000182193620081304300FFE8 +:104060009362008200031E00304200FF0002140031 +:1040700000621825ACA300088F620040ACA2000CBF +:104080008F620048ACA200108F62004CACA20014FA +:104090008F6200508F63004C0043102304410003E3 +:1040A000000000000A000FFA8F62004C8F6200507F +:1040B000ACA200183C02080094424B5E3C03C00BCB +:1040C00000002021004310250E0004B8ACA2001C03 +:1040D0008F6200548F840020AC8200008F620058F1 +:1040E000AC8200048F62005CAC8200088F620060CA +:1040F0008F43007400431021AC82000C8F62006477 +:10410000AC820010976300689762006A00031C008D +:104110003042FFFF00621825AC83001493620082D6 +:1041200024030080304200FF14430003000000001D +:104130000A00102EAC8000188F63000C24020001CE +:104140001062000E2402FFFF9362003E30420040E6 +:104150001440000A2402FFFF8F63000C8F4200749A +:10416000006218233C020800006210241440000280 +:10417000000028210060282100051043AC820018AF +:104180003C02080094424B5E3C03C00C000020211E +:10419000004310258F8300200E0004B8AC62001C81 +:1041A0008F6200188F8300203C05080094A54B5EA9 +:1041B00024040001AC620000AC6000048F66006C57 +:1041C0003C02400D00A22825AC6600088F6200DC8E +:1041D000AC62000CAC600010936200050002160097 +:1041E000AC620014AC6000180E0004B8AC65001C92 +:1041F000020020218FBF00148FB00010A3600005C3 +:104200000A00042127BD00188FBF00148FB00010D2 +:1042100003E0000827BD00189742007C30C600FF6D +:10422000A08600843047FFFF2402000514C2000B63 +:1042300024E3465090A201122C42000710400007D0 +:1042400024E30A0090A30112240200140062100467 +:1042500000E210210A0010663047FFFF3067FFFFC1 +:1042600003E00008A4870014AC87004C8CA201086E +:104270000080402100A0482100E2102330C600FF4A +:104280001840000393AA001324E2FFFCACA201082B +:1042900030C2000110400008000000008D020050F4 +:1042A00000E2102304410013240600058D0200548F +:1042B00010E20010000000008D02005414E2001A09 +:1042C000000000003C0208008C4200D83042002070 +:1042D0001040000A2402000191030078910200833B +:1042E000144300062402000101002021012028219E +:1042F000240600040A00105400000000A1000084FD +:1043000011400009A50200148F4301008F4201F8FB +:104310000440FFFE24020002AF4301C0A34201C4D7 +:104320003C021000AF4201F803E00008000000006A +:1043300027BDFFE88FA90028AFBF001000804021F3 +:1043400000E918231860007330C600FFA080007CCD +:10435000A08000818CA2010800E210230440004DDF +:10436000000000008C8200509483003C8C84006428 +:10437000004748233063FFFF012318210083202BCF +:1043800010800004000000008D0200640A0010B7D5 +:1043900000E210219502003C3042FFFF0122102173 +:1043A00000E21021AD02005C9502003C8D03005C30 +:1043B0003042FFFF0002104000E210210043102BAA +:1043C00010400003000000000A0010C68D02005CCF +:1043D0009502003C3042FFFF0002104000E2102135 +:1043E000AD02005CA1000084AD07004C8CA2010866 +:1043F00000E210231840000224E2FFFCACA20108F6 +:1044000030C200011040000A000000008D02005080 +:1044100000E2102304410004010020218D02005419 +:1044200014E20003000000000A0010E82406000562 +:104430008D02005414E200478FBF00103C020800B8 +:104440008C4200D8304200201040000A24020001B3 +:1044500091030078910200831443000624020001B6 +:1044600001002021240600048FBF00100A00105410 +:1044700027BD0018A1000084A50200148F4301008D +:104480008F4201F80440FFFE240200020A00110DD1 +:10449000000000008C82005C004910230043102BB8 +:1044A00054400001AC87005C9502003C3042FFFFA5 +:1044B0000062102B14400007240200029502003C09 +:1044C0008D03005C3042FFFF00621821AD03005CE9 +:1044D00024020002AD07004CA10200840E000F0A66 +:1044E0008F4401001040001B8FBF00108F4301005C +:1044F0008F4201F80440FFFE24020002AF4301C0D6 +:10450000A34201C43C021000AF4201F80A0011238B +:104510008FBF001030C200101040000E8FBF00107F +:104520008C83005C9482003C006918233042FFFFBA +:10453000006218213C023FFF3444FFFF0083102B30 +:10454000544000010080182101231021AD02005CBD +:104550008FBF001003E0000827BD001827BDFFE84B +:104560008FAA0028AFBF00100080402100EA482336 +:104570001920002130C600FF8C83005C8C8200640F +:10458000006A18230043102B5040001000691821C6 +:1045900094A2011001221021A4A2011094A20110E2 +:1045A0003042FFFF0043102B1440000A3C023FFF43 +:1045B00094A2011000431023A4A201109482003C95 +:1045C0003042FFFF0A00114200621821A4A001102E +:1045D0003C023FFF3444FFFF0083102B5440000196 +:1045E0000080182100671021AD02005CA100007C52 +:1045F0000A00118AA100008130C200101040003C66 +:10460000000000008C820050004A1023184000383F +:10461000000000009082007C24420001A082007C07 +:104620009082007C3C0308008C630024304200FF31 +:104630000043102B1440005C8FBF00108CA20108B7 +:1046400000E2102318400058000000008C83005442 +:104650009482003C006A18233042FFFF0003184395 +:10466000000210400043102A104000050000000026 +:104670008C820054004A10230A001171000210437A +:104680009482003C3042FFFF00021040AD02006403 +:104690009502003C8D0400649503003C3042FFFF0E +:1046A00000021040008220213063FFFF00831821A8 +:1046B00001431021AD02005C8D020054ACA2010840 +:1046C00024020002A10200840E000F0A8F440100A0 +:1046D000104000358FBF00108F4301008F4201F85A +:1046E0000440FFFE240200020A0011B30000000093 +:1046F000AD07004C8CA2010800E210231840000214 +:1047000024E2FFFCACA2010830C200011040000A04 +:10471000000000008D02005000E21023044100045C +:10472000010020218D02005414E20003000000006B +:104730000A0011AA240600058D02005414E2001A92 +:104740008FBF00103C0208008C4200D8304200208D +:104750001040000A240200019103007891020083B6 +:104760001443000624020001010020212406000455 +:104770008FBF00100A00105427BD0018A10000844C +:10478000A50200148F4301008F4201F80440FFFE90 +:1047900024020002AF4301C0A34201C43C02100046 +:1047A000AF4201F88FBF001003E0000827BD0018DA +:1047B0008FAA00108C8200500080402130C600FF7C +:1047C000004A102300A048211840000700E01821EB +:1047D00024020001A0800084A0A00112A482001481 +:1047E0000A001125AFAA0010A0800081AD07004C7F +:1047F0008CA2010800E210231840000224E2FFFC12 +:10480000ACA2010830C20001104000080000000006 +:104810008D0200500062102304410013240600059D +:104820008D02005410620010000000008D02005440 +:1048300014620011000000003C0208008C4200D805 +:10484000304200201040000A240200019103007849 +:10485000910200831443000624020001010020217C +:1048600001202821240600040A0010540000000042 +:10487000A1000084A502001403E00008000000006D +:1048800027BDFFE0AFBF0018274201009046000A95 +:104890008C4800148C8B004C9082008430C900FF3F +:1048A00001681823304A00FF1C60001A2D460006DC +:1048B000240200010142100410C00016304300031E +:1048C000012030210100382114600007304C000C19 +:1048D00015800009304200301440000B8FBF0018D3 +:1048E0000A001214000000000E001125AFAB0010EA +:1048F0000A0012148FBF00180E00109AAFAB001000 +:104900000A0012148FBF0018AFAB00100E0011BACE +:10491000AFAA00148FBF001803E0000827BD0020D5 +:1049200024020003A08200848C82005403E000086B +:10493000ACA201083C0200080342182190620081E9 +:10494000240600433C07601924420001A062008154 +:10495000906300813C0208008C4200C0306300FF7D +:10496000146200102403FF803C0208008C4200E027 +:104970000082102100431024AF4200243C020800B2 +:104980008C4200E03C03000A008210213042007F8C +:104990000342102100431021944500D40A000AF17B +:1049A00030A5FFFF03E000080000000027BDFFE086 +:1049B000AFBF0018AFB10014AFB000108F4201803C +:1049C0000080802100A088210E00121B00402021C1 +:1049D000A20000848E0200548FBF00188FB0001018 +:1049E000AE2201088FB1001403E0000827BD0020AB +:1049F00027BDFFE03C020008AFB00010AFBF0018B9 +:104A0000AFB10014034280218F5101409203008412 +:104A10008E0400508E02004C14820040306600FF6D +:104A20003C0208008C4200E02403FF800222102197 +:104A300000431024AF4200243C0208008C4200E0F6 +:104A40009744007C92050081022210213042007FB1 +:104A5000034218213C02000A0062182114A0000B36 +:104A60003084FFFF2402000554C20014248205DCB8 +:104A70009062011224420001A062011224020C8003 +:104A8000AF4200240A00127324020005A060011244 +:104A90002402000514C20009248205DC9202008170 +:104AA0002C4200075040000524820A009203008136 +:104AB0002402001400621004008210213044FFFF21 +:104AC000A60400140E00121B022020219602003CB6 +:104AD0008E03004C022020213042FFFF00021040D4 +:104AE000006218210E000250AE03005C9202007DAD +:104AF00002202021344200400E000259A202007D13 +:104B00008F4201F80440FFFE24020002AF5101C0B1 +:104B1000A34201C43C021000AF4201F88FBF00184D +:104B20008FB100148FB0001003E0000827BD0020F3 +:104B300008000ACC08000B1408000B9808000BE4CE +:104B400008000C200A0000280000000000000000FF +:104B50000000000D6370362E322E3300000000007E +:104B60000602030400000000000000000000000036 +:104B70000000000000000000000000000000000035 +:104B80000000000000000000000000000000002005 +:104B90000000000000000000000000000000000015 +:104BA0000000000000000000000000000000000005 +:104BB00000000000000000000000000000000001F4 +:104BC0000000002B000000000000000400030D4066 +:104BD00000000000000000000000000000000000D5 +:104BE00000000000000000001000000300000000B2 +:104BF0000000000D0000000D3C020800244258A4F3 +:104C00003C03080024635F70AC4000000043202B8D +:104C10001480FFFD244200043C1D080037BD7FFCCA +:104C200003A0F0213C100800261000A03C1C080046 +:104C3000279C58A40E0001AC000000000000000DED +:104C400027BDFFE83C096018AFBF00108D2C500055 +:104C5000240DFF7F24080031018D5824356A380C5B +:104C600024070C003C1A8000AD2A50003C04800A46 +:104C7000AF4800083C1B8008AF4700240E00091510 +:104C8000AF8400100E0008D8000000000E000825B8 +:104C9000000000000E001252000000003C046016EC +:104CA0008C8500003C06FFFF3C02535300A61824ED +:104CB0001062004734867C0094C201F2A780002C69 +:104CC00010400003A78000CC38581E1EA798002C67 +:104CD00094C201F810400004978300CC38591E1E7E +:104CE000A79900CC978300CC2C7F006753E000018C +:104CF000240300669784002C2C82040114400002D7 +:104D000000602821240404003C0760008CE904387A +:104D10002403103C3128FFFF1103001F30B9FFFFAF +:104D200057200010A38000CE24020050A38200CEA2 +:104D3000939F00CE53E0000FA78500CCA78000CC46 +:104D4000978500CC8FBF0010A780002CA78000346F +:104D5000A78000E63C010800AC25008003E00008C5 +:104D600027BD0018939F00CE57E0FFF5A78000CC29 +:104D7000A78500CC978500CC8FBF0010A784002C9E +:104D8000A7800034A78000E63C010800AC25008025 +:104D900003E0000827BD0018A38000CE8CCB003CA8 +:104DA000316A00011140000E0000000030A7FFFF33 +:104DB00010E0FFDE240200508CCC00C831860001D8 +:104DC00014C0FFDC939F00CE0A00007A2402005139 +:104DD0008C8F00043C0E60000A00005D01EE302163 +:104DE0008CEF0808240D5708000F740211CD000441 +:104DF00030B8FFFF240500660A00007B240404008D +:104E00001700FFCC939F00CE0A00007A24020050C6 +:104E10008F8600103089FFFF000939408CC30010D5 +:104E20003C08005000E82025AF4300388CC5001432 +:104E300027420400AF82001CAF45003CAF44003065 +:104E40000000000000000000000000000000000062 +:104E50000000000000000000000000000000000052 +:104E60008F4B0000316A00201140FFFD0000000060 +:104E700003E00008000000008F840010948A001AEC +:104E80008C8700243149FFFF000940C000E8302131 +:104E9000AF46003C8C8500248F43003C00A31023C8 +:104EA00018400029000000008C8B002025620001C2 +:104EB0003C0D005035AC0008AF420038AF4C00301C +:104EC00000000000000000000000000000000000E2 +:104ED00000000000000000000000000000000000D2 +:104EE0008F4F000031EE002011C0FFFD00000000D8 +:104EF0008F4A04003C080020AC8A00108F4904044B +:104F0000AC890014AF4800300000000094860018FF +:104F10009487001C00C71821A48300189485001AE8 +:104F200024A20001A482001A9498001A9499001EE9 +:104F3000133800030000000003E000080000000038 +:104F400003E00008A480001A8C8200200A0000DC24 +:104F50003C0D00500A0000CD000000003C0308009A +:104F60008C6300208F82001827BDFFE810620008C4 +:104F7000AFBF00100E000104AF8300183C0308000F +:104F80008C63002024040001106400048F89001049 +:104F90008FBF001003E0000827BD00188FBF00106E +:104FA0003C076012A520000A9528000A34E500108D +:104FB00027BD00183106FFFF03E00008ACA60090F3 +:104FC0003C0208008C42002027BDFFC8AFBF003460 +:104FD000AFBE0030AFB7002CAFB60028AFB500248D +:104FE000AFB40020AFB3001CAFB20018AFB10014D3 +:104FF00010400050AFB000108F840010948600065F +:105000009483000A00C3282330B6FFFF12C0004A71 +:105010008FBF003494890018948A000A012A402323 +:105020003102FFFF02C2382B14E0000202C020212F +:10503000004020212C8C0005158000020080A0215A +:10504000241400040E0000B3028020218F8700107A +:1050500002809821AF80001494ED000A028088211C +:105060001280004E31B2FFFF3C1770003C1540002B +:105070003C1E60008F8F001C8DEE000001D71824AD +:10508000507500500220202102A3802B160000350D +:105090003C182000507800470220202124100001F5 +:1050A0008F83001414600039029158230230F823D2 +:1050B0000250C82133F1FFFF1620FFEE3332FFFF0D +:1050C0008F8700103C110020AF510030000000001D +:1050D00094E6000A3C1E601237D5001002662821B3 +:1050E000A4E5000A94E2000A94F2000A94F400187D +:1050F0003057FFFF1292003BAEB700908CED0014CA +:105100008CE400100013714001AE4021000E5FC31B +:10511000010E502B008B4821012A1821ACE8001405 +:10512000ACE3001002D3382330F6FFFF16C0FFB9FE +:105130008F8400108FBF00348FBE00308FB7002CDB +:105140008FB600288FB500248FB400208FB3001CC9 +:105150008FB200188FB100148FB0001003E0000868 +:1051600027BD0038107E001B000000001477FFCC24 +:10517000241000010E00159B000000008F83001416 +:105180001060FFCB0230F823029158238F87001064 +:10519000017020210A0001973093FFFF8F830014D4 +:1051A0001460FFCB3C110020AF5100300A000163B6 +:1051B000000000000E00077D024028210A00015770 +:1051C000004080210E00033A024028210A000157C6 +:1051D000004080210E001463022020210A000157A4 +:1051E000004080210E0000CD000000000A0001797F +:1051F00002D3382327BDFFE8AFB00010AFBF0014C3 +:105200000E00003F000000003C028000345000709F +:105210000A0001BA8E0600008F4F000039EE00012F +:1052200031C20001104000248F8600A88E070000C4 +:105230003C0C08008D8C003C3C0908008D2900388E +:1052400000E66823018D28210000502100AD302B9D +:10525000012A4021010620213C010800AC25003C28 +:10526000AF8700A83C010800AC2400380E000106FE +:10527000000000003C0308008C6300701060FFE633 +:10528000006020213C0508008CA500683C06080051 +:105290008CC6006C0E00152A000000003C010800BE +:1052A000AC2000708F4F000039EE000131C20001C8 +:1052B0001440FFDE8F8600A88E0A00008F8B00A8A6 +:1052C0003C0508008CA5003C3C0408008C84003898 +:1052D000014B482300A938210082182100E9402B06 +:1052E000006810213C010800AC27003C3C0108008C +:1052F000AC2200388F5F01002419FF0024180C0035 +:1053000003F9202410980012AF840000AF4400205D +:10531000936D0000240C002031A600FF10CC001279 +:10532000240E005010CE00043C194000AF59013843 +:105330000A0001B3000000000E0011C800000000C8 +:105340003C194000AF5901380A0001B300000000C9 +:105350000E00011F000000003C194000AF59013849 +:105360000A0001B3000000008F58010000802821CE +:10537000330F00FF01E020210E0002F1AF8F000487 +:105380003C194000AF5901380A0001B30000000089 +:1053900000A4102B2403000110400009000030215C +:1053A0000005284000A4102B04A0000300031840AF +:1053B0005440FFFC000528405060000A0004182BF0 +:1053C0000085382B54E000040003184200C3302548 +:1053D00000852023000318421460FFF900052842CD +:1053E0000004182B03E0000800C310218F4201B80D +:1053F0000440FFFE00000000AF4401803C031000A9 +:1054000024040040AF450184A3440188A3460189D8 +:10541000A747018A03E00008AF4301B83084FFFFCB +:105420000080382130A5FFFF000020210A00022A59 +:10543000240600803087FFFF8CA40000240600387B +:105440000A00022A000028218F8300388F8600304E +:105450001066000B008040213C07080024E75A1822 +:10546000000328C000A710218C4400002463000121 +:10547000108800053063000F5466FFFA000328C04F +:1054800003E00008000010213C07080024E75A1C34 +:1054900000A7302103E000088CC200003C0390000C +:1054A0003462000100822025AF4400208F45002097 +:1054B00004A0FFFE0000000003E000080000000060 +:1054C0003C038000346200010082202503E00008D4 +:1054D000AF44002027BDFFE0AFB100143091FFFFC3 +:1054E000AFB00010AFBF00181220001300A0802141 +:1054F0008CA2000024040002240601401040000F8A +:10550000004028210E000C5C00000000000010216B +:10551000AE000000022038218FBF00188FB10014A8 +:105520008FB0001000402021000028210000302111 +:105530000A00022A27BD00208CA200000220382188 +:105540008FBF00188FB100148FB0001000402021D1 +:1055500000002821000030210A00022A27BD002077 +:1055600000A010213087FFFF8CA500048C440000B0 +:105570000A00022A2406000627BDFFE0AFB0001093 +:10558000AFBF0018AFB100149363003E00808021CC +:105590000080282130620040000020211040000FD0 +:1055A0008E1100000E000851022020219367000098 +:1055B0002404005030E500FF50A400128E0F0000BC +:1055C000022020218FBF00188FB100148FB000106F +:1055D000A762013C0A00091127BD00200E000287C6 +:1055E000000000000E0008510220202193670000F7 +:1055F0002404005030E500FF14A4FFF20220202113 +:105600008E0F00003C1008008E1000503C0D000C66 +:10561000240BFF8001F05021314E007F01DA602120 +:10562000018D4021014B4824AF4900280220202150 +:105630008FBF00188FB100148FB00010A50200D6E4 +:1056400027BD00200A000911AF8800D027BDFFE068 +:10565000AFBF0018AFB10014AFB0001093660001E7 +:10566000008080210E00025630D1000493640005B2 +:10567000001029C2A765000034830040A363000521 +:105680000E00025F020020210E00091302002021FB +:1056900024020001AF62000C02002821A762001062 +:1056A00024040002A762001224060140A76200142D +:1056B0000E000C5CA76200161620000F8FBF0018AA +:1056C000978C00343C0B08008D6B00782588FFFF19 +:1056D0003109FFFF256A0001012A382B10E000067E +:1056E000A78800343C0F6006240E001635ED00102C +:1056F000ADAE00508FBF00188FB100148FB00010F6 +:1057000003E0000827BD002027BDFFE0AFB1001473 +:10571000AFBF0018AFB0001000A088211080000AB1 +:105720003C03600024020080108200120000000090 +:105730000000000D8FBF00188FB100148FB0001053 +:1057400003E0000827BD00208C682BF80500FFFE51 +:1057500000000000AC712BC08FBF00188FB1001487 +:105760008FB000103C09100027BD002003E00008A6 +:10577000AC692BF80E00025600A0202193650005AD +:10578000022020210E00025F30B000FF2403003E03 +:105790001603FFE7000000008F4401780480FFFE3D +:1057A000240700073C061000AF51014002202021D1 +:1057B000A34701448FBF00188FB100148FB00010B1 +:1057C000AF4601780A0002C227BD002027BDFFE8CE +:1057D000AFBF0014AFB000108F50002000000000D9 +:1057E0000E000913AF440020AF5000208FBF0014FB +:1057F0008FB0001003E0000827BD00183084FFFFC1 +:10580000008038212406003500A020210A00022A49 +:10581000000028213084FFFF008038212406003654 +:1058200000A020210A00022A0000282127BDFFD065 +:10583000AFB3001C3093FFFFAFB50024AFB2001828 +:10584000AFBF0028AFB40020AFB10014AFB000105C +:1058500030B5FFFF12600027000090218F90001CE0 +:105860008E0300003C0680002402004000033E023C +:1058700000032C0230E4007F006688241482001D9F +:1058800030A500FF8F8300282C68000A510000100B +:105890008F910014000358803C0C0800258C56940E +:1058A000016C50218D49000001200008000000001B +:1058B00002B210213045FFFF0E000236240400849E +:1058C000162000028F90001CAF8000288F910014DA +:1058D000260C002026430001018080213072FFFF4A +:1058E00016200004AF8C001C0253502B1540FFDC27 +:1058F00000000000024010218FBF00288FB5002457 +:105900008FB400208FB3001C8FB200188FB1001429 +:105910008FB0001003E0000827BD0030240E0034D3 +:1059200014AE00F9000000009203000E241F168040 +:105930003C07000CA36300219202000D0347C8211D +:105940003C066000A3620020961100123C0A7FFF13 +:10595000354CFFFFA771003C960B00102403000597 +:105960003168FFFFAF6800848E05001CAF5F002820 +:105970008F3800008CC4444803057826008F3021FE +:10598000AF66004C8F69004C24CE00013C057F00BF +:10599000AF6900508F740050AF740054AF66007050 +:1059A000AF6E00588F6D005824140050AF6D005C2E +:1059B000A3600023AF6C0064A36300378E02001461 +:1059C000AF6200488F710048AF7100248E0B001841 +:1059D000AF6B006C9208000CA3680036937F003E0A +:1059E00037F90020A379003E8F78007403058024E6 +:1059F000360F4000AF6F007493640000308900FFE1 +:105A0000513402452404FF803C04080024845A9841 +:105A10000E00028D000000003C1008008E105A9805 +:105A20000E00025602002021240600042407000173 +:105A3000A366007D020020210E00025FA36700051F +:105A40008F5F017807E0FFFE240B0002AF5001409A +:105A5000A34B01448F90001C3C081000AF48017814 +:105A60000A000362AF8000282CAD003751A0FF98D8 +:105A70008F9100140005A0803C180800271856BC20 +:105A8000029878218DEE000001C00008000000009F +:105A90002418000614B80011000000003C0808009B +:105AA0008D085A9824040005AF4800208E1F001866 +:105AB000AF7F00188F79004CAF79001C8F650050C4 +:105AC000122000C0AF6500700A000362AF84002896 +:105AD0002406000710A60083240300063C050800E6 +:105AE00024A55A980E000264240400818F90001CA3 +:105AF0000011102B0A000362AF8200282407000463 +:105B000014A7FFF6240500503C1808008F185A9877 +:105B1000AF5800208E0F0008AF6F00408E090008BC +:105B2000AF6900448E14000CAF7400488E0E001054 +:105B3000AF6E004C8E0D0010AF6D00848E0A001405 +:105B4000AF6A00508E0C0018AF6C00548E04001C1D +:105B5000AF64005893630000306B00FF116501D8FB +:105B6000000000008F7400488F6900400289702394 +:105B700005C000042404008C1620FFDE240200036C +:105B8000240400823C05080024A55A980E000287D0 +:105B9000000000008F90001C000010210A0003622A +:105BA000AF820028240F000514AFFFCC240520008D +:105BB0003C0708008CE75A98AF4700208E06000487 +:105BC000AF66005C9208000824100008A36800215A +:105BD0008F9F001C93F90009A37900208F86001C79 +:105BE00090D8000A330400FF10900011000000005C +:105BF0002885000914A0006924020002240A00205C +:105C0000108A000B34058000288D002115A00008A3 +:105C100024054000240E0040108E00053C050001C4 +:105C200024140080109400023C050002240540006A +:105C30008F7800743C19FF00031980240205782531 +:105C4000AF6F007490C4000BA36400818F84001CAC +:105C50009489000C11200192000000009490000C27 +:105C60002406FFBF24050004A770003C908F000E9F +:105C7000A36F003E8F84001C9089000FA369003F32 +:105C80008F8B001C8D6E00108F54007401D468231C +:105C9000AF6D00608D6A0014AF6A0064956C0018E7 +:105CA000A76C00689563001AA763006A8D62001CE8 +:105CB000AF62006C9167000EA367003E9368003EE0 +:105CC0000106F8241220014BA37F003E8F90001C98 +:105CD0000A000362AF8500282407002214A7FF7F73 +:105CE000240300073C0B08008D6B5A981220000C0F +:105CF000AF4B00200A000362AF830028240C00335E +:105D000010AC0014240A00283C05080024A55A9869 +:105D10000E00023C240400810A0003EB8F90001C5B +:105D20003C04080024845A980E00028D00000000F4 +:105D30009363000024110050306200FF10510135C0 +:105D4000000000008F90001C000018210A00036270 +:105D5000AF8300283C0D08008DAD5A9824040081C3 +:105D6000AF4D00203C05080024A55A980E00023CC7 +:105D7000A36A00348F90001C240200090A00036209 +:105D8000AF82002802B288213225FFFF0E000236C2 +:105D9000240400840A0003628F90001C1082FFA478 +:105DA00024050400288B000311600170240C0004FA +:105DB000240300015483FF9E240540000A00043B95 +:105DC000240501003C04080024845A988F62004C8A +:105DD0000E00028D8F6300508F90001C0000202168 +:105DE0000A000362AF8400288E1000042404008A95 +:105DF000AF50002093790005333800021700015F8F +:105E0000020028219368002302002821311F00206E +:105E100017E0015A2404008D9367003F2406001206 +:105E200030E200FF10460155240400810E000256A6 +:105E30000200202193630023240500040200202196 +:105E4000346B0042A36B00230E00025FA365007D4C +:105E50008F4401780480FFFE240A0002AF50014005 +:105E6000A34A01448F90001C3C0C1000AF4C0178F9 +:105E70000A0003EC0011102B8E1000042404008A89 +:105E8000AF500020936E000531CD000215A0001622 +:105E900002002821936F003F2414000402002821EF +:105EA00031E900FF11340010240400810E00025675 +:105EB000020020219362002324080012241FFFFE09 +:105EC00034460020A3660023A368003F93790005B1 +:105ED00002002021033FC0240E00025FA3780005CA +:105EE00002002821000020210E00033400000000E1 +:105EF0000A0003EB8F90001C8E1000043C03000886 +:105F00000343A021AF500020928B000024050050D5 +:105F1000316400FF10850161240700880200202100 +:105F2000000028210E00022A2406000E928D000097 +:105F3000240EFF800200282101AE8025A2900000DF +:105F4000240400040E000C5C240600300A0003EB5D +:105F50008F90001C8E0800043C14080026945A9868 +:105F60003C010800AC285A98AF480020921F00035B +:105F700033F9000413200002240200122402000658 +:105F8000A362003F920B001B2404FFC03165003F59 +:105F900000A43825A367003E9206000330C200012A +:105FA00014400132000000008E020008AE8200089A +:105FB0003C0208008C425AA010400131000249C244 +:105FC000A76900088E14000C240C0001240300149F +:105FD000AF74002C8E0E0010AF6E0030960D0016C0 +:105FE000A76D0038960A0014A76A003AAF6C000C3F +:105FF000A76C0010A76C0012A76C0014A76C001609 +:1060000012200136A3630034920F000331F0000226 +:106010002E1100018F90001C262200080A00036246 +:10602000AF8200288E0400043C0E0008034E30218D +:10603000AF4400208E05000890CD0000240C0050D5 +:1060400031AA00FF114C00862407008824060009AD +:106050000E00022A000000000A0003EB8F90001CD3 +:106060008E04001C0E00024100000000104000F4ED +:10607000004050218F89001C240700890140202105 +:106080008D25001C240600010E00022A00000000DD +:106090000A0003EB8F90001C960D00023C140800D0 +:1060A00026945A9831AA0004514000B83C10600070 +:1060B0008E0E001C3C010800AC2E5A98AF4E0020FA +:1060C000920700102408001430E200FF144800D6A4 +:1060D00000000000960B00023163000114600165AE +:1060E000000000008E020004AE8200083C1408008C +:1060F0008E945AA01280015B000000008F7400741F +:106100003C0380002404000102835825AF6B007417 +:10611000A3600005AF64000C3C0708008CE75AA0A0 +:106120008F86001CA7640010000711C2A76400122C +:10613000A7640014A7640016A76200088CC80008B2 +:1061400024040002AF68002C8CC5000CAF65003041 +:1061500090DF0010A37F00348F99001C9330001152 +:10616000A37000358F98001C930F0012A36F0036A8 +:106170008F89001C912E0013A36E00378F90001C96 +:10618000960D0014A76D0038960A0016A76A003A0B +:106190008E0C0018AF6C00245620FDCCAF84002874 +:1061A0003C05080024A55A980E0002640000202136 +:1061B0008F90001C0A0004A7000020218E1000040C +:1061C00024070081AF500020936900233134001070 +:1061D000128000170000000002002021000028218A +:1061E0002406001F0E00022A000000000A0003EB34 +:1061F0008F90001C3C05080024A55A980E000287C9 +:10620000240400828F90001C000028210A000362F1 +:10621000AF8500283C0408008C845A980E0014E8CE +:10622000000000008F90001C0A000482000018216A +:106230000E00025602002021937800230200202144 +:10624000370F00100E00025FA36F002300003821FB +:1062500002002021000028210A0005A82406001FB2 +:10626000920F000C31E90001112000030000000032 +:106270009618000EA4D8002C921F000C33F90002CF +:1062800013200005000038218E0200149608001229 +:10629000ACC2001CA4C8001A0A0005432406000969 +:1062A0003C05080024A55A980E0002872404008BA0 +:1062B0008F90001C0011282B0A000362AF85002874 +:1062C000AF6000843C0A08008D4A5A983C0D0800D3 +:1062D0008DAD0050240CFF803C02000C014D1821B4 +:1062E000006C2024AF4400288E070014306B007F20 +:1062F000017A282100A2C821AF2700D88E060014F9 +:10630000AF9900D0AF2600DC8E080010251FFFFEDD +:106310000A000408AF3F01083C0508008CA55A9804 +:106320003C1908008F39005024CCFFFE00B9C02171 +:1063300003047824AF4F00283C1408008E945A9828 +:106340003C0908008D2900500289702131CD007F61 +:1063500001BA502101478021AE0600D8AF9000D08D +:10636000AE0000DC0A0003B1AE0C0108548CFE3014 +:10637000240540000A00043B240510000E00032EF3 +:10638000000000000A0003EB8F90001C8E0F442CCD +:106390003C186C62370979703C010800AC205A98AF +:1063A00015E9000824050140979F00349786002CCA +:1063B0000280282103E6C82B132000112404009238 +:1063C000240501400E000C7A240400023C01080060 +:1063D000AC225A98AF4200203C0508008CA55A9880 +:1063E00010A00005240400830E00084500000000F2 +:1063F00010400009240400833C05080024A55A9895 +:106400000E000264000000008F90001C0011202B81 +:106410000A000362AF8400280E0008490000000053 +:106420000A00055F8F90001C0E00084D0000000060 +:106430003C05080024A55A980A00062F2404008B66 +:10644000240400040E000C7A240500301440002AB5 +:10645000004050218F89001C240700830140202127 +:106460008D25001C0A000551240600018E04000839 +:106470000E000241000000000A00051BAE82000869 +:106480003C05080024A55A980E00023C240400870D +:106490008F90001C0A0005360011102B8F830038E6 +:1064A0008F8600301066FE9D000038213C070800F2 +:1064B00024E75A1C000320C0008728218CAC000070 +:1064C00011900061246A00013143000F5466FFFA05 +:1064D000000320C00A0004F6000038213C05080033 +:1064E00024A55A980E000287240400828F90001C75 +:1064F0000A000536000010213C0B0008034B202148 +:106500002403005024070001AF420020A0830000B4 +:10651000A08700018F82001C90480004A08800180A +:106520008F85001C90A60005A08600198F9F001C77 +:1065300093F90006A099001A8F90001C921800078A +:10654000A098001B8F94001C928F0008A08F001C45 +:106550008F89001C912E0009A08E001D8F8D001CBC +:1065600091AC000AA08C001E8F8B001C3C0C080014 +:10657000258C5A1C9163000B3C0B0800256B5A18A4 +:10658000A083001F8F87001C90E8000CA0880020CB +:106590008F82001C9045000D24024646A0850021F4 +:1065A0008F86001C90DF000EA09F00228F99001C98 +:1065B0009330000FA09000238F98001C93140010BC +:1065C000A09400248F8F001C91E90011A089002560 +:1065D0008F89001C8F8E00308F900038952D00140D +:1065E000000E18C025C80001A48D002895270016AC +:1065F000006C3021006BC821A487002A9525001863 +:106600003108000FA485002CA482002E8D3F001CB1 +:10661000ACCA0000AF88003011100006AF3F000088 +:10662000000038218D25001C014020210A00055161 +:1066300024060001250C00013184000F00003821E0 +:106640000A0006B8AF8400383C07080024E75A184F +:106650000087302100003821ACA000000A0004F6B9 +:10666000ACC000003C05080024A55A980A00062F7B +:10667000240400878E0400040E0002410000000084 +:106680000A00056AAE8200083084FFFF30C600FFB2 +:106690008F4201B80440FFFE00064400010430258B +:1066A0003C07200000C720253C031000AF400180BC +:1066B000AF450184AF44018803E00008AF4301B84F +:1066C00027BDFFE8AFB00010AFBF00143C0760006B +:1066D000240600021080000600A080210010102B6C +:1066E0008FBF00148FB0001003E0000827BD001812 +:1066F0003C09600EAD2000348CE5201C8F82001C0C +:106700002408FFFC00A81824ACE3201C0E0006D1CE +:106710008C45000C0010102B8FBF00148FB00010A0 +:1067200003E0000827BD00183C02600E344701005A +:1067300024090018274A040000000000000000009F +:10674000000000003C06005034C30200AF44003893 +:10675000AF45003CAF430030014018218F4B000093 +:10676000316800201100FFFD2406007F2408FFFF90 +:106770008C6C000024C6FFFF24630004ACEC000016 +:1067800014C8FFFB24E70004000000000000000024 +:10679000000000003C0F0020AF4F00300000000060 +:1067A00024AD020001A5702B2529FFFF008E2021BA +:1067B0001520FFE101A0282103E0000800000000EF +:1067C00027BDFFE0AFB10014AFBF0018AFB000109D +:1067D0003C05600E8CA20034008088211440000625 +:1067E0003C0460008C87201C2408FFFC00E8302457 +:1067F00034C30001AC83201C8F8B001C24090001D2 +:10680000ACA90034956900028D6500148D70000CF0 +:106810002D2400818D6700048D660008108000071C +:106820008D6A00102D2C00041580000E30CE00075C +:10683000312D000311A0000B000000002404008B88 +:10684000020028210E0006D1240600030011102B9F +:106850008FBF00188FB100148FB0001003E0000844 +:1068600027BD002015C0FFF62404008B3C03002048 +:10687000AF4300300000000024020001AF8200148A +:106880000000000000000000000000003C1F01505C +:10689000013FC825253800033C0F600EAF47003884 +:1068A00000181882AF46003C35E8003CAF59003074 +:1068B000274704008F4400003086002010C0FFFDF1 +:1068C00000000000106000082466FFFF2403FFFFA3 +:1068D0008CEB000024C6FFFF24E70004AD0B000092 +:1068E00014C3FFFB250800043C08600EAD09003806 +:1068F0000000000000000000000000003C07002035 +:10690000AF470030000000000E0006F901402021D2 +:1069100002002821000020210E0006D124060003D9 +:106920000011102B8FBF00188FB100148FB0001012 +:1069300003E0000827BD002027BDFFE0AFB200182C +:106940003092FFFFAFB10014AFBF001CAFB000101A +:106950001640000D000088210A0007AA022010211D +:1069600024050001508500278CE5000C0000000D77 +:10697000262300013071FFFF24E200200232382B71 +:1069800010E00019AF82001C8F8200141440001622 +:106990008F87001C3C0670003C0320008CE5000043 +:1069A00000A62024148300108F84003C00054402BC +:1069B0003C09800000A980241480FFE9310600FF13 +:1069C0002CCA00095140FFEB262300010006688015 +:1069D0003C0E080025CE579801AE60218D8B00003B +:1069E0000160000800000000022010218FBF001C81 +:1069F0008FB200188FB100148FB0001003E00008B0 +:106A000027BD00200E0006D1240400841600FFD804 +:106A10008F87001C0A00078BAF80003C90EF0002BC +:106A200000002021240600090E0006D1000F2E00D0 +:106A30008F87001C0010102B0A00078BAF82003CD0 +:106A4000020028210E0006DF240400018F87001CAD +:106A50000A00078BAF82003C020028210E0006DFEF +:106A6000000020210A0007C38F87001C0E00071FAB +:106A7000020020210A0007C38F87001C30B0FFFFEF +:106A8000001019C08F5801B80700FFFE3C1F2004FA +:106A90003C191000AF430180AF400184AF5F018813 +:106AA000AF5901B80A00078C262300013082FFFF8E +:106AB00014400003000018210004240224030010E5 +:106AC000308500FF14A000053087000F2466000801 +:106AD0000004220230C300FF3087000F14E00005DD +:106AE000308900032468000400042102310300FF00 +:106AF0003089000315200005388B0001246A00024C +:106B000000042082314300FF388B00013164000112 +:106B100010800002246C0001318300FF03E00008B4 +:106B200000601021308BFFFF000B394230E600FF80 +:106B30003C09080025295998000640800109602178 +:106B40008D8700003164001F240A0001008A1804A8 +:106B500030A500FF00E3202514A000020003102749 +:106B600000E22024240F000100CF700401096821F5 +:106B7000000E282714800005ADA400008F86000CAD +:106B800000A6102403E00008AF82000C8F88000CE0 +:106B900001C8102503E00008AF82000C3C06001F6E +:106BA0003C0360003084FFFF34C5FF8024020020D6 +:106BB000AC602008AC60200CAC602010AC652014E8 +:106BC000AC642018AC62200000000000000000004F +:106BD00003E000080000000027BDFFE82402FFFFDB +:106BE000AFBF0010AF82000C000020213C0608005F +:106BF00024C659982405FFFF248900010004408021 +:106C00003124FFFF010618212C87002014E0FFFA31 +:106C1000AC6500000E0008160000202124020001CF +:106C20003C04600024050020AC822018AC852000C4 +:106C3000000000000000000000000000244A0001E5 +:106C40003142FFFF2C46040014C0FFF78FBF001035 +:106C500003E0000827BD00188F8300082C620400A1 +:106C600003E00008384200018F830008246200011D +:106C700003E00008AF8200088F8300082462FFFF52 +:106C800003E00008AF82000827BDFFE0AFB10014A9 +:106C9000AFBF0018AFB000108F6B00303C06600033 +:106CA00000808821ACCB20088F6A002C3C02800039 +:106CB00024030008ACCA200C9769003A9768003892 +:106CC00000092C003107FFFF00A72025ACC42010CD +:106CD000ACC22014ACC32000000000000000000083 +:106CE000000000003C0360008C6D200031AC000807 +:106CF0001580FFF9000000008C6E201405C00020F4 +:106D0000000000000E0007DA8F84000C00024080B3 +:106D10003C09080025295998010938218CE4000014 +:106D20000E0007DA00028140020220213090FFFFAE +:106D3000020020210E0007F8000028213C0C8000F2 +:106D4000022C58253210FFFF3C116000240A00205D +:106D5000AE2B2014AE302018AE2A20000000000018 +:106D60000000000000000000020010218FBF00188A +:106D70008FB100148FB0001003E0000827BD002081 +:106D80008C6620143C02001F3443FF803C1FFFE848 +:106D900000C3C02437F9080003198021001079C20C +:106DA0003C0C8000022C582531F0FFFF3C116000A4 +:106DB000240A0020AE2B2014AE302018AE2A20006A +:106DC0000000000000000000000000000200102190 +:106DD0008FBF00188FB100148FB0001003E00008BF +:106DE00027BD002027BDFFE8AFB000103402FFFF31 +:106DF0003090FFFFAFBF00141202000602002021F6 +:106E00000E00081600000000020020210E0007F806 +:106E1000240500018F8400088FBF00148FB000107C +:106E20002483FFFF27BD001803E00008AF8300089C +:106E3000000439C230E6003F00043B42000718401E +:106E4000240210002CC4002024C8FFE0AF42002C14 +:106E5000246300011480000330A900FF00071840DC +:106E6000310600FF0003608024080001019A5821C8 +:106E70003C0A000E00C82804016A382111200005D0 +:106E8000000530278CE900000125302503E00008CB +:106E9000ACE600008CEE000001C6682403E00008A8 +:106EA000ACED000027BDFFE8AFBF0014AFB000108D +:106EB0003C0460008C8508083403F00030A2F00028 +:106EC00050430006240200018C8708083404E000C7 +:106ED00030E6F00010C4001E24020002AF82004021 +:106EE0003C1060003C0A0200AE0A0814240910009D +:106EF0003C08000E8E03440003482021AF49002CBB +:106F0000240501200E000CC0000030218F830040BA +:106F1000106000043C021691240B0001106B000E5F +:106F20003C023D2C344F0090AE0F44088FBF00143C +:106F30008FB000103C0C6000240E10003C0D0200CD +:106F400027BD0018AD8E442003E00008AD8D081069 +:106F50000A0008E7AF8000403C0218DA344F009086 +:106F6000AE0F44088FBF00148FB000103C0C6000BF +:106F7000240E10003C0D020027BD0018AD8E4420E9 +:106F800003E00008AD8D08100A0008BB24050001CD +:106F90000A0008BB000028213C08080025085DA461 +:106FA0002404FFFF010018212402001E2442FFFFD9 +:106FB000AC6400000441FFFD246300043C070800AA +:106FC00024E75E208CE5FFFC2404001C240600015D +:106FD000308A001F0146480424840001000910275C +:106FE0002C8300201460FFFA00A22824ACE5FFFCEB +:106FF0003C05666634A4616E3C06080024C65EE06B +:10700000AF840058AF88009C2404FFFF00C0182103 +:107010002402001F2442FFFFAC6400000441FFFD76 +:10702000246300043C0766663C05080024A55EA0B6 +:10703000AF86004834E6616EAF8600982404FFFFF7 +:1070400000A018212402000F2442FFFFAC640000BE +:107050000441FFFD246300043C0B66663C06080007 +:1070600024C65E203568616EAF8500A4AF880070CD +:107070002404FFFF00C018212402001F2442FFFF48 +:10708000AC6400000441FFFD246300043C0D66660F +:107090003C0A0800254A5F6035AC616EAF860090FF +:1070A000AF8C005C2404FFFF014018212402000380 +:1070B0002442FFFFAC6400000441FFFD2463000490 +:1070C0003C09080025295F708D27FFFC2404000679 +:1070D000240500013099001F0325C0042484000109 +:1070E000001878272C8E002015C0FFFA00EF3824F6 +:1070F000AD27FFFC3C09666624030400240403DC7E +:1071000024050200240600663522616E3C08080052 +:1071100025085AA4AF820074AF830044AF83006C8B +:10712000AF830050AF830084AF8A008CAF840064CB +:10713000AF85004CAF860054AF840078AF85006007 +:10714000AF86008001001821240200022442FFFFC4 +:10715000AC6000000441FFFD24630004240400032C +:107160002403000C3C0A0800254A5AB0AF8A006884 +:107170000A00098E2405FFFF000418802484000102 +:10718000006858212C8700C014E0FFFBAD650000AB +:107190003C0E666635CD616E240C17A024081800DD +:1071A000AF8D0088AF8C009403E00008AF88007CAE +:1071B0002484007F000421C200004021000030210F +:1071C00000003821000028210A0009A5AF8400A092 +:1071D0001060000624E7000100C4302124A500014E +:1071E0002CC20BF51440FFFA2CA300663C090800E2 +:1071F00025295F6001201821240200032442FFFF9B +:10720000AC6000000441FFFD2463000410E0001A9C +:1072100024E3FFFF0003294210A0000A0000202100 +:107220002406FFFF3C03080024635F602484000100 +:107230000085502BAC660000250800011540FFFBBF +:107240002463000430E2001F10400008000868803A +:10725000240C0001004C38040008588001692821E2 +:1072600024E6FFFF03E00008ACA6000001A94021CE +:107270002409FFFFAD09000003E000080000000042 +:10728000AF4400283C04000C034420210005288260 +:107290000A000CC000003021000421803C03600083 +:1072A000AC6410080000000000052980AC65100CDB +:1072B0000000000003E000088C62100C27BDFFE80E +:1072C0000080282124040038AFBF00140E0009D527 +:1072D000AFB0001024040E00AF4400283C10000C96 +:1072E00003502021240500100E000CC000003021A6 +:1072F00003501021AC400000AC40000424040038CE +:107300008FBF00148FB0001024053FFF27BD001869 +:107310000A0009D58C430000000421803C03600072 +:10732000AC641008000000008C62100C03E0000840 +:107330000002118227BDFFC8AFB400208F940068FF +:10734000AFBE0030AFB7002CAFB600280000B821A8 +:107350000080B021241E00C0AFBF0034AFB50024B0 +:10736000AFB3001CAFB20018AFB10014AFB0001043 +:107370000A000A12AFA5003C504000018F9400683B +:1073800027DEFFFF13C00028269400048E92000021 +:107390003C03080024635DA01240FFF70283102B1A +:1073A0003C04080024845AA4028410230002A8C0CC +:1073B000000098210A000A212411000100118840D0 +:1073C000122000260000000002B380210251282470 +:1073D0000200202110A0FFF9267300010E0009DE33 +:1073E000000000000016684032EC000101AC2021D2 +:1073F0000E0009D5020028218F89009426F700018C +:107400008FA6003C3AEB0001316A00012528FFFFFE +:107410000011382702CAB021AF88009416E6FFE7B2 +:1074200002479024AE92000002E010218FBF00348A +:107430008FBE00308FB7002C8FB600288FB5002488 +:107440008FB400208FB3001C8FB200188FB10014CE +:107450008FB0001003E0000827BD00383C0E080084 +:1074600025CE5DA0028E102B0A000A0DAE92000000 +:1074700027BDFFD8AFB10014AFB00010AFBF0020E0 +:10748000AFB3001CAFB2001800A0882110A0001FED +:10749000000480403C13080026735AA40A000A5ACC +:1074A0002412000112200019261000010E0009F517 +:1074B00002002021000231422444FFA0000618806F +:1074C0003045001F2C8217A1007318212631FFFFC1 +:1074D0001040FFF400B230048C690000020020214B +:1074E00024053FFF012640241500FFEE0126382524 +:1074F0000E0009D5AC6700008F8A009426100001A9 +:10750000254700011620FFE9AF8700948FBF0020B8 +:107510008FB3001C8FB200188FB100148FB0001011 +:1075200003E0000827BD00288F85009C00805821BB +:107530000000402100004821240A001F3C0C0800E4 +:10754000258C5E1C3C0D080025AD5DA48CA60000BA +:1075500050C000140000402100AD1023000238C0CC +:10756000240300010A000A930000202115000003F3 +:1075700000E410212448202400004821252900018E +:10758000512B00132506DFDC106000062484000167 +:1075900000C3702415C0FFF5000318400A000A91CB +:1075A0000000402110AC002624A300040060282124 +:1075B000254AFFFF1540FFE5AF85009C512B0004D5 +:1075C0002506DFDC0000402103E000080100102157 +:1075D0000006614230C5001F000C50803C070800C7 +:1075E00024E75DA424040001014730211120000F8D +:1075F00000A420043C05080024A55E20148000059A +:107600002529FFFF24C6000410C50011000000005A +:10761000240400018CCF00000004C0270004204097 +:1076200001F868241520FFF5ACCD00008F99007893 +:1076300001001021032B482303E00008AF890078E4 +:107640003C05080024A55DA40A000A9B0000402117 +:107650003C06080024C65DA40A000AB42404000104 +:10766000308800FF240200021102000A24030003F4 +:107670001103005C8F8900A4240400041104005F3E +:1076800024050005110500670000182103E000082B +:10769000006010218F8900483C0C0800258C5EE0BA +:1076A0003C04080024845F60240300201060000F65 +:1076B00000005821240D0002240E00033C0F080096 +:1076C00025EF5EE08D27000014E0000B30F9FFFF8E +:1076D000252900040124C02B53000001018048210A +:1076E0002463FFFF5460FFF88D270000016018211C +:1076F00003E0000800601021132000323C0500FF69 +:1077000030E200FF004030211040004200005021D4 +:1077100024050001000020210005C84000A6C02467 +:1077200017000003332500FF14A0FFFB2484000191 +:10773000012CC023001828C000AA6021008C502111 +:107740003144001F240C0001008C18040003102792 +:1077500000E23024110D0041AD260000110E004C56 +:10776000000A1840110D00368F87006C510E00562C +:107770008F8C0060240D0004110D005A8F8E008440 +:10778000240E0005150EFFDA01601821240B1430B9 +:1077900011400006000018218F8400A0246300011E +:1077A000006A402B1500FFFD016458218F8A00807C +:1077B000AF89008C016018212549FFFF0A000AEB00 +:1077C000AF89008000E52024000736021080FFD03A +:1077D000240A001800075402314600FF0A000AF389 +:1077E000240A00103C0C0800258C5EA03C04080014 +:1077F00024845EE00A000ADA240300103C0C08002E +:10780000258C5E203C04080024845EA00A000AD96E +:107810008F89009000071A02306600FF0A000AF301 +:10782000240A00088F89008C3C0C0800258C5F60BE +:107830003C04080024845F700A000ADA2403000470 +:10784000000A4080250B003024E6FFFF016018216C +:10785000AF8900480A000AEBAF86006C000AC982B3 +:10786000001978803C07080024E75EA001E720218A +:10787000000A18428C8F00003079001F032C380456 +:107880000007C02701F860240A000B08AC8C000038 +:10789000000331420006288000AF28213062001F1B +:1078A0008CB8000024630001004CC804000321428E +:1078B000001938270004108003073024004F2021CE +:1078C0000A000B4CACA60000000A68C025AB0032D1 +:1078D000258AFFFF01601821AF8900A40A000AEB86 +:1078E000AF8A0060254B1030AF89009001601821ED +:1078F00025C9FFFF0A000AEBAF8900843086000724 +:107900002CC2000610400014000000000006408059 +:107910003C030800246357BC010338218CE40000B9 +:1079200000800008000000002409000310A9000ED8 +:1079300000000000240A000510AA000B000000004F +:10794000240B000110AB0008000000008F8C00A089 +:1079500010AC00050000000003E00008000010214A +:107960000A000A7900A020210A000AC700C02021CD +:1079700027BDFFE8308400FF240300021083000BC2 +:10798000AFBF0010240600031086003A240800044C +:1079900010880068240E0005108E007F2CAF143074 +:1079A0008FBF001003E0000827BD00182CA2003094 +:1079B0001440FFFC8FBF001024A5FFD0000531C28A +:1079C000000668803C07080024E75EE001A730213C +:1079D0008CC900000005288230AC001F240B000178 +:1079E000018B50048F840048012A4025ACC8000058 +:1079F0008C83000050600001AF8600488F98006CB7 +:107A000030AE000124A6FFFF270F000115C00002C1 +:107A1000AF8F006C24A600010006414200082080C0 +:107A2000008718218C79000030C2001F2406000155 +:107A30000046F804033F382410E0FFDA8FBF00103F +:107A40000005C182001870803C0F080025EF5EA081 +:107A500001CF48218D2B00000005684231A5001F91 +:107A600000A66004016C502527BD001803E0000843 +:107A7000AD2A00002CA7003014E0FFCA8FBF001011 +:107A800030B900071723FFC724A8FFCE00086A02F9 +:107A9000000D60803C0B0800256B5EA0018B30213F +:107AA0008CC40000000828C230AA001F240800016E +:107AB000014848048F8200A400891825ACC3000047 +:107AC0008C5F000053E00001AF8600A40005704009 +:107AD000000E7942000F28803C04080024845EE0F8 +:107AE00000A418218C6B000025DF000131CD001FA0 +:107AF000001F514201A86004016C4825000A108053 +:107B0000AC690000004428218CA600008F9800601A +:107B100033F9001F8FBF00100328380400C77825F1 +:107B2000270E000127BD0018ACAF000003E00008DD +:107B3000AF8E006024A5EFD02CB804001300FF998D +:107B40008FBF001000053142000658803C0A080033 +:107B5000254A5E20016A30218CC4000030A3001F3A +:107B600024090001006910048F9900900082F82513 +:107B7000ACDF00008F27000050E00001AF860090CE +:107B80008F8D00848FBF001027BD001825AC000129 +:107B900003E00008AF8C008415E0FF828FBF001067 +:107BA0008F8600A0000610400046F821001F21002B +:107BB00003E4C8210019384024F8143000B8402BE1 +:107BC0001100FF788FBF001024A4EBD00E00021329 +:107BD00000C0282100027942000F70803C0D08008F +:107BE00025AD5F6001CD20218C8B0000304C001F43 +:107BF00024060001018618048F89008C016350253A +:107C0000AC8A00008D25000050A00001AF84008CDC +:107C10008F9800808FBF001027BD00182708000133 +:107C200003E00008AF88008030A5000724030003AC +:107C300010A3001028A2000414400008240700022A +:107C40002403000410A300152408000510A8000F49 +:107C50008F8500A003E000080000000014A7FFFDCE +:107C60000080282114C3FFFB240400020A000B8BB0 +:107C700000000000240900050080282110C9FFFB36 +:107C80002404000303E000080000000014C5FFF115 +:107C9000008028210A000B8B24040005240A00011F +:107CA0000080282110CAFFF12404000403E000082A +:107CB0000000000027BDFFE0AFB00010000581C24A +:107CC0002603FFD024C5003F2C6223D024C6007FAA +:107CD000AFB20018AFB10014AFBF001C309100FF6D +:107CE000000691C2000529820200202110400008F0 +:107CF0002403FFFF0E000A4B0000000002002021B9 +:107D0000022028210E000C390240302100001821E9 +:107D10008FBF001C8FB200188FB100148FB00010FD +:107D20000060102103E0000827BD002027BDFFD818 +:107D300024A2007FAFB3001CAFB20018000299C2AA +:107D4000309200FF24A3003F02402021026028213E +:107D5000AFB10014AFB00010AFBF00200E000B6E2B +:107D60000003898200408021004020210220282138 +:107D700014400009000018218FBF00208FB3001CA1 +:107D80008FB200188FB100148FB000100060102166 +:107D900003E0000827BD00280E0009FC00000000D9 +:107DA00000402821020020211051FFF3001019C0CB +:107DB0000E000A4B00000000020020210240282192 +:107DC0000E000C39026030218FBF00208FB3001CE1 +:107DD0008FB200188FB100148FB00010000018216E +:107DE0000060102103E0000827BD00283084FFFF59 +:107DF00030A5FFFF1080000700001821308200012D +:107E00001040000200042042006518211480FFFB8E +:107E10000005284003E000080060102110C00007A2 +:107E2000000000008CA2000024C6FFFF24A500046F +:107E3000AC82000014C0FFFB2484000403E00008AF +:107E40000000000010A0000824A3FFFFAC86000083 +:107E500000000000000000002402FFFF2463FFFF79 +:107E60001462FFFA2484000403E00008000000000C +:107E700030A5FFFF8F4201B80440FFFE3C076015AC +:107E800000A730253C031000AF440180AF400184BF +:107E9000AF46018803E00008AF4301B88F8500D0EA +:107EA0002C864000008018218CA700840087102BAE +:107EB00014400010000000008CA800842D06400033 +:107EC00050C0000F240340008CAA0084008A482B75 +:107ED000512000018CA3008400035A42000B208033 +:107EE0003C05080024A558200085182103E000085F +:107EF0008C62000014C0FFF4000000002403400066 +:107F000000035A42000B20803C05080024A558209D +:107F10000085182103E000088C6200008F8300D0E8 +:107F2000906600D024C50001A06500D08F8500D0E8 +:107F3000906400D090A200D210440017000000000E +:107F4000936C00788F8B00BC318A00FFA16A000C13 +:107F500025490001938700C4312200FF3048007F8B +:107F60001107000B00026827A36200788F4E01788A +:107F700005C0FFFE8F9900B0241800023C0F1000CE +:107F8000AF590140A358014403E00008AF4F017806 +:107F90000A000D0931A20080A0A000D00A000CFF49 +:107FA000000000008F8700D027BDFFC8AFBF0030A2 +:107FB000AFB7002CAFB60028AFB50024AFB4002097 +:107FC000AFB3001CAFB20018AFB10014AFB00010D7 +:107FD00094E300E094E200E2104300D72405FFFFA1 +:107FE0003C047FFF3497FFFF2415FF800A000DF04B +:107FF0003C16000E108A00D18FBF00308F9100B068 +:108000003C1808008F18005C001230C0001291402C +:108010000311702101D57824AF4F002C94EC00E2BD +:1080200031CD007F01BA5821318A7FFF0176482186 +:10803000000A804002091021945300003C08080007 +:108040008D0800580246C02132733FFF001319808B +:10805000010320210224282130BF007F03FAC82118 +:1080600000B5A024AF54002C0336A0218E87001049 +:108070008E8F003003785821256D008800EF702323 +:10808000240C0002AE8E0010AF8D00ACA16C0088F5 +:10809000976A003C8E8400308F9100AC0E000CD6A5 +:1080A0003150FFFF00024B80020940253C02420094 +:1080B00001022025AE2400048E8300048F8D00ACC5 +:1080C0008E860000240E0008ADA3001CADA600188B +:1080D000ADA0000CADA00010929F000A33F900FF84 +:1080E000A5B90014968500083C1F000CA5A5001634 +:1080F0009298000A331100FFA5B100209690000865 +:1081000024180005A5B00022ADA00024928F000B1A +:108110002410C00031E700FFA5A70002A1AE0001B6 +:108120008E8C00308F8B00AC8F8400B0AD6C00085B +:108130003C0A08008D4A005401444821013540247E +:10814000AF4800283C0208008C4200540044302113 +:1081500030C3007F007AC821033F282102458821CF +:10816000AF9100BCAF8500C0A23800008F8A00BC70 +:108170002403FFBF2418FFDF954F000201F03824CD +:1081800000F37025A54E0002914D000231AC003F76 +:10819000358B0040A14B00028F8600BC8F8900D038 +:1081A000ACC000048D28007C3C098000ACC80008ED +:1081B00090C4000D3082007FA0C2000D8F8500BCEE +:1081C00090BF000D03E3C824A0B9000D8F9100BC3F +:1081D0009233000D02789024A232000D8E9000346C +:1081E0008F8B00BCAD7000108E87002C8E8F0030FE +:1081F00000EF7023AD6E0014916D001831AC007F5C +:10820000A16C00188F9F00BC8E8A00308FE8001888 +:10821000015720240109302400C41025AFE20018C2 +:108220009283000AA3E3001C969900088F8500BC86 +:108230008F9800D0A4B9001E8E9000308E8400303C +:108240000E0002138F0500848F8500D0000291403C +:108250000002990090AF00BC0253882100403021F9 +:1082600031E7000210E0000302118021000290803B +:108270000212802190B900BC3327000410E00002F4 +:108280000006F880021F80218E9800308F8B00BC82 +:1082900024068000330F0003000F702331CD00034C +:1082A000020D6021AD6C000494A400E294AA00E2E7 +:1082B00094B000E231497FFF2522000130537FFF57 +:1082C0000206182400734025A4A800E294A400E24A +:1082D0003C1408008E94006030917FFF123400221D +:1082E000000000000E000CF6000000008F8700D098 +:1082F0000000282194F300E094F000E21213000F34 +:108300008FBF003090E900D090E800D1313200FFFB +:10831000310400FF0244302B14C0FF36264A00010E +:1083200090EE00D2264B000131CD00FF008D602180 +:10833000158BFF338F9100B08FBF00308FB7002CAB +:108340008FB600288FB500248FB400208FB3001C97 +:108350008FB200188FB100148FB0001000A0102150 +:1083600003E0000827BD003894A300E20066402423 +:10837000A4A800E290A400E290B900E2309100FFCE +:108380000011A1C20014F827001F39C03332007F4A +:10839000024730250A000DE8A0A600E23084FFFF66 +:1083A00030A5FFFFAF440018AF45001C03E00008F4 +:1083B0008F42001427BDFFB8AFB000208F9000D0CF +:1083C0003084FFFFAFA40010AFBF0044AFBE004039 +:1083D000AFB7003CAFB60038AFB50034AFB4003033 +:1083E000AFB3002CAFB20028AFB10024A7A0001893 +:1083F000920600D1920500D030C400FF30A300FFE8 +:108400000064102B10400122AFA00014920900D08C +:108410008FB50010312800FF0088382324F4FFFFB7 +:108420000014882B0015982B02339024524001260B +:108430008FB40014961E0012961F00108FB7001004 +:1084400003DFC823001714000019C400000224032E +:108450000018140302E2B02A52C00001004020219B +:108460000284282B10A0000200801821028018210D +:1084700000033C0000071C033064FFFF2C8600094A +:1084800014C000020060B821241700088E0A0008FA +:10849000001769808E09000C31ABFFFF3C0C001007 +:1084A000016C402527520400AF4A0038AF9200B853 +:1084B000AF49003CAF480030000000000000000061 +:1084C00000000000000000000000000000000000AC +:1084D00000000000000000008F4F000031EE00207F +:1084E00011C0FFFD0017982A027110240A000E83A4 +:1084F0000000B02155E001019258000131130080C5 +:10850000126001CF012020219655001232A5FFFFF5 +:108510000E000CCBA7B500188F9000D00291A023BD +:1085200026CD00018F9100B8000DB4000016B403F1 +:108530002638004002D7582A0014882B2405000151 +:108540000300902101711024AF9800B8AFA500146A +:10855000104001BC8F8900B03C0C08008D8C005489 +:10856000240BFF80921E00D001895021014B28244A +:10857000921900D0AF4500288E4700103C08080033 +:108580008D0800583C1808008F18005430E33FFF56 +:108590000003218001043021012658212402FF809C +:1085A0000162F824920C00D0AF5F002C92480000CA +:1085B00033D100FF333500FF0309982100117140CA +:1085C000001578C0326D007F01CF382101BA282113 +:1085D000318300FF3164007F3C0A000C00AA88212F +:1085E0000367F02100033140009A10213108003F59 +:1085F0003C1F000E00D1C021005F982127D90088C0 +:108600002D150008AF9100C0AF9900ACAF9800BC29 +:10861000AF9300B412A0018A00008821240E00014B +:10862000010E4004310D005D11A0FFB2310F0002B8 +:108630008E4A00283C0300803C04FFEFAE6A000035 +:108640008E450024A260000A3488FFFFAE65000456 +:108650009247002C3C1FFF9F37FEFFFFA267000CD4 +:108660008E62000C3C180040A267000B00433025CE +:1086700000C8C824033E88240238A825AE75000C23 +:108680008E490004AE6000183C0F00FFAE69001474 +:108690008E4D002C35EEFFFF8F8B00B001AE6024B5 +:1086A000AE6C00108E470008A660000896450012C8 +:1086B000AE6700208E42000C30B03FFF00105180AA +:1086C000AE6200248E5E0014014B182130A400011C +:1086D000AE7E00288E590018000331C2000443808A +:1086E000AE79002C8E51001C00C8F821A67F001C1A +:1086F000AE710030965800028E550020A678001EFC +:10870000AE75003492490033313000045600000544 +:10871000925000008F8C00D08D8B007CAE6B0030AF +:10872000925000008F8F00BCA1F00000924E0033E9 +:1087300031CD000251A00007925E00018F8900BC7C +:108740002418FF80913100000311A825A1350000F5 +:10875000925E00018F9900BC2409FFBF240BFFDF4C +:10876000A33E00018F9500BC92B8000D3311007F2D +:10877000A2B1000D8F8E00BC91D0000D02097824AB +:10878000A1CF000D8F8800BC8E6D0014910A000DE2 +:108790002DAC0001000C2940014B382400E51825C0 +:1087A000A103000D964200128F8800BC8F8700D075 +:1087B000A50200028E45000490FF00BC30A4000317 +:1087C0000004302330DE000300BE102133F9000224 +:1087D00017200002244400342444003090E200BCFE +:1087E00000A2302430DF000417E0000224830004DC +:1087F000008018218F8F00AC24090002AD03000413 +:10880000A1E90000924E003F8F8D00ACA1AE0001A7 +:108810008F9500AC924C003F8E440004A6AC000241 +:10882000976B003C0E000CD63170FFFF00025380A6 +:10883000020A38253C05420000E51825AEA30004D5 +:108840008F8600AC8E480038ACC800188E440034C7 +:10885000ACC4001CACC0000CACC00010A4C0001420 +:10886000A4C00016A4C00020A4C00022ACC00024F4 +:108870008E6400145080000124040001ACC4000880 +:108880000E000CF6241100010A000E768F9000D025 +:10889000920F00D2920E00D08FB5001031EB00FF86 +:1088A00031CD00FF008D6023016C50212554FFFF66 +:1088B0000014882B0015982B023390241640FEDDFF +:1088C000000000008FB400148FBF00448FBE004032 +:1088D0003A8200018FB7003C8FB600388FB5003464 +:1088E0008FB400308FB3002C8FB200288FB10024DA +:1088F0008FB0002003E0000827BD0048331100209E +:10890000122000EF24150001921E00BC241F00015C +:108910000000A82133D900011320000DAFBF001CB7 +:108920008E4400148E0800840088102B144000022E +:10893000008030218E0600848E03006400C3A82BC3 +:1089400016A0000200C020218E0400640080A8212F +:108950008E4700148E05006400E5302B14C0000221 +:1089600000E020218E0400640095F02313C0000471 +:108970008FAC001C240A0002AFAA001C8FAC001CA4 +:10898000028C582B156000A8000018218E4F00386B +:108990008E6D000C3C0E0080AE6F00008E4A0034DD +:1089A0003C10FF9F01AE5825AE6A00049246003F7E +:1089B000360CFFFF016C38243C0500203C03FFEF20 +:1089C000A266000B00E510253468FFFF8F8700B812 +:1089D0000048F8243C04000803E4C825AE79000CE4 +:1089E0008CF80014AE60001802BE7821AE78001436 +:1089F0008CF10018AE71001C8CE90008AE690024EF +:108A00008CEE000CAE6F002CAE600028AE6E002025 +:108A1000A6600038A660003A8CED001401B58023F2 +:108A2000021E902312400011AE72001090EA003D29 +:108A30008E6500048E640000000A310000A6C82183 +:108A4000000010210326402B0082F82103E8C021FA +:108A5000AE790004AE78000090F1003DA271000AEA +:108A60008F8900B895320006A67200088F9800AC76 +:108A70002419000202A02021A31900009769003CDC +:108A80008F9200AC0E000CD63131FFFF00027B80CC +:108A90008F8500B8022F68253C0E420001AE80256C +:108AA000AE5000048F8400AC8CAC0038AC8C001845 +:108AB0008CAB0034AC8B001CAC80000CAC80001084 +:108AC000A4800014A4800016A4800020A4800022AA +:108AD000AC80002490A7003FA487000212A00135BB +:108AE0002403000153C0000290A2003D90A2003E6A +:108AF00024480001A08800018F9F00ACAFF500085A +:108B00008F8300D024070034906600BC30C500027B +:108B100050A00001240700308F9200B88F8A00BC5B +:108B2000906D00BC924B00002412C00032A50003DF +:108B3000A14B00008F8600B88F8800BC240200047F +:108B400090C400010045182330790003A1040001FE +:108B50008F8A00BC8F9F00B800F53821955800021D +:108B600097E9001200F9382103128824312F3FFFC2 +:108B7000022F7025A54E00029150000231A800047A +:108B8000320C003F358B0040A14B000212A00002C6 +:108B90008F8500BC00E838218F8E00D0ACA7000480 +:108BA000240BFFBF8DCD007C2EA400012403FFDF2A +:108BB000ACAD000890B0000D00044140320C007FC5 +:108BC000A0AC000D8F8600BC90CA000D014B102494 +:108BD000A0C2000D8F8700BC90E5000D00A3F82413 +:108BE00003E8C825A0F9000D8F9100B88F8D00BC57 +:108BF0008E380020ADB800108E290024ADA90014D5 +:108C00008E2F0028ADAF00188E2E002C0E000CF613 +:108C1000ADAE001C8FB0001C240C0002120C00EE44 +:108C20008F9000D08FA3001C006088211460000288 +:108C30000060A8210000A02156A0FE390291A023C7 +:108C40000014882B8FA90010960700103C1E0020EE +:108C50000136402302C750213112FFFFA60A00103F +:108C6000AFB20010AF5E0030000000009617001099 +:108C7000961300121277008F000000008E05000C82 +:108C80008E0B00080016698000AD7021000DC7C36F +:108C900001CDA82B0178782101F56021AE0E000CE2 +:108CA000AE0C00088FB300100013B82B02378024DD +:108CB0001200FF048F9000D00A000E3C000000005C +:108CC0008E4D0038A6600008240B0003AE6D000036 +:108CD0008E500034A260000A8F9800B8AE70000475 +:108CE0003C0500809311003FA26B000C8E6F000CBE +:108CF0003C0EFF9FA271000B01E5102535CCFFFF54 +:108D00003C03FFEF8F9200B8004C30243464FFFF27 +:108D100000C4F824AE7F000C8E590014964800124F +:108D20008F8A00B0AE7900108E490014AE60001832 +:108D3000AE600020AE690014AE6000248E470018BB +:108D400031093FFF0009F180AE6700288E4D000811 +:108D500003CA802131180001AE6D00308E4F000C27 +:108D60008F8C00AC001089C200185B80022B282178 +:108D7000240E0002A665001CA6600036AE6F002C13 +:108D8000A18E00009763003C8F8A00AC3C04420037 +:108D90003062FFFF00443025AD4600048F9F00B8CD +:108DA000240700012411C0008FF30038240600348A +:108DB000AD5300188FF90034AD59001CAD40000CC4 +:108DC000AD400010A5400014A5400016A5400020AD +:108DD000A5400022AD400024A5550002A147000196 +:108DE0008F9E00AC8F8800B88F9200BCAFD5000872 +:108DF000910D0000A24D00008F9000B88F8B00BC39 +:108E000092180001A17800018F8400BC94850002B3 +:108E100000B1782401E97025A48E0002908C000234 +:108E20003183003FA08300028F8300D08F8400BC79 +:108E3000906200BC305300025260000124060030F2 +:108E4000AC8600048C6F007C2403FFBF02A0882145 +:108E5000AC8F0008908E000D31CC007FA08C000DEF +:108E60008F8600BC90C2000D00432024A0C4000DDA +:108E70008F8900BC913F000D37F90020A139000D0A +:108E80008F8800B88F9300BC8D070020AE6700105C +:108E90008D0A0024AE6A00148D1E0028AE7E0018D4 +:108EA0008D12002C0E000CF6AE72001C0A00103D54 +:108EB0008F9000D0960E00148E03000431CCFFFF7B +:108EC000000C10C000622021AF44003C8E1F000443 +:108ED0008F46003C03E6C8231B20003C0000000036 +:108EE0008E0F000025E200013C05001034B500089B +:108EF000AF420038AF550030000000000000000015 +:108F00000000000000000000000000000000000061 +:108F100000000000000000008F580000330B00200C +:108F20001160FFFD000000008F5304003C0D002085 +:108F3000AE1300088F570404AE17000CAF4D00307D +:108F4000000000003C0608008CC600442416000106 +:108F500010D600BD00000000961F00123C0508005E +:108F60008CA5004000BFC821A61900129609001464 +:108F700025270001A6070014960A00143144FFFFBC +:108F80005486FF498FB30010A60000140E000E1681 +:108F900030A5FFFF3C0408008C84002496030012D7 +:108FA0000044102300623023A60600120A00105964 +:108FB0008FB30010A08300018F8200AC2404000155 +:108FC000AC4400080A000FF08F8300D08E0200002E +:108FD0000A0010EA3C0500108F8200C08FA7001C19 +:108FE000921800D0920B00D0920E00D0331100FFE7 +:108FF000316900FF00117940000928C001E56021B6 +:1090000031C300FF036C50210003314000C2C8216E +:10901000255F0088AF9F00ACAF9900BCA1470088D6 +:109020009768003C03C020218F9100AC0E000CD645 +:109030003110FFFF00026B80020DC0253C0442008E +:109040008F8D00B803045825AE2B00048DA900387D +:109050008F8B00AC0000882100118100AD690018E1 +:109060008DAF00343C087FFF3504FFFFAD6F001C5F +:1090700091AC003E8D65001C8D660018000C190037 +:10908000000C770200A33821020E102500E3F82B14 +:1090900000C2C821033F5021AD67001CAD6A001813 +:1090A000AD60000CAD60001091B8003E24050005D5 +:1090B00003C45024A578001495A9000403C02021FE +:1090C000A569001691AF003EA56F002095B1000480 +:1090D000A5710022AD60002491AE003FA56E000294 +:1090E00091B0003E91AC003D01901023244300015B +:1090F000A16300018F8600AC8F9F00BCACDE00082E +:10910000A3E500008F9000BC8F9900B82405FFBF35 +:1091100096070002973800120247782433093FFF70 +:1091200001E98825A6110002921200022418FFDF2F +:10913000324E003F35CD0040A20D00028F8600BCAC +:109140008F8C00D02412FFFFACC000048D8B007CFC +:109150003C0C8000ACCB000890C2000D3043007F77 +:10916000A0C3000D8F8700BC90FF000D03E5C8244D +:10917000A0F9000D8F9100BC9229000D01387824D0 +:10918000A22F000D8F9000BCAE120010AE1500147F +:10919000920E00182415FF8002AE6825A20D00185B +:1091A0008F8500BC8F8300B88CAB0018016C102435 +:1091B000004A3025ACA600189068003EA0A8001C0C +:1091C0008F9F00B88F8700BC8F9800D097F900045C +:1091D000A4F9001E0E0002138F0500848F8600D0B4 +:1091E000000279400002490090D200BC01E98821C8 +:1091F000004028213255000212A0000303D1202193 +:109200000002A8800095202190CD00BC31B200045E +:109210001240000333DF0003000540800088202156 +:10922000240600048F9E00BC00DFC8233327000300 +:1092300000875021AFCA00040E000CF6A665003866 +:109240000A0010388F9000D0961E00123C080800CB +:109250008D080024011E9021A61200120A00105948 +:109260008FB3001027BDFFE03C1808008F18005096 +:10927000AFB00010AFBF0018AFB10014AF8400B0A2 +:1092800093710074030478212410FF8031EE007F75 +:109290003225007F01F0582401DA68213C0C000AD5 +:1092A000A38500C401AC2821AF4B002494A9001071 +:1092B0009768000690A600620080382124020030E2 +:1092C0000109202330C300F0AF8500D010620019DF +:1092D0003090FFFF90AE0062240DFFF0240A005092 +:1092E00001AE6024318B00FF116A002F00000000E6 +:1092F00016000007241F0C00AF5F00248FB100147C +:109300008FBF00188FB0001003E0000827BD0020B9 +:109310000E000E1C02002021241F0C00AF5F002451 +:109320008FB100148FBF00188FB0001003E0000849 +:1093300027BD002094A200E094A400E290BF011396 +:10934000008218263079FFFF33E700C014E00009DF +:109350002F31000116000038000000005620FFE603 +:10936000241F0C000E000D18000000000A0011ED73 +:10937000241F0C001620FFDE000000000E000D1858 +:10938000000000001440FFDC241F0C001600002227 +:109390008F8300D0906901133122003FA062011336 +:1093A0000A0011ED241F0C0094AF00D48F8600D466 +:1093B00000E02821240400050E000C5C31F0FFFFC2 +:1093C0001440000524030003979100E600001821D3 +:1093D0002625FFFFA78500E68F5801B80700FFFE8E +:1093E0003C196013AF400180241F0C00AF50018472 +:1093F000007938253C101000AF4701888FB1001468 +:10940000AF5001B8AF5F00248FB000108FBF0018BD +:1094100003E0000827BD00200E000E1C02002021E2 +:109420005040FFB5241F0C008F8300D090690113BA +:109430000A0012163122003F0E000E1C02002021ED +:109440001440FFAD241F0C00122000078F8300D0B2 +:10945000906801133106003F34C20040A06201133E +:109460000A0011ED241F0C000E000D180000000072 +:109470005040FFA1241F0C008F8300D0906801137F +:109480003106003F0A00124634C20040AF9B00C8BC +:1094900003E00008AF8000EC3089FFFF0009404284 +:1094A0002D020041000921801440000200095040B3 +:1094B00024080040000830C0000811400046582130 +:1094C000256701A800E2C821272F007F2418FF800C +:1094D00001F818240064302100CA702125CC00FF57 +:1094E000240DFF00018D202425650088240A0088B2 +:1094F0003C010800AC2A004C3C010800AC2500509F +:10950000AF8400D43C010800AC2900603C01080095 +:10951000AC2800643C010800AC2700543C01080062 +:10952000AC2300583C010800AC26005C03E00008B6 +:1095300000000000308300FF30C6FFFF30E400FF72 +:109540008F4201B80440FFFE00034C00012438257F +:109550003C08600000E820253C031000AF45018076 +:10956000AF460184AF44018803E00008AF4301B86F +:109570008F86001C3C096012352700108CCB00043C +:109580003C0C600E35850010316A00062D48000144 +:10959000ACE800C48CC40004ACA431808CC20008C8 +:1095A00094C30002ACA2318403E00008A78300E466 +:1095B0003C0308008C6300508F8400E88F86001CF9 +:1095C0002402FF800064C0210302C824AF59002890 +:1095D0008CCD00043305007F00BA78213C0E000CCE +:1095E00001EE2821ACAD00588CC80008AF8500D032 +:1095F0003C076012ACA8005C8CCC001034E8001072 +:10960000ACAC000C8CCB000CACAB000894AA0014E2 +:109610003C0208008C42004425490001A4A9001422 +:1096200094A400143083FFFF106200178F8400D0D1 +:109630003C0A08008D4A0040A4AA00128CCE0018F3 +:10964000AC8E00248CCD0014AC8D00208CC700188B +:10965000AC87002C8CCC001424060001AC8C0028B4 +:109660008D0B00BC5166001A8D0200B48D0200B84B +:10967000A482003A948F003AA48F003C948800D4CE +:1096800003E000083102FFFF3C0908008D29002497 +:10969000A4A000148F8400D0A4A900128CCE0018BE +:1096A000AC8E00248CCD0014AC8D00208CC700182B +:1096B000AC87002C8CCC001424060001AC8C002854 +:1096C0008D0B00BC5566FFEA8D0200B88D0200B418 +:1096D000A482003A948F003AA48F003C948800D46E +:1096E00003E000083102FFFF8F86001C3C0C0800DD +:1096F0008D8C0050240BFF808CCD00083C03000CA7 +:10970000000D51C0018A4021010B4824AF8A00E8B6 +:10971000AF49002890C700073105007F00BA10212B +:109720000043282130E4000410800039AF8500D0C8 +:1097300090CF000731EE000811C000380000000093 +:109740008CD9000C8CC400140324C02B13000030EF +:10975000000000008CC2000CACA200648CCD00188C +:109760002402FFF8ACAD00688CCC0010ACAC0080DB +:109770008CCB000CACAB00848CCA001CACAA007C67 +:1097800090A900BC01224024A0A800BC90C30007FF +:109790003067000810E000048F8500D090AF00BC57 +:1097A00035EE0001A0AE00BC90D9000733380001AF +:1097B000130000088F8300D08F8700D0240400346A +:1097C00090E800BC35030002A0E300BC8F8300D00A +:1097D000AC6400C090C900073126000210C000052B +:1097E00000000000906A00BC35420004A06200BC8A +:1097F0008F8300D09065011330AD003FA06D011341 +:109800008F8C00D0958B00D403E000083162FFFFFD +:109810008CC200140A001305000000000A001306A1 +:10982000ACA0006427BDFFD8AFB000108F90001C23 +:10983000AFBF0024AFB40020AFB20018AFB1001426 +:10984000AFB3001C9613000E3C07600A3C14600680 +:109850003264FFFF369300100E00125534F40410EA +:109860008F8400D43C11600E0E00099B363100102D +:10987000920E00153C0708008CE700603C12601255 +:1098800031CD000FA38D00F08E0E00048E0D000868 +:1098900096080012961F00109619001A9618001EBE +:1098A000960F001C310CFFFF33EBFFFF332AFFFF45 +:1098B0003309FFFF31E6FFFF3C010800AC2B0040FD +:1098C0003C010800AC2C00243C010800AC2A0044F8 +:1098D000AE293178AE26317C92020015960300162F +:1098E00036520010304400FF3065FFFF3C06080090 +:1098F0008CC60064AE243188AE4500B492080014D2 +:1099000096190018241F0001011FC004332FFFFF08 +:109910003C0508008CA50058AE5800B8AE4F00BCFE +:10992000920C0014AF8E00D8AF8D00DC318B00FF9D +:10993000AE4B00C0920A0015AE670048AE66004C00 +:10994000314900FFAE4900C8AE65007C3C03080009 +:109950008C6300503C0408008C84004C3C080800D8 +:109960008D0800543C0208008C42005C8FBF00242C +:10997000AE6300808FB00010AE8300748FB3001C04 +:10998000AE22319CAE4200DCAE2731A0AE2631A41F +:10999000AE24318CAE233190AE283194AE2531986F +:1099A000AE870050AE860054AE8500708FB10014B3 +:1099B000AE4700E0AE4600E4AE4400CCAE4300D07B +:1099C000AE4800D4AE4500D88FB400208FB2001846 +:1099D00003E0000827BD002827BDFFE0AFB1001459 +:1099E000AFBF0018241100010E000845AFB00010F1 +:1099F00010510005978400E6978300CC0083102B5C +:109A0000144000088F8500D4240700028FBF00187F +:109A10008FB100148FB0001000E0102103E00008A7 +:109A200027BD00200E000C7A24040005AF8200E858 +:109A30001040FFF6240700020E0008498F90001C1A +:109A4000979F00E68F9900E88F8D00C827EF0001EF +:109A5000240E0050AF590020A78F00E6A1AE0000F1 +:109A60003C0C08008D8C00648F8600C8240A80009E +:109A7000000C5E00ACCB0074A4C0000694C9000AC0 +:109A8000241FFF803C0D000C012AC024A4D8000A2A +:109A900090C8000A24182000011F1825A0C3000A3E +:109AA0008F8700C8A0E000788F8500C800003821AB +:109AB000A0A000833C0208008C4200508F8400E884 +:109AC0000044782101FFC824AF590028960B0002FA +:109AD00031EE007F01DA6021018D3021A4CB00D46A +:109AE000960A0002AF8600D03C0E000425492401EE +:109AF000A4C900E68E080004ACC800048E03000868 +:109B0000ACC30000A4C00010A4C00014A0C000D0CA +:109B10008F8500D02403FFBFA0A000D13C04080023 +:109B20008C8400648F8200D0A04400D28E1F000C71 +:109B30008F8A00D0978F00E4AD5F001C8E19001053 +:109B400024100030AD590018A5400030A551005434 +:109B5000A5510056A54F0016AD4E0068AD580080C7 +:109B6000AD580084914D006231AC000F358B001070 +:109B7000A14B00628F8600D090C900633128007F1E +:109B8000A0C800638F8400D02406FFFF9085006387 +:109B900000A31024A08200638F9100D000E0102168 +:109BA000923F00BC37F90001A23900BC8F8A00D077 +:109BB000938F00F0AD580064AD5000C0914E00D3BB +:109BC000000F690031CC000F018D5825A14B00D347 +:109BD0008F8500D08F8900DCACA900E88F8800D881 +:109BE0008FBF00188FB100148FB0001027BD002068 +:109BF000ACA800ECA4A600D6A4A000E0A4A000E2BB +:109C000003E000080000000027BDFFE0AFB0001037 +:109C10008F90001CAFB10014AFBF00188E19000464 +:109C20003C1808008F180050240FFF80001989C0CD +:109C30000238702131CD007F01CF602401BA50215C +:109C40003C0B000CAF4C0028014B4021950900D47F +:109C5000950400D68E0700043131FFFFAF8800D095 +:109C60000E000913000721C08E0600048F8300C870 +:109C7000000629C0AF4500209064003E30820040BD +:109C8000144000068F8400D0341FFFFF948300D659 +:109C90003062FFFF145F000400000000948400D6CF +:109CA0000E0008A83084FFFF8E050004022030213A +:109CB0008FBF00188FB100148FB000102404002251 +:109CC00000003821000529C00A00127C27BD0020B1 +:109CD00027BDFFE0AFB100143091FFFFAFB000101F +:109CE000AFBF00181220001D000080218F86001CCD +:109CF0008CC500002403000600053F020005140285 +:109D000030E4000714830015304500FF2CA800063E +:109D10001100004D000558803C0C0800258C57D4DC +:109D2000016C50218D490000012000080000000056 +:109D30008F8E00EC240D000111CD005900000000B1 +:109D4000260B00013170FFFF24CA00200211202BD6 +:109D5000014030211480FFE6AF8A001C0200102170 +:109D60008FBF00188FB100148FB0001003E00008FF +:109D700027BD0020938700CE14E00038240400148F +:109D80000E001338000000008F86001C2402000122 +:109D90000A00147FAF8200EC8F8900EC24080002D7 +:109DA0001128003B2404001300002821000030216A +:109DB000240700010E00127C000000000A00147F3E +:109DC0008F86001C8F8700EC2405000214E5FFF647 +:109DD000240400120E0012E9000000008F8500E844 +:109DE00000403021240400120E00127C00003821B3 +:109DF0000A00147F8F86001C8F8300EC241F000351 +:109E0000147FFFD0260B00010E00129B0000000003 +:109E10008F8500E800403021240200022404001055 +:109E200000003821AF8200EC0E00127C0000000020 +:109E30000A00147F8F86001C8F8F00EC240600021E +:109E400011E6000B0000000024040010000028218F +:109E5000000030210A00149C240700010000282182 +:109E60000E00127C000030210A00147F8F86001C37 +:109E70000E0013A500000000144000128F99001C72 +:109E80008F86001C240200030A00147FAF8200ECBE +:109E90000E001431000000000A00147F8F86001CA1 +:109EA0000E00128B000000002402000224040014A3 +:109EB0000000282100003021000038210A0014B9D8 +:109EC000AF8200EC004038212404001097380002D3 +:109ED000000028210E00127C3306FFFF0A00147FC9 +:109EE0008F86001C8F8400C83C077FFF34E6FFFF8D +:109EF0008C8500742402000100A61824AC83007431 +:109F000003E00008A082000510A000362CA200800B +:109F1000274A04003C0B000524090080104000077C +:109F20002408008030A6000F00C540212D030081C9 +:109F30001460000200A0482124080080AF4B0030CC +:109F400000000000000000000000000011000009F7 +:109F500000003821014030218C8D000024E70004EE +:109F600000E8602BACCD0000248400041580FFFACB +:109F700024C60004000000000000000000000000F3 +:109F80003C0E0006010E3825AF47003000000000EF +:109F900000000000000000008F4F000031E80010BA +:109FA0001100FFFD000000008F42003C8F43003C89 +:109FB0000049C8210323C02B130000040000000047 +:109FC0008F4C003825860001AF4600388F47003C93 +:109FD00000A9282300E96821AF4D003C14A0FFCE62 +:109FE0002CA2008003E000080000000027BDFFD085 +:109FF0003C020002AFB100143C11000CAF45003828 +:10A00000AFB3001CAF46003C00809821AF42003047 +:10A0100024050088AF44002803512021AFBF002849 +:10A02000AFB50024AFB40020AFB200180E0014F199 +:10A03000AFB000103C1F08008FFF004C3C18080018 +:10A040008F1800642410FF8003F3A82132B9007F29 +:10A0500002B078240018A0C0033A70210018914083 +:10A0600001D12021AF4F00280E0014F10254282105 +:10A070003C0D08008DAD00502405012001B358218E +:10A08000316C007F01705024019A48210131202158 +:10A090000E0014F1AF4A00283C0808008D08005457 +:10A0A0003C0508008CA500640113382130E6007FD0 +:10A0B00000F0182400DA202100912021AF4300286D +:10A0C0000E0014F1000529403C0208008C420058A3 +:10A0D0003C1008008E1000601200001C0053882104 +:10A0E0002415FF800A0015743C14000C3226007FF2 +:10A0F0000235182400DA202102402821AF4300282D +:10A10000009420210E0014F12610FFC01200000F51 +:10A11000023288212E05004110A0FFF42412100005 +:10A120003226007F001091800235182400DA2021A9 +:10A1300002402821AF430028009420210E0014F192 +:10A14000000080211600FFF3023288213C0B08003A +:10A150008D6B005C240AFF802405000201734021FE +:10A16000010A4824AF4900283C0408009484006296 +:10A170003110007F021A88213C07000C0E000CAA47 +:10A180000227982100402821026020218FBF00284B +:10A190008FB500248FB400208FB3001C8FB200183D +:10A1A0008FB100148FB000100A0014F127BD0030E9 +:10A1B0008F83001C8C62000410400003000000002C +:10A1C00003E00008000000008C6400108C650008AB +:10A1D0000A00152A8C66000C000000000000001B1D +:10A1E0000000000F0000000A000000080000000648 +:10A1F000000000050000000500000004000000044D +:10A200000000000300000003000000030000000342 +:10A210000000000300000002000000020000000235 +:10A220000000000200000002000000020000000226 +:10A230000000000200000002000000020000000216 +:10A240000000000200000002000000020000000206 +:10A2500000000001000000010000000108000F24C0 +:10A2600008000D6C08000FB80800106008000F4CC3 +:10A2700008000F8C0800119408000D88080011B820 +:10A2800008000DD8080015540800151C08000D889A +:10A2900008000D8808000D880800124008001240D0 +:10A2A00008000D8808000D88080014E008000D88DB +:10A2B00008000D8808000D8808000D88080013B4F8 +:10A2C00008000D8808000D8808000D8808000D881A +:10A2D00008000D8808000D8808000D8808000D880A +:10A2E00008000D8808000D8808000D8808000D88FA +:10A2F00008000D8808000D8808000FAC08000D88C4 +:10A3000008000D880800167808000D8808000D88E0 +:10A3100008000D8808000D8808000D8808000D88C9 +:10A3200008000D8808000D8808000D8808000D88B9 +:10A3300008000D8808000D8808000D8808000D88A9 +:10A3400008000D8808000D8808000D88080014100A +:10A3500008000D8808000D8808001334080012A4B6 +:10A3600008001E2C08001EFC08001F1408001F28EF +:10A3700008001F3808001E2C08001E2C08001E2C88 +:10A3800008001ED808002E1408002E1C08002DE41A +:10A3900008002DF008002DFC08002E08080052F4DB +:10A3A000080052B40800528008005254080052308D +:10A3B000080051EC0A000C840000000000000000BE +:10A3C0000000000D727870362E322E33000000002F +:10A3D000060203030000000000000001000000006E +:10A3E000000000000000000000000000000000006D +:10A3F000000000000000000000000000000000005D +:10A40000000000000000000000000000000000004C +:10A41000000000000000000000000000000000003C +:10A42000000000000000000000000000000000002C +:10A43000000000000000000000000000000000001C +:10A44000000000000000000000000000000000000C +:10A4500000000000000000000000000000000000FC +:10A4600000000000000000000000000000000000EC +:10A4700000000000000000000000000000000000DC +:10A4800000000000000000000000000000000000CC +:10A4900000000000000000000000000000000000BC +:10A4A00000000000000000000000000000000000AC +:10A4B000000000000000000000000000000000009C +:10A4C000000000000000000000000000000000008C +:10A4D000000000000000000000000000000000007C +:10A4E000000000000000000000000000000000006C +:10A4F000000000000000000000000000000000005C +:10A50000000000000000000000000000000000004B +:10A51000000000000000000000000000000000003B +:10A52000000000000000000000000000000000002B +:10A53000000000000000000000000000000000001B +:10A54000000000000000000000000000000000000B +:10A5500000000000000000000000000000000000FB +:10A5600000000000000000000000000000000000EB +:10A5700000000000000000000000000000000000DB +:10A5800000000000000000000000000000000000CB +:10A5900000000000000000000000000000000000BB +:10A5A00000000000000000000000000000000000AB +:10A5B000000000000000000000000000000000009B +:10A5C000000000000000000000000000000000008B +:10A5D000000000000000000000000000000000007B +:10A5E000000000000000000000000000000000006B +:10A5F000000000000000000000000000000000005B +:10A60000000000000000000000000000000000004A +:10A61000000000000000000000000000000000003A +:10A62000000000000000000000000000000000002A +:10A63000000000000000000000000000000000001A +:10A64000000000000000000000000000000000000A +:10A6500000000000000000000000000000000000FA +:10A6600000000000000000000000000000000000EA +:10A6700000000000000000000000000000000000DA +:10A6800000000000000000000000000000000000CA +:10A6900000000000000000000000000000000000BA +:10A6A00000000000000000000000000000000000AA +:10A6B000000000000000000000000000000000009A +:10A6C000000000000000000000000000000000008A +:10A6D000000000000000000000000000000000007A +:10A6E000000000000000000000000000000000006A +:10A6F000000000000000000000000000000000005A +:10A700000000000000000000000000000000000049 +:10A710000000000000000000000000000000000039 +:10A720000000000000000000000000000000000029 +:10A730000000000000000000000000000000000019 +:10A740000000000000000000000000000000000009 +:10A7500000000000000000000000000000000000F9 +:10A7600000000000000000000000000000000000E9 +:10A7700000000000000000000000000000000000D9 +:10A7800000000000000000000000000000000000C9 +:10A7900000000000000000000000000000000000B9 +:10A7A00000000000000000000000000000000000A9 +:10A7B0000000000000000000000000000000000099 +:10A7C0000000000000000000000000000000000089 +:10A7D0000000000000000000000000000000000079 +:10A7E0000000000000000000000000000000000069 +:10A7F0000000000000000000000000000000000059 +:10A800000000000000000000000000000000000048 +:10A810000000000000000000000000000000000038 +:10A820000000000000000000000000000000000028 +:10A830000000000000000000000000000000000018 +:10A840000000000000000000000000000000000008 +:10A8500000000000000000000000000000000000F8 +:10A8600000000000000000000000000000000000E8 +:10A8700000000000000000000000000000000000D8 +:10A8800000000000000000000000000000000000C8 +:10A8900000000000000000000000000000000000B8 +:10A8A00000000000000000000000000000000000A8 +:10A8B0000000000000000000000000000000000098 +:10A8C0000000000000000000000000000000000088 +:10A8D0000000000000000000000000000000000078 +:10A8E0000000000000000000000000000000000068 +:10A8F0000000000000000000000000000000000058 +:10A900000000000000000000000000000000000047 +:10A910000000000000000000000000000000000037 +:10A920000000000000000000000000000000000027 +:10A930000000000000000000000000000000000017 +:10A940000000000000000000000000000000000007 +:10A9500000000000000000000000000000000000F7 +:10A9600000000000000000000000000000000000E7 +:10A9700000000000000000000000000000000000D7 +:10A9800000000000000000000000000000000000C7 +:10A9900000000000000000000000000000000000B7 +:10A9A00000000000000000000000000000000000A7 +:10A9B0000000000000000000000000000000000097 +:10A9C0000000000000000000000000000000000087 +:10A9D0000000000000000000000000000000000077 +:10A9E0000000000000000000000000000000000067 +:10A9F0000000000000000000000000000000000057 +:10AA00000000000000000000000000000000000046 +:10AA10000000000000000000000000000000000036 +:10AA20000000000000000000000000000000000026 +:10AA30000000000000000000000000000000000016 +:10AA40000000000000000000000000000000000006 +:10AA500000000000000000000000000000000000F6 +:10AA600000000000000000000000000000000000E6 +:10AA700000000000000000000000000000000000D6 +:10AA800000000000000000000000000000000000C6 +:10AA900000000000000000000000000000000000B6 +:10AAA00000000000000000000000000000000000A6 +:10AAB0000000000000000000000000000000000096 +:10AAC0000000000000000000000000000000000086 +:10AAD0000000000000000000000000000000000076 +:10AAE0000000000000000000000000000000000066 +:10AAF0000000000000000000000000000000000056 +:10AB00000000000000000000000000000000000045 +:10AB10000000000000000000000000000000000035 +:10AB20000000000000000000000000000000000025 +:10AB30000000000000000000000000000000000015 +:10AB40000000000000000000000000000000000005 +:10AB500000000000000000000000000000000000F5 +:10AB600000000000000000000000000000000000E5 +:10AB700000000000000000000000000000000000D5 +:10AB800000000000000000000000000000000000C5 +:10AB900000000000000000000000000000000000B5 +:10ABA00000000000000000000000000000000000A5 +:10ABB0000000000000000000000000000000000095 +:10ABC0000000000000000000000000000000000085 +:10ABD0000000000000000000000000000000000075 +:10ABE0000000000000000000000000000000000065 +:10ABF0000000000000000000000000000000000055 +:10AC00000000000000000000000000000000000044 +:10AC10000000000000000000000000000000000034 +:10AC20000000000000000000000000000000000024 +:10AC30000000000000000000000000000000000014 +:10AC40000000000000000000000000000000000004 +:10AC500000000000000000000000000000000000F4 +:10AC600000000000000000000000000000000000E4 +:10AC700000000000000000000000000000000000D4 +:10AC800000000000000000000000000000000000C4 +:10AC900000000000000000000000000000000000B4 +:10ACA00000000000000000000000000000000000A4 +:10ACB0000000000000000000000000000000000094 +:10ACC0000000000000000000000000000000000084 +:10ACD0000000000000000000000000000000000074 +:10ACE0000000000000000000000000000000000064 +:10ACF0000000000000000000000000000000000054 +:10AD00000000000000000000000000000000000043 +:10AD10000000000000000000000000000000000033 +:10AD20000000000000000000000000000000000023 +:10AD30000000000000000000000000000000000013 +:10AD40000000000000000000000000000000000003 +:10AD500000000000000000000000000000000000F3 +:10AD600000000000000000000000000000000000E3 +:10AD700000000000000000000000000000000000D3 +:10AD800000000000000000000000000000000000C3 +:10AD900000000000000000000000000000000000B3 +:10ADA00000000000000000000000000000000000A3 +:10ADB0000000000000000000000000000000000093 +:10ADC0000000000000000000000000000000000083 +:10ADD0000000000000000000000000000000000073 +:10ADE0000000000000000000000000000000000063 +:10ADF0000000000000000000000000000000000053 +:10AE00000000000000000000000000000000000042 +:10AE10000000000000000000000000000000000032 +:10AE20000000000000000000000000000000000022 +:10AE30000000000000000000000000000000000012 +:10AE40000000000000000000000000000000000002 +:10AE500000000000000000000000000000000000F2 +:10AE600000000000000000000000000000000000E2 +:10AE700000000000000000000000000000000000D2 +:10AE800000000000000000000000000000000000C2 +:10AE900000000000000000000000000000000000B2 +:10AEA00000000000000000000000000000000000A2 +:10AEB0000000000000000000000000000000000092 +:10AEC0000000000000000000000000000000000082 +:10AED0000000000000000000000000000000000072 +:10AEE0000000000000000000000000000000000062 +:10AEF0000000000000000000000000000000000052 +:10AF00000000000000000000000000000000000041 +:10AF10000000000000000000000000000000000031 +:10AF20000000000000000000000000000000000021 +:10AF30000000000000000000000000000000000011 +:10AF40000000000000000000000000000000000001 +:10AF500000000000000000000000000000000000F1 +:10AF600000000000000000000000000000000000E1 +:10AF700000000000000000000000000000000000D1 +:10AF800000000000000000000000000000000000C1 +:10AF900000000000000000000000000000000000B1 +:10AFA00000000000000000000000000000000000A1 +:10AFB0000000000000000000000000000000000091 +:10AFC0000000000000000000000000000000000081 +:10AFD0000000000000000000000000000000000071 +:10AFE0000000000000000000000000000000000061 +:10AFF0000000000000000000000000000000000051 +:10B000000000000000000000000000000000000040 +:10B010000000000000000000000000000000000030 +:10B020000000000000000000000000000000000020 +:10B030000000000000000000000000000000000010 +:10B040000000000000000000000000000000000000 +:10B0500000000000000000000000000000000000F0 +:10B0600000000000000000000000000000000000E0 +:10B0700000000000000000000000000000000000D0 +:10B0800000000000000000000000000000000000C0 +:10B0900000000000000000000000000000000000B0 +:10B0A00000000000000000000000000000000000A0 +:10B0B0000000000000000000000000000000000090 +:10B0C0000000000000000000000000000000000080 +:10B0D0000000000000000000000000000000000070 +:10B0E0000000000000000000000000000000000060 +:10B0F0000000000000000000000000000000000050 +:10B10000000000000000000000000000000000003F +:10B11000000000000000000000000000000000002F +:10B12000000000000000000000000000000000001F +:10B13000000000000000000000000000000000000F +:10B1400000000000000000000000000000000000FF +:10B1500000000000000000000000000000000000EF +:10B1600000000000000000000000000000000000DF +:10B1700000000000000000000000000000000000CF +:10B1800000000000000000000000000000000000BF +:10B1900000000000000000000000000000000000AF +:10B1A000000000000000000000000000000000009F +:10B1B000000000000000000000000000000000008F +:10B1C000000000000000000000000000000000007F +:10B1D000000000000000000000000000000000006F +:10B1E000000000000000000000000000000000005F +:10B1F000000000000000000000000000000000004F +:10B20000000000000000000000000000000000003E +:10B21000000000000000000000000000000000002E +:10B22000000000000000000000000000000000001E +:10B23000000000000000000000000000000000000E +:10B2400000000000000000000000000000000000FE +:10B2500000000000000000000000000000000000EE +:10B2600000000000000000000000000000000000DE +:10B2700000000000000000000000000000000000CE +:10B2800000000000000000000000000000000000BE +:10B2900000000000000000000000000000000000AE +:10B2A000000000000000000000000000000000009E +:10B2B000000000000000000000000000000000008E +:10B2C000000000000000000000000000000000007E +:10B2D000000000000000000000000000000000006E +:10B2E000000000000000000000000000000000005E +:10B2F000000000000000000000000000000000004E +:10B30000000000000000000000000000000000003D +:10B31000000000000000000000000000000000002D +:10B32000000000000000000000000000000000001D +:10B33000000000000000000000000000000000000D +:10B3400000000000000000000000000000000000FD +:10B3500000000000000000000000000000000000ED +:10B3600000000000000000000000000000000000DD +:10B3700000000000000000000000000000000000CD +:10B3800000000000000000000000000000000000BD +:10B3900000000000000000000000000000000000AD +:10B3A000000000000000000000000000000000009D +:10B3B000000000000000000000000000000000008D +:10B3C000000000000000000000000000000000007D +:10B3D000000000000000000000000000000000006D +:10B3E000000000000000000000000000000000005D +:10B3F000000000000000000000000000000000004D +:10B40000000000000000000000000000000000003C +:10B41000000000000000000000000000000000002C +:10B42000000000000000000000000000000000001C +:10B43000000000000000000000000000000000000C +:10B4400000000000000000000000000000000000FC +:10B4500000000000000000000000000000000000EC +:10B4600000000000000000000000000000000000DC +:10B4700000000000000000000000000000000000CC +:10B4800000000000000000000000000000000000BC +:10B4900000000000000000000000000000000000AC +:10B4A000000000000000000000000000000000009C +:10B4B000000000000000000000000000000000008C +:10B4C000000000000000000000000000000000007C +:10B4D000000000000000000000000000000000006C +:10B4E000000000000000000000000000000000005C +:10B4F000000000000000000000000000000000004C +:10B50000000000000000000000000000000000003B +:10B51000000000000000000000000000000000002B +:10B52000000000000000000000000000000000001B +:10B53000000000000000000000000000000000000B +:10B5400000000000000000000000000000000000FB +:10B5500000000000000000000000000000000000EB +:10B5600000000000000000000000000000000000DB +:10B5700000000000000000000000000000000000CB +:10B5800000000000000000000000000000000000BB +:10B5900000000000000000000000000000000000AB +:10B5A000000000000000000000000000000000009B +:10B5B000000000000000000000000000000000008B +:10B5C000000000000000000000000000000000007B +:10B5D000000000000000000000000000000000006B +:10B5E000000000000000000000000000000000005B +:10B5F000000000000000000000000000000000004B +:10B60000000000000000000000000000000000003A +:10B61000000000000000000000000000000000002A +:10B62000000000000000000000000000000000001A +:10B63000000000000000000000000000000000000A +:10B6400000000000000000000000000000000000FA +:10B6500000000000000000000000000000000000EA +:10B6600000000000000000000000000000000000DA +:10B6700000000000000000000000000000000000CA +:10B6800000000000000000000000000000000000BA +:10B6900000000000000000000000000000000000AA +:10B6A000000000000000000000000000000000009A +:10B6B000000000000000000000000000000000008A +:10B6C000000000000000000000000000000000007A +:10B6D000000000000000000000000000000000006A +:10B6E000000000000000000000000000000000005A +:10B6F000000000000000000000000000000000004A +:10B700000000000000000000000000000000000039 +:10B710000000000000000000000000000000000029 +:10B720000000000000000000000000000000000019 +:10B730000000000000000000000000000000000009 +:10B7400000000000000000000000000000000000F9 +:10B7500000000000000000000000000000000000E9 +:10B7600000000000000000000000000000000000D9 +:10B7700000000000000000000000000000000000C9 +:10B7800000000000000000000000000000000000B9 +:10B7900000000000000000000000000000000000A9 +:10B7A0000000000000000000000000000000000099 +:10B7B0000000000000000000000000000000000089 +:10B7C0000000000000000000000000000000000079 +:10B7D0000000000000000000000000000000000069 +:10B7E0000000000000000000000000000000000059 +:10B7F0000000000000000000000000000000000049 +:10B800000000000000000000000000000000000038 +:10B810000000000000000000000000000000000028 +:10B820000000000000000000000000000000000018 +:10B830000000000000000000000000000000000008 +:10B8400000000000000000000000000000000000F8 +:10B8500000000000000000000000000000000000E8 +:10B8600000000000000000000000000000000000D8 +:10B8700000000000000000000000000000000000C8 +:10B8800000000000000000000000000000000000B8 +:10B8900000000000000000000000000000000000A8 +:10B8A0000000000000000000000000000000000098 +:10B8B0000000000000000000000000000000000088 +:10B8C0000000000000000000000000000000000078 +:10B8D0000000000000000000000000000000000068 +:10B8E0000000000000000000000000000000000058 +:10B8F0000000000000000000000000000000000048 +:10B900000000000000000000000000000000000037 +:10B910000000000000000000000000000000000027 +:10B920000000000000000000000000000000000017 +:10B930000000000000000000000000000000000007 +:10B9400000000000000000000000000000000000F7 +:10B9500000000000000000000000000000000000E7 +:10B9600000000000000000000000000000000000D7 +:10B9700000000000000000000000000000000000C7 +:10B9800000000000000000000000000000000000B7 +:10B9900000000000000000000000000000000000A7 +:10B9A0000000000000000000000000000000000097 +:10B9B0000000000000000000000000000000000087 +:10B9C0000000000000000000000000000000000077 +:10B9D0000000000000000000000000000000000067 +:10B9E0000000000000000000000000000000000057 +:10B9F0000000000000000000000000000000000047 +:10BA00000000000000000000000000000000000036 +:10BA10000000000000000000000000000000000026 +:10BA20000000000000000000000000000000000016 +:10BA30000000000000000000000000000000000006 +:10BA400000000000000000000000000000000000F6 +:10BA500000000000000000000000000000000000E6 +:10BA600000000000000000000000000000000000D6 +:10BA700000000000000000000000000000000000C6 +:10BA800000000000000000000000000000000000B6 +:10BA900000000000000000000000000000000000A6 +:10BAA0000000000000000000000000000000000096 +:10BAB0000000000000000000000000000000000086 +:10BAC0000000000000000000000000000000000076 +:10BAD0000000000000000000000000000000000066 +:10BAE0000000000000000000000000000000000056 +:10BAF0000000000000000000000000000000000046 +:10BB00000000000000000000000000000000000035 +:10BB10000000000000000000000000000000000025 +:10BB20000000000000000000000000000000000015 +:10BB30000000000000000000000000000000000005 +:10BB400000000000000000000000000000000000F5 +:10BB500000000000000000000000000000000000E5 +:10BB600000000000000000000000000000000000D5 +:10BB700000000000000000000000000000000000C5 +:10BB800000000000000000000000000000000000B5 +:10BB900000000000000000000000000000000000A5 +:10BBA0000000000000000000000000000000000095 +:10BBB0000000000000000000000000000000000085 +:10BBC0000000000000000000000000000000000075 +:10BBD0000000000000000000000000000000000065 +:10BBE0000000000000000000000000000000000055 +:10BBF0000000000000000000000000000000000045 +:10BC00000000000000000000000000000000000034 +:10BC10000000000000000000000000000000000024 +:10BC20000000000000000000000000000000000014 +:10BC30000000000000000000000000000000000004 +:10BC400000000000000000000000000000000000F4 +:10BC500000000000000000000000000000000000E4 +:10BC600000000000000000000000000000000000D4 +:10BC700000000000000000000000000000000000C4 +:10BC800000000000000000000000000000000000B4 +:10BC900000000000000000000000000000000000A4 +:10BCA0000000000000000000000000000000000094 +:10BCB0000000000000000000000000000000000084 +:10BCC0000000000000000000000000000000000074 +:10BCD0000000000000000000000000000000000064 +:10BCE0000000000000000000000000000000000054 +:10BCF0000000000000000000000000000000000044 +:10BD00000000000000000000000000000000000033 +:10BD10000000000000000000000000000000000023 +:10BD20000000000000000000000000000000000013 +:10BD30000000000000000000000000000000000003 +:10BD400000000000000000000000000000000000F3 +:10BD500000000000000000000000000000000000E3 +:10BD600000000000000000000000000000000000D3 +:10BD700000000000000000000000000000000000C3 +:10BD800000000000000000000000000000000000B3 +:10BD900000000000000000000000000000000000A3 +:10BDA0000000000000000000000000000000000093 +:10BDB0000000000000000000000000000000000083 +:10BDC0000000000000000000000000000000000073 +:10BDD0000000000000000000000000000000000063 +:10BDE0000000000000000000000000000000000053 +:10BDF0000000000000000000000000000000000043 +:10BE00000000000000000000000000000000000032 +:10BE10000000000000000000000000000000000022 +:10BE20000000000000000000000000000000000012 +:10BE30000000000000000000000000000000000002 +:10BE400000000000000000000000000000000000F2 +:10BE500000000000000000000000000000000000E2 +:10BE600000000000000000000000000000000000D2 +:10BE700000000000000000000000000000000000C2 +:10BE800000000000000000000000000000000000B2 +:10BE900000000000000000000000000000000000A2 +:10BEA0000000000000000000000000000000000092 +:10BEB0000000000000000000000000000000000082 +:10BEC0000000000000000000000000000000000072 +:10BED0000000000000000000000000000000000062 +:10BEE0000000000000000000000000000000000052 +:10BEF0000000000000000000000000000000000042 +:10BF00000000000000000000000000000000000031 +:10BF10000000000000000000000000000000000021 +:10BF20000000000000000000000000000000000011 +:10BF30000000000000000000000000000000000001 +:10BF400000000000000000000000000000000000F1 +:10BF500000000000000000000000000000000000E1 +:10BF600000000000000000000000000000000000D1 +:10BF700000000000000000000000000000000000C1 +:10BF800000000000000000000000000000000000B1 +:10BF900000000000000000000000000000000000A1 +:10BFA0000000000000000000000000000000000091 +:10BFB0000000000000000000000000000000000081 +:10BFC0000000000000000000000000000000000071 +:10BFD0000000000000000000000000000000000061 +:10BFE0000000000000000000000000000000000051 +:10BFF0000000000000000000000000000000000041 +:10C000000000000000000000000000000000000030 +:10C010000000000000000000000000000000000020 +:10C020000000000000000000000000000000000010 +:10C030000000000000000000000000000000000000 +:10C0400000000000000000000000000000000000F0 +:10C0500000000000000000000000000000000000E0 +:10C0600000000000000000000000000000000000D0 +:10C0700000000000000000000000000000000000C0 +:10C0800000000000000000000000000000000000B0 +:10C0900000000000000000000000000000000000A0 +:10C0A0000000000000000000000000000000000090 +:10C0B0000000000000000000000000000000000080 +:10C0C0000000000000000000000000000000000070 +:10C0D0000000000000000000000000000000000060 +:10C0E0000000000000000000000000000000000050 +:10C0F0000000000000000000000000000000000040 +:10C10000000000000000000000000000000000002F +:10C11000000000000000000000000000000000001F +:10C12000000000000000000000000000000000000F +:10C1300000000000000000000000000000000000FF +:10C1400000000000000000000000000000000000EF +:10C1500000000000000000000000000000000000DF +:10C1600000000000000000000000000000000000CF +:10C1700000000000000000000000000000000000BF +:10C1800000000000000000000000000000000000AF +:10C19000000000000000000000000000000000009F +:10C1A000000000000000000000000000000000008F +:10C1B000000000000000000000000000000000007F +:10C1C000000000000000000000000000000000006F +:10C1D000000000000000000000000000000000005F +:10C1E000000000000000000000000000000000004F +:10C1F000000000000000000000000000000000003F +:10C20000000000000000000000000000000000002E +:10C21000000000000000000000000000000000001E +:10C22000000000000000000000000000000000000E +:10C2300000000000000000000000000000000000FE +:10C2400000000000000000000000000000000000EE +:10C2500000000000000000000000000000000000DE +:10C2600000000000000000000000000000000000CE +:10C2700000000000000000000000000000000000BE +:10C2800000000000000000000000000000000000AE +:10C29000000000000000000000000000000000009E +:10C2A000000000000000000000000000000000008E +:10C2B000000000000000000000000000000000007E +:10C2C000000000000000000000000000000000006E +:10C2D000000000000000000000000000000000005E +:10C2E000000000000000000000000000000000004E +:10C2F000000000000000000000000000000000003E +:10C30000000000000000000000000000000000002D +:10C31000000000000000000000000000000000001D +:10C32000000000000000000000000000000000000D +:10C3300000000000000000000000000000000000FD +:10C3400000000000000000000000000000000000ED +:10C3500000000000000000000000000000000000DD +:10C3600000000000000000000000000000000000CD +:10C3700000000000000000000000000000000000BD +:10C3800000000000000000000000000000000000AD +:10C39000000000000000000000000000000000009D +:10C3A000000000000000000000000000000000008D +:10C3B000000000000000000000000000000000007D +:10C3C000000000000000000000000000000000006D +:10C3D000000000000000000000000000000000005D +:10C3E000000000000000000000000000000000004D +:10C3F000000000000000000000000000000000003D +:10C40000000000000000000000000000000000002C +:10C41000000000000000000000000000000000001C +:10C42000000000000000000000000000000000000C +:10C4300000000000000000000000000000000000FC +:10C4400000000000000000000000000000000000EC +:10C4500000000000000000000000000000000000DC +:10C4600000000000000000000000000000000000CC +:10C4700000000000000000000000000000000000BC +:10C4800000000000000000000000000000000000AC +:10C49000000000000000000000000000000000009C +:10C4A000000000000000000000000000000000008C +:10C4B000000000000000000000000000000000007C +:10C4C000000000000000000000000000000000006C +:10C4D000000000000000000000000000000000005C +:10C4E000000000000000000000000000000000004C +:10C4F000000000000000000000000000000000003C +:10C50000000000000000000000000000000000002B +:10C51000000000000000000000000000000000001B +:10C52000000000000000000000000000000000000B +:10C5300000000000000000000000000000000000FB +:10C5400000000000000000000000000000000000EB +:10C5500000000000000000000000000000000000DB +:10C5600000000000000000000000000000000000CB +:10C5700000000000000000000000000000000000BB +:10C5800000000000000000000000000000000000AB +:10C59000000000000000000000000000000000009B +:10C5A000000000000000000000000000000000008B +:10C5B000000000000000000000000000000000007B +:10C5C000000000000000000000000000000000006B +:10C5D000000000000000000000000000000000005B +:10C5E000000000000000000000000000000000004B +:10C5F000000000000000000000000000000000003B +:10C60000000000000000000000000000000000002A +:10C61000000000000000000000000000000000001A +:10C62000000000000000000000000000000000000A +:10C6300000000000000000000000000000000000FA +:10C6400000000000000000000000000000000000EA +:10C6500000000000000000000000000000000000DA +:10C6600000000000000000000000000000000000CA +:10C6700000000000000000000000000000000000BA +:10C6800000000000000000000000000000000000AA +:10C69000000000000000000000000000000000009A +:10C6A000000000000000000000000000000000008A +:10C6B000000000000000000000000000000000007A +:10C6C000000000000000000000000000000000006A +:10C6D000000000000000000000000000000000005A +:10C6E000000000000000000000000000000000004A +:10C6F000000000000000000000000000000000003A +:10C700000000000000000000000000000000000029 +:10C710000000000000000000000000000000000019 +:10C720000000000000000000000000000000000009 +:10C7300000000000000000000000000000000000F9 +:10C7400000000000000000000000000000000000E9 +:10C7500000000000000000000000000000000000D9 +:10C7600000000000000000000000000000000000C9 +:10C7700000000000000000000000000000000000B9 +:10C7800000000000000000000000000000000000A9 +:10C790000000000000000000000000000000000099 +:10C7A0000000000000000000000000000000000089 +:10C7B0000000000000000000000000000000000079 +:10C7C0000000000000000000000000000000000069 +:10C7D0000000000000000000000000000000000059 +:10C7E0000000000000000000000000000000000049 +:10C7F0000000000000000000000000000000000039 +:10C800000000000000000000000000000000000028 +:10C810000000000000000000000000000000000018 +:10C820000000000000000000000000000000000008 +:10C8300000000000000000000000000000000000F8 +:10C8400000000000000000000000000000000000E8 +:10C8500000000000000000000000000000000000D8 +:10C8600000000000000000000000000000000000C8 +:10C8700000000000000000000000000000000000B8 +:10C8800000000000000000000000000000000000A8 +:10C890000000000000000000000000000000000098 +:10C8A0000000000000000000000000000000000088 +:10C8B0000000000000000000000000000000000078 +:10C8C0000000000000000000000000000000000068 +:10C8D0000000000000000000000000000000000058 +:10C8E0000000000000000000000000000000000048 +:10C8F0000000000000000000000000000000000038 +:10C900000000000000000000000000000000000027 +:10C910000000000000000000000000000000000017 +:10C920000000000000000000000000000000000007 +:10C9300000000000000000000000000000000000F7 +:10C9400000000000000000000000000000000000E7 +:10C9500000000000000000000000000000000000D7 +:10C9600000000000000000000000000000000000C7 +:10C9700000000000000000000000000000000000B7 +:10C9800000000000000000000000000000000000A7 +:10C990000000000000000000000000000000000097 +:10C9A0000000000000000000000000000000000087 +:10C9B0000000000000000000000000000000000077 +:10C9C0000000000000000000000000000000000067 +:10C9D0000000000000000000000000000000000057 +:10C9E0000000000000000000000000000000000047 +:10C9F0000000000000000000000000000000000037 +:10CA00000000000000000000000000000000000026 +:10CA10000000000000000000000000000000000016 +:10CA20000000000000000000000000000000000006 +:10CA300000000000000000000000000000000000F6 +:10CA400000000000000000000000000000000000E6 +:10CA500000000000000000000000000000000000D6 +:10CA600000000000000000000000000000000000C6 +:10CA700000000000000000000000000000000000B6 +:10CA800000000000000000000000000000000000A6 +:10CA90000000000000000000000000000000000096 +:10CAA0000000000000000000000000000000000086 +:10CAB0000000000000000000000000000000000076 +:10CAC0000000000000000000000000000000000066 +:10CAD0000000000000000000000000000000000056 +:10CAE0000000000000000000000000000000000046 +:10CAF0000000000000000000000000000000000036 +:10CB00000000000000000000000000000000000025 +:10CB10000000000000000000000000000000000015 +:10CB20000000000000000000000000000000000005 +:10CB300000000000000000000000000000000000F5 +:10CB400000000000000000000000000000000000E5 +:10CB500000000000000000000000000000000000D5 +:10CB600000000000000000000000000000000000C5 +:10CB700000000000000000000000000000000000B5 +:10CB800000000000000000000000000000000000A5 +:10CB90000000000000000000000000000000000095 +:10CBA0000000000000000000000000000000000085 +:10CBB0000000000000000000000000000000000075 +:10CBC0000000000000000000000000000000000065 +:10CBD0000000000000000000000000000000000055 +:10CBE0000000000000000000000000000000000045 +:10CBF0000000000000000000000000000000000035 +:10CC00000000000000000000000000000000000024 +:10CC10000000000000000000000000000000000014 +:10CC20000000000000000000000000000000000004 +:10CC300000000000000000000000000000000000F4 +:10CC400000000000000000000000000000000000E4 +:10CC500000000000000000000000000000000000D4 +:10CC600000000000000000000000000000000000C4 +:10CC700000000000000000000000000000000000B4 +:10CC800000000000000000000000000000000000A4 +:10CC90000000000000000000000000000000000094 +:10CCA0000000000000000000000000000000000084 +:10CCB0000000000000000000000000000000000074 +:10CCC0000000000000000000000000000000000064 +:10CCD0000000000000000000000000000000000054 +:10CCE0000000000000000000000000000000000044 +:10CCF0000000000000000000000000000000000034 +:10CD00000000000000000000000000000000000023 +:10CD10000000000000000000000000000000000013 +:10CD20000000000000000000000000000000000003 +:10CD300000000000000000000000000000000000F3 +:10CD400000000000000000000000000000000000E3 +:10CD500000000000000000000000000000000000D3 +:10CD600000000000000000000000000000000000C3 +:10CD700000000000000000000000000000000000B3 +:10CD800000000000000000000000000000000000A3 +:10CD90000000000000000000000000000000000093 +:10CDA0000000000000000000000000000000000083 +:10CDB0000000000000000000000000000000000073 +:10CDC0000000000000000000000000000000000063 +:10CDD0000000000000000000000000000000000053 +:10CDE0000000000000000000000000000000000043 +:10CDF0000000000000000000000000000000000033 +:10CE00000000000000000000000000000000000022 +:10CE10000000000000000000000000000000000012 +:10CE20000000000000000000000000000000000002 +:10CE300000000000000000000000000000000000F2 +:10CE400000000000000000000000000000000000E2 +:10CE500000000000000000000000000000000000D2 +:10CE600000000000000000000000000000000000C2 +:10CE700000000000000000000000000000000000B2 +:10CE800000000000000000000000000000000000A2 +:10CE90000000000000000000000000000000000092 +:10CEA0000000000000000000000000000000000082 +:10CEB0000000000000000000000000000000000072 +:10CEC0000000000000000000000000000000000062 +:10CED0000000000000000000000000000000000052 +:10CEE0000000000000000000000000000000000042 +:10CEF0000000000000000000000000000000000032 +:10CF00000000000000000000000000000000000021 +:10CF10000000000000000000000000000000000011 +:10CF20000000000000000000000000000000000001 +:10CF300000000000000000000000000000000000F1 +:10CF400000000000000000000000000000000000E1 +:10CF500000000000000000000000000000000000D1 +:10CF600000000000000000000000000000000000C1 +:10CF700000000000000000000000000000000000B1 +:10CF800000000000000000000000000000000000A1 +:10CF90000000000000000000000000000000000091 +:10CFA0000000000000000000000000000000000081 +:10CFB0000000000000000000000000000000000071 +:10CFC0000000000000000000000000000000000061 +:10CFD0000000000000000000000000000000000051 +:10CFE0000000000000000000000000000000000041 +:10CFF0000000000000000000000000000000000031 +:10D000000000000000000000000000000000000020 +:10D010000000000000000000000000000000000010 +:10D020000000000000000000000000000000000000 +:10D0300000000000000000000000000000000000F0 +:10D0400000000000000000000000000000000000E0 +:10D0500000000000000000000000000000000000D0 +:10D0600000000000000000000000000000000000C0 +:10D0700000000000000000000000000000000000B0 +:10D0800000000000000000000000000000000000A0 +:10D090000000000000000000000000000000000090 +:10D0A0000000000000000000000000000000000080 +:10D0B0000000000000000000000000000000000070 +:10D0C0000000000000000000000000000000000060 +:10D0D0000000000000000000000000000000000050 +:10D0E0000000000000000000000000000000000040 +:10D0F0000000000000000000000000000000000030 +:10D10000000000000000000000000000000000001F +:10D11000000000000000000000000000000000000F +:10D1200000000000000000000000000000000000FF +:10D1300000000000000000000000000000000000EF +:10D1400000000000000000000000000000000000DF +:10D1500000000000000000000000000000000000CF +:10D1600000000000000000000000000000000000BF +:10D1700000000000000000000000000000000000AF +:10D18000000000000000000000000000000000009F +:10D19000000000000000000000000000000000008F +:10D1A000000000000000000000000000000000007F +:10D1B000000000000000000000000000000000006F +:10D1C000000000000000000000000000000000005F +:10D1D000000000000000000000000000000000004F +:10D1E000000000000000000000000000000000003F +:10D1F000000000000000000000000000000000002F +:10D20000000000000000000000000000000000001E +:10D21000000000000000000000000000000000000E +:10D2200000000000000000000000000000000000FE +:10D2300000000000000000000000000000000000EE +:10D2400000000000000000000000000000000000DE +:10D2500000000000000000000000000000000000CE +:10D2600000000000000000000000000000000000BE +:10D2700000000000000000000000000000000000AE +:10D28000000000000000000000000000000000009E +:10D29000000000000000000000000000000000008E +:10D2A000000000000000000000000000000000007E +:10D2B000000000000000000000000000000000006E +:10D2C000000000000000000000000000000000005E +:10D2D000000000000000000000000000000000004E +:10D2E000000000000000000000000000000000003E +:10D2F000000000000000000000000000000000002E +:10D30000000000000000000000000000000000001D +:10D31000000000000000000000000000000000000D +:10D3200000000000000000000000000000000000FD +:10D3300000000000000000000000000000000000ED +:10D3400000000000000000000000000000000000DD +:10D3500000000000000000000000000000000000CD +:10D3600000000000000000000000000000000000BD +:10D3700000000000000000000000000000000000AD +:10D38000000000000000000000000000000000009D +:10D39000000000000000000000000000000000008D +:10D3A000000000000000000000000000000000007D +:10D3B000000000000000000000000000000000006D +:10D3C000000000000000000000000000000000005D +:10D3D000000000000000000000000000000000004D +:10D3E000000000000000000000000000000000003D +:10D3F000000000000000000000000000000000002D +:10D40000000000000000000000000000000000001C +:10D41000000000000000000000000000000000000C +:10D4200000000000000000000000000000000000FC +:10D4300000000000000000000000000000000000EC +:10D4400000000000000000000000000000000000DC +:10D4500000000000000000000000000000000000CC +:10D4600000000000000000000000000000000000BC +:10D4700000000000000000000000000000000000AC +:10D48000000000000000000000000000000000009C +:10D49000000000000000000000000000000000008C +:10D4A000000000000000000000000000000000007C +:10D4B000000000000000000000000000000000006C +:10D4C000000000000000000000000000000000005C +:10D4D000000000000000000000000000000000004C +:10D4E000000000000000000000000000000000003C +:10D4F000000000000000000000000000000000002C +:10D50000000000000000000000000000000000001B +:10D51000000000000000000000000000000000000B +:10D5200000000000000000000000000000000000FB +:10D5300000000000000000000000000000000000EB +:10D5400000000000000000000000000000000000DB +:10D5500000000000000000000000000000000000CB +:10D5600000000000000000000000000000000000BB +:10D5700000000000000000000000000000000000AB +:10D58000000000000000000000000000000000009B +:10D59000000000000000008000000000000000000B +:10D5A000000000000000000000000000000000007B +:10D5B00000000000000000000000000A0000000061 +:10D5C0000000000000000000100000030000000048 +:10D5D0000000000D0000000D3C02080024427340D2 +:10D5E0003C030800246377CCAC4000000043202BB0 +:10D5F0001480FFFD244200043C1D080037BD7FFC61 +:10D6000003A0F0213C100800261032103C1C08003A +:10D61000279C73400E0010FE000000000000000D6B +:10D6200030A5FFFF30C600FF274301808F4201B8BD +:10D630000440FFFE24020002AC640000A465000860 +:10D64000A066000AA062000B3C021000AC67001844 +:10D6500003E00008AF4201B83C0360008C624FF861 +:10D660000440FFFE3C020200AC644FC0AC624FC4F9 +:10D670003C02100003E00008AC624FF89482000CFA +:10D680002486001400A0382100021302000210803A +:10D690000082402100C8102B1040005700000000FD +:10D6A00090C300002C6200095040005190C200015C +:10D6B000000310803C030800246372F00043102133 +:10D6C0008C420000004000080000000090C30001F0 +:10D6D0002402000A1462003A000000000106102330 +:10D6E0002C42000A1440003624C600028CE20000DE +:10D6F00034420100ACE2000090C2000090C300017F +:10D7000090C4000290C5000300031C000002160034 +:10D710000043102500042200004410250045102578 +:10D7200024C60004ACE2000490C2000090C30001D3 +:10D7300090C4000290C500030002160000031C0004 +:10D740000043102500042200004410250045102548 +:10D7500024C600040A000CB8ACE2000890C3000123 +:10D76000240200041462001624C6000290C20000C5 +:10D7700090C400018CE30000000212000044102558 +:10D780003463000424C60002ACE2000C0A000CB8AA +:10D79000ACE3000090C300012402000314620008FF +:10D7A00024C600028CE2000090C3000024C60001E1 +:10D7B00034420008A0E300100A000CB8ACE20000FC +:10D7C00003E000082402000190C3000124020002CB +:10D7D0001062000224C40002010020210A000CB8DB +:10D7E000008030210A000CB824C6000190C200015C +:10D7F0000A000CB800C2302103E00008000010212C +:10D8000027BDFFE8AFBF0014AFB000100E00130239 +:10D8100000808021936200052403FFFE0200202186 +:10D82000004310248FBF00148FB00010A3620005C6 +:10D830000A00130B27BD001827BDFFE8AFB000108A +:10D84000AFBF00140E000F3C0080802193620000E7 +:10D8500024030050304200FF14430004240201005E +:10D86000AF4201800A000D3002002021AF4001804C +:10D87000020020218FBF00148FB000100A000FE7B4 +:10D8800027BD001827BDFF80AFBE0078AFB700747A +:10D89000AFB20060AFBF007CAFB60070AFB5006C38 +:10D8A000AFB40068AFB30064AFB1005CAFB0005874 +:10D8B0008F5001283C0208008C4231A02403FF80D5 +:10D8C0009365003F0202102100431024AF42002460 +:10D8D0003C0208008C4231A09364000530B200FF86 +:10D8E000020210213042007F034218210004202749 +:10D8F0003C02000A0062182130840001AF8300144A +:10D900000000F0210000B82114800053AFA00050A7 +:10D9100093430116934401128F450104306300FFC5 +:10D920003C020001308400FF00A2282403431021A0 +:10D9300003441821245640002467400014A001CD60 +:10D940002402000193620000304300FF2402002003 +:10D950001062000524020050106200060000000062 +:10D960000A000D74000000000000000D0A000D7D8B +:10D97000AFA000303C1E080027DE738C0A000D7D2E +:10D98000AFA000303C0208008C4200DC24420001C1 +:10D990003C010800AC2200DC0E00139F00000000D8 +:10D9A0000A000F318FBF007C8F4201043C0300202E +:10D9B00092D3000D004310240002202B00042140CC +:10D9C000AFA400308F4301043C02004000621824E1 +:10D9D000146000023485004000802821326200205B +:10D9E000AFA500301440000234A6008000A0302112 +:10D9F00010C0000BAFA6003093C500088F67004C25 +:10DA00000200202100052B0034A5008130A5F08103 +:10DA10000E000C9B30C600FF0A000F2E0000000015 +:10DA20009362003E304200401040000F2402000488 +:10DA300056420007240200120200202100E02821A3 +:10DA40000E0013F702C030210A000F318FBF007C97 +:10DA500016420005000000000E000D2100002021EC +:10DA60000A000F318FBF007C9743011A96C4000E45 +:10DA700093620035326500043075FFFF00442004D6 +:10DA8000AFA400548ED1000410A000158ED400085D +:10DA90009362003E3042004010400007000000004A +:10DAA0000E0013E0022020211040000D00000000B5 +:10DAB0000A000F2E000000008F6200440222102393 +:10DAC0000440016A000000008F6200480222102317 +:10DAD00004410166240400160A000E218FC20004CE +:10DAE0008F6200480222102304400008000000005A +:10DAF0003C0208008C423100244200013C01080035 +:10DB0000AC2231000A000F23000000008F620040A9 +:10DB100002221023184000128F8400143C020800D7 +:10DB20008C423100327300FC0000A8212442000125 +:10DB30003C010800AC2231008F6300409482011C3C +:10DB4000022318233042FFFF0043102A50400010E8 +:10DB50002402000C8F6200400A000DF20222102302 +:10DB60009483011C9762003C0043102B1040000678 +:10DB7000000000009482011C00551023A482011CA7 +:10DB80000A000DF72402000CA480011C2402000CE2 +:10DB9000AFA200308F620040005120231880000D9A +:10DBA00002A4102A1440012600000000149500066B +:10DBB00002A410233A620001304200011440012007 +:10DBC0000000000002A41023022488210A000E098C +:10DBD0003055FFFF00002021326200021040001A81 +:10DBE000326200109362003E30420040504000110B +:10DBF0008FC200040E00130202002021240200182C +:10DC0000A362003F936200052403FFFE020020216F +:10DC1000004310240E00130BA362000524040039F6 +:10DC2000000028210E0013C9240600180A000F3036 +:10DC300024020001240400170040F809000000003D +:10DC40000A000F302402000110400108000000000B +:10DC50008F63004C8F620054028210231C4001032A +:10DC600002831023044200010060A021AFA4001829 +:10DC7000AFB10010AFB50014934201208F65004092 +:10DC80009763003C304200FF034210210044102102 +:10DC90008FA400543063FFFF244240000083182B00 +:10DCA0008FA40030AFA20020AFA50028008320255C +:10DCB000AFA40030AFA50024AFA0002CAFB4003457 +:10DCC0009362003E30420008504000118FC20000B5 +:10DCD00002C0202127A500380E000CB2AFA00038EA +:10DCE0005440000B8FC200008FA200383042010068 +:10DCF000504000078FC200008FA3003C8F6200607D +:10DD00000062102304430001AF6300608FC2000073 +:10DD10000040F80927A400108FA200303042000212 +:10DD200054400001327300FE9362003E30420040D6 +:10DD3000104000378FA200248F6200541682001A10 +:10DD40003262000124020014124200102A4200151F +:10DD500010400006240200162402000C12420007A4 +:10DD6000326200010A000E7D000000001242000530 +:10DD7000326200010A000E7D000000000A000E78E9 +:10DD80002417000E0A000E78241700100A000E7CDB +:10DD900024170012936200232403FFBD00431024C4 +:10DDA000A362002332620001104000198FA20024F8 +:10DDB0002402000C1242000E2A42000D1040000600 +:10DDC0002402000E2402000A124200078FA200243F +:10DDD0000A000E9524420001124200088FA200247E +:10DDE0000A000E95244200010A000E932417000831 +:10DDF0002402000E16E20002241700162417001059 +:10DE00008FA2002424420001AFA200248FA200248C +:10DE10008FA300148F76004000431021AF620040B2 +:10DE20008F8200149442011C104000090000000081 +:10DE30008F6200488F6400409763003C00441023C9 +:10DE40003063FFFF0043102A104000088FA20054E7 +:10DE5000936400368F6300403402FFFC008210049C +:10DE600000621821AF6300488FA200548FA60030D3 +:10DE70000282902130C200081040000E0000000015 +:10DE80008F6200581642000430C600FF9742011A04 +:10DE90005040000134C6001093C500088FA700341D +:10DEA0000200202100052B0034A500800E000C9BF1 +:10DEB00030A5F0808F620040005610231840001BF0 +:10DEC0008FA200183C0208008C42319830420010AA +:10DED0001040000D24020001976200681440000AFF +:10DEE000240200018F8200149442011C1440000699 +:10DEF00024020001A76200689742007A244200646D +:10DF00000A000EE9A7620012A76200120E001302B7 +:10DF1000020020219362007D2403000102002021E1 +:10DF2000344200010A000EE7AFA300501840000A77 +:10DF3000000000000E001302020020219362007D09 +:10DF40002403000102002021AFA30050344200044A +:10DF50000E00130BA362007D9362003E304200402E +:10DF60001440000C326200011040000A0000000062 +:10DF70008F6300408FC20004240400182463000152 +:10DF80000040F809AF6300408FA200300A000F3054 +:10DF9000304200048F620058105200100000000050 +:10DFA0008F620018022210231C4000082404000184 +:10DFB0008F62001816220009000000008F62001C0A +:10DFC000028210230440000500000000AF720058D8 +:10DFD000AFA40050AF710018AF74001C12E0000B2A +:10DFE0008FA200500E00130202002021A377003FF1 +:10DFF0000E00130B0200202102E030212404003720 +:10E000000E0013C9000028218FA200501040000309 +:10E01000000000000E000CA90200202112A0000543 +:10E02000000018218FA2003030420004504000113F +:10E0300000601021240300010A000F30006010214D +:10E040000E001302020020219362007D02002021B5 +:10E05000344200040E00130BA362007D0E000CA9D5 +:10E06000020020210A000F3024020001AF400044CA +:10E07000240200018FBF007C8FBE00788FB7007430 +:10E080008FB600708FB5006C8FB400688FB30064DA +:10E090008FB200608FB1005C8FB0005803E00008C1 +:10E0A00027BD00808F4201B80440FFFE2402080013 +:10E0B000AF4201B803E00008000000003C02000885 +:10E0C00003421021944200483084FFFF2484001250 +:10E0D0003045FFFF10A0001700A4102B10400016C1 +:10E0E00024020003934201202403001AA343018B5E +:10E0F000304200FF2446FFFE8F82000000A6182B4E +:10E100003863000100021382004310241040000510 +:10E110008F84000434820001A746019403E00008C4 +:10E12000AF8200042402FFFE0082102403E00008F6 +:10E13000AF8200042402000303E00008A342018B25 +:10E1400027BDFFE0AFB10014AFB00010AFBF0018A3 +:10E1500030B0FFFF30D1FFFF8F4201B80440FFFE17 +:10E1600000000000AF440180AF4400200E000F42C9 +:10E17000020020218F8300008F840004A750019AA1 +:10E18000A750018EA74301908F8300083082800042 +:10E19000AF4301A8A75101881040000E8F820004F0 +:10E1A00093420116304200FC24420004005A102120 +:10E1B0008C4240003042FFFF144000068F82000472 +:10E1C0003C02FFFF34427FFF00821024AF82000434 +:10E1D0008F8200042403BFFF00431024A74201A63E +:10E1E0009743010C8F42010400031C003042FFFFE3 +:10E1F00000621825AF4301AC3C021000AF4201B8E9 +:10E200008FBF00188FB100148FB0001003E000081A +:10E2100027BD00208F470070934201128F830000BA +:10E2200027BDFFF0304200FF00022882306201006B +:10E23000000030211040004324A40003306240005D +:10E24000104000103062200000041080005A10219D +:10E250008C43400024A4000400041080AFA30000FD +:10E26000005A10218C424000AFA2000493420116D4 +:10E27000304200FC005A10218C4240000A000FC0BE +:10E28000AFA200081040002F0000302100041080D1 +:10E29000005A10218C43400024A400040004108084 +:10E2A000AFA30000005A10218C424000AFA000082C +:10E2B000AFA200048FA80008000030210000202138 +:10E2C000240A00083C0908002529010003A41021A4 +:10E2D000148A000300042A001100000A0000000054 +:10E2E00090420000248400012C83000C00A2102125 +:10E2F00000021080004910218C4200001460FFF3DE +:10E3000000C230263C0408008C8431048F42007027 +:10E310002C83002010600009004738233C030800CC +:10E32000246331080004108000431021248300017D +:10E33000AC4700003C010800AC233104AF86000864 +:10E340002406000100C0102103E0000827BD0010D2 +:10E350003C0208008C42003827BDFFD0AFB5002436 +:10E36000AFB40020AFB10014AFBF0028AFB3001CA2 +:10E37000AFB20018AFB00010000088213C150800B3 +:10E3800026B50038144000022454FFFF0000A021ED +:10E390009742010E8F8400003042FFFF308340001F +:10E3A0001060000A245200043C0200200082102465 +:10E3B00050400007308280008F8200042403BFFF9A +:10E3C000008318240A0010103442100030828000AC +:10E3D0001040000A3C020020008210241040000778 +:10E3E0008F8200043C03FFFF34637FFF0083182407 +:10E3F00034428000AF820004AF8300000E000F980B +:10E400000000000014400007000000009743011EB8 +:10E410009742011C3063FFFF0002140000621825C0 +:10E42000AF8300089742010C8F4340003045FFFF47 +:10E430003402FFFF14620003000000000A001028ED +:10E44000241100208F42400030420100544000015E +:10E45000241100108F8400003082100050400014FE +:10E4600036310001308200201440000B3C021000C5 +:10E47000008210245040000E363100013C030E0093 +:10E480003C020DFF008318243442FFFF0043102B91 +:10E4900050400007363100013C0208008C42002C3D +:10E4A000244200013C010800AC22002C363100055A +:10E4B0003C0608008CC6003454C000238F85000041 +:10E4C0008F820004304240005440001F8F850000BE +:10E4D0003C021F01008210243C0310005443001A28 +:10E4E0008F85000030A20200144000178F850000C5 +:10E4F0003250FFFF363100028F4201B80440FFFE68 +:10E5000000000000AF400180020020210E000F42F9 +:10E51000AF4000208F8300042402BFFFA750019A60 +:10E52000006218248F820000A750018EA751018835 +:10E53000A74301A6A74201903C021000AF4201B8D8 +:10E540000A0010F5000010213C02100000A2102467 +:10E550001040003A0000000010C0000F0000000052 +:10E5600030A201001040000C3C0302003C020F00EE +:10E5700000A2102410430008000000008F82000851 +:10E58000005410240055102190420004244200043D +:10E590000A00109F000221C00000000000051602C2 +:10E5A0003050000F3A0300022E4203EF38420001C0 +:10E5B0002C6300010062182414600073240200011F +:10E5C0003C0308008C6300D02E06000C386200016A +:10E5D0002C4200010046102414400015001021C0F8 +:10E5E0002602FFFC2C4200045440001100002021B0 +:10E5F000386200022C420001004610241040000343 +:10E60000000512420A00109F000020210010182B64 +:10E610000043102450400006001021C000002021BB +:10E620003245FFFF0E000F633226FFFB001021C0B2 +:10E630003245FFFF0A0010F2362600028F424000EA +:10E640003C0308008C630024304201001040004667 +:10E6500030620001322200043070000D14400002CC +:10E660002413000424130002000512C238420001E2 +:10E670002E4303EF304200013863000100431025B0 +:10E68000104000033231FFFB2402FFFB0202802412 +:10E6900010C000183202000130A201001040001525 +:10E6A000320200013C020F0000A210243C030200D1 +:10E6B0001043000F8F8200082403FFFE0203802412 +:10E6C00000541024005510219042000402333025DC +:10E6D0002442000412000002000221C03226FFFF83 +:10E6E0000E000F633245FFFF1200002700001021CB +:10E6F000320200011040000D320200042402000129 +:10E7000012020002023330253226FFFF00002021D2 +:10E710000E000F633245FFFF2402FFFE0202802439 +:10E7200012000019000010213202000410400016EF +:10E7300024020001240200041202000202333025E8 +:10E740003226FFFF3245FFFF0E000F632404010055 +:10E750002402FFFB020280241200000B00001021A3 +:10E760000A0010F5240200011040000700001021EB +:10E770003245FFFF36260002000020210E000F6305 +:10E7800000000000000010218FBF00288FB500247A +:10E790008FB400208FB3001C8FB200188FB100140B +:10E7A0008FB0001003E0000827BD003027BDFFD068 +:10E7B000AFB000103C04600CAFBF002CAFB6002817 +:10E7C000AFB50024AFB40020AFB3001CAFB2001847 +:10E7D000AFB100148C8250002403FF7F3C1A8000EC +:10E7E000004310243442380CAC8250002402000351 +:10E7F0003C106000AF4200088E0208083C1B8008F5 +:10E800003C010800AC2000203042FFF038420010EC +:10E810002C4200010E001B8DAF8200183C04FFFF4C +:10E820003C020400348308063442000CAE0219484E +:10E83000AE03194C3C0560168E0219808CA30000B3 +:10E840003442020000641824AE0219803C02535383 +:10E850001462000334A47C008CA200040050202128 +:10E860008C82007C8C830078AF820010AF83000C18 +:10E870008F55000032A200031040FFFD32A20001BC +:10E880001040013D32A200028F420128AF42002019 +:10E890008F4201048F430100AF8200000E000F3C45 +:10E8A000AF8300043C0208008C4200C01040000806 +:10E8B0008F8400003C0208008C4200C42442000106 +:10E8C0003C010800AC2200C40A00126900000000EC +:10E8D0003C020010008210241440010C8F830004BD +:10E8E0003C0208008C4200203C0308008C63003886 +:10E8F00000008821244200013C010800AC220020D5 +:10E900003C16080026D60038146000022474FFFF6D +:10E910000000A0219742010E308340003042FFFFEB +:10E920001060000A245200043C02002000821024DF +:10E9300050400007308280008F8200042403BFFF14 +:10E94000008318240A0011703442100030828000C5 +:10E950001040000A3C0200200082102410400007F2 +:10E960008F8200043C03FFFF34637FFF0083182481 +:10E9700034428000AF820004AF8300000E000F9885 +:10E980000000000014400007000000009743011E33 +:10E990009742011C3063FFFF00021400006218253B +:10E9A000AF8300089742010C8F4340003045FFFFC2 +:10E9B0003402FFFF14620003000000000A00118807 +:10E9C000241100208F4240003042010054400001D9 +:10E9D000241100108F840000308210005040001479 +:10E9E00036310001308200201440000B3C02100040 +:10E9F000008210245040000E363100013C030E000E +:10EA00003C020DFF008318243442FFFF0043102B0B +:10EA100050400007363100013C0208008C42002CB7 +:10EA2000244200013C010800AC22002C36310005D4 +:10EA30003C0608008CC6003454C000238F850000BB +:10EA40008F820004304240005440001F8F85000038 +:10EA50003C021F01008210243C0310005443001AA2 +:10EA60008F85000030A20200144000178F8500003F +:10EA70003250FFFF363100028F4201B80440FFFEE2 +:10EA800000000000AF400180020020210E000F4274 +:10EA9000AF4000208F8300042402BFFFA750019ADB +:10EAA000006218248F820000A750018EA7510188B0 +:10EAB000A74301A6A74201903C021000AF4201B853 +:10EAC0000A001267000010213C02100000A210246E +:10EAD0001040003A0000000010C0000F00000000CD +:10EAE00030A201001040000C3C0302003C020F0069 +:10EAF00000A2102410430008000000008F820008CC +:10EB000000541024005610219042000424420004B6 +:10EB10000A0011FF000221C00000000000051602DB +:10EB20003050000F3A0300022E4203EF384200013A +:10EB30002C63000100621824146000852402000187 +:10EB40003C0308008C6300D02E06000C38620001E4 +:10EB50002C4200010046102414400015001021C072 +:10EB60002602FFFC2C42000454400011000020212A +:10EB7000386200022C42000100461024504000037D +:10EB8000000512420A0011FF000020210010182B7E +:10EB90000043102450400006001021C00000202136 +:10EBA0003245FFFF0E000F633226FFFB001021C02D +:10EBB0003245FFFF0A001252362600028F42400003 +:10EBC0003C0308008C6300243042010010400046E2 +:10EBD00030620001322200043070000D1440000247 +:10EBE0002413000424130002000512C2384200015D +:10EBF0002E4303EF3042000138630001004310252B +:10EC0000104000033231FFFB2402FFFB020280248C +:10EC100010C000183202000130A20100104000159F +:10EC2000320200013C020F0000A210243C0302004B +:10EC30001043000F8F8200082403FFFE020380248C +:10EC40000054102400561021904200040233302555 +:10EC50002442000412000002000221C03226FFFFFD +:10EC60000E000F633245FFFF120000390000102133 +:10EC7000320200011040000D3202000424020001A3 +:10EC800012020002023330253226FFFF000020214D +:10EC90000E000F633245FFFF2402FFFE02028024B4 +:10ECA0001200002B00001021320200041040002846 +:10ECB0002402000124020004120200020233302563 +:10ECC0003226FFFF3245FFFF0E000F6324040100D0 +:10ECD0002402FFFB020280241200001D000010210C +:10ECE0000A001267240200015040001900001021A0 +:10ECF0003245FFFF36260002000020210E000F6380 +:10ED0000000000000A001267000010212402BFFF6B +:10ED1000006210241040000800000000240287FF59 +:10ED200000621024144000083C020060008210249D +:10ED300010400005000000000E000D34000000002F +:10ED40000A001267000000000E0012C70000000059 +:10ED5000104000063C0240008F4301243C0260202A +:10ED6000AC430014000000003C024000AF420138F8 +:10ED70000000000032A200021040FEBD00000000B2 +:10ED80008F4201403C044000AF4200208F430148C5 +:10ED90003C02700000621824106400420000000071 +:10EDA0000083102B144000063C0260003C0220004F +:10EDB000106200073C0240000A0012C3000000007D +:10EDC0001062003C3C0240000A0012C30000000038 +:10EDD0008F4501408F4601448F42014800021402D2 +:10EDE000304300FF240200041462000A274401801B +:10EDF0008F4201B80440FFFE2402001CAC850000D5 +:10EE0000A082000B3C021000AF4201B80A0012C3FE +:10EE10003C0240002402000914620012000616029F +:10EE2000000229C0AF4500208F4201B80440FFFE18 +:10EE30002402000124030003AF450180A343018B9A +:10EE4000A740018EA740019AA7400190AF4001A8BA +:10EE5000A7420188A74201A6AF4001AC3C021000C6 +:10EE6000AF4201B88F4201B80440FFFE000000002D +:10EE7000AC8500008F42014800021402A482000801 +:10EE800024020002A082000B8F420148A4820010DD +:10EE90003C021000AC860024AF4201B80A0012C345 +:10EEA0003C0240000E001310000000000A0012C3D4 +:10EEB0003C0240000E001BC2000000003C0240006B +:10EEC000AF420178000000000A00112F000000008E +:10EED0008F4201003042003E144000112402000124 +:10EEE000AF4000488F420100304207C0104000058B +:10EEF00000000000AF40004CAF40005003E00008AD +:10EF000024020001AF400054AF4000408F42010096 +:10EF10003042380054400001AF4000442402000158 +:10EF200003E00008000000008F4201B80440FFFE2B +:10EF300024020001AF440180AF400184A74501884D +:10EF4000A342018A24020002A342018B9742014A94 +:10EF500014C00004A7420190AF4001A40A0012EFC0 +:10EF60003C0210008F420144AF4201A43C02100059 +:10EF7000AF4001A803E00008AF4201B88F4201B8DA +:10EF80000440FFFE24020002AF440180AF4401842C +:10EF9000A7450188A342018AA342018B9742014AF7 +:10EFA000A7420190AF4001A48F420144AF4201A8A3 +:10EFB0003C02100003E00008AF4201B83C029000A0 +:10EFC0003442000100822025AF4400208F420020FF +:10EFD0000440FFFE0000000003E000080000000005 +:10EFE0003C028000344200010082202503E000083A +:10EFF000AF44002027BDFFE8AFBF0014AFB0001042 +:10F000008F50014093430149934201489344014882 +:10F01000306300FF304200FF00021200006228252A +:10F020002402001910620076308400802862001AE1 +:10F030001040001C24020020240200081062007707 +:10F04000286200091040000E2402000B2402000177 +:10F0500010620034286200025040000524020006BD +:10F0600050600034020020210A00139A00000000C2 +:10F0700010620030020020210A00139A00000000F4 +:10F080001062003B2862000C504000022402000E77 +:10F090002402000910620056020020210A00139A7F +:10F0A0000000000010620056286200211040000F8E +:10F0B000240200382402001C106200582862001D3F +:10F0C000104000062402001F2402001B1062004CA6 +:10F0D000000000000A00139A000000001062004ABD +:10F0E000020020210A00139A00000000106200456F +:10F0F0002862003910400007240200802462FFCB00 +:10F100002C42000210400045020020210A00139604 +:10F110000000302110620009000000000A00139A6C +:10F12000000000001480003D020020210A0013901E +:10F130008FBF00140A001396240600018F4201B805 +:10F140000440FFFE24020002A342018BA745018870 +:10F150009742014AA74201908F420144A74201927F +:10F160003C021000AF4201B80A00139C8FBF00148C +:10F170009742014A144000290000000093620005F4 +:10F180003042000414400025000000000E0013026D +:10F190000200202193620005020020213442000475 +:10F1A0000E00130BA36200059362000530420004B9 +:10F1B00014400002000000000000000D93620000F7 +:10F1C00024030020304200FF14430014000000001C +:10F1D0008F4201B80440FFFE24020005AF500180B9 +:10F1E000A342018B3C0210000A00139AAF4201B8FF +:10F1F0008FBF00148FB000100A0012F227BD001854 +:10F200000000000D02002021000030218FBF0014FB +:10F210008FB000100A0012DD27BD00180000000D9D +:10F220008FBF00148FB0001003E0000827BD001846 +:10F2300027BDFFE8AFBF00100E000F3C000000002C +:10F24000AF4001808FBF0010000020210A000FE7AF +:10F2500027BD00183084FFFF30A5FFFF00001821F4 +:10F260001080000700000000308200011040000202 +:10F2700000042042006518210A0013AB0005284055 +:10F2800003E000080060102110C0000624C6FFFF44 +:10F290008CA2000024A50004AC8200000A0013B573 +:10F2A0002484000403E000080000000010A000080F +:10F2B00024A3FFFFAC860000000000000000000057 +:10F2C0002402FFFF2463FFFF1462FFFA248400047A +:10F2D00003E0000800000000308300FF30A500FFBD +:10F2E00030C600FF274701808F4201B80440FFFE6F +:10F2F000000000008F42012834634000ACE20000AF +:10F3000024020001ACE00004A4E30008A0E2000A2B +:10F3100024020002A0E2000B3C021000A4E5001051 +:10F32000ACE00024ACE00028A4E6001203E00008F2 +:10F33000AF4201B827BDFFE8AFBF00109362003FA6 +:10F3400024030012304200FF1043000D00803021E2 +:10F350008F620044008210230440000A8FBF001017 +:10F360008F620048240400390000282100C21023C5 +:10F3700004410004240600120E0013C9000000001E +:10F380008FBF00102402000103E0000827BD001811 +:10F3900027BDFFC8AFB20030AFB1002CAFBF003403 +:10F3A000AFB0002890C5000D0080902130A400105F +:10F3B0001080000B00C088218CC300088F620054AD +:10F3C0001062000730A20005144000B524040001BB +:10F3D0000E000D21000020210A0014BB0040202156 +:10F3E00030A200051040000930A30012108000ACCC +:10F3F000240400018E2300088F620054146200A9C7 +:10F400008FBF00340A00142C240400382402001298 +:10F41000146200A3240400010220202127A500106B +:10F420000E000CB2AFA000101040001102402021CD +:10F430008E220008AF620084AF6000400E0013020D +:10F44000000000009362007D024020213442002031 +:10F450000E00130BA362007D0E000CA902402021B8 +:10F46000240400382405008D0A0014B82406001274 +:10F470009362003E304200081040000F8FA200103F +:10F4800030420100104000078FA300148F6200601B +:10F490000062102304430008AF6300600A001441B7 +:10F4A00000000000AF6000609362003E2403FFF79D +:10F4B00000431024A362003E9362003E30420008E5 +:10F4C000144000022406000300003021936200343F +:10F4D000936300378F640084304200FF306300FF85 +:10F4E00000661821000318800043282100A4202B67 +:10F4F0001080000B000000009763003C8F620084C6 +:10F500003063FFFF004510230062182B14600004D5 +:10F51000000000008F6200840A00145D0045802313 +:10F520009762003C3050FFFF8FA300103062000450 +:10F5300010400004000628808FA2001C0A001465F9 +:10F540000202102B2E02021850400003240202185F +:10F550000A00146E020510233063000410600003DB +:10F56000004510238FA2001C00451023004080217D +:10F570002C42008054400001241000800E00130231 +:10F580000240202124020001AF62000C9362003E81 +:10F59000001020403042007FA362003E8E22000413 +:10F5A00024420001AF620040A770003C8F6200500F +:10F5B0009623000E00431021AF6200588F62005066 +:10F5C00000441021AF62005C8E220004AF6200187C +:10F5D0008E220008AF62001C8FA20010304200088B +:10F5E0005440000A93A20020A360003693620036C4 +:10F5F0002403FFDFA36200359362003E0043102422 +:10F60000A362003E0A0014988E220008A36200350F +:10F610008E220008AF62004C8F6200248F6300408E +:10F6200000431021AF6200489362000024030050A1 +:10F63000304200FF144300122403FF803C02080004 +:10F640008C4231A00242102100431024AF42002816 +:10F650003C0208008C4231A08E2400083C03000CC0 +:10F66000024210213042007F03421021004310214A +:10F67000AC4400D88E230008AF820014AC4300DCF9 +:10F680000E00130B02402021240400380000282122 +:10F690002406000A0E0013C9000000002404000123 +:10F6A0008FBF00348FB200308FB1002C8FB0002894 +:10F6B0000080102103E0000827BD003827BDFFF8B7 +:10F6C00027420180AFA20000308A00FF8F4201B8BC +:10F6D0000440FFFE000000008F4601283C020800A5 +:10F6E0008C4231A02403FF80AF86004800C2102165 +:10F6F00000431024AF4200243C0208008C4231A099 +:10F700008FA900008FA8000000C210213042007FA6 +:10F71000034218213C02000A00621821946400D4BC +:10F720008FA700008FA5000024020002AF83001401 +:10F73000A0A2000B8FA30000354260003084FFFFC1 +:10F74000A4E200083C021000AD260000AD04000455 +:10F75000AC60002427BD0008AF4201B803E00008F8 +:10F76000240200018F88003C938200288F830014BC +:10F770003C07080024E7779800481023304200FF38 +:10F78000304900FC246500888F860040304A000321 +:10F790001120000900002021248200048CA3000015 +:10F7A000304400FF0089102AACE3000024A50004C7 +:10F7B0001440FFF924E70004114000090000202153 +:10F7C0002482000190A30000304400FF008A102B27 +:10F7D000A0E3000024A500011440FFF924E7000184 +:10F7E00030C20003144000048F85003C3102000346 +:10F7F0001040000D0000000010A0000900002021B2 +:10F800002482000190C30000304400FF0085102BCB +:10F81000A0E3000024C600011440FFF924E7000122 +:10F8200003E00008000000001100FFFD000020219F +:10F83000248200048CC30000304400FF0088102B99 +:10F84000ACE3000024C600041440FFF924E70004E0 +:10F8500003E00008000000008F83003C9382002832 +:10F8600030C600FF30A500FF00431023304300FFE7 +:10F870008F820014008038210043102114C0000240 +:10F88000244800880083382130E20003144000053A +:10F8900030A2000314400003306200031040000D4A +:10F8A0000000000010A000090000202124820001B7 +:10F8B00090E30000304400FF0085102BA1030000FE +:10F8C00024E700011440FFF92508000103E00008C7 +:10F8D0000000000010A0FFFD000020212482000491 +:10F8E0008CE30000304400FF0085102BAD030000C6 +:10F8F00024E700041440FFF92508000403E0000891 +:10F90000000000000080482130AAFFFF30C600FF41 +:10F9100030E7FFFF274801808F4201B80440FFFE17 +:10F920008F820048AD0200008F420124AD02000426 +:10F930008D220020A5070008A102000A240200165B +:10F94000A102000B934301208D2200088D240004A6 +:10F95000306300FF004310219783003A00441021D8 +:10F960008D250024004310233C0308008C6331A044 +:10F970008F840014A502000C246300E82402FFFF1A +:10F98000A50A000EA5030010A5060012AD0500187B +:10F99000AD020024948201142403FFF73042FFFFDC +:10F9A000AD0200288C820118AD02002C3C02100030 +:10F9B000AD000030AF4201B88D220020004310247A +:10F9C00003E00008AD2200208F82001430E7FFFF23 +:10F9D00000804821904200D330A5FFFF30C600FFD1 +:10F9E0000002110030420F0000E238252748018054 +:10F9F0008F4201B80440FFFE8F820048AD02000034 +:10FA00008F420124AD0200048D220020A5070008CA +:10FA1000A102000A24020017A102000B9343012057 +:10FA20008D2200088D240004306300FF0043102164 +:10FA30009783003A004410218F8400140043102360 +:10FA40003C0308008C6331A0A502000CA505000E44 +:10FA5000246300E8A5030010A5060012AD00001401 +:10FA60008D220024AD0200188C82005CAD02001CC7 +:10FA70008C820058AD0200202402FFFFAD0200245A +:10FA8000948200E63042FFFFAD02002894820060BD +:10FA9000948300BE30427FFF3063FFFF00021200FC +:10FAA00000431021AD02002C3C021000AD000030DC +:10FAB000AF4201B8948200BE2403FFF700A21021D8 +:10FAC000A48200BE8D2200200043102403E0000821 +:10FAD000AD220020274301808F4201B80440FFFE81 +:10FAE0008F8200249442001C3042FFFF000211C0AC +:10FAF000AC62000024020019A062000B3C0210005E +:10FB0000AC60003003E00008AF4201B88F87002CE2 +:10FB100030C300FF8F4201B80440FFFE8F820048CF +:10FB200034636000ACA2000093820044A0A20005F0 +:10FB30008CE20010A4A20006A4A300088C8200207E +:10FB40002403FFF7A0A2000A24020002A0A2000BD7 +:10FB50008CE20000ACA200108CE20004ACA2001405 +:10FB60008CE2001CACA200248CE20020ACA2002895 +:10FB70008CE2002CACA2002C8C820024ACA20018D9 +:10FB80003C021000AF4201B88C82002000431024D8 +:10FB900003E00008AC8200208F86001427BDFFE838 +:10FBA000AFBF0014AFB0001090C20063304200201D +:10FBB0001040000830A500FF8CC2007C2403FFDF4A +:10FBC00024420001ACC2007C90C2006300431024B8 +:10FBD000A0C2006310A000238F830014275001806F +:10FBE000020028210E0015D6240600828F82001400 +:10FBF000904200633042004050400019A38000440E +:10FC00008F83002C8F4201B80440FFFE8F82004892 +:10FC1000AE02000024026082A60200082402000254 +:10FC2000A202000B8C620008AE0200108C62000C75 +:10FC3000AE0200148C620014AE0200188C62001830 +:10FC4000AE0200248C620024AE0200288C620028E0 +:10FC5000AE02002C3C021000AF4201B8A380004469 +:10FC60008F8300148FBF00148FB000109062006368 +:10FC700027BD00183042007FA06200639782003ADF +:10FC80008F86003C8F850014938300280046102344 +:10FC9000A782003AA4A000E490A400638F820040F1 +:10FCA000AF83003C2403FFBF0046102100832024C3 +:10FCB000AF820040A0A400638F820014A04000BD6A +:10FCC0008F82001403E00008A44000BE8F8A001455 +:10FCD00027BDFFE0AFB10014AFB000108F88003C2B +:10FCE000AFBF00189389001C954200E430D100FF9B +:10FCF0000109182B0080802130AC00FF3047FFFF46 +:10FD00000000582114600003310600FF012030215B +:10FD1000010958239783003A0068102B1440003CD7 +:10FD20000000000014680007240200018E02002079 +:10FD30002403FFFB34E7800000431024AE020020C0 +:10FD40002402000134E70880158200053165FFFFB9 +:10FD50000E001554020020210A00169102002021F5 +:10FD60000E001585020020218F8400482743018062 +:10FD70008F4201B80440FFFE24020018AC6400006A +:10FD8000A062000B8F840014948200E6A46200102D +:10FD90003C021000AC600030AF4201B894820060B9 +:10FDA00024420001A4820060948200603C030800A9 +:10FDB0008C63318830427FFF5443000F02002021C2 +:10FDC000948200602403800000431024A482006019 +:10FDD0009082006090830060304200FF000211C2F8 +:10FDE00000021027000211C03063007F0062182556 +:10FDF000A083006002002021022028218FBF00186C +:10FE00008FB100148FB000100A0015F927BD002033 +:10FE1000914200632403FF8000431025A142006348 +:10FE20009782003A3048FFFF110000209383001CA6 +:10FE30008F840014004B1023304600FF948300E4AD +:10FE40002402EFFF0168282B00621824A48300E439 +:10FE500014A000038E020020010058210000302170 +:10FE60002403FFFB34E7800000431024AE0200208F +:10FE700024020001158200053165FFFF0E001554B4 +:10FE8000020020210A0016B99783003A0E0015855A +:10FE9000020020219783003A8F82003CA780003A1D +:10FEA00000431023AF82003C9383001C8F82001418 +:10FEB0008FBF00188FB100148FB0001027BD002035 +:10FEC00003E00008A04300BD938200442403000126 +:10FED00027BDFFE8004330042C420020AFB00010E3 +:10FEE000AFBF00142410FFFE10400005274501801D +:10FEF0003C0208008C4231900A0016D600461024BD +:10FF00003C0208008C423194004610241440000743 +:10FF1000240600848F8300142410FFFF9062006287 +:10FF20003042000F34420040A06200620E0015D63D +:10FF300000000000020010218FBF00148FB00010DD +:10FF400003E0000827BD00188F83002427BDFFE0D1 +:10FF5000AFB20018AFB10014AFB00010AFBF001CBB +:10FF60009062000D00A0902130D100FF3042007F50 +:10FF7000A062000D8F8500148E4300180080802140 +:10FF80008CA2007C146200052402000E90A2006383 +:10FF9000344200200A0016FFA0A200630E0016C51E +:10FFA000A38200442403FFFF104300472404FFFF03 +:10FFB00052200045000020218E4300003C0200102A +:10FFC00000621024504000043C020008020020217E +:10FFD0000A00170E24020015006210245040000988 +:10FFE0008E45000002002021240200140E0016C5D8 +:10FFF000A38200442403FFFF104300332404FFFFC7 +:020000021000EC +:100000008E4500003C02000200A2102410400016A1 +:100010003C0200048F8600248CC200148CC30010A4 +:100020008CC40014004310230044102B50400005E2 +:10003000020020218E43002C8CC2001010620003AD +:10004000020020210A00173F240200123C02000493 +:1000500000A210245040001C00002021020020219A +:100060000A00173F2402001300A2102410400006CB +:100070008F8300248C620010504000130000202168 +:100080000A001739020020218C6200105040000441 +:100090008E42002C020020210A00173F240200118A +:1000A00050400009000020210200202124020017F6 +:1000B0000E0016C5A38200442403FFFF1043000274 +:1000C0002404FFFF000020218FBF001C8FB2001806 +:1000D0008FB100148FB000100080102103E00008E1 +:1000E00027BD00208F83001427BDFFD8AFB40020A8 +:1000F000AFB3001CAFB20018AFB10014AFB0001026 +:10010000AFBF0024906200638F91002C2412FFFF88 +:100110003442004092250000A06200638E2200104D +:100120000080982130B0003F105200060360A021EB +:100130002402000D0E0016C5A38200441052005484 +:100140002404FFFF8F8300148E2200188C63007C30 +:1001500010430007026020212402000E0E0016C585 +:10016000A38200442403FFFF104300492404FFFF3F +:1001700024040020120400048F83001490620063A2 +:1001800034420020A06200638F85003410A000205C +:1001900000000000560400048F8200140260202139 +:1001A0000A0017902402000A9683000A9442006015 +:1001B0003042FFFF144300048F8200202404FFFD1F +:1001C0000A0017B7AF82003C3C0208008C42318C19 +:1001D0000045102B14400006026020210000282159 +:1001E0000E001646240600010A0017B70000202161 +:1001F0002402002D0E0016C5A38200442403FFFF35 +:10020000104300232404FFFF0A0017B70000202139 +:10021000160400058F8400148E2300142402FFFFAF +:100220005062001802602021948200602442000184 +:10023000A4820060948200603C0308008C633188D3 +:1002400030427FFF5443000F0260202194820060FF +:100250002403800000431024A48200609082006088 +:1002600090830060304200FF000211C2000210279C +:10027000000211C03063007F00621825A083006077 +:10028000026020210E0015F9240500010000202144 +:100290008FBF00248FB400208FB3001C8FB20018D2 +:1002A0008FB100148FB000100080102103E000080F +:1002B00027BD00288F83001427BDFFE8AFB00010D2 +:1002C000AFBF0014906200638F87002C00808021F4 +:1002D000344200408CE60010A06200633C0308003A +:1002E0008C6331B030C23FFF0043102B1040004EF2 +:1002F0008F8500302402FF8090A3000D004310245E +:10030000304200FF504000490200202100061382C5 +:10031000304800032402000255020044020020215C +:1003200094A2001C8F85001424030023A4A20114AE +:100330008CE60000000616023042003F1043001019 +:100340003C0300838CE300188CA2007C1062000642 +:100350002402000E0E0016C5A38200442403FFFFF2 +:10036000104300382404FFFF8F8300149062006361 +:1003700034420020A06200630A0017FC8F8300242F +:1003800000C31024144300078F83002490A200624E +:100390003042000F34420020A0A20062A38800383F +:1003A0008F8300249062000D3042007FA062000D18 +:1003B0008F83003410600018020020218F840030E9 +:1003C0008C8200100043102B1040000924020018FA +:1003D000020020210E0016C5A38200442403FFFF63 +:1003E000104300182404FFFF0A00182400002021F5 +:1003F0008C820010240500010200202100431023FC +:100400008F830024240600010E001646AC62001003 +:100410000A001824000020210E0015F9240500010F +:100420000A00182400002021020020212402000DCF +:100430008FBF00148FB0001027BD00180A0016C52A +:10044000A38200448FBF00148FB0001000801021E1 +:1004500003E0000827BD001827BDFFC8AFB2002089 +:10046000AFBF0034AFB60030AFB5002CAFB400283A +:10047000AFB30024AFB1001CAFB000188F46012805 +:100480003C0308008C6331A02402FF80AF86004843 +:1004900000C318213065007F03452821006218241D +:1004A0003C02000AAF43002400A2282190A200626F +:1004B00000809021AF850014304200FF000211023D +:1004C000A382003890A200BC304200021440000217 +:1004D00024030034240300308F820014A3830028F7 +:1004E000938300388C4200C0A3800044AF82003C5C +:1004F000240200041062031C8F84003C8E4400041C +:10050000508003198F84003C8E4200103083FFFF1F +:10051000A784003A106002FFAF8200408F8400146D +:100520002403FF809082006300621024304200FFA9 +:10053000144002CF9785003A9383003824020002CA +:1005400030B6FFFF14620005000088219382002866 +:100550002403FFFD0A001B19AF82003C8F82003C80 +:1005600002C2102B144002A18F8400400E0014EC34 +:1005700000000000938300283C040800248477983E +:10058000240200341462002EAF84002C3C0A0800C0 +:100590008D4A77C82402FFFFAFA2001000803821E7 +:1005A0002405002F3C09080025297398240800FF22 +:1005B0002406FFFF90E2000024A3FFFF00062202B2 +:1005C00000C21026304200FF0002108000491021B6 +:1005D0008C420000306500FF24E7000114A8FFF5FD +:1005E0000082302600061027AFA20014AFA2001030 +:1005F0000000282127A7001027A6001400C51023FB +:100600009044000324A2000100A71821304500FFF8 +:100610002CA200041440FFF9A06400008FA2001077 +:100620001142000724020005024020210E0016C5D9 +:10063000A38200442403FFFF104300642404FFFF4F +:100640003C0208009042779C104000098F82001401 +:10065000024020212402000C0E0016C5A382004493 +:100660002403FFFF104300592404FFFF8F8200146E +:10067000A380001C3C0308008C63779C8C440080A2 +:100680003C0200FF3442FFFF006218240083202B4D +:1006900010800008AF83003402402021240200199A +:1006A0000E0016C5A38200442403FFFF1043004739 +:1006B0002404FFFF8F87003C9782003A8F85003427 +:1006C000AF8700200047202310A0003BA784003AFA +:1006D0008F86001430A200030002102390C300BCD8 +:1006E0003050000300B0282100031882307300014D +:1006F0000013108000A228213C0308008C6331A065 +:100700008F8200483084FFFF0085202B004310219A +:1007100010800011244200888F84002C1082000E6B +:100720003C033F013C0208008C42779800431024B0 +:100730003C0325001443000630E500FF8C820000D6 +:10074000ACC200888C8200100A0018E9ACC2009884 +:100750000E001529000030219382001C8F850014A3 +:100760008F830040020238218F82003CA387001C47 +:1007700094A400E4006218218F82003434841000B5 +:10078000AF83004000503021A4A400E41260000EAA +:10079000AF86003C24E20004A382001C94A200E483 +:1007A00024C30004AF83003C34422000A4A200E430 +:1007B0000A001906000020218F820040AF80003C13 +:1007C00000471021AF820040000020212414FFFFC9 +:1007D000109402112403FFFF3C0808008D0877A83D +:1007E0003C0208008C4231B03C03080090637798CB +:1007F00031043FFF0082102B1040001B3067003F88 +:100800003C0208008C4231A88F83004800042180FC +:1008100000621821006418213062007F0342282101 +:100820003C02000C00A228213C020080344200015E +:100830003066007800C230252402FF800062102458 +:10084000AF42002830640007AF4208048F820014D2 +:100850000344202124840940AF460814AF850024B6 +:10086000AF840030AC4301189383003824020003A6 +:10087000146201CF240200012402002610E201D1FB +:1008800028E2002710400013240200322402002234 +:1008900010E201CC28E200231040000824020024CA +:1008A0002402002010E201B82402002110E20147D6 +:1008B000024020210A001AFB2402000B10E201C1B1 +:1008C0002402002510E20010024020210A001AFB39 +:1008D0002402000B10E201AE28E2003310400006B3 +:1008E0002402003F2402003110E2009A024020213D +:1008F0000A001AFB2402000B10E201A5024020218D +:100900000A001AFB2402000B8F90002C3C03080005 +:100910008C6331B08F8500308E0400100000A82158 +:100920008CB3001430823FFF0043102B8CB10020A9 +:100930005040018F0240202190A3000D2402FF802F +:1009400000431024304200FF504001890240202122 +:10095000000413823042000314400185024020212C +:1009600094A3001C8F8200148E040028A443011459 +:100970008CA20010026218231064000302402021A0 +:100980000A00197C2402001F8F82003400621021AB +:100990000262102B104000088F83002402402021A7 +:1009A000240200180E0016C5A382004410540174DE +:1009B0002404FFFF8F8300248F8400348C62001096 +:1009C0000224882100441023AC6200108F8200149E +:1009D000AC7100208C4200680051102B10400009BF +:1009E0008F830030024020212402001D0E0016C516 +:1009F000A38200442403FFFF104301612404FFFF8E +:100A00008F8300308E0200248C6300241043000783 +:100A1000024020212402001C0E0016C5A3820044BF +:100A20002403FFFF104301562404FFFF8F8400249A +:100A30008C82002424420001AC8200241233000482 +:100A40008F8200148C4200685622000E8E02000035 +:100A50008E0200003C030080004310241440000D6F +:100A60002402001A024020210E0016C5A382004471 +:100A70002403FFFF104301422404FFFF0A0019BAB8 +:100A80008E0200143C0300800043102450400003F9 +:100A90008E020014AC8000208E0200142411FFFF8F +:100AA0001051000E3C0308003C0208008C423190BB +:100AB000004310242403001B14400007A3830044B8 +:100AC0000E0016C5024020211051012D2404FFFF05 +:100AD0000A0019CB8E030000A38000448E0300009F +:100AE0003C02000100621024104000123C02008011 +:100AF0000062102414400008024020212402001A41 +:100B00000E0016C5A38200442403FFFF1043011CFE +:100B10002404FFFF02402021020028210E0016E5D8 +:100B2000240600012403FFFF104301152404FFFFE6 +:100B3000241500018F83002402A0302102402021CF +:100B40009462003624050001244200010A001ADFE5 +:100B5000A46200368F90002C3C0308008C6331B0F7 +:100B60008E13001032623FFF0043102B10400089AB +:100B70008F8400302402FF809083000D00431024F6 +:100B8000304200FF104000842402000D0013138245 +:100B900030420003240300011443007F2402000DAF +:100BA0009082000D30420008544000048F820034CF +:100BB000024020210A001A102402002450400004A0 +:100BC0008E03000C024020210A001A102402002784 +:100BD0008C82002054620006024020218E0300080F +:100BE0008C820024506200098E02001402402021F1 +:100BF000240200200E0016C5A38200441054007188 +:100C00002403FFFF0A001A458F8400242411FFFFEC +:100C1000145100048F860014024020210A001A405B +:100C2000240200258E0300188CC2007C1062000391 +:100C30002402000E0A001A40024020218E030024E4 +:100C40008C82002810620003240200210A001A404E +:100C5000024020218E0500288C82002C10A2000367 +:100C60002402001F0A001A40024020218E03002C9B +:100C700014600003240200230A001A4002402021CD +:100C80008CC200680043102B104000032402002691 +:100C90000A001A40024020218C82001400651821AD +:100CA0000043102B104000088F84002402402021B4 +:100CB000240200220E0016C5A382004410510041F8 +:100CC0002403FFFF8F8400242403FFF79082000D8C +:100CD00000431024A082000D8F8600143C030800FE +:100CE0008C6331AC8F82004894C400E08F8500246F +:100CF0000043102130847FFF000420400044102175 +:100D00003043007F034320213C03000E0083202159 +:100D10002403FF8000431024AF42002CA493000062 +:100D20008CA2002824420001ACA200288CA2002C36 +:100D30008E03002C00431021ACA2002C8E02002C4C +:100D4000ACA200308E020014ACA2003494A2003A8F +:100D500024420001A4A2003A94C600E03C0208002C +:100D60008C4231B024C4000130837FFF1462000F35 +:100D700000803021240280000082302430C2FFFF36 +:100D8000000213C2304200FF000210270A001A7E40 +:100D9000000233C02402000D024020210E0016C5BF +:100DA000A38200440A001A84004018218F82001494 +:100DB00002402021240500010E0015F9A44600E0A0 +:100DC000000018210A001B16006088218F90002C5B +:100DD0003C0308008C6331B08E05001030A23FFF49 +:100DE0000043102B104000612402FF808F840030EC +:100DF0009083000D00431024304200FF5040005CFF +:100E0000024020218F8200341040000B0005138225 +:100E10008F8200149763000A944200603042FFFF03 +:100E200014430005000513828F8200202404FFFD77 +:100E30000A001AF3AF82003C304200031440000E57 +:100E40000000000092020002104000058E03002402 +:100E500050600015920300030A001AAF02402021DF +:100E60008C82002450620010920300030240202173 +:100E70000A001AB72402000F9082000D30420008C9 +:100E80005440000992030003024020212402001074 +:100E90000E0016C5A38200442403FFFF1043003850 +:100EA0002404FFFF92030003240200025462000C9A +:100EB000920200038F820034544000099202000322 +:100EC000024020212402002C0E0016C5A3820044FB +:100ED0002403FFFF1043002A2404FFFF92020003B3 +:100EE0000200282102402021384600102CC60001B3 +:100EF0002C4200010E0016E5004630252410FFFFAD +:100F00001050001F2404FFFF8F8300341060001373 +:100F1000024020213C0208008C42318C0043102BFF +:100F200014400007000000000000282124060001F2 +:100F30000E001646000000000A001AF300002021EF +:100F40002402002D0E0016C5A38200441050000C90 +:100F50002404FFFF0A001AF3000020210E0015F9F7 +:100F6000240500010A001AF300002021024020217C +:100F70002402000D0E0016C5A3820044004020216B +:100F80000A001B16008088211514000E00000000C6 +:100F90000E00174C024020210A001B160040882139 +:100FA0000E0016C5A38200440A001B1600408821CB +:100FB00014620017022018212402002314E2000505 +:100FC0002402000B0E0017C0024020210A001B164D +:100FD0000040882102402021A38200440E0016C553 +:100FE0002411FFFF0A001B170220182130A500FF63 +:100FF0000E001529240600019783003A8F82003CD9 +:10100000A780003A00431023AF82003C0220182141 +:101010001220003E9782003A2402FFFD5462003EF7 +:101020008E4300208E4200048F830014005610234C +:10103000AE420004906200633042007FA062006311 +:101040008E4200208F840014A780003A34420002B0 +:10105000AE420020A48000E4908200632403FFBF1E +:1010600000431024A08200630A001B598E43002015 +:101070009082006300621024304200FF1040002381 +:101080009782003A90820088908300BD2485008872 +:101090003042003F2444FFE02C820020A383001C48 +:1010A00010400019AF85002C2402000100821804B2 +:1010B000306200191440000C3C02800034420002EF +:1010C000006210241440000B306200201040000F1A +:1010D0009782003A90A600010240202124050001D9 +:1010E0000A001B5330C60001024020210A001B5297 +:1010F00024050001024020210000282124060001CF +:101100000E001646000000009782003A1440FD04CD +:101110008F8400148E4300203062000410400012BF +:101120008F84003C2402FFFB00621024AE420020AA +:10113000274301808F4201B80440FFFE8F820048A0 +:10114000AC6200008F420124AC6200042402608380 +:10115000A462000824020002A062000B3C021000FE +:10116000AF4201B88F84003C8F8300148FBF0034DE +:101170008FB600308FB5002C8FB400288FB30024B9 +:101180008FB200208FB1001C8FB000182402000124 +:1011900027BD003803E00008AC6400C030A500FFA4 +:1011A0002403000124A900010069102B1040000C49 +:1011B00000004021240A000100A31023004A380443 +:1011C00024630001308200010069302B10400002CE +:1011D000000420420107402554C0FFF800A310235B +:1011E00003E00008010010213C020800244260A432 +:1011F0003C010800AC22738C3C02080024425308D6 +:101200003C010800AC2273902402000627BDFFE0D9 +:101210003C010800A02273943C021EDCAFB200180F +:10122000AFB10014AFBF001CAFB0001034526F411B +:1012300000008821240500080E001B7A02202021CE +:10124000001180803C07080024E773980002160014 +:1012500002071821AC6200000000282124A200012E +:101260003045FFFF8C6200002CA6000804410002FC +:10127000000220400092202614C0FFF8AC64000059 +:10128000020780218E0400000E001B7A2405002036 +:10129000262300013071FFFF2E2301001460FFE5BB +:1012A000AE0200008FBF001C8FB200188FB1001477 +:1012B0008FB0001003E0000827BD002027BDFFD835 +:1012C000AFB3001CAFB20018AFBF0020AFB1001425 +:1012D000AFB000108F5101408F48014800089402C0 +:1012E000324300FF311300FF8F4201B80440FFFE7C +:1012F00027500180AE1100008F420144AE0200046D +:1013000024020002A6120008A202000B240200140C +:10131000AE1300241062002528620015104000085A +:101320002402001524020010106200302402001272 +:10133000106200098FBF00200A001CB58FB3001C8B +:101340001062007024020022106200378FBF00205C +:101350000A001CB58FB3001C3C0208008C4231A06F +:101360002403FF800222102100431024AF420024F6 +:101370003C0208008C4231A0022210213042007F42 +:10138000034218213C02000A00621821166000BCCA +:10139000AF830014906200623042000F344200308C +:1013A000A06200620A001CB48FBF00203C046000F1 +:1013B0008C832C083C02F0033442FFFF00621824A7 +:1013C000AC832C083C0208008C4231A08C832C0892 +:1013D000244200740002108200021480006218256A +:1013E000AC832C080A001CB48FBF00203C0208000C +:1013F0008C4231A02403FF800222102100431024DC +:10140000AF4200243C0208008C4231A03C03000A99 +:10141000022210213042007F03421021004310219C +:101420000A001CB3AF8200143C0208008C4231A0B9 +:101430002405FF800222102100451024AF42002421 +:101440003C0208008C4231A0022210213042007F71 +:10145000034218213C02000A0062182190620063D6 +:1014600000A21024304200FF10400085AF8300141A +:1014700024620088944300123C0208008C4231A888 +:1014800030633FFF00031980022210210043102126 +:101490003043007F03432021004510243C03000C0F +:1014A00000832021AF4200289082000D00A210246A +:1014B000304200FF10400072AF8400249082000D83 +:1014C000304200101440006F8FBF00200E0015C87E +:1014D000000000008F4201B80440FFFE0000000041 +:1014E000AE1100008F420144AE020004240200024B +:1014F000A6120008A202000BAE1300240A001CB4BE +:101500008FBF00202406FF8002261024AF42002057 +:101510003C0208008C4231A031043FFF00042180CE +:101520000222102100461024AF4200243C03080090 +:101530008C6331A83C0208008C4231A03227007F26 +:101540000223182102221021006418213042007F5A +:101550003064007F034228213C02000A0066182400 +:1015600000A22821034420213C02000C00822021FB +:10157000AF4300283C020008034718210062902175 +:10158000AF850014AF8400240E0015C8010080212F +:101590008F4201B80440FFFE8F8200248F84001424 +:1015A000274501809042000DACB10000A4B00006B8 +:1015B000000216000002160300021027000237C2C4 +:1015C00014C00016248200889442001232033FFFA8 +:1015D00030423FFF14430012240260829083006374 +:1015E0002402FF8000431024304200FF5040000CD2 +:1015F00024026082908200623042000F3442004038 +:10160000A082006224026084A4A200082402000DCB +:10161000A0A200050A001C9E3C0227002402608252 +:10162000A4A20008A0A000053C02270000061C00A0 +:101630000062182524020002A0A2000BACA3001037 +:10164000ACA00014ACA00024ACA00028ACA0002CDE +:101650008E42004C8F840024ACA200189083000DB1 +:101660002402FF8000431024304200FF1040000598 +:101670008FBF00209082000D3042007FA082000DBD +:101680008FBF00208FB3001C8FB200188FB10014E1 +:101690008FB000103C02100027BD002803E00008B6 +:1016A000AF4201B80800343008003430080033A8D5 +:1016B000080033E0080034140800343808003438D7 +:1016C00008003438080033180A0001240000000024 +:1016D000000000000000000D747061362E322E33C1 +:1016E00000000000060203010000000000000000EE +:1016F00000000000000000000000000000000000EA +:1017000000000000000000000000000000000000D9 +:1017100000000000000000000000000000000000C9 +:1017200000000000000000000000000000000000B9 +:1017300000000000000000000000000000000000A9 +:101740000000000000000000000000000000000099 +:101750000000000000000000000000001000000376 +:10176000000000000000000D0000000D3C02080019 +:1017700024421C003C03080024632094AC40000079 +:101780000043202B1480FFFD244200043C1D080070 +:1017900037BD2FFC03A0F0213C1008002610049058 +:1017A0003C1C0800279C1C000E00015C000000008F +:1017B0000000000D3084FFFF308200078F85001885 +:1017C00010400002248300073064FFF800853021B8 +:1017D00030C41FFF03441821247B4000AF85001C48 +:1017E000AF84001803E00008AF4400843084FFFF9A +:1017F000308200078F8500208F860028104000026D +:10180000248300073064FFF8008520210086182B10 +:1018100014600002AF8500240086202303442821A1 +:1018200034068000AF840020AF44008000A6202151 +:1018300003E00008AF84003827BDFFD8AFB3001C19 +:10184000AFB20018AFB00010AFBF0024AFB400209B +:10185000AFB100143C0860088D1450002418FF7FBD +:101860003C1A8000029898243672380CAD12500051 +:101870008F5100083C07601C3C08600036300001B6 +:10188000AF500008AF800018AF400080AF40008428 +:101890008CE600088D0F08083C0760168CEC0000F1 +:1018A00031EEFFF039CA00103C0DFFFF340B800011 +:1018B0003C030080034B48212D440001018D282466 +:1018C0003C0253533C010800AC230420AF8900388C +:1018D000AF860028AF840010275B400014A20003ED +:1018E00034E37C008CF90004032818218C7F007CF1 +:1018F0008C6500783C0280003C0B08008D6B048CEA +:101900003C0A08008D4A048834520070AF85003CC0 +:10191000AF9F00403C13080026731C440240A021E6 +:101920008E4800008F46000038C30001306400017B +:1019300010800017AF880034028048218D2F0000EE +:101940003C0508008CA5045C3C1808008F1804585E +:1019500001E8102300A280210000C8210202402BD0 +:1019600003198821022838213C010800AC30045CAE +:101970003C010800AC2704588F4E000039CD00010F +:1019800031AC00011580FFED01E04021AF8F003444 +:101990008E5100003C0708008CE7045C3C0D0800F9 +:1019A0008DAD04580228802300F0602100007021D2 +:1019B0000190302B01AE1821006620213C01080067 +:1019C000AC2C045C3C010800AC2404588F46010890 +:1019D0008F47010030C92000AF860000AF87000CA0 +:1019E0001120000A00C040213C1808008F18042C68 +:1019F000270800013C010800AC28042C3C184000DA +:101A0000AF5801380A000196000000009749010410 +:101A100000002821014550213122FFFF0162582199 +:101A20000162F82B015F502130D902003C0108000F +:101A3000AC2B048C3C010800AC2A0488172000154C +:101A400024040F0010E400130000000024080D001F +:101A500010E8023B30CD000611A0FFE93C18400021 +:101A6000936E00002409001031C400F01089027147 +:101A700024020070108202E58F880014250F0001F7 +:101A8000AF8F00143C184000AF5801380A0001968F +:101A900000000000974C01041180FFD93C18400061 +:101AA00030C34000146000A1000000008F460178A0 +:101AB00004C0FFFE8F87003824100800240F0008A0 +:101AC0008CE30008AF500178A74F0140A7400142C6 +:101AD000974E01048F86000031C9FFFF30CD000111 +:101AE00011A002E1012040212531FFFE241800024F +:101AF000A75801463228FFFFA75101483C190800AA +:101B00008F39043C172002D08F8C000C30DF00206E +:101B100017E00002240400092404000130C20C0074 +:101B2000240504005045000134840004A744014A00 +:101B30003C1108008E3104203C1800483C10000184 +:101B40000238182530CF00020070282511E000046B +:101B5000000018213C19010000B9282524030001C8 +:101B600030DF000453E00005AF8300083C0600109E +:101B700000A6282524030001AF830008AF4510000C +:101B80000000000000000000000000000000000055 +:101B90008F83000810600023000000008F451000B4 +:101BA00004A1FFFE000000001060001E0000000005 +:101BB0008F4410003C0C0020008C102410400019B1 +:101BC0008F8E000031CD000211A000160000000031 +:101BD000974F101415E000130000000097591008EB +:101BE0003338FFFF271100060011188200033080F0 +:101BF00000C7282132300001322300031200032CD9 +:101C00008CA200000000000D00C7F821AFE2000028 +:101C10003C0508008CA5043024A600013C01080006 +:101C2000AC2604308F6D00003402FFFFAF8D00043E +:101C30008CEC0000118202A6000020218CED000037 +:101C400031AC01001180028A000000003C02080053 +:101C50008C4204743C0308008C63044C3C1F080055 +:101C60008FFF04703C1808008F1804480048382182 +:101C70000068802100E8282B03E430210208402B73 +:101C80000304882100C57021022878213C01080046 +:101C9000AC30044C3C010800AC2F04483C01080067 +:101CA000AC2704743C010800AC2E04708F8400182B +:101CB0000120302131290007249F000833F91FFF3C +:101CC00003594021AF84001CAF990018251B400028 +:101CD000AF590084112000038F83002024C2000725 +:101CE0003046FFF88F84002800C3282100A4302B41 +:101CF00014C00002AF83002400A428230345602100 +:101D0000340D8000018D10213C0F1000AF850020A4 +:101D1000AF820038AF450080AF4F01788F88001444 +:101D2000250F00010A0001EFAF8F00148F62000839 +:101D30008F670000240500300007760231C300F0F1 +:101D4000106500A7240F0040546FFF4C8F880014CB +:101D50008F4B01780560FFFE0000000030CA0200D2 +:101D600015400003000612820000000D00061282DA +:101D7000304D0003000D4900012D18210003808023 +:101D8000020D402100086080019380218E1F000019 +:101D900017E00002000000000000000D8F6E00043C +:101DA00005C202BD92070006920E000592020004D1 +:101DB0003C090001000E18800070F8218FED00181A +:101DC000277100082448000501A96021000830821D +:101DD000AFEC0018022020210E00059E26050014FD +:101DE000920A00068F7900043C0B7FFF000A2080D6 +:101DF000009178218DF800043566FFFF0326282422 +:101E000003053821ADE70004920E0005920D000491 +:101E1000960C0008000E10800051C8218F2300008E +:101E2000974901043C07FFFF006758243128FFFF52 +:101E3000010DF82103EC50233144FFFF01643025EC +:101E4000AF260000920300072418000110780275E5 +:101E5000240F0003106F0285000000008E050010A3 +:101E60002419000AA7590140A7450142921800040D +:101E70008F860000240F0001A7580144A7400146A7 +:101E80009747010430D100023C050041A7470148B3 +:101E900000001821A74F014A1220000330CB000494 +:101EA0003C0501412403000151600005AF83000897 +:101EB0003C06001000A6282524030001AF8300087B +:101EC000AF4510000000000000000000000000000E +:101ED000000000008F8A000811400004000000008C +:101EE0008F4410000481FFFE000000008F6B000093 +:101EF000920800043C1108008E310444AF8B0004AA +:101F000097590104311800FF3C0E08008DCE0440A3 +:101F10003325FFFF0305382102276021000010212F +:101F2000250F000A31E8FFFF0187482B01C2682115 +:101F300001A9F821311000073C010800AC2C044431 +:101F40003C010800AC3F0440120000038F8C0018D5 +:101F50002506000730C8FFF8010C682131BF1FFFBC +:101F6000AF8C001CAF9F0018AF5F00849744010442 +:101F7000035F80213084FFFF308A00071140000397 +:101F8000261B4000248900073124FFF88F8200209F +:101F90008F850028008220210085702B15C000024B +:101FA000AF820024008520233C0B08008D6B048C3D +:101FB0003C0A08008D4A04880344882134038000C9 +:101FC000022310213C0F1000AF840020AF820038A4 +:101FD000AF440080AF4F01780A0002968F8800144A +:101FE0008F5001780600FFFE30D10200162000035A +:101FF000000612820000000D00061282305F00030E +:10200000001F1900007F302100062080009FC8219A +:1020100000194880013380218E180000130000024F +:10202000000000000000000D8F6C000C058001FB1B +:102030008F870038240E0001AE0E00008CE30008EC +:10204000A20000078F65000400055402314D00FF17 +:1020500025A80005000830822CCB00411560000245 +:10206000A20A00040000000D8F7800043C03FFFF6B +:1020700000E02821330BFFFF256C000B000C1082C1 +:1020800000022080008748218D3F000026040014B4 +:10209000A618000803E3C8240E00059EAD39000011 +:1020A0008F4F01083C11100001F1382410E001AB02 +:1020B00000000000974D01049208000725AAFFECDC +:1020C000350600023144FFFFA2060007960600080D +:1020D0002CC7001354E0000592030007921100077B +:1020E000362F0001A20F00079203000724180001F9 +:1020F000107801C224090003106901D58F880038C7 +:1021000030CBFFFF257100020011788331E400FF1E +:1021100000042880A20F000500A848218D2D000092 +:10212000974A01043C0EFFFF01AEF8243143FFFF44 +:10213000006B1023244CFFFE03ECC825AD390000D2 +:10214000920600053C03FFF63462FFFF30D800FF23 +:102150000018388000F08821922F00143C04FF7F83 +:102160003487FFFF31EE000F01C65821316500FFB3 +:1021700000055080015068218DAC00200148F821F5 +:10218000A20B00060182C824AE0C000CAFF9000CB3 +:10219000920900068E11000C032778240009C080E4 +:1021A0000310702195C60026030828210227202449 +:1021B000AE04000CADCF0020ADC60024ACA60010CC +:1021C0008F8800003C0B08008D6B048C3C0A0800D3 +:1021D0008D4A0488241F001024190002A75F0140C3 +:1021E000A7400142A7400144A7590146974901046D +:1021F00024070001310600022538FFFEA7580148D8 +:102200003C050009A747014A10C00003000018213F +:102210003C05010924030001310C00045180000534 +:10222000AF8300083C08001000A828252403000103 +:10223000AF830008AF451000000000000000000060 +:1022400000000000000000009205000424AE00021F +:1022500031CD0007000D182330620007AE020010D8 +:102260008F90000812000004000000008F4F100043 +:1022700005E1FFFE000000008F7100008F8E001846 +:102280003C0308008C630444AF91000497450104AB +:1022900025CF001031E61FFF30A2FFFFAF8E001CDC +:1022A000AF860018AF4600842449FFFE3C0C0800AE +:1022B0008D8C0440974D010401208021000947C303 +:1022C0000070C02131A9FFFF0310F82B0188C8213D +:1022D000033F202103463821313100073C0108002B +:1022E000AC3804443C010800AC2404401220000334 +:1022F00024FB40002527000730E9FFF88F860020E7 +:102300008F8400280126382100E4C02B170000022A +:10231000AF86002400E438230347202134198000CD +:10232000009910213C0F1000AF870020AF820038C9 +:10233000AF470080AF4F01780A0002968F880014E3 +:102340009747010410E0FDAE3C1840008F5801781B +:102350000700FFFE30C5400010A000033C1F00082E +:102360000000000D3C1F0008AF5F01402410080072 +:102370008F860000AF5001789744010430D90001E6 +:10238000132000ED3086FFFF24CCFFFE240D000259 +:10239000A74D0146A74C01488F9100182408000D55 +:1023A000A748014A8F630000262F000831E21FFF73 +:1023B0000342702130C90007AF830004AF91001CB5 +:1023C000AF82001800C03821AF4200841120000302 +:1023D00025DB400024D800073307FFF88F85002055 +:1023E0008F84002800E5302100C4382B14E000025F +:1023F000AF85002400C430238F8400140346F821E5 +:10240000340C8000AF86002003EC8021AF460080B2 +:10241000249900013C0610003C184000AF460178AA +:10242000AF900038AF990014AF5801380A000196F8 +:10243000000000008F630000975101043067FFFF28 +:102440003228FFFF8F4F017805E0FFFE30EC0007D8 +:10245000000CF82333F0000724F9FFFE2404000ADF +:10246000A7440140A7500142A7590144A740014693 +:10247000A74801488F45010830B800201700000226 +:10248000240300092403000130CD0002A743014AC0 +:102490003C04004111A00003000018213C0401414C +:1024A0002403000130C9000451200005AF83000857 +:1024B0003C0600100086202524030001AF8300089D +:1024C000AF44100000000000000000000000000009 +:1024D000000000008F8E000811C000040000000002 +:1024E0008F4210000441FFFE000000008F7F0000BB +:1024F000276400088F91003CAF9F0004948500087A +:102500009490000A9499000C30AFFFFF0010C400B3 +:102510003323FFFF11F100A6030320253C0E080022 +:102520008DCE04443C0C08008D8C044000E88821CA +:102530002626FFFE01C628210000682100A6F82BF0 +:10254000018D2021009F80213C010800AC2504441E +:102550003C010800AC30044024E200083042FFFF98 +:102560003047000710E000038F830018244F000756 +:1025700031E2FFF83106FFFF30C800070043802139 +:1025800032191FFF0359C021AF83001CAF990018F7 +:10259000271B4000AF590084110000038F8C0020DE +:1025A00024C5000730A6FFF88F84002800CC28211E +:1025B00000A4F82B17E00002AF8C002400A428230D +:1025C000AF850020AF4500803C0408008C840434B3 +:1025D00003454821340E8000012E6821108000053B +:1025E000AF8D0038939100172406000E12260011BB +:1025F0002407043F3C021000AF4201788F8800148A +:10260000250F00010A0001EFAF8F00140E0005C472 +:1026100000E020218F8800143C0B08008D6B048C97 +:102620003C0A08008D4A0488250F00010A0001EFCA +:10263000AF8F00143C021000A7470148AF42017859 +:102640000A0004CE8F88001424040F001184003D7A +:1026500030CE002015C0000224030009240300012D +:102660000A00021AA743014A0A00020DA7400146C8 +:1026700094EF000894F1000A94F0000C8F8C003C59 +:10268000001174003207FFFF31EDFFFF11AC00377E +:1026900001C720253C1808008F1804443C0F08008F +:1026A0008DEF0440000080210308682101A8382B29 +:1026B00001F0702101C760213C010800AC2D0444E9 +:1026C0003C010800AC2C04400A00027A8F840018F8 +:1026D0003C0208008C42047C3C0308008C630454D8 +:1026E0003C1F08008FFF04783C1808008F18045026 +:1026F000004838210068802100E8282B03E43021BD +:102700000208402B0304882100C57021022878218B +:102710003C010800AC3004543C010800AC2F0450CC +:102720003C010800AC27047C3C010800AC2E047876 +:102730000A00027A8F840018A74001460A00043577 +:102740008F91001830CD002015A0FFC52403000D87 +:10275000240300050A00021AA743014A974E010408 +:1027600025C5FFF00A00038130A4FFFF8F980040C9 +:102770001498FFC8000010213C0508008CA5046CCB +:102780003C1F08008FFF046800A8C8210328302BD5 +:1027900003E22021008640213C010800AC39046C92 +:1027A0003C010800AC2804680A00027A8F840018F3 +:1027B0008F8C0040148CFF5900E8C8213C18080099 +:1027C0008F18046C3C1108008E3104682723FFFE2B +:1027D00003034821000010210123302B0222702125 +:1027E00001C668213C010800AC29046C3C010800CA +:1027F000AC2D04680A0004A524E200088F88003884 +:102800003C03FFFF8D02000C0043F82403E4C825BD +:10281000AD19000C0A00038F30CBFFFF0A0003C381 +:10282000AE000000974A0104920400048E26000CBA +:10283000014458212579FFF200C7C0243325FFFF4A +:1028400003053825AE27000C0A0002E68E050010AD +:102850003C0DFFFF8D0A0010014D582401646025D6 +:10286000AD0C00100A00038F30CBFFFF974301042B +:10287000920E00048E290010006E1021244DFFEEF0 +:102880000127602431A8FFFF0188F825AE3F001022 +:102890000A0002E68E0500108E0F000CAE0000004C +:1028A00000078880023028210A0002B8ACAF00205F +:1028B0001460000D3058FFFF3C04FFFF0044682403 +:1028C00001A47026000E602B000D102B004CF82484 +:1028D00013E00002000000000000000D8CAF0000BB +:1028E0000A00025001E410253B03FFFF0003882B80 +:1028F0000018802B0211202410800002000000002C +:102900000000000D8CB900000A0002503722FFFFC2 +:102910003084FFFF30A5FFFF108000070000182162 +:10292000308200011040000200042042006518219E +:102930001480FFFB0005284003E000080060102120 +:1029400010C00007000000008CA2000024C6FFFF9A +:1029500024A50004AC82000014C0FFFB2484000402 +:1029600003E000080000000010A0000824A3FFFFFF +:10297000AC86000000000000000000002402FFFF01 +:102980002463FFFF1462FFFA2484000403E00008BC +:1029900000000000308EFFFF30D8FFFF00057C00F4 +:1029A00001F8602539CDFFFF01AC5021014C582BB7 +:1029B000014B4821000944023127FFFF00E8302184 +:1029C0000006240230C5FFFF00A418213862FFFF73 +:1029D00003E000083042FFFF3C0C08008D8C0484AB +:1029E000240BFF8027BDFFD001845021014B4824D8 +:1029F000AF4900203C0808008D080484AFB20020D5 +:102A0000AFB00018AFBF0028AFB30024AFB1001CB7 +:102A1000936600040104382130E4007F009A1021FD +:102A20003C0300080043902130C500200360802152 +:102A30003C080111277B000814A000022646007004 +:102A40002646006C9213000497510104920F000473 +:102A50003267000F322EFFFF31ED004001C72823FF +:102A600011A0000500004821925900BC3338000431 +:102A70001700009000000000924300BC307F00046B +:102A800013E0000F0000000010A0000D0000000087 +:102A9000960E0002240AFF8000A7602125CDFFFECC +:102AA000A74D1016920B0004014B2024308200FF2A +:102AB00010400085010C40253C0F0400010F40250B +:102AC0008F5301780660FFFE2404000AA7440140EA +:102AD000960D00022404000931AC0007000C5823B5 +:102AE000316A0007A74A0142960200022443FFFE12 +:102AF000A7430144A7400146975F0104A75F01482F +:102B00008F590108333800205300000124040001CC +:102B1000920F000431EE001015C000023483001043 +:102B200000801821A743014A0000000000000000B7 +:102B30000000000000000000AF481000000000008E +:102B40000000000000000000000000008F51100095 +:102B50000621FFFE3113FFFF12600003000000009A +:102B60008F481018ACC8000096030006307FFFFFA6 +:102B700027F900020019988200138880023B302157 +:102B80008CD800001520005700183402920300046E +:102B90002405FF8000A3F82433F100FF1220002C4D +:102BA00000000000924700BC30F2000212400028F2 +:102BB00000000000974B100C2562FFFEA742101684 +:102BC000000000003C0A040035490030AF49100005 +:102BD00000000000000000000000000000000000F5 +:102BE0008F4C10000581FFFE000000009749100C7B +:102BF0008F51101C00C020213127FFFF24F200302C +:102C0000001218820003288000BBF8213226FFFF43 +:102C1000AFF100000E0005B300112C020013C880B4 +:102C2000033B98218E78000000027400AFB80010BA +:102C30008FA80010310FFFFFAFAF00108FA400105E +:102C400001C46825AFAD00108FA60010AE6600006D +:102C500097730008976D000A9766000C8F8A003CF6 +:102C6000000D5C0030CCFFFF3262FFFF104A0036DF +:102C7000016C2025960600023C10100024D30008A9 +:102C80000E00013B3264FFFF974C01040E00014926 +:102C90003184FFFFAF5001788FBF00288FB300242D +:102CA0008FB200208FB1001C8FB0001803E0000825 +:102CB00027BD003010A0FF700000000024A5FFFC1D +:102CC0000A0005EC240900048CD10000AF51101853 +:102CD0008F5301780660FF7A2404000A0A00060177 +:102CE0000000000000A7C8218F8800388F4E101CFC +:102CF0000019C0820018788001E82021AC8E000005 +:102D0000000E2C0200C020210E0005B331C6FFFFCB +:102D1000023B28218CAD000000025400004030210D +:102D2000AFAD00108FAC0010318BFFFFAFAB0010C8 +:102D30008FA2001001424825AFA900108FA70010F4 +:102D40000A000631ACA700008F8F0040148FFFC926 +:102D50000000000097420104960B00023C050800A9 +:102D60008CA5046C3049FFFF316AFFFF3C1108005D +:102D70008E310468012A382124F2FFFE00B240217E +:102D80000012FFC30112C82B023FC02103192021EA +:102D90003C010800AC28046C3C010800AC24046829 +:102DA0000A00066B0000000000A4102B1040000970 +:102DB000240300010005284000A4102B04A00003F8 +:102DC000000318405440FFFC000528401060000735 +:102DD000000000000085302B14C0000200031842E0 +:102DE000008520231460FFFB0005284203E0000853 +:102DF000008010218F85002C27BDFFE800053027BB +:102E00002CC300012CA400020083102510400003F5 +:102E1000AFBF00102405007FAF85002C00052827D8 +:102E200030A5FFFF0E000592240426F58F830030A5 +:102E3000240402BD004030210083382B10E000093B +:102E400024050001000420400083102B04800003AF +:102E5000000528405440FFFC0004204010A000085A +:102E600000C350210064402B1500000200052842D9 +:102E70000064182314A0FFFB0004204200C350216B +:102E80008FBF0010000A4C02312200FF27BD00183E +:102E9000AF8A002C03E00008AF8900300A00002A46 +:102EA00000000000000000000000000D7478703683 +:102EB0002E322E3300000000060203000000000046 +:102EC000000001360000EA60000000000000000081 +:102ED00000000000000000000000000000000000F2 +:102EE00000000000000000000000000000000000E2 +:102EF00000000000000000000000000000000016BC +:102F000000000000000000000000000000000000C1 +:102F100000000000000000000000000000000000B1 +:102F200000000000000000000000000000000000A1 +:102F3000000000000000138800000000000005DC15 +:102F4000000000000000000010000003000000006E +:102F50000000000D0000000D3C02080024423C204F +:102F60003C03080024633DD4AC4000000043202B08 +:102F70001480FFFD244200043C1D080037BD7FFC87 +:102F800003A0F0213C100800261000A83C1C0800FB +:102F9000279C3C200E0002BA000000000000000D3B +:102FA0008F8300383C088000350700708CE50000F6 +:102FB000008330253C02900000C22025AF85003000 +:102FC000AF4400208F4900200520FFFE3C03800015 +:102FD000346200708C4500008F8600303C19080078 +:102FE0008F39007C3C0E08008DCE007800A620238F +:102FF00003245821000078210164682B01CF60214F +:10300000018D50213C010800AC2B007C3C010800E4 +:10301000AC2A007803E00008000000000A0000412C +:10302000240400018F8400383C05800034A2000194 +:103030000082182503E00008AF43002003E00008E9 +:10304000000010213084FFFF30A5FFFF1080000733 +:1030500000001821308200011040000200042042CC +:10306000006518211480FFFB0005284003E00008DC +:103070000060102110C00007000000008CA20000BA +:1030800024C6FFFF24A50004AC82000014C0FFFB8F +:103090002484000403E000080000000010A00008E1 +:1030A00024A3FFFFAC860000000000000000000029 +:1030B0002402FFFF2463FFFF1462FFFA248400044C +:1030C00003E0000800000000308AFFFF93A800130F +:1030D000A74A014497490E1630C600FF3C02100073 +:1030E000A7490146AF450148A3460152A748015AE6 +:1030F000AF4701608FA400188FA30014A7440158A4 +:10310000AF43015403E00008AF42017803E0000838 +:10311000000000003C038000346200708C49000015 +:103120008F8800002484000727BDFFF83084FFF853 +:10313000AF890030974D008A31ACFFFFAFAC000083 +:103140008FAB0000016850232547FFFF30E61FFFCB +:1031500000C4282B14A0FFF73C0C8000358B0070B6 +:103160008D6A00003C0708008CE700843C060800DC +:103170008CC6008000081082014918230002788064 +:1031800000E370210000202101C3C82B00C4C0212E +:1031900001FA4021031948212502400027BD0008FB +:1031A0003C010800AC2E00843C010800AC290080E2 +:1031B00003E00008000000008F8200002486000762 +:1031C00030C5FFF800A2182130641FFF03E000089B +:1031D000AF8400008F8700388F8A004027BDFFB87A +:1031E0008F860044AFB60040AFBF0044AFB5003C8F +:1031F000AFB40038AFB30034AFB20030AFB1002C81 +:10320000AFB000288F4501048D4900ACAF47008066 +:103210008CC8002000A938230000B021AF480E1050 +:103220008F440E1000004821AF440E148CC20024BD +:10323000AF420E188F430E18AF430E1C10E001254D +:103240002D230001936B0008116000D400000000E2 +:10325000976E001031CDFFFF00ED602B158000CF81 +:103260000000000097700010320FFFFFAF4F0E00FC +:103270008F520000325100081220FFFD00000000B4 +:1032800097540E088F460E043285FFFF30B30001BD +:1032900012600132000000000000000D30B8A040B4 +:1032A00024150040131500C030A9A0001120012DE5 +:1032B00000000000937F000813E0000800000000F9 +:1032C00097630010306BFFFF00CB402B1100000311 +:1032D00030AC00401180012300000000A785003CB5 +:1032E000AF8600349366000800E02821AFA70020D5 +:1032F00014C0012427B30020AF60000C9782003C6B +:103300003047400014E00002240300162403000E9E +:1033100024194007A363000AAF790014938A003E82 +:103320008F740014315800070018AA4002959025A8 +:10333000AF7200149784003C8F700014309100101D +:1033400002117825AF6F0014978E003C31CD000834 +:1033500011A00147000028218F6700143C021000D3 +:103360003C0C810000E22825AF65001497460E0A48 +:103370002408000E3405FFFC30C3FFFF006C582505 +:10338000AF6B0004A3680002937F000A27E90004E2 +:10339000A369000A9786003C9363000A30CC1F00A3 +:1033A000000C598301634021251F0028A37F0009D9 +:1033B00097490E0CA769001093790009272A00028B +:1033C000315800070018A82332B10007A371000B81 +:1033D00093740009976400108F910034978F003C1C +:1033E000329200FF024480210205702131ED00403D +:1033F00011A0000531C4FFFF0091282B3C12800072 +:1034000010A000140000A0210224382B14E0011B9E +:103410008FA500208F4D0E14AF4D0E108F420E1C45 +:10342000AF420E18AF440E008F4F000031EE00087F +:1034300011C0FFFD0000000097540E080080882195 +:1034400000009021A794003C8F500E04241400012A +:10345000AF900034976400103095FFFF8E68000035 +:103460000111F82317E00009AE7F00008F650014FA +:103470008F8B004434A60040AF6600148F4C0E10B2 +:10348000AD6C00208F430E18AD63002493670008D5 +:1034900014E000D2000000000E00009E2404001082 +:1034A0008F8900483C08320000402821312600FF67 +:1034B0000006FC0003E8502525390001AF990048BB +:1034C000AC4A0000937800099370000A330400FFAF +:1034D00000047400320F00FF01CF6825AC4D0004DA +:1034E0008F820048064000EAACA20008ACA0000CA5 +:1034F0009783003C306B0008156000022628000608 +:1035000026280002974E0E148F450E1C8F6700046C +:10351000936D000231C4FFFF31A200FFAFA2001083 +:103520008F6C0014AFA800180E00008BAFAC001415 +:10353000240400100E0000C7000000008E7200007E +:1035400016400005000000008F6400142405FFBF32 +:1035500000859824AF7300148F79000C033538214F +:10356000AF67000C9375000816A00008000000006B +:1035700012800006000000008F7F00143C0BEFFF5C +:103580003568FFFE03E84824AF690014A3740008FF +:103590008FA500200A00024602202021AF470E001E +:1035A0000A0000F5000000008F5901780720FFFE97 +:1035B000241F08008F840000AF5F0178974B008ABA +:1035C000316AFFFF014448232528FFFF31021FFF16 +:1035D0002C4300081460FFF9000000008F8E0048A3 +:1035E0008F8D003800C048210344202125C60001EA +:1035F000240C0F00AF86004800E9382324864000E1 +:1036000031CA00FF11AC0005240800019391003E6F +:103610003230000700107A4035E80001000AAC00A3 +:103620003C18010002B8A025AC9440008F930048DC +:1036300030B2003630A40008ACD3000410800097EC +:1036400001123025974E0E0A8F8D00003C0281003A +:1036500031CCFFFF25AB0008018240253C03100060 +:1036600031651FFF25390006241F000EAF48016099 +:1036700000C33025A75F015AAF850000A759015844 +:1036800014E0000A8F93003824120F0052720002D7 +:103690002416000134C600408F580E108F94004449 +:1036A000AE9800208F550E18AE9500248F450E144D +:1036B000AF4501448F590E1CAF590148A34A01522E +:1036C0003C0A1000AF460154AF4A017814E0FEDD19 +:1036D0002D2300010076A025128000178FBF004423 +:1036E0008F84003824160F0010960084000000001C +:1036F0008F45017804A0FFFE24150F001095006E81 +:10370000000000008F470E14240202403C1F1000EE +:10371000AF4701448F440E1CAF440148A3400152FF +:10372000A740015AAF400160A7400158AF42015481 +:10373000AF5F01788FBF00448FB600408FB5003C6B +:103740008FB400388FB300348FB200308FB1002CAB +:103750008FB0002803E0000827BD004814C0FED049 +:1037600030B8A0408F420E148F84004400004821DE +:10377000AC8200208F510E1CAC9100240A00020E76 +:103780002D2300018F910034978A003C3C12800069 +:103790000220A821315800401700FF300000A0216E +:1037A000976900108F9200343139FFFF13320035D2 +:1037B00000002021008048211480FEA000A03821B4 +:1037C0008F420E148F840044AC8200208F510E1C57 +:1037D000AC9100240A00020E2D230001936A000917 +:1037E0009378000B315000FF330F00FF020F702160 +:1037F00025C2000A3050FFFF0E00009E020020216B +:103800008F8600483C1F410024CD0001AF8D004849 +:10381000936C000930C600FF00064400318300FFAE +:10382000246B0002010B4825013FC825AC5900005C +:103830008F67000C97440E1400F22825AC45000455 +:103840008F450E1C8F670004936A00023084FFFFCF +:10385000315800FFAFB800108F6F0014AFB10018DF +:103860000E00008BAFAF00140A0001A60200202159 +:10387000AF6000040A00013EA36000020A00024695 +:1038800000002021000090210A0001702414000192 +:103890003C1280000A000195ACB2000C8F91000030 +:1038A00025240002A744015826300008320F1FFFCC +:1038B0000A0001F9AF8F0000AF40014C1120002C2D +:1038C000000000008F590E10AF5901448F430E18AD +:1038D000240200403C1F1000AF430148A3400152A6 +:1038E000A740015AAF400160A7400158AF420154C0 +:1038F000AF5F01780A0002278FBF00441120000645 +:103900000000000097460E0830CC004015800002F1 +:10391000000000000000000D8F4D017805A0FFFEA3 +:103920000000000097530E103C120500240E2000EA +:10393000326AFFFF0152C025AF58014C8F4F0E1461 +:103940003C021000AF4F01448F500E1CAF50014895 +:10395000A34001528F840038A740015AAF40016054 +:10396000A7400158AF4E01540A000215AF4201783A +:103970008F490E14AF4901448F430E1C0A00028E7A +:10398000240200403C0E20FF27BDFFE03C1A8000CF +:103990003C0F800835CDFFFDAFBF001CAFB2001853 +:1039A000AFB10014AFB00010AF8F0040AF4D0E00AC +:1039B0000000000000000000000000000000000007 +:1039C000000000003C0C00FF358BFFFDAF4B0E00EC +:1039D0003C0660048CC95000240AFF7F3C11600043 +:1039E000012A40243507380CACC750008E24043817 +:1039F00024050009AF4500083083FFFF38622F71AE +:103A00002450C0B3AF8000480E000068AF800000B3 +:103A100052000001AE20442C0E0004353C11800001 +:103A20000E000ED9363000708F8A00403C1208001C +:103A300026523C88020088218E0800008F5F00001B +:103A40003BF900013338000113000017AF88003044 +:103A5000022048218D2700003C0F08008DEF006CEC +:103A60003C0C08008D8C006800E8C02301F8282178 +:103A70000000682100B8302B018D582101664021DB +:103A80003C010800AC25006C3C010800AC28006833 +:103A90008F44000038830001306200011440FFEDC4 +:103AA00000E04021AF8700308E0C00003C0508008C +:103AB0008CA5006C3C0408008C84006801883023CD +:103AC00000A638210000102100E6402B00821821BA +:103AD0000068F8213C010800AC27006C3C0108009C +:103AE000AC3F00688F49010025590088AF99004418 +:103AF000AF890038AF4900208E070000AF87003043 +:103B00008F4D017805A0FFFE000000008E0600002A +:103B10003C0B08008D6B00743C0408008C84007022 +:103B200000C728230165F8210000102103E5402B80 +:103B30000082382100E8C821240908003C0108005F +:103B4000AC3F00743C010800AC390070AF4901780B +:103B500093580108A398003E938F003E31EE000178 +:103B600015C000158F830038240E0D00106E00194B +:103B7000240F0F00106F001D00000000915900007D +:103B800024180050332900FF113800043C1F400066 +:103B9000AF5F01380A0002E7000000000E00090EC6 +:103BA000000000008F8A00403C1F4000AF5F0138DA +:103BB0000A0002E700000000938D003E31AC0006D1 +:103BC000000C51000E0000CE0152D8210A00034320 +:103BD0008F8A00403C1B0800277B3D080E0000CE6A +:103BE000000000000A0003438F8A00403C1B0800CD +:103BF000277B3D280E0000CE000000000A00034392 +:103C00008F8A004090AA00018FAB00108CAC00108E +:103C10003C0300FF8D680004AD6C00208CAD0014E7 +:103C200000E060213462FFFFAD6D00248CA7001816 +:103C30003C09FF000109C024AD6700288CAE001CC0 +:103C40000182C82403197825AD6F0004AD6E002CE5 +:103C50008CAD0008314A00FFAD6D001C94A9000234 +:103C60003128FFFFAD68001090A70000A56000029A +:103C7000A1600004A167000090A30002306200FF71 +:103C80000002198210600005240500011065000E75 +:103C90000000000003E00008A16A00018CD80028A1 +:103CA000354A0080AD7800188CCF0014AD6F001439 +:103CB0008CCE0030AD6E00088CC4002CA16A0001CF +:103CC00003E00008AD64000C8CCD001CAD6D001845 +:103CD0008CC90014AD6900148CC80024AD680008BC +:103CE0008CC70020AD67000C8CC200148C8300646C +:103CF0000043C82B13200007000000008CC20014F2 +:103D0000144CFFE400000000354A008003E0000886 +:103D1000A16A00018C8200640A000399000000007F +:103D200090AA000027BDFFF88FA9001CA3AA0000DD +:103D30008FAE00003C0FFF808FA8001835E2FFFF18 +:103D40008CCD002C01C26024AFAC0000A120000487 +:103D500000E06021A7A000028FB800008D270004BA +:103D60000188182100A0582100C05021006D28268C +:103D70003C06FF7F3C0F00FF2CAD000135EEFFFF3E +:103D800034D9FFFF3C02FF0003193024000D1DC091 +:103D9000010EC82400E2C02400C370250319782551 +:103DA000AD2E0000AD2F00048D450024AFAE000005 +:103DB000AD2500088D4D00202405FFFFAD2D000C22 +:103DC000956800023107FFFFAD27001091660018CB +:103DD00030C200FF000219C2506000018D4500345E +:103DE000AD2500148D67000827BD0008AD27001C15 +:103DF0008C8B00CCAD2C0028AD20002CAD2B0024EA +:103E0000AD20001803E00008AD20002027BDFFE032 +:103E1000AFB20018AFB10014AFB00010AFBF001CBC +:103E20009098000000C088213C0D00FF330F007FF8 +:103E3000A0CF0000908E000135ACFFFF3C0AFF00D0 +:103E4000A0CE000194A6001EA22000048CAB00149A +:103E50008E29000400A08021016C2824012A40241E +:103E60000080902101052025A6260002AE24000432 +:103E700026050020262400080E00007624060002F5 +:103E800092470000260500282624001400071E0083 +:103E90000003160324060004044000032403FFFF6C +:103EA000965900023323FFFF0E000076AE23001068 +:103EB000262400248FBF001C8FB200188FB100147D +:103EC0008FB0001024050003000030210A0000809C +:103ED00027BD002027BDFFD8AFB1001CAFB0001830 +:103EE000AFBF002090A80000240200018FB0003C6A +:103EF0003103003F00808821106200148FAA00382F +:103F0000240B0005506B0016AFAA001000A0202162 +:103F100000C028210E0003DC02003021922400BCE6 +:103F2000308300021060000326060030ACC00000A1 +:103F300024C600048FBF00208FB1001C8FB0001872 +:103F400000C0102103E0000827BD002801403821EF +:103F50000E00035AAFB000100A0004200000000059 +:103F60000E0003A1AFB000140A00042000000000FE +:103F70003C02000A034218213C04080024843D6CE2 +:103F80002405001A000030210A000080AF8300548D +:103F90003C038000346200708C48000000A058216F +:103FA00000C04821308A00FFAF8800308F4401787C +:103FB0000480FFFE3C0C8000358600708CC500003C +:103FC0003C0308008C6300743C1808008F180070D4 +:103FD00000A82023006468210000C82101A4782BD8 +:103FE0000319702101CF60213C010800AC2D007441 +:103FF0003C010800AC2C00708F480E14AF480144FF +:10400000AF47014CA34A0152A74B01589346010800 +:1040100030C5000854A0000135291000934B090059 +:1040200024070050316A00FF11470007000000001C +:104030008F450E1CAF450148AF4901543C091000A3 +:1040400003E00008AF490178934D010831A800084A +:104050001100001000000000934F010831EE001025 +:1040600051C00001352900083C04080090843DD06F +:10407000A34401508F4309A4AF4301488F4209A0D4 +:10408000AF420144AF4901543C09100003E000086D +:10409000AF4901783C1908008F393D8C333800084E +:1040A0005700FFF1352900080A00047300000000E2 +:1040B00024070040AF470814AF4008108F4209445E +:1040C0008F4309508F4409548F45095C8F46094C32 +:1040D000AF820064AF830050AF84004CAF85005CBA +:1040E00003E00008AF8600609346010930C5007FF9 +:1040F000000518C0000521400083102103E00008DE +:10410000244200883C09080091293D9124A800021E +:104110003C05110000093C0000E8302500C51825C9 +:1041200024820008AC83000003E00008AC80000497 +:104130009347010B8F4A002C974F09083C18000E3B +:104140000358482131EEFFFF000E41C0AF48002C5C +:1041500097430908952C001A008040212403000190 +:10416000318BFFFFAC8B00008D2D001C00A058216F +:1041700000C06021AC8D00048D24002030E7004099 +:10418000AD04000891220019304400031083004858 +:104190002885000214A00062240600021086005642 +:1041A00024190003109900660000000010E0003A96 +:1041B000000000003C07080094E73D8624E200016F +:1041C000934F0934934709219525002A31EE00FFCA +:1041D000000E488230ED00FF978700580009360036 +:1041E000000D1C003044FFFF00C310250044C02513 +:1041F00000A778213C19400003197025000F4C00DE +:10420000AD090004AD0E0000934D09203C030006EB +:1042100025090014000D360000C32025AD04000858 +:104220008F59092C24E5000130A27FFFAD19000C45 +:104230008F580930A782005825020028AD180010B9 +:104240008F4F0938AD0F0014AD2B00048F4E09407D +:10425000AD2E0008934D09373C05080090A53D9010 +:104260008F4409488F46094031A700FF00EC182110 +:10427000008678230003C7000005CC0003196025E1 +:1042800031E8FFFC01885825AD2B000CAD20001053 +:1042900003E00008AF4A002C3C0D080095AD3D86B8 +:1042A0003C0E080095CE3D800A0004C901AE1021E5 +:1042B0003C05080094A53D8A3C06080094C63D8054 +:1042C0003C18080097183D7C952E002400A6782104 +:1042D00001F86823000E240025A2FFF200821825B1 +:1042E00024190800AD03000CAD190014AD00001036 +:1042F0000A0004C4250800189526002495250028E6 +:104300000006C40000057C00370E810035ED080072 +:10431000AD0E000CAD0D00100A0004C425080014F9 +:104320001480FFA200000000952400240004140063 +:1043300034430800AD03000C0A0004C42508001033 +:104340003C03080094633D8A3C05080094A53D8029 +:104350003C06080094C63D7C953900249538002819 +:10436000006520210086782300196C000018740075 +:1043700025E2FFEE01C2202535A3810024190800A3 +:10438000AD03000CAD040010AD190018AD00001411 +:104390000A0004C42508001C03E00008240201F4FC +:1043A00027BDFFE8AFB00010AFBF00140E000060E3 +:1043B0000080802124050040AF4508148F83005001 +:1043C0008F84004C8F85005C0070182100641023DE +:1043D00018400004AF830050AF6300548F66005450 +:1043E000AF86004C1200000C000000008F440074E7 +:1043F000936800813409FA002D07000710E00005DA +:1044000000891021936C0081240B01F4018B50046E +:1044100001441021AF62000C8F4E095C01C5682376 +:1044200019A000048FBF00148F4F095CAF8F005C90 +:104430008FBF00148FB000100A00006227BD001863 +:104440008F8400648F8300508F82004CAF640044DF +:10445000AF63005003E00008AF6200543C038000EB +:10446000346200708C43000027BDFFF8308700FFE6 +:1044700030A900FF30C800FFAF8300308F440178BF +:104480000480FFFE3C028000345900708F38000029 +:10449000A3A700033C0708008CE700748FAC000062 +:1044A0003C0608008CC60070030378233C0E7FFF97 +:1044B00000EFC82135CDFFFF00005021018D2824D9 +:1044C00000CA1821000847C0032F202B00A8102580 +:1044D0000064C021AFA200003C010800AC390074A8 +:1044E0003C010800AC380070934F010AA3A0000201 +:1044F0003C0E80FFA3AF00018FAC0000312B007F8A +:1045000035CDFFFF018D4824000B5600012A4025C0 +:10451000240730002406FF803C05100027BD00085A +:10452000AF48014CAF470154A7400158A346015280 +:1045300003E00008AF45017827BDFFE8AFBF0014D6 +:10454000AFB000108F6500743C068000309000FF13 +:1045500000A620250E000060AF6400749363000580 +:10456000346200080E000062A362000502002021F0 +:104570008FBF00148FB00010240500052406000131 +:104580000A00057027BD001827BDFFE03C0380002E +:10459000AFB00010AFBF0018AFB1001434620070AC +:1045A0008C470000309000FF30A800FFAF8700303C +:1045B0008F4401780480FFFE3C18800037110070A2 +:1045C0008E2F00003C0D08008DAD00743C0A0800E1 +:1045D0008D4A007001E7702301AE282100005821A8 +:1045E00000AE302B014B4821012638213C01080048 +:1045F000AC250074000088213C010800AC27007045 +:104600001100000F000000008F6200742619FFFFE8 +:104610003208007F0002FE0233E5007F150000062D +:10462000332200FF2407FF800207202624A3FFFF78 +:1046300000838025320200FF0040802124111008F1 +:104640000E000060000000008F49081831250004AA +:1046500014A0FFFD3218007F001878C000187140C8 +:1046600001CF682125AC0088AF4C0818274A098083 +:104670008D4B0020AF4B01448D460024AF460148CE +:10468000A35001500E000062A740015802201021E3 +:104690008FBF00188FB100148FB0001003E0000826 +:1046A00027BD002027BDFFE8308400FFAFBF00100A +:1046B0000E0005BB30A500FF8F8300508FBF001098 +:1046C000344500402404FF903C02100027BD001830 +:1046D000AF43014CA3440152AF45015403E000082D +:1046E000AF4201789343093E306200081040000D4C +:1046F0003C0901013528080AAC8800008F47007486 +:10470000AC8700043C06080090C63D9030C5001000 +:1047100050A00006AC8000088F6A0060AC8A0008D8 +:104720002484000C03E00008008010210A00062207 +:104730002484000C27BDFFE8AFBF0014AFB0001009 +:104740009346093F00A050210005288000853823AA +:1047500030C200FF240300063C09080095293D866D +:1047600024E8FFD824050004104300372406000283 +:104770009750093C3C0F020400063400320EFFFF44 +:1047800001CF6825AC8D0000934C093E318B002091 +:104790001160000800000000934309363C02010349 +:1047A000345F0300307900FF033FC0252405000873 +:1047B000AC98000493430934935909210005F88209 +:1047C000306200FF0002C082332F00FF00186E002D +:1047D000000F740001AE6025018920253C094000CE +:1047E00000898025ACF0FFD8934309378F4F0948E3 +:1047F0008F580940306200FF004AC821033F7021F2 +:1048000001F86023000E6F0001A650253185FFFCE2 +:10481000001F58800145482501683821AD09002056 +:104820000E00006024F00028240400040E00006242 +:10483000A364003F020010218FBF00148FB000104E +:1048400003E0000827BD00180A0006352406001200 +:1048500027BDFFD024090010AFB60028AFB5002453 +:10486000AFB40020AFB10014AFB000103C0108009D +:10487000A0293D90AFBF002CAFB3001CAFB2001811 +:1048800097480908309400FF3C02000E3107FFFFF3 +:10489000000731C0AF46002C974409089344010B30 +:1048A00030B500FF03428021308300300000B0218A +:1048B0001060012500008821240C00043C01080040 +:1048C000A02C3D90934B093E000B5600000A2E038E +:1048D00004A0016000000000AF400048934F010BAE +:1048E00031EE002011C00006000000009358093E80 +:1048F00000189E0000139603064001890000000086 +:104900009344010B30830040106000038F930050EC +:104910008F8200502453FFFF9347093E30E6000882 +:1049200014C0000224120003000090219619002CEC +:1049300093580934934F0937A7990058330C00FF57 +:1049400031EE00FF024E6821000D5880016C5021AD +:10495000015140213C010800A4283D869205001821 +:1049600030A900FF010918213C010800A4233D885B +:104970009211001816200002000000000000000D37 +:104980003C010800A4233D8A3C010800A4203D808E +:104990003C010800A4203D7C935F010B3063FFFFC6 +:1049A00033F00040120000022464000A2464000B6B +:1049B0003091FFFF0E00009E022020219358010B32 +:1049C0003C08080095083D8A0040202100185982C3 +:1049D000316700010E00049A01072821934C010B56 +:1049E0008F4B002C974E09083C0F000E034F4021BF +:1049F00031CDFFFF000D51C0AF4A002C974309088D +:104A00009505001A004038212404000130A9FFFF59 +:104A1000AC4900008D06001C00404821318A00404E +:104A2000AC4600048D020020ACE20008910300199E +:104A300030630003106400EC28790002172001188D +:104A4000241000021070010C241F0003107F011EAF +:104A500000000000114000DE000000003C090800DA +:104A600095293D8625220001935F0934934E092143 +:104A70009504002A33F900FF0019C08231CF00FFEE +:104A8000978E005800184600000F6C00010D80251D +:104A90003045FFFF02051025008E50213C034000E9 +:104AA00000433025000A6400ACEC0004ACE60000D2 +:104AB000935F09203C19000624EC0014001FC60077 +:104AC00003197825ACEF00088F48092C25CD00018B +:104AD00031A57FFFACE8000C8F500930A785005846 +:104AE00024E80028ACF000108F4409380100802130 +:104AF000ACE40014AD9300048F530940AD9300085B +:104B0000934A09373C19080093393D908F4309486F +:104B10008F460940314200FF0052F82100667023A1 +:104B2000001F7F000019C40001F8282531CDFFFCCB +:104B300000AD2025AD84000CAD800010AF4B002CE3 +:104B4000934B093E317300081260000D3C060101D1 +:104B500034CC080AACEC00288F530074AD13000469 +:104B60003C0B0800916B3D903167001050E0000352 +:104B7000AD0000088F6A0060AD0A00082510000C27 +:104B800012C0003D000000009343093F24160006B8 +:104B900024060004306200FF105600C924070002FA +:104BA0009758093C3C0F0204330DFFFF01AF40252D +:104BB000AE0800009345093E30A400201080000894 +:104BC00000000000935309363C0B0103357F0300BE +:104BD000327900FF033F7025AE0E00042406000862 +:104BE000934F093493480921312AFFFF31ED00FF2B +:104BF000000D1082310300FF0002B60000032C00FC +:104C000002C56025018A9825001220803C094000D9 +:104C10000204502302695825AD4BFFD8935F093732 +:104C20008F4F09488F58094033F900FF0332702134 +:104C30000006B08201D668210007440001F828234D +:104C4000000D1F000068302530A2FFFC2547FFD86B +:104C500000C260250016808002074821ACEC0020CD +:104C6000253000280E00006024120004A372003FCB +:104C70000E000062000000009347010B30F200407C +:104C8000124000053C1900FF8E180000372EFFFF70 +:104C9000030E3024AE0600000E0000C702202021C3 +:104CA0003C10080092103D90321100031220000FBA +:104CB00002A028218F89005025330001AF930050B6 +:104CC000AF7300508F6B00540173F8231BE0000298 +:104CD000026020218F640054AF6400548F4C007434 +:104CE000258401F4AF64000C02A028210280202159 +:104CF000A76000680E0005BB3C1410008F850050B3 +:104D000034550006AF45014C8F8A00488FBF002CF8 +:104D10008FB3001C25560001AF9600488FB20018D3 +:104D2000A34A01528FB60028AF5501548FB1001429 +:104D3000AF5401788FB500248FB400208FB00010DD +:104D400003E0000827BD00309358093E00189E007C +:104D500000139603064200362411000293440923EF +:104D6000308300021060FEDD8F8600608F8200506D +:104D700014C2FEDA000000000E0000600000000017 +:104D80009369003F24070016312800FF1107000C2B +:104D9000240500083C0C0800918C3D90358B0001E7 +:104DA0003C010800A02B3D90936A003F314300FF77 +:104DB00010650065240D000A106D005E2402000CD1 +:104DC0000E000062000000000A00069000000000D3 +:104DD0003C09080095293D863C0A0800954A3D801B +:104DE0000A0006F3012A10213C09080095293D8A92 +:104DF0003C04080094843D803C06080094C63D7C39 +:104E000095030024012410210046F8230003CC0060 +:104E100027F0FFF20330C025240F0800ACF8000C87 +:104E2000ACEF0014ACE000100A0006EE24E7001816 +:104E30003C010800A0313D90935F093E241600011B +:104E400033F900201720FEA5241100080A0006905F +:104E5000241100048F6E00848F4D094011A0FE9E26 +:104E6000AF8E0050240F00143C010800A02F3D908D +:104E70000A00068F00000000950E0024950D002802 +:104E8000000E6400000D2C003589810034A6080056 +:104E9000ACE9000CACE600100A0006EE24E70014B2 +:104EA0001460FEEC000000009502002400021C00CB +:104EB00034640800ACE4000C0A0006EE24E700109D +:104EC0000A000741240700123C02080094423D8A70 +:104ED0003C06080094C63D803C03080094633D7C7A +:104EE00095100024951900280046F82103E3C023FB +:104EF00000106C0000197400270FFFEE01CF282569 +:104F000035AC8100ACEC000CACE5001024070800C7 +:104F1000AD2700182527001C0A0006EEAD2000145E +:104F20008F7F004CAF7F00548F7900540A000699A0 +:104F3000AF790050A362003F0E0000620000000045 +:104F40000A00069000000000240200140A0008274E +:104F5000A362003F27BDFFE8308400FFAFBF001011 +:104F60000E0005BB30A500FF9378007E9379007F8B +:104F7000936E00809368007A332F00FF001866005C +:104F8000000F6C0031CB00FF018D4825000B520053 +:104F90008FBF0010012A3825310600FF344470000D +:104FA00000E628252402FF813C03100027BD0018DD +:104FB000AF45014CAF440154A342015203E0000845 +:104FC000AF43017827BDFFD8AFB20018AFB10014CE +:104FD000AFB00010AFBF0020AFB3001C9342010977 +:104FE000308600FF30B000FF000618C23204000215 +:104FF0003071000114800005305200FF93670005F6 +:1050000030E5000810A0000D30C80010024020213B +:105010000E0005A702202821240400018FBF0020D4 +:105020008FB3001C8FB200188FB100148FB0001026 +:105030000080102103E0000827BD00281500003281 +:105040000000000093430109000028213062007F26 +:10505000000220C00002F94003E49821267900886C +:10506000033B98218E7800248E6F0008130F0046B2 +:10507000000000008F640084241800020004FD82F8 +:1050800033F900031338007C0000000093660083AE +:10509000934A0109514600043205007C10A00060CB +:1050A000000000003205007C14A0005302402021C3 +:1050B00016200006320400018E7F00248F5901045F +:1050C00017F9FFD600002021320400011080000AE9 +:1050D000024020218F4209408F9300641053000644 +:1050E000000000000E00066D022028218F430940B9 +:1050F000AF630044024020210E0006020220282156 +:105100000A000860240400013C0908008D2900649D +:10511000252600013C010800AC26006416000012A0 +:10512000000000008F6D00843C0E00C001AE6024C2 +:1051300015800005024020210E00082E02202821A3 +:105140000A00086024040001240500040E00057014 +:1051500024060001024020210E00082E02202821F2 +:105160000A000860240400010E000041240400012C +:10517000936B007D020B50250E000062A36A007D38 +:105180000A0008A38F6D00848F6600748F480104A5 +:105190008E67002400064E021507FFB63126007FF9 +:1051A000936B008326440001308A007F1146004340 +:1051B000316300FF5464FFB08F6400842645000112 +:1051C00030B1007F30A200FF122600042405000148 +:1051D000004090210A00087624110001240FFF806E +:1051E000024F702401CF9026324200FF00409021F0 +:1051F0000A000876241100010E00066D0220282105 +:10520000321800301300FFAA321000820240202121 +:105210000E0005A7022028210A00086024040001CE +:105220008F6E00743C0F80002405000301CF902591 +:10523000AF72007493710083240600010E000570A4 +:10524000322400FF0E00004124040001936D007D14 +:10525000020D60250E000062A36C007D3C0B08006F +:105260008D6B0054257000013C010800AC300054E7 +:105270000A000860240400018F6800743C09800063 +:105280002405000401093825AF6700749363008387 +:10529000240600010E000570306400FF0E0000417E +:1052A000240400019362007D020298250E00006232 +:1052B000A373007D0A00086024040001324D0080C1 +:1052C00039AC0080546CFF6C8F6400840A0008C9FC +:1052D0002645000127BDFFC83C0A0008AFBF0030CB +:1052E000AFB5002CAFB40028AFB30024AFB200209C +:1052F000AFB1001CAFB00018034AD8212409004008 +:10530000AF490814AF4008108F4209448F43095039 +:105310008F4609548F47095C8F48094C9344010814 +:105320009345010BAF820064308400FF30A500FF7D +:10533000AF830050AF86004CAF87005C0E00084A78 +:10534000AF8800601440017D8FBF0030A760006807 +:10535000934D0900240B00503C15080026B53D482C +:1053600031AC00FF3C12080026523D58118B00035F +:10537000000000000000A8210000902193510109C5 +:105380008F9F005024040010322E007F000E68C052 +:10539000000E6140018D282124B40088AF54081804 +:1053A0008F4901048F4A09A43C0B000E034BC02116 +:1053B000012A10233C010800AC223D6C8F430958A0 +:1053C0003C010800A0243D9097470908007F302346 +:1053D0003C010800AC263D7030E8FFFF0008C9C062 +:1053E0003C010800AC3F3D94AF59002C974209089E +:1053F0009710002C8EB10000930F001803749821B1 +:10540000A7900058AF9300440220F80931F000FF44 +:10541000304E000215C001B2304F000111E0014FC3 +:10542000000000009343093E3066000814C00002EB +:10543000241400030000A0218F5809A424130001A4 +:105440003C010800AC383D98934F0934935109371B +:1054500031EC00FF322E00FF028E6821000D288003 +:1054600000AC5021015058213C010800A42B3D887C +:105470003C010800A42A3D8693490934312200FFEB +:1054800002022021249000103C010800A4303D8439 +:10549000240700068F9F00503C010800AC273D8C7C +:1054A0008F88005C8F59095800008021011F282334 +:1054B00004A00149033F20230480014700A4302BAE +:1054C00010C00149000000003C010800AC253D70FF +:1054D0008E4200000040F809000000003043000246 +:1054E000146000F80040882130440001548000100E +:1054F0008E4200043C0908008D293D743C0AC0001E +:10550000012A8025AF500E008F45000030AB000807 +:105510001160FFFD00000000974D0E0824100001EF +:10552000A78D003C8F4C0E04AF8C00348E420004DB +:105530000040F8090000000002228825322E0002F7 +:1055400015C00180000000003C09080095293D7C41 +:105550003C06080094C63D883C0A0800954A3D7EFA +:105560003C1908008F393D74012660213C18080061 +:105570008F183D983C03080094633D92018A2021D6 +:105580008F4E09400329F821248F000203E32821CC +:10559000031968213C010800A42C3D8AAF8E0064E9 +:1055A0003C010800AC2D3D983C010800A4253D803D +:1055B0000E00009E31E4FFFF8F870048004020214D +:1055C0003C010800A0273D918E42000824E800011C +:1055D000AF8800480040F809000000009344010B28 +:1055E0008F4C002C974A09083C0B000E034B4021BE +:1055F0003149FFFF000919C08F8B0050AF43002CC9 +:10560000974309089506001A00403821308A004067 +:1056100030DFFFFFAC5F00008D19001C0040482107 +:10562000AC5900048D180020AC580008910F0019E7 +:1056300031E30003107300F0000000002862000254 +:105640001440010924050002106500FD240D00032B +:10565000106D010D00000000114000D90000000095 +:105660003C0A0800954A3D8625420001934D0934C5 +:1056700093580921950E002A31A300FF00032082D0 +:10568000331F00FF9798005800047E00001FCC00D5 +:1056900001F940253049FFFF0109102501D83021CB +:1056A0003C0540000045502500066C00ACED0004B0 +:1056B000ACEA0000934309203C04000624ED0014EA +:1056C0000003FE0003E4C825ACF900088F49092C4B +:1056D000270F000131EE7FFFACE9000C8F48093045 +:1056E000A78E005824E90028ACE800108F4509383F +:1056F00001204021ACE50014ADAB00048F4209400D +:10570000ADA20008934B09373C1F080093FF3D9062 +:105710008F4309488F4A0940316600FF00D4202199 +:10572000006A78230004C700001FCC000319282555 +:1057300031EEFFFC00AE1025ADA2000CADA00010B4 +:10574000AF4C002C934C093E318B00085160000F88 +:105750008E58000C3C06010134CA080AACEA002845 +:105760008F4B0074AD2B00043C0C0800918C3D90D5 +:105770003187001050E00003AD2000088F62006008 +:10578000AD2200082528000C8E58000C0300F809F3 +:10579000010020213C19080097393D8A3C1F080070 +:1057A00097FF3D7E033F782125E900020E0000C7E8 +:1057B0003124FFFF3C0E08008DCE3D6C3C080800F4 +:1057C0008D083D7401C828233C010800AC253D6CC0 +:1057D00014A00006000000003C0308008C633D8C10 +:1057E000346400403C010800AC243D8C1200007081 +:1057F0008F8C00448F470E108F900044AE0700201E +:105800008F4D0E18AE0D00243C10080096103D8000 +:105810000E0000600000000024020040AF420814A7 +:105820008F8600508F8A004C00D01821006A5823C0 +:1058300019600004AF830050AF6300548F650054BB +:10584000AF85004C1200000C000000008F44007473 +:10585000936800813409FA002D0E000711C000057D +:1058600000891821937F0081241901F403F9780439 +:1058700001E41821AF63000C8F44095C8F83005C46 +:105880000083C0231B000003000000008F50095C50 +:10589000AF90005C0E000062000000008F8C005092 +:1058A0008E4700103C010800AC2C3D9400E0F80944 +:1058B000000000003C0D08008DAD3D6C55A0FEF5CC +:1058C000240700068F450024975909088F8B006430 +:1058D0008F9400503C0F001F978200588F86005411 +:1058E0008F93004C3328FFFF35E9FF8000A9502437 +:1058F000000871C032320100AF4E0024A4C2002C57 +:10590000AF4A0024AF6B0044AF740050AF73005433 +:105910001640008032380010570000868EA4000424 +:10592000322300405460001B8EB100088EB0000C82 +:105930000200F809000000008FBF00308FB5002C76 +:105940008FB400288FB300248FB200208FB1001CC9 +:105950008FB0001803E0000827BD00389347010905 +:105960008F8800380007FE0003E8C825AF59008083 +:105970008F5809A08F5309A4AFB80010AF580E1468 +:105980008FB40010AF540E10AF530E1C0A00096202 +:10599000AF530E180220F809000000008EB0000C72 +:1059A0000200F809000000000A000AA88FBF0030BA +:1059B000A5800020A59300220A000A5BAD93002475 +:1059C0003C09080095293D863C06080094C63D80A8 +:1059D0000A0009F4012610213C010800AC203D70AA +:1059E0000A00098E8E4200003C010800AC243D7084 +:1059F0000A00098E8E4200003C03080094633D8A31 +:105A00003C04080094843D803C1F080097FF3D7CC7 +:105A1000951800240064C821033F782300186C0007 +:105A200025EEFFF201AE2825AC45000C240208004B +:105A3000ACE20014ACE000100A0009EF24E7001803 +:105A400095060024950900280006240000091C0082 +:105A5000349F810034790800ACFF000CACF90010D1 +:105A60000A0009EF24E700141460FEFB00000000A8 +:105A70009518002400187C0035EE0800ACEE000CF0 +:105A80000A0009EF24E700103C07080094E73D8076 +:105A90003C04080094843D8A3C03080094633D7CE8 +:105AA00095190024951800280087F82103E378232E +:105AB0002407080000192C0000186C0025EEFFEEEA +:105AC00001AE302534A28100AD2700182527001C27 +:105AD000AD22000CAD2600100A0009EFAD20001425 +:105AE00093520109000028210E000602324400FFF3 +:105AF0008FBF00308FB5002C8FB400288FB30024E7 +:105B00008FB200208FB1001C8FB0001803E0000896 +:105B100027BD0038935F010933E400FF0E00066DD6 +:105B200000002821323800105300FF7E322300404D +:105B30008EA400040080F809000000000A000AA2F8 +:105B4000322300401200FF5F000000008F540E144B +:105B50008F920044AE5400208F530E1C0A000A8A14 +:105B6000AE5300248F82001C008040213C040100C1 +:105B70009047008530E3002010600009000000001D +:105B80003C0708008CE73D948F83001800E3202336 +:105B9000048000089389000414E30003010020211D +:105BA00003E00008008010213C04010003E000082D +:105BB000008010211120000B006738238F8C0020FB +:105BC00024090034918B00BC316A0002514000016D +:105BD0002409003000E9682B15A0FFF10100202105 +:105BE00000E938232419FFFC00B9C02400F9782407 +:105BF00000F8702B15C0FFEA01E8202130C2000335 +:105C00000002182314C00012306900030000302184 +:105C100000A9702101C6682100ED602B1180FFE012 +:105C20003C0401002D2F00010006482B01053821FE +:105C300001E9302414C0FFDA24E4FFFC2419FFFC3E +:105C400000B9C0240308202103E0000800801021CF +:105C50008F8B002024060004916A00BC31440004AC +:105C60001480FFEC00A970210A000B5E00003021B7 +:105C700027BDFFE8AFBF00108F460100934A01091E +:105C80003C1F08008FFF00902407FF80314F00FF6A +:105C900031E8007F0008614003E6C821032CC021E1 +:105CA00027090120012770243C010800A02F3DD0C6 +:105CB000AF4E080C3C0D08008DAD00903C040080F8 +:105CC0003482000301A65821016C182124650120AB +:105CD00030AA007801424025AF48081C3C1F08004C +:105CE0008FFF00908F88004003E6C0213319000722 +:105CF00003074824033A7821AF49002825E909C061 +:105D0000952E00023C0D08008DAD008C3C0A080069 +:105D10008D4A009031CC3FFF01A61821000C59801C +:105D2000006B282100A72024AF44002C95220002FC +:105D30003C1F08008FFF008C9107008530593FFF02 +:105D400003E678210019C1800146702101F868211D +:105D500031CC007F31AB007F019A2821017A50219C +:105D60003C03000C3C04000E00A328210144102138 +:105D700030E6002027470980AF82002CAF88001C46 +:105D8000AF890024AF85002010C00006AF8700282F +:105D90008D0200508CA4010C0044302318C0007701 +:105DA00000000000910C0085240DFFDF018D3824D8 +:105DB000A10700858F8B001C8F8900248F87002806 +:105DC0008D65004CAF850018912F000D31EE00203D +:105DD00011C000170000000024090001A38900047D +:105DE000AF80000C8CE400248F85000C240A00088E +:105DF000AF800008AF8000103C010800A42A3D7E5F +:105E00003C010800A4203D920E000B32000030211E +:105E10008F8500248FBF0010AF82001490A8000D62 +:105E200027BD00180008394203E0000830E20001F5 +:105E3000913F00022418000133F900FF001921826C +:105E400010980039240800021088005B8F86002C0F +:105E50008CE5002414A0001B8F9F002091220000DD +:105E6000240A00053046003F10CA00472404000100 +:105E70008F860008A3840004AF860010AF86000C54 +:105E80008CE400248F85000C240A00083C010800E3 +:105E9000A42A3D7E3C010800A4203D920E000B3256 +:105EA000000000008F8500248FBF0010AF82001417 +:105EB00090A8000D27BD00180008394203E0000833 +:105EC00030E200018CF800088CF900248FEE00C449 +:105ED000A38000048CE40024AF8E000C8F85000C9E +:105EE0008F86000803197823240A0008AF8F00105A +:105EF0003C010800A42A3D7E3C010800A4203D92FC +:105F00000E000B32000000008F8500248FBF0010B0 +:105F1000AF82001490A8000D27BD00180008394278 +:105F200003E0000830E20001912300003062003FEE +:105F3000104400278F8500208CE400241480002169 +:105F4000000000008D2E00183C187FFF8F85002078 +:105F5000370FFFFF01CF1824AF8300088F9F000881 +:105F60008CA8008403E8C82B1720000203E020213E +:105F70008CA400840A000BEDAF8400088CA3010CF4 +:105F80000A000BCBAF8300188D2C00188F860008F9 +:105F90003C0D7FFF8F89002035A3FFFF018358242C +:105FA00024040001AF8B0010AD2000CCA3840004BA +:105FB0000A000BF9AF86000C8CCA00140A000BED26 +:105FC000AF8A00088CA300C80A000C30AF83000819 +:105FD0008F84002C8CAC00648C8D0014018D582BA8 +:105FE00011600004000000008CA200640A000C3064 +:105FF000AF8200088C8200140A000C30AF820008C7 +:106000008F85000C27BDFFE0AFBF0018AFB10014B3 +:1060100014A00007AFB000108F86002424020005F2 +:1060200090C400003083003F106200B68F840020CF +:106030008F91000800A080218F8C00283C0508006B +:106040008CA53D708D8B000431663FFF00C5502B41 +:106050005540000100C02821938D000411A0007359 +:1060600000B0F82B8F98002024040034930F00BC5C +:1060700031EE000251C000012404003000A4C82BFE +:10608000172000D10000000000A4282300B0F82B46 +:106090003C010800A4243D7C17E000680200202198 +:1060A0003C0308008C633D6C0083102B54400001BE +:1060B000008018218F8800243C010800AC233D7427 +:1060C000000048219104000D308300205060000141 +:1060D0008F490E188F8300140123382B10E00059CC +:1060E000000000003C0408008C843D7400895821A5 +:1060F000006B502B114000560090602B006930233C +:1061000000C020213C010800AC263D7412000003B1 +:10611000241FFFFC1090008A32270003009FC82430 +:106120003C010800AC393D743C010800A4203D92BC +:106130008F84000C120400078F830020AF910008A9 +:10614000020020218C7100CCAF90000C26300001A1 +:10615000AC7000CC3C0208008C423D748F8A001069 +:10616000240700180082202301422823AF84000C5A +:1061700010800002AF850010240700108F86001CDD +:106180003C010800A0273D902407004090CC0085EA +:10619000318B00C0116700408F8D001414A00015D2 +:1061A00000002021934A01098F420974314500FF04 +:1061B0000002260224A300013090007F3071007F8E +:1061C0001230007A2407FF80A0C300833C09080036 +:1061D0008D293D8C8F880024240D0002352C000869 +:1061E0003C010800A02D3DD13C010800AC2C3D8CA9 +:1061F00024040010910E000D31C6002010C00005CF +:1062000000801821240800013C010800AC283D74DE +:10621000348300018FBF00188FB100148FB00010BD +:106220000060102103E0000827BD00203C010800A9 +:10623000A4203D7C13E0FF9A020020210A000C817B +:1062400000A020213C0408008C843D740090602B49 +:106250001180FFAE000000003C0F080095EF3D7C70 +:1062600001E4702101C6682B11A000072C820004F4 +:106270003C1F60008FF954043338003F1700FFE5DE +:10628000240300422C8200041040FFA0240300429B +:106290000A000CDF8FBF0018152DFFC000000000A2 +:1062A0008CDF00743C0380002405FF8003E3C825D5 +:1062B000ACD9007490D80085240E0004240400108A +:1062C000330F003F01E54025A0C800858F880024DA +:1062D0003C010800A02E3DD1240300019106000DD1 +:1062E00030C9002015200003000000003C03080016 +:1062F0008C633D743C010800AC233D6C0A000CD655 +:10630000000000008F8700108C88008400E8282B94 +:1063100014A0000200E088218C910084240900016F +:10632000A38900048F440E18022028210E000B328E +:1063300002203021022080210A000C67AF82001465 +:1063400000071823306600033C010800A4263D9294 +:10635000122000058F8C0020918B00BC316A000454 +:106360001540001524CD00043C0F080095EF3D9228 +:1063700001E4702100AE302B50C0FF6E8F84000C02 +:106380002C85000514A0FFA32403004230980003CD +:1063900017000002009818232483FFFC3C0108002A +:1063A000AC233D740A000CA30000000000A7582491 +:1063B0000A000CCB016718263C010800A42D3D9271 +:1063C0000A000D33000000003C010800AC203D74C1 +:1063D0000A000CDE240300428F83001014600007C3 +:1063E000000010218F88002424050005910600007C +:1063F00030C400FF108500030000000003E0000827 +:1064000000000000910A0018314900FF000939C25C +:1064100014E0FFFA8F85001C3C04080094843D7C46 +:106420003C0308008C633D943C1908008F393D748F +:106430003C0F080095EF3D920064C0218CAD0054E4 +:106440000319702101CF6021018D58231960001DAF +:1064500000000000910E001C8F8C002C974B0E103A +:1064600031CD00FF8D850004016D30238D88000043 +:1064700030CEFFFF000E510000AAC82100003821D5 +:1064800001072021032A182B0083C021AD990004A5 +:10649000AD980000918F000A01CF6821A18D000AFC +:1064A0008F88002C974B0E12A50B0008950A003818 +:1064B00025490001A50900389107000D34E60008C0 +:1064C000A106000D03E000080000000027BDFFE06A +:1064D000938700048F8F00248FAD00143C0E7FFF44 +:1064E0008F89000C35C8FFFFAFBF001CAFB000188C +:1064F00001A8182491EA000D000717C03C1FBFFF38 +:10650000006258252D2E00018F90001837F9FFFFEB +:106510003C1808008F183D943C0F080095EF3D8A09 +:1065200001796824000E47803C07EFFF3C05F0FF2F +:1065300001A818253149002034E2FFFF34ACFFFFE9 +:106540000310582327A500102406000225EA0002A4 +:1065500000621824008080211520000200004021E4 +:106560008F480E1CA7AA0012056000372407000000 +:1065700030FF00FF001FCF008F8B001C00793825F3 +:10658000AFA70014916F00853C08080091083D9169 +:106590003C18DFFF31EE00C0370AFFFF000E182B5A +:1065A0003C1F080097FF3D8400EA6824A3A800115F +:1065B0000003174001A248258FB90010AFA90014AD +:1065C0003C0A0800914A3D93A7BF00168FA800140B +:1065D000032CC0243C0B01003C0F0FFF030B1825BC +:1065E0003147000335EEFFFF010C68240007160059 +:1065F000006EF8243C09700001A2C82503E9582563 +:10660000AFB90014AFAB00100E000076A3A00015C8 +:106610008F8C0024260200089186000D30C40020D3 +:10662000108000068FBF001C3C05080094A53D802B +:1066300024B0FFFF3C010800A4303D808FB000185B +:1066400003E0000827BD00208F9800140118502B8C +:106650005540FFC7240700010A000DB630FF00FFB8 +:106660009382000427BDFFE0AFBF00181040000F69 +:10667000008050218F880024240B00058F8900089A +:10668000910700008F8400200100282130E3003FA3 +:106690008F86002C106B000800003821AFA9001075 +:1066A0000E00040EAFAA0014A38000048FBF0018D0 +:1066B00003E0000827BD00208D1900183C0F0800DA +:1066C0008DEF3D748F9800103C027FFF8D08001401 +:1066D000345FFFFF033F682401F8702101AE60239F +:1066E00001883821AFA900100E00040EAFAA0014D3 +:1066F0000A000E04A38000048F8700243C050800D4 +:1067000094A53D923C0208008C423D8C90E6000D21 +:106710000005240030C300201060002C00444025F8 +:106720008F85001C00006021240B000190A30085D0 +:1067300000004821240A00013C0F800035EE007063 +:106740008DC70000AF8700308F5801780700FFFE2B +:106750003C038000347900708F3800003C0508004D +:106760008CA500743C0D08008DAD007003077823E4 +:1067700000AF38210000102100EF302B01A22021B2 +:10678000008618213C010800AC2700743C01080079 +:10679000AC230070AF4B01483C1908008F393D9481 +:1067A000A7490144A74A0146AF59014C3C0B0800D8 +:1067B000916B3D91A34B0152AF4801543C0810002E +:1067C000A74C015803E00008AF4801788F4B0E1C1E +:1067D0003C0A08008D4A3D7497490E16974D0E14D9 +:1067E00001456021312AFFFF0A000E2731A9FFFF72 +:1067F0008F8300249064000D308200201040002917 +:10680000000000000000482100005021000040214D +:106810003C07800034EB00708D670000AF870030CC +:106820008F4C01780580FFFE3C0D800035AC007078 +:106830008D8B00003C0508008CA500743C0408000A +:106840008C8400700167302300A67821000010219D +:1068500001E6C82B0082C021031970213C01080009 +:10686000AC2F00743C010800AC2E0070AF49014809 +:106870003C0D08008DAD3D94A7480144240900401B +:10688000A74A01463C081000240AFF91AF4D014C75 +:10689000A34A0152AF490154A740015803E0000840 +:1068A000AF4801788F490E1897460E1297450E1083 +:1068B00030CAFFFF0A000E5D30A8FFFF8F8300245F +:1068C00027BDFFF89064000D308200201040003A90 +:1068D00000000000240B000100004821240A0001F0 +:1068E0003C088000350700708CE30000AF83003067 +:1068F0008F4C01780580FFFE3C0E80003C040800B0 +:1069000090843DD035C700708CEC00003C05080039 +:106910008CA50074A3A400033C1908008F390070F3 +:106920008FAD00000183302300A638210000102124 +:106930000322782100E6C02B01F8602101AE40253A +:10694000AFA800003C010800AC2700743C0108001F +:10695000AC2C00709346010A3C04080090843DD1A1 +:10696000A3A00002A3A600018FA300003C0580FFA6 +:106970003099007F34A2FFFF006278240019C6001E +:1069800001F87025240D3000AF4E014C27BD0008E2 +:10699000AF4D0154A7400158AF4B0148A7490144EE +:1069A000A74A01463C091000240AFF80A34A01526D +:1069B00003E00008AF4901788F4B0E1897460E127E +:1069C00097450E1030CAFFFF0A000E9130A9FFFF55 +:1069D0008F85001C2402008090A40085308300C0B5 +:1069E000106200058F8600208F8800088F87000CBA +:1069F000ACC800C8ACC700C403E000080000000039 +:106A00003C0A0800254A39543C09080025293A2047 +:106A10003C08080025082DD43C07080024E73B3437 +:106A20003C06080024C637C43C05080024A5353CB4 +:106A30003C040800248431643C0308002463385C6F +:106A40003C020800244236303C010800AC2A3D508C +:106A50003C010800AC293D4C3C010800AC283D48F5 +:106A60003C010800AC273D543C010800AC263D64C5 +:106A70003C010800AC253D5C3C010800AC243D58BD +:106A80003C010800AC233D683C010800AC223D609D +:086A900003E000080000000013 +:00000001FF --- linux-3.13.0.orig/firmware/bnx2/bnx2-mips-09-6.2.1b.fw.ihex +++ linux-3.13.0/firmware/bnx2/bnx2-mips-09-6.2.1b.fw.ihex @@ -0,0 +1,6496 @@ +:10000000080001180800000000005594000000C816 +:1000100000000000000000000000000008005594EF +:10002000000000380000565C080000A00800000036 +:100030000000574400005694080059200000008436 +:100040000000ADD808005744000001C00000AE5CBD +:100050000800321008000000000092580000B01C98 +:10006000000000000000000000000000080092589E +:100070000000033C000142740800049008000400E2 +:10008000000012FC000145B000000000000000006C +:1000900000000000080016FC00000004000158AC3D +:1000A000080000A80800000000003D00000158B052 +:1000B00000000000000000000000000008003D00FB +:1000C00000000030000195B00A000046000000006A +:1000D000000000000000000D636F6D362E322E31DF +:1000E00062000000060201020000000000000003A0 +:1000F000000000C800000032000000030000000003 +:1001000000000000000000000000000000000000EF +:1001100000000010000001360000EA600000000549 +:1001200000000000000000000000000000000008C7 +:1001300000000000000000000000000000000000BF +:1001400000000000000000000000000000000000AF +:10015000000000000000000000000000000000009F +:10016000000000020000000000000000000000008D +:10017000000000000000000000000000000000007F +:10018000000000000000000000000010000000005F +:10019000000000000000000000000000000000005F +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000000000000000000000000000000002F +:1001D000000000000000000000000000000000001F +:1001E0000000000010000003000000000000000DEF +:1001F0000000000D3C020800244256083C030800A1 +:1002000024635754AC4000000043202B1480FFFDB2 +:10021000244200043C1D080037BD9FFC03A0F021D0 +:100220003C100800261001183C1C0800279C5608AA +:100230000E000256000000000000000D27BDFFB4B4 +:10024000AFA10000AFA20004AFA30008AFA4000C50 +:10025000AFA50010AFA60014AFA70018AFA8001CF0 +:10026000AFA90020AFAA0024AFAB0028AFAC002C90 +:10027000AFAD0030AFAE0034AFAF0038AFB8003C28 +:10028000AFB90040AFBC0044AFBF00480E001544FA +:10029000000000008FBF00488FBC00448FB90040B1 +:1002A0008FB8003C8FAF00388FAE00348FAD003078 +:1002B0008FAC002C8FAB00288FAA00248FA90020C0 +:1002C0008FA8001C8FA700188FA600148FA5001000 +:1002D0008FA4000C8FA300088FA200048FA1000040 +:1002E00027BD004C3C1B60108F7A5030377B502864 +:1002F00003400008AF7A00008F82002427BDFFE092 +:10030000AFB00010AFBF0018AFB100148C42000CAA +:100310003C1080008E110100104000348FBF001887 +:100320000E000D84000000008F85002024047FFF54 +:100330000091202BACB100008E030104960201084D +:1003400000031C003042FFFF00621825ACA300042C +:100350009202010A96030114304200FF3063FFFF4E +:100360000002140000431025ACA200089603010C03 +:100370009602010E00031C003042FFFF00621825A8 +:10038000ACA3000C960301109602011200031C009E +:100390003042FFFF00621825ACA300108E02011846 +:1003A000ACA200148E02011CACA20018148000083C +:1003B0008F820024978200003C0420050044182509 +:1003C00024420001ACA3001C0A0000C6A782000062 +:1003D0003C0340189442001E00431025ACA2001CB0 +:1003E0000E000DB8240400018FBF00188FB1001457 +:1003F0008FB000100000102103E0000827BD00208E +:100400003C0780008CE202B834E50100044100089A +:10041000240300013C0208008C42006024420001D9 +:100420003C010800AC22006003E0000800601021DD +:100430003C0208008C42005C8CA4002094A30016AF +:100440008CA6000494A5000E24420001ACE40280B6 +:100450002463FFFC3C010800AC22005C3C0210005D +:10046000A4E30284A4E5028600001821ACE6028819 +:10047000ACE202B803E000080060102127BDFFE0F5 +:100480003C028000AFB0001034420100AFBF001C3E +:10049000AFB20018AFB100148C43000094450008BF +:1004A0002462FE002C42038110400003000381C23D +:1004B0000A00010226100004240201001462000553 +:1004C0003C1180003C02800890420004305000FF44 +:1004D0003C11800036320100964300143202000FB6 +:1004E00000021500004310253C0308008C63004403 +:1004F00030A40004AE220080246300013C01080007 +:10050000AC2300441080000730A200028FBF001C03 +:100510008FB200188FB100148FB000100A0000CE07 +:1005200027BD00201040002D0000182130A20080BF +:1005300010400005362200708E44001C0E000C672F +:10054000240500A0362200708C4400008F82000C2D +:10055000008210232C43012C10600004AF82001095 +:10056000240300010A000145AF84000C8E42000400 +:100570003C036020AF84000CAC6200143C02080015 +:100580008C42005850400015000018218C62000475 +:10059000240301FE304203FF144300100000182121 +:1005A0002E020004104000032E0200080A00014041 +:1005B0000000802114400003000000000A000140F8 +:1005C0002610FFF90000000D2402000202021004B0 +:1005D0003C036000AC626914000018218FBF001C4E +:1005E0008FB200188FB100148FB00010006010217E +:1005F00003E0000827BD00203C0480008C8301003C +:1006000024020100506200033C0280080000000D3B +:100610003C02800890430004000010213063000F6A +:1006200000031D0003E00008AC8300800004188074 +:100630002782FF9C00621821000410C00044102390 +:100640008C640000000210C03C030800246356E4E0 +:10065000004310213C038000AC64009003E00008DC +:10066000AF8200243C0208008C42011410400019A3 +:100670003084400030A2007F000231C03C02020002 +:100680001080001400A218253C026020AC43001426 +:100690003C0408008C8456B83C0308008C630110AD +:1006A0003C02800024050900AC4500200086202182 +:1006B000246300013C028008AC4400643C01080053 +:1006C000AC2301103C010800AC2456B803E000083C +:1006D000000000003C02602003E00008AC4500146C +:1006E00003E000080000102103E0000800001021D2 +:1006F00030A2000810400008240201003C0208005B +:100700008C42010C244200013C010800AC22010C87 +:1007100003E0000800000000148200080000000050 +:100720003C0208008C4200FC244200013C0108000D +:10073000AC2200FC0A0001A330A200203C02080009 +:100740008C420084244200013C010800AC22008459 +:1007500030A200201040000830A200103C02080027 +:100760008C420108244200013C010800AC2201082F +:1007700003E0000800000000104000080000000036 +:100780003C0208008C420104244200013C010800A4 +:10079000AC22010403E00008000000003C02080055 +:1007A0008C420100244200013C010800AC220100FF +:1007B00003E000080000000027BDFFE0AFB1001417 +:1007C0003C118000AFB20018AFBF001CAFB00010EA +:1007D0003632010096500008320200041040000733 +:1007E000320300028FBF001C8FB200188FB10014BB +:1007F0008FB000100A0000CE27BD00201060000B53 +:10080000020028218E2401000E00018A0000000051 +:100810003202008010400003240500A10E000C6786 +:100820008E44001C0A0001E3240200018E2301040F +:100830008F82000810430006020028218E24010048 +:100840000E00018A000000008E220104AF82000821 +:10085000000010218FBF001C8FB200188FB1001450 +:100860008FB0001003E0000827BD00202C82000498 +:1008700014400002000018212483FFFD240200021E +:10088000006210043C03600003E00008AC626914DD +:1008900027BDFFE0AFBF001CAFB20018AFB100141E +:1008A000AFB000103C048000948201083043700017 +:1008B000240220001062000A2862200154400052E5 +:1008C0008FBF001C24024000106200482402600018 +:1008D0001062004A8FBF001C0A0002518FB200183C +:1008E00034820100904300098C5000189451000C90 +:1008F000240200091062001C0000902128620009F7 +:10090000144000218F8200242402000A5062001249 +:10091000323100FF2402000B1062000F00000000C3 +:100920002402000C146200188F8200243C0208008C +:100930008C4256B824030900AC83002000501021DB +:100940003C038008AC6200643C010800AC2256B84D +:100950000A0002508FBF001C0E0001E900102602A1 +:100960000A0002308F8200240E0001E900102602E6 +:100970003C0380089462001A8C72000C3042FFFF26 +:10098000020280258F8200248C42000C5040001E01 +:100990008FBF001C0E000D84000000003C02800090 +:1009A00034420100944300088F82002400031C009D +:1009B0009444001E8F82002000641825AC50000073 +:1009C00024040001AC510004AC520008AC40000CFF +:1009D000AC400010AC400014AC4000180E000DB844 +:1009E000AC43001C0A0002508FBF001C0E000440E4 +:1009F000000000000A0002508FBF001C0E000C9F78 +:100A0000000000008FBF001C8FB200188FB10014CF +:100A10008FB000100000102103E0000827BD002067 +:100A200027BDFFD8AFB400203C036010AFBF002447 +:100A3000AFB3001CAFB20018AFB10014AFB00010DC +:100A40008C6450002402FF7F3C1408002694563822 +:100A5000008220243484380CAC6450003C028000B6 +:100A6000240300370E0014B0AC4300083C07080014 +:100A700024E70618028010212404001D2484FFFFAF +:100A8000AC4700000481FFFD244200043C02080042 +:100A9000244207C83C010800AC2256403C02080032 +:100AA000244202303C030800246306203C04080072 +:100AB000248403B43C05080024A506F03C06080085 +:100AC00024C62C9C3C010800AC2256803C02080045 +:100AD000244205303C010800AC2756843C01080044 +:100AE000AC2656943C010800AC23569C3C010800FF +:100AF000AC2456A03C010800AC2556A43C010800DB +:100B0000AC2256A83C010800AC23563C3C0108002E +:100B1000AC2456443C010800AC2056603C0108005F +:100B2000AC2556643C010800AC2056703C0108001E +:100B3000AC27567C3C010800AC2656903C010800CE +:100B4000AC2356980E00056E00000000AF80000C2C +:100B50003C0280008C5300008F8300043C0208009C +:100B60008C420020106200213262000700008821C0 +:100B70002792FF9C3C100800261056E43C02080017 +:100B80008C42002024050001022518040043202483 +:100B90008F820004004310245044000C26310001D1 +:100BA00010800008AF9000248E4300003C028000BB +:100BB000AC4300900E000D4BAE05000C0A0002C1C4 +:100BC00026310001AE00000C263100012E22000269 +:100BD000261000381440FFE9265200043C020800A9 +:100BE0008C420020AF820004326200071040FFD91F +:100BF0003C028000326200011040002D326200028F +:100C00003C0580008CA2010000002021ACA2002045 +:100C10008CA301042C42078110400008ACA300A85B +:100C200094A2010824032000304270001443000302 +:100C30003C02800890420005304400FF0E0001593C +:100C4000000000003C0280009042010B304300FF96 +:100C50002C62001E54400004000310800E00018628 +:100C60000A0002EC00000000005410218C42000039 +:100C70000040F80900000000104000043C02800021 +:100C80008C4301043C026020AC4300143C02080089 +:100C90008C4200343C0440003C03800024420001AC +:100CA000AC6401383C010800AC220034326200021E +:100CB00010400010326200043C1080008E0201409F +:100CC000000020210E000159AE0200200E00038317 +:100CD000000000003C024000AE0201783C02080027 +:100CE0008C420038244200013C010800AC2200384C +:100CF000326200041040FF973C0280003C108000EC +:100D00008E020180000020210E000159AE02002059 +:100D10008E03018024020F00546200073C02800809 +:100D20008E0201883C0300E03042FFFF00431025A3 +:100D30000A000328AE020080344200809042000086 +:100D400024030050304200FF14430007000000005D +:100D50000E000362000000001440000300000000C9 +:100D60000E000971000000003C0208008C42003CAB +:100D70003C0440003C03800024420001AC6401B804 +:100D80003C010800AC22003C0A0002A33C028000A7 +:100D90003C02900034420001008220253C02800089 +:100DA000AC4400203C0380008C6200200440FFFE25 +:100DB0000000000003E00008000000003C0280008A +:100DC000344300010083202503E00008AC440020E8 +:100DD00027BDFFE0AFB10014AFB000100080882144 +:100DE000AFBF00180E00033230B000FF8F83FF94B6 +:100DF000022020219062002502028025A07000259B +:100E00008C7000183C0280000E00033D020280241A +:100E10001600000B8FBF00183C0480008C8201F884 +:100E20000440FFFE348201C024030002AC510000E4 +:100E3000A04300043C021000AC8201F88FBF0018F0 +:100E40008FB100148FB0001003E0000827BD002010 +:100E500027BDFFE83C028000AFBF00103442018094 +:100E6000944300048C4400083063020010600005C5 +:100E7000000028210E00100C000000000A0003787A +:100E8000240500013C02FF000480000700821824B2 +:100E90003C02040014620004240500018F82FF94C8 +:100EA00090420008240500018FBF001000A010210F +:100EB00003E0000827BD00188F82FF982405000179 +:100EC000A040001A3C028000344201400A00034264 +:100ED0008C4400008F85FF9427BDFFE0AFBF001C4E +:100EE000AFB20018AFB10014AFB0001090A2000074 +:100EF000304400FF38830020388200300003182B74 +:100F00000002102B0062182410600003240200501D +:100F1000148200A88FBF001C90A20005304200017F +:100F2000104000A48FBF001C3C02800034420140EE +:100F3000904200082443FFFF2C6200051040009EF1 +:100F40008FB20018000310803C030800246355ACE6 +:100F5000004310218C420000004000080000000007 +:100F60003C028000345101400E0003328E24000008 +:100F70008F92FF948E2200048E50000C1602000205 +:100F800024020001AE42000C0E00033D8E2400003E +:100F90008E220004145000068FBF001C8FB2001870 +:100FA0008FB100148FB000100A000F7827BD002009 +:100FB0008E42000C0A000419000000003C0480006E +:100FC0003482014094A300108C4200043063FFFF80 +:100FD0001443001C0000000024020001A4A2001021 +:100FE0008C8202380441000F3C0380003C02003F29 +:100FF0003448F0003C0760003C06FFC08CE22BBC8C +:1010000000461824004810240002130200031D8229 +:10101000106200583C0280008C8202380440FFF7C6 +:101020003C038000346201408C44000034620200C2 +:10103000AC4400003C021000AC6202380A00043BE1 +:101040008FBF001C94A200100A00041900000000C9 +:10105000240200201482000F3C0280003C03800028 +:1010600094A20012346301408C6300043042FFFFFD +:10107000146200050000000024020001A4A2001276 +:101080000A0004028FBF001C94A200120A00041977 +:1010900000000000345101400E0003328E24000095 +:1010A0008F92FF948E230004964200123050FFFF6F +:1010B0001603000224020001A64200120E00033DA6 +:1010C0008E2400008E220004160200068FBF001C32 +:1010D0008FB200188FB100148FB000100A00037C8B +:1010E00027BD0020964200120A00041900000000EB +:1010F0003C03800094A20014346301408C6300041C +:101100003042FFFF14620008240200018FBF001C60 +:101110008FB200188FB100148FB00010A4A2001479 +:101120000A00146327BD002094A20014144000217B +:101130008FBF001C0A000435000000003C03800043 +:1011400094A20016346301408C6300043042FFFF18 +:101150001462000D240200018FBF001C8FB2001822 +:101160008FB100148FB00010A4A200160A000B1457 +:1011700027BD00209442007824420004A4A200105D +:101180000A00043B8FBF001C94A200162403000138 +:101190003042FFFF144300078FBF001C3C020800D1 +:1011A0008C420070244200013C010800AC22007017 +:1011B0008FBF001C8FB200188FB100148FB00010C9 +:1011C00003E0000827BD002027BDFFD8AFB20018FC +:1011D0008F92FF94AFB10014AFBF0020AFB3001CDB +:1011E000AFB000103C028000345101008C5001006F +:1011F0009242000092230009304400FF2402001FA5 +:10120000106200AB28620020104000192402003850 +:101210002862000A1040000D2402000B286200081A +:101220001040002E8F820024046001042862000216 +:101230001440002A8F820024240200061062002637 +:101240008FBF00200A00055F8FB3001C1062006092 +:101250002862000B144000FA8FBF00202402000E09 +:10126000106200788F8200240A00055F8FB3001C93 +:10127000106200D2286200391040000A2402008067 +:1012800024020036106200E528620037104000C3D7 +:1012900024020035106200D98FBF00200A00055FCC +:1012A0008FB3001C1062002D2862008110400006E0 +:1012B000240200C824020039106200C98FBF002038 +:1012C0000A00055F8FB3001C106200A28FBF0020D0 +:1012D0000A00055F8FB3001C8F8200248C42000C33 +:1012E000104000D78FBF00200E000D8400000000CA +:1012F0003C038000346301008C6200008F85002075 +:10130000946700089466000CACA200008C64000492 +:101310008F82002400063400ACA400049448001E10 +:101320008C62001800073C0000E83825ACA20008D9 +:101330008C62001C24040001ACA2000C9062000A24 +:1013400000C23025ACA60010ACA00014ACA0001860 +:10135000ACA7001C0A00051D8FBF00208F8200244F +:101360008C42000C104000B68FBF00200E000D8490 +:10137000000000008F820024962400089625000CAF +:101380009443001E000422029626000E8F82002045 +:10139000000426000083202500052C003C0300806B +:1013A00000A6282500832025AC400000AC400004A6 +:1013B000AC400008AC40000CAC450010AC40001440 +:1013C000AC400018AC44001C0A00051C24040001B9 +:1013D0009622000C14400018000000009242000504 +:1013E0003042001014400014000000000E000332D0 +:1013F0000200202192420005020020213442001008 +:101400000E00033DA242000592420000240300208A +:10141000304200FF10430089020020218FBF0020CE +:101420008FB3001C8FB200188FB100148FB0001062 +:101430000A00107527BD00280000000D0A00055E97 +:101440008FBF00208C42000C1040007D8FBF002019 +:101450000E000D84000000008E2200048F84002006 +:101460009623000CAC8200003C0280089445002CBE +:101470008F82002400031C0030A5FFFF9446001E4D +:101480003C02400E0065182500C23025AC830004E4 +:10149000AC800008AC80000CAC800010AC80001464 +:1014A000AC800018AC86001C0A00051C2404000156 +:1014B0000E000332020020218F93FF9802002021AA +:1014C0000E00033DA660000C020020210E00034226 +:1014D000240500018F8200248C42000C104000582B +:1014E0008FBF00200E000D84000000009622000C2B +:1014F0008F83002000021400AC700000AC62000476 +:10150000AC6000088E4400388F820024AC64000C6C +:101510008E46003C9445001E3C02401FAC66001005 +:1015200000A228258E62000424040001AC6200148D +:10153000AC600018AC65001C8FBF00208FB3001C8E +:101540008FB200188FB100148FB000100A000DB8D0 +:1015500027BD0028240200201082003A8FB3001C0F +:101560000E000F5E00000000104000358FBF00200D +:101570003C0480008C8201F80440FFFE348201C0EC +:1015800024030002AC500000A04300043C02100001 +:10159000AC8201F80A00055E8FBF00200200202106 +:1015A0008FBF00208FB3001C8FB200188FB10014C2 +:1015B0008FB000100A000EA727BD00289625000C4A +:1015C000020020218FBF00208FB3001C8FB20018B3 +:1015D0008FB100148FB000100A000ECC27BD002878 +:1015E000020020218FB3001C8FB200188FB10014AD +:1015F0008FB000100A000EF727BD00289225000DBD +:10160000020020218FB3001C8FB200188FB100148C +:101610008FB000100A000F4827BD002802002021CB +:101620008FBF00208FB3001C8FB200188FB1001441 +:101630008FB000100A000F1F27BD00288FBF0020A9 +:101640008FB3001C8FB200188FB100148FB0001040 +:1016500003E0000827BD00283C0580008CA202782A +:101660000440FFFE34A2024024030002AC44000008 +:10167000A04300043C02100003E00008ACA2027882 +:10168000A380001803E00008A38000193C03800039 +:101690008C6202780440FFFE8F82001CAC62024024 +:1016A00024020002A06202443C02100003E0000891 +:1016B000AC6202783C02600003E000088C425404F3 +:1016C0009083003024020005008040213063003FF9 +:1016D0000000482114620005000050219082004C57 +:1016E0009483004E304900FF306AFFFFAD00000CCC +:1016F000AD000010AD000024950200148D05001C03 +:101700008D0400183042FFFF004910230002110031 +:10171000000237C3004038210086202300A2102B8E +:101720000082202300A72823AD05001CAD0400186B +:10173000A5090014A5090020A50A001603E0000869 +:10174000A50A002203E000080000000027BDFFD822 +:10175000AFB200183C128008AFB40020AFB3001C39 +:10176000AFB10014AFBF0024AFB00010365101007C +:101770003C0260008C4254049222000C3C1408008D +:10178000929400F7304300FF2402000110620032FF +:101790000080982124020002146200353650008037 +:1017A0000E00143D000000009202004C2403FF8054 +:1017B0003C0480003042007F000211C024420240FD +:1017C0000262102100431824AC8300949245000863 +:1017D0009204004C3042007F3C03800614850007D1 +:1017E000004380212402FFFFA22200112402FFFFF8 +:1017F000A62200120A0005D22402FFFF9602002052 +:10180000A222001196020022A62200128E020024BB +:101810003C048008AE2200143485008090A2004C65 +:1018200034830100A06200108CA2003CAC6200185E +:101830008C820068AC6200F48C820064AC6200F0C0 +:101840008C82006CAC6200F824020001A0A2006847 +:101850000A0005EE3C0480080E001456000000004B +:1018600036420080A04000680A0005EE3C04800873 +:10187000A2000068A20000690A0006293C02800854 +:10188000348300808C62003834850100AC62006CC7 +:1018900024020001A062006990A200D59083000894 +:1018A000305100FF3072007F12320019001111C058 +:1018B00024420240026210212403FF8000431824C6 +:1018C0003C048000AC8300943042007F3C038006DF +:1018D000004380218E02000C1040000D02002021E8 +:1018E0000E00057E0000000026220001305100FF9E +:1018F0009203003C023410260002102B0002102339 +:101900003063007F022288240A0005F8A203003C0D +:101910003C088008350401008C8200E03507008017 +:10192000ACE2003C8C8200E0AD02000090E5004C8F +:10193000908600D590E3004C908400D52402FF806F +:1019400000A228243063007F308400FF00A62825F1 +:101950000064182A1060000230A500FF38A500803E +:10196000A0E5004CA10500093C0280089043000E50 +:10197000344400803C058000A043000A8C8300189A +:101980003C027FFF3442FFFF00621824AC83001842 +:101990008CA201F80440FFFE00000000ACB301C0BF +:1019A0008FBF00248FB400208FB3001C8FB20018AB +:1019B0008FB100148FB0001024020002A0A201C455 +:1019C00027BD00283C02100003E00008ACA201F88B +:1019D00090A2000024420001A0A200003C030800E5 +:1019E0008C6300F4304200FF144300020080302179 +:1019F000A0A0000090A200008F84001C000211C073 +:101A00002442024024830040008220212402FF80DF +:101A1000008220243063007F3C02800A006218218B +:101A20003C028000AC44002403E00008ACC300008A +:101A300094820006908300058C85000C8C86001033 +:101A40008C8700188C88001C8C8400203C010800C6 +:101A5000A42256C63C010800A02356C53C0108003C +:101A6000AC2556CC3C010800AC2656D03C01080001 +:101A7000AC2756D83C010800AC2856DC3C010800D5 +:101A8000AC2456E003E00008000000003C0280089F +:101A9000344201008C4400343C038000346504006F +:101AA000AC6400388C420038AF850028AC62003C42 +:101AB0003C020005AC6200300000000000000000A5 +:101AC00003E00008000000003C020006308400FF34 +:101AD000008220253C028000AC4400300000000061 +:101AE00000000000000000003C0380008C62000049 +:101AF000304200101040FFFD3462040003E0000893 +:101B0000AF82002894C200003C080800950800CA73 +:101B100030E7FFFF0080482101021021A4C200002D +:101B200094C200003042FFFF00E2102B544000013D +:101B3000A4C7000094A200003C0308008C6300CC02 +:101B400024420001A4A2000094A200003042FFFF42 +:101B5000144300073C0280080107102BA4A00000DA +:101B60005440000101003821A4C700003C02800855 +:101B7000344601008CC3002894A200003C0480007D +:101B80003042FFFE000210C000621021AC82003C17 +:101B90008C82003C006218231860000400000000E2 +:101BA0008CC200240A0006BA244200018CC2002420 +:101BB000AC8200383C020050344200103C038000EC +:101BC000AC620030000000000000000000000000D7 +:101BD0008C620000304200201040FFFD0000000039 +:101BE00094A200003C04800030420001000210C0BA +:101BF000004410218C430400AD2300008C420404F7 +:101C0000AD2200043C02002003E00008AC8200305A +:101C100027BDFFE0AFB20018AFB10014AFB00010A5 +:101C2000AFBF001C94C2000000C080213C1208001D +:101C3000965200C624420001A6020000960300004E +:101C400094E2000000E03021144300058FB1003021 +:101C50000E00068F024038210A0006F10000000045 +:101C60008C8300048C82000424420040046100073D +:101C7000AC8200048C8200040440000400000000D8 +:101C80008C82000024420001AC8200009602000019 +:101C90003042FFFF50520001A600000096220000D3 +:101CA00024420001A62200003C02800834420100C8 +:101CB000962300009442003C144300048FBF001C94 +:101CC00024020001A62200008FBF001C8FB2001862 +:101CD0008FB100148FB0001003E0000827BD002072 +:101CE00027BDFFE03C028008AFBF0018344201006E +:101CF0008C4800343C03800034690400AC68003830 +:101D00008C42003830E700FFAF890028AC62003C0D +:101D10003C020005AC620030000000000000000042 +:101D200000000000000000000000000000000000B3 +:101D30008C82000C8C82000C97830016AD22000070 +:101D40008C82001000604021AD2200048C820018BB +:101D5000AD2200088C82001CAD22000C8CA2001465 +:101D6000AD2200108C820020AD220014908200056C +:101D7000304200FF00021200AD2200188CA20018B1 +:101D8000AD22001C8CA2000CAD2200208CA2001001 +:101D9000AD2200248CA2001CAD2200288CA20020C1 +:101DA000AD22002C3402FFFFAD260030AD20003400 +:101DB000506200013408FFFFAD28003850E00011E8 +:101DC0003C0280083C048008348401009482005066 +:101DD0003042FFFFAD22003C9483004494850044D0 +:101DE000240200013063FFFF000318C200641821C1 +:101DF0009064006430A5000700A210040A00075C8C +:101E00000044102534420100AD20003C94430044BE +:101E1000944400443063FFFF000318C2006218219D +:101E200030840007906500642402000100821004E1 +:101E30000002102700451024A0620064000000008A +:101E400000000000000000003C0200063442004098 +:101E50003C038000AC620030000000000000000085 +:101E6000000000008C620000304200101040FFFDB6 +:101E70003C06800834C201503463040034C7014A70 +:101E800034C4013434C5014034C60144AFA200104B +:101E90000E0006D2AF8300288FBF001803E00008B1 +:101EA00027BD00208F8300143C0608008CC600E884 +:101EB0008F82001C30633FFF000319800046102111 +:101EC000004310212403FF80004318243C068000B7 +:101ED000ACC300283042007F3C03800C004330211B +:101EE00090C2000D30A500FF0000382134420010E0 +:101EF000A0C2000D8F8900143C028008344201000A +:101F00009443004400091382304800032402000176 +:101F1000A4C3000E1102000B2902000210400005AC +:101F2000240200021100000C240300010A0007A48F +:101F30000000182111020006000000000A0007A49A +:101F4000000018218CC2002C0A0007A424430001C1 +:101F50008CC20014244300018CC200180043102BD3 +:101F60005040000A240700012402002714A20003A5 +:101F70003C0380080A0007B1240700013463010014 +:101F80009462004C24420001A462004C00091382B8 +:101F9000304300032C620002104000090080282119 +:101FA000146000040000000094C200340A0007C15D +:101FB0003046FFFF8CC600380A0007C10080282188 +:101FC000000030213C040800248456C00A000706A3 +:101FD0000000000027BDFF90AFB60068AFB50064F9 +:101FE000AFB40060AFB3005CAFB20058AFB1005403 +:101FF000AFBF006CAFB000508C9000000080B021EB +:102000003C0208008C4200E8960400328F83001CDA +:102010002414FF8030843FFF0062182100042180D7 +:1020200000641821007410243C13800000A090214B +:1020300090A50000AE620028920400323C02800CA1 +:102040003063007F00628821308400C02402004099 +:10205000148200320000A8218E3500388E2200182C +:102060001440000224020001AE2200189202003C3B +:10207000304200201440000E8F83001C000511C068 +:102080002442024000621821306400783C02008043 +:102090000082202500741824AE630800AE64081086 +:1020A0008E2200188E03000800431021AE22001873 +:1020B0008E22002C8E230018244200010062182B6F +:1020C0001060004300000000924200002442000122 +:1020D000A24200003C0308008C6300F4304200FF81 +:1020E00050430001A2400000924200008F84001C77 +:1020F000000211C024420240248300403063007F6C +:10210000008220213C02800A0094202400621821D1 +:10211000AE6400240A0008D2AEC30000920300326D +:102120002402FFC000431024304200FF1440000589 +:1021300024020001AE220018962200340A00084250 +:102140003055FFFF8E22001424420001AE220018F9 +:102150009202003000021600000216030441001C27 +:10216000000000009602003227A400100080282101 +:10217000A7A20016960200320000302124070001B9 +:102180003042FFFFAF8200140E000706AFA0001C14 +:10219000960200328F83001C3C0408008C8400E807 +:1021A00030423FFF000211800064182100621821B4 +:1021B00000741024AE62002C3063007F3C02800E5D +:1021C000006218219062000D3042007FA062000D75 +:1021D0009222000D304200105040007892420000E0 +:1021E0003C028008344401009482004C8EC30000FD +:1021F0003C130800967300C62442FFFFA482004CE3 +:10220000946200329623000E3054FFFF3070FFFFBF +:102210003C0308008C6300D000701807A7A30038A7 +:102220009482003E3063FFFF3042FFFF14620007DC +:10223000000000008C8200303C038000244200300B +:10224000AC62003C0A00086A8C82002C9482004038 +:102250003042FFFF5462000927A400408C820038FE +:102260003C03800024420030AC62003C8C8200348D +:10227000AC6200380A0008793C03800027A50038CA +:1022800027A60048026038210E00068FA7A000484C +:102290008FA300403C02800024630030AC43003830 +:1022A0008FA30044AC43003C3C0380003C0200058B +:1022B000AC6200303C028008344401009482004249 +:1022C000346304003042FFFF0202102B1440000769 +:1022D000AF8300289482004E9483004202021021B2 +:1022E000004310230A00088F3043FFFF9483004E01 +:1022F00094820042026318210050102300621823C8 +:102300003063FFFF3C028008344401009482003CAB +:102310003042FFFF14430003000000000A00089F42 +:10232000240300019482003C3042FFFF0062102B26 +:10233000144000058F8200289482003C0062102324 +:102340003043FFFF8F820028AC550000AC400004F2 +:10235000AC540008AC43000C3C02000634420010B0 +:102360003C038000AC620030000000000000000070 +:10237000000000008C620000304200101040FFFDA1 +:102380003C04800834840100001018C20064182145 +:102390009065006432020007240600010046100424 +:1023A00000451025A0620064948300429622000E2E +:1023B00050430001A386001892420000244200010D +:1023C000A24200003C0308008C6300F4304200FF8E +:1023D00050430001A2400000924200008F84001C84 +:1023E000000211C0244202402483004000822021C8 +:1023F0002402FF80008220243063007F3C02800A98 +:10240000006218213C028000AC440024AEC30000EE +:102410008FBF006C8FB600688FB500648FB400600A +:102420008FB3005C8FB200588FB100548FB0005052 +:1024300003E0000827BD007027BDFFD8AFB3001C24 +:10244000AFB20018AFB10014AFB00010AFBF0020A2 +:102450000080982100E0802130B1FFFF0E000D8444 +:1024600030D200FF0000000000000000000000006B +:102470008F8200208F830024AC510000AC520004F6 +:10248000AC530008AC40000CAC400010AC40001451 +:10249000AC4000189463001E02038025AC50001C61 +:1024A0000000000000000000000000002404000103 +:1024B0008FBF00208FB3001C8FB200188FB10014A3 +:1024C0008FB000100A000DB827BD002830A5FFFF0F +:1024D0000A0008DC30C600FF3C02800834430100DB +:1024E0009462000E3C080800950800C63046FFFFC5 +:1024F00014C000043402FFFF946500EA0A000929B1 +:102500008F84001C10C20027000000009462004E5F +:102510009464003C3045FFFF00A6102300A6182B52 +:102520003087FFFF106000043044FFFF00C5102318 +:1025300000E210233044FFFF0088102B1040000EF3 +:1025400000E810233C028008344401002403000109 +:1025500034420080A44300162402FFFFA482000E30 +:10256000948500EA8F84001C0000302130A5FFFF15 +:102570000A0009013C0760200044102A10400009AD +:102580003C0280083443008094620016304200010F +:10259000104000043C0280009442007E244200145B +:1025A000A462001603E000080000000027BDFFE061 +:1025B0003C028008AFBF001CAFB0001834420100DD +:1025C000944300429442004C104000193068FFFFD1 +:1025D0009383001824020001146200298FBF001C9D +:1025E0003C06800834D00100000810C200501021C1 +:1025F000904200643103000734C70148304200FFB5 +:10260000006210073042000134C9014E34C4012C6D +:1026100034C5013E1040001634C601420E0006D2F9 +:10262000AFA90010960200420A0009463048FFFF99 +:102630003C028008344401009483004494820042A8 +:102640001043000F8FBF001C94820044A4820042FC +:1026500094820050A482004E8C820038AC820030FC +:1026600094820040A482003E9482004AA4820048E2 +:102670008FBF001C8FB000180A00090427BD00207E +:102680008FB0001803E0000827BD002027BDFFA081 +:10269000AFB1004C3C118000AFBF0058AFB3005445 +:1026A000AFB20050AFB000483626018890C2000398 +:1026B0003044007FA3A400108E32018090C200003D +:1026C0003043007F240200031062003BAF92001CE5 +:1026D00028620004104000062402000424020002C4 +:1026E000106200098FBF00580A000B0F8FB300540F +:1026F0001062004D240200051062014E8FBF005889 +:102700000A000B0F8FB30054000411C002421021C5 +:102710002404FF8024420240004410242643004049 +:10272000AE2200243063007F3C02800A0062182140 +:102730009062003CAFA3003C00441025A062003C26 +:102740008FA3003C9062003C304200401040016C7E +:102750008FBF00583C108008A3800018361001007D +:102760008E0200E08C63003427A4003C27A50010F3 +:10277000004310210E0007C3AE0200E093A2001038 +:102780003C038000A20200D58C6202780440FFFE68 +:102790008F82001CAC62024024020002A06202444C +:1027A0003C021000AC6202780E0009390000000003 +:1027B0000A000B0E8FBF00583C05800890C3000133 +:1027C00090A2000B1443014E8FBF005834A4008028 +:1027D0008C8200189082004C90A200083C0260009D +:1027E0008C4254048C8300183C027FFF3442FFFF6C +:1027F000006218243C0208008C4200B4AC8300182C +:102800003C038000244200013C010800AC2200B4DB +:102810008C6201F80440FFFE8F82001CAC6201C094 +:102820000A000AD6240200023C10800890C300016E +:102830009202000B144301328FBF005827A40018E6 +:1028400036050110240600033C0260008C4254044B +:102850000E000E470000000027A40028360501F0F6 +:102860000E000E47240600038FA200283603010045 +:10287000AE0200648FA2002CAE0200688FA200306E +:10288000AE02006C93A40018906300D52402FF8070 +:102890000082102400431025304900FF3084007F5F +:1028A0003122007F0082102A544000013929008023 +:1028B000000411C0244202402403FF800242102180 +:1028C00000431024AE220094264200403042007F94 +:1028D0003C038006004340218FA3001C2402FFFF1D +:1028E000AFA800403C130800927300F71062003359 +:1028F00093A2001995030014304400FF3063FFFFDA +:102900000064182B106000100000000095040014F3 +:102910008D07001C8D0600183084FFFF0044202323 +:102920000004210000E438210000102100E4202BE5 +:1029300000C2302100C43021AD07001CAD060018D4 +:102940000A000A2F93A20019950400148D07001C99 +:102950008D0600183084FFFF008220230004210030 +:10296000000010210080182100C2302300E4202B39 +:1029700000C4302300E33823AD07001CAD06001867 +:1029800093A200198FA30040A462001497A2001A1A +:10299000A46200168FA2001CAC6200108FA2001C63 +:1029A000AC62000C93A20019A462002097A2001A46 +:1029B000A46200228FA2001CAC6200243C048008A8 +:1029C000348300808C6200388FA20020012088218F +:1029D000AC62003C8FA20020AC82000093A20018E1 +:1029E000A062004C93A20018A0820009A0600068B9 +:1029F00093A20018105100512407FF803229007F54 +:102A0000000911C024420240024210213046007FDA +:102A10003C03800000471024AC6200943C02800616 +:102A200000C2302190C2003CAFA60040000020212F +:102A300000471025A0C2003C8FA80040950200026C +:102A4000950300148D07001C3042FFFF3063FFFF29 +:102A50008D060018004310230002110000E2382107 +:102A600000E2102B00C4302100C23021AD07001C51 +:102A7000AD06001895020002A5020014A50000167C +:102A80008D020008AD0200108D020008AD02000C9E +:102A900095020002A5020020A50000228D02000878 +:102AA000AD0200249102003C304200401040001A68 +:102AB000262200013C108008A3A90038A38000183A +:102AC000361001008E0200E08D03003427A4004080 +:102AD00027A50038004310210E0007C3AE0200E016 +:102AE00093A200383C038000A20200D58C620278D9 +:102AF0000440FFFE8F82001CAC62024024020002F0 +:102B0000A06202443C021000AC6202780E00093957 +:102B100000000000262200013043007F14730004EF +:102B2000004020212403FF8002231024004320269C +:102B300093A200180A000A4B309100FF93A40018DA +:102B40008FA3001C2402FFFF1062000A308900FFDF +:102B500024820001248300013042007F14530005C9 +:102B6000306900FF2403FF800083102400431026F7 +:102B7000304900FF3C028008904200080120882173 +:102B8000305000FF123000193222007F000211C0C5 +:102B900002421021244202402403FF8000431824F3 +:102BA0003C048000AC8300943042007F3C038006EC +:102BB000004310218C43000C004020211060000BCA +:102BC000AFA200400E00057E000000002623000199 +:102BD0002405FF803062007F145300020225202468 +:102BE000008518260A000AAF307100FF3C048008F7 +:102BF000348400808C8300183C027FFF3442FFFF46 +:102C000000621824AC8300183C0380008C6201F839 +:102C10000440FFFE00000000AC7201C0240200026C +:102C2000A06201C43C021000AC6201F80A000B0E65 +:102C30008FBF00583C04800890C300019082000BB5 +:102C40001443002F8FBF0058349000809202000878 +:102C500030420040104000200000000092020008B6 +:102C60000002160000021603044100050240202164 +:102C70000E000ECC240500930A000B0E8FBF0058E7 +:102C80009202000924030018304200FF1443000D93 +:102C900002402021240500390E000E64000030217E +:102CA0000E0003328F84001C8F82FF9424030012D5 +:102CB000A04300090E00033D8F84001C0A000B0E88 +:102CC0008FBF0058240500360E000E64000030212E +:102CD0000A000B0E8FBF00580E0003320240202165 +:102CE000920200058F84001C344200200E00033D38 +:102CF000A20200050E0010758F84001C8FBF0058C3 +:102D00008FB300548FB200508FB1004C8FB0004889 +:102D100003E0000827BD00603C0280083445010044 +:102D20003C0280008C42014094A3000E0000302140 +:102D300000402021AF82001C3063FFFF3402FFFF00 +:102D4000106200063C0760202402FFFFA4A2000ED0 +:102D500094A500EA0A00090130A5FFFF03E000087E +:102D60000000000027BDFFC83C0280003C06800830 +:102D7000AFB5002CAFB1001CAFBF0030AFB400281E +:102D8000AFB30024AFB20020AFB00018345101003F +:102D900034C501008C4301008E2200148CA400E491 +:102DA0000000A821AF83001C0044102318400052EB +:102DB000A38000188E22001400005021ACA200E471 +:102DC00090C3000890A200D53073007FA3A200102A +:102DD0008CB200E08CB400E4304200FF1053003BA2 +:102DE00093A200108F83001C2407FF80000211C0F3 +:102DF0000062102124420240246300400047102456 +:102E00003063007F3C0980003C08800A006818217C +:102E1000AD2200248C62003427A4001427A50010E2 +:102E2000024280210290102304400028AFA3001426 +:102E30009062003C00E21024304200FF1440001970 +:102E4000020090219062003C34420040A062003CAD +:102E50008F86001C93A3001024C200403042007FE4 +:102E6000004828213C0208008C4200F42463000141 +:102E7000306400FF14820002A3A30010A3A000107E +:102E800093A20010AFA50014000211C0244202401A +:102E900000C2102100471024AD2200240A000B4577 +:102EA00093A200100E0007C3000000003C0280083F +:102EB00034420100AC5000E093A30010240A00014A +:102EC000A04300D50A000B4593A200102402000184 +:102ED000154200093C0380008C6202780440FFFE2A +:102EE0008F82001CAC62024024020002A0620244F5 +:102EF0003C021000AC6202789222000B2403000214 +:102F0000304200FF144300720000000096220008C7 +:102F1000304300FF24020082146200402402008437 +:102F20003C028000344901008D22000C95230006EC +:102F3000000216023063FFFF3045003F24020027E5 +:102F400010A2000FAF83001428A200281040000830 +:102F5000240200312402002110A2000924020025CD +:102F600010A20007938200190A000BBD00000000A8 +:102F700010A20007938200190A000BBD0000000098 +:102F80000E000777012020210A000C3D0000000000 +:102F90003C0380008C6202780440FFFE8F82001C9C +:102FA000AC62024024020002A06202443C02100013 +:102FB000AC6202780A000C3D000000009523000678 +:102FC000912400058D25000C8D2600108D270018FA +:102FD0008D28001C8D290020244200013C0108009E +:102FE000A42356C63C010800A02456C53C01080095 +:102FF000AC2556CC3C010800AC2656D03C0108005C +:10300000AC2756D83C010800AC2856DC3C0108002F +:10301000AC2956E00A000C3DA38200191462000A94 +:10302000240200813C02800834420100944500EAF9 +:10303000922600058F84001C30A5FFFF30C600FFDC +:103040000A000BFE3C0760211462005C00000000D7 +:103050009222000A304300FF306200201040000737 +:10306000306200403C02800834420100944500EA8E +:103070008F84001C0A000BFC24060040104000074F +:10308000000316003C02800834420100944500EA27 +:103090008F84001C0A000BFC24060041000216036A +:1030A000044100463C02800834420100944500EA95 +:1030B0008F84001C2406004230A5FFFF3C076019E6 +:1030C0000E000901000000000A000C3D0000000095 +:1030D0009222000B24040016304200FF1044000628 +:1030E0003C0680009222000B24030017304200FFB0 +:1030F000144300320000000034C5010090A2000B10 +:10310000304200FF1444000B000080218CA20020FC +:103110008CA400202403FF800043102400021140EF +:103120003084007F004410253C032000004310251C +:10313000ACC2083094A2000800021400000214037C +:10314000044200012410000194A2000830420080D3 +:103150005040001A0200A82194A20008304220002A +:10316000504000160200A8218CA300183C021C2D20 +:10317000344219ED106200110200A8213C0208003F +:103180008C4200D4104000053C0280082403000457 +:1031900034420100A04300FC3C028008344201009C +:1031A000944500EA8F84001C2406000630A5FFFF2A +:1031B0000E0009013C0760210200A8210E00093918 +:1031C000000000009222000A304200081040000473 +:1031D00002A010210E0013790000000002A01021AF +:1031E0008FBF00308FB5002C8FB400288FB3002420 +:1031F0008FB200208FB1001C8FB0001803E00008D0 +:1032000027BD00382402FF80008220243C02900069 +:1032100034420007008220253C028000AC4400209C +:103220003C0380008C6200200440FFFE0000000090 +:1032300003E00008000000003C0380002402FF803F +:10324000008220243462000700822025AC64002024 +:103250008C6200200440FFFE0000000003E0000834 +:103260000000000027BDFFD8AFB3001CAFB10014B1 +:10327000AFB00010AFBF0020AFB200183C1180000B +:103280003C0280088E32002034530100AE2400201E +:10329000966300EA000514003C074000004738250B +:1032A00000A08021000030210E0009013065FFFFE1 +:1032B000240200A1160200022402FFFFA2620009FC +:1032C000AE3200208FBF00208FB3001C8FB20018D9 +:1032D0008FB100148FB0001003E0000827BD002854 +:1032E0003C0280082403000527BDFFE834420100AA +:1032F000A04300FCAFBF00103C0280008C420100E4 +:10330000240500A1004020210E000C67AF82001CA4 +:103310003C0380008C6202780440FFFE8F82001C18 +:103320008FBF001027BD0018AC62024024020002CB +:10333000A06202443C021000AC62027803E0000884 +:103340000000000027BDFFE83C068000AFBF001072 +:1033500034C7010094E20008304400FF3883008243 +:10336000388200842C6300012C4200010062182581 +:103370001060002D24020083938200195040003B0E +:103380008FBF00103C020800904256CC8CC4010054 +:103390003C06080094C656C63045003F38A30032AC +:1033A00038A2003F2C6300012C4200010062182566 +:1033B000AF84001CAF860014A380001914600007BE +:1033C00000E020212402002014A2001200000000CE +:1033D0003402FFFF14C2000F00000000240200208E +:1033E00014A2000500E028218CE300142402FFFF52 +:1033F0005062000B8FBF00103C040800248456C0AC +:10340000000030210E000706240700010A000CD638 +:103410008FBF00100E000777000000008FBF001064 +:103420000A00093927BD001814820004240200850F +:103430008CC501040A000CE1000020211482000662 +:103440002482FF808CC50104240440008FBF00103B +:103450000A00016727BD0018304200FF2C4200021D +:1034600010400004240200228FBF00100A000B2726 +:1034700027BD0018148200048F8200248FBF001023 +:103480000A000C8627BD00188C42000C1040001E5C +:1034900000E0282190E300092402001814620003D0 +:1034A000240200160A000CFC240300081462000722 +:1034B00024020017240300123C02800834420080DA +:1034C000A04300090A000D0994A7000854620007F0 +:1034D00094A700088F82FF942404FFFE9043000508 +:1034E00000641824A043000594A7000890A6001BC0 +:1034F0008CA4000094A500068FBF001000073C00BC +:103500000A0008DC27BD00188FBF001003E0000888 +:1035100027BD00188F8500243C04800094A2002A57 +:103520008CA30034000230C02402FFF000C210243B +:1035300000621821AC83003C8CA200303C03800068 +:10354000AC8200383C02005034420010AC620030C3 +:103550000000000000000000000000008C6200007D +:10356000304200201040FFFD30C20008104000062D +:103570003C0280008C620408ACA200208C62040C27 +:103580000A000D34ACA200248C430400ACA300203C +:103590008C420404ACA200243C0300203C028000C6 +:1035A000AC4300303C0480008C8200300043102487 +:1035B0001440FFFD8F8600243C020040AC820030A6 +:1035C00094C3002A94C2002894C4002C94C5002EF1 +:1035D00024630001004410213064FFFFA4C20028CE +:1035E00014850002A4C3002AA4C0002A03E0000836 +:1035F000000000008F84002427BDFFE83C05800404 +:1036000024840010AFBF00100E000E472406000AED +:103610008F840024948200129483002E3042000F85 +:10362000244200030043180424027FFF0043102BB0 +:1036300010400002AC8300000000000D0E000D13CE +:10364000000000008F8300248FBF001027BD0018EA +:10365000946200149463001A3042000F00021500B7 +:10366000006218253C02800003E00008AC4300A083 +:103670008F8300243C028004944400069462001A64 +:103680008C650000A4640016004410233042FFFF44 +:103690000045102B03E00008384200018F8400240D +:1036A0003C0780049486001A8C85000094E2000692 +:1036B000A482001694E3000600C310233042FFFFEB +:1036C0000045102B384200011440FFF8A483001677 +:1036D00003E00008000000008F8400243C02800406 +:1036E000944200069483001A8C850000A482001680 +:1036F000006210233042FFFF0045102B38420001CA +:103700005040000D8F850024006030213C0780046C +:1037100094E20006A482001694E3000600C310237E +:103720003042FFFF0045102B384200011440FFF8E3 +:10373000A48300168F8500243C03800034620400BB +:103740008CA40020AF820020AC6400388CA200243E +:10375000AC62003C3C020005AC62003003E00008B3 +:10376000ACA000048F8400243C0300068C8200047B +:1037700000021140004310253C038000AC62003081 +:103780000000000000000000000000008C6200004B +:10379000304200101040FFFD34620400AC80000491 +:1037A00003E00008AF8200208F86002427BDFFE0E1 +:1037B000AFB10014AFB00010AFBF00188CC300044D +:1037C0008CC500248F820020309000FF94C4001A22 +:1037D00024630001244200202484000124A7002047 +:1037E000ACC30004AF820020A4C4001AACC70024FC +:1037F00004A100060000882104E2000594C2001A1A +:103800008CC2002024420001ACC2002094C2001AE5 +:1038100094C300282E040001004310262C4200010E +:10382000004410245040000594C2001A24020001F4 +:10383000ACC2000894C2001A94C300280010202BC8 +:10384000004310262C4200010044102514400007BC +:10385000000000008CC20008144000042402001084 +:103860008CC300041462000F8F8500240E000DA786 +:10387000241100018F820024944300289442001AEE +:1038800014430003000000000E000D1300000000B0 +:10389000160000048F8500240E000D840000000037 +:1038A0008F85002494A2001E94A4001C24420001D1 +:1038B0003043FFFF14640002A4A2001EA4A0001E57 +:1038C0001200000A3C02800494A2001494A3001A7F +:1038D0003042000F00021500006218253C028000F3 +:1038E000AC4300A00A000E1EACA0000894420006E3 +:1038F00094A3001A8CA40000A4A200160062102356 +:103900003042FFFF0044102B384200011040000DF0 +:1039100002201021006030213C07800494E2000660 +:10392000A4A2001694E3000600C310233042FFFF58 +:103930000044102B384200011440FFF8A4A30016E5 +:10394000022010218FBF00188FB100148FB000101B +:1039500003E0000827BD002003E00008000000008D +:103960008F82002C3C03000600021140004310250A +:103970003C038000AC62003000000000000000004A +:10398000000000008C620000304200101040FFFD7B +:1039900034620400AF82002803E00008AF80002CEE +:1039A00003E000080000102103E000080000000010 +:1039B0003084FFFF30A5FFFF0000182110800007B2 +:1039C000000000003082000110400002000420428C +:1039D000006518210A000E3D0005284003E000089C +:1039E0000060102110C0000624C6FFFF8CA200005A +:1039F00024A50004AC8200000A000E4724840004C1 +:103A000003E000080000000010A0000824A3FFFF4E +:103A1000AC86000000000000000000002402FFFF50 +:103A20002463FFFF1462FFFA2484000403E000080B +:103A3000000000003C0280083442008024030001A2 +:103A4000AC43000CA4430010A4430012A443001490 +:103A500003E00008A44300168F82002427BDFFD88E +:103A6000AFB3001CAFB20018AFB10014AFB000107C +:103A7000AFBF00208C47000C248200802409FF8007 +:103A80003C08800E3043007F008080213C0A80008B +:103A9000004920240068182130B100FF30D200FF17 +:103AA00010E000290000982126020100AD44002CFE +:103AB000004928243042007F004820219062000005 +:103AC00024030050304200FF1443000400000000B3 +:103AD000AD45002C948200EA3053FFFF0E000D84A8 +:103AE000000000008F8200248F83002000112C0032 +:103AF0009442001E001224003484000100A22825F4 +:103B00003C02400000A22825AC7000008FBF0020BE +:103B1000AC6000048FB20018AC7300088FB10014C1 +:103B2000AC60000C8FB3001CAC6400108FB00010B0 +:103B3000AC60001424040001AC60001827BD00280C +:103B40000A000DB8AC65001C8FBF00208FB3001CAD +:103B50008FB200188FB100148FB0001003E000087E +:103B600027BD00283C06800034C201009043000FAE +:103B7000240200101062000E2865001110A000073A +:103B800024020012240200082405003A10620006F4 +:103B90000000302103E0000800000000240500358B +:103BA0001462FFFC000030210A000E6400000000D7 +:103BB0008CC200748F83FF9424420FA003E000089E +:103BC000AC62000C27BDFFE8AFBF00100E0003423F +:103BD000240500013C0480088FBF0010240200016E +:103BE00034830080A462001227BD00182402000163 +:103BF00003E00008A080001A27BDFFE0AFB2001864 +:103C0000AFB10014AFB00010AFBF001C30B2FFFF67 +:103C10000E000332008088213C028008345000806E +:103C20009202000924030004304200FF1443000CF8 +:103C30003C028008124000082402000A0E000E5BBD +:103C400000000000920200052403FFFE0043102440 +:103C5000A202000524020012A20200093C02800810 +:103C600034420080022020210E00033DA0400027A6 +:103C700016400003022020210E000EBF00000000AD +:103C800002202021324600FF8FBF001C8FB2001897 +:103C90008FB100148FB00010240500380A000E64A4 +:103CA00027BD002027BDFFE0AFBF001CAFB200184A +:103CB000AFB10014AFB000100E00033200808021BD +:103CC0000E000E5B000000003C02800834450080BE +:103CD00090A2000924120018305100FF1232000394 +:103CE0000200202124020012A0A2000990A20005D7 +:103CF0002403FFFE004310240E00033DA0A2000594 +:103D00000200202124050020163200070000302187 +:103D10008FBF001C8FB200188FB100148FB000103D +:103D20000A00034227BD00208FBF001C8FB200187D +:103D30008FB100148FB00010240500390A000E6402 +:103D400027BD002027BDFFE83C028000AFB0001077 +:103D5000AFBF0014344201009442000C2405003629 +:103D60000080802114400012304600FF0E00033214 +:103D7000000000003C02800834420080240300124E +:103D8000A043000990430005346300100E000E5B51 +:103D9000A04300050E00033D020020210200202167 +:103DA0000E000342240500200A000F3C0000000022 +:103DB0000E000E64000000000E00033202002021FD +:103DC0003C0280089043001B2405FF9F0200202135 +:103DD000006518248FBF00148FB00010A043001B93 +:103DE0000A00033D27BD001827BDFFE0AFBF001844 +:103DF000AFB10014AFB0001030B100FF0E000332BD +:103E0000008080213C02800824030012344200809C +:103E10000E000E5BA04300090E00033D02002021AE +:103E200002002021022030218FBF00188FB1001422 +:103E30008FB00010240500350A000E6427BD002055 +:103E40003C0480089083000E9082000A1443000B0B +:103E5000000028218F82FF942403005024050001D4 +:103E600090420000304200FF1443000400000000B4 +:103E70009082000E24420001A082000E03E00008A0 +:103E800000A010213C0380008C6201F80440FFFE7A +:103E900024020002AC6401C0A06201C43C02100014 +:103EA00003E00008AC6201F827BDFFE0AFB20018E4 +:103EB0003C128008AFB10014AFBF001CAFB00010BF +:103EC00036510080922200092403000A304200FF8C +:103ED0001443003E000000008E4300048E22003890 +:103EE000506200808FBF001C92220000240300500B +:103EF000304200FF144300253C0280008C42014008 +:103F00008E4300043642010002202821AC43001CED +:103F10009622005C8E2300383042FFFF00021040E2 +:103F200000621821AE23001C8E4300048E2400384A +:103F30009622005C006418233042FFFF0003184300 +:103F4000000210400043102A10400006000000004C +:103F50008E4200048E230038004310230A000FAA6B +:103F6000000220439622005C3042FFFF0002204006 +:103F70003C0280083443010034420080ACA4002C91 +:103F8000A040002424020001A062000C0E000F5E7D +:103F900000000000104000538FBF001C3C02800056 +:103FA0008C4401403C0380008C6201F80440FFFE19 +:103FB00024020002AC6401C0A06201C43C021000F3 +:103FC000AC6201F80A0010078FBF001C92220009A2 +:103FD00024030010304200FF144300043C02800020 +:103FE0008C4401400A000FEE0000282192220009B3 +:103FF00024030016304200FF14430006240200147C +:10400000A22200093C0280008C4401400A001001F9 +:104010008FBF001C8E2200388E23003C00431023EB +:10402000044100308FBF001C92220027244200016F +:10403000A2220027922200272C42000414400016DE +:104040003C1080009222000924030004304200FF4B +:10405000144300093C0280008C4401408FBF001CC7 +:104060008FB200188FB100148FB000102405009398 +:104070000A000ECC27BD00208C440140240500938B +:104080008FBF001C8FB200188FB100148FB00010CA +:104090000A000F4827BD00208E0401400E000332A5 +:1040A000000000008E4200042442FFFFAE420004E4 +:1040B0008E22003C2442FFFFAE22003C0E00033D56 +:1040C0008E0401408E0401408FBF001C8FB2001887 +:1040D0008FB100148FB00010240500040A000342C1 +:1040E00027BD00208FB200188FB100148FB00010D0 +:1040F00003E0000827BD00203C0680008CC2018838 +:104100003C038008346500809063000E00021402B6 +:10411000304400FF306300FF1464000E3C0280084E +:1041200090A20026304200FF104400098F82FF94C5 +:10413000A0A400262403005090420000304200FF5B +:1041400014430006000000000A0005A18CC4018091 +:104150003C02800834420080A044002603E00008AE +:104160000000000027BDFFE030E700FFAFB20018FD +:10417000AFBF001CAFB10014AFB0001000809021A1 +:1041800014E0000630C600FF000000000000000D33 +:10419000000000000A001060240001163C038008A3 +:1041A0009062000E304200FF14460023346200800B +:1041B00090420026304200FF1446001F000000001D +:1041C0009062000F304200FF1446001B0000000008 +:1041D0009062000A304200FF144600038F90FF9463 +:1041E0000000000D8F90FF948F82FF983C1180009B +:1041F000AE05003CAC450000A066000A0E0003328C +:104200008E240100A20000240E00033D8E24010034 +:104210003C0380008C6201F80440FFFE240200028F +:10422000AC7201C0A06201C43C021000AC6201F893 +:104230000A0010618FBF001C000000000000000D8C +:10424000000000002400013F8FBF001C8FB2001847 +:104250008FB100148FB0001003E0000827BD0020CC +:104260008F83FF943C0280008C44010034420100A3 +:104270008C65003C9046001B0A00102724070001B3 +:104280003C0280089043000E9042000A0043102632 +:10429000304200FF03E000080002102B27BDFFE0C2 +:1042A0003C028008AFB10014AFB00010AFBF0018DF +:1042B0003450008092020005240300303042003068 +:1042C00014430085008088218F8200248C42000CDA +:1042D000104000828FBF00180E000D840000000007 +:1042E0008F860020ACD100009202000892030009E2 +:1042F000304200FF00021200306300FF004310252F +:10430000ACC200049202004D000216000002160327 +:1043100004410005000000003C0308008C630048D5 +:104320000A00109F3C1080089202000830420040B2 +:10433000144000030000182192020027304300FFC0 +:104340003C108008361100809222004D00031E00B0 +:10435000304200FF0002140000621825ACC30008C0 +:104360008E2400308F820024ACC4000C8E250034D3 +:104370009443001E3C02C00BACC50010006218251F +:104380008E22003800002021ACC200148E22003C96 +:10439000ACC200180E000DB8ACC3001C8E020004A5 +:1043A0008F8400203C058000AC8200008E2200201B +:1043B000AC8200048E22001CAC8200088E220058C1 +:1043C0008CA3007400431021AC82000C8E22002CC0 +:1043D000AC8200108E2200408E23004400021400A4 +:1043E00000431025AC8200149222004D240300806B +:1043F000304200FF1443000400000000AC800018AD +:104400000A0010E38F8200248E23000C2402000196 +:104410001062000E2402FFFF92220008304200408A +:104420001440000A2402FFFF8E23000C8CA20074AB +:10443000006218233C0208000062102414400002AD +:10444000000028210060282100051043AC820018DC +:104450008F820024000020219443001E3C02C00CE7 +:10446000006218258F8200200E000DB8AC43001C9E +:104470003C038008346201008C4200008F850020DC +:10448000346300808FBF0018ACA20000ACA0000411 +:104490008C6400488F8200248FB10014ACA4000803 +:1044A000ACA0000CACA00010906300059446001E68 +:1044B0003C02400D00031E0000C23025ACA30014D6 +:1044C0008FB00010ACA0001824040001ACA6001CA2 +:1044D0000A000DB827BD00208FBF00188FB100144F +:1044E0008FB0001003E0000827BD00203C028000D0 +:1044F0009443007C3C02800834460100308400FF75 +:104500003065FFFF2402000524A34650A0C4000C20 +:104510005482000C3065FFFF90C2000D2C42000752 +:104520001040000724A30A0090C3000D24020014C9 +:104530000062100400A210210A00111F3045FFFF85 +:104540003065FFFF3C0280083442008003E0000831 +:10455000A44500143C03800834680080AD05003891 +:10456000346701008CE2001C308400FF00A210239D +:104570001840000330C600FF24A2FFFCACE2001C80 +:1045800030820001504000083C0380088D02003C4E +:1045900000A2102304410012240400058C620004D0 +:1045A00010A2000F3C0380088C62000414A2001EBD +:1045B000000000003C0208008C4200D8304200207D +:1045C000104000093C0280083462008090630008BB +:1045D0009042004C144300043C0280082404000470 +:1045E0000A00110900000000344300803442010039 +:1045F000A040000C24020001A462001410C0000AB4 +:104600003C0280008C4401003C0380008C6201F875 +:104610000440FFFE24020002AC6401C0A06201C499 +:104620003C021000AC6201F803E00008000000004A +:1046300027BDFFE800A61823AFBF00101860008058 +:10464000308800FF3C02800834470080A0E000244E +:1046500034440100A0E000278C82001C00A210233B +:1046600004400056000000008CE2003C94E3005C33 +:104670008CE4002C004530233063FFFF00C3182179 +:104680000083202B1080000400E018218CE2002C15 +:104690000A00117800A2102194E2005C3042FFFF72 +:1046A00000C2102100A21021AC62001C3C02800854 +:1046B000344400809482005C8C83001C3042FFFFF5 +:1046C0000002104000A210210043102B10400004F3 +:1046D000000000008C82001C0A00118B3C06800840 +:1046E0009482005C3042FFFF0002104000A21021C3 +:1046F0003C06800834C3010034C70080AC82001C33 +:10470000A060000CACE500388C62001C00A21023F5 +:104710001840000224A2FFFCAC62001C3102000120 +:10472000104000083C0380088CE2003C00A21023EB +:1047300004410012240400058CC2000410A20010E1 +:104740008FBF00108C62000414A2004F8FBF0010B6 +:104750003C0208008C4200D8304200201040000A81 +:104760003C02800834620080906300089042004C54 +:10477000144300053C028008240400048FBF00108D +:104780000A00110927BD001834430080344201009B +:10479000A040000C24020001A46200143C0280002E +:1047A0008C4401003C0380008C6201F80440FFFE51 +:1047B000240200020A0011D8000000008CE2001C54 +:1047C000004610230043102B54400001ACE5001CB0 +:1047D00094E2005C3042FFFF0062102B144000079F +:1047E0002402000294E2005C8CE3001C3042FFFFD4 +:1047F00000621821ACE3001C24020002ACE5003882 +:104800000E000F5EA082000C1040001F8FBF001032 +:104810003C0280008C4401003C0380008C6201F863 +:104820000440FFFE24020002AC6401C0A06201C487 +:104830003C021000AC6201F80A0011F08FBF0010BA +:1048400031020010104000108FBF00103C028008A1 +:10485000344500808CA3001C94A2005C00661823E1 +:104860003042FFFF006218213C023FFF3444FFFF4B +:104870000083102B544000010080182100C3102138 +:10488000ACA2001C8FBF001003E0000827BD001879 +:1048900027BDFFE800C0402100A63023AFBF0010B5 +:1048A00018C00026308A00FF3C028008344900808E +:1048B0008D24001C8D23002C008820230064182BDD +:1048C0001060000F344701008CE2002000461021E8 +:1048D000ACE200208CE200200044102B1440000BBE +:1048E0003C023FFF8CE2002000441023ACE2002099 +:1048F0009522005C3042FFFF0A0012100082202146 +:10490000ACE00020008620213C023FFF3443FFFF43 +:104910000064102B54400001006020213C028008FC +:104920003442008000851821AC43001CA0400024C4 +:10493000A04000270A0012623C03800831420010A8 +:10494000104000433C0380083C06800834C40080CB +:104950008C82003C004810235840003E34660080A2 +:104960009082002424420001A0820024908200242E +:104970003C0308008C630024304200FF0043102BEE +:10498000144000688FBF001034C201008C42001C2C +:1049900000A2102318400063000000008CC3000434 +:1049A0009482005C006818233042FFFF0003184324 +:1049B000000210400043102A1040000500000000D3 +:1049C0008CC20004004810230A0012450002104364 +:1049D0009482005C3042FFFF000210403C068008D9 +:1049E000AC82002C34C5008094A2005C8CA4002C06 +:1049F00094A3005C3042FFFF00021040008220219F +:104A00003063FFFF0083202101041021ACA2001CB1 +:104A10008CC2000434C60100ACC2001C2402000297 +:104A20000E000F5EA0C2000C1040003E8FBF0010B1 +:104A30003C0280008C4401003C0380008C6201F841 +:104A40000440FFFE240200020A001292000000004F +:104A500034660080ACC50038346401008C82001CD0 +:104A600000A210231840000224A2FFFCAC82001C0C +:104A7000314200015040000A3C0380088CC2003CD7 +:104A800000A2102304430014240400058C620004D7 +:104A900014A200033C0380080A00128424040005C9 +:104AA0008C62000414A2001F8FBF00103C0208009B +:104AB0008C4200D8304200201040000A3C0280089E +:104AC00034620080906300089042004C144300055B +:104AD0003C028008240400048FBF00100A00110962 +:104AE00027BD00183443008034420100A040000C70 +:104AF00024020001A46200143C0280008C440100E6 +:104B00003C0380008C6201F80440FFFE2402000296 +:104B1000AC6401C0A06201C43C021000AC6201F8A8 +:104B20008FBF001003E0000827BD001827BDFFE875 +:104B30003C0A8008AFBF0010354900808D22003C40 +:104B400000C04021308400FF004610231840009D23 +:104B500030E700FF354701002402000100A63023A2 +:104B6000A0E0000CA0E0000DA522001418C0002455 +:104B7000308200108D23001C8D22002C0068182329 +:104B80000043102B1040000F000000008CE20020BA +:104B900000461021ACE200208CE200200043102BE4 +:104BA0001440000B3C023FFF8CE200200043102326 +:104BB000ACE200209522005C3042FFFF0A0012C1E7 +:104BC00000621821ACE00020006618213C023FFF83 +:104BD0003446FFFF00C3102B5440000100C01821D1 +:104BE0003C0280083442008000651821AC43001C60 +:104BF000A0400024A04000270A00130F3C038008B7 +:104C0000104000403C0380088D22003C00481023E7 +:104C10005840003D34670080912200242442000166 +:104C2000A1220024912200243C0308008C6300246C +:104C3000304200FF0043102B1440009A8FBF001039 +:104C40008CE2001C00A21023184000960000000017 +:104C50008D4300049522005C006818233042FFFF5A +:104C600000031843000210400043102A10400005C2 +:104C7000012020218D420004004810230A0012F276 +:104C8000000210439522005C3042FFFF00021040FA +:104C90003C068008AC82002C34C5008094A2005CE5 +:104CA0008CA4002C94A3005C3042FFFF0002104053 +:104CB000008220213063FFFF0083182101031021AF +:104CC000ACA2001C8CC2000434C60100ACC2001CA3 +:104CD000240200020E000F5EA0C2000C1040007102 +:104CE0008FBF00103C0280008C4401003C03800018 +:104CF0008C6201F80440FFFE240200020A0013390E +:104D00000000000034670080ACE500383466010024 +:104D10008CC2001C00A210231840000224A2FFFC39 +:104D2000ACC2001C30820001504000083C038008E7 +:104D30008CE2003C00A2102304430051240400052F +:104D40008C62000410A2003E3C0380088C620004C8 +:104D500054A200548FBF00103C0208008C4200D8BF +:104D600030420020104000063C028008346200807F +:104D7000906300089042004C104300403C028008C1 +:104D80003443008034420100A040000C24020001A2 +:104D9000A46200143C0280008C4401003C038000AB +:104DA0008C6201F80440FFFE24020002AC6401C0E2 +:104DB000A06201C43C021000AC6201F80A00137743 +:104DC0008FBF001024020005A120002714E2000A72 +:104DD0003C038008354301009062000D2C42000620 +:104DE000504000053C0380089062000D2442000101 +:104DF000A062000D3C03800834670080ACE50038F9 +:104E0000346601008CC2001C00A21023184000026E +:104E100024A2FFFCACC2001C308200015040000AFA +:104E20003C0380088CE2003C00A2102304410014E3 +:104E3000240400058C62000414A200033C038008D3 +:104E40000A00136E240400058C62000414A20015ED +:104E50008FBF00103C0208008C4200D83042002076 +:104E60001040000A3C028008346200809063000811 +:104E70009042004C144300053C02800824040004C6 +:104E80008FBF00100A00110927BD001834430080AD +:104E900034420100A040000C24020001A46200146E +:104EA0008FBF001003E0000827BD00183C0B8008EE +:104EB00027BDFFE83C028000AFBF00103442010074 +:104EC000356A00809044000A356901008C45001461 +:104ED0008D4800389123000C308400FF0105102319 +:104EE0001C4000B3306700FF2CE20006504000B1C8 +:104EF0008FBF00102402000100E2300430C2000322 +:104F00005440000800A8302330C2000C144000A117 +:104F100030C20030144000A38FBF00100A00143BC1 +:104F20000000000018C00024308200108D43001CD7 +:104F30008D42002C006818230043102B1040000FF6 +:104F4000000000008D22002000461021AD2200202C +:104F50008D2200200043102B1440000B3C023FFF29 +:104F60008D22002000431023AD2200209542005CDA +:104F70003042FFFF0A0013AF00621821AD2000206D +:104F8000006618213C023FFF3446FFFF00C3102B90 +:104F90005440000100C018213C02800834420080C7 +:104FA00000651821AC43001CA0400024A04000274D +:104FB0000A0013FD3C038008104000403C038008B9 +:104FC0008D42003C004810231840003D34670080AB +:104FD0009142002424420001A14200249142002475 +:104FE0003C0308008C630024304200FF0043102B78 +:104FF000144000708FBF00108D22001C00A21023EF +:105000001840006C000000008D6300049542005CB5 +:10501000006818233042FFFF0003184300021040CD +:105020000043102A10400005014020218D62000439 +:10503000004810230A0013E0000210439542005C70 +:105040003042FFFF000210403C068008AC82002C7A +:1050500034C5008094A2005C8CA4002C94A3005C56 +:105060003042FFFF00021040008220213063FFFF2A +:105070000083182101031021ACA2001C8CC2000483 +:1050800034C60100ACC2001C240200020E000F5EF8 +:10509000A0C2000C104000478FBF00103C028000EF +:1050A0008C4401003C0380008C6201F80440FFFE48 +:1050B000240200020A00142D000000003467008062 +:1050C000ACE50038346601008CC2001C00A210233D +:1050D0001840000224A2FFFCACC2001C3082000178 +:1050E0005040000A3C0380088CE2003C00A21023E0 +:1050F00004430014240400058C62000414A200037D +:105100003C0380080A00141F240400058C6200047C +:1051100014A200288FBF00103C0208008C4200D867 +:10512000304200201040000A3C02800834620080B7 +:10513000906300089042004C144300053C02800834 +:10514000240400048FBF00100A00110927BD0018B5 +:105150003443008034420100A040000C24020001CE +:10516000A46200143C0280008C4401003C038000D7 +:105170008C6201F80440FFFE24020002AC6401C00E +:10518000A06201C43C021000AC6201F80A00143BAA +:105190008FBF00108FBF0010010030210A00115A8C +:1051A00027BD0018010030210A00129927BD001800 +:1051B0008FBF001003E0000827BD00183C038008E3 +:1051C0003464010024020003A082000C8C620004FD +:1051D00003E00008AC82001C3C05800834A300807A +:1051E0009062002734A501002406004324420001F8 +:1051F000A0620027906300273C0208008C42004810 +:10520000306300FF146200043C07602194A500EAAB +:105210000A00090130A5FFFF03E0000800000000BC +:1052200027BDFFE8AFBF00103C0280000E00144411 +:105230008C4401803C02800834430100A060000CD3 +:105240008C4200048FBF001027BD001803E0000847 +:10525000AC62001C27BDFFE03C028008AFBF001815 +:10526000AFB10014AFB000103445008034460100E7 +:105270003C0880008D09014090C3000C8CA4003CC8 +:105280008CA200381482003B306700FF9502007C3E +:1052900090A30027146000093045FFFF2402000599 +:1052A00054E200083C04800890C2000D2442000132 +:1052B000A0C2000D0A00147F3C048008A0C0000DAD +:1052C0003C048008348201009042000C2403000555 +:1052D000304200FF1443000A24A205DC348300801E +:1052E000906200272C4200075040000524A20A00CB +:1052F00090630027240200140062100400A2102111 +:105300003C108008361000803045FFFF012020212E +:105310000E001444A60500149602005C8E030038AB +:105320003C1180003042FFFF000210400062182153 +:10533000AE03001C0E0003328E24014092020025B1 +:1053400034420040A20200250E00033D8E2401409D +:105350008E2401403C0380008C6201F80440FFFE73 +:1053600024020002AC6401C0A06201C43C0210002F +:10537000AC6201F88FBF00188FB100148FB000101D +:1053800003E0000827BD00203C0360103C02080039 +:1053900024420174AC62502C8C6250003C048000AA +:1053A00034420080AC6250003C0208002442547C2D +:1053B0003C010800AC2256003C020800244254384C +:1053C0003C010800AC2256043C020002AC840008F8 +:1053D000AC82000C03E000082402000100A0302190 +:1053E0003C1C0800279C56083C0200023C050400B7 +:1053F00000852826008220260004102B2CA5000101 +:105400002C840001000210803C0308002463560035 +:105410000085202500431821108000030000102182 +:10542000AC6600002402000103E000080000000058 +:105430003C1C0800279C56083C0200023C05040066 +:1054400000852826008220260004102B2CA50001B0 +:105450002C840001000210803C03080024635600E5 +:105460000085202500431821108000050000102130 +:105470003C02080024425438AC62000024020001BF +:1054800003E00008000000003C0200023C030400AE +:1054900000821026008318262C4200012C63000194 +:1054A000004310251040000B000028213C1C080080 +:1054B000279C56083C0380008C62000824050001EC +:1054C00000431025AC6200088C62000C00441025DB +:1054D000AC62000C03E0000800A010213C1C080096 +:1054E000279C56083C0580008CA3000C0004202754 +:1054F000240200010064182403E00008ACA3000C9F +:105500003C020002148200063C0560008CA208D018 +:105510002403FFFE0043102403E00008ACA208D0DF +:105520003C02040014820005000000008CA208D098 +:105530002403FFFD00431024ACA208D003E00008C0 +:10554000000000003C02601A344200108C430080CE +:1055500027BDFFF88C440084AFA3000093A3000094 +:10556000240200041462001AAFA4000493A20001F4 +:105570001040000797A300023062FFFC3C0380004C +:10558000004310218C4200000A001536AFA200042F +:105590003062FFFC3C03800000431021AC4400005B +:1055A000A3A000003C0560008CA208D02403FFFEED +:1055B0003C04601A00431024ACA208D08FA300045E +:1055C0008FA2000034840010AC830084AC82008081 +:1055D00003E0000827BD000827BDFFE8AFBF0010AB +:1055E0003C1C0800279C56083C0280008C43000CA1 +:1055F0008C420004004318243C0200021060001496 +:10560000006228243C0204003C04000210A00005B3 +:10561000006210243C0208008C4256000A00155B10 +:1056200000000000104000073C0404003C02080099 +:105630008C4256040040F809000000000A00156082 +:10564000000000000000000D3C1C0800279C5608CC +:105650008FBF001003E0000827BD0018800802403B +:1056600080080100800800808008000000000C8095 +:105670000000320008000E9808000EF408000F88A1 +:1056800008001028080010748008010080080080BD +:10569000800800000A000028000000000000000050 +:1056A0000000000D6370362E322E316200000000C3 +:1056B00006020104000000000000000000000000DD +:1056C000000000000000000038003C000000000066 +:1056D00000000000000000000000000000000020AA +:1056E00000000000000000000000000000000000BA +:1056F00000000000000000000000000000000000AA +:10570000000000000000000021003800000000013F +:105710000000002B000000000000000400030D400A +:105720000000000000000000000000000000000079 +:105730000000000000000000100000030000000056 +:105740000000000D0000000D3C020800244259AC8E +:105750003C03080024635BF4AC4000000043202BB2 +:105760001480FFFD244200043C1D080037BD9FFC4F +:1057700003A0F0213C100800261000A03C1C0800EB +:10578000279C59AC0E0002F6000000000000000D3E +:1057900027BDFFB4AFA10000AFA20004AFA3000873 +:1057A000AFA4000CAFA50010AFA60014AFA700185F +:1057B000AFA8001CAFA90020AFAA0024AFAB0028FF +:1057C000AFAC002CAFAD0030AFAE0034AFAF00389F +:1057D000AFB8003CAFB90040AFBC0044AFBF004819 +:1057E0000E000820000000008FBF00488FBC00445E +:1057F0008FB900408FB8003C8FAF00388FAE0034B7 +:105800008FAD00308FAC002C8FAB00288FAA002406 +:105810008FA900208FA8001C8FA700188FA6001446 +:105820008FA500108FA4000C8FA300088FA2000486 +:105830008FA1000027BD004C3C1B60188F7A5030B0 +:10584000377B502803400008AF7A000000A01821E1 +:1058500000801021008028213C0460003C0760008B +:105860002406000810600006348420788C42000072 +:10587000ACE220088C63000003E00008ACE3200CDD +:105880000A000F8100000000240300403C02600079 +:1058900003E00008AC4320003C0760008F86000452 +:1058A0008CE520740086102100A2182B14600007DC +:1058B000000028218F8AFDA024050001A1440013C7 +:1058C0008F89000401244021AF88000403E0000810 +:1058D00000A010218F84FDA08F8500049086001306 +:1058E00030C300FF00A31023AF82000403E00008D0 +:1058F000A08000138F84FDA027BDFFE8AFB000108B +:10590000AFBF001490890011908700112402002875 +:10591000312800FF3906002830E300FF2485002CE1 +:105920002CD00001106200162484001C0E00006EB2 +:10593000000000008F8FFDA03C05600024020204DF +:1059400095EE003E95ED003C000E5C0031ACFFFF93 +:10595000016C5025ACAA2010520000012402000462 +:10596000ACA22000000000000000000000000000C9 +:105970008FBF00148FB0001003E0000827BD00188F +:105980000A0000A6000028218F85FDA027BDFFD8B2 +:10599000AFBF0020AFB3001CAFB20018AFB100140E +:1059A000AFB000100080982190A4001124B0001C1A +:1059B00024B1002C308300FF386200280E000090D4 +:1059C0002C5200010E00009800000000020020216F +:1059D0001240000202202821000028210E00006E43 +:1059E000000000008F8DFDA03C0880003C05600099 +:1059F00095AC003E95AB003C02683025000C4C0095 +:105A0000316AFFFF012A3825ACA7201024020202C8 +:105A1000ACA6201452400001240200028FBF0020D7 +:105A20008FB3001C8FB200188FB100148FB000101C +:105A300027BD002803E00008ACA2200027BDFFE03E +:105A4000AFB20018AFB10014AFB00010AFBF001C70 +:105A50003C1160008E2320748F82000430D0FFFF41 +:105A600030F2FFFF1062000C2406008F0E00006E63 +:105A7000000000003C06801F0010440034C5FF00F9 +:105A80000112382524040002AE2720100000302126 +:105A9000AE252014AE2420008FBF001C8FB200184A +:105AA0008FB100148FB0001000C0102103E0000877 +:105AB00027BD002027BDFFE0AFB0001030D0FFFFB2 +:105AC000AFBF0018AFB100140E00006E30F1FFFF41 +:105AD00000102400009180253C036000AC70201071 +:105AE0008FBF00188FB100148FB000102402000483 +:105AF000AC62200027BD002003E000080000102158 +:105B000027BDFFE03C046018AFBF0018AFB1001420 +:105B1000AFB000108C8850002403FF7F34028071E6 +:105B20000103382434E5380C241F00313C1980006F +:105B3000AC8550003C11800AAC8253BCAF3F0008DA +:105B40000E00054CAF9100400E00050A3C116000AC +:105B50000E00007D000000008E3008083C0F570941 +:105B60002418FFF00218602435EEE00035EDF00057 +:105B7000018E5026018D58262D4600012D69000109 +:105B8000AF86004C0E000D09AF8900503C06601630 +:105B90008CC700003C0860148D0500A03C03FFFF8B +:105BA00000E320243C02535300052FC2108200550D +:105BB00034D07C00960201F2A780006C10400003F4 +:105BC000A780007C384B1E1EA78B006C960201F844 +:105BD000104000048F8D0050384C1E1EA78C007C96 +:105BE0008F8D005011A000058F83004C240E0020E3 +:105BF000A78E007CA78E006C8F83004C1060000580 +:105C00009785007C240F0020A78F007CA78F006C55 +:105C10009785007C2CB8008153000001240500808A +:105C20009784006C2C91040152200001240404008C +:105C30001060000B3C0260008FBF00188FB1001491 +:105C40008FB0001027BD0020A784006CA785007CC2 +:105C5000A380007EA780007403E00008A780009264 +:105C60008C4704382419103C30FFFFFF13F9000360 +:105C700030A8FFFF1100004624030050A380007EDF +:105C80009386007E50C00024A785007CA780007CFE +:105C90009798007CA780006CA7800074A780009272 +:105CA0003C010800AC3800800E00078700000000AF +:105CB0003C0F60008DED0808240EFFF03C0B600ED9 +:105CC000260C0388356A00100000482100002821B6 +:105CD00001AE20243C105709AF8C0010AF8A004859 +:105CE000AF89001810900023AF8500148FBF0018F3 +:105CF0008FB100148FB0001027BD002003E0000812 +:105D0000AF80005400055080014648218D260004D4 +:105D10000A00014800D180219798007CA784006C7C +:105D2000A7800074A78000923C010800AC38008076 +:105D30000E000787000000003C0F60008DED080892 +:105D4000240EFFF03C0B600E260C0388356A001011 +:105D5000000048210000282101AE20243C105709F2 +:105D6000AF8C0010AF8A0048AF8900181490FFDF95 +:105D7000AF85001424110001AF9100548FBF0018AB +:105D80008FB100148FB0001003E0000827BD002081 +:105D90000A00017BA383007E3083FFFF8F880040D1 +:105DA0008F87003C000321403C0580003C020050EE +:105DB000008248253C0660003C0A010034AC040027 +:105DC0008CCD08E001AA58241160000500000000F5 +:105DD0008CCF08E024E7000101EA7025ACCE08E092 +:105DE0008D19001001805821ACB900388D180014AD +:105DF000ACB8003CACA9003000000000000000007E +:105E00000000000000000000000000000000000092 +:105E100000000000000000003C0380008C640000D3 +:105E2000308200201040FFFD3C0F60008DED08E047 +:105E30003C0E010001AE18241460FFE100000000D8 +:105E4000AF87003C03E00008AF8B00588F8500400F +:105E5000240BFFF03C06800094A7001A8CA90024B4 +:105E600030ECFFFF000C38C000EB5024012A402129 +:105E7000ACC8003C8CA400248CC3003C00831023DD +:105E800018400033000000008CAD002025A2000166 +:105E90003C0F0050ACC2003835EE00103C068000CC +:105EA000ACCE003000000000000000000000000048 +:105EB00000000000000000000000000000000000E2 +:105EC000000000003C0480008C9900003338002062 +:105ED0001300FFFD30E20008104000173C0980006D +:105EE0008C880408ACA800108C83040CACA30014AC +:105EF0003C1900203C188000AF19003094AE001807 +:105F000094AF001C01CF3021A4A6001894AD001A54 +:105F100025A70001A4A7001A94AB001A94AC001E98 +:105F2000118B00030000000003E0000800000000E7 +:105F300003E00008A4A0001A8D2A0400ACAA0010F7 +:105F40008D240404ACA400140A0002183C1900209B +:105F50008CA200200A0002003C0F00500A0001EE53 +:105F60000000000027BDFFE8AFBF00100E000232A6 +:105F7000000000008F8900408FBF00103C038000AC +:105F8000A520000A9528000A9527000427BD0018BF +:105F90003105FFFF30E6000F0006150000A22025A6 +:105FA00003E00008AC6400803C0508008CA50020DC +:105FB0008F83000C27BDFFE8AFB00010AFBF001407 +:105FC00010A300100000802124040001020430040A +:105FD00000A6202400C3102450440006261000010F +:105FE000001018802787FDA41480000A006718217C +:105FF000261000012E0900025520FFF38F83000CAC +:10600000AF85000C8FBF00148FB0001003E00008B4 +:1060100027BD00188C6800003C058000ACA8002457 +:106020000E000234261000013C0508008CA500205B +:106030000A0002592E0900022405000100851804F7 +:106040003C0408008C84002027BDFFC8AFBF00348B +:1060500000831024AFBE0030AFB7002CAFB60028CD +:10606000AFB50024AFB40020AFB3001CAFB200182E +:10607000AFB1001410400051AFB000108F84004049 +:10608000948700069488000A00E8302330D5FFFF8B +:1060900012A0004B8FBF0034948B0018948C000A20 +:1060A000016C50233142FFFF02A2482B1520000251 +:1060B00002A02021004020212C8F000515E00002C5 +:1060C00000809821241300040E0001C102602021E9 +:1060D0008F87004002609021AF80004494F4000A52 +:1060E000026080211260004E3291FFFF3C1670006A +:1060F0003C1440003C1E20003C1760008F99005863 +:106100008F380000031618241074004F0283F82BF8 +:1061100017E0003600000000107E00478F86004424 +:1061200014C0003A2403000102031023022320219B +:106130003050FFFF1600FFF13091FFFF8F870040C6 +:106140003C1100203C108000AE11003094EB000A9E +:106150003C178000024B5021A4EA000A94E9000A8F +:1061600094E800043123FFFF3106000F00062D00E4 +:106170000065F025AEFE008094F3000A94F6001846 +:1061800012D30036001221408CFF00148CF4001052 +:1061900003E468210000C02101A4782B029870213B +:1061A00001CF6021ACED0014ACEC001002B238233A +:1061B00030F5FFFF16A0FFB88F8400408FBF00347A +:1061C0008FBE00308FB7002C8FB600288FB500240B +:1061D0008FB400208FB3001C8FB200188FB1001451 +:1061E0008FB0001003E0000827BD00381477FFCC03 +:1061F0008F8600440E000EE202002021004018218C +:106200008F86004410C0FFC9020310230270702360 +:106210008F87004001C368210A0002E431B2FFFF0A +:106220008F86004414C0FFC93C1100203C10800040 +:106230000A0002AEAE1100300E00046602002021FA +:106240000A0002DB00401821020020210E0009395B +:10625000022028210A0002DB004018210E0001EE76 +:10626000000000000A0002C702B2382327BDFFC8A1 +:10627000AFB7002CAFB60028AFB50024AFB40020F4 +:10628000AFB3001CAFB20018AFB10014AFB0001034 +:10629000AFBF00300E00011B241300013C047FFF40 +:1062A0003C0380083C0220003C010800AC20007048 +:1062B0003496FFFF34770080345200033C1512C03F +:1062C000241400013C1080002411FF800E000245C0 +:1062D000000000008F8700488F8B00188F89001402 +:1062E0008CEA00EC8CE800E8014B302B01092823F4 +:1062F00000A6102314400006014B18231440000E82 +:106300003C05800002A3602B1180000B0000000000 +:106310003C0560008CEE00EC8CED00E88CA4180CC1 +:10632000AF8E001804800053AF8D00148F8F0010C3 +:10633000ADF400003C0580008CBF00003BF900017B +:10634000333800011700FFE13C0380008C6201003C +:1063500024060C0010460009000000008C680100B3 +:106360002D043080548000103C0480008C690100B2 +:106370002D2331811060000C3C0480008CAA0100A8 +:1063800011460004000020218CA6010024C5FF81D5 +:1063900030A400FF8E0B01000E000269AE0B00243A +:1063A0000A00034F3C0480008C8D01002DAC3300AB +:1063B00011800022000000003C0708008CE70098D4 +:1063C00024EE00013C010800AC2E00983C04800043 +:1063D0008C8201001440000300000000566000148D +:1063E0003C0440008C9F01008C9801000000982123 +:1063F00003F1C82400193940330F007F00EF7025E6 +:1064000001D26825AC8D08308C8C01008C85010090 +:10641000258B0100017130240006514030A3007F1C +:106420000143482501324025AC8808303C04400037 +:10643000AE0401380A00030E000000008C99010030 +:10644000240F0020AC99002092F80000330300FFD5 +:10645000106F000C241F0050547FFFDD3C048000AF +:106460008C8401000E00154E000000000A00034F4E +:106470003C04800000963824ACA7180C0A000327BF +:106480008F8F00108C8501000E0008F72404008017 +:106490000A00034F3C04800000A4102B24030001D9 +:1064A00010400009000030210005284000A4102BF6 +:1064B00004A00003000318405440FFFC00052840DE +:1064C0005060000A0004182B0085382B54E00004AB +:1064D0000003184200C33025008520230003184222 +:1064E0001460FFF9000528420004182B03E000089F +:1064F00000C310213084FFFF30C600FF3C0780003E +:106500008CE201B80440FFFE00064C000124302557 +:106510003C08200000C820253C031000ACE00180AE +:10652000ACE50184ACE4018803E00008ACE301B809 +:106530003C0660008CC5201C2402FFF03083020062 +:10654000308601001060000E00A2282434A500014E +:106550003087300010E0000530830C0034A50004C3 +:106560003C04600003E00008AC85201C1060FFFDC7 +:106570003C04600034A5000803E00008AC85201C42 +:1065800054C0FFF334A500020A0003B03087300086 +:1065900027BDFFE8AFB00010AFBF00143C0760009C +:1065A000240600021080001100A080218F83005873 +:1065B0000E0003A78C6400188F8200580000202171 +:1065C000240600018C45000C0E000398000000001A +:1065D0001600000224020003000010218FBF0014E7 +:1065E0008FB0001003E0000827BD00188CE8201CC5 +:1065F0002409FFF001092824ACE5201C8F870058EE +:106600000A0003CD8CE5000C3C02600E00804021A6 +:1066100034460100240900180000000000000000BA +:10662000000000003C0A00503C0380003547020097 +:10663000AC68003834640400AC65003CAC670030E2 +:106640008C6C0000318B00201160FFFD2407FFFFE0 +:106650002403007F8C8D00002463FFFF248400044A +:10666000ACCD00001467FFFB24C60004000000004E +:10667000000000000000000024A402000085282B78 +:106680003C0300203C0E80002529FFFF010540212E +:10669000ADC300301520FFE00080282103E0000892 +:1066A000000000008F82005827BDFFD8AFB3001C48 +:1066B000AFBF0020AFB20018AFB10014AFB00010F0 +:1066C00094460002008098218C5200182CC300814F +:1066D0008C4800048C4700088C51000C8C49001039 +:1066E000106000078C4A00142CC4000414800013AE +:1066F00030EB000730C5000310A0001000000000C0 +:106700002410008B02002021022028210E00039873 +:10671000240600031660000224020003000010217A +:106720008FBF00208FB3001C8FB200188FB10014F0 +:106730008FB0001003E0000827BD00281560FFF1AE +:106740002410008B3C0C80003C030020241F00011F +:10675000AD830030AF9F0044000000000000000047 +:10676000000000002419FFF024D8000F031978243A +:106770003C1000D0AD88003801F0702524CD000316 +:106780003C08600EAD87003C35850400AD8E0030BE +:10679000000D38823504003C3C0380008C6B000007 +:1067A000316200201040FFFD0000000010E00008F2 +:1067B00024E3FFFF2407FFFF8CA800002463FFFFF2 +:1067C00024A50004AC8800001467FFFB24840004A7 +:1067D0003C05600EACA60038000000000000000080 +:1067E000000000008F8600543C0400203C0780001D +:1067F000ACE4003054C000060120202102402021DA +:106800000E0003A7000080210A00041D02002021C1 +:106810000E0003DD01402821024020210E0003A7C5 +:10682000000080210A00041D0200202127BDFFE096 +:10683000AFB200183092FFFFAFB10014AFBF001C21 +:10684000AFB000101640000D000088210A0004932C +:106850000220102124050003508500278CE5000C40 +:106860000000000D262800013111FFFF24E2002066 +:106870000232802B12000019AF8200588F82004430 +:10688000144000168F8700583C0670003C0320001F +:106890008CE5000000A62024148300108F84006083 +:1068A000000544023C09800000A980241480FFE90F +:1068B000310600FF2CCA000B5140FFEB26280001D7 +:1068C000000668803C0E080025CE575801AE6021B6 +:1068D0008D8B0000016000080000000002201021E4 +:1068E0008FBF001C8FB200188FB100148FB0001042 +:1068F00003E0000827BD00200E0003982404008454 +:106900001600FFD88F8700580A000474AF8000601B +:10691000020028210E0003BF240400018F870058C5 +:106920000A000474AF820060020028210E0003BF39 +:10693000000020210A0004A38F8700580E000404E1 +:10694000020020218F8700580A000474AF82006083 +:1069500030AFFFFF000F19C03C0480008C9001B8DD +:106960000600FFFE3C1920043C181000AC83018097 +:10697000AC800184AC990188AC9801B80A00047518 +:106980002628000190E2000390E30002000020218D +:106990000002FE0000033A0000FF2825240600083C +:1069A0000E000398000000001600FFDC2402000324 +:1069B0008F870058000010210A000474AF82006025 +:1069C00090E8000200002021240600090A0004C308 +:1069D00000082E0090E4000C240900FF308500FF21 +:1069E00010A900150000302190F9000290F8000372 +:1069F000308F00FF94EB000400196E000018740043 +:106A0000000F62000186202501AE5025014B28258C +:106A10003084FF8B0A0004C32406000A90E30002BE +:106A200090FF0004000020210003360000DF28252D +:106A30000A0004C32406000B0A0004D52406008BB8 +:106A4000000449C23127003F000443423C02800059 +:106A500000082040240316802CE60020AC43002CC4 +:106A600024EAFFE02482000114C0000330A900FFE3 +:106A700000801021314700FF000260803C0D800043 +:106A8000240A0001018D20213C0B000E00EA28049D +:106A9000008B302111200005000538278CCE000026 +:106AA00001C5382503E00008ACC700008CD8000001 +:106AB0000307782403E00008ACCF000027BDFFE007 +:106AC000AFB10014AFB00010AFBF00183C076000BA +:106AD0008CE408083402F0003C1160003083F000C0 +:106AE000240501C03C04800E000030211062000625 +:106AF000241000018CEA08083149F0003928E00030 +:106B00000008382B000780403C0D0200AE2D081411 +:106B1000240C16803C0B80008E2744000E000F8B47 +:106B2000AD6C002C120000043C02169124050001FB +:106B3000120500103C023D2C345800E0AE384408E9 +:106B40003C1108008E31007C8FBF00183C066000AD +:106B500000118540360F16808FB100148FB00010E1 +:106B60003C0E020027BD0020ACCF442003E000080B +:106B7000ACCE08103C0218DA345800E0AE384408B5 +:106B80003C1108008E31007C8FBF00183C0660006D +:106B900000118540360F16808FB100148FB00010A1 +:106BA0003C0E020027BD0020ACCF442003E00008CB +:106BB000ACCE08100A0004EB240500010A0004EB27 +:106BC0000000282124020400A7820024A780001CC2 +:106BD000000020213C06080024C65A582405FFFF67 +:106BE00024890001000440803124FFFF01061821A0 +:106BF0002C87002014E0FFFAAC6500002404040098 +:106C0000A7840026A780001E000020213C06080063 +:106C100024C65AD82405FFFF248D0001000460809B +:106C200031A4FFFF018658212C8A00201540FFFA6D +:106C3000AD650000A7800028A7800020A780002263 +:106C4000000020213C06080024C65B582405FFFFF5 +:106C5000249900010004C0803324FFFF030678213B +:106C60002C8E000415C0FFFAADE500003C05600065 +:106C70008CA73D002403E08F00E31024344601403C +:106C800003E00008ACA63D002487007F000731C266 +:106C900024C5FFFF000518C2246400013082FFFFF5 +:106CA000000238C0A78400303C010800AC27003047 +:106CB000AF80002C0000282100002021000030219E +:106CC0002489000100A728213124FFFF2CA81701E7 +:106CD000110000032C8300801460FFF924C600011A +:106CE00000C02821AF86002C10C0001DA786002AF6 +:106CF00024CAFFFF000A11423C08080025085B581F +:106D00001040000A00002021004030212407FFFF2E +:106D1000248E00010004688031C4FFFF01A86021B7 +:106D20000086582B1560FFFAAD87000030A2001FC7 +:106D30005040000800043080240300010043C804D0 +:106D400000041080004878212738FFFF03E0000886 +:106D5000ADF8000000C820212405FFFFAC8500002D +:106D600003E000080000000030A5FFFF30C6FFFF71 +:106D700030A8001F0080602130E700FF0005294295 +:106D80000000502110C0001D24090001240B000147 +:106D900025180001010B2004330800FF0126782686 +:106DA000390E00202DED00012DC2000101A2182591 +:106DB0001060000D014450250005C880032C4021BF +:106DC0000100182110E0000F000A20278D040000A8 +:106DD000008A1825AD03000024AD00010000402109 +:106DE0000000502131A5FFFF252E000131C9FFFF12 +:106DF00000C9102B1040FFE72518000103E0000830 +:106E0000000000008D0A0000014440240A0005D162 +:106E1000AC68000027BDFFE830A5FFFF30C6FFFFCC +:106E2000AFB00010AFBF001430E7FFFF00005021EB +:106E30003410FFFF0000602124AF001F00C0482174 +:106E4000241800012419002005E0001601E010219B +:106E50000002F943019F682A0009702B01AE40240B +:106E600011000017000C18800064102110E00005CC +:106E70008C4B000000F840040008382301675824B8 +:106E800000003821154000410000402155600016E7 +:106E90003169FFFF258B0001316CFFFF05E1FFEC3D +:106EA00001E0102124A2003E0002F943019F682A5C +:106EB0000009702B01AE40241500FFEB000C188078 +:106EC000154600053402FFFF020028210E0005B51B +:106ED00000003821020010218FBF00148FB0001075 +:106EE00003E0000827BD00181520000301601821E9 +:106EF000000B1C0224080010306A00FF154000053A +:106F0000306E000F250D000800031A0231A800FFA3 +:106F1000306E000F15C00005307F000325100004FF +:106F200000031902320800FF307F000317E000055C +:106F3000386900012502000200031882304800FF72 +:106F4000386900013123000110600004310300FFA3 +:106F5000250A0001314800FF310300FF000C6940A1 +:106F600001A34021240A000110CAFFD53110FFFF00 +:106F7000246E000131C800FF1119FFC638C9000195 +:106F80002D1F002053E0001C258B0001240D000163 +:106F90000A000648240E002051460017258B0001E8 +:106FA00025090001312800FF2D0900205120001281 +:106FB000258B000125430001010D5004014B1024D5 +:106FC000250900011440FFF4306AFFFF3127FFFF5D +:106FD00010EE000C2582FFFF304CFFFF0000502117 +:106FE0003410FFFF312800FF2D0900205520FFF24B +:106FF00025430001258B0001014648260A000602B0 +:10700000316CFFFF00003821000050210A000654B7 +:107010003410FFFF27BDFFD8AFB0001030F0FFFFE6 +:10702000AFB10014001039423211FFE000071080A8 +:10703000AFB3001C00B1282330D3FFFFAFB200185C +:1070400030A5FFFF00809021026030210044202104 +:10705000AFBF00200E0005E03207001F022288218A +:107060003403FFFF0240202102002821026030216A +:1070700000003821104300093231FFFF02201021A7 +:107080008FBF00208FB3001C8FB200188FB1001487 +:107090008FB0001003E0000827BD00280E0005E0B7 +:1070A0000000000000408821022010218FBF002036 +:1070B0008FB3001C8FB200188FB100148FB0001076 +:1070C00003E0000827BD0028000424003C03600002 +:1070D000AC603D0810A00002348210063482101605 +:1070E00003E00008AC623D0427BDFFE0AFB0001034 +:1070F000309000FF2E020006AFBF001810400008BD +:10710000AFB10014001030803C03080024635784A2 +:1071100000C328218CA400000080000800000000AB +:10712000000020218FBF00188FB100148FB0001015 +:107130000080102103E0000827BD00209791002A5D +:1071400016200051000020213C020800904200332C +:107150000A0006BB00000000978D002615A0003134 +:10716000000020210A0006BB2402000897870024A3 +:1071700014E0001A00001821006020212402000100 +:107180001080FFE98FBF0018000429C2004530219C +:1071900000A6582B1160FFE43C0880003C0720004B +:1071A000000569C001A76025AD0C00203C038008E4 +:1071B0002402001F2442FFFFAC6000000441FFFDD9 +:1071C0002463000424A5000100A6702B15C0FFF560 +:1071D000000569C00A0006A58FBF00189787001C2C +:1071E0003C04080024845A58240504000E0006605C +:1071F00024060001978B002424440001308AFFFFFD +:107200002569FFFF2D48040000402821150000409B +:10721000A789002424AC3800000C19C00A0006B964 +:10722000A780001C9787001E3C04080024845AD8BD +:10723000240504000E00066024060001979900262C +:10724000244400013098FFFF272FFFFF2F0E04007A +:107250000040882115C0002CA78F0026A780001EA3 +:107260003A020003262401003084FFFF0E00068D41 +:107270002C4500010011F8C027F00100001021C0CA +:107280000A0006BB240200089785002E978700227B +:107290003C04080024845B580E00066024060001AC +:1072A0009787002A8F89002C2445000130A8FFFF12 +:1072B00024E3FFFF0109302B0040802114C0001897 +:1072C000A783002AA7800022978500300E000F7543 +:1072D00002002021244A05003144FFFF0E00068DE4 +:1072E000240500013C05080094A500320E000F752E +:1072F00002002021244521003C0208009042003376 +:107300000A0006BB000521C00A0006F3A784001E80 +:1073100024AC3800000C19C00A0006B9A784001C70 +:107320000A00070DA7850022308400FF27BDFFE873 +:107330002C820006AFBF0014AFB000101040001543 +:1073400000A03821000440803C0308002463579CBF +:10735000010328218CA40000008000080000000028 +:1073600024CC007F000751C2000C59C23170FFFFCE +:107370002547C40030E5FFFF2784001C02003021B0 +:107380000E0005B52407000197860028020620217B +:10739000A78400288FBF00148FB0001003E00008FE +:1073A00027BD00183C0508008CA50030000779C2F5 +:1073B0000E00038125E4DF003045FFFF3C04080098 +:1073C00024845B58240600010E0005B52407000143 +:1073D000978E002A8FBF00148FB0001025CD0001BA +:1073E00027BD001803E00008A78D002A0007C9C2C6 +:1073F0002738FF00001878C231F0FFFF3C04080076 +:1074000024845AD802002821240600010E0005B564 +:1074100024070001978D0026260E0100000E84002F +:1074200025AC00013C0B6000A78C0026AD603D0838 +:1074300036040006000030213C0760008CE23D0469 +:10744000305F000617E0FFFD24C9000100061B00A5 +:10745000312600FF006440252CC50004ACE83D0443 +:1074600014A0FFF68FBF00148FB0001003E00008D7 +:1074700027BD0018000751C22549C8002406000195 +:10748000240700013C04080024845A580E0005B566 +:107490003125FFFF978700248FBF00148FB00010A5 +:1074A00024E6000127BD001803E00008A786002499 +:1074B0003C0660183C090800252900FCACC9502C8A +:1074C0008CC850003C0580003C020002350700805B +:1074D000ACC750003C04080024841FE03C030800B3 +:1074E00024631F98ACA50008ACA2000C3C01080066 +:1074F000AC2459A43C010800AC2359A803E00008BF +:107500002402000100A030213C1C0800279C59AC3B +:107510003C0C04003C0B0002008B3826008C4026FB +:107520002CE200010007502B2D050001000A4880C5 +:107530003C030800246359A4004520250123182199 +:107540001080000300001021AC660000240200013E +:1075500003E00008000000003C1C0800279C59AC18 +:107560003C0B04003C0A0002008A3026008B3826BF +:107570002CC200010006482B2CE5000100094080C8 +:107580003C030800246359A4004520250103182169 +:1075900010800005000010213C0C0800258C1F986D +:1075A000AC6C00002402000103E0000800000000B1 +:1075B0003C0900023C080400008830260089382677 +:1075C0002CC30001008028212CE400010083102539 +:1075D0001040000B000030213C1C0800279C59ACD7 +:1075E0003C0A80008D4E00082406000101CA68256F +:1075F000AD4D00088D4C000C01855825AD4B000C9D +:1076000003E0000800C010213C1C0800279C59AC76 +:107610003C0580008CA6000C0004202724020001F9 +:1076200000C4182403E00008ACA3000C3C020002D4 +:107630001082000B3C0560003C070400108700032B +:107640000000000003E00008000000008CA908D042 +:10765000240AFFFD012A402403E00008ACA808D05A +:107660008CA408D02406FFFE0086182403E000083E +:10767000ACA308D03C05601A34A600108CC300806F +:1076800027BDFFF88CC50084AFA3000093A40000C1 +:107690002402001010820003AFA5000403E00008DC +:1076A00027BD000893A7000114E0001497AC000266 +:1076B00097B800023C0F8000330EFFFC01CF682119 +:1076C000ADA50000A3A000003C0660008CC708D058 +:1076D0002408FFFE3C04601A00E82824ACC508D04A +:1076E0008FA300048FA200003499001027BD00086A +:1076F000AF22008003E00008AF2300843C0B800031 +:10770000318AFFFC014B48218D2800000A00080C3B +:10771000AFA8000427BDFFE8AFBF00103C1C080065 +:10772000279C59AC3C0580008CA4000C8CA2000462 +:107730003C0300020044282410A0000A00A31824DF +:107740003C0604003C0400021460000900A610245A +:107750001440000F3C0404000000000D3C1C080015 +:10776000279C59AC8FBF001003E0000827BD00180C +:107770003C0208008C4259A40040F80900000000B7 +:107780003C1C0800279C59AC0A0008358FBF00102C +:107790003C0208008C4259A80040F8090000000093 +:1077A0000A00083B000000003C0880008D0201B880 +:1077B0000440FFFE35090180AD2400003C031000A9 +:1077C00024040040AD250004A1240008A1260009DE +:1077D000A527000A03E00008AD0301B83084FFFFCD +:1077E0000080382130A5FFFF000020210A00084555 +:1077F000240600803087FFFF8CA400002406003898 +:107800000A000845000028218F8300788F860070C9 +:107810001066000B008040213C07080024E75B68ED +:10782000000328C000A710218C440000246300013D +:10783000108800053063000F5466FFFA000328C06B +:1078400003E00008000010213C07080024E75B6CFF +:1078500000A7302103E000088CC200003C03900028 +:1078600034620001008220253C038000AC640020CB +:107870008C65002004A0FFFE0000000003E000086B +:10788000000000003C0280003443000100832025FA +:1078900003E00008AC44002027BDFFE0AFB10014B6 +:1078A0003091FFFFAFB00010AFBF001812200013DF +:1078B00000A080218CA20000240400022406020003 +:1078C0001040000F004028210E0007250000000096 +:1078D00000001021AE000000022038218FBF0018E8 +:1078E0008FB100148FB0001000402021000028212B +:1078F000000030210A00084527BD00208CA20000AE +:10790000022038218FBF00188FB100148FB00010F3 +:107910000040202100002821000030210A000845F5 +:1079200027BD002000A010213087FFFF8CA5000498 +:107930008C4400000A000845240600068F83FD9C45 +:1079400027BDFFE8AFBF0014AFB00010906700087C +:10795000008010210080282130E600400000202116 +:1079600010C000088C5000000E0000BD0200202155 +:10797000020020218FBF00148FB000100A000548BC +:1079800027BD00180E0008A4000000000E0000BD76 +:1079900002002021020020218FBF00148FB00010B0 +:1079A0000A00054827BD001827BDFFE0AFB0001052 +:1079B0008F90FD9CAFBF001CAFB20018AFB1001498 +:1079C00092060001008088210E00087230D2000467 +:1079D00092040005001129C2A6050000348300406E +:1079E000A20300050E00087C022020210E00054A9B +:1079F0000220202124020001AE02000C02202821D6 +:107A0000A602001024040002A602001224060200AE +:107A1000A60200140E000725A60200161640000F4D +:107A20008FBF001C978C00743C0B08008D6B007896 +:107A30002588FFFF3109FFFF256A0001012A382B45 +:107A400010E00006A78800743C0F6006240E0016A4 +:107A500035ED0010ADAE00508FBF001C8FB2001886 +:107A60008FB100148FB0001003E0000827BD002084 +:107A700027BDFFE0AFB10014AFBF0018AFB00010DA +:107A80001080000400A088212402008010820007DA +:107A9000000000000000000D8FBF00188FB100141F +:107AA0008FB0001003E0000827BD00200E00087210 +:107AB00000A020218F86FD9C0220202190C500057A +:107AC0000E00087C30B000FF2403003E1603FFF1D7 +:107AD0003C0680008CC401780480FFFE34C801405D +:107AE000240900073C071000AD11000002202021EE +:107AF000A10900048FBF00188FB100148FB00010CF +:107B0000ACC701780A0008C527BD002027BDFFE0EB +:107B1000AFB00010AFBF0018AFB100143C10800030 +:107B20008E110020000000000E00054AAE04002067 +:107B3000AE1100208FBF00188FB100148FB000105D +:107B400003E0000827BD00203084FFFF00803821BB +:107B50002406003500A020210A0008450000282145 +:107B60003084FFFF008038212406003600A0202149 +:107B70000A0008450000282127BDFFD0AFB500242A +:107B80003095FFFFAFB60028AFB40020AFBF002C88 +:107B9000AFB3001CAFB20018AFB10014AFB000100B +:107BA00030B6FFFF12A000270000A0218F920058DE +:107BB0008E4300003C0680002402004000033E0289 +:107BC00000032C0230E4007F006698241482001D1C +:107BD00030A500FF8F8300682C68000A1100001098 +:107BE0008F8D0044000358803C0C0800258C57B84A +:107BF000016C50218D4900000120000800000000A8 +:107C000002D4302130C5FFFF0E0008522404008446 +:107C1000166000028F920058AF8000688F8D00447C +:107C20002659002026980001032090213314FFFFDD +:107C300015A00004AF9900580295202B1480FFDC9A +:107C400000000000028010218FBF002C8FB600289A +:107C50008FB500248FB400208FB3001C8FB20018A2 +:107C60008FB100148FB0001003E0000827BD003072 +:107C70002407003414A70149000000009247000EB9 +:107C80008F9FFDA08F90FD9C24181600A3E700197C +:107C90009242000D3C0880003C07800CA3E20018D3 +:107CA000964A00123C0D60003C117FFFA60A005C62 +:107CB000964400103623FFFF240200053099FFFF91 +:107CC000AE1900548E46001CAD1800288CEF000041 +:107CD0008DAE444801E6482601C93021AE06003881 +:107CE0008E05003824CB00013C0E7F00AE05003C21 +:107CF0008E0C003CAFEC0004AE0B00208E13002075 +:107D0000AE13001CA3E0001BAE03002CA3E2001284 +:107D10008E4A001424130050AE0A00348E0400343E +:107D2000AFE400148E590018AE1900489258000CA8 +:107D3000A218004E920D000835AF0020A20F0008D7 +:107D40008E090018012E282434AC4000AE0C001817 +:107D5000920B0000317200FF1253027F2403FF8058 +:107D60003C04080024845BE80E0008AA0000000020 +:107D70003C1108008E315BE80E00087202202021C1 +:107D80002405000424080001A2050025022020216A +:107D90000E00087CA20800053C0580008CB001782C +:107DA0000600FFFE8F92005834AE0140240F0002FF +:107DB0003C091000ADD10000A1CF0004ACA90178AE +:107DC0000A000962AF8000682CAD003751A0FF9413 +:107DD0008F8D0044000580803C110800263157E05B +:107DE000021178218DEE000001C0000800000000A3 +:107DF0002411000414B1008C3C0780003C080800EA +:107E00008D085BE88F86FD9CACE800208E4500085D +:107E10008F99FDA0240D0050ACC500308E4C000899 +:107E2000ACCC00508E4B000CACCB00348E43001019 +:107E3000ACC300388E4A0010ACCA00548E42001405 +:107E4000ACC2003C8E5F0018AF3F00048E50001C97 +:107E5000ACD0002090C40000309800FF130D024AFF +:107E6000000000008CC400348CD00030009030231F +:107E700004C000F12404008C126000EE2402000310 +:107E80000A000962AF8200682419000514B900666F +:107E90003C0580003C0808008D085BE88F86FD9C4F +:107EA000ACA800208E4C00048F8AFDA0240720007F +:107EB000ACCC001C924B000824120008A14B001906 +:107EC0008F82005890430009A14300188F85005805 +:107ED00090BF000A33E400FF1092001028890009C7 +:107EE000152000BA240E0002240D0020108D000B76 +:107EF000340780002898002117000008240740005C +:107F000024100040109000053C0700012419008057 +:107F1000109900023C070002240740008CC20018A0 +:107F20003C03FF00004350240147F825ACDF001854 +:107F300090B2000BA0D200278F8300589464000CED +:107F4000108001FE000000009467000C3C1F8000C0 +:107F50002405FFBFA4C7005C9063000E2407000443 +:107F6000A0C300088F820058904A000FA0CA0009E1 +:107F70008F8900588D3200108FE400740244C823AA +:107F8000ACD900588D300014ACD0002C95380018B6 +:107F9000330DFFFFACCD00409531001A322FFFFFAB +:107FA000ACCF00448D2E001CACCE00489128000EB2 +:107FB000A0C8000890CC000801855824126001B6C2 +:107FC000A0CB00088F9200580A000962AF870068B2 +:107FD0002406000614A600143C0E80003C0F080086 +:107FE0008DEF5BE88F85FD98ADCF00208E4900189E +:107FF0008F86FD9C8F8BFDA0ACA900008CC800383B +:1080000024040005ACA800048CCC003C1260008164 +:10801000AD6C00000A000962AF84006824110007FB +:1080200010B1004B240400063C05080024A55BE8C1 +:108030000E000881240400818F9200580013102B39 +:108040000A000962AF820068241F002314BFFFF6F4 +:108050003C0C80003C0508008CA55BE88F8BFDA0E4 +:10806000AD8500208F91FD9C8E4600042564002084 +:1080700026450014AE260028240600030E000F81BA +:10808000257000308F87005802002021240600034D +:108090000E000F8124E500083C04080024845BE8FE +:1080A0000E0008AA0000000092230000240A0050DD +:1080B000306200FF544AFFE18F9200580E000F6CAF +:1080C000000000000A000A6A8F920058240800335A +:1080D00014A800323C0380003C1108008E315BE89C +:1080E0008F8FFDA0AC7100208E420008240D002867 +:1080F0008F89FD9CADE200308E4A000C24060009F9 +:10810000ADEA00348E5F0010ADFF00388E440014DD +:10811000ADE400208E590018ADF900248E58001CE3 +:10812000ADF80028A1ED00118E4E00041260003160 +:10813000AD2E00288F9200580A000962AF860068B1 +:10814000240D002214ADFFB8000000002404000735 +:108150003C1008008E105BE83C188000AF10002037 +:108160005660FEAEAF8400683C04080024845BE8DF +:108170000E0008AA241300508F84FD9C90920000EA +:10818000325900FF1333014B000000008F9200585A +:10819000000020210A000962AF8400683C05080045 +:1081A00024A55BE80E000858240400810A000A6A2E +:1081B0008F92005802D498213265FFFF0E000852BA +:1081C000240400840A0009628F920058108EFF5325 +:1081D000240704002887000310E00179241100041B +:1081E000240F0001548FFF4D240740000A000A228B +:1081F000240701003C05080024A55BE80E0008A444 +:10820000240400828F920058000030210A00096285 +:10821000AF8600683C04080024845BE88CC2003808 +:108220000E0008AA8CC3003C8F9200580A000AC0B6 +:1082300000002021240400823C05080024A55BE8FE +:108240000E0008A4000000008F92005800001021CA +:108250000A000962AF8200688E5000048F91FD9C75 +:108260003C078000ACF00020922C00050200282181 +:10827000318B0002156001562404008A8F92FDA004 +:108280002404008D9245001B30A6002014C001502C +:1082900002002821922E00092408001231C900FF93 +:1082A0001128014B240400810E00087202002021D5 +:1082B0009258001B240F000402002021370D0042B9 +:1082C000A24D001B0E00087CA22F00253C0580005B +:1082D0008CA401780480FFFE34B90140241F000201 +:1082E000AF300000A33F00048F9200583C101000F4 +:1082F000ACB001780A000A6B0013102B8E500004FA +:108300008F91FD9C3C038000AC700020922A0005F8 +:108310000200282131420002144000172404008A80 +:10832000922C00092412000402002821318B00FF46 +:1083300011720011240400810E0008720200202135 +:108340008F89FDA0240800122405FFFE912F001B39 +:108350000200202135EE0020A12E001BA2280009DA +:108360009226000500C538240E00087CA2270005CF +:1083700002002821000020210E0009330000000027 +:108380000A000A6A8F9200588E4C00043C07800055 +:108390003C10080026105BE8ACEC00203C01080013 +:1083A000AC2C5BE8924B0003317100041220013BBE +:1083B0008F84FD9C24020006A0820009924F001BBE +:1083C000240EFFC031E9003F012E4025A08800089F +:1083D0009245000330A6000114C0013200000000E5 +:1083E0008E420008AE0200083C0208008C425BF09E +:1083F000104001318F90FDA0000219C28F8DFD9CAD +:10840000A603000C8E4A000C24180001240400145A +:10841000AE0A002C8E420010AE02001C965F0016C1 +:10842000A61F003C96590014A619003EADB8000CDA +:10843000A5B80010A5B80012A5B80014A5B800167C +:1084400012600144A2040011925100033232000272 +:108450002E5300018F920058266200080A0009621C +:10846000AF8200688E4400043C1980003C068008FE +:10847000AF2400208E45000890D80000240D005045 +:10848000331100FF122D009C2407008824060009E8 +:108490000E000845000000000A000A6A8F9200588A +:1084A0008E5000043C0980003C118008AD30002053 +:1084B0009228000024050050310400FF10850110AF +:1084C0002407008802002021000028210E00084512 +:1084D0002406000E922D00002418FF80020028219F +:1084E00001B8802524040004240600300E0007256E +:1084F000A23000000A000A6A8F9200588E500004D1 +:108500008F91FDA03C028000AC500020923F001BE8 +:1085100033F900101320006C240700810200202191 +:10852000000028212406001F0E000845000000005E +:108530000A000A6A8F9200588E44001C0E00085DE3 +:1085400000000000104000E3004048218F880058E0 +:1085500024070089012020218D05001C240600012C +:108560000E000845000000000A000A6A8F920058B9 +:10857000964900023C10080026105BE831280004F0 +:10858000110000973C0460008E4E001C3C0F8000E0 +:10859000ADEE00203C010800AC2E5BE896470002DF +:1085A00030E40001148000E6000000008E42000468 +:1085B000AE0200083C1008008E105BF0120000ECC8 +:1085C0003C0F80008F92FD9C241000018E4E0018FD +:1085D0008F8DFDA08F9FFD9801CF4825AE490018D3 +:1085E000A2400005AE50000C3C0808008D085BF06E +:1085F0008F840058A6500010000839C2A6500012FF +:10860000A6500014A6500016A5A7000C8C8C0008DC +:108610008F8B00588F8A0058ADAC002C8D63000CF6 +:1086200024070002ADA3001C91460010A1A6001172 +:108630008F82005890450011A3E500088F990058DB +:1086400093380012A258004E8F910058922F0013B9 +:10865000A1AF00128F920058964E0014A5AE003CB8 +:1086600096490016A5A9003E8E480018ADA8001432 +:108670005660FD6AAF8700683C05080024A55BE8EA +:108680000E000881000020218F9200580000382140 +:108690000A000962AF8700683C05080024A55BE872 +:1086A0000E0008A4240400828F9200580A000A4D8C +:1086B000000038210E000F6C000000008F9200585F +:1086C0000A000AC0000020210E00087202002021CA +:1086D0009223001B02002021346A00100E00087C47 +:1086E000A22A001B000038210200202100002821BE +:1086F0000A000BA52406001F9242000C305F000107 +:1087000013E0000300000000964A000EA4CA002CEB +:10871000924B000C316300025060000600003821CB +:108720008E470014964C0012ACC7001CA4CC001A53 +:10873000000038210A000B7F240600093C050800D0 +:1087400024A55BE80E0008A42404008B8F92005837 +:108750000A000A4D0013382B3C0C08008D8C5BE896 +:1087600024DFFFFE25930100326B007F016790211B +:1087700002638824AD110028AE4600E0AE4000E45C +:108780000A0009B3AE5F001CACC000543C0D0800E9 +:108790008DAD5BE83C18800C37090100ACED00287A +:1087A0008E510014AD3100E08E4F0014AD2F00E467 +:1087B0008E4E001025C7FFFE0A0009F4AD27001CED +:1087C0005491FDD6240740000A000A222407100015 +:1087D0000E00092D000000000A000A6A8F9200585E +:1087E0008C83442C3C12DEAD3651BEEF3C010800B8 +:1087F000AC205BE810710062000000003C196C6264 +:1088000037387970147800082404000297850074C2 +:108810009782006C2404009200A2F82B13E0001948 +:1088200002002821240400020E00069524050200FF +:108830003C068000ACC200203C010800AC225BE892 +:108840001040000D8F8C0058240A002824040003D7 +:10885000918B0010316300FF546A00012404000171 +:108860000E0000810000000010400004240400837A +:108870000A000BC28F920058240400833C050800B4 +:1088800024A55BE80E000881000000008F920058CC +:108890000013382B0A000962AF8700680A000B49F1 +:1088A000240200128E4400080E00085D0000000043 +:1088B0000A000B55AE0200083C05080024A55BE841 +:1088C0000E000858240400878F9200580A000B728B +:1088D0000013102B240400040E000695240500301C +:1088E0001440002A004048218F8800582407008344 +:1088F000012020218D05001C0A000BB32406000175 +:108900008F8300788F8600701066FEEE000038219D +:108910003C07080024E75B6C000320C00087282187 +:108920008CAE000011D0005D246F000131E3000F18 +:108930005466FFFA000320C00A000B8C00003821A7 +:108940008E4400040E00085D000000000A000BC801 +:10895000AE0200083C05080024A55BE80E0008A450 +:10896000240400828F9200580A000B72000010212C +:108970003C05080024A55BE80A000C7C2404008761 +:108980008C83442C0A000C5B3C196C628F88005865 +:108990003C0780083C0C8000240B0050240A000196 +:1089A000AD820020A0EB0000A0EA000191030004CA +:1089B000A0E3001891040005A0E400199106000648 +:1089C0003C04080024845B6CA0E6001A91020007B6 +:1089D0003C06080024C65B68A0E2001B9105000865 +:1089E000A0E5001C911F0009A0FF001D9119000ABD +:1089F000A0F9001E9118000BA0F8001F9112000CA6 +:108A0000A0F200209111000DA0F100219110000EA4 +:108A1000A0F00022910F000FA0EF0023910E001094 +:108A2000A0EE0024910D0011A0ED0025950C00147E +:108A3000A4EC0028950B00168F8A00708F920078A6 +:108A4000A4EB002A95030018000A10C02545000178 +:108A5000A4E3002C8D1F001C0044C0210046C82147 +:108A600030A5000FAF3F0000AF09000010B20006B4 +:108A7000AF850070000038218D05001C01202021E9 +:108A80000A000BB32406000124AD000131A7000F3A +:108A9000AF8700780A000CF9000038213C06080076 +:108AA00024C65B680086902100003821ACA000003D +:108AB0000A000B8CAE4000003C0482013C036000C5 +:108AC00034820E02AC603D68AF80009803E000087D +:108AD000AC623D6C27BDFFE8AFB000103090FFFFE7 +:108AE000001018422C620041AFBF00141440000275 +:108AF00024040080240300403C010800AC300060E6 +:108B00003C010800AC2300640E000F7500602821B2 +:108B1000244802BF2409FF8001092824001039805D +:108B2000001030408FBF00148FB0001000A720212C +:108B300000861821AF8300803C010800AC25005856 +:108B40003C010800AC24005C03E0000827BD0018CD +:108B5000308300FF30C6FFFF30E400FF3C08800098 +:108B60008D0201B80440FFFE000354000144382583 +:108B70003C09600000E920253C031000AD050180A0 +:108B8000AD060184AD04018803E00008AD0301B81F +:108B90008F8500583C0A6012354800108CAC0004E8 +:108BA0003C0D600E35A60010318B00062D690001CA +:108BB000AD0900C48CA70004ACC731808CA20008AA +:108BC00094A40002ACC231848CA3001C0460000396 +:108BD000A784009003E00008000000008CAF00189C +:108BE000ACCF31D08CAE001C03E00008ACCE31D449 +:108BF0008F8500588F87FF288F86FF308CAE00044A +:108C00003C0F601235E80010ACEE00788CAD000827 +:108C1000ACED007C8CAC0010ACCC004C8CAB000CF0 +:108C2000ACCB004894CA00543C0208008C4200447B +:108C300025490001A4C9005494C400543083FFFFA7 +:108C400010620017000000003C0208008C42004047 +:108C5000A4C200528CA30018ACE300308CA2001414 +:108C6000ACE2002C8CB90018ACF900388CB80014B8 +:108C700024050001ACF800348D0600BC50C5001975 +:108C80008D0200B48D0200B8A4E2004894E40048CC +:108C9000A4E4004A94E800EA03E000083102FFFF80 +:108CA0003C0208008C420024A4C00054A4C200521C +:108CB0008CA30018ACE300308CA20014ACE2002CB2 +:108CC0008CB90018ACF900388CB8001424050001E8 +:108CD000ACF800348D0600BC54C5FFEB8D0200B823 +:108CE0008D0200B4A4E2004894E40048A4E4004AE1 +:108CF00094E800EA03E000083102FFFF8F86005885 +:108D00003C0480008CC900088CC80008000929C0F8 +:108D1000000839C0AC87002090C30007306200040F +:108D20001040003EAF85009490CB0007316A0008E8 +:108D30001140003D8F87FF2C8CCD000C8CCE001491 +:108D400001AE602B11800036000000008CC2000CC8 +:108D5000ACE200708CCB00188F85FF288F88FF3025 +:108D6000ACEB00748CCA00102402FFF8ACAA00D847 +:108D70008CC9000CAD0900608CC4001CACA400D0F0 +:108D800090E3007C0062C824A0F9007C90D8000722 +:108D9000330F000811E000040000000090ED007C9B +:108DA00035AC0001A0EC007C90CF000731EE000153 +:108DB00011C000060000000090E3007C241800347D +:108DC00034790002A0F9007CACB800DC90C2000746 +:108DD0003046000210C000040000000090E8007C53 +:108DE00035040004A0E4007C90ED007D3C0B600E97 +:108DF000356A001031AC003FA0EC007D8D4931D4C4 +:108E00003127000110E00002240E0001A0AE00098D +:108E100094AF00EA03E0000831E2FFFF8F87FF2CE8 +:108E20000A000DAF8CC200140A000DB0ACE0007057 +:108E30008F8C005827BDFFD8AFB3001CAFB200180D +:108E4000AFB00010AFBF0020AFB10014918F00157C +:108E50003C13600E3673001031EB000FA38B009CA7 +:108E60008D8F00048D8B0008959F0012959900103E +:108E70009584001A9598001E958E001C33EDFFFF17 +:108E8000332AFFFF3089FFFF3308FFFF31C7FFFFA1 +:108E90003C010800AC2D00243C010800AC29004432 +:108EA0003C010800AC2A0040AE683178AE67317CE6 +:108EB00091850015959100163C12601236520010F3 +:108EC00030A200FF3230FFFFAE623188AE5000B4F6 +:108ED00091830014959F0018240600010066C804C1 +:108EE00033F8FFFFAE5900B8AE5800BC918E0014A5 +:108EF000AF8F00843C08600631CD00FFAE4D00C04E +:108F0000918A00159584000E3C07600A314900FFE4 +:108F1000AF8B00883084FFFFAE4900C835110010C8 +:108F20000E000D1034F004103C0208008C4200606A +:108F30003C0308008C6300643C0608008CC60058A3 +:108F40003C0508008CA5005C8F8400808FBF00204A +:108F5000AE23004CAE65319CAE030054AE4500DC40 +:108F6000AE6231A0AE6331A4AE663198AE22004845 +:108F70008FB3001CAE0200508FB10014AE4200E06F +:108F8000AE4300E4AE4600D88FB000108FB2001898 +:108F90000A00057D27BD0028978500929783007CF5 +:108FA00027BDFFE8AFB0001000A3102BAFBF001427 +:108FB000240400058F900058104000552409000239 +:108FC0000E0006958F850080AF8200942404000374 +:108FD0001040004F240900023C0680000E00008172 +:108FE000ACC2002024070001240820001040004DDE +:108FF00024040005978E00928F8AFF2C24090050CC +:1090000025C50001A7850092A14900003C0D08007C +:109010008DAD0064240380008F84FF28000D66005E +:10902000AD4C0018A5400006954B000A8F85FF3017 +:109030002402FF8001633024A546000A915F000AE4 +:109040000000482103E2C825A159000AA0A0000899 +:10905000A140004CA08000D5961800029783009094 +:109060003C020004A49800EA960F00022418FFBFF7 +:1090700025EE2401A48E00BE8E0D0004ACAD00448C +:109080008E0C0008ACAC0040A4A00050A4A000547A +:109090008E0B000C240C0030AC8B00288E060010C8 +:1090A000AC860024A480003EA487004EA487005014 +:1090B000A483003CAD420074AC8800D8ACA800602A +:1090C000A08700FC909F00D433F9007FA09900D4C2 +:1090D000909000D402187824A08F00D4914E007C88 +:1090E00035CD0001A14D007C938B009CAD480070F4 +:1090F000AC8C00DCA08B00D68F8800888F87008422 +:10910000AC8800C4AC8700C8A5400078A540007AB0 +:109110008FBF00148FB000100120102103E0000861 +:1091200027BD00188F8500940E0007258F860080CC +:109130000A000E9F2409000227BDFFE0AFB0001017 +:109140008F900058AFB10014AFBF00188E09000413 +:109150000E00054A000921C08E0800048F84FF28F4 +:109160008F82FF30000839C03C068000ACC7002069 +:10917000948500EA904300131460001C30B1FFFF97 +:109180008F8CFF2C918B0008316A00401540000B3A +:10919000000000008E0D0004022030218FBF001857 +:1091A0008FB100148FB00010240400220000382179 +:1091B000000D29C00A000D2F27BD00200E000098C9 +:1091C000000000008E0D0004022030218FBF001827 +:1091D0008FB100148FB00010240400220000382149 +:1091E000000D29C00A000D2F27BD00200E000090A1 +:1091F000000000008E0D0004022030218FBF0018F7 +:109200008FB100148FB00010240400220000382118 +:10921000000D29C00A000D2F27BD002027BDFFE04B +:10922000AFB200183092FFFFAFB00010AFBF001C0C +:10923000AFB100141240001E000080218F8600583C +:109240008CC500002403000600053F02000514023F +:1092500030E4000714830016304500FF2CA80006F8 +:1092600011000040000558803C0C0800258C58BCBB +:10927000016C50218D490000012000080000000011 +:109280008F8E0098240D000111CD005024020002A1 +:10929000AF820098260900013130FFFF24C800206A +:1092A0000212202B010030211480FFE5AF88005806 +:1092B000020010218FBF001C8FB200188FB1001464 +:1092C0008FB0001003E0000827BD00209387007EC8 +:1092D00054E00034000030210E000DE700000000D3 +:1092E0008F8600580A000EFF240200018F87009825 +:1092F0002405000210E50031240400130000282199 +:1093000000003021240700010E000D2F0000000096 +:109310000A000F008F8600588F83009824020002F5 +:109320001462FFF6240400120E000D9A00000000E3 +:109330008F85009400403021240400120E000D2F70 +:10934000000038210A000F008F8600588F83009894 +:109350002411000310710029241F0002107FFFCE8A +:1093600026090001240400100000282100003021FB +:109370000A000F1D240700018F91009824060002A7 +:109380001626FFF9240400100E000E410000000014 +:10939000144000238F9800588F8600580A000EFF53 +:1093A00024020003240400140E000D2F00002821C5 +:1093B0008F8600580A000EFF240200020E000EA93C +:1093C000000000000A000F008F8600580E000D3FBD +:1093D00000000000241900022404001400002821C9 +:1093E0000000302100003821AF9900980E000D2FA9 +:1093F000000000000A000F008F8600580E000D5775 +:10940000000000008F8500942419000200403021E4 +:1094100024040010000038210A000F56AF9900986C +:109420000040382124040010970F0002000028217A +:109430000E000D2F31E6FFFF8F8600580A000F0047 +:10944000AF9100988F84FF2C3C077FFF34E6FFFF2D +:109450008C8500182402000100A61824AC83001893 +:1094600003E00008A08200053084FFFF30A5FFFF65 +:109470001080000700001821308200011040000217 +:1094800000042042006518211480FFFB00052840DD +:1094900003E000080060102110C000070000000079 +:1094A0008CA2000024C6FFFF24A50004AC820000AB +:1094B00014C0FFFB2484000403E000080000000047 +:1094C00010A0000824A3FFFFAC86000000000000ED +:1094D000000000002402FFFF2463FFFF1462FFFA74 +:1094E0002484000403E0000800000000000411C010 +:1094F00003E000082442024027BDFFE8AFB000109F +:1095000000808021AFBF00140E000F9600A0202124 +:1095100000504821240AFF808FBF00148FB0001034 +:10952000012A30243127007F3C08800A3C042100B6 +:1095300000E8102100C428253C03800027BD001846 +:10954000AC650024AF820038AC400000AC6500245C +:1095500003E00008AC4000403C0D08008DAD005811 +:1095600000056180240AFF8001A45821016C482174 +:10957000012A30243127007F3C08800C3C04210064 +:1095800000E8102100C428253C038000AC650028B9 +:10959000AF82003403E00008AC40002430A5FFFF98 +:1095A0003C0680008CC201B80440FFFE3C086015F8 +:1095B00000A838253C031000ACC40180ACC0018475 +:1095C000ACC7018803E00008ACC301B83C0D08003B +:1095D0008DAD005800056180240AFF8001A4582148 +:1095E000016C4021010A4824000931403107007F05 +:1095F00000C728253C04200000A418253C02800058 +:10960000AC43083003E00008AF80003427BDFFE81A +:10961000AFB0001000808021AFBF00140E000F9685 +:1096200000A0202100504821240BFF80012B502452 +:10963000000A39403128007F3C0620008FBF00140B +:109640008FB0001000E8282534C2000100A21825C0 +:109650003C04800027BD0018AC83083003E00008FC +:10966000AF8000383C0580088CA700603C0680086D +:109670000087102B144000112C8340008CA8006040 +:109680002D0340001060000F240340008CC90060CF +:109690000089282B14A00002008018218CC30060D0 +:1096A00000035A42000B30803C0A0800254A59202A +:1096B00000CA202103E000088C8200001460FFF340 +:1096C0002403400000035A42000B30803C0A08008B +:1096D000254A592000CA202103E000088C8200009E +:1096E0003C05800890A60008938400AB24C20001CA +:1096F000304200FF3043007F1064000C0002382726 +:10970000A0A200083C0480008C85017804A0FFFE24 +:109710008F8A00A0240900023C081000AC8A014096 +:10972000A089014403E00008AC8801780A00101BFE +:1097300030E2008027BDFFD8AFB200188F9200A49E +:10974000AFBF0020AFB3001CAFB00010AFB100142A +:109750008F9300348E5900283C1000803C0EFFEFA0 +:10976000AE7900008E580024A260000A35CDFFFFBC +:10977000AE7800049251002C3C0BFF9F356AFFFF2E +:10978000A271000C8E6F000C3C080040A271000B0F +:1097900001F06025018D4824012A382400E8302595 +:1097A000AE66000C8E450004AE6000183C0400FF5D +:1097B000AE6500148E43002C3482FFFFA6600008C3 +:1097C0000062F824AE7F00108E5900088F9000A030 +:1097D000964E0012AE7900208E51000C31D83FFF1A +:1097E00000187980AE7100248E4D001401F06021C4 +:1097F00031CB0001AE6D00288E4A0018000C41C22A +:10980000000B4B80AE6A002C8E46001C01093821EB +:10981000A667001CAE660030964500028E4400200C +:10982000A665001EAE64003492430033306200042B +:1098300054400006924700003C0280083443010077 +:109840008C7F00D0AE7F0030924700008F860038BA +:10985000A0C700309245003330A4000250800007BA +:10986000925100018F880038240BFF80910A00304C +:10987000014B4825A1090030925100018F9000381A +:10988000240CFFBF2404FFDFA21100318F8D0038AC +:109890003C1880083711008091AF003C31EE007F0A +:1098A000A1AE003C8F890038912B003C016C502404 +:1098B000A12A003C8F9F00388E68001493E6003C7C +:1098C0002D0700010007114000C4282400A218251C +:1098D000A3E3003C8F87003896590012A4F90032A8 +:1098E0008E450004922E007C30B0000300107823D7 +:1098F00031ED000300AD102131CC000215800002D3 +:1099000024460034244600303C0280083443008062 +:10991000907F007C00BFC824333800041700000289 +:1099200024C2000400C010218F98003824190002BE +:10993000ACE20034A3190000924F003F8F8E003834 +:109940003C0C8008358B0080A1CF00018F9100383E +:10995000924D003F8E440004A62D0002956A005CE3 +:109960000E000FF43150FFFF00024B800209382532 +:109970003C08420000E82825AE2500048E4400384B +:109980008F850038ACA400188E460034ACA6001CAD +:10999000ACA0000CACA00010A4A00014A4A0001661 +:1099A000A4A00020A4A00022ACA000248E62001479 +:1099B00050400001240200018FBF00208FB3001C23 +:1099C0008FB200188FB100148FB00010ACA2000845 +:1099D0000A00101327BD002827BDFFC83C058008DA +:1099E00034A40080AFBF0034AFBE0030AFB7002C4E +:1099F000AFB60028AFB50024AFB40020AFB3001C51 +:109A0000AFB20018AFB10014AFB00010948300786B +:109A10009482007A104300512405FFFF0080F0215A +:109A20000A0011230080B821108B004D8FBF003435 +:109A30008F8600A03C1808008F18005C2411FF805E +:109A40003C1680000306782101F18024AED0002C62 +:109A500096EE007A31EC007F3C0D800E31CB7FFF1B +:109A6000018D5021000B4840012AA82196A4000036 +:109A70003C0808008D0800582405FF8030953FFF02 +:109A800001061821001539800067C8210325F82434 +:109A90003C02010003E290253338007F3C11800C2A +:109AA000AED20028031190219250000D320F000415 +:109AB00011E0003702E0982196E3007A96E8007AF8 +:109AC00096E5007A2404800031077FFF24E300013B +:109AD00030627FFF00A4F82403E2C825A6F9007ACB +:109AE00096E6007A3C1408008E94006030D67FFF22 +:109AF00012D400C1000000008E5800188F8400A00E +:109B000002A028212713FFFF0E000FCEAE53002C1A +:109B100097D5007897D4007A12950010000028217C +:109B20003C098008352401003C0A8008914800085F +:109B3000908700D53114007F30E400FF0284302B81 +:109B400014C0FFB9268B0001938E00AB268C000158 +:109B5000008E682115ACFFB78F8600A08FBF003440 +:109B60008FBE00308FB7002C8FB600288FB5002431 +:109B70008FB400208FB3001C8FB200188FB1001477 +:109B80008FB0001000A0102103E0000827BD0038AE +:109B900000C020210E000F99028028218E4B00105A +:109BA0008E4C00308F84003824090002016C502351 +:109BB000AE4A0010A089000096E3005C8E4400309D +:109BC0008F9100380E000FF43070FFFF00024380C9 +:109BD000020838253C02420000E22825AE25000498 +:109BE0008E5F00048F8A00388E590000240B000815 +:109BF000AD5F001CAD590018AD40000CAD40001029 +:109C00009246000A240400052408C00030D000FF5A +:109C1000A550001496580008A55800169251000A45 +:109C20003C188008322F00FFA54F0020964E0008F8 +:109C300037110100A54E0022AD400024924D000BCB +:109C400031AC00FFA54C0002A14B00018E49003051 +:109C50008F830038240BFFBFAC690008A06400307C +:109C60008F9000382403FFDF9607003200E8282495 +:109C700000B51025A6020032921F003233F9003FD2 +:109C800037260040A20600328F8C0038AD800034A9 +:109C90008E2F00D0AD8F0038918E003C3C0F7FFF9F +:109CA00031CD007FA18D003C8F84003835EEFFFF61 +:109CB000908A003C014B4824A089003C8F850038E5 +:109CC00090A8003C01033824A0A7003C8E42003439 +:109CD0008F9100383C038008AE2200408E59002C42 +:109CE0008E5F0030033F3023AE26004492300048A0 +:109CF0003218007FA23800488F8800388E4D00301F +:109D00008D0C004801AE582401965024014B482583 +:109D1000AD0900489244000AA104004C964700088F +:109D20008F850038A4A7004E8E5000308E4400303E +:109D30000E0003818C65006092F9007C0002F940FE +:109D4000004028210002110003E2302133360002D6 +:109D500012C00003020680210005B0800216802197 +:109D6000926D007C31B30004126000020005708027 +:109D7000020E80218E4B00308F8800382405800031 +:109D8000316A0003000A4823312400030204182129 +:109D9000AD03003496E4007A96F0007A96F1007AEA +:109DA00032027FFF2447000130FF7FFF0225C824D5 +:109DB000033F3025A6E6007A96F8007A3C120800A8 +:109DC0008E520060330F7FFF11F200180000000078 +:109DD0008F8400A00E000FCE02A028218F8400A047 +:109DE0000E000FDE028028210E001013000000007C +:109DF0000A00111F0000000096F1007A022480245E +:109E0000A6F0007A92EF007A92EB007A31EE00FF32 +:109E1000000E69C2000D6027000C51C03169007F3F +:109E2000012A20250A001119A2E4007A96E6007A98 +:109E300000C5C024A6F8007A92EF007A92F3007A67 +:109E400031F200FF001271C2000E6827000DB1C090 +:109E5000326C007F01962825A2E5007A0A0011D015 +:109E60008F8400A03C0380003084FFFF30A5FFFFFB +:109E7000AC640018AC65001C03E000088C620014A0 +:109E800027BDFFA03C068008AFBF005CAFBE0058F6 +:109E9000AFB70054AFB60050AFB5004CAFB40048F8 +:109EA000AFB30044AFB20040AFB1003CAFB0003838 +:109EB00034C80100910500D590C700083084FFFF29 +:109EC00030A500FF30E2007F0045182AAFA4001043 +:109ED000A7A00018A7A0002610600055AFA000148E +:109EE00090CA00083149007F00A9302324D3FFFF26 +:109EF0000013802B8FB400100014902B02128824C2 +:109F0000522000888FB300143C03800894790052DB +:109F1000947E00508FB60010033EC0230018BC0092 +:109F2000001714030016FC0002C2A82A16A00002A3 +:109F3000001F2C030040282100133C0000072403CD +:109F400000A4102A5440000100A020212885000907 +:109F500014A000020080A021241400083C0C8008FA +:109F60008D860048001459808D88004C3C03800089 +:109F70003169FFFF3C0A0010012A202534710400DA +:109F8000AC660038AF9100A4AC68003CAC64003013 +:109F900000000000000000000000000000000000C1 +:109FA00000000000000000000000000000000000B1 +:109FB0008C6E000031CD002011A0FFFD0014782A26 +:109FC00001F01024104000390000A8213C16800840 +:109FD00092D700083C1280008E44010032F6007FC8 +:109FE0000E000F9902C028218E3900108E44010006 +:109FF0000000902133373FFF0E000FB102E028210F +:10A00000923800003302003F2C500008520000102C +:10A0100000008821000210803C030800246358E4FB +:10A020000043F8218FFE000003C00008000000007C +:10A0300090CF0008938C00AB31EE007F00AE682318 +:10A04000018D58210A0012172573FFFF0000882197 +:10A050003C1E80008FC401000E000FCE02E02821BC +:10A060008FC401000E000FDE02C028211220000F55 +:10A070000013802B8F8B00A426A400010004AC00E9 +:10A08000027298230015AC032578004002B4B02A70 +:10A090000013802B241700010300882102D0102414 +:10A0A000AF9800A41440FFC9AFB700143C07800864 +:10A0B00094E200508FAE00103C05800002A288217F +:10A0C0003C060020A4F10050ACA6003094F40050EF +:10A0D00094EF005201D51823306CFFFF11F4001EDD +:10A0E000AFAC00108CEF004C001561808CF500487F +:10A0F00001EC28210000202100AC582B02A4C02133 +:10A10000030BB021ACE5004CACF600488FB4001056 +:10A110000014902B021288241620FF7C3C03800838 +:10A120008FB300148FBF005C8FBE00583A620001ED +:10A130008FB700548FB600508FB5004C8FB40048D5 +:10A140008FB300448FB200408FB1003C8FB0003815 +:10A1500003E0000827BD006094FE00548CF2004428 +:10A1600033C9FFFE0009C8C00259F821ACBF003C4A +:10A170008CE800448CAD003C010D50231940003B9D +:10A18000000000008CF7004026E20001ACA200387D +:10A190003C05005034A700103C038000AC67003041 +:10A1A00000000000000000000000000000000000AF +:10A1B000000000000000000000000000000000009F +:10A1C0008C7800003316002012C0FFFD3C1180087F +:10A1D000962200543C1580003C068008304E000159 +:10A1E000000E18C0007578218DEC04003C070800B3 +:10A1F0008CE700443C040020ACCC00488DF40404FF +:10A20000240B0001ACD4004C10EB0260AEA4003073 +:10A21000963900523C0508008CA5004000B99021F9 +:10A22000A6320052963F005427ED0001A62D00549F +:10A230009626005430C4FFFF5487FF2F8FB40010C0 +:10A2400030A5FFFF0E0011F4A62000543C070800C3 +:10A250008CE70024963E00520047B82303D74823DA +:10A26000A62900520A0012198FB400108CE2004097 +:10A270000A0012BE00000000922400012407000121 +:10A280003085007F14A7001C97AD00268E2B00148C +:10A29000240CC000316A3FFF01AC48243C06080092 +:10A2A0008CC60060012A402531043FFF0086882BC0 +:10A2B00012200011A7A800263C0508008CA5005814 +:10A2C0008F9100A0000439802402FF8000B1182182 +:10A2D0000067F82103E2F02433F8007F3C1280008D +:10A2E0003C19800EAE5E002C0319702191D0000D38 +:10A2F000360F0004A1CF000D0E001028241200011B +:10A30000241100013C1E80008FC401000E000FCEFE +:10A3100002E028218FC401000E000FDE02C02821B8 +:10A320001620FF558F8B00A40A0012860013802B85 +:10A330008F8600A490C80001310400201080019194 +:10A34000241000013C048008348B0080916A007C5A +:10A350008F9E0034AFA0002C314900011120000F66 +:10A36000AFB000288CCD00148C8E006001AE602B45 +:10A370001580000201A038218C8700603C188008FD +:10A38000370300808C70007000F0782B15E000021D +:10A3900000E020218C640070AFA4002C3C028008F7 +:10A3A000344500808CD200148CBF0070025FC82B33 +:10A3B00017200002024020218CA400708FA7002CDF +:10A3C0000087182310600003AFA3003024050002AB +:10A3D000AFA500288FA400280264882B162000BA9D +:10A3E000000018218CD000388FCE000C3C0F00806C +:10A3F000AFD000008CCD00343C0CFF9F01CF58251E +:10A40000AFCD000490CA003F3586FFFF01662024CF +:10A410003C0900203C08FFEFA3CA000B0089382547 +:10A420003511FFFF00F118243C0500088F8700A4B8 +:10A430000065C825AFD9000C8CE20014AFC000182D +:10A440008FA60030AFC200148CF800188FB0002C1B +:10A450003C1FFFFBAFD8001C8CEF000837F2FFFF5A +:10A4600003326824AFCF00248CEC000C020670216C +:10A47000AFCD000CA7C00038A7C0003AAFCE002C6B +:10A48000AFCC0020AFC000288CEA00148FAB002CAA +:10A49000014B48230126402311000011AFC80010D2 +:10A4A00090EB003D8FC900048FC80000000B5100E5 +:10A4B000012A28210000102100AA882B010218215E +:10A4C0000071F821AFC50004AFDF000090F2003D3D +:10A4D000A3D2000A8F9900A497380006A7D80008D5 +:10A4E0008F910038240800023C038008A228000055 +:10A4F0003465008094BF005C8FA4002C33F0FFFF14 +:10A500000E000FF48F9200380002CB808F8500A4DC +:10A51000021978253C18420001F87025AE4E00045F +:10A520008F8400388CAD0038AC8D00188CAC0034B2 +:10A53000AC8C001CAC80000CAC800010A48000141B +:10A54000A4800016A4800020A4800022AC800024F7 +:10A5500090A6003F8FA7002CA486000250E0019235 +:10A56000240700018FA200305040000290A2003D5D +:10A5700090A2003E244A0001A08A00018F84003886 +:10A580008FA9002CAC8900083C128008364D008051 +:10A5900091AC007C3186000214C000022407003414 +:10A5A000240700308F8500A43C198008373F0080C5 +:10A5B00090B0000093F9007C240E0004A0900030BD +:10A5C0008F8F00A48FB8002C8F8D003891F200017E +:10A5D0003304000301C46023A1B200318F8E003820 +:10A5E0008F8600A42402C00095CA003294C90012CC +:10A5F0008FAB002C0142402431233FFF010388250B +:10A60000A5D1003291D000323185000300EBF82152 +:10A610003218003F370F0040A1CF00328FA4002C2A +:10A6200003E5382133280004108000028F850038AC +:10A6300000E838213C0A8008ACA700343549010005 +:10A640008D2800D08FA3002C2419FFBFACA80038A0 +:10A6500090B1003C2C640001240FFFDF3227007F03 +:10A66000A0A7003C8F98003800049140931F003C45 +:10A6700003F98024A310003C8F8C0038918E003C9D +:10A6800001CF682401B23025A186003C8F8900A447 +:10A690008F8800388D2B0020AD0B00408D220024C8 +:10A6A000AD0200448D2A0028AD0A00488D23002CFD +:10A6B0000E001013AD03004C8FB1002824070002D8 +:10A6C000122700118FA300280003282B00058023E8 +:10A6D0000270982400608021006090210A00126FAF +:10A6E0000010882B962900128F8400A00000902172 +:10A6F0003125FFFFA7A900180E000FC22411000189 +:10A700000A00131D3C1E80003C0B80003C12800898 +:10A710008D640100924900088F92FF340E000F995A +:10A720003125007F8F9900388FA700288FA4003033 +:10A73000A3270000965F005C33F0FFFF0E000FF4CC +:10A740008F91003800026B80020D80253C0842008A +:10A750008F8D00A402085025AE2A00048DA5003874 +:10A760008F8A003800007821000F1100AD450018D5 +:10A770008DB800343C047FFF3488FFFFAD58001CC7 +:10A7800091A6003E8D4C001C8D4900180006190052 +:10A79000000677020183C821004E58250323882B29 +:10A7A000012B382100F1F821AD59001CAD5F0018D4 +:10A7B000AD40000CAD40001091B0003E8FA40030C1 +:10A7C00024090005A550001495A500042419C00013 +:10A7D00000884024A545001691B8003EA5580020E9 +:10A7E00095AF0004A54F0022AD40002491AE003F7C +:10A7F000A54E000291A6003E91AC003D01861023BB +:10A80000244B0001A14B00018F9100388FA3003031 +:10A810003C028008344B0100AE230008A22900301E +:10A820008F8C00388F8700A4959F003294F000121F +:10A830002407FFBF033FC02432053FFF03057825EF +:10A84000A58F0032918E00322418FFDF31CD003FFA +:10A8500035A60040A18600328F910038240DFFFFFD +:10A86000240CFF80AE2000348D6A00D0AE2A003860 +:10A870009223003C3069007FA229003C8F90003871 +:10A880003C0380009219003C0327F824A21F003CDF +:10A890008F8E003891C5003C00B87824A1CF003CD1 +:10A8A0008F8A00383C0E8008AD4D00408FA6002CEA +:10A8B000AD46004491420048004C5825A14B004849 +:10A8C0008F9000388F9900A48E09004801238824B6 +:10A8D00002283825AE070048933F003EA21F004CD7 +:10A8E0008F9800A48F8F003897050004A5E5004ECF +:10A8F0000E0003818DC500609246007C8FAC003055 +:10A9000000026940000291000040282130CB000283 +:10A9100001B21021156000AA018230213C0E80088E +:10A9200035C20080904C007C31830004106000032D +:10A930008FB900300005788000CF3021241F00043B +:10A940008F910038332D000303ED8023320800037C +:10A9500000C85021AE2A00343C188000A7C500383A +:10A960003C0680088F04010090DE00080E000FDE18 +:10A9700033C5007F0E001013000000000A00140D04 +:10A980008FA300288F9800348CC90038241F00033F +:10A99000A7000008AF0900008CC50034A300000A1E +:10A9A0008F9900A4AF0500043C080080932D003F60 +:10A9B000A31F000C8F0A000C3C02FF9FA30D000B8D +:10A9C0000148F0253451FFFF3C12FFEF8F9900A49E +:10A9D00003D170243646FFFF01C61824AF03000CD4 +:10A9E0008F2C0014972900128F8400A0AF0C001048 +:10A9F0008F2F0014AF000018AF000020AF0F00141D +:10AA0000AF0000248F270018312F3FFF000F59801F +:10AA1000AF0700288F2500080164F821312D0001BF +:10AA2000AF0500308F31000C8F920038001F51C2EB +:10AA3000000D438001481021241E00023C068008BE +:10AA4000A702001CA7000034AF11002CA25E00007A +:10AA500034D20080964E005C8F9900383C0342004F +:10AA600031CCFFFF01833825AF2700048F8B00A472 +:10AA7000240500012402C0008D640038240700343E +:10AA8000AF2400188D690034AF29001CAF20000CE2 +:10AA9000AF200010A7200014A7200016A720002038 +:10AAA000A7200022AF200024A7300002A325000128 +:10AAB0008F8800388F9F00A4AD10000893ED000030 +:10AAC000A10D00308F8A00A48F98003891510001A9 +:10AAD000A31100318F8B0038957E003203C27024A1 +:10AAE00001CF6025A56C0032916300323064003FD5 +:10AAF000A16400329249007C3125000214A00002BA +:10AB00008F840038240700303C198008AC8700345B +:10AB1000373201008E5F00D0240AFFBF020090216F +:10AB2000AC9F0038908D003C31A8007FA088003C8D +:10AB30008F9E003893C2003C004A8824A3D1003C79 +:10AB40008F8300380010882B9066003C34CE0020A4 +:10AB5000A06E003C8F8400A48F9800388C8C00205D +:10AB6000AF0C00408C8F0024AF0F00448C8700286E +:10AB7000AF0700488C8B002CAF0B004C0E0010135D +:10AB80003C1E80000A0012700000000094C80052B1 +:10AB90003C0A08008D4A002401488821A4D10052B3 +:10ABA0000A0012198FB40010A08700018F840038AA +:10ABB000240B0001AC8B00080A0013BE3C12800875 +:10ABC000000520800A0014A200C4302127BDFFE048 +:10ABD0003C0D8008AFB20018AFB00010AFBF001C32 +:10ABE000AFB1001435B200808E4C001835A80100BA +:10ABF000964B000695A70050910900FC000C5602E8 +:10AC0000016728233143007F312600FF240200031F +:10AC1000AF8300A8AF8400A010C2001B30B0FFFFBC +:10AC2000910600FC2412000530C200FF10520033D0 +:10AC300000000000160000098FBF001C8FB2001832 +:10AC40008FB100148FB00010240D0C003C0C80005C +:10AC500027BD002003E00008AD8D00240E0011FB8D +:10AC6000020020218FBF001C8FB200188FB100148A +:10AC70008FB00010240D0C003C0C800027BD00207C +:10AC800003E00008AD8D0024965800789651007AB4 +:10AC9000924E007D0238782631E8FFFF31C400C0B3 +:10ACA000148000092D11000116000037000000007B +:10ACB0005620FFE28FBF001C0E0010D100000000E4 +:10ACC0000A00156A8FBF001C1620FFDA0000000082 +:10ACD0000E0010D1000000001440FFD88FBF001CF0 +:10ACE0001600002200000000925F007D33E2003F6A +:10ACF000A242007D0A00156A8FBF001C950900EA78 +:10AD00008F86008000802821240400050E0007257E +:10AD10003130FFFF978300923C0480002465FFFFE1 +:10AD2000A78500928C8A01B80540FFFE0000000054 +:10AD3000AC8001808FBF001CAC9001848FB20018E2 +:10AD40008FB100148FB000103C0760133C0B100053 +:10AD5000240D0C003C0C800027BD0020AC8701882E +:10AD6000AC8B01B803E00008AD8D00240E0011FB90 +:10AD7000020020215040FFB18FBF001C925F007D78 +:10AD80000A00159733E2003F0E0011FB020020215C +:10AD90001440FFAA8FBF001C122000070000000013 +:10ADA0009259007D3330003F36020040A242007DC0 +:10ADB0000A00156A8FBF001C0E0010D100000000B1 +:10ADC0005040FF9E8FBF001C9259007D3330003FE2 +:10ADD0000A0015C636020040000000000000001BFB +:10ADE0000000000F0000000A00000008000000063C +:10ADF0000000000500000005000000040000000441 +:10AE00000000000300000003000000030000000336 +:10AE10000000000300000002000000020000000229 +:10AE2000000000020000000200000002000000021A +:10AE3000000000020000000200000002000000020A +:10AE400000000002000000020000000200000002FA +:10AE50000000000100000001000000018008010066 +:10AE6000800800808008000000000C000000308096 +:10AE7000080011D00800127C08001294080012A8E3 +:10AE8000080012BC080011D0080011D0080012F010 +:10AE90000800132C080013400800138808001A8CBF +:10AEA00008001A8C08001AC408001AC408001AD82E +:10AEB00008001AA808001D0008001CCC08001D5836 +:10AEC00008001D5808001DE008001D108008024001 +:10AED000080027340800256C0800275C080027F4C8 +:10AEE0000800293C0800298808002AAC080029B479 +:10AEF00008002A38080025DC08002EDC08002EA4F3 +:10AF000008002588080025880800258808002B20CF +:10AF100008002B20080025880800258808002DD06F +:10AF2000080025880800258808002588080025884D +:10AF300008002E0C080025880800258808002588B0 +:10AF4000080025880800258808002588080025882D +:10AF5000080025880800258808002588080025881D +:10AF6000080025880800258808002588080029A8E9 +:10AF7000080025880800258808002E680800258814 +:10AF800008002588080025880800258808002588ED +:10AF900008002588080025880800258808002588DD +:10AFA00008002588080025880800258808002588CD +:10AFB00008002588080025880800258808002588BD +:10AFC00008002CF4080025880800258808002C6853 +:10AFD00008002BC408003CE408003CB808003C848E +:10AFE00008003C5808003C3808003BEC8008010091 +:10AFF00080080080800800008008008008004C6401 +:10B0000008004C9C08004BE408004C6408004C64A9 +:10B01000080049B808004C64080050500A000C842D +:10B0200000000000000000000000000D7278703683 +:10B030002E322E31620000000602010300000000E3 +:10B0400000000001000000000000000000000000FF +:10B0500000000000000000000000000000000000F0 +:10B0600000000000000000000000000000000000E0 +:10B0700000000000000000000000000000000000D0 +:10B0800000000000000000000000000000000000C0 +:10B0900000000000000000000000000000000000B0 +:10B0A00000000000000000000000000000000000A0 +:10B0B0000000000000000000000000000000000090 +:10B0C0000000000000000000000000000000000080 +:10B0D0000000000000000000000000000000000070 +:10B0E0000000000000000000000000000000000060 +:10B0F0000000000000000000000000000000000050 +:10B10000000000000000000000000000000000003F +:10B11000000000000000000000000000000000002F +:10B12000000000000000000000000000000000001F +:10B13000000000000000000000000000000000000F +:10B1400000000000000000000000000000000000FF +:10B1500000000000000000000000000000000000EF +:10B1600000000000000000000000000000000000DF +:10B1700000000000000000000000000000000000CF +:10B1800000000000000000000000000000000000BF +:10B1900000000000000000000000000000000000AF +:10B1A000000000000000000000000000000000009F +:10B1B000000000000000000000000000000000008F +:10B1C000000000000000000000000000000000007F +:10B1D000000000000000000000000000000000006F +:10B1E000000000000000000000000000000000005F +:10B1F000000000000000000000000000000000004F +:10B20000000000000000000000000000000000003E +:10B21000000000000000000000000000000000002E +:10B22000000000000000000000000000000000001E +:10B23000000000000000000000000000000000000E +:10B2400000000000000000000000000000000000FE +:10B2500000000000000000000000000000000000EE +:10B2600000000000000000000000000000000000DE +:10B2700000000000000000000000000000000000CE +:10B2800000000000000000000000000000000000BE +:10B2900000000000000000000000000000000000AE +:10B2A000000000000000000000000000000000009E +:10B2B000000000000000000000000000000000008E +:10B2C000000000000000000000000000000000007E +:10B2D000000000000000000000000000000000006E +:10B2E000000000000000000000000000000000005E +:10B2F000000000000000000000000000000000004E +:10B30000000000000000000000000000000000003D +:10B31000000000000000000000000000000000002D +:10B32000000000000000000000000000000000001D +:10B33000000000000000000000000000000000000D +:10B3400000000000000000000000000000000000FD +:10B3500000000000000000000000000000000000ED +:10B3600000000000000000000000000000000000DD +:10B3700000000000000000000000000000000000CD +:10B3800000000000000000000000000000000000BD +:10B3900000000000000000000000000000000000AD +:10B3A000000000000000000000000000000000009D +:10B3B000000000000000000000000000000000008D +:10B3C000000000000000000000000000000000007D +:10B3D000000000000000000000000000000000006D +:10B3E000000000000000000000000000000000005D +:10B3F000000000000000000000000000000000004D +:10B40000000000000000000000000000000000003C +:10B41000000000000000000000000000000000002C +:10B42000000000000000000000000000000000001C +:10B43000000000000000000000000000000000000C +:10B4400000000000000000000000000000000000FC +:10B4500000000000000000000000000000000000EC +:10B4600000000000000000000000000000000000DC +:10B4700000000000000000000000000000000000CC +:10B4800000000000000000000000000000000000BC +:10B4900000000000000000000000000000000000AC +:10B4A000000000000000000000000000000000009C +:10B4B000000000000000000000000000000000008C +:10B4C000000000000000000000000000000000007C +:10B4D000000000000000000000000000000000006C +:10B4E000000000000000000000000000000000005C +:10B4F000000000000000000000000000000000004C +:10B50000000000000000000000000000000000003B +:10B51000000000000000000000000000000000002B +:10B52000000000000000000000000000000000001B +:10B53000000000000000000000000000000000000B +:10B5400000000000000000000000000000000000FB +:10B5500000000000000000000000000000000000EB +:10B5600000000000000000000000000000000000DB +:10B5700000000000000000000000000000000000CB +:10B5800000000000000000000000000000000000BB +:10B5900000000000000000000000000000000000AB +:10B5A000000000000000000000000000000000009B +:10B5B000000000000000000000000000000000008B +:10B5C000000000000000000000000000000000007B +:10B5D000000000000000000000000000000000006B +:10B5E000000000000000000000000000000000005B +:10B5F000000000000000000000000000000000004B +:10B60000000000000000000000000000000000003A +:10B61000000000000000000000000000000000002A +:10B62000000000000000000000000000000000001A +:10B63000000000000000000000000000000000000A +:10B6400000000000000000000000000000000000FA +:10B6500000000000000000000000000000000000EA +:10B6600000000000000000000000000000000000DA +:10B6700000000000000000000000000000000000CA +:10B6800000000000000000000000000000000000BA +:10B6900000000000000000000000000000000000AA +:10B6A000000000000000000000000000000000009A +:10B6B000000000000000000000000000000000008A +:10B6C000000000000000000000000000000000007A +:10B6D000000000000000000000000000000000006A +:10B6E000000000000000000000000000000000005A +:10B6F000000000000000000000000000000000004A +:10B700000000000000000000000000000000000039 +:10B710000000000000000000000000000000000029 +:10B720000000000000000000000000000000000019 +:10B730000000000000000000000000000000000009 +:10B7400000000000000000000000000000000000F9 +:10B7500000000000000000000000000000000000E9 +:10B7600000000000000000000000000000000000D9 +:10B7700000000000000000000000000000000000C9 +:10B7800000000000000000000000000000000000B9 +:10B7900000000000000000000000000000000000A9 +:10B7A0000000000000000000000000000000000099 +:10B7B0000000000000000000000000000000000089 +:10B7C0000000000000000000000000000000000079 +:10B7D0000000000000000000000000000000000069 +:10B7E0000000000000000000000000000000000059 +:10B7F0000000000000000000000000000000000049 +:10B800000000000000000000000000000000000038 +:10B810000000000000000000000000000000000028 +:10B820000000000000000000000000000000000018 +:10B830000000000000000000000000000000000008 +:10B8400000000000000000000000000000000000F8 +:10B8500000000000000000000000000000000000E8 +:10B8600000000000000000000000000000000000D8 +:10B8700000000000000000000000000000000000C8 +:10B8800000000000000000000000000000000000B8 +:10B8900000000000000000000000000000000000A8 +:10B8A0000000000000000000000000000000000098 +:10B8B0000000000000000000000000000000000088 +:10B8C0000000000000000000000000000000000078 +:10B8D0000000000000000000000000000000000068 +:10B8E0000000000000000000000000000000000058 +:10B8F0000000000000000000000000000000000048 +:10B900000000000000000000000000000000000037 +:10B910000000000000000000000000000000000027 +:10B920000000000000000000000000000000000017 +:10B930000000000000000000000000000000000007 +:10B9400000000000000000000000000000000000F7 +:10B9500000000000000000000000000000000000E7 +:10B9600000000000000000000000000000000000D7 +:10B9700000000000000000000000000000000000C7 +:10B9800000000000000000000000000000000000B7 +:10B9900000000000000000000000000000000000A7 +:10B9A0000000000000000000000000000000000097 +:10B9B0000000000000000000000000000000000087 +:10B9C0000000000000000000000000000000000077 +:10B9D0000000000000000000000000000000000067 +:10B9E0000000000000000000000000000000000057 +:10B9F0000000000000000000000000000000000047 +:10BA00000000000000000000000000000000000036 +:10BA10000000000000000000000000000000000026 +:10BA20000000000000000000000000000000000016 +:10BA30000000000000000000000000000000000006 +:10BA400000000000000000000000000000000000F6 +:10BA500000000000000000000000000000000000E6 +:10BA600000000000000000000000000000000000D6 +:10BA700000000000000000000000000000000000C6 +:10BA800000000000000000000000000000000000B6 +:10BA900000000000000000000000000000000000A6 +:10BAA0000000000000000000000000000000000096 +:10BAB0000000000000000000000000000000000086 +:10BAC0000000000000000000000000000000000076 +:10BAD0000000000000000000000000000000000066 +:10BAE0000000000000000000000000000000000056 +:10BAF0000000000000000000000000000000000046 +:10BB00000000000000000000000000000000000035 +:10BB10000000000000000000000000000000000025 +:10BB20000000000000000000000000000000000015 +:10BB30000000000000000000000000000000000005 +:10BB400000000000000000000000000000000000F5 +:10BB500000000000000000000000000000000000E5 +:10BB600000000000000000000000000000000000D5 +:10BB700000000000000000000000000000000000C5 +:10BB800000000000000000000000000000000000B5 +:10BB900000000000000000000000000000000000A5 +:10BBA0000000000000000000000000000000000095 +:10BBB0000000000000000000000000000000000085 +:10BBC0000000000000000000000000000000000075 +:10BBD0000000000000000000000000000000000065 +:10BBE0000000000000000000000000000000000055 +:10BBF0000000000000000000000000000000000045 +:10BC00000000000000000000000000000000000034 +:10BC10000000000000000000000000000000000024 +:10BC20000000000000000000000000000000000014 +:10BC30000000000000000000000000000000000004 +:10BC400000000000000000000000000000000000F4 +:10BC500000000000000000000000000000000000E4 +:10BC600000000000000000000000000000000000D4 +:10BC700000000000000000000000000000000000C4 +:10BC800000000000000000000000000000000000B4 +:10BC900000000000000000000000000000000000A4 +:10BCA0000000000000000000000000000000000094 +:10BCB0000000000000000000000000000000000084 +:10BCC0000000000000000000000000000000000074 +:10BCD0000000000000000000000000000000000064 +:10BCE0000000000000000000000000000000000054 +:10BCF0000000000000000000000000000000000044 +:10BD00000000000000000000000000000000000033 +:10BD10000000000000000000000000000000000023 +:10BD20000000000000000000000000000000000013 +:10BD30000000000000000000000000000000000003 +:10BD400000000000000000000000000000000000F3 +:10BD500000000000000000000000000000000000E3 +:10BD600000000000000000000000000000000000D3 +:10BD700000000000000000000000000000000000C3 +:10BD800000000000000000000000000000000000B3 +:10BD900000000000000000000000000000000000A3 +:10BDA0000000000000000000000000000000000093 +:10BDB0000000000000000000000000000000000083 +:10BDC0000000000000000000000000000000000073 +:10BDD0000000000000000000000000000000000063 +:10BDE0000000000000000000000000000000000053 +:10BDF0000000000000000000000000000000000043 +:10BE00000000000000000000000000000000000032 +:10BE10000000000000000000000000000000000022 +:10BE20000000000000000000000000000000000012 +:10BE30000000000000000000000000000000000002 +:10BE400000000000000000000000000000000000F2 +:10BE500000000000000000000000000000000000E2 +:10BE600000000000000000000000000000000000D2 +:10BE700000000000000000000000000000000000C2 +:10BE800000000000000000000000000000000000B2 +:10BE900000000000000000000000000000000000A2 +:10BEA0000000000000000000000000000000000092 +:10BEB0000000000000000000000000000000000082 +:10BEC0000000000000000000000000000000000072 +:10BED0000000000000000000000000000000000062 +:10BEE0000000000000000000000000000000000052 +:10BEF0000000000000000000000000000000000042 +:10BF00000000000000000000000000000000000031 +:10BF10000000000000000000000000000000000021 +:10BF20000000000000000000000000000000000011 +:10BF30000000000000000000000000000000000001 +:10BF400000000000000000000000000000000000F1 +:10BF500000000000000000000000000000000000E1 +:10BF600000000000000000000000000000000000D1 +:10BF700000000000000000000000000000000000C1 +:10BF800000000000000000000000000000000000B1 +:10BF900000000000000000000000000000000000A1 +:10BFA0000000000000000000000000000000000091 +:10BFB0000000000000000000000000000000000081 +:10BFC0000000000000000000000000000000000071 +:10BFD0000000000000000000000000000000000061 +:10BFE0000000000000000000000000000000000051 +:10BFF0000000000000000000000000000000000041 +:10C000000000000000000000000000000000000030 +:10C010000000000000000000000000000000000020 +:10C020000000000000000000000000000000000010 +:10C030000000000000000000000000000000000000 +:10C0400000000000000000000000000000000000F0 +:10C0500000000000000000000000000000000000E0 +:10C0600000000000000000000000000000000000D0 +:10C0700000000000000000000000000000000000C0 +:10C0800000000000000000000000000000000000B0 +:10C0900000000000000000000000000000000000A0 +:10C0A0000000000000000000000000000000000090 +:10C0B0000000000000000000000000000000000080 +:10C0C0000000000000000000000000000000000070 +:10C0D0000000000000000000000000000000000060 +:10C0E0000000000000000000000000000000000050 +:10C0F0000000000000000000000000000000000040 +:10C10000000000000000000000000000000000002F +:10C11000000000000000000000000000000000001F +:10C12000000000000000000000000000000000000F +:10C1300000000000000000000000000000000000FF +:10C1400000000000000000000000000000000000EF +:10C1500000000000000000000000000000000000DF +:10C1600000000000000000000000000000000000CF +:10C1700000000000000000000000000000000000BF +:10C1800000000000000000000000000000000000AF +:10C19000000000000000000000000000000000009F +:10C1A000000000000000000000000000000000008F +:10C1B000000000000000000000000000000000007F +:10C1C000000000000000000000000000000000006F +:10C1D000000000000000000000000000000000005F +:10C1E000000000000000000000000000000000004F +:10C1F000000000000000000000000000000000003F +:10C20000000000000000000000000000000000002E +:10C21000000000000000000000000000000000001E +:10C22000000000000000000000000000000000000E +:10C2300000000000000000000000000000000000FE +:10C2400000000000000000000000000000000000EE +:10C2500000000000000000000000000000000000DE +:10C2600000000000000000000000000000000000CE +:10C2700000000000000000000000000000000000BE +:10C2800000000000000000000000000000000000AE +:10C29000000000000000000000000000000000009E +:10C2A000000000000000000000000000000000008E +:10C2B000000000000000000000000000000000007E +:10C2C000000000000000000000000000000000006E +:10C2D000000000000000000000000000000000005E +:10C2E000000000000000000000000000000000004E +:10C2F000000000000000000000000000000000003E +:10C30000000000000000000000000000000000002D +:10C31000000000000000000000000000000000001D +:10C32000000000000000000000000000000000000D +:10C3300000000000000000000000000000000000FD +:10C3400000000000000000000000000000000000ED +:10C3500000000000000000000000000000000000DD +:10C3600000000000000000000000000000000000CD +:10C3700000000000000000000000000000000000BD +:10C3800000000000000000000000000000000000AD +:10C39000000000000000000000000000000000009D +:10C3A000000000000000000000000000000000008D +:10C3B000000000000000000000000000000000007D +:10C3C000000000000000000000000000000000006D +:10C3D000000000000000000000000000000000005D +:10C3E000000000000000000000000000000000004D +:10C3F000000000000000000000000000000000003D +:10C40000000000000000000000000000000000002C +:10C41000000000000000000000000000000000001C +:10C42000000000000000000000000000000000000C +:10C4300000000000000000000000000000000000FC +:10C4400000000000000000000000000000000000EC +:10C4500000000000000000000000000000000000DC +:10C4600000000000000000000000000000000000CC +:10C4700000000000000000000000000000000000BC +:10C4800000000000000000000000000000000000AC +:10C49000000000000000000000000000000000009C +:10C4A000000000000000000000000000000000008C +:10C4B000000000000000000000000000000000007C +:10C4C000000000000000000000000000000000006C +:10C4D000000000000000000000000000000000005C +:10C4E000000000000000000000000000000000004C +:10C4F000000000000000000000000000000000003C +:10C50000000000000000000000000000000000002B +:10C51000000000000000000000000000000000001B +:10C52000000000000000000000000000000000000B +:10C5300000000000000000000000000000000000FB +:10C5400000000000000000000000000000000000EB +:10C5500000000000000000000000000000000000DB +:10C5600000000000000000000000000000000000CB +:10C5700000000000000000000000000000000000BB +:10C5800000000000000000000000000000000000AB +:10C59000000000000000000000000000000000009B +:10C5A000000000000000000000000000000000008B +:10C5B000000000000000000000000000000000007B +:10C5C000000000000000000000000000000000006B +:10C5D000000000000000000000000000000000005B +:10C5E000000000000000000000000000000000004B +:10C5F000000000000000000000000000000000003B +:10C60000000000000000000000000000000000002A +:10C61000000000000000000000000000000000001A +:10C62000000000000000000000000000000000000A +:10C6300000000000000000000000000000000000FA +:10C6400000000000000000000000000000000000EA +:10C6500000000000000000000000000000000000DA +:10C6600000000000000000000000000000000000CA +:10C6700000000000000000000000000000000000BA +:10C6800000000000000000000000000000000000AA +:10C69000000000000000000000000000000000009A +:10C6A000000000000000000000000000000000008A +:10C6B000000000000000000000000000000000007A +:10C6C000000000000000000000000000000000006A +:10C6D000000000000000000000000000000000005A +:10C6E000000000000000000000000000000000004A +:10C6F000000000000000000000000000000000003A +:10C700000000000000000000000000000000000029 +:10C710000000000000000000000000000000000019 +:10C720000000000000000000000000000000000009 +:10C7300000000000000000000000000000000000F9 +:10C7400000000000000000000000000000000000E9 +:10C7500000000000000000000000000000000000D9 +:10C7600000000000000000000000000000000000C9 +:10C7700000000000000000000000000000000000B9 +:10C7800000000000000000000000000000000000A9 +:10C790000000000000000000000000000000000099 +:10C7A0000000000000000000000000000000000089 +:10C7B0000000000000000000000000000000000079 +:10C7C0000000000000000000000000000000000069 +:10C7D0000000000000000000000000000000000059 +:10C7E0000000000000000000000000000000000049 +:10C7F0000000000000000000000000000000000039 +:10C800000000000000000000000000000000000028 +:10C810000000000000000000000000000000000018 +:10C820000000000000000000000000000000000008 +:10C8300000000000000000000000000000000000F8 +:10C8400000000000000000000000000000000000E8 +:10C8500000000000000000000000000000000000D8 +:10C8600000000000000000000000000000000000C8 +:10C8700000000000000000000000000000000000B8 +:10C8800000000000000000000000000000000000A8 +:10C890000000000000000000000000000000000098 +:10C8A0000000000000000000000000000000000088 +:10C8B0000000000000000000000000000000000078 +:10C8C0000000000000000000000000000000000068 +:10C8D0000000000000000000000000000000000058 +:10C8E0000000000000000000000000000000000048 +:10C8F0000000000000000000000000000000000038 +:10C900000000000000000000000000000000000027 +:10C910000000000000000000000000000000000017 +:10C920000000000000000000000000000000000007 +:10C9300000000000000000000000000000000000F7 +:10C9400000000000000000000000000000000000E7 +:10C9500000000000000000000000000000000000D7 +:10C9600000000000000000000000000000000000C7 +:10C9700000000000000000000000000000000000B7 +:10C9800000000000000000000000000000000000A7 +:10C990000000000000000000000000000000000097 +:10C9A0000000000000000000000000000000000087 +:10C9B0000000000000000000000000000000000077 +:10C9C0000000000000000000000000000000000067 +:10C9D0000000000000000000000000000000000057 +:10C9E0000000000000000000000000000000000047 +:10C9F0000000000000000000000000000000000037 +:10CA00000000000000000000000000000000000026 +:10CA10000000000000000000000000000000000016 +:10CA20000000000000000000000000000000000006 +:10CA300000000000000000000000000000000000F6 +:10CA400000000000000000000000000000000000E6 +:10CA500000000000000000000000000000000000D6 +:10CA600000000000000000000000000000000000C6 +:10CA700000000000000000000000000000000000B6 +:10CA800000000000000000000000000000000000A6 +:10CA90000000000000000000000000000000000096 +:10CAA0000000000000000000000000000000000086 +:10CAB0000000000000000000000000000000000076 +:10CAC0000000000000000000000000000000000066 +:10CAD0000000000000000000000000000000000056 +:10CAE0000000000000000000000000000000000046 +:10CAF0000000000000000000000000000000000036 +:10CB00000000000000000000000000000000000025 +:10CB10000000000000000000000000000000000015 +:10CB20000000000000000000000000000000000005 +:10CB300000000000000000000000000000000000F5 +:10CB400000000000000000000000000000000000E5 +:10CB500000000000000000000000000000000000D5 +:10CB600000000000000000000000000000000000C5 +:10CB700000000000000000000000000000000000B5 +:10CB800000000000000000000000000000000000A5 +:10CB90000000000000000000000000000000000095 +:10CBA0000000000000000000000000000000000085 +:10CBB0000000000000000000000000000000000075 +:10CBC0000000000000000000000000000000000065 +:10CBD0000000000000000000000000000000000055 +:10CBE0000000000000000000000000000000000045 +:10CBF0000000000000000000000000000000000035 +:10CC00000000000000000000000000000000000024 +:10CC10000000000000000000000000000000000014 +:10CC20000000000000000000000000000000000004 +:10CC300000000000000000000000000000000000F4 +:10CC400000000000000000000000000000000000E4 +:10CC500000000000000000000000000000000000D4 +:10CC600000000000000000000000000000000000C4 +:10CC700000000000000000000000000000000000B4 +:10CC800000000000000000000000000000000000A4 +:10CC90000000000000000000000000000000000094 +:10CCA0000000000000000000000000000000000084 +:10CCB0000000000000000000000000000000000074 +:10CCC0000000000000000000000000000000000064 +:10CCD0000000000000000000000000000000000054 +:10CCE0000000000000000000000000000000000044 +:10CCF0000000000000000000000000000000000034 +:10CD00000000000000000000000000000000000023 +:10CD10000000000000000000000000000000000013 +:10CD20000000000000000000000000000000000003 +:10CD300000000000000000000000000000000000F3 +:10CD400000000000000000000000000000000000E3 +:10CD500000000000000000000000000000000000D3 +:10CD600000000000000000000000000000000000C3 +:10CD700000000000000000000000000000000000B3 +:10CD800000000000000000000000000000000000A3 +:10CD90000000000000000000000000000000000093 +:10CDA0000000000000000000000000000000000083 +:10CDB0000000000000000000000000000000000073 +:10CDC0000000000000000000000000000000000063 +:10CDD0000000000000000000000000000000000053 +:10CDE0000000000000000000000000000000000043 +:10CDF0000000000000000000000000000000000033 +:10CE00000000000000000000000000000000000022 +:10CE10000000000000000000000000000000000012 +:10CE20000000000000000000000000000000000002 +:10CE300000000000000000000000000000000000F2 +:10CE400000000000000000000000000000000000E2 +:10CE500000000000000000000000000000000000D2 +:10CE600000000000000000000000000000000000C2 +:10CE700000000000000000000000000000000000B2 +:10CE800000000000000000000000000000000000A2 +:10CE90000000000000000000000000000000000092 +:10CEA0000000000000000000000000000000000082 +:10CEB0000000000000000000000000000000000072 +:10CEC0000000000000000000000000000000000062 +:10CED0000000000000000000000000000000000052 +:10CEE0000000000000000000000000000000000042 +:10CEF0000000000000000000000000000000000032 +:10CF00000000000000000000000000000000000021 +:10CF10000000000000000000000000000000000011 +:10CF20000000000000000000000000000000000001 +:10CF300000000000000000000000000000000000F1 +:10CF400000000000000000000000000000000000E1 +:10CF500000000000000000000000000000000000D1 +:10CF600000000000000000000000000000000000C1 +:10CF700000000000000000000000000000000000B1 +:10CF800000000000000000000000000000000000A1 +:10CF90000000000000000000000000000000000091 +:10CFA0000000000000000000000000000000000081 +:10CFB0000000000000000000000000000000000071 +:10CFC0000000000000000000000000000000000061 +:10CFD0000000000000000000000000000000000051 +:10CFE0000000000000000000000000000000000041 +:10CFF0000000000000000000000000000000000031 +:10D000000000000000000000000000000000000020 +:10D010000000000000000000000000000000000010 +:10D020000000000000000000000000000000000000 +:10D0300000000000000000000000000000000000F0 +:10D0400000000000000000000000000000000000E0 +:10D0500000000000000000000000000000000000D0 +:10D0600000000000000000000000000000000000C0 +:10D0700000000000000000000000000000000000B0 +:10D0800000000000000000000000000000000000A0 +:10D090000000000000000000000000000000000090 +:10D0A0000000000000000000000000000000000080 +:10D0B0000000000000000000000000000000000070 +:10D0C0000000000000000000000000000000000060 +:10D0D0000000000000000000000000000000000050 +:10D0E0000000000000000000000000000000000040 +:10D0F0000000000000000000000000000000000030 +:10D10000000000000000000000000000000000001F +:10D11000000000000000000000000000000000000F +:10D1200000000000000000000000000000000000FF +:10D1300000000000000000000000000000000000EF +:10D1400000000000000000000000000000000000DF +:10D1500000000000000000000000000000000000CF +:10D1600000000000000000000000000000000000BF +:10D1700000000000000000000000000000000000AF +:10D18000000000000000000000000000000000009F +:10D19000000000000000000000000000000000008F +:10D1A000000000000000000000000000000000007F +:10D1B000000000000000000000000000000000006F +:10D1C000000000000000000000000000000000005F +:10D1D000000000000000000000000000000000004F +:10D1E000000000000000000000000000000000003F +:10D1F000000000000000000000000000000000002F +:10D20000000000000000000000000000000000001E +:10D21000000000000000000000000000000000000E +:10D2200000000000000000000000000000000000FE +:10D2300000000000000000000000000000000000EE +:10D2400000000000000000000000000000000000DE +:10D2500000000000000000000000000000000000CE +:10D2600000000000000000000000000000000000BE +:10D2700000000000000000000000000000000000AE +:10D28000000000000000000000000000000000009E +:10D29000000000000000000000000000000000008E +:10D2A000000000000000000000000000000000007E +:10D2B000000000000000000000000000000000006E +:10D2C000000000000000000000000000000000005E +:10D2D000000000000000000000000000000000004E +:10D2E000000000000000000000000000000000003E +:10D2F000000000000000000000000000000000002E +:10D30000000000000000000000000000000000001D +:10D31000000000000000000000000000000000000D +:10D3200000000000000000000000000000000000FD +:10D3300000000000000000000000000000000000ED +:10D3400000000000000000000000000000000000DD +:10D3500000000000000000000000000000000000CD +:10D3600000000000000000000000000000000000BD +:10D3700000000000000000000000000000000000AD +:10D38000000000000000000000000000000000009D +:10D39000000000000000000000000000000000008D +:10D3A000000000000000000000000000000000007D +:10D3B000000000000000000000000000000000006D +:10D3C000000000000000000000000000000000005D +:10D3D000000000000000000000000000000000004D +:10D3E000000000000000000000000000000000003D +:10D3F000000000000000000000000000000000002D +:10D40000000000000000000000000000000000001C +:10D41000000000000000000000000000000000000C +:10D4200000000000000000000000000000000000FC +:10D4300000000000000000000000000000000000EC +:10D4400000000000000000000000000000000000DC +:10D4500000000000000000000000000000000000CC +:10D4600000000000000000000000000000000000BC +:10D4700000000000000000000000000000000000AC +:10D48000000000000000000000000000000000009C +:10D49000000000000000000000000000000000008C +:10D4A000000000000000000000000000000000007C +:10D4B000000000000000000000000000000000006C +:10D4C000000000000000000000000000000000005C +:10D4D000000000000000000000000000000000004C +:10D4E000000000000000000000000000000000003C +:10D4F000000000000000000000000000000000002C +:10D50000000000000000000000000000000000001B +:10D51000000000000000000000000000000000000B +:10D5200000000000000000000000000000000000FB +:10D5300000000000000000000000000000000000EB +:10D5400000000000000000000000000000000000DB +:10D5500000000000000000000000000000000000CB +:10D5600000000000000000000000000000000000BB +:10D5700000000000000000000000000000000000AB +:10D58000000000000000000000000000000000009B +:10D59000000000000000000000000000000000008B +:10D5A000000000000000000000000000000000007B +:10D5B000000000000000000000000000000000006B +:10D5C000000000000000000000000000000000005B +:10D5D000000000000000000000000000000000004B +:10D5E000000000000000000000000000000000003B +:10D5F000000000000000000000000000000000002B +:10D60000000000000000000000000000000000001A +:10D61000000000000000000000000000000000000A +:10D6200000000000000000000000000000000000FA +:10D6300000000000000000000000000000000000EA +:10D6400000000000000000000000000000000000DA +:10D6500000000000000000000000000000000000CA +:10D6600000000000000000000000000000000000BA +:10D6700000000000000000000000000000000000AA +:10D68000000000000000000000000000000000009A +:10D69000000000000000000000000000000000008A +:10D6A000000000000000000000000000000000007A +:10D6B000000000000000000000000000000000006A +:10D6C000000000000000000000000000000000005A +:10D6D000000000000000000000000000000000004A +:10D6E000000000000000000000000000000000003A +:10D6F000000000000000000000000000000000002A +:10D700000000000000000000000000000000000019 +:10D710000000000000000000000000000000000009 +:10D7200000000000000000000000000000000000F9 +:10D7300000000000000000000000000000000000E9 +:10D7400000000000000000000000000000000000D9 +:10D7500000000000000000000000000000000000C9 +:10D7600000000000000000000000000000000000B9 +:10D7700000000000000000000000000000000000A9 +:10D780000000000000000000000000000000000099 +:10D790000000000000000000000000000000000089 +:10D7A0000000000000000000000000000000000079 +:10D7B0000000000000000000000000000000000069 +:10D7C0000000000000000000000000000000000059 +:10D7D0000000000000000000000000000000000049 +:10D7E0000000000000000000000000000000000039 +:10D7F0000000000000000000000000000000000029 +:10D800000000000000000000000000000000000018 +:10D810000000000000000000000000000000000008 +:10D8200000000000000000000000000000000000F8 +:10D8300000000000000000000000000000000000E8 +:10D8400000000000000000000000000000000000D8 +:10D8500000000000000000000000000000000000C8 +:10D8600000000000000000000000000000000000B8 +:10D8700000000000000000000000000000000000A8 +:10D880000000000000000000000000000000000098 +:10D890000000000000000000000000000000000088 +:10D8A0000000000000000000000000000000000078 +:10D8B0000000000000000000000000000000000068 +:10D8C0000000000000000000000000000000000058 +:10D8D0000000000000000000000000000000000048 +:10D8E0000000000000000000000000000000000038 +:10D8F0000000000000000000000000000000000028 +:10D900000000000000000000000000000000000017 +:10D910000000000000000000000000000000000007 +:10D9200000000000000000000000000000000000F7 +:10D9300000000000000000000000000000000000E7 +:10D9400000000000000000000000000000000000D7 +:10D9500000000000000000000000000000000000C7 +:10D9600000000000000000000000000000000000B7 +:10D9700000000000000000000000000000000000A7 +:10D980000000000000000000000000000000000097 +:10D990000000000000000000000000000000000087 +:10D9A0000000000000000000000000000000000077 +:10D9B0000000000000000000000000000000000067 +:10D9C0000000000000000000000000000000000057 +:10D9D0000000000000000000000000000000000047 +:10D9E0000000000000000000000000000000000037 +:10D9F0000000000000000000000000000000000027 +:10DA00000000000000000000000000000000000016 +:10DA10000000000000000000000000000000000006 +:10DA200000000000000000000000000000000000F6 +:10DA300000000000000000000000000000000000E6 +:10DA400000000000000000000000000000000000D6 +:10DA500000000000000000000000000000000000C6 +:10DA600000000000000000000000000000000000B6 +:10DA700000000000000000000000000000000000A6 +:10DA80000000000000000000000000000000000096 +:10DA90000000000000000000000000000000000086 +:10DAA0000000000000000000000000000000000076 +:10DAB0000000000000000000000000000000000066 +:10DAC0000000000000000000000000000000000056 +:10DAD0000000000000000000000000000000000046 +:10DAE0000000000000000000000000000000000036 +:10DAF0000000000000000000000000000000000026 +:10DB00000000000000000000000000000000000015 +:10DB10000000000000000000000000000000000005 +:10DB200000000000000000000000000000000000F5 +:10DB300000000000000000000000000000000000E5 +:10DB400000000000000000000000000000000000D5 +:10DB500000000000000000000000000000000000C5 +:10DB600000000000000000000000000000000000B5 +:10DB700000000000000000000000000000000000A5 +:10DB80000000000000000000000000000000000095 +:10DB90000000000000000000000000000000000085 +:10DBA0000000000000000000000000000000000075 +:10DBB0000000000000000000000000000000000065 +:10DBC0000000000000000000000000000000000055 +:10DBD0000000000000000000000000000000000045 +:10DBE0000000000000000000000000000000000035 +:10DBF0000000000000000000000000000000000025 +:10DC00000000000000000000000000000000000014 +:10DC10000000000000000000000000000000000004 +:10DC200000000000000000000000000000000000F4 +:10DC300000000000000000000000000000000000E4 +:10DC400000000000000000000000000000000000D4 +:10DC500000000000000000000000000000000000C4 +:10DC600000000000000000000000000000000000B4 +:10DC700000000000000000000000000000000000A4 +:10DC80000000000000000000000000000000000094 +:10DC90000000000000000000000000000000000084 +:10DCA0000000000000000000000000000000000074 +:10DCB0000000000000000000000000000000000064 +:10DCC0000000000000000000000000000000000054 +:10DCD0000000000000000000000000000000000044 +:10DCE0000000000000000000000000000000000034 +:10DCF0000000000000000000000000000000000024 +:10DD00000000000000000000000000000000000013 +:10DD10000000000000000000000000000000000003 +:10DD200000000000000000000000000000000000F3 +:10DD300000000000000000000000000000000000E3 +:10DD400000000000000000000000000000000000D3 +:10DD500000000000000000000000000000000000C3 +:10DD600000000000000000000000000000000000B3 +:10DD700000000000000000000000000000000000A3 +:10DD80000000000000000000000000000000000093 +:10DD90000000000000000000000000000000000083 +:10DDA0000000000000000000000000000000000073 +:10DDB0000000000000000000000000000000000063 +:10DDC0000000000000000000000000000000000053 +:10DDD0000000000000000000000000000000000043 +:10DDE0000000000000000000000000000000000033 +:10DDF0000000000000000000000000000000000023 +:10DE00000000000000000000000000000000000012 +:10DE10000000000000000000000000000000000002 +:10DE200000000000000000000000000000000000F2 +:10DE300000000000000000000000000000000000E2 +:10DE400000000000000000000000000000000000D2 +:10DE500000000000000000000000000000000000C2 +:10DE600000000000000000000000000000000000B2 +:10DE700000000000000000000000000000000000A2 +:10DE80000000000000000000000000000000000092 +:10DE90000000000000000000000000000000000082 +:10DEA0000000000000000000000000000000000072 +:10DEB0000000000000000000000000000000000062 +:10DEC0000000000000000000000000000000000052 +:10DED0000000000000000000000000000000000042 +:10DEE0000000000000000000000000000000000032 +:10DEF0000000000000000000000000000000000022 +:10DF00000000000000000000000000000000000011 +:10DF10000000000000000000000000000000000001 +:10DF200000000000000000000000000000000000F1 +:10DF300000000000000000000000000000000000E1 +:10DF400000000000000000000000000000000000D1 +:10DF500000000000000000000000000000000000C1 +:10DF600000000000000000000000000000000000B1 +:10DF700000000000000000000000000000000000A1 +:10DF80000000000000000000000000000000000091 +:10DF90000000000000000000000000000000000081 +:10DFA0000000000000000000000000000000000071 +:10DFB0000000000000000000000000000000000061 +:10DFC0000000000000000000000000000000000051 +:10DFD0000000000000000000000000000000000041 +:10DFE0000000000000000000000000000000000031 +:10DFF0000000000000000000000000000000000021 +:10E000000000000000000000000000000000000010 +:10E010000000000000000000000000000000000000 +:10E0200000000000000000000000000000000000F0 +:10E0300000000000000000000000000000000000E0 +:10E0400000000000000000000000000000000000D0 +:10E0500000000000000000000000000000000000C0 +:10E0600000000000000000000000000000000000B0 +:10E0700000000000000000000000000000000000A0 +:10E080000000000000000000000000000000000090 +:10E090000000000000000000000000000000000080 +:10E0A0000000000000000000000000000000000070 +:10E0B0000000000000000000000000000000000060 +:10E0C0000000000000000000000000000000000050 +:10E0D0000000000000000000000000000000000040 +:10E0E0000000000000000000000000000000000030 +:10E0F0000000000000000000000000000000000020 +:10E10000000000000000000000000000000000000F +:10E1100000000000000000000000000000000000FF +:10E1200000000000000000000000000000000000EF +:10E1300000000000000000000000000000000000DF +:10E1400000000000000000000000000000000000CF +:10E1500000000000000000000000000000000000BF +:10E1600000000000000000000000000000000000AF +:10E17000000000000000000000000000000000009F +:10E18000000000000000000000000000000000008F +:10E19000000000000000000000000000000000007F +:10E1A000000000000000000000000000000000006F +:10E1B000000000000000000000000000000000005F +:10E1C000000000000000000000000000000000004F +:10E1D000000000000000000000000000000000003F +:10E1E000000000000000000000000000000000002F +:10E1F000000000000000000000000000000000809F +:10E20000000000000000000000000000000000000E +:10E2100000000000000000000000000000000000FE +:10E220000000000A000000000000000000000000E4 +:10E2300010000003000000000000000D0000000DB1 +:10E240003C020801244295C03C030801246397FC6A +:10E25000AC4000000043202B1480FFFD244200044A +:10E260003C1D080037BD9FFC03A0F0213C100800B6 +:10E27000261032103C1C0801279C95C00E0012BECF +:10E28000000000000000000D3C02800030A5FFFFF0 +:10E2900030C600FF344301803C0880008D0901B87E +:10E2A0000520FFFE00000000AC6400002404000212 +:10E2B000A4650008A066000AA064000BAC67001803 +:10E2C0003C03100003E00008AD0301B83C0560000A +:10E2D0008CA24FF80440FFFE00000000ACA44FC029 +:10E2E0003C0310003C040200ACA44FC403E000084F +:10E2F000ACA34FF89486000C00A050212488001491 +:10E3000000062B0200051080004448210109182B4B +:10E310001060001100000000910300002C6400094F +:10E320005080000991190001000360803C0D080134 +:10E3300025AD9258018D58218D67000000E000083E +:10E340000000000091190001011940210109302B42 +:10E3500054C0FFF29103000003E000080000102108 +:10E360000A000CCC25080001910F0001240E000AC0 +:10E3700015EE00400128C8232F38000A1700003D81 +:10E38000250D00028D580000250F0006370E0100F4 +:10E39000AD4E0000910C000291AB000191A400026F +:10E3A00091A60003000C2E00000B3C0000A71025D6 +:10E3B00000041A000043C8250326C025AD580004F8 +:10E3C000910E000691ED000191E7000291E5000336 +:10E3D000000E5E00000D6400016C30250007220075 +:10E3E00000C41025004518252508000A0A000CCC99 +:10E3F000AD430008910F000125040002240800022B +:10E4000055E80001012020210A000CCC00804021A9 +:10E41000910C0001240B0003158B00160000000076 +:10E420008D580000910E000225080003370D0008EA +:10E43000A14E00100A000CCCAD4D00009119000156 +:10E44000240F0004172F000B0000000091070002AA +:10E45000910400038D43000000072A0000A410254A +:10E460003466000425080004AD42000C0A000CCC00 +:10E47000AD46000003E000082402000127BDFFE8CC +:10E48000AFBF0014AFB000100E00164E0080802108 +:10E490003C0480083485008090A600052403FFFE1C +:10E4A0000200202100C310248FBF00148FB0001081 +:10E4B000A0A200050A00165827BD001827BDFFE8D6 +:10E4C000AFB00010AFBF00140E000FD40080802149 +:10E4D0003C06800834C5008090A40000240200504F +:10E4E000308300FF106200073C09800002002021F9 +:10E4F0008FBF00148FB00010AD2001800A00108F74 +:10E5000027BD0018240801003C07800002002021DC +:10E510008FBF00148FB00010ACE801800A00108F8C +:10E5200027BD001827BDFF783C058008AFBE0080DE +:10E53000AFB7007CAFB3006CAFB10064AFBF008475 +:10E54000AFB60078AFB50074AFB40070AFB200687A +:10E55000AFB0006034A600803C0580008CB201287A +:10E5600090C400098CA701043C020001309100FF17 +:10E5700000E218240000B8210000F021106000071C +:10E58000000098213C0908008D2931F02413000176 +:10E59000252800013C010800AC2831F0ACA0008423 +:10E5A00090CC0005000C5827316A0001154000721C +:10E5B000AFA0005090CD00002406002031A400FF41 +:10E5C00010860018240E0050108E009300000000EA +:10E5D0003C1008008E1000DC260F00013C010800F2 +:10E5E000AC2F00DC0E0016C7000000000040182110 +:10E5F0008FBF00848FBE00808FB7007C8FB60078FD +:10E600008FB500748FB400708FB3006C8FB2006848 +:10E610008FB100648FB000600060102103E000083B +:10E6200027BD00880000000D3C1F8000AFA0003017 +:10E6300097E501168FE201043C04002030B9FFFF8A +:10E64000004438240007182B00033140AFA60030E7 +:10E650008FF5010437F80C003C1600400338802188 +:10E6600002B6A02434C40040128000479215000D69 +:10E6700032A800201500000234860080008030217E +:10E6800014C0009FAFA600303C0D800835A6008066 +:10E6900090CC0008318B0040516000063C06800899 +:10E6A000240E0004122E00A8240F0012122F003294 +:10E6B0003C06800834C401003C0280009447011AE3 +:10E6C0009619000E909F00088E18000830E3FFFF97 +:10E6D00003F9B00432B40004AFB6005CAFA3005835 +:10E6E0008E1600041280002EAFB8005434C3008090 +:10E6F000906800083105004014A0002500000000CB +:10E700008C70005002D090230640000500000000ED +:10E710008C71003402D1A82306A201678EE20008A2 +:10E72000126000063C1280003C1508008EB531F4E2 +:10E7300026B600013C010800AC3631F4AE4000447E +:10E74000240300018FBF00848FBE00808FB7007C40 +:10E750008FB600788FB500748FB400708FB3006CE3 +:10E760008FB200688FB100648FB00060006010212C +:10E7700003E0000827BD00880E000D2800002021BE +:10E780000A000D75004018210A000D9500C02021D7 +:10E790000E00171702C020211440FFE10000000006 +:10E7A0003C0B8008356400808C8A003402CA482300 +:10E7B0000520001D000000003C1E08008FDE310017 +:10E7C00027D700013C010800AC3731001260000679 +:10E7D000024020213C1408008E9431F42690000160 +:10E7E0003C010800AC3031F40E00164E3C1E80088F +:10E7F00037CD008091B700250240202136EE00047D +:10E800000E001658A1AE00250E000CAC02402021CF +:10E810000A000DCA240300013C17080126F796C020 +:10E820000A000D843C1F80008C86003002C66023E5 +:10E830001980000C2419000C908F004F3C14080024 +:10E840008E94310032B500FC35ED0001268E0001BA +:10E850003C010800AC2E3100A08D004FAFA0005845 +:10E860002419000CAFB900308C9800300316A02397 +:10E870001A80010B8FA300580074F82A17E0FFD309 +:10E88000000000001074002A8FA5005802D4B021A7 +:10E8900000B410233044FFFFAFA4005832A8000298 +:10E8A0001100002E32AB00103C15800836B00080FD +:10E8B0009216000832D30040526000FB8EE200083E +:10E8C0000E00164E02402021240A0018A20A000958 +:10E8D000921100052409FFFE024020210229902404 +:10E8E0000E001658A2120005240400390000282149 +:10E8F0000E0016F2240600180A000DCA24030001B7 +:10E9000092FE000C3C0A800835490080001EBB00C6 +:10E910008D27003836F10081024020213225F08118 +:10E920000E000C9B30C600FF0A000DC10000000065 +:10E930003AA7000130E300011460FFA402D4B02123 +:10E940000A000E1D00000000024020210E001734B6 +:10E95000020028210A000D75004018211160FF7087 +:10E960003C0F80083C0D800835EE00808DC40038D7 +:10E970008FA300548DA60004006660231D80FF68ED +:10E98000000000000064C02307020001AFA400548F +:10E990003C1F08008FFF31E433F9000113200015FC +:10E9A0008FAC00583C07800094E3011A10600012FD +:10E9B0003C0680080E00216A024020213C03080129 +:10E9C000906396F13064000214800145000000005D +:10E9D000306C0004118000078FAC0058306600FBDB +:10E9E0003C010801A02696F132B500FCAFA000580A +:10E9F0008FAC00583C06800834D30080AFB40018B8 +:10EA0000AFB60010AFAC00143C088000950B01209D +:10EA10008E6F0030966A005C8FA3005C8FBF003061 +:10EA20003169FFFF3144FFFF8FAE005401341021E4 +:10EA3000350540000064382B0045C82103E7C02598 +:10EA4000AFB90020AFAF0028AFB80030AFAF00249F +:10EA5000AFA0002CAFAE0034926D000831B40008B6 +:10EA6000168000BB020020218EE200040040F8095D +:10EA700027A400108FAF003031F300025660000170 +:10EA800032B500FE3C048008349F008093F90008F2 +:10EA900033380040530000138FA400248C850004F9 +:10EAA0008FA7005410A700D52404001432B0000131 +:10EAB0001200000C8FA400242414000C1234011A3C +:10EAC0002A2D000D11A001022413000E240E000AAD +:10EAD000522E0001241E00088FAF002425E40001FF +:10EAE000AFA400248FAA00143C0B80083565008079 +:10EAF000008A48218CB10030ACA9003090A4004EAF +:10EB00008CA700303408FFFF0088180400E3F821C8 +:10EB1000ACBF00348FA600308FB900548FB8005CB2 +:10EB200030C200081040000B033898218CAC002044 +:10EB3000119300D330C600FF92EE000C8FA7003473 +:10EB400002402021000E6B0035B400800E000C9BAB +:10EB50003285F0803C028008345000808E0F0030F7 +:10EB600001F1302318C00097264800803C070800B8 +:10EB70008CE731E42404FF80010418243118007F5D +:10EB80003C1F80003C19800430F10001AFE300908D +:10EB900012200006031928213C030801906396F116 +:10EBA00030690008152000C6306A00F73C10800864 +:10EBB00036040080908C004F318B000115600042BC +:10EBC000000000003C0608008CC6319830CE0010D2 +:10EBD00051C0004230F9000190AF006B55E0003F9A +:10EBE00030F9000124180001A0B8006B3C1180002E +:10EBF0009622007A24470064A48700123C0D800806 +:10EC000035A5008090B40008329000401600000442 +:10EC10003C03800832AE000115C0008B00000000EC +:10EC2000346400808C86002010D3000A3463010015 +:10EC30008C67000002C7782319E000978FBF00544B +:10EC4000AC93002024130001AC760000AFB3005059 +:10EC5000AC7F000417C0004E000000008FA90050D8 +:10EC60001520000B000000003C030801906396F1A2 +:10EC7000306A00011140002E8FAB0058306400FE56 +:10EC80003C010801A02496F10A000D75000018212E +:10EC90000E000CAC024020210A000F1300000000FF +:10ECA0000A000E200000A0210040F80924040017EB +:10ECB0000A000DCA240300010040F80924040016CC +:10ECC0000A000DCA240300019094004F240DFFFE9A +:10ECD000028D2824A085004F30F900011320000682 +:10ECE0003C0480083C030801906396F1307F0010DB +:10ECF00017E00051306800EF34900080240A0001D2 +:10ED0000024020210E00164EA60A00129203002592 +:10ED100024090001AFA90050346200010240202103 +:10ED20000E001658A20200250A000EF93C0D8008BC +:10ED30001160FE83000018218FA5003030AC000464 +:10ED40001180FE2C8FBF00840A000DCB240300012C +:10ED500027A500380E000CB6AFA000385440FF4382 +:10ED60008EE200048FB40038329001005200FF3F61 +:10ED70008EE200048FA3003C8E6E0058006E682364 +:10ED800005A3FF39AE6300580A000E948EE200041A +:10ED90000E00164E024020213C038008346800809B +:10EDA000024020210E001658A11E000903C0302188 +:10EDB000240400370E0016F2000028210A000F116B +:10EDC0008FA900508FAB00185960FF8D3C0D800853 +:10EDD0000E00164E02402021920C00252405000151 +:10EDE000AFA5005035820004024020210E001658C5 +:10EDF000A20200250A000EF93C0D800812240059D9 +:10EE00002A2300151060004D240900162408000C68 +:10EE10005628FF2732B000013C0A8008914C001BA5 +:10EE20002406FFBD241E000E01865824A14B001BA2 +:10EE30000A000EA532B000013C010801A02896F19D +:10EE40000A000EF93C0D80088CB500308EFE0008DB +:10EE50002404001826B6000103C0F809ACB600303F +:10EE60003C030801906396F13077000116E0FF81C2 +:10EE7000306A00018FB200300A000D753243000481 +:10EE80003C1080009605011A50A0FF2B34C60010DC +:10EE90000A000EC892EE000C8C6200001456FF6D42 +:10EEA000000000008C7800048FB9005403388823D8 +:10EEB0000621FF638FBF00540A000F0E0000000000 +:10EEC0003C010801A02A96F10A000F3030F9000138 +:10EED0001633FF028FAF00240A000EB0241E00106C +:10EEE0000E00164E024020213C0B80083568008041 +:10EEF00091090025240A0001AFAA0050353300040F +:10EF0000024020210E001658A11300253C050801DF +:10EF100090A596F130A200FD3C010801A02296F1D7 +:10EF20000A000E6D004018212411000E53D1FEEA94 +:10EF3000241E00100A000EAF241E00165629FEDC07 +:10EF400032B000013C0A8008914C001B2406FFBD32 +:10EF5000241E001001865824A14B001B0A000EA598 +:10EF600032B000010A000EA4241E00123C038000EF +:10EF70008C6201B80440FFFE24040800AC6401B8B0 +:10EF800003E000080000000030A5FFFF30C6FFFFCF +:10EF90003C0780008CE201B80440FFFE34EA0180A7 +:10EFA000AD440000ACE400203C0480089483004899 +:10EFB0003068FFFF11000016AF88000824AB001274 +:10EFC000010B482B512000133C04800034EF01005A +:10EFD00095EE00208F890000240D001A31CCFFFF30 +:10EFE00031274000A14D000B10E000362583FFFEC5 +:10EFF0000103C02B170000348F9900048F88000490 +:10F00000A5430014350700010A001003AF87000470 +:10F010003C04800024030003348201808F890000B7 +:10F020008F870004A043000B3C088000350C018052 +:10F03000A585000EA585001A8F85000C30EB800099 +:10F04000A5890010AD850028A58600081160000F75 +:10F050008F85001435190100972A00163158FFFCDE +:10F06000270F000401E870218DCD400031A6FFFF7D +:10F0700014C000072403BFFF3C02FFFF34487FFF9A +:10F0800000E83824AF8700048F8500142403BFFFF5 +:10F090003C04800000E3582434830180A46B0026E4 +:10F0A000AC69002C10A0000300054C02A465001000 +:10F0B000A46900263C071000AC8701B803E00008F3 +:10F0C000000000008F990004240AFFFE032A382460 +:10F0D0000A001003AF87000427BDFFE88FA20028B5 +:10F0E00030A5FFFF30C6FFFFAFBF0010AF87000C99 +:10F0F000AF820014AF8000040E000FDBAF80000071 +:10F100008FBF001027BD001803E00008AF80001477 +:10F110003C06800034C4007034C701008C8A0000B3 +:10F1200090E500128F84000027BDFFF030A300FFA0 +:10F13000000318823082400010400037246500032D +:10F140000005C8800326C0218F0E4000246F0004F4 +:10F15000000F6880AFAE000001A660218D8B4000DB +:10F16000AFAB000494E900163128FFFC01063821FA +:10F170008CE64000AFA600088FA9000800003021EF +:10F18000000028213C07080024E701000A0010675E +:10F19000240800089059000024A500012CAC000CA4 +:10F1A0000079C0210018788001E770218DCD000022 +:10F1B0001180000600CD302603A5102114A8FFF50C +:10F1C00000051A005520FFF4905900003C0480000F +:10F1D000348700703C0508008CA531048CE30000E6 +:10F1E0002CA2002010400009006A38230005488046 +:10F1F0003C0B0800256B3108012B402124AA00019B +:10F20000AD0700003C010800AC2A310400C0102109 +:10F2100003E0000827BD0010308220001040000BE2 +:10F2200000055880016648218D24400024680004B0 +:10F2300000083880AFA4000000E618218C6540006B +:10F24000AFA000080A001057AFA500040000000D91 +:10F250000A0010588FA9000827BDFFE03C07800076 +:10F2600034E60100AFBF001CAFB20018AFB100140C +:10F27000AFB0001094C5000E8F87000030A4FFFFD0 +:10F280002483000430E2400010400010AF830028C7 +:10F290003C09002000E940241100000D30EC800002 +:10F2A0008F8A0004240BBFFF00EB38243543100085 +:10F2B000AF87000030F220001640000B3C1900041C +:10F2C000241FFFBF0A0010B7007F102430EC80001D +:10F2D000158000423C0E002030F220001240FFF862 +:10F2E0008F8300043C19000400F9C0241300FFF5CB +:10F2F000241FFFBF34620040AF82000430E20100EF +:10F300001040001130F010008F83002C10600006B8 +:10F310003C0F80003C05002000E52024148000C044 +:10F320003C0800043C0F800035EE010095CD001E26 +:10F3300095CC001C31AAFFFF000C5C00014B482556 +:10F34000AF89000C30F010001200000824110001F9 +:10F3500030F100201620008B3C18100000F890249B +:10F36000164000823C040C002411000130E801002A +:10F370001500000B3C0900018F85000430A94000F6 +:10F38000152000073C0900013C0C1F0100EC58242B +:10F390003C0A1000116A01183C1080003C09000171 +:10F3A00000E9302410C000173C0B10003C18080086 +:10F3B0008F1800243307000214E0014024030001E9 +:10F3C0008FBF001C8FB200188FB100148FB00010D7 +:10F3D0000060102103E0000827BD002000EE682433 +:10F3E00011A0FFBE30F220008F8F00043C11FFFF00 +:10F3F00036307FFF00F0382435E380000A0010A685 +:10F40000AF87000000EB102450400065AF8000245F +:10F410008F8C002C3C0D0F0000ED18241580008807 +:10F42000AF83001030E8010011000086938F0010B8 +:10F430003C0A0200106A00833C1280003650010032 +:10F44000920500139789002A3626000230AF00FF8C +:10F4500025EE0004000E19C03C0480008C9801B811 +:10F460000700FFFE34880180AD0300003C198008CE +:10F47000AC830020973100483225FFFF10A0015CCB +:10F48000AF8500082523001200A3F82B53E0015993 +:10F490008F850004348D010095AC00202402001AF1 +:10F4A00030E44000318BFFFFA102000B108001927D +:10F4B0002563FFFE00A3502B154001908F8F0004A1 +:10F4C000A50300148F88000435050001AF850004F2 +:10F4D0003C08800035190180A729000EA729001AD1 +:10F4E0008F89000C30B18000A7270010AF290028B9 +:10F4F000A72600081220000E3C04800035020100FF +:10F50000944C0016318BFFFC256400040088182100 +:10F510008C7F400033E6FFFF14C000053C048000F0 +:10F520003C0AFFFF354D7FFF00AD2824AF85000466 +:10F53000240EBFFF00AE402434850180A4A800261D +:10F54000ACA7002C3C071000AC8701B800001821C4 +:10F550008FBF001C8FB200188FB100148FB0001045 +:10F560000060102103E0000827BD00203C020BFFD3 +:10F5700000E41824345FFFFF03E3C82B5320FF7B14 +:10F58000241100013C0608008CC6002C24C5000193 +:10F590003C010800AC25002C0A0010D42411000501 +:10F5A0008F85002410A0002FAF80001090A30000D2 +:10F5B000146000792419000310A0002A30E601002D +:10F5C00010C000CC8F860010241F000210DF00C97D +:10F5D0008F8B000C3C0708008CE7003824E4FFFF09 +:10F5E00014E0000201641824000018213C0D0800FA +:10F5F00025AD0038006D1021904C00048F85002847 +:10F6000025830004000321C030A5FFFF3626000239 +:10F610000E000FDB000000000A00114D0000182151 +:10F6200000E8302414C0FF403C0F80000E00103D65 +:10F63000000000008F8700000A0010CAAF82000C93 +:10F64000938F00103C18080127189640000F90C0B7 +:10F6500002588021AF9000248F85002414A0FFD38E +:10F66000AF8F00103C0480008C86400030C5010044 +:10F6700010A000BC322300043C0C08008D8C002438 +:10F6800024120004106000C23190000D3C04800080 +:10F690008C8D40003402FFFF11A201003231FFFBCC +:10F6A0008C884000310A01005540000124110010EF +:10F6B00030EE080011C000BE2419FFFB8F9800280F +:10F6C0002F0F03EF51E000010219802430E90100FF +:10F6D00011200014320800018F87002C14E000FB79 +:10F6E0008F8C000C3C05800034AB0100917F00132F +:10F6F00033E300FF246A00042403FFFE0203802496 +:10F70000000A21C012000002023230253226FFFF1B +:10F710000E000FDB9785002A1200FF290000182138 +:10F72000320800011100000D32180004240E0001FF +:10F73000120E0002023230253226FFFF9785002A82 +:10F740000E000FDB00002021240FFFFE020F80249B +:10F750001200FF1B00001821321800045300FF188C +:10F760002403000102323025241200045612000145 +:10F770003226FFFF9785002A0E000FDB24040100CC +:10F780002419FFFB021988241220FF0D0000182104 +:10F790000A0010E9240300011079009C00003021C8 +:10F7A00090AD00012402000211A200BE30EA004028 +:10F7B00090B90001241800011338007F30E900409F +:10F7C0008CA600049785002A00C020210E000FDBC4 +:10F7D0003626000200004021010018218FBF001CC6 +:10F7E0008FB200188FB100148FB00010006010218C +:10F7F00003E0000827BD0020360F010095EE000C45 +:10F8000031CD020015A0FEE63C0900013C1880083D +:10F81000971200489789002A362600023248FFFFD7 +:10F82000AF8800083C0380008C7101B80620FFFE01 +:10F83000346A0180AD4000001100008E3C0F800052 +:10F84000253F0012011FC82B1320008B240E00033C +:10F85000346C0100958B00202402001A30E4400033 +:10F860003163FFFFA142000B108000A72463FFFE5D +:10F870000103682B15A000A52408FFFE34A5000194 +:10F88000A5430014AF8500043C0480002412BFFF90 +:10F8900000B2802434850180A4A9000EA4A9001A16 +:10F8A000A4A60008A4B00026A4A700103C071000DE +:10F8B000AC8701B80A00114D000018213C038000FC +:10F8C00034640100949F000E3C1908008F3900D861 +:10F8D0002404008033E5FFFF273100013C010800CC +:10F8E000AC3100D80E000FDB240600030A00114DD6 +:10F8F00000001821240A000210CA00598F85002830 +:10F900003C0308008C6300D0240E0001106E005EE2 +:10F910002CCF000C24D2FFFC2E5000041600002136 +:10F9200000002021241800021078001B2CD9000CA4 +:10F9300024DFFFF82FE900041520FF330000202109 +:10F9400030EB020051600004000621C054C00022C8 +:10F9500030A5FFFF000621C030A5FFFF0A00117D82 +:10F96000362600023C0908008D29002431300001B0 +:10F970005200FEF7000018219785002A3626000263 +:10F980000E000FDB000020210A00114D000018219D +:10F990000A00119C241200021320FFE624DFFFF866 +:10F9A0000000202130A5FFFF0A00117D362600024D +:10F9B0000A0011AC021980245120FF828CA6000499 +:10F9C0003C05080190A5964110A0FF7E2408000187 +:10F9D0000A0011F0010018210E000FDB3226000191 +:10F9E0008F8600108F8500280A00124F000621C064 +:10F9F0008F8500043C18800024120003371001801A +:10FA0000A212000B0A00112E3C08800090A30001F6 +:10FA1000241100011071FF70240800012409000264 +:10FA20005069000430E60040240800010A0011F08B +:10FA30000100182150C0FFFD240800013C0C80008B +:10FA4000358B01009563001094A40002307FFFFF06 +:10FA5000509FFF62010018210A001284240800014F +:10FA60002CA803EF1100FE56240300010A001239EE +:10FA700000000000240E000335EA0180A14E000BB7 +:10FA80000A00121C3C04800011E0FFA2000621C005 +:10FA900030A5FFFF0A00117D362600020A0011A5DD +:10FAA000241100201140FFC63C1280003650010096 +:10FAB000960F001094AE000231E80FFF15C8FFC08A +:10FAC000000000000A0011E690B900013C060800A1 +:10FAD0008CC6003824C4FFFF14C00002018418241F +:10FAE000000018213C0D080025AD0038006D1021E4 +:10FAF0000A0011B6904300048F8F0004240EFFFE0D +:10FB00000A00112C01EE28242408FFFE0A00121A14 +:10FB100000A8282427BDFFC8AFB00010AFBF003435 +:10FB20003C10600CAFBE0030AFB7002CAFB6002861 +:10FB3000AFB50024AFB40020AFB3001CAFB20018C3 +:10FB4000AFB100148E0E5000240FFF7F3C068000E2 +:10FB500001CF682435AC380C240B0003AE0C5000E8 +:10FB6000ACCB00083C010800AC2000200E001819A6 +:10FB7000000000003C0A0010354980513C06601628 +:10FB8000AE09537C8CC700003C0860148D0500A0B2 +:10FB90003C03FFFF00E320243C02535300051FC237 +:10FBA0001482000634C57C000003A08002869821E0 +:10FBB0008E7200043C116000025128218CBF007C31 +:10FBC0008CA200783C1E600037C420203C05080150 +:10FBD00024A59288AF820018AF9F001C0E0016DD8E +:10FBE0002406000A3C190001273996403C01080010 +:10FBF000AC3931DC0E0020DDAF8000148FD708084F +:10FC00002418FFF03C15570902F8B02412D502F56C +:10FC100024040001AF80002C3C1480003697018042 +:10FC20003C1E080127DE9644369301008E900000AA +:10FC30003205000310A0FFFD3207000110E000882C +:10FC4000320600028E7100283C048000AE91002034 +:10FC50008E6500048E66000000A0382100C040219F +:10FC60008C8301B80460FFFE3C0B0010240A0800DE +:10FC700000AB4824AC8A01B8552000E0240BBFFF3C +:10FC80009675000E3C1208008E52002030AC4000E9 +:10FC900032AFFFFF264E000125ED00043C010800B5 +:10FCA000AC2E0020118000E8AF8D00283C18002009 +:10FCB00000B8B02412C000E530B980002408BFFFAE +:10FCC00000A8382434C81000AF87000030E62000B8 +:10FCD00010C000E92409FFBF3C03000400E328240E +:10FCE00010A00002010910243502004030EA010092 +:10FCF00011400010AF8200048F8B002C11600007B0 +:10FD00003C0D002000ED6024118000043C0F000435 +:10FD100000EF702411C00239000000009668001E38 +:10FD20009678001C3115FFFF0018B40002B690252C +:10FD3000AF92000C30F910001320001324150001BD +:10FD400030FF002017E0000A3C04100000E41024FB +:10FD50001040000D3C0A0C003C090BFF00EA18247F +:10FD60003525FFFF00A3302B10C0000830ED010047 +:10FD70003C0C08008D8C002C24150005258B0001FF +:10FD80003C010800AC2B002C30ED010015A0000B4D +:10FD90003C0500018F85000430AE400055C00007CF +:10FDA0003C0500013C161F0100F690243C0F10009A +:10FDB000124F01CE000000003C05000100E5302498 +:10FDC00010C000AF3C0C10003C1F08008FFF002447 +:10FDD00033E90002152000712403000100601021A6 +:10FDE000104000083C0680003C08800035180100E7 +:10FDF0008F0F00243C056020ACAF00140000000011 +:10FE00003C0680003C194000ACD9013800000000DD +:10FE10005220001332060002262B0140262C0080BF +:10FE2000240EFF80016E2024018E6824000D1940ED +:10FE3000318A007F0004A9403172007F3C16200007 +:10FE400036C20002006A482502B2382500E2882541 +:10FE50000122F825ACDF0830ACD1083032060002B0 +:10FE600010C0FF723C188000370501408CA80000CC +:10FE700024100040AF08002090AF000831E300706C +:10FE8000107000D428790041532000082405006038 +:10FE9000241100201071000E3C0A40003C09800033 +:10FEA000AD2A01780A001304000000001465FFFB6E +:10FEB0003C0A40000E001FFA000000003C0A40000F +:10FEC0003C098000AD2A01780A00130400000000FC +:10FED00090A90009241F00048CA70000312800FF0E +:10FEE000111F01B22503FFFA2C7200061240001404 +:10FEF0003C0680008CA9000494A4000A310500FF90 +:10FF000000095E022D6A00083086FFFF15400002DE +:10FF10002567000424070003240C000910AC01FA33 +:10FF200028AD000A11A001DE2410000A240E0008EA +:10FF300010AE0028000731C000C038213C06800008 +:10FF40008CD501B806A0FFFE34D20180AE47000078 +:10FF500034CB0140916E0008240300023C0A4000AB +:10FF600031C400FF00046A0001A86025A64C000807 +:10FF7000A243000B9562000A3C0810003C09800077 +:10FF8000A64200108D670004AE470024ACC801B83B +:10FF9000AD2A01780A001304000000003C0A80002A +:10FFA000354401009483000E3C0208008C4200D8C6 +:10FFB000240400803065FFFF245500013C01080047 +:10FFC000AC3500D80E000FDB240600030A001370C6 +:10FFD000000018210009320230D900FF2418000166 +:10FFE0001738FFD5000731C08F910020262200016D +:10FFF000AF8200200A0013C800C0382100CB2024A3 +:020000021000EC +:10000000AF85000010800008AF860004240D87FF34 +:1000100000CD6024158000083C0E006000AE302446 +:1000200010C00005000000000E000D42000000009E +:100030000A001371000000000E0016050000000009 +:100040000A0013710000000030B980005320FF1F28 +:10005000AF8500003C02002000A2F82453E0FF1B03 +:10006000AF8500003C07FFFF34E47FFF00A4382485 +:100070000A00132B34C880000A001334010910242D +:1000800000EC58245160005AAF8000248F8D002C62 +:100090003C0E0F0000EE182415A00075AF83001071 +:1000A00030EF010011E00073939800103C12020041 +:1000B000107200703C06800034D9010093280013B0 +:1000C0009789002A36A60002311800FF271600047F +:1000D000001619C03C0480008C8501B804A0FFFE06 +:1000E00034880180AD0300003C158008AC830020FB +:1000F00096BF004833E5FFFF10A001BCAF850008A4 +:100100002523001200A3102B504001B98F85000455 +:10011000348D010095AC0020240B001A30E440001F +:10012000318AFFFFA10B000B108001BA2543FFFEAF +:1001300000A3702B15C001B88F9600048F8F0004A8 +:10014000A503001435E50001AF8500043C088000DC +:1001500035150180A6A9000EA6A9001A8F89000CEA +:1001600030BF8000A6A70010AEA90028A6A60008F0 +:1001700013E0000F3C0F8000350C0100958B00163A +:10018000316AFFFC25440004008818218C6240007D +:100190003046FFFF14C000072416BFFF3C0EFFFFD0 +:1001A00035CD7FFF00AD2824AF8500043C0F8000D3 +:1001B0002416BFFF00B6902435E50180A4B20026C6 +:1001C000ACA7002C3C071000ADE701B80A00137083 +:1001D000000018210E00165D000000003C0A4000DF +:1001E0003C098000AD2A01780A00130400000000D9 +:1001F0008F85002410A00027AF80001090A300007E +:10020000106000742409000310690101000030210E +:1002100090AE0001240D000211CD014230EF0040EC +:1002200090A90001241F0001113F000930E20040A5 +:100230008CA600049785002A00C020210E000FDB49 +:1002400036A60002000040210A00137001001821A8 +:100250005040FFF88CA600043C07080190E7964147 +:1002600010E0FFF4240800010A00137001001821B7 +:10027000939800103C1F080127FF96400018C8C043 +:10028000033F4021AF8800248F85002414A0FFDBAA +:10029000AF9800103C0480008C86400030C50100FF +:1002A00010A0008732AB00043C0C08008D8C0024A9 +:1002B00024160004156000033192000D241600027C +:1002C0003C0480008C8E4000340DFFFF11CD0113E3 +:1002D00032B5FFFB8C984000330F010055E0000160 +:1002E0002415001030E80800110000382409FFFB35 +:1002F0008F9F00282FF903EF53200001024990241B +:1003000030E2010010400014325F00018F87002CA2 +:1003100014E0010E8F8C000C3C0480003486010038 +:1003200090C5001330AA00FF25430004000321C03C +:100330002419FFFE025990241240000202B6302513 +:1003400032A6FFFF0E000FDB9785002A1240FEA3A6 +:1003500000001821325F000113E0000D3247000455 +:10036000240900011249000202B6302532A6FFFF1F +:100370009785002A0E000FDB000020212402FFFEDB +:10038000024290241240FE950000182132470004DA +:1003900050E0FE922403000102B63025241600042A +:1003A0005656000132A6FFFF9785002A0E000FDB8C +:1003B000240401002403FFFB0243A82412A0FE87AB +:1003C000000018210A001370240300010A0014B968 +:1003D0000249902410A0FFAF30E5010010A00017E3 +:1003E0008F8600102403000210C300148F84000CB9 +:1003F0003C0608008CC6003824CAFFFF14C0000267 +:10040000008A1024000010213C0E080025CE003880 +:10041000004E682191AC00048F850028258B0004D4 +:10042000000B21C030A5FFFF36A600020E000FDB37 +:10043000000000000A00137000001821240F0002C1 +:1004400010CF0088241600013C0308008C6300D004 +:100450001076008D8F85002824D9FFFC2F280004FA +:100460001500006300002021241F0002107F005DA2 +:100470002CC9000C24C3FFF82C6200041440FFE9CF +:100480000000202130EA020051400004000621C093 +:1004900054C0000530A5FFFF000621C030A5FFFFB6 +:1004A0000A00150436A600020E000FDB32A600017A +:1004B0008F8600108F8500280A001520000621C0B5 +:1004C0003C0A08008D4A0024315200015240FE438C +:1004D000000018219785002A36A600020E000FDBC7 +:1004E000000020210A001370000018219668000CFB +:1004F000311802005700FE313C0500013C1F800806 +:1005000097F900489789002A36A600023328FFFF92 +:10051000AF8800083C0380008C7501B806A0FFFE80 +:100520003C04800034820180AC400000110000B621 +:1005300024180003252A0012010A182B106000B2AB +:1005400000000000966F00203C0E8000240D001A71 +:1005500031ECFFFF35CA018030EB4000A14D000BAC +:10056000116000B02583FFFE0103902B164000AE02 +:100570002416FFFE34A50001A5430014AF85000436 +:100580002419BFFF00B94024A6E9000EA6E9001A0D +:10059000A6E60008A6E80026A6E700103C07100023 +:1005A000AE8701B80A001370000018213C048000D7 +:1005B0008C8201B80440FFFE349601802415001C93 +:1005C000AEC70000A2D5000B3C071000AC8701B8F5 +:1005D0003C0A40003C098000AD2A01780A0013045F +:1005E000000000005120FFA424C3FFF800002021D8 +:1005F00030A5FFFF0A00150436A600020E00103DCC +:10060000000000008F8700000A001346AF82000C34 +:1006100090A30001241500011075FF0B24080001B0 +:10062000240600021066000430E2004024080001A5 +:100630000A001370010018215040FFFD240800013A +:100640003C0C8000358B0100956A001094A40002D8 +:100650003143FFFF5083FDE1010018210A00158599 +:10066000240800018F8500282CB203EF1240FDDB27 +:10067000240300013C0308008C6300D02416000111 +:100680001476FF7624D9FFFC2CD8000C1300FF72DF +:10069000000621C030A5FFFF0A00150436A600029F +:1006A00010B00037240F000B14AFFE23000731C039 +:1006B000312600FF00065600000A4E0305220047BF +:1006C00030C6007F0006F8C03C16080126D69640CA +:1006D00003F68021A2000001A20000003C0F600090 +:1006E0008DF918202405000100C588040011302769 +:1006F0000326C024000731C000C03821ADF81820FF +:100700000A0013C8A60000028F850020000731C030 +:1007100024A2FFFF0A0013F6AF8200200A0014B2E1 +:100720002415002011E0FECC3C1980003728010080 +:100730009518001094B6000233120FFF16D2FEC6B1 +:10074000000000000A00148290A900013C0B080080 +:100750008D6B0038256DFFFF15600002018D1024A0 +:10076000000010213C080800250800380048C0217E +:10077000930F000425EE00040A0014C5000E21C0EA +:1007800000065202241F00FF115FFDEB000731C07D +:10079000000A20C03C0E080125CE9640008EA821FC +:1007A000009E602100095C02240D00013C076000EE +:1007B000A2AD0000AD860000A2AB00018CF21820B3 +:1007C00024030001014310040242B025ACF61820B6 +:1007D00000C038210A0013C8A6A900020A0015AA01 +:1007E000AF8000200A0012FFAF84002C8F85000428 +:1007F0003C1980002408000337380180A308000B4F +:100800000A00144D3C088000A2F8000B0A00155A9B +:100810002419BFFF8F9600042412FFFE0A00144B18 +:1008200002D228242416FFFE0A00155800B62824F8 +:100830003C038000346401008C85000030A2003E3F +:100840001440000800000000AC6000488C870000E5 +:1008500030E607C010C0000500000000AC60004C8E +:10086000AC60005003E0000824020001AC600054BA +:10087000AC6000408C880000310438001080FFF923 +:10088000000000002402000103E00008AC60004406 +:100890003C0380008C6201B80440FFFE3467018095 +:1008A000ACE4000024080001ACE00004A4E500086A +:1008B00024050002A0E8000A34640140A0E5000B12 +:1008C0009483000A14C00008A4E30010ACE00024E4 +:1008D0003C07800034E901803C041000AD20002872 +:1008E00003E00008ACE401B88C8600043C0410006E +:1008F000ACE600243C07800034E90180AD200028EC +:1009000003E00008ACE401B83C0680008CC201B8EA +:100910000440FFFE34C7018024090002ACE400005B +:10092000ACE40004A4E50008A0E9000A34C50140D5 +:10093000A0E9000B94A8000A3C041000A4E80010F1 +:10094000ACE000248CA30004ACE3002803E0000822 +:10095000ACC401B83C039000346200010082202541 +:100960003C038000AC6400208C65002004A0FFFEE6 +:100970000000000003E00008000000003C028000CE +:10098000344300010083202503E00008AC4400202C +:1009900027BDFFE03C098000AFBF0018AFB10014D5 +:1009A000AFB00010352801408D10000091040009FF +:1009B0009107000891050008308400FF30E600FF31 +:1009C00000061A002C820081008330251040002A86 +:1009D00030A50080000460803C0D080125AD92B078 +:1009E000018D58218D6A00000140000800000000C0 +:1009F0003C038000346201409445000A14A0001EAC +:100A00008F91FCC09227000530E6000414C0001A44 +:100A1000000000000E00164E02002021922A000560 +:100A200002002021354900040E001658A2290005B5 +:100A30009228000531040004148000020000000028 +:100A40000000000D922D0000240B002031AC00FFAF +:100A5000158B00093C0580008CAE01B805C0FFFE77 +:100A600034B10180AE3000003C0F100024100005AE +:100A7000A230000BACAF01B80000000D8FBF001812 +:100A80008FB100148FB0001003E0000827BD0020D4 +:100A90000200202100C028218FBF00188FB1001450 +:100AA0008FB00010240600010A00161D27BD00208B +:100AB0000000000D0200202100C028218FBF001877 +:100AC0008FB100148FB00010000030210A00161DF5 +:100AD00027BD002014A0FFE8000000000200202134 +:100AE0008FBF00188FB100148FB0001000C02821F4 +:100AF0000A00163B27BD00203C0780008CEE01B8A1 +:100B000005C0FFFE34F00180241F0002A21F000B6D +:100B100034F80140A60600089719000A3C0F10009F +:100B2000A61900108F110004A6110012ACEF01B835 +:100B30000A0016998FBF001827BDFFE8AFBF00104D +:100B40000E000FD4000000003C0280008FBF001098 +:100B500000002021AC4001800A00108F27BD001842 +:100B60003084FFFF30A5FFFF108000070000182130 +:100B7000308200011040000200042042006518216C +:100B80001480FFFB0005284003E0000800601021EE +:100B900010C00007000000008CA2000024C6FFFF68 +:100BA00024A50004AC82000014C0FFFB24840004D0 +:100BB00003E000080000000010A0000824A3FFFFCD +:100BC000AC86000000000000000000002402FFFFCF +:100BD0002463FFFF1462FFFA2484000403E000088A +:100BE000000000003C03800027BDFFF83462018054 +:100BF000AFA20000308C00FF30AD00FF30CE00FF10 +:100C00003C0B80008D6401B80480FFFE00000000F2 +:100C10008FA900008D6801288FAA00008FA700000F +:100C20008FA400002405000124020002A085000A10 +:100C30008FA30000359940003C051000A062000B16 +:100C40008FB800008FAC00008FA600008FAF0000AF +:100C500027BD0008AD280000AD400004AD80002491 +:100C6000ACC00028A4F90008A70D0010A5EE0012E2 +:100C700003E00008AD6501B83C06800827BDFFE829 +:100C800034C50080AFBF001090A7000924020012F5 +:100C900030E300FF1062000B008030218CA8005070 +:100CA00000882023048000088FBF00108CAA003425 +:100CB000240400390000282100CA4823052000052B +:100CC000240600128FBF00102402000103E0000878 +:100CD00027BD00180E0016F2000000008FBF0010A4 +:100CE0002402000103E0000827BD001827BDFFC84B +:100CF000AFB20030AFB00028AFBF0034AFB1002CAE +:100D000000A0802190A5000D30A6001010C000109A +:100D1000008090213C0280088C4400048E0300086F +:100D20001064000C30A7000530A6000510C0009329 +:100D3000240400018FBF00348FB200308FB1002C2B +:100D40008FB000280080102103E0000827BD003884 +:100D500030A7000510E0000F30AB001210C00006F5 +:100D6000240400013C0980088E0800088D25000439 +:100D70005105009C240400388FBF00348FB200302E +:100D80008FB1002C8FB000280080102103E00008F4 +:100D900027BD0038240A0012156AFFE6240400016A +:100DA0000200202127A500100E000CB6AFA00010F5 +:100DB0001440007C3C19800837240080909800087B +:100DC000331100081220000A8FA7001030FF010025 +:100DD00013E000A48FA300148C8600580066102333 +:100DE000044000043C0A8008AC8300588FA7001020 +:100DF0003C0A800835480080910900083124000829 +:100E00001480000224080003000040213C1F8008D9 +:100E100093F1001193F9001237E600808CCC005456 +:100E2000333800FF03087821322D00FF000F708057 +:100E300001AE282100AC582B1160006F00000000AB +:100E400094CA005C8CC900543144FFFF0125102373 +:100E50000082182B14600068000000008CCB005446 +:100E60000165182330EC00041180006C000830800C +:100E70008FA8001C0068102B1040006230ED0004A9 +:100E8000006610232C46008010C00002004088211C +:100E9000241100800E00164E024020213C0D8008D7 +:100EA00035A6008024070001ACC7000C90C80008DC +:100EB0000011484035A70100310C007FA0CC00088C +:100EC0008E05000424AB0001ACCB0030A4D1005C43 +:100ED0008CCA003C9602000E01422021ACC40020C6 +:100EE0008CC3003C0069F821ACDF001C8E190004A3 +:100EF000ACF900008E180008ACF800048FB10010A7 +:100F0000322F000855E0004793A60020A0C0004EF5 +:100F100090D8004E2411FFDFA0F8000890CF000801 +:100F200001F17024A0CE00088E0500083C0B80085B +:100F300035690080AD2500388D6A00148D2200309F +:100F40002419005001422021AD24003491230000D7 +:100F5000307F00FF13F90036264F01000E001658AF +:100F60000240202124040038000028210E0016F23F +:100F70002406000A0A001757240400010E000D2859 +:100F8000000020218FBF00348FB200308FB1002CC1 +:100F90008FB00028004020210080102103E00008CD +:100FA00027BD00388E0E00083C0F800835F0008009 +:100FB000AE0E005402402021AE0000300E00164E4E +:100FC00000000000920D00250240202135AC0020D9 +:100FD0000E001658A20C00250E000CAC0240202179 +:100FE000240400382405008D0E0016F22406001299 +:100FF0000A0017572404000194C5005C0A001792E8 +:1010000030A3FFFF2407021811A0FF9E00E6102363 +:101010008FAE001C0A00179A01C610230A0017970A +:101020002C620218A0E600080A0017C48E0500080A +:101030002406FF8001E6C0243C118000AE38002861 +:101040008E0D000831E7007F3C0E800C00EE602121 +:10105000AD8D00E08E080008AF8C00380A0017D074 +:10106000AD8800E4AC800058908500082403FFF7A9 +:1010700000A33824A08700080A0017758FA7001066 +:101080003C05080024A560A83C04080024846FF4F3 +:101090003C020800244260B0240300063C01080121 +:1010A000AC2596C03C010801AC2496C43C01080163 +:1010B000AC2296C83C010801A02396CC03E00008AE +:1010C0000000000003E00008240200013C02800050 +:1010D000308800FF344701803C0680008CC301B893 +:1010E0000460FFFE000000008CC501282418FF806A +:1010F0003C0D800A24AF010001F8702431EC007F20 +:10110000ACCE0024018D2021ACE50000948B00EAD8 +:101110003509600024080002316AFFFFACEA0004D0 +:1011200024020001A4E90008A0E8000BACE00024C0 +:101130003C071000ACC701B8AF84003803E00008DA +:10114000AF85006C938800488F8900608F820038DB +:1011500030C600FF0109382330E900FF01221821C1 +:1011600030A500FF2468008810C000020124382147 +:101170000080382130E400031480000330AA00030B +:101180001140000D312B000310A0000900001021B8 +:1011900090ED0000244E000131C200FF0045602B9D +:1011A000A10D000024E700011580FFF925080001CA +:1011B00003E00008000000001560FFF300000000DD +:1011C00010A0FFFB000010218CF80000245900043F +:1011D000332200FF0045782BAD18000024E70004FF +:1011E00015E0FFF92508000403E0000800000000F6 +:1011F00093850048938800588F8700600004320070 +:101200003103007F00E5102B30C47F001040000F39 +:10121000006428258F8400383C0980008C8A00EC0B +:10122000AD2A00A43C03800000A35825AC6B00A0AD +:101230008C6C00A00580FFFE000000008C6D00ACEF +:10124000AC8D00EC03E000088C6200A80A00188254 +:101250008F840038938800593C0280000080502120 +:10126000310300FEA383005930ABFFFF30CC00FFF9 +:1012700030E7FFFF344801803C0980008D2401B82D +:101280000480FFFE8F8D006C24180016AD0D000049 +:101290008D2201248F8D0038AD0200048D5900206D +:1012A000A5070008240201C4A119000AA118000B17 +:1012B000952F01208D4E00088D4700049783005C18 +:1012C0008D59002401CF302100C7282100A32023FD +:1012D0002418FFFFA504000CA50B000EA5020010AA +:1012E000A50C0012AD190018AD18002495AF00E848 +:1012F0003C0B10002407FFF731EEFFFFAD0E002876 +:101300008DAC0084AD0C002CAD2B01B88D460020B7 +:1013100000C7282403E00008AD4500208F8800386E +:101320000080582130E7FFFF910900D63C02800081 +:1013300030A5FFFF312400FF00041A00006750258C +:1013400030C600FF344701803C0980008D2C01B875 +:101350000580FFFE8F82006C240F0017ACE20000B6 +:101360008D390124ACF900048D780020A4EA00082E +:10137000241901C4A0F8000AA0EF000B9523012056 +:101380008D6E00088D6D00049784005C01C35021B0 +:10139000014D602101841023A4E2000CA4E5000E9D +:1013A000A4F90010A4E60012ACE000148D7800242B +:1013B000240DFFFFACF800188D0F007CACEF001C73 +:1013C0008D0E00783C0F1000ACEE0020ACED002438 +:1013D000950A00BE240DFFF73146FFFFACE600285A +:1013E000950C00809504008231837FFF0003CA00C2 +:1013F0003082FFFF0322C021ACF8002CAD2F01B8D2 +:10140000950E00828D6A002000AE3021014D282407 +:10141000A506008203E00008AD6500203C028000C4 +:10142000344501803C0480008C8301B80460FFFED9 +:101430008F8A0044240600199549001C3128FFFFBB +:10144000000839C0ACA70000A0A6000B3C051000A6 +:1014500003E00008AC8501B88F87004C0080402174 +:1014600030C400FF3C0680008CC201B80440FFFE7F +:101470008F89006C9383006834996000ACA90000E8 +:10148000A0A300058CE20010240F00022403FFF744 +:10149000A4A20006A4B900088D180020A0B8000A74 +:1014A000A0AF000B8CEE0000ACAE00108CED000481 +:1014B000ACAD00148CEC001CACAC00248CEB002018 +:1014C000ACAB00288CEA002C3C071000ACAA002C26 +:1014D0008D090024ACA90018ACC701B88D05002007 +:1014E00000A3202403E00008AD0400208F8600380C +:1014F00027BDFFE0AFB10014AFBF0018AFB00010C0 +:1015000090C300D430A500FF3062002010400008D6 +:10151000008088218CCB00D02409FFDF256A0001E0 +:10152000ACCA00D090C800D401093824A0C700D4A8 +:1015300014A000403C0C80008F840038908700D4B9 +:101540002418FFBF2406FFEF30E3007FA08300D400 +:10155000979F005C8F8200608F8D003803E2C82364 +:10156000A799005CA5A000BC91AF00D401F870243D +:10157000A1AE00D48F8C0038A18000D78F8A0038AC +:10158000A5400082AD4000EC914500D400A658244F +:10159000A14B00D48F9000348F8400609786005C4C +:1015A0000204282110C0000FAF850034A38000582A +:1015B0003C0780008E2C000894ED01208E2B000447 +:1015C000018D5021014B8021020620233086FFFF30 +:1015D00030C8000F3909000131310001162000091F +:1015E000A3880058938600488FBF00188FB100145D +:1015F0008FB0001027BD0020AF85006403E0000815 +:10160000AF86006000C870238FBF00189386004823 +:101610008FB100148FB0001034EF0C00010F28219F +:1016200027BD0020ACEE0084AF85006403E0000815 +:10163000AF86006035900180020028210E00190F4E +:10164000240600828F840038908600D430C5004084 +:1016500050A0FFBAA38000688F85004C3C06800034 +:101660008CCD01B805A0FFFE8F89006C2408608234 +:1016700024070002AE090000A6080008A207000B1C +:101680008CA300083C0E1000AE0300108CA2000CCE +:10169000AE0200148CBF0014AE1F00188CB90018E5 +:1016A000AE1900248CB80024AE1800288CAF002896 +:1016B000AE0F002CACCE01B80A001948A380006818 +:1016C0008F8A003827BDFFE0AFB10014AFB0001023 +:1016D0008F880060AFBF00189389003C954200BC22 +:1016E00030D100FF0109182B0080802130AC00FFB1 +:1016F0003047FFFF0000582114600003310600FF4F +:1017000001203021010958239783005C0068202BB9 +:101710001480002700000000106800562419000102 +:101720001199006334E708803165FFFF0E0018C08F +:10173000020020218F83006C3C07800034E601808A +:101740003C0580008CAB01B80560FFFE240A001840 +:101750008F840038ACC30000A0CA000B948900BE7F +:101760003C081000A4C90010ACC00030ACA801B8FF +:101770009482008024430001A4830080949F008011 +:101780003C0608008CC6318833EC7FFF1186005E72 +:101790000000000002002021022028218FBF001835 +:1017A0008FB100148FB000100A00193427BD00203B +:1017B000914400D42403FF8000838825A15100D4E4 +:1017C0009784005C3088FFFF51000023938C003C1D +:1017D0008F8500382402EFFF008B782394AE00BC85 +:1017E0000168502B31E900FF01C26824A4AD00BCA0 +:1017F00051400039010058213C1F800037E60100AC +:101800008CD800043C190001031940245500000144 +:1018100034E740008E0A00202403FFFB241100015E +:1018200001432024AE0400201191002D34E78000F4 +:1018300002002021012030210E0018C03165FFFF79 +:101840009787005C8F890060A780005C0127802358 +:10185000AF900060938C003C8F8B00388FBF0018D6 +:101860008FB100148FB0001027BD002003E00008E6 +:10187000A16C00D73C0D800035AA01008D48000402 +:101880003C0900010109282454A0000134E740006C +:101890008E0F00202418FFFB34E7800001F870242D +:1018A00024190001AE0E00201599FF9F34E708802F +:1018B000020020210E00188E3165FFFF020020215A +:1018C000022028218FBF00188FB100148FB00010A4 +:1018D0000A00193427BD00200A0019F7000048212A +:1018E00002002021012030210E00188E3165FFFFFB +:1018F0009787005C8F890060A780005C01278023A8 +:101900000A001A0EAF900060948C0080241F8000A3 +:10191000019F3024A4860080908B0080908F0080EF +:10192000316700FF0007C9C20019C027001871C045 +:1019300031ED007F01AE2825A08500800A0019DF67 +:1019400002002021938500682403000127BDFFE8E1 +:1019500000A330042CA20020AFB00010AFBF0014D1 +:1019600000C01821104000132410FFFE3C0708009F +:101970008CE7319000E610243C088000350501809A +:1019800014400005240600848F890038240A0004CE +:101990002410FFFFA12A00FC0E00190F0000000018 +:1019A000020010218FBF00148FB0001003E0000868 +:1019B00027BD00183C0608008CC631940A001A574F +:1019C00000C310248F87004427BDFFE0AFB200188A +:1019D000AFB10014AFB00010AFBF001C30D000FF9B +:1019E00090E6000D00A088210080902130C5007F86 +:1019F000A0E5000D8F8500388E2300188CA200D042 +:101A00001062002E240A000E0E001A4AA38A0068F3 +:101A10002409FFFF104900222404FFFF5200002088 +:101A2000000020218E2600003C0C001000CC582421 +:101A3000156000393C0E000800CE682455A0003F18 +:101A4000024020213C18000200D880241200001F10 +:101A50003C0A00048F8700448CE200148CE30010E1 +:101A60008CE500140043F82303E5C82B1320000580 +:101A7000024020218E24002C8CF1001010910031A6 +:101A80000240202124020012A38200680E001A4A9C +:101A90002412FFFF105200022404FFFF0000202147 +:101AA0008FBF001C8FB200188FB100148FB00010D0 +:101AB0000080102103E0000827BD002090A800D47A +:101AC000350400200A001A80A0A400D400CA4824CB +:101AD0001520000B8F8B00448F8D00448DAC0010BF +:101AE0001580000B024020218E2E002C51C0FFECEF +:101AF00000002021024020210A001A9B2402001726 +:101B00008D66001050C0FFE6000020210240202119 +:101B10000A001A9B24020011024020212402001511 +:101B20000E001A4AA3820068240FFFFF104FFFDC4B +:101B30002404FFFF0A001A8A8E2600000A001AC138 +:101B4000240200143C08000400C8382450E0FFD4EC +:101B500000002021024020210A001A9B24020013C9 +:101B60008F85003827BDFFD8AFB3001CAFB2001877 +:101B7000AFB10014AFB00010AFBF002090A700D4E9 +:101B80008F90004C2412FFFF34E2004092060000C8 +:101B9000A0A200D48E0300100080982110720006CD +:101BA00030D1003F2408000D0E001A4AA3880068B7 +:101BB000105200252404FFFF8F8A00388E09001878 +:101BC0008D4400D01124000702602021240C000E57 +:101BD0000E001A4AA38C0068240BFFFF104B001A5A +:101BE0002404FFFF24040020122400048F8D0038F9 +:101BF00091AF00D435EE0020A1AE00D48F85005403 +:101C000010A00019000000001224004A8F9800382C +:101C10008F92FCC0971000809651000A5230004805 +:101C20008F9300403C1F08008FFF318C03E5C82BC9 +:101C30001720001E02602021000028210E0019A993 +:101C400024060001000020218FBF00208FB3001C5C +:101C50008FB200188FB100148FB0001000801021D7 +:101C600003E0000827BD00285224002A8E05001436 +:101C70008F840038948A008025490001A48900805F +:101C8000948800803C0208008C42318831077FFF35 +:101C900010E2000E00000000026020210E00193446 +:101CA000240500010A001B0B000020212402002D46 +:101CB0000E001A4AA38200682403FFFF1443FFE1C9 +:101CC0002404FFFF0A001B0C8FBF002094990080A2 +:101CD000241F800024050001033FC024A498008035 +:101CE00090920080908E0080325100FF001181C2DE +:101CF00000107827000F69C031CC007F018D582576 +:101D0000A08B00800E001934026020210A001B0BFA +:101D1000000020212406FFFF54A6FFD68F84003840 +:101D2000026020210E001934240500010A001B0B5B +:101D300000002021026020210A001B252402000A45 +:101D40002404FFFD0A001B0BAF9300608F8800384E +:101D500027BDFFE8AFB00010AFBF0014910A00D458 +:101D60008F87004C00808021354900408CE60010B0 +:101D7000A10900D43C0208008C4231B030C53FFFBD +:101D800000A2182B106000078F850050240DFF80E3 +:101D900090AE000D01AE6024318B00FF156000088D +:101DA0000006C382020020212403000D8FBF00140F +:101DB0008FB0001027BD00180A001A4AA3830068DC +:101DC00033060003240F000254CFFFF70200202146 +:101DD00094A2001C8F85003824190023A4A200E8D7 +:101DE0008CE8000000081E02307F003F13F9003528 +:101DF0003C0A00838CE800188CA600D0110600086D +:101E0000000000002405000E0E001A4AA385006899 +:101E10002407FFFF104700182404FFFF8F850038B8 +:101E200090A900D435240020A0A400D48F8C0044B5 +:101E3000918E000D31CD007FA18D000D8F83005458 +:101E40001060001C020020218F8400508C9800102C +:101E50000303782B11E0000D241900180200202143 +:101E6000A39900680E001A4A2410FFFF10500002C8 +:101E70002404FFFF000020218FBF00148FB000104A +:101E80000080102103E0000827BD00188C86001098 +:101E90008F9F00440200202100C31023AFE20010F6 +:101EA000240500010E0019A9240600010A001B9751 +:101EB000000020210E001934240500010A001B97A0 +:101EC00000002021010A5824156AFFD98F8C004494 +:101ED000A0A600FC0A001B84A386005A30A500FFC0 +:101EE0002406000124A9000100C9102B1040000C99 +:101EF00000004021240A000100A61823308B0001B5 +:101F000024C60001006A3804000420421160000267 +:101F100000C9182B010740251460FFF800A61823FC +:101F200003E000080100102127BDFFD8AFB0001862 +:101F30008F90004CAFB1001CAFBF00202403FFFF07 +:101F40002411002FAFA30010920600002405000802 +:101F500026100001006620260E001BB0308400FF12 +:101F600000021E003C021EDC34466F410A001BD8F2 +:101F70000000102110A00009008018212445000154 +:101F800030A2FFFF2C4500080461FFFA0003204047 +:101F90000086202614A0FFF9008018210E001BB037 +:101FA000240500208FA300102629FFFF313100FFF8 +:101FB00000034202240700FF1627FFE20102182651 +:101FC00000035027AFAA0014AFAA00100000302170 +:101FD00027A8001027A7001400E6782391ED00033E +:101FE00024CE000100C8602131C600FF2CCB0004C4 +:101FF0001560FFF9A18D00008FA200108FBF002097 +:102000008FB1001C8FB0001803E0000827BD002826 +:1020100027BDFFD0AFB3001CAFB00010AFBF00288A +:10202000AFB50024AFB40020AFB20018AFB10014B8 +:102030003C0C80008D880128240FFF803C06800A1C +:1020400025100100250B0080020F68243205007F57 +:10205000016F7024AD8E009000A62821AD8D002464 +:1020600090A600FC3169007F3C0A8004012A1821F7 +:10207000A386005A9067007C00809821AF830030CF +:1020800030E20002AF88006CAF85003800A0182154 +:10209000144000022404003424040030A3840048C7 +:1020A0008C7200DC30D100FF24040004AF92006089 +:1020B00012240004A38000688E7400041680001EA1 +:1020C0003C0880009386005930C7000110E0000FE3 +:1020D0008F9300608CB000848CA800842404FF805F +:1020E000020410240002F940310A007F03EA482567 +:1020F0003C0C2000012C902530CD00FE3C038000DC +:10210000AC720830A38D00598F9300608FBF0028F8 +:102110008FB50024ACB300DC8FB400208FB3001C5B +:102120008FB200188FB100148FB00010240200018C +:1021300003E0000827BD00308E7F000895020120D3 +:102140008E67001003E2C8213326FFFF30D8000F4E +:1021500033150001AF87003416A00058A39800582B +:1021600035090C000309382100D81823AD03008479 +:10217000AF8700648E6A00043148FFFF1100007EC3 +:10218000A78A005C90AC00D42407FF8000EC3024C8 +:1021900030CB00FF1560004B9786005C938E005A91 +:1021A000240D000230D5FFFF11CD02A20000A021B6 +:1021B0008F85006002A5802B160000BC9388004824 +:1021C0003C11800096240120310400FF1485008812 +:1021D0008F8400648F9800343312000356400085CA +:1021E00030A500FF8F900064310C00FF24060034FE +:1021F00011860095AF90004C9204000414800118E1 +:102200008F8E0038A380003C8E0D00048DC800D84E +:102210003C0600FF34CCFFFF01AC30240106182B34 +:1022200014600120AF8600548F8700609798005C8F +:10223000AF8700400307402310C000C7A788005C99 +:102240008F91003030C3000300035823922A007C92 +:102250003171000302261021000A20823092000111 +:102260000012488000492821311FFFFF03E5C82BD9 +:10227000132001208F8800388F8500348F880064F8 +:102280001105025A3C0E3F018E0600003C0C250051 +:1022900000CE682411AC01638F84004C30E500FF50 +:1022A0000E00184A000030218F8800388F870060A8 +:1022B0008F8500340A001DB78F8600540A001C5613 +:1022C000AF87006490A400D400E48024320200FFB1 +:1022D000104000169386005990A6008890AE00D753 +:1022E00024A8008830D4003F2686FFE02CD10020AF +:1022F000A38E003C1220000CAF88004C240B000180 +:1023000000CB20043095001916A0012B3C0680005C +:1023100034CF0002008FC0241700022E3099002015 +:1023200017200234000000009386005930CB0001D2 +:102330001160000F9788005C8CBF00848CA900841A +:10234000240AFF8003EA6024000C19403132007F28 +:10235000007238253C0D200000EDC82530D800FE65 +:102360003C0F8000ADF90830A39800599788005CB5 +:102370001500FF84000000008E630020306200041E +:102380001040FF51938600592404FFFB0064802411 +:102390003C038000AE700020346601808C7301B86D +:1023A0000660FFFE8F98006C347501003C1400013C +:1023B000ACD800008C6B012424076085ACCB0004F2 +:1023C0008EAE000401D488245220000124076083CB +:1023D00024190002A4C700083C0F1000A0D9000B6C +:1023E0003C068000ACCF01B80A001C2B9386005934 +:1023F00030A500FF0E00184A240600018F88006CEB +:102400003C05800034A90900250201889388004812 +:10241000304A0007304B00783C0340802407FF809F +:102420000163C825014980210047F824310C00FFD1 +:1024300024060034ACBF0800AF90004CACB90810C3 +:102440005586FF6E920400048F8400388E11003090 +:10245000908E00D431CD001015A000108F83006045 +:102460002C6F000515E000E400000000909800D4F7 +:102470002465FFFC331200101640000830A400FF52 +:102480008F9F00648F99003413F90004388700018E +:1024900030E20001144001C8000000000E001BC320 +:1024A000000000000A001DF8000000008F84006496 +:1024B00030C500FF0E00184A24060001939800481A +:1024C000240B0034130B00A08F8500388F8600602A +:1024D0009783005C306EFFFF00CE8823AF910060D1 +:1024E000A780005C1280FF90028018212414FFFD59 +:1024F0005474FFA28E6300208E6A00042403FFBF81 +:102500002408FFEF0155F823AE7F000490AC00D4FF +:102510003189007FA0A900D48E7200208F8F0038EF +:10252000A780005C364D0002AE6D0020A5E000BC27 +:1025300091E500D400A3C824A1F900D48F950038F8 +:10254000AEA000EC92B800D403085824A2AB00D48B +:102550000A001CD78F8500388F910034AF8000604F +:1025600002275821AF8B0034000020212403FFFFF5 +:10257000108301B48F8500388E0C00103C0D0800CC +:102580008DAD31B09208000031843FFF008D802B6B +:1025900012000023310D003F3C1908008F3931A88B +:1025A0008F9F006C000479802408FF80033F202166 +:1025B000008FC821938500590328F8243C06008029 +:1025C0003C0F800034D80001001F91403331007F60 +:1025D0008F8600380251502535EE0940332B0078A4 +:1025E000333000073C0310003C02800C017890253A +:1025F000020E48210143C0250222382134AE0001D9 +:10260000ADFF0804AF890050ADF20814AF87004455 +:10261000ADFF0028ACD90084ADF80830A38E005976 +:102620009383005A24070003106700272407000142 +:102630001467FFAC8F8500382411002311B1008589 +:1026400000000000240E000B026020210E001A4A38 +:10265000A38E00680040A0210A001D328F8500383B +:1026600002602021240B000C0E001A4AA38B006884 +:10267000240AFFFF104AFFBD2404FFFF8F8E00389D +:10268000A380003C8E0D00048DC800D83C0600FFDE +:1026900034CCFFFF01AC30240106182B1060FEE2A1 +:1026A000AF86005402602021241200190E001A4A3D +:1026B000A3920068240FFFFF104FFFAC2404FFFF1C +:1026C0000A001C838F86005425A3FFE02C74002091 +:1026D0001280FFDD240E000B000328803C1108014E +:1026E000263194B400B148218D2D000001A00008CE +:1026F000000000008F85003400A710219385003C66 +:10270000AF82003402251821A383003C951F00BC32 +:102710000226282137F91000A51900BC5240FF926B +:10272000AF850060246A0004A38A003C950900BCC0 +:1027300024A40004AF84006035322000A51200BC40 +:102740000A001D54000020218F8600602CC800055F +:102750001500FF609783005C3065FFFF00C5C8234C +:102760002F2F000511E00003306400FF24CDFFFC93 +:1027700031A400FF8F8900648F920034113200046D +:10278000389F000133EC0001158001380000000083 +:102790008F840038908700D434E60010A08600D4DF +:1027A0008F8500388F8600609783005CACA000ECBA +:1027B0000A001D2F306EFFFF8CB500848CB400849E +:1027C0003C04100002A7302400068940328E007FAE +:1027D000022E8025020410253C08800024050001FB +:1027E00002602021240600010E0019A9AD02083064 +:1027F0000A001CC38F8500388C8200EC1222FE7EFA +:102800000260202124090005A38900680E001A4AED +:102810002411FFFF1451FE782404FFFF0A001D5508 +:102820002403FFFF8F8F004C8F8800388DF8000045 +:10283000AD1800888DE70010AD0700988F87006005 +:102840000A001DB78F8600542406FFFF118600057D +:10285000000000000E001B4C026020210A001D8FAA +:102860000040A0210E001AD1026020210A001D8F15 +:102870000040A0218F90004C3C0208008C4231B0F7 +:102880008E110010322C3FFF0182282B10A0000C6B +:10289000240BFF808F85005090A3000D01637024EE +:1028A00031CA00FF1140000702602021001143825D +:1028B000310600032418000110D8010600000000B2 +:1028C000026020212403000D0E001A4AA383006831 +:1028D000004020218F8500380A001D320080A02191 +:1028E0008F90004C3C0A08008D4A31B08F85005013 +:1028F0008E0400100000A0218CB1001430823FFF34 +:10290000004A602B8CB200205180FFEE0260202133 +:1029100090B8000D240BFF800178702431C300FFB4 +:102920005060FFE80260202100044382310600036A +:1029300014C0FFE40260202194BF001C8F9900386E +:102940008E060028A73F00E88CAF0010022F20233E +:1029500014C4013A026020218F83005400C368210F +:10296000022D382B14E00136240200188F8A00440F +:102970008F820030024390218D4B00100163702341 +:10298000AD4E0010AD5200208C4C00740192282BEB +:1029900014A0015F026020218F8400508E08002463 +:1029A0008C86002411060007026020212419001CD7 +:1029B0000E001A4AA3990068240FFFFF104FFFC5AD +:1029C0002404FFFF8F8400448C87002424FF00012F +:1029D000AC9F00241251012F8F8D00308DB10074F7 +:1029E0001232012C3C0B00808E0E000001CB5024D3 +:1029F00015400075000000008E0300142411FFFF35 +:102A0000107100073C0808003C0608008CC6319095 +:102A100000C8C0241300015202602021A380006876 +:102A20008E0300003C19000100792024108000135F +:102A30003C1F0080007FA02416800009020028218E +:102A4000026020212411001A0E001A4AA391006886 +:102A50002407FFFF1047FF9F2404FFFF02002821E7 +:102A6000026020210E001A6A240600012410FFFFD4 +:102A70001050FF982404FFFF241400018F8D0044A0 +:102A8000026020210280302195A900342405000134 +:102A9000253200010E0019A9A5B200340000202142 +:102AA0008F8500380A001D320080A0218F90004CD5 +:102AB0003C1408008E9431B08E07001030E53FFFC3 +:102AC00000B4C82B132000618F8600502412FF80B1 +:102AD00090C9000D0249682431A400FF5080005CB9 +:102AE000026020218F8C00541180000700078B8228 +:102AF0008F8500388F82FCC094BF0080944A000A02 +:102B0000515F00F78F8600403227000314E0006415 +:102B100000000000920E000211C000D8000000006A +:102B20008E0B0024156000D902602021920400035E +:102B300024190002308500FF14B90005308900FF18 +:102B40008F940054128000EA240D002C308900FF7D +:102B5000392C00102D8400012D3200010244302553 +:102B6000020028210E001A6A026020212410FFFFB3 +:102B7000105000BF8F8500388F830054106000D341 +:102B8000240500013C0A08008D4A318C0143F82BD2 +:102B900017E000B22402002D02602021000028214D +:102BA0000E0019A9240600018F85003800001821A5 +:102BB0000A001D320060A0210E0018750000000000 +:102BC0000A001DF800000000AC8000200A001E78FA +:102BD0008E03001400002821026020210E0019A994 +:102BE000240600010A001CC38F8500380A001DB7A7 +:102BF0008F8800388CAA00848CAC00843C031000C1 +:102C00000147F824001F91403189007F024968255F +:102C100001A32825ACC50830910700012405000157 +:102C2000026020210E0019A930E600010A001CC331 +:102C30008F850038938F00482403FFFD0A001D3460 +:102C4000AF8F00600A001D342403FFFF02602021C3 +:102C50002410000D0E001A4AA390006800401821AD +:102C60008F8500380A001D320060A0210E00187503 +:102C7000000000009783005C8F86006000402021E8 +:102C80003070FFFF00D010232C4A00051140FE11C8 +:102C90008F850038ACA400EC0A001D2F306EFFFFBA +:102CA00090CF000D31E300085460FFA192040003AF +:102CB00002602021240200100E001A4AA38200683C +:102CC0002403FFFF5443FF9A920400030A001F12DB +:102CD0008F85003890A4000D308F000811E000951A +:102CE0008F990054572000A6026020218E1F000CEF +:102CF0008CB4002057F40005026020218E0D0008DE +:102D00008CA7002411A7003A026020212402002091 +:102D1000A38200680E001A4A2412FFFF1052FEED33 +:102D20002404FFFF8F9F00442402FFF73C14800E11 +:102D300093EA000D2419FF803C03800001423824EF +:102D4000A3E7000D8F9F00303C0908008D2931ACAE +:102D50008F8C006C97F200788F870044012C302113 +:102D6000324D7FFF000D204000C4782131E5007F07 +:102D700000B4C02101F94024AC68002CA711000068 +:102D80008CEB0028256E0001ACEE00288CEA002CAC +:102D90008E02002C01426021ACEC002C8E09002C2C +:102DA000ACE900308E120014ACF2003494ED003A1D +:102DB00025A40001A4E4003A97E600783C1108003D +:102DC0008E3131B024C3000130707FFF1211005CDE +:102DD000006030218F8F0030026020212405000127 +:102DE0000E001934A5E600780A001EA1000020217B +:102DF0008E0900142412FFFF1132006B8F8A0038F5 +:102E00008E0200188D4C00D0144C00650260202109 +:102E10008E0B00248CAE0028116E005B2402002172 +:102E20000E001A4AA38200681452FFBE2404FFFF5A +:102E30008F8500380A001D320080A0212402001F67 +:102E40000E001A4AA38200682409FFFF1049FEA160 +:102E50002404FFFF0A001E548F83005402602021C7 +:102E60000E001A4AA38200681450FF508F85003864 +:102E70002403FFFF0A001D320060A0218CD800242B +:102E80008E0800241118FF29026020210A001F2744 +:102E90002402000F8E0900003C05008001259024CB +:102EA0001640FF492402001A026020210E001A4A2F +:102EB000A3820068240CFFFF144CFECF2404FFFF04 +:102EC0008F8500380A001D320080A0210E001934C1 +:102ED000026020218F8500380A001EE500001821BD +:102EE0002403FFFD0060A0210A001D32AF860060B0 +:102EF000026020210E001A4AA38D00682403FFFF00 +:102F00001043FF588F8500380A001ECC920400033E +:102F10002418001D0E001A4AA39800682403FFFF1E +:102F20001443FE9D2404FFFF8F8500380A001D32E4 +:102F30000080A021026020210A001F3D24020024FD +:102F4000240880000068C024330BFFFF000B73C20D +:102F500031D000FF001088270A001F6E001133C017 +:102F6000240F001B0E001A4AA38F00681451FEACF8 +:102F70002404FFFF8F8500380A001D320080A02145 +:102F80000A001F3D240200278E0600288CA3002C77 +:102F900010C30008026020210A001F812402001FC4 +:102FA0000A001F812402000E026020210A001F81F6 +:102FB000240200258E04002C1080000D8F8F00301D +:102FC0008DE800740104C02B5700000C0260202122 +:102FD0008CB900140086A0210334282B10A0FF52C6 +:102FE0008F9F0044026020210A001F8124020022DA +:102FF000026020210A001F81240200230A001F8191 +:103000002402002627BDFFD8AFB3001CAFB10014C7 +:10301000AFBF0020AFB20018AFB000103C0280007C +:103020008C5201408C4B01483C048000000B8C0208 +:10303000322300FF317300FF8C8501B804A0FFFE2E +:1030400034900180AE1200008C8701442464FFF0AC +:10305000240600022C830013AE070004A61100080A +:10306000A206000BAE1300241060004F8FBF00209B +:10307000000448803C0A0801254A9534012A402171 +:103080008D04000000800008000000003C030800E0 +:103090008C6331A831693FFF00099980007280215B +:1030A000021370212405FF80264D0100264C00806C +:1030B0003C02800031B1007F3198007F31CA007F2F +:1030C0003C1F800A3C1980043C0F800C01C5202461 +:1030D00001A5302401853824014F1821AC46002475 +:1030E000023F402103194821AC470090AC4400281E +:1030F000AF830044AF880038AF8900300E0019005C +:10310000016080213C0380008C6B01B80560FFFEEC +:103110008F8700448F8600383465018090E8000D69 +:10312000ACB20000A4B0000600082600000416039C +:1031300000029027001227C21080008124C200885C +:10314000241F6082A4BF0008A0A000052402000282 +:10315000A0A2000B8F8B0030000424003C08270045 +:1031600000889025ACB20010ACA00014ACA00024E4 +:10317000ACA00028ACA0002C8D6900382413FF807F +:10318000ACA9001890E3000D02638024320500FF13 +:1031900010A000058FBF002090ED000D31AC007F26 +:1031A000A0EC000D8FBF00208FB3001C8FB2001861 +:1031B0008FB100148FB000103C0A10003C0E80004C +:1031C00027BD002803E00008ADCA01B8265F010052 +:1031D0002405FF8033F8007F3C06800003E5782457 +:1031E0003C19800A03192021ACCF0024908E00D412 +:1031F00000AE682431AC00FF11800024AF84003899 +:10320000248E008895CD00123C0C08008D8C31A8CE +:1032100031AB3FFF01924821000B5180012A402130 +:1032200001052024ACC400283107007F3C06800C37 +:1032300000E620219083000D00A31024304500FFFC +:1032400010A0FFD8AF8400449098000D330F0010F9 +:1032500015E0FFD58FBF00200E0019000000000010 +:103260003C0380008C7901B80720FFFE00000000BD +:10327000AE1200008C7F0144AE1F0004A6110008AE +:1032800024110002A211000BAE1300243C1308010C +:10329000927396F0327000015200FFC38FBF00207E +:1032A0000E002146024020210A0020638FBF00202B +:1032B0003C1260008E452C083C03F0033462FFFF93 +:1032C00000A2F824AE5F2C088E582C083C1901C0CF +:1032D00003199825AE532C080A0020638FBF0020E5 +:1032E000264D010031AF007F3C10800A240EFF8084 +:1032F00001F0282101AE60243C0B8000AD6C00245D +:103300001660FFA8AF85003824110003A0B100FCAF +:103310000A0020638FBF002026480100310A007F89 +:103320003C0B800A2409FF80014B30210109202435 +:103330003C078000ACE400240A002062AF8600381D +:10334000944E0012320C3FFF31CD3FFF15ACFF7D94 +:10335000241F608290D900D42418FF800319782498 +:1033600031EA00FF1140FF7700000000240700044D +:10337000A0C700FC8F870044241160842406000D40 +:10338000A4B10008A0A600050A00204D24020002F6 +:103390003C040001248496DC24030014240200FE73 +:1033A0003C010800AC2431EC3C010800AC2331E8BE +:1033B0003C010801A42296F83C040801248496F8F4 +:1033C0000000182100643021A0C300042463000120 +:1033D0002C6500FF54A0FFFC006430213C0708006E +:1033E00024E7010003E00008AF87007800A058211F +:1033F000008048210000102114A00012000050217C +:103400000A002142000000003C010801A42096F8B7 +:103410003C05080194A596F88F8200783C0C0801C1 +:10342000258C96F800E2182100AC2021014B302BAE +:10343000A089000400001021A460000810C0003919 +:10344000010048218F8600780009384000E94021BA +:103450000008388000E6282190A8000B90B9000AE7 +:103460000008204000881021000218800066C0215A +:10347000A319000A8F85007800E5782191EE000AF3 +:1034800091E6000B000E684001AE6021000C208028 +:1034900000851021A046000B3C030801906396F2C2 +:1034A000106000222462FFFF8F8300383C01080176 +:1034B000A02296F2906C00FF118000040000000032 +:1034C000906E00FF25CDFFFFA06D00FF3C190801A5 +:1034D000973996F8272300013078FFFF2F0F00FF60 +:1034E00011E0FFC9254A00013C010801A42396F818 +:1034F0003C05080194A596F88F8200783C0C0801E1 +:10350000258C96F800E2182100AC2021014B302BCD +:10351000A089000400001021A460000814C0FFC9A5 +:103520000100482103E000080000000003E000085B +:103530002402000227BDFFE0248501002407FF804C +:10354000AFB00010AFBF0018AFB1001400A718242F +:103550003C10800030A4007F3C06800A00862821B1 +:103560008E110024AE03002490A200FF1440000836 +:10357000AF850038A0A000098FBF0018AE1100244D +:103580008FB100148FB0001003E0000827BD0020A9 +:1035900090A900FD90A800FF312400FF0E0020F448 +:1035A000310500FF8F8500388FBF0018A0A00009EB +:1035B000AE1100248FB100148FB0001003E000089A +:1035C00027BD002027BDFFD0AFB20020AFB1001C47 +:1035D000AFB00018AFBF002CAFB40028AFB30024C9 +:1035E0003C0980009533011635320C00952F011AE5 +:1035F0003271FFFF023280218E08000431EEFFFF9E +:10360000248B0100010E6821240CFF8025A5FFFFFB +:10361000016C50243166007F3C07800AAD2A0024EB +:1036200000C73021AF850074AF8800703C010801ED +:10363000A02096F190C300090200D02100809821BB +:10364000306300FF2862000510400048AF86003854 +:10365000286400021480008E24140001240D00054B +:103660003C010801A02D96D590CC00FD3C0108013D +:10367000A02096D63C010801A02096D790CB000A46 +:10368000240AFF80318500FF014B4824312700FFC9 +:1036900010E0000C000058213C12800836510080D8 +:1036A0008E2F00308CD0005C01F0702305C0018E9D +:1036B0008F87007090D4000A3284007FA0C4000A73 +:1036C0008F8600383C118008363000808E0F003025 +:1036D0008F87007000EF702319C000EE000000001B +:1036E00090D4000924120002328400FF1092024795 +:1036F000000000008CC2005800E2F82327F9FFFF09 +:103700001B2001300000000090C5000924080004BF +:1037100030A300FF10680057240A00013C01080193 +:10372000A02A96D590C900FF252700013C01080179 +:10373000A02796D43C030801906396D52406000583 +:103740001066006A2C780005130000C40000902168 +:103750000003F8803C0408012484958003E4C82118 +:103760008F25000000A0000800000000241800FFC2 +:103770001078005C0000000090CC000A90CA00099C +:103780003C080801910896F13187008000EA48253D +:103790003C010801A02996DC90C500FD3C140801FD +:1037A000929496F2311100013C010801A02596DDAA +:1037B00090DF00FE3C010801A03F96DE90D200FFA2 +:1037C0003C010801A03296DF8CD900543C0108016D +:1037D000AC3996E08CD000583C010801AC3096E43E +:1037E0008CC3005C3C010801AC3496EC3C01080140 +:1037F000AC2396E8162000088FBF002C8FB4002859 +:103800008FB300248FB200208FB1001C8FB000183E +:1038100003E0000827BD00303C1180009624010E13 +:103820000E000FD43094FFFF3C0B08018D6B96F413 +:103830000260382102802821AE2B01803C13080150 +:103840008E7396D401602021240600830E00102F71 +:10385000AFB300108FBF002C8FB400288FB30024AB +:103860008FB200208FB1001C8FB0001803E0000859 +:1038700027BD00303C1808008F1831FC270F0001CD +:103880003C010800AC2F31FC0A0021D700000000E9 +:103890001474FFB900000000A0C000FF3C05080040 +:1038A0008CA531E43C0308008C6331E03C02080045 +:1038B0008C4232048F99003834A80001241F000282 +:1038C0003C010801AC2396F43C010801A02896F0C5 +:1038D0003C010801A02296F3A33F00090A002190B1 +:1038E0008F8600380E002146000000000A0021D714 +:1038F0008F8600383C1F080193FF96D424190001DD +:1039000013F902298F8700703C100801921096D895 +:103910003C06080190C696D610C000050200A02102 +:103920003C040801908496D9109001E48F870078B8 +:10393000001088408F9F0078023048210009C8801D +:10394000033F702195D80008270F0001A5CF00087C +:103950003C040801908496D93C05080190A596D6B0 +:103960000E0020F4000000008F8700780230202134 +:103970000004308000C720218C8500048F820074F1 +:1039800000A2402305020006AC8200048C8A0000DD +:103990008F830070014310235C400001AC83000062 +:1039A0008F86003890CB00FF2D6C00025580002DD3 +:1039B000241400010230F821001F40800107282153 +:1039C00090B9000B8CAE00040019C0400319782197 +:1039D000000F1880006710218C4D000001AE882375 +:1039E0002630FFFF5E00001F241400018C440004F9 +:1039F0008CAA0000008A482319200019240E000414 +:103A00003C010801A02E96D590AD000B8CAB0004B4 +:103A1000000D8840022D80210010108000471021E9 +:103A20008C44000401646023058202009443000872 +:103A300090DF00FE90B9000B33E500FF54B900049D +:103A40000107A021A0D400FE8F8700780107A021E4 +:103A50009284000B0E0020F4240500018F860038AC +:103A600024140001125400962E500001160000424A +:103A70003C08FFFF241900021659FF3F0000000018 +:103A8000A0C000FF8F860038A0D200090A0021D70D +:103A90008F86003890C700092404000230E300FF3D +:103AA0001064016F24090004106901528F880074AA +:103AB0008CCE0054010E682325B10001062001754B +:103AC000241800043C010801A03896D53C010801E7 +:103AD000A02096D490D400FD90D200FF2E4F00027B +:103AE00015E0FF14328400FF000438408F8900780D +:103AF00090DF00FF00E41021000220800089C8212F +:103B00002FE500029324000B14A0FF0A24070002F3 +:103B100000041840006480210010588001692821A9 +:103B20008CAC0004010C50230540FF020000000093 +:103B30003C030801906396D614600005246F0001D1 +:103B40003C010801A02496D93C010801A02796D782 +:103B50003C010801A02F96D690CE00FF24E700017B +:103B600031CD00FF01A7882B1220FFE990A4000BA4 +:103B70000A0021C6000000003C0508018CA596D46F +:103B80003C12000400A8F82413F2000624020005E9 +:103B90003C090801912996D5152000022402000352 +:103BA000240200053C010801A02296F190C700FF05 +:103BB00014E0012024020002A0C200090A0021D75B +:103BC0008F86003890CC00FF1180FEDA240A0001B5 +:103BD0008F8C00748F890078240F00030180682186 +:103BE0001160001E240E0002000540400105A021C6 +:103BF00000142080008990218E51000401918023BF +:103C00000600FECC000000003C020801904296D65F +:103C100014400005245800013C010801A02A96D751 +:103C20003C010801A02596D93C010801A03896D690 +:103C300090DF00FF010510210002C88033E500FF7E +:103C4000254A00010329202100AA402B1500FEB9B6 +:103C50009085000B1560FFE50005404000054040E1 +:103C600001051821000310803C010801A02A96D408 +:103C70003C010801A02596D8004918218C64000455 +:103C800000E4F82327F9FFFF1F20FFE900000000F0 +:103C90008C63000000E358230560013A01A38823E8 +:103CA00010E301170184C0231B00FEA200000000E6 +:103CB0003C010801A02E96D50A002305240B000123 +:103CC000240E0004A0CE00093C0D08008DAD31F893 +:103CD0008F86003825A200013C010800AC2231F893 +:103CE0000A0021D7000000008CD9005C00F9C02335 +:103CF0001F00FE7B000000008CDF005C10FFFF65F2 +:103D00008F8400748CC3005C008340232502000173 +:103D10001C40FF60000000008CC9005C248700018B +:103D200000E9282B10A0FE943C0D80008DAB01040F +:103D30003C0C0001016C50241140FE8F2402001045 +:103D40003C010801A02296F10A0021D700000000E2 +:103D50008F9100748F86003826220001ACC2005C6F +:103D60000A002292241400018F8700382404FF8067 +:103D70000000882190E9000A241400010124302564 +:103D8000A0E6000A3C05080190A596D63C0408016F +:103D9000908496D90E0020F4000000008F86003831 +:103DA0008F85007890C800FD310700FF0007404074 +:103DB0000107F821001FC0800305C8219323000BD1 +:103DC000A0C300FD8F8500788F8600380305602131 +:103DD000918F000B000F704001CF6821000D808093 +:103DE000020510218C4B0000ACCB00548D840004E4 +:103DF0008F83007400645023194000022482000164 +:103E00002462000101074821ACC2005C0009308037 +:103E100000C5402100E02021240500010E0020F40F +:103E20009110000B8F86003890C500FF10A0FF0C8A +:103E3000001070408F85007801D06821000D10803F +:103E4000004558218D6400008F8C0074018450233C +:103E50002547000104E0FF02263100013C03080170 +:103E6000906396D62E2F0002247800013C010801B1 +:103E7000A03896D63C010801A03496D711E0FEF890 +:103E8000020038210A002365000740408F84003873 +:103E90008F8300748C85005800A340230502FE9A8E +:103EA000AC8300580A00223B000000003C070801D8 +:103EB00090E796F2240200FF10E200BE8F860038E1 +:103EC0003C110801963196FA3C030801246396F8E8 +:103ED000262500013230FFFF30ABFFFF02036021D7 +:103EE0002D6A00FF1540008D918700043C010801F8 +:103EF000A42096FA8F88003800074840012728211F +:103F0000911800FF000530802405000127140001EE +:103F1000A11400FF3C120801925296F28F8800789B +:103F20008F8E0070264F000100C820213C0108013F +:103F3000A02F96F2AC8E00008F8D0074A48500082F +:103F4000AC8D00043C030801906396D414600077A4 +:103F5000000090213C010801A02596D4A087000B09 +:103F60008F8C007800CC5021A147000A8F82003846 +:103F7000A04700FD8F840038A08700FE8F860038A0 +:103F80008F9F0070ACDF00548F990074ACD900583B +:103F90008F8D00780127C02100185880016DA02165 +:103FA000928F000A000F704001CF18210003888013 +:103FB000022D8021A207000B8F8600780166602108 +:103FC000918A000B000A1040004A2021000428803A +:103FD00000A64021A107000A3C07800834E90080C0 +:103FE0008D2200308F860038ACC2005C0A0022921D +:103FF0002414000190CA00FF1540FEAD8F880074A4 +:10400000A0C400090A0021D78F860038A0C000FD97 +:104010008F98003824060001A30000FE3C0108012F +:10402000A02696D53C010801A02096D40A0021C6FE +:104030000000000090CB00FF3C040801908496F340 +:10404000316C00FF0184502B1540000F2402000347 +:1040500024020004A0C200090A0021D78F8600387C +:1040600090C3000A2410FF8002035824316C00FF23 +:104070001180FDC1000000003C010801A02096D580 +:104080000A0021C600000000A0C200090A0021D7D2 +:104090008F86003890D4000A2412FF8002544824EE +:1040A000312800FF1500FFF4240200083C0108013C +:1040B000A02296F10A0021D70000000000108840DD +:1040C0008F8B0070023018210003688001A7202127 +:1040D000AC8B00008F8A0074240C0001A48C0008B3 +:1040E000AC8A00043C05080190A596D62402000184 +:1040F00010A2FE1E24A5FFFF0A0022519084000B8F +:104100000184A0231A80FD8B000000003C010801FF +:10411000A02E96D50A002305240B00013C010801BE +:10412000A42596FA0A0023B78F880038240B0001D3 +:10413000106B00228F9800388F85003890BF00FFE9 +:1041400033F900FF1079002B000000003C1F08012C +:1041500093FF96D8001FC840033FC0210018A080DD +:104160000288782191EE000AA08E000A8F8D0078D7 +:104170003C030801906396D800CD88210A0023DD16 +:10418000A223000B263000010600003101A4902379 +:104190000640002B240200033C010801A02F96D505 +:1041A0000A002305240B00018F8900380A00223BF6 +:1041B000AD2700540A00229124120001931400FD3F +:1041C000A094000B8F8800388F8F0078910E00FE2E +:1041D00000CF6821A1AE000A8F910038A22700FD10 +:1041E0008F8300708F900038AE0300540A0023DEE6 +:1041F0008F8D007890B000FEA090000A8F8B003861 +:104200008F8C0078916A00FD00CC1021A04A000B31 +:104210008F840038A08700FE8F8600748F85003859 +:10422000ACA600580A0023DE8F8D007894B80008F1 +:10423000ACA40004030378210A002285A4AF00087F +:104240003C010801A02296D50A0021C6000000000A +:1042500090CF0009240D000431EE00FF11CDFD8543 +:10426000240200013C010801A02296D50A0021C6C3 +:1042700000000000080033440800334408003420E4 +:10428000080033F4080033D8080033280800332826 +:10429000080033280800334C8008010080080080A3 +:1042A000800800005F865437E4AC62CC50103A4579 +:1042B00036621985BF14C0E81BC27A1E84F4B55655 +:1042C000094EA6FE7DDA01E7C04D748108005A74DC +:1042D00008005AB808005A5C08005A5C08005A5C8A +:1042E00008005A5C08005A7408005A5C08005A5CBE +:1042F00008005AC008005A5C080059D408005A5CEB +:1043000008005A5C08005AC008005A5C08005A5C51 +:1043100008005A5C08005A5C08005A5C08005A5CA5 +:1043200008005A5C08005A5C08005A5C08005A5C95 +:1043300008005A9408005A5C08005A9408005A5C15 +:1043400008005A5C08005A5C08005A9808005A9401 +:1043500008005A5C08005A5C08005A5C08005A5C65 +:1043600008005A5C08005A5C08005A5C08005A5C55 +:1043700008005A5C08005A5C08005A5C08005A5C45 +:1043800008005A5C08005A5C08005A5C08005A5C35 +:1043900008005A5C08005A5C08005A5C08005A5C25 +:1043A00008005A9808005A9808005A5C08005A9861 +:1043B00008005A5C08005A5C08005A5C08005A5C05 +:1043C00008005A5C08005A5C08005A5C08005A5CF5 +:1043D00008005A5C08005A5C08005A5C08005A5CE5 +:1043E00008005A5C08005A5C08005A5C08005A5CD5 +:1043F00008005A5C08005A5C08005A5C08005A5CC5 +:1044000008005A5C08005A5C08005A5C08005A5CB4 +:1044100008005A5C08005A5C08005A5C08005A5CA4 +:1044200008005A5C08005A5C08005A5C08005A5C94 +:1044300008005A5C08005A5C08005A5C08005A5C84 +:1044400008005A5C08005A5C08005A5C08005A5C74 +:1044500008005A5C08005A5C08005A5C08005A5C64 +:1044600008005A5C08005A5C08005A5C08005A5C54 +:1044700008005A5C08005A5C08005A5C08005A5C44 +:1044800008005A5C08005A5C08005A5C08005A5C34 +:1044900008005A5C08005A5C08005A5C08005A5C24 +:1044A00008005A5C08005A5C08005A5C08005A5C14 +:1044B00008005A5C08005A5C08005A5C08005A5C04 +:1044C00008005A5C08005A5C08005A5C08005ADC74 +:1044D0000800782C08007A900800783808007628C0 +:1044E00008007838080078C4080078380800762872 +:1044F0000800762808007628080076280800762824 +:104500000800762808007628080076280800762813 +:1045100008007628080078580800784808007628AF +:1045200008007628080076280800762808007628F3 +:1045300008007628080076280800762808007628E3 +:1045400008007628080076280800762808007848B1 +:10455000080082FC08008188080082C40800818865 +:104560000800829408008070080081880800818813 +:1045700008008188080081880800818808008188F7 +:1045800008008188080081880800818808008188E7 +:104590000800818808008188080081B008008D34F7 +:1045A00008008E9008008E70080088D808008D4C96 +:1045B0000A00012400000000000000000000000DBF +:1045C000747061362E322E31620000000602010145 +:1045D00000000000000000000000000000000000DB +:1045E00000000000000000000000000000000000CB +:1045F00000000000000000000000000000000000BB +:1046000000000000000000000000000000000000AA +:10461000000000000000000000000000000000009A +:10462000000000000000000000000000000000008A +:10463000000000000000000000000000000000007A +:104640000000000010000003000000000000000D4A +:104650000000000D3C020800244217203C03080023 +:1046600024632A10AC4000000043202B1480FFFD7F +:10467000244200043C1D080037BD2FFC03A0F0219C +:104680003C100800261004903C1C0800279C1720B2 +:104690000E000262000000000000000D2402FF80F6 +:1046A00027BDFFE000821024AFB00010AF42002011 +:1046B000AFBF0018AFB10014936500043084007FD1 +:1046C000034418213C0200080062182130A5002094 +:1046D000036080213C080111277B000814A0000220 +:1046E0002466005C2466005892020004974301048B +:1046F000920400043047000F3063FFFF3084004015 +:10470000006728231080000900004821920200055C +:1047100030420004104000050000000010A000031B +:104720000000000024A5FFFC2409000492020005FB +:1047300030420004104000120000000010A00010E1 +:10474000000000009602000200A72021010440257D +:104750002442FFFEA7421016920300042402FF80A9 +:1047600000431024304200FF104000033C020400CC +:104770000A000174010240258CC20000AF421018EB +:104780008F4201780440FFFE2402000AA742014044 +:1047900096020002240400093042000700021023A0 +:1047A00030420007A7420142960200022442FFFE67 +:1047B000A7420144A740014697420104A74201488D +:1047C0008F420108304200205040000124040001C3 +:1047D00092020004304200101440000234830010A2 +:1047E00000801821A743014A0000000000000000DB +:1047F0000000000000000000AF48100000000000B2 +:104800000000000000000000000000008F421000C7 +:104810000441FFFE3102FFFF1040000700000000CE +:1048200092020004304200401440000300000000E7 +:104830008F421018ACC20000960200063042FFFF03 +:10484000244200020002104300021040036288214B +:10485000962200001120000D3044FFFF00A7102118 +:104860008F8300388F45101C0002108200021080D8 +:1048700000431021AC45000030A6FFFF0E00058D5F +:1048800000052C0200402021A62200009203000413 +:104890002402FF8000431024304200FF1040001F1C +:1048A0000000000092020005304200021040001B90 +:1048B000000000009742100C2442FFFEA742101691 +:1048C000000000003C02040034420030AF421000FF +:1048D00000000000000000000000000000000000D8 +:1048E0008F4210000441FFFE000000009742100CB0 +:1048F0008F45101C3042FFFF24420030000210821E +:1049000000021080005B1021AC45000030A6FFFFC4 +:104910000E00058D00052C02A62200009604000260 +:10492000248400080E0001E93084FFFF974401044D +:104930000E0001F73084FFFF8FBF00188FB1001405 +:104940008FB000103C02100027BD002003E00008DB +:10495000AF4201783084FFFF308200078F8500244A +:1049600010400002248300073064FFF800A41021E7 +:1049700030421FFF03421821247B4000AF850028EE +:10498000AF82002403E00008AF4200843084FFFFC0 +:104990003082000F8F85002C8F860034104000027B +:1049A0002483000F3064FFF000A410210046182B70 +:1049B000AF8500300046202314600002AF82002C37 +:1049C000AF84002C8F82002C340480000342182115 +:1049D00000641821AF83003803E00008AF42008074 +:1049E0008F820014104000088F8200048F82FFDC49 +:1049F000144000058F8200043C02FFBF3442FFFFD9 +:104A0000008220248F82000430430006240200022A +:104A10001062000F3C0201012C62000350400005AF +:104A2000240200041060000F3C0200010A00023062 +:104A30000000000010620005240200061462000C51 +:104A40003C0201110A000229008210253C020011DB +:104A500000821025AF421000240200010A0002303B +:104A6000AF82000C00821025AF421000AF80000C16 +:104A700000000000000000000000000003E000084B +:104A8000000000008F82000C1040000400000000B5 +:104A90008F4210000441FFFE0000000003E0000808 +:104AA000000000008F8200102443F800000231C291 +:104AB00024C2FFF02C6303011060000300021042C7 +:104AC0000A000257AC8200008F85001800C5102B29 +:104AD0001440000B0000182100C5102324470001DA +:104AE0008F82001C00A210212442FFFF0046102BE1 +:104AF000544000042402FFFF0A000257AC87000064 +:104B00002402FFFF0A000260AC8200008C820000D9 +:104B10000002194000621821000318800062182169 +:104B2000000318803C0208002442175C0062182130 +:104B300003E000080060102127BDFFD8AFBF0020B0 +:104B4000AFB1001CAFB000183C0460088C8250006C +:104B50002403FF7F3C066000004310243442380CDD +:104B6000AC8250008CC24C1C3C1A80000002160221 +:104B70003042000F10400007AF82001C8CC34C1C59 +:104B80003C02001F3442FC0000621824000319C2DA +:104B9000AF8300188F420008275B400034420001B9 +:104BA000AF420008AF8000243C02601CAF40008090 +:104BB000AF4000848C4500088CC308083402800094 +:104BC000034220212402FFF0006218243C020080EE +:104BD0003C010800AC2204203C025709AF84003895 +:104BE00014620004AF850034240200010A0002921E +:104BF000AF820014AF8000148F42000038420001E1 +:104C0000304200011440FFFC8F8200141040001657 +:104C10000000000097420104104000058F8300004F +:104C2000146000072462FFFF0A0002A72C62000A3A +:104C30002C620010504000048F83000024620001A9 +:104C4000AF8200008F8300002C62000A1440000332 +:104C50002C6200070A0002AEAF80FFDC10400002A9 +:104C600024020001AF82FFDC8F4301088F44010062 +:104C700030622000AF83000410400008AF840010B1 +:104C80003C0208008C42042C244200013C01080034 +:104C9000AC22042C0A00058A3C0240003065020068 +:104CA00014A0000324020F001482026024020D00ED +:104CB00097420104104002C83C02400030624000AC +:104CC000144000AD8F8200388C4400088F42017878 +:104CD0000440FFFE24020800AF42017824020008CD +:104CE000A7420140A7400142974201048F8400047B +:104CF0003051FFFF30820001104000070220802168 +:104D00002623FFFE240200023070FFFFA742014667 +:104D10000A0002DBA7430148A74001463C02080005 +:104D20008C42043C1440000D8F8300103082002020 +:104D30001440000224030009240300010060202124 +:104D40008F830010240209005062000134840004A3 +:104D5000A744014A0A0002F60000000024020F00E6 +:104D60001462000530820020144000062403000D68 +:104D70000A0002F524030005144000022403000980 +:104D800024030001A743014A3C0208008C4204208E +:104D90003C0400480E00020C004420250E000235A1 +:104DA000000000008F82000C1040003E0000000058 +:104DB0008F4210003C0300200043102410400039B3 +:104DC0008F820004304200021040003600000000D4 +:104DD000974210141440003300000000974210085E +:104DE0008F8800383042FFFF2442000600021882FC +:104DF0000003388000E83021304300018CC40000FB +:104E000010600004304200030000000D0A00033768 +:104E100000E81021544000103084FFFF3C05FFFFE4 +:104E200000852024008518260003182B0004102B71 +:104E300000431024104000050000000000000000A6 +:104E40000000000D00000000240002228CC20000BF +:104E50000A000336004520253883FFFF0003182B86 +:104E60000004102B00431024104000050000000037 +:104E7000000000000000000D000000002400022BD4 +:104E80008CC200003444FFFF00E81021AC44000055 +:104E90003C0208008C420430244200013C0108001E +:104EA000AC2204308F6200008F840038AF8200088B +:104EB0008C8300003402FFFF1462000F00001021F9 +:104EC0003C0508008CA504543C0408008C84045064 +:104ED00000B0282100B0302B008220210086202144 +:104EE0003C010800AC2504543C010800AC240450EB +:104EF0000A000580240400088C8200003042010072 +:104F00001040000F000010213C0508008CA5044C47 +:104F10003C0408008C84044800B0282100B0302BE9 +:104F200000822021008620213C010800AC25044C91 +:104F30003C010800AC2404480A0005802404000851 +:104F40003C0508008CA504443C0408008C84044003 +:104F500000B0282100B0302B0082202100862021C3 +:104F60003C010800AC2504443C010800AC2404408A +:104F70000A000580240400088F6200088F62000088 +:104F800000021602304300F02402003010620005D7 +:104F900024020040106200E08F8200200A00058891 +:104FA0002442000114A000050000000000000000E1 +:104FB0000000000D00000000240002568F4201781E +:104FC0000440FFFE000000000E00023D27A4001078 +:104FD0001440000500408021000000000000000D8A +:104FE000000000002400025D8E0200001040000559 +:104FF00000000000000000000000000D00000000A4 +:10500000240002608F62000C0443000324020001AC +:105010000A00042EAE000000AE0200008F820038AD +:105020008C480008A20000078F65000C8F64000404 +:1050300030A3FFFF0004240200852023308200FFFC +:105040000043102124420005000230832CC200815D +:10505000A605000A14400005A20400040000000098 +:105060000000000D00000000240002788F85003849 +:105070000E0005AB260400148F6200048F43010864 +:10508000A60200083C02100000621824106000080C +:105090000000000097420104920300072442FFEC45 +:1050A000346300023045FFFF0A0003C3A203000778 +:1050B000974201042442FFF03045FFFF96060008A6 +:1050C0002CC200135440000592030007920200070F +:1050D00034420001A20200079203000724020001EB +:1050E00010620005240200031062000B8F8200385A +:1050F0000A0003E030C6FFFF8F8200383C04FFFF48 +:105100008C43000C0064182400651825AC43000C87 +:105110000A0003E030C6FFFF3C04FFFF8C43001091 +:105120000064182400651825AC43001030C6FFFF4A +:1051300024C2000200021083A20200058F830038FF +:10514000304200FF00021080004328218CA800009C +:105150008CA2000024030004000217021443001272 +:1051600000000000974201043C03FFFF01031824E4 +:105170003042FFFF004610232442FFFE006240251C +:10518000ACA8000092030005306200FF000210800E +:1051900000501021904200143042000F00431021B3 +:1051A0000A000415A20200068CA400049742010420 +:1051B0009603000A3088FFFF3042FFFF00461023AD +:1051C0002442FFD60002140001024025ACA80004CE +:1051D000920200079204000524630028000318834C +:1051E0000064182134420004A2030006A202000752 +:1051F0008F8200042403FFFB34420002004310248A +:10520000AF820004920300068F87003800031880E5 +:10521000007010218C4400203C02FFF63442FFFF56 +:105220000082402400671821AE04000CAC68000C1A +:10523000920500063C03FF7F8E02000C00052880CB +:1052400000B020213463FFFF01033024948800263E +:1052500000A7282100431024AE02000CAC860020D9 +:10526000AC880024ACA8001024020010A742014022 +:1052700024020002A7400142A7400144A742014680 +:10528000974201043C0400082442FFFEA742014863 +:10529000240200010E00020CA742014A9603000AF4 +:1052A0009202000400431021244200023042000711 +:1052B00000021023304200070E000235AE0200103B +:1052C0008F6200003C0308008C6304442404001037 +:1052D000AF820008974201043042FFFF2442FFFEE4 +:1052E00000403821000237C33C0208008C420440D1 +:1052F000006718210067282B004610210045102167 +:105300003C010800AC2304443C010800AC220440EA +:105310000A0005150000000014A0000500000000B0 +:10532000000000000000000D000000002400030A3F +:105330008F4201780440FFFE000000000E00023D95 +:1053400027A4001414400005004080210000000044 +:105350000000000D00000000240003118E02000078 +:105360005440000692020007000000000000000DFB +:10537000000000002400031C9202000730420004D9 +:10538000104000058F8200042403FFFB344200021A +:1053900000431024AF8200048F620004044300081D +:1053A00092020007920200068E03000CAE0000007D +:1053B0000002108000501021AC4300209202000730 +:1053C00030420004544000099602000A920200058F +:1053D0003C03000100021080005010218C46001890 +:1053E00000C33021AC4600189602000A9206000461 +:1053F000277100080220202100C2302124C60005A8 +:10540000260500140E0005AB00063082920400064B +:105410008F6500043C027FFF000420800091202162 +:105420008C8300043442FFFF00A228240065182169 +:10543000AC8300049202000792040005920300046A +:10544000304200041040001496070008308400FF2A +:1054500000042080009120218C86000497420104E2 +:105460009605000A306300FF3042FFFF0043102121 +:105470000045102130E3FFFF004310232442FFD8F2 +:1054800030C6FFFF0002140000C23025AC860004C5 +:105490000A0004C992030007308500FF0005288038 +:1054A00000B128218CA4000097420104306300FF62 +:1054B0003042FFFF00431021004710233C03FFFF51 +:1054C000008320243042FFFF00822025ACA400008E +:1054D0009203000724020001106200060000000091 +:1054E0002402000310620011000000000A0004EC16 +:1054F0008E03001097420104920300049605000AEF +:105500008E24000C00431021004510212442FFF29C +:105510003C03FFFF008320243042FFFF0082202550 +:10552000AE24000C0A0004EC8E0300109742010424 +:10553000920300049605000A8E24001000431021F7 +:10554000004510212442FFEE3C03FFFF008320248E +:105550003042FFFF00822025AE2400108E03001091 +:105560002402000AA7420140A74301429603000A11 +:10557000920200043C04004000431021A742014471 +:10558000A740014697420104A742014824020001B6 +:105590000E00020CA742014A0E0002350000000076 +:1055A0008F6200009203000400002021AF820008F7 +:1055B000974201049606000A3042FFFF006218215C +:1055C000006028213C0308008C6304443C0208006E +:1055D0008C42044000651821004410210065382BDE +:1055E000004710213C010800AC2304443C010800A2 +:1055F000AC22044092040004008620212484000A86 +:105600003084FFFF0E0001E9000000009744010410 +:105610003084FFFF0E0001F7000000003C02100084 +:10562000AF4201780A0005878F820020148200278C +:105630003062000697420104104000673C024000BF +:105640003062400010400005000000000000000033 +:105650000000000D00000000240004208F420178AB +:105660000440FFFE24020800AF4201782402000833 +:10567000A7420140A74001428F82000497430104E2 +:1056800030420001104000073070FFFF2603FFFE8C +:1056900024020002A7420146A74301480A00053F31 +:1056A0002402000DA74001462402000DA742014A32 +:1056B0008F62000024040008AF8200080E0001E998 +:1056C000000000000A0005190200202110400042DD +:1056D0003C02400093620000304300F024020010BE +:1056E0001062000524020070106200358F820020D5 +:1056F0000A000588244200018F62000097430104DC +:105700003050FFFF3071FFFF8F4201780440FFFEF1 +:105710003202000700021023304200072403000A6F +:105720002604FFFEA7430140A7420142A7440144CB +:10573000A7400146A75101488F420108304200208E +:10574000144000022403000924030001A743014A76 +:105750000E00020C3C0400400E0002350000000068 +:105760003C0708008CE70444021110212442FFFE8C +:105770003C0608008CC604400040182100E3382194 +:10578000000010218F65000000E3402B00C2302193 +:105790002604000800C830213084FFFFAF850008D0 +:1057A0003C010800AC2704443C010800AC2604403E +:1057B0000E0001E9000000000A0005190220202166 +:1057C0000E00013B000000008F82002024420001F7 +:1057D000AF8200203C024000AF4201380A00029232 +:1057E000000000003084FFFF30C6FFFF00052C00E2 +:1057F00000A628253882FFFF004510210045282BF0 +:105800000045102100021C023042FFFF004310211E +:1058100000021C023042FFFF004310213842FFFF0C +:1058200003E000083042FFFF3084FFFF30A5FFFF98 +:1058300000001821108000070000000030820001E5 +:105840001040000200042042006518210A0005A152 +:105850000005284003E000080060102110C0000689 +:1058600024C6FFFF8CA2000024A50004AC82000027 +:105870000A0005AB2484000403E0000800000000D7 +:1058800010A0000824A3FFFFAC8600000000000069 +:10589000000000002402FFFF2463FFFF1462FFFAF0 +:1058A0002484000403E00008000000000000000160 +:1058B0000A00002A00000000000000000000000DA7 +:1058C000747870362E322E3162000000060201001C +:1058D00000000000000001360000EA600000000047 +:1058E00000000000000000000000000000000000B8 +:1058F00000000000000000000000000000000000A8 +:105900000000000000000000000000000000000097 +:105910000000001600000000000000000000000071 +:105920000000000000000000000000000000000077 +:105930000000000000000000000000000000000067 +:1059400000000000000000000000138800000000BC +:10595000000005DC00000000000000001000000353 +:10596000000000000000000D0000000D3C020800D7 +:1059700024423D683C0308002463401CAC40000006 +:105980000043202B1480FFFD244200043C1D08002E +:1059900037BD7FFC03A0F0213C100800261000A8B2 +:1059A0003C1C0800279C3D680E00044E00000000CF +:1059B0000000000D27BDFFB4AFA10000AFA200049E +:1059C000AFA30008AFA4000CAFA50010AFA6001451 +:1059D000AFA70018AFA8001CAFA90020AFAA0024F1 +:1059E000AFAB0028AFAC002CAFAD0030AFAE003491 +:1059F000AFAF0038AFB8003CAFB90040AFBC004417 +:105A0000AFBF00480E000591000000008FBF0048A6 +:105A10008FBC00448FB900408FB8003C8FAF003876 +:105A20008FAE00348FAD00308FAC002C8FAB0028D0 +:105A30008FAA00248FA900208FA8001C8FA7001810 +:105A40008FA600148FA500108FA4000C8FA3000850 +:105A50008FA200048FA1000027BD004C3C1B6004F6 +:105A60008F7A5030377B502803400008AF7A00000F +:105A70008F86003C3C0390003C0280000086282575 +:105A800000A32025AC4400203C0380008C6700204C +:105A900004E0FFFE0000000003E00008000000003A +:105AA0000A000070240400018F85003C3C04800043 +:105AB0003483000100A3102503E00008AC8200201D +:105AC00003E00008000010213084FFFF30A5FFFF35 +:105AD00010800007000018213082000110400002F1 +:105AE00000042042006518211480FFFB00052840B7 +:105AF00003E000080060102110C000070000000053 +:105B00008CA2000024C6FFFF24A50004AC82000084 +:105B100014C0FFFB2484000403E000080000000020 +:105B200010A0000824A3FFFFAC86000000000000C6 +:105B3000000000002402FFFF2463FFFF1462FFFA4D +:105B40002484000403E000080000000090AA003153 +:105B50008FAB00108CAC00403C0300FF8D6800044C +:105B6000AD6C00208CAD004400E060213462FFFF8A +:105B7000AD6D00248CA700483C09FF000109C0243A +:105B8000AD6700288CAE004C0182C824031978252B +:105B9000AD6F0004AD6E002C8CAD0038314A00FFB3 +:105BA000AD6D001C94A900323128FFFFAD680010D4 +:105BB00090A70030A5600002A1600004A16700006A +:105BC00090A30032306200FF0002198210600005CD +:105BD000240500011065000E0000000003E000082D +:105BE000A16A00018CD80028354A0080AD780018E1 +:105BF0008CCF0014AD6F00148CCE0030AD6E000859 +:105C00008CC4002CA16A000103E00008AD64000C04 +:105C10008CCD001CAD6D00188CC90014AD6900144A +:105C20008CC80024AD6800088CC70020AD67000C4C +:105C30008CC200148C8300700043C82B1320000713 +:105C4000000000008CC20014144CFFE400000000AF +:105C5000354A008003E00008A16A00018C820070D0 +:105C60000A0000E6000000009089003027BDFFF820 +:105C70008FA8001CA3A900008FA300003C0DFF808B +:105C800035A2FFFF8CAC002C00625824AFAB0000A3 +:105C9000A100000400C05821A7A000028D06000446 +:105CA00000A048210167C8218FA500000080502175 +:105CB0003C18FF7F032C20263C0E00FF2C8C00019B +:105CC000370FFFFF35CDFFFF3C02FF0000AFC824B8 +:105CD00000EDC02400C27824000C1DC003236825F9 +:105CE00001F87025AD0D0000AD0E00048D240024D8 +:105CF000AFAD0000AD0400088D2C00202404FFFF90 +:105D0000AD0C000C9547003230E6FFFFAD060010E9 +:105D10009145004830A200FF000219C25060000106 +:105D20008D240034AD0400148D4700388FAA00186C +:105D300027BD0008AD0B0028AD0A0024AD07001CEC +:105D4000AD00002CAD00001803E00008AD000020FD +:105D500027BDFFE0AFB20018AFB10014AFB0001024 +:105D6000AFBF001C9098003000C088213C0D00FFA0 +:105D7000330F007FA0CF0000908E003135ACFFFFC5 +:105D80003C0AFF00A0CE000194A6001EA220000441 +:105D90008CAB00148E29000400A08021016C282403 +:105DA000012A40240080902101052025A62600021A +:105DB000AE24000426050020262400080E000092D0 +:105DC00024060002924700302605002826240014ED +:105DD00000071E000003160324060004044000030D +:105DE0002403FFFF965900323323FFFF0E00009279 +:105DF000AE230010262400248FBF001C8FB2001891 +:105E00008FB100148FB00010240500030000302172 +:105E10000A00009C27BD002027BDFFD8AFB1001CA1 +:105E2000AFB00018AFBF002090A9003024020001DD +:105E300000E050213123003F00A040218FB00040FE +:105E40000080882100C04821106200148FA700380C +:105E5000240B000500A0202100C02821106B001396 +:105E6000020030210E000128000000009225007C75 +:105E700030A400021080000326030030AE00003082 +:105E8000260300348FBF00208FB1001C8FB0001894 +:105E90000060102103E0000827BD00280E0000A7C5 +:105EA000AFB000100A00016F000000008FA3003C9B +:105EB000010020210120282101403021AFA3001042 +:105EC0000E0000EEAFB000140A00016F00000000E9 +:105ED0003C06800034C20E008C4400108F850044C4 +:105EE000ACA400208C43001803E00008ACA30024FD +:105EF0003C06800034C20E008C4400148F850044A0 +:105F0000ACA400208C43001C03E00008ACA30024D8 +:105F10009382000C1040001B2483000F2404FFF028 +:105F20000064382410E00019978B00109784000E4D +:105F30009389000D3C0A601C0A0001AC01644023F7 +:105F400001037021006428231126000231C2FFFFE3 +:105F500030A2FFFF0047302B50C0000E00E4482164 +:105F60008D4D000C31A3FFFF00036400000C2C03D7 +:105F700004A1FFF30000302130637FFF0A0001A479 +:105F80002406000103E00008000000009784000ED2 +:105F900000E448213123FFFF3168FFFF0068382B00 +:105FA00054E0FFF8A783000E938A000D114000050E +:105FB000240F0001006BC023A380000D03E0000844 +:105FC000A798000E006BC023A38F000D03E000080C +:105FD000A798000E03E000080000000027BDFFE8BE +:105FE000AFB000103C10800036030140308BFFFF43 +:105FF00093AA002BAFBF0014A46B000436040E005C +:106000009488001630C600FF8FA90030A4680006EF +:10601000AC650008A0660012A46A001AAC670020F4 +:106020008FA5002CA4690018012020210E000198E2 +:10603000AC6500143C021000AE0201788FBF001462 +:106040008FB0001003E0000827BD00188F85000006 +:106050002484000727BDFFF83084FFF83C06800049 +:1060600094CB008A316AFFFFAFAA00008FA900001D +:10607000012540232507FFFF30E31FFF0064102B9D +:106080001440FFF700056882000D288034CC4000E2 +:1060900000AC102103E0000827BD00088F8200003B +:1060A0002486000730C5FFF800A2182130641FFFC6 +:1060B00003E00008AF8400008F87003C8F84004419 +:1060C00027BDFFB0AFB70044AFB40038AFB1002C6C +:1060D000AFBF0048AFB60040AFB5003CAFB300342F +:1060E000AFB20030AFB000283C0B80008C8600249B +:1060F000AD6700808C8A002035670E00356901008D +:10610000ACEA00108C8800248D2500040000B82122 +:10611000ACE800188CE3001000A688230000A02142 +:10612000ACE300148CE20018ACE2001C122000FE6C +:1061300000E0B021936C0008118000F40000000022 +:10614000976F001031EEFFFF022E682B15A000EFB5 +:1061500000000000977200103250FFFFAED0000028 +:106160003C0380008C740000329300081260FFFD35 +:106170000000000096D800088EC700043305FFFF1A +:1061800030B5000112A000E4000000000000000D86 +:1061900030BFA0402419004013F9011B30B4A00007 +:1061A000128000DF000000009373000812600008F6 +:1061B00000000000976D001031ACFFFF00EC202BB9 +:1061C0001080000330AE004011C000D50000000078 +:1061D000A7850040AF87003893630008022028217C +:1061E000AFB10020146000F527B40020AF60000CB0 +:1061F000978F004031F14000162000022403001662 +:106200002403000E24054007A363000AAF650014B1 +:10621000938A00428F70001431550001001512401E +:1062200002024825AF690014979F00408F78001440 +:1062300033F9001003194025AF680014979200400D +:106240003247000810E0016E000000008F67001464 +:106250003C1210003C11800000F27825AF6F001452 +:1062600036230E00946E000A3C0D81002406000EB9 +:1062700031CCFFFF018D2025AF640004A36600022E +:106280009373000A3406FFFC266B0004A36B000A1C +:1062900097980040330820001100015F00000000C3 +:1062A0003C05800034A90E00979900409538000CF9 +:1062B00097870040001940423312C00031030003A9 +:1062C00000127B0330F11000006F6825001172038B +:1062D00001AE6025000C20C0A76400129793004017 +:1062E000936A000A001359823175003C02AA1021FA +:1062F0002450003CA3700009953F000C33F93FFF88 +:10630000A779001097700012936900090130F821F5 +:1063100027E5000230B900070019C0233308000741 +:10632000A368000B9371000997720012976F001019 +:10633000322700FF8F910038978D004000F218211E +:10634000006F702101C6602131A6004010C0000519 +:106350003185FFFF00B1102B3C1280001040001768 +:10636000000098210225A82B56A0013E8FA50020F1 +:106370003C048000348A0E008D5300143C068000DB +:10638000AD5300108D4B001CAD4B0018AD45000007 +:106390008CCD000031AC00081180FFFD34CE0E0022 +:1063A00095C3000800A0882100009021A783004029 +:1063B0008DC6000424130001AF860038976F0010CB +:1063C00031F5FFFF8E9F000003F1282310A0011F6D +:1063D000AE85000093620008144000DD000000005C +:1063E0000E0001E7240400108F900048004028218F +:1063F0003C023200320600FF000654000142F8253C +:1064000026090001AF890048ACBF0000937900095C +:1064100097780012936F000A332800FF3303FFFFC1 +:106420000103382100076C0031EE00FF01AE60254A +:10643000ACAC00048F840048978B0040316A200088 +:106440001140010AACA4000897640012308BFFFFD2 +:1064500006400108ACAB000C978E004031C5000827 +:1064600014A0000226280006262800023C1F8000F7 +:1064700037E70E0094F900148CE5001C8F670004C8 +:10648000937800023324FFFF330300FFAFA3001013 +:106490008F6F0014AFA800180E0001CBAFAF00142F +:1064A000240400100E0001FB000000008E9200008A +:1064B00016400005000000008F7800142403FFBF81 +:1064C0000303A024AF7400148F67000C00F5C821EB +:1064D000AF79000C9375000816A0000800000000BA +:1064E00012600006000000008F6800143C0AEFFFF5 +:1064F0003549FFFE0109F824AF7F0014A37300089B +:106500008FA500200A00034F02202021AED10000F9 +:106510000A00022D3C03800014E0FF1E30BFA040A3 +:106520000E0001900000A0212E9100010237B0253D +:1065300012C000188FBF00488F87003C24170F003F +:1065400010F700D43C0680008CD901780720FFFEAC +:10655000241F0F0010FF00F634CA0E008D560014E1 +:1065600034C7014024080240ACF600048D49001CE9 +:106570003C141000ACE90008A0E00012A4E0001AEE +:10658000ACE00020A4E00018ACE80014ACD4017822 +:106590008FBF00488FB700448FB600408FB5003CD6 +:1065A0008FB400388FB300348FB200308FB1002C1D +:1065B0008FB0002803E0000827BD00508F910038FD +:1065C000978800403C1280000220A821310700403B +:1065D00014E0FF7C00009821977900108F9200381A +:1065E0003338FFFF131200A8000020210080A021F3 +:1065F000108000F300A088211620FECE00000000CD +:106600000A00031F2E9100013C0380008C62017878 +:106610000440FFFE240808008F860000AC68017863 +:106620003C038000946D008A31ACFFFF0186582343 +:10663000256AFFFF31441FFF2C8900081520FFF950 +:10664000000000008F8F0048347040008F83003CB2 +:1066500000E0A021240E0F0025E70001AF870048CD +:1066600000D03021023488233C08800031F500FF3F +:10667000106E0005240700019398004233130001B7 +:106680000013924036470001001524003C0A010027 +:10669000008A4825ACC900008F82004830BF003610 +:1066A00030B90008ACC200041320009900FF9825FF +:1066B00035120E009650000A8F8700003C0F8100B3 +:1066C0003203FFFF24ED000835060140006F60250E +:1066D0003C0E100031AB1FFF269200062405000E71 +:1066E000ACCC0020026E9825A4C5001AAF8B000028 +:1066F000A4D20018162000083C1080008F89003CAE +:1067000024020F00512200022417000136730040BA +:106710000E0001883C10800036060E008CCB001461 +:10672000360A014002402021AD4B00048CC5001CFC +:10673000AD450008A1550012AD5300140E0001989C +:106740003C151000AE1501780A000352000000004D +:10675000936F0009976E0012936D000B31E500FFF7 +:1067600000AE202131AC00FF008C80212602000AFF +:106770003050FFFF0E0001E7020020218F86004805 +:106780003C0341003C05800024CB0001AF8B004856 +:10679000936A00099769001230C600FF315F00FF5D +:1067A0003128FFFF03E8382124F900020006C40065 +:1067B0000319782501E37025AC4E00008F6D000CA5 +:1067C00034A40E00948B001401B26025AC4C00047C +:1067D0008C85001C8F670004936A00023164FFFF00 +:1067E000314900FFAFA900108F680014AFB1001845 +:1067F0000E0001CBAFA800140A0002FD0200202108 +:10680000AF600004A36000029798004033082000A6 +:106810001500FEA300003021A760001297840040FD +:10682000936B000A3C10800030931F0000135183CB +:10683000014BA82126A20028A362000936090E00F8 +:10684000953F000C0A000295A77F00108F7000147E +:10685000360900400E000188AF6900140A0002C921 +:10686000000000000A00034F000020210641FEFA4C +:10687000ACA0000C8CAC000C3C0D8000018D902570 +:106880000A0002EAACB2000C000090210A0002C526 +:1068900024130001128000073C028000344B0E00DC +:1068A0009566000830D300401260004900000000E7 +:1068B0003C0680008CD001780600FFFE34C50E0037 +:1068C00094B500103C03050034CC014032B8FFFF02 +:1068D00003039025AD92000C8CAF0014240D200012 +:1068E0003C041000AD8F00048CAE001CAD8E00087F +:1068F000A1800012A580001AAD800020A58000189C +:10690000AD8D0014ACC401780A0003263C0680005B +:106910008F9F0000351801402692000227F90008D9 +:1069200033281FFFA71200180A000391AF88000048 +:106930003C02800034450140ACA0000C1280001BDA +:1069400034530E0034510E008E370010ACB70004E3 +:106950008E2400183C0B8000ACA400083570014068 +:1069600024040040A20000128FBF0048A600001AB5 +:106970008FB70044AE0000208FB60040A60000187C +:106980008FB5003CAE0400148FB400388FB30034D0 +:106990008FB200308FB1002C8FB000283C02100065 +:1069A00027BD005003E00008AD6201788E66001438 +:1069B000ACA600048E64001C0A00042A3C0B800074 +:1069C0000E0001902E9100010A0003200237B0252D +:1069D000000000000000000D00000000240003691A +:1069E0000A0004013C06800027BDFFD8AFBF00208D +:1069F0003C0980003C1F20FFAFB200183C0760003C +:106A000035320E002402001037F9FFFDACE23008E9 +:106A1000AFB3001CAFB10014AFB00010AE5900000E +:106A20000000000000000000000000000000000066 +:106A3000000000003C1800FF3713FFFDAE530000BC +:106A40003C0B60048D7050002411FF7F3C0E00024F +:106A50000211782435EC380C35CD0109ACED4C1819 +:106A6000240A0009AD6C50008CE80438AD2A0008F7 +:106A7000AD2000148CE54C1C3106FFFF38C42F718B +:106A800000051E023062000F2486C0B310400007CC +:106A9000AF8200088CE54C1C3C09001F3528FC0027 +:106AA00000A81824000321C2AF8400048CF1080858 +:106AB0003C0F57092412F0000232702435F0001008 +:106AC00001D0602601CF68262DAA00012D8B000180 +:106AD000014B382550E00009A380000C3C1F601CCE +:106AE0008FF8000824190001A399000C33137C00CF +:106AF000A7930010A780000EA380000DAF80004870 +:106B000014C00003AF8000003C066000ACC0442C01 +:106B10000E0005B93C1080000E000F1A361101005E +:106B20003C12080026523DD03C13080026733E500C +:106B30008E03000038640001308200011440FFFC25 +:106B40003C0B800A8E2600002407FF8024C90240E7 +:106B5000312A007F014B402101272824AE06002066 +:106B6000AF880044AE0500243C048000AF86003CA2 +:106B70008C8C01780580FFFE24180800922F0008F5 +:106B8000AC980178A38F0042938E004231CD000172 +:106B900011A0000F24050D0024DFF8002FF90301D8 +:106BA0001320001C000629C224A4FFF00004104298 +:106BB000000231400E00020200D2D8213C02400007 +:106BC0003C068000ACC201380A0004A000000000AE +:106BD00010C50023240D0F0010CD00273C1F800896 +:106BE00037F9008093380000240E0050330F00FF67 +:106BF00015EEFFF33C0240000E000A3600000000D4 +:106C00003C0240003C068000ACC201380A0004A0EF +:106C1000000000008F83000400A3402B1500000B30 +:106C20008F8B0008006B50212547FFFF00E5482BA4 +:106C30001520000600A36023000C19400E0002027C +:106C40000073D8210A0004C43C0240000000000D7B +:106C50000E000202000000000A0004C43C024000D2 +:106C60003C1B0800277B3F500E0002020000000082 +:106C70000A0004C43C0240003C1B0800277B3F7014 +:106C80000E000202000000000A0004C43C024000A2 +:106C90003C0660043C09080025290104ACC9502CBD +:106CA0008CC850003C0580003C0200023507008083 +:106CB000ACC750003C040800248415A43C03080021 +:106CC0002463155CACA50008ACA2000C3C010800D4 +:106CD000AC243D603C010800AC233D6403E00008A7 +:106CE0002402000100A030213C1C0800279C3D68C4 +:106CF0003C0C04003C0B0002008B3826008C402624 +:106D00002CE200010007502B2D050001000A4880ED +:106D10003C03080024633D60004520250123182121 +:106D20001080000300001021AC6600002402000166 +:106D300003E00008000000003C1C0800279C3D68A0 +:106D40003C0B04003C0A0002008A3026008B3826E7 +:106D50002CC200010006482B2CE5000100094080F0 +:106D60003C03080024633D600045202501031821F1 +:106D700010800005000010213C0C0800258C155CDB +:106D8000AC6C00002402000103E0000800000000D9 +:106D90003C0900023C08040000883026008938269F +:106DA0002CC30001008028212CE400010083102561 +:106DB0001040000B000030213C1C0800279C3D685F +:106DC0003C0A80008D4E00082406000101CA682597 +:106DD000AD4D00088D4C000C01855825AD4B000CC5 +:106DE00003E0000800C010213C1C0800279C3D68FF +:106DF0003C0580008CA6000C000420272402000122 +:106E000000C4182403E00008ACA3000C3C020002FC +:106E10001082000B3C0560003C0704001087000353 +:106E20000000000003E00008000000008CA908D06A +:106E3000240AFFFD012A402403E00008ACA808D082 +:106E40008CA408D02406FFFE0086182403E0000866 +:106E5000ACA308D03C05601A34A600108CC3008097 +:106E600027BDFFF88CC50084AFA3000093A40000E9 +:106E70002402000110820003AFA5000403E0000813 +:106E800027BD000893A7000114E0001497AC00028E +:106E900097B800023C0F8000330EFFFC01CF682141 +:106EA000ADA50000A3A000003C0660008CC708D080 +:106EB0002408FFFE3C04601A00E82824ACC508D072 +:106EC0008FA300048FA200003499001027BD000892 +:106ED000AF22008003E00008AF2300843C0B800059 +:106EE000318AFFFC014B48218D2800000A00057DF6 +:106EF000AFA8000427BDFFE8AFBF00103C1C08008E +:106F0000279C3D683C0580008CA4000C8CA20004EA +:106F10003C0300020044282410A0000A00A3182407 +:106F20003C0604003C0400021460000900A6102482 +:106F30001440000F3C0404000000000D3C1C08003D +:106F4000279C3D688FBF001003E0000827BD001894 +:106F50003C0208008C423D600040F809000000003F +:106F60003C1C0800279C3D680A0005A68FBF001046 +:106F70003C0208008C423D640040F809000000001B +:106F80000A0005AC00000000000411C003E0000886 +:106F9000244202403C04080024843FB42405001A23 +:106FA0000A00009C0000302127BDFFE0AFB00010B8 +:106FB0003C108000AFBF0018AFB1001436110100C3 +:106FC000922200090E0005B63044007F8E3F00007B +:106FD0008F89003C3C0F008003E26021258800403F +:106FE0000049F821240DFF80310E00783198007897 +:106FF00035F9000135F100020319382501D1482582 +:10700000010D302403ED5824018D2824240A00406A +:1070100024040080240300C0AE0B0024AE0008103E +:10702000AE0A0814AE040818AE03081CAE05080426 +:10703000AE070820AE060808AE0908243609090084 +:107040009539000C3605098033ED007F3338FFFF9A +:10705000001889C0AE110800AE0F0828952C000C4E +:107060008FBF00188FB10014318BFFFF000B51C090 +:10707000AE0A002C8CA400508FB000108CA3003CF2 +:107080008D2700048CA8001C8CA600383C0E800ABA +:1070900001AE102127BD0020AF820044AF84005014 +:1070A000AF830054AF87004CAF88005C03E000085A +:1070B000AF8600603C09080091293FD924A800024E +:1070C0003C05110000093C0000E8302500C51825EA +:1070D00024820008AC83000003E00008AC800004B8 +:1070E0003C098000352309009128010B906A0011AA +:1070F0002402002800804821314700FF00A07021B1 +:1071000000C068213108004010E20002340C86DD26 +:10711000240C08003C0A800035420A9A944700007B +:10712000354B0A9C35460AA030F9FFFFAD39000007 +:107130008D780000354B0A8024040001AD3800042E +:107140008CCF0000AD2F00089165001930A300031B +:107150001064009028640002148000AF240500022F +:107160001065009E240F0003106F00B435450AA47B +:10717000240A0800118A0048000000005100003D68 +:107180003C0B80003C0480003483090090670012AF +:1071900030E200FF004D7821000FC8802724000155 +:1071A0003C0A8000354F090091E50019354C0980F3 +:1071B0008D87002830A300FF0003150000475825E5 +:1071C0000004C4003C19600001793025370806FF2F +:1071D000AD260000AD2800048DEA002C25280028EB +:1071E000AD2A00088DEC0030AD2C000C8DE500348C +:1071F000AD2500108DE400383C05800034AC093C1E +:10720000AD2400148DE3001CAD2300188DE7002091 +:10721000AD27001C8DE20024AD2200208DF900284E +:1072200034A20100AD3900248D830000AD0E0004AE +:1072300034B90900AD0300008C47000C250200148E +:10724000AD070008932B00123C04080090843FD83F +:10725000AD000010317800FF030D302100064F0013 +:1072600000047C00012F702535CDFFFC03E00008F1 +:10727000AD0D000C35780900930600123C0508009E +:1072800094A53FC830C800FF010D5021000A60805E +:107290000A00063C018520211500005B000000006B +:1072A0003C08080095083FCE3C06080094C63FC83D +:1072B000010610213C0B800035790900933800113C +:1072C000932A001935660A80330800FF94CF002AFC +:1072D00000086082314500FF978A0058000C1E00AC +:1072E000000524003047FFFF006410250047C0253B +:1072F00001EA30213C0B4000030B402500066400EE +:10730000AD280000AD2C0004932500183C030006B6 +:107310002528001400053E0000E31025AD220008DA +:107320008F24002C3C05800034AC093CAD24000CBB +:107330008F38001C34A20100254F0001AD38001029 +:107340008D830000AD0E000431EB7FFFAD03000024 +:107350008C47000C34B90900A78B0058AD07000812 +:10736000932B00123C04080090843FD8250200149F +:10737000317800FF030D302100064F0000047C002F +:10738000012F702535CDFFFCAD00001003E0000893 +:10739000AD0D000C3C02080094423FD23C050800B1 +:1073A00094A53FC835440AA43C07080094E73FC4AD +:1073B000948B00000045C8210327C023000B1C004C +:1073C0002706FFF200665025AD2A000CAD20001004 +:1073D000AD2C00140A00063025290018354F0AA4E8 +:1073E00095E50000956400280005140000043C00A9 +:1073F0003459810000EC5825AD39000CAD2B00103C +:107400000A000630252900143C0C0800958C3FCE5C +:107410000A000681258200015460FF56240A0800F4 +:1074200035580AA49706000000061C00006C502581 +:10743000AD2A000C0A000630252900103C03080084 +:1074400094633FD23C07080094E73FC83C0F080014 +:1074500095EF3FC494A4000095790028006710219F +:10746000004F582300041C00001934002578FFEE5B +:1074700000D87825346A8100AD2A000CAD2F0010A9 +:10748000AD200014AD2C00180A0006302529001C80 +:1074900003E00008240207D027BDFFE0AFB20018C8 +:1074A000AFB10014AFB00010AFBF001C0E00007CE5 +:1074B000008088218F8800548F87004C3C0580080D +:1074C00034B20080011128213C1080002402008089 +:1074D000240300C000A72023AE0208183C06800841 +:1074E000AE03081C18800004AF850054ACC500042E +:1074F0008CC90004AF89004C1220000936040980B1 +:107500000E0006F800000000924C00278E0B00745D +:1075100001825004014B3021AE46000C3604098034 +:107520008C8E001C8F8F005C01CF682319A0000493 +:107530008FBF001C8C90001CAF90005C8FBF001CA4 +:107540008FB200188FB100148FB000100A00007EB7 +:1075500027BD00208F8600508F8300548F82004CFF +:107560003C05800834A40080AC860050AC83003C0D +:1075700003E00008ACA200043C0308008C63005444 +:1075800027BDFFF8308400FF2462000130A500FF12 +:107590003C010800AC22005430C600FF3C078000CC +:1075A0008CE801780500FFFE3C0C7FFFA3A40003DC +:1075B0008FAA0000358BFFFF014B4824000627C02F +:1075C00001244025AFA8000034E201009043000AE6 +:1075D000A3A000023C1980FFA3A300018FAF00000D +:1075E00030AE007F3738FFFF01F86024000E6E00D8 +:1075F0003C0A002034E50140018D58253549200022 +:107600002406FF803C04100027BD0008ACAB000C32 +:10761000ACA90014A4A00018A0A6001203E0000862 +:10762000ACE40178308800FF30A700FF3C03800005 +:107630008C6201780440FFFE3C0C8000358A0A0011 +:107640008D4B00203584014035850980AC8B0004CA +:107650008D4900240007302B00061540AC89000836 +:10766000A088001090A3004CA083002D03E0000828 +:10767000A480001827BDFFE8308400FFAFBF0010D2 +:107680000E00075D30A500FF8F8300548FBF0010F0 +:107690003C06800034C50140344700402404FF907C +:1076A0003C02100027BD0018ACA3000CA0A40012DF +:1076B000ACA7001403E00008ACC2017827BDFFE0CE +:1076C0003C088008AFBF001CAFB20018AFB1001477 +:1076D000AFB00010351000808E0600183C07800007 +:1076E000309200FF00C72025AE0400180E00007C79 +:1076F00030B100FF92030005346200080E00007EE6 +:10770000A2020005024020210E000771022028215C +:10771000024020218FBF001C8FB200188FB10014CF +:107720008FB0001024050005240600010A0007326E +:1077300027BD00203C05800034A309809066000826 +:1077400030C200081040000F3C0A01013549080A08 +:10775000AC8900008CA80074AC8800043C070800C9 +:1077600090E73FD830E5001050A00008AC8000083A +:107770003C0D800835AC00808D8B0058AC8B000828 +:107780002484000C03E00008008010210A0007B5E3 +:107790002484000C27BDFFE83C098000AFB0001036 +:1077A000AFBF00143526098090C8000924020006E6 +:1077B00000A05821310300FF3527090000808021F7 +:1077C000240500041062007B2408000294CF005CB2 +:1077D0003C0E020431EDFFFF01AE6025AE0C00004F +:1077E00090CA00083144002010800008000000000A +:1077F00090C2004E3C1F010337F90300305800FFD0 +:107800000319302524050008AE06000490F9001184 +:1078100090E6001290E40011333800FF00187082E7 +:1078200030CF00FF01CF5021014B6821308900FF8C +:1078300031AAFFFF39230028000A60801460002C61 +:10784000020C482390E400123C198000372F0100FD +:10785000308C00FF018B1821000310800045F821B7 +:10786000001F8400360706FFAD270004373F0900DC +:1078700093EC001193EE0012372609800005C082B8 +:107880008DE4000C8CC5003431CD00FF01AB10211C +:107890000058182100A4F8230008840000033F00CA +:1078A00000F0302533F9FFFF318F00FC00D970253F +:1078B0000158202101E9682100045080ADAE000C80 +:1078C0000E00007C012A80213C088008240B000463 +:1078D000350500800E00007EA0AB000902001021DB +:1078E0008FBF00148FB0001003E0000827BD001800 +:1078F00090EC001190E300193C18080097183FCE57 +:10790000318200FF0002F882307000FF001FCE00BD +:1079100000103C000327302500D870253C0F4000A4 +:1079200001CF68253C198000AD2D0000373F0900CC +:1079300093EC001193EE0012372F010037260980D7 +:107940000005C0828DE4000C8CC5003431CD00FFF1 +:1079500001AB10210058182100A4F823000884006E +:1079600000033F0000F0302533F9FFFF318F00FCAA +:1079700000D970250158202101E9682100045080B8 +:10798000ADAE000C0E00007C012A80213C0880086E +:10799000240B0004350500800E00007EA0AB00091A +:1079A000020010218FBF00148FB0001003E0000808 +:1079B00027BD00180A0007C72408001227BDFFD002 +:1079C0003C038000AFB60028AFB50024AFB4002060 +:1079D000AFB10014AFBF002CAFB3001CAFB20018A2 +:1079E000AFB000103467010090E6000B309400FF48 +:1079F00030B500FF30C200300000B02110400099C7 +:107A000000008821346409809088000800082E0056 +:107A100000051E03046000C0240400048F86005487 +:107A20003C010800A0243FD83C0C8000AD800048F9 +:107A30003C048000348E010091CD000B31A5002064 +:107A400010A000073C078000349309809272000860 +:107A50000012860000107E0305E000C43C1F800871 +:107A600034EC0100918A000B34EB09809169000825 +:107A7000314400400004402B3123000800C8982303 +:107A80001460000224120003000090213C108000CA +:107A900036180A8036040900970E002C90830011D6 +:107AA0009089001293050018307F00FF312800FFF5 +:107AB000024810210002C880930D0018033F78216E +:107AC00001F1302130B100FF00D11821A78E0058FC +:107AD0003C010800A4263FCE3C010800A4233FD06F +:107AE00015A00002000000000000000D920B010B29 +:107AF0003065FFFF3C010800A4233FD2316A0040FB +:107B00003C010800A4203FC83C010800A4203FC459 +:107B10001140000224A4000A24A4000B3091FFFFAE +:107B20000E0001E7022020219206010B3C0C080008 +:107B3000958C3FD2004020210006698231A70001C8 +:107B40000E00060101872821004020210260282123 +:107B50000E00060C024030210E0007A1004020213B +:107B600016C00069004020219212010B32560040DD +:107B700012C000053C0500FF8C93000034AEFFFFEF +:107B8000026E8024AC9000000E0001FB0220202138 +:107B90003C0F080091EF3FD831F10003122000168E +:107BA0003C1380088F8200543C09800835280080EF +:107BB000245F0001AD1F003C3C0580088CB9000427 +:107BC00003E02021033FC0231B000002AF9F0054AD +:107BD0008CA400040E0006F8ACA400043C0780004E +:107BE0008CEB00743C04800834830080004B5021EF +:107BF000AC6A000C3C1380083670008002802021A3 +:107C000002A02821A200006B0E00075D3C1480003A +:107C10008F920054368C0140AD92000C8F86004844 +:107C20003C151000344D000624D60001AF960048E4 +:107C30008FBF002CA18600128FB60028AD8D0014D6 +:107C40008FB3001CAE9501788FB200188FB5002459 +:107C50008FB400208FB100148FB0001003E0000833 +:107C600027BD003034640980908F0008000F760033 +:107C7000000E6E0305A00033347F090093F8001B4B +:107C8000241900103C010800A0393FD8331300022A +:107C90001260FF678F8600548F8200601446FF6574 +:107CA0003C0480000E00007C000000003C048008C2 +:107CB0003485008090A8000924060016310300FFD7 +:107CC0001066000D0000000090AB00093C070800A2 +:107CD00090E73FD824090008316400FF34EA00012E +:107CE0003C010800A02A3FD81089002F240C000A6C +:107CF000108C00282402000C0E00007E0000000002 +:107D00000A0008608F8600540E0007B9024028213F +:107D10000A0008AE004020213C0B8008356A008034 +:107D20008D4600548CE9000C1120FF3DAF860054B5 +:107D3000240700143C010800A0273FD80A00085F70 +:107D40003C0C800090910008241200023C010800C5 +:107D5000A0323FD8323000201200000B2416000160 +:107D60008F8600540A0008602411000837F800804C +:107D70008F020038AFE200048FF90004AF19003C15 +:107D80000A00086C3C0780008F8600540A000860D7 +:107D900024110004A0A200090E00007E00000000D3 +:107DA0000A0008608F860054240200140A00093A71 +:107DB000A0A2000927BDFFE8AFB000103C10800072 +:107DC000AFBF001436020100904400090E00075DA9 +:107DD000240500013C0480089099000E3483008043 +:107DE000909F000F906F00269089000A33F800FFE3 +:107DF00000196E000018740031EC00FF01AE502530 +:107E0000000C5A00014B3825312800FF3603014091 +:107E10003445600000E830252402FF813C04100056 +:107E2000AC66000C8FBF0014AC650014A062001299 +:107E3000AE0401788FB0001003E0000827BD0018E1 +:107E400027BDFFE8308400FFAFBF00100E00075DC4 +:107E500030A500FF3C05800034A4014034470040B9 +:107E60002406FF92AC870014A08600128F83005472 +:107E70008FBF00103C02100027BD0018AC83000C1F +:107E800003E00008ACA2017827BDFFD8AFB0001016 +:107E9000308400FF30B000FF3C058000AFB100141B +:107EA000AFBF0020AFB3001CAFB20018000410C277 +:107EB00034A60100320300023051000114600007B3 +:107EC00090D200093C098008353300809268000593 +:107ED0003107000810E0000C308A00100240202119 +:107EE0000E00078302202821240200018FBF0020FA +:107EF0008FB3001C8FB200188FB100148FB0001028 +:107F000003E0000827BD00281540003434A50A000E +:107F10008CB800248CAF0008130F004B00003821F0 +:107F20003C0D800835B30080926C00682406000286 +:107F3000318B00FF116600843C06800034C20100D2 +:107F40009263004C90590009307F00FF53F9000400 +:107F50003213007C10E00069000000003213007C46 +:107F60005660005C0240202116200009320D0001FD +:107F70003C0C800035840100358B0A008D6500249F +:107F80008C86000414A6FFD900001021320D0001D8 +:107F900011A0000E024020213C1880003710010083 +:107FA0008E0F000C8F8E005011EE000800000000B4 +:107FB0000E000843022028218E19000C3C1F800867 +:107FC00037F00080AE190050024020210E000771EA +:107FD000022028210A00098F240200013C05080024 +:107FE0008CA5006424A400013C010800AC240064BA +:107FF0001600000D00000000022028210E0007716D +:1080000002402021926E0068240C000231CD00FF56 +:1080100011AC0022024020210E00094100000000A6 +:108020000A00098F240200010E00007024040001E0 +:10803000926B0025020B30250E00007EA266002503 +:108040000A0009D3022028218E6200188CDF000468 +:108050008CB9002400021E0217F9FFB13065007FC1 +:108060009268004C264400013093007F1265004066 +:10807000310300FF1464FFAB3C0D8008264700016C +:1080800030F1007F30E200FF1225000B24070001D1 +:10809000004090210A00099C2411000124050004DD +:1080A0000E000732240600010E0009410000000006 +:1080B0000A00098F240200012405FF8002452024C4 +:1080C00000859026324200FF004090210A00099C62 +:1080D000241100010E00084302202821320700303D +:1080E00010E0FFA132100082024020210E00078321 +:1080F000022028210A00098F240200018E6900183D +:108100000240202102202821012640250E0009647A +:10811000AE6800189264004C240500032406000198 +:108120000E000732308400FF0E00007024040001AE +:1081300092710025021150250E00007EA26A0025D2 +:108140000A00098F240200018E6F00183C1880007D +:108150000240202101F87025022028210E0007711D +:10816000AE6E00189264004C0A000A1B240500043D +:10817000324A0080394900801469FF6A3C0D80084A +:108180000A0009F42647000127BDFFC0AFB0001860 +:108190003C108000AFBF0038AFB70034AFB600303E +:1081A000AFB5002CAFB40028AFB30024AFB20020AD +:1081B0000E0005BEAFB1001C360201009045000B59 +:1081C0000E00097690440008144000E78FBF003885 +:1081D0003C08800835070080A0E0006B3606098067 +:1081E00090C50000240300503C17080026F73F907C +:1081F00030A400FF3C13080026733FA01083000347 +:108200003C1080000000B82100009821241F0010BD +:108210003611010036120A00361509808E580024E6 +:108220008E3400048EAF00208F8C00543C01080077 +:10823000A03F3FD836190A80972B002C8EF60000FD +:10824000932A00180298702301EC68233C0108006F +:10825000AC2E3FB43C010800AC2D3FB83C010800F7 +:10826000AC2C3FDCA78B005802C0F809315400FF4A +:1082700030490002152000E930420001504000C49E +:108280009227000992A90008312800081500000271 +:10829000241500030000A8213C0A80003543090092 +:1082A00035440A008C8D00249072001190700012E9 +:1082B000907F0011325900FF321100FF02B11021EE +:1082C0000002C08033EF00FF0319B021028F70213C +:1082D00002D4602125CB00103C010800A4363FCE1B +:1082E0003C010800AC2D3FE03C010800A42C3FD02D +:1082F0003C010800A42B3FCC3556010035540980C1 +:1083000035510E008F8700548F89005C8E850020C8 +:1083100024080006012730233C010800AC283FD484 +:1083200000A7282304C000B50000902104A000B3DA +:1083300000C5502B114000B5000000003C010800B2 +:10834000AC263FB88E6200000040F8090000000033 +:108350003046000214C0007400408021304B000100 +:10836000556000118E6200043C0D08008DAD3FBCCD +:108370003C0EC0003C04800001AE6025AE2C000025 +:108380008C980000330F000811E0FFFD0000000092 +:10839000963F000824120001A79F00408E39000478 +:1083A000AF9900388E6200040040F8090000000018 +:1083B0000202802532030002146000B300000000B6 +:1083C0003C09080095293FC43C06080094C63FD0EC +:1083D0003C0A0800954A3FC63C0708008CE73FBCB2 +:1083E000012670213C0308008C633FE03C08080034 +:1083F00095083FDA01CA20218ED9000C00E9282116 +:10840000249F000200A878210067C02133E4FFFF09 +:10841000AF9900503C010800AC383FE03C01080037 +:10842000A42F3FC83C010800A42E3FD20E0001E754 +:10843000000000008F8D0048004020213C01080012 +:10844000A02D3FD98E62000825AC0001AF8C0048FA +:108450000040F809000000008F85005402A0302180 +:108460000E00060C004020210E0007A10040202134 +:108470008E6B000C0160F809004020213C0A0800C6 +:10848000954A3FD23C06080094C63FC601464821A3 +:10849000252800020E0001FB3104FFFF3C05080007 +:1084A0008CA53FB43C0708008CE73FBC00A7202305 +:1084B0003C010800AC243FB414800006000000001A +:1084C0003C0208008C423FD4344B00403C01080081 +:1084D000AC2B3FD4124000438F8E00448E2D0010F1 +:1084E0008F920044AE4D00208E2C0018AE4C00241C +:1084F0003C04080094843FC80E0006FA0000000007 +:108500008F9F00548E6700103C010800AC3F3FDC99 +:1085100000E0F809000000003C1908008F393FB462 +:108520001720FF798F870054979300583C11800ED5 +:10853000321601000E000729A633002C16C0004594 +:10854000320300105460004C8EE5000432080040F5 +:108550005500001D8EF000088EE4000C0080F80924 +:10856000000000008FBF00388FB700348FB6003096 +:108570008FB5002C8FB400288FB300248FB2002059 +:108580008FB1001C8FB0001803E0000827BD004029 +:108590008F86003C36110E0000072E0000A6202515 +:1085A000AE0400808E4300208E500024AFA3001044 +:1085B000AE2300148FB20010AE320010AE30001C9B +:1085C0000A000A75AE3000180200F8090000000029 +:1085D0008EE4000C0080F809000000000A000B2E59 +:1085E0008FBF003824180001240F0001A5C000200F +:1085F000A5D800220A000B10ADCF00243C010800D2 +:10860000AC203FB80A000AA68E6200003C010800B8 +:10861000AC253FB80A000AA68E6200009224000929 +:108620000E000771000028218FBF00388FB700347B +:108630008FB600308FB5002C8FB400288FB3002484 +:108640008FB200208FB1001C8FB0001803E000082B +:1086500027BD00403C1480009295010900002821AC +:108660000E00084332A400FF320300105060FFB830 +:10867000320800408EE5000400A0F8090000000068 +:108680000A000B28320800405240FFA89793005878 +:108690008E3400148F930044AE7400208E35001C7D +:1086A000AE7500240A000B1F979300588F820014A8 +:1086B0000004218003E00008008210213C078008AC +:1086C00034E200809043006900804021106000097E +:1086D0003C0401003C0708008CE73FDC8F8300303E +:1086E00000E32023048000089389001C14E30003A6 +:1086F0000100202103E00008008010213C0401005B +:1087000003E00008008010211120000B00673823CF +:108710003C0D800035AC0980918B007C316A0002F1 +:10872000114000202409003400E9702B15C0FFF12E +:108730000100202100E938232403FFFC00A3C82402 +:1087400000E3C02400F9782B15E0FFEA030820219C +:1087500030C400030004102314C000143049000387 +:108760000000302100A9782101E6702100EE682B7D +:1087700011A0FFE03C0401002D3800010006C82BC9 +:10878000010548210319382414E0FFDA2524FFFCF1 +:108790002402FFFC00A218240068202103E0000846 +:1087A000008010210A000B9E240900303C0C800040 +:1087B0003586098090CB007C316A00041540FFE9C2 +:1087C000240600040A000BAD000030213C03080021 +:1087D0008C63005C8F82001827BDFFE0AFBF0018DC +:1087E000AFB1001410620005AFB00010000329C043 +:1087F00024A40280AF840014AF8300183C108000D2 +:1088000036020A0094450032361101000E000B7F3B +:1088100030A43FFF8E240000241FFF803C11008005 +:108820000082C021031F60243309007F000CC9406F +:1088300003294025330E0078362F00033C0D10002D +:10884000010D502501CF5825AE0C002836080980AF +:10885000AE0C080CAE0B082CAE0A08309103006970 +:108860003C06800C0126382110600006AF870034DA +:108870008D09003C8D03006C0123382318E0008231 +:10888000000000003C0B8008356A00803C1080002E +:10889000A1400069360609808CC200383C06800081 +:1088A00034C50A0090A8003C310C00201180001A49 +:1088B000AF820030240D00013C0E800035D10A004B +:1088C000A38D001CAF8000248E2400248F850024FB +:1088D000240D0008AF800020AF8000283C01080074 +:1088E000A42D3FC63C010800A4203FDA0E000B83F4 +:1088F000000030219228003C8FBF00188FB1001477 +:108900008FB0001000086142AF82002C27BD00200C +:1089100003E000083182000190B80032240E00010B +:10892000330F00FF000F2182108E00412419000236 +:108930001099006434C40AC03C03800034640A0007 +:108940008C8F002415E0001E34660900909F0030D3 +:108950002418000533F9003F1338004E24030001AA +:108960008F860020A383001CAF860028AF860024DA +:108970003C0E800035D10A008E2400248F8500240F +:10898000240D00083C010800A42D3FC63C0108004E +:10899000A4203FDA0E000B83000000009228003C68 +:1089A0008FBF00188FB100148FB000100008614213 +:1089B000AF82002C27BD002003E0000831820001B7 +:1089C0008C8A00088C8B00248CD000643C0E8000C4 +:1089D00035D10A00014B2823AF900024A380001C4E +:1089E000AF8500288E2400248F8600208F850024E8 +:1089F000240D00083C010800A42D3FC63C010800DE +:108A0000A4203FDA0E000B83000000009228003CF7 +:108A10008FBF00188FB100148FB0001000086142A2 +:108A2000AF82002C27BD002003E000083182000146 +:108A300090A200303051003F5224002834C50AC0B3 +:108A40008CB000241600002234CB09008CA600480C +:108A50003C0A7FFF3545FFFF00C510243C0E800017 +:108A6000AF82002035C509008F8800208CAD0060E2 +:108A7000010D602B15800002010020218CA40060F4 +:108A80000A000C22AF8400208D02006C0A000BFC4F +:108A90003C0680008C8200488F8600203C097FFFC6 +:108AA0003527FFFF004788243C0480082403000189 +:108AB000AF910028AC80006CA383001C0A000C302E +:108AC000AF8600248C9F00140A000C22AF9F002068 +:108AD0008D6200680A000C6C3C0E800034C4098072 +:108AE0008C8900708CA300140123382B10E0000443 +:108AF000000000008C8200700A000C6C3C0E8000AC +:108B00008CA200140A000C6C3C0E80008F8500249F +:108B100027BDFFE0AFBF0018AFB1001414A00008DC +:108B2000AFB000103C04800034870A0090E60030AB +:108B30002402000530C3003F106200B934840900EC +:108B40008F91002000A080213C048000348E0A0018 +:108B50008DCD00043C0608008CC63FB831A73FFF0E +:108B600000E6602B5580000100E03021938F001C4F +:108B700011E0007800D0282B349F098093F9007C05 +:108B800033380002130000792403003400C3102B93 +:108B9000144000D90000000000C3302300D0282B6F +:108BA0003C010800A4233FC414A0006E0200182159 +:108BB0003C0408008C843FB40064402B5500000145 +:108BC000006020213C05800034A90A00912A003C65 +:108BD0003C010800AC243FBC31430020146000037A +:108BE0000000482134AB0E008D6900188F88002CDE +:108BF0000128202B1080005F000000003C050800C9 +:108C00008CA53FBC00A96821010D602B1180005C80 +:108C100000B0702B0109382300E028213C01080036 +:108C2000AC273FBC12000003240AFFFC10B0008DEB +:108C30003224000300AA18243C010800A4203FDAD3 +:108C40003C010800AC233FBC006028218F84002435 +:108C5000120400063C0B80088D6C006C0200202181 +:108C6000AF91002025900001AD70006C8F8D002821 +:108C700000858823AF91002401A52023AF8400281C +:108C80001220000224070018240700103C18800856 +:108C90003706008090CF00683C010800A0273FD82D +:108CA0002407000131EE00FF11C70047000000005B +:108CB00014800018000028213C06800034D109806F +:108CC00034CD010091A600098E2C001824C40001A7 +:108CD000000C86023205007F308B007F1165007F1B +:108CE0002407FF803C19800837290080A124004C0C +:108CF0003C0808008D083FD4241800023C010800FD +:108D0000A0384019350F00083C010800AC2F3FD4B3 +:108D1000240500103C02800034440A009083003C8B +:108D2000307F002013E0000500A02021240A00016C +:108D30003C010800AC2A3FBC34A400018FBF0018DE +:108D40008FB100148FB000100080102103E00008E4 +:108D500027BD00203C010800A4203FC410A0FF94C0 +:108D6000020018210A000CC000C018210A000CB72C +:108D7000240300303C0508008CA53FBC00B0702BDC +:108D800011C0FFA8000000003C19080097393FC43B +:108D90000325C0210307782B11E000072CAA00044B +:108DA0003C0360008C625404305F003F17E0FFE337 +:108DB000240400422CAA00041140FF9A240400421B +:108DC0000A000D248FBF00181528FFB9000000000D +:108DD0008CCA00183C1F800024020002015F182585 +:108DE000ACC3001837F90A00A0C200689329003C00 +:108DF0002404000400A01021312800203C010800B8 +:108E0000A0244019110000022405001024020001D2 +:108E10003C010800AC223FB40A000D1A3C0280005D +:108E20008F8800288C8900600109282B14A000027B +:108E3000010088218C9100603C048000348B0E007E +:108E40008D640018240A000102202821022030210C +:108E5000A38A001C0E000B83022080210A000CA6AE +:108E6000AF82002C00045823122000073164000355 +:108E70003C0E800035C7098090ED007C31AC0004C9 +:108E800015800019248F00043C010800A4243FDA57 +:108E90003C1F080097FF3FDA03E5C82100D9C02B2B +:108EA0001300FF6B8F8400242CA6000514C0FFA3C1 +:108EB0002404004230A200031440000200A2182340 +:108EC00024A3FFFC3C010800AC233FBC3C0108008C +:108ED000A4203FDA0A000CE70060282100C77024B4 +:108EE0000A000D0D01C720263C010800A42F3FDA1F +:108EF0000A000D78000000003C010800AC203FBCD7 +:108F00000A000D23240400428F8300283C058000C2 +:108F100034AA0A00146000060000102191470030B6 +:108F20002406000530E400FF108600030000000066 +:108F300003E0000800000000914B0048316900FF89 +:108F4000000941C21500FFFA3C0680083C040800F5 +:108F500094843FC43C0308008C633FDC3C19080048 +:108F60008F393FBC3C0F080095EF3FDA0064C02109 +:108F70008CCD00040319702101CF602134AB0E00A9 +:108F8000018D282318A0001D00000000914F004C07 +:108F90008F8C0034956D001031EE00FF8D89000438 +:108FA00001AE30238D8A000030CEFFFF000E290075 +:108FB0000125C82100003821014720210325182B55 +:108FC0000083C021AD990004AD980000918F000A84 +:108FD00001CF6821A18D000A956500128F8A0034A7 +:108FE000A5450008954B003825690001A5490038C2 +:108FF0009148000D35070008A147000D03E0000867 +:109000000000000027BDFFD8AFB000189388001CF7 +:109010008FB000143C0A80003C197FFF8F8700242A +:109020003738FFFFAFBF0020AFB1001C355F0A002B +:109030000218182493EB003C00087FC03C02BFFFDD +:10904000006F60252CF000013449FFFF3C1F080031 +:109050008FFF3FDC8F9900303C18080097183FD2F3 +:1090600001897824001047803C07EFFF3C05F0FFA2 +:1090700001E818253C1180003169002034E2FFFF2F +:1090800034ADFFFF362E098027A50010240600020C +:1090900003F96023270B0002354A0E0000621824F2 +:1090A0000080802115200002000040218D48001C16 +:1090B000A7AB0012058000392407000030E800FF4C +:1090C00000083F00006758253C028008AFAB001441 +:1090D000344F008091EA00683C08080091083FD9AD +:1090E0003C09DFFF352CFFFF000AF82B3C0208008B +:1090F00094423FCCA3A80011016CC024001FCF40B4 +:10910000031918258FA70010AFA300143C0C08000A +:10911000918C3FDBA7A200168FAB001400ED482412 +:109120003C0F01003C0A0FFF012FC82531980003B6 +:10913000355FFFFF016D40243C027000033F38247F +:1091400000181E0000E2482501037825AFAF001487 +:10915000AFA9001091CC007C0E000092A3AC0015CA +:10916000362D0A0091A6003C30C400201080000675 +:10917000260200083C11080096313FC8262EFFFF4A +:109180003C010800A42E3FC88FBF00208FB1001CF7 +:109190008FB0001803E0000827BD00288F8B002C3B +:1091A000010B502B5540FFC5240700010A000E0497 +:1091B00030E800FF9383001C3C02800027BDFFD8ED +:1091C00034480A0000805021AFBF002034460AC056 +:1091D000010028211060000E3444098091070030FE +:1091E000240B00058F89002030EC003F118B000B11 +:1091F00000003821AFA900103C0B80088D69006C7D +:10920000AFAA00180E00015AAFA90014A380001CD9 +:109210008FBF002003E0000827BD00288D1F0048F5 +:109220003C1808008F183FBC8F9900283C027FFF34 +:109230008D0800443443FFFFAFA900103C0B8008A9 +:109240008D69006C03E370240319782101CF682332 +:1092500001A83821AFAA00180E00015AAFA90014C6 +:109260000A000E58A380001C3C05800034A60A00AA +:1092700090C7003C3C06080094C63FDA3C02080058 +:109280008C423FD430E30020000624001060001E12 +:10929000004438253C0880083505008090A300680C +:1092A00000004821240800010000282124040001B6 +:1092B0003C0680008CCD017805A0FFFE34CF014034 +:1092C000ADE800083C0208008C423FDCA5E5000444 +:1092D000A5E40006ADE2000C3C04080090843FD9F0 +:1092E0003C03800834790080A1E40012ADE700144B +:1092F000A5E900189338004C3C0E1000A1F8002D91 +:1093000003E00008ACCE017834A90E008D28001CC3 +:109310003C0C08008D8C3FBC952B0016952A001440 +:10932000018648213164FFFF0A000E803145FFFFAE +:109330003C04800034830A009065003C30A2002089 +:109340001040001934870E00000040210000382131 +:10935000000020213C0680008CC901780520FFFE1A +:1093600034CA014034CF010091EB0009AD48000838 +:109370003C0E08008DCE3FDC240DFF91240C0040F4 +:109380003C081000A5440004A5470006AD4E000CA3 +:10939000A14D0012AD4C0014A5400018A14B002DAA +:1093A00003E00008ACC801788CE8001894E60012CD +:1093B00094E4001030C7FFFF0A000EA93084FFFFBD +:1093C0003C04800034830A009065003C30A20020F9 +:1093D0001040002727BDFFF82409000100003821B4 +:1093E000240800013C0680008CCA01780540FFFE7D +:1093F0003C0280FF34C40100908D00093C0C080041 +:10940000918C4019A3AD00038FAB00003185007F24 +:109410003459FFFF01665025AFAA00009083000A6F +:10942000A3A0000200057E00A3A300018FB80000E6 +:1094300034CB0140240C30000319702401CF68257F +:10944000AD6D000C27BD0008AD6C0014A5600018C0 +:10945000AD690008A56700042409FF80A56800061F +:109460003C081000A169001203E00008ACC80178B4 +:1094700034870E008CE9001894E6001294E4001082 +:1094800030C8FFFF0A000ECD3087FFFF27BDFFE089 +:10949000AFB100143C118000AFB00010AFBF001896 +:1094A00036380A00970F0032363001000E000B7F6D +:1094B00031E43FFF8E0E0000240DFF803C042000AD +:1094C00001C25821016D6024000C4940316A007FBF +:1094D000012A4025010438253C048008AE270830C5 +:1094E0003486008090C500682403000230A200FF8B +:1094F000104300048F9F00208F990024AC9F0068C8 +:10950000AC9900648FBF00188FB100148FB00010A9 +:1095100003E0000827BD00203C0A0800254A3A80E5 +:109520003C09080025293B103C08080025082F1C91 +:109530003C07080024E73BDC3C06080024C639044D +:109540003C05080024A536583C0408002484325CFD +:109550003C030800246339B83C0208002442375415 +:109560003C010800AC2A3F983C010800AC293F941C +:109570003C010800AC283F903C010800AC273F9C10 +:109580003C010800AC263FAC3C010800AC253FA4E0 +:109590003C010800AC243FA03C010800AC233FB0D4 +:1095A0003C010800AC223FA803E0000800000000D6 +:1095B00080000940800009008008010080080080C8 +:1095C00080080000800E00008008008080080000F5 +:1095D00080000A8080000A00800009808000090065 +:00000001FF --- linux-3.13.0.orig/firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex +++ linux-3.13.0/firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex @@ -3,8 +3,7 @@ :1000200000000000000000000000000000000000D0 :1000300000001010000009C80000000500000000CA :1000400000000000000000000000000000000000B0 -:080050000000000000000000A8 -:0800580000000010B180000659 +:10005000000000000000000000000010B180000659 :100060000000001F03060011000000080500FFFF4C :10007000000000180002000000000008050000FF5A :10008000000000180002000000000008AC000001A1 @@ -155,8 +154,7 @@ :100990000000001091D40000000000080500005580 :1009A000000000188000FF360000000C29800001C4 :1009B0000000000C1F800001000000082A00000752 -:0809C000000000188000FEDEBB -:0809C80000000010B1800004E2 +:1009C000000000188000FEDE00000010B18000046E :1009D0000000001F0306001100000008050000FFD2 :1009E0000000001800020000000000002A000000C3 :1009F00000000010B1D400000000001091DE0000E3 @@ -415,11 +413,3 @@ :1019C00000000010001F00000000000C6BD7000199 :0819D000000000188000FE0475 :00000001FF -/* - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - */ --- linux-3.13.0.orig/firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex +++ linux-3.13.0/firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex @@ -3,8 +3,7 @@ :1000200000000000000000000000000000000000D0 :1000300000000E88000009500000000500000000CC :1000400000000000000000000000000000000000B0 -:080050000000000000000000A8 -:0800580000000010B180000659 +:10005000000000000000000000000010B180000659 :100060000000001F05060011000000080500FFFF4A :10007000000000180002000000000008050000FF5A :10008000000000180002000000000008AC000001A1 @@ -382,11 +381,3 @@ :1017C0000000000C2980000000000010001F000035 :0817D000000000188000FE3546 :00000001FF -/* - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - */ --- linux-3.13.0.orig/firmware/bnx2x/bnx2x-e1-7.8.17.0.fw.ihex +++ linux-3.13.0/firmware/bnx2x/bnx2x-e1-7.8.17.0.fw.ihex @@ -0,0 +1,10227 @@ +:100000000000164800000068000005D8000016B87F +:10001000000031CC00001C980000006C00004E680D +:100020000000825400004ED80000009C0000D13037 +:10003000000095340000D1D000000088000167085E +:1000400000004294000167980000008C0001AA3073 +:100050000000C2600001AAC0000011C400026D28A7 +:100060000000000400027EF0020600DC0000000137 +:100070000306100002000000010600D80000000086 +:100080000306020000030200020600DC000000007C +:1000900002060068000000B80206007800000114A3 +:1000A000010600B800000000010600C800000000C2 +:1000B0000206006C000000B80206007C000001147B +:1000C000010600BC00000000010600CC000000009A +:1000D000020D004400000032030D004C0004020336 +:1000E000040D005C00000004030D008C00110207E9 +:1000F000020D015C00000001030D01640002021802 +:10010000020D020400000001030D020C0003021A9C +:10011000030D02200002021D040D028000000012E7 +:10012000030D03000018021F040D03600000000C03 +:10013000040D400000000A00030D0004000F023708 +:10014000020D01140000000D020D01180000002D29 +:100150000310100000030246021010100000026499 +:10016000071011000010024908101140000000089B +:100170000710116000100259081011A000000018AB +:1001800007101800020002690210101000000000A1 +:1001900004104C0000000100021040280000001074 +:1001A0000210404400003FFF0210405800280000A9 +:1001B000021040840084924A02104058000000005F +:1001C000030C200800030469030C201C0004046CC9 +:1001D000030C203800110470040C207C0000004F38 +:1001E000030C21B800110481040C21FC0000000F55 +:1001F000030C223800040492010C22480000000085 +:10020000010C224C00000000010C225000000000F4 +:10021000010C225400000000010C225800000000D4 +:10022000010C225C00000000010C226000000000B4 +:10023000010C226400000000010C22680000000094 +:10024000010C226C00000000010C22700000000074 +:10025000010C227400000000010C22780000000054 +:10026000010C227C00000000020C24BC00000001F4 +:100270000A00000100000001020C2000000003E859 +:100280000A00000100000002020C20000000000A29 +:100290000A00000100000004020C20000000000120 +:1002A0000520040000850000062007800010049649 +:1002B000042200000000160004228000000000401C +:1002C00004223BD000000008042248000000000681 +:1002D0000322481800040498042248280000000C57 +:1002E000032248580004049C042248680000000CC3 +:1002F00003224898000404A0042248A80000000C2F +:10030000032248D8000404A4042248E80000000C9A +:1003100003224918000404A8042249280000000C04 +:1003200003224958000404AC042249680000000C70 +:1003300003224998000404B0042249A80000000CDC +:10034000032249D8000404B4042249E80000000C48 +:1003500003224A18000404B804224A280000000CB2 +:1003600003224A58000404BC04224A680000000C1E +:1003700003224A98000404C004224AA80000000C8A +:1003800003224AD8000404C404224AE80000000CF6 +:1003900003224B18000404C804224B280000000C60 +:1003A00003224B58000404CC04224B680000000CCC +:1003B00003224B98000404D004224BA80000000C38 +:1003C00003224BD8000404D404224BE80000000CA4 +:1003D00003224C18000404D804224C280000000C0E +:1003E00003224C58000404DC04224C680000000C7A +:1003F00003224C98000404E004224CA80000000CE6 +:1004000003224CD8000404E404224CE80000000C51 +:1004100003224D18000404E804224D280000000CBB +:1004200003224D58000404EC04224D680000000C27 +:1004300003224D98000404F004224DA80000000C93 +:1004400003224DD8000404F404224DE80000000CFF +:1004500003224E18000404F804224E280000000C69 +:1004600003224E58000404FC04224E680000000CD5 +:1004700003224E980004050004224EA80000000C40 +:1004800003224ED80004050404224EE80000000CAC +:1004900003224F180004050804224F280000000C16 +:1004A00003224F580004050C04224F680000000C82 +:1004B00003224F980004051004224FA80000000CEE +:1004C00003224FD80004051404224FE80000000660 +:1004D0000322519800040518022380000000001038 +:1004E00002238040000000120223808000000030C0 +:1004F000022380C00000000E022383800007A12099 +:10050000022383C0000001F402238BC0000000011D +:100510000A00000200000001022383000007A1205E +:1005200002238340000001F40A00000200000002E0 +:10053000022383000000138802238340000000058B +:100540000A000002000000040223830000000138BA +:10055000022383400000000005240000334D00000A +:10056000052480000F430CD406249CC06ACE051CD1 +:100570000120000000000000012000040000000035 +:1005800001200008000000000120000C0000000015 +:1005900001200010000000000120001400000000F5 +:1005A00003200020001A051E032000A400020538C5 +:1005B000022002240000000002200234000000009B +:1005C0000220024C00000000022002E40000FFFFB5 +:1005D000082020000000080004221400000000028F +:1005E00004221490000000300422390000000010A2 +:1005F0000422510800000002042251A80000000655 +:1006000004221408000000020422155000000030EB +:1006100004223940000000100422511000000002A2 +:10062000042251C00000000604102400000000E075 +:100630000310201C0002053A021020C00000000137 +:10064000031020040002053C02170008000000020D +:100650000217002C00000003031700380002053EBB +:100660000317004400060540031700600005054617 +:10067000031700780002054B021700040000000F6A +:100680000410806800000004021080000000108048 +:1006900004108040000000020410802800000002C6 +:1006A0000210803800000010031080400002054D49 +:1006B00002108050000000000210810000000000C5 +:1006C000041081200000000202108008000002B522 +:1006D0000210801000000000021081080001FFFFDE +:1006E000041082000000004A041081400000000253 +:1006F0000210800000001A80041090000000002406 +:10070000041091200000004A041093700000004A79 +:10071000041095C00000004A021080040000108000 +:100720000410804800000002041080300000000225 +:100730000210803C00000010031080480002054FAA +:10074000021080540000000002108104000000002C +:1007500004108128000000020210800C000002B585 +:1007600002108014000000000210810C0001FFFF45 +:10077000041084000000004A0410814800000002B8 +:100780000210800400001A800410909000000024E1 +:10079000041092480000004A041094980000004A97 +:1007A000041096E80000004A0200A468000AFFDC7A +:1007B0000200A280000000010300A2940004055181 +:1007C0000200A4FCFF000000030100B40002055574 +:1007D000020100DC000000010301010000020557D6 +:1007E0000201007C003000000201008400000028AB +:1007F0000201008C00000000020101300000000432 +:10080000040101380000001102010328000000006B +:100810000201055400000030020100C40000000184 +:10082000020100CC00000001020100F800000001FC +:10083000020100F000000001020100800030000011 +:100840000201008800000028020100900000000062 +:1008500002010134000000040401017C00000011C9 +:100860000201032C000000000201056400000030BA +:10087000020100C800000001020100D000000001D8 +:10088000020100FC00000001020100F40000000170 +:1008900002140000000000010214000C000000011E +:1008A00003140040000205590214000C000000006F +:1008B00002140000000000000214006C00000000A0 +:1008C00002140004000000010214003000000001C6 +:1008D00002140004000000000214005C000000008C +:1008E000021400080000000102140034000000019E +:1008F0000214000800000000021400600000000064 +:10090000030400040012055B030400540003056D9A +:100910000204007000000004030400780004057065 +:1009200004040088000000050304009C0003057413 +:10093000040400A800000004030400B800050577C3 +:10094000040400CC00000004030400DC0004057C67 +:10095000040400EC00000004010401240000000075 +:1009600001040128000000000104012C0000000027 +:100970000104013000000000020401340000000FF7 +:1009800003120490002205800212052000000002DC +:1009900002120388000000640212039000000008A5 +:1009A0000312039C000305A2021203BC0000000412 +:1009B000021203C400000004021203D00000000071 +:1009C000021203DC000000000212036C00000001B0 +:1009D000021203680000003F031201BC003C05A5A1 +:1009E000031202B0000205E103120324000205E332 +:1009F000021201B00000000107103800000505E5F3 +:100A000007103C00000505EA07103C20000505EF33 +:100A100003168030000805F402168054000000021E +:100A200003168060000505FC0416807400000007B2 +:100A300003168090000206010316809C0005060341 +:100A4000041680B000000007031680CC00080608DA +:100A5000021680F000000007041680F40000000C6D +:100A60000316812400040610041681340000000CD3 +:100A700003168164003B0614041682500000000433 +:100A8000031682600002064F041682680000000808 +:100A90000316828800080651041682A80000000A86 +:100AA00002168804000000040316880C0010065982 +:100AB000021680EC000000FF03040408001406691D +:100AC000030500440002067D030500500004067F74 +:100AD0000405006000000004030500900013068375 +:100AE00002050114000000010305011C0002069626 +:100AF00002050204000000010305020C0002069832 +:100B00000305021C0003069A040502400000000AC7 +:100B1000030502800020069D0405400000000D0032 +:100B200003050004001006BD020500E00000000EF1 +:100B3000020500E40000002E04164024000000021C +:100B400003164030000306CD02164044000000208A +:100B5000021640700000001C02164208000000014E +:100B6000021642100000000102164220000000019F +:100B70000216422800000001021642300000000167 +:100B80000216423800000001021642600000000117 +:100B90000A000001000000010216401C0003D09072 +:100BA0000A000001000000020216401C000009C4F7 +:100BB0000A000001000000040216401C0000009C16 +:100BC0000216400000000001021640D8000000019B +:100BD00003164008000306D0021642400000000041 +:100BE0000216424800000000081642700000000291 +:100BF0000216425000000000021642580000000099 +:100C0000081642800000000203042008000406D3F6 +:100C10000304201C000406D70404203800000080D0 +:100C200003042238000406DB01042248000000000F +:100C30000104224C000000000104225000000000CA +:100C400001042254000000000104225800000000AA +:100C50000104225C0000000001042260000000008A +:100C6000010422640000000001042268000000006A +:100C70000104226C0000000001042270000000004A +:100C8000010422740000000001042278000000002A +:100C90000104227C00000000020424BC00000001CA +:100CA0000A0000010000000102042000000003E827 +:100CB0000A00000100000002020420000000000AF7 +:100CC0000A000001000000040204200000000001EE +:100CD00005180400006A000006180760001406DF0B +:100CE000041A000000001600041A800000000040F2 +:100CF000031A08B0000206E1031A19C8000206E34D +:100D0000031A2FC0000406E5041A2FD000000006C5 +:100D1000031A2FE8000206E9031A300003F906EB74 +:100D2000041A3FE400000007031A487000040AE4B4 +:100D3000021B800000000034021B804000000018ED +:100D4000021B80800000000C021B80C000000020FD +:100D5000021B83800007A120021B83C0000001F456 +:100D6000021B8BC0000000010A000002000000010D +:100D7000021B83000007A120021B8340000001F436 +:100D80000A00000200000002021B8300000013881A +:100D9000021B8340000000050A000002000000045E +:100DA000021B830000000138021B8340000000008A +:100DB000051C00002D020000051C800034240B419E +:100DC000051D0000212A184A061D4D5056560AE8F6 +:100DD00001180000000000000118000400000000DD +:100DE00001180008000000000118000C00000000BD +:100DF000011800100000000001180014000000009D +:100E000003180020001A0AEA031800A400020B04C9 +:100E10000218022400000000021802340000000042 +:100E20000218024C00000000021802E4000000FF5B +:100E30000818100000000400041A08000000000256 +:100E4000041A082000000012041A09C0000000481B +:100E5000041A250000000010041A2580000000126A +:100E6000041A261000000012031A2FB000020B060D +:100E7000041A400000000006041A4030000000027E +:100E8000041A482000000002031A4C5000020B080C +:100E9000041A081000000002041A0868000000127A +:100EA000041A0AE000000048041A2540000000105F +:100EB000041A25C800000012041A26580000001267 +:100EC000031A2FB800020B0A041A4018000000068B +:100ED000041A403800000002041A482800000002EA +:100EE000031A4C5800020B0C020E004C000000329A +:100EF000030E005400040B0E040E006400000004F6 +:100F0000030E009400130B12020E014400000001B6 +:100F1000030E014C00020B25020E0204000000012A +:100F2000030E020C00020B27030E021C00040B2907 +:100F3000030E0280001B0B2D040E02EC00000017B4 +:100F4000040E200000000800030E000400110B48EE +:100F5000020E01100000000F020E01140000002F0D +:100F6000020C100000000028030C400800040B597C +:100F7000030C401C00040B5D030C403800020B61A5 +:100F8000040C40400000005E020C41B8000000016B +:100F9000040C41BC0000001F030C423800040B632A +:100FA000010C424800000000010C424C000000000F +:100FB000010C425000000000010C425400000000EF +:100FC000010C425800000000010C425C00000000CF +:100FD000010C426000000000010C426400000000AF +:100FE000010C426800000000010C426C000000008F +:100FF000010C427000000000010C4274000000006F +:10100000010C427800000000010C427C000000004E +:10101000010C428000000000020C44C000000001EE +:101020000A00000100000001020C4000000003E87B +:101030000A00000100000002020C40000000000A4B +:101040000A00000100000004020C40000000000142 +:1010500005300400009C00000630076800130B6791 +:10106000043200000000160004328000000000403E +:101070000332183000020B6903322E7000040B6B30 +:101080000432508000000008033250A000020B6FB1 +:10109000023380000000001A023380400000004E3E +:1010A0000233808000000010023380C00000002066 +:1010B000023383800007A120023383C0000001F4C3 +:1010C00002338BC0000000010A0000020000000192 +:1010D000023383000007A12002338340000001F4A3 +:1010E0000A0000020000000202338300000013889F +:1010F00002338340000000050A00000200000004E3 +:1011000002338300000001380233834000000000F6 +:101110000534000036E200000534800031DA0DB9F4 +:10112000053500002C721A300635644053780B7177 +:101130000130000000000000013000040000000049 +:1011400001300008000000000130000C0000000029 +:101150000130001000000000013000140000000009 +:1011600003300020001A0B73033000A400020B8D23 +:1011700002300224000000000230023400000000AF +:101180000230024C00000000023002E40000FFFFC9 +:10119000083020000000080004322DE000000002AA +:1011A00004324000000000D8043246C00000012094 +:1011B000043250C80000002404322DE80000000270 +:1011C00004324360000000D804324B40000001208C +:1011D000043251580000002402020058000000327E +:1011E0000302006000040B8F040200700000000482 +:1011F000030200A0000E0B93030200DC00070BA10A +:10120000020200FC000000060202012000000000B3 +:101210000202013400000002020201B000000001DD +:101220000202020C000000010302021400020BA8DB +:1012300002020404000000010302040C00020BAAD5 +:101240000302041C00040BAC03020480001F0BB05B +:10125000040204FC000000130402800000002000CF +:101260000302000400140BCF02020108000000C8B2 +:101270000202011800000002020201C40000000086 +:10128000020201CC00000000020201D400000002B2 +:10129000020201DC00000002020201E4000000FF83 +:1012A000020201EC000000FF0202010C000000C875 +:1012B0000202011C00000002020201C8000000003E +:1012C000020201D000000000020201D8000000026A +:1012D000020201E000000002020201E8000000FF3B +:1012E000020201F0000000FF0216100000000028BA +:1012F0000316600800030BE30316601C00040BE6F2 +:1013000003166038000D0BEA0416606C0000001331 +:10131000031660B800020BF7041660C00000003E20 +:10132000021661B800000001041661BC0000001F35 +:101330000316623800040BF9011662480000000031 +:101340000116624C0000000001166250000000000F +:1013500001166254000000000116625800000000EF +:101360000116625C000000000116626000000000CF +:1013700001166264000000000116626800000000AF +:101380000116626C0000000001166270000000008F +:10139000011662740000000001166278000000006F +:1013A0000116627C00000000021664BC000000010F +:1013B0000A0000010000000102166000000003E8BE +:1013C0000A00000100000002021660000000000A8E +:1013D0000A00000100000004021660000000000185 +:1013E00005280400008A00000628076800130BFD8A +:1013F000042A000000001600042A800000000040BB +:10140000032A250000020BFF032A296000040C01B7 +:10141000032A2F4800020C05032A336800020C0738 +:10142000032A392000020C09032A393000020C0B70 +:10143000032A3AC800020C0D042A3AD00000000624 +:10144000032A3B9800020C0F032A3C2000040C11D5 +:10145000022A3CD000000000022B800000000000A7 +:10146000022B804000000018022B80800000000C3E +:10147000022B80C000000066022B83800007A120A1 +:10148000022B83C0000001F4022B8BC0000000017E +:101490000A00000200000001022B83000007A120C7 +:1014A000022B8340000001F40A0000020000000249 +:1014B000022B830000001388022B834000000005EC +:1014C0000A00000200000004022B83000000013823 +:1014D000022B8340000000000A00000100000020F1 +:1014E000022A3CD400000000052C000036700000E9 +:1014F000052C800039BD0D9C052D00003ADB1C0C2D +:10150000052D800017512AC3062DAF704A120C1505 +:101510000128000000000000012800040000000075 +:1015200001280008000000000128000C0000000055 +:101530000128001000000000012800140000000035 +:1015400003280020001A0C17032800A400020C3105 +:1015500002280224000000000228023400000000DB +:101560000228024C00000000022802E40000FFFFF5 +:101570000828200000000800042A3910000000029A +:10158000042A393800000020042A3A3800000010EC +:10159000032A3AE800020C33032A3AF800100C350B +:1015A000042A3C3000000002042A5000000000021F +:1015B000042A501000000002042A502000000002FB +:1015C000042A503000000002022A504000000000AF +:1015D000042A50480000000E042A391800000002B6 +:1015E000042A39B800000020042A3A7800000010CC +:1015F000032A3AF000020C45032A3B3800100C473E +:10160000042A3C3800000002042A500800000002AE +:10161000042A501800000002042A5028000000028A +:10162000042A503800000002022A50440000000042 +:10163000042A50800000000E0400A00000000016E4 +:101640000300A06C00060C570400A08400000005F5 +:101650000200A0980FE000000400A09C000000140D +:101660000300A0EC00080C5D0400A22C00000004A4 +:101670000200A060000003070300A10C00060C6537 +:101680000400A124000000050200A1380FE00000C2 +:101690000400A13C000000140300A18C00080C6BA6 +:1016A0000400A23C000000040200A0640000030744 +:1016B000000000000000000000000000000000002A +:1016C000000000000000000000000000000000001A +:1016D000000000000000000000000000000000000A +:1016E0000000000000000005000500090009000DD1 +:1016F00000000000000000000000000000000000EA +:1017000000000000000000000000000000000000D9 +:10171000000D001B001B001C001C001D0000000031 +:1017200000000000000000000000000000000000B9 +:10173000000000000000000000000000001D002567 +:101740000000000000000000000000000000000099 +:101750000000000000000000000000000000000089 +:1017600000000000000000000025002B0000000029 +:101770000000000000000000000000000000000069 +:101780000000000000000000000000000000000059 +:1017900000000000002B00470000000000000000D7 +:1017A0000000000000000000000000000000000039 +:1017B0000000000000000000000000000000000029 +:1017C000004700AE00AE00B300B300B80000000058 +:1017D0000000000000000000000000000000000009 +:1017E00000000000000000000000000000000000F9 +:1017F00000000000000000000000000000000000E9 +:1018000000000000000000000000000000000000D8 +:10181000000000000000000000B800BC0000000054 +:1018200000000000000000000000000000000000B8 +:1018300000000000000000000000000000000000A8 +:101840000000000000BC00C3000000000000000019 +:101850000000000000000000000000000000000088 +:101860000000000000000000000000000000000078 +:1018700000C300C400C400D600D600E80000000089 +:101880000000000000000000000000000000000058 +:101890000000000000000000000000000000000048 +:1018A0000000000000000000000000000000000038 +:1018B0000000000000000000000000000000000028 +:1018C000000000000000000000E800EC0000000044 +:1018D0000000000000000000000000000000000008 +:1018E00000000000000000000000000000000000F8 +:1018F0000000000000EC00EF00EF00FA00FA010524 +:1019000000000000000000000000000000000000D7 +:1019100000000000000000000000000000000000C7 +:101920000105010B010B010F010F01130000000065 +:1019300000000000000000000000000000000000A7 +:101940000000000000000000000000000000000097 +:101950000000000000000000000000000000000087 +:101960000000000000000000000000000000000077 +:10197000000000000000000001130123000000002F +:101980000000000000000000000000000000000057 +:101990000000000000000000000000000000000047 +:1019A00000000000012301320000000000000000E0 +:1019B0000000000000000000000000000000000027 +:1019C0000000000000000000000000000000000017 +:1019D000013201350000000000000000000000009E +:1019E00000000000000000000000000000000000F7 +:1019F0000000000000000000000000000135014A66 +:101A000000000000000000000000000000000000D6 +:101A100000000000000000000000000000000000C6 +:101A20000000000000000000014A014B000000001F +:101A300000000000000000000000000000000000A6 +:101A40000000000000000000000000000000000096 +:101A500000000000014B0158015801590159015A79 +:101A60000000000000000000000000000000000076 +:101A70000000000000000000000000000000000066 +:101A8000015A016E016E01710171017400000000C4 +:101A90000000000000000000000000000000000046 +:101AA0000000000000000000000000000174018D33 +:101AB0000000000000000000000000000000000026 +:101AC0000000000000000000000000000000000016 +:101AD0000000000000000000018D01BA01BA01C53C +:101AE00001C501D00000000000000000000000005F +:101AF00000000000000000000000000000000000E6 +:101B00000000000001D001DD01DD01DE01DE01DFAA +:101B100000000000000000000000000000000000C5 +:101B200000000000000000000000000000000000B5 +:101B300001DF01E0000000000000000000000000E4 +:101B40000000000000000000000000000000000095 +:101B500000000000000000000000000001E001FDA6 +:101B60000000000000000000000000000000000075 +:101B70000000000000000000000000000000000065 +:101B8000000000000000000001FD02260226022ADB +:101B9000022A022E000000000000000000000000E9 +:101BA0000000000000000000000000000000000035 +:101BB00000000000022E024002400248024802508B +:101BC0000000000000000000000000000000000015 +:101BD0000000000000000000000000000000000005 +:101BE0000250025100000000000000000000000050 +:101BF00000000000000000000000000000000000E5 +:101C00000000000000000000000000000251026F10 +:101C100000000000000000000000000000000000C4 +:101C200000000000000000000000000000000000B4 +:101C30000000000000000000026F02A202A202AE3B +:101C400002AE02BA00000000000000000000000028 +:101C50000000000000000000000000000000000084 +:101C60000000000002BA02BB02BB02C202C202C9EB +:101C70000000000000000000000000000000000064 +:101C80000000000000000000000000000000000054 +:101C900000000000000000000000200000004000E4 +:101CA00000006000000080000000A0000000C000F4 +:101CB0000000E000000100000001200000014000E1 +:101CC00000016000000180000001A0000001C000D0 +:101CD0000001E000000200000002200000024000BD +:101CE00000026000000280000002A0000002C000AC +:101CF0000002E00000030000000320000003400099 +:101D000000036000000380000003A0000003C00087 +:101D10000003E00000040000000420000004400074 +:101D200000046000000480000004A0000004C00063 +:101D30000004E00000050000000520000005400050 +:101D400000056000000580000005A0000005C0003F +:101D50000005E0000006000000062000000640002C +:101D600000066000000680000006A0000006C0001B +:101D70000006E00000070000000720000007400008 +:101D800000076000000780000007A0000007C000F7 +:101D90000007E000000800000008200000084000E4 +:101DA00000086000000880000008A0000008C000D3 +:101DB0000008E000000900000009200000094000C0 +:101DC00000096000000980000009A0000009C000AF +:101DD0000009E000000A0000000A2000000A40009C +:101DE000000A6000000A8000000AA000000AC0008B +:101DF000000AE000000B0000000B2000000B400078 +:101E0000000B6000000B8000000BA000000BC00066 +:101E1000000BE000000C0000000C2000000C400053 +:101E2000000C6000000C8000000CA000000CC00042 +:101E3000000CE000000D0000000D2000000D40002F +:101E4000000D6000000D8000000DA000000DC0001E +:101E5000000DE000000E0000000E2000000E40000B +:101E6000000E6000000E8000000EA000000EC000FA +:101E7000000EE000000F0000000F2000000F4000E7 +:101E8000000F6000000F8000000FA000000FC000D6 +:101E9000000FE000001000000010200000104000C3 +:101EA00000106000001080000010A0000010C000B2 +:101EB0000010E0000011000000112000001140009F +:101EC00000116000001180000011A0000011C0008E +:101ED0000011E0000012000000122000001240007B +:101EE00000126000001280000012A0000012C0006A +:101EF0000012E00000130000001320000013400057 +:101F000000136000001380000013A0000013C00045 +:101F10000013E00000140000001420000014400032 +:101F200000146000001480000014A0000014C00021 +:101F30000014E0000015000000152000001540000E +:101F400000156000001580000015A0000015C000FD +:101F50000015E000001600000016200000164000EA +:101F600000166000001680000016A0000016C000D9 +:101F70000016E000001700000017200000174000C6 +:101F800000176000001780000017A0000017C000B5 +:101F90000017E000001800000018200000184000A2 +:101FA00000186000001880000018A0000018C00091 +:101FB0000018E0000019000000192000001940007E +:101FC00000196000001980000019A0000019C0006D +:101FD0000019E000001A0000001A2000001A40005A +:101FE000001A6000001A8000001AA000001AC00049 +:101FF000001AE000001B0000001B2000001B400036 +:10200000001B6000001B8000001BA000001BC00024 +:10201000001BE000001C0000001C2000001C400011 +:10202000001C6000001C8000001CA000001CC00000 +:10203000001CE000001D0000001D2000001D4000ED +:10204000001D6000001D8000001DA000001DC000DC +:10205000001DE000001E0000001E2000001E4000C9 +:10206000001E6000001E8000001EA000001EC000B8 +:10207000001EE000001F0000001F2000001F4000A5 +:10208000001F6000001F8000001FA000001FC00094 +:10209000001FE00000200000002020000020400081 +:1020A00000206000002080000020A0000020C00070 +:1020B0000020E0000021000000212000002140005D +:1020C00000216000002180000021A0000021C0004C +:1020D0000021E00000220000002220000022400039 +:1020E00000226000002280000022A0000022C00028 +:1020F0000022E00000230000002320000023400015 +:1021000000236000002380000023A0000023C00003 +:102110000023E000002400000024200000244000F0 +:1021200000246000002480000024A0000024C000DF +:102130000024E000002500000025200000254000CC +:1021400000256000002580000025A0000025C000BB +:102150000025E000002600000026200000264000A8 +:1021600000266000002680000026A0000026C00097 +:102170000026E00000270000002720000027400084 +:1021800000276000002780000027A0000027C00073 +:102190000027E00000280000002820000028400060 +:1021A00000286000002880000028A0000028C0004F +:1021B0000028E0000029000000292000002940003C +:1021C00000296000002980000029A0000029C0002B +:1021D0000029E000002A0000002A2000002A400018 +:1021E000002A6000002A8000002AA000002AC00007 +:1021F000002AE000002B0000002B2000002B4000F4 +:10220000002B6000002B8000002BA000002BC000E2 +:10221000002BE000002C0000002C2000002C4000CF +:10222000002C6000002C8000002CA000002CC000BE +:10223000002CE000002D0000002D2000002D4000AB +:10224000002D6000002D8000002DA000002DC0009A +:10225000002DE000002E0000002E2000002E400087 +:10226000002E6000002E8000002EA000002EC00076 +:10227000002EE000002F0000002F2000002F400063 +:10228000002F6000002F8000002FA000002FC00052 +:10229000002FE0000030000000302000003040003F +:1022A00000306000003080000030A0000030C0002E +:1022B0000030E0000031000000312000003140001B +:1022C00000316000003180000031A0000031C0000A +:1022D0000031E000003200000032200000324000F7 +:1022E00000326000003280000032A0000032C000E6 +:1022F0000032E000003300000033200000334000D3 +:1023000000336000003380000033A0000033C000C1 +:102310000033E000003400000034200000344000AE +:1023200000346000003480000034A0000034C0009D +:102330000034E0000035000000352000003540008A +:1023400000356000003580000035A0000035C00079 +:102350000035E00000360000003620000036400066 +:1023600000366000003680000036A0000036C00055 +:102370000036E00000370000003720000037400042 +:1023800000376000003780000037A0000037C00031 +:102390000037E0000038000000382000003840001E +:1023A00000386000003880000038A0000038C0000D +:1023B0000038E000003900000039200000394000FA +:1023C00000396000003980000039A0000039C000E9 +:1023D0000039E000003A0000003A2000003A4000D6 +:1023E000003A6000003A8000003AA000003AC000C5 +:1023F000003AE000003B0000003B2000003B4000B2 +:10240000003B6000003B8000003BA000003BC000A0 +:10241000003BE000003C0000003C2000003C40008D +:10242000003C6000003C8000003CA000003CC0007C +:10243000003CE000003D0000003D2000003D400069 +:10244000003D6000003D8000003DA000003DC00058 +:10245000003DE000003E0000003E2000003E400045 +:10246000003E6000003E8000003EA000003EC00034 +:10247000003EE000003F0000003F2000003F400021 +:10248000003F6000003F8000003FA000003FC00010 +:10249000003FE000003FE00100000000000001FFFD +:1024A0000000020000000001000000020000000027 +:1024B000000000080215002002150020081000008E +:1024C00000000033000000020000000000000005D2 +:1024D00000000005000000000000000000000002F5 +:1024E00000000003000000020000000100000004E2 +:1024F00000000002000000020000000100000002D5 +:102500000000002000000040000000400000000328 +:102510000000001800002000000040C000006180A2 +:10252000000082400000A3000000C3C00000E4805F +:102530000001054000012600000146C0000167803F +:10254000000188400001A9000001C9C00001EA8023 +:1025500000020B4000022C0000024CC000026D8003 +:1025600000028E400002AF000002CFC00002F080E7 +:102570000000114000000001000000010000000107 +:102580000000000100000001000000010000000147 +:102590000000000100000001000000010000000137 +:1025A0000000000100000001000000010000000127 +:1025B0000003D0000000003D00000001000D0000FD +:1025C000000700D000028140000B81680002022059 +:1025D00000010240000F025000010340000C000007 +:1025E000000800C000028140000B81680002022048 +:1025F0000001024000070250000202C0001000006B +:102600000008010000028180000B81A80002026026 +:1026100000018280000E8298000803800000000004 +:102620000000000000028000000B8028000200E093 +:10263000000101000000811000000118FFFFFFF3FE +:1026400001AFFFFF000000000000000000000000DC +:10265000000000000000000000000000FFFFFFF18C +:1026600000EFFFFF0000000000000000000000007D +:10267000000000000001000000000000FFFFFFF666 +:10268000005FFFFF000000000000000000000000ED +:10269000000000000002000000000000FFFFF40640 +:1026A0001CBFFFFF00000005000000000000001438 +:1026B000000000000004000000000000FFFFFFF227 +:1026C000004FFFFF000000000000000000000000BD +:1026D000000000000008000000000000FFFFFFFAFB +:1026E000002FFFFF000000000000000000000000BD +:1026F000000000000010000000000000FFFFFFF7D6 +:1027000001EFFFFF000000000000000000000000DB +:10271000000000000020000000000000FFFFFFF5A7 +:10272000002FFFFF0000000000000000000000007C +:10273000000000000040000000000000FFFFFFF369 +:10274000018FFFFF000000000000000000000000FB +:10275000000000000000000000000000FFFFFFF18B +:10276000010FFFFF0000000000000000000000005B +:10277000000000000001000000000000FFFFFFF665 +:10278000005FFFFF000000000000000000000000EC +:10279000000000000002000000000000FFFFF4063F +:1027A0001CBFFFFF00000005000000000000001437 +:1027B000000000000004000000000000FFFFFFF226 +:1027C000004FFFFF000000000000000000000000BC +:1027D000000000000008000000000000FFFFFFFAFA +:1027E000002FFFFF000000000000000000000000BC +:1027F000000000000010000000000000FFFFFFF7D5 +:1028000000EFFFFF000000000000000000000000DB +:10281000000000000020000000000000FFFFFFF5A6 +:10282000004FFFFF0000000000000000000000005B +:10283000000000000040000000000000FFFFFFFF5C +:1028400000CFFFFF0000000000000000000000CCEF +:10285000000000000000000000000000FFFFFFFF7C +:1028600000CFFFFF0000000000000000000000CCCF +:10287000000000000001000000000000FFFFFFFF5B +:1028800000CFFFFF0000000000000000000000CCAF +:10289000000000000002000000000000FFFFFFFF3A +:1028A00000CFFFFF0000000000000000000000CC8F +:1028B000000000000004000000000000FFFFFFFF18 +:1028C00000CFFFFF0000000000000000000000CC6F +:1028D000000000000008000000000000FFFFFFFFF4 +:1028E00000CFFFFF0000000000000000000000CC4F +:1028F000000000000010000000000000FFFFFFFFCC +:1029000000CFFFFF0000000000000000000000CC2E +:10291000000000000020000000000000FFFFFFFF9B +:1029200000CFFFFF0000000000000000000000CC0E +:10293000000000000040000000000000FFFFFFF367 +:10294000020FFFFF00000000000000000000000078 +:10295000000000000000000000000000FFFFFFF189 +:10296000010FFFFF00000000000000000000000059 +:10297000000000000001000000000000FFFFFFF663 +:10298000005FFFFF000000000000000000000000EA +:10299000000000000002000000000000FFFFF4063D +:1029A0001CBFFFFF00000005000000000000001435 +:1029B000000000000004000000000000FFFFFFF224 +:1029C000004FFFFF000000000000000000000000BA +:1029D000000000000008000000000000FFFFFF8A68 +:1029E000042FFFFF000000000000000000000000B6 +:1029F000000000000010000000000000FFFFFF9733 +:102A000005CFFFFF000000000000000000000000F4 +:102A1000000000000020000000000000FFFFFFF5A4 +:102A2000010FFFFF00000000000000000000000098 +:102A3000000000000040000000000000FFFFFFF366 +:102A4000000FFFFF00000000000000000000000079 +:102A5000000000000000000000000000FFFFFFF188 +:102A6000000FFFFF00000000000000000000000059 +:102A7000000000000001000000000000FFFFFFF662 +:102A8000005FFFFF000000000000000000000000E9 +:102A9000000000000002000000000000FFFFF4063C +:102AA0001CBFFFFF00000005000000000000001434 +:102AB000000000000004000000000000FFFFFFF223 +:102AC000004FFFFF000000000000000000000000B9 +:102AD000000000000008000000000000FFFFFFFAF7 +:102AE000002FFFFF000000000000000000000000B9 +:102AF000000000000010000000000000FFFFFF9732 +:102B0000040FFFFF000000000000000000000000B4 +:102B1000000000000020000000000000FFFFFFF5A3 +:102B2000000FFFFF00000000000000000000000098 +:102B3000000000000040000000000000FFFFFFFF59 +:102B400000CFFFFF0000000000000000000000CCEC +:102B5000000000000000000000000000FFFFFFFF79 +:102B600000CFFFFF0000000000000000000000CCCC +:102B7000000000000001000000000000FFFFFFFF58 +:102B800000CFFFFF0000000000000000000000CCAC +:102B9000000000000002000000000000FFFFFFFF37 +:102BA00000CFFFFF0000000000000000000000CC8C +:102BB000000000000004000000000000FFFFFFFF15 +:102BC00000CFFFFF0000000000000000000000CC6C +:102BD000000000000008000000000000FFFFFFFFF1 +:102BE00000CFFFFF0000000000000000000000CC4C +:102BF000000000000010000000000000FFFFFFFFC9 +:102C000000CFFFFF0000000000000000000000CC2B +:102C1000000000000020000000000000FFFFFFFF98 +:102C200000CFFFFF0000000000000000000000CC0B +:102C3000000000000040000000000000FFFFFFFF58 +:102C400000CFFFFF0000000000000000000000CCEB +:102C5000000000000000000000000000FFFFFFFF78 +:102C600000CFFFFF0000000000000000000000CCCB +:102C7000000000000001000000000000FFFFFFFF57 +:102C800000CFFFFF0000000000000000000000CCAB +:102C9000000000000002000000000000FFFFFFFF36 +:102CA00000CFFFFF0000000000000000000000CC8B +:102CB000000000000004000000000000FFFFFFFF14 +:102CC00000CFFFFF0000000000000000000000CC6B +:102CD000000000000008000000000000FFFFFFFFF0 +:102CE00000CFFFFF0000000000000000000000CC4B +:102CF000000000000010000000000000FFFFFFFFC8 +:102D000000CFFFFF0000000000000000000000CC2A +:102D1000000000000020000000000000FFFFFFFF97 +:102D200000CFFFFF0000000000000000000000CC0A +:102D3000000000000040000000000000FFFFFFFF57 +:102D400000CFFFFF0000000000000000000000CCEA +:102D5000000000000000000000000000FFFFFFFF77 +:102D600000CFFFFF0000000000000000000000CCCA +:102D7000000000000001000000000000FFFFFFFF56 +:102D800000CFFFFF0000000000000000000000CCAA +:102D9000000000000002000000000000FFFFFFFF35 +:102DA00000CFFFFF0000000000000000000000CC8A +:102DB000000000000004000000000000FFFFFFFF13 +:102DC00000CFFFFF0000000000000000000000CC6A +:102DD000000000000008000000000000FFFFFFFFEF +:102DE00000CFFFFF0000000000000000000000CC4A +:102DF000000000000010000000000000FFFFFFFFC7 +:102E000000CFFFFF0000000000000000000000CC29 +:102E1000000000000020000000000000FFFFFFFF96 +:102E200000CFFFFF0000000000000000000000CC09 +:102E300000000000004000000000000000000A1137 +:102E400000000A0000000A040000FFFF0000FFFF6E +:102E50000000FFFF0000FFFF000000200000002135 +:102E600000000022000000230000002400000025D4 +:102E700000000026000000270000002800000029B4 +:102E80000000002A0000002B0000002C0000002D94 +:102E90000000002E0000002F0000001000000001C4 +:102EA000000000010000000100000001000000011E +:102EB000000000010000000100000001000000010E +:102EC00000000001000000010000000100000001FE +:102ED00000000001000000010000000100000001EE +:102EE00007FFFFFF0000003F07FFFFFF0000000F8C +:102EF00000007FF800007FF80000FF1C0FFFFFFFBD +:102F00000000FF1C0FFFFFFF0000FF1C0FFFFFFF73 +:102F10000000FF1C0FFFFFFF0000FF1C0FFFFFFF63 +:102F20000000FF1C0FFFFFFF0000FF1C0FFFFFFF53 +:102F30000000FF1C0FFFFFFF0000FF1C0FFFFFFF43 +:102F40000000FF1C0FFFFFFF0000FF1C0FFFFFFF33 +:102F50000000FF1C0FFFFFFF0000FF1C0FFFFFFF23 +:102F60000000FF1C0FFFFFFF0000FF1C0FFFFFFF13 +:102F70000000FF1C0FFFFFFF0000FF1C0FFFFFFF03 +:102F80000000FF1C0FFFFFFF0000FF1C0FFFFFFFF3 +:102F90000000FF1C0FFFFFFF0000FF1C0FFFFFFFE3 +:102FA0000000FF1C0FFFFFFF0000FF1C0FFFFFFFD3 +:102FB0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC3 +:102FC0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB3 +:102FD0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA3 +:102FE0000000FF1C0FFFFFFF0000FF1C0FFFFFFF93 +:102FF0000000FF1C0FFFFFFF0000FF1C0FFFFFFF83 +:103000000000FF1C0FFFFFFF0000FF1C0FFFFFFF72 +:103010000000FF1C0FFFFFFF0000FF1C0FFFFFFF62 +:103020000000FF1C0FFFFFFF0000FF1C0FFFFFFF52 +:103030000000FF1C0FFFFFFF0000FF1C0FFFFFFF42 +:103040000000FF1C0FFFFFFF0000FF1C0FFFFFFF32 +:103050000000FF1C0FFFFFFF0000FF1C0FFFFFFF22 +:103060000000FF1C0FFFFFFF0000FF1C0FFFFFFF12 +:103070000000FF1C0FFFFFFF0000FF1C0FFFFFFF02 +:103080000000FF1C0FFFFFFF0000FF1C0FFFFFFFF2 +:103090000000FF1C0FFFFFFF0000FF1C0FFFFFFFE2 +:1030A0000000FF1C0FFFFFFF0000FF1C0FFFFFFFD2 +:1030B0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC2 +:1030C0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB2 +:1030D0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA2 +:1030E0000000FF1C0FFFFFFF0000FF1C0FFFFFFF92 +:1030F0000000FF1C0FFFFFFF0000FF0000000000AA +:103100000000FF0000000000000003120000350076 +:1031100000000001000000020000000300000000A9 +:103120000000000400000001000000000000000199 +:103130000000000400000000000000010000000387 +:10314000000000000000000100000004000000007A +:10315000000000010000000300000000000000016A +:103160000000000400000000000000040000000354 +:10317000000000000000000000003FFF000003FF0F +:10318000000000000000000100000001000000013C +:10319000007C100400000004000000000000000299 +:1031A00000000090000000900080009008100000D7 +:1031B0000000008A00000080000000810000008004 +:1031C00000000006000007D00000076C0000FFFFB1 +:1031D0000000FFFF0000FFFF0000FFFF071D291197 +:1031E00000000000009C042400000000000000011A +:1031F00000000001000000010000000100000001CB +:1032000000007FFF000000FF000000FF000000FF43 +:10321000000000FF000000FF000000FF000000FFB2 +:10322000000000FF0000003E000000000000003F22 +:103230000000003F0000003F000000000000003FD1 +:103240000000003F0000003F0000000F00000043AE +:10325000000000000000000600000000121700003F +:10326000221700003217000012150000221500007E +:1032700032150000021000000010000010100000C5 +:103280002010000030100000001000001214000098 +:10329000221400003214000000E38340FFFFFFFF10 +:1032A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:1032B000FFFFFFFFFFFFFFFFFFFFFFFFF0003000FA +:1032C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:1032D000FFFFFFFFFFFFFFFFFFFFFFFFFFFF3328A1 +:1032E000FFFF3338FFFFFFFFFFFFFFFFFFFFFFFF81 +:1032F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:10330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:10331000FFFFFFFFFFFFFFFFFFFFFFFF00003C106D +:103320000000000800000000000000000000004055 +:103330000000180800000803000008030000004017 +:103340000000000300000803000008030000080359 +:103350000001000300000803000008030000000350 +:103360000000000300000003000000030000000351 +:103370000000000300000003000000030000000341 +:103380000000000300000003000000030000000331 +:103390000000000300000003000024030000002FD1 +:1033A00000000009000000190000018400000183F2 +:1033B00000000306000000190000000600000306DC +:1033C000000003060000030600000C860000030650 +:1033D00000000306000000060000000600000006D2 +:1033E00000000006000000060000000600000006C5 +:1033F00000000006000000060000000600000006B5 +:1034000000000006000000060000000600000006A4 +:103410000000030600000013000000060000100476 +:103420000000100400106440001064400000000020 +:10343000000000000000000000000000000020006C +:10344000000000000000000000000000000000007C +:10345000000020000000000000000000000000004C +:1034600000000000000020000000007C0000003D83 +:103470000000003F0000009C000000060000000566 +:103480000000000A000000050000014000000140AB +:103490000000000000000000000000C00000013F2C +:1034A00000007FFF0000004800000048000000000E +:1034B00000000000000000480000000400000004BC +:1034C00000000004000000040000000400000004EC +:1034D00000000004000000040000000400000009D7 +:1034E0000000000B0000000A0000000400000009BA +:1034F0000000000B0000000A0000000100000001B5 +:1035000000000001000000010000000100000001B7 +:1035100000000001000000010000000100000001A7 +:10352000000000010000000100000004000000098C +:103530000000000B0000000A000000010000000174 +:103540000000000100000001000000010000000177 +:103550000000000100000001000000010000000167 +:10356000000000010000000100000004000000094C +:103570000000000B0000000A000000000000000036 +:103580000000080000000200000001FF000004002D +:1035900000000000000000001E491E491E491E498F +:1035A0000E490E490E490E49FFFFFFFF00000000C3 +:1035B000FFFFFFFF00000000000025E40000800086 +:1035C000000000130FFF0FFF0000000000000000CC +:1035D0000FFF0FFF1000100010001000200020004F +:1035E000200020008000800080008000400040001B +:1035F0004000400000000000000000010101010146 +:10360000012001012001010101011001010101015D +:10361000012001012001010101011001200101012E +:10362000010110010101010101200101200101013D +:10363000010110010101010101200101000001232C +:1036400000000123000001230000012300000123EA +:1036500000000123000001230000012300000123DA +:1036600000000123000001230000012300000123CA +:1036700000000123000001230000012300000123BA +:1036800000000123000001230000012300000020AE +:1036900000000032000000070000000700000000EA +:1036A0000000000802150020021500200000003074 +:1036B000081000000000003300000030000000315E +:1036C00000000002000000050000000600000002EB +:1036D00000000002000000000000000500000002E1 +:1036E00000000002000000020000000100000006CF +:1036F0000000000100000002000000400000004047 +:103700000000002000000013000000200001000065 +:10371000000204C00003098000040E4000051300ED +:10372000000617C000071C80000821400009260081 +:10373000000A2AC0000B2F80000C3440000D390015 +:10374000000E3DC0000F42800010474000114C00A9 +:10375000001250C00013558000145A4000155F003D +:10376000001663C00017688000186D4000197200D1 +:10377000001A76C0001B7B80001C8040001D850065 +:10378000001E89C0001F8E800000934000000001D1 +:103790000000000100000001000000010000000125 +:1037A0000000000100000001000000010000000115 +:1037B0000000000100000001000000010000000105 +:1037C00000000001000000010000000100000008EE +:1037D0000000000C000000100000000100000001CB +:1037E00000000001000002110000020000000204BD +:1037F000000002190000FFFF0000FFFF0000FFFFB4 +:103800000000FFFF07FFFFFF0000003F07FFFFFF73 +:103810000000000F00007FF800007FF800000000AB +:10382000140AFF0000000000000000010020100149 +:1038300000000000010086000000010000000001FF +:1038400000000000000086020000000000000000F0 +:1038500000000000000086040000000000000000DE +:1038600000000000000086060000000000000000CC +:1038700000000000000086080000000000000000BA +:10388000000000000000860A0000000000000000A8 +:10389000000000000000860C000000000000000096 +:1038A000000000000000860E000000000000000084 +:1038B0000000000000008610000000000000000072 +:1038C0000000000000008612000000000000000060 +:1038D000000000000000861400000000000000004E +:1038E000000000000000861600000000000000003C +:1038F000000000000000861800000000000000002A +:10390000000000000000861A000000000000000017 +:10391000000000000000861C000000000000000005 +:10392000000000000000861E0000000000000000F3 +:1039300000000000000086200000000000000000E1 +:1039400000000000000086220000000000000000CF +:1039500000000000000086240000000000000000BD +:1039600000000000000086260000000000000000AB +:103970000000000000008628000000000000000099 +:10398000000000000000862A000000000000000087 +:10399000000000000000862C000000000000000075 +:1039A000000000000000862E000000000000000063 +:1039B0000000000000008630000000000000000051 +:1039C000000000000000863200000000000000003F +:1039D000000000000000863400000000000000002D +:1039E000000000000000863600000000000000001B +:1039F0000000000000008638000000000000000009 +:103A0000000000000000863A0000000000000000F6 +:103A1000000000000000863C0000000000000000E4 +:103A2000000000000000863E0000000000000000D2 +:103A300000000000000086400000000000000000C0 +:103A400000000000000086420000000000000000AE +:103A5000000000000000864400000000000000009C +:103A6000000000000000864600000000000000008A +:103A70000000000000008648000000000000000078 +:103A8000000000000000864A000000000000000066 +:103A9000000000000000864C000000000000000054 +:103AA000000000000000864E000000000000000042 +:103AB0000000000000008650000000000000000030 +:103AC000000000000000865200000000000000001E +:103AD000000000000000865400000000000000000C +:103AE00000000000000086560000000000000000FA +:103AF00000000000000086580000000000000000E8 +:103B0000000000000000865A0000000000000000D5 +:103B1000000000000000865C0000000000000000C3 +:103B2000000000000000865E0000000000000000B1 +:103B3000000000000000866000000000000000009F +:103B4000000000000000866200000000000000008D +:103B5000000000000000866400000000000000007B +:103B60000000000000008666000000000000000069 +:103B70000000000000008668000000000000000057 +:103B8000000000000000866A000000000000000045 +:103B9000000000000000866C000000000000000033 +:103BA000000000000000866E000000000000000021 +:103BB000000000000000867000000000000000000F +:103BC00000000000000086720000000000000000FD +:103BD00000000000000086740000000000000000EB +:103BE00000000000000086760000000000000000D9 +:103BF00000000000000086780000000000000000C7 +:103C0000000000000000867A0000000000000000B4 +:103C1000000000000000867C0000000000000000A2 +:103C2000000000000000867E000000000000000090 +:103C3000000000000000868000000000000000007E +:103C4000000000000000868200000000000000006C +:103C5000000000000000868400000000000000005A +:103C60000000000000008686000000000000000048 +:103C70000000000000008688000000000000000036 +:103C8000000000000000868A000000000000000024 +:103C9000000000000000868C000000000000000012 +:103CA000000000000000868E000000000000000000 +:103CB00000000000000086900000000000000000EE +:103CC00000000000000086920000000000000000DC +:103CD00000000000000086940000000000000000CA +:103CE00000000000000086960000000000000000B8 +:103CF00000000000000086980000000000000000A6 +:103D0000000000000000869A000000000000000093 +:103D1000000000000000869C000000000000000081 +:103D2000000000000000869E00000000000000006F +:103D300000000000000086A000000000000000005D +:103D400000000000000086A200000000000000004B +:103D500000000000000086A4000000000000000039 +:103D600000000000000086A6000000000000000027 +:103D700000000000000086A8000000000000000015 +:103D800000000000000086AA000000000000000003 +:103D900000000000000086AC0000000000000000F1 +:103DA00000000000000086AE0000000000000000DF +:103DB00000000000000086B00000000000000000CD +:103DC00000000000000086B20000000000000000BB +:103DD00000000000000086B40000000000000000A9 +:103DE00000000000000086B6000000000000000097 +:103DF00000000000000086B8000000000000000085 +:103E000000000000000086BA000000000000000072 +:103E100000000000000086BC000000000000000060 +:103E200000000000000086BE00000000000000004E +:103E300000000000000086C000000000000000003C +:103E400000000000000086C200000000000000002A +:103E500000000000000086C4000000000000000018 +:103E600000000000000086C6000000000000000006 +:103E700000000000000086C80000000000000000F4 +:103E800000000000000086CA0000000000000000E2 +:103E900000000000000086CC0000000000000000D0 +:103EA00000000000000086CE0000000000000000BE +:103EB00000000000000086D00000000000000000AC +:103EC00000000000000086D200000000000000009A +:103ED00000000000000086D4000000000000000088 +:103EE00000000000000086D6000000000000000076 +:103EF00000000000000086D8000000000000000064 +:103F000000000000000086DA000000000000000051 +:103F100000000000000086DC00000000000000003F +:103F200000000000000086DE00000000000000002D +:103F300000000000000086E000000000000000001B +:103F400000000000000086E2000000000000000009 +:103F500000000000000086E40000000000000000F7 +:103F600000000000000086E60000000000000000E5 +:103F700000000000000086E80000000000000000D3 +:103F800000000000000086EA0000000000000000C1 +:103F900000000000000086EC0000000000000000AF +:103FA00000000000000086EE00000000000000009D +:103FB00000000000000086F000000000000000008B +:103FC00000000000000086F2000000000000000079 +:103FD00000000000000086F4000000000000000067 +:103FE00000000000000086F6000000000000000055 +:103FF00000000000000086F8000000000000000043 +:1040000000000000000086FA000000000000000030 +:1040100000000000000086FC00000000000000001E +:1040200000000000000086FE00000000000000000C +:1040300000000000000087000000000000000000F9 +:1040400000000000000087020000000000000000E7 +:1040500000000000000087040000000000000000D5 +:1040600000000000000087060000000000000000C3 +:1040700000000000000087080000000000000000B1 +:10408000000000000000870A00000000000000009F +:10409000000000000000870C00000000000000008D +:1040A000000000000000870E00000000000000007B +:1040B0000000000000008710000000000000000069 +:1040C0000000000000008712000000000000000057 +:1040D0000000000000008714000000000000000045 +:1040E0000000000000008716000000000000000033 +:1040F0000000000000008718000000000000000021 +:10410000000000000000871A00000000000000000E +:10411000000000000000871C0000000000000000FC +:10412000000000000000871E0000000000000000EA +:1041300000000000000087200000000000000000D8 +:1041400000000000000087220000000000000000C6 +:1041500000000000000087240000000000000000B4 +:1041600000000000000087260000000000000000A2 +:104170000000000000008728000000000000000090 +:10418000000000000000872A00000000000000007E +:10419000000000000000872C00000000000000006C +:1041A000000000000000872E00000000000000005A +:1041B0000000000000008730000000000000000048 +:1041C0000000000000008732000000000000000036 +:1041D0000000000000008734000000000000000024 +:1041E0000000000000008736000000000000000012 +:1041F0000000000000008738000000000000000000 +:10420000000000000000873A0000000000000000ED +:10421000000000000000873C0000000000000000DB +:10422000000000000000873E0000000000000000C9 +:1042300000000000000087400000000000000000B7 +:1042400000000000000087420000000000000000A5 +:104250000000000000008744000000000000000093 +:104260000000000000008746000000000000000081 +:10427000000000000000874800000000000000006F +:10428000000000000000874A00000000000000005D +:10429000000000000000874C00000000000000004B +:1042A000000000000000874E000000000000000039 +:1042B0000000000000008750000000000000000027 +:1042C0000000000000008752000000000000000015 +:1042D0000000000000008754000000000000000003 +:1042E00000000000000087560000000000000000F1 +:1042F00000000000000087580000000000000000DF +:10430000000000000000875A0000000000000000CC +:10431000000000000000875C0000000000000000BA +:10432000000000000000875E0000000000000000A8 +:104330000000000000008760000000000000000096 +:104340000000000000008762000000000000000084 +:104350000000000000008764000000000000000072 +:104360000000000000008766000000000000000060 +:10437000000000000000876800000000000000004E +:10438000000000000000876A00000000000000003C +:10439000000000000000876C00000000000000002A +:1043A000000000000000876E000000000000000018 +:1043B0000000000000008770000000000000000006 +:1043C00000000000000087720000000000000000F4 +:1043D00000000000000087740000000000000000E2 +:1043E00000000000000087760000000000000000D0 +:1043F00000000000000087780000000000000000BE +:10440000000000000000877A0000000000000000AB +:10441000000000000000877C000000000000000099 +:10442000000000000000877E000000000000000087 +:104430000000000000008780000000000000000075 +:104440000000000000008782000000000000000063 +:104450000000000000008784000000000000000051 +:10446000000000000000878600000000000000003F +:10447000000000000000878800000000000000002D +:10448000000000000000878A00000000000000001B +:10449000000000000000878C000000000000000009 +:1044A000000000000000878E0000000000000000F7 +:1044B00000000000000087900000000000000000E5 +:1044C00000000000000087920000000000000000D3 +:1044D00000000000000087940000000000000000C1 +:1044E00000000000000087960000000000000000AF +:1044F000000000000000879800000000000000009D +:10450000000000000000879A00000000000000008A +:10451000000000000000879C000000000000000078 +:10452000000000000000879E000000000000000066 +:1045300000000000000087A0000000000000000054 +:1045400000000000000087A2000000000000000042 +:1045500000000000000087A4000000000000000030 +:1045600000000000000087A600000000000000001E +:1045700000000000000087A800000000000000000C +:1045800000000000000087AA0000000000000000FA +:1045900000000000000087AC0000000000000000E8 +:1045A00000000000000087AE0000000000000000D6 +:1045B00000000000000087B00000000000000000C4 +:1045C00000000000000087B20000000000000000B2 +:1045D00000000000000087B40000000000000000A0 +:1045E00000000000000087B600000000000000008E +:1045F00000000000000087B800000000000000007C +:1046000000000000000087BA000000000000000069 +:1046100000000000000087BC000000000000000057 +:1046200000000000000087BE000000000000000045 +:1046300000000000000087C0000000000000000033 +:1046400000000000000087C2000000000000000021 +:1046500000000000000087C400000000000000000F +:1046600000000000000087C60000000000000000FD +:1046700000000000000087C80000000000000000EB +:1046800000000000000087CA0000000000000000D9 +:1046900000000000000087CC0000000000000000C7 +:1046A00000000000000087CE0000000000000000B5 +:1046B00000000000000087D00000000000000000A3 +:1046C00000000000000087D2000000000000000091 +:1046D00000000000000087D400000000000000007F +:1046E00000000000000087D600000000000000006D +:1046F00000000000000087D800000000000000005B +:1047000000000000000087DA000000000000000048 +:1047100000000000000087DC000000000000000036 +:1047200000000000000087DE000000000000000024 +:1047300000000000000087E0000000000000000012 +:1047400000000000000087E2000000000000000000 +:1047500000000000000087E40000000000000000EE +:1047600000000000000087E60000000000000000DC +:1047700000000000000087E80000000000000000CA +:1047800000000000000087EA0000000000000000B8 +:1047900000000000000087EC0000000000000000A6 +:1047A00000000000000087EE000000000000000094 +:1047B00000000000000087F0000000000000000082 +:1047C00000000000000087F2000000000000000070 +:1047D00000000000000087F400000000000000005E +:1047E00000000000000087F600000000000000004C +:1047F00000000000000087F800000000000000003A +:1048000000000000000087FA000000000000000027 +:1048100000000000000087FC000000000000000015 +:1048200000000000000087FE0000FF000000000004 +:104830000000FF0000000000000001D20000150091 +:104840000000000100000002000000030000000062 +:104850000000000400000001000000000000000152 +:104860000000000400000000000000010000000340 +:104870000000000000000001000000040000000033 +:104880000000000100000003000000000000000123 +:10489000000000040000000000000004000000030D +:1048A000000000000000000000003FFF000003FFC8 +:1048B0000000000300BEBC20000000000000000556 +:1048C0000000000300BEBC20000000000000000546 +:1048D0000000000D0000000C0000000000000010AF +:1048E0000215002002150020000000300810000012 +:1048F0000000003300000030000000310000000222 +:10490000000000040000000000000002000000029F +:10491000000000000000000200000007000000028C +:104920000000000200000001000000030000000180 +:1049300000000002000000400000004000000004F1 +:10494000000000200000000F0000001B000080009D +:10495000000103C00001878000020B4000028F00AD +:10496000000312C00003968000041A4000049E0059 +:10497000000521C00005A580000629400006AD0005 +:10498000000730C00007B480000838400008BC00B1 +:1049900000093FC00009C380000A4740000ACB005D +:1049A000000B4EC0000BD280000C5640000CDA0009 +:1049B000000D5DC0000061800000000100000001EA +:1049C00000000001000000010000000100000001E3 +:1049D00000000001000000010000000100000001D3 +:1049E00000000001000000010000000100000001C3 +:1049F000000000010000000100000001000005AA05 +:104A0000000005990000059D000003C00000FFFFA5 +:104A10000000FFFF0000FFFF0000FFFF0000004656 +:104A20000000000C07FFFFFF0000003F07FFFFFF33 +:104A30000000000F00007FF800007FF8FFFFFFFF7D +:104A4000FFFFFFFF0000FF00000000000000FF006C +:104A5000000000000000190000000000000001D369 +:104A6000000035000000000100000002000000030B +:104A70000000000000000004000000010000000031 +:104A80000000000100000004000000000000000120 +:104A9000000000030000000000000001000000040E +:104AA0000000000000000001000000030000000002 +:104AB00000000001000000040000000000000004ED +:104AC00000000003000000000000000000003FFFA5 +:104AD000000003FF0000000F0000000700000000BE +:104AE0000000000E03150020031500200100003017 +:104AF000081000000000003300000030000000310A +:104B00000000000300000006000000030000000396 +:104B10000000000200000000000000020000000091 +:104B20000000000600000004000000020000000277 +:104B3000000000010000000400000001000000026D +:104B400000000040000000400000000400000020C1 +:104B5000000000020000001F000010000000208084 +:104B6000000031000000418000005200000062801F +:104B70000000730000008380000094000000A48007 +:104B80000000B5000000C5800000D6000000E680EF +:104B90000000F700000107800001180000012880D4 +:104BA000000139000001498000015A0000016A80BB +:104BB00000017B0000018B8000019C000001AC80A3 +:104BC0000001BD000001CD800001DE000001EE808B +:104BD00000000F00000000010000000100000001C3 +:104BE00000000001000000010000000100000001C1 +:104BF00000000001000000010000000100000001B1 +:104C000000000001000000010000000100000001A0 +:104C10000000000100000001000000010000000190 +:104C20000000000100000614000006000000060459 +:104C30000000FFFF0000FFFF0000FFFF0000FFFF7C +:104C40000000002000000020000000000000000024 +:104C500000000023000000240000002500000026C2 +:104C600000000027000000290000002A0000002B9F +:104C70000000002C000000010000000107FFFFFF02 +:104C80000000003F07FFFFFF0000000F00007FF85B +:104C900000007FF80000000000000001CCCC020101 +:104CA000CCCCCCCCCCCC0201CCCCCCCCFFFFFFFF0D +:104CB000FFFFFFFF000000000001000100110807D6 +:104CC000CCCCCCC1FFFFFFFFFFFFFFFF10000000B7 +:104CD000000028AD7058103C000000000000FF00EC +:104CE000000000000000FF0000000000000002843F +:104CF0000000150000000001000000020000000399 +:104D0000000000000000000400000001000000009E +:104D1000000000010000000400000000000000018D +:104D2000000000030000000000000001000000047B +:104D3000000000000000000100000003000000006F +:104D4000000000010000000400000000000000045A +:104D500000000003000000000000000000003FFF12 +:104D6000000003FF000E0000011600D60000FFFF48 +:104D7000000000000000FFFF000000000000FFFF37 +:104D8000000000000000FFFF000000000000FFFF27 +:104D9000000000000000FFFF000000000000000015 +:104DA000000000000000FFFF000000000072000093 +:104DB000012300F30000FFFF000000000000FFFFE0 +:104DC000000000000000FFFF000000000000FFFFE7 +:104DD000000000000000FFFF000000000000FFFFD7 +:104DE0000000000000000000000000000000FFFFC5 +:104DF00000000000BF5C0000FFF51FEF0000FFFF98 +:104E0000F00003E0000000000000A0005554000086 +:104E10005555555500005555F000000055540000FB +:104E20005555555500005555F0000000BF5C000079 +:104E3000FFF51FEF0000FFFFF00003E0000000009F +:104E40000000A0005554000055555555000055551B +:104E5000F0000000555400005555555500005555BB +:104E6000F0000000000000001F8B080000000000A0 +:104E7000000BFB51CFC0F003097772A2F215595114 +:104E8000F96D6CA8FC81C659CC0C0C8540DC0DC4B6 +:104E900015CCF8D58631618A7D9541B057493130BE +:104EA000704A40D8361203EFB7514C7BCCA089969C +:104EB0001ED420749D0684664493FF06955FAC0C57 +:104EC000A19934B19BBB042A0F0059F6FA14600370 +:104ED00000000000000000001F8B08000000000020 +:104EE000000BED7D0D7854D5B5E89E3967CE9C99C1 +:104EF0004C923361122690E049081035C0000182BF +:104F0000457B8060639BEA1050538B76402B91DF8A +:104F100048B1E659DF9D03F931F2D7203E4AADD5BD +:104F2000815A4B5BDB1B7DD1D2EFD9DE89582F7EB6 +:104F3000AFBD97025EB1856BB0D6B656BCB4D52B6B +:104F4000FD3E5ADE5A6BEF9339E76426095EF5F6AB +:104F5000FB5EF16B77F639FB67EDF5BFD75EFB8C37 +:104F60005F0D33E5E38C5DC07F501EF530C68A339C +:104F7000A5F59CA9C6CDAC96B196A8A26F85776B16 +:104F800024D6DA5B83F5C9F56C1A633E6C5FCAE020 +:104F9000CF52EA2717A9B17404DEBF24D5497A6637 +:104FA0001C77D92233A6CD84926D3F2215C01829D3 +:104FB000DFD90195D1BF0B958CB59D9CD1F0BC5527 +:104FC00087FF45597EE48DCBE18FB96CEE0589B141 +:104FD0003F6ACD85E961C67F337958932731F65E04 +:104FE00032D6F0FCA4A1EFAD75AC61EC757F11AECB +:104FF000D3543E3395B1394CA57558EB938BBA4BCE +:1050000012216877E0454DAECEC0C322B0C879F01A +:105010005C6669FFCCA1F00FE28F99341ECC93A699 +:1050200079AC7E03009F6D7DEEFE83E38AFE4C86A5 +:10503000FFE63096878F60DD8F78121FC3E7C1FAD5 +:10504000BBCC71505FF3C4128670E23AE25333F086 +:105050005BF35AEB189CDFB59E5CEB189C5FF4CBBE +:10506000856FABDD1FEB3BBB9897B1E33EBD3C8E3C +:105070007CD230A59E017D9B904FE665E8B26471BD +:1050800027C1938B2EC01FBA86F892429C9FFEAD1B +:10509000BD0EC8CE36B10063B3B3CC3F02FF24DCF3 +:1050A000FC537FFD87C23F5F12FCC31A8A492EACB6 +:1050B000F5BBF1DD52EF3BED9F360CBE457F8B7E9D +:1050C00043F82F57BFA17C6266E51331BEC52FD6CA +:1050D0003CFF557847E20FC67A887E8CC5259C3701 +:1050E0005337593CDFDECE5696001BF0299914E960 +:1050F000FA83340DCBA0897A438AC86F0CD8E5486F +:10510000F4F3292C81F469C747A5A233F0915C160A +:10511000FB06EAB1C79942F3CA1195C6013C3D4E60 +:1051200070343AF117D4E20CF9D957525D9880F1F6 +:1051300058A828AB1CDC976C6D906D7C729F8F35E6 +:10514000F78688507C9E092C3506F1777E91DE9497 +:105150009F7B1C37BEDA7DB11309D0BF66B112FB4D +:1051600026AEDF937D3DE9C1F52826E207D6931EE2 +:105170006E3DEDF993C57AB2CB7587588F05FFE088 +:10518000736B5D39FAB9E1CFF5BEC3674457C01000 +:10519000667EF675F9705D158C9DC475213D430AD8 +:1051A000D1C9174911FFC2FA4E127FB8D6077CC584 +:1051B00090AFDCEB933595F062CD2FAB5F6C9067D1 +:1051C00065E0FC1DD3689DBE413862348EA431EA8F +:1051D000F73396F81DBE07FE3B42FC1732188EAF20 +:1051E000446180E9581ACD26D0B5A37F1EAB994AF9 +:1051F0006A8BAD855209255823B4EBF88BD48CFC0F +:10520000C822B50E39791D89519C1B6F96DEB4EA10 +:10521000C710FF3543E97FECD37EAA7714C7BE8160 +:10522000B8F47A383FB8F10378F37A6CF494358E99 +:10523000CF639F9EC2F195438E9BD42F38F005FF1C +:105240000C94CB7162DC9D55AC472A847A9DD7F4CF +:10525000039DAA6AF47E58D9203E774C9AF39C0F9E +:10526000FE3CE54F14E1FC92A4F5FB80BEE35A7AC4 +:10527000098FDD82AF164BE7D5D7A0FCF2FCCAC27E +:105280009550D6793C59F9685F126007FEDC9B5453 +:10529000990C03BF778AC39F8BDF1E4DEA0EF97C02 +:1052A000B4436E4841FB47EF2D6A6A00BC7546AABD +:1052B00066928E313C32AE2BCFC3517C99987F5F82 +:1052C000E717094EC0DF6508BFC58716BF5519A689 +:1052D000A1417D22E0C70B24D67A582CADF331646E +:1052E0001B9E2CFC001E66E138457ACC2BC3F3B024 +:1052F000D16B2A7A060F5F9EEF257A6E5C3079BFFC +:105300005491817B93C7CBE92AEC319363D5A837BD +:1053100073C9DF2EC0530DC971CC83EDC6D4B3144D +:10532000CAD156F1FC1D165FE48176631A633E5CB8 +:105330000FF87F82BFA2E80CB10EC16ABBAE0E723D +:10534000FE2AD7F6213CD75A70B4087C65F8EB5A90 +:105350004F71062F167F4DF02696E073B53AB64092 +:1053600046B06B52695C77BB97B5903E31D9119CC2 +:10537000AFC863C931E7EF5095BE1FF97BA5A043C5 +:10538000516DD79D5E803F1C95098F45032B1AD127 +:105390005E054E5EF33BC69F939D1AD3D0CBBC886F +:1053A000EF7A7D0196E116D3C47923DEC44A84A343 +:1053B000A83E1D5F44FA50F3A008F6F84C86F4535B +:1053C000E7F718F110D2FB6AB6C2E69F7CC1C3E5CD +:1053D000146036523519BA3E240CD3CEBAFD81552D +:1053E00035D82E4878A962F5821F0CE6017E50055B +:1053F0003F00DD3722DDF35A748F07EA1375CD8342 +:10540000F001BF8F45FEEAF1B152ECD7D3A934A722 +:10541000385E8E237E435E81171DFE4379F6F27956 +:10542000AFF4F8683EE9568EAF428DA574A04F5E8A +:105430008D612811E42BC005AA4181B7004BF54FBF +:105440000154865C782BAA8F79D05F97AB7AD31200 +:10545000C7D37D0867D04893BD00FC3184F751B9AC +:10546000F5D5FF09EB79F4B01433998D0F19F0E1FC +:10547000D40CBEF47B41DEECFECA45FA91A85E90E6 +:105480005FE510B767967D007EFD2AC2256B9C5FA5 +:10549000476B87D436497F1DF597AC79119F96EFFE +:1054A000DDAD6D31116FEFE2588037A967461AF70D +:1054B0003B80E5D837391FA6897E9A91427B44F616 +:1054C000704EC61F09D67859DAB64E5F5990A5EDD1 +:1054D000FE48B3E9C1F9EE12CFD43685E090C13E63 +:1054E000B09ACC3AC152D038B8CC0B13B1FE259A41 +:1054F000C7EA2787583A0074DA563393D9FD6619FC +:10550000FB411B148F0B1543FBE5C68B6BBE654E31 +:105510003847DD2F24EB6F64D9F70CED27B3372C18 +:105520003C01F28EE000B333F4017FE9A007EC68A0 +:105530007BD9E326F2F97DF80AE8DAC538DD59C2ED +:10554000EBB0635299F7B49FFC369DF34B94FB5339 +:105550007E76439AE4243A3AFF2A28F8EA6196F8DC +:1055600035F295BF2C41F8DD560CF6ACC08667F4D9 +:10557000279147AA9751FB6D536F373DE8A74CD051 +:1055800066102F08BEDAA672F832F36CA175762782 +:1055900053EC573EB41B7C7C558FF3D2E2CB6ACEE2 +:1055A000C7DD354D850C9FABBDA48FF27A9E4C7B39 +:1055B00023767E34D9B2A9B84ECE775F83F282C506 +:1055C000976897A241073F5AFC668D3FB2DC45645D +:1055D000BB5D2F07F667C48FDCDE8F177C3FA1EC25 +:1055E000AC8701BDF5B8B610ED7A65738CECFB4362 +:1055F000E15F94AE2038EB35A4B7C718E3B970F972 +:10560000E8F9C2EDFF1435CAAFD9FDFB503DD46DAA +:10561000EB0BD638DF833790A9570C1DAF40F853FA +:105620004C8FC550EEB6FA52CDE0EAB149DE920594 +:1056300011A0EBD640EA04BA829DDDA50B1AA05D4D +:105640007002F02ACAA9DCABA2BC7E1C9535F2AD73 +:10565000AE939C8504BDD940AF3A1150ACCC96D9DD +:1056600056A8F60F480CF5EFF6A89CF27B0432D151 +:105670004E0AD8AC71B60FECA671EFAF39AA39C695 +:105680008FF2F6016B7CBDF57395B6F1DF9B64C1BB +:10569000D5A312BF0C00AEE07D1ECC97AA40ACF69D +:1056A000A80BD07ED6C2C61EEA6A8DC150BFB3BA5F +:1056B0000897A711FC06D0DDA477E56A93FC6EA8D5 +:1056C0006FA6FDDF728FDB9F6CF4A2DC80BD473ECE +:1056D000B1ECBD35CF88FC36DA76C0C132E8E1BB2B +:1056E000593086FEC0694FE2B35E78DEB6AC8DF904 +:1056F000000EDFB2D6CF7542D9067C4AF252E74D92 +:105700007DB342F02DF4DB191F9BC27EF298B2628A +:10571000846F671DB7B7B9E6DD96342755D9FCC548 +:105720006D407F9447D0BF6AB67E79D1AE4955604F +:10573000687736E863B52C718D91C76D728CFB2943 +:1057400096B8DB5B3C747CC638FF7B4103A3BC048A +:10575000439B18CA6190D9E4A222D32E2357CEFAD4 +:10576000DE15B747110F91B1C60C0FF0FB33A04EF9 +:10577000E2E0F245F28C27511EBEBB25BE20047428 +:1057800089F88D3BBDF0FEC52D8B176C0779885CC1 +:10579000C24839FCC87B876733F6C798CA158C1D89 +:1057A000DA72DB6633C4F18F7A726BF248E9EB3E52 +:1057B000D47B27A8DCEDE5FEE21EC1DF4139C5F54B +:1057C0005B35B4B3CBAFCCFDB0800EFDECFE4394A3 +:1057D000EB1F59F01DF8515F43FC1435C33E42479F +:1057E000BE73EE23DC787FD4EBA1798F7AF93E6F1C +:1057F0006FFE6A5AFFB98189C3EE1BBA611DB8BF3B +:10580000B0EA4705FC0867AC06E184F776FB0F6059 +:10581000A21C44962E277ACACBF8BE932D670E3F62 +:1058200059D65AADFD441FAEC3BD9F1884D3978887 +:10583000B6C2F31D61D0A5601F77F8CCE638B51B62 +:105840008836D9FCAD7289FBC783FDE6017D617C9A +:10585000D593E847F96435D1901D7F79CD3DCCA330 +:1058600067DA77097CC82C657A2766E03E82EB2DE3 +:10587000CE0D7FCEF5363BF79D83ED07F7EFF1A315 +:105880005EDB3E61506E6B2DB93DA22EB1E9A71DC6 +:10589000B51727AFDBE5015583F63B43AF754FC422 +:1058A000F849CC1B9BA4A3DCCF3CACA39ECC8FCCF3 +:1058B000B4C7A793FE85BFF2DAF6C5A11A18CFC602 +:1058C000973B2E52AE07E78FB8E76F6AA8C83EFF36 +:1058D0009F383ED85BA4F7F9D4ACAB740FE1D50D7B +:1058E0008FD54FF226CEDBE10E54F1B8C4503D38CF +:1058F000E0C0E7C5EA3F7719F2B038CA597B68A61D +:10590000B6D286977C89CBD9157E235F2A1E0AF7EB +:10591000C5EAC75CF376469CF34ECFCC5B86F34E6C +:10592000479D87762C5E60E6A11D8B6FFF03DAB181 +:10593000A0D6D3702BF2A36B3F502060ECA86BFA7B +:10594000CCE7713F5025C7886F556E3FE43A256517 +:10595000A2FDE8F1183CAE67901F16443F8C42BE92 +:10596000DC0FFB3F96FDAEB2F96195381FF7C3DC43 +:10597000F860AC4C7B23CFAEA74D2E6F623FBCB21C +:105980004E3002D36FFC25C075C7611FD97F761ECC +:105990005ADBF621AFFD8AEFE7EE10FBB9DB58BC0E +:1059A000005F9E61DE0684F70C3B5A30CB46EF4F1A +:1059B0004B223ED4ED237FC984FF10CECFF7F81CD5 +:1059C000FED4AABDCEFAEDACA904EDF0ED0FFA5865 +:1059D0000AF07187CBEE5C29717DB28AB576219D84 +:1059E0003B45BC6AA506A6175CF2753FF8FA9C1504 +:1059F000505F26717BF0661256E6CFC0B53A9452DE +:105A00000C78FFABBE59377C8C61FF54D738949F1C +:105A100030F77FDDFC706BB713BE91E077C36BF995 +:105A2000E7B9E0900F788C54167E5D29F8CDA25727 +:105A30009B5A308D15825F16E0A5B910751994FF39 +:105A40001E48B5C33C4949F0056B9DCBE3DEADD3A1 +:105A500049EF8DD0AFFD7DF6BB0FFB150FEDB72DD8 +:105A6000D21B477D6DED9B826A2BE1C223F3FDC8FB +:105A7000B6E808EFAB867FEF866B4918ECC1F4A15E +:105A8000F0817FB35B8275DD2D19377326E6F0F95F +:105A9000119F1296DC8F273F07DA6F9043DD1E18A7 +:105AA0002F10EA237F27A03BFDFE0DF807EABB6A13 +:105AB00046FA2EAFDAF9DEEDFF3C2EEC256CEF490D +:105AC0008E0A48C4500F84D264BFEAE4B7066CF271 +:105AD0006BD17D6314F4C698DCFAC90B3B3BDC1335 +:105AE000A8421F7844DD82E38F3D9E0694878D8C0B +:105AF000696D33EDE32A34EE107D701EDECF417CFC +:105B000030C6F761B128E2A93B890736783E10BF5D +:105B10000ED7DDFE92C4503FB5FB5A29FE6896337E +:105B20001DE3EAFE2AFEDE7F5C8A78B93F4C78EA04 +:105B30002A6D780CE31907251E3F82FD00C521FC64 +:105B400021D330808E5DE0778431BEFD0FFC1C6573 +:105B5000412891C07E52B4D9E7877EFFFCC4ADCD09 +:105B6000585F1DBD5AC6FDCD2131CE99EF3C398716 +:105B7000017C5DDFCB6769DA9FA414DCD7ACEE93C0 +:105B8000286EB6E61FF369FED54FAD7ABC11F1F36E +:105B9000832BF537489FB6133D563FB3F45F4DB1A5 +:105BA0001E15E8D1BE59C423CD587429745DE7672A +:105BB0009F43FFC75ABF853F55EF217BB7FA4098F7 +:105BC000E2B883722C437BE8EF87B2298BBDFB8D53 +:105BD000C4E37A6FE52BCD089FE740FF2D045FEF0C +:105BE0008D3E5C97A7AC95FD1AE63B89EBE3EDC8CB +:105BF0001E98DFF6A426C1FBB7BEBD4FA99C8AF351 +:105C0000EE5356521C6733E1C182533DB0CB44FD85 +:105C1000A5566995681A16FDE3F70A06E0F98603AA +:105C2000521AF7535052BC32A03BE348605F421E09 +:105C3000A0FB7AC197EBFBD6917E5FDFBB8DECD8E2 +:105C400086834EBD0678A573D2352F4BB146ACFF87 +:105C5000EF6F15E800CF9B47BE5980F8877956282B +:105C6000203F3ECD291738FEB9A2A1E3317696CE6A +:105C70000537F4DECFE773E9CD37F18FD2A1E7AC7A +:105C8000F9B2F39C951D1833AAB8C39AEFBDFB88EF +:105C900009F3BDF5D4EF1FC17394B57FFDD3235F26 +:105CA0004279FE714043BDBFE13BBF7EE41EC0E3CD +:105CB00099837E2FF2C5DB3FFAD6E30F41FDED5706 +:105CC000A6CC44553459E6F2FCF6937F2ED1619C64 +:105CD0004D3F5A3C16D7BDE9E94563D930FEC6DBD6 +:105CE000C04729BF1D9E14D14F3F08E38D85EAB3FD +:105CF000A274D1E350DFA10908DF9913FE18CAE6A8 +:105D0000067886F2BCBE17E8348DD7EF05BCAE7FAF +:105D1000E23E3AAF1C8A5F73BC374AFA673C86DAC8 +:105D2000D7F72DBDEECA5A2C7D311DC76367C97EDA +:105D3000BAFB6D380E749C9E9B6EEFB2F30AEAC7F5 +:105D40000D4FDCCFE775D1ED0CFE316F28DDEA9108 +:105D50006E7919BABDCBD63EFA10BEEC1B93757F97 +:105D60006E9D8BAF7BFAFAC26CE7F876FCA6478192 +:105D7000DF16119729928D65F26CE483EF3EFE5099 +:105D800004E9EB8F3522BDBFF7EE04067CF15BDF43 +:105D9000D95B50FECEFEC8AFED873EAB7FF432D963 +:105DA000E9B79FFEB9A2939D031711FCB9B7D9E0DB +:105DB000BF23E8DFAD17E7391B1ECB4FFB0B327457 +:105DC0005A9F5AD2A017D0738A27AE4F717E5F9F19 +:105DD000EA5FE6C942B76D7225B71B297E4EB6EE63 +:105DE000B15F2A2CE4A4A7A70EE978FA6A7C9E8BFF +:105DF0008ED6FA355CFF5C1B3D1FE3729A4B1EDFAB +:105E0000DEE797D10E5AF47D5BEC7737A43C2FB3D5 +:105E10002C726AF9374C5A3E2C9DDCFCD0E596E397 +:105E2000D4E8CEF7475EC7C5E1E98B7848543C1407 +:105E30005F9B4B410FA33D2A5052688FBA7CFACB2F +:105E400026F2C58B3EB61FBAB417CC617A96F856C7 +:105E500007FA795332753914A778BF1CD1683FE629 +:105E60003EEFF6C1F640B7C173E8D494B103B88FE2 +:105E7000F5F2787067FF3C86FA1FCB0A3CEF6D9B0A +:105E800045711AABBF148D519C5889EA0BB28DAF86 +:105E9000B4CDA1F643F76BADBFDD07F59DD19218E8 +:105EA000FAFBF9DAF7A3FDECE2F76DDB6593F6A1F7 +:105EB000DDA12D6AA56D1FDAADE7DC073F2F0FB31B +:105EC0000FBED8FDDBE0FC11F7FC39F7C1C7653C1C +:105ED0000F10E79043F64B5A88E20AE3843CBF2157 +:105EE000F47E394B6F66DCBF89ABF63875F3D97E2B +:105EF0008C4B7F7DC9C97D2B609E42D6417169B0B4 +:105F0000FAB517660DC7CFCEB8B4DFCBFD20161794 +:105F1000F171CFA07EE1F38973CB7319789E5C0990 +:105F20007F3E3C7780CE172F8129F1BCBB6299BEA2 +:105F300005E199B8FCC8B757103FBCBF38F920BF7E +:105F4000E816BF988EFD7DB7FEE1ECEF033EBE3E46 +:105F5000D867077CB387D2A7FB43DADF4733F34622 +:105F6000B3CD3BC46F1EE5B9E0579616F073E693C8 +:105F70001E8AD39B0B0D8F0FF974028B61EED069D3 +:105F80004FA2DA87F1B965A61FF93424B75E82FE05 +:105F9000646848BC8AC70976B8E2CC171BB71A6D8B +:105FA0009CF962E351C3C499EB7DB3878EEF8E33C6 +:105FB0004BF90FD2FE2E709171E6C81863862786C2 +:105FC000E8FED8A29FD665E2CB37FA0A16F1F8327E +:105FD000A378F24DBEABDA4D802B32DE7812DBBFF8 +:105FE000DA397F119EC74426F2F77314FEFE1E4C69 +:105FF00092C0F306D93051DEF7AEF86235E5AD4414 +:10600000D900FA67567CD3DF9C488B7C9304D22F4F +:106010004FD3FB3D3AEA61CD83EB582C85683FFABC +:10602000C7324674CF85C707447EC94EB01B58FAA5 +:106030001BF8B9607752A3FC93ADC92895DB930692 +:10604000BD7F87C5D7F9E81C919F4FEF15F18F767B +:1060500085B5607954D8EB5F0A7ECE947C1F72E8D8 +:10606000D46FF6DE8A708582E457E682AB27593D0D +:1060700089E7BFC426E1BC5DC93AAA6FF7A4753CA5 +:10608000BF6AEFFCA72D2AF07F8174368AF5AE8EA9 +:10609000E7B7D4CFA33C02B25B923E6D926CB35390 +:1060A0009D3E1ECFD0EA787E9D66C0FB59D89FE703 +:1060B000390EE12F0137B4A77C284DE3EDBFECC9C1 +:1060C0001E7F7F408CBFB3FF1AB2CB72C2F420DDBB +:1060D000A260FFB0DFCEFE57E879B7EF8881F1A567 +:1060E0009EC52CB61FD61F6EAB213877F6BFC82AC7 +:1060F000E1FD4362DED06D3D44C7D2B65AEADF1DF2 +:10610000609FE1717126F2A278DE48B78F89BC28C2 +:106110007DFF16A87F4BC011D081B50BD1FE5E4527 +:10612000E3CB55E6119107F82DE417F6BC3B7ECD85 +:10613000E3D6E35882F6E1E3AA4306FA8FE36A4A1C +:1061400016A2DF35AEEE32CA9B1C57155A41CFABB3 +:106150004B6EC5F201CFD9238B30CFADD44BF1AB11 +:1061600071D5D59FA776D557ACC2F72FFAC2044F89 +:10617000C1152DD5387E019E37E23AE423742EC82E +:10618000749DE293D639E38E5865E170FB19B26CC9 +:10619000965E24790C624CC4562F72D5C7B9DA5773 +:1061A000BADE5FE67A3FD3516F13F866B54AEA9BD1 +:1061B000680307648277BB68C35A81B1F19C5404B9 +:1061C000B4FB0B1E524FD7F0F2351B5FDD8FEB1A7D +:1061D000464F9EF471B91F17F566E0C3FF5383194C +:1061E000782A096F141FC9E8897A13931576CC1E93 +:1061F000D413A6FD1CC4A6277E8D723B544FD41425 +:106200000E0C0397A517BA849E8005531CE51D96B6 +:10621000F80FD20375A02FA6D9F541AC05F55F5450 +:10622000092D92E7913EA0F333C0503BC65D142F79 +:1062300027C9BB3EB608CFD30E9D5AB57705C8C354 +:10624000C6D94ACC8FF4177E91250F5856E40FF526 +:106250003B43D1B4C3EFB49EDBFCCD8BA3DBBC3D91 +:10626000EAE9102F313FCFD20B23D10DF3CCD81454 +:106270008E1F0C62E5D5050D1DF05128F450DEFC93 +:106280009285BA2DCFA254D02DAFDA49677FD4467C +:10629000679685CEAC9EEC814567F0D3896E25E983 +:1062A00017993E75285CFEB64B496F20DEB00C9501 +:1062B000B105864D7FF8346D1FC6C71E5CBA7EB32C +:1062C0000FF303C714CD403C4E53B89E66079DE7BD +:1062D00061D6B8A03FA62978BE196965DC45E4E718 +:1062E0005B2569AEDFF26B0D9640FD173528AF4890 +:1062F00029030F4EE774413806D7837A0FF384D40D +:1063000056665412DF265876FB365FC962DFDC76AC +:10631000C782EF0B0AD77F5639127F23FDD0AE58C4 +:10632000F80C56C73CD9FC922E6187760BFBD68DB4 +:10633000F608EBCF7D95F8B349E1F1FE40590F43E4 +:106340003C07E45805DA25539EBE08EDD2EE00EF77 +:1063500067B5B7C6BD49E03B20E8E39EF716B18EAE +:1063600031C23F77BF5F25DE2B8D3C8F4C69EC2619 +:106370007BA59429A751DF2B7A17EDF7D9E1217975 +:10638000B2AB10AF3ED69A7EAC02F1CAF5BFB5BE35 +:10639000DDCFBD42FBBDFCB256CA13DCA070BB947E +:1063A0005987785F7B84AD10ED16A0FE61C0B7B051 +:1063B000BE4D48E762A433B75F2ADAA15923F3F54B +:1063C0003D8AE6D06BD6FBA764E34B8AED3CA22B5B +:1063D000BE36FE791DF9673BD973592D30F3709D98 +:1063E0004F3077BE6607F6F3B194E9A9C89CD30E87 +:1063F000CDC31F927FB14DA1FC8B660355B33FEE19 +:10640000CABFD09D7E71B7CB2FBED8FDC968FDE253 +:106410008BDD7F0CE3177F4B1945FE4520541FBDD4 +:106420009DBD0FBF78BAF1072FFAC56C35F78BA762 +:10643000184F623D14B97911E61D45665976A1756C +:1064400011C6B72273B95D38A8DCD98E76E113AADC +:10645000F14384EFF70AE3795F71C320F3F34476E5 +:10646000BD6495BEB1FC9CBE237C8346E7F52EFE41 +:10647000F8B9E04BF779FD07357E963C80638A2DAD +:106480000FE0A35ACFBFAAC669E4FBC1F92E328F31 +:1064900001E4E6F72437AEBC8D41FEAFF672BBCA0D +:1064A00052EA129BFDD95AFDA1C76FCE2BC3C46F10 +:1064B000B6A27CBC9FF9471FBF09F9B9BE207BA5D6 +:1064C0000893DA11BE7DA43C8662BF4DDE94A82BF2 +:1064D0008FE1238E734CF60FC61B26FB3FC238C7D5 +:1064E0006CFF601EC36C7F96FC895CF902A18A5820 +:1064F0009CFCB9522F433C75CD8FF5A0DEED2AF7F9 +:106500002A5B2A32F730AC79D6FB2752BF8EA8E23D +:10651000C57872C7E1C5744ED2E56B6DA0F3C4B007 +:1065200057DB5F3114EEE57E6EC7A5B66D931E1B7B +:10653000267E2689FB571DDA730457DE8C4818EF38 +:106540000DB4F7FF8FC312EECFA2251501A8DFE32C +:1065500017FE1420F357B6F356D07B0D08BF54E650 +:10656000656837A4B69D34DF48F03508FC496DF7FF +:106570004F7A6C9873DA0F1A3E0B8F37FAB9BE91C7 +:10658000DAB6D3FC165E3B6A643A77F0A1F30F7477 +:10659000F30DF8F9FDB518BF0F22D778E91CD0F23A +:1065A0001B41BFB4911C3DEBD43F52889FB32FF2E7 +:1065B0006B7C9E402BC9A795571F4A74909DCA4B70 +:1065C0007439F603169FE4F94C86EDD5904CE7B18B +:1065D0008AE00BE9CA741CD7D333A3CA8BFC92168A +:1065E00078EC36605DD3A114EBE811F967D63C8CEA +:1065F000557D65399E6F1A9533314EFD5D21372AE1 +:106600000B91FE54110FB3F09EC1663601E0DFE539 +:1066100017E70A95AC12F977E3828D9F40FF57D5B3 +:106620004D7FB6F389A1FA8805107E6981375085C0 +:1066300079FA33B83E62D1DA11CE27F8B9AC5CC32F +:10664000EF8D5874B0F06ED1C387F791F1BE810120 +:1066500074B1D18345397E07F3CDFB9C76C9A20B7B +:10666000EC02EF5FEEB1AF7F27F181B5FE27FDE2CF +:106670009CEDBF69FD8F625009E13F74E95796C3F5 +:1066800092028637465BBC2AE06FDB3E3A2F24D36A +:106690007998C547EAC0AE7439CCF3E2DF0AFCD181 +:1066A00051DF23A173DB09CCFA77A7E37EC4047121 +:1066B0000FC68A0706D7F2786039F209D06F42CD4B +:1066C000963BBDD3288A42FBC2F19F66940706EF32 +:1066D000093F56FFF236C5717E1F6E70D6C7309ED9 +:1066E0007F369ED99E839C8DC17C2DBCAF24EE71DC +:1066F00058CFADF33AC5A5B7ADD27D5E77DEEF3C9E +:10670000BF1DE9BCCF3ABFDD05E6559D9DC1677B46 +:106710002573DC9374E3B344370DA4DF58BCE786DC +:10672000F185F92C966618554A50BC81D5F13C2D5F +:10673000599CE75AFDC32AD7272A7B87EE45296C47 +:10674000C024BDE5A2874587EE6A26F2E68D502972 +:10675000BC0F0BEA750B3A044B810E80A7B0C03F0B +:10676000AB1778F5300FF26FC17CC5710F4761DC54 +:106770002F2C12F9C941171D149137A7B89ED7AA1B +:106780005C9F5DECF9E93455D0239FE5DBE9C1B4AA +:10679000ECF9EE163D06F9F622E79B6FCD1782F96C +:1067A00026BE8FF972B473D3FF6A419F2E9DD3A783 +:1067B000AB96D343BD86CB859B9EF0AF11E947A630 +:1067C00002F8620CD20BFD6A700F292FAD91D349EC +:1067D00085FF906E639B9D74535D72918B4ED6FDC9 +:1067E00030BF6A2C277E7E3D40F12C7590AF9EED28 +:1067F0005700D6AD658CE2682F621209C613FF5AA6 +:1068000048F06F8BB114DABD71950FF0B82B6EF1B3 +:106810006CFDB7EA4DC3C6B9BE9C049B3905F6E9C9 +:106820004995CA5CEDF2954402CF8F0AE7338F1C7D +:10683000C17B8A3AF9CFF9028FE1A84EF73D1F12CA +:10684000F2421C6DBB97A534707F416DE4A552AF39 +:10685000AC6054E7F71E959A85BF9329AEE1C4A3B7 +:106860007B9CDC74B6E155CADD6EB425DE3F7DCD80 +:10687000671FBF4795D05F382E511EAB5A0BBB5ACE +:1068800084BF562B41BE506B63212A071634F07A21 +:106890007C2BBEFF21D20BFD0A83AFB340F70EBBAA +:1068A0003EFA67ED3F2A3378B1E070F3CF7F177E71 +:1068B00076207E6CF6F17E8C09007EDE6D60299676 +:1068C000C5BFB5CAA273324B63DC727EAA9BE4AF2C +:1068D000DACB907FD5F9A0DF80BF1EBAE3058ABB73 +:1068E00028BAE6916CE75B2FA8DC7F57F01E2B9D42 +:1068F00033E89EA5F9F6F7FCBE3DC8D14F548A0F88 +:106900003EA162DC6F9B9C36849C509EE1B6F3FFF7 +:10691000A4921FD8A2F071420F3AF4C76DAACF918A +:10692000E730A867A26CC06BDB175A76E2943FF1A0 +:10693000925A9CB9CFA144F97D0E2B3E69E55D3C8E +:106940007F6A6EC01EAFEC4932713ED74B71CA8769 +:10695000936C5215060E6E0B50FCBA509C9B94190A +:106960002A9DD794199AC64BBD08F9AACC881561FF +:106970007DF77C2EDF5B451CFF2971BE77409CEFC5 +:106980003D94D4A97C3C594DEF1F4BC6A8BE3F593E +:1069900047F5149EFF41FD916403957DC9383DEF95 +:1069A0004D3653F9FD64829E3F916CA1F23BC9566E +:1069B000716ED8466557D2A476DDC96E2A0F267B44 +:1069C000A87C26B997CABDC914B5DB953C40F53201 +:1069D000A3B1C143EB089E46BB56DE0AEBB6F91BDA +:1069E000183FB7FB1FB30E3BEFA55E9A2A72D4C7C0 +:1069F000B78C73B49FB2B7D2F17E52CF658EF713C6 +:106A0000BB673AEA15E6158EF697B42D74D4671F66 +:106A1000F9A4A3FD8C7493A33EFDE04D8EF6537B49 +:106A2000573ADE5F7E60B5E37D7E6CA3A3EE8FDE1A +:106A3000E368AF3D3060E23E4E99C062980F546803 +:106A4000B022BD90F42EE9D9CE30E859E0BDE9017D +:106A5000113F46EE2EA47651FC9E83AF919F07FA1C +:106A6000E633C22FBC1F87CF65437C87A2D1247F2A +:106A70004E3E791FB5B3EDDBA60790CF8F3BF707EE +:106A8000567C48B3F248C0FEE1F762982A53BBDD5A +:106A9000326FB7182FFCCDCEDCA3623199F67F633D +:106AA0003C4EBDA434F2FBC00A93FF13E38A78ED99 +:106AB000FC8287F2A2FFD39E3F356FC0599F7BC2F5 +:106AC000592F4D38EB45F57CBC413C8A731E26CBD3 +:106AD000945F1A3C3E71E6565A0FBF8FA588BC974B +:106AE000DB03DC4FEA4EF64EC3FB5E16FC20754519 +:106AF0001AEA77438F6868F76BF9F7020AF914F01E +:106B00005CD3747A1F2BC212FCC97400FDED939FF5 +:106B100038EC29C8F86D011DC6B5C1A5543BE15438 +:106B200075AE2F0235CEF5B8FDA41581F7E7278F96 +:106B3000D63FDA637D1F45DCCFB0EE7B966EEAE987 +:106B4000C7F879E96D1AE527FBA67AE3B8FFEEAA44 +:106B5000F136EC437F18EA5896AE4D6D463FA5F4EA +:106B600060C553E8175C752EBD00F9B5B4559B811F +:106B70007EC1AB015DE46B274A310E567A70976790 +:106B8000218C7332C0CF054A1B7BE87CA6FD697E51 +:106B90005EF3FCA91B35CC37FE63A48AF4DB99674E +:106BA000FC06C629CE14F1EF2E9C7966EE0B488CBC +:106BB000DF270F17D9BF8F71E6FB3F9FE383F1CF2C +:106BC0003CF5F33932E535A71CFA7CDD856373505B +:106BD000FF9B0B5935DE4FDBA0298CF21271BDE80B +:106BE000CBDCC628FEB9A744E9C2F14BC67A77626E +:106BF00019CCAB70DC970039A8A0B8A92CFA1DF607 +:106C000051BFF6178334DEC649FCF9C67009F9FB9B +:106C1000ED61BD3D8471C80ABECFD8788DE99F80F3 +:106C2000EF4F8D8D9950EFF0C0561CDF9732FAAEC2 +:106C3000CC7B15ACBA02E57691B6085382CE96733A +:106C40007D60ED4B834706C09740FBD6B3A800FAA2 +:106C5000B5C37E062809F5543BD6B719BC1E7EABDA +:106C6000750AFA11EF795B772D0738CAF22A857F0A +:106C700096E8C17BB677CFF5CE407FC63A27387409 +:106C8000CACFE1FE9944F989C00F1FB7C771F20757 +:106C90003CE4C7E4CBCC2C9CC9D883C96A8207DE0C +:106CA0001B11D8A41447F8FEB338CAEFB9E72F0375 +:106CB0003FC1AEDFE17FAFA9821E30BEBFC26BFA1B +:106CC000A6A3DDE0F62F9D5469BC87921A953F4E2E +:106CD00046E9F903499DCA6793B161E393B9CA6D67 +:106CE0002E7F65CF54580DCCBB479C4BFFA9C66B7C +:106CF000564DCFDDFFE1E4E131F59384F003DECAC8 +:106D000036F173D69CED377B3ED704FCE5BF538E3E +:106D1000EFE77AB3D47EEFB1D39728C5CDE1D9FBA5 +:106D20009EAEAF2F2539E37921B247D6508EA2AC63 +:106D300017E5AD34DAE3C17314EB3E05F91FF0E259 +:106D40008765EF1C2A447EA961BD0896529360288E +:106D50004FF3CAAB36A3BCB2A9CEE7073D5ECAEB80 +:106D6000C7F11642796F20FE5600E34A4575D2F707 +:106D7000A1FD3B7D7E1DE5F6C1E7FEACE0796FE746 +:106D80006B8A8AF1B3D2674F539E72A77740C17363 +:106D9000CF5050598CE7FF9D4AE2520C4585823D09 +:106DA0009D58DF5390F836BE8719173F1F05B9F17C +:106DB0009B5FC3F74A90990D6530BFCFFC2CAEB7EF +:106DC0009E793BD5ABE8FD78CC97BA10501677E3A7 +:106DD0007BE4B52B481D751A580FF37A68EB850EC6 +:106DE000136C9F3FC8F5040B71B91BAC6B50B7F91E +:106DF0008183CF65FE9CA9BCB4D6B5EED09F5F1849 +:106E00008FF9EACF7A7A317E54FAEC2EC22FEA2338 +:106E1000D43F079387B50E8BCE363F7C1EE65FA02E +:106E20005F9AF2A42A3DE4FAD177E74ACF1AFA66CC +:106E3000A457CA17C31488D63C6E4FE60DC03876E7 +:106E40007B268BEFE8B9BE43469F6C427A6DE7E73D +:106E500004A5B70D2818573F5867E64D83E76B56D2 +:106E600054CDDC0C747935E811F6D5CCABC7784538 +:106E70002448F70BACFC87B75CF90F6B45FE836FBA +:106E80000BBFCFB1A6A2B76426C6ED03FC5EC99ABC +:106E9000B0A8879D75EB3B590735335C04E5FA8351 +:106EA000BB26E0BD86F5ACE716BCC7C07E2A31D450 +:106EB0004FBFEB9F57F831A8AF833AAAF6757D33E1 +:106EC0003E89EB58B7DDEB45142C0C723CACEF035C +:106ED000FE09A1FC828200D572D0E8B95C465F7CD5 +:106EE000DBB38B0357021F571A9A1768FD70DE3FFA +:106EF00077AAE55057B44BD90CACFF0BF1D59A6B80 +:106F0000BCE2A30EFFF213A34ADC631887E38FED04 +:106F1000C4F3C4DA6695CEC34BBC713AD7614779E6 +:106F2000BE12B2C07CC0B714EEA0F39FFFE8F452CB +:106F30005E1A1E47E2FD865A991D96A1DCA300FD4C +:106F400030CFA94BA67EF0BCDB578474891D427DEF +:106F5000CCBAB93E9EFDAC9FF6ABB5ADC61D14B71D +:106F6000D1E6937F9389CFF17CDA4B849E9CABB1C1 +:106F700005B86F3B1BAC20606A9B6F5883FD26AE43 +:106F800058F67F0D1DBF0F9532E97CE8156E0F8214 +:106F9000DBE22D98372DFD3C14DB0C8FFBBC0B2F57 +:106FA000BF13E8D217E0F493C2896D3FC3B87DB830 +:106FB0008AD1FB70E2F778EFE26CB1AAE37942C7BD +:106FC00000ECAB0BF17D4C433A5E89FA02F1665E50 +:106FD000B7D8407DA724EE44797C74EB759D985F0B +:106FE00007789FA802DE1F095E4778EFDB6C8CD71D +:106FF0006CF5B97F013F80CE71AF237994C30FAC9C +:1070000041F986F73FC1FDCE0F8B98A00B7F5F5BE8 +:1070100069D5C1BFAA0338360B79C6832FD0FFB517 +:10702000B6F6F520CFBE85FCFD97603ECC8FC43808 +:10703000655B11AE8B99B8CF3E7BA99CDAEFE1F787 +:10704000C7F07ECAD5D2F24F4D85E7FE493C0E12FD +:107050000C733D1C0CEB645F014FB46F3CFB52287A +:1070600085F808865B7BFCF8BEBC8AF67D79293EF4 +:107070000E9648FF3C714FCFA32DE1FE67B5F3FBA1 +:107080001C7ED7F738641107955DCF1FA930FACB66 +:10709000A17FDBC012D21F7B82E29CA09CC799EF2C +:1070A0008E9B9FC07DE165677B17A2DB5073EEC8A6 +:1070B00073584E637F5888EA32A6860F61B92FC88D +:1070C0009976A6366311A9BEBADE43744CA60F9416 +:1070D000A2FE9A2DA5DAD1EF2F9CDF2BE13C636F46 +:1070E000AEBAC8F3D834E50B6C0F791B52746EF846 +:1070F00094B6C2D6FFAE3C715E24F4894FE37CDCCB +:10710000C67A16E0F74080F6FC3B2E42BFF844609A +:1071100053667CDF2E6B310DEF412DC8AF25FFED9F +:1071200084907FA97FDE75E86728A827A0FDC301AA +:107130001E6F3D5BCA7AD19F91A30623FB26F20501 +:107140003789792D7D81F957C614C69EBE76F242E5 +:10715000DCEF3E7D6DC942F4CB1F18CC373CAB58F9 +:10716000DF23A27CF4F431CF0570327ED0E0C5B4C9 +:1071700049F60DD978793CCAF7111FE9ADDD612ECA +:107180004F83FB7DB1EEA704BC9D3EAE0FEF4BF2EB +:10719000FB55CAB93C969A05FC27F4BA3F711BF11E +:1071A000991F6C1C7EAF4A65A68978B5F0A09679C8 +:1071B00059CA1EBF3D5740FD9F0AF279ACF3D35C1C +:1071C000E7C977E789EF930D392FD509EF9B06E9DA +:1071D000C2F7299BF28DB1A8A77FB890C3EDE683D3 +:1071E000B782226E72CE437058CFCF22BF013C8A45 +:1071F0009CA0EF5628E7647A6FAD7770BF36F89E93 +:10720000AFE36D8DDF8B55A25C5E958312F9792C0F +:107210002A9FB5DF3BCD43BF7B6246CEACFBB0437C +:10722000D7113B62207F55713D3B540E4DF277AC38 +:1072300075FA75E77B777ECA20DCE7C638D661C968 +:1072400057663D25F41EED09DD7793D95771DFB6FA +:107250004EE45FAC9380AF00FE6D3FE5F786DFB68E +:10726000F609CFF2EF90AEEBDB27F24074C7777AE6 +:10727000D61FBC93F6731B5E0F995E68BF1EF53276 +:10728000E06B5BDA7DFF389E1EAF67DA9F40050832 +:10729000F0BDA3B594A2BF1112F429F1A6257ECFAB +:1072A000F888847AA03318FF2DF7B39821030D3A9C +:1072B00007F5AAD28976768F92D1BB9877B827C87E +:1072C000EB469ED2D95143F69EDA87825FEB34CBF0 +:1072D000C81F10F53D9DE867ED51628730FE603EA6 +:1072E000E3D7D11F81FE06CAAB795335ED6F3A2B38 +:1072F000D938F40B9F2FE1DFD5EB7CC6BF1FE3E944 +:10730000F70612FEA06D9F75A6F817135828EB78A4 +:10731000A663BC0917371ECCDF8778B5DE3F5F72E6 +:10732000058D0FFD743A77293B720BDAD19267FC19 +:1073300014A77DD8E79477ABBC51C873575273DC60 +:10734000A35450BE91CF582BC9B53F5AE490674B18 +:10735000CE9573E359CA764E7D42D8F90C7F4DA085 +:10736000F74F09BA7625F511E6A9CC31CFE523CC44 +:1073700033CD310F6AE2C1EF9A0D13E775DFCB71A0 +:10738000EB45ABB4F4E24FC5F8324B7C210FEAABCE +:10739000077AAF46B15F126E28C7D4ED71C2EFAE67 +:1073A0003BB0EB10B263D21F7F02E983F929C8DF3B +:1073B00057F8E3A782C599FAC5CAC7C3A80B8BB310 +:1073C000EA419E0F2CF6ED9BF2639FC4FAA61D9531 +:1073D0009A39CCFECCADE7160ED1875CDF7D70F319 +:1073E000490E3A0E9D4FA1F719BB9660F63C7A6B99 +:1073F000FE4DA5C658E6947303E55CAEB0F40033C9 +:10740000512FECB6DE9BAF76D697A15F9D798FFEAC +:1074100059893FD31FBF03B43B68B57F337BFB3C27 +:1074200057FB4AABFDBBE4CFB9E1B1F40ED6D1FFB7 +:1074300093FFE21FF40F11BE5D5ED77845D678AC9E +:107440000BC7B3FCFE695BF35EC00F60EE0EF72C5A +:10745000403B7EF6F34CC7FB15DF9063C198CDDE51 +:107460004D137CAA9C0B38F09CC16F889EB3A893E7 +:107470009E9B4E7D62D87BD6BF493AEF59AF4A6C8E +:10748000A27B9FD304FD5A60E780E3B73C2C39E42C +:10749000F7EFF0FEADC07B690E7FA686CBF7DF1C51 +:1074A000BCA539E02DFB48E1DD1AE0FAF601512ECA +:1074B000D65AFBF13EC162DD43F70B1743DB4011A7 +:1074C000E6F382CF0BE562999921FAEE7F8AE7E72E +:1074D000431DE31DD7FDE50BAF7F9CBEFF11F5DA21 +:1074E000CF29FD6571962D7E8D7E37DEBBBF1FCF08 +:1074F000A3FD43DFAB22AEFF9589EB99FD1E4E4302 +:1075000048E02FC2BF73EBEE773E5F9C4BAB51AFB1 +:10751000E39C5FD41571DEF6FEE1B996BD665BCFE4 +:107520004D021E39C2B27E87677281F03F5483F2EA +:10753000E03AB4A661E3F9A387E32A075ED684F8AC +:10754000BAA51C78392AF0D2A525687FD815FDA0E8 +:10755000E070E2E35E01472E7CBC22DEB37397103D +:107560009F48821E5D62BFEA6E6FE55575A91F2EAA +:10757000DCBB47A0A39CFFD1D0F1B111E8685A70E1 +:10758000681F2E1C4F8F00C7B72D7E8A1A44970F95 +:107590000B8E17045D72C131D58243FF70F1F1F299 +:1075A0000870DC20E0581BE279AF5DD50982C7E2A4 +:1075B0005764F3AB8A72F33DC613ECE7C5C12AE703 +:1075C0007772D9EB63BDA3C9FFF8AD58DF4872F2FB +:1075D0005692E703BD29F0B03625D1794E4B94E79A +:1075E000958E345F8BCF2C192EBFFC8E94E4807F58 +:1075F0002478B684F879D5BA5E67BF3507F25C792E +:107600003426C7AF0BAF43E8F8FF393E7787B8DDC4 +:107610001F099F96BC7C54781C493E73E251E3F9E4 +:10762000641F341E4782E78551E37165377ED7ECCE +:107630005D7033307EFB777C666FBFF6EF7CF9813F +:10764000E0F131C4E328F4E5DFF1383C3C4F8F1A18 +:107650008F2B558C67FE5DBE3F18F976EF133F2ADE +:107660007CBAE7CD858F5C7875CF678DD732C2FC49 +:107670006E3C8E048755368C169FAEFDEE47864FC6 +:10768000D7BCFF657C8AF12E1A9F23C06195378D88 +:107690009A3F4D6A77407C9F60CAD7371DBD06E48C +:1076A000FF58C3AC59F49D34D998BA742A633B0A85 +:1076B000783EF21471DEE79E6F4701DF171C6D58AC +:1076C000B48E7EC7259E47FAE3B837F6B35ACCEBA3 +:1076D0006992E83CCCDDEFA8C0EF9A82B088F71B36 +:1076E000F9B3A17FD34B12DD63CBB53ED6605B17F8 +:1076F000DD03B4D1571A8AEFA34CDF518BE7348DE9 +:10770000D9E1B0E87C3CBEF4FDE9A1B8F4A1E8A160 +:1077100091E0B9A9A07294744E117E236CF0F72CFD +:107720002FE3DF23D67D780ED774D24FF78D5EC25C +:1077300047FCF77DFE5701B46F6A98C17F8FCACAB4 +:10774000A79419E59FDFFAC0A5FBE97778962DA5E8 +:10775000F65F17F19F2174B2F84BFCBED4D8E5A6B2 +:10776000CFFE7B4EAF1758E7C3ADE508479F625C7D +:10777000FE3D18FFE8B57EFAEE907F69E336BC93D4 +:1077800071FC33618FFD3B4C0705BFCD59CEF7A986 +:107790007D27123EAF6DBFFA928007FADF3C90055D +:1077A0007F7DA2FF0D098FC8BF37CA9B6C7957FF39 +:1077B000EE7AEFEEFF9382027A7F5CE4DBB9DFA71B +:1077C00045FFE6E6E1FBB36563C4EF361993EDBF11 +:1077D000DBE4C6DF9282C48B0550BEEC693D7517B1 +:1077E000CAD30295F898C9FA3484DBC2C36295758E +:1077F000E34F1A5A74BA6E7C0DD1C982C79A0F53DF +:1078000081307FA4D6E079454522EF73EEF6406AD9 +:10781000339D6B8BDF839401AE7C9AFF15E4875C0C +:10782000F35BE34664965660DCA0DF988CE75FEE7E +:107830007558ED8EFD79D1A710BEBEA35E6D4BC508 +:10784000D0F5BBF5D2E4BD4EBEF9B3E09B08C6311E +:10785000887EADE5CD36FAFDA92040FD2F969F0E1E +:10786000A00C4339F9C1569F0EE3DE288BFC6F183C +:10787000DFCE1FFB047FBD25DA47243378199EA392 +:10788000BDCCF5CB81FDF79467CB67392AEE25EDAA +:107890002FA876E4F12E6D9CD1893F4908FC528ACD +:1078A000EAABEFE815E5287737C8FCDCF480D25A5C +:1078B0003E03F95CD1D7E1B9E668D761E13BA71E89 +:1078C0001578EE3B11F7611CBD6619E7D7EB97F50C +:1078D0007BD741B94FC8ED696C6A1BE7BA42318F5B +:1078E00092680FC418AB2ADC795F7735C9399D7B64 +:1078F000D5173E701FE6B3B10EFEDDDAC9CBFEB080 +:1079000009CF55FB149E77F8D2FDF9294C68017E0A +:1079100075C4D923CBDE4B625ED94A253699E70977 +:1079200070FDF40E4B54171667F4D410BDD4B1D4C7 +:10793000FA1DBEC9763A65D6B945C0CBF9E940AA69 +:10794000A9F0561B3F250A15073D8E093DFF6FAE76 +:10795000F8D98D2778DC14D6417933BFB8B27C1FB3 +:10796000AE23D2F25E12F3EA13853C2FE6DD54E536 +:1079700033B85E6BFDD63A57EEBF62323E5FD6E853 +:10798000F693B8BC5DDF9CE77C2EFA574BC61A3ADB +:10799000A7FD14CF3BB0C68B3400BEA6E1BAE25BB4 +:1079A000F22B3278B6F0B9D2AFDF3EF8BB5100EF20 +:1079B000ADFB43FBF09E7C71FBC05DC847EF84E2EA +:1079C0008545363EFDACA06B865FB95DC47668B771 +:1079D0009A64DD97CD7E2D6D90B2C2ADF8636FB025 +:1079E0002CE7F683FAC0652F356F8F0FDB37B35660 +:1079F0002A8F4B67A93C29E861F53FC9D2F9735139 +:107A00000F354894C775B27569E14A58C7725F6F00 +:107A1000FE4C28EF12EBF8E52689E28E837E9C6B04 +:107A2000BE9BD74AE68DC06FCB851D5FBE96E7FF34 +:107A3000DCDCEA5C0FC8DFD16B70BE7FE0F31D03B6 +:107A400076A92B22FE24BFE2D554D10CBC8F710C39 +:107A5000718F7E46539EF8EE08A3DF274CF03FD986 +:107A60002B0DB7FE04F3E7B616F2FCFB630DB75E11 +:107A70008D4752ABF6B21F0FE8E83F0D6FEF13F7DB +:107A80004A0EBB3EF941A75F3B07ED4D0D4E9A2EC6 +:107A9000BFC5A64F7F13CEA3F96E58E6C91AD77D8E +:107AA000231CE2F0FC556AC9E6DF9D0F737D77FD6C +:107AB000DEECFDCF87F3F9FB87B3DBBBC5383FD9DD +:107AC00093DE72D4F3D737671F671526C3C13827F3 +:107AD000D7FDE666CCFF39EE757E37EB268DD37584 +:107AE000BEC6F5FFB1FDF77495225DD67B34BCBFF1 +:107AF000BE728C4E7AE3B36B6750FEE26CD17E7A35 +:107B000028DE5B08E5ED2736BE80EDFB96B398478F +:107B1000CFE803371C07851C5BF605ECDAEB68D76A +:107B200022F83BD3A8AFE454EC337CC9666111D290 +:107B3000DD5C4DDFA3DF1FD438DDC1EF85C689973B +:107B40009D7EECF32EF972D373D55E97DFE6E2D714 +:107B500057598CFC6BB3314F433DF0EABD52FAE309 +:107B6000507FA5316F9FFDF7492D7E3FD6386B1DA5 +:107B7000DD636CCCF3DAEF1FBACB9C7E6D63F6FD50 +:107B80008BBBFFC5FAB5C71A399FBF7AEFACFC951E +:107B900059FABD5D5831AA78C5ABF70E2F2FAF8AC1 +:107BA00075BD21D665F113FAD52B6D747FCF45973E +:107BB000E6DB9CF3DEB0DC39AF2527C7E3ED41F40B +:107BC0004B80DEE427597E2EEB983582DDE5E77D9C +:107BD000FF0F2BF7DDB70080000000001F8B0800AF +:107BE00000000000000BDD7D0B7854D5B9E8DAB356 +:107BF000F73C924C92996466F20E3384478000936E +:107C00001042A80893844828A81320109E1D1043F2 +:107C10009410A2624FDAEB291B0218D06AB094D2FA +:107C20004AED10D152EB23B1698BCAA10382D27302 +:107C3000B40D2F4B2BD6D852DE6A6AB5A2975BCF14 +:107C4000FAFFB55666EF9D84408FBDF7FB2E7E7E12 +:107C50003B6BEFF5F8D7FFFEFFF598132652DB9646 +:107C600047C8B18AD989CBE893FE53888790D91247 +:107C7000FDCB4B88CD41FF70C3F771F121FAFDDDDB +:107C8000B5844486137276AD8D44AC841C3775BFC1 +:107C900039C14588FA84E27F8AD61FBA63E9C134C4 +:107CA0002F74E37FB390BE0FFD4E2ED8424B2EE8CB +:107CB000673C215FC0BF29D167E80199446C382E29 +:107CC000F982FEBF62479CAE4CCEA498009EFBF9A1 +:107CD0003BB2219990B4DEFD9C07B8009E99B31386 +:107CE00043F6DEDFC5F33287FF2287BF2E2CABD6EB +:107CF0003184D4CE644FE378C6F6B566D5E3B84692 +:107D0000FF7785E97C72A3F00F040F2161C4CBAA31 +:107D1000367DBB957BF47870C9A4A18DF6B350690C +:107D2000334FA4745858972FDD459FCF25DAB0FD07 +:107D300073895E7C2E2424D08674F416558EA6E3B7 +:107D4000B7C612A990D2674B7C78A88F9013B34620 +:107D50000DD3C2338BD3B76A67FB468A5672C214FF +:107D60007CC40DF4FCBA4C9EA2E5774EBDB811CA96 +:107D70007FE93439243AC4DCEA92F8F1B45C744205 +:107D80002E9069F9768713C7AD9AB3D4ACEDB77A64 +:107D9000B97E3E558BF4F37989C35B6E23AABD008F +:107DA000B8AEBB30383A3ACF153B976E4AA3E3548E +:107DB000D56D9D08E3ACD871C03C82BE2F71B0F97F +:107DC000963A58FB450A9FAF8DCE379E90B7816F8C +:107DD00061BEDF90C24FC1DF4A9719DE0BB89634FF +:107DE0009C2B0FD8619E8CEFC57B95E361A5C38466 +:107DF000CFB1F6508D633CFEA9262611B24C6E28F9 +:107E000071D32A9F25121DDC9FC33C68258BD5FFAB +:107E100034C989CEA3078FF50C8F6F9F9AB5D15DBA +:107E2000D83F1E1BFB918F81F078A2353640609CB5 +:107E3000C98CBE1D16A2C2FC4F6ECE0AAFF745E13B +:107E4000FC8CC3E99AF3E95AC798281FBC7DCFB9C7 +:107E5000C520D7B4DE067B12831FF0F51D27C303B0 +:107E6000E9A2F2501495873FC793EAB63EF8F90F9E +:107E70005CAE8CF273FA2EA9451E83CF707242EF6E +:107E8000FAFDC9C5028904619C3DF75A6B5BFB187A +:107E9000EF38A7572FFD0053A0E510FF7BC59CA529 +:107EA0009BE2E9D4D7C7254C86799E368C7B9A44D1 +:107EB000E22700BFCC91FD40A7D30D4C0F2E328797 +:107EC000E30BE8B8CFF371FEB046AE08E745F58C9A +:107ED00071DCC5B5B23A8FCE7311D7278B6AE5F73F +:107EE000E0B9B8414FBF932478EB78186F261BEFA9 +:107EF00084A5E5D6224ABFE3DFCA2950E1FB9CEF07 +:107F0000C42FA3E3BEC6F9E138F0A91DDE33B804DF +:107F1000DCFF61E0975E7AF454AC9E4F38BF9F0857 +:107F2000EAFB79CDD08F91DFE61AF86D8F259805A1 +:107F3000FAEFE4AE458BEF07BEDB15EB1FEAED4D24 +:107F40009FA79C32831FF853A37F3A2CFEF73B5C1C +:107F5000C09F69FEF5DEDE7C797C6653EC52A0FBA7 +:107F6000ACB8DA303C79FB3F95E6B6CA14D43DE1B3 +:107F70005908FF3E27835BE80BC2EDD642547D5182 +:107F80003A093BF527AE3756EC78CFECA5ED978054 +:107F9000DEB073267141FFA9BBB650F8DE3671FD25 +:107FA000F1747CF8295F74BC1EFBC1F9A13F7D3FD1 +:107FB00090FDFA7DD85411D68C5BB3D3D70AE38AEF +:107FC000F2A235AC2CE0DF1336E1FB4F1A1371FE41 +:107FD00027663D8EFCF2C71FE414C8E406EC5BD8AC +:107FE000F42FB16F809F6BD9B7114E1FE26B20FB4E +:107FF0007696900AA4C7D53B1E9908F3FB6632FA21 +:108000000D6777307E4DE7F4FEA3A56BB416BEB3C3 +:108010007CBEA7F97CCFF6E0379400F64FD473729C +:108020007DF6472E077F6CD4CBC170A79EAE2B7612 +:10803000E8E15DDCA087B7D0E960F03436C5825E48 +:108040003921F8A64646BB73225886FA7D0FE87799 +:108050000D9E0B9D37266F0B24F56EA03FD915EBB7 +:10806000007E74015B80BD3CCFE8F8898DF1FB3F59 +:10807000607E7DD88F1EBD7C5E4F77F023B478DCA8 +:10808000E1F0EAE6BFB0560F17E9D6B73F6E62726D +:10809000AC6E8943BFCF6161703A5A631D2AE3E732 +:1080A00022B0833DE31BDA2F50C2BAF117733EE9C9 +:1080B0006FFC81FCA81BF523DF25FE55683767C6DA +:1080C000215EDF7D408E4CA1E5DFCF8CDB25FBFA06 +:1080D000F22BC7AD02FA7E3233CE0472D81F1CFFDA +:1080E000AFFCCB771F188776C358FF41C0EB75F8FC +:1080F00097EF3E706DFC1AFDFEFEEC498B418E063B +:10810000E2EFC7B81F78FC1F32DAB91341A6FF7B34 +:10811000EC06F76B841FB3ECB6517F2794D53BF880 +:1081200038353B2AD1EF3C6E0A6E8C077A1E333904 +:10813000801F8B4EB1F8A386FB57029ECF12F5F03D +:1081400009FB3390FD34CACFC9AA070B60DC9355F5 +:10815000F3747EEFDC2B1924921C2D57554B01F044 +:108160001B7AE435464FF7371C161CFF0DEECFF691 +:10817000B4BB928DFD08FB56B3E39E4D69141F55A9 +:108180000D5BD3B4F3D9E16476EDFB4E368F1E7FE1 +:108190005861FEB0BBA9EBFE206DFFB13D9898A4DD +:1081A000A1D311831E3AC9E90BF580FFAA94A0B9A7 +:1081B0002F3E9C3B4736E827E6A719F591A87F8A12 +:1081C000EB5DE338467C5EEF789F273A84BF7D966F +:1081D0008062BDACF74FFBE3DF9E710DF58DE3BE12 +:1081E000E5D4D3C138FE13E0FFBBA3FC6A1C2721F2 +:1081F00089E1B56807A3FBF1DB6E423E3C31EBD56C +:108200004940B7771FF8DBC979A067961F9E04E045 +:108210002724C563FD77E9945281DF4312FA85F381 +:10822000762C3D9C8672F9378CAF8F9FC8413EB645 +:108230002731FE3D6EF1EBECA0513EB770387FC4A4 +:10824000F145485B5630FEFAF1F5877EF075A3766E +:10825000634B22B393E4EAB8D1600F1EE981279201 +:1082600005E5FEE279F1A41861F16999BD594A0466 +:10827000FF31783FE885EEAA78472B4545953530A4 +:1082800003F4F8C96326D33A0987453F7016617C29 +:10829000E8FBAAEFA191F4FBACA01C00D1AB843A9F +:1082A00013295D4BED2AF457787CE64FE3212EAB82 +:1082B000B67A41EF574D09BE2F43DC392FCEBB9E16 +:1082C000D62DEA1CBCCE45BFCFAE901CD0E5216AAE +:1082D000D7BBE8FC9F81C257080390E2E68428AB35 +:1082E00033374FA5741FE9EE30D9698BEF3F3673F2 +:1082F000B38DF6BB715D301542E5AAC7466CB66515 +:1083000011E2F1043AA7F8E9FBC7464D8772C70F9F +:1083100044FBBCCD814984BC620AF924FAFDF9C74B +:10832000CAA62B143F8A3435DF44DBB7253D86EDE2 +:10833000E7CE5D75E7CFE9F7A38FD54E5768FF45C8 +:108340008B44FB55D3CB8650782789F23D3150764C +:10835000C505BDA67C42A63D96335D81F19202F72C +:10836000105ABEF4580EF6571CA275D361128DD860 +:108370005EF4574EBFAB0A25516319F93325557189 +:10838000972A81BE7BABA4A14CA1E30F4AFEE6E68F +:10839000BC11844CA8288923B43C2C79EB746B3E27 +:1083A000D02990EFA5CFDCE46DD87FD12275247C55 +:1083B000B7A8DFDB5C41DFD7E78555A0CF1312E319 +:1083C0001F73635BB377302171E6063503E9D8C2CA +:1083D000F826D33F0CF944947369395E534E65E532 +:1083E0008EF5E46BC1BEE2D264A67F3A62FBFEBEAC +:1083F00056C8EB2282F29A788A049EA5CFC3B1A414 +:10840000C346EDCDED5652584CE3E2DA243BE75B30 +:108410003EAE8DC125DA11F5F6249093998C07F1C3 +:10842000FB2C0AD7BF7379CDF1733B4022CA6CD0C5 +:10843000CBB209E171CBD2D72AE97B4F2C09B5D356 +:10844000A73B996079262181767BB4DF3778B7E541 +:1084500039C1DDC0FFE52969F94DBE683F14DE0D65 +:1084600000AFC82751B81580DB2DCFCABF274F03F7 +:10847000771E83BB2389E1830EF353F07B3A3A479F +:108480000EDE42411D97A497E7A2CE0233A1F58EDE +:108490002473B9F5B2F6EE3282F6B9FBDB316190A6 +:1084A00043620BF9839A3C4B0B9F77DD9511243C7B +:1084B0002EFABE4E8958407FD45DC9C3F7EEA6BEE2 +:1084C000E942C83A84B7EE8A93A8E3B4EFD9FCA294 +:1084D000FDB8F07B7FF05080517FAD717204F27E69 +:1084E0001B098BFFD6C4075292AEE1F7D45D91FA17 +:1084F000815FC1F7BE418474021EE97B9217858FAC +:1085000078BD68DFD638981E5AD35E9242EC1A3A8C +:10851000289C0E16367FC0B349639F7FC5F972B69B +:10852000E02F6AD741CFDD919E87F161C7E765A350 +:108530002AB1BFF558AF4361F15391C2F46151675D +:10854000924395A27C21F841D0B323A9A104F1550F +:1085500029395A7DBDE7FD1AA75F5190F22DAD9FD5 +:10856000B228242FD5C027F8DE282784FC90F109F3 +:10857000E5FFC5209710D701FC7E2A0FA3B57464D0 +:10858000704F4862768AF201A35F9A3D0CF008FCB6 +:10859000F4E6878C01F8211BBF17751EB4C03CEBB5 +:1085A000389C29A72209A3F2D83C56D2E77E484638 +:1085B000D176372531FBD4D15636EE263A7EC736F2 +:1085C0009900FB1409FD49DEFD7529D57F293D651C +:1085D000827A8BE29BEB4BEA1ED8A2F5DB93DF9D00 +:1085E000BE4189E2C705463E290A6F39A7EB349898 +:1085F000F778C49F6A4BD2C92D292E88EA1721A784 +:10860000A23FD14F6232EBC7CE9F3DFA87DB3DAA36 +:108610006F300F481E8E41FFF9CBD73BD2007AA7AF +:1086200092EB1DF6FE307573A19EC7E31F26519C89 +:108630001C3B523614FCF87B5365EF196A57E64829 +:10864000A18D80F8D9A7FC3564B0C6FF2236AF9D56 +:10865000FA134B69E52FE8B8733A635599926E7631 +:1086600030C66BD7F8651FB548C867F7D210B4B1EC +:10867000A0377FDC9B6AC1718E55E42486B470718B +:10868000FCDF0EF95BB9B77C8A3285BBC694A3F9CF +:108690006E6776A7252130229996979B4808F97C2A +:1086A000AA5BE7CFDC9AA48F37843FE34C0CF8A198 +:1086B0009DB17E7FFE8F1BC250945F960F4A698EDC +:1086C0000F03BE52DA0897CF88A90EE8281355A2E7 +:1086D000F37F35398BF98955F4E3D8687FC7A560F6 +:1086E000A6047192DBEA873C05A50BCEBF5CBEE712 +:1086F00080D9057496FC4D74D460B293DBBBEE4216 +:1087000098A73B8EF1E1E118628BA1FDBF4E9F4817 +:1087100077AE977E9B3DA215EC87D0673D7AF02A15 +:108720008BABC5F7C35265A683960FBB87E7374966 +:10873000D81F89D1F03FED97003CBFFDC77D67A6EC +:10874000507A9807B3FE5C74FC591A399850C1E608 +:10875000BD2499E17749721C3ECBE3587F877D9415 +:108760004D609CA1743E541E5E8B0DE535205CDF90 +:1087700066F4A47C0FFAD2C3E9E6B1B0F2CF5D4C47 +:108780009E2E71B96AE0654F02AB67A4CF61175F97 +:108790001F93981E7BC8FE6210F848F835B1B606E4 +:1087A00002FC4C314A809FB694D0F9F4D1CFDDC998 +:1087B0002C7F43ED18CEB7B75D61FA6F83146EC995 +:1087C000A172B0C1CCF2F08F38C28EA43EEA5BE257 +:1087D00068DC9817B543C27FFFA4AD3211F4E256AE +:1087E0008E370B8F2F051C1B78BE23E14A1CC69FBA +:1087F0000F73FF49C93D8374568A6997B4A99904D8 +:10880000558786CE668749E7F7275C49C0F67557D6 +:10881000C69170F2B5F475117E27A95E5D9CF1C911 +:10882000E97908A7715E46BC4538BCA21CC855A6AC +:10883000120D5C25C4B101C62921FAB8A43FBFE3DB +:10884000F964E1B7C83A3B1385D7A27B1FA1F19623 +:10885000AA1DFF3C1B3F3A6E1C5135E3DE9B1C7882 +:108860002119E56A92E3EC28FAA0FCFE858CF683D8 +:10887000D929FADC6567F61CF4B28857408E1D349E +:108880005EB939B9E497D0BEC7BEF176428F249E57 +:108890008AFA73126D7B33B73737733BDBE3F72903 +:1088A000CC3F157077733D25F44D85EDD5B1673418 +:1088B000F3BC3999F1F31189F11D35E859D09EF2D5 +:1088C000ABAAB5DB467C1EE57254772546C7075137 +:1088D0007CDAF1FD97E507164D0AC9A3215F5A21FD +:1088E00091A1F431612AD313A2DD5F92EDD8EE2F6E +:1088F0005C5F087D326B91BEDE055EEF02AF3790A4 +:108900009DD6DA092927AA9FEA39FD7C178F59BC21 +:10891000B45E8E8BF91D575D816ED0FF4A6CC21814 +:1089200042E9BAEBFF9479D751B8BBDF34FB5BA1C6 +:10893000BBBD8C9E25F3D73429F4BDB94D72C0B2AE +:108940009380CFDED83E76399DEFFF16FCEA62F3C6 +:10895000A873452C43E8B8E9756CFCCCB60392A229 +:10896000919BCC5A564F719939BDC3EBCA0BE17D2F +:1089700040D942496CE3EF2D80430A5F7A9B8479AA +:10898000EDF4063A714ADF743FEBD7EE0F4B77E414 +:1089900045E7D76CAACC03BDDEEC89F3835E2F716B +:1089A00087125C409FD39108B8E1134E772A1037A5 +:1089B0002E7507125DEEE8FCBCB2231DD64DE34ECA +:1089C00033B85A92F47C40352AB323A495D94199FF +:1089D0001C017F0A659C8EE7599F8B7645D4F7244E +:1089E00071BDEE21A117D1CF21CD04E944701E9EA7 +:1089F000F5C3F87A0BA363D4AF1951007E4DCEC3F3 +:108A00001105F2A82FEF64EB08467E1CCDF53D9DC5 +:108A100047AE761E03D96F51CFDC4F1C2AF83C8E2F +:108A2000F34DC97CD702985FDD865FC45925A0C38A +:108A30002E290EEDC023584FE09DC23111E0107C6D +:108A4000A424ED9132E87CEEBB8B3864D23F7C7578 +:108A50008D3F1BBB5C2B8F1B2C88FF5D16FDBAB8AE +:108A6000F0D32B5DCC3E6D73072B80AEF57BB75AF0 +:108A7000809E77ED7ECF12EA432FF7B4BF4EFC48BD +:108A8000B5CCFFAFABB68561BE25F315A4D7CA0D33 +:108A900096B095D2A5EED9F68809FCD907881FE4CF +:108AA000BAAEADFDB5748A9F8CBAC078C88B7928F0 +:108AB0009375E645ED447A5D4402BB9BDEB6B40E89 +:108AC000F93735CE0FFC0B7E28F807974BECAA44FC +:108AD000FDA2CB6635D74BBF5FF6C5FA61DDE2B5C7 +:108AE0001826E702BFAFB74F3B2251918D7FD11AB5 +:108AF00081E752776825E07BCB3A6F09D0674B3925 +:108B00007100DF50BFE35E289737D909F0FFF5CE3B +:108B10005BE809F17EC2034C0E7EC8F504FD5700E8 +:108B2000FED74617CB13527F05F5CE6B6606A7C25C +:108B3000E1BC941CF826F22308615A74FEC6713514 +:108B40007CA3021DAF1FCE360BAC9BAEE4FAA36430 +:108B5000FE6EE9CF1ABA3F0A810EAD97FEEC2EC920 +:108B60008BFCBB7B5DB90BEB13AB17DEB3FCC74AC9 +:108B7000FAFD4E8DDE10F3E8437F6C87F9D84F770E +:108B80001E62FA2382FC26E0157414F46A757911CA +:108B90003FB750F38CEF2D94AEB4BFD706C7627FBA +:108BA000429E8DF2D7CAF93ABD7AB76442BFB2137A +:108BB000E7B9AA5A41BA1C9CB76439D075952B2DD8 +:108BC0001FF870DB2F8F5A24FAFE0517F38B56B56A +:108BD000486C1DB9E5A8A50AEC80FA1319FCAD197B +:108BE000CCE493ED3F3F8A7A7F46078BA35775B459 +:108BF0002B77D8A3FCE7BB787009F0E7AA362B895E +:108C000091802ECCCE1AF98EEA059407A25A309E96 +:108C1000033F1FF52009F9C00E0BBD7989FB91C4F4 +:108C20001E2C34817EF48CCE077D7790CF53F45F79 +:108C30001EEB3F6803BD57C0FC7D619F0EBBBC426D +:108C4000CF46506F52EF15EC9BE8BFB7BE1F5500E3 +:108C5000F87D9FEB454AB737FBD2FBA27FDF13B30A +:108C600088375E430FC0B3868F4EBBD87AC86997EA +:108C700082F02AA50C4F8A85CD5F596F0B435EE3C6 +:108C8000756705C34F920DF173D8B4AC0EE8743814 +:108C90009DF14FB3697D6E03B337EF001F1D9C97A5 +:108CA00040987E61FA64DBCF985DAB53ED1847D5F1 +:108CB00085E6209D892BC60FEB812474C852151FB1 +:108CC000E537235DBD2F1EB0C03C66B431BE8EE2D9 +:108CD0002BACE343AAA790DE9792791E9CD20BF0AF +:108CE00029E2DE445B2462F6F696BB441EF786203A +:108CF000EE853CB49F95E15F5FF1AE1857B417F174 +:108D0000EECAC6FF4A83E7DDA9BFC627C451107F5C +:108D100088B84AD4B7B8999FF6218F77E2399FACCB +:108D20002C6C437DBAF24C03CA85BD82C9BFFDB429 +:108D30005E6F89B88A460C3C0E6BBB05F2E8E53FD6 +:108D4000921C4DA47FFDB202D68F406F5FA55E30AE +:108D5000F5FFEB0CEB63596EC6B7E7F65004A37E44 +:108D60006F40BFF7F24E09D753AFB73F1239210119 +:108D7000FD56F2F8E2F2B36513FF02EB2D7B1271A0 +:108D8000FFCAA567677FE32F14DECBBBA7F8C16ED0 +:108D9000BA9A82C80FDDEE183FF8B554BD55405C55 +:108DA000BDAEEDD504C8135DF8E9D802D06B856E71 +:108DB000A6072EFE4C6E047CACFFF10B93E1FBCAC0 +:108DC000B0940CFEDAE53D3FFA07D8A9DADDAB61D5 +:108DD000E70869FAE9AF2CB07E600AEF62EFF7248A +:108DE000A25F77E1C9AD9301CF4D6D4DF8FDE293E0 +:108DF000BBB07CF0C72FECFF1CFC8060821FEA5DDB +:108E0000FCD9D66F7D0E7C3B27C10FF3A80B296CD4 +:108E1000BD4FF0AB51FFB41F40B913FC3103FC3917 +:108E2000E0F36AA647047F1E2B61EB21B34AD93ACF +:108E3000CBB1E931D5E8BF72B9AB5FE0DC05726751 +:108E4000A2F84BA5EDE7CC74EE8275F0257CFE759B +:108E5000798C1F9A29B7407E202E2F62C9A0F5E693 +:108E60002D6A9F0CF86C8E25C531C8A7909C8CAEDE +:108E7000CFCC6E79FD3389D27134556767297FD3A2 +:108E8000DE767F41FDDAB7CC2C0FD0CCFDEE798BAE +:108E9000DEC37507CA008EB322EF235FCB6E29D8DD +:108EA0009FA8D7E387713C34F3BC07ED1FED48D191 +:108EB0001A9ECF949635C13AF2E1FB2393806F5FFF +:108EC0003E7F6F6C5D9E96BF59FBF40E26F7E9B5A9 +:108ED0009DB7C03CBF9ABB741C0CB38AAF93B8203B +:108EE0003F06764EB5EBF4DBD7DD4C4F7A1CC4F56C +:108EF00015C8BB28C405FBEECA09396146FC3C8590 +:108F0000FD7BADCC1FF2FE6ADE53B0AEB5DD1C4A70 +:108F10001B0F76A999DBA7DD0C5EDADE01EBE2B46C +:108F20003FC7570AB09F4E7312B65759FB69BBD95A +:108F3000BA5898C3DF9D0D760AFA2BB4835D51AB06 +:108F4000D1AE782D7EE0878B50250DF13566F1E8A6 +:108F5000E8BC8D7912D063B0BEBCCD5DF2A87B7C3D +:108F6000F429F22A467A1C83EF74DE899E00D62308 +:108F70007B92D18E0CE4771C9CF781A58B8EBBED88 +:108F800095F7500FD503BFC3F8A1333A7B2BF8698F +:108F9000FB4BEF21BFCFDACBE853BFD7678638E56D +:108FA000D2DA00F933751CEB397F6F97BA6A70FF1C +:108FB000C74B310EC8837DC0F97F65C57B67416FA4 +:108FC0000DDE9BE685F8F98397981C1C3699109F57 +:108FD000875B47ED02FB42FD5564E5FA066FAB1572 +:108FE000F1CBFCF792F9CBB7423CB5AA96F8413FDA +:108FF000D47754667AD1AE5811BFF57B8F22BF0863 +:10900000BF95DAC3E5D0AF93DA9D1888AFA6063BCB +:10901000901EAE78ACEF9C1ADA5A8EFC955F04FC79 +:109020007570DEFE4D3618772A7140FFDBB3022FD4 +:1090300065E03C2402FB1EB69B5B4A15DA7E7BB9D9 +:10904000D7413148F1B53B15EC3CC9B570BBB61CF6 +:10905000FDE1FAD4857E889B7AE98B97D6A1DF540F +:10906000EF8D457866EC95EE657E879D30F825E4BA +:10907000CB19E19BC220FFEF73BC09FC7D60EE5C65 +:109080000278F9E0E79401E9F71953199F3AA7B676 +:10909000A19E79FD25EAD78C89F263FC2FA87F4336 +:1090A000CB498A43F2A39CCDB66AE9D9626676CAF7 +:1090B000C9ED4E4E05A3EB692E47A7B9FE39EDB6B3 +:1090C00070FEE6F959873A06ECECFB9CEED81DE8F9 +:1090D0007FDEEFAAE51194A3BA67995FE6B206F2C4 +:1090E000EFD3F0ADAB8CD949912787BC39E6CB21C2 +:1090F0002E71413CEC6D85F5624A3FA4EF575DC38C +:109100000B005F5F703B9A9E2B61FC46FD35C49B54 +:1091100067FE6EA5268FE5D9FB8AFF640FCFFF257A +:10912000070B213FEB4E89473FC62D979862C00E33 +:10913000E54BFE562FAEE761BCDAED4EF3B7EAE43D +:109140009AF97BE73DF18CAEE1DF2AB0DE92E8F1DF +:10915000B27E0DFE5CEFF837C60F71CCCC16750CE5 +:10916000C40D22BF2FE61D5E175BADD563311E36E1 +:10917000CFF008520D7A81FAE376CC073BE838103D +:1091800067B7DEF4248BB39B903E1FB9D9FA6139DF +:109190009D1FF865EE9CE01A665FE3711EEE1CB23F +:1091A0000CDAB99B52A5269F16CF0EDC8FB58DD356 +:1091B00059F8E3F5545ED08F7B85F1633DF871BEBD +:1091C000FEF54394BF997E98B197D1BD7E2FB37FB2 +:1091D00022EE06BD07FB06414FF8C646E5BADED2D1 +:1091E000350CF853F079FDE4AE61809FFEF44379CD +:1091F0005C18E5AE7CD430CC2B887E3E307B71DDB4 +:10920000ED031A37A21FCBE521FE652607822EC685 +:10921000F805E0823850E8E7127770A207E032459F +:1092200036C1FABFD0A7F52F6FD6EDEF37EA539BC3 +:10923000C2F4962D1C176ED2F00FAC61C517E01367 +:10924000F759C535327CC4E57955C4776EE7CDA0B2 +:10925000AF88CD84F87E28EFC473C067333C76ECCA +:10926000F70989D1D7BAB712D2A1908761F14A6BB9 +:109270001CEEA315F918235C933D4C8E05FE459C0E +:1092800001F976A8BFC2C3E8BE80F35B8347D2D999 +:1092900071C1D75E53E83DC8BBF7677F44BB2F2B36 +:1092A0003F24C61176308AE775BAF502984F655E9D +:1092B000FFF55A0E303D23F84E7C5739BF1751DE6B +:1092C00085E7F322EF5AADB07C7E0CD1EDB312FDF1 +:1092D000F5C4E36BAFBDBFDEF10F99AD5751370356 +:1092E000FAC33C02886F69851FE6D7CCF16D6CA785 +:1092F00010E5E32EE157F934F0709F0CB61D4DEEEA +:1093000063FDAD67DC49FA75821EBFCCD04F7F701C +:10931000371BF2FDCD39FB09E49FE26C095C7EAF9F +:10932000A2DFBFB9E73C80EAAF447DC7F258038DA6 +:10933000638437C6DB37BCD74B8F66537B2DF0F386 +:10934000F39C1E64DBF5CDF3113ECFFDB09F0BDA2D +:109350002D5274EB2376BF771DE485132779F3D163 +:10936000BFE6FB31E32793BFCA945F275F69C985D6 +:10937000F31FEEA01EFE946AFDBEC6B45092AE9CD2 +:10938000519BAEAB9FD53058F77D50E348DD779FBA +:109390005AA02BE7347F45577F684BA9AE3C7CC76A +:1093A0005775F5478467E9F78BAD6BAB067918B550 +:1093B0006781AE5DA2D245F2E9FBD16DCBF4F4300A +:1093C000E073ACE06B5B5781569E2E7A06233D120C +:1093D0008BF5F89872C5B0CFF306F963EC5E037FA6 +:1093E00018DA0BF98A238C3FE2F635FF15D6AFE386 +:1093F0008C72C4FB1D43DB4D4EEAA3DF7EE4647D2B +:10940000DC1205F87F3F1434FEF45B06F92FAF4EF3 +:1094100064EB4457660DE0773339996B65EB8773DE +:10942000F93AA2F83E3285E985C129FC7CD075F273 +:10943000F329CECFC7FAE367EAE67AC05E54108C10 +:10944000C71D15EBFE0A799DF94A84E453F9D9C684 +:10945000E7B39DB7DFB1D681FDFD606D2A3E77AEE3 +:10946000F5E2FB27D6E6E233BCD68FEF5BD716E3F7 +:109470007337F503E1F9F4DA0A76AE626D10EB3D6D +:10948000B3B61A9FCFAE0DB1733D46FA5D49427B2C +:109490003B97E8F5DABC6AF9BAE8338F3CDC292758 +:1094A000F4C647AFF6F2A26BEEBF6E3C9D5F71480B +:1094B000C3A71353E25DB87E38814CC0F87680F6BE +:1094C0009FAEF5571C1A3A307F1BF9875CBD6FA819 +:1094D000761F8E78CE05864EA76296B2F521352F7F +:1094E0008AA7FEF9AA6FFC046C1FA443D03F06ECC8 +:1094F0008FA6FD0103FF0694445D1C2D9EBFE47CF6 +:1095000058C2F9B5C4C0AF3B38BF36FE7FCAAF07FB +:1095100063E2D12F3F68F666BA35F43F181387EF40 +:10952000492EF1CEA1F4A35EB2C307EB062966C4AF +:1095300087049109E68F8738304F127383F914033B +:109540001E25EA57FA687F250AD35F126C3882FE1F +:10955000FDA6A87EC57D10B151BE977BF303ED47F4 +:10956000B5803FB6AC6B01F873EFA47875FB674A22 +:1095700015F99AFABA14E4AD8FBC60AF7637286F4C +:109580003F06798BFBD7C99BE07772356788761FDA +:10959000A5789670795B92B20FE54DF07B29D83BA8 +:1095A0000D1C6F717E7F2B85C59307B99F02FC51FF +:1095B000D087BFF29B14BD9F77A3F82E214C2F12AA +:1095C000D2950E7AE246DB53C951A05D892D418DBB +:1095D0001B73E3EDFBC367AF767B5DD7956FA29AF4 +:1095E000460239AFE1D0D5D8EC2AF013D961BEDC00 +:1095F000A5E1E3CA84E085145A7FAF99EC85F509AB +:109600006AE6BD0E0FF23DE295FE0BDA68399F97D0 +:1096100027A892D742F9C64A0B8D201F5DAF7D0661 +:10962000FA229F3F27F027A45B53416EF2E2711F9D +:10963000BB5FA089E74D8B44712AD5BD1EB12511B2 +:10964000FA25D29A2408635A08ACA76F91FCCD3250 +:109650001D4F4EF1350150E32A4A648247325BF0D8 +:1096600039897436C192DD64D22D43FD9B2AD426FC +:10967000807310B9EA403E4F797AD517B02F079220 +:1096800093D781B7461B5B7FFE34863DD552C2CE51 +:10969000C3FD31260C71D30C1272A4D27AFF2607B7 +:1096A00016C3F89F9A1CEE03882CE54F5D98F7953A +:1096B000501F94DA0BABEF443966EF11DFBE683D03 +:1096C0002CCBBDCBDFDDC8F2104D9B19BF37AD638E +:1096D000E591A98CBF07F167612A938B18A2AA04B0 +:1096E000FBA594F320FE18DD7229DE8B181D10AF48 +:1096F000F623489758D28678DD5CB53DB411BF2C6F +:10970000C2FD3B522448BE88D3F2CFF5F567B3B50E +:10971000046C948F62ABDB22E66BF4A7805F48C7D2 +:1097200055E65870DFE31352E82BA910C79C961436 +:10973000AD5F69260D44F269E1B86EBA945D0F5DC4 +:10974000CCA5FECE0065C1AA5809F7A7DC287D1676 +:1097500001538F8FB2F2FE34B20BF207B52E920A8C +:10976000FB132D761BCAD9862C966FB08C24783EBD +:1097700098384CBA798A7D7482FF283E1602FC968E +:10978000B0F41EE0C792DA80F12051BA32A0DE7E3A +:1097900089F181916FEF4C1579844CC6EFE4DAF6CC +:1097A000AFFD56E7DB2E14C66766BE514CCB25CE07 +:1097B000852E07F55BBE3F61269CCF683F4A501857 +:1097C0006D69C16F837E6EAF723EEEA6F5D7FEE087 +:1097D000FCC3662A3FED8B25FCFE057CA7FCF976D1 +:1097E0000969833CD2564FE83E807FC11BDEC370BF +:1097F00084B4FDB5BBB3C1AEB8CAFC5D780E65A13B +:10980000D50BEB4F6D90C70446B94AE1A1FCF42497 +:109810008022B3F2145A9ECF512BBEEF86BF29DFB0 +:10982000E42CF7AD73411E72A7E4003F65D04EEA09 +:10983000B7D0F2B96F9371903FEE4F6F4D106555F1 +:10984000C2F3F4371BBE0BBD3664F93DEFFE3BF4AB +:10985000DF29E3BE0CA99AADE74CE0CF9BF9339F1B +:109860003FE72F67EB4F43AA278421AF77D6EC6DF4 +:10987000B2033F8E26788E94288C3FDFCA728621F1 +:109880000F734E224D90475337133CD7077205EBA9 +:109890009DFEE594D685E032DAC290A73FBEB66D54 +:1098A000EC06B3467F52DA048A585A87C19D877105 +:1098B000D82412FD07F3288FCE0BF9EC165E9E56C6 +:1098C000C7F272D600D5AB60DF0CFA388684536DD0 +:1098D000B81FD887FB40E469C401F06657440EC244 +:1098E0007AEEB84009EAD5F124F46A277D4E0CB42B +:1098F00063B9D8166E82294E81F172C07E7A15A0A6 +:109900006319F570A15C415AF0F955D286CF99A43C +:10991000139FB7916E7C0689C30CCF03A93EE4DF89 +:10992000C936AAE707E3BA1CE6E50A7658315F3A7A +:10993000AB2264F1F6E19FD488F38124948D7960A1 +:1099400025943D57E36F9C9D3F6F31DC8FE135E9F6 +:10995000F7BBBECEF5E6512E37DB25AE4756897BE9 +:109960003642DFBF939617560CF7C3B96DFA1DF355 +:10997000C0EA7C1BE6FFB69BBD59E87FC0E530908E +:10998000B7AB6BFF379200EB8C2BD2405E6B366C23 +:10999000CA8238A066263F27A3A859551A393FB76F +:1099A00094C125F63B88F77FE07A1DD7AC285CE7A9 +:1099B00028FCB84E28F2790B9CA867CAA9E300FBE3 +:1099C000D12FF07984B95E10F2532BF840512DE974 +:1099D000B4DD5CBFCF0FFBE11684599EB85C21114A +:1099E000F49705FCD5BBEE27943F16D41EC0BC7E71 +:1099F00074FF115B9F2E99DFB118C6AF596E2556C3 +:109A00005C2F6A7907E4795EADD50BE59A45528003 +:109A1000ADC3DAC243A1BCC3B711E474DE03013F96 +:109A2000E459E978988FBDC5C6D6296D747C58D79E +:109A30009B56CBF785D43ED809FC49EB05C05FBEE9 +:109A400085D657E83393B0FD74B12ADB9F143B955C +:109A5000ED4FF25A1B0EC37D24DED5C4AFD261E7B1 +:109A6000EDDC25B17DC504FDA981FC9D1F3E78D5A7 +:109A700089F126F80583E0ADCAF2C98DB217F689DF +:109A800012C581FD2CE0E73F9B6B9B301FFE4935E3 +:109A90009D1C1D7F6E8B8F9D4738C4E47C6E757E48 +:109AA00017E4A96C1556AFCC728F2AAC5FD8480565 +:109AB000CA7D3E61F98F657CDFBF316EB0355AD803 +:109AC000B824A2831FF419D8DBFEFCB0FEE627F40D +:109AD00006E897EE3EE45DAA789DF96BFC09F20F6B +:109AE000725B60F3CBF12660B520CA37E0859D3B01 +:109AF0007A80D99598A725AD3DB7B9D425B015E79B +:109B0000DCA1211BED88B616A28D236CA5C13BB547 +:109B1000FBC3379704176BD78B8AD398FC4D4CE364 +:109B20007CFF869A0DE3C99319BFFFFE4D82F7BEF5 +:109B30009C7F93E213E44FB231F91C002F03CE7FD8 +:109B400039D7E3FC19F533BD4D40DF99692CBF5679 +:109B5000585129C3FAD1B81F8ECBF826E94D9FFE84 +:109B6000F0DF1FBEFEEE0954A531BFDC743D7E79E7 +:109B7000B99CB9B08ECEFBA345565C7F1576B30079 +:109B8000880572DD49C254F6C17EA05D496B267816 +:109B90001F8F3B087BDC793FC0E6D536A2E8F2A4F4 +:109BA0000E5D39A33655573FABC1ABFB3EA83157CD +:109BB000F7DDA7FA75E59CE6625DFDA12D015D79F3 +:109BC000F88E0A5DFD11E1A0AE3C6A4FB5AEFE47CE +:109BD000744A113A9FC293B25F05FAAA81CEBCA221 +:109BE000A81D1FDD16D2B59FD0B57426E8AFB17B96 +:109BF0006B75FD90D3D46FA3E506FA1FA38B5F06A8 +:109C00003DE2AF95C80F7C8042F61DEBD3B2FFF466 +:109C1000F40BA0C717549BA3FE1EB4220FFF15E838 +:109C2000E337F889C6B87AC511F5B09DC2577BA451 +:109C3000E530C8C3B6347D5EAB5CB6E3BC3E3A21CA +:109C4000E3FE975AE05057948E1F414730EF0304CC +:109C5000F78519E7DD1387CB3BCD788F0A9D076C1D +:109C600099B6A6EAE91DE3D5D33B2E574FEF78BF4F +:109C70009EDE89C57A7A3B03B97DE237B9424F77D8 +:109C800081DF62FA1FE0F7CBC6E7BE34635E701275 +:109C9000EAD94F76703DDB5B0FCCB11545F5005529 +:109CA000A96138E724F0D64B2FD8593CD3A31776B7 +:109CB00070BDB0C3A81702AFA651F8C6877C18576D +:109CC000FE6EF1840CD073E9649F38F710FA02F548 +:109CD000B72AE4FC18C8795CA3BF4B053BB1D38A13 +:109CE000FEE4B1C335874D00A78DC5010FF140EAF1 +:109CF000ED34B1EE187A1BDAC5DA1A545013D98D47 +:109D000041D4A7E76E667CF13BD08774B2BF873839 +:109D10001D16A70C7A8418F4A0D11F167A66827AD1 +:109D200014E3E61BB51B03C5EDF98B983D11FA75DD +:109D3000022F93652AFAF7C2CE3415877C70AEA045 +:109D4000C0169089491BC777A1DD994254D4C33707 +:109D500055F81F5F03789BFEBB0CF0AB7AC5F3513F +:109D60007C9374C4771BDB575D2121BE8D7836D977 +:109D7000BCE897C466B2F5DF987481F7600CB4173D +:109D8000F87E31C68F7C76723E8B570A8F0E69B291 +:109D9000D3769EBB7CE8CFBCE8F4BF0AE593AB5812 +:109DA000FC38FE4440867D56390D3EDC6FF7A22F0D +:109DB0005806E593F7B3EF45A742B80F6B4823FB6E +:109DC0005EB0BEE15538A75FF52DF6FD95F737E19A +:109DD000F92E6AEC58FB929632289FDCC8BE4F38A9 +:109DE0001D6E82F288663EBED4F66A02D8C36FB397 +:109DF000FB157AC53D3CCE99C2E9D28BAE3C7E982C +:109E0000CCEB8B38674A35A3D7F2EEE02DC85E065F +:109E1000BA19FDFB7212C2F234A2E2733A09E3737B +:109E20000689E0F75B4917966F87909E962B89D736 +:109E30000CE5AAF45CC4FB6C1A2263DEA2D86FC3E3 +:109E4000FBF2CEFCE737484274FD5CF8092D49C1AE +:109E500055E047B8CA8278FF47553AF37BA34FE6EF +:109E60003F7892D46C3FFD7E9E9F278BAE8317E197 +:109E7000FE0D3AE4C3E0F74E4F67FB6BA69162DC40 +:109E8000373CAD989DAB9B067E31C54FE47B8A1372 +:109E9000F6E5E15D477DC4CFD17C91218FACA81858 +:109EA0008714C8DE512034F5E9A3BF0DF1F48B20EF +:109EB00090E9842C4D9F70AB8A411BF37306AA77FF +:109EC00082EFF77991AF87CE09FA4CC89FF97A3FB4 +:109ED000AA3E9DF951E2398D5497C57F89F32A58DE +:109EE000AFE2BEEEAA562B61FB74483AECC7A9213B +:109EF0000D48D7B3A355333B6FCAF44F15E7BB2AC0 +:109F0000CE4F677759910EE7EE94C290D7A9D9F951 +:109F1000FA29E0B77EFDA7BCA128B773387FFEEE13 +:109F200070CD46A6DFB95FF5BD91F217A3A2F24F3F +:109F3000FD4515EE237C7B31D38FE07EEBF4623F51 +:109F4000FEA29B97051C19AA84F6E27AF5A24BF4AF +:109F5000CFF562BAE83F40598F96B3F957A98EE121 +:109F6000C1CD9F197546FB125A0772904A5A242890 +:109F700067916E7C7A8963BD3B078E5CFA4D50CE4B +:109F8000B43554CEA4FD3B410FC2FC371F2CD4EA9C +:109F90004133CF3B9B6D0FE3BAAC42C201C82728C7 +:109FA000877AF26D7BD2BFC47C5B7BBA97E7C11A1C +:109FB00026B07D580D63E179C66C6FC63CB231DFC7 +:109FC000D22B3FA3CF63DCDCC2ED478BB01BA15487 +:109FD00098376CFFD4D98F897E2F3CA74841D42F66 +:109FE000B7A5840EC2BC6E210D9950DF64EB92C1FF +:109FF0005E6CE1E788B60C13F12CA52A3C1D2CEF12 +:10A000003E96D3F88562760EF9855C1BEE9FDFE401 +:10A01000B16C823C5EF4BC266FC7CF9F8EE1F72007 +:10A020006C8AE5F8D8128F71C923301E6D172B7B0F +:10A0300087015C7F3251AA527892891FCB16D9E1F1 +:10A040005EC7F294BF473A90AEC77268FB132F29E0 +:10A0500004E2F3171CDDB14E3ACE0BFB5AF7B452B3 +:10A06000783E3EC2CCF4237B64D53A16CE415E7E68 +:10A070006C06AD3FB6D38C26796CB109F5E4250B9F +:10A080007918F6FDCCB2C93685FA2197BECEF7E134 +:10A0900028FE6CEDBE8105994C5F1EEB278FE84EC4 +:10A0A0002A49C880EF697D9FEBBD926ED29D331423 +:10A0B000F71EFDCD4D74FB45DC49B7613FA26CBE78 +:10A0C000E224A1646D3F5EC6AF4A90C07947F315A4 +:10A0D000177E4FA47E2CAC27243A8B1588BB4A8967 +:10A0E000E35040C223DF48E75EF72A4C52BA7BFCBC +:10A0F000C7C1609798FF89795E1FACC3E8FDCEB1F8 +:10A10000445F36E6752B3399FE341BEE65A8CC34DC +:10A11000C2CBEE6510E7C33B94401CE483EE30F104 +:10A120007D54A9013CFFF8E82457FE160D5E6664D5 +:10A13000F0FB5BF83D120E5A1FEF2730CC630395FE +:10A140001F1FE5DB291992AEBED05B8B85FCA84EA4 +:10A15000F45F1771F97932939D735FEC60EB2F7F99 +:10A16000DAFC3EA6F7971E8DB50012BFB688248C88 +:10A17000A6ED42DF4DFE4DC00B7CEA3F00FB6EC8F2 +:10A18000A3CC8F7094E616B1FB04A6E23AAAA466AB +:10A19000A09EBD5E3B312779E96719E0BF2684BDEB +:10A1A0000EDA4FECC8F3B87FAF3883B0F3E33DF776 +:10A1B0005B760DD3EE1F9B935CF219F04B8B9944A9 +:10A1C00092601FE57F58197D8F9000F859ABF78F8B +:10A1D000C0BCD70B99A14FA19E38074B0E75E3B9B0 +:10A1E000DF32F04B72FAA0BFFD6313F091910F00C4 +:10A1F00070B0BF03F1432187FB8E84BEE98AFF68FC +:10A20000B9CCE6C4FB36EFE2F415E3DE287FBA7280 +:10A21000983EE99624BCF76520F8C47E6281C74F5A +:10A2200033981F249E024FC673799F6698783D76B7 +:10A230002EEF85CC20E2F5C3ACBF0E335318EEB041 +:10A24000F0FB1F0698EF03BC9F7F76BED74B87CAF3 +:10A250004C82E3DC117B7D703DFA7F09AECF333851 +:10A260005C63AE0FAE27FF87FC1120DD7F74E60C28 +:10A270000C17A5E7E72087646A37DEEB7147D2F554 +:10A28000C177E47F8837802FE9FAE0FB25C21761A8 +:10A29000F0CD257E73AACC81D19CA7319EA311E776 +:10A2A0006BE62AD496527B176B61EB6BB1B32496A5 +:10A2B00027FA27CFD3F4D0D143224E881FF75B591A +:10A2C0009ED1DF3D4C6B3F7FC3F1F34266E038C067 +:10A2D0007FC730AE172AF4F58E1BEA897B3288DD02 +:10A2E0008479F287F286E0396F387F84F0677AF1FB +:10A2F0003EDCB7B9BE17FB8FC5FAE0A6226F0AF89D +:10A300000D019B3D2253BBB069646D2EAC87045296 +:10A31000FFF314DB674DFD550D9D041C17D71E710F +:10A320000C31F78F8795F28B450D7DACABFCD813C4 +:10A330007A5F6BBF57EEF9B56388262F339A74990D +:10A3400098BFDF6D62F961BEEF26E5C6F0BE05F687 +:10A350006DB841FF0751FF0B7B51FFF24FBC608787 +:10A36000A8BD27B0CED01D1F8BF6A0696471AE7654 +:10A370001D283193E939B3E17E8BA89DFE9FDD6FE7 +:10A3800011F55F24A226F7D5BF82EF055D02F6BE68 +:10A39000E921F6D746D6B6D9CE0C857B497263E063 +:10A3A0007970AD3FE60CA54F7D72C9AD996ED8F7B7 +:10A3B000CACF2904F7DACEE8F2B7115D392D74C49B +:10A3C000764697BFEDD495C57E5AB38BEDA72D2D5C +:10A3D000B4E13EFFAC8653BA7E9A4DECFEA4418DAB +:10A3E0005DBAF6A501BBEA4C843CEF795DFD2DEB2F +:10A3F000181FE73477EBDE9B9500EE671DDA724598 +:10A40000D7CFF01D24465B1E11B6C568DB8DDAE39D +:10A41000D09547B7A5EAEA9B1DB9BA7209DF1F14A8 +:10A42000B0B17D3A65B67CDDF7FAE4CA5B33417FB3 +:10A4300091761D1C3DFBC207D867A3289B312F09CD +:10A440006B9A930A7AEF0FAF4F0E60FF46FE571FCD +:10A450009CC4D793585C2DF88114FA73E17B7F7C00 +:10A4600071BF27300FE8FE23B88F04F6B18973D08F +:10A47000B9C41B64F791F479BE663DE7FB4B96BE09 +:10A48000BFD7F4C885FE9E9228DFB27B4A2E958AFC +:10A49000FB8DF4F7CA89FA6B783F8FF0FCC340F765 +:10A4A000CB99AFC4E9EE978B8E9780EF2F0DBEF658 +:10A4B00078EB6F783CB99FF959AE790FCB7704FEF2 +:10A4C00092FAFEFE684F1C90A693FBEF64323A4569 +:10A4D000C7C9C4EF66C37D2EDAB806DE0F14D7F401 +:10A4E000DCEFF7A5C73304E1BD51FF9886E95F872C +:10A4F0007BCD06EAFF8DCCC0E00C8C63FF39BB1B23 +:10A500000B36360DFBD90B72B0C9C2CE33520D8655 +:10A51000F90911D71063DC93CBF6BF2D4EFD4FF434 +:10A520000762215740ED76ECB76270DDE46B92C3B1 +:10A5300002785D62EB7EE7712F9C3B8FBCF3BF30EE +:10A54000BF21E29A3819D6E5AE17CE9EFC0ABF6F3E +:10A5500001F2DE60B7C74E1989E76B1E85780D6082 +:10A56000E0E7241EA530A451FD9168B2E339A84468 +:10A570000B2B8F85FC0CADF709B99C04734980F94E +:10A580004F8473266C3D24719F72518B6FE37AC8A0 +:10A59000C79D7F8BC5FBB133F5EB229F9099BF1D03 +:10A5A00005782976213EC7BC3435457B8F49CFBA23 +:10A5B00091C8EFF4932F8EEE8BD1E765443EE6E62B +:10A5C0001BCCCBF4DC1F60C8CB0C9457FABB2774B0 +:10A5D00035B38FBC92E520ABD7BD2B06FD0191674B +:10A5E00012F3346531B9FE534AC094459F7FC90CBC +:10A5F000C85974BEC762585EE6D8F4698930B58F11 +:10A60000492011E253D8E79B91D49BFE9047D9A0F3 +:10A6100091FB63CEBEF584838F777B1641BC967920 +:10A62000024E18EFBC85FDCEC5F958FE4C60FA2CE1 +:10A63000B3A73E7BE6F3E779AEEFCE2711DD3DCC45 +:10A64000A2DEB82CA68FCEACB5D9360C8D7EF77EA7 +:10A65000CFDA00719D3B879FCB0A30FC7CF812F368 +:10A66000E797B7BC6781F34F93B34A6E077C403DD1 +:10A6700098C772A5CB02F767DFED0E8D80F7F55E08 +:10A68000127811F35B5D96D914CF1F727FE54333C7 +:10A69000CB137D18C39E029EC95995B7C33C3FBCDE +:10A6A000B9CB0274ED298FEF42B99B9C15C4F13EE2 +:10A6B0009C6828DFCACA84EFD308707E437BD987A1 +:10A6C0007D34DA43E33D63AB2D3CCF68D40F99F181 +:10A6D0003AFDB178DFAF916F97D8C8A60CFAFD6B41 +:10A6E000FB522C1054D426A8C31CBA7CC73FA71712 +:10A6F0003ECCEAC4796D29E9CEFE4121E62F1CAD9E +:10A70000749C55FB589E7B95985F877E7E0B393EE7 +:10A7100007BA67CFE85F0C24BFD23EBE5F8D3FC94A +:10A72000FE5F67407F93F6BF990CCF4D5203E69DC5 +:10A7300035FB6B4FBD42F9453675276BE556ACEFDF +:10A74000BC2E75E17A5C3D69417AD777D07925C016 +:10A750003326027965B2573FAFBBB4FB2D69BBBB53 +:10A76000499BC527411C618EAE0FD3FFEB4827F6EE +:10A77000B7AA4DFFDE686706E283DF70F9137C55E8 +:10A78000CBF1502BF01ED6C327EE1912F778CE204E +:10A79000A12DC0BF954E9B2A8F8575A4C062806B8A +:10A7A00029F1225D971AECA6B897E80EFB1CE4A3EA +:10A7B0003B9A8DF0072C00E79D2DD79E57CFF93B94 +:10A7C0000E7F5D16A3FFAAD8994750360A3B713D0C +:10A7D00089C2F784163EA204F0BE7151FFFDF19DBF +:10A7E0004F47E89CE4F8A936B00F739243BBA17EB3 +:10A7F000D6A9AEB3126CC4B40770BDE983BD17DE31 +:10A8000082FD7578E9C54418A06BFB4DF4CFDABD25 +:10A81000B203F201B57B5F457EED0F6F3DE7D14995 +:10A82000B780AB1DE4DA0897C83F1BE56747168B76 +:10A830008B03DEC02FA09D79701BDE7BD57D3F3B57 +:10A840000FEE92A9654D8245415502DB28EE772136 +:10A85000FE800DF27C53ACEC1E9A771CA53638EFC7 +:10A86000EE719A82A0FF36389639E1DCB3B8D7DBB7 +:10A870002399D83DFE649913EE11596CE5F7507E8B +:10A880003D2E9243F9F5571676DFA72B2E84F71B42 +:10A89000743B651CBF64FEC7E3E03E82F4ABF60286 +:10A8A000D8D7B60BF0AB8983A794758F63F76E3258 +:10A8B000BAB972187CF56ECB26B8CF7003B533F0F9 +:10A8C0007C9CCF1374355B3F083BF08E37BEEEB0F7 +:10A8D000C6C6F8B33E26F06829E41B8EB2DFD5FA6F +:10A8E000D8114884FCBFF19E48E1C7F6770FF325E5 +:10A8F0006E1FFE55F73C8AFC73BD5321AEC4683B06 +:10A9000031CF7A7E4F8D91DEE2FB2BFF90FBE40787 +:10A910005B36FBDE5F9CF3059F573DDCBBADB1C7EB +:10A92000F5D47E019CF570EFF635FCFCC7B97EAD21 +:10A9300007FF3C59FB9ED135DA8F0BBF3FC3E7F9C8 +:10A94000CC1153456B1FF0E666B3FCDD48B71284AB +:10A95000F58F511176BF657FF5C4F9ECFEE0EA286A +:10A96000ED5A0270439EB6AFF132B359BDC7B97EFE +:10A97000E848EAAA417970047E0AF1FD872F0DF7B5 +:10A9800069EF0B5439BE3F98CEECB5B867B3486950 +:10A990009080AF043D6E4E0E7E0FF403DCB3CBF21D +:10A9A000FD8C9F051D808FBDE887EBE33401F70622 +:10A9B000BE7E24E2B381EE35AD877BC7AF897F854C +:10A9C000DD9BCAE128971FC0FD11175A24DCF776DA +:10A9D00081849AB0FCB084FB3D2F1C637E2344D657 +:10A9E0005211E867260F354FCD4E8C80D487D8BEE4 +:10A9F000EAA5BB57E2BE25283F40F5C6D254769E55 +:10AA00006BD9067D5CB3FC61BD9E86756388D76A91 +:10AA10004910ED53CD367DFD5AC2D6576B0DFB9DC7 +:10AA20003CDCAE18FDF6AA6CEEAF1791A21B396F95 +:10AA3000F528092CCA467D1B9441AF8EE7FB9D2F5C +:10AA4000ECCE49D1FE3E4EBB4FD29D3382DFEB1997 +:10AA500032147EBFC781CFD5D981E5D0CFB7B243FD +:10AA60002BB2C15F39CAF1A774B3FB3EAB993DB3BA +:10AA7000421292FE695D68433FFC41B8F78BE2D118 +:10AA80006A657652F805B27C9F9C00F938295479A2 +:10AA90001B34F9E9B40AD8B7B1A524900FFA734B67 +:10AAA000A51DEF79D86562F7FBD9ACEC5EA2F03357 +:10AAB000130FC21AF990B6ADA5907275744548820D +:10AAC00017F250EB70FF4BF36482F7B789718ABBC2 +:10AAD00082ED004FF61CBB1F40DBE20BE43B34FD74 +:10AAE000136EEFEB39AE1FDF9B83F7EC7EB46F384C +:10AAF0003E4712C607E21C018C097E8CC013FCBEC7 +:10AB000011D19CCB1CD92645CCB04EDFB66E3EF0A1 +:10AB10004DDD7A761F52F77304F7E1B87E9556EA59 +:10AB20004D88C257D7FE54129E6FE0766B21C49DAC +:10AB3000B086C3FD31718E61610C51E334FB6EAAA6 +:10AB400039BFCEDFC7E2A965C49F0DED16D8488294 +:10AB500089E26C6159DB78B4332BCD4EF0376F78D6 +:10AB60001F0A972363BD8B70E602ECDD4B565C5FDA +:10AB7000AA7F3A1EF382AB4DDD387E4736D7B7C386 +:10AB8000F87AC11012807D4BF5FB87E3FA9B15EE36 +:10AB9000972A40BD6603BA1E063B4AE77DD72B3194 +:10ABA000786F5DCFFD2D0EA282BCAEDE9F82F1B12B +:10ABB0002B27907F6F1EDC17D2958DF24EF518A4CF +:10ABC000B8DF7C2274BB02F77CA4533F8596AF6448 +:10ABD000D7B3F2E0AE1A132D7B076DBA1DF6C5D4BC +:10ABE0008FEC3A0BE59183B6B27241578D4CCBE5B1 +:10ABF000837EC4EAC30634CA58B3063D7D3B9C47F6 +:10AC0000B9E8147E4317DEDF53FFF270D3160DDD73 +:10AC1000270F62FAF9620CAB77D1C7EEE326B95D74 +:10AC2000BA7B84070F32E9EEE111F314ED486ADFD5 +:10AC3000FD9FE676ED2E7EEFCE9438D21CC3EE1744 +:10AC40005761DFD6A17DC3112F07B29398DFEAE8E1 +:10AC5000C2FD35A21FE3B97C31EEDDFCF7893E3041 +:10AC6000EB7FB7F202B713749C0D384E5E201FF6CF +:10AC70009FD7CFCACC07BA517A299C5E0ABBF77717 +:10AC8000178E0BFD3AC1CF73748F037B72E86A266F +:10AC9000DEAF28E0A6FE9C1DFD2E0EFFDF387FDC18 +:10ACA000D5C4F1456196116EB63E0BF4053B53CE0B +:10ACB000F13B7950B43EF697D985BF9B70A3F3332F +:10ACC0000FFAD7CC4F439700AC331CDA3B02E92292 +:10ACD000E02764ABAE9F8BEB0CED8A09BB4F2629B6 +:10ACE00007DB3DC8EF9317F7FB423BDF18E637025F +:10ACF000FF8BFBD4486010AE73D571FDD0730F5A33 +:10AD00001B3B9F4186D0F9015E67CD2CE4F373F0C5 +:10AD1000F939B4F736F7C8DD89EEEC399ADF9111CD +:10AD2000EF7BF0DED35F5E01EF4F27BF7DF5077449 +:10AD3000EF8F1E13385DBF347A08380DF8ECC1B3BD +:10AD4000013E814F905B6C97A7979F1E7DDE434726 +:10AD500083FCFAFEC9F1F83ADEAA6F503AC27E5F70 +:10AD6000AF9E9F5775F84CF0FB71A2DD43B534AE32 +:10AD7000CFD1C4F51DF7A8907F58BDAF12F799AE9B +:10AD8000FAE573BF5069FBBB5FF86E02A1F8BEA085 +:10AD9000B478E05EA6BAA7362604201FA4A809A0AE +:10ADA0002F2F84D9EFB51AF5F9C39C0EC20FAAE76D +:10ADB00076E5E2330FDD06F8F8FB536607D8CDD50C +:10ADC0007BAC112BC6EB77A13F44CBEFB1F283985C +:10ADD000775CBD57EFFFDCFDE3EF7ABCC84F6A86B6 +:10ADE00029159E910C429FF5BBCDFE08E0EB84EC4B +:10ADF000A7C390D5A47B13C0676C0F70C0150AABB6 +:10AE0000DBE4A596C4DEDFA905B280DFB1BAE32199 +:10AE1000F4A3561BF681D7F6E3477D6B90FEDCBAB0 +:10AE2000C00B09BBD17F69FAC98F9F7F99C277E1B7 +:10AE30000F29F9785FE5EEFF4A90E8F7CB6D398985 +:10AE40004B316E5BDFE73D401F801F60D5DA534614 +:10AE50004FEF5E09732E641F7BD6992309102FD7FD +:10AE6000ED32A31F5AF7DC934F43BE87FCDE8AF70F +:10AE700026AC7CEEF05B5FA1E595ED66D74C06B69F +:10AE80005DF244E9B2DACBFC114187BB7F7618EF63 +:10AE9000EF82F7E09F0A7AAC6C3F6021A37BE3ADC1 +:10AEA000ACED00DEA7D98B2E6DEFDD82F76DFEE4F1 +:10AEB000530BF0F385FD1249F1F56E5FFBD47F254E +:10AEC000403D41971E3AF5A24FE4B6970BB11EE6FE +:10AED00005FAA3D3D7A81AC37CC52F9F43BCD7FEBE +:10AEE000C1EA8779D73E7F5F02C07F4E6960FCFC74 +:10AEF000C38D1E38EF267E0FB2D6CCDED73E713F13 +:10AF0000F2D98AA3F77BD8F9AD409AA918E797063A +:10AF1000F3BA736715CEAB868490CF6A7F2863BC83 +:10AF2000FF09FF3D01231D252F938773AD56BCBC40 +:10AF3000E91C6CDCA470A9C7D8EF9812720FD1DE9F +:10AF40007B8137CE16457FE7EF548FBD2736F0D390 +:10AF500056F35AAB773F88F7305CCC0AA440BE90DA +:10AF6000E241E5F892E03E5BF968790AA30BF12A29 +:10AF700045BC1DACDFC07BA8DF690EC48CD1B5E336 +:10AF8000E7C0D8F8221F40E18E857CE6390FCB0759 +:10AF9000D37F9DE8DF325F17F906FCCFB17C9E3D81 +:10AFA00072BD9BAD5B0AB9FEF804938BFA70650520 +:10AFB000CA7BA7399202F5C207E64828EF56DD7D25 +:10AFC000023D7CB0DBCCE555FF9DC2A5485A7CEE26 +:10AFD00097F01C64CD36ABEEDE97289F58A2EF7D2C +:10AFE00051B91371CF0A2EDF46FA19E5FDAA41DEE9 +:10AFF000C94EF735EF65F96F9A6F0BBA0080000004 +:10B000001F8B080000000000000BDD7C0B745465F2 +:10B010009270DDBEFD4AD2493A2F48E4E1EDBCD141 +:10B0200090745E105ED224806148A0F380090ADA31 +:10B030003C46101212C11933E3EC4963008161767A +:10B04000E2E2CEE22CBA0DA2CBECBA3B198D4C4613 +:10B050008169D4717007B1054450866D5111C740A4 +:10B0600002E8A067DC75ABEABB37DDB74308FA9F9F +:10B07000FF1C77C3C9A97CF77BDCFAAAEAABD757D8 +:10B0800017002F400A40A3C9F7F42F92119EB2383F +:10B09000BD0AC27F33B97D79009F3CF3F2893B4AF8 +:10B0A00010769A92AB807E5C36691CC06AFA13C730 +:10B0B00035E36F6B11B6BBEEAD827C8015CF968207 +:10B0C00032563CFF71223D7FF8928CCF3FB139015F +:10B0D000E879B7E96CD0CA0BC157F85B81CF8336EA +:10B0E0006A7947185209FA4700C2D53670FAF1BD9D +:10B0F000AB8FCB4E5C0A9AA16FA3DD36703EE1F1B7 +:10B1000039BEA7B9535E6C8E1FD80FD06776D37B3C +:10B11000BB7E72498EA3758C6783B96ABF0360B921 +:10B12000847F4CC03D9C2EAC7C256C5E96129B7C33 +:10B13000EE56FC633C8CFF4A06F80CF2E22761F302 +:10B14000CFFFB2EA660FD2057620D1D2702CFD4C2B +:10B1500005B8DAE6AC7C250BE0621BF65942CF0F4E +:10B16000DEAC307D956E7CD170ECDBA74280E310C5 +:10B1700046478D7EAB776F667AADFCD7267E4FF360 +:10B180001E8BDF8278AFF6D554523FB6DF13ED83C6 +:10B19000F552FEB5F6ABA76364FF273703E3032A36 +:10B1A000DF4D0F813716F9DEB75FF6ED42D47A1125 +:10B1B000978D48F7DE671C3E2FD2674314DCED46BF +:10B1C0003C7AED7D718908372488765F8A7923C4BB +:10B1D000879EF745414327F2A7D7DD1797600BED10 +:10B1E000BFE477729C82EDA00F2A3BC39E6B10A038 +:10B1F0009DF10882E89F21DB46B7E2FB2F776414BC +:10B200002119E1B21546B726533BABC8CBBB580753 +:10B21000500AF021B84F4C227CA3E3F2090FF0BA98 +:10B220008C6948CFA562ABB0E2B5F63830607BDF01 +:10B23000AA2A407A2DDBAAA7C33DB6FA783FEEF5DD +:10B240009E474D2179C0DFE5E0334306CEDFA17F85 +:10B25000BE12B60ABE44C88F87E4276DA0FC3469CD +:10B26000F2530885243FF8638061006BAC82DF33C2 +:10B27000E4BC9F01D1F9900C165A43CE7B6312EEC9 +:10B28000F3336CCB24F0DE1496CB559EF38C8F26D3 +:10B29000C79A9CF5909CE50CA4A7067B9EFFD3B8AB +:10B2A000077148E3DE77F3FF1161CFDE53D92F52E8 +:10B2B000FB376F8F7E17068EAF38F0C55D80EFEFDE +:10B2C0003D60617C7A0FFC61F483D47EC1E2247C12 +:10B2D0007B1FB2B8085FEF81585F16F58F427E235F +:10B2E000DFDBF75FCD0FD27980F5CC97C71433F34E +:10B2F000F3F2BEBF9E91886FFB2C0A209D9A0FC46B +:10B3000000CD6F7E21CA07347FFFD5719E3079F85A +:10B310007FDDCF6A337858FE62A1E15992D704707D +:10B32000D17E9A5F9CF0E43A7C7F53D741F352EC94 +:10B33000AFF8DD7FE593BEE97DF6A099F4D14553E2 +:10B34000F00940D5B4DB37B5C3847CBC188B8BDDEA +:10B35000845A6EA7D7EDB55D8B2E820EBD4807DAF5 +:10B3600017D26505E9C9C1E8F1E2B7961E97EEA2CA +:10B37000F737EE1B0FB2239C2E924B3C8FF55925CD +:10B38000DEBF787EE06A3ED8C80EAC0BD039186AB2 +:10B39000DFEFD0BE4BFF2FED5BF2DFC8BEBFF8D6AC +:10B3A000F25BC87F9B22EC51E4391828E7BFF90112 +:10B3B000B7FF3DD6C9F8DEE0F94F737C5BF7FF0DB0 +:10B3C000F9FE2CF23D6E68BE977D6BF73D14DF5F92 +:10B3D00053F91E6BB7903EDBFF5FA3216CFF43ED7B +:10B3E000FBBBFF4BF7DDEFFFC86E6B3AE2B715FC16 +:10B3F0000105E106D50FD9908CCE03AEB769A4B292 +:10B400004B96D87E07C87EF3DFB8E4430E89E76F1A +:10B41000004325D1454E5EC97E869CBC85FD043423 +:10B42000F78CCFA6E4C94F6FE1F9F701F97BDF573D +:10B430007D04A362F05B705CFB3A7C3F8E6B4F3106 +:10B44000D8DB157EFE1E3DB7D03A7104BFF3B1586C +:10B45000F77003F97B469B19FC617E860DB01DE6F3 +:10B460008F446786B5F1370A5EB21B910F514E23A8 +:10B47000F824724DC3E6E3F8250E3BF3311A7C5EE7 +:10B48000BBED1BD1C54A74318ABFE1571174E9A7DE +:10B490009BE81E924EC6E42D01DAB7118C5ED5CF23 +:10B4A00092BE126B2BC671F49CA60CA41B7A56910B +:10B4B000F47545E5EBD6E1FD6A74EFA7A74AEFAF57 +:10B4C0004BD748FE0C45E70D83D0390427DBD95F05 +:10B4D0008CC2F148AC6DFBE117E4D79AAACDA66403 +:10B4E000DCE77CB7E42432CC8740790CB661A1E478 +:10B4F0007C8AF7ED0E2CC3F689866DA95BB03D0FF3 +:10B500005D172862E85708DA53CB093F93E4F969DD +:10B5100029E207F34CCEA71024ED835F280534DF22 +:10B5200079D088F3E7CD4F2BA2F947E811E9798F5D +:10B53000E47B0AF186D45C23F1AF1684DCE34FFD93 +:10B5400021A4739DCACF371C89BCAFF9B1CB5EAFC4 +:10B55000C3FE39EDEE1637EE6F9EB1EF03D207F35F +:10B5600026A749ED12E3B31E70E89BAA7CCCA3C9C1 +:10B5700089849FDBD4C2F4986E3F87F4955CB7C88A +:10B580005FC50CAE1788A3E7343EC821FA1598FBB7 +:10B590004EAF45BCED4764E72E85F60BEC97C3979D +:10B5A000380FF1AD651F3BB44E756B71D5F424ECCB +:10B5B00056F181653B372497F03EBDB1B4CFC683C9 +:10B5C0001B88EEFDEDFBDFD3F7FF58DAA86BAF77F2 +:10B5D000E8DB5BA76D0C9F3FD87E6A2B0B250FFA2B +:10B5E0009C498F4A2EDF35E2230DBFD7D7C1028A8F +:10B5F000BB20D9A5D4908F4A2F4BA37E03F70FA46D +:10B6000093A0CB02195AE8DC5697C3629AAFF59B18 +:10B61000D3C5BAE674311F08D909240E2E85E28CF1 +:10B62000C1D63BB57CAA44712992CED5993770DC3E +:10B63000305A17E5E154BC3283F1B50B793A312B1E +:10B6400067E716C7E0743831CB312A1DF19CBF0F74 +:10B65000A502E5B2BC61B189ECCCFC655325B243CF +:10B6600047AB83068205E9B80F84777CE54CAB09CC +:10B67000A3571EED03DFBBEDA7220E8D5C3F4BED04 +:10B680007FC7002BA8FF9D3865D482BCF0F956EE29 +:10B69000CF4B57181E8D15F6AE0015888CE7A83ACB +:10B6A0005DD00FF290FE6343F4D7DE3B18BD34F952 +:10B6B0009B0F42FEEE6A107C26FC6BC3F09CA8F246 +:10B6C00063DB06F1DE53CB0B4C8BC3FA97A9EFA9D2 +:10B6D0001D84EECB54BA63FCCCF4DE5625F938AEAB +:10B6E00004978DE2E2E5EAF9DD861CF623ABEBDE9A +:10B6F000929D88212C9FBC9CF531EC10F1B115FF77 +:10B700007D958E61ABDF1891570818492EEA22E229 +:10B71000DF6A352EAE8E781E190FCF4DB785F22910 +:10B72000398C27E7772E1F979D14E70F2617F654BD +:10B73000198CC5A1B8B7609AC14DF47B63CAD55ABC +:10B74000DAE79AEA7403D9A16D55971397E485E86F +:10B75000183AE7195599C5A1F6EBD5E6061FEB1B7C +:10B76000118F1F55E3F16D95C551D36C213A6FAB25 +:10B77000BC9248F2D67F2EE0FAE7421B37B8DED201 +:10B78000F414EA38A27FA5C5F710A25AE754FEB414 +:10B790004AB4ED94772BAFDA399AE47E869CF7F8B9 +:10B7A0008FF0F9EB55164A27F5EBB3638F3D399AC5 +:10B7B000F229CE3DCB67401EA5173C1B5248EF54E3 +:10B7C000494ECE6748E026F93E3712D84E27F91287 +:10B7D000767A71AE5C25CE61D28E849DB7237F369A +:10B7E000ABFBACA812E3B635E8E5E55E55BF2F2FFD +:10B7F0007DF24826C295D54B4A69FD47D4F3712F97 +:10B80000C90DF1BDAA701D99A3150D8512A4D336DB +:10B810005D81BCB0F9F3C159532C85C6FF79FB9308 +:10B820003F27722EAF5C5CEA0F932B9017C6937F75 +:10B83000B872B73EEF9254A2CFDB2CF7E9FBE7E3F7 +:10B840001C5B22BDE7FAF2F74F247F3121F9D3DEEA +:10B850003718DF3479EBF78754FA7797C995E40FF7 +:10B860001724BA3CEEB0F37944A5A706BBF7FDE573 +:10B870009D55644777589C590A19E584E9767CD52B +:10B880008215D34AC86C955B0B5FA1F69D2DD8C677 +:10B89000FEEE7413CF5B647F6F4602B6EF4E955E8B +:10B8A00025B85871CC4C44F84795EE4B73A7BD8A28 +:10B8B000DB852A678DD9C3F9B2AD31F9748EF03DBD +:10B8C000E87993BEF21A1207EE671A3AE1C630BA67 +:10B8D0005558A3C018469F19F6045DFBF6D434DD15 +:10B8E000F8598A43D73F3B778CAEBFCA59A8EB378C +:10B8F00067087FE7C88EABEFFC10F779649FD94EDD +:10B90000243C4274490ED105F17D94F03D32E18131 +:10B91000D1DF43BA1E4F3732BD8F932C85E9B31365 +:10B9200055C0F279025ACEFC90E4B85AE8AFBAC7D3 +:10B93000734CE40F8251E4FFEA419CE77A55AFD59E +:10B940004E36B17F57E7D6CB51B59AFFABAE8CCC14 +:10B950009F060F13BEF3CB643BF9434910A6071DA6 +:10B96000246742DF0D256FBF7AFCEA4D744E2FA687 +:10B97000EBF3C8BF92445EDB8BFA97FCB0C1F44591 +:10B98000BFBE8B90337386902F0DA29E88277D516A +:10B9900060D68FD3E0298CB38CB8CEBB6D56867F32 +:10B9A0006AB333FCCFB65486EFB5290CDF6FCB6595 +:10B9B00068CE107624A915F999145A27A9CA6DBE24 +:10B9C000DE7989D4734782063E27476EFB7E9CC38F +:10B9D000A6C607382F312381FB3F2A7BDF26E5856A +:10B9E000E4B53B78D6467EC502F099C84EDE097EA6 +:10B9F00013E53D174190DB77236A041783C2702952 +:10BA0000B8382FFA3DE8032943F55B6F0278ECC99B +:10BA10009F3E4279BB7CB293E42F6068117E1E6A20 +:10BA20003384BFF354BA4BC9207D9CD872A68EF4E0 +:10BA3000E46D2620BF912489EC42921ACF7CF4F861 +:10BA4000F8A825D7B0B7ABD397DC92511A4E1F8F09 +:10BA500099C6217F1BD4B887F30AA684DC5DE17EFA +:10BA60004F6186B04FCF395C4E7AFF6394DB653C03 +:10BA70009CECD768F8A286976A512F7E27436FCF38 +:10BA80000ACCA82F71FD6AA7C76C4758BEBD302AE3 +:10BA9000784DFC3CB765A4E8F113FA42C8CB60FCD2 +:10BAA000D3F8FE75E546938F530ED76C7AAFD180ED +:10BAB000F139BEC798D890BA84FDC07AE67F6DC4CC +:10BAC0007E22E526BFECFDADC514A794C84E52BF3B +:10BAD000F9DD011BE98563140F15903DFCA8BC1826 +:10BAE000F975B41B3D4BE4D7515BB08ADA1F4D901A +:10BAF000ED0F61FB2349799DCEAF77A76C17F191CC +:10BB000033E0C2F63D9509455BB035778A89EDDDB6 +:10BB1000398F6317E581B6AAF89C57FD222FFA23C7 +:10BB200034EFA3EAABC7EF273FEAB1A44489E5604D +:10BB300079DC446E6718442CEB34B13FB45D66FD8C +:10BB400072BC6AE65BCB20A4AFCEA9FA4AD34BF312 +:10BB50008538C139F0A650FC375FB587F50D7AFD01 +:10BB6000535BA56F3744E89F24D23F7103F552A47D +:10BB7000FEF99B8CD890BD9307FA5BE76D7D7ED272 +:10BB8000A3DE4A89E95487F1A0A780FC8142D3391A +:10BB90001BC981C472A0E9A1BA2A8C134B082E2EAE +:10BBA000B6E2F80A8C5B289F52D7E534DD630B9729 +:10BBB000B3C566A07866FB6233DD033EE770FF2DF8 +:10BBC0009D13D3CE0A85F4F4B67D828F053BDE7ECD +:10BBD00087F63FB77AC9C634E267170A3CF173C7E4 +:10BBE000F858F2BB8EF9AE24435EB8BCB798896EA4 +:10BBF000E53B2EDD44F21B79DE818C29C57BE04ECE +:10BC0000BDAE9FA68E1B4A7F79CB2197E2D21E093B +:10BC1000FC12FAFF3DD3869513BE3DA3CC4601B37B +:10BC2000B93D439EFCB28DE85A056C7F7BD2CAAC0D +:10BC3000A27F26DFD7BD1115974FFB9DD2073A7B18 +:10BC400039F573ABCE5E36060D7CAF370DF476B8A2 +:10BC5000C2AAB7C333EC8E083BADB7C37382B6F745 +:10BC6000483E7A5E5BC871FF2CA530A2DFE02579E3 +:10BC70009D9D3B41B74E0D887BDCB90827229C83F4 +:10BC8000F0368A7B9CD3068CA37BDDB965B374EB5D +:10BC9000769B2197E4A34F8A76EE4279ACB1BAF550 +:10BCA000FBC3009FE8B83EC1EA95E3B90D13719D4F +:10BCB000C6D6BFB09C4D6AFD92FDFC427FA76E5E6A +:10BCC000F1A16EDD7B9C017B0585BF45279D2F1370 +:10BCD0002C09BA2B287C1977BEE56582AD56711FF9 +:10BCE00078354AC0070CB081F2910FC89E15642FB9 +:10BCF000AE1A7CB9643FA247CC1C45F25893B09170 +:10BD0000D081D9E0F980F4D6844F7DEDD49EFA65D8 +:10BD1000A74CF6A87D8FECB5C4139FAB625EA7FC61 +:10BD200066A7C4FE78A3CDC071DC27899DF96BC3DB +:10BD3000E4FF931F88FB514875A52E4EA67C59261B +:10BD4000E755DC15B12E19E9D3B43787F366AF6434 +:10BD50004FFB94CE851C3BDD2AECAAB1AFDF9F4898 +:10BD6000A77E57E328C427BA42667D02B79B381FD7 +:10BD7000136D70C7A9C934B62FE6DB4D1C57DF9F82 +:10BD800029F458F41F419150DEA2933CF2589A379F +:10BD90005B023ADFFDF6AF0A5C64976D996ADC4F8F +:10BDA00009351C579372FC19CABFDD9F19CBCFC749 +:10BDB0005529BF3791636F37DA490F279D74DBC769 +:10BDC000229E5DC925AC07BA4E06A6D079BD3F5369 +:10BDD000E1F1C32BA7AD9D46EF7B54061ADF659FAB +:10BDE0001E43E32137DB4079B9359407C0A1490BE5 +:10BDF00095B7294F03874C3C4E7BFF96F2933EDA72 +:10BE000047D249D72ADE6FAE4DC97270BF63D15891 +:10BE1000B23338DD32F8B97D7F6B4A8A82FBAA994A +:10BE2000664F71127C04893491E944E10FD8C94707 +:10BE3000A4B677D8D1E988D71EAD0DE007A4FB16CC +:10BE40008CCB489FD04F14B66BA4FEF1B5D3F3381A +:10BE5000EFA0F57BA10CE92B6BFDC36B693D7BC4A7 +:10BE60007ADAFA05BB871DDD944774B2ABF4B6A746 +:10BE7000B84970BFFC4A223FE37E35FE8C9695712F +:10BE8000249F4B0C4A3EC19444CFB8CC145AD79946 +:10BE90004DEDF7635DC3A73858DF9CDB4EFA66BAF9 +:10BEA00089F57873EE56BE8FEB322B7B4F26D3BDD0 +:10BEB0003C9E3F7C6EFAC9BD9DDDB86EB3FD2F7C04 +:10BEC000AE507E6793DDBB1C3024529E7F89DCBF61 +:10BED0001F1786FC70D6106AD3795B12DA8F2B138A +:10BEE000FBB784EDCF8AEDA5EAF895BB336BD7138A +:10BEF0009F9759399E5EAB9EDD2D89D021A31C5E94 +:10BF0000C99D389FDE7B652BDA5DA4691775929D0C +:10BF10004D8DF63D45344E76E7523EEB4840F88B6A +:10BF20009DC867176D4CC9D6AD7765F247B6B1B4F9 +:10BF3000CE64F48E705F4B836650485F18C16F41CA +:10BF4000BDD23579C9CB19C924970AF79FA475309A +:10BF5000CE3B9EED5A94C9F9552DBFF8A3AF955F1E +:10BF60006C56F55473D9BA3CAEBF982EB1BD0F6470 +:10BF700009B96F6EFD94E90B468F93F8DAD87A858C +:10BF8000F599D6EE5927F4418709EEAE41D8F8DF8E +:10BF9000F2DD94B742FDB789F46123BC645E13E619 +:10BFA0008F41E7A57EFD576008F96BC64765B60F60 +:10BFB00091F81A3D55FCBE1AC93E8F726DBFCD7AFD +:10BFC000B0D6887E564D947D9E84ED8D4FDD536BAB +:10BFD000447B5733CA3ECF80ED9D99AF88FE34FB3A +:10BFE000DF1B9C00079F3A2DDA0EFB5BD47E61F7C6 +:10BFF0006931BE5093EF13B52EC497738ED87E78F7 +:10C00000F7895A2FFB9136CEDB5FAE8CF259AE9397 +:10C01000D7AB6B7D5117470CE89725A12F1B841ECA +:10C02000B8302B8DF51964BA0A0DA42F6B47169101 +:10C030005E7A4CD56FC3901765F8FB7B3CAF56A476 +:10C040005F5376E0AEB80CF243365F92E2E87D07CC +:10C05000F87D8D548584CF3FC8F5FC5326E5F3A4C5 +:10C06000E019D29B4DD5C7B249EFCFCE16F129D8F2 +:10C07000FB32894F0BC0C371C60235AE33A0B092FC +:10C080005F556FCBE4F832D24FAB033FC72191FE2F +:10C090001A84C78532D51304EE32231E26950E4D21 +:10C0A000898E2C9A87783D2BF0423CB16D4A0E0C5C +:10C0B00013FEF9338A44E73BD7CAF7B0D1B79CCC1B +:10C0C000F75CC35FEF6C433B8947EAD9B66E86598C +:10C0D000D9C0FB196E0C9A9DB8CEEA93C0F669865A +:10C0E000DCC876E072B703C2F36C87557AC6778BEB +:10C0F0007C24D2D549744DCE00BF01F99AFC9BD760 +:10C100009EA1BCFD61D51E687C9C1A039D518921AE +:10C110007A231F9CC4078DEE48CF62BA4F78E5CBD7 +:10C12000C393898FB3092F9CDF152DCE7DDFF3518B +:10C130003EF20F22F13CABE21389EF673788E767E5 +:10C140003788E767AABD1A0C5FEDFC6A74D2CE2F60 +:10C15000A87A6B418363D71629D4AEAD72707CA7E1 +:10C16000E139507E762BD7929FA1E42690A5D90B7A +:10C17000A147343A6AF8697AA18BEEE574F825ECA8 +:10C18000D4E397C0E729BEF5B7ACA7E458233FAF87 +:10C19000CF4DDD49F14F7CE0325D76414256BAA089 +:10C1A00073E717407E777CEB3E1E3F603F11FBD06C +:10C1B000F463E47E347D39705FAADE54F5A8A63FAF +:10C1C000A750A443F349374BE41F7B747EDF34B898 +:10C1D00037C22FBE2F227FF543DDF8DB53D7E9FAB4 +:10C1E00067299B75FDB3731FD1B5AB9D8FE9C6CF92 +:10C1F0002DDBA9EBAFB1EED1B5270703EC771E69B4 +:10C20000ABE4F8F7B6F37DEC7FFAD538F925354E77 +:10C210007E85E2643C9FAF529C8CF0509B939FFFC5 +:10C22000475B19C3C36D2E86813637C3C8733DE79C +:10C23000B9EF1AC98F2F0B74B0DF1B93E1B92B0B29 +:10C24000CFF95C83AF3D16F931FEB4F0532155F8B8 +:10C25000599ABDDC7070C21BE467251D96214A19EE +:10C260005CFFC67F2E832B2C3F1E5FD507A4EFE318 +:10C27000D5FCC91C23ACB7207F6B6C46FF70E4D79C +:10C28000D22C917722754DF78C0D56E0FBC98606AE +:10C29000C9D90EFCDC4BF77A08FD9E2246C56D1D00 +:10C2A000A6DEF7E18FC5085E5A4F76C9701BE539E7 +:10C2B00092938C1096B79B87EFBC19E7DD61EBE496 +:10C2C000FCCF82430F352DC6E7B0DE5BCA7E936696 +:10C2D000C7BDEF18BEBAF5C6EDF8D22C717E364850 +:10C2E000221FE04D3072FE2D321F3241DDDF9C7681 +:10C2F000AF1C47F1CC9BC0F78973553B8BF4D864D6 +:10C30000490C9D434DFE6BEC467F4E1CD99D472A40 +:10C31000685EE37185E911E93768F18E26F7A8EFC9 +:10C32000DB69FCE593C0FEDCF81E5F701BBEAFACA2 +:10C33000AFA382E290899F77BE4C70A8B848C37FB4 +:10C340005F5B03CBCD81360F437FDB0A551E5BB8A5 +:10C35000FD4A5B2BB75F6DF3323CD4B64995C70EEF +:10C36000EE3FDCB69DDB47DA7CAA5CEEE1E701A29A +:10C370001FD265B3A697ACD3F83E048C0286E44185 +:10C38000F1C275E4A13155E8E748B9184C0E007CBC +:10C390000ADD97DC81F690F4D89DE01D4BF51D0D6C +:10C3A000CB3B4C93A46F2E0FF5B6474D745F11A98C +:10C3B000DFE683C27237D0DE7B9C3762EF35FD2625 +:10C3C00063DC4676CA22DFE7A43CC2D7F72F3C2DB8 +:10C3D00084C7D0EF137C31A562EC9B48F9C6134F9C +:10C3E000535EFB42A9EB904BBA061D22E2CCC6512C +:10C3F00062FED7C54FCB7F0D85DFBF67BB5ECF4ADF +:10C4000009D9B3683EF3086FB2717DB1D9E2F33D4B +:10C4100044F1DE8B517C1EC1E61A5D1396BF399143 +:10C4200025E2D4FA24D7892CF60F7A9EFE473A2FBC +:10C430005D319C6F898CA33E0D540C0FF79722F54C +:10C4400069B3FD0A9FBB01765E32B09D6F3680876F +:10C45000EA898A2C6095C8EFCF2EFF50BC7772C056 +:10C4600045EFB51BAF7B5FD9DC7A89D71FB4DF20DE +:10C47000EA969AF797DA9784E50DB2B2D53A040CAA +:10C4800010CF5943F4BB51799ED2D7A0D30FDF3AD6 +:10C49000FBE9FAA5AE7F0E9A1DA2EF5CCF2CE6C396 +:10C4A0001D14217DADBCBFCB43F03987674436C92D +:10C4B0003F6523B1FFC2DEBF66921F7DE1B609F67C +:10C4C0006930501FDEA8FED3F49EA607379A614557 +:10C4D000A72EAF935C48791D8D1F63B3F57500914E +:10C4E000E7ACB7101986F8F63E2FEAE27A63A37D2F +:10C4F00012B2DCB5EF0F27A90E099C7AFBEDB2DA78 +:10C50000B8DEB478A193ED38A01D27D5823BED09A4 +:10C510005F778651C4416074E62E0A3B37ED6A9D11 +:10C52000C31E84BF46BCE316068D4A98BC55AAF8C4 +:10C530004E5B301D38BE5CE8623F30CE2EF2433396 +:10C54000AC501245EB7E79258FD69DA3FA095B4C42 +:10C55000E027BE0D2F2B94C84F5C9DE49A954DF9B2 +:10C56000D2872727F03D17E5566F0EE9A3197255BC +:10C57000EA623A37C9463EAF9A9EA9B77D60960DEA +:10C5800054CFE0647E47D20B20F8EA369CE7EA9667 +:10C59000EC94B78F3CC7AEEE8327C9AF1FCA3F1DCF +:10C5A0004A3F45EA0F8DEE91745E9DE45E4E72A6A1 +:10C5B000E997C8FD6A79E32608B29CFE64E1B36E90 +:10C5C000824F488AB83F069F6B04F27B75F77D4027 +:10C5D000F38B645177DA374BC44391E7FB41953FC6 +:10C5E0008DAABE284A026B2AF1C303AC3F7B678D3C +:10C5F000E138E4EFB245FD15AE945D1B56D7A8F9BE +:10C60000353DEAF71B75DD515E392C7FB0313B813A +:10C61000E7D5593FD5E9C1D5AD5FE8F4D7EA3C216C +:10C620000F45ED4AF17D08D7AAF778BB46BB371313 +:10C63000DF57763EB2F7B042EFDBF1837788CF87E2 +:10C640006C422F1F4E61DAF44AFA7A9C3AEB25D5F8 +:10C65000FEEFD4DD031DAB7E9BE3DCBAAE182FD119 +:10C660005FC34B8B8F357DDD74E0E33364B77BA410 +:10C670004B671E24FA3D6F61FFAC91F04EE2B8FAB1 +:10C6800009E2D3B3870C4CDFA65916BEE701A332EB +:10C69000B636364497DE8FAF5D27A4E1A7BD4FC302 +:10C6A000AB4712790A6DDCBF660BBBF4A16AD78E6B +:10C6B000990217892F17F6DE2A51C2B1FF7942205D +:10C6C0003FC116E2CBFF2F3FE90E10FEF249C3BA7D +:10C6D000EF9B915E3D9DDB4C9C57FE86FE91866FE5 +:10C6E0007B2CF8683D7081621FC6293C5107889BEE +:10C6F000340EA3B84DB425DBAB5F901E9BA2420E57 +:10C7000022B17FB28AF646A905083F2B7430DC229D +:10C710003915825325B751E4B37D2C8F33A165249D +:10C720003DBFCDEA4C351AE8FE50E411E7256C9A7E +:10C73000C36C1C061BE93EC568F69A86915EAC8DFB +:10C7400057EB20059DB4BAC415F83B19E9624C00BB +:10C75000C588E357A0DF6E42FAD62F5FF0D33C1AAC +:10C760006F9FCC74D4EA1A691ED171FEE1966AF209 +:10C7700077BE7BF0EF8EB8F0F9C7891D9C97FD73EB +:10C780006057FEBFE19895C7F6F177458DFEC04C26 +:10C7900022EF6AE8637BA4D17F210418DE057D0CBB +:10C7A0003D60E7FE25E064B80CDC0CEF811686A73F +:10C7B000D27634E1498005C3B79A3E85101D5625CF +:10C7C000AC1F47EFB1976FCF627DA3DE4745DE6FA9 +:10C7D000D424D8F83E05FB45DDE699285FBB83EFFE +:10C7E00033FE9BCEC103B26B91A06F4B01F96BBDC1 +:10C7F000096690E8BBAD14A147BC1780F3B0BD2615 +:10C8000075FE2585DB251545ECEFC05585FDB24944 +:10C81000EA7DA3A6674B6E1575C0F095183FA54F2E +:10C820005F2F5642C94B9AFF5785EF2DA67E1E59A2 +:10C830004FA6D7C33B72841EE3522BFCB324C9D04E +:10C84000129ED7684F1D26F2826ADBA2D839CF31FB +:10C850002E479CC3DE3803CB09FED45BC711BE82D2 +:10C86000AF93F6FD5195470C388785BEB79B64F4AE +:10C870001FA4E7AB557D8FDA98EDD564924FA25790 +:10C88000B75EFF43EAAD5C17305145418B63255CD1 +:10C890006B6122C9734066B9853E862EB0B3BD2F49 +:10C8A0000727C3E9E06688F2CDB0123A187E073A4E +:10C8B0001956418021DCE27416E1FB0D56BF2CCEE7 +:10C8C000EF8FED7C8F3B6BB981F2D625DF15F59CA0 +:10C8D00043D1A52147D88FA1E9820779DC8DD0C546 +:10C8E00023F08BA4CBC85C3E471A5D347A44812F79 +:10C8F00095E838058232414A55D3FC69781CA95D18 +:10C90000012E6ECF18921EFE76BABF2B0B7A8C9C2E +:10C91000E788A4478590134D6E347DB658DD3FDD22 +:10C92000E510D4F44F478EC2F2A2E9213C6F7C5F40 +:10C93000ACCD8FD4535A7F494CF9150555FADFFC1D +:10C94000F3DE3ACA8F971497AFA512A7CD392F8976 +:10C95000F6A4F2E7D2B1FD939CDF8B764179B1C9A1 +:10C9600009B04E7AB56E3AB6DBDF54BF53B466EB0E +:10C97000BE03BC6CFB81D34E7673A4CD49FB7CD83F +:10C980008C38231E568B80728688235F6803FE5E78 +:10C9900042C3D362117E1F8EF7929F9672DEBB80D8 +:10C9A000F20CDAFE4657FA5F322924134A31E54D7C +:10C9B000268CF6ACCB290DAD8F7870BDFC08150F19 +:10C9C0006DDE049BD9C5F5A0C98E62DA77C768F71A +:10C9D000C61C3A5FB1E2DE561BB747F52F27183B5E +:10C9E00064BAFFECC811741E0CBE98E3FA5B5A27B8 +:10C9F000F2F960F6A8F7433327A176E778FE81F0D5 +:10CA00006E8EF9329BECFEC5C2631B838E905C4A2E +:10CA1000C89485B8FF76976AA7B43A7AF2CB907F2C +:10CA20001396B964526DBD1FE291C47330AEA1E597 +:10CA3000656AE3BABB785DB9EF1E92C78B09C7CCB4 +:10CA40001FF2391A29E44BD54BFB0FBCF6E008D195 +:10CA50007443D8F9693EF0C55FDEC5F3D67CD9E6EC +:10CA6000A4E1BD71823E93F63DB696E907369DBEC0 +:10CA7000D0CEDBC46E0B7F4F3469DF98EFD1B8297D +:10CA8000C74E67D0BEA69E0EB6537AAB77FFDB23A8 +:10CA9000849C6BF75557A56F62B7B57A8F356F8950 +:10CAA0007A8F3564B8A9FD6B89E3EEA64326BE4FA5 +:10CAB000FA48B5275ADDE70A757F17C8AEC9F41DD5 +:10CAC000EC52AE53019FF0A315FC47E77EFC49BD35 +:10CAD0003E6FEA8CCC0B8B3AB9C8EFAD23EB548E8A +:10CAE000E6A8F571A36014E3AFD6650EB65FAD1E80 +:10CAF000E567E03A95C3F1B25B26392D358ABAE88D +:10CB000019F28FF93CAD19955724EA59459DEFF27A +:10CB100028B1AF5FABF5F46B1E9781EA36D6EC37E0 +:10CB2000F3779C3B515D94917F5DF6049F8BE52AE2 +:10CB30008EDAF9BB7793C4F78DB0238965ABE069D2 +:10CB40000B9F9382A787BB883E0566E167EF7CDA7F +:10CB5000B289DAED1BA2BDA4777F95D077137D1F34 +:10CB6000DD1EA5D693E37BE8DEAF20BD2F9DECB99B +:10CB70003557E8A976D59E6BF79EDA7DF99AD8EC01 +:10CB8000E11497F5F7078D3AFDD1AEFAD725841F4A +:10CB9000F98B2D2671DF1E25F03FF8E6FC18F277A1 +:10CBA0009F37BA63A87EE6F2F1F478B84EFD57A934 +:10CBB0001F99709DFC45C9F1ADFC7D4EC976A3A0BF +:10CBC000872A6F2FB4B9E07D5388DE1AFE33E467FD +:10CBD0002ACC744FB80CEC2C87AF3DD96EC5F69AB1 +:10CBE000CDFC6500A29A1B4F76ABF490CCDFCD4C08 +:10CBF0003C24EAA95E0077BC1FDB9654032861F24F +:10CC000012A5448312965788C94DD4B5639D37E960 +:10CC1000C6C797A5EBFABBD47A1CAD4E59F35F1388 +:10CC20005CB7E8E64D09DCC3F5A3499545BAE7F0E2 +:10CC3000A990FB32FC27E2D41699CED5A420C02FB0 +:10CC40001CF4DD8F3395ECC6C41EFDF9B0A8755BEE +:10CC500065C10E20F98E3A6ED4D5315B6C33F93B49 +:10CC600022CB10755D65B96A5DD74818A9FBAEBCCB +:10CC70009FDEFA3AAF7190F90F934B88BE1881622C +:10CC8000FF659AC1F6067CDE307A6BE7EA05E86458 +:10CC90007B9DE2D6D37D78839EEE691E3DDD47AC59 +:10CCA000D0D37D548B9EEE37B7EAE9EBF0EAE99AF0 +:10CCB000B169A26E7C5647B9AE9DB3FD3BBAF16334 +:10CCC0007CB5BAF6AD7BEED08D1FDBB944D75FD013 +:10CCD000BDF286E4A0D0BF46374E9383E2433FBA0D +:10CCE000A61C78F11FEB431075BD654877CABF0ECF +:10CCF000C6FF76A903E2A46FCEFFD65C555F6AFC3F +:10CD0000BF417DB988EC2D9ED3398744FDD71C9B4C +:10CD100095EBC4505E72E9FEF332443BE91E5FF3CB +:10CD20000BDCAA7E996B33B29D981323F48F561FA8 +:10CD300016190F4AB6435F503E666E991491F7D3A9 +:10CD4000D7990F758F511AF0EBDA85C74126BB587A +:10CD5000FA81D21E8BEF293E2DEE4522E3CF92A021 +:10CD6000A79DCCEEF81E34C30AC5A1021FEDFE2418 +:10CD7000326E82CE5DBC4FB37A6E22E3D5070CE8EB +:10CD80004F6470DD18FBB1570D03E2D75423FBAF9E +:10CD90001EF667DB46799EC945FAFEA13FAE0DB689 +:10CDA0000BE27402F95FBDFDF54477D6D3FD5A6FEF +:10CDB0000270FDCCD1750DF55EB2F7C9600F8E1310 +:10CDC000E91DFA7939D7B397D63B2B89387271D9D7 +:10CDD000FB4F3C877876ABFEECF0859D9C475A9DD7 +:10CDE000E4FA6D6EE9C07BAC48A8E5CDB43C5A5777 +:10CDF0009B9F614C9E93E38CC87C56D020F213DE3F +:10CE00001F89EF0C3F21A42684EA5B2F6F3271DD6E +:10CE100007A871F722950F5A7E62A1BA8FB3B8C4E2 +:10CE20000AB49F8BBAFFC0FC5895DAA3E6355A9C2A +:10CE3000548AB974A48DEB3BC055EC14F92B2D5FCB +:10CE40003142FE3A7ECF50FB5F95FAB12ECF05CF2F +:10CE500024DD501D6868DF62FDB3B384DD3F3B6BAA +:10CE600004D75786D6BFC879B3452D6FEAE4FBEEE9 +:10CE7000D6533A795EEC7D4FD71F4CEE33515E307E +:10CE80005839663AF90DC8F7CF889FC1BD6933EFAD +:10CE9000447A5E78DE32EE46EAB657A57EC2EF3FB0 +:10CEA000DD1660BE6AFB3BD37692DBC1B620C3C8F9 +:10CEB000FD6979050D9A5F02D6075A1DE7C07A4AC7 +:10CEC00017D7D1FC6C4CBA9A7764D98507D69AD417 +:10CED000BA03CF76CA8F5F9D1F534879DBD36ADDD3 +:10CEE000EC69B56EF6B45A377B5AAD933DADD6C9F1 +:10CEF000F69A6C9B282F715A12F7028B4679868D11 +:10CF0000A13A81957DF974CE9A0B82774914370E38 +:10CF1000F3A48DC1F74A181EA4719DBC379BFCBFBA +:10CF2000F3066F3ED53BD58FF9977AAA673A1FED86 +:10CF3000BD481E46D52F9FAAA778ECBC599CBF853B +:10CF4000BFFC199FB7B70C32501DA3F70549D4A1F8 +:10CF5000D98266BA775A99E2C9A2F752BD16D5E3CB +:10CF6000D373924B2D8FD96B127E5CAFEACFE58DD8 +:10CF700011FEE45882A52138738C38A70B09B23F03 +:10CF8000BE359BBF8FA7EFB91CFC7E17D5AF780FBE +:10CF900058383F1259D754F43B8B5F0ACB834E1D50 +:10CFA000E3E0759233C477EEC9B3A37C54F702C1B2 +:10CFB000C068AACDEAC7F7B8A80BBD40F9613A9F8F +:10CFC00054941E565735758CF0379B5E3B7B86F22A +:10CFD0004B1FE47A2AC684D52135C51DE4BCD4BCD8 +:10CFE000310A8F433C39CEB3C8B09EF8D2640D9A53 +:10CFF00069DE50F9EDC1F67DE17B819FE739A82E0E +:10D000004AC9A2F768EF453CE611DDB5FD6A7884B0 +:10D01000D6B9BEFC6B795BAD7DACFAE16C3A3745B5 +:10D02000545F760DFBB86A8CC81B9D364144FD9950 +:10D030004A37D0EACFF2583F6D54F91CC9A756952C +:10D040004E45685F293F6F8946DB5E145A17C77BE0 +:10D05000E8FE65618BE3B9C3C9542F3996D23BA171 +:10D060003CBCBAEEAED1AE3563C2F2E1286FE2FF4E +:10D07000DB9815C5F2D174E0D419FAFF10EEFDE784 +:10D08000B1C5445F6D5E247D91AEA3889E470D7E41 +:10D09000B35AFFD63686F3E147B9BE4CA3EF37A5A6 +:10D0A00067EFA800C785BD3BBF184DF5B64DEAFD3B +:10D0B0005593766FD2A5CF0F213DBC946F18785F42 +:10D0C000027CEF6251ED86459B3FD2A89B5F13E740 +:10D0D000FE39D165AFAA1F70BCCFA0E6A3C9CEF4BC +:10D0E000E7A3553BA4A924E9A4C843971224C72069 +:10D0F0002F9EED5289F63EC48BF8B751F2B23DD760 +:10D10000F255EDAAFD9697AEE53C5E197430B4C8B1 +:10D110000EB687967781F3F5FD79A8CDAFEAE2F3F5 +:10D12000FF01B894F3D5504D00000000000000004E +:10D130001F8B080000000000000BFB51CFC0F00364 +:10D1400009E772A2F22FA1F1F9D1F89B3950F94CFD +:10D15000ECA8FCA968F2E8781D137E7942D89A9968 +:10D1600081C109883D81388019BFDA7222EC7A24A6 +:10D1700009A1DB81F46E207E0CC4AD820C0C2DC2A3 +:10D180000C0CD781F45441CADC8B8EEBF8A96BDE12 +:10D1900028260DB7C8A1F28F6A32307CD76260B002 +:10D1A000D381F06B90E4838162C73421EC77CA0CA1 +:10D1B0000CD7B419184AE4B09BFB1E287F1D289F8A +:10D1C0000C35070023238ECD68030000000000000B +:10D1D0001F8B080000000000000BCD7D0B7854D59C +:10D1E000B9E8DA7BF69E5726939D64122630849D1B +:10D1F000F00A187012120810ED24048D8A3A3C547B +:10D2000044D009D28A089A22D658693390072182DD +:10D2100004B52DA2E21090A2B53DD1A2E5F4D49EB2 +:10D22000416845E568B4F8E839D806B43E7AD51BBC +:10D2300069ADFA5D2DF7FFFFB57666EF9D17F69C99 +:10D2400073EF899F2ED75EEF7FFDEFF5AF352E7719 +:10D250002663DF60EC0CFE41FA3B8931569E4A9909 +:10D260003BBC9805185BA939F5F602C66E72848F2F +:10D27000EA65F07D841C7E44C7EF136A989F3107EE +:10D28000D6CF63AC18FF03ED9A7C723889ED5E73DC +:10D290005438F454FFF674A5C298560A29DBD2ED2F +:10D2A000807E5842EDED7133FA3B53C858C3894F25 +:10D2B000A61C31F2F06F90A507DE3D07FE67069BC6 +:10D2C00071C6C1D869DF828C241BBCFF3F37B27C9A +:10D2D000653C639F35F64E3932BE7FF94D0E56DF01 +:10D2E000550C2963EFB8B270BD71E7D553189BC6D2 +:10D2F00060D01CC8FB60113353EBBC69BF94AF1402 +:10D30000A5E6B3D2279F740D306FC6E296F6D07FA4 +:10D3100012FBB7B71FB49D02FF4C67CCCB8BD82E46 +:10D32000295681DF3D81B5F19190BFE9F12A162B95 +:10D330004EF58FF38E4E498D33E87C036737DFC19E +:10D34000E069D43BEDDBD8CAA05D93CAF1A13947AF +:10D350000E6F64FDF1C1807F936F636ECC3738FC34 +:10D36000010F740DE1EFF071BC79BDA902B6977D94 +:10D370009B79089FFACD63183C59867892F6DF8F27 +:10D38000270DFFF3F0E47B08AFFF2978C25807E7C9 +:10D39000234C7746D3CDF928C379A4EA99D25C40CF +:10D3A00003B11E47A0F513C7544CBD71E40F8E8026 +:10D3B000F26E8F699F8D76AA93C5707F9A18C73BCE +:10D3C000FA83292AA1F09E76C0C5BDCC49F5948088 +:10D3D0009BFA51B40E86F808F0DA4BE3CEB3C29153 +:10D3E000B108C3F9AAB945191C7E5903AEF7E1C6C5 +:10D3F000FAA98A095F1E56D9E22E1F6D18AD53FD9A +:10D400003E4B64231CBF5CA82F9832783F76B8014E +:10D410005DBD1903BA8AE738C38FB0143DD9D7F57B +:10D42000AF7DEB72C6114EA675FDEB50EB6A4A9FBD +:10D430009061C60BFB3C9AC5BA8C75F47D37D677E4 +:10D4400096FB3F5879B31A09D64117F1F481D7A753 +:10D45000E2FA40DEFCBB589FEA73D2BEC1BAFE7D41 +:10D46000A07529AC232249FDD7A5686E828B31AE09 +:10D47000E2FECE54655A6A7EEF318DF7DF377E9833 +:10D48000F0D2A1316A778CC5DEC3F5031E76131E78 +:10D49000FA22444FCE2074702EA691C5718067F396 +:10D4A000A199AC780AB12FB61A52A72FC6E641BD92 +:10D4B000E6AF1C8B112F59A08CFA37E6718AC9167A +:10D4C000F8F4E1B198871D5E9D08F7E2FEFBDFB935 +:10D4D000F982E0F5F85DE270B2C3C5680F7063527F +:10D4E0004E0A3F0C3CE8DC2CE01518783F55F7ADB0 +:10D4F0005395ECFE78D092335D8F150B84CAA52925 +:10D50000D1DF569D7538CEC5E5CA7117C06B524D37 +:10D5100032B81CBEBB705DD0FF3BEE58A604FD3890 +:10D5200065BD5A866F7A54ABC6B9B688F5CD751409 +:10D530007B4EC1FCEEA92DCC580EE90CDCD401F0D9 +:10D54000E88146580BE0E70F1BDD947EF6D6445A7F +:10D55000C760F8B6A3B1678AA29AF2AB9B3D1310DD +:10D56000FF027278BCCED8A835077EFF2DC4BBD190 +:10D570007A29F19E88A4E0BABC386F289F24E6017E +:10D58000709C24959BF84380C3D313894634187F3D +:10D59000128B4624D8EAECFD2C9C3470D3041F0374 +:10D5A0002E008752DC8FC240C7B3A002B182794CF3 +:10D5B000564D70B8A756A6466B2F9DD0E92848CD8A +:10D5C000FB3689E30D0B0538BE2AE120CE6330FA25 +:10D5D000BB0FE054CCE958C27A23A32C8174B45910 +:10D5E0007C3FCDA2D5B89E912B7519D7D12219FCBD +:10D5F0002BC8108F9AC5BCEF5BE0A5F9348FD676A7 +:10D60000E37C2EC379201C560A38F5C7B7CB06C277 +:10D61000B791D1684406785E2EC716E0B88EA2A4F2 +:10D6200086A4902EC5E34EE8B7D5183FCEBA71FC5C +:10D630001C89A5FE60FC345DEF44BCBF1EF703DA15 +:10D64000E7845BBF2DC37ADC272EFA80015C03617F +:10D65000258E722BA7A76E1EE6437AA20AE10ADF87 +:10D660004F22DC3DBEA8A4C2F869E57B23D8F5377C +:10D67000E4D8F5380F77B846427D26541FA6F9DE68 +:10D68000AB4619EEA75A198F4421FFC09AE9ACCED8 +:10D69000845FEBC4FA1D01164914A7F6F93E07C7CB +:10D6A00097AD65D59E1B7C58CF4BFB309995453483 +:10D6B0001FE207A005E0878AF8A1131EDC8A70D25A +:10D6C000A3FAB3846701AD5AD209FF47203EDFAB0E +:10D6D00086F3B0DDBD6B9C8B131C2EC709DE321F99 +:10D6E00007FED5114E1E91AF94541ACFB984C32BA7 +:10D6F000CBC7123A2CD4B194E7B37596C0857B1191 +:10D700006E535370F322BC106EE3C2B81D6C6451AB +:10D71000449AC0E1B309E193C63A920AEC8F5B4F99 +:10D72000C431DDA1D4FFF17BD0DF8EA38E705C37D6 +:10D73000E123037C9C9282535E0CE86E00796DD4E9 +:10D740001F5E7FE078A3F8B87C33E404E0EDFD3899 +:10D750002F45E3787BB6F2486D70E8EF203F5334F5 +:10D7600019E1E87473B8B50417C4715F3EC5BE60B3 +:10D770007D8E8E12DA278019C927FC9371DF829182 +:10D7800004CA25E287D3537A8AA7486649D33A95D3 +:10D79000909725CDFADBE2B884E3DD26EAA80D4EAA +:10D7A0009A87D3C7F705E44D8249B84E96F4A0BED8 +:10D7B00000720FDBE372CF8CC5FC9D349ED1BEBDE1 +:10D7C000A8940DA44F2BD80EEA20799C29E8DF6E8F +:10D7D00070F8D8C65B649DEF59B7F329FABB267D74 +:10D7E00071F0760A7BD7800F00F115ECC0A4076EAC +:10D7F00052D94109E44853E88771DC9F4D5804FB36 +:10D80000DBCAF8FEB3986C91738E10D7577721F16D +:10D81000603F41AE67B9D80549AA103C3BBDCB90EB +:10D8200053F7B3D8BB885F63D6F748086735B7624C +:10D83000A459BE18FA260B2DA2FA7BB6BEBBC18531 +:10D84000F2E3FB5A09E184C0AF3D02BF52E36C240E +:10D85000BE91684CB0B755941FBC7F3D1EA5FD1C02 +:10D86000B39EC9384E7E43AF84A951DE87B7826E1E +:10D870005AB62CC86058EE0ECBC8A7C676943CEBBF +:10D880000E98F135CA16A5E3D032EDCF03909E3144 +:10D89000F016C6CF5FEFB5E0AB818F674D97F1C84B +:10D8A000A171B0BE4B05FC2F15FC8395A9EFF418B0 +:10D8B000FB4AF68292CA03603EBA03FE837A6D8900 +:10D8C000947844EA5F3E4FF0A379F8DD981FCCBB13 +:10D8D000489684DDC0E5D23C5176F8A937264C83C2 +:10D8E00029BF1476C05E03749F7A6ECB34E8FFE5DF +:10D8F0009990D7C57C73B13FBE0F2F17B0480D96D6 +:10D90000974B8938F43BAF7213D917975638483E76 +:10D91000CCC3F99BE0F2F1C1BF28B80FB7545ABF8E +:10D92000972193A4F98478FFA26C4DA983FA7FA96B +:10D930004C227A3EF2D67B77CF86F91DAB94C23863 +:10D94000BF97C26FFB982F355E1FBC74A621BCEC3D +:10D95000E3A4F86080E46C9680770E28288CF802A7 +:10D96000D7BFB2C5FA72B57A9263C18A8E439C372B +:10D97000F1FD1E19E9AA423DE39EF425BF8F115C1B +:10D9800098AE4CA7D93362F84C898B71A5332E948D +:10D990009B2C827C2884DF8DFD0178E5AC34ED176B +:10D9A000FC9B16552CF3F51459CB1DE6FD2D48AD07 +:10D9B000C7C0278FA17747623ACA8D3629FE26A8AD +:10D9C000E06C8B7B72D53CA02BB587317F00E59551 +:10D9D000924860DD719CCF3B70DD00E7B4A03391CD +:10D9E00084EFEE7CC6BA91972A1D6E84AFA3381AD5 +:10D9F00097F5D4FAD9BA2CC29B3431D7CDC5AF6ACA +:10DA0000483F467FC0502C72CB8EEF8ACEED0F453B +:10DA10006FEBE6A9D027B47A86F0067D678D8CE39C +:10DA20002C9506B4B78C7186A5ABB3AD0724A1C005 +:10DA3000FA6F07C8A03ED450D9F0660C3E9E02FB98 +:10DA40001FE7A156F66EC0FDCF38BF610CF20FFF85 +:10DA500039DC7FB178F652F62EA4C14034FE2EEAAE +:10DA600035B283C3A737DF22CFD4E4D54C47FDD6E8 +:10DA7000178E4490FFB012D28380DF50BA47E6FA87 +:10DA8000CF0F44FA80CCF563586EC4DC0FE837DB67 +:10DA900064D473235AB5A2A37DC4F99BA1E7DAD756 +:10DAA00077AFA0F33DB246E9A6F4EF0471FE6E290C +:10DAB00076BF4CF08958FC039E483C89A9BDBE0A3C +:10DAC000D340FAF0CF5EEAC6F1944AC3EEAF27FB2B +:10DAD0000DF66B0FF5B7D86A2F790211410FEC43A1 +:10DAE000D20FC4F74DA3BFE51EC8BE2897633F9170 +:10DAF0004DF8EC0C72FD319D3DA8A1FF09BA1A77D3 +:10DB0000263BB56F084BC4DBD365EE840BE821DD03 +:10DB1000035C1816E393DEA1F9A23E877A64063609 +:10DB200001BC6A6FEC26BB0551A80250383D6CA2BF +:10DB300047DCDF14DD0AFA62C7C7C17A7C62DE3EC9 +:10DB40005F8CF3E530A74337FC837C26836987101D +:10DB5000D4191556FAD58AC2C43F3223D6EFB884F9 +:10DB6000F42C4CAD7CF9764867C1F70B6063715DAE +:10DB70009973E504C9501699373E37358FCC1CD0C0 +:10DB800077B1FC35D01721FF99C73F1517699ADF88 +:10DB9000299C1FAAB334BFE29EB8CCC795103E3073 +:10DBA000CF53D6F96CF904F713E669F98EF339BF50 +:10DBB000D432DF53E6F936B8F9B858AF32ABBFDF2D +:10DBC000305ECD8AEA61D27F92859F59610ACAA5EB +:10DBD0004FD987915A94673B4244277E4DC0D7DD89 +:10DBE0004DC8A8318DF8B1DD7F08FB75DABC5FAC9C +:10DBF00042E475E0B31CCED6721622BCA1BC83F5FC +:10DC0000D941CB2B0420997ED57F008BB8F1A8CACF +:10DC1000DA31FB25D49A8EF8CEFF4EBDCDE5F08DDE +:10DC20002847215DC1A27E9CDF474CAE45BBEA235D +:10DC3000C448D8878F7CD3F76CE0F8E2463C6F1677 +:10DC4000766E8E43F8937CAD9CCFB13E7C93CED064 +:10DC5000BE72FF08E879847771E6DE4072BE8DCB34 +:10DC6000AD38FC83F96F7658E5D80D3BACF96FB150 +:10DC700005B9C8BFBE759FCA90AFDF6893135FC96F +:10DC8000DC2F7303AB6F45FB6793F03B2DD7989266 +:10DC90000DFBB6E6170F4D477B2CE4E0FCE7CF60A9 +:10DCA000CFEAAE14DC570512CE48716A7D0AE3EB69 +:10DCB0006B92C297CD96065FDF26B5FB3294D7F103 +:10DCC000AD2A9D6F302127A93D0CA51C70443C5303 +:10DCD0002DED68BED7B759D737DCFAEDEB05C94C47 +:10DCE000EB5DB5BF8EF8C760EB71EE97C8DEB4F39D +:10DCF000A1690EC9A23F1B786ED019E035D7BBFED3 +:10DD0000E04934C17857E1A10CE92FF533B81FB6CB +:10DD1000FE5C4C876B77CD3FD8EE3A6C97F3F5DB22 +:10DD20005D3F48BBF640228AF466E8FB1E773DDF84 +:10DD30004485FBE7DA83C39487A0DC3144F9B8A1BA +:10DD4000DB03DD9D39037851871F490F8B87705E98 +:10DD5000A71AD1B1CED851357A39DA75475F733009 +:10DD6000B0A420AFB506715D2D928EFA79DD96F9DB +:10DD7000545E77DC11900B04F162FD828BF6A27D7C +:10DD8000B9CAA172382B3D0AEA0F75150517A0EC28 +:10DD900038AAC64399307EEDF7B9FD5155B16105FA +:10DDA000B6BB4CBF5A4579F2DCE34D4B31BF4ABF9D +:10DDB00050413E7C9B83FB033E7AEC89E90CE6777D +:10DDC000F4A7E92C89F357124ED47F56013E233E27 +:10DDD000DDF44FE9A44FAD7A72CD9E79D08FF48BEC +:10DDE000749A4FED9337EC73D1FC9A387E3EBD3078 +:10DDF000E31EB12E3780E6E806E1978CC7430BA1FE +:10DE0000C91A17BB0EF503030E067E2E6F2BF96D94 +:10DE100010E7B53F93FC6B7D78AD407D685F07E907 +:10DE20008201F07AA783FBBB3E2C702DC6794AFB9A +:10DE30000F5D4BEBEBBA4AC5F549CD99CE3FC178A2 +:10DE4000DBC43AA11EAD23FEA894180FE51F3E2A9D +:10DE5000F175754DD9ED41B8EEDFED5C4EE7101B65 +:10DE600008BEC67C97EF2F691D09F5966FC92C4433 +:10DE7000BD71CE3FFDD4DF03DF6FD9EF48A29E070F +:10DE800029E97BD7B739AC763D487409F0E066C123 +:10DE90005F6E3EB086F8EFCD5D77917CBAE5A06A03 +:10DEA000914F00673ADFBAE90D47186D929B7EFEED +:10DEB000633FEA597F0E3EE6473B0EC6A973021D3B +:10DEC000941DB3CA35ECFFF3ACFEFD81E246E739A1 +:10DED000B7746DE6E3312E470DBEF267FC9FBCFEC2 +:10DEE00072EE90C37A3EF6293B361DE53EDB9F3D40 +:10DEF000A0FE69C83583BF805DB42B0EE37EF8E4D5 +:10DF0000FFDA85FEEFA35FFD65D79D08F7673C1A32 +:10DF1000E2F72D8FFD69D77751CE1C74C988271F72 +:10DF20003FF3E37D3B21FFF1EF27962249FD87E098 +:10DF3000571F177C968BEB5FF7CCDC11888FEB9E1D +:10DF40009A33820DE0D730D28F01AF1226BC32F463 +:10DF50007BFD20F43702B2BF12A96D5F0E1F702443 +:10DF6000D145F4D19B2ED2BB6E816F0DA027DC5C16 +:10DF70007F03F90931BF1EE07BF3E3DC1EEC0FE702 +:10DF8000F82839886972149AA0371F5878F979658A +:10DF900098AA611DD7CB7A494ED9DBDD721CF6F306 +:10DFA000DCC1F7EF53F6A513E17E0BEA3353FBEF29 +:10DFB000DF47F83F33FBEFDF170EEB39F8A76CF5BF +:10DFC000C33BB1F040F680F6BBB17F6B9EBA2263D3 +:10DFD00020BF9119BEC9B380EF4AE127790EC4A1D1 +:10DFE0008274F7E44FF6ED0CE0FEBAC2F370BF7F27 +:10DFF000FA693E2AADEFABBDD722FDF53EE3D23A3A +:10E00000A1CDAA67DE2039F6F153AF3875E2E7A05B +:10E01000FA827CFE98F5FD75A3BCBE59F87D6FD9D8 +:10E020009B9E44BF8EB14F3727E6D7EA7EFA4EFE5D +:10E030009E9B131CEF6F4E1C5A240DB06F554A2146 +:10E04000971F891C82CB1ABDDBA9F9ACFB2955E0CF +:10E050003E9EBC00F16EB07D34D6AFE1FA6798F613 +:10E06000732FA7D7C1E8F2E3DD2E45CA48EDEFC70D +:10E07000428FB92521BDC106A057C33FC41C4B87A1 +:10E08000DC273B3ECC56ACF860B437D63D1C3D0F88 +:10E09000BF9EAF07AF73D0D82BEF0FB70D73397F8B +:10E0A0007EA9C04576C22BAAFEA35B113F9E57599D +:10E0B0002734B9ACF03D451FC00E7F19F5A189A9E1 +:10E0C000FCE515524B36B4BB3C02F2444FE1A9517A +:10E0D0001EAD7430DD349FD3B5EB42486787838C27 +:10E0E000CE5F8EE4B104EEC76FF2561FC1EF5BA0A6 +:10E0F0007F06FDB7366AE834646D8D414AFBCE0574 +:10E10000234532EAD96B51EFC7F1F63FF6D8638069 +:10E11000A717E30020A20E83A834DBB36F8AF9BEF1 +:10E12000DAE8263DEEEAA2271494DF52F1130ACA78 +:10E13000954B624F2878BE75A4EFBC456FC123B8DC +:10E140008B8B324BDBA1FFDF485CAE5E3C6FB7B21E +:10E15000DCD4EF25A29F4B8A778790FFBE20CE1795 +:10E16000EDF07A4AE1FC75C3A41F8770BC1746FF27 +:10E1700028C48DB120F925F3855FF2C8F81F3FB898 +:10E1800016E078B4480AA3BFEC68C3461FF2E1A3C7 +:10E19000FA420BFE1D9AF49E84FDE407772BC8AF6C +:10E1A0003B914FC0FAF6C2FA905FEC03B8617E3F34 +:10E1B000C00DD3C71A754A1F6F2CA2F29F3586294E +:10E1C000DFD55841F9271B23943FD0584BF9A71BA3 +:10E1D000A3943FD8B898D25F35AEA4EFFEF6FDCD3C +:10E1E00059E8879F2C7521BAFEBAB19ECA938D0D4E +:10E1F000547E9BC2F583FC36D686FEE286067E1EE2 +:10E20000D3A94617474DF337EA3DAA70FF426F5A2C +:10E21000AC13F9D6E9DA45E5B8FF2DE3AF9A82FBF6 +:10E220007854BF3786FAC5A7E3DC74D6402E4CA0DD +:10E230008BE7C7CFA0F3CED519B1471593BD5FD8F3 +:10E24000E664C969B88F899A5C947FDF04FD0EE0AB +:10E250007871ED6E2517FA59102BD065DACFAEE63E +:10E260002CB42BA688F279256A75F1F0FBB85ECC48 +:10E27000FBB9AAFA10D2D97342DFBA3AE660452652 +:10E280003D6461AD357F83689775D1B821CF77D371 +:10E29000C350CFA2CF703A72A1BFDCECD7D3475A9C +:10E2A000EA39B43D51F4170FC69F1CFE5AAE276BD6 +:10E2B000CABBC8DF64B477E514BF31FCA64B98F144 +:10E2C00017A1FC757D79B0B00CFD1AE0754DE4B86E +:10E2D0008AFAFAB5600229902E676127EADD60DFCD +:10E2E00052FA2D564FA92B9454F979638D86E70B7A +:10E2F0005264B6E34CDA50FE34EB3984FD1C7E0CDC +:10E300004C0CE11D9CE58E99EDAE0F047C3F13296A +:10E31000E0D11AC49FC1C631F88BC157BEF0453F4A +:10E3200051CA53FB63A483B5B7EF93311F23AE20CB +:10E33000EBA275CF8D862DEEECD0891F36F448A464 +:10E34000BF8F3D51D04967664C27FEE5F208FE2598 +:10E35000F4DF06FC5F3C375894967804E54F57810C +:10E36000A55E70A4E157EDF120FFD8D4708AD2D316 +:10E370000D85DB27B2E1D76BE7A75FF862D92AC02A +:10E38000EB4763A66E473FF9AEE71DE417DFA5F63E +:10E390005C8DF36838E1D237C27C5F562201B59CB0 +:10E3A000F8364DC5C0DF862DFAF6227D70B874B6FA +:10E3B000150E0947FBBCFAF07110FA48E109AF07E6 +:10E3C000760A7397125E267520919EB48CA7BBA126 +:10E3D00074594352C5FD7F5B894DC1795FC3122AD1 +:10E3E000E2E39890968B4CA4CAAF13BC77E5BE9B32 +:10E3F000474C45E929887E9D7820C60694E39B8496 +:10E40000DC81E9901F285FF871E4B40FF3506E547B +:10E41000A9D280F113AC41F9D01CD705B298E432EF +:10E42000D4A573993A1C18A65627F790FFAD469BC2 +:10E430005F930920BA767D8190B71C6FAE5D9FB95E +:10E440001BEDD5096A6C9ECAFD02E4EFAEF34DAE3A +:10E45000417DED6CD707A3F7A01EE812F46EACF770 +:10E460001D77EC2AECB750CBACCED491BEB9FF7877 +:10E47000AEF0379E0E30D2E707EBFF5F447CC863F7 +:10E48000B0EFE847553F641DA82F3E07FB8F7994F6 +:10E490005758FECF20AF30BF0BE415E60F83BCC248 +:10E4A000FC3320AF30FF38C82B4CF7819CC2EFA75C +:10E4B00059F446C46335C0CF9F9B9C6C25C59FD93A +:10E4C000FCDA6B05FC8DF45695E3410B3AEC505E9B +:10E4D000BCE5E4E7604AFDA805E93C45BC98B637D1 +:10E4E000E2C0B31EFF319640BDF6E2FD1D4770FD50 +:10E4F000E177B4667497DEFD52D1612FE4FD932578 +:10E500003A17DFF14A43D283E572D7613FEEE36FFA +:10E51000F939E053E32505FD2AFEEED66FA3BE5977 +:10E52000C6221BC83FABF41E7241BDB2455A18FD4E +:10E53000883B5F774670BF763AC34734D8D79F2F62 +:10E5400061E14EA42734A241AEEE192FC998FADB3F +:10E550005EBF13EBF9B7BCFB3DECCF5FF4C0AD94ED +:10E560008E7BF436FA3EEE5F6EA77C77F20E4C4758 +:10E57000689F2C7E15E6953179F32561E82FE390AD +:10E5800072111A4CC1C3DFBA0BED84E00B3B36634A +:10E590009A37BAF3F92A287F4E2D20383DF19BDCBB +:10E5A00079619847CBB7E512C4B7434A36E51FA84F +:10E5B0000F50BE54754491FF3D5DA9D4264C72FEA8 +:10E5C00041959F67EC539D942A8A83F43D23DE5046 +:10E5D000492A6437A8C7F9798E7A94E75D5A07C546 +:10E5E00083EC9262FB088FEBAD712DC639CE632AA6 +:10E5F000F74B96EEE6F87FA0474EA01FF560F7C6F2 +:10E6000034E48B07BB0B1DA83F952ADCAF72B0E743 +:10E610001E4F3AC0F9C1EEB523381F8EA75D05FD28 +:10E620003CAA7A697E4F221E949BDB6751FB1253F2 +:10E63000FB0C5C37B62F48B57F42B4FFA54A346B5C +:10E640006A2F3B300D637B1F6F8F7A47E815EBF81D +:10E65000FFACF2B89467FBB52F9571FCB1627C3BBF +:10E660003D1D12ED5AA478DA54D467D628DC4FBA8F +:10E670002E8BF4CA728FE029A2FE4981F717F79D0D +:10E68000CFC5689CA78F17D2F9F5E07C414EE91FF2 +:10E690002497BD293E4FF92C5B7EA4AD7EA1AD7CB5 +:10E6A000B2ADBCD49A5FC1F5FBB0D08B1B58E2C1B0 +:10E6B000B5281743323F4F7FBC88D617F618F8C0ED +:10E6C000E56989E803E4E85D547F9EC2A8BE90A393 +:10E6D00025428EBE9067AC5F4FC3753730EDAE629A +:10E6E000AC7F4C6604BFD858AA5F28C66789F13C46 +:10E6F0002FC63B1C2A7D11EB1F38CAE5650A9E51C7 +:10E700003AEFFC85147EB118F9C945D6FDA810F37F +:10E71000B3CBBD666716E14F67F70237EEE3BD3551 +:10E720000A8D5BD8159E83387F51A8E030A6784EBD +:10E73000F24B00D53806FC08B6B2F3DFA6CBC8779B +:10E740009E4FEF98837CE6E787804F40BEEAFDFA54 +:10E7500036F467359CB8B0BD16D2D14EABDC39ACBF +:10E760002C64683FA86D8B283E8E1D63147757B8C4 +:10E77000B9CC7183090FA68564C2BBC2CD014EFF1F +:10E7800081BDB31C82FE96A463BF2E7E3E11E2764D +:10E790009C896E473B916E170F4CB7631D2CEE4062 +:10E7A00078BF2D733DA7369E36DF14377730097C4E +:10E7B00004C60D1F2A3B7D14E3DCB459D390CF74FB +:10E7C0006E76F278CB31E13D487F539C9CAFB0F739 +:10E7D000D960716F539CE5FDE3DEC6307D5B0D4C67 +:10E7E000744C378F631E93E4E70F07BF04E9EAE830 +:10E7F0008FEFE7FFD56BD16BE40EAB3E3E8699F40D +:10E80000F18201F0FDC439A9FA85A49F52FC3BFBBB +:10E81000F20C9D5F950D12D7F330E209807837C86E +:10E820004D4C0FC617B87558C76F030B68FF583C9F +:10E83000E2AB82F6741C05F0A91071766AB33E87CC +:10E84000F84E9BDE847E36D771168E4095AC57F815 +:10E850007953679225D0CFDDA9B16CF2BFF470FF78 +:10E86000A6711E89F484FCD975DCEAF72C14E758EC +:10E87000619B9FA450F8530A6DDFED7E916B9D560E +:10E880003FE7DDDF75D03964FC7507D1F59E992C23 +:10E890002E65F0FA781EB5E302F7EE76E293DC3EE1 +:10E8A000794AF465F84B6E72F2F3A6236F4DF422A9 +:10E8B0003CD63A75C2C7CE2DD3BDB8FE3DC70B4975 +:10E8C0003F3E3C6B725A0FE9653C5EC525FAD9386C +:10E8D0006BF28B2B619CA7012E686F1F082D1F8583 +:10E8E0007165F7D4B829EECCBF471B8576EB13BB17 +:10E8F000855FFD043F9F6E17F0261B1EE0EB096944 +:10E90000A477DDE994455C6AF44EC43BD9CDCF27AA +:10E91000FC63A551E857EF2A90B87F61987E9A531F +:10E92000FD349BFB31E9812A3FE74872FF81C0FB40 +:10E930007CB78FF40FBB3E597782DF2B00BD701B75 +:10E94000F6771D8B46C83E03358FFA397BBD304EB6 +:10E95000F013F3CE0F14C8A807A5F4C3E84E27C6DA +:10E960004F86B48D58E76CF5C25D8D3C7E780FEA1A +:10E9700081E331FE09F44258C78B421F7C58E88D71 +:10E98000A0E7ED735AF4BCF0628C4F39D41A9BA304 +:10E99000CC443D2E5C8AF99FB5C69ADC901F23F7C4 +:10E9A000E66148F9E1D6BA3998F73749249A7E05E5 +:10E9B000F97808E31418D7FBF631A1F7B1AC5AC8BF +:10E9C0004F5A1108A3DF678C1C7EA108F9D42A7E58 +:10E9D000BFCABF97EB51FDE854F887FC4D996B1106 +:10E9E0005F0E0B7E7B58ECA3915FA6C492C417C147 +:10E9F0009CC6B802E39C580DC4883F1DC60007C4DE +:10EA000067A726CE9B3A46F2733648D307DC7F6E63 +:10EA1000670CB7FF7BFBF6FF65849F79FFB30BCED6 +:10EA20007EFF816F116B1BCCFE717D7E0E5ED6EA80 +:10EA3000CB9F66B1B768BF423C5EB46FDF64D0CF96 +:10EA4000217588B83DBF637E3DD2C727829E8DF475 +:10EA50007D0137F68E95BF035F7F1FE1E851EA45E0 +:10EA6000F009E7EBFE26E8C76782AFB0BF8CF92C50 +:10EA70005396FF6FA7C92F897047BBECB4016F563F +:10EA80004FF1DBA0F753FCD13F0CEF501FBCBF127E +:10EA9000F446F3CC077BECEBD05BEA1C566FD61048 +:10EAA0004FBFCFC208FB39BEF99678D35352CCEB97 +:10EAB0002A4FE9070D27C00E3917E7DFA372F8F4D4 +:10EAC000AAB89EEA6CBD4C42C59F6D99730C586103 +:10EAD0003512295E4C6277CD413F66751ACFCFDB88 +:10EAE0007461731CF378C6300BCB7F3C07CF09AA47 +:10EAF000C7F2F22896437EBE1A19E1329D73C336DF +:10EB00002498C96E54B59355C81FC06ECCC7F9E997 +:10EB100021BD1AB724BF41233C385BFE9010F4BFDF +:10EB200057F009C0AB22EC4F8D73FB7138BBAFC4FB +:10EB3000C5F1C8484B91D9E798ECBE470DBB2F31C2 +:10EB400092DB7D8991E6FDDF8BFA22F27F4527B9C2 +:10EB5000D2E7A769F670FD45E89F0586BE68E3CB5E +:10EB600086FE59E0B1E24D46BED16F84FAB5E3911D +:10EB7000A1378E15DFEAF673BCF2FFBDA96EB38430 +:10EB8000FEB75EC24B55E0D5563CDC03B8EC6EE3F5 +:10EB9000F715B2EEE071CC7BB7646562FFC79D915B +:10EBA0004B5DE5A9FDBACF19B9DC9C87FD8B0DB291 +:10EBB0007F579ECDFEA93E4FDCBC1F06FC5F12FBBB +:10EBC000D68DFB08303F26F8FC6916B90EF1A7C9AF +:10EBD000A993FF29FE8283F8EC607830981FCBD888 +:10EBE0006F839F34BAF93EA752CE875F12F50A2A87 +:10EBF000D82C2D23D5EF77055EBCE419380EEE0E28 +:10EC0000176FEF6F8A129F6222DEB1602F97D7468F +:10EC1000BD3B5D92E0239A2CF8B68CFCE43231AF18 +:10EC2000C20A56691E77B318F7322F2FB78FDBE66B +:10EC3000E27CD0E08FC6B8855BACE3B68B7E0CBDC2 +:10EC40000D3D0F38EEA4E65E8A572EC4386648F5AF +:10EC50002DD108EA112FCD7C6FEFBDA8CFE71409A5 +:10EC6000FF5184E17DB807443F3B9D91208EE70032 +:10EC700038A19F211FE68DA9EA6327898F37C449F0 +:10EC8000DF33E9FB0F101EFD75E0FB6D06DCFD0AAE +:10EC9000AB7195A6E6FD770157236FACF3B28A4FAF +:10ECA0008E64C3FC26DCC7E3B7A311EE3F2D8C8432 +:10ECB00076A3DD9C2EF6F3B1366E778C77C59E7CFD +:10ECC0001ECA1F7EC449F75E777EDF19413AD9E933 +:10ECD000D4DB517EB754CB6417E5D67C5BCA86740F +:10ECE000C70F5A9F789EE1E551EEDFE86C2BA47ABE +:10ECF0000FAECE227F86910FADE1FE8DFBF7DF7365 +:10ED000011DD4F6AE3F7933A6D7E8E7F76713FC7D0 +:10ED1000619788D7DA2FD3BD973E3F47A5F073ACF4 +:10ED2000177270856CF7731C263E3A889FE339177B +:10ED3000F773DC9FE07CA7A98DFB393A7D855EB433 +:10ED40005F3B7D0B48875423DC5EEB6C137E0E9F8C +:10ED5000E1A7D0BD57C13C7EEBE2FE829791C07324 +:10ED6000866E4F7E0E9FE1A7E0ED5F72713FC71B7D +:10ED700067D19EFC1CE9D6F15F17EDFF88EDCB87CC +:10ED80006AFF64E60D26F8FE41CCDBC9F4F6C93013 +:10ED90009F3DF7BF19A67342D6115B05F97D927EA0 +:10EDA0000FEA6DF13CAEA7ED91AC74FC91A0A37499 +:10EDB000C10F0EB7DD23A33D30A9EDBE6A2FF2F1DE +:10EDC0002D60FF32B27F65F3B86357C8E4B729DC22 +:10EDD0003C8EE391CDFE4D770BFB7705DF6FD37E45 +:10EDE0007EE51AC2FE4D77F3F51BFC069AD6E0FDD0 +:10EDF0005F635C03BFED7461DC2F5699E90FE6D5C4 +:10EE0000B198F303D02FD3DDE5A9EF2362B9C27E19 +:10EE1000020A827C7014F72F1AFC08E8B1D94C8FD3 +:10EE2000F5F67105BF1B8E1E1BFF8BE8F14AF77FBD +:10EE30000D3D9EE376503FE5EE7F981ECBDD43D03F +:10EE4000E34C37D717FFB3F458E1E6F450E5FEC7BB +:10EE5000E83122DA5FE41E8E9E06A6C75A37A7ABBA +:10EE6000F9C3B6B7D263D4FD9FA3C7EBDC9C1E1BCE +:10EE7000FBE8F1143FCF6E7B6703FAC1411D11F42B +:10EE8000A858E8511F861E1B07A7C75B683F07A14C +:10EE9000C746B17E430E43D366333D360E42171844 +:10EEA00088AA0C4D8F8D67438F76BB02ECAC08BAF5 +:10EEB000A006B32F18D86D88C7F6F3B6E1CE892F18 +:10EEC0003FFF0EF2234C502377BB4D7A7BB91ABB20 +:10EED00097F236FEA206787C7EFF7701ECF71D568E +:10EEE000BE19D3C90E7900FB1953114D5AEE3B4C94 +:10EEF0000C07C3A897675AEF4DAB1ABF57EE9FFD9B +:10EF0000654F13EEA7367D1AB6DBEF167E3DDB7D2F +:10EF10000003FEB09FFB11AEC6FEF6DDEB40D794BA +:10EF200069FEAD79570E764FA0CB6DDA4F3530F4D0 +:10EF30003D81AC8B145AEF5AC91B46FA6BCA630762 +:10EF4000D02E6B12F1227DFD80FDAB83FDDBED2E1B +:10EF5000B4C4BFDC1E885F8867E768FF73B8837D31 +:10EF60006A8133B7FF5D72EC08AEEBEE597F7ED35A +:10EF700081F17A4F7974A4D78FCB4E3B316E01DD8E +:10EF80001708B7F81D5EB23B9AA49E3A6EDF25992A +:10EF9000D92F83F790E7A3FF0EF107F95E08F0C7BA +:10EFA000740FACCACFF95753FABB7938EEDB02FFC6 +:10EFB000F12F04F41113F3AA53B8DD7B1DEBA674F3 +:10EFC00029EBA2F46D25F626AE6309EB25FFD1C629 +:10EFD00034FFF908E7FFAEF999EE9F521CA1A8CAC9 +:10EFE000F04512F37DCA2271EFCDB04BC6DCC728C5 +:10EFF000AE69625C21B95414DF48F76CC7606528BC +:10F000001FBF95D1BD332827FE6FB49F98705AE279 +:10F010004A0BDAACF9B1E2BEC37871BF93BE17E018 +:10F02000F93EBF2F37D6F6DD88FFDA851F06F09B45 +:10F03000D8FDA40ECFC0F16383D945863FF46E1688 +:10F04000F1784C78CD1AB89FA125677A70A0F606A2 +:10F050005C1D6E1E3F62DCB730EC29F625B3DCBBCD +:10F0600037E8D613D23B916EF33CDCDED92545F36D +:10F070003C39263AB4C5676D9662DC4FE38BF37278 +:10F0800011AF45572B646ED7615C56B388CFF295AC +:10F09000D593FC7115D727914F7ACB18723A261564 +:10F0A00025C8EFED2DEA0A629CCE5D83C4E95CEDD4 +:10F0B000E17265C3147E5E70D75B12D9A7778DFFAE +:10F0C0004ED01C77E530E2AE467FC7DD6382CF26A7 +:10F0D000DF5A37CAC14DA10543C2DDD1E1A078A3F3 +:10F0E00061EBB5F17A8395BB7CAC0DFDDE9F8D8E17 +:10F0F0003F87A076893897BE3811811B8EBEF88F66 +:10F10000309D33D9E3439ADC6137FAF39B420B8697 +:10F110003CCF737D2EB16436C5755C8EFB7668CAB4 +:10F120007482AB43EFA27B6669C5C0F721F586EA1E +:10F13000F14E3D70799CC8F0709FEC117A36EC96D8 +:10F1400039FE6973558C213FDB9CC7E87EBAAAD98A +:10F15000CA451C9513D76D82E3680F97BB378A1495 +:10F1600051A8A214F76D1FE12B20894674C2F8390B +:10F17000CB6A0FE763CF2991551C1FADE506BEC7CB +:10F18000AB53FE06F4A7ADBB744539E2E1EB428F09 +:10F19000F467F33874631EAF7BB83EF9BA585F3B2F +:10F1A000E06B6262CA1FE16F929232C0A977B49C91 +:10F1B000E82C407A2CA2EF9B628FD78E8571362D7A +:10F1C0001AAFE1FE7CA6C65DA8375C315AA6F3F201 +:10F1D000ADD5DE95E673DDCBFDFC9EC147FEAA23CF +:10F1E0001E48C3BE1EF2B7B088A223BE4A827F9ECD +:10F1F000AB8102807122E85724BF64D8CDE59F8897 +:10F20000B3020EFE75E2AC7EA630079E13C57D8C60 +:10F21000F4B5F41D125DDA32FC2BF7FB17FC00E7A6 +:10F22000A31E8C515CD5A1E95EE29F7F6BE171A3C7 +:10F230002797CD26FDFE5579F9C3A8BFF5FEDEC59B +:10F2400030BEF8E4A597D4223F3CB9EC9A8BB1FCD0 +:10F25000A4C46A257E69D68FF1ABFEB1FA4F0F20A8 +:10F26000DC5A3C14DFA006FF25FA0EBD0713F1CBD4 +:10F270001550FFEF8EDFA6013CFFE03BFD03540B72 +:10F2800097B124C91F239EE7C6F4D863B8CFCA3507 +:10F290009714A1FEB9D5A9E523BFD8DAEA2A45BE5D +:10F2A0009EF9093024B4EFAE48E3FEBD5ED049308C +:10F2B0004EE67B0B1F31FB4FAECDE1FBE16E688963 +:10F2C0001494E1BB0A61BA6AE81FCBF1E00B5FEC72 +:10F2D00020AEBFDA5D42F118CBEA79DC8D1187737D +:10F2E000CD4A9E7F5DF81FED7A995D0F7B56E091C8 +:10F2F00012E471EF8A8FCB1FA629B6F79DACF7CF2A +:10F30000CCF8A04DB7E2832A9BF02102F830C582E9 +:10F310000FD29973CE1E1FB6211D015CAF9CCDFD8F +:10F320003FF1EAF02B442FAFAA442F467C9C1DEFFF +:10F3300037C5D6BBE5E2FEF461D0437BD9821C9D84 +:10F34000F07FED75B42F27251D435AB419EB35FC1A +:10F35000EEAA734691FE0CBA30E821E213F766FC80 +:10F36000555B7D90C67C3D7325BD3F5DA0FC31E3C0 +:10F37000FF754827727F3A59C2C257E1F9EF1285EB +:10F38000C533B252F8BEA482DF4B5DD2B381DE1723 +:10F390005AB25E62A74CFB76E60CE4DD16B8697DD6 +:10F3A000EF2B38CE1EBEED1749ADA83FB6ABBDBFA3 +:10F3B000198170CDE474D7E491F6A3DFBE35FDDD8D +:10F3C0009611009FF65C9DE20BECFECED609698497 +:10F3D000D7ED578E22B9F683469DC500BE7FC08B00 +:10F3E00071D8DFA274C2F77B01EE31A8FFA3C6304B +:10F3F00095031DFBBDC8C79C611684F22B1DDDF56E +:10F4000087711FFE238DE21EFEF6CBD8B978EF651B +:10F41000EBF45563507EFCED8ED818ADD8BC8EC48D +:10F42000481E77DE3352E687CE220E9D89EFB1511A +:10F43000FC7B82D28760FF4FC1D67D9C5660E86F0F +:10F44000A25D0FB56BF7777B68BEB94E8DBF3F10DD +:10F45000292F87FCC273020CCFDF1E72F2FB4876A5 +:10F46000787EC3CBE5C14247878EE77B93BD397376 +:10F47000F1FCCFBB7D77477918558A9CB91779B0D5 +:10F480001EF79BB57C35AD1C85C7C38DFBA3EF98DC +:10F49000DE1D1AB3BE8BE45C5A713488F7665A8459 +:10F4A0001C6A39E4E1EFDBCC5BB617EF298D29EE5E +:10F4B00095BE598CFD29D49FBE1EFA31E96B4B6075 +:10F4C0000919A51887D341F1CADEF16E0DF9CF9263 +:10F4D000A29A0F9401F008FF4E99F0A105E5A94901 +:10F4E0002F5967E82539AD55081F6F1D9390CF2E12 +:10F4F000F116103D142242C1787F2DAA1952CE6315 +:10F500005C78DCC5E3C2E313795C38E631CE0E5398 +:10F510008C0BC714E3C2B11CE3C2318F71E198C7F1 +:10F52000B870CC635C38E6312E1CF318178EE92FC7 +:10F530001B6394627C3896633C38E6311E1CF30BE7 +:10F540005DFC9E3B2B8A79CB112E93C749B8AFDE69 +:10F55000766704EF8D1C10FB3867F3A2ADC7619D81 +:10F560006911856C84B40795CCD7789E6EF6A60594 +:10F57000B91FA235F824C3F7B5D40BD229BEFCEECF +:10F58000B77C94A62DFA39C3B8884E557764970096 +:10F59000F6B55F3CD7ED41FA624D5961CC5FD9EACF +:10F5A0009EC4D8B4B24F563D09F97DDE680BBA9AB5 +:10F5B000EECEA97D55A7FC42CA8FADAC4A67743E1A +:10F5C000B6B0E508A4976130299D8F317AF72412EF +:10F5D00093C479188BBBC731763C72005823633FC4 +:10F5E000F12E6EB98FA17FAB2B5E9D89E75257B488 +:10F5F0002C9A44ED955C8DFA9F3B454A95E7B45DA6 +:10F600006A948BFE17B644A0BF574EC8D4FF46A8D5 +:10F610001FC7FE0BB54BCB90BFBE25937C7CDDA9ED +:10F620006F24FBAA1DF805CCF7F2287FBF636C0D91 +:10F63000DBCD0A046205F0DE38F73F94A7713993F9 +:10F6400029EEB7CAC019D11EC998F77342A20CDBC4 +:10F65000BD726FB1627BEFC2FA1E48791A970BC771 +:10F660000B19BDCFD33BC99D4039BF02F1793CEEA8 +:10F6700027A7B7CBA37B748CA3185BE42E45E67C4D +:10F6800000839478BB24CECF6867AF87FDCAA6728B +:10F69000A31DFBF22F0AF28596AD3C66C25B98D0A3 +:10F6A000D7165BFB95CB06EFD7548FF4D921C667ED +:10F6B000D210FD1874E57546D2119F7BA7F07D59D5 +:10F6C000B470AB41A732DAEB5EAF557FEC4DAB6E59 +:10F6D0004D83F15BD338BE7BBD5D470BB1FD790A2D +:10F6E000F941D9FEBA1730FF9D9D32F1BD5C05F698 +:10F6F00019FACB6DD34A908F1C1774921D58B10024 +:10F70000BF67EF50985E805B1D57F15E438049F400 +:10F710007E55BBDA3197EE3DA812C5D394557CFBDC +:10F720009232F83E63EEA7447F339E9125D4535E18 +:10F73000F471BC283937BD1EE5ED25E78E9E867431 +:10F740007597EDDE8C9186D3B89DB717CBA1BEB46B +:10F75000EBCD7AD2FFCA7D12CA9FBF7DC2E5C4DB62 +:10F760005EDEEF44275F3F631DA4E76D082A74DF68 +:10F7700048CEE3A953AD5F8E78E07CC84DF7719D0C +:10F780005FCD70239F6FFADC55CBF96037E97F4E70 +:10F790004F4CC3FBB585DB653AF76AD2BC097C4B9D +:10F7A0002923BDF4A88E726BAE42FEDF8CF314C227 +:10F7B000FBCCF42B13E89FD976C843F5D5747702B8 +:10F7C000F9F7DE9ABF466BA07C6FA5427AF8DEB6E9 +:10F7D0004551A2234DD6C693DC09FF1BD2D9DEF5D5 +:10F7E000DC1F9721B128CEE3F525B38375DC5F4597 +:10F7F000F7CEE9492DD9641F83A18B7E8C595A75A8 +:10F800002DBDCB91594DF15999736BDCBC9DF51D04 +:10F8100097E61A1ED786E5D7E33A9BD9117CB7C77E +:10F8200020DDCCCC7BA402F48B7D937F6BCE9AA59C +:10F83000D7F9705CEBFDF6029F3B89FA749EC6FD1A +:10F840009C7A11D71F0B84FF02BED3FDD8BC662B58 +:10F850003D23AAA1BE39266E7D1786A1B50DEB1BEF +:10F8600025E6A18AF5CF7EDFDA7E9488FF1A65BB94 +:10F870002F3F45E0871D4EF6F5E705F66AA85FE7DE +:10F88000C5797CA37D5D7901EEA729D0BC7C7D0183 +:10F89000BE2EFB3A6669A7AA50EED9D7319B756F89 +:10F8A000403C1CDD60FD6E9FEFAC9ABD51D4676794 +:10F8B00015290493D9ACAB09ED6663DFBD8556FA13 +:10F8C0003DEE75887B4AD56B908EC7B6C920005235 +:10F8D000FD8FEFF0B2B869BC893BB22CF949899130 +:10F8E00096FAE7EC2FB4944FE99A6C293FF760A998 +:10F8F000255F929C65A93FED68B5255FDE7DB1A5CA +:10F90000FE8C371758F2337B9658EACF7E7FB9A525 +:10F91000FCBCDE5596F26F7CBED692AF62775AEA97 +:10F920001B760E0B86BB23018CCF0C9420DF32E0BC +:10F93000B52CCDEA2FB7DB35763FB53F8DC37B388D +:10F94000BBE9A634EED7C95D54C862A6EF817993AE +:10F950002DF9E0D25216B3C831AB1DD5F2D5C2C5D0 +:10F96000FCBD5337E9DDCD395792BF75ED24A78E25 +:10F970007A16995E59683666F2FB02CF8FA7FBD0E4 +:10F98000AB3322B7E1FEE33DB37836DEC373923C7E +:10F99000F3FA9C64077B7D3FE4FADF3837BDA5E4CA +:10F9A0002D4AB0D814F46BB545C7817CDCD618A7B6 +:10F9B00054298AC651AE280146F7D1B4A25ECA6B5B +:10F9C000953C7F459A4EF8A655427DD3BA540DFA20 +:10F9D00031ADEB5599C779F4821DDE69B2C3ED767E +:10F9E000774CD3F61D6029FB1BECDAE437A85D1ACF +:10F9F000B52B44C3A974703BBB92753B303D9FF55A +:10FA000052BA97D517A23EFD9A33EE1809ED6FDC76 +:10FA1000FBCA4A9CC7CC322FDDD303BBFCC1B4F276 +:10FA2000945D7E3253CB4779BDD319DD7A1CC7BDB7 +:10FA300043652837AF9D7FA91BF9C1B5939430F773 +:10FA4000E383418DF6F9FD59612EE7851C519867D6 +:10FA50001CD4BBE2AE71A5F83D57A927799BBB54D6 +:10FA600093503EFE29CD908F652417B23B94B0AEE3 +:10FA70002368F46AAC176863E124D45B5008F2127F +:10FA8000E5FB0F789C7461D1842308A751AB9312D6 +:10FA9000BE17A745743ADF2C3C71E151C98FF214AF +:10FAA000E683F2F42145E08993ECAEB5F72B647759 +:10FAB000AD7D5EF5E013516B372B25C848FCE84758 +:10FAC0009D06FD54717954F8D08404EA03774BDA2B +:10FAD0002EB2735A5C61B4731E1078F010E205D830 +:10FAE0002327735B376AD07E926F37C5539E1338D6 +:10FAF000B411D329A19332BA4BCE1D27356541BE2F +:10FB0000A4B8C081E7A5D3CAAA9A302DAFAC7304BC +:10FB1000209D512361B81BFB5D1A3F77B87AC5FC65 +:10FB20003751CFA9F2B9E9FCA070D6FB8B911FAB7E +:10FB3000C3DC13547377D03B776C85F59E6095DFFB +:10FB40004D78AE219E17504A7AA7B6282D81780E9F +:10FB50007AB684E723F12AD6857A47289294501EF4 +:10FB6000423B3AD7D3921E09FD8AA322DD12E03C24 +:10FB70001BB58ED1396E7EA447C27BB7A1D5563C4A +:10FB8000FFC217FB13E24FFEBA36CB773FFAFD00F8 +:10FB9000BECD32E73FDEAC583AE28F776A615693CA +:10FBA000CEFD76F38B5378F38CD09B1E12FA8EC168 +:10FBB000BF0D3DF6409F7DB82721035EEFEB8DB56D +:10FBC0004F42BED020DE9BE94D3AC85F74DB7CC259 +:10FBD000C77CE19F5AFAD7AE960CA45357EFE10CBD +:10FBE00024989BB8BED5E9B1DAAB953ECEAF66F8A6 +:10FBF000B87C54DB41E29F6B7AAF10FFA0FF27D6A1 +:10FC0000737D5DFD83AF2D3383B1977D7CDE537FA4 +:10FC1000A555A39FB720A93D4BE931911E8154B44E +:10FC2000C78DC7A9225DDAF7737773E005ACB79B80 +:10FC3000692F68A6542DD42EA6B8D6DFCAB45F2C7F +:10FC4000C4E81EC0EEE62C7ACF957593CF9DE5DF14 +:10FC500011A03CD46F277FCDF7BD0CED0EBD41A1A7 +:10FC6000F7E8ECE38D617DF25CA6F789E23CEF6694 +:10FC70006D1B108FCE3D687D2FAB2469CD4F3B6A45 +:10FC8000CD97775BF333DEB4E6F70BB8E23BACE33A +:10FC90000C38C07FC6E8FCE84317F1F0631AB81EC1 +:10FCA000D15FEFB1DA374CE841D789AD99D963D547 +:10FCB0003BAE13FACF75367DE2A44FBBB20ED2C86D +:10FCC0007DB17B2E0238C51A1C6109E6F0C787FE9C +:10FCD000369EEB41BD39E877FAC2A7D3BE5E7B47BB +:10FCE0009FBF313ED1E46FBC2BFC6AFD61E473BF62 +:10FCF00077316C3FD771EC6823CAA5D10AC9256D4D +:10FD0000C6EA87D3D09F8CE590BFA2401F41F7047D +:10FD10009F57695F36897376E37D26C37F7685C0FA +:10FD2000C3F906BC583C8DFB619269A89F9F7B90EC +:10FD3000B1629B3EC8CB233E2C2F49DACB23BEAA0F +:10FD4000DCBE2343988244F02E17FA27E6D7833C83 +:10FD500029B3DD1F18B1D89A0F1F55494F9DCAA26C +:10FD600019C89FD1F4C67EA60E72CF60AAB86730BC +:10FD7000D5F63D178D33807B6E992F9128E87F9EB5 +:10FD8000B645AF97B07CCB52B048A0EA2D3E71BECD +:10FD900056CC8A71DFE7E2EF1C209C5FE3F7795CC9 +:10FDA0002727BE81FA017BC541F7873615E8DB516D +:10FDB0002E692FF2F775B5345652E24B9DBBFDF01C +:10FDC0004C18DF62EFF35BFEAC9131E4EB5D8D6EBE +:10FDD000867CFEC9468DF2071A83947FBA51A7F438 +:10FDE000606311A5BF6C0C53F9AF1A2B28FFEBC64B +:10FDF00008E5938DB594FFC85FD56CF77B9AFDBF7E +:10FE000029BF27D0DD39E4F78CE111F4471E8E6F4E +:10FE10007DFECF95DC2F3C7C3FDC5F8CFE5375A0D4 +:10FE20007E847F794D1BF797AEA9E0EF30AE29E3D2 +:10FE300076473BDB6D79CFC905FD627ECD81ED74E0 +:10FE4000CEED54BBEBC9FE2BF709FBEF76B2079B57 +:10FE50001E74B38D05293BD0B0FFECFAB8C9AEB61D +:10FE6000F073F4BC205E78DD12975BCCFA1EDF44A1 +:10FE7000D4250069276BAF3C9B09AC3F21FC40C5F2 +:10FE8000C14FAAC94F24F253F5CCC359A6F2705101 +:10FE9000C99C6C53BEC87D72F10693DF685C7AE939 +:10FEA000B3D9A6FC711C90FB8922C87FFF7FFB9110 +:10FEB000BAD1FF01EBFE49CE2FB2D00F10FFA9C27D +:10FEC00030BEE63739BF18897628CA1DF4A3E15E33 +:10FED000733ECF785C73117F67B94F2EE8129D9FF8 +:10FEE00098E4C20BC47F845CC8CF8CCB184F97D8E2 +:10FEF000CBC21BF421E58383CEC575A63BA78BF34C +:10FF00007839550EDA5392BF6FC7E51B95E3FDEDC7 +:10FF1000B84CEFBD99FAE1EFD1264CFBCCD0BEB284 +:10FF2000CA89295DD6FC7F971C32F06BABD24DE7B6 +:10FF3000B05BBF1C186FCF4B9704BEF6CD5B3E3352 +:10FF400023050F8A032AC4949703F51CC275C69A29 +:10FF500055CBB8D73558F34BD759F34B565BF3A66F +:10FF6000F184BCFB9AF978E435B39C7D0703A7269E +:10FF7000A6E4EC0A567001EA17DF64617A87E6FAB4 +:10FF8000B6348B9DF71ACA42F25FF2F786978B78E8 +:10FF90000956739CCE490BD6EBA4DF4F4B37E43A9E +:10FFA00097BF6E8040DFEF9D98C62FB8485ECBDFCD +:10FFB000C4B7CA71FB7B7FCB6DEF64EA367F825B8F +:10FFC000E7EF3AE7AFB7FB3FE3DCDF0FFF87EF1C5C +:10FFD000F69FCFD71BD7E8EF14F07F849BF16E5DBF +:10FFE0001F7E2B3D5218E6B11CDF4D41F8AD6791E5 +:10FFF000DDA4E77D83E25CAE32DE8B883392BFBA4C +:020000021000EC +:10000000A091E5029FECF05EBEF477B508EFE565E0 +:1000100032F90B594321D134E16121BD03E7C4F228 +:10002000FC2D12CB9658DF7DC4AB441F5999617AE1 +:1000300027EE54333FB73FB574612EEAF5C67E0311 +:100040003C2CF7060B1A4C7299211E7079CEC4EF26 +:10005000CD7CD326B78DFD5F6E7B17F4EF48473913 +:100060002857F8EF85ACC1F338942F8CBF0BD6EE30 +:100070001B5ABEF8E784DB26A09D9729EB68E7357D +:10008000AF506A775BFD71CE33E8ECC2FFCF4DD144 +:10009000DB1F65568376FFEF30E00CDAFFEEBBD94D +:1000A000BB31A6E9F5C573DCD8EFAB99E12972093C +:1000B000470C7725E43DE19F32C8BB5CC90B6ACF92 +:1000C0004BE5BDDEF728FFBB2CFD21CCEF4867F1E7 +:1000D0009A10F6CBF39BDA5EBEE0C868310EF0ED05 +:1000E0005FA69F6A8D57A6E81D961AE7F862A5BF1E +:1000F0008FD275A28BB42AB6DDE120BB727BB99496 +:100100006A9785EDA421DACD67DB9501DAF98C7663 +:1001100020635A4DFE3BC33F278BF998C757500FBA +:10012000D062E96837DC3D57D1D07EF9CFCE237756 +:10013000B875D7B1EDEAD8FEED60DA1B8CF9CB03C8 +:10014000CF3F81E5E6F1D521E6FF5F0D8FE1FA7340 +:100150008AF2AF3D3FA8BE31F72CD60BF3C3A718E8 +:10016000981E4B9787EA0F74FD8D03AFB7C3D65F18 +:1001700026CD2F18DB3AE4FC06E90FD6BBDDB6DE50 +:100180004CA7A37F7F489F4958DF68419F1933F9E7 +:10019000BD60364521F9315A613E67E900E3AEE3BF +:1001A000792F8B27500FD4EA7A76A07DFF7A91962B +:1001B00089FC75DBA199E4EFF76E96E80901AFDAE7 +:1001C00021617C6AC58A8E2A277CDFB98E75216CF5 +:1001D00077AE4B78F0DEDBCE9E8407FDFA152B3B25 +:1001E0003723BFAC684E27DE3B937590DF38F33C76 +:1001F00085E21632CE53E8DC21337316DD4FCF98FB +:10020000C9E3CF9AB5CA3DA864373BB5F924FFBE10 +:10021000C3485F1ABD82FB974637A861F4FB8D5631 +:10022000447E3D7F97D97B5BAFA413DFEA95F09CBA +:10023000C12B4951B4EF9A23DCBFE4FD1EEB948837 +:100240005EAC7E77AFD4B1A11AE1040C18ED97BC77 +:10025000C881DB253FA727E4EF044F84B7C2F58DA3 +:10026000FB057CC7B0EE43E80763EB783BD01C2569 +:10027000BC976F9C5318F1C979EBACFACF688DFF2E +:100280008E8EE2D2B693FE78BBC21E1980FEEDF9C7 +:10029000D1DFEBCE64C5C3D71B2E9F8F3F2595754D +:1002A00016F5847D6A3F1FB0CB69BBDDCF845F80CC +:1002B000E434ECD31821B72A8A9BE7D039443F397C +:1002C000CF7F57CDC08F7E76562BB7A35C2CDCE654 +:1002D000A4B894A514A766D86FBBB022E2C9687110 +:1002E0002FD9D65E6A688F92FC3D5FF4E3656E7C21 +:1002F00007C9E582348B7E7ECA9D877401B880E78A +:10030000A9CCCFDF59D8203105BFA7C6EB6167283C +:100310003E0EF84C00DF6B9719EAF586FF20753F1B +:1003200031AA217135696137DABDC6BDC45BC5BB71 +:10033000DB9BD2C35755E17CFF4D25BC690A423D8A +:100340008C0F4AD39731B053AEBD3B72A11BE5630E +:100350003523BB64957FF626BC7FEDFA7C148B9920 +:10036000E2225D4A3D4378B93ECFB77C7F16ECE987 +:1003700098E9BDC16A5F610DCE678378C7690E0BCE +:100380003763BB396E87E51CC0F5791E8B650FD4CA +:100390007FC8F2FD59D06363AEB3E93FCD72AEE0E2 +:1003A000FA7CEC20FD4FB0F5AF0DD87FAADF6C4B87 +:1003B000BF2D0AE3EFE62EE6716B76FBE17E7F75DB +:1003C000AB3FA7FF39CCA6103F87A13FC85F10C83D +:1003D000A4FB063BFCDC9F58336FAC42FEA890F5B3 +:1003E0003CE60281BF467C404DC0FEBB17617AF7F8 +:1003F000B8DA67FF6ED57F67238F29EF3F5F39BD7E +:10040000AC9BFCE6CB5CFA50F77C4F3432F287BFF2 +:10041000E1A95F86CEA05FDCBDC0D5520179E44181 +:10042000A0273D7FF79A0BF15EF2091177DF127872 +:10043000767CDD00F695912E559852513A44B933A9 +:10044000391EF9FE5299C5F8B9736CCA02D33B2420 +:100450004B618115C4571296752DAB972CE7302749 +:10046000C47D76984F79DD00E7E7E6F954660D51D3 +:10047000EE4A96D37CF0F72D07994F65E9F0F379B2 +:100480004BF8015B02AF8E1F6A3ECB14BEBE41CB60 +:100490009DDD049F65B2E1AFB6CE6719E3F01D762E +:1004A0003EC25F0FF3291F6ABF703E9543ECD732FF +:1004B0005737C16799F8FDCF81E6537916FBB549E7 +:1004C000AD8F21DFDC2E717EE4CB68D884F7D9FFB5 +:1004D000326F6D90E843D865D760033C0753383DD1 +:1004E0002D09B9E99E97D12FBE5B1171F1FBE998F7 +:1004F00076029D47E81DCE20E5F7819D17A178ABD8 +:10050000224A1F6B0C53F9E38D159437FA295E29A3 +:1005100091BD3765B544F69E7DDD5519DCBEDB9E89 +:10052000A75DBD02F96C95979F4FAC9CCD22EE94D0 +:100530003DC758D7B3E87FD97A252B413B7AF27E65 +:100540003EEF404D2EC545784B8E743742DE7585A3 +:10055000AAA3FF186831CAF18CD13B3275B2E01DF5 +:10056000C00730CEB5273E772FF28FCA0CEE47AECC +:100570000B1D5D8C7A449DB0FFF0BA2BF97F56714C +:100580007B3ED66C7D777689F0E3E644AD7EDF2551 +:100590006CCB27FC7738ADF66680953C8F713E8139 +:1005A0007A55871D241709CAAF9C1AFEBB32579C87 +:1005B0007C4E43FD959528A43F6DF76879288FF010 +:1005C000E7D4D0CE7439391D2FB5D9994B8679D758 +:1005D000D7F89D293BDCED7EE4E91956BFF1A7ACC5 +:1005E000785B0D160EF23B4D867FB8D7CF1763C8E8 +:1005F000557B3D633E970BFEB9AB3149718AC6FC12 +:10060000F2951E09E5C49886A425EE90E1EFA39823 +:10061000F4B2C1D6B14BFA306FA877BCF3855F1D39 +:10062000F468FA3D57EC06F568FBFAAFECB7FECA82 +:1006300097C7B181E885FBCB971C75901FD0808F41 +:10064000018FFFD774A36430E3DE1A6326FF9A4359 +:100650008EBAD15F951FA8A6384DFC7ECA8227D6D8 +:10066000384DC7B31F48F81E72BF38D2865E09F9ED +:10067000873D2ED43E1F234EAEEFDE8D8FDFA30BC2 +:10068000326F18ED05FBEF2FDC2EC7884FDDEEE84B +:10069000721740F984606C5306B4FB4CEED2AA206A +:1006A000EFCB295DB91B7A5BDA7067B806CF9DB3D3 +:1006B00007F6371AF2ED9E0CEE573BA12647A35FD3 +:1006C0007D49B0FA9E8C9C01EA377C9FFA3B5FF033 +:1006D000597BF9A302AE0F08B977D59A273FD8877F +:1006E000E7B07A7129E28EB7A87B1EFE0E58DBCBED +:1006F00063E9F705768B7161A165A847BC1F882562 +:10070000324CFCD9AD6B0ABFE7D53513CBCFFF3FD9 +:10071000C54FBC0CFDB55DE2D3F09CF82F658E3261 +:100720000C75B0CF03FA7914FB717FDE4EF86BF4D1 +:10073000F36B4FCF037498149F5DFB26D8A0BFCEF8 +:10074000EC1985EF9E3CB16D646D00E8E3D7393D4F +:10075000A3B0BC56FA60D311C0CB5F23AD811CF8A7 +:1007600022E3834DA85F9C7FF1877BB6A1DE3CC16D +:1007700049F75037DBEEF985341E0F14D2AC7038D0 +:10078000B67A68381CEA0F874366F81BF37F29188E +:100790007916BFC3242F9F2661DC370BAF80394603 +:1007A000467479A6C1BEE7E95D8F6E63681E27AA0D +:1007B000F01D2FE8E7050E8736BA9766F433271841 +:1007C0007911FB39B6FAD579F83B6C9E63FC5CD2A3 +:1007D0003D8EC5D3FCD4EE1573BBC8084DE1BF7F79 +:1007E000C1F7E1580EA79B19993CCD127A4993B3F2 +:1007F00023381F526DDC0F6FD5A05D6B417CF1403B +:1008000071DAAF6846FC29BFD7D3AC75BA979BE0C5 +:10081000F88980C7BFE7467A701E4E117FD55EC14A +:10082000E1E63F965D4AF6D2385686EF53A465F26C +:10083000FA30EFF7A9FECC0E32FA3DE3F87ADB8B03 +:10084000EFA138604FF03E9E8EEBA1FBAB1ED6E5CC +:10085000C6FDFE6CDBE79B9A2B701DE122CC8FD886 +:100860007E571BC68DEF469D01F4CB4CC8A31F6E6F +:1008700017C8357CE73A3ED24976533FBE2EF6FD87 +:10088000E940E43382AF1D4EAE9E3DDBA0FDE6495C +:100890004EF29B9E2F772C5E8EF874B18FE4367CDF +:1008A0005F6CBEF73349F4F77F01BB1BB70C0080C8 +:1008B000000000001F8B080000000000000BE57D19 +:1008C0000B7C54C5B9F89C3DFB4AB29B9C6437C96C +:1008D00086BC4E1E489004372F089AE209011ADEA2 +:1008E0004B091A0DCA0644A3BC82D5BA557A399071 +:1008F0000701834604F5AAA51BAA2DBD7DC5C755D2 +:10090000AE451A04BD684163A5082A1AD1DB628B83 +:1009100025825ED6D79F3BDF3773B27B4EB210B4D1 +:10092000F777FBFBFDA17698337366E6FBE67BCF9A +:100930003767474B1642CA09D9F0B9BD2E58484807 +:10094000B3B5D333D7418894FFC0F7A578421E31A1 +:1009500091C66E5A3FB0ECC98F7E564648AC5C5883 +:1009600022105A16F4CE2C7513D2FE5A5E8948EB2B +:10097000F1127D9A4CFFE121653E272127DCFE78AC +:10098000898E7B0EFE5C49885D96CC7E3ACEAB1E8E +:100990002541A2FDD289774E297DA57D0DF1DE404E +:1009A00097A02474C794E610922677FFE25E3A8CF3 +:1009B0009D04AB4C39384E2AF4B787DA3F11E3C3B4 +:1009C000E3547B140F3C3F0073D2FFC627B2D258CA +:1009D000377BACAA389696A1B65E56DADF877144AB +:1009E000D2A9123ABFB9A603C71543B1D84F0C75A7 +:1009F000F442DD2C35113FC5C736C15F00F39023AB +:100A000082998CA37013F6477428D8FE6C0241FCBF +:100A1000459BC79CDFC6C6274D44C8193C0F1DBF68 +:100A20000CF0641C3FC6AEF44029486CFC89D31D11 +:100A3000FE20857BA289F8BB0BC3783D2499B1FDCC +:100A400071C984655B8E5AE78B681FC07F226BA7D4 +:100A50006851603F5BA4EDF6458E70FB29BE7F6F49 +:100A6000A528D500AF55203EE8B7B182ED73FC0153 +:100A7000570991E95AF249D9F78A089113051C8F51 +:100A8000EECF0CEC3FA19310DA3F269FEDCFC6C20C +:100A9000CD4486BAE7312C630BFA105FB1A4DB4E6C +:100AA000BC301F516B2A60BD74CC11845CDBD9D281 +:100AB000AE661092247A0BA0BDE8BE07DACD13080B +:100AC000E94A62ED97D03AB447832F06E0A3EB885A +:100AD00007F868FBC1325135D1759F2145DB45BA16 +:100AE000D4F80AC9BC883E6FE0709E702B7EC43B70 +:100AF000E92340AF5DA47F8F8DD2B75A21781FA71D +:100B0000703AD56EC50EF0924E3297B6DF2C317822 +:100B1000B7D169081D57BD84041F87B59B3B09E009 +:100B2000639B95AE1DDE1F61C5E731F93D05FE08EB +:100B3000FC7ECDE7AD48F43501BEBA48DF689217B8 +:100B4000DE0F233CB7F3FE9B5395DB619D46BA9EB7 +:100B500038FDE44FEFA5EB209758BD2369B1412044 +:100B60007591E33C2489B8DE87F838495FDA9B86C3 +:100B7000E2EF892B9EFBE867E719672B87BB838F22 +:100B80007360D91F6796821C38207A058A1F7B0103 +:100B900051E3E2910E3A609DF6651B91DE9574C9B2 +:100BA0000CFC4BF97DD390FCEEA2FC2E0CC9EF5B44 +:100BB000A3F0FB0343F1FB3F80BF1F1B8AFF34FE02 +:100BC000FE91343C7C1F077C2743C9F0F54DF1BDF5 +:100BD00097BFFFDC85F1FD5C147CFFEE22F1BD3791 +:100BE0000ABEF721DDF1F963B4F9F307E67F05DF0B +:100BF00033CC6F8779D9B8AFE2FAF8B84A366D17B7 +:100C000080AE25A62788BC8AD0711F99E19036D284 +:100C1000E7CFB8953FFE2FED6FDFF9F67722F0F3BF +:100C2000E5F47F9DDF6B571DFF90F9FE7E3E7DF161 +:100C30004B2ECF8DF2C2C8FF0297AF142F9FC17801 +:100C40004639D945480DD0CD336EFF575C8E4D03E4 +:100C5000B9B4EDCE246123ED9BA1F4088974BEB331 +:100C6000090C8F2B24194BEDBD6DE61EC10CFD9BAD +:100C700024411574E3591393A38F675C075D5F4CA0 +:100C80006239C8352516CADB397C4954E1C178CDB3 +:100C9000DC7EE84A521B416EA772399D9A28F09279 +:100CA000D56B5395A444A64F9261FE3365E26DA6C1 +:100CB0005C26B7811E3539ADC163F205491FE89541 +:100CC0000AA2805E0CCBFBEB1ED7E4FD1207F437C3 +:100CD000733DA564C1B8298912D6B5F1A2ADB38818 +:100CE000AFAB88AFB328BCCE517C9D979E6F9D461D +:100CF0003C0D77BD574903EB2D4B2C8F3E1EA51C99 +:100D0000DD7EC218248DF24F0BE3D73907F2D04EA7 +:100D10005306F4B4EF4A184F8993F6B9A08148B14D +:100D200030EE23560A3785F791659BABAC743D5D79 +:100D3000ABA562B0E74634323D272FCBEA12E9DC9F +:100D4000D3F938463A1D78DFDA3DBAB410F1321BD8 +:100D5000E6B9B292D90D09546EC06CC0FF948948AF +:100D6000924DF578E97ADB05D5B308E87F9AC3FBA5 +:100D7000387470D4E2FA8DE36B2521EB707E0D5E42 +:100D8000E228BB40FFB5D85F8A539B7C17D3DF4670 +:100D9000ED0B47241E5DC5882E7BFF3E17AD2BB69D +:100DA000C4E28DB4BA82DB53749F6E467E7150608C +:100DB0002784F13A787CB65F55BE2601F01C53407B +:100DC000A7023BCF479F53BC99E44ED207F6513E52 +:100DD000A58F4218EF108E175E4769A97E1DC5A525 +:100DE000B08EF0F86D9A5D73D7C5AC47EB171D2F29 +:100DF000AC5FC01E3F9650DE3B1BC34A75126D822E +:100E0000FD7B3726D84CE9E3128FBF83D16BD378B3 +:100E10005F119697B1B287801CBC92CBC12BED0EAF +:100E2000949BE42BF3C93E3B7B768EF20F95962480 +:100E30001D6C3DB240FAF3185A277DC2B9B88B9A9F +:100E4000FF5126B7F4F32F08DCE59D5C4AB1E022A0 +:100E50000B7D43D8590BC09EA6CF7FCEE9FB1D4B1F +:100E60004F26C8B96B3D937E0EE30DEA1FF8171CA1 +:100E70002F9EF4A96219A097A0BD087B935EC2F8CB +:100E800015ECC127B9BC488862DF3DC9E58A46CF69 +:100E900057B74E22B9B4B4D989EA4C62654209F217 +:100EA000D3B38948F74CAF2A3312CD8210864783DB +:100EB0004F1B779F814F175899BFF08E85D43DE126 +:100EC00060F09544AC6795A76A5F249C1A7CC6F5D0 +:100ED000EE5F13F04EA676C40B6BFC58BA02D5E455 +:100EE00003175B674C09EE9F6AA1A599F45E7F2BFF +:100EF0005D82CDE47F0DD6BDFC928FEEF152FCF405 +:100F0000DA4BD79A28BE56CEA46D39C3A78B6F4A49 +:100F10000F7788D23BFE9C301D344F29AE7383245B +:100F200052474C3B40FD8EE683DE230E5AFFE8BE5F +:100F300011D33C94FE9B5FF7D62553D5909174B6A0 +:100F4000BD83CA89E6B902CA5BA23E1C530576DCA2 +:100F500034563F93583A0DEC84E66B04B41B42F4CC +:100F60007D15DAF7E8EDB830FFB4E27ACB5D4C6F6F +:100F700035570951FA31F9F635B77B9A679DBFDFCE +:100F8000AD494CCF365F47FB0DE10F69FDE6F379C4 +:100F900003E09280DD1932A1BC6D568EFF41A0F5B1 +:100FA0003D953619F7A38C0E9842F721866FC8A796 +:100FB00089587F95EF05E5AFD8243ACEDEEFD850BB +:100FC0002F744E8F0DC27B7BBE4AEA0039DFA9E445 +:100FD000A278B2513A7094B012E8D842F95AE47546 +:100FE0004ECF8949E8A70A65EE3C944F66D89F68C2 +:100FF00074F6F2C837B3C06EA2F49406F32FBF4460 +:10100000E8047BABD79ED7E1A5F3AEDC297A6DF27D +:1010100079E86410DCA71DA0878DF0BD5621C608B5 +:101020008EC178A07017C0BCBB33FA0F5C46C7797D +:10103000B5CA645A47E7DB3BC136BA0FF59DEF529C +:101040006857DE60FA6D1870947C3338BC47FC003A +:10105000C75756A62FF93A6747D92FD1F9A903D612 +:101060000770817EA17028807731B32F03E486B6A4 +:10107000FEE1CAC719494C5E45C8C7194943D803A0 +:101080009AFC003B00DAA97DF4E94A02F631B38FFD +:10109000A2C9ADFAA48B965BF549DF406E45ECC35F +:1010A000E2A4F28BDF07BAD388670B473BADCA12C5 +:1010B000AD4F847FD3F72877F4D9F2C2742F8448D8 +:1010C0008F339ED1BF9D6E59B3DFEF7189D1C7BFFA +:1010D000C4E3BB0DE0B2B8FB44FF45ECCF9AA4419A +:1010E000FA6B4D247E8C789A229E6C4EA0F2F2749C +:1010F000A580F02A210A12CA5BEAC245C033D1DEBC +:10110000817E50029599E6022E97E97F898A9D9803 +:10111000EDE1BAAB46D2D5937D1E5DFFD43A59D7E7 +:101120009EE62FD0B5A7377A75F5CCA60A5DFFEC01 +:1011300080A2ABE7A835BAFE79ED3E5D7D64679D80 +:10114000AEFFA887FCBAF6D1C1465DFB981D4DBA2B +:101150007A517740D7FFB29DAAAEBDB8A75DD75EE2 +:10116000BABF53572FEF7D48D77FFC91A0AE7D4289 +:10117000DF0E5DFB1527BA75F5EFF4EFD4F59F4848 +:10118000CC6A1FAB0BE750D29A64B3B64F265D3BD7 +:101190003947E5F2694A9802DD5F5FB1E0556502C3 +:1011A000E4D59B4FF5ED3CD685CCEB6B9809C1326D +:1011B00032D3F221BCA7D2BFA06F29163F8C1C6787 +:1011C0002295CF10B754BC96F07358CF3BD33E2234 +:1011D0006371DE0F07F435ED57457213643AEFC4BF +:1011E000FD2209D2FACC0BD0D560B8840BC045BC27 +:1011F0003D00D79F44AF0A0F55A5373F253A5C0AFB +:10120000FD0B70CD8146FADEEC1009F60843C0C92B +:10121000E1995D219881EF06C14B98DF6F8437F02B +:10122000CE2745FB22F6ED6492D3FD67E0672FF1F0 +:101230009E1381CF1CB8DED387A85C21D1F150A5C5 +:10124000DA51AF56294210F076764D7FD1BE9143E8 +:10125000C0EB21613AA170C5C87A3E8C2BD0F3A1B6 +:10126000D3EB393F1DA9E4BCF8BE107E65FA97D9CF +:1012700069FD66C0EFC44A813C9C131DBF73CC96C8 +:1012800030FE2E02AFA92E3D5E3F2395734A29FE04 +:101290009439896688A31AE59C863FEA0F65BACA25 +:1012A000A3EB9D4B5D4CAF5D84DEB9D415A9A72E91 +:1012B0005EEF94B8BE81DEA17A61BC0BF48FD92FAA +:1012C0005F8C5F33C935482F4C720DC7AFA964716D +:1012D000704D8F917C01F9A76D02D90EF1BAD92E0C +:1012E000E6FF46F36F66F379C3FECD6973A47FA36F +:1012F000D85263412E503B611EAC47F377CE94B970 +:10130000F681C9FA318F0386E157AE827EC385BB71 +:10131000C135C85E69709DC75ED9BD96C52B761F65 +:1013200014BDDBE9AC2FBAC59E640AEF6652148483 +:10133000D88A76EE52E3278C4FCDF7ED00A78FAE1B +:101340007F298C5B235709373BE0F92A2CA3D15B1B +:10135000C075D1764EC0F5EDEC1CF59BD0DBF0FDF1 +:10136000ACA6237E0A52732BC38B7A2C0EE399EB27 +:101370003710F44BD6AF657ED176BE1F9D1CFEEBB9 +:10138000DD8C7EAAE22BD0AE6D159C281F5BDF673B +:10139000FE459B45081216477E10D6BF2F6D5C0296 +:1013A000D8AB670EBCE1F047F83BEF70B80F73B8ED +:1013B0008FDD3E00F74F006FCB7FC0E1AE5BBCA975 +:1013C0005C07778684F204E48B1886D72A7513A00D +:1013D000CBA9A203E16CC927411BEA2565E6941459 +:1013E00010DE4C6EB76430B91C077299D6ED201729 +:1013F000C17F95CDC7418EB5D3BF289F41EED1F9AE +:101400002D1EFA3C420EC780DCA3FDE308EBAFC9FA +:101410003DAD7F0C89E83F843CFC0F908774DF88EA +:1014200095A43279B8BA7D0CC2E5F744FA534679EF +:10143000A8D5F7F5E5A5F60DC13F5A995071222FB1 +:101440005F67EFF5EBEAAE9A505EBECEDE23F99110 +:10145000F5D43A7B7E64FF34BFA4ABA7377A74FD22 +:10146000339B645D7B76A040D79EA37A75F5BCF66E +:101470000A5DFF919D8AAE3EEAA11A5DFFD1419FB0 +:10148000AE3E66479DAE7F51B75FD7FE1BF807F8AB +:10149000FF2466BA42F1F41B2A07C1DFFF8BCB3A67 +:1014A0001DCF21DFBFDA03E79DADC957D923E9D1AD +:1014B00058EE4B66741BAD5DE3DBDD6B7CDEC974FF +:1014C0007F7AD6D4E9F8B886CBB37D6B1AB1FDA587 +:1014D000354DF8FC1CE723B3DBA4DAE09C62A7E9F6 +:1014E0007D1BF81952A70AF4B94DF09F437D71484E +:1014F0007F0E011611C403AF0CD1F922E0AD22D743 +:10150000782747E0A3DADEA06B9F22DDAC6BAFA1AA +:10151000F8B89CCAEBEF7A56E99E4F937FA87B6F91 +:101520006DC6A287808FD67BAC04F8683D6178D405 +:10153000F0BADECCF0ACE175FDCE451EB04306F04E +:10154000AF164D570AC3F84FDD72E974B512F0FFBC +:101550005D0FF8B5FB12297ECF43C717C2AF11AF9D +:10156000FBF9795C8D557FCE3E8DCB2BAD84F8BFDA +:101570009BE2F7E001F1533F427BFE3886717EE348 +:10158000BC545E95BBE9B81F8F7CF3C6CD64B09C9C +:101590009EE266E7163526EA58517BA7C6A2D6C05A +:1015A0003985E68F9A0586F3D6E4A95E38D7AF76FB +:1015B0000BFC9CE34E6CBF5DDB932878325341D229 +:1015C000132187849CF97520876B92AD18AFABE12E +:1015D000F900C6F7C6737C7C5B7AFAC674C4E9432B +:1015E000A3238D3EA2C97733E924803FB3839FF3C1 +:1015F00085CFED9600FEC93B945F5206F38B512FC9 +:101600001AC70F4047B09B1CEC3C0F3B82DDBFDF8D +:1016100085F65234BCAF5F2365982DE13A2141C471 +:10162000E77A81E94F6AF07ABEE7C4F1512F128F51 +:1016300003C70770E13C83CAFB02C84F50F93E3C28 +:101640009EACDC8570C039EB30E2FA8F27FBD6B94F +:10165000995D5980700EF3BDE86527A73BAF1C89E3 +:101660003737FD772FC4D7CC9D78DEB1C5A1D555CE +:10167000CC1BF1E5B3F38F1899B56BE759A9FE20A0 +:1016800081F392B8320227E2C404FDC0BE8AEB5552 +:101690004CC5843CB1A56EBA67346DCFF77B4C5E08 +:1016A000ACBF624E86733D5A87B348B5EE957D78E0 +:1016B0005E2A5D2AD0767B4BED2BFBBF8379225CC3 +:1016C000BED4BE02F4D3A5D521304DE9B02B76A00F +:1016D000AED8A9CFD5953B5057A1BE8D9F1B3FB12A +:1016E000A5F6951607C6017F05783FD06252D13E18 +:1016F00024CE20F8CDFFE87398AEC227F7E782FD2D +:10170000E5317B47CA606710DD7B47DC56C47F4507 +:101710008A7F37ACC7B9BA1FDDC1BB0B939C107F62 +:101720000BEF43D0B00F0CEFBE82203F870AE2BE22 +:10173000647B3E55ABE87CD99568F6D0FFA48D500C +:10174000975B4C520F3E48C27D3215340956C85340 +:10175000282412C8AB667E2E1857C0CE3B251BB37B +:10176000875F77B373913EB7C84B26A7123C5B588F +:10177000BE508D09FB27F0320C7F0BF6EB739B39C3 +:101780007D317CBCEAF1BFE38E3C17243D330BE88E +:101790003ABA5A9292E07CACAAC5741BE8939FF0C7 +:1017A0003C08BA4FBFC37DF2BA62FD2C7EFB01D06C +:1017B000FFA07DE3705D68DFA2ED97668F466BBF8B +:1017C000EA1AD107F099ECFEADF3E9BCCB77BA8AFF +:1017D000458AB7C37562592FADAF783E15CF61BF4B +:1017E000E47CBDD2D49F02F1E58D07BA7C50C63CA3 +:1017F000BD4A4D97416EC9BA75ACDC5585F26C5D3A +:101800005C7C25ECB7711D87BFFA4F37ECC3CCCF9A +:101810006D3E942F32F3FF172273215887C0DFBF2C +:101820009EEB93EC6466B71FE27AEB7ACDCEA58C83 +:10183000CBED56E11C35D96B7D0DB3007F8BEA44AF +:1018400002E7C50BC3ED2C8E10607EBF9DFE05BB6D +:10185000D84F12A7027B36A8FA78C012E29D9A4CA4 +:10186000FB2F6E373CE776F112435CE1EABAB05EDB +:101870003983FF1F447CD5CA4C1ED77AE38290DFA0 +:1018800030DFA7D7476F7E2D2E04FD7918DEA5EB3C +:101890003EBC60D476E867C4C72DC98C3E0F71FD8D +:1018A0003D801F827DC9229F6085D40A233E8CF033 +:1018B0000FE0CD80870673F1D46479301E8CF0532D +:1018C0008C217E9750FC423E46347C4C15675AE092 +:1018D0009C6DF15C01F5A4113F463C687E8D06CFFE +:1018E0001F353889F7701C9DEF830E0B01FD457A7B +:1018F000AEC4F3BA39BC5F043CE8BF48F42F8B0395 +:10190000C92FBA609D14991B69BF79AA45E7F72CC6 +:10191000E17ECF22E24B80381C85F378947DD6F9A6 +:101920003FC6751BE19AC5F585D14F22E69E42B0B0 +:10193000CB1626F3F8D1587DFC8894250F29778D96 +:10194000FE9246570B037375768940FC037589DA5E +:1019500015B77A44F94317F89B96AD20A6E6DAFB53 +:10196000CDC857E28204E0C7B9C42E3B68FFA5F496 +:1019700021C0354789C1BA36DEE94EA106F8F256D4 +:101980003A5C00CF9315B4DF16B22EB454F700FEC4 +:101990006EF558711E4A679F46D259343CAC49E6F1 +:1019A000FEE25832F662E0FF0A6C0E163FEB8178D9 +:1019B00072BF600F6E17C2710DFA4FD54A45E5161A +:1019C00060DAF2F07A07CE474813DA4FC388736CB7 +:1019D000491E22AEA69D136BF479BDDDD12332BA28 +:1019E0003B39401FBA73623F813846DB885BBC805D +:1019F0006F4D3F523BE727307E5B2C8B6368F23D97 +:101A000016EC1590A705E62F22E974907EDE77C3C9 +:101A10008E2E8A0BBFC34C40AFF8850F5B09DA9559 +:101A2000FD16A4AF80E574E4FB7E27952285B08E79 +:101A3000CB25281779D8F9F622C2FC26A2D2FE11AE +:101A4000715C3F6C1B7DEE8F59B1C394C7FAAD86B4 +:101A500033DEF6887173C3E31AE71BA49F0CE31B04 +:101A6000C769E3F94E6D566FAF0271BD57C4E2B559 +:101A7000D058C0ECC9DF279B747A6591DD956176FB +:101A800085EBC7D31C7591FA592BB5F734BC85ED9E +:101A9000B0D33A3BEC6ECBC77A3B8C7CFCADECB060 +:101AA000FF4AFE18EDB0B3C76C28F74FD7C40681C4 +:101AB00038B53C0533351B1292D06E56A1B407D20F +:101AC000111E2D6FC1257B05C0EBC7208CC1AF96C1 +:101AD000D9B99DCBEC15BCF4F9666ECFE01F4A076F +:101AE0009B93A42E90C3363B69894982F7989ED672 +:101AF000E61B18B7C02B4885D1E3819F275F743C54 +:101B0000F0F3E421E281074C4DEFFD08ECC25744AD +:101B10000271DBEB3C3FC4E757051663794DE06685 +:101B20002CC514361FF537C5946490536F5C770746 +:101B3000F8994FDB30FEB6FC071FDD532E037EE81D +:101B40007EC37B4B166F85B89938D284F6777B2697 +:101B5000F38FC5B502FA831B646BCDD3C067EEAAC1 +:101B6000E214E07F4FBC09F8F5742CE3D776F764F4 +:101B70007C7EF6D87ACF223A4EAC2716F3C1C4B594 +:101B800039F742FE1B7999AE97005F12D4C76D56A4 +:101B900056E6A598917EF252183DA5A730FCB65B9B +:101BA000FC054D8590570A9B1BC683DDAC12C9010D +:101BB000CFCDF85C1404B46FDA62FD05B747E04F8F +:101BC0001BD71EA2CC5B3AD4FB567C0E70E1FB49BE +:101BD0006C3D5ABF42FE7E215F973D1487F3B525C9 +:101BE000D1753922C78967CF399F19F9E491E46A21 +:101BF0002FE0A5DDAD14A720BFF459404E5EEFD90C +:101C00007F44881F8E9C63F15AE757424F36D8DDD8 +:101C10005562701DA5C758419A55067E689505F313 +:101C2000047A0BDC4E88BBBF6E969C49148E497CAF +:101C3000FF7D53A8FDC9E839B916F665CAE2711BE4 +:101C4000D934F6487DF37AE193BD9320AEAB5AD0F8 +:101C5000DF58685783B0AE08FB869FDB51BB691C19 +:101C60007F8FAE73E1645189891FC20E6C21FB2204 +:101C7000ED4B2A26F6C1B9E4BBBCFADEE433F361CE +:101C8000F97D44B2560B91F626F546C6815DC0FE3D +:101C90002C0CE8ED23A3FDB4A8CCFB924B067C747E +:101CA000FB101F4566E48BE1DA9584DC87FB7BF74C +:101CB000E4A7EC7221F85332D69D93DF50404E508A +:101CC0003B687E19C5CB9CC9A2D4437B77044C04E6 +:101CD000E4E8A6320BFA0F9B0AFA5EBE12F8B1CC0A +:101CE0002C633CA0A0B7B61ADBCB25B08B7A618AF7 +:101CF00034ECCFE2E90E477024E8EFF23FD9174702 +:101D0000D0CBA6B2E3A3418F6DE37444C5A063CAF0 +:101D1000B830FE003F320AD1B5B8AFFBEE8C45F9C2 +:101D2000F45E87C8E3D6D4D0A0F8767A183F4EE1A7 +:101D300071EDC55B05CCDF595C7EB8CA46FB2F6EE2 +:101D400015902F17AE16DF8778E2C280DE2EF337AC +:101D5000517B4D463CEBED356ECFD1C1AD40BFC39D +:101D6000B5E78CF6C9FD29DC3E2B212591F64934D7 +:101D7000FF49B34F3A88F230E31F36FF22333B8FDF +:101D800022CA3CC4EF14F1E4CB5752F84E97E5E673 +:101D9000023E6EE2FEE6A6C05B76F06F377D25223E +:101DA0009F6FB352C305F29DE32B7FBA96AE6FCF00 +:101DB0009D97A67E40DB7F9D62E5F73EE4072B8181 +:101DC0000F5EB1201D455B973D20927CCAF7310123 +:101DD000014B6D5F9C8118628E90374E7E4F25B906 +:101DE000AC5FC88D902FBFE3FC99B89AF9CDC96557 +:101DF00044C9007FB020773BE4FD51C58471A5D86C +:101E0000917209F0ABD67F9BC0F2EA6D3BAB14AA8E +:101E1000BB48365D07CC27D375809ECB09C4613D96 +:101E200037E0C2322F9088657E201DDB4706F2B076 +:101E3000BC249083CF4705C660BD20508AE5E840AA +:101E400031969706AEC0720CD573D0AF3050856511 +:101E50005160063E1F1B9887E56581B9587A03F5E6 +:101E6000D85E1C588C6549A0019F97069662BD2CD0 +:101E7000F07DAC97075661392E701796E303CD5865 +:101E80005604D662BF0981BBB17E79E07E2CAF08D3 +:101E9000DC876565E0116C1F880770BE9A9DB848A5 +:101EA0006279075E2FD867DBA2C8E12FB85EB93927 +:101EB00045390E74A4F513795EB8B1DF7FA7E8EF5A +:101EC0005199EC3DF63CF4DFF34AC07FDF46E54034 +:101ED00006DD9F15A373F1DED12729CC7F8EB57463 +:101EE0002AE942D85F4F9CCCEE03ACD8B90A4B52DA +:101EF000E11A56FCE77D9043B0DF669598307F9FEE +:101F0000E0F9534C7EAF0072A2ABD0540372FDEEE9 +:101F1000C2D37B80AF67952B6560A6CA6AF7FE5C6B +:101F20009457D565B0CE4B532DEC3E528A22A4D2A5 +:101F3000F1B2CB92A7CFA3EDD92D267467652255B8 +:101F4000415D9E4C50BE69F195AE58BD3ECC4DD51D +:101F5000ECBDBE2DD07FDB88FC12A647D8FD01F179 +:101F6000AE5CF41FB7597B0433C839EAD83CAEC91C +:101F70007EE8DFB6E8676047E5B67B5FB0C3FCAAE2 +:101F8000B714D69B9BCAF82EA7539E14431794F7F9 +:101F900090F202A4BA8D0CFA27C5D2FAA81DEA0B5A +:101FA000508EEE0E4E8AA3E5989D3D2F80F828EACC +:101FB000E99BE4A0F5CBF693BD20068A7BE56A2772 +:101FC000AD971E51F64238B2BCCF5F1D0FFB640DBA +:101FD00036C7D3F56C7B9778D7D27AC5C94E11DC5A +:101FE0008281FDB79126B0BFB47DB1CB9D0AE03BA5 +:101FF000E33609E334DBCC7D31898583F7A70BE039 +:102000000638291D80DCCF50FA711F284D94A8B8DE +:102010000FD2F402DC07462FB353056D1F4A601F31 +:10202000BA62A52A68EF9F42A4EDD05E6442796D42 +:102030006DCD45BDA2D11DC5EFE8B9CEC87D60E329 +:102040006C33D8A9D1F03BFB9F04BFC7383D47C3D1 +:102050002FD01E8B9F9E9F8F17723AA47C5C9F9AF5 +:102060001CBD5F0BC79311CF5D26B29FEA9E887B94 +:1020700031740F69D735A926EDBECEB0F0FA43C052 +:102080006BF2FF3D5EAF4A6572261A5ED1384D0B8A +:10209000DF438C266F603C807B283947304E99B3F4 +:1020A0001DE27DF770BC6EDCC9E2939A9C8B79BA15 +:1020B000AA279D84E5DCB57C5D51E5179733561E54 +:1020C000C708C7658BB603FD3FCCE739E1561E4A0A +:1020D000457F431F5FEF304955B07FEA4496BF32DA +:1020E000BBE27545C4FD91F19E321E9C00FEE20BE1 +:1020F00083B07F39D45E30D37DA7FFEC8132AE5000 +:1021000032C13D512DAF85480D9E483ED3F479989C +:102110000F357A48427F10E814FA1FE1EB0C8F2349 +:10212000B0BC861F8EE8DA1821FFBA1C19F89ED6BB +:102130003F1ADDFEB746B72D4F221EE32A997D9048 +:10214000D09284749C30D90F9A26827EFD56A0DFEF +:102150003FA68A1745BFAFFF1FC9859FA712842FCF +:10216000BB52DA03F947D954EFC8C0979514D7107A +:10217000CFF75851FEC984ED9F5CC9F2F828BE7AAA +:1021800020DEA99A9C41D02BA2AD7F32C04F6C8932 +:1021900012F83F27DCFEBED4F3F081142717C36684 +:1021A0007EF2606886230DF2D2A558A8FF9DD63B2B +:1021B0002AE03E581FE1F5BB1D13BE797CE293D4A3 +:1021C000B37F6829C4FB63A752917E7D9F40A98C91 +:1021D00092307F4DA3E30BE97F8D1FC3FC23156B6A +:1021E000FCD35088F2EF4B18571B2F9A3DF30C97F6 +:1021F0006B0E0F939BD1ED9924E427CAE78C7F38AF +:10220000FD6FEC393F9F6BEBFDE202FCBE61DA5BD8 +:102210002AF4D6E2A6761E3FD1D619E361F73063E1 +:102220006612F44B9C3C7EBA0CE2A702DC47B55F19 +:10223000207E1AD4C557B4B8A9764FDC88E7911E22 +:102240007D5E1BC8A32723E021DC9FFA3E9FB3736A +:102250009D3701EE17A8AFB23886960F3E13FE4D9C +:10226000E114BC02C6913AFF85F1DDAC0C125C476B +:10227000D73DF30B8128741D07BE10B134C64D67DE +:10228000D1F7C06E3820D88376DA7F4FB18DC0F990 +:10229000DA01A709FDBA03EF0BC807078AE3304F3D +:1022A0006A5FF178CC8330E64769E5D5FE8621F395 +:1022B000C68CF8B9FABA171DB02F8F4893EC39E8DD +:1022C00097B273464D1E6BFDE67AACDC6EF1CFF033 +:1022D000807F73437F0B7D425A2476CEA8D15F9ACC +:1022E000E3E99715FACFB465CCAE1C41826B25C7E4 +:1022F00060BA7ED5E39FEFA1E523E173BC0397D0DD +:10230000F9DB657E8EB77244652E1DE05F07CEF166 +:10231000FC3530AFE2EA2E063A7CC4FBD42FEEA5A2 +:10232000ED336DD44F05395C7ACC2D43DCB9FCC557 +:1023300064C0C72CC3FAB5528B9F19FDD1251E7DF1 +:10234000BCFC4CD93CF47FA3C5CBB5B89EE6974204 +:10235000DC4E1A428E1BF1ADCDBF4060FE27B108A6 +:1023600028C70E40D7092827EE0038490BCB275045 +:102370006C02E6131C2C2BC5F304E275F173CA9EA4 +:102380008CC8734A6D3DF4F9C8A1CE2F1744C9E734 +:10239000B8C7C3F4CC020B8B570AAB5E5C00F32EBC +:1023A00028B609ECDE16A3D385ECAC8CFC88F75F6D +:1023B000E85D8F79BCC6F3881F79985F7AC0D293A5 +:1023C00021F178A67708FA8C869723964E3CF73A47 +:1023D000B24424E0971FF48F4F2543AC5B2BDF0200 +:1023E000FAA0F85F0038498ED837D93DE4FE1F8146 +:1023F0003C1CCBE0F39E81F686188C73D701BE227D +:10240000D6FD2C87FBB087F9DFC4A616409CB77DAC +:10241000D1563BA176EA86FCD3E52AC5FB06D25FFE +:10242000BE1DE4C36A27C60DEA1A3E2B5F5B14810A +:10243000C70A86C7857B374840AF75392DC96AC43E +:102440003C467C1EF630B862383D7710E539CF50F7 +:10245000F18FFC5A46177B63BC3D747EFB9FF24AAA +:10246000408F6BF10F9887DD5766F1DADB24B60EEB +:10247000903591F45D1758A1931B3121810423EB12 +:10248000E64E8C77C684CCF8DCC8478F1AF848C370 +:1024900077B4FDD3F06D7CAEE1FB48C3860288C7FC +:1024A000B5C70E6D27C5A4E9E3E9C6F36FEDDCD728 +:1024B000F8DE477C1FCFF827207DD559D591C3E1A1 +:1024C0005F0D3F87BF5A2F01BFD8F9B9BA76AEEF7B +:1024D0002C48C273FCC375A2C2E2365217C4058EE3 +:1024E00073BDABE93DED7C30DA799FD3706E185344 +:1024F00040EB11E73F46BDA7ED63B47342E33E896D +:102500006903E7A3FAF3C1287CA3F1CBAB9C1E2F90 +:1025100094EF70B595E5311A9FBFCDF7F58CFF5F4D +:10252000E78FA3537DBFDC24011D6E9221A709E232 +:10253000A716CC773AFA958D809DE72C37FD14E2EB +:10254000DC471A8ED656835C28B7E0B9440FE5FB0A +:1025500065743D1B38FF0FC4553BC4E04801FC07C0 +:1025600041776E1B9B6FD7D567955B503F6FDA52F3 +:102570001C047FA68EB073BA0DE5DF4BE8A1FF3EC9 +:102580009A6FC5F1EC1B043C57B27FBDDE07FBDD43 +:10259000D3F0601DC653475A13413E6AF480173585 +:1025A000285FD92536C7DE91E3AE827BDCEF755814 +:1025B00008E61F0BE1736399DA7F8B73CA5280EED2 +:1025C000FA201F10CFDF799C9770F9C0E3B25A3C14 +:1025D000DC189F8D16971D6E3C56A317235D4C4D3E +:1025E0001BFADC38DA3E47C46567A50D2597E45A27 +:1025F0009D7CD1E4912617DEE2F01FCD6FBB0ECE9D +:102600008B8EFA6D1C7F0F1C5C5306F96166BCAFA4 +:102610006AFFFAE753801EC8CDC290F1D82D9A5CAC +:1026200086F3F982309EAFF187F30E819DEB1BF5A7 +:10263000798746BD105D4E9D5F0E25A631FB48D3C0 +:102640001BA01F921C4C3F989C61BAFFB67AA2AEA9 +:10265000A1D5AB1661B903C6B1E7C5E277678CFCBB +:102660006E94F3DAFC83E46748244157247FCA4C14 +:10267000DF0CC8792BB60FDC03382E049BE9501B06 +:10268000DCCAC634F00BDCCADDB0EF37BB958EB4C4 +:1026900088F19B2D2C9F513411FF13684FFB30AFF5 +:1026A000516B7F2A8DADA7B58AF5DB933CCEF35FE6 +:1026B000B46C7EBFD86381387C1A3B77DBE73C7F04 +:1026C0003EF5BD9C7EEE067934326CC76FE2FB4965 +:1026D000C157203ED26AF17922E3779BD312915EF3 +:1026E000E2273CD90B71D266C9240914F466624210 +:1026F000B9DAA2386A9E2E84F718DCAD4EE57195E2 +:10270000DB43F39DF03E5B9FD961FE2292DF9E0288 +:102710001D5C1E86CBB8DEA7D2981EE8702B4F0238 +:10272000BE6E772B4F011E0366D506F80ED887F6CE +:1027300053FE83E36B031F9F7A72782E88F38AC35C +:10274000FA5EC20B30DF1DA28ADF253B6BF29E8052 +:10275000FBF2C3BD5F7390CF1F71BFE6605AF910E3 +:10276000FDC3F7813F8673EB2A997C1A8445F27B7F +:102770004C5A9E27B5730FC17AAE6E1D3A7FB28B4D +:10278000C8E78D5339F838D4BF7E3B8DF9D7C7D20F +:10279000987FDD02F29C78D938F1171887E209CFCB +:1027A000718781BFBF32FCF9FBD07FBFC8EF4D7C82 +:1027B000C6ED9408FC7D9636043F6AF83B7B6C546A +:1027C000029C3B6ADFC930F6D3CEEBB57A7BA27EA2 +:1027D000FEB612562723D8BCAD3C4FC3CDEB76C313 +:1027E000F71CEC33D97748B4BC076D1CF70827CB2E +:1027F00007F24C728F28C77BFC980FD096A8FF5E1B +:10280000416F5A957B041D3F7E84C0E7212C7E9545 +:10281000CBCE0F8CDF3D3BCAFB1F4D9B8425155251 +:10282000A3019F56511C128F6923D8FAB57B62DA37 +:102830007D9DC59B44DD7D1D4D7F2E7E9EA07E87A8 +:10284000734FE0DB68F96BFE02E92508D97C460A84 +:10285000AD90B7F56DF52AE0332E69B05E2D1E31CF +:10286000A057BD17A9572B46940FA15789B72052DF +:102870009E6A7AB5CF705EA39573F8BE74707F1BA5 +:10288000E424C865F81E12CA6733F34737C7B37824 +:1028900025D01F7C1F610EC7BB31AF46CBA7D1F23D +:1028A0006BB47C9A81EF8218F269FAAC7DADA974A1 +:1028B000BFFA4713BC6F97BA40DA930A7908936559 +:1028C0000271A7B61C125F01EDC5262FC4E7136B7A +:1028D000A5360BAD27CA046EBAC3BD44D549C7BDE2 +:1028E0007D440EFB3E9D3A6F0F849A126469AA875D +:1028F000F64BA893F1FB475A3CF940CB3AFCBECAD1 +:10290000007E38FC09328BA3DA65E65F57914CB440 +:10291000CFC3FD4C5ABCF9468677166786CF74A0A4 +:10292000BFEE8D45FB74369CE8A31CE8C67CB7CD92 +:10293000A9D5CB808E35FE81EF4B3D11117F35E659 +:102940000FDD6EC0AB317F287601E3C741FA8EC33D +:10295000B1C9ADDC897CF3D5B973E2B8F03D35FA85 +:102960001E8173B7183793A731323B3F269280718F +:102970001DBBECF7C37A623C1512C8C966ABA35DF8 +:102980008080EC0D260279B0D57C1CA58E087F2EA8 +:10299000C05439C2E4A599FC59A373910345E79D3E +:1029A000C441A4565B471C5D7FB5E395CF0588DF26 +:1029B000E5375541FCEFC5856C8CCD51E2DC5A1EE4 +:1029C000D540DE18B9EAE0BECA88BCB156DF417D09 +:1029D000FEBEEFE0B7C91BFBD5C3BE831097FDDF7A +:1029E000CA1BD3E4D311D17FE42E8ADFF954A88027 +:1029F0007F369F8EB800E393CC4FA8E57856BFA0F2 +:102A000078B687F17CC4C2BE1B317FD7CB8847CB59 +:102A100024866ACB9D09A887347FF42A7BE7143883 +:102A2000EF3E65ED1F0BF39E7AFECD4CB00B8FFD94 +:102A3000E88C13920DDE33F73BE1F989D56F38E16D +:102A4000DED5B1D5229E135FCFEDFE856BBE1E078E +:102A5000E71E07393D8D4A57F68D88D04724908C64 +:102A6000FAF5E6205D5984BDBC74471C2736565FD5 +:102A7000DEEDD2D535BDBADCC6E2CF4B7FB5C79A05 +:102A80004ED77FF38E44F48B4FF0F398134F677655 +:102A9000815C36A5B3FD1F95EEFB13F01BAC0BFC60 +:102AA000E2F776D9480FCAA55E0B617EF24C21850C +:102AB000E54DC21FE3BA5EDA1D87E32ED9CAF441A1 +:102AC00003C56D80E2D1BFEB6694FBC6752F39D686 +:102AD000FDD208BAAE251BD8F712A0FF6AC8C70CF2 +:102AE000B0B896112EA35E58DC3D17FDC445B7B1B2 +:102AF000739E458FB2FBAB463D7103F1B657D22EA4 +:102B00004B3AF5CF6FDA7537CE7393E13EA8516F2C +:102B10008434BD318E8C3F47E54DB32337E17CF7DC +:102B20000F4FAC61CCF8D735762C4FAE91B0DC3777 +:102B300042C67D59BA73CF4BE9C8CEBDE340DFCE64 +:102B40007AB9DA7E2D09C725CC5DF37A1E91811EF4 +:102B5000795C95FB230B38DE2D84C521B6F278BC59 +:102B60002819E3F1AFD7425E80EA60DFDFD1E213DC +:102B70000B00DE883CE60517884FA4A673B8C75340 +:102B8000B8515F16BE26930BEBCB68F0477B6FB94D +:102B9000C8CE578CCF35BED8C7E5F40D8FCD6D03A9 +:102BA00014363FFF972CFC9E10CF9B13395E447E5A +:102BB0006E2112439E9C4A0E9108BA35D2E54DF023 +:102BC000F15BD0230EF69E9DD8D7E23D018D1E7796 +:102BD0006D42BC69F40237814C1083213D1E53C500 +:102BE00085EF1150BAD3D5FF6EE9CB02B97093E1EE +:102BF000FB0B7F1786F65746A7E732F865652AE88C +:102C0000A525C4D72621FCECDED70973E74B770155 +:102C10003F3F2610E0A3E5CFFEFA199043B7FC76BC +:102C20006B3CC8A18FCC9D2930DFB2C75BE3416EFE +:102C30009F30ABF1F0FE4741268F8CF3B5A66B7E3B +:102C4000BCE210A89C5C01FF848DBF419D0D7CF609 +:102C5000DF8F5B24D0A32B77D87AE0FEEB8AA7190D +:102C60001E69FD7D565F8FF85AB953CF6FB7FC7C54 +:102C70006B8ACCEEA7A573FCA583285EF19805E3CB +:102C8000A52B0E89F0D932B292F4237CC6F7611DD0 +:102C900021BA6F2BBBC5066BC2E0766AB958819F1B +:102CA00056727B71A5C12E6C8C126FB9CD40E714A2 +:102CB0002F78CF5CA5EBC1B05090C9E1E65FD81486 +:102CC000380FFAE8ADD42E88879C7CEC0FF1426176 +:102CD00098EEB5EF7F9DECCE3BAF7CF83BE78F01E4 +:102CE00039CFF589BC932E10CE6477B17299A527A0 +:102CF000FE0A8A97655D16AF4A1F2FFBB5A8806B49 +:102D0000468EDA30BEB6F4D72F1EBE9CAE67E913EE +:102D100016F74C068E03E4B3B65F2B81CE4BC2FB95 +:102D200073CB532F5AE522F61CF2DCB57D5AFAC458 +:102D30001E2BC4CF8DF8ACEEDE63657C66D8AFEE9B +:102D4000F7A782FE6DFEC5592BD0C347BB05929AEB +:102D500033F8FDC6C7FF100FFDB4FD1AD8BF41FB05 +:102D6000D633FBB932EC87799AD1F66F3E08CD7233 +:102D7000A4EFDF3C47E76D7CCBE605B81B7FF3FD96 +:102D80007858FF5FCC4D8CCE7FDC9A02FAB6D1A288 +:102D9000A64858B2E78DDB6E47FABBE9F5DB319FF9 +:102DA0009FD2771AF02F852F0DE05AF2E87C84EB42 +:102DB00046E247FA6BFC31BB2FF69999D43C31C4FB +:102DC0007E7EC9F9E42FDB6D68CCFF050EE340EE93 +:102DD000FE510CB27CAB55686768F7805112D3FA8C +:102DE0006776B63FAFA76B795C4C8EADE4BD563EBF +:102DF000B61EE5D85F339554E0778A079D3C135F94 +:102E00009F92CAE51FE6FFE27B544454C373E8DF98 +:102E10006B5162C6EADEE3F12836FF6D7C7EBAEEC6 +:102E200058E1325AA60CE429F4C23A5608EC1DA027 +:102E30001BC8731D9DC1E4F000BF3FB681ED0FE7D5 +:102E4000F74F0F3139B22238B706E540AFA5271545 +:102E5000FA05F7D40A28076CE17BCE917CFC9885B3 +:102E6000F3B1BE9DAECB2C44E273B780F6FE8D5B12 +:102E700068BF087B63E5D34C1EAF847BD4BA3C6249 +:102E8000C6875A7CFF26C3F98A561AE5C0670639F9 +:102E900030703EF068F279E3F19ABDB5CC12FCD9FE +:102EA000C3C0AF476D68CF2CFBB505F3BDFFF6ABD4 +:102EB000BD87AFA5F4FDB76E8D4FF572D5C8A78D50 +:102EC0004FCE2743F1E9DFDC3E32249FD2E743F2C5 +:102ED000A99B7D2FE31F265707F0ADE7CB9BA2C828 +:102EE000D5EC8C41F643C215B4FAD77F5B9A8DF9C5 +:102EF0000A06BC6AF834CAC7E7E0D2E510F291FED0 +:102F0000394422F0A8E14FA3CF5B7EB91CE719A09A +:102F10005B8D3E353D35409F4678F57834B67FC8A9 +:102F2000E590B6EF9675D42F86BCB6E745BCA7757D +:102F30004AEE8F87BCFFD61816073825F17A22ABE8 +:102F4000F7275BDB405E68CFFB63D8FD8E53BEFE88 +:102F5000F8C408FFECFD5D623CC4BBFB82CC9F362D +:102F6000D21F444AF13E2FF7B7A7888EAC00F85322 +:102F70009D792510C13FDD62E1F591EC7704781E63 +:102F8000C97F11DFE12B609DDABD2C5531A7513C83 +:102F90002E662092C6979BE3210EB378D752FCEEA3 +:102FA000D40D1D7AF86F74D4E2F9EE8D5BF4F70C52 +:102FB0006F22412BD8518D8FEA9FDFC2E5F92D0694 +:102FC000BAF1F3F8A1916E6ECCE0E762C5A498F96E +:102FD000B92CFFE3562EB7A6888573EA28BE4FEDBD +:102FE00017F15CE7F42E91B4019CBF62F63F515992 +:102FF000BEC00A4AB79171C7934057A3A2EBE593AD +:10300000FF7E6CDC5DB4CBB267DE1EFB082D4F3E4D +:1030100073F492DF41FDD937B3DE2683FB57EFFE11 +:10302000FC7A904FA776DBF0DEE7A9DDFF997517F4 +:10303000D49FB379619DA7D631FF56DDED447D7DE8 +:103040002A93D977CDCF9F1DDB87F296DDAFBE2FB8 +:1030500083E57F9DDEF5E5BBF07DD0D3BB2854A092 +:103060004FB93FB5F2B918F48F4F3D7F765CE4EF6E +:103070001B7C5B7856F0F3C1534E5207F936A7120A +:1030800059FC69E5EF26603EFEF2A7F758E15E4481 +:10309000F5EFBF1E0BF2E5D493CC4EA0F6EB363025 +:1030A000991F7DF48A7B2C74FFFE0E361DF5F3CB41 +:1030B0007F7CD76CF84EEB60BC303C9CA27800B8AB +:1030C000285E1A412E46C3C753FFB4F8F8E47A9835 +:1030D0007FD9AEF178DF3A8C174161CF9D983744A4 +:1030E000E167CF779F1D0B7EF385E07D3D839D5B80 +:1030F000FDFF02EFA97FDAFD65F47E4706D3374670 +:10310000BA1F4CD7CFFE00EBBF717A71BDC3E4F795 +:1031100084CC7F56F8FF77F6BBE89F16DE0BEDF701 +:10312000CB7CBF9D12F87BA79EFF3A8B5C04DC33FF +:1031300033FF59F9FAFC700FD83526AFBD8CAEEFCE +:103140002D129C5F25A0B5817646B383E5A1F7D605 +:10315000E6E07D1BC2FD86D902D3CF7764327F4182 +:103160003BC79DEDBE11ED88D9CA267E6FCD84EB9D +:10317000E97557FC6CE3107ED21C45447BEDD5B558 +:10318000747E8AA7579D26A959C6E768B7CDF7333D +:10319000FB6EBE32837D3FD4BDBF0EEE6FCEA9D095 +:1031A000FB11D71AFC82ABEBF4ED5791EDC910A7D8 +:1031B000BFAAD1428202C4870DFD33D9F79FAE2644 +:1031C0004DAD2CDE72D17841BF8EDF09248F653280 +:1031D0007F51C3CB603C703CB2EE83F066F333BFEB +:1031E000D0468CDF6FBD55873F23DE08F71331AB28 +:1031F000C314C6AF4D61F74523C643B807F0C9F104 +:103200007DB17835EECF85F07C67143C874BFD7738 +:103210000608B707670FD8830EE4A7D71E1330EE52 +:10322000FC5AC5E28E62A8FF4A403BECB3CA526228 +:10323000A770BF6A213BF19C455164691CFBFD00EE +:1032400068172AFE13E3FC0915269D7F99A8C4EA96 +:10325000E072D524E9EAC9BE11BAFEA975B9BAF679 +:1032600034FFA5BAF6F4C6125D3DB3E9725DFFEC1A +:10327000C0245D3D479DAEEB9FD7FE3D5D7D64E77D +:10328000B5BAFEA31E5AA46B1F1DBC45D73E66C728 +:10329000ADBA7A51F79DBAFE97ED5CA76B2FEED9C8 +:1032A000A86B2FDDBF59572FEF7D58D77FFC91EDCD +:1032B000BAF6097DFFA66BBFE2C493BAFA77FA9F0C +:1032C000D3F5BF32F482AE5E45FEA0EB5F6D7F4367 +:1032D000579F22BDADEBFF5DCF07BAF669F2DF74F1 +:1032E000EDDAFECF2838A37B0E670CEA38F04FD812 +:1032F0009F59DE2F75E398890FE3C356D284A59DAD +:103300007FCF2C967463E9E0E7905BC6F8FF5F26F9 +:10331000F885DBD43620AE57279CCD02B9FE5AE59E +:103320003C5D9EA1F63D9739F0FB0BF1E1F3FFF810 +:1033300090487A4A291D86042CA5501CE971513AFF +:103340000CC560991472E1735728114B77281D9FA3 +:103350002787D2B04C09E561991ACAC1D2131A83E2 +:10336000655A6834962342A5F85E7AA818CB8CD0AB +:1033700015F83C333401CBAC50353ECF0E556129A6 +:1033800087666099139A86656E681EF6CB0BCDC56D +:10339000323F548FCF4786AEC1F292D0622C478520 +:1033A0001AB02C082DC57274E8662C2F0D7D1FDF16 +:1033B0001B135A856561E82E7C5E14FA21966343DF +:1033C000CD585E165A8BA5377437F62B0E6DC0B2EA +:1033D00024743F3E2F0DDD876559E8117C5E1EFA8F +:1033E000572CC7857E8AE5F850179615A15F62397C +:1033F00021F40B2C2F0F3D85EF5D117A02CBCAD043 +:10340000EFF0F97742FF81E5C4D05E7C7E65680FFE +:10341000964AE80FF8BC2AF4329693426FE0F3EA3A +:10342000D0EB584E0EBD8DCFA7848E623935F40196 +:1034300096DF0DBD8F654DE86F584E0B7D84E5F42A +:10344000D0197C6F46E8132C6786BEC4E7B3429F51 +:103450006339E0D75746FDCE8AE91CC4531C49C3E3 +:10346000FC5EDC43BA73A307E147C4A85C9CB39A33 +:10347000DD436FAB3A3319EDD5553699DF0F35C8BB +:10348000D5AFF0771BE033B32CDF9DD2246DBF8E18 +:10349000D3EF6B157B93C10E6A2BE95B06718D4DE3 +:1034A000397D0BA06CCC627A6E6116B3036ECC6270 +:1034B00071CE7F1BC3F2D217AC1A89F171E21E1EC6 +:1034C0001C3BB87ED0FA3BF3F8EF9939FAB3F077AA +:1034D000678639CE70FB5D280F695696FFAE2C8C3F +:1034E000FF187F7767D8EF3767257FABF7EF3EDFB1 +:1034F000FCEBDD3FF03540D5AC9867D1FDAAE7FB8A +:1035000055DF7413C6C7B4EFA3F7F1EFA3DB96E959 +:10351000E335F554CE55D179EA6F63F9AFC6F63E7F +:1035200085A09DB37E19CBEBA9CF3061BF7AC3399B +:103530002A21DDF87D8D7AFEBD7163FBA22871C35F +:103540009F6519E2B09C2EEB799FF5CB443C2F3A56 +:103550007388FDCED5DE642B01FBBA6FB90DE99AF5 +:10356000B4B3B8E2DBC9CF64CA11E7330D54AE2A55 +:1035700094EFF62EBFC30374BDBEF5090B9C8FF507 +:1035800065AEC28F0384E920C8F27832099E97D4D1 +:10359000ABABF0FBF4A48064A03DC7F16931C9DD99 +:1035A00080479265C77B8FA2499F6F5D90CDCED536 +:1035B000B5F23D13C39BBA8EC5B3D75B9B0A20FE01 +:1035C00007890EA6717C9F4C302E1B67BF95EDFBC3 +:1035D00007F7E56C87FB4B11765A2CE0AF9EE8EDC0 +:1035E000B64359893C2EC9F0FE01FFAE2AFC1134C6 +:1035F0003AC843BAB0C27DC97AB71DED3FF8AEAC48 +:1036000099B2467DE7DCA5606FBE37F0DD0B0AD3CB +:10361000381EA7A3EFF957C729A3E93E1FE5FC5DB4 +:10362000AF5AD448BAB0086CBD64ADC0CF3FD465C2 +:1036300050AFEFB0E5B27B9A7C1DD046E5DA846CE2 +:1036400036CE0702C74B2661EFF1FC045B476210E0 +:10365000ECE27AB719D769C954AE87BCB4FA0C1F2B +:10366000AE9398FB6F6F80FCB30C09BF7B666B5900 +:10367000A5803CAAEF58BB0AE87C002E33315BA939 +:103680007E6D202C4F897408ECF75C22E1A378F75B +:10369000770808DF392EB73E6C15189D6F62F9E781 +:1036A000EB339BF077CA88D977E4CD8879B5FDF6FE +:1036B000C3BC745DFECE67EF10D0AE6679A47E9871 +:1036C0009FAE6321BF0F68C49B9FEE17E0F7D26CDB +:1036D0003EEF8F9C08FFE079BDD6B945E1756BF4EC +:1036E00052BFDA89E73D1ADCAD82AFAE01F0B9C94D +:1036F0008670D6C37AC686F150969DC4BE779A3935 +:10370000356BD110EBC1587104BD18E9CC62E2FBF6 +:103710009CC57E8F55A37B8D6EF2B299BCD7CA49EA +:103720007C9F23BED787F94B93B2B5DF0564DF2BAF +:10373000FB2ED19F577D3783DD6B7C8FE70D65674F +:1037400077CD81FCEBDF67F1F7E4A602CC67E5F308 +:10375000D33F0AF211EC271DBFDE61C7FDBC8CE32D +:10376000D58817A3FC4F1A5827F15BC7F17C815C01 +:10377000782EE3737F870DE950DBDFE303DF8B55A2 +:10378000B2705F248E374EDFA7389F9CCA62EF036A +:1037900039C1F7DCD4FB6C48E7DA7E18FD2F4D8E7B +:1037A000BF0B7E251DFF417844E5D9DE849502ECF0 +:1037B000D75C0E4F0AA7AF3DB685424384DCB9897A +:1037C000E33D39CA7DCB9BF8FB0A6F87FCB573E3F9 +:1037D000D08F2591F1F245D9FAEF914D759AF03CD1 +:1037E0006BC68343E76B1C9019BC33EEEDFEF48F80 +:1037F000401FF556948B0FACD5FF4ED7223EFF11DC +:10380000DE9F2C189E5E7E3720C6801DDD19FAEBE8 +:103810002F7F4BC74FF25951FE2791BE5FFE16CE48 +:10382000C5EBD8EFC2ED4D3885755B6D2EDEA7ED8B +:10383000544A106F33654107CFD60C530D9CEFEE01 +:103840004D989376038567CBDC1B851B22D6996246 +:103850004EC0FCBF3DB639698DBCBD91B6EFFEDEF2 +:103860009FC7805ED95B2FED82FCC8F85AF69D5C3D +:103870005705CB178CAF2031D01FE66D8C18CF5574 +:10388000CBDAF7CC9B9AB684BED759BB6E02BCB7D5 +:1038900065AE157F2F6BEB4CB5428C90279DB5C75D +:1038A0007BE01E70FB6482F77392E492D5201A933A +:1038B000CCF7DAE17BB4A492603EE11E5BB610194E +:1038C0003F5ACDE1546A589E65BBAC3F3FFA5466FF +:1038D000FB3A2687C5E55E88CB5E3D928E67AF35A5 +:1038E000C12FEAB2942B18BF867D57F97EA1AF1481 +:1038F000F8A95A942AA10CE4F0736BAE0FB5FBB390 +:10390000163BFB5D564B988FEDE7B83C07BEB47095 +:103910007EDAA2C9FB34263F22FA6BF48F7AC332D7 +:10392000D99A0BF2FFB761BE44FD81E3D07558EA26 +:1039300008CABDFBB4F1AED1F4875F00FDA6C97F14 +:103940004B1DD51763215F8AF0B88B3F6D6EC4772E +:10395000C3F7F2F1B766F8AFC1EF7B9B2501DAEF51 +:10396000172401F4F3739C5EC3DF1F9004B4B7788F +:103970003F4D4FDFF31D76CFF89E01B9C0D66BE502 +:1039800070537D45A0BFB5D68472C45AC9F49875EA +:10399000B28A7A6333D7D7164F043E48188E37B3AE +:1039A00073701D0F5C634578EF4B93822CCEE44F10 +:1039B000E3F832819EB583AB40F1735FA6740DD3FB +:1039C0001B2AFE9EF6FDDABACC04F183688CD81768 +:1039D0004B8D15D76557D8F7B92D192AEA134BDD4A +:1039E0003328EFEE0FC3A55853F8FD644A0AD69961 +:1039F0005665346D3FC6F1689DFC0CEA1B231C9A8A +:103A00005E19D83FC3BE0F92FF86FABD73AD693011 +:103A1000DF03745F404E3D20C8476F807DA7F408E8 +:103A2000F2BCBD96C5DFEE2934B173C0160F7EF728 +:103A3000CCC9E77672FBF7DD8A495215EDB7A58050 +:103A40007879680EBF7316FE7E26E9188897C17BC9 +:103A500065AB2E81FDF9773917E1BB77FEF176B8BA +:103A6000AFEF2836A1FCD9E23B8EF7AF7FCFF5DF71 +:103A7000E5277AAB1368BB6BA684F7F7B5E7133E6F +:103A8000EC11E1F9FF0066D74971008000000000E9 +:103A90001F8B080000000000000BB53C0B7854C5DC +:103AA000D573F7EEDDDDBC374F1209B09B7720E010 +:103AB00012080488B2E1D5200437801A4CD00D8F4B +:103AC00080219088B6D096BA0B0149354AC4D86295 +:103AD0008BFE2B458BB5D6A058698BB801B4D15A53 +:103AE0008D162B6D15A252044589F8687CFCE53FC4 +:103AF000E7CC4CF6DE0DCFDA7FFD6432775E67CE21 +:103B00009CD79C99330965F642953136A1BC95B195 +:103B100002C612CAFCCC0BE9A6D2BF968F1DCD58A7 +:103B20006C81D9C51C8CFD440936AB90F74F67EC0E +:103B300061A89F3025689F9CC4587CBAC90559E686 +:103B40009E122C1B8BF95B55A640FDE88F924ACD47 +:103B5000507F82124FE56DF8CF65F80FF3331B638A +:103B60004D9AC8FB233D4B4BA01D0BDA989DB19F8E +:103B700007623DE63468AFF0F25C47A9C71F8DE5E8 +:103B8000ADD50CFA675956FBC34EC662E04F5B02D7 +:103B9000631A33B34A48E79B19B3409AE1C8602CD3 +:103BA00019CACD2C682A64CC14559DEA85F6E5899E +:103BB000DE460FA465D0CE5C48E5B644AA0F0315D7 +:103BC000C147B5DA85F55AA04A7B348DEFC1F40CB4 +:103BD000FE26025C580FFA5D27EBB3958C8D61ECE5 +:103BE000BB369A138BD9579186FDDF57CA2AF5ED5C +:103BF000A2475B7066F43B03FF471618F3B62C63CD +:103C00005E4B37E67F29C6DD1F7786217C71806A8F +:103C1000ECFF270A8C53101A6792C34470C9F43919 +:103C20008BE356C4D7739131CCAF601E3AC3F5FB1A +:103C3000D81C40FC31E62A99333CD4FE7587458C6C +:103C4000D3A0E0FAA7E038901E5EFDDE5D4F40BBDA +:103C5000568FC3847422EBCF1470250978E47799CA +:103C60002E1D62A27289F7F0F205A27D936F357B5B +:103C70002F3BF45D15FD151DF436C524213E1C8532 +:103C8000AA23545E29DAEDCE74573A8A902E787DB5 +:103C9000B63F4271C6E8FBE7E3DBA3BD6E37CC83DA +:103CA00055CF662CAD3F1C32859525BC1DC6F52F22 +:103CB000E85FBE4FF4E7167861DFC07758FF266CE7 +:103CC0009A19AAB74AE05FE6A7C5983C01A83FE366 +:103CD000A7ACF16CFD1E11F399B1A9FDB3D701CFCB +:103CE000ACCAE27A18F96DAD918E5609BA3B2AE951 +:103CF000AF1A8877DCF9E6E3A77E27ABDDA3329025 +:103D00006F324DC4B7CD8E0CA54607C78702DEBB08 +:103D10008630AA6FB69BFDD65848A3CDEF60AACED9 +:103D200035F9AD23202DB1BCA3625A79FB272A7C3B +:103D3000B7DA5BFD28171E54BC2DB80ECC633223B6 +:103D40003F4472D2656AB49BE4C8B9F8241CDE6FA4 +:103D5000CB27C0778C8D077E095CD6EA2FF88FE6DB +:103D6000F1B003E6CF66C23C52FACF43CAA37581D5 +:103D7000C4569447202FE2BC6799874C57BFF5C9BA +:103D8000F0033AF89E7044271D1B067F8C6563CFB5 +:103D9000A8176EFF2F5FCFF003C017450EBE2EECA5 +:103DA000AD6813E23151F4F956F93EBB02EBFAA9C2 +:103DB0000B041FC076B79DF377CB6A35E027FE76FC +:103DC000477874FC60EB55993B116464AF42A9EAF3 +:103DD00070D0BADB1CAD24572CA95CEEEF8FF351E9 +:103DE0006A1574DE611D62A01749DFF1E7E0FB5A36 +:103DF00051BE4AC05D66F556E27AB3EA4203FF550A +:103E00000F31F289A4D7E74C6C29F6FB8793EFDEDC +:103E10007939CC2FA592EBA749025E593FA5D2551F +:103E20008270031FAA7ABC4C2B077E3B9BBC19C235 +:103E3000F96C01D2795108AEF07A3787C12FFB8F28 +:103E400095FD8F3B7BFF923F65BBC3BDE34723DFFF +:103E50005991F7E09BB5D26FA37C19237DAAA533B6 +:103E600037F63339739D2DB280F3655D34F2A1D5F9 +:103E7000C08F57AA67971B3F767238F7450DF90632 +:103E8000F5B26D2EB3A39CB4314FA98672C41C4702 +:103E90007284E5B154847F03E370803E74D4C038EB +:103EA000EB9D5C9EB5295CCE740AFD70F7158E6D96 +:103EB000EB14D2ABFE6E3E67CB19A4272033D31888 +:103EC000FC0EBF0C4339C3F20467BCD08B1EE60165 +:103ED000BD72B7D04FF85352443B5C48730FAB8070 +:103EE00072AD120814F8B00CFA35A31E2FF12C6332 +:103EF000B1BCBE06E358C4389699BC9E84AF791015 +:103F00000BAC83F19A15169185FAEC1A930BE51A0E +:103F100033BBD31643DE5A92E2BAC311EAD7920EEC +:103F2000FD427B2D5507AFC005D3C1153E9FEF5C09 +:103F300020BF59F1A6A1DC3F31C441788C672ECA5D +:103F4000C32F0DF92EC51CE70E10FF5C9DB608D2DD +:103F5000B68A5A6511A7D733EA184E5A084347154F +:103F6000889F685C3F87827A2AB18CD345EB37996A +:103F70001D13815EEE9B3B3B0BE7BB17F902EDB3D4 +:103F8000B92605EBDBDDF6122E5FF9787BBF8A4C94 +:103F9000ABD5D1C9DE49C7462D82F6774FB7D815C4 +:103FA00007AD07D7FF5F46061E86BF274F1893E66B +:103FB000D0D17183A087FB2ABD6E06DFEF1E97A2CA +:103FC0002CD0F5B7C6C9E97B53456D1A3321DD6D99 +:103FD00022394128417A5BAF50BFE1743A5FB4B3F4 +:103FE000097CB45D638AB041DAEA9EA42C2DC0F24C +:103FF000081AB7D51CA7E0B83637E3789BE39A6771 +:1040000006F86BD20356041DE490650994573B23D0 +:10401000A93FAB5DE87DFC25A1BD9AF2D01DCED0B5 +:10402000B84BC4B8AD4A4F2AAECB4F344EE7409F91 +:10403000D3B3A1FE4F92B30A914E365D91733FE226 +:1040400049BB6D38D919B2DD3383BDB54E488F4CAD +:10405000BAF6D0222491F1398371DE2784FC78DB13 +:10406000CECC0ACCFB6D10BE6B15ECDFE3C946BEAF +:10407000B9F28BA71739A8FD0A67B2A1FD0D48CF89 +:10408000B27DCB60CFCD587E6FF9B5649FDE57E926 +:10409000BA7F21F46729B6106932D6BD6521C07593 +:1040A000EF544670F6D91382EFD738B97CD85471E3 +:1040B0002C15E12A73723A6C45BA443E637605F9D1 +:1040C000F0DE71C7A89F94295CEE48BBAEADC2E29A +:1040D000C675DB342F679BAAF0F55C108DFDF3F9F4 +:1040E0009739399CF7B94FA72E66483F2EEA578E6D +:1040F00023E93F1EA53AA471B8BE3AFABE8FC99F04 +:10410000634F0FD2A1D33E12E7D12BECA8F84A4E51 +:10411000E71DD6385ABFB6A99E80EAE47CB298E083 +:10412000FB82F0D251E5257A4F11FC913053D05BE0 +:10413000A52590EDD4F3C9A46CE213E0032FF14957 +:1041400021B593F026CEEC7EEA09A8D731C36247A9 +:10415000F45CA9F2F95CAC1D7584388DB1C79D9EE5 +:104160001D4817206F46207ED99A446A5F6DEAC8C1 +:104170006E44FA5C17A434BC7D19D80E5D881FB359 +:104180002B05E99CA5737D7E8B90299FB614C5E114 +:10419000FECB1BCBEB2966EF58CC97FD7BE1580B90 +:1041A000EA90BFC730B4DBE767B21B67C3F71B15E4 +:1041B0000ECFFCA6E9650AC8B7A093EBB7577DB050 +:1041C000C0B98CBDE6B33137A892BFF8EC947FC379 +:1041D000974AF9377D0E4AFFE6CBA3F4A885EBDBBF +:1041E000F989EC46D2D3CC6E4179F28290072F88C0 +:1041F0007E19BB35153409C0F39722931D97ECA89F +:1042000067EA1540A51A97F357BB55D4357DF2B52B +:10421000726E94100E3C5FE39960286779A342F9AF +:104220000C46FA05D7754173FCB63B60C879331369 +:104230000DF5AF6D1E68C8BF2DD6B5A22CD3F0FD0D +:10424000FAEA61867C4D2F280E188AD92209DFB739 +:10425000DAB8DC050BCF84CC708B9DD7FDAC71EC4C +:10426000805530FE672F6B541EBE0E472D5CCEF876 +:10427000FFAAF2FD137CC775F9FCD02086F096FDED +:104280001BF6BDB84EBFB2921C5CB845617E980269 +:10429000EBF1DF80ED6E7DC8EAC27A8BB6A8CC8BDD +:1042A000F0A0D106E37DF05AF6B63B685DFD0F62E3 +:1042B000BD1EA8B70D8A8E6BCC6F07D25CD82DFAC5 +:1042C000510A0722FE8FC733773C98522722DECA55 +:1042D000415BE3A3F2D65A13EA1DF5E56413B4FF7C +:1042E000E84995211FDD74F31B63EC80D7BA17DA18 +:1042F000FF5A0CFD1D6D55991DC6FB7087F521E415 +:1043000077A09201A88743F30C8C40BADC31D063CC +:10431000CE00FAFEA03630C28EF4B02699E8BB3F3C +:104320003E60FEA84F902EA13FEFF7626C0AB0F2FC +:1043300042CD953292E888EFA7FC6C741A2B86FA6E +:104340002D5A19CA75E09B5938CFA3AD89A63B08F1 +:104350008E2789AE16981D16FD780B5A54D203B0DD +:1043600018168493DDA37AC176865F2BEFB759F1D7 +:10437000B201FDD7F1969BADB44EB70C8A0C208AE2 +:104380006FC031CEC2DF1F03EF78ADA17CDDB32A51 +:10439000D9756CB4635309CC6BD6F6C94528AF58B0 +:1043A0002AEFFFB3044937EB69FCD36E28C2F5DF6F +:1043B0001E13C0FDF549D39387CDB00E56B37704D5 +:1043C000E26FE92CFF830AB0C4A93DEFDD3D01EAAD +:1043D0007DF0B8E6C2EE5B98DB9551C4E7857CB60C +:1043E000C02CF4D8EA64E267660E3CF233187FE32F +:1043F000DF0718E47E489EACE57696AC0F60988A9D +:104400003109A6288047AF834DB303DEAA58FB06C7 +:10441000C2270B507D070209F8B3D7430A787BAF58 +:1044200028E60E7639AC978979F576FC7B829FA7D2 +:1044300065703D20E5DEED220FF5B9FCDDCBF53DE5 +:104440002CF0C12CC0CF52C6F1D3C05A3EC1FDD50D +:10445000B51919547F69E39299687FD10FF0B00CB8 +:10446000E80FD7BDD61E7F6B17E4EB7744B802D0B8 +:10447000EEDE0CCECFD0871DF9F426D1E4A5BC5BCF +:104480002C385EDDD30A4BC4F102DA51B4C36C2080 +:1044900030506E7C00EC5A9C80FD29D47F7DAB129D +:1044A00008C09F4B584F10EDE2E5BF565C41DE95CA +:1044B0000DD771B1E8B7CE7C5717C25997A7BC8307 +:1044C000FB42B603FAD5C9A3E5ED7C1C29471A982F +:1044D00039540EFCB5D8D6D285FBC7C5ACCF2E5407 +:1044E000CE207CAD9A1FEBD9986D2DF6E3898A21F9 +:1044F000B8EA002EAB530FBFCACE002E6BBD81179A +:1045000066111E145780F5876309F34C89C77940FB +:1045100079D0D11FAEF0795D2C9CB5AE0EA2937010 +:104520007875EBE0D0AFC312D6753BD253AD9FAFD9 +:104530007FED1EC033F4FFCF468D59E2880EBAB22C +:10454000C684E800E09E85F270499B0ABA294417A8 +:10455000921E6EDA19B0A0FEFD90B5C64603DFD4F8 +:104560006FD979ED386CB7F5350BEAEFEA8460B6B0 +:10457000098C8B24FF55F7945D11A2CF9B02C6F9DD +:104580002FDB61CCFFB7F083B3308F11ED002F8BA1 +:10459000B7ABB40FD1D5A3F652BF2FF5335710E602 +:1045A000BBF4A0EA429FD052D0678985970EAFC472 +:1045B000D3FF37DCE1FE89FD1931DC3FE1622EF4E7 +:1045C0004F7CCE0AE2AEC34261DF9CCB3F21E71FA6 +:1045D000AE5FDFD2C09E8075FCCCEC8E4B20391EC6 +:1045E0002EA7C70E407D23E573ADD097B2FFC5A8B7 +:1045F00027217F6CCB53B16807FEB3EDA9144C970C +:10460000A01E2A08E9A1EF2D0C0E42BDFDBD6722B8 +:104610005C489A6C66F08DEF43FEA39D2A3B9BFCA1 +:104620009C39D0FB4E06C22BF4E972F5A1C176D4B9 +:104630009F429E5EC80EFCB6F35C80F31C15EA77C1 +:10464000A198E7BBCD7C7EEFB5F0F92EEA374FB0ED +:1046500023709EBFB0BA50941F8F0892BE3F0EF3D6 +:104660006CD2D90BD23E90F3FB9CB53E1884F2E598 +:104670002BDF3C6C067AB829A76B04F263F53D5634 +:10468000B2076E7A3A26C020FF81523A80ECE103ED +:10469000C158C45FDD931C7F2138FAEC035B66B21E +:1046A000CE3EB848BCAD601EF293AED8F3C74368A7 +:1046B000AF2A6E680AF0AEB0450789DE776B27F542 +:1046C000724F7170D3DCCA5C361BAE4F3A7390BD2B +:1046D000CDAAED48A70AF3B233519837BB8FC15A20 +:1046E000D4623B80FF8BEC4F6E58497CD09383FAA9 +:1046F000B52132A80D40BB6AA7E2DA86FC766B6969 +:104700002CBA0A35D648F0E46472FB5671BBD96AFC +:10471000C09B15FA8A8471F3331DFCBBC34EAE2BCC +:10472000B615C68F09C11DFE7D169206EAC568D36F +:1047300059F7C195629CE5AA89ECEC7A0BB7B74FA3 +:1047400009FFCB984CAE5FC764F2FD5D49A69DD2D0 +:1047500053B03DC6753F35D51AC07D669785ED4689 +:104760003BEB35CDBDE547B06E6F667A27E07A78D2 +:104770004CD1F391DFD7458DD0507EAE8FAF1D82E7 +:10478000E90DAC4BC3759D555CE1C0FDF4E1149B94 +:104790004B25B9050B3206ED044EC7AF68D1CDD815 +:1047A000EF61C41DCCABAAF88F5FE23A1D86F147DA +:1047B000C3F887D32C812668E77FD64AF6C3C6485C +:1047C000E68FC0F927C591BFF47A21A7E64FB1BAA9 +:1047D000D18F533565A30753E8CFCF005FD5B69E81 +:1047E0000D23619CB526AEA7D726B000D22D5BDF86 +:1047F0005D84F8BB9CADB7E33AC2EC779D493C1FA2 +:104800003D99D931492730AFFA498CFCBE4468C57F +:10481000845F43BEDEC2CB57643E51D1560279DC81 +:104820006B203D4C5703DB603E57C388B89E57430F +:10483000BF486F0C99660C5F4FFCCD86FF4B609EA6 +:10484000B3CDCC6F4AA0B4391AD26B8A59300EE678 +:10485000177C9129080F9D8D007CD7054DC15CC048 +:10486000DBD5E66007E2EF90CA36A01D3A9B39B56A +:1048700095B01EF5EB2E0EDEE6CCDF73784D260EDE +:10488000EFF79500EE0B6E30B3032AC0D390E0F043 +:10489000D3F79B395DC3F7E6D842ACAF105D5581C5 +:1048A00090407AC6F5253AC5CA6342EB04F56D918E +:1048B000F0FDF64C27D1599580778BD794827E8076 +:1048C000E5623F78838DAD8FC1F666576C05ACD33A +:1048D000480053BF4E0D16B96F6CB7CC06FE5C0690 +:1048E000FCED04BC6C16F4BE4CF2F7AF8DFCBD0BB6 +:1048F000F90BC655D09E047C5689F45CFCB153F08C +:10490000C74EC11F0F64CA7D693BD9D1CB845C39C6 +:10491000D778CBAD2C48F87AD64AEB2EC7BD5AA42F +:104920004F64F273430987A4F35AD6684139512B77 +:10493000F4AF091613F5E7D2D65F5810094BB7EA62 +:10494000EC35FAB7D58272AA6E7BF8779DFE560DCC +:1049500072CC7406534BCF22844FB932C2857C513E +:104960006569273F8282F22D2F24DFC2DB69AD7C8F +:104970001FA9B5707BCCCAB8BCB082BD8972BE26F7 +:10498000BD6738CA0569A7D78AF5B732C73405CAE3 +:104990006BD11EC37310B43BD0FFBA85C36D16F63E +:1049A000F5C256A37D52D31C3E2F6EA7687DFD9A9B +:1049B0008FEAED0C4DD829472C3DC3515FE8FCAC84 +:1049C00064AF1C3171F8FD298CEFAB9378B959D8DD +:1049D000A392EFF7656AC2BFECA775BA9A79E28233 +:1049E0003A39EB99C2D89585E8875002480757BBFA +:1049F0004B3B79BA36A8C4223F323690F89CF3F389 +:104A0000D5EE1F939DE52953FC5158EED63ED0CFED +:104A1000EB55FC635C7F3BE97826D849A877C2CE8A +:104A2000715849E259F560B89DE49FC4F2C84F84BB +:104A30007299FB8BC95E5829EC89A96A741ECAE970 +:104A40006A25D285FB85D5B6D81178E87B1AEC6C3F +:104A5000A48FEAB723485FFF2B827F3F551AE337C5 +:104A600041FA96C8CF8FFBDE2CB4AFAB632D664CFA +:104A700057A9DD34CEBF4C3DA407F6C6AE9E826278 +:104A8000F76D7B06D977B7978EDA02361FB367D9F1 +:104A900066DB06D1F9A638A78F79DD0D70CEC57318 +:104AA0004ECAC7CE76C37EF1D4F33D37D84035E544 +:104AB0006E8F9D6D06FC9CBAAFE741CC4FDC9E3AF1 +:104AC0001BCFED4FDDD5333882F24378F95AD19FB1 +:104AD0007FC86CECEFD4FD3C9F0CE5784E573D89C8 +:104AE0008BA6EAF10AE997542117A41FADDAB48F17 +:104AF000A79358D034FAC2F5A667795233E1BB1AAE +:104B0000733406D7A522C74DF9D40CAF230BF05F41 +:104B100057A1F82D300F76309023F436EDBF370AC9 +:104B2000FFBA5CB7542167643A321BFA85F6D53771 +:104B300067C7A15E85FE867E9BFE9E1370CAFEA49B +:104B40001DB358F039F43F26ABE83FEF5FCA0DD9EB +:104B50005F4B7FF8277D9BFECD39C6FEA47D2BE7FA +:104B6000311C7913FDEE398CDB51021EF97D831265 +:104B70004CBE0EFD692FAA744EB521F99819CF19B4 +:104B8000D9D1686E3F47707E589CC5E5FC861FB939 +:104B9000E2D0CEF7FF59A573EC0D6B3D9535E8CF0C +:104BA0007A7CEC18243169877ED8F1378B03E6B123 +:104BB000429C773688F3CE15BB3A2CD3A0FF06482B +:104BC00027EBFC1DF5F2FE00EB36CF8E09C1B138A4 +:104BD000CB24F4CBDAF3DE0BB8254B117289CF7BF3 +:104BE00084985F69BEBB3E4BB70EF27B9366BCB741 +:104BF00021D3DD629E576531312EEFEF7285AF5FB5 +:104C00007524D7870BC7C4D81C9787EE47D46E7519 +:104C1000D2B9C5C48C493FC8D2E159B60BF99D7BC6 +:104C2000CEEE77DEC3FDCE723C9780B33AA1EB5651 +:104C300050F66CF7F6A99B512ECCF8A9940B2022C4 +:104C40006C787E2AF3D5B3A7A473FF27E67FBEFD59 +:104C50009ACD783EDE19C9F745F3C70E8F4439D493 +:104C6000ED8C32D9413E3DECACD98D70CE1F7BC569 +:104C700034FC5E6A8DC9A9E1E738447F0F3B3D6D86 +:104C8000588EF5D13FE5B5703AF1BEA4BAFC304F6D +:104C9000EF88282FFA053B4D6C0AEA6989BFCD5988 +:104CA0009C2E7723FE8A42E3CB7141C291BFE9E893 +:104CB000BA343A8778DC59FA4C567268DCC79DDE04 +:104CC000EDB85E725C98E608FC7EAEF1C3D7EF21CA +:104CD00031FE33627C4F09D09F4E6FCC9E1265C867 +:104CE000CF9D99C8DC7AFFF6DC81867C6575A6A12C +:104CF000FEF58B8619CACBAD5DA3F5F6815CB78B4B +:104D0000DD8F4D03BE8F03BC7475B0E1BB900F9D6A +:104D100031748EBAAC793AF9CBE37AAB28AD6F85B2 +:104D20003CF0CFF2DE39945FD11B45F9CEC8AE69B5 +:104D3000A8B73B7F1B4FFBCF57D560CECFB11F6BC2 +:104D40000CF173F9C0F9EBD0AEE88CF417DC02700B +:104D5000963FF19D325CEF15BB14F2EB96ABAC5372 +:104D60004940FE8CA0FECAD5D747DF0CDF674CE672 +:104D7000FAAC1C752B9437093FE5B9F8E688E03F9B +:104D8000AD9BC33DB5B782FA93E5FFCCE2769DCCEF +:104D90006BC9DBCD64DF8AF968DD0AA557F50EA380 +:104DA000B4615785D951807EC75F24A1FE80FAD1B6 +:104DB000A4DFA55C927CD338368E459F1BCF56214D +:104DC0007FAA50FE40BFBFC9737F8DF4366B4DB7CD +:104DD000D986E704D1163BEE1367158F4CADD5F598 +:104DE000D3D4318FA1FCB226310BEACB2A48F5F29D +:104DF000CA7B8E7B174AB6515E4939CEBC2D74E80A +:104E00007783F04748FAF858C837D9BE4BE17AD8CB +:104E1000FF343FBFF8639E37291BFAE92A65954F97 +:104E200092FCE81A8CF6FF7F0B7E585F9B42FBAD2D +:104E30006E378E3BABD861C27390B4BE79703ABD09 +:104E4000D03C2CD99CEF5E55D96AA48F57274EECE5 +:104E500072E339DF0F478D42B9C8EC3DDF209D3644 +:104E6000EC9D90897EE7FC6C0BD52FC73395D1A1C3 +:104E7000FD40C3DE283ABF69D86BDDA640BD86D8A9 +:104E80009E1C94B7B7E57BF3B3F15CEDB92F0FFF30 +:104E900010EABBA363E83E63C3DE880398BF5255A4 +:104EA00068EF373DCB3D14F1752E382F961FC3E9BF +:104EB000CCDBCCF9CF2BF8B046D0ED02C1873566FC +:104EC000D08B00F78D2FAB0CE5D38235CAF05DE8AF +:104ED0008770C4B8B2757C28F94D43BA1C85F4C9F3 +:104EE000E9B2BE375EF0B753F4CBF9A01CF7A5D0FA +:104EF0004FF9B078DAA7AFE84DA47A925F259FAA60 +:104F0000F9DE7938EFF226E06F18C7BB2E6D34F268 +:104F1000CB85E9E44BB303EF8194281AD28915D2EB +:104F2000C93AFEF6F4E965FBB4143C8F59EF34DD61 +:104F3000C142E5375C22BDCF1074B2203A988D761D +:104F4000A4D618E1C27B2ED5C90E92632B7F0C1913 +:104F500040C14ACD3319F5EACAFB15F227A2BE4576 +:104F6000BB7ACCA146F24BCBF1E7F58E600EC0D3F5 +:104F70009CDE2C4A276678EB914E6A7AAF15781C36 +:104F800071D673C7CF1A37921FEFB380D5C5C80F3C +:104F900063F41716B95D740EA9BDACB1871CE8E7C0 +:104FA000F3AAC81FC70731FBBD0AF717A2FF50FAC3 +:104FB000FBE479A2F4FB59934C86F3CFCFCDAD83BC +:104FC000D1FEEFE7FF2BE57AEDE4768DF45A7DC74D +:104FD000EB634C789EE274931F70C740EFED389FEF +:104FE000BAD981DF68905F76D753B1E89F97F86CA4 +:104FF0003707B3719FD20E78447F647B8B5A16E0DB +:105000007A3C8ACEEBA4BF54D8152F326E8F483A23 +:10501000AFEBCD24FC487D23E5F733BE54DAC44A18 +:10502000397E213D24E97BB999EBB1E540F7B86EB3 +:10503000E17C14D23F23895F18F00BF24748FF70E0 +:10504000FE08E91F41FF714368BF112ECFA57E9A6C +:10505000F068E6AEDF433F758FCDF7E03A4D1C06B2 +:10506000F200F051FF24E7837E725AE86B890F89C2 +:105070009F9744BE3ECF1D447EBA30FF44909D6B47 +:10508000F5573092B390EAE5AC1666D7CAEFCF0B6E +:105090003EB858BE794AF099845BC2D965E1F6956D +:1050A00084FF4F8CDB1F729C3FE6CD7E8BE421E8B2 +:1050B0000D1CFF9D6CAEA7FF5BF33A97FE78A76FC0 +:1050C0007E17A73F5E099B9F9C879CD7CB62BE172C +:1050D000AB5FBEC8B6887BCF46FD02F58EFD01DA18 +:1050E0009D7A36DF8E724C557A8ED17DF667231C01 +:1050F0008887579F8BA0FA6E5B1CEDEF273FF7FE6A +:10510000A73F77E03E62CE178847F71EAB99E9ECE0 +:105110003D099784F3CF026ED0435F67EBF61DF233 +:10512000FBB7D54B922FC2F9369C5FC3F973C69D6E +:105130006027E23C9F51E89E40C82E64A4A73A3302 +:1051400006D17999E46F9D9D48F608CB53E89E4FB0 +:105150007FFBEBCDD10E68FFE9E89891E85FDDAF0A +:10516000B6DF3B5E09F1F1A4C7BE7EEAEFACBFBE7D +:10517000ABC8F38EC8290AF1AFE4D30BD3E5EF3403 +:10518000D257F50AD9355648F5FACA7B0E7E1B95DB +:105190007369FCE6CCE9B367B83D1667217BEC4246 +:1051A000743735E7EC76CDB7A0BBA939C921BA3B36 +:1051B00097FD7D550EDFB702DD5D95F32DEC9FF376 +:1051C000AC2FE949497F33FEC4E98665F2FD4A67A1 +:1051D000249F6FA76510C9E92A21A7679C618D8864 +:1051E00067AFD8FF4B3A2EC8F7AED0AF3FEE4F7047 +:1051F000DF71B1766D555223C37B685E48F5724905 +:10520000DE970E5FFF5B722ECD4EA911F52F56DE95 +:10521000349D63DDCF63CFDE8DF3BF903DCBEC914A +:10522000463F41A3750ED2CDA7417EDFFC5CEBA9C2 +:105230006EE1F8EEC35BD02CED8244B40B804E36A9 +:105240007D2B3A619E54F4AF1FC63FF1DCC43F7022 +:105250002EAEC77E95C97314F24F7460FE32C61E1F +:105260007864E0C1F53A3DB559F845E47D5AF4EB70 +:10527000EC3C8B9E1E90C7E97AFFD71F3C86F12F2E +:10528000FE2116B2A7F7C7F1FB8A1B7F7C1DDD57F5 +:1052900094F53B865856F3FB8CBED4C53A3ED93FB5 +:1052A00024E51BF453ED1FC0F0860ADBFFC351DF7A +:1052B000E07D487F83EA42B7F0E1D5EF7D5803F9FE +:1052C0007FF48EB7EBE36BB47A7EFF494B6A8F595C +:1052D000AC836F7FC3A812876E3E9F8B7DFF3FD24A +:1052E000BF67473F4EC7905BBB4A11DE016682D75E +:1052F000FA65B55D29C038107E8FFC05215FB49832 +:105300008F28AEA72929034F3CE03BD7CF1BD2AF54 +:10531000B5613F4D49265A372D66BEDDA29B8F3BB6 +:10532000C9CCE172328F5E1E8CCFE5749B96CBF5B3 +:10533000DF3ED54EF30638ECE80FB8F1EBEA435DFB +:10534000288F078F71E0B9C96DB999FC5EA5C95E58 +:1053500082F6E995AA6B34D3E9B37926A1B7F2585E +:105360003AD2099D6BE07CF03C61049D33F885BF27 +:10537000DE86E7089ABC9714CBE5A5BCAF4EED4C92 +:1053800086FA742E713CC749E343F908E187A77B8D +:10539000EA74D958A5FBE664DF205F6B780E9D6444 +:1053A0007347C486EE9583549C82DF351127A60D82 +:1053B000622B66139DB76BE837FA3C47FA0579BF55 +:1053C00055028E2AC01FF6536566660BD8EB370E62 +:1053D000B08CD80DEBDF1D6D71217BCBEF72FC2AF9 +:1053E00031CE8D2A9767D67ACD708FBDEFFE7CAE19 +:1053F000BC7FEF3AF46612DA4F5126BABF86D3D19A +:10540000E3614D0CDD07E91ECC56A03CB08AF136B5 +:105410008873366BF46F57E17989FCDEBD6E02DD6F +:10542000C3DD20FD03CBC5BD2FC08B05E7857F679E +:10543000E0BC2CEE7C9C17B4778ED0C9C530787157 +:105440000DFBD633B3FFBA5CE8DEBDB46B247DFC44 +:105450003497D13A760C4959437C35C04674BF71B4 +:10546000D0B1C7F0BEAF76DB04973E7EAC63406A36 +:1054700009DE0BEE68485CD3A3E3937FD4CFB12F52 +:105480002CC0FBC3D14B91BEAFFC3A7D4D69129E3F +:105490005B4D34F0E5DEDB3EFCF499244C63E85EC2 +:1054A000FDDEAFC63B705FA89ABA494EB0AF228905 +:1054B000DE27C755A63A74FC31325711F7BEDD9787 +:1054C000E702BC6A0AF04174489E6929A3BDC82F4F +:1054D0001BA329F2816D14FEE626C51807769BE012 +:1054E000B3DB721591DAB95C343B06633F325EA4DC +:1054F000638879B5DE4F394BD49F25DA770CF9DE16 +:10550000A11A1DBE3AACCFFD790CE22B65AE8BEE35 +:1055100047A3DC43BF822FCA85F3EC1860A3F5EFE5 +:10552000186009E0B9614783CACFEDE26C0134ED40 +:10553000E53D6EEDCB6A928BB7E53A0CFEA58E0188 +:105540004984F77D6AE3212E176CA4BFFF519FF8B1 +:105550000DCA2B4D8BA3F89523A69E22E4BFDB72C8 +:1055600013B83C52802D74F6F8F521B940712DE73F +:10557000910B14B7A289FB8D17920775B94EC13FE5 +:105580008D0CF9F73F9507F8D3C6F4E7F73E7E1682 +:10559000ED255FF7B5FF7FE293EBC3F8641F2E2E76 +:1055A000E27FA342E7AD5AF2EE18BD1F7393A0D37A +:1055B0008EA838AECF1A12BF41BAB0AEAF49610E55 +:1055C0007D3D95CB4F9B8C739948F45B137DAD4625 +:1055D000760AD0E3351807946BE6719EF1DC7ED431 +:1055E0004C3DC3713ECF0CF6DE9B0BE3BC2BE2328D +:1055F00042F114F10ADE7391F04BFD26D7FF8BBE0A +:105600003C40ADBBBFF2AE22E63588917CAA4A771A +:105610009FA07BA7EB530FE8CFBDB51FC550BD8D35 +:105620006D2ADD0F96E7DF1B93A6D991DF37B62AE7 +:10563000142701BF16BC47B750B4AB1D7D730EF6DF +:10564000D79BCBFDC9DEE3F669B10EC4DFF13F3B6A +:10565000113FDF57EDD8EEB97FAB744E73C567418C +:10566000350ECF0DD63B0DF1ABDE93E669A85F6B2F +:10567000989DEE531E895D5DB616EA353DA088798A +:1056800034BEE045BE843CCA9109830E96635CF546 +:1056900084FB92C94E6BFA6E4C2CFAA30EB3C62E45 +:1056A00084D7DFA2121F817D7E200DE7AFC493FC5B +:1056B000793B7D33C54BBF9D658DA7799AD9018C08 +:1056C00087DE2FF8BF4ADC9340BCD80A43F1D340B1 +:1056D00097ECB2C2509C6BA70938A790EC4BA2DFA5 +:1056E0001745FB5A8C9FC67B21EA9E22F4A74B7973 +:1056F000658E1F4DF6EAC7BB178F4152D392E77AEA +:10570000717EA7F62C1B837838887403EB7EC7CC98 +:105710006D1EA483085BA37FA003E32FB9BC686858 +:10572000DE48F7101AF694F2384485DB1917EAF7C9 +:1057300088A0C73B3CD0AF7A11FD6E31DE6B68BAF2 +:105740003FC2A65CCED8A2B6B0EF62DF53E3377E8D +:10575000AF6A31E64D792619477E4971A1A773FFDB +:10576000B3B850531E33C48586ECF45576E4A34F8A +:10577000D3CDE4CFDC28E24237625CE859ECF66E28 +:105780001FA3389076211F24DF493EDB2FF621C06E +:105790005F95682787E2CA07297EB203DA13F15CB6 +:1057A000203E8FD3C573166E57CBF87219CF199F51 +:1057B000C7D7FD0F270B296E736F6F61893EBE6CD3 +:1057C000BFDAFDD858D2273C4EB909E8E9A9B3E0C1 +:1057D000617B8E6A38DF96F6BC940FF70AB825BD58 +:1057E00086B71F21ECFAEEB0B873EF05E2CE77670B +:1057F0004ECAC92BD2C57FEF9FC79C14FF338AF6D0 +:105800002D23C4FC8177A7A17F80A57A52F5FBC028 +:10581000F22CA39FE9DE3E397669FB99F2EDC6FDD5 +:10582000CC3D62FE7D7089785555F89BABF19C1498 +:10583000F87486804FC6A3574706B3F13E9A8C4B47 +:105840002FB3B21B2BA2F9BDEB953ABCCD10F89A41 +:10585000B189D79BD1C453ECE7A1E85079F524D1A5 +:105860009FC8CB794AF8CAB3849D22EE1387C35FE1 +:105870003EB9FD331B98B04B77B8E6E2BD916B8B18 +:1058800099B83732B2CD9D857E24233E5E95F8F1DE +:10589000171E9C8270DCCB42F7E8A07C6A495CDF73 +:1058A000793592A9ACBF64C7E5075BC8EEE2712405 +:1058B000CCDB6DE6F74A457E34E46374F9E2B0FC74 +:1058C000565E3FD6DCCDF4F115E84F50E89E9DECD6 +:1058D000CF2FF6AB3DD3F0FEFEAC5D8A1DEDF1EBB4 +:1058E0004B4E5950FE974FEE7E6120CCF7873BC65A +:1058F000CD8D8E80EFE8EF0278EFDC51DAE6378B62 +:10590000F629743F817ED676C5AD025DD6172B8110 +:105910000C677FBABE33CF786E461836B66718AFBD +:105920007329ED918EA87D06B50F5A2F61FCEB4AC5 +:10593000787C5F78BDFB653DF17E02F50FB89BD3A7 +:10594000CECF85C3EB3F24E46A97C9B41C830D1FF7 +:10595000DD714D9BED0A585FC6E9E3B11D73E7FAAF +:105960000B38B8EEB0F99E0FDE4D525EEBE6EB3031 +:10597000B60F9E0F5FF7F5C397A08FA5467A8933C0 +:105980007B0E7C0A70C42529763C6759E189684101 +:10599000FD5D3E59D2F78D73DDE930BF0866B85F13 +:1059A00011A26FEF5CA4EF154CD65FD086F2C563F1 +:1059B0006286F754A6EE51FADAE799E99D106AFF7C +:1059C000FC8E9A36BC8F01EB41E594CF3A0FBDB700 +:1059D00087E54BC2F843D037F127EE77003FD96710 +:1059E000D32B02BF1F8938F0AE495C1E77658873E0 +:1059F000837C6E671E1778EC116957A40E0FE9A11E +:105A000075865F10CFB574F3263CCD4B92F3F6CF7D +:105A10009D09F3EE4A60C315A093AFF2D6B4AD1F53 +:105A200084ED3D66BCDF6666B7B5BD0C72659EC091 +:105A30000BCBF71D1474A3209F2D27028075DFA5C3 +:105A4000F8296E08D7FD2CF37AB93F9FF8C3DABB6B +:105A5000B5F3B47FBD7F7B77587BA6255D4A7BB1CC +:105A60002E33C3D6AD2C6CDDA684E5AB653E6090CD +:105A70005F52AE2DD87DCF8694248C5751D07C4474 +:105A8000F96C5146C2908FFE786E741AD2A7431BF0 +:105A900008223DEDD13B0FDA80762B507E11BDB64A +:105AA00090BC9E83FC4DF9BBE6E2BDC16B8B1B37FE +:105AB000A442FD218FDEDD6683AAD7AFBF47C3F7BF +:105AC0007E321F6D6D3343BFF3463FF102F6675ED2 +:105AD000BBF9E04CE53CF4D91A368FAD61797F58BB +:105AE000FDB60BC8F3F561EDD78495B784E5B784AF +:105AF000E59B8DED6B1629C41735B07E88B80BF188 +:105B00004951BEF4F7B78FC67B94573CFA3F6D1BE3 +:105B10008A49CF125D4FCC0FCCD5D3A9BC675B951A +:105B2000C4FCA80FB473C8A791F9E7A093BC70FD9B +:105B3000C5CBA744FDEF53783FAAB6D56AB7021D7F +:105B40001E8DE0F14CFE37F8FE826279611E4777C8 +:105B50008E0CE039DB69A05BB4FF0FDC931B877010 +:105B60002CEE5419DE575DDEA9D27B2BE8592ED7D7 +:105B7000C505DED4A6D0FB2BB56FF17E6A77A901EF +:105B80007C32A32F1EAC4DA1763705B477F5763560 +:105B9000853642FD257B9400DEF75DB2C558BEBC5C +:105BA000DD9897F1530DCCFCAE7EBF7C04FF48EB33 +:105BB0006F7F839D4AF6D7C27C71AF57C43F5DACFF +:105BC0001DDEC2DC75F984DFB0784E69E79883C9C1 +:105BD000D7A19FF5C5C4423C7F017BD856ACBBB76B +:105BE00026CF054EFABC8C810DFEB16F29A5B2FD02 +:105BF00029A5C33210FDFAFF6474CF7FFCAE9D77F8 +:105C00004E7060FD46720E7C7C7234F9833F067BD9 +:105C1000963B0BD60939CDF9FA8A5D1DEA4086FB21 +:105C2000A6F7A2E81E537FBF3EF96D3E3D690E9C6C +:105C3000ED3E425F3CEDFF4652B9C4E307DFE7FBB0 +:105C400006696F4E10FD753C96B8673CD24D549C6A +:105C50001DFDDB4BC4FD840F76A8D4CF715BDC2324 +:105C600033D1FFBA754E0A3EE2B558EBB16060AC75 +:105C7000EBD98A58B47BFF09F582E4AF09A86827FD +:105C80008D2F6374EE303E68660E271E117A6621F2 +:105C90003D8CDBCDE30A3FC4F305CE1F74BEB0F8E4 +:105CA000772AD9B712AEC9C58261043E0F08BE7803 +:105CB0007FEB53D4CF89ED9A1DE1F978BB4674563A +:105CC00007748957D28F63BC258C5B775075A16AA6 +:105CD0003EB183F3755DBB1240F9B5FC66CD4D71E5 +:105CE0008F61743E59D6037AB5EAE8BBCE1D98465B +:105CF000FE3E41DF36F80FEFB7C7B3F6DB310E7368 +:105D0000D98EFF8CAEC3E9794FBE88E32B648597AB +:105D100012C77712F6814877F27B42FBC8D2812CFA +:105D2000241FE4BDF5260BA3FBE97E53A40BFD471E +:105D3000F27EBABC8FBECA647F1EE96415E807F420 +:105D4000138E1CCAFD6AFF32B9A6621E749B1BE348 +:105D5000D666F9ADF4EE843AD9D478B6FB6C6F0A06 +:105D6000B9B86C28A3F4AB7C1E0F25E3B69AA43F08 +:105D70003A59C40D08BF9D6C7F249FEF43BECA777C +:105D8000503B759489F62DDD1A1BCCE3D3ED83B01F +:105D90007E4554C2E70EE8FAC3FCCF68DF513121DB +:105DA000E1BB99602F7C9AFFD55CBCCF5E312AE1C4 +:105DB000E90CC87FFE682FCF5F9E50A4417EADF2F4 +:105DC000F5DC29904F18EA3E91AF834FF60BDF4F79 +:105DD000E2F7C72FF39EC2B4C112DD8CFE85534A91 +:105DE000CF0A7C484DD67F4D6187FFA084F2089F83 +:105DF000AB00F34CC07FF674FC50772F1FD7F87DB3 +:105E0000013EF503F858E0E7F130F0F3D85278DCC2 +:105E100003D2E702191FD36C8C8F612E1EC725E3B6 +:105E20009E64FC527E282E6BEBA5C4659D12F16426 +:105E3000E1F172CA1E1E57D6E467DD11B4FF35C604 +:105E4000B32C8F023A023CAD7CFAED587C2AE42652 +:105E500085CB1B96CACF87E53B622767057390FF0A +:105E6000DFF7B1A42CA0DF25AA77D050C047A7F355 +:105E70008F8351CEBDBFB52916E5D047BF515D33E5 +:105E8000A17EBD383F61DFA8417C2FA4D3994FEF9D +:105E90002E9CDCB9311DEF7B670FE572E1A453BC8A +:105EA0005BF4CDFEC13F847A6519D38B506E839C21 +:105EB000CF1D7A3639BFFD1A826F7A34C87598DFE4 +:105EC000238338DD59CDCC1FC3FDC20CE3B2344867 +:105ED000D5C2905CC6F2587A536061AAF037533C41 +:105EE0009E5C2789FF7EEB02248FEF179A6C4CC3D0 +:105EF00079E6B3AD76D45B727DA6AAD1AE20C89FF9 +:105F000095A0B7513CAF147ED1953B157A176C79AB +:105F1000A7467AF67DC1B7E1F2EB23D64371D94BA0 +:105F2000B72EE471FB425E613838D2C92CBBF9BF91 +:105F300022A72A860A3935928DBC447D5B39B4A8E4 +:105F4000FF3A4C55AB1DF8DEE4CAE4BC422B3F9F40 +:105F5000227A5922E208E4BAAC7C2093E27159F724 +:105F60002F697FBB44C0C4B6F2F89DDB9D2ABD27D4 +:105F700050BE7B2073C0A79B762B74BF6FE6EE44A8 +:105F8000CAC7F6A651BEFC970326F1F7AAF87A967F +:105F9000FF3297F2271EF9D368F12E138FEBB1333E +:105FA00019D743EB70BA92BF0360F6E7FFB404ED74 +:105FB000B74E8D051C549FE2A83C021C8F889BF2B3 +:105FC000B0F0F86E471CF6E3017B0BE997B9F9B91D +:105FD0008143C44B59534DCCA1C3F335688FC17A6B +:105FE0004438229943772FF00D113FD524E436F33E +:105FF000BBBBD04F5E29E8202A2FC150BF32BA96D2 +:10600000E821C67599A17FE6E57ED03EFAC06F49CA +:106010003C0E0BFBBFA6D2182FA6957C42F1479EE3 +:10602000BE38F746A27FADC4E84FF5A44F3BC1F898 +:10603000FC8F9E8F8E7E3654D86DF92C9FFB01FB12 +:10604000E19DF8E1F441CE0F6045FC14DFF7B8564E +:10605000E0FD34E3FC71DA1D45FCB141E043D29B25 +:106060002797C5E0D33671C546BCC6BB8DF84C2C0E +:1060700033E22BD963C4D380CA0C43799A77A8A1A1 +:106080007CE0D242437E50E37843FD21AB2719F2F6 +:106090004EFF5586FA99CDB30DF9ECD6EB0DF5739D +:1060A000B72C3094E707EA0CE5C376AC34E487B745 +:1060B000FFC050FFF2DDEB0CE523837718CA47756C +:1060C0006E36E48BBA7E66A83FF6D03643F9B8EE5A +:1060D0005F19CA271C7FD290BFA2E7F786FA137B0D +:1060E000F719F2A5EC4F86FA936D7F31E4A7DAFF3A +:1060F00061A8FF9DD4F70CE5D31D1F1ACA67E47D84 +:106100006AC897BBBE36D45F3DC87B02E54EA5A9E1 +:10611000E58120433A776C42FEBD2EC9CCDF17B92A +:1061200044BFFF2752FE09BAFD9C45DF60CA38779D +:106130007B498F6FA09E2F42BA9EC9D0CF7FBA5D98 +:1061400021BA3E97BE8D03FBD7AC9B47BCDBC6CCC8 +:106150003A3812CBEC867CB227D5507F40A5C3508D +:106160009EE6CD33940F5CEA32E40735161BEA0F46 +:1061700059ED36E49DFE3243FDCC668F219FDD5AFA +:1061800069A89FBBC56B28CF0F2C35940FDBD16856 +:10619000C80F6F5F6DA87FF96EBFA17C64B0D95046 +:1061A0003EAAB3D5902FEADA62A83FF650C0503E1F +:1061B000AE7B87A17CC2F17643FE8A9EDD86FA1310 +:1061C0007B83867C297BD1507FB2ED35437EAAFD4F +:1061D0006F86FADF497DC7503EDD71C2505EFFA178 +:1061E0008BE29AD91F148ABB9991F789A11CECED17 +:1061F0003CD48BCB59A40BEDED707B5DDA63E5AE3F +:106200002F0DE3AC3235925F7695CAEDB4CA61FCCE +:10621000DC13EC789B8DCB597EDE5FC6E8DDBD38A4 +:106220008C374FE07E471E479F44FA9554A403FDE8 +:10623000A060CFC4A2DDE270DAA1C85EC6DF21880B +:106240000AD997E96774EF625CC8BEAC45DE013ECF +:10625000681BE6AD1A5684FBB29DD370BF7213F370 +:10626000DF8EF6EF54B520AE1BF4F02B11673F071D +:106270009A6E033CEAC67B31A235BDF03CFC3BDDA7 +:106280007692EAF7F52BDEFD50609EFAF392BB6141 +:106290001F6586AD64AB0FF80CF875B3CF4EF936B9 +:1062A0005F2AE57FE27350BAC59747E9CF7C2E2A73 +:1062B000DFEA2BA6FC833E37E503BE324AB7F93C42 +:1062C000F47DBBAF92F28FF8BC94EEF02DA5F4579D +:1062D000BE462AFF35ECFF31FF1B9F9FD2765F330E +:1062E0007D7FD2D74AF95DBE2D94FFAD2F40E96E78 +:1062F000DF0E4A7FEF6BA7F23DBEDD94DFEB0B5262 +:106300003EE8EBA4FC3E5F17E50FF80E51FE055F7B +:1063100037A59DBEE394BEE4EBA1F2977DBD943F0B +:1063200029CEFB360F53C4796834BD33E899944BBA +:10633000FB3DF9FDCD4CEF665C37F99E857CB722BD +:106340007C3F10BE0E1F88FEB549FC5D0AEDB29C75 +:106350006D78EF33F4AE84631BEE0D1F10E3F4BDD4 +:106360005321ECEB25821EE5BB15F25EC012C1077E +:1063700045488F79448F2F5FCA7E47EE935333BCD5 +:106380008F0F83B46E90C94FFE81681E573B31C397 +:10639000DB8EDF6BA31B2DDC3C75D1F7722BF70F67 +:1063A000F5BCA8BAB639CE3D5E83B81F7DCEF2BD2E +:1063B00027D251FF94FD5BA5FB2EAF683195E8070E +:1063C000D927F0B06F98C990BE98E1E94078DECF48 +:1063D0006E3CF67367288EF76ADC6203BF5730079E +:1063E000C58BCF61EEE7F109C06BC0D0C3FC75CCA3 +:1063F0004FE9C34EEF4BB87EF360838079EF782B83 +:10640000BD8F596EE57C110EC7EBC3B8FDFDFA30A8 +:1064100093213D96E1791DE1389AED7EE416A8922C +:106420008E71DDC9A85F7B1E4438BE78F693634A3F +:106430006608BFD20F717BA9B87F74B322F6FFFD47 +:10644000E2E8A9BCFABBDC0F331FF65B789F4DC6B0 +:10645000C99F6ED4482E629C3DFA694F377E37172C +:10646000E10F978FD5F8EE4721C6EBDB787F6FC53C +:10647000503C94BC2F510D1638EEEB6232A59FA311 +:106480003B3A99C3E3C6FBB737EEB1927C04BAE856 +:106490002139354EA578EB574C811C7C1F6EA389A2 +:1064A000AFBFFF251E076DB67BA85DEDD6F89174D2 +:1064B0008F06E804FD5AC5051C5F920E5688FBF74F +:1064C00072FD81BEBEC1FE3FFEDDD83CA48386BD09 +:1064D000E3E85E5A9349C4598BFE112E9C871A57E4 +:1064E00040EFB095A3F180F4372E86EE0D77A86CBF +:1064F000F5CEB3C8CB8C024E47AFA4F277FC9A041A +:106500001FCAF281059CAE068A7AE5FB5EA47799E4 +:1065100056746A2EF427B3D1DD057AFF4C1FDDAE29 +:10652000FE535A966E1E0DBBDFE1E7E7ACBB60760B +:106530000C0717D755BE5F2CC7D1D08F81CA25C98C +:106540007CB26FDF908178E27A41D29F6A89F13E16 +:1065500014AD9F471FFD3B0B04FDA3DD3FCBEA8835 +:10656000BB0E40EF0614E2BEC5FB3F767AF763012F +:106570007351BA8879285D026484F4EEF1DF63C157 +:1065800073D13AD64EDF57142F1C8CF906D633251B +:1065900015FABBA679EDF3A900CA9CD67BA6A60185 +:1065A000DCB30335CF635AB15D3986E780C03F85E0 +:1065B00005E8EF511A375C86E721BF2EDD80F755DD +:1065C00066093F05D09D5B453D9AE5EAF6C3FA1D95 +:1065D000BD279FFCC7C5058AE01B7731B6AF5EC7F4 +:1065E000E94CDEFBEEE39FE2654706E25999B98785 +:1065F000DE9F6CD86B4D403AACC31DA6AAB713A55D +:10660000BEE676C232B013B01EBEAB47EF53BE1D1E +:1066100041F7EA3F5060210AFBF387B43B57A9DCFE +:106620002FF72F134C49C57DF4BD8497A5B6C0083C +:10663000C40BE8E90AC477DD7BEDB78F443FE0A4E3 +:10664000C060B45FB55F595D4D4E83DCA7779DA4F4 +:106650009FEF6E8DFBCDC2E10D87C36A617EBCC723 +:10666000A414BFF025DA192027B87C38CCE15FA547 +:106670007A53F1E210DA2F749F30DD43FE02966206 +:1066800073F177288DE3AF17E376FE2FF75BCB7BB3 +:1066900065E17028763E5E3F7822393C52FFF487F0 +:1066A00087AF8384E707055C7EB0C16E9AF75AD343 +:1066B000DAF495A8CFC64714E251D02CB3F7FB8883 +:1066C000BFD722B87F4CFAC3E43E977DD394CECF98 +:1066D000A18286F78B58985FC963B36BB81EB32449 +:1066E000FF146B06FEE9F33B9518FD4EB3998BF44E +:1066F000423E7B4BE289FC4DFF071713B47E40649A +:1067000000000000000000001F8B080000000000D7 +:10671000000B8BE46060F8518FC093D1F8E8F83B30 +:106720009A7C2E0B7EF5847006507F3210C7017163 +:1067300024108700B13F107B01B12B10E7B131303D +:106740006402710A10C70371141087027100107B74 +:10675000B321CCB16167607066C76FD772364CB138 +:106760008F5C08B62727657E19C5431F73F031304B +:10677000B0F023F87DFCA8F29C7C08768130657629 +:10678000D503F503000ADD9FC4800300000000006C +:1067900000000000000000001F8B08000000000047 +:1067A000000BDD7D0B7855D595F03E8FFBCCCDCD24 +:1067B000C9FBE60527214050C04B40888AF60001FE +:1067C000E37CFCED45AD467FB41704893C24222AC6 +:1067D0009DB1934312428054A3A246447AA188D823 +:1067E000919988CF3AE87F115BB1D53675B0BE5B21 +:1067F000AC1DEB032983B5D2FE769CB5D6DEFBE655 +:106800009E939B87B6F3FDFF3750BBD9E7ECC77A61 +:10681000EDB5D65E7BED737DFE5CA68E66EC0BFC63 +:10682000F335C6F234C6D899FDA5F9F75ABC7722DC +:10683000FC9B45189BCED8E800FCD3646C4EEBDE85 +:106840000FC64F636C577B95EA837A1953182B64F4 +:106850006C67675590417BB535527A14CA9D955641 +:10686000DE05D0EEFBEB59D436711CA6B222C62A47 +:10687000FD7C1CC66C86F5D18CD777B55F98C3427A +:1068800050EFEAF80F6D723F5CB21C6BAB2CE9A7BE +:1068900071D8170CFBE97F385A23EA958C11A8852B +:1068A000F87FE57C5CD1F6B9B71F2078BFDFA9324D +:1068B0001F1B08C7AEAED904E72E9B45F1A5840384 +:1068C000E1B3A6F7C3F765E121FC009E3358B7CAD0 +:1068D00090A6B6F58B088C572BC663FA5C3596CD1F +:1068E000D8E696C439D563196B6BB1CFA9F630D60B +:1068F000D9D24965574B373DDFD0D243F5CD7AC267 +:106900006F005C7A08DAA5CD1B30A17D4D7F3D3B41 +:10691000DAEDA8B36405F14F13F87A0B7A1CEFB3E4 +:106920006A128EFA9AECD97EC47F430B63960FE10C +:10693000F1537986A1BEE303BE6CF2442331207685 +:106940006DE8EAF90CEA81B0FD9A0FE8D79EED35C3 +:106950005B01EF09C6BC0FF0F94FC6CEF31F453AF5 +:106960001ED67F7314E6AE81BF5F54413BBD210F3D +:10697000F13883F1E7FDF462AC00E03C8F4938E187 +:106980007D1A5CE7D5A836CE3FC1D5EFBC90779194 +:106990001A66CC3FCA8AC470BEEEB47E30DF79C6B8 +:1069A000252B14E8C74EA5F5ABEAE7CFB61683F062 +:1069B000DBDE52C3ACF18CED83BA09E5F6BF688D1E +:1069C0005CFEB9BC1842FED7CC5219037C6F3B6009 +:1069D000EE6230FFED28FFB05EEE031EE173FB7E3A +:1069E00096B85FA17EA54D058CF52C2AAADD0CFD7D +:1069F000CEA807FA019C3D4AF21D06CFEDB95E1301 +:106A0000DBEDD3FB2EC47A4F3C4FB5A13EA11EE86F +:106A100007ED26C555BB78F240B981E7EF8C87F7C3 +:106A2000DB3DCC8AC17CDDB7B1442BF4ABB5801F14 +:106A3000D8EF541133F381FED7DDF8910FC6BDAD09 +:106A4000D16BFA2AFBF960C15FC4FF367DDD270AEE +:106A5000F4AFBEC26BE2BCC3F1A3AC29ED3DF2239F +:106A60003E083F1A811F9333F06121F0213C381F0B +:106A7000DCE59696047B17687A4B4B84F8D2D56296 +:106A800052B909F904FCEAC0A62503D7E566953595 +:106A9000F5821C6C0EB2A6FD280F91DA8CED64C94C +:106AA000D87AE2DF2DC8BFB3092C8BD5319683BCD1 +:106AB0002FA57A32580DF37B52750B55CC6625D530 +:106AC000DE66804FF6C4FE7A16B4BF25C0EBBF6207 +:106AD000DB2D7B667FFDB8BDD55197EFBB3C7D4973 +:106AE000750A6307D895D6C480637C0BC74F87CFE0 +:106AF0009F61BCAE00874F59DF6DD9005FB7D21DD3 +:106B00006163805E0A606F307608FAD5D7D1B854D9 +:106B1000DF73FB22FBB9B3FAE779D35E64DB40AFE6 +:106B2000452CF623A4FF8C3A184DC579938D0CE0C3 +:106B3000FA29F68779B267F2797ECAB6586D7A3F3C +:106B40005D7E696FB0715EA9D735CE62A6D97E5BD6 +:106B50000BA35D38955441DEB47C66A0DD60913CAA +:106B6000C6607ED5B018EA09C90FCDD0DF4B5FF7FC +:106B700029B910ED07E7236F07F0BF4DF047D9E5BE +:106B800008FF8FF015F077F6D9753F9F09F307FAE4 +:106B90003C51B40381897CBDE658DE042EE130D23D +:106BA00019A6087FAEB1B341649E46A1877172EA0F +:106BB0004A59221D1EBD3B827A5B8E0BF37D944E9B +:106BC0002FA87F3CD4FC3ACE6F0E9C4F9F08758453 +:106BD000A71AE0A91C386F5720DA88FA6D766DDDA8 +:106BE00037188D3356F529FDFDB2AD71A48FA20A79 +:106BF000D747211C3F0D8F10CE9387F6C139AE1CAD +:106C00000FE8C2504F0470BC021C8FC321C791FD16 +:106C1000E578EE7140E222B14943F1FFB5A40AE301 +:106C20006A735CFCB746C8FFFFA6713FD1B91CACC4 +:106C30009DE54DA01E24D39F37105F899F1BEFB5A4 +:106C40002FDD11413EA36A433A497EFE51F493F38E +:106C5000BBF939D27965FF81F36A25AC6AE0BC6E75 +:106C60007807C8EF08D751D1A909CC9A0AAA1FF50D +:106C700003B46F5D1E642817DDF52C8172D77D7813 +:106C80002EF94977A9EC05946BFB650FBB1FA6BED7 +:106C90000BF52EAE2D7B1AF5DB166625174E1C5C08 +:106CA000EFDE0B7E86ED437DC5C8DEDE05F504D440 +:106CB000CBBA75B27F7735E60516C13CDD1E781F6D +:106CC000A2E7EF1403D2459715F0E701FEBC1CDBE9 +:106CD000C3F3BB178AF6D97CBC726C0FE3145FC197 +:106CE000DB97AF54999D66C7DC70E57AD9A2580648 +:106CF0007837282AD1E509618FB6A13D0238738320 +:106D0000C622A48BD1EA3577015D6E9B5B54BA181D +:106D1000FA3F3BB748F90DCCB743E1FEF17661CFBE +:106D200052F3341B0A3AAD4F78924A3897B16F2B21 +:106D3000CC6A063EE51E4D5C86FAB973FD01E6039A +:106D4000FA94D5431D3CD3BAF073EC79AA33D2D769 +:106D5000BB95D749FFCEF0B33790FE3360FDB60147 +:106D6000FD67E8CD5A330A935D90D1EEED7CDBDF11 +:106D700098807967B477F45D44C293203EC8F77574 +:106D80006F81BCA4D1E70981E73681F735280F6907 +:106D9000EBD1C07FC2BC06AEC7C9E4FFCFD2911E03 +:106DA000EF32D2733B37DCD886F4C97D8B4535652D +:106DB000203C46BD735DCED09DF8FCADF058C4AC10 +:106DC000EF2985838F37D08EC41FC0F633849ECEC3 +:106DD000ADB7B5F8C421F1BE1CFD3DE37C46F665B8 +:106DE000B0F1DDF8DE21E809F33D9669BEFF2E7AA9 +:106DF000CC08C1B8057FFDB8B96FB9F4CB08E90B71 +:106E00002B94C601F74A477BDA5FB718AFDB03FD67 +:106E1000C274FD5FC0F7895A4190EC805600744DF2 +:106E2000C34FF6F37A19ED6351F6102EFA0320EAF8 +:106E3000E5D1EFA3EFF33BC54BEDF408B727BF5205 +:106E4000E3BF53108EF94CC77D534074F1C0780AEC +:106E5000D8436F694D0EC941A820A31EED6CE959B6 +:106E6000A0A7ADF34EA1B724DDBC552C918F74FCC7 +:106E7000FC2AF3C249838FE3A6579B27FA5A1CF5D5 +:106E80006CA1377A3F1B1C1F45F5D23C7A8197E4F1 +:106E900012F051D4C281F8F88D1843FBD1963D6EA3 +:106EA000487CDA053E6EBEB74BBC4608FF60EFDBA0 +:106EB0003D566411EE87B233E3E541BC80EE152AFE +:106EC000E79327E4253E790A6C8670037E156A06EF +:106ED0007E31166368FFDCF8E9065FAF727EDDBFC6 +:106EE00063819EDF0FE769AAC1E749C111A571342B +:106EF0008351BFB01A3F0DE703F9EB23F90B590497 +:106F0000873702039C81A5D56883FCB61F3C8B4D57 +:106F1000C47EA1285B09A5371467F3A15DBBDC57CC +:106F2000164C73AC93B1AAEAA0939B6E25C20ECB0C +:106F3000FAB6945C39F9BFED1A2FD5DB0BA3DF4706 +:106F40005ACE11F2E0A60FD06D8E9A36BE6E707AD0 +:106F50006EBB46D06B49E6755CE2BFD7412F5AB095 +:106F6000B02E73C4B85B22AC5BCBC1FD13DF1F56E0 +:106F70009AEC59DD04BA99899E45F07E23E3788C1A +:106F80000EC42F423A7AD46EE6477F77269F5FCAB7 +:106F9000D55CED453FDACFAE6855CE6228BFAD2A4D +:106FA00019E56807F80BFA58B0BB2D7E8672FAD93E +:106FB000DBE309FEC1E4ED8E16BF637DDEB14E6FEB +:106FC00040FD76C7FCDFDC763EA0BCA1A0BA96747B +:106FD0008CA5E8885700E90EF0AF10F3EFF8F68DB6 +:106FE00052EE5620FDA41C4A79ABB42C0BE31B6077 +:106FF0003519EEAFB3DB59346972DAE8697492F48B +:10700000013AAC453A840D361BE70D4CB393584A10 +:107010003A744555E2E79A33C7EDD22AFBE17E4C3C +:10702000C80B2BCFE372AA47695F32D8FABB05E8D9 +:107030003491D671B782ED4AEA5802E5B7533C3F26 +:10704000538DB5231C254B120AE2738FF0C764FCE5 +:10705000AF5DC07DCBD9DC0F6CAF3076223CB74A38 +:10706000389A04BDFAE5EB56D23B822E52BE4AEA6C +:107070002C7497D97A6FFC0E7CAF55371BA887828A +:107080004ADCF256A29F25E4DA667D38AFA1B0FE55 +:107090003F306F3862EE427DF07D95EF738C9A8EB3 +:1070A000EB30FE9353AE133D8DA38B282EE57DEB85 +:1070B000028AA3C0738ABB9458DD4C013E9446D823 +:1070C00041A4EFF5DEF8F789EE13DA93C40F66D921 +:1070D00038FF773D16A338DBCCB885FBAD1DDF9EAE +:1070E000CE16A5C9D3A388EF99A40FAC44A89FAF2F +:1070F000B76A5C4EB64C3CE95F16C27641A24B259E +:107100009B661913F1553449FB36210FC0F7471020 +:107110007FFFCCA334BF6970F840DE8B914EDFF562 +:10712000F445108EEF7EDBDB98E0F43842F455F93D +:107130003CF09F89F4F1AB1C867F543D5C6FCD63BE +:10714000B4AF088558027D77AD81D32D3BC21216AE +:10715000EEEF905E69F40920BDA034CCA84D2AAFB3 +:10716000FA44B2DA24FA3C8FF085996DA11ED1431E +:10717000DD4C83E777E8CDBFFE0E8C7FC7612D6ABB +:10718000B334F96351DA6F483A15CC877596691FA5 +:1071900027DA0FEF1F703F400F713B26ED02C8E961 +:1071A000EB08976E70391DA9FDF1AED3CCDFA2DEDE +:1071B000D20D8AE7E9C257E83016DB489F4F91C6E7 +:1071C000401FAD7B0AF109C49EEC110282FB4BAF5C +:1071D000612528568276707ABF1FE2AF5659320D6C +:1071E0004F4F79D01117668D405698EF06F1CCBB02 +:1071F000CE4B70E8601778D05AFA3B5E1A07A7F8B2 +:10720000620CD6FF81E691FDF4104B06804F9BAADD +:107210006B593C6D5FAB633F6883DB0C1EB773F645 +:107220001B9C2EAEF92E76C239E27E21DD7C2F2DFD +:107230009E37783F9DBD27E904C433908069FEDD09 +:10724000460F7B5201FBD956DE416225ED848CF35B +:10725000B1B8EAB05F5A398FA7FE4A35B97D13FB42 +:107260005A1FBB2449EB6384FBDC2C975D7D5B8953 +:107270008FD3D2FC1C6FE9E1483ABDA53FC9265E19 +:107280004CFDBAA6DC9854503EAA8C29241342BE69 +:10729000BA5C74841D34C1B909F78163D14F682683 +:1072A0007D18A88E133FFD663795BE725BF813FC00 +:1072B0007D4A6E27727BDC11E5E7135E7F92F45402 +:1072C000A8FB20D31CF21A671767239DF8F9C4BDE9 +:1072D0005072B948D0FC3E33E89057298F72FCE1D8 +:1072E000D7A5B01F6FF9685D16F4AFCBF95ABAFD98 +:1072F00090FE49EC62CEBF23354497FBC539C4C02C +:10730000F1397D3E83B1FB90BE7A9CCE93F66C5DE5 +:107310001C447CF7F45C9893CE0777790FD8B1249E +:107320006CBC76821F80E5BD2D0695F2FDBDE87729 +:1073300041FFEDC2AEC9E7FFAA71FBD5A6717BB2D2 +:10734000C71F0B225DD9A1CBFE6E0290A4FA88164E +:1073500045992BBBAD3777A8F931AE904E57A62D86 +:107360001C12DE756F952C782E3D9EA36517BC7799 +:107370003AC30DE00C5C1FC3F5FFAC25B2E039CF7A +:107380005F4F97EDC8BF52A4C3FEF536D23DF93525 +:10739000D21F55629D957432B227D56BB93D619F5E +:1073A0007FC1DFA7CEF1ACD022A88F65BCBEA7738A +:1073B000F166D4A715AF684C05B91B2BEC31DBCABD +:1073C000E3FE7EF88B7A8242E930EE98252C918498 +:1073D0007663BA9DE70B25ACEB3FD0CFAF6069E792 +:1073E0000895287717D0F95289EBDCA15C873D6EB0 +:1073F000ED5FCF87FBFF1FF1E15EBD3760A4F52F86 +:1074000053588CE25DAB7EAB2C4E93D7A7849CB2D5 +:107410007521F66E9ADEDDAEF4E6A251DAB9526D50 +:10742000E07E49EF0BE368FF74F4BCCD0CCFA16E96 +:10743000FCFDD3E8DF16BE7F1EDAF1E7B52C3E4E29 +:107440000373F86D721EF0DF9EC7F52CFDDB9DED1A +:1074500017927EBAF7F3EB0F7A806F63D7B2682B7F +:10746000F19F1DC1F32953F0DF14FCAEDFCAF95BB5 +:10747000D5C51274FE643BF95FB5C456BC38CE3A2C +:1074800016C5BE639A18F929D50BC14F01142BD626 +:1074900039CFFFAAB73AE5A358F82FC52EF93041E6 +:1074A0000EF2410EAABBE39B71FE92231AF71D5CFC +:1074B000F38F357B2FA0F9405E1264D7D3C6D1502D +:1074C000BEA2ADC80FB75C16A35C4E1E38EF5F2B93 +:1074D000777F40B9CBEA97BB4F5968F15EA86EEB56 +:1074E00098FFF238226E4C4DF7EFA5DCE9CCFA3369 +:1074F000F289C546E6078DB85DB25CA5737F81FB56 +:10750000AC3591209EEB6FF71A3FC1F374FB971ACD +:10751000437BB37D4D69693A9E3B3D5CBFEE0CF009 +:1075200032A273792DC24D1794A5BA888786595314 +:10753000BA1EEE9FBF55C481783C68FC29707CF26E +:10754000D3EB5E575D67C9A9E9F5B0A8733CDA4B88 +:10755000F8BEDD2C65143790F37464C79841FE576C +:1075600035D925793E7E28779E1FF16C0FD5E670C0 +:10757000FFCC54D3CFCFDB4355C52C0D5F791E39DB +:10758000183DDDE791A6D78AE442D99E3B8FE21EE3 +:107590006698FB0D67EA625F01CF30BE3BB3DD68E2 +:1075A0006D0559DECAACE97A21EF87F06A86B70A21 +:1075B000F7D1D0CE4A64A05FA5CEF71DB010FEEC87 +:1075C0003C670D19A4D7847CB3D0C8FCA30A3D7EC8 +:1075D00001CE6FCF66E4E7D8552CD186EBB939EEF2 +:1075E00088D341BBAFEB67523B1BF7BDA976F1389F +:1075F0004B9D0BF17617897696A35D6C40BB4631A7 +:107600002F73CC6B0D98F70A091F4B1F2F3A60BCE4 +:10761000C5A21DF9FBA976E680F196897696A39D11 +:1076200031A0DD4A810773CCCB9CF3A6DE8FF28AB2 +:10763000F731DA276D28BCC44FFB97F72B1CF2E714 +:10764000E6C3B3855C1E9F2B9CD780F272FD0B1E98 +:10765000CA633958E89453D9BEAD85D5AD1C8BFBB0 +:107660007A9BE7958476D13CF279AA5D689791F987 +:10767000F9E241DA2F16EDFD740E3098DCB4097989 +:107680006F13F2EE7E7F52ACFFCE1AB52193FCFE53 +:1076900045BC677A8CE219DE1AFB9C8919CE6BFE19 +:1076A0007FC7F3B8D07B9D35ADDDB361ABF7707BA1 +:1076B000632BC6B936456EEF9E05F557ECC6D67AF4 +:1076C000E57F1E9E3FD39739F07C8A2D6BADAFFCD2 +:1076D0009F87E747ED3738F0FC9E7DC39078CAB8A6 +:1076E000967BDC3F0ABDBFD11323FDBEA1F0C608C7 +:1076F000C2BB41E455843C75ADEBA13E89C5FF8416 +:107700007A6923FCD787FE9D6E921D1AAE9F7F82F9 +:107710001EC375B629C2FD4239EF569DEF7B6479D1 +:10772000270669018E40894E7E182BF426C60A7CF6 +:10773000F09C62BF6E70BB2CF0FBB9AB7E4C371C6B +:10774000EB16FEF167F48FF09C8CC7335CF647E8CC +:10775000C7BB73857DCE638EB87C7B764245BCE625 +:10776000B436F23C3261A78B044D0F5D716300F5B6 +:10777000DFDD8D99ED34781ED4DE2BEA1B421776BF +:1077800056621CF5250FD56F6FE1F96D1B84FD96D0 +:10779000FE8E1C7F56EB3A1AFF50E18D9BC642BF0E +:1077A00093E04762B30E21271D83C8C90F3D5C4E8D +:1077B000FE15C6C73CB2C740EEB0DC0DF538948F5D +:1077C000403D0E03FD1FF0FFE3347F849E7FB7C56D +:1077D000A4F21E80079F1F6C89527D6F4B1DD577C9 +:1077E000E1FE01EAFF24F60FD5C754B2FF7B5AD859 +:1077F00059E85A6D6DF153B9A9C5A0F2872D91B31F +:10780000302EBEA3C5A4FA2D2D35546E698952D9E8 +:10781000D6524765BD7261BD879FBBA901C073DBAE +:10782000EDD594AF36F5984EE3333D7A2834ADFF6D +:10783000B9C4B35E997D01F6FBDA0995C741FD270E +:107840000EE5646EF7750FC6254FE8BC5D28662906 +:107850000519DB5D84EDB28F70BC98D1676999C75B +:107860006BC4794B8E08F80ABA6779338F7705B6FF +:107870009BF59A802F62D41B99DB2DC67635AF0914 +:10788000F8CA6D359879DE65D82E2FCF5E4479869B +:107890002CD6EA8776C50B8D3CDC5FE5E5DBD7F1BE +:1078A000E7D6213FEEBB0AF8F37C6C4FF2C99EC3CA +:1078B00071B3A789E7D87E22F717B2A661BC478CBF +:1078C000E3E5E3DF7905F71B8A1A8D5D7E10A95B7E +:1078D000B15E80F3993BB19EE7E3F31516C59802BC +:1078E000EBADA820AE28305E0ED45558AFC505CDFF +:1078F0008A0AF57C2F9FFFCEE97D4C81E745D3A016 +:107900001DF4BB15EA2AF42B9E06EDA09EEFE3F0D2 +:107910001496C5A95DB738EFCF298BAF473FCDDBB4 +:10792000682AB834EE11F900C5113EFEF8C678ABEE +:107930000716F9382FB3BE09EFBBAF63E4BFDEEA29 +:10794000796936E6831534727DF4B4A774CEFA6A89 +:1079500080BB94C571FD6C1A3BAE04E3EA7965AC5B +:1079600019EB81713513B09E5FCAE36B9BC69D5DB9 +:1079700082F91AF9F87E22E911DB807D5D60FCCC8A +:10798000098B86D857C9F29317E7501C3DBF416554 +:10799000D650F91E96F3FC7AF4C2A307119F3F78E4 +:1079A000383EF7087C1EF4BC3E1BF3ECC20B393E9C +:1079B0006F6EF0727C467178B74C12F88CE6F06608 +:1079C0004D16F88CE2F86E992CF019CDF12D11F8C6 +:1079D000649DC1F1F944B78A8D0CFE901BFED2253F +:1079E000CE737CD3DB5C42E74D575E9D5C0A75EF3E +:1079F0005E0EDFEC8ECDADAD00DF86594CC7B8EA28 +:107A000006B11F33FCAC13E745FAE0B9DA360FF7DD +:107A1000B7245FF27EEBB5F333E45FCB52F22BEF8A +:107A2000B7FE77B09DE457FE6F83767E78F07E9246 +:107A30008FF9BF0DBD933EBE1BBF0CFC487AC0BE84 +:107A400066777CACDE09EB71D44226F220FF3C7BEA +:107A500056F540FEDCBD94E37BB7C0B744E20BF4BF +:107A6000CD03B8F74B7C05DFF242C3E02BF8991742 +:107A700012F80A7EE68786C157F0393FE4C4F787DB +:107A80001E6E6787E36B9BC0A34DECA7C12C0F8DC7 +:107A900047748478445D7844478847F4ABE17117B4 +:107AA000E29103A5C8C72A09011E7943E0617887DE +:107AB00084278587017884D3F0308243E29FC2C354 +:107AC00008BD933EFE48F1E810EBA843F0C310FC5C +:107AD00090E3B8D7D1E6094EFD163CCDA9DF369F1D +:107AE000C6F5C1369CBFB07F7D044FE7FA20B56E66 +:107AF000B3B9DF6808BA0D36DF531F38E73BFB43E5 +:107B0000E77C4F7D9879BEB33FE2F3FDADE205B966 +:107B10009EF837BC623FAEA5EF8B9B2DC7BE18DA2F +:107B20005D2CDAD95AFA3E3BEECCFF817697794547 +:107B3000BCC0D12E36A0DD95623CE698D71A30EF56 +:107B400055623CCA1BED8F170C18AF49C2A7A68F10 +:107B5000670E186F95686739DA1903DAAD11F332D9 +:107B6000C7BC03F29DAE1BD1F99DB1C4EB8837862B +:107B7000677A1DE78EFE6A675D9E1352BDB27F3E37 +:107B8000399E3C0763F19889F07464C75FC3BCC336 +:107B90006E6FFD9C023C77CA656457BA3BFEAE0D22 +:107BA000F3C475B6667402F0F0D7E82C81E389F36C +:107BB000231415A443A05CA7B8FE068FC5F0A83E09 +:107BC000501DA5F8710A4FD15EC6430693273DC2EA +:107BD000CF7FF548671F2FF9793E5BA8B8F359EEC0 +:107BE00043FAFA588C61DEBBCC3718F1B9D688CF8E +:107BF000BF588D0EF8DDC482513C0FAED4E20FE1C8 +:107C0000BCEBEAD731DC4279EB9BBFD56EE2715C0D +:107C1000B382C4308A79DE16BBCA1FC5FC5863CE56 +:107C20004C3A4F6C2B74EE073FF2F2F57CC0AB512F +:107C30006964F175CCFC76C98234FA50D2377F7F03 +:107C40001DF2E74F1D4B0F75D6413D874D51C06F5B +:107C5000B9CD5839A701F030C688FEE583F41FC3BB +:107C60001EC6F6C7BD8B0FE9C0776334233BFA69A4 +:107C7000C7CDC45F633CD70F6C9AB9B31DE0EFB9B1 +:107C8000A2680AFAC3F95F5F5789FA2235CEE95C28 +:107C90002E3EC37ED83ECEF381E4F9F8E840BC0F17 +:107CA000E9136EE84E62CAB31692793E22EF4BE4B6 +:107CB000B3B9E9FD8A97EFA3545FFFBEB2A300CF2B +:107CC00031FC51F493619E78FA393CCCF336AEC363 +:107CD000E1E699AB4DCCF94D1ADDDF13F3C87A8795 +:107CE000C82392F5BB2B5882F2CC251C5180635AD5 +:107CF0003F1CC7BC621F1CB24B68BD1B5066F7B768 +:107D0000EF9EF38F0AF2FB02357E12E16391B89E7B +:107D10004E1F7F439CCEAB53E317441DE3A79E4702 +:107D2000F8F8A97A03AF839B4AF26ECC5948F10F59 +:107D3000BD9EE731B24667BE976E34CBBC25D557A2 +:107D400038306FE97CCDD27CB40F2C37E81C8239F7 +:107D5000F7E9321F67719D18909997BE0974BDE6C7 +:107D6000B087113F3E87D669FCF8CDBB3CAFE41A23 +:107D7000714EB384C5C2F8F263A636A05C7ECC5EB9 +:107D80000E4F4DF37747FB449E5AA787CE5B6CF8A6 +:107D90008B766869B7C771FEB2ACC759BF9A5D5898 +:107DA00084EBF1EAAD1E3AC7B9C6752E93E3E3FC46 +:107DB00059C69A3BD04FDE20ECF76283E9F960D2D6 +:107DC000563D71DF74B493E37C3C0EF221EEDBD3BD +:107DD000E2F9CB4309AF05EFDF7D74EA25E730EC2C +:107DE0009FE828453D9FCB683DBBE5F6AA4E277C22 +:107DF000C3C1EF86579E7F0C0687BE57B1D2E338CA +:107E0000B29C26D6A3E4D73A7F7832269B7D16E033 +:107E1000652A0EFDAB00D99D0B31399BDA37CFE0D7 +:107E200076AAF90C2C87EB7709F63B7360BF4D05FA +:107E3000DD319443998FE1F737539C45D163A4F723 +:107E4000374586795F0EEFB521DE570FDD1FE4EF72 +:107E50008B2FA6337EC793E24D3C1F09F3DB305EC8 +:107E6000D2E6897D03F7CF6DAF680C139DDA3CCD68 +:107E700064A7EC0A66A25EF055F3F7BE235A815A56 +:107E8000298418EA1D250DBB31DFEC0A9F47C4BBCE +:107E9000A264AF7D21DBB2300EE4894772812FDE10 +:107EA0007FE47ED6AC503C8EFDB448A307CF3D9F07 +:107EB0007FE8AA46AC2F8FCCD391454D629C8F7F33 +:107EC000F0F07406F075ECCB66498AB324BC18C791 +:107ED0005AFEA846718D15FF924DF32FDFBF6CCF70 +:107EE0007C184779E25CF33DB29F6DC4B7E58F5FC4 +:107EF000F4735BE0E3073AB4AD17F97A76347211A4 +:107F0000745DE563DFC2F880C45FCA89DFECA67CDC +:107F1000A6E57B7329CF31255F3AB487FE3E28332F +:107F2000DDD7E812EBE358B697F2C195BD07AF2451 +:107F3000F87A2FF5205E4A7933FB77986FBDCF230F +:107F4000DBD1BD24FB41253116DE1F7B70A7B76A4C +:107F500012CEBBD3BB98FC9DF5440709A77FEF6DFC +:107F600036AE2B7FB551852C9EF32FFBC218F75BE5 +:107F7000BD574B625E1F9474FF3460BACE59991599 +:107F80005280EFD7924A82F2D155A477AEEDDD420E +:107F9000F903AB9F74AE37A06B340970AF78558B83 +:107FA000CEC7FA230F844D80E7C3BEFBC3487F983A +:107FB000679117E4DE6338CF7D71FC537903C763A3 +:107FC000EC8417E56C75EF263E9F6B3D7F88FF289C +:107FD0001978DEBBDFE73CEF657BF347E45FAFD8A2 +:107FE000F7E90E1BE63BB6FFA31D9867BCF23F3FC7 +:107FF000D9F10F18AF7D2660A03E5AFD837FDFF1D7 +:10800000F740C78F9FF4A92817C79F7E60CF36A877 +:108010001F7F7D7CAD02F59F0A3D71FCE13F159904 +:1080200030CEDAA7E71623DE6B1F9BE338D77497B1 +:10803000C75BF8BD9C7E7812FC9EF8930A1E86836F +:10804000E3224A173F0E3DAA318C2B7EFC9A8FF219 +:108050000056C3B375B5C89F55942780F59B81AE74 +:10806000D73EB491CED507D2D72E53235826CB3046 +:1080700015F5DA472FFAC6B9D3B0F450DEC06A76E8 +:1080800082F4BABBDFEA23C0C73306E7DBA7EC7391 +:108090002F26B9AC7E68139FD7C5B78FF11F670D28 +:1080A000E4DB073E677EC8A76CE5F7B6E1CB47F394 +:1080B00033FA8FF29C7ED563DF1C321FE0B86B9DD4 +:1080C0000E46DF26E1A73FE1B3FE8476FCD8FE7FB3 +:1080D000DAB3AD00F9EB8BCE477EEFFB741403B936 +:1080E00078DF73E24A5C7F279EF619782F69F9D30F +:1080F000AF92FD38FED82FBC26E96D1652C00F395D +:10810000CE527FFAD02FB956E195D5BBB393BE704E +:108110003F9FAE4D2C6830C3F49CFCEF6B135CDECC +:10812000AF4D1CBC58C9C0B7A8BF8ADB974421D14A +:1081300065D5EE37BDE25E7D8A9F4A1DF2F19D79DD +:10814000F87C303E4AFC0DC47F461A3F77F3753AFF +:10815000D87A3CBED3477107C9DFE3221F6D754251 +:1081600079956558A7A9BC832F99B771BADFB58EE9 +:1081700005BEC3ADE3E1F1F872742AC3C57EE640E3 +:108180007AAD2FF1D239B616F6D2FAEBF098AFE20B +:10819000D5BC132F78D82EE8D2169ECECC0C79E31E +:1081A000ED2DFCFC42D6F5508CE72F1718B5983F03 +:1081B000E4BE0FE2315466A6C1639CABC6329DEFAC +:1081C000822521FCEF127978B7CE544BF0AA81B109 +:1081D0003E427910C6EC5387C7509CBE80E7530AD5 +:1081E000BEE84CF8D9220F66303FE7AE0AB61DCB89 +:1081F0003B4BA03C63A0FF32DF1F5FECCFE0BFDC56 +:10820000A58876B9FCFEBEEE67FE20E8A93B951373 +:1082100087C7E0F3052AF97BF0BC339897D6FE2C8C +:1082200071DFDFB24C633ACF8BE5E74FF0A808FD72 +:1082300073F1E7B4A88DFE8D9735937FE2C77C1567 +:108240002883AC97CAEF88F512826588F51C76D42E +:10825000184B8325291E5028C62DF487B87F7FB17F +:108260007E2CFD7E7D806DA7780DA6837FE1B89F73 +:1082700061D3BDA9E1FAE35465F49101FEFD8C02DE +:108280000937EE2F8AC4569DF03218E25926DE16C1 +:10829000A3370578955A4905E1AE6047A93E1A41D2 +:1082A000D130A53ABE9E511C26A6209D03EC2DDAA6 +:1082B0005FA8B6AA7C71BA0BCEC27E3E32B1CFF6B1 +:1082C0008A7DB6E4F34DAAF57A1CEA3769CD4F1ED4 +:1082D000ADA4FDF7763FF6539B4FE0F3CFDE5E662D +:1082E000E2BE66ABF0F3B7663BF7D90FF8B9FD9382 +:1082F000E5D65CC1C76F0A3EEA316541DA7A20D023 +:10830000607FFB83CE6BEA697FAB733CDCCFE57C9F +:10831000BAC1CFB77CD5C6145A27712048DAFD8977 +:108320001FFAB91F353A10DB8F72182EB789F6B8CD +:108330002F3D9A61BDB8F7A5ED2D712A9FC3B58673 +:10834000F10EA31BD3E570FFFB0CC9751C16E67478 +:108350005C2F9C5F5F7E7C83EED3C0BA203FF74CDE +:10836000357E18E9EBC37B3D61CC4FE6F9BD9AC879 +:108370008396F16939CECB7EBE9F96A5CC03D6F30A +:108380001A6A76025DBA6745385D588CE212FFE6DC +:108390004FE57BD07EF64E45C4DB14BF5857CC3436 +:1083A0008AFAD795E6B76893E90144B1F4A1DC688D +:1083B0002857092AB370BD801CFE01D713CC9FCD6E +:1083C0008EF66F4A61FE9C887727FAF33A1048CB05 +:1083D000A33289A594137CEEC9E3E7C861288FFB1B +:1083E000F3781C0AEBB5B84F8E7D80748ED4F0F80C +:1083F0000E00A8D1B9B480AF48AEAF46E7FA4AC97B +:1084000063AE935E9F083AFD41C805CE8FFA65F0D2 +:10841000F53C20FEF439F2C71D7F420AF2FB6F1DC6 +:1084200095C82FE30CF61F2A7DE16663FD8B118A48 +:10843000EF3C8CF5B6F6F67A8A174DE5F2AC073AC2 +:10844000EB29FE3343C48FEA9CF1A3BC00873318A9 +:10845000E0F2C766F238445980C72574A399E21D3B +:10846000415167168F87A4EAF5BC7DAA3E91BFFFF4 +:108470000A718CB240E638467960A83886F04F2BF6 +:1084800052FACD196FAD10F761E66A21D20BDE26E4 +:108490009EBF5A6EEA36FA3D15662BBF3F23E4A90C +:1084A000F45C46F7F7E13DED4F64FFF2B5CEF86BB3 +:1084B000A0CE59CF1179A4A5AEB86C8EBCB7C4D2EA +:1084C000E2BBA83F855F22EFC10CE7979C1770F9CC +:1084D0002523CC637E59B1EA897EE25E4D5BAE33E3 +:1084E0002FC3EDC70C172F70DBD9B659535E2B0085 +:1084F000B92B7A6A2FC99DA6F7E2D515D693CDEF91 +:108500007F1CFCA697E2F7DB989FE70DBBD6FFA97F +:108510006BF87DB81D052CC11F1AF49DA62CF19E89 +:1085200019D67AF46BA5FE53E23FFE9342FCBA8E55 +:10853000F4801FF5C4987E3B1B6627A80CAC8C32D8 +:10854000BCE2FFECBAD9B9B8EFCC625D19D79F9401 +:108550008B936BB95CE8ECF41CAC47D6EA147F2A29 +:1085600089C7729208876DF5458AE84A11FDC905E9 +:10857000F14EBF0F95DFE04FDD41C27A61CC70D480 +:108580002B851C1537461CFD583BF75BF1FA173F4E +:10859000A789113D222B81669503F3E523429E4A6C +:1085A0009624496F97353BF7B511218711573FB78F +:1085B0003C7506C4BE07CC3FCA13D0219A9C4679AD +:1085C0003174DF5D3FEA23BA94025D900E2719975C +:1085D000838A45B03E2A07D243CA1BFC8FF6E3A329 +:1085E000609C24233BE3C037603AE99455E3A453ED +:1085F00076D4491F49B79C3AD3D14ED24D7E876A73 +:10860000303A9537F5AE477CBE2A9DF6C97527E806 +:10861000541602796028E7494531E9DE2EC9F90E82 +:1086200021EFC8407F9A7F25E9E296FB922690636E +:10863000D43F05CCC42B2B6C6236C59123829ECAD5 +:108640003A29E799FD4BB7BCEB0CE41DFD363FBF63 +:10865000079E857E19C9FBBB2CDD2FF3F8C376D6A8 +:10866000642CF97D0C1D1889F7E0E5BD3CD0C32FC3 +:1086700091BE78CB79FFD303702869E74CB2D474EC +:1086800066AA746731497A77BC688FFE334BC3772B +:108690003CDAD1C968BF389D9410C78F6D07BB9A6B +:1086A000764EA98BF39E91E2CD0C11BF43FB9A3518 +:1086B000707D8F467C01CFD1B64DFC366F06BF96DC +:1086C000E0B58EA0FC8E13F08D93F75A7A9CF70AD2 +:1086D000C6D89CDF555D4EF919B5D6799FA15CDCF3 +:1086E000632917F75CCA5DF759CA3C7D0AFA41DF76 +:1086F0005BCB285E597633BFEF366A2D3396A48D57 +:1087000053160F1B4B00FEDDF820439CE98B803392 +:108710005E71FD828B493F7DEFE6D97999EE49EF95 +:108720006989184BC6E2FD143F95D93DE6B318BFE1 +:10873000A9DCCEC7AC6C345433D42FA7F7B5003CBA +:108740001ECC5333A8BDB966EF840718F2259E13DB +:10875000047A8E6B8FCF427FAFB23DA6925DD72D4C +:108760002388F2D2CDCF93C7AF2B27F8C7AD1B45D7 +:10877000A5DBBE94FDE5895FCC83F94777AA51D884 +:1087800009B2D1A77C16FA4F147381FEA69D54300E +:108790008F654C90FB51EF06621538AFD96EAA1465 +:1087A0000B6EE2F74D07A39B7B3E793FECDE95FB1A +:1087B00069DE76A3C071AF6F97E0D18C20CFDB94D8 +:1087C000F7F3527E74A7BC9F67AAB84FAFEAAEA476 +:1087D0003C31F7FD3C95F138E632713FEFE781F827 +:1087E00074A28B91767FB4AAFF7E5ED9AAEA20D2CA +:1087F0006F97DF56830057D90D0C36948C4D480087 +:108800005E6972869FE0AA039427EC3E4A7E98C474 +:10881000B3DC1F32964C45FAC467137D6C6E0F5261 +:108820007412F7BE460BF9AEB999F1FB3BDD8CBE75 +:108830000335BAD36EC510C33CA1F77709BD0FEB62 +:1088400062FEA234BDBE2B6EE5611E93D4C352EF0F +:10885000823A14F6CA54D10F9870B3733D5409FD8F +:108860005AEDD2AF55422F57B99EBBF939216164F9 +:10887000E4AFC4DBBD2E1607859E2E6625989FFAB1 +:10888000299B593CD7EC9717799FCCED1FB9E3731F +:1088900072FC2949E7FC729CE1E2408A6E537CC677 +:1088A000136106FA763D85C22EB8E209293FA681FA +:1088B000DF1189807F84FA35323F4EF72D220D2C4F +:1088C0006A22FC5BB91EDEE4E5FD54BFAD607EA408 +:1088D000BFBCEF5C94E3D66088E0FE951A6B453927 +:1088E000C89FCFCF4FF2853D184A9FDA5ABF3E2D21 +:1088F0000CC6B7607FA9572B934CF5A6C52BA45E79 +:10890000977ADCADB7B3DCFA7784F9253E3D9E5CFF +:108910006C0EA40F806FA6DF8FDA5821EC4639B7B2 +:108920009BF7AED445DED8C5732DF8E7966F3E1C95 +:1089300029A48FF8B0A45107F50B147A7F38B86AD0 +:1089400003EE7FB62CE0F59782CB78FD3285F647B3 +:108950006F88F74011D2071E915FFC5961958DEB2E +:1089600065A3899040593EF47DC0B6169ECF2BDB9F +:10897000697A94EEF34A3DE373E57FE821E7B9872E +:10898000BE927F3F42EA1F7D25CF8BE828DFFFDACA +:10899000E269749F9D767B5E7F33DD73F2755F477E +:1089A000F777DC7AC82FF4D0D5A88714D243CF2329 +:1089B0005F35C3798F5DEAA14490F17B56D39AE984 +:1089C000A3653EB3593561FC9F054D7A2EE34852AD +:1089D000AFFF0CDBC3787E3DC6A2D0DED3D0CCD0B7 +:1089E0007EF8E68B384903BFFF973FDFA47B391E33 +:1089F00093919CBAE5F8B594DC5AAFA19E7C3328DC +:108A0000F68F2CAAF078208F571406636F23FC95FD +:108A100011F62C0F658F4C1EE9CF7411AFAB44FCDF +:108A20002D3654BCCEED570C90676364F924B778AB +:108A3000ADDCB9788EF7334F14E3B1C3EDA7A4BD15 +:108A400095F659DA5D69B72BB32A5DE7BABD2FA059 +:108A50001DFBAC56A5FC62397FD712D6C0BFEFC153 +:108A6000E5D827F6CA9F552C0E7A81D46696C6EFB4 +:108A7000438B7BAD522E8383DC5392F22CDB4B79FC +:108A800076B71BB11CD72CA6F5F4E976CE8FF1DDB5 +:108A9000D73D1BC86047E5B8EA403936B386B0A772 +:108AA000D705AD4A7C7F4B6DB4299601CEDC108F83 +:108AB00073DCBB726B00E5FB1EA457DABA0F668944 +:108AC000753F610DD16B9EA0D703DB9DF48A0C43EB +:108AD0002FD9FEAFA6575CD02BCAE935D8770186CF +:108AE000A0D7BCA1E8B539B6ABB30AF368E26A74A3 +:108AF0002CE0B335A626BF06F57B9AD487F03B3031 +:108B00009B63B303784F624FF4D9030ABC3F379499 +:108B1000CDE5C7481EC67676B54ADFBB6546770306 +:108B2000C2B9A7BC96BE3D9AF23BCBF9FD948DE548 +:108B30008B8357A5D1614FCFB38EEF2FEC71DDDF63 +:108B400097A53FA438CE23B62DE1718292384BE031 +:108B5000797EFD12BE8EC097A5EF17062C5E1F2FE3 +:108B6000BE93F2DC940EFA6EDDA6727EDC26FD9CCE +:108B70001E979F23E30CC16A95E2413D7130E1D01D +:108B8000CE732EF7C7B2C4BE00DE533C2838D1B92D +:108B90000FD0843FE3DBEE7A2EFC1F8FCBCF91ED1D +:108BA000B561F69DB9F547290EF69DAC945F331A71 +:108BB000FD9A6D3195F028013C5037752DED5650DA +:108BC0006F977CAE597CFD77472E9FD4EFDFDC9901 +:108BD000C5EF8F768978653469CCC150504E1D8FB2 +:108BE000674BFADE91C5E9DD25F2ACA7F5C5E66471 +:108BF0000FD54EC457EB8E76CF0967687791586FC3 +:108C00005D1E7EEFB26BAC37B11EF0EC52B87EB495 +:108C10005FF2C8EFB1105FF72C3576A2FCEC3F5C39 +:108C2000B58552F7E2269D4BED37E36A5568703DF6 +:108C3000795988C79BC735442D7E1E29C74B3EC432 +:108C4000BFEF928C2C047A2C0985A8DDFE20E80762 +:108C5000A253BCD4914717E2FEBFA4D3E3AF2DCEFD +:108C6000C2BC8A48B9499F50CF2B6F66783F42CE2D +:108C7000B7BF5CCCA79B5B26217E4B93D9E9F74B12 +:108C8000E47C8F0733EB235DCE27E8FDD4FBBB1CD0 +:108C9000F3F91A9CF3F996C07C08B7BF7BFDE46931 +:108CA00083CFF7D420F379253F04DF9E39F59B2C41 +:108CB000DC8F466A603E947F9C2F3470BE9253B71F +:108CC0002BD969EBF3AA10B7DBCF483AEAF1D20B04 +:108CD000D3F4D0CB423E1E88EDF25F65E2BD908EAC +:108CE00000CAF11E25E11F87766F8A4ADF15EDDA8B +:108CF0007E32897EEF0316F76B72EBEC5918B7C81A +:108D00000FF1F8FC03DB67533F45EF5E8FEB51EB50 +:108D100061F4BDA28D183FC0F324B73F2DFC4290F3 +:108D2000FF83B8EE47CD6794C716E969FEC904D43E +:108D300013EB54F2E3186CFFF5E9FDF1991E8F185F +:108D40004F9CAB49BFA244F8E743F8175126CFCD5B +:108D5000A8CECFD964FC86D55A4C19D37FAE21E377 +:108D600094F23C439E63E4B0E4ACF4F3B531CC52EE +:108D7000F1FD5896588FC8555AE66C3C0718D71322 +:108D80009F8D729DB716BA913FD3CCCF47C6DC9763 +:108D90009B8A6B9E03DB149449A0DF8359F23E5FEC +:108DA000BC14FD86275CF51FB9EABAF8FEB7BE848D +:108DB000EB3958A8EEEF7FE584D0EF13F12519B712 +:108DC000FFDF59DC6FDB1ABB3D807AFDEEA0951703 +:108DD0008271C7A2CE3A93F615C5D8AF643EB3F000 +:108DE0003B135A3BDF7F6A21A67E15FE46A01DE994 +:108DF000FD757C1C37DF06E3AFE4A3E4EB97E527C2 +:108E0000984C53D3E83C50F891F690FE63B97E82BB +:108E1000CE4F61FB407CAD6631E26BA9DF50919F84 +:108E200055F5E6FA00F215F62EB8DFAB08F1730738 +:108E30001F3B1AC073E2C1F8AA8BEFE6EB311E3F6D +:108E400062DD03F2A6EB33F1A9DF9EABBD8A39BC2C +:108E50001DEFA9B93D807E01D871F20BEC2695EE8D +:108E60008F8EC09ED3BECADFB56F039EA376E58A00 +:108E70007BF7A0FFEFAF447B64925CCC3CD13727FB +:108E800027CD6E7479929128B54F36E27EC7BE8F9A +:108E9000EB8907626E3D91F05F05E591AC5CA247FE +:108EA0004FF5BC1726E0BAD66DDA37C8F9DFDC1209 +:108EB000E8A07D5D284979835D0BD6D07787A45ED5 +:108EC00019D06EC0F7499DE74DBF7FFAD50ACCD3C4 +:108ED0007A7BE927D9988FF36BFD4436C2FBFECD30 +:108EE000FF968D79836FDFACD1FDF72B715CD8F7DE +:108EF0007EABE52FD3F13B2FDF11FAF4D59075034C +:108F0000AE0BB68EE7935C93D03078CDC787FF5613 +:108F1000ECCD422591AAAFEACD77D4255CAB7CFCA1 +:108F20001C6FC54307BD6598AFBB3797E259EFEBA0 +:108F30007C5DBCFF68C54E8CCF3F22ECCBABA1D88B +:108F40000694078407F9F4EB033E919FD8E7E1F616 +:108F5000D29A8FE72B71213F6EB87EFC4C168DBBE9 +:108F6000F44E8DFCAC4540EB75A0A2E34D2B281EC2 +:108F7000E4867BE9DBBD3F2E05B8966E52E877426A +:108F8000B0FDCDB07F8CAFDB487151375E8B6C6725 +:108F9000DECB55BD0B28DEBA78AD42767CF1768506 +:108FA000D6B93B0F770933B7CCACCC908F7B80E739 +:108FB000092E73C55FDDFED5DE90F0ABA6B3193C7C +:108FC0005E34F1D689E6F0E769EF839F8F49A91FE8 +:108FD000B6F8A93CD66250794388CBF58A270FFEB4 +:108FE000987488DE371DE56EFFE177B32E87576BE7 +:108FF00022DCBF3F6FE7276D8FC3EBA92C9693242C +:10900000FD65919E5928E8FF35E6374300E79DC28C +:109010008F9F7A0AEA69F89DEC56689FB706562C2E +:10902000E6DD2D447C27E3F8DCAF5F88BF5B3204CC +:10903000DECF87DCDFA5F9EBF01EACDF2A8DDF3752 +:10904000703F97EBE106219F6D4FDF3D0FE5E5F89F +:109050006D0A7D5F7AF9DE77280F75E9933E43E369 +:1090600041C823A8DFA47CBAE50FF6C55E5CF729EA +:10907000393BF05DA287940358371191771551EB76 +:1090800032C8DB30F9DDC73D4747E13A77CBD3F152 +:1090900041F62D6F86789EC212D39A87719AA52CBD +:1090A00046F95DC0E757FE9678C8EF78D6F2981774 +:1090B000E6655AF5B04EF77FCEF743AD8F8EB90314 +:1090C000FDE8293FD52987BAF6B1B2A9E8EFD5FE68 +:1090D000284446B5F685F6AFE3BAFEDA4EF13D25F3 +:1090E0006147E5EF83B8E974DEF333B5B347402F4A +:1090F000379DCEFB5C77E5C175FF18F35B6B772B73 +:10910000E49FD5BEE87E6F733DF7C4BEC751DF2E26 +:109110007FF3F630E6557FA07717211FF6EDDE10BE +:10912000C6BCC7F7753B8C74FD20A165FCEEC84535 +:10913000D98AFCFEB4237F9575DA84F71FEFF71800 +:109140009837B27AAF8FE7453EB79CF800759E0F0F +:10915000F968E6FCD5E50FDC5964F27C35671EEB57 +:109160006E0F9D7B5E0BFB329C66B0BCBE549E6056 +:10917000EFD0F98EABC5FED19DD728F345DDEB7A54 +:1091800076B6735D035D689F68033C94FE23F21816 +:10919000DB1EF4D9789FFD83378A77E279F7B1DD5A +:1091A0003F0DE33DF3D439A5C8CF3BD63B66C8EFAE +:1091B000EE1E17FA40D607CB6FDD077609CF4B5668 +:1091C000BEEE23FF66E52FD4AC8918C7D8E921B8D5 +:1091D0001E7FEDD9A249505FF1B0A7603E4787F2EC +:1091E0005825BF52F9C5823FCB1FF911E5BBA6F246 +:1091F0008C059F563C7CD08B72E2A6E79CDE835E9A +:10920000FEBD0917BF7ADF9987FB9BB6073FF3A224 +:10921000BEF9E0198515570EECDF74FF4F791EB9C2 +:10922000E0D7E079E3C9AF3F358DDA19B82F1B8C51 +:109230007F635076CE24F9FEE7A760DEA6377C94E4 +:10924000B7DEF4CFD7939CFF4E6F26395F79DF8668 +:1092500022F42B9A3C769141257FDEB4E30692BF3F +:1092600065BFB8A1487C6FB484EB03BB04F15ABA64 +:10927000FD9B84D7D52C4EF2D7749F16C338CCA74C +:109280003A6B7838033F0F67737DFCBB5D3EFA98FD +:10929000F1EF303E8BFEDACB9AF8DD23673E0D59B5 +:1092A0001EA87F2AE260DFCB56C53A03AB5E84F886 +:1092B000F23FAB776FA4FB7D1F56F07BF040075B5E +:1092C000D04B41BBA6FD626E31E70B33D15FA77E69 +:1092D000A03AE7E0736CDFE7B102931DFD445E2F17 +:1092E0009F7FAD981FE00EE2B9C0EF8AF8F7C798EC +:1092F0002BEFF9DA47AF998F79CE7F14FA20B5DEDC +:10930000778B3C71B1DEFF7084EB11CC8BA63CF601 +:109310003E4FB2D8910FED73C4CFFBF37D3D621D7C +:109320003BDF035C94AF9CA2E7330AF9BF576FF5AC +:1093300039E27FAB1F15F71ADCF941AEFCE5656237 +:10934000DDBBF9E7D603875C7A806D2F1C51DC7A90 +:10935000A5274179E7B04EC96F5BB9CF43F9BE1F6E +:109360003D74E89797835C7FD42BD7A7539FA6D6ED +:1093700027D019E9D6B4FF4C96697D7E84DFC7CD2E +:10938000B43EE179C6F51962A4BFFE66FA344567BA +:10939000E77A5C36883E3D96EDBE17303107EF8B9D +:1093A0007DF88315A3293FCD4557A93FDD7AB13319 +:1093B000DB1CE45E05F76BFAEFB970FA49B95CFEA5 +:1093C0004FAB689E94BC4AB994F669903C7D371DBA +:1093D000DDEFF7A3FE291C982F61CF6635F83B23FC +:1093E0006D5E5683F1135B0D46515EDDE717184144 +:1093F0004479BEE95946DF53B9225C99FA9D073C8E +:10940000FFB9E979FE1C2F7463FDB39FF07A748E67 +:10941000DA9CE97B49E561F1DD22F471609C7961B8 +:1094200093EAED5A4CE479F6D239509B22D6516E2C +:1094300098D69147ECBBF15E18E6F7CE13E344B340 +:10944000D44F4CF0896A6F29381FEFC146A7AAD7BD +:109450008F81FAACB079BE0EFC8A9EA33E5205F510 +:1094600039E14A5E3F439D8ADFA3D8C3AACEAFC786 +:10947000DF135015560BF3E8A5DE04CEB905D6AFC1 +:109480001FE4BB3DCCAC5C90B32C1FB303B5FD70A7 +:109490006679A19E47F89B18C768CBF5531E67BB3A +:1094A00087F71BE978729C5ADD9C43F7D6AA01D74F +:1094B000CAFE796A758EFFC49097F2AFDA73F97CB1 +:1094C000ED305F1BB593F41B5929F37CB52CCE17F7 +:1094D0002D476D7E18CAFF15E6FAFCEB61999FCF08 +:1094E000E313BF7FBA78178FA79E1845BF9FA09D33 +:1094F000FCD53FC0F3135764D139D71B412E1F97BA +:10950000E674794E837AAD7FD4F5285C6F280FDD41 +:1095100080E5F89C7863988F97C4F12EBF52E3E3FF +:10952000859AB3917F8AC5FD610598B710E8D16629 +:1095300031D33B06978A336F56D36A4F2469DE6C6A +:10954000C7BCAC1CEC0FACA74BCFE2EB09F6B66482 +:109550008F5EADE3F5C64455DB5193E0684238A613 +:10956000F81215B8FFBADC9718CBE5CCB9DF3F8EFF +:10957000E39EC1F51D7E0F779A58A7D39E5C21F319 +:1095800049493FAD7E459C27F4713F56E6F12118CD +:1095900088CF6AC411DA3D728CC7776A9F73E64937 +:1095A0009CF5228FB79DE5D24BE7883CA27386D904 +:1095B000C7AE0F0B7D5FCA4ABF4C5E689F62757273 +:1095C0007EF0DF6B99AF334BFCFE049D73AD110150 +:1095D000A5932F56E5605CD81BE6F653E6597B4D04 +:1095E0008DF2521E75E93B29AF938E1857D1EF17B4 +:1095F0001E61DFA2BC2A39AEC1E998CABB7C9FE7D5 +:109600005D4E395A7337FE2E8EE7B08725CCFE7C2F +:10961000C3934778BEE1F4C3FCBEE0E3B86FC6383D +:1096200059C4793F25600699994697AC9A3C47BD45 +:109630003D20F829F216A7F257F43B5CE9E34C35DC +:10964000F8EF60E6D45539FAB3179DF986B502BE36 +:1096500068C89F4078A61F71F2F56CE1FFCD28B075 +:10966000115356F796EB7DA881CE81CE1EE61CE8FD +:1096700069377F07D2D191B739854DBE1B7F076807 +:10968000001DDF77D251CA01D053433D9A6B39E9AF +:1096900099DFE0A46761CC49CFE24627DD4AE24E7C +:1096A0007A95359DE6785FD15CEBA88F5E77B6A39F +:1096B0007D2518A0F4FA98CEBF73B41FDB7DA1A35B +:1096C0003EBEE77247FB0989C58EF7A7EF5D3E22D4 +:1096D000FE4FEA5DE36827F97FC6937FEF184FF2EC +:1096E0005FDE63AF65DC3F898A3CD7C1F8AFA9CDA7 +:1096F0007330AF279AB4E9F79FBEAA1CFC6758F8ED +:10970000235F729D97087D8FF9CAE8A7FDDE13EAF3 +:1097100044BF34176403F5ACDBBEE71E789EE2EC71 +:10972000EE3C859B3493CE233E53ADB3285F88F542 +:10973000527CBB5D15DF3F99ED27BB7C8BAA7E2B4E +:10974000FDFCA93887EF2F8A73C4F93BD83FB47763 +:109750006559CC263BA8B2FEDFE1047A87F319CF26 +:10976000EBB16FD9585F8EF6ED688D990BFA06EB69 +:10977000E7F6EB7BB02F5371BF00FABC2A07F0BBB2 +:109780005C057D0E535D6AD8731513EFCF311BEF67 +:1097900077809DA37BD0B9AC40593311B738297B72 +:1097A000627E01427068F9E9748FE664D304FAEED0 +:1097B000E0C950EA7B8CFC77831B787EC06562BF72 +:1097C0007172C9186AF7FA95F823BA8CFD0C210753 +:1097D0003FE2752FDF7F0C17276BDA794736E6CB30 +:1097E000BC5EC3F30FE4F37A41A7FA1C9E77B07A0C +:1097F0004996CDEF637AE85C1AF747F83B82D726A3 +:10980000F8FAC53AC68936D5DFEEBC677FB8D9C647 +:10981000F8E3EA030B1CDF67B9F4551E8FBBF4FFB6 +:1098200032871F76510EBFBF7E9198F71228F03B0A +:109830004897001F72B17C7EE63C5C0FF03CA9406B +:10984000FD1B87C1F502BA2F88577A9088FFC6A200 +:10985000AF3C06A05F99C3E7BF98C53C2817BFBCC3 +:10986000725536B64B8D27C701E0D0EF7935D7F664 +:109870001481DC9C3857213B0EF3F9F1796C61D9E6 +:10988000060CA5CAF97EC9E21FBF027275218BD2F0 +:10989000B8727C6605E9FB8E520FAEB9262B990F84 +:1098A000E3AD79DD47F1E2DFAF3FF1CF37025CBFD7 +:1098B0005EFEA7C7F01E008B1FAD403B77598FC6D9 +:1098C0004CE0FBCA90B50CE586D58DEC9EF69C1F4E +:1098D00004683DACB993C7D7D63C389EEE57AFC9A4 +:1098E000767EBF53CACB35425ED6DC3F86EE63CB75 +:1098F000DFBF708F8FBFCB8CDF856813BF53BCA1D8 +:1099000080E7F1EA2CFE9D1CF4830DB50AF9B82D11 +:109910008FFFBECF887F6F05E6B7D11F621C8E9781 +:10992000849C361EC89F2AFCB14D38FE1BCFECAB81 +:1099300040FDF593090F8CA57DCDB491D183093BF2 +:10994000141578821DA27DC3EF5930EACBB06F7831 +:1099500058F85337A916F9F53709FFFE3395FBF18F +:109960009A1A8DE850EF3DA06521BDC2E82C4BBD91 +:10997000003E5C1893E4E5EFE5C2BEE674A1371241 +:10998000B7BE797E3B8F8338FD34112F927E590C00 +:10999000FEA2DEFE941DD008FF1E67DCF1ACA44AD7 +:1099A000FBC7AFEA87EDCFF96AFAB94F891F403E8E +:1099B000F4D6707DDB9B0CF2FB15608A78BE97D3E2 +:1099C0003F738FF36C0EF7CB0EA30F0CE37CD7E045 +:1099D0006516E8BF6C7E1FCED66AA94E2999E0BEF7 +:1099E0005985BC6EE7405994CFED8357395EE30744 +:1099F0003DFBE2AD473776CEC4EF3670FA621D7F8D +:109A00009792F9B3B8DF21F5E073A7F1EFB48AEFCD +:109A1000C44C137168377CD360BD91B195EB55F49C +:109A20004FFEF8CFF43D887D79E6CFCF417FFE052C +:109A30008DEE2F07F4A3DEDC0C783E8E7A753C7E2B +:109A4000EF8DDB11FF930A7D57C36FF27D67C03046 +:109A5000A6501C3BCEB230EEFDF1C36368DF7950F7 +:109A6000D0A7343BF61ED27995B673943186FCDFCD +:109A7000F7730A07D2B737C97F9F6C92CE3AF5BC0D +:109A80007EFA4A3856F74CA5C3E06B7BF2A99C805E +:109A9000FB7A78B43AC9F13CFE645BC63CFCD5C5A0 +:109AA00027FE88DFD761FFC2BF5B34E9C0D465A859 +:109AB0000F91C5783FF107A74EA7F19851C9FD67EF +:109AC0009DE91EDA572654FC5EEF6A1FD7DFC74FA9 +:109AD00069D44E8E3BE9C9599A01F2F95F81FC4A7B +:109AE0000D008000000000001F8B08000000000037 +:109AF000000BB5597B7054D519FFEE631FC92ED9E1 +:109B00009B5D084168BC24212110D2650910A2D6B2 +:109B10006B40C01061019FAD5317A84049B2AB58CC +:109B2000A93376C69B045B2AB69351A7A52DED5C9D +:109B3000A83A3E885D2048E86C329B8090203889A6 +:109B4000A005DBB18176A855C2AE6905DB694BBFC4 +:109B5000EF9C7BDD47A0FA4F9349CE9ED777BEC7D7 +:109B6000EF7B9CB395F1F63E180F901373A8FA544F +:109B70006C5F0010583FC7000120D2B304846A8094 +:109B8000443EF8059CEFC84D7E00D84F763BD4DDAF +:109B9000389FA3B483B712C7EDF06010DB0A006DE5 +:109BA0009F3B357E957E6E257A3F05C0716729689B +:109BB00006CDCBED708B3B35DFEB1907301760AA74 +:109BC000020013E89CB8E8463E92D3007633BE52BA +:109BD0007C023BD7E2B3C2D0053A3F79E189F18CF0 +:109BE0002F65B74A7C703E2156AEBE48FB158DC925 +:109BF00091A3A87E5A9FCD57A40A0CF000FCB8157B +:109C0000F7D402FD685083E3B9A9BE733A9E538C22 +:109C10009F6EA06EC1B64553D2FBA0D37A6BFFFCFA +:109C2000F6C26D5B715E96419702002E6CC7794952 +:109C30004E95C92923BD0901AE073FEAC9E5E4F302 +:109C40009FAF77225BD477F3757E8FEEAD47F9FC3B +:109C5000C7447F1B92807F5D05980710A693B1FFD4 +:109C60001D217EE15609E0D3785F958A3C351DFBC6 +:109C70006D911DDB4631F69359387FD011BA4DC135 +:109C8000730FFE41843CD4C347AFE4180DA897E995 +:109C900087761568EEB1F47E70A6F5D9C964F743EE +:109CA000828A1A87842D59447C86637FB16BD82EB3 +:109CB000E93A671FC6F6F74A6819D1ADE96A59480B +:109CC0007A5C00ED6D0AB633450845B18D16223D2C +:109CD000A4337ABA6C770BEA1D92A11B57CD027898 +:109CE0004C11989D2D3BC49EC4B972809E279DAC9B +:109CF000B5C6B35B1DFA2603D23C60E3786B8523BF +:109D00009349EF077AEF2F51916EC2909712BE667A +:109D1000BEE77C504BC35F441199DE23742EB6FF1F +:109D200056426B89EFC6DEF3F63C942FF2E76811DA +:109D3000E0924141FB9632819410978308C906193D +:109D4000342687AC7AD2F1DCE7E1743EA7FF192A0A +:109D5000DF97D6979376D243E443C47B25B3FF566F +:109D60000FDAF3B5F7BA66AC7133FEC1837A397096 +:109D7000D66190DF61FFBE28AE6B79F772D530CE29 +:109D80005FEE6EBC91F4798F62B3FCA12E97FC6EEE +:109D90002FFA03F25B69FA6D25F92DB25249FE5094 +:109DA0004DFD0A46AFC33E58CFFCF48008E4A7E857 +:109DB0000FCC3FD01F941781D6A37FB0FDE5CCEF29 +:109DC0003B06458DFA7A3CD798C6FA75ABA9DF31C8 +:109DD000B848617E2FA2EA03E4BFF13E46270A306D +:109DE0008D4C2B40305A99EEC7794C2FBDA67E4E34 +:109DF000A34F51EB92A40C3FC99344CBAF78BF4D16 +:109E000060F3EFB7DFB1ED79F41B505C2214006C06 +:109E100056381EA110FB88CF479D6C0F6C7EB37621 +:109E2000C51E946FF34989CDCFD31E5E883E05359C +:109E30004BDB0F535B1B8C2EB4117F3B2450D12E78 +:109E400073B1D5E600DC7CDFE0611B77E79964DF66 +:109E5000CEBE3B66CA84F3B30EC841163AFF99FCE6 +:109E6000E055946F4B0FEA15C6E20FD96578BB1E1B +:109E70003E13C2705E09F2BC4FB97FA99C83FEB24B +:109E800080CBF91BE5DE6D3A32E6CFD7F611EE96C0 +:109E90007843FB086789A17F16206CE1C0E9F3795C +:109EA00021B477A75D9BA9B0163646DD63E91B2672 +:109EB0001EAA1DF0B0E55F32F23BB2C3B78BFC6B5C +:109EC000A453D20A50E7A708EF84635D1B2C443DDE +:109ED0003EC4D5061B3BA5738E2A80F51AC0F71029 +:109EE0008F0F1DD9D400D47FDE767E783A5F7395CC +:109EF000D6E1DFE368EF321DFC71A41F3E2DF90DA2 +:109F000095C6E5F3C3A60DAE4EA5FF0F8B8493A6B1 +:109F100098003FC77EA4CB969AC7BF2678E613A9C0 +:109F20008A5A39451FD73DFE87492B8FA49D774A12 +:109F30001937FEC24CFC500225572586077F9CF03E +:109F4000FBAEE4DF8DC33619FA1DC8CF6B22D70BE9 +:109F5000C647E64F579E2C5C790455F2A8573BE65E +:109F600041798F79CCFC51C7E34EB2433018FE5F84 +:109F7000C6788EFDDA0FD55D3095E9E574E13C2EAB +:109F800027E1A75606765EEDE9123FD9BD06F543F7 +:109F900072AD8F098681EB37929E10DA6070F9649A +:109FA000FCBD5A4CF4DA255AB769A7003E5CD7F8D5 +:109FB0007296FC3B868E4EC2B6399A391E31F51226 +:109FC000C9D2CB3EFAB060AC7EAE58FA298222D21A +:109FD0000F480F78082FD08F4A98341627965EC8FE +:109FE000BD481F1F537CC1F5EF98F4F1C7BD067142 +:109FF000F127537E6F3EC74BD894BBC99098DCEBDA +:10A000004C7CC0331C1F4EFC25B923C0D735EF1440 +:10A010008CF8D4B1F26DDC635B63275B80610F2247 +:10A02000C037EECCC4D72653FE4D59F2874342C603 +:10A03000F9E8A7EE3568A775267EAFC74FA38DDB7D +:10A04000AF11F1A2ABFF3FFEB2ED32231FEDE2A252 +:10A050000F3023C32E4B7D5FCA2EA0E5B2B8B6D910 +:10A06000C9ED307A6486072A5338C8DEBF18E31872 +:10A07000601C5BB243606DE760DFB69B50EE40B79B +:10A08000A434E0FEC4609D6B16C5B313B29F482490 +:10A090006273B6EB18E7F6F797AE56916E604864B8 +:10A0A0007E30E764C0C84179022703AE92710C0488 +:10A0B0003ED203EE63F93371A2F45425D1E95F5423 +:10A0C0004D69BBE544C045F97E3F4A4638124EFE15 +:10A0D000FD6D3A77CE803CCF81F3DF2F9498BF2D72 +:10A0E000F9D99A971C48B72E5F6271FFE8E0E6BB8A +:10A0F000981D4E880A8D5F3A21B2754DBF940C11A0 +:10A10000FB4BF6DA587C89A0DD04C6AF8D9D1FE9B4 +:10A110009EE65BE74ED97FAD89D340BEFA5C03D59E +:10A1200075935C7ECA634BBE626379EFE20DAE5FEE +:10A13000533D53A6ED5AAC209F177FFB288B4B89CC +:10A140000E010A91F0D1C2C3AFEB28DFC53786EC10 +:10A1500080EDC2CE213BE5D9B5965F6FE3F8B0F054 +:10A16000B4212EAEB17F15E3E9602EC4911EC8ED77 +:10A1700076B24BF390D51FB6537E0E9A7550F88584 +:10A1800073ACBFA94B60F26D7A413054FC78B8FBD8 +:10A19000A09DF808EF1160E2549ADFB598D63542D9 +:10A1A000F4FB14E7B3E3C5861D99FD6F9B38FCF6FD +:10A1B00017E0F0897C333E544005E1F0F26D410F29 +:10A1C000E1FEF250AEAB12CFBF3C20313CFC0F3C65 +:10A1D000B2BC7682EA3034E8685CD4487E6BDDA598 +:10A1E00013A376AA1317C73E617A6B88F52E227DDA +:10A1F000DC09A12692EFCE984B89A3BC0DC3DCEFFE +:10A20000EA630EC310683EBA95E44CF438D8B8FE41 +:10A21000BAC0EA0B2BFE6C30EDBAC1B4C3060CAC6D +:10A220003E0C694DFD3C4FC1CE4CBB2C9B9EA99F63 +:10A230007AE0F1A23ECAE345C2169549FF89590268 +:10A24000B4537F928BD9433FC4CF0D933EF19CA66C +:10A250003D9974C25979ED47F913987F8ECA3CFF36 +:10A260008D9E96AA29AE5C2FEF67DBA3C38A0BA64F +:10A270003D1A923C3ED59B79B43FDE5A09C529FD73 +:10A2800064DBA35F2DF1842AAF7FDEDB66BD6CF556 +:10A2900057A0A3501D1655B8FE070627ECA2BA6EAC +:10A2A000D30249A77A608297D7BF4DFF59BD22805C +:10A2B0002ABB28F66DD983F31FAF899691DDF07E16 +:10A2C000F026897C6CCABA6766E3FE8F3A6C7E8A98 +:10A2D00027A0ED2AA33AE90785CF3504C84FF7D860 +:10A2E000FC741FB85423E9143F23581F031B77182D +:10A2F000547F44BAFEC6EF0784136C8331E176C203 +:10A3000009D6DB43F978FE4A4CE5E3510F2BBB300D +:10A31000BF23F9958B3EB153BCC4BAFB14CD67D7AC +:10A32000DD03A5259EB5D4CAEA44AFFBFA7577F8DC +:10A33000335EE759E361F44FD26B3826B0FB66AA6F +:10A34000CE9B28509D97E83E78C4CBE243FE6C320A +:10A350009368EAA7B32FE7F3BAA398E417B632BF1E +:10A3600008DB8CAD5E1C0FBF22B0FC0287D048F327 +:10A37000312EBE93CBF47DE90DC1705000C3BA827B +:10A38000E2F97A0E05B8B4367A9EEAE5CB1D4E5650 +:10A390004F6E40FB3C8EF85E6FE631EA7F0FEB9A22 +:10A3A000166865F79A56D8CADAF5F8F7B5C0D878BE +:10A3B00070A9ABCD4EB8B0EA10365E3C368E349BF9 +:10A3C000386FCEC275364E277833718AF26C67F7D4 +:10A3D000FD014921793AFBFEF1AB1B481F581F17BD +:10A3E00093DF9AF506EA89D93D31E436489F1F99F3 +:10A3F00078BC48F73774F5961A89E9475CC0DB9951 +:10A400003D078BC9CE89EE2B45218CBFAFF51C9C37 +:10A410004138414198DE1B5FC675697C35475DE474 +:10A42000F49FF7912F9E27DE93FC946F90AF32FB41 +:10A43000F8145F07E4E13CFF35FC4810FA98FD444E +:10A44000E14846DD1E3924058D34FF42791EA4F80B +:10A4500056EE35EB66395940F970A65765FD9618EA +:10A46000B7B7D8CD5B3CFF1EFE0E6263E78F99AF96 +:10A47000D39B68FEF25417901FC2677A03F5B71496 +:10A480004BF034F6B7BCB3A91CD2CE0781DF6B23E7 +:10A49000B66401BB370E898CBFC8D06841A99BE266 +:10A4A000DCAE4594D79699F1E268B16B23E15AA7E7 +:10A4B000732702D8493EDCBF9FF22EF21B59C0F72A +:10A4C000B79AB8EA7CA7DE358BECD53D61B684221D +:10A4D000D5E473BC2FF106EBBC7353F78FEBD59328 +:10A4E00069F71F4E1FE5247FDA7FC6613408745F69 +:10A4F000BDF2DE3748DE01AC3B907E4BB743F790B0 +:10A50000BDDECF3128EF4328F455F2EB2D3D1BCAB9 +:10A5100029FF81D0CAECF14CD743895FE0BEE6B396 +:10A520002E8AE4D0DCFD6E01CBB307E63E47750B07 +:10A53000D629CBA86ED91FB3B1BA2570B29AE16DF6 +:10A54000FF896A5F095D9CC0EF22BACD037290F467 +:10A55000D13C50FD5603D51B27EB58DD229CACF6B1 +:10A56000511C9A43F754AA5B064A59DF92E77E2FA3 +:10A57000AF5312BD39ECBD4080628E1728CDC04B61 +:10A5800053E79B2CBF3775495A3A6EAC7DCD5E9927 +:10A59000D179C4C24B54D0181EF6F2B6A96B7F0114 +:10A5A000C9D1688B32FBB6ECB1F1F90EDE02B4B35F +:10A5B000FDBA5F64F67C8B86D00EF576630A208B3D +:10A5C000C7CDFAFDF8D9D08D14078FDF162AA776EC +:10A5D000D49B190F75A8637C83B08AD97DA493D7C7 +:10A5E00053D9764C7AF9FB4B9E0F1E0C5E63FE8F9F +:10A5F000663CACB7F3771CAAC326615C7BDBCCD787 +:10A60000CB317E29185F5E35FDE51460BD2150CB4E +:10A61000EF8D51F265B4D7EA3B04A305EDBFFA4EC6 +:10A620001BAB27A086D7D941FCA5B855BE43CE8821 +:10A630005B386323BF5BBD34339EDD6DD641777FCE +:10A64000411DB4D36BD6416550C6EB71B78BDE09A3 +:10A650003FEDB72912AB3B8C52A27FBD3AE828C62A +:10A660003115E3583FC6316A312FBDE4BDC67B507A +:10A67000F67E2B2FB554FC8EBDDF1CEF3DFB7A3EE2 +:10A680008B9B39504C40FC177283FA6B564C5EB36F +:10A69000F6B7C02A66B756B82B037796FD46A8EEE4 +:10A6A000AE1C6BBFB8A9FFF074C739D24F584ADA55 +:10A6B000F10E0D3F5CFA6C9070E37406E393F1BC0D +:10A6C0000F44350327E1AE4780F2484B05AFCB4638 +:10A6D0006EE7F90BF92E72A4C5FB9149BCBEDA7284 +:10A6E0008FC0DE597B2B7EC7F27A737CD04EF1A8E7 +:10A6F000AC73CD53E4AF08BCD3F45EB3DCCC7B2B9E +:10A700009C3CCF2DB7EE6B96FC267E5AC0ABF3B8BF +:10A710003C9EB5B49EF2E07233EFADA8C9B47F3968 +:10A720000C2E9E8C7CDCAB09AC7E5AA965CEAFBAF0 +:10A730006FF69B64A62F8B9B2BDED079B26B627079 +:10A74000F41E7A1F3D5EF19722D247D8C4BBBF5C8E +:10A75000ED1AA6F7D6B794D96DB827E2CAAB521056 +:10A76000BF1F9BFA6EF5843E62FB8DF3EBE9DDD0F3 +:10A77000DA9F449949CF965FF927C29C47DCE97676 +:10A78000E3FBAD758F7915D61EB71953282E40A55A +:10A79000EF9AF7BEECF8DB5271AC8AEC70BC77A094 +:10A7A000CA9E66AF8B9B43E52C7F741F2E50DDE95C +:10A7B000F8124D7CC9AC158455665ECCC4DB45C22D +:10A7C0001BD977EFE1E5DF205C74AE1E2FA8697915 +:10A7D000F3C0A9BC6969744762125B8FF7A1B2BB71 +:10A7E000C7A5F3F914E37324CAE9A1D175760F7AEA +:10A7F00063F6BCA7B9197491FAA56B5F7A9AFC034A +:10A80000DAD87A0BA739365D9B8CF238BAB0622C55 +:10A810004EC91DB503A3A3F7388C1759BDCFE34C20 +:10A82000E29CC2EA5D802940387CC3C499DFC7E35B +:10A83000D87C0C4E84C7051095C83FE6830C0F509A +:10A840005F46C7C6F6663024F297F972BC57A86215 +:10A85000E3BA8C38BC0586D9F8ADF4E483FB6E030B +:10A8600055A6FE42D0DB2861DD148D2FA370132F77 +:10A8700090F32F20EE28E45CCB6E29BDC870C1C2D6 +:10A88000212EC66286BD635B7CCF1338DFF3357043 +:10A89000521CBDDFC7E38ADFC5E54C8E007BCFB21B +:10A8A000F8BA4986A512F27F8B0CCE5C5CBFF788A4 +:10A8B000C8FCB567583528DEF97DE6BEBFE2BEA903 +:10A8C000AC3481070229396B711FBDA3CD97F10606 +:10A8D000CCF413BFA6BC0DF4B8C5EAF3E43789DEA7 +:10A8E000C29883D531A2539708F7AB7C3CEFD1F7E0 +:10A8F0001C7948A7B65D8033F4BD450997CFA25FA8 +:10A900008B21C913A0F53C7ED113F0192FFFFE83D4 +:10A91000F6012C52483F42BC40BCEAFAF27A4C1491 +:10A9200000E33B6F5DF2D213D5A9EF81FCB1636701 +:10A9300004CC5382A6B1BCE477BAE35417A3D52F55 +:10A94000A6D7CFEB7D6BBFE543F9045561FA8110C3 +:10A95000A814EF27C24E85F28948EB7CDC4C1FA27D +:10A960009DEE35F1F57E6E5E157D6FF4B2B14A2530 +:10A970003CDF37DEE927BD079C457308B7E59E102D +:10A98000A3FBBEB0671A23221B7383E35278768140 +:10A9900056437AC62A81E1F37127A7772587B72E18 +:10A9A0000CCF4EE4673BE2DEE925FE80E15637DF5F +:10A9B00037F50F728C363CEFBB529081EF8AE87707 +:10A9C000123D280E9D998FAD5CA7A90FBBA9244706 +:10A9D000395C2939B2CF21B96EB6E41253728D3D7C +:10A9E00047B7CDA0F829AA6DC302936FBB0FE598B6 +:10A9F000ED30BE42EF0D5F7718D3880F4B2E5434E5 +:10AA0000FB5E4931F565C9A9901D282F686807CB01 +:10AA10008EA8AFEDB99972DAC09447457BCC1A2B5A +:10AA2000C77F016E376664C01C0000000000000094 +:10AA30001F8B080000000000000B2B106060F85115 +:10AA40008FC03BB950F9E8389913959FCE8D5F3D83 +:10AA5000212CC380604FE16060E86686604F28FE6D +:10AA6000C6C4C0F0108AD73043F02116841E697620 +:10AA700006062520D604620376FC76A9B1628ACD4B +:10AA8000916760705446F02F493130F04903FD253D +:10AA90004D99BF46F1D0C0B34C50F99F7551F95F45 +:10AAA000F41918544D91F8BAA4993F0DA8773A10AB +:10AAB00003007D8679E568030000000000000000C7 +:10AAC0001F8B080000000000000BCD7D0B7854D5D3 +:10AAD000B5F03E33E79C7964667212263084002715 +:10AAE0000F20F5061C428080B13D3CA595DB8E40D1 +:10AAF0006DB05E1D8242541E41ADA4967B73200F43 +:10AB000002048835D7A2A53AE00B1FB4918272AD3A +:10AB1000BD1D15BDE8ED6DD3FBDBDFC7451B1E2258 +:10AB2000C5577CDBFF6AFDD75A7B9FCC392713C002 +:10AB3000B6F7FBFFF4B39B7DF66BEDF5DA6BAFBDBB +:10AB4000F61E9F3F8FC9A319FB02FFBEC6588B8715 +:10AB5000315690491993F55E3FA6CCFCA2D491677B +:10AB60005F78CF25FFD93867DE14FDDECCD850C61C +:10AB7000BE27CAE0CFC0FC6C91B1E0B15216575964 +:10AB8000BA3CD3CF6CC6F3BA47625F48F8D5596E6A +:10AB90008DD3E88F4C60B98C7D12E0A939138AAA55 +:10ABA000207D2D906A2E66EC73962C6593B17EC342 +:10ABB000D4C4784ACFC7B45962B5DDA12C70B00DAA +:10ABC0000CEB373725269D5032DFBD723C8DFDC220 +:10ABD0007FF17B7548434CC6F96C92ACE9F518DE01 +:10ABE0002863FE687CD266C85502BC085FC293A881 +:10ABF000E4E31B2C11666C2AD3A9FF27C3535E4ADA +:10AC000042FDF7E36ADC07A5D7871F65AC84B1ADC9 +:10AC1000939F8D2501AE1CB99B69988698D15D8163 +:10AC2000EDFF91B1298C7D84F8D43370CD601E1A6C +:10AC30002703BF134F3D8CD3B943D1B7D7205EFE56 +:10AC4000C31BBF974AD3B5389FAD93877A36C31CD1 +:10AC50003635E935656318DBD8A44F9221DDA4F4BD +:10AC6000D42EC5FACF2934DFD6A672FAFEE4E4B1B9 +:10AC7000B9BD15088A73DCD682606D8AE0EC4C6E33 +:10AC80008079ADED7DE482CDD06E764117E5D52398 +:10AC90008F5DE0D3B15D84DA6D0D4055F86E865955 +:10ACA000EADE62C25FED52C887ABB44A6CA7167584 +:10ACB0001A80632657011DACF9C07F6196640CF8B9 +:10ACC00034AC9B269633B686F092E13323341CF2E3 +:10ACD000398CE389A586131FAA1ACFE71C593E9F1A +:10ACE0004D807F57009EA08D06FFFB02F0AEFCC991 +:10ACF0009B403CFBCBF8776B3CD58E4F80D3CB3A57 +:10AD0000DEF34EC0D4F95DF97C6182F059757D7037 +:10AD10003DF284F7F25CA4A352E539EA83292BC9FA +:10AD20000993664FCAE0ABF1C8AE0B0ED9E6B596F3 +:10AD300085A327FF8E21834C25FE16EDDDFC69A53A +:10AD40009F34A52E38A4D0FC3CF6F90F56BFB909A4 +:10AD5000283ECEA6078A8D184C9D6D645F376440EF +:10AD6000518B62C4A438D42B9B63CC83BC775C2208 +:10AD70001687F15BF3A0D342C67E685E9336013F2F +:10AD8000DEE66EFABE05C79E6EFB3E2B198B43DADC +:10AD90001600B9AA1838FEFF028C21DDB7483DB570 +:10ADA000AC34A30F7C824E3EEDD93F4980A7AD5213 +:10ADB000FCD35EE4BBE111E23B286F97F3299DA72A +:10ADC000566265BF8CF3F55BED64D62257523A5B51 +:10ADD000CDC77975BF54877C353C447CDE92A7A6ED +:10ADE00023D05F47B1BACB5B9C81E71926713DA8A0 +:10ADF000703DD0A138E1FE3996839CFE8C2994B633 +:10AE0000847939D39A639784B3F493C7F1F198792D +:10AE1000856986F0BBCEF91C8A2584A7584DDD8B49 +:10AE20007C6198B1056147B999672FD7D6C716A03D +:10AE30009E32A17FC08F3FC688DF6DF5391C69281F +:10AE4000473C0C475E81F9E7DD74388D72138A98B0 +:10AE5000398047B5A2ED3D6F04FB6384AF80908ECF +:10AE60008427F90CF6E32F32188AB01A4BB024C9A4 +:10AE700091535F0FC6476E3DEDD36D79FCBF982DA2 +:10AE80005F82FF5FA49DCCC9D4EF5F1FCC195C2EFD +:10AE90002DB165DF738CDF7221EBF302DD5A27AB36 +:10AEA000FA06A09B1A55D3C81FF8D73745F00DE016 +:10AEB0004BAD6AEB91401E7D38EF09D81F974FB517 +:10AEC000C829C7679327B73CFE11E53127238F1F99 +:10AED000B115A49F5922E64138C3A26F35AE9A88B6 +:10AEE0006718B707C7ED97CBA90B72513FA99A7A9C +:10AEF00094CA639DCC3EFE4694479844B194F8189A +:10AF0000F1D19CBB8D2581AEB2DAF0D2125C6726FE +:10AF1000A8424FF7C42E199F69D78344037EBC15FE +:10AF20008B26DBF0B9A3C8732EF473EB01989A81DA +:10AF3000FCCFCC28F189DCBF9E71F954242E67A385 +:10AF400025CEE7AC93EB9B88357F1CBF14F92B45CE +:10AF50009DE5B034D7CFAC81F21F5557A62592D3CB +:10AF6000DE76D48FBE6A0FF0FA40B8B637F9091F03 +:10AF700083C1BDFD42BEBE78430DEC3A1B1E352990 +:10AF800022EC8DCB35D49F9299645FA01E659D0203 +:10AF90003FF118AEF79B9B1AD97158BF024F2D662F +:10AFA0003AE495F2A46184C47CA7A19C54F1546650 +:10AFB000643FC843B5DDB82E2A45FE25FA044CB5DA +:10AFC0004B30656C3DF5AB949D77B53481A309D7C3 +:10AFD00075A588CB9BAC33E243256A727A6A5CBE66 +:10AFE00040EE264B088FDF298F567BA68112184E24 +:10AFF000793D313E8BDC597416F50695CF7EFBCB3F +:10B000009A7F4AE5764F7F9EF1BC55CF960EE5D3E9 +:10B01000477ACB3193CF27C6529416C9277BEDF2DE +:10B0200024DA35E33F6DF0B4093D4A7F00AA1C8D58 +:10B03000DFBD19E8DD367C6E6C297C5F2C71BB8826 +:10B04000CD77E2C16A0F785A8C7892358E3F0B3FEC +:10B050006DC3C7E6523E944F7472CFBB0DEC1759C7 +:10B06000C906478ADB73852C3504F5C76793CA5137 +:10B07000FF0ED68F1B8FCD4AFCA524AE47055C1E64 +:10B08000BD12B3E8C416423F37E07C10DE28E80169 +:10B09000A0BB1FE88D7A02E6718394659ED67C9AE8 +:10B0A000C3D67CA259E168C1F98CC9C0DFFF5DAC91 +:10B0B0005783B573C33F5839AEF74BC8FE72CF8B79 +:10B0C000D34DD138DDB68BF92921AEE72CBE86F9F8 +:10B0D0006DCF3EBF04F1977B7EB2E627FC58E3CBF1 +:10B0E000FEB135F2A40C9C3B258D8FD30F479CFA03 +:10B0F000F16A8CDA995272278EE78DB6919EF586A9 +:10B100000C82438D4107E7636AD4822DC95A9E9C05 +:10B11000C62AB05D28CE568CC7F530C9E643BD9629 +:10B12000CFBD9C1FA2550E7EFD91E4B69F393CAB6E +:10B13000845E70E3EDDD41F8FBDD5F5E44FC7D4045 +:10B14000E0EB0CFC7D00E7E1E6EF777F398EE3EB87 +:10B15000604156F95EE52F75E08B09FD9C2BFAEFF7 +:10B1600088B14E2FE02137EE31D1DE1CB5A87BC768 +:10B170001286F61D9F475B41F210CA95E2E9511510 +:10B180008057AFE96DC33574B398CF1CEF11FFB191 +:10B190000AB45F4B72EB80BF4E0B7DEF866327AC2A +:10B1A0001F28673B405F63FAC9AB1CEEC1F8EC8E09 +:10B1B000266D1AF2717FBE419E9782FEEFA87F2A0C +:10B1C000EF22C05F6BB4AC92CC0243A2FD5440AC02 +:10B1D0003747ACF546E007F07604F166F1DFCE358F +:10B1E00097925EF51B86A1417E14D4433B2BB28E11 +:10B1F000C1468DFFC936FC5878013CBC8E7858A9F1 +:10B20000F5AEF7C238ABAAD953985A78D85AE52187 +:10B21000BA5E3F6DEC6EBBBD38CEC3D75D5694CFE2 +:10B22000F9538675253CB8DC6D073C5590FC6A12D5 +:10B23000F2715E0DE851E0DB76FC0E78BB5F4A7C74 +:10B2400084F3C99BDDA7E23CDEB1EC3A16A3FD4CCA +:10B250008B807BFB5783044F4B81B60B6554F27098 +:10B260007E65F5025F03F94BF264E1AFBC1A032D72 +:10B2700007F6819C543C300F6F5983867A2A474ADF +:10B280001A32CCB355EC8701FC1E1C5FCBD80134BD +:10B290007E30A6D37A58E0E174D12ADAD678603EBF +:10B2A000B945B2E98354EB5D42FB2AF5C8D7FF8864 +:10B2B0005B3CF84EFB9E3CA313CD343632C69E4415 +:10B2C0003C3F2F270B10BEE0F81622532E330C1FE5 +:10B2D00054D8A618B4DF956B92462284F49DC2968A +:10B2E000D8F86AAC9837E8032315CAD077BB97F330 +:10B2F0004B47FC7DFFF210D60B129D46B32A03FB91 +:10B300001B85EC80722AF802E83F06E7AFD7F43CD1 +:10B310008B7D8CD27A554927BE1F86F8DAA6F4C6F3 +:10B32000B0DDB6352ADFCF9AEC05C2B3878F03FFB5 +:10B33000E9B4FFF07018DE95F8FE40A96364378425 +:10B34000432CA5E33EF12A9E8FC0FA69403E80F867 +:10B350008A64F013407C41AAE97113F19357D667D0 +:10B360008E65849F69085F909926F29F1CEA34706D +:10B370008A77C80D7FF847E8EF8EC3DEB8C96C7CCA +:10B3800028EC1B0B4F23EA41DEB2ACD356FDB3DBF6 +:10B390000D868CFDCDF6E790BE7F5AE80FE0D78B87 +:10B3A000916EB3B5F7885F5968C839F5E76DF4EA6F +:10B3B000278620B134B24F55E1BF688E71FBD8EBC0 +:10B3C00067A607E6E5053C2122BC9D92F077C4D92B +:10B3D000A230EEC73D8EFD851C0D3AEC7A6FA3CAF4 +:10B3E000FBAF85D60E7F538AE4C8DBCFC449CE07B6 +:10B3F0003026FA67204D07683FC1F72B4803EEFF60 +:10B40000FA81C39FB0A9AC9265DB37C88CEF2F508F +:10B410004D7D513CB0DDE078718DB7C809F739B783 +:10B420000BC9FA49AB4DC999DAC9ECA46DBFB6A1F5 +:10B43000DFEFC7E9B35161072558379A8BDA88AD3A +:10B44000FAD70B4C91BF921EC73AE62DE2FE8C84D0 +:10B4500047E7FA30C6ED2885CD4D937CC4CECDAEFE +:10B46000B2EC626B1DB7ADF79DC8777EB1FECE978B +:10B47000127720DF6DCAAB4FDBF1D3ACB27AE213A7 +:10B480007D11D5DB3466AE8EFAC2E2B34D2E7C5A06 +:10B490007EBDB6A614ED0398CEED68351627389418 +:10B4A000689252375C16FFF68F5B66F16D27E9AB49 +:10B4B00040E72D06F22F7C13FB35CEB72A685BE4FC +:10B4C0008F1F43CAF92325ECC441F8573F37BBDE31 +:10B4D000FDFDD3783C17E1A88BCD985E06FD2C6F5F +:10B4E0005C43E9B2C64DD3D05E78A3BD3462E7DFDA +:10B4F000633BC750FED80E85F4D3B19D520AD79551 +:10B50000633B6E88101D3EFBE20B2FD01BD519D17B +:10B51000932569FFB0AC5D22BFC293AF8E1BD51BD4 +:10B52000C2FCC635B8F55AB653310CFBFE5FC0D924 +:10B5300022358C43E1DBD8D453837E54CBBE7C05CB +:10B54000F9A680FC375CCE6583FC298F7B922FA304 +:10B55000DE6BFCACD9370A50D17CC417DF00559F95 +:10B560000E950C437FE35AB5619C669BC7DA7C3528 +:10B5700049EB40A8CB81B7DF7B1487BD6CC163DE8C +:10B58000CBCAE528EA83607C3DD0637688AF0BEFB9 +:10B59000F74AE47F6D167CE1C6AFD2B8659A6CA31A +:10B5A000BF0276A55E91D9377BCB796A95F7E1FA30 +:10B5B00003E37DE0E1FEAEDF7A921FD07A0B6334C5 +:10B5C000E6A39EEB98C6EDB810ED572DB9B4E05C3C +:10B5D0007F2187738B148C6F009C6D192FD665D6D5 +:10B5E000CDF7897237C3FD4BAB80777645771AF973 +:10B5F000CF9AC760FCB3A9294176D8063945EB6BD1 +:10B600007353ED34B4DF605F588B76D396A8467AD7 +:10B61000B139B4CF5F07F3DBE0E7F5B684F6FBD1D1 +:10B620001EEC684AF2F69AF8AE897ABA95DFCFF343 +:10B6300086C8C7F751BB0D26CF6F6BAAA7F65BE292 +:10B64000BCBF0D6C17AF5725FA61BB455EF4C3EE66 +:10B65000999780744BB555BE87F2E8D042F9B6F49D +:10B66000FA966A513F949A675408A6B597D7083856 +:10B67000FACB0D57F97E47F9C6A686697CDF653A95 +:10B68000EB15ED738DC32467B91B0EE67194EBCEF9 +:10B69000F65B745E5F69DCE6E02FE097695E9B9C79 +:10B6A000E720BF40F916C6E6A1BC784DE6BFB91247 +:10B6B000D8A08CB59480DE9EEBE57ECA468B1F8BAE +:10B6C000985C5D89F61D93BF9A6FF3F3E8CC4FDF6A +:10B6D000CB99DFF15D837DBD437EB3F3A5793BE775 +:10B6E0004B3FCA0F0C395B37D9B9F0DD962693F082 +:10B6F000B9A9A99AF82D47C8BDBB5EAD57D8D7AE3A +:10B70000F161BEECE67CE1EF453D7B24407E526F6B +:10B7100014E699CFE7FBD54ADB7C6230CF7C3E5FF5 +:10B72000C7F732A7FFC2FADE827264F31BC8F14A80 +:10B73000BF4EEB409AD681B5B85E16C2BAE13D3035 +:10B7400003FDDC967EDA88FA098A9E2E02FD7406D5 +:10B75000BF624B9331BD4CC175A77A3A9EAF284268 +:10B760000F3417556AA8D79A43324BA37CCB26AE29 +:10B7700021CCAF352C47BDE43B022B6E31DADD0D19 +:10B7800069944FBF060B0B437F2BD8BFD0CEAF1BA6 +:10B790006CB96D5CD9D2A79F3511DFB686B828C8C1 +:10B7A0008D73A7974DCAA2D762B3E9BB7B7EBFF565 +:10B7B00024DA91FF428D2DC47783F2C32DC00F553B +:10B7C000767DCA689FF03ED007ED796FC8F465B505 +:10B7D0009B1A6751BFD6B87B9A9F77E035A3F7AF26 +:10B7E0005F8EF4BEFED500C3FE06C3AFD27803ADB4 +:10B7F00077DEC6EF52DA4FEF689CF0E9D5C4B95D49 +:10B8000094C5C7E87C7D5FCEF5375B5789ED6FE265 +:10B81000ED93373AF061C1F55B8FF180370B5FF63E +:10B82000E3612F7B2908707F12661ACAC5D3AF4E19 +:10B83000A5F1AE3FCAE502F042787A1FF0E42BE6AC +:10B840007CDC5869D7CBF3883F40BF529A23F01372 +:10B850008837C04611E85DC1E90FD427F883555CED +:10B86000DFFBE26C2AF183555E05E50CD78504F514 +:10B87000D3DC544FFC9653D1437CA2845CFD857885 +:10B880007FAA26FA0BB9FAD3787F39159CCFC271FB +:10B8900080CF263FB05EFF16F12287601C9BFEF032 +:10B8A000C76E247C0E86AF4347C7E59E495EB63718 +:10B8B0003592BE68C7F509D2EDC5462DAD03B87EF9 +:10B8C000911CF17568ABD0D39B715D81EF41DCC4F5 +:10B8D000A25D2BF3FD593BB3FE34E687FC26C6E59B +:10B8E000A143E17A442E9353BBF1FC00FDD4A5782B +:10B8F000C8C4BFB797EB746EDC1110F52A18D5B326 +:10B90000D61D39C0FB09B35E62220BEE766D03E9EA +:10B91000F38E3CC34078DB59BBFF7ACC178BBC6CF1 +:10B92000523EA41AB4CEF91553A37C90E7DDFDBBBB +:10B93000F1E2CFDBA061FFA17CD15E6AE7ED4B9C19 +:10B94000FD75A87CBC4D72271F3FC8F367EB7F9342 +:10B95000F6430E7FBE68CF76F0F625CEFE06A35BDB +:10B9600040AF75EC3B7D31A093635D49917ECF295B +:10B97000AF77D48B543538EA3DFDEA38B2F7AC7E68 +:10B980000FF5969E915F4E0A7EE9CF079257B03C25 +:10B99000C696CA79335B8A20AF24474990BF3B7F64 +:10B9A000CA86792319AB6F9C41F6D732A1379637F7 +:10B9B0005ECCF31D4B55D4FBCB5212F9179609BD43 +:10B9C0005067B2225C7F1232B7EBAC75166C065A28 +:10B9D00067EBA2CEF5A74EE3EB4F5DCCB9FED4EDFD +:10B9E000545CFE737D14DA73CB1B6739F4F3F28E6B +:10B9F0001B088EE5429F2F17FA1BECF051B5507FC4 +:10BA0000261210E038B969DC28B2E325FDCE46F4F1 +:10BA10004F5F13A4F352377EACF38AC751AF4DCEBC +:10BA2000AC0FCB5C7104EE7499581F989C2438BFFE +:10BA3000EC7833509E00CE65D6F912CCB7767C6692 +:10BA4000FC63518E8B2A6406925BC04796738F7E8F +:10BA5000FC256F74E8F72F8BB70BC43833055CE710 +:10BA6000DADE2A6F42BCD33AD07F8EF215C4CB5FA8 +:10BA7000CA4F1B33FC44EB26AB0F925DF3D7F31593 +:10BA8000D7B35F96CE8F7B34410798D7781BDD5CA8 +:10BA9000F4B2DA5D8BF8043CB4CABA635F6AD1C908 +:10BAA0008DA763F5418F3717D2C37368FF7C87AAD0 +:10BAB0005F817AEB1AC4DF10C423C7DB4958075BE8 +:10BAC0006CF6D8B28E1B9EAD067EAB6BCFCB976C5F +:10BAD000E3D7B517B7C5A2B8FFCCAB44BFE235ED8D +:10BAE0001CCFCB772C99DE62C307E0BB0CEDE5BD24 +:10BAF00082FE03F05D26F05DE1B497EBCAB9BD5C50 +:10BB00001777E13B951DDF75826F609E2D3FA4790D +:10BB1000CECA0D8432785A1A5B4378BE23A24750AE +:10BB20009F9E84F5AD05F4D63161D71FDF3129B270 +:10BB300004E54B867C08F39379DE2FF23BA11CFBD6 +:10BB40000F89FA3B27479664D1C76E7A2C8DDD2882 +:10BB5000E4C0B4CE0DC81EF904EC113CB7182A2776 +:10BB6000FF4DC6FD43E8C13F62FCC0F1D0F57F4800 +:10BB700051B5ECEBB7D5AF365B3E66C743B006F2C6 +:10BB8000763BA0CC592E335BBED8010F0B4DE1762E +:10BB900031FF4B09BE61EC2DDB79A4D29BB714FDBC +:10BBA000A5337433FD35B433431EDD97E51C39A34B +:10BBB00087F449FDEB0AC15F3EA97FDDF1A2DD5D9F +:10BBC00072C6738B96A683D3EDE789B26C308C6F07 +:10BBD000B1EC6CB9F15FA723BF1E827E8ED2FABA98 +:10BBE000C13A6F16E7AB29871FC2DBD836CD7E7E00 +:10BBF00063F9B76065D1EDE7086D81E44BB854E7B0 +:10BC000045D66DF8FA70DB39A6DE25EA03AEF1DC25 +:10BC100064E4EC7B3767993F9D1CA05D96BE85FC74 +:10BC2000DF5ED66978D07F0FF61CC587004E7BF8A3 +:10BC30007EC38FF660B09CFBBF7215CE37EC208FB1 +:10BC4000970A0ABDD15EBE4FC37A9F8C74B66368F3 +:10BC5000F44DC9D463BD667B09EE5BC6CB0CE3B77C +:10BC60002C7F169313673C279163FCDC548EB5F749 +:10BC7000F0949F1BD8CE518B14C4EBE552F673F3AE +:10BC800073F49B9D6BBD1F3619934E8CC9C8C95A5E +:10BC90009413A05557D33C8A071CCA1A24B4176FB3 +:10BCA000F5242728A84FE6CF3351E4BCF31BFED080 +:10BCB0000269FE307D221E656E55593A11837C8ED5 +:10BCC000FE08EEDC96AB95B342307E3E6E0A607F96 +:10BCD00051A3CC6CC638A1FC527DA2077776E685CD +:10BCE000B37E5D0DF911FA7BD8BEAD7DDAAC79403B +:10BCF000EFFC718CE28A98397716C62BE4FF1DCFD2 +:10BD0000FF93CADB5BF64807F0EB09B28FD394CE02 +:10BD100052F87E7A0ED27532BA8BD3E4AF0C01DFC3 +:10BD20009E003E54E524E5D5C66729CF62FC3CD190 +:10BD3000F257B41524BF81F35B99E89D8B5D78437E +:10BD4000CC83F2B25949EDA8ABCA9C1BCF8102B497 +:10BD500093DFAFD077DBF7696B151117D5F452CDB0 +:10BD600089313CDEC52E4F5B8A5937FA79ADBCDF8D +:10BD7000C71A68BD898BB84A21F74C9C7BF8A3DAB7 +:10BD800044F44F5DAE78445CA57139F2C546C5CC2C +:10BD9000FD2A9E633FE7257B44660926E2CBE87CCB +:10BDA00088CED1808FD6E0A127F291D6D03303E39D +:10BDB0008AB47CEA8F55F4D6F4EB8512ECAF6107B8 +:10BDC000D2EB5AE5C04C05E8B531CCE9B5A2F5E0B7 +:10BDD00006C4F71A45AC932CE1A7B80FA0F1A97CD3 +:10BDE000D25F691FC5A7B11D6596DE025015DD73D0 +:10BDF000549970F67352391AAFB1DBC16A3CEE4107 +:10BE0000392B95C53A7CEA06668F03FAB1A06F4BD1 +:10BE100053BD234E55897A8EE2799C925C3109E9B3 +:10BE20003A474AB690FC80FDC06C7AD6F277E7B00C +:10BE300045B9E9628C8BBCE830C6B3DCD77498F89E +:10BE4000873D3192F4408E661338D40B2213DCC93F +:10BE5000D2810998E7F156C10AF963BBBE77C7538F +:10BE6000DDAA648F6F2C69FCC10576FFBAA75DF768 +:10BE7000A0BD6FC551FD44F0AF555ED2F84F547F61 +:10BE80007753E305C857FDF08AFD4D7FDCE73A0E96 +:10BE90007FB1D04FD6FC607FF1D44AE0978E24E882 +:10BEA0002ADCE7B5F0F3DE9CAF80C22ECEC853305B +:10BEB000C9E7678DEB9EDF4F05FE5B9B4ED1F83FD8 +:10BEC000431828DF47F91C6080C7911F0E39F1D84D +:10BED000D60E7A18F9F9056F9CD6B54D06D139D82A +:10BEE00029F0E91A871D3E0B1D747E8E75AE7438DD +:10BEF000A438E3DA2C3AB046F803FE1863E1EF33D6 +:10BF000028B5C5595A78B0E862E5019FB9BD67E028 +:10BF1000EBBB9A3E9D8EFBB3962630C121BD6BDDF7 +:10BF2000F57E1C6FF43A96423D3FBA88F3EBE82E5B +:10BF3000588AA2948FA3ECE8262FD745B9DE65F87E +:10BF40008BA394A77259E3E5B228BF6BDD4C2300A5 +:10BF5000E5318DD179694CEF7B6E1CFA7D1AB99F62 +:10BF600083E154006F778AF914AEBB711E9A218564 +:10BF70007ADFEF300E8135707F8712E5FD2AE29C73 +:10BF80002B652E3002D00F8C6D786DFDEC14F82FE0 +:10BF9000349F62F3E07BB1CEF2E7E17849E778774E +:10BFA000887A211DE0C7F27667F90E014F89556E38 +:10BFB0007038ACF24ED1BE543BC16660AA27E62170 +:10BFC0001EA0C0D1CF3651AF0CCBB19FB8B3BC438C +:10BFD0008CA3142C223D3E46F811EF6ADA4172A47C +:10BFE00014B4D07957AAA9FD022E4FBC9DE547B1E4 +:10BFF000E4ADA5A993CAF575BCFD58AD6F8661A3E4 +:10C000007FA1CAE5C24A510EF0485045850E709591 +:10C0100096839C495C4ED7C1F76087E05F37DF337A +:10C02000C803DF8E823F617F521C85C56F969FE0FB +:10C03000D0D1A90EFE638DC06FF6F8D306BEF5EB26 +:10C04000CFD7FB2F7094273567B91173E6AB7567AF +:10C05000FD78B933AFC71DF52D383A9B1AA7CD1E11 +:10C0600093F1FB7616E88568F7EF2EE0E7399BD071 +:10C070002F3C06E3686A29ED107EC06DE8BF1B8384 +:10C0800071360D941FD1D83C6DF6105C3FABA7CD37 +:10C0900056C8DF45E5B7A3BF10D299AA8807A961A2 +:10C0A0008E7810B09B66AA68671A0983D622612F22 +:10C0B0007506FA1693BF28D6C93C36BFCA4295AF5B +:10C0C000D723AC7D9FDC2DD9D79B85621C4B3FB21B +:10C0D00022D09AE867B6F80AD613DC8F2C50F9798B +:10C0E000047C8B51FCA880C75A6FE648C64284ABDB +:10C0F000B300E040FF559CDF9B185EAF531C50A47B +:10C10000BA2F8DF960854EFBBA58322DE1F9CC0873 +:10C11000B09F110F8557251DFEC69C72A7FFB13336 +:10C120008FCFAF08F7DBB0FE05701F0FEDFED33BDE +:10C13000B30EC7DDAAF2F5BB39BC6C38F2FB2B722B +:10C1400062990AF00EF9663BF1FF560C48C6780E6C +:10C150003C27023B22FFE2CBFD14C7399FC7AFB19A +:10C16000CB59D6B81B5B5CDC1AD576BE6DE1DD1A07 +:10C1700097C9C9E1C8C7BF90926BB11E2B8FF9ED6B +:10C1800076973F91A47374379CCFA8C6CD08A705B6 +:10C19000DF41D558C7F3963D02FDC2382399697A2D +:10C1A00000EE91086F04FD813AA7870B6EB09328CB +:10C1B000EE66C0FC6AB3C7ADB9E359ADF371B0C365 +:10C1C000B6AA9333F3BC5F4ADE42F33FE2E376BDA7 +:10C1D00026E29B44DC62FE90746CA28DEFF60BBEEF +:10C1E000EAB0C5D5D1BE4FC4F5D01FDA2D9807F9F6 +:10C1F000FAA9CACF55016B66CEF9686F83E18EFA52 +:10C200006EA34AF748862501108C936955C91E55BF +:10C21000EA872EC5B82490D1349E5F2B2D6D6BA478 +:10C220000919BFAF1F356C29AE9FDD9486F0C60C8F +:10C23000A411D647A986915090BEBBA4F7262452DC +:10C240008D3FB917E7BBC29F1C8DA1836F8F4CDE5A +:10C250008FB0FE1CE90270BD201B3FC3725BFD9FC7 +:10C260003BEA2BBC3E9875FBF17B2E330E70FC65D0 +:10C270008F93B7C5657E1AB2F109BBCAE396F7344E +:10C28000C9BBB07FFBE32ACE314E14FEB433F7CFE7 +:10C29000F96840FFA2FD8F722644D06E7BBADD4B59 +:10C2A000695B6329A5AF79D8B66AB4CF9FF7B26C42 +:10C2B000FE422BED453B0194C57F097E38867C0B01 +:10C2C000E912595371DFBDC4FCD374BBDF7889C94F +:10C2D000FD3DC0607391DEAFB5CE50ECFB616B1FCE +:10C2E000EC6E97F14BF58EA4FD63FF7D041EF756AF +:10C2F000576D2140FFCE7F01DCD71C56E85CDCB2D5 +:10C30000872CFC1C3BCEE3B7AE11F15C57B1440463 +:10C310000BDF661EF2D7BCCDFE3332C9B62EFD59F7 +:10C320001571CFED0AF9414CF81FAE1757772A0E59 +:10C330003FC9F21DCEFC32B66028EE439775292C1A +:10C3400005BC700DB3F95960BEEF08F95FCE1ADA7B +:10C35000703FD72AE4A84E63F210585F573EF69319 +:10C3600029A897151F5F8F4FC33E4CB7C5D95F1BD8 +:10C370004AA9B87E1FDF3FE9D20B18B64FB515E2C8 +:10C38000FE2E8F65F5EF2E6D77C27736F8DDF05A09 +:10C390007E92C1E090F770BABAC71DE2B3E241CD18 +:10C3A00073BAF737D5A78BFACE7B7F676B77C15F00 +:10C3B000D8EE6B3E9D65BB6778B676B306196F53B2 +:10C3C000B4338172D62F77FE04E15092B9DC6D8AC6 +:10C3D0009DA5BC08CABD67282F3B737B8C03C2FB9D +:10C3E00045067EA4FD747A04D95F4DFCDECA134A6B +:10C3F000E25BB86F7AE2F75E86717B4F28EC105EE5 +:10C40000A130254947BF80A15D42E5C60BDEA8A744 +:10C4100058080DD67F6FDE3D28A7DFF0F1381D26C6 +:10C42000F778B15FE3436D36FA379E50D223F2605E +:10C43000FC9A7F6249E4E3191FA69722BE2EECAB5B +:10C44000559005FEEDE1A7BF8BFD5CDB3757C6FCC1 +:10C45000B7B11FC0DFDB0F3E3285413F4FEC0DB35C +:10C4600034C22FA754DC575DBBDF4B76EA753F0B18 +:10C47000D3BA70EDBE9577CF87F1A5C7C2044FCD73 +:10C48000BEE5F7F908BE66EAE7DA4717E66E17F386 +:10C49000F2036A9E582FD625333D02E3FD57FAD8A2 +:10C4A00095685F5878B0F8735668868CF7B8AEDD3B +:10C4B0009347764C3F5FCB50BF02A32AD9950BB26E +:10C4C000EC936EF6717DF7D67B3CDE54DAF3E4151F +:10C4D00034BFEEEFD07C25A0C8EB30DE6A314FA828 +:10C4E00047F3301F905263A0FCAD07243EAFEEF13E +:10C4F000BB02C538FE2EB58EF41A3F87B1E09DB55C +:10C5000067460BCAF52C2DAF04493EEB677B493FCC +:10C51000AFDEE34DE3FE0952DA47CD0E799DF7B960 +:10C52000981192800F56914A8474FF4AD27BABBA1D +:10C53000B7D0FD90D5079DF20E788EA701FEEB5E79 +:10C54000F4C6E763FEE7F7477480E774CFBD11A434 +:10C55000078CB3440539F8DAA74EFF30F6FF69FEC1 +:10C56000C0FE18EBA3F8B3D5DD9BF8782E7D721AC8 +:10C57000FF317CE03E7797CFE96FF888FD7A0ADDDE +:10C58000DFDA3324EB7AD87F6F4BE897EBF67E74D3 +:10C59000A709E3BEB5EFCD3BF15EC18A3F7F70E7EF +:10C5A0000F70DFF5AF010DF5E2EA075FBFF366C07C +:10C5B000E7DB077D1EE493777E79FF7D7740FE9D64 +:10C5C00097C7554A90FF858FDBC1EF3CF2A7A17852 +:10C5D000DFE8C65FCE1986F3BFF1C0AC612C8B7E5D +:10C5E000B3D27780AF523EFB3A96A27EF483D0DF7F +:10C5F00030C83E2152175D9EDEFFF42884EFED9790 +:10C600007C1477B05AE77106ABBA57525C36E671C4 +:10C61000BFB5EAE18DE427188867738427C6E51C57 +:10C6200043D057ED5FF8AD0BAB3055E23AF6C7FAA1 +:10C63000687D71B75BFD02D0F3FCC1E9F711FB4CDB +:10C6400045BCAF7E78131FD745BFB7F11FD306D2C5 +:10C65000EFE501F45B7117EDA5F7678F3BB6E8B71F +:10C66000F2C0B7CF78CFEF1D97DC0E86DF7AE19F5F +:10C67000BFDF67FCD18772B72FC78C117D7DA9F909 +:10C6800050F64EEB07A318F0C529A5EF0A94BFBEDC +:10C690005FFA348C1358F2CB1755D463EF1CF89D16 +:10C6A000AA933E672109ECA87758FF5F0FDA55ABD4 +:10C6B000447CFDEA7BC269F433AC5A574F745A95F7 +:10C6C000BA649E1EA1EFE47F5895E27CBF2AF5E490 +:10C6D00022290BDD747F3ED7A3A902612766E828D3 +:10C6E0005523FD8ECE457E1B8C7ED6BC359CF754E3 +:10C6F0001B1D4D85E47430797C67974F96B05CF8CC +:10C700009D2CFB7E754A7A916591D3FEF3912F792A +:10C710000FB3D09FDD6F68CDF76C727CF6F97C3972 +:10C720007C0551D8270FC4DBFA561FE9E1D726FA5A +:10C7300028FEE9A8A2FF682DC863DF730ADB0D4D50 +:10C74000AEA87C43D1B39C83FCC165075DD928B5F5 +:10C750000D8376579A7C1D719F2325D779996EC3D7 +:10C76000CF2A5FDF6B12EE7F7E15601417F7AF01E3 +:10C77000DA0FADBE3390C275EDE9039FDC87EBC9DC +:10C780003B77F9185FE778DCE272E14F7CE3C02782 +:10C7900077FE3794BF818D75ACBFF6E4F791CF7FFC +:10C7A0002C61AC197B775FEE04BC5F751DD4C5F3BB +:10C7B000E7E5BFFAC137914F318FE7A5CB739257A9 +:10C7C00060BCD0F21F0F93D09E591DECFD33EAA13F +:10C7D000371FCF450AB0B70F7C3205E9F5E6A38FC6 +:10C7E0004D40FD07F6A16E3F27BCC6FE9E84CD7E60 +:10C7F000BFAE7B6B0FF2FD7558CEEB4B5F089941D6 +:10C800003B1CC747BBE4BA83B9466082A31EF5B39D +:10C81000DAD777539CF6DF66A1876CFA7421D2F9D8 +:10C82000BA3DCEF1AFF473BB78B5DAB78CD7EF2C45 +:10C83000E4FCD043ED56F82547B9BBBD55FF5A7F00 +:10C8400009F15BA61FDE7E9538D770D37DADE8F782 +:10C85000BA3D9F8F73F6C7F976E038FCFBF7246684 +:10C86000E2791E7B2440FBDD156A7A6C7E057DA78C +:10C87000F70BAC7CA11817F3684FFD42C8E78A207C +:10C88000CF3F2AE2E75744208FF0FA7B7F8A7CB3C0 +:10C89000F2B10043FB6CE5AFC05E02BCAE7CF4DFDE +:10C8A0004621DD56FE6A2DD17DA52F4DF4EE7BC4C9 +:10C8B000C77643BDB71E798ECADF52D2A370DC950E +:10C8C0004F048EDAEFF959E9CA6E9F70263BE7D321 +:10C8D0002CCEAD5AF0DC6A0CEDAFE8DC0D242D8EC9 +:10C8E000F323DF15C57D0EA7F9BAEDE983FEE2ACAF +:10C8F000F6732B9E8BA023D56F32CD7EAF95F1784A +:10C90000D7FFE3E23755496AB8CF54118F800F45FE +:10C910004EB6A31F55894527221FB7C5161838EFF5 +:10C920008E0A6D22CAE5A37E6EB7F9A07FB28F0F83 +:10C9300075D1B9AFBF487EDFAE2F0227421467C85A +:10C94000CA6CDF4B283491BE872AE0BBFDDC270A86 +:10C95000703BF0E43C87FF85C4F161867DFCBD003F +:10C96000667A519E17670E46699FFAB2750F466E3A +:10C97000E1E57956710B2F17F2BFBA8ECBB79B5EEC +:10C980008B9FD8D883F1FD8B9F184EFE93C5A17164 +:10C99000AFA35EFF05EA56DCCFE7F9881EE73F91BB +:10C9A00058F8F790FF87FA31A4AF2ABA13178F8788 +:10C9B000FCE5F5A5E4BF7BD9CFF76DDFDDE531956B +:10C9C0005C3C7F10F07F5F22F8AF44570C345CC2B0 +:10C9D00074956FAE533C5E82758779BEBB00E3DD14 +:10C9E0006DEDBD216CBF46A2F3C7CB7EFFC21CC458 +:10C9F000E52B2F1CA390D72B7FCDD41C1877C97E95 +:10CA0000BD8DBB53447F4F407F9E4C7F193C72BF0E +:10CA10001193FD84970C9EFC84B797FBCF5D4CBAB5 +:10CA2000F76EC333C5775B785E1C7EE932C4CFE214 +:10CA3000F0D8432C32109F6E7BC38DDF0FB108D628 +:10CA4000B3E37EE3133FE0EB79BFF1A99FFC467DA2 +:10CA5000A3E412F2237D86F955DEE4E8A1A5E4778C +:10CA60001A57807CD793DD9ECD8CC7E5EC65168F79 +:10CA7000F17D5C079F87780FE565C6F5FA075834A6 +:10CA80002D03FFCB72A81DE17B29E7A70ADA6FDF30 +:10CA9000656905DBFF03EB55902E6EBA2D65868A1E +:10CAA000E557B3741BFAF701DEFC4041065E56D42D +:10CAB00043F15DECD7E7766F6C40EAF733FFD0CCFB +:10CAC000BD94BADEF79A106F750006AE8748166EF1 +:10CAD00067E82AFA75EA8EFCF1737B39EB2FE7E7FA +:10CAE0001AFDFDF8F9BB0DB67A8E7586EA49D9FABA +:10CAF00081BC2D9E64609EC3E1FE5EE7E7EF736438 +:10CB0000818B9943118FD61F6F7F42EA3E0FDF65FD +:10CB10009919B86B763BAC330FE5F714FA213F3B1C +:10CB200070774B4B0D637B619B87E7D3909F6D16AE +:10CB300061DEB802F79B4B6510155B3CD3C5012E37 +:10CB4000871707B8BF08CA4D2CBF48E4F1CD14BC05 +:10CB500022886FF014815E3AF670E56FCED307A796 +:10CB6000535DC7173E3DCBFAC40CA647A7F07B6ABE +:10CB7000E4BF7D366EFABC9973F92FEB77CD677100 +:10CB80004AA32C41A9157F11639D9416B26E4A8B5E +:10CB9000580FA5A3581FA53AD33C9CDFB9BC95B04C +:10CBA00038E5CB5882D2BDC5FC3EC3312918DF9D84 +:10CBB000655D8175E47773A07CED7F7A294EE0E6B0 +:10CBC0004049D675C6EBBFB8A6C57E3FEC013FED28 +:10CBD000E3F7AED7890ED6F79B037CBDBF39C0ED16 +:10CBE0008DBDEBF9BB02C71EF0C777436FC7C34CBF +:10CBF000CD83718F6F7DB104E3BEAC7A0FE5F37521 +:10CC0000FAD3A38F9D87F1B9DF0C183F08101C6978 +:10CC1000E24F8B5F96FA43DC7FDFA1BC655F6786DE +:10CC20000712CD01E8E7F04F83649F5E7F8B44F6E7 +:10CC300029D32592A7AB049D1ECAEF3E8DEFAD9878 +:10CC4000DB7C3AEAE5AB3A7C47E97D8BCE3986BDA1 +:10CC5000BF5B051FB1CE1FD1B9F45567B9B77815C1 +:10CC60002CBCC867EE7E181B9987FE6EF29538E4DF +:10CC70009EFB67ADF7B9FAE3A518BF6FC26AF83D2E +:10CC8000BB5DAD6A493BDEC358AC4EC475C627F6E2 +:10CC90006B0F06F8BAAC6F63496C9FF270FCDD262F +:10CCA000EE57DF1BF052FF56BD07ADF918CCFD4E15 +:10CCB000CE838867BF59CBF8BAC1CF37526A27BD38 +:10CCC0009B75DB033E7A97667CEDA5D7A19E19BFC5 +:10CCD00007EC2390EB5BA5548CDEFBD9EB8B231E7A +:10CCE000679C57FD1EE687EEF1E908E3F83D3E0339 +:10CCF000F17A38C0ED96B1A93533417CD99B8B537D +:10CD000085E877D3313E8BFBAF2264241CE4EFAD82 +:10CD10005C277077FAE159B967F21F20B0A623EEBD +:10CD20002DC84C875ECA77E50B5DF54B1CE523F0FB +:10CD30006C0EF4C188104B87318E72833903D7FF94 +:10CD4000DBEA18C9CD485C1881BE23409FE0FB4B4D +:10CD5000780C1284B408F2B8358572E615E5B990FE +:10CD6000DEEDE99E87443F22E6AFC97DCFB514A32F +:10CD70003CB74B0D21FBFC93018A3313F3BF56C420 +:10CD800071403F0CFBBD6DCF240DF110F52516232E +:10CD90003DDEB4E8F1F045D7707A8CBB1AE9F1CFEB +:10CDA000AA710D969F5ECCDF1102FC2FC1EF15B565 +:10CDB0001F5F81E9ACDE4B96E07CDEAC55397D6AC5 +:10CDC000F979512EEB8EE07D14B6879F5B5494B3B6 +:10CDD0009482716947D617223FECC589E1B80F7B71 +:10CDE00052784F0F5542209F52338C694DE21BD829 +:10CDF000FF7099E7016E03E5A0A23C5D82F4FF227B +:10CE0000C0E391C61FB9E66D46F79053BF998E7186 +:10CE100021D33C143FF7CCAB3E7ACFE0F4DE20C9FF +:10CE2000EBE9898CE21E376E55E99EF4A5419DDF42 +:10CE3000DFFD1CBE43BBED9B82299C5F598D9AC6CA +:10CE40007BE61FF64EBCEC29C6F1EEAF24780BEB67 +:10CE5000916F370549DF007D58A412E3DA7A6B5AE7 +:10CE600028E0C018BEC0B63FED528CC5180795B378 +:10CE7000393C270A72D515205661D383E5AD1807D2 +:10CE800075DB01D0F1A0AF6EB3DE23294F06ECEFC6 +:10CE900062458392235EF4B680A857960C70FD9984 +:10CEA0000CD03B2CACA704E5EAB6DACA12DC273E6C +:10CEB000F3EAF2E1789E7FDBD683A390BEDFC279EE +:10CEC000029EDEFC3C350AF569D91E1FCDEF56B532 +:10CED000C783FAC07C94D13EE1B6BF7FE5D83D2838 +:10CEE0001F78DF14E65315CCEB3F6F45B86EC5FDD8 +:10CEF0004E2803C7B51A8FE39C14E47EE80941AEBF +:10CF00000F2A82E2FCBA62803EA808723F791AF9C1 +:10CF10007543CE37C94F5E15E4EF96303F3FD7CD0E +:10CF2000D26E5210F5C8FCCBD2188B66B5B3CE6B5F +:10CF300061BEB75F8DFCB9D51FC7FDF6E9C5F7D156 +:10CF40007ECA9AF7E9CFFB62E8BFB5E86ACD63BC59 +:10CF5000CCD2F82E1A0BC54B707EDF10705BE58CBF +:10CF6000C54BBE6D3BBFFF4690FB8F6F0D8AF272C3 +:10CF7000DE2E532EDA47C4BDEA3277395F8F9E79B1 +:10CF800075EA1FEF41780FF8C9CF787AEBA731A483 +:10CF9000D3F6CFBB397D1E06FA4CE0EB15D273A356 +:10CFA000F5AE455115E9E7223F6BF15766D35BEBD0 +:10CFB000C5FB1A3C4ED3D21F83DA8745E718F71911 +:10CFC0000303C0460F559CA7B6152497213D7DB598 +:10CFD0003D2ABACD5675493351CDCFF1CEA778123F +:10CFE000DF20F7146F6DF2E31B3C2CD5043B29BA0C +:10CFF000D7A8517AAA29466957934E6993C027A0AA +:10D000008DD6A1CD623DDB24D29B043EADD4AA6F68 +:10D01000D94972393FBF97CBDBC80F2297F177C44C +:10D02000AC773D80AF9A107E96749EEBF7C7C5B281 +:10D03000A424CEE39B91FF868AF3FDA1B5FC3C7E40 +:10D040009BE013CB6F67CD6F8B90DB2D421E6E0F75 +:10D05000E8028FFC1CD95724DE151179EB7EC81924 +:10D06000F0DF2B65C7FF6D08FFCACEA37387C3101F +:10D0700081321E5F6AC5937E58C352678AEF76D3AA +:10D0800021773E7F3760535392BE9F6AAAA7B4AB05 +:10D09000A981CAEF971277E378B935679EFF1E41E1 +:10D0A00087BD961E38C779DE1E48FC8CE80179C220 +:10D0B0007FEC1CCFDDCFB1DE318C4B86F99CC038C4 +:10D0C000E431673F575C7BEB0AF2BBDFEA493E8DF8 +:10D0D000F4FFE487DF30D1ADB5B46322C56F801DA6 +:10D0E0007908E1ADCBD53FA69BA5E6E639187F5C74 +:10D0F000E7D31FC5FC1F262D9B83F1C775C3F49B87 +:10D1000070FF91B3E55A5A07EA46338A3F1EBDE5E0 +:10D11000F656BC1FD91934FE83CF5BC9C3F7282C40 +:10D120007B6EF0F938DFA3988E9B74CE27A69D8F77 +:10D13000813F5E41B8FF52FEF8E77EF9F473FE5876 +:10D14000C4F9E356945785F8E175ECFF6CFC705A0E +:10D15000F0C15B22F5E6087D2FF82120E4DB3DFEDF +:10D1600087A2BE25EFA0CFDAED7ACFD28343BDAC44 +:10D1700001F5CC93973D7819AEE3BE3D634B705EED +:10D180000F8E4C1562DC53D4CBFD780FFEE9EEC256 +:10D1900005985EF26021EE03FAF58AD210C373C5DA +:10D1A0008AA28FAFC0F7E92ACA586A0CA5E9926231 +:10D1B000986F54D4EB12F5C6170D5DAA47FE7A7A24 +:10D1C00025838970CEE48C9EF91BF4372C87AFD76A +:10D1D00012B70FFEBAFE00BFB47EA0BD88EF86A2D4 +:10D1E000BD834FBEB178FCBCBF05BCFFAFDAE7B270 +:10D1F000A41903D6CAC5F82AA0A3AF633D43F9001A +:10D200003D6F203D025DBB4C5CCF7258DFB3183BD5 +:10D2100064F1B33A9AF399D56F6D0ED7EFB53956DD +:10D220005C05B7BDC7D23F78BE03F278FD00F5C8F4 +:10D230003871FFA69C75D2FEF93CD64D6905EBA16D +:10D240007402EBA334CE342FA6952CEE15715353F4 +:10D25000305DE14FDE855BAE1A7FF2DB0827C64DFD +:10D26000495EB487564D47F9BBCC922BD7BE968901 +:10D27000F38AB3ED7373997105F1CF60EF8DB2C18D +:10D28000EF19C5A70CBC67F425EE81ACC6F90CB844 +:10D290000772BEFE1EDDEB60CF915ECD1FA73F8201 +:10D2A000F9F0AD8FCFC1F775F3F1B635D8D3F76C80 +:10D2B000F98F67508F2AF38C34C1F070F6F8422B47 +:10D2C0005586F178BD96BC4B358AC7F3F3F33759D1 +:10D2D000F895AC7ADBD0093A7960DCDEDF7A9C81A4 +:10D2E000EF5C263AB95EE076C83D39CEF8446BFC77 +:10D2F000E628EBC6FB80DE3C66E2BB756E785A73AF +:10D30000AEE8064EE89F87359E37C4C7FBB2718BE7 +:10D31000602FDD83FC31F0DDA1FEB8C53D08B7D537 +:10D320009F3B6ED18D9F7D39DC6E5B9263ECC57E39 +:10D330006DF17E8FE44CCE1AEFB70FEB019FFEFC30 +:10D340004C7CFAE4AFF7FD667A14B54390F603A778 +:10D3500070430DF9D77779E91EFA9B9A91331EF83D +:10D36000B1E587A57113E554F86172C5FEB865E8AB +:10D37000A2C48C28BEB3C2DF8BD8D2B380E22E5EAB +:10D38000AFF1D0BB7BA9675837EEDB7284BFE4B244 +:10D39000C8109A476AFDA5F4EEF8964FBD85AFA078 +:10D3A0001DD1A132F4B33CB555A5FCE6F5AA4AEF70 +:10D3B00005FE4B72349E8BFE29CCE33053BBD45A0E +:10D3C000EB3D3684F38DC9897B374B99FCB2D8028B +:10D3D000BAA7F66E58A6FA273A170E9B16C5F7E1BC +:10D3E0005051005C5DA51E1E276B7AF8395D7FEAFF +:10D3F000E5E7703CEFC67F449C77B9BF3F1FE1EB88 +:10D40000EED26A39807AABADFA041DB644761CE5DB +:10D4100069A797E2CB20FD3AC2173166CA12C0173E +:10D42000294AE15D7FF6610EDF0F063B27D1BD8CF7 +:10D43000DC0E96351EEDC31CEE470A96B3AFD33B08 +:10D440006F8687623583D00FBFCF71E6F66FE5F048 +:10D4500077223BC5FDCF3794E4B3680ABE717B9E4B +:10D4600064DAF8570EF1F9BC0EFDF3B8A624F57F87 +:10D4700002F321CA539C53EB4F5E34D15FD03A99EB +:10D48000F341688714403E0AA5F82972A43A417E08 +:10D49000ABB6A84A70BE2125C95F9F5AAF5E4CEF5C +:10D4A000FB55033D8A292578DFF8C9778621DD837E +:10D4B0001D9DC3EDF14C9BC2FC1EED36C147A5D5A9 +:10D4C00027999E657E91AAB807F92438C8FC1B05E8 +:10D4D0009D2CFEB5EEB384BB38DE4ACB79BB94C23B +:10D4E0000A87DADAFF3CCCF16EF19DBBDFDF0BFA85 +:10D4F000B52A305FA46FBBCAF05D0E4F358F33CFB6 +:10D50000ADF2C42F8271765F98C63764D8367EFB41 +:10D510008E05A337C5D0AFB36D72BC10E13E25F8C0 +:10D52000D7ACE1EF72BBC7690973F84F57815C0153 +:10D53000BCDBB74E19856FCB1D0FF7C5A2212CE7B9 +:10D54000FBEDEDE110F9834F5755F6E17BFAA74368 +:10D550002B864ABABD1F2E47659E5421DEFB9BD702 +:10D5600051D486EF1694A1DC839DDD16296B437F91 +:10D57000CBA987BD82DE0D24CF4FA54A476068EF57 +:10D580007153A57BB0A919F1DF4C43B9DDEAA1F8CD +:10D59000A45349CB8FA60791EFEFAEDA10417EB8C6 +:10D5A000DB902B913F3ECFAD9B1702F8B7B6E70754 +:10D5B000F1FBA6168F84DFCBB6563E5F0EFD94CDF1 +:10D5C000C8A77AF406C614BA5D457CB54DBCDBAF7E +:10D5D000CDE5EFF5E5D5F07761F3E2FC1E0EE80F3F +:10D5E000BE0FA9E6E76A5AE74B3FA0770E6BF8FE3D +:10D5F000552BBAED06CA8BF31B6DB6CA9CE7087CA7 +:10D600009DB6C68334549FCFD3A1985679D253C8C0 +:10D610007EE5EF645AC7755A8F27BD0CFBADF01C31 +:10D620005D8AF04483479742FF6F5A7434AD733E6E +:10D630003EA76D178E4DA19E3A25FCC3F0BD10FD8F +:10D64000516F5AFE0A91CF94F7D1BBECDAE1BE04D8 +:10D65000C16D9EBC1CE7B1EDC24B4761BC8FD6F5D6 +:10D66000E20FE8BB387772CFEBADDCC40D88EFD6A4 +:10D6700082A15252E84B6328E3AE3F1DE585BF4FC0 +:10D680004AE73900DFEBDFE7EF8EA0CB11DF0BEAD3 +:10D690009FC73AEBF712F8FDC651A86BF95B94559A +:10D6A000F42EB9E8EFAD6E2FD5BFB341A7F7DD4E2D +:10D6B0001E80153617DF2DE7E75DFDEBCA123E4EE3 +:10D6C00078C7C635F83D5C6D3BAF82FF6E09713F90 +:10D6D000DA9B0F7F40EBED76C6EFA35BE38FC6F1DD +:10D6E0004B3279BA5F05F03C7228FFE20AE8FFAEE0 +:10D6F000C612F2CFB75878C43FA0DB306C07FA6788 +:10D70000981634BE0293BC5CC8D323A2DEB6C3DA3B +:10D7100053A85F66FCFB113FC6292E0DC7088EADCE +:10D72000D5EFD3FDE3ED1A877F7907E7C3E5B13E77 +:10D730003FFA03AFEE90B4DDB6F3B421021E8BEED8 +:10D74000A5098DE83EA443A2B8118C49F04C1126DE +:10D750004A297E37D720D2F3596FBA14FAD92EFA54 +:10D760007DBDDDC3F83B30BD0CCF8D9675308A93FF +:10D7700000BEF063FCCDB28E21E8E361BB63F1DF54 +:10D7800060FEF59D3E1DE1286D7FDF8FF5C31D5EB8 +:10D790007A2B1219D963F16D49061F63049C793BFA +:10D7A000D6D3F863AA98C1DFA7D49FA7776DBB7CB7 +:10D7B0003AADAB727C1BAD379D797C7CD6D74EF1F0 +:10D7C000E1351ECA8FA9E6F08FE97A6C2D9EDF5EE7 +:10D7D00015E3F3BEBA1AE84CF0267A4AB17E95A654 +:10D7E000E1B956DE4E5E4F190970C3385723DC523B +:10D7F000062FA502AE52840BF0558AF527D0BC0F38 +:10D80000E33C23ED43F5CDC599792C15F35A8AF005 +:10D81000D37D19CE4F4042F30BBC6AB9C82917F922 +:10D82000F35DF23F9BD797F1170E3CB88E9B34EE19 +:10D8300018715EEAC1EF12C6A13F4A709476F81CD7 +:10D84000ED3BA28B7A681E3B7CBAC4E1D2517F8546 +:10D85000045CA12E89F01ADA21E611B7F13B941F7E +:10D860007F8E99F81EE6FA7CFEEEEE1B1355F2331E +:10D8700080F1FEDAF751FEB6A9741E70F7E73CEEB0 +:10D88000363551DDB381EB1589597A0B80AC6C5676 +:10D89000A9FDF62A7EAF54ABC99FA9A27E3AD4B99E +:10D8A00090F443FCE43FD2EF90B8CE874387836483 +:10D8B0007F8E5AE7C40BC06FE07EB6C8756E1C360B +:10D8C00087CE44BD8AE57995A47F493E27DBFBC519 +:10D8D000F3955FCBA49FC387772E40FF6CE870A2BF +:10D8E00004F924E6AA571F292561081F02E8A85E4B +:10D8F0008307EB597EDC10CEB492D243988643CC9A +:10D90000CCE17953CAE73F37311BD2BD3312F4BEA5 +:10D910004778127FBF9BF09F4F691AD3CE4AF1FD23 +:10D9200070B244A354D779AA516A8D67AD935B4511 +:10D93000FD7F0F7BB2BE831936FEECB3EB2D39624F +:10D94000DEF4EF785EF8554EAF66A5AF167F57A1AF +:10D95000F940083DCDECC1BC5421BE67B446D82186 +:10D96000FD7EEA8A45641763280FCE87317E9FE8E3 +:10D97000BC70F92EE4F3F1468F670DE9311ECF78C4 +:10D98000E210D841E7E37BA94604F59D59E4A1F1F3 +:10D990005E7F867FDF18BD7414DA51DBCA424C8289 +:10D9A000EF8930D7A7DBAA37DC84FCD1BD43CA4757 +:10D9B000FD7CB7B0A7EEDEB5B20DE3BBB6E20F87D4 +:10D9C00040FDA7269F9C87F5524F7AE88C736687A7 +:10D9D00074470EF4F7C6CB018AE77BE35F3A1BB0CE +:10D9E000FCE331A1ACBFAB90F1233099DBD386C30C +:10D9F000AE0672489877D70F0E3F4676DDE8EA8488 +:10DA000089FA57AB66339078BA0150C1DE351CED08 +:10DA100031C9CE8D89FBB955FC3BF0A68E71917A48 +:10DA200011CFB7362569BFCC2AB8BFBE35BA3B1F68 +:10DA3000ED8DCD7B64BA035AB56BA1FFEF515F56F4 +:10DA400060543A63FB53969D93243BD7DAA7BF5E9D +:10DA50005E678431FEEA05AECE3B2A660EC1F568EC +:10DA6000B0F5E2C7A1AF58F710498F51C8B437B32A +:10DA70007E6CD37AFD88E7ABBA240DD78FABC0E6B6 +:10DA8000423C96EE9052F6F5232AF406E8DD0D8C22 +:10DA9000F43CD7BB51A14740FFFA29FEB19DAF0727 +:10DAA0004B63BDEDA47F3ABD7CBD90750FDA65CBAD +:10DAB0004DD0B7004B49CC1882F1525737C8718C02 +:10DAC0000BBD5AAC3396FECCAC570915EF5F5A7AB2 +:10DAD000385FC01115EBC31093AF0FF93BB95E1E51 +:10DAE000D2C5D31345493A87A158BBA199756D4F4B +:10DAF00048277CE4777493BE1FB283EB7D8B2E3076 +:10DB0000BF33FEEE44DB8E8933116FE11DC51EBCB1 +:10DB100037BA2556A7627A322C39E201888838CF85 +:10DB20001DBB48D883A6D84F14B47D1391D9BA6BC6 +:10DB3000A98AFAB0340E7285FB93A265F761B0C86A +:10DB4000DBC20E662C49EF2AB0867ABA7F1216F035 +:10DB500007AB7A0DDAC7762DFC0EE2B3B4AA7B04CC +:10DB6000DA1591AEE3ECEFE0FB7DE108CD2F5295A5 +:10DB70004AFB715D2AE7AAB8B43AE9C7FA57C73C2D +:10DB800004DB2939CD307F2ACEB4F57A669E7786BC +:10DB90007368FCFE7D43974FEC1B52146F69ED1BBD +:10DBA000364A89D7284E621AD72B1DF194B144C743 +:10DBB0007D03D713778F5477A31C8E0B09BC44FBCE +:10DBC000E87D6EDA4F803D5F117A6A2EDAF3D6FC7B +:10DBD0007C627EE1A25EFABDABEFFDF37103E10B67 +:10DBE00056778F906CF08D0E89F995F7987E84AFFB +:10DBF0000AE687F36F87F945079F5F58948763FBB1 +:10DC000072B0BF4C3F26D12392F26A488F483B6FD7 +:10DC10007735B4C37EDC7CF0B8C0CF68841DD707ED +:10DC2000C369279E2D1EEA216460C45BA565BFBA47 +:10DC3000D63D3FFFFD9E906B3D7A3152DCEFBF3306 +:10DC40006DF6ED433297D787E260FF15A3BEE7F785 +:10DC5000855047601C53E8618F390CD73B48513FD2 +:10DC600085BA65739CCD6F15AAFAB3237E693476A5 +:10DC70009C6D3F2AF6A1E12A4EDF20F0ABD7B61FFC +:10DC8000FC5198EFE37F14E67EAE6055430CE574DB +:10DC9000E0FE93C39B1BF3A42E423BF1429EDF3672 +:10DCA000D943F7E1C7A17C16A0FD728FB18446EE7F +:10DCB000ADC5FDE9C6AD2AD995A95DFCBE526A3253 +:10DCC000B727BAD3EF737B3CA5D2B9BE59CDEFFBD2 +:10DCD0006FAFD950782D8E5393A8F2DAF82752936C +:10DCE0007D1FFEAED8CFE3F22DFC2E927D5DB0F20B +:10DCF000EE763EE17FA13FF457691AAD8FF127E53B +:10DD0000C27A9473AD90E26447443C8E7791BCA98B +:10DD100030F7AFA5F9EFE558FE39EF918DFCFD9F87 +:10DD2000CCEFE58C8860BBA8F3DD1FCB6FE79BCC05 +:10DD3000F11B8EAA146C16167E9DEEB487FC19DBBF +:10DD4000638902FBEF37CC8970FF936AAADCAF309E +:10DD5000D1695F4C8DF0DF0D982CE095D39C6FDE80 +:10DD600010EBB2FC93A9FC3D971EFE5DA962B4EED8 +:10DD7000C17C8EBAE6F19E6B1E5511C46F59F679BF +:10DD80005874FC2CCCFDDFE8EF40FF8322F44928D7 +:10DD9000E5257A6FA9EA217D6AF1D57213F80ABEEA +:10DDA0007B76FE8EFC1AA5A89F80DEA9AD6EBFC64D +:10DDB000323FC2BD11EC1FF4B73BFC1B367D84F82B +:10DDC000C37EDB603CB49BDB584243BD61422F64A1 +:10DDD000CF747909AFE14E29CF8ED7D1218EAFAB69 +:10DDE00010AFA49F9FA6F1B7C64B28FEB7B5E0526F +:10DDF000F23B05DBC77AB0DD74616FB58A38E04865 +:10DE0000919AA27954F7919DB1FBC2DE18EA794B41 +:10DE10001EAC712CB84942EDF1DC5D5E4E0F8B2ECD +:10DE200015FCDD0E2F330DDC6F65A1C732E22BDD53 +:10DE3000F9FB19163D9E15E710FB7B6646ECF10BCE +:10DE40006EBBD7B26FDDF6EBB0B04EEDC332D8ABE0 +:10DE500095197BD65A67374AA957BE8AF2FA80AA23 +:10DE6000737F4422F60A1479C786E89EF1437277DD +:10DE7000B092FB43F9FB58820F8F0B7B52DE3A9531 +:10DE8000EC00A553CC7B87C4E77B763E6C3D131F2B +:10DE9000A2CF0AE1D63E2D66C6109B1F673623FF30 +:10DEA0009796E279CD54F97EE6D332AA97C53F54CE +:10DEB0008CBFC7E2F60B813EA377C0FEBFF1070916 +:10DEC000BF1E937B634E3FCFFFB81F687FE4AFF068 +:10DED0000331979FC7EDD771FB892CBF0EFED9FD8B +:10DEE000456E3F4F11DEE22D453FCFD3910B507F62 +:10DEF000367A487E4F093FE4E68E7973CD9ACCBBE3 +:10DF0000184A5A263865533DCA7F0F93CB9BA5D735 +:10DF10002D3D9F45AFFF6FE2C341F4FA1F72988811 +:10DF20008F15F2156532AEE70F3DFC941FE3625F7B +:10DF30000D0BFD6CADF7B8CEDBD6F530AEF313CEDE +:10DF4000619D17F238F87E89CBDF2DB33D01843B0C +:10DF50005FCC37AF8FA7F9BDE2F76D984269A7781C +:10DF6000B7316F9E13AFE71F74F3F37AEEF7F71B29 +:10DF7000D14B50BEE679289E75EA4BCE7AF38A9F44 +:10DF8000892E0410F3E7703AF4B70BB1824548DFED +:10DF9000D932B5BBE094B35D067E515FE3707DED91 +:10DFA000D3B3D48BF2730837FCB3FCBEECF0C78C50 +:10DFB000826F4733F05F1473D6AB5DF24CC177B21A +:10DFC000C15FC486D65665E0BFB8DC7766B8740E0C +:10DFD000FFB7AACF52AF2C3BFC0BE70D027F39FBFA +:10DFE0003ADEF7F94EED59FA1574FD6EFD99EB5DC9 +:10DFF000D9E81EC774DC5F18C0474C21FD9DDFC700 +:10E00000FD32799A42E997E72333BAC0C6476E7E5C +:10E01000983F51217E19C847827E820E67E50FC165 +:10E02000476E7E38573E72F347868FCC824B6D7CAD +:10E03000E4E687CBD728A4CFF2E730FA3DAE817C67 +:10E04000C4DB9D953F041FB9F9210B1F115FB8E197 +:10E0500077F3C9FF387F680AD73342BFE4E97F29E5 +:10E060007FA4A30B6DFCE1A67362C61CE28381FC56 +:10E0700021E822F8E3AC7417FCE1A6F3B9F2879B20 +:10E08000EE19FE48931EB1E077D339B97E4C1E3F9E +:10E09000C7EFE78B73A3B30E740E9DBBFC333BBC81 +:10E0A0002503E9FD17D359177416F29F17FF4BD7B5 +:10E0B0001358176C7476D36BD125AD44CF81741689 +:10E0C000F815743E2BFD049DCFAAB707A1B39B7E24 +:10E0D000193A336EB7CCE3F6A69B7E40E7808BCE31 +:10E0E0005F8A7E67934F377DCF46472BAD1FE47E17 +:10E0F000EF7BB9DC4E3985861DD6CBC95EEFE35C7C +:10E10000EECF9E982BEAE53AE3B4ACF4BF457FDF4F +:10E1100013F5F6613A3903C7DE0D0DF5E8F7DBF7C5 +:10E12000A43E7C816D9CFF0BC280523A00800000AF +:10E130001F8B080000000000000BED7D7B7C54D598 +:10E14000B5F03E67DE93493233E4319317332181D2 +:10E15000A0894E02A480783D7980E1A19D205540A0 +:10E16000D4415E010209D42ABDA5971308AF346AD1 +:10E17000120382459D00B1145FA1179522ED0D0F8A +:10E1800029F6EABD915A442FA5817A3150C4D85A54 +:10E19000A5F7D3FAADB5F63E99334302787BBF7F3E +:10E1A000BEDF8DBFF6B0DF7BAFB5F67AEDB5F730E9 +:10E1B00056C7D828C65AEAD8F48E7C067F3E696ACC +:10E1C0003C635FE3DF6D8CB99C12959F5DE5648ACB +:10E1D0002592DFB4C13F81417D7763E13AFCCED91E +:10E1E000308829798CFEBE66BAF697873065502450 +:10E1F000CD5898FA738E878E1D583E94CACFAEB212 +:10E2000052FF387EB0A0BFFEE306E8DF7B8DFE3311 +:10E21000A89C3195B164DEDE9AC29889FF931912E9 +:10E220000F5C302431B636C3EC33C0529F77B32A2B +:10E230008483D69FF6356598CF48374183A472A56D +:10E240005B9B47366305023E2623FCAF08FEB7CB37 +:10E25000A05A12AEACB746867E1D980A79F4F01D1E +:10E26000E594A9BD356C54C2087F23941744CAEFC6 +:10E2700010FDAF91022743304F35D31C68F731B6FC +:10E28000FE568E2FAD5E25D683F595380D629D41E5 +:10E29000867034398E9E94603E26AB4335D0FC8D1B +:10E2A00017BBAD9179553A19F5CF58A7811547E0BD +:10E2B0003250FD35B7621E7C9359B8CE7FFDFD8F7D +:10E2C00072FAE85BB0C34CED59BA399C2B45D60BBA +:10E2D000F0A17C75390BB7437E86956DB0023CD7B3 +:10E2E000494C718C847CC94AF9F8E704FCA58B7908 +:10E2F000AECF653BE59B216D64472C4588BF5A8FA7 +:10E3000003FB4933FBB07E8EC7DC29C3FCD6353313 +:10E31000351BEAAD5BEB502D50BE2E3E3B6C80F9B9 +:10E32000AFFB8A8FBBEE3E5F7835F6AF28BE24E8A0 +:10E330009F86F2F1766E6C5728EACD7686D7403B01 +:10E340002FEBB23143A47FC6325DE7E2186631A2FB +:10E3500043A71B2B5D4147113AE5F498BDD198675F +:10E3600084F57DC6EC01A4BF35AE5A8B0DBE2B9A49 +:10E370008AF35876A47EFD2ADFB87A932E6D02FCCC +:10E380003BAEEC77C5204E4FBB5DB5D38350FEA2AC +:10E39000B46C7A504727E75C9C9E8E0BBA6323834C +:10E3A00056A413E8F1F86DB83EA7EC6B90F0BBDA19 +:10E3B0003A09D3AAEC94000E61CF54EB22846BA3EC +:10E3C000ECCCA5F46AAAAF427DC4E311E7831BFC41 +:10E3D000B08E7A551E61F1617FCA94428063A2C0FB +:10E3E00053B851E6F8CD63E15C80DF8E46396D0E9F +:10E3F000CC6BA8B3A814F7F791BA876506ED9B2BF1 +:10E40000184B85FE8CAC5335E2D770AAD30AFD3D7C +:10E41000567E369883FD489CEE27181C6993A07E93 +:10E420004BD82823DB38D836F44D13A47794CBCCC3 +:10E4300002FD2776CF9EC2002FAF3AFDB44EE3A96E +:10E4400089E719D06773E37627F2855D6D29DE10C1 +:10E450007CC36DEBD270FC8471C6B37D748BFD8D73 +:10E4600037A77543B96364747E7886CFEB84FA76F8 +:10E4700006F9DAFEF6F36F27EC9F5C4137C726A654 +:10E4800048DDF9B80E5D7BA8E76A65328ECB54474C +:10E49000D2B91B19DB03FB16F7C92E59916D089FE2 +:10E4A000D352A01D8A7736AFB38474F81D9BCCF18C +:10E4B00056BF8AE57E087490E79783C82FD64A9C9A +:10E4C0000E8C0EA6205C34FCC67EB337962786FAE7 +:10E4D000E16B7DFCCD3A645CFD88487AAD89C3D997 +:10E4E000E8EC929D0057DF5E67611CCCDFA7FAF66F +:10E4F00075C33C5B0AB20A71191ABD1D9D3874EBD5 +:10E500005CA8B7FC454700F1613F653983FC20CE2C +:10E51000DAF8297E5B0ECE603EE07B712B9272733F +:10E52000601CBB2F253707F8B2C9A9305CA77185DD +:10E5300039F743C89FF0727E6AF755E6D9B0CA9999 +:10E540009B03EB6F5D65A56F8358FF8D2F4F497C53 +:10E550005007AF8F04DFD4D2C6157101FDFA925D6A +:10E56000003FE2C7614FA58E1F3FEBE27C54EB37C3 +:10E57000767CAD9C8D54BCE3010EE189666703E0B7 +:10E58000BBA4D298B608D6DFAE9A9D48FF2D75770A +:10E5900037CC427CBE63209A6899684E9BAF5B97EC +:10E5A00046C7B1FD9B45FFBBBCEA535200E9E4EE10 +:10E5B000496F79206D539F629866D3781A19D458A1 +:10E5C0004CCF98A4203D23E34E03FED39C3E4985C7 +:10E5D0007E77B9D49932F0DEC76C150D47C6403A44 +:10E5E00057FD4082F4D624D6598EEDFDBC7E5D6B7E +:10E5F000DD0615DB17F0F4BAA4FB26613A2CD6939E +:10E60000D466267A0EB7D5BB719FB4564E4BF3C174 +:10E61000B7BD30EC61D0DF59D7A7C7ACC0E79224B3 +:10E62000DE9EB1DF54E07CDA453ADE75BC02FB2B9E +:10E63000A9CC7912E1B1A3CB44F4B1E3D87766E277 +:10E640007EFF0CE085CC369CE9F306FB8177FD2A42 +:10E650004F6E2300B011BF3AFE67727A725FD0E945 +:10E6600003F181E87458F279717EF7C1F846587F5A +:10E670008BC9B715E17747F36E9E8EF779111EB7F8 +:10E68000366FE7E964014FF5299A7F8B97A7735D91 +:10E690009B69FEB1F3089B585A20FF3AE621EAFD38 +:10E6A00077D731101CAE77FCFF8FDBCF0C38AEDD97 +:10E6B0007EA72B9A0F5CD18FFFFAFAF97BE9F17FE5 +:10E6C000DBFFBF6D7F9F2B9BF8E6B5E981513DBB1A +:10E6D000CC42C8DF374D2BB5CDD6F19D82642ECF0D +:10E6E0003E7232A1472B648FB46F9A6043F9D9B25E +:10E6F0003260578680FC6D9B6647B9D5125CEDCEC3 +:10E7000045FB01F4296479F55FAEB1A25E525F2149 +:10E710003B57437A8733DB86E5CD90C6F2E6A452B9 +:10E720004AABAA1C40B9B036C96D9BA3930350AF46 +:10E7300002E5527379B677BE6E5E2D421EB19530FA +:10E740002368BF31237B7B835F670709FDA0A5AEEC +:10E7500074E270183F8CFA1DFC1D9938E118EA69C3 +:10E760002DA0A759484FCBDE9883F353E400CAA9E4 +:10E77000A1223D44310620C9866123A8EF76B270FC +:10E7800027F2E5D69F2D473EBDCE0983C378431AB5 +:10E7900043C76E8374A247F6A1FECC1A41CF053D54 +:10E7A000CF853A0E747030985D67443E3F9A119F52 +:10E7B0005F87FDA1FE1E609AFE1E5F087A129964B3 +:10E7C0003E94F7E326E5E0FC403FC4FA9A9EF67ECD +:10E7D000929FE03F08F5384887D5A2069CE7A680BF +:10E7E0009119A09D738A4EFF6257EA6FC926A6E071 +:10E7F0003A92879BC32A8CEB88D1D762F5B23EBD93 +:10E8000020087A85AE9FB83C6754FAB353B733D427 +:10E81000CB9BDF603B51B95DFB06DB4F4A6ED39368 +:10E82000048745020E7F5C1518570F08CE919C7621 +:10E83000340A0C430A7D0CE8C66668B2E237470E1C +:10E840003C5E02E31E7BC94EF05EEE3287113FCD87 +:10E85000E3EF9E8EF0EAD91ECF10BEF526E7569460 +:10E860006379C95F6E4039D56CEADA8D724C664FB8 +:10E8700034546482BD63E4F86A4FE2EB6CEFD87BFA +:10E880006137E1DB1A40703F56B1BC02F5A91E9911 +:10E89000DBB5CC18F454023DEF79D13C9DEB3F4100 +:10E8A000D27F76B5DD9A87E32C79E2D58D36B075C7 +:10E8B000F6C892D02F008EA319EB403D80D2F37E94 +:10E8C0005D9E437A27A5E35B9E6B40F9B876007D99 +:10E8D000E90EB19F3AC2F142BEB63594C09CF7949E +:10E8E00032917E6D9292C158E11A49E80F2F36603D +:10E8F0007A0F926F1A87BB0C30DD63D6EA1F9854EB +:10E90000358EE637D9007BF9974FFC78A3634C64CA +:10E910007E39EEFF7C53CDC1F26555FDE913DF4230 +:10E920007D15E8AA6324AB407840BBE961DDFEFBBE +:10E93000E5206E3FFF5A7C61DEB20FFAF11941BF4C +:10E94000866FE0A0D1BE48CF2FDC765A5F9585D583 +:10E9500062F9BE6ED93E5BD79F2F49ACDFC8E23E5D +:10E9600000BCB81ACDCE3A58862B7C2BE93FA60CBA +:10E97000339300CF725257513E94E7EE75B0DB816E +:10E980007ED66F0A905DB2634CF8B1B188DF4C3926 +:10E99000A022BF08DF58CEC01E6D8F7710FEC2BB0D +:10E9A0000C15CFF5A3478E4A32D0B8EBD5A2DA8545 +:10E9B00030CE058783ECB8E78D01A2AFE71D66A7CF +:10E9C000CA8D5C2FF2B71C399C86FA50B0257B6348 +:10E9D0003DC03747C0FB8DA4BC8DA40F3A3BEECCA5 +:10E9E0008679AC07FB0AE7B13E69AA15EDA8E66097 +:10E9F000AD1559C3CF0ED656F891CFE5CA6C358CFC +:10EA0000D35CC2F5DB9C64F724A4CF9CB56E89E986 +:10EA1000F6D907020FE100A75F3549F00723CC03C1 +:10EA2000E1B2AB3880FCCDE26445B85E5346ADA29E +:10EA3000F483CFF3A21F063AADA398B620EDBF949E +:10EA40008A133F40BED163EEF83784DF7A973DB03A +:10EA50001DF277D83A12B0FF14B75DC6F5A732F8A9 +:10EA60007F0055BD0CF8417B328339EBA05E6AAB69 +:10EA700099FC1929AD66B2635A5499F8D8DAB92CC1 +:10EA80008CEB4855E533E8E749E9FE74158EE34918 +:10EA9000923BCD989E65663E1D5FF29C3AFF15DA6B +:10EAA000A11E06F93A7E733131B8CC0DF3B6643845 +:10EAB00025B207B16E31DA95FCCFAECAAA05FA7D50 +:10EAC000B18EF3CFF53F64E1ED12955B5714F1EA97 +:10EAD000E8AF318BFAEDAFB017104E666B6397213C +:10EAE0004107D7151CAEE6D675CB701DE63CDD3C64 +:10EAF000E07FBF446707CC239301B707BEF447C646 +:10EB0000F705FE19A1280B71024BBFD8F1071BDADC +:10EB1000573D66EE57205BA458D8F73A3F458B9B8C +:10EB2000CBA1D87E064BBC9E967E86F17EF71C71EB +:10EB30004F46BA7F76457621F2F57A8D4F31DE3F2A +:10EB40008A35C44FB2D3AE0C87F97F3789F7BFC778 +:10EB50005EDBEFFE5E91C4EDA7E63701B1008F3DAD +:10EB6000AB7DDF45BB74FD66996D87AE0EB6723C1A +:10EB7000B63432E2B72D4AE03753707FD51A032AF4 +:10EB80008CDF9E27F869852F5C27FC4D2ACC375EE9 +:10EB9000CCB73D236837201D8C67CEED80C7F87257 +:10EBA000A6D86E22BEDA80ED8694BB19D22D03184A +:10EBB000CB30FF38D12EBE515D8674D09C11984960 +:10EBC000F033FAA4CA82083C1C028E7115500FED76 +:10EBD000E6A4571F41BF5AB87C2A43FEE34882711E +:10EBE0001278BF48E4E472027C391A79BDC469D155 +:10EBF0007447FC12E97E29D00DCE737434DE5B04B9 +:10EC00007CD28DACC20CF454E7E67268C7420E9712 +:10EC1000B8404C7F76DFFB55044733C37D94B53253 +:10EC2000BA3CAD35A514E92E83E9F261DC936E1789 +:10EC3000E12BEDD8B6A932AC6B6D15930D382E5380 +:10EC400095AA228E1FE41BEB27C8D46F7AB9BBD4D8 +:10EC50008C7E9A7259413CB9AAF2B7A35FAC4FCFF0 +:10EC600049724A45F958CF593AF426F2D772FD2233 +:10EC700005E81CC64B3FD6FB5D845F5A75F4FC98D3 +:10EC80007EFF19AE9D365913D4B89BD01F1ABD6FA5 +:10EC9000DF1AE4EFF323235D709735FE1FF7B71AF1 +:10ECA00013983D0FFD9B0D32F971D0D79801733445 +:10ECB000BD20ABA9D09FE505BEAF4D1D46755802DE +:10ECC000EA214C316379C6DF2CFAF9EE7AC59186D8 +:10ECD000780F0B3F9F41E8AB1A1C1A069909AE0D3D +:10ECE00082FF95BE9651867ECFB5995CEF0249446E +:10ECF000FBE76131F71E39B8250EE1F481856CF32D +:10ED0000A263EACC7F85FACE72861E63B6DE586BAC +:10ED100075E9E5160C2D7BFEFBDF16A11F85513F23 +:10ED2000BA99FC1F3391BE34BDC6D5296BF25D4143 +:10ED300051DFA76FA80D1B51BE1718BA6EB0823CE9 +:10ED4000DADCB473637926CAE1CC1B8DC073760F0D +:10ED5000EADA684AD6E90BEAAF362AE3AEA22FB068 +:10ED60000F2656A17E91A1A58F4E54403FE8B08A50 +:10ED7000B4BAE94D942BF526F525E4698B92985A9F +:10ED80003E1AF99C56BE75A3027079D1CEFB5FD4B2 +:10ED9000BA75A39A716DFD03F6A93D187F6D38858C +:10EDA0008DCC8EF2332CE0E11FB479629D4E7FA9A9 +:10EDB000DED53509CF1D34BC0C16FC15F4CE0EDCA7 +:10EDC000BFCD42FF6C4E1E4AE71DEEB05909F7A3B6 +:10EDD0000F8C1F64253A79354EB96DD0A86BD3D707 +:10EDE00078415F7F75737E5A60E0FA4D6CBFF70E15 +:10EDF00012E53BCCB5386EE96B0EE2232D7577EF4B +:10EE0000443E523A2C7F6B1CFAC9DEBFC784E91915 +:10EE1000838CD46FF8E7A1614E2EF7D2104EE80F25 +:10EE20002038BC324EC675C4C26908AEAB9FFCCA5E +:10EE30004136717EC1661E1AC9CF17D01FF7E26A2C +:10EE4000900FFDC061D1A03E3F2A53C8D871927D7A +:10EE500097E352143A2F4A0AAA8CFC12325374FCDC +:10EE6000526B6FBC9C1E75DED4E65418D6375ECE4E +:10EE7000A2FC1463B07A10C0E3A95747DF89E2EE21 +:10EE80002921CFB29CCA5284FB671B4646F9F56321 +:10EE9000BFD7EBE7FF81F06F7E537B648D5971A381 +:10EEA0003C6D6381807B08E2BD298072642353B28C +:10EEB00031FFD84B8B9A4AD01E79DB407CA45E523E +:10EEC00097CEF5A33F582D46BFF7B5EC91D87D5BA3 +:10EED000A430A247A39195239F1B8C861FFAE37D44 +:10EEE000329D93998E703D0AF9237E0D20172429B7 +:10EEF000C2378C6123951B4E5954942F06751DE91A +:10EF000037466790FCC64139B40DE1CA9A8095C274 +:10EF10007A6D1C65CCE05018DAEB03F185BD4F3CEF +:10EF2000367103EC63C311FB19EAB7538C7F6A3D5A +:10EF3000F9ABD916E8AF38D21F8CB30BF16ADD17E5 +:10EF4000EC8CD3F72FEC98DD4FFC68A33AEE2AFD4A +:10EF5000355ED1DFCF70DEB1FD697CEDF1271A2778 +:10EF60005EB5BF9D57F477A0BFF9697CAFF189C743 +:10EF700037225F327672F963C47EF18BFD41BF5652 +:10EF80008027D211F47394E0592E45F58F6620EE58 +:10EF9000D3587B49FBE6B839BF88C5FF8B75B5D31D +:10EFA000FBDB8717DCDC2E8A9597269497455C4E11 +:10EFB000A6EAE8C282F2F2A681E5E59FDD4CE30312 +:10EFC00044079A5CFE2A31F47B848B2589AFDB925F +:10EFD000C1A410E997DCEEF97BED8F19823FEEB00A +:10EFE000B1863CB42B26C84ED42335FBE1C53AE7A5 +:10EFF00044F45BAC7F540EA0FED9673708BB42B324 +:10F0000053EA914E492F95B7E3B92AD81B93C9DE2D +:10F01000007B041D4BED304F1BF2F9D6A2DF4CC133 +:10F020007AA0AF929D136B6F083BC433373AFF62EF +:10F0300062484A02F8382A64D25777E42DEFC47543 +:10F04000369433EA27D62E88D52763F5C758FD3086 +:10F05000561FCC7828463FFCC6FA18D7A7AE572FC4 +:10F06000C3BFFEF431D20F69FF7F8FCBF13A9EEE22 +:10F070001AF43D92E355715CAE1DE895C93E0F3719 +:10F08000A6B871F81D263699F4E7F13E37DA8905FE +:10F0900002CF55894E09EB81E1E8C473783989398B +:10F0A0000200C75C552E044E0C76BBE228443DBAE4 +:10F0B0004E262B6DC718B0EBF15CE81507D9CD11C2 +:10F0C000FBFD85C7C6A23E06763D9DA70E60C78F95 +:10F0D00013FBEACF6E278D6F303705F2913FD6DDF7 +:10F0E0009D8674DC6E0A92FFFA67C22FBA577C0DB8 +:10F0F000E21C492B7F55F84BF70D50BE5F941F1053 +:10F10000DFD8F25F8A769D03B43F24DA1D19A0FD93 +:10F1100051D1EED800E5BF16E56F0DD0FFBF89765F +:10F120005D03B43F2EDABD3B40FB13A2DDC92BCA01 +:10F13000B97CFD40949F8AE9FFB4A8DF2DF2CD2E63 +:10F140001FF75B0C703EF6A29FF3BBEA235D8A3F7C +:10F150002182C77437D7D3357DEE9AFE2B61DF62EB +:10F16000DF684792C93124D2DF8F05FFC4BFFAE2BE +:10F1700088FDA8F1B3DC913C3E43B343357BF1E716 +:10F180006E1FB573B40ABB957530AE7F5D1DCED3CF +:10F1900091E693E99C90FC3A487FF374F43A2BC9CA +:10F1A00044FDEE2AE4F08CC067A8ACC14786FCB9E8 +:10F1B000C27E37BB38BFDEE58AF4A7F7835708FF66 +:10F1C00055F81AF4599EC4A2EA0D4447D3C4FCC3AF +:10F1D000D7A0E78A98FE06A2AB5931F506DA5F4A56 +:10F1E000CCB803ED83604C7F2F89F20EF11D2DFC0E +:10F1F00088D7A2BF583A0EE3B9F0581CA7A841D54A +:10F20000F963347A71A832F91592596F147D24B0DC +:10F210002E1ECC22E8C374D9CF9411C45C496E76FB +:10F220000FE2F33019830CF576D3E51C2AD7E24DB3 +:10F2300036F856BB317E646D5252217503FA03FADB +:10F240003B6C621FF4E921182780723E49257D45F9 +:10F25000A7D7BD9784441F8ED6EB343D44F33FDFE0 +:10F26000B1C93C91FC9323B9BF5FCDB3921F00CCD1 +:10F270000CCF20E4C08629013C777FCFC5E9E95A4D +:10F28000E706D73A27B8D6F9C0C5A4F8248C0302FC +:10F29000A91A407935E1E5FC960A8C8B78C740E7DE +:10F2A0002D8F34A99685EC4A3EAFC55F68710D5A23 +:10F2B000FC8516EFB009FDFC78AE93E76943BF9477 +:10F2C0002F99C3F1A02ADB51EF689FC6CF73DA8F65 +:10F2D0006DAAC0F3A5CFCA6527D2459E293811D3A0 +:10F2E000ED41EE3FDED03A75D270944F61239D0F11 +:10F2F00044EC0E4FAEDEEE18EAAC2DC5F2F669A571 +:10F30000E4E7ADFFB2CC8AFC68BD33DB8676A3763A +:10F310004ED552C1CFAF764C8BCE1FE8FC2A76DD9E +:10F32000FB5D9CAEC3C25F78E3E11995185791ABC2 +:10F33000BA0B6D5C8E939FECAC4BD0CD0A03C589A4 +:10F3400024A31E05F4930BF617E25F8B1F49663A60 +:10F35000FCF831FE85D373018690A12EC0009E1A61 +:10F360007E0D57E253AB1F8B57660CE421DD5D76B3 +:10F3700039A95CE3E303F1FBCB625D4393F9BEDEA5 +:10F380006454A7923E07063FF2E5834953B9BF1C78 +:10F39000F106559A8F99886F7F06F48BFE653C972E +:10F3A000EC2F5E47C3D347229E2E165FBB4C2A9D8F +:10F3B000AB1F6A7BD883F14BEB7F1E1AECECA71FC7 +:10F3C000ED5B27FA01F0D8D09E068E6893477F2325 +:10F3D000BB6872723F768C6617D56CB2929E359080 +:10F3E000BDD767DF09BB4FB3F3747C607A32C5DBEE +:10F3F00048FDDA77DAB952D926CB9BAAF17FD4AE91 +:10F400005C40E37E43BBF27ACFA7BE819DF8487F84 +:10F41000F0D5ECC4999B6CDFD44EACEB175FD7F200 +:10F4200067F5C5CF2A0E09FAABD6D8315B467EC642 +:10F43000EF89BD522DE2EEC61B1CC4AFEC3B25F29A +:10F44000272F568D34AF6A75F532F403D33907D0C0 +:10F45000FBC2B52CACFAA99CF6B3D67E7187857534 +:10F46000EAF6DFD2BD90D6F16D3FE371650BC10EB8 +:10F47000E8D4F16B3F9E1F276079743E33CC4A4439 +:10F48000BC626C657F71992B4EB5DD7244D77F7B72 +:10F49000B2E0E3DF62DF227B44B41F681F7DB12A44 +:10F4A0007CCB11D8972592F27CB26E5F323CDC06A1 +:10F4B00078360C3F97D7DF7ED6E03A674519FB03D5 +:10F4C000F0AF57CDCE128C07559F9128CE774E398D +:10F4D0008FB71B1B96C84E9BF3FDC52390CF8DF9AC +:10F4E0003060C673C6A55DDCBF926A5856F843F813 +:10F4F0006E3AC41E088AF43294F70EC587E762B3E9 +:10F500007128687FD1545BE84439799F43417B7708 +:10F51000F634E57D3C3F983D2BDF8A709BDD6153DF +:10F52000E86B65463BCACF2FBFA6B8E07902DBB3D4 +:10F530008DCC8AF9A96666B4C1F7B5D64A33C6F54B +:10F54000A5DA9915D3C5AB617C8053C2E820CD6F95 +:10F55000F6819FFC05FB5B60EC3C48F1D3223E7BCF +:10F56000F68137FF8A76EF3C256846BDE5C65D66C5 +:10F570007EB621E05FD0119DBE795F74BAB0333A98 +:10F580003DE25874BA020F0201AEAF7F65601817F2 +:10F59000DAFBD3383A07590CFAF13FB8F934D0D72F +:10F5A000B0E8F982368C777DF56FDFFDFD0F21DD48 +:10F5B000FBB681ECF4576F001D18E1670C67E1FCA6 +:10F5C0002E3CF59367BE0FE51776A7A225C80EF56A +:10F5D000F078D6C5CF5988BE2FAD0A8C2B07BDAEAB +:10F5E0006CF1812CE4BB97F6FDF33358FEC7972CE2 +:10F5F000E4EFFEA3F0031EFC60FFB9A770DC97E206 +:10F600000A91EFFFF1C5D786229C163DFF8B2C8C0B +:10F6100043B9B0FBF9624AEFFEE94DF8BDF0D39F64 +:10F620000C9D4DCA5A380BCFE9B57E16BF603B33EF +:10F6300008E077EE638703F9592C5D7DD37E17A32D +:10F64000FF97FA5DDF3508F7DFAE7815BF8B76FDE3 +:10F65000E853FE95DEE1DF3A2A5F0490190D703C15 +:10F660001FCFE5FAE25D9628F80FDB128D8FF3A02D +:10F67000CFFC0CEA0D0F47E79F03BDE067306EDE5D +:10F68000A55993507E9E177ACF39F8EE81FA3590BE +:10F69000EF82FC4B423F885D677A0AB7276AF645DE +:10F6A0008FBFDFD87F7D7F0A97CB797872AAE30F6F +:10F6B0006996FEFDDBC344FDDDBBFBEA1BB87F02A0 +:10F6C000B613D0D862B1AF5E97B4FB13ECA174D877 +:10F6D0002F8BC579A796BF98E9D64DFE8A4022C2E6 +:10F6E000FD1D111FF18589EFDB0BAB422330BEF707 +:10F6F000DCAADAE1E53A7D6CFE966547BD4037D578 +:10F700007B928B28C65CE457FFF47002FAA56EE882 +:10F7100030913CBBB0EBF0E67948A71D2616E7A375 +:10F72000F2142CBFD8F146C2BD903F7F9BAB08CFEF +:10F7300059B5F60BB67C6F78B98EEF7DD37DA8F105 +:10F74000876A2787C36BA3BB26A4C37E5BBC450A1D +:10F7500060B5C51DDFB9EB0EB46DB619C8CF516CDD +:10F7600064414311AEE395A369905FF38B51C5B833 +:10F770001EE8621AE637C8C1C905C89F9E31913F8D +:10F7800010F28FC9406787F25ACC67611DF7A670E7 +:10F790007BA9E16E4715EA99D0DF11F4B424EC940B +:10F7A00014913E89F57B4A3B12D07E396F726C9082 +:10F7B00012914E6B7F83F3505FE4FDB24E3EEF85B6 +:10F7C000C23F5E75C044F6484DFB9A8412B4E7FE12 +:10F7D0006690308EA9B75D227EB0604B347D554176 +:10F7E000DF1E18F7425B3CF57F21399C857AD68570 +:10F7F000F870969BB7273E58B5EB577F45BEB7309C +:10F800001CDD3E961E568975C15F9E9EAEAEA41B42 +:10F8100066341647CAAB57803CD09D47547FD864A6 +:10F82000467D7DE114F355C77B1D6D0882878DEC05 +:10F83000A5C537B0721F8F2B90ACD0FF05FC17D831 +:10F84000838BA7B20A2D9FCE1390AE8164FF7CEA12 +:10F85000578F1980BED31079806FF6721CF94FFF55 +:10F86000F8B199E4C7851E502C60DD4B3D23C69549 +:10F87000EBE67771DFE1049CDF455F67821BE0B553 +:10F880001FF735A69D3CBDB8A781FCD1751D871318 +:10F89000306E6971C7203A57DEFFA2E49601CE1799 +:10F8A0007B9E8B63FDECD3453DFCDC38960F69F203 +:10F8B000F50CFE13E4F0CE14E5D914D477EB0791E0 +:10F8C0001E903AA8B6B0B69FFEB4763F49F1D17704 +:10F8D000B6C4DBA71A9653FDB73CC1DD2990EF29CA +:10F8E000ED52F0FE9067120BAC812A7F30041E7639 +:10F8F0000E4179193293FD5C9F4CE32C608017C850 +:10F900009F63649D46A0CF3928776FA234C16FCE24 +:10F910002E298C2A5D7CA325EA9ED3FC564BD43934 +:10F9200014DBA62B07F82F44B99A40E73C9DE81753 +:10F930005DB433BAFE62D649E356BFF0B545DF2F5A +:10F940002AB65CEF57CC68D7FC45C0E72D8F7218FC +:10F95000E19324E2077ADF3671B9C982FF80EB595F +:10F960002CE4F83CCB415A5FCDF7BF3F7C2EE82317 +:10F970009FACF8C1F0B983845F01F7FB1689D355BA +:10F9800039EBCC84F9CD14FACDE203526701A4E738 +:10F99000C1BA518F18FB82A4C683FC9A67656A02BC +:10F9A000D2D9BB1C2FD5623D582FB108E1A7D27820 +:10F9B000A7043E16B22E5A17C8AF352930DED21E24 +:10F9C000E009903A76B03811E9E6CFC05F713F8226 +:10F9D0005EC26CEE2BF11B0BD7AA6D3170D6C33112 +:10F9E0001BE1178D97A57B019EFDD0D926C1EF4F56 +:10F9F00033254ACF64E29EDDA63A89CB09B572066B +:10FA0000F2E9CD338A8BF1BCF271F487A5898E4679 +:10FA1000231F645AFC5DA715C6B18FE84B5379F1DB +:10FA20006A9EFEAFCD2B276F01FD7FB329E4453FD2 +:10FA3000CCE64AD07BB9DE6243BDE54B6FE86BC4D0 +:10FA4000E71C43F0281EB17F58A20C25BA5CC1E127 +:10FA5000FC6451EDF0DAABE8A5A930769C5BCC0FE5 +:10FA6000F5A80207C52179714E901F9FC5F3E36F7A +:10FA7000B2D3FDA954190CC97EE0AD7D538D60AEA3 +:10FA8000BBE9CBE2F10B03C55FA5BEA62FA6A2B2D0 +:10FA9000847AE70DB57B90BE52EFCF2F5AE38FCC1F +:10FAA00073B304FB10F5E61FF2FB337107F674A67F +:10FAB00043BD25153EF23F26DF732A0FE397F2532D +:10FAC000B9BE9028F4E4AD12AB47BF8007E85D2AC9 +:10FAD000C274B37739E48FDC2B915EBD646F8961AA +:10FAE0008983D6CFF5EAB8DA3619C77F208FC607E3 +:10FAF000BC3C3015EDB1541FF5EB75707AF5AC5682 +:10FB0000FDD84FE2A1E0B237086E3CFE0CE149EBB4 +:10FB1000B6B20DA82F7B589D84F5D62573BA5837F9 +:10FB20009BEB4368CA26BAF9F7247CC1FAAD37715A +:10FB3000B819ED3CBF1EC7D994C0E7952C1B1EA871 +:10FB400044FDBF88A7DD2B25653B6DC6668E470B40 +:10FB5000ABC075623EAE0BA6A1EC71E8E05B565BF4 +:10FB600088F3481DC2BF6F755B558CD3792B49D381 +:10FB7000833B1D484F6C9F5746B9F99090F79F986B +:10FB800094D4112847DE3131B45792B262EAE7E4E7 +:10FB9000C928371E1272F6B34059223289CF1C4A47 +:10FBA000A20BBEFB4CDC5E88C5FB03A95C1ED65CC9 +:10FBB0004E67619DFCA899FE39D90B3597B3A2F227 +:10FBC0002FAE82950CD3C9C1AA43747F7409EBA2EE +:10FBD000D0E5251D0616D6EDDF7D363EEE17BFB308 +:10FBE00010BFFA6EFBB0ED14CFCC7C0953E323FBBE +:10FBF000B5E6B281A9B0F76E31C854BF66BA99FCB8 +:10FC00008C351B0C6D782E5773D9CCCB07F3FE6A5D +:10FC10002E0F622A9E711BA19F026CF7E9BA7988A8 +:10FC2000FF5F48147F56733985CA357DB8E6B2C484 +:10FC3000EBC3B8A80FD6ECFB42ACCF48F967E18321 +:10FC4000F245DD6720F93A05E429F2DBB36159CDCD +:10FC500005FC5C0AFC81E4E9592DDE4E8C7B7115B4 +:10FC600030D46191FC4BCE6E92AF6918C781691F89 +:10FC70004F6BF0C27284D3A5E91AFFE83462BF4F1C +:10FC8000050E1AF1BE4F75E0E004A6A397085CE3E9 +:10FC9000F04E5F1F5C53D67475CAC02BB6A5BEFD6F +:10FCA000A37C1BA0F090C6B7FEFD4718D79B6290BF +:10FCB000A3F818C6246971C648229B6483E0835D5B +:10FCC0003F2ACFD0A779FD48FB77269703DF1B9902 +:10FCD000CFDB3F977AFC5F57A32CD5E49AB1372B43 +:10FCE00018AF4B5B63D20E4817E8D2CE98F2A498B7 +:10FCF000724F4C3A83D7BF3FB17B94016CCA3DA988 +:10FD00002726633CC4FDE9DDDFC37B5B8D6B4E4E74 +:10FD10002E87F49C919C2F2D3D2091BF5583DFD2DF +:10FD200000237DD511E836A3FF346E64E0A80CF5FE +:10FD3000AAF74914A7EBE8D8D3897CA61ADBF97493 +:10FD4000ED3AB89E5BDD7186DA0DD87F9E4CFBBC28 +:10FD500021EF2CD55BB2E26333EA6D1BF35B8228A3 +:10FD6000378332E757405E4A3A345CBAAF92F13893 +:10FD700054CE4F2F7995C3381FF517129D73F6EDAA +:10FD80003FECD711D91F5AFDFF2838F05B8C7789DB +:10FD90007BE8D33A23D4FFDD928F46E178FF81558B +:10FDA000C6207F0E0F47B933ABEAC1E1987FDF92DF +:10FDB000DC833885D3A6EEA7317EA437F5D2642341 +:10FDC000C8A3D3F1DD991887FCA7272F133C4F2731 +:10FDD000773F8DF05CB8E5AF3C9DD99D2943FA8B08 +:10FDE00027474EA1FAB9DD4F63FA668F87A70BBA92 +:10FDF000330D4E1415DE29E5906E77727EF80CD81F +:10FE0000CDC857FF23462E7F24F84CF750E56C2AC7 +:10FE1000EADFD55C2E3E0DB69715F8E5FD4F75BFB0 +:10FE2000D80E70B8FF1FE3E8FCB6FDE25D93821CBC +:10FE30004E41D4C35339E9EBE4A391F4254D3E6A16 +:10FE4000F888CFEAF291FC88915F4FA7288B3CC9D4 +:10FE500091EF7FF9F97791C727EC81DA421FF43BE4 +:10FE60006B9623D040F109DDA3900E1FB7F175C149 +:10FE7000FE213C3B045EBE12F2EDAB546E571E4CAD +:10FE8000194FFD81BEAF5A119F9566D2CB5A2B15E3 +:10FE9000AF3D09BF2914071DF17F98C8DE6915F72A +:10FEA0009D5B97E4927FAE4FCFFF8985DAC3761DC5 +:10FEB0008AF39889FC48C7875B179679E99EA05F0B +:10FEC000F1227FD1F826337624A31F5FE39398E6CF +:10FED000FC51A2B4C60F19837ABAFB98F79A58104E +:10FEE000ED837BDB38BFEBCB97203F3FD2CFF5E6EE +:10FEF000B7BAF8BC343999BAA683E24C539FF4BB25 +:10FF0000499F40818B7A59F3B0ED08EF2FBD53170D +:10FF10007946219C9EB33D981FA167E730250FF3DA +:10FF2000678AB8388D6EF00FFD77739E486DC3F801 +:10FF300091451E7E6EF1A10C7A17ECBB935E85FA9B +:10FF40005B84BE76FAF273FD59ACFB7BB83FFE17BB +:10FF50004FFFE378BA0FE9FFBF8BA7252B3EBA3ED0 +:10FF6000BE29F6E566A9D394CAF926F733403EEADE +:10FF700013DED450AD47E717BEFF074BBC148724F0 +:10FF8000E613F7C86B15F740F2FE4517FAF80DF3C4 +:10FF90005DA98F9FFEC0DA88FEBED3E60E920FA742 +:10FFA000C1EEAC433E2AFC82A7C5BA8BFF71F15B60 +:10FFB000687FFFCAC3EFB1A0BDCFF474B531F0DEE6 +:10FFC0000FFBA52F03B7FB7E61203DBF8FBEDA87F5 +:10FFD000117DD9041DA519C25BE7239DDDE3203FF8 +:10FFE000756BAE4C7A51EBF7E3C2A817B5FABB09B3 +:10FFF000BEAD637C4EE49B405F84BFDE1966EA17AA +:020000022000DC +:100000000188F53F999E1646F803BDF1716758893E +:100010007F3261177F52951D46FCDE8241E0589E7B +:100020002B53FB081DF62654EAE8E713E1F7FB041F +:10003000F5A3445DBEF033805E90A07F7FE35AF964 +:100040001A1DA6ACD1F603A7BB0F5B52C96F8CFB80 +:100050000BF7C15E413F1A3F3EE90DBD8C74D7A737 +:10006000676B76FEE39944AFEBE3395D6FB3F177ED +:100070002EF60A7EAF8DBF0DEC12943F608FBF82CB +:1000800074F30034DFE746BD38F4CB6E1C77854649 +:10009000C74133D2DD3CE107602BA3ED568C9FEACC +:1000A0004B1BAE4CCF57B83FFC0A3F03FB9B25BA16 +:1000B0001DD77BE2F27B4D48EF4FDAB89DA7C9B759 +:1000C0002D78B806EBDB02F8C7FDA9D5FBF345BBDD +:1000D0008C71CAC7C5FA8EBD352211FDE39A7D1E0B +:1000E0006BAF2FC52540BF353036FA976BEC3EF22B +:1000F000E3DD62E0FEF6DE764B147D9CDDE715F471 +:10010000A3CCA6F2BA781FD207B6C775D5E4600CA7 +:1001100095AEFE9661BCBE464FAF48829EC20B7143 +:100120003FA90B6F60B83F6AEC9C1E2F6D34B4E1A1 +:10013000BEB8941C5A88ED2FCDB0E38D2156839024 +:10014000C4FED5AF56A1BFEBAC91D30BFAA1F57E9F +:10015000823E3D1DFE8DF71D62F574C8570DFA7C79 +:10016000249994C8F95AB5B8CFB3543E3374B94EF4 +:100170007FC7185CF2C761257F846E107EE38AE832 +:100180007BC440F8E92E0EEAE8BAAF9E7C96FA1BD3 +:10019000C8EE5EBAE523BAB784E76E7ABAA88ED005 +:1001A0008FF4B584E3EBE849678F935E8F7EA0728E +:1001B00046EFBCC48B745C4517BDBB5223FC41C9E0 +:1001C00087BA27E0BE8A1FD9C1D03EAFE9E1FB67FD +:1001D000EC81B6C368BFBB2ABA3291DC6B849F53F3 +:1001E000A3376D9E630E341BD02E39F431A7B3D2E2 +:1001F000B3B36720BF7EDDEE2D453FD597DE90CFB0 +:100200009BACF37BB00EE253739E949C4807AFBB4C +:1002100099E22438F972104EA5667E0EB2A2DB9FD9 +:100220003F4F67978EF2F2B8F509B232CC0BDF4B35 +:1002300003C4658FF072BDABF4B42D84FA58A9DD08 +:10024000467CF0F19661DB2DFEC8F87337FBDD3894 +:10025000FE082FD7D7BEF4064778499F0E14E37ED9 +:10026000CEF6F2388352B32F07EDACD7EDA9A5B87F +:10027000BF276AE7686A490E5EDD2AF570D84FB479 +:100280005A3AE3E97CAD6938F2A7CAB976AE2FB223 +:1002900029442715829E1EF5733C3C3A91FB1B7F37 +:1002A000237524A15C93AD4D0F61FEA49CF800E280 +:1002B000E71DC995897E4EB6D0E43A678DBC6B3395 +:1002C000B09FC6C8CEE9E22A1E9540D176D397FCEE +:1002D00036F05531BD19B70FCA6DBB85E40996F3E9 +:1002E000B80CDF36947B53AC167A4F231EFD5FBCEF +:1002F000BD827E9929D65F9DC475A33F0FF92594D1 +:100300002B5ABFBC9C75E03E6101D345FDBB4B5BE6 +:100310006DDCFF07ED54E4A7F1787D91B7EBE4E3E2 +:1003200066B8F01D166D7D6B4C1D85383F7509C88C +:100330003598DFB612D59295847CDA5688FEDD9D1D +:10034000F1E64E37CC638957DC3B643EB203CF0AFB +:100350007AC8493077E2F9B6467F1E5BC912C4AB52 +:10036000068F3536C00FCAE179F600DAF3380F315F +:100370009F283845E0C2FDEE5368A8085C806ECB2C +:100380009D457AF8383AF13C3C162E03C1435B0791 +:10039000CED79D70255CB6C87B16133FBF640F7027 +:1003A0003F5B0C9C30CB4BF26923EEAFA52C44FE97 +:1003B000E1A556A6A05F6ABE6519F967AB84DF9B0D +:1003C000A1D30FF4924B32E7BB97764B2427F05C16 +:1003D00045CF2FF19C449FAED6FCBCBB62FCB14222 +:1003E000DE2D413F317E3BA2DB016727B958B32F99 +:1003F000D6EFAD46C9E9881F8CEF8BA736FB491FA6 +:10040000EC46608FC1CCD5B40FD1BFC6E5BFE24585 +:100410007FCEE685D945E86F8E33723D725ED3B0EC +:10042000ED75421F403D42F3CB69FBF94B6FE95E2E +:10043000A483ED69A52F23BCC8B933E66AFB89CF35 +:1004400053AB877EB9AB9D532C47FE07FACEBF78DE +:100450007D3C8EF1CDDC5494B3CB255F2A97B3431A +:10046000A3D2E70C213AA7D0FCEA0BF19CC0108183 +:10047000EB7CE18F9FAFF9DF014FBE183CE9D38BD6 +:100480007478F2E9F154CE3AE363F0A46FB714F054 +:1004900084ED104F51F1E1AD7CDD0F0839A1D1ADF4 +:1004A0006B659B81E9FC1489458A7F2DEA956F9ADB +:1004B000C8BFFA9F822E010FC5A817BEE529FD39D6 +:1004C000C2DD8EF64D3EEAF7AC0AF18DFEDCA9E8FE +:1004D000EF5A151A8EF17580D7E2A9FDC8C986FDBD +:1004E000B62AA4931EC1D7B5FC67BD261A9FFCF09F +:1004F000A8476CB408BDD69785FD14676BFAA28F28 +:10050000CED7E78AF3E5A5773B42D8DF59714EF0A5 +:100510009997FB1F3EF3F2386F2DADAD4F8BA7407F +:100520003FB3DE4FFA5F426E68FE5D660C515CE6DB +:100530006653D8368FF4AFA019F5AF3F5DE4747100 +:10054000ECD89C8538CF3F4DB7338C5730A6713AE5 +:10055000992BCEB5FEC47C421F1B4AFA9996EED366 +:10056000BBDA0C517A57CFCE54A177D546C54DF49E +:1005700095F70CD5F42C15F5AADE3D364D6F57F0E6 +:10058000DE81FACA30619F32B20B7A0E6452FD737B +:10059000184701A0ED3186B6E23E533BF8796D8FE6 +:1005A000D0A36A165DB809E57B0FE37C593D602155 +:1005B000FB831955D2A7CEF5E9F3E1F4BB74F8DC5F +:1005C0002FE20FABCD9D43519FEF11FA9696D6CEF9 +:1005D000FF318DF7205F17FCBCDACED36BADA1BC29 +:1005E000B4648CCFE176567502E43BAE073EC02F73 +:1005F000387D107D6239CA979E0305D17AE856AEE0 +:10060000D79E37F1F6EACFFD023EBD79E8FFEDE96E +:1006100049A177D93E099AE97E478FD03735B8ACE2 +:100620003EFF5C3AE2ADA74FBFE4F0D82CD6D16ACA +:10063000F2658D40FD0AF53A3CE7DEC0E36E6BC221 +:100640007F98857A5E4DD597F7537E4C1CC527520F +:10065000F76343691E1E3A8C5FEAE4651A1CFAFCD4 +:1006600082424F6549BD29FDE99B35E7D705291E23 +:100670008DF1F8E3B182E55E512F667CB2B78AB99D +:10068000BE4DE78D31711B4C9F365C990EA569FB01 +:10069000243AFF41F4298FC27944F7F7A1494DC0AC +:1006A000F7027ACFCB84AF25ADB3EFC7388E53A016 +:1006B000FF23FEF7B7AC2F16F7D8896EC7FE31833C +:1006C000EC39D6C4CF793F3429F7E33E7595779A54 +:1006D0001FD4C1474DE3FAC21C8BD0DF81DFEAF99A +:1006E0008D565E5CDAFF79C8AA34CE17E245BC1796 +:1006F000637759502FD88FFFF4E9EBF17E54B1BFE7 +:1007000007F7703FF3D89EDE837817B9BAA390E25B +:100710002D06AFEC24FEF0A18975A2BFE9C3ADF1AF +:100720009C7ED13F0AFDCE1FCDFB9D6F003B541731 +:1007300007B648E06DBE05EC56E0C7AFED2A31C400 +:1007400043BF8BB649018CD71D2BF835DA2F835167 +:100750007E8838A12AD6B5AE1BFA9FDFC8ACA32984 +:100760004E2C6C482738333A1749181DA678310D9E +:100770003E2077EA13A0DD22254CE721B1F1174C8A +:100780001F4F81F8C0737F9D9EB3A46923C511F4E8 +:10079000E9091DB171017FB344D38D1A254735F99D +:1007A000F95384E3A8885C19489E821EB43B6D14FB +:1007B000E18FEFE73D12C17309ABE57100429EC5C1 +:1007C000EA2DE70C5CFECEB734D3F75FD2FCDC2F0A +:1007D000C8BAC5F936D763AE85F77F1178D7F05D13 +:1007E000DDC33A6F85FE3BC5FCB57AD52B59E79240 +:1007F0009BF817ED05803397F3562EE7F16BBF0E8C +:10080000791F2BE763E57AAC3C4F3573F9ADD1879F +:10081000FEDC11F59AB12BC306C4F3D1550AC53FCE +:10082000ADB026DC84F758BFB0F1AF8A7045BE7812 +:10083000DA467AE32386C09677604B4C58CFF3D9DB +:10084000EFE3885FAED9C8F9DD1AF19EED9FC5FED2 +:10085000FFBDD83FA6740EA743384E2EDE57AAA080 +:10086000F126580B8DB8AF273A3FCD32223D01DF3C +:1008700071009C6F17F4BED4D2B90EFD5A87BD4BE0 +:100880009E7589772CF01DD209F80FC8FFD814FA8D +:10089000095EA41FCF7CF5688F8FB3862E213D940F +:1008A0000DBDDD88F26A75DCD271F4CE21533EC1F4 +:1008B000FC44A6F4A6115FCA70529C690C1D6AF331 +:1008C0002B63BD5946BC47603DF330F6A3CD377668 +:1008D0007E87BD12B77F62E6556D0D3D8BA1E83076 +:1008E0001F969E1C9967A93574A0DB47F391301FB2 +:1008F000E623A75F653EE8AE43FA345AE3E95EA318 +:100900002E4EDA81EDD929A9DF7B1A91B861FE3D1F +:10091000FC31CB463B9D6DE0EFF08E17743CDE6101 +:100920003983FB624D3CA3F7500F337B6035C0F138 +:100930009089EDC3FD08DDE5E8DF653DCCF83E5369 +:100940004FF1F825C9CAE3AC80E3FB30BEF5B0CD6A +:10095000A2105FF6F9A2E29335F97CF87799E45793 +:100960003C64B33890BEA03EE51FFA5D5C389B6CDA +:10097000645DFC71F695F4882A660FF2C575B5F4CE +:100980006E8A8775D03B3213D2FD62BD5D12CE2FC9 +:10099000E32146729B8D0E887756B93D5726D611B6 +:1009A0003BBF327C4717F1E888B6DB58D3938A1EE9 +:1009B0005E87108E8911786AF08B9DF715EBDF0248 +:1009C000702FD6C1DD6AA1778D017B2CDDDD4FFB59 +:1009D00018BBEF614F6812D2C91726D0FB50EFAE9B +:1009E000B4929C7457F4D2BDDAD391F75B689D87BB +:1009F000C5B072DCB80C8C379D23F65FECBCB4F547 +:100A0000C4AE33160EDA7CAFB5CE235A7FB1EB7588 +:100A10000ED03E669D6F9B83F390AE4FB3EE02C443 +:100A2000EFAB3817DD79A7C6A7DEC4FD987B6D7ED6 +:100A3000C558EDB738FE6B6FC6EF846FCFFE2C89BB +:100A4000DEF35C70E75B206B27DC3EFB214CBFB61E +:100A5000ED1FEE7400714D2893E8DCFB073F9EF01C +:100A600038DE6F9970CFEC8792F17D8AA72FDC99E1 +:100A7000047264C2BD9238171FF96DBCD73AE10108 +:100A80008994AAFFF334D4CF47FB3664C273FBBB0F +:100A90008DFC5D58E842D1FBABD6A6F37381B5E976 +:100AA000DCAE5997EEE3EF50333E6F369DC76F8152 +:100AB0005D619A4AF30E9970DEC76F052E9488FD2A +:100AC00086329B74FACD898996FB947C5E4F7F2E8B +:100AD000B4355D8AB2B763F59A2D627CEDFC12DB0A +:100AE0007FA7405FCEFD6E5B717ED08FC3C7E51BD5 +:100AF000CE6B5A01FFEAF5CD13334AC623197F277F +:100B0000CF5F8FBDBD6D0E3D8B783CECFD389EF404 +:100B100036637701AE03F7DF7E379D3FF3F80A17A0 +:100B20003FAF195F11D8F9087C4F006E51AF399C67 +:100B30006069AB8725BC29E8F698C68FE0AF51E322 +:100B4000BF421EE0FB4D1ADFFD95FF49E2FB93F02B +:100B5000E5AF21E8BFE9A2EF9DAC97BE41E634E1E5 +:100B6000772A0BD0F79392EE62B2BF23FCFA55DCE2 +:100B7000671F67727E7D34EE31924F27717CE49F50 +:100B8000AC93E8BD8F8FC4F0C701F9084E2F2572D2 +:100B90006EADF1312904FC13EBAF53899F25B2D020 +:100BA000511C3F5DBC0B9509FC8CECD93E3E16BD3B +:100BB0005FFACE97864B14A7F2645C02F9398F0F67 +:100BC00097C8EFF93ACA2C8473A1A4BD0368C07B0F +:100BD000AB043FE8E4F63C6936DA1FB757A4CEC150 +:100BE000EF9302CEB7CF5AD785F3BA3DEF9D9998D0 +:100BF0007F07EB3662FD6FE31570D28F9CF4EE4DEC +:100C000065BE54887EC3A263BD87F0BD9129F93CBF +:100C1000CE39D0D929637A529E8BE2A647BCC5D380 +:100C2000778C76D1BDC482BDDDAB31FD6DC545EF9E +:100C30004FDD7C20383E19FB9BE20A60B96B5612EF +:100C4000DDC760D3387DBCBFAA8AF67B2CBE2732B5 +:100C500075DA1DF03DF66E363E4FC3FE9C3E94F3B2 +:100C6000B950CEBE6E68FF1D4F4D00E737666EB3BC +:100C700001F725537F6A40FE385DE0CB15E2711D18 +:100C8000D34395A6390EA28787717D40075F201E4A +:100C900034BAD0E8E15559C073AA80A791DF7F9C90 +:100CA00016E2E71BF8372D05DDEFDA9F93F47A8D16 +:100CB0003F9E9044FBD9FCDDA4F7DE071106745576 +:100CC0001EF497239C8911C0BC4FDEE72339593E9F +:100CD000EB9E49985F1E5ADF4597899DBAFB3848BD +:100CE000571F9AA3D287059D7AA649E4FF61FAFBB4 +:100CF00038068C7FE3F7F83D0E2EB75343E6A8FB8A +:100D00003DA89FEBEB837E92924172D548F16779C3 +:100D100022FE0CA88CD651EA90C2F88EDE6B568962 +:100D200099090E2C6CF5D316E9C4F8F05BC2C14AE0 +:100D3000A423482B069D3D738F80BF29ADC28478C4 +:100D40007F7F0C7F3FE975A9E93E82CFFB0E9FA014 +:100D5000579267BB451CDB8D1E661D4CF25252D16B +:100D60009F71E36B69FC3CD0C3EF95DCB09CC36D15 +:100D7000DA2C89E1FBD9ACD14EEF9EC3B85F7FADD1 +:100D8000BBCF7DCF2C6EFF4F5B39328CAE80578B43 +:100D9000B4F8399F0999F6D4608875E2B9B7870528 +:100DA000E8BDBEAA2C592FE7DE9D262B569C27B303 +:100DB000D2398B3C8BD3C12487D486FBEE8414AE0E +:100DC00077D33ACC44BF274CC192649C8735948931 +:100DD000FEB1D2CB71AC734484AF950A799109F41A +:100DE00012A4B86FC968D4F18B583E838E339C8FA0 +:100DF000B72FADB224ED7D7E1AA79BE01CAFE91F93 +:100E0000C27ED1DEE9BBA5DB3587F0E2E0FB3B1318 +:100E1000B2F1DCEADE8C6C6E1F4CFFD549CC977CBE +:100E20009C4E4E7CCC8A719E2706B84F1ACAE0F2BF +:100E3000E48DDF2DC844FBEC447C3013EDB3251961 +:100E40003E027ACE340BBDD77FC21BA2FC13E2BE9A +:100E500009D63F83695730D345F5B91D86F5D14F83 +:100E60007E223394A97F1FEB844D6B372C03DB1D4F +:100E70004AF66560BCD4AF67A44A78AE5123E691C8 +:100E80009367A1F300AD5DCEF4F55D383EE8F7EC75 +:100E90000FC81363F8381EE7C4170DCCBF6F417F2E +:100EA00008C68D82428EF1A18F99031B0CA8CF97A3 +:100EB00087855F349A2FF7C5F15E544D283F6658F9 +:100EC00003E578951CFEE40D2911FEFB9ED8AF4F7B +:100ED0006A7C41F0E9271724929FE3DDD9317C7CBD +:100EE00014D70F6E0F09BE1DE47C1BFFF47CF1F6D6 +:100EF00059EBBB106FB172AF2C77483DAEF7F610CF +:100F0000C77B390B5279C56FEBA7A078B98BF9FA7B +:100F1000958B1AFF0B7472BE3F299FF3EDA263817C +:100F2000C3989E3252E3E39CCF4FCEF3931C787F5D +:100F3000C1BF53FAE82D1295035FDD89FCE44AFE38 +:100F4000CFD75799E3A2FD087CA73D6354441E5DAB +:100F5000AFDC95661DE5F6480CFE22760397B311CB +:100F6000F9CA548CE3CB74C8FC772858ADD49F9C45 +:100F7000D5F0F9DB881E126D4F5CA71ED0370FC667 +:100F8000FD71DAEF69404B27DA8F19A27DB195A97F +:100F900071A81F4C13F695B077403FF8D70CD28755 +:100FA000B99DE3413B07EDEFD181452EC3C0F38EE0 +:100FB000F32AFF8EEDC61B1C01E46B7F7A97BF33CB +:100FC000355199311ECF3927B1D05AFD7DE561A049 +:100FD000BF1B75726178D80A3668247DE32E67548A +:100FE000BAA0C31355FFE67DBEA8F242102AFAF25A +:100FF00011C70251E9515DA3A3EA7FEBA412951E2C +:10100000D35D1155FF969E6054FA06169271D1B7C2 +:10101000F64E8F6AF7271676D37B67AAD29597424A +:10102000F7D1E9EFB6CBA1A8F605E2FE6B095B1894 +:10103000D59EEDE5EF12D4C27F88BF1B62DE251876 +:101040002ADE4DBE7B9A29EA7D83A1784F3601BF07 +:10105000D1F563EFBB1A32E3E9F72860AF8F44792B +:101060007B057E40DD423E50B68B85C37E5C0FD54E +:1010700065376CE5F77763D7A5DD876586178C58EC +:10108000EF2F3E89E1D36B164F343E6DBE687CC6B0 +:10109000E545E3333E108DCFC4D1D1F87429D1F8A2 +:1010A0001C54118DCFE460343E53A747E3D31B8A11 +:1010B000C6677A55343E336BA3F138784534BEFCAD +:1010C0006A5554F9900DB5D1F428F099DBB422AAF1 +:1010D0009D864F15FEBB1A3ECB1CCD32DAD5153B93 +:1010E000A3DFA9B85EBCFE43A6B8C72CF07ABDF753 +:1010F0009881EF956726235F09D6BBB9FE1365EF8C +:10110000FC5AC88BC3DE3BCAF1C910FC8BB27F8688 +:10111000AF27FB47D377D01CC67D319975129F8FBF +:10112000D5E32B91DF1B90EFF7661921BDD4D0B921 +:101130000EF587CFBDEF9C960CC4AFA76702DF7892 +:10114000D8DE4CED8FC6BD44FD1FBA0A5FC673835F +:10115000EBE5837DFEA33B6BC98FA3F97306F4E334 +:10116000F83223FC8D98A74AFCAD6C455910EF6707 +:101170007F61E2719CBD13F9B960D9F74B28BFCFED +:101180004EB271F95966F567A2BE585A6191E8BD31 +:1011900044C732F2AB94BD65A2FB93C7DB78FDE395 +:1011A000E7B3699F819E4BFEB7BE383D110F75BCFA +:1011B0003070AA16EB7D6718BD635B26EE091C92A2 +:1011C00098A2A2BC4EE6F2FC78BC81F7E792284ECA +:1011D000EFB89F91FE785CCAA3FEFBCEB366B3A8BE +:1011E000F3ACFDD54E1E87A7C5E92D63E2BC13E025 +:1011F00083E50FF97CDA791FCAB1DE782D4E8FC7EF +:1012000001AA637C1447CE188F5BDCDFEA227B687F +:10121000BC78FF65BF3158EEC279E6F37BEFFB4542 +:10122000FCDE09815FF477535C4693886BD5E6D585 +:101230005840F38A957BE41FC7719B6CC23EF2D580 +:10124000E13CF6AFF4051A38FAA3ECE0FDACE3D4C8 +:1012500072AC3F9DEBC9C75D1D1FB6205C66DC10FC +:1012600000CCF6D1C9BB137F72FEB80FEDA4F574A4 +:10127000DE553E8DBF1F51E12C39F333C897A6735D +:101280003A6AF54B4D061E7FF432EEA3B4211C6F73 +:1012900015FE761BEEBF32E127FE759F3D1FBDBFD9 +:1012A0000E7B7FB86D793FFBAA4F4F624DF4FD3B3B +:1012B000F6D321BE9FDAA8BDE69F867D7F18E7ABF7 +:1012C000ADEF5D17C777F9CF2DF4BE3CD1B94EDF36 +:1012D00018685F697029BBA81AB18B4FE2F9FA351B +:1012E0003E53961A3A9EA98B77AC70876D4EF21FCB +:1012F000F5AF371C1F004E57F09D89C3C8EF53361A +:10130000AD84D6359EA9F49D882FAD5E95FF0CE87F +:1013100087F908E719F1C3DC6442BE0370EAC94CDF +:10132000BE92EF687A591F5C62EDA5EBF5C7F4E950 +:101330005BD7D213FB87D704F1FEC6FB4E29CCE363 +:10134000CE9429DE145C3FFF7B7F03DF1FE5C0875F +:1013500070DF4F16728AE573FD2100FFE1FCFEC2CB +:101360001C212BFAB172A2F58A52F1CE4679CC7BC0 +:10137000497D76A4789FA334F677B262E0A1AD37B9 +:10138000566E69F69EF63EFB40EB4FCB12F2CDC790 +:10139000867D0DE520BB486FE9FAAD81FCD26F2454 +:1013A000DF33B719E877D8B33790FFE78D947B1F09 +:1013B0007A07D3CF0C25BBE0A877C14E2C1FFA6368 +:1013C0005EAEC9BF9C2CEEB72C97A579E8F7CA1B77 +:1013D000F9FE4C3FCCE7888DDD87690FAB6AAD84A1 +:1013E000713CF9D9456B901F9819D59B7CF39211EC +:1013F000FA73DF91D80FECB3C922FE3C139F7A2C0D +:10140000A2AF11FD10999EB0D109FD9AC5BDBE7461 +:1014100023ABB7C0D7EC69723811BE76DEEF5B85BF +:10142000EF1561BFE5D93C7D6320EECC109C8F2485 +:10143000D17C6ECC933AF17DF472372F9F52F4D366 +:10144000348CA72C2FD5EADF711EEB978B777E1398 +:1014500094906938EE37E107396CE4F8B833CB4A39 +:10146000EB7ECD5162C2773DEE0E72BFD49DA3EBF1 +:1014700024946777879491181FA8ADEF8E2CFEEE09 +:10148000DBB4D1BCDEB4E06CD35CDDFAEF567AE9B4 +:101490007DDCBBA79F31227F792F661F57E23FE497 +:1014A000C83E0EE23FA0FF77EE1B46F661D92C3F07 +:1014B000EDCBBB9842DFEFB010F1B5E9AC89D23388 +:1014C00059077D67B12EBE7FCFF4EDDFC149D9B496 +:1014D0007F1FC8D2EDDFAEB87F3271BE11BD6F077E +:1014E000E263B0CFE765250FBCCF06E2DF65D39797 +:1014F0006D5BEEBF923F69766F848F77101FFAA6FF +:10150000FE616D3DB0BE1FE0FCC06E3A4071E1204F +:1015100017D01F0EF35E9935EACA751EEA873FE9B8 +:10152000F5A4BF5B3F1A402FBACAF9612BCDF33A3D +:10153000CF0F63CF270FA62899D9BAF3859A935670 +:10154000ABEF664C0759B603EF55958C1A02E5359B +:10155000C2AF15D7C59436CC17F1EBFE213EA25F82 +:101560008F99C739E07B76F8C376C5A55DA4A7F44B +:10157000263327F211EDFCFDE978685784EDF8BEBB +:10158000EE6B6F65F5765DFBD27B39FFFDFC51FE9E +:10159000BB2E9FBB24F2CB7D3EC34172F4EC63664D +:1015A0008A2B1B62E6FB3149BB9F82BF9883FB2FCE +:1015B0008BFB9F9874C8834E219535D0578B473C41 +:1015C0002BEEB57DEE0AD0BBEA9F3F9A2261BF7336 +:1015D0001B73EFC471E73666F8395279FD97B37C17 +:1015E000D4EF599FF2E9315C57A583C76BB1502105 +:1015F000FA012D869193AC787E6958D97B0CDA2F4D +:10160000C974D0EFD8950F3E7502DF973BBFD74422 +:101610006FAB2E6CBF2BB1139B19154FB0E04AFB7B +:101620006161D81465A72CDE159D5ED2119DAE892F +:10163000910FB172E04484BF0790BF5FAFFD729B12 +:10164000A4FC8ED37F98E2271609FC5B2CB53D6D78 +:10165000B07ECBE379457548EF8CC7C5A43CE12F3C +:10166000427D74B3E0FBCF6705FF13DB5B06E7DF6A +:1016700084F657E9E029B3099F5B6D3E94A79FE389 +:10168000435298FE05979FAD59BCBCF5298B4F126C +:10169000F2765431C6BDF07D55B385CB4BF8B3F22D +:1016A00077D6142BE2B3D5AC98BDD8EE9FF83D9E0B +:1016B000AA2D0BE8F78EAA5917DD7BB86130C75BFE +:1016C0008DE10533FE0EA6BF5E195E07F35D1CB407 +:1016D000D3EF2019BF32D2EF40621804C697C85624 +:1016E000C589EF772FD9C7CF37A4C1FCDC6AE39750 +:1016F000CD41EC4FBBBF64DD5BA9E291DA6D5F9534 +:10170000D3FB5F0B56DC4BEF4AF5BDFB20E2D11655 +:101710007C7F06E51FDEFAC520ECF7DCA3B213E9F7 +:10172000E0DCD3255DF83B500B1A1D3EF4B3D7B077 +:10173000DA003F8F895E77BDC4DF9FF868DB7B09E5 +:10174000C8E73FD2E2D39CB509B4BF7DB509FAFB27 +:101750005F3BB619E8FDC01D8DCBFF6D0C8CD73AF1 +:1017600075E6485CE76DAE91767C5F502BD7F47FD1 +:10177000A37BF473C8776EFBCA40FBC108F20DE38C +:101780003BCB1F9F42F18E3B827617EE3F5FE376A5 +:10179000717F99DF13D9F1A895F8959F75AC43BD7A +:1017A000B3A67102E1A7AAB18AE03FE42E3BE9119A +:1017B0003B0EC4D329ED0EE7683BB6DFC18C15FDA7 +:1017C000F99D0F66F1F3D492C1DC6FB2E35DFEDEEA +:1017D000E304C3B8492837973C2A53DCE591A91F95 +:1017E0009CC0F7AEB5FD049A561AE773FCF7431F89 +:1017F000D4E845CC67E14E03BD8B76AD7D65193CE1 +:101800008EE617BBBF76A801FA7D81D87D76ACB194 +:10181000C88EFEF1D8FDF6606336BD1FC336707FFB +:10182000D0F8C112FB5AFE46FB6ECAE07EF61DCB15 +:10183000981A15EFACED332DADF177ED1CD81A6089 +:101840004ABB83DE2DA0F8F66583F939F0B2C16694 +:101850002E4FFEBA7CD7DB00A7CB59A17B0763DCF8 +:1018600013530A91CE7CBDCE52740738447C1ECBF4 +:10187000E1F7DD369B8232D1A731F4CF6F43BEA9A9 +:10188000B16A04EEF7A58379DCEDF359A1B9D8CF9D +:10189000DC95A14F0F32A4BB1B68DFCFBD3C4DC60A +:1018A000F33A7C2F97DFD70E96E2EFB49A928244F8 +:1018B000971ADFCE85F9B6F573BEFDF860AE1FE569 +:1018C0002605A99F1A9F537B776506DAB3CF2C9222 +:1018D000E9F70A343D2C41E0CEEF63F45E9E7534A7 +:1018E00087877FB4ACDE9E40E350BE6334BFDF1D0C +:1018F00037B29361BFB9580E74B2DC63F0E13D19A1 +:101900007F809DD1D783F667B03C378FBF8B28335C +:10191000ABCF61C59F9393F9BB79AD3CADD1C19F6E +:101920009A24DAA7CB61A7E2EF0D619C3CC9CF9165 +:101930005C7E2EF7987DFA7787B6A7953410DE1572 +:101940002527497B8F9861DC04E75F5280C79BB1F4 +:1019500075BD6FC8FEC83CE75AC3651837180BB78A +:10196000B9627E3FC4F901A98C0D403A6FE0F92DB0 +:10197000117C526BAFCDCFBCD461A4DFD319C9F9B0 +:101980001A7B48A67338739AC721F831C51BA53353 +:101990007E5FE669CF2EB28362E33992ECF005BD3B +:1019A00022536646A447B3CCCAF19EC4237290CE9C +:1019B000F11E3134917DF285CCF5A397C47C329C25 +:1019C000C13DF361BC74C31E7A8FCF63535EE6FBE7 +:1019D00023FADE48ECFA3DB692BD488F5A9C94C675 +:1019E0001752D608FEBC5026FEFC60B7C4E3593639 +:1019F0008C57F4BFBBFD94DC64C579FC7EB0D0236A +:101A0000ACDC0FB3792C73A2FFC3C3025B0C43227F +:101A1000F8AA11F8920E48E21E1108281D3FD27E46 +:101A20004F224EC4FF6AE33E986FECB4F4333EFE9F +:101A3000E9E7ADD58FDBDAE5C7790DD46E9B8DDF95 +:101A4000D361EB023EACB7203BF41EC22B7DCD6CC4 +:101A50001F972F5D7E84DB212FB7E30FD97C19F808 +:101A6000DEA9763F68A07B40B1FAFB52E1A703797B +:101A7000A75A491F32133C97C6FAE97E215DD73D2C +:101A8000ECB203255EB44B6B826619F5839A7D5CDC +:101A90003F585A2F87AD5C2FA7F7237CC22FA7C1D1 +:101AA0007DB080CF2549F1A29EA5569A19FA9F5A7A +:101AB000FDDDCFFC00F58285F9E4CF8BDCCF76DA53 +:101AC00031BE26723FDB69C738E22BEF67433D1812 +:101AD0004F5AC9EF5FB4A1FF0BFD672B19F9B7DAB5 +:101AE000847FEDFF02044A420200800000000000F3 +:101AF0001F8B080000000000000BE57D0B7C94C5E7 +:101B0000B5F87CBBDFBE92DD6413421E04C26E5E7C +:101B10000408611320A2202E096054C4E5A1825A52 +:101B2000DD4080BC13A1F6468BCD2201A2620D35AB +:101B30002A5AC40DAF82451A2C2285481750A45545 +:101B40006B5AB5175F3411AABC13C107B6F4FA3F3C +:101B5000E7CC4C76BF0DF171EFFFFFFFDDFBBBB1B2 +:101B6000769CF9E69BEFCC79CD3967CECCFA6D66E1 +:101B7000C6A2196B61AD01DD68C67C45CCB5C9C193 +:101B80001853E15FA8B758B3FC0F3919FE99593CB7 +:101B900063F163E9BFA13F2B6AB5623F7BC40C1BB5 +:101BA00063DFE0DF3521ED4D4F32ECCF5F65AC39BF +:101BB000C69D149BCD982DDBE3B4BA187B6ADDF487 +:101BC000B722C64017BD8EB1ABA88B8FC1D891F09C +:101BD0004D51770364EC719D9EB101F8F452D3A48A +:101BE000812175D13FF87EE1F449E30148185B3E5D +:101BF00057E0FFAC593A59775B605E2B6DC1E76ADD +:101C000022F46F90F598E993D319F32BB23EA0C953 +:101C10000DF378D4C234DF0B854F0D1BDF00E35B7F +:101C20001DB2FFD49B264387C7F3647DEBA36E8070 +:101C3000EF5183763C33EBA9BBB122BF77F7FA4F64 +:101C40009A56C17C0733772E4B63EC628A77ACA33C +:101C50003F638E6E7B01908BAD7C7F6AD348F856D4 +:101C6000A47D267C9431C3C559CC01F835C4296EB6 +:101C70003FD6E3A02FC05A939EBA5E8F73521D3E8B +:101C8000A4A7C5E9C87B08DE2B704023E0DFA3B31F +:101C90005369889B1848866E06E65AFF2610EDD7D2 +:101CA00029DE29F8BDF8C1530F99907E3386E57877 +:101CB00061FC928BAA9BC1D819E946BF02FDCCCD2D +:101CC000CCEDCF0ED2DB64E6F436231EA8DF2D9BCD +:101CD000F0FB2D0EAF07C7937C92D1EC30E2781B5E +:101CE0000C6C36F24B7359AA4EC90E3E9FEFD011C1 +:101CF0005C19593A1AFFA1AC190516184F8D993481 +:101D000046EF08F64BB5A7EB70FEA90379BFC838BC +:101D10008F6E22F44B6DF6C6231CA9AA770ECE3B1C +:101D200075F602A3CF89E302FF001CA31BFD968971 +:101D300048CB521DCB80F16E7438381EEC25C5D8C7 +:101D4000DF30DB6C45E67DDAB3D982E36764AD6FE3 +:101D50004C8571995D7561FF0C9837F653EFBDCDD9 +:101D6000AF7706E179C8AE16211CF97AEFDD387F2E +:101D7000D6EF2AF726783E28F6FA22571463C9FAD6 +:101D80001DB98B61BC27149877C87C6579C4A910EC +:101D90007C0D8AC77713CA632E639B58F0F96017CE +:101DA00023FA2E7118095E87CF5E6086EF8CFFDC08 +:101DB000437859E250E9FD7D6A47A41DE166EEBB18 +:101DC000E7E23C3D5607C935CA39F48FAB77B89086 +:101DD0000FCC711D0F8FC4E72E9D2B8305E5FEDC14 +:101DE000EF12D63F04A0989DDE07916EF9FA8EC7D8 +:101DF0006EC2F93CAC0AFDD0B1EEA7D02F65A63576 +:101E0000EF21A83E18D7F1581194CF1898CF12CBD4 +:101E1000D82AD7036E059EEF8B6376842B12C89465 +:101E200008EF5BAD8A9FC1B8A3414EF5F8DD44C50C +:101E30009F01F8B1BABADFC6F1AF77BCEDC2FE853B +:101E40006A60BF928352E14E8FCB2716177FD0096D +:101E5000EA05A2960162F409F01C704BC337FD1825 +:101E6000535C2C6083F726337703D26F17D215E0CB +:101E70007FC208FA045E7D4267F6A36288CC76EBE7 +:101E80006D50BF2B4B194FF0C5B5333DF24D133C90 +:101E9000847A6AD60C2303FACC6FE2F23457F0212D +:101EA000535D033C23409A1D91847FF82C95731950 +:101EB000C71B5B65F46F8221521B9D46045AD28D6D +:101EC000B1A5BC1F8E07E3181F607779906F477329 +:101ED0007A0262E9F94E21978C3D20CA265E8AEF8C +:101EE0004A39AB41397370BD61CE17DF87FADC0E1A +:101EF000A513F1D6557A3E0AF5C1DC367DC0047CC7 +:101F0000C71A27BB3B846C7E932A64343EF8DED329 +:101F1000C06A16E4B736BD1FF93538CE3FA21CD6CD +:101F2000BEC779DDC1F9F5C09C2FA33AE07B4FB75E +:101F30006DB020DE9E98CE583BAD0FC0F550C6ABBD +:101F40009E7607CDC7F5F34CF8CED33FD733E4BF29 +:101F5000279476B79EF3B90BF9FCAEF41977BF0A54 +:101F6000F5D8D1C3F210AE449599F5C04FC7055EC0 +:101F7000A20F00DE60FCA7141091D8207E9F52565D +:101F8000272D82F6D1451C9FB1456E7D15EAEF984D +:101F9000EEC928B7DDD731B61EC64F88AC6D41FEFD +:101FA0004FB82B2B6F19CC336214BB6B06BC775226 +:101FB000F04912BC130D3A3BF1019F13C78B3EE071 +:101FC0002178BA4744B8D643970498BB2D96CA46A1 +:101FD0000BF6634B15ECB7A2BF42F2BCA298CD7EC4 +:101FE000219BC4488D8EE5E5112815953518F03DE7 +:101FF00095A911BCBD01BFF378149F4F7F9DFEAE24 +:10200000E9D9B45E503D16E47C3DC0F20F470CC1E7 +:1020100095606245385F6C47FE0130DC3BE07942F9 +:10202000616D2E7E3F218D970F2505545C2F9E6696 +:10203000FE359B10AF59463BE2756AD6A12348CFC7 +:10204000A966D6AA473ABA0C673AB282742C4C9861 +:10205000A977C277BACE7EB26E39B43DBE74FA9C0F +:10206000F9F8FE082B9777DF0ED74C5C3BD9C09868 +:102070004F8683ECE27B80F7F36722740A2C488753 +:102080000FA7457720EE9C1C8F886B9604CF992371 +:10209000DA0E701DDE9F49CF65FDC287AFD951684A +:1020A000C7E1FA8DF4D964F2AF7706F58F35269E35 +:1020B000EC8E7183990FE9D5BDC3E25F0F2C70AE32 +:1020C000DE357E5206F50B50BF1787F07EFAE96EBB +:1020D00085FA19884E270D8CD629DFCB23481E019F +:1020E0005DC558B7BE9CE0C0FE35BA8EED684A5853 +:1020F0000DCC8374B3B6E87C19D1417EB22AD04EA0 +:10210000FC1BB0A37D730EED1A927F77E2CC11C158 +:102110007E0D428F571A039968DFC8F7647D808966 +:10212000D5CA7A0CD4F78AF5AE3282D7979BBDA375 +:102130009CC0D7BB8CAC94C68982766B085E725506 +:102140009A770F5E3625F8512F235EB0DEFD884D5D +:102150008BB7A786F0E7B8E8E2FB0F2AF4FEB12CB4 +:102160005DC098437899FD02E99B807D7AC83C2444 +:102170001EE6ADF9F45F2C27888F791E63A73EA772 +:10218000373EE47BF3F24AA632E0A779E54BA6613D +:1021900019BE9EF5F46B34096307DA703942986111 +:1021A000DE5F5A261A91997EF28BE946E4DB05AC94 +:1021B00096CA52D64425AA291DD8698E4695E6E3CB +:1021C000D8A2F81D4EAEF674648BDA75D85E016A3B +:1021D000F86954DD3ED01A5740B3A253D0BE7234D2 +:1021E000403D01C07E50F5E1FAD37224D2AF40BF2A +:1021F0009571B080028A5736E8086FBE557C1D8203 +:1022000071133D303F5F83CE8DE3D43AB9BD80EA90 +:102210009CD65B3011091E513618B81E97DF5BCA79 +:1022200074012C750A2F57A23D60ED8D0F395E8326 +:10223000A1D68CF64AF7209D1DF9F64BA37B36CE2E +:10224000E7CBD84C86F64A83ADB6B1883F2799FADA +:10225000D21228A2E7B93A6EE0A298A17DF39EA51A +:1022600005E9BEC0A92378C3F13DBF495B5FB8460D +:102270005B2FF36BEBF398F7378930F58A2DDAF69D +:10228000054E3B8D3F97B9883E0D06C75F9CC887BA +:102290000FAA0CE15F3A90E34D378897A931936616 +:1022A000D3BA18636419042F873F35375641781B1A +:1022B00062B83CFC57E10D87B3C999C9ED28509F1E +:1022C000F8BD069003812FB2DBE66D336D403D30E3 +:1022D000CFE688C2799C56BAB3681D7AC4E6E0FAA4 +:1022E000C24EEBEC5C3B1F73ABD06BC714D7E60060 +:1022F000BCA77BF4F907711D9BF7B03E0FEDE3C25D +:102300009956D2377B4E59FD2678BF14709704FA40 +:102310007A8FEB1DB29FC3E7077F0E55AEDB40B24D +:10232000B971E09FA0BD13DA8FD669E013A9A76148 +:10233000CC0FFB7B7E877A1AD86FB80ADFFFE46484 +:10234000840BF1F8B8EED88ED746939E24FD57BD86 +:10235000A47B3383F777F4F706B0FF997BDF9FA266 +:102360003882F3EF7A7908F1CBE80653707CFCBF32 +:10237000552175FC7E234CE24A289BB5EDA56BC325 +:10238000DE63FF610A8553DA2D4F18BD43D10E7D00 +:10239000DA939F8FF03C61682A4279BF94E4FD0B89 +:1023A000C2757CB2E7908ECB5D26DA37FB2ECD4B23 +:1023B00053516F1F31BBD00E413B16F5E423C23E93 +:1023C0004F34331FAE9FD2BE957654B87C7D24EC3B +:1023D000E8734EF762B45FD925800AF0AD177693A3 +:1023E000D9FA821BED3DD6A6D87139A976B0CE8533 +:1023F000A0BFAC6D8A3B85FC261DF937D5565DE73D +:1024000015D09E61D511DE58BA4A7AA2BA99F9164A +:1024100002BDCC667720D941FD7C57E4A03FC5E1E1 +:10242000947054EF9ECEBC5682A306ED1FF44FE687 +:10243000C3770DE077E09F41F82786D94692F7D120 +:1024400071D21EF473FFA7D9DBE38FE8094F1E9DFD +:1024500087AFC3F64F2283F8FE87D39D980AF3FC1B +:102460003B36C0BAFB46A2FB12E2F70B5C9F470269 +:102470008BA572B80EBF3393D6E12F9847ACCBB77C +:1024800044A3DD26EB9FE8BD3FB1833C2C643ED2E4 +:10249000CB65CC4F256BEE477CB000D65D15F0BF09 +:1024A0006096FB3DB427502E036172195AAF64ED5C +:1024B0005C8F837C0642F8A712ED7BC06B95990573 +:1024C00022B16CD5BE57CDBAE9BD9ADDDF98021AAC +:1024D000B9E17C95A05F945B8B780AF30FA4BD2FC4 +:1024E000FD00B6A2FB55E2AFEFD9EFA4A3291EED84 +:1024F0008246857F7F8ADEEA3603FEAB1ED1915C81 +:10250000C34053C7E4E3FAC4F9A8C631E524AE7B5F +:102510007120A628FFE65D7AFF034EEAEF0A40BD70 +:10252000EA651B462458A9A3742AAEAB657EC3C7CF +:102530001D21F329673BA6A08AF982BD6144F9A851 +:10254000D8A27D5ED5AAADD730F5E31EBB0DBE5334 +:10255000F761CBB85742E4707CAA2D0EED3380CDE5 +:10256000F90DE25D7F47B4F732F221CBAFEAFDE32C +:102570005E3130768DE22E4CE57AC5887258AE32E7 +:10258000F7E5FCD32752B85C1DB45EE8E70D795E31 +:1025900090EDA3F8437EC1E5E5717A2AB7DF23DB2E +:1025A00085FDAAFA584CC8FB7DBD775B2A5FCF0E2C +:1025B0001AF9F3476D916EC463A291359AF382FDC7 +:1025C0001275ACC11C8B7106CF1DA96330FE20E3D0 +:1025D0000B3E86F6A3AF3FF72FA47F9AACD7115DD1 +:1025E00093F5E6F5CB500F0A3FE6BBF82432BBDB90 +:1025F00080F8443F1EF90F96651F83F18C3AD0ABEB +:10260000382EC824FA056B2DCC87F0C0738676BBB4 +:102610009AC0E5CF88629F87EFB38082FE03D826F9 +:10262000D85E97EA59CCF1EFCE21F91670540B3EE3 +:10263000EB8163B712B04505F915E351B80EB0262A +:1026400013E9256215AA2791DD7B14EB20B7479289 +:102650003CBE54F223F9F3798F0E22FF9ED5F52369 +:102660007DB1D2C6FD0E805B8357296F6B158EDF5F +:10267000FC82765AE7BAEF071B5F09894B08BA3E1E +:1026800092CAF128DBBF167AF8AD54F7CF717E6796 +:10269000DE339B31DE387A3497976A8F95EB599009 +:1026A0007F84AB7A0923FBAC5AF8DB1753BC6B1061 +:1026B000EE95EF5B7DFA68D4A72D148731C4794776 +:1026C000A15A4AC3F69114AF5A8BE3972CF17EB608 +:1026D0009F05E355F9DF14AE28E2F0DAD17E8A4394 +:1026E0007B3C84EF5E16FC25CB3D824F7BE61527B5 +:1026F000F0D9AA27FC463ADA29AE51BD931B13F94B +:102700007AF71CF43B58452C433FA97AE7C4DC57C1 +:10271000B1DE6AC9C53851FE0753ED68DF9DC98D2A +:102720007521BC66A7F705843345DF5186FAC536A7 +:102730003A90F24B186FB0C74A718F70FE937C9736 +:1027400000FC8AF84AB8DDEC477EED896B1898D713 +:102750009C16E4CB0DA9BC7DB05847062FF1B0F90B +:10276000D660DD1AC7E904ED3AC4CF39E7E40D08B5 +:10277000CF86541E375A94A8771C0796709AC12AA0 +:1027800049ED2D8F4E902C2BE89B9FC2E36F1005D7 +:102790003EA887D82BE79B14F29316810155971713 +:1027A0008447BEBF28D148E3475E5409AFA9761ECF +:1027B00047B4350A3C03FD11CFE3BBDB0BA361BE7D +:1027C000E9CD018ACF58F05B49F8958E874762FCC6 +:1027D000AA9F3A1EE307EBEAF20E605C477DB0FD6C +:1027E0006AC4AFA3C95E802154F55FAA87E2358C25 +:1027F000F35949B39DEC1DA6D666A1FFF2B5E0D30F +:102800008B29EE4EE4AF82770DF4FD2F1FE1F65BCE +:10281000734AE5E01878EFD87BC0974ADFFAD3C750 +:102820000E98D1CE4F5D954AF1225B238FEFB074A5 +:10283000601080577DE4431F87EF9D41084ABF34F5 +:102840002BF117BE87FEC3BC068711D1E76C663A31 +:1028500084DBB66A864E103F4981E7198DB3741840 +:102860007FC91071A3F0EF47A4717EFDFD253DC522 +:10287000DD75661EF7AD4A8F6DD173BF90F8A66AFD +:10288000481CCD5F9FC6E3AA86A689140F0FB757D1 +:10289000AA762E65C817E1FA47EA1DC977BF5779AE +:1028A0003CEDF74CC6D338FF351838BE7DFFD291CA +:1028B000FE19CCF83A92F628587C440F19D7F253F7 +:1028C000A91A1C2B1251872DED98E083D679AB62A3 +:1028D00074D5D9388E6B118DF38895D138AB520FE2 +:1028E00064A19C34DA99E2C0F1160E4639641F984F +:1028F00018F28BFA885587FA5C5DEDC656A6C6C4F9 +:102900001750FD71A843FFBFA71A08EE0F043F360A +:1029100028DD0AD935CC9D8BEBDD5BA9DECCB4314B +:1029200022BE8FF25B17E1477FC5A6727BD956F7AF +:10293000FEF34BA1BE4EF8E9058F66CF207E79509D +:10294000554CF0FD2F63FE4CFDBE1CC314B4E3F2E6 +:10295000D2741ABE0FE1976406744D7D59EF417928 +:10296000540D9CEFD507E35AF0BD67E2BD63D2E09A +:10297000BDAB1B0264AAEEB31F7FACC8D19B1E7D0A +:10298000AD07EE348758C77CD4BF46EA913685F44C +:10299000884BC7BCADDCBEB4A01C1C040261FF3A6E +:1029A00073540EEAE5AF2CBCF41570B87C472DFECD +:1029B000656477D65E41F147563B12CBB808E8070D +:1029C0007AF78DB33CFE332D8DF3D1E022D047A0B2 +:1029D000076AF13B80A7D96931D4BE3796B9EDB00B +:1029E0007E245ABCD311CF751DB989C82F7BA3E2B1 +:1029F0000BD00E8449A5E0BAF7B1888F84E32DD1BE +:102A000032F116C4CB1BC25FC4EF3AE1FBB175854E +:102A10001ED427607F919C754F37523C24F6DE8987 +:102A2000D4BE57F13FB500E771338F63354F772739 +:102A300045C46119AF43BEDDF51F7A1E2701431758 +:102A4000D7B3C2527712FA05033C461DEA8101450D +:102A5000B57FBB1FE3916F185CB8A7D1C59A52C868 +:102A60009E6DE4F15319872EC07829CC439F386AB4 +:102A70007C097CF7178AE3A912E4DF32F15D1B8F32 +:102A800033341703E3037CCD4E8EDFE6F90E929FBD +:102A90009E784F15EB89E7E0BAD2556B977130FEFF +:102AA000FC47F27907ADFB5D631D76D4833DF19E53 +:102AB00039469AC749C157BE395922FEC5E3455D1B +:102AC000B307F0FD3CF3647768FCAF4B15720B7EE7 +:102AD0000FFA5D5D7E1EFF7986F987A29C74313105 +:102AE0005E29976BA6F2FDC2AE22BE8FC0C6BACCDD +:102AF000C8175D3DFB82DD51A17122D92EF701E39C +:102B0000975DDEDEBB4AE8A753F1EEE6B4103E96D1 +:102B10007CBF372FA100FD8EBEF8FF6DC6D789B7E9 +:102B2000D23CCFE0FB93CCAE92C7A1E9A088D3B151 +:102B3000A9DC8F61AAD78BF3797740562EE2231C4C +:102B40000EA9A7F68AF786273333FAF320BB3EA4F3 +:102B5000CBB05DC3489F6E13F0A28861BC609858EB +:102B60000B8727B4C4229F7CAC38B2D164967CBD5D +:102B7000372299F83D84AF77209CBDE1F38C9831E2 +:102B8000A26FB85E4E73EF26FC88FE7DAD4F48768F +:102B9000C493D1D87A37C50BABAC2EE49F77F01134 +:102BA000BCB7E1165300E3C15D066B23CAF191C8BF +:102BB0003B0FF507D4EE317B0FE1F8B36FBD6E0527 +:102BC000D69503FD1C8B00FEAEE28E7C9CD778B3BD +:102BD000F78F28C79566EFE07840C1D941DE21D153 +:102BE000A84F3DFDC43AED19E1B92CFC1C9E42856D +:102BF0007FFF4DA3F76D3EFF0E9B2B8DF89ADE6392 +:102C0000D6FE34CE5181B7FD06F7F8CF00FEFDABFE +:102C100007E72E03780AA3DEBBBD06D7F52713729C +:102C2000C96E12783928E6355FE7890FE835F07606 +:102C3000E0772AEDC5839380DFCF1A04BC5601AF3D +:102C4000EA1AF86DF0A2CD45F271BF42F2417F5011 +:102C50007FC91743F264D22D6B21F92B36BB50FE8E +:102C6000D646808881FDF3968007FC0E86F633B445 +:102C7000937DBD89B986A10E483671B94A5EA99087 +:102C80009E9571B512E6494113F35F69DE8B88E7C3 +:102C9000BF45FEC7180CED790A6DF4DD8EF7225A98 +:102CA000685F773C87FFBBE8CFD82A1DC63F6688A0 +:102CB00078D68CB346F2A3E60BBB6A069600DF4CCF +:102CC000E636E0F76F665E03CAFDADCC47E51CE66D +:102CD000A7F27616A0E73F621D54FF7364CEA03AB8 +:102CE000C0FFF4278764601C2B04DF51E99C3FEE92 +:102CF0008AE3FCF16902C511FA7F2F7E9D2EF8034D +:102D0000E4381EC701394ECF4D0D919349FD05DDC5 +:102D10003A964503FEA6C73B73711FF29A4B9C2E51 +:102D2000538EDB093FFB15D0A47941FE0085624D2F +:102D3000023C5C2B48D87E9EAF63D7BA2B288E7D91 +:102D4000D8BD342E0EE09CACB7125DDA5D7A3FAE92 +:102D5000EF9B950EDA57796DA9B72106DA5F1BAAAA +:102D6000B896C1FBD7C54D8F0EE038E879C177DB47 +:102D7000B3153FAEE3D3D6F0B840D14043D05F8720 +:102D80007FAF4FD7D6A7BAF59DB8AF36355BEBE727 +:102D90004F63AB3EC3B8FBB4EFF0F7AF4A17FEFE8C +:102DA00030368CE26EDFDFDF9F98CEED308DBFCF07 +:102DB000301A097AEC260BD7B7EDE30F8EEB82F9C8 +:102DC0005E68731216FF3A94DBCD8BD33DD7E1FBDF +:102DD000E70C1D0B48CFD50366873076BCDECCDC14 +:102DE000C0D39FD4DBA97EA23E91CA53F50E2ACF51 +:102DF000D467D1F373F52EAA3F93EE9E9E0EE3ADFA +:102E0000B4703AC8EF2F167CBA7250FE931EF8FECB +:102E1000CA370C542F6D6D9A8261AFC5833E7E20F8 +:102E200012F0BD78AB42F1958A36B711732FE6BF29 +:102E3000E25D81CBCFC2373AA6A11AA9BAA8302F3A +:102E400088C875599EBBF03B63DE3D1E8FF8F9B410 +:102E50007E2CC171B2DE4D709CAE2FA27277BAA7E4 +:102E600004FBB9DB3A5724C278376EEB5431BE37D6 +:102E7000D9AD901D3DC1CDFC7EA0C31A035F3FD6E6 +:102E800024995D28B71347CC78E6C70CF5B2B71A7A +:102E9000F17273ECBCC9FD900FC616ABD8EF56E0CB +:102EA0004BAC4BBEFD6E79E578A8123C71769F4223 +:102EB000F8797BA79EE0387F2482F6D1CFEF8C246F +:102EC000BE3BDF6822BB62AFD1674A81FADE94085D +:102ED00017EAC9BD290368BD3409793A0D74623017 +:102EE000EF992FA625A09FF1D236A515FDEAFCED9E +:102EF0003129C8AFA7635B8FDE47FB0D468A23836A +:102F000023FBC9D3A8E70626BA50BECE097D0C160E +:102F10005E24AEEFD546694F7A8763FD7484D80F7F +:102F200081FAF46FB7E79A104F725E8B5E1C9E8039 +:102F3000FE131B1847F8C952545D5D481C02E17628 +:102F40000C09D6F7BE30DD85F3CADCFE64EA4F011A +:102F5000CECDCF3F757E0FC1EB2739DFBAFD99018A +:102F6000BF845AE58EE511E877C03ACEC6827EDB93 +:102F7000BB3AD28DF3DC6B701DAD437DFE8C95E2C8 +:102F800042BFFAF9BD1FEFC6F291AABC7B71D6E928 +:102F9000B14487925FCC999204FD36EF62B9285E06 +:102FA000C301B664802B7BCD670792E07B39FE9826 +:102FB000424CDF716DC93D3800EABF7E4909601C93 +:102FC0003FAFB565BD82B19E4B1B06A05DBB2BDD3F +:102FD000A1F1B3860F2A3A4CFBB061764376F367D2 +:102FE0000538DEF3035A17C5805C0D535A4F2D7513 +:102FF000A21CFC35CF4B78E5F19817DB66BE7D3B14 +:10300000C379F992D0EEF5151B295E8ED3C7DC9FEC +:10301000B33BD3C83ED9A5F3D1BAE49B6B76A1DD0F +:1030200076D6E37B0AF9B10AFAA3DD5995EB8BBAA0 +:103030000AFDC38FD25DC0796CD0BA6B8B103FD5BF +:103040003B1F9F3200FA9D1DCF5C0A805EFAE2852D +:1030500029E49F83178B7ED1D99DCBE26F83F71E26 +:10306000CE2EA0BC138FBE95BEC36AF8779E14EB1C +:103070001DEBC8A17D14626907653998B13DB62D75 +:10308000667F320BD2ABA66DA913E3FEA3BD661714 +:10309000FAAD6B9CBE248CAFC9F513D6C123C82FE3 +:1030A000494631AE7D26F90BDF77FD93713739DE66 +:1030B00093461E0794F1B9B546BE5E6F02BD837C90 +:1030C00027D76BF8EE89F43121F13D58547201CEC7 +:1030D000E4274D1487F9BEDF97F6558DF09B0AC49F +:1030E000BA3BBBDFB2973B60BEC7CCDECF51EFCC63 +:1030F000676E1E2F575D0ED4CB7F34BBBFE0EB68ED +:10310000770ACE01D6D5AFB15FB51EECAEB410BB19 +:10311000CBFCFDD6D52FCCEE6F48EF7FCFFEE1FA8A +:1031200078F1173A960B7CB0F871AE6F96097F7103 +:10313000992DDF4CF2FB8AAEF210ACAF57F3377B20 +:10314000C65B6CCB23F9C635F372F8DA07F2ED05EE +:10315000BD1480F5C33B043BB52FC3F88F1BFE673E +:1031600003BE9970111CCA90F531FC7DA0D3A00C50 +:103170008077228BD4F473B3188A03336BEC7F6EA1 +:10318000BE02EEF1826EE3CF1F8944BDB9F88B3CDD +:10319000D29F7DCDE765319FDFE37CA07C6BA86784 +:1031A00024C277F5E77615E57882AA67DE90751C6C +:1031B000E01F83CFDD972234F0F7F0F9F784FF1E8C +:1031C00085E74BB0CF781E529BF003DBCAB2C9CF64 +:1031D000DC857E32FA71338C64C7B6D9C0BF85FEF8 +:1031E0006D6FF627F9DF2BE337C53C0FA8CD22DE44 +:1031F000DF944076CD00137FCE12187F2EC79F1329 +:103200004FE3839EE579177322E8FBBDFDED83C391 +:103210007F437EBA99D697E65CEE97362F1D42E340 +:103220004BFF7980BEF6F511A86F9645927E6EB67B +:10323000AD6F4CC57EF7EB5DA8479A9D81DBD14F02 +:103240006FFE8CEF9383FFCCD71DD567C3BC06F010 +:10325000977BEAE847817F4CF560FE03F403BCBE30 +:1032600027E87744E5FEE911F47B4706F7098EF479 +:10327000E47DF071BCD32255E4F7F0764907D92EEE +:10328000FDDCF70DDC5E6D8E69EA8FFB6BF7657810 +:10329000EF463ACF99BFC9E20D89C3C4AB9EC519A9 +:1032A0002097C74A366DC5B82B2BE17EDDFB328FE8 +:1032B000E56BEE978F3776DC700BE061FC3F748A2C +:1032C000CFD19BFE3D7184FB759ABC9067372688F1 +:1032D0003802A777F79B7A17E5E8C8E7D64C9147FD +:1032E000A368F26D308F06E36CBE1787D0F78B664C +:1032F000703BF7FC125D0BDA1401918FF3AC88334D +:10330000FADA6C44F767051EEF127AEE59B1EFEC6A +:103310006B3570FF490D24D7E077DB8652FC20C067 +:1033200004DFED8E14CF1DD1585FF687510CE1EA12 +:10333000927A4611F93322BFE65981EF1F906FD37D +:103340008278EE33DFA64FBCC13A81FEF3BD7A4DE1 +:103350007CE6D9DA11126FFCFDA7781E534FFCA54D +:10336000CA29FC45FF8399D8BFAD3FCDF7DC9263F6 +:10337000F96B1C84B79CDDD86FA789F85CE24DD24D +:10338000F5D91E3EEBB610FF19795CEDA8BDC3164A +:10339000BA7F76D4F3890DF5D18775FA80F15BF2A7 +:1033A00070EE10F93D7788BC9E3B967C7C07AEF7AB +:1033B00077945EBA93DA2BB5790A2733DCAF22BE55 +:1033C0007AF07352A7C947DAB3B1271F89E3C7D68A +:1033D000F39CE7439CC896F9483C5FE96484C08F3E +:1033E000C8377FD149F36682FE7BD6F0F124BC7BDF +:1033F000543EFF3D7E6D7ED69E9E38939FEC508955 +:103400009765769739142F1FF6F7FE0DE17FC09A66 +:1034100067C67DEED2E882C3187FA956613D063C9F +:10342000AFCBF41E477994768A8C979E31B41FD225 +:10343000E13C967CBF75B222A2AD5A01B93DD5B62A +:10344000691796000FE183BDC0F5E8197B200AE1FA +:10345000AA80A609B1B8EF0B321CCBEB689786E7C0 +:10346000AF9068C6F3E7680F54B4EADD9628AC1B4A +:1034700083FD605CAF8ED3816DE7718972D61ABF10 +:10348000544FFE9C792CD831E776FF360AF54CB9BB +:10349000D56A5E827653583E49F9CE95ED6939BDBD +:1034A000DB7BC313A65F76E8357C7026840FE87952 +:1034B0007FA3909300C5017BEBDF405468FED919D0 +:1034C00041E73361743ED343E780269E78A6F558E2 +:1034D0000AED5FC978808BEF8356FC86EF6B2E1761 +:1034E0007AB7A25F6B3EE27D805EBBEF27CB0A33EB +:1034F00053C787F8191559CC8C749171BF0A0F53B3 +:10350000AF0AC933ADF03333D677E9407F58898E9F +:10351000AAA0278D03FD899EE566669E00F5721CB4 +:103520000F4B9D9FE2C612AE5E7084E17B7426DF76 +:103530003F582EF588CD28F4A22B11F136648D5119 +:10354000D3FF9CCD78179E5718EAD7B6CBF1DD99FB +:10355000DC6FCF0AA5B3B36FBC4C11FD9F7BAEA748 +:10356000BF9EE7F580192FF9D2C1FD2A03C2F79E4D +:1035700051C6C57E9C0CF65F05F2466A104FBB72C1 +:10358000BDC9B1509ED371BDBB2B06EAD968C7F245 +:10359000EFCB7A0FDEC3F8FC81F78C84875D6F1A5E +:1035A0005A301E532BF0D326C63F55EF1D75DC80D5 +:1035B0007187DAA12519C1792C58936B463E59B809 +:1035C00036D73C37C40F5DB6E56014E26B985547BB +:1035D000F197535B46515EDA29AB8E452AF87C940D +:1035E000199F9FB11EF89303DA17AC8DC90B3D7775 +:1035F000B070CD3D434B42F03C7C8B16EF235AB567 +:10360000F591BBB5F5FB3219F93D3FF4BDDC80B651 +:103610003EEAB0B6CEBAB5794E2F8DF5CCBC11F7D7 +:1036200097D6EA5DD8546AD5F94C20EFAA95CB31EC +:10363000DBA6A77DAE523BCF673AB16B653EDAEDB4 +:10364000151F951C42FF6CE13B1C3FE1F977A54734 +:103650000E7D4D71781D53285F6BB3427A3C3C2F31 +:103660004FC6977AEB93A5326E9E15CA4FE1743F11 +:103670002DF28F2AEB2A46E17E8EC4FF95ADAB2951 +:10368000BFBE6CAA76FE15AACA965C569FFAB87D94 +:103690006F753B103FC5E21C53E7B25BAFC7F5AF98 +:1036A000F3D6A293B82E5C5557C88E8D8207ABFE19 +:1036B0003C05F153FCB0C2509F14FF76C82B94E731 +:1036C0002AFCB385623FCD3ED6B1BB03FACDF72BC2 +:1036D0006497CE0DCBA72B59150647581EDDC2DDCA +:1036E000FBBFC6EF86E7D3C9BCABF28DDF98B479D8 +:1036F00076DCFFBFAAAD458FF39F2FE1F54DA07398 +:1037000011FC6852707FEE3856AEC47C30CFEF3378 +:10371000F1BD66FE5E15E3795E32FF6A8109FC0247 +:10372000D053876D46E28B0B6BA229EE798106831D +:10373000722D8F6B56F5E3F5AA0D0AF9BF55C2EE4F +:10374000A9FA158F5F2F5079FE3CF28B3B04EE4AAD +:10375000311FE48FD076D6C4FD67990F867962EE6B +:10376000907C824A9817E6CF637E58E87BA1F96186 +:10377000A1ED217176F2E7657CE159837FEB6680EC +:1037800053FFB30817DACD8C7922902F41DF707F79 +:10379000683AD75FBDFD95C5C25E3690BD0CFE0A86 +:1037A000CDB7B92C83FC9D01A81371FDFD9589DE71 +:1037B0002FD1F9B75AA0CD20FC98121D8F1B96DC93 +:1037C0006624FC34F77F81EC9EE6C779DC12F700B3 +:1037D000D08E6C5E3D44BB0FD893D7EDCEC4F8CEEF +:1037E0006DAB935CDAF555EE03FAFB5F7E7DF5F782 +:1037F000C775E27DFC4FC0EF6D22BFFB3691D72D20 +:10380000FD9BDB7AF2BAF938126FE1ED52EE64BB40 +:10381000F46F2E2579238784C4B59A63FC16CCCB2C +:1038200064A5DF6F5F6A93B01FBA575B683EC71528 +:103830009E0F5A12E179E81AC4DB13A9A988B7E4EC +:10384000217C3DCA2F7067DA797FDAC792F4666E01 +:103850007726FA2DC7575BF2104F329FEC682E5F28 +:103860004F2247F3BC9774314EFA109DA64C8CE062 +:10387000F95AC727F3FD0DDB688F11EDA64D0E9E9B +:10388000175562F4FCF1EA1078E0BB66C4538E1859 +:103890004FE20DE98D7648C92F4C7CDF5CF5A661BF +:1038A000FD8E235944BFE3627D937481958CF8EBC0 +:1038B000B6B7FAD3B93CA917BF9B2FE5BEB581ECCB +:1038C000B01EBEDCC4FDE8981E3F9ADBE1EC761E1C +:1038D0000F689E2CF6A181BFE43EF43FB03ED9E1D3 +:1038E000D7FAD1C03FB6503FFADBF9AC873FC2F8F8 +:1038F0002C9C6FFAE2A7EFC167B3BF8DCFE0FD311B +:103900001E5BDF7C56F5D2F3BB7CB8CFF19BC7A31F +:1039100018F43BA936C5BBD0FFDBB43CCA0DE509A2 +:10392000D51785E39DF4EB8B2E9767F384A033EED8 +:103930001F2921FBD1A79E7B781AE57D6C32D851D7 +:1039400015D66C31D139A9EA9D6594EF09F54E5E23 +:103950005F49FB3935BBC3F23F7FF578BC83F27911 +:103960007DC9980F047631E587546F3450FE68F5B1 +:103970003B7A17B2450DEB5E81F085BF8F705C041A +:10398000BEAD69D5171BA37B3F070EA1F5B766E750 +:10399000C39F61BC393C7FB454EC0B84EF2B2D1FCB +:1039A000628BA3FCE22BD81568F7015E5C01E4474B +:1039B000802783939DF877D9D65F6DDF03709E7C57 +:1039C0003F211743436736BE1E85E738E53E93DC4B +:1039D000773BD39A16EDBD0C5E65794EEC4B04E94E +:1039E000C6F5B663B782B126CCD3A6B2D210881A78 +:1039F00007DFAB6C3150BCAAF2F90D9B9F46FDFB73 +:103A00009E89CE65563CFFEA5FAF423F6087216EDC +:103A10002A9F8E55890FD2ABC6C1E3BB923EE5BF4C +:103A20007DD5E818C1DBD16E9074AAD8B1DFC84645 +:103A3000F4C66761EB7E6387F532F46AED9C42F170 +:103A4000CDAD5F1951DE4EEE535882B3F7FBA59B07 +:103A50005E8FC27E925E3DF4EB45B7C0B43DA3A934 +:103A60001FE577F445BF05182B1D83FC6D6398AFE8 +:103A700056FABEC93F15E9FAF3C5C4E79FAAB59C3B +:103A8000CF9F591E8FF66CA9C1176FA792B797AE3B +:103A9000BB47F09F3B899FA7F125E17CE6AFBD992D +:103AA000E6B3807989EF4A9FE1F94A5F809FB6E3E8 +:103AB00032748CCC52088E4FD79BE83CF9A7221F5A +:103AC000DAF717BDC83FB99BEC937BC41C29433080 +:103AD0001FE3D19C2E9D420F3371CE5CFAE1351B62 +:103AE00057B6233D4E0D722760FC0CE6EF1378525B +:103AF00030FF50FFE7C9099C1EFC3C05BD87E7D994 +:103B0000B01DFBB71BE85C45C87B8437F9FD1F8BF4 +:103B1000EF03DC11180FF8349EFB270CB774916F7C +:103B200014FE4EF592D2A90EC0FF95595C0FF4C851 +:103B3000F9C607B95C0B39FFFC1DAE3FAAFDD38B5C +:103B400048FEDB0D8104ECE7DF3F4B21F90FCF731B +:103B500017F4DF6810F2AB7D0E70A94A283EF771AA +:103B60003F7F4173483E3DE249EC17D780FD1CC8BA +:103B70000A9DA7D8F716FBC20B85BC87D32F5CFE26 +:103B80000D59625F59C8BF7C9FADBDFCFE6550DE1C +:103B90007D849F4AB02FEC28A7EF99C8AEA95CADF1 +:103BA000A77CCC63AB0EC65F097C7DBA55CAA7560D +:103BB0009FF6C8E7129E2F5FFAC22605F9335C3ED6 +:103BC0004F97FA95CBCA27B45F563E4BD9FF5D7D20 +:103BD000DA836FAD3C2EEC439F8ECCD2EAD32F58C4 +:103BE00076F4387C682F1E4CF1FD30BC4A7C86EBA5 +:103BF000C53F0E71107EC3F522C3949E103C4AFC53 +:103C000049FE64CC4BDFE9E15BC99F727DEAE1CFFD +:103C1000F0F96AF118FEFC73D43F008FE7773C7F20 +:103C2000B6B24D11E7247C879247933CBA49BDB0A8 +:103C3000A643C971A1757F58BD35ACBF3BACEE0939 +:103C4000EBEF0DABD76AFA57EE3E68E479B4014D5D +:103C50003F53DD0DE42FF5B613FC7C1F72E767467A +:103C60001FF2C5C06ECAE7353CC07C784EBCFB6510 +:103C70001EEFEA727447A13DB2DCC2EDC22EBBA8B2 +:103C8000C7F07A777FE30AD47FB2BDDBC2E3CF5DB2 +:103C90009EEEA89890F843679B9ECE6777F8797C54 +:103CA000AB373CCB08AF1D22FE35596F4DA91B8D9C +:103CB000F9D56974DEEC7C8341D433E89CB4B41B41 +:103CC000FFCE3C7F1D877046F07839F3B955CC772D +:103CD00099C749C64AFFB02C0AFDFB796D3CDFA5A8 +:103CE0006495969E0BACB3A2030ED42FDA3C958557 +:103CF000E8BFE1B9CCB5DAF6722107E56172E015EB +:103D000071FF703968927A2597E58A7812EDB72DA0 +:103D1000127A78B23EFBA6D980EFAEC37A6682FAF9 +:103D2000F9363D5B81F3DCA690BD8A073950BEA40D +:103D3000FF27F17506E564486F3CF63C7FF1A3FC74 +:103D40009F225FECFA2007F302CEEC7A2F732FD676 +:103D50005FFAF7940F58EFFE85FBBEBE13F56DD7E3 +:103D60003E13E54E74ED7B2DE5A758DF63223FBF80 +:103D7000EB0113DFCFD867A3F849D7206ED72F7B8D +:103D8000F9AB9C0E5A3FF8BD007BB3F839CFF36D09 +:103D9000FF3C8A7EDEF9369815DA05FB22495E6A19 +:103DA000F658288FA3EBE5AFF243F376FEABF39121 +:103DB00079195D367E1EBD2B86FB01357BAFDC801D +:103DC000F904553BF71BE7C1F3C2DFFF2B07F5658D +:103DD000D70BDCDE3967E85887B1D4435B3CCD862E +:103DE0002B31AEC8E83E92BBB636CD42B9E88D174E +:103DF0008E87AE7DDC9F00BC94A29EEF0B1F1FFD43 +:103E0000B7C5C7677772FD7505C3FC83205E14379D +:103E10006FB7F9CD0ACD9FB7EFFB2A07F5CB77CD6A +:103E2000F79F38DFFEFF7BE69B34F4BF2B7D39BF65 +:103E3000B7643908BE70BEEFCDD72FFD84EADB6DC5 +:103E40002E82F77BCAFB9543FF77D1FBD6FFB1F4F7 +:103E5000FE83A0B7CD8E71CEAE97FF95C27EC0BC5B +:103E60007FF23F74DED23E2FD0BB0EE742FFD75920 +:103E7000EB3B2E27591B64672C13FB02AF253AD767 +:103E8000F3F3C6DC0F2A147E508BC8FF5CC674B4F3 +:103E90005F5768AE203BB370E0239FF17C361DC1B5 +:103EA000F39AF9EACDFCDE30ADDF3769A03E80FB46 +:103EB0000F0797C2F7A1DF419BCEBE8CB77762FB9D +:103EC0001417B7EFA70CBC81F2670BCD6FCEC6B845 +:103ED000F024ABD62FBA21CCCFB9CEA17D5EC45E83 +:103EE00088C3B85B51B681EEF49A82FD43FCBFA54E +:103EF00043F9BD57D7B1A606BBF53F8517F2535519 +:103F000081973F85E1A5371E041E19B773C2F1A63C +:103F10005A1F6AA792819FCAE745FEADF45325FE5A +:103F2000C2F1C684DFABD22783F85507F2FDE290D9 +:103F3000F168DE3DF814F8FEA1780DA7CF77E1799E +:103F4000E3507E5F44389E07AAB92ACAD3D5C21E61 +:103F50009FA4C6F0FAC076BD87F0E7E7FCFBB94B3B +:103F600045BB63A23546A53C2EC7A0E0FD33C98CF6 +:103F700025ABCC67C238BFBDE31594BBE2C74C7418 +:103F8000BFCB40559CBF55799C1BA4D5179147FDCD +:103F9000DDC658ECB790E149B1E264E652787F861D +:103FA000F7F5E0213DBC6F08F7BEF0BD62B4A1B1EA +:103FB000DFC32A9DEBA63FC0773A96A934AE5B17C4 +:103FC000CBDF8FCAA3F77D3AFEBE1BCFC91B983D3E +:103FD0004501600717DA7F7204FD88E516DA479815 +:103FE0005AC0FD0529F76387F1F8872C5F1FE6109B +:103FF000E70EBC43D1CE9DD63094FC9165164FD5CB +:104000008BB80E3D1F49E78A8A57FCE8C63108DFA6 +:10401000F67E2E649753D37650FEFDDC8639F7BCCE +:104020000BEDDE2D166AEF1EE665C3009FA714C7D1 +:104030009D2F42C3DC9B0F1A31BF795AEB8E731848 +:10404000BF9B362B92F23CA7B1D63F613E289BA581 +:10405000A7F13BB7DB8C888B1B5B3F53D1BFBA7199 +:10406000BC826A8D755AEC2977033CC562FFD63A4B +:104070008CC77F9659785CB878C5A0CC5468BF11BE +:10408000CFFF5DC6BFB97A98909789CA5AF4530694 +:104090008BF340B23F8E43FA45E02361183F67231C +:1040A000EB830B79FF924653671AFA318D86C01065 +:1040B000289FCB2E48C6794E4D6553D68CA67C1DC5 +:1040C000BA37A5D3C20E51BC7CB5D3817E9C9789EB +:1040D000FC8C554E8A4F754E7419F11E95CED54EF7 +:1040E0003BE64D4766BB0F21DD1734290E94F7CE12 +:1040F000898CC7DB6D3CAFE1A83D908EF18DA3AEFE +:10410000A12E8C9B0F96F93F2322C84FBC6FB87726 +:10411000E43080B3B8A9F80D94737609E69D8FF961 +:10412000BC8C98F7E1DB225800E521783FD6E861A6 +:104130009497E9FAF91571C1FBB106EB797EEA6350 +:10414000C80F382FCC57053E5B67E828C3712E0C8B +:1041500015EDB1F67C2BE72F86F0751AEC9938BF78 +:10416000CEE5161DEED34D7D80F31BF0BF5985F7CC +:104170001F545904EEC7DB059FDDB154F5B4407DF3 +:10418000A099A978BFD58DADB9E43F9FC8F6262088 +:104190005C27EE6757219DE6AD5A4DFB22925E4C9F +:1041A0006D9FD40FBE73629393EE8193F43D915D46 +:1041B000307558289D6629441F988F19E17F2E7B02 +:1041C000EE0C1C17DAF723FDA61604D2F1FEAAC9DD +:1041D000FA4AE6C6F53491B9705D3ECFB8FC9D6FE2 +:1041E00054298E24E55DCAB59467809BE457CA6361 +:1041F000B81C6FAEE7672DB7D49BA97CAEDECED4DA +:104200000CC6B6D527527D7BBD83CAD6FA2C6A7FF1 +:10421000A1DE45F59DF563A9BEABDE4DF5DDF545A7 +:1042200054EEA9F750FB9D803ECCF380EF93BE91F6 +:104230007A06E1D3E505F580A49FA171A20EF5B43D +:10424000A41FF8BB74FF86BC17AB2FBBE0FF15FCA7 +:10425000A0C77CD17941BC62DD12A227B16E8B0D63 +:10426000CE0F5313C7C786E83995DF7780FA303E03 +:104270002F387F0C055ECC0BD205DF9B104637E450 +:10428000438917783F109F178A97338F5C81742F6B +:10429000D5B928DEC13A9E7F89EA56DABF4D31B2E0 +:1042A000DD18AFEDF89995617C54AF73259AF07CD9 +:1042B00052A9C2D49078C38F6A2D4C0D59BFEEAA73 +:1042C0008BD1D4E37E76E4550C9FFD21C1BB11F95F +:1042D000F1E8BD67FFFE2B18FFD9FB3F19E1257EF2 +:1042E0003CB3E949FCEE920817C52318DE4D47F1AF +:1042F00017DA2FC3BFD07BF4E6FA22E9DEBC75469D +:10430000FB5F7F85F1DA157A3BEAD1B90D7C5D7EE2 +:104310001FE90878FF50D051DEE7572CE3E261F740 +:10432000EBED1B96CAF59D88E71CBD2FF9E7944776 +:10433000B85C6F17E938DAFBFFC4F7E5F7C2C7FBD3 +:10434000388951DC04AC7E560774F8F87E6300CFE0 +:104350003C7FAC98E9DE05C511C7EE80766FE36B54 +:10436000745F9C527798F213BC662B9D13643EC316 +:1043700099D0F1943A7EAF1CEB181883F14D792F48 +:104380005CE468B711CFADA34E40BE999B7580EE3B +:10439000A9624D8A1DF7694A447B893C2FAF7A8711 +:1043A000CEB231F6EE303DBF176CA84AE5B5C398E2 +:1043B000D81768A27557C6B14A56F17B194B9A7245 +:1043C0008D0B42D697B9A27D1EDE1F11D2FE77312A +:1043D000EE80C6E23264C601E27E89015973CB5099 +:1043E0006F0F987DBD8AF397FDFF368CDF87F0E570 +:1043F00050FEFD6B51998DC17B48B91D3877F66D24 +:104400001BE9FC1D731831AE2ABF37372B6F05E649 +:1044100029CF5D85B73ED0BD9394F7F844D4944D31 +:10442000A8BF4E868D5B29D63B989F11F73F4F6002 +:10443000C63BED0BF3785EF9F65FD3FE5AF907261B +:104440005AC7CB47F2F59665FBF3F97D7CDAF8F9AC +:10445000A45F7F44F730D6ECE4F73542C9E3BB32C2 +:104460001EECE2F987E171DC57B67F1075D9B8F917 +:104470004EBEEFF75D7173795EAEE6773CFE2BF1D1 +:1044800058A35CA4FDA69A9797C75FEE5C1AEED777 +:10449000201F86C7D1BF2BCE1E1E574C1E7EF9FD96 +:1044A0008ABEF4A98CAFCB7A695D4EDAF151782ED1 +:1044B000CE9B391CF15E979F86F946D57513A80CE3 +:1044C0003F27575A379CFA97D78DA2E7B5C29E016E +:1044D000839BCE59CA78E6797F4634FB16386AD674 +:1044E00000B0F0FE79D5118DFB71F29C74D7363D8A +:1044F000F90F5DDB46AC47BE2C6B7BCCA883F6DAAC +:10450000E1DCCE3A1BB62F50BDED18EDD755B17694 +:10451000A20FD08D9943F787305FB05FDFF055FC75 +:10452000DA568BFC5BD6AAB837E17A646EA5F8C779 +:10453000F96D3F32F842E83975B8AA39C724E19FCE +:1045400038DCA1B9EF00E145782A4CADE7DE4749F8 +:10455000F84D24E3F7CF76FF09F76F4FAF1D45798C +:10456000D065AD3BAA791E5AA41DE32AA7C2F22347 +:10457000678BEFCD1ECEEDBFD3621FECF4763DE925 +:104580005F8417E5F894A23D6776A778EF4E81AF78 +:10459000CF518F8C09F62F6B5D4DF6E0B99D3764D6 +:1045A000A0FDDFB5FBEDA874A4AB78AF6B6724DD8D +:1045B000DBD7B5F39753F6025F9F6D9D1887F227FF +:1045C000C7BF6738BF4FE26C1BDFEF637E9EC754E7 +:1045D00085781E150A673FBAD741BE27F3B74EEF5D +:1045E000FC6D942E3B48C71A7353635A6AF03E0E13 +:1045F0008BC1E7C378826137BF9799E41BC67F30D0 +:10460000ABC983FA5BF6339BDDE4F7C97BC6983C04 +:104610003728CEAFC0FAF5A617E05F5466A478FA43 +:104620009D231DB7DE8E7AF87503D163D15016C075 +:10463000F8C5853A5B0BD27991D345FBAC778E12E6 +:104640007A26B1630CE67754362ACC8D79668929AF +:10465000FC7C8C90FD4EA7EBAD9571749E80ECECCC +:104660004ABF9E794791FEC8C47C753636908979D9 +:104670002429C027F8FEDAE1DC7E3F6AE4799B95C5 +:10468000A93C2F7FB0C83BA98CE579FC67649EFFED +:104690008C4026E6BD54BE9044792F6764DE3EB45C +:1046A000239C95793C7F5FE2B7F2BE0399C877956A +:1046B000735BB3F079A7D37E8EF28B5EB4D17D4568 +:1046C000BA976C225FCDB2DEC4D76F3AEFB06C53AD +:1046D000520BFA8DAD82CFD6F5E41DBB1251CF0E31 +:1046E000B8DF1A157AFEA0CCD8C4CF1B283CDF4512 +:1046F000D6E5BCB08EF33A23F8B92C42D405FC655C +:10470000514D0477279EAF40FC6DE5E7064E25B579 +:10471000EFA23CD4AD43E97EC74EA77FC16E7A6E4F +:10472000A1FB15CB7C0AE9F3F2E74C74FFE9C9ADB4 +:104730003CEE5E5E5F47F76F9683D8E33937288B90 +:10474000F0BCDA4943530A7EF7647F28D1AFBA9FA1 +:10475000DB4B876D4FA4907C6F3429A8AFCBC1523F +:10476000407BEF3C6BBAF369DE8E9E3A2BDF68A28A +:1047700073025E68C773A10CEC20E41B896F78AEEE +:10478000C95BEC746AEF756817F2D72EF0FACE7039 +:104790001E0FA88A6C7D2295E6C7E504E8C3F3C91D +:1047A000993FE9977198C791A1A07E286FB574A22F +:1047B000DD51BECD40F7970E96F971C20F2B0385E0 +:1047C00086FBC5658CDB9793F5DB283FECC2164B67 +:1047D0001ECEAB53DCCF597EDF4F397E5EB2B9F9C6 +:1047E0007D237417123BB93999F2C5A7620E19F1EE +:1047F000C9087E3E21B62907E959BEF20A1DE5899E +:10480000E8B9DF05A55BA13C7A33E9D14AA147AB02 +:10481000568E8B1E8772F5969EEE132F8F5E407E0E +:10482000DF0515E4E932FA3F1C6F83B3B95D500927 +:104830007282E795ABC439AB8ACDFCDECA8A153CDF +:10484000AEC89EE3F7942EB604A2F07B8B37E95DE9 +:1048500048A70A636B667FF84E4436D75FD0DF8B7C +:104860007A498EB7D8D2BA00C75BFCBC85F47944CC +:10487000761C7DEF4CEB63F168E7F6EECFE10EF6C8 +:10488000DB10159ABF23FBF5CCA795C7932EB0F686 +:104890009F7C00AF7CBECD42708144D1F9B5F0F968 +:1048A0009E36003C00FFE9E72D747EEB53D0833E3B +:1048B0003C871DE37E94F21CFEACA77B7F102E5C30 +:1048C0008F16FAB5EF57F57345631E65D55B852ADC +:1048D000BE1F9DCDF531D0E126C2D35B063AA71AA3 +:1048E0008EF7F3426FF7C8DDF391C477A70770FA2C +:1048F0009FDECEF3E73A6338DF009C2998DF7CFA2D +:10490000F921B974DE138D22A07BB99DD3FD744CBF +:104910006B8A3DE4B9E4373CD09488FC81EFA4A1D4 +:104920009DC0EDB10AF32ACA67C17CE7FC3C2A03AB +:10493000A6CBE42B033FF2BCC36C6157E0F7E24522 +:104940005E3DE9AD5623EA65AFB01F2BB785E73B67 +:10495000F3E793B2159967ED889379D698DFED5315 +:10496000282FA6A2E1EE32948B8ADAD5B723BF4A6C +:10497000F82B545684FAA053D1131C9D167E4F3643 +:104980000BFD4E2A2FEDF1C1794E13DF9B91ED9077 +:10499000F62D6B82712A1B945534BE53C60DF87CDC +:1049A000E47B800623AE139D13C5F33EE62BE10B9B +:1049B0009FAFA4EF826CAE673A9D8E47C7C705CF05 +:1049C000B99DBF342A3AF65BFC6BF45C7BF28E41F6 +:1049D000D617E35C619CB1D95C5F55007C0867E643 +:1049E0005A6DBE79D6466D7DD8366D3D7BA7B69E95 +:1049F000D3A6ADBB5ED1D66F17DF457F1FCFBBA35C +:104A0000BF8F25FAFB0E13F7F7B18EFE3E96E8EF47 +:104A1000633BFAFB58477F1FEBE8EF635DE21BFD4A +:104A20007EACA3DF8FCFB7648BFBEEC47D467B0AE1 +:104A3000BC73304ED9937F5C660D3BC735509EEFFB +:104A400091F9A0917DE48346229DE4B9D8F0F35B0F +:104A50003DF7E2869DDF42FEC2713EECEF7D3C1BDE +:104A6000E0FA44695F91A4E07D7CFEE18B689DB72C +:104A700058319FBD63F9A72BD03DDAD1DFFB7436E7 +:104A8000DA6986EECDFCBC7480F44CC752C75BD7A4 +:104A9000487B04F8A618B08B7C2CCFCF7EE77DB77F +:104AA000DF79CFAD964FA43DF7ACA13B09F5E5B159 +:104AB000ADE65508E73111BF64B3CD61F90DDC4FA8 +:104AC0005AF488B21ED7A7DDD9FC9E81F387013B3B +:104AD000DFC29FF32E8E223BBBA7BE4AD1D17D19E8 +:104AE00089F1B40E497B2C45017B0CF51FCC1FD7F7 +:104AF000E9216B741AF887FA2334FC367C4B6CD8A6 +:104B0000F993019AFE2377A7869D3F19A63DDF30D2 +:104B10006BE97E5C9F67AE1AA5E957E219178637E5 +:104B200001A7B04B4BD01EC475E67E33ED3F2E7E01 +:104B3000574F764C293E04BD588A63011D4B378A76 +:104B40003CEA3AED7A5BAA321FDE27364FAC43923D +:104B5000DF4AEDCC1D03EF9FCD6DDA8CF7B896FDE3 +:104B6000E1ED7C3B9ECB5326266070E27743BC1F71 +:104B700023DFA418DC94B75BB9232306EF753B73DE +:104B8000F855CACB947C9262B047203D5B9AB87DC1 +:104B90008FF1317D6C90DE2D4DFD22D2ADC1798536 +:104BA000E4AF903D7C01F357A0A974A2E2338E0CD0 +:104BB000C2BF48AC1B12DEE3C2FE67E97C9C1F8BC0 +:104BC000E79579AFAD8B05D29DD11DF87225AE4F1B +:104BD000B9AD9901B4D39E6E89BFCD89C70DBCFF15 +:104BE000C4792C7AB3300AF3E9BED866A0F3047F07 +:104BF0006FDEB00EF39C57366D30621CA05CF51B67 +:104C000029CF736B8B11F39CAFDDD242ED0BB61441 +:104C100093BFB890D592BF7842DEEB21E65F5AA0F1 +:104C2000ACB5E3F9DD115C4F9446F07DC7C9FAF1EC +:104C3000AFC6917DA550BEEF2CCFF4C9FDD14E6912 +:104C40008DA17B98FA8F10F76185F1FDF937F43C5F +:104C50008E3B8BD3B9AFFBA1665E74129FCFBA387F +:104C60009CFCA89B0343B9DF9AADF55B4B8D8EB7D7 +:104C700050BFB33FEAE9F7517AE2082E03D9C7558E +:104C8000B0BEE0F947CF78BD860F6B26456AF87451 +:104C9000360BE17FF8F42D98EC12529F35354DD349 +:104CA000FFD659C3C3F83A2FF89CF4C1559A7394B0 +:104CB00055D842E7500A7AB5F3F398D76BDEAF6266 +:104CC0003334E7F3CA36F27D85AA9D31B4EF582A12 +:104CD000EFD5F3F2F6EADDBC1D26A291AFC185AE99 +:104CE0007FE7EB9F81FF1683D87F988DFF9DD61BB2 +:104CF000EF60E9F5DC4780F74960FC40730F81D82D +:104D0000BF44B8C9DE15F1A4AA2C1E4FAAF2B51BE8 +:104D1000F1BE0EC0BBDA0FF3349B14A207F437F7D1 +:104D2000CBE3F5259477ADCD1FC3F130DFB2FAB0F8 +:104D3000BE18E524FC39F01DB77BF7F0BCD7856BB6 +:104D4000C2F33557D1FE6935C68742E8F6EC08074D +:104D5000F16DF9961D8706001E667A387F56B64EAD +:104D6000371467F7E627E06BBA177B0103BEC27DF5 +:104D70001F905FBFA3EF79A3B9887E879C7FB59B07 +:104D8000F3DF00E4BF9CDE7C57E5AB35D2BD2B6B77 +:104D900015F69893F7477C0C407E0CC307E12F0C67 +:104DA0000F123F3DF80A7B1E8E97055E46FCB160F0 +:104DB000B7E2F72BBDE7D117DEC2E9BA90B51BF118 +:104DC0001CCAC29D8A0BEFBD97FB396C6C581CE95D +:104DD0008D348A23557B045E241F78389FCFB8C852 +:104DE000E322B7E0BDAFA3827C316BAA561E6FBE33 +:104DF000184FCF7F289FC0CA4F71D8EFCB1F721EAC +:104E0000520F63BC90F842E44B87CB4778BC71EB00 +:104E100008116F1CC3C668F2A3FBB8A7233C3F5A16 +:104E2000AEDBE1EB46F11FF8BA21F5A757AC07DE80 +:104E3000E5867816BADEC876117F5B747F16DD478B +:104E400092B2B41FF52BB6D829BFBF7829CFBB2E9D +:104E5000867E8E10FB6145435A0AAE031F3F3864BD +:104E60009D0FEF69BA372E7E2CD0F9D872431CDE25 +:104E70007329FB7DBC7C720AE68D1C5B6D9A4DF735 +:104E800009FFCC4CBF9354B52B81DF3FA7B7C66356 +:104E9000BEE6D917FAD1FD487F16EB45E5F217A318 +:104EA000F03841C572BEFEFE6888B77D04ED3FB79D +:104EB0006CA68D0B7B4B0EEAFFBF618C08FA9FC07E +:104EC000B1F2681DA275FD84C57E0B8E7B62AB813D +:104ED000EEB182E76EDC37FAB112F8E41ABAEF46A7 +:104EE00089C7B8CD9977F5743EB34CBF3F07C7ADBE +:104EF000ACDF9D82266C691EAC97E8579ABC7FC3D5 +:104F0000EF562CDF90429B508D2DF43B0321F1DEB8 +:104F1000E323D06FC4782FD4BD4B33A2F93DB597AE +:104F20008FF74ABCF844BC77B358BFD14EC712EDD7 +:104F300074CCEF413B1DEB68A76389763AB6D7ACDA +:104F4000D1DA7147C4FEAD8CFB0ED67F46BFE3E3DA +:104F50002B6059B5B4DE5AB3D0FF5CAC44B8D05E18 +:104F60005CAC70B95EFC9185EF3FF99334FC107E28 +:104F70008FEBD5DD606B85F0ED3517CD2CF4DCF2D1 +:104F80004416A3A9179A9334FD27DB9D9AE7D726E9 +:104F90000ED53CBFCE91ABA9DF9075A5A6FF8DAE17 +:104FA000899AFA4D63AFD3F49FEE9EAEA9CF2C9AA7 +:104FB000A3E97FB3A758F3FCD6D9659AE773BC770A +:104FC0006BEAB797DEABE9FFA3DAA59AE7FFA6671E +:104FD000748F5F1BFA5726BC77C84CE5573ABB8ADB +:104FE000F6E1E23733AC48FFF185BADACBE52D8C38 +:104FF000C8E1FC3D77A43B2BA73FBF3F0AF9769061 +:10500000B81F6A5C0EA76732036B8DFCDAF624E4E6 +:10501000A3F07EE1CFC7471EB8E0001A3E96937B0F +:10502000AB0AFA68FC150746A541FD8D9C525E1F30 +:1050300077E0B7A9507F27E7B95B55D02FE3471E2C +:10504000B880CF6F1E59C5EB3319991E1DDB07DDE4 +:105050008AF932E3AF495DE5E2711071BF4680E243 +:10506000163DE759CCD6405AC83D21880F3C378FB2 +:10507000F8C032007C8CE501E0632C5F013E2E011C +:10508000FD7508F818CBC3E06F62FB1FC1DFC4F2E7 +:105090000DF037B1FC13F89958B6839F89E55FEAA4 +:1050A0006753F94EBD97DEFB6B7D299547EA6BA9E7 +:1050B000FDFDFA3A2A3FACF751FBCD3922DEB15B58 +:1050C000FBFB5472BF52EE4F2EAB651D91A8073A01 +:1050D000D418FCFD37B9EFD8B77FAFB24F42ECAF71 +:1050E00068E6F6E6D0BEA2F677349E4EF3CEC7F65B +:1050F000779D3333F082F95B2ED6BE8A2940EF8A42 +:105100007B06C2C71D97C3EDDDAB46BACB73C68421 +:10511000FCBE80D84F5F6BE0FBE6723F5DE625C8C2 +:10512000FD73FA0BC92792F90A579BF9F96D993F5C +:1051300020F393267FCE48FE2734AAB4CF66535976 +:1051400000F30C64FED1041C08E83E218E917E48D9 +:105150008076631EBFC75A0FE5C6AFA17F4E483E9B +:105160009489F930AE9920F6E5A11FC137F9732F64 +:10517000E5474D10791883701F93F7A37D5B1BFAE9 +:1051800043F87EBF8E8318874BFE27D004FA3DA3D9 +:10519000F0FC01998781FD2379FF008E9BFE0FF8BB +:1051A0007E54504ED64E6C77621C6EED3D6617C62F +:1051B000CFE4EF2A505009F03253E835DA64C7BA29 +:1051C000582FD996048A0F1588E7FDD2BD6B916ED2 +:1051D0001E93FDA34892ABB441680F4C17F6F2B78B +:1051E000D0AD05DF0BA79BA497A447483E09D14348 +:1051F000D24FD2379C8E927EE1F49274FC9F4AB7D4 +:10520000D12ABFE7CF5469A6FB03BF8B8E7775B356 +:1052100029D1D0E59D74EF38C473F145C721ACCFD7 +:105220006313E9774FE4F38FFA78EEFDBCDB101DD2 +:1052300042EFAB852E57332EDF5FF693F75FC8F151 +:1052400053B1FF98DEFD174FE6E7C28ADEE571F441 +:10525000D7C5BA89FBEAB9F921F99AD90BC92E66E3 +:10526000566E5F3AE01FD44BD75C5435F66611E3B7 +:105270007A0A166615F9AF286CDFFA7A618F5E1F1D +:10528000668F86DB975FE408FBD2C99C3FF05ED750 +:105290004B3914EFD5DA2F98F785FC9CE6D0D37DF7 +:1052A00034F21E57792FF024214793F05EE028FC5A +:1052B000FD4C2FAD87D7321F95D7C17CB0BC81057F +:1052C00068FDBC11142FD66FC2541FA81F8C9C768A +:1052D000079ED12B1C55984EF77504EF2B8C1E3969 +:1052E00086EE2BFC9B3DE4BEC203931CB4CF78C07A +:1052F000CCCF05A3BCE1EF23CAF9FC01D69D7458BD +:10530000170EC2BA84E5ABB02EA5C3FC5E83750947 +:10531000EBD767F1DF2998E2D0E6FBC8F76FB0174B +:105320008203D237BE6EC8F9DD40C4E7EB314326B5 +:10533000E17C5F8FB96212D2F7F598041D2F4D46BC +:105340002CFB7A5FF2FD0DD9FC7CEA0DF629F4BD49 +:10535000FF0FF8BCF272F81C87BC897144F3DB5173 +:1053600089A9B8BF1625EE557D33470FF593081A66 +:10537000D81113EAC6119CD7D45D49E5A7F52C1BBB +:10538000F15A69E6F80A8F43B18D09BAD0FCE36B94 +:105390004DDEEB46A27DAF6B8BBA0A9E7FBAF6ED6F +:1053A000EDE83F801D3D0DE1AAD43B56B9302EF308 +:1053B0003ACF1F65970EA6CCB0F5E647B671A6E6C4 +:1053C000BCA3E4C74AB3C4A38FEFAFA7BBC7717E2A +:1053D000E6F7A4CA3C9781267EDF82BCB713ED199D +:1053E0003AE7186637E44770BD36D0C4F5748FBE0F +:1053F000328A7519C6C9473DF86804C5192393DC7C +:10540000F3701E324E7B7E6024DD833221303C1AE5 +:10541000EB45181700500F887CAC6B87D75A538127 +:105420000EF543BD55F81ED35FD2A37E7C234361A6 +:10543000FD148CEB8EB2925FF81DF21B2EFFF78CE1 +:1054400014F29FC37234E7E4045D003ECACB39FF17 +:105450008E9EF2E326B0CC27316E5178D88099D356 +:10546000C1BCC944BE7F38F930CF030AFAA1DD04BC +:10547000E7AB76853D0DF33325EA9823448F591C1D +:1054800011CC11024F6456ACA66E730DD0F48F1E72 +:105490009BAA791EE31EA679DEAF284F53EFEFB922 +:1054A0004AD33F617681A69EE4BD5ED33FB9748640 +:1054B000A63EA8F6364DFFC1757335CF9DBE72CDA1 +:1054C00073794F29F3B9DBB3E2B99EC6BFB4C645C1 +:1054D0009A7E45D605742E32A3E93ECD78CCC1E341 +:1054E0000D3EF807F9EA0B3C780BE5E4446D1CA28D +:1054F000D03EF1152451B2C85B62CCE5C075A0D096 +:10550000AE8D4B245B8B287F3EF93BF29A76FD50A3 +:105510003EF00EBB3C1F5472BB229C0F5E45BD94F7 +:10552000C6F70942E78BFB04A178C17D82D03AEE31 +:105530001384F6C77D82D0E7B84F10FA7CD4612D72 +:10554000FDC7B46BE97FC59182EF45AF2B3BB47CBF +:1055500021E935EEC48CCBD26B36FC43EB34E3EB64 +:10556000FC24C05380F5A69BA497A4DF7F956E67AB +:10557000478AF3DE826E5FB05563F0FEFAAE62AE2C +:10558000AFFB5ABF158BFB02EAD72CE49D31BDFD62 +:105590007999071AFEFB2CFFA6EFB0E13AF195AE20 +:1055A0006304D23389F1DFC37828C1FB0DEAA50477 +:1055B000CC2641FFA6EC965C5C37BB06751FC5DFA9 +:1055C000EFFE3F2308244500800000001F8B0800E9 +:1055D00000000000000BDD5A7D7454D5B5DFF7CE16 +:1055E000CCCD4C32432621E403244CBEF81CE0CE43 +:1055F0004C625169BD20A17435B026F8418231CC8E +:1056000090044140438ACF60F165628206AAAFB13F +:1056100004A43EAB131EA0BE876D40AAB44DDBA907 +:1056200028B52E6DA9DA575A5C7190D6A25619E3A7 +:105630007ACFD8D5D6B7F73EF7643E84DAFEF1DEEE +:105640001F2F595927E76B9F7DF6D7F99D7D6E6413 +:105650009B4B3FE801FA89A9D500F16DAEC15D0A07 +:10566000C027F4733540F314681FF202D8756CAC90 +:10567000C1517ABCA67E2E408EAE72DDA5BB3570C0 +:105680000284BD6044711C58A1B419FB6B2DD888ED +:10569000F446B75BA3596500C58E905B9F04D0F3B9 +:1056A0001BBB1D72B11D3CB96E1A0F9ED2A00BE040 +:1056B0004D1B340C3993EBCAB2D8B16812CDBBCABA +:1056C00082EB15002436A8D1FD65BC0ED37FE840DF +:1056D000517417D6AF9A1673CCA0FE3DAABE1F52C6 +:1056E000FA377944BF4589503D719716DD8F5B7954 +:1056F000DB26FA235B3CD183440FA28E7AE463C697 +:105700003E9C3A93E5019FE0DF435658467C3D14AA +:10571000552355F3016645ED60B5A7F403F6F3BED6 +:10572000A38E95B8EF398FBBD3FAE70E15A7D19B9F +:105730007FDC93D6EF8BCD4CEB0FBCA0A7D5E32439 +:1057400017A45F736A41DABCA9F8A7FA013E77DAB9 +:10575000486B9FB6B16305CCE37E43CD07B822BE4C +:105760002C8DDEB40BD9AA82FDD7E9E50024D7F34E +:10577000C1B47EF008B934DF5118253B98628548E2 +:1057800016AEF32D1B441CF95C37342C3512308EC9 +:10579000D3FAACD11E94DF65C8436EBEE0CB42E3C2 +:1057A000B074F038C107F647ECD48FF4886FEC374B +:1057B000ACA23F928DF5DDB33D6C4F36ABA14205F7 +:1057C000C023B6F806B0A4D86116DAA193F56A90A2 +:1057D0001D3CB26D729A9DDE68DAE3EED9C0FB3AE9 +:1057E00068873541945BCF5D4E289B4FF3E225A43B +:1057F0009FB5A61D1F9F6E84741EEFE6FAA3AEF33D +:105800001B004934CF17EB34A9EA9A7A9AAF40C308 +:10581000516F729DCDE6FC3ABFC2EB34E70A7EE0E1 +:10582000AB1ADB91DC47B106BD763FAF3B8BECFB9F +:10583000A6FB86EE9F815D4D5ABF8DF685F6660B01 +:10584000223F758BE356F0019C7EE2D77B9D57E0AB +:10585000BE3A51AE57026C1D5AD810C17F97A39C17 +:10586000889F69F83FE9A18EE48BE588CFC2EBF70A +:10587000EBC0EB8DFB5B01B0BF8D82E06BB4538B53 +:1058800046CA927A4CD15384F472A80B59445F787B +:10589000BCCBCEE5BF77A1FD56011CEE2AE6FAB7D8 +:1058A000BB3C5C0E75CDE4F6A35D3AD78F752DE059 +:1058B000FAD35D06D78F772DE3F2FB5D416E27F3B8 +:1058C0008442804A615AE37291F623E55277B7D059 +:1058D00093678B2DB81FB750A7C232C59F94F707A7 +:1058E0003E95F739AC0BBDD2388A33725CADC59B9F +:1058F0007BD6991C27E34A661C91E5FFD67EC7E557 +:105900006B4DDAB923C5BEE5BEB1FF127E92EE4FF4 +:10591000FC73B929BF72316F823FA9B714FF61FFD1 +:105920001AF71F883792FF48F9462BD56524AF7BBD +:105930005D42CE520EEFEA425E7B7561C710319C2C +:105940003ED457C85CBAD6F2E730D94F9B4BF364CC +:10595000E19090735D1D4C00F88211DC7B2FB6AF97 +:105960001DB0C120B68771D9CE7C516E47FEC211E1 +:10597000DB9BF1947874330473630AD51216A2D7B3 +:1059800073BFE27E08EB2D7DE9E3DA40D0B9D9B9E7 +:10599000F46D5AA70DAC6FC6655C2A233AF77D609B +:1059A0009940A535390FDB3B5F1FBCEAB994F8F588 +:1059B000BAEE2A782B87022DCCFF84FCACD3AE92B2 +:1059C0001CD7DBE5BE9C7A8CFCE4358B9E85F5D13B +:1059D00068452E9D5FA81FF62B2C6359C8C7475DED +:1059E000D1AB9E43FD7AF6219140526E28CFEC99BF +:1059F000746EF45AF52ACFA7ED6B5C9E50C8EB7617 +:105A0000D8454C453BFD05C9ED8F2F58208B626C66 +:105A1000839DFD2364F6FF31F2E159EE3FE6D0A904 +:105A2000FE9EEFD4BC18EE2F44EB4FC431C5E9F411 +:105A300046B7DBC14DFE7DCC15051CF78E327828AC +:105A400017F5FE8E7AA4704159929F505CCCBF949A +:105A50003FDC342364F521BF211B1436907E0E5B9E +:105A6000F46EA4BFD3F96CA18172B95A31341FEF1F +:105A700027AA51BCBA05ED98CEA33A3C17C97E259A +:105A80009DC86C73DF19FB1A8F4B0B9528D9D16811 +:105A9000C4C2E7F8E83285F9C6B86690BC7F05480D +:105AA0001DF9AF87580195E4A79025FC944AF2535D +:105AB0009821FC94EAE4A754929F52FBB5633ED62A +:105AC000D3756357F17E437D57707DFAB4889A4D44 +:105AD000F1F946453F88C5AA03B0231BA7C6BB57AB +:105AE000D58490B5E93EC1F774F37CF9943E7DE22C +:105AF0005C79CA971E673BBA158EB31D8A382F3B57 +:105B0000EE5738CECAFA87FD66BD56D4BFB243D42D +:105B1000E336679F922BF6575925F64725EDAFD20E +:105B200026F64775DA1F95B43F6AA73844758A434D +:105B300054A73844758A4354521CA2F6B5102CA5BC +:105B4000A3E1F309802529FE75F5981D96A4F8C9EF +:105B500022C84BAB5F632F491B5FEB2E4BEBFF6201 +:105B6000F1ACB4FE2F797C69F52FCFBC226DFC72AD +:105B70007D515A1D167C2959C77806467D5AFD5A13 +:105B80006848D243395D1F0CA7D15FD5B0219D5E17 +:105B9000684BDAFC1BA1336D7E457B77DAF8359DC7 +:105BA0000AB4A6D6311C939DB5EC9BC876F2978AB1 +:105BB000600BD9F91B397FBDDD564E7A1EDE40766B +:105BC000DAB1395B177AEE5F26F4AE82D073A29118 +:105BD000F5BC5D13F55ABDC87D11FB19463D2F413B +:105BE000BDFC08F54C650CF54CE5B3A8672A9F434E +:105BF0003D2F41FD9D443D53F902EA99DA5F443D52 +:105C000053F912EA99CA9FA39EA93C857AA6F295F8 +:105C1000AE062E5FEB0AF1BCFFEC5ACFE5E9AE769B +:105C20006EFF6D572797AF7745B87D04F968B525A6 +:105C3000F9229C5B99225FC2B59529F2211C9B5ADF +:105C4000271C9B3A9E706C6A3FE1D8D47EC2B1A9F2 +:105C500075C2AFA9E309B7A6D69FD03DEC8784579C +:105C600053E7113E4DADCFED8F3CFF36D9D7C3EF93 +:105C70003F47E5F4DCF0510543C301DFCF1BAC2502 +:105C800058CF09FBF3102BD8BA5F6D58822120340E +:105C900016E078300F128C2B433896F4168A01DF09 +:105CA00003E67E5CC2FDA767091CC83FA877DF3109 +:105CB000607C797A9687DBE57C1DDC162AE5F86442 +:105CC000FDE2E332D797E3383EA6F081E7A38FE207 +:105CD000B96FBBD34FF79543AAB22688F67408F183 +:105CE000D14A8CB7730E1BAA03FB1B8EB97D160F0E +:105CF0008D6FF7D37DE53726EE91E3A75BE1059B3A +:105D00003FB98FC73E57B69FE8C57C02B726F71943 +:105D1000B7523CC738614471DEC2C4A96B72717C52 +:105D200028B2A886E8D769022FE03A57D27D6F4E95 +:105D30004431F6A7D8F78B26BD50E4C8B3145F1FD3 +:105D40007B748598972DE63DF6E8045E7F45AFB2FB +:105D5000DF82EB2F3C0CC620CE7FD5E477CEE198D6 +:105D600085D60BF78AF524DDF0C3A59A87EE93D08C +:105D70007E677135C948018ADBB8AFE7685F527E3C +:105D800072FC7474191B9E1FB712ABA8CA9D33FB1B +:105D90008324E7A02AC6D9ED062151B8F5783D50F5 +:105DA000BCFF7C755E6D01D11D069D60EAF2EA5F65 +:105DB000A6ED9BC57639D3E5F36B464489E5E056FD +:105DC0005644BAEFA6E36D7964CBF39368FC01D037 +:105DD000CB3C7CF4C017FC49FE661B47543CFEC01C +:105DE0000BA75487427A87131353EC0835711DE9CA +:105DF000DDA7DB80F4526F75DB286E649EEF122FF7 +:105E00007C487881B932FBDDA2BFE3AEB1B3F75273 +:105E10003CFAAEC00B12E784DD620FA17D0AC7B564 +:105E20000F7BF1BA4172FE6E561408AF219EF0A0AE +:105E30003DBEA7BE54B80AE76DAE8896AA28AF5BF0 +:105E4000260FCECBB7301EB0F991CF77232756342B +:105E5000209DB3BD4F1592DC3EECBD3E37C694117C +:105E600027E23AADA67C5AB7AFAFA34D86E70E69DD +:105E700074AF7913E38C3183F85F981BA77DF50B22 +:105E80009CD780BF14A7C32F4F2C24BC9589FF3605 +:105E9000F4DAC21ADED33664E0BE8D26EEDBF819E2 +:105EA000B86F8ADFC47D3AE88CFB2C4DB9A18BC456 +:105EB00063594A7C87F8A6DC7F117C03E6FDE52B5D +:105EC0000EB1CFF0CB27AE67DCD25EA5126E917813 +:105ED000A7A95BE0193802D12A85EAD7B09F367DA1 +:105EE000D7D0159CF70B13C7AC1C9BC2FA78D5C44E +:105EF0002DD78FCDE1B850177770FB0D63255CAEC1 +:105F00001A9BC5ED2B9D223EC4BF07D1BBE93E17AE +:105F1000C912386A18183765DAA90FDCB564F7B307 +:105F20000DE504C1C5E58483905E03E1A28964F7B1 +:105F3000E11D93C8EEA3C0B835D3EE573595D5D241 +:105F40003E662D5380FC55DA7D28F213B6D71568CE +:105F5000AFD4BE3CD26D2BA4798781F71732EFA75F +:105F6000D2BE33FDA139C7BCB73B45DE68FC3E4F0E +:105F70004C5E49CC071A0D2FDFA301260B0303D477 +:105F8000B3CB2BFAD7FB038DBD957C0F8AE4FA9334 +:105F9000F72CAA3B52EE555477A5E41908622C4C15 +:105FA000B9E712BE77887950E84FDECB280D3496DA +:105FB000722F2E37F997F737A26F15F36285FE64BB +:105FC000BE40E627284F4071B7D6F27A6D11E3C084 +:105FD0003CBFF057613F6F9AFE3AB17AF1C600DAE2 +:105FE0004BC7CEAA22F81B76D9827A23FF6CCE8DBE +:105FF000DFAEE039B6C30FC69205008D20E505314E +:1060000040BB5F6DD6BF73F4DADFF47959CE5CEF35 +:106010003EFAF9C608D2DFB9F01B41E22F19078317 +:1060200006E939C76B40C8FBE97DC8FCC477FC6250 +:106030007C669EA2C52BCE0999577B73E733DF4E52 +:10604000CDBFC8FC1D9E637C8FD9BBB2D8B7CB8CAB +:10605000A764570FDD72199FA7FBFDE679857EE1E6 +:106060009921F02F95847F3D5902FF529DF02F9585 +:10607000847FA99DF02FD509FF529DF02FD509FFF0 +:106080005249F897DAFF54167C58F873BF9DEEBF5B +:106090003033F1CD83B87E739706C48FBC273F7A27 +:1060A0004BB641FB78F44E8DE3A2BC2F3769A79E17 +:1060B000B79725E570A6F31B363A3F50EC551EA462 +:1060C000B3BADDA153DC9E581D7C82D6C9F1EA1A11 +:1060D000C5999037AA7850AE93DD66BEA622E1BB83 +:1060E0001DCB8D0141A7AE5C9C8BD32CF01CA05D19 +:1060F0003D5E640C519C9D581D7A8ACAB5C3BE93FF +:10610000533C744EE569A49FE6229177457996AE9B +:106110007425E57CD22FCEDDDBC997B1BC60E607E4 +:10612000514F7DE5C85F63819BE58E76DB4BF7AA17 +:10613000937E717F9179B7645EC2CAF921AD538BAA +:10614000F628229FA0F99379092927995F48CAC7A1 +:106150007D92F3A82ECD43B825EC9CBE94EC3EDC9A +:10616000AFE4533CA8B5D49D64DCFC405939E1E66A +:10617000317FFABDB0CD3CDF3AF6546825346E2746 +:10618000A237ACD7E57B984EE27EC5BDDF437E8566 +:10619000E352F240ADFBAE60BF688D6219B8B4FF48 +:1061A000DCF8C089A9DF23BB8B191AF1DBEAC6F042 +:1061B0009092F768E957D88E33EBE7FD229FD6849B +:1061C000709DE474D3D6326D2DE501115E7478694B +:1061D0001F1EEE97F39A285FEE67BD0A793C807C1C +:1061E0009789F5FC29F4D712FD94F5A51D8CFA5D6D +:1061F0004C2FECF668256554BA99CF4FC9C1947FEE +:106200004B2C6AD3891F2BAE8BF5D5EEA88DD659B2 +:10621000DBEBE3FC7BE83EB14EA82F4F9B4BF8C96C +:10622000EAD6A662BD295BF81FF2C738B315E5921E +:106230004F79B67CC495CE4FCB276CF2DBDA9FA7A3 +:10624000B5A5B53F6023FB6E34E3FDDADE459A4A1F +:10625000F3AD62BF9E8089074D79FE7E8B6317E5A3 +:10626000F91B077E5AA5905DB697F814DC677E404F +:10627000F8BF27C32F1ADDFDBC9F7179EEC1FD2346 +:10628000C9367790E9A33D44C86F5A0704FDD6810B +:10629000B0E6C5729D35A45DC6EBBB98DEF8BAFBCF +:1062A0007E62AEEBD0695D7087F89DE1AD3DAB4A93 +:1062B000791F030FDA486E2EDDB3947026DA01DB06 +:1062C000A5B487E680F03FB97F7FC0CAF4FD817432 +:1062D0007F92E791F4ABD6FBC260E0BA2DC5783E61 +:1062E0005EC4AF32F3758D66BEEE112D182B56923B +:1062F0007E8FE761FBD18B9C131BCDF5579B7A40BA +:10630000B9703C19B77F530F4D24D794F9448FE8E7 +:106310007E3160E296C5B1AA2DDEE478B96E53BE37 +:1063200098477A21FBF8A2A92F1ADFC1E3C5FAD258 +:106330009F5BC6F1EAE11D8574FE1D5138AFD67131 +:10634000FF89A977907F3F9943995B7877D3C15BA9 +:106350004BE870B546590F92AF36C427E4D7EBCC63 +:1063600073AF357671FF4ECC0E350452707FEBEE75 +:1063700027A7539CC4FDC7284EBCFEE40F7E75A51D +:1063800027795EC9FDACED1BE4B878D37D797E8BAF +:10639000888B7D1417379AFB6EE915FA02D417E142 +:1063A00037A9D770AFC2E7434BE7E551C23DE37869 +:1063B000C0D467A61EA57EA51EA5FCF11CE23CAEBE +:1063C000C4CB92FFADA61EEE0888B8B2DAB4BBD536 +:1063D000EB17715C5CDB170ED0F1DB68B637B6A645 +:1063E000B78FCBDF2DE5EFBD87EC787448C87FF41D +:1063F0003E9BC8B31D16F9C1773B9EF9F90D38EEE7 +:106400009DBD83A5A9EF2A6D66DE6C9D89176F4639 +:10641000F95F2C5F88F2EF0BA4C4BF9B1F35E55FCB +:106420003EF4FEF729BE6CC9E277B716FC5B80F23A +:1064300079F7F06EDB146CBFB14DC9237E1F0C944D +:10644000897D0E0DDACA09FFB7FBDC94E77DD08C9D +:106450000399F68CA50129F2A5F340C94FE215393D +:106460009EE2D111E463EB16C704984F74F3F2DD9A +:10647000781FF9B169A732BE48BECF6D09FF0BDDA9 +:1064800057CE39847D6FC2F9F4BE736E915EDAE146 +:106490004DE23928183AC2EF60B779F93E8EEBBF6A +:1064A00040EF0D4F9B765359198F12FF12576A1800 +:1064B0009FE8BD67BF2AF65F6E11E5BF660FCD6A24 +:1064C000FF1B78AF7253FC03E247E25989635F37E1 +:1064D000E522F1AAC49F978A3B1A1CE82BA7F783F1 +:1064E00002D07B3C493B957432E38FDCE7949CA15E +:1064F00027C84EA6DC36DB4F3840CB863EDAC72BAA +:10650000A67D66EEF35C9990E7A5F896FC8ECB012C +:106510008D71417E927FC90F625843255CF6D5B9D3 +:106520008C0BCF75EBA524A74BEDEF5C5988FD34A0 +:1065300051023A9DB3978AAB8DAD4A84E8DA3A5D51 +:106540009C77907ED23A9EFFF7E6C6E9FCED17797C +:10655000FF730A9E2BB4AF2D0E95EDC2DCDF3F9A80 +:106560007F1E0BE49B79FFB88BF05A53B6E9FF31DD +:1065700071FE8E7456F03E65BB3C7F47DC71577EE2 +:106580004ADCFD5DBB797E211DF21FE8AC007A9FDD +:106590001FE93FE752D94E057F72DE569BA00F2EB2 +:1065A0002D7A5021DC52AF85B1FDA6CE576D0A96EB +:1065B000966A61AFD32A868CA202C66D8C2B7A5C58 +:1065C0007A31ADD793A717A79EFF39CE1B38FF723C +:1065D000AE2C5649F9A884CFC1F21E71DEB094E208 +:1065E000CFC8BE3C7AE180AD8A3ED24918744716C6 +:1065F000E7D5EB54E853D83E62DA143ABFBB158EA8 +:1066000007B2FDCE39A1FC6AE2C372E4BF7F4B74CE +:1066100077E4E8C407FC19D7C5F848D769F2EBDD81 +:1066200001816B33F32199F98F699A87F323899F4D +:106630005960BF887FBFA67ADBCF6C69EF2BF2DD94 +:10664000A76DF05ACE3BB49AEF396D940709F0FB71 +:106650003D0086BC7B06AE2924BB687DA0766F0416 +:10666000CF8F520582145F7E678DD7531C383F58F9 +:1066700094DF9D72DF3913CDE277B5F383CFBC7C15 +:1066800039AEFBFEF1493E8ECB86CAE7C6CECA02C2 +:10669000D6B75E2DE2504A3ECA2882643EAA75F003 +:1066A000DE52C0F55A37F74CA7F2FCA0A381E2FDF9 +:1066B0001277FD923CA4BBEEE13CCEF79DD924F2CB +:1066C0000CB7FCB28AED7A89A9D74D7F3DF1881BC2 +:1066D000F1431BB6B971DDFF1ACA8946B06B53D7B7 +:1066E000F152FA64E2B1ACD0D5D568971BD5E11B65 +:1066F000AEA0F8AF440F95F078CF45F3D5B27C8BC0 +:10670000EE6768DF9BFFF934D3794F7D694523CE6F +:10671000DFB4F9A9094467E39E572F77AB9C2FFAA2 +:1067200032E995DE9FDC24807D83F3E8FCBD5A319D +:1067300096575F24AF92B9CEF5E67D66A5799FA9FD +:10674000CB0FDED058CD7A65FBB8147FEB8F2B6969 +:10675000EF7237457335F0723E55A3F7DF901B1883 +:10676000D79EB74027BF57997846B6B799F23B9F57 +:10677000DB5F4A7EB0E1D083A564F76FBB44BDE91F +:10678000D0AA1729EE850E64097C6D054DC7792DB9 +:1067900011818F617D3EE71BE5FAB755E730BD0DEE +:1067A000FB0269E727255CA8FD6DABF84E649AE50E +:1067B000031FE1AE33D6581BD9C919C4A711D6A7F8 +:1067C000B08F33FD96A5FC5DCA5605088F9CE97F06 +:1067D000CA55E94CE23757F5508CE2DBE663797E27 +:1067E0008B306DB6F35BDD32BE399752DC401CE670 +:1067F000263FE8F8DEF34B41D401944BCBF316135C +:106800007F8DD78F1DD108276F3A2CF0C7A6A12303 +:1068100027271790DD9AF8C3C4359B4D5C73EB3185 +:106820002197CDC7CE6A2DA9F78699F9F74C410477 +:10683000F88DEAA6C63D38344C7ABB12EFEDFE6502 +:10684000ABBBAD549AF9686B8271E1AE99AFF0FDC4 +:106850007773AF496FE62BF794F37EEB27A6E2A799 +:10686000DDD5368EB7723ECA83E775DA27CCA3F83A +:10687000F991439491C520BEF31971F0BB7AB1230D +:106880003448F67A872578641DE7D1DAE7937DFEF0 +:106890001DDF211D227B1E36CFB5D8E6EC3EC21B84 +:1068A000C6AD4E2B953D9B9D8C3F8C2DAF38285F00 +:1068B00030FC7EB6AA4C2013499C50719D5D45A1C9 +:1068C000219A5F04E89D163ABF620AE1FE0B3FFC85 +:1068D0004380F8BE303531026E7AB7685C4DEF16F2 +:1068E000C7AB4DB978E301E26FD2B3E27CF8960D05 +:1068F000FA1CFC5D4910E87B9698F9DE18F958E51A +:10690000EF4F8695D8BF71DE27CBD947DFBDBC6F6F +:10691000DAF9EF2B823FA67D9FCAB754F9695DF380 +:106920001D72AA79AFD226173BC9DE15C3804EA4CB +:10693000AF2ACFB790DD7C2D6107BAC7F798F29CDC +:106940003A79199F938AA780CE2C78D6AB46B2703D +:10695000FDAF819DDF4335D56170FFF04F3FA6EF5E +:106960008CA6583E38918BFD53EE50F41E64B579D9 +:10697000F42DFECE66E4E3C30E4AB6FDAC28F41A4D +:10698000C965B2253EF7EB0A9D4B4FDB151C5F3006 +:106990004F755BCC3CA71DED7BB1F81786B77D3CEE +:1069A000211FE72F4E649F25F95E48BCF5E433D5DF +:1069B00054DA391FB978D812CB9A47936A8DF13CD3 +:1069C00072391786FDF2241DE87F10C86F6E33CF31 +:1069D0001749EF52F32F147BACACAF849DBF93BB30 +:1069E000E054A374BF5B3C7CE234ED73B1DD19A3CA +:1069F0003C35D86D7F1CCF53D3BAA7A6E6BD3587EB +:106A00008F36F804414B618FD0E31772D3EF975064 +:106A100023EE595023709794376F3EED1C14FE2ED1 +:106A2000F91E756A222FBC5EE4F7478711D75C24F4 +:106A3000CECAF255C2358857AEAC32A0A626690739 +:106A400052EF725DA95FA947B8F3D4F3B965ACBF43 +:106A5000B95F07BAE7C4BFF50B85F5975383FC3ED2 +:106A600034B6DF477AED712D2D0B79FFFFE92D3319 +:106A7000AE84B2B19CFFE9F88271257B06961FA90E +:106A8000FDECDF186FE6937CD678DB1591478C28F8 +:106A90007F67BCA9A679E3DF3DBA54F14E68E65F93 +:106AA0007BE8BB4785BE7B04C6BB896D2EB3DFD3B5 +:106AB0006DA5FEED1E7D17F0778F62FEB69CF4EF9C +:106AC0001EB755305E2486985E44D093DF15F6D00D +:106AD0003A382F12C9E1713DF4FD636EF2BB42F208 +:106AE00065A6B309041DC957BBF8DEB2B047CC4F49 +:106AF000DCAEF1F79AA15CF15D62E882888B37D653 +:106B0000E4097BB7C66B082F7FED6E17901D4A7D99 +:106B1000F3538027A96F8BA9EFC95EA1EFC94E354A +:106B200096457A5BBFC448D5DB6E8A99F8F703C4F3 +:106B3000F576E2AF5E7C9737506F94D03BE5407DB1 +:106B4000A14AF8E8E9BF7EE58DBB88BF976D8C53FD +:106B5000077C82DF811F56307E1A51CDFD1DCAE2AF +:106B6000F99336AE2B21FD598A030B5BF19CDC9B1C +:106B70001D9D45FA1D70A93C6EA04A65FF1B281398 +:106B8000F306367899CEB8FEEE77A57DB77A617DAB +:106B9000BED49FB827581313480EA82FAEA39E1A31 +:106BA0008E72FE203121F5DDE48289232E98FA18B9 +:106BB0006F07F19DAAA4F359EDEF1486EE66FF3737 +:106BC000FB07F28C12C24599F2DED3EDEB9B4E76B9 +:106BD000E052DD84F32FA5A79C55DA230753F44335 +:106BE000C71CED3BA7E72AB607A9AFBDF2BCDA6622 +:106BF00011DFDD66E80F2E13F620EFFDD32267BF0D +:106C0000C98F32109F457E83FE3693EE892314B7D9 +:106C1000E627ED5531C4F763D23E65FCCAF45BA5A7 +:106C200013E3D9848BF9ED109FCB1FA931E9B78706 +:106C3000483EF023DD43F59E2DA74AF8BBBACFF6B8 +:106C4000DBFF20BFFDA7E2D0B7697E811927265B55 +:106C5000D05E2C6C57EBCDF74585E4FC8629BF351B +:106C6000188726A27FBC5063E6D7B667C42353DEDD +:106C7000CDE6F837DE433F9A9FD4D71AF35ED4BCF3 +:106C80003DEB2CC5B5E6ED36E11F9DB546061D8EE4 +:106C9000CB920E783E9844FB91F3D66CF8D324C285 +:106CA000C1979C1FBF2C8FDE59392EE27E5FD682A2 +:106CB0002FD27E47E01C7FBFF5D25F2CFC1E7116E1 +:106CC000E5ED213B395024EE6D7982C62BE6F9368D +:106CD000D71EFC25CD7BC9F7872ABA07C19F4F5C19 +:106CE000467C9414055FA3F69D95A3FCAE325292A8 +:106CF000B011DD91C677A6125F6B3A7FCA717B8DAA +:106D00008CDB9F21A74CF948B925F73B3A8970EEF7 +:106D1000FF95BCFE079BFC511E702F000000000079 +:106D20000000000000000000000000400000000023 +:106D30000000000000000040000000000000000013 +:106D4000000000280000000000000000000000100B +:106D500000000000000000000000004000000000F3 +:106D60000000000000000010000000000000000013 +:106D7000000000080000000000000000000000000B +:106D80000000000000000000000000000000000003 +:106D900000000000000000000000000000000000F3 +:106DA00000000000000000000000000000000000E3 +:106DB00000000000000000000000000000000000D3 +:106DC00000000000000000000000000000000000C3 +:106DD00000000000000000000000000000000000B3 +:106DE00000000000000000000000000000000000A3 +:106DF0000000000000000000000000000000000093 +:106E00000000000000000000000000000000000082 +:106E10000000000000000000000000000000000072 +:106E20000000000000000000000000000000000062 +:106E30000000000000000000000000000000000052 +:106E40000000000000000000000000000000000042 +:106E50000000000000000000000000000000000032 +:106E60000000000000000000000000000000000022 +:106E70000000000000000000000000000000000012 +:106E80000000000000000000000000000000000002 +:106E9000000033200010000000000008000033282C +:106EA000001000000000000200003320001000006D +:106EB0000000001080000000000000000000000042 +:106EC00080000000000000000000000080000000C2 +:106ED0000000000000000000800000000000000032 +:106EE0000000000000003358000100040000000111 +:106EF0000000336000000000000000020000336862 +:106F000000000000000000080000336C00000000DA +:106F1000000000020000392000000000000000080E +:106F200000003AF80040000000000040000039383E +:106F3000008000000000004800003A3800400000D7 +:106F40000000000800003A4800400000000000185F +:106F500000003370002800000000002800003C20E2 +:106F6000000800000000000100003C2100080000B3 +:106F70000000000100003C220008000000000001A9 +:106F80000000200800100000000000100000200099 +:106F90000000000000000008800000000000000069 +:106FA00000000000000000000000000000000000E1 +:106FB00000000000000000000000000000000000D1 +:106FC00000000000000000000000000000000000C1 +:106FD00000000000000000000000000000000000B1 +:106FE00000000000000000000000000000000000A1 +:106FF0000000000000000000000000000000000091 +:107000000000000000000000000000000000000080 +:107010000000000000000000000000000000000070 +:107020000000000000000000000000000000000060 +:107030000000000000000000000000000000000050 +:107040000000000000000000000000000000000040 +:1070500000000000000000008000000000000000B0 +:1070600000000000800000000000000000000000A0 +:107070008000000000000000000000008000000010 +:107080000000000000000000800000000000000080 +:107090000000000080000000000000000000000070 +:1070A00080000000000000000000000080000000E0 +:1070B0000000000000000000800000000000000050 +:1070C0000000000080000000000000000000000040 +:1070D00080000000000000000000000080000000B0 +:1070E00000000000000000000000000000000000A0 +:1070F0000000000000000000000000000000000090 +:10710000000000000000000000000000000000007F +:10711000000000000000000000000000000000006F +:1071200000000000800000000000000000000000DF +:10713000800000000000000000000000800000004F +:10714000000000000000000000000000000000003F +:1071500000000000800000000000000000000000AF +:10716000800000000000000000000000800000001F +:10717000000000000000000000000000000000000F +:1071800000000000000000000000000000000000FF +:1071900000000000000000000000000000000000EF +:1071A00000000000000000000000000000000000DF +:1071B00000000000000000000000000000000000CF +:1071C000800000000000000000000000000000003F +:1071D0000000000000000000000019C800000000CE +:1071E000000000080000200800100000000000104F +:1071F00000002000000000000000000800004870AF +:1072000000080000000000010000487100080000B4 +:1072100000000001000048720008000000000001AA +:1072200000004040003800000000003880000000EE +:1072300000000000000000008000000000000000CE +:1072400000000000800000000000000000000000BE +:10725000800000000000000000000000800000002E +:10726000000000000000000080000000000000009E +:10727000000000008000000000000000000000008E +:1072800080000000000000000000000080000000FE +:10729000000000000000000080000000000000006E +:1072A000000000008000000000000000000000005E +:1072B00000000000000000000000000000000000CE +:1072C00000000000000000000000000000000000BE +:1072D00000000000000000000000000000000000AE +:1072E000000000000000000000000000800000001E +:1072F000000000000000000080000000000000000E +:10730000000000000000000000000000000000007D +:10731000800000000000000000000000800000006D +:1073200000000000000000008000000000000000DD +:1073300000000000800000000000000000000000CD +:10734000800000000000000000000000800000003D +:1073500000000000000000000000400000400000AD +:107360000000004000004800004000000000004015 +:107370000000482E0040000000000001000048000E +:10738000004000020000000100004801004000022F +:10739000000000000000300000400000000000403D +:1073A000800000000000000000000000000030002D +:1073B0000008004000000004000030040008004005 +:1073C0000000000400003B800028000000000028AE +:1073D00000003BD0001000000000001000003BDA6D +:1073E00000100000000000010000380000800000D4 +:1073F000000000800000380000080080000000024B +:10740000000039000040000000000040000020089B +:10741000001000000000001000002000000000002C +:107420000000000800005198000800000000000162 +:107430000000519900080000000000010000519A6E +:107440000008000000000001000039800010000466 +:1074500000000004000051A80030001800000010D7 +:10746000000051B000300018000000028000000051 +:10747000000000000000000080000000000000008C +:10748000000000008000000000000000000000007C +:1074900080000000000000000000000080000000EC +:1074A000000000000000000080000000000000005C +:1074B000000000008000000000000000000000004C +:1074C00000000000000000000000000000000000BC +:1074D00000000000000000000000000000000000AC +:1074E000000000000000000000000000000000009C +:1074F000800000000000000000000000800000008C +:10750000000000000000000000000000000000007B +:1075100000000000800000000000000000000000EB +:10752000800000000000000000000000800000005B +:1075300000000000000000008000000000000000CB +:1075400000000000800000000000000000000000BB +:10755000000023E80080000000000080000000011F +:1075600000000000000000000000200800100000E3 +:1075700000000010000020000000000000000008D3 +:1075800000002E70000800000000000100002E71B5 +:10759000000800000000000100002E72000800003A +:1075A00000000001000024E800380000000000385E +:1075B00000002DD00008000000000008800000003E +:1075C000000000000000000080000000000000003B +:1075D000000000008000000000000000000000002B +:1075E000800000000000000000000000800000009B +:1075F000000000000000000080000000000000000B +:10760000000000000000000000000000000000007A +:10761000000000000000000000000000000000006A +:10762000000000000000000000000000000000005A +:1076300000000000800000000000000000000000CA +:1076400080000000000000000000000000000000BA +:1076500000000000000000008000000000000000AA +:10766000000000008000000000000000000000009A +:10767000800000000000000000000000800000000A +:10768000000000000000000080000000000000007A +:10769000000000000000250000400000000000087D +:1076A00000002508004000000000002080000000CD +:1076B000000000000000000080000000000000004A +:1076C000000000008000000000000000000000003A +:1076D000000030000000000000001000000050A179 +:1076E0000000000000000001000050B80000000091 +:1076F00000000002000050C80090000800000008D0 +:107700008000000000000000000000000000296070 +:1077100000080000000000010000296100080000CE +:1077200000000001000029700008000400000002B1 +:107730000000297800080004000000048000000018 +:10774000000000000000000000002FB00008000052 +:107750000000000400002FB4000800000000000436 +:1077600000002FC0000000000000000800002FC82B +:1077700000000000000000080000300000000000D1 +:107780000000001000005040000100010000000156 +:107790000000500000000000000000200000080869 +:1077A00000100000000000040000080C00100000A1 +:1077B00000000001000008B7000000000000000108 +:1077C000000008B6000000000000000100001000EA +:1077D00000400020000000040000100400400020D1 +:1077E000000000040000100800400020000000021B +:1077F0000000100A00400020000000020000100CF1 +:1078000000400020000000010000100D004000209A +:10781000000000010000100E0040002000000001E8 +:1078200000001010004000200000000400001014B0 +:10783000004000200000000400001018004000205C +:10784000000000040000101C0040002000000004A4 +:107850000000300001000080000800040000300437 +:1078600001000080000800040000000A0000000081 +:1078700000000000000030680100008000000001EE +:107880000000306901000080000000010000306C41 +:1078900001000080000000020000306E0100008046 +:1078A00000000002000030700100008000000004B1 +:1078B0000000307401000080000000040000306609 +:1078C0000100008000000002000030640100008020 +:1078D0000000000100003060010000800000000294 +:1078E0000000306201000080000000020000305003 +:1078F00001000080000000040000305401000080FE +:107900000000000400003058010000800000000466 +:107910000000305C01000080000000040000307CAA +:1079200001000080000000010000307D01000080A7 +:107930000000000100001C180010000000000004FE +:1079400000001C30001000000000000400001C3883 +:107950000010000000000004800000000000000093 +:107960000000000080000000000000000000000097 +:107970008000000000000000000000008000000007 +:10798000000000000000000000004C100008000093 +:107990000000000200004C1200080000000000027D +:1079A00000004C14000800000000000200004C160B +:1079B000000800000000000200004C200008000049 +:1079C0000000000800004C00000800000000000259 +:1079D00000004C02000800000000000100004C0400 +:1079E000000800000000000200004C300008000009 +:1079F0000000000800004C400008000000000004E7 +:107A000000004C44000800000000000100004C5041 +:107A1000000800000000000200004C5400080000B4 +:107A20000000000200004C520008000000000002AC +:107A300000004C600008000000000004000014007A +:107A4000000800000000000200001402000800000E +:107A50000000000100001404000800000000000203 +:107A600000001410000800000000000200001414C0 +:107A700000080000000000020000141600080000CA +:107A800000000002000019B8000800000000000813 +:107A90000000142000080000000000020000142470 +:107AA0000008000000000002000019C800080000E3 +:107AB0000000000800002C10000800000000000179 +:107AC00000002C11000800000000000100002C1232 +:107AD000000800000000000100002C130008000056 +:107AE0000000000100002C0000080000000000025F +:107AF00000002C02000800000000000100002C041F +:107B0000000800000000000200002C300008000007 +:107B10000000000200002C320008000000000002FB +:107B200000002C34000800000000000200002C209F +:107B3000000800000000000100002C2100080000E7 +:107B40000000000100002C220008000000000001DD +:107B500000002C23000800000000000100002C247D +:107B6000000800000000000100002C2500080000B3 +:107B70000000000100002C260008000000000001A9 +:107B800000001480000800000000000200001482C1 +:107B9000000800000000000100001484000800003C +:107BA000000000020000149200C000180000000253 +:107BB0000000149000C00018000000020000149C97 +:107BC00000C00018000000080000149400C0001855 +:107BD00000000008000014A700C000180000000109 +:107BE000000014A400C0001800000002000014A649 +:107BF00000C000180000000100001610000800007E +:107C00000000000800001620000800000000000826 +:107C1000000016300008000000000008800000008E +:107C200000000000000000008000000000000000D4 +:107C300000000000800000000000000000000000C4 +:107C40008000000000000000000000008000000034 +:107C500000000000000000008000000000000000A4 +:107C60000000000080000000000000000000000094 +:107C70008000000000000000000000008000000004 +:107C80000000000000000000800000000000000074 +:107C90000000000080000000000000000000000064 +:107CA00080000000000000000000000080000000D4 +:107CB0000000000000000000800000000000000044 +:107CC0000000000080000000000000000000000034 +:107CD00080000000000000000000000080000000A4 +:107CE0000000000000000000800000000000000014 +:107CF0000000000080000000000000000000000004 +:107D00008000000000000000000000008000000073 +:107D100000000000000000008000000000000000E3 +:107D200000000000800000000000000000000000D3 +:107D30008000000000000000000000008000000043 +:107D400000000000000000008000000000000000B3 +:107D500000000000800000000000000000000000A3 +:107D60008000000000000000000000008000000013 +:107D70000000000000000000800000000000000083 +:107D80000000000080000000000000000000000073 +:107D900080000000000000000000000080000000E3 +:107DA0000000000000000000800000000000000053 +:107DB0000000000080000000000000000000000043 +:107DC00080000000000000000000000080000000B3 +:107DD0000000000000000000800000000000000023 +:107DE0000000000080000000000000000000000013 +:107DF0008000000000000000000000008000000083 +:107E000000000000000000008000000000000000F2 +:107E100000000000800000000000000000000000E2 +:107E20008000000000000000000000008000000052 +:107E300000000000000000008000000000000000C2 +:107E400000000000800000000000000000000000B2 +:107E50008000000000000000000000008000000022 +:107E60000000000000000000800000000000000092 +:107E70000000000080000000000000000000000082 +:107E800080000000000000000000000080000000F2 +:107E90000000000000000000800000000000000062 +:107EA0000000000080000000000000000000000052 +:107EB00080000000000000000000000080000000C2 +:107EC0000000000000000000800000000000000032 +:107ED00000000000000000000000000000000000A2 +:107EE0008000000000000000000000000000000012 +:087EF00007081100000000006A +:00000001FF --- linux-3.13.0.orig/firmware/bnx2x/bnx2x-e2-7.8.17.0.fw.ihex +++ linux-3.13.0/firmware/bnx2x/bnx2x-e2-7.8.17.0.fw.ihex @@ -0,0 +1,19382 @@ +:100000000000379000000068000005D800003800AC +:100010000000553C00003DE00000009000009320EF +:100020000000F300000093B8000000C4000186C087 +:100030000001322400018788000000740002B9B07A +:1000400000005CC00002BA28000000AC000316F0FB +:100050000001919C000317A0000011C40004A940F6 +:10006000000000040004BB08021100B800000001F9 +:10007000020600DC000000010306100001FF000082 +:100080000A00000100000008020617FC003FE00122 +:100090000A00000100000010030617FC020101FF26 +:1000A0000A0000010000000803060200000304002B +:1000B0000A00000100000010030602000003040310 +:1000C0000A000001000020000406024C00000002AB +:1000D0000A00000400002020030601E000040406DA +:1000E000030602440002040A030602540002040C40 +:1000F000030602640002040E0A0000030000204010 +:10010000030601E000040410030602400003041487 +:100110000206026400000028020600DC0000000065 +:100120000A00000100000008030601D800020417BD +:100130000A00000200002020030601C0000204198A +:10014000030601D00004041B0A0000020000204046 +:10015000030601C00002041F030601D000040421AD +:100160000A000002000020400306022000020425CD +:100170000306023000040427020D00440000003290 +:10018000030D004C0004042B040D005C000000046F +:10019000030D008C0004042F030D00A000050433A0 +:1001A000020D00B800000002030D00C00004043876 +:1001B000020D015C00000001030D01640002043C1B +:1001C000020D020400000001030D020C0003043EB6 +:1001D000030D022000020441040D02800000001201 +:1001E000030D030000180443040D400000000A0042 +:1001F0000A00000100000008040D03600000000C6C +:10020000030D0004000F045B020D01140000000D3B +:10021000020D01180000002D020D01140000001D48 +:10022000020D01180000003D020D01140000004DF8 +:10023000020D01180000006D020D01140000005DA8 +:10024000020D01180000007D031010000003046A75 +:100250000210105000000001071011000010046D82 +:100260000810114000000008071011600010047D04 +:10027000081011A000000018071018000200048DDB +:1002800004104C0000000100021070040000000186 +:100290000A00000100000008031040D40002068D8F +:1002A00002104028000000100210404400003FFFF0 +:1002B0000210405800280000021040840084924A36 +:1002C00002104058000000000210413800000001F8 +:1002D0000210413800000001021041380000000106 +:1002E00002104138000000010210413800000001F6 +:1002F00002104138000000010210413800000001E6 +:100300000210413800000001030C20080003068F92 +:10031000030C201C00040692030C203800040696EF +:10032000040C20480000001D020C20BC000000014D +:10033000040C20C00000003F030C21BC0003069AFF +:10034000040C21C80000001C030C22380004069D88 +:10035000010C224800000000010C224C00000000AB +:10036000010C225000000000010C2254000000008B +:10037000010C225800000000010C225C000000006B +:10038000010C226000000000010C2264000000004B +:10039000010C226800000000010C226C000000002B +:1003A000010C227000000000010C2274000000000B +:1003B000010C227800000000010C227C00000000EB +:1003C000030C22D8000406A10A0000010000000965 +:1003D000020C2000000003E80A0000010000000AEF +:1003E000020C2000000000030A0000010000000CC5 +:1003F000020C2000000000010A00000100001001B2 +:10040000020C2000000005DC0A00000100001002C0 +:10041000020C2000000000040A000001000010048B +:10042000020C2000000000010A0000010000200171 +:10043000020C2000000005DC0A0000010000200280 +:10044000020C2000000000040A000001000020044B +:10045000020C2000000000010520040000710000D3 +:1004600006200780001006A50422000000004000BE +:10047000042324000000160003221170000806A7C0 +:10048000032211A8009006AF0422C000000000065D +:100490000322C0180004073F0422C0280000000CFB +:1004A0000322C058000407430422C0680000000C67 +:1004B0000322C098000407470422C0A80000000CD3 +:1004C0000322C0D80004074B0422C0E80000000C3F +:1004D0000322C1180004074F0422C1280000000CA9 +:1004E0000322C158000407530422C1680000000C15 +:1004F0000322C198000407570422C1A80000000C81 +:100500000322C1D80004075B0422C1E80000000CEC +:100510000322C2180004075F0422C2280000000C56 +:100520000322C258000407630422C2680000000CC2 +:100530000322C298000407670422C2A80000000C2E +:100540000322C2D80004076B0422C2E80000000C9A +:100550000322C3180004076F0422C3280000000C04 +:100560000322C358000407730422C3680000000C70 +:100570000322C398000407770422C3A80000000CDC +:100580000322C3D80004077B0422C3E80000000C48 +:100590000322C4180004077F0422C4280000000CB2 +:1005A0000322C458000407830422C4680000000C1E +:1005B0000322C498000407870422C4A80000000C8A +:1005C0000322C4D80004078B0422C4E80000000CF6 +:1005D0000322C5180004078F0422C5280000000C60 +:1005E0000322C558000407930422C5680000000CCC +:1005F0000322C598000407970422C5A80000000C38 +:100600000322C5D80004079B0422C5E80000000CA3 +:100610000322C6180004079F0422C6280000000C0D +:100620000322C658000407A30422C6680000000C79 +:100630000322C698000407A70422C6A80000000CE5 +:100640000322C6D8000407AB0422C6E80000000C51 +:100650000322C718000407AF0422C7280000000CBB +:100660000322C758000407B30422C7680000000C27 +:100670000322C798000407B70422C7A80000000C93 +:100680000322C7D8000407BB0422C7E80000000CFF +:100690000322C818000407BF0422C8280000000C69 +:1006A0000322C858000407C30422C8680000000CD5 +:1006B0000322C898000407C70422C8A80000000C41 +:1006C0000322C8D8000407CB0422C8E80000000CAD +:1006D0000322C918000407CF0422C9280000000C17 +:1006E0000322C958000407D30422C9680000000C83 +:1006F0000322C998000407D70422C9A80000000CEF +:100700000322C9D8000407DB0422C9E80000000C5A +:100710000322CA18000407DF0422CA280000000CC4 +:100720000322CA58000407E30422CA680000000C30 +:100730000322CA98000407E70422CAA80000000C9C +:100740000322CAD8000407EB0422CAE80000000C08 +:100750000322CB18000407EF0422CB280000000C72 +:100760000322CB58000407F30422CB680000000CDE +:100770000322CB98000407F70422CBA80000000C4A +:100780000322CBD8000407FB0422CBE80000000CB6 +:100790000322CC18000407FF0422CC280000000C20 +:1007A0000322CC58000408030422CC680000000C8B +:1007B0000322CC98000408070422CCA80000000CF7 +:1007C0000322CCD80004080B0422CCE80000000C63 +:1007D0000322CD180004080F0422CD280000000CCD +:1007E0000322CD58000408130422CD680000000C39 +:1007F0000322CD98000408170422CDA80000000CA5 +:100800000322CDD80004081B0422CDE80000000C10 +:100810000322CE180004081F0422CE280000000C7A +:100820000322CE58000408230422CE680000000CE6 +:100830000322CE98000408270422CEA80000000C52 +:100840000322CED80004082B0422CEE80000000CBE +:100850000322CF180004082F0422CF280000000C28 +:100860000322CF58000408330422CF680000000C94 +:100870000322CF98000408370422CFA80000000C00 +:100880000322CFD80004083B0422CFE80000000C6C +:100890000322D0180004083F0422D0280000000CD6 +:1008A0000322D058000408430422D0680000000C42 +:1008B0000322D098000408470422D0A80000000CAE +:1008C0000322D0D80004084B0422D0E80000000C1A +:1008D0000322D1180004084F0422D1280000000C84 +:1008E0000322D158000408530422D1680000000CF0 +:1008F0000322D198000408570422D1A80000000C5C +:100900000322D1D80004085B0422D1E80000000CC7 +:100910000322D2180004085F0422D2280000000C31 +:100920000322D258000408630422D2680000000C9D +:100930000322D298000408670422D2A80000000C09 +:100940000322D2D80004086B0422D2E80000000C75 +:100950000322D3180004086F0422D3280000000CDF +:100960000322D358000408730422D3680000000C4B +:100970000322D398000408770422D3A80000000CB7 +:100980000322D3D80004087B0422D3E80000000C23 +:100990000322D4180004087F0422D4280000000C8D +:1009A0000322D458000408830422D4680000000CF9 +:1009B0000322D498000408870422D4A80000000C65 +:1009C0000322D4D80004088B0422D4E80000000CD1 +:1009D0000322D5180004088F0422D5280000000C3B +:1009E0000322D558000408930422D5680000000CA7 +:1009F0000322D598000408970422D5A80000000C13 +:100A00000322D5D80004089B0422D5E80000000C7E +:100A10000322D6180004089F0422D6280000000CE8 +:100A20000322D658000408A30422D6680000000C54 +:100A30000322D698000408A70422D6A80000000CC0 +:100A40000322D6D8000408AB0422D6E80000000C2C +:100A50000322D718000408AF0422D7280000000C96 +:100A60000322D758000408B30422D7680000000C02 +:100A70000322D798000408B70422D7A80000000C6E +:100A80000322D7D8000408BB0422D7E80000000CDA +:100A90000322D818000408BF0422D8280000000C44 +:100AA0000322D858000408C30422D8680000000CB0 +:100AB0000322D898000408C70422D8A80000000C1C +:100AC0000322D8D8000408CB0422D8E80000000C88 +:100AD0000322D918000408CF0422D9280000000CF2 +:100AE0000322D958000408D30422D9680000000C5E +:100AF0000322D998000408D70422D9A80000000CCA +:100B00000322D9D8000408DB0422D9E80000000C35 +:100B10000322DA18000408DF0422DA280000000C9F +:100B20000322DA58000408E30422DA680000000C0B +:100B30000322DA98000408E70422DAA80000000C77 +:100B40000322DAD8000408EB0422DAE80000000CE3 +:100B50000322DB18000408EF0422DB280000000C4D +:100B60000322DB58000408F30422DB680000000CB9 +:100B70000322DB98000408F70422DBA80000000C25 +:100B80000322DBD8000408FB0422DBE80000000C91 +:100B90000322DC18000408FF0422DC280000000CFB +:100BA0000322DC58000409030422DC680000000C66 +:100BB0000322DC98000409070422DCA80000000CD2 +:100BC0000322DCD80004090B0422DCE80000000C3E +:100BD0000322DD180004090F0422DD280000000CA8 +:100BE0000322DD58000409130422DD680000000C14 +:100BF0000322DD98000409170422DDA80000000C80 +:100C00000322DDD80004091B0422DDE80000000CEB +:100C10000322DE180004091F0422DE280000000C55 +:100C20000322DE58000409230422DE680000000CC1 +:100C30000322DE98000409270422DEA80000000C2D +:100C40000322DED80004092B0422DEE80000000C99 +:100C50000322DF180004092F0422DF280000000C03 +:100C60000322DF58000409330422DF680000000C6F +:100C70000322DF98000409370422DFA80000000CDB +:100C80000322DFD80004093B0422DFE80000000C47 +:100C90000322E0180004093F0422E0280000000CB1 +:100CA0000322E058000409430422E0680000000C1D +:100CB0000322E098000409470422E0A80000000C89 +:100CC0000322E0D80004094B0422E0E80000000CF5 +:100CD0000322E1180004094F0422E1280000000C5F +:100CE0000322E158000409530422E1680000000CCB +:100CF0000322E198000409570422E1A80000000C37 +:100D00000322E1D80004095B0422E1E800000006A8 +:100D10000422F640000000200223800000000010A2 +:100D20000223804000000012022380800000003077 +:100D3000022380C00000000E02238BC000000001CF +:100D40000A0000020000000802238380000864708B +:100D5000022383C0000002260A00000200000009EE +:100D600002238300000864700223834000000226EF +:100D70000A0000020000000A022383000000055F51 +:100D800002238340000000010A0000020000000C62 +:100D9000022383000000015702238340000000006B +:100DA0000A0000020000100002238380000C96A8B5 +:100DB000022383C0000003390A0000020000100172 +:100DC00002238300000C96A802238340000003390D +:100DD0000A00000200001002022383000000080E37 +:100DE00002238340000000020A00000200001004F9 +:100DF000022383000000020302238340000000005E +:100E00000A0000020000200002238380000CF8503A +:100E1000022383C0000003520A00000200002001E8 +:100E200002238300000CF850022383400000035289 +:100E30000A00000200002002022383000000084D87 +:100E400002238340000000020A0000020000200488 +:100E500002238300000002130223834000000000ED +:100E60000524000031F60000052480002AC80C7E0D +:100E70000624DAD0630C095F0A00000100000002BA +:100E800002231480000000000A000001000000049A +:100E900002231480000000000A000001000000117D +:100EA00002231480000000000A0000010000000876 +:100EB000022000BC000000320A0000040000001004 +:100EC000022000BC00000002022388400000000154 +:100ED00001200138000000000223884000000000CB +:100EE0000A0000010000001102231480000000012C +:100EF00001200000000000000120000400000000AC +:100F000001200008000000000120000C000000008B +:100F1000012000100000000001200014000000006B +:100F200003200020001A0961032000A40002097BAD +:100F30000220022400000000022002340000000011 +:100F40000220024C00000000022002E40000FFFF2B +:100F500008202000000008000A0000010000001026 +:100F600008204000000002000422110800000002D6 +:100F70000422340000000002042259000000000690 +:100F800004226040000000300422F3000000001042 +:100F900004221110000000020422340800000002A4 +:100FA00004225918000000060422610000000030ED +:100FB0000422F34000000010042211180000000277 +:100FC0000422341000000002042259300000000600 +:100FD000042261C0000000300422F38000000010F1 +:100FE0000422112000000002042234180000000234 +:100FF00004225948000000060422628000000030EC +:101000000422F3C000000010042211280000000296 +:10101000042234200000000204225960000000066F +:1010200004226340000000300422F400000000109D +:1010300004221130000000020422342800000002C3 +:1010400004225978000000060422640000000030E9 +:101050000422F440000000100422113800000002B5 +:1010600004223430000000020422599000000006DF +:10107000042264C0000000300422F480000000104C +:101080000422114000000002042234380000000253 +:10109000042259A8000000060422658000000030E8 +:1010A0000422F4C00000001004102400000000E03E +:1010B0000310201C0002097D021020C00000000265 +:1010C000031020040002097F02170008000000023C +:1010D0000217002C0000000302170038007C1004E7 +:1010E0000317004400060981021700700000000C7D +:1010F0000317007800020987021701C408100000D6 +:1011000002170344000000010317040000080989C6 +:10111000031704300008099103170480000409999B +:101120000A000001000000080217003C0000000453 +:101130000A000001000000100217003C0000000837 +:10114000021700040000000F021701EC000000026B +:10115000021701F400000002021701EC0000000277 +:10116000021701F400000002021701EC0000000267 +:10117000021701F400000002021701EC0000000257 +:10118000021701F400000002021701EC0000000247 +:10119000021701F400000002021701EC0000000237 +:1011A000021701F400000002021701EC0000000227 +:1011B000021701F400000002021701EC0000000217 +:1011C000021701F4000000020A00000100000008FC +:1011D00002130078000000320213003C000061A8F6 +:1011E00004130108000000030213010400000000C2 +:1011F0000213013400000000041301080000000382 +:10120000021301040000000002130134000000007A +:101210000413010800000003021301040000000091 +:101220000213013400000000041301080000000351 +:10123000021301040000000002130134000000004A +:101240000413010800000003021301040000000061 +:101250000213013400000000041301080000000321 +:10126000021301040000000002130134000000001A +:101270000413010800000003021301040000000031 +:1012800002130134000000000413010800000003F1 +:1012900002130104000000000213013400000000EA +:1012A0000A000001000000880200A5F8000000000C +:1012B0000A000001000001080200A5F8000000017A +:1012C0000A000001000000900200AA840000000053 +:1012D0000A000001000001100200AA8400000001C1 +:1012E0000A000001000000900200AA88000000002F +:1012F0000A000001000001100200AA88000000019D +:101300000200A270000000000200A27400000000B1 +:101310000200A270000000000200A27400000000A1 +:101320000200A270000000000200A2740000000091 +:101330000200A270000000000200A2740000000081 +:101340000201620400000000030100B40002099DD4 +:10135000030100CC0002099F020100DC0000000133 +:1013600003010100000209A10201007C003000001D +:1013700002010084000000280201008C000000002F +:1013800002010130000000040201032800000000F7 +:101390000201055400000030020160580000FFFF08 +:1013A00002016060000000000201607000000007A0 +:1013B000020160B000000000020160C000000001F6 +:1013C000020160C800000000020162080000000085 +:1013D0000401805400000003020180780000000036 +:1013E000020180E800000007030180F8000209A361 +:1013F0000301810C000209A5020181240000000004 +:101400000A00000200000008020180E40000468893 +:10141000030180EC000209A70A000001000000801F +:1014200002018038000000060A00000100000200EE +:1014300002018038000000070A00000100000400DB +:1014400002018038000000060A00000100000800C8 +:10145000020180380000000E0A0000040000200095 +:10146000020180EC0000003802018100000025E448 +:101470000201811400004BC803018680000409A901 +:10148000020100C400000001020100F80000000198 +:10149000020100F0000000010201008000300000A5 +:1014A00002010088000000280201009000000000F6 +:1014B00002010134000000040201032C00000000BE +:1014C00002010564000000300201605C0000FFFFC3 +:1014D0000201606400000000020160740000000767 +:1014E000020160B400000000020160C400000001BD +:1014F000020160CC000000000201620C000000004C +:10150000040181A800000004020181D00000000055 +:10151000020182340000000703018244000209AD89 +:1015200003018258000209AF0A000002000000080F +:10153000020182300000468803018238000209B1AE +:101540000A000001000000800201818C00000006FA +:101550000A000001000002000201818C0000000767 +:101560000A000001000004000201818C0000000656 +:101570000A000001000008000201818C0000000E3A +:101580000A00000400002000020182380000003838 +:101590000201824C000025E40201826000004BC879 +:1015A000030186E0000409B3020100C80000000145 +:1015B000020100FC00000001020100F40000000133 +:1015C00004010138000000110401017C0000001139 +:1015D00004010138000000110401017C0000001129 +:1015E00004010138000000110401017C0000001119 +:1015F00004010138000000110401017C0000001109 +:101600000215C090000089260215C09C000000044D +:1016100002140000000000010215C02400000000B8 +:101620000315C0EC000209B70315C100000209B997 +:101630000A000001000020000315C1F4000809BBE6 +:1016400003140030000209C302140040000000012E +:10165000090000020000100803140004000309C57B +:10166000021400440000FFFF0A00000400002000F4 +:1016700003140038000209C802140044000FFFFFE1 +:101680000315C160000709CA0315C198000209D1FA +:101690000900000100001008041400040000000309 +:1016A0000A000001000020000415C16000000007CE +:1016B0000214000000000000020090C40000E000DE +:1016C000020090CC0000F300030090D4000209D384 +:1016D000020090E000007300030090E8000209D5CA +:1016E000020090F400007300030090FC000209D790 +:1016F0000200910800005300020091100000000455 +:1017000003009128000709D90300916C000609E045 +:1017100004009184000000060300919C000509E686 +:101720000300942C000309EB0300942C000309EE42 +:101730000300942C000309F10300942C000309F426 +:101740000300942C000309F70300942C000309FA0A +:101750000300942C000309FD0300942C00030A00ED +:101760000304000400120A030204005400000043B2 +:101770000204005C00000006020400700000000487 +:101780000304007800040A15040400880000000522 +:101790000304009C00030A19040400A800000004CC +:1017A000030400B800110A1C010401240000000019 +:1017B00001040128000000000104012C00000000C9 +:1017C0000104013000000000020401340000000F99 +:1017D000030401D000020A2D0204022C00000004C0 +:1017E0000304025800040A2F0312049400210A3350 +:1017F0000212038800000064021203900000000837 +:101800000312039C00030A54031203BC00030A578B +:10181000021203D0000000000212036C000000015D +:10182000031201BC003C0A5A031202B000020A96DD +:101830000312032400020A98021205B400000001FA +:10184000031205F800030A9A0212066C0000000158 +:10185000021201B000000001021207D800000000CF +:10186000021207D800000000021207D80000000092 +:10187000021207D800000000021207D80000000082 +:10188000021207D800000000021207D80000000072 +:10189000021207D800000000021030D8000000013A +:1018A0000710380000050A9D0710392000050AA21C +:1018B00007103B0000050AA707103C0000050AAC12 +:1018C0000316803000080AB102168054000000029E +:1018D0000416807C000000050316809000020AB9FF +:1018E0000316809C00020ABB021680AC0000005464 +:1018F000041680B800000005031680CC00080ABD5D +:10190000021680F0000000070316810000060AC5D9 +:101910000316812800030ACB0316814000060ACE75 +:101920000316816800030AD4031681A800030AD7AE +:10193000031681E800030ADA031681F800030ADDC2 +:101940000316820800070AE00316823400020AE741 +:1019500004168278000000040316828800060AE953 +:101960000216881020200101021688202020010183 +:101970000216883820200101021688482020010123 +:101980000316E6BC00020AEF0A000014000000087B +:101990000316806000070AF1041680A4000000020C +:1019A000041680B000000002031680F400030AF859 +:1019B0000316811800040AFB0316813400030AFF92 +:1019C0000316815800040B0203168174000D0B06E8 +:1019D000031681B4000D0B13021681F4000001FC04 +:1019E00002168204000000030316823C000B0B2049 +:1019F00004168268000000040216880C010101012F +:101A00000316881400030B2B0316882400050B2EE5 +:101A10000316883C00030B330316E6C400020B36A2 +:101A20000316E6E800050B380216E79400000001F3 +:101A30000A00001C000010000316806000070B3D28 +:101A4000041680A400000002041680B0000000020A +:101A5000031680F400030B440316811800040B479F +:101A60000316813400030B4B0316815800040B4E00 +:101A70000216817800000001021681840000000136 +:101A80000216819000000001021681A400000004EB +:101A9000021681B800000001021681C40000000196 +:101AA000021681D000000001021681E4000000044B +:101AB000021681F4000001FC0216820400000003FB +:101AC0000316823C00020B520216824800920092DA +:101AD00002168250012401240316825800040B547C +:101AE00004168268000000040216880C010101013E +:101AF0000316881400030B580316882400050B5B9B +:101B00000316883C00030B600316E6E800020B6333 +:101B10000216E6F8000002040A00000E0000102081 +:101B200002168174000000000316817C00020B6520 +:101B30000316818800020B670316819400040B6969 +:101B4000021681B400000000031681BC00020B6D78 +:101B5000031681C800020B6F031681D400040B71B9 +:101B6000021682440E490E490216824C00920092DF +:101B700002168254012401240316E6C400020B75E8 +:101B80000316E6F000020B770216E794000000014E +:101B90000A00000E000010400216817400000001CF +:101BA0000316817C00020B790316818800020B7BEF +:101BB0000316819400040B7D021681B4000000011D +:101BC000031681BC00020B81031681C800020B833F +:101BD000031681D400040B85021682440000000025 +:101BE0000216824C0FFF0FFF021682540000000005 +:101BF0000316E6C400020B890316E6F000020B8B05 +:101C00000216E794000000000A0000070000200010 +:101C10000316806000070B8D031680A400020B944E +:101C2000031680B000020B96021681F4000001C07A +:101C3000021682040000003F0216823C0000007F72 +:101C40000316E7BC00080B980A00000F00004020B4 +:101C5000031680F400030BA00316811800040BA3E5 +:101C60000316813400030BA70316815800040BAA46 +:101C700003168174000D0BAE031681B4000D0BBB6F +:101C80000316824000060BC80416825800000006A6 +:101C90000316827000020BCE0216880C01010101AE +:101CA0000316881400030BD00316882400050BD3F9 +:101CB0000316883C00030BD80316E6C400020BDBB6 +:101CC0000216E794000000010A00000D00004040E9 +:101CD000031680F400030BDD0316811800040BE0EB +:101CE0000316813400030BE40316815800040BE74C +:101CF00003168174000D0BEB031681B4000D0BF875 +:101D000003168240000E0C050216880C0101010129 +:101D10000316881400030C130316882400050C1600 +:101D20000316883C00030C1B0316E6C400020C1EBD +:101D30000216E794000000000A00000D0000800079 +:101D4000031680F400030C200316811800040C23F2 +:101D50000316813400030C270316815800040C2A53 +:101D600003168174000D0C2E031681B4000D0C3B7C +:101D700003168240000E0C480216880C0101012057 +:101D80000316881400030C560316882400050C590A +:101D90000316883C00030C5E0316E6C400020C61C7 +:101DA0000216E79400000001021680EC000000FF1C +:101DB0000304040800140C63020404CC00000001B6 +:101DC0000305004400020C770305005000080C795D +:101DD0000305009000070C81030500B000020C8889 +:101DE000030500C000020C8A030500D400020C8C1D +:101DF00002050114000000010305011C00020C8E05 +:101E000002050204000000010305020C00020C9010 +:101E10000205021C00000020040502400000000A28 +:101E20000405400000000D000A0000020000000848 +:101E30000305022000020C920305028000200C948E +:101E40000A000002000000100305022000020CB48A +:101E500003050280001D0CB60305000400100CD31E +:101E6000020500E00000000E020500E40000002E64 +:101E7000020500E00000001E020500E40000003E34 +:101E8000020500E00000004E020500E40000006EC4 +:101E9000020500E00000005E020500E40000007E94 +:101EA00004164024000000020316403000030CE337 +:101EB0000216404400000020021640700000001C82 +:101EC0000216420800000001021642100000000144 +:101ED0000216422000000001021642280000000104 +:101EE00002164230000000010216423800000001D4 +:101EF00002164260000000020A0000010000000912 +:101F00000216401C0003D0900A0000010000000AE5 +:101F10000216401C000002710A0000010000000CC3 +:101F20000216401C0000009C0A0000010000100185 +:101F30000216401C0005B8D80A000001000010027B +:101F40000216401C000003A90A0000010000100452 +:101F50000216401C000000EA0A00000100002001F7 +:101F60000216401C0005B8D80A000001000020023B +:101F70000216401C000003A90A0000010000200412 +:101F80000216401C000000EA02164000000000019A +:101F9000021640D8000000010316400800030CE6BA +:101FA00002164240000000000216424800000000F5 +:101FB00008164270000000020216425000000000A5 +:101FC000021642580000000008164280000000027D +:101FD0000304200800040CE90304201C00040CED99 +:101FE00002042038000000200404203C0000001FF0 +:101FF000020420B800000001040420BC0000005FBF +:102000000304223800040CF10104224800000000FF +:102010000104224C000000000104225000000000D6 +:1020200001042254000000000104225800000000B6 +:102030000104225C00000000010422600000000096 +:102040000104226400000000010422680000000076 +:102050000104226C00000000010422700000000056 +:102060000104227400000000010422780000000036 +:102070000104227C00000000030422C000040CF5CF +:102080000A0000010000000902042000000003E82B +:102090000A0000010000000A020420000000000302 +:1020A0000A0000010000000C0204200000000001F2 +:1020B0000A0000010000100102042000000005DCFD +:1020C0000A000001000010020204200000000004C9 +:1020D0000A000001000010040204200000000001BA +:1020E0000A0000010000200102042000000005DCBD +:1020F0000A00000100002002020420000000000489 +:102100000A00000100002004020420000000000179 +:1021100005180400008D0000061807B800090CF926 +:10212000041A000000004000041B240000001600F8 +:10213000031A16C800020CFB031A17E000900CFDEE +:10214000031A404000040D8D041A405000000006A0 +:10215000031A406800020D91031A52C000020D9349 +:10216000031A800003F90D95041A8FE4000000079C +:10217000031B3D900014118E021B800000000034F0 +:10218000021B804000000018021B80800000000C31 +:10219000021B80C000000020021B8BC00000000159 +:1021A0000A00000300000008021A16D00000000216 +:1021B000021B838000086470021B83C0000002269B +:1021C0000A00000200000009021B8300000864707E +:1021D000021B8340000002260A0000020000000AE1 +:1021E000021B83000000055F021B8340000000010A +:1021F0000A0000020000000C021B830000000157CF +:10220000021B8340000000000A00000100000020C3 +:10221000021A16D4000000000A000001000000406D +:10222000021A16D4000000010A000003000010008A +:10223000021A16D000000003021B8380000C96A82F +:10224000021B83C0000003390A00000200001001D5 +:10225000021B8300000C96A8021B83400000033978 +:102260000A00000200001002021B83000000080E9A +:10227000021B8340000000020A000002000010045C +:10228000021B830000000203021B834000000000C9 +:102290000A00000300002000021A16D0000000040B +:1022A000021B8380000CF850021B83C00000035205 +:1022B0000A00000200002001021B8300000CF850FD +:1022C000021B8340000003520A00000200002002AB +:1022D000021B83000000084D021B83400000000227 +:1022E0000A00000200002004021B83000000021309 +:1022F000021B8340000000000A00000100004000B3 +:10230000021A16D8000000000A0000010000800038 +:10231000021A16D800000001041B944800000002B5 +:10232000051C0000327D0000051C800036190CA041 +:10233000051D0000333B1A27051D800036BE26F61A +:10234000051E0000206534A6061E501035FE11A2A1 +:102350000A00000100000002021B148000000000BF +:102360000A00000100000004021B148000000000AD +:102370000A00000100000011021B14800000000090 +:102380000A00000200000008021800BC0000003231 +:10239000021B945C000000320A00000700000010DD +:1023A000021800BC00000002021B945C0000000246 +:1023B000021B884000000001021B942C0000000258 +:1023C0000118012800000000021B884000000000E6 +:1023D000021B942C00000000021B9440000000012E +:1023E0000A00000100000011021B1480000000011F +:1023F00001180000000000000118000400000000A7 +:1024000001180008000000000118000C0000000086 +:102410000118001000000000011800140000000066 +:1024200003180020001A11A4031800A4000211BE12 +:10243000021802240000000002180234000000000C +:102440000218024C00000000021802E4000000FF25 +:1024500008181000000004000A000001000000102D +:102460000818200000000600031A1A30000411C0EA +:10247000041A300000000012041A3090000000120C +:10248000041AD4C800000002041AD4D800000020A6 +:10249000041AD5D800000002041B44000000000606 +:1024A000031A1A40000411C4041A30480000001234 +:1024B000041A30D800000012041AD4D00000000220 +:1024C000041AD55800000020041AD5E000000002CC +:1024D000041B441800000006031A4000000211C843 +:1024E000041A500000000002041A5080000000127C +:1024F000031A6140000211CA041AA0000000000281 +:10250000041B443000000002031A4008000211CCF2 +:10251000041A501000000002041A50C800000012F3 +:10252000031A6148000211CE041AA008000000023C +:10253000041B443800000002031A4010000211D0AE +:10254000041A502000000002041A5110000000126A +:10255000031A6150000211D2041AA01000000002F8 +:10256000041B444000000002031A4018000211D46A +:10257000041A503000000002041A515800000012E2 +:10258000031A6158000211D6041AA01800000002B4 +:10259000041B444800000002031A4020000211D826 +:1025A000041A504000000002041A51A0000000125A +:1025B000031A6160000211DA041AA0200000000270 +:1025C000041B445000000002031A4028000211DCE2 +:1025D000041A505000000002041A51E800000012D2 +:1025E000031A6168000211DE041AA028000000022C +:1025F000041B445800000002031A4030000211E09E +:10260000041A506000000002041A52300000001248 +:10261000031A6170000211E2041AA03000000002E7 +:10262000041B446000000002031A4038000211E459 +:10263000041A507000000002041A527800000012C0 +:10264000031A6178000211E6041AA03800000002A3 +:10265000041B446800000002020E004C000000321F +:10266000030E0054000811E8030E0094000711F057 +:10267000030E00B4000211F7020E00C400000000B7 +:10268000020E00CC00000006030E00D8000211F973 +:10269000020E014400000001030E014C000211FB78 +:1026A000020E020400000001030E020C000211FDE4 +:1026B000030E021C000411FF030E0280001B120314 +:1026C000040E030000000012040E200000000800A9 +:1026D0000A00000100000008040E02EC00000005E2 +:1026E000030E00040011121E020E01100000000F64 +:1026F000020E01140000002F020E01100000001F46 +:10270000020E01140000003F020E01100000004FF5 +:10271000020E01140000006F020E01100000005FA5 +:10272000020E01140000007F020C100000000028BF +:10273000030C40080004122F030C401C0004123349 +:10274000030C403800061237040C40500000001FF4 +:10275000020C40CC00000001040C40D00000003A04 +:10276000030C41B80006123D040C41D00000001AD1 +:10277000030C423800041243010C424800000000E0 +:10278000010C424C00000000010C4250000000000F +:10279000010C425400000000010C425800000000EF +:1027A000010C425C00000000010C426000000000CF +:1027B000010C426400000000010C426800000000AF +:1027C000010C426C00000000010C4270000000008F +:1027D000010C427400000000010C4278000000006F +:1027E000010C427C00000000010C4280000000004F +:1027F000030C42D8000412470A000001000000093F +:10280000020C4000000003E80A0000010000000A7A +:10281000020C4000000000030A0000010000000C50 +:10282000020C4000000000010A000001000010013D +:10283000020C4000000005DC0A000001000010024C +:10284000020C4000000000040A0000010000100417 +:10285000020C4000000000010A00000100002001FD +:10286000020C4000000005DC0A000001000020020C +:10287000020C4000000000040A00000100002004D7 +:10288000020C4000000000010530040000C30000FD +:10289000063007E80003124B04320000000040003D +:1028A000043324000000160003322C700090124DF7 +:1028B000033234C0000812DD0432408000000010F2 +:1028C000033240C0000212E503337400000412E733 +:1028D000023380000000001A023380400000004EE6 +:1028E0000233808000000010023380C0000000200E +:1028F00002338BC0000000010A0000020000000843 +:102900000233838000086470023383C00000022613 +:102910000A0000020000000902338300000864700E +:1029200002338340000002260A0000020000000A71 +:10293000023383000000055F023383400000000182 +:102940000A0000020000000C02338300000001575F +:1029500002338340000000000A0000020000100063 +:1029600002338380000C96A8023383C00000033931 +:102970000A0000020000100102338300000C96A838 +:1029800002338340000003390A00000200001002F5 +:10299000023383000000080E02338340000000026F +:1029A0000A0000020000100402338300000002034A +:1029B00002338340000000000A00000200002000F3 +:1029C00002338380000CF850023383C000000352AE +:1029D0000A0000020000200102338300000CF850BE +:1029E00002338340000003520A000002000020026C +:1029F000023383000000084D0233834000000002D0 +:102A00000A000002000020040233830000000213C9 +:102A100002338340000000000534000034CD000084 +:102A20000534800035A50D340535000038931A9E15 +:102A30000535800037C028C305360000350036B3A1 +:102A400005368000225643F30636D08025F012EB7F +:102A50000A000001000000020233148000000000A0 +:102A60000A0000010000000402331480000000008E +:102A70000A00000100000011023314800000000071 +:102A80000A00000100000008023000BC0000003213 +:102A90000A00000400000010023000BC0000000228 +:102AA00002338840000000010130013800000000BE +:102AB00002338840000000000A00000100000011FD +:102AC000023314800000000101300000000000000B +:102AD0000130000400000000013000080000000088 +:102AE0000130000C00000000013000100000000068 +:102AF000013000140000000003300020001A12ED25 +:102B0000033000A40002130702300224000000007A +:102B100002300234000000000230024C00000000CD +:102B2000023002E40000FFFF08302000000008002F +:102B30000A00000100000010083040000000020000 +:102B400004322C400000000203322C500004130910 +:102B5000043293C000000002043294000000001010 +:102B60000432C000000000200432C1000000002038 +:102B70000432C200000000200432C3000000002024 +:102B80000432C400000000200432C5000000002010 +:102B90000432C600000000200432C70000000020FC +:102BA0000432C800000000200432C90000000020E8 +:102BB0000432CA00000000200432CB0000000020D4 +:102BC0000432CC00000000200432CD0000000020C0 +:102BD0000432CE00000000200432CF0000000020AC +:102BE0000432DB800000000204322C4800000002A6 +:102BF00003322C600004130D043293C8000000025D +:102C000004329440000000100432C0800000002014 +:102C10000432C180000000200432C2800000002085 +:102C20000432C380000000200432C4800000002071 +:102C30000432C580000000200432C680000000205D +:102C40000432C780000000200432C8800000002049 +:102C50000432C980000000200432CA800000002035 +:102C60000432CB80000000200432CC800000002021 +:102C70000432CD80000000200432CE80000000200D +:102C80000432CF80000000200432DB880000000204 +:102C9000043210100000000204322C000000000278 +:102CA000043210200000000204322C080000000250 +:102CB000043210300000000204322C100000000228 +:102CC000043210400000000204322C180000000200 +:102CD000043210500000000204322C2000000002D8 +:102CE000043210600000000204322C2800000002B0 +:102CF000043210700000000204322C300000000288 +:102D0000043210800000000204322C38000000025F +:102D10000202005800000032030200600008131194 +:102D2000030200A0000B1319020200D000000007EC +:102D3000030200DC00031324030200F00002132747 +:102D4000020200FC0000000C020201200000000052 +:102D50000202013400000002020201B00000000182 +:102D60000202020C000000010302021400021329F7 +:102D700002020404000000010302040C0002132BF1 +:102D80000302041C0004132D0302048000201331ED +:102D90000402050000000012040280000000200070 +:102DA000030200040014135102020108000000C8CD +:102DB0000202011800000002020201C4000000002B +:102DC000020201CC00000000020201D40000000257 +:102DD000020201DC00000002020201E4000000FF28 +:102DE000020201EC000000FF0202010C000000C81A +:102DF0000202011C00000002020201C800000000E3 +:102E0000020201D000000000020201D8000000020E +:102E1000020201E000000002020201E8000000FFDF +:102E2000020201F0000000FF02020108000000C8D9 +:102E30000202011800000002020201C400000000AA +:102E4000020201CC00000000020201D400000002D6 +:102E5000020201DC00000002020201E4000000FFA7 +:102E6000020201EC000000FF0202010C000000C899 +:102E70000202011C00000002020201C80000000062 +:102E8000020201D000000000020201D8000000028E +:102E9000020201E000000002020201E8000000FF5F +:102EA000020201F0000000FF02020108000000C859 +:102EB0000202011800000002020201C4000000002A +:102EC000020201CC00000000020201D40000000256 +:102ED000020201DC00000002020201E4000000FF27 +:102EE000020201EC000000FF0202010C000000C819 +:102EF0000202011C00000002020201C800000000E2 +:102F0000020201D000000000020201D8000000020D +:102F1000020201E000000002020201E8000000FFDE +:102F2000020201F0000000FF02020108000000C8D8 +:102F30000202011800000002020201C400000000A9 +:102F4000020201CC00000000020201D400000002D5 +:102F5000020201DC00000002020201E4000000FFA6 +:102F6000020201EC000000FF0202010C000000C898 +:102F70000202011C00000002020201C80000000061 +:102F8000020201D000000000020201D8000000028D +:102F9000020201E000000002020201E8000000FF5E +:102FA000020201F0000000FF0216100000000028DD +:102FB00003166008000313650316601C0004136801 +:102FC000031660380012136C041660800000000EB7 +:102FD000021660B800000001041660BC0000000882 +:102FE000021660DC00000001041660E0000000042E +:102FF000021660F000000001041660F400000031C9 +:10300000031661B80002137E041661C000000007B9 +:10301000031661DC00061380041661F40000001141 +:10302000031662380004138601166248000000008F +:103030000116624C00000000011662500000000002 +:1030400001166254000000000116625800000000E2 +:103050000116625C000000000116626000000000C2 +:1030600001166264000000000116626800000000A2 +:103070000116626C00000000011662700000000082 +:103080000116627400000000011662780000000062 +:103090000116627C00000000011662D400000000EE +:1030A000031662D80004138A0A0000010000000918 +:1030B00002166000000003E80A0000010000000A98 +:1030C00002166000000000030A0000010000000C6E +:1030D00002166000000000010A000001000010015B +:1030E00002166000000005DC0A000001000010026A +:1030F00002166000000000040A0000010000100435 +:1031000002166000000000010A000001000020011A +:1031100002166000000005DC0A0000010000200229 +:1031200002166000000000040A00000100002004F4 +:1031300002166000000000010528040000AC000039 +:10314000062807C80007138E042A0000000040006C +:10315000042B240000001600032A30000002139004 +:10316000032A400000101392032A8408000813A2C7 +:10317000032A9348000413AA032A9668000813AE92 +:10318000032A98B8000213B6032A9950009013B886 +:10319000032B4D9000141448022B80000000000007 +:1031A000022B804000000018022B80800000000CE1 +:1031B000022B80C000000066022B8BC000000001C3 +:1031C0000A00000300000008022A9CA80000000278 +:1031D000022B838000086470022B83C0000002264B +:1031E0000A00000200000009022B8300000864703E +:1031F000022B8340000002260A0000020000000AA1 +:10320000022B83000000055F022B834000000001B9 +:103210000A0000020000000C022B8300000001578E +:10322000022B8340000000000A0000030000002081 +:10323000022A9CAC00000000032AC4E00004145CD5 +:10324000032AC500000214600A00000200000040CA +:10325000022A9CAC00000001032AC4E0000A1462A8 +:103260000A00000300001000022A9CA800000003CE +:10327000022B8380000C96A8022B83C00000033928 +:103280000A00000200001001022B8300000C96A827 +:10329000022B8340000003390A00000200001002E4 +:1032A000022B83000000080E022B83400000000266 +:1032B0000A00000200001004022B83000000020339 +:1032C000022B8340000000000A00000300002000E1 +:1032D000022A9CA800000004022B8380000CF850F6 +:1032E000022B83C0000003520A00000200002001EC +:1032F000022B8300000CF850022B83400000035285 +:103300000A00000200002002022B83000000084D8A +:10331000022B8340000000020A000002000020048B +:10332000022B830000000213022B834000000000E8 +:103330000A00000100004000022A9CB000000000CA +:103340000A00000100008000022A9CB00000000179 +:10335000042B944800000002052C0000345A0000A1 +:10336000052C80003AB30D17052D000030F11BC469 +:10337000052D80003C6B2801052E00003C1D371CEC +:10338000052E80003B5C4624052F0000336D54FB66 +:10339000052F80000A3F61D7062F97E00D04146CBB +:1033A0000A00000100000002022B1480000000004F +:1033B0000A00000100000004022B1480000000003D +:1033C0000A00000100000011022B14800000000020 +:1033D0000A00000200000008022800BC00000032C1 +:1033E000022B945C000000320A000007000000106D +:1033F000022800BC00000002022B945C00000002C6 +:10340000022B884000000001022B942C00000002D7 +:103410000128013800000000022B88400000000055 +:10342000022B942C00000000022B944000000001AD +:103430000A00000100000011022B148000000001AE +:103440000128000000000000012800040000000026 +:1034500001280008000000000128000C0000000006 +:1034600001280010000000000128001400000000E6 +:1034700003280020001A146E032800A400021488F8 +:10348000022802240000000002280234000000008C +:103490000228024C00000000022802E40000FFFFA6 +:1034A00008282000000008000A00000100000010A9 +:1034B0000828400000000200042A5000000000021A +:1034C000042A501000000002042A502000000002CC +:1034D000042A503000000002042A93580000002003 +:1034E000042A94580000000E032A94900002148AC3 +:1034F000042A94D80000000E032A95100002148CB0 +:10350000042A95580000000E032A95900002148E9C +:10351000042A95D80000000E032A96100002149089 +:10352000032A968800021492042ABC980000000224 +:10353000042A500800000002042A5018000000026B +:10354000042A502800000002042A5038000000021B +:10355000042A93D800000020042A94980000000E4A +:10356000032A94D000021494042A95180000000E37 +:10357000032A955000021496042A95980000000E24 +:10358000032A95D000021498042A96180000000E11 +:10359000032A96500002149A032A96900002149C63 +:1035A000042ABCA000000002042A50480000000EBB +:1035B000032A96980010149E042A98D00000000256 +:1035C000042A991000000002042AC48000000002AE +:1035D000042A50800000000E032A96D8001014AE72 +:1035E000042A98D800000002042A9918000000025A +:1035F000042AC48800000002042A50B80000000E0B +:10360000032A9718001014BE042A98E00000000254 +:10361000042A992000000002042AC490000000023D +:10362000042A50F00000000E032A9758001014CE10 +:10363000042A98E800000002042A992800000002E9 +:10364000042AC49800000002042A51280000000E39 +:10365000032A9798001014DE042A98F00000000254 +:10366000042A993000000002042AC4A000000002CD +:10367000042A51600000000E032A97D8001014EEAF +:10368000042A98F800000002042A99380000000279 +:10369000042AC4A800000002042A51980000000E69 +:1036A000032A9818001014FE042A99000000000252 +:1036B000042A994000000002042AC4B0000000025D +:1036C000042A51D00000000E032A98580010150E4D +:1036D000042A990800000002042A99480000000208 +:1036E000042AC4B8000000020400A0000000000C7E +:1036F0000400A050000000020300A0EC0008151E0A +:103700000300A19C000415260200A45C00000C002C +:103710000400A6A8000000020200A6D000000000DD +:103720000200A61C000000030300A0700005152A7B +:103730000400A084000000050200A0980FE0000033 +:103740000400A09C000000070300A0B8000D152F86 +:103750000400A22C000000040200A688000000FC67 +:103760000400A68C000000070200A6F40000000080 +:103770000300A10C0006153C0400A1240000000574 +:103780000200A1380FE000000400A13C0000000787 +:103790000300A158000D15420400A23C00000004E3 +:1037A0000200A6B0000000FC0400A6B40000000760 +:1037B0000200A6F8000000000200A0300000000097 +:1037C0000200A034000000000200A0380000000049 +:1037D0000200A03C000000000200A0400000000029 +:1037E0000200A044000000000200A0480000000009 +:1037F0000200A04C000000000000000000000000DB +:1038000000000001000000000000000000000000B7 +:1038100000000000000000000000000000000000A8 +:103820000000000000000000000000000001001780 +:103830000017001F001F0022000000000000000011 +:103840000000000000000000000000000000000078 +:103850000000000000000000002200340000000012 +:103860000000000000340035003500360036003717 +:1038700000370038003800390039003A003A003B80 +:10388000003B003C003C0043000000000000000042 +:103890000000000000000000000000000000000028 +:1038A0000000000000000000000000000000000018 +:1038B0000043004C0000000000000000004C004DE0 +:1038C000004D004E004E004F004F00500050005180 +:1038D0000051005200520053005300540054007E27 +:1038E00000000000000000000000000000000000D8 +:1038F00000000000000000000000000000000000C8 +:103900000000000000000000007E01E00000000058 +:103910000000000001E001E501E501EA01EA01EF34 +:1039200001EF01F401F401F901F901FE01FE0203C6 +:103930000203020800000000000000000000000078 +:103940000000000000000000000000000000000077 +:103950000000000000000000000000000000000067 +:103960000208020C0000000000000000000000003F +:103970000000000000000000000000000000000047 +:10398000000000000000000000000000020C021C0B +:103990000000000000000000021C021E021E0220A7 +:1039A00002200222022202240224022602260228E7 +:1039B0000228022A022A022C000000000000000057 +:1039C00000000000000000000000000000000000F7 +:1039D00000000000000000000000000000000000E7 +:1039E00000000000022C022F000000000000000078 +:1039F000022F023202320235023502380238023B0F +:103A0000023B023E023E024102410244024402479E +:103A10000247024B024B024F024F02530253025421 +:103A200002540255025502560256025702570258D6 +:103A3000025802590259025A025A025B025B0260A2 +:103A400002600286028602AB02AB02AC02AC02AD9F +:103A500002AD02AE02AE02AF02AF02B002B002B1DE +:103A600002B102B202B202B302B302CA0000000005 +:103A70000000000000000000000000000000000046 +:103A80000000000000000000000000000000000036 +:103A90000000000002CA02D7000000000000000081 +:103AA00002D702D802D802D902D902DA02DA02DB3E +:103AB00002DB02DC02DC02DD02DD02DE02DE02DF0E +:103AC00002DF02F000000000000000000000000023 +:103AD00000000000000000000000000000000000E6 +:103AE00000000000000000000000000002F002FEE4 +:103AF000000000000000000002FE02FF02FF0300C1 +:103B0000030003010301030203020303030303048D +:103B100003040305030503060306030B000000006E +:103B20000000000000000000000000000000000095 +:103B30000000000000000000000000000000000085 +:103B400000000000030B03A90000000000000000BB +:103B50000000000000000000000000000000000065 +:103B60000000000000000000000000000000000055 +:103B700003A903AB000000000000000000000000EB +:103B80000000000000000000000000000000000035 +:103B900000000000000000000000000003AB03BFB5 +:103BA000000000000000000003BF03C003C003C109 +:103BB00003C103C203C203C303C303C403C403C5D5 +:103BC00003C503C603C603C703C703E703E703EA46 +:103BD00003EA03ED00000000000000000000000008 +:103BE00000000000000000000000000000000000D5 +:103BF0000000000003ED04150000000000000000BC +:103C000000000000000000000000000000000000B4 +:103C100000000000000000000000000000000000A4 +:103C200004150480048004870487048E048E0494A1 +:103C30000494049A049A04A004A004A604A604AC64 +:103C400004AC04B204B204B804B804BE04BE04D088 +:103C5000000000000000000004D004D104D104D210 +:103C600004D204D304D304D404D404D504D504D694 +:103C700004D604D704D704D804D804D9000000001F +:103C80000000000000000000000000000000000034 +:103C90000000000000000000000000000000000024 +:103CA0000000000004D9050400000000000000002E +:103CB0000000000000000000000000000000000004 +:103CC00000000000000000000000000000000000F4 +:103CD0000504055B055B0570057005850585058791 +:103CE000058705890589058B058B058D058D058F54 +:103CF000058F05910591059305930595059505A8F3 +:103D0000000000000000000005A805B005B005B8DF +:103D100005B805C005C005C805C805D005D005D83B +:103D200005D805E005E005E805E805E90000000024 +:103D30000000000000000000000000000000000083 +:103D40000000000000000000000000000000000073 +:103D50000000000005E9061A000000000000000055 +:103D60000000000000000000000000000000000053 +:103D70000000000000000000000000000000000043 +:103D8000061A068A068A0699069906A806A806ADA6 +:103D900006AD06B206B206B706B706BC06BC06C13B +:103DA00006C106C606C606CB06CB06D006D006D888 +:103DB00006D806E106E106EA06EA06EB06EB06ECA3 +:103DC00006EC06ED06ED06EE06EE06EF06EF06F053 +:103DD00006F006F106F106F2000000000000000007 +:103DE0000000200000004000000060000000800093 +:103DF0000000A0000000C0000000E0000001000082 +:103E0000000120000001400000016000000180006E +:103E10000001A0000001C0000001E000000200005D +:103E2000000220000002400000026000000280004A +:103E30000002A0000002C0000002E0000003000039 +:103E40000003200000034000000360000003800026 +:103E50000003A0000003C0000003E0000004000015 +:103E60000004200000044000000460000004800002 +:103E70000004A0000004C0000004E00000050000F1 +:103E800000052000000540000005600000058000DE +:103E90000005A0000005C0000005E00000060000CD +:103EA00000062000000640000006600000068000BA +:103EB0000006A0000006C0000006E00000070000A9 +:103EC0000007200000074000000760000007800096 +:103ED0000007A0000007C0000007E0000008000085 +:103EE0000008200000084000000860000008800072 +:103EF0000008A0000008C0000008E0000009000061 +:103F0000000920000009400000096000000980004D +:103F10000009A0000009C0000009E000000A00003C +:103F2000000A2000000A4000000A6000000A800029 +:103F3000000AA000000AC000000AE000000B000018 +:103F4000000B2000000B4000000B6000000B800005 +:103F5000000BA000000BC000000BE000000C0000F4 +:103F6000000C2000000C4000000C6000000C8000E1 +:103F7000000CA000000CC000000CE000000D0000D0 +:103F8000000D2000000D4000000D6000000D8000BD +:103F9000000DA000000DC000000DE000000E0000AC +:103FA000000E2000000E4000000E6000000E800099 +:103FB000000EA000000EC000000EE000000F000088 +:103FC000000F2000000F4000000F6000000F800075 +:103FD000000FA000000FC000000FE0000010000064 +:103FE0000010200000104000001060000010800051 +:103FF0000010A0000010C0000010E0000011000040 +:10400000001120000011400000116000001180002C +:104010000011A0000011C0000011E000001200001B +:104020000012200000124000001260000012800008 +:104030000012A0000012C0000012E00000130000F7 +:1040400000132000001340000013600000138000E4 +:104050000013A0000013C0000013E00000140000D3 +:1040600000142000001440000014600000148000C0 +:104070000014A0000014C0000014E00000150000AF +:10408000001520000015400000156000001580009C +:104090000015A0000015C0000015E000001600008B +:1040A0000016200000164000001660000016800078 +:1040B0000016A0000016C0000016E0000017000067 +:1040C0000017200000174000001760000017800054 +:1040D0000017A0000017C0000017E0000018000043 +:1040E0000018200000184000001860000018800030 +:1040F0000018A0000018C0000018E000001900001F +:10410000001920000019400000196000001980000B +:104110000019A0000019C0000019E000001A0000FA +:10412000001A2000001A4000001A6000001A8000E7 +:10413000001AA000001AC000001AE000001B0000D6 +:10414000001B2000001B4000001B6000001B8000C3 +:10415000001BA000001BC000001BE000001C0000B2 +:10416000001C2000001C4000001C6000001C80009F +:10417000001CA000001CC000001CE000001D00008E +:10418000001D2000001D4000001D6000001D80007B +:10419000001DA000001DC000001DE000001E00006A +:1041A000001E2000001E4000001E6000001E800057 +:1041B000001EA000001EC000001EE000001F000046 +:1041C000001F2000001F4000001F6000001F800033 +:1041D000001FA000001FC000001FE0000020000022 +:1041E000002020000020400000206000002080000F +:1041F0000020A0000020C0000020E00000210000FE +:1042000000212000002140000021600000218000EA +:104210000021A0000021C0000021E00000220000D9 +:1042200000222000002240000022600000228000C6 +:104230000022A0000022C0000022E00000230000B5 +:1042400000232000002340000023600000238000A2 +:104250000023A0000023C0000023E0000024000091 +:10426000002420000024400000246000002480007E +:104270000024A0000024C0000024E000002500006D +:10428000002520000025400000256000002580005A +:104290000025A0000025C0000025E0000026000049 +:1042A0000026200000264000002660000026800036 +:1042B0000026A0000026C0000026E0000027000025 +:1042C0000027200000274000002760000027800012 +:1042D0000027A0000027C0000027E0000028000001 +:1042E00000282000002840000028600000288000EE +:1042F0000028A0000028C0000028E00000290000DD +:1043000000292000002940000029600000298000C9 +:104310000029A0000029C0000029E000002A0000B8 +:10432000002A2000002A4000002A6000002A8000A5 +:10433000002AA000002AC000002AE000002B000094 +:10434000002B2000002B4000002B6000002B800081 +:10435000002BA000002BC000002BE000002C000070 +:10436000002C2000002C4000002C6000002C80005D +:10437000002CA000002CC000002CE000002D00004C +:10438000002D2000002D4000002D6000002D800039 +:10439000002DA000002DC000002DE000002E000028 +:1043A000002E2000002E4000002E6000002E800015 +:1043B000002EA000002EC000002EE000002F000004 +:1043C000002F2000002F4000002F6000002F8000F1 +:1043D000002FA000002FC000002FE00000300000E0 +:1043E00000302000003040000030600000308000CD +:1043F0000030A0000030C0000030E00000310000BC +:1044000000312000003140000031600000318000A8 +:104410000031A0000031C0000031E0000032000097 +:104420000032200000324000003260000032800084 +:104430000032A0000032C0000032E0000033000073 +:104440000033200000334000003360000033800060 +:104450000033A0000033C0000033E000003400004F +:10446000003420000034400000346000003480003C +:104470000034A0000034C0000034E000003500002B +:104480000035200000354000003560000035800018 +:104490000035A0000035C0000035E0000036000007 +:1044A00000362000003640000036600000368000F4 +:1044B0000036A0000036C0000036E00000370000E3 +:1044C00000372000003740000037600000378000D0 +:1044D0000037A0000037C0000037E00000380000BF +:1044E00000382000003840000038600000388000AC +:1044F0000038A0000038C0000038E000003900009B +:104500000039200000394000003960000039800087 +:104510000039A0000039C0000039E000003A000076 +:10452000003A2000003A4000003A6000003A800063 +:10453000003AA000003AC000003AE000003B000052 +:10454000003B2000003B4000003B6000003B80003F +:10455000003BA000003BC000003BE000003C00002E +:10456000003C2000003C4000003C6000003C80001B +:10457000003CA000003CC000003CE000003D00000A +:10458000003D2000003D4000003D6000003D8000F7 +:10459000003DA000003DC000003DE000003E0000E6 +:1045A000003E2000003E4000003E6000003E8000D3 +:1045B000003EA000003EC000003EE000003F0000C2 +:1045C000003F2000003F4000003F6000003F8000AF +:1045D000003FA000003FC000003FE000004000009E +:1045E000004020000040400000406000004080008B +:1045F0000040A0000040C0000040E000004100007A +:104600000041200000414000004160000041800066 +:104610000041A0000041C0000041E0000042000055 +:104620000042200000424000004260000042800042 +:104630000042A0000042C0000042E0000043000031 +:10464000004320000043400000436000004380001E +:104650000043A0000043C0000043E000004400000D +:1046600000442000004440000044600000448000FA +:104670000044A0000044C0000044E00000450000E9 +:1046800000452000004540000045600000458000D6 +:104690000045A0000045C0000045E00000460000C5 +:1046A00000462000004640000046600000468000B2 +:1046B0000046A0000046C0000046E00000470000A1 +:1046C000004720000047400000476000004780008E +:1046D0000047A0000047C0000047E000004800007D +:1046E000004820000048400000486000004880006A +:1046F0000048A0000048C0000048E0000049000059 +:104700000049200000494000004960000049800045 +:104710000049A0000049C0000049E000004A000034 +:10472000004A2000004A4000004A6000004A800021 +:10473000004AA000004AC000004AE000004B000010 +:10474000004B2000004B4000004B6000004B8000FD +:10475000004BA000004BC000004BE000004C0000EC +:10476000004C2000004C4000004C6000004C8000D9 +:10477000004CA000004CC000004CE000004D0000C8 +:10478000004D2000004D4000004D6000004D8000B5 +:10479000004DA000004DC000004DE000004E0000A4 +:1047A000004E2000004E4000004E6000004E800091 +:1047B000004EA000004EC000004EE000004F000080 +:1047C000004F2000004F4000004F6000004F80006D +:1047D000004FA000004FC000004FE000005000005C +:1047E0000050200000504000005060000050800049 +:1047F0000050A0000050C0000050E0000051000038 +:104800000051200000514000005160000051800024 +:104810000051A0000051C0000051E0000052000013 +:104820000052200000524000005260000052800000 +:104830000052A0000052C0000052E00000530000EF +:1048400000532000005340000053600000538000DC +:104850000053A0000053C0000053E00000540000CB +:1048600000542000005440000054600000548000B8 +:104870000054A0000054C0000054E00000550000A7 +:104880000055200000554000005560000055800094 +:104890000055A0000055C0000055E0000056000083 +:1048A0000056200000564000005660000056800070 +:1048B0000056A0000056C0000056E000005700005F +:1048C000005720000057400000576000005780004C +:1048D0000057A0000057C0000057E000005800003B +:1048E0000058200000584000005860000058800028 +:1048F0000058A0000058C0000058E0000059000017 +:104900000059200000594000005960000059800003 +:104910000059A0000059C0000059E000005A0000F2 +:10492000005A2000005A4000005A6000005A8000DF +:10493000005AA000005AC000005AE000005B0000CE +:10494000005B2000005B4000005B6000005B8000BB +:10495000005BA000005BC000005BE000005C0000AA +:10496000005C2000005C4000005C6000005C800097 +:10497000005CA000005CC000005CE000005D000086 +:10498000005D2000005D4000005D6000005D800073 +:10499000005DA000005DC000005DE000005E000062 +:1049A000005E2000005E4000005E6000005E80004F +:1049B000005EA000005EC000005EE000005F00003E +:1049C000005F2000005F4000005F6000005F80002B +:1049D000005FA000005FC000005FE000006000001A +:1049E0000060200000604000006060000060800007 +:1049F0000060A0000060C0000060E00000610000F6 +:104A000000612000006140000061600000618000E2 +:104A10000061A0000061C0000061E00000620000D1 +:104A200000622000006240000062600000628000BE +:104A30000062A0000062C0000062E00000630000AD +:104A4000006320000063400000636000006380009A +:104A50000063A0000063C0000063E0000064000089 +:104A60000064200000644000006460000064800076 +:104A70000064A0000064C0000064E0000065000065 +:104A80000065200000654000006560000065800052 +:104A90000065A0000065C0000065E0000066000041 +:104AA000006620000066400000666000006680002E +:104AB0000066A0000066C0000066E000006700001D +:104AC000006720000067400000676000006780000A +:104AD0000067A0000067C0000067E00000680000F9 +:104AE00000682000006840000068600000688000E6 +:104AF0000068A0000068C0000068E00000690000D5 +:104B000000692000006940000069600000698000C1 +:104B10000069A0000069C0000069E000006A0000B0 +:104B2000006A2000006A4000006A6000006A80009D +:104B3000006AA000006AC000006AE000006B00008C +:104B4000006B2000006B4000006B6000006B800079 +:104B5000006BA000006BC000006BE000006C000068 +:104B6000006C2000006C4000006C6000006C800055 +:104B7000006CA000006CC000006CE000006D000044 +:104B8000006D2000006D4000006D6000006D800031 +:104B9000006DA000006DC000006DE000006E000020 +:104BA000006E2000006E4000006E6000006E80000D +:104BB000006EA000006EC000006EE000006F0000FC +:104BC000006F2000006F4000006F6000006F8000E9 +:104BD000006FA000006FC000006FE00000700000D8 +:104BE00000702000007040000070600000708000C5 +:104BF0000070A0000070C0000070E00000710000B4 +:104C000000712000007140000071600000718000A0 +:104C10000071A0000071C0000071E000007200008F +:104C2000007220000072400000726000007280007C +:104C30000072A0000072C0000072E000007300006B +:104C40000073200000734000007360000073800058 +:104C50000073A0000073C0000073E0000074000047 +:104C60000074200000744000007460000074800034 +:104C70000074A0000074C0000074E0000075000023 +:104C80000075200000754000007560000075800010 +:104C90000075A0000075C0000075E00000760000FF +:104CA00000762000007640000076600000768000EC +:104CB0000076A0000076C0000076E00000770000DB +:104CC00000772000007740000077600000778000C8 +:104CD0000077A0000077C0000077E00000780000B7 +:104CE00000782000007840000078600000788000A4 +:104CF0000078A0000078C0000078E0000079000093 +:104D0000007920000079400000796000007980007F +:104D10000079A0000079C0000079E000007A00006E +:104D2000007A2000007A4000007A6000007A80005B +:104D3000007AA000007AC000007AE000007B00004A +:104D4000007B2000007B4000007B6000007B800037 +:104D5000007BA000007BC000007BE000007C000026 +:104D6000007C2000007C4000007C6000007C800013 +:104D7000007CA000007CC000007CE000007D000002 +:104D8000007D2000007D4000007D6000007D8000EF +:104D9000007DA000007DC000007DE000007E0000DE +:104DA000007E2000007E4000007E6000007E8000CB +:104DB000007EA000007EC000007EE000007F0000BA +:104DC000007F2000007F4000007F6000007F8000A7 +:104DD000007FA000007FC000007FE000007FE001B6 +:104DE00000000000000001FF0000020000000000C1 +:104DF000000003FF000004000000040100000401A3 +:104E0000000002380000011C0000011C0000011C11 +:104E100000000050000000500000005000000001A1 +:104E200000000158000001A8000000C8000000A018 +:104E3000000000C800000000000000000000005A50 +:104E4000000000FA00000401000004010000000A54 +:104E500000000032000004010000040100000158BD +:104E6000000001A80000001800000068000000B861 +:104E70000000010800000158000001A8000000180F +:104E800000000068000000B80000010800000001F8 +:104E900000000002000000000000000802150020D1 +:104EA000021500200810000000000036000000007D +:104EB00000000004000000040000000000000000EA +:104EC00000000001000000040000000200000002D9 +:104ED000000000010000000200000020000000406F +:104EE0000000004000000003000000180000200047 +:104EF000000040C000006180000082400000A3006C +:104F00000000C3C00000E48000010540000126004D +:104F1000000146C000016780000188400001A9002F +:104F20000001C9C00001EA8000020B4000022C0011 +:104F300000024CC000026D8000028E400002AF00F3 +:104F40000002CFC00002F08000001140000000010C +:104F5000000000010000000100000001000000014D +:104F6000000000010000000100000001000000013D +:104F7000000000010000000100000001000000012D +:104F800000000001000000010003D0000000003D0F +:104F900000000001000D0000000700D00002814069 +:104FA000000B81680002022000010240000F025045 +:104FB00000010340000C0000000800C00002814016 +:104FC000000B81680002022000010240000702502D +:104FD000000202C0001000000008010000028180F1 +:104FE000000B81A80002026000018280000E8298FE +:104FF00000080380000F0000000100F000028100A3 +:1050000000090128000201B8000101D8000E01E8E2 +:10501000000002C8FFFFFFF301AFFFFF0000000028 +:105020000000000000000000000000000000000080 +:1050300000000000FFFFFFF100EFFFFF0000000095 +:10504000000000000000000000000000000100005F +:1050500000000000FFFFFFF6005FFFFF0000000000 +:10506000000000000000000000000000000200003E +:1050700000000000FFFFF4061CBFFFFF000000055A +:105080000000000000000014000000000004000008 +:1050900000000000FFFFFFF2004FFFFF00000000D4 +:1050A00000000000000000000000000000080000F8 +:1050B00000000000FFFFFFFA002FFFFF00000000CC +:1050C00000000000000000000000000000100000D0 +:1050D00000000000FFFFFFF701EFFFFF00000000EE +:1050E00000000000000000000000000000200000A0 +:1050F00000000000FFFFFFF5002FFFFF0000000091 +:10510000000000000000000000000000004000005F +:1051100000000000FFFFFFF3018FFFFF0000000011 +:10512000000000000000000000000000000000007F +:1051300000000000FFFFFFF1010FFFFF0000000073 +:10514000000000000000000000000000000100005E +:1051500000000000FFFFFFF6005FFFFF00000000FF +:10516000000000000000000000000000000200003D +:1051700000000000FFFFF4061CBFFFFF0000000559 +:105180000000000000000014000000000004000007 +:1051900000000000FFFFFFF2004FFFFF00000000D3 +:1051A00000000000000000000000000000080000F7 +:1051B00000000000FFFFFFFA002FFFFF00000000CB +:1051C00000000000000000000000000000100000CF +:1051D00000000000FFFFFFF700EFFFFF00000000EE +:1051E000000000000000000000000000002000009F +:1051F00000000000FFFFFFF5004FFFFF0000000070 +:10520000000000000000000000000000004000005E +:1052100000000000FFFFFFFF00CFFFFF00000000C5 +:1052200000000000000000CC0000000000000000B2 +:1052300000000000FFFFFFFF00CFFFFF00000000A5 +:1052400000000000000000CC000000000001000091 +:1052500000000000FFFFFFFF00CFFFFF0000000085 +:1052600000000000000000CC000000000002000070 +:1052700000000000FFFFFFFF00CFFFFF0000000065 +:1052800000000000000000CC00000000000400004E +:1052900000000000FFFFFFFF00CFFFFF0000000045 +:1052A00000000000000000CC00000000000800002A +:1052B00000000000FFFFFFFF00CFFFFF0000000025 +:1052C00000000000000000CC000000000010000002 +:1052D00000000000FFFFFFFF00CFFFFF0000000005 +:1052E00000000000000000CC0000000000200000D2 +:1052F00000000000FFFFFFFF00CFFFFF00000000E5 +:1053000000000000000000CC000000000040000091 +:1053100000000000FFFFFFF3020FFFFF000000008E +:10532000000000000000000000000000000000007D +:1053300000000000FFFFFFF1010FFFFF0000000071 +:10534000000000000000000000000000000100005C +:1053500000000000FFFFFFF6005FFFFF00000000FD +:10536000000000000000000000000000000200003B +:1053700000000000FFFFF4061CBFFFFF0000000557 +:105380000000000000000014000000000004000005 +:1053900000000000FFFFFFF2004FFFFF00000000D1 +:1053A00000000000000000000000000000080000F5 +:1053B00000000000FFFFFF8A042FFFFF0000000035 +:1053C00000000000000000000000000000100000CD +:1053D00000000000FFFFFF9705CFFFFF0000000067 +:1053E000000000000000000000000000002000009D +:1053F00000000000FFFFFFF5010FFFFF00000000AD +:10540000000000000000000000000000004000005C +:1054100000000000FFFFFFF301EFFFFF00000000AE +:10542000000000000000000000000000000000007C +:1054300000000000FFFFFFF1002FFFFF0000000051 +:10544000000000000000000000000000000100005B +:1054500000000000FFFFFFF6005FFFFF00000000FC +:10546000000000000000000000000000000200003A +:1054700000000000FFFFFF061CBFFFFF0000000050 +:105480000000000000000014000000000004000004 +:1054900000000000FFFFFFF2004FFFFF00000000D0 +:1054A00000000000000000000000000000080000F4 +:1054B00000000000FFFFFFFA002FFFFF00000000C8 +:1054C00000000000000000000000000000100000CC +:1054D00000000000FFFFFFF701CFFFFF000000000A +:1054E000000000000000000000000000002000009C +:1054F00000000000FFFFFFFF00CFFFFF00000000E3 +:1055000000000000000000CC00000000004000008F +:1055100000000000FFFFFFFF00CFFFFF00000000C2 +:1055200000000000000000CC0000000000000000AF +:1055300000000000FFFFFFFF00CFFFFF00000000A2 +:1055400000000000000000CC00000000000100008E +:1055500000000000FFFFFFFF00CFFFFF0000000082 +:1055600000000000000000CC00000000000200006D +:1055700000000000FFFFFFFF00CFFFFF0000000062 +:1055800000000000000000CC00000000000400004B +:1055900000000000FFFFFFFF00CFFFFF0000000042 +:1055A00000000000000000CC000000000008000027 +:1055B00000000000FFFFFFFF00CFFFFF0000000022 +:1055C00000000000000000CC0000000000100000FF +:1055D00000000000FFFFFFFF00CFFFFF0000000002 +:1055E00000000000000000CC0000000000200000CF +:1055F00000000000FFFFFFFF00CFFFFF00000000E2 +:1056000000000000000000CC00000000004000008E +:1056100000000000FFFFFFFF00CFFFFF00000000C1 +:1056200000000000000000CC0000000000000000AE +:1056300000000000FFFFFFFF00CFFFFF00000000A1 +:1056400000000000000000CC00000000000100008D +:1056500000000000FFFFFFFF00CFFFFF0000000081 +:1056600000000000000000CC00000000000200006C +:1056700000000000FFFFFFFF00CFFFFF0000000061 +:1056800000000000000000CC00000000000400004A +:1056900000000000FFFFFFFF00CFFFFF0000000041 +:1056A00000000000000000CC000000000008000026 +:1056B00000000000FFFFFFFF00CFFFFF0000000021 +:1056C00000000000000000CC0000000000100000FE +:1056D00000000000FFFFFFFF00CFFFFF0000000001 +:1056E00000000000000000CC0000000000200000CE +:1056F00000000000FFFFFFFF00CFFFFF00000000E1 +:1057000000000000000000CC00000000004000008D +:1057100000000000FFFFFFFF00CFFFFF00000000C0 +:1057200000000000000000CC0000000000000000AD +:1057300000000000FFFFFFFF00CFFFFF00000000A0 +:1057400000000000000000CC00000000000100008C +:1057500000000000FFFFFFFF00CFFFFF0000000080 +:1057600000000000000000CC00000000000200006B +:1057700000000000FFFFFFFF00CFFFFF0000000060 +:1057800000000000000000CC000000000004000049 +:1057900000000000FFFFFFFF00CFFFFF0000000040 +:1057A00000000000000000CC000000000008000025 +:1057B00000000000FFFFFFFF00CFFFFF0000000020 +:1057C00000000000000000CC0000000000100000FD +:1057D00000000000FFFFFFFF00CFFFFF0000000000 +:1057E00000000000000000CC0000000000200000CD +:1057F00000000000FFFFFFFF00CFFFFF00000000E0 +:1058000000000000000000CC00000000004000008C +:105810000000000000000032000000320000021111 +:1058200000000200000002040000FFFF0000FFFF74 +:105830000000FFFF0000FFFF000000000000003735 +:105840000000002100000020000000010000000115 +:105850000000000107FFFFFF0000007F07FFFFFFC0 +:105860000000003F0000FFFF0000FFFF0000FFFFFF +:105870000000FFFF00007FF800007FF8000000003C +:10588000000028AD000029180000291900000005BB +:105890000000000700000000000000000000FF0002 +:1058A000000000000000FF00000000000000FF00FA +:1058B000000000000000FF00000000000000FF00EA +:1058C000000000000000FF00000000000000FF00DA +:1058D000000000000000FF00000000000000FF00CA +:1058E000000000000000FF00000000000000FF00BA +:1058F000000000000000FF00000000000000FF00AA +:10590000000000000000FF00000000000000FF0099 +:10591000000000000000FF00000000000000FF0089 +:10592000000000000000FF00000000000000FF0079 +:10593000000000000000FF00000000000000FF0069 +:10594000000000000000FF00000000000000FF0059 +:10595000000000000000FF00000000000000FF0049 +:10596000000000000000FF00000000000000FF0039 +:10597000000000000000FF00000000000000FF0029 +:10598000000000000000FF00000000000000FF0019 +:10599000000000000000FF00000000000000FF0009 +:1059A000000000000000FF00000000000000FF00F9 +:1059B000000000000000FF00000000000000FF00E9 +:1059C000000000000000FF00000000000000FF00D9 +:1059D000000000000000FF00000000000000FF00C9 +:1059E000000000000000FF00000000000000FF00B9 +:1059F000000000000000FF00000000000000FF00A9 +:105A0000000000000000FF00000000000000FF0098 +:105A1000000000000000FF00000000000000FF0088 +:105A2000000000000000FF00000000000000FF0078 +:105A3000000000000000FF00000000000000FF0068 +:105A4000000000000000FF00000000000000FF0058 +:105A5000000000000000FF00000000000000FF0048 +:105A6000000000000000FF00000000000000FF0038 +:105A7000000000000000FF00000000000000FF0028 +:105A8000000000000000FF00000000000000FF0018 +:105A9000000000000000FF00000000000000FF0008 +:105AA000000000000000FF00000000000000FF00F8 +:105AB000000000000000FF00000000000000FF00E8 +:105AC000000000000000FF00000000000000FF00D8 +:105AD000000000000000FF00000000000000FF1CAC +:105AE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C68 +:105AF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C58 +:105B00000FFFFFFF0000FF1C0FFFFFFF0000FF1C47 +:105B10000FFFFFFF0000FF1C0FFFFFFF0000FF1C37 +:105B20000FFFFFFF0000FF1C0FFFFFFF0000FF1C27 +:105B30000FFFFFFF0000FF1C0FFFFFFF0000FF1C17 +:105B40000FFFFFFF0000FF1C0FFFFFFF0000FF1C07 +:105B50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF7 +:105B60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE7 +:105B70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD7 +:105B80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC7 +:105B90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB7 +:105BA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA7 +:105BB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C97 +:105BC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C87 +:105BD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C77 +:105BE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C67 +:105BF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C57 +:105C00000FFFFFFF0000FF1C0FFFFFFF0000FF1C46 +:105C10000FFFFFFF0000FF1C0FFFFFFF0000FF1C36 +:105C20000FFFFFFF0000FF1C0FFFFFFF0000FF1C26 +:105C30000FFFFFFF0000FF1C0FFFFFFF0000FF1C16 +:105C40000FFFFFFF0000FF1C0FFFFFFF0000FF1C06 +:105C50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF6 +:105C60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE6 +:105C70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD6 +:105C80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC6 +:105C90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB6 +:105CA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA6 +:105CB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C96 +:105CC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C86 +:105CD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C76 +:105CE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C66 +:105CF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C56 +:105D00000FFFFFFF0000FF1C0FFFFFFF0000FF1C45 +:105D10000FFFFFFF0000FF1C0FFFFFFF0000FF1C35 +:105D20000FFFFFFF0000FF1C0FFFFFFF0000FF1C25 +:105D30000FFFFFFF0000FF1C0FFFFFFF0000FF1C15 +:105D40000FFFFFFF0000FF1C0FFFFFFF0000FF1C05 +:105D50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF5 +:105D60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE5 +:105D70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD5 +:105D80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC5 +:105D90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB5 +:105DA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA5 +:105DB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C95 +:105DC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C85 +:105DD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C75 +:105DE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C65 +:105DF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C55 +:105E00000FFFFFFF0000FF1C0FFFFFFF0000FF1C44 +:105E10000FFFFFFF0000FF1C0FFFFFFF0000FF1C34 +:105E20000FFFFFFF0000FF1C0FFFFFFF0000FF1C24 +:105E30000FFFFFFF0000FF1C0FFFFFFF0000FF1C14 +:105E40000FFFFFFF0000FF1C0FFFFFFF0000FF1C04 +:105E50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF4 +:105E60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE4 +:105E70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD4 +:105E80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC4 +:105E90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB4 +:105EA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA4 +:105EB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C94 +:105EC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C84 +:105ED0000FFFFFFF0000FF1C0FFFFFFF0000FF1C74 +:105EE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C64 +:105EF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C54 +:105F00000FFFFFFF0000FF1C0FFFFFFF0000FF1C43 +:105F10000FFFFFFF0000FF1C0FFFFFFF0000FF1C33 +:105F20000FFFFFFF0000FF1C0FFFFFFF0000FF1C23 +:105F30000FFFFFFF0000FF1C0FFFFFFF0000FF1C13 +:105F40000FFFFFFF0000FF1C0FFFFFFF0000FF1C03 +:105F50000FFFFFFF0000FF1C0FFFFFFF0000FF1CF3 +:105F60000FFFFFFF0000FF1C0FFFFFFF0000FF1CE3 +:105F70000FFFFFFF0000FF1C0FFFFFFF0000FF1CD3 +:105F80000FFFFFFF0000FF1C0FFFFFFF0000FF1CC3 +:105F90000FFFFFFF0000FF1C0FFFFFFF0000FF1CB3 +:105FA0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA3 +:105FB0000FFFFFFF0000FF1C0FFFFFFF0000FF1C93 +:105FC0000FFFFFFF0000FF1C0FFFFFFF0000FF1C83 +:105FD0000FFFFFFF0000FF1C0FFFFFFF0000FF1C73 +:105FE0000FFFFFFF0000FF1C0FFFFFFF0000FF1C63 +:105FF0000FFFFFFF0000FF1C0FFFFFFF0000FF1C53 +:106000000FFFFFFF0000FF1C0FFFFFFF0000FF1C42 +:106010000FFFFFFF0000FF1C0FFFFFFF0000FF1C32 +:106020000FFFFFFF0000FF1C0FFFFFFF0000FF1C22 +:106030000FFFFFFF0000FF1C0FFFFFFF0000FF1C12 +:106040000FFFFFFF0000FF1C0FFFFFFF0000FF1C02 +:106050000FFFFFFF0000FF1C0FFFFFFF0000FF1CF2 +:106060000FFFFFFF0000FF1C0FFFFFFF0000FF1CE2 +:106070000FFFFFFF0000FF1C0FFFFFFF0000FF1CD2 +:106080000FFFFFFF0000FF1C0FFFFFFF0000FF1CC2 +:106090000FFFFFFF0000FF1C0FFFFFFF0000FF1CB2 +:1060A0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA2 +:1060B0000FFFFFFF0000FF1C0FFFFFFF0000FF1C92 +:1060C0000FFFFFFF0000FF1C0FFFFFFF0000FF1C82 +:1060D0000FFFFFFF0000FF1C0FFFFFFF0000FF1C72 +:1060E0000FFFFFFF0000FF1C0FFFFFFF0000FF1C62 +:1060F0000FFFFFFF0000FF1C0FFFFFFF0000FF1C52 +:106100000FFFFFFF0000FF1C0FFFFFFF0000FF1C41 +:106110000FFFFFFF0000FF1C0FFFFFFF0000FF1C31 +:106120000FFFFFFF0000FF1C0FFFFFFF0000FF1C21 +:106130000FFFFFFF0000FF1C0FFFFFFF0000FF1C11 +:106140000FFFFFFF0000FF1C0FFFFFFF0000FF1C01 +:106150000FFFFFFF0000FF1C0FFFFFFF0000FF1CF1 +:106160000FFFFFFF0000FF1C0FFFFFFF0000FF1CE1 +:106170000FFFFFFF0000FF1C0FFFFFFF0000FF1CD1 +:106180000FFFFFFF0000FF1C0FFFFFFF0000FF1CC1 +:106190000FFFFFFF0000FF1C0FFFFFFF0000FF1CB1 +:1061A0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA1 +:1061B0000FFFFFFF0000FF1C0FFFFFFF0000FF1C91 +:1061C0000FFFFFFF0000FF1C0FFFFFFF0000FF1C81 +:1061D0000FFFFFFF0000FF1C0FFFFFFF0000FF1C71 +:1061E0000FFFFFFF0000FF1C0FFFFFFF0000FF1C61 +:1061F0000FFFFFFF0000FF1C0FFFFFFF0000FF1C51 +:106200000FFFFFFF0000FF1C0FFFFFFF0000FF1C40 +:106210000FFFFFFF0000FF1C0FFFFFFF0000FF1C30 +:106220000FFFFFFF0000FF1C0FFFFFFF0000FF1C20 +:106230000FFFFFFF0000FF1C0FFFFFFF0000FF1C10 +:106240000FFFFFFF0000FF1C0FFFFFFF0000FF1C00 +:106250000FFFFFFF0000FF1C0FFFFFFF0000FF1CF0 +:106260000FFFFFFF0000FF1C0FFFFFFF0000FF1CE0 +:106270000FFFFFFF0000FF1C0FFFFFFF0000FF1CD0 +:106280000FFFFFFF0000FF1C0FFFFFFF0000FF1CC0 +:106290000FFFFFFF0000FF1C0FFFFFFF0000FF1CB0 +:1062A0000FFFFFFF0000FF1C0FFFFFFF0000FF1CA0 +:1062B0000FFFFFFF0000FF1C0FFFFFFF0000FF1C90 +:1062C0000FFFFFFF0000FF1C0FFFFFFF0000FF1C80 +:1062D0000FFFFFFF0000FF1C0FFFFFFF0000FF1C70 +:1062E0000FFFFFFF0000FF1C0FFFFFFF0000FF1C60 +:1062F0000FFFFFFF0000FF1C0FFFFFFF0000FF1C50 +:106300000FFFFFFF0000FF1C0FFFFFFF0000FF1C3F +:106310000FFFFFFF0000FF1C0FFFFFFF0000FF1C2F +:106320000FFFFFFF0000FF1C0FFFFFFF0000FF1C1F +:106330000FFFFFFF0000FF1C0FFFFFFF0000FF1C0F +:106340000FFFFFFF0000FF1C0FFFFFFF0000FF1CFF +:106350000FFFFFFF0000FF1C0FFFFFFF00000A28D8 +:1063600000003500000000010000000200000003F2 +:106370000000000000000004000000010000000018 +:106380000000000100000004000000000000000107 +:1063900000000003000000000000000100000004F5 +:1063A00000000000000000010000000300000000E9 +:1063B00000000001000000040000000000000004D4 +:1063C00000000003000000000000000000007FFF4C +:1063D000000003FF000000000000000100000001B9 +:1063E000000000010000000000000002000000901A +:1063F000000000900080009008100000000009FFDD +:106400000000076C0000008A00000080000000818E +:10641000000000800000008A000000800000008171 +:10642000000000800000008A000000800000008161 +:10643000000000800000008A000000800000008151 +:10644000000000800000008A000000800000008141 +:1064500000000080000000010000000100000001B9 +:10646000000000010000000100000001000025E420 +:10647000000025E400004BC800004BC800000018D5 +:106480000000111A005432100000000000210543E2 +:1064900000000000000025E4000025E400004BC8D7 +:1064A00000004BC8000000180000111A0054321000 +:1064B0000000000000210543000000000000000172 +:1064C00000000001000000010000000000000000CA +:1064D00000000001000000020000000000000006B3 +:1064E000000000030000000400000005000000019F +:1064F0000000000100000001000000010000000198 +:106500000000000100000001000000010000000187 +:106510000000000100000001000000010000000177 +:106520000000000100000001000000010000000365 +:106530000000600000000003000060000000000395 +:106540000000400000000300000003000000030002 +:10655000000003000000030000000300000003002F +:106560000003F00800000000000000000000000030 +:106570000000000100000001000000010000000117 +:106580000000000100000001000000010000000107 +:1065900000000001000000010000000100000001F7 +:1065A00000000001000000010000000100000001E7 +:1065B00000000001000000010000000100000001D7 +:1065C00000000001000000010000000100000001C7 +:1065D00000000001000000010000000100000001B7 +:1065E000000000010000000100000001000000FFA9 +:1065F000000000FF000000FF000000FF0000007F1F +:10660000000000FF000000FF000000FF0000003E4F +:10661000000000000000003F0000003F0000003FBD +:106620000000003F0000003F0000003F0000003F6E +:106630000000000F000000001217000022170000E9 +:10664000321700001215000022150000321500005C +:1066500002100000001000001010000020100000C8 +:10666000301000004010000000000000000000009A +:1066700000000000001000001214000022140000AE +:10668000321400004214000000000000000000006E +:106690000000000000008906000089260000003686 +:1066A000000000360810000008100000FFFFFFFF88 +:1066B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA +:1066C000FFFFFFFFFFFFFFFFFFFFFFFFF000C00026 +:1066D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +:1066E000FFFFFFFFFFFFFFFFFFFFFFFFF800C000FE +:1066F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA +:10670000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:10671000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 +:10672000FFFFFFFFFFFFFFFFFFFFFFFF00003C1029 +:106730000000000800000008000000020000000443 +:1067400000000005000000040000004000001808E0 +:1067500000000803000008030000004000000003E0 +:106760000000080300000803000008030001000304 +:1067700000000803000008030000000300000003FD +:1067800000000003000000030000000300000003FD +:1067900000000003000000030000000300000003ED +:1067A00000000003000000030000000300000003DD +:1067B00000000003000024030000002F0000000977 +:1067C000000000190000018400000183000003069E +:1067D0000000001900000006000003060000030688 +:1067E0000000030600000C860000030600000306FC +:1067F0000000000600000006000000060000000681 +:106800000000000600000006000000060000000670 +:106810000000000600000006000000060000000660 +:10682000000000060000000600000006000003064D +:106830000000001300000006000010040000100417 +:106840000010644000106440000000400000001987 +:106850000000000100000000000000000000000037 +:106860000000000000002000000000000000000008 +:1068700000000000000000000400200000000000F4 +:1068800000000000000000000000000041002000A7 +:1068900000000000000000000000000000000000F8 +:1068A000000020000000007C0000003D0000003FD0 +:1068B0000000009C0000000C000000050000000A21 +:1068C0000000000500000053000025E30000005414 +:1068D0000000005400000004000000040000000458 +:1068E0000000000400000004000000040000000498 +:1068F0000000000400000000000000010000000291 +:10690000000000000000000100000002000000097B +:106910000000000B0000000A000000000000000161 +:106920000000000200000000000000010000000262 +:10693000000000090000000B0000000A0000000930 +:106940000000000B0000000A000000090000000B1E +:106950000000000A00000000000008000000020023 +:106960000000040000000000000000001FFF1FFFE7 +:106970001FFF1FFF1FFF1FFF1FFF1FFF000025E45A +:106980000000800020002000200020008000800007 +:1069900080008000400040004000400000000000F7 +:1069A00000000002000001780000017800000000F3 +:1069B000000000000000017800000000000000005E +:1069C00000000000000000010000000200000000C4 +:1069D00000000000000000000000000400000000B3 +:1069E00000000001000000020000000000000000A4 +:1069F0000000000000000004000000000000000192 +:106A00000000000200000000000000010000000281 +:106A10000000000000000001000000020000000073 +:106A20000000000000000000000000040000000062 +:106A30000000000100000002000000000000000152 +:106A40000000000200000000000000010000000241 +:106A50000000000000000000000000000000000432 +:106A6000000000130E490E490E490E490092009293 +:106A7000009200920124012401240124000000005E +:106A80000000000010001000100010002001012084 +:106A9000010110010101010120010120010110018A +:106AA000200101200101100101010101200101204B +:106AB00001011001010101010000000400000006B5 +:106AC00002004104020041040200410402004104AA +:106AD00000000204000002CE000002CE0000000010 +:106AE00000000000000002CC0000000000000000D8 +:106AF0000000000000000001000000020000000093 +:106B00000000000000000000000000040000000081 +:106B10000000000100000002000000000000000072 +:106B20000000000000000004000000130E490E49A0 +:106B30000000000000000000100010001000100015 +:106B400020010120010110010101010120010120AA +:106B500001011001200101200101100101010101C9 +:106B60002001012001011001010101010200410485 +:106B700002004104000000020000000000000002CA +:106B80000000000000000002000000000000000003 +:106B900000000000000000020000000000000002F1 +:106BA00000000000000000020000000000000000E3 +:106BB0000000000000000004000000060200410484 +:106BC000020041040000000100000001000000017B +:106BD00000000001000000010000000100000001B1 +:106BE00000000001000000010000000100000001A1 +:106BF0000000000100000001000000010000000191 +:106C0000000000010000000100000003025555557E +:106C100002555555000002CE000002CE000002CE03 +:106C2000000002CE000002CE000002CE000002CC26 +:106C30000000005400000054000000540000005404 +:106C40000000000000000001000000020000000041 +:106C50000000000600000003000000040000000522 +:106C60000000000000000001000000020000000021 +:106C7000000000000000000000000006000000000E +:106C80000000000100000002000000000000000001 +:106C900000000000000000060000000000000001ED +:106CA00000000002000000000000000100000002DF +:106CB00000000000000000010000000200000000D1 +:106CC00000000000000000000000000600000000BE +:106CD00000000001000000020000000000000001B0 +:106CE000000000020000000000000001000000029F +:106CF000000000000000000000000000000000068E +:106D00000E490E490E490E490092009200920092DF +:106D1000012401240124012410001000100010009F +:106D200020010120010110010101010120010120C8 +:106D300001011001200101200101100101010101E7 +:106D400020010120010110010101010100000004E6 +:106D5000000000060000000000000001000000022A +:106D6000000000000000000000000000000000061D +:106D70000000000000000001000000020000000010 +:106D800000000000000000000000000600000003FA +:106D900000000004000000050000000300000004E3 +:106DA00000000005000000030000000400000005D2 +:106DB00000000003000000030000000300000006C4 +:106DC00000000003000000040000000500000003B4 +:106DD00000000004000000050000000300000004A3 +:106DE0000000000500000003000000030000000395 +:106DF000000000060E490E490000000000920092BB +:106E00000000000001240124000000000000000038 +:106E10000E490E49000000000092009200000000A0 +:106E20000124012410001000100010002001012096 +:106E300001011001010101012001012001011001E6 +:106E400020010120010110010101010120010120A7 +:106E50000101100101010101000000010000000317 +:106E60000000000400000003000000040000000512 +:106E70000000000300000006000000050000000400 +:106E800000000003000000040000000500000003F3 +:106E900000000006000000050000000400000003E0 +:106EA00000000004000000000000000100000002DB +:106EB00000000000000000010000000200000005CA +:106EC00000000003000000060000000500000004B0 +:106ED00000000003000000040000000000000001AA +:106EE000000000020000000000000001000000029D +:106EF000000000050000000300000006000000057F +:106F00000048004800480048009000900090009021 +:106F100001200120012001200402040204020402D5 +:106F20000005000500050005120012001200120005 +:106F300008000800080008000120012001011020BD +:106F40000101012001200120010110200120012068 +:106F50000101102001010120012001200101102068 +:106F600001010120000000040000000600000123D0 +:106F70000000012300000123000001230000012381 +:106F80000000012300000123000001230000012371 +:106F90000000012300000123000001230000012361 +:106FA0000000012300000123000001230000012351 +:106FB0000000012300000123000001230000002045 +:106FC0000000003200000007000000070000000081 +:106FD00000000008000000010000000000000000A8 +:106FE0000000000002150020021500200000003003 +:106FF00008100000000000360000003000000031E2 +:107000000000000400000005000000000000000473 +:107010000000000100000006000000010000000266 +:1070200000000040000000400000001C00000020A4 +:10703000000100000002070000030E00000415001C +:1070400000051C000006230000072A00000831008C +:1070500000093800000A3F00000B4600000C4D00FC +:10706000000D5400000E5B00000F6200001069006C +:10707000001170000012770000137E0000148500DC +:1070800000158C000016930000179A000018A1004C +:107090000019A800001AAF00001BB600001CBD00BC +:1070A000001DC400001ECB00001FD2000000D9004C +:1070B0000000001E0000001D00010000000207800B +:1070C00000030F000004168000051E000006258046 +:1070D00000072D000008348000093C00000A4380AE +:1070E000000B4B00000C5280000D5A00000E618016 +:1070F000000F6900001070800011780000127F807E +:107100000013870000148E800015960000169D80E5 +:107110000017A5000018AC800019B400001ABB804D +:10712000001BC300001CCA800000D2000000000148 +:10713000000000010000000100000001000000014B +:10714000000000010000000100000001000000013B +:10715000000000010000000100000001000000012B +:1071600000000001000000010000000100000028F4 +:107170000000002C000000300000000100000001B1 +:1071800000000001000002110000020000000204E3 +:10719000000002190000FFFF0000FFFF0000FFFFDA +:1071A0000000FFFF07FFFFFF0000007F07FFFFFF5A +:1071B0000000003F0000FFFF0000FFFF0000FFFF96 +:1071C0000000FFFF00007FF800007FF800000000D3 +:1071D000000000010000FF00000000000000FF00B0 +:1071E000000000000000FF00000000000000FF00A1 +:1071F000000000000000FF00000000000000FF0091 +:10720000000000000000FF00000000000000FF0080 +:10721000000000000000FF00000000000000FF0070 +:10722000000000000000FF00000000000000FF0060 +:10723000000000000000FF00000000000000FF0050 +:10724000000000000000FF00000000000000FF0040 +:10725000000000000000FF00000000000000FF0030 +:10726000000000000000FF00000000000000FF0020 +:10727000000000000000FF00000000000000FF0010 +:10728000000000000000FF00000000000000FF0000 +:10729000000000000000FF00000000000000FF00F0 +:1072A000000000000000FF00000000000000FF00E0 +:1072B000000000000000FF00000000000000FF00D0 +:1072C000000000000000FF00000000000000FF00C0 +:1072D000000000000000FF00000000000000FF00B0 +:1072E000000000000000FF00000000000000FF00A0 +:1072F000000000000000FF00000000000000FF0090 +:10730000000000000000FF00000000000000FF007F +:10731000000000000000FF00000000000000FF006F +:10732000000000000000FF00000000000000FF005F +:10733000000000000000FF00000000000000FF004F +:10734000000000000000FF00000000000000FF003F +:10735000000000000000FF00000000000000FF002F +:10736000000000000000FF00000000000000FF001F +:10737000000000000000FF00000000000000FF000F +:10738000000000000000FF00000000000000FF00FF +:10739000000000000000FF00000000000000FF00EF +:1073A000000000000000FF00000000000000FF00DF +:1073B000000000000000FF00000000000000FF00CF +:1073C000000000000000FF00000000000000FF00BF +:1073D000000000000000FF00000000000000FF00AF +:1073E000000000000000FF00000000000000FF009F +:1073F000000000000000FF00000000000000FF008F +:10740000000000000000FF00000000000000FF007E +:1074100000000000002010010000000001009000AA +:10742000000001000000000100000000000000005A +:10743000140AFF000000900200000000000000009D +:1074400000000000000090040000000000000000A8 +:107450000000000000009006000000000000000096 +:107460000000000000009008000000000000000084 +:10747000000000000000900A000000000000000072 +:10748000000000000000900C000000000000000060 +:10749000000000000000900E00000000000000004E +:1074A000000000000000901000000000000000003C +:1074B000000000000000901200000000000000002A +:1074C0000000000000009014000000000000000018 +:1074D0000000000000009016000000000000000006 +:1074E00000000000000090180000000000000000F4 +:1074F000000000000000901A0000000000000000E2 +:10750000000000000000901C0000000000000000CF +:10751000000000000000901E0000000000000000BD +:1075200000000000000090200000000000000000AB +:107530000000000000009022000000000000000099 +:107540000000000000009024000000000000000087 +:107550000000000000009026000000000000000075 +:107560000000000000009028000000000000000063 +:10757000000000000000902A000000000000000051 +:10758000000000000000902C00000000000000003F +:10759000000000000000902E00000000000000002D +:1075A000000000000000903000000000000000001B +:1075B0000000000000009032000000000000000009 +:1075C00000000000000090340000000000000000F7 +:1075D00000000000000090360000000000000000E5 +:1075E00000000000000090380000000000000000D3 +:1075F000000000000000903A0000000000000000C1 +:10760000000000000000903C0000000000000000AE +:10761000000000000000903E00000000000000009C +:10762000000000000000904000000000000000008A +:107630000000000000009042000000000000000078 +:107640000000000000009044000000000000000066 +:107650000000000000009046000000000000000054 +:107660000000000000009048000000000000000042 +:10767000000000000000904A000000000000000030 +:10768000000000000000904C00000000000000001E +:10769000000000000000904E00000000000000000C +:1076A00000000000000090500000000000000000FA +:1076B00000000000000090520000000000000000E8 +:1076C00000000000000090540000000000000000D6 +:1076D00000000000000090560000000000000000C4 +:1076E00000000000000090580000000000000000B2 +:1076F000000000000000905A0000000000000000A0 +:10770000000000000000905C00000000000000008D +:10771000000000000000905E00000000000000007B +:107720000000000000009060000000000000000069 +:107730000000000000009062000000000000000057 +:107740000000000000009064000000000000000045 +:107750000000000000009066000000000000000033 +:107760000000000000009068000000000000000021 +:10777000000000000000906A00000000000000000F +:10778000000000000000906C0000000000000000FD +:10779000000000000000906E0000000000000000EB +:1077A00000000000000090700000000000000000D9 +:1077B00000000000000090720000000000000000C7 +:1077C00000000000000090740000000000000000B5 +:1077D00000000000000090760000000000000000A3 +:1077E0000000000000009078000000000000000091 +:1077F000000000000000907A00000000000000007F +:10780000000000000000907C00000000000000006C +:10781000000000000000907E00000000000000005A +:107820000000000000009080000000000000000048 +:107830000000000000009082000000000000000036 +:107840000000000000009084000000000000000024 +:107850000000000000009086000000000000000012 +:107860000000000000009088000000000000000000 +:10787000000000000000908A0000000000000000EE +:10788000000000000000908C0000000000000000DC +:10789000000000000000908E0000000000000000CA +:1078A00000000000000090900000000000000000B8 +:1078B00000000000000090920000000000000000A6 +:1078C0000000000000009094000000000000000094 +:1078D0000000000000009096000000000000000082 +:1078E0000000000000009098000000000000000070 +:1078F000000000000000909A00000000000000005E +:10790000000000000000909C00000000000000004B +:10791000000000000000909E000000000000000039 +:1079200000000000000090A0000000000000000027 +:1079300000000000000090A2000000000000000015 +:1079400000000000000090A4000000000000000003 +:1079500000000000000090A60000000000000000F1 +:1079600000000000000090A80000000000000000DF +:1079700000000000000090AA0000000000000000CD +:1079800000000000000090AC0000000000000000BB +:1079900000000000000090AE0000000000000000A9 +:1079A00000000000000090B0000000000000000097 +:1079B00000000000000090B2000000000000000085 +:1079C00000000000000090B4000000000000000073 +:1079D00000000000000090B6000000000000000061 +:1079E00000000000000090B800000000000000004F +:1079F00000000000000090BA00000000000000003D +:107A000000000000000090BC00000000000000002A +:107A100000000000000090BE000000000000000018 +:107A200000000000000090C0000000000000000006 +:107A300000000000000090C20000000000000000F4 +:107A400000000000000090C40000000000000000E2 +:107A500000000000000090C60000000000000000D0 +:107A600000000000000090C80000000000000000BE +:107A700000000000000090CA0000000000000000AC +:107A800000000000000090CC00000000000000009A +:107A900000000000000090CE000000000000000088 +:107AA00000000000000090D0000000000000000076 +:107AB00000000000000090D2000000000000000064 +:107AC00000000000000090D4000000000000000052 +:107AD00000000000000090D6000000000000000040 +:107AE00000000000000090D800000000000000002E +:107AF00000000000000090DA00000000000000001C +:107B000000000000000090DC000000000000000009 +:107B100000000000000090DE0000000000000000F7 +:107B200000000000000090E00000000000000000E5 +:107B300000000000000090E20000000000000000D3 +:107B400000000000000090E40000000000000000C1 +:107B500000000000000090E60000000000000000AF +:107B600000000000000090E800000000000000009D +:107B700000000000000090EA00000000000000008B +:107B800000000000000090EC000000000000000079 +:107B900000000000000090EE000000000000000067 +:107BA00000000000000090F0000000000000000055 +:107BB00000000000000090F2000000000000000043 +:107BC00000000000000090F4000000000000000031 +:107BD00000000000000090F600000000000000001F +:107BE00000000000000090F800000000000000000D +:107BF00000000000000090FA0000000000000000FB +:107C000000000000000090FC0000000000000000E8 +:107C100000000000000090FE0000000000000000D6 +:107C200000000000000091000000000000000000C3 +:107C300000000000000091020000000000000000B1 +:107C4000000000000000910400000000000000009F +:107C5000000000000000910600000000000000008D +:107C6000000000000000910800000000000000007B +:107C7000000000000000910A000000000000000069 +:107C8000000000000000910C000000000000000057 +:107C9000000000000000910E000000000000000045 +:107CA0000000000000009110000000000000000033 +:107CB0000000000000009112000000000000000021 +:107CC000000000000000911400000000000000000F +:107CD00000000000000091160000000000000000FD +:107CE00000000000000091180000000000000000EB +:107CF000000000000000911A0000000000000000D9 +:107D0000000000000000911C0000000000000000C6 +:107D1000000000000000911E0000000000000000B4 +:107D200000000000000091200000000000000000A2 +:107D30000000000000009122000000000000000090 +:107D4000000000000000912400000000000000007E +:107D5000000000000000912600000000000000006C +:107D6000000000000000912800000000000000005A +:107D7000000000000000912A000000000000000048 +:107D8000000000000000912C000000000000000036 +:107D9000000000000000912E000000000000000024 +:107DA0000000000000009130000000000000000012 +:107DB0000000000000009132000000000000000000 +:107DC00000000000000091340000000000000000EE +:107DD00000000000000091360000000000000000DC +:107DE00000000000000091380000000000000000CA +:107DF000000000000000913A0000000000000000B8 +:107E0000000000000000913C0000000000000000A5 +:107E1000000000000000913E000000000000000093 +:107E20000000000000009140000000000000000081 +:107E3000000000000000914200000000000000006F +:107E4000000000000000914400000000000000005D +:107E5000000000000000914600000000000000004B +:107E60000000000000009148000000000000000039 +:107E7000000000000000914A000000000000000027 +:107E8000000000000000914C000000000000000015 +:107E9000000000000000914E000000000000000003 +:107EA00000000000000091500000000000000000F1 +:107EB00000000000000091520000000000000000DF +:107EC00000000000000091540000000000000000CD +:107ED00000000000000091560000000000000000BB +:107EE00000000000000091580000000000000000A9 +:107EF000000000000000915A000000000000000097 +:107F0000000000000000915C000000000000000084 +:107F1000000000000000915E000000000000000072 +:107F20000000000000009160000000000000000060 +:107F3000000000000000916200000000000000004E +:107F4000000000000000916400000000000000003C +:107F5000000000000000916600000000000000002A +:107F60000000000000009168000000000000000018 +:107F7000000000000000916A000000000000000006 +:107F8000000000000000916C0000000000000000F4 +:107F9000000000000000916E0000000000000000E2 +:107FA00000000000000091700000000000000000D0 +:107FB00000000000000091720000000000000000BE +:107FC00000000000000091740000000000000000AC +:107FD000000000000000917600000000000000009A +:107FE0000000000000009178000000000000000088 +:107FF000000000000000917A000000000000000076 +:10800000000000000000917C000000000000000063 +:10801000000000000000917E000000000000000051 +:10802000000000000000918000000000000000003F +:10803000000000000000918200000000000000002D +:10804000000000000000918400000000000000001B +:108050000000000000009186000000000000000009 +:1080600000000000000091880000000000000000F7 +:10807000000000000000918A0000000000000000E5 +:10808000000000000000918C0000000000000000D3 +:10809000000000000000918E0000000000000000C1 +:1080A00000000000000091900000000000000000AF +:1080B000000000000000919200000000000000009D +:1080C000000000000000919400000000000000008B +:1080D0000000000000009196000000000000000079 +:1080E0000000000000009198000000000000000067 +:1080F000000000000000919A000000000000000055 +:10810000000000000000919C000000000000000042 +:10811000000000000000919E000000000000000030 +:1081200000000000000091A000000000000000001E +:1081300000000000000091A200000000000000000C +:1081400000000000000091A40000000000000000FA +:1081500000000000000091A60000000000000000E8 +:1081600000000000000091A80000000000000000D6 +:1081700000000000000091AA0000000000000000C4 +:1081800000000000000091AC0000000000000000B2 +:1081900000000000000091AE0000000000000000A0 +:1081A00000000000000091B000000000000000008E +:1081B00000000000000091B200000000000000007C +:1081C00000000000000091B400000000000000006A +:1081D00000000000000091B6000000000000000058 +:1081E00000000000000091B8000000000000000046 +:1081F00000000000000091BA000000000000000034 +:1082000000000000000091BC000000000000000021 +:1082100000000000000091BE00000000000000000F +:1082200000000000000091C00000000000000000FD +:1082300000000000000091C20000000000000000EB +:1082400000000000000091C40000000000000000D9 +:1082500000000000000091C60000000000000000C7 +:1082600000000000000091C80000000000000000B5 +:1082700000000000000091CA0000000000000000A3 +:1082800000000000000091CC000000000000000091 +:1082900000000000000091CE00000000000000007F +:1082A00000000000000091D000000000000000006D +:1082B00000000000000091D200000000000000005B +:1082C00000000000000091D4000000000000000049 +:1082D00000000000000091D6000000000000000037 +:1082E00000000000000091D8000000000000000025 +:1082F00000000000000091DA000000000000000013 +:1083000000000000000091DC000000000000000000 +:1083100000000000000091DE0000000000000000EE +:1083200000000000000091E00000000000000000DC +:1083300000000000000091E20000000000000000CA +:1083400000000000000091E40000000000000000B8 +:1083500000000000000091E60000000000000000A6 +:1083600000000000000091E8000000000000000094 +:1083700000000000000091EA000000000000000082 +:1083800000000000000091EC000000000000000070 +:1083900000000000000091EE00000000000000005E +:1083A00000000000000091F000000000000000004C +:1083B00000000000000091F200000000000000003A +:1083C00000000000000091F4000000000000000028 +:1083D00000000000000091F6000000000000000016 +:1083E00000000000000091F8000000000000000004 +:1083F00000000000000091FA0000000000000000F2 +:1084000000000000000091FC0000000000000000DF +:1084100000000000000091FEFFFFFFFFFFFFFFFFD5 +:10842000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:10843000FFFFFFFFFFFFFFFF0000FFFF0000000046 +:10844000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:10845000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C +:108460000000FFFF000000000000039B000015005B +:1084700000000001000000020000000300000000F6 +:1084800000000004000000010000000000000001E6 +:1084900000000004000000000000000100000003D4 +:1084A00000000000000000010000000400000000C7 +:1084B00000000001000000030000000000000001B7 +:1084C00000000004000000000000000400000003A1 +:1084D000000000000000000000007FFF000003FF1C +:1084E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:1084F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:108500000000000300BEBC200000000000000005C9 +:108510000000000300BEBC200000000000000005B9 +:108520000000000300BEBC200000000000000005A9 +:108530000000000300BEBC20000000000000000599 +:108540000000000300BEBC20000000000000000589 +:108550000000000300BEBC20000000000000000579 +:108560000000000300BEBC20000000000000000569 +:108570000000000300BEBC20000000000000000559 +:108580000000000D0000000C0000000000000010C2 +:108590000000000F000000000000000000000000CC +:1085A0000215002002150020000000300810000015 +:1085B0000000003600000030000000310000000321 +:1085C00000000000000000010000000300000001A6 +:1085D0000000000200000040000000400000000415 +:1085E000000000200000000F0000001B00008000C1 +:1085F000000103C00001878000020B4000028F00D1 +:10860000000312C00003968000041A4000049E007C +:10861000000521C00005A580000629400006AD0028 +:10862000000730C00007B480000838400008BC00D4 +:1086300000093FC00009C380000A4740000ACB0080 +:10864000000B4EC0000BD280000C5640000CDA002C +:10865000000D5DC00000618000000001000000010D +:108660000000000100000001000000010000000106 +:1086700000000001000000010000000100000001F6 +:1086800000000001000000010000000100000001E6 +:108690000000000100000001000000010000050EC4 +:1086A000000004FD000005010000051E0000FFFFA2 +:1086B0000000FFFF0000FFFF0000FFFF000000467A +:1086C0000000000C00000000000000000000001C82 +:1086D000000000F4000000010000000000000000A5 +:1086E00000000000000000010000000107FFFFFF84 +:1086F0000000007F07FFFFFF0000003F0000FFFFBA +:108700000000FFFF0000FFFF0000FFFF00007FF8F8 +:1087100000007FF80000FF00000000000000FF00E4 +:10872000000000000000FF00000000000000FF004B +:10873000000000000000FF00000000000000FF003B +:10874000000000000000FF00000000000000FF002B +:10875000000000000000FF00000000000000FF001B +:10876000000000000000FF00000000000000FF000B +:10877000000000000000FF00000000000000FF00FB +:10878000000000000000FF00000000000000FF00EB +:10879000000000000000FF00000000000000FF00DB +:1087A000000000000000FF00000000000000FF00CB +:1087B000000000000000FF00000000000000FF00BB +:1087C000000000000000FF00000000000000FF00AB +:1087D000000000000000FF00000000000000FF009B +:1087E000000000000000FF00000000000000FF008B +:1087F000000000000000FF00000000000000FF007B +:10880000000000000000FF00000000000000FF006A +:10881000000000000000FF00000000000000FF005A +:10882000000000000000FF00000000000000FF004A +:10883000000000000000FF00000000000000FF003A +:10884000000000000000FF00000000000000FF002A +:10885000000000000000FF00000000000000FF001A +:10886000000000000000FF00000000000000FF000A +:10887000000000000000FF00000000000000FF00FA +:10888000000000000000FF00000000000000FF00EA +:10889000000000000000FF00000000000000FF00DA +:1088A000000000000000FF00000000000000FF00CA +:1088B000000000000000FF00000000000000FF00BA +:1088C000000000000000FF00000000000000FF00AA +:1088D000000000000000FF00000000000000FF009A +:1088E000000000000000FF00000000000000FF008A +:1088F000000000000000FF00000000000000FF007A +:10890000000000000000FF00000000000000FF0069 +:10891000000000000000FF00000000000000FF0059 +:10892000000000000000FF00000000000000FF0049 +:10893000000000000000FF00000000000000FF0039 +:10894000000000000000FF00000000000000FF0029 +:1089500000000000FFFFFFFFFFFFFFFFFFFFFFFF23 +:10896000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:10897000FFFFFFFF000019000000000000000001E1 +:1089800000000000000000000000000000000218CD +:1089900000001500000000010000000200000003BC +:1089A00000000000000000040000000100000000C2 +:1089B00000000001000000040000000000000001B1 +:1089C000000000030000000000000001000000049F +:1089D0000000000000000001000000030000000093 +:1089E000000000010000000400000000000000047E +:1089F00000000003000000000000000000007FFFF6 +:108A0000000003FF00000000039387000000000047 +:108A10000000000000000000039387000000000039 +:108A2000000000000000000F000000070000000030 +:108A30000000000E0000000E00000000000000001A +:108A40000000000003150020031500200100003085 +:108A50000810000000000036000000300000003167 +:108A600000000002000000050000000200000002FB +:108A700000000000000000050000000300000001ED +:108A8000000000040000000100000002000000409F +:108A90000000004000000004000000200000000270 +:108AA00000000020000010000000208000003100C5 +:108AB000000041800000520000006280000073004E +:108AC00000008380000094000000A4800000B50036 +:108AD0000000C5800000D6000000E6800000F7001E +:108AE0000001078000011800000128800001390002 +:108AF0000001498000015A0000016A8000017B00EA +:108B000000018B8000019C000001AC800001BD00D1 +:108B10000001CD800001DE000001EE800001FF00B9 +:108B200000000F80000000010000000100000001B3 +:108B30000000000100000001000000010000000131 +:108B40000000000100000001000000010000000121 +:108B50000000000100000001000000010000000111 +:108B60000000000100000001000000010000000101 +:108B700000000001000012140000120000001204A6 +:108B80000000FFFF0000FFFF0000FFFF0000FFFFED +:108B9000000000200000003800000000000000007D +:108BA0000000002300000024000000250000002633 +:108BB00000000027000000390000003A0000002BF0 +:108BC0000000002C00000000000000EC000000008D +:108BD000000000290000002A000000010000000140 +:108BE0000000000100000001000000000000000083 +:108BF000000000000000000107FFFFFF0000007FF1 +:108C000007FFFFFF0000003F0000FFFF0000FFFF25 +:108C10000000FFFF0000FFFF00007FF800007FF86A +:108C20000000000000000001CCCC0201CCCCCCCC78 +:108C3000CCCC0201CCCCCCCCCCCC0201CCCCCCCC9E +:108C4000CCCC0201CCCCCCCCCCCC0201CCCCCCCC8E +:108C5000CCCC0201CCCCCCCCCCCC0201CCCCCCCC7E +:108C6000CCCC0201CCCCCCCCFFFFFFFFFFFFFFFF41 +:108C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +:108C8000FFFFFFFFFFFFFFFF0000000000010001EA +:108C900000110807CCCCCCC910000000000028ADA2 +:108CA0000000291800002919000000000000000041 +:108CB00000000005000000067058103C0000000095 +:108CC0000000FF00000000000000FF0000000000A6 +:108CD0000000FF00000000000000FF000000000096 +:108CE0000000FF00000000000000FF000000000086 +:108CF0000000FF00000000000000FF000000000076 +:108D00000000FF00000000000000FF000000000065 +:108D10000000FF00000000000000FF000000000055 +:108D20000000FF00000000000000FF000000000045 +:108D30000000FF00000000000000FF000000000035 +:108D40000000FF00000000000000FF000000000025 +:108D50000000FF00000000000000FF000000000015 +:108D60000000FF00000000000000FF000000000005 +:108D70000000FF00000000000000FF0000000000F5 +:108D80000000FF00000000000000FF0000000000E5 +:108D90000000FF00000000000000FF0000000000D5 +:108DA0000000FF00000000000000FF0000000000C5 +:108DB0000000FF00000000000000FF0000000000B5 +:108DC0000000FF00000000000000FF0000000000A5 +:108DD0000000FF00000000000000FF000000000095 +:108DE0000000FF00000000000000FF000000000085 +:108DF0000000FF00000000000000FF000000000075 +:108E00000000FF00000000000000FF000000000064 +:108E10000000FF00000000000000FF000000000054 +:108E20000000FF00000000000000FF000000000044 +:108E30000000FF00000000000000FF000000000034 +:108E40000000FF00000000000000FF000000000024 +:108E50000000FF00000000000000FF000000000014 +:108E60000000FF00000000000000FF000000000004 +:108E70000000FF00000000000000FF0000000000F4 +:108E80000000FF00000000000000FF0000000000E4 +:108E90000000FF00000000000000FF0000000000D4 +:108EA0000000FF00000000000000FF0000000000C4 +:108EB0000000FF00000000000000FF0000000000B4 +:108EC0000000FF00000000000000FF0000000000A4 +:108ED0000000FF00000000000000FF000000000094 +:108EE0000000FF00000000000000FF000000000084 +:108EF0000000FF00000000000000FF000000000074 +:108F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:108F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:108F20000000FFFF00000000FFFFFFFFFFFFFFFF4B +:108F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:108F4000FFFFFFFFFFFFFFFF0000FFFF000000002B +:108F5000032313031303231303030323A0B090433A +:108F60000200020006040604032313031303231361 +:108F700003030323A0B0904313131313131313130A +:108F800013131313A0B0904303010200000000006C +:108F9000000006290000150000000001000000028A +:108FA00000000003000000000000000400000001B9 +:108FB00000000000000000010000000400000000AC +:108FC000000000010000000300000000000000019C +:108FD0000000000400000000000000010000000389 +:108FE000000000000000000100000004000000007C +:108FF000000000040000000300000000000000006A +:1090000000007FFF000003FF002625A000000000F5 +:10901000002625A000000000002625A0000000007A +:10902000002625A000000000000E0000011600D65A +:10903000002625A000000000002625A0000000005A +:10904000002625A000000000002625A0000000004A +:1090500000720000012300F30000FFFF0000000089 +:109060000000FFFF000000000000FFFF0000000004 +:109070000000FFFF000000000000FFFF00000000F4 +:109080000000FFFF000000000000000000000000E2 +:109090000000FFFF000000000000FFFF00000000D4 +:1090A0000000FFFF000000000000FFFF00000000C4 +:1090B0000000FFFF000000000000FFFF00000000B4 +:1090C0000000FFFF000000000000000000000000A2 +:1090D0000000FFFF000000000000FFFF0000000094 +:1090E0000000FFFF000000000000FFFF0000000084 +:1090F0000000FFFF000000000000FFFF0000000074 +:109100000000FFFF00000000000000000000000061 +:109110000000FFFF000000000000FFFF0000000053 +:109120000000FFFF000000000000FFFF0000000043 +:109130000000FFFF000000000000FFFF0000000033 +:109140000000FFFF00000000000000000000000021 +:109150000000FFFF000000000000FFFF0000000013 +:109160000000FFFF000000000000FFFF0000000003 +:109170000000FFFF000000000000FFFF00000000F3 +:109180000000FFFF000000000000000000000000E1 +:109190000000FFFF000000000000FFFF00000000D3 +:1091A0000000FFFF000000000000FFFF00000000C3 +:1091B0000000FFFF000000000000FFFF00000000B3 +:1091C0000000FFFF000000000000000000000000A1 +:1091D0000000FFFF000000000000FFFF0000000093 +:1091E0000000FFFF000000000000FFFF0000000083 +:1091F0000000FFFF000000000000FFFF0000000073 +:109200000000FFFF00000000000000000000000060 +:109210000000FFFF000000000000FFFF0000000052 +:109220000000FFFF000000000000FFFF0000000042 +:109230000000FFFF000000000000FFFF0000000032 +:109240000000FFFF00000000000000000000000020 +:109250000000FFFF00000000555400005555555513 +:1092600000005555F0000000555400005555555567 +:1092700000005555F0000000000000000001000053 +:109280000000501400000000FFF55FFF0000FFFF2A +:10929000F00003E0000000000000A0000000040057 +:1092A00000000000000000000000000000001000AE +:1092B000000000000000000000000000000040006E +:1092C000000000000000000000000000000100009D +:1092D000FF5C0000FFF55FFF0000FFFFF00003E010 +:1092E000000000000000A0000000080000000000D6 +:1092F000000000000000000000002000000000004E +:1093000000000000000000000000800000000000DD +:10931000000000000000000000020000000000004B +:109320001F8B080000000000000BFB51CFC0F003B2 +:1093300009AB48A3F2EFF0A1F2D17181007E79422E +:1093400098858132FDF93C0C0CE540DCCD832A6E1A +:10935000C604A1ED3919189EB333307003E973AC1C +:1093600008F978A8BD070C10621E7A0C0CADDA1053 +:10937000F64E6DCADC358A8706E6B445E5FFB48251 +:10938000D0ED36109A0B4DFE17547EB93984E6B6EF +:10939000C56EEE0A73E2EC7FE28CCACF72C6AF3EB6 +:1093A000C0034203009EF27A77B803000000000079 +:1093B00000000000000000001F8B080000000000FB +:1093C000000BCD7D0D7814C79168CFEEECECEC9FCF +:1093D0003492566225048C90802591C902020B4775 +:1093E0009891F8B17C0F5F168C7DB28FF8161B6CCC +:1093F000F97FE33831EFEE6C0DFA43089016836D78 +:10940000C071B2E09FC35CFC22278EE3BCFCBC951C +:109410008D09BEE4BDC8C4E7E03BFB22E39F248E78 +:10942000EDD3913838F7C87155D53DBB33AB1F84A8 +:109430002F4E4EF99CA6677ABAABABAAABAAABAAE1 +:109440007BBD6A119B3D83B1B3F8B78CB107DD8C4E +:10945000B1D25CA96FFE9BAF0C8719FBC094596F0A +:109460001D636653F2EFB06EB67BB50E281F08DCA5 +:10947000F3956178BE5956356F0CBE61C90BE31781 +:1094800030B6B58DB18C97EA9FC2BACA9831509B5D +:109490001BC72A4B988BB145D8AE527B3BC0E8EF37 +:1094A0002C8CED65016642BF1F682CDD5B050F5FEC +:1094B0004D34B232C6DCBC0994AB33DF82F791E5A0 +:1094C0006CC4BB24D79F5B53584615FD50C3F5852C +:1094D00089E0E871AD72F3AB1BD2476CED6B582895 +:1094E000FCF627E11F3293110EE6DEC118C251C30C +:1094F000D2EEAAF1FB39DD96481F9985F8FACB42E6 +:109500009CEF78ED2CBC74B4A95476B56954BA6B51 +:109510009891AEA5F9195FC73268D2B8BD35330F3F +:109520000624842EC118E03BF052F541C4C7C54C57 +:1095300022BCF5D67C5D35C6C0AB55B25A1B3E6623 +:10954000E2B44CEA07269A7E14FA9161DC83F0BDFE +:10955000AC8D1E0FF16F8DB7FA238EE7659717C696 +:109560004350CE656CA816F19A86368CB9A2697301 +:1095700018EB51681F85C73A6F7F2EFCA9952E07FF +:109580007DE5A0DF5157C2C5D45F96FE797CC570DA +:10959000FEC0D72CC2A232CCCFC3FCB15E98DAADEC +:1095A000526213CE4F3FF2974627E0E794C1467AC6 +:1095B000A19D279C60C83FD67797966E243CC941F1 +:1095C00057DA2B5149F83C55C9F9C31B7699DE7916 +:1095D00063E0A552A14560E1655CB880FEC8E7F490 +:1095E0000A70D2F8A14CFDFB63B00E60BC101B26C4 +:1095F00026296440906AC68A982EF145119310CFAF +:109600008C3568C8BF61DF1FBADFF5D4AF64EC6288 +:109610006703E7D1AF0CFD567F0CFD9E035E1FFB79 +:1096200012F58BD4395B92EB771BAC3B46EB4FA327 +:10963000D20B2D697DD77239B3B52D42CF99FC4D30 +:10964000C305E305638ADE0B722D10CCB02A68F7E0 +:10965000AF8DEA08F00E721AF1990BE907E307A241 +:10966000EC7517D03D1073CA1FB55299143F76950B +:10967000CE9E9298685DC1CAAD5273DF8DD7EEE37E +:109680002E3B407E55797275393833C7D713CCCF0E +:10969000BD22C118F17D9CD9D7B7EC6209D40B1D4E +:1096A000C16B559C3F3B73F6AC7BB14DCE07E3F5E8 +:1096B00063E1E5355645F2C8AA7BB4EECF490550C3 +:1096C00046361AC336787E86FFC0751CB9C5189E0B +:1096D000041DDC72BC6503D0197822F628F0DDAEDB +:1096E000C035ECF55AD473D764904FBA4BCBAABCB3 +:1096F000A88F583BD75B6A90A98B737C3A587A65E0 +:1097000004E55A57F995110672A3CB138FC4A17EB5 +:10971000ACF46903FBED3E53C8504F76476616E242 +:10972000BCBACF544F498E31BF00E3F2C28FF0551F +:10973000717E63D11CBCDD11978AF09CAAE572672B +:1097400057E0FB861BEA8A2E27B17F2508E3C2F883 +:10975000CD7503C606E06325114C78B5D1FD58E3FD +:10976000C09F7416E53EB6B1D69DE4783F261CA393 +:10977000EB096326CA558DC57AC768EF510BCCC07B +:109780003C94BBD9E71A8E5BF3A30B48EE637B5D79 +:10979000C5A12503D7558EFFD30E7A33CD95EB7730 +:1097A000668E7EA0DF7AA43A5CC26A12D76D3E5EF6 +:1097B000BB15D63A407AC86841FC754AC50BD0AE95 +:1097C000198FDFE548CFBFB9015EC05D06F9CB1B3D +:1097D0005965229E3BC1B0292151B163489A47E5A2 +:1097E000BFB9F1BD26BF63E7BF7912D81388CC0B90 +:1097F000D98538FF8E20A7FB78E375C1FA6273C65E +:109800007FEF51628938E9A3E409298CF39D47F081 +:10981000CB95474F54011CCB24AEA7E5B06222DCA8 +:109820004C93DF1DB6E149978D6512BCF7F8793F7F +:10983000F9FDCF979B96E3FB932CBE12CB9EAAC556 +:1098400042FFE5AD97200CBE647C382D7A689B639F +:109850005C4832A3402AE3FC8C7FFEDA18C0086A19 +:10986000F8D36E4DAEE7F47587719DBA592FF2604B +:10987000543E89701BF03F84BBA001EA36BCBA8D10 +:10988000AB8D6A98B7D6A48E7822C84FBCBDC5A749 +:109890006EA4C73C2C9DCF13F9F4687B86BD31CBF9 +:1098A000663FA29D3A065EDE72375D2F8D61A7B2DC +:1098B00060F1A4F080B602B663C1640FD20DB4CEDD +:1098C00008CEF34141EF07845EBA0FF512D4770B4F +:1098D0003DD4DFA653B9AF2D4AE5436D317ADFD9C8 +:1098E000564FE5CE3683CA5D6DCD546E6F8B533BBC +:1098F000A5BC5345BA3D583EB04F22BBFC75E3476B +:10990000F0C983A1815718D6CD57791D6439AB00B2 +:109910003A6F79D930812F1F2C1AB8CA05203CB173 +:10992000FB07E61180F7C15903AF48503F22FD30D5 +:10993000D389ED2FE0ED0F6EF9A56162FF3ED642AF +:10994000EBA972DD39F0C0E5E5D38807281F2C8527 +:10995000EF8293FFEEFBF81DEE4BAACE6F3C9F9C6F +:1099600032F87CA5C69700A53E95C37F62CBBFD2D7 +:109970007C49645D04D8D9F26F26CDFF02D13FE85F +:10998000A92B6C7AEA25C9C3C79F7F7E70BF2CE6DE +:10999000AB682306483CB65A4A3C29413F05AD43D3 +:1099A0008617481BA87CD69474EC0F98A2FCDC7C2C +:1099B00054818D4B73ED95BA189B098FFE2F2A9F0A +:1099C00045B9E7C5CD064339F37F9078D07E7B6DEE +:1099D00093CAD7B1A1A29CFD81786EED2BE417DC70 +:1099E00064FF3C8FCF178D6E6FED07AC76E3C2A995 +:1099F0009DC3CE9DE43C990C7602D8714F32CD3197 +:109A0000DF2F33CD314F5F90AFD7C9D24372717A18 +:109A1000DC9DD7EF1D79F5A95F75B17A58DA95B756 +:109A2000D8F40CFC1759EF77D4CBD6153BEAE1D527 +:109A3000158EBAD6E0B48F2A367EC2519F7EE702D9 +:109A400047DDA35DE4A817D43539FA2B5EF1678EA4 +:109A5000F7C1DAB58EF71F15DFBBF3E6DF93579F2B +:109A60006C3F2542CE59CFCBAE5E9C20BB6E751DA0 +:109A7000977F72FCD259F0CF5FDE376B412F1BAB63 +:109A80009F2D449FA8DB08BB48DE72F9ED3225B25A +:109A9000B3EF97E26B56A21F6229D8670CED7FA740 +:109AA0007C67F6BA7B74BDC6C5F5235BCDE7B3EC26 +:109AB000CC3215F9CC1F72C5D3C0477E4F5A2BAE9E +:109AC000CDCDA74CD8A716FCCBCEFCD88DEBA543AB +:109AD000D30FE23EE4FEABFF2C726D7034FC56FFF8 +:109AE000DB83AE66DCD7E7EBE1EDF2806A1FC76A85 +:109AF0007F2EFCCED293E7E98F893317D4EFFA8C0F +:109B00008BF64D3BD0FF007AA257F81F7AD0FF00AA +:109B1000F56ED0375802A027D0BE397D11D3B17D64 +:109B20004178D840FDD1D27E696314E65F103122BE +:109B300011A83FB9AC66CB8A6968F20E13FE76D7DE +:109B4000AF2D6413F859423197631F14883AF7ED2B +:109B50003EBDD851F7462A26DC37BD2DD67101EC23 +:109B60002F63B5587239E02E7C3772BDCDBE6A7650 +:109B7000B9B95DEF5E93447BA74FE2F2DD7A7FC017 +:109B8000E5A2F7C7C19CC6FE969DE97771FAF27D02 +:109B90006630D46466D05F22B1E42C6D341D839EA0 +:109BA0000CF1CB9F1A0F1D45C311B47BD368845EA3 +:109BB0000C722408F61FFC532E596F5E07CF3B60D2 +:109BC0005FE08EA1FD1D7C1D9F7B847DE477253A9F +:109BD0005CDCCF2125C8EF14A7F24F3D1FB77BFEF9 +:109BE0004806F7119F566207D968BA3DE5E27EC381 +:109BF000E62CDD3E43FB788B6EBD414E3758356316 +:109C0000D2ED4617D723BD729AD6E1B233852EFA2C +:109C1000BEDE45FA6D4770C1B66AFCFE253703F318 +:109C200090ED9033D4EE8F8D877CB84221800BF776 +:109C3000A7FFC8E10A7986B43F055CE3F25B71CB0C +:109C4000B9F8ED4594EBF9FCD661D13D106FC175C3 +:109C50009A9BF74CF23F221FBA6A91DE5C7EEF14AA +:109C60007275A73CF447A54B565EABA96B504EB43A +:109C70000615929337BBCDA309941301893D0AF3CE +:109C800076A31E0479BEE93E4F0CF9B0F51FDDF551 +:109C90006E1DE071FBE8FB7C385B65605130055A56 +:109CA000613F89F86269CF4876BF3373B49FFA7712 +:109CB0002EE73EE6D49E2B0A336C7C3CBCD3764C1C +:109CC0009367E5FCD4F9EF6F76B324E9397540A1C9 +:109CD00079FD6DCAD73B1FE7377B450AE81676AB9F +:109CE0007CDE62DF77F3A11734D986A7D63D9ED7F5 +:109CF000BD63C09DC597F51DBABF8B477F3FDE771B +:109D000080BF15088FA70E588DF09C287703FD03A0 +:109D1000873664C0D2023ECAF0FDA9E83F073FACD7 +:109D20006D013F9B3706BC9AEB75F4D39E0BDE7337 +:109D3000E9E3537BBABAD1AFF54B4F6C3AFA795A93 +:109D400077CCA1F1AE15769085F74DF775958D1509 +:109D500087C8E2DDBD6315C2FD0133A3EEF9549F50 +:109D6000DD0ACFD78CC32FE7E28FA5EE3F127FC06D +:109D70007C913F5ADC5C0EB39E52E2FBF3E60FEBA4 +:109D8000BBF3E40FE087F56E280D397EE555615C85 +:109D9000EF2C8676A5C51F56BFA3F842D0E9A3C213 +:109DA000792EBE5037BBF537173256251BA4477B9B +:109DB000B47693E88BBC8AFE89D47CF22782A225F4 +:109DC0003F23FC65509EAA9A4172DE0F9B56DC77BA +:109DD00005EB9CF24BA975CAAF488B91B1FAEDD552 +:109DE000715C85C645CF098E2B0759C687F311FED6 +:109DF0006A644BB4A3BDEC9F9BABF97731FC6EBC9E +:109E0000F9C88CFBB3D1AD84F6B5974D1C9FC91F23 +:109E100027B22E4EF19FC9B66741597FDB86F7F115 +:109E2000BF93D9DB36BB7E1FCAE64539FC1B896B65 +:109E3000C9BF1762AE18DAC91D91A326BEEDC6FFD1 +:109E400003FA6D657C7DB2CA62CE77289C17A19B10 +:109E500060B1897EFE80A18EB835D44F22FE23DA10 +:109E60009D8BEE7E21F7AF90E3FF0BE594B772A0D8 +:109E700005E9AAB06012FBCBE255817D05F61B5DBA +:109E8000C7F709175C6FA25FC8335D9B8F53A98228 +:109E9000FDC19A0BECFDF3FD6B4F5B9ABDE1C9C5AB +:109EA000A5543DCE4BC16F2CCAE5564F2DB7DB54A0 +:109EB0007580695006524F66309E91E33793ADBB73 +:109EC00000E9C9F9EB4128F9FE294DE378227E0724 +:109ED000DF65F92A3A39B9D8D7A64B6FD8E204051D +:109EE000E3C47F7FE8961C74EB683397BE69FBCEB2 +:109EF0002DC7087E3908CF6D7C6FBD9FEC386FBAD7 +:109F00005DE705D74F11AED21C5C77A1FC03384E3C +:109F1000DF3324AF85F2B2CC2BF24CC09F4BE6ED81 +:109F20004EDFC3FDCAC7DB3E74F8133D7219CDEF97 +:109F3000B2D52FCACB6DE35C26FC8C8C0DC96B426D +:109F400076FC89FD6370E4B9B31857AC73933D3B5D +:109F50001EBED74696A7E5925CFD789D9BECA2E3DA +:109F6000B01F42B970BCAE2A6D8EE1AFC9F7A7AF82 +:109F70008DACA27E4EDF3D24C7691E2AE109E7A908 +:109F8000037C9735BF281BC173C3FDEBBC75B84F6D +:109F9000F473FAEE04C37E95CC8D0CFB5336260C7D +:109FA000A396CB3D845339564276DEB233B7AB6BC2 +:109FB0002FC8F597A553DE3CFB22DCFEEB13F3EC38 +:109FC0008BE8939A678198674ECF0B3C37B826C4CD +:109FD000F3BFB41969790CBD6895D72C75C5119E6E +:109FE0006B3CC3A563D9A3F970FCD5E6C6B46C8FEE +:109FF0009B7D44387ED60078007AFC4C1E097DA4F7 +:10A0000071010F512BAF02F0777A26339A71FF5B03 +:10A01000CC089FB0F24EA11EB4E29CB2FAE7EC6FFE +:10A0200017D8D6A706EF1DF6B2D03BB9F8C329FB67 +:10A03000BE2BAB1F51BF413B77B89BFBE9C37EDA18 +:10A040003FB8C3F2DBC379F051FC6EBA44F2B243BD +:10A05000C86FF83B82F103B92EF630E2EB1A10A874 +:10A06000384FB007AE9169DD1AC69630C5B192E897 +:10A0700067072D433ACC5316A5F8CB787EFBAD6D20 +:10A08000C353ECF8B5F0B7D523FCBE67960FA33CDD +:10A09000975DD1CF519C6292FEFFDE6952CB44F0B6 +:10A0A0007F3107FF1705FCE6B575A3E1EF9D3B7B0C +:10A0B00042F87BC681BF27077F14F540A7ABF6BCEB +:10A0C000E0B7E0566B18D1D57ABF4DCC2B7F3EDB85 +:10A0D0006629E457EEBC20F630C627EF15F3433F60 +:10A0E00032DA0F30CF7B659B5D2B6BDC8EEFA9BA2C +:10A0F000DF68C7B826CC1BF78FE3C1E753DF9E624A +:10A100005FC76999EFE73BF111EA751167F6E89CC3 +:10A110000FBBE4441AC7F35476D3FECA134ED1786A +:10A12000FE28CCE75318E767042F9877E95A803761 +:10A13000003856EBB03EF404D6A11DD36CF52CBE0E +:10A140004BCD48D066D77755759FF0A2BE0F337DB3 +:10A150000EF25BE62A92779E30E8698047913306DB +:10A16000F20FB07F15FA2F1575C040BDCF6AA1AEB2 +:10A17000C338E1346B443CFCDECDE310B829B4CDE8 +:10A18000FF41D9E5D80F58F35F9BE777B5CA9F8C9D +:10A19000439F9F5CE675D0E728D2A7D4419FA3F2E6 +:10A1A000A2D1F4F9C9657338FF358F6D07AF55DF5C +:10A1B00098222FB4C95791C741A482F979847DD4DC +:10A1C0003F6D958132A57A7D2C86C2E5C5198997A8 +:10A1D00070BC54E5A14617B42B5F1F7B610B94DD67 +:10A1E0001EEEF759E9AEF49D84F177AD985988FEDB +:10A1F000D60F85DECD1FFFD1368015F4CD97DA540A +:10A2000046FB99D7E64C186FED6903D6B1D9033DEB +:10A210007B6492A73DFADAB597027EBAC2350BDCB1 +:10A22000244DD65C7D23DA93B5FA02B4977F254B93 +:10A23000D67AFD956CE36B6B3F2A1B0386568BA980 +:10A240002F0319F4BF166B2C96D1B95C936DF8806F +:10A2500079FF1ABFAFA88DB5630E5479B373DEBB17 +:10A2600056F0FCA23B2E9D7DD06DD30B9778381F06 +:10A27000B0B0D8F7CAB1E85876B64587C7002FB551 +:10A2800018EB6329CA8F29DF0BFBE979183FE4CF6C +:10A29000BF2DC7DD1E80A37C63CC83F01F17FE3665 +:10A2A00089A99D6528EFEAB403C8378FEDF70BBE87 +:10A2B000D10E20DF843CAEFC751DF28CC1377D9E33 +:10A2C00084E6C138685DC244537BF6DE0126FC3E5D +:10A2D000ADC49F263B8E7C3255E278A13F8C0F4760 +:10A2E000B99F7D9187D3BB20121B94E0BD3EF29DA8 +:10A2F000C1EBE07D772268A01C9B5D7E70B089F683 +:10A30000CF6C04E37DB3A7A5A9CE1AD59147E17D13 +:10A3100045AB39B81CE6A10BBB7E7A22BD05E9DA54 +:10A32000DDC6FDE11173D8C4B49F8A560E9705BFF0 +:10A33000A224288F626AE4FAD5682C4A15CF0C2A29 +:10A3400098C7D1C56218BF2B599D3631BF626ABD0F +:10A3500057C37E6757694D2837BA37B1D8169A0761 +:10A360007F5F02DB40CC4750D85046C139CA0976DE +:10A37000B98D5EFE48E256ECBFCB93588478F24725 +:10A38000B97DAF449204CFBD1EB0E3A10C34A40D3F +:10A3900084E7D1FBAE671B6C70AE1274506A999162 +:10A3A0000EE6F86CB748A449190B7C37D4623BBF62 +:10A3B000C893D868A05D5DCD1226CAA300F22723FA +:10A3C0007E5C89F4AB88C49EC57518A84D917F0E3C +:10A3D000D6DD140E875E8EDFDD7B9FD292E6747B26 +:10A3E0009961FE8B8BE5FEC2381FE311A4DBEF7190 +:10A3F00071A1BFA6E1B1CC4314EFF76A7204F4FC7B +:10A40000E707D874A81745DC4CD7709C74E67BB876 +:10A410007F073C211E7BF48399D7A0EE6D0930ACF9 +:10A420002B770E19981FA06D643103E092A39C0F47 +:10A4300028A708FBADE7F95B80BFCF22FCA115037D +:10A440009453286B1C7F3D72F26777A3FC3EE68E27 +:10A4500099CCB66E18AC1BDB3ECBA7833C70D833CF +:10A46000A6639D9D4B4FE6F6DD5CEF587E40585F3E +:10A47000B7235CB2C6D7D764FD4B8D4029DCC756E5 +:10A48000DC29F260853C9D2A505DC986251C630647 +:10A4900098681E785FB54E6FF7905C4D971F80F9F6 +:10A4A0007716BD5CCEE3B82B34DC2F4B468974F6AF +:10A4B0009393DF575B7044363AF32F0A56DBE26A18 +:10A4C000F05FA0CE59F7325BFBAA5C3F9A9507A1DB +:10A4D000C7627679B5DD37B097C7E95F6CC2BC84D7 +:10A4E000EDD2400B862095DD3F6C6AC6FD71682079 +:10A4F00082A169DFF69F503D301D7620382F7948C4 +:10A50000C57CD2673C3AF5EF6BC09829C89B5A9935 +:10A51000ECE89DF5A7347C3F38BC9BF8A4AF8EE7F0 +:10A520006D5AEDFB86DD0CD7732FB44727446F1DA2 +:10A53000B40FDAFA035E7589F788FFD373F9FBD39A +:10A54000B3B2F9AC2AD65D86CA8AA1DD4E31AED54A +:10A550008F777888F480D59FC2864DAC5B72D06BC4 +:10A5600024CC6791EFA3AE74BA8AB2A518E6A516FB +:10A57000403F19E847A94F1AD86EF0B59FABC3B654 +:10A58000F5DE17E5FD3343C467CF21FF8DF58D99C7 +:10A590006B711C614FC2930CDA59982F867209E4D3 +:10A5A000F611E2CF5A99FCA2416D80AF2D63727112 +:10A5B000C9C9B6D347024487AE5725C267E9F4F844 +:10A5C000862A94D32FBB19DA3F6693217930AE39AE +:10A5D0009DC5D0E62C9D99FC548CF09CBC10E56583 +:10A5E0009790D756BFA74B59CA6E8F1E7627FE0588 +:10A5F000E72195B52470DDDC7552D291DEA5EBB86C +:10A600009F6433404A7E10C345F9CFB49EA05DEAF3 +:10A610009129048F5CB2BE0CE545CA9839613EE6CB +:10A62000D63616ABB1D9D95BE5A48A72716BE50257 +:10A6300075ACEFBC112556034A3FD5AC4FD12688E7 +:10A64000A78DDF6F93DFDE6FD49DF877BB9EB5FAE1 +:10A65000CF8F97FB824768F3E63BCF38F9DE0D5783 +:10A6600046105FE129C67C5C77655E9689C35A080F +:10A67000078C27719D3ED2FD3F960781DE61AF3189 +:10A68000DF05F5FFE9F52EDF81F519C6E730B4F6F1 +:10A69000567BDFF2E7619D873197FE22C6BEB0F59B +:10A6A000BB1DA6C03FEAFB9D6D7AC59BB3D0FE8A59 +:10A6B00056A0BFA74CE1FAAB5CD1A90CC943E4F7A3 +:10A6C00029A88376763F946CD2739F1E753C6711E0 +:10A6D0002E1765FCB74E7A6CBA02FC56D1921AC49A +:10A6E000A5077297F458B727B117F330CD5295FCF0 +:10A6F000602BDD4192AFA722FA419ED7C9883F0B5C +:10A700002AB9DD9152847FE7B54B22A407D1AEF47C +:10A71000601E3123FBF2C3E1E509B4AB4FA17F0F0B +:10A72000F57BCDAA565CBF0069D20B72AC4849706C +:10A730007E9BC9926887607EEBD9C5C2FF88788FFF +:10A740000C97C9367FA712FDB3E4111D9FC72BDEFE +:10A75000B43F67C32D9D00DF550ACF7B6589FB247D +:10A7600073B1F06742FB5DAB2A3E7704E1BEC84F90 +:10A77000FEC322453BC0E569EDF2E7118E026D3E56 +:10A78000CAD335DD9FE890814EBB3011AF82B1CB8B +:10A79000BAA31D98F754E4E6746266CD72F4CB5800 +:10A7A000EF5776D710DD403E5CAAC0B846A7C1D0AF +:10A7B0005EC8FAD9317FA81AE1E2F20DE7B76C3131 +:10A7C0004FA1C6E7E5894DA40FE1FB3593FA1E7A48 +:10A7D000C87E8FBA2267575E85F41CEFFBC1D7E6AF +:10A7E00068461DCF87C5F5BE4BD8CFAE2D23EC4AAA +:10A7F000BB9FAA3EF3901DDFBB96587A6498A13C9C +:10A80000BD5D99CDE574E5B187EC76C0AEA5C3E436 +:10A810003FD522098EEFB9DA551BA1DEDFC8EDBCAA +:10A820007E91CFE6DAA0A77C684F35241EB6E749B3 +:10A83000690DEC15D4239A114311CFB685787B2D81 +:10A84000D2E3E0E3C1E1EA42CC374E29DCBEBF4BA4 +:10A85000E1F927563FDD6DB10AE4BFBEB67A2A7B27 +:10A860009522EE5F88F27D82B2247C00ED01EB3B05 +:10A87000EB7977FDDA47EDFB875E85E7B3DDE577BA +:10A88000B6DBDA507CC0D98EEF73EE2AE0FE6AABFD +:10A890009D776938AF9DCBE167CAC92580D76637F8 +:10A8A00014D603DCF6F55C67D07910591E3BEF72C5 +:10A8B0007351E37DC837ED5EBEBFDF5BDA42EBF07C +:10A8C00043C0D344F2B91BE48BDD0FA280BD8D7A67 +:10A8D0004411F2C71BD12B9C765E2C8AFECCC7FCA0 +:10A8E0008D0FF3F198754E2481F6AD4DAE3C3EA12F +:10A8F0005C09F9292F69A5BBB6F0A46D3E61AFE4F0 +:10A90000C0CF4EB14FED6DD3A844BA0FA35CCCCBF2 +:10A9100073B0CA1EA4FB2C9C573D95C72CBA083AAD +:10A92000F7D5B76BF6FDC018EFD54D41FB7B27FD82 +:10A93000FBEAEF553704C7F85ED01DDE6BCEF79CFF +:10A94000DE2197933FADF2D5BCF10B966C747C3F42 +:10A95000C67B7553ADFDBD13BE822577AA1B6AC7A2 +:10A96000F85EC007EF35E77B0E5FAFC4D7994F772E +:10A97000F2A137E2E4438B3E7E85CB7F368F9F8FFB +:10A98000525992CB6921B77B2CB92DE4EF56A132F5 +:10A99000BA5FBB21DD8EE5276E1A7816CA202A130E +:10A9A000807FFBDC67D298BFE2FFE477A3387FBFEC +:10A9B000924E935C66DDCB9F077DEA2F48C7502EF1 +:10A9C000CBDECE0E196451AF90BBCCDB4E72D96F8B +:10A9D000C96576CF72F4BF5BEF3F54EEA1F7201745 +:10A9E000CF203F2A11B602F79D411127B7E462102C +:10A9F00037A98B727259CDCAE52F587255F64EE6BB +:10AA00007B2197D5AC5C4E5A723DE85D34FEF72051 +:10AA10009789AFC75BA7ACD6298FBDFAB187EC7415 +:10AA2000CAAEFBD0D5648FF483B8930AA1F4A45ABC +:10AA3000781E3C2B5F6BDBBF0D79B9BECE7ED7781D +:10AA400025C98B1FC9711DE759D6A2FD08ED5E5FB0 +:10AA50002587D36AD725FABFDFC7E9BFF505777A1F +:10AA60004B55CEEF9B0FF70A2FCF2BBBDF27FCAA4E +:10AA700032FC2D16FB1BF87BA09149181F5AE015DC +:10AA80007E9A43870F1F2EE3C72BD01EB3EC20B650 +:10AA9000EE8A2BAE80E7297C4EF6C708C58B355071 +:10AAA000738910CA07667860BDF7CB236407F69FE9 +:10AAB000F16E413D6246998E7206F712742EB05EB9 +:10AAC00039E0AAA2734846C886BF3A31BED5CF56F0 +:10AAD0006984E8B206E98AFBB1281BC4FEFCB54CC8 +:10AAE000A7FD3E7CEFB1AD0BF7551B5F44FFE4299A +:10AAF0004DD191A5016EF313643FC3FAC0B9AE6B9B +:10AB00003C81F693565F4679309D212EBFACF19E75 +:10AB10005BA2907DDD374D799872E0D11F86F85D9C +:10AB20009A5888FADB1F1D61D723DE252BEF9A196F +:10AB3000A5A8C734ED00EACFB2AB7BBCE827502A0A +:10AB40002AE6E33EE856319F2CFE0E35317B9C54BD +:10AB50006ED94B712523B181E2A9A1984E79A6F453 +:10AB60008778023B0FFBDD20F8E466B7B101F9B747 +:10AB70000FE8A5433F7D57A912EDBF3436E0D3114E +:10AB80005F4606FD0EE652C0B78EFA0BE812E4F4FB +:10AB900041BB2F10D509AE76B14E2C38F2F178BFFB +:10ABA000E0A3BE254F3394037D8DC3AC2A84DF71AF +:10ABB0003955D030C2707D5BFD041A40EE607CB622 +:10ABC000325185E33DE68FDF85FC6BEDF3B27C2BE4 +:10ABD000F4A1070882740D5FBEDAE802F8BB84FFB7 +:10ABE000DC68E1F30E45B8FF40D6B87F0BD66DBBED +:10ABF000D706AFE5B7CCEE8F6A9DFBA3ED5A99233C +:10AC00002EB5BDF6FCF6473DC8BFD0BE3F78EA186A +:10AC1000E5D5E9AE18E6AFF5372C38A6A33DB1244B +:10AC20004C7E56ABFD7BA1A63D5E9B7F57AD84FE5F +:10AC30006CF8DC7E9EFBA81E99F9B07D2AE5F2D562 +:10AC4000D4E5C64F194DFEB9638FFFC844E3C3DF97 +:10AC5000BBB8DF203B55473A7C511D2BBFE74E4F19 +:10AC6000E26BF67EBC953C2F7F8C7DA8CF1E4F3DBE +:10AC7000DFFD677EA94A2CCECFD59DD4AEB5F59326 +:10AC8000117AEE50C8C820FDF3E775BEFBD3F1C6BC +:10AC90007D24E51CF7646EDC1FE3B827857D552510 +:10ACA0001BECAD3A927FC9FDC0D2FD4B57B1E7A175 +:10ACB000BE35C1F325542D19DF04F895457E83D5A3 +:10ACC0005FA7C1F31B4057107FCA8692862D2F9332 +:10ACD0005392884F1B94DFA08AFC865291DF30D5B7 +:10ACE000D267957EE7B96891DF309ACE63E7FF853A +:10ACF000E37C5DA1BF10F5889AB9AA11FD166A9888 +:10AD0000C5506E403B8A4BC3B6463B8C7684CEDB47 +:10AD1000AB358CCE572BB22111FD6B781CA854BCDF +:10AD2000F784B587518E2B6A620BF6C72A79BE4627 +:10AD30009978EFADE4EF7D35BCDE5BCED2B5186718 +:10AD40000AF378556FF9D01358F756F278955537BE +:10AD50009B18ED73CD794ABAA30A9FA71D71ABDE8C +:10AD60002A11273AF370649D8D0F7B7FFF8D082A8F +:10AD7000ADC7A7BA3B572CC9C51F7B3DE9C8587C56 +:10AD8000D285F147CFF8FCD165F9FBE581C8DA102F +:10AD9000E2314DF132C0998EF1847C3C76CDEDCE1E +:10ADA000E271CEC788C78E3C3C76E4E1D1AA5BF362 +:10ADB000E8288F39F0D791C5DF4207FE3A428F91DC +:10ADC0005DD19187470FF27309F13FF9BB3A749E49 +:10ADD00087D5155C6B8AF3C8FCFCA595B713E6E72D +:10ADE0001DBCEB12A687F82BCE701C8BBFA7237F50 +:10ADF000233E2A9DF9611EE4EB12F417C597A9A51D +:10AE000098A7182F1B243DECF4134D61B12174E178 +:10AE1000B17A8EA78251FEDB89FD457FA172BDBC50 +:10AE20004F4E5CA6C2FA0AC6070CF443FB5B9219AC +:10AE3000F42386E366E3FF0B93DF7AC45D24F44AD0 +:10AE4000990885D378267B9BE719C4F0BCF6752A50 +:10AE50005FA7A5EBCC46C407884D86DF95B50C915E +:10AE6000FEDD8E76E0A7A0F4C45BE2DC6EE0741732 +:10AE700076437BE0FB27D0DFD955524CFAF93A955F +:10AE8000EB59631D73E843D083D7A9363D180C0FE7 +:10AE900070F3769C752F0BFFF54873E216C4E7EE4E +:10AEA00072732FC56F417E79F17C5979AC9FE2BBFB +:10AEB000589F0EF5597563DE3FF1F5662349DF4B68 +:10AEC000B15736E2BA7C5D22FAEEAE018DCDCFB13C +:10AED0003BF4C1EED5E7AB6F87C95EEC0B9EECA9E6 +:10AEE000B6E9BBBEFA71F56DBB1D0FF97270F7794B +:10AEF000EB5B317E2A7FFC71F5EDBD6AA94D2FD643 +:10AF00005B7A7158453CE4C3D357FFF1E8C7475417 +:10AF10006E17829E7A04E11935EEC7A41FBF911BFC +:10AF2000F71B382ED3B83F3D7FFCFCFE2CBE5444AB +:10AF30009CE99AE6F877F1FB5F5732D35D887ECCC7 +:10AF4000EE1F6CD073796EAC66589CE7E3786511A0 +:10AF50001E873A5F7C4ED6DF7DBEF8B2FA1D3DCF2C +:10AF6000B4C3BEB6FAEF94845E5BC9F7EBFB195F1E +:10AF70009F1ADE070172ED7595DB1DDF56E33F5327 +:10AF8000691FCBF7ADBB82AE1790BD605DF9107E37 +:10AF9000EB1E022627D95ADBBAFB45F67BE36DC4CC +:10AFA0006B51C8F5A2F8AE08BF03B9FA0EF63B9E86 +:10AFB0005CED9440AE227C4B3E9A5CFD50F0C5F5B2 +:10AFC0006AE2431CBF634593BF06FAD9D67C2DC500 +:10AFD00067B270B7F23C91A29572D10AD467A99971 +:10AFE000B4BE8A2F95C93EDA06FB1EBBBFCECAAFE0 +:10AFF000BB5E35241FF25BEBE4F25B27DB2E6B6F4D +:10B0000014BBD21D30EE7454E618FF8F27482F94DE +:10B01000B5F078CCADB251E4B3D9C79DFFE16E1D58 +:10B02000CB9F54EEE374E8544CBEEF17797F9D45F7 +:10B0300011DACF4930AE3D8EDB2527A6FBD0BE8D81 +:10B04000F238ACAAF37C1FD0EF94EF837A9DECA783 +:10B050002A9EEFA34484FD54C5F37BD00ED06C75BB +:10B06000ABDFDE2AB09B6CF075CD7D2C6BBF907D85 +:10B0700092D946F93EAA6E32DCBFFB809F5CDCFEB3 +:10B08000A0FC1E9F9A6024DF22DC5EF1E871D68866 +:10B09000F614E6FB8CC1F79A8FEBAD13AAB1D8B7C3 +:10B0A00068B4DE347EC1E3179156AECFA6C6338DA9 +:10B0B0001CBF5C4F66EF57616F308CFB5AF499B23E +:10B0C0005EE8CBACFDBA4DC23828CA1B1F0D338ECB +:10B0D000FD1AB6ECAEA424EC129A4744E7F4B6ECA1 +:10B0E0002A454D35627F304FD26BE5E27B25C2DFCA +:10B0F0007BF8B7E8374F5B7616E2BFBF94DB594861 +:10B100000FCD56CFF2D32A85F8A9BF74C4617FF55D +:10B1100067EDAF5F3BECAFFEDF9794A3BFEDF1A906 +:10B120005F23BBAB7F29B75FFB3D23FF45FB552367 +:10B13000BFD394F523447F4FD67E75E2B16BE938D7 +:10B14000F6EB1F188F7D226FCDC2639FC853B3F0FB +:10B15000D89797B7D6573AECC05F1FE20FE5C8996A +:10B160003722EB6CEBA86FC96FC97EED433C6A399F +:10B170003CE6ECD7E420DAAF7D3A8FC774D5AFE573 +:10B18000E71C5630F26715A58A1A291E66D9AF89C1 +:10B19000049D83CFB75FA79DC37E05BB722FF27F4F +:10B1A00070FD00E292F937264D34166FAD4C3C88A5 +:10B1B000F2435D9FA4D8B9B2319EC1E73FBED4F837 +:10B1C000125F2F9A8472E181CFBE4DFBEEA2FA117D +:10B1D00013FD2A8572CA18EBFE8B0BF5A687F1BB0F +:10B1E000225993903F8A74AE373B824D0EFFF34352 +:10B1F000B975F938B6FFF719C6613E5E5AFA73B4ED +:10B20000574D3682E74CACF56AE56BC07EA711F16D +:10B2100033CD007B16DE4F5F37B205ED797DBDE69D +:10B22000C279CDDC1873F17B72AC7B9178BE86B5A8 +:10B230006EA7DE22D60DC8AD5B005F95C99108AD43 +:10B240009BA52F075703BE41ECD0FB7DD3E03DD437 +:10B25000AB3A53E52AD637F1F7D975B1E9B7111DE5 +:10B26000FD89778F9CC0F37AE626AE9FFAB7C4A417 +:10B2700085F0BC24B34FAA06FAFCD0C7F3024B3AC0 +:10B28000994B0F89492C16F96B94F3A3B910BF247D +:10B290008F2AA0FF6DBFEAC47861BFF0BBF70FFA39 +:10B2A000881F4B6AD94114E1559D038602F014D6DC +:10B2B000EAC5A89FCA3B35D7CC10FABB46980BFB12 +:10B2C000315312D60B3732D7B564D78B7C35D13F8B +:10B2D00033CFAEC8C0F3E24E26219B142607324876 +:10B2E00077FD169EF7A4D5F27BD48A1B78F9A6CFFA +:10B2F0004D74FA99A09755AFEC4C0D52DE13AC5338 +:10B3000054C3534D9EA7579864B146C04361C300D0 +:10B31000C94F09E68DF0071A580C5D167F0570625B +:10B320001E86B4712083E7A4CB3BF97309B811FDE5 +:10B33000DCF978982C9CBF1370FD46C0F9BB2C9C9F +:10B340003109E10AE84E38CB114EC4DF46279C850F +:10B35000B502CEDA944470AE1E31507E94E4C159E9 +:10B3600032CEB987777D563E9F29FCACE696762E85 +:10B370007FC8BE8A24D4CC4B7528CF74F207627C78 +:10B3800084EEF7AB4C90BF95DDC962B3007F2F32DE +:10B390005788EE95A84C1E46BDA46A6606DFAB7AB8 +:10B3A000D28F7A4B65BA81FB4D59ECC31AF544062E +:10B3B000F3B3BC9A2B46E7D69B77F27E358E9F6C13 +:10B3C0007F1AEF8FB1BDB9B8A99BFAA73862A36EF7 +:10B3D000107D646D40E83F918F55C732BE79389E2D +:10B3E000FC5B7B1ED3340675943F096E8F4D15753B +:10B3F0007A5F852C6E6B4FF729D8EAB44E797B348F +:10B40000FDE8FC523EDE2A859F1CE643725FCC3786 +:10B4100092D84C7626D4891FB2F38BC0FC249A0FA5 +:10B42000E5E5E5F065103E004F0CE9A7AE7E6D8BBB +:10B4300044ED008F823EB3A4C9E009F08C70009EF9 +:10B44000519EE7F0A57F247C79EDF8190B5FCD368E +:10B450007C4E8C2FA963227CB5AA748ED6FB523504 +:10B46000F949FEFBE1CD997F228BFBA0FE5878B411 +:10B47000F20CF3CF81DEE317F7598A73A0D67D98DB +:10B48000E3E51F5AE73FB3FB4A7905C51594572FEB +:10B4900031310ED2C958ACA47EF47CC683C7CADF52 +:10B4A00090373F58F1A6EDFC8E15EFC7B8BCFDDC18 +:10B4B000CA037E6EE72BBA7B4CF9B4D3CFFD4CD6D2 +:10B4C000F738B017E956C7F3754EBF66E5B5C37ECA +:10B4D00007F07840F4E7D9BC9BC6BFD99D38E0B7E8 +:10B4E000FB7BB48421E9E3E3237F5F3338ECA6FEE2 +:10B4F000F787D534C6C33A5C69DFC5A83FFF81E74B +:10B50000AF59F9ED519674A11FA79AE92EC4DFB681 +:10B51000B6168ADB3FDA96A0B2BFAD95CA4880C3A3 +:10B520003746FED2D308E7B9F29758B88EC6CBCFCC +:10B5300037C8DFE759F906DD227F69EF229642FE20 +:10B54000AC8EE8CF22C821BF388F8820A03D1BE4F5 +:10B55000E7044EBFF6D316CCB3EE2AAD5F887EB4B7 +:10B560001FFBF9398E82FA98F15C1D3F9F8271268C +:10B57000775D2F9DAB00FCFED85F4AE7FA0DBC8FCC +:10B58000443154F2E31BAD7183C7E3B89D18DD93DA +:10B590006C47FB78A767A885C7C36F5B89F733ED56 +:10B5A000C4871731F6726F5717C6B7432E5E3FE355 +:10B5B000EFA0FA366157D01FD8215104DE959B6F5A +:10B5C0005580EBAF4AF4DD215E3F3C7BD60BED8A24 +:10B5D000C52705724CC23C9092662E3F42177EB53D +:10B5E000DC7E5FC82FFC5CEF86DAF879BFFDD39272 +:10B5F0002D763BD17AFF1BBFA5272D7CF17B273C05 +:10B60000AF5E487861C21FE8A95B6C3C8C72030C8A +:10B6100065AC17D473BC04102F3CEFF23748677742 +:10B6200010B6B6882F113FCF9E6BB7E68925AE7B4B +:10B63000D96CC775B80F36BCFBE1FB6A300CF87DDE +:10B640004966D373C8976FF17CF868DD3B77E3F9FF +:10B65000E6F3850FE05102445F0E4FA08EDF2F18F6 +:10B660000C2732F89135DE36C47B18ED4685E4F5BB +:10B67000B6593CCEBB7F93427E863F005EA6042631 +:10B68000C08B45DF1C3F98E5767FE974C107330323 +:10B69000E2BE28962A8FDBECD72C3EE13BF287C92D +:10B6A000295EB274B93D8F769F884BEF6CEBA9B0E1 +:10B6B0009F4B95837CDDAEF11B7311CE19CC28BC5A +:10B6C00087F4C648A32F8CFE78A08F96AB4FDBC8BB +:10B6D000882E73D2A90AFB39D6197B861B590147DC +:10B6E000D7169BBC9FB167A4918D718FEC1FABDC0B +:10B6F000864E049433E5DCEE2BDF93A0B80458AEFD +:10B70000A79AA7621E24481668B333502CF29A55A4 +:10B710001F5E6555D49069D4D1AE353212EE8BA739 +:10B720006E1676AACAE5F5D6FBF4AB303F6E987D6F +:10B73000CE2B5FCCD8EEFBD8C5C942A04E809F4B24 +:10B7400028FF401279D503948FB7EF3756DDA47ADE +:10B75000BC7680F46E401F207BEFDECBF839043CD2 +:10B760005B4BF6C2467600E5F234D12E21F8E05A62 +:10B77000C1B75BABB426FCAEBC96B5D3F9E8CAB290 +:10B7800026DC07013BB5935CE81CA03DBA9A4C66E9 +:10B79000703F66D9EBB04F203BB444E7E5CD012EB6 +:10B7A000076E12FD5BF5A77DC6CDC80F53C7B9471D +:10B7B000F0F301AEBF2ABF54C8FDB1B0BFB1E72757 +:10B7C0007E31A0887EE25F08607C345D48FA43D514 +:10B7D000F9398CC01E4003E02BA09A94CF562EE07E +:10B7E00029574D03F9ACD8BC7CA549F64F6A5F5781 +:10B7F00008F12AF37C82DAD455D7C3FB9ECB94D8C8 +:10B800006A1DEF874BED33E1FDBECBBE18417C6C6A +:10B81000AD5A5C8E78D82DF8FDC4657C3D7B37260B +:10B820000F233E2395A92D3F473F15D209FA2B87B9 +:10B83000FD21EE07778BFC977239254D81F70AC8F9 +:10B84000D56001EEC3539F776189FC3D0FEF27154B +:10B85000F789C9098273DFDD8CDFF328D6E53ECB9B +:10B860008FBB9459F170C9BE0E9F0A58F2D6B94EDB +:10B87000FE54EBA35FF0BF552F6AD025D44FC5957A +:10B8800049232EE854FBA9DCFBA100F7E306C43AE8 +:10B89000C0442ABC37B61B6D3209F79B8017987FCE +:10B8A000D1DFA6BD28FF86049EA745383E3BFD8913 +:10B8B0006F07C84E4839F282A745528D2E921F4E0F +:10B8C0007B556B003C4D1037F853E1295FFE59FB67 +:10B8D000FBFFAEF01635C424DCC797205D059F172B +:10B8E000D9EC85F7045F961BCA98EBFD45F1BEA81D +:10B8F000C16426C91BDE8F71CBC820CAC7504C9BC0 +:10B900008FF6D0F4CD438D68C706221AC52B3FB001 +:10B91000E48ADBF800E540A7DFF82DD23F9A4E9984 +:10B92000D7C377B384DD3538FCF967713DEDDFCBE4 +:10B93000F7F7FB87AB27BCAFCB5FD3E2C8839C9301 +:10B940004E38F220B58656477DAFA55F859D395E9E +:10B95000BF969D29FB8D4090C31BC472AFC8C3EE38 +:10B960006E4B51BEBFD5BE3CC8E7571D491808EF06 +:10B97000CCCAA4C96CF65D7EFF5541BE7EAA825C2E +:10B980008E57378CF0EF0C1818E5CE8E84817AC76D +:10B99000DB9334518E9DAB9FC21D23D45EEB615B64 +:10B9A000B0FD27FDF19AE0228C2BA51CF9D8308F31 +:10B9B00059F87C70B8C387FBC7BD885FD23563EF89 +:10B9C00017F2F16BC5AD66EF9918CF933E5F26CEA7 +:10B9D000495E5BCFC49F7E31E6C7DD28EECDBDE377 +:10B9E0009B0F1D7D084875C712AF8676F5B2335F91 +:10B9F000398AE7EADC78FE90CBDBA378AE6E634B46 +:10BA000080F5F2FB010B70FDBDC75CCD88AFF7D8A8 +:10BA1000F1828536FE5E1314E7827B3C14B7022E5A +:10BA200026B9B329E5719C07BB61AFB37E3D5B5B73 +:10BA3000867EDFEBF778581A507E63DEF993C620D6 +:10BA4000D70737B06437FA59BB049FDCFAAD0B1443 +:10BA5000DC27DCB850AB42FFA805C75541AE37DF45 +:10BA600081F5A97B73CF6F0AA615CCF77BE3A98577 +:10BA7000577E9A613FE9EE0AD42345DC9F998FC730 +:10BA8000EB7A9C709E6B1EF9705BF7B08C07877C1D +:10BA900048227B217FDC1B84BD988B8F25E99E4645 +:10BAA000B35D66E8F77820700FDDE3B8D9F46A2853 +:10BAB000074EFBA6A7D12E6C437EE771CB0BB97D59 +:10BAC000CA7F4F63B2DF778CF3FDCEF0501CED0AD6 +:10BAD000EBDE9BA03A407394647EEE7467E41CEF47 +:10BAE0006B267E7FDA774DD916804B975812EF87F9 +:10BAF0003BD73D955177620FCA8BBBDCA96B58755C +:10BB00000E4EB09F57E13D805E5640F7F858E70A69 +:10BB100029BE4AFEC754C6A8C2F89BF37C6200D770 +:10BB20001DF473BBB0C30251E7FBFC38EB63422E3C +:10BB30003480658AEBA1400D66E8FE8A7AE7BD8114 +:10BB4000163DEF88F0F8C778EBD505165850E5F1AB +:10BB50008DB3149FE4756BFC5329A919F9FD0EBC34 +:10BB6000227B81BD5F1EEF18957F22F2CFAD73352A +:10BB70008CC522889F9E36F17B229EF867288FE92C +:10BB80001FDD0CF3E03A8A78DCD19CC6F384BD3526 +:10BB9000F14289FC67EEB0AB4A880EA87797373F31 +:10BBA00082FEAE6782FC9C2E93F9BD1CDEA069600C +:10BBB0003E6AB72711417DA7DCC3E3CC8DC14402A7 +:10BBC000BF73475A3C6817FEE0ABD7B560FDA6C807 +:10BBD0002A1953FC9E13FDBC77F8C9C51867E97E86 +:10BBE00022C43264BFA715949B373DE5E6F6F3D730 +:10BBF0004234FE4D5FBFE1318C4B48DF5AAABF4D46 +:10BC0000FBB80EA2C34D4F5FFE6353CC07EDF18E20 +:10BC10002D223FD88C45F01CE0AD5EF657A847AD0D +:10BC2000F95BF803BB97F2476E3A54E4C82FB94961 +:10BC300086F6A81FA05C3B865FE9E742BEBC1B827C +:10BC4000FD04FACD0F0DD2FD7E370DFC8507E725EB +:10BC50005526D95B30DEAB418FD58EEC63F371890D +:10BC6000FC87EF3E7E40C17CEF9B0E1D50AEA57D54 +:10BC700026D787169CEAA15D26CA25B5469B8979F9 +:10BC8000D6CBBFF64401EA939BBFF6FBEE8BEAE806 +:10BC90007EB591D5B00E6E3FE4A6F3973EDD957765 +:10BCA0000F21BF3FFD36FC277C7FF3377EBEEA9F26 +:10BCB000E1BB7740EEFB4094BE33F496F21DAC2717 +:10BCC000824994FBB73FE39463B71F7A83EE3FD377 +:10BCD0005C6CA4F2D39827E55C0FF9ED3F60671424 +:10BCE000DC1FDF3EB08DFC98B73FF5DE3FA13CB9CD +:10BCF0003D4F1EBE83FF18C3EF180AE5F91D0F95CF +:10BD00004C4ABFDDFCC4075F36018FEF7EFD575FF5 +:10BD1000C6FDC92DFFF1EB2FFF0DC615BEEFD350A9 +:10BD20009EDF7EF8AD2FFF35CCF3BD67BC2EE48BD4 +:10BD3000F7BFF7778FED87FAFBAFCC5920417D76BF +:10BD400088AFE3F79FFC5D19E673DFF9BD9553906B +:10BD5000EFEEFCE6F22913D945EF031FA5BD767877 +:10BD6000D2443FFD190993E318FBAE28F3E8F0EE47 +:10BD700093A7155C67BF95D808EAABDB067EAF20BA +:10BD8000FF1D35D808E2E5B9A7DE38FAD7507F0F96 +:10BD9000E8E21D832E30EFA92EFA3D91CC54FC5DD4 +:10BDA00091DB9EBAFC334BEBB0F4C474A40B1B21A3 +:10BDB000FD388A9E2F013DEB72F41C977E5FDD46B5 +:10BDC000F7EBDC3E00F49B379A7EEFE13F968CA6C2 +:10BDD000DFCA3CFA7DC06EF90AE5D63C5532A61D95 +:10BDE00068F98D6FFDE61513FEDED2FB79EB753C2D +:10BDF0003CB74A1CAEE290714508D7DBD7FFFEB1D5 +:10BE0000FD61A4B397F6AFEF3FF1C1743CCCFC0BDE +:10BE1000CFC835888791EF79B583F0CD4DDFFB2909 +:10BE2000E9E1F7BFF9A2A293FE600512C8CDF75968 +:10BE3000F6EF38FA7F6EE33E2A76EB23FF7FD53F9D +:10BE4000C1F7B7E2BD111AD18FEA470DFE3B2FB7FC +:10BE5000A5D734EB741F6029CDFBB6345F0FB7A5AF +:10BE600007D7E1EF3EE4E37D47C865DD1B96A5AB50 +:10BE7000548FF47C7D159D2F1C879ED6FC359CFF2E +:10BE800085F0FE11E77A1DCD37230ACA7F8BBEEFFE +:10BE90001F38ADFC33B4CF7C47D15C1741DD33A2F2 +:10BEA000901DF4A45BC3FB48F3E98E71800DE47F21 +:10BEB000681FF3DC5E3E3F6C0D39EF93B4F071AE5A +:10BEC000F57CEE799C1F9EEE0AE90E7EB1F0B5A5D9 +:10BED0005CA13C0B7781427EF96E8FFE53F4838C1C +:10BEE000BCE06107E1938E82C59497930F6727DAD0 +:10BEF00071B6F3E472304EF732CA616D019A36F9C9 +:10BF000079671E98886E8347AD1A8ED379B1A52EB6 +:10BF1000867E8BFE86E114C5E76F7529ED52EEBE75 +:10BF200041EBFB5743D5DC7FDAA0B8307F75DB31BE +:10BF30002E9FFA3D0397D27DB7B35CC4C7F970FE5C +:10BF40004388EF97DC9B03B147168E8F77B7384F46 +:10BF5000B7ADA63D4EFE9BAA7011FA4D3B06BFFD44 +:10BF600002C6AB7D0D65551887FF85E88FD504D9CE +:10BF70001B8E7826C08178BCC585B951305E018D95 +:10BF8000772EF89E1672D7BDD9177B6402BBE80FD7 +:10BF90000D9F85C7E7055FB83707697C0BAF78CF82 +:10BFA0004123FAA1C5EF6D60DEC93D613AC247F792 +:10BFB0001EC8950BD84C21470BB9FFFB6D9437C6B3 +:10BFC000779DF18A80C6FDDF4F86B83FB9C037E064 +:10BFD000A3B357117E3F959A9063350B31BF85E728 +:10BFE00025E6AF03AF673885F7CF14D6B862F08483 +:10BFF00015D6CB6407F944BCA860A949F878A8AA6B +:10C00000C6D50EF3AA2EE0F87CC833D27C03C0B1AB +:10C01000754BA17E10F9EA988761DCF2CE69EC20BD +:10C02000FA8DAC716788F65E16A47C372FE2612129 +:10C03000E61FEA0FAC4739F00517ED87A2C73EF7B8 +:10C040006C2594B387D6344D8372AEF8AEEA55C9E9 +:10C05000351DEA728190FB0BD9425CE777A4939778 +:10C0600020FAEFF842BB17F5EDE7BF646CC510CDC1 +:10C07000A37BD63AE4FCE8FCDF21C2CFB63B8F5F5E +:10C080003A279CCBFF653593F3239C9B6E6B19EE8F +:10C090000BB49972B210E486F154CCC07142D81E30 +:10C0A000F7B5357C3F9DDD9F88BCEEEC7D9EEC4E68 +:10C0B0008A4B9E117C93C35B01F18FB79EDF83C1D6 +:10C0C0009EFB25233D520F7C68DB079C117C60D1D1 +:10C0D0009BB13AF324C63F250FD9EB163EC79BE729 +:10C0E000472DBFDCC6CC93B308DFE6490FFD7E0CBD +:10C0F000D50F8AB24F3CB7DA5F9C474F30BACD9329 +:10C1000040506906DF57CCD81C26B8B3F2AC92BFBA +:10C11000B7EAF9F4AFBCC5D9BEBAC7592FAC77D6C8 +:10C120002D7EB1F8C3E29BFF2A7F94A04E5E94A3BC +:10C13000F3B9F450C6BA0FAE9265E8FEB74A33635E +:10C14000BF9F67CED4F87505A5744F9B0BFDEC839C +:10C15000D36617D2EF138E1317EE6A3B347FAC7B96 +:10C16000F63C32F4BF00EF7F83F7363C66F3DAEB40 +:10C17000ACBC76A3FE75A8EF8C69245F7ACBFF7701 +:10C180006410F1BCA8A9C51ECFCC2FFF0079FE6DAD +:10C19000384FAB9E9F5FBEF3E3CFF3EFC7F1BB8594 +:10C1A0007F2E7F7C43ABA5FCC18A24BF67ED8090C6 +:10C1B0004FD3D8F0160FB7D9E2AA2D9F6EC6FAA1B9 +:10C1C000F2E7753C97F47215D2AD9075D23D478079 +:10C1D000C2BAB313E8C9FC7B8E14178F7F37269E33 +:10C1E0003A81F72E56246B69FCEC783836D4BF912F +:10C1F0008527B304E3A2D3D908E599EB71AD0943D0 +:10C2000066335B62CF6209F0CCFDAFDCBB34DE3954 +:10C2100008ABFDC775FEE18898DFA1907104E9F4D1 +:10C22000C73AFFF093DCB83F196BDC8FFAFB630F62 +:10C230005C5EC0CF7BBD2A915DB8EBF27B280F4DD1 +:10C240001996E8FE3625C87F07F42E973F86F69AA2 +:10C25000754F50E3BFECA3DFF13BEC4EFC1CE1D982 +:10C26000362D3903ED89703CE93CBF1975F17C2509 +:10C27000714EB617EF119272F708F5463F9E73158F +:10C28000BD48878FD4EFA87B84DC858B46F79F7FE2 +:10C290008EC11DEAA479ABE7797E215C62CCE7BF51 +:10C2A0003F36BF19EFF5B2EE0F2A2B7CFF127E7FCF +:10C2B00010A37CC98AFE853D183F0B4F359EC4F6FE +:10C2C0005F2B5CD01CC6F7D5FCBD27C5DFFB64C364 +:10C2D0004445BE49D349DEFA12CAEB28C77D354230 +:10C2E000AF47D8B064F9C974CAA3995168CBA3F118 +:10C2F00056F23C1ACC97199E007FDBC5FD91DBDA24 +:10C3000074CA97C113AAA83F7CB53C6F06F70DFC11 +:10C310001E168DDADDDB16A1725F9B41E5B7E5F8ED +:10C320000538AEAF86DFF7968D8388F2B8380F7E7A +:10C33000B890F37DAEE4FBC77271AEA3F713571745 +:10C34000DAD7C9D242C9B11FE96E8B7EFA884DDFB8 +:10C350002B1A3FEFE08DC0739BFE91C5FDFD9D77CD +:10C36000A718FABF7C997D0CFD55578871BBDB5A25 +:10C37000E9DEEDAEA26E03FD523BDA9254576571D1 +:10C380007F5184CD47FB5155938638CF301FFD8AAE +:10C390006A30C3EB31F15E1BE2F53AFE3ED5B6D909 +:10C3A000719FB737D2EAB8C75BAB6112EE4343B1B6 +:10C3B000A4E3799101DFD9D67FD5B1CD2AE6F57511 +:10C3C000B390D68BF670A489F2EE4FC580CA989FC1 +:10C3D00092B9F44421EE1FA28A8E3675EFDDCE7B32 +:10C3E00054F09E47FBEF2AFA2229BA6F5FA94C50FE +:10C3F0005E9395E7E18DB8F27E4F2B3D80F7B3A9B0 +:10C40000C7AA491FDC2CF0AF6AFCF74EB2F246EF28 +:10C41000596ABFC722041607EA8510FE5EB00BEF0B +:10C42000B34B9898476556C9F4FB208179ADF43B2E +:10C4300092C1D932C338DE8EB9B744C0B261731B22 +:10C44000864CBCC769AB5E43F199D0EAFBD7A2DF4B +:10C450002DA41D5E4765C377AF443F4EA8F9680B16 +:10C4600096FD855544BF50F389ABE97DF33BEBF175 +:10C47000B99CBD1FCFA4FBF17A2A6752DC6A7C7994 +:10C48000E9CAFDAE18AD63DBEF9C51BD38AF5E91DC +:10C49000D77E66DEFB4FE4BD5FE0A80F1671FBAAF6 +:10C4A0002B9BBFB387E1798ACEA2FB23C8EFFB7138 +:10C4B0005E68B7D7811D65A387A20E38EA9F2D88D5 +:10C4C000EFE7EB8CCB653FCB1888777FEB51BADF7A +:10C4D0008EE97292D5633DC3F01E4EC95093E8D7E2 +:10C4E00009C6D226E64517AA8CEE97F4B7C60CC447 +:10C4F0009BBFD530108FFED6B8A827A8FCF7E2C4A2 +:10C50000A1C252FBBD9CC334DEDF175AF945E908CE +:10C51000CF238292CEFDAC30912FB3722A3A4A4E8D +:10C5200099F6FB03404E3D85FDFB504E318C37A7FD +:10C53000E91EDCECFD64358CF4D778F4EB6DE3F7A1 +:10C5400091750AB9F56D39F17DC24B94DF8F9793E0 +:10C550004309CAB7FB69FFAF2EC1FB668EE3607467 +:10C56000EFD7AFB6A2BF5F16F97647FADFBCC4AC0F +:10C57000B5C9BD28E7F7CF16245EA07E357E8FB201 +:10C5800085F7C1B9B3E99E17BAAF06E5C52715B25D +:10C590005BF2E1EC44BBD99E4715ED8DA37F2D20C6 +:10C5A000E49D5C7BFF5A1DE03D51A83BEEF7F5682A +:10C5B0004E3EC8E299AD70EA833C3C0FB6B8268582 +:10C5C0003FBFF6F87C7902BF05E0F3171C9FAAE98C +:10C5D000C0A7E0DFE379F7C4D0EFD32ECA9520BF20 +:10C5E0007A3C36F975FFDDC91EFC9D89E031376B59 +:10C5F000D7517EDDF88A537EA5488E9AF3D900CABA +:10C60000D58CA003EA1D641A5F0B97F3418DDF27D9 +:10C610002D8713D5C82F73A626FE83F8A886EF634F +:10C620003C9A539E499AF5BB8F9C5FFF13F7BF124C +:10C630000A008000000000001F8B080000000000BE +:10C64000000BC57D0D7854D599F0993B37933B434A +:10C65000667267F237F9BF09034C30E2244C60D0B0 +:10C66000606F62D0A0B18E16DBD8A5DD41C1E22794 +:10C67000ED372A2ADD85CE0D24904412060218AC2F +:10C680003F0302D52DAED155B4AD5F7782CA626B40 +:10C69000D7E8A21B2D6E078AAEEE767753D7DDD290 +:10C6A000FD68FDCEFB9E7333F74E26FCD8EEB7F443 +:10C6B000B127EF3DE79EF39EF7BCFFE7DC33444C28 +:10C6C00078C34E42ECA44D23164256C90A214D149C +:10C6D000F6DB4E5AE7D1D21721913C42889744C8E5 +:10C6E000024272E99F843679B33AE290A15D677C99 +:10C6F00034873E2AA848B408F4F9700EE91CA9272B +:10C7000064332F3F837F5F20E46B32EDBC285D2EC6 +:10C71000B1D6E7A70CF599656F8C1031270D4BCA80 +:10C720009805F098AEFDE87D73F353B4FE918C71DB +:10C73000F5722036D200FD75C79E6830F67BA95C85 +:10C7400083F8E8B0CBA6911BE9FB8FD8B3F7532F42 +:10C750000BD8DE658B46C24017425412A4F805E49C +:10C76000BDFD35E976F3609E4D50AD11A02F2149F6 +:10C7700012BE94904A1B8940BFB610F1C8F9E9F681 +:10C78000CDBC7DA583D5678E7B853EAEC33CAEAD6B +:10C79000C23CEE624E5F42970BC623248AE3E72930 +:10C7A0001AAEA34DA1EB09E3574455281FB9F79DD5 +:10C7B000155B0A09E929F2375A159C9766A5FDF61B +:10C7C0006CBC44D8489F5FC7F1525FA15D51D859F6 +:10C7D0004F12FD9674FF775A23D7011FE45468BFA8 +:10C7E000B6BA685998C471F4757091D3E42EC37CBD +:10C7F0006EE4F8E9F4A5AF8842639A2E2EF291A96F +:10C80000FD57787B9D2EB47D9BE0A1E3C8741DFD90 +:10C810004807F219FDEFEBC0B7409F205D6729FD87 +:10C820009C10CADF40870BE4F355B28CCF6D226DAC +:10C8300047E96AE3EDBFE9526F97F97AC238BDE183 +:10C84000ADE155B40BF550444B025D2279D17EFA2F +:10C85000AA4D726933E6215DBE25D37636EF08D244 +:10C860003B8FD29D08E9F7F55299988174DD7CC21F +:10C870009280752CAA0AEFADA13079C74A0ED0FE7E +:10C88000B556D59243D743AB22814DF471516DF427 +:10C89000B2403DCC27BAF04B743E3D544E9273D219 +:10C8A000F4FA4D1189C37C74F82FAC110DF0B61455 +:10C8B0007746805FEE3F65517281A4CBC238DF7549 +:10C8C000740A028C572F240ED4A4F9EA81FD25881E +:10C8D0008F58B0BC18F07FA0BEB624720E79DD125E +:10C8E0002301DF2C032C462599F6BFA5A251CAF6D9 +:10C8F0005EAED716F015D07EDB9512F91C723D7D29 +:10C90000BFAD0E63BF7E6BE461B9686AFF7406A7B2 +:10C9100052944F04CD423E9B49E534EF39EFED94FC +:10C92000AE123CD7F9A426DD0E616B3698C96FE1D3 +:10C9300065EAAF8500C0CBDB5FF752788EFA0CC09A +:10C940009B6C9DEDED8B283C9F565D0ECBFBB57629 +:10C9500095E257B890FE5D46C85FC6BFDEAB51F8A2 +:10C96000D71EF569C0F3A84C70FD9FE77CEBEC4C3B +:10C9700024418F92BC388EA3C32AC020BFD5EA6160 +:10C9800058C7A39C3F1F28FAA117D62FF37D8DB758 +:10C990007FD7ADBEC4DAB37172E8B2123AFFC22FCC +:10C9A00075A83D20DF54315829DE6A27976B2F6127 +:10C9B000EB2D337EA5FC7B14DED7E9A9CBF524BF94 +:10C9C0007829BF58D2FCB2592E4E18F5D066EFC563 +:10C9D000F14BAF189664DABE27EFA676E07F4D11D3 +:10C9E00002B49AF414361E53289CBBA8B011964189 +:10C9F0006FFF2FCED671237E5205EDCFA00F3603E9 +:10CA00005F7D9EF1E399E3B73AEAB28FFFD1B9C6F1 +:10CA100047BA14A7EDE50397DE2765B35F6B732272 +:10CA2000FF6EE2DB0A15E93F552E47A41B9DE97610 +:10CA3000172B8F99A5642161D0A79BF24EC9B71A15 +:10CA4000FA11DD4CDF3FE1544577D3D4795DACBCBE +:10CA50004E37EEFEB879DC82F4B805D9C625A4427B +:10CA6000FE7086511E99FE7425A21B1D14AADB1FA1 +:10CA7000E803BBE5268262A5741BEA10ECE8B790D8 +:10CA800004F63BF430D5BE97C1F353327B1EC7E7A3 +:10CA90000E3FE3EBE9F01D9DB5E09C7E8A2C3FD96B +:10CAA000D046F58C7DDD5F35B4CDCF52DFDAEE8731 +:10CAB00075D2F178708ECB027E8A2CCAA5E12CE368 +:10CAC000D6FF6EE3914BE83CE436268F6E9FADE5D2 +:10CAD000560ADFF3B7764DF2C2F342ED94812E355C +:10CAE000C3A1A5B716C26C9C723F6D57B87EFB7888 +:10CAF0002ED0A19B28F0FE90EA6981FA4F5EB76BB9 +:10CB000004F416BCAFEBBD5AFA7E72CF783EADF797 +:10CB10006836C54EDB2736285D22F07F0F1901FBF2 +:10CB200013A7F6059858C7AF46955B45C42F321337 +:10CB3000FCBDC4066AC7E93CDC2A356E46BCF64B30 +:10CB400076D063436A6D3E3907FD3E77FF239FAF82 +:10CB50007F8FAAB4F0FEE75BB17FF9C80330DFA591 +:10CB60004C9F658E33D44EFB3F077F9C0F7F7DDD4E +:10CB7000F5FACCFEA11EE6E1582B9CCCA1CE8D434C +:10CB8000FD34064E8E8334774DAE33CA3F5BB7B764 +:10CB90006B0513FF839E00FA744BBF2C3E4DF9507A +:10CBA000B4FF73F169CA8756D0CDA5F4790EA31FDF +:10CBB00039FB993549FDF77E78D582F0679F51B8EA +:10CBC0001B60DAFF0E2E7F99F3EBB6303FAD9BFA78 +:10CBD0006BCF66A1F3A09BF967DD4ED60EFF517AAD +:10CBE0003A64659FD11EEC700BCC1FA678A8C530A7 +:10CBF0003FFE8FE211A3B0C8F524A568B91A44F925 +:10CC0000677EA6D84B9214B6837F1580E7F1E406C1 +:10CC1000D08BB210B82A44619FF89F2983BF972B0D +:10CC20009100F863B9C7AD014A21E827699F07E37E +:10CC3000D1767E8E4F4D96F7BC1A8175CB554954EF +:10CC400073033EAC7EB27D451CED1CC5317A55E9BF +:10CC5000D4F709EFBF96EBA7752756245E31D43F72 +:10CC6000ED76167E7809FD63215988EB675D9E8F0E +:10CC70007A288F22BB682A5D7F138B245E99955E8C +:10CC80006789FE0FE85A116474A9E878479B19C4B4 +:10CC9000F59BB07A011ED7DA003F551A212180DFBB +:10CCA000233E0AD7445D8AE0E594A6EB5D097F59EF +:10CCB000A1FEC428BC0F610581F7DBDFE9BA8AC297 +:10CCC0000D9B75789C407FF7FC3E9F48D0DFDA8A49 +:10CCD000B4DEA0FF39DBCCB08EA78EFF5C9214606F +:10CCE0009CB9EDAF1CB9AA10C7D166D07EFF22F463 +:10CCF000ECB53E92C6E7528E8F7BC9F12380CF25DB +:10CD0000746E5639CD9FE8C2CD4CCBD15CF5AD8D5C +:10CD100080E7C35BA84F170298CACB3CC439252CC7 +:10CD200048F391CEFF344EFD05D89332885315F069 +:10CD30006F029688213E2579416C07F1E8A92C7293 +:10CD40004E48178EFB631E8FBE1493B07C312613A2 +:10CD500091AECFD3312FC24FC6148477C4FC58C6CE +:10CD600063017CDE1B0B21BC39A612167FB66379EA +:10CD70002016C6725FAC13CB442C82E5A3B1D55804 +:10CD80003E1C8BE27B4FC5D661F9FD9886CF1F8A8A +:10CD9000F562391C8BE3F3EFC58611FEAB5802E157 +:10CDA00067624F60B9353682CF7FFCDBD9F9E7F295 +:10CDB000137E18EB5D6C8C87473F9E8D71F474ED8C +:10CDC0009F87F8D960DF179C096F7A83AEEFB8852B +:10CDD000069A5E80E3B780FE5A70FC09531CF6C3C6 +:10CDE0008F3F7CDC027668DCA6580D7AE1B09BAD03 +:10CDF000C39547A2E537E5419C4EF618F1719E15A3 +:10CE0000B45CBABE959E1A5C07E759F164AE0BE2BA +:10CE10003CDACED0FF0B5D4CCF4DB1A71EA6779A62 +:10CE2000CE4437E5D3A54E09D489B892FAB3C723C7 +:10CE3000088366C8AD80329C74525854448CE39A7F +:10CE4000CE84358023AD5214FC79F1CC975527E878 +:10CE50001DAA8772E93CD5E3AAF62DF09B797BEAFF +:10CE60002FD77B206E2449D562F0A34542C7A1EDA0 +:10CE70009ED7F223609F17A8775BC17F6A3D119D03 +:10CE8000918DCE2F1CBF7506E805998467805D38AB +:10CE90007CFCDCF60D46248638E5A756F50A0F958E +:10CEA000C32B05162FFF3046B453B390AEDA294A90 +:10CEB000D7551E09E5F4C739AA0AFAA4FF6D21B1B6 +:10CEC000AF06C6152C00BF302E2440765E18DFD783 +:10CED00065A3F87EF2116980BE477F7B7814E01766 +:10CEE0007E451A72A91C1D39C1EA0F074923F8B8FB +:10CEF000E56B587FAEE3B5F8FE151FD940694DAE1E +:10CF0000CFE1E3775F07FAF3F0090165D315B49930 +:10CF1000ECE091137CFCE34222B706DAEF68B10142 +:10CF2000BFAC46AF8588A26601F8F01A12001BF666 +:10CF3000C2F8DD338C7C1D7CDD3C5EE32BE6FE5FBE +:10CF4000387E6E3B5EB6C6FCBEFF61F3FB2261FC21 +:10CF5000F3BCE652611D178EDDC9D6713C92751D7A +:10CF6000E97C4DEBF8C2F19BCEBB8E49F33AAE059E +:10CF70007EFA716502F53E0D232736D29558282793 +:10CF8000B4A7916F49F400E53BC799DE30FA0B670F +:10CF9000A87D023B772621B0724480E7FABA0F736E +:10CFA0003ED0C77B8CCB53FF99A408EDFAFD1BED57 +:10CFB0002BF2A07FE64F64E217F7E422DF2C9458AF +:10CFC0007DBFFF94B4A2DED89F25B35EFE86A99EE6 +:10CFD000BF0F0A9ACAD3A39E2FF6413CBCD04BDBAD +:10CFE000D743FB1DF6ACFD4DD66F74DF61AAB723A6 +:10CFF000FE0B2BF4F176B8B3BDFF9847C6B2DFFF46 +:10D0000016C65FB444FF5F14E9BA38619D6E453EB1 +:10D01000CA94B7977F7B3BAEEBE1B1BB67C03A1FC9 +:10D0200039D18AF61FE403F853E73F901B0B7DFECE +:10D030001FF439C9C2D7A511335F3DAF84B1BFC555 +:10D040001374BD0DCF17A5CCF00BE38C5F0E2B1125 +:10D050006C9FE927045E32B79FBBDFC03F24CD6FD2 +:10D06000FA7899EB59D06E7EDFAD9E7BFCCCF7ED64 +:10D070008AB97DAE37E3FDF38C9F239BDBCFDE992E +:10D0800081FFF8B9E56566AFF9FD1A2DFBF887A7B2 +:10D0900019BF7A9DB97D6534FBFBD38D3FEF3933E2 +:10D0A000BEF587CCEF4FE6F9A6F1EFD272CFDAF5F5 +:10D0B0008497F37CA2AA81BFABE713E9132D154433 +:10D0C0002D1F7D08ED8C827CAFDB173D2FA3F7F37E +:10D0D000D0A2F81E887F53E063523BF7D8A2D41E3B +:10D0E000888B556B3EC20F2F1A413801C95A0AFB73 +:10D0F0005F7A0B6187E624A0D7EACF9ED26E077FC6 +:10D100008D3A96E06FBB561ED46E077DD36E47BF37 +:10D11000D0B5DED602F5477578DDC1E4E3B4BE15BF +:10D12000E24BEA8FB9A2B651806FD3E135B3DF8508 +:10D13000FEBB353A3EB5B3B2DF1CBF16AE3FA97E8B +:10D1400003C6DF291098AF637D31B6BF09FCD266F4 +:10D150000A37F7237EF708240AF12FF19BE35711D2 +:10D16000FC3C4ADFC1D24427C4D3C339ACD4E97BE9 +:10D170005901D3037A49FFB515D1FEAC41165F536F +:10D18000495257D2F9000919BD031AC033F8FCAD52 +:10D19000CDBD63402A6BB303F3C4D6959BEF02FD6C +:10D1A0006A5DBDFB1E2CD71DBC17F4A7357AF87E2F +:10D1B00084D71CFD36C26BDFF97328A95F70590153 +:10D1C0001DD7BAFEC30D589F17E1793479631FF854 +:10D1D000136D2CEE7CD432F111F809DA069B02F9BA +:10D1E0009E6DDF49BDF67821A40E2B65C8C33FDADA +:10D1F000F6C94710D77FD24E430CDABE2C49E94F0F +:10D20000E1B27679AFDD10CF95C1DF74ED3DC9D2C3 +:10D21000D67E88EB57D626A07E80C7A965AB13962D +:10D220001554CF3DC6E36A4F50E9027EF1B4D3787E +:10D2300018A62F17A23FEC59AD7481BD7586681CE6 +:10D240004B1F7FD7220B1827DFC1F251AEA060D24F +:10D250006B8FAEA4F881BD5E43A3493A5E79F2B705 +:10D26000886F79875C0B79051DBF72C08FFAF30553 +:10D270001CFF820E652FD4EBF895AF19B1AC70A6E8 +:10D28000F12B080610BF820E86DFA4FE5A13183554 +:10D29000E2F7308F53A7E0B59AE315A578D1712A4C +:10D2A000002F88A3D698F1AAE0742B07BC0A010FBF +:10D2B000335E15D1A4896EE5C111C4AB7C8D19AF65 +:10D2C000F2E88825D780D723169E5FB86B1ABA4537 +:10D2D000397E1AC34FE1F8296BCDF8291CBF4A8E5D +:10D2E0005FE55A337E8A4604237E95C131C4AF720E +:10D2F000AD19BF4A6DCC2219F0CBCC4F64E237FA9E +:10D30000FE3525E78A077A63C947F6637C730CCB41 +:10D310005EBE0E5FAD88928D79463DC7E2A85C6F18 +:10D320004485BC786FCD6605F83AFFCAE2065069BD +:10D33000E9761BB15D6F4E767F7EB25E20AB317EAB +:10D340001327DEFE0AE5A3BC625F633FEDE744F40A +:10D35000E5A2AFD07E47923ECCD7EAE32EB788480D +:10D3600037DB2C82FE2E11E3E4C64BA7CE3FC74726 +:10D3700054905B5D9F8EA6AC1AC42DFD3E8276DF75 +:10D38000EEFE28A9D271FA538F4BD9EC03F1891321 +:10D3900093FB06900CC8D87FA8237109FC0C57C6D4 +:10D3A000FE43BFAFB584D4A7DBE3F32CFB10FA3800 +:10D3B000E29902922830D285CD43145502F64E3CB4 +:10D3C000538CF5DBFFE4D123C007F620F55B280F73 +:10D3D000D9F3125ED08F0F561232064A4F4CE13C01 +:10D3E0001EFC937F6D87F8BBEFCD1CCC598FD67D8B +:10D3F00028815F33609134E0C7815907BDD0AECE3C +:10D400003B26850D79E8FEA646F4AB07294D609FC3 +:10D41000030C16E8FD076033E2728435C90FFB5632 +:10D420007ABD78ED6A6A073EB019DA5378671AD682 +:10D4300080FF8A5A75F8F74BA1FD4E4746BD60E163 +:10D44000B005FBEB11E83CA8BE3E3934B154A2F65E +:10D45000E04742B846A2F0A5DA445F5BE5F9EB8B02 +:10D46000160BE144B6F5840C0BE489CF9492C47C8E +:10D47000DACE138F84693B8798201E437BC7990AB5 +:10D4800053FD6E2A97EA1C4AE3F029728AC29F7202 +:10D49000FB2387E21AC85375684C83BCB2BD33A125 +:10D4A00002FD9CCB139A0079AE4E6A9008EC474679 +:10D4B00071BF5B5C1F89829E747AF364C8FB9474AD +:10D4C0000A4435E661C2CDDF10815F8306BB5A9BFB +:10D4D000E65FC7193BF24126DEFF54A098F2358E75 +:10D4E0003379D8EEBFBF7D5D563A4E6D5F8FEDF458 +:10D4F000793CC0F5C157BE30A238804F7D1E6123F4 +:10D50000959B7C9EE739E2DB219DA4FDF4D50F4B72 +:10D51000165AE6F3FD64A28C49375D9AEE774721EF +:10D52000CB737E75533C8AFBE8F298047AE0AB57E4 +:10D53000317880C2804F3EDF6F7E6FF54CB45383ED +:10D54000FEDA7D10B7EAFDBC59C8D6F3AB56121D02 +:10D55000E1EF95D2F23DBFD09EC8A2B76E296279A5 +:10D56000880199B443FBAFDD7B405A6168B788F707 +:10D5700037A0B0FAE5774D531FA0F514AF3FDDF0AB +:10D58000C12ED073FD7E0FEAB901DF5B59F5517FE3 +:10D590005D630BE62DAD44B65E41E1224647D4FD06 +:10D5A000382F0F9E1F380D7A9FF6D7B75CDE0BF928 +:10D5B0008B5421C3B7EF6CB405F482A64A1307D08D +:10D5C0003FB2E07B7DC100E621FB4994C8507FDC7F +:10D5D000CAF60345D6AFB34DE6F95B62B32CE0A2C1 +:10D5E0004A97B82CB5BDA596D61FA5F12CF88F6526 +:10D5F000C1784B2D1D776B8B3401F9BC25D6439632 +:10D600002AB04F5E2BC9A5F2E9E478BA2B4982AA69 +:10D610005052BADAEC775B9D6B313F5C4CFD65D8BC +:10D62000CF2C5E6EF6C3297EC94700BF50AE7C206A +:10D6300000FB4386F76BC0741ADA53582E62E72C4E +:10D64000BA2DCA960A78EF5E123840EB2A5E7FC682 +:10D6500002B9D37B8FDFF5379514BF922041BAD73B +:10D6600016317E5A97DA8E7EDD9A429EE79D4FE60E +:10D6700083BEBE3FA85D03FB00D45EE33CEEF6B183 +:10D68000FCCAA0EF59CCA750738CFB8C15D1400B72 +:10D69000D0FF1E89AE5303D061FD6BB368FDDAB7CE +:10D6A000AD01D0C7FABEDA128E5F3F617C321E93A5 +:10D6B00008D8DD77A8BE81F2BD984CF653DD7B22F9 +:10D6C000E645F81F620A9639451E7CEFDDDBFF6FE9 +:10D6D000F2333ACED06CB2D798877BC79722609747 +:10D6E0005D84C5DB39A401F3313992E2D944F17983 +:10D6F000F7EAC4C002F063AE1602B02F449A59DEB6 +:10D70000F4AB773475413BB79DB8AD6EE8FF9FBD74 +:10D71000C6BC8C6E7F497321F7D3997F405541AFCA +:10D72000E4991A076DE3E742F4FEA93F8E74714B4A +:10D73000B2BB9FE2F1FEBD255FEEA4F0F69007CFED +:10D74000AB9CECB60A2AC84190C9A73EDE8A26AA3D +:10D75000CF297D225D39AE5021F239FA1964359313 +:10D76000F7BD5C0F904E66CF74F911B87D1EF45171 +:10D7700039CE224F977339AC59FB7DD6CECFDA9193 +:10D78000E665886F8114B0A0BC11D9D3558AF28E9A +:10D79000EB3E40E5ACCB42A6F83169B9230990BB1A +:10D7A000CF216F26F9226282CB4F018F67987CD1FF +:10D7B000A59900F8BF5BDEA6C8D7898F4F40DC93E0 +:10D7C0002967B80F45919677355CABE5A5F5E2D7AB +:10D7D000BFFDC1C042C37AE9F4FA79867E5CD153B9 +:10D7E000F445E3BAA6D7B916F962203486E744B205 +:10D7F000AC2B8EFBBDC2CA6B35AAAB8ED4D926E941 +:10D800000FFE5D9F4CE90FFC44E9DF25C3FAEC6392 +:10D810007E915F201605D687D147A3F123DB97BF02 +:10D820000BD7A3EFF87C8C27FB39FDB4367251EB94 +:10D83000930BEB13B890F5098CC1FE98FB161AA850 +:10D840002A53D727733D68D84C603F6C90EF9F7D7B +:10D85000DEF5C93FFBD7AF16831FE92701F0B333CD +:10D86000F5C57B3195EB9D76AE77C208F7142AC8D3 +:10D87000E799FAC4E11FC9013D71DA7F37A79F9587 +:10D88000F1FF72D92D20FD4482F48D2450FEFB025D +:10D890000105E4BFC42F9C84FD80521FDB17A02527 +:10D8A000EE079C8F0EE7D3FBB7412C8EE7BB82E8D7 +:10D8B00047592C39E86F3B4F6C2755CA543DF087C8 +:10D8C000965B785E760F2FF7F2FCEC2E0E3F9A9166 +:10D8D000AF5D5864B62BFA7EB0A59AC5055245A136 +:10D8E000693FAE6CA519AEED36C3C5CBCC70F53A29 +:10D8F000735EE69B85EC9C916EBFDEE276E6BD989A +:10D900001FCBA12F9E1C2F049A59D97EC818B73F50 +:10D910005F023B01FA0FEC042D8E833D42FBC4EC09 +:10D92000D138B747276201CE27212C070A3DCC2FDB +:10D93000CBB027BADD988E8EBADDA859FBF3F65A24 +:10D94000B40302F2AEEE879D4F1F8FE876E002C768 +:10D95000B9E07624D509F1D38C2E970C7998ADC215 +:10D9600048EAAFE85039C24C6109851D6542621F23 +:10D97000F8018B0EA3BD5C5A6A8E3F52C5CCCEA770 +:10D980008A99DEB31F1B1B86ADCA84C5A6902A38B0 +:10D99000C738D6097242FC36A4F366D8FFA7FEB298 +:10D9A0000DF6FFA971BDE1C76C9EA451423DB5CDF6 +:10D9B00032A140DE659D2FFAD8ADF4F178B11BFBA2 +:10D9C000EDAABB7D78056D777FA30DFD0CC2F765D1 +:10D9D000EDF017E52B7B609DDA12C42302E8AF114E +:10D9E0005F05F2894A75C9672C8140E05C30846F1D +:10D9F000B0F96D3B7637A92F84732FD2C48C10E415 +:10DA0000B922A403E94F26C0FF22BE08EEDF0F466D +:10DA10005D0AE8235B85791F39AC30D802949839C8 +:10DA2000B5DE56D16CE2D367AB08EAEFFE45C2DE45 +:10DA30008D601FE9B4205ED76E6479B5C1F6B85623 +:10DA400000E3691EA2C13AE4C455D42FA512F363C2 +:10DA5000087B7FA7B718EDEB9CF9FC9C05D59C9F34 +:10DA6000D1F86DAB531DC7FE4A1D0AF46797669443 +:10DA7000009D0743AD7DB0BE77DF28B8C18F7AB572 +:10DA800096BDF7AA9BC9E36647E4090BE5B5390FD4 +:10DA9000FEFA3A91F25D5F0ED3A744DB741DE84DA8 +:10DAA000DA6F40A4F37FBE88A86D158017AB3FBB2B +:10DAB000FBBD7ED817B1090CFE51C9F73B001E3DD6 +:10DAC000998B7A90DA18B453FDEFEF41BEE92B4DF4 +:10DAD00079C1CE49A1CD6316880315731CB85518BA +:10DAE000433ED436E6C9070AD37EE4D69C6400F8E8 +:10DAF000610BF7D7B7781D68EFEFB7241558F7B566 +:10DB0000EED5010812EA4A6B513E762E58700CD4BD +:10DB1000B17EAE52E7D33EAEA71EE4E5A8EF940473 +:10DB200071EDE8F253EDE0E7833C025FF5D9B48D87 +:10DB300088FF6CB6DFD8BFFC2DAC1F7C1D4F3D525B +:10DB4000BBDC8A7984D252C6F73D3C8FABEBB99BE4 +:10DB5000299EC00FFAB85FF332B97DD036D60B29B3 +:10DB6000F67E818CECA3A5E78C9B68747DC40DB216 +:10DB700005E2BEAB783B77FB826F88D45E78AA6AF9 +:10DB800057588047BC9F5C2B5187DE037905CC53E7 +:10DB9000FCFBB56A33D50BF522C216EFBFF7837FC6 +:10DBA00090795EAAC4C3E01C5867CA1F73DC1C9E30 +:10DBB0006BC66F472CD0701ACF0184B01C88A9584F +:10DBC000FEA176A32FC32E4CA977255687312F1699 +:10DBD000C7BC4FDE65BE7DFD06BFF39312AEEF38C6 +:10DBE0005D4BCB05535EE906A86A9CBEFF372C440B +:10DBF000B334422964CDCFE9A5BEEF78BCB8C614D2 +:10DC0000D70FAEB72472F269BD8BF15DFF5C1BEAE2 +:10DC1000413D6EEC2F2A433F0AF3472077D7EB7E36 +:10DC20005402F5544F6319EEFF3E600F8CC2B936B3 +:10DC3000CAB332FAC9E218FA693D3755607D8FE5FB +:10DC40004D84FB8BF202FB50CED58F91FFEA66D755 +:10DC500060BC1B3B26837F3270767E179CAF1B9087 +:10DC60002CF246DACF68F0ADD51817CB363C27ED4D +:10DC700090140BC8C92A2B8B7FC8352CFE71DFD1BD +:10DC8000F4F1102D87DD576F83E3290F947891AE5F +:10DC9000F72CDA277729E7B00F7E737E709B256C0F +:10DCA000C3796E20E400F56F56C55F93F71BF4DB74 +:10DCB0002A91247321742B6C5D500C794F31857E31 +:10DCC000ED60DEA95E8C13F839D5C1D0B4E76417D6 +:10DCD0001717313D500AED855C7200E6DB74F5DF05 +:10DCE00042FE7570B120C3B1CA9DF19713B7D1E759 +:10DCF0003B0392027EEABA122687BB624F34ACCC59 +:10DD0000817CD60896B6DC9404FAD0669534EA0392 +:10DD1000936D243C0FF4D8AA921F5C07F2F441AD36 +:10DD2000560A2706C225DF7F405C0479BA91F9AF15 +:10DD300052BA5E5D727C86CD0E79BFF09B33A9EC42 +:10DD4000BC5FFC9B070AED90371CB9048293F77700 +:10DD50007F0BDB0F5B983C2E2B7EE43AF03B6D3C57 +:10DD6000BF9249C7E74A2C93F8751BE46117CF3F70 +:10DD7000EFBA7936FA9B8316E55688A72909A520BC +:10DD8000FDBFDBF4F7EC4AD7AA20F24F04ECD22017 +:10DD90003FBF36E866F991A779BBC35C5E5A393C50 +:10DDA000D4710AF791870A034BE1DCF7FD7B165E1D +:10DDB00007780F89813ED0F7B796BED881B09FEB28 +:10DDC00015ED8D0ED0F74312D3E7B7953CD301F391 +:10DDD000F2742C339F9F6A5B66D2DB9D6B6E36D9E3 +:10DDE0003922A6F03B8649B9689A940BCCD33A897C +:10DDF0005F83FDBB9596442FF841642007FD0230F8 +:10DE000099781EAF8324C1361231DC5E1384FDBEC7 +:10DE100002F4E3072D32E33FDAD7F3944E7699C14B +:10DE2000E48B4495CAA9FE942BAE067B796DD2C6CD +:10DE3000F6C39CE2D5B01F77B2730681F8EFD963C1 +:10DE4000C2E6BDB4FDCFC20E3CB7257A24DBCB14AD +:10DE5000BEFE6D06EF0C0B9BE11CF30DEFB3F6332A +:10DE6000E67937775138F2861D6130F9523121D782 +:10DE70007153FC86B77EC1CF68796AAC76DE53B445 +:10DE80000CA518FEB7ABA401FCC104D7278B4EAB81 +:10DE9000F98BE9F36FBC9ED300FC3EFF756A322913 +:10DEA0005E5F54E546586F5D4FEEE67AC8E14F89F4 +:10DEB000B06EA3B7D88EC2BADFD32229104FD97261 +:10DEC000230102FA43FBF64F5FF1E2F9645CB7838A +:10DED000BBEF7B00D64987E5D23503608733CF257A +:10DEE000DBCA7F8576B8FF664EB76B686F57F07CEC +:10DEF00036F0D76627AE932E3FFD0D3602EBD55791 +:10DF0000979B106A8C79F8318C5307EA0BAFCEA13E +:10DF1000FDAC7D4D2488579E7C35E8A75DAF4A480F +:10DF20007FEAB18EF7D0FA5DB3662BA0E78A6E0E5A +:10DF3000BA60FC5DB30E76AA98EF4C2A9B68FB9FF3 +:10DF4000F45C8AFB21459E04E659E13B9104B557F8 +:10DF50009BA81F9FA006F96831E3EBB170239E6B6D +:10DF600070521CC0AF90833C3F1DE4F9E9C2B00A77 +:10DF70007839BD110DF3FC3934D2067E69B0A01E8C +:10DF8000B4150A2461E06331CF61826D5E81FBC309 +:10DF9000CB65885F2CEA22EB6710C7783D17E44712 +:10DFA0000F9E1822807F7EB1C2BED75159BC49C492 +:10DFB000A402E7E17B2C7B4DFBBD7AD95DD07202D8 +:10DFC000F4DE46189BFEF75281FA0FA03F75FD72F2 +:10DFD00079C95C5CDF456DEA49787EB1FE759E309B +:10DFE000E105BB902FD0F888F6F99BBAA3C32B08A4 +:10DFF000F8D3F7CD01BAA1FF5D067EF6683F8CF33A +:10E000008433FC6F300E9CB7073E7C92CF673A7E1C +:10E01000CAC955DBEF0DB27D270DF69DFC8D2CCFC7 +:10E02000EF33FB2336AB26C3BEC6BF147FE9BADE8F +:10E03000D0547EDD12F3379CCE99EA3FE692C4F8C5 +:10E0400023C0AF3E36BFBE52F61DC760A96D2FE894 +:10E0500082E9FCC997809E146FAB24979C36E09DA3 +:10E06000237B4B4E1BD6BD21A998EAE71FF39BEA01 +:10E070009BC6022678E178C8D47E514A35C1577CC8 +:10E08000D46E6ABF78226C82BF70A6D3D4BE85AC32 +:10E0900030D55F25DD61AA5F22DF6582AFF17EDBCF +:10E0A000D47EA9D265AAD7F9EA69CE4FBB62E10452 +:10E0B000F3EFD404D0774BAC1DE11DB14E2CBF70F3 +:10E0C000F669CC2BEEF2B37CD3BC07DFB956F35123 +:10E0D000580CDBC17EBB55FA9EA17FA9A23D916D74 +:10E0E000BCE26561D3F382F64E13ACC715B90FFEDF +:10E0F0003DF299AEF774BB39EADB8171F13D37E649 +:10E1000005E0DC5E1BE7BB7B7EB6A4E155FAFCD3E1 +:10E11000C20ACC9F51FFBC14E46CF0B5BC6EE13276 +:10E12000AA6F79BB5716BDE3057EF6046D2BE0FCA4 +:10E13000C3B355635E6837E0667CB6B4640ECA51FB +:10E14000E63E95F357CDE86F67EE4B65CA5F21E772 +:10E15000F3BE20CB373A7D8D59DFEB28667C379AAA +:10E160001A12904FF97EE6201C740139F1E6E1F9AC +:10E17000ABFE606BC9B9CEF9959CB19AF64D97C1CB +:10E180003CE97A9688510BAC4BC9191BD6DF572C4A +:10E19000EB713C7E37A88FDB1764E7BFFA605CF059 +:10E1A0002F60DC1AC087EDDF4E37AEEBCC8CACE3D2 +:10E1B000BAC414EED7BACEB8B0FE4E6BE4BE123A73 +:10E1C0004F35A96848CF003BEF38237E1BE952D278 +:10E1D000F40B97CC46FAE978F5FB183D3E684D48BC +:10E1E0005702BC4020E0F70EF8CCF4E82CB598FCC0 +:10E1F0007167065EFB0B223D25B4DE298E215E4E43 +:10E200008ED7C5DAC96E0BC1F3A0DAD7589EB4C455 +:10E210003DDE55A1A4F751EE3FD1950B794D5750F6 +:10E2200031F9AB2564EB18F019596EF6932F2F6373 +:10E23000F98A7B8FDF85FBA27B4ACCF9B0B56B9462 +:10E240006B20CEBC3FA45D03FDDD130DBF314B49F8 +:10E25000F7ABFBFBD37D9FB46A1A3FB3B18C9D979C +:10E26000CDF4DB03C54C0F4CE1FB69F66333F9BE1B +:10E27000F7D80E94ABC1593687257F7A79DB5FA03A +:10E280003E0FFCD053C2C6EB7DE5C2DEBB16E69363 +:10E29000851F6F2C65F3B9D64AED667DFAFB11BD7B +:10E2A000FE47A56CDFEFB23266B7FB628132D06702 +:10E2B0005B62212C9FAD4AF57A82782E606C6310E8 +:10E2C000F540F20BB0CEEFDB59BEC56FD18A2E33CD +:10E2D000C4A321BE3F42A2C7E0BBBAFBE71536008C +:10E2E0003F0FFA44F65C8C8E417E69F2B9BE9F22E4 +:10E2F0006952ADE9396F9FA7C9AD867EF471EEFF13 +:10E30000BD3582FA8EDBB9811A651FC8C3C0FB4FC9 +:10E310007AE13BB32F97327FA7BF34EE85EFFC2421 +:10E320001FB56FC067D3D8B7EECA7827AC6B37116B +:10E3300002304F71D69731BFA5BE1EC6F3784E3856 +:10E340008F17489FF7A672FBAB12C33912FD7C5E94 +:10E35000A67E7EA9203C5182F1775201BD92C91759 +:10E360009E761AB7D3FE4BEAC504E4956455417E08 +:10E37000D7F30E4BE0DB5ECAE805CBCDF95A77BB8D +:10E38000399FEB0C12FCCEC1A516667CA76180A953 +:10E39000A0085CAFBA2117E06165398DEFF5BCC705 +:10E3A0002C1FCBF37DC8E9B289DB97C19C9417BEC3 +:10E3B000431ECD6371A76E5FA6D37F7A1C395D9C27 +:10E3C000369011A7CD2ACB1EA70DF0386D80C769F6 +:10E3D0000A6F575EC6D6F7202F873ADE32C569BD71 +:10E3E000659E0EC8C3E971DA6D0F355F8FB01EA749 +:10E3F000919BAF37C5690F79508F5D7C9C36C6BE47 +:10E4000037276DF287FEB4BF3BBD9F2B920F0DE700 +:10E410007B06A739F734566665E70738DD20DE014D +:10E42000BAD178A701E8A6B77B92FBF553E31F3D6D +:10E430003E2201689F1907A5DF677AE6414722ABB4 +:10E440005FFD6111A3B731CFC6EE37E079D3F9563E +:10E45000CC8365E6DBFEAEACAE435A6CCCB7CDEDFB +:10E46000502BD2F9B6BF2B9BBB355BBE2D737C3DC9 +:10E47000CFE897D87EDEE8F27D12C42BFDCBE95BB6 +:10E4800079E93CE2832E36CE87BB666ED59AC11FF2 +:10E490007B0CFDB19C596C5F78C4673EA7711B8FE4 +:10E4A00053FE89E70B77C4DA79FE2E8CFEF358B25F +:10E4B0007114BE8B742E2798272F50C316C88FF661 +:10E4C000C53AB13EA7897D37E98A506F5C81F33B3D +:10E4D0004CFE02A33BD9F9DC505C85B8890EA1390A +:10E4E0009534BD2C552C6F581231CBA9BBC32CDFF2 +:10E4F0000ED50CEFBAF9603BF4774F974B057DD101 +:10E50000EF6F1D83F3969FAA04F5C62E7702F57B65 +:10E51000A6BCEBF31D8891E1EE1C982789AF9C0502 +:10E52000FA22A541BED0E197D11EBF7CF302365F2F +:10E5300042264A40DF455204F8C1E58FE343FBD948 +:10E54000024B18F515617ED02C92A8AF81739A20EA +:10E55000C0008F3D556F385F30382BE5CD33D0BBD1 +:10E5600067D16E15EDD88638F66B4FEE210AF4EBC5 +:10E570008B93085D578F2FD002FCEAE9906B61FF07 +:10E5800069F077D6ACF7713CED65FC385813407CE8 +:10E59000A97C4CC483E7C76BA0694109ACCBC5E239 +:10E5A000254A975CB1727E56FC2C909FD47E66D72C +:10E5B000301FA99AED8ADEFF1ECE67DB97EC46BEC0 +:10E5C000A07CA2592F8332D5A9D1710647DF25F54A +:10E5D0004E588F31B206C60DC64947DEF4F33FAA46 +:10E5E000CF9FE20D79964FE1BBFEC2E9FB03FCBB76 +:10E5F0000B4CFD5E10DE3FF0F2F340B108CAC59E41 +:10E60000D86A2C737AD87E0A5941F87E8A213F6EE7 +:10E61000D8A72CAD62796647069F67EE53E6D8E32C +:10E6200047601DC9A53EF41BE3B1288E1320E37893 +:10E630006EC39D210753ED19A3EF4890F911378060 +:10E6400082F560D96DF1A4EBA7D3C799A59EC70E3B +:10E65000586C61FC8E96A48E95C03E92C53B02FB21 +:10E660007A6F5804D433C777E7A2FD0E70FD42C419 +:10E67000782BCC63F3BCC2BDE017EA78E87A665722 +:10E680006C1DEA8D784CC3F9152D9BA8007F03D231 +:10E69000C890E792A97E01FD3110EBC576697BC178 +:10E6A000E90BF49C09FBDC197EC032337CA17EC0EF +:10E6B00085D2E362E93629FF3CEF9F49AFF37EE75D +:10E6C0007F817922AAC748640E7CE72491482EF006 +:10E6D000A98C65717B7854A47C992332BA7CC5C51A +:10E6E000FA2DEA34D3A33492C1571979964C7AF5AE +:10E6F00070BF6E7CD7BC0EB02F3A3EBADD4D97D1BD +:10E70000C5B07EDB63ABB12CF26B784FD2406CDDD1 +:10E71000E26CEBBA84DB034F9B19BFA248E6BA2632 +:10E72000507FB832BEA7C8DC37D3F1AD6B9E104125 +:10E730001FCEB028029CA3F825F79BA6DB07D2F7D3 +:10E7400079FE7FF1C1B355713C97DCE7CE7EEFD205 +:10E750005FF33CFC4B453C2E172318976FB664F7CC +:10E7600097BAB9BF6FE7E753F5E734BE5D510ACFFB +:10E77000C538C6B7767E2E558FAF2ED6DFFBF24A50 +:10E7800033BC6CB919BE69D9CDA6FE26F30A3C9FED +:10E790007FB1E3DDC7FDF521671CF3A2F6CE437818 +:10E7A0009E1EFA33DE0FD2CFF7512FBE7F8E9F2FE2 +:10E7B00080F72BD8CF58F01CAE817E7D66FA895841 +:10E7C000AFD3AFF04B1DE7BC9784CAC59EFDE7D819 +:10E7D000BFB4DFF14B09FCEE41DFBE7615F56800F2 +:10E7E000CFAF0EDA099EFFD3DBFDA1F31A7226909C +:10E7F0007E0E4E3FC0FB56031F1DE2FCF379F12E47 +:10E800001049B7D4F8F9D7F973F3959FCDCF7AF6BD +:10E810001718A7F711690CECD480EF54AFA710B507 +:10E82000E5089C2BDD147CEB18ECE3DD53675320EB +:10E830009FA5AE4C7443BD3310980F71F5D1521B98 +:10E84000F677A7357C14D67B0689E0773BFD4E260C +:10E850006F5B62445D45E5FAE5BA8304FC6F498964 +:10E8600026A13F6730B000D4F63A9220F07D0EF139 +:10E87000133C37E1088E7989E11CB6B58C9F87BEC1 +:10E88000F92EF4B372F93932B2EC2EFC2EE35AFEB3 +:10E89000FD721CF20F06FDF18F90BFA0EF0DAACC08 +:10E8A0007F2767E8732A130340083A706E304A5A8C +:10E8B000601D5491D5FF8AD5E379368A7FAE9FD605 +:10E8C00083DFD3C6F30C2FB1FA3EBDDEA7D7F37CAE +:10E8D000C3D9DF63FDA0DE7F88F5AFEBCD57DB98B2 +:10E8E0007ECDAD607E5C6E85EE77F5A1DF25291AC1 +:10E8F000FA5DB94AF49C7EDC4B3CAEEA5A741FD2F6 +:10E9000091FA0C51F8EE62F4E4F786619F7BE07DAA +:10E910003BC6D7FD4DBB4DE73EE48AEDC4F83D86CE +:10E920003DC4F21AD3E19169D70C78A13DFBA4F460 +:10E930001FD879CC27EF36AFCB137767AC8B5A66ED +:10E940003CCF30655D3E3DCFBA9C38CFBAAC3FF787 +:10E95000BAFC63A9C2EF13F95DD6F5E97D651FE640 +:10E96000C306EA589EACDCAB207D5FA1F4037EF5C4 +:10E97000F86C2BE0BBBEDE63AC5D1FB4BBCCD06ECD +:10E98000D641964FF3B3763402F4B238F773C7F535 +:10E9900068EFC6CACAB776C178403FB66F80E5D186 +:10E9A00012A6D7458FD486E7248304CF89DF698DEB +:10E9B0002C2C2B82FCEF0A158E43EBDF7BDA8DF9D2 +:10E9C0004892CE47669E5F749D7813B6B3FEE8FE0C +:10E9D000DDC59E5FBCA1ECE2CE2FEAF9DC3FF41C62 +:10E9E000A39E0FCECCFF66E6875759D9FA343EF482 +:10E9F000D6751B3F47DEE762F5F51F214F64E2A79E +:10EA00008BCE53FD91C61D728EA19E70821DCD9B33 +:10EA10006A4777955DAC1DFD3BB4A30353ECE8D882 +:10EA2000E7B2A3053E6A8B1AFF78F3ED87FD31A3A9 +:10EA30003EA97B87E9139E773F1F3D5EF81FA6C75F +:10EA4000C5F26981FF0FA65F56FF7C81D7663A87C2 +:10EA5000F6B69BE50D17C019D30BC8472F83764533 +:10EA6000B8AFFE5E99615FFD8F154F7EE1EC2F30F0 +:10EA7000BF98D3C4CEE5EAF904BDDDC77C7FC45E90 +:10EA80006EE1FB242C2FB28BE745CA7CF12E763C3D +:10EA9000D69CFF285D9D11D72DA37159103FA5C7A6 +:10EAA000B87F3BE43B28CFD5758CC8307E7146DCFF +:10EAB00097191766C6797FACB84D2F2F347E0B702F +:10EAC0003AD5B5E971A66C017F5DCFBBE8F44AAFDA +:10EAD000B7F03F9A77B8503EB8B3283CBB1C92B60B +:10EAE000ADC41FCD4B3F9F22A7B08F430DF401074C +:10EAF000590DFC9EB9AFB6A09CCDBFA19C9F475DB0 +:10EB0000C7CE913496333E76AF63E74B2E2F574CEA +:10EB1000FD6F5FB2E016B8972C6E61DFDBACE3F7F8 +:10EB20006D920E1BEEB7C5F9BD6F32BFF74D7F2F4B +:10EB30006E6772376431C7D3B7703C6EE17CBB3D02 +:10EB40003656CCCF87E07EF3500BC17D640F09ECC5 +:10EB5000B1B071089E33938905E2CB9B003F83FEE1 +:10EB6000923B6C16D8F71E5A4C929087DED1431216 +:10EB7000F05DE6508EBC11EE5118720B018DE25D16 +:10EB8000D37E741CCE93D4ECF4AF22582E60FBA439 +:10EB9000DD667F74E8FAD9B8DFE551898A7EA2AFD5 +:10EBA000D00274D5C75B5A6E37D167F23BED93B98B +:10EBB00049C87B6EEF61F86F7FBFAE14FCE41DA502 +:10EBC0008152F093297E78DF628D7AF531DCF7F39C +:10EBD00015E2FAD7A814AF79E7C76BF25C3F7FEF75 +:10EBE0007C7C33E9DFC01DCF8673C1F158BCF48350 +:10EBF0005970DFD770E9073970FF5702CB03B1278F +:10EC0000B01C8C8D60A9B7CFCC77D668667866AF1C +:10EC1000199EBDD3AC1FF243D9F3A5BADFA58F73FC +:10EC200020F622E2158F25B1DC173B86E5606C0CDF +:10EC3000F149C4C611D6DB678E938967265E997841 +:10EC400064CE43A79B4C26D0DFB77179F210D9026E +:10EC50007EFD4FDC91619043BA34AF6DA07509ED34 +:10EC60001319D63771F69A318893E221CA77F0CE1C +:10EC7000E2142E51FEEB760DCECBE5ABEC3CC9A8F1 +:10EC800026D8C14EC7358F03F8B5FEB9F526FCFD71 +:10EC900012B1837F3FF790F9F95E95ED271510F6D5 +:10ECA0001CE70F07E1BD8C0F5CCD99F348613CE692 +:10ECB0003A5348B482E9F5855E8EAA1BF15CFCB636 +:10ECC000103B57B24D15EC706FDFB6AD02EE23D19D +:10ECD000E778BE05F675E09C0969561186F6708ED8 +:10ECE00059A7937E4F041CCB017A256232D172A7BB +:10ECF0001FB7E6AAC05DB83F543F21DD64881FB747 +:10ED0000853E91D8BD5529DC2FDB16AAC5F323DB40 +:10ED1000BA53EDB07FA2116904EE8D9117D76E87BB +:10ED200073CF745D5E2F473B3EF1327C579A1F6272 +:10ED3000F7AA3CBE95AD4FFD7336A218E833F790A5 +:10ED400019D6E94816CB788E251FBE836B007AB39F +:10ED5000763ABDF3B77A04FC3EF63EA2C0F7FBA4B8 +:10ED600039533ED97DAE3540F7F910FF34F1EF4805 +:10ED7000681C34234DA79F5AD55F001F3DC9EDC4C1 +:10ED800053FA7E3687E3BC4CF0F2002FBFCFDBEDA9 +:10ED9000D3F71F8F2DCF07FA7C8FC33B78A9CF679E +:10EDA000EE7EC1F4FDD9BCE71CA6EFD3F2439E8CE6 +:10EDB000FB97CA4CF5355AADA9DE7F828D37DD7AD7 +:10EDC000CEDE691EAFFE90C304CFECF564DC4F9439 +:10EDD000407AF91F2E333D2F68378F3BDD78DAB24A +:10EDE00099EF82BE7535DB14D8DF7035B3BC83ABC9 +:10EDF00099E9536294F75A13FDF32B8AD2F4D6E9BA +:10EE000095638DC7671ABE531884EF18F2D2EB4A88 +:10EE1000C470C0F81DFF14390A31398A3733398A72 +:10EE2000874EF5C2779CF114BBAD3BDECCE4B8E76E +:10EE3000F2FF62FB7BDF4961FECF95FC18F7F79E7E +:10EE40008ED139CD817597506E5CA11489D0E7F9C8 +:10EE5000E2C446B06BE4255203FB5BF912D904F31C +:10EE600026490AC33AE6918D086BBC5E9619DCCD43 +:10EE7000EAF7811CCE49CFBF36A408909FB80CBFDB +:10EE8000C8A771E7C38D83C0CF0ADC90698091A5C4 +:10EE9000A9BFD24461F0575E3C9BDBDE144CEB39DA +:10EEA00071C3143D87F2734F2B5DBE2C7A89D2FD5E +:10EEB000CA8AA634DD75BABD18E2F91AF85708FEF9 +:10EEC000A5BC97DDEFCF6097CAE07005CBD751792D +:10EED0005F5AC1E41DEFAD7D31A5CBB9596F66EA2C +:10EEE000D14CFDB90AEE5C64E7EB98BE540515EC15 +:10EEF000AE8BAC4DE35D8378DF0CFCF24C86BCE658 +:10EF0000C38D3854CFE59F142C40AC8657342BE08A +:10EF1000A1CBA3D71DF93AE0D9F05C4270D175F1CD +:10EF2000BF186F8569FEC4ADFE293CAF7F6EB989FD +:10EF30003E730F99E102C2E04C7D1F7849209A612F +:10EF40005E359A836826BBE731C193E7986371F415 +:10EF5000EB0FC586313EA0761FCBFD45EFE0650C7B +:10EF6000780FEF22B8876A04ED9F830424282F09C5 +:10EF7000258E40D8320287E7683F75235A2B8433A9 +:10EF8000737AC39C49089EBFA87147D6C3BCE4618D +:10EF90009B06F92A598D639EA8C7F367A3F0FB016E +:10EFA000D49F0ACCA15D784415EF65223E9697B5B3 +:10EFB00027FBF05E45BB4A1AE09B3FB81E12FDCB13 +:10EFC0009DCCBF2C5D492CC67B28641F696179F9F3 +:10EFD0007099D16E1CE07EE6C10D7172533DDB3736 +:10EFE000AFBD14F0E67E26DFA7A1E1219E0BDCE495 +:10EFF000F4E2FDC03D7B6C2DEC3EEC31B68F1C2461 +:10F000000D2037B29464F79F07284CF196F346F829 +:10F010007DE8BC5E4E30D8CFEA737C6102F7FFF525 +:10F02000ECB9FD3D981FC55399533375FF5E1653D8 +:10F030006C9C109357599A60FD34337995F392ADD7 +:10F04000088FF07A798CC1CFB17A2AA908CBBDA4F8 +:10F050000672973ABDE794470E019FCA71DB494695 +:10F06000FFB0C0EEFD66EB13704746B2ADCF9C8794 +:10F070008936831ABD4B0E31793BC8CF2BCC7D82AC +:10F080009D5738C8CF2BD4ED27F89DB40EFB138CB9 +:10F09000257598F6431443BDBE2E076745CA4CE755 +:10F0A0001B387DDC2AA38F9CB45B803EB24A2CA027 +:10F0B000EFDCE28880FBEF87D87CDD524280F8836A +:10F0C0003CC1E8E1CE8BB3FAFD1C9635062758FB10 +:10F0D000396A14F5DBC169F2DCEBB81EC90F51794E +:10F0E00030C8C99DE59177807E978E50F930D9ADB3 +:10F0F00084A99D9FF3E7816101BFD73CB0B3F69C23 +:10F10000F7DBFE650C9002BD2061321BF4313987BC +:10F110005F347313B98BD99DC07BE057F62D526ACB +:10F12000D1BE25DFC573362E55690439112A591C05 +:10F13000D733F09F684FF2459627CF0B3079C997A8 +:10F14000183CA39EC3792C1E74F8392CF37B360A25 +:10F1500033E42B44E50BF7F3E25EA3BDEBE3F233BC +:10F16000D3435618CF65E978904A7D3F97F19B3C91 +:10F170002C68F05DFC8EF2C867C877937C49902FAD +:10F18000854AA67F9F2A0F0B95706E6E98DD973F7C +:10F190002F38D10AF35C384E14D8A776562AD8FFF8 +:10F1A0009C7AED08F07DD3187B5E5B18B0029EFA66 +:10F1B00038B28FF55F5C117156A21C6CFE351B2FA7 +:10F1C00085E720E7BFCEF87CE109C6E77D8B189F75 +:10F1D0002F18677CDEB788F16DD371C6E73A1C1C27 +:10F1E000637CAEC3B41FE4731D9EA4CFA2B837CF17 +:10F1F000C0073DB3768F9F9BCFA356E4EB139C8F44 +:10F20000A58815F9789CF37D5E98D51FE7B0AC32E0 +:10F21000788CB59FAF06ACC0E77DC0E7946E07C59C +:10F22000F04F802F0FEEF45834831F2355327E3F6A +:10F23000A88AEDD9E4619CCBC3CFCBD5465807FD56 +:10F240005EB4838B6D2333E838BDB5FD812360E761 +:10F25000AF7420DCB76777E20E281FDA3D720745EE +:10F260006770CF87080F3EF421C25B2AD97D16F95B +:10F270003FCD49CC80EF3CAAD67D04DF67F5D64868 +:10F28000F87E6EF59AE11500D7E68DB0B45844C00B +:10F290007DF4181986BCF86C312240BC3C5B8BE3D2 +:10F2A000BD67C44BED047DCF55C1D62D7798EC8555 +:10F2B000EF9672BD64B8DE20A72D957A7E4729812E +:10F2C000FE26FB2122F23D911BD1BED171E23E838D +:10F2D000FF715D25FBBE38DFABE1BE97AD82F11754 +:10F2E000ED3F5E9FC58E6E0BA696A27F45A4091AC0 +:10F2F0006B4CFA55937E60701F7E7FDC1F3C85DF70 +:10F3000053F9A504BFA785F97F2D4DA7F1BCE06097 +:10F31000F0343B2FE867F1D5DA26165FCD82738D86 +:10F32000346E7336537FC4F03B3A0EFADC788EC0ED +:10F3300039D54FF95FB07E8F713FE5615E56AF9F63 +:10F34000E8057B53478D3CE0BDADF9542FDA0F8BB8 +:10F350003402703E49B43A20BEF9368DA71493FFAB +:10F36000721FC85155546B857DBFAA7571945BEAB5 +:10F37000BFDC0FCF1D3BA91D9937D58F71EC1C51F8 +:10F38000C1FFCEF46774FFC5B193DD179CE9DF3888 +:10F3900076B2FB83674DC6AD0976EFD9CE94CAEE3F +:10F3A000172E34CD7F920E6D89247C3FE26AD9F905 +:10F3B000DAD5602F49C0A2C27E1DAC0B1DAFDCCEDA +:10F3C000F3554BD9F78AF9445E0A7EBEBBE9742F28 +:10F3D000B82FBF793F17F5CE9E3C62928F5D5C9F40 +:10F3E000EDD6F94A0E94C23A3EEF561F84F9537A8D +:10F3F0000F439999EF1B089E32FDCECA008F23D48C +:10F40000F05E769F6540C673E3FAF7C633BCECF74F +:10F41000B31EE7E3DC69551F87751C0DB27862C027 +:10F42000CFE28981D05BC82F039C8FA6B31F0E7ECD +:10F430002E5687FBEF7074827FFD5D7E5F93C391D4 +:10F44000C0DFEF7A968FF7229FE78B1CEE5DF6CF39 +:10F45000EDF83D018DFB012F67A831EBF7040F722A +:10F46000FD3DF9FB1121761FCA53E591FF83FCB1E5 +:10F4700046447D0CF606FD908A42939C649693F771 +:10F48000C575242C705E4ABF57D5AB28A3B8BE21E2 +:10F49000D68F037EBF250FCF53B2EF06FDF25ED8A5 +:10F4A000A7F446D8F957478B8CDF63BECDF59E3B5A +:10F4B00034A102BCB932325669C81B3AFC2398E722 +:10F4C000D3EF1B3D1F5EDB558FBB8D42AEA522FAED +:10F4D000FB1E91F159BE98EAADA574F24AD15F6C5A +:10F4E000003E53D9BD238E3A9F1BF0F5E699F3B049 +:10F4F000296E2F4FEA7C5548F9CA897C750AF0A31A +:10F500007CF5CBEC7CB5C36EE6AB913BB2F1954A92 +:10F51000CC7CF5AF69BEFA57235FED6863DFEBEC97 +:10F5200008D6DA819F76B4B59EF3BEE1E9F80A34D5 +:10F5300009E46507821BD18FDFDE5686DF73C1F9D0 +:10F540004063DE89FA01A4CA00536232FF94D37F7C +:10F55000928F78FE2493FEBDCBBEBB14D77B25E7EC +:10F56000CB95D9F9F214F065D385AFAB6BE518B143 +:10F570002970CFAF82EBAAEB0DB122525245FB7935 +:10F580002494588AF1B74050DF3FEC27C8E739FC94 +:10F590007B1DB5C36201BB3C9D5C57554DD2BF0A74 +:10F5A000FAD3F30406B95E3A07E090887982016ED7 +:10F5B0000F3E6D26F83D99BB497C6D03D8D7E827EF +:10F5C00061B89272BAF58063EDD146B8CF90A8B910 +:10F5D000B48CB7FE8537722E3DD1B6E326D0B70F77 +:10F5E000ADDE87F7A16C3F94A3407EDFB1F6D47205 +:10F5F000784EE3EC85B05E43FEB13E8C570481CC7F +:10F60000B892F2FDF5C28DD49D3D6FFCAACB3B694B +:10F6100066F175A6BE77F982EC3BBB8C3CCDE4EF7E +:10F6200022713EF076C8B07332A90FCAD5C428C87B +:10F63000B32B14477DE09D461FB8DB1228178E556B +:10F640004C1F7CA58AE9032FD7077255E4A62A939D +:10F650003E902F4A1FBC3D9FE19D0367C272516ED1 +:10F66000BF0AFD65CA6D66A9DB83017EEFDAC1764C +:10F67000C5740FDE3ACE2F6285BA12FAA37CF80D5C +:10F680005C87A2437D609F89A8A07F3D6449B1FB50 +:10F6900017F6307D03FC08BF8FA3763C83F7FA4D45 +:10F6A000A70FA29C0E941FA3D0AF1C62FEF3972B52 +:10F6B000236B613C7935BBDF4A56C7D06F26CD63DB +:10F6C000B87ECED5D9E54D26132ADEF7BCA270E967 +:10F6D0006C8A9F7BD569693641FEF90EF4E7BA83DF +:10F6E000F22F01FF5ECFD35C5CDE637498C9CB5010 +:10F6F0001B9397A16101F7591E0A32F9000CB4055A +:10F70000E9DFF379A86D5FF260909D4387EF920F78 +:10F710009EFD5E12F4F241CADF70BF8623725C83E5 +:10F72000DF5393FFD68EBF07E3587D7A39DEB7CB20 +:10F73000D75DE73B713DD747C32C7FEF0866DF2FCE +:10F74000B8507ED1FDC4A83B9C00BAAB10275D8A9F +:10F750007CB3B72A4B3E7230B44336C69583B6703D +:10F76000209C65FFCF45A8BD84F83028E23AEA72B4 +:10F77000F24855F829A47F88FD6EE9A4BECAF44377 +:10F78000406119F8E3B9B4BE7A0EDE2FAE081F4609 +:10F79000FC7CA79F38A85CF87C1D1D0101F4E94C96 +:10F7A000FFC82DE82F0B5214F4A701BF23D0FFCCC4 +:10F7B000ADC93EF0472BA93F0DF735E458539837B4 +:10F7C00025F7F37B1E29BFDF6888437FC5F997CAF9 +:10F7D000C731783FB33DFC660ADC4F67AD677A40BE +:10F7E000ED684812833CBC3939BFF09B55E8BFE84F +:10F7F000BF539A3A160B023F08F8BB65B444FFDBCF +:10F80000017EB61E67303FFBEF61DC44C639A39929 +:10F81000DA04E6C36AD69123706E48CFDBAB246965 +:10F820009F03F9A07611EFBBA07EF549783F7FD604 +:10F83000FE23D06D5DB72648282FEA29C0E77CF269 +:10F8400021AE1FCBAA4FA793CFD1B5CFBE0B71E886 +:10F85000431D04EF93E9F9E6C1A5808F63AD402015 +:10F860001F5790EC43F92A582DE03DED8FAC66BF51 +:10F870005332DD3A6FE3F98CED3C9FE11027922281 +:10F88000CB5F611ECC2191518C5355962773E4C9EF +:10F890000C6EE3F5B282DFC99076060F403EC4F0ED +:10F8A000FBA1CE8E14BBBF55F524F13B8466C1F499 +:10F8B0007B16AE28FB9D323D3EF0B439CCF5F0F11D +:10F8C0009E019EFC1D32DFDDED603F257FD80FF9E4 +:10F8D000CE37AB239EEA26BCEFB00BE23D5216407A +:10F8E00079D47F976989B5391FEE4D8683116231CE +:10F8F000ED97E7A46BAB99FFE654D8F74AB60E1222 +:10F9000048287065794483FD6A69350924099EABEE +:10F91000216D39304EB80AC69194B8E9779F32E923 +:10F920003AA79AF1B5FE7B0D440CFBB3EDB7E8F2B4 +:10F9300055ED0ED75517313C219EDC4248D6F8FED6 +:10F94000CEF2964BAB315FAE1E83EF6437D710DC3F +:10F950002FE93EFB2509F61F36CFB2619EFFE5EA8F +:10F960003D3774F9689C40F1EEC0EF6B6849F1EFE8 +:10F97000CE1BB905F60592D5446B6BC6DF3F6D070C +:10F98000BDDA5A9DBCA190E2B90598B78C904DD5CF +:10F99000A96DF8DD35879103E8DFDFB5EB70EA8606 +:10F9A0000B799FF0FCD10FC4C8D580B7BC46E2F9F3 +:10F9B000CA400EE8B1B7F8791EEF1AD22D1BBEF37C +:10F9C0004D72FA79791ECCCBF35F5E7E0EE276BE85 +:10F9D0006E77F33256CDF440E94AF95DD4875493FB +:10F9E000E2FE7D4E027F5748AB63F7EE96AF49E2E9 +:10F9F0007DFA72B3CCEE6F2513687F3C2B993EF9EC +:10FA00003AEF87FA135F83F570069516B8DFC6AB39 +:10FA1000527D06FB22ABE52E886728FD58BB3513C7 +:10FA2000781F9907F436C4DDCDACBDAC32FD47E399 +:10FA30009455306FF7CA090DF8D2D3CEE214FDFD0C +:10FA4000F8372955F369C9E950BE86F9397207F3C9 +:10FA500073747AFC6F4E8F1F5585BF8574E4F65C16 +:10FA6000EFE77B55E1BB187DC7349B01BF47A0FF83 +:10FA7000CBD2BF9F9C39FFD2956C3C171FEFCFF9BB +:10FA8000386D55EA9FC1FCF57E8E5446BEC3FA67B9 +:10FA9000F375AD0C74C195347ABD5EFE9727BC1129 +:10FAA000DECB5F93C276FA73031F6CA92E9A9E0F6A +:10FAB00032F95DE783F26AF6FD79F94C55807BF700 +:10FAC00086EF6D7C1CEE5BDC1EB16D0D50FA1DA83F +:10FAD00066E7CBBFEB26B7801C0C6FD0DE857916AE +:10FAE000B4CBB5707EA420F9833BC02F2F503DECE2 +:10FAF0002E42FDF7E0400FD089C7DB989FFE493BBF +:10FB0000D90B799BE1DFB1EFFF86AF27CF6C84750E +:10FB10004BD65960FF617803FF5E18F4A6F1772099 +:10FB2000337EF7E2A56AC564D73D1D4C4F4EFEFEFD +:10FB3000857BE463C84FC597D814B8AFECE525EFD3 +:10FB4000BC06EB30D4655301EFA16F7608702FEE41 +:10FB5000F61601F348DB37C8381FEA3FE37CBCC91F +:10FB600077715FDF7BACC0341FF87C8FFDBE9DFCDE +:10FB70006E3ECEBF18ED9F97AA33F81D0C1DEF8285 +:10FB8000E4229CCF0E3E9F697F172312B0187F1787 +:10FB90002309F332F8D999BFEFB0392782E7C83388 +:10FBA000F5D074FAECE7E52D7F536DD093E7F3437E +:10FBB0002EB81D515D96627D4B0BA65C23C0FD10D7 +:10FBC000FFE1B5E23DB94BAC79B8DEAEF5EC7C4F68 +:10FBD0004D87EF08EC7F92489E0A7E8D8BC847E0E8 +:10FBE000F70AAB5BA4090DEFD555F0FD72FE7E4D13 +:10FBF000AFF97ED8CCFB62CBC9D65F433EAD3AE3CA +:10FC00005ED872B81FD705F5E6FB63F5DF6FD4E366 +:10FC1000D5CC7965FEFEE3BF5567FFFDC7E9E8A2D5 +:10FC2000FFFE639EA8FE07C8DF85E66FE006A3DE41 +:10FC300020FECE239EA370298A2ECF78CF5639A7D7 +:10FC40006F19753B451AA7FE3F84B140FD00800047 +:10FC5000000000001F8B080000000000000BED7D7D +:10FC60000B7854D5B9E8DAB3F73C929924933079FC +:10FC700062E29EBC431EEC3C084111262F0D8276A9 +:10FC8000F28280018710639090335AF5A4AD961DDF +:10FC9000823452E4C44731B6D83349C1E658AB8107 +:10FCA000C616ADB5C3B3F6D4B69187D24A6B042E4F +:10FCB00022624FEA915B7A0ED5BBFEF5C8EC3D9906 +:10FCC000106C6DBFEFDE7BA65F5DACBD5EFFFAFF23 +:10FCD0007FFDAFF5C8BEE8D2A8311B429FC26FE1DD +:10FCE000E454ECFA416155B1266FF30B9E3C847FDE +:10FCF00055F6B3D90809AED3E853EBD4ED11921001 +:10FD0000D483DFA72242460752AD51084594E00F45 +:10FD10000E843645205F9E13219B8290A504F2A39A +:10FD2000DF87BC158F61D7E4C3711F098E401EF7B2 +:10FD300083644D391F6F53842BC1A699CF43D137AC +:10FD40009E30E37A620292B304844CFEB5488EC0C2 +:10FD500069820779F2F177695415705FA8043977E1 +:10FD6000C9386FF1AB02C0A6E03C82F90ED37C1E0D +:10FD70002BB7FB683E9B961B13DCA81C8FB7E92FA3 +:10FD800062D3705E88F9CB0684E6C0EC55846211BC +:10FD9000AAB67B37E1B150359E5E4F2142F1CDEEE0 +:10FDA0004D80871A3BB28BD150CF47EB5FAEAF820D +:10FDB000EF5F5884EC5BA203F99BBE8C10E4A3AB0D +:10FDC0005C06C85BCA0C3E11CF6B5B595D94E70AB9 +:10FDD00074FC970D08F9B3107A6C8305F9CD93CBB9 +:10FDE000ED22F202FC8F567E159DC2FD986D7D09B5 +:10FDF0007538BD5516083CFB32EE4F003E79B2F225 +:10FE0000DB24FD5A465B02C609DA9CB81D69C70DA2 +:10FE10009391CB17028E3DAC9FF44B775ADC18FFC1 +:10FE2000DB120C35BE50F842DDA4DE36CB98C56E31 +:10FE3000FBFBCD6BEDE7342FA3532074DD66E9B3F4 +:10FE4000D871BB87D33F2F783BD1A93C80ABD30F70 +:10FE5000FCF2B5C4CC54331E4A95E978BCFEBEC44E +:10FE6000B684318037F9FE0404F027B7E9E0364D57 +:10FE700001770187DBFE8F81BB7F5AB8EF479E1069 +:10FE8000FC6006F8437C5FE6A4F4DB96D047F8E418 +:10FE9000EF0DFFF0E70CFF49D6DF3CD94EE72173A9 +:10FEA0007E370830EE450FF28A8553AF17FB7C038F +:10FEB000F273B98AFF3FA3261CF92D817C6ABA3BF5 +:10FEC000CA9D3F353ECE337C4CB7BEFE00F530BEFA +:10FED000CE01DEB2A0DFB1CDD761B97311A1F12D92 +:10FEE00018F4BBCA0CAAB960EAF677197D71F62B33 +:10FEF000F4BF6E48D4CD633A78EAE55482B77FDA2E +:10FF0000AB6FB7D667D5CD9FCBDB87D3F5F8E47859 +:10FF10009E44FFCF099FD3F1E1B4F84CC7F88CFCA5 +:10FF2000FCF0391D3CF36499F0DF74F80CE6CBA9C2 +:10FF3000FAFBFF952FD75E251E83F9F1EF8DC7FFE2 +:10FF4000DBF851053C5EC5FAFE1F3C5E199EFEAB18 +:10FF5000C42397934326D40EFA2FEBE97B8F2CC250 +:10FF6000701FAD292E1671174872E5D763FCBCE2ED +:10FF700034917AD886760F8718F715A68F8FD454C8 +:10FF8000AE07BBF4A2DB8AC02E3D66507E5982E9E3 +:10FF9000A4D6890AD8CBC1ED8E30BC7DCB194DFAE1 +:10FFA00047C8153107B7AF3B2E166D09519FA7A85B +:10FFB0004633AF54F86F78208FFD8C2348AE30E085 +:10FFC0007ED463A26F970070154784D2CF9CBEC7C2 +:10FFD000DCF57F1B7DDDE2E72A6FA683678BF36A82 +:10FFE000F5601FF33F5C02D065E8ABD47FC08E891B +:10FFF00011EC8ABA936655C4701F874F8908BD24D7 +:020000021000EC +:10000000B90F3A71BF7535854618FF88113501BDA6 +:10001000B11BE782F62DDBB206B7607CA2867A526E +:10002000FF75A7DE2E9AA00FE72B03E62B1BF839EE +:10003000B271B5663E8E5403A3B79A0C708C985C6F +:10004000B9DF07BEAB332B83F8ABB97EC9D7C14745 +:100050007C7365B460D6F0C17B6CBCD2666A578D88 +:100060009CF01A0D9A7EA554CA87E6FA8E956321F4 +:10007000E87D9AF1E9B21A81B4479227B94EB3FEEE +:100080002353F5E5C1ED3F764692F237058A97E0B6 +:10009000F2FF60FDD7355FB93D6A9881952FCC5F3F +:1000A0004909257F38FEBA9D9E4B408F13829A7C6A +:1000B0003FACA36F8429BBC8BA1C4DA98B08E001D3 +:1000C000496EE2577E61B11CB3A590AC5B11E86547 +:1000D00012E58F20CFE1E2E3C6E07209D79FEB4241 +:1000E000DE6E5CDE625056A1B490E35B52AF30FE30 +:1000F000C43C2457398C37A313F357E1E479F1FE5C +:1001000078FD637FAE5C0CF08E1C31D8373AA7AE19 +:10011000CFE55266BF9E7F7252A95FED00BB9DF096 +:10012000A79ADC1411284F4B0D23ED3F2B5FBD0523 +:10013000B0E07E339F508D32EEB709F33DEFBF4EF6 +:10014000D3FF28C3E735207B62010E357C16C4112E +:10015000DEA2726E68704B7228797394F91F6F3843 +:10016000B3497BFEBDC15D7EC85142F82611E4EE65 +:10017000C8919B49FB656CFC21939A5C08FC6E520C +:10018000D6BBF3AE7E1E1CDF53C9118EE791136EF2 +:1001900023F831790D02F1171B1BF619D6E3748091 +:1001A000ADDF77A1AAA69FEE5481D1C7D313A6E0F5 +:1001B000FAA9998FF66693F58ED07508DD3F38EB76 +:1001C0005115F872D30C22271A1B6A499C23B38657 +:1001D000C639464C589E60F88FDF10E1DB08F2C448 +:1001E000E22ABF0FE73FFC240A6D5102726BBD4942 +:1001F000CE04BEE4F2EA25C9B33C754E406E4D9282 +:10020000539BEA193FCA997521D7D546D22FE7AB40 +:10021000215F5DD41A0D5F3D966AD2C9B337997ECE +:10022000381AE437369CA07EF58889C66F7EBBC835 +:100230001EBD91AEBB6E58275FF8F45A01E6F11867 +:10024000E3D38BBE23CF2343001FEB076765A2D404 +:10025000407FCB9AF4729CCFBF718955FF9DB5CF7B +:10026000165DEB605CB4D82CEFC2B476D42C23EBD3 +:10027000FFD3C5C80EE54326F7C608FC3DB3E18FA2 +:10028000F79271595CE943D3681BC527C57FCBA0A2 +:100290006D600BAE17DB33769F1BCFE7639B3B2A6A +:1002A00046C3B78FA4EAE53BD7D7500FF4599D2436 +:1002B0001B43E9B5FA1A3124DC26B37C562B67823E +:1002C000F930351D91B8E0C527C27C00D772A41A59 +:1002D000A1FE32E4BA81C23D6E04397192D185B774 +:1002E0003F89FC1173413ED588443E9DF4D647B505 +:1002F000E079341B87238A70FA5D26D7DFBE57ACBE +:1003000001BA9D63F3484D1F3D545A42F4F845D05D +:10031000E3CD3EAAC79B3BC477B5F6DA4AAF7E3E33 +:100320004326EF914530DE57E978587EAD077CBE15 +:1003300083EC5ED0AF47F0FC89BE75CF24F1B9A342 +:1003400006F99112B047DA787DCC2A710879E83F36 +:10035000D1D266E59112FCFD27A94E02E79A275CEF +:100360009BC3707EA3B580B41B7B4B2C12D1D4EB06 +:10037000D8F380A8D3FB994F84EBE02D6DE2FACE41 +:100380009FBC4AB32E2232AC04EF4B1B42EB2B5BDB +:10039000868D941FFD446C0FA5EF5233285E1BB76A +:1003A000866E9F9A1141CBFB849071A87BD2E9F8AD +:1003B000481A4E06BA363685EEE7A934AA374FAE4C +:1003C0007F6FA5CB0676255DBFBCFCEB69148EF56F +:1003D00069D4AE383A78F3E104A04FA760CFC07873 +:1003E000FC306634136104DED671B709E46A1BABD6 +:1003F0005F20BB4F833C5973A2C29408FAA8192905 +:10040000821C900FC1707CC0EC9680DEE17AAF2F29 +:100410000CF41EFEE7197311A9A246C500DDD5BB79 +:10042000802FD4C1703BD8A1984F7E09F4F4BCA5AD +:10043000B76FFFC4F8732A7AB66ED5DB75EF807D8F +:100440005B12B06F8F9AC67F09FC7F14F35737F0A9 +:10045000D7E5E2FC5A8DBEE276EED125C5844F2F5A +:100460002EB11A802FA7E2A769EDDD25E2E7EACFDA +:100470001C5D42EDDD771E288E6809D14E4E735EFD +:10048000957FFDCE0357B69BDF617838CDE439E721 +:1004900023B0B75B34F4CE49D3CBBDA656FDB84BE1 +:1004A0009BF5E3F2F571CCDD130E760A863813F86E +:1004B00099DBBF6853F1347A98C6BD393C587E4801 +:1004C000944ECE41D149FD17C0CB75697A3E099E45 +:1004D000CF5103E6039033DF96889CC9D8BADA90EF +:1004E000284FE6BB1B83E677B57CC7FD652ECF831F +:1004F000DB07F8EC6FF4A7FE4EFC3535FE7D57C5E3 +:100500005F7CDDDF260D1BE7E55179B216A763A9F5 +:1005100016D27E2C5526E96D58BF021DB1A5585044 +:100520009B0FF2281CC1BE91FA43AB2F03D3F358A3 +:10053000DDDB995A787A183D1AFB761F4A40C007CE +:10054000BEBE58A0E3FD22027BF27727F63C04F9F9 +:10055000F0370C76904F4B9BCA899F5C7A0CEB0569 +:100560009C57D3A2A99C6D586DD4F61BCCB78D4176 +:100570007C7B2195C69F03FE03B21339C6E6D9DA08 +:10058000577818F6DD1A3B1E9D07E3B46EDD67CC85 +:10059000C1DFEF49A3F3FD629A4CE06E96D87C2D43 +:1005A00078BE58EEBC0DB20EE6FB2581C827248D1F +:1005B00019B5F26895F7BDEA50727C0FE3EFA79981 +:1005C0001C2F903DFD69C44F749378CF875FA6F0D0 +:1005D0003536DC2DC03C73C126C0E5790C0E3E0FCC +:1005E000D362BA6FD6123E7E2FD80D13F8ECA4F862 +:1005F0007CFB44DD43B12553E3F3D9A07576B5F810 +:100600003C36B8828CAFDE8CEC193A3B37D9077E8A +:100610004E6E1AE50F8DBD2B00BF737E78FBEEF793 +:10062000567A74FE9C3D1AE69B2ABBA3808F5E4DD2 +:10063000A778793C02E9F61B7FCBD61D5F9F27D7B1 +:100640000A7D601FE3D437237272BDA9D6C10A1692 +:10065000DF19BAC7DC3E1862BD18D2295EF038D562 +:1006600080CF8B7D82B2854E5F67CFAC39815E1DB6 +:100670009335F6D954F65A03F59702F69A2FA20845 +:100680008FFB3B86FFDF82BD96A7B3D71E2A7584FA +:10069000B0D7DAB1BDA689BF04DB6BC791FB963931 +:1006A00030DE123ADE3153DF2DD0CFD1AFA615A9FF +:1006B00050DEF03891AF17D9B84799DC3EDEA0D7AD +:1006C0000B1782E4E6247979421F5F9C4ABF5C0CD9 +:1006D000E2AFE9F40BB6E79341DE1D1F685E791FB8 +:1006E000F0F140B892214FA6CF68BAC8EC9F70C213 +:1006F000775CDE70BEC3FEE38723B8FDF117139568 +:100700008D32C8C5CA72E86FE8F2B58288F13954F3 +:10071000676D073B6D88B5FFF01B3944FF0CF90C82 +:10072000541F75607D84413FCBF880CB093E3EA7C6 +:1007300013D747D1E916024FEBD6778D329EFF2AA9 +:10074000EE4FC3CF01FD270E403CE96D039317CF59 +:1007500044F87639A95FA6C5D7CC743DDED7FAF444 +:10076000F80AD653BFF1A54EC4FF329C81F1D6F4EE +:100770003907B768F22BBB9C349E85283F9CFC97B9 +:10078000B4A22D72408F0DF92AF25F047EF35A89CC +:100790005CF8ABF599EFF38DFF027EAEA4CF9AD251 +:1007A0009D57151F3C8D500DA1C7E5E25F95C1FC1B +:1007B000EF9941EC83D35B29BF2E62743E69F2E767 +:1007C0006BE13BCDF0F33B36DFD33E03F1ABB09DA5 +:1007D0001159ABF12F5CE9D4FF3DC9D6135FE7BCDB +:1007E0007C69105D5BB7EAE15D75AFDEFF5D936E1E +:1007F00027F54F7A7BC2414E1EE37CD346EDE06382 +:10080000EE4A22C7878EE9FDA535E99FCD9E5B2183 +:10081000B888BE410F22B42B1AD69FBC11ECEDA1B3 +:1008200037C5816E8DDD9C9E61D0ADE309399C4D4D +:10083000E530D8095ABCFD8CE9299EBFAD3DC84EB4 +:1008400031C80611F8F64D91AC83A3B7DED646D772 +:10085000491822EBD044E73BB431C2D7ED0C31AE9E +:1008600042C75D21F974E33ECCF861CA71A7B18F2C +:10087000FEC71FD1D7DF93FE8FF5477EFC19F9F72E +:1008800050AAACF3DBB95F7214EC1347C03EF98297 +:1008900079F4EC08C843DB6801C4D77ECFC659B3EE +:1008A000B596D891470DEE8722A0FE11831DFC89D5 +:1008B000D213D48F58C3EC240E4F6E903EE3FA66E9 +:1008C0003AFD88D709D167177D3605E4EEF1C66594 +:1008D000C650F85A7A6926F2CF08E4799C00D659B6 +:1008E000BD46DEFC779A898CFBDF41EBACF1520A06 +:1008F00069CFF5D59AADE5243ED0E87D34513B8FE4 +:10090000034C5F1D4CA7F04FD8B512B56BA78A9367 +:100910007D94AE9FFF7146571E276B94DC21E364E4 +:100920004B1BC420B943ED2F989776BDA02039C347 +:10093000FBE772E66AFBCF4BA3F293C7E152F37079 +:10094000FB88A9F973621C562F789C4F189EA61A33 +:10095000EF0D888FCF993A7E5494C1F67358FCE816 +:10096000E8ADD713FE3A5677603ED0E59D07FEF31B +:10097000F8329CFF4DEBA1F920CF8B209E140BF297 +:100980000699487CC723107B6ED9D6D5C644B2DE03 +:10099000FE93F8BF478FA511FE54587CEAA849D1B1 +:1009A000E9AFE075F71306E791543BDB971A26FB96 +:1009B00052D3E1E7B741F8F9ACF2FE277C3C2C1F9B +:1009C000818EFBB83F86FCC957F2B327F882C7EF88 +:1009D0004DE876E0CB11C96505BEEC42D4CE3A6B4A +:1009E000391D77A618A1B6B00FE2CEE0AE5AC0D638 +:1009F0009987BF4784DEBFDA984DE9E1426AE64154 +:100A000058E72852D9E28073942AD143E30361F670 +:100A1000415CC5B9AD9BE4D7F8CCF6302C3F4A8E8B +:100A20006E2D85FAE10252444C97D2D18AEFC1FE75 +:100A300044ABCF2A235CFF7226DDAF6C5FA0FE1EA5 +:100A4000CADB07CD32F843315B0B4D6017EE196AF4 +:100A50008954313C07FBD744C239BC67616AD7214E +:100A60003A41CC4F67E15F49F09F738F55E1FAB38C +:100A700062470C368CAAD18C738F59703F0F75BBAF +:100A800013EC589E6DCCF03F66B901A1B838D7E899 +:100A90004205A15732F6D741BE308DF777A0CE354B +:100AA0001FE3E99B2CAFBEF618E47F6CF038055CC1 +:100AB000FF4CC63B7512C68F2454151A707F67779A +:100AC000E53F6E49C6F07EE7E1D22FE3F1CCCF8857 +:100AD000F59293ECBBB1F696FA4A09CF733E834F79 +:100AE000B5CD80BCC3EA960DD86FBB6FD7CB75125E +:100AF0006E3F12E3BA1BE1BCF39997097C651E5E59 +:100B00007F0669CFFBFBE2AE971F53D331C9BB2AE7 +:100B1000D1694CAFB23195F8B9E72ABC95121EBF26 +:100B2000F199D8C7F3C2109ABBB5DC8A707EE53361 +:100B300079F5E642B2CF5528E3F4F6676613784BB1 +:100B40009BD55908CFC7848A1FAFC1F35827D275E8 +:100B5000FA88E5881BD6BDCDE251CDA097F9FEF00D +:100B6000357226F0EF443E9BC6AF26F20934FFC62D +:100B7000CFEF6A25769105D90DD7E37CB4270FCE48 +:100B8000CFAA895685F8F916CFAAD771FE0DC17E76 +:100B9000F79612C267C48F385B1D3F08FB3CB767EE +:100BA0005038F63F7567CABB785E6F3C159FBC1A1C +:100BB000F6B53652FE0DE6C7E42CEAEF8E84872E9A +:100BC000FF21971F6C1F34EA04723D87D343E0F77F +:100BD00063380C68F4C16ED80FB2C8992B31FC3E53 +:100BE00016CFE6EB86B74BEF8E5201CE25BD39C44A +:100BF0003FE0FD8F30F991A6B0F839F24BF5208235 +:100C00004403812756146EAFC5DFE3C29167374EA8 +:100C1000636720925F8297D06E5C5E9DE6DE49CE70 +:100C2000FBC62716F638619C5F4B601FF3F63CEE5F +:100C30001480D77E37C01B2BD615DE9DA7C17F1E23 +:100C4000A5CF480C62ED5CDF5B88EB8F8CCE4A054C +:100C5000FF6575865ECEE0F5678273ACD62C264FB5 +:100C600064DA3EB692D263FCE130DFA093D04BD180 +:100C7000CAB79F317C765CCA413ECDB9EF0EC96FD1 +:100C800002B9D671298F7C8FED094D0F1EC7ECB8C4 +:100C9000148DD462ED773ACF403F0E523E199E3EFE +:100CA00072AED974D448FCB2E07EB95CBB37C215D1 +:100CB0001F7305BBAAE3923005FC12F9EEBC16CBFC +:100CC0000E12BFF7133C71F872E6BBE281CFEFDD85 +:100CD0005D1E8F6C1AFC4B0CFF4CCE027EB5E70EEE +:100CE0002E323E696DA6FB8213E72592F2C83C4680 +:100CF000FEAB32B796F447F71F4724EA77954AAE22 +:100D0000C550AF7434C6AE0A93F980D37124C65B64 +:100D10004EF0F49440E46FF07C2FB3F14BFB299F2D +:100D2000C6377BC4D51AFB84F3F954EB024B060A91 +:100D300017F883800F45CED4EE7773B8EFC84084A0 +:100D40003F30FD29DD126D946E0C3F93F960E6345F +:100D50007C9042CA4B47F79B00DF1D0CCEF813FE78 +:100D6000C85C368F7538FD53662419776D06E5E744 +:100D700091E1CAE2EB61BF265B02F5824AE7737933 +:100D8000FC95A315587EC6F33C2C7499E09BE90FA3 +:100D90006C9E5802F5CF3FF395FA4D44FEBA0AC94E +:100DA0007E2AFE6584384FF645B62EEECB404C3F8A +:100DB00007AF5BE4E5F8D4AE538E77DE4F7526EDD2 +:100DC000A73C93D22B2077E87EE7E72F678469E47E +:100DD0004C2D9333B41C39DC1D501E6760F70EECAC +:100DE000743E2D3FAFCC8449DE9320CA6047B40ADD +:100DF0009ECD80F83527E436F8CEE7D7861160C35C +:100E0000F6CD6AFCF1530C47EB68B82A4642DC2564 +:100E10004CB669ECC28FFA04C267F7E011BA8A26B1 +:100E2000F3C73D0926324ECBC319511E2D7C92FBD0 +:100E3000391217B532F82C417A4BD2E7E3E2E436A7 +:100E400083A829B7513DF653A7CB9389E9709A9DA2 +:100E5000E341BDB13A3BEB2B197A7B9EEB8BF2540D +:100E6000D79DD02EB8FE547659E9681D8923C43F1A +:100E7000803FC17D8F6144FC773442E372F1CD7EC7 +:100E80004387863F4C59F964DC5811A902C6CB99B7 +:100E9000460C5C54A0FC8C80E903766F18B2435C6E +:100EA000E250B4BBC48EE975283642E9C120D7347C +:100EB0008F97003DBEC6F82BD64AF9F050987707B9 +:100EC000B493901C43F894C9A75FA7E450F9644217 +:100ED0003A3E419745FF424DF921A1F61A3A4E5646 +:100EE000618FA0E1A7897E911DFAFDF5275F3CB3D4 +:100EF00010EEF9A4D2FE1C78FC3ACD3A985B43E59B +:100F0000E337187CDFC8B4D27E9CEE1180E7503402 +:100F1000B2F74483DDE3790EF28B12AC8AE80CC899 +:100F200027E07FA017E64F0FF04F9C89E6FF2B8B41 +:100F3000AEAB0296BE9845FB8F8BA4F582E913CE2B +:100F4000ECDC6F89549E3D62C3769118B0936C16A9 +:100F50004C2872AED083805FB694E3F984E86720B2 +:100F600093DA27588F91F94ED62B5C6F8DF5A681B9 +:100F70007CC9A6FB72C1767970BBB3C6BEFD240ED8 +:100F8000749CC681B6D9DD513361BFE2781A5271C3 +:100F90007B9395DE570886E7174CBE98989FBB89D0 +:100FA000C54D222F5989FF7B3893FA9152F6194289 +:100FB0007FA90C9B06B88911B955BB86FE46BBFEBE +:100FC000DC6CE4A548D2BEE35231F2CDB8923C2F9E +:100FD00025E53909D41FBA787259140A819760B887 +:100FE000FD0C4E9E77654B5548034F39B26F82FE1C +:100FF000CB91DE7F9ACA0E798FF157C72551A77F13 +:1010000002709A74DFFDD80F54B5E39FA3E307C6BF +:10101000B5225533EEBF65BACE113980E6DBCFE697 +:10102000E204DBE470EE14EB15AABF703A60A37A19 +:101030001EE435F7BB603DDB67633D92593E9E1968 +:10104000ABD17BAC1D972B512702F69D80DBAE63A5 +:10105000FA671DD33F137660D039A72C366F2E7FE9 +:10106000A6F20379FDB34CFEED3E589700FCB0C7E5 +:101070006217E03CF54361EE04D00BB51994BF6BE9 +:10108000D9B8332C95AE331ABCDD9729D3FD28810E +:10109000EE47E1E152001EBC1E54AD7D104C1F47CF +:1010A00016B733C374FC14A08F8D7CFFBCECCCD27C +:1010B000F91E311FD6DF560181A93CB74A7F2F2A7E +:1010C0003BCB46DA656759757EC19A20FD9D9745F1 +:1010D000FD87BC2CEB55D9015A3D248801F9D7C9AD +:1010E000F8C179FE8849C6F8BA338B9E6F7165BB2B +:1010F0008AB3703AF0974ADF18F8DBDD121A7440B1 +:101100003B976FAC04E6850984FDBAF2E55572376A +:10111000CE1B5F372AC48FDB1B5A1FD9BA04572B4B +:10112000C6A38BC9C30E079D4F87C36F4AC77024E0 +:10113000755078AE19DE27489A795ED34EEB2DCAEA +:1011400032327FC9D75D5D02DF5D12C4E96E81EF87 +:10115000B8BFC559942F928605A2D792BC18219882 +:10116000DE490AEDD7A6F884357981F9F61A6AF3D3 +:10117000408FF4C65989BEFA55B6A73E0BF8E0A4D5 +:10118000DF0FE89A7B7254027FF7C36C5703E0814C +:10119000CF4B16ED49E0B75A4F52B8FA62F47C8152 +:1011A000D0D7193D0629BC367721C01317291BE873 +:1011B0007954940AF66C5C0CD31F71C8B307D68FB0 +:1011C000C54DECBEB8705C4F7BFF12B94B60FFC8D9 +:1011D000179B5F04FAAF3A5CD90FF753AB8B9C4572 +:1011E0003DB8F4E51D74BF2318DF7733BEC6F07732 +:1011F000C0BCA6A24BB09DC0EB19A7F07339BF5B72 +:1012000019FF942F77AC00B83B36FDD00AF7D39284 +:101210008607042B597FDB483D8E6F0CC783004740 +:10122000D27039E19F2415DBCB20F7C3537C08B380 +:101230009C1453160FF89E0ACE8E2ED1D5AA959FD8 +:101240009B4C04FF0341E7A3B87FB09DF9EB6939DC +:10125000EE47807E9D7B1F3541FF6B77BE6B0A7525 +:101260001E76A2FD55E24968A7F669871DD921EED1 +:1012700051BEBC95D81FEB2C388FE9D7F19C40F4B8 +:101280001A6AB2F84064760CEF3E9C84F3333B5C00 +:101290007340B5C7611E18CD0BE8A1A40ECC57064C +:1012A000C0CF6E3FEC5F243D80C8E9538E3FAC1940 +:1012B000520E02DF638F08E260178C1E627F5D486A +:1012C000B42A2AE6F39FED7E4BFE0AFEBE09978BF9 +:1012D00009C0DF8309C027BDB34C0AD8E11F667B74 +:1012E0008601FF3112B66FF0F768478402FB47B200 +:1012F0001915D9AF80F7E07973B9C1BFCF7D80AE42 +:10130000835359916C7D7A9C306F59440F00BFFF15 +:101310007B168D931E3622D51203F12C3A9F822C18 +:10132000D74FC9BA82459808F3F70BDA73A83CD5B2 +:10133000F0CFA1CFC2C7736B86493C6F1D931FE5E9 +:10134000CB770AA735743F96255279F1DC802013BC +:101350003EDED95DED20F5E1AE24FE4EFD9F75B871 +:10136000FC0E9DDC58DD0CF3EB0DA7F621961B6FF0 +:10137000035C870C771F80FD89434548817579CBD5 +:1013800049FF61227619BC874C9E1DC4CEC1FCD199 +:101390008DF3EF65517D75D8E42171ACC349F41E1E +:1013A00076AF6163B6D71658D7C1EBF03DC6D749C3 +:1013B0004D3B0503B16347C93CD73749842EFB97A2 +:1013C000AD6A8571D63B120BCD98EE4FFC6840ECB0 +:1013D000C7FDAFCF8B1E003FE9E32C6A77ADEF135B +:1013E000E8FE77DF1BA6468DDEDEFEE21B440F2CF7 +:1013F0001EA1E724D78FEC96E05CB2F3FC7EC27F9F +:10140000EB317F85C17E7C3685FF82D19F02FC1344 +:10141000CC7FD61A2ACF20669A114DED15C8FB96BF +:101420005B881DCFE566019B0F969344CEC5C5E54D +:101430001782FF69CEA670F27102724F20F8E5FAAA +:101440002A3C9BC7C9A99C9523E9B97FDEFF647933 +:101450009F5B04F2BE309BEA214CBF98EC10729F58 +:10146000F7EFFC761DB9A73F410FC0B3868F9CD91B +:10147000749FC789FD7F766F48063CC906BC4EC184 +:101480001F31B9F3E07D00298EADD3E81372B706A2 +:101490004F874D6AB68CF38753C3891EC27C9E0A60 +:1014A000F0EC5FF6BCD80FF2254FF0815C7DE207CF +:1014B000B5049F1D4033902F9E5642679480FD2FA8 +:1014C000D02B1E89E8BD8EA6A5C47F9FD0577B0474 +:1014D00082F70ED5E60BC3FF5C3C5C4BE3A68E3077 +:1014E00085C925425FBE6E0AB2EC13EB18FC0DEE07 +:1014F000674759FC7EA33C79BD45313FDB037E360F +:10150000EEAF54A179F885F2AFB95EE3EDB97FBDD6 +:10151000AEEB17C41EBC2BE1E724057F0DFC1CEECF +:10152000BFF1FA3733BA1533BFA916F803E7D795D9 +:101530000C1339BAEE8C97AC075B0D5DF7B6937A56 +:1015400079C5FD376C8051BEB20EDF08FE4DF5BF88 +:101550000A76E0ABA9E4CA9DB01F86FB5B78F9D799 +:10156000915A3BF7F66CCABFEFC1BE2D91E75E62A0 +:10157000475FD82184BC8715DC4FB2BF6ADEFFC24B +:10158000F4F860288A9C5FBAF05CFD9720AFEE8C7F +:1015900022E76A92FD0D84CE171CF314A0ABA3873B +:1015A000E2E5C27025E187F3F1B201ECE4EEE1C7B8 +:1015B00017C0BB02F7B17573FE076217CC7BE377E8 +:1015C0005F5800F1A9753E6106DCCFB830F4AF9FDB +:1015D000801E6ADFF94F76581A3DDFFBA909F639FC +:1015E0000CBE01FA7D28CA0EF5DEFFCEA30B009FCC +:1015F0003DC33DA4FCFC7706487EFF775F20F28464 +:10160000F3E5F91F0CBCFA5F9077472A10DFEAF088 +:101610003CF155C8A38648B21F863C074D8D9A7889 +:10162000DCF6DDFBC8BAE27CB07898F2276A32912A +:101630003804E7C7D33F0F4742144EA3A93DDFCA82 +:10164000E24FAD2C8E54C9FC90D7191FEC60743852 +:10165000BF41493A9301FE8612B7BC84B0E1E8AEBF +:1016600012F85E4EBEA3CBC5E47ECFF9AD467E4EEA +:101670002405F637EF7AC4E8A6F1529CC7E51F406F +:1016800039D0D342F3EBA01CF2365A9FCFE7F4EFE8 +:10169000C29A42D95F01F8A85DDA6A3010BAE1F166 +:1016A00023E761784E1BE43DA0C779FD3D6C1E0128 +:1016B000F8A9BFC4E1E6F5CE6F1539DC05146E91CB +:1016C000C35D40E11639DC05146E91C35DA083FB58 +:1016D000F761EDA1E0E6F894007F0E722E6714E446 +:1016E000D81A3E4E2B8DD73C5252B513E4786B1F5F +:1016F000A59F2DCFB513CE4DBC924DEDF47522DFD5 +:101700003FA4710BF191396F82BDF7517F980C7A2C +:10171000A92DC67396C8A16FD27B23079EBA334505 +:10172000FBFECBE90DC865D4CCFBECA3E52908F79B +:1017300073F691F214239EC79FF6CD4B01B97CE658 +:1017400011F3EDAE2BCCA372224E4AFD1F93556EC2 +:1017500083F8CA91F2BC8C83843F22157101CE2F8D +:10176000A274EC64E75A3A57440F401CDC60B12382 +:101770001786BBA1267A00E23FE7D9FA825819EC16 +:10178000FBA22502B1EF7A4DEA10D1EFF6E114D0B9 +:10179000EFD63CBF6926CE2F6BDEBD00423BF95829 +:1017A000BEC2FB33B8F5CE4FB11D5BFFC49D2B61AC +:1017B0009C1D22B28B8950AF9BB44FB1F0F75724D8 +:1017C000FB591EA714AF64EFE8DFB599B0E3D9FA6F +:1017D000EA3551BB0BDB2B280CA7A5F7B2F8BBD021 +:1017E000D243EC95FBFCF3891F71EE9EF08E3CAD6D +:1017F0007CA4ED9346A81D94D43E7A23CCE7E6EC76 +:10180000D5C530CC7AB62FE880F508F6916AD3E9D1 +:10181000453187C5BDEC6EF25E8CC5E58EFD1AE8DC +:1018200023B39B9CDF936F771BBBC93DA5F1944607 +:101830006228EDD2E985ED464FE21CB06B7A997DC6 +:10184000B393C28DDB93FEE44A9703DAE3FE497F4C +:1018500096669704FD83BD01F9FFF8C94DBBB4FB43 +:1018600067C17A07FA2FB1819DA236113E944D0AC5 +:10187000C89FF3503591E0B140BB1F111CE703FD39 +:1018800008EB292DA73C25273690F2B860309D3C07 +:10189000508EFBD991E322F5D0D0D5DD87E3764099 +:1018A000670DB3037EFC2ED1739D1E89DA6F9E33C4 +:1018B000C47EFB60830B9DC6BCBEFDA577897CAD55 +:1018C000DB4BE9D6B9D76904BF773B8B8B74565C89 +:1018D00020769C2A22C2F79DA6E1CD70DFAF730B64 +:1018E0008AC69E1DEA5C309609F2F50F2FD1F5707D +:1018F000C86020F1934383B903609F08EDD48EEB59 +:10190000F4CA8366127FA5FE20F67F1E05BF7C7D8C +:101910003B227180CE116A77A23CBA3E3AF7BE41B3 +:10192000F887FB3FD8AEBA06EC9E68875901BB2406 +:10193000A96A3485AE47A464807F52E579B49AF0F1 +:101940005B6129F0DBFE65AF6EB6C0B855D8BFC28B +:10195000EDB727BB5E82FED497040471CCEDC6BE02 +:101960000AB847BABD5AB6AB300F4FC3849D03F2D5 +:1019700005791A88DFD3E958A980DCDAD24DFDA7B2 +:101980002DD87F02FF68FB4BDDC40EEB94C31538E6 +:1019900047B078AF700F69AFDA10F04527C627E47B +:1019A00017FBAEF769CF872DAE1A4B81F3061CEEFD +:1019B0003F184757017EFEF0A219A99AF874749552 +:1019C00077C757A0BDBD481115F0C3463D602FE352 +:1019D000A5AE74E37C9FD16D56204EB548F0C1BED4 +:1019E0005A34B35FD2D8FDDFB56C3DADCD31B0D444 +:1019F000C4D639DB4FB0AB0520673F647C003F396C +:101A00000ECB61F20F4C97563F5947E097025D1D90 +:101A10006657E117357CEAA8A47605DFDF81FD1E55 +:101A2000B2CFB35C22F44EC2F406F9C7E976B32311 +:101A3000AB08F0B43587CAD9A46C81C401906A227E +:101A4000F88A5BBE536ACBA3FB43A1E2087D6C1E00 +:101A5000B133DC25A01762E3E9BE41AC586E0883C0 +:101A60007853A1A00CCA64FF99EC278DC7262A835E +:101A70001A7CF2B8C8B9B808424FE4FBB504F6D4F2 +:101A80008E1CAE77F4FE006F17D89F0A23745FD2C6 +:101A9000A71680DFC9F7A7F8BC7DDDE14D5A79B6FE +:101AA0009DE1DF97C3E28B76BAFF116750669078AD +:101AB0008D8DCEE35CDC0DA5F41C6F0FC1CB861CB5 +:101AC000AA7F62D3DC242E371E1B41E6119B865A67 +:101AD000A07D6C4F82D0E3D4E2D94EF44C5A8E41B3 +:101AE000BFFEC1DE027FEEC7D47EEFC47C0DFE1CBC +:101AF000C801C6A7F47E03930713703379B0782F1B +:101B0000A57BE75E6A5FF1F80D426399B0EECE19EE +:101B1000528A40CF779AC6C83AEC34C845DD8EC0A9 +:101B2000FA9E4E2E545B7D24DE509D9B59D4E30CCF +:101B3000B4FB835126FBC57FA846645FF9672FBDC0 +:101B4000E5D3FA899C2EC17E10C85F885B7279FC50 +:101B5000AB6CF761909F9D06FF6638F7C2E567E7BB +:101B6000CB0FEBEEAF04CB4F8B44E595C567F56922 +:101B7000F78B60EF35A288A4AA0DA7D62E860F8B0F +:101B800081E0F3919263DFDF42F4FF58B719EC9BD9 +:101B900084D11B400EBD05974E887D83481A17439C +:101BA000F50D1AB492FD111ECF0B86E7176C9D70D0 +:101BB000BC73FF14F685A0FEC78CDEEF313EFB0B35 +:101BC000ABAFE1773D3FDBA87F3695BEE1ED3FAFA0 +:101BD00038231F87EBBD009EBB75FB5B30AFDABCC3 +:101BE000A9EBF5EDA37206E8AB3D9F1DC5E4C181ED +:101BF0001C8AD7E7D97E40AA6779545D887E789E93 +:101C0000BFA735951EB57F2212B8609B11FAB15758 +:101C1000D428708E76C62C41774E85A712923E1E30 +:101C2000E3F69413C6FF33BD07EC41E43EED643E9A +:101C3000D3DB15C1EFBC4CDC27C6F3B8D2FB2EBDFD +:101C400041FB4EBD69AF9277BCAC9648C22F0BC129 +:101C5000A9C4703C2C5F43EE29407FB5C46EDA18EE +:101C6000B43FAC87274C0E0DCF74F8ED35EC6E0702 +:101C7000FE3CC5E04ADD7165F89F6774D8C6CE4565 +:101C8000DB14B95BC2F0CE7E452E84A5D26B902BBF +:101C9000B63B02E7C92316A03FC2F9BBC8B2BE6C6F +:101CA000387FB7A57BB809F862B6346680F705625D +:101CB000DD7AB8E39BF4E775133D31BAFCCCF6242A +:101CC0005DFD646FAAAEFCDAAE59BA72A75AA4CB16 +:101CD000A7F55EA7AB9FD157A1CB67F5DFACAB9F54 +:101CE000E3ABD3E5738756E8EAE70FB7E8EF0B7C81 +:101CF00092B6FF2990136FD273E9C822976AD7076B +:101D00004FD7CF4A25F89FBD573FFFA8B2A0F3CACF +:101D100053F05330FDD7F4EAF729533D8B88BCBA12 +:101D20009887489CC8BA356733F055C21AE43563C2 +:101D3000796A0DE2FFE9FA0BF077CE5ED827BA5840 +:101D400043EF61BD0A4521ECDB43417C5EE788A29D +:101D500072F752DD34F630E5F36A33DD4FAEB6EAA2 +:101D6000EFFB7C8FADE7EFCCA272643A7E3DCBF8FF +:101D7000F514E7D77E67C576A00FDCD3C15DDDB96A +:101D800043E886FB86311E1BB1D7EE94FCA8506356 +:101D90000F3CC1DA6F67EDFB37D8C9BCBEB92181F2 +:101DA000A43B36C8E4FBB7376493D4B74121DF07BF +:101DB0003794917427B6D3207D66430D498736B892 +:101DC00049BD67373491F4B90D1EBAEE3CCB25FE00 +:101DD000BE1491D7976242C6BF6F74E8CF3B07E845 +:101DE000B256F2437B59F2C23B1053E163527BB1CE +:101DF000F98AF705BA4EAEF61DD4D47F795684839E +:101E0000EC3FCF4573891F3A4DFB3F6DF0F80E66EE +:101E10004C2F1739BFA0CB6BD243D5C37C40CE4FDC +:101E20006D79B6F61BE49D8F29F013E0A3207EEDBB +:101E3000A5FC5A006B92F87D6349DA71F83D329E39 +:101E40006FF145857C3FA03497EAEF76C69FED4160 +:101E5000FC99904BF9F34FB368BDFF57F8F3FD5D64 +:101E600011C44E7EDFD89712AB99EFFBBBACE43BBD +:101E7000CAB623D00328C65505FC0BA17F13B6B7FD +:101E8000AA728DCCEE4827EFF7F2730B53D34D1F98 +:101E9000E748DD9148E25017EDC805F6503B1C4A73 +:101EA000C6F84958026F65E24A1E3BDD7FBB8BD9FD +:101EB0004B12A62BE84BC510E0F310EF754DC58F04 +:101EC0002B72659DBD107CEF2FD5F394C9EF987EE2 +:101ED0009D05B7FBACEB2C2BF7EFB3CE389FA3CB14 +:101EE0008F6786BA67D0CED6D9EF9FFD0A59679C17 +:101EF000CFD7827DA519BF2197DAAF0DB9540EBF98 +:101F0000CFEC8CF78DB201F8F7FDE36983DAFB6261 +:101F10004B58FDE9F1FBB049270783D6E9F4EDC33F +:101F2000A81DE71388DE6BB744AAD6C8CFD2FECA75 +:101F3000F89B44D7BD8EAB8AEF38907A1BC0D5860C +:101F40000C645FB7CD6223EF09A17EE385310D9F5D +:101F5000763B5D77E4823FE042B23D8EAC23E2D730 +:101F6000E39FDB12478EF4D1BC7A37590773913067 +:101F70000E7C2F8CC5899DB8DF1D5F8C24FED6DCBE +:101F8000B13682871D10FF817DE52A6C8AC4F1235A +:101F9000AAB06EBCD49FA9B08C417B0BC417D2F001 +:101FA0001A12945E11F8CD211C3C82DB8B07B0FD28 +:101FB000808128B2283D0E0334718B504F40D48F5E +:101FC0002D3D43CBE7A3D11EAC5AD002344ECAAF4D +:101FD000AF517B00CE6BD165FB59E0A9F867D67F86 +:101FE0008A5D39648BB92A7CA915DE7F85F303EA03 +:101FF0004609F5E0F449EB57BF0B72BC4B35DBC12A +:102000004F43122D7FDF68B1C33ACC163DDB7231EE +:102010007FFDB3E88EDB47EC19EF6C7A9F403A0501 +:10202000768E013BA59F62B82A6C254D77C0B4D946 +:1020300077827767A01E970FC1F96F3C44E3013D9B +:102040000F533EEFE9A6F921C6D74FB374772E7F21 +:10205000670E6D02FC852550FC108A62FC9B19FD01 +:102060000C16AF5F057FD58BE96507E9344CF0FFAF +:1020700070E376CF43A47A3339E725F8DDE4BDF386 +:1020800040BC57DF8F2BFB41D28F09F703F7122D8E +:10209000963E9705F35178D3B0DF78E57E0E266340 +:1020A000FC492514BE75A2E747B9745FD37507F8DC +:1020B000C118815BC87D8E612438B5EDFE6AFAECEB +:1020C00087FEA7A38F18517502E22B153EB30CF1C2 +:1020D00091603A9D03990FE3FED944EDEB69E876F0 +:1020E00086D1A3A26B910FF61B175EDE1009E35693 +:1020F0007755FAE05C59555739492B9EA6FB2715B1 +:1021000046D901F7992ABB1693FAE55DF5A4DCD50B +:10211000554BD2855DB791EF0BBA96FBB4E7DAAABF +:102120001CB81F8D5CA8B0E1F134F2FC8F20773031 +:102130007FB8A45ADDF705979B74ED8C15EE3BE84C +:10214000B958CF8D8007134A12205E2346D610BCA3 +:102150006C4E4C70025E3E6272D7654F25F1990855 +:102160000529DAF77D4CFDC2BB205F305DFF08EB2F +:10217000C294308CE8B966BA4F83F5E44C485F15D9 +:1021800050C877E4FF9BF13342D7D0F58BAEACB7A4 +:1021900077DF12FDB6034EB2A80F2E7DBD0CE7CB44 +:1021A000A36F73607EFCE97386A512A6D9EE371083 +:1021B000113E4FE75DFB24E895DD8DD1DF8AC5F543 +:1021C000E5E77FBCDD88E5C1EE950229FF4E3E2D97 +:1021D000BF6696272C0FD3ADF8755732D8152B90C4 +:1021E00044EE79D5E7C92B9F93218EA98CC17E6ED1 +:1021F000E31AB34CE28597311CA5B83D002AD2FC06 +:10220000C25290B7ECC7CA77C2BF319FA5F5DFFDB8 +:10221000CE8320FF464505C2A86DFDCE7D0EDC5F56 +:102220005A6BA11D9AA7F7B3FDCA1D66B25FD9D636 +:102230004FE56D3A52C661DF6618E2AF4678074E49 +:10224000EEB181BF9B8FC839DB6B5BE979A0B34FDF +:102250009B07206E7E166083F26481F8C3C7372027 +:10226000D7A60C34A57C9FCBF3783DC0FB16370472 +:102270009573F92F78FE59BC5F23EF6FF0C4EBF232 +:102280004A2FAA346178535B11796FC484BCD43E61 +:102290007359C67A401F60DAB84AE9360AEB9FE8FC +:1022A000876A9EF77825782F04C5607DA580D9E6DA +:1022B0004BB090F7D09CE4FD29F1266407FD9A52BB +:1022C000E3DF0FE7058A5DE544EECF419E03A338C7 +:1022D0009DE7DA4DF265165F0F84E60C2051707FA2 +:1022E000F32F5379E3427609CA2B9022B1F7E188A4 +:1022F000FF539540F5760DEA23DF6F46C3245D82D8 +:1023000046497A2B1A27A91BD9C93B6D0B2C585F5C +:102310006179D7087F942116E42ABD275254631EA1 +:1023200080F87D6303D66338DFE447249E5F5F2334 +:1023300093771639DFD64DBC0F2193FB97489293C4 +:10234000976AF4FF91A79791F7BF6483FE5CF76DDE +:102350007954AEB4E5D175B25D6072692DA5339242 +:102360003C4FDD81F32BDC59E49E312E27EFBBABD4 +:10237000CB2DA47CBBD1DD1D87F3C73ECC47B02F4E +:10238000B03D4FD6F9DFC76AEF4C84F53AF050A65E +:1023900011D23A0FBFA7A13238D5646DFCF7EC6AB1 +:1023A0000C278BC769E33CDE3CEA8F6C87B258E0B0 +:1023B000CB652BC9F93BB67F16776B34893355A3B0 +:1023C0002609CEDF6E60F3F209EE2A02EF7AFA1EDA +:1023D000015F4FED9C3F24D59404EB5171D2F9314C +:1023E000F857F868FC79457BED3ED86F5AD2BE1E8F +:1023F000817E0B9C83A3E726CA9757917DD1A67E49 +:10240000338278B7D0EEF93DACE7E5CD6619D64D0D +:10241000536B2D191F080DE78A9A3CABC93DF2E5B5 +:1024200016971DCE41DCD4FC3542E74DCD981731CF +:102430003F47342FA3FB8F58B9C33E2BC63F691FBC +:102440005741DF9FBD76C93E819EAFF791BFFB31FB +:102450009083C87E428C84C8FE4FB46A43704E6E2F +:1024600079EBA387E05DB69978A2B07F25238F0929 +:10247000F03D95BDF6F4D72E47133B1DEC9B6B0941 +:102480007D683CBA4B94415F382599C8E7B70E5236 +:10249000F9DCDBDCA312FB74091E0CCFBBBEAF90D2 +:1024A000BCC38907E2EFFA8D819CB3B86F92013EFD +:1024B000D80A85FDAE3689C6710A118D17B5B0FBF5 +:1024C0002EC17E8DA5CB44C66DB37450FB0E7768CC +:1024D0004E9C2C3F82E721B8FF19B17DEAB119204B +:1024E0001FB2ED22DC9347F7444EAC7F90ABAEBCFD +:1024F0007C321FE5353A9FE2519788C8113B15D1D0 +:1025000075FC00D51761CF085A7BA3D2AEAE72E03E +:10251000718E1C6CDD6C93E1EFA928BF83BFB7827D +:10252000C9E305FEE0FC7A20B92F19F4DF6F12A988 +:102530009DB5F0F20B11DAF8F1EFF2A8DE2B027D77 +:102540008EE75908FA19EBE139A0CF715A02FA1C4B +:10255000A7456BA93E2F063D8EEB29A0BFF1F730B2 +:10256000A6BF2D4C7F171AED3340DF971C73E9F49B +:1025700070D1EB353A3DCDC73FC5F85C39E8D6950B +:102580005BD2F57ABC82E9F1A3E5EE95DA7DB15331 +:102590004C5E9C66EB12BDAEA6007FC11E2DE0F521 +:1025A000BD5F22F23EE9B95F52BAAB46C4EC1C3DB6 +:1025B000FD409E33FA8E3D8EE92BEC883FF0258D51 +:1025C000FC47B354A207A7A2DBC77934FE58D25FF9 +:1025D0002BC26185E245C533BF8C80DFAECCEF53A3 +:1025E000D1B76B96EB32E8EB7464BFAD03FC1B8F85 +:1025F000998C532D766C067FF9234C67B37D727FDF +:1026000045001C866BF928F2F984805EC5F51588B3 +:1026100067951C171515CF5769453DB06E137BA9FB +:102620003E8B75C39D9200BEE39B2C70E672229F89 +:10263000E8B1EBF233DB1374F593BDB2AEFCDAAE66 +:102640006C5DB9535574F9B4DE325DFD8C3E972E46 +:102650009FD55FA3AB9FE373EBF2B9434DBAFA4842 +:10266000751DC9D3E8FBFC618FAE3E2C8B14A057BF +:102670008288C0AE9FBDB75DDFFE24B67371DE8B6E +:10268000FF07782C41344FCAB15CC02C7FE069D081 +:102690003F6566BB1FB75FD16A0CD8C508EC2A241A +:1026A000025DEA3D36B2FE94203B3B381E71E76B7B +:1026B000EA6158B745AF79C8F9EAEBF3231C840FF8 +:1026C000587CA25AB4117A7D744C54C037B9133C6B +:1026D000144780AE1F414740CF7DC847F6CB83E605 +:1026E000CFE31748DC4AFDFF7601CDC0F5CC097A6F +:1026F0003A87C97A3A5BB3F5748E50F4748E2AD354 +:10270000D339DAA5A7F3DC31E1C0D3B01F89F18456 +:10271000CAE0BD7E3DDD399ECBF0FF42E13918AF06 +:102720000ADAFA475837D3E1734D7E707C673E91E1 +:10273000FB17DDD4EFC1BF064BA9465E634109F824 +:10274000145EA77A2078FD73FC15BAE3D17D579209 +:1027500003B6F59B1371B9324AE5C09C254ED8F6F5 +:10276000432756CF9D09744D42AFF0FB451E38BF3D +:10277000A459DF5DF97360FF54195361DC7E33396E +:10278000B7B8FB9069139C7B3D3A077D1FE00EDED6 +:102790004755F3F93EAA4BCD07FBE306EF4A98C72E +:1027A00009C1A06C7480BCA0F36A7B7DC24FD6EBDC +:1027B000A9603B595DBDD94FE21ED83F0579022F74 +:1027C000C039889DAC907851907C29F404E9B5A07B +:1027D0003888D0ACB7A3518B1E5F3D651EA79036DD +:1027E000597E4E1D071923DF1722B507F4FBF53577 +:1027F000CADBF762B88FDEF2D64CB0E326C54302DF +:10280000F8DD09F8E1FBD3D889677EDDE80D305E9D +:102810004A9707ADC7ED9F057CCE21F87C16E8B13D +:10282000278CDA0BC79FA67E50C91BAD049E38418A +:1028300056C04EDA134DF9E4B880C6F6E0FC9C634E +:10284000D45F496B772A409F3D4EE500E48FAF1778 +:10285000C87BE5A5275C229C174BF7E27258EF1B5B +:10286000DD95F0AE46E3FDF49CC68F3F6C23E7C9CF +:102870007C5FA6E57BCABDE43CFCF10769F9DC930B +:10288000AA1889F3392AEB5FE8AB8C043DF6904037 +:10289000ED9B49F4A47ECE424E8F1D7F3AF0A59267 +:1028A000003D5ACE298723F1F7D671F78D51683252 +:1028B0007DB85FB140A27E03F727AA909BA4372280 +:1028C0002F49AFD69FB8989F4DF05B871492773110 +:1028D000FFC25AE32A7F1EF8DE1B893234F60A4F04 +:1028E000FB62DCE49D7447A59BBCD773319FDAD1B2 +:1028F0008194EFD3BB92155C7E8CBF1F6E7193BF2A +:102900009310779722D278A75782F5E54B2E2C8625 +:10291000F9BC9F4FCFFFA46DF5127BF6566CD681A4 +:10292000FFE97F528A867383E4CDB110FE78209E42 +:1029300016746E5052C9B9D82251CE859B275105C5 +:102940007FD90EEF8F006FC07D75E179F332F51AF4 +:10295000C297C42E99AEDE31760E690F7B47AAC1AD +:10296000ED34801CD953A8B77BA20AE8FC797A130E +:102970006A227C755399A0F4603EB849427ED82FF4 +:10298000F86BE755B4515D05F8691C34237A7E086D +:102990002569CF6F73B9D288F8CF7D08F8AC8DC5A3 +:1029A000CDDECBF7127ABF379075B00E7F3F5B2B31 +:1029B000F820EEB5D4822DB0547817DCBBB24313A7 +:1029C000CF6EEBFFD90921F22AECA42767899FE695 +:1029D00006D6B9B84035009C479E12E83BF40CAED1 +:1029E00058BE1E2A3C44BE094CBEC537ED1612C463 +:1029F000C9FD07CB7FBCAE10E88B1436BBD89A78E4 +:102A0000F55EAD5CCB1EEEBE17EA337B9EC77BF155 +:102A10008FF8C75B6AA9FC8AB3A8CC4FA2E7611301 +:102A2000DBE9F764342E407D19D937C6C23B4EB07E +:102A3000C182D36B2CDEDA25329C6FBB4CF5C6C34A +:102A4000FB4BB4720D4F4F85B8209692DE6FE2714A +:102A50008D9625AE0E3C1E9E931774FB3AD1736380 +:102A600001C4B14E0A643E110954BFD91CC3544677 +:102A700004C51DCD5DD678B0E783E38F66C9FB5DE5 +:102A8000C823D56CDF45E391A4BC4BB2D8CDE48616 +:102A900095772EF0BDB72086F547E38FA2C51EAF10 +:102AA0008BBFD913E2B5767DA15FD69517BF96ADE2 +:102AB0002B9F33AAE8F2734F94E9EACF1B73E9F234 +:102AC000D79FABD1D5BF61DCADCB2FBCD4A4AB5F5E +:102AD0008E56EBCA2B2D6B75E5D5F6BB75F99B129F +:102AE000BEA4ABBF48EED695238F7B15F0173244BA +:102AF000927B2B93E24C41F2F98627E25D5ABF624A +:102B0000228E9360227C6106BA68F5E53C458674A6 +:102B1000A180E52F4E7F35CBD30DF4C572F81A1A7C +:102B2000AF716D86A354A9AE7343409F175409013A +:102B30001CDBC23BDB5703DF6F8CB40BF3713E939E +:102B4000DFDFC65C8FE5CA0B658FED073DF7C25E20 +:102B5000C907C005EE77D3F2CDE188C65F66598814 +:102B6000BFF4246CFAE07C64AE44CED37E68509C03 +:102B700030FE7AC3680AA47718BC2680AFC5E0513E +:102B800020CD163D4F1660BEB823BA3F05FCA1828A +:102B9000791F8543BCB5E0270601F4F80BAF9CEA2A +:102BA000BD0EF7F73142E300C7C8E885A1EFE07436 +:102BB000F66B24E88C66979D7A6C31E073D448E21A +:102BC000891F98D056A47967E283FBE979A8168B10 +:102BD000E896607D484A229C0B8953A83F7B6A8A0D +:102BE00038ECBC8CF2D701AE5389A1DF0378B180F9 +:102BF000B6E7F78753B395F8DB22B4ED6F25ED798F +:102C0000DE78291A796668DBCBF4FEBD8435A00D29 +:102C1000CA1DA41C4F93FC9DD24A78EF10EB9BA8D1 +:102C2000E86C09F0526EFBD840CE5182D588CBC7F4 +:102C3000057A8E1549F45D1F345F1A9FB07B53A14E +:102C40003DB597497C1FD72BB7E8EDE5D9489F0FD5 +:102C50008EDFDB14AA2F8C41EFBAD8309B91EF1393 +:102C600070D3775DB4EF92C1BBBE2D2C6E87125C22 +:102C7000E43ED6BFCC771442BC8AF713369BE26F92 +:102C800084BD43738781BE77123C8F72B5BC09FC4B +:102C9000A566545004FB777F291074ED1093E32B45 +:102CA000D9BA59693FFC67D00FAB145ACF60B1C78E +:102CB0007D1FF3C72A351201FFDCDE8C22F3653855 +:102CC0002FEEF8950BA7A75ECC6DFB166E7AEA8700 +:102CD00059F73F85D31906EF61B0D3D1366637F186 +:102CE000BF7FABCE24FAE46AF5E2D73357FF6836EC +:102CF000C65378A44F86BFBB193EEB1C3947F9BFBA +:102D00004167CD8171187ED058A6F69CD2D733CBBF +:102D10007F341BCEF119913F06E8FC13337D77E732 +:102D200035EC42E0FC3FBD9A43E28677299E17A12D +:102D30001EBFDF8E0E8E93777C2A914CECAA49F44D +:102D400067FC13CC070038F0CF74FCF011C08DE79E +:102D5000D312199AAEE4077C6B89267F67248BD146 +:102D6000978FFB59F9D39146E50AE7F3E9E0C3F8F9 +:102D7000D29D837E7136E55F9E723C05DFAF7D712B +:102D8000B681D5A3F76BEF52DC04AFFF91FCC74CC3 +:102D90002386A185DF479866BED7FD8DF3BD5A3ADD +:102DA000C0DF4F86715AC2AF0EAE5BFE4170ED9D23 +:102DB000CDF8A3E0EAE05ACDF0FED7C2E542E3BF8A +:102DC0008F4E9B1E2E4CCFBDB00E51D5387DDF28C7 +:102DD000E6EAE07BE873802FE6EAE0BB0FF80DF946 +:102DE000297C4BB1FF03766788FB4CD5C49F5E43BB +:102DF000E3EEE12699C4B3C3EB0412A71350BA91D2 +:102E0000BE43F1D7DD6B9AA05F1CF24783FC7BD5F4 +:102E10004CE39FCA78A6360EFC75C64F7729AE3EA6 +:102E200080BB2593C9831A7DBDBEA07AFC5D1D645D +:102E300033B0FB6DE983F4FC3762F7DB64F2DE78D4 +:102E40003F5BAFC1F7DB50894CECF3CD066C9F8341 +:102E50005D1BD33EB411E7EF490C27FB862D09FF1C +:102E60007E420019D58BED750D9D383CE737BC6669 +:102E70004F374E8D8F75E29E526F88733E05B33C7F +:102E8000DF9BADD1E3EB867E6E4FD7D879F968CC66 +:102E9000409C26346EA0F867E7ADE23F1BFED701E9 +:102EA0008FCE01F9EF26F29FEB8BCE97FF4D86F880 +:102EB00005E87DD8A7198F0827FAA0675659B67676 +:102EC0003FED97B3B9BED6BF8313D0D37FDB3B387A +:102ED000013B4640EA8C50FD4BE4FBF3824CE2CED2 +:102EE000785978C11F68B15D992EFE0DFEBA334640 +:102EF00078BFA8AC1ED2FD1B5CF5701F735766B976 +:102F00004521E7A49D553DC4DE410ABC8F12EB7EEE +:102F1000AD4E6B67C7378DEAF2899E13755ABB7B3E +:102F200066FB98AE9C9F9B363AE8B9E964EF395D41 +:102F3000FD5E8381EC778DAF46DEC142884F8FEB1B +:102F4000CA2B5C36353A0AE2D49774FD6EE9A6FCCA +:102F50009DD68BEAB5DF8D928B9C1BCCE8B3D46BEE +:102F6000FBC9EAB7EBF239BE045DBBDC2159579EC1 +:102F70003F9CADEFD75EA62B2F67E7C42A2DE5FA5D +:102F8000EF681F81FFFF00F516837B0080000000C3 +:102F90001F8B080000000000000BDDBD0B7854D52E +:102FA000B538BECE9C7925992427C9240C10F0840D +:102FB0009741794C9E2490E0490214DAA0C3CB0BD0 +:102FC0001671820801421241DBB4F56B060229A595 +:102FD0005A63B1D52AB60357ACB6B6464B952AD03C +:102FE0004194E2FD098D88885EB4E31B04C908287A +:102FF000F657EEF5B7D6DAE724734E1283F6DE7E87 +:10300000FDFFC3C7B7B3CFDE679FBDD77BADBDF6AE +:103010000E00C0E7F87FFBA80AB7BF08C00E1A343D +:10302000A56369FFE1C7F238AA0394E553693F1F1E +:10303000CD05FEF93C87FA6B6E7F26C05888DA40D2 +:10304000A6A7315B201920F483B2B4F7AFC4EA001D +:10305000EC771596856A6BA410A0C5068D9BBC58AD +:103060005E5192AB7A00167BFEE39884E3C346C7B9 +:10307000E9AE718701D8AED032681EC74629005824 +:1030800042AEE2077C1F120136E5016456C10D0114 +:103090007CFF73FAB9AABB2CF34BD80870CAD97B52 +:1030A000FB30BDDDF159028433BA9F3BEC01503C4B +:1030B000F4DCC3CF4F558AF747833660767277BF0B +:1030C000F1F43ECE274586C6F63100B7246B03D215 +:1030D0007BF94ED7B89F2541B8A0B7EFA4F0F353C2 +:1030E000C37AFF8EB18E4BFF8EDCC77A9CFC3CB35B +:1030F000A57778CC34E095DE7BFB0C7DBD8ECF06CA +:10310000422823FE3D55C0B1EB3BD9DCEEF82C0D37 +:1031100042BDAED7CBCF913E4212E2BF0A7FD994D7 +:1031200006909A966B071B4085E7BC0D10EF1A04BA +:10313000DB898E8CF7A1CC1E8BA78B2AB0BF1D75A7 +:10314000237D8424F81CA756E176BCDDD58EFFC70D +:1031500083B90ED4DFA8E3B81E3FF07AAA40B5C306 +:10316000F05EC6D3E7611D57838E7A49EE7FFC5629 +:10317000BFF6D77199FC5C79DFDDFDBC2FBC114730 +:10318000BD1FF77E22CE0106F2386B88AF34A8ABA4 +:103190008D20BC16428A9FF8067F02EE2C80EBE958 +:1031A0003795F8021F96E27B291D1BB6E2AF89AB6B +:1031B00053FC215CE30DB65826C1B106A21B00C723 +:1031C000FCEBEE0427C1B973F79F87043DF4F214BA +:1031D00085BE2B8592E4CF932E7D7EC8D902EF89E0 +:1031E000825E604A6C3EF1F578795CFE2664D554C7 +:1031F000DB451FF3A9A2E6CB03A9FF5A86F7277088 +:103200003A9DE63CDE9D124A4AC17E285006A33C08 +:10321000492514A753793BCB99D45DF60FE3E19B85 +:1032200042F0C0F5351DAF093FE7EE7E7EBEE35CA0 +:1032300022ADE3E7FE642FCB99093081E6771616BD +:10324000A646082E255E86E363BB2A5383C83FE368 +:10325000FE38650095D1E68D8ADD0170A139187EB2 +:103260006E64CFF506FB901B0FE97CA2DAB58708E8 +:103270002FC1C4DEFBFD46E7973CBBF61B925FC641 +:1032800078D47FD6989EFDAFCCB309F9A6C31511AB +:10329000AE2A885FC9C02FD2A51DEBE57A5DBAFBC7 +:1032A000D5AAEFE0D2B6AC49F1CB3E7C165481E012 +:1032B0008F0B0F6F4279DC2A3502D1B51BDAB8DCEF +:1032C00024F9EF95B1946DB10C219FC3FCBDA910F9 +:1032D000B453FDCF52B405F0BD5065E32FA3384E73 +:1032E000689D1D5AB0BC27E9FBBF8AE2779A422E3F +:1032F000C585E58584A16140BC355D113CE0E7F9F9 +:10330000364E088CE5723C95CE67038B884E63522F +:103310008A7F5B21AF67143D37D6794887CB0D573D +:103320006A87E8FDC7FDDA5F088E8713866A442F37 +:103330006A1EF86130D7C380747078C6D75201E135 +:10334000751EB454A517B819E562B71C581F276F2E +:10335000DE4EEB1D2F6FEAF8CBCE13FCDF315AFBAC +:103360002BCDE384136ADBB1FF8944BD4CC112BF8E +:10337000F7A13EDFEC3CF1DEE7FAFB276CA2FD444F +:10338000BAE86F8C6FF493F4F2DD667760BDA3BB8F +:103390005DBDC7D518C6FE99C3051D209E81D6DD2B +:1033A000F9C7B4AD84B7256D6F3917637B525E459D +:1033B000765E91E847EB58628F3AD3B1FFA7B9C167 +:1033C0000B04AF7A15B427E87D35EA9C83F0ED94C1 +:1033D000603ECDA3D381253EEF4C10A5319FA4BC08 +:1033E00059D979587696479D440F5DF522ACCB5458 +:1033F0000FF0F73A4B2DF599A2AE02EA5D2FC159B5 +:10340000E85DC8453D4E7288F4B8D2536F23372B20 +:10341000CC8F09425E68D9FFB594E8B32FF9657384 +:10342000773C7F3F3E5FD488F48CE305777EFCFCDD +:10343000F754A69FF7E9BB35E10420F8FCA3F2AAF4 +:10344000734807AF6753456CE87D389FD86E97B2D5 +:103450008DBEE339BCFF7BF89D3BFCA3FC9B48374A +:10346000D83BD84E499654B1BE1DE6F58DD6E1BA8B +:103470005256993E3CEE76005E771088DEAD768F30 +:10348000C7AF08BEB607FD6417F5CBDFBB5EDDF73F +:10349000BD78FEDEF3C2601ABF6CCFC10C2A7BE19F +:1034A000EF63CFE4F4CFDFF5D0C6F84709388DC617 +:1034B0005FE177FA697DEB95B7A7DD8FEB5D898CCE +:1034C0002CD3FA779AD7BB5CD76F867E5CF9B08332 +:1034D000F5A52187EBA083C75DD56E7E6ED58B5693 +:1034E000FBCD4A27617A46F2150275D4AF1635082E +:1034F000F5AB752FCC5ACBF2041A5D65B43CF3FCE6 +:10350000ECBA7EC89503D7115D67A5B72D127A4F27 +:10351000758AD2ACDF41117AE146CF5CD687376E2F +:10352000B4CE5B73129E6E6AEB673D3A5D7D5F9F22 +:1035300077599EA0875589D50788B5A1B06328D152 +:1035400003CEAB9EF809EC81ACB5F8E99392B07F5D +:103550008DFE1F15753C14C179C9C953DCA4CF7EFB +:10356000342A780BF51F722CFABE6423FA0CF0385B +:1035700067769E3C2A139DF984BE473CFE6C12FE82 +:103580005ABB535636097E699D44F2244FE0B5D6A6 +:10359000ED89903EB5C2CB9837CE6B6D5E66CF7924 +:1035A0009DFA16CA9D5EE46D2DE929EC3FA0506B93 +:1035B000A5F93986B5EF1F44F2FE56C9CF7C045AEF +:1035C0001EF1EB7A3B4884B792686C0DE1D1E703BA +:1035D00045C6BA37498C0B7ECD4D76EEC0A62A780B +:1035E00007EDC537944AB78ACFB3D26C01928FEBFF +:1035F00095C56937C6C9D52CC91668677B6571DA68 +:103600003C7CEF7A97908B39DFFAFB4AA62750D3A0 +:103610005DA5347EF0AEA9C4D76932CFA762C1F9E7 +:103620000237CE67D0454FBE0BE17BB30E6F63DC34 +:10363000ABAA62058D9E6E7878878BF9D5674EBBF5 +:1036400097F460B8C52B499391B5B5E95C3F6FF726 +:10365000A5115C57EA70588FB64307BD6F0F2B80DA +:10366000657D82766725CDE72519B663715ED152F7 +:10367000D370BC9CCB8C7E1127E9B3CC96B6676522 +:103680009AE74B8EF0369CD72D8F570C80B8F5EE0D +:10369000CE137AA70EEDF9783BBA0EDF273BBA0EB0 +:1036A000EDF9F8E7916637845CDD75ED847D0A8D70 +:1036B0005701CA7A85CB2408C5D9533B00A6937E0F +:1036C000A84FB38337B5FB3D635DF51204DA7BC1C8 +:1036D000BFD1FECC7FCBBDD2C7EB7A7B5F7ED94B0F +:1036E000FABAEA3F1B6DF253EA51BFD13CEB3F1BE4 +:1036F000F3857ECA4A5DEED6937F9111FF5C15CFAC +:10370000BBC6F172FBAFF575FEFA806DFAB65EE6E8 +:10371000FB7F75BBEB8A4C7B208CED574640DBDA98 +:10372000CB778D7E59E9E8987CC1BC76544617D199 +:10373000BC274C01ADB7EF9DD1D7BF52B73F76A4A0 +:103740004797323F28DA6FEC5EB2032ECFD924754B +:10375000F79FA5C3F3CC0CA1CF8BEDDAA2E70B4901 +:10376000AD285288CA85115B8DA71B2FB78ED296C4 +:10377000313FEBF46CE0E19EA45FD8982F5F1AB95B +:10378000CD25F59CF77A498C6FF897567AB5AEA39C +:10379000FE33C984BF9EF0B7737B973D0B5A8A9462 +:1037A000457258E8B77B5E1EE77492BCB141CC8588 +:1037B000B0982A674F7B9AEA3E195CA87F4EA2DC3C +:1037C000E6760D1D456C3FF96046AB84EB5D5A8390 +:1037D000FA09FDC5C5EBADFE57DBB88F480E86EC88 +:1037E00040F26BC9717F2BA95990EB9CB4EE4F90BE +:1037F000D5E8BD25B79BE5F9C9C33F76929E9716DC +:103800007B1A251FCF77DAD358BF69A753213B60B6 +:10381000E9DDE6EFD4EA7A84EB392497A057BFE4D8 +:10382000CA7CF447D03E816228263DF174F34E787D +:103830006724CD67612AC9F789081021CF3AECB314 +:10384000E2FC7DC31F794FAECCCF47B8CDB463BF88 +:1038500031B4FEE10316C7D1DD9D4592498E7D88C6 +:10386000FC3F02DF3BDDAC70392D5F9B988FEDF3A1 +:10387000F28393F359BEC7867E84EB6A5827E0D360 +:10388000F992B0E361BED0832EF9E65A82936B3091 +:10389000282DAC971B1BA99E6543FD8B7093E535C6 +:1038A000720ADB5F6DFCDD162938EB6A89EC28EDC6 +:1038B000F1EFE2B89BD26CD08272D1DBA25C41F214 +:1038C000D82B43630BBEB7E2D73FE471C2E942FE97 +:1038D0000F7FB4C286E63D8CDE2149F4F992682858 +:1038E0009754B1474DF4CB385E6A34CACF0DFB25EF +:1038F0003329ECB3E17899573AFD2D39346E451EE2 +:10390000C96B15C24CCF67287E80E3DEBF73782A6F +:10391000C9BBB3BB2EE7122E225C8A815C0920BB97 +:10392000C74ABFA79BF1F9E5DDF52BDA674983C9E3 +:103930002E45472DA904F5F78EC76DC23F16F3A893 +:103940005B17C9FA26E9B947ECFE6DF8D4FBA71955 +:1039500079B4CE1CBB2A11FCBE2929C2AED2EDB867 +:1039600005821460C1AEA77E4AFDB64CC2F5239D08 +:103970002C06FF50EA67730B7FEDBAA014A675E31F +:10398000825248BF7FB3AABD88F5D14A471AD9AF42 +:103990006462F466DFF667E75AFB7DE8882E7D9D5A +:1039A000F48D04FE6D043729364AD8898D61F63FBF +:1039B000D2209DF0FCA37C5D3E8F42394772694462 +:1039C0003087F8AEDEA6AEA67638827619D18FA4FF +:1039D000707F033EA0B43D49F663834D61BB038E07 +:1039E000697984B7CE5963F2499E9D714487B25C70 +:1039F00040792761FB83F9D50BEC088FFA4168DF2A +:103A000060FD2FF90B447D5874A90DEB9F3E71F3B7 +:103A1000023BC2B5FE8AE8FB548782DB447B7E749E +:103A200029F907830B36893A32120C423BA6E0AEE5 +:103A300005211CFFC334C3BE882EA279D63F7DB9B1 +:103A40006D531CFEBD05424E7E9820FA7D980337CB +:103A5000CC2678E74647C5C7DD3ECBB7E9724BD0E9 +:103A6000FBF26712224498C67BE0EB7DFC27F285CF +:103A70009E585EA5F7B3C77E4FFD9EF3A9E96CEF94 +:103A80009E4059C3FEDEE86D04977BF3D3B93FC176 +:103A900087FC3BEBF756901EF650BBF0EF8CEFFC2B +:103AA000295FC86D1823C6AF1FA4A4113EB2D285EA +:103AB000DD8C0849FB01C75DB6EA768DC08F57568D +:103AC000F2884F41891590BE79EE62761ECDBFAF68 +:103AD000F91ADFFB0F9D2E96B7E8F0C2B1C87EA998 +:103AE0007F7AF45603BF64E70CD6E1EB2D10F3A305 +:103AF000FE3C6E36C2776C37BD18E3F6B7CEE3FFF7 +:103B0000A47542A1780FE93C6F93D2BD0E236EF5E8 +:103B1000E15AFDBD12631E2AD3FFF267BE732FD593 +:103B20004151D365B6C77F22DE731BDF45FAC7EF6D +:103B3000AED2ED5C49FB8B93F87CD5C60E27D9BB82 +:103B4000ABDA258DECDD6E3ED36E89E72BEF70B1DD +:103B50004EAFAC795B98FF709ECC7F9AF0532DF4FA +:103B6000D2056F2BDFF6184F4D378FA7F2787DE126 +:103B700021B940E0FF7F0C0F2DBDC3B34B9E58E031 +:103B8000D7C57F39FA7B6390FF0A7BF21F14F4C11B +:103B9000B7395FF17B15E2BD55DF41FC51DC5A3589 +:103BA000D3F1AA1D39B6C563BAFBDF517B3840F2A9 +:103BB000BD2B2EB0E3F1D060FCB561570D903E599E +:103BC000F5D46F9F0CE1FB2B1EFB690AA0BC396981 +:103BD0006FCBF2E3FB75DB37A468144FB287524812 +:103BE0004E9E0CCBD3C3BDD85D37EA7C65D853F568 +:103BF000C0BA033EFCF5DF5BBF8BF3FF54423B07CB +:103C0000E15DBFE36FADA497F76BEE18F8685CF465 +:103C1000F7B1BEBCC6D3B816F1DCB0D36C07ADF8B3 +:103C2000D54FB354369842836D6C074506D37BF568 +:103C30000F3AFC14E7A93F2253A41F1A20D64AF3D7 +:103C4000B3BEDFD0FE0EDB590ADA73D9937AB6A37E +:103C5000E661BA6FD8F1A38FE5142A4FBE4EF1BDCD +:103C600086787F1AE15EDB873D35AFC01CDF35E02B +:103C700003E14CB65F5A1EF9D5EFD87E7C7D401E1D +:103C8000BA4170FAC1FF932261FBE9F6E1A935ACB4 +:103C9000C7D799E44E973D4E76802B5E9F0ABCAA0B +:103CA0003B258EDDC02E51D6392229E467D76D75AC +:103CB000F843F8B8EEB7FFFE10C58FE035977FA444 +:103CC0004AF5734E1BB54B5A4C62FB0952A4E26E87 +:103CD000FCACFCED7B22BE3250866AC4CF8ADF7F0B +:103CE00022FAA37D9B80FD573EFE16C763EA829EA3 +:103CF00046772FF8A96ADFEB8C7A7AC14FFB5BD34A +:103D0000C83E6F79E402C3FFE41E0906E4F47CBFF9 +:103D100076FB2927F1CB6944849246F8926B9CA9E3 +:103D2000BDE1297235D9BFD8CEF184FEF055443CAF +:103D300051C474CDF0AF7DDDE5AFA6EFFD6E4D0A49 +:103D400020BE3FB0370AFA7E60439686F3AF758493 +:103D5000B2142EC5F3DA5FDCCA74B7ECA55BB3808E +:103D6000F59F36D056C2EB1C48EBBB69CB3C5EDFFF +:103D7000520832DDD53E20737CE0133B4C7FBC17EC +:103D8000FE7855E70F17DC3CEEBBC2EE874DB89EC0 +:103D90000F9CF80BD64387E5F07689DAB7BD49F278 +:103DA000F1938E4C89F85D7EC9E126F8DCB23B6D5B +:103DB000AB0BEB8FEA72A4EAA54FA6111FDD92634D +:103DC0006F7429BCFE900E2F89E348B415504CCF78 +:103DD00081E37F2E38EBBC9EE204F8FC3EBFA93F96 +:103DE000C3EB836DAE44693C9659227E8C3F87A11C +:103DF00098FD6DFEE9E25B50CFD2FA9D8542EE362A +:103E00003CFCC1B4FB88BFD04F4945F89C3FF28EC3 +:103E10007310F60B796D3092E6D5F11ED7C19FA9CC +:103E2000A6FABAE1D1B0D30591783E7DF03D0B9F63 +:103E30009ADBD11E64B83540AA4A7EC207CED8B4F8 +:103E400067E83BF8DDED0AF943D83FCE1FEAA60B41 +:103E500067F7F39C6E7E33FC9D653A5F5BF165E529 +:103E6000F3C3163E872D82BFFBB67F438CA73A472C +:103E7000F821824F1DF26388F951F017A03C1C898C +:103E8000F47EEAD17D47AFC3759C6A7778ABF96B56 +:103E900066F959FB04F227F697D1FF4CF0131E2E5A +:103EA00038C97EF555A17F8AF33E451B86637BE1C9 +:103EB0004B7CDE2B5F7AC04FF6FD3F4B6E2EEB4303 +:103EC0006E5EB4C0F31318938A9F417DB1F232DA6B +:103ED00007B3C2D7F03FAD72F1E705AA88CB5AE429 +:103EE00022FE1C853838AEF8CD472CE73E4539C751 +:103EF0007AE8C1BFB15E42B0C65C48B7F5E18FB9A0 +:103F0000BE81F412D7F7CEA57DFF9EEB36C3D3DA80 +:103F10001ED1E54ED73EE43A0825937FB65BE6789E +:103F20005A27CEA595ECEC4773C22184CF06DD6EEF +:103F3000EF54622964676F4833EA70430DF50B8DC7 +:103F40005342F47E82BE8F1288A5A461D9A4FBE9F6 +:103F5000EBDDEF64BD8BF69B3DE154D6BB7171B7D1 +:103F6000F5C9FA7E8B4FF4379E17FE494EA1BC86E9 +:103F70006818A6F7162F4289CDF38E82689F2A5FB4 +:103F8000FC1DC517CF8646D8689FEDAC3BF63BDAE3 +:103F9000773B6BCF4D0F91FDA4DBA1EF86BE9685DD +:103FA0007382F720707412E13CA4390722FC6F146D +:103FB000A081DA175A52289E2D2717EE7F06DF5F61 +:103FC0008A80A778BE35EEB10202A9919C9EF10DC0 +:103FD000D47F4ED2F7CB500F71FC788BB97DC5AE34 +:103FE000534C7F2B2CF417D4F7ABADF4575DA8D30B +:103FF0005F1EE411FD4D953DECB7771E90C314870D +:104000003AEB06B62FCE229F2026D17F97196F67F5 +:104010001F95C2E4B7432893E9BA1EF980EC2A83BE +:104020003EADFE7B0FFFFE0F6F147F0FBBD43DF93B +:104030009FE3EEC7F2F493AF8D7A86EA4FBD3AF470 +:104040003FA167FFAA3D7F637FAE738F0B685E9DC4 +:104050007BFE3C94F471E7D32E3FD175E73A17EF1E +:104060004F86F624874752FB1081F796DD17C64529 +:10407000598EAF67FC7CBBD0C9783DBBEBEF6F526C +:104080007EC3D95D2E95D6D1B027897DA686A7138C +:10409000C2B4E9D3B9FB4271308E2EFED1F5D43BC8 +:1040A000455CB213E991F605D19FD7683D0DCF94D9 +:1040B000FEFB5AF23F76EC75523CBDEA4FFF358E5F +:1040C000E455E7137B9D24CFD06FFB05207DACDB4F +:1040D00031EE3E07C2F90CD980E84F0FFD43C3759E +:1040E000E44FF7848B804327C281D68570A9253B96 +:1040F000AC2F78FCFC5F161E1FB3FF50B76B02C8D5 +:1041000039F1709134F13C39EC9668FD7F4C194CD3 +:10411000EB1D86FADF4FEBBE308EE24BFDAD7BE749 +:10412000FF5FD66D832FB5EE57FF65D72DE8FFFAF9 +:1041300042A1C7AC7CD093CE9FFA16D77F97ECE70D +:10414000F95E22FF5FA0F517FD2BAEFF92F13E8EC8 +:10415000E2A05F16EF5945FF5FC5FB0B3ADE9315F2 +:10416000B2FB3B77FFD7505EEF25AEBBA8E85F15EB +:10417000DF5FBCEE2EBB490EB887E1FC6E87488737 +:104180008AE506DD1ED9807E058DB7315BDD260B05 +:10419000DF84FD143D560D8BF5FD870D90AF51BEAC +:1041A0005908ED8CED6CA7601DD7BD3158D648F18C +:1041B000241708FAFAC4EB7988E284767535F78714 +:1041C000A0F0638CBA32D1A550BD652DCE07EB2D82 +:1041D0009936A545ED1B3EB2F7C5F96437DA3D4E79 +:1041E00093FFE2B1F82189239C267F25019E55EC9F +:1041F000389F04BF1DC2EC07C6BD8FFDB522916775 +:104200009A08E190E2B92438B1DFB85131E0A4F165 +:10421000FA5DEA88D5643FDD5124FCD10DB01A5413 +:1042200082D311E17F76C1138C1F1D6EBE02E0F8B0 +:10423000B9DDCF75C78D750C473BA01F29D661F23C +:104240003B291F97ECBD78B856321C1BB9DE52EAE9 +:10425000525ACCEFF33A37A8954070DE405B02D457 +:10426000AEDADE728DFBDF83EB4D4522FFC50A57C8 +:10427000A32C8418E78D79F5FC20AF3B1BEC1C5771 +:1042800044BF81E38A0A903F2757423BC7ED02F6BD +:10429000D35DF62CE73328118A6FB5DC9C22F61F1C +:1042A0007241E53C1B4B7EC9E6DD0107D17510D993 +:1042B000564247C831F35AAECFF48026E1B83321D5 +:1042C000E0A03C0862EFED1C5F0D742CC1FAC1C286 +:1042D000CD3E8A873824753DB7CF90C2DBD9CFF564 +:1042E000EF4DC2FABC7503D369DE19D5E0F0527DFB +:1042F000768E9F4280872076640EE98DF9B27FBB6F +:1043000098EEDC0388B7393AD6AF4DBE656A12F62F +:104310007BAA48EC03CC87C03C0A615CDD1268A430 +:104320007DDB6B86C646A4C5C5399E29CAE17EF3EE +:10433000EC01C7CDF87C1ECD34BD277FCCA3C1F1E5 +:10434000F93C25E010F90D7ADE9476C557CA9B1A20 +:104350004FF0C275ADAC7685D7E1FC56FAFD6FAC77 +:1043600024B855BB14EC0195853543482E4E95CBAA +:104370001EB815D77BF85117B98F70EAE72F67532E +:104380009CDB5FF8ED69244FF3C0BF81F2F8964AD9 +:10439000FEE7BD84DF22C9BF9DE10AEC3F2CDB5262 +:1043A0007388BE33E75149223DF54E91D84F911F96 +:1043B00095589E66DC2B85BF86BFAE2D77B17C3AC3 +:1043C000B555623FA2AA3AB89FE2269B4B5C8A8B06 +:1043D000F1A6A5905FB44287F35F1CFE174650FF1D +:1043E000DF3AFCEB547A12E6FECB516E11BD9CAA6B +:1043F0005EF7339A4E6791CADFCB28AC298EE0AFC7 +:1044000073AA5FB2F33E60483B3CC6345EF0C7A57A +:1044100071E3AD2DFF158F7714FD5E8A139DBAB73A +:10442000651A6D7F2F05BF447E0BAEABF556ECBF12 +:104430001CE7477EF14CF0DF5548F423D7B15EB05E +:10444000E6531971938C424B1CEF41737D29F64959 +:10445000CAA7EF98FD31AB1FF65F459EEE38C0E569 +:10446000DDE303116B2F7119C3CFEA927F3A7E7699 +:104470009688B8EBF8742D189F9F31A658E0C9288C +:1044800077EEFAF4F59544F7852E3F0DA341DA1443 +:10449000DAE75D505B51486455E9CE7B8EEADF6C0C +:1044A000C43AC22FABD8C1DFB95E796B6A1AD66F36 +:1044B000F049FBA9AC5173A6A56339BA58E0E5C62B +:1044C000DC8AFD48D650ED9FE50C0ABFB992E8E2C0 +:1044D0002CAEDD85FCBB337A383B5ECF1A65052AEE +:1044E000617B9CBCAA7227803D0E3E53953453FDE0 +:1044F0006BBE81A6FE33D41C53FB3772479BDAABED +:10450000FD79A6F6DA62A1470E155EB86E0DAEF320 +:10451000D02EA742203C4470F176C3E550E9854A8D +:10452000A2E383A3030ECA4F30E65B506C67781496 +:1045300014838873D8859FBFBC8BFE80E97FF32CE2 +:1045400029BC0EF17DB0E89EFD4B100E27747F7FD5 +:10455000AA7C7CE11AE287B0C38F16092C83E07E27 +:104560000DFB6D86C6FD248FE656B8631457984D33 +:104570007100A9275DAD2DFFA09ADF2F9515E2E30D +:10458000A55BCCED8F155DFE3C7DEF31D42FB47F64 +:104590003BD79217319BF2B853A8343FB7D265A0EE +:1045A000D81C9F7A4C1271B3D02B425EF625A70C13 +:1045B000FAB4D261AD4E7F4639551E934A7269BC3A +:1045C000D3DCCF285F433BCC8EE3FC67B39BCB3778 +:1045D0009A152EFFDAECE3F2AD6695CB779A73B9B4 +:1045E000AC2D16764F4613E23B2EFF25A33AE0FC96 +:1045F000227EEA96AF215D9EC68E137C330E893CE7 +:104600003583BF8CBC850CAAC79D1798D9B42F38A9 +:10461000A500A0AD58DFFF59B2F579D28F3885508B +:1046200032BE0F757B9FA7FDABAEFA2D6F99DB6F86 +:1046300093F69BEAEB73CCF5DB2BF6C7BFDFD7FC19 +:1046400033AA554710F5EAECBBC5BEA5B5DD98DF2A +:10465000C1B5FE05BCDFE6D554CA6F0112F603A949 +:10466000DDD66B7E8201970574CE05C79D59E9AFF3 +:1046700089CF2FBB4F1FF73EFD7D03CEE0D7D4F887 +:10468000FC72EB78AF2D1BEFA038E76C1079347318 +:104690007741BA3ABEBBDF23FAB8AFA506A7F23915 +:1046A00006B21D88EE175CBE357E5FD15A6E5E5035 +:1046B0003364188E5719C89388BE32965CE3A07D88 +:1046C0008AA3B3DEB251397E18CE1FC7BBEE737515 +:1046D000C8AC3838FD49A7CBC37798F7578D72A778 +:1046E000BEBED76D22AFFCF594E09005A6F7DDFCC9 +:1046F000FE9F74797834598C331E0D3C19F5C0CC6B +:1047000061026E3006E13EB61BEEC677FB825317A0 +:10471000DDD123D4578BAA4123397FDDE7DA90D945 +:1047200071DF3FA8D3FF910DC21F22F8D6C4B5C3D5 +:1047300004F11D03DE3DBE3741BC6FE8EFA333211A +:10474000EC1276D45AB21B66A37E247D3C55F6B09B +:104750001C387A44F6BB585A087DBE8C7E5529E831 +:10476000EC97C85E9C5DE369A4732EA88F8710BC8C +:1047700097CD5F564DF149D0E5951BFF917D981778 +:10478000B19BE497552E65F423A7DE2B36EBCFC300 +:1047900094CFE5E89EE7597D9E7DADDB90570ACA30 +:1047A000673BF2F1399DEEDE93B5CE62E2173D6FC5 +:1047B0007FBC0312E2EDBD733A3D8CAF1079B17F3F +:1047C00029BF309BE873F58CE136F2370E4F3F97E7 +:1047D0004EFBCF065EBAF8B4A92538222E4EBD791D +:1047E000866B3EE153052D99E8E270A020A1C2D36B +:1047F0008DAFCD8173E91027BF70195FC857972A15 +:10480000E70E456D6C2F1C9AFC09EBB913B98A8D24 +:10481000F6478D7CEDB40969E23C45C93B1EDAAF31 +:10482000DD197DDB43FCBA00C20E927FDF848883F2 +:10483000E8F17A8872FD0600677C5EF78DA0715CF6 +:10484000F8268881349CEC6DE0F8E50313EEB89F00 +:10485000E297E3F4F83DB2FC465B9C9D3C6B8280A2 +:10486000AB5CAC5D3681E09BDE719CF462C6640794 +:10487000903CD690BE281FE860D18484C5BDE0730B +:104880005FD1E2DC09F1F0AE0E3AA9DF637A1E25B2 +:104890000190F0E448CBDD162F47C64F1078DF5269 +:1048A000A48DA3F71F9820F4FBF874212FE8DC24D3 +:1048B000DBB9B9AA6D539C3D30437FAF6B1C67D009 +:1048C000497CBED4DFC8F996955BF212A2BDC893AD +:1048D0007D45C172EB3C85DD24F4625FF833F4DB87 +:1048E00097D58F861E5C55AC7D9DBE6BB7893C32DB +:1048F0007BFA7C1FC10794B98CF75996F558E96685 +:104900005CC93BB71790415E6DE3FDF5713BD53750 +:10491000C8CFDA1C5AA0C8DEEEFEE3AADF7E7144DF +:1049200021F5971509FB6D9E3E2181E4EF664F68E6 +:1049300028C1E784E44FA0FDA6D0765911FE576C3C +:1049400021D1E1B2EAAC6184976BCA8B3A34AC7F77 +:10495000509D934F76E99DFABC4E82D003A180F022 +:10496000F34ECCF8C1501AE760D1807CFACE3533D3 +:104970005CCCF71F1C194E2782E068E1B2796BE826 +:104980001DDD4EFB375D4E7DF0E01AB6933EF00D17 +:1049900067DD82F282C73D385DF82D07417B9EFCC2 +:1049A00088D9BA3D76ED42AB1D26E4E4072427B151 +:1049B000FF9C80B93D63CB07C789C87BCA33617F41 +:1049C000F527D74213CCF697559E9DF48838C7EC4F +:1049D0005D705F3015EDE6E9398EF7C92F69929861 +:1049E0003E0CB936BBDABF97EC87D9D36B0ADCB87B +:1049F000EED4F00489FCBEAA6A756A128E3773BAC7 +:104A0000544CE319789B39FD668E43CDDC72B39329 +:104A1000F6FFB71405EE227A716CAF52691F7DD98B +:104A200096BC17E8BDB1A104C6F73533CFDA08FE4E +:104A30009B77A01DED27BBF6F264C2F3E107CF79A7 +:104A4000E3F393BBF9A2CD497E66E5831F0F22BE37 +:104A500030E402C01DF747980EBDC2DE8280EF0B26 +:104A6000E59CDEAF3F3917AA84DC46E6AB1787B278 +:104A70003F928DFE08CAB9AB4BF60E25FC2F590F9D +:104A8000BC1F7A7AC8FBF6433864A4CADD48FB9F92 +:104A9000541F57C8A9039CA7737AE0675B68DFAF10 +:104AA000A505EDFF6C6AFF94EBEBED6E85FA97C7F9 +:104AB000C0E4775CF599DBE4775480D98FA98BBE8D +:104AC000BD83DE57D6B994D46CF27BCC7ECD4E67D5 +:104AD000A4F545FC7EECA700DB883E951C8B1F34BB +:104AE000DAE207E599EADFC82D35F59F05313BE7A6 +:104AF000C3A9D078E7403A17A438580E6A4A2C3434 +:104B000090CE0B5798FA5F5332C3345EC18B11DEDF +:104B10000FCFC0F7295F78963B605E4FD3A74C77E5 +:104B2000939A2EB21ECD8BB49BDA0B0EEC348DE72C +:104B3000EF50AAC8FCCC3FE6DF47E58584AB7D7427 +:104B40008E4895A01126232B460355946F5C7CA2BA +:104B5000711F95A1CA463EEF184278B578F9FC233B +:104B60009F876C42F8535CE1DB32F039DA0BB660B8 +:104B70002DE91DC5A63E5023D1B99940564D0E9D35 +:104B8000A7099E227D52126BABA233AD133F6BDFA0 +:104B900047E58E8EB28D130B091E88671CB7CE6356 +:104BA00063FB79AABC6B1CE5A19C7D34A9203E2F38 +:104BB000DF387F033ECD5743713AEF887C8A3F054B +:104BC000AA9235CABB5CF5E4E51C6F3C30B1E2EF5C +:104BD000F43DE3DC1078CDE7A40F4CD4CAE83CC028 +:104BE000E10A59E4BF4C75B03C4BB485153DF8C89B +:104BF0007ACAF93507DBBBB79508F977F8050411D0 +:104C00004EFC709AB02F8B3B8639E2F96CB66E1F62 +:104C10006694E8F6380522719C5999471EA538EF2D +:104C20006D25C9FCBCB85A7DDE41F4A0D815F277D9 +:104C3000338E0594B138DE0E6FE15EF23F761CEBE9 +:104C4000289754EAAF8A7345D32BD65490DCCFB55E +:104C500003F5DFA14C49A2FE190BFDB6441AE7800B +:104C6000233C12E7B9BA5CECC7ACAE70FF96E2ED3C +:104C700019C740E45182B692E9E76AA74AF300BB3C +:104C80003FE77AE4EFF7508FA9AEBEF9F8BDBB332A +:104C900033495ECDAA5032292F69D6CF655D5E506B +:104CA00046378E4767B028D73834F0F8146C7FD871 +:104CB000A8232B03C25B711AF2052001EBB3A4AE4B +:104CC000FE0BA790FD31ACAB3D447CBC59D2EBA1AF +:104CD00041DC9E6119CF18BF68E7C0E31B3D041F8C +:104CE000E3FCA0924971CD0C5BC7383E6F67EBE0E7 +:104CF0007CF29B6CEA282A4B4706CB4A508E5E76A4 +:104D0000313542F0395FED0C131C2EBB78CD00928B +:104D100073A8F71FBA97E86D8A83E5FB0E67473DD6 +:104D2000E509C4321339AFDDF1D4F2463A7779D3CD +:104D3000CF667C83FDA0976CE9B2D437DC3214C116 +:104D40008F863DF191AD6B9D1A9ADEF091D45D276F +:104D5000BE5CD5BD4E6D849BF35EBAD6EDC6FAE25D +:104D6000AE7AE9C27771DDEA928773291E780E3C2C +:104D70007C2EED5CEE75D7127ECFDDEDE0C3933B6C +:104D8000A82BD1B52F51C4D5BD815CF2370F750862 +:104D9000BBB31DF1AEE1428787A29EB185F4BE3D53 +:104DA0007D13763B5736A08AD677EE36A0A024DC5A +:104DB0001475828AF26447EE92964A2FD1A59A4ED4 +:104DC000FADB58E7311A07EDFE6313B59B4A38EF5B +:104DD000C488A77EF7CBC553ED31CEC3730E87468B +:104DE000CA3B6E28593B86F4F7B15241FF0D53245C +:104DF0008EC337349D67F956D7748EE16B9C1B3D8B +:104E0000ADE721B739C4F9E1BAFF966F20FF12E58B +:104E1000CA46299FCA679DABE3F814DA3FEE928F2A +:104E2000E36DFDDB7D89C16AFEEE2C499947F64AA8 +:104E3000E48FDF5F4879F6B312947914E7B9BD7453 +:104E400085A80F51E6515EFEC3257F16F581CA4F36 +:104E50006D281F5F288D8A7A8EF20AD5F796E8F5BD +:104E60003CE515CA33D851FAFAC22983D8CEE0FD01 +:104E7000AAB3D313D8FFEB6B3E739A9E31C5597A10 +:104E8000B4CB929093F385FCF968C640966346FED6 +:104E9000F32A9BC2F9CFBF2C912CF9CFA050FEF37F +:104EA000AA511D8B52F83CAC7F2AE57FD5053DBC4D +:104EB0007F30A7690F7FF7B04D1D4272F27459F031 +:104EC00021C2FB99E40EE6B397AB5FCE22793B6B30 +:104ED000A27E2F89121B41F8590041F6531658CE75 +:104EE000CBCEF58C70D03ECDDCF966FB6D0E44D890 +:104EF0008F995DFDC5E74CF1BB8B9066C0A1C36384 +:104F0000557ACE487D5E7F2C21792DA963A9EEF0DC +:104F1000766409FBFE5195F54AAE9BF7B313AF38A3 +:104F2000362ED80BDEDB9B517F222B3D81FE2C954C +:104F30006388F7480EDBA34E3F8E53AFCBD5A972E3 +:104F40009D4CFC7376670EC4DB712FEBFA2275A7BC +:104F50008807798723DCBD04DFC86D9C5F3E46C0AF +:104F60007B952D924D787859D70B065E116E7A1E7F +:104F70003EB6E7D1794CC403F6BFEAC617FD2D71E2 +:104F80007898A5CF6B47A2E0F7D81F12C2DB727AE0 +:104F9000CEF3A43E1FEB7C2FEAF8BFD4795EA47950 +:104FA00016F53DCF8BA4AF8AFA9EAFC1B7069C0C15 +:104FB000BE055D5E2D989FC3E73F8CFAECEA1CF6B8 +:104FC000138D79F6A49F07D5DEE8A73FBA39566A54 +:104FD0003E776EC0D1989F210F76E8E724BBE79714 +:104FE000B6D53C3F713F416AD31F593EC8C9767E52 +:104FF0003E37D7B795F669523BCEB2DD96AAC2CD01 +:10500000244F7DA5C304BCDBFFD69A5148CF1D12A7 +:10501000F17F6AD32E7EBFC7FABEF4BA7A9797E5BE +:10502000280858DE914C96C83E0E9AECC10A3AC93F +:105030001E9FBFE9BED9B20FF01D53FFAFF9D69A3C +:10504000DA67A83FB4D8BF7799EA33FD3FB7D8B73E +:105050005B4DEDB3DC0F9BEA65D10EB63F0F354FCC +:1050600067FF79F28918DBA111DDCF7E56F7B39F78 +:10507000233F1BF9733FF9D9581E68F6F3F3FF6815 +:105080002EE1F2C5668DCB8EE6009756BE2EEC88DB +:1050900016523E5B893795FD90C409C125A5889FAE +:1050A000D223B111E47C4C3CD6CEF6F186BDA536B8 +:1050B00027C51F5E94C30912E9C909A9BD9DFF3424 +:1050C000CAD4CF64D0E2E24CA9D531A03CEF543D24 +:1050D000EE32CBF3EE143E1FD2A448A9A8075C76AB +:1050E0003F14627D6850B93984F5E5A5C27E0C682D +:1050F0006BD94FB816BBD23EC87C37DA4138DFF9DE +:10510000B552B885E383216EFFA65BDC1BF0C4813A +:10511000755C5FE08188CCE738C47D12F37492AD92 +:10512000F0CE799EE9B311FCD4FF5856EBAD6EDE9C +:105130002736EE8F78DDF6F99597AEB797534C8CFE +:10514000F21D243FC70B426976DE9FB0EA53AD548F +:10515000C4D3AE6E117A3E96038DDB707ED7905E1F +:105160002539A6203CC88E6D526D040F830F4BA2CB +:10517000B1D60C2F5D8FE5E0FD9B3AF8781A85D803 +:10518000EAB4DC18EDDF17BD1B6C21BA30FC1F83BD +:10519000DED17FD8974272EE38F03E4FE2E41FCA6C +:1051A000E46F949E0FB75079D5C57699E47E7F7EE3 +:1051B0009231FF5DCDF3995EF63407B98C34D7EAAE +:1051C00074D8C8F5E79A9BB8BEBF39C4E581E68DAF +:1051D0003A1DB671FB8BCDF772FD507358A7C78788 +:1051E000F9F9311D7E7796EAFAD25DC1F145B08BAF +:1051F000D2E60E59F10FF1F84F4C17ED8928FF4315 +:105200007971F480F827795DE7D3E5747F7490BEF7 +:10521000F156A78DCE856C7698EF3FFA72F430D7B1 +:105220008306E8B09E72EC5A50395E699567685FF4 +:10523000F889EEE700DA7D695F426E43A39F421072 +:10524000CECBD02EC9F92AF645B091E6D3FFF704AC +:105250007E6C490BF95E2EB4D3F9BCB423EDE82281 +:10526000BA6FC2F02F7BC0C5E26F96E9F7607CD9B8 +:1052700079227C1C4407FDCDF38989DA2B24B70CF5 +:10528000F824A60B3A491CE4E13C6FA72B1C5E47AF +:10529000F2E69904916FE1090C8D3F5FFDA62E6F38 +:1052A0007E344A7BB394F7072FEEFD9CECD00E07BB +:1052B000C7D7EA9F7EED92ECA406E59CC93EEFD2EB +:1052C000F3928DF57C830D82949795EF02B78473EA +:1052D0005C3DB1F27429DB25651D1AF1AB62F7C79D +:1052E000DB51D6B2A1E9631EBFCF769BC8FF6AD857 +:1052F0005DA4C49F0B1F3351D2F3E2BFDABD63E557 +:10530000B1F92639F12FA73FB5474CED00D142C284 +:10531000FF755EA117AE09CE607C2C8076E6C38552 +:10532000D0C1E52288711904714E7B31F8B95C0255 +:10533000012EB71405874DA478B533C07191431081 +:105340005B42F7E97C34B954A9809E72F152E5A022 +:1053500021FF0C79D8EAD4CFFD74C575BC7914D778 +:1053600031F05138D1BC4F67E5AFCE3C95E7DBF962 +:105370008749360FBEDF79500E4B6CA7A9FB39FF6A +:10538000295FDCFB52B050BF9F0905C848CA87B1EE +:10539000DCCF74AEECDF582F9FA3A834F1ACDD9FB7 +:1053A0007B7D5C1CB445DF7F7C184B3A6795B2303F +:1053B0006A57E3E8ECEA89828F2A164C01D27FF61D +:1053C000851A2589418A22E24253DD509880FE28C1 +:1053D0005C3C3786C6BD5AB71336392042FC30A034 +:1053E000244F22BB62FB28ED9A899971F72551ACB5 +:1053F000F532E2139443C42794FFC572E8672C6F1B +:10540000AF05ED79CA63A8F7AB2C5FE680808715FE +:105410004EF5657F63BEAE47BE26F858F977F1CEEC +:10542000BDC7E8BCE63F6A872E36EED7B1C017D7B6 +:10543000B582E8C9BA2E235EBC0AC4BD5A772C3C9B +:105440001CA0D2382FEA84883698E4D0CEC781E4F5 +:1054500050BE2CF227633384BF63E5DFEFEB78A8FF +:10546000D3E50104D50292DF9D929A2FEE57026197 +:10547000BFEF19CDFEC5CF261AE76343BA9F54B6D6 +:10548000E17E01673EDF763AA1F77B7F364D14FB64 +:105490007473DCE74DF2AEBEE96F2639553F46E046 +:1054A0003FBF452DA0FCB435FA3EDF77F2037710FD +:1054B0003C56B4DFF5E48B2A7D77CBB7E83E82B368 +:1054C000073C6CB7C08B990C23E31E3363BC39EEE9 +:1054D0008F75BDBED5B45FF4F2CC57594E93DF4EF5 +:1054E000E7D30E4BE21E32637E876D1DEFDF9FD345 +:1054F0002D9FD17F7EF37B39249F737E3486E0F924 +:105500000707C7BBEA68FE19E44707B64DE43C1B32 +:1055100091477B78C695EC9F19F65DE7C9DEF7EBFE +:105520008DF919DF31E6755A924C707C4C87FB6916 +:10553000DDFE79D9D17186BEF3D193574A1460EC60 +:105540007A9ED6312ECDD38D9FFEEC22AB5D5CE1F1 +:105550006DE1FADC7EEC2294A4CF53BF63AB855D92 +:10556000347F599B83CF137D457BC8986F4B328422 +:105570009D54EFEF7E33CFD17D416FF7FD6636103E +:10558000FB62653E11AF74D17832A56D867D541AE9 +:10559000F79A19F79919E7748D7BCD40F3FBC8BFD3 +:1055A000DDE0ADE4B8C709F034529C7C5EDAF472F9 +:1055B000FC2C2C583A23487C31B72585F793EC4EC8 +:1055C000BF7D2FD9095F17FB7BE84FB0BDFE8A2650 +:1055D000F61D0C7819799AF6B4D034F663AE43947C +:1055E0000CA67D0A3FE78D5E8B7625F57FD5DE988C +:1055F000392687F6CBEE1E47F7752D97C3296371C1 +:105600001D1F1EFE75F1417CED14449C1E6C5FF560 +:105610005C94EF1B6BF8D2FBDB41AE2F83B607F631 +:10562000E2B8AF65DD77EB5EE886C37CED97EF2DE2 +:10563000C15AADDC9E552175EF475D485894B5D7EA +:10564000DBBDDFD1DFFE46AE1C942765D23E47DBD3 +:1056500022714F9CB8D7113966289D939B8443D102 +:1056600079DACE4C4187A18F81E1D7E9F0B35D13A0 +:10567000FA4465BBABB0CAC6F884CF558ECB4EB2E8 +:10568000DCBF5678A5C82F87BFABFC7E79CC9C9F2A +:105690005138FE2732BF8F72713BC5853EB37FA163 +:1056A0001CDE3649F0576186AD313E8ED1E2CB1219 +:1056B000F140BDEE52158E6B4C9C24F46C21C4CE8F +:1056C000505E763DC5970BB9D75C7731AF93E974DF +:1056D000D2AE537C0FE01619E982CF25B757D138E7 +:1056E00065E44FF829FEDBA8097F0E7D1BDA4FDC4D +:1056F00069BD674DE42D2768D04E7CB649EA900914 +:10570000AE93D1BCA6520385EF9FAD043F975320C3 +:10571000C0E53468E4723AB471F97568E7B21A3AD0 +:10572000447F5F5288CEA74E0437DFF7290FDF276B +:10573000F8006E53F8DEA119CB6C14972EFC37914C +:105740004FD51F3C16EAF0F0113C0ABF3A3C68BD49 +:10575000B40F3C4DBFD7F77F0A1E5F8310F3FD0CDB +:105760000873F90D88D8057DAACF513EF6CC13C039 +:105770007203AE88301C4AA241BBD00F1678541970 +:1057800074853A3AADA75C5BAAC3218DEE182CEA6A +:10579000BE67F1EE492AD39771DF22F29D4FF045A3 +:1057A0009B4CEB6F9584FCB5CAADC2A4CA732A8A20 +:1057B000F67593FE783DC5C10B0B2AD70CA7730174 +:1057C000939E13F54995BF1F86F53B27FDF97ABADD +:1057D000EFA6707C658103E1B8563A70FD14AC0FFA +:1057E00057FD3EBAD7EAAC7EAF55CB4BDFE77B9A8D +:1057F000D08652246C3FEBF9965F213D9AEDF1D3B0 +:10580000BADD2EBF3FBF90B7E31AD79692EA6DE498 +:10581000FE885885E22DE9D3C5BD4E4341DCC7F46F +:105820007433F03914637D6316AA6B24C453E6897C +:10583000D002DA9748CA0F6C9854446C88E3E0B8F9 +:10584000F72BE23EA8BB27E9FEA9F7AE7DC142B225 +:105850005370FD38EF65F9814DD4BF33D91DA24097 +:105860008431EEC3BA3D596A6F93D778E8B9806F37 +:105870005FE5B393B49F901CB23EEF4B1FD9922EBD +:105880002EAAC7753590AEC0F23793825BE8FD064D +:105890005B7468013E5B97F4A693E94153F85C4161 +:1058A0008B419FB5488F440FCF0A7AEC3A2F40F6D0 +:1058B0001AEDA72DD1644AB5CD9A1F5B94E2A5EBF2 +:1058C000BCC4F81316C68A498EE3771EE1EF38A3ED +:1058D00043F3F03B77CFD1BF03D982EE74F9D4B054 +:1058E000E76F67E8BEB6DD36E41B619707208EAF31 +:1058F0001AF624D889AF1A3E8470520EF1D9232D9E +:1059000064CF97229F81B88F6A1FD939BBD688FB95 +:10591000511BFEB47B1FED57947D2381E345E52F9A +:105920001F1F4EF6F155C7A32D14C7EBDCFDEA602F +:10593000310F639FEA82F455F4F954F9B61F937E50 +:1059400058BDD60E742E79B5D428EA0EB722CE25CE +:1059500077B42E24B86BEE189FBBD0F3F46AF575BC +:10596000E138FB4BB1FF477A9E3DAA3D96E32AFE04 +:105970006379205FE4F3C69F04515F63FB84635641 +:10598000391FDB4FF93175FA7D6CD6FB45ADE7E089 +:10599000ADF92DC727E9F92D4360C857BC87ED1D28 +:1059A000C2AF710F9B717E79F503C3B7D1BED5EA43 +:1059B00007D630FFAD1E32269FF8CFB8970D22CA0A +:1059C00015D4EF3149ECF3C1F4334C3CCBF4B92D91 +:1059D000DF28F17EA33C5C8612F487C63F3460C5A5 +:1059E00077992ED083F2517DC2FC87BD6C3F354242 +:1059F000199FBF607BF2B1B4D8301E374D8510D2ED +:105A00006F4B426C18C9D3D06EB79FCFA36CC960DF +:105A1000DA1D1EF2DF4B7A7EF55AAF44724329132A +:105A2000722DE74809DF637916F53DE16375F228C9 +:105A3000D3BD93D6B290E61967EFEF7DE9DA24B2D1 +:105A400087FF600F2451DED9D923C3BE303E5C14DA +:105A500041A07F411CA3F0C8ED1D94A75478AF9DD1 +:105A6000E161D0DDD3CD5AAFF9952A84ABE85EC0B1 +:105A7000D537A11CC2FAEA17FEBD85EEF75CFD43DF +:105A8000CEDC457B665C2AC167C70B32EF7B15C352 +:105A9000C32D65582F42FA0C23FD3C0DED32C9652C +:105AA00097CF066A1C9D24A889A0C6C5199272D3F7 +:105AB0004DF564FF2053FFD49261A676E37C8861A4 +:105AC000DFA6695798FA4F800E7915AEA304F92026 +:105AD0008233CD989E6F6A87F382EE4BF09FD0930E +:105AE000027FAE904B213D3CF1B4992F4AA28D7CB0 +:105AF0007F5C82CE370947ECA673FA2ECFFBC7E94D +:105B00007E3F573FF95F5A997E4F613664F796FFA3 +:105B1000754F528A4DC053C4C78A61C43D65D85E73 +:105B200074C0016195FD46D0F39DC2E4C7749F1B0C +:105B300009B750BF49241710EE990133BC07CC3781 +:105B4000C37B60D00CEFC1B566780F6934C3FBB27C +:105B500026337C734266780EDF38D1D47F645BA530 +:105B6000A97EF9BD5F37F51F1D9E6DAA5FF9F0751F +:105B7000A6FE63DB179BDAC7EF5C61C63F8A7582BE +:105B8000C3D35180FB727AD2435E64B5B9BF7C5CEB +:105B90005E45724F3FAF5170E0BBBDD24308FF116D +:105BA0003D58F1DF92F07DC67FB4C6D3284D647AAC +:105BB00088901E4ED0CF17F5A0877EE8606D992E95 +:105BC00027753A30E4635F7C6BE079B1AE97916EF4 +:105BD000368C31E235B89E80C7F73CF9034AA59B65 +:105BE000EFFDB8276928FB4B81E1D0487971171286 +:105BF000C639486EA96BA5185FD268F117254FD337 +:105C0000AF484E6D69C1F56453DCCF7C7E67CE74BE +:105C1000F3F99DFEF6378A3A22A67ADE1190494FB3 +:105C200016BDABB624E3F70A8E8B7C2DAB9F5A18BA +:105C300015FB2E934E77ECA3FB4126E8F79397C410 +:105C40008CFD95C65F129F4E4279CAF7661F4308C6 +:105C5000E0FB4E45BC8FFC934BF6701324FA897F12 +:105C6000BE2D0BFFF8822DC8F6A1D55E6CA908B039 +:105C70007D8BF67F36D99981BCE09365456232848D +:105C80006F59BFDF7FB21BFD61CA95817620BFB718 +:105C9000B32BDF28B888EE11EB24DB6610DA6B2D0E +:105CA000D72F0A911DE005255A4CF14FF173B02C06 +:105CB00018294339FBB624E2A235DA3B4377E07C6E +:105CC0009F25BB97F6FF17B673FC69FB286D5F59DC +:105CD00051FF7923465CCD88B3ED688E709934C648 +:105CE0002F131D59E360519B32258FF4D66AE17F53 +:105CF0009FA24995F27752589EB8A1C315B7AF1726 +:105D0000774FFC06DAC734EE895F2CF9D92F5EE9AC +:105D10003BCD710E972CF1FEA22B75CC36111F31A5 +:105D2000E21983E52F63FFF4B7DE95BE93A638181A +:105D30003C9A714979A271EBFCC52D825FF8BEDBFC +:105D4000B7670CAE2479DDF33B6738BE767DE34B55 +:105D500026FABEA1E935133DD784DE32B547BD3101 +:105D600007C51111CFFF4DF85BF564C28FEF26799F +:105D70009128B1BCA9D9E1F8169D2FEF7F9DA7F816 +:105D8000FBC79B3B189FC63ADF6C3EC6F568739411 +:105D90004BEB3A8DF883513A9F157F572286762434 +:105DA000DD3FDA5F1CE2FE72913FF06D39F0A688AC +:105DB000F74486501EED855690849F195B44FCB0D5 +:105DC000504AF1937E6C1DB8FF0D8A4FBC624BE5C3 +:105DD000F5416DE40D8AAF376C127E09689107C8F2 +:105DE0004FEC4C49E1FAD8BCE0B072E2AB317ABF7B +:105DF0000C9BB04FBD912124A7CE64D29DB6F4F781 +:105E0000210223B91F2841A2CBDA74F473D3E8EF3F +:105E10003F84C6513E54B0BC7D11F97127124367CF +:105E2000C80299BFFB37A2EE14FC58BBFBA7CC7F7E +:105E3000AFD864F63B424F4B224FCD1375D2398C0D +:105E40004F738379343EE57371FE3F3E9FFD057FBE +:105E5000CFA1A45CE4B794960B3BD32867970B398A +:105E60005C5B6EC8E3DB47F17D04D52E203B15BF9C +:105E7000AFB19DB8C7C5FCD67D6F2328746FA377DB +:105E8000B87A8EF8CA2B03E7B17CA33CC714EF2580 +:105E90008792FC9FD94FBA385ED035DF23227FF43A +:105EA000A31922BE0C14842AECCEC3FA46B9B03B27 +:105EB00057BDF0F69B24AF4E9705AF298FCB575AAD +:105EC00095B297E35B35E52A7F0FE7C97EA24B8643 +:105ED000F5B44FB0CA2DE265FDC5C9FB5AF7473787 +:105EE00075FC8CE2726792D591F41DE3BB388F9AF2 +:105EF000F2B8F519F3E81EE78BF9C288FB1AF5979B +:105F000067FE6014C9B97CCA47EB456F7E5B87C3E7 +:105F1000710758F2D574B88191AF26EEEBFC898EEB +:105F2000E7F5E562BDCF3BD53536812F3FF9F5DE8C +:105F3000E18D61A2536F86B8AFD91897EE27A7FD00 +:105F40009A858D39BF7F11DB573C3896CF3518F3D2 +:105F500030C6FD4EBEF6FDF2387F1AE94DDC6F32D9 +:105F60002381E963D59ED7DE24F9B0FC57630B0883 +:105F7000BEC67B56F8225C393FEEB02DC2F043B866 +:105F8000FE88C67DE2C061CE4333E0FB55E169FC8B +:105F9000BD8ECEADDF11F7140F0485CEE9AFDAF573 +:105FA00067FE7B61AB8CFD17CBDFE7B0EA1B058298 +:105FB000DF243FD305425EB88CF7B2EDA6F7D6E6F4 +:105FC000685BCB797F0454D2DB2EBB1E57D2F550D1 +:105FD00091AE3FA563D7B6903DDFF5F739AE407D72 +:105FE0002EE2A53C4FB75BC449BAF4BAE457B93DB9 +:105FF000283F7716C7955F167A7C0284D81F2985BB +:10600000600B193F2EF966BF38AFAFC7AD7EB89FA2 +:10601000FD76926064570CD1BFFF8BA4338F47B0DD +:106020001C16F05792581E313FF0AC835BC23CC93E +:106030005FD67C9AD32AD8DBDE84DFFBE56A631D5A +:10604000217DFF47ACC70805AE4B1AFA2CC527B611 +:10605000E9F185614975361261972F09ADA3727414 +:106060009D7FD032B57BFCE1AB4B3E0C62BDA2CD37 +:1060700065A338984313FEB17B14CA4CA26F7BA36F +:106080009BFCC257CA455CF65CF6E1B551E81BFFC4 +:106090007736BB8F4E89D3238A1D24714F84F89E97 +:1060A000D2E4394AE75F87346571E99822FCF61F2C +:1060B000640FDB497A64CD58258F4483F1FE9972D1 +:1060C000CB3E2AC0D125A6F886FBE892B8FD71091F +:1060D0001473FB185F773BFB63AAA93F40AE653C96 +:1060E000BFA51ED689A5C4F29E66AA3BA69BD77102 +:1060F0006E8A9217CFAFD67B4B7FD4EC33C1C96386 +:106100008F403C9C3C4DD90C9FB4A6515CC6E11B12 +:10611000B42CFD7C27C22963A376523F1F046FC7AE +:10612000C54F48D0BF6D9A2F76277B967E91A9ECFC +:106130006AD7288EDF173E2FB5BCAB196D9FB8F517 +:106140000C83592C177F1084C6B528D7F6662F7696 +:1061500093DCB8AB597BF95DECD79A9DCFF18634CF +:10616000BB22519E7EFA147C6EF2C3C2267839B4EB +:10617000B91D533268DED3DD64270F4C9FCD74A95F +:1061800082C6F50DCA6C1ECFADEF535AE7B71EE7B6 +:1061900017893B3760D7CF770205C94BBBE14AB9B6 +:1061A00072ECBC5CFC5C263FC629811EFF12F073BA +:1061B00018EDFA3D7E89653F0BDD28E479A3CB47D6 +:1061C000F57B43F4F7B6DC74CF28D7AFD35ABD7C48 +:1061D000DFA72AEAE2EFA225E4C6E107BAF1C1F39C +:1061E00023FC79BBDAFF4274FB8FE2E752CB0D163A +:1061F0003CF668776AB5A49F36648EB2C59FA7FC4B +:106200007B79E53593894F6813E612ECE74BEE078F +:106210007903457C5EE047B81258564F63BA4F8BFE +:10622000A7F33EE89EE275FF5B74DF6A81D766875D +:106230007F20F1F1E6B5D2FCDECE0F5F37D966BA2A +:10624000EF3237041C97716CB18573248A4987F843 +:106250007CCC846A9107E87EA3AD86DA9FF23A553A +:10626000A63B3D1E516C2CCDBBB49AFC8DA7B688C5 +:106270007DBA4FBCC0F7F9494B9B0611BF39B6BC7C +:10628000CFE70A294C4D7AF372BA0FD24F71119BA6 +:10629000E9DE9FF13B134DF7048D6D4F37D56FDC71 +:1062A00038D8D47F7978B8A97DD9BD579ADA573EC6 +:1062B0005C60AADFD436C9D4DF05373F3B96E226BF +:1062C0007ABC398DD6D60B3DC031713F11AA2596C7 +:1062D000DF975BEE2F1A5D6DBEBFC861BDBFB69F75 +:1062E000F887357EF2C8643D8E66DC5B6BDCAF32CE +:1062F000C57B49F7AB8C7A2E81F7E336F8845D30A5 +:10630000304BC8A5AAE90171BFAC8E3F3A2E2CE4F0 +:106310008A2A117DEFD6E5930107C7F98E2A7ACF35 +:10632000F999A08FC95E5B58E33C863A96A3ADDE2F +:10633000D9FCF731063A033EE2C7094407E308EF08 +:10634000F37DD49EEE15785F1E964DF07111117994 +:10635000059D901DE1F00D93C8FF32EE23EE01FF85 +:10636000E3E2FE27E3FCBD15BE93CF9BE19FFE0F4A +:10637000C2FFB5C9967B83BF24FC9DA1B6482AAE57 +:10638000C7A1804A719AA94B6B39AFC9E1F333BCFD +:10639000A6EBF742387CE21CAE555F6C6D8648BCBC +:1063A0005E76AC572A81F70BEA426E7C6FC346805B +:1063B000012AA12EE826BC6DF055BAF9BC7D38C87B +:1063C000FB88EB510FD17C5B074E73931FF0699AEA +:1063D0008DEF5A6BCD09FA482EB46E1572415A7A78 +:1063E0006F0DCDA3352D2BC7C5FA2492A0DF979D45 +:1063F00020EECB05B77E6FAE5D9421BB68D7B81C8D +:10640000B5C5CCBF4047B4B15F4628D1F25CB351AB +:10641000FFCEC9C20F4F9B9E6EBEEF4B1B64EE1F9B +:1064200082C3638A0DD2647AB1D5E8F14DE253BBE1 +:10643000BE6F6AF7FE2444CF8DFBDE12F4BFF7096E +:1064400021412F46BCD36EB93F6CD87AEB7D6316E1 +:106450007AD1F9C3F8FE40A7C0D7FA91C0F75559D1 +:10646000E7232D9DEE23BECA819F003DCF297129D0 +:1064700061DE4150996FEC88AFFB24BAA7B88DE577 +:106480009F5DBF67C23A4F2B5D7DE9797F493A2F07 +:10649000BEAA0F3AEF432F5AE97C634EAB8BFAF753 +:1064A00075AFB1ACCB91F5FA3DC8E099AB9F9306BF +:1064B000E67F87A218F903368A5FDC59FE6994E209 +:1064C00037E1B53EB6BFBBEEFDB6DC2762D415BDE5 +:1064D000AE9625BE258B3FF4F3AC7EEF8C96CCFCBC +:1064E0006183C9F974EE6FE3CD4417C63A3246B4FE +:1064F000411BD27FC2C57B80E456C208BF1414E59D +:1065000017C20FEDCBF62923FB6E4FD3EF9BB13EA5 +:106510005F7D959BE19516825EEFB969BACAA6DFE9 +:1065200033AFDB833A9CD0CE78CED5CB7D6C5D701B +:10653000F10879943E05E71587D79EFD43A67B5960 +:106540000C3B44F189F96454AB6B096E8A22FC055B +:106550003514801A92DF7DACE7765A0F7E3FBD8FEF +:10656000F5FCE42A615F58D793FE4F5B8F52C1EB75 +:10657000F10A3F4E0D6940F7CA24D8DBD8BF490065 +:10658000B79817CA91F87DDA84EADED773AD811F18 +:10659000BBBEBFABAF47D1FCA935BDD857D6F5E0E0 +:1065A0005CDAA7E45EC27A3CBDEB176BBFFF2DFF40 +:1065B000A3EFEF0A3FA355F79B8CE7CEDBC4FB4E5E +:1065C0007B10B2E2E0B6EF2A99FB1FBC4AE421BA85 +:1065D0007CF85EBC9F11EAE1F78406187E0FE24B5F +:1065E0005B22ECC864BFAAC7B3DA38DE98E453F381 +:1065F0003741F77C56CADAC1ABE2FCD104FA2587F1 +:106600004AAB3D8EB832FC4E30D9DF5DEDE457D950 +:10661000757962EFF663FF47ECF34B2D093F6F7F0F +:10662000817C59EFF4D7EAE7FECA7CC59C7762818A +:10663000972E4F359B0E9F006845747C2D18817FE7 +:10664000E23A8CF2FF0118C8B63E0080000000005C +:106650001F8B080000000000000BC57C0D781CD5C6 +:1066600091604D4F4F4F8F349246B26446C6404BB7 +:10667000D6CF180BA76D8451B2C2B4462369C42A81 +:10668000DEB121C6385E32961D4E84B03B71364471 +:10669000E158A62D4B42D65A58B24C20E025635BF8 +:1066A0008ABDE0809684EFD8EFD8FBC6E6CF39D814 +:1066B00044260EE7DDE312C5F6729B2CDF7D5A827D +:1066C0009370EB8BAFEABDD79AEEF1E8C7CEB7BBBC +:1066D000E2334FD5EFAF5EBDAA7A55F5EAA9D7B53B +:1066E000355D590AE00198DEA9033495C6D361846B +:1066F0007B0D75DA1BC0B234B0730AE15F0124026E +:10670000584F3FF262FC47BF6800BEFA3F339BEB35 +:10671000D9E7E9A2207ED7BF9FDEC6E1445103C27C +:10672000A1C53BD3D83FD0E94F7883BCBF81FDF3EF +:10673000F8AFD87F072CA3FAB0CAFAE7371E35A9FD +:10674000BFEA02DE3E624C4642BCEDA54AAA7FCEBD +:10675000DC85F5814A99D57BABA2997AA075FC7549 +:10676000FA351CAF6FAB3F6122BE7230E6A8CF2B6B +:106770006DFD857B259675329CB57D67CB41BC143C +:10678000FAA502BF5DC27A954AFC71E3F7ED035F9B +:1067900071613F08F2EFF8F323C287D5DF7EF5651C +:1067A0006F12E06C7506060D912F2722EBC158C1C0 +:1067B000E5ED014C80B24CBBD9C6B5DAB5B8FD3DAC +:1067C00012361D094A29AF8BCA9E6027C28F57C94E +:1067D0003AEDDFE30D9D0380F085A0046E5BFDC8FC +:1067E0003B6E565F88DFE0D39971CB6212A46D7463 +:1067F000BB66531EA4D50C3C12D95014F7CF8E574C +:1068000079DCD9FFDA2E67FF7BA3F1BB0DC4FBBA9D +:106810004489E3FB0DDD4B1CFDA6A3C6266A375059 +:10682000B126E77C2F458D2DC62DB43E8E0F34E466 +:10683000A6D77EA47FBA16E09B499595F3E1FF9415 +:1068400068FFB4687F201960E5B3C9202B2DBAFF1B +:106850004A8BC64102789E3EE598D7DBFDF68F2332 +:106860008B6C308AC5441DB63DB69AEF3F18DAFAF4 +:106870009CFBBF1300D7D568C41EA6F5039CFCF192 +:106880000C7F239FD67CF8A5F08BB47F55526A10FD +:10689000F76EA005B9D54F74E8D944727E2182FB0A +:1068A000ACCDBEBE7D627DF3D1A15FB4B36075890E +:1068B000124F119D2F22BC06EB09A16599FA11C355 +:1068C000C5E8A25E8FEDEA32ED1EA376EECC7CD554 +:1068D00010F4E5E27B6FD0C9370BC5CF6A372207CA +:1068E0007C015B7BE5D208C4100F9FA61A0C1F48E1 +:1068F0004CDF80F451AA021AD12DF31D19B69EF473 +:106900004C496AB0C2B69E2A294AEBCDC6AB449E1A +:106910001A5886ED4B4E2F5A853B054F1A125B775E +:1069200009ED2FB67FBDE2BEF077EAA97FC941929B +:10693000C7455167FF9F527BDCDF81EACE13D4EE5F +:10694000428394828AD9D709C86433724274447EE0 +:1069500087BA85B7274D9C0ED9E1922C784956FB12 +:10696000CAACFA1BB3EA5767C19FC96A1FCE82EF50 +:10697000C86ABF210BDE9CD5BE33ABFE4B59F53B3D +:10698000B2E0871DED6B2E6E2ECAC55FD97C63B554 +:1069900053E438E875EC5C60FB371B3FDEB3B6E9C7 +:1069A00097248F6A65C3354CDF1C2B71E8CD0CFD35 +:1069B0006172BB0DBF266C3F35071F03A4183F0053 +:1069C000C4CE6C77AC7BD319FB38B3CD9719C764B1 +:1069D0007CD8DC110F1F203E2FC5F300F9AA7C31B3 +:1069E000F21BF159074EE4A2F3D394808D6FAC2BC8 +:1069F00047F95CC1A700599C03C7883E5ED257EB9C +:106A00008B6237E13813E930F19BEBBE4D463E8E89 +:106A1000DBFF329E09D8B4D5DDB8732B9DC30DDEE4 +:106A200000D9117D93C35B699E50B9A29938D68A6B +:106A3000E01A571AE137E3FE043410FE0AA3A78ACE +:106A4000FFD1B97AD384E2D0FF215032F446BC178B +:106A500081AD1E61706F99531F74BFBF35F5BA6D5C +:106A6000BC8AA682D20F68713743FDA56599FE10D6 +:106A7000C87D4EFC26194FBD8EE7F4BDEDC0F7630F +:106A80009676D9F456A2F82BA337B0F3B7E5BE6ECD +:106A9000D6B5F8B49BC14A84D7FF4AD0BFD55D773D +:106AA000BC88F4431034AA8F06E3305597D90F41C0 +:106AB0000238988474048DB691985E4C7A4DE90D35 +:106AC00058FB60AAB40FBBF93E20DF00ED9327F816 +:106AD000C1FB80F64BB91203A27B3FDA473DB82FCA +:106AE000A1E07D1D50486C26E8EB0217D1BFB257DC +:106AF00071F07736BD3D59FB61D14FCEB21766A319 +:106B0000FF7AA27F3E1BF8E67F4BFABB2A5546DF91 +:106B1000FE6A4E7F2F8C98C49717902F0775661FBB +:106B200031FEEFAFE3F548E7C272B403892464FF96 +:106B3000A8CAA421131FBB60BA47A7736DCAA0FEE1 +:106B4000F9E56E30917E059161464FB26FC9DE2D39 +:106B50006870D2ADC870F2717E161D7DBF271D1FF3 +:106B6000B6E8782BDCCAF4C0BF111DC936A4765B29 +:106B70009AE2BB9B102E3661A707BF5DB3651A680A +:106B80003EA4A344741E0A71BD3214E2E71098C6F5 +:106B9000BB75484FBFE0DBA68D6754BBBEEB15FA53 +:106BA0006437D953587A8CD8561AC71352B4149DE7 +:106BB000C39036C91E95836E4823BD5D1BA3E0427A +:106BC00078B01C74AF467EC830B333C0DD6176D672 +:106BD000F37D75633B25B4C560ED96823EA8113EFA +:106BE00078EE20EC43BE07F26374F9EC14D23D80DA +:106BF000FFE5B2E37DC0EBAD7D5196226CA3BB0CEB +:106C000036B8E2F27DF96ED6BE5C802DA63C87BF19 +:106C100060EDCB5BB719DF6BA27DF1972E489FDB50 +:106C2000F6E555B62F29D8A9203ED77ED9B92FFD34 +:106C3000516EFF63C9E4E1421530BBA246CE63F05A +:106C4000A8010EFBC62A07C57998B2EC63B277712A +:106C50009FFA84BD5BBEEE23733B8D8706149212B0 +:106C60000A4BA74D99FCBF65E8BFA13C28C16973D9 +:106C70000CEB7737AB09F428A0A8F403E320D60780 +:106C80009771FF4DF92DEE2BDAC17DE61490DE02EF +:106C9000F403F33F0333F6A106C0F7B7619AD52397 +:106CA0006C1668CC6A895520BE83EDEF44ABB0BA50 +:106CB000FFC4DF9C24FBB6A45ED67D04F7684D8C30 +:106CC0008F221050495F991393619C7751BDA49313 +:106CD000EF5ADC319C26FE28B9580412E25DD71425 +:106CE0003F4FF4FB8BDE9762A4B24BA220C5917F8D +:106CF000B57080C9C93E8F5E4EE7E26859C045FA5B +:106D0000B639A295131FEF6BBFEF86F89CF696E19C +:106D1000921AAEBCCCEE9F3DAE171206D13B1806C0 +:106D2000238AF51E774C27BE2ECDF3541C5A82F4CD +:106D3000BCE65EB6FF9EAA422325F0DC6A93BBEB5D +:106D4000C3DC2EB560AD91F12A6884031E1C5ABDC8 +:106D50002875F1BD4EC0210E2F0E6B8C2E9A21BED0 +:106D600057F1EFF3D1E34AE7C91EFF06B11FF8A5BB +:106D70009CCE35FC79B5600D7093057F1E70C7AF52 +:106D80000FE3BA8CEDDCAE29D0395FE7433C4DE729 +:106D90002BC8D80FEDBA51DC4FDAC7D1EB80F1BF69 +:106DA000D9A2A4C649FFCA81F28D36FB705FCBC65B +:106DB0004D06D1CF059BECF6DF074DDC4E7F27EC6F +:106DC000127E769D8FCEE97D782AD0B8D6FEDCF58E +:106DD000DF176F8DA27C36DDD7153E4472582AE44A +:106DE000B05492889F47A2C0FCEC0B911E379AD6F4 +:106DF000B8C4B89BF8FD163058793368ACFCAF4284 +:106E00004FFE8DD093AB68C9CB487FC599BDF63B8B +:106E100023DE18BE85ACF3008335D077CAB89EAEAA +:106E2000B1F5469C2BDFBB3CA8877B059D32F4095E +:106E30001C24FA44043F3CE08E45887E482F705164 +:106E4000FF68AC95C60DA546C2C856786E186D543D +:106E50007F6EEF9F32FE52047F2105A53C5CCFBEC2 +:106E60006A6D15E9DBE5630610BF7D3ECCE9F4E20F +:106E70005A631D8DF390D8BFAE0F87952212EB5445 +:106E8000A2390FDBAF391A7B8DCAFA57F4D7486D98 +:106E9000AE9E0834E76B347FFC6EEAA70FB88E53C2 +:106EA00038C886C726FA7E6EEF171C7C4EFBBB9E49 +:106EB000F1453C48FC61ED1BC8F1207DCFD023C6D5 +:106EC000EA418E0537DC64B3FFCB72EF774CD0E735 +:106ED00041B11EEAA92C76F0DD8384CF6C7CE74BB0 +:106EE0001906C5BC6E3C331126FDB57272FA04A1B9 +:106EF00051777232EC47F86B6BE37F46FD3BD3BAB8 +:106F000042FA2934357C82DA59740A550D4BC4BED5 +:106F10005F5B6B7C9DE83F12D9D7CCECF6F38843DE +:106F2000C5ECE7855CE5F45380CE4B9CE733E7F393 +:106F30001CDF913F8D43385E9F881361C9FCDE7D65 +:106F40001D12B34BB194549A2FC24E4FD8170DE770 +:106F5000E78CBB083E9D107C6A7DD785FF843F533C +:106F60006EA4DB2E26C297F3E113193E7C42F0217A +:106F7000A39F96E1F36FD9F9BC38A2BB48DF58FB59 +:106F8000DA951A695D82A4088D69AB29CEB1FAA49D +:106F9000FE1A91A66BAC7815C187C5F82FAE8D1D72 +:106FA000A4718A239A8BFA3D1F06F6DDE2AFAEA8E4 +:106FB0003146F3239F8D53698D9F3D9EB5BE43821D +:106FC0002F707F9EA771516EBECBE4E6E430DB6785 +:106FD0001CE70582B14B33E99B91340428CEF0FDC8 +:106FE000C8476937D1F528D7032B1AA6C2C4539FC7 +:106FF000D2D32724846F0A690AC591EE4FB91DFBCD +:10700000B52AED8C9B21FFBC4A786EAB32597BDCF4 +:107010006785F1F702ED086A59E8E4E7B7E6E2E7C9 +:10702000858EFBB3B5B11F125E9A39CCE474C1F8FA +:107030005CA1FDF38061FC03E12B4B106771347F91 +:10704000BDC3AEFD99D89F703BDFE7B76E8BFD9C4B +:10705000DA4384FB47573A1FF6FF05AD0B0CEC5F94 +:10706000C0ECAF0F092E9E72EDF4545C6E178FD6F4 +:1070700073B91AADEF0CA7C85E0A71B95240F7C5D3 +:107080006EBA7CBE211157DC23ECACDEA4C6CABDAF +:10709000C990B0C37456FE45B28195FDC9288F5B77 +:1070A00000F77786027CBFCAD6ECD8C4E3BBC85DC4 +:1070B000E47F6E14F54B81DBE91DEFB2F860999225 +:1070C00030280E3FDAA44E935F08415B9CA892E9FA +:1070D000CB83954852E5B41B48BFBB367699D41E86 +:1070E0007998DD13E04F21F9A796DF54D8D1CAEC87 +:1070F000F137D11E27FF5EA9BF031CF70059E37BC0 +:10710000616BF869C2B39EC72D6B5EBF3F4CFA68D6 +:1071100014E994CB2E8506E147097FB5A8D4E97719 +:1071200079B3FC2C390B2E5B83FE899FE2A5FFA06F +:10713000E6A27FB1E1D49B65EB78FBA68D0DBE5C2A +:10714000F19AFCAC38DEA8F07F066EE90CBF28D6B9 +:1071500041F41F58CEE93DDB3CA0DBF432AE6BB40A +:10716000636171CEA17ADECE8A5351DCCA1EEFB4C0 +:10717000FC2C6CB7B58FE81C80554CD6859DDD473F +:10718000BFA33D81C71F74DAEC374F206B5DF3E07E +:10719000931D179B2FDE66E165B5936583E12DCBCB +:1071A0007C1DD5D0E0A33878361E5B9BB91E1FED41 +:1071B000E864E714C913C9E6289AFFCCAE0B49D19D +:1071C000946D1DD971CF4DA2FF3D6B8DADCDA8073C +:1071D0006ACEFFBD4AF35B7C61E9038B3EB2A0CF70 +:1071E000CCB90A1C1F065764F4C3B78A13DFA6FB89 +:1071F0003273A70CE3583E99FFE811825798DE805E +:1072000097BE87B11EF1351535B04BA7FA42A65F80 +:10721000BBDF2F60FAE1379219EFC7F11E69AE604C +:10722000FA6A97CB08D2BC2B6488D494123FC1A1D0 +:107230001E16A780A392D3EE7DA4B98CFCEC098620 +:10724000A7DB1F67FAE700D93175763DAE1D1A64DA +:10725000F8C23169B1D06728AFBDCD2E361F9EBBB5 +:10726000BD440F4BCF87DCB17E827FE1892D3ECEBE +:10727000E6E57EB164BA80E236C1CFEB9306D9F081 +:107280002B401F07F2CB9C7E33D861F7E5F041B16C +:107290000FE5350093A4B7E5541EC9CDAF8E6E40FF +:1072A0008F702EBE0FBD17B1DD9B79E504E31B6F18 +:1072B00077DD7B74AFF24A53FC59C2DBD3BD86C184 +:1072C00080F524E78DB71BDFA6EFCFDF6EA4885EC5 +:1072D0006F37035B77F00B90207EEBC9BF17B6DAF0 +:1072E000F8E6E5CBF09BC823FE78FED8EA79E452B5 +:1072F0009F05BF7A0BBF97687E4FF7DAF7223713E7 +:107300003512EC1CB976ADF1BD6676BF637CDF81CA +:10731000DFDD885F1DE1B70EEC7EDC1BCDFC5CCBB6 +:10732000A6DF7347E7C6AF2FA9BD47F1430BB6F4FD +:10733000C5DBCD1A8F5B7657313CE5EE95023FD029 +:1073400065A77DF076F31C7ED6DFDE66BC43F5C113 +:107350002FE85326F9F5CF2BFAB8467AD91083A037 +:107360007F44FE790C8A075791DE3219DFFA28DE56 +:10737000EDA671D20C2E8029061791A647F8A724F6 +:107380001774CE82E6A2EF8BC8B25C96A18F5A8AA0 +:10739000E3223EA5DD01570FC92F0AEE1FE03C7E18 +:1073A000FFD28374AE40181D95521A4C65E78CEBE2 +:1073B000E89B9FB8D8A1F54880C56B7C11D7A5FC88 +:1073C0008C3CCFC86B8F0C74EF6CC973B790673C63 +:1073D0003759FD80470D507CF0EB6E33DE5741721C +:1073E00013FF3FB4FEDF48C626C27336F971178C0F +:1073F0003139BD52B9417BF2B734FE532E63D51BF0 +:10740000A457CA15267FD9FBBC28C2F9A3B48DF3B3 +:10741000777F3BF76BFA9BB85EF044B8FFEA8D705C +:10742000F9F74538BF7F1036E408D96D149FC6F2CE +:107430004CD850EC705F93A1DA61FC89D4201DE434 +:107440007A607495D7BF43463AFD8CB96C7ACAD23C +:107450004BC83F25115BFC410E4C008BB788F14AAD +:107460009BF97E927DB5DE763EDF20F0B4D643F602 +:107470009BFD9E74A6FE0F457DD459AF097ABC755D +:107480009BA145B0FCDE6D464584E1BF2540F70178 +:107490002E7399EBD28ACCFE0FD2AFE574DF1CAB12 +:1074A000A5F6BEEA7A265756994DEF97A2C68A08E6 +:1074B000BF07E271D850EE7B1985EE7F6FB69F4F04 +:1074C00029869732E327A54384F76CFD33FD389E68 +:1074D0004FE6AF945A900FC62B6466D78DBB629B64 +:1074E000EF27BEADE07237A29E5B7C1EE72BF6FD58 +:1074F000F3E2F328D77BC4BA465CC0E4C55C95C709 +:10750000E21FB1DB630FBE4CF2F287797A0F3619B6 +:107510007FA29FE503F82A54662F7CB68DF3C757E8 +:107520002BA23FF81C8E5BBAFE4E1F95659FDBD6E3 +:10753000BE11EB17DFF3D5DD04D3FAB6E33CD7FC7D +:10754000F1AE1FD0F7E0D651DF46FC5EFEC5E62265 +:10755000BA17556038467926F08E9BF16D7B851CF5 +:107560004BD9E8B9A58DF3E5DD6D7C3F8B233C1E3F +:10757000371B1D521ECED772736247CCD6EEDE8803 +:107580009B8DF3BF05DE4F274F067AAB292EF9F608 +:10759000697E2E8044E742BF0C3AD9A77B4D554700 +:1075A0008AC2B56E43DB49F8ED92197E7B1BF7A9C1 +:1075B000F6F9B7B59633BC8A823FE4E398F2F494C7 +:1075C000CD9E7D3022E2BF3AE824AF7249B4682EE6 +:1075D000FC2DBCE887F263C8E7A7F8ECD35D1F4138 +:1075E0005F3DBB4F67F1D32577FD9AD915A0F1F820 +:1075F000695F71AA89ECB9231572E210ABCFFB3930 +:10760000E5B72C89F5FF8B1BF55A5157569ECBC514 +:107610004BEEC062D2AB2082AB3CEF254FCC570083 +:10762000BCBD65D7EC2D4D410FCE3FB5CDAF01C5EB +:107630006543CEFC97138D9D2AC551C7F13BF1DD03 +:1076400070A492D165BC81DB6179C5B141BA3FC9F3 +:10765000FB6CA5B493F24B0AF83E8DC7745F31966C +:10766000CF7426BE44FBD5DFB1BA3D1FE7193B00FE +:107670002E17B61B1B0E0F12ACB4C801B251BED9E7 +:10768000CAE5B63628B1384FBF3AA996D791FF124E +:10769000CE5BEEA77A95D58F055CD109EBB201E7F9 +:1076A0005DDAA51F667A1FF4DD4D389EB771B59B74 +:1076B000FC970FDB1411B7BBA84AF8FD48420EB087 +:1076C000FC98FC47F3A85F15D28D6055C4F95DC3E3 +:1076D0004D706911E9EBC809AA2FAA57348ABB1467 +:1076E000259CF7026A65B7B10DEB3FA67B08DA8FE0 +:1076F000AC7B022FEC61FBE2CDFA6EF1C150122699 +:107700007B3DDCAE3F6B3B9FFF4B44DC57EAB08ACE +:10771000CE8D16F7FB9FBB9BF0EE9274349FE10871 +:10772000A486D620FC7197CCF8F799AE974FADC1DF +:10773000751E78E48DE25B11FECBC44FD6DF8A70F4 +:1077400089E1865E5CC7B3BDFF3842DFBFDD7DE106 +:10775000147DEF778DC4283E7EF8EFDCFA4E840F5F +:1077600023834CB2B899C1ECE102919FD2AFE07E85 +:10777000D9EFC15BC4F921CAFEE4C9D364F7A4926E +:1077800051B68EA1648C9581EEE6499A77EC646CD3 +:10779000B38BEC45B308F2AFCFDC7FFBDD70471352 +:1077A000FA91DE37761D527DC893C74BF23A2C987A +:1077B000FCD4D3EFC63EAB67E08AEA3B9F3E6CAB9E +:1077C0001F771983CBB0BECE7CB033E223BF3876AF +:1077D000663BCEFB71E08CE9AA24F97B85D91B05B9 +:1077E00037719B376F553C467ACFBF5F627CEFAFF6 +:1077F0008B65EED3D9FF511EEDE76FBD53BEF12768 +:10780000A6DAE4349CF2B2F10BA30AB38346FCDBA4 +:1078100063CB918EE355DC0F415E8A4DD8E4FF5D6A +:10782000C1CFFF2ACE23EF7EC9F4125F04917E0EF2 +:107830003CC4B994FE17A07349A9EE1C6E22F97FCF +:1078400042D2495D64EB116BDCF1FD3BD45CE79304 +:107850008547F63C56FDFF6DB5E29BCE79B361B529 +:10786000B2CBF8623DCF0BA4FB366FACCBE8B3E9EB +:1078700025E5AE87999EB2F2F42C3F8A995AC8BF8B +:1078800045DDF94C6F2AB187A003DB059BD569BAAA +:107890002F82A571D35DCADAB17B9E96CAA041FE44 +:1078A0004595B857DC7BE21E49C33DAC9613928EDA +:1078B000EBDBFB9949809BE8DE751A4C5C576DE366 +:1078C0002450FC56A99F4C17E138CBF68346FDA205 +:1078D000FB75C94772FB8E1BBC4CEF9971DAFFDA5E +:1078E000FD0ACBF729AC4747BC92EE8B1B96103FA5 +:1078F0005AF7EB2867ECBEB2A8D70853BCA3C25016 +:10790000A7355C6FED00D72F958D90326CF7C6B51B +:1079100042F5D4EEFF75BAAB3413FF8003C27E9BF1 +:10792000B95FB7D973F8AF2ACBFE2B223DB1924A8B +:10793000E7F78696193DC0CE9554F21538E72155E4 +:107940006EE4D139A6C1A4BA9C9FAB90CB1EB4CA39 +:10795000E750BF1888EC0B499595C79201305091BC +:107960009C4D0619FC727B38D25246F29AD84CFADA +:10797000DD92D7737B8B3E4D7CB5CD9DEA71517EF8 +:1079800068CB89CA3C94B7E7979EDDD0C461268F47 +:107990002FA45F2AE9D033F0B1D327367CD606BFB7 +:1079A00058F51ABBAF627031C077FF52A15421B8AD +:1079B0001361B30A61117FFFD488143B44E77A89CD +:1079C0006A121E1FD7070E92DE954B104F92E7E505 +:1079D0002507499E7B5B38DFCAB1F53C9E972DBFDA +:1079E000C4826B447E2750FEC297D3BFADE779A611 +:1079F0008B8297CBB747D0DF13947F69D7EF5D5960 +:107A0000F4FF181AFF280C39F501F38B2C7DE02EBA +:107A100028F5D1F9DF971C60E7FC8C1F56A6ACB2A5 +:107A2000DB059EC244672C879D70B28DAF6F3A6AAA +:107A30007CBDE5968CDE9CCD0EB5F45FC62E8DF731 +:107A4000D07EE6CBA900C59BF3756639E6D07B4EA8 +:107A500039475E67F7548787791C6E68CF06E6FF63 +:107A60000E0DBFAB929F39BE7FF5A09FEB81091A27 +:107A7000776F1948F0A92BE737AB9DC55F33769632 +:107A8000E0B3536FFC9383CF1076F099055B7C666F +:107A9000C1169F3198F8EC36CE6729841D7C368458 +:107AA0007C56373F9F9DFA77E2B397FF83F8ECCF80 +:107AB0005B67F8EC75E297ABE0B31F5D0D9F8D0738 +:107AC0006279642F8ED7F3BC4A2B2F67DC0C1C64C1 +:107AD000FE0C707DAB7E2B70D0ACA0BC568E677355 +:107AE00003CF67AB6DE4E783BA56E4B3D5F37C2AE2 +:107AF0004B2F5B796C2DEE3D711A677C8FC2F2AB18 +:107B00005C95AF9CE822BBB31CCF05E4ABA3229EDF +:107B10005A089A44E7546D6A0AC88F0AA11EA73B07 +:107B2000EA82B12996EFB33CEE4F18810C5E43BD5B +:107B300090A2BC3638C6F5B595C786DB25515C6783 +:107B400079CA692756D74B3FF7AEA4F8A6D30E2CB7 +:107B5000CC827FDDE2F4231E17FADEA277A1B0CB40 +:107B6000B2F705F5F745DA07EB5C181A9E3B2FD400 +:107B70005AB70587C612E15CFB7D672BF7C7BAA22F +:107B800086DA7ACB15E15348EDE73B4FD6B5D62ED2 +:107B9000B3CB39C287ED726EC1969C5BB025E70C02 +:107BA000B69D27D7217C35E7C9BAD67F1F395FDD5F +:107BB000FA1F23E7DB5BB93F8C72DED47A75E749A5 +:107BC00007F5BB52395F3EB65362F7ABC45F39F07D +:107BD000F20ABCD01F60F19BA6CAEEBCB3581E913E +:107BE000F56B4AB0FCE35697236FC52A95EE3BCF61 +:107BF0006CB7E5D35BF14CA57B23FB5E1531EE6DD5 +:107C0000A5388FBEB078CA0E8A4351FC58496CCE55 +:107C100045BFB0882778F290BE39E8B54A0E7F9903 +:107C2000E67BBC3DF6276C5E4869A40790DE7F7A50 +:107C300095F47EF86AE8BDAE15389EB3ACE3ADD6D8 +:107C400079D7D1C7E4BC3DF658EB2D8E750C5CE5B9 +:107C50003A465BAFE27C38D5C2D7A1CEC4B975A68F +:107C6000CF9A2A37E5D1FCCF846377901E3EF2434A +:107C70000F1C725DEE3F67F864FD99ED37E7E29304 +:107C8000BB1CDF4792C0E2F74F265516272F9135D0 +:107C90005709F9BFC90083479341567E8BE2E8D567 +:107CA000EC5E96950728EE8FDF9F4836307828697E +:107CB000B0F2994AEE375F2327D83825111CDFA68A +:107CC00007825B701EFBFD6530E0A82FED083AEAE5 +:107CD000976CD71C70A031E480AF4BE80EB82A1225 +:107CE0003F41FBB5F8AE06C777F47B1CF042E54395 +:107CF000938D93AD8C6F809D7FB5D7438AE8EE0D51 +:107D00009D3C43F1746FA96292BE83A5F28733FE56 +:107D10004B25E3A71F09B93865E7A7C7049F3E268F +:107D2000F37D1C0BCA013AE7C7C43B8BD72BBE7946 +:107D300086F86568B8B292E5F1228D495F7B8BB514 +:107D400043D44E17F1C2B17A49A7F3F9E3D3FCFD4E +:107D5000920C7E86C76CFE2E04CE9CEEB5E9E9EC53 +:107D60003CCE0F5AFD8EF3F702E9676D76FA58792B +:107D70009C561C64B6768A07ED1DB29FAB36DCB10B +:107D80009CE2AF4159AFD6D8B4AFFB6DF772D9F7CB +:107D900076BF8BCCDCD37DD26ABBA7FB9D889B23AF +:107DA0009DA2D47E6CBFC4E271E38D8925C4774760 +:107DB00046C24590433EAD7220897498035F558159 +:107DC000F8448EFE2B841E1CDFDFC3F07C4C8384C2 +:107DD0001BCFDF7139116376D652BE8FE38DFA1255 +:107DE000D23F4786944DB49F03C7DB41A320240AAA +:107DF000DF391B7FDCD0C6EF777C9A6D5FF0DF61E7 +:107E0000C27F0EFB6501F853300E7C6F3D71D8E4E4 +:107E1000F1C1770A9CF759D56D73E4BB5CE9F8F3BF +:107E2000C571BCA4CF88FF5FF3B1B8B38CFCEAD3B3 +:107E30002EA787775832BD39F8379B4FFFA0CDEF7B +:107E4000B023AE944F3F6CE5F8A05C37131DAE42F3 +:107E5000AEEF68E372DDD16693EB3F11E38EF8F885 +:107E60007D53361EBD426EADB870F5490855146598 +:107E7000EAB78AF87F5B24C0DA55EF373576AFB2C0 +:107E8000403D65B5A3FB945C791E56BB01576EFC63 +:107E9000DE14FC3D94D4979CF7509CDB9552D0BFE8 +:107EA000B5E2595564EBB9337E0B72D012BAB719EB +:107EB000AF97392C237C13C5C345BD6AC1A2DECF61 +:107EC000DB5BF37DDDD263FFCFBD2997BCFD67513E +:107ED000BF6E596207C9F5F191D625641F8D55F41F +:107EE0006B929FE82489F7876F76B1FBB759E8A4B6 +:107EF00074379DC979FF34731E4658FD6CEF2BAD66 +:107F0000D2DBFD3F7F42ED94EE7FFE09C5F3BC223C +:107F10006F4309C624BAA7B6E8344653A03F352AB2 +:107F2000E8A90C8391CA41EFCF59F5945D41C2791C +:107F3000711BBC4C76B504097AAFA1C48626297E94 +:107F40009E1D4F54EEF2B27B0F80B849E704F92131 +:107F50000573F07F61952E0D237ECB2EDE2D915E75 +:107F6000AADE3FC5EE1FABF7EB73AE777F1226E6B6 +:107F7000D2EBA5C26E25FCDC88DF5E99CB48696335 +:107F8000426AC7F1BFD7A68A7B0CBEFED24B3BB577 +:107F9000F5B6F95E17FC5EE616F79F629C31314E2E +:107FA000D9F024D038AF8A710A681CEC5F46E3D45C +:107FB0005D3E4E75039F0774FEAEB45A8E49253957 +:107FC000E86EBD2BAD4606E5F7273189F854FD9DD7 +:107FD0009BF9516D9153DB28BE8AF6CC92F3B8FE23 +:107FE000FBDA604EFBF85DC1A7A84FFE8EEB039E47 +:107FF000DF309F1E99C30E7D4FE897336D4E7BFA9D +:10800000EFDBAECE0E3DDF7615F674AFB04317AAA8 +:108010007F7A867B34BA3F3B3CE966F73487E5C913 +:10802000997B9B4304ABFCDEE6705729BB77B1EC30 +:10803000D6C3C6C12736A2FEFDF583926EE2F76B6A +:108040001F7CED077713B9BEF263DFDD085FF7B57C +:1080500073ED9B187EA65B421DF4D3EE657F4DEB5E +:10806000B8DEE567F784D63DD2F108CFB7B6EE7932 +:10807000168AF7487EA17C11E777C7F9BBA827F3DA +:10808000D7A6E95C7CB64061F17410FE297BAACCCE +:10809000F391C0B598E21EC0EC96E30535269D1F0E +:1080A000BBEE07B6EE5DDF50D879F26C99F3DDC90F +:1080B000AE203F67BDE21DCFB305227E13E2EDAED9 +:1080C000AF9B647904D713FFD37D4D03A4CC8A4CB6 +:1080D0003EC8AE248877D753F7507D3148FA208DBB +:1080E0002B1B1ABD43D925436A27B6DF551730FF2E +:1080F00013C2CF240A7549A757AE3AEB0F371A4C73 +:108100007FBB45DE54260FE41CD8F340901EECDD07 +:1081100051E52392A0C7CA1334DFAEDD39E8A18947 +:10812000FF2D66EFBA197D8EEFAE7985F2460EDD32 +:108130005FC8DE2D1D2AA8994833D8CFECD443D58B +:10814000337E0DCB0FFC6AC14707BB34CAF759B960 +:1081500099E671E3BAD8FE7A5F2AE7464B40FE06FD +:10816000ADA793E75BF4A2BF41FC6DE5D17804BDF8 +:108170003C553C2EE5E96E7C8FFC1B7777EB7BE46E +:108180000F23236CA2FA3C412F080F1F8F23EC42D0 +:10819000FA0C8ABFF390B2F236F87C26C5C9F245D4 +:1081A000BD1F26D93C85300DFC1D4280D1339BAECE +:1081B000D6FBC30C5DDD8EFC1AE504CF9F71F7C8BA +:1081C00040EF23CC7082E5D7983DDEC0AE52966F6B +:1081D000C3EABB6535E0C5793F1FAD14F926895B5D +:1081E000F9B8894F51E98E1A9BA3659971ABA3C663 +:1081F00096E82D19D82A2F3B07451E8005F753FE18 +:10820000601DE5153AEFFBADF3D18217D1BD3FD22A +:10821000F33055A13CAD4C4D87C964AA35533D643C +:10822000C7D58C71BD7BE3ABBCAC7D8597DD513789 +:108230001BE72B517ECE59F08A815458C57E1563B9 +:108240005C9F5BFD56CCF4F3B07629D12F1595C514 +:10825000FBC62E9637FBC2DF72BE54FF9BC85FA4DD +:1082600083630DBDCE06C1D73C0ECA9FCC90BD3AEC +:10827000CDFC825492E75F82FBFD130F90DC05DD9D +:1082800040FA23644E84E92DCE8AA3C3618AFFDFBE +:1082900078000225B4AD4846925BED182A60E4FBF5 +:1082A000DADE0989F2386A0C75DA20BEF9BEF39E6F +:1082B0004BBBE8667C5879005229927BD379EF5505 +:1082C00003891E9AB7A2C11BA0F77D2BB2EEBB6A31 +:1082D00045DCAC36EB7BB6FDFB4C34F73BC8D9F440 +:1082E0009C65FF864C60F9D9B547A514BD2753FF9F +:1082F000EA2CCB9F731F4849749EC09E1226D42F30 +:108300001C8DCDE93F3D27E8F88278F7704CE46F8B +:10831000D3FD06C1FF24F2B73F10F9DBBF14F9DB30 +:10832000E745FEB6C59FAA8BF3D37CFEA3D715679E +:10833000FE1594CBC0DE2DD143AA4F67FCBFBF3AD8 +:108340005A29113F3CD7682ED990E3BED73AEF8F18 +:108350008ECFED577D671EBFA746F83D60EE184BE8 +:10836000FB29EF90E7E35A7EE073C20F7C4EF88161 +:10837000978D7F7C39BBCF8501F47B6C7EF8738D44 +:108380001AE3CFDAA79C7EE0A183359B6F24FD70B2 +:10839000CA0D225D66A9678EF7243F8B4A96BFFC03 +:1083A000B3A8CD5F5EE8BAFE31FAC5ED64F7587F39 +:1083B0006F65B63842F6F9B9D0BFCF62ED7776FD7A +:1083C000FCF10393DD971C15F191A3A91DEAD6BA20 +:1083D0000C1F40BBE4D05797EF3F9F7FA0E221C620 +:1083E0002F5F3DC8FFFECBD19978CB436CDF8E2E3B +:1083F000AD92D8F986F24479E1DF491A67B6235E77 +:10840000BB6F4BE46DC076D7B5737FBD464EE4D1EC +:10841000BED44CBA25521135DDAD67F839B39DE5B0 +:108420005765CF5F23E232F0D4DCF197C5EDBF5F33 +:10843000FC65A578EF61F9D935969FFD54969F9D0F +:108440005A989F1D6AFFFDFCECD9F733C1F6F388FB +:10845000A0FFCC3EA22227FB7FB678102292A67DF9 +:10846000CA0F6AAB076D72FD805BBC93B4FE9ED0F1 +:1084700002F9B177163FB8BDDD25CED1A5FC1C278A +:108480007AB833FDEA419F32EB290F44D1191EE13E +:108490008449F4C65E89417A1F9265E793C540F925 +:1084A00023B2B0273C1067F6822AECC03C618FCD26 +:1084B0006F67E8E27CE3FE054023B3D7C1E7C4CF92 +:1084C0002AFBE8BECAB60F1E916FA93E9A9036D815 +:1084D000F4FB2362BD7D49D545ED6BD3F7B37895A9 +:1084E00052AABB28BF6491B8E7F268C0F2C14683C4 +:1084F000956C3F6EBF98CCA3F78456FFD1E06A1FFE +:10850000D4CDFF6EA24FD8B156BBBE0312CFCBEC79 +:108510005052D538549F1C5373F96D7FDEAE39E449 +:108520005C29951CEFC2903FD87B57B5323467FE6B +:10853000A1473D778D6CB383FA7C8925F4774F8E04 +:108540007872F3C39E7685CD3B3A0BBF587C68BDED +:10855000B79AC9A715F77033F76F4BB543FCFEAD5B +:108560003B40FAE5A976E7FDCE65F76E4B9DF76ACD +:10857000D3D1D8D3ED142FAC5853D4A9CDF9F7A04B +:108580009E6D677838F3AFF324F17EA192BF5F5000 +:10859000B3EE5FE7CBC37E61462EB2FC5B03F55BB7 +:1085A000612EBECF921FFFC2FCB1C3C4871EE2D3AF +:1085B00069F6778B8AD29F307E2CDA6348C48F5558 +:1085C000828F2D7E1C6B447E745DBE1F638D616641 +:1085D000DF8C0D7FF4DA256C77A191BF9B998F2FEB +:1085E000C786055F3672FD341B3F3E3E2F3FF2F5D6 +:1085F000A4E8575C77D116C545EF1503E9DD6C3D5E +:108600006A63DC30EAC8BB0117E58D0E548456F767 +:10861000D8F4EB0346F87FD03E523DE9CB8066E5C7 +:108620004BBB985EF4192507EDEB3E25CEC1616387 +:10863000BEF71AB149D2CF234963D2FE2EC22ABD5A +:10864000221E33D2F6289CC5F2C9B647993F3C702A +:108650005D4D259D8F9FB4BB1CEB3E7EDD43417A73 +:108660000FFE58457F90BD033BFE0DB6BE99F1C489 +:108670003A51DF19947FEA1DE0FABBB8ED9160A78B +:10868000FFF2F166F6318B9FFEF536E393765A9F43 +:108690007F98E98B616404F2F7864D5794C58FCCBF +:1086A000D50EFEFA5F597641B65FF4FF01CB3ABDB5 +:1086B000D610500000000000000000000000000084 +:1086C0001F8B080000000000000BFB51CFC0F0031F +:1086D00009CFE647E53308A0F21FF1A2F2E3D0F894 +:1086E000AD687C4E6E547E3F9AF9DBD0D4938AF904 +:1086F000D81918C480588E1D55BC9201420B43698D +:1087000016205DCE86905760C16EDE7905085D0447 +:10871000A49701F105207E27CEC0F05A9281C1496D +:108720008281E19F3865EE45C78F45A96BDE28261B +:108730000D4F5645E573193230B81A01D3A931846B +:10874000DF8524BF1C28C66D0861BB6A3330A800D2 +:10875000F98DAAD8CD7503CAAB02E57718E3B7BF88 +:10876000DA1295FFD30295FFD01595BF1A4D3E3B07 +:108770000495FF320C956F1801A101B3E1B1A1E896 +:1087800003000000000000001F8B08000000000034 +:10879000000BED7D7B7C54D5B5F03ECF99C93C7282 +:1087A00012263081249C890102069C604044AA273D +:1087B000E1D1806847441B1571406AF1818E88358C +:1087C0007AB1397912026AB0A22008935811ADB675 +:1087D00051C1DA56EF1D1E4544BE1A7BAD558B764E +:1087E00050AB5EAFDA48AFC5DB8BF5DB6BED7D32AE +:1087F000E74C2680BDED67FFF8E2AFDDECB3DF6B41 +:10880000ADBD5E7BED3D2E771ED14712F225FC9D5E +:10881000434848248414A453B326922455349D4CD1 +:1088200022CDF4D35FC598874C22C4A7F51802CD9A +:10883000132D41A27E42245FCCFC5590100F217D68 +:10884000521E1410830C25C405FFD20991B598015E +:10885000FDE418B46E25214AB087C42A684A366BF5 +:10886000EF9D4A081DCEF7E510A86CE2B88129F407 +:108870009FB4BF9C229290E840AEE47F2725DADEC9 +:108880005546221E1DEAC50D28578B88F668987E2E +:108890002F62F55DE5A4DB4BEBAB722A29D0FAA47D +:1088A0009C841FA2492E94D3BCA74C7B50A4F555A1 +:1088B0003711E42A9C5BE421DA9FC6DBBB75569E28 +:1088C00053CEF26B0B49A2428076B4AC0AF2BD8F54 +:1088D00043DE0D6D6C79B386F56F4E5613CD61F89E +:1088E0009E0CF97C69B8AE0D0B753D344F8EED09C9 +:1088F000CDF7DBBE7FF1EF21A211F2C8884273C62B +:1089000099345F393A17E0B2564986345B7B2B6D58 +:108910006B8857C8A3067EEF2F17C9521C47EE0D70 +:10892000CDF3031C93AFB9AA108EBA141E08C7D694 +:10893000CAEFF5C371CC3F108E6B008EE1341CD7AB +:1089400000DCC269385A796B1D6B0A7B1CF05B0333 +:10895000F0AB00F83D159A3FDEF67DFCBE508CD69C +:108960005B03708CA4E1A8D64BFABB949EC272CA7A +:1089700084F5AEA1EBEDA063B5552C36613E9FC1E9 +:108980009CE9FAFC9D2F1B12CD13DA1AD6E79E162E +:108990002732D2578C009E3C9432936E428A69FAF9 +:1089A00025D0A19E4392E548DFE44B02E3A8380EB0 +:1089B000DD17D7C1BEF04F492625FADD6B244C20C8 +:1089C0006AC9A70BE7D3FE0B4CE7BE18D2BF2FF442 +:1089D0006A80E750D817B47C58D06C94E8F7759744 +:1089E000C4BE07FD154E4B08309F3BCFDC47609D52 +:1089F0007ED82F5EDC2F65F6FD12AEBB656B0AD606 +:108A000065CAA483F6D7F88DF8C390974D97D6140E +:108A100004FA8C6F4D017DAA6EAD99C2E93E6F00DC +:108A2000F1587FC89F70D175AD6D20243986908E26 +:108A3000063749D24DDBDEA061BEAD218429C59247 +:108A40007933AD7F74AA98E8A0F5E52031001FFDC9 +:108A500069194B5F01A0D2F93C407230FD579EA7C7 +:108A6000E4E18E52BCDDE99B974B2A06A75F7F4469 +:108A700074C0D75B9E83F0B7F21E3DDF9177858689 +:108A80003BEA135284F0C13C45C4126052148EB2CA +:108A90006C9008CC53A6F3A4709472E786AEB2CD66 +:108AA000E30E22613D49AA8E47E9F7168120BD59A0 +:108AB000E5430511D7315670637ACEB16F0940474F +:108AC000CD4192E8A074EBF3CF33938CA6E2A334AC +:108AD000A079F9A39435CF525AAE24B5FC8AAF1FC2 +:108AE0000ED6FACE39768E7B9E6D1F7DC6F194E34D +:108AF00017A3091FCC331105FA682E974558DFD705 +:108B000037DFCA3E80AB3C448D74EB03F1F2366133 +:108B100078B983F4E305E9DAC24B878FE185EE92F9 +:108B2000AC78F931305F3A4E879C70E773B8803C7F +:108B3000F3031C105FBD51C473158583F035C2A1CA +:108B4000B9A62E4AF1229308C243D1464FECA04564 +:108B5000A2775AA49CCEAFD53FBA14E4E41D1C8F73 +:108B6000CD8D22CA1B6B5E99EBCE84E33C81B53B75 +:108B700007E87B521A0E6B7C622D83434F2DC2A1F6 +:108B800042FC5AE160CD6B2DCC0BE934598BF88E49 +:108B9000885F2F9D7A8DBA6CFBCAC2C71DFD70EC31 +:108BA0006570ACFAE780A3B79FCE7B189D577CBD5C +:108BB000746ECDABBD1F5E268397FEF5C0CB92AF22 +:108BC000C41DA983792CD5541DE8EC5AC95417014A +:108BD000BFA74AD243549EC2DE2385741FFA9A5E11 +:108BE000D575CA4F040FAE87480B7263B67DB85473 +:108BF000A69274224DC9DA5E898A609250FAECFB23 +:108C0000B2FED0CB13F6DAE6F33DC11F04FD989C0B +:108C100041CE80F91CA1EB4F92C1D7FF61435F3970 +:108C2000E887471B7A27EC5506965F2B9138EA5167 +:108C3000EE1E15D7B3B2D3D35109EB1A3DA393CE91 +:108C4000671D976FC4470BA91E75EDF64FCB65DB0B +:108C50007C96FAC4C3AE2CF3EE8793D58EAA13AEDE +:108C6000FC81ED076BF781105B2F50781972B436D9 +:108C70000C76041594C0DF5CDBAB93C3F574BFE9DD +:108C8000795318F37993409679064F6E9E83C1D13C +:108C9000AA77C4D7D44668BB6625B25FA7F86E2909 +:108CA00010234D243DAE85770BEECDBEA6A1767C7C +:108CB0000F80BBB47616EA9FC42C073B88E6472F8B +:108CC000A5DF7FC5E965C03C4E401F3FFF7F4C1FBD +:108CD000BFF9FAE8E375A1E09F8F3E947E3B2386BF +:108CE0007A5D6B689E09F2E833B0C1289F903A2BF9 +:108CF000D17EA67342FB02FE4490DF2103F5931C54 +:108D00006AB4403B7799936FC9454E3B2354174B48 +:108D10005AFD821DA370BB03CC09E097B28F243D9E +:108D2000B01EA2623B20CB2F4F01FB7B536D69101D +:108D3000DBA1FD33D87A646847E1006AC097600719 +:108D400092CB72A3E38FB77EE738A1F9D1DCA8FFFD +:108D5000E4EB139FACBF6783FBE0ED64F29E050775 +:108D60004ADF43C12F31290D7F23B61CF932B5D319 +:108D7000221D20278ADA4C285D05FF47F1D746D807 +:108D8000FE24A17CCC7F20E84C5E1731FCBBC8AC34 +:108D90002476CECB4F84EF30DFEF3F13A36345DA69 +:108DA0004F7701E99426A4EB292A89E1FE69998F7E +:108DB000F5BA577F2F29D07929B7699560D785658E +:108DC0003DE702BFBDDF269CCFD68604794701BFB1 +:108DD000481CFD22235746D1DE2BA9EF1320EF2A92 +:108DE0004A0990B7CA2DBA232D8C4E5BDBA95C844F +:108DF00072B72E82DFA0B433DCE476D05D14EDD9F7 +:108E00009184D1D926B067C3B8E1707C57BD534E69 +:108E1000F6D357CBC9ED835B806FD0718F7EDF5067 +:108E2000E7D1F92D49CE564B29FD5C250AD8FFD153 +:108E3000EF93A50097B71B3E27EFD8FC17578B433E +:108E4000B17CC9DA6A75BA4DAE2F21CC9EA41A80C6 +:108E50007AC178FB788D0CFFBEBE3D5FD2A91D693B +:108E600097701F0D36BF2B434F4D904F4FE7DF6973 +:108E70009750AF7887DA81B09FDE690F27CC2CED51 +:108E80002DB8A4FB791AFB397ABBA1821EFE76832A +:108E90005B007CC13A750AD725EDD5AAE13BF1BC50 +:108EA000BF9D41BF5BA01FE0C7B74709E88F4AF2EB +:108EB0001202FD29F55103FAA37F49A06F65FF90C7 +:108EC0006E58E739C7AE40FDD2EACFEABF24639DB2 +:108ED0005B824C3FDEC2D7B925A8274CE1C4EB2CFE +:108EE000E1EB4CF3410EE722F1B8706E6FE8997038 +:108EF0003CBF94BB98D9956EC5443BF844F3F0E869 +:108F0000B43F1B3DF6CFA38CF91F061B6755C63C2B +:108F1000DACB981ED92E9BEE9319D75D44DB3BF438 +:108F20004193945312455590AEFF6829316A81CF21 +:108F3000E413A41BCA9F8E80FC10395F93DDE79376 +:108F40009513D3FD491A2D77F4C7F9755035816F04 +:108F5000107BB94DFEB8412E805F35D8F629D493E9 +:108F6000823926E88B52507E2FE576CE0FE5508968 +:108F70001083FDD76CF13B42F6CAE0FF298B3C0819 +:108F800078DB23AA0C9FC4301A83E8978D77682872 +:108F900057F7001F933513F98A353F656839FA2171 +:108FA000892F3B5FDC92E187B4E0B84521DC4F7745 +:108FB0006102FC8E8A587E634764F07E32F9487302 +:108FC00071E56B31F05715A8C8B72CFD2A733D6FBA +:108FD000DAD6037AB86D3D6F665B4FB37F345F4F6F +:108FE000767ED602EB5106D2430BACC73778BBCCAA +:108FF000F95BF2C655464CBB5C585DCCFDBFF00733 +:10900000EB28A2EBA06B5B3D6A56E84A3AAFA3B0EF +:109010001ED07FE77612BBDCA5EB392A160C5CCF9D +:10902000AAE27B8D26BAEE2374DD12C07710F9E533 +:10903000717FAFC2BE9F1549637E9E7EB8C6B13FA9 +:10904000D70C468F1F8A3145027950DE86F689ABF0 +:10905000A813E590B782AEE7346A5F319942D6151E +:10906000337FAE2FC2FCB9EB8A99FF96D6437FAE11 +:1090700095B7E6B1AE582BF4D9F65FEBCCA1AF03B0 +:109080007D788A888E7EE7E4ADC8F75C4554BE8162 +:10909000DF55EE657EE72A1206BFB2C79D44394A06 +:1090A000B705FAA1BD453DA49AF6B7EE0B89C1B547 +:1090B000BC0AD7D38F0F89F98532F1A3F07567C247 +:1090C000695B31F72F67D0D9B68D2AAEB7A538F2D4 +:1090D00020F8CF2B24D5D1AF0D4F155216BADBB6E1 +:1090E00091D35D303BFDB8DC3755C84306D2DDAACD +:1090F000E28B75D60FF3170FE3A4933723B211E079 +:10910000328EE3FDBED01422EA697CBA4463752333 +:109110009D674D207636CC27AC93A61C5A3E6C0139 +:10912000D3235AF9FE9C292DF0BC4DD3F5F34B7394 +:109130001783DC9284ACF6C7F606BA26BACF373767 +:10914000B8313DFAE6185CCF60FBA0BD8138F8422B +:109150007B4266FC576FCA9F037EAA60D94489711F +:10916000A1E1D720FE75F4635D2409969E7F91549A +:1091700060E34341064FC9481A1A8307916DF050C6 +:10918000876F1741BEDD5747C810DA8514D144E810 +:109190007F5C1D6982ED4CE1708564C357261CD647 +:1091A000CF1711BFCB2F19DD2DD9E87527D00FC8E8 +:1091B000E9726E57C8915036FDD6A2AB2E0AA78A27 +:1091C0005190EF14A05E610B49C0FE59CBBF974888 +:1091D000D11B001F854B62228CBF8AFBDF04E26E2D +:1091E000190AFECD32AD0BE8ADAB2D87D39BD6056A +:1091F000F3B98DCF230BBDDD968DDED448D4003D71 +:1092000073BA1AFB3EAC7B8860E4112A97C22DEC3E +:10921000BCCD1A974EFBD7405723806EF4345F0ABB +:1092200055E8A8673CC8F1911F8C374295F094A788 +:10923000772D01FCC57C06F0D97041F7AE19608F1F +:1092400010D207E72EE1E204E649B5BBEF215A3E12 +:109250007CA929CCA4F99186BB0F58CEF0054913FF +:10926000CE315A1BD839C330D26BAA59F409458D77 +:109270008640BF1A11BC6A2ED86DC2D06776A9B4D9 +:109280009FD6461281B3C450AC07F9FD88292E0D34 +:10929000FA0D8789E886797D87441A75D09B5979BC +:1092A000C87047617F2844DF05E310394A2EB4E1D6 +:1092B000CF1B8C2D2394DF9DAEC61E04387A2B98CD +:1092C000BE3DE4BC1D08A77B9524017AF34DEB312C +:1092D000603EDBBB2E268B6C74BF83F31725428C5C +:1092E000848D2EEF93183CEF892EF77CD707F5720B +:1092F00098BD41E623FD8E235103F6AF8FDA634913 +:10930000469F4FC1F823176835026D372E42907E75 +:10931000E9BE1CC6E6112B047DFEDE2EB50EF42739 +:109320008AB757C964DA5E74E2CD1B347E0878BB15 +:109330005A52983EBFBC27F9001DA780C249A770AA +:10934000F21E7A3109F8D316FB0C650A9DF78A9E46 +:10935000E49BB43C58E7250694572449092D9742CD +:109360001201B8A9FADD02D011F83E902E6A09EA7E +:109370005DFEF9519836C0ED00C24DA7F441C70D0E +:10938000D2CF00BF7639FEFBDB69BFEDFBA5884974 +:109390006CFB87D0FD63936BD47EAF90B3E83156FE +:1093A000FD13C9D9B4DDCBE496A527D07D7648421C +:1093B00079C9F6D9C9CA6D621A7BCA285CCF23D68F +:1093C0005FAF0CF0984BE181FA4B95F2AE534F939F +:1093D000D3798AB08F6FDDB317E06D9EE9D280FE3E +:1093E00033CBE742DE5A2FC83B99EDAFDD3B7F3BE5 +:1093F0001AE4DA4B11970EE7700785DEF7F01CB917 +:109400005AD21F0AB3F9B927437BC28C679839E453 +:1094100043F49F745FBF6448C60CDABEB74A484045 +:10942000B98B1C6E390BFAA3FB0EF669EFB43D87BE +:109430007269FE3C81DC482A0939FF19C9744D184C +:109440000887B93B5C87018E73619D36BC9CFFAC7D +:109450006DDDF47F236582F4B5FBCD61E76D82712C +:10946000486E14E43899B1823C4DD3F3A6307BECBE +:10947000A519FFFE1EC17950AAA6F37A69CABF07D3 +:10948000C13EAD3604B467CE9F26245C59D647BF93 +:109490002B3AA593B9C6A7B80EFAD7E7A2F47AF487 +:1094A000305BD74191F435D2757DEB99775ACEA2D6 +:1094B000E36935EEBEDC5096F564AE639A33DF8F18 +:1094C000F719A41CCEAF65921381794F5062A36542 +:1094D000909B8F7DD39C0EF64692F475209F8D2134 +:1094E0007D5BED66172CC17326D927E2F9A9EC63E1 +:1094F00072E408C42B007E83625638932215947B55 +:109500001B1D0DE26FE6721F8BE83EACFE5C66F140 +:109510001011BE0F490A8D925C801AA5833CA20BE4 +:10952000CC4889A0FC21641AC655043D7FEF7E1704 +:1095300060BF82B18E7CE9FD0AFDCA29A4D7BF7B3A +:10954000BF2798AF271D5F12B49F97AFA6FA0C18DC +:109550000DCD0D1AA62E885C017956C1CE0D57355A +:109560008458F08ABCD31083A0E7AA3AF001AF2F49 +:1095700049C2B4DE1FA99C23B007B95FCBB2FFBCC0 +:10958000E5E4B048F1EE8DA80E7F8ABB483DA97393 +:1095900086D682D1C38EA75F01A586DDE97683D505 +:1095A000FB47A7CD548E876DFE63D9579AA6EBE390 +:1095B000AC4F9A11633285441D768E2C32BF59B35D +:1095C0006FB11BF9F6B12FBF942673BB9B401C45AE +:1095D000744A36B86C91C30EFD48D1DA6E1402E0BD +:1095E0005F5D62D8F77B02F816C8EBD07546EA24B7 +:1095F000F020C9D1BA45CCFEC0B89675DE85E470BE +:1096000005C44D2C443F6C5BC1D030E35FCC7F4739 +:10961000DC3EE463169DEE2AB83894023DB3F0E2D6 +:1096200010F0BD5685EA3534BFBFE069D44FDA8EFD +:10963000E51217A5A7B65029EAD36DC74E1916CF64 +:10964000B23E2F61FC228710EEAF532116A77FBEDA +:109650006D21D10DF33952C1F8CE3AEFBF1A10EF98 +:10966000A2EA721CFA577D4C9FAAADA27A11A5639B +:1096700035E68BB9B481FD58E3D03F01E25CE05898 +:10968000BC7FDF098EF2ACF318988F19A560FF6BD1 +:1096900004F96A66B9E20E98DE09A09FF57FD760EB +:1096A000DCB283E3D1EF0CF575F047538E00FB2A53 +:1096B0004DFF0907BE8926A6FBB5F94F6492D82055 +:1096C000A05FC01D877D9B09D73695F923896CD48F +:1096D00001FC5A84FC8910373318BDCBA176F4C342 +:1096E00050D82581BE5CA1591857D442EDB021C88D +:1096F0002AD6F60A1330FD14ED664DFED04E7F7F5C +:10970000949DE734CDBED2E3DA51A02793318397FD +:109710002B6A24164579147F0DF407994CC0F9CBB8 +:1097200045FB5E0B835F4961FA85CDCFF4915D7F88 +:1097300069110DA250382A39AC9FCCFED78B353237 +:10974000943F28475585F6D3317632977F19FBE54C +:1097500024F52BAD3EC298243102C25046CFF0977B +:109760005311811822123A4BD2E4290CBF108FA555 +:1097700080DE0534582EBF0DF336E87F30EFC0345D +:109780009AB7C155322E354EE17A8012027A62F5CF +:109790002D3A95001FA01F667C0F2B19F86878C61C +:1097A000E19796088B13CA5CCF6CB1668C32291B8B +:1097B0001C4ECEBF05BA02D387E3ED4290C54BC223 +:1097C0003A37717CDFC7E5D27A904B34FF032E879E +:1097D000EE6AD031DDD8508EE9030D112C6F6998F7 +:1097E00082E91D0D06A6EB1A6A315DD310C57A6AAF +:1097F000618B1BF0B6A9B067A3007AACB9ABE620C9 +:10980000ED7293BFE775B0DB08798EE5C1581E4E47 +:10981000D7A7FCB4C684FA793D9788740A8F0FD90C +:10982000DEB497CE77D3A89ED7059A6F6DFDD1EEA3 +:1098300016A83F9ED5BF52395063523ADEE4E17616 +:1098400065D1FC13C081F1CB5B603C9A6E2AE0FECF +:10985000B5936CD700ED281C3785BFDA781EB9D3D5 +:1098600060EB7DBBE69510F893D8FC372ABDB85E57 +:1098700064595309E9567EDD84EB1FCFFBA772EADA +:10988000229B9C5AAF30FB6A53E5579BF77D7CDEE9 +:10989000AAD667508E47FC4A6C39ECABC0D25EC387 +:1098A000A5833F6BB729E8D05F30AB7F2A938E7ECC +:1098B00007C6F4A4747DB52A424AE9A73B33BEE744 +:1098C000D71A68CF9A0A8B735A5351E366FBD8C0F4 +:1098D000F3CA7645E37A568CF9255F60FA7BDB2084 +:1098E000F5A19E5995AE37E83CB513E8B927B94EB6 +:1098F000B0DB418F5B2E6B8E755D9191F7F8D87E52 +:109900003D597CECE6F8385BE6EBE7FD9C9ED1EF39 +:1099100088C74432856EEDA2EB6C7286FE2FB420B0 +:10992000C7911F3A3FDF910FCE1DEEC86BD39CFA53 +:10993000D1F025E31CF99215131D79459BEAC80760 +:10994000AA6A1CFDE5CF98E328F755CC7394FFADC8 +:10995000F09E9F018FD919F993EDC715BF91446807 +:10996000D5CB5F91D0CEAB27BDCA30D0A756080467 +:10997000F429A8A7517D69019B221157EC9A09721D +:10998000F8728A6A571E4DE55E05FC1E0B56B81C20 +:109990007AB4D5FFAED490A6C5B4FFB7E2AC7F9A37 +:1099A000A2FEFE9649ED609ABFE2F677EE38839606 +:1099B000BFF98A1481E5BF497ACF83BC694AFC3C70 +:1099C000B4B718E8EA22EE37380C7E29CA2FDFE058 +:1099D000F1AF44EE2D86F8E93794C4E58C6FFCB501 +:1099E000E615CA6ADFF0F41643BE91F8A6B70C87F5 +:1099F000EF6BDBBE695BC7E2B860809FC688EA6D2B +:109A000021F06FEA91D33B7819C6556BCCEFFFA9D3 +:109A1000A2727FA7F129F0815059F4B8E7ED871AB7 +:109A200098DFCCCABFA8C4FE02ED16C7F354D02FEE +:109A300017B7EF52609F16AA9C7EE504AEEF4DCBA0 +:109A4000DF47CC6AB063DEF8CD906EFBF959A1EA2E +:109A5000F4FB668EB328BE8BE1ED3A2182EE4D77A2 +:109A6000A278A16D9E2135C0EE09DCC8C6310B0578 +:109A7000475C6180F75FA8323FE6DFB0CE616AD60F +:109A80007512CB3E0CC03ADFAABF12E1FB19A50745 +:109A9000F005BD70F87D05F46F32BFC0C10F16B779 +:109AA000480E7ABA6CA9D7915F18BF30375BFC4E6D +:109AB0003F7D9BAEB41D67D337ABA90606F4973F35 +:109AC0009FD98F2423CE3B486202F8C98611B31177 +:109AD000E667C5755BFAEC8819FAEBF45FA4D97FE9 +:109AE0007121F7FBEBF26414515C6F92CD94A59F4A +:109AF00053FA1C5E410C88F7180EDF6D7A4D6889A9 +:109B0000ECF073E42F901DFE1B5F95B35CB1FBA9D5 +:109B1000C2E9F558EB2DB0F41523AE633CA8BF277E +:109B2000047A4067A0AC7936DD376BACF3B1F9F756 +:109B300070BD067815B59FCF9BF150B6735AD49877 +:109B4000E97AD554AF01FB5B21BD187F9F1F62FEF0 +:109B5000506F09DD99D09F4CB1E203F9C5FCB231D9 +:109B600055C779898FE91EA09FB5B535791007A82B +:109B70009A31D24EC7F3D78A894418FA63E751BEA7 +:109B8000B9722209F9480CFDE1BBDF7CDE9DB2E130 +:109B9000D56A4FE673BE26C743D9E8B23FCE6441CB +:109BA000757231D3D7D09EA05F9270FEE6A2761672 +:109BB000E86F72857C18FC3D1F08B1656A16BFBC52 +:109BC00035CE09E5DD49D60B4F5191DE5A0F0948D4 +:109BD0006FB9257D31888B22AF4AC85FCD9AC86B9B +:109BE00031F0238E5323CD3ADC03E9D361FFBB0E62 +:109BF000793509FDE1F133C01FDE9AB1DF8E66C40D +:109C0000B38C1663EDB01E61685D0CC6BBE56D01DB +:109C1000FD94B9D3185E02A7B278B1BAB38AC81F4F +:109C2000416FF7C5B64179281835DFA3E54FA82C59 +:109C3000AEBE3FAEC117C1B8068554A25F5D714785 +:109C400030FD39E70F8FA9CCAFFE84CAEC1754FC66 +:109C50006D7E809A406C23F083B0416AC0A4977CEB +:109C6000D6790EB3D7CD6215EDF599920FE1732435 +:109C7000A877BB6C7ACAA3BC5F2BDF4ED70FE7BEB9 +:109C80009FA74E417B4CD199BDA4E866D20E071226 +:109C9000EC3B55B6E933AB475FCAECA160CF69EF47 +:109CA000DAF8C1CF39FFED28DE1682FEAAA4E84F0C +:109CB00060BE9A611810F7E50EB1FB4CFDF5FCDBB8 +:109CC000F0FE8A429709FEABC0597393CD709EC1D6 +:109CD000CFF7A8F86D5182789E8CED2C7AA274F69D +:109CE00073D5EEF7085AF4463E02BEA37278758C1F +:109CF000BDCA9DCDCE1CABC676DBDBABA1C871EF78 +:109D00009758E7458BA7F08E897E36F8C7AFE67681 +:109D1000DAF29D0FEC03FFF7F233A9851C81389529 +:109D2000ADFB9E037AA06A23DA71A473DF9B34BF74 +:109D3000A4CECBFCE9248A7CFB6322D602FFF81870 +:109D400046A4ED3FF64D7E10CE2F4DBACE0BE97EE8 +:109D50007C5F65E7E2B28F9D47CB697EC7FC143C10 +:109D60007E8EF8187F3489BB11F9723BF3F79AF4B1 +:109D70003FC87FA7D3E9FFFDEE0667FE2A326F28B2 +:109D8000F881AFBA472109DAEFD5197CB197E3EB37 +:109D9000BB24DE067C6B15E77BCB7E3A5E053BEE93 +:109DA000EAD3B530C4735AF0FC23A7E70F297DE945 +:109DB000AEF4F76B8209D5607842BF4D731E9317DE +:109DC0001FEF989E84FDFA0EE52788F78C75AE523A +:109DD0007ACF07FFB779871261FA13930FB00700A4 +:109DE00074D76CAF36C01F4EA1A50F71B6C7F95F0F +:109DF000D9EE5CEF89E091B97E4B6F1E6C3DEA763F +:109E000001CFC132E94C75098E78A7FE7B484D32EF +:109E100069AE027FDAF7F19E52BDE9D25C343DEAC9 +:109E20002949C0B9DF68308A50BEC7CF607647FC89 +:109E300034484FB6FDB8FF65FB09D07ED2C0F6AB03 +:109E4000839D51D8A7561CA1DB1D47F92EC8CCCE47 +:109E50005A1D3A4179112D978E535E76FCF6E01724 +:109E600085F39F4530A55390FE516EBDCDF5D76665 +:109E700025FA2D8C97FF8D4420DEAB394F433DD41E +:109E80006C1574D07B17ADBD2017E875D12B5250DF +:109E90000CF3AD0CF5FDB5787E78A64BE176574A0C +:109EA00086FDB9684A7816F0EB662512CA8373F806 +:109EB000EF333F6DF594CA189EE3F8EA14E0AFCF94 +:109EC0003F763AC6615EE39B2503CA67F07E3E7E1D +:109ED000F489C984CEAFF9713F49A2BF2DA182DCBC +:109EE000BD668784F472ED4FFC189F76CD93CB1E30 +:109EF0009C4BFB117EEAC7F9484F7E771BF3AF36C8 +:109F0000633FD73C7DE14B265F17DC196C6EB4CE06 +:109F1000B123219063CB5CE40A1697C7E0D0AFEF82 +:109F2000B557EE0BC1BCB6E761DC413FDDCAB43EBC +:109F30006DBF88A6F3B2D0EDD52EB67F3FF2AB75DC +:109F4000304F61FBAE85B8BE9E6F2BB03EA1254F52 +:109F5000FD031D6FA14BB1EAE13ACC4784C4285AF6 +:109F6000FED123025B57CFF82E4F18C6EF5217E3EE +:109F7000394723D6B7E6BB787B65DB705A6FF1DAD9 +:109F8000BC5288E398FE93C703A0A75CFB932FDA2B +:109F9000A656613C76DF5CBA9F6FD82EA17E7165B4 +:109FA000BB94718EC0FC69D72347A0F59F7A7FD6FA +:109FB000EF68BB0F295FF65096F561EF1FD45F4045 +:109FC0003EE68B035FBEE119C5E13FBB61FB3B1879 +:109FD0002FAD89A4AFE82CCA820F3AFD6B99F53FEB +:109FE00023C754F0DFDFD0B31AFD9C37ECF8F80D2F +:109FF000D82F3764F8D73E847F140E8C57EF74F94E +:10A0000083689772BFDB67E4E0643C0FD83E24AB03 +:10A01000DD6EC5A95BFCE39367FEB4C5A4F4F4D17F +:10A0200093FFB9C5A4F0DCFFC59FB6FC0BC0FD399A +:10A030008F06F47DC3A37FD8721BC891675C22D0C2 +:10A04000C927CF3DBCED7E9AFFE4F53113614B3D4E +:10A05000CAF9D127E1A343411F59F1DCCC61408FFC +:10A060002B764E1F468EA3F77F42E92A61A32B4B26 +:10A070006FD79F115830CAB33CCDC00739D8A782DB +:10A08000DCFFB340FA3AA85D7B7DFCA80A7AD83E93 +:10A0900083F4017CF6EC7867DF6D34FF31C58F2BDC +:10A0A0000B7EE8CA468878CE941C01E74DD7EFB8FE +:10A0B000F05BDFA882548940F737903E944703F065 +:10A0C000FA0AC56B551AAF83E291FB476F88BFFF51 +:10A0D00006C44364E2F163F8C79903F1F8C2003C97 +:10A0E0005EB7F57E28DC3124ABFE6AE171D9CE8BF8 +:10A0F0008E6B5F7D92B17F0783F3526E97DCEB32FC +:10A100005E77C1FE7BF247DBEE0F029E5D91B98068 +:10A11000F7C73F2B21A027297D0B010E7DCFB9B4B6 +:10A120006EDAE69AE77E8BF2EA939D2FAB3AF275F0 +:10A130001210283FFD84F4FFFD1AF4CDEB0596596B +:10A14000A6F7CD7A83F6BB8C766146107FB3DEA886 +:10A1500002FCB1F3BFEB1317D4EA788FA000D77DD0 +:10A160007D82ED8BEB13BBE6C3794026DCF3DCA2EA +:10A17000250FFBF12A4C017C1E9E05F437183EADDD +:10A18000F56BB0FE3368F90F9DFB7620DDF4A92056 +:10A19000172CFC7ED27554BD85D64FFE42D5C4A97E +:10A1A00034AFF4A9C077CC27240DEE2F65E21DEE65 +:10A1B0002D2D423DA5296BFC51263D78DD4E7FBA01 +:10A1C00075EFC982CB89F6F589D7F3D5E0F53F5C09 +:10A1D000FE67C2AD71A60BF9F2AFC22E3CB77F5934 +:10A1E000D1EFBB09E8E30585C0FDD2F34BDF97F55E +:10A1F0002C76E04BA0F7D8ECA46F4D115A87D0769F +:10A20000DF32A85CD1D3746A9547A749787E65CDC3 +:10A21000C7FA9E3FBB6A2DC8DF23F04E02E5CF7B15 +:10A220000BA39B31CE5194E3AE503A3EB1D420A85B +:10A230000F2F2F76A17E08716404EF63B3F3EA76E3 +:10A24000EB7CDA174339FD6B3E3FB2FDD1471FA5CA +:10A25000FC670E0C4C496D0F89B4E6039E2B98FCED +:10A26000172A9E9041BE9C5BFB840C717F7B05A6E8 +:10A27000C7BED6E046BD0E4E4A216EBD2ED685E540 +:10A28000BFE4FEA3394B68DE2627CF2D7F4206BDF3 +:10A29000E0DC8AAE22E0C707200E338B1C6D7333DF +:10A2A0007BAB71ECB7314EEFC0AD2C5EE240F17D7F +:10A2B0004580BFBDA31EDEBC9C7EDF5F2E440065D3 +:10A2C000FBEB9B7CC08FF7EB4E3FCCAEB1EF0B307E +:10A2D000EF9250970C7CBB9BDBAD3FE4FEBA6DFC6C +:10A2E000BEFA767E5FFDD1061DD3C71ACAB1FCC780 +:10A2F0000D11CCF7344CC1FC930D06E67734D462D3 +:10A30000FEE98628E69F69A8C3F4D986A5F83DD062 +:10A31000B1BD05E047C6093DE0FFFAD7863896276C +:10A320001BEAB17C969BD9AB25ED549F3F8DEE8BFC +:10A330007A160FD64DED51FBB99A55EF360E8F5365 +:10A34000F363CBDD343D523B7F12F0E1D651DF1E8B +:10A350000FF8DAAF9F22B2FB61EC3D008FDAB960F3 +:10A3600039F81D02EE88A9A7FBFB5541EC36B78DE5 +:10A37000DE4ADB55923C1DF099D81B047C9F47F1C7 +:10A380004DEBCF8975B540E8695D6D5807FDE297E3 +:10A39000424F4B3ED811E379F992754A4DC589F188 +:10A3A000781EE75BCF57C78B60BF3D2F303FDF85FF +:10A3B000B51229B7F1814B62CEFC99BC5DFEECB2BF +:10A3C000E3C6C1C2BD4DA7FF9AED2717C435DBF622 +:10A3D000914777FAD5256D8FF1EEE903FBB352294A +:10A3E00050CBF4664D7E0FF81B8581F0A598E63BB7 +:10A3F000682959FAB40EE7CD3E02718C975EC7FC0E +:10A400002A97939402FA3AD8590AFD7E852960DC8E +:10A41000C962125141FF5E42A2985E45E298BA8A33 +:10A42000920A3B2F99A1C1BD25C1384B827896C1B4 +:10A43000E69779BF29334ED9C5EF9384A6BA6376E0 +:10A44000FBEA679C9E9EE729A5A365403F838D6339 +:10A45000F10F8B6FD40C89EE02FAB3F062A583B5CD +:10A46000CFC48F351F02C406E74CB3573C5F4C5135 +:10A47000DBDDA9233F9CBEB8DD55428BB6AED527A8 +:10A48000025B190B9E399ADF7228DCCDFCA34C0FBE +:10A49000DE5ACFECFEADF3BDE8B73FB2B2F4E53122 +:10A4A000E4C4EBC8E483F78D9CB00EF03672BF8431 +:10A4B0007C64DDC8BFEE82B8B49214E32B25BEF8ED +:10A4C00018D0F7ABDFFA8F42F00BD70C89BD6DDFE8 +:10A4D0003F5B6E8F8F04BE93701BEFC0F723B52BCD +:10A4E0005C1E92A6D7FAB5FABA727D707874B71F5F +:10A4F000FF3C3F73DEFDF437C87E48D307ABB7DBC4 +:10A500003B12EF8DA624A2015FA8F116A37E17CB04 +:10A510002506F81D2EAF4F2A80FFA7DCB12F60FE65 +:10A52000979184C2EC436D28E8011B834C1E6E1981 +:10A53000FA5E21EADB722ACCFC2627792F8310876A +:10A540001C5F45482DD0E5349212E09C44F47E54C3 +:10A5500008F221D7E3F4AFF5F753EF7C7FC025680D +:10A56000387F70A83E44D7B3488C1A6CBE869C17BF +:10A57000847B6FC244B8AF383328A03D78457DB89E +:10A580000BFC5F9FB963C33D93583FF8BD48C3FDC3 +:10A59000B8C8376E06E8AF27BB1E62D089DBDE275E +:10A5A000B2D65713888D82FEC39A5003CFB5B88AAE +:10A5B000987F71A654919B3A0E7E133C3EFE39EE75 +:10A5C0004F7C8CE219F2BFA0F409F92D541E41BA58 +:10A5D0009DCA23F8DE4DE511A4BFA4F208D27FA3E3 +:10A5E000F208CA7F4AE511A43FA3F2486671E393DB +:10A5F000613E7AD3D2E1308F661EB762C5AF5BE3AE +:10A600009FC3E16EA58647C7FDB54A6170327FA33F +:10A6100026309E548E8EC0FB6334C57B1F7D7D1813 +:10A62000E3F38DFF4AE1FD8A4AE28E80FF69FC8EEA +:10A630009401A11D43B83F6ADB37F4DF49487FB975 +:10A64000849C4DDB95D4BF06F12F77529A83D45F5B +:10A650009FC463B3D33E8F5C761D1D7AEA0789479A +:10A66000AE0B323F24B4D7CD14C61F8FA1CC11F24C +:10A670007E3195847824F2E7008178D9DC733E320C +:10A68000AFA6F9BB6ECDC5F2F244CA788CE683EF73 +:10A69000B2FA637F9842BF68C1523F01BDA972DF21 +:10A6A00007C907E9B8B99FF03C8935BA717D91DDDA +:10A6B000E0FFAF5CA0E17DD70DE72DF50259AD8D30 +:10A6C000BC8DEBE98C07B0BFFBD5DEBA2B69FE89E8 +:10A6D000C5BE48372DDFF16CCBE135B4FEC667EF60 +:10A6E0005917A6E9FD21F9775743DEC3E2CBFC9366 +:10A6F000F6BA4FA1F5736F142B25EC6F37E637C50B +:10A700008378AFF3B44AF68EC28E69ECBE83859728 +:10A71000EB3D12E2A3DEA372BD9F927910CF2930E8 +:10A72000EE43D93FCB80385342ED09887395B56825 +:10A73000F25CF0F7F2B8F90F8458BD07F019BF00CA +:10A74000E3C63DFCDEB3E5075EE9617EC9D3BA1816 +:10A750009E9F784D4C40C0FED37B177B41BF7A7AD9 +:10A76000EF1111D2D32222EA254FBF76B707EEF0C0 +:10A770006CDEBB7C18F327C7BC54F320FFE2617189 +:10A78000EA2DC0F426D9DBBF2D025F9C00ED7DAC25 +:10A790003DC4136F82F6E174FB660F7BEF672DB447 +:10A7A0002FB0B75F8EEDC7D8DA83FE51F44BE7F8D0 +:10A7B0006BF8F8F70C68BF18E73F9ACF3F73DFFDDF +:10A7C00080B7EB11626BC6039D2F93D13F5AFA9865 +:10A7D000EE9D678BF77F92EF8B5C385F423F94E191 +:10A7E0008579EDD85F7ADCF7245089B6C55B62E4E1 +:10A7F00092435EE767E48767D42FCD281F97513EC9 +:10A80000D191DFF37FEE15A3741D4F07999EFC7461 +:10A81000B009F5C1D62211E3BB770AECFEBBF98281 +:10A8200084EB4CAF2782F0DA7DFE54ACFFC4B3ACAE +:10A830007DE963B117215EB567AE48806E32E550A1 +:10A84000474E298B3B0DE6BF782A6D977F9E4C8043 +:10A850009E9F4AFEBAC64BF379A3844AE08FA35366 +:10A86000F1DD7E9ABADE4D41581099D6A7357B6945 +:10A87000BF9309A3D3FCD9C13D1E9A3F6250BB06CA +:10A88000FDFB7D4DB3ABD274FEF0E623BBAB69FE9E +:10A89000294ED793A56812CFAB24D207F6E7B60DA1 +:10A8A000CB9BC6D2FC0E28A7F9D3F63AE321FEE2F1 +:10A8B000C967E7489BA73AE4AE756E3318FEB63514 +:10A8C0001878AFCFCA3F0C720BE034FA2C84D3C394 +:10A8D0001B4AF17CE8E10DF372451F8C935D7E6DA0 +:10A8E000E37E89A7388A5190D0F93DB541E4F9FF5C +:10A8F000966796F17BE753D3E5AB363BCB77F4977E +:10A900007F3103ECA71D1B64CC1FF17C31A3919612 +:10A91000CB1BE69B63ABB03DC6B5CB45D124E4ADC4 +:10A920003877CA0FFE02FC40A6E225104C9F0BB9F7 +:10A9300083860978D2CDB80BD675AE4EE243A85EB9 +:10A9400050792C217BE9F7C97D4633E84174BFDD9E +:10A950000FFBBF8C9F639E5B926A86FD4C260A2C80 +:10A960002E42EEAD01BCDE32A612F9CC017FCF1E25 +:10A9700038CF7D4211904F4E5C991ABE4C877D397D +:10A9800063CE5C9A1F91C3F8E3B9A5F12B409E1FDB +:10A990007D5BD081FF34BE79CB1890977BF6CF23B7 +:10A9A000902A7B65DCBF4A509362C887F2A5EFDA34 +:10A9B000ECA3CA88C2F943E99A0AA0F7E00FA7F20C +:10A9C00033BF96822AB81F957814F4C611392E1613 +:10A9D000D718514CB8BF4FE1312207E24D34D310A4 +:10A9E000F4345FAC9608C66792174526F76A75AFD0 +:10A9F000FDDEFD93BD32DE8FAE7A39B8A2978ED7D9 +:10AA0000A24D3D1DE87EDB46B505D62B8F89E015AE +:10AA1000A87139D63D53764FD26A4FC71D9793E53B +:10AA20009C374CF4BB66C078C7B49A2761DFF17BD2 +:10AA3000A914834DD7827CE5E7C5B9C772915FFF42 +:10AA4000A44CE0F1024E3E332BE875D0B9D8E9B4FE +:10AA500083C2763E13CEC2670E9DEA88BFA2FAFD7E +:10AA6000CBA756E13D6E9DC135EE067932B94C213A +:10AA7000A03F11E9BA3D707EF719BF5735F990F73D +:10AA8000B01880770908F2892E1E97D8632EDE034E +:10AA9000F7869EACF3128803D8B77FB1940479C6C9 +:10AAA000FD974A4BBC06F869657BAA09F811318D00 +:10AAB00040F55090CF04F5ACCAD4A2B9A8A7ED6573 +:10AAC0007E6637FD0FE63761B3CDFF44FF379BD875 +:10AAD000FCD061E0334EFF54A6FFE9B21CA73FF261 +:10AAE000CEDBA408BEFBF52A8BF779FACCC8267C0E +:10AAF000E78FDA5B12E82FB1FFE95846F3DBC8C8ED +:10AB00003C783782B863BF03FACD2BD1C2808F7EE9 +:10AB10007F658EC8EFBBB8F0DECAC3BD04F96A75A5 +:10AB200051BC03F8D5E46744D4216F834B96B4DE5F +:10AB3000E4DED401E0A3A7D78A20ABC9E907CDB1F1 +:10AB4000600FEE9E7ACD08D0AF5A7D2A9E9F370BBC +:10AB500071A2211F67F4D9BA5FC477099F98E146B3 +:10AB60003EFF34A525889F6A8DE5743785A1FF7C5B +:10AB7000762E1EA4E290CEF3EE584E17D84B4F71AE +:10AB8000FF0D39668EC5F71E1F2423C0CEE9E9628A +:10AB9000DF8D43ECFD008FCEEE1702876071485ABF +:10ABA00025E8474D39A21587D404F41C38A512DBDB +:10ABB0003FC5DFAB3C51FB0E0E1FDABE03F661054D +:10ABC00004FE81FE4E71D781EF1DA61A010F8B4442 +:10ABD0001E379161072C247D68A750BD7E3DEE6332 +:10ABE00042ED0024506DD632B0DFDC028B033E49CB +:10ABF000BD7E24E8ED3A6E4713FCB8967E3F72A501 +:10AC000026021ED27A7EB40BD67BF2FA3DE17ABCE4 +:10AC100046D83DF13EBC5F32D264F1122F829E3F96 +:10AC20008AED1328A77AFBE3B09E912BD93DB46639 +:10AC3000355A07E72FFB7396CC94CF04BD3C5509DA +:10AC4000F99D394B5ADD341F16B5E110737F20E7AB +:10AC50003B33211F6816506EECA179731A1D177CC7 +:10AC600016402FDD84EBF1FADDB5143EE54B82C8CA +:10AC7000A7C3626AF518E077D788A8170412C95BE2 +:10AC80004996FB475D9C5E02CD9FDE08783E90C3EF +:10AC9000E4DD014E07567EBC3BF63CC007DC23706A +:10ACA000AF71643F1CD93DA80310C04DCB5FCCB140 +:10ACB000E2CDCCE1EC1E0F4DC7835DC8ECBBBF817C +:10ACC0000E5E45BC703A981BC953AFE174207D8578 +:10ACD00077042C7F46A6DD6AA5CAE7A76270D66016 +:10ACE000FD28FC3D93D6521657B2AA787425F8DF9A +:10ACF000AC7B2B2552EC43C0AF52C4E345821CCF42 +:10AD0000FCFD55EB1D18ABBFCFF93EB1D240F305AA +:10AD1000718CDFE7F0457F8F9EAE3FDEBDF8CF3907 +:10AD20008EF88E1801FBFABF73AC78DD38DE47B6BB +:10AD3000E296FE56782BD40C063853B8CB5EDAEF89 +:10AD4000A222F65E9225EF4E16DED34BD8B93A69B1 +:10AD500092C9435564C07BA32EF70549D8C699ED27 +:10AD60006FA1DF7E4E55BDE9A5F1D322A8C7B2B8C9 +:10AD7000A4D1626C98D7A687517DE20AA07F2BFEF2 +:10AD80006811F7CBD17DA8C0FA6B86E8552CBEFDC3 +:10AD9000EE9907A91D55031B1FF42E73DD4CD0B38C +:10ADA0006ABC2C3FCFFB781BC4ABD7C05912EA61F9 +:10ADB0008FB2F25358F9C5504EF3233D4699B72050 +:10ADC0002B5F49D8DF35AE09C44EF54E4AF39734B0 +:10ADD0003FF1B1F8A3954C5E0CCE57DCDC1F40B8B8 +:10ADE000BD1F9B04E35A7C25CD3FB2DBFD677BD9B9 +:10ADF0007EB5D273BCBAD3EEBF83DAFD405B72641A +:10AE0000F83C3F4B015E27E2D3363B2907E5780645 +:10AE1000FDEC59CDEC94EE16CBCED0F62DA5F987EE +:10AE200038BF0EFCB5F970BB90A633BA9F315EA156 +:10AE30000E8C0884AB3E07AEFA96D4CA6897FCF035 +:10AE40009EFC3C18E77739C6855E5BBCC8FD39C6F9 +:10AE500045F6BC0D0FB10C3C2C38193C8CF4794CE8 +:10AE60003B5C2D381EE4FCFD579C7FF7723E5F2251 +:10AE700019DF817E9B551DFD8BE60166770D86CF20 +:10AE8000C1FC9316DE2CBE30C7CFF0954E19FF3DA6 +:10AE9000C8E38A4AA790A95A6EBA5F93E3F7A087DE +:10AEA000D465BB97D2E065ED03CD29E4EB08213AE8 +:10AEB000DFD2162AB76DF4D7E8B5E2717491C5B543 +:10AEC0006898CE8579D17ECBA69069F671EFE2E3E2 +:10AED000CECD61E599E3DEE9E5FC4C3AEC18B7EC40 +:10AEE0001EA62F58F53AFBC735F8B85111F5E5768F +:10AEF00086A7B29504F1A6DF93AA86FCC1CAE7CB68 +:10AF00007E00FA4F41393F5F4B35823E2F9B6111E6 +:10AF1000F4B52E3EAFFBD508BB87250804DE3936D5 +:10AF2000FE2B6A421C8FC760F7BE149FF929E3CF3E +:10AF30004C4FA77A7B9717EDA7B8436FB7E01E90E9 +:10AF4000C90C97EDFD9E293ED171AE67AD736EE4DD +:10AF5000E51943E838137668E80F3A7F0AF3539609 +:10AF60001B45E8A7BC99B77B30A15DEA45BD93C4FA +:10AF700073295F1AEFEA5DFE229D6F629D1A69A236 +:10AF8000EBDA9EE81E0BFBA69310EE97EADB0BFDB7 +:10AF90006EB994A0BD35CC68BCE45A9A4EF8C5DAB7 +:10AFA0009C71F47BE82611FD4D1F7999DDB53DD1EB +:10AFB00084DF2D3FD4F6C493798BE83A36AEBD7B5F +:10AFC000F668D8FF0931320ABE4F63F68EB58E5D42 +:10AFD0005E1697F9A2B7DF2F952CB7D9EB8A392BDC +:10AFE000391DF879DA2F658C76FAA55EF41EC72F25 +:10AFF000F59297E9051B138C0F3527C404C4F56D32 +:10B00000F735E5807DB0DD378FE07B6506F3EB6CCF +:10B010004F70BF94CFF22B9939E017FA9597F977D3 +:10B020007E0BFCBBC0DEFE6D38AA2125B6F6E89784 +:10B03000F2597E25D6FE55DEFEF7D07ED2F1C74707 +:10B04000BF94DF39FE5B5EE6D77AFF84E33F996702 +:10B05000B767DFE3E34E78C6DC0D7CEE54C2FC221A +:10B0600063123134D5FC52D20DF26BEBE39DA91C77 +:10B07000F483C87180F38FB87E36E6812518B7B99E +:10B0800035E39DDECFF93E77F9D87EDAB399DAD78A +:10B09000B08ECDF3110F6425C138FD310FFC9760E0 +:10B0A0009FCFC825CCFF36E6811507C61EC7BE76E2 +:10B0B000F95C2CDE728968D9D72EDFA481F6F59170 +:10B0C000DA253530EDF12D2ABE4B35BE93BD533513 +:10B0D0007E4702F9AAFEF9E9D4F8A1E37E5E897AF7 +:10B0E00056C9E767615EF9FC4CCC3F2AF635C23C95 +:10B0F0004C91F97F940D32DE971F693AFD3E37FB84 +:10B10000F2F93B8B5FCDEFB305FC3EB6FB7C5BF900 +:10B110007945FEEC2A3C873E724F69B764E38B3772 +:10B1200073788E164814EA6DE57CDB2ADFDD383A49 +:10B1300007EC83EE7B8EFFFEEC9606762EDDDFDFDE +:10B14000EDECDD33FC033B5963EF746C5DB9F8EE55 +:10B15000D990CF9B5105FBF6661F8B97335203DEC8 +:10B160007F3AC30E7FD1CDE2006FF611873C0840D5 +:10B17000C85DBE7D3DD9F996358FCE3ACB9E63F939 +:10B1800061B1A128276EE2ED8ED4EE65F8AD6AAC10 +:10B19000047ACD5CE789F0FBB8D82780BFA11FBF38 +:10B1A0003DD9F17BD33F0ABFF5A58EF77C6EE2F85F +:10B1B000A81814BF6A0EECA344FDC9E1B7BFBF4194 +:10B1C000F1BB3BFF5C1B7E6F1A1CBF3765C3EF787A +:10B1D00077F466F86EC8316297CF543EB5D8E593E0 +:10B1E00097EB0DFD78E6F2DF924FA76E67EF4E5AB0 +:10B1F000F2690C974F96BED1F588717F0EF38B20C4 +:10B20000FF19E7222F78683E2190BE267867635A9F +:10B2100017CAA7A1C0A234904F5494827C5A48F018 +:10B220003DF60D8FB47D7A4007FFEE72E42B9BAFA5 +:10B23000CBC7F1FECD9787FD5BDF8B9631F9B471FB +:10B2400033954B5583CBA57B7CECBC648BAFFF7DEA +:10B25000B724B4FF0A72690BC26D10B9D4ED3B4933 +:10B26000B9B499F1CBC1E452978FC985477D9972E2 +:10B2700085CB055BFB6C72E9111F930F4F0E683F86 +:10B2800070FC6C72E909DEFEE7BE41E4527F7BA7E9 +:10B290005CFA199FF784C7CCDD70D4A292DE083B1C +:10B2A00077253940076B01CE74BF6EFD5967C26BBD +:10B2B000934B3F164C7CBFCB2C64FE854CB9F422DB +:10B2C000E71B6F5872C9E47EDF84532E957765972C +:10B2D0004BE55D724EF971E4D21B03E5D21BD9E553 +:10B2E00012E35BE35A985D3E0EE412C4836FEF6590 +:10B2F000FAE5DF896FCDF1F3F3887FB05CB2EC83C0 +:10B30000C1F9D657934B567F5B7BD8BE4BF3ADD874 +:10B310003627DF5A3219F6EB1C3FD313B3F0AD1CBE +:10B320007F16BE35C7CFE8D9B21728E85BEC726943 +:10B33000CE20FCEA44726996DF8A73617AC738903E +:10B340004B59E25DFE5E7AC7AC7F147E33E4D22CAB +:10B350008E8FC1F58EAF2697ACFEB66E70E277C2C7 +:10B360000E8A5F21AD774CD849F18BEBB4F0CBFC62 +:10B37000BA1E8DF14B8ADF597E1B9EDCCFC40D5067 +:10B3800081C7BB6373E03B044441DC54A65F701A81 +:10B39000A17632D8F5FB25C677E5546392F1EFAC80 +:10B3A0007E286AD709405799F134278AFB3A6FF211 +:10B3B000AD486F9FB98D4BFC363F8DE2892E80BC26 +:10B3C0002173FF557F9C97E9B837D796BE379770A2 +:10B3D000DE9B63BF176496B0DFBBCA05BF14FAE9F2 +:10B3E0009CF7E59AFD57E1BDAD2CF7E5AE877D31C1 +:10B3F000E87DB9319110F8B99AF3AC7BB9D6FE6308 +:10B40000EF4D06CE3A96C2FB5FDAE4D3013FB7F9BF +:10B41000F9BBA07503F6DF6DFE2CE75E84DF3B55BC +:10B4200078D76D85170F76FFABC9EFF02F1EFFFEA3 +:10B4300017A5DF0D707EB15C903438476916D8BB14 +:10B4400059A6901379283CB07FF0AFEA74DF3DE84D +:10B450002F75EC772518C5F7566E49093AF0394A29 +:10B460004FF730FC1119E8C99A37F83B613E87A5C0 +:10B47000D80698E79D533FC478938F777AF077ACDE +:10B480003EA93AA2423C63B390647EAE62C2FC5CC9 +:10B49000246E26D9FC18BD41E01E6DD77CEB70767A +:10B4A000CE56E47C07656390F9534BD4D4EB315A04 +:10B4B000BE93F32FF82B1A8AAF22E0DF2239857E64 +:10B4C000AC2B482FA60B480FA64FB9633F82F95DFE +:10B4D0004AE2E8DF6AF206CE467FDDDF795E161EBD +:10B4E0008ED4CE40E4983586D9CCF858BC19EF09F3 +:10B4F00032FC5970EE807742289DA61A5E33DE1D1D +:10B5000005F7AA53C6BB0ADC6FFF00F3B704A2BB62 +:10B5100000EE39E57117B45B64BE6EBC6BDB5F8F08 +:10B520000462FBA1FCF2F861E35DC77DE9FF70D422 +:10B53000B3DA5B7E6C99F303EBBD348ADF97EC746E +:10B540007654315D51E4874102FEC6236E81DD6B86 +:10B55000AC2126BCF3383DC8E22B6791B80CF0ACA7 +:10B56000259D987E55FE3087F460BBB9A417D3F3B0 +:10B57000491FA6544EC92C3ED37A6FAC5EB4BF3778 +:10B5800026B9593CA95943CAE33EB8F7C4F6A97194 +:10B590008CE1CBA3EBDD76F9E4D274BC4FFF9F7E48 +:10B5A000C13A07FB4F805BA9C1EA2F2F5411BF326C +:10B5B000892651CFE2F1D9185B68B3ABEE6A60F728 +:10B5C000EAE0F7B7208E3BD788A31EE82A8BE33B3F +:10B5D000B854BC4680DE05CAA6411EB8F5CE10DCC4 +:10B5E0007F59CDDFBFCDDC7F13026C3E8DA32EC60D +:10B5F0003887D57E11DF49585DC8DEB35DF5267BFF +:10B600002F706FF1F71CF7A2AD74956FB91BE4CDE5 +:10B61000AAA2FCA62BABE0F703C4845D2FC94C7D26 +:10B620009D12C61FAF2A9A77DCFB1DBE76566FB0FF +:10B63000F25511D22E9C06E3337937D63DC96D3FC2 +:10B64000775F5549CB73E1BD1B168FB1AA381E82B7 +:10B65000FB34E69B5E0DF6D9F489F557007F5A4519 +:10B66000D879F42A9F88BF6FF7D921FFC3B05E61F4 +:10B67000F26B0EBE9C39BEEB73812487601C685947 +:10B6800080E271D7A8C9A8C74AC14EBCBFEC2963E4 +:10B69000EF13BB8BE2F83B7A6E2AF0002F27C2C76C +:10B6A000313FD38FB569A2233EBAADDA48C27CDB05 +:10B6B000F248845220F1966794F3386B99C7015B86 +:10B6C000FD7DC2FB3B3BC0F4229015532602FDEEEC +:10B6D00043FA855F68C4FB18D00F2DAC86331D5A22 +:10B6E0006F83DB3827306960795A4EB2FB4B633881 +:10B6F00089BBC88D22DCF3FD8CDFF3B5FCE9259D09 +:10B70000CC9F3E7AE58ADD78EE18F319E0DF2C2134 +:10B71000B1DDDF04FF6FB51BEFCB50BE87ED4B797A +:10B72000FBD19B9DEFE2E92DCE7C29BFAF52466C49 +:10B73000EFE551BA2D3DF41F8740992CCDF86EDD11 +:10B7400033B1DE55CA847B669C402CE08C13C8FC68 +:10B750007D9ECCD48A03888BC65508B7937CFFA402 +:10B76000356FB20174D372BB81EFFACBC9D9483FB0 +:10B77000924CF0BE30159C95A06F486E4D45FBA8CD +:10B7800085E6613ABEA482F9382FD77A597E052B17 +:10B79000EFEFDF3F0BFB6FBE3D82FD4BC93359FF1F +:10B7A0003E2A07C6E3EFDCED236C1C7C2F5B766B37 +:10B7B000FB081B07DFD3967DC95F12360E2BD77AA5 +:10B7C000597E052B478F34C8355F42A9A6F0F9FC96 +:10B7D000F0378FABF7FE9EEABD2DB638AB148FB3B2 +:10B7E000FAFDFC3FA4200EFBF7ED61FC7DB2C5C95C +:10B7F000B1F8BB1056FCB7259F94A91FCC043E643A +:10B80000C9A98532C17BAB169C16BAB536B8C769D3 +:10B81000C169A12FD98A790EA7855A2FCB733859C0 +:10B8200072CE9A4FA67CBBB4BD4B013FF989E4DBD5 +:10B8300015A159152DB89FE4BF807C06F906EFD1FC +:10B84000FD96BF5F9519AF3F98BC8D99373ACE1BD7 +:10B850008CDD85B360BE54878AB0B82C83FD0EA7FB +:10B86000C67ECF149EDD61EFC4936E70F5AB16DD1E +:10B8700014B1F7D017F1727F95F53B9C49F64ECB8A +:10B8800034F67B1F0BA0BC0AF44E5EEEEB9D390C28 +:10B89000DAFB58F9E5BCBDE4E3E55AA215DEA1B632 +:10B8A0007E07F352DE5E0DB172EB7741EFCD63BFE1 +:10B8B000870A3E1188B3BD378FFDFE69EE34F6EE80 +:10B8C000BB950736110AA6F32A356B745BF91A4A41 +:10B8D0002F00977BF378BF05FB501EB537D4560079 +:10B8E000DCEE5D2432FD693C8FDF3A26B17AE11A45 +:10B8F000C7EF3FDC3BC87D9509B9CC0EDA73C9BDF3 +:10B9000062948EBBDEC7E4DFFA13FC7E581BD7EFD0 +:10B91000EF82FB4454BEDCC3EF1335F3FB433F809F +:10B92000FB4334DD7DD16494AB56BFF74D5FF882A5 +:10B930004EF3F5AF4804F059CFDF8F5B1BB91B7F87 +:10B940007FA7D997EFB87FDC2C33BBF0AE06E7FBBF +:10B950001BE7F379B75E7215BE8F2FFBD8FBF85249 +:10B96000F2EA4B105F752AF1087FBF7D6EED6F8B99 +:10B970003EEFEDE757943EAB187D82AED27AC92CEC +:10B980003CD703FA1CF34F4C9FEB33E8737D067DE5 +:10B99000AECFA0CFF519F469E52D7CACCF8B3A7E04 +:10B9A000B760FD2291C75B5D5868FF1DDAF55F5CEB +:10B9B00078C977C01EBA44CD7A3E7C88CB69B9C2BB +:10B9C0007481DE97C98F4EC4877EABC4CECC9D04F4 +:10B9D000AFE7F42451DF5929E038F0AEE872C097A0 +:10B9E0006E7E134308F53E259B3CA3ED8DDC027C67 +:10B9F0007DA796C511B076D6B93409CE47FEE5AB22 +:10BA0000A0FBD2A157D3FD689B475ACEB17BA1D6EC +:10BA1000FD954CFE38985CBCAB68A25B07B93597C6 +:10BA2000FD2E4B6E6195BBCC06DFCB72999FBC7926 +:10BA30002E8BA3EF0C4D7497F9B294474587DFD84E +:10BA40004AFF1490715EF52486FB85D0FD027AA131 +:10BA50003CBE46837DB84667FBF0FFD3FBFF92DE1A +:10BA60002FBA0ADFA95AFF858471331372AF5F05BD +:10BA70007133277B9FE99140741DD0B365670DA694 +:10BA80008F5ABFE3D51A88DE07F47BF9CD1715C0AE +:10BA9000B8D1021E775694CF7E7731103D983F295A +:10BAA0005D6ED6A4E335C08FB3E2BC2593607FBC46 +:10BAB000CACF1B0243D8FB0BD6BC248D9D3B481A32 +:10BAC000D3AB3B285F4E8C49C77304A8410FFBAE34 +:10BAD000AF584C7487412F64F6F5AAD863B5F0FED1 +:10BAE000E8AAF9A334B07B2DFBF6A262761FE48EA0 +:10BAF0009A9CA5F67B0BDB838C7EBF59507D04D6C8 +:10BB00001FF1A56A4075384D232901FC6135EC1DF4 +:10BB100031A188BD6FAD90889BF9E7F97D42122372 +:10BB20005FE53EE18F658A7AE0173EF68EB17F834E +:10BB3000807E502B2EE54FC179BB611ECA3331BCCC +:10BB40003FB86B720E8EFFE756763FFACFB76A6F3B +:10BB5000ED84BC1F9EDA20E4D762FE5B3B68BE2FFB +:10BB60004F24DD909F33E2AD9DB4FF45F78A2C3E14 +:10BB7000EFD89012687F7828113B30E89704E0DE18 +:10BB800076E094BEDD709ED0D7C8E2C895D09F0CF9 +:10BB9000FEFB750191DA0D6FF98EAC0772BF9C2424 +:10BBA000D1AF62DD5FFBB721B1D7607EF265E7966A +:10BBB00003DFBC43D54A60DFDDD1E69A08BFBF543E +:10BBC000FA2941BD895CE4657E963E4AFB34BFF0AC +:10BBD000F60B1FB2C79F2C2C60F870D7B71A701FD6 +:10BBE000C2AD47F089A4C0298C0E6A86C4DE837179 +:10BBF0006ADC957B212EF7F27818E34E666817CC45 +:10BC000080FB68972D65F957791C56A63F22D3FF14 +:10BC1000D097CBF93D5D7BFD4490C332FBBD414DD8 +:10BC2000CEF8BD41E73B8D163D1043D6E17D44FC87 +:10BC3000B7CEE84311D37154C488F0F738FBE9421A +:10BC4000F8F2D493A78B67A90D0DF3FBBFFBF8A8FF +:10BC500022008000000000001F8B08000000000090 +:10BC6000000BCD7D0978545596F07D4B6D492579B3 +:10BC7000D92BFBCB820408500989068DF82A80064F +:10BC8000042D1625D8C11401FAC7760BB476974A4D +:10BC9000775EC84240D0804BA33658C1A599E99938 +:10BCA0009E8CE34CF3F7E2148B0CDA80815660BA79 +:10BCB000A10DB4E3E8D7F6FC115CE81E7BFCCF399C +:10BCC000F7BD54BD4A2A40DBF3CF1FBFEECB79F757 +:10BCD000BEFBCE3DF7EC7729BDDE7B6C563563FAB3 +:10BCE000719BB7833176BE61E5834C642CB9430800 +:10BCF0008B198C0D1588A15DC58C6D08AC738A15E8 +:10BD00008C6D6A632C349EB1CD5032283F6F2BA7C7 +:10BD10007253F5C24C15EA6F2B58DBCCE03D7656DA +:10BD200050C7098C29D7AC53F0B963B9DD1F723302 +:10BD3000B6A53E617508E0DD1936C632195B97C6B7 +:10BD4000CB9B327DEFA4D53016700FCE1654789F62 +:10BD500069EC7DE85A6001F6652263CD0A1B140088 +:10BD60002F562F3306F80AF92CB409FAB731AF93DE +:10BD700095327607F32E9905F01D32D353D2184B26 +:10BD8000DA0E403AC0B54E5D4A8672B07D409A02E6 +:10BD9000E53A819D2B67F4F725FEEF4B809D58C255 +:10BDA000DF0DF85456DE771AF552E4796C09ED0888 +:10BDB0003FB3DD63732AB72B30EE90646F150A0131 +:10BDC000B60DBD9E0DB09ECABC2FC178BA93DEEFF2 +:10BDD00042B8374BF53A106E5380288CF5B479A8E9 +:10BDE000ECBE2A5143BAF5DE9E177200EA4FB4A9A1 +:10BDF0002C0074FD0D0C17C7AB2F4E0ABD2420FD7F +:10BE0000CBE9F9536D5E1680F72E642CBC5601BA4F +:10BE10009DB07B9907EA6F97065AF723FD7F9DC86F +:10BE2000F0BB9FFD243055017A6FB9FA1B450CCA4F +:10BE3000CF1E0A14211C19472857F46039982BD6B5 +:10BE400062A9E6719819CF0379FC7988CA1D30EF91 +:10BE5000E760CA26A415D3BCC13C19EF0DD27BBD47 +:10BE6000C9032E1C879E6557105FA8AFA901FC1758 +:10BE7000CDCC609B00DA6167CDFE8A91F47C4811DD +:10BE8000A9BF4552AFCA8034B72B931AE4E9C03F2B +:10BE90005B85AD355E062C39A9618E0BDB29D4AEEE +:10BEA000EB4FD36A18D0FDF9B643DA7BE322FD14D9 +:10BEB000AD6B15029319CB6EF27BF4246C27894E7F +:10BEC000C46719EB477AE0F3F6C991F62BF0BB355E +:10BED000D4AEB11FF8B3ABDDEF498BC2AF4B101A34 +:10BEE000FB01EEDA0B1F877EB2E72D7BD12544E301 +:10BEF0002D737CDA19B52B6A1A1256513FAD821791 +:10BF0000E0ECF043820A78A84D4C5C19D5AFBA0E2C +:10BF1000F08EE2C32E2164C3FE958798023CC35C79 +:10BF2000F6906D16C0AE8509BDEDCA48BEC5BF739B +:10BF300051FCD7F5A74522F1C93189F8E440E6550F +:10BF400022F52730C101FD65C95A0ACA79D6403A9F +:10BF5000D3E19D6D508178C7CEC32E985F1DF8EA5E +:10BF6000C53627D381CF5E063E457837F029967FC8 +:10BF70000D7C89E5DF001F62FD8F800F11EE6FAB36 +:10BF800025F895368DE057DB1A08FEA7363FC17BB2 +:10BF9000DA1AA9FC495B80CA9FB5ADA6FAD7DA5A6E +:10BFA000090EB705095EE460AD48C7991B655D04DD +:10BFB0007CB3EB3CBB1CC06AD9DFFF24B41AE9CFC9 +:10BFC00060C2801F3E32F825DBB370CBDBD08ECD54 +:10BFD0009219B001EBF62C0CBC4DED66782578FE7D +:10BFE000B23FFD5F8F54231D92BD489FD405DFF102 +:10BFF000213FA62E8347C00FBB6CAA945EC9D8A967 +:10C00000DEAF373827A0DCB28E34A0F729E5918D5A +:10C01000084FABFEF81BAFC0F77EA3DCD3E3043CB4 +:10C02000B666361C571584EF27B8B4CE9784F8301F +:10C03000767FCF01787ECB004A0E4D8BCEA07F2D30 +:10C040000074BE96C3CE32C6DE9EF580300BDAFD9C +:10C050005679A0E749A87F16D4C52C981F9BBEA689 +:10C0600067B18BDE97B378FF0D9385487D66CF5D12 +:10C0700066BDD1FFFD3D1AB0DEB1D322F5FF1368D6 +:10C08000AF03FC768932BF1AF5F619D1BB8BA15EDE +:10C0900050D7933C6E023D04F8DEEA97489F9436F1 +:10C0A000B13E566C3012D4A7D5297DA84FEF4BE591 +:10C0B000F290CDE4F70681BF445D60A02259EA3CCE +:10C0C0004960255036F0E7261FA668003B23306301 +:10C0D00051F512F6C7689EDE2E017AC07787AE77DB +:10C0E0008676417F2B917FC7E13C7279BED57F4137 +:10C0F000C5F92EAD735681D287E7AAF95E18F133E0 +:10C10000DF8B6D87FD8A51F5E67BEC8B0B32CE73AE +:10C11000D716467A27A564485D5B61ED57AC8EDF84 +:10C120006F543B268DFD7D268CD18F295729762D86 +:10C13000A906FB992D7B7741D78B17DDEB23F95CA3 +:10C14000CA4409E6212501F4A23BD27E525AFD3FA2 +:10C15000A7C2F7FFD9988F940465C12CC283BFCFC3 +:10C16000762F9F8BF2FCAD6745B609E00C99CF7333 +:10C17000468F520953C6DCA95C3E1232562EC4E7E4 +:10C1800009DB65A6C2F344A6DBB2AAB114BC618682 +:10C19000FCDE3B3B0BF9C326785F425353BBE6E61C +:10C1A0006AE8EF9AD99F2620BED7FC5C1424EC3FA6 +:10C1B0009DE3513935A915EDF8CD530BA6AD007AA5 +:10C1C000A60ACCDFEF1EA947EE4AE5FAE545C61AF6 +:10C1D000B05ED879AA15E7FFB31AB780F2FCD9C7C9 +:10C1E000DC0EE519788EB7F3F1A305413BD2EE01E1 +:10C1F00066BE06F82F8797765B6B0B8EC3BE03F483 +:10C2000012746DFFD3354EB4231D171DD43F630345 +:10C21000C96887ECAE80920ACF4BB68A1A7EAF43CC +:10C22000490809D03E25A9EA908A76D1277A514F4C +:10C23000A45C2F13DFF7BA6F0F21FD1FDFEBA2F60F +:10C24000B62467C805F08BDA79A50CEA5FAC9315C4 +:10C2500094E3177B16FB498E14511947764D1171E3 +:10C260003E5ED43C439B8085538430C9155BC342FA +:10C27000286727EEC823FDDB212843522589832A1E +:10C280005F6D882E0CB9C316DEBB03F5F57487F21B +:10C2900092820FBD47506E3BD72B5EE4D76B957DE6 +:10C2A0007B7F0EF59D9AD35F02FAC596BA6FEF19A0 +:10C2B000AC6F849983F6BD5ABD737905C99B6EC86E +:10C2C0009FF0A503DB8B0D383F58BF02E9D2C90EA2 +:10C2D00096C177EB0D51EF557609C538CEBB18895D +:10C2E0007F67DAB5EA7237E205FD98720B15F5EE55 +:10C2F000DD427106814302D0355729910B518FE6FB +:10C300004A2C05E627D769B3C8BDDA69D503368359 +:10C310002FAEFBC0FA3C9F45C1F09DAF1B7C124B7A +:10C320009FD871E566C8A9884F6EA74C0F63F1CD01 +:10C33000CD2893FBAA0954526A917EBB7C3E685F6C +:10C34000A4398754EFA5F1BD8E0DB6233F16AE1B61 +:10C350001BDF6B353115F9E25A50BEAA8AEFF5772B +:10C36000286E9C7F3EDE9412AB1CBB5325921B9023 +:10C37000E79753A12CED11C11044FA1FD79BC0F4CD +:10C38000287D3A7E7B9A059E10CAB5B49FB4BBC483 +:10C39000523FB97FA2A57EEA9E2A0B5C19BED6D277 +:10C3A0007EDAA17A0B5C3330D7D2FE9A530B2DF094 +:10C3B000F4C13B2CEDAFFBA0C5527FFDD0372CF56F +:10C3C000375C5C6B817DEC114BFB1376B61AED3B51 +:10C3D000F3780734E46725A312F59749AFA70D7DDD +:10C3E00030EC9F2AF2D030FD41D73A3CE0DC47F5F3 +:10C3F000979CC8E99DE485F7A2BEEB52732DF08BA4 +:10C40000C86740FF8C79252C10F57E62F9441688A8 +:10C410006A97B5B8CA520F1CA0BC9F68C0E4679564 +:10C42000925CA30E7A096C5B67E6ED8DCB81EFD64B +:10C430002639C9AFEFBA5EFD5E13D43FF6868DADE7 +:10C4400087771E33F8FB68A6F6239CFF921E3BD32A +:10C45000212ED93BDD1E467D91E2B693BF9FE27E41 +:10C460003A80FDA6943919FA972975430CFDD8CE68 +:10C47000B61EAD0CFCEDDE365D2B03C525D7F9C32A +:10C48000E8D7C8194C15E17BA9756C2FC2A91A878A +:10C490001F4B55E97BA91AB48F964705FA891AE70D +:10C4A000715124FD37D4E520BB252BCA6FFE310323 +:10C4B000E32FB077202F67E74F227F92C42D07DA52 +:10C4C000CFCDA3FAE54F8B54CFBE482FC4FAB35952 +:10C4D0004CDC04FA2DB9D44BFA75E82189FC8EE6C0 +:10C4E00039BFB4A1BFD0C4FA6D3C3E0B4BE8AF5F7F +:10C4F000CF06A9BC816909F87CBCE8BF17E1DAD096 +:10C50000D69928FBFF9C1E388974DA620FFC2D7EB9 +:10C510006F4B9ADBABAB88B5522820BF743BAA3671 +:10C5200015A35FE4DFF2367DCFC6F07B772E98BC93 +:10C53000AD01F0B9F319D12B507BCD89FAE24E5FF2 +:10C540008697DB7FC3BEC8CC5506ED6E7BB4AC0AC4 +:10C550009F67C87E1F8E2363B122E8D0AF9AC6EDD5 +:10C560005C4246F521159E27F4CA5EEC2E91A9F592 +:10C5700048AFC41EE60D03BD1696A8EB57E0F75D65 +:10C5800082B20BF471DE3DEABEEFA0DFA9947825FC +:10C5900080F35B5BB739D17F659E21A4D76336B04A +:10C5A000BBC8374FF178B033F3AA7D36E41B9FF355 +:10C5B0006307B45FFB868DECCFDA67E410FA0D8A6F +:10C5C00073BFF61EF049F6326EA74A765C4576AA2E +:10C5D000575076929FDFE5F0A29FFF1CF2850DE396 +:10C5E000B21EE28FB359DDEBD17599E0EE139115D0 +:10C5F0002665EC5D8FE5E4FCB322480E9B5A267459 +:10C60000A4015C59512CA5ABE8DFFA3AB0ACA95BA8 +:10C610002E654079CD2C41CE42B94A2B213E5ABAE3 +:10C6200072C129F47F7C8A5BC5EF975CEB5C8AFA68 +:10C63000595200BF69F1E3632979BB1040395F2982 +:10C64000BF4F7EA40A7A1CDEF3A5BB89EFB30DBEF3 +:10C650008792C7558B13C9EE3E666BDD6B8B8AD70D +:10C66000F29BC2825681EFAD1306DD91782AAF6945 +:10C6700080DAE53DC02AD13F296C1A145AA05DFE2C +:10C680003D56BEAF4F0FA89857287CA0C7F25C71EB +:10C690001E24FA768A5C1FA5A40592D02EA6DC582B +:10C6A00096867990E474D6BCA022C2379F1A71E2B4 +:10C6B000FB067F98FADCF46F3F1A8E4B2F8444E020 +:10C6C000EB9787029B26E03882369A6F3614965293 +:10C6D000901F1F5C40FC58E8B940DF6FFAA4BF2BE5 +:10C6E00005EA6F730CED4F41FB7537F7C376B9ACB4 +:10C6F0007172308DEB916FA6713D66DB04967D2AD9 +:10C70000947616207DCAFC8347A0FFBF6785959B62 +:10C71000C86E0F090B407F780CBF6DCACF947A06A4 +:10C72000E3280E2BFBA83C6C9407A0ACE074C189F5 +:10C7300027D1291D399F7D9D196F62BB3EA6BCA9DB +:10C740004495B612656E397EEFA0D8FF12A94BA6AC +:10C75000A13FDCD799B60BE30906F14A02C0850F69 +:10C7600065100CED37517EE8BB090CFD2435286BB4 +:10C77000AEE491DF2B62C3F65DC4F883E91C76B2A8 +:10C780009E76E4A3A97BA2EC3F433B6785A71DB23D +:10C79000C2350356F89A5356F86383AE10A59C40F1 +:10C7A0007F89E800FFA70E7E2CA03F7F1008CAA655 +:10C7B000833D6743ED3701FECDE057A0DF57A45B13 +:10C7C000E3A1E6D31F9E66C9444D4B1CD47C3AF1CD +:10C7D000AC988CF6D4EA5F349FBEF75E6CDF1CDD4C +:10C7E0001EE872D6ADDCBE1C4AEDC9C0B639A897AA +:10C7F0008312E9B577777C368EFB474399FE24E4B4 +:10C800006F95F0BEF321D18F793567B04B1F0FF8CC +:10C810003A55AF1D5B3DEA3DDEBA1FE093A71CA869 +:10C8200056D86CE9F0A136D43305B2EAA0FCDC3D61 +:10C83000CF2702BCE15FA11EE093AA9A4DF6ED90CE +:10C840008DE66783C0F31A1B6C8CF22366DE6EAB39 +:10C8500041AF2D69A6FFA627F23C503811FDF7A97C +:10C860007B18ABB0E62BDCBC5E73637D6538B65ECF +:10C870004BF65DCDA700FF6A067D12E6D34CBA43A6 +:10C880003DC1533436B40964AEFA6DF95C341DB35E +:10C890001BADF094D3AE0EB4C3477D4EF25F99F456 +:10C8A000D1BE9F03FC29F8D3A88FA79C4E92709C01 +:10C8B0002744DEBF97C1FB51F4CF6267C530D46710 +:10C8C00005DCAD216C1F531F3C7D6CCA010BFE6162 +:10C8D00027C6A149D3201E43BDC65ADBD12FFC5128 +:10C8E0005A5206F90F15AC02F960B6E4F68691FECD +:10C8F000EF485E706B99E3ECF893CB511E8E490CB8 +:10C90000E56743B1BA15E30AE51712D93D259155FC +:10C9100056BA31CF3A30E50090FEE92FBDACD316C0 +:10C92000C9A3FEA88D31D4FFFD6D4E86FAFF953662 +:10C9300085E057DB3C04FF539B4AE59EB6722A7F95 +:10C94000D2E6A5FA9FB5D512FC5A9B4670B8AD81C8 +:10C95000E09B327D87D3603E4F433BCCEB2654BEF9 +:10C96000EA2C45FE6892306334424E6F5BF34DE72C +:10C97000129083671E3F7C5326D0E5E40312CF77E5 +:10C98000E8876FDA5B1695CFD56455B99A110F72A7 +:10C99000E132F3BB20DF9328BF1B7082C9C931E2AB +:10C9A0006E07F3931E62ABBD4EFFE4CBE927201860 +:10C9B000FD0CDA46EB47E3FD00A1BB7B603C1B1995 +:10C9C0006B45F965F2407707E6D98A65823F1054D6 +:10C9D0008309076EC4713B50CEBDE836E85A1EC6C7 +:10C9E0009DB681568A436BDC461CFA6D8A4B3BBE72 +:10C9F000EF64EB8B23F1A81987C6C60351F1BDC5BF +:10CA00007E600608F92BC129703BC986E31FE2B797 +:10CA10009634DE6EA2726C5F2AE5A7783EAAC2F356 +:10CA2000717D9A37024F5153F7A745D57BCB2B67C2 +:10CA3000A647C1E5CED4A5ED51F9ABB2A4AA7DE9D4 +:10CA4000DE08FC367E90E7AB34D4F7FFD3F92C67D1 +:10CA50002A9F8F1F66FE380DF311FADFF23CDFEBE1 +:10CA6000993FCEA5F8D6B07B452CD9BB09E3DA12A5 +:10CA70005D4C40797A99911DC518408CB647AAC083 +:10CA8000D00E47D9A337296E37EC51612A4BF08E6F +:10CA9000325F51F648C2F9005AA8F6ABF139A378D3 +:10CAA000D5AC0794C364AF18B7A7545F8A7642D455 +:10CAB0005C532CFDD0BC9687A2E699617C67B54B90 +:10CAC00093FBADF07F97DD33F96B8B3CE044BDB554 +:10CAD000E58BD1F9765BBAA9EF87F116BFBC264288 +:10CAE0008F427C528225AFD720D4C171063A6D9611 +:10CAF000EF3607AD70D30356F88E7BAC70D4F7C811 +:10CB00009E5E31AC6B27A3EDFA7BA02F51BFA983AA +:10CB1000CBE78172672B59F18DE8CFAC62DE6E1CDA +:10CB2000FF8A9E444B9CF90EDA5CCAA30A945F7795 +:10CB300032F520E66F8A6AC72BA81FB6B74C3C882F +:10CB4000F99AE77DE5645F7AD253791C26161F3C7B +:10CB500083EDBE368975A0BED1B9FD770265309EE2 +:10CB60007DEC6149437DAFAF6721BE5E62F51B5628 +:10CB7000F55AF3162D31F9886D0D6B8B4AE07DF572 +:10CB80003B0902FAE7C5D5E77CA5C8FFA0B7304F3F +:10CB9000D3529D568F7ACC840BAB4B6E8C869DEA1C +:10CBA00050FB0BD0BE582B5F8B714B6150B5B7B8A3 +:10CBB00047FA352D9DB1795E9DC687F44C4F1B39E0 +:10CBC000AE2B1D87D9DF39B057382FEC0BE0B7AB50 +:10CBD000A3E4471E14502E5B824CC3FCD68A754CCE +:10CBE000EB83F992580ACDCBC9274B77615C08DDFE +:10CBF000901FA11A32F8E374CEDFB1F3D9D22489A1 +:10CC000085F05E8B4762981F62C112D215C4E7F0AF +:10CC1000CF969E8FC35FA29E689228EE4A4B057FF7 +:10CC20000AE0739B05D60BF0B9A669073D00AFEA91 +:10CC3000625E72C7D84003EA91966AB0FF8407F734 +:10CC4000479CF01FF5877E21F0597130CA8F403C18 +:10CC5000D02F9C827C67F52F5AD02F9C42743A17B4 +:10CC60004DA79B206620F9731F23BB1565C7EC8574 +:10CC7000A3DB313B233B067E5365C48E25CFF4F600 +:10CC80005C05CF87524515F3C99D2BE5863E6B3E6B +:10CC9000D1FE651EE334033D56804F601CBF4C1827 +:10CCA0009A8CFDFDD2AE081D68BB58600BEAE5DF2B +:10CCB000286914D71C4FF54E1679BE5377D601EC70 +:10CCC000F2FE2D03D8E1F8DD9C86EB23704242DAB8 +:10CCD0005C847F99A6EE40F83FD2993EAB0EFBE70D +:10CCE000F0869E3FCE3950803023FBA064246DD265 +:10CCF000EB100F8E1FB8CC3AE71BAB9CCFC22016AF +:10CD0000E8A3F8F48D12F0CD5641DD56531C792F6F +:10CD10000DDF13C6786F81BE511EE53DB7F91ED0F9 +:10CD2000B6FB6AF4EF383DB28D7AD1C027FAFB32F8 +:10CD3000EA1D259084F1D0D68DB282F6E6ABE29161 +:10CD400075A9712FD737DAA491EF01DAED26FEE24B +:10CD5000E8F887B03EFAFBB631F0FF4BD3E352FD63 +:10CD6000D98DFA2BC60F9AAFCFBA8CF1027E36F46A +:10CD700013D5409238567FA033D78F3EDEDE98FE23 +:10CD80005C849F27B0654CFCE2F407E3DD1A335E58 +:10CD900097BD74647F289FE12C4AD111122910CBD2 +:10CDA000C8A8DF7D32B727815E5A67DA1E6012C6D7 +:10CDB0004D23BEBF92FB03094C0FA1DFC9CA035B21 +:10CDC000A2C7FFF8DEE9B42EF1EC3AE675012ACFEE +:10CDD000CABDA4876B57F6FAECF07C4713EBC74F3C +:10CDE000EF681A70619E66C7E0804BC5FA078E6FC8 +:10CDF000C4EFD67626912E9ECE7A294F5E72BD4C18 +:10CE0000FB4052AEFFC4BF12BE53925A2561FE864C +:10CE100019FB1C3AD3EA5EC0EF96D83427EAA7EC98 +:10CE20003A59C138A8D3DEEAB363DEEB4EA6D23A54 +:10CE3000BEAC88C5945F63433AF0CCB34DEA36CAC2 +:10CE40002375CA4C20F950B735201CCC24BDF42CD6 +:10CE50002BA6FCA0BE4EE27E216B151626D13F68A4 +:10CE6000DD61987E42EFDE9948BF558CE2B1E26504 +:10CE7000BD02E251FCFB2495AFF3C2DFD5863E94A0 +:10CE8000086FF27B9E199E3F9E97620FF0F76176C6 +:10CE9000C83E15342921B20BC67ACC12C67933E7C5 +:10CEA00001F92FEBE7C4C0B2A395D699D875E63A3D +:10CEB00093B53EFBF42336A4BB22B254DBF44BF70C +:10CEC000B76470CD5EF4670E362612EF163759ED53 +:10CED0007A518C5D8FCD77D46A9D3331AEC88EC9BF +:10CEE0007780F890BD32F964449CD7CDE33807F3DE +:10CEF000F6901CB026E5FD4991F8712736443FAA0B +:10CF0000C0F0A362DFAF53F41F201D4A6486FE1AEF +:10CF1000EE1B12613C8E84565A97C4CC6F7B4EC474 +:10CF2000CF15ECCC995305F65F64018CE7DA052642 +:10CF3000231CF9EE20C3EF0619E81F9C6FB7C8F059 +:10CF4000BB1B9C1726615ECFE1FACF49981F4D01AC +:10CF5000877800EDAAEC5750E836D8D47D189FE8C2 +:10CF6000476CB44ED8A17897F8E0FB1D8733593B46 +:10CF700034DB90C4F32D1D1EAFB3B202D737D46596 +:10CF80000CE476CF93F7CE7502D31DC7853C888F0E +:10CF90000E64AC267BE8B898C70251795887DCCA82 +:10CFA000907E8E8B8596E7FBDA18ED1B32E17A775F +:10CFB000C92CC4E7D7867E99C9BC9DF8DE4CA7640E +:10CFC000590F715CCC6181F4D1FACFB73CDF07FE19 +:10CFD00034EE47BA74FF8996F515C7C5D238FD5FA0 +:10CFE00015D3BF326AFF917ED32DFD76C98CF2E94D +:10CFF0007A6322F1436C1C7321A37E302373E47A9D +:10D00000D4867CBE1E457F00DF98914AFB22CE6706 +:10D01000F03CEAAC79A532E5DFF2ADEB52371A7C91 +:10D020006FEE979895618BF197BD32E5EBDCB1CF50 +:10D03000AD7EF213C84B3523F11593AA07109FB5A7 +:10D04000CB1C2AAE9FC7CBBB9F6E63B40E70D2D5EC +:10D05000BA0CF555EA536D095D20A72751D7811FFA +:10D0600055FAD4B3737518EF6981E7F3BA32F68DC8 +:10D070005B3E4A9C67964D32936BABC6A8B787C799 +:10D08000E13EA726434E80CB26A35E1DAE8701D688 +:10D09000627CC04296712D6B152CEB51A7310FCFDE +:10D0A000F1A9593ECAFEB0687CEAD2C6A877846B63 +:10D0B000081F89B5C6C3A7AEEAD2F89C31F29E5DBF +:10D0C00019C7C78D85CF32998F2F6EBD7D80E8B38C +:10D0D0004C34F3F4567C96314EDF4BE263AC530094 +:10D0E0003E3563CD17E25337C67C2D730C107D9609 +:10D0F000497C9FD568F8D45DCE7C19F9C10D76D0F6 +:10D100009F52FC3CA1991F7C32E54D6B7E90BD790E +:10D1100093AF0CFD5466C03F9E1B067C2ECC5B5B20 +:10D120004EF265C47F5FC32AD0F75F93B93CDE91AE +:10D13000EF0EB547C9F34ED06B1AE88510E81F2CE7 +:10D1400077819ED0C6E3FE350FC12F433CA9D1FEA7 +:10D15000B5722AFF1AF0C6FABF69AB25D8ECA762F0 +:10D16000B54071E5E47B048A2B63E9F66226CF7B48 +:10D170006CCD5196AE44FDED4BE0EB3AABAF835036 +:10D180003A123732D64FFA7DCBEDAC12FD8E89BB09 +:10D1900039DE19B3B2429280743A30D0867A66B1E1 +:10D1A0004DC57CFB069519FB57206E053F6EB9688F +:10D1B000E81EB03098EF1ED467BF88FAE7F94C9BA1 +:10D1C0009177510EEE453A78ED2ADAB13B4EE750B1 +:10D1D000DC7734476298E7763842AF639E1B14A22F +:10D1E000FF252FE55D2C79F1942FFEEE75DC47725B +:10D1F00012EC37C689997E6BDEFC89A6176C98F70E +:10D200006E5AEE5E237A1175818984BF3D142A46D9 +:10D2100014C20AFA87995E998501BEEDAC83F63D8A +:10D220006C7585C98FD82A2843ED14EF71F96B8A84 +:10D23000896BEF888119AE92639C2A35A5E0DAF3F9 +:10D24000067C347D24FD63F3EDCF645AF3EA9FB28C +:10D250008AC76761657E1A3973B1EF9BF9F38599C7 +:10D260005CBF6EB0737D13DBCEC46737D23013F969 +:10D27000EBA2F69E2D825FA13C28A0BD290AC2F335 +:10D2800028BAC9198302EAF778F8EF143ECA616335 +:10D29000C86D21DBFC31EE4F2E64F2FB381F2443B6 +:10D2A000C2C871EF1931EEBAB7CAD868F2C2D71145 +:10D2B000EE382479DBD5085D4C3AFCBF969BAF670E +:10D2C00032739F0FF9CF669E505AEF55C9FFCA12AD +:10D2D00079FE35A3FE43790AAF3F67E113EB7E5732 +:10D2E00069DF87823A7994FDBFC121A10BF342EB3C +:10D2F00079BEA830FC21DF7F1B6462A73BB2EF3010 +:10D3000056BFC5EEC795DCADCF0F02FD3CBA4CFB56 +:10D31000FFF4FAD61F0C529ECEA160DEE57B89DFBA +:10D320007D7E10F00ECA4EC50172F26D2910403D8F +:10D33000F8B918508A61C8694581FFC884FE372949 +:10D340002FAEEE53516F5729B81EDE147C243C0BD0 +:10D35000FC32257DF4FCAA6947FF90C9F356A76DFE +:10D36000E1025C47A82FAAFF43E6287E4153F0BBA9 +:10D37000D4DF0C439FC7D62B599CFECF19F675C935 +:10D38000BDAF7CF832E09DA85654098057624538FD +:10D3900063118CA7E7ADD22A74F79D467BF0EDAB05 +:10D3A000919FCFE5051C5951DF75AA8A1C207DD5B8 +:10D3B0003F1DEB67FC67C5DFBF05FDF5DCEC5630B4 +:10D3C0008EBBE0B5558B2523F1807E14ECC77971B7 +:10D3D00013F1B9D9CF6BAEC1E728AED2EFBFF914C4 +:10D3E000E8AFD75207F304803D4FDF727306C8D110 +:10D3F0006B99837958DF20143C7A00611BB717CBF7 +:10D40000B30A1E453F66C6DC8F5E781C65F52A3B75 +:10D41000EDEBDB68F835E6773BB3241A4F6716A7C8 +:10D42000A7498723F7001D32E2D3A1DC681F458797 +:10D43000F2ACCC9174F869913601C70548A62C2A44 +:10D44000C6FDFC2CBC1270D4B2FBE74C832E72D408 +:10D45000FEBF7A1CE9CA423EB198FAA9E474E8F921 +:10D4600018CF2598FD4C2AD2AAF0F9917BF6111E0F +:10D47000AEC37CBD9765E81AEA5B0DE6F7592FBD90 +:10D480003F1DF1887DDF9C8F43F95CBF85B27999A0 +:10D4900066F8419BECBD9E05502A654F7F5381F78E +:10D4A000BA8BFB1B47DB875F97CDF75F41C8A1E1D4 +:10D4B0007B9DCA2BCE96A8764B0DBA1C2CD01A1089 +:10D4C000DF44DCF706F58FD602FD00CFE4C3E95553 +:10D4D000146F95B1EA85209F0F64737E02BCFD88AE +:10D4E00077E2F45ED45DCC55C6F17ED4F324C37CE0 +:10D4F00081AB024A7A3EC8504E5C2CA0602EA8F93F +:10D50000E98A473B6B711CA172E4033D3BFC289EFA +:10D510000BE8431F05FCD98701C63868A71DDAA0B0 +:10D52000BF9F6BA7B82A765C01038FFE3CAD19F153 +:10D53000184127C7E00B8FE3BAE064BB5787473336 +:10D54000C4DEC616E4ABB96EB2F3F0BC3114C557F5 +:10D55000BD061D7AB3B85DDEF8076723AEC7C6D235 +:10D56000F972F9ED5B23E5EE5BA3C91DF0DBB711A2 +:10D57000FF11FC961297DFDAE2F09B8ECF63E91081 +:10D580000B43CF3AEE6F9330CF8CEBA017AFD6FFA3 +:10D590000E60A7C05A1D1E846BF5B770BDBA442635 +:10D5A000583BE5D30F40BD2BE0A6F61F0881C711FD +:10D5B0005F87A2235941AF6A34BF8559A63DB8B2EF +:10D5C000FE45A7A6B5603DF42FF1FEBF8FE3901591 +:10D5D000D65900ED1C658CFC2CF33B7719DF993193 +:10D5E000D71DC0F99B61F8E1265D6FC8E6E7379269 +:10D5F000B2797C174F2ED65C422E1AB387E5E287AC +:10D60000C4E797908B8D467B989F7F20398A2B1794 +:10D61000AF529958C1E52211E5C28BDF637A8307C7 +:10D62000F1E572B02FEB7F931C9872F274F62F2CF9 +:10D6300072F238C07A7EFCF1AD35C6978CE383FA7E +:10D64000799536DA577F814DDE85F44CAE55641CF2 +:10D65000EF1B5926DEDAA12C9ABF4186FCDAC78679 +:10D66000F63A50FEEAF8FEA55BF4018DBB47BD6CAF +:10D6700001D41F33DEDB69AEA35DC5F74933B9972B +:10D68000213D62E5D75516F606A2E4EDEB86FCF6E1 +:10D6900065FB4F21BDFAD8E004F473CCF9881DCFA7 +:10D6A00019E37BDF2DD4CE8CC6E797B21B4236B789 +:10D6B0001B82314F69FFE96C1D4DBE67DCF7139289 +:10D6C000EB78FDFC9721D79F1AF898FA3D11F53BAE +:10D6D00092C7A3D339BB28FDFE29E9F77B3659E46D +:10D6E00015E4FEB351E53E1DE4BE7854B9FFAF38F2 +:10D6F00072FFE568FAEF2F20E7EEEC51E4FCDFB2B1 +:10D700002E8FDEF30C7ACFFB8AF4AE30DE2FCDBE47 +:10D710006C7A97668F4EEFB2ECD1EC7A7C7A5764D4 +:10D720008F629781DE93B347B3EB9E1176BD7A3457 +:10D730003C9CF87D81DB7DEC87E5EB3AD2515BE1E7 +:10D74000A6753EB3DD19DC6441F3A8AE417FFA391A +:10D75000F0C7306E047B777DF67FCF7CCF457C624F +:10D76000E77B86C8FDB35D4F77937FF617F8CE92BF +:10D77000D1BE939ECDF5FAA5ECFE372276FF4EA4DE +:10D7800043ACBEEC33CEA7F4E7055665737D360790 +:10D79000F5D3CE87D304CCD7E76B6101FDEF66C329 +:10D7A0008E9CC852B91E32DEDB29870519DBB72AE9 +:10D7B00002EE078AEAEFFEB1FA8BC503F05B8BE35A +:10D7C000ECCBD6BE89EF9D31BE37ECBF197E445FEE +:10D7D0005AFF6AD4DFBA61AF7483CF4D582BD41E81 +:10D7E000C9E676E5BB58823FFE006EF546FDCDFDED +:10D7F00044AEAFCDF188FE7E36887605C2BA90453C +:10D80000EF2F7BC9D4FB789EB1394B36F5FE06C4A9 +:10D81000AF2DDBE437DE5F3C3C9F36ECCAD3C63C21 +:10D820009830E0D96BE0F9C45878C6D2E972F17D3E +:10D830002D82EF8EEC9AF8FD99FB0ECC79B3A39272 +:10D840008038F948A7A9374AABF0D15F0DFBB1FE8C +:10D85000DD387E2D51392092425112B0DFE78C3CE9 +:10D86000F273F76CA375B1BE754A25FA75B9ABB9F9 +:10D87000BD53EF29ECC37D04FF60CC572C9F0EBF36 +:10D880006FEF9F30AD82E8F263C4FB863AEE27A6C5 +:10D890001CA65DF74C2B526414A63487EEC1F8B673 +:10D8A00047D03DE80FE973DC7C5DCBB378D4FC87CF +:10D8B000599AF90D73BCCC537D89F6EDD45E49D4E9 +:10D8C0005BFD57D2DEA13762FB081DD32B895CCEEE +:10D8D0007E3A77A73952293F76D2E00798A7E3240A +:10D8E0002FB8A9627A84AE23FBE7F3E5F3B70A48C1 +:10D8F0006757397C0A9EBAFC3AF94FA2DA4BFC9181 +:10D9000050C6F98379DEA6FE22784C9B66C5A372C9 +:10D910001AE211E9BFDBC4E7BD2BC1C76C179F2E0C +:10D92000BC9D5EDF4A79037DBDCC3AAA298F407940 +:10D9300085A0EE501C507EEE2A0CA113965614F8CA +:10D940008CEB8FD66BF8BEC5D6A958BA9942E7C4FE +:10D950006FF0322FEEE7B8C1E9D6319E665FC81F7F +:10D9600045AF4744AD53095F26FE59DFB77B46F903 +:10D97000FEE5E62F523D5C5EA2F217A99ECC51DA7D +:10D980001BF98B6436A8E3391688F9785E15833F56 +:10D99000F49BBD2A8DD36C5FE0E1FC9212C7EF2BA4 +:10D9A00030BE6BF2F792AE7A5642FAA45547BAF5FA +:10D9B000353205D7C1D1EE233EF32A1FA4E71782E3 +:10D9C0004CC1737ADACDA932E665CDF199E335FB26 +:10D9D000F71AFD0FE36FECBF3F6D638D7FEFE6E35A +:10D9E000AD8AC26B6991CF1B3D6E73BCB1781F6A63 +:10D9F0000B8667D9709D2B40657A7026FB2DAE2370 +:10DA00003AF97CDB1B41B27270B979E0CEB580C2C5 +:10DA10005929701DF67BEF551F3E860754069CD38F +:10DA2000DA919FEF9F07EF14D33E7509E7EB2FCDF7 +:10DA30001F1D49DFA2BCD85E9B53919491FCD1314C +:10DA4000BBB2318334957FDE6188DB3B8E784FB982 +:10DA500001BEDDE39FE701FC3B8E791B33E1BD9EF8 +:10DA6000ED93376F467881C0F77FEA47DC3EA05BD5 +:10DA7000C71C0E07B6FFAF793AC24B05F22756C155 +:10DA8000FB04EFB5FA7B11F9EAE279AE1CEEDF7424 +:10DA9000F88438EDB8FEFB86C768377FEC76BF3672 +:10DAA000DB2DE3F700C46BF733E3BB410C5DD03FE4 +:10DAB000BD28923EEED0D2F4AF21BDBE10E91CBB12 +:10DAC00010FCB75FE07AF1D1BA6C7513CF133EE862 +:10DAD00021FBA41C9E0ACFB7D58B22EAA3FDD767F2 +:10DAE0006F9E06706FBD28E0B93287ECA7F54CDC5D +:10DAF000EBDB8EFA485D437CD1BD14F8B992F8F99E +:10DB00003BD48FC69F6B8FF0E77880CE3F393E9F26 +:10DB1000011F75211FBD31EEE4D7D18FFABDC0E3DF +:10DB2000EA0167E9662FF473FF1E89CEB5C5E39756 +:10DB3000D1C6BB04E0B76AA53E3C5FF0566D3A8D96 +:10DB4000BFF78BB45D98D47E2D7F88C679D4278AA1 +:10DB5000EB551AFF13D1F2B17FBA63C220D93FFF50 +:10DB600053381EED97DCDE8D81FF8EAF86BFF754F4 +:10DB700000F1FFC24EF80B7B3209FFA3B5A5B4EE4E +:10DB80002B257DE2467C603C2EB42F80EF5FE1F7D1 +:10DB9000A482C17CD40F26BE97AB175F1DA9175F67 +:10DBA0001D4B2FA21FE0E1FED127F7AB744E8FFC77 +:10DBB000A378FAE980C7EA5F5C867E3AE0A9B97289 +:10DBC000FD04743F8CEFFDB974671A5315F041677B +:10DBD000E0236AA791BE071D43FB64848BADC4C7D5 +:10DBE0001000293723BFAFF373B80A7C4CD0DF1D78 +:10DBF0008180275D8ADF7F5A91FF0CD2D59631282C +:10DC00005D49DEFD8391F3F3C158F3335BFAA8035A +:10DC1000CF6D9DAF1368BCDA4546E71E75A6A620FA +:10DC2000BE33341B9D079195C10E5C579BAFCAADA7 +:10DC3000A837F18CB21CB5DE90AA39991CB59E9418 +:10DC4000DEA058E04CBFC7D23EBB51B5D4E704CAF2 +:10DC50002DF579ABBD16B8A0B5D6D2BE28A859E02F +:10DC600062BDC1D2BEB4C76F81C7F5365ADA8FDF45 +:10DC70001EB0D44F08ADB6D44FDADD6A8127F7075E +:10DC80002DEDA7EED12DF595E11E4BFDB443BD164C +:10DC9000B86660BBA5FD35A74296FAE983BB2DF5B2 +:10DCA000D77DD06F81AF1FDA63693F830DEFBB1261 +:10DCB000F83E4C51954D7E142DF57CFD4967C7CB40 +:10DCC000A07E1133FFBC365C779DE191683F119BCC +:10DCD00067A37D1C3AFC87F6D51FB3BF49ABB6EEF0 +:10DCE000FB007ED8BF03DEF7D53AC88ECE88D93781 +:10DCF000E563252978FE74C62189E1BAEB7CE42B23 +:10DD000071245F31E03FE4AB4F0DBE1A392EE112B2 +:10DD1000E3D28EE37E34735CB7E2B8E0BBB7C0B841 +:10DD2000C251E3D28C7DDDD04F677AF1C8F1CD309E +:10DD3000F637C78E7306AE6B268F1C5FECBAE6A271 +:10DD40001C635D13FCDAE87352E7DFE6E7A4746C4A +:10DD500088F4D004D20FE719C813C0FE62B9555732 +:10DD6000468EC35CE7F4E94E2FD2C707FD84B002AC +:10DD7000730E517E904BB5CA5D62B955EE92BC9E52 +:10DD8000B1F90626644CFAC6E11315FE1B8D4F6EE1 +:10DD900065C01730AE5B812F90FEB7CA7F1E3DBFB6 +:10DDA0001343CF4F595D0AD246BB35551EED7CA7B4 +:10DDB000492F887B3A7232E3DB97DE9C2BB62FBD6E +:10DDC000397F9E7DD99EF315EC0BE8FF1D380E269A +:10DDD00007D42B895B76E78CD0FFBB732E276EC1EF +:10DDE000BC37E253B680FB65E07B71FF6B90F2DBE2 +:10DDF000AFE618F7B8C4895B5E35E81A895BCECB0D +:10DE000018B7ECB57D9BE213ED6B3C3E017FE0273C +:10DE100039E42F1AF14C90FB7917BC9907F028E8E8 +:10DE2000EF30CF97194D07EDE788FFE58EFFD0C89B +:10DE3000F11F1A6BFCAFB5F3FCC46B47F8B9FFD701 +:10DE400033A47026D0631B9B4CEB30E67A4B4380A7 +:10DE5000511EC4276FDDCD783EF338F6DBA0FA847F +:10DE6000BBDCF87C0D95F1F8EEDD9C2B8EBBDE8DD6 +:10DE7000C6FB0AF8EEDF73BE823F79A571D4068C2B +:10DE8000A3A0FF8E2E4E1FFD4C125F1731E2A90D8D +:10DE90001B8DF3B7ED3CEE49CCE574F883C12F6FD1 +:10DEA000E472BEF225D7921FDB252491BEEC3AEB3B +:10DEB000A0FEBA6D4288F1FC34CB85F70EE45C9D80 +:10DEC00082FEEA85C3FB33A2D7574E1B743811A1DB +:10DED000833317FA3DF3E0C9AF6747D3A171059DBE +:10DEE000F788D0C17A3F86397EBBD24FFB3B6E9418 +:10DEF000DC7C5F7719A3F3FEC0C9B7CCBEDA388AE1 +:10DF000003EF77E6EB0CF563628EC4488FAB7C3F82 +:10DF1000520FFC4771AAF4FD30EAC34F0D3B69F381 +:10DF200058CFCFB88C7D338931E7645CC6396CD764 +:10DF300025CEED96E41A7AD2CEB211FFCEB63DECE4 +:10DF4000B751FB7D64633D2C9EBEF4E6F2799823C5 +:10DF50006A1391BEE78C7D83B1EDCD76B1F43A3092 +:10DF6000F8DB4D9332F03CB648F30691AF273A5EAA +:10DF700033CB94DAA189D1FBEF52B58B13A3EF33E6 +:10DF8000486F6093A2E14CBF735274FBEC46C5022C +:10DF9000E7043C96F679AB554B7D416BB9A5BE289D +:10DFA000E8B5C0C57AADA57D698F6681C7F53658DD +:10DFB000DA8FDFEEB7C013428D96F69376072CF515 +:10DFC00093FB575BEA7FC406E7624A685DAE6FFE6B +:10DFD000AC42E0EBB34B3CB89FAA2BF376676014DE +:10DFE0007A9BE5814CCEEFF1EA4DF97FADCD1F9ED6 +:10DFF000350ECF41375AF44183A1170FB4ADA6FABD +:10E00000836DADF4FC7E633E713D1AEF1901D48738 +:10E01000903FB5B77D3ACEA7CBB81FE00321703F44 +:10E02000CA91ACB4D2BA057A529847BCE1227C2F8F +:10E030006ABC3EB6343C2B6ABC339DCB2DF5B39500 +:10E04000BB2CF50DC098D7422C7493678DE5F91C55 +:10E05000F521CB7BEDF92DDB51FE3678EC0CE58F0D +:10E06000F6A7D17E4BDF7C3CAFB101F755E682BD10 +:10E07000C99D311FF3E11BF6B478D08F31E91DCE75 +:10E080005D317FD60CA4F74D1E8C7F0FA4023D4757 +:10E09000B11F974BCF583A1E32D6EF1AECD675F90E +:10E0A000570DBD6696A0BFB6231DE71D913E09A87A +:10E0B00088FFD8798DD8EFC77E17F4DB0B28AFBF68 +:10E0C000073DBF8D8DD4EFFDB9FC3E8F0611022FA9 +:10E0D000F0971A6CA1063FE98356168276F2DBFCB4 +:10E0E000BC6157E68D5E3C2FF9A35CAB7D324B19CA +:10E0F000144B384A2F09C5B735A25E6EC8B4539E7B +:10E10000AE21CEFD692F19E3FEAA7CF2E7F3C70A20 +:10E110000B7F74E506E6E3FE8178FA1EFE0E1440DE +:10E120003F72198FDF81CFC3816A920BE33C62603B +:10E1300000E91D2B07B17633C8F8BE7DE6B61B7625 +:10E1400090DF1B78FE503A9DD78EC7771BDA1445B7 +:10E1500086793DAFA829B83FD3BCB70233B6D1FB0F +:10E160009BFFBBDA99B0B9AF30B67D10FF89F90BD0 +:10E170008F9BC645B798D1A1A34039EE8FF8AF5C0D +:10E180009ED7DE91AF5D403EDF91EFFF14E9C59C65 +:10E190008172A413C09FE373A60CC37FA07A0FC043 +:10E1A000987FC5FB672E63FD01DE6379D88F3CDC69 +:10E1B0008F9887FDB8793F00CB04670CC3766A9FC0 +:10E1C000CFDB5FEE77A2E6938F7B80DF4BFA89ACE3 +:10E1D000A5E0FDAAB70757903FB6347817953D6D77 +:10E1E0004A2AEEB37DB74DABC0FB2D6E5F3A4DC1F1 +:10E1F0007D2F4B57ADA0D2EC3F60C88BBD58A6FB1E +:10E200004EA462D1FF22E5F7F9BA9304EE0EA76B94 +:10E21000A7616F876623FF388DF3AF8175BE8A4E85 +:10E22000CB79AB5E86E374A9F21FA3E3AC9336AD62 +:10E230008CD3E5F2D675468E130402BEFB89BB2C47 +:10E24000A4131FD72BA3AD1F99E38DD77F208E7EFC +:10E2500030C76BD22D763FEBC6B27A3FAE8B4A8287 +:10E2600093EE9FC26B1B48AE929C865CF1F6CDD0BC +:10E27000FF2BC8A7B257453E6D36BE2719EBA0CD80 +:10E2800040BA756991EF9DB4F9E7205D46D0F1324F +:10E29000E9740AF5B00DE39C7E179D9F638A10AD6B +:10E2A000C71B8D7D53786019E9B9F1BB537721FD08 +:10E2B00036B6FCA35304FC56E4713DFB68C5F91A5D +:10E2C000BCDFF75136F4E02EF49BD725D17DC78D06 +:10E2D000CB3FAD89BEDFB779FF330AEE136E1CD793 +:10E2E0009989EB07CD4CFE24DA4F8CC5B331781FEA +:10E2F000F1A3DECED7059831AFCD3A3F0764C22BEC +:10E300007A002EC6788BEBE966C3CF34CFFF48493D +:10E310001976D473CB75EBFEFB153D569845FBA7DC +:10E3200052247ED3F190038EAB4B247E7A0E6FF293 +:10E330002DC57DD1612A7F87FBB93323F814AC1337 +:10E34000089F00530E6AC523F119810753EDD8CFFA +:10E35000E5E2F3BB7CBEDEEF70323D113E9D01B4C1 +:10E360001F40FAC87CDFDA936E13D6E970A9BF8C20 +:10E37000AFC3BA545E6FAEAB6707420CD76D13AB39 +:10E38000199D1311B11DC67D89031A9E1BFFE173F0 +:10E39000EFCCF74C80FAB28007CF1F007C44C63820 +:10E3A000560298F23CEF1C3940FB369489B84FD89E +:10E3B000D979ECC8A1EB19BF7289D6918E1D41BBEA +:10E3C000D567C2780013C6D397300C6B4E0FC025AB +:10E3D000C3B08EF04E63DFCA0F9F3B76A493AF3F6E +:10E3E000BC8C7AEF48A748F6C7C7924274AEF42FA8 +:10E3F000BC1EDCE759D98BF754EA2ABF9774236314 +:10E4000096F5F5E37976A27B4D41600FE293B46E09 +:10E4100088D253F61C3909F92B320F0344F7C83C54 +:10E42000F4F379A81EA07948AA18A0792852CFB38E +:10E4300012184F511D4FBBAB300EBA3FA25354C2FE +:10E44000F8A02C8DF016ABF9FA7A52ADA0A03FB42B +:10E45000C9D89F704B35BF7F4171F038FD17799C4B +:10E46000FF7F95C7F76FFD2A8FFBC529EA7ADAB7D8 +:10E47000E86C10691D3E054B77F4F83B8DF764435B +:10E480004F737AFCB42870222F2A0F02A39987F7C2 +:10E490008B398B33D2705DCCA7CA0F605CF9BCB1ED +:10E4A0001F0BE6E91F511F1DA94E4F08F0793B33A2 +:10E4B000EABC19E3BAD4BCC59B2F332E8E577FFB21 +:10E4C0005289CE358BCEC053B701BEF7EE49A77B3C +:10E4D000E94E344AD50300DFF7F36CDA0FF2691E18 +:10E4E000B7F3F78B4359A8FF361EDEEAC7D2F9EA25 +:10E4F0001A1DAF5BF840502D7AFCFE9FF9C85F5A99 +:10E500009F985C87F1682C1E27BEF81737CEC36131 +:10E51000BC77A8822694F291CD245C6CF83EB33B84 +:10E520000DDD9593CFF5E7DB865F7C421EA47CEF83 +:10E53000090FC4DFB46E6BBD77B5C52FD8F12AA51E +:10E54000E6C8739ED70CDADE8BBEDF62B9BCC08E24 +:10E55000DF033D63C957DEB67801DD93B2C288DFC1 +:10E5600041DF58EA57C5E43F973446FCD90BF4FF26 +:10E5700021A2C76295FB858BBD8E10EEB3BACD6F1D +:10E58000F5834FFE49A2FBF24EE0BB40EF134DE393 +:10E590007761BB587AAC1C1E3F8F0F86E9C3A82D4C +:10E5A0005BEC3F4BF4C07B4124EB7969A2C7A5E843 +:10E5B0001060A937E26BB17458B118E8533272FC9D +:10E5C00027643FD1E704D007F31FB1F4B8519A672D +:10E5D000C375FD150B04169D3F31F18DA5572C5DBC +:10E5E000C0FF3C9108F4F8ED66BE5E70DC18B7140D +:10E5F000FE3F344E3FE6A5151AC7397E4F8462ECC4 +:10E600000F506D1950BF0A8888E76117A1FDB0F45B +:10E61000EBB7635EBD25C0F7218EB02352D3C1E8AE +:10E62000BC4DECFD26B178C68E63BE612F46DCB3CF +:10E630002687F3D15F589A6FE46DA658F3DBAC3AA6 +:10E640007354BD6BE66B22F2CEF9AA39B8C0120F33 +:10E65000092C300C2B601FD77A2415CF731F6BCC7D +:10E660007C0AD5D442275FDF63D23CF2A73E5D2708 +:10E67000D0FD300B995375C37B770393E1F8FCB35E +:10E680005C049BFD9EEFFD98EEF7D703AC15CFE53C +:10E69000AD85EE83559171AEF5D8E93BB1FE49ECFD +:10E6A000F88391714FB992717F86CAA506F3AB7C4E +:10E6B0005FCDD05D8CEDAA8CE45959BEC6FDD72C38 +:10E6C0001EBF6DCE4F35F4722BC56997916FDD9CDF +:10E6D0003F4ABED5CD066DF8FE9D4E7798F6A10453 +:10E6E0006D1F0DF381651F4A807EE7A33BF71BB4C6 +:10E6F000EFBB3B21790A26CB7BB0C9748A43BE9716 +:10E700005F83CFF9FE24A6F2F36C09786F8084FB57 +:10E71000C0C07F8FA2D3087B7C60E5EEBE0CBC47F7 +:10E720004EA6FBE045E624FB1078480871BF4EED8D +:10E73000DE5B4DFE2EED3B6D0EDACE47F717482A15 +:10E74000A37B7402C540904AC47322C1928F0DE12D +:10E75000267456CEE3A5E1EFEAF07ED43A5300A743 +:10E7600019CFF93A9D591447F544F55F32DAF7406D +:10E770006B8D91B78AED3FB6BF6E631F66B7DD3B09 +:10E78000A0019EDD6F4A95ED8CE389F1E64F0DBF48 +:10E79000D5ECAFC599AEC851E7EDCFE5B82DE75D33 +:10E7A000CCD27C6F787DC1F4CBD89AA3D17E99DB93 +:10E7B0007EF7518B5FC6EE3EFA55FCB273F9771FB8 +:10E7C00045BFECF33337D1FACAF956505495917DD1 +:10E7D0005232EE8B8371161AFBA498AC4E403A3B32 +:10E7E00083799671FD2E5F25FCD3558DCEB54255AC +:10E7F0003F86B4E9B2977EAF639B791F80B1BEB20A +:10E800002D5749DD44F71CF17D5872A322601C6925 +:10E81000FAFDE6F7CDFED3CBBD02DE23166F1DE376 +:10E82000F3FC2B5EC7F87C34B93A2CB4BEFB1D5CFC +:10E830005F7843A2B86799E7217A1E1B570B05DC66 +:10E840001F3B2B0584824CCCDFFF72D9B731CFF54B +:10E85000AA83F2CDF77EEBC3C76A54A413CCFF346E +:10E860008AB79FC2FCBE344E24FFBCA780E7E7A452 +:10E870007681E2C28DAABDE15528DD79BE2905D099 +:10E88000AFDA107C17EF3D3E5FEEB7A15CB9F366DF +:10E89000D1F3F3E57C5FEA794F8217ED94F97E7747 +:10E8A00002BFD7B6DBF81D18B580FB7F6A01A7A7AA +:10E8B000A780FB473DB640796B05EEA7176892CC61 +:10E8C000F13B659DEE87705E94E9B92408142F76BC +:10E8D0002704CA1F8CA29BD9AFF322288769A3BD46 +:10E8E0006FA7E7381E7A3FCD7ADFEE04E3FD090615 +:10E8F0005ECE8B89F4BDEE34C0CB1DDD4F327F2E52 +:10E900008E7E9E785BFECCC94877779E36A580E2E6 +:10E9100035431F7A0E9D12922F472FF2F5A5010F56 +:10E92000B8FD38DF606FC6817EDE547EBE8BEB2380 +:10E9300027ADCB44F925C6BA3FBFD7A619FF45FD81 +:10E940000DD9AAAB713592A9CF7A47FA31EF6A1780 +:10E9500070D96EF87E1AD35F04313F88FB1E7E6348 +:10E9600080CBDD6537A21F7B6B1DF79356A09FC43C +:10E97000F5A5C5AF89F57FDC2CA0E03D42AB3CB2EC +:10E9800082FE44AC1FB4495B44FEC226F017F0FC83 +:10E9900052AC1F64EA9BCD4191A13EDB526D23BF77 +:10E9A0007E4BF9E01B37205DAA6595F21AE5038BD3 +:10E9B00067527D0D7DE72D7C753AB5E7BFA3E44D29 +:10E9C00020FACDAF79877E1FC19CA72DD5E726A061 +:10E9D000DDD969CC23DE473B3B2B8A0E8CFBC9ABD0 +:10E9E0003CA522F94B463EE4C0C309744FFABB5E16 +:10E9F0007708F3B9B38DF5AE155B245AEF5A517908 +:10EA0000DA87E7A2567409E45D075AFD29186735CD +:10EA1000AF5B64C7FD0B4A8BBB15F7023507ADFE34 +:10EA2000536CBC0E1E05D1A705E8339ABF15EB5FEA +:10EA3000C5FA0D6D0586DF50C5AAD06F3866AC7378 +:10EA400099FEC302639D0BD8C3BE20CA8E99FEC334 +:10EA50001CB1BE1BF9B745E6EBD7AC6E11D175B64C +:10EA6000F4D11B37A0FC579794E078BF69C47F5B53 +:10EA700082BF7262FCB9E50B89E46BA79D91FEDC55 +:10EA80005975ED0BED80DFDE872766FF16EA9F29BB +:10EA9000B01BE7C2D4EFD5A17FF4A68DF4593CBBDF +:10EAA000E70C4AAC0CE4CD1514A834E72129E86240 +:10EAB00072949C2719E3C9AC1E124AA2E4FA078695 +:10EAC0003E4C5DC7E358607A2D1FE3B3B2925DB848 +:10EAD000EF17EC06F905AE62B50AF9C76CFF816065 +:10EAE000E43FF6F83459C5F53089BEA7021E685FC9 +:10EAF0008A8389049704D3A92C0DA6525916CCA356 +:10EB0000FA71C1522AAF0A16D3F3F1C1490497072B +:10EB1000A75139215849E5C4E075544E02BB82ED36 +:10EB20002A823E2A27076FA6E753828BA89C1A5C8D +:10EB300040A537F835AAAF0CAEA0B22AB89C9E4FBC +:10EB40000BDE4D7075F09B04D704D7507975F0112A +:10EB50002AAF097650591B6CA776D3838F127C6D30 +:10EB6000F0092AAF0B6EA5B22EF81CD59BF27714D4 +:10EB7000FF09F6F596D457147E0F7598FC9E9D718B +:10EB8000F4DFFB86FEBCBD403B5A501369B739A683 +:10EB9000BDD9EE5C81F59CA5E80C3B4B299E2EADC2 +:10EBA000C2787A27C87F3ECCCF7DE34AE85CE29901 +:10EBB000026E4F5D365DCB2B8EC4CFA9B3F839A161 +:10EBC000FBF6ACE1EB0DB5E997958F3952C0DFDF6D +:10EBD00029EBE41FEC6C65740FB3AB6C4040FDD0C7 +:10EBE000E791E9F755EC399FECC575FCF9355A35D5 +:10EBF000EA43550F501EE7566D26C15985FC5C70DF +:10EC00004D81F67B949BA2EACCB9B84FA2A853C41D +:10EC1000701AF32E3E84D5594C09B348BEA32FC1B8 +:10EC20006A87920B4D7F6BF0496CBF734A5915BFD1 +:10EC30009F889F2BDAFC7009C5753BED6101EF7D64 +:10EC4000D321B078292A4FB9B3BBE565F4E74B7AF5 +:10EC5000BCFBF077D08A74EF34C42FB9D04EF815CE +:10EC6000F7AAF52EE8AF74BBB6CF05CFC78502F57E +:10EC700009008FDFADEFC372427FA83E11CA497B06 +:10EC8000C2FB507D4C0E0FD6BB019E7A88ED4735F6 +:10EC90005039A0CE4C0278DA296D3FBAB535838160 +:10ECA00099C9384FF6504732E0B3F337CCDB0E70DA +:10ECB000ED47BD12B8F391F9073F0BFD1D735E9C44 +:10ECC0006AAF86F4CE7F40A1BCC94E79D0955A3147 +:10ECD000727EFA70DC38CE20BF2F225F1BA2790033 +:10ECE0009EA8D2691EF87DF4B76AFC5CF5B58582F2 +:10ECF000390F8585F87E82E2C3FAA1D94CC17B2FFA +:10ED00006FC9E1BFAF90D85542BF1364F21DD077F1 +:10ED1000C282A4E879E07A60E7B07F38367DAF2D13 +:10ED2000E47AED7F9ABE6F203F67C6A7EF2D46FCC1 +:10ED3000792939BEB990CB25C8F14D48C778ED5A2D +:10ED40000D3AC5D279A7AC4C247AB999A857F27379 +:10ED500070E83FDD6DF0F7E5D275D5FF2774AD2F74 +:10ED60001C9BAEAC96C7E3E639E578FA66B331EEA4 +:10ED7000D1F41CA3BC61F12ECC2F3C6CD075E31EEA +:10ED80009E2F34F59CF3555F384F8DE8B91B0B2F40 +:10ED9000A1BF0C3DF328A2303D3A4F3A7917FA5300 +:10EDA000DDC677CEE5699D38CFAC22CDE00F9E372A +:10EDB000754B8A0FCF3BB299FC9C37F8819DE934A3 +:10EDC0003F6A15BF2E9091FFB3B36A22E5118AC145 +:10EDD0005F90ABE8B7A6C25826552B229E2337F783 +:10EDE000C13165B9275ACE4C7B1E9143931FD2FA8D +:10EDF000F8BA7298E2D703069E917EF87A49F743F3 +:10EE0000B996759A3E6F2EBD67B68FC7B7E70C3DB2 +:10EE1000D1D7799CE89854C7FD8394CE34E2E3942B +:10EE200059013CC11D75DE3360C7FCE26B85D2150C +:10EE3000F1EFCFFF87F8F709BC50A706F3FE0AFDF4 +:10EE40005E5011D81D15EAFB20664FAD46BB662704 +:10EE50007F5A657CFED43A16C2DFB9017AD13939BE +:10EE60005DE4BF3F0AFC3A9BEC8C3D55C1F93F97EE +:10EE700017385C58135F0E9444B51227F3CCCEFBC1 +:10EE80006E75E7E0F94B2501E15F01BCB916CF894A +:10EE90000E32037EDC3DFDCFCF0F9C29BCF72DCC7D +:10EEA0000F6885DAAF0B6BF83A0096DA7885F6BB17 +:10EEB0009A7C7C29FB6FCA63447E944A537EF01E81 +:10EEC00038D07FFF1E2D17F1FC995D865EBB6894DC +:10EED000F1FD9934922790732E3F06FF6F0C8F2D12 +:10EEE000E726BEEF5F42DE37CEF9958EADCD3CA66C +:10EEF00033265FE1F274D3EFE2BAE6B1B38E29E8CC +:10EF000037F33CE63D98C784F976963963F2980268 +:10EF1000F9F366FE3276DDD9CC639AF748C4D2396C +:10EF2000B5C8BA0F16F5D12B51E3E95DCFF8EF98CC +:10EF30001E95689DFA82267E88F6FD4235100205F0 +:10EF4000D03837320F5F21665518EA1FFC09528C02 +:10EF50006BD977BD4EBC1F74DE1F05A6011E87FF4F +:10EF6000285129333FE531E77BF7E633B0737B2B3C +:10EF7000FF251FD7C50E9F0518F03850790DED6B92 +:10EF80009A77647F3EFAB5B1782F092C1F75FF6818 +:10EF9000ECF8972C7BC78DF3F39C52EFC4FB69E32D +:10EFA000ADEB4D2FB21B7E49605A1194492B873A25 +:10EFB000F1075B3A1591D6F5CCF5AA1CF51517AEFD +:10EFC000CFE5DCC3FDC65C16A2DF1589E5DB9F1625 +:10EFD00005AEC77E9E8BAC9B1DBE2A7ADDECFEDCA7 +:10EFE000BA7AE8E099E175B38017DB6BE9FD95C863 +:10EFF00067CF55FF03DD6730CF0EF129D279DABF35 +:10F0000066E0BA7953CDEB99888F99A78E1DBF9989 +:10F010008F8A8D37E71759F3D417BCB7A58449B742 +:10F020008C9EA736F36466BC89793065143D1D4B10 +:10F030006FF3FB4D028F2F998DDFCF7FC4A037E890 +:10F0400081661C27EBE4FB88348740FB882E785FC1 +:10F050002FA3BC48F5E871C1705E9C85C78DB65E74 +:10F06000D814675FC68345DC8E34D978FE4F58F3D9 +:10F07000FA4AC4ABA9D225607C2CB3211BEE075FF2 +:10F0800055C4ED51B37723ED5F8DCDFBAF2AE2F18F +:10F09000E63C7BB84C31F282DE51E4291E3D4ED96C +:10F0A0007AE7E3774FAD9218C6DBF3965F933D5650 +:10F0B0003EF957C817E3707F18B713C3F38587FB72 +:10F0C00046A18FB98F23765D65B87EB98BF2C7E60E +:10F0D0007E0EF3799F419FFDC6F899A3B71CC787A1 +:10F0E000FB3B502E2F775F476CD90CD3BFA7EAD2DA +:10F0F000FB3BF617717D19BB2FE428E643C645FCA0 +:10F10000A25B86FD0F6B3E648E58FF83A29AA83CDB +:10F1100048C542BEAEBCDF25EA80AFEBD8B85DF88B +:10F120003B66B718FB541AC7C9748EA5F11DC98B6D +:10F13000FADD15478ECC7D27269C785160A1283DAD +:10F140009D28F753BE31F1A24CCF63E5AD03E56DC9 +:10F150005244DECCF989472F737E629F9BF313697B +:10F16000F74C39AEE36F4CE07631B6FDE731ED6335 +:10F17000D7A7CD75D9D8F74E1AF37F21303D1BF5AF +:10F180006FA35D1F7739F26ED2E9C417DF53B05F0A +:10F19000D71FF8FD93E6BAFB2DD569B4CE7EA251F8 +:10F1A000A2F580A4C94A1FE609068A78FC62DAC182 +:10F1B000D8F5BB66A6EF253B68CCCF2D6807CB23DF +:10F1C000EB7989D51C8E67074DFC2E771DEFE398F0 +:10F1D000F91A5EC78B236FA69CFDB488F17B482E7D +:10F1E000B11F61899DEF5B8E7DFEC630DD9FB9ED5D +:10F1F0006AF8D4FF05780B5C9300800000000000E3 +:10F200001F8B080000000000000BE57D097854D535 +:10F21000F5F87DF3DE2C4926C9CB4A02497813085C +:10F220000442C2000102449D1040AC80836CC14482 +:10F2300098B0C9122011AB585106420011FF440585 +:10F24000B18A7640545AAB0D884B157022CA0F5ABA +:10F25000AB4171C10553414551882C3A2E2DBF73E6 +:10F26000CEBD2F796F9200B6FD7D5FBFEF9F7EF51B +:10F2700072DF5DCFB967BBE79E7B67517F8BCA3476 +:10F28000C6EE86FFFB13E1FFF9D6C0632EC60EFF64 +:10F290006C67967CC6A2FB5B1E5D0EF9F7CB0F8FE9 +:10F2A0002F86F2F7FB5B558941FD7C2B6350EE5FA7 +:10F2B0002B07B2E0C3E8FE9087F2BBD7F709C8502E +:10F2C000BF61290B5658B1DE722BD68BECC22AE5F2 +:10F2D00038E837DBE90E423EE21DD98DE346FC6398 +:10F2E000922D08ED22CA9D955B54C6DE807633B21E +:10F2F000180B963F5189EDA6F770C6D9A1BFB11E74 +:10F300002938CCC1E8EF3CFCFF9A8288E0B0EC964B +:10F310007CC9E205C161FD18B33177F238ECFF6EAC +:10F320002B5B03FD17E7144E1C0AF94FD65A991DA3 +:10F33000F24CF235F7A375C1FF7A62862733368522 +:10F340003E30D6B8B432380CC69FBAE4A83503E6CE +:10F35000A57694596C0AE4175B3F6D348C5FEE37E9 +:10F36000E719F3EE7B18C699566057D7001CD357A0 +:10F370009BCB6732E5D3467DBE004F04223195B169 +:10F38000C51F1DCC7BD50047BE169DF8790EFC230A +:10F390008FE59D97111F2FB0A3309F73AC30761C63 +:10F3A0007C1E0313AE73D2646D6373A10DFE5DC149 +:10F3B000D8F74B1BF25E057C5F65193A44EB0FF3FF +:10F3C0005044BDAEE3699CE29C5DEC53C88FE904F8 +:10F3D0000327C13A2E9D1D1C06F53F10F01ECE5E80 +:10F3E000FBF02B00EF619F9DE672F8E7275EC3F507 +:10F3F0008F9823B1E5B44E766F5DAF96F1F4F4B615 +:10F40000CED05F7F6CE16B5E0FC4EB64DF9CE63CAB +:10F410005463A5B3AB4CEBA5B7D7E711DE6F737997 +:10F42000F96FB33598F79D916C765BE39FEF6C2392 +:10F43000784A2446F363760FD1E19D77F4DEE20744 +:10F440003CDF39CD6A41BABEAB216B8B03F207C4F6 +:10F450007CEFEA75BABF3F1A52D6F4EB2D48F74B52 +:10F46000A2D963006749F9B9FECB0C789DBAF7B70A +:10F47000AA06F992AC15497E27966F70633B48B790 +:10F48000F9E17B44F7C8CA008C3B9529679BD7DB21 +:10F49000D5D25E1F2F2A24B3403FE3778D7F57EAF2 +:10F4A00098EAC4721B95FB8732CE579F4A816A68DF +:10F4B000DAA393E7D7B89E9775F2DC8CE95B1D3D24 +:10F4C000B768492DFD545B5909C22D5B986F7B2F9E +:10F4D000A2C3946BA35BCA1FD1F87AD714F17AF553 +:10F4E0004903523E83B4FAEF7D52AC30EE039A42A8 +:10F4F000E5AF460F886D6C0BBF225D27E8E4AEA533 +:10F500003E4A63051DDE2DD60F48DEB31DF235568B +:10F510006F4A9CA19FDBB538EA3F66D08E864CC00F +:10F5200073B56A51250D536524E26D855319B9955C +:10F53000DA71B86BA23D8FE1BA41776C4234B657AD +:10F54000084F8A53F9D1C84F8F202FF76F812B7C3A +:10F55000BE8F68161A776827CFC388AF6F3A7A1EB6 +:10F5600041FC2D56FC76C4F76207CCBF8D765B0557 +:10F57000BE6EC2FE937034A74AFC88E3CAB83E95BB +:10F58000BF6BC4F559AEB06A483746DDF14423C0BD +:10F59000B518BAB543AAA8500EA94371A820E158DE +:10F5A0007C67DF9F70DC5B64F7711FC155D9DB0B93 +:10F5B0007453B6F83692576A029BEA75B69E47199D +:10F5C000AC27E2F745319F8FACC174C4EBD0CE437A +:10F5D0005F34AE7F73FDC577507F9F76F29D488381 +:10F5E000F2228D9D0DE0708A4FC3F156E3BF076193 +:10F5F000B9B71EE733A9C6E2473E2962D10109E740 +:10F60000A5C5939CD8CCB41EAC4BEBFE01629AC747 +:10F610001B8CCB2D4F86673FF603FDFD05E7E3E925 +:10F62000AEAE40B9CF0A12689C988BF403749E5D0D +:10F63000E9BC383E9993E3D36673905C057C1ED693 +:10F64000685D2A07225CBF149FC734CE8F067C1EDC +:10F650004338DAC3E7F71F77F0209E4EBB999BF53E +:10F66000699F3F1C8B1354C5C0DFABE3CCF358D963 +:10F6700097E79BC4F877A459385DBB78DEB1B8989A +:10F680001D05D4D91DCC1FD117F2A39807F9E35E4D +:10F690009B59EE29AE68AAFF73C650C5057858E994 +:10F6A000924A10AE95713CD5EBEDD68A1417D4FB77 +:10F6B000A7A01FC5C5E9797326CC03FA8B13FCAB51 +:10F6C000D7DF27EAEFD386520A04D103F16A93E524 +:10F6D00036F119E1E2FC75228DF73B427612FF4EBE +:10F6E000BF5B0ED825E2DF31C307B4E8D5E9BB1B09 +:10F6F000AD19589E2A333FF00513FA5485FF9DCF6C +:10F7000044FDC8565A608EE5BDBCB1C1B6F52BD9D3 +:10F7100009D37CCECA36F5EB47B7FA71FC37063110 +:10F72000554A6DAD6FC3F5ACCBD5AC67DDC8D70717 +:10F7300051CF5A5BF4EC58C6E5C305F46CB6CBA8C0 +:10F7400067992FDB28776B3AF1756D8CE4F80EC75B +:10F75000DF152EBE2E6B191B89ED519EA2FC8E97D4 +:10F760005925C971E817E9EEDE8E1D37AF910C748B +:10F770005802E6571CB6E7F84F1074A380988C8D9A +:10F78000473AEAA42A980796C27C82E6611668077F +:10F790009FEA54C05B82E296DCD07FA3ADB1A603A2 +:10F7A000E0ABA907736F81E13A94A9F51DA05EE46F +:10F7B000308DC91AD2158B29C0F23E16F716C8C76C +:10F7C0008D57575A211FA7B1785CDE46FF380FE2EC +:10F7D0007B6D095365E08B1B5C5CCE4F5DF22DD9D0 +:10F7E0008D4985008A86F2441D9182FC5DC2DC8FC2 +:10F7F00041BBBFAD58CE320DF82811F41FAB01BD8F +:10F80000031E1C1AA3752C62E99B65C9588FF3CBA4 +:10F81000A79D3C93387DAA91DE68A263D2F7CCED18 +:10F8200024BBF51AD6A830B2EB1A1896DF91517C9A +:10F830003DD6D7F968A585CDE67AB2D2CFF1ABC671 +:10F84000ADA14E54C2AF02F85D43F0F0F174FCEA92 +:10F85000F348C8764B2AB48F2CE3FC19BEAE7E0168 +:10F86000CFAA4E9E0AE44FF6F3F9F332F08143F04B +:10F870004164997B36D9BF2CC62DA1DDABA9CC0341 +:10F8800079E690C88E766895C4471105EE04B49762 +:10F89000D90C0B53C03E2D16ED3D254CFA1CE858F3 +:10F8A000463A2679AAB0CF75BAC68F1EF7AB01E8E3 +:10F8B00077F8A218F71AE0338BC3E743B886A58020 +:10F8C0003E42BBB36B6511D2C36B53791FF7023E47 +:10F8D000EADAE0EF13423EC5CBBE14D821C0DF9B6D +:10F8E0000DAF16D27AF694A05FA7ED40C3FE7494D4 +:10F8F000F3F0D711FF73A0C1E3C4723DCF820CE6D1 +:10F90000B539B239EF71A490FCD1F37ECC3F02C37C +:10F91000B0C190BA0E34AC70229D5FC9E9BC12042C +:10F92000431F037DE3FA005E324A185B968A6083C8 +:10F930007C8A6EA1F796796B7CDDDAA17B5D5E81B6 +:10F940003CB16AD0DFFB326BC2F59EC056DC8EE361 +:10F95000AA0EA6DE05FDFB7F043C3B5AF07C6AF74D +:10F96000A4D71E82FA2BAB62DCA8D7AD4339DD5990 +:10F970007F131BA826BD1EA07125964D7435BE446D +:10F9800072AFA1E5695A80F9C9BBA2D4352EECE764 +:10F99000BD74B41B3FBEFD4C3483F97FA23445E3F4 +:10F9A000BC8E2F793B1AF1F7F11299ECA22912D7EC +:10F9B000D75397FE63C034C80785BC48CBF43CEFEF +:10F9C00032E82BB63889F4F19C00CCD420DFE66D08 +:10F9D0008B1244C7F3F3EB124C795D0FCFB7B34AE8 +:10F9E0005CFF797FACB7758279CED916D707613EB7 +:10F9F0000E0204F17D7C67FA66B4C7BE17FC9096D0 +:10FA0000E9DD8FE3E3BC7CD0EE935D76162479D5F7 +:10FA100060654E2EF725A0771F1FAAD5BCF6EDE92D +:10FA20006443F93053624D76E23BB60FF1FA598ADE +:10FA3000CC905EC3E73DF363D586EB38B38835F9E8 +:10FA4000FBE03CA595B7E4733D80EB100E57B8DEA4 +:10FA5000985E576563486372AF1128DFCEAD964854 +:10FA6000BE85EB0F9007FB5E827E6708FD32B3D642 +:10FA70005C7E7AFFA27D0FA1FDFA828DECBA1B504D +:10FA8000BF18ECFD70FDF28DAE5F06B081E7411E40 +:10FA9000553B33637D17B0AF8F2F85BAB0F5FA6A47 +:10FAA000A983D2AF97AA943EEFD2689DE6BD50BF1E +:10FAB000AF13D153C300D4CBA30F143BAE83EC8D53 +:10FAC00029B2760CF963F3B8E0431AD22BE84F174A +:10FAD000F24BD08AFC610589E284796D00249C0791 +:10FAE000129255C81BE1AAAD7FED25DCFF00DC8F2B +:10FAF000B9711F9F65477AAD66EC2CCA1F7D7E37B2 +:10FB0000A6D8689CB2B07D4E38DCCE4C01F7408060 +:10FB10005B467DDAEB4D8DB50FB7AE4FDB83BFBDD6 +:10FB200076F3414FB665BFEB7CF2BCD08F33B68E17 +:10FB30005DD9112650BDFB8B8C4627513DD1B5BCFC +:10FB4000490A203FCA29C9445F0EA4C754C49FE292 +:10FB500017F049882F68F02E33D0F30DBBA2880E22 +:10FB6000523AC9CC5E805F387DCA1E902348CF4E82 +:10FB7000DEDEC11CCBD0AEF1EDBA9DD77FC9A6DACF +:10FB80005388EF522C9406532C0544AFC74CF4BA5B +:10FB9000DA9C073A34E54F5A1B33505E00FD1D33A3 +:10FBA000AEC349A9ED7D50466626F1ED0CCD33027A +:10FBB000F5D64CE65DA9129FD6D2F7E34AEDBEDB3F +:10FBC00090CFB74ACC0F789AFFFC53CFA17C9AFB19 +:10FBD000A70D31289FBE546A9371BC8AC76A623CE4 +:10FBE00028A7147F0CB6FF32C0E554F8784B327565 +:10FBF0007F80274602BDB500FF890430A369E56F09 +:10FC0000609CEF00CFC8E70B76FE40F97D1E4713DE +:10FC10004BC17E1B47E03CE6943B2B9741F9C21752 +:10FC2000CCFC37F7890DC95A34E1AF93C05F276C1C +:10FC3000B760ABD58D76E18243B21B8759C89A086D +:10FC4000BEF0F60BEB8EDA48BE5B5853DA90D6E581 +:10FC500060E9D890AF16B2B5DFCA7990EEFCF20336 +:10FC60008669981D395BC8E570BA9F87741FD542B5 +:10FC7000F7801FF273F9615E595829C0E574F5EFFA +:10FC8000ED1E1B7CFFF2830E9BD1AFF5F5D6BFC6F0 +:10FC900048BD5AF880B1E584BFAFEBBA5C505E9CBA +:10FCA00014FCD2AC0784FED15E80097680EC2E9ED7 +:10FCB000565883314300EE8ACD5637D27EC553B2B3 +:10FCC000C789F6D2613BD91B154F9D21FAAD903CF7 +:10FCD0004D521F022706E5B7BE6EF39EFA6C04CAAA +:10FCE000E77960B78F02969CFBCC395E1FE83D0236 +:10FCF000E5F1F6BF8FB80DF3203F1C6DAC5B715D75 +:10FD0000BDADD1D9C6BAD5FD7D04433FC4EFBFA771 +:10FD100075F9728FC43AB85AB79FFDD8091BF2EB38 +:10FD2000D7B0406A1CAEA35C6E8B6D6BFD82635EC8 +:10FD3000CCA77215FD7E175BC7ABD10EE94FF4FE61 +:10FD4000F48B30FEEC0FECEE5138DED38B6218D022 +:10FD5000C1174A25A7FB876B92512FCFB6FA93554F +:10FD60004AF9F7D98FFC9AE8F18683BF4E66644F53 +:10FD70007A522D240FFCA908DFCC4D1308BE59CCB4 +:10FD800047F438FB61D98BF6ED39858DDCDEC6BAD8 +:10FD90007E2BF8C6CEAAF27E837A0A7A5A03F07CCA +:10FDA00061636467F8DF92038F4958BEE58804DF1A +:10FDB000CF35244924BF0E5A1D889F9B76C7113D1D +:10FDC000BD96C9E55EF1C1732390BF6E7229957629 +:10FDD00095E037CB35585D65007E87BF4CECF7B4B6 +:10FDE000ED7AA87F16BE3FE836D5277C7DB1C51ECB +:10FDF00029F5863499DBD1F0F716CAC505BCAF16D4 +:10FE00007E66DA69845FEBC2E5F0C26D5F8C7810C4 +:10FE1000F96E9AB33216F073F6D0515B47E48B4417 +:10FE20000BCBC279357C4679E64ED2D0CFAAE363BC +:10FE3000E10B605718F977EB6761FC6B2E07FD4DFE +:10FE4000785B083B89358988B7A611A8CFFD30EECD +:10FE50006330CEACF550DFC0AF2D74616BF9EE6A44 +:10FE6000E13F2697C5A27D7383E0F7F0F50AE7FF2F +:10FE700013617A4F6FCF3671BE6F4FEFE9765885B9 +:10FE800035F038E2A9E2B0DD8D72B8E229CE6760C4 +:10FE900050366501DD9FF8E3DE77AF03784ED45925 +:10FEA0001347D1A866F93A7B07F029DAA3604745E2 +:10FEB000907CFD9EECAC9462D06B30FF13895E8623 +:10FEC00074DD8A3FE17B9BFC99C8487EFDC7E4EA6C +:10FED000CEBBBE9563DAE7C71BDA91ABC95D5AD9D1 +:10FEE00013B1300CFBEA0FF33AA37C0CC7AF8ED7EB +:10FEF00070F9B82353233C87CB47F87B9719F03828 +:10FF0000F7C96F48DE7D07F24E5651BF005DA3FE74 +:10FF1000867D02EAFB05816F295F837A8BF2F5E328 +:10FF2000A5BCB6E036E333BCFC30CA9FA496F5B757 +:10FF30002E67FE68E8B769B71CD802533BA535C5E4 +:10FF4000C4037C3511DC7F704A15F9383DCFA69685 +:10FF5000C33C4FF9F354F46F374530F2FF9CF2364F +:10FF6000C5C4A17F53F877AA1D67728EF503728C02 +:10FF7000F829E798619F541D2DEAA7F0FAFAF7BF18 +:10FF8000EF926334F40F04B85F229C6EC93284F997 +:10FF9000360ABFC570F9E7A7D17F77DADFD582FED1 +:10FFA000BAD32BCEF1BC921DCFD0CFC396113F1D3B +:10FFB000F35F990C73629F31EFBB43C8AEF2D85226 +:10FFC00001EFD3394AD8EC03D53168A7CBD1F9FB7F +:10FFD000D01E9D0508473B7BC6DA303B40D8B7B3FF +:10FFE000D65B5BE887FE1B20FFD00DC27E9FBDC99C +:10FFF0005C3E77D709A2BBB96174E76BE71C666604 +:020000022000DC +:1000000017A1CFFBB03E4877C365A705E9FCD47EB6 +:10001000EEDF3ABDC2CA5622BC7F94020CFA39BD4B +:100020004B26397DFA059E67FE24A2679DFE75FC6E +:100030007D8D74D9BD7DBDFEF5B31F0FB80DAA54DB +:100040003CF761DE43907EFDDCE16E2F61FEF9F747 +:10005000323E64ADEB17EFF9610ACD6B8F9DE1BCC9 +:100060004EEDF99F0CD4C7A75EB4D3F9DAA9E576B3 +:10007000DA37FBF74493BE3F95CEEDC4EADDDFE708 +:1000800035921C5F41EB53DB859FA39CDEF5D311BA +:10009000F44B9CDE65D7108E857BA2C85E5EF8624D +:1000A000448061FBDDDFD3BEEF3F05CF021BF7CB02 +:1000B0009E027ADC81741DC7FD5E0B5F1AF4E83284 +:1000C000187FFECE7ADB74282F7EF91F7928A74E81 +:1000D000EDA8B7A11C033BF811A4AF87BABC748F7D +:1000E00015D6EF24DA861D61AA5D7F1A8BE734AD41 +:1000F000F1C2F1700AF08070015E66A3FDDA1E3E67 +:1001000076FCD7E2E3DB29387EC5AE810CFD392DC4 +:1001100078913CFC7B7400F632083FFFBEE7FB3C65 +:10012000DC975F0CDE0684B7FFFF3FF09EFCAF5DFF +:100130005F4EEF3777E1FA2A9CEE5BD3F5F3375346 +:10014000FEE96837CDF712F93DA6EB7F2BFCFF37B0 +:10015000EBDDEBBF16DE8BADF701B1DED1AA9DFC66 +:1001600087FFC860BF00EEABBBFEB7F2F585E16E5E +:10017000B68B2C6E473ECCEF031698502491F54178 +:10018000764735A863ECAF61BC6B8BCCF720B41F0E +:100190001983FF862E1777E5FB8F6AF6E9B072DCCC +:1001A0003F813DF118F9B13F550E01DC0DBE42B261 +:1001B00013EC8CD3D5B944C7E3B89FBAC633CE7A13 +:1001C0003FDADD3EBE5FC1FC4EB46F07DB55CCBFEE +:1001D000B10CE603F5DF88B6A8D55AFBF81993B839 +:1001E000BF448AC13815F33EE5BAB0FDC6A4127308 +:1001F000F944B6254981FE27CEB6B280847E697364 +:10020000FD895D55826B12ABACE17E9C8BE289F679 +:10021000870D69DA16999F3FB39B019E095AD71B38 +:10022000D10FB3B52BDF7756B31B999648FE0ADA88 +:10023000673266A1F56A482C787C8D11BF7C2A0054 +:10024000DF774A7E22EEF718F96FC678FE41F994FF +:100250006207D9C97606FB473E6FD37E93A24B2C2B +:1002600018A6D182E7A18457AF7527E275905DADDE +:10027000769BDA13DCD59E7E0ECDF97F8FDFDBDA3D +:10028000C1AF9EF6624D53D0CE8C61316EDC9FC7FC +:1002900038D2989248CDC97F88279AE40F1CCAEAC1 +:1002A000C81F58A07CDD0C47269507D1CF555D05AA +:1002B000ED911ED398C6CFB1CB28CE40623E763E9C +:1002C000AAC5DE7CB300EC4D17A5C4AF6F6EE5F692 +:1002D000E5B9C26756F601FA43DFB77F00DAB5E247 +:1002E000CFDF5886ED646671E33E98793C9A3A0018 +:1002F000FBE57C115B6031ED83E33C9126FC248CB3 +:100300008C37E593BC1D4DF53B94649ACA537D3DF3 +:100310004DE59D66F735E5D32B079BEA775E3CD428 +:100320009477F97F65AADF65F5B5A67C56ED75A6CD +:10033000FADD1F98662AEF11986B2ACFD976A32988 +:100340009F5BF71B53FDDE2F2C3795F709AE3195D8 +:10035000F7DB7FAF29DFBFE14153FD81EF6F3195BF +:100360000F6AFC83A97CC8F11DA6FC654D2F9AEA93 +:100370005F117AC5942F627F35D52F76BC6DCA0F79 +:10038000573F34D5BF32E56898DF43F52F02BA50A6 +:100390002AF979DF55DA09537DD8A99521DD580569 +:1003A0003D5C9D7DC6543EDAFD93A93F1BC8073CCA +:1003B0003F75A07F18D2485647A99335507AB4AFFD +:1003C0002F220BF9E111FF4A24AA37067D9F817A7B +:1003D000E3CDC24574EE752E859F072BAC4941BA1B +:1003E000BEC6E1F4E3BE5FE7DB9890CC82B01F8D20 +:1003F0000D4994AAA12816847D695C2882D2F85000 +:10040000027D4F08C5519A18EA44DF9342A9942609 +:1004100087BA50DA21E4A234259443696AA807A573 +:100420001D43FDA85DA7501F4AD34243E87B7A686D +:1004300010A519A162FADE395444A916BA9A525786 +:10044000E82A4A3343E3A85E97D0584ABB864AE974 +:100450007B566832A5DD42D329ED1E2AA7343B34F2 +:100460008FD21EA13994F60C2DA27639A12A4A7B8F +:10047000856EA3EFB9A15B29CD0B5553DA3BB48C44 +:100480005277E82EAAD7277427A57D43F7D1F77EA8 +:10049000A17B28CD0F3D44DFFB877E4BE980D0A3B5 +:1004A000940E0C6DA6B420F424A58342BFA77470EB +:1004B000E8196A3724B49DD2C2D04BF4FDB2D09F64 +:1004C00029BD3CB497BE5F11AAA7D413FA2B7D2F88 +:1004D0000A1DA07468E86DFA5E1C3A48E9B0D0873E +:1004E000F47D78E830A523424729BD32F4774A47A6 +:1004F000864E507A55E84B4A7F153A43EDAE0E7D55 +:100500004BE9A8D04FF47D74E8074A9BFD0885D6D7 +:1005100030B9D82CFF2CE7D1DFE38C6FD3EFD6DCDA +:100520005EC8E37BA21EA1B8D5319512EDCB37464C +:100530009D7C95E4E420BB86F91AAC9ACAC7519316 +:1005400019BB1EFFA131563FC84EF6C31BB7F37649 +:100550002B8B8E7EB408F55F959D619C42B8FCD5CF +:10056000C77DB3606F12DA5D2BFB3656A01FE66EB7 +:10057000576319A6BFCEE2F6464516D7A78BB2B889 +:100580001F36D497EB93B2AA2CF2E7B3C44B83EB9C +:1005900019D443FD5BEACFEC29F2CEA60CD2179713 +:1005A000D8CFA5D6BB581CD6F71119013CEC2FC9E2 +:1005B000F2DD9945E73BE6F8AB7FA19F7BFF43FD6A +:1005C0003C74A17E98E2B18D06FD572AD6FD23AB7F +:1005D000B704FD668DE916F772F85493F49C7531F3 +:1005E000E4EDA9DCDF04EB4E7ECFC643B21B6D9574 +:1005F0006961FE5F7B85D9AF540AF2B208E8A3F4C3 +:1006000026F9EFF6BCD6E58D1E4674B6AA420AF06E +:10061000B8C6BAD75CD0BFCFE36842FD5F1A768E0A +:10062000BCACEAF974631CA6AFE28B8F104E9F3806 +:10063000CFF05D24AE695796D95F0A20133C1F02A4 +:100640003C782EB237E9E6FD0310BEBFC93C1E5A06 +:10065000AD4B277CADE67E54DD7F5A0EF2D903FC0C +:10066000FB61D273E9E80FDC3BFF9614B4CF57D59A +:100670006CB7E2B960637A1563D1463A0AF078A79D +:100680007466C378D9527F9582F46EB5B04DE4C7D5 +:10069000CE60149F63895AA2A1BE90453C9EDEFEA7 +:1006A000F26E9C5FF4F4130BC79B7F8144F6E82A3B +:1006B0005B65763CEF8FDAEDC7731180E3E83DAE02 +:1006C0002DCBA17CA4C21C4A5F93DD1849FE7C059A +:1006D000C634DA9DCC6C577E89CE754E3F142F748C +:1006E00054E27E51FC43FF3AB5C37822A5D2B30C45 +:1006F000C69BC154ED41D5400FB563E7E1FA7C22BA +:10070000E268F00FE37D4A916E00FFA54BA23C3DED +:10071000A0FCA4900B401F7EA33FD32A7138D87C45 +:1007200089F003105760DEBED69EB9C6659807D61D +:100730000339794D372E678E4A023FCB443B985F91 +:1007400011D215CE0FE353D279F9B1BBA5C0165E15 +:10075000CE52203FFD50478AB398DA61E5304674A7 +:10076000C8D0C7C97C2BAA8258EE83C5D1705FA4BC +:1007700030C506F82C17F15B6CAD44F15B26F860D0 +:100780003EC76AB6BF86E58D9296A942BF89DD2431 +:100790009D0E08AE461C1FEB2ADEF7DF83FC747F3C +:1007A0001CC3B8181D7FA56B975531A2EB3AEBAD72 +:1007B00048275F476BB84F2B15E34F95797C4A3834 +:1007C000DE90EF10BF1E818F63B747378F87F631FA +:1007D0008C3F05E31699E2A6F83D7DDE3A1DD4482C +:1007E00095419C8F5F62DAB3B8DF10F3A849BA99DC +:1007F000E13C8E7E13ADA1FFFF57DDE2393CCB6EAD +:10080000A1FDD0B1724D92FB98E481695EC870CCB5 +:100810004037E1F466B588F516FCA0F3814E3F83BE +:10082000BAF1381B3D2D11F03166388F93F1BB2A98 +:10083000BE73BABDD2580EFD5E9956C590FF3E11EB +:10084000F155FDBBF51AE787FCDB59A29D56998D42 +:100850007CAF8F0F7F1EE21341B776A7C3D303F09F +:10086000315C8C5F2381DC447ABBDB4E7410AE4775 +:10087000B2C5BAC39FCFA6CB5B0B7ED7E87BE95A44 +:10088000BB2702FA2BAD7DFE163C2FF954C42B601A +:100890002431AD8F2AF026E84A11E32AD89EC607F4 +:1008A0003EC0F5BAC7CECF41057D84E35797FB47DD +:1008B00070FFDB8BBC2024BFF7C62E94A6E1799E87 +:1008C000E83759C477D6DBA74AE5063974BBC07B45 +:1008D000126B3B3EFC7601A7478F0FFD19BE0FA0A0 +:1008E000FD3633C63B2F16FDE8F911D1162FFA69F4 +:1008F000AEDED876DCCAB1EE7C5E57AFAB3BFB1602 +:10090000D247A9CD8DF711EE5FC64C71BD8BC5F8EE +:100910004DA23E53E3DB3C5F0CD7EF4716CB1128CB +:10092000776B435F3DF927E83FDE6BA3D39978D619 +:10093000F8E49F90EF303E53433C9DA27CCCF8CC32 +:10094000BE182755EBE94B789B29C6D3FBDD5060D9 +:100950001989E7D97B63AF499D01F0AC1F3B4B9AE6 +:10096000619867B2124BF191F5F66B52678BF2D931 +:1009700050BEE7DACF73489F94AABB309ED4319E15 +:10098000D17DA2048DC7533A341681F571DCD98626 +:10099000FE12C6F3F2FA7123526742BBDAF1CB07BB +:1009A00061BBF5636D115D61BE1B46F90B70BE7ACC +:1009B0007D280FE2BE7CD53046F79BE2D3FA2EC1EC +:1009C00090B67865E97ED4BFAC90B9B3349C5F67CC +:1009D000C9E8F7DA20E0F48CE4F1A8AB34F3395835 +:1009E0006436D74F45D9DCAFF64A54E7255928AFCE +:1009F000C75B543CF625BEC7FE47DA88BFEF931AA3 +:100A0000FB213F15CB6A21A6FF4FB45F2F815ECC3F +:100A1000A7632221F7BD7ED4D3364DA944F96C6D6E +:100A2000E16707F94F841EA323E34C5339D1FD6BD3 +:100A3000DDE2743F05E90FEB305BA6F0DB90FEA032 +:100A40007630FE3D92D76F35C83DF817E9816420B6 +:100A5000688C83648A4F1A6BD0EBD612EF3C948B70 +:100A60001B043F017BA71AE3A13F10FCB421CD3743 +:100A700019ED60A6A81296DF27A912EAEB0651AE7F +:100A8000C79B03C14A646F887ABA1E5F7D190BA0A9 +:100A90001E5FDD2C17F8BC6D025E989707F11C2BCA +:100AA000F49B3EBEADD04BFAD736CC5F85E9BD1284 +:100AB00087C75FC4D8637DF03C5C31C9E7FB27DBA7 +:100AC000482FDE93AA06D06F78B2196FBE548137D3 +:100AD0000BEA5D3B6E45105FE9EA64AE472A19E216 +:100AE000E53E7D7E0A233C115A0DEB62F778FD331B +:100AF000C83FC4B4049069D6023FE9156BC973B707 +:100B0000A0BFEABE16F83C36844FE272D236CA461F +:100B100076C259812FDBB0E7484E86CF5FD72FFAD8 +:100B20007A86D3412B3D10965F37D6968AE3DD0F48 +:100B3000EBC3E3A4D9DA66BF1CF47DEFE87DB41EF5 +:100B4000AB1219E9D16555FF733DE26BFD201BED3A +:100B5000A7D88A947D5D0790E947F5578DBF96CD5C +:100B600084F2D505760CE5877E1BFCD311FF604F20 +:100B7000633CE111ED2D4F02E4D76FB2318C1BBE07 +:100B80000BBA457BF98DEE9904E7BA09CB1D782F96 +:100B9000C8D9C742D4B8DEFB6934F2E3CB421F0E9A +:100BA0003EDE501C0BE509A3D4BEC85FFAF741C76F +:100BB00082327E8F1FC9BF0F195D8BCE39C8FB49AA +:100BC000EFAD2B7A77F440F4CFF552E81CF47E2990 +:100BD000B85AC6795DC5687F173F2CA8E27DC6B8B4 +:100BE000343EAE675870E440CCDF243309EA3BBFA3 +:100BF000492C423FE110298ECF0BFF23E296D1E72B +:100C0000566D1579FFFDE36617227D071D08FFCE9F +:100C1000271E1CA780BE714ABCDCF3C4DFC6E17985 +:100C2000641CFA4FF2A9BD4A74C90E0DA7BC0F701F +:100C300002F50F581BC8BE38003CB10C487248F78B +:100C400078C28F25AA2C05F1313AC1AF607D5B31A6 +:100C5000635BD0AF287F44F5ADFDB44CA33D32A417 +:100C60003BD70F6B85FFD789F7E20CF26BA7906F2C +:100C70000F897A76F6969686FEEFF1360DE5C586F3 +:100C800022B3BED15367BECDE4278AEC65CE3BBA12 +:100C90009AF3D634733E28C6DD1B7B9E213CFAFDB9 +:100CA000B1FBC3E2164BBB73BDA9A72FDBB49B10EE +:100CB000CE9723A35166419ECB0BFF4945C84D7784 +:100CC000E138833CFAAABB4D8CB350423AD0F5FCD4 +:100CD00091C547EF46BD57EBD52C14D32DEAEB7ADF +:100CE0002D31EC3E8C9EDE21F4F8E8045F655BF765 +:100CF000606E13ED572E5D4CF7349BE592E8AFFF25 +:100D0000215F35C67558D3B4BE46FD5425DAC5E615 +:100D100078AABA1BE5E3DE08C9156DEC9FEB0B352D +:100D2000C5E7C1F84BA65E7B91FD3C8F5FD2ED9F7E +:100D3000F0F20F045E3D17B15F6AC5B8976ABF7CD9 +:100D40007789F64BADA8F793A0BF4BB55F8AE5C690 +:100D5000332EB4533A5B887F57A5654AE5867948B8 +:100D6000D91CAE47BB31AEBFBD4319EE8722C0547C +:100D7000C27DB6C5E1097AA0BD03F6DD68D72BAA0E +:100D8000DB939548728FF272A1EDEFB8BF3E2EF95A +:100D90001EC3F5904B5652BC92ECF4903C09E7937D +:100DA000F6E6FBEFF209F01FD9EBC1EE4FDC8772DC +:100DB000C3330AE048FC97E0D8D3161CBA5C7AA883 +:100DC0007B80FAD7E3D4DA8327DCBFB0BFBBB3CDD7 +:100DD00038B7F6DAEBFE8431DD19AD8FCBFD571550 +:100DE000EDF8FBDC0A433DFBD1E8571C782E79C6B1 +:100DF0006DA1438A23CC13D1D6BD414748669E04DA +:100E0000E02BF44B40DAA9BB46EBECD06A499ED804 +:100E100052B8DCDF1BBB8E5247B37DDFD944273A83 +:100E20005D87DF7FD3D3A5823F6AC57C47DA7D2506 +:100E3000A4FFD5BE26BEBB31CCBED7E954D74F2FB9 +:100E40007DFDE95DBD01AEE412AE9F4A71BE86FA3A +:100E5000C925EE429CF7153F5F1181F6D088D11667 +:100E60008A0F6D857F61EF2F1674ADCF27BCDE9A98 +:100E7000B0795FF1F32907F53BA8ED7E753ED4EB21 +:100E80001F090D3E8BFC1593C8F57A4C49E57ECAC7 +:100E90008F64A43FAD05DC1E2EEE7CA323B217E7C2 +:100EA000BFB94EE437BB89EF2E6F272EFF77C2EE16 +:100EB000057BF96799EC65A6A23CB4336F11DAA300 +:100EC0004C892579E1EFE1253B0BF49E86FBB207C7 +:100ED0005BECE512A3DF67F5651AF97D0CF68FCDA3 +:100EE000E8EF69CF4ECECED6FD3DDC4EB47A980504 +:100EF000EDDE70BB53B7AF9802F672626BBBD32ABC +:100F0000EC4EFCB30E30D8A9CC1744BB2146C4D15B +:100F1000C27C23BAA23D35C1E2C67BF4ABD03E4DC4 +:100F20006CB14F99E2A1FD4C4C6132F9E7EE95C0EE +:100F30000E25BBCCE7473CC51D8A64C8F7FF693B5B +:100F40009075E77E00B04753B1BD71BF66DCCFE955 +:100F5000F7D792C498F5A5950CCF61EDE33509F567 +:100F60005182D827D5FEDCA5FE0ADC878DBFB62BC3 +:100F7000BE17B1C7C2E384E3C75B24ACAF7AD442E7 +:100F80001FC76F2AFA2BF6FC18993ACB40277B86AD +:100F90007EDE0FEDE6D557D9E87EF86AE117F3FF5C +:100FA0001049FBFDE22E03528DE7BF3542DE6F286C +:100FB000F179D01FBFDA952C4D33F4776F36E79B6C +:100FC00075636791BDFB4AD45221C779BF6C05F7A1 +:100FD0002B86D3E922D1CE2EF0B17E8225C241FBF1 +:100FE000D1A112EE4B17654770BE5162251CD7EE9A +:100FF000D1F7A5EEC9B8DF2C2FE0D75F41EED86E50 +:1010000080F21BB32379BC8DAAEF7F18191BEB8AE2 +:101010009237AF319C2BDC9E2DF8516A4AC1F5BF47 +:10102000DFAAFB21BD57A17CBF3FA96B5FA48F75D1 +:101030009775FB2DE2C97A472ED9137ABBD7B37CBB +:101040004BB2619C4F864E7C7F06924466B70CBAC9 +:10105000F724F8FB63952928773F0621BB4CC2FE95 +:10106000BD5E74495A2FFFEED9191AB55F919D6480 +:101070006A3F85E859B4DF94E55D85E5F78D9E48C4 +:10108000F6E8861277EA34DAAFDA881431C2621AE7 +:10109000CCEBBEE18CE6A9C35526F8F7DE6C2E1F1B +:1010A000D68D5D9982F39A92CDE5612DD23BF2996E +:1010B000D817DEE75A49FD240FE37247B7DF609F78 +:1010C0004F711AEB2677A3780F5C4FF44B9409F815 +:1010D000A788FE37784EA7CC64483F6EEA571F4773 +:1010E000E7AB38B436208DC5F535D0F706A6FF69D5 +:1010F000BB9A900ED3D53E08478CA0B3B8124EE7EA +:10110000F5F6585ABFF5C3BDF4CE09F2C94C9ADFC3 +:10111000778497FA521FD17BB2E08FF85182DE4A72 +:101120006C812C97914F8666119F001FF8884FFAAB +:10113000523B7DBE09A31A9F413F4CFDD536F22B91 +:101140005C2E73782ED55EF2BC1241F394536C443E +:1011500090294ED5F238E60FC9814C18B7E89508AA +:101160008F28DF623CDF5A29E4EC8AA56083D859D6 +:10117000B37DA808BF608A9335F78BFD0C0DEB6734 +:10118000D55207D82E2DFDE8EDC9CFDDA575FB6240 +:101190006C9FDFD2FECEA52A8D1BDEDEDECEF8C32D +:1011A000C2C6BF6B698A68CFE1F5BF23F37D82E8D1 +:1011B000C7D14E3FC3C3E66155CD7112E1F38968D3 +:1011C000079E1161FD38D2222FD84F643BFD5C1978 +:1011D000065764D7F80BF613D50E5C4CF1A55C9B53 +:1011E000DB7A7DF5764E31BE7E7ED36CC7F632C794 +:1011F0007D7C42921BF6FD3DBC8E1EA83F154F1E06 +:10120000F97196F0F71ECA2CF559F89E43D9F220D1 +:10121000A5E1F438126CCE06F2A3B893516EBA2A47 +:1012200007C7A21E38B3B67F2CEEDB7D31BC5C5203 +:101230007C03313FF29FD307DAD016F9209AE1FA06 +:101240005DDF854DBD16BE4F95F83CAEAFBE6A243E +:10125000FA473AF7E0FCFFE6527C8302EFF13B9855 +:1012600007D6FF6DA023CCBF03F480F9F7966A94EC +:101270001E5E9A4DE9311BB7D3AE17EF45E03D3EF8 +:101280009C4F560F2EAFB27AE87EF79B5230BE6964 +:10129000E43FDFC6979258A2FFBEF1C32F63AC5163 +:1012A000BCBB728DC77CBFB564BCF9FE6AB97788D8 +:1012B000A99C65F76BC9935F8BCB8769ABE3B6E0FD +:1012C000BE62F2A80453FD89AB3B99F2853DB87C20 +:1012D000183BB28BE9FB756539A67C79082C128C1A +:1012E0006BD0522C7EE8FFECEB56BAEF78B672600A +:1012F000875B789EF47938DE8FE9F78DDE157C0305 +:10130000DF711DCEBD9FCE707E23FF2933B4D7D9A8 +:101310001FB81F7EFA0312F3C39459939FE2146F10 +:10132000DA6C7763BD190FC8CCD70F6723117C5FC8 +:101330001DCCDAB286D6D1FF08D66B827A782E64BD +:10134000895A4BEDBE8C601ADE379DDE28FA93FA7F +:10135000D2BD898FAA5665E078F393A11CECA56FE6 +:1013600046D7CEB220BDCAAF27E1B9E2373B648A87 +:10137000139D53F5CE0015F039775FDDBB05D0EF37 +:10138000B15A99A930EE896DF6CD3C3ED0D301FD1E +:101390008D2DF006287E3290E99D86F4FCD5AC4078 +:1013A0001EC57B2D49227A6E032FB3DE43BC5862E3 +:1013B000B4C720BD79BA7B22C275F33A6B9C5F3209 +:1013C000D2BBB83F24FAF1B3FC54BC27726CAD9584 +:1013D000EE4B02DF8CA173A4DA040BF7CFEE20FAF8 +:1013E0009AA668361C7FDA5A99EC09FDDD099D2F13 +:1013F000D93DB20FF65CCCBF5AF2E1BD15171219F8 +:101400008CBF283D92D67551D5C00E088F7E6F3C9B +:101410005C2F9C049EF119EEC3CCDDCDEFA3B17C13 +:10142000D582F718C6340C7F0CE7737A7F9758B4CF +:1014300063BE3C34CECAF1C6E348E754D7E7E1BB0C +:101440004E2746FB3F57207DCFEE5BD303403C9EAB +:101450005A773FDEE738B5EBD10C7C17A951BC5762 +:10146000A58FE36BE7BDAAAB2C436BB17DF3FB19F2 +:10147000E21E3B53028F3F88F6F2071D4C76440B69 +:101480007E97717CE8F541E4F17B77C16409F0E86F +:10149000D318DD732D6575227E8FE34FC34502FCA3 +:1014A000A91512DDFB996E714F791BF5F2F26815E3 +:1014B000D753EFFFA8E0EBC77B703B50977B9F8A29 +:1014C000FC74FDFC6E0FB71FF17E30FA4367138882 +:1014D00074EFD086FCA5DF0F7EB647BCD86F34D939 +:1014E0006E49C47BDC367AC766169E7A40BE629B24 +:1014F0003D1070E13B1C9CAFE7DA9EBABF2F5677D8 +:1015000055D2BDC7393B25F6A084F5378FA0F867C3 +:10151000C62A03F83E050B8C6880FC7C4DA90CA202 +:101520008732C0EF093B40A0A05CF1B3C0CA78E8A5 +:101530007FA6883360DBA0DC2077E6D799EF152FF4 +:10154000C4FBC4A67334EF4A3C8F9881E7112ABDCF +:10155000A762BE3F586BA57337FD9EB3372A9AE248 +:101560004CE7AEE7F1342DF391D979C0D92C5F6007 +:10157000DF188257720758EBF9DC80E325B6C07399 +:10158000B1F985CF67969BCB998A5A291068637EFB +:101590003A7E630B99867263DE5689FCFFC313ABF8 +:1015A00008CF7301CF09D0EF2CBF3766523EDEDB88 +:1015B00064417C4703D04DE50B37F17500C4BED5BF +:1015C00035B965BD3F4B6CB2219E3EF3392BFD789A +:1015D000EFA8F27B5AFF7DB0CEC8F773B6076CA8B0 +:1015E000974FB0DA1827F04DC50307F721D97EB61B +:1015F000FE9964B417CBE2835996387CA7E287F54D +:1016000023D35BE8704EC00CFFBC6DE67C387EFCDB +:10161000CC4BFAAB159E1C6B1BD0FFD36AFD443C30 +:101620002EDACA68E7CFDC2AD3F9ACA19EE93C7573 +:10163000B6BF89EE57CD0638AB55FCEA277A9C0930 +:10164000563AC6B9FED2F9B6A237B98CE8ED1CAC51 +:10165000BFDC16BD5DE27CC3FD55193DC53D2E378F +:101660007FE707EF0F4EC24261B784CB97F07B99BB +:101670001F8121B81CE6D57490DFCB3BABA8429FFD +:10168000660550A4B427776709BD3813F520A49FD9 +:101690003FF04C0CAEB7BEEE37A07EE9D5A25F6E30 +:1016A0009E1E4C47BAB9F9F908B71F871F157CE78A +:1016B00056C87FB35D666DC9C1A199BEC13DD13E1B +:1016C000117A72BEBC394345BD28E4E2C5F607FF76 +:1016D0002A5CD310AE7EA8F7395C9FAEE6F01C5DA5 +:1016E000CBE19BD10A2E3FDDE7B8F951BB1BFB3D97 +:1016F0001E1124BD7D1CE0AAA675E576C33907D06E +:10170000511FB20748DF7F99C4F57D337C37BE7720 +:101710004481759FD3AD210FEFFF95DD6327FD3E1B +:10172000E7D9683AA7FA4A2AEA40FBA357833188E7 +:10173000B7B93B38DE5AE6D3ACEF7D88B7667D7F1C +:1017400089F8C20005D48B0B187FE761C1AE0EF497 +:10175000CED1DA225627D33DBF46925F403A747EFF +:10176000CB5E30C737DA99DBE1C0F56927DE1B0DA8 +:10177000037C6F6616D60738BECBFA76CA8D849F77 +:10178000A66EC4D791412BBE5FD2B45DA2F79AE694 +:10179000DF541483AE62AB88D75DDA93DBABCB7BCF +:1017A000723927792A291ED7AF31751DCE6F138F55 +:1017B0004B67AFB03A3AE7DDC4E181BD38C1236978 +:1017C0002A2BEBCBE3FB1DA8DF9C9636FD2375622D +:1017D0009CF9B285ECE60A1BB79F4F897DC53A514B +:1017E000BEAE27B7A33788B8C553B01DA5FB77C3D6 +:1017F000ED01F43F809A9A8FF33B2859288E3E37AB +:10180000C7B7BE27D45B71D89E1504101AAC5A4DC9 +:1018100023ACEB8AB85974CF770A7CC1F51D5350BD +:10182000B50DDB1DE9C85499BF1FE36586F8BE37C7 +:10183000AC1F0DBF09FD465057863D4769C117E9EA +:10184000587F13E6010F4722EA86DF84ED5D0AC365 +:101850007B06FEDD76B207AC431BD3C91F18C958FF +:10186000751F8C07DD5B8374B52F25215B85FA53CB +:101870009548B7B86732EC5BA8A7CCE6EF87B01500 +:101880008DFD717D7AB3152AAE1F40BDF37CC285F4 +:10189000E8C9FC5E5305BE23349871422B20BC9AE4 +:1018A000F215365EBEAF67E984F56990C73D03D295 +:1018B000C15532C5754D286852F01D2324946B80A4 +:1018C0008E27054F2B783EC03C5A5D2CE48307CC15 +:1018D000EF455DA368F41E6B9A8755CA643F69C3E0 +:1018E000B1BFF773F8F9BFC4B2293F66248B277ED6 +:1018F00074685684DF3B52EA8B7676C5F24B9BEFD9 +:10190000273D67F1F95AF83D9DA65B791CD814A5CF +:10191000CE8AF162B14C6DF2C37A2C8CAFA3F9344C +:10192000011FE1B966A9D248E3A7CD66F1B85E15FB +:10193000A01C119EA6393C8ECDE2E0E5651A94C349 +:10194000FC1EF05992D10FF4714F6E9FCDD7F773F3 +:101950004A630DC50796F0F7BDFAC0F48CEBB3D01F +:10196000D6BCEFD3B0BF79601660BD79BB9ECFA265 +:1019700077CD24CD82E37F29E8799EC319C47315FE +:10198000F647335F47E159C805F8C191C3E7E5C899 +:10199000E17EA4B33DF57D651DE9EB79BBFEE77DF6 +:1019A000DCC7B6D7FF7C3B0B12FE76DB097EC9D2C3 +:1019B000D495DE3B63F4D204F69385F959209F70E9 +:1019C000FEB61C6E6FEA743D4BE8590B085FD4A35A +:1019D0003730BF6D908BEE471F33C6A9CE65B56417 +:1019E000A7CCDD6AFECE8C7A5A36C92D8AD3966C86 +:1019F0004D33707CE9F20837CAF3525B1DEDFF25C9 +:101A00009467D92DF22CBC9DB596DB6BD6B512D957 +:101A1000BFBA5FD60EF61BCAF7F234770A7F974239 +:101A20001B41EF530A3B7B169F0A7CAF30D9D9F696 +:101A3000CA2F3E207FFC037CFE8AB083A787BD9F10 +:101A400053BEDA0C9F9FB94BE81CDD69A3FDAD3D89 +:101A5000EC5D9D6A69AC1FE5BADFA5D03B12063F7D +:101A6000BBB04BBC8CC763F3EF8AB0373BE6584D35 +:101A7000F78674FEBF06EFAF1BE4AA77186397F7EB +:101A8000453F8214403AB8C653B49FA7CB8274BF77 +:101A90004961AC533CB683BD3FD5BB93E280811F07 +:101AA000FD5158EEB17E6584E74DFC471BEF285C85 +:101AB00091D3CEFB14850997F43E85FE5E6719CA63 +:101AC000E12E2DF1F16507F87DF8EF23FE997108FD +:101AD000F29A0408C960EC96C823AFF920DFF88FAA +:101AE000582675C4F7DC5E7B18E3B7CB9629B4CED5 +:101AF000653137537C77D0EE203BD93F34F830C581 +:101B00007BDB1C74FF6B2302978F7044F3FE2D8DDB +:101B100034EE54D67802E3A8AF4C6C8846B2D0E3DA +:101B2000EA5716F57B00EF83CF7972E704473A9DB9 +:101B30006F8BF88C3FBF83EFB78C477F17E55F9CB7 +:101B4000E0E90DFCF95AD31407DAB1392F4DC0780A +:101B50008D531B9A1EC1FC0339AFF1FCDD4D1911E9 +:101B6000947F9DE79789FED8EB13D0AF7BEAB73C13 +:101B7000BF00CAF11CB54CBC07573658A2F7E0AA03 +:101B8000841ED6FD61659657783A9405D16EB85893 +:101B9000BD2D39DE2AD48772F4318A87D99CEBA90E +:101BA00042BBE5961EDE5B73703F7928909C04E390 +:101BB000CDB5B006D49FFABBD0AB2CE6F742AB7ADA +:101BC00072B9A3A72B7B79A91F1D6FD05FF5BFD377 +:101BD0005F52587FBA1D3353F03DF4BFEEDFE95F2B +:101BE00097237A7F9FB49EFF43FF4EFF1372CDFD74 +:101BF000E9F6AE0E472EF22AD0DDB8DE5CCEEBF36E +:101C0000D1BFD748C1A449281F0EC8747E599394E8 +:101C10006C7916C77F3D81EE5B9EA91C186B817E97 +:101C200077093D50733BF72FD42CE3F7104E3C352A +:101C3000700092D60271BE7DA2FEB00DDF155A284B +:101C4000CEB917ECACB78DE885EFA6D4DB8A0DF6DC +:101C50006A45B35FA551C177476B923E57CA691C6D +:101C60008BF0372CBB601CC85F72743DC4E1CC1391 +:101C7000F01CCCF3ECCD31C0A97FD7DF990EEF2754 +:101C8000A617EFE751942DFD5BFAEB2DF1F52A8BAA +:101C9000E4FAB0FF21F7ACB7695F9D67C173CD016E +:101CA000EF57DA506FFFAEC7D083C6F1F4762DFE42 +:101CB000E226B3BF7817F717EBE3B8C5FCCAE21BFF +:101CC0006EC238F6983F366D40FEBF7A236B7E7742 +:101CD000125D6523ED7ADE3E71581AF76362FEDB12 +:101CE00027D9FD1817BD3FB2E1D76FA39EBD339A28 +:101CF000E13BF4D70F8CCED8918FF1EAB1122B646F +:101D0000ACC81EDD0DCFA3AD3D8A627A11DE18D9B5 +:101D1000E5D61EDEAF90FE1A5D5116300299CFC691 +:101D2000E9C1F71799DEF1F1E545F9D09FB7DFC2B8 +:101D300086B1F816BC1DCFE1F6714C2F8EB7FDE2CF +:101D40009D58F8CBD881FEC1E59D25A4637DDCE8D4 +:101D50001E45D1BDFAB78C1BDDC3FB634E7F63FD0F +:101D6000587A2FAABDF15BC9774127D1627C6F21D8 +:101D7000D09F414F5E3B2CCA941F3F2A81798C7EB5 +:101D8000E9F19D4CF992B22EA6FAD7CDC831958FC4 +:101D9000B637E41BED027DDD2E75FFD550EF4B4CC1 +:101DA000CAA7B8D526E42F58AF9D6331BDBF938A2B +:101DB000FE8879ABAF227F776CA894D28ADAABE841 +:101DC000F1CFF9A171945F108AA2FC9B72C308DA6B +:101DD000173D2FD1B902F47316DFF3D91FDF9761D6 +:101DE0003F0B766ECF3FC4ED2B2FC69B8E96DFCA7E +:101DF000473D34BAB36AA9C6F7C74211D44FC3D01E +:101E00000FF3B19F91B8AF80EF153B069520FD14FD +:101E10005547AB48DFEDF14BFF5E5C0E581BF97C7C +:101E20008787C6527F7AF9905E99A673186BD2564F +:101E300005F94487C3DA2851FAAB500EA50B778E0B +:101E400055309EFA2FD98F26A29E80FA4E4C5DDE29 +:101E5000219C5F40FE3067FBF8B50BB9532AEEFBBF +:101E600078F23C5EA4EF314B1A1507E2C169537159 +:101E70001F38A6A04FCA2C433FD5F59319CA297B1A +:101E800022B3A17E2D85B4D850EE6B27BE66622F9B +:101E9000B37C6AFE3D83577F4F87BD53544E333A20 +:101EA0005D14F732C7A135485CCFFA9FE5E70F9381 +:101EB000F37C7370BE0D45AC6407C98B860C8C1F18 +:101EC000F94FCD1F7AA6751EA3F2FD418CD2C83002 +:101ED000AE798198974E9F1783A354D47F53668B16 +:101EE000912EDEBCE28A06DCD7D4DFD6AF1F9EE39C +:101EF000C376E867F233EE19D205EDD03B7AF138BC +:101F0000C6D1781692DF62FFE3BB0DE81F59B8C750 +:101F1000BE45827A0B639ABAA17C8DEDEDBB03E5D9 +:101F2000C39B2FFF7004EF977B9CD114B7BA704FFF +:101F3000C4AB98BF5CA67066B02B3C4B498EB433E3 +:101F4000CF8BF1A1CB3B2F11F5EC199812BE577630 +:101F5000A6F2BD9D63315D1F45F1BFBED59CEF7CF0 +:101F600082FFCA05DD4E13FC57AED4117F4DC580EC +:101F70007798D7B425522EDEFB87C5A0787C2BD26C +:101F8000633FA44B4E8F15A138C1C72ED10FA7FBBD +:101F900070BE5C104AA07A3A7FAECFF33DC5E574BF +:101FA00043FE6218EF57AA85EE3DF996A7E6237F18 +:101FB0005C9C3E7E50F01E9BB550B2227DD8212DF8 +:101FC00036F0B3B7259E7D4432EAFB152E8BF15EC9 +:101FD000D38E5F48E7BF13F5A739414F921F29867B +:101FE000A17FAE2C49233FEB8D774A78E8C36EB4CE +:101FF00006B3D08F73635504F9D3661DAA5C19AD7F +:10200000B55EAFC9A13CA6019EC685BA52FABB1EF9 +:10201000BE20AE7B7968A2C063DE259D0FF6F77007 +:10202000FF9D3560776F76A1FFCE27233F1C4F675A +:10203000EA7DE4C7E1E5BAFF0EFD82E81F6C39FFD7 +:10204000F337FBF3907FEC8916D339652BBF5E1114 +:10205000D75F5F6FB5F277F0EADF1A6081F2AF5CAD +:102060001EF2EF05327D87118EB9D7069EB6427EED +:10207000DEDDCFC40CD25AF058A704B3D0AF555709 +:10208000C9F153B756A67B2AF01735D6782F54D806 +:102090000F0718B737C2E97A6EA80BE147D72BBAFA +:1020A000BC7E7E690A6D5675B97D317D335F69D816 +:1020B0007910F0337F7DACEAA777F90E9EC57712D1 +:1020C000F1C13CBC8A05FC43F2E54C1AB330837E77 +:1020D000192DEFC83F44FA47F556A39E291E5248D2 +:1020E000FBE13079FDD5B6B7A93D9EC1A11E1AFA14 +:1020F000E44FCF7C00DD5BADC16EF81EE0AF9468AD +:10210000B79FB5A60F5D0FEBF0EBF8F88BC89FCF2C +:10211000F5C4E55E921E88207BD5EE1FCB488E422B +:102120006A94A3D6303B55FF9E9CFBCBF843C93540 +:10213000EF07F47936D874BB89CFFFAF8CDB15CDB0 +:102140007C90776D2EC2817A01C7EF9BCBF5EF7F34 +:102150000EAEB6F543DF66F82E4D3F740E834F8703 +:102160004387EB7501EFA5EA8F2B736D226EDDAC13 +:102170003FA0DEE7F8BEDEA9DD3D549457B2D4F4AB +:1021800039F9937647688887375F8EA0FA1E472C07 +:10219000F9D58B5FFEE20CBE2B7D306FDC95B9D09C +:1021A0009F67975D61063B4E9F973ECFBF897983BE +:1021B0009E19956BB0EBF5EFFFAADE1931763BF176 +:1021C00003FC79AFB91CECFBBB1A48EFB08D512A68 +:1021D000FA65C2F9359C4FC3F912EC3E92ABFB9FF6 +:1021E0008BA373089D7FC3F9D3E5FD90F40CF22710 +:1021F000CAB73395F65C7C0FE88CC6F5EB68F47FC4 +:10220000229FE6C4D1EFF5EC95EBEE1B2CE1FB949D +:10221000DC3E1C2AECC370BD762CD77B07E2F38A28 +:1022200027D3F311BF17A7C73F5B491F554864AFBA +:10223000D82135EA235F3B7C56FD0BF9AC2AB7D990 +:102240004EE17656AC8DECAC8BD1DB86FF3CBD6DA0 +:1022500030D25B7BF6F483B97CFF09F4F660EEBF05 +:1022600065D7BC44F405F2DF8BFBA8ABFFEA8E45D3 +:102270003D8888C0FB06402FF9F83ED2FE01E96E8A +:10228000F4DB5C7D9EEF474027D17E247C3F502AC3 +:10229000E4B44FECE377E77977E77279F04784B7F6 +:1022A000A84B541FD4B7976AA796265632F43BF929 +:1022B0002035CA217BF3EF9498D7FD955FB8EE7572 +:1022C000A2FEA5CA97B7DA59EF0BD8A71FE55E8221 +:1022D0007DEAF238C6913E0CF2FB0117DBBFC80F56 +:1022E00070FC36E32BA8E8FA3E01F53DD0C5C7FFE8 +:1022F0000E5D8C2EAE3BEB80F5FC29F7C789E80715 +:102300009C88B126E447F8E97E4F5794434C3FFF41 +:10231000203F03F10DE57F7E7718E0F1EAFB58CB13 +:10232000F908940F2F8C6DF64B48ACA5FE8FB93F82 +:10233000BCBB96E6CDDF6567BE46859F138A7C3EB3 +:10234000E4A30DF982B0FC265E1FF58FF17DF71630 +:10235000FDC418FF9D13BFB07F9A46C4A1DDBA53D8 +:10236000A2F7B2AF2B3C6543BFCAE8E2C67D9DA091 +:102370005E749E3CC909AC79DD4E89E69BFE74E42F +:1023800046BFC2EF55C8D05F458114207F795DFDFF +:10239000084F1B7C999E67DE1FE11FFE8E4985401A +:1023A000BFBD4E62F80E3AF683718A97D21ECFF9FE +:1023B000A87D26B50FDA132FBDFDA4421EBF1B5EFC +:1023C0002F47AF27E221A97F58937175529BBFEF2A +:1023D000D24FD46FB058E6A3BD36E4E98C8DE86FD8 +:1023E0001ACE385D5CF674FA243FA73FE60983F7FE +:1023F00042F375B501AF666E1FBC10BEBAB76A2F47 +:10240000D67FB6994E6215EFAB67601EB189928A8E +:10241000F6F5026FC45ABC8C37BA58D0B53F7B92E0 +:10242000270DE08B6026FF59335DFB7B4C42BA5E83 +:10243000C0F4FA391B71FDBD1666BA1F397C97D4FA +:10244000DC3E5BA1FB7ED47ED2D33D37A2BF0DD64E +:1024500083CA29AF5C80CEEBC2F285617CC1789ED5 +:10246000F812E57101FF1D9D70FCDC28F0F38DB8BA +:10247000E7D13094DB8D0DE2F7B0EEC9E376E1AD44 +:10248000795C0E2ED3D7D9F0FB352CAD659D99F82C +:102490007D1B03DC84A7C989026EFFC849A300AE77 +:1024A0008678962B019DDCF5F4B08D2B884EBC0A06 +:1024B0009E5328FE111B5F07793259E0E59EA7AFB6 +:1024C0007C0FF1824712C85FF30BF8F9B27DE7C1C8 +:1024D00036F96B4A9ED9BEA47F00BDCC27C2C17617 +:1024E0009207EFD5603F996DE06346EBF69EB0F63C +:1024F000CC9AF84BDA8BF51815B65E23C3D66B5819 +:1025000058BECC9C8F51B8BC8A414480BD35ED8506 +:102510007B6A9213319E48A237EC401EDBF0770AAB +:102520001ECFBB76927310D2A566ED0475FF90376F +:10253000FE3D07D0EC589457246F276C44F93C0EAD +:10254000F99AF213277962914E2A6B52A07E5DDED2 +:10255000A48DF87B90D7ADB8C74AF776F3266F54B1 +:10256000609D26E7FF691FF6A748A5EF8D725D8085 +:102570002E6BC3E0D81496F787D55F7F11F9BD2283 +:10258000ACFD92B0F2B561F907C2F2ABCDEDCB670D +:10259000F0F3D572583F44DCC5F8635F9E6EF7D503 +:1025A000E5E339D8DF9EBE61630DB4B9BA9AD3F7BB +:1025B0009B79B32719E9D32AE47F69A2D7D3167D83 +:1025C000BED21E7D6487EB295E7E45546E2CCEEF15 +:1025D000587FA621BF1C8BD062E9BEF601B0BF7048 +:1025E000E11D0D2B0BB1BCA8807E3F04DFBF1F6D2A +:1025F00088BB7CF51E3BC13773273F8F1C16F5F057 +:1026000088D4443A2F6EB2535CDEC611A9F92DBFAF +:102610003732EB238E8F59BBA400FE44DE9C40D89A +:10262000FBEDF25A99FC1A9B785CE00D0FB47ED753 +:102630001ECF85F1772FD6F078C556E518EF59FDF6 +:10264000679B8AE5E1EFDD7F82FF68E3DDF1B37927 +:10265000E678353D9E563FAFF55DFCF75F7FCA4B90 +:1026600032C4D58A3837A6049330AEB1FA40425FFF +:10267000B4C35FB6304781E13C42B713BF5EEAA303 +:102680003B3F2797CEE6777F44FB5352BDAD13DA2D +:10269000799FF1DF8B1BBC73FB5D4334AC5F494614 +:1026A000E8C9AFF30BD10F7D72E96271982FE2A0F8 +:1026B00045FCED653BEB65FCFDA2932F1C8D22FFD5 +:1026C000341E16A09DF7B5427474A6F2FBBDE7292F +:1026D0006FA17D808B85F69E87F11645C752F9A2C2 +:1026E0002AFE5EDBA27F4452B98EBFAF6E6514CF67 +:1026F000AFCFB3FEC9845D8371DF1215AB22DA6EF2 +:10270000107EA8AFB6C9D4FEB823F671E4EBE39B04 +:10271000C625E3230633AD4D3637CCC7BD7B2CFD34 +:10272000BECD67502F487EE4808CF6D0E0918CECD3 +:10273000D1C1608F6A2EDC227AC7205D0C7A01EA53 +:1027400041FE4490FF8E2913F6E6CC3FCB744FFA3E +:102750008B4DCF50BD2FB726C5E17827B7BE938CE0 +:102760007EADB94CADC7F3DF6B7B737E3B0E720D54 +:10277000FB9F0B741B01F5BEDCC6F9762ED025DD60 +:102780005509A3F3E26DCB88AEE6A6C80CE97AAE94 +:1027900087BFEF35177FA7414374733A74C0FF308A +:1027A0000E214ED0E93CA0538CAB9DB7AD6D3AAD38 +:1027B0007881D369381D87D36D38BDFEAAB7882BC1 +:1027C000E8CBFAFE92F8CAF0F785E3EBFA14D1EF02 +:1027D0005B35CB0B6F0ACA8923F84F92DF8B4B70A6 +:1027E000DFBBB7D9BEE6FAB65EE6F2E9BADE8BDF4A +:1027F0005F61F003DD2BCE11F57B88780EBABD0D3D +:10280000FBAFC1CDF5FEDE9FF8BB38FECE36F243FE +:10281000EF8DE5F7BC56DD3989EE79E9F5EB3BDB69 +:1028200016F37B604B53661AE4DEDECEC93FE379D4 +:10283000EEDE0EFC3D9BBDB7F5FB19EF91F917F2EB +:10284000DFFF39B2F8E8097C3FE9C3D060D5F8FE74 +:1028500080B582C7FB5B13EBA2671AE6B777613FCF +:10286000E2271D9E73E2BCECC3B49B55A4CBFACE09 +:102870003735E0FD767F0785E66BFFA14CC5DF119C +:102880002A16F76FAB057D59A3BFA1770FAA13F1E5 +:102890008761F03BDF2FD7A44D74D0EFEF24F277A0 +:1028A0007CACD1D7AB36033C9E4485CFCBC54CBF67 +:1028B000FBFC5D6F2ED7DFE92DDEBF9155821BE655 +:1028C000A1E2F9F7D49FCADE6F8071AC1903340C12 +:1028D000B61AECEE22DE73530B317EE372D99DCF34 +:1028E0000CFEA2C9160E57F83B71F8FB8C48B7D501 +:1028F0002EFE1E8EE19D27D37B38EDBDEBB6B5B71E +:102900008BDFE3C45FF8E4EF9CB4BCA326D3BD5CCB +:10291000B2FBEC8CDFC74DF2F0782A7BA2C3131117 +:1029200043EF4B0DB3C6D3BD357A3FC39ACE165C89 +:102930004B72B78E7E576D7B6F49C837DEAFFEDEB8 +:1029400055E3F29786E37DFD6A8969096EC33B66AC +:102950001D6C63701FABE7F5F14BC53853657E1FE7 +:10296000197FE811EF05B77A578CB9DFC7FB2776D7 +:102970007F9405F76BF5BDA5E67D82F15DB3C68C4E +:10298000CA20D66BB4306D87DAF24E568D8847B3C5 +:102990003BF93B348DCB6FA3FB65D5E58CDE33ABC8 +:1029A000D1CFD5E68B7B0DE27D1AFD9DB7D244FEDB +:1029B0003E4D29B477E519FC0FBFF0FDB38BDD4B1D +:1029C000D6FD853A5D8C435DDF1FE93D7909F15302 +:1029D0000707D1FBAAF4CFE99D2AEB1D43DCE89F52 +:1029E00068E6CF0E2985788FB27E61C29226037F7A +:1029F0007C58314E9DDE0BEF5B3AE9BDF4CB7F4A4C +:102A00005B82EBF489ED0A133FEEB9E3C499E71357 +:102A1000318DA67BC87B7E1CAC615C886C6924F917 +:102A2000C07E8C243A2F8E2D49D10C7CF18DA0874D +:102A30004D599E13BD615DE464A07F678B1CB32676 +:102A4000E7FB904F5639E9A6385B25E232AA25F319 +:102A5000FB1883DD9C6F07BB25918AF7DA148DDEA6 +:102A6000FDD4EFD7D77756161BF7A791A27EA4689F +:102A70005FDFF9E6F7CB0DF8AAB7BFFCB70188AF67 +:102A8000E4F16EBA4F8AF20EF2FF0B1B0EC22A005F +:102A9000800000001F8B080000000000000BED7D8F +:102AA0000B7854D5B5F03EE7CC2BC924993C800176 +:102AB000023D8110034EE24908218100934020BC71 +:102AC00074784803469944AAA8B44EA92D692F36B4 +:102AD00013124208A9465EA2451CF051DB0A06C447 +:102AE0005E6CBDED10145151A3B556AD4A4044ED96 +:102AF000F5DE462857FA5D6FB96BADBD4FE69C43D6 +:102B000012B0FDBFEFFFFEEFFBA175B3CE7EAFBDF0 +:102B1000D6DA6BADBDF69EE5F5099AA432767888D3 +:102B20008BB1744C1D112913D23B15C60A190B2702 +:102B3000BB226324809DC9946FFF5B754481FC496F +:102B40001A541AC4D845FC330DEBA597AA6EC63AA1 +:102B500095D03B35586F884B7B8C31F6A755695F14 +:102B600095016CB7277B14A87242EE99C014AC9FF4 +:102B7000CAD804C6D64BD0D06828C86CFE3330847F +:102B80006532B409B05D663B64A8C746B2C863D07D +:102B90009FD3D5D6A5E441CA6CE1EE1C2CCF1C17FF +:102BA00033B11A6372117E873FB2299F61FE182DDF +:102BB00093C6C958880512F9776930948339E1388A +:102BC0008E39D8F2800FEB8567E0FC06F961EC43A3 +:102BD000014E77F9E39220B5B119F6545ECF0EFDA0 +:102BE000DC20FA39E6E8A8C079F5484C3DA0E17749 +:102BF00073FD1B443D1D3FCE55F670B74B8C0BFF4C +:102C000003B86083C5B8475F3AEE5908BBFA872519 +:102C1000C4574E0C5F8B600C88CF4E9813ADDB060B +:102C200089F0661F742891B963E398AB49848FC318 +:102C300009C9751137AE73DA5745306E6753CD60E9 +:102C40001C53AC9C42ED395DC9FE880FD77F5A10EA +:102C5000D7B5C6BDC48EEBC86CEAC8EB73199BA38D +:102C6000D9A85C630AABEAF0E1BAF5E4E27C8E8FA6 +:102C7000095EA7C1F75376F80EFD7CE0613609EADC +:102C80007FC052A4062936FEF3121FBFBEFEFF25E9 +:102C9000E086EFBE48F370AE9222B856A7A48E1716 +:102CA000B07EB8C4E979CC03C59BBC47B3603D6E28 +:102CB00061626DEEFEB6630DE46FF0C2B801171BE2 +:102CC000D26F999906F3DAB0D34130FC69B341F978 +:102CD0009B45F98F99DF5106F839A08DA2F1073F86 +:102CE000F5CC4C52115F9FBE9A89F8F8A1E2417C65 +:102CF000FCEEEFCAF2008C7FCA5FA34A327C0F362B +:102D0000651628063C053FB7CD6430EF1AE669F634 +:102D100040B9134975950D50AEF12189D6F8941438 +:102D20003A1A04380CF063004F1E5158F54718E763 +:102D3000E4860CE2A70F59D7FC8998BFD54EFCD288 +:102D4000680F75215D857F9246B07FE71B341EFFBB +:102D50005D0A4392BDC1B56A26E285F93C92B3840F +:102D6000B1BB3599D6F3065BD081ED010A3D8D40AC +:102D70007F2FD9BB2A107EA90670990FF5E17FB885 +:102D80003EC764E09802C6E6A771BA6FC4FA139012 +:102D90001778BB378C574729298037C62AB1BC2DF5 +:102DA000A5B0CB0FEDFCE7A16F152169D9072D0E5A +:102DB000E2FCFEF2DC1D4588877B049D6C9CB739E4 +:102DC00080EBEE7285C2C3A1DCA72854E0FB9D2DE9 +:102DD0001BBE50808FEE7CAE8C057DC477812B6945 +:102DE000F701BDDD00B4AB5C41BB3BECA78DFCD56E +:102DF000F8409C4BBA86B1155B2DDFED9C4E6BC243 +:102E0000E6EF37B499E1DF08BC32A53A3968E01F34 +:102E10006B5AF7FE1B79CFE7C4EA3DA9B9D3CF249B +:102E2000C03F26B2891795CBD7FFB2BE2BEF793BB7 +:102E3000F6C7F93753FB178F047838976163ADB045 +:102E4000E0E7426B5C48F7E732603C28EF58776276 +:102E500020F7D276BAEB61814198DC2EDAD1F94BBA +:102E6000E7A7230AABC3799F9258D57E18CFEF1CF2 +:102E7000EA5D481FBF8B1F218591B05847DA029049 +:102E80008F2F8B79FFCEC1566279609ED245D0DFFD +:102E9000EF6480DD98CFD7E5379F1794E2BC7E7B47 +:102EA000A1A0B4D6171BC711A5FB971369DF901912 +:102EB000D133D0D1D37DCCBFE61AC534CECD384E78 +:102EC000252607B68871EB746AADFF899063DDF53E +:102ED00075ECA331067E443A87FE26BC156C4CC4C3 +:102EE000FD2A4335F16BF2D5E527B441317E6047C9 +:102EF00096B24C981F5B3B9EB1A1D82E9F3FF0EC41 +:102F00004C3FB4C3BC01EFC2C458FDC7AFE6F9FAE9 +:102F1000B8B7F4CAAF8017D7E543FCE724FC4F5D90 +:102F200015D63FA2E8307409F33A8CF0306CA7EE66 +:102F30009D26776CBEF789F9FB59CF918BC8DF6E60 +:102F400039F2187CAB96D90CE457BD7F5B3EEF7F1E +:102F500066A21C40B95C1D1F1DB31AD2B9F7B3108D +:102F6000CEA7D2C9962F8076AB53F9F7583D8EAFD6 +:102F7000B9F7F272731B798AEDEC76C7F2ABCB79B5 +:102F80003D1DD6E7A98FEFF1AB3D9C2FD6A631565C +:102F900072E9F8C3E52C2704ED353A420F77231D7B +:102FA000ACB3B1C750BE95877ED68DE93AA7A711BD +:102FB000D2FB137E4CF9753697C70934BB46F1BC7A +:102FC0008002AE3E3F93E8E24B59B5A31EB228BD46 +:102FD0007B066DD5D365BF9C8E04E5A47DCD4A0FDD +:102FE00023F2B91CFB753EA7FFB27C0FA576D8F77C +:102FF000512E356223D8FF20AE4FE8FA805E7F8CD9 +:10300000986F593E972FCA7899F0D36D6723F3696B +:103010009D3C23B0FC8284D4F32A349D9F7F7F950E +:103020000DE865C1E4D4EF8F86F14FDAFF1087C752 +:10303000A73E330AE0D2FC9D1CBE2675821DE086A9 +:10304000865D5533005FCBF2FDD7E41BC6A7B70BF7 +:10305000DF0BF0FBC399C1A27CD2577A6E89A23CE8 +:103060009492B4569C77564F1ED2975EEF0D897D91 +:10307000F81B2906E338351FC24CCCA3EF7443BEBE +:103080007F5A7E1FDF7121CFC17AD4164B9156C073 +:103090008FEC521D7500073487A6F0FD33E0027DEA +:1030A000E53AFC17A0A8D6F515E93B8046CDE985A1 +:1030B000B4C5FE79AFFE025BEA58D6E441BA80554A +:1030C000D97931AD7FF9870ADC19BD1EF246B8E720 +:1030D000269C77238379231FEC04C501FB91594F6C +:1030E0002BEC4B1220BF1AF8417AEEC5BF49795834 +:1030F000ABDA73E66AA4D3A07C11D3E03BBF42BA3B +:10310000BAAB01E427D4CB0CBE47F079A0B35698F4 +:10311000C7EA673E48526150B7213DC0FA7C7E6DD8 +:10312000343B0AF33D96F9E24894679FD4332D0B64 +:10313000E4499133786BBE41BFFD646763D2246874 +:10314000EF3FF629DA3CA8BA4A01FE41BAF84A89AB +:103150004E4BC7FA63F720DE3EDFBF21A306D6E160 +:103160004E418F9F67F2FD867D7564E4BF40B9CA0A +:1031700051B327B402F85AFD2193DCBA56C82D404A +:10318000AE638141BECF96CBBF8F74516B13F98F65 +:103190005E4FE39EED0EF9490FA8525337005D3D97 +:1031A0009EC5E9D7690BD0772FD21CF1673BA733B7 +:1031B000F57BF4BDF936E669CDE7EBC98A62EBE948 +:1031C000D72ECEC0FC6B613D114FB2ABC78670A04D +:1031D00012782105D773A707F7357D3D2B94B5F7F6 +:1031E000205E57039E9D30AFD55288C37697278CBB +:1031F000FA19EB6AAE86EF77FA5D3DAD04FB93E614 +:10320000437F2B457FB0D0474BA0FC7F80BE46F963 +:1032100011FB29DC7F55F88BF4C394AF1C4807E7FA +:1032200083EE106862EC5A8FED94497F663D474B00 +:10323000207FD52107ADEBB73BECA6FC3B199437BB +:10324000E8D3D67D7A777E623AD20DCB67F948779C +:10325000FA7AE8FB757FEBA1EFD7B02E4F18D7A510 +:103260004271CBC80FAB1F1ABDC79989E922D58619 +:10327000F818945380FBB6BE3EECABE749EFBF5560 +:103280008C95ED4CA3F59C7F683853E19FB71D02E8 +:103290008302B6A27987D2084EBA3094604010AD4E +:1032A000E3FC9FDDEA2D2824552084F53E7BFC4F6E +:1032B00077FD08FA9DB70986EEA171B8701C67FD0D +:1032C000A0376712AAD7231E5767DA4288E7FB1395 +:1032D000F2EE2F85FA8D2FD9C9F608B05EBB42BA3F +:1032E000487A809A4CEB7E0CD605E5A49FDB2D2A0C +:1032F0007335E0BA38BD32530D78B68597AEC7F650 +:10330000ECB0CE11588738359EA9063CFF8105EDFB +:1033100064DF85FD6FA2BE5E25D63F2127D5548E82 +:10332000296D2F04914F811E50DE246AC34CFD404D +:1033300033A74DF4C1BA6D38CF40A9C41E84715F64 +:103340005F05F986F636C425D9A3D05E778D3B2478 +:10335000C1FE6B2FFD82F6117BA959CF0B649C79BE +:103360009F25111E4E0F442F9F20BDA05E37968DC6 +:10337000457A013C6BD8FED9B714CD49530AECD03D +:10338000F901E58E8DA984E725C7EC2C02F33DCB2E +:10339000D85ECC3F1B767AC285313A6259500FE72E +:1033A000E1E4F229B9D88CDF14BF199F699566BC96 +:1033B0000D0A98F134A46A94297F68709C297FF8DB +:1033C000CA02133C2234C954FE1B75E52638333C2F +:1033D000C7547E74CB42133CA67D99A9FC553B6A29 +:1033E0004DF96323B79BF2AF7E62B509CEEDF8913C +:1033F000A9FC3587D699F2F3A3ADA6FCF1C7369B9D +:10340000E0095D0F9ACA4F7C678F29BFA4FB17A6FE +:10341000FCC99F1E30C1537A7E6D2A3FED42A70939 +:103420002E63AF98CA4F77FDDE045778FE642A3FBB +:10343000CBFB91297FB6FAEFA6FCB939E74CF07CBB +:10344000EDBF4DE5BB58D318DC8F7E98159C580016 +:10345000F2424EF89CE8FC9D1B259606047CF6D8AB +:10346000220FDA3B5FD72E995660A6DFF3CC7D930F +:103470003CEAF276C970A11F5428F318DA21673BA1 +:1034800024A2F7BFD8D772FDAED1C694A9301C379D +:10349000DFA7BF038259813AF6740F437DEDDB51FC +:1034A000D681FB477231F084613C297E17B319F055 +:1034B0009056E931C183025E53F92155AA297F68EC +:1034C00030C7943F7CA5668247848A4DE5BF51E7AB +:1034D00037C199E14A53F9D12D01133CA6BDCA5415 +:1034E000FEAA1D4153FED8C84A53FED54F844C70E6 +:1034F0006E479DA9FC3587C2A6FCFC688B297FFC22 +:10350000B176133CA16B87A9FCC47722A6FC92EE8E +:10351000274CF9933FED30C1537A0E99CA4FBB1037 +:1035200035C165EC2553F9E9AE374C7085E75D533D +:10353000F959DE93A6FCD9EA67A6FC55FF0EFA3DC1 +:10354000EA238D4ECF638548E75F98F2BF8C1B1945 +:10355000FD17F82EAD4ED2A462A4FBBF99DABB3F93 +:10356000212907E9A78EC56BE8EF59A370BDFD6758 +:1035700005A3843DC0BAE3508F0F07C86F0764C628 +:10358000BC503E15FE81FA8CC4FE4AFA7D929F75AE +:10359000A09E08FA0BE93B1ED067703FD1E93A556F +:1035A000CECC44FB2421A69F665C1C7FE5FAE93360 +:1035B000058CC6F35141F017C89FB777EC9F897E01 +:1035C00089DB58B81937E50AC597DC0DFCF95A5C58 +:1035D000DF76EB6C17E0CDD0DF4B71ED190503F012 +:1035E000F16CD7E754BEB75D3B6F5782C91AEDBB8C +:1035F0007BC0FEB701BFB6D7035F811EB3B9DE4300 +:10360000F0D67A2FC1DBEB554A77D4E750FA60BD8C +:1036100046F93BEB8B09DE55EF2738525F49E99EAF +:10362000FA007D7FB4BE8AE0C7EB83943E51BF921F +:10363000D25FD48728FF49B0BF11DE571FA6B4A3BD +:10364000BE85BE1FA86F27F860FD0E827F551FA1A3 +:10365000F450FD1394FEBABE83F29F03BD0BE1DF6D +:10366000D647098ED61F23B8B3BE8BE0E7EBDF2128 +:10367000F8687D37A5C7EA3FA5F4E5FA1ECA3F5EA4 +:103680007F81E0CF857FE2648124FC596E5AFF4040 +:10369000F9557B1429F63DF7EAC0495CB77509492D +:1036A000DFC6FC854CD614B42F2C7684751DFE2CF9 +:1036B000DAB797335688FACEB0EC3D8DB0DE0DB256 +:1036C0004474D790AAEE411BF3F302AEE76D88670E +:1036D000E1B802221BD2B36FC57FA9A04EA5D71FA8 +:1036E000453BE09610D83764BA011DE6101D1EFF59 +:1036F0005A76120B533F6BC606FE1BE7C3DC91B72D +:1037000033615CB7CBAC0BEDA687C706FF8EDF6FCE +:1037100071871CA4D6312D1BEDCCF9CEE8A06FA289 +:10372000DFFA2545DBA3F6DFDF9DEDB341280F90DF +:10373000FFDBCF3270FFA9FCBB1244BCBC664FACB0 +:10374000427F84673CC7B367BC6C4AB3C60592C767 +:10375000C3783E19133AF353C05BF577C724E33EB1 +:10376000761D9AE8C0D70B986A47BE5EC4FC2F64EA +:10377000A23E877A23C0DF64614AED63835EACBFFB +:10378000140C058483939C231169F39D9C1FACE367 +:1037900050C53854D1BF9E4E1B1750C7437A7A8C00 +:1037A000FFF1EF4191EF8F53098FD7B29E5D388EB5 +:1037B000FFFAB72FCE48A363F8D5FD190C9708F090 +:1037C000567D4C21FB18F43FF24F577F9FFBA79B80 +:1037D000CBBEC7F7C306EEEF5813FF6105E677DFF0 +:1037E00006340502E26CE8858750CFAB867CAAF7E9 +:1037F0005D0E9F05BB14E5D397711F92BF56AA8536 +:10380000FF0FED4B1E76BB0791DF224AED7E398E0E +:1038100031947BDF1AC7CF37AAD1B984EDAE952298 +:10382000DCD711B5637B7F99E0A1726BC606CBC66E +:10383000939D1FD93E1EBEBF86748274EF8964A318 +:103840005F6183CCE922FCB2A2A19FDAE609F8D13C +:103850000F79CBCE947CF2F703FDA01DB451E0515B +:10386000A78FEFB4406A90674077F3B19FFF7C76F3 +:10387000620ED2C79DBF2D51719D1BB1FDF458FB47 +:103880000C5D5DD09F92ECDB8D7ECEF9A854205D5F +:10389000962446F664929FAC6E7F1FF273F578CE45 +:1038A0005FAF79ED95116A97F3A59E7F8718DF1DAD +:1038B00062FDE777BE3402CF05BE73CCAE39B1DF0F +:1038C000C26E9FD1EFD34BCF758F146519E671E7A8 +:1038D000A193DCFF879E42A8FFDA6095C66977B99D +:1038E000A36979B17E58BAEDF35E7B6214E287D1A9 +:1038F000F8747A541C89C1DD6EE3F8B9FF0EF8E163 +:10390000BB3A3F8461BED73AD5E46F42FBDD80BA53 +:1039100028A4C1873D0EA4C75AA651BA820528BD66 +:1039200095851D48FF81F07D0E06FDDDCE3AE8FB52 +:10393000778A6F1E89F09DAC678617DABBBEA5E15A +:103940000574CB2C6ABFAF6228CC7B61A4E6054C22 +:10395000173C2A9D09ABC44FEBB0FF6E29B47E180B +:10396000F4B7ECC9B2F5C3E1FBB50AA72F3691B1A4 +:10397000C750F7CBD2BAC3B06EA7EF1B5B807E0BEC +:103980007D1E1B057EA78DF36FC476AAD731A29743 +:103990009E7F73D2FAF5F255F11D2786CB28BE7AA9 +:1039A0006E427ABCF3B7CE54B22B19D7176F17FB00 +:1039B00037C2A82FDA71FF2638F430F2C71D616EC6 +:1039C0004FAD89FF3BD5EF96644D1A09F2D8CEFD75 +:1039D0008B7FB6BB3C8D1AF26964249D7B39E82C41 +:1039E0000AF987D6ADEEFD44E2CF2F65AE4FB09118 +:1039F000416FC1E8D87EFD67395294349AF6F3C717 +:103A0000502E1CF582DD8EFDA6BB343CE7FC734ACC +:103A10006424E7FFDEFD815D4C88F915EF413D38F8 +:103A20003DA607AF891FC9D0EEEF96588F3499F4A1 +:103A30001E9A9754CE3A90AFA5E21F04715C3B13D7 +:103A4000984729E98BCF835E3C10F952D65C34DE6F +:103A50008C00F911D86097D62A5D3A0EA0CF2AB40F +:103A6000EF9DC25F76EC7FD208AF61E8FFB194585A +:103A7000FF6A19EB60208724CF0F484FDB097A9A41 +:103A80009201F5E2434FE078642FF3A0BF285C2E4B +:103A9000FCB60E8ED74BF1C8F5AF37C6733F6D231A +:103AA0004E95E4A527C78376AF2D9EC639D215EC77 +:103AB000427C6606873D64B48B8F650E21F85A07F9 +:103AC000977BECABC60C943F6EA686717DAFF54B31 +:103AD0005A2BC987EE26B4AF170021907FA8D86E65 +:103AE000E23366F15F0119913F7221FAAFC8DFC47A +:103AF0009E477FE622F4674A68F6BCAFE38DFC5729 +:103B00004F8E055B0BD7D5068608C8912C56ECC2A4 +:103B10007134B9172623BC2EE15A3A57B2CA8966C6 +:103B2000D0AFA24E036C0BBA3C03E86FBADFC6B14C +:103B30002389454136D82E64B3689FFDE71C42BCFB +:103B400034A6C3F8596C1CFDB5DB6819873555ECF4 +:103B50009AE74AC6A574F371D92F64D1B8EE15F26D +:103B600014D693FC5E358BA3EFA4909F751D95AF83 +:103B700071B9C378EEC69ACCFE5E7DBFD4D32C6CEF +:103B800001E6F3F84E4784D32D50EA60B154F01F9C +:103B900075E7CCCFB01DD04AD92983DF05F59C53FA +:103BA000FA3A2B3CC575A64F78BE182BEF477F55C8 +:103BB0007FF3BBD2B4B59ECEA863E73B3B562F4301 +:103BC0007A3FBF13C42C8CE767653573ECC80F0FC1 +:103BD000C8ACAF7307540BA2A6F1C6B3A8494F4BAC +:103BE000B5C0C32CE54759F2C759F20B2CF0244B52 +:103BF000F9720B3CC7527EA1055E66295F6BC9BF97 +:103C0000DD92BFDA02FFC8527E9D25BFD592BFD993 +:103C10000427168E12E71E0F5AEAEDB1D40B131DBE +:103C2000C5F8044C363CA7622ED2C39E3A2D931E93 +:103C3000D6F15CE7B85F02BC2F20D129C5BED3A75F +:103C40005AAF46BF71878DE0EB0385EBBB55682704 +:103C5000D1DC4EB6FF7FE2510F781AD63F7A15635A +:103C6000FF8AFC7415DA251EE2ABDF82DD8469145D +:103C7000EC26FCFE1CD84D98FA3E965FA1F68FEB21 +:103C8000C409926A30F98BC9297B6D87EB24C6A9D8 +:103C9000E8F451785C8ECD13FE5FFC7EBC099EFC7F +:103CA000696A6CDE0CEDF461A6FC32207A63FE9446 +:103CB0009E71A6FCC58BC79B60366F720C26BE3406 +:103CC000D3C7B546FA30D0F3CB8007FF5531F8950E +:103CD0001F2A14B7D1F9C11AF62B98EFBE83A9BBDE +:103CE00051FE3FE54B684A4D063BB390EB3FFB9ED0 +:103CF000DB4CF87C25A97D2EE2E59AD3324A0A56A0 +:103D0000F61C8BE23A698718ED1B0F16AA545E3B2E +:103D1000D425AB80F7DC835DC382542FC470DF7879 +:103D2000F6901C5907E3E9CCBD7F13B6B317DA410F +:103D30007DED95546817E5E2C7D0AE4AA3BE781171 +:103D4000E4412E2A370A9DEB55F17398AE61787ED7 +:103D50001D5BE7EE785A67E6F2CF80FA1DA57C1F5F +:103D6000D8173D3B230FDA3FE777F5605C48B63F55 +:103D700091F6B70E3F3FF7DA172D27B9CBC2FE3FBA +:103D80006619E2454E0AFC34EC3FBA0CF7997D8780 +:103D90001D2AFAD7116F61F8FE0ED04FD889781B13 +:103DA000EF5885FBEF50853DA6A17DEAA1EFE8B86D +:103DB000761421F73164791CA0EE77972F5E83DFAC +:103DC0006DC2CFCE0EE3BA2C5E6C8FC503D1BA1A8A +:103DD000E287CCF5C5BA9AE3835E063383E6B55530 +:103DE000DAC3CFF7C3CC5564A0D3834B1CBE422AA1 +:103DF000FE059EDFAD88963B7C680FF8BD6793019A +:103E0000FEF2E402CA7FADDCFB458316CBF7C81E89 +:103E1000CA5FDFF4D1E705B86E2020F0FC96B571DB +:103E2000FFBBABD73F6FF0A7C3F89EB5B1F57740A6 +:103E3000F98E62A707DB5B1A34FBE13B727E1FEF52 +:103E4000F75DEA87DF1B952B314EE95A8BDFDE1ACF +:103E5000D7F14121D7477B049D5585C3151E1FDA35 +:103E60008BEDEB711F9C6F8B925CCF3B4DBA11CBEE +:103E7000D34EAE4BC0F9174ADA18A8229DE6F8D205 +:103E80000AA5DDB3203F3EC745E7397B9FE372C6F5 +:103E90002AF75F3D782A1EE9A423A2D35B17D1DB62 +:103EA000BE83C00FF0FDD9E70A06DCBFDF11F4F4D2 +:103EB000B22DE21E689F9E9BA3B0B0F11C44ECDBC8 +:103EC0004B83092C6CA08FF95A9A096ED8EF20BF4A +:103ED000C4C167199D033D69EF96BF0DF33B50E2E6 +:103EE000F4AC23C9C8CFE3C60BFA76B2FCC655E2E0 +:103EF000FCA5D513B36F0F4639FF1E64EA74C4974F +:103F0000067A6518EA171CEC96513FF3D4BA43E8D9 +:103F1000DB2D38EE30C929A7668635E688C9211819 +:103F20004F9E05D6FDD9B88C185760C583D59F3DE7 +:103F30007442A229CE66AFE5FC2E573FBFEB2AA400 +:103F4000F69EBC5B5516BA637EEDD8FEDD40F8DC0C +:103F50005BEF92B07E41F4335985CA79079982F4B8 +:103F6000A8A12709F9E220A3782CBD3DA9CAD94907 +:103F700072E0D8283AF7DD77EC2CC56D1C888EDA14 +:103F800083710C078E2D4CAEF5C5DA675DE974CEF2 +:103F9000A7F7BB4FEC3B580EC7BB4FD0F93E905B29 +:103FA000A97DD08DBEEE3A7CCD21F3BE626DFFD2ED +:103FB000FA61DA4F1BF19F50EEBF0B83E513D01F60 +:103FC000C63A591A8C7F7EE17749DFEDC59B7B218C +:103FD000959B9B375BC6F3AA6D235377A31F0DF404 +:103FE000627917C0691AC0502F3DCCE344D38B4788 +:103FF000EE26BF83D013E78E33CBE17D196FC6DB8E +:1040000071DF0C27125DCE4D32E7CFCD7B76057E7A +:10401000FFE562978AED4A794B87A2BF733BE209BD +:10402000E4E7EB0757C777F7819721F650CA40FCC2 +:1040300033A4DB46FA6DDA850CD26FE716805E3D5D +:104040004079E70585CAEBF086B86E2FC5877A7F81 +:10405000FAA7D3C6EF19A97188AF6CFFDD2ED42360 +:10406000F6650CACAFEBF3D0E1FB7BF7576718F1CB +:10407000D7F64406EDAF1BAAE3697FBD7B02F713B9 +:10408000B401DE70BCCE604214F1D396C1681FDB70 +:10409000ABAD23F9737F52978CF18965C08F889FF0 +:1040A00096092AD5CBCB8832A463B716C80F5239EC +:1040B000BECFB665C03E0BF53B6FFCC1583CCFD9B7 +:1040C000EB857D0CD72D1A3D86FEC341E36586F650 +:1040D00057B3C4685CE19FBB290E49DF7707A16D28 +:1040E0000E4BDE7690F79FCDBE2DA37F606F0697B7 +:1040F00093737F552BB7A31CD1E408F281759D55AE +:104100004F17E95DCC9D4A7CB459F0818EBF0AE51A +:10411000C93D68EFEE63AE10EE2B2A0BB98CFE1A88 +:10412000BDFC76A1AF6D99772095E6A7AD7E690CB1 +:10413000D257B59BA45B85E2FB0CFD116DD5F11E3A +:104140009CDFF6AACDA9C6F3B24BFB75CB186FBCAA +:1041500001F4109497A951B50CE92A8D690D98EED8 +:1041600010E51F10FDFE54E8890FA19E7815E1238C +:104170002E1BFB0F80DE09F8DB5527CB0ADA3F0741 +:10418000E588D2879DA2B71711EDED12ED3D2ADA31 +:10419000DB7028B5DC85786CE1D1AB99EDE13207B5 +:1041A000B43B34ACAD43BDA842F9EAB013F1146698 +:1041B000E4D77A54D883BB44FD7D07CBA5381C0FC8 +:1041C0000648833C4F6F0F6EC4380D4902BD07E4AB +:1041D000F5C36B79FEE0381B9DB73FFCE33904DF84 +:1041E000EFE6F053825ED3DBFD1A9E8F3F2AC6A70F +:1041F000B79FDD7563725F7E343DDD2BE6D721C648 +:10420000F5943D287F00E3CDFDA312090F60B7E9C7 +:10421000722EEFA06CDA3FF2A3F12658A79FCBC90C +:10422000BBF53179D73D0160DF9C2ED90576A4DB43 +:104230001FF2A38AD42BEFD2B9BCD3E3381A55D0DE +:104240007733315D982C61BE885FD8C4F43F5CCE73 +:1042500025F7CA39CD85F4DD2CE6DD22D6D519F651 +:1042600093FC7466C99108B697B58EE4E579D0A140 +:104270003C244FA7B2BECE715B04FE1DE116F24B8B +:104280006CB4B50FE86788DBC1E59C726124C9B9DD +:10429000F2A92E17F6B3D1CDF7FF8D6A4118FD4470 +:1042A0001B555B88363566D03F2542976A1B2C8E9E +:1042B000D64699F279BCF9D40BE4B76A4914F242B4 +:1042C000ECB309EE5BE631F20F680CC7A9A83C9E7F +:1042D0000261ECCF157473FF8DCF668ADF7065C9FC +:1042E000279D4964CF9F36F6E3C8B099F43AE5328A +:1042F0007119C38A12FB8CB765E97DD3476FDC85E2 +:10430000EEAFE8A79C958EC6B98AC99E69C962E4DA +:104310009F52D40292C7BB7C3C3A6E571DDFC77FC9 +:1043200082401FED350ABAD06145A7BBC2021147D2 +:10433000D9BDF12A68EFDE3FA41560FB877D0AF93D +:10434000C75B4AB3F720BE5B7C37131DEDCAE0FAAA +:1043500085AE57ECCAA895DFC7EF2A97B7567FC43A +:10436000AEBACDD4CEF90C594539B441DDECEA6B87 +:104370009F6A17F4B653D0ED1382DF37662D1C30D9 +:10438000CE409F975E4E01F1A7F5D1BECD6DD657B9 +:10439000B28F0D2C3FF476F5727ABB3ADEFA6BF7EA +:1043A000A6226E972614FAAB8BC81FE5A7384F5B81 +:1043B0009D63FB69E00BA56206E92F2D595CCEBF1A +:1043C00092B59A09FC44D02E6AC9485D3003D6A143 +:1043D000294B26397EDF8C2697515FB0E237255373 +:1043E000A6785EC6260D3F6C43FA6E77D13E9225C5 +:1043F00053FC545306D7379A6CFE3EF9D7DADE46A3 +:10440000556F6FC20D87B3609FF6DDCC5AD263E360 +:104410008594E45362AE42EBADB0AE2E8C07636F71 +:1044200029146FDD3F1D0FECA7BAA748F7CB0CECA2 +:10443000AFBA9CDCBF5C3FBBEA52F1E81AF625D666 +:10444000837121AC3095E4EE08F8E75A439C738AF7 +:10445000DFA2DF8A7D6144C8BC0F8C8D98FD277A6E +:104460007B97E367AB7EAAFB5FF77670FEDE775043 +:104470000EA3DFEF3C73119E9FEA87AFF75AFCB0A3 +:10448000A8BF0F24A7F376B8493EEFB3B343523227 +:1044900091A7EA19CC38EB42BF0F97049F41BAF5B8 +:1044A0005DC823792E1D3A4A71AE80773FE14DE316 +:1044B000E77EAC34407A74E37C80118F1D8B28BF7B +:1044C000F9FBCC43B02D320CE5F19382AFF5713E90 +:1044D00099195D86FAE2BEDF7C281BE3F68F16F1A0 +:1044E00073B55C5712DDF7B18EFBC5226E5F3B6D75 +:1044F0002C1C8FE7DACF713C7B99C781F47059BFD0 +:104500007055B48AE2856599C7F55AE6BD17D3A1FF +:1045100038FFC05B45782F40E3F36E0B04C2C84FF1 +:104520004150C4D864287390CB6B1F0BD07C6B3484 +:104530003EFFD7B58504BB011FCE7C1C4FB5888FCD +:10454000651EE7506C87C7CB06EF006D68785FE3A8 +:10455000E4F4D58B5781C7D735994D453DD2EB2033 +:10456000FE63395A15B5DBCF3CB68A797C5212F816 +:104570000F9A879BCFE35E20678A3F4F7250FCB94A +:104580005C183C5744FCC6FCA827DEBB44253B9284 +:10459000F90212FAB158E0CAF6A52B2E97E31F10C4 +:1045A000FF8D49C3580DEE3FAB93285EC6300FC751 +:1045B00044BC07E06E0DD03E1FD0F1CFFD7B356EC1 +:1045C00007E9FD975BFF989E147019F9AD29839F49 +:1045D00077344A0117DA1FE13F7039A6F7CF66201A +:1045E000AEA0BFC18EDD463F4C4CCE48E2FE8559A1 +:1045F000CE3859AAC9CFF97FDAEF9E3731539C776D +:104600000CEC7FAF99C8F83D477BC08BFB5776D742 +:10461000B719EAC1E7DD7DFB95F4D4AA4736C7F99F +:10462000ABFA8A276A39E05869E4D76513399F2EB7 +:104630009B28E21E4011433F4D932A935C6BF4D4B8 +:1046400032B48B40FFD4D800FD639CAF51FE625C56 +:10465000AF49CE7ECDF8C3EB268A786BA1A7AD9784 +:10466000605CE9B4DEDCAF827F005EB679D06E7E3E +:104670003ECC5625007D9E10F4A9B7ABEB6FB96216 +:104680007ED1C9FEA5489FB9886748C71405AA27E7 +:10469000C2F727F717915EADD3EBBDC24FDC1F7F8A +:1046A000280E16A438FD00B703B259A56B411FFBB5 +:1046B0009CAEF7C7FCCC9C9ED77B16F2349DEB4199 +:1046C000FDF1A5AED7E8E7882DA8675D85F5CAB9E5 +:1046D0001E22F6C5FEF06AD57774B9E5F49AD7279D +:1046E0004EB5EC8B572827504714F65233E2D1577A +:1046F000DE258FECCB5E722F36D94B5B7CFC7C6069 +:104700008B58C7B6906737DA796D3E99CF6BA5673E +:104710003733F88786B37609CFF3BC2C24A152A790 +:10472000D3FB43022F3F11786912E7300FD7FB0507 +:104730003F5412FC487D90D2D6FA9594367BCF52E6 +:10474000FCC14FC110C378AEE4E8CF49DEA7CE6309 +:104750009E38A0A7B49D3D5194B32C144FF127BBB4 +:10476000EB43542FB5928F77E7CAB84770EE3F9B63 +:10477000E8107415FCD9447E2FA6DB0E74B85CA734 +:1047800051E61F4CFBAA3D125E87ED97CA118CDFE4 +:1047900090B01D80DD3358645626FA5F7F40FE9648 +:1047A0004D7F50F8BE21FCAD832DF4DC16E9B51F1A +:1047B000E350A86E29E5F8DAAC31D23B3657A6367D +:1047C0006401EC2873F5607CFF919C4EF2636F29C5 +:1047D000E5E70F834B8F466BA19FA3C54E0FDAF51C +:1047E000A9F33AC9EE02E227BF6CEA3C6E67A55610 +:1047F00099FDB1596D6638C5E28F75F7E39FBD52DB +:104800007E7FD5C2EF0CE904E9C027D3FDF118FF84 +:10481000F410DF38FCDC2FB8D9C7CF61EEAD3C30E7 +:10482000A3B290E889CE6974BE77E472FDF77CA9E3 +:104830006EEF7434AD04788EDF457666167B624683 +:104840000EFAD3F0DE89663C3FEC20BBE71DA10FDA +:10485000354ADA4BA30DFB8D23921B47E747B30B79 +:10486000E224833C45FFBB91DFD0EF6EE2AB9C546A +:10487000D379DB266D603F60ABA0F37509BF257F60 +:104880006BAB2D32A05DBFBD7814F165FC0E07E95E +:104890008D09170653BAA594F7F3A43D28BF9F4E80 +:1048A00074437EBD2DA5074CF69D2B6CF6A36CF2D0 +:1048B0000D6CCFDD2BC6A7974BB6F5B0BEC6E7296A +:1048C000FD7AF69C6E5FEAE53C362661BB1E9BD9FD +:1048D0009EB3EAFD238BB99C57BCE7AE3ADD479CFB +:1048E0006E42617078B1E19E96E2DDF527B4F3D8AF +:1048F0005717C95FD91B3720ECBF785725D97FF7E9 +:104900006A32F9519F9CD2396C34D21DD84FC89766 +:104910001BE318D1579C8F9F47DAA7F5B080FBD2D5 +:10492000F6589601AFA3906EF97ABCE81D25A11F39 +:1049300036B9B2038C34902BB68E28EA2FC96E5943 +:104940006B50F17BD48F71652FCE3B40F269B35B26 +:1049500096918F8FCF4B25BEDF02FD523CA16FD4C5 +:1049600046E4FBF00A59C3630D17E378A17966A208 +:10497000DFB3D385E769C31B926F41795756AC709B +:104980007F31EE0F067A6FF3EA30E7B339C5FCFEEC +:10499000E6A6CAB3C7B2A0DE03ABC868256D0AE5B8 +:1049A0005AB3C6CF213C5F5D740D86FA474B3B5D21 +:1049B000677C588FDFD76DAB940FA31FF101945321 +:1049C00030CE574A47C57543F9CDF30EA4101FB337 +:1049D00044C2DFE65281DFD9B5ECCD74DA07885FD7 +:1049E000DB4A3BDF1B8572609E4CB81B3668DD617D +:1049F00062631662F44E04C683C110ED9E1F84A745 +:104A0000433D4FB9ABC7598CF778CD74B1A5B49677 +:104A100035A7C7FCCC4FE6D7B276801DF339FCC072 +:104A2000BC4E3AA76DAB74A8A8E71C7173B9BAC5A0 +:104A3000C3FD618975E6F61C53F644B3845D2ADE36 +:104A40000B489A3F18E3C4B9BC8E9F7720BC02EA9A +:104A50007B86290CCF3FF5F3B57B87F2F331ABDDD5 +:104A6000EB64350CE5CB7971FFED9EE2F2E8CD0009 +:104A70003F08721AE5F888BB603F037888B8DFA664 +:104A8000D36FBCCF2C9747041DE6715AE4B28D3921 +:104A90004C7A6EAF7EE9B50DA85F36097EDC20F456 +:104AA000CB267B94F44BD8A7C88EDAA078F2C9CE77 +:104AB00004FE1C0AEDD95233482FDB5EACEB95A106 +:104AC00062A4BF2D287735C4FB3A26ECFA90670024 +:104AD000FDC5EE31E3DD95618E87609E304B2FA2E0 +:104AE000673D08EF36663B83F6440BC6224BC67D16 +:104AF00023CAF70DE632D15B5BE501FABE49C84730 +:104B00008687777DE83DC3437DEB5143579AC73392 +:104B100024986A2ED74F7B563DEA3E71BF39376CD9 +:104B200063E8A7BF3FE1C34EA4BFA79FE1FBF6E543 +:104B3000EE431F7E86D3D7DE0F78DCDDDE5739FCEF +:104B4000E4070944DF8D895DCB70BD7E61D786E7C0 +:104B500043FAF4AB8F0FAB8179FFAE989F1B3DDD1D +:104B60008FBE7BA458D2F59B23C5DCFEFC5C31E8EC +:104B700037CB64FF60926F55DA0D467BF1E192E02E +:104B80004B2867AD76A3749CDBB70E6511D969B964 +:104B900060A7EF49217EA678BEDC95E2BEA92B4036 +:104BA000FC973B4F25FF8553D8EF23EF629E06D03D +:104BB00023171706FF40E3B1ADF6E339B3EF47C95A +:104BC000741F0E463A0EF70B37E3E707356FF1F81F +:104BD0006B47D78866D4733AF4F8408BDDA9CF775A +:104BE000BFA0F37D42AFDC9FC9F1F6D4EFCCFE8FBE +:104BF0003F179BFD1F504BC6F8B7FD475F8EAFE9CF +:104C0000633FFFCF929A3F1BF71D5F87A6603995E0 +:104C100079149C17BE79407E9852CD6B7CAFA1E38E +:104C2000F8C0E78F05CF9BF7EB6B0E59ECAEDEF8C3 +:104C3000CF8084F714747A7B2525648A3FBF1C7D5E +:104C4000394B74FB95115DADB9236E8F1EA787F0AC +:104C5000979BEDE48F884E0E384B389DB8F09D1D24 +:104C60009D4E7AE36E44F9659BC7EC11769B5B46DB +:104C70007A92387D2495E8F4E64F2A81FE9A9706C9 +:104C80005330F58D7B751C9E33CCCD7B699831CE2E +:104C900032D7E2DFD5D3BA124ED7736E881CB41365 +:104CA0005D6CAD3E0EFBC29C6F46FE6A87F5BFABE6 +:104CB000E4DEEA26A0A3394EEE3FBDA3E4D73BC312 +:104CC000D0EE3D380E80CB4B9EA80E43BB5327F849 +:104CD000BF81FDBF5AE4574B68FE33E8FE858ECF97 +:104CE000FEF9DA7CFFC28F3E7B931F3168F26B3492 +:104CF0007AB81FB1D93DF07A7FDD78D2FF290A96C4 +:104D0000E0B8ADF1A4B179B4535CF095CE6371A174 +:104D1000BF0CDBABC3F9C03A4DCF9B2D470A71DC0A +:104D2000420FB9CCF8950B934DE7E58A4DBCAB31FA +:104D300063CD9A354522DE60742C3F20D651B930C0 +:104D400095EAF58B3F11077BB9FEFFD938D833457B +:104D5000C19B71FED638D87F149F3A5D3C5CE45FFE +:104D6000F5CFD097BE1E20A7EB783B6C955264928E +:104D7000D3DBDF247ECBA07BF97ABDD8BD95D8FBF1 +:104D80001B8DB4FFFC98E4415DD8E941FD2D6932EB +:104D90008F5BF7611CB687F8B209FB59A344C7E1E2 +:104DA0007A7D2947DF6B34E80FB94C438F116B2DA7 +:104DB000796D27BE6BA138BA358CB06C7DF6F99D44 +:104DC00095785E6103390DCC9B34ABBBE308DAD92F +:104DD000690EB2B39B66F3F70F9ACAB8BCD852C239 +:104DE000E5EC3691DE5FC2F5897513FD9BB1FF9F3F +:104DF0000AFC254EF46F45B9A3C3EF4FF06F37C2DD +:104E000080979F0AB9D42299F7AFED473289AE77E0 +:104E100072BCF58D1F5627FCBCBA9C661C766608D2 +:104E2000FFBAD007F04ADAA4544A59450188B49C25 +:104E30007022EE47CE9A4503D2E5897AF3799FDE58 +:104E40005E70AD6292E72E9F59DFD83658E7873003 +:104E50008F0BF7DF467A798B7760BBF2E57A737C4C +:104E600089DEDF5C5B870DE97FEE059B894FAD69CD +:104E7000D9779F71A1DDB2293461C07E605E5D3358 +:104E8000C6603CA48B52FD7B70ADD435C330AFF708 +:104E9000C3DF27BD6CD35A7E4ED5E81BB584EE6FB9 +:104EA000B4D8291E6353067B0DDF09DAF48642F17C +:104EB000A27A3B9B1239BDD436C575CD30E065531F +:104EC000AE83DED948084B8FD37DBE7A1E77F96159 +:104ED00009B74BA6FB3A18DA2109E12FEC18F77253 +:104EE000BA44A5755EBE56720473F1DDAE1407C6F2 +:104EF00073257898DE4E04DF219BEEEBB1E3BC977F +:104F000087F753BC4C02C0587E794B2695D7DFCF2C +:104F1000A86D524CF1750ADE0B1A8D7411A4434929 +:104F200027D215A47188772586FF0416E5F622EBB3 +:104F30006203D9C74F475FA2B858064CF2511FFE13 +:104F4000F38625F1449FAD3F94843FA97B7D2D9E40 +:104F500067803DD16A88E75B81FF84A93B6F0CDCE9 +:104F600086E583631D2AFAE156E49CB1A3BE74145E +:104F7000EC0DF413B176FE5E860BFE623F9961F391 +:104F8000FB1A41CBFB193731433EEA5FC24F183F52 +:104F900049F8790A5801F2975A1D217A758E15FA47 +:104FA000B7B76F7D3941C45959E3DA36F96AE38DF1 +:104FB000FE8976BF4C710CE754467134DB1C618A64 +:104FC0006368CEB485D6A1DE27E2326AC5BCE13F74 +:104FD000CDF84EDD7211C738F95399F94DF1D3F17F +:104FE000CC6F58C76917524D70191B6E2A3FDD35BB +:104FF000DA945FE1B9DA943FCB3BDE04CF56279BCE +:10500000CABB58EFBB7E3CCE8249146741556453FE +:105010003EF7B3B5F0B8563FFCC57549F5F7D83142 +:105020007EB95ABCAFA1D3417326B763975BE22325 +:10503000D258388CE73837005D44F15DC290394E64 +:10504000D6C5DAE8DDB44BE22EC47ACE9864F1DB43 +:10505000F5B37E3139C3E9B37FB9C5E360B3D59FFA +:10506000501C17ACD7DB595076A658AF998B5752C6 +:10507000FC88E3420AF3233D3C37F1A96CC89F2E1C +:10508000F0E3B005C9FFE4B8904EF96116183B0A89 +:10509000EDFCE30AC5A939F05DC824B4032DF12C59 +:1050A0002A8F6771E09751A67CE1DF0C52BC4A253C +:1050B000D021B63BEB82C4FCB0EF3B168BF8152F2A +:1050C000C79BCE1FD305BE6EAD182DD17B8CAAF920 +:1050D000BD1107E2358FFA31ADC77D8CE3F54E2B5C +:1050E0005E675C993F3E51DEBD02FD4F6DD54AA51E +:1050F000F19CE78F93F8FEF9A3499238B7B7AE83D6 +:105100002789AF435C12CEF36478D180727DCE855F +:10511000D1A4F7F4EE2797894B9E23F4CE6D49E690 +:10512000FEB259654A05ACCF7B8B25D2DF4EAE1C53 +:105130004DFADCB979FC7E861E6FFF9E88B73FB9B9 +:1051400052A9F81694FF2BFAAF3576499CBC1E770E +:105150008F138C1AEE5958E3EEF538FB577EA850A2 +:10516000BC7F788A24E216078EB3678B2D71F55FBA +:105170003BCE3E4CFCF85EB144E700E39405CD45E0 +:1051800085788F927D81F7E7ACF70856AC9CDE8C72 +:10519000EF6DEA71F6DF5A397EE67AF22BA5D11B64 +:1051A00019D72E9E47F541A8505CFE97274F3E8F9A +:1051B000F11DAF957B5737F07794A8FEB7987A9694 +:1051C000EC5E4BDCFDFAA673B67150FE7D901714B1 +:1051D000976F89C37FDF1675A1BFF3839DDC1F69BD +:1051E0008DC3FF20E7A3C4BEE2F03FA853AE280E54 +:1051F000FF5D418F55E1C83C5CE7AA1C8545A4587A +:105200001CBE958EFED1F8F69649DC8F69077B238C +:105210003915E3FB61BF43FFC02A89E2FB6BB494FD +:105220009928BA7AE3FBE13BED874DD26E3C9FD1E2 +:10523000E3FBDFABE3FE849A950AE57F5028D13982 +:10524000953EBEEE48AFBF89DE51FD20F4C83C2C30 +:105250007702C68DE54ED48DBFA238FF7F76BE3A69 +:105260007FEBEDBC8D4A13CC77E31229B24742BEE7 +:10527000BB91EE7BBFC2D829D467B7E52D5A8FF713 +:105280003ECF31F626F25559FE5F8F5C44BDC7C74D +:10529000F50790A376AC1FCF5C27B17C826FC1FA73 +:1052A00009788EE292F6CB50BEAB9EBF2739271805 +:1052B000A1FD76916A0BA91A96B7C8591797B3F151 +:1052C000825F0DF9E2DC3D60C7B8EFB9A576DA8FF1 +:1052D000E7AE8806E8DD051FECCB99AC773F30DE02 +:1052E000E3447E588CFB37F4F78DAFAEABF83E8EBF +:1052F0004B8F2314F427C35FA47737F3576C83FCD9 +:1053000078E187DC94B3DB8FF2642EC8139CC7E28C +:10531000C566FA9CEB7F84FCAE783E3606F217CE6B +:1053200033E7C75BE8DE3799C745E9FBE326DF4291 +:10533000F2DB639C099ED3BEB200AA24436AEFF05D +:10534000B6037DBC9E3BF330EA65EE6D3243FECB87 +:105350009B2CE2137DCCF775F653E78DD1068CC7F5 +:10536000DDC45CDD18F7F7DE77F97A2F05BDB512DD +:10537000C6357D854470461D7F7FE01B217614F77E +:10538000C5A5C0F7B3A0DF8C95D10AA4CBA5ABB857 +:105390001E7843C8A1FA0DE790BABED4B0649CE36E +:1053A00056C87F77A8C29C88DF16B35E08FA834987 +:1053B0002FBC69C527B43F5EAA1F72BDC2AA27C60B +:1053C0000BBC5D37D9AA27B6D33BA6CE6F0DBC2F39 +:1053D000ED1476CD09CB7B79CBF573683CECC33803 +:1053E00011D6C116427BDB96FCDA65F4EBE97192CB +:1053F0000F2F0D06271BF827C1E771D03B4A3957FD +:10540000B61E575ACEB01F26F2FD70A58C57335EDC +:10541000F52BE49F7EA390C7719ECFE1E714B1F214 +:105420005137BF77C6DE34F2830DF107FDFE5ED83B +:1054300093DBCA07B63BBB44B90AE5781BD2C31B52 +:105440006F29748FAE6B0753F1096FBDDCEF675E98 +:105450006D577DB1F3C885D1B123D43EEC93D69975 +:105460007FB2E1BBDEF3A33F67981F6F8B788DF1AE +:105470009DAF8A765B273CC2F05CEB8D715C0EC7FA +:10548000173AD538A4CB9C6813DA6519393D33BE79 +:10549000877C097C8DEF6786599784EF33C7E7488F +:1054A000EC41A2C35F84912F8F835E8F7478899CB7 +:1054B00089809C291A48CE44489F8BD73E11F1C75A +:1054C000113A079F27E4C61B39D174BC0FA6CB8FB6 +:1054D0001CF86BF413EBE93C8B5E3CC737B07CF8EF +:1054E000C6574FB5C4E1B8814FD14FDE0AEB8EFDF0 +:1054F000BCA13DE2427C04C6D6AEC3756065AEEE8B +:1055000031308E56FF981BC98ED36EF5E0FBA6C7CF +:10551000CB6EA6FC37CA5C6764C87FB3E2AA11AA47 +:10552000617D5B1F60538388DFB18F7B6F81F9657D +:10553000E7FC577D10F4CC37C5BBDABF9FF9CB1120 +:105540009986F5183FB9EC3793511FC4E003E08BFF +:10555000718EC8A8BEE271757A5DD6F973A247F460 +:10556000ABC749FDD3D529C187EF88F3A29A96949A +:1055700099FE3EDBE5FCB62C9BD1FB172BEEB33B33 +:105580008CFEF3EEC9B2691FEB5ECBDF995E71381A +:10559000CE916DA0BF772773BB3E184CA17738AC76 +:1055A000FD7C3AD9ACF7AE68600E9C67303AD48186 +:1055B000767CCD8A2BABB76C9C18E7E1A18ECC44EE +:1055C0006339EE97AA69EBBB1D3D8EC5BFA29CDE79 +:1055D000DD8E13EF587C2AA9F4DDC5FCD121B0BEC5 +:1055E0002BDAF9BDAA4BF573EEEF74697E792BD2F5 +:1055F000473A7FEFB739BD80F8DB15BD4DC6B85FC0 +:10560000077CEF6B5DDAC4FEDC0A7A2FEA176E5B6B +:1056100094DB4939118A7B725F70905D137F613032 +:10562000D9359D4B6E27FF8EDE7E7FEBBC5DE82B70 +:10563000ADB0CE98AE17EDB7D57BA9BF84D2149A82 +:10564000C7605B90F6C1C15E0FE95B2E1797C74339 +:105650006C212985E6CBDC830C7EB92155663B3C69 +:1056600021C76C873BD2534DF9D1C91C8FF80EA4CA +:10567000F1FBB271FEC172660C9F158A7B1DEA397F +:10568000AD3E1E1FDDEAAB95DF43F9AA2914CFED2D +:1056900009F373DF05C2DED0E5E98240CF62B43B97 +:1056A00075BFD9B68281F7215D4EEA703CE8197D5D +:1056B000D1FF35A522FEDCC7F317E0337786DF0183 +:1056C000D04AB9DDB6C006382BC06841EE2F9F6BBB +:1056D00039F72829E57CA2A7D1C9C19252EE078EDD +:1056E0007AFA38AFD3F5BB788DEB779056DC85FA34 +:1056F0001EC83F99E42DABD85A18D393BCBE7F5235 +:10570000AFB3E86D6EA1B7C5EBEFB95AF4B4C00CF6 +:10571000B31C1DCA22A4A72D147E8A4BF5306E4FF0 +:105720005BE56D55A9F9BE47367B35C0E5297FAFEE +:1057300074DBB8B387F11EE6791F8F9F3AAE2D3226 +:10574000E96BC77D511BF9F5847CECB2ACEB3CBF37 +:1057500042E77FC741AFF380DC3D6E8F66DC07EB2D +:1057600092AE7D730E58B8EC78FE8BEE1A1FDF5F99 +:105770008C7EABD7B5239E938676FBA3239D6E1FAD +:10578000DFF16818E936AC32B24FE2849E74648768 +:10579000BA13F53E16F64A495319DB2AE8299BFD50 +:1057A0001BF953B6E50DEC07D6E773BEC4BFB6745C +:1057B000C2007A138C1FDF35DFB6E417AE5A809B28 +:1057C0004B25D37C405F6A2E1D64A477AE2F6D7A83 +:1057D000808D447DB733D75115E9438E6CDAD1D132 +:1057E00042E3679E5349230DE3CA3BE095DD386FE2 +:1057F0001BD9912C8BEB6D9B7E9E9381F3E94C7CA6 +:105800006494DA87DE76FB64FF369C87B7D4BF1DCD +:10581000C7E3D2DF6D17F597D8D8F3C6DFD9B0D676 +:10582000BF4BD8892C8BEB6F7A7AB9F5D92805C391 +:10583000184F08363D9D6358CB3D25F8F8ED51C112 +:105840009581BECF419F48369C83EAE389620C3B39 +:10585000D4BBB3948FCBA572791DEB97ADC373F412 +:10586000708DC27FF7A446A17B84E7D72A7B509E28 +:1058700039EF1E9F2CF781777D7FEE16E76147C4D5 +:10588000F8D0DE34CACFF95A8249EE5E579C668260 +:10589000F5F7A60CFEBC44E14722397A228BC77B80 +:1058A000BFB396DBBD7157B5D9FB7A27474FDFB938 +:1058B0009BEB297147FE66C7FD1DD2F55EF40BB464 +:1058C000D414418BECED521EB7B4F44202ED537A7E +:1058D000BD0F4B55FA5E050A04B6BFF44212E5C788 +:1058E00035F6D8719F5F1EDD487EFEA517E2689FE2 +:1058F000AB6ABB4F7301FE6F5E2B79D04FACE7C72D +:10590000EABBA9DCCD2D8A25EE8305DC8673357DC7 +:10591000DFA9099BE3FC9665FB97744AB175D2F742 +:105920009103A5FECF903ED59C0EF26F3A73F979A4 +:10593000657F72E08ACF8572ACE7FEFCFD1C0C33FC +:10594000E5BF03117E1EF5C6D9A877D03B4A172FB5 +:10595000E2F9E042A6D35B7B13FADD6631167A10DA +:1059600048AD32CB1E7B6747B4A7427B15F80F9832 +:10597000CBACCA054D1AB78BD559783E9061A77745 +:10598000782E5E64B68B18AA95DE5BFF75E3B9844A +:105990008A2C09E3781DE42DD2C56DFE0ED2E36F8B +:1059A000837D25E2A1F7BD5E4554DCCE5C3D518090 +:1059B000A7CBDA5BF8FE1C7B5BA1DF43D1EDEA8667 +:1059C000C44F328CF7BB6FD96AC6C74D772598D6BE +:1059D000EDFA409A297FE5CEE126B8C2637E3765AD +:1059E00096F76A53FDD9AAF9DD944595934DE513D1 +:1059F00058DF7E7B3A4A944DF9B42F4D9D9242EB8D +:105A000078040F0AD16E1F24EDC1784CFD7CA252A0 +:105A1000E0BCD2B7C486EF471EC5F747F00D13E1CF +:105A200047D6FDFD094C6B1A9689EB62B643128A84 +:105A3000B95D33FD51F33E9920ECEE044BF9295347 +:105A4000CCFEE6EBA630AEF70AFB521F0FD211FADE +:105A50002B2A84BFC53A1E600F5B21EA11229ED615 +:105A60003AAEDB9FD81FFE1ED49F8E716DDA958FE4 +:105A7000EF4AFD20656A0DDD2FEF74F338EA4EB56D +:105A8000C1968AE786E912DDCFDBE49E7E3C05FD08 +:105A9000CB405F78CF399B3D4B7CA8FB1DF4F63A99 +:105AA00085BE7C4CE8B52F668CB719E556E7C86013 +:105AB00086067C7B3431B309E3365F8ACBA47D094B +:105AC000FD25158389CF4C71DB9DB95C8F3E7A78BB +:105AD000AC0DE54CB92D68C3FA33339E263B7816DE +:105AE000D68571956770FFCC67A27F60475B7E614A +:105AF0000C9FE58FDE47BF1F5491BE3F3C0CBE7725 +:105B0000FE5C6269D0CF6D51B51AEBDFE676AA1163 +:105B1000E2F7F6E743B80EFA3A6571BF4C00FEE2D1 +:105B20003A49E9BBC90E7901EA0F81FE6E7FD47E46 +:105B3000CA783E91900EF49347BF2365F2DB18D6E6 +:105B4000C7E4B7596FA11F150403E2F5792FD79366 +:105B5000FBF387740AF9F6EFC24EFC58DC23FD40D4 +:105B6000C4F1BF25DE53FA04DF5372E2FBAE1AC163 +:105B700047EB8B293D8671FEF0FD4D11E76FF57BFC +:105B8000DE233107EE1FE1BB25BA37D2EB97734D09 +:105B90006F0B00DE94A92922AEA9E7852130C4A4A9 +:105BA0007885EED39E2FF5EF9A32A87F7AFB475384 +:105BB0009CAFF1FDB04BF21DEC3BA81F744A65147D +:105BC000FFFEFCDDA3F73418EC39652AD7BB9EBF76 +:105BD000DE1CA7BE69EDD33CF5150C18AF9D10591E +:105BE00044FB5A7FF99B64F13B3E2E7E0F2861CD2A +:105BF00055840F3DFFD5299209BF09D125D4DE8DEB +:105C00002D8B69BF3D3A45E8DBC26FD7EE3F40744C +:105C10007D2EC842F8CE77BFE312ED58F90FE902A6 +:105C2000D38F855D89748129D2057E47BA4018E9F2 +:105C30000261A40BCEB77EFA8E7481E989FA2A4AF2 +:105C4000CFF96057E2A1C4B43FC6CE81F9FE46F257 +:105C50001ADF7B5CBBDB81E2B6A67D607CD534FFBE +:105C6000D08B726183947914CF514F2C880FE1B996 +:105C70004BED65DEA94BB0BC4B873B71AF5E25DEBB +:105C80005DF31BCA9F38FC2CC51B04EB94EDC6B812 +:105C900076E89BF4EC20C6AB0F30CE2B4D4F58E886 +:105CA000F34AE5EEE22941E7D409183FB19FE54305 +:105CB000954A905728DF137C211BD263BF76855706 +:105CC000F7C73207B72FE2936ADDC6F6757FACCA15 +:105CD000F9548C27184EE1FED82B1C9FFE8ECDB0B8 +:105CE000A96E137D5EE9BB10EDFE5ABAC7790EDFCF +:105CF0007FA6F336735CEB9125C3C21847B031948D +:105D0000A4A11F5FF22CA17DDD8567D825782ECD5B +:105D1000E3593D19402B2518B7B68C9FCB6B2C88C7 +:105D2000E7292D8C897BFD22AE28C0C2E81FDAE866 +:105D300095FDE82FD4EF153B224B88CF589D667A0E +:105D4000E7C46189AB8B9D834F1571137A5C995FB2 +:105D5000FE3AF1694CBDB2FBD14D92F8DD1AFD1D42 +:105D600048F51F7B0792481EF19B23CE63C539DDA2 +:105D70001C6FB64A7692D04702BC093627475A8F25 +:105D8000FBFB1BF90E55E1F10EEB910F5FC6F3091A +:105D90008D7EF788FFBEE150FE3B4E8E1CAE17E9AC +:105DA000FA389E4C448DE7457E8B3E838F5296E0B9 +:105DB0007D21DB49671EFA5FCC7A89355EC27A9E07 +:105DC000AFD3EF6D532DE73A5768F75F69393DEE72 +:105DD000E5BC97D17DA9547F90FC35D542AF4E6389 +:105DE0001DA6F3548C7331EAB318E762D46731CE41 +:105DF000C508639C8BB13CC6B998F567B3BE8C717E +:105E00002E66FDD9AC2F5F127FC1A401E32FF47978 +:105E100066ABAFD27A6E4DE7F6C3B6850BFDDF42B7 +:105E2000BEC478008AEF616FA3FE4C3FDDA9D2B9F2 +:105E3000817F3DA2B0575FE57EAA21A29FC118CF06 +:105E400001FC942EE239F47812DD8FE50C04B428BD +:105E5000B433347EDE50DC37B6DAFD43118F5B2578 +:105E600089E85DC7E75066D6FF8758C75F6833C5C6 +:105E700087E87E2A3D3EC4596533C587D82D741402 +:105E8000992A9BFCD0D9EA4F28AE705B2DB7AB9115 +:105E90005298C1DE506AB85D5505EB1F36DC17A974 +:105EA00016F12B37E07C0DF2C2609FD870FC5519BB +:105EB0001D7EE1A7083BF5776C901FA40E36B890C5 +:105EC0007EBF32F341C0E787625C7A7D1BF3365CAC +:105ED000D47D1886FDD46AFF30A6515C69B049A113 +:105EE000DF2D5C5FAC1D5311063D2D4CBD561D359D +:105EF000C66949C6FA0ABDFF4B7110BA7E5BD36210 +:105F00008EAF591E36C30918A7937729BF5AED0DD6 +:105F10001B7486E3FB6A2AD3E3DD236827EB788DC5 +:105F2000CD9FA9387FC3BC77D3BCFE1F9FB74E5F00 +:105F30006FC707760D827E3E929CACA93036AFE5E6 +:105F4000820E5E4DEC79A10EC67D067FFB01EF9FB0 +:105F50006CFBE62EE4CB8F363A198F37546FFA215B +:105F6000C0C1AD4E8ABBBA096F5EC0F893A7651277 +:105F7000BDC809A5547EF9BA44BA43FCF1B62F73E3 +:105F8000514F783B357813D2DD4729017ABF3B5812 +:105F90007FB58CE7056FC777D33BE36764E6C1FB4A +:105FA000226F577D64477FE8BB1AD38C7A25CCDFFC +:105FB000F4BBB9374EE3FAF232999FDB2C5BC6E3B0 +:105FC00036DE6DBF6A0FF78B70FA0E4A7C7DB74FD5 +:105FD000E3FA6D70E56D14EF80EF09940FA01FC018 +:105FE00078495FB77EAF15FDBE9DD173239E5B7E62 +:105FF0002431CF3AC2A7F6E11AF413029EE85D7B82 +:10600000F1EEA663F8B0DDFC3E853A12FD888EFA0B +:10601000D132CAB702D1CE092C8BF5BCF1625F0C2C +:10602000E62C31FC3EB1615DD64F403CE1EF0C0304 +:10603000DF2F6FFF84E23C9E01BCE13EF2AEA7671A +:10604000FD61803F0664E3BB8CCBBD7FA6DF11F80A +:106050005E01ACF050F42B99F1F7E369FC77973FC0 +:10606000DEBA2591F42D0F0B3A06D3EF66527FC1AD +:10607000B67F5D83F779828CCB3B978893B2D2ED64 +:1060800052582FF41B78E2597B32F493B0F2E38A32 +:106090007908974B3DC92548D7DD1548D77A1CE6C6 +:1060A000D23ACBEFB0BACF56A09C5F21FC062B7C36 +:1060B0006679C9C4EFF506F9BF2FA1F7E5CCDD8CF1 +:1060C0007881E6E97EA0954F1E9AE6A179BEBBF2E3 +:1060D000B141284FDF4EE5EB72661D8F97018D6051 +:1060E000A451DFCA9EA6CB63A6DA0DF85F5EB58524 +:1060F000E2624079EF29F772FCE3BC9F8179F78572 +:106100005F2B1E1ADDA7080F2BF077CDFAC0839BFB +:10611000B5FF6409B4BF7CA59D61BCDCE5F0B07C33 +:10612000B1A319C7F31ABE2F5FDC175EF8B9C9A572 +:10613000F860C407A746F4CC4F2BA4DF81F5EC41EF +:106140007FEED6E933117E172981FCF601079E33D5 +:10615000E01FA528461778D170683AC69D79484E49 +:10616000EA74A3E329B8F58BF5F87B91DEBF24AA86 +:10617000185F1CF44EBA95E244747AB2E009E58FD8 +:106180004DF7BB2A14C76AFD7D6B13BDCDC2F1D399 +:10619000FA0489FE8333449CBE0DD6B18FDFC3A5BC +:1061A000F51E86EBBA7F79B814EB8569FE4796C475 +:1061B000C7E11140E371FEBB6D59780207E36EF64B +:1061C000B310EAED8D5EF37D135BC46CC75E7ADFBE +:1061D00045BC4B25F4F2DE7A516E67DA5B16F46942 +:1061E0006FDA14FEFBABEB0F2F65A372715C935C4F +:1061F000A768DFE7FAA5CDA9B564E27ABCCEEFA720 +:10620000B37437FB48C70FE0DB9656EA45F9DA1856 +:10621000C74C7ACB0B42DEBD2C525B32EFE7523DCE +:1062200093EBF18AF09FC7BE47F8779817EA458A43 +:10623000F09B2B429FEABF9C8DF2158B1FFFD27201 +:10624000DC8F6FF5EBFCFFF4FF4EFABF7C259AEB79 +:10625000008000001F8B080000000000000BE57D9F +:106260000D7C54D595F87DF3665E5E3293302180C7 +:1062700013059D006AD401277CC9478497640221D5 +:106280001F64423006059C408040758D2D7653D7A3 +:10629000FFE605428C89DA6845D1FA3181F055DB99 +:1062A0006D40B056A93B10B4AC8204B5185AB5681D +:1062B000AD05D775A36897EEDF96FF39E7DE9779CE +:1062C0006F3221B11FFFDDFDFFE3AFBDDCF7EEBB99 +:1062D000F7DC73CF39F77CDD3BDE803665F714C61B +:1062E0005AB504770B63AC3B911D1F0B75FD17323C +:1062F000DB0675F6D5F9F3E7A731B618FF2D47EBA6 +:106300004EAC8F63CC9DAFED65D0FE032D214DCFFC +:10631000C076361651193B8F7F19D82EC9525FCCE3 +:1063200086B34866B49EA55DC1D8486C77B1E5795F +:106330009B661BB37B04635FFA94341CB6A122896D +:1063400031A89FAA92C209F0BED5A16F9C8E70E6BB +:10635000A8BDDBFC8C1D9AA03015DE97E5AFDC9A5A +:10636000202170210DE1726AACB62595B14D4A2706 +:10637000AB43386724B8D7FBF13D4BC919C5581555 +:10638000FECB0BAD03239BEAE07BE691D9300F6394 +:106390004A78118BA43196ABB3B98BE0BB5B34B5B3 +:1063A000370CDF851A1D1F9C52E97B761EFE97C7AE +:1063B0003A5904BE5B1672D546E0FDB2BBADEF2B79 +:1063C000993D5A277C58EB30039ABF02FFCA1E2E14 +:1063D000E63F079F87199B1AAD1BF018EDDBB44908 +:1063E000C3422EC6EC38D719D17646E90C97336DE7 +:1063F00072FFE746D96A63359D3EF8D6C5FC08BFF3 +:10640000F3EFAF9CD4E28DBE0F6A92657C67A482E5 +:10641000FA5BDABC886900C77C2D79C447D7C0F71E +:1064200093D8A4F332C2B38721BECF8658AD9C3532 +:10643000F0B8463F465D6E2EA7FE8CFA068955766B +:10644000C2BCBA2A0A6D6180AB69C4D82DB89EC699 +:10645000FB9502AE17EADD4CBB92B1FDF51EA625F9 +:1064600030F652BD97CA487D263D3F58EFA7FAA1A6 +:10647000FAE9547FA55EA3FAE1FA022A9B464C1A78 +:1064800006736773FEB888211E8DFED36686566A32 +:10649000A6793BCE5D41F03D60E0CB3D85F00DF44B +:1064A00049F478D69FB14596F87A6A404F4512A7CD +:1064B00027FA83F7853EEF96167ADF4070D31FF0F8 +:1064C0004F129619BCEA85EF54C14F45D9C567E410 +:1064D0008950FA1DEC83CC281D3933A16EA22B35CF +:1064E000D36E79CFD842A6197564187613D3D468C1 +:1064F0007D985CE6F103FC729DFCC88780FF8D07E8 +:10650000D6306F32D43D7E9ABF5CA7D07363DE2D48 +:10651000F5C02B0E9C2F4C227DE0F534E871A8EDE0 +:10652000AED3B4EF6A50E6CD0E3E8878662E9D0558 +:10653000018EC6D4B98B917E1E916C7E19F9506381 +:106540005E37E04512FC29053F227C3E318ED5A600 +:10655000A5E3776E7D25D465AF9DB5B8619D58885C +:10656000E453028E036522F28F8CFC1621BCC2100C +:10657000611BE145A3F1185BE246FA95581B3B8F7E +:10658000C2CC353C2E1FC5C2BFB1BE8EFDE672A87F +:106590007625268E87F19523B23F11AA1BB009C03C +:1065A000A58C086A9A0BFB9B447566F7FB174E880F +:1065B000D71FA787A7E604F7201EE4C822E28BB600 +:1065C000D9DAB358EFA37F972D8CF4DFE4E2F43AE5 +:1065D000107C1B059DCF7184981FDA39EC4C237A0F +:1065E000F5EBCC3CFEAB827F3E9D153C80EBA09C46 +:1065F0001B4FE3C27A7461DD580FC646BB3F729AE7 +:10660000E86988F8618D2FBEF8E2345C0F46F877B0 +:106610009C9B4DFCF3E9AC50B7793C840BC781716E +:10662000DFF8AB8C3BC47600C7FB66FE563C3A0BEA +:10663000019E1E40B9E38BE2FD9120C89D0C2C17F2 +:106640000EB3013E7B63E461543ECC621113DFF470 +:10665000E1FDD0A79F7E0AF4BB1187B645DFF7A204 +:10666000DC98CAF182DFBDADD4DEC660DFF84ADB5C +:10667000181A01F0BF9D02ED2F46709BC21AF4F369 +:106680005D68CE6672F18242A25112EFD9BDE11A65 +:10669000802BD166D4BF17D2F83CA83E36E77B21C9 +:1066A0001DEA21D57FD80B7C959CC9FC2DD44DB714 +:1066B000B611EA0ED8E7906FD814FB877DFBD1584E +:1066C000944B5037E408C927531DD773D147EFB017 +:1066D000145C5F6BBB2F3446F372E5887DE13A763C +:1066E0001DB6379E4766855273465273D7E580972D +:1066F0005BF8A7EC261B48CD71D1769BE05D37F2A5 +:106700008F3D94C87C383FCDF630CA8385B6F036CD +:10671000B11EF87C603EF0B24882697DED21E676DC +:1067200071BAC3FDD35867E3FD15397C5D8DD290F6 +:10673000F3B1FD3EA0E55E913395E83533E7427253 +:106740002B97919C925C2CDC42F873B39588EFDA1E +:10675000143FE19B71B9A508B9750179754A1A17FB +:106760004F5E8584BC1A31247A6F89CAAB08C2A5F2 +:106770002E718613012E45E2F24ACDD4B9BCF24CFB +:1067800019447E737905F2691ECEFF3D2D389FF0C6 +:10679000E00FB1E004FC7E68F00CB51DEE3F1CEE8E +:1067A000F90E2FF4BF48C069C0CD3C8BA85C82EBCA +:1067B00086FD0647B2DF18F408749C9DC3E9695949 +:1067C0008ECBA2A764E7B82D700C19EE876B2B71E6 +:1067D0009D99CDE66F99C2FAED4F4FCFF0523B69CC +:1067E000F42B7F90803F24775310F9C4F83EB65FB6 +:1067F00055E86D7BB2B53B902F62E5CFC9C67124D9 +:106800007F4E369693FCD173E2CB9F4A943F26FD90 +:10681000A912E50FAE67E30F7EF00390C33D08C2F7 +:10682000D8E87B3D87CB9F4A943FF05DE295B7DA8D +:106830007E09E32D0EC96119C6DBB4BC3C2E7F9DD9 +:10684000FC5F1CBE5FC3BA44609F49EC7ACC710503 +:10685000D0655B8E4CFD2DBE5B9A4B74E49D320877 +:106860003E391D6DC6F58179276ED01DB85F55463E +:10687000D215D447AA74E8C737F47E0CF9F944CE90 +:10688000312E3F936AFF0D580EE8A43B5400F5DD0E +:10689000B3B52711BF4F89F1CA73B4A7B1BE5DD09C +:1068A00047768ED68E746CD4414E6D17722AE09A5C +:1068B000D65F4ED9F3A45AA137EB480F6F5FEC6E49 +:1068C000473E37E07A41AC53E32FE3CB91BD825E84 +:1068D0001B5FE8D3BF756904F6037AA2A51FBE4EFD +:1068E000F6043E9EDDC94BE3FD8BA21FA37C3B2536 +:1068F000149164E44BED459CCF9E19DA7E2C136F06 +:1069000061B5480F893F61B57BE2C0F3B2F83EB193 +:106910009CB78B7D7F0CE180F7072BD6DA9A892E06 +:10692000E530A7CBC91794C3CA39A745AF8FCAE1D1 +:10693000147A0EFB5608C78B95B7A9B9829F456993 +:10694000D839038DF397DA399FC4F055AC9DF31114 +:10695000EE674EF667DB395D1549A427F674CB7EEA +:10696000D896D878F67832CAF3D8F668CFE8C29EBF +:10697000D1853DA30B7B4617F68C2EEC195DD833E1 +:10698000BAB067B0ECA93EFB6629C0F505ECF3CCC4 +:106990001B079E5CAF659E49E726321DE0F3BADC1B +:1069A00029084FC2C6BC0BAEE77EE07B0E972AE0FB +:1069B00072537950C07B08E125B838BCDB67848608 +:1069C000E5C278B3CF456409ED7030CF105FAAFD02 +:1069D000C09BA8FEA5CDD4DCB9C467A7BCB87FDC3A +:1069E0006B63B43FE9CB9CE16DB024F9B2EB20EED0 +:1069F000A73DD55C0EF65473399821E82216BE16D1 +:106A00002197FAD67DC2AAF53618F7EA5C764A06CF +:106A1000F97045666F0ECAE3C9B3421938EE1560C6 +:106A20002626A4D0738D81BDB57DB3BD200CFD9FFE +:106A3000DCAC3F9988FBB8EE915266C37B3626A545 +:106A40000CF0333F97F3E3A6A6F8F2D128BB051C60 +:106A50005FCED07C38FF5FD73F4FFB98F11EE40933 +:106A600097CF8CEBE59B2A5AD4E5D0DFB498793DDB +:106A7000BD38342DD7B45EAAD7ADA09EFAFE63EC24 +:106A800052360CF0B131A1321C078EF737BB1F20F4 +:106A9000F899FB83944B4D7035A55D8AF833E6F980 +:106AA000FE2E356243FCA6B376B4437B566E1DEBD7 +:106AB000F545E709722480E333EFD0EC3A839FE990 +:106AC0000F3E4999E9B3C8B3DB72ADFA15FC115F0B +:106AD0003CF0FAB8492D2CFA5D716606D9CB467B9D +:106AE000D280D0AE66A6BF0BD8CF8C751EEA423ED0 +:106AF0000F26D5A27EF5D7B7A31BC6E07EA5083B1F +:106B0000BAE7C063A49F28D55564472B03D8D16B3F +:106B100067697F8774E7C9D66EC7F2E9195A2DE114 +:106B2000B74E5F8AF3DEC0E2EB15EB6686BE437CB0 +:106B3000F2B09B7D1BDF7F13F448F25FB95915E279 +:106B4000791CE8917ED24BFF21D7A49746F545CD1D +:106B500046FAE210D771A8ED0C3D0CF8BC15C74DF4 +:106B6000B4B5F91B24D45F75D2636F433D0BE1F9D3 +:106B70009A7A9653E845AA3744F8847D52D837D09C +:106B800040A57DB0AFAEA2FF46E9F6D940AE7C90FD +:106B90005BD76E1FC358C938A3FDEDEDA88FCC9904 +:106BA0006013F6D4DA76CDCED809C5D4DF74D8DF39 +:106BB0007AEDE2FDAAAA1AF8A7A2BD1F70033E3B18 +:106BC0000FAE685781BEE4C5C6F755EFE3F7333320 +:106BD000B59D4E98DAFE833767DC9B8AE36B3B9367 +:106BE00061FC7FBDEAAEAAC333B0DE7BC99B50CF48 +:106BF000E90A57A989086F4E2DF6B7BAEBEE2A15A8 +:106C0000DE1F1DCBC7BF31AFBE4A1F8D780AEEA174 +:106C1000F50DB6F9510EC27841E4EB99209FCCFCFA +:106C2000DD95CBF5ACFDB90EC2D31C474446BA99ED +:106C300093C1341DE0C8C9648D36A09763D95D69DE +:106C40002827FE318F513BE8FF25EABF12FA4FEEAD +:106C5000FFDD8BB82F8CECFF3D7CF7327DB7887F52 +:106C600037137962269F77839DDEFF0BBDAFE5EF7B +:106C700017D8B3DA2E77239C95EDAE8C68FB9FE492 +:106C80002EAB6A184FED8F51FB4EDE7E703C5BBF22 +:106C900037F4A5238C1560F970AA5E1984322B8F06 +:106CA000EB27B12558DA6938CE09A5D7550AF3BCC8 +:106CB0008695B50712098E53C427CF737C1BF4F158 +:106CC0008BDCD22A9DC3F921C159C3E11C885EFF28 +:106CD000DCD2A0CFF7721754E92E1AEF738267093E +:106CE00087C7A08F0F724BDAF56CA49FCF640DE5B8 +:106CF000B9CCF46D4057C593FF7889591F5A28E6DF +:106D00007B74AC5E83F848CAECA5F5D5BC5E66D64C +:106D10004F6ECF13F214D6D8360DA51CFFB75220F4 +:106D200069B81F005C16FDF21BA2DF6F89F284C2F6 +:106D3000FB0790547912A793E5F09D2BCF66D12BDA +:106D4000FAF889BDD8AE013EE764FD26E006BA1820 +:106D50009EF7FD98757EE47D7C6FAC737ADE8306CA +:106D60009D8CC89B3A383F4CC89309AEB1790E311F +:106D7000FFDE72D4CB9AFF64675B4878723A57BCE7 +:106D8000CC8FFE7F660FEBA80F28F654F28318FD18 +:106D9000CCF17456A05E60E297F134BEE097AFDBB1 +:106DA0006F469ED7820FA37FE8F7DABC38FC34B673 +:106DB000EB3E839F26D3B87BF9BC07A2DF81F8A006 +:106DC00054AC536C69F463F0E784BC7BDB5D525CCC +:106DD000BCE7117C213EFE60728B79B8DD0F7AC270 +:106DE000FCBC3874A51648DC6FA5EF233A30E8DE0A +:106DF000D1F5D3769DCB97321A4FCC375BE0DFB01D +:106E0000770C7A36F0B85ACCE74F422F80EF17D381 +:106E1000B8D51C9F71E85AD0D980E357D1F882EFDA +:106E2000E630309C8747F96BB0F9178875EEB307E9 +:106E30005516413B4EF1B8B9FE9213BC2DCF241F1D +:106E40008DF1BFD5B5BE4A8C7F07C12FE4CC9F72B0 +:106E5000F97E9994C9EC42FEDE49DF0B39E588D210 +:106E6000671D7D27E4E8D7E52FE61BE2FE1E2923F8 +:106E7000FBE5386371F76D45E6F6220B4CA6F75D2E +:106E8000223ED7EA194FFAFA789644F1B7E64C1E3B +:106E9000FF68F5E67A1BE0FD174BAE9944BBAFB037 +:106EA000DF9F03FD08E331CF835D81E55F1AD75192 +:106EB000A7483AEAC78AF0A763DC0CCBA473D3C80F +:106EC000DE911D550CF577C51B06DB0769E5F02142 +:106ED000D9D01F61498F8EEB64A83738BD3AAB8596 +:106EE000F2A1DCD04E5A07415F410E3C3BE27F9657 +:106EF000FCC6F0B73FC9E4CF8CCCE274C102698410 +:106F000067C36F60D407C37BB4CE0ECA683765DA37 +:106F1000C288BF84ABF6E88950FF5263A718E97FA7 +:106F20009D3AEAF9EADD8CFC88CECDBA4EFA2350C0 +:106F30005C8A87B103152F50FB6E10D809D05EF51F +:106F4000F1B82CFEA19EDBBD68AD4D87EF9BABE594 +:106F5000302A9BCDD52B6CDD68D76ABCBE2957A6DD +:106F6000F5FB627C12D57B62E8E057B86E57727B06 +:106F700007EDBFD1B511473C3BFDF8C19FDEB61709 +:106F8000FA49AA497027026A5A333BF313A07C7767 +:106F9000DD56D2EF8E5FADEBE8EC3C99119A8AAEEC +:106FA000EC56BB4EF10B75DDB3E4EF3BE9084D1D2C +:106FB0000E783EB1BE93EF3F9525051929513B262A +:106FC00076BC51012E1F7E79605733E2A75B524F8A +:106FD00051E9086F41FC9CCC50FC0D30FEC9AB1E42 +:106FE0001A83FD77AF5CBDEF17F8FE2AC52FC1F3FA +:106FF000EE5D2AD955DD39F7785699E44FC538A5A5 +:1070000016C73B3E76553EE225A9C0AF24A622BF57 +:1070100076DF8F76D4897593294EDD9CB1DDB3027E +:10702000DBAD7ABBE43A68A756CAD3303EA47ADB1C +:10703000083F977975FD14F4FBC7D9A1CF918F173D +:10704000D71EC8477A546FDDBD11E33B977DF55DD0 +:1070500082FB24534FB540D992B15EC5E7CDD51B15 +:1070600054843798B1DC3616F5811CF514CAF366E2 +:107070006DA37A053CBFC26BAB5A9DD21F1FCD8F4B +:10708000B1D9A16B11AE26CFAA646CF7FBFA10B48C +:107090006BC9896F3F260BFC555CB37DCB72A48F07 +:1070A0005DAA1BF1D22CE99EE5186F5F9CECDFC650 +:1070B000FA7FB72AC0EDD725B5B0BE8CD687E4CE0F +:1070C000A843FFD68E7AD589E17CFD2AEC4C7598D1 +:1070D000E2DC9367E5A406E0BBABAFDE4EF667C526 +:1070E000354D1EE4CBE68C5553115FCD229EB12A5F +:1070F000E0D882FAD2973382E9D8BE7BB3BE99DB5F +:10710000E92A433B7D203BFB24D8CBEE61D1E7C18C +:1071100000DF479A57C2FCF1BDEFA1A363E3D9CBCF +:10712000ABBE3706EDE556C32FB04B25F9D6BCD420 +:10713000D94EC6994FF74CC17D7FA7C78DFEA4F7E6 +:10714000B49CAB03FF33E82E27F05F4B774417C99D +:1071500087A42DBA1DCDDD4ED2233655BCA0C693D3 +:107160001F4F2F0EDD1830C945A78FFB41705DD929 +:10717000B5D1758CFDEEE4E6B6FBE3FA41C4BA6E18 +:107180001FFABAAE24FA0CF0FD97858626C71FB009 +:10719000F1BC1A7D79821BF92528ECE584A52CD752 +:1071A0008E72D9377C0BE6CBE882DFDC136C65F698 +:1071B0001128DF656EFC8B3C9B10761927EFC618F3 +:1071C0002F3448BE4D2826DF2636CFA6C7A18FF91B +:1071D00036FADDF6A9FE6D5E025F27FD76DFF4ADBF +:1071E0002DA6BC8B5D0185E034F2707A26308A4B87 +:1071F0003B43D76DC881F9BC2EB15E693A02A7A5A1 +:10720000E44C231729ED999B143FBDEFC9517BD75F +:1072100053FC4B9371BC6B31FE08FBD2E46EBB3563 +:107220009F46B5E6CF5CAB3DCB22F0BD7BB9AB76DC +:1072300018F47FED20F9344F04AC792903C9052FE8 +:107240003B955C0674D75D573E4C82FA8F855C880F +:107250005DCF7F12FEBC4ED04F30AEB807F413ACFA +:10726000EF05FD04EBFF2CE8A247C46F0E55ADCE31 +:1072700027FC95302901ED030C36C3BA3705B89DBC +:10728000B47B366F3F04BA7F2E1EDD23DCA8F721C6 +:10729000DC17F2430E0637C3A0FB10FC316DDAE7B2 +:1072A0005DE7395D8665E942E3358BF1DAA8DC53A9 +:1072B000BF598C17B6C463F76932F15D20ED454FB5 +:1072C00086CF3CDE7AC24FABC39AFFD3ED9BB41599 +:1072D000F5492887C9D0FE3D4187B1E33BCFC99628 +:1072E00078C337025C0F73DA3B29EEE03CA7D0FB92 +:1072F000DDC26E8AF6CFE3FCD8BFCD15D54BFFDCDF +:10730000FE0DBCA5C86D2569DC6E776F9B2294438A +:10731000A84FC874535CD8D0AB55E65690BF6DF9F2 +:10732000193C2EC7C297836ECDE49579AE2C68FFC9 +:10733000EE5E7B16EE0F3F4A0E798230CEC1746549 +:107340000CCAF1EE9F862E735F202E020BECB179F2 +:1073500068D451A21C6123FE8CD8B01EDBBE7BEF2B +:107360005B2371FFFDD13E9598574FB7852FCFE82E +:10737000DF2E279FCBAB09FBF612DDB686246ABF52 +:10738000A45A0A7BE19F8B1B8FD3FE7373A5ECD7A6 +:1073900048CFFBC50D37A27CD164FFE5547F93F63F +:1073A000DB937BED384DB6F4CE15EA14A82F4D5F74 +:1073B0004E695497E68F127EDF10ED77EF168494B6 +:1073C000962CCC7FE9BEE146A83741BF5B504EC149 +:1073D000CE8A7C70527B3319E1BE54C0F5238735C9 +:1073E000BE6F948FE7C78F9F9E407A8883C73FCE3A +:1073F000CE1D9F0FEBB854EA4E467D3B3BFFE1E5C7 +:10740000F619889FD3186161B37FB7614B208BC693 +:10741000A3F977EFB387519E43EB31EB707EFB14FA +:107420003F50343BB8F2279E5388275CAF0BF0EBFC +:1074300060EBB53447D21326829DD470FCA65690DB +:107440002B91973F5A6EBF0AF0C3BA6F6AC53C8250 +:10745000FCA796AB57917F9DF4A5FC973F5EAE933A +:107460007DC6F7AB437B3FAC35C78163F97CA0BCDD +:10747000875FE40F2D0EA784CB2E18876BC2FEE327 +:107480007CFFA8E8FF50405B988FEBAE69E588F77A +:107490001363B9BEC802E583C8292E3782117793DA +:1074A00013E8A2727FF7C5F1E6D92DD679C23E7BEB +:1074B0004911DAA9EB2E1F2E7BA3EF5F11F4D12423 +:1074C000DA19FC1AAACBA03806085E15E30EB48FB1 +:1074D000038E5501F789A4D08FC8EE9DA8685BA0E4 +:1074E0005DD0A7CCA5FC0F74D003DC41D5A5A09E30 +:1074F000A666317F423ADA8F765DEC57B6F3D02834 +:107500009C9F4AFD34793E4F46F97E9388A3DC74F4 +:1075100031CF2FFC75F5955B783000CCAC69C23F5C +:107520000EF3DB2FC677D6AC71603B06FB50EE0C3A +:107530006AE7758C12762AB40B7A3EDF9881EF35B4 +:10754000B53717E828589DA0A01EBF2F89B5215D2B +:107550003835877ECA14FF5856E3985B0CEDDDB9C9 +:1075600052EF30E86F83CB367723D497C07E8D718E +:10757000B45B74C787E6F62ED67B7F05C65B6A1CB4 +:107580000CF5A525758E0FCDFB37FCDD6737D9CD02 +:10759000CE45CAC60C93BEA066DA2DED9DECBECFDB +:1075A000E41482CBF25CCDE7791B86DCF94640DB44 +:1075B0002CE8E531A497F27CBEAF767B38DEBA7D4D +:1075C0002C2C492817B89CEEAE959251AF4B02F97E +:1075D00081E2C3796B83CE5CF1F06553D0EE81D547 +:1075E0006ECB4D277C107EDD158C0DC3BC13C4976C +:1075F000295FEA168F6D6EF19428BEA04BC2975397 +:10760000E837B1F8DAE0DAA361FECF92E9096ED982 +:107610003D38BEFAE3C745EB09DDF7264CEF8FA7EF +:107620004DF9DC8FD454B36D24EA0777E1FCC90F20 +:1076300018A27938814EB8DFB26D0CCACF77C57EFB +:1076400068F871005323CBE2F8BD8D7D71F7ECE053 +:1076500061C437D87111FB703664BF46AEC6484E60 +:10766000E6BAE57018D6E590E2B7233C875224D6F7 +:10767000260D2EC760BD4FE07A0F241716C7C8F736 +:10768000BE78D610E1BB22A4521E77CB6846FE9688 +:107690006732457E6F8D14C63863BEBCA419FD31B8 +:1076A0006780CE797E396B46795021D6A9796AC335 +:1076B0007BC3A1BD57B2F919E878CBCE49240F9B03 +:1076C0002694513FAC04F6F44B30DEDE9642F26273 +:1076D000B49DE138959EB3577E0820EAB941BEEFCC +:1076E0007E9BB937C0FA2C651107EAF937B3DAE4A3 +:1076F0003C183FD1BEEE36D41392D47F9CBA1CBA4C +:10770000BBA77DF5BE2A281326F0BCD01BE5DEB74B +:107710000A81DE9CAF7E7BA51BF09762D34BC6032C +:107720003E9F2D60FABA4CCC2FEA5D1480F78D3F56 +:10773000B76D6D04C3B027F001ED63D71EB97E5558 +:107740004256346FD031F7E00AF44F1AF8BFFFCD3C +:107750004F7661BD12E39DA8DF083BC488B7567A17 +:10776000B95FBE12F5009857D349B6C5C5F143714C +:10777000DB34FC37C0FFF7F3B8BC4ACB5EB9E19409 +:10778000F0535DE6E1FDC9D05F0D7122FD9F847A63 +:10779000715A4F6C5C96C779C9FE81AE8687776B4C +:1077A000A457855CDE79B84F16D829AE7BFE3CB372 +:1077B0009F47D87D7DDF1F3B1F673FF85B950FD547 +:1077C000F378EF80EF15FD36A4DF87E65F918EA991 +:1077D000E4C3C65D311CF3AEECB8AB00FE4E833E95 +:1077E0008A7471F73C4ECFCD37902C437E4DC175D6 +:1077F000BE476A4B9989FAD42E99A1BDF6B1EF0321 +:107800000DE3434D5ED6CB806E4AAFFFAD86FDA43F +:1078100056B15A19F584795CAF74EF92EFC56DAC2F +:10782000C9F357CAA7513BFD0B4D72E2C83C9BC53B +:107830006F3CD0F786DF38F6F992B97CBE7D79CF00 +:107840003B659EF7BC53F821DF61611EEF3F658900 +:10785000CB6138F7EE498C5D77CE47FEDD58BFAF80 +:10786000D1EEAFED677EA8BE929E4F3857457AFFA6 +:107870003FD5D750BDB3BE96CA3DF57554EEADD7D2 +:10788000A9FDF4BB18F1C7C72B13C2EB611E1F275C +:10789000467E83F92D7ABAE2C57C1724009CE7C99D +:1078A000AA2B49FE3449A109C3F0BD94C4F07C4B16 +:1078B00053F2A9CE2E6A9F49FE3766D73DF8BEA780 +:1078C0002193A17FE984A25F9A82763618315BE02A +:1078D000F999CFC2540FD980D9411E3D3F868F6F91 +:1078E0009FE9DA82E36F48A99DCA80EF5BE7DFB9C1 +:1078F000CD0EF2B1B97D47E45318E777AF4E588506 +:10790000B98927257D0CE6D1E5FC4BB803E31FCBF5 +:107910003E8CF8505E5C73E48E954EF8EE28C65CA3 +:107920008CBCE4E9D1F808D3031D35A3617EDB12DA +:1079300044FC27B71AE3B9F6A45A0FF75B7F6FE54B +:1079400061685F7159E84EACCF7DB56805EAD51521 +:1079500017F1FE0E1DBD7A27CA9B7B126B3D204995 +:10796000D98F8E54ACC2F7F764F1FE1BFFA56215E8 +:10797000BE97AB58B093FC4FD7BB1594DB1EB0132A +:10798000605E9BAE9E344C81E7C30B65B1EFC12CAA +:107990000CB90124EA54EFEBC6F3154BD09E03FA61 +:1079A000B859C8E93EFA07C48AFDDA8EFAD99DE9CA +:1079B0009DE48F6C1DA32F0B727D81F4B066FC17C4 +:1079C000CE59D2297FAF8CB9331EC7F33FC522EE03 +:1079D000E66621DCC715A31D0BB1BB603D829F2469 +:1079E0007B512F503D768BDE45B26F94682F6369D3 +:1079F000D7CD7E0DA657BE327E1ADA87BCAD8BE995 +:107A0000F998C7AD883C6E8999FA43FBF18E908650 +:107A100079C7C741CFD061BC7CD796C8282FFA67F9 +:107A2000CB9A91EE406F60287714D4B726F6E7C75B +:107A3000B290556FC98FD133927C56BD4411F9E095 +:107A400076000EE1B52BFE9747A07C1E25717A6566 +:107A500087C3186749627D7F5E8CA72C13F3796911 +:107A60005E2AF17F8EFDF87E8CA7D6AC4BF5A27D09 +:107A7000381DF5618CFF9E0E6F4841BF4AF8C11951 +:107A800066BDFD67F3542E77C20D3D23F03D8C801B +:107A9000F9668D2F689D18BFBBBB6036D1EF1C45C2 +:107AA000D0AB7E6387960DFB6B9D119FBCA103E954 +:107AB000F368AE41BF0BABF17D5F1E895EDC81FEDA +:107AC000CF81F3460AAB6B28CE2D8BFADC0E8CBB34 +:107AD000C94BFD97237DFFFBAB1F7524A68B75A5B6 +:107AE000F1EA56607F6F4ABCBEFE70DD56D46F026D +:107AF00005770446C2BC1605AB28FEF7E55C6BDED5 +:107B0000F2895C1EE78DE673DFAB60DED14F0BB808 +:107B10005FA93C575F19F4F5B7E38CF7465993C951 +:107B2000E3D595C08D6361BC6C1BD773B2677ADAFD +:107B30001B68DF0ED9BAA19EF24C5A3BCAA117C4EA +:107B400077959EEFFF0AF39A60ADBC8A89AE7BEC15 +:107B5000911528B7CEE0890E58C2E15A649C8AFE7E +:107B6000805E550B13DDB2B7C79BCED9A53137E97F +:107B7000C73703DD46806ED7789EFA15E915CC64C9 +:107B8000175D17A57F8DB103484FB34E5BF9E5FA3A +:107B90005E6B7DCE396B3D8759ED9A3CD55ACF77D8 +:107BA0005BEBF33CD6FA7CAFB5CE1A39FDC3EE41A0 +:107BB0007A7FECB9087A62F02FFCDD5C6BE5979C6C +:107BC000AC6AE2C724E0478CC72931E727CE749C12 +:107BD000253FDB831E467EB6244F7017EEF36B8E77 +:107BE000C80CF372746C3805FD2B12F98F16ABA319 +:107BF000E706A6501E797702EA512AF3F68D3F96E2 +:107C0000C7E570DF0141A438A09D33DB41F6C862AF +:107C100066B53FFBCB197602E54CB1582F67E3CF31 +:107C20000328673C97C80CED0DE6E7F3B2C17F1C53 +:107C30000F9DDA6684435329DFCED968951B6B42CA +:107C40009120D2D72DA04F7B33486E6928AF155DA8 +:107C5000628F23B5DD6D6D7FD957B7937DE4043C0A +:107C6000617FB1786AF105491F5000405B2AE61137 +:107C70006D6DC6F3AACC6FF7235B3057C863D64B44 +:107C80009E2E9044FE720BE5EF9F65367F02EAE37D +:107C90000F737D1B7333C81E8A3D6FE6ADE0E7CDE1 +:107CA0002E035E46BF7DDD25C7D19490DCFC39D81C +:107CB000F321B43F12EC41AA270499AE6751BEDE0E +:107CC0006DF34662FB4BA9FD86BA5A92E78DC23F1F +:107CD0008CEB817EE72ACF2B3DA930F63AA13755B0 +:107CE000A92E1DED5EA0B34FFAE64BF88DC9E31344 +:107CF000F68A9107129B177EF73CCEAF01316F5386 +:107D0000FE9C66CD9F3BB82280FBACC4F7E1C679F0 +:107D100007B7A29C6CBA9E897DFDDFB71E00B9F43F +:107D2000E8C13FBC550EF3ABE990FC18BF7D747BF6 +:107D300003F937D49D92BB00D6E3A271BD6F95A322 +:107D40005F2EDF4E79C74DE9A31EBC18F1EC63240A +:107D5000BFE7F9826B10CF6BC2095E6E376929E805 +:107D6000E29BC98CBFB08CFBE275C25E06FDF98D4B +:107D7000800397A0B62B07ED244DED453A181EA9B8 +:107D8000EDC6BAAAD9FD612FCA91DA6E5C7745C3F8 +:107D9000C46178DE919183FA7143C55A1ECF017B8D +:107DA000EB22A4E7D3F60F109F41F8EFBCD887C9A8 +:107DB000BE28B0C61D142F3FD7745D4C3CC1D81FE0 +:107DC00015C6FB319EEF9A673DE7D483710607FA2B +:107DD000C93E20FDFB0B98405A2AEDD7741E0CFDBE +:107DE000FD4897E8EFC77C5FD44775A18FEA097F0C +:107DF00079FEF76D73853F48C4099E5EACED9F87A1 +:107E000079327319D1C3B41E9DC7CDE6723FCACC77 +:107E1000D33CBFB222C19AF7659473E6723A1AB2A4 +:107E20003D60B7DA0385029EA50CE87A62FFBCFAD2 +:107E3000E3F3AC719A26CF9F777E7808F60611DBC4 +:107E4000C2B913C9AE2DBD7EA507EDAE35D92ED270 +:107E50007F1EDDFE19D1B73360F71730A4F7EF7C32 +:107E600086FBE35AAFC290DE9B33B6CF25B83CCC3D +:107E70008D7239359DCBE11AB0476C509F17E6FEE5 +:107E8000EF351AA3731144E1A3284599FE0C7A7EBD +:107E90002EFBCE174F79918E3B35F403A781B8A006 +:107EA000B881A05B9585BABAA09FB460129D2337B4 +:107EB000ECE2352CFAD797E72CECEBEC69517D71AD +:107EC000CE57DFD5B6E13CC01E467E59D321CD88C2 +:107ED00067E74D7BC76A573B35BB251F1ACFA5996E +:107EE000DF0F9373B8DD92610B37A0DD7243DFF9CA +:107EF0003C8A0F37796DC26EB5917D0625B53FD3AB +:107F0000C3286FE44CC78A2EB45BCE7AEDB5E8EF98 +:107F1000FAF8C0BD64BF2AC0C7189F563C201F9006 +:107F2000AF7D8AD79911473EF4887C6C8C3DD990FF +:107F30006F6F8AE66733E4F71F74A13FF374BA4C9E +:107F4000792EB788BCECE7841D7E8B97AFD72D1EAA +:107F5000BE5EB788FCEC787281E490D87762E5C3A6 +:107F6000755AB5250ED95F4E58E5C3998EDF681A4C +:107F7000B46F433900F47C6D81384722E4C5407109 +:107F8000C9331D32F73BB93DED32F59337AC0A9E4C +:107F9000BB1759E393F6B6459678D45F5F9E70B9E8 +:107FA00061C87FB54FFE5BF945B5D712BF283B13BB +:107FB000D04308FC117E0AF1587344F6A31BA68F28 +:107FC0003FDE31F82356FE839C2739CEE5BC49FEBF +:107FD00077E3F3D340272DC437B5EE9964B7D818AB +:107FE00097FFE126E423837F36296185E80EE4FECE +:107FF000431944177977E1FE21E82276BDFBC97F5A +:10800000DFD793FF6B0AACF2DF58CF58F96FACEBB8 +:10801000DF5AFEBF386F3897D720FF312FD758BFB0 +:10802000F7B4905E60CD53D4A429D13C45C32EFA59 +:10803000F1E1DB5760BEF16D39C1C602B45F7D3C32 +:10804000BFF033D1CF6D39A1667C9E7249DD04B497 +:10805000A3D90F795EE2FDF89EF21243F7E1387D75 +:10806000EF77F2EF8DF771F25697923D23ECE5D85A +:10807000F25FE78AF303227F15E07AB4C092F7C873 +:10808000EDADFB0FDFB942E7F9B3DFA7F7225FB22F +:10809000CF5ED3D76D457BCEB0D7361D5EB702F32A +:1080A0009198ABD3837A71534332F94F96CEF38ACA +:1080B000F873D8D306F83B76D5DC06942BAE4D3654 +:1080C000A21F230F69C7E13BB68AFCCD5D84A702DE +:1080D0003E9E612F3E76F89B2B445EF78F089E8074 +:1080E000C8EB16F6E536FC9EE379377DAFF1F9185B +:1080F000F6E833876B09BEF933B5BDF8FD2D687717 +:1081000099F8FCD777A7258AF3EA167F6D5226DF08 +:10811000CF6B3CA00EA17DB7C4191E1B277EDB547C +:10812000CEF7F566297E9C74F2ACDC2E84AB3C372E +:10813000320E8F82547EAEBA45DEF30A3AD723F36D +:10814000BCE7ECF5DC4ECCBEDAD68E67D25F58C801 +:10815000D76D203B71B8A697E0F74BC2321B8A5D02 +:108160009893D548FB841A007DDD8BF37A8AF7CB90 +:10817000FEDFB613375DBD9CECC4B3B00FB138F66B +:10818000CF9CAF86A964FF544BE427543D6D1B314F +:108190006E5103FBABCD6DB2FB62ECC1C1ECBE2AEC +:1081A000904F946704EB1018417A4737EAE3352182 +:1081B000B01FD17E03FBD1EB6671ECC30317B40F84 +:1081C0005D0E6E1F36837D887EA858FBD0C5DAE62B +:1081D0002A5306B707D7E2BE1CC76E6EDE59166378 +:1081E0000F6E502F640FD6964946BC9BC75B66AA9C +:1081F00074AF00FD217DCF4AA2786FECFD2E4B8538 +:108200003F1EFFFE9CF36885E23C1AC3BC9FE4BF9F +:10821000C5B9B4DD1ECC9BAD12719AD603BB18FA5A +:1082200087AA32C11EA0E7CA236639629C4B5B3A1B +:108230008FF1F8733ACFBB3933A1AA07E3583A1B41 +:1082400091259BF2E6EA8AB9DC3893C1E546536A88 +:10825000C89365D22F1BC5FB268761E7321DE3DE7D +:108260006F5FECDF6A3E0758365F31CE1706E79343 +:108270007F56A7F177CFD616CE9F1AB5678DFDC270 +:10828000F8EEC6F95CBE2C9E2F89EF838BB13D1BA7 +:1082900021EE1F7045C2B651E63812F72F1AFEC6FE +:1082A000A35BDB153C57BE569C23610FB759EE65A7 +:1082B0005921FABD2D475B817095E768D55866DB7B +:1082C000D6FF0AFDBBD963152FFAC79A1D91DF4867 +:1082D000E49767FE6DA9749E6A1CD2D11C688BFE60 +:1082E0002F9093E3D04F99FBF03564CF3E59CEFBEE +:1082F0009DCB6AED480F05AC8DCA6FCD0E7D13FB8B +:108300003F38E17AFB08803710286BC4B27876706A +:108310009D81177E8E8FD3CBEF6786EAF039E85DBB +:108320009407E2F48549DEF7A7636B7CE427E51C3C +:108330006F2B73B47F447CAD9BA9D5633F79B38326 +:108340000D34CE40E705C5BAC03ED584EDDEB6B5E6 +:1083500075A68CA3F3F12D1C3ED63626CEF978E314 +:10836000BB23C22E3C9A0CFBBC894E9E2CE174921E +:10837000B988977255B800F3A45AF1620C28F7E453 +:10838000851E41385B33973B705E4D8B00A62CEC0D +:10839000BFFBFE0C985F8D4F7A5E1A0625D23EF920 +:1083A00053BBC93F1BEBE768FCA5A8EB25ABF09ED0 +:1083B00094A8DFA37415B6B727F0FA53474AB6E37B +:1083C0007E5DE315E772DFD1BC66BA786E3E971723 +:1083D000F7E46ADB112EA08B1D38FF13B93C8E1712 +:1083E00067FF7C86D68985EECF9068DD7E1C6FDDC9 +:1083F000603D3AF139ACC76EEC17D6E359A2E741BC +:10840000D66320BFCF8BF3393E7FB0B08F3F7E66FF +:10841000E60F80FB25AC5F00EE833170BF3200DCDD +:108420003F17701F1674F4EA50E8C839E5C1F72801 +:108430001EA0277AA5D998AE02FC2073FAC6B8FA16 +:108440005CD405D15E948C757D6E279DC3704DF90B +:108450002DDA8D6AE1A71DEA5494FFFE31E8AF3AA8 +:10846000FB4AF1AAE6E9A8C774DF8AF5596F7D6770 +:1084700085FD7A60EB0CBEEEFEB7BE437A56F95826 +:10848000FFE512F0655BF1971DEAF5263FBCA013EE +:10849000C30F0F12797B0DC050DE1727F8DF1427AA +:1084A000284FD23D1827935FFD5307C6C98EF6C5E6 +:1084B0000196ACD14647C7DBF186B40DCF0539DD57 +:1084C000DE8D188770BA25BF8E52FBB4DE9402F0A1 +:1084D0007D319F4530A7A3EF5C12FB4F8A13940FA9 +:1084E000E7E33D50FC5935C11B5367995C7F04B9E4 +:1084F000F47BC4F307F3B9BC76BA35C7481CC7038D +:10850000E380DC58E4B6CE6B9197D79F58F8797525 +:1085100033DA49EE603EB51FCDE1BA81C1BCDC382B +:10852000AFD235185F3BAA68E9B87FEE58B8644D02 +:1085300000E4BE9CDC48E75B549FF5DC9D519E1532 +:10854000F15A369DEBAF005F52E1487CCE04BF0488 +:10855000930BA7A2DCD0422E99DFFF53C8F7CFCEF2 +:108560008BE2DCFF63D82BE529FACAA029AE77DAC3 +:10857000E396902E366D297F14ED96B31D17A5A2B4 +:108580007CEF34E26C31F1BD33633A75B4D34F679D +:10859000D86BB7B8FBC7F9584CFC2E36DED721E4B0 +:1085A0005334AEC7BC18D7FBAF8EE76D7071BD30CA +:1085B0001FF38660BCA45B77330C99CA7704299EAD +:1085C000775C7330FD6F18CF7B4DAC8F5DE1F9693F +:1085D000A01351FCF5F98606B2E35E2AE1EB31B94E +:1085E0008CD34575D0D097F465690077396010CF8A +:1085F00015C8ED3F51315FB37574E761D4D39A1656 +:10860000CBFEF530FFA6F6D59BABA0FEEEE52EF235 +:1086100023BF9BEA4D46FBBED5BDE1528A1BEB232F +:108620004F1F76635C9CD3F54DAFBEB703E5F61BD9 +:108630005ECE7FFF567AD769B483E05B3733AD9364 +:10864000A2666FC4FC343547A57C29D33AD07AE3BF +:108650009FC3D41EF0AC4F9D427A83370DC7F5F00F +:10866000F61E76AA81F24A800E14733C59AC932A06 +:10867000EC0FF90EEDBEA9B89FB96537F2A5B1CEE2 +:10868000C6B9C4D8757531AF65DD9D952B280FC966 +:10869000F033390BACEB96546CAD83BD6259B7DC4B +:1086A000CA15A42FE7029D78F15E00940750CF9B76 +:1086B000EE0A4700BE43D1FC46CA3353055C81D461 +:1086C0008D3AC27D88B97B91BE14AF951EF2475496 +:1086D00035A662BFAED42C8CBF42B723308ED152A8 +:1086E000E8B2DC8F629CA733EC9BA397746AB8BF97 +:1086F000835EE6463FD1718C5F3AF01C5E8382F563 +:1087000024CC0AC860FDCED719F755ADC5FBAA2405 +:108710003C6FB73582ED4F6732378EBF3620E4A805 +:10872000FECE0ECC7F19EA3D0129C7BEBBC37A4FEE +:10873000C0C61DA8179EFECA88E7D6EF40B93C7098 +:10874000BCF71F569BEF09D857F8F94ECC97889E77 +:10875000BBBCFDB7E67B027A0A975D6EBE2760FD63 +:10876000CF1FDC61BE27E087A527569BEF09D857AE +:10877000BA69B5F9BCE9AE639B578B7B027E42F2C6 +:10878000739073D1BF2EE4F704F4140EED9E80FFB6 +:108790005B7131231E06FAAA9E80FA6A8A8DEE79F1 +:1087A000018B8CDFA316E38FA817FE8407174A42BC +:1087B000CE0FA89FFE12F79D81EE3788147A795E5E +:1087C00041FFFB0DDE277CC69CC7C6F5E2E7B1433F +:1087D0001F159AFD5D87ADFE2CD0AFCE14925E1CA6 +:1087E0008A98F55E78FE8978CEF87D93024E1177EF +:1087F000418F30F6B38885B93E041200FDF68BDC5C +:1088000061CA5F60FAD554FF78D7A3EF61FD9E86F9 +:1088100044AF4CED3A19F2DB7F1672B94AFB3BB616 +:10882000F7318E473BF72F7E5C220DC7F3AF513DEA +:10883000AA7727D2778B03F4200021B5E8E655EA22 +:1088400098A81E754911D30240DFF73898A13F1050 +:10885000FF108A899EDDAB502FFAD861E5AF1B98D7 +:10886000D17F32E94D861ED6FA66DD0AE42F432F0A +:10887000CA78AD8EF4B081FACF38B27E65B32BAA38 +:1088800027013C11F42B2B057754A27EE278EDFEF4 +:108890006D6AAAB53DE50719FDE9EBB7919E18F39E +:1088A0001ED6774C91C98F39587B56DCA7C78C2BC5 +:1088B000223DC62BE2A8D6BC0C63DF8BDD5FEF291F +:1088C000E6EBF2AF01ED1AFCBEA86BC39DC138ED1B +:1088D000A61471FDA2684EA707F7CDD631DCEE8E47 +:1088E0006DD755C4E91EFAB914DB9D6E88DFEEA67C +:1088F000BE765BE97C48CB01DE0EFB2F33B5CF2D76 +:10890000E2FCD49A1CDFEFF74E9161FF060384B7B7 +:10891000FB383EC06EC82F9A8AF66AB000CB3EFE86 +:10892000CAE2F62ED8AB85D4DEAE939DD1EAE07CC8 +:108930008F7BB33C2B8EFCF059E547ACDCE8933FD2 +:108940000B998EE73EF266876EC4FE8D38FA60762C +:1089500046D11C7E4EA62999E321D68F3043E021D3 +:1089600041C815E39E36BCCFC0EC27FAA66867C89D +:10897000E95B8B9E5B6996D3B7BF96B8C62CA741BF +:10898000AAED427BA02481D7FFFEB5FD061DFE1D8A +:10899000E28DDDCDF1B90A1D47567FBCE5DE80F7DB +:1089A00034ED5B38DF9201E2B2DF89AED377A8DF26 +:1089B0007586BF9BDB75B1F7736C28EA773F47017B +:1089C000F93F3AADFE8F0D7DFD6A1B70FC3959727F +:1089D000309EDEFFED32A177FB0E4764E33CA297A9 +:1089E000F85AB3F85BAE0D5BFD2DCD6D96F8F083B4 +:1089F000D1F11E2CE27ABC86FAB211EF3CBAA32167 +:108A00009FEE13B48515339C0141EF479FE1EFE7DB +:108A1000283CEF29F6FD6F857D00F4FBA4A05BEEFA +:108A2000A7019AC5FD28DB36A95B23BF8EE46F0042 +:108A3000F80B330F907F3B174C47CC9BCDF3E5D819 +:108A4000312D297F4A552396DF9A1DDA8970CECBC6 +:108A50007EDF8F7A62F6FAC8B8361FD1FF0F8AB868 +:108A60009ECBFD7A82EF910ECB4C70ED11F4D43495 +:108A7000263EFF9D2E36F4E53E7FCF734543F2F749 +:108A8000F07BD3522E51DACDE7353F2EEBF3FBFCD2 +:108A9000AC88DBEB2F15717B3D82F036A53789FB67 +:108AA0000BE2F39191AF67F8D38E6ECD7A19F7A3ED +:108AB000652324BF8DAF37F9D7968AF77DF32891C8 +:108AC0003C782ED7C8BF5B5F766027E58FAE938476 +:108AD000FCFFE79DD67CBBB76A886FFAF2ED8ED1BA +:108AE0007E35A0FEC55EAB41FD6B4ED6E46E07F44D +:108AF0009FFEC6CB3B3DB05EE5225FFD57AFBD4D4F +:108B0000F9A34F083E8BE57FA37C4BE07B20FEFF63 +:108B10005CF08DC1FF9F14FDDEC2FFFF5EF477ABFA +:108B2000D47413FFB39AEDE6BCC1FF78ED2B83FF3D +:108B30003F25FA16FCFF11C235F282FC7F16D727BB +:108B4000F63E1EA3FC83A06FE8F70FD4EF20FC2FA6 +:108B5000170F8DFFE5E23E7E948B2FC0FF878BAD14 +:108B6000FCBF96F5FD11FFF7F1EF330DC4FF351D86 +:108B7000FC7EA158FE4F8D8E975A6CE27FC31E3942 +:108B80003A4ECFA77B406DBA62FEAE8FFFB71AF4A4 +:108B9000B46525F2B111C77CE2B56F6E17F1B5313E +:108BA000C5C84F5338DE07D34FA0FD3882C3CFF17D +:108BB000F997EA3BA03F4EC4F1FBF4C788355E6AE3 +:108BC000C4F5FAC7C97A4BE83CA5CF36A43859ABEF +:108BD0006F38C5039DFF9FC4C71471FF746C1C28B8 +:108BE000361E0A7AF8D2E238FA39C38433C3EEC5A6 +:108BF00075F96FEEE789083D74207F0FCCF32E31B5 +:108C00004F2699EC8DB499A17A7C6EE451348B3C5B +:108C10008A840C5B22E64B0C35AE0CFD3789FE35A1 +:108C20009B098FBB676BCDC5A477CAC417D7163D08 +:108C3000BE4DF0D17DC447E25EA7D838FE97F3451C +:108C40005DF835FBFB4B99C17711FCBF1A517FA42E +:108C5000F8B3EA661EE7DF5C6CD2EB0D7F6862A1B9 +:108C6000E8573C07B89FA476C2FFFD33D1CED0AB06 +:108C7000D811CD6B962BF7E4E66E2179A1335D1AFE +:108C800065916BBA452E19724D9C7B626F59FBD969 +:108C90002EE248F7E46A3FC4FEB68B7101EE1F175F +:108CA000933FB4AD36C584C73D79A17D08A75CA5C7 +:108CB0002F403F19C6411A50FF8D74AA18FFBEE914 +:108CC000DB32DD4361F8DF0C3BE960B1E14FCE22DE +:108CD000BBEE6071D576F48F0F66E7940FAFADC42D +:108CE00073428E22683F23AEDD7488F026D667B0CB +:108CF000FE06CAEBF840EC3BB16542B16107737AFE +:108D0000607A9FDDF5068E1BBB7F1AFA1DABB3EEB2 +:108D10001F278B8D7D503B8978FDA888F349EC3D5A +:108D20005E47C7F6CA284F7B8097B7E01992C636D0 +:108D3000BFF97CE359A1971D2FEE5BA70F890E04A5 +:108D4000FDBE5ECCF16EE469C078BF43380DFDC254 +:108D5000C8BBC738B3B9DF11C21FFA75E3CCC92548 +:108D6000FFDDE3CC0D146736CE03368B387365A672 +:108D70004EF7CC540E106736E9B5A92553E3C695D6 +:108D80008697703D350DDFBF24F0BB29C5C8370C71 +:108D900053BEE1156C73E1D530CFE60E89E4598BF3 +:108DA00097FF1E00E695954C23394E7C9AB0545798 +:108DB000CDE7ED5F0538E8DE0B79099D7F6BB94A99 +:108DC0000ACBA67B6B5E4D0931FC7D14A543A2F551 +:108DD000589B2985315493B753A2F5737A78FEDAFC +:108DE00065BEB01DFDD66B34B5771EE633D475076E +:108DF00078DEF1E3AFA05FEBE32C895DE4C57CB4E2 +:108E0000908EF96767F0F786603DCA3A5653FEE0E8 +:108E10002B21572DEAB32CC0EF3951E13FDC078BF2 +:108E2000A758EF3D291C24BFB0EE9DE3130F99D640 +:108E30006D5689F59E6A231FCD98AF918786EBB05A +:108E40007042340FED3FEABB271E82F5C91774F755 +:108E5000F4E2503EAE838197E8BD23E11EC443ABEC +:108E600087B9916E95C8BD87F11E87356FC90CF320 +:108E7000388DBC949A6A7E3E614DF841CA4B598B3D +:108E8000792980A7B5769E07EE0C27501CFD8858DF +:108E90008F5D3EB61EF3B0D49D32E567E6796BDB9D +:108EA00066A25F18FAC5BC9F247F4304F30D810DB1 +:108EB0007BD19F9DB0588F4C867A0BE01FF34950B1 +:108EC0007F32E7B92CF0DAE87E1B032F83E5BD186B +:108ED000F7D934A71BF9892186795F6B44BE09D382 +:108EE000B53770FF8EF261A71DF50155E4AB331F56 +:108EF000F7C71BEBC8E4FB74C4CB97001FEEDF2A57 +:108F000033F9D1112F53AAC8BF5F0274A0C1FB125D +:108F1000BF236EDC65A075AE2BB1E64DEFB2333FDB +:108F2000D255EB5B32C5015B3BF6D2BAE81D369EEB +:108F3000FFC242E4DF0DE1FDC2E82F8C80C6310D97 +:108F4000CF15733E692DEBDC88F7087BBF75A91F31 +:108F5000E57CEB84E71C586FCD18C1D07FCD6CDA6F +:108F6000013C0FBFF40959E27285F17BFEEA52C35E +:108F7000FC778DC23C3F487731ECDFA0A752C13768 +:108F8000358D129DE35CCEFC0ACAA96A16A472153F +:108F9000ABA552623EBA47FFA65ACECF805F15CF2F +:108FA0000FECD2D3A8AECD72A47EA472D7CF85CE5B +:108FB000DD62A4EA2393DCFAC4D867D49087FC7FEF +:108FC000B9A17089451FD7E8DEF1E839C6C3D56875 +:108FD000871AF69C6FD1E10EBAE7F27F98BE38533C +:108FE000F8BB07D217617F8B94903ED7D6AB8C230A +:108FF0007FA6B0BB1FAB41BDE6F9061E37292E9CEC +:109000005483F397B3583EF9A541AFA1737CAEC327 +:109010001FCA56FD683CE6DD187E8085C1B1DCCFF5 +:10902000F155630A9A23479FA9B2BD817E039FAD84 +:109030001DF97B31D35FC673409B262EA4F3F467E2 +:10904000AB1D463E7BDC739A063E9688C192443C3B +:109050005715F1DC258B6A8AD11E888DE3B236BEA6 +:109060006EB1713A3BF3B49FCF88AE83719F96E99E +:109070007B5A87583CB35ACEE799D003C6015D624C +:109080003FABACB6F2AF13ED938917B8D742C80324 +:1090900023AE6AF849960427929FC46E33E851A222 +:1090A000B8549FDF44B7515C8AF637935D6AF293F8 +:1090B000682ADEEF719AF5F9D955BAF7547F200383 +:1090C000CF0FDF60DF517015D643F47B1907172CE3 +:1090D000DB817100C3AFF2C582AAD5E2FE63FB0259 +:1090E000D43F4670FDE78B1266E84509F4DCCBF50A +:1090F000A0DFE373EE874C5A807C26F26E4F7B6CC8 +:1091000005F1FC06CF2EE0FA5FB6CED8D5A09FA51C +:109110002EB0C60DEF11714123EEA788B89F325AC9 +:10912000273F5F6C7F972CE0FA5FDB6C2D1DC70734 +:109130007DFF128243FC1E8DD7C5EFEDC5B81EEE34 +:1091400047EEF6AE2EDC37CE825CC6F9EB8821E422 +:10915000ABF1FCBE07457D42C3BC475562A7F03C5E +:109160005DCE930F33946B49FBED2C01F82ED86B39 +:10917000B39C3B9813705AEA263EA67D2636FF32F2 +:1091800096CF93300101FA5FDCC1EF4D5A739F3BDC +:109190001FE34195E718DD9B64E4591AFA0CFED2EF +:1091A00022CA8104B1EFB858AD86FB9402FB08EDEA +:1091B00043016BDE65C2F81A920BEE99096E9C4F63 +:1091C000C2782B3DC6D2AD0E720BF71127F61727CA +:1091D000EFD49DC8F32A9A613FA73CCE287FF0F9CF +:1091E000C6EC930D1537D1B98E8F2728E2DC976432 +:1091F000C1C770ADF310EE2B78AF4CD8DF1F3F4ED8 +:10920000BCF90EF55AB1BF6AC25FE0F42ED7EF1277 +:10921000F3A2F878CCFE9A26E671B3F83DC67EFE3E +:1092200083987905B5E332EA372B16887DD5C77C5C +:10923000488F573ADA96217DB4C0BEA963D9D1418F +:10924000E70CF527EC748F152600DA4DFAF9C18A80 +:10925000170208D7D9DA147F02ED93610FD2CF95A8 +:10926000D21809F3CB5BAE6ABA047F62A965DB450D +:109270005E0C4D07B59C069C3FE81192EC179DA033 +:109280005EB388EFAB465CF54C4388A17EA44BC926 +:109290008CDF23A65562BBA5A047215D977A6AF9AA +:1092A000EF5C82AC263CE33D02A330BEC848AEDE94 +:1092B00010D86B473DD43DD6CE52A647E3B029B671 +:1092C000537EC46F093B457958A5CCEDC07221F39C +:1092D000D3BD231520F0E87E0FD646E54DAC93CAEA +:1092E00025EC9483DB1B5EC2F32D995CDFDBBA2097 +:1092F00083F8BB58650E5CDF165F7732DDDF3948D7 +:109300003CA851E2F11E1D6411DE6FDE175F9ECC9A +:109310004232C843ED0F4C32EFFF52F8461E2F2A5F +:1093200003924D072C2F18CBEDA547FCCD09865D88 +:109330008D7CD228597E97E7EB9EAFB4B1F006BC86 +:109340003F618D87911E3213FD98980FE5619AF960 +:10935000BEC9FB16F07B06EE13F2ADDC1EA4FBFFCC +:10936000F062B7861998F7B290EAE577C35E8D7917 +:10937000F39F4DA17BCDDEABA4BD15BEF3D277EF3D +:109380007C7170246E7795EAEE97DDDEFEF6B431DF +:10939000DEF30BB85DF9C282BE38D00B0B4CF66A17 +:1093A000CA827EE7265E32CB67C34F1C2B4F7B857C +:1093B0003C9D93D5E59A8C74966E233AEF17A710CF +:1093C000E32F2CE0BF77714201BA8179BDFDFA6DC0 +:1093D00094B71064DE8D29283FECAB56575E45E309 +:1093E000BF4EF0A9E2DEFFD3F1F3C9DE5AA018F3B5 +:1093F000798BE075717887217E4662BC06C86578F6 +:1094000034EE0292DFC88B3B89ED832CA4A35FC4AA +:1094100018B70C2F2C26BDE68E1D186F781EF77C12 +:1094200023FE0C7C703C59BC67DF5A8DF755C47E17 +:109430000F70FC96E016E3BCBB80F1BC8A0542AF1E +:10944000B4F3F918FE0FE3DE3063BDAA829C1E62FE +:10945000CB9FC7AC8FE18F8FC5C7C1E8FAFE9EF0E6 +:1094600021CEBD1C443884FFDFFC7CF07C143EFF21 +:10947000FD85B7AE6C88FF7B0A04F7E852BEBEB12B +:1094800065F43E7A03AFE5DBCCE76AFEE3F5F295DF +:10949000E21C8EAB746A94DE8CBC9AF3AF9719EF22 +:1094A000DDA5D8DFDFF8F715928E050D7FD6A5A5CF +:1094B00026FE7094F6E12F839EC7FCEE42CAB1D21D +:1094C0006D22DFE672827389711FFE857F87A1435B +:1094D000E0E9E858CE5FAC86FB9D12C7B9598BE92D +:1094E0003CABBFD466C43DFCD8BF71DF3BCA429BD6 +:1094F000299EA2ECE4F206EF8F37C769A697F6F92A +:10950000BDA6979AE244886FB37FECFA68BBEBB1D3 +:10951000DD40F1A14069BFF890E08B0EE21BE37ED5 +:10952000F9A2637B76F0FBE5B76CC073264AE3CE05 +:10953000DF618A1FE0A9B0D4448781287E4B08BF31 +:1095400031F94AB1EB555EAA18EDCBA97D341F273E +:10955000AE9C585C6AEFBBFF9FDAF7FD4E43C4F048 +:10956000F3F9D1CF37C711A6F307731CDCAF9C9A70 +:10957000BF680DE6D5B4FAC64F22755EE0C7E8F7BE +:10958000A519A1EA52F21FB2886D12FA3DF87DE6E4 +:10959000914276C1F36B9BC5BAC796B1BFBB5076FB +:1095A0006CDB0EF3EFA2DC78EC8757629E51D4BFE0 +:1095B000A5AB8CFCA9211BEA1BFA44FE7B97CDBE10 +:1095C000CFF3283F0BD7F802E7A2EFA9E7F7B1BF27 +:1095D0002AEE37329E37958EB5ACAF9A5F4D7EB48A +:1095E0002247E7083C7FAC8EB6EAB5B1FD16655A56 +:1095F000F5DC0D9E6FD279DF33E27EA6333B571C3C +:10960000467BF80B8FE245BFE4BDF5E15F7DE8885E +:10961000E65F74A52B9139E82FE9A8DA8EFE15F4E0 +:10962000C3E1F9C5EF97F23C35B56337FD0EB13AAA +:10963000FE79FA3D2A252C75A23FA926B39DA1FDEE +:1096400093E409137F44847FBF2853C62BBFFBE0FC +:10965000013A78DCCCDFDF28E572BA2995D1B86B06 +:1096600041BFC673CB793B1B18DE9B3AD0789B4A2F +:10967000F93E5CE36BA7FBFF933C9D76FA1D88E8FF +:10968000EF5158F6CD7D629DB3FAF82CF80CF181BC +:10969000F83D8A2C01073CFF277A1EF3BB1A03E52D +:1096A000F9997E57636FE9C8683FCF967A2F1837CC +:1096B000063BE805C403D841FB4B4D76D063827E60 +:1096C000D9D7CF8BF54A7F415EECA1CA67B583D06D +:1096D000FED027C95E8C4FF4CF938D88DF8B6061FD +:1096E0009DEC870BE7C92E5C5463F19F3A31CFD5CF +:1096F0006C077CED3C5999F26273A7BBC2E88FC836 +:1097000063FE46E4873F373FB659F85D06CA938546 +:109710003E463093FDF3EE9810B7A7449EBA09FF7A +:109720000AFFDD5D2BFE6197A0F1ED36E67DDC1DC5 +:1097300007FFCCBFB1624AF41C35FE99FD1F981F8C +:1097400088F689C2DCDC6F25F0FD7F005E751E0D9A +:10975000008000001F8B080000000000000BE57C6B +:109760000D7C54E595F7B977EECC5CF2C504020C9C +:109770001AE026808CEB80930F3084AF9B0F144847 +:10978000D0C9072151B0038A1B10B7A3D0956D75BE +:10979000B99010B249D6C656FAB696D691A20BEB3E +:1097A000C7A6D6AD1FEB76878FFAFA12A291B2A8A0 +:1097B0006B5B232AE247BB54A4B5BBBABCE79CE76A +:1097C000DE997B8749B05FBF5F7FEF3BF991CB7339 +:1097D0009FCF739EF39CF33FE73C937AC08F069034 +:1097E000E9D716EFC803F05FEAC25FF8CE0711CFE2 +:1097F00078000FD517E253FB216CC3FAAFBC340AD3 +:10980000E43280B6AC27F483A500191F666B2E1FC7 +:10981000F5578CA100F0E7BC39A632C7ECEFA227C0 +:10982000D6AB667D01BEBA5DEF998DE375FB5C3EFC +:1098300003DB4A60EB8FEDB30074C0F13D6559B1B5 +:10984000AE027EDD43E3A9D67A9B6F8238F6F7AD90 +:10985000CD8A8EC6F5642E71BF6D9F3FA3D659AEDB +:1098600052B1AC26CB95CD6DC66C1CBF12E08C8678 +:10987000EBAF8288BE0EC7AB2AF3FAE22180C300A9 +:109880004BFA7011D5B92BAA73F1FD6135B7C8A594 +:10989000111F14C7389DCBB0F36C80ABFD1200F5DF +:1098A000F78D7BD05560EFBF4E5D6B3ED7E0B324A4 +:1098B0002C038CC3B20461AA3F4F9F45C967719DB9 +:1098C000C4F51D3401AECF7812620FE1AB99194394 +:1098D00051E2E395EA9B077146E8F39554E5E27A95 +:1098E0003EA88ECC0B63FB627F4577019641192C15 +:1098F000ACCBC6F6B74BDC7F5500629A4483C5E219 +:10990000E3B15CBD5182FBB15D8E4B5326E0FBAAF7 +:109910008D15B52BB15C15CECA3B7505362B86620D +:10992000E23F682F1C7659FB8F9F814BFBF4B148B7 +:109930005F2BB25CC6715EDEBA05DE72E33EBAB77B +:1099400079A89CE187101488BD91719FC2663F3849 +:10995000342A4E7CD9B02A33360AE73B1AFA5E9C89 +:10996000DA9F0E808FF8B901190197003CF352ED90 +:109970003A03DFDF56116E0C233F5F917B4312AE3B +:10998000E3CC7260FEE2FB95D6FB1C7C1F9F17B9EF +:1099900081CAF8094EC2757EC19CEE7A591F0F53D9 +:1099A000E97F06F3F1E77A2442FC51AAA4685F102C +:1099B00048807489E4CAEFDBD385537F44E38FE3A7 +:1099C000F16FA276F0646F283C13E097D78A793F55 +:1099D000A8D6D7D1FB7B6468E5FE167D92F8BFCB95 +:1099E000BD461F4BF4833686F8DDB94CE27E16FF88 +:1099F0002C791D981A3324E203D28D12001BB43E39 +:109A000088E2785FAB8C6C223A3283064482C49F32 +:109A10001FF0B3572F1E1D49231FD6D3136B007D94 +:109A2000ECF0F51DB4DE34FD7F1916F2B58DF63B72 +:109A300033B9DF179B2F93E62B19BEBEDBE28F02F3 +:109A4000A138F221F3CE19C55D5AB2FE5BE6BC899E +:109A5000F1E24D3CDEEACE46A6E3EBE16C87FCF595 +:109A6000EA4FB0FC9E8D40D45534C2BACC71DAAA0C +:109A7000C2DFE6FD53752D8CF23F65A1BE9BCA0F78 +:109A8000EBFA77E8D9FE2CB09CB160E0A6289942A9 +:109A9000EEC0A8DBD78A740F148AFA7706F7B41AD7 +:109AA000F9CC0FD63F6761E4F95D9D4DBCFEAB5E1E +:109AB0009541B7E985B94319A0DBF4CFBCD3631C4A +:109AC000E505672E71B45FF449A1A3BE02AE70D460 +:109AD00057A9258EF262DF3C47FB6BFC558EF25294 +:109AE000ADC6D17EE62737F33AAF7C7A83A35D51CA +:109AF000FC0E47F9BB8B22FF9BE4B1E4852F3BFAB8 +:109B0000CF1EDCEE6877B0A97CF410F2AD5D826602 +:109B1000DAF72CF079EAF0DCC899F99349CF79B7F4 +:109B20005CFA72B54D3E8F850BF95C789528F8B8D4 +:109B30007E32D743BBFBC3849EA63D807C1FCB25D2 +:109B4000083B70E2CF442F65567FECA2F680B48EBE +:109B50009E08B0ABE9595FBAF3F2A3B9915F10FF69 +:109B600012F2198CBBA9DDF7C2429FA09C9E61BD79 +:109B7000A524E4F457543E9B721E779BED7F360973 +:109B8000D8AEA00D8CED1174E481CD2E831231C8B6 +:109B90000EAA5A5EB42BE4B0B39EF3C26E82646F19 +:109BA0000F11B67B8A0CDAFD6448FCA2BD1F86B695 +:109BB0009D27C5946AF70373763461FBAF54A96798 +:109BC000C8EED3C7857CE42D921907C097F348FFF0 +:109BD000813696EC66F30F40267B89444B215A5F11 +:109BE0001FE3861CC40DB4BECC69CFDD29E5FC3E65 +:109BF0007821CE7CE8F6032A527C69343F3F0DDBA6 +:109C0000D79B7D53F1437D632B901E7A3E92158541 +:109C100032C60BFA3A2CFBCABDBEDF0F2F4CAD2665 +:109C2000505205A176925FCBBE430A2EA9CEDD61CC +:109C300010AE390CBE33AE503ABCA0F1BE2ECE5B96 +:109C4000D34EB8A2324BE00A843B79747E9A1488D2 +:109C50002B6300BEBF502FADC37673EAFE3CE47F9A +:109C600017EED920D1ABC472880FEDCF46647A6F5E +:109C7000CC92630FE1F8EF073FAAA2F1CE920D1844 +:109C8000415FEEDC8A94CE0038B2150DB137F9FE93 +:109C9000863AA11FACB2BAF86695E6A971F7E5114C +:109CA000BFD57CD9A17F52C7AD09643AEA6780A1CC +:109CB000921DFFBBADB1D7DF467EB4F9F7A8A4AFC4 +:109CC000BAB4B52F90FDFFD8EFD1882F1DD9A8BF0A +:109CD000F0FDA1899EF8A252B2CF9187BD123DFB43 +:109CE000E0B299B44EA411D75BDCE8E2F56D98F6CA +:109CF00034F3C91393FA46E13CAD817B3D3AD2BCC3 +:109D0000DE1F53C86E7F2FEC633B571370E10A923E +:109D1000EB417CF145DA4F9826F0C5F1A5C0ED2066 +:109D20002B36D98D7CEBD8960D5D38EE94A51ABFF5 +:109D30007FDF6DF87B715D2F155C2DADC5F759BBCD +:109D400064F086D88EB19D3D4AF287CFFB728DD5E7 +:109D5000617C76D6C9BCBED4E7CE1AB11E4452632C +:109D600049DFE03A8C3A2A578B750C2000A67DDE3D +:109D7000FFF2E987C8EE215EEAA81B012FDDB819C2 +:109D80007F9503FCEDCBEFAE33141EAFABCE869BBD +:109D9000EEAA137A6BB875EE36D795FAB4D6E75AB1 +:109DA0000DA65DCEDA5F81ED1B64517EBDFF957D12 +:109DB0004690E7FB26CFD787F361FB454525836EA9 +:109DC000E4CBC4633FDEE7CF4DDBFEBBF6F5DD6BD6 +:109DD000AE0FDF3FC8EF9F16EF4F7820890F503F3F +:109DE000BC744631CBFDADADCAC5E7392D89F22330 +:109DF000C4C72C1EFF311E7F89187FF95451FFC044 +:109E0000CBEFADA3FA46305ECD237B6264C043C87E +:109E1000DF465FDFAB79A554BE5CA33222909F532F +:109E2000BD07F2A18BDA4104EA91DE674CFFA05135 +:109E3000039DF58F82EF71FCAEE5D218188DFA51B3 +:109E4000B2E878671FC965A73B349DF4F0C0CB1F0B +:109E5000B4AA0B00DE73830307B11E29A75FF3D7F3 +:109E6000B762FBAE94FA1589FAB9FB5B99CEC18D46 +:109E7000A851E02BC77EB14EC1F1EE2B10ED8FBF84 +:109E8000FC0B961FA4FBA85DCE9F33F95D7F3AE6DD +:109E900042DB022FD7BD715A2D32F5F6255C6E25B7 +:109EA0007E4050ECE76D15FA4FA8FF8FEACCF351D6 +:109EB0009B787F82DEEFAE718EF7461DC4AB43C93F +:109EC000F1C0F8CF7D3A8ED73046ACFB0D1A3FFF7C +:109ED000C2F2B13AE1B74140AC13D7FD16EF97B9E2 +:109EE000EECF9625E4E414BF8F8A755CAB14F54E73 +:109EF000A7798F5CFF50161D858018F7B9651BD7B1 +:109F00006D9B26CE3B7A205003B6CF1CB68F00A6A1 +:109F10003DD62CBF80FD94BEC387707FEFA9CF884C +:109F200076E1B867F5830AD9D565D0C776B026E45F +:109F3000869336BD9619C0B24DAFA801C5514F9C4E +:109F4000D06D76103DA2248EC3F268D7B6C921E445 +:109F50004FF316D737DE46FC75FAC0B73C1AD2DB92 +:109F6000BC771BE394E62D1E7E6FE9D52ED47F27A8 +:109F700051269EAB31F99515F1137F16798C7574C6 +:109F80009E614B6F88E4D26A9F552F997CD3B3EAC8 +:109F9000916FB7D4087DB6081D031DF7A0B6E4B3D2 +:109FA0004B691E3012FB9A4BED967BC5FEDDD9FF47 +:109FB000DC3A3A4F0385675C84BF5F45B3B007E581 +:109FC00005DA7B4375B67936D508BDE1AB17FBE4FE +:109FD00029BDF7E7E23C8DD2A485A8DE20AA804BFC +:109FE0009C1B571EF9E78CA1E03DC992E7B1FB49E4 +:109FF0004E3C59A5EF909D6E3A96B75F1D9794EF32 +:10A0000068FD8BEB944949F9DE58FFA225DF817A80 +:10A010009B7C6BE6FC0D8578CE502FDC746CE27E69 +:10A0200015FB3578CC798CC9FBF5F958CE302693E1 +:10A030005DAC3B56B05F998BF425F4CD55EBA9DEB2 +:10A040009A27722CB09FE6F1F8B41DA40F3C3E296C +:10A0500044F1114BDEEFAE4779F7D9E57DE17E3A69 +:10A06000E7967C5F716CE17E63FE85658F4F778F2D +:10A07000633D8EE301E91B8B0FA09330A23EE1729A +:10A08000F3B1F1EB3B892FBEF0626E9F2FE65F814B +:10A0900084D0FC75C7A6AF57265E7CFDC8A7E5CC6B +:10A0A000A752B1CFA74D3F21D56EDF502FE221AE91 +:10A0B000EC76F67B553FE8B134B87A778DD07BA744 +:10A0C0006A4D7B5666C94FF87A9E2724F66366BDB3 +:10A0D000D01B031EE33692CFFB0A84DDB1C6F9AB79 +:10A0E0007A314E9D39AF4DBFACA571EA2C79BA805B +:10A0F000FF09BD184FA844FCB5FED8B8F59D4187AF +:10A10000FEBA95C6B9C25C4762BDE63C6BEACDB209 +:10A11000697F13F5D5093DB4D9C9B78BEADB2FD3D5 +:10A12000F9B1E83F68EADB7FAF738EBBA1DEA9EF30 +:10A130007AF5B59FCBBFFD53FBA91ED37F1ECE8FF3 +:10A14000FC56BDECC085D6F342BF71958F70B2044A +:10A15000BA7C9E9D13C38AEB7CD7CE9FB74DDC455E +:10A16000F69FDF9B7CEE34E74F951B9719CF79DA8A +:10A17000D46BAE65265E49CACD7E1AC7B54C8CBB82 +:10A18000DC0551B6CB83BA467639817B2B2B1FAFCA +:10A1900017F1AA9B259BBFA0CB83F3C95FCA0C8094 +:10A1A00046F1928CA0907F7815FBDBF4DDC34BC5A4 +:10A1B000FC3B2BF5A7689C874D3AF6A5C8D3A6852E +:10A1C000FABF50FDB6A60CF697DE9F0831C2B397D2 +:10A1D00041AB417E5A5799D747762689E711A51298 +:10A1E0004E08D4AF277938B7D7AB01FB57706C1A3C +:10A1F000DAA9E5607D06ABA9FF32BF8BFD382815D3 +:10A20000FE928E3FC4FF65FACDEC6F59F1D86560C0 +:10A21000F37B50666F883AFD290FD50792F5FBF75F +:10A22000E2FCE4C7ECF36A143F25DC1DF7B27ACAFE +:10A23000598EFCAA33F955B7EF1FBE3906DB3D0F27 +:10A240006A94E3D4D5EE9334AE8A3FB48E2339D1E9 +:10A2500041379D5B4D866D058CD3391EB5FEB82BFD +:10A26000B484E473AF888B660624E6CB94604C29F3 +:10A27000A4F6BA7AE61AF24FB70CB29FB7AD6943AB +:10A28000DC4BFE5091041378951120FED6968AF986 +:10A290001274C4DEFD29E430BD27EDF47AA0E7573F +:10A2A000AE594CE7493B9D5B7EFAF2ACC336F9FFF1 +:10A2B000A8DE19F77A63EBD3F0D6742CBB56713C49 +:10A2C000EE0B60E23CC403244FBB9A9E55D7E27E5E +:10A2D000FD66EBE0ACC368973F35E5F28196C8A711 +:10A2E000F5F6F85AD0E7217DAAC19943E7918EF798 +:10A2F000D16F26FBD7B9AF6134ED7757B60121D2C4 +:10A30000B7F1BFE925FFA33520C328AC6FF5F77A75 +:10A31000C82E1E35F9BF5E81EDC4CFCC982BB60D8B +:10A32000A7DA1F8CFACAC94F3AEE0219F7A36A9F3F +:10A33000E027EAED9817FBAB2149A5726D50C49D4B +:10A34000D5F9FF6C10FF4153582E3CA5DBE2255890 +:10A350005E8EFCD6510EAFC57D8ADBF10D24FC78F4 +:10A36000F9BC88B16A8A3D1E01CEB80018FA318A5C +:10A370000358786B1735447ADE2B80D876EC5FB3C0 +:10A3800077A75148F282F3B1BC0485DC5AF282E728 +:10A390002444F193F7FFDD1542C94FECB39A22BF75 +:10A3A0009E7DB8CFB89FCB43A9729CD8E7B747DA58 +:10A3B000E72B1BB21DF19DFD669CB41BE592EC4B97 +:10A3C000F7DE275FA0751A7BE5D074EE6534131DA8 +:10A3D0001190438CFFE312C7476E30CF41775D9FEA +:10A3E0009BFC426DD3E410D9A1EE993F74AFA1F864 +:10A3F00048411E64926D97F5036BB1BC7AB74BA2CE +:10A40000F3CE1FAADF921BEBE27C80E1A17DFD026F +:10A41000826F1ADF92A7EB62228FB1BE5DE2FD5C14 +:10A420000B210FE1D49B21CCCF5B20CA4F098206C0 +:10A43000EDF3F55129D4C57CEB5B7209F6DB6F8C2B +:10A44000E5B23ECF9D7B4A65080BE9EC4A428F237B +:10A450002E3C65C3AB15451F1F3A9F6793277F446A +:10A460001E2C25BDE08AC9B8B45DFFE862F93A8BBD +:10A47000F2C57A0AFA38FED58CF2C574AA4E794133 +:10A480003A1757637D0B2A30D25B83147F60BD621D +:10A49000B889FEF5F3DD40FD52E52E8D9C9D986652 +:10A4A000C3F52D91A7AA77948A7C99B72C295732A6 +:10A4B000FE905CB5467ADDDF20FEEA6A540B915DC2 +:10A4C0008B8789AFA49788FF2D11A71CADBF59E4D6 +:10A4D0009F22A89F756C1FB9CB198F9AF2E9175963 +:10A4E000BF6644B2AC389F43DE3A0361912FABC5DF +:10A4F00035E4923E6B5349AF414861797AAF0E32F1 +:10A500007C5792FFD7E7BF17CFFDF606817F5E9A93 +:10A5100079F501477CA1C1A98FA62C35ED8B8AB8AE +:10A520001FED51EF427D67C36C8A1384FFAE8171CA +:10A5300097382FFFB644E08B1395863F8CFAA3B073 +:10A54000C66997169C91537044460A8E18EB28579B +:10A55000A997A6E088A98E7A0DA28315A49F758578 +:10A56000E5ED1ABF1387781F748D223D7EDBD5C0C1 +:10A57000EB5A7459EF64B2E7EF4D17F19ECC6AC500 +:10A58000989023E2B86BD2E0D21FCD5DF370834385 +:10A590009FC6DDD4AE12220AC9FF3560B07FB11468 +:10A5A000199C57407637F228F1A3BABAAE3D0FD7BF +:10A5B0005373E5CC7CD2DFB50BC38F3770FCC5007D +:10A5C000E21FE9717AFEBA3CF204B5A7757867D14B +:10A5D000F831A0F6F7505C81E26AE52AC7D500861B +:10A5E000186758EBB8DBC401F4F9F3F6331F9C4C41 +:10A5F000F6C5F233DF3FB01E34A4A3D96F8CE867F1 +:10A60000AE43FF9FF8B2B95C3F4E7CAB5A183EC1D7 +:10A61000FCCBB2F8971EE7ED9460D434E2DB802BDC +:10A62000F410BE6DF242D4EE6FBCD12070DBC70DCA +:10A63000827F9F3B9FA5A6CF6759E324E423259FF4 +:10A64000F58B863F2C9F65953DF1BA11D7E931F125 +:10A65000E6A1A665728CE3E3857B486F76FB659D7A +:10A66000F4CDC73FD5F6903CEC6E90CC38A0902747 +:10A67000D28F7715A3F7F649100CDBF83F34F5E3DA +:10A68000D3667CF6D9AD3E8ED73EB7D5CFE51F6DEC +:10A69000D5F819DF1AE0F707B786B87C786B1997F9 +:10A6A0009FDFAA73F985AD4B1CF1DDDD0D1ACFEFED +:10A6B0008937323D9E9878EA741E4C5C932E9F82B7 +:10A6C000B86642631A5C73766FD575E51A590F74D4 +:10A6D000C38A2FECA7F4363AF2A3449761D2659867 +:10A6E0007419265D86499761D265987419265D862E +:10A6F000499761D245CF2A0293E467160A7F2175F4 +:10A70000FEDEA566FCB5327265233E732EDD329304 +:10A71000CE1BEC13799F5E13BF8F32EF0F58FE44B0 +:10A72000472E701C5A0D00E3AD2A2DE6190A8A78CF +:10A7300034C56952E3CF1BEA34EEDF1ABC9771DBF4 +:10A740007A7F9F427C4C8C6BEA5FEB9C1CFA5241F7 +:10A750000FF54733748670834236742ECACB63DBA1 +:10A760003AC90F0117E224F42FBBB3BDCD31927F5C +:10A770005F29D7AF5ED8E7AF4FB33F88A0789E6E12 +:10A78000B7D0AB56FB43EEC1C5344F778156DC8E54 +:10A79000F6E88349836E92FF430B34793BCAFFEAA4 +:10A7A000E0AF6FD46625FB1F32FBAFB82C945F6718 +:10A7B000E3E78D8DC24E1D9A2EFCB34EADDECDF972 +:10A7C000B0A04F72E592DCFCA38FFC44AB5D527FDE +:10A7D000476E6CB49DCF8C80C8C301C206E2474669 +:10A7E000638641B84D5D10B989E42B4375BD497A44 +:10A7F000382310E238FEAFCB85BC820F279B48F38D +:10A80000EE5123C16479783C23F8BCD875D7034353 +:10A8100048EF009A092FE5BF64F4B6C81EFF850C07 +:10A8200042AF37B23EF0A2BDEE2A627BF60F43D8AC +:10A83000EE8881FE19E119FFD919A41F7940D4E3EC +:10A840004DA68AFFCDA81B199F497F0D3E09F9FC33 +:10A85000BF3273020A96B7404688FC993B5DD19996 +:10A86000A4EF7F23F76AF4FCE7C602E6EF2B21E5AD +:10A870005E82435D813D9DC5346F85CCD8ECD56A41 +:10A8800079492C8DFC76346671BFB1E5FA0EE2E3AE +:10A89000338DC28EDAEE41689E39E63D159957F93F +:10A8A0000AE1A337CD753E63EEC7B5FE6FBF4E74A8 +:10A8B0008CD17D57D3FDA255E83FC61067BCA88454 +:10A8C00024A2FFE846097AA5E1F959EBFFEEEB6F08 +:10A8D00097D088093C269FBF2A89CF748003847F44 +:10A8E000E69D76E613179C7196177DE22C5780DB68 +:10A8F00048C9F739CA8B7DCEF2357E6779A9E62C37 +:10A9000043BBC073AAE90F831D9FB9C453B1E5EDE2 +:10A910002EF0871B4FB11F998AEB2CBE0FB74F4B00 +:10A92000CB973FD368E3F33D92C045C64439F4105A +:10A930008AF08B656347456CFD061A851D48D88BE8 +:10A9400080CC38BB3B50CF7EE170FBA07E320FE263 +:10A95000367DAA2A56FEA1A4A404E9EAA405BBEC0C +:10A96000F388FD573F59C8FD2A1FDCCC47A7F6B82E +:10A970008BE7B3FC7A8267E4CF587EDB91DB25F668 +:10A98000DB6A7B23ED77201DD5282F1AE7A9BD10A0 +:10A99000B7F9F99974CE5CE4BF1D593C0ADBF56741 +:10A9A000A39FAED1FD2BD1CEE26B667E7BFC8E3CAD +:10A9B0005BDE17399CA827FF82FCB71C7A3ADF5B65 +:10A9C000FEF770FC48F5EF3E6834FDBBABE02ADAD9 +:10A9D000EFB3F98DA3E390F4E7AD7E963F4F78A7F0 +:10A9E000DA9DF4BBFEAB3197F99511107C5083B022 +:10A9F000C7258D6817FF2B9D5DDCB520F23FF4BEA7 +:10AA0000C35F9845FABC528233743F6F57538687B1 +:10AA1000C609B8C5F8DD652AE7D1137E670CFD04C9 +:10AA20008DC97934634EF23E557C5E445D81F2D728 +:10AA300069EECFF55F73C70CDE3F630CC5E93A736F +:10AA40008CD3149F04E3A90D47CBCC761C1CEDDE00 +:10AA5000C0F927B33C66C53FBD4F799ECEF1462B6A +:10AA6000E5A35E5B31F5D63CD2AB1453C57F6B9B3F +:10AA7000AA1E31CC3807D9C19FACD0044ED364C3D1 +:10AA80009B93C4C748DF445ACF11EDE0400536A977 +:10AA90009CA45C4D78AFFFB103AB26907E6DC34D97 +:10AAA0009C8CE522AFC0D1D321361DE9ACF8CE7124 +:10AAB000B7CCFE17147B8B28EED80B85C22F1C2237 +:10AAC000FFCC805EE0B8D1730A087F39C2710BAF4A +:10AAD000E957DAFC411197502F16978013D36C7108 +:10AAE0002BEFB4F189FB95EC2F568BF36FF98B00AC +:10AAF000517D3BD667A0BFC8F135BA6140B8D38C51 +:10AB0000DB78A72929FAE2873AE5095F94202AF938 +:10AB1000B15F4F84FDC366F40F29AED27CB353BF3F +:10AB20006446D1BEA5D12FEA827025F1333328ECDB +:10AB3000DE0CF7E02A9AB71FE410E5F7FBF73E7941 +:10AB400094EC85B13B211F2C0733DEF199710499F8 +:10AB5000E312579974F6D745AB36617BDD8C4BF425 +:10AB6000CFF472FBFEF77CB14C71EE0FD0799CE70D +:10AB700037E312082FC96FD1CDFE649F291E351F00 +:10AB8000B2392E711DAD95F6E563110F887B40A299 +:10AB9000788115575888E24D76AEBA49E3F32341E0 +:10ABA000C0A0F9E60C41A80BDB1C096CFA1AE5AF52 +:10ABB0002BDCAE9050C309FF6BED8A7117CA97B7B3 +:10ABC00025B298F1C52AA43997E5ED2F59FE5517FE +:10ABD000CB5957A0308FF894893091FA2D6C8CDCCA +:10ABE0006A8EF3A6DD8F6B8B2966FEE79A5B75850F +:10ABF000F4B290F37F3B7ECB0692730D0617B3FD44 +:10AC0000D3709D388FB768532FC95F7FA98BFDB76D +:10AC100073C1437F1F4292AE6DFCFE8FF198C0F569 +:10AC2000B17BDD74DFB3392F770736477BE572C41C +:10AC3000CD363E9AE9D07BB7DC37D6517FE3E64B81 +:10AC40001DF52BC2531DE5D6DD5738CA8B7D258EE9 +:10AC5000FED7F8E739EA976A558E72C3921A47FB16 +:10AC600070FEAF94311AF3EFABC4BF657B25E65F8E +:10AC7000EDBE82C6124DE049C2CDDDD97D7ECA4708 +:10AC80005AF8D1C289DD059139DB7393FAED5F572C +:10AC9000B81C3833551F3EB242E0ED15857D9174E6 +:10ACA000783CA127A392316396F0FBD7A6F5FBD79A +:10ACB0003EB422C5EFA7762BCA6E7F7E3CED436B78 +:10ACC0001DE34FCA8513FEACBEB98ED4005C5D7D1A +:10ACD0003BC130B86EFE362562D363998433731856 +:10ACE00067F6B19C948A73689DB7FE60C38876E668 +:10ACF0001DF453280EFB33F453E8791CFD9438FA05 +:10AD000023EFA29F1267FF24C4E5E7D14FA1E70B11 +:10AD1000E8A7D0FB63E8A7D0F30825F067FFE9E7D1 +:10AD2000598DB45C524CF635E6198BF2BB2CF07D94 +:10AD3000FD218A23527EC9C7F40F32FDF98A794E6C +:10AD400004FD093EA59CC35FA3FF4FEDE93E94BB04 +:10AD5000F8E2E709E5ECA724675D641720691706A8 +:10AD60001E5BD33C8136C6B40B03133DC2AF31F535 +:10AD7000D8A87C6D0FE9D78AEFDCC7F6C003DA49A3 +:10AD80008A83799B847F4F7682F4510BDA05C22146 +:10AD900006EA69B623561C4EBD8BCB6A8512F5FABE +:10ADA000FF703B810A7131C5156BAD3CCB0576E276 +:10ADB00077B30BB56417F246B20B3F594CFAD15733 +:10ADC0000821BAD798C63E789A6CF6E1727244C6EA +:10ADD000B19723FC176B1DEA46E69F2AC110F1C10B +:10ADE0000B29717C930F1C7A951DF5820F10613E23 +:10ADF0002B647F194F8878EB5C73AB147F6F953DA4 +:10AE0000DE5AF19D6A83D65DAB23DFC98EBCAD38B7 +:10AE1000E2AF9CA6C5F16AF2C5FA6A3BA37CFF6F5C +:10AE20005E99D747FBA8F89D7CABE989329FCA8918 +:10AE30004F387FF987CE7A6F4A3EE0F22627DE9BB5 +:10AE4000E18EAF267E0C98767360EFF1DA92DFC167 +:10AE50006E0ED4455D77DAECE6C06C61370792760A +:10AE6000B362D3887633E2B49B7EB13F991F8BFCEB +:10AE7000DF707633D55E7605EE3846F26CD9CBDEE0 +:10AE800026338E9B17E37B1FAB6599C75D3D4BC493 +:10AE900027321BFF631DFBB50021EF443EE7D7922D +:10AEA000BC1C547F10273F44AD50F91EA432A9F4B6 +:10AEB000B00CC9F38EF6B7BE298DFDC573BC82DE1A +:10AEC0001FD4A6E5D139B6706BFF630F3ACE71FF80 +:10AED000E5D6393EBE83EED5676A5A31F9D1BB9AC1 +:10AEE00096F92A08DFCE9C564CF7188FAF901C714C +:10AEF000015CDF9A26877E17727DDCD4931450FAAA +:10AF000018F93ACADCB26EC295B679BB8BAE5297CD +:10AF1000213D5F6D9AFD08C54E52F5D0EA8583F953 +:10AF200014FF1EC80DA91482F9EA89AB1E512EBF69 +:10AF3000B0DDAD5F8E719CBC6B62C81CAF3C6DBB5D +:10AF40004EEDD88F89BFD7154088E286CBA08FE31E +:10AF5000CFB530C8CF77E747BE42FCBE1671D338B5 +:10AF6000ECFBD2E61DE635850BEC8FD19446FF7ED7 +:10AF7000717E787B13C793455CE4627A163FF9993A +:10AF80004EFFA09BC6A5EF5DD0FDE44EEDA36C1A6D +:10AF9000F7A2E3F8853CA162E23C17C87288EE3F55 +:10AFA0003E3037F20D5E8F8EEA763C88140FEEA3AA +:10AFB000E47FFEB712AEFB840C71BACF63E478383D +:10AFC0003E9E6AC736972FFDB6A0C7E7E1FB168104 +:10AFD000E75FA57E6BD42CE6C3F0F706C2D2798A70 +:10AFE000D79AF19B6943FF87EF89E2993843FA4882 +:10AFF0000D3CC1E5B3A09EA17B306D39FF019134BA +:10B00000F8C1FB89CB1177F492BF67DA1B8AD78F1F +:10B010002682E8DFA7E75D44DF2891E38421D3DEC1 +:10B020008C0E89F3301A05F1A4DD4E802D9E2F91F0 +:10B030007C3AEBD552E376A213B5AC15A77F89E82D +:10B040001BCEDEFFB19F74AFF7E4F411EA3DD15699 +:10B0500092F79D5285CCF87A7AE19E6DB6B88F450D +:10B060007FD78AC43D63BEFFDB35AD78348C805B0F +:10B07000D4DEBA11BF07A3CA104977EFE81D73BE2B +:10B08000ECD2284CC5F52CC17D263DD5B840E3FD5A +:10B09000F706059EF7E64719CF7D60C6C3DF31E3AB +:10B0A000E18493E869C9CB65837773BCEF9CA1F019 +:10B0B0003D5EA352C4F38CED5E5F5B1EC5E9FE9658 +:10B0C000EBB728AACFCBFE5DF42A92FFCEADD63DDA +:10B0D00087E8955C76479B894F5E583DDA7EDFEDC9 +:10B0E000BF9B04BE557D0F9BF1300FE36D72E745AA +:10B0F0007CC9F9BD09D5E333BE84F3F64C92D9CFB0 +:10B10000EF2938EABF89D6352E43D8231FAAFD3947 +:10B11000C21ED0C705CA29B26F9DC44B6CAF65452E +:10B12000C0A0FE658AF8FE9D22ECC98E9C4BB8BC7F +:10B130003354C9F7463408F33DEB9C7123C78FBEE7 +:10B14000467422BF3A908F446F5B2DDAA59C64FD54 +:10B15000D76B1B793C2F7D2F8EB0F5F2CD6CFF3A6B +:10B1600042857BC87E75844EAA32BE2F5F29F66D5C +:10B170004796BC24DD3D31AB5E83A84AE7FF9EFCC9 +:10B18000FA11E5E75E735D563977495467FF4D1B49 +:10B190005A42F4B6958D9144BC23E2A7FB3813CCF8 +:10B1A000F1AD7BE3B9D5DA3602FE3D45B794102FF9 +:10B1B000D56A9F740ADFAB4B34E92D7CEE28F6B4D8 +:10B1C000929D6A5350CFD178FECB64C3A6B716596F +:10B1D000E315A4BF1F3763A56CD27B92D76394C9D4 +:10B1E000303D8DDEBBD46CD7E6191AA4761D7315DD +:10B1F000A07DEF98382740F4744C12FA774673FB21 +:10B2000023DBB2485E6F839F91BCFAC5FEA21BFA96 +:10B2100002E5C97B7C8ACF9EE7B29E969C7699FB1D +:10B22000E729DACEB8E11C76247DB4D8F5683C86EF +:10B23000E3F5E82AE3B1D4FEA352EE79B4E5DC0FDE +:10B2400064A75510F1A91EE8F5F9D8AFCE70F895AE +:10B2500056FFEF35459A57DAE2F9A3A64541DC6F70 +:10B2600011FBEC9934B2FCA5AEBF53420B33069FE1 +:10B27000B9E2BC2119A769FD3B43E38BECF4EF3441 +:10B28000F97AB1F153E91B8E8EC752E28133CD7842 +:10B2900060EA78E7CC79773E76A0D91ED7DA598470 +:10B2A000B8877146DC5F6F5BCFD69502E7F4484202 +:10B2B0002E7B503E9F48B3DE6F9BED869BB7DC92A2 +:10B2C000A384BC7A80E4B5A340C8CFEC57BE6EC659 +:10B2D000E90CD607D9AAC85FFC726EA487F6273B93 +:10B2E00020733E3BBB34E48A38F8EAE13CFD9F9092 +:10B2F0008F8C37CEAD7CF656115F3180F24F3B29F3 +:10B30000BE5240F36E677C7F0EE593ECB7D2DB67ED +:10B31000FCB694ED73F4FE90DD5EF70C921DBDD883 +:10B320003ABCF025319EE907D2E753DBBD3EF59BE1 +:10B33000A38DCC59B671358F63BCDF35BEFCD44AC2 +:10B34000A7BF01AEFCED55347FBE1C73A5D107D657 +:10B35000D38A2FC39491F560578A1E4C7D66E40C06 +:10B36000CA747FF9F557DE7EA41DFDAF0C33AE9B8A +:10B37000F5AABA91EE175FA84FE26C173E871E61DF +:10B38000393A473295FBFBCB85B5FFE5AF1CB89545 +:10B39000EE8F237F381E7A2E0CCC1F0294E4FF48D8 +:10B3A000862C709E8EFFC69B29710699F8663CA775 +:10B3B000F678FF52F93F81B4291B4B1FAFF7928DEE +:10B3C000C2AFCC87218970F81472E838741779E617 +:10B3D000B738DEF82B4E481538CE2F2FD8B791F757 +:10B3E000DDDAAF547A1EDBAA4A24EF3D77C781E24B +:10B3F0005B59F1BFE17CB0F7C93850DE370BFD5D1A +:10B40000C2C5F024F0FD8776DF477C8FEA5C7EE1E1 +:10B410001EBB7C6C5EE9BCB7F0B8B9EFEDBE7A5EDE +:10B42000D7E3F922CFF4B83294312638BC9ED8BC89 +:10B4300052E42BAE7CDAB92FA9EB6E97F5EC66C21D +:10B440002D84C767121EF770DE351587676444D3F5 +:10B45000C6ED76C995E39AC7A5932FE0FB0D3D4F46 +:10B460008A7DF863C9D96BF465F8719FE7FCFFBD6D +:10B47000FE208D47F981501297A58E77319C66E1A9 +:10B4800047C48B8C0F8DED0AB495325E64FCB8C551 +:10B49000F0FA287F9C55B4F9012AD7227E249C7AA1 +:10B4A000A72B9A5D25519E57E47BADF9B2E5036A5F +:10B4B00009D2F7972D5336B6E3BC3DE4C5A3DEFEB3 +:10B4C000B079CA46631AAE86B0238E132EF18AEF86 +:10B4D000939AB8EEE8CC091C97B0C6E92FF2AE4EAD +:10B4E00027A7EE16D9CC6F6771BFFE7C115FE80706 +:10B4F000F17D40EFE52EC69BC9FBC5283DE4BF07A3 +:10B500001A04FF6B81BF1F3883BE8988EB38B219DC +:10B510007C14FF86943C37ADEBCCF8A41FFEA8B991 +:10B520009FC3EAAF270FF33C6DA11F64D17D89FE55 +:10B53000C0A1A314173847B73A6DF271345BE0AC81 +:10B5400043454F29A782C9714F358BF8724D5F5C17 +:10B550002121AE0D556844BF328CFFF06CB3B0A30F +:10B5600039147022FB3CCBC5FEA895B7F74EDA3CE8 +:10B570004879139F99678716D17EB83C6E5B4BB6AE +:10B5800033BF9E924F5FD3D85AEB439EC69A4D3C31 +:10B5900092C8ABC717136EEA30F3E9FD944F2F80C2 +:10B5A000447EDE8A3BA6CE57437975BE5FF0FF67C7 +:10B5B0005EDDE283C5472BCED4E11FE3C8977B0253 +:10B5C000C21FDFB520B28FF49087E227349E5F63FD +:10B5D000BF5035F1CEAEA6AEE1BE0FFE4FCDF6F8B0 +:10B5E0009326EEA11C49892B1D2912F76D562FECCD +:10B5F000CBB7E33A4BCEFA4D5CD73F0CAE1BD7220C +:10B60000F47A424F66C9A69EEC5B45E7ECA8758FBD +:10B6100058D735DF9C645C059A7D9C1F873B72423E +:10B62000A4C73A4C7BE057C2A3EDF70EAD67C74104 +:10B63000718F0FFC363C5348F3AE4EDB3E551F274F +:10B64000FCBF501B9FFF8BE9E307E6465E23FB919F +:10B65000AA8FBD7EA73E3E31CCDFBBD85CBEF4676F +:10B66000D43F0BA2ECAFAC09A0BEA1EF93CDF77510 +:10B67000107E6B9340E0B78BC48576B400EFC3D1E6 +:10B68000DC9842F71AAB02DF5748CFD43C89FA2244 +:10B69000DBA12FD8FEB536AFDE4838B467F741A638 +:10B6A000D36897380FBD463DCAFB81C7ADD89B7F95 +:10B6B000E1BC7799FB08F785595F92ECB27E4CD9D3 +:10B6C0003729B492C7DD8DC0C33591E88C7C4674B0 +:10B6D000C216A157DB42A0DDCF7A359AF6DEE435FB +:10B6E000CD30A23E5A5ABE5C69994DFA46B43BE24F +:10B6F00016E3124DAE79C44F515E932FF07FEAFAF4 +:10B70000D6A8ABB81EBD436DC2C434FCBDCF67D054 +:10B71000FD0E4BEEDAB644CD6044FA7576058EB96F +:10B72000499F5B7150B4609C875B1614F3D7409CB3 +:10B73000E3A1CB6188EFE5BE3B3F3299D6AFC67E31 +:10B74000558B9C82C6F0831031FD16E2879A8C8B54 +:10B750004E6DA17B2A665C54D5445CF460D306B977 +:10B7600093CE4DC0C5F60D9F4CCFD9B22CBE773EBF +:10B770009CBC129ED24DDC41F1A13E335EF4A8196F +:10B780002FCA54A08AE3F27160BF8AF093FDDE32C3 +:10B79000E10CFB3DE727E646E6121D4571E7DF0FAA +:10B7A00099D9E7FC5ED617E787E7B530981571DCC5 +:10B7B000FF07F5C0F52D7F981EB8B1E58FA8077675 +:10B7C0008D4FC429B3C89FF594E8F27DC8EFF0957A +:10B7D0002EC65547822E8177425EF13D0545E055E4 +:10B7E0000B67B9513C468F49E22CEF27531DF7AB4D +:10B7F000529F5E77D4E74B43D735CD058EFC86F755 +:10B8000093CB781C37AD7336C7E78D168E87C3A3ED +:10B8100052DABF93E4C4A3D6791B5BAEB7DBCFBFCC +:10B820008553CFF69D20C433EC3A3DEAA6A0FDEF48 +:10B83000BE748C8A727E9FE492E319D63D516550A6 +:10B840006ECA4E8ECB717176BE86F87CE6C4E7B2C6 +:10B850007FE30A8574F26F72CA4260CFD74F9F535D +:10B86000F94D5A5F8E32C47F4F26C7FA3EFCFC5218 +:10B87000C7FDCCAFB738EF855AF359E5374CBFCA8F +:10B8800063CE6FBD7FF3AE3EA0B85066FC1996F351 +:10B89000CCBB24BE5F1BB1BE8FE517F348CDDE8362 +:10B8A000B4AF43C142CE230F05E51C8A530E19677E +:10B8B00085FF1514FE9775CF359DBEA0733664883D +:10B8C000FCFCE341A7FF351C9F53FD2E6F46748897 +:10B8D0005CD37F7DEDAD8DF4FD5CAFF9FDDC83AF16 +:10B8E0007DFA28F9613FD72307885F6FA2BAE1FC90 +:10B8F000C925C07875CDCEBB67D2DF27FBCC946B52 +:10B90000BF953719265F62B54BFA6309FDC2F1A2F4 +:10B910002110799C0BEC55F016D6D7BB51005D7306 +:10B92000937AC06FFA1FE7CA5491176D06CD1E3780 +:10B93000E83CB854E8199FED7EDEE7D0333BCDF10B +:10B94000DB4C3DD3616CFA5CFE1FEA9977D96EE45B +:10B95000CB0EBDA26439F5CCBB73F5D3A46F47D031 +:10B96000371FFE31F40DF8F338093EDC7A2D79C625 +:10B9700073FE9979CE0D69CE85E71CD7FB3F2D6903 +:10B98000E40FF2C5BE59F937A8F4F1F99382CFFF5D +:10B9900096FE4E4F723D11E0EF5B7CCEF57CDE767D +:10B9A000FF17C8B4AD9080500000000000000000F8 +:10B9B0001F8B080000000000000B7BC5CFC0F0A368 +:10B9C0001E815DD0F884F02A12D5A3E3C74C0C0C7D +:10B9D00002CC949901C2967CA87C560E0686B7DCF0 +:10B9E0000C0C5CEC0C0C056C0C0C0E40DCC58B904C +:10B9F000F7E380D01A4208B13601CADD318A8736B2 +:10BA00009E2ECAC0304B0CC1D71547959F218A6026 +:10BA1000EB485366972D503F006CC3B2AD800300D6 +:10BA200000000000000000001F8B08000000000064 +:10BA3000000BE57D0D7854D5B5E83E3367CE9CF913 +:10BA40004B4EC224CC84099C8401421B7482411158 +:10BA5000FF4E426AA317DB29A2175BDB3B285AB0D3 +:10BA6000FEA4D4ABB44F9B03F9611282048B8AC14C +:10BA70009F011469AB6D6AD57ABFD6BE01BD14FDB6 +:10BA8000EC2DD7EBB54AB10DD572AD551BDB87A4B4 +:10BA9000EF617D6BADBD4FE69C934988B57DF7BBEB +:10BAA000F7854F77F639FBECBDF65A6BAFBFBDF6A5 +:10BAB0008E5F2D63B5E731F601FE405917648C2D7A +:10BAC00028940F7E75E6C0AA46C6CC7B95D483F039 +:10BAD0006867CFEE2DE74719DB7DAB67BE17EAFB42 +:10BAE000EEB8C9A341FD81BEDA9DFE1AC65A99C4BB +:10BAF0005805630F458CE7EAF0BB2D1EF6A00EED4E +:10BB0000239960BA1EDA6DAB2D6561C6EA9942EDE4 +:10BB1000BAEEB8F4901FDACDE867FA1CF83E99BF88 +:10BB2000C0A34718AB1A92199B52806B777BFEF823 +:10BB3000EB3E18BFFD009533E48C2700DFB16DAC00 +:10BB400001E19AA1B679020007BB07EA30DE8CB0AA +:10BB5000CEDF67455D4BF17A1F6FFF70FBC1E3AF2E +:10BB6000CF825F98C9D4D3E13DFE0AEDE66C8371C4 +:10BB7000EA18FD7C00FFD5F7E73D2B00EE99591838 +:10BB8000572D3C9F3778D0519FC1E4FF35647D0726 +:10BB9000F378057F81F9CDD8C6E7317704E67BDA03 +:10BBA000D8F95AF3B2E6FD5F6D7EFB5E3DA37715D3 +:10BBB000D29F95A6FDC4076B0E318063F73D301A06 +:10BBC000B0823FF36DE297076EF1A47AE193E34709 +:10BBD00076507D4F8F27B50EE15133C1B938AF6D27 +:10BBE000C02750CC09336310F8638E0C25C0B556BE +:10BBF000F0D33F61B900D1C14B9D998770BC876E6E +:10BC0000617A2FC0D3B5E3EAE7E6C2B8C917BD6CC5 +:10BC10000EC29BFF9384F8B4F8C72A6BB7292C3F58 +:10BC2000015F25E5CC3EBF0DEF49B56D9FDF86F77F +:10BC30006458E7EF05DE935A8AD75D78B7FAAFBF4D +:10BC400005F01B1E8B7737BEDD749A2CFE756604DB +:10BC5000D3F3601EFD4B4B6151011ECE6F1E0A8F48 +:10BC60009D37F221CE7BCFADC3523A5C98B785A702 +:10BC7000FFBAF3E77CB00BF940E27C50173D391F67 +:10BC8000540D011F9CF6DF890FFEB2F58072F6BFDE +:10BC9000C37AC0F68807F7FCAC724BBB7E2C0970E8 +:10BCA000F4B6B3634998D76DED2A95D9768DCABE9F +:10BCB000F618955B405C3398DF96B758CE047E0A41 +:10BCC000D5417BDBB8A50BE13B1BDC015D73D423C5 +:10BCD000A998A37D798BEEA8FBCD20F5BFB19FE598 +:10BCE000905F37B73366F819DBD4AE52B966DE3EE3 +:10BCF00015F5635FEAD7CBB1DD597315DD2BE1F4A0 +:10BD00008C7F8B553276AEC04749C950C71580E746 +:10BD1000BEB897AD4FC17CFE6C78AE847AEF997E49 +:10BD20006DBD06EFFDC6FA2BE0FBBE26358DEF9309 +:10BD3000A9ABAF63258C85D77EAEEC751BBDFB7CB4 +:10BD40006C39CA5926C3E41B910EDA0EE41F89BD73 +:10BD5000FEB284DF272B6B10CEE99287E4EEA68635 +:10BD6000DA66EC776683A23318878DC8BF1E82F926 +:10BD7000D5C1BF0F6A015EC6EB165D4AFC436F94E6 +:10BD8000225CD07E3DF4A39D6D7BCF0B16053A9FC0 +:10BD9000277EAFAD7B6F7112DAFF5E62296D21C025 +:10BDA0008DFDD9E81C99AED33C7BC4BC6AFB9CFDDD +:10BDB0009D97BCF44BD229F0CB09DB77005723E2E7 +:10BDC00010E07FEE4CC54823DEFA58CE2F8D85BF9C +:10BDD0004F7EF965E4DF998077B366EC7CDCF0BADE +:10BDE000E713993EBC3809F8C94A6C18E9E086FFA8 +:10BDF000BC3A658507E1B3C30DE39EA703DC256369 +:10BE0000E1B6F8FA3BED1A336021EF68AF233ED973 +:10BE100005751DCA1DEF7B97A3BED4B129C07DC790 +:10BE20005BFA4EA4DF28BF48BCAFAF485C8FEEF48E +:10BE3000F176E616967B90E6D3F6C60E80776075AF +:10BE4000E5FC5EBDC0170312E78B3597CCBF10F938 +:10BE50007060A54742D53BB06AFE52FCFEACAB3CDD +:10BE60001EE4CB9A12EDB3F4FE124EDF992BE737A6 +:10BE7000CF46F960C4FE501A83F9AF3ABAF82A687F +:10BE8000FF2FC0A712D073C79FB53504E76AD17ED4 +:10BE9000A492E9208793CB94238897E42AE053283F +:10BEA000AB904F6DF27900F9345C8C4FA38724A8D6 +:10BEB0000F2CE37C7AA3E0538BAE06FC433CE6AF49 +:10BEC000A96DBECAC6B76EBAD6F8B537914F073E50 +:10BED000037041FDD4274FC2A7ABDE5B3C7B023E23 +:10BEE0003566E81E1C6FDB787C9A29CEA716BD0B41 +:10BEF000A5735C261FA371673236DC0BFD3ED7A508 +:10BF0000BC85FC3A905674B4BFDDF31E9047BC3438 +:10BF1000EF26D5305363E7ED9EE7D879F4C7D16EAD +:10BF20001FC3AF2B27E657ABBCAD3DC75E23391B04 +:10BF300023FEDDDCAE53B911F918CA4DD8F4CCB1EB +:10BF4000F2BACFC35621BDFB826CD5A348F7C6F920 +:10BF500045DB592563EB88EE59E4EF45048EC1803B +:10BF60002E01F88F55513D1F4CC2F8BED1BAC112F7 +:10BF7000D0BF34DA1E140EACE785857A08DA670381 +:10BF8000BCFE2B29DE649E5DA8FF49D29ACCC4D8A2 +:10BF9000F7D0FF3A6F03638F49878CFA80A37F0342 +:10BFA000FBB7C3A716E96F7380C317591FA2FA1610 +:10BFB000693086C4DE286971E4DB1F4ACC68896178 +:10BFC000BF50077A9E79D7ABE633F1C23887D7BD29 +:10BFD0006A9A40AF0552FA2909F061E86D75CC8381 +:10BFE000E30E2F6700D74FF17BE8574BF2719E5E4F +:10BFF000779475D8F0F273E99889E3223AC295A450 +:10C00000AA607120FECB198B237E8CA6D5C06F65EC +:10C0100020382418DFD30275685461A86D7E802F04 +:10C02000BA4C3E3A64D387767E28D65F6021FF3EC5 +:10C0300068F55737C9FEC4F7E3F3036F0778F825AF +:10C04000E1E1ECB6558887A7104FF0BCB976E1CF97 +:10C05000CE8679840EFA527E1DCA8526C99500EADD +:10C06000FF06FA3E7F1ED4B7D4B0B65EA83F2EE9D5 +:10C070007C5C793086F67640AF62391B5C56BF7FB8 +:10C080006DBC01FCEFD9E908F511A962FCF9047156 +:10C090003EF02888F389DAE623C37CD0EEC0F99419 +:10C0A00015F0E49EC7E6406E39FA07CDE72EFC3462 +:10C0B000A3FE667948AEC8C3849F2D3EDD83DFCFE3 +:10C0C000F5707D62E125B87098F0A5E9AC0DC7D395 +:10C0D000CE76F66BF507F866A877430B87093E0D19 +:10C0E000E12BA3FE8BE39B01BE2363FBFBA380E755 +:10C0F00046E8CBC4EFD930CDCFFADEFACEEAC79A04 +:10C10000EF987E9EEF18EDC76BA3BB1B4F1E8FB33E +:10C110001F37DE4E068FF5DD5F0ACFC9E6E586677D +:10C12000B2EB2336329719600FCE423E02F9BABE07 +:10C1300047A1F1B72EE3F6D1D6039F20BF729BC76C +:10C140007816F9CB7CC147F19C6D965CDEDA48DF4E +:10C15000ED8C18F1A5F5E3CBE55D60E79A20EFB72C +:10C160004A5C8F6F837A0EEA3357C9E654D083DB7B +:10C17000324B031887D82AECD1D88AC6F5E7A39D9D +:10C1800060C4DEF5C27AD91AE0CFEF5ED9BC1EE3F7 +:10C190000777308D3F8FF0FEE257B5F0E7A2BD354F +:10C1A0007E12148969D36FD6F30AC558912E02EF17 +:10C1B0007A0FB71FF2425FED10FAAA22985E81FC57 +:10C1C0001A9D1ED477C27AB8E3924B2F43BDFAC8AA +:10C1D000F7F4F95EC0C7BE4B2E957E8DF312EB626D +:10C1E00097D07BA3E3F5A525C463DE976AD6808E3E +:10C1F000377998012B9A55C8659F4539DEE5394B4B +:10C20000F2C377B5CB34AA3FD2DB2CFD6401D6193B +:10C21000C9E501CFD2A60E199546DB1B480703D608 +:10C2200051078C6BC84C6E233A448BD2FB1129B05A +:10C230003C07E31A8F751FBC18F535CBD1FCACF762 +:10C240004D6C9A836FF2385FB42B71FE505EE52916 +:10C250002ED70C95CB3303E45907C8AF8A65BCDEF3 +:10C2600004007A519E0D3AE599213BE1FE6BC1BB7A +:10C2700040D2B8BD27FA03F978AFA702E16132F2E4 +:10C2800071933CBA8E1CF047B72AA6F7142A8F7810 +:10C290004BC6C2BB49CC1BFA7BA8587F7FABF918B1 +:10C2A00061E837FAD1FBADC07EEDF6EB38FDB8E5BD +:10C2B000C1E2AFADF2308AA77868FDDFA7A49E9BEC +:10C2C00083EBFE252FC5E76AD97000F59FFBFBEADB +:10C2D000FEB98E3882BB6CBE696170A81EFB5D4AD8 +:10C2E000F1DFFBBEB6A82A635B7FBB847DBF2BC09A +:10C2F000CB5F7A789CEFB0C747E5905857F79570B9 +:10C30000BB702CFCEB391FB07E2A3F3E1226780A08 +:10C3100075C5559729FE53A897883AC783D9CC2469 +:10C3200019E75DC5524887B2963686F0FA13CCF409 +:10C330009E0A3C806B0EF0D453C372F5C04F32B0EE +:10C34000A18A7E69CDC147B0EE43DD66AB2B60B3F9 +:10C35000C5A2853AF4C374DB7B6B1E3D35FDB1B0DD +:10C360000D2F5DB3EE247F34A8F378B19ABF7B39EB +:10C37000FAFDEA562585A6A2AA9B2C03FA2028A737 +:10C380009807993BCC6A904E41D5601E8CC368508B +:10C3900007F883E134AF47C57B2DC3DBC778DDAF3A +:10C3A000B7B12618B747F8934FCFBA9AF8A047E726 +:10C3B00071FD1E7D7EA9079E87BC9C2E7D5226E8BE +:10C3C000C57D0290AEC80FD06E2AD2F528AE1BA252 +:10C3D00083FCBF713DE11EC107F83F16D68E7E5C1F +:10C3E000F0A3B780E75E8C37CD42FFE000957D1863 +:10C3F0002FF221FE7379F2534B38FE413215E23FA2 +:10C40000F4FD8142FC88EA071DF590661AE817CA18 +:10C41000519642F91C30F206D25349F03AD2D15F1C +:10C420005AA0E300D2512AD07100E92215E868D55C +:10C430002D3A5A758B8E56DDA2DB404D2EEEA0E3D1 +:10C44000EADDAF38E9F8CDBBAFFE1BD27100E95889 +:10C4500044BF1D92F93A7AFA0EA02FF4936DE4EBE3 +:10C46000FCC1EAF55437577B282E906D5C9F453F01 +:10C47000FE8F077C145CB0F679FA74680FEF6F904A +:10C48000A7703ED06BE9BBAFCCF2ECC6F8C076111A +:10C49000CFEA15710A6BDCA7E7CE2E1DB2C1B3112E +:10C4A000FD3BA86F443B02CAE653B22AC6ADB3496E +:10C4B0001EC79E21F8EC51E84F07FD3BD8AE52F95C +:10C4C0002DA867A0DFC7A09E9943F13B2AFB405FE0 +:10C4D00061792FBCCFCFC138A64AE5B70F785A5142 +:10C4E0004EEE6907130DF8EBCE7695CADBDA352AE6 +:10C4F0009F688F51797FBB4EE5EDED7554F6B7A778 +:10C50000FE88A186DEF685541A9EA5ABBCC4D783EF +:10C51000CF7D0CF0B0737592E2251FDFEB49E790F9 +:10C5200087B4C1172E6C2C3CB7E669789AAFF3A29A +:10C530009D7C402638989CFEBB79C5DBADC1FE17BB +:10C54000EC95797FD1F4C517458BB6BB19DBF53C6B +:10C550000FF3C2766A7F6B6DF1FE6EC17103FF0C43 +:10C56000F0E1B8B1FE7473F1FED6617F9B9E17F0C7 +:10C57000850FB6CE2CDEAE1BFB8BFCB3802F71304B +:10C58000BDB8F8B81BB1BF69E5DA15E847805E6A47 +:10C5900046BEAF5AA595E3FECFB429DA1AFEDCE811 +:10C5A000C0E781247F9EC0F6F524174CDCE7527566 +:10C5B000F11CDBD3F37C1E9F8753A21F85F77FD727 +:10C5C0006A46F66AA451DBA902CB7C63355FCF557E +:10C5D000ABF41D589FE6E7E34D9DDDCF24905391CA +:10C5E000E44126417F53A0EEC17DC6644EF2403D3A +:10C5F000A1F0F1EFAA359904CF233AB483EFBE013D +:10C60000750F7C57A5433BA827FC1C9EA9A7E5A94D +:10C61000DD3661274D39ED20F3227C8DBA84626AC4 +:10C62000ABB01BAB52BCFFC8030761AD327631A87B +:10C630009D25F07EDB9719D975DFF7FE92E2069112 +:10C64000E58CFCF7B2CED43E13FCF16955A684F319 +:10C6500002C7587F10EC8DDBCE7C228EF6F1B469D8 +:10C66000AC0DE573C9A227E7623D51C532B88E6EA5 +:10C670005BF45C1CE3EA097C0FF592B39E9F8BF59B +:10C680003F3EBF78AA5DCF5A65E25A30406DF64111 +:10C690003CE3F41FAACCDC5E7F0AF721015EA0EF29 +:10C6A0005601EFB3DEDF12BC55ADBC7EBC23B1CF6B +:10C6B000049B68DA744322E34AC0DBDF24E09DC1B7 +:10C6C000E1D19A05BCD3015E80ABBF59C03B83CF9B +:10C6D000475B2CE0958DA9DA24E0AD483BE1FDFFF6 +:10C6E000409E13BE0F75DEBFCE0C639C92C912D85C +:10C6F0002103C25E02BCADC379DF18D06B4D9BDF56 +:10C70000FA8297CBFB69D3399F4CAB53CC29A78CCA +:10C710006FA759F49A56A71EC17616BD12754173BC +:10C720004AC9F8DF59744CD4858FD8FB7F0595ED45 +:10C730008293D32FBB82CF272BE6135359562B2F2F +:10C74000F4F323A10FA65571789E78C5B91E4E3F0C +:10C75000E45C0F4F1CE2FCF5236B7CB12E4EFF0511 +:10C76000E7B3ACC05FD6378ABFA649E1AF6592F8A0 +:10C770006B71E1AF6592F86BF9CBF0B749CC6753B9 +:10C7800084FBC9309FBD144738D97CEA9509E11A6A +:10C790009D4F3DCCA7C4369FFAE08478189D4F7D0D +:10C7A000F888BDFFC9CEA70FF9A1B4B03F159327F4 +:10C7B000E687CDE738F9A1F45C273F6C3EB7383FF8 +:10C7C000949EC7F9A1478CD723E209B1308C377FFB +:10C7D000FCF17EF0AA73BC337EE91CEF07BF2C3E50 +:10C7E000DE19BFE2E33D78E4CB9E47D1FE6AF0D08C +:10C7F0003E6316687290F63774B2A3F7D574C7D04B +:10C80000CEFF4A7590E2797B6BEE54D17EEA49CD3A +:10C8100027FFC9DAC7EC6BCFBF77AD2DCE9015FBE4 +:10C8200088E3D1252BECAEACB0BBDCEF2DBBAB3736 +:10C83000C5ED0BF7FB9F0AFB91C9B938DAFD9114DE +:10C840003B566FA39BD5CE82CB82F3A3C2F5B46CCB +:10C85000C1B5535B9CC27D8D8BD6AB207737363EFE +:10C860009AC6FA8FD945EB5B6AFEF3E17AA4F352DC +:10C87000075CDF342F5DDF22FDE7C39597330EB8E9 +:10C8800036B2CC84F8B2F6FFC6E38F432CF39C0C8F +:10C89000E5864A27DFCE405F0CF8632F2A5E1B9F98 +:10C8A000041BB8DDB8B1D1C9571B641E6FB3CAAC45 +:10C8B000CCD74B649ECC8335AB95DC2C81BFA5A037 +:10C8C0004FBFE3EA77BBAB6EF99DE8867E3013EB92 +:10C8D000C5FD4EFF4888F61DC323012ADDF3DC2089 +:10C8E000F0DBD7A0101CD9EAD93BBD80AFBE5B53AB +:10C8F000E497865AF4F9EB75EC8FC737BB1AEE3420 +:10C90000D07F0988BC2559D32494070195D743F9D2 +:10C91000CBC81F0DB4B086805E18A72CA93519842A +:10C92000BFB6D8525B7EC606817FC6603C187FC307 +:10C9300027B4865E1BBF047D1E9A47D8CBE54F5FA8 +:10C94000AD192BB7E1357B6B3F43BBB7ABA69BE083 +:10C9500052659E5765C1A5AABC1E40B8D0DE46B838 +:10C960006CFD97E90057FDF870B9F165E1C1BDFFB5 +:10C970009718F1321D5CC5692312955502EF71C4F9 +:10C98000FB148C3F4FA172EA48193DAF1C9946F544 +:10C990008A9138D5A32333A93E65A486CAC8C8C7DF +:10C9A000A90C8FCCA53234721A958191062AD591A3 +:10C9B000B3E83B6BFFD03F72263DDFB480D3B1FFBD +:10C9C0001CA0A364A3DB82D3899E252D2C3507E808 +:10C9D00052221F7C99F25B5AC18E950AF82A11F8EF +:10C9E0002A17F82A71E36BA185AFE1D8525B7C6C02 +:10C9F000B388775B74DC8C74B4D17FB18FF37DC462 +:10CA0000CBF5C3A65A162FB7DB994D0AD99925AD98 +:10CA1000DCCE2C71D1F1A3C2351E1DA7B579986E5D +:10CA2000F70F56051DF5A9997247BD627915D36DAB +:10CA3000F2230CEFCE06FD39255DEB7CDEF831C725 +:10CA40007756DC32503FDFF1DCAF2F72B5E3FC5498 +:10CA50002EF2574A918671F0D72DFC6230D616DF40 +:10CA6000FC82C06B615EFCFB08FE8AF676DACA7F48 +:10CA700030D67500DE2A538ADE8BF92CF227D6EDEC +:10CA8000827AC58FFC0CF7D725D6B2EE69DC7F31F0 +:10CA9000D434D6D7F96A059F032F9D4EA99DB419AA +:10CAA000CFBC6F2DC7BC8FCABF9719C597D899E463 +:10CAB0000F1D5B8BB92F085FB4E8FE752553585ED8 +:10CAC00015F24AC27D405E2FCC1BEA1C7FAFA3FC4F +:10CAD000F2B3CB4AD345F2B826DDDF125BDDB65F99 +:10CAE000EF86774CBFE8E3957FF8FE6FF345A2240D +:10CAF0007FCF606790FC1D070F6E3A4DB65D0DCA83 +:10CB00001758EF3ACA17286708F9325DC8F56A2145 +:10CB10005F12285F480E4DA3E75542BEC451BE9C2C +:10CB20008672A846E8838F531942F902A522F82C91 +:10CB30008872E6B4829CB1E2572CC6F9CE923B963D +:10CB4000BC018D4B71DBDBCFD46B7BEDF2A6E174C6 +:10CB5000920311216F22AEF51C11EBB944E88B88CA +:10CB60007B3D375AEB598FDBD7F3ED2E39739B4B57 +:10CB70005FFC9B580FA3FAA2617F1DFA9DB75F501F +:10CB8000E9F1DAE2CF5D17CC267913497379331EC8 +:10CB90007C51216FC6876FC8A1376EB3F459ACF1D1 +:10CBA00024FB101C4F7D0D4F103F2A20B6BDE0BF67 +:10CBB00068F3AF8DED82B725F38FD63D0D78BBD4EA +:10CBC0009739E403FA979C76083725D8F6EBDF8C83 +:10CBD00065485FDF4971931285EFD3DC36FFAD14F2 +:10CBE0007E07ED8FF8F8BABD4C41B899DA86EBF9BB +:10CBF000B6AB580EF781F44EA7BC9B7E4BD021B745 +:10CC00001237963BEA55D75639DA87189777144C7E +:10CC100000BE8DAD74CABD50CA29F70275F31DEF71 +:10CC2000AD7D8831722F36B97510177A3626F46CBF +:10CC300018D7C19402FF8684BEB5BEB3F4A3450FD6 +:10CC4000C60649EFF5D4707EF58635E98AFAB174E7 +:10CC5000E99A7713D9137E175FF8055FA8826FFDF5 +:10CC60006EBE48587CD1EFD0433D2EBECDBAF8F60B +:10CC7000630AE7DB90D08F1BE73D5187F1919E5906 +:10CC80002EBE15FB24F09F3E471A1FBEC849E13354 +:10CC90001D7C9BFDD07CDBCD303FB15F626DB80F5A +:10CCA000BD715E771EF325955A99EAA153FBF2FBFD +:10CCB0003006D5CCF749812F1B15A0DFC6537AF378 +:10CCC0003BE179F78A303D8FB021865B5E16FD49E6 +:10CCD000C595235F39F934940ABAF848C8CF49F2A8 +:10CCE000CDC58A2EF6BBB85D6B9EC2521D0CE350BB +:10CCF000FD8604AFF41755B29BBA0F4B39CCB7EB96 +:10CD00008B7B487F1EBB1C1437D6ABF331A48759ED +:10CD1000A368A84F63C98C84FAB082B5AD5807F0F8 +:10CD200077B7F378FC5D35379D7A050E2BB79D718B +:10CD300031E077209CB958017C1D8FB37E5C7F5217 +:10CD4000D5AA0CF67BF3AF251DF7230249BECF16FB +:10CD500042DCE3BE439CC7F382753C9ED717E7F1E4 +:10CD6000396847F13CAB3ECADFF17C2C6CB36FBA3B +:10CD70001AF6137FA809C11FF9AF32CC87F627DA5C +:10CD8000284EA7CA83799467AC9EC7E55435974768 +:10CD90003E61753C0E1748F4531CAE4FEC8F79C3BF +:10CDA00006C3F6E17AAD01F53DC615B17D30A9EDBA +:10CDB00040BE6C51B87D1E0919D729247712DAD1EB +:10CDC00090A093CD0FB1E2956A12E410CE277F01B7 +:10CDD000F51B48B014FA09C04906E2454932ED5B3B +:10CDE00062BE94D7A3B39D218C5FCA2983E2873AA0 +:10CDF000875BC6F7C8DF096D9707F71DD534F13B90 +:10CE00008B313ABFE313DF2B31FE5ED5057EC53E85 +:10CE100026C63F09BFB67D4BCD56379B79FFE6B995 +:10CE20004AAE43C2E779C77E655F8DC4D7F389A751 +:10CE300063CB6CEBA8EFFD3FC630AF61EE3D9FECDE +:10CE4000683913D7C9EC5292D7BE7C4C2B628776D7 +:10CE5000B7EF29937DE3F36FB725BF845DEB0D73C7 +:10CE60007D0B78D411FF6E3CA27F66E171CEDF109E +:10CE70008F1B45DCD9C2E3465B9C59B3D5AD796CB9 +:10CE8000AC1974E06F23E20F79FEC4F763CB6C72C8 +:10CE900072E3BCFDB10CFACF8847AD8047FF5AAFB3 +:10CEA0008E79B235325FBF1B932C85FEC586FA356D +:10CEB00026D9736733CA7728ED7F37EF45F8011F0E +:10CEC000343F4DF05D823DE0B5C11300CB0EEDB7B0 +:10CED000E950A27DE7D3830EFBCEBF56A1F1FADF66 +:10CEE000BF52C7CD5DCD9389611909659E473E0F3D +:10CEF0008707711B9005A3FD79D4CBB319C7E39ABB +:10CF0000733C94EFBECD67FC0CDB6D96F5A928371A +:10CF1000361FF0318C7F6DD63DAD74EE470F115C3E +:10CF20006BCE29DFD16B83EB5F841EF893CFF8398A +:10CF3000CA4BF8FE2EE6F89EB516F34B5F12DFF5EE +:10CF40008BFDD0FEA6AB73EBD09FAEAEA3BC1DADE8 +:10CF500079D5B615589F5E4FE7D9DE50ACF8D6416B +:10CF600086F10490CFFFA1D8FC087F6288F200DE32 +:10CF700000FB02FB1D16F23310CE186814FBA22929 +:10CF800096A17824E7EFF1F85759FB70196EA1C20A +:10CF9000FA273967F1E3E60AE7BEC5E60ACE2F288D +:10CFA00027345BDDEA6773C5B053CE9DF3DE49E4F9 +:10CFB0005C3F976B492ED754D5E0724FEC477813FE +:10CFC0002992739B859C73C3FD3B21D7C693679AB7 +:10CFD00021F8AA8ECBB3603EDE2447512E32DA17F9 +:10CFE000017F8FD6A1BF0EE4590D97E7D83E28D612 +:10CFF00021E8ED75F6755826DE07927C9DF9557D82 +:10D000001DF667F171B9786FAD536B1D66E77279E4 +:10D010008678453C66E716F22E345B1DE4591DE622 +:10D020004F65E79A8447808FF23BB3A3EBB0C3B15F +:10D030000EB3EFEFA2F5F7CDEAADB4FEB2359CCE5C +:10D04000599F59548E6D4439366B7C3E18F523E454 +:10D050001CC931CD30C90E0BA4189DFB080BFC81F7 +:10D060008CE072AC66BF41F34D811CABC1FD503EFC +:10D07000DF7012F05743F893BC36FA9689F7A1FA9D +:10D0800071F09772E2CFE2432BAF05F5AF3DAFC52C +:10D09000C2DFC9F2567A46F5C0371C7AA067563708 +:10D0A000D9E93D88C754018F0539C6F36E7A528C91 +:10D0B000CE0B6E48963761FD18CC1FF310CA5B7318 +:10D0C000B4BEDC780C0BB9552DE456B0DE25B7D4D0 +:10D0D0001CC37DC560FF0ED36393838CB5313B7D4C +:10D0E0002DF906F2EC6ACCC7B3C93313D7B7E9E719 +:10D0F000EB3D12CED3735F7490E4416FB5B01375FE +:10D100002EEF6297A77671BF8FE3B37219AF9B7E44 +:10D1100085C7656B58F326E4C3599EDC3AC063EFBC +:10D12000ACF514EF3F76B992125F31B912EC21F1F0 +:10D130007B16EC27FBBC7B845D65D58FCFE276D474 +:10D14000A81CFFF337C89E62604FA15D26CD5E3BF1 +:10D15000C79E7F31106E36FD0B88BE247F228D1C4A +:10D160004E9807D11DF90AE9DE5BCDE98C7CA0D988 +:10D17000EA563FBDD53967BED2DCDD27913F07B9FE +:10D18000BC69B4ECAC3C974729CEAFA1C420C99F81 +:10D190005E217F46F5C75CA73E58ED17FEACCFB8C1 +:10D1A0001BE7D12BF449AFD007BD6E7DE2FA7E9B21 +:10D1B0009FCBB15FC9C60EA473AFD02785EFB93E30 +:10D1C000B1E8E7D7B51D829E27BCA783DF285EE5BF +:10D1D000041CFAF3CB4B8BE5C5592513FC599097EA +:10D1E0004111D7F980EAFA93137FDF87F92C94571E +:10D1F000A351A9AFFCEC84ED2DFEF0B3CF51BB40A1 +:10D200005DBF817C1A69CC539E42B04E6FF0727044 +:10D210000C56C9FD0BFEF30CAD0F20556A40C3E759 +:10D2200087CD3EE4E7C56CD88F7E48A32BDEE3BDF7 +:10D23000BCB4D87AB4CAB5877F3BE5199B7F72D05E +:10D24000EF8C071D6387591E8349EC60BE0FE5987C +:10D25000C186ED79D7A3FCDDFEC694673015E9C021 +:10D26000F209E35F01F08331CFCF9AB727D9CF28F6 +:10D270002E5F9F43DB9E85EB583E70CAD879DC86D3 +:10D2800030D0B990E38BF3E193D37303E2D74FE748 +:10D29000081DEBD05D8EF66BBEDB91473F94FD829F +:10D2A000E4F731C02FC6D9FC6193FC06F0F9282FB2 +:10D2B000AD249A6676BBC10DA735AFF1C693C31FE7 +:10D2C000AEBD121D8D2F0AFFB1B85ED707632F23A5 +:10D2D000DF1CD3F8395B596EBB7F288AEE3228EC0D +:10D2E00046AA3F3484EBD8F46B0FA27FD00CEFB189 +:10D2F0005454AD2355C05797E0E32A959C44765784 +:10D30000A884D6F7DAC311CA433BEEE95737C22BDC +:10D310006FE912D2135E6F431BEE639C77E23CD53C +:10D320001E3798AD723B6D4398E7776D90DB548C58 +:10D330009BEBCC50913F7A349E4736DEBCD584C7F8 +:10D340008127251A9C100F17615B18AF53C4033A4D +:10D3500003A9E5F6FCF1456A80DE5709B8CE3B51DA +:10D360004A79711D9A87FCE66CF876B506FDE417DC +:10D37000BD0C8FE56765532DFF1BC01765C34F7F3D +:10D38000807409737BDB1F6936F3481789B5CD427A +:10D390009B5F93DFB29FD7D2595B1AF9B133217BE0 +:10D3A0007AEDFAFCAF8CBFD1B84486D5A13E97592F +:10D3B0003085E37D2E9059A6227F2DBCD0E804381D +:10D3C000FE80EBBF02EDDF0CE979EBBB0B2A5612B6 +:10D3D0009FE0BC904FA024B9FC8704D8996897447B +:10D3E0003DA6BF483E024B80BE75C4BBC7814BC83B +:10D3F000417A05EBB06984EF3F0653FC9C2EC6636F +:10D40000D0CF29454CCEC4232BBA44C9AD2C25A579 +:10D410006953E16CDA678C06FEDAFD5E4EFD4AC6A2 +:10D4200016F641E843F42B0FD1BEC45FBDDF93C0B5 +:10D430001B60F750BF489D0FA614FAED81750FC20F +:10D44000887580FEC2D20F2D19B7EB687D6C688F8E +:10D45000D173263F6EA01E0FE37E0CC6CBC0CEAAB2 +:10D460008176BF6F5287C1F766D67E88B5BF1BAA8B +:10D4700063746E349472CA3D353139B9D65531BBB7 +:10D48000687EDC28FF00A7D6D8F4F678EDFED665D6 +:10D4900007C8CF1A5B3C440ED716F87A82F9795B3D +:10D4A00032141FC70D2FBB1E903D3C4FA5237C851A +:10D4B0009A213FE7830FD0AE113601F89BE985C56D +:10D4C000F0F23C26115414EA3EADFBCB780ED41793 +:10D4D0005B69D8CF91FE0BFEBE009F5F6B0C4D8247 +:10D4E0000E5EB99FF2DA8127C82EDF12FA023B5294 +:10D4F0008FFAE10B14D7E8AEA8ACA17368569EBFB3 +:10D500001AA6FB012C3EDD5B71690CEDDBAEF8A5C4 +:10D51000313466BA7CE918CAE703154F182BF0FBC3 +:10D5200013A5E833B1EE582DF96BDD27664E6D2B50 +:10D5300032BF10E3F202AFBFE1E7BD158C018EC22E +:10D54000DB1DF3A808CF1FEAB9DCD912FAB181FEBE +:10D5500096A2CB6DD8BF12867161FCD6C64103E39B +:10D560000A4A269CC1F37DEE7EAC71E047427F857E +:10D57000CED25BEB4E72BC2F0AC7D87AC6C03C60D5 +:10D580001FD811BD45DAFBD4123304EBC45778AE73 +:10D59000E1B8C9E7E795F2BC0985E2CA1248045C24 +:10D5A0005705FECF39F751354FA15FDBFEA10C7E49 +:10D5B00054313BA35BB1FC5B6339E2AD532A9FDF7F +:10D5C000DB3881FD12CBBE8B7E0CE02C8F7CE58F8F +:10D5D0009D6F227E3BC1519B4222A2EF209E9B86E3 +:10D5E000F25D3CB7E3D7E437ED7C9708807D89484E +:10D5F00014F66547B876C2380CDAC96C02FB2DA068 +:10D60000A4323C5FB98DEE4390D92904BF9CD8FF6A +:10D61000720DC0312FC0F5BD9CE4E789DCFA756B53 +:10D62000D09817C0FDED20EFC7DDFF83C1E686006F +:10D630007CFFAF6AFA342CBBAB1609BDE75A27E171 +:10D64000E8A4E2F9DADA14178ECC28912A391FE31C +:10D650004FB03E85672158EC2CAF262FE474457BF4 +:10D66000CE17F332DAF7AEE3E7B8AD73E325AE7B5E +:10D670000DBCC6678D998DB46F31EC8B211F39CFEE +:10D68000897B911EA760E97CFEA980D3DEEF687FCD +:10D6900092BD668B87C023A3589CE9B260F3B24069 +:10D6A000B13853B87C5278A0BB1DCE44BE6BCB5270 +:10D6B000DE0D9E97D7F8F904A4F75D421FDD81FACD +:10D6C00008EADF10FA07CFA76379777B1D95F7B6D5 +:10D6D000A7E87D67FB422A37B51B546E696FA572B8 +:10D6E000637B9ADA29F14E15E9B63D3E78B7441EC0 +:10D6F000FCCB2DCF4397DB2383AF609C8399FFC680 +:10D70000EBE29CF54D3D3F6DC13CDEED65839779C5 +:10D71000008447BEF1E3CE6700DEEDB3065FC123B0 +:10D720006D8F06F63DD389EDE7F1F6FD3D432D788B +:10D73000AE7BBB3807C912CB4E82072E271FC0A075 +:10D740001BE0637B85D8679BE4770FE377506EAF70 +:10D75000F970E305E47E83CF77A4E5C518E53F11B2 +:10D76000FCFB7B8E12FC24AA1631F6B39E373A6975 +:10D77000FEF3AC3CA734BBC4263FF6057C1CEE860A +:10D780000F07F73362BE8A366C6088765120733F8C +:10D79000AEBF9255070D3AE79DD8674A3AF6179DF6 +:10D7A000D479B80006DD2A0AED95C614AB85473F4B +:10D7B000529DCFCB5B0DF2DB1E09F0F3881BEB9B78 +:10D7C00055BE8E0D3A1FF5B8788E0630DA53F2B397 +:10D7D0005EB27BBE3F4E7B6C673616DA8D0BA7764A +:10D7E00012FB7692F36432D80760BFE55401A7F8C4 +:10D7F0006E93AB1E10F7734D961EBF17F4B8D6D5B7 +:10D80000CF0A5573E06FDAC31EB6B09CE705339BB1 +:10D81000BD10BB3CE8A8572E2B77D4A34BAA1C7590 +:10D82000ED6CA75D54B5F2638EFAF41BE73BEA3E5C +:10D830006D91A35ED2D8ECE8AFBCE542C7FB70FDAA +:10D8400052C7FBBF14DFEB5DF8B8D9559F6C3F0A98 +:10D85000C64DA760DC94FBBDDDDA157CDF0769846B +:10D8600072B9BF81EC276BDF0A190CED6B4533C829 +:10D870009E0FC262E5F121A73FE74B38E3A7B1E570 +:10D8800046DEEA17F797148C93927D6F10DFC8611C +:10D89000960FD039546E77A3F8453BC2CFBE9DADED +:10D8A000E5DFA5EC796FEE52167945784D0DEA8DDE +:10D8B00093C52DDCE3C496A5278C0BB9DBB3B0ACC4 +:10D8C0001FB5AD9BF1BF93D9519B1D353BC81CF9CA +:10D8D0008D46660DDDD314649E542F941D893B4DF7 +:10D8E000B447376013581FDD58223D635C6F8DA02D +:10D8F0003C5980FB2C9E237EB45FD8A5798A19C73A +:10D9000026A7D74242AF3D1B4C9F19847E94AA03A1 +:10D91000317BFC4D51B85DCFEAF9FAEC6BB889E286 +:10D92000AD4AAD46F1BE1A39AF7E26C2C6ACD31E93 +:10D930003CAF3E0BF729F939D74092FBDFAADE4F07 +:10D94000A53F61D273EBBDC577AC9EF369778A9F23 +:10D95000EB55D43CC37D9070FF5EE675F05D862D7F +:10D960008B14F617B7639C9EECD49CC87B71C60FD2 +:10D9700046F9AB7E72EBE06691D774FCEB7919EF58 +:10D980002158927F56AE05FEB9292851FFC7BFCE58 +:10D99000EDD017DA471CF6C7578395F47EC992BDC0 +:10D9A000F2629B9DB884F1BC5DCC9CFECC3CFB78C4 +:10D9B0003CCF83C9C34F7F807E406A62F97C51ECC3 +:10D9C0004ADAE7B3EA3F4D79295EF55399D13ED85B +:10D9D0004F533539B3C8F76EBBFBA2D8D5D4CFF1BE +:10D9E0005BF332DA912FB4AB12DE2F80F3C4F8FA76 +:10D9F00092D6BD32E6119F0CEE2FBAF8B717FB99FD +:10DA000085FD1A942F2CE72FA078BD5C6718060FB0 +:10DA10000A139CF281293B515E9C77E2D3EAD248FB +:10DA2000A13FAB7F15E769CBA3CE6A3CCF3B8BF31D +:10DA3000C4FD384DA7730E279BA78AF3B49DC31E60 +:10DA4000C5B388678D87E7CEF6CC84F90272849FD0 +:10DA500083947D86562CEEE686C3A7417F76396F88 +:10DA6000C1119D188E0E84C3C65F9D511E9FEC048C +:10DA7000F93C9971E5B06B5CC0435D25797324CFA7 +:10DA80008FD732A315F0D93D9D11DFC0177F1852F3 +:10DA90000BF110BFFA29768BEDDC8A9280F78EFEAF +:10DAA000DA485EFB75F057505EDBDFDBFC3915F5BD +:10DAB00002B4F346BBB95D1F0D527B6F543EEABC06 +:10DAC000178BB757A64B742E8672AB299F8C3D835C +:10DAD000FE865C97DA85EBE38520DFF71A09645E42 +:10DAE0000812FF1926EEC383E9DC8676B98FF59319 +:10DAF000EC57AAEAC85F1BCFDFC9BAF6532DFC5911 +:10DB0000E7B8D8892B75D26F9EBA2F63FC68B27EB6 +:10DB1000534775C3CB198CCF56F07B6EC79BC7EFAD +:10DB20000AF3F89D9807C517AC7904B43411A32300 +:10DB3000327BC279748A79B8E9DF69CD6392705B10 +:10DB40007ECE183C55AFA3FD44B35A11FB9CCE7951 +:10DB5000646B783E7C67756A17C631949022E40244 +:10DB60008F13C1FC94909D2F35AE07365477B3F5D3 +:10DB7000B80E18CF6F1BCF4E51D5EF38D67134C4C5 +:10DB8000ED9BC0285E051F36723E1C0966A2389EBA +:10DB90003FD97D90FC7AA16F82757C7FD2DAE7DE77 +:10DBA00054CDF323AC7DE94DD53C1F02F308345B23 +:10DBB000DD8203EACEFDC9052F9D647FD2B91FA97E +:10DBC000AACEBCB0602247FB939B443E09C3CB0A5C +:10DBD0006DF32F0D15CF3BB7EA7117BD06AA459E11 +:10DBE000818B3E03AB9DF45934963E8B8AD167609E +:10DBF000B5E0BB95C5E91257BFEDA0CB58BEE2F129 +:10DC0000DF32BEC4D916ADB5598279F7304EB7BEF2 +:10DC1000B24BF1DA3EB649DBB60E9F7F5ECBFC5DC0 +:10DC200008FAF1790659A006EFC9E0FBF3161F7F49 +:10DC3000C2FB96FA6B80E7B685B5A557407D4D4887 +:10DC400072E0C72A77B6C31C66A17FAED2157FC724 +:10DC50005F9D3361DCA6BB5D75C8FBEEAC4CFAA6DC +:10DC60003B567B3BCAC7AE6892F2790CA386EEAFF7 +:10DC70000E26F4F9984F70A56B7CC0E39588475F3A +:10DC8000B45FC45D387E67193903ED9824885994D0 +:10DC900027A55B592ACFD711EDCB5BF809D6694D83 +:10DCA0003339AA87316F13F0711DF6973C7B308FA3 +:10DCB000FB796E7CDCB6D023F29BF839140B8E7D99 +:10DCC000219157932C17718B54AC983D6BD1ED7EFD +:10DCD000C0573DC61244DC7DCA2D3C8FB9179F0347 +:10DCE0001EE785D2B7221C5396E424C4E3DD62DF2D +:10DCF0004A626A6725EAF33A7E7FE2FD5F0F0A3ED9 +:10DD0000E3798B1B04FFDAF86C43313E033EA56DCB +:10DD1000DB1591CC46A47F40CA6BE8DCCFB885AF59 +:10DD2000DB2E2BAFD7642F203FC5AD5C08C6D77163 +:10DD3000B9CEEFA91C0CF1F89916D650FC33FDC5ED +:10DD40006D12E6CF7664C206CAD31991E6A666BE06 +:10DD50005F3A8C718519D506D559933AFC20DE338C +:10DD600094D625BC87A0DA5087511E4501DF788400 +:10DD70000CE3E5B82F5BC60699AF88BEF62A298A60 +:10DD8000D3C6C3572FC1FB26A5926D4D0A8EFB55F6 +:10DD900046F7C195B79AF90C2EED857E0DFB9D5186 +:10DDA00033B40EE546C7452CB50EDE57DFC8DF9706 +:10DDB00083DB85EF61EA4D4A0DD18D5D6CA39B1A23 +:10DDC000CED07D96CB229941C4A3AAF3FC30CC1FC0 +:10DDD000453C6DF6E5C85E0E9E6D1A08CFCE9ED30B +:10DDE000D90A1BDFEF157CE1AD6346AEBEC07F5B99 +:10DDF00090B9018E4D8DE5812F86B15D90E8368B0F +:10DE0000350ABEE5F9D441C1B7C09779A453B26EC3 +:10DE1000D0C4ABCCE2E19C817882753995C3314C9A +:10DE2000F94B9B7B14BA5708E8F612C3F8BAC749F6 +:10DE300037356C3C8074BB39C4E333BEEBCDFCBDDD +:10DE4000808712C0930EF4F0B60DB22BA15D04E8EA +:10DE500067600EDBE11FB2E950D7AABC0CE386A1D4 +:10DE60007A33FF2AB49FB23C847BDE98AF45FADA5E +:10DE7000DBCAE3E965318F84FB1580AF97105FC182 +:10DE8000C64113D79185AF6EB9ED57B7A2FD73C0E8 +:10DE90009B3275DB7A61A998DD5FF4C7403E14B10F +:10DEA00053ACF627D3AB05BF96C7752D7B00D6D5EF +:10DEB0001B0897ACF17535593D6DE5F9020E689E6A +:10DEC0008AC84F55742BCF37C3F3E2623C2F0EF351 +:10DED0004529BF346AE575A54CD243E29E0019DF9F +:10DEE00037D23D1994B7E5E3EF5897C893C6F014BD +:10DEF000EAC72E91176DE5B975C5D3CE7C41C9CA65 +:10DF000073BBD891A7D5354EFEDF9630979F5D2223 +:10DF10007FA927EE213BB4C7CA0B3F2C515E784F37 +:10DF2000757A39DA45E6AB21B2A7F6562834BF9E9A +:10DF3000C3915DFE1ABB1C77E531C59D794CEEBCE3 +:10DF4000F05A7335BF6F28B653C5FDE9DEBAA51385 +:10DF5000E69F6C6CE77907DD22EF6074DC71CEBF61 +:10DF60009D13E6F20FF78F345AA769B2179404CFC6 +:10DF70002BF623DD904E3ACF67ECAAB889FC1B5FE5 +:10DF800082E7E3617E1CE50BC5783EA34F4E71FB33 +:10DF900041DCE7208BF716DD2C3AF75638E9D6EB53 +:10DFA000CAF3ECADC839E8D63B4AB75D0EBAF5CE38 +:10DFB000BD94E201BD785FC422A0579FB71BE3ACBC +:10DFC000B526CF83EAD6F93E6E577C29E5EDF7E812 +:10DFD0000AF9153DC9E2785475CEE7169DE6858CA1 +:10DFE0004F86013F770B7DA678F879780B9F330534 +:10DFF000FEFE51F0C93F8A7A4FF20AA2FF31B41BEC +:10E000001B189B8A59560062657D5AC2F53D10CE99 +:10E010005C82FD1EFFE5FF8853BC21E671C403A2AC +:10E02000621CB0975B691EFF3ED343F3003AA15FC9 +:10E030003533ECD4EB4A96DFEF6ED10FE8A1175BD6 +:10E04000775D1557135CB02E292F7C74DD2546E9CA +:10E0500067923D981079E1AE7567D1FB6F4DBFC7F0 +:10E0600082E99BC30BB83C41B9E4E6CFFFAAF303B6 +:10E07000EBBE1BF3ADFCECF31F2ADE377E1E473FE1 +:10E08000D943F1C37E7EBF5F416EDF1F86F7F195F6 +:10E09000C21EB2FCACF432E18FE89E0330AFE89DC3 +:10E0A000B53B8AC573AC38D971E8FB20ED67668251 +:10E0B000287F766FBD228871AFDDDB269643770B14 +:10E0C00039B443C8A1ED228FCF7ABF5DC8DB7B5C3A +:10E0D000E7ABC311BE7E5E12FCBD5B4D0791EEEC5B +:10E0E000E9CB2EC4BF9B917CD14B7268DA96C1B24A +:10E0F00089C6C7B8BA231FE243E6EDFD24ECDC571E +:10E100003DD9F756BEDE47C5CB3D48BF2AC0C3A6A2 +:10E11000CF75D3FE51BE94F8B1F6462EC7E2D94C66 +:10E120002FE378C04C14567AE2BB74FE6F671FDD94 +:10E1300001847ABC644525A39C2BB4977667977AB3 +:10E14000D01EA98E7B99077DCAAD7C9F53857F3CED +:10E15000FE91A77B60E28CDFB73AB3DFB90F1A17E5 +:10E16000FBCED5AE7DCEF8E1DF1E463B2FEEBA5F8B +:10E17000FBA3E2FDBDB0EBFCECFF23BC6F970703F4 +:10E18000F67CF669124B237F4EBBEE75C7B9C050C3 +:10E1900084DBEF6C6D98BD668BA7DF230D96A17CA9 +:10E1A000DF71ADB8A70C43602887EA86BE43E7401D +:10E1B00056DCF4FBA7D05EA978E35C94FF532321DF +:10E1C000BEDF78ED1A47FE23F81F532336FF6C4756 +:10E1D000E7522AB79FF8CA5E1FF437EB4696E2F77C +:10E1E00030B097F0BE7B5DD0B9652B233AD7C6BC63 +:10E1F0008CF22F4C279D6B57723937AB8FE5906FA0 +:10E2000066AE32253C179A5CCB52067C5FBDD64683 +:10E210005FF82FB975CC7DF0CDC82753534CC77C20 +:10E22000D5647FDBDE7B6DFEC254177FB8C7DFADE0 +:10E230000E5E40FA10F803EDA7597A9B94C7F133AC +:10E24000E1B61C6E8D2D778E1F8769223DDCFCE8C0 +:10E250001EE7A3F25B4BC4B9CE8FB1CB3FBB07F037 +:10E26000B1B3EBE17F9D4DC8EDF7D8FD528BDF6474 +:10E27000665C887462E9A8F05F8D9A62F27C544E05 +:10E28000A72719DF629F99502F942F71E67D692D82 +:10E29000CE7AB0DE59B7F69946E962DD0B60E50B40 +:10E2A00064D2BA7D7ED988F932FA9D5F893C767E48 +:10E2B000148442161DFF4558FF11C92309777E506B +:10E2C0003F26659247C7E77AC81E0C57283954562F +:10E2D00032DB49FE186BE442C52BE209210D1D34E7 +:10E2E000F487528EF30C85FBCDA3422FA56313E177 +:10E2F000D1B8BC89E1F952BC3F9DE29DE0B7AC27A3 +:10E30000FB54A67824AC1F3322FC99665C7FE0277F +:10E31000E373CB8FB7C639191D26DBCE3A2FDA89C6 +:10E32000E74561FE65D3B51ACCDF63787FAC6EBB81 +:10E3300057753A3F675AD6A2D550BCF67048231F8E +:10E340004B9C0FED14F26994CFCAC02F00B97B7AB1 +:10E35000303310B1C5ADA4F256877F10636DDCAECB +:10E3600064692AB5A9ACE1191C7F0A8F837644BA87 +:10E370006B50BE745638F5EC6F841CFB76C44B7240 +:10E38000480BF1FD24A69A71FB3ECA898864BDFF43 +:10E3900032F2C51F22AFEECFE2D9BE52D680791B32 +:10E3A000FD9B7F7B7E2BDEF73E537C9F18E7FB991E +:10E3B000EC7BD8FE8D4DAFEC9781EFB4199CAFDEAE +:10E3C00089FC89F84A9BC3CF3BB3467D4727C0BF32 +:10E3D000EDF395746FC8944FADADC1FBA346FB41FF +:10E3E000DD00FA71587CC7323C7E67E5F181DFFFC2 +:10E3F0003F715DC65B07F3E8EF7BC3563CCA88AD4F +:10E40000B0C5BB3F810E2AC675357DA7DF66D71D17 +:10E410001478B1EAE807609C6E646826C5E7E418E2 +:10E42000F78FE59899B7FB6D4C6B2DEC63D4E2F94F +:10E43000BA0B49AE33ED40F475DBF31311B1EF2D98 +:10E44000A763DD51D40B2A9DFB817964D8E98E79CD +:10E45000BC8C741F3B0F2BCE585FFA6BDB3A1A72E1 +:10E46000C1DD25E28A56FDAE388F978D8E9F4AC555 +:10E47000BA1B0BE31F8D88FC84B0C9EF15D2A08CAA +:10E4800014DAF72FFEBA84E31BA1CCEF102EA535CA +:10E490004D709D1F33286E36DA6FD4D9EFE8F3182C +:10E4A000EF77B4DECAEB3E201FE6D56A8B97503E6D +:10E4B000749788B31BCBF979E360829F8B72AF3F6F +:10E4C00058E727EC7AD28ADF0D848DF7F9FA1FC757 +:10E4D0005E16F1B92B160A4433FD5CD49BAB455E46 +:10E4E000D89AC7EFDD8F7A6DCD99A04553B8FF77E5 +:10E4F000FF7ED4DB5EBC0F85F21AFBF7BF0AF595F1 +:10E50000CB438CCB9F7409E2E96DC6CFDFBCCD5EF7 +:10E510002839CDB6CEA695883876D6477ACC847F72 +:10E52000C80757F5FB1C7AED8BDB9CF5ABD9D24ABB +:10E53000941B576FF5B11C9076B54BEF854A38BDEB +:10E54000BEC8DABA51DE76897BE3AEFBC13C05F189 +:10E55000B6FA34ADC66BBBD76466098FABBD09FC98 +:10E56000ACDBE4CC35E19C82F700BCF6D869979E21 +:10E57000C5B09F5C775523DDE94FF2C38DF72BB310 +:10E580004E384F360F37DC965F311E1CF21EC928FD +:10E59000760F5B4389E4D8C71D3D6FB15E661D8D64 +:10E5A0009837FBF587F07CC65AD3AFE179C2E38197 +:10E5B000E939FCFB4F1794E8E2BBB633789E51DB98 +:10E5C000A958F6467369E43B2B3F21A0B6118C9203 +:10E5D0009C267EEA8D9DE47D02DE7B27789F9CF859 +:10E5E0007BCC3FFEE0749E024EF7E988785E56E8E9 +:10E5F000810E5FFAD3A8573AFEDD4BE7B33ACADA89 +:10E60000E8DE4CB39AE9744F66325D8A74F6BFE86F +:10E610008D7A6A042B639C20DE4AF1CA65253E216F +:10E6200067F8BEA63F6CD2FE76B72F132B033C2BA8 +:10E630005FE779134DE14C06BFF3C696FB304EF50C +:10E640009387AFA4FC8E6B62E7CB2817FFA184C72A +:10E650003DDFFED6F74E67005FF7231196277F3028 +:10E66000A7A03F78CD635E8AD37EE9BB111AFF9ADB +:10E6700047BFB87B09F423FDE01CFD28ADCB0EFAA3 +:10E68000FE9A272EFE9929E6833E75C73A910767C1 +:10E69000A662A8FFAEF3B37FC07870D6A50755BDBC +:10E6A0009FF277AED95346FB1BA3FC2243FB7A3A79 +:10E6B000FFF90FC5FE0E4387E0F7B7223CBE2BEDF6 +:10E6C000D9FB05826FF0EF7D382F29D1C67E03E399 +:10E6D000AD15F38376143730BF29D1FD6B6F7D7391 +:10E6E0008782F914D7ECD9A15C61DBFFB7E054F75E +:10E6F0006C31719DA849AD16E3CB8BBFFB48099ED9 +:10E70000BBFAD277DFEF5E04CFBFE465C34B403E78 +:10E71000DCB0C77B04CF690474979D2AF255AF27FC +:10E720001104EDBFFF1FE7FF02BE7B13E410A6C874 +:10E73000BD79F037CA0FB10EF631CAA11B9E74AE77 +:10E74000AB1BF6BCA6E07C340F1B4E9C85FBF74E42 +:10E750003BD9DDFE183BA1609CF986C11EF2E76E35 +:10E7600078ECED43B83E6E70ADCF37F197F8583B7B +:10E77000F99B252E7F78CF9449D9B35F7AE4D87D71 +:10E7800026E0F1AD477F779F0978BCF6CF7FBCEFDD +:10E790007F607CF0C7010DE5CB0DDFFACD7D5F8397 +:10E7A00079BEFDA4DF837CF1CE530FED1E80FA3BD2 +:10E7B000AFCC992F417D9F58F7EF7CEF4F953AF4FE +:10E7C00073E3539F988A7C77E3E38BE9FEBDF1C640 +:10E7D0007FA71DCF2ADAE1C9F1738B4F4AE8443095 +:10E7E000F62351BAE8C0FA87155C67EF49FC5CDE96 +:10E7F000F583EF2BC87FFB0D368C7879FAB1D7F60D +:10E800007F0DEA6F035DFC45E802F39EE6A1731BF2 +:10E81000F969787EE3FAC72EFEF4398D58FA52D89A +:10E82000FD0D6C98E4F5187ABE08F46C2CD0735C7E +:10E83000FA3DDC43F909370C02FD4E194BBFB7F125 +:10E840009733C7D2EF4889DBCFB9F6FE017CF9D800 +:10E8500094A276AEE5E75CF7F82513FA53EFB8D645 +:10E86000EB78785E25FC8DEF9418EF96E07A7BF4D8 +:10E87000DBBB07A248677F0AEF5B7EE79163D3F1BA +:10E8800010E61BBEE12F201E869FF26B3BE19B6BC7 +:10E890009EFA39E985771EFF574527F9CD4A24901E +:10E8A0009BEFB0D19F17D06EBA5EECB75DF7C0FF9B +:10E8B00039FF107C7F1DEE9F69443FAAEF37F8793E +:10E8C0009AEB739F69D5310F245741F3BE3EC7D7EA +:10E8D000C3F5B9BDCB30CFDE8DF7BA52EBFC7F81EB +:10E8E000AEF877DDAE7FECC8F9C87FE3D1D39ABF2D +:10E8F00086F33F03DE3FE05CAF63F9665841F96F92 +:10E90000D1F79D1DC7955F40FBFC0F15CD8376B2F7 +:10E910006F5821BDFC3DAFF6606A2CDDD1EF5D4143 +:10E92000FB65EB8BEE37BBF96166A96B3D0B7C9CFD +:10E930006C3D9F7C1E1F0E4F534A7507BF58F85AF7 +:10E940001757C8AFF4962874FF7EB74FFF39E60714 +:10E950000F3FEB633B7594EFA7B3627FDF13FD2896 +:10E96000DDB6BF2287D3940F2A4735BAFF626CDE2B +:10E9700093C775EF1E3FE7A99832C3730FEE739DDF +:10E980006E3BE366AFF14AA686FCB44F9562BCD4F9 +:10E99000D3F6E410C6914BAF1EBA9515FEBE8FF5A7 +:10E9A000777BAC712F2BE572CD2AB7A29F8DE35CEC +:10E9B000C2720F925F9896EC798BC482E0F75CBECE +:10E9C00079DF27C9EF81F7C82FEEE7D678B296A690 +:10E9D000FBCAFCF53C0F12BC8B215C379D62D17CDD +:10E9E000A994C7593FAFA5579622E913E0BEEBDCC7 +:10E9F000AF182AA24FAD12EF69457FA8BB3D43E592 +:10EA00004DA58CC72DB44103BF07BFA50DFB83F1F6 +:10EA100072B82E651C4CFF4BFAD7C87FB1F266E680 +:10EA200085325F43FCFA75BE5FE64FF0B8B657E437 +:10EA30007F76F89CFE6DA7C0AB558EEEDF54ADDA45 +:10EA4000837FFFB1BF29D6C0F9214DFE6A57A96463 +:10EA5000F965E497DC21313A176E4A2AA787C17419 +:10EA6000AD92C7E3713E5ED52067CD87F9ED744F57 +:10EA7000A1496500F98BCE3BE5C9AE7BA8B456DC55 +:10EA8000C338249C3B83F8BA34C524D42F5B232994 +:10EA900093E8BE82690F3614DE779F23EE51ACE314 +:10EAA000F5585A63D87E4769B9B55F4B79CF533370 +:10EAB0009A86ED06C2E97B11EF561CA09165883F4E +:10EAC0002AD530CF7B5BEE3AA763F16599136FBB14 +:10EAD00005BE1E12FC81393A55E58E738ECC7ECE72 +:10EAE000D18A7F7489FBB2CAA66B2BF0DCEFB8F138 +:10EAF0008FDAB6535368178AB84757BBC85B68E1CB +:10EB0000F9B7C72B387D613DFD53A93DEE51B9DC06 +:10EB100015F7B0EEDD328FE0FAD34E65EF527CDBB5 +:10EB2000FCCD27F1DC8936877D0FEB1DF26B9FA4AE +:10EB3000F8C4697C9DECDD7CF493B8BFA49D21E210 +:10EB4000150B9DF18A9F0979FF13C1D7EC6CEEA7D5 +:10EB5000BE52CAFD56596B233FF827A20E64203FD0 +:10EB600079B4DEC2DB8FD6EBF9FB8FE0E7BE525AF9 +:10EB7000DCCF3D544AFB63E3DC4B23F23FC7CAF1D1 +:10EB80003E9EFF27EE93EA087BE2983AA5DD51D935 +:10EB9000C0EF075A78408FE2DFB9888AFB12B83E8F +:10EBA0009199759E83C743AD7182E72C7D05E1DFA6 +:10EBB00006562BEEABDD2165EEC6BA2905E85CFCF6 +:10EBC0009D92906B9F9F2DE49A19C0BFE77957A43F +:10EBD00096F2E3B731FE771FCC34FF3B2C9BEB6EF4 +:10EBE00024F9BBCDDC4A7801F94BF2D65CEFD7F0C3 +:10EBF000DED2AD9935F4DE94550DCF778F3D4F9F22 +:10EC00007B7626949768D3F9FA3FFBF61EBCC26B5D +:10EC1000738AE74BFD5F94BB735F008000000000C8 +:10EC20001F8B080000000000000BE57C7B7C14E5D6 +:10EC3000B9FF33337B4BB2496673DD5C0893844B79 +:10EC400080804B88C8CD3204C414A92EA8152DD5B8 +:10EC500005412284244654DA7AEA842055E053D2CE +:10EC60006A6B6AB167E10852053FCB454C6DE0B76E +:10EC70000444506C03B5201E6D636D2B2290351635 +:10EC8000A11E4FFD3DCFF3CEB09724424F7FE7AF9B +:10EC90001FE86778E79D792FCFFB7DEECF6CF2B050 +:10ECA00069AE79E5005FD29FC900935409E06A809C +:10ECB000753E5B75D01DBD6F5D6F5653B93F79BC16 +:10ECC000EC0F96F7EEB7DEB7FA9387D90CA8045885 +:10ECD0001938B64DC1AE75933AD4A959008F661D47 +:10ECE00098A400401E8D978DFD65B6B07314805EAC +:10ECF000BD01FC2301EC592D10C0F901FCDCBE98CC +:10ED000014F0AA38AE6D9CFC3E3D67531B2080E397 +:10ED1000AF0423094A01DE4B0F1452FF93E0731531 +:10ED200017033CF5EDB165F4FED3937EFC7815F046 +:10ED30009F2A188BEFD1BF34809F483A0CC17519B8 +:10ED4000F3DCEA2615EFB9745EA7A241C66A0FC0CC +:10ED50004F71ADD4368641705331BD84FDB8EEB4E9 +:10ED600032D1FF94E483C1B1EFEBBAA6E2F8923955 +:10ED70003E800A3AB6ED60FE191E005AA7130C9C9D +:10ED800004200942DC7643275FA7A8254C87740836 +:10ED9000560FC1419EAEE9009EEF56D8A01447E938 +:10EDA0009BED721B4A1A8E778BED4C579918FACB54 +:10EDB000121A6FBDFAD7110032B533E9AEC1E3B50F +:10EDC000BAF4C769BEF7D2FD93556C37AB15A716D9 +:10EDD000E2FA06A82A9F93451F17AE97E6CBF68165 +:10EDE0008FF627C1DCA67025DF6A58EDEB3D1FEDDD +:10EDF0008FF65B606E2F170C89E621FADAF1BDBC45 +:10EE00001A08AEC67D1442A744FB2B82085F35501A +:10EE100065BAE6B8FC928DD7FDAEFAD7145CB7217F +:10EE20004B5F8E88AEFB5A5A1FAD1F70FDF87C33C6 +:10EE300075E0628C806C9E07F0E25AFD2B82AB8BF2 +:10EE4000693F1AEF079FAB0EB9F93C93E6A446C79A +:10EE5000C3034A937200AC579DE0918BF0FDF35EC3 +:10EE60000556E354D7296E3E6FD772083AF121ADAB +:10EE70002C6B4509B611847AFA38A20FACA8C27679 +:10EE8000D11457C4F0F1FEF9FD7C7A1FDBDA4A0792 +:10EE9000845D267DF0FF9405D82E8BB6F361ED27B7 +:10EEA000746E4510731FE7C97FF7A3776114F5C728 +:10EEB000BC4F8B54E6A6137E896720AF379F2D7F0A +:10EEC000F7A3CC0331E37F4F4DCD223AC23570CD4D +:10EED000974AF4FDC4F7ACEB85474E651E40701AA7 +:10EEE000C97A13E102DCB899F1C84F9EB1DEBEDEEB +:10EEF000B3E8685435FC7B17E17E850D9AF1FA542E +:10EF0000CAF79FEBC257971B4ED589D70B4945418E +:10EF1000207C42C335C4B778BD8AAECD5346BF9D71 +:10EF20008574CA7EE5FAEA6A9C47B18524DADABEBE +:10EF30005B579D24BA3F0DB28FDE071D343527CABB +:10EF40004717EFCD807BB0FF170D693E82A8C557EC +:10EF500029169FA97A139DABC5D750E1677E72C071 +:10EF60007DCC672E08C6F1591A44F89A54EB030970 +:10EF700099A5637995A7CB4DE3ADED937F2C5CF418 +:10EF80002C13B8B0C188746A7B97D920888BCC0BBE +:10EF9000F8D3C334AFA11FF38E8DE2CBA3E3B3311B +:10EFA000E79359ED025B0C3EB2FD6A5CDBC293D77E +:10EFB000C463EE1C6FDCFBB0D2F627E23F0DFF12FC +:10EFC000FF0D00D1B6F0620763DF33B8AE82714E39 +:10EFD000358CEFE72D30A4308E571870372848F75E +:10EFE00082067C3E663E6FC2FB89787AD5C213B238 +:10EFF00039E109E9E02379D0F396E273E26D5B979A +:10F0000093E9928F74213AF4D08BD81E300F824648 +:10F01000716F7A5878C3FF7CB4AE221C274C7CE811 +:10F020008DA75392164FA794B2783AA5FAE2E95207 +:10F03000DCD5C4FB3E88FB06E4D3F4715A3C5D4D3D +:10F04000BA95E1DFBEE85658136AA2FDF4A60FF2A6 +:10F05000EBA8CBD3E934D16944944E8A3B783BC9C1 +:10F06000A502C4B342FAC426F06153BB4ED2FD429E +:10F07000BA9FC5AFFB5D39CCDA02B709B8BF44AF60 +:10F08000AC96A67BF0F901887F3A47BD7C80B188B9 +:10F0900070826DC209540412F44A90AF2910E6FB45 +:10F0A000A9D0C5ED7440BC97127E834D6212A15762 +:10F0B0005348FE32EE3F8058F98BFD06F135F2558C +:10F0C000C3D338AFDD35331CA0791568A033437D39 +:10F0D0009CE2B99AD6070706E03E93CA20487ACA4E +:10F0E000A922FF95C48E23AE922DCCF25A592F9EA1 +:10F0F000B35535AC201C48A45F681FEB51BF58F4D2 +:10F10000A7F74B745E3FC2E56D7ACF8E745BCD740A +:10F1100053C3019CCF61EEFF4AF7ED24FD98D29BCB +:10F12000BF01C24D24CF0A689F2C5FF4E384DB212A +:10F13000E639142E0F08BE2C50C089F82A6C08310D +:10F14000DE8A106F0A3DDF2A70E3C2BFB4EEA2E58B +:10F1500021E6BB5293EF4AD6C6E3AAD8886F83F262 +:10F16000EE2CDADFF9876520BA1424E04DD33AF7A4 +:10F170000DC57E4D177AA7D800DF8218FC0D08A4B4 +:10F18000F9168C01184C673ABE373EBFE689D70B9B +:10F19000F7CFBA85F1F8EF0F6FF4F425E79F7FC43E +:10F1A000EB5B80B87BE611175F53B7681DC9B49F4E +:10F1B000AD821EA573FC4F3B2B89C4EE06498DE240 +:10F1C00034F808F0F33F7F44E5AB0D02377A90BE88 +:10F1D0001BBFF37C076D37A7B285AF1DB27E13E16D +:10F1E000069ECC62F08F585EC8EB1FBEBC88AF890C +:10F1F000FA66C07F9F98753D3E3AB045F6ADC0BBFC +:10F20000032F3AF55039E90BB1DFD2B55DD27C6CF2 +:10F21000CFF308BB53F3E8DFA279A12683C7EF8FB2 +:10F220005E89F3FC42823964373CB3EC18CFB752A5 +:10F23000CD1A4D6AB4D8A627CF423B629947E6E77C +:10F240001CCB15EDCF99D1F757B5CC4E47E5020E43 +:10F25000972EAB781DD432454EAA6401E2DBC4B3CD +:10F2600006E09654C29DCC7A7F115EE95C533D81E5 +:10F27000FB990E6A7254EF97D0F80E1E7FC003D32D +:10F2800092C9BE7DD6D525113E0648D0608C46FC7D +:10F29000D5C6EF47AB5565925FD67AACFD699EC087 +:10F2A000F7890E452E37B7894E6C4F84D3990F07D7 +:10F2B000B60AFBACE06160B93EE82D85AD9A812DC0 +:10F2C000212909CF79BA3233B9AB9CF9E1C6796308 +:10F2D0004D56C4FBCF067CCC0F43F2143008FF26FA +:10F2E000BE51FC9976A12E935C297C3806C7F8FFA5 +:10F2F00020539E0E8118FC231D0691FD9346FDF1BF +:10F30000B84F3CB7C25AC4550CDF58FBB4F69788C7 +:10F31000FB672CDCE742DE97B8F8F33029F73A2D8B +:10F320008A8B22146CE3327ADB43515C04194FD68A +:10F33000F8A3C3F1F35BE3F4675F45E59EA1B3FC7B +:10F34000F282CAB69CCFB85D223926A33C239C2406 +:10F35000F80D52E0E0DF25A493A3DA9034A4BF7740 +:10F3600066C090C8DEA8069F86FDFA93C5ECA72468 +:10F370000FEABC7635B6BD01DF3E1B8EE7CCEABC9A +:10F38000167D1768F7B879DE8B497A3B9D7F26C9D1 +:10F390003FB6CB2DBBA881AF2E68E16B32FA218638 +:10F3A00012B58F6EF1045EA5F72C3BA934ACC90EE3 +:10F3B00089FA1BF85C8792FF81EB4B94D72989F27D +:10F3C000D59DC1FC7939FA386D81F07CAD371D705F +:10F3D000D99A3F35FAFC0F06409B7415F617227D2B +:10F3E000D2884FF10027D030916A7D10C09A5BB768 +:10F3F0007BB3597E43584539BDE6EB92E8FFB1EB4C +:10F40000710349B2669668DB3314D1BE5D22A31B3B +:10F410003C667F310C67FFE2510DFD1F9CFF427679 +:10F42000A30B90FE3F289CFD957674F32338E1D022 +:10F43000E8738A4DAD623D572807D123EAF5BCCD6C +:10F440002DC7F9056B464ED749BEE3114488032DFD +:10F45000F9625B667BDF89FB5C85E3D23A1CAE0612 +:10F4600050F1EA6CB92FCCF849902F2E53BEDC43F3 +:10F47000F24562F9F2259DA3122B5F202A5F4EA26E +:10F480008F47F41F5129FC3E27FA7D80F2C591A1D8 +:10F490008973D14232E1CF92CF0E3C4EE20797CD35 +:10F4A0000F3EDCA7BDBA0134BC3A67FA755A8F9398 +:10F4B000F0898F64CED4988EF641C078D49FDC005A +:10F4C000DF46DCA467B8F97DC4657A065E33325442 +:10F4D00053FFFA243FFB690D40D75B3CFEAC0CBCEC +:10F4E0005FEAD53A080BE4CA11FE87BA85BCC2E7C9 +:10F4F0005690BCB2F56737D01FCBEF2EEE1BEF7DD9 +:10F50000F903BDF0AB665D117FFFD0A17BAEC347B1 +:10F5100057FDC6EEDBA85DB97F64E94B4BCF5A7A45 +:10F52000D3D2BF73328A4DFA587E54E7D7492F5D44 +:10F53000F89A9CB11AA2EB58B700FDDD72DA6A7E28 +:10F5400015C985D5E5F337933F7C61D8FC6407DEA8 +:10F55000BF2D43E17136B75E198EADE7141BBA5B60 +:10F560007D3C9F885FDB32D9A0784C2FDC96CF673B +:10F570001C9C5F2FCE6168CB7D1D7DE9456B5CB91E +:10F58000377E6FCBF80AFDB8D5A3CFA1FE1F560476 +:10F590006AFC7DACB33E5366BC3DB3ECC924C2F1FA +:10F5A000CF1688B88045A73501934E231B994E0F7F +:10F5B0009B747A6EFD95D1C97AEE5FA653603ECBFF +:10F5C000F3F393049DD25B3E092BFF1C9D1EFE2A84 +:10F5D0003AADF66F7CAC44C44D7C83119F4FFAE585 +:10F5E000F0646CFFAC46DE4AF6E66A7F55D2606C8A +:10F5F0006F9ED4D12E61FFD39922BEB7598D1CA224 +:10F60000E78C41B2B689F84E6DA9A6756E2EAB8017 +:10F61000D531F1A8CD657235C5F95697CD4FBE3BB2 +:10F62000860E9B5B7BE2E2089BC9BEEA235E38251F +:10F6300053D86D4F2F90590E25052028E3AD69282A +:10F64000D3A99D57887E37F9D9BA68A3AC0C6AD87C +:10F650003E70EDAA29A4F7562F20154FF6CA118344 +:10F66000F6D98A72D4C9968CB05BD24C7DD21A0876 +:10F6700073BF93E2372837D2BA66859FC98AFA8D5D +:10F68000EE718976F95C203BFE3CD9F1E44FAF8FF7 +:10F69000EF7726D831AAEE0F935F6023BF80FCA5D9 +:10F6A000CBF88D9E693E8E6FEEC830FDC75C184862 +:10F6B00076CAA38FB4C10783E152FC0645811EEAD6 +:10F6C000035F96BD72D0C4F9D3FE15928ECFAD9B69 +:10F6D000D72291BEC8FB42613B19A0C57BC7C8E8D1 +:10F6E0007B9D19C98CF37576711EBEB03A95423F69 +:10F6F00036B73A9AE4B5F5DC6F32CC38709278AE12 +:10F70000B2D33F35F5AB9E4B15F6F3B8AE96A9696B +:10F710007D3CB7DD5C27CECBF6D0BAC18E6013D26C +:10F72000659D24E4A7F1A6DDC4BB38E7CD0BD50D5C +:10F7300024EF771C2A59534E3808681534DE0E2DF5 +:10F740002097B8FB979F2F9B781A521DD059795C50 +:10F750001A2FBC55E88F88772ED2A32353E8A31D18 +:10F76000C9283F984E81FC5931749A9829C7D169AC +:10F77000F7DBF35364F203CBB40C5A47465910E459 +:10F78000F2E87C3BCA703E1AC7A6AD1949FB5B186C +:10F790004E5D1DB37F6BBEDDC97DCBAB6BADF94C50 +:10F7A0007ABF726A63DC7CC9D5F1F3252F30F7E7A5 +:10F7B0006A691A55D9FF7CAFF433DF64EB3CCC7334 +:10F7C000DB7BF14F2932D999E51A494248A1F9DC8E +:10F7D000BDE7CBBBF8632935868FF799F3ECB5E825 +:10F7E000680BE4CF8E9157A9F43EC955FF8E43773D +:10F7F00063F7E3835725915FB3590AB986D0B95FA0 +:10F800002BC3265CF7BAF5554076C4733A30F77AC5 +:10F81000DCC61452C6F765669872B98ADF936C2D00 +:10F820004D368AABB472AC1EFF04393E5064C50736 +:10F8300012ECC8BC99AA311F9FCF34E387DED6866D +:10F84000D78751BC62B9EC633B332C816D6C340EAD +:10F85000E30283E33743CDF1F2020F729C62BD02F3 +:10F860000D0ACA893EEC0D1F5871706A57E81C6F6B +:10F87000B0A3DC26A3CE8A4FF48E4B84A7D075208C +:10F88000897485BA748E8B0F36E333C5BA5665C357 +:10F89000F50C690DB03D99B10C383EA0A8411E474A +:10F8A00082B56C37A5943EE3B914B79C0870846C9C +:10F8B00017A4D79F2DFB0ACF83EC879E0C11EFB7BF +:10F8C000DA9019DFD6D74EE17C084A8708D9551758 +:10F8D0009302D76762BFECD275BA9FA4BB2242AE37 +:10F8E0003580544CF246E678DFFF6FF2BA26335E7D +:10F8F0005E5B72DA92DBFDC969B647D1FF38F8C4A6 +:10F90000DCAF93BFD1E9D11B88BE734DBB1AFDAEEE +:10F910000732B309AFA053FE44598B0EA844F144FB +:10F920004DA6F11371EF6D45DC13FD11A7D0871FB4 +:10F93000E902C43DD1DF8A1326E0BCD52EE26F88F0 +:10F94000CE066502EB0989E2EC45D6F397C139C2D0 +:10F950004C53C8AFA4789F126B6787B89D685F1738 +:10F96000DAACFC8F8FF13E08FC8CF77C972A13CE23 +:10F970004BA6694D1477186213F6FE00B4F70DDE3E +:10F980008C0A64EF270784FDFFA4FF4F2C07FAC3FE +:10F990003DE295719364FA5388E30D9922FF036465 +:10F9A000E7D811C7B43FBD650ACB9BE442F4F7200A +:10F9B000D60E92439246F64FF031CAFF90DD447A5C +:10F9C00069DD170A3FFF78ABFC1F2B701D8FDB74BE +:10F9D0007E7EF502D98734243B283C999EAF9183E3 +:10F9E000838BAFC81E62FF73CA13D5EC7FAEF308DA +:10F9F000BD68A05EA4FC5627F961888B4991CEA909 +:10FA0000E931FA749D3DE2F595D3F3913924D78C11 +:10FA10006784FC7CCE9F283F432C6FD3333D228FDD +:10FA20003668FAE16124EF6C06CB0D6BFE9C27DA99 +:10FA30001E37486EBB235E9203EB663526939CB758 +:10FA4000E46DE273B727EBAF113D8FF463CFBD993F +:10FA500059F506E1FA5719D077FC779A15FF559BAF +:10FA6000E2E2BFD312F0A601C7BD20C3F2FBFEF550 +:10FA700038B090C77DC781BBF79C1860E0FEDF5BA4 +:10FA8000F8692ABE047FB4455289CEA71EFE5D2ABE +:10FA9000D955EF3DACB09D7BA71967BDEB91FF1E1B +:10FAA0004B71C71E53BFDD98A59F669C2DCF662660 +:10FAB000BB37A850D2E192FC58B225859388567B7B +:10FAC000692833AE6DAD63A9131A481F2FD9BACF79 +:10FAD0005180FBBC778B87E390A728C185FB3DB5A0 +:10FAE0006BC006CAAF0CCF12FAFBC62CFFE7342F4F +:10FAF000AD87F0F5C7762784590F77DA85FDA3DF48 +:10FB0000288D252F42FC495CD7C1BD050ED2FB0BC9 +:10FB10002594C31EBEBD6A37CEFB1733AF99B8EE2E +:10FB200085EFA90EB24B164E8108C523976C9556EA +:10FB30003D84EFCF37E3DD89FB9A67D8E3E4F0DD5E +:10FB4000A1FB1C4C7CA57C7A2EC9EBC72496677759 +:10FB50003F16FF1CC2E2E0AF71DC05382E9DEFC2FC +:10FB600096F8FE9E43F7AFDA8DFD3BDA1C1C875FEB +:10FB70009420DF13E5F7C02C331E3816AE11F1C008 +:10FB8000F275E55AFF7E9E25B74FA1BF87A081D3AE +:10FB90008FB8F87AE61155B433353EAF256DFB0EBC +:10FBA000B24CB4758E25FED971E883943BB0ABD1CD +:10FBB0002BFCBCAF6DF8B47937768F017F7A98F360 +:10FBC00087613BF1DF6470696E5CDF4F4C3F6ECC48 +:10FBD000456CC7EEAF65DFABBF66BFCDDDB009E9F1 +:10FBE000DA88805F5E115D5FA357F87773C1F6B75F +:10FBF000AFDAF7D7B2E2E3FFFFEABEFB7B6F29DAA9 +:10FC0000477DC9038B3F4E9BF66DF39EA7A6E7E3A6 +:10FC1000BECEFD48F239711D8BB7BC7F27F1F5C20E +:10FC200036D4C32259781C72A278C56D33DE169182 +:10FC30005D82F80CD47C8F717110E9427640A07D12 +:10FC400000F77BA7227E912F17D57CFC8E30220CEB +:10FC5000AFECA56BD82B8FEB038709784BC4D73952 +:10FC60007B5711F17F22AECEF523F7666789FA8DB7 +:10FC7000059A3E9DE2740BC1BF4A15FC77E27F6393 +:10FC80003F1DBBEE0795F07FC8C6F656C561E13F44 +:10FC900057BCE908521C61A7BDF31CEB93C3C27F9C +:10FCA000A77EF2F32A5E75B35D015F182C4F46FF05 +:10FCB00097CAF51367338C1BA9BD03E5C34696B7F6 +:10FCC0000AC72546FFB64CF42F1F534A2131E3A241 +:10FCD000DB47FA69F2B43F7FEB088FBB6C20E9DBAE +:10FCE000C97F4F9628BE7D393AEBC131CA844ACAD2 +:10FCF0007643241DF75311FC60EA44B6DB5D8DD4D6 +:10FD00004E3C873141C516FB3C991DD41EA3974537 +:10FD1000483E259E8F0E3F3AF83DDAE7B3C524EE04 +:10FD2000E16B5FC4DB81154712EC464BEEBEBC6D48 +:10FD300037C9FFC5FFF9E334C0EB47B6961C3AFF5D +:10FD40006DCF3E9AA6931EB01969749E1F05851E3D +:10FD5000483CFFFFCC92E2EA4CEA78A9F8FF6391B5 +:10FD600055DFC5F57C86F295D65B77E0736E1F4450 +:10FD70003B04BC346ED7F4EFE17EEE9DE76E68C2C3 +:10FD8000FEFAB6F8FD2F7EEE27399AA8632930CF08 +:10FD9000BF80DEAB7BD6CE79F4BAB7148EBBD64328 +:10FDA00084F196F87E7DE80307E180E85738B17763 +:10FDB0003FC2D04172ABDECCCFD41F38CD78AB4F31 +:10FDC000B0876BFAC92FBE9E65DAC3A67C41FA7074 +:10FDD0003EC9C07551180382421F36FFD269B87000 +:10FDE0001D1FBD93BB81EA28CE3CFB469A541E954D +:10FDF00037002B589F9D0995A607FAA0AF753D6760 +:10FE0000CA25AB6DE569B436493816EDE2BA0DF591 +:10FE1000A50BD7517BD2C97664EDD11EE62BC47EEB +:10FE200064B087FCF98E9C91D8BF64BB3D6BA6D8AB +:10FE30004E1AE949EBDC16EFFCCBF4ADF43EEAC117 +:10FE4000243AB75D17584F5A7CB964BB9442718904 +:10FE5000DAA0DDE7D27AD3756A689FA3CBDDC7B994 +:10FE600085DE9F4E7182E65F5EE073F968AF04B98C +:10FE7000C5BDDFAFD9F4B183F8EF0C1E90EAA173D2 +:10FE800054E639D2FB3ABFF08DAF5472BF4AFEFF41 +:10FE9000E5CEF179A2C1D58CF7175FC17FD7BCE35E +:10FEA000F4D1FE6B5EBC9F71FFA1AD81715FFBCC95 +:10FEB000A33964F7D4D88D1C95AFE27ECD2F1E6098 +:10FEC0003C2E3AFA400E88FC601EC923DC671EED0A +:10FED0006FE1FA5B797FF74080F158F38CE2A73A43 +:10FEE000C2F336A8DEDEC7B9DE942DF8C609F78D59 +:10FEF00022BE388F23515EEC4307B03C338E29413C +:10FF0000925F4ED8F807F20BCE77664B248F94A3FE +:10FF10007617D167D91E0FE36950B6B087A61E3D8C +:10FF20003FFDBB74BFD8D6809E22EDDF30E9257D32 +:10FF3000C9720D34F283EAE95F25346E8FE3DBF892 +:10FF4000FCDFF03ED539C43CCFF4FA70A33399F20C +:10FF50004E1FE6408D88A7C131F283EAC458888BD2 +:10FF6000BFAFA2F90E82D643FBFF7EB68897D46F4F +:10FF7000F970FAD3C477F3DD0D543FF6B7B73E708E +:10FF8000E4135FA0DD3698D6D5F9176E832F5B2377 +:10FF9000B966D1A3BECD1997AFA97FF62F09FC1B77 +:10FFA000DF8F7612D3AD1ED235B28B3F7444A69349 +:10FFB0003E31705EAA4BBCE749675C1CBA7ED747EE +:10FFC000EF50BD597D421D9AC57F963FBBC8E4F7EF +:10FFD000C4F34AE4FF19D9F1FC0FEBB3AF286F5219 +:10FFE0006B0F6E26FA207FFA0CC46DEDB6F371FC30 +:10FFF000F9F1D6FDC7EFC07D7C1CB2F8335EAED6FA +:020000023000CC +:10000000ECF8CBF49F933FD10F7F7EECC69B23FB94 +:10001000E04BBCDF275FBA451EFCFF993CDDB5868F +:10002000EBFDA2F48EE7C345FDC8D365D9BDECB5A1 +:10003000749C064E3FBF6420C9C544FA5AF233513E +:100040002E7AB2B53EE52298F6D52539F7C2D9E920 +:100050003FC77D7F96A700D9D175CFFE9DF513923E +:100060003542F52E75C14FB8FD28E92B6EEFBB85E3 +:10007000F2D3BDF71D4FCFC4FE71A41BAF66FADCEF +:10008000497456E43491FF46FF9EE242CDA41F47D7 +:10009000D39A54A073842A08711D6AFB6B9C0F4F7E +:1000A000F4DB8C2A286BC0F3697644F36D9BB2387D +:1000B000FFC6F9366385536DCEE2FC1BF72FB7B947 +:1000C000548A3345B2ADBC9A2F4CE7F8D07EA8587D +:1000D0002DF0C5FEF38583D8D6A8AE495362F590BE +:1000E0006FAADCD0571C7E5BB6B06B87E588FD9DA0 +:1000F00030E9BE521171118010E7359BE9BC695D92 +:100100009E34F6EFED661E1247F6527DC909537E06 +:10011000F952E44F9104B03FFBBD19363C67DF183C +:10012000F9FE526C1FFBC9A91936C48B6FA2BCB370 +:1001300004DB6FFDE423D17F953CC68EFB7ACE387D +:100140003D631AF6DBE4ED3524176D32A8CD48BFC8 +:100150009569A1066A53FDC18ABCE8FA40DB19A083 +:10016000F5ACCA037535FB7DBA46F1A5668FCB4762 +:10017000FEB64D9E3227769C350EFD14C799B240CF +:100180006BC271529CA100B51D382EB5412B9D4A02 +:10019000ED550380F34315366D2AE773709BE4AF8A +:1001A0005E9A37619E951EDD4BE77882CE24FBCAAE +:1001B000AFCD665C5E4911E7A2A4CB0DDBF1FA0777 +:1001C000938E7FCCB6F2CB229ED4BD2777A319FFA6 +:1001D0002F22FE54948DDB081791261B6CCCA2FEB7 +:1001E000E7B6116E4E385C1C0FBC2D7DAD7D382EF0 +:1001F000B9C255743F81EE1D69EB03740DE7044EDF +:10020000678B71C334EE1D772A625C77432A9D2386 +:10021000E888E74AAE4366FB1E028867926B1D883A +:10022000E7D1C482F175DA89EB50D2B7F23A6E7336 +:100230008A75CC09963477E13A463B8303C87FC47C +:10024000F93FCFC6FDDDE10C0E267C19857088E8EC +:100250007EE2AEAB3688FD15329F30DF71DDE69968 +:100260001769BC7A1C9FF2CFE7927FA1D0F312CA24 +:100270002F294FC8D57939EC0A9875EB7A33F99D57 +:10028000134DFF1F3A85BD6CD59D82F2450EE72BBD +:100290008FC85C9B5C7120BECE6722ACDF5FCEFE58 +:1002A0008B8BE5C7F804B937B1ED639687132FE35D +:1002B000AF67E7987A251FF2691FA184BC98CFCC5D +:1002C0008B21456CB1791B4B1EDE9E5C5598837467 +:1002D0009A6913CF69A0EB5CC7EBD3643A979E236E +:1002E000F3A182DAA03502B67F68EAED44FEDE951E +:1002F00020572D1C8F7C4BBD9BECAB916FC15DB427 +:100300009F4B75C2A7449DF0E82E97CCF1AA437687 +:10031000AE8F7D2A65D45393B07FE5613B90DF6B50 +:10032000D5CBF6BC65D6CB2AB5CDD47FDE8CB393C6 +:100330009F43FDBBC3004F93FDE395418B91A749BC +:100340005A326831F44A29CB886B5BF5B763C42D08 +:1003500048F5E5C7BD3F461D1B245C1C34D04A2A26 +:10036000A4BAD992F8F78FC4D7CD8E7D2BFE9CED21 +:10037000594185FC8F6BCCB88F2F1CDC6FE07AC79E +:1003800099F1F471EFC63F3FE132F1F59B734CBD3B +:10039000679E7762BDF1684893598E5D8E9EA70473 +:1003A0003DA37E4580E97AB519F7F5E8F174CCAC48 +:1003B0008EA763B63F9E8EB973E2E9961788A7535E +:1003C00041CDF0B8FE010D1571ED81CB27C43D5F25 +:1003D0008C8A2BB65DFAD88CB8E707B7CC8E6B0F3A +:1003E0006DBD23EEF961C1F971FD23B62C8E3FB7C7 +:1003F00004DC24E26064A831FE79659232AF527C5D +:100400000741E77655DB77E3C6B77060E0DFBE7083 +:10041000A024BFA8D03975A1FF2A4D403C6419C45F +:1004200009BDCFDF7D8AEBFC2E87832713F8FE4AB8 +:10043000BF6378DED40B17928A2492BF1ADA139422 +:10044000ACE8B6174A247F8DA91052D0907A28B90B +:10045000681FF9DB5DF7A5F9A4FC987A1D94FBCD24 +:100460003EC2551AE368F9BBA91C57B9206B9C8F93 +:100470007B52F1F3F72D3864B18C7A7BA52CFC818B +:100480001FCAF25DB1F9D51773843FF3628EB00BCA +:100490007EEE086D27396073093DB952E6BDD11F64 +:1004A0009DE2A4691483E6FCCB1D6BA64D227DD88A +:1004B00055A67928848AED6BD12A4F7991F541852B +:1004C0006103AE0B8120B747A37E203CA33EF835E5 +:1004D000C9B93B64D40F38F56DAA719DA4E13A5DAA +:1004E00060A455B09EBC8BF2B21EC8921ACB290EE6 +:1004F0007E49FF685F8EE94DCFFD8B27CA647FF58B +:100500002C5078FF3D353F3B7B3E2B86BF287745FF +:10051000076CD3B8EEF5A443BB692CD1EF7585F316 +:1005200010BFA1E7FAB0FF2F174FACD9F0442AD57E +:10053000939D2C13753AD6FD2E939E5D398AF0ABB0 +:10054000167CECB883E960D9A79FB29FAC96404374 +:100550003ADA3F30AD87DBAB75614F5EA4A412E59C +:10056000AFED2D869BE468DBACB0F866C9E0716F37 +:100570003B21E296B7FD17C4D9779FE4D8F9BD4F68 +:10058000CC792B0E05AEA673BC89188CEDA5C0D511 +:10059000A4FFFD2A6834CF9CC0BC078E607BD65A6E +:1005A00089ED68EAA7E767A36CA5FEDF81EFF72F67 +:1005B000E1FCFFC8D178DE5BC06F27FBEFF89D4BF5 +:1005C00053C90F3DE111CF4724D036C68C779339FC +:1005D000DE893B97BC44F629CD47F3D37A68FE59B0 +:1005E0002A9450FB3804CEFEBEB8F7BC37836E1792 +:1005F00076A6DF4E760FFE339C89FD8D279D9C5796 +:1006000069BC3705282ED3B8C7C971C1EEC517B666 +:10061000FD1497785741D7004769941EB7B72AA0B1 +:10062000215EDECFD49DB9C46BE332AFA8BE73EABE +:10063000F3E3194F8D9B049E1A7F29BE1B69DC04CE +:100640001CA76C4CBD84A75CC253E3A6D25CAEBBB6 +:10065000A421FA18FF51C491E6A43A2C24C450AE48 +:10066000332FCCBD9ABE2714F5EC2BD5927CA2CBB0 +:1006700026C9C5796028BCB23A5DE24503E5E46D60 +:100680002C4201DE34713CA73D738C69F795D1BED5 +:10069000DFD9BB6D008A56787DD87383D91FABBC78 +:1006A000323AA05C7A81E48C86761814B17E63FBC2 +:1006B000A03B2C335D502EBD407CDD6577A92447DF +:1006C0002F2F97743E4CCB8F50649FD7467652BBEA +:1006D0009242F44B2387C39233C827698A6CCA19A4 +:1006E000D05DE89F8D30E5D094DC6D37AC14719C03 +:1006F000443B70EAD63EEC403FFE1576E07AA55CBE +:10070000D82B61FA9E65686B7C5C75A2F9BD5B2F86 +:10071000FB8FE2525760FFDD9AFB3FD3033BC84E8D +:10072000C46BA84CC8AB503899ED810A537E41D8B0 +:100730006D7E3F186F37A2BD389FCED7B21713C753 +:10074000AFC915F6615DAED033E3C9D7C5768A4B24 +:10075000E7BC6D0ED2B8693CB7791EF516D34F428F +:10076000399C8E931FCB17EF39A473652EE4D7C63F +:10077000A776AE790CE5BD6B90A90F8C9D6BF6E367 +:10078000BF4BB54FF77F49F2B6D3C671F79E03C38F +:10079000B9FEB7BF7D57225F92720F1F9CC0F65102 +:1007A000F721C167DB32B4DF4E24BFE2B0025497B9 +:1007B0009A64EB7278FAD8D76E92CBC847EDB9C27B +:1007C0006F72B5493AC5B75D9AF08793547534D7BF +:1007D000AD0780E39D67B797B27FBCC8A4C7862CDE +:1007E000FF6AE2BFA5CA8622B5344A7F6BFC0AB213 +:1007F000D3CBFBA4774B6E8C7D1E0A1FE3BACC9E35 +:100800006A4D5646F7A6BBD5AE6F1DC3C50775AD7D +:10081000997C1D46F10DBC551F167438D7D69CD156 +:1008200057FCB83EB7B383E801BF4D02CAA7D5FF56 +:100830009FF798FF5E9885D0C2F378FEE2081EEF1E +:1008400097B91ED34FEDE4F50CF76B12F90BF54E8B +:10085000A127CE5D54F8396BDC916D531415715E90 +:100860001E6EE9607FB7DDA911DE929E0541BFF6DD +:100870002496ABF57BAF177EA8077C543FB32D3988 +:10088000F2071A3FB2C7A951BE25496D810CCA377C +:100890003884BE1E8674DBE18EDEB7E64B6A7F8A43 +:1008A0008BA211373AC555936C2D706DCCB92ECAF9 +:1008B00015F59BAFE70A7C6E4B0ECB94F789A0EF42 +:1008C000B491D7155D27F0BCD63A87719C7C9B23E9 +:1008D000F257CA9FE0BA54C2CD3010EB84F6A11A89 +:1008E000F14D92AAF33E9254CD175BDF6EADAB7E15 +:1008F00014CAF574B48B56C0257943F2A73E39DA91 +:1009000076216F6E2BB1707F9AED9E4B6D1298E33E +:10091000A2EF77E59E5DB3B290F625F4B8CD1662EE +:100920007E4B9B03AA319EF6AF8BBA51E2374F9FA5 +:10093000FC188EE5475FBA913103FB7DAFC9BE66F7 +:100940001C32FD0BF13D4C5DA79DF561ED3F6E4EF8 +:100950002FA7FC84DCF1E056BC7E3C2F3484ECAA4B +:1009600017D302A7493EBCFCEE7CAEEF3BBDCDEEFB +:100970009B4972B2CBF871018EBFF879BB4671A466 +:100980001FBCDD13FE92CEF95712FB81DD76D18FAD +:100990006D3424719EF60F1D944FBABEED7D077D18 +:1009A0005FF3A837F0298D3BAEAD692AD16F3CB417 +:1009B0003453DC11E57380F9C20BA69F38646313CE +:1009C000F16124307036F251B157D84516FDDB4D38 +:1009D0003EDE4BF6D5D0FEE585011D1C9F7BC9B4DC +:1009E0000B57C08102A2F74BFB6E2FD570DCEEA037 +:1009F000F8EE7FC471D75D7A0CEE0ABCC29E2D3032 +:100A0000E77DCE1B48F652FE7BDF9F1C694887FAC4 +:100A10003F878A484FFE13FCAF7A63E46D08EDC947 +:100A2000589CF7E2FB04BEABB7451C1C9F3D052C50 +:100A3000AF5E38DEC6FEFD0BDF553D243F707F9074 +:100A40008EED9728FF53CC6D8E1735FDFEB35114F4 +:100A5000FFFD6CCF928144EF7FE4DA793FC82755E0 +:100A6000C9C48FDB81E5A5C5CFE5C4CFB894725565 +:100A7000C491CA894F887F1D9D33987F5F92395FEB +:100A80008A7CC27C837CA252BD50B98A7CC3EF0FA2 +:100A90006579B0ADF3D870FE3D013C9EC1A3A92D90 +:100AA000334EB7856704E943E84A7BB883DEAFC4B9 +:100AB000F99BB4287F574AE08FCD372FCA4D63BAD0 +:100AC00058F2F73BA63E4AA162AC18FE89D1F7A2C4 +:100AD0007DC91EA85AFB37E4B7527D8C4C767BE368 +:100AE0009B0AEB99C65727DCB455B459FF8FD51B29 +:100AF000A652C9C9B8EA96FD749DE00F4D25779AB4 +:100B0000F48D86E770355E7594B793E674EE17BF83 +:100B100071A08FA038E7AE8EAF8F20FFABFBA41380 +:100B20009270CA5D9F47FE4039A707F7221DA14F6B +:100B3000FB88F1D71F5EBBA5AE348A7FCEF58E9AB7 +:100B4000694B42FE192FF675BBB77C2DBA44F0AE47 +:100B5000579FEB453A7C9E17984B78EA3EFA790E00 +:100B60009537BEF4D69FD2C85ED8E5D047A87C455D +:100B70007FAD0FFD37C32BCEBFD2ACBB217EA37898 +:100B8000F4D9D6CC0DCC6F7AE78DA437EE91D47D15 +:100B9000945FF937930F2CBF7AA13059A066D7CD57 +:100BA000D3C95E52F315A07CCE3D4FDAE3FCDF21C2 +:100BB00086C17E491D422688E75F6BD683D424D840 +:100BC000414321ECA0B84A7DC0DD40DF7127C6D18A +:100BD0006BCDBC5EED65FCE87FF39AF653299492E9 +:100BE000FD84E7CFF194C8EF15DF46BC6DB7C12196 +:100BF0002732E70BB2A00BDA292BD333A276D4909D +:100C00007C7D29EB75135FDBAA841C8A6C93828C34 +:100C1000F72DC0FC36E194B6813FF236F4E3DE1CDA +:100C2000DA0F307E26D80CCE9F4EF096027DB73A72 +:100C30000EC534E1FD9E762918A4E783625F36FC79 +:100C40004BF6E479D8BA8ACA1CC64384F7BF88F643 +:100C5000CFF54709FB6F3D7A90C2964B43097999CE +:100C60007EF29D3B00FACCB36CF09AF1A622288A62 +:100C7000B52FE150DFFE42349E64303D3EB68BBA64 +:100C8000E963E6F8F8278DEA573F30F7BFC7C20996 +:100C9000F8980EA7CCEFFAEB4C3AD46E31E9B05687 +:100CA000E0C4FA7EB81E82BCFFA5E6FE13F789F306 +:100CB0001F24FF7711DADD84C79AF5F1385B6CD217 +:100CC0006171021DEA02929837A888794D7BFF6E08 +:100CD000B0FE88752E36D799B8AE2576911F5B8207 +:100CE000F8A17CDDFFD63A13CFE9B8754EC3617821 +:100CF000DC3955675ED139958296CEF5CFA61D6D4C +:100D0000E121F1BDE9A61D7D7DABB0277775763C6D +:100D1000467C5FB1475149CF777756A550BD40F724 +:100D2000111B4767BBDBC7AC3150DEED3C34E866D6 +:100D3000FABEA8E2A8CCFC30E6CD8A6012F91B6F9F +:100D400056A49472DD869649F3E37BAC57BB8F0CB7 +:100D5000FA5D39DBE9D32A49BC341DA948213B603F +:100D6000A7F9BB25D29B7FFB0DCD3BE6B06D2CC513 +:100D70003D57E179D0B8D7FF6CDE66B227CE7A4511 +:100D80003CE26067E32D749E4B8FC82ADD3F7744B9 +:100D9000D463D73EA304656C5FBF5DD487D4E37989 +:100DA00049BC5E3BCF5FBF6770E6DDEEE8F9CF3749 +:100DB000F15AE1D19E9849765E5E0AD7BB5E3FC08C +:100DC000CEFAEE4C7ECA7FCCC4F186E8C597F0110E +:100DD000440A9C79E57EE1BF6E93804C8283DEFB02 +:100DE0001DE41F9CA97285699C33BB8F3A28FF3A8A +:100DF00075D751510761D60159784AA4FFD9CE64FD +:100E0000B36EB1C541E7B4F4A8D5EE72909EF69BDF +:100E1000F652DDB3EF737B31D9FDB49E6725AE2F5B +:100E2000DFBFE765CECBD66D15F5148BDB7EE420F6 +:100E3000BC2E467C6A2447A085E5F3923687DA9774 +:100E40005C59D41ADFBEF732B81C9667CAD7613036 +:100E50008C70F9D91421CF3F3B9ACC7ED26787455D +:100E600014FF2BF0C97AEF881917EB09CBBAE3AA64 +:100E7000E873E78EF438A8FE627AFB274CBF99ED41 +:100E8000FBA6115DBE01815ADAE737DA5354B24B43 +:100E90006776097932A3DDC971F16F406825E9BB36 +:100EA000EEBDAFADA2B8B751E58A0C56A3F2699179 +:100EB00079DE000D4C8F33967F8F6DA69F0F8AC908 +:100EC000DFE9B677317F77CF7337F0EFDDAC8F3F57 +:100ED000BF1BCAE2E93503847C99B155C8B51BA094 +:100EE0008BC7BF81E88DF377E78DB889ED1FF44795 +:100EF000A93EBA766BFCFB75097A70629E3DAE1E08 +:100F0000A13FFB20F15CE6E699F2C23C97991121E2 +:100F1000B766BCA5F882B8EF43E115E5146FB3E8F6 +:100F200094782E87B4AFAE3FFA8D69675BED9B4C2A +:100F3000FB36A4067F3A06F77B18D4A346162F8704 +:100F4000BFB35BB63D8FF37287F2843E383F68FFD4 +:100F5000280DFF59FBDA2B458E12F62B96E5911DD5 +:100F60002DB7FF94D2DFAF152A9045FEC52F93828F +:100F7000C4773FF07EF0C331955CAFD249F9BB7ABC +:100F80005BCB4CCA5BD56FB5FBC89FA86F5358EEBF +:100F9000D46F750ABE27BCE07AFCEDD2758417B415 +:100FA000D30D1A7F16A56C285ED826F1EFAECC9A29 +:100FB000F68983E87A24C15E9FD9BFBDBE2A2FC6B9 +:100FC0005F3F3CA8347D3E5D6D5A2E7DDADB9FBDD0 +:100FD0005E7751D88BD6FD3AE467A27B5DBBC4F641 +:100FE0006DD45ECC95C85EECDEF39083FCD16E4987 +:100FF000FD2485EC78936EBB3ABEE3207914990208 +:1010000091128ABF4A2B997FEAD828C5EB4B92C828 +:10101000A3FDCA4EB513D0742C99E5DFB9E3227F46 +:1010200044F609D53DDC23A002E7E607189F54F7F4 +:1010300040F85E0AB5ABF83BFBBBA181EB2E13E495 +:10104000C192F20DABA8A4BD0956B0FFB40256F28E +:1010500075C4DE132C1747BCE2506595E30F0E8E66 +:101060000B0663DE2FE92D6F965E26FE752841BEC6 +:10107000E07ED670FCE0B0A2527C6757C7DF7F41AC +:10108000F54311B4B34B68DFA6DDB2AB2389FD8A0B +:10109000EEA3EE20D1F3B489D73366DCBD699CC2E0 +:1010A000F491C78BEB88BD2F97100EBAF75C280A16 +:1010B000E079BFB0F7E5E13A9F7F90CF73C996F82A +:1010C0007AF1A5A1F87A708BCEF5269D715D431C4F +:1010D00059D175BD64EB4AF3F5C16792D4C1E727D6 +:1010E0004B07E2ECFFFA5F2971BF2B87FBB98BE45A +:1010F000E03B260EC016C9217DFA873C8DD7D7D498 +:101100002ECE5BDE23AE38FF37455CC5CEF3F7EA63 +:10111000AF326AA9FFB3E214AE4B808BC64C6A3F74 +:1011200058A270DDC283C7160F8D8DB78124FCE5F0 +:101130007A7B84EBE0EA8F8ADFB5AB3FDA9333C882 +:101140004D726FC334AAF7BDC19427074B526A088A +:10115000D706CD9B4BF1BE03FCFEFC3C337F61FE0A +:101160002EDE0A1347BB8ECD48A17842F79E6CFE57 +:10117000BEE303AF88C37D9EE73F4FFC66F931FDB8 +:10118000D9A5317E14D3A71EF749FCB4F36D67705F +:10119000A6447EEE85E3DFA2FD1EB6F1F76E4D7B21 +:1011A0009C067D4F52FF4E12C7272010B88AFCB60E +:1011B00007F72E1A2A3EB65FC1E7B1B66D6137D583 +:1011C000052D3D99C2E5C24BF7FC9EEBFD96BE7422 +:1011D000F51364F7A09D7303D93D3BDBED2C7F2A0B +:1011E000DEAC64BCED3C529959CADFABFB5268DC03 +:1011F000A5876D5CFFB7F470E51B33C95E79B38AD0 +:10120000ED1EE9CDCA4C925363C8BF25BBE7F02061 +:101210006E5BFB71E78BEFB1BBF725711C4282124D +:10122000811718148797DA5DAFB23D508B72301674 +:1012300037D67B5ABE8DC719946FE22524E98C8777 +:10124000EDE25ADBB63387F6B1C41EE2F36DDA6A1B +:1012500017FDDBC415E87703F03DC327F379BE41E2 +:10126000B7F01C66388285940F7CDDF4035E3F196D +:10127000184872F0F52981A1747D313F3E3E6340EC +:1012800015AF1BA4D97CEE6777D9FBFC7DC5ADF902 +:10129000428EA665425C5ED1BAFE2C5FE063864357 +:1012A000C487C88ECBCB31F36EACD7BBA6913C9A2A +:1012B000EDCD9448AFDF6D3EFF3B33DF04CAA4544D +:1012C000AEDFA0EFA33C1427F7DB493FDE6CD61F4F +:1012D000DFFC8D5BAFA3F701F5B69BE205E384DD90 +:1012E0006EC5FD13E3FCD6BA6EAE8E976FB75EC6C1 +:1012F0007E9A956FCAB7213044D8F5EE1492FBE779 +:101300000FD9CDEF008283FC237BEFFFD277CF9400 +:101310000742B97608E51A5DFF89B8D35DF9571021 +:10132000E76F1A7682E344AFEF3BF9A287E56C12D0 +:101330009460D7E42FFE98D3D7BA9A60369FEF0A0D +:10134000B8250E9FD6399F05F13B0D89E7FC9D7CA2 +:10135000CB4FEC5AD5487CA9BBF8F716EB94E06369 +:10136000834A45DE92E3C7EDB3F8FB432B9F7949EF +:101370009FB6DDC7BF83D934ECC24A92FB67CDEF7D +:101380007870DD45CE18FD7036EF13EE7FB00A227F +:1013900006F6EF1B26F2704BA7499C2F581A167AB7 +:1013A00074E92D428F0ED935CB4E72FD9B683FEB11 +:1013B0003E162FC7A9EEF546537F4EFEA29B71B68F +:1013C000D4B41F9B20C310F23C8BAF4B77BDBF92B0 +:1013D000F3950168A078DC4DE3E2F13114028F66E9 +:1013E00063FF6DD5922F4878D0E3FB6F9B3B8B71E9 +:1013F00078B3F97DCFE5F0B5333FB09ECEB5BBB342 +:10140000E79B2335CACF7D584474A933F9C43754B8 +:101410006BA3FC9AEF0D757433BEB325D8B39BDA7A +:10142000DD46964479F5E7CC7328CE0D6CCE177A5D +:101430006637E5DFEA1C2E95F6678DB7D5CCE35805 +:10144000FCE9CB8531F7B963CF55F09BF55C59BE0C +:10145000F8CEF6757BB090BF0729BFB27C61D3B0E0 +:10146000D746913C7C7DDFE1518E98733CD31818B0 +:10147000CA7A68CFFE1CCD1D8B3FD9C49F8DAF9219 +:1014800034DBD4AFF1783C43782439BE7DFF8DDF67 +:1014900022BCECBA394BD262F4EF4BBF4B1B1C336E +:1014A000EED976F1BD03FA61436E4D8D5DE7A3BCC5 +:1014B000CEB321311E7223FFDE47DDEED163453D01 +:1014C000251854775157367FB3A84B6B367F974812 +:1014D000B3F2F17A81C4F9F8B8DF8B0B39CCDFF9BC +:1014E000DCEBE43C5DB75DE5EF7ABB4FAA1BC4F7CC +:1014F000A00D4A21B6C781FA09F929674D7AD37D33 +:101500001DEF8FD7459D1DCA6DAE479C3853E4C172 +:10151000B19FEB112735804FF83BA27F42B5E8BF62 +:1015200016BA1492E7932924857C3705341BB5A796 +:1015300082D14CFC373114BE81C45538C7E6F9ABB3 +:101540004B9476F6757E51FAD8E0AF163EF16134D1 +:101550008E38DE2EC1C30AE9E7B1A0F598EBE27A36 +:101560009D71BAB683F6935520F4862F45F063E457 +:101570002C70BCCD5ADF445B27EF2355D33228FFB4 +:10158000B1FD4023B7F7A297CB755899E67B1FE1D1 +:101590007B48BF6B6C41DE674E83787E3C84FBDC0E +:1015A000A7B3A058E4EBCDFD76DB43ACD7BBEF454A +:1015B000C6C675A516081C4F6891E06D14AEBE52E4 +:1015C000B11F1C5FE17C8B39FE0408F1F9418D9657 +:1015D000F1461EBD2799E7334D257A48E11CF9CB2A +:1015E000942BA75B770EF07AD3EE8E9CFB5E65346E +:1015F0002FE56BCFE538ED5A498E2894D771158ABF +:10160000BAE13084C87E47B11FF73D6971C1EC81F2 +:1016100005B48E80F85DA9C43ACC2DC18D5C5733DA +:10162000C7AAB32904389513AD07B09788BA1B3BF6 +:10163000E5E355AE0B1D43B80DE70478DC77A4ADA8 +:101640008379305BF06A7FCCEFCEA6803E8EE87C5B +:1016500021A988D76BD5253D945CC4EBED9A022176 +:101660006962EF7C7F8A3354C374A4BAA1F17DE52B +:10167000FF457D31729546F548F0F0548DC65F65A3 +:10168000D6D526D64B5F4812754456FDC143C92FA7 +:1016900072DDA9556F40FB9D64ED57BE92FA03C3FE +:1016A0003EBC385A1F8B749869D281EB64517F0F0E +:1016B000167408735C204517DFF1AA784E36E11FD7 +:1016C000479C14C8D57BFFAE30C98D95532D3E0E77 +:1016D0006DE13A4AA403B5ADFD26EECFC2CFFF05BA +:1016E00051FAAACBD05A0000000000000000000010 +:1016F0001F8B080000000000000B6B966760F8511C +:101700008FC06F8451F9E87899282A5F5414BF7A02 +:1017100042F8110B82AD27C8C0708E0382FBA0D89F +:10172000098875A1F81314FFE244E8D9CECFC0B000 +:101730001F888FF3A39A6BC704A15D1919185A1952 +:101740001818E480B88E0B21AFC00CA137DB333002 +:10175000F8B820C4CF583030885B32307CB4A4CC89 +:101760005FA3786860897054BE75002A3F2E888117 +:101770006107921A9B00D2CC77886060708CC02D74 +:10178000BF240695DF9186CA174393D72944E5D72E +:10179000C442680025F4A86FC803000000000000E0 +:1017A0001F8B080000000000000BCD7D0D9814D5A4 +:1017B00095E8ADAE9FAEEEAEEEA91966A0079AB160 +:1017C000067A608C0316302246D462F80966DD4D35 +:1017D00087F8CCE88BA60416D145B74537CE6ED036 +:1017E000AEA1677A7E18B4111607C4A50534E05F70 +:1017F000C644B3E67BC9A611E29A8DFB96E4254662 +:10180000F7E1A6419768BE18277CABB879F87CF75A +:101810009C7B6BA6AAE919C67DEE4FFB6979EBDECE +:10182000BAF7DC73CFFF3DF74E50AD26C9AB08F9D0 +:10183000187EF479A14208A91B7D126215492B215B +:101840009F2124BDBB96E0EFAD85843493D19F34B6 +:1018500099B687FF09103245775E84F65D02494FDD +:1018600031097900DED7C37FF2819BE9F7171D5557 +:1018700049BF4E480B3916203309994B86F169123E +:101880005D84E77C62E2B395A4F0F9DE92D2D7E002 +:10189000F973DD8E934B08D9A0D91784E938EF4E40 +:1018A000B767C7E8FB1F4B563DBC278B6B08B96C6D +:1018B000741EE54F421C9C4F52BDC912281CEF0FED +:1018C00011B31FDEB699383FE709626669F922DD78 +:1018D00029426BF7BB5C8690E26C3A473D4DEC16B3 +:1018E00042AE240681F15AE2CE3131469F4336B1F1 +:1018F00035C413494509B93C68CF817A49531C71F5 +:101900002E7C37AC40FD6FAB49FB90762E5C970385 +:10191000D268FBEEE80AAB44FBCFDE6B92147D8A03 +:10192000C5CB8841FB133593D01E89241510AFE435 +:1019300020697C8C8220A9432F12588FA7689900B8 +:101940005C3A834B2B0696D071E4A07D25940580EC +:101950008B7E9F8DAE8803FC4A9C38E2C584A8B478 +:101960000FF83E5B4D0A2D8D840413F45D2B948F8C +:101970003D0D65DA8EE89EB20B6FB6DA8C6B2DA347 +:10198000E5EEE8C2D782B49DAC1363366D2715AF80 +:1019900046B825DD22367DCA92430480DB6070CBD9 +:1019A0006A9A9513ACACE8365902F3FE48AC889FAE +:1019B0000B397E3E7390C12B69A4200A809FEFBE35 +:1019C00018A665314ECC1052A169017E648DE84F96 +:1019D00040BDC6DA8B3AD91711008E02C397CEC626 +:1019E000BD88D72B717D7FA011E02A0622ADF8CEED +:1019F000047CB6403DF457CBEA25DD8F2FC08F170E +:101A00005F72EDC4F0956D14709EE4EC82F8B551F0 +:101A1000CF7B3E7FF8BD0DFC2520CEF0A7D1F2850F +:101A200002FBFF4D7445011F1EBEF83AF205A17C72 +:101A300041CBEFCAF637C28C2F36C1FB20B9B10AB1 +:101A4000D67F6CBE504891327318685EC4D1F4538F +:101A500017B1B15899F1CD22ADB05430100FCD521D +:101A60002BB05AD8141B47F1ACC0BA4099AE3FF026 +:101A70009758EB5F1709D6C5D39EAEDBBE08E0557D +:101A8000728E205DC7191D5FC6EB47F0AE16B231EE +:101A9000B66E26ACDB6779BDA4B37A5807286F8B86 +:101AA000D27511D83AC0BA6C8BD27510D8BAE99EEB +:101AB00032456A3DE0635B54AFD73CF4B66D645D7C +:101AC00026D57BD765DB4733EBA97022E6055F722D +:101AD0009651F9B26DF9AC2ABB656C7C6633A95D91 +:101AE0005293A72C30BECF8648FBB7E8D3DAA45F69 +:101AF000BF96C2188C1BF341FE64A30A9BAF6EEC29 +:101B000003BA7E0ED697E2FBF7B2F51C3CB301FD9B +:101B10007A944F2B14F25823085BA37E15857F51CE +:101B2000497F1DF88EE2DD60FCB06B69CC83F7EE77 +:101B3000E50B47F03EFBDF11EFFD6578EF2FC3BBF0 +:101B40005B76F1D11F2DC4BD78EF1FC1FB7E1F3F17 +:101B5000F45F38B91EE4667F19FEC50ED1786B12AA +:101B6000218D9223C668FF7D7126C7B3C9F90ECCBB +:101B7000E7FD95B440E1ABC93776029D128DF1B314 +:101B8000FC96E5C4909F4C02E32854AE1455421ACB +:101B9000E8F36380B7368C65A47B02E32838CEE592 +:101BA000547EC5687FD382F6DBB01EC1B76CD68F7A +:101BB0009642B98A829FEA3FD9D585C24AC44BB5BD +:101BC000410AFDF4BBE5E2572C8083EA16730AC58F +:101BD000C96410C9222B17E97BB54E331D844B0F06 +:101BE00081FE0892FFEEE3D7502D7142545E872CA0 +:101BF00043D041AE1B8A0F4E79252986A89EF93F16 +:101C0000245A7B2A425F5C4A2E657C6B08D04F8D3C +:101C100064201EC4E680B90F46B1E884697967D5AF +:101C20008C4745CFBA448400D29D1A7D50A53823F5 +:101C30009DCDF355D0477DDAAA2A52412EBB4FF1F4 +:101C4000439114299EF40F057C8A9A7D19ACDBCE52 +:101C5000A0FDDD7F867193C4DC47E72724A934A368 +:101C6000780969C6BECF35C2B340DA3490734C9E52 +:101C70002D6B6672224CE93588F57962D1F1C34942 +:101C800013F56BB5661F867A4ADB69C0E3142D5FD6 +:101C900044FA6B528C60E3B9701D6EDA1947F82F65 +:101CA0005C1807F8B387438CFE934A2154A13D95F5 +:101CB0006F168C47A47C7C9507FF7D9C7F27B79B84 +:101CC00064B587EF25D2D62C5C82F8C575A9B1889A +:101CD0003544EBB7497AA8DAD3EE2C6178DD66910A +:101CE000954315E4C669AEDF2293ADF9421D5B57FB +:101CF000B0AF1692D11FC8FF4B09D3079793E106E7 +:101D000089AEEF1DC1624E1650FE5F0E707CF0FA78 +:101D1000B19B401F90923D1BE888CAFFC5C2279027 +:101D2000FFA111799FD0918ECAE4FFB97652B10D0F +:101D3000C4E91CAD1400BD70716D3E1E9841C86FA2 +:101D400014EB0F601E23F2EF705FDCA0E3F71E5A66 +:101D5000D86E513CF53EBBA8DDF2E06115A7BB1B78 +:101D6000381D7437ED447B82CA2DB4275C3B489202 +:101D70008E31FDFD1C99C7EC9F122BBFC0CA176B9B +:101D8000C3819B61BDE57C1CD6A3CF952BC4897F05 +:101D9000D133FFCFF3F1E63C57AEB7DED91CF9449F +:101DA0007A8BC3C3E5E7DC73E4E7F08B118FFCBCEF +:101DB00098DB13E5F2B3AF4C7EF695C9CFBE32F98E +:101DC000D917CDFBE4E7C83CCF6EF7C9CFBE8FB2C1 +:101DD0007130090F3FF1372837FB9AC6D75B5DA0FA +:101DE000B7644F596674DF379D3E3DDFEDE1EBB4DC +:101DF0005550108F5DDCAEA5F63EEAB7F27EDDF6FB +:101E0000A3723BDFBE9ACEABA785CBED0495DB601A +:101E10008FC799DC56F2373B82476E775533FD48C2 +:101E2000E5C2019FBC02F94DE9F60290DFA0179BC5 +:101E3000C35846BA9D312ABFBB02F976F8DE99E550 +:101E4000EA4F27BE2A0AEB9F7FCDAF3FFDEBDFDDD8 +:101E5000743EFDF9E9AC7FAE6CFD7365EB9F2B5BC7 +:101E6000FF5CD4F6AD7F6E64FDD7F8D63F57BF3325 +:101E70000E7233574607177F4F6F0338C44400E98B +:101E80007ECE7326D9027C6048696A2BD3F9A69C62 +:101E90008831BA5E237C9CA07A601CFA71F5E974E3 +:101EA000AE4F45D526C087E5EBE9EADFB1F42DD585 +:101EB000B33F07F9A13E9776400C29DF4B3984AE3A +:101EC000E79593AD57E1FD6F37A65E83E7D3CF2B40 +:101ED00002D0333968929206EB936F77E680BCCEDE +:101EE000C7132D5EFE60F47B2E7F50E1F659DA5F5A +:101EF000E7B0E3D0EF5BC2A937A1DFBEA61CFA7939 +:101F00002372E410353ED00F73DA1DFAEC6DCAF976 +:101F1000F0DFDB4838FEB3F16BE778DF33FCF7C264 +:101F2000385347C7815F69B2DF7F46FB9ECBF7F727 +:101F30006EA676BD8872FD0380A7825D7F06DE4FA8 +:101F400054AE838CFE78268E52D1AE9FE5AC7E0DCA +:101F5000ED26A2DAFD408F57A4D59486EB8DFABF0B +:101F60002741CBF4998B2BAA40ED909C46F518D4D1 +:101F700073BF38175FDDDB887E94B910BA75C75F11 +:101F80001AB7D10F50E2F624AF7E86F76F6AE8F7F2 +:101F9000C545B0C3D26D2ACCA35B5FA57AED0C45D5 +:101FA000B3E30A7DDFA331BD9993D32F37023F24DA +:101FB000C882CD749C20F5C717D0F787E36D0867FA +:101FC000B7BEB1087496A3AA10E6B334C1EC9C6006 +:101FD000EDEA4290222157CBEC98A589348E5F8E92 +:101FE0002F773E6E39A8A589E2C12F8C277AE82782 +:101FF00028A58B02F73FC1BE21F9872C15EC40EED6 +:10200000B7058C948371066BD6FC7E4A42F303CCF1 +:10201000AE3F679D6A159FDCCA85CC76C03F4909F3 +:10202000445D38767FD44243B97ABEFEDC751E59D2 +:102030006F7BE3DE12F4E348A49FE2A7F38AF43750 +:10204000A02C39417D33C8C9B6F4DE12E87945D5F4 +:10205000B3749C872231945B1DC7A388C7FB014FD3 +:10206000414206322A3EFB333A3E7B33717C126298 +:102070009359B4FD99B640A11FED6A66178D3C9344 +:10208000ECF924C7C7EA4018E7D115607AC22026C8 +:10209000D2435E1B5FDE542D0A8CCE93FE1B35FDB2 +:1020A000F224D25CE32B878CA9BEF6E576CE054000 +:1020B000BC7520D72D62029C128513E44AD535F1F8 +:1020C000755E7B2520327D267E319DE27ACFAB1F67 +:1020D000DF0D307BEE7440C5FEAE3A5B2562DCA0BE +:1020E00096F903B1E82AA7087A4120E9268C294805 +:1020F000BF29B970C27A05527707E8F731B9A4D77A +:10210000B4FCE7E34314E70D839F224F52D07FE8EE +:10211000EA5C85F4E98EFB8F01664FADE2EB2906A0 +:102120004DB3B915E2428AB1AF11A4BDC5E328C6CB +:10213000A3400FD9CEF9C3307FA75A41BDE8F6239B +:10214000AB1AC6CBCAF1518EDFA8C8E8E4F780DF2E +:102150004B00BF57A960EF6ED5022B0B88AF632BE6 +:1021600011DFAD81008CF75F066F65F3F8DB11BC02 +:10217000B974F205C4934B27031AA59356E45AA4E5 +:102180001383145762BD49E7D5383AAF727CFD47D7 +:10219000CDCFC57B5534902A6800DF700AE15B2CF7 +:1021A000F9E0FB8FC6BB0B9736025791C165FED78E +:1021B000808B04ECDF0568F97E4EAFF74B2515F8F0 +:1021C000FCEE00A79B480AF90BDA7BFD5097BFE8AD +:1021D000F7FF0AF2E101F89EB67B401AF67DEF8E1A +:1021E0001385F9337E48317E90FE53F9C185AB9F4C +:1021F000C36D9002A3E7E6C07FCABA8CE8C556D289 +:102200002C81DD4EC226E067AE64CF12297E93AFEB +:10221000DC48BAE9FBD35660B8FF12905F6E9C9F12 +:102220007D7775DD5A66CF6B01D48BF489F6FCE9B6 +:1022300004F32783B5012738B7827E4E507FC62B23 +:10224000EFC7828BC795B0CA2064C98712F3834C4D +:10225000827A354A4A04ECC42AD024D4BEAB26067E +:10226000C695A8C41590CEC862B4F76A439F76BFDE +:102270005FC17E056B1BF938F209FA9568BF33FF21 +:102280001DFA3D0FBC21B207FB85D5F978D268BF96 +:102290007DD47EA14634B5FB747C062102027670A3 +:1022A0000B93BF3DD49E81F7447ADE0AD0F13453BC +:1022B00031C0EE8A68450276E87B4BD461023E1C51 +:1022C000B7B381FDC0CE8E34931301BAEE11D31F84 +:1022D000A75313CA84E8B1BB6ED694F1FC74883C52 +:1022E00035AAA3DF8DD5EEDFFB09F672A3275E20AA +:1022F000693346E97A9CF989CB6C4290EE59FC74BB +:10230000E4FB00B1413F66B5D52AFA75673FFE5838 +:102310005C48D85212F0BF528B2AE1E5AF80D93C1D +:1023200076B5ACE7EE14A8C92AC7D75A250F3C05E5 +:10233000E808F838BEC12A4D601D4429D57E33F81F +:10234000ADADCC7FDF16B9899C68017BF8268C8304 +:10235000E5EA2637825F43C866EC97A81ADAEB2EC7 +:102360009D1EAEBB0EE38FDDF5D761FCB15B4EC5A4 +:10237000C18F7AB9EE3B16F49B3B5B458226F84F42 +:1023800033302E933B3B734ABAC2FC2284C90BDC28 +:102390009F6964F4E63A8F006F2E4E0D08DADFE98C +:1023A000162677B645FEC6125B993F0FFD2B1A1D08 +:1023B000978EBFB275C882FD57C5D6ECA07E6E3F22 +:1023C000EE38F42780FF0E318311BE137CF515E142 +:1023D00038B76C5B335A715FD0ECAFD05E56634E4A +:1023E000642EC8DD91F73A8C9B7C654E158BAB2B28 +:1023F000C4506168C102BE1AA5FF82CFEF217A6086 +:10240000B45F8FBF2311A717FCC12051D3C0B7E51C +:1024100078CD29643DC60524AB9DED57D7CC077F09 +:10242000682C7A97E2BDBF03FB94E2AE08F4158CEA +:10243000AF7000CF5DD43E9B84A262E09830179FBE +:10244000BF837DE1A02EFDDA4B7FEF89FEF87C563D +:102450009B316E3CAE9BF217993D76BDAC9836FA37 +:102460008924FD1AF88512998BF04B89975E6B04CD +:102470003B5A6276B254CBF6A1894EED440F9E765C +:10248000291691801FC2AC9FF2FE9F50DA24A8DF6C +:102490002FA614A90EE2190BB9FE2BE317AD764255 +:1024A000FBEE7A87C98424B162C26446CFF00BB7D1 +:1024B00098E01B92F8E5A22E2D62EB2B823E8E8BCC +:1024C000982740B5F34980DBA2FF00DCB1C5B4EC2E +:1024D0008D1B59375833E9BCF53675588E033DB11D +:1024E000F62E9D8AB01E73E1E97FDF2895AD47E6A1 +:1024F00005F2A667DF8EBEB22AED47DFA4B4CD0693 +:10250000BC9C8B8789E51F80AD00ED2859227D5248 +:10251000AD330CF37C98AFF7435C2FFD25E8255ACB +:10252000DECEF5D00319039FBB32CDF87C24636265 +:102530007D5766113EB7662C7C6ECBACC4E7964CDB +:102540000ADB29F55D2AACDBC3F543BB04881B38E5 +:102550004BDA5EA19F3C1C1D7A9D601CE10A5686E9 +:102560000DACA9D4AE912E6D8338D5C3D543D70712 +:1025700028084F4F6ADE7CB49E969B865E1768B92A +:10258000BBEBA217BB28480FCF61EDD7489F6F73F5 +:10259000281D3F1CE271B6C4B5E7C1039397F750FD +:1025A000350EF878B88EC7CF26F85D06BEA3CF8764 +:1025B0001B3FD97821296FB1F9AE6EFB199D6F4889 +:1025C00065F0EF9252385F14599F25649FB46A33C7 +:1025D000CE7F0EEF9FEAA9FFE6D1537F09417280BB +:1025E0007BDE2783FB210EB7A20F5B905A1395EC7D +:1025F0008DC057B1F5C7AC205DDA48E2454730A041 +:10260000BF5ACC97391F1DFD6FD160F6116FAFB463 +:102610009A64067D757FD9FB9A9516C6331D0828E6 +:10262000D3F75B5ADA549EAF8271855E89E58D409F +:10263000DC06F7777F24A2FD931BA33DB4735A47B2 +:10264000DB8D09A77E1E3B7782F324520AF36A369C +:102650008ABA6F5E5F2D2B8734C6AF135D8F17F973 +:102660007A5C29F2F9F37E1694F53BEDA900594402 +:10267000593BB1C1A367E8BFF1AF847DE5C9D7D6A7 +:10268000F8CAB5D74CF595F5C57EFB68EADACFF800 +:10269000CA0D77CFF79565FDB3BE72ACB5CDD75FE8 +:1026A000CDB2CFFBEAB59655BEFA7F2BBEAF2DC398 +:1026B000C7D565E509AF1B910C2EA71D167F1E29F6 +:1026C00073FBE07CE5B3B3FD65D66F90DC50C5FCD1 +:1026D00005E6177C95F036E570981E7B5B8476AC3A +:1026E0006C503F1AED1BE2AF1FDDE7E4F1CFCD12D6 +:1026F000F599C1DEBB0FE3A31D4E500FD2E79950F1 +:10270000438150FDFE0FB2FD6BA607D29732BE4843 +:102710005F8C795642E53C2F97EE7A32E6F6B73C6D +:102720007A2698B813E3D66411B3332DBE4F148CB8 +:102730009BFB315E083A11F4A16EEE87D0D78792E9 +:10274000C2E25FB2F521C88FC3D3BFF61AD893A7F0 +:10275000172926C891FF2B19388F9EE9CC8FA070BE +:1027600021FF6CBDE414E67F05A534EECB04930293 +:10277000F20BEC237CD11BD796037EFBAA0C4F7B7C +:10278000404FD0FAFBA7373EB018F0F4F722DFD75E +:1027900029E13EDBD64B26639CA12F93DA9594D199 +:1027A0008E29423E4C9F7CAC7D0DB4FF918CF3CCC6 +:1027B00066D42288D2C397CCAA023BF92329E0B37E +:1027C000E3B3D1703BC42F42B3066DE8F7CCBCA194 +:1027D0008B60FEF73716D13E3873F2D9CB3B097CBC +:1027E00017C3EFB6360A8837673A293C86EB4BC7E2 +:1027F000A3EDA2ADFAFC7E03E0A5F386B8E3CFC556 +:1028000002EC03AAAD741D3CFCB22CCAFC4AA9958B +:10281000A03F4FA463E44BB8AE56ACDEE37FDED3FB +:102820003A84E3C7A7892448D74698D531BB84F1B9 +:102830006DAA5F009F71B67EAA4E0A96C0C814E2C8 +:1028400078D4EE463B54FCD7A5C54720FE7B5950B3 +:102850007F8C96A5E37F4276A1FD1218962F83F117 +:10286000EDDB81BE480BF31F75FA0FC84F35E9F752 +:102870002715EFBAC07E23F1D483DDF3D1028C7B20 +:102880006D6DDD18EE0438C4AF54811C175B03274F +:1028900082B47FD18E159779F6F7B4E3A11F1EF5A8 +:1028A000E063B95CD93E1AE9670CFBE84C46FDE1F0 +:1028B00051BAAE7B6516AFBA49B1FE50A6F4F26BC1 +:1028C000D91FFF749F7B65B6EEAF4AD62A68E7D260 +:1028D000973CBB183769FF03D504F5F44DDD3F7B0A +:1028E00011F4B29C35E3109FCFCA65EF975AD8BE5A +:1028F0002B5499FF0EC92C6EDF23503A9D392A3F85 +:1029000054BEAEF70B8E03FE917367CC847551896C +:1029100083FBBF352B0DC1A987C6ED1D27687D48F8 +:102920008F99404F6E7DFD5A569F6B4C231F3AD5B1 +:102930001AD277AE5E29427ED2D626E551D1A327A0 +:102940001F94995D9EE3F8D82AFBE1BD8FE3ED2F3C +:10295000646667E4A2DCCED0B7FBF21846FAE1F871 +:10296000D92C1F45BBE541D960FC49ABC12F709AFA +:1029700014A47762B1BC164FBD53EDADD7B7E1BE1D +:102980003895D61F7F4CF112023A167DED993D54D1 +:10299000A4F5D4CF0D812EA07894A75C6381FCEAC6 +:1029A000053F08FCD9FA1545C0A37AB3C6F693755E +:1029B000EA8980FC4AB0BC4D374FF6F7B2FDA0EC77 +:1029C000E177D560F13557BE8FA95FCAE47A395FE8 +:1029D00080DD511CCFEE70F380F3D78FBB7F0AFEF2 +:1029E00097773F30D768E33EFA97E46FB649B0DE99 +:1029F000B21D077BFA7AF9C9B6655361DFD422F1BB +:102A000056961FBA5980792C2FDAB0CF4621463F0F +:102A1000E6AA623CC5F77F871772BA83B8A199B35B +:102A20004E80BC10981F2971FF5132CAE2459CEFBD +:102A3000C682B7A38C7FBF0FFC7BD128FF12F19A0F +:102A40004037C4B7F8BEFF58FDB8FC4B2E183FEF17 +:102A5000AB27C3F6017F225B3F8275CCCAAEBD5C5B +:102A6000F2D1E91ECEDF5FE57C3D6A1FE479D98CA7 +:102A7000C33A04C19FA5DF2B40231EFBE29FB93E52 +:102A80000A86597D391CD44F7D1DC60FC6B83F0C30 +:102A90008B00B429993E3846F519DB37A5F2A60418 +:102AA000F286C499FFEAC2716E7B066F9CD3AD9427 +:102AB000A0FE34C8E773FDE95FCBE3C3F95BACFF6D +:102AC0008470FE12F056370AE7987CE1C6AD46F3F3 +:102AD0002331DE9E35585C5DA4022B00791F062948 +:102AE00038A01FF282C5D68BE74326FCF1F5B1F280 +:102AF00033E2ED051627D558FC958E5BE479320458 +:102B0000F279E8B3188A41DEC07C1E2FF0E72194E9 +:102B1000E737963F5D3D066943A0C7CED7BEBCFFF1 +:102B2000F8B5A9F1E547795E842619A7C6D93F1BF8 +:102B3000FD4E22A73C7267B6E2A767CB5E8D71A4FB +:102B40002009981087C9C6AF23B681F908B8CEBD51 +:102B5000F0043A336AB0FC7B90ABB05E71AA8FE7A9 +:102B600052A854AB889DF3FAF3ADB3A4A710BFA24B +:102B7000C6FC3BCA4F7190C322E176864EF240A755 +:102B80002A8F371C5352572975989F49BC7224EBE2 +:102B9000C6C10CE637F535AD30208FAE51CAAB5EFD +:102BA000BBD0B55F739902B3030CEE77C6597EA60E +:102BB000BB3F520ED739794449265744358F766842 +:102BC00028BFCD02BA2CCF0F72F3891E76F3BB78E3 +:102BD000DC6F2CBA74E1391FDEEE11491AF4E99961 +:102BE000FB0ACA2AFABCAD78489941E9EBEB0AD353 +:102BF000BB67EE63F87837F3A12F1E749F3219EB91 +:102C00006F7BE15165A9077FB7713B88C2A7F8F1D7 +:102C1000C5F89768C3473E867DA18322F2CB58F062 +:102C2000AD8F1F392A79F0F4F64111F707DF96A826 +:102C3000E0A9857223F2EDB9F32AF8ECF5F5F197E6 +:102C4000B09F33F7169414CE4315DE94D93C218FF0 +:102C5000F2B6E71E55C0C7381FDC1BCAE8BBC0FB75 +:102C6000A1FDE2F99470F110E665861D9E374BD503 +:102C700001EECBBC3C691FF82D579DFD26EE5F96FB +:102C8000E7A984609E0B46CB7DCD6C3FB00FE6D9A3 +:102C90000A65A3E054C053F93C4330CF05A3F08D3F +:102CA000E0D90C8C8BE7AD99E2516F7E7EF9333A17 +:102CB0008FED9B46E563987F713E3862ADB43FAFC0 +:102CC0009E76E1581418373E32007078F64FB62ED3 +:102CD0006278D82A1D5327326ED4A4DFFBF65B1C22 +:102CE000D23C1943F628DCCECC20D64A0AC7CED532 +:102CF0004CDE53CE390DFEB4BB4F1557FF886CAA7E +:102D000019ED6FB24DEB7DF10307F3C7E3D7F2F88E +:102D1000B1CDBE77E5A48BF7723855CABF207FC509 +:102D2000788EC55DE361D49762423A55D63F7E9F67 +:102D3000E5F2D1FD3E37DDCDDB2547212E2C25A840 +:102D40001F2CA03D8DFE59571DF383DF50948AF947 +:102D50004FD4AE7C430139A1FBCF65E5EA59FEEBC8 +:102D60005871DA5CD9B90D17DFAE9D4ECE2E3808FA +:102D7000766C36D07C27DA73138CF7F64DDFD6BE2F +:102D80001AECEC3A05E59BC8ED9BF2F97DC0E7E350 +:102D9000C6EBE93C3E50305E9872E3E6380F378F61 +:102DA00077ACB87B791EAF3B0F379F17CE1D819E46 +:102DB000C80A2D77621ED904E3F76E592CB3CFBA37 +:102DC000A62F89A3DF1355B8FC66F392132C7EE17E +:102DD0009E6FE9AE66EB561B542AD20D9D6F6DB007 +:102DE000CEBBCF9E72CFAD914E886F50FF421C0775 +:102DF0005E49BD6E97E4D9DF9D1164712B7904DFC4 +:102E000026F6272699FD2607ED19C14B20DF3777D7 +:102E10000CE994EBABF2F3716E7EB67B3ECECDC780 +:102E200076CFC79D2F3F7BAC7CF6D1737DCC7E22C5 +:102E3000867BAE2FCDCAEEF938AAAFE13C5F9F7B0F +:102E40003EACB6D587FFE9C1F2780D9BFF1D5CEF64 +:102E500097E3E9BD31F8EBBDEF077DFC7575704C6C +:102E6000FEBA3A5881BFDEFBFE6C46972FD455D48C +:102E7000C377A85FF2ADCFB974C6FCF138A3213295 +:102E800058DB0C6E14D942D83CEEAFFB606527C509 +:102E9000C73373ECEB61FCDB356A5D513974472F46 +:102EA0000980AAEAE77CBA5CD44227E9336FCDA84F +:102EB0005A4DE1738242C5F1F652FF05F8E4918C58 +:102EC0008ACF336FCC1E773FAE27E3F8E475CF2669 +:102ED00009E5754FE2F44F3E07F45D9B9C0F6E963B +:102EE00065B138545037F6015EEF0C0A3E3C52FC97 +:102EF000DDE9A5F3BDF75EC7EC25AB60E94C8FE2D9 +:102F0000795A170FF2E4E600ACCBE032422601FD1D +:102F1000341FCB05281E662C2BAD90183EBE1EF428 +:102F2000F41FB74900E6E1E2236FB1BC948DCB6793 +:102F3000EDF3E6CFFF84D30D69A919F1432AD9CD6A +:102F4000EE7A1DA0F86A69427982791553F3D49F0D +:102F50008F811E63EF2F0FA6B6C0BCA6AEE7E75D5C +:102F600079BC40206AD764DC97D431FFEFC083611D +:102F70004E673A9E3FDA5946BF1E3CED0CD69D4B3C +:102F800067B2695980E715617B37CC3B229474881E +:102F90005324F3796C97E3F1570AF64F819E12029E +:102FA00019FD81899834D03EF901A78BA8EE2C81B8 +:102FB00026C983AF74427CB2CBD62C908BC9EA6F02 +:102FC0001D6E6B45FF7D18F68D92D3870EB741DCE1 +:102FD0006E893AFC18152DD336E43B97D2FA464B4E +:102FE0001D06B934CD2E58B0F5D2C5FDE2382916EC +:102FF000950AFA5F522C8C0324F475D7409C4FA895 +:10300000795980B872D75682F1DBFAB57902F23479 +:10301000B128A843BFC946F34515EA6F2526C43B2E +:103020001BBB587DBDA5A630BE428EB13D45C9C271 +:1030300078A53B4E48B76F2754AE4D0FDB3F003CA1 +:1030400085924CBEB9F6F936B980F6777871DE0212 +:103050007B6EEFBD2BC8CD1EB9752CC8FC766ADB24 +:1030600058056D942E07459455E481C59B43B76878 +:10307000D08EE5EF8A649905FD51B303E34E616A92 +:10308000CF1709D2E73FC0F8867D4C11806E9B4B6D +:1030900048BF943F313EBD4DD6EBE1BB6DF72AED05 +:1030A00005B66EAFC2E12738E30DE3B8EB16D2AD3B +:1030B00003B06EDD4199EDA37D2D8F71549DE2C962 +:1030C000A078082FDA59FC3EC54B7CA99A827DE492 +:1030D00070695BF10D5AFF527B0499A927D1E6E094 +:1030E00039E5C5948F0CD003854E8043AE2506E4A8 +:1030F000F7C4D7B2F814C5D73F03BC516ACE4A8D86 +:10310000809F144C83F448E95FDE4BBFEF7959345C +:103110001DE2E19BB2B8819A70CEB1CBD03E6D99E1 +:10312000985F47E95C82FE96A911D45347B8FCA387 +:10313000FC7506E05AA6FF0EF98B689326D45FF95A +:10314000FB0F4DB30AF0BD267EF38E24B59F577753 +:103150006CDB91A45DADEF38B41DECE993036B62B9 +:103160005EFFF054EF9FC5609D7E5590711D4EF53A +:103170000A183F3A55B8EBAB503EB9276840D9CD55 +:10318000D759C797ECF023419483BF7A54C078FA9B +:10319000FA41C18154F233D57603D0DBAF76DDD36B +:1031A0005029BEB4EEB810201743FDCD0D95F201A5 +:1031B000D70FF6607ECFFA5ED9B22AE0395B9D9ECA +:1031C0000DF2A03B73700FECB3B8F6CA2C50E87543 +:1031D0009885C2FC1ED5C478E8927FBA3A0EE747BC +:1031E000CE06ED2695D6779DF81CE6EB1CA95E1160 +:1031F0008738E6C6378226A481DDA3A467EB1E7854 +:10320000EF89297601EDB01DBE753054B9A23E7626 +:103210001E63798622099B9D145FCB3413FDA5D3D1 +:103220002501FBCF72BFBA7CBE72C793DBBDFE9295 +:103230004CED06A36534FE2E36FBE3F08BD530CB88 +:10324000B754457C4E55EDAB605EC0B61D35608F02 +:103250003FB59DE9E1CAE7413AAF6070760B617313 +:1032600033F09B671F1CF7B9A41401BC6D964A2864 +:103270003796D5A6F03E05771E0363CCA33BD3B1AA +:103280005D42FD915221DEB55965DF6733CE76D0C0 +:10329000ABDDB5D7AAA0AF37EBEC7D777C152B1B48 +:1032A0006E99D75BBCACF17AC72DB3FA9E4C2FF662 +:1032B000B7995423BDC63452803C74385F02E73757 +:1032C000379393ACBD7E2D2FBFB512E47177C2AD9D +:1032D0007F9B9779BD565A09FE72B73183D9B19A4F +:1032E00081F43FFA7E59C5F77D9934C2D19FC9E375 +:1032F000BC55928F43BE10C874D83FE86EE6F0BB51 +:10330000FD344B02F0CB39FDB7040215C76D61F0F7 +:10331000691DCF207D74D7FE14F7E9E97ADFAB7A17 +:10332000F85EE6EBBD95B0733452D224A04F8A33D9 +:103330008DD3F2E5A3EDB6A8CC4EE970E92A61126F +:10334000908B54C26EECF1D0B76899789E396E9725 +:10335000BDD7CBFDBBCAF4E5EC62F415043EA04337 +:103360002E4BA471FFD3A59FB1E419E50FC4637779 +:10337000A61DF13AD6FED3236A80CB51FFF81D5427 +:1033800089ABCCCE1E7E6C1ED8FD269EA771E7476A +:10339000DD0B3C37EBCEFB9CF9D5D2F979E48DFB04 +:1033A000BE07E8DD6317FE10E40CC479F5F92AF0D6 +:1033B0006930C1F4EE927FFA7394333D27BE1C0747 +:1033C000B976A4EE3ACC2F74E5CB58F3DE9269DFE0 +:1033D0009184FDD38C8DCFAC395F877EB29A448ABD +:1033E00020C7A434C17DC764819DB3007B8592BE94 +:1033F000D292C27D9960924E1CF45C227D0BFA152C +:10340000C743A409E2AA893CB9C5235F431C9FE1D5 +:10341000B39964C77C5AEE58877A211C5F8B7AE295 +:103420009E18B12BE1FB6995F90953D5D48F55F05E +:103430000B3A0E8C2B5F9C6DECFE885139C8F4FB67 +:10344000E9E321D413A2E6042BED73481D6B90CE63 +:103450007F0D6B7009E0F332CCAFCC9EB8E716CC91 +:103460006F7F2384718F23D185AFD913C0ABDCB1BB +:103470001DE727767C1D9FA3EB6C223E459D9D7723 +:1034800086FB409A0CB09B4CB60F6FA587C56A6F40 +:103490003F3B593FF68E71F1F40B55E1F2D87A4F6C +:1034A000AD409F23F8799ABC86F79A1C0FEAC01F9B +:1034B00047DEB814E1D87882F1C732EAA712E60FE6 +:1034C0000F07AB215F8134A7352F3DAEE7F4E2EC67 +:1034D00080FDF708C75B90F23DEE03B4F07925D983 +:1034E000BCD4E6A122EE0B24C9A5402723F5CDAC20 +:1034F000BE3B93C67E0632BDD86FA4A58074239BC5 +:103500001C4F6E7B93B5575A797F66597FADB49E39 +:10351000C0F7C708D88DE12485CF232FA8FEAD0BB7 +:1035200081DD65F6FADE4BF11D88DFB1F075F4C47C +:10353000ECAA52057CBBCF7C6610E5461FD73FF94D +:1035400046B31DE4FF0097CF3DA07F9AE05C5B1E71 +:10355000CB5BB8FEF843B82400E39F3AE6F5C2DE41 +:1035600006DAA30AA3D750732DFA115B655616131A +:103570004CCFA8640885930679E93331AEC9E208D7 +:103580008B8D4296AEE7D69089FA4720A6BAAA82DA +:10359000BFD5A73D887A616B356BD74706D58D2D92 +:1035A00090DFC0CB521ECB51859669BB909CD7B1A2 +:1035B0001C66E5B1FA0D451FD4A1DF680DFF4E185A +:1035C00064DFCDF0F7B35561E3F44B05366E787CDC +:1035D00078FBB57D0CDE1AFE1D39C8BE9BE1EF6796 +:1035E000ACF50927E9BAF8F2E4E97AF8F44801D72A +:1035F000416BE9F5BDAF5A94F7958FBC317B4AC951 +:1036000033CED1D2CC71E9E214D085476E9F0AD96E +:103610003781DCDCDBF7AD655D095A96ED068196F6 +:103620001BF49F75ADBC82905B3A6E46B9B68ECBEB +:103630008DD51D7FC2CA036B14838EB36E8F807EBF +:10364000D23A2E0F08B115D037EF34A6CFF4D37E7F +:103650001E0831BBCCD5AFEB345BC1BC9F32FDBA89 +:10366000AED6CE0915F4CFBA5ED9A75FDDF7AB3B76 +:10367000D6A0DC19290FCC4478561376CE7235C803 +:10368000718C931B0DED73E07C6908E138F9D84328 +:103690000DA097DE11F237FD05C4276F0DFBCEE3B9 +:1036A000B94F377E7F16840FC82DC97EE9630AF7AC +:1036B000C94E71B87FDED8FDACE37AA3BC9FEE1093 +:1036C000EB67DDC8FE43BA08FDBDD3D77D08F3C460 +:1036D000A57CC3F594CEEE09A93EFF65B5BDC32711 +:1036E000A73FE9BC3321765E30C7C79FE8F76EFD80 +:1036F000FF00BCA13C70F7AD0B1782BDF06FA58B2E +:10370000DD33285D50FCFDE053A60B572EAE3B9BEE +:1037100021A0C7DD7538CBE3A144A270CF19C57FC6 +:10372000F0ECC593AFF7F0F5E31CEFDF0F1915F1DF +:103730005F3EFF77D68703102F7DE7E5E5B8CFBC66 +:103740005BC9DF047CBF9EE3C5C5C729AA8FBA3C0D +:10375000FCB66EE0AE9716D179DE7AA0BA46F0D00C +:10376000F3AD07B6AD985A0B78AB9E0FF194F50701 +:1037700018FE6E19ECDCD1E5F3F75C3CE6FF15F0C2 +:10378000F816877B048F493B57C97E5DD7622B6251 +:1037900005FB752C3CDECAFBDB1DCBDFFF38FDEEE5 +:1037A0004DB2F7FACD40AF2F2FAD0AB58CE26B7555 +:1037B0009CF9D16F12763EFE14D537DEF99E1C9C23 +:1037C0001983F8CA9B12B3C34F0E36B1B2CACB7B72 +:1037D000683D7DBEC9CFD79FDCD384E5727E3C6750 +:1037E0005D46F4A3E3DED3F27601E2F1FF1434B3D5 +:1037F000B4E9F5219B84E97A75C63EBB1EF4D03D41 +:10380000270503ECACDDB1C5FFD330C6D6AB7D19BF +:1038100043F0FA71A131EC6D312CF8CE9767332B60 +:103820000FBDE599B7289918679234FABE82FD3C1E +:10383000D171126116279C68FBAA32B8EAD77BF2D5 +:10384000FFE9BF51DB7F8E206CFAEBCBCF1178CE36 +:10385000A3E17D0DEE7D4FAE7E82DF6F26433C8E71 +:10386000A09D2097AAD7407C6F89C1F2C44ED7068D +:103870002ADE53342A1F4971440FE23AA8C511FDCC +:1038800006F18CDAF1CF8B6433ED3BA532BC9BDEC5 +:103890003841C74D3BC10E3C5ACBCF296AFAA3DE53 +:1038A000F34BA370147C65B1E3F1EDDEB87D786471 +:1038B0003FC536BCF1E2BE50FE35C88FBAB17F5667 +:1038C00037E431F6F1BCB435E185DD9097D6E7EE0B +:1038D000A335EF70F7BF08D8B9B939CB1EABB44FD9 +:1038E0008A276B60FFA67818E3E2D4DB21C0B751CA +:1038F0006A8F17297E4314D7C7D0FF29E0BD11D1A5 +:1039000056E667DD123658BEBFFA1AE6ABF7B79E29 +:10391000D4412E9D99EE6FEFB60B245582797A2D06 +:1039200012EE1BBBED0FBFF165D24BE1EB37D9F9BE +:103930004E621554386712B94C42FF9D34B37D284E +:10394000AA0FC78D9B5B5F5962C17D37547DA671FD +:10395000DF905816DCB3201B12E669484909F331A1 +:103960007F2FDB77872BECABB8E38C4D379C2E2772 +:10397000D8EEC18C81F9C7C9831A3B6F7E5CC07DCC +:10398000EA1D99E6EDC0B7D49F6079B437904296AE +:10399000BE9FD4609E80D40AF2AA481E4379613645 +:1039A000827D3FE5784467FA3A7DE997BCF718666F +:1039B00058DE9C7BEEE04C94E445CF39D84B15FBA8 +:1039C0004198A7105B64C338AE3C9A740DCB23A911 +:1039D0009962CC837326031A29A616D172C478166D +:1039E000E2EFD20059A1C1798620A3AB42FF921C1D +:1039F0009C3BA99969CC0BE0B996CB56BC12A7E5C4 +:103A000069C6EFF09C4A64E18A95D09EC202E73A0B +:103A10000859B102F2146A2E62E5AF0DD0EFB5512C +:103A20007D41FDEC9D6FA13F60EF04FC1CE4F2269C +:103A300002F28B7EF724A717E0A3B7F09EB321C252 +:103A4000F2A959BDD8B16EE75B0BE03DBB2714135B +:103A5000C63CF2E09939F610CCFBF6546905A4FE99 +:103A600048BABB4F531804FA70EF43582EB6549D12 +:103A7000F4C8B33361169711256697F451FCB23838 +:103A80009A136CA0EBA2BE3C691ED0E30F38BC6A4F +:103A900092ED1FFF02E0AD83722FEE6F12A3382864 +:103AA00079F6EF3BC6909B3FE47253EDF8F120CCE2 +:103AB000F32538A805FD761C197CCB630FF5362D50 +:103AC0008C837E75042DDD44F19F6D52317EEFD6DF +:103AD000FF3D87E7172372D82A76B1F804D2BDD507 +:103AE0006B11E40BE0031DF2BC57229F742F515958 +:103AF000DEA8D18B7990942F7E51892FFA64A7EAA2 +:103B00004AC0DB8F44C45B2349F1433CFAE6176BA0 +:103B1000D14D4BB37B52D8BE4537FC0F05E9B76199 +:103B2000EED775BDB0C78B0FA2E753B0DF93ABAD37 +:103B3000417CF6C9F941A0BB5FF5DFB55CAEC77D3E +:103B400060A49B77C2F77403DDFD36CCCF89101BD0 +:103B5000F3EC603FF8ED1A1CB7189C8FDD0E26DDE4 +:103B60007B0169FF4A73E0841C3BFF3EA31C3F3688 +:103B7000E8F587FA3F73039B77ED870F8FE4ABD3AC +:103B8000FE822DDCFFE67441DEBE8B78F308AF8841 +:103B9000B038587766E576AF3E5678BED9CB8A1DE9 +:103BA00088403CDCBE663BACB343F10BF2F2B1CCD7 +:103BB0007AE403C2F7630D4EBF8DE4DAAAA280F166 +:103BC00000E48FFE8C834F63507FF15E900F7AC0CC +:103BD0005CBA089A265E3C0A76EAD2C07090E2CDC2 +:103BE000E8923EF0EAD9F23CD59A883FCFBC274311 +:103BF000E78979E689C00F6BE1BE9B00C65B8286D0 +:103C0000D10678936B6D8CDB899A3E9F9F0DF6C130 +:103C10003992BF2A6A2FB27B8D883909EFCF60793C +:103C2000B5E5F0B8782987AB29E2CF9F9DD9B11FC0 +:103C3000E9FF7D9268B328FE030304F5E84C879DF5 +:103C40001708753C8CF5E181A122D8A54A8B1F9EEF +:103C500040926C06B843700FA409FD3D8EED1B8F9A +:103C60007FEE65D8CF0875FC1596CBE1A3D4FB4158 +:103C7000C993AF68B4B0FB1EC76A7774ED646CB7C4 +:103C800062AEB518D6D78A106E370D0EC2BAEECF17 +:103C900014F0E9AEF39137A6E03CF6196C1ED2356C +:103CA0005B8AB09E07E87A02FFECCBCF0F009FAB98 +:103CB00051AADD05941BD89EFE8B79E3B2C6E019AC +:103CC000A15FC30FD717381DE632BD385E0AE0C1C9 +:103CD000729ED1993880F96DEF1B243D89DAF13D50 +:103CE00049C782759F41D79D78E26C4A931500BD04 +:103CF0002CE7D978E5E3B874E0DA6572AFE3403FCA +:103D000084F6B3B41EDEB373A0E5DF95AFFBDA48EB +:103D100079DEF459CCE77ABF979DAF261DF4E739D9 +:103D2000975ECEBFEE7ABBE52394DF4BE3F0FBE377 +:103D300099C19D2C3E55C0E7E383ABF0FCFBAC4141 +:103D4000BA1E942E66D5B2F31ADFD8B31AE9B97B3E +:103D500090E03EF3EC3DF9CE10CC2F4086AB12D470 +:103D6000A4EA4DB735E27CD561B82FA62FB911EF83 +:103D7000A7EBDE4370BFFCF1C107F11E8346A20E24 +:103D8000837C7548DE82F68D567C18D6B9BFF94122 +:103D9000DC8FEA4EB2F6B3761D70A0FD0584ED6FA0 +:103DA0007F63CF3E0BEE3D50F87E7758B31FBCBA11 +:103DB000166D3813F210E4DEF4DF5D08E3DFCDE2C8 +:103DC000800E49FFF46ADAFE82161DEFF9537A6914 +:103DD00019EA37B8F5F995703E7CFA32561FE96555 +:103DE00065B296C509693DCAE369033A9EB7A8EE74 +:103DF0002DF4CE80EFF3ECFB509384E7DEABD712CB +:103E00003C5F3113EAE1FBC5AC3E7C21AB17971157 +:103E1000CC3348F616F2B87FDFEAF63F8CF252EC6C +:103E2000A5965D0B948F11C88374F562563D82FA96 +:103E30004F0CFD18F9D2E59FEECC417CEECBBC30A7 +:103E4000C8E4E01096DD735F32EFAFA9D968037B59 +:103E5000E3BB9CFECB9FC12607E97E26444EE711BB +:103E60008408E3F71619867811E5149423D368FDC6 +:103E70006EB312BD337E6FA03FA05397CEDC38D80F +:103E8000D11397FAE88E74513AF39E93DF54F0976A +:103E9000EF3EE82F6F18F297D7BEE02F2F2BEEF4EE +:103EA000E9CFC52FFBEB5B8FF9EA5D38063383DB87 +:103EB00097B17D1C8C2B0FD6E9F5107FDCC6CF01A6 +:103EC000F7C23E077DBF27D381CFAD3C9EFD008F5B +:103ED00043EF86B836C4A13BF66F87F34BB94C3B32 +:103EE000F6D7C7E3D38F64F2F82C713C53FBA114CF +:103EF000B904F22AC851F01FDC73288A6DA13D3045 +:103F000018326E80F183B50E0978F0351C61765752 +:103F100084C783A89D8FF71846347D5E3FF1B60BAA +:103F2000F8F6CD94781AF328ACE92CEEAD2474BCE5 +:103F3000E7F9BD08B3839C461BED9797156B18E412 +:103F4000F3601D1D1FE2B0AD2507CE954DDD60600D +:103F5000DCA36A3111248C331BA8E712E96302EC5D +:103F6000F745A83F06F39EB69EE2C1EBBF267B7DD8 +:103F7000E5C16A36AFE93CEEA4F278563CD4F6319E +:103F80008C3BA0B1785057F5BA7A90372DE194A8C0 +:103F9000D5817DD283F6EB8046F8B90362433E8635 +:103FA000C78E0D41BB73ED5837FFCA6FBFDEA6F950 +:103FB000F3AFB66458DE550FE45DD175DA22A77F02 +:103FC00009FAC6B5E3C692935D196A1779E4AA6443 +:103FD000064ED4C13903C85FAF60C72635CE6741EE +:103FE00096EF9D853C4A9497FA4F2297C37DF094B3 +:103FF0001E6A407F058A93BDFA8BA26A7D0D3E5FE3 +:1040000016A91D1751D87E8EACD3F13D7AE27C768D +:104010005C5746F7E5934AA6E44CA1F06EE1F04AFE +:1040200009E5C4245A8E70F8649DB6F7ACDF87A505 +:1040300099E3F6DF97A1F62BEDFF468D9F8F99A5AB +:10404000D8607FCF86934594EE0E68B3F679FDEA8B +:104050001B3546CF07F2E3C711207F099CD52D7091 +:104060000FC16CE053763F8E5BDFCDE5DC4393FE02 +:10407000869CF0E0FDCB1C8E4889C5EBB4BB8C8DD3 +:10408000A90AF55FE670C8545DE3F931371F33C103 +:10409000FC146BC317F1DC54D052D12FA0FCFB658C +:1040A000CD932F3792172A5B7F87FB7EDB0204F2CA +:1040B0009BB3370790FE820D83716FDCEC4A3E6E36 +:1040C000AFE0F717D4192BCDD53E3A6DF4C53DC2FC +:1040D000498F7F3081F5962C967FEAF2D5FD9FBD02 +:1040E0000DF9EA0B41FB4F35F0DF52B605FCD2D992 +:1040F000DC8EFCEFB6CB4619FF0955D64668E7F2D1 +:10410000DDFD51EB6E56F6B773F35A46E8D53DF731 +:104110000E3FD0E78EFD38AC7BCD1F2C3ED145CB7A +:104120008F3AEBF05ECE014DE4F108C2F313D9F9FA +:104130009D2D9AE1E34FA52B85B9AF357F700DFA20 +:104140006BDD3CEFD66A67E788CBE73DD6B98FDFFA +:10415000CBD680867131E6575C1EB4F350568E077D +:1041600071BD9538CF13E479C9359352F1799EF535 +:10417000788EF36FF7C8B9321E5FE3F967F88338BA +:104180001C94A97E7986CFAF668AB519F71B459234 +:104190007E9ECE7F4A9EE0BDF0FBFE582960BC4B60 +:1041A0004A39EB6979D70F9B098FC7E0FDC3E02F30 +:1041B000EEC672CA5A07F8B13503EA558877CF843C +:1041C000FB4A86F0A9513B019E316A3FC053273A12 +:1041D000DE3BE5B9B7F569A0D70DAA7D015C35FDD9 +:1041E000EE74FB1B00F3B7F9BACE0A5BDF043C7830 +:1041F000DA7FDBD75E66ED7F2C59CFC1FB5725EB0D +:104200007986C7CAE718C7A2C7C3A5352AACDF2E6F +:10421000274620EF2DB736D008E5D3772B980FA08F +:1042200037509508EFD38AB999E0BDAE171E00FE4E +:10423000D8C0E210EBDF67F5B435DA5FCF664A9895 +:10424000FFFA483DB1AC5AC83F240582F1437218C9 +:10425000F2E214F01728BEE61F2DF9F2DF94B5EC58 +:104260003C986295D92F26B35F5CFBE06161E87AE8 +:10427000881FBE3D70C70AE932B84F64E87528FF51 +:10428000DF813F5F01E72DE13E1288EBD46EEDC286 +:10429000FA3D4211DBCFDEFA00D6EF0915B1FDA5DC +:1042A0005B1F62F5D5456CDFDBB317E3408FDCCBDA +:1042B000E8E891C3AFD7A35DB5C19E14F2E4C34E45 +:1042C0002B7EF7B0520BEFCDEF843C7AE8179C3F82 +:1042D000A66D185A02F6F0B4A4390B96615A738190 +:1042E0002C6DF954FA3D0C76C5B404ED97BE9A6670 +:1042F000389F5ABF902A3FED150EEF314BFCB4FAB0 +:1043000085BF9332ED7B1CDE22F9B4FAED0CC17748 +:1043100083BCDF3DE9C0A7D4AF80DF39BCDF2EBD51 +:1043200062BF0D1DFE7EFF286AA0DC6D28BE83EBF8 +:10433000DE903417C2D661035DF735DA27FA1ED74F +:10434000B72141BFA7AF1AE8FA7ED2EF611D1B5E0D +:10435000E1E3D375FCA4DFC37A357C8F8F4FD7EBB5 +:10436000137E8FEBD230C8BFA7EB3291EFE977888D +:10437000F706877F47F10EDFC575664F1FFEB357FF +:10438000EBBD76A2BB3FBCA7EC9E54F7797B94E9CA +:1043900083D171DF11664561DC92B00ECF99ED6477 +:1043A000F0E6ADC00AA8FF88E995473A8784852DD5 +:1043B00040273F1266D176ABA3A2BB7F894FB0AB3B +:1043C000E11CC6F41DA9808574C1CE473C22FCA423 +:1043D0001E8FE8AEB527757AE6555FDC85E3D6AF6C +:1043E000CD0BEBE0A9996485C6DECF8C8EF60BF57C +:1043F0006BA05EB7C852AD02DC14CE75A8B7736C63 +:104400005E23F096105EC0DFACA8675E14BE75DA5E +:10441000B9F0C1FDDA5EF894E2AD04BE53285CAC9D +:104420007F060FBC07F8140ACF1A6D6CFD71A42427 +:10443000A27DD09D60F1A0EED25D45C8A7EA1E1016 +:104440000C888766276F2CC2FD3FA7F16A62AA27F6 +:1044500037B13CF6A0B6E98F20DFFC9CFBD9128671 +:104460003FCE1AA70D3CFB67DBE03FF5E857EC8831 +:104470007AFC0AB9D6EF579065F3B1DD7230306A35 +:1044800061FF6A16EE5F01BC0E2D1F4A18FBA0BC2F +:104490005CDC84F1AB27F519F3839E7BB2B772BF66 +:1044A0006337F73BF6660C7C1E2A7D3BCCEEED9421 +:1044B00030C836C8EDABF54B36EF4CD279CE29304B +:1044C0003B69B93830B989B67BE22986977D197383 +:1044D0000FCB476CC6E703193A4F19E143FCED8F48 +:1044E000B376CBC50D16F0DF33FCEFBF2809BF1E36 +:1044F0000C92F5184C0A1EBF85845B71D7CB9CB417 +:1045000008BE5BFC79806B80C205F38AEBCECE26B9 +:10451000B06B06D8FD26CBC557C2DEFC9671FA2DCE +:104520007AFB7D424DEBB01FBBFEE67D814AE7AAD8 +:10453000C7EB07CF21F07E9ED1783FB79EFCA4FD4C +:1045400038614F3F033AED671CBBBABC1F3AA20368 +:10455000F80C425C84E2F3CDE80CE6FF1CBF05E9F1 +:10456000829AAFCF8A54FF3F05FB84E047D46BF3B8 +:104570001C32F1FE3F029EBB04F0FB9B9D77D07185 +:104580009E7C8E14185DFD66F29FC2BA16D8BA8E54 +:104590007C4F9BDF387FDCF9E2FABBF37D32CEF053 +:1045A00036F1F976A0FD1C843831E5AFFD09F63D02 +:1045B000E1F14E85F3915260715185C739CFE9E73A +:1045C00013DE1F21C7FC71794AD7F8F78A4EFF4CDA +:1045D000C43C44578E97F7E3C63FDD7D2AD7CFFF13 +:1045E00036F523813FBE9989E3F371CE7F854C3345 +:1045F000966B63DC3FCD98F83E9B5984EF97943AD5 +:10460000719FEBE08FD8B8F5C499DA007CF0824254 +:10461000E0BCE1C1EAE2540CC6AACE54C84BDF02AA +:104620007EB1274EB065CECEA920470EC9E63F42E7 +:10463000FCC7E98C198FD1E7E1674FDD00F73B3DFF +:104640007D48C16B5E9FD9FAEAD4FB60BD9F6718B5 +:1046500035393C9D5086759FC3D6FDF089BF766E77 +:1046600003BE1408DEAFB97FDE4B78AFD2D179DF5D +:1046700031C68BF3BEA0D9668CCAB7C853CA09F03D +:104680007F222D04FF7EC5C4FB7F09F35D07A24393 +:10469000C678FC42C7B92276C9B9E31C3EC1CEF741 +:1046A0000DCC61F41C39C8FCEEFDF31E9F0A747139 +:1046B000F4D04B989F3C507FDEFEAF1EAFFF27F833 +:1046C0003CF61F3AB53B0B72788E02774E90A34FA3 +:1046D0003F7E03D8410314FF70DE69E0C2D2EEDBF7 +:1046E000209E36374C2AF1271DE7BA98473F8D8E1A +:1046F000F3ABDD39F89EAF1B5DA9A9706E2B622A62 +:104700001847A6EBE0C3DF40D3D06E905B91CD316C +:1047100003F4C4334F7F676AA5732774BCB513C114 +:10472000DB7EE81FE886F60F71F4A3CF3F3E15F05D +:10473000F6C49CF3E22D5DA9FFA7E4E254E0E78311 +:10474000CFF2F34F52EFE424F8A32F503F1E367DF3 +:10475000888DFA4CD6572F04FF6A7A8CF9B973D535 +:1047600014CAC1CF5004E475D837F4F853200FA40D +:1047700076943FE164D9FBE35F76BCFAA0FCBBCF43 +:10478000A8D42186B874DC3D37EE8ECFFC3B35E1F2 +:104790006F3F536571EA6680C31C1B8ED657FCF2CF +:1047A00088C241BC7AA0FCBB6680A315FECE6665BC +:1047B00038CCEFF9FB8BEB29827F6F87563D5F0189 +:1047C0001F2D7C5E73A13F8AD7D983FEEF9F8CD5C6 +:1047D000303B89E227E2858B9A0537D678F68FCA77 +:1047E000FA6D74FCFD1C81BB61E8FADCF1CE756CDE +:1047F0007F304586203F6D2CBC947F4FC7477C8E11 +:10480000851752B6CF3593CFAB99CF4B2E303CB9ED +:10481000FBB14D797FFF63CD43D2FEFFF4C58F63BB +:10482000FE7DB3F7C9F730BEBEF7DEEF582067252F +:104830001E478AB4B2F3D6914DFD0887AB2F222DC7 +:104840002CFFE348E9CD30C8B9674A332BDE07EFC8 +:1048500044ED7F8C79ED4B3DBEC7BBEF609121D419 +:104860009791452AE6414416B1F1E87725E43F3EA9 +:10487000AE3B9EE3B65FCFDBAF1F697FAA52FBA3BF +:10488000601FA3FDC9E481D8A1ECC1BC0F3AFEA60C +:10489000F978FEE65DAFDC126D76FEC6CDB719E0A5 +:1048A000F936931ACCC699B04E6E5ECD32769FC063 +:1048B000A419E98B216FCBCDAB71F369C6BE9FA85C +:1048C000C0F243209F86F677E684807FCF4A88B186 +:1048D0007BE9DC7EC75AC7913CFAD28222DE5B516B +:1048E00014F15C816B07BBF7D6D079A955E3CC2BCB +:1048F0003B3A2F5FBE50F97CDCEFCBFFDE4E799E5A +:1049000050797E1091F8BD121CDF1DA4F4EA9FC2FD +:104910003809660FDFF17490405C2AA81B0576DF2A +:10492000B45584B894C8E505F50B300F2F0BD7E9C3 +:10493000368EDA33DDDC9E19818B58685F89091663 +:10494000B72AC797A8FBF944C24D46B8C7EF52DC57 +:104950001F1AB5DFBF827FDF20A733FB3DA8A64823 +:1049600025FD50DE1F5D30A44789DB7B39D5D2F9A8 +:10497000B970E4FB91FBD06B99BD3772BF71593FA1 +:10498000E5FC7955959F3FCBEDB9B1E823C7EDB86C +:104990002C3F276FC07D927346F9B60BECBA26B058 +:1049A00037D93961913FDDEFA75431BFDD7D4A0929 +:1049B000B63F4A8CF9E7A14BE6B7C5DDF8B6F1532F +:1049C000DF39CB295562C5739613BD3F695B24A6B9 +:1049D00080DE7E28127B09D6E9646710E9EC445931 +:1049E000FCE130353F818F4A7DB3F1BCEA91BE6076 +:1049F0000CBECB6D9A19F3DA7BA5DE99E3DE97F650 +:104A00004BD8E7A7F8BAAB8AED477CBDCA40386CF3 +:104A10008928C01FF6A65D3BBDFB4BF62681E14908 +:104A2000222B80AF7FD9B944F6EEE7B8F9916EB981 +:104A3000FCFBD13CEDE1E9EC7E528E1F7E2E7EF533 +:104A4000224E48C4B812ECEB5BF97DDB1B9F7FE480 +:104A5000A547283E365E16D4C1BFBFEAECDE97BE3E +:104A60005F0BE7FED4148B97E75F8273D56BDB2374 +:104A700084E557A562C097EF9200E62DBF4B7E1AE2 +:104A80005BE0C1CBAE2A763E8CF4CA986FEBD07F48 +:104A9000404EFF715EF6E5DFDE32E82FAF23AB2636 +:104AA000C339B1753B645210200FDB9F8FDB57C5B4 +:104AB000F6456E21E91CF0ABBB4F70FB5FCF512078 +:104AC000CFE6D6057AA3386F148E4739DE7F4DE9DD +:104AD000D9F0EC67DDA6151488FBBCF9DC82EB2E5F +:104AE00027D04F213715FC846A52713F724DAF1F9A +:104AF000CEF3CDA31C6E37DF762C38A483828F7F54 +:104B0000DCE737ABFCF9CC13BEA796D359F93DB51A +:104B100013FDFE7FC1F797FCDBBFFFC518E3F7D499 +:104B2000A653B06FE2DE83A650F908FB1282C4F6EA +:104B30008F7AE2E7A94FD07A719CFAE4F8DFC37963 +:104B400075B8C7D20290F03E50A65F8F64D8FD0DB5 +:104B50005939F505DC5FFCB948C0AECA5693A3705D +:104B6000DF8B230806F89D96FEC52AA033EB67620B +:104B70006DA091B312B48FAEC47B0A4E56C9FCBC73 +:104B8000C53111FAB5FE455F06E776B3B21987BFA6 +:104B90000F2BDEC7FEDEC5927F3151CF5DA1B5CBB5 +:104BA000207FFEF6A905788FEE6DDA0A09CAEFF2CA +:104BB0007EDE7DE2D98504F63D9F8E9222CA8582F3 +:104BC00002F6D16DCF892827FEE49B51D46FB77DC3 +:104BD000EBF6FDD7D0F185BF8EB27369DFBAE57110 +:104BE00096E79D65F7977DE74BFFE0F079C13EDFE3 +:104BF000FF03B671FBEC0080000000001F8B080073 +:104C000000000000000BCD7D7D7C54C5D5F0DCFD9F +:104C1000BC9B6C929B905D36C926B9090403E56381 +:104C200083018346DD44A4A06817444DACD52550CC +:104C30000C1A31FA52491FB5B9F9209090842849CD +:104C4000E4332C282D8AD440D562ABED0691476B16 +:104C5000FBBED1C72A5A6B037EB78AD1AA585FAD73 +:104C6000EF3967E626776F12C1F6797EBF377F305E +:104C7000CC9DB97367CEF7397366B6A18E95F54EA4 +:104C8000658C6901DF15098CDDEC64D787DC8C3D10 +:104C900055CB58D4C9D8D7F877216317B94B6CC90D +:104CA000A98CDDB83779A6950D3FBFD106FDE1FD92 +:104CB00020948BA70E3FD7CB14C5C2D82CC6DE4F8D +:104CC000709445A05DDADB771DC3717AAFB63B25E2 +:104CD000A833C9F6167CCFA9D8F57E415608D379FA +:104CE000408AE441FBFB0F4854BFB177DA2E570EE0 +:104CF0007E7F97A302E6C9581DF5D7E77BD1DE92E8 +:104D0000C674E87791929C6B51A17C787FE2003C5D +:104D1000BFE9E1AF9ACE85E73759D9E0C20063B762 +:104D2000ECB51E774E676CAEDBCAA2F98CFEBEA650 +:104D30007F83899297B155F85F78FFA65FBC33EF08 +:104D40004FF0DE5F7D56E652A0EC7FCBF16BAC8777 +:104D5000DDD50CC739643F31200FBF7FCBDE371C58 +:104D6000B82E58EEA0FF3CC62EFCDC16DB6EEAFF28 +:104D700029FBD2C172E1796FF347D644281FF9E0CD +:104D800055862583F7F479C17AFF8AFF4963ACE63B +:104D900035D7D3470CF39DA324A4BE1D0FFF39873D +:104DA0009DF3B515C7FBFD6C1C8FED1D078D23F121 +:104DB00070AA567EFA881DDFD618F3C0FAF67FDA9D +:104DC000A34D03F81EFC5B8F06F0ACFAE7DF7BEE29 +:104DD00080F9B3DFB8943DB0FE5B1E7CABE73F606B +:104DE000BD1F1C725A64A89F7CF2673FDD0AF593D1 +:104DF000AF9C355382FA158A44F03F79E01F5E1567 +:104E0000C659FDE4C5E319E077F5A3178D67EE9168 +:104E1000DFD7CB93405711035D418DC6510FC17849 +:104E2000E3A1FA84284DF878FFC0298705BEFF99D1 +:104E3000C406AD05F0BCF72B8705E67B34C8061128 +:104E40003E4F3DF2C6D1FF80FA07801FE728F88168 +:104E50007567587C5846331894AB1EB9E27BE71748 +:104E600062690FA8881F36D8A4B847C1EB8B80D7DA +:104E7000C261BC8E89C787008FD3119F80C7E92389 +:104E8000F1F801FE67CE483CDE36028F553BB76233 +:104E9000E323E308EF63E1F1E647AF4C0A9F06CE58 +:104EA000D1338073A5C4E775A112AC573C480FF10C +:104EB0009A8FF0EC8C2C84B6936BFF9EC5803EDEFF +:104EC000B50F5E8770187CD2A9EC86E74B9F7CD922 +:104ED0001184EF9F7CF47907E21FFE12A5D9506779 +:104EE000437F2F30A8AF9278E596FB13A24EA0EF38 +:104EF00055777E3EEFD542C49B3C4878882C9AAFCC +:104F000026E2F43CB4DE5511CE0FAB227D4BA4E972 +:104F100023E1FD38CA134F2C3EA522C4E3F17948A2 +:104F20007763E1515FB782EB3E07DAB5B762F87598 +:104F300024BD0C3A42D370BC56C2EBC95DA78EAEFD +:104F400083FED15F3B14CBB950B70F3A50DE6807F0 +:104F5000ACCA9EC0487C33EBB5494B51AEB27A82A5 +:104F6000BB193F663AF805D2C17786E900DF47FCF6 +:104F7000EA70391D3F9F7E3DDF0E5EF7296A0CBD4A +:104F8000E870AB5BEB2479FC7A813382F2FBB85D8D +:104F9000BD770D7C77F0593BDB0DAF5C37F31DBB64 +:104FA0009A3072BE7F017A540DF4787D8DD4341E10 +:104FB000DEBB5EE3FA44A74FBD3D7CA795A906F88A +:104FC000AC720EBE2EC177D96F5D6C0F7CD7FA1B09 +:104FD0009784F3B8A5C71E7102BC6F8963515CFF4B +:104FE0003B3B5C110DEAF7FEA2F63A94671FF638D8 +:104FF000197C96DDD0F34B82CF0AC6AA19C88FA7B9 +:105000001E5DF319CAF3933BADA07BA03DBE97F89C +:10501000FC86654A754332BCF7F8D73FC5FE2B1FA7 +:105020008A472505FD6FB84E82FAC96D4E09BF77D4 +:10503000F2B72FD3F8277F9B10C039FEEDB15F4E3A +:105040006706FD77C366BB3A6098FF4A665387E000 +:105050008BF461AC03006EEA6DEB47BABF099FF3B6 +:10506000F7A4AF05EF201FDD84E504280F25055DBB +:10507000D363FAD178B738076F0FB809CFE9962212 +:10508000C2733AE2FBA6BDB1F3F887D0C7B73806C2 +:1050900057F0FE1DE99C2EFAE93D47B2C4E949B438 +:1050A0009BDFD7FBDB927363FAE9EFAF72B2EADE04 +:1050B00051E452B218F7A6BD5F9D153B9E269E9BFC +:1050C000BFC39FFF48621ACA7976C015D903EBACFB +:1050D000724427A54CA5E721B45BF47ABAF82ED622 +:1050E00093A1FE6B3BD835588FE3F5C71CAC92FA01 +:1050F00027421DE72B0F9C44FCDEFC4B176B817194 +:105100006F7EECE5CFFE04F5F711E680D1F73DFDAB +:105110009FDD01F4F0FE0E2BD314B433A259DB5003 +:10512000FE1D70B2DDD0E57D7B342BC580EF9B9FEB +:10513000701D47393154EF05AA9347AEA7A1B6AC0D +:10514000FBCD3CC61A6BC3545A59F5CE015C9F6621 +:10515000637BA0B4B1EA9FF1FA7805EB5A29B4A3B6 +:105160009C71C84A03CCEBDE78209242941F09C49C +:105170007F572427133E81AC67A0BC5A5B3B7FD38B +:105180009B2817648D295E1C8F91FEB431DBDB08F0 +:10519000DF2F04BDE8F374D8C34A00D6E14078029B +:1051A0005CECB6F0FA1C18DFEE4B2D8019B326DF4D +:1051B000E220D27DEB54A500F9745132A71F278C51 +:1051C0008FF4C88E7432FCAEECB77D6C941FAEE5E4 +:1051D000CF319247A09F3782FC62130DED403AEE2B +:1051E000A95037E0DB910AF38EC1BF5B217928F823 +:1051F000E3D752C0F719C2A1CEA9EC81B29C75D8F1 +:10520000717C66CDFF6823ACE3DE655F4F1A807565 +:1052100094DB3AED41D4D7174DFD6863F6F03ACBF5 +:105220009F58D72F256299B60CF573B97BD25B587E +:1052300002B2E538E8FF94C47A5BA09C2BFF7DDBCB +:105240009B67435DD0CF11AC8F1B1EE7889DDBCBE6 +:105250000D8CCD3F80DF933BECB71AE86DC613A1F0 +:105260002B2E8379FDA0328FE4DAD4DED0A5D3A033 +:105270007E6DE5849956C0C31AC10747ECBD9E29CF +:10528000885FF82EAEE73A366847788699E220B80C +:105290000A7958C102A2CE089E7FAAB2EF467A359B +:1052A000BF7F6D3472E565D0E507472297A13ABE0E +:1052B000EE99C1A791CCC3BDCABC786618EF50E087 +:1052C000683C1B391EC077F3C068F09554826FC0EC +:1052D000265B357CFEC3BC5D2DD248FE2E4F387652 +:1052E0000DDAAFE509938E6039965DA2CFC38C8F3E +:1052F0004FB009E8A42E39B82919E0134E0E7626CE +:1053000043BF2A7930CB06F4F24725BC199FAFB2D0 +:1053100086B3BD008F0F32C36779102EFDA3DBBBB0 +:10532000C3DFD3747BC11285F5BCB2DC1EC1F9D7D3 +:10533000C75FB019F9EC588353B1C2BAFE8E5D60F5 +:105340009C6B582FE1E195C4EE4C5C7F293096347C +:1053500087E4DE0FA20867961868013EFC011BB0C7 +:1053600003F3B2EB8174B15CCA542A97B120E1EB2C +:10537000872CDA847A03E6FD30AE439F37F3F76774 +:1053800021BFB0DF8F6EDF99E7FD666DC736E4673A +:10539000FDF927C9E15FE178CB81B12F9809DFE9F9 +:1053A000B87B9B916FF47E0D824E991C9CBD08FDCD +:1053B000257546891BF4C866210F8E5DC8ED285FF0 +:1053C000543E8E7696791C169E1B1CE24FF42B22BF +:1053D00016E60679E213A4A3BF67EEA77FDF577333 +:1053E000117BE36C9C6FF00F8837F3BCCCEB3D96E0 +:1053F000CCE75381EF19F8AD22AC3A54E85FF16580 +:105400005210DF3B7621F7137F0F628FCBBDE05147 +:105410009487156156DD528068BA3788EBD4E76906 +:105420005E5745E73AA915E93A2807F2947F7D9D32 +:10543000EF25DB383F89F9B2DEA325F2ECD3BFC7F5 +:1054400082767626FD8E5DC8D71700B0E0FAD83593 +:1054500071A4FF2A6A1AE87BCD200F91DECC703C44 +:10546000E150A7A3BEEC9EE4CDA987FE203DC20873 +:10547000B71371EA749BF1798A785EAF4E47F9DE13 +:105480005C9E4ECFF5719A252ECF747EEDB6B0CAD4 +:105490008358B7057C8B817E979F9CDA5303F30A70 +:1054A0003624AA2C0BEAF81D6C4FD54EFC1CC65BAB +:1054B000EE65B92D00DF1A1B23BC41CF498B810E4D +:1054C0003FA8DDBB1DE97979CB7727A1BD74B30275 +:1054D000EDF05ECDFAEF4EAA307C4F9FC7AFEF499B +:1054E0002B453951C378BF13F2539B513E57B89E99 +:1054F000DB6C94CB2712385D9DFAF377BD53889F00 +:105500009503C8D77AFB7752387D2D1776C3AF4BFA +:1055100079BCE2BD5A65CBDC3C5C5770520BCCFBCE +:1055200044DDB45CD403CB5BD695A27D7F42520FA1 +:10553000B880DFF3EF3FF01DC4835B01C717F8F6B7 +:10554000C49E0DBC7D969A6309603F5686F0C9BF24 +:10555000FFF960F274A3DCE9A0F5340CC1933F9726 +:10556000A1447F9615B3C01E285A267787EBE1FB2E +:10557000EBCA1D05A82712855F164CE1FAD635DD6A +:1055800042F06D063C60D92DF1F59E9762A5F1F4CD +:105590007EC114EE97BB26C936C4B7C7CF2256C00A +:1055A000EB17F6703005FAD95990F4B6674998A10F +:1055B0007FD1EC0091877670B943AD87573749FDAD +:1055C000F568D76A7F8C63E8D78CCBEEAFFF21B448 +:1055D0007F0876503DD44B9A7CE968877B0F39036E +:1055E000687F5C979243DFAF8C3C7F18DF9B04D2CF +:1055F000C50AFD56DE7FBCC70EF5B3F63A02B81EEB +:1056000017F0543FD1CF6022FA1D93E54A5708E8BE +:10561000E1C3B2D2A46F8A173066619ACE17E4282C +:10562000C4314D36D6534CF57453FFDC98F68CD408 +:105630007E09E5BA0DFA34007C7DB6DE3E5CBFEF34 +:105640005AA6A0DDBFBFBEB704DB233732B6BB000E +:10565000857B94EAB2CC943AC07B268376A4831AE5 +:10566000A668F0FE7D96DEF9C887B7221C00EE8A98 +:105670006DF0D9C61CE4EF43F41EF0794A43817102 +:10568000FD038948F793E5CF13510F9C7CE26C052D +:10569000D79FEA0CAEC4FE279F74AAC887350CF0CA +:1056A00080F411E278E8B2470F63BDFB4927AB07EE +:1056B000BEEA7208BC2C70115E5A902F801FE290D7 +:1056C0002F803F3C8E7EEA7FB244A6FED30EFD675C +:1056D000A90CE31758E45E9C54F7A351AA0F1C7061 +:1056E000AA0032A0A7C8E60AD4FF398E00C67FD62A +:1056F00027C4CAE9F6146EB7B4A7E8FE7755793C1B +:10570000F4AFD29C0CF925B8BAAF09E703566F3550 +:10571000F23DD05B7BCAAC617AABEA5D4AF4362ECF +:105720004BC8B35F4924CF9E1AB00671DDDD87A454 +:10573000FBD0AF5AF3DA52D705D02E3F6145B0B255 +:10574000556CA02903FBAB6E9AD7FECC400EC9B7AF +:1057500043CE14A4D724D66F213B4561CA1EC0DFB7 +:1057600034D64170F796717C4D2BE6F8DAB384910C +:10577000BE052C1CDE01F5BDE5F10AEAF14705FD89 +:105780008265DF9E07CFF71559580BD44E3EBEE613 +:105790002F77C138EB7F23911D77CA1EA571BC40BE +:1057A00007F580CF92B2EA6806B4AFD2929813E3BD +:1057B00048FEEA6CE48BA432D0AE39543294ABABE1 +:1057C0001E8A8BA01DC08A52E9FB730F49D10B11B1 +:1057D0006F6D0EF25B3F2C60D10B91EF9BE3C86FB6 +:1057E0005DF7D5A02F3475586E4C2C76442D89B8B2 +:1057F0006E2D09E11279DE1A403F3BC3C6E7630113 +:1058000083B10EE9B06EEA8D156C185F5DB587B691 +:1058100037A25C63A13494D743CFEDA172F46F0E2D +:10582000DF53B52015E6D3E5822EE702DD6CBAB76B +:10583000599B8A7401F34E8252D8B32C3FEC5A64C0 +:10584000F0E79F13F245AF77BB44BF896117D935A5 +:105850002CEC42397FCA5EFD97BBD03F3F2405EA5E +:1058600061BE13AE7921175899953CB1541AA078AE +:10587000836401E431EF131F31E48753C96109E305 +:10588000B84965030EE487B98796A60D18E8AFBB43 +:10589000EDDD2C7CFE558ACAE38E024E3A7C363909 +:1058A000FA2D284FB5C7409E021CBB2F7BF5C4FDC7 +:1058B000A84D84BE194C117E922D9C86EBD9E41024 +:1058C0007254CC5F157AE8C3143BD1C3DF049DBF8B +:1058D00027D60BF4FC1ECACFE05410DC48E73E1676 +:1058E00041BBD9BE70BE36A0E2F80AA723399C8618 +:1058F0007080FE1FF2FE81F7EE4FA5FE01A42BBDC6 +:105900003FC0290DE55F77F9EDD7E378137E23A932 +:105910005609E1732BD19D17E0069CF92FC3C90CE2 +:105920009F894BDA9D5930EEA7657C1ED31EFBDCA8 +:10593000375AFCB0F2732B8B9E6DA80BB8940E3CBB +:105940009F9B8574BB3F7D26CEEBC3E34BD324F4F2 +:1059500077C671384D471BC8437828A5F8FDE5C0C8 +:1059600073688FB903B946FAC918C7E1A9C31F2CD8 +:1059700091DC2BA719DB39FC37C589F6FC31DE4FEA +:10598000E4FE3C9B686EE77AF0D49FD7105CBDC5FF +:10599000A08F7270FDFF6CB243FD53E057D4F32526 +:1059A000C51C2FAB1E9109CEAB86E03BE040F8EA68 +:1059B00070483AF491039FCF7D02E08CCF95F02B95 +:1059C000EB511E1D7232944727BFD29C08978DC0A1 +:1059D0005548E73503258797C1B8FB2C6AC8AA0C40 +:1059E000C3A774E0231FE2696379EF141C6F9DD095 +:1059F000DF7E5BB40EE595455693515E558838467B +:105A000033ACA97F2AD925A41F2F17EBCADBBC7A98 +:105A10003ECAE90F598282EB58077212D7F9F14357 +:105A20005204E54EF3571DC7501EAD3B9F911E49D2 +:105A30008A3ED0514A72C81A70C1FCD6DD1538DED4 +:105A400088FA7D7F3CC9D3482D23A1AD61A400E92C +:105A50003422917FB44A1B9827C3386A63F86CD408 +:105A6000DFCE898F1D45B909425C015A66391ACCCF +:105A7000C7605757B17EF27B1E9A1EBE6C1CACF7F6 +:105A800046D641FED0BB977D1995E0FD2A411F4DBA +:105A90007957D52FC0F93F6EA5F8C5878F6FA2F94A +:105AA0007E582CE46674CBB124984792DFA1BA0CDF +:105AB000F6E8874F4C480A8FE237E8A5BE8E757727 +:105AC000717976EDB8879FD5006ED78F53086E49F0 +:105AD0001A2BC57875522394245FAB7DC87FCC56B2 +:105AE000ED5B6CA01F1D2FC142F5D000F1AD5280BF +:105AF000FCD29C37E9B16350B72B0AD9672B053E1E +:105B0000BEB007578EC37DAB5A36D808A4FBD75A10 +:105B10007910E5EEBBB50AD5753A07B53B8FE24D76 +:105B2000558A84FB1737D958A313FCB73B4CFCA00C +:105B3000F7ABAA0CD945BF25CE14EC17CB177ABF0B +:105B40001BAB87C63BC2FBF179E9FAE6E65E69B0BA +:105B5000D11097B969AF6BB0D118978C24C7D4878F +:105B6000EC56F1FE69FD6A9083189F74F121308E26 +:105B700044EFFD7C5AB81DE1E22CEB77A0DA5DD54D +:105B80002995A22B73B1756112F2819371BFC03C4C +:105B9000EEA65A9921DC9A019F58466A152ADFAD74 +:105BA000F531846B67AD4AE5CFC6717B24C7C2FD72 +:105BB0008E5DC2BE8E08FCF508BED34BBD3F62DCD5 +:105BC00001F46603BBB885E2ABC1E07AC42BDA2DE1 +:105BD000A0176D8D4D1487B5690E8AE7811CFF19DA +:105BE000AEC3A6707B19FA33A21B067218CAF39CC7 +:105BF000E17DD8EE5D286BD8DF5B36E8C07EED0234 +:105C00009F27851ED5D7F70B318F5F8879CD10FA86 +:105C10008CF952C9DE77FA358674AED7415F658557 +:105C20004689A71BE03F80FB2EC85EE8D71BE0FF3C +:105C30001B9CD7CD1DC7E7A5C1F3710BC154988A32 +:105C4000F07793BCF8A48C11FF8D855F331EBC0BDD +:105C50005907AE2F521B669CBE2BE979676D35D56F +:105C6000CF73869E23389C66FDFD62FD7FD4F17163 +:105C700086EB9C91127A79DC2C5EC77E712C54875E +:105C8000F2252E74555F23AC2747B555B322AC8758 +:105C90004A503E2E0FCAD568E77A964418FA215525 +:105CA0009D1243BF242E149E87F129F7F4F0099426 +:105CB0005371F98384D7A4E25E8711EEA7A7FB3363 +:105CC000EB77A256A578EC501CB7DEC61A0A31AEA7 +:105CD00093BF09E3BFF7C6FF84E2BD359A5371A6AF +:105CE000925CA278F00A9B4CF6E9398EF0299CE789 +:105CF0009A4D0B358C199CBAE7DC2896777B42FFCE +:105D0000C0E7BBD63665E1BC2B92D4CFD0AE63DA08 +:105D1000F44B7EEF233D42729069D22528F72AE2A8 +:105D200079BD25F5D616B4F32AC6ABB74BD0FF8A9A +:105D300054C72568075664F3F61B44FBA171415B09 +:105D40002AF18B3DF96D99912D3EDA3A87D76B6335 +:105D50006F1BFCAEF752994E9F1AF30ECB07A0CBE8 +:105D6000641C57A74BD744135D1633B28BC7FA4E4A +:105D700017D2631ED2A54C65D212A04BB4FF849CEF +:105D8000003AF4E3F849C5DF4C8739A99CFE26A404 +:105D900072F97B69AAB0DF041DBA845C317F7F8A07 +:105DA000E8AFC747CCFADB6B05FD0DEBE9BBE6C1FD +:105DB0006BD0CE77EE9D948BEB793033928EF18D54 +:105DC000542BD7EF0FFEE3BEF4C5582E7A30BD0238 +:105DD000FAC789EFB5D8411F417DAAFFB3EB54E064 +:105DE000B7A91359248FCA686E0EAC3355F4EBB4BF +:105DF00007D2B0DFB485DE65B87F7AA9584F0DAB06 +:105E00002E43BF8C815F86FB0766BF50D76F2D93F3 +:105E1000BBC9FE6B4E88858B3ECEA5A9BA9FF750B5 +:105E2000593CFACBE8E7A5A29F57A255C4FA799747 +:105E3000A6023C1C4A085D75837CFCF7E866FDB849 +:105E4000D0959CFEB89CFD6F18EFFA548E5F89FBCD +:105E500029FFDE78EF26E8FE3CB7CFA639789C8094 +:105E600095821F8A766F80FB9DF78153D6921C2303 +:105E700057C92EE8427B81E858A1F28E54EE9FC0AC +:105E800010471C33713C1E9F837A27D6F5F7EF48E5 +:105E9000E5F1CF697143ED36D4FBC3ED1C6FDE2510 +:105EA0002C46AFA72E9463EA7E996932BC1737510E +:105EB00089B10FFE5DB8ACC117F1FF1732F2EF4F99 +:105EC000E5723F705DE6A4024D1D7E1FF4E63DC401 +:105ED000A77E07E94D9D5F753E05B83AD2E0BDB794 +:105EE000E13DB4BF1C1DB7929DB871B29283FCF422 +:105EF0006A2AB773E2A2E5644FC64DB4445C40BA67 +:105F00001BF33E96111F1B8B73C95ED4FD69F3FC16 +:105F1000757B7123DA8BE98CED4E5DFC3B947B7BCA +:105F2000841C88D306836827C63542497AFFDBD9AB +:105F30008BCB3B7262ECC587055EC05E7C18D79D3B +:105F4000B7F97E19D7B751D8F12DC5A5AFA3FCFF7E +:105F50007822B7835DD105AF2741FBB8626E078F0A +:105F60005BD8C1C2D368BEF4BD4D4376FB20F19B24 +:105F70000BDAD1BF19170A4FC0FC27B0C37F8BDFE4 +:105F800079F3EE53C4E7A90B63EDF5374DF43B16F7 +:105F90009E9B853D3BB4DEC960EDCD40F901D43D0B +:105FA00003EB9FF9D828F0DD3419B431F8AD1B2F7D +:105FB000EBA6F666BB194EEACC5838A9B43FF6A258 +:105FC000903F00A71739FF1BE898E279F230BD52E5 +:105FD0005D31D5FF4D7DF52FBE9FC4C29A0FA6BE81 +:105FE000ACF5A328FAEF281FD1DE903BEE0EA2FD00 +:105FF0000BF43E8872326EF3019293667A77647383 +:10600000BDA18FEFF4707A717A86EC56A67A29BE1C +:106010004A761EFEB542FD2CFC4F2ED1A705FDFB96 +:10602000FC233243B93C193732605EDF61510BFA11 +:1060300065D3D800D567E0D2A05E006E31D6CF66BA +:1060400083590E2BEE4F459B90EEFEA884ED1EF873 +:10605000DE675BFA5F97E0F9EDE9E15F0DC073D9A8 +:10606000C3F9C2CD029417A3600934B44C7613FF70 +:10607000B256FBFBC6FDDD976C41B787EC35BFF22E +:1060800076BC113FDAD07A709FC6CEF4BF88D8CFE5 +:10609000011A31EC5BDB079297A1BD760FDA514014 +:1060A0008713F7723BA1E13589E22F9D6847917D07 +:1060B000C5E8B9760D8B3420BF64058EAB88D397C5 +:1060C000ACE4A78340CEC1F8D0F8D7E2157C0FF836 +:1060D000F89C2B0C7CDC00FC140560A6CC0F92FD18 +:1060E0007D2A81DBBB7A3BD86193112E5262511815 +:1060F000BFB3E684A4A2FD3C6E6180ECC79419EAAC +:106100004716B2BFB65DF27BB04353CE520F60BDAF +:1061100061EDBD97CC073B31E51C2E672EF2ECF804 +:106120001DFAA5851E95CB995047D08EF3037315A4 +:10613000E1AAD7D17C45F8AE9F199C85DFBD48C048 +:10614000BF29FDC6349C9FF97D4DF44FB97461148D +:10615000EDE1B582FE8265FCB9997EEDA9DC9F0177 +:10616000FD7D9187FC9B10D5AD6EBE7E4C9311FEDC +:10617000CD77F1FBCED79C8467A73F966ECDE32EFB +:1061800012749BE4092EC4713F5C3A703BD219D063 +:106190005508C7A992C3D91274F900FC2A1B3C7F89 +:1061A000CE165C84CF815E167B3C63D3CB10DFC9F7 +:1061B0006EDA3F5B364437331D187F59FE65124354 +:1061C0007B791973305546FF80893C9BE0D1270BC2 +:1061D000A97F08F962D96B0B8EFE19E8E2F50C2B4A +:1061E000C33C28BD3F13FD35169C87F6CEB2854EC5 +:1061F000E2A3E5AFCD69C27D5F25D7562DA1E1DDD4 +:10620000E11CCE4BCA8D793F265F87E69733727CBF +:1062100066AC5B47AB73FE323F5F26276AF1D3471C +:106220001B0FE60CFCB25CF08BFEFE09A9770ADAC4 +:10623000F76BBBA297AC8779EF4BE94F97A1BEAE46 +:10624000EB484B633163FBEB383D42FD12CD8F755C +:10625000F53AD493CB6DEC88DD606FB47BB8BDDBD1 +:10626000EEE1711468D7B0BD45D023C6BAFC505FCB +:106270008E25D8136F3C54FABFA7A863CBCD651DFC +:106280005F3BD5D1E20D41A6A6CEA6542BBE8EA370 +:1062900001CD69453910A2FD0307D0239632C6C54A +:1062A00027207E7BA974B37E2A13410F62A9304553 +:1062B000C2328505A84C65212ABDAC9A4A1FEBA0C5 +:1062C000329DF552E967FD5466B1412A55CCA033A1 +:1062D000E45FE4E20E2CD427B21095FB73B81F776D +:1062E000A2CE063603F975E4BF69F54EA52195FCEB +:1062F000396AAF01FF0DF350FFE0C9D5F3739EBFBC +:1063000018DAD7FC97B5A085F0C4F375CCF0B1CA04 +:1063100013B6371AE2AF0D0FC89437ADE3477FFECF +:1063200007A117FE20F86D7F5DE05818E7F5801C87 +:10633000C0FCA47D293C3E3ADC9FF77B4EBC377104 +:10634000C905AFA39DF6A996A8A2FD3116BEC68EBB +:10635000071764A1BE3981F160F8DE89E32559127F +:106360007CEFCDB65F4EC1B830D8170EDC4778F35E +:10637000EE9773499E441DCCE635E0F7F2000B2200 +:106380009C55D0B7F942DF669CB9BEBDDB133C8695 +:10639000F2E5999F83E704EBBEAD4D22BF91D90290 +:1063A0004D98E75121FC13B35EBAD213FC0BBEA784 +:1063B000C38729C1D2B770DFE7A50931792D1F78CE +:1063C000B87DB93F575D8570D7E1005653C50618B3 +:1063D000FF8DB6B3088FA783C71B7773785CE90975 +:1063E0000F923EB4A9C49FCFFC7CCA788C279F6EC5 +:1063F0001EFFD4F1FBDF340F6407949FBABCD8773B +:1064000041200BE3DDCB5B9D3C0FA1E3E2A0115EDD +:10641000CB3BEE6535293CDFC49E32B29DB1CC64E6 +:1064200094D7BABD34B4BF2DF6AF5133E17A3F51A2 +:1064300077A31A47F9E41B8DEEEF157666A3F08B70 +:106440009A96B28851FFAEAD68790FED7F979FA9FC +:1064500067A17D2CF20A9CD12D1725A23F9ACF0A65 +:1064600030C6E092F9F373DF8DB0A506FA8FF347DB +:10647000C89ED7F31786F84BF8F14D99B1FB9DE70D +:1064800078399F14781D4407BE864035C2C9A604DA +:106490005885A19F8D954EF6423F9FB580DAEDA9B4 +:1064A00023DAA779F17DE1F78FBF36C056BA8DEDBB +:1064B0000B0ABCDCEEF95676EE7AB7262BF09DF58A +:1064C000AA733ED18F5A18138F4AF05A62F5A6C0AC +:1064D0000BC037407987224E0808257C342787195E +:1064E000E6793B7C81323C17D09037DBE736CCB382 +:1064F0002159E4137D79B66F89D16EFAEAEC6361B4 +:10650000947F790ECA63389A302FE9849BE319FD92 +:10651000A45BBCB1FB852DB54A80F05B2B078C7E5C +:10652000C5109EA73CF82EE259F6713CCBB6FE5240 +:10653000D4C7E0BBD0F88EE87BF5587720BE55DA9B +:10654000970FF2BC3B13BE7D11EEB78D81EFE6BE17 +:106550001FF797E038EEDC992E92C7614DE27EC9B5 +:1065600041E4A71BC5BC6DBEEA2882D6169407D1AC +:106570009E733298B731CF9BC17A0C7869B677F8A1 +:10658000309FBAF92BEBA8F6518997CB153B18D061 +:106590006F1AFCEE8F678457231D391ED134B4E780 +:1065A000ED8782513283DC671667EC740465CCDBBF +:1065B000EC5AEB20F9DFA8042E4928C4B8B81AD148 +:1065C0006088BED613F3B1DEB63E3E807EE67E69BD +:1065D00060FE04C45B818DECE338410FBB0A8E90F2 +:1065E000FFBC3BDDC5F3483A9C0BF0BDAD4CEEC79C +:1065F0007DFED6E089729CD24E002CCADD9D958727 +:10660000958B709C6216C0EDE6BB5964F30D06F9DC +:10661000D5906EA5715A3F7F23ED69EC57ED6088E8 +:10662000C7C3B7BE9DF634BCBFE1C70E07CAA90DEC +:106630008F87B3919ED3FCBC7FCFAEA30B12B0BFAC +:1066400024F7E3BE3CFD417DC7CAD09E969CE1BACB +:106650003A7531D5D7F96C3C5FF8D68F9F3D0B9ECC +:106660002B556800107CAC3CBF592FA3B2B16E868D +:10667000E704911F647EFE7F33383D785B97B8D086 +:106680007FDBD05A6841BF76823640FB8689D5963B +:1066900060C48DE5E20538AFC425A53609E6951836 +:1066A0000C586CF0FCD75EBE7F33A17AB105E19B3C +:1066B00027FA9BBF33D4AF35B400E19BB8C442BCCA +:1066C0003A01C6A1EF9DE6FD5F78391CBA1823B9DF +:1066D000B0C3CEEA312EB0A34E913436DCEF39216F +:1066E000DF76C2F851E2935E34A6D8F6A13AA3EF62 +:1066F000B4FCE8A77D986FD1B292EB8B242DB460E7 +:1067000022EECFCDB5503DB1285286F3DC90EF603C +:10671000B8CFBA43626427F5FCD87129C26142112F +:106720005368FE452C8876CC8E1F5D351EE960428D +:1067300067471AFAFBFA7CAC3E99E7973C0D86193D +:10674000D80D79456F337594F525160E30E42F7DFD +:106750003C73FB4B024FE977DEC37E8C78E864B470 +:106760002F0A25F5EFB10FA4790DE3CEF0F1FCA9C6 +:106770009E5DFC7C9A79BCED021FE99503C22F62F5 +:10678000B46F8FC9D014AFBFC341712E904F9427FF +:10679000DD33AB89F6953A445C08F4B46FD134E448 +:1067A0000BC007D247D1806CD40FFF1CCFE7BBAE24 +:1067B000C8323F42F15F80278CB3BD2D988AF92003 +:1067C00096D670DD9B6EECC7E7B1BD3C908E7470C1 +:1067D0005F726F1AF2CBB61FBF9D8678EA99F59269 +:1067E0000FCBB60477198EB3AE6866F5328CBBB9A1 +:1067F000AB10D386EFF1F5A65A22E912D847E3EEA3 +:10680000ADDB80FE402AA8398CFF1FDAD6BC01E33D +:10681000607783191C257DD9EBC2710FCF5D7C7623 +:1068200000E775A783FCDE9D52DFB393D0DF2EB760 +:10683000D079B1BBC37A3C094C7378AFBBE8849C78 +:106840000FFDF7CCE7749272F1E292C9D03F455246 +:106850003E06239D5D9755316E3CEE67762E2E41A8 +:106860007ADA14F47D8CFB179E255189E70132B248 +:1068700017C9255411DE2109F50226CC537CB53801 +:106880005487FEFC1E89D5607CB5C01A7895E28ECF +:1068900057CB8CF081B61FB6976B1427E8B0874BA7 +:1068A000D057B94F62D5982FD5FAF9B23ECC0FD454 +:1068B00040AEEFC1BE6018AD45B9F66922F99150FE +:1068C000A7FE3B4AE46A51EFAB847ADB5B6E6A4F0A +:1068D0002A0E49E877F680DF89FBFC9E32835F262B +:1068E000C413C637F4F993E155887E08FB2FCC53C7 +:1068F000F5765E457579299B6005B9EB29AA90EE7E +:10690000C3F9078B6E4F30C825CF8B2CB2020C27F2 +:106910004FC0727CD974A23B8A13315B682BCAC703 +:106920003D756D2E94CB8D82DFE179C94A94CB4FB2 +:106930009E45FE6BA7C81764B67ED2C78D3A5D8AA6 +:10694000FA703BAC17E5C49CB3687DFA7776FE0815 +:10695000D685EB5ECAF65A00EFA75EFF3EC165CF53 +:10696000A7EDB49FE679ADB9EF49F4A7ADAC0CFD46 +:1069700063331C9ECAE07A64CD5FDAFAD0EFDE980A +:1069800066A5F77C8F047E8006A1EF35D771320CA7 +:10699000C386F740FF5D9615BA72FC2C8C33AE901F +:1069A00090EF86D60D7F0184AB8DFFBFBD28E5C675 +:1069B000BD306ED792962294272D3E17D78716E0CA +:1069C00048D41FE7B2089E176A7B7440433F3E9845 +:1069D000037E3CEE8BB18120AEC31B768771BD89EF +:1069E0004B46E20FE98F9887EC5CE5D2A9D0BFFD5A +:1069F0001ACB4CF2DF047DB5FF4425FADA2F717D06 +:106A0000A4FD88C7BDE1CF42F162804914E6FB4393 +:106A10009C2FB042BF9FC3A3334ED8FDD06EF192DE +:106A2000BFC2CF53B028E5A32FEBCC4DC171333398 +:106A300045DE9232C0F127F00C539037CFA472FE9E +:106A400034CC23F071790E32534B4AC17C260B9D16 +:106A5000136AB730CA8FD31603CE92F9BC70DE1911 +:106A600055AA4AF9D2F807F35B21F1EF978B71DC55 +:106A700099E1A6FB0A498FA807159203D2A269C320 +:106A8000FD9318874B8175303899F3A5FA28F245A4 +:106A900095762BE233A9E8B13598B7DB137893E408 +:106AA00038EB74127C41CC685F031C2A5A9D31E795 +:106AB000BBD4CDB1F5A451E21C880FFDBBEECC4197 +:106AC0000DE1D42331F51EFC6E0D7C0FFD97E258CD +:106AD0003A32C75132EF74C47CC7AEC4D6BDCC5075 +:106AE00087EFF6087C01FF5E82FCE61676D0019106 +:106AF00097ADCDE4F27FCF5E9BD09B031223FE8A3D +:106B0000FACA04BC10FFB48585A2DED2AF91DEB014 +:106B1000B010C22B21D0742B9E7F98F2C08B519461 +:106B20002FADEF27903CD1F5872E07DC997C1E17FF +:106B3000FAB85DEF2EFC674C1CA5332178EB73444B +:106B40007FDCBE6AB0F76FC17DBA8647DD78529AA6 +:106B50003D981C49BF0DC6FB9B9FEB9B21FD94BF3D +:106B600044CF8B243A9992AC5A509E821CBFC68D5A +:106B7000FE9625B500D73B2DC8D2516F4F9BE897A5 +:106B80001A90FEC5B9C60D6C7001F6D3C01EC4FDC7 +:106B9000C69DD1D25B719C8E569682EBEDC87FACC0 +:106BA0001CDBDB996D26E647FE757C32D7F3450783 +:106BB000C91EECED7458906FDB6D1DD5F85EEF4487 +:106BC000206080E7E1AED9F515A84FE7502C9D95E0 +:106BD000160D6CC17DCDEE575C0CFDFC6E612F8EE9 +:106BE0006D17339BB0F7ACFC3CDC901DE8C4FA0891 +:106BF000BB62DA6186E70CB20303D15CF86E3AE857 +:106C000085EF2A68DDB312C4A71A04563B07E8AC27 +:106C10007250437DA862BED278288BF873B586D7B0 +:106C2000A75CBC3B65B4FD9021F9959F4AF9E3450B +:106C3000171F26BB3AC236BFC24689BF8067C7E36B +:106C40006EB5417E9E2B9FFB01DBE7EA7AB99FEC94 +:106C5000B576D0B39723DC575BD478C24B84DE8BF8 +:106C6000DCF94210FDE20D6F02A9C1F30DABEBC7D9 +:106C700085A70E8FC36C1DEA687EB8EE4F6CD042BC +:106C8000A5A3ADA3D6C7E9475F4FBA298FC72DEC9F +:106C9000B8B53EEEE7A895D16772611E594146C26C +:106CA000CAD5F18E8479E9198003DCFF49AC6264AE +:106CB000C7EE98EC25BBB9E5E20A07D24D5E31A3D9 +:106CC000BCE0A4E08A9F627DADB0D38042289EC024 +:106CD000AA2BBFFE7A367D9FC7FF2A03A5088F1F08 +:106CE000DD35F3F059F0BDF4D6DE0CA3DDF38E37BD +:106CF00091E633A172208AED6897E27C26DC795018 +:106D0000C6BA67AA85D4F4DDB64186FEC3DDC54C9C +:106D100041BE4914ED89530FC6E378C3E32834DF3D +:106D200009732D0ACE6FC29D1F331A07DE53D5910A +:106D300070CBF2C5D3FCDF011946EB10F3CF16F38D +:106D40004FBF53CCFFE6C061CC4FCA33CDFF2DFC03 +:106D50002EFA059D913E8761FE19ADBDDF3CFFA275 +:106D60008874138CFBB6787F36F2C02C941FB172F6 +:106D7000EF7471E97D29BABCD3F59BA9DD16D53036 +:106D80000EBA0F56D61140D28C95DF6BD27386F6B1 +:106D90007D305E4DF290E8354AFB1E9D09FD419421 +:106DA0000F5A09F8F9A097DC0F1D669792DFA77CB0 +:106DB0009C04734E78C8A2E1BD0D66B9F7F8782639 +:106DC000F41523FDDB55C522BB0D71785D5F301BCB +:106DD000D75319809EAD68CF99F4D1587A6B849EB1 +:106DE00012FA41665A14D7F5FF8B9EA2C399C00CC4 +:106DF0007BC67FEFF27A9457005BB40FEE1CAF7244 +:106E00003E545810ED04DD3E003E24B8A70B3F2A47 +:106E1000BD92D1B9EE44E037F4E374BA1BEFE3F16D +:106E2000AFF13E1EEF4FAC04E965413A56851EE9CD +:106E300095B9DD3220F23E407219EC5E4FD1413AF5 +:106E400027802B48F25373351AC189A23D51BEB633 +:106E5000642FDAC16067635E6962D58A2DA8678195 +:106E6000DD038EE29176D963259C0EBB96029E616E +:106E70009EF58FC5919C689FA3EC46BFA4AFDC41F3 +:106E8000ED6D9D12E5B7B5C9BCFFCE0E89F2EB33AF +:106E900031EE0FB06AB7737A692F57226013437DC2 +:106EA000802D721BEC618147147794B75E04F61F46 +:106EB000EAB1B085F29F191B6CC6F849FB6C7E5E87 +:106EC00000ECB37CB4CFF6EBE77C84DDA7DA04FDFD +:106ED000093BCF8F75C46FBAB053753B90F5CB5655 +:106EE000182FB318EC3EFCA6D22FA39CDC737E6E49 +:106EF00032DA818F0B798A7667D36C5C8718978535 +:106F0000D24306BBD02BEC42AFB00B5F17FADE2B9F +:106F1000F0EE1DB20BC392D12EF4225C883FD8CC88 +:106F20007BE650397F1AF4FF5FE9DC1ECCC0F767BF +:106F3000A2DC8EA3F775FE5A21E6D1E60F1F457835 +:106F4000A0097A90FCA55E1A3F2904321DED4C1B66 +:106F50001F3FA94AE176A7C6E957E73FFFEA58FA7B +:106F6000DE9F123E8A7CD305CEE06E18CF5B15DB28 +:106F7000DE5658310FFD9CC4F713E8BCD10A131F2D +:106F80005E9FCED7ADE33F7B3523FC67FBC16F42ED +:106F9000790914B81BE9D2D6FF0CFAED99D55E95A4 +:106FA000E24AD0DF321BF399F9BAF648D179E87793 +:106FB0006A4BDD740E0737326E80FA4AF82EFA0DEE +:106FC00095AC9AF29CAF494F1144DFBF1EBFB7A2E8 +:106FD00010E8C2407F7965F07DD46B7EDEEE596D9E +:106FE0006124A76CFD327EDFDB9942FD77C89C2EC1 +:106FF00013EFE4FD13FDA116C6F50ADB4DFB1B6282 +:107000003D550ACF5F954918B09562BE49FE8E2660 +:10701000CC77F48439DCF4F565687C7D7BFC1D0E4F +:10702000B433BB3F4850D10F6EF30B7ED2383FE9EB +:10703000E355324EF76D3E2E17F6686C97260DC35A +:10704000E706D1AED7753AA8ACAA3E8AF0F22D7306 +:1070500013CDAFD0343A17E4FB3041C5FCCC1DFE54 +:10706000D0EF50CE6F9FC3CF9BE9DFBB9171BED0F5 +:10707000EBA82651AEDC50BDA209FDD23BE07DB4A9 +:10708000DFDAD47E19E33FAC97CB6F984214E967FF +:10709000E55E678C9CB821125BF79AFC8BB6C21335 +:1070A00014CF794CF06BDFEB7104878D551D0FA069 +:1070B0007DB95101B8E1BACBBA27E3BAAF48978995 +:1070C0009EF6005EE97C18E007E37B912276C90416 +:1070D000E8E72FE4710EBF1FF089F882B50AFC7251 +:1070E000F8AF06F81BF4920EAF447FD8916FE41B03 +:1070F0005BF828EAF7ECB09FFCF73625DCF443F4A4 +:10710000BF81DEB400E77F84B757C74F61451FFAE0 +:107110001389806FF41BC82FF50AFCE0BEE76AAE46 +:10712000CF0E58F83CB49F3854D4DF7D2F70B9B9D6 +:10713000A3933D8072B2FEB1579B09CFE7D7937DF1 +:10714000BDB1F0A04B9D3A3C5F5D9FEDB1872C65D2 +:1071500000AF15DB63E159D21975E17ED6B6EA17A7 +:10716000285EB4A368308876898AAA07E6A4FA392B +:107170005D035C22022E0B505E241602DDABC8EFCD +:10718000A195B8BF95541422BFC3D7609318E98B5B +:10719000C128E7B74C15E1E12D8E950317A65B6278 +:1071A000F8DCAB71BEF1FA39FE3C450ED5C8376A42 +:1071B000243932069F3BF03C9C81CF89EE6E403EE5 +:1071C0005746F275613AF7C346CA17C1DF6516C163 +:1071D000AFE16646F245A1F7FC3A1CAA04BF09FEDE +:1071E000CFB83385EEA1D829C6C3B825E77FB18EC5 +:1071F0006258C728FC0E763CC9A73C9D5EFC1D4723 +:1072000071DE5D306FE27F33BFB26AA22FBC5C8655 +:10721000FA0BFEDE5E0CFC3D0AFF9BF9BBDBAFCD3B +:1072200073A1DF0270C273853BFD5C4EEFC03A7CF8 +:107230006FBBBFDA5109F56D285F94D3F377E5EAA8 +:10724000154757FC0FF0B7996E017F04477F9943AC +:107250001DDA3FD0EF55B1A03D1216F72C0CD23EEF +:107260004945238BE0BEF84685C5A19F19417EC0E4 +:10727000F86AD5C1A318F7CC44BA86F5660AF9E9CD +:10728000D174BA8E4A74DE5EF0A98EA79BAAB97D2E +:10729000795319B7FFB61556B8284EAA845D88FFF2 +:1072A000BC3B2DE4F7E6F9C3CFC6E0DB167659897F +:1072B0001EB87ED8E91F7C16FB77ADD6E91AF40319 +:1072C000D455A4AF1CA4AF8E26EC3F24FF19D003E5 +:1072D000D297D0576007CF47FB2A637D4600FD7ADF +:1072E0001DBF3ABE37CED78E3AA07D3BBC5F17C0DC +:1072F000382EC86BA86F033E22FA500DF8CC457E9D +:10730000DF4D7C938D49410AD27F64DE0D48DF4812 +:107310007FC437DC1F41786DE571245A5F6621D741 +:1073200047954557515CE50EABDC6F015896FCE57F +:10733000CBA093EC2C37DDCB7368E0E320D2730451 +:10734000C68B0FA05DFEA2ACCB25B4CF3287E6F191 +:107350004209CAE11E216F6E12F6B10DE9471A49C2 +:107360003F780919B6EBF465B6E3DB3A4F109C356C +:10737000A0973CB41BCB5E22BA8079BE68015DCC7D +:1073800056C7DAEF6D4516B26F7616F3FD8648F1F3 +:10739000E0535F13DF333AFFB93F657001AEAB6B6B +:1073A00015A3FB6394AA5E09E576561953B93D19F6 +:1073B0006BFF2FEF8CA5E7ACB27EDA0F53D1C12F54 +:1073C0001CE90FEC78ED57144FD8B83E3E80F0F52D +:1073D00099D6A3685CEEE445B85DDC57CCF5D8F6E9 +:1073E000303F07A27646299EDF5E6319CA2F647A72 +:1073F0009E00B49F25FCB71577D5275FCE28EEB049 +:1074000000E15DB1CBCE30EE60F677CDF6D8729369 +:10741000BF5261AA579AEAE6F903FF927F31C7F497 +:107420003CA1DF42F7F9259CC61F425BE4B0572C14 +:10743000CDC2EBB83E5231785FC71FE6266258A135 +:10744000F0F9B9DE30F703683F246FABFF32DC0F91 +:107450003920FC1FDD5E37AFD73C5FF37ABE2D3C91 +:107460003C18D800BDB6090F49A0DD2FF8D4284735 +:1074700087EC8009BC5E6FE087C77DFA7BFDEBD1AE +:10748000AF68BFC042798FBEA7176F95B8DF700D88 +:10749000EEE3666B36CAEBDFA3C703857CDE6118BB +:1074A00017BFB3538C7BB549EF8DAD6F410F22BD34 +:1074B0001672B9A5C3295BE37230BB88CB41B39F79 +:1074C000BB2D8DAFFB7C5C37DAD38A417F4D4038D2 +:1074D00086294F2B94AEC4C02553C065FC99C28B3E +:1074E000713F201B268372F04CD77FC21F6B6FF851 +:1074F0008BB9DEF7EBEBAFD2E5365F7F5221D7EBEE +:10750000BABD995DAC51BC37BB8ADB65E6F5AB62B1 +:10751000FD19B08CCDE052FCA7C06306FAEF29C379 +:107520007ED8FEBA50F96879ED8B849FD89910A562 +:10753000FD483D9E92F0D00B31F11437C65312C76F +:107540008EA7ACB10E909E60209731AEABE7F1B73D +:10755000CDE279FC43FB1DD3F8FE0AC39B570CFB1D +:10756000754A81A57902944F66F8683EF1E75CF5AB +:107570002CE62AE78040267BA18C9FBF33CFDFB368 +:10758000A49FE0E4A9B1AA6F1AF2CEBA562FAE4377 +:10759000787FAA3192476A876441BDC396B000CF15 +:1075A000EF0D494B0CF14C05981CEFF79C0F25CAC9 +:1075B000FF9AECF0AE74985C7C615CCCBD9F9E1A27 +:1075C000077DA74DC4E5F69770B806FA6C1AFADF86 +:1075D0006DF929BB70FFBAF40A37F783E67877A113 +:1075E000BC6C14791CBB1263CFE976C685B6523CDD +:1075F000FC5527DD53C78A22B2F1BC4096CF3588AF +:10760000F97DED738E9620FFE5315B00F933AF7A9B +:10761000F4FDECD7D2E5A1738B3C7E1DB48BB8B6DC +:10762000C518DFBE6F2AC87143BE54BCC863A03FF3 +:10763000D4C7C5CA2EA4C340DF9B3ECCBBE82A4EAC +:10764000C7F46EF68AE0E7A1731B33383E757CEF12 +:10765000E9E2F8F62C196418FFF085DDD5B4DF29CE +:10766000F09354DCCB703CAFC837CEB185084F1BCC +:10767000C1A040FC76151F0CA29FFE299ECF83F768 +:10768000D23B76D539BE016F3EC41B2CF962C41BB8 +:10769000CC37BE2C165F80C757108F3ADEF4F33C10 +:1076A0000F0B79D0D67A82F6CFDB8A1C4427017182 +:1076B000AFD9101CA62A945FD71B2D2DC0FD07CF74 +:1076C0000C2FA98A2F841FB1C6AAD0F975F67D4B5D +:1076D000CCF995F639B1E757E28B9AFA313FCDB341 +:1076E0006460747A2D5B4CF4A0CF6F649CDDB04E67 +:1076F0002B8E67A24B99E73924761CD7ACA3C00B1D +:10770000E0F045BA21AF6A888E03B6F948471D2FCD +:1077100046CA51BE316DCACCB80BA01EFCB80CE9EC +:10772000B29B4D9C89FC9726F224D65843D242E264 +:107730007336B887E3AF04DBF704E541F40F129624 +:1077400084EF5EA10EAF0FF35671DF3DBEC86141FD +:107750007AEAEABC8DEE2BF8B4C841BB89F1C5FCCE +:107760003C8F0E1F7D7E5EC18FDF15FC38820F655A +:107770009E3F9120E224091DCF07C758775AC6289B +:10778000EB8E7F91451C33409E4DEB9710EE99F99F +:107790002FD07E4E428D6554BEBA21C3C9E905DFA4 +:1077A0000327A14DC4CF76151452DE5492E47B9E7C +:1077B000CE6FB5723B6923D00DC6454B32747E1136 +:1077C00074728B25865F74F96896872CD0ABEF377F +:1077D000535EEA9872AE0AE8E61BF6B59204DDCC79 +:1077E0001F138EFD4437DF00BF920CCF48F8E9FB32 +:1077F000393D4F0FD0793F55DBEEC27B9D7A7E7CC1 +:10780000557D1CAEBF6E27F9218D5E59D00D0B5AE8 +:10781000894FD8A8EB4FEAD4E81C755291E338950C +:10782000854D74AF2B88C23E846342C446F17C7D93 +:10783000FD0985FC1C6E0EF8C368E7751572FED154 +:10784000D7A3CFD7BC2E5DCE5F27E485619DD7E35C +:107850003A59B1013EB9C3EBED799A91BDCC24B947 +:10786000DF0AFC91144875A17E7775BCB305E30D62 +:107870005BF31D018C4BB4063F263F6D67A585EC7D +:10788000C186ADF336D44DC4FD1085EC7DED467E4A +:10789000CF45AA2398264D189EA72AF8EB74F9BD68 +:1078A000FF91A1E719F3F847A229BF17E189F3482F +:1078B00014F9BD878FBFECFB09CA2391DFDB7EFC87 +:1078C0001D1FE6F7B6CD796C0A96EB2CBDBFC3FB46 +:1078D000AFB48336CA977CE6E771A4B76ECB8CDB76 +:1078E000653C57BB577CD75BB36F3BC2E344ADC627 +:1078F000DEC8C3F830FF8E99EE1ECAE071E07D430A +:10790000F1F1FECD87707E75D325B41F61C5AB78CC +:107910001C7E520ECA857DE2BECD132D7F624B7157 +:107920009F7216B3284923C76D9BC5647CAEC349BB +:10793000EFAFB7C37B36E37BD03F4E99616CBFAAF4 +:107940003C68D0734D7E3FC117D36DF01EB72489BC +:10795000F3DF5E1D1F1774B01F033C5AD22C118A2F +:107960003F863EE2E7592F92E95E3F561C7B0F5B54 +:1079700012E63F83BD9584F9CF3347B6B7FB0FBFFF +:10798000125511DF2ACFE3F2CD1CEC83B6A6A2DBA1 +:107990000237A84678F1F9B5CD99B41BE777C2AEA6 +:1079A000AEA0FC9159DE1C9C870EAFF6E6E737E3EC +:1079B000D1F281069830D0E5BD625C1D3E7ABB668F +:1079C0004DA776CFE7392C68B8076D9CD8EFF1CC7E +:1079D0005D4C79089ECF27527B5095245BE1F03DAA +:1079E000345FD8C3878D72C0BE2418C57D62DD0E9A +:1079F000D2F349B56E0BD191196F9F087876260E98 +:107A0000D10333E6D9EAEDF0E5F928277C558CE27D +:107A10007C5295D6F724B71742B8BF7EEAF50DB170 +:107A20007941655A08EFAB5924D661CE131AB25387 +:107A3000AE8E953BBA7EDE2F71BF469380FEE1F994 +:107A4000E6EAFA64BCBF7C4B74F1E4A7E1B5CF84ED +:107A50003DEA39AF7BD14A95EC510DEDF6FBCAF802 +:107A60007D3E23EDD190655439DDBA98CE7D7F8A75 +:107A7000B905D2D87ADA6CD72C10720AE4D3DF11A8 +:107A8000FE79CB47B747FF24F0F0FB0C712E5DE980 +:107A900067E25EA12F50FF0527D64968470DDD2B11 +:107AA000B43C48E7C0F4F786E0B48C8D6AC70CD9C3 +:107AB000EF5772387A99F600E6EDFA9E5A9C867076 +:107AC0003ADF2FE074EE0AD742467641DC68E7C819 +:107AD0003C4B3AA451E1D3F9EDE0A3DB07BADD97C3 +:107AE000168E2378E9700178F9FCB346DA7D3F15EC +:107AF000EBED59F404F92B3D20CF69FF84F5CB530E +:107B0000D1EF8ABCBD05E3515A2B0BE4217D17D67A +:107B1000A7DF88764661A8D0987F3AA17074FB7B76 +:107B20009D4FB7BF83227F442F87ECF151F3889597 +:107B300031F288EF12FB71CA1C9EE79998CFEDD401 +:107B4000C4A93C9FB7376AA1BCD9B6AA90C76AD06E +:107B500013D57E9ED79B51E3E079AC05B1E7EF7E6C +:107B6000E88FA3F68BFC5C4EFBFD9C6E30DFD5A846 +:107B70003F817E4AFDF03C98BAB4CE6EA49F30D0CF +:107B80000F1B86E710FD9C13CB67F7B5E9F41319BB +:107B9000CACF46FF30B1A89FF27C3CC077C8EF1D2A +:107BA000D117F2918E6EF4E7D378091BAF6AC6B392 +:107BB000AB3B7EE4481EEDDE29CF124DC2E73A1DF5 +:107BC00029C130D115E089E848A966945FECEF48F7 +:107BD000E6765721B7CF753BC15F1D92787EEE37B1 +:107BE000F39D32D29F581643573E71AF8B805F6F23 +:107BF000F40599EE072912F928732D14CF1BDAFF2B +:107C0000B6F7CA185F682D1A6046BB0DE07C0BC141 +:107C100079E2A2921838078341A4BB657E0EE7245F +:107C2000C03BED8B8A7113A71E9431CEBC810D52DF +:107C30001EBB56C4CF3DF402BD1718E0F6B638DFC0 +:107C4000E1457A203F83D1BD66F047F7BDBD23CE25 +:107C50002FBC63C6E718F69A591EF85898E48117A6 +:107C6000E501B48FCF14F26076936B21979B63C8C4 +:107C70008331EC5A6DF1379E3337FB7D096523FD67 +:107C80000384D319F8073BFCA3D8B73310DEB3F055 +:107C9000FEFA1564F7B549E02FA7625CB67F731E44 +:107CA000945DE75A282E0B7094302E482971B45FEA +:107CB000D25187714E5F238BA2DD7E6126E7AFB67E +:107CC000E7BF4823BBF0ABE7D3F0DC4FFBEAA612DB +:107CD0009433DBD7B2309EBBF455BF4DFED6E43AA9 +:107CE0001BDE35C4DA11BEA84F678978894DAB43D6 +:107CF0007F20012C581CB7F5732BF91F69855A1F7B +:107D0000E261CE792012E7607DE02ED47B09AF7569 +:107D10004B415C6F903539D3C88E0ECA3379999C2C +:107D2000C2D8ECCC099CCF5E0B59A8FFB1EA528CAB +:107D300033E9797E09B8B2142A8F60A9C739129045 +:107D400085611CDF398CFC3622213E6E14CB2DB3AD +:107D5000E1397D3F6C51B0FD3535A8505DA1521F12 +:107D60007FF36CFEBE0EF7DCCCD8F347BEE5A3C7AD +:107D7000993A2D81FF42FF53FB09B757F538ED0FB4 +:107D8000F1FF226F02F1A1E7C7BEE5E7F9B03BFAC8 +:107D90005F48C6FBAE87F32762F366F57CD9DBC785 +:107DA000733B373393E31FD916F3237E2BE26A5ECE +:107DB0009117A3E74754A7EBF7F8C5C615F5F8EAFE +:107DC0003231AFDB857DC2E468077EB7BDDBA2A0A0 +:107DD0005DE77DFAC4663CDFBC2F25F22ADED7A81A +:107DE0003DC8F75B992D427117D724B7C81789F59D +:107DF00007BEF4C7FA0123EC7FD339CCFF2E7F8076 +:107E0000FE0C76B32D93CF43F707F47CC116FFC168 +:107E10006351E40689DF0FAF6572BBD09A5DB53E52 +:107E200097F88FDF57B9CFD67B0CF336F7F9A70653 +:107E3000EAD4617E6B17FCD63EE7A528D9BD354C48 +:107E4000C17BCBC69207EDE507691FD95D6559EA8D +:107E5000E0744CF1FC5FDE9BDD8AE7E787F457EACC +:107E6000903DEBCF34D09B43E8339DEF87F025F274 +:107E700067743CBA4BF8FAF71439227528F7967FE5 +:107E8000BBBC3890CC97E0FBEE872C8CEF2BC6B6B2 +:107E9000BBC5B96D733E1CFE8D960747797618FBFE +:107EA000D7F25BD1AFD1CF69DFB135BF552B4638A3 +:107EB0006874CF0CDE3D4B71DDB1F85AF0EB337EC8 +:107EC00055C88558BEDDF8CAC066F27F4158A0FF8C +:107ED000BB7196231DE1BD5FF4F769DE52E467DFF5 +:107EE000B18E52B4C7753A180B5F7ADE687759BD08 +:107EF000B4B090F2C607D19EF70E364A9793DC9243 +:107F00000731EEDC85765BEAF0B90B6F3816DE33AD +:107F10000E99E15F4778EB9283A98B90EEC29CEEBD +:107F2000CE3916DB6F7ECED3A957C0B8BE728BF8A0 +:107F30003D11F19E1B54127EAFCC467AE2BC7763B2 +:107F4000DF1B9EBFE8AFF0733A177E7E9A7EA922B0 +:107F5000DFCA34FF8B64F33EB4E8EF0B7AAE4C1DFE +:107F60009EFF777DB1FDCA963EEDB97AB4F9FB99D3 +:107F7000B7AC7078FE97E63BBF795E2A9FFFF78A21 +:107F80004ED36FE2E8F3BF62FE18F3CF0F2DC0DFD0 +:107F900089B8BAEC34E3DAF8F7BF5FF9CDFDAEAFDC +:107FA000317F471376F61874C4D64ADF33D111D126 +:107FB000C3B7A6232D75B1818ECCF4B0B0C04EF4FA +:107FC00032928E04FE041E4E4B1F828ECCF470A69D +:107FD0007464A68F613AD23C5719E8C84C0FD7DEBB +:107FE0006A2779E62B67BBE98CEF083AB2D0FC4FE1 +:107FF0004B1F828ECCF430928E385D98E76FA6933B +:10800000FF71FA50D6925C31D2C7E27F893EA2A9B5 +:108010005718E8C38CE750C9C5440723E943E04536 +:10802000D0C769F12EE8C38CE733A50F33DE87E9AB +:10803000234A72449FBF19CFE1BAB5C9DC4F1AA2D7 +:108040008B33C3B30A78769F39FF9BCF7399F1FDC9 +:108050002FE3595D4B7C6FC4F315FF923E01BD6069 +:10806000C0B3195F4B16AD257C8EC4B380AFC0F38F +:1080700069F127F07C5AB93D069ECDF81BC633E363 +:10808000FE5A98FB1366FC019E5DB178FE76F83BC4 +:108090001D7F9AF17B3A3CA63A63EFB7D2CBC55924 +:1080A000DCDEBC040D6DEC173F7ABFAB45BF4DC2A3 +:1080B0008E4F4D1AFD77A6AECDE27EC7CB7ABF2C90 +:1080C00026E2907C1EFBEB7B2BD13E9A65DD94B6BD +:1080D000D83D725D5B248BF89D860EC918CFBC2DF0 +:1080E0008BFB7D3DB560789F35FC7C7BCD009D0F83 +:1080F0004ABB73B00EEDA7EC9A14161C056EDECFCA +:1081000027B0E0D9C6EF45E87BFEF230ED57793F66 +:108110009F44ED3DB5328D8FDF47FF7AE4F8716300 +:108120008C9F769AF1FDD43EE23E25EB42BA27EFD2 +:108130005E6C1AE5BEDFCDB5918E46FBC8E77AE9E5 +:10814000FBF88AA52111DF96C19EDDC2FFCBAC49A9 +:108150004FFC15FDF32D65DE1C8CDBDC9ACDF1E7C1 +:108160004BE4F629B305F211BEBEB88E3ACC6FF5DA +:1081700094CA01CC176B4828F2D13D25CBE7C6DC69 +:1081800033B2CED241F7290E9F63ECE8433FC46A75 +:10819000618314B737F59F99CDE9A041C4DFBD35A0 +:1081A000D6ED780F66FEAE2512EE2FA488F9C81121 +:1081B0001BBF27150103FC3CED3E87A8376FACB40D +:1081C000D13D9FE21ED5D5DF437B9CF247C01EDF29 +:1081D000DBB37A23FA219B6B03D21B06F8F8D8E8AD +:1081E000FB27EF657DBBFD96DC6CB15F21E6DFD53B +:1081F000FC7DDA6F8A5895DBD8793809BEDFD25D0D +:108200006EDE6FF93EADAFFBCAD1F75BBAAE34EFAD +:10821000B7F0FE7A3BBC17B3DF02FD63F65BCC65BB +:10822000F79521DA7F19B95E11FF17FB30144F5112 +:1082300071FF8505F07E9EAEE7AD817A8667FBBA59 +:108240004A303FFCD3A01CA03CDBF9213A5F6FC64B +:10825000675742B784FB36DD75B64109F06FBDA69E +:108260009BFC202BD003FE9E9FB93FFBF26B3A5F35 +:10827000452288422340C7B2981FFA5FD7A688FBE1 +:108280006942927E6E6550FF5D9E1CCCDF6DAAC375 +:10829000F34C8D8C558FC373CDACB51FF3953C203B +:1082A000F78C71E9213D650FBD029C3674BF48D73C +:1082B000F9B1E7373F11F0189FAD9F630B91BF678E +:1082C0005F72F4188E6BD7EFD14BB5C5DC57D480F5 +:1082D000312894F3B77139DF9517A5FC8AA88BA5CF +:1082E000D833E87760827CBF43D6F370E877DF321B +:1082F000041F76F5F1DF33E9BE8B49F8BB15FB525D +:1083000082F5C86F9A858570BFBFFBEE709A2B957A +:1083100090B3C88EB2321854530DF73475AFAD4ACE +:10832000B3723A2B403E6EA8E1F768757FC5289E70 +:10833000D5BD548DE03DF369ACDF85719289658EC2 +:10834000A885CE8798EE0512F01E8B8E86E0280158 +:108350001C73088E820FFF83F8AEE17C5EFFB0676E +:10836000C3FFC17CBC62163886F3B2BB1D94D736FE +:1083700016FC86E0EC0638278EDDEF135CBBC7B831 +:108380005FC7CFEB774BEA6D785E45DFAFEBBE3270 +:1083900076BFAEBB59223EEB6A9652904F74BEEA4E +:1083A0006A5EBA85F6E92C59B44F3736FFF075FD91 +:1083B000BE67F5F7F0F7D586F78B7BA72C9E362C9A +:1083C00057D3046EAF1272C199ADCB5707FDBE8172 +:1083D000F93D7DFCB432C7715CB7993FD2C47D4E84 +:1083E000693E7EAECEDC3E2F9BEBBBED593C1EA61C +:1083F000DF57B53F97C7ADBA5EB2F2FC7511A7EA79 +:10840000BA92C7A9CCEBF39AE256DEA1B8D5D569EA +:1084100018B7EA1671ABEEE337A461BCAAAB9CC7F0 +:10842000ADB667A9317AEA4CBF3F042F41BFCEEC0D +:10843000EDAEB0FB5F9F87DE7F5F4AEF5FE9BE88EE +:108440006B443C4F01BD85F82ACD0F8CA67F4E07AB +:10845000DFB942FFCCCB6654EA7A76ADA0C333E5F0 +:10846000175D6F3FEE08DD918DFAA58CEF83D42266 +:10847000FC6619E41CE85B927367382EB3DEC942D0 +:10848000B0BE4F5EB446C88F34C953FC33CA4BAD3F +:1084900054ABA3FBCD2DAC7A933252DE7A58E9C6A9 +:1084A000F908B7FC9084F73034E4D848DE9BE569DE +:1084B000B3BDDA89F7F836D686B6E0FD50F7034C3F +:1084C000F0FE991AB74CFBF58DE2DC9E96C07F0F4B +:1084D000CD3CFF6772395C1F4C0E97A35DB25F5AAB +:1084E0001A9327E9CEE174FD0F017F56187271F9D6 +:1084F000DFF802FE0E4F53B185F2D29B8AEBE54BBB +:10850000609E4D5516FCA56BB6CDB7D885FB865A37 +:10851000B545C17DC46DBEFA17F07E6F6DB945C516 +:10852000DF293FB2BC82E2A25BAA2C67231DCD13D8 +:10853000F7996F55F87DE6DBAA2D015CB7A6B869FF +:108540001F727B35CF2BDA9619E0F065C1CB0BF4A7 +:10855000F30AF077E4E6CF18DEE316F1F1DFA76D5A +:10856000D35E50D0EC9BB4BC348ABFC3A11639157E +:1085700055C1FB5F8351DA4F0FCAA128D4DD5AAF32 +:1085800086FBC0DBA4C8B3181FD5CA2D741F4ADFF1 +:10859000AE79D13FA3FD50164FE3756B07D3707DC5 +:1085A000CE5D36DAE57845F0FBDE5D8E74A49F6D16 +:1085B000BB9A281E98501CFB3BE67D758FD1EFA01F +:1085C000C407629F6F2B8FD07D344E66782EE29C5D +:1085D00051C3EFDD3DB3F2A884BFFF6033F5F387ED +:1085E00099857E5F4173D3EF20BF08F3413ED96B7D +:1085F000095A503F69AF4BE4A7DD6FD79C467CFE1C +:108600009FA95C1EEAF79AE5E75842B83FBA56E8D8 +:10861000619B9B9F4FD7F16E2E739BE77EE3EF8AA2 +:1086200078E42BB618EF63EC12F79EDA947E8B0297 +:10863000F0CB784429C083E11955FC5EE3ADB3B2B9 +:108640000ADCEA301D6EED7B600B9E6FF13CE4A608 +:10865000DF5FC17C3BCC7363E3F8BED5D195B753E4 +:108660003EDD6D573A2C4827A7FEFCB246F6D152A4 +:108670003FE5590ED1ED129E479550931A98087612 +:10868000AC5BF50626C2BC6C358E00DAB5F31E9ED7 +:108690003A7EE01BD6D15AAB0426D2FD7A72602214 +:1086A000F050AB80CFFF03FCEEA62300800000005B +:1086B0001F8B080000000000000BED7D0B785C555F +:1086C000B9E8DA7BDED3C9CC4E9A844C92A63379D2 +:1086D00034499B94496931E5A4B81B2A96873A2D01 +:1086E00029A68A38A9A5A690E2143C877244B393C0 +:1086F000A62D2D25A48FC4BCD0496CA14F4CAB2016 +:108700002A1C27A1780B173520287250D38A7C4762 +:10871000EF399EC001E49C5B8FF7FFFFB57666CF13 +:10872000CE0C690BDE73BCDFCDF7F5DB5D7B3DF670 +:10873000FAD7FADFEBFFD72CF8E6F5BE751EC6FEBA +:108740008C7F1F66CC1B9018CB49941D5B6675759A +:108750005C9628DBE6C8E1581583BF78DEAA8CC496 +:10876000FB53A2DF6E89358E18C633D7B3C56ADED8 +:10877000F26CC60636DA955D01C696677EDB7FEB46 +:1087800062C6065BEC8A03AAFB37FD70E74D50AF6B +:108790003D6F616558DEF8987F8361BC8134E35793 +:1087A000E3F84B183BE4D7FAA51074D41EBFE1B927 +:1087B0005A28BBB47E8665F6182F4333760596BFDC +:1087C0007F830A701CB2C17FF3199B1F68B941C334 +:1087D00072A6F62959616CB6E3C8BE537E28976924 +:1087E000AF4850FE4C398BAFC0FE41DEFE23E53969 +:1087F0005DD4BE9A97AF2DFF01F51F407860FED67D +:10880000213B7E840D0C756431986F4766873F006D +:10881000CFDE9A781ECEC731B475DC09E35B25CD77 +:108820008FE56762B784575C81EB51FAD59B703D49 +:10883000C66D215C8FC1D3DBD63218EF2D581F06D1 +:10884000DF1E9813F78753C0BFAB352FB41B16AC90 +:10885000139FB6C4FB591579A1634E9A0AFB33FCEA +:10886000F3D5269707A4B89F017CEDB1F561EB52D3 +:10887000F89E2DDE87F3B923B02C6C85F90D66C404 +:10888000FD08FFBAC0125ECEE1F0C28A8771FD0614 +:10889000FD02FE584558F34C9FC7806DC41FAA3A8D +:1088A0008F798876170B47BA7538DFEFFF3FDC7F8B +:1088B0006DC83373FF6704FDA41D27787EE3BC5F9A +:1088C0007CFCFFFDFFB2FDDB03C5C48767C607461E +:1088D000ED3C328B20BFDD965DEF6CAA4A8C33569F +:1088E0002553BD17DB2DC15E2A0B833CE86DBADA38 +:1088F0001981F683F7C45CAA85B17B631D59D70241 +:108900003F8B45E410B2DE41A53D2B08E5EEF53284 +:1089100093A06FDF398B3B08FCAD2F2A2BED50EE77 +:108920005F5FEFC4727F0B6FDFDF20AF8CC178DD3C +:108930000DC3AECF19F85E7F94BFEF6F1EF36F309B +:10894000CC6B10E503CAA77B6046304E4F6DF1F04B +:108950002E2951BFA282CBA1C14DF5CE79308F8196 +:108960003A99603EB5F99DD31F86F6837572C001B2 +:108970004D4ED58DB9CAA1FCC04A39E48079CD13DA +:10898000E5FC95D65000CAE5D809CA85852C16079E +:10899000BEBCC031E2C2F11C0532D3A03EB399493E +:1089A000D86F545947E3F6E7F171B73325AE413B31 +:1089B0002D2AC70E42F9EA6FDE137F10D7A7D6A182 +:1089C00038484E315F4D2EC81FFC1FAE2D8BC69F01 +:1089D00084FA59AA33BC2B84702F928A16E378B09C +:1089E000B821DCC720C133D07247FC97F07E5BE32F +:1089F0002C66017EDDAF9D5450EE645D6F3D3B61A2 +:108A0000D857654572D966838D837EB61A7B4C83B1 +:108A1000A16631433D941DA6F2941EA03843A515CE +:108A2000897132424A52D92C9F3A5A1F67BF31E0AE +:108A3000A115B667A46A7ABBEF235E113E8DF8C319 +:108A4000205BB7B0E8AFBF0CEBC7C62DA183B01E4B +:108A50001DCEA77A5F037DC4EAFA9FBDAFC122E5B0 +:108A60006C993588E5E34135AF09E0E8F99827349A +:108A70008CED5AC77B3B00FFB7DE6EA77DDAFA713B +:108A8000396641D9CDBAD8DDD02E6B8E1CDB056599 +:108A9000CB0D7B020C96D2658956B012C6F63235E4 +:108AA00088E59A20A7934C167A6039ECD3E9473EC3 +:108AB000B5F61618E78E8FB9091F2EF9CC0A5F2478 +:108AC000C5FCF567B6B364D0A837ED3FEC6C8CA558 +:108AD000687F8FA0A3C1A7636B3D307EBC4D52A4BD +:108AE0002BA1BCF92192FBFB577B18CE7BB683CB25 +:108AF000E5C78E0D7671393D7E04E5761D5BD6B3F4 +:108B000072196347AD1C1F630D7C1F6323562A0F28 +:108B100044EC3109CA9D2D277F7F04D7276C0F11A4 +:108B2000EE627BA4C34DF362481FFB65D68C74CE06 +:108B3000AC23FE55B0EE278EDB1B91BE701F50CFCD +:108B40003B2EF42E66D5FC8DD5067DACE921BF0AFF +:108B5000EF0FADAAABC0F93D397CF31E570D8C8BDE +:108B6000C48B7A8256B91FEB4FC892D0BB00DF404E +:108B70008F1A41FD08CB5ACF4B2B4A015F25E532B6 +:108B8000ECBF66E8FEEE00C077C4C5A8FEDF8E1C11 +:108B9000096B85D01E951ED23B6EEB5E0E733F5166 +:108BA000CF44FF1FAC510B717CF13DF893015F4F37 +:108BB000D8453D3BBEA6B90EF6F3AA78316C26FB2C +:108BC0004215D3D6C3F78FBB79FBDB8297F768508A +:108BD0007F24536F2FFD14F59AA3ABF5F9B5EF552C +:108BE000AD34FFEB2CD0A6EBC0437B3D4B8DF3BFE8 +:108BF000F105B594D687CA5F1AFAE4EA76E83FDB56 +:108C0000172B56009EA6E0CB6BAC73687D75F835CC +:108C1000E6C4FD9C2AAB4E006D7E51AC98C1BA7D76 +:108C200071C1F7087EBDFD978E8E8451AF34978F4A +:108C3000A7D183BF59EA22FAA9B1B0B88C74F3392D +:108C40007BEC6090AF1F960B22F643880F05564EC3 +:108C50007FA1D16FBB6E35E0E58EA09BFA673B58D4 +:108C600014EB1F9F38E96A327CE7C9799C3E01BD4D +:108C7000663D0DF893DF6057DA801EF2C337AD45CD +:108C80007CF26A7626C15AC8B5E38BAAB0FEDB1E19 +:108C9000F651A88F6D0CFB198CD75D3691A7C0B328 +:108CA000B3693B957B338EB90EA2BEEF925819F291 +:108CB000E3C23B4EA37CD06AD785CA52F0919FCEC7 +:108CC000B3D0F73B5B16853640BB1D1E8F824B7FB2 +:108CD000D41A6AC4EF1FF5D8150D5E64CBB17CD4ED +:108CE0005B8F0EFDA4AB03F6375BE0C3230FBFD44D +:108CF000857A6AC7CA932E09DA7736023C481FE1A3 +:108D0000C8CE79483FCD9C7F2FB1587661B9F31A10 +:108D100099B51BE6D12949B4EEFB9A8B57217DED1D +:108D20005B992D31837CF94C19A7E7A9F5FF1B3B13 +:108D3000F17916509D0857E7B6EDA15D018EA79E0B +:108D4000CB1973F3FFB2FD40B69F437925B1E830EC +:108D5000CCBB438981CC656CE8ED854C033CEACE05 +:108D6000E0F4EA5EC86208DFD0C7BEC736A0BC0226 +:108D70000141F60EE3FCC3A381EC4779238DC45176 +:108D80001E69CB9D93074388DF316A7F64B933BA8C +:108D900055417B6B98A11CE93DE763C84780F330E0 +:108DA0006C0F9F19DF056577959D050CFCDCF3EAD8 +:108DB000EFFEC4BCF064F0DE200F34012FECF8AC01 +:108DC000A7617C5F2323BBCEF7EAACB8ECC5E7A66E +:108DD000EBB19FEFDBA1CFD0F355D7197CB23AC3EB +:108DE00038C06A3F56A4BE10E4EB164D25177ACA68 +:108DF0005CF41DA08300AE837605E3EB8A4B9B2BCE +:108E0000A600DFED7D74428BC33CD4A0352AC17E21 +:108E1000E7B49C6588272CE289F8F2B05178F921F3 +:108E200028CF519D5194A7DE06C33CC45E5861BC57 +:108E3000393836A906CA755588077F272FDA454580 +:108E4000BE0F9D3D01921F03215ED67633A233F300 +:108E5000BCBBCAED84AF53FC13E610877DCF47FE41 +:108E60005BCCCB32CE1FCB80DAEDE59C7EF7BB81AD +:108E70001F939D3DE2B2C0F8B92DC559F83DA668D3 +:108E8000FED5C07F7F5CCCF5F50E601FA82F813E1C +:108E900041F2D1FCFD178B85DD8D7FF05D1FE3DF97 +:108EA000E994275939CE1BD6F35180A1F38A67FD87 +:108EB0004679F68A185F5F0F2FD3D7838F43280335 +:108EC000F2D2DB224B9FCFE6DBB01A60F1461EBB2D +:108ED0004BC2C6CD1C7F007AEDCF88228DC9EBEC4A +:108EE0005393F1CBCB0C6580B3647F727B1D2F6CE9 +:108EF0004A72BF39267CCC2CE1787202090BE9E971 +:108F00004A161B26B93FA97A903F45AC0CF1DB67A6 +:108F100065F7FA16315626E05C22F45CF3FACD2AA6 +:108F2000E7E399F19519BF6B995E3E9A25F0620AC5 +:108F30004F93EBBD4EAF36CB3B1DEE33C5C1A9758C +:108F4000D772C57ED1DF04E9D7FB33265509F77BFD +:108F5000390B1D0479E13D76965DB79810F34DC449 +:108F60006FA88FCFC7EF4A8CE8DE5BF79F8E400A71 +:108F7000BDACB684E3C5A1479FF007D06F61E37A2B +:108F8000B3CBB40EFB8A39FEEE2BE674BEE7545623 +:108F900025E259FD779E601AF2CB5F58620ED437F6 +:108FA000BE1BD88AEBFB0ECC0BF9A7EFB909E42561 +:108FB000307EE1727C9F1F0136A924C68526313997 +:108FC000EFFC9FDD4F6B6B711C5D3F9A56BF663B9C +:108FD000C91F5D5FCA8FCB53F215D1D6A07F68CE73 +:108FE0003AC227A19F2CCAACF724F48DC9E145AB46 +:108FF000501FA8B68CCF77C27C7BBAAEDBB3629928 +:1090000041FFD096EE5D5E6AD03FD882D56ADD7BA7 +:10901000E91F45AB8DFAC765E5A07FE425F48FBB5A +:1090200087EFDB47FA8D536FBFE279D43F663BD4BD +:10903000C34864573E3C42FADE7EBB3EFECA3DA8B2 +:109040004FE9FDAF2C5FB907FBCFFEC4137EB4BB65 +:1090500066FBF4769DE4DF9A8F70D3BC6B57E13CDE +:10906000CD7AC8806D6ADE497AC83F3EFC2FFB8C02 +:109070007A48F6C3B5AB506E9ACBCC39E2423D7D0F +:10908000A6FD1BB08EB814683F20F6E5CEE115AB07 +:10909000DA80E7D90E8D5F2B2D4CE85FF24327BABB +:1090A000DAAA70FD81DE53D0E361C1CFAABF618F20 +:1090B000A23E5D5FEE213AEFDF74E301B4AFEABF99 +:1090C00073AC6F16DA53BF586B43BC7CB8D84AF800 +:1090D0001BFB2EA7C7773671FD18FD2A349F479FCB +:1090E00093500F298CD955D477CDF3FE7A71257D15 +:1090F000CFFC1E766CED5836CD83A1BC3BDE1ED96D +:10910000184E21B71E17F3ED68850526C57B44C2AE +:10911000F5DAA7A82A7EB7203BAC31E26B326CC0EF +:10912000743AB5BE5BC0D4D9897256A6CAB0BDF533 +:10913000DD227ABFD615FE5E318CDFFF586D27A089 +:1091400025EB9705DF99C7F53E66EDCA437DBEB5B1 +:1091500048FD87625887B7EE5D5C8172279DDDD23E +:10916000D11AEE43BB69AA6C4BAD670ECCD5E1E2D8 +:10917000761DB3862A903FA118E3F8B693FC835B73 +:1091800005BEFCE0D84EF29776803CB322FF6A9190 +:1091900015E28B80E3DB419EE412E180FC96E2AEB7 +:1091A00020CCFB4F41AE6776CA1387BE81F0DC61ED +:1091B00027F9861B201BE4D8D43A15CB29E515C81E +:1091C00027D5058559C5015E2FFA4FC92F21AF8ECE +:1091D000B745D6A6DABFCB05DFDB9F31A14A8B139B +:1091E0007CD777ECCD24BEEB3D266B8E85D3F9ED95 +:1091F000FE0C9DDE027B54CE5F697DEA4A027B90C5 +:109200007EEEB270BD8D6D65EC208CF7C762B077D5 +:10921000510FDE34AF06F9E871495B3B0BD7ABCD9C +:1092200043F5C801DD50CED57C6C1794FB36F6BCF7 +:10923000B101DA1DACA820F8FAD6F504D1B4A8180B +:10924000CAAE473CE889C8872DD274B8FCEB6312DC +:10925000CA7BFF164BE035839DDA17D9DB86FDDE2E +:109260006E61A41717749D18B5E377D733BEFEACB3 +:109270004B6A30D87FF9B0C871F8F4CDF044F9C525 +:109280001ADD2C6E90935BE6467C254BF03B76FA1C +:109290000E5B1C21FCD7F9E99D072E7B5E43FBCAC0 +:1092A0000DF48376A29D3FF5F1734BF8FA17083A57 +:1092B0006ADBB6FD9A0C943B128B39F0D924E71F78 +:1092C00087676F03F7B777FF49227E30B88CC5DA1E +:1092D00049EE4E925EEBED6071D4F77CA726480F05 +:1092E00078642B7CB496CAECF350FEC40E16C1729F +:1092F0006FF41DAAEFFFAD95E495B7B967B54CFBC8 +:109300009AAC77CC24FF75797DBE729F18720A796A +:109310004F7A04F1E702CEF7DB78F9B7C505C4F759 +:10932000CDF25A7FAA821EA03FD72315B5FEB7689B +:109330001FFDAC64C8E80FBBAE84B73B5ECCF957E9 +:10934000EEBB60B8E03EB1F175F765733C44FE36A4 +:10935000B51F0AD88DF0BDB133DFF17F05D7FD7899 +:10936000FE22F487F49ED9E197508F687A6C3E3ED6 +:1093700077C823CF921E72D21A3AC8D07FE2263F16 +:10938000D31D73DC430E839E7CB7D8DFDC2D47C929 +:109390008F73B65563BF294B7CC70CD71B551C0F69 +:1093A0008EEAFE0A36D2F738D24BDB426917D14734 +:1093B000E076DCFFDEA67941D4978FDA39FC677757 +:1093C0007D5F42FF65EF26262BBE14FC6C1373E213 +:1093D0007B7DBDF4F67A3DF4B31AFB417BB772A9ED +:1093E000B17EC35AB54A6C1D7C7F7B6121AD330BC6 +:1093F0004BCC83FABDB055EE167AD7D12BB91FAA44 +:10940000C72FC7DA71FFC3ABDA6E41FFE155CE104B +:10941000E2296B58A14E18E828A7EBAB6C4B16B7A6 +:10942000136C59D3EB7B0B8777E2303596C8BD6858 +:1094300067B2B932AD7B6F44263B7D7B0B53102D59 +:109440007BABD92BE8AF6481E8E428DA7F9BB93D98 +:109450005A60E565E6F150BF589B7DF6F50087E35D +:109460000BF215D84F87F3BE1237CD3F9D7FE04FEB +:10947000C29FA597FB5BE49528A781DEAF237EB44E +:1094800054CD46FF438F6D823D2DCA1A8CFFFB2AB7 +:109490001BE1A15C3BA14D54E1FB893C96821F7707 +:1094A0009645FCE83FE811FE83C126EEA7EA6F1956 +:1094B000F3A37DBBC3737D362EF5561BB7BFB7B67E +:1094C0005D7DA04D4A8C5F63E17638DB612738C94A +:1094D000C78AFA42B546F6DC7E7B9CF4CC1EA0B36C +:1094E000E1C57C7D8D763ADAE5CD68974B81A8861B +:1094F0007672F871B2AB9F047D05F9476786F2CAB0 +:109500000128BB6F94158DF865F819E43F9E6699A4 +:10951000F484592D631AFA1540DC8FFB6AD15F1D64 +:109520008F3F88FCFD6E9F72908412B7D333D03E7C +:10953000A532B7D37DE7E632C48B6976B9C9FE7927 +:1095400059F84FEFFAD5BFC79F243F000BA33FF850 +:10955000FCEDF0F029E4D723E11609ED02DDEEA2DF +:10956000A5D2ED5486FEE6AC5B0F65A35F7E57ADDA +:1095700005E09A532DEC56937D6EB6C791AFA13D91 +:109580003E07EC7184EF83B6BFA1ABC488FF4E32B7 +:109590009433B6EAE9F637DAAF786C49E39BECF13D +:1095A0008C6A61EFE97639B62B99D91EFF83E0A367 +:1095B000667D664065537E58C4C30E50E0711C60E2 +:1095C00025CEDE2C7AAEAC8667B3E06B3E0FD3D0EF +:1095D0002EF5295C6F413B9DE05B0D323E93DA4BEB +:1095E000582E606CD1DEA5F4B995D5D0FEA62A6EB2 +:1095F000C72AD81FC6536ADDD45F5F4F833E44FD40 +:10960000591874E5A5A8FFD8259CDF97BEC0023283 +:1096100094FDCDC9FBF17FCB6EFF4815C79FF3B515 +:10962000DB03A5C9767BDBB67734F27FDFDDE57738 +:10963000A0FFF945F8E7C3764EAEFFAF197621BF1C +:10964000F036CB4D7694E7A7C657B18B90EB176BEE +:10965000D747AA82537E98F3B1EB8F1E3BF9EC7C7F +:10966000283F502B93A97AF4D859E7BAF7386F30CE +:10967000EB9D2AFA287250BF546E3B86FAE527DD2F +:10968000A4BF4DD72FD92CA42F6D0D9717039B5E28 +:109690006F477D33E736B694C0AF88486B617E4D27 +:1096A000F39D349EAE2FE6348C4B686F06AD5DA4FF +:1096B0002F7683BE88F2AEA06BCF35E8C7652F5AF0 +:1096C000188E57D0D2457A663ABDB152E88DA027A0 +:1096D000AE2985F1E73C61D01F59426FDCF401C12E +:1096E00013043A47B930D8D87518E9F76C79325C69 +:1096F000537A7014F4E0EC0BD7834B12F07C01E149 +:10970000C941782AA6C333E52FD02ECFACAF4AF893 +:109710000BEA0E5CBE0AF5BA0B87F39D31239C0B56 +:109720001F5748FF2F68DC7B18FD21BF2FE77430DF +:109730000DCEC6D53E3C2764855C2F37E35501C26C +:10974000055DE709B8FCCE1109E56FBAF500B83B35 +:1097500009EEE634700BBFC98D0716EF413FCB5DB4 +:10976000160E07FBB09C064EBE0EDA32B78033975A +:10977000E0F27D5A26B8F4794E9AF6D157C708EF31 +:10978000FA1A67DA47A621DDF91B559227FA788A7B +:10979000D8CF5589FD3C5C4AF46B80CB92806B64DA +:1097A000C89EF27CEFAE20973F667FD210F08871A2 +:1097B000A40BAB4AEB5F7F834743BBB867A94CFE62 +:1097C000B4FD6E7533CE1BEC5E867CA6E719A6A1B0 +:1097D000DC7967A93C8CFEFF9EE863AEEB61FE3D41 +:1097E0007179F6F5C88F1A643A2F9993E79AC47382 +:1097F000C7FE7887AB0AEAC74BADBA5DECE47E8B57 +:10980000B8833F351B3EB31D713FDA3F791A0B69B0 +:10981000F0361061E407E96F64DA25C01F73A59183 +:109820009D1FC1F5DA24133D433F878C7A8B8DEF62 +:10983000DB6053F122DCA73221BF0637DFE842BEEE +:10984000D01DE77A9F793D9E2CE57A5868B481B7A0 +:1098500013F2B03752BF19F735100DC8C67DB50BDE +:10986000B91688B229BF1592CE00E8539C7EDE5E01 +:10987000D35C8AE7417AF9F597E200F240ED4909B5 +:10988000E3AD0ABE28133CE679B4CD77E8FA4A7313 +:109890002A3B63C37C493F474B791EF1A5A053F097 +:1098A000A364FB5DC73F331E07AD60B7A3DE8276BE +:1098B0003BB4EFAB95DB50CF7B9B81DE0878117B0F +:1098C00094490E84BFC41A4538FD4E26A19E9907BF +:1098D0007AA0C6E30246516FF2453C746EA1A8938C +:1098E0000CE32A600A93A8DFE575B54946BCCE3182 +:1098F000D9E5400F245795F5EC00FA03983ACD4E80 +:10990000B796E54CB7D3BF84327849C28FE1387837 +:1099100092E2BC66B22B73C5B9D07F955DB9A28CBB +:10992000EB63E76B5756CEFFEBB62B5794717CD5A4 +:10993000EDCA01B42BA9DDAA51C4B38BB72B4FFEDE +:10994000220EFBB0236FD1E428BCDB1EB96312FDED +:109950004D177A1EDE2DE21B589BA4588A80BFAC9F +:10996000D92E21DFCB43BF6B0AFADA57CCE9EBEEF5 +:109970005C754DD99299CF293E5DC6F9ECD5E23C94 +:10998000C7CC6F55C6F1F9E6A24813E2796EB3ACC5 +:10999000398007E736C6494E64AF3E4DE75F1FC4C6 +:1099A000B92D9E87FD773FB77D26C8F17DBFC06387 +:1099B000F3FA1F2C17F55E9D1E5427E29FAF31204E +:1099C00023FE4B8D93645FE6B0C0EA8F2A89F6537D +:1099D0007666831696CFCFDEDC5B96C2DE34CFE7A9 +:1099E0006741AEBF9C68E7F2BAE70E99DB07E8452E +:1099F000C7F5AC55288E05FF42979FFF79F07E99F9 +:109A00009F076BF5CEE8C1D4F6E8B5E86F84D58E34 +:109A1000ED12FE00B4A77CC23E1D456984FA6FAD0D +:109A20009BE4F6895332433FF103B5F387518E111E +:109A30001DA01CFF32B7178A5848467B72B041A65A +:109A4000F7BD1A18FCE8EF16E78C5376A6B04BD793 +:109A5000333665A7A23D8A321EFBBF5BAEDB131A0D +:109A6000D9A3EB9AC11E257F7ADCBF3A2361670632 +:109A7000D0CE5C444FB2137F2EF62920ECC400DA1E +:109A8000990BD1CE84AF6427ECCC00CE333B616719 +:109A90009688FE3F2DE7F45522FA9718EC4CB4ABAC +:109AA000753BB3B7704243BC8429074E129EC378FE +:109AB0008B314E04F01CCF7AAC7CFCFC162540E5C3 +:109AC0002E47D27971D9BD8EA47D38E19ED0ECB8F5 +:109AD000EFEB3C6C18C60BEC4EDE276FF4B1BBF01D +:109AE0001CC96C771DB7279FCB7C4BCC5F7FF63AA8 +:109AF000B567109F02517B00CF850285DA4E9C57D7 +:109B00006E4466C312DAED7C9F061A580CE35A982D +:109B100015DAA3DC8DE406C8FE77F2F3847C7D9F22 +:109B2000047EE8F67F7E436414FD3D7916586AD8BA +:109B3000C3FCE80609F1EF4BFF9A11203D4C9C93C2 +:109B400043D338C29D6B9A7FD13DC9F46CB6A375DF +:109B5000FBD167A26FEFB87CC691623D6A2CCA51F7 +:109B6000E41BB9DFC8C874CF49D81D50A673CFCC49 +:109B7000D94A25DA9F571D0BDEE874259D17AA08E0 +:109B8000EB9E53BA9E15BC11F52EE5F464DC03FB85 +:109B9000E19967DFE7A4EF8AF6DA8930EA61184FC6 +:109BA00046F6ADDCD586F140402EC4D774BF4E6F6B +:109BB000246B91CE57994EB7A83A44F6B6A15EAB46 +:109BC000D43B2767A19FFE470DA36427486CB20CC6 +:109BD000FAAB6AA17696E0827D2543353C8AFA5637 +:109BE0006CB337807C3067BD5ECFD7291CE6650932 +:109BF000DB974CAFCF595FA79D35E2D338A75BD633 +:109C0000A0C4CA68DF19F7136ECC253BA1373246D2 +:109C1000E7307B409FB3207EB46DA732C801568CDD +:109C20007CC21A96306EEE81E7789CAA723A2CE1DB +:109C300079058BE6068886AD318AAB838FD0775F56 +:109C4000423DCD82791120EFB9FE41F20AD64FC2D2 +:109C5000F3BBA73379BB4FAEE0ED0A229A1FF58222 +:109C6000DECD1BD6A2DC5299D68E71A58A563C6CED +:109C7000B4638A841E9BCE6F70A1CFEE56A69DB5AD +:109C8000615C317F8E360CBB2660BEA3B5C364F722 +:109C90000F005FC3F3A76EFBC8CE1228F7DC0E746B +:109CA00004FB5BE16C7455A07C7BCE467ED081E6E4 +:109CB000FA4B50FEC72BB99ED6ABFBE7C47A48B32C +:109CC000B87DA57FF7C03CCEB79658BE45F90F03C7 +:109CD000188795424E7C568CD7E9E5743FE7DD4CFA +:109CE00016A360DA98847EBABF15E3E8EDE714BDE9 +:109CF000D02421FF611FBAE134E0FF1CB701DF016E +:109D0000EFF6E0FFF8F9B85601F37A709B5B3FF786 +:109D1000EFC6B8C54ED1FE6F1FCAEF46BBDD588FE8 +:109D20007183E6FAFC7B54B66511F91BB5EB817FB4 +:109D3000E67FF1F2CF5B295E263B818FC5D3FB8D99 +:109D40009EF91F711FFAB7D6B0189E73DBAEE5ED12 +:109D50006D351C1F62BF5C4B726CE0472E0DED81B0 +:109D60001CC6EB3F7A19A7FBDD2F8EF421DFF2B77B +:109D7000D819E287BF65FB38F2CB0BDD7F7DDFD3DF +:109D8000D68B75077AF11BF3830E548A38B1F5C967 +:109D9000707E5078F941CFF7EB028FF478F22E39CC +:109DA000594F3A5AC1EB5FAF9074FCE5727E9593C0 +:109DB000E4BC82FAA9A1FDF704DE558B714B1B6E42 +:109DC000F6A5F2B7E84FDD5E9A2A4FD9473F2FFE3E +:109DD0000AEA7FAB7293ECA3DE4757FA25A8CF04BB +:109DE000BCB26725E2576D68AF6128F02CAE573DD5 +:109DF00031C9CF83061A72B3D06FDF6D63D791DF9D +:109E00007463200BE5DF0EA11766FB6212B6637F59 +:109E1000C314B4B3C0E6F784485ECB353C9E53F51B +:109E2000D46463FCB0BC08958BEEB2F145E4A77F27 +:109E300014140376F1F19D5F457F097CDF65EF0A1D +:109E4000A1E93FD3F9F9C0A6ED14F7D26BD3283FAF +:109E5000E5A4C877F8B678CE1779677AFD63222F24 +:109E6000E2F134F5DF13F54F88A7B9FE1F44BF7840 +:109E70009AFE63A2DFA934FD7F28FA9D4E53FFAC02 +:109E8000A87F2ECDF83F16FDC6D3F47F41F47B3179 +:109E90004DFF9F897E2F4FABE778FE8AA87FD53490 +:109EA000FEAF44FB09F1BE3A10203C4E97EFD6B608 +:109EB000ED87D7642CA638703AA7EFDEFC26F9E7C9 +:109EC000FBB780F65133B31FBE1CFDBD30FE668C60 +:109ED000DBC8A178698A07AA39347E6D7021DA2D32 +:109EE000A1374E211EDD2ECEF1985A89F4ABC73F23 +:109EF00015965FB987C72BF1FC01ED059E3FC03C6D +:109F0000CA53142776AD92897AA719FF7A5B158A0E +:109F10007FD92CE2F0A6DE47B26619EDF6EE537259 +:109F2000DCE64BF8AF6A222C9E63E0A705A758BE7B +:109F300004767C41FCBB5200F3626ED7F5A2DE1BB7 +:109F400054F8FEF17A3ECF1A8CA32AC4EF293C6E56 +:109F50003832AE225F4EE797DA2EF80EC061213814 +:109F6000409FDA05EB590364E701BAAF196171DB71 +:109F7000427C8ED7E3387A9CD8250FD7D1778E07CD +:109F8000799C8BEDD4B81AF426C66D12F136E9E24D +:109F9000B10666C0BF7F9FC7783C6135C723A4CB9D +:109FA0005B8CE7C2F3B8DFEF500D97F309BC99273C +:109FB000EB7823E3BC847D521D10E36526C633E6AF +:109FC000FFFC4EC4810FCC40B7BF9DC792DAA5A35A +:109FD000AFB7C5FC0766A0A33F99C64BC70F7E6706 +:109FE0006A978EEF9C317D371D7F78C334DE23A2C4 +:109FF0007E443C7F314F16EBF6DE7469A66F3DFE62 +:10A000006F7EAC7D1FA797D04FF1DC5FEBE1FE3593 +:10A01000B43BC7720DF68D383FD5CF457F549E4572 +:10A02000856F8C2FCAFA18BE031DA9DD60FFBC1B0B +:10A03000E4F361CE919D68A776DE2E2BA87FCC79C4 +:10A04000BABD4FA29D9F298EC61C7F6C3A6F6BE1F3 +:10A05000E7A4D3E36992DBCD74FE38935D84FE0FF1 +:10A06000D49F7C8D8C25FB3F58F8A3CA74BF4767EB +:10A070001987DBECFF70BF1B64EA65097FD3BA3236 +:10A08000CEDFDCD6189EDD427D29D50F444EBAD0F6 +:10A090007FADDB975EB1DEA9E2868CF6666F21B7F5 +:10A0A00037411F09EC253B2B42F6A6F79F33C82EFC +:10A0B000BA50FBF283B22B673A3F7F57F09F1F8B5A +:10A0C00073BE125816F45B3C23D6B104F41FF43F60 +:10A0D000E87E8780A81F15EB1710F5BA5FE30453DD +:10A0E0007F678C0F343F757E698E67FD0F5BE4F5EB +:10A0F00072184FDD3D41E7868E3C16C2B803DB1374 +:10A10000AA6A0BCC7C6E07FDFF500EF3557BD3F48F +:10A11000379D7F41FBB7E87B2BDE885B8CEDC1FC74 +:10A12000C0FD9EC9AFFA7DB13E7ADCC13A1D0FA0D9 +:10A130003BC9DB288F3B98A2EBAF24D3B5D1BF84BA +:10A1400074ADFB97FEBE2293D6F56BE3673391AEF9 +:10A1500013FB97DADFF47DE16F7FB79CEFDFC0621E +:10A160009E57A8859C3C0ED552B71CE7E3B82C320D +:10A17000CF6290BBE702166A3F539EE24C79893367 +:10A18000E523CEADC8C87E1D6C4A166221E4075790 +:10A190007FB36AEF4A3C3778DE42F97CA55DEAA7D7 +:10A1A00070BE774D488154F19239CE1BFAF05CAD08 +:10A1B000A315BE6323BD99E4D8EE56F80E2CDA360B +:10A1C000917FD71DCA1BC2F5D6849C1E6D58477659 +:10A1D00071AF262BA4AF9F5E734D19B47B2B5B260A +:10A1E000EAACB085A9DCDB2253DC7C6F43BB13E90E +:10A1F000B7AF595650AFEE3B7703D5F7297208F346 +:10A20000903AD7B7BBB07E3066A5FCD898C8831DFE +:10A210008CCA6E948FFD0D632EF4A362FE6F872DA2 +:10A22000511FD386353AF7EE8B8490ADCEAA8ACAF9 +:10A2300094A72BEC1B33BCBF0E70793280FA0DB49F +:10A24000B3E5BC48FEBA589E22E1FE2D78CA45F01F +:10A2500016642B432EDC0F41BF8E2D9610E665DA77 +:10A2600034E013C0B40A0AA30CE37E1D5BECF4DEF9 +:10A2700013E4F46A63B08E86FD831D4F9461826B94 +:10A2800072C26B2AB813D72EE220DFF3BC697DC5FA +:10A290005F268E714D4EE4F3154B12F338FDC8FC6A +:10A2A0004B26CEE3FCEBEFFE42F3F99858BFAD2E00 +:10A2B0007E0EB6F58435D4C612F3D2E5AFCE07A62E +:10A2C000F88353E3F2F75690BF304FDFD3637D52EC +:10A2D000F174BAD1F7C74C3F7A7CB77E1E70E25456 +:10A2E0007D25DA75DD0DF317A11D19B4F2739358AE +:10A2F0006380FC4F1F12FED5BB441C7FBA73D13E56 +:10A300008DC71FE4B46C7FC3E2C5B8121E97ACAF13 +:10A310008B1E57F189A9F88398847232BF6BA80D00 +:10A32000FDC129E20FBEC6F72BF539FDC5EACDFA0E +:10A330007C805F1FC1F1D52D7B96DB8DFCBA51A5CA +:10A34000F8315F0913CAD1641CFD9700D2249EBB6B +:10A3500039D919B514F505D53942716FE36FB16A72 +:10A36000B4AF55E7249E43A801B33F939DFBB31EB2 +:10A37000A78672FFD54F2E473FF5E06C16C2382DE9 +:10A380006F5D6192BFD26F0D8F225C7EE06F5B3399 +:10A39000A7FB37CDEDB5867FA3F8385FC7159FB70C +:10A3A00002BCAC8EFBDD3E542CFF45FD32E7ED8F49 +:10A3B0001179C7F844F9F2B2C8DBEFEC70133FD360 +:10A3C000F394F5F12A9C87280F65B4768CFC918371 +:10A3D000B5B21BF12AD65CEF4B15473AC5D7DFCD96 +:10A3E000649A21BFA2D31E5E0B360A5B567967437F +:10A3F0004745C20F770D94110F9855A1F8B9EC5B42 +:10A4000081C7D610FDFB8D71DAFFEBD089F33A1FBF +:10A41000FF8F8AFFDAF3F18ACA0B3B1FAFA9FCEB6F +:10A420003E1FAFA84C3E1FEF4D9C8F4B7F89F371B1 +:10A430001D1FC8FF5685FE3FCE57BB241627BD689B +:10A4400095C8CF01FC413C4EAC2B8763A0691EDD53 +:10A450005B71D616D880ED7B37E50671BEFABAF689 +:10A46000EE3CD19707ED26B61648EC4AE0539581AD +:10A47000A4787FBD5EB3E4537D4E2E4BE47D011E78 +:10A48000E708FE46E5643FB75A9A941776E7FE154B +:10A490001EF27F52F9F03CA0831465331D4D9D6B75 +:10A4A000145B189EB7746F7337A68AC379BF7CE4B8 +:10A4B000A7022F476BDBE9FCA3BF4126FF78BF4E05 +:10A4C000FF0D9CFE3BBD7CBE3A1D2FB158882E0669 +:10A4D00096DB090F06240BE973A3673EBA12F96CE9 +:10A4E000FFB2C030D24BFF2FD7FAF17EAC3F08FC51 +:10A4F000E9F6B37C8C7FF369DC7FAEF34D1D1F74EE +:10A50000B873AE94096E7DBE7DADECF06B741F8B9D +:10A51000F3F06B30EFFCE649927373D76727F1E5F0 +:10A52000FCBA89364A4DDC929D7C7EF58C95CE9F97 +:10A53000F2D773FF7F77AB42E37CEBB93719EA714F +:10A54000B90DC9E39C6C0E537C056B9854514E8138 +:10A550001CD1320289F9513B837DF420AE27CCAF68 +:10A56000EF9687AEC138A23BDBBC2AEA0B03B75C8F +:10A57000FD00BA1E0632C36B1D74BEE58CE2F9AB5A +:10A58000611F62EB6D04DFA10E035FC7FC22CC0BE1 +:10A5900078D0CDF95BB72DB2D698D7F31B711EF0EA +:10A5A0006BF1D4BF9F6EBF1F748F6FC4FCC981C392 +:10A5B0003FD9EF5C467AABB0C3D6EC57ABA6E3E32A +:10A5C00083282752F07DFD1C89595910F9F64CE378 +:10A5D0008CD6DE21639EAB01AF086F62AA93CEEDED +:10A5E00075FC4A37EFEE5627D31C06FEB5968D60F4 +:10A5F00030C1E8A687FC28A7FA819F33F26FFD6C73 +:10A600000CF9D05B2FBB154BE8BDF03E393FCFFCBA +:10A61000F40A3F29FC55225F99093E1D1FBE83BEE7 +:10A62000C0647C651107EE8B939E806F2C528E78F0 +:10A630001B21BCCD35E16DD11793CBAC21F99CC763 +:10A640008C77BDE2DEB1A3150BF63997A6E027178C +:10A65000CBAFB463E7C5AFD2E1C71EC14F9EDA648A +:10A6600097310F25101991107F0B9AC37E564DFE1E +:10A670006CB297BCE2FE1A1FE3F2F29F051EEB4F8D +:10A680007D9C3D954A12BE75B606886EBB5BF3880D +:10A690001F786B27288E3AB731BE12FDE5736B1910 +:10A6A000DD53E3AB8B88B869BE6EB62BF9FECC35B3 +:10A6B000D179AE894F78CEF1BC87BED60A1A5FD762 +:10A6C000EFF24DFB357AE6618E7FC0DFF03BDD7E39 +:10A6D0009E0F6BDE27AF3827F4D6257FE783E2E3B2 +:10A6E00017CBF7D3D67B01AF804F1C3D047C2205EE +:10A6F0005EBDDFEFEA4FF3F9DAFB95DF97093B2DFB +:10A700009DFC1EAD03F9964D71AF1467345037A50B +:10A71000DF5EC2084F62523863FABCF5F36FBD3C8E +:10A720002597575892E85D3F07BFE948F11AE4AF13 +:10A7300073DC8A0BCF69B258D99A95FEF33FB7D62E +:10A74000EF6D4AB77E1807C0F5741E376090D304CA +:10A7500047A77B84F66FE9FC056B3A6AE9BE47EED2 +:10A760002F3B7205DDAF087AFF5A8C9355DADD0175 +:10A77000D43BBF857A0FD057DBA6C77E4172FB79E9 +:10A780004B00D7A7BA79C3BF20913E887A07EF471D +:10A790007E467D3ED7CDE7FAEFB5F3193DC1AEBB9E +:10A7A000653EFAE10EA4F6DBE9F90701768AE67F59 +:10A7B00042F8554E9CCAA2F8F407EAF26BD00E6636 +:10A7C0004A84E23E5E2B95457C30E7C766BB772A1C +:10A7D0004E1DEDDE85683F4FC649DEAA8CE20CFBBC +:10A7E0005A56935CD1E3EDF5799BE3D7F538F58FB5 +:10A7F000A37D4CBAEE941DDC3A9FECD0D476B07EAB +:10A80000FFC13F1D785269277B85DB351AD8351883 +:10A81000FF936D57FD92013F2644BECD4C764DF718 +:10A82000FCFFDA7CD2A7E65F985DF3AC888FF96B0A +:10A83000B56B9ED2E72FEC9A4E433EE9E7165FBC1C +:10A840005D1343BB8619EC1A0DEC1A668C07BB6CC2 +:10A850000DCE6F1A1EBD4F3E7872FE7BF3C10BCF3B +:10A860008BE1F92239B7F13CF8858FB3389EE314B8 +:10A870003476513967419ABC9866EE974A270F2E75 +:10A88000222FE60DA4C7B4F940E25CA0F5E8B12E92 +:10A890009EFF13BFC07B01C2C9F7026CE6F702AC92 +:10A8A0005E50417CA86F5D4F13AA481543EB29EF1A +:10A8B000C20C8F7FFD08E921FA3AE436723F5CD082 +:10A8C0001A71A15C99CA135AFCDE7942379FFF7A4C +:10A8D000CC5E807EBAE6E43C84A97C1A713FC0CF8E +:10A8E0008E1C1DD74A893FFB17E4CC7CAE9258BF23 +:10A8F000B04AF18257F1386A6B204CF7E2C01FF979 +:10A90000DBCCEB89E15ED7427B8BEA9C44FF9C2D3C +:10A910003B14477D1CA47C14E3A9E0FB95F87DABB8 +:10A92000C256CC867EB642D0D3007F2C1E9545AA57 +:10A930008CF7C91C518CF7C9E8F7D71D978648AE2C +:10A94000151CED5B837AC94CEDEFB270FA619FE69E +:10A9500071C329F69FF2D8B45B389EFB615FAB0CE4 +:10A96000F8DE7323C7F7D8026752BC9B7FFD64EA09 +:10A970007B1F1A2E2CDF6DAE903B15BADC997EEF53 +:10A98000C3C771BDA6FCAE7911D24F66BAE74FDDE1 +:10A990002211DC0E85C592FC65B648238DB73EC2F8 +:10A9A000EDDDC6303DCD78F201E4076A32DA772278 +:10A9B0003FF0743AFEA05D5C7EA021DFF14EC4FF43 +:10A9C00074FCE033C8C3732EFC1C53BF1FD01C2F74 +:10A9D000638EE778FFF98523D24618FF90697D7270 +:10A9E0001A22826F8439DF68383F3E5A62E21BB90F +:10A9F000A6FCC114797B0CF749CFDB83F51C5C60A6 +:10AA0000C4F36979968F28C6F3DA4F1D7D242CCEC6 +:10AA10006B0F105F89752DC7F1CDFEFC99F015FA0B +:10AA20001FC37D9CF9BC38F5F72F363EA9092FC905 +:10AA300031C06B8E4F8A89F8A4589AF8A41C8C4FA9 +:10AA400082FA1C8C4FAA36C6279D5D83F7E6EAF191 +:10AA5000494F233E1526E292CC7804F03F47F0A7F9 +:10AA6000D19B753C9EE2671FE679FAE6F320D0AFF2 +:10AA7000449EDC24DD0B01F3A63CB73EED4DCA7FBE +:10AA8000793B60A53C39BF332CE13936B0F0498DB4 +:10AA9000F25FC214EFA020DF0E611E9CD45692CD4F +:10AAA000F93CF2FDBC0893108FFD114F14FD2A7A7A +:10AAB0005EDCB5FA7D35E84F48C6A3D7111E9F9AD4 +:10AAC0003A0F399157585F89F3D970447DC9963947 +:10AAD0005D0FD2E19B82FB2ACEC781BF8C625E44B0 +:10AAE0000F9E0B2928576509E7FF36CC0FC7D3D730 +:10AAF0006370B3B013A6C3DB86FD7D424EE575BD22 +:10AB000041EB057F94BF921799A4FB6CFCB05E46A5 +:10AB100078AF4EC0AB9AE0B556E5A48757CFABFCF3 +:10AB2000D1D14D7BDB4ADF132E09E71513F9897D5F +:10AB3000DA1D97227DBE1DB5CBC81FFFF8CBAF1223 +:10AB4000BF1C6C52E87EB61C3649E75A39CD6FD22D +:10AB5000FC159945F13E0C731E23DEE3C0E159411B +:10AB6000E3EAF07C44CF6B34CD1BE09953B5C420AD +:10AB700077AC5C5FE98DCB185E86F9AEC45FCE37EB +:10AB80009FF41F0FBCFE12972B1F14FE464CFB199F +:10AB9000A1FD34E0AF84F03295E723E59AE035E398 +:10ABA000738AFDBCF2BDF63391B7CBE30D0CF9BA55 +:10ABB00004EF4F0EDCBC1AEF65CB9827FC56C29E03 +:10ABC0004F773FD3B5E2BE97AC52EEEFD2EF671AA4 +:10ABD000C0B84F94274D27FD743F93C6E3D062E27F +:10ABE0007EA6EEF3BF9F49C57B71A6EE676A38BFAC +:10ABF000FB998AF13234C00325C0E384CE61401151 +:10AC000096459C907E4F867EEF97379B590B17F1A8 +:10AC10007B16908FD694723BF2F2D200CFCBCAE073 +:10AC2000F11E53F732D4652D4294F0E1F830CE5B3B +:10AC300025BC9D0FC7CF4ADCE3715B907F57CFB334 +:10AC4000D3E354D3C5770EEAF75F5FE03975CBB134 +:10AC500047C3184FB434C8F74D8FE3D4E1DBBFEAE4 +:10AC6000A162A37CA811F11A7ABD6E6FE9F5FBC44D +:10AC70003CF688BCEED2867FF0DB108F356F00F398 +:10AC800014D3C9F3F471EBA9EDFBDE4DDCBE8FAD3F +:10AC900062769447B1B69F15A3FE3068BA0FFBF4F5 +:10ACA00023CFFA31AFF28E556EFA5D8C7E9B5AA39C +:10ACB00054CD7C2FB6395EA1A791C72BE8F3BB53C7 +:10ACC000C037939F2657C427E8F75D0C44F97D17DA +:10ACD0007D2DEBDA6CC8E79A6116D0BEB06B94E7B5 +:10ACE000F924F494B8514F31EB839F48E8838F5691 +:10ACF000BD87BFE6CE2A8ECFE9E2779706391DFEE3 +:10AD0000BD68B7350D7ECD16FB7EB35D8DE3F7B222 +:10AD100005BEFCFEF077288E7E9B555B4DF419B383 +:10AD2000328C631A6DE0F98DB19093DFF389F14BAA +:10AD30008B13F14BDD0DF5CE54F6A41E7FE40D040C +:10AD400092F4947915D131E4B7876C5A3EFEAEC5C2 +:10AD5000D8D006F243F77C3732D7E8E7323F87E6B0 +:10AD600006A6F21DC53D062EBC87205DFEEABF8A01 +:10AD70007D4DE4AF6AD2EA8CE9F5C868F17CCCD7A6 +:10AD800000738692D4C0E33AF330AE1320FCE3AFF5 +:10AD9000FE77FC9750EEF75BE85E7D5F440B23BFC8 +:10ADA000890B7E628EEF54C53D8347AD9CCF1E2D2F +:10ADB000F584DAE0D5917FE1E78D47CA9CE49F995D +:10ADC000A812FC55D1C82E7ABF7E9366C17FD2F9F6 +:10ADD0004D12F91FC9F775DD57C2FD47F70978B263 +:10ADE0007D9C0EE2EC2ACAEF1868E17C0EFF92E32C +:10ADF0007027E2A8B700EB09F487F07C3142F72E08 +:10AE0000C9A57C9C1CD33D4C33C51197FD68B1BBD3 +:10AE10001ABA963CDFE1477B43B767728EDF772330 +:10AE2000DA33AF9728C9F9B1A638E33F88F9A78B81 +:10AE3000338ECB71F29778994D41FFC889769E1772 +:10AE4000DC536CA5BC6DCCA344FEE213F752C1FCED +:10AE500028EF7750CFFB5519D1C1E03DA9F38CF70E +:10AE6000CB5C0F4DE437F2BCE2A219EE99BEE03C98 +:10AE7000E29D92B877284E718125117EAF188E829F +:10AE800078B4C7707FD57BE50FA78FE7D45C568475 +:10AE9000736371269657568BBC2D537C298C4E714B +:10AEA0002FE9F28CBF5ECDE9EB62F38C07AAA5BF58 +:10AEB000EA3CE36F08F8F567AF93EF5FA1C6EF01D7 +:10AEC000282CE479C7B90DF600E5B15BB59D74FF98 +:10AED00049248BA5CA2BCED7B4CD04348E939B883E +:10AEE00007CF6FE0F3D1E3C5BDCDA9F1ECBF4B7C3B +:10AEF000F8B555AE2C637C389457537CFD0CF1C8E3 +:10AF0000737FF49A0BD948D1F3A792F843DFF19FEE +:10AF1000127F50AB95A47BD3F5F8F11B91A9E4A463 +:10AF20008F1FFFB8A837C78FDF8DEF97B069F1F794 +:10AF3000FA399B39CE72A518275D9C259A9942DE75 +:10AF40007825E8D722F6C6C146ED45A857E559E869 +:10AF50007EB38F583CFCBE880312C51BDCA69DB295 +:10AF60005720FF897854B48FDC6CC48E71CB1B974B +:10AF70003B27F9BD3071EA1F14FD6F1B7124E9FDF9 +:10AF8000B77FDB91E44709B2DD74DEB411F6276EBA +:10AF9000D89FE0ABBF7B15810C9ADE33CB4D3E943E +:10AFA000EF2EE40DFEE97276CBABAEA74F19C67F4C +:10AFB000AE3A23FBF505F09F0FB10F511CA3E89F9C +:10AFC0004EAEFFB1D5F9F429D013B6D9D517AA7171 +:10AFD000BD314812F8C0AECAD72B52FDBE8ABE8E14 +:10AFE000EE2FC631AC8291A505FD3A2B582DEA8F84 +:10AFF0009DB57B9DFCDC5C4BD23BCCCF1D786106C4 +:10B00000CA5B71FF52BA768E00BF4F29DD7855E7D3 +:10B01000DAC716C094DD21EEAFF4143E146F82F24D +:10B020009D3F7669CE3C7C9F7CEEBEE3CBE3A7F1EF +:10B03000776ADC2C4369C77EF1BB5FF641D9536B5D +:10B040000F601C7599768A21FE80CC1841BEDEF90E +:10B05000656E77DC5F514CF32CDB7DC099CAFFDE57 +:10B06000DD4AC83455F634C435D4D7731A2378333F +:10B07000E1D438B9A8CF19E6A38F9B0EFE99C6D5A7 +:10B08000D77F4ADF378DEF38F606F276169B13FB33 +:10B0900015DD9FBCD5879760001569630BB05CC652 +:10B0A000ED69D7A14B5EC1FAD5326C4C21C8BD39D0 +:10B0B0005D71BCF739F21397864CB0EA9CFCEC3713 +:10B0C000D0BF04EB86F6C7035F89AA783FD2AD2BC9 +:10B0D000FDAC5DA1721CEB373E57A9B5035D384A44 +:10B0E00093E3156E8DAF95916E6E2DCC8A112E9FC8 +:10B0F00083F9025DDF2A71BA8E15CAC49FDF3C2036 +:10B100000DA1BFE281FF8C6DCF87F2D061E904C64B +:10B11000DD6F8CAF1D23BA8B9550FFA12FF33890B4 +:10B120009DB83EE509F83796766D47BFFCC6034DDE +:10B130009719EF4DDD78680F8DE7AAE0EBF680C830 +:10B1400077779726AF572CF66FFF8476F39BF82B13 +:10B150002D12CEFBDFA97CEB81CCE254F3DE18E7A5 +:10B1600071F81B0F04290E5F9FCFAD8786EC4D1938 +:10B1700089799EEFBCCCFB699EDF1611EFB20D7F83 +:10B180008709E3FCF177982EA3632AE20FDBD2FC58 +:10B190002ECDA7177279BE4DE499021C16D44FE844 +:10B1A0004E4F035CDB44F9B30BA594F4B6CD25FAFE +:10B1B000E31FD24F7620E9F7BD3EBB50E82B30BEEF +:10B1C0009A9BB8A707C76FCDC5BC03FDAF6B01E65F +:10B1D000613A906E49FE6E6171283BD17FA5E07B9C +:10B1E0002D4EBF3BA5C8A1AB6A910F58DF9930C661 +:10B1F000D9385908DB7B5EB4901F05C689A37EE26F +:10B2000066BC1DCD2798A25F5E94E13D6F1E9545FB +:10B21000B51A9C8FA97D48233B0114A3E855FEE98C +:10B22000FD99688F2205F9AB99FFDEB350E4B99818 +:10B23000F82F43E7C1D2F4FC37219FA2749F88A363 +:10B240004E3E837E0647E95BAD28171CACAEEDACE5 +:10B2500041CE27E23B6591A7C7FB3B1159509F6B3D +:10B26000E6EB5A107BA8AD389BF4C4494B1E960FF1 +:10B270002DBF0AD755758EA03FA720766439D60713 +:10B28000A35EBA0FA520766C793D9495FFF4711DED +:10B2900040C4C163E835E27BC1E21F8EE2EF9DD47A +:10B2A000081DA160712DC537154493E3DBF343C935 +:10B2B000657D7E4528AD4B12E3122830FFA2C5D62E +:10B2C000B1E5DC0FA9CD82717755648DE177BE863B +:10B2D000D54A023F0B44FBAF87DECCBCCA40473A9D +:10B2E000DD14958EDD8DF7C917E1BAA5B85F01654C +:10B2F0003AEEC303424FD1E949AFFFBEC0DFC704F6 +:10B30000BDE46EE1BF73F61D8C35A532FFFDB31FA2 +:10B310002C0C24D169CFDA1BFB902FEF93B85F7010 +:10B320008BF00BB2067E8FD53EF1BB69B3C5EFA69D +:10B33000E9FDF6B938BD769BF2807E25E6F12B411A +:10B3400087DDAD8706316E6DF4CC27C95ECF65E130 +:10B350003ED45F617CBA9F100887DF5722E25F7E90 +:10B360008EF333D06F6EC306FA9D85EE658CE25C7A +:10B3700086BE2B91FFAFDB36717533DA3D997208CB +:10B38000F599DB3B7EF832EAB3B7D755DC827877A4 +:10B390007B9D88337A3C2729CEA87B4D2EE52F054F +:10B3A0001BF97D85AC305B32E2F78F17BA92BEAFE6 +:10B3B000EFFFE81907E5D9C5BECBF5ABD82FFDF9EE +:10B3C00038CE903F4CF16FDDCB2274BFC8ED8D5766 +:10B3D0009FA6DFB129CC26BE767B23CCCB3BF3BC2A +:10B3E000A6E848F44B2757CDFAC4CED6AECADF52F2 +:10B3F0007C592F3D7B5B63F4EC6F3D44CF1DAD2347 +:10B40000F44CF417F7A4600C4909F2E9643DC35702 +:10B410009B2CFFFC91E472417372D959688ADFD486 +:10B42000C79FCB92E284FB5B1FAFFC6D19CE372E1A +:10B43000E6799ACA3B5AC7C5FC5FA6B2DEDEFC1DA0 +:10B44000F33CCDF332CFC30C8779DD5CC0AF909E67 +:10B45000AD82AE066B5F207DFC6B0B2345972EC142 +:10B460007BCF6244AF3B5FBDAB0B6D82C1731F1DD1 +:10B4700047FFDCAE42C6E364964535BCAFC7F59CDA +:10B480004B433BDD55B188F675343AECC4F8CF5DDB +:10B49000D131BA3738D0714FD2BC2A9C879CC8278B +:10B4A0008BEE497E3F58514FFA5401BB87E6ADF30E +:10B4B00075A6707C30EB2553FCF6DD6C8A9F9F49A6 +:10B4C0006F1D2DE57180F717F278E4FB4BF7AEC4E2 +:10B4D000F9DF1FE5FEB8FB851EF35629002E61D863 +:10B4E000E9E4537F86FA1D155C3FD5D749E7671E0F +:10B4F000C1CFEE6F55284E99D58DA7D42FBD578D4E +:10B500006CA6BC9CAA71A7318EEEFEC217C8FFA71D +:10B51000B028ADC7FD85C514C7B7A376FC5EA433BC +:10B5200026CB6CD6958C65CCD91BC6F5877D597515 +:10B53000A941CE0C46EF50B07FA023D9AE34DB9D9D +:10B54000FAFAB16513049F8B71BF7881B03FF5752E +:10B550007645CF92FD74E7DFC16B84D3886F449F3B +:10B560005DC437BD62BD256909C77390C47F9E95D0 +:10B57000581F8B5B5D8FF31C14718B31F1DC219EA6 +:10B580003B45BCFAFDA2DC2BCA5F13CF07C4B3F264 +:10B5900074838FE21E44BBFBC45387674E544EB680 +:10B5A000CFB4E4731B67615652BDBB343FA9DEBB09 +:10B5B000B838A9BEF255FEBD74F8E38F247F6FEE54 +:10B5C00096E4EF29755949655DAE1534E727F5F323 +:10B5D000541527B54BF73DADE15BBFB0907E69A731 +:10B5E000FBD25C15DBC7918FBA2A383F35EF8F4D00 +:10B5F000D899B0FEFB71FDF57566D9DC2EB4C9D1C2 +:10B6000095C5063FFA4E6FB439EC49EC2BB386036F +:10B61000ABDF03FED1429E27B2BB94D3CF6E711F26 +:10B62000CDEE0332F9EF7797F278FE6D45FD2AD221 +:10B63000FF8EAF009EC2D311BF9BE13D1EC3AD8CF8 +:10B64000E86404E3FA41CF7614465904DEBBAC81CA +:10B65000319287F7B220FA275CCED018DA336C37F4 +:10B6600094615C97873D45E5B8A857145E3EC5EBED +:10B670007B91FECA13F89757A849CBAB50CF0BC9A3 +:10B68000E837F9FDA56F7F15F139843FE360289312 +:10B690008A740563DF8332C6371F3EE758B904E179 +:10B6A00011FCCDFAE5282B31F2B7D05EBAEFFDCE12 +:10B6B0007AD8BEA5D3F911ACFB53C837779AF231CB +:10B6C0000E97F2FB7CE92F9BF24387760513657793 +:10B6D000A942F1892F5DCAF506A0F31F1BE9FCF012 +:10B6E000019DCE93F9A5997F9AF9E6EF2F65E2FEC9 +:10B6F00062C12743B28AFA9E837D3131EF20CDFBB0 +:10B7000015FCDE01316F9D5E1D6C9CF85BA9D64572 +:10B7100072A1AC2B1AC610C3D28E89E52E780E8882 +:10B72000F63FAF0EFF06E12EEDE2F79A7F6DA1FA2C +:10B730001A8E17E8B829697D8AEE492E17B09B68E2 +:10B74000FE663E5F722F289206B86AE26EA625C991 +:10B75000E3ACA4B241FFF6E37951B6383F1E6EADBB +:10B76000A538FE7B5B43F4EC6D55E9A9DB5B594CD6 +:10B77000213FBBC24608CED9F2781BDEC3B73814CE +:10B78000A0752BDC3D49D76C14958E48E20496FCDD +:10B79000F1AF5647E410D4FF1FF0900CC9008000B1 +:10B7A000000000001F8B080000000000000BED7D72 +:10B7B0000B741455B6E8A9FE77BA3BA9848424908B +:10B7C0004075E840D0009D104202112AA1C180E8D6 +:10B7D00074101510B00311C2BFC15FBC57870A09AE +:10B7E0009F302889220203DAA028EA8CB775FC7002 +:10B7F00051D734E123CE373ACA2817B541069171A3 +:10B80000307E71E6EAF8F6DEA72A5DDD4994B97369 +:10B81000EF7B6FADF7DA35539C3AA7CE67FFF73E63 +:10B82000FB9C24D55B14E370C6920A822C50C8D8C6 +:10B83000FA1F775439D219731630EF1AC6D8DA01C5 +:10B84000498C953066ADB0848608F0343139EC64AB +:10B850006CF8FE10AB85F6561B2F3B237F6DC7EFB0 +:10B86000AC05ACC80EDF7D87BFF1D06F4E4896A106 +:10B870001D3375664D1B167BBF596033F0BB1D77BA +:10B8800007D934785A2377B23CA82FF1C220A318E5 +:10B89000EB636081307CB776D16372149E4926F9E0 +:10B8A000A000FD333F2BDA2B41D926F172B55A7631 +:10B8B0008A07059827F3A96591F1B20C657838726B +:10B8C000C2ACD649FDBD632DC1793169889B8F2BF0 +:10B8D000B9E09903EB77E1384A84BE93989B8FD304 +:10B8E0001AA1713C5066388ED44EF51BD4B2E8E5EF +:10B8F000E54DBC3D630A8D9B1460EE8DF8BD0ADFFB +:10B900009F0D0F78BDB0AEA4D996531CDE9D2CE0E0 +:10B91000C4F621E687759F1D1628A1FA047CF45F02 +:10B92000CA14470A6303EF82A6308F1DB92C54084E +:10B93000201AD0C098AD04CB1D3FC772EEAD8C89E4 +:10B94000BA322C8765A5C7CAD00F9374F51A1E7634 +:10B95000E486B29D85B1B2061FC0BF84F84E8A3C12 +:10B9600041F0492A08B100CCD369EA6C34203CEE9E +:10B97000E2EB75DAA28D065C7F038787D3D9C1EB32 +:10B980006F55CB62849783BC7DFF82B0508978FF6E +:10B99000D63823AC1B577BFE7D8481B10CC6EC925C +:10B9A000F789333646BFEFE07F9DC303B3103E8374 +:10B9B00036943D71A620F63E3B20C7950B6C36822F +:10B9C000D3E67A436823E07773455E4AA08771B473 +:10B9D000E79ED5F0D110C6B6AD86EFAC8C3DB05A1F +:10B9E000A4726FEDFB3685827EA4671678C70AE3E2 +:10B9F000AC774B79388E2D325930031C6C0552B11F +:10BA00001DD6D9A2D2F1DA995B897EEDC837F04C08 +:10BA1000ABE67C63B7F172AA4F2D3B391F89B25A4E +:10BA20001679BDA39097BBF849D2F8299835CD1562 +:10BA30007BBF1EF909DEF74D0B05FCBAF6DA3C9A1E +:10BA4000F19911A3B7A47A8362053ACB1C11688AD5 +:10BA5000A7CB28D15D8B97F5D87EE488404B7CFB43 +:10BA600056A2E33CBFD780EB1FB28D490658FF16A4 +:10BA7000AF44E366F95A2B4DF0BEEF54788F5D1654 +:10BA80002A4C76C6FA033E3C654C66ECA723025B63 +:10BA9000BC19D8EFBA4FF5F46F9338FD0FD9C9E947 +:10BAA0007F7D3ED03FC07BF0364EFFEBF3819EA101 +:10BAB000DC7706A77FADDC672AA77FAD0CFD10FD04 +:10BAC0006BE52EB8E507B39C4E1DFDE7DEFEF6F7ED +:10BAD000D37F700DD1FB4E95BE6D813544DFDB54B5 +:10BAE0007E7006383FCC50CBA297D3FF545EB6157C +:10BAF000280CE97FBD4AFF3B4C9DC788AF2BD20481 +:10BB00004537AFCD5E03C16F876CAAEE894F667B68 +:10BB1000399F0446C8FF8E705B97BD20D488FDE432 +:10BB20005BC20E18675DBFC5E18350B60F4EA2F22F +:10BB3000FA45B78716E073F1EDE10528BE16ADA30F +:10BB4000F286C5EBA8BC36C342F0B5FFDA1C72C062 +:10BB50003CCC7D67D4EF4EC77E6DF4BD39736A5619 +:10BB60002D96FB39C30EE2B690E007B834AF66FB02 +:10BB70003C66C6FA99428208EBEAA70419C94B91C0 +:10BB800049081F1BFE1BE061AE67BB0D004FB3C829 +:10BB9000F615EAF8FA98BA4EC04E26F6D7D50F3306 +:10BBA000113F30673130398D13F2E4C7D6FF863745 +:10BBB0008FBEB38B0119E5AD299DD31DF41F2AD487 +:10BBC000C90390C704A74D9E6835E185D93A53CA89 +:10BBD000A09DC0A85FADBF839E5536E4D3F59E3DC2 +:10BBE00036E64439D26043BADF98539582E5CAFC01 +:10BBF000476D51786EF43C6A6385F43E13DFE77D50 +:10BC00009DCA94918C041CCEDFEA35C826A0DF6C57 +:10BC1000781F1A19EBDFCA6E554E6BF302F81A93B0 +:10BC2000E44EC4DBCED54C390DF0DBA13E37D64512 +:10BC3000AA2D0833838139C6815CAF07410E4BCDF5 +:10BC4000591AADB4C2FAF6AAEDFE382CF037E44327 +:10BC5000D7D0FBC441F0DE5AFE8680F50F0D97FF6A +:10BC600013FBCDDEC0F588D43C3B362E2E794358ED +:10BC700016E0FD80BBE2DFB37418B41CEB37F81993 +:10BC8000F0637F06F53675FE6E7CDF2AB3E1B8DE21 +:10BC90007475BD21827FF686A88CEDB3E13DAE3789 +:10BCA000496E6546A4FB824E9B45076F07C21BFA8F +:10BCB0002F00C5C08C08C737645C57969DF33503C9 +:10BCC000BEDE0B6D9C43B71CBB1BBEDFEC64D561B5 +:10BCD0001D5F661671399655A4D28BA8F443786F10 +:10BCE0001C2E67178D2278F62B8275B7207C747412 +:10BCF000D202F8D4CBFF9664B6C80FFDCAFED44A70 +:10BD000013DA2B5962D1469CA649A55351DC8DF21A +:10BD10003CBF88F3D7DFCC723EF67BD0B3668D0292 +:10BD2000ED5B720C212BD4B714DC4774D0A2D24740 +:10BD30006FFAC28AF4D147276F2626CD0839515CA5 +:10BD4000F0F55993582DCEA7441D6F8CBACE31EA29 +:10BD50003A374C7FAA9AF8B2C0C0705EF682E2858C +:10BD6000A664B447D2093F843F8063761153F948F3 +:10BD7000A5C3822E793D1EE1630D98485E5B73B8C2 +:10BD8000BC6685E971F49FF8D4F846E31351522A52 +:10BD900011AF5ABD5D607EE24F9322209EAD3E0EF4 +:10BDA0004751EE8C1811AE456211A0995DAFAE23DC +:10BDB000A980098887A4A2400DC2B30B3E398A40EE +:10BDC000F351E9EF87E6B3A980D30DD08FBF0AE620 +:10BDD00063678A411E847669A4B50AE023DA82EF9C +:10BDE000DF4DF69AC18BF25674723DAAF51350E1FD +:10BDF0005BABC29BA5031D0D233A9AA7D2D17C7CD5 +:10BE000076A7A3347B3C1D45EB391D350A161D1D55 +:10BE1000C92C9E8E96C7E868B99E8E3697713ADA1D +:10BE2000ECF98CE86873D93F4847B59C8E5A3CA71B +:10BE30006D7AFBA0518577E608F92E5C8706D72E30 +:10BE4000BA40FEEDD31DAE1BA6F79F4C74E653E936 +:10BE5000CCD7339DCDD3E8EC12F1659743B209E519 +:10BE600053458459A4981C602CDA82F2B83FC887E5 +:10BE70008D606BB480FEC7F96EF7EC995C05B5EB8D +:10BE800073DAED481766436B751ECA918D804F8437 +:10BE9000EFD483CC58D23BDFEE54D70FF0DE89FDD0 +:10BEA0001DF4DC377930F2ADD7E045F9D802FD0E4C +:10BEB0002941FE35A085D325E7353EB6B2D6637756 +:10BEC000433F7B36AC12033A7C2427C01F41134CFE +:10BED0008327D87556786E2A3E9F85F4B1A3BE5D40 +:10BEE000ECC9DE4C2EB96F1ACACFE4932F5E2FC077 +:10BEF000C7C90DA76763270F0D0F3C87F3DC5516E5 +:10BF00006D31EAE4BEEBB6FB5A8748DDE57737B919 +:10BF1000ADF231AB68253B2D516EDB37F48C47C653 +:10BF20005A094EC92A3DA4084C403B8D4D64C43784 +:10BF300026154FD92ADFBF5E9446F8043E9611DEDF +:10BF4000620EDB6DD4F9119B8A02BF41FAB6D6B1FD +:10BF500053D664E4EB0EB2DF98786972E6AD91E9EE +:10BF6000B42E33D0D77756E2C3377BE2C3C4A7C61B +:10BF7000872D1E03E99147974A71F3FA4CE5BF9666 +:10BF800011F27BD4DF88C0299C675B46D9140283F9 +:10BF9000294C764C9B007406DF2B6D5C6E98C1FFBC +:10BFA0007CB610E9AD91CBB75EF8FB7C8CBFCF635C +:10BFB000BF2E0F5370FDEF7A0317A8BCC9700AE5B6 +:10BFC000B0AB4495BB2A9EEC9B002FC3BBE3C5CE10 +:10BFD0008232EA47D715876D1E46F47111FB715600 +:10BFE0003E7A0CF57CCBC93BC4A1F0FE602B9723B5 +:10BFF0006D755C8EB4B51A48EE3EE201C5ECC6DE46 +:10C0000044A694924B83BE2C7BA46E157B0CE6FD5C +:10C01000050A026F77BA7AF49B3B227743FDA33F70 +:10C02000334B6BBCDDE9CC5AB1850D45BCFFCEAEC0 +:10C0300038B2BAD399D57786E859C3B726674C7713 +:10C04000A972A795AFD7EA498FA75F15FF974A272F +:10C050009AFC5833DC9F5D3C0AF1D14AFDA3FE2FC8 +:10C06000D6E9FFDEF45B8BC52FF99DB1FE925894A3 +:10C0700019DC889F908C767A2AC823A318D37B7DFD +:10C080008BFD838B47C5FC75A48B704FF6030A228A +:10C090001D5D0C2BEE9243C3E87B8F81E822C9978C +:10C0A000447A18FC9D627A5FA67C8AFE8FE6EF5C7C +:10C0B000AA5CB5564465E44BB0C35E43FBD7A3CA44 +:10C0C000514F4EEB76948FCC600BA2DDA5F131ACD5 +:10C0D000633CC2C7D3AAAD4395ABAB38BD231FD4D5 +:10C0E000E8E233F5C55D7C3311BF4B6C2F4F3DA5A6 +:10C0F000C4C9E184F55F1D5BFFD5C56497445E5BF1 +:10C100008DED030609EBE14976720F76F1B5D8FEA5 +:10C1100061D5CEDDA5E11307C0EF81BEF17BE9D685 +:10C12000CE46A4ED3C456CC7E72331BB780E7EEFCD +:10C130005AB44A1C82F2724347A58DF8489E8BEF91 +:10C140007F489E9AEEEA458E067A96A30783F751BA +:10C15000BC649BCC24E4C3B537AFB30F41BA081A13 +:10C1600018CA6F31D2B24641BE09184276D44F8107 +:10C170003CD233BDD1FB26351E712FC62386905D80 +:10C18000C3482E7B795CCB6AEB405F07614D712D14 +:10C19000AB33CAEBCBD4B2D8C9CB15BC7D0BC633FD +:10C1A000AC3ABB4D0E119EEC725AC408B2D685FE55 +:10C1B000976EFDE0979F320F27BA22FCA594258148 +:10C1C00009AFABF7A4C5B53717788FB9611CA3CAFF +:10C1D0002FEB727C32FAF94F0F0B6C46BA59678815 +:10C1E0004E42BF8FF5F3939F263D2778312EB6D16F +:10C1F000CCE315138D1529A791EE41A698FA42FFBD +:10C200000297570F17733BCD2C8514B413CC0AF348 +:10C2100086242402DE8F0DFA8940D39F00BC7CF96E +:10C22000389EFFA7389E4D8A5A908FB4FE13E1FBCB +:10C23000A84AD7CCA9DA45A64081DFD53B9FFDC7E8 +:10C2400030FF63D82FCE13FD3F2BDABD3DF4DB3931 +:10C25000BCF2C9628A97788F8D87F9AD75336923EF +:10C260002CA1E99B09368CC7AC1D6641A79655FCED +:10C27000E286998D1EF2F7D85433C69DE009F36F1C +:10C2800072866682C866E52399E2CB01B89902D529 +:10C2900028A77FF9EC5D33D3619EEB10076318FB91 +:10C2A000E6D99DDB15E8AF492D331481F0EF1D76FB +:10C2B000B5ACEC9C7929DF33D6417273AC3570088C +:10C2C000E7EDAAB791BFE82AE9B4A07CB860E6F12F +:10C2D000D9D47AD62CA6C4D6593E92C32F558D6791 +:10C2E000A56A712CC6E357D1621E67FAB38ABFAF45 +:10C2F00055786705A2DBD04EB6839240B971AFDAAC +:10C300007FFFA5AD95F85EAC007F81CBB3462C27AF +:10C3100007B85C39A17E0FF6C53BC8BFA21C656E8D +:10C32000F83E5506390DEB133D1D0A7E578E3EE94A +:10C3300028B2CB048B9BFC8CF7715DFDEAE3DB3B01 +:10C34000EB9446F44BB4F6F72C02E88D80A73A9FA5 +:10C350007EF57C3E2E753EDABACFA9F26C74B1FC44 +:10C3600021CE43FB5E2AF69F277953DF2A5B74F3C5 +:10C37000D8A9F6BBB3ABDFF041EA57E67E51568051 +:10C380008F9354C1CB5FA8EB3C58247FAEEFDF57AF +:10C3900014B8C8F1136240412CA50EC6D1CD5F7B05 +:10C3A0003A87FBFF13BF5B5A1F3EAAAFD7E1998DB7 +:10C3B0001CD53B9E13E959C373BF812C48F31FE47E +:10C3C00037A0DC685B59FC4823C0F75E9F65931774 +:10C3D000D63760A485C7A9523B66A05E6DBB5BA43F +:10C3E000B828E0336F0DFA63912786A23C144BD234 +:10C3F000189228FB06FA07BB44443E8785DF53C6E4 +:10C40000EDB6CF2AD86EB45BDABE053B14ED9A4A7E +:10C41000F6CC1A80674AE4AFB42FD07637E7E71638 +:10C42000553E6AF34CF1742AA8B7532A0223118EA1 +:10C43000A3464A34EFAE7AB993E4A5BD203008E5AF +:10C44000D28ED4D047189FBAA7DC22ED81F10E9589 +:10C450001F6D41FBAEB5D122E3BC5B17CD36C8F0F2 +:10C46000BC779421C4608EF7DE1D7D1BDFA7CA7CDC +:10C470003DA991D7260FC2F2B13E71EB49C5F50C2B +:10C48000C217D1B75350DE57F4253D97EA13855AAA +:10C49000576CDE62C42EE07A36ABEB113D8CE28342 +:10C4A000A2CCE7AFCD5BF4B14AFDBCCB13D69584EB +:10C4B000F6AE4E2EAF35FBB3306E962867D6B1F888 +:10C4C000388AF60C8CA894911E3439F843F6C6A528 +:10C4D000B69BDF30817D00B4F782A5F3D0770007EB +:10C4E00065AB10DA0B7078714BD1245CCFCDE718B7 +:10C4F000C16DFE9D57DD7F06ECC3F23322AD73FEA6 +:10C50000CE542FAE7F79477012E3FB05DE7CE0D777 +:10C510004CA37B7F14FAC97CE4756F1380E08176AD +:10C520007613CAD34CE3CAA29528C79CB2E404F898 +:10C53000D732AE37328DA993300E9D79ADC5DB0C65 +:10C54000DF7F6C168F1E41BBDE9ECCF642B9367C77 +:10C55000672DE3F1C954D457B53691C6B349625A31 +:10C560002394339398CD5ECC58E91AF1E8BF423F4B +:10C570009D8B5CE21E90CBC965E2D19FE2FC8303F8 +:10C5800044A337A61FB5F5DF2CFB2DE8C75FBECF50 +:10C5900012879761E1F8F288FDF1E5A2487C79E421 +:10C5A000B1F8F219958F1B58D842765D8005F78255 +:10C5B000DEFEC876681BC26F91FDD7DBB0CD4BDFC6 +:10C5C0001A19AEBBF3094708E91AA76786F92E7E48 +:10C5D0006AD86ED4432FFCFD168A8B74FED6E8DD34 +:10C5E00003D52F5C069281F611420370DEE7773C9B +:10C5F000FED09D507FFEC9CC3424E5F673F3DEFBFC +:10C600001DF4B7C4E06248FF1756776C433D3B61A9 +:10C61000C9CB03500F5ED8FF8B87106E7F7EDACABE +:10C620008C30DE9F0DAC1EE9F9E089036777E0B836 +:10C630004F3B8AD02EFBF3CF5F1C8CF189C54FBDD9 +:10C640003200F7DFCE3FF95429959F7C62383ECF08 +:10C650003FF1F8E05ABE0F36A0C615EB67C9CFEC24 +:10C66000A7FA0CEF9DDEFED17E97A8FB894B7EB624 +:10C67000BEA30F288925FB5C0A3E17EFFBC9A7FC68 +:10C6800029BCCE9F8D54BF18205306A6CE472E2E10 +:10C690001F97ECB3C6E165C8B6783C7D0472F459C7 +:10C6A00068373414FFFEAC00EF61DC820BB3A7B82F +:10C6B00093793B9CC759783E03ED57C0FB54787F74 +:10C6C00001F9B407BBE2C5915C9FAED81F3FFE01E4 +:10C6D00053CFED5F51E576016A0B9D5DDDCFCAE575 +:10C6E0007862FB436AFB279FEC6A6FFCCEC8BF935E +:10C6F000C01E5BA2F2D54BEAFE12FC6EED0FFCB63B +:10C700000489242FF67E09D3AD1BC6FBDC96BC073B +:10C71000ED86C56AFF17CD9C6FCFAF96EF3F0374D0 +:10C720007476B52CFBCCB1792CD8B6F26836D0CD66 +:10C73000D267328AF57270E9138F186E84F71F83FF +:10C74000FEC688CDD2998FDD3B06DB3D610CE3BC94 +:10C75000963E71A82FEE277D1C3E928CED16EC4C78 +:10C760002DD6EBED85DB26CA3E9DBDFA8FF2E78B19 +:10C77000655C8E2D099B4336019F6F4DEA8FF263F6 +:10C780009BE0CD87714A4D0123EA4557896C56409D +:10C790003E8EFFE69747FB41FD8A574695929D6B7B +:10C7A000F05F7B35CA9F878C14BF7AFECD7946E453 +:10C7B0009B85C398C10846537BC17D96D330FFAF9C +:10C7C000543C6FBCDE598F71BD52133B6C003994E1 +:10C7D000FCA820ABE5B70D408F4C6E9D1B81EFCFC1 +:10C7E0001992BD1B4B883E497F2A3F37929C1D1FE3 +:10C7F00059FD071CEFA39F99BD683F2DDC164F37ED +:10C80000F52F9B292EBC626F5332EE43BDF0772388 +:10C81000E9DBCEBD02C9852EFF0F909005E39FDFB7 +:10C82000EDDA20001ECF67840688883F5768401ADB +:10C83000FFEE26D4F7F5FB5EFD2BEE272C0AC58F05 +:10C8400093480FFD4B04D51E61057ABA4A6C8712D6 +:10C85000C9541AAB5FDA007A42B78FB2F44CAB0519 +:10C86000FDA745532DDF3B1ED02593082E7682CBA6 +:10C8700092CBC283511E0A26B1AA399B9A09361857 +:10C88000E73CFE6B102F3398D762A46B20D9CF4FB3 +:10C89000BE7AAF11E8BB9F31FCDE7294BB008FBD46 +:10C8A0005CEEAF7B3A9DE414437F5B9BD7F2AC3FD9 +:10C8B0006CF3E9E2831FEFFFC5BADF21DD069C14AC +:10C8C0006FF9588A24A701FC0EA8FAF8639197B56E +:10C8D000F68DE143C9B8FFB424DCA70AE301077E63 +:10C8E0002EA41900EE1F9F7BCCD1535C78F1B9B414 +:10C8F0002ACBF0EE7249D3C3A7F09F408F5525F2A3 +:10C90000152508F7E63EE49F65F60916057BE84F16 +:10C91000FB2ECD76FF4F11DEB56ADCE03E73B088AA +:10C92000E038C7E9DDEBEEFEDDE412CEDFCDA5FE9B +:10C93000A9384E5655878C71A8AC29CCDB045D7C98 +:10C9400060F4DE2E027C6F66010BC2903567D03C2E +:10C950001632C023C1DD3B09F967F1548027F0C3CB +:10C96000FCE9ADA48FB7AC645E6319944DA1755812 +:10C970009E0F16C1FD22C6D3AC4CD6F1F3822D50CA +:10C98000D6AF7FA7AE1EF0B7F8D1F8FA252C42E358 +:10C990002EFDD977567D3F5A3C1418CC82F6F2977B +:10C9A0002AFC9A4BE59B715DC2341BF9CDB7FC5C48 +:10C9B000A0785BBA254CF3EC8479A27D304BB57B33 +:10C9C000FE64F4D37A57DC592BD741F99386F97278 +:10C9D0001D809E5411CA8D30B78796F8C247498E84 +:10C9E00030F1D91BC1F75D6AF373BB4762E2953042 +:10C9F000EE989FD5D0BA593D13AFEA0FE5FA1A82E7 +:10CA0000D39820592E6C968A27F626C7EB0990A555 +:10CA100058AF6CE7FD2F640AC17B11EBA0F5AE297E +:10CA2000E1F1DB6307F93EEFE7FB5343565D9CF40E +:10CA300073E64D41FE06FB87D9D3BAE33911CEF533 +:10CA40003B13E0AE87731EC2371E4FCB9F0378F7B0 +:10CA500040A70FA8FAE33D8CAC66EBE9B191F0F189 +:10CA600040A3C0F58E5233F36698F7D699A52457A4 +:10CA700037030CD0CEA58ECA50CE32CD1F8E600AA1 +:10CA800048D2C8AE32D597AEE1E5D0733F9AB5AD86 +:10CA900002FA3107B2D15EDE5A6361116E07D9D155 +:10CAA0000EFA7074602FE27BBED17F14E316672A02 +:10CAB000E5C144B70D1CCE0F160787067BD0BBDA45 +:10CAC0007A36A7061B892E8A98B8A788E88ACA8E64 +:10CAD000414C44FA760DE078720D4F0AADD1C13F5A +:10CAE000D300266A0F70EFAA3731C599464FE6C2C8 +:10CAF000270CE8FA9EF69A7D9A795970258E9F69DF +:10CB0000905813CC27D3112C5A55A8AB37B556E201 +:10CB10007CB280EE14589FEBF42D95D8DE55CCC432 +:10CB20002698EF5601F819E9EA6E81F497E3E56774 +:10CB30002248B7CBAA2503CAE78C1B36D1F7F714D6 +:10CB40004B068C27FD5195F329AA9DBE5D68CBC687 +:10CB5000FAEDD99280FD953C07FA0CDE2F7BAED220 +:10CB6000B8CC4978E4F6BC23B81BFDA0CC9B0A8A5C +:10CB70009B807E4F96483C3E3BB2F5207EDFB9520B +:10CB8000227866AD51DC38FF947615CE351CCE196F +:10CB900037DCD588ED7ED28FA5E13CB258A380ED7D +:10CBA000D66570FA5957CBED3013785AD82E678670 +:10CBB000283496633958C9F94E4CFD753645319B7A +:10CBC0005340EF3D90CCE7956130DE5403CF078AA8 +:10CBD0007939ED2E41DE43CCDC46F3CBB4B26A2189 +:10CBE0008DBFC77501E9C9CF3875F09DC0E19D398A +:10CBF000883F87DA8E39EF85F16F155810F5F76F9A +:10CC0000D2353B3CE244FAFBC42C678E4479FBBA34 +:10CC10009961FC2E7D407C7D9EA73A05E3935F7869 +:10CC200027501CF10BA79C920ACFFD685FF520D717 +:10CC30006DA3383E567CDD9F8574FA69C58CAFC8FC +:10CC40005F59F1F580B8F71F839F1AD2F9D74BEBE4 +:10CC5000DB2761BB65AC631DF2CBB2B09185747C00 +:10CC6000BDDFCEC7BDF8AE95E4CA2D2D83F618DD25 +:10CC7000DDF978C5D746CA1B6850E344B1F12DF4FD +:10CC8000BE6B5E5FF789DB678BB5EB1BFFFE6B212D +:10CC9000BEBCFFA2DACE44EF59593419E578A29F01 +:10CCA00034D668A0F93293948CF1EEB10359571938 +:10CCB000F313C71A052A6BF6FC54D0EB7594EF00FA +:10CCC000EDA1BF0BDE0F9211EEA74D5C8F9F0E19E9 +:10CCD00094FC1108371B53006EA7553B5EEB4F9B2E +:10CCE0009FF6FE821825BDDFCF08F63896A5689C12 +:10CCF0001D80F508E70B3334B91431E1783BBC07EC +:10CD00004D1294977A0F4E623AFA8AE1C5C1141D0A +:10CD10005EFA3675440CC06F573FBF77472138DC49 +:10CD200019EDAA3C541EDF21E740BDD110271F1D7D +:10CD3000255DF292C4F403062397AFCABE1DBE0A56 +:10CD40005D596DDFF5BDF2C42C8C379614F2EF6F90 +:10CD500078FEC9136B4C3A7D6AEA1C8078E82ADBBE +:10CD600012CA4E280FD395C584FAF484FAAC8472A3 +:10CD70000E6F3F37253A0AFDF279CF3F3DCB047C59 +:10CD80003DB77FF43601CA9B8CCFCCF2015FCF2F29 +:10CD9000E1726CF9CB0266C275C16FB997917DEDF6 +:10CDA000F4462DF30B110EDEA3186F5EBA5F10056B +:10CDB000E03F67F89908CAA5A5F89DA4FB2ECCED25 +:10CDC000F2A5E153F45DAFFD1718482E6C2C384DD9 +:10CDD000ED9635FCC582F6E5FAC2557ED4CB7F339D +:10CDE0007339676201B93FE60BECAF51F342B93ECC +:10CDF000B9902D1FC2F928AF0822CA832E7AC77EA8 +:10CE00009D31FE8AC5AB5F7E0BF7351DB77EDA8894 +:10CE1000FBEEEF2EFB70148EF71FD8A41CE579688B +:10CE200028EAB3D9F5F386E2FB39CBF20F62DED400 +:10CE30007BE6E82EB453F73C7F749609E0F59E2B11 +:10CE40009A2B805DF3E8F3AFF372467417C2D3FDFB +:10CE5000C21B04DFF772A3B9E88F3DF1BC782395BC +:10CE6000F3A3BBB07CE6F9CF78FB61D15CDC471B58 +:10CE7000A57C4EF0DF2B72F9F910F8F72887FF2315 +:10CE800041DF6F53E5D4816AF9FE51B89EA55CDF9E +:10CE9000CEDDD13113E5CA5C03E827A0E7BD1F7FD3 +:10CEA000F0F3BD008FBD0D0EB68793A31FFD854C1B +:10CEB0004EFAA04F5A490F74BA412FA08DC03AA222 +:10CEC000B85FE01865A3785C62DC06F4E333A41F66 +:10CED000E71692DE195B22E79566C49E5F54C11384 +:10CEE000DAE7954A6A3E24D8C3D0DFECD94E2FC684 +:10CEF0005598293A0AE971B39DAF0FF888F0ED54BF +:10CF0000F1F36FA3B85FF76FA3B89D3CBF6422F540 +:10CF100007FE8982F98B4A8D85ECB52D3572761224 +:10CF2000DABD357D0D4A5CBCC64C7ED916B425B041 +:10CF30007E597E08F304FBA14D823C7B3FF76FB422 +:10CF4000F5CC4279A5938B5B164DC846B9B8C52D73 +:10CF500067A39CD1E46FEF72319C112F17C3193D69 +:10CF6000C9453064336A74FB26379A793ED08DBB4D +:10CF7000B93CEC7AAFEE9768FD5CEAFB2DA97CBE6C +:10CF80009ADECD6C0A93DECE7CD09D867842458DAC +:10CF90007EEBD6B6217B100F1F8E9E4670DD52F3BE +:10CFA000987D5E618CDE3BABE5774701DC671979E4 +:10CFB000FC43A32BFCE13ED9FCFB3369BF32AF94A9 +:10CFC000E3E78C01EC3DE0CB43A335BC33A297BC37 +:10CFD0005291EA67B3E86DC83FFF1F7FFFDBF09710 +:10CFE00081EFFFABF85BD6F0E1A5C95B958FB70A7F +:10CFF00011732697B764EFE27BCCB33E5C1228280E +:10D00000D5C98DB9FFBA2C9BF6EBD5F938EE78B1BE +:10D01000FA0628CE5D7C9EE4D3DC7F7150FC22D1E1 +:10D020003F7014467F7E0FAC3B8DB944F493DFB361 +:10D03000448779D1FF31041E7911C7ED6714415639 +:10D04000823FC4D4FD49BEBFFB7E79A02FFA3D4A82 +:10D05000A991FAC1F806D3D35F8BF78F77F748878A +:10D0600046A2BBCE578CA13D02D26168FB02ACBF89 +:10D07000AED0AB407F7695DE801E65B2836FB45034 +:10D080001EE6967C8342F43A3389F641B6B8F978C5 +:10D090005B661610FD36304ECFACDE40E3F7408FB6 +:10D0A0007CDC7C038D0B7600D94F31BAEC4C46B852 +:10D0B00076A7CBCE647D1EC2276A9CF313B4B374EB +:10D0C000FB909FA87114AD9F4B7DAFD165DF266D9E +:10D0D0001E9C0ECFDC9749717260AFC138CF65A539 +:10D0E0007CBF4F93E787460716A13EE8B2EFD5BC59 +:10D0F000B3F99B73897E97A17E80F6EB5D9CDE770A +:10D10000DA23E4F7186C522AEE2B3497CACB917EBF +:10D11000D638922D08970F819EFB807E0A64AA71F3 +:10D1200011D5BF741406C8CF9F1B645EB467168206 +:10D130009A1C578CE413EF5F336689958DDDCB180D +:10D14000F78B8F6FFCDD1ADF5EE9CAEFC7796F13CB +:10D15000566EC7796DCBE67EDFFB42F408E6C5CCA0 +:10D16000C338034CEDF38F930C02C885D3EA7EE1FC +:10D17000B1DF8CA4FD702D6EB04985D7B183A52990 +:10D1800018C7D2DE2F679D14C700920E6E86F5ADCC +:10D19000488E127F363099EFC3282E09E94D8BAFA8 +:10D1A0009C6D31525C8221A84BD0AE1528DF63A95B +:10D1B000ED1BEAC756CB8256E08B1D833B27A15D52 +:10D1C000B4A38A05D12EC001287E875F42FBAD96AD +:10D1D000C05051E70FAD488A0E20BB3AA3D382FD61 +:10D1E0005EA885A1E1BB15CAB7AB71D338D16FC2B8 +:10D1F00078BB1E7E1790D48B7BA2F3D3C944E73053 +:10D2000027F2F72FD1AFD0FC892EFF20C19F48F421 +:10D210001B7AF327961B4E0D5EA5F32712D7B11C80 +:10D220003EAD28A6E76123C68F59B4B4A77C87E535 +:10D2300086D3D44FE2FBAEFA6D1F7E8B705AFE5C34 +:10D2400042DC2781EE96C6CAC27702E24357EFD688 +:10D25000C9C112557EF858285FC0F8392F3BAA3B48 +:10D2600042E83FAE50E36919EDD149083757499874 +:10D27000CD43BFF11CE7C7312FEF3E847188D4EA5C +:10D280008E5C2497156A9C38D1BE2B7FB9CD88FE61 +:10D2900052838951DE08B3B9485E01FCCF607CB689 +:10D2A000AA69B8847EF85F56EFDB79C60C65C7D0F3 +:10D2B000934FD3FB1409E7B34CE4F98E6C06978BBC +:10D2C0000D363BC98BAAFB87D03C3F1C1DF818F9D3 +:10D2D000BACEE02D453E7698C24F7540FB9B9B9998 +:10D2E000D48834C9C297E37E7395854918FFA94A4B +:10D2F000E3FB509549430BFF04CFF6D3EE4233CC0A +:10D300004F186D22B87C66953F4739D3DBBEFC775A +:10D31000AA9EAB7ACF1E40FBB22AC94EFA61F37DBA +:10D3200043F658695D6192E3755BDD69C837DF9547 +:10D3300072FBF3C3D1FEEF4A797E4A29EAB90BAA00 +:10D340003D5365913CC8172F253DE8C375BA41EEA2 +:10D3500018B2104D959E74E0A7AA2CA6FE5A9B8386 +:10D36000505F0303EC00B9B4BDAA230BFDA2EDA5E9 +:10D37000166F130C318D797391AFAF1242CDA82F78 +:10D380004C2C2717CFE354FBAC5E9CC7646B6B0936 +:10D39000C69DD92273EA591B85D3594F7416D3976A +:10D3A000267656E33F68BC35A9230BE7B7D5025371 +:10D3B000433EF3F2723B8CB591E26CBC3CD5C6CBDC +:10D3C000ED334F64211CDA01E6422ABEFFA384F547 +:10D3D0009BA0BD1178F51E21B89BF2D5F0244139F0 +:10D3E000D67710BEF185351BEB5BB763BD45E471A5 +:10D3F00031E6357F1CD5C5953393787B038CD748B0 +:10D40000FDB18840FC95937AF6F2D8FAE65BC34505 +:10D41000741E66058F9FEFAC9477B442BF3B0556F0 +:10D42000D30428F0240D3B83FBAC4C19E036831F5A +:10D430005D339AE3B73BBDCA86534847BFCF2779D0 +:10D4400018A3573BC9CD2AB02351EE21BD22DD34AC +:10D45000D88696CC23BA97EA22D80F4BF6A25D72F3 +:10D460004B3EA7CF5BD68A9222125D123DDE227818 +:10D4700033318E5495CCF31B6FB143F97BE4C1BCBF +:10D480000D4616D0D9A9637F620D86B89C7AA80193 +:10D49000FAAFBB50588CFB4F5A7D9D85F79BD88FB8 +:10D4A00035ADB26634FA458E0EC217E6AAE1FEF635 +:10D4B0003D4207E10BE1A8103E808F4A882CDC0A30 +:10D4C0009D2389C7B7D6DE64E2EDA7DA4E523DF65A +:10D4D0007929F87CD47ED59E20C149AC3103CDBBDF +:10D4E0000CBC7F430EEF6F7B953214E979FBBC24B3 +:10D4F0002FDAAF2F59C297133D27E05BCB4F6D2E2C +:10D50000F52F1B8D7A15E8D54EF237308E1A994ECD +:10D51000911E5B70078F07C7E2F4216E07A879ABF5 +:10D5200089FAFB0206A3A1EAC2B34208C7C7FDB647 +:10D5300078FD1E21BB6119F0EF46943BFB12ED858F +:10D540000E1A7705E8E11D22EAD5F8EF57ECEF79DE +:10D550003FE4258CAB17C7ECA0587C93C376C75625 +:10D5600037D9DF51347629AF7F0D7D877153AEFFF8 +:10D57000E4EC9B916F17E5113D384CDC6EBFB9753B +:10D58000C89E46D5DE423B4D8BB76AF2E9C3D15502 +:10D590003B107EDBCBAA1EC02705F52E254F456D1F +:10D5A00087F1D6EFDBE71AA3EE9FACFA0BD8356014 +:10D5B000571E50F7E5AB5FCBCF44BB66952065A205 +:10D5C000FDF2B8CA8FC70E0E8E7B7FD618A07D9E47 +:10D5D00018FE221C7F2A1E16231E68BF30B08EF054 +:10D5E00052CFF1BDD4C7ED3B1664E255E51CCF9296 +:10D5F0000EEE88577D19F128F580C7E588472FC7BB +:10D60000A3148F37B2E356009D235F205EE3EAB791 +:10D6100070F8D4A27ED5F16F6AF36E232B8CC127EC +:10D62000A55876AFC538CA6BE0BF026AFF8455E4DF +:10D6300077C9A568DF3497563D8C7C9B847E672133 +:10D64000FA5DAC1EE902E3F9789EFBC26A26E3B9F3 +:10D6500040C07FE9B41EEC8D8D07ECF5484F7F503C +:10D66000E1ABBD5F3BDA4CF443FB356857B5585529 +:10D67000FF411A80FD94E675D95594D751A7E63538 +:10D680002CBFDE19C0FE4EABFB49EF8FE67AEFFDF3 +:10D69000D13C3F4D2B6BEB83FEA99FA491F171F31D +:10D6A0003F75B5E3F17D660A64935F680ED96F76C6 +:10D6B000A37DEEA7BC398D7EB65AA4DFA3BDB0759D +:10D6C0004D8A84F9F81A1D1D3B3688ECE33A551E45 +:10D6D0007C3A3A8DE6F11993C82E067AA27AADDC2F +:10D6E000E54F9D33909DD1DDCE5C1597BFA3F91F0B +:10D6F00007CEF50BA1FF01F626E5C1753E6357E1A4 +:10D70000C5F5C781E78690BE00FB93EC98CE575CC9 +:10D71000941FF49139B01DF95279269FFBB92CF46E +:10D72000C46338FF97B3296FE02CE6FB9829CF84B8 +:10D73000E717EC77901E6A88EE765C06E54F04F6F4 +:10D740002CFAAF1ADC0E74F95D2107E2E96CAC7CAF +:10D75000F9B53AFC1FC0FC1E8C9B5A2283F5FBE1F5 +:10D760005A59CB53C132EA9F97543B6869122F0F25 +:10D770004C0D649765607E19CF135A9A0CEF9D97F4 +:10D7800002BFCF9271BD9D02EBC0FD5A4D2E1DD838 +:10D790009049EB05F83141071FF047C88E3AFB91DD +:10D7A000610FFA23638D9FBE80F9519DD946CA0748 +:10D7B000FB48DB6FFD77B7AA9F3B0B101E800F8ADB +:10D7C00033AE39CFEF4D38F09840FECC0153EBD15A +:10D7D0005DD85EB679D1BF3FA0FAB3844AB0B31624 +:10D7E000A82235118E5BD5F56F314B03463A63EBBA +:10D7F0005EB1C14AE7A6579C3B3D1BCF15ADA8FFC4 +:10D80000662E3D13F2843E11A2F70EC6F93D6A8DD5 +:10D81000E503E5F5E0EFD83EB6609EBAED20EB44B7 +:10D820007DC9D23BFBF6E427ACF868A3DFF83D796D +:10D830005989E3937F5D4A7A8794E48A84BC24A65D +:10D840002F1BBB97679469FC18FF7E5619A3F70B33 +:10D8500012FA3B63F64FC23CA2CEE705925B67CD5E +:10D86000A19177C2FBDB46066ACB325420437DFD93 +:10D870009F93B8BF0FF4897E156BE5790967CCF2E9 +:10D880005C9407A9BE88659ECEFEB9A38CFBB7F356 +:10D89000ADDCCF02396FD1CB35ADBEB4AAE77DB8D0 +:10D8A000DBD575B83AB81EBD8D3D62D4C7396E2F31 +:10D8B000E372F08E3289FA19788EEF4BDCC63E3F68 +:10D8C00088E70B96868B68DF7BE05D11923F67CC23 +:10D8D000018A239C110CC167D1FEDDC4F394163C70 +:10D8E00025903C78715FA5D105F58B770A5EBC8FDA +:10D8F000608CEA4F2D00BDC5E3123CDF11D741F02B +:10D90000407D5584F189A78DB4BF7B8ED139DE650A +:10D91000ADAF515E42D62DCC6BCD4278078EDAB8D2 +:10D920009DB46A7D764C8E2697852C9877A7C16723 +:10D93000B11CA0EF16D7B35456145B67623E12D3E6 +:10D94000E70DA17EDB174FA7A8DFE2F35BFE6E8D2C +:10D95000A717E592F4B9A6BFF6947139ACE9F14482 +:10D96000BDDE5C2A3F52C6F1C8F5CF3302CFA74CCB +:10D97000B4AF543DAAE9E385AA3E3E6BE4F6C0028B +:10D980006B1B3D5F2C73D3FC16B3A89AEFD2694191 +:10D990007DD21B1DBCA8D2D1FE043A587A2E72D477 +:10D9A0004A70F7BE40F92277B1880BF87081295888 +:10D9B0008BF3EA07FA9EF2572704683E99B73011B5 +:10D9C000F7FB17602E44F13F6E6724DA15897684E1 +:10D9D000365F8DAE12FDEE317785C89E38BA5ABAE1 +:10D9E0001FFD14A52AF830E6F12A6B4CAC099E0FF6 +:10D9F0003A7EFC7814E6D9A05845CC2FBD681FB7F5 +:10DA00002D15DE0B06535000DE9EB49EF1F8F8FB98 +:10DA10009AFF131C81706B6AE1F2B0A991E3F7CB16 +:10DA200032BE6FF41FEA33B99CC3AF1DC7CD67EC9C +:10DA3000F0EA021A7F92ADC884F98A3EB14821BF4C +:10DA4000013AEC034FD41D688F1A5FB6F2B813C8C1 +:10DA50002B27C8E32B555131A9FF151184E72197D6 +:10DA60004532F2FC342642FD24FC07B4BFD2B9A0F3 +:10DA700019EBA719583015E6BDDC1A5987EFBFCA54 +:10DA80007E7D2EE2FFF6A41A13E2FD2D31D089F23D +:10DA9000A7CAE6F5DC42BDC8265CCFAF4DF2A7F8B9 +:10DAA000FEB849FE8CCBA71CF1ACA33B7D6BEB0110 +:10DAB000FCD3FC2720BD61FCC32935E351226396CA +:10DAC000E0A5B37E09F337AAEB6B7AC51A5A437106 +:10DAD00077EF4E84F372A329C8EDD3F8F568F04AC6 +:10DAE0005CD7525BE0E15403ADC35E0EF0FD8B39B1 +:10DAF000F0B868A4F8A609E511AC23A99CAFC351FE +:10DB00003EAAF775C0EF702EFA69392CA4C65B15D2 +:10DB1000F447418AD37CFE660E64603F26D1AFEEA7 +:10DB200083CA8CEF072B71F6DB838EE4028CC3343F +:10DB3000B0242FE2CD23FEF861A4A7238A89613C9B +:10DB4000E78EA4E43D2C05E96A4008E3565FE76BE5 +:10DB5000791401CAA3389ACEE3E2474FBAC86F16C8 +:10DB60000E1989DE8EBCEBA0BC9C23953DC75F0AD5 +:10DB7000CB399D1D39C8E9EFA88DD3E9515BF61E5D +:10DB8000FDFD1DA3CAB93CFF326B9007F71F7AD386 +:10DB9000970FAE06C9A2CBB7187B932588FCFEE091 +:10DBA0001C0BD96B631D43E3F229AAD4F3879EE9CA +:10DBB000735350FF1CFD0B2B75C33A7DE55CBF8C86 +:10DBC00035BA6F457BFCCAAF8D2C0222AAE0E30E6A +:10DBD00011F38BAF54EF93A98AD6E60C807E0FD950 +:10DBE000338B915E0E9D72E708D05F7BF6107A76DC +:10DBF000CDC396391FCF297B8E5D7D3219DA7FA97F +:10DC000058A58DC807E65681EC1E00679FB1841E9B +:10DC10008A13112A4164B1663112443B6C5532F9C2 +:10DC20003FAFAAEBC33D6684F797B339DE5F157843 +:10DC300059A965C4DFDE761B950F2F934274966C4D +:10DC40003F887D1D1D37B0A06925F68BF613D26D78 +:10DC50008E9545747A022A4EE2F7E0AE8B88FF7605 +:10DC6000D5FEAB52EDBF5C180AF7E7739D06C26F95 +:10DC7000BB9AD7EDD9B0D489FB258798F80CAEEFC5 +:10DC8000A2EBDA1401E5B22A478E26E4656BEB7944 +:10DC9000A94A5AAABF6767894A1741F5BB829C67A0 +:10DCA000282F98F9C167C8C6FE24F5FD41BA2FA3F5 +:10DCB00020E77519E1FBEA8025A624E467C52EE17B +:10DCC000FC2639DDCD0CF05A65927CA857B15DEA8F +:10DCD000703DFD4A4E8C677AC4714E941FEDCEF9AB +:10DCE00044CFC2A191397ABBE3502FF4DBACD2C947 +:10DCF000A11FA0DF7B54FA3D9A756D4AA0877EB4C0 +:10DD000067BB0A0F40BE87CE1939AC44BFED76EB36 +:10DD100025D1EF21957E775E32FD1611FDB6677332 +:10DD2000FA6D3F554B747BD4B5309E7EB3807E0137 +:10DD30006E875D0109E5637BB655DEC38974E74AEA +:10DD4000F8FEB0E062886FF00372F4FAF7B07DC8B5 +:10DD50006CCC272FC03C31A89FE0958AD16F373813 +:10DD60000A890F0E350EC9433BFFA83ADF44FED0A7 +:10DD7000FA61CEF8F892F6FE08C2CB8AFCE0A73C26 +:10DD8000AE23AABFEA6D2FC8417B93B53E2823DDA1 +:10DD90004F54F969A2CD7A0AD7C1D281DE75FAD97A +:10DDA000736C0E7DDF1B5E7A1FA79A8F83F7279512 +:10DDB000EAC6117B1E2731BE35BC34F02B94EF1719 +:10DDC000CDC1F7F1BC78678D8DECECB4EA4EBADFCB +:10DDD000E37DF55EB70226AF3989F07BB30FC587C7 +:10DDE0000C8EA92AFC32DD08BFBF94C7FBFDBDC164 +:10DDF0000DE8230FF79D7A5F4F590EC639BBC1CD91 +:10DE000009EB49FEBF076E37A5F83F41BDF63E134B +:10DE100007D0B9B74A1697B7D39B9DF41BD4C7F95F +:10DE20003DD94B5CAF81C419CDF3A1B87D34E9472E +:10DE3000B55FA4A37C54AE9CFB1BB013275D597B3C +:10DE40002B96EFACE83BD7097268D20481F2B82C6C +:10DE500007FC0F2B00B74937D4DE9A01F5C3AF3862 +:10DE60003717CF894EBA5150F3BE2A6E423E98748E +:10DE70009340795D7F7B05DA17621C3060C63CB445 +:10DE8000EBD5F39F4E351F41839F3886EF4F8B6351 +:10DE9000B81C4C1D2351994083F27006CF4F063DAC +:10DEA0006C26BF8B05CC38EF3F5C015A7204F61B21 +:10DEB000C86DD5C9D5E3575BE7C84EDE4EBF5FE6F8 +:10DEC000192368FB48644727E271903ABE9687831E +:10DED000DF5F374C5F6FA27A8F3A3FA7C4ED6C9C2F +:10DEE000D7F461FCA9F77F8FCFAC34635AE1752575 +:10DEF000209F25C467E0B2312847B3BF75A17E07D4 +:10DF00008385F2D2DE377B4DA4D7DC2CF83CD8DFFA +:10DF1000BE327F338650DEBF7BE11CB2DB921D3206 +:10DF2000CAC319EAFCDA1CC3E9FD4C66F0225EF1B3 +:10DF3000B749D37B40476F4C7EF008F6F76ABEB511 +:10DF4000CBFECC2A8DD96B875E078307403E858543 +:10DF50004DDCBF08FA56A17D5B6D17D14FB99A45CC +:10DF6000A9FE47B8B33108F76FBCF4FCA4324AFBF2 +:10DF7000559A5DF7975C6ECF817D3711D7358D054A +:10DF80005E8E92BC6C35211C9C2CC4E70FF344FDC3 +:10DF90009AA8F727D876925D00BF8ECCECEE7C4C29 +:10DFA000D3ED1BCBD3023B41B91DDBAB76C2715322 +:10DFB000E0BA31A3306F372CF0386A8740FAFC564C +:10DFC0007E8E9A95796D9CCEE3F9AA2B0FA256A06E +:10DFD000B80FD88524B75FAB15D4FD30666C2E55CD +:10DFE000E1091F79BEBEDBD417E5B56C63089F3627 +:10DFF000C78F7DABA0FD94C3366685794C710669E9 +:10E000009D7F100CDE35B49EE0E15BD363F03CD61F +:10E01000A5EFE2F1500DED6EC3F69289DB2760AFFC +:10E02000E038573F67A171AE619D841F3F1309FE21 +:10E03000B78DE17E615F7F4D6506C0AFBF54FB7257 +:10E0400014BE7A2BC41433E8C3B7D438D09536B095 +:10E050007B280EA69E23729BE9FE056F449C804799 +:10E0600032A714A6D239E5E263DE43589E5AC2CBEA +:10E0700085617E8FE73515BC3C7C7F27DDCFE9F7D6 +:10E08000F1F2889723062C5F55E0A6F352FD99FF25 +:10E09000AA61487F9291DF07C15A5D68974C16C408 +:10E0A0006751AFBD53C7EDE5C9F983C83E7B7375B2 +:10E0B00035C9A5D4D9D32BF1DC219BCAF365CAFDA0 +:10E0C000B58D582EAFE67990A9BE90711B94A70725 +:10E0D0008447907EEF1BD397CBBD80CF7C3DE03350 +:10E0E00035C0F328C72893CDD70E23BABC5DF5976A +:10E0F000B6223D24D2E70BC86B0887059A1CE1794C +:10E100002B33A7F33827FEA6F725FF88E8F2382639 +:10E1100031227DBCC5CF479D78C7EB43BC28495C05 +:10E12000AE319BB7F976F8FEAD07F218F78742B328 +:10E1300029DE81748EFA6BFA7A21039E368185D1AD +:10E140000F62CE04397FC69260872A8DC87F99C13D +:10E15000641E2760BA7A987FA62D5971E0BD8B01A5 +:10E16000DD7BFAFFBF5BF5EDC08F7A0EF950626779 +:10E1700068BFB9C02D8818FF7951AAA5F363537001 +:10E180002FA608CF9BADA0F2CC127E7E664A4165D9 +:10E19000D59FA09CFCA691F064EEB7DF88787CED5B +:10E1A0003A9364C5F9A8E795C9950238BF50ACD930 +:10E1B0009541330A73CDEE7A49689D4D707BC7490E +:10E1C000F919220BAFC1F8E8934191EC21962E2862 +:10E1D00058BEFCC57E3C8E96C5F172D9356EC2C361 +:10E1E00094BA95663C6FC50202CB77E33C53C81ED8 +:10E1F0009CE2194DF6BF67FA8FDF4D467F403190A4 +:10E20000DD6408D410DF4D433988CFEAD789FF5F3A +:10E21000686421CCE7FFD5F437A8AC008EF2717C9E +:10E2200053E824DA11D7B28164C71D873E2D3A7FA7 +:10E2300082D90287D271DDCFF725FEBB12EF744180 +:10E240003A0DF27BE6AAA22B73D18E3C3113EC4837 +:10E2500080EB895302DD1F79FC9E7EE40F1E9FF345 +:10E260006113CEE7F8A834CA7FAAFADAC12214E70C +:10E27000104C269D1CAB32859B6EC3751EB649188B +:10E28000D7EDE60F8181C94AD5AD132A2B0CEBFBE4 +:10E29000E33F619C4C4FA68CDF6F5A99ECC5B807E1 +:10E2A00070A8D50BE30E9CC9EF396163F3085916CA +:10E2B000E694F12E450BB3D1FEDF747FEDBB684FC2 +:10E2C00065280637FA0D5D7A4A08CCC15C18E75814 +:10E2D000650EE6E51EB707E6200B78C66EE2E5ECB4 +:10E2E000C0BB58BEC7B96D4E7539E6EDDF7113AED0 +:10E2F00073469D40FAA5B2AECDD417C6B941496167 +:10E3000088878BA9C18969F0ACAE16189EC79F2675 +:10E31000ED36A3BFE1ABAFCDC53C9FEAB112F1F33F +:10E3200071979C8B7904C7B36503CA41C0871FF7F7 +:10E3300097FFDBFA4F85FEA17C3C17FA4FFF1FE8E1 +:10E340003F439DBFFB7FA87FB33AFFA13DC3679AC0 +:10E3500007FA07A2A9F4AC5C8B743BA3AB7FE5483A +:10E36000063C674902EEACB2EAFA5AE253DF0CDE31 +:10E370007FA2DDD3359E9D8FE7F15B2386E1FFCC45 +:10E38000386D34CE3BF9ADB9C86F6FCEB4A26DD342 +:10E39000D5AF67C6FA0E435C7CA5D5C5FDD36B5CD3 +:10E3A000A8AFDFF1CFA7B2706842AEDE3F7DB317F2 +:10E3B000FF74C6586ED7BDA9FAA7C76D5CAE1C47DF +:10E3C000FF5488B5AB1DABC657660CF2B01EF633D2 +:10E3D000B4A7A6AFBBFCC241DC3F3DE6BE34FFF4B0 +:10E3E0000DD53F0D8ED5FC53E1B6EFF74FDD5CAE9A +:10E3F000B835B9D29883F1846393D7C7FBA7128F3E +:10E40000AF5C344B0694EF6FCF36527CEEEDD94DB6 +:10E4100024E7BE0443411F37EFCDEFEE9AB76A877A +:10E420008F650A9D67121BA434CA7360E146CC3F16 +:10E43000B97715F8B1D0DF66751DBF12F8F929A5B7 +:10E440008889986F9199CEEDAD34D0414DD9BA738A +:10E45000616ABE84CB16A47B2A5C122BC6FC40D01A +:10E460005EF4BDCDC6E3CEB9EA3937A77A8EEC3E6D +:10E47000A443DCEF50CF5739EA98819FBB0D8B48FE +:10E480001759A6F004EC7F80CC18ED4398A205F84C +:10E49000FE87FCB3C475B70B3DD3515E055FA7D7AC +:10E4A000C16EE3E793543EF6B8F338FDEF26FBEC7C +:10E4B00006658401E9FF69152E3714AC1C887A6D56 +:10E4C00056B520A17C6E7CF7F1B57825D76B6E81AF +:10E4D000EE52F3499CEFDAF317E6A2DC7DABC6CA35 +:10E4E000D0CE7CF35BFF2E5CE73BE5490CE34B7938 +:10E4F000157CFD9E3AE0138CA3D5713EF1F6617355 +:10E50000FC3AFA4A9C6F173EBF1648DF8493D853F3 +:10E51000782EE3C0D80FE764019CC2FDD89F517EDE +:10E520009B5FFE720E9EB308832E413BA6636CEA8E +:10E5300043E8CF85D5FDD58BEF2E34EBEF857C4BB3 +:10E540005D1F1E77E7E778521FC2F34531B8687246 +:10E5500041834B977C5B8BF2EDFA7A2E1766CD6880 +:10E56000E372A1CE9D1B559F485F6FB9AD783712FE +:10E5700073ABEB3EF6ADFF5D8423CA0B8487262F79 +:10E58000922A78DE19CE0FE34A55261E4700BF9027 +:10E59000ECC7443C46553EBFDEA4ACCD50E5EE1A78 +:10E5A0007856CEAE35E3B820AFE8DEAD590137CDB1 +:10E5B0006B9A54C9E7E76FA3F969F379C7D5BA8BAA +:10E5C000E689F28BEC0F8E978B6699FA9DA6F55B28 +:10E5D000CDFBADAEE3FD56FB6B489E5F07729FE43B +:10E5E000BAA736AEDFE3E6508E2AD7D7ACD2C9F54C +:10E5F000C4755D34B7AE45F97A9D325040BFA27202 +:10E600003A8C83F6F58C5437C2EDAF63B93F38B915 +:10E610006E379DF79A3263255FC7EC46A2B7B753B2 +:10E620004324CFB5714F7C1B2079EA99A1ADA3B5E6 +:10E6300019D73113D781FDD7713A9E12E0EB98E2DA +:10E640005949EBB821D048FDFBA4DDD42F3C77918C +:10E650009D3399D3714605D71F6FFC55CEF5EBF46A +:10E66000C70FE129B342C35390E03945836701875F +:10E67000E78C6A3E8F19B377D3BA66553772784AFA +:10E68000959C8EA4CA3938DFE3D7713A023D5CA568 +:10E69000D7936E956E8EABEBD6F0364B5B6F3D87A6 +:10E6A000E734A407F87E1AE20DDA5D2775E9B11C9C +:10E6B0001CE7B5FCD61CD463EF6874A0F1A7AAC709 +:10E6C000DA57CBEC0333C535285E3CC169207BB5F6 +:10E6D000CAE76DC67B17C650E60EEBC1BF8DF74B80 +:10E6E000B5B8CE745BF06032D97DF29AF7110E6046 +:10E6F00097AB7E8A6143DF985FCA7C2BE3FCEBB665 +:10E700006B7FEF1C89F4E134D3BECE8342EB61B260 +:10E71000C7875A25B46F1FBC3685FC9EE3E8E70A1D +:10E72000313D67B071BFB30AFC5BCC1F07BFB45962 +:10E73000B54FD5FB0B82CD48A73EF467D5FD1FBD75 +:10E740001FCB543F7622F8B11B2FC18FFD5105F727 +:10E7500063A782DF8E17C7BC79ED6627FA1B478D4A +:10E76000F1F921C7FE8FFBB3920BE3FCAF31F62C1E +:10E77000C2F78D6AD59FBDDA4D7E52623C04FCCF54 +:10E7800085151931BF937ED87E722AD103F867F5BB +:10E7900015185F62FE38BC758B8324FA038974D325 +:10E7A0002CCA143750E320994895469C7F4440F882 +:10E7B00026EE5BF446672253FEE9F88C49F34BE8FA +:10E7C0002788B82F98A37E2F0416923FB4732C137A +:10E7D000317F96AD0BD2FC8E9B029B2AC899E4F642 +:10E7E0004316C66B80249ACABC8B538DBDCFF7F7F6 +:10E7F000A5722B7E37D1E8F4627EEA676F1A89CE64 +:10E80000A7CADB7D28E7AE66ADBE34A40749F04653 +:10E81000A4181D0DD906F3D4F9CD43433666D2E5CD +:10E82000075CBE4F8C2B0F0B67C5B51FB15F8AAB62 +:10E830002F02A75B5F3FF29837AE3CAAA32CAEFD38 +:10E84000E8B7E5B87279B43AAEFDD873FEB8F265B0 +:10E850002C60C0C55FD13923EEBBCF58A01DF3811A +:10E860002E2BB78A0AC56BE5370A800F87A9D01F00 +:10E87000FF7520AE9F61D15A03C2E928DE27027ED0 +:10E8800062255B14D71F7BCE741AF11984FF109F89 +:10E89000973128EBF2EEA748E65819FE3738A1BEAB +:10E8A000E1A4FDC861DD78472A5CE98837C07909B1 +:10E8B000C623BAE10913A5D14EDAC7422101D743D5 +:10E8C0006DD965DB199D0F4A5CCFC5D5B62387315D +:10E8D00067CA7892E2A35F82BFD4C78DF787C6E389 +:10E8E000D32EC5E3D351108F4F97371E9F2965F163 +:10E8F000F84C95E3F1D9A73A1E9F19FE787C66CEB5 +:10E9000088C76776201E9FFDEBE3F1991B8CC7E358 +:10E91000C086783CB995FAB8FA411B82F1F418AD7B +:10E920006DDF05EB3F5A6615118FF9AD0D71DF6B89 +:10E930007854E0BF9EF038AD3E118F9BE8FED81FA3 +:10E94000C2E77709F864C6D9DFBBAFA7E10BE49C47 +:10E95000F90A8A532F9F43F24F8DCFE04F1FA73EF6 +:10E960003EF341D24FAF0EE571EA094C36217E0FDE +:10E9700065CFF1F59178FB043D437AA85AD3436AF9 +:10E980005C0AD36E905FAEEA16B796CC58BE967509 +:10E990000E300DC2FC85C83AB4CFBFCA7EFD3D81A2 +:10E9A000F22CDAB43C8BDC2B481F7550F9A8E369D4 +:10E9B00013C6E79D2C48F3D7CB47CC4BBB64F93843 +:10E9C000558CFC43725ACA8DC93D12AA0AC93DF042 +:10E9D000830DA7C86FE0FE9E2E2F81FCE4B72A03AB +:10E9E000AE51A817671A99FEBCB7F6ACB882EF33E0 +:10E9F000BF7590FB3DBDF9C713AFB834FFF89FCD8D +:10EA00003F780BFDE31160E75C71A9FE714DEE00EC +:10EA10008C234CE6FEF19BA7C07F80F76F5C3784A8 +:10EA20009E5DF3A8E6FBB79E632E05E35E5FD65BB3 +:10EA300049EF36BE7B07D9A155BF31D37DEE13F028 +:10EA4000522E2C9FE3F76033533DE9C1892A9E0F74 +:10EA5000A9FB79131A26F8310F60E2C907494F89DB +:10EA6000068EE7EA742160C3BCA009522EEA1BBFE0 +:10EA70009105F790DDA324619E4C16B33D8BF8BE43 +:10EA8000A8E67B76A6F27CB0097756527F5DFB0F35 +:10EA9000CB78DCB1CAB93B17E38C13EAAD024EADBB +:10EAA000CA59F32EEE3F23C1A3AC3BB19BE3EBC4A9 +:10EAB0004A29C4CF67FE81E6D3791B93707FFA445D +:10EAC00011A7A313AE3CAA9FA0DE3FD12E44290E6E +:10EAD000AC9483BFCEB0FE17742FC18907049AEDA2 +:10EAE00009181BEDEC136D43E8BBAE7CD84DAEEFBF +:10EAF0003F9FD966E7F96D26A911F3840EDC25AA9C +:10EB0000F9B08AE73EAC9F9944FBBBCCA494BC818E +:10EB1000F5F597F17A6363E1B3E9B1FDDF8FCCD20C +:10EB2000AE5B110E33076BF9C40EDC574FB4430EC6 +:10EB3000984405F948092677CB83D5EF0F25E6C120 +:10EB40006A74F143EF4F809FA4BF4FE3C4A22B2907 +:10EB5000BEFFA6DB14447BD837DDAAA0BCF4896DC8 +:10EB600026DCAFFE7074E05194175BF277AF443F40 +:10EB7000171896F0B4C32384ACFC1EE4D971722339 +:10EB800041EEB5399EDE8972EC861C2BE9C549FD44 +:10EB9000EF3E82F470A8D64AFE74A2DCABB2C92460 +:10EBA0008FD0AEC6FDAF89EABE52356B257975159B +:10EBB0008BD0B3FBBEDDF7CB3F907B2FA39CBE3D3C +:10EBC00069377DBFC6B1BC02E53BC8EF57F0FDD841 +:10EBD0008F6513C2BD4A0238C0786FA62A44B73E7B +:10EBE0009740F4021638F93717F05E9A1EFC9B76B0 +:10EBF000FBC501D85F22FC12E5C98592C06FAFD07A +:10EC0000C53126A785EC22EDBFF66C07B6391EA2EA +:10EC10007D8629BDE895D7F21FE77AE5EADEE0E9CF +:10EC2000F56520FF32BFB6FF49FB759A5EF9217882 +:10EC30007ECF3EE85984DB6416A2EF8E3AC699492E +:10EC4000CF99E40FAFF8EFB0FB59B7FDD0383FE0F4 +:10EC50001FDD07D5E0390913FEA09F77447E4F19C9 +:10EC60004CE49AEC52A42FFE7B678362C2F8A42F77 +:10EC7000DB487B290CEDC202BC5EDC4BF3AA62FED2 +:10EC800094087C77B537DECEA83A3994D6FB3BC1E1 +:10EC9000E0152A10DEDC4EA17A947B8CAF3FCBC806 +:10ECA000D75F95509F088F44FB04F783116F97AA95 +:10ECB0005FB3C7A9F68CC4867C3708FDF6FDEC036C +:10ECC000CC8F54ED9AAA84BC8444BBA6701CD75741 +:10ECD000732DB27B1C3CCFAB714491794D28570CFE +:10ECE0008E0ACA2BD1DA25F693884FA08BCBC66546 +:10ECF00074C70B8C45F1BE231937D4B5C1FA863CD5 +:10ED00007C19DD6F79A4EF8DB7BE8EE5870693BFC2 +:10ED10003A721CD7EB83FB2F7CB20DCA3E83703353 +:10ED2000E57F95BC33CB8D794C76DE4F16ABDF5249 +:10ED300083702ECC2B6EC2761646EDAE1AB16CA443 +:10ED40003E5F7D823AEFABD47B13725998E2B949AA +:10ED50000DA2A050BC96998CC5F0CC0A9944E8DF6E +:10ED60006262A6A4347866B53A45E4EF24DEEF6F1C +:10ED70008AFE588CFDFAF278F972AFE3D4209C8FAA +:10ED800020D07C2E2F102243A1EC4BE3F5538B9F18 +:10ED9000E88770F35569EDAFFE08DBFB54BB2159E2 +:10EDA000EE3CF41DACFBFA40DB1302D0C58B814A6C +:10EDB000F35080F7EC71365AFFF57EBE1F7C4D593B +:10EDC000A38079E6D707E412BDFD71E3387E3E6883 +:10EDD0007A196F37DD5F6BAED3ADFB7AB993615CA7 +:10EDE000E9FA19A7282FB5CD3197ECBEE909F2A5AC +:10EDF00006FF817EFE755792BC7E7D4EBC7CF1E3A2 +:10EE00003FDC245F0E6718E87CAB99CB17F108C68E +:10EE100053AE57E5CB0CD64AEF67B1303D67B30E22 +:10EE20009E5F71AA4BAE0C4CCF8B932B2B914EA6B1 +:10EE3000333FB5EB70FC98E48A13E80EF32C26D828 +:10EE40009C245F7BA0AFDB7BA22F9D1CA575CEEA27 +:10EE5000258FE4D59B4737E33A6639234EBC5FECF8 +:10EE6000572EB317F7ABBACBD32EFD44F67977FD07 +:10EE7000D441F230310E34ED87F34A5AC7915DAE7A +:10EE8000E5958468BDB0AE367C0FEBFF4179AAB73B +:10EE9000D77BB2CFBF5F7E7408746EAC17BB9CFD8E +:10EEA000705EF2BE71A37E382F7988CCE29EF34B60 +:10EEB000E4FE1374794A8E92CE75F794A0121A6EFE +:10EEC000407B6D979D6DC0F3A1634B2AC7FAA0DD0F +:10EED0000A35AF6A884FE2F94D1D4CDE0DE3994DBE +:10EEE0000AE5F99B6D626A632A9E4FE820FBAF3307 +:10EEF0008389687F69E70976B99882FD0DF171FE13 +:10EF00001FE2E37153F89EF667CC05F07D11E0F93E +:10EF100046AE27BE6AE179EF5FA50A144FFC6AA6E8 +:10EF200093EC810F365AE91EDA79EAB9DD74EDFE09 +:10EF300015BC511CFAFBF53837F1A1C2AAB269EF32 +:10EF40005FD898454FF5FCE73CF55EBFAF52A5B9D9 +:10EF5000D46F4BA680FDD66D19743D8E5BB729D357 +:10EF6000CDFF4E0D6F7F689CC4BF73CB9FE2F9E16C +:10EF7000CE1A273FE7C6024568475A8D9E6B6C46FE +:10EF8000D46F7785F743FDB25CA788F6BF6FE0C901 +:10EF9000AD6550FEE83933EDCF2CDA7B6D4A043F86 +:10EFA00033C9593DED232D0AC5EBB525FBE2CBCB8B +:10EFB000C2F1E515097A2C516F9D8FE9212FEAA145 +:10EFC00033A88728CEC1F5501DE3F8047AB7E8F3DB +:10EFD000D7343D34D752F529D2FF6215EF566BF086 +:10EFE000DC6E8097F527438B1B893F3B0F223FF751 +:10EFF000BDDF5D8CF91F4FA972FD97E3FC7FC5EF64 +:10F00000AC032B8693BE1B3895E8E3ABED768AB351 +:10F010007F65E77ED157AF08148FD932E09B75DB4F +:10F02000A19F2D63AC22F718E46B46F5C5EB45397B +:10F030003FA55BE44574FF464D92C8E38CCC46F790 +:10F0400000E0296278D6B536AEBB13EA0782824764 +:10F05000FB7129EB48462692C773BC31E3D4A18DDE +:10F06000D0FF8A6B9388B7162BE1490846D3B726A1 +:10F070003FD2251EE7C0F332069B2C5642BB65FBF0 +:10F0800053E9EF1E648CE7FB1EEBBF59E9C70FB5D0 +:10F09000FB792CCFD528C89EE3BFF5D1DFC559D861 +:10F0A0003096EE7748B774F6A944FA683112DD2F2E +:10F0B000BCB39CDE0BD3AA3BF0EF6E9C6D7150FC91 +:10F0C000FFD0762BBF4FE4157EFEEEEC2E0E8F8523 +:10F0D000394EBAC73971FDCD42443D9FD3914CE7BB +:10F0E0008F77DD918C70FD50BB7F430CD27D824CBD +:10F0F0000AC6DFC3B1D3588D7C727AC32DBF2B47AC +:10F10000F84E9B5582FA7C7CAA275972C6EAB5F361 +:10F110009AA6B4B2C750BE8CFFD648FC6102BD8827 +:10F12000E7660F6FBC6A11F2C9697F522ACE57DABF +:10F13000F008DDF307EB22BC9E6EB1D3BADC2CBC29 +:10F140000EE3A32B36AC5FB70DDAFF0EEC38CC1B09 +:10F15000393D2D89E273A75F7611764F8B05FC9EB2 +:10F160004266EAF1FEFFB7C61909EE9503795CEF36 +:10F1700034C6F524E4AFC26B50EF2E6B31D23ECCD7 +:10F18000E16927B696A5C7F84B98D6D07910DBDF92 +:10F1900003F5D0FE03C54BF7151EDBF4F93AE4DBAB +:10F1A0000FCAAC22E6192D7AD4487FF7EA9FE537DB +:10F1B000FC4540EECF53F194C87FF3360DA27B1F80 +:10F1C000D906CE87378E17481FFC17F870DEF85126 +:10F1D000313E6439D3E2CE9B3F9560076AF25ECB45 +:10F1E0002FB57999BCD749F781CA02C8DFF5E3F991 +:10F1F0007D1EEBC7F3F3C7A6BFAEDAF75B98BF730C +:10F200007C60258E3390C945486F52A75885EEAF74 +:10F2100093A9F78C78F87D4E5BCD7E03D1A329F0BE +:10F220008BDFA2DCDFB06824F27FB3DADF2FC70503 +:10F23000FE653CF45F7757E0D3830CE96E0CC9811F +:10F24000BAAFA71B303FD7B945BBD7D05F6547B929 +:10F250009FEE27BAD4E4783ECC77770FFEDB63E3EA +:10F26000B97D959FEEA77EAA2B4555BFC933515F47 +:10F270003DB4D8C0701EE3BF1968C0FB77EE0556D9 +:10F2800044FBC05636CD60E47647673EEED77DF34B +:10F290005D9F068083B3CCA0EA3D7F3B9E4F742ADE +:10F2A000295F08D0DFAA2CA384F10867591AFF4E02 +:10F2B000B6D177F90569ED681F8AED295FA45C1165 +:10F2C0009B9781D924A70DFFECB481E8C2BD859737 +:10F2D000353AF8AC55203E5D85A90FC5FC9E82707D +:10F2E00021D7BBA83F576559683CADBFED65952157 +:10F2F000841F93654F7AA97A3F33C3BC6C2E7FC0BD +:10F300001F61FCEF68F1FB4E1C855133CA216DDE95 +:10F3100075B6D0043C579908BF3A759E77E33C8197 +:10F3200064C678A15CD0FB3C9B54F9A97DAFCDD3DA +:10F330005112881E25FB2785E5531E6180FEBEEF16 +:10F340002E934BCD53EC68C172FF0223EDCB19D540 +:10F35000F38FBB5880EE2571A6733BFFA2FD9ADDAB +:10F36000984F2E35023D0E80F6C6959447DEBF2994 +:10F3700053C4FCF226B39A6F0E8605C663942A79AD +:10F3800037D62B169BD8E4A57C5A925B0D275D24BB +:10F39000472F1AFC643CBD3D3E8FFFFD57C6F781E9 +:10F3A0007244FF330B002FDE415CEF27C2E5F7E329 +:10F3B00039FF3C87B97BF09D77026FB75EF0F27B37 +:10F3C000579864C07B54FA1BA7D178FD8DD267F79C +:10F3D000A7E238824A7FA640975C80F17799F97D51 +:10F3E000C96756B7FEF48CB9FB78DAF366759C8270 +:10F3F0002D42285F77CF53743CF7B732D26426F79B +:10F40000E0DFFDBFF2FC5F3CF4C63A008000000084 +:10F410001F8B080000000000000BE57D0B7854D521 +:10F42000B5F03E8F3933934C9293104212427212D0 +:10F4300008440C388118115027098941020EF82818 +:10F44000A0E22404089097506D542C13129E8286DB +:10F450001A6D7C0F28F8423AD88854020EC122BD9A +:10F46000551BABDE4BB5F5268202F2C81814ED2D04 +:10F47000ADFF5A6B9F93CC4C9282DFFDEFFFDFFB19 +:10F48000DD7CAD877DCE7EACBDF67AEFB5F7D4CA14 +:10F490000EB1339B31F6AEC9B32D95B1E5E9F6D97E +:10F4A0003E282F1792ED6E78D69BE01B3CDD9BAD7E +:10F4B000FCBB601F126D83F7116CB6179ECBAD506D +:10F4C000CE64EC07FCBBAEEFB3749DC45C837ACB17 +:10F4D000931E34D778A03E93B5676AA1DFB2B39983 +:10F4E000E336B0DEEF650A7361BFA1FD986372E396 +:10F4F0001C83198BB73CF2E4B1F1D080D98FEC8436 +:10F50000F64FB8A3B40DF06C36E05C1CE6D926C00B +:10F51000D7360B63B100677A8C4702B8D91EC62C68 +:10F5200071000F36D5188BABD70EB9A0BE3FD7628E +:10F53000DF6A8777EB0A1C1D16467F3FA4C17F2C2C +:10F540001D4C86EF8F4D642AC2E774443386E33343 +:10F550007BB3341C5E381C23627318ABE64D98D025 +:10F560002AF822C63296A7C3676D5CD481F085D78E +:10F5700071F8DA0CF8EEB6E8F01D7E1CE153C254C7 +:10F58000558AA62E1C969C5EF85883B6A60EBE43DE +:10F5900087F60D005F696619F5C760BE5193FB8160 +:10F5A0009705CFCF8023FC71BBC6241CDFDBB81DC1 +:10F5B000FA738F91D56D1AC74F3C8E5F95C4F1C316 +:10F5C000DA539D11D03EDED22944522787F2603CA7 +:10F5D0004564FE0DFDE06761BEA308D7A32DCB27D0 +:10F5E00033C047DB9CD1491AAC5BB1E59D23C258BF +:10F5F0007C32AF84FDD84DA73B3202E14C8AFEF24B +:10F60000728620315CD7AADA7C27C219AB30B705E5 +:10F61000E0F1CF543C5B019EAA7B73E9FD5EA1E65D +:10F62000DF1F40BCBD67B26F83364D331D0961B12A +:10F63000F88C13DD80C7DDFF182EE23AF9DF93A8BE +:10F640009D30AB28418272B55311CDA9BDEB64E06A +:10F6500025BF35DA1D9F4DEBE61DA2C2738F40EB2F +:10F6600052B5CEE4B1A4E2FC3F6C2E8371638A9C58 +:10F670009F21FDA74033ECAF69BD64C17A4D732271 +:10F680003D0CEA9D153A9EB99FE8CD66477C36A5AC +:10F690007A7D227E9FAAD9DDD0A616C7C3F5B3F125 +:10F6A000F53E6939D87C0CF860B1F5F7CD38AF4933 +:10F6B0009278A7D3467C1037730C9453584F791621 +:10F6C000962581CA274D6CF66B36023E6E66440065 +:10F6D0005F999813F9A4748BE84EBF22E0BD00EF48 +:10F6E000337BFBB9D4F74DD18DEC5EC4EBFA540FEC +:10F6F000E2B556660E7C7F4EB647FD33FE2EFB5EAE +:10F70000628E00FE2EC37600D7C391F69C9901ED60 +:10F710004E3844C6AE646CBEC46AF0BBB5F1854FCA +:10F7200077C278797529A91B627BE9FF739D9F5E7B +:10F73000D6EBC7211D07F4FF9889CB1D7BDB8B43DC +:10F740004B02FA2F3DA17422DD955AB67DFA63F87B +:10F75000C4E89F356BB1CE3197D2BFC9678EECDB61 +:10F76000EF5F00768477AFC2D7D1DA38EA18C231BA +:10F77000D0FC3ED5E767F0A9314E1B8E9F89E36729 +:10F780008C28099083A5162BF165A925FD18E2EDBB +:10F79000C7CA01637E17EFBFFFF955E73B0E21BFD4 +:10F7A000C72A8E2D48D76D56ABB60AF8E080F57A99 +:10F7B000BD1CA121BF096156E2A7BCB0700F95C363 +:10F7C000C73CD588EB1C6E65666489182D09F1D39A +:10F7D00066BD6C0483E794B0A925D83E2FCCAC99C4 +:10F7E00005EC6FD4316C0FFD336CDF661D938DF526 +:10F7F0007ADBF172E6551AC9E329E111C46779E1B0 +:10F80000660FB6CF1BAA65AB30BFF966FB6784A74E +:10F81000FA286D1B3C8F46F3791BF3EDD4F1FFA55D +:10F8200043A07EE687035D66F6AD67D0ED09AC07C1 +:10F83000CF2557398E231E463BF87A47643A536DDD +:10F84000201F5FDD7FDBBF87C1FB3809EA4F24B48F +:10F85000B9D90490BF488B13F5F587FF3C2A82E4A1 +:10F860004BC4AFF76E99921450D6EBF7B67FA764EE +:10F870000AACAF0565AFFE5D407192211A65871530 +:10F8800050B036A2F7BB1C0FF5D709BCBDBBB1A465 +:10F890004066EC0BC1187FADC701F37AD8CA82C6A7 +:10F8A0000B844F0EE9DF04FDDB34A3FEAD77627FEE +:10F8B0008F8E33CA2DCF3A00FE874DC1FD11C9E8A6 +:10F8C000EDB1608C577BB06CCBC62494A78E2CD442 +:10F8D00017B6EB5C31B9803FCDAFE64521749F147C +:10F8E000375E016385AB37315C5FD3F737330DE0AB +:10F8F00035C50A0E0F96610D3594DB49695B495F8A +:10F90000C99A1BE9C49CA08DDB00ED9272F9FAFC48 +:10F910008749A5F534C5E6FA86423513D3B6BF0745 +:10F92000F5DFBAD6A5E5E2FAA4141F423A6C9A357F +:10F9300071ACCB86F24B7620FDA48F503C02D4B341 +:10F9400034811C449C24899E74E8D282F3A7EFB7CB +:10F950006E93502EE6BA2EC37E0CFA486F72282E94 +:10F96000A41B9DAF9A16A7894200FD5C9BCBE9279B +:10F970003D4374A0DDB32163569E15FA93A3A75CA3 +:10F980002969BDF5D2D41122CE3B2D89D70B8F75B5 +:10F990008AB9502FADC91587C84C935D7370BE6985 +:10F9A000B3172AEE54EC57A27966AFF3587311DE01 +:10F9B0007291A5437F2373351ACFA49695607DD3AA +:10F9C0006C8B0DF5D513CEED56EC3F3D63EBBA34A1 +:10F9D000E40B55B663FDF4265827A827DF3B97ECC8 +:10F9E00000039E0DAA5C8470E448AEBB488F0D9A5C +:10F9F000E840FB6FA8F441EA16A83F74D038A91E6E +:10FA000050FD9810CC2FC6F3E33CBE1E0D82D37D73 +:10FA100023EAC92CC6507F1BDF53EC8CD6F5965CCD +:10FA200085EA696E350FF5FFE46F9C84975B72651C +:10FA30009ADF7EB9235C45B899E3AE529CA7D3A662 +:10FA4000A1BE05F5ED13A17EEC4ACD8EEB6F89EDDD +:10FA500078F00AFC6E17EDE9F8198919CA677F3347 +:10FA600064EB0600E578AEAB14D72D47EA78E446A0 +:10FA70009CCF8332E96D26733D9E7C938DEC505371 +:10FA80006C3BE1797D3C23BBECDAF5C7C2D1DCB33A +:10FA9000C43A19DA37E1B04C6837D96C8287A1E9EA +:10FAA00060B74FC1FAAC86D9D381576D769539E0EE +:10FAB000FB0D960FB85DA5DB1F365DEEA7039B7CA3 +:10FAC000097C0154D1F003EA1DA88FF645214CE8CA +:10FAD00009687FF8C2CD327E142DAEC588F729B3F0 +:10FAE000C318D2DDA65C2EEFD89A8EDF8A386EBBA3 +:10FAF00047AE203A696712D42B6D1248DE976694A0 +:10FB00002A38D8C22681E8A84CA73B26DB93D1BE71 +:10FB100073E78613BE61787A96318E27B6D14CF69C +:10FB20007D69232C48C07A3256C7EB35713E545656 +:10FB300071FD066BC1FB650FD2F70773B91C656CCD +:10FB400095DE7F237FEAE386F5D8EDC176EE0613D6 +:10FB5000B73BDCFB24B293BACABB2391EFC3CE867A +:10FB6000894214E9612D484F6570FBB4B455EA57DA +:10FB70004FB1660FD9C95DE817C4068D1BA41737AE +:10FB800098FC0F6DCFA67155A44B639C27182B4290 +:10FB90007ABED8382FEBF36D9B733EB203EA3FD1A8 +:10FBA000FA9C15F1F6D84CB0A4C98EB347E23ACC12 +:10FBB000B13A7F954BF8B03F3412FD95872486F417 +:10FBC000FA98D0EE90385F905D3B6FC4ACBB7E0B73 +:10FBD000F0C6648F1E87F0C5CBCC22C540FFBA5C4F +:10FBE0008B6A03BC43FF8F0B9B1370BD1E4FD084E9 +:10FBF0007AA0CFEC22CE4731450EA912EDAEE88EA9 +:10FC00008234B487A732B615FA1D125EB305F964C3 +:10FC1000C89D19E3EA617DDFD1E543D8F8C603D872 +:10FC20008FFF2E4DDD0ABC19BFCA9DBA2C13C7A980 +:10FC3000A9636487337A3FF8272BEAB0DE83892CE7 +:10FC400046C27AAC4EC07A6B060BC4F76B4AC03E14 +:10FC5000CD447653498E24CD5685BAABB15C934BD7 +:10FC6000724353A37F9F40ECD81005BAE3D1483EBE +:10FC70008FC1A27427DA87A04FA81C03F2602BC0A3 +:10FC80007F24379AE01B626645420C7F8F7406A87A +:10FC900077EC82EF43F26BB270FC21C3F97383EE11 +:10FCA0007F3CC13CCDDB109F190AADE7DE33871ADC +:10FCB000505E7465297609F82A6EEEE10684E7AC99 +:10FCC00020D7482AEBE3979CCDCEFF1CD7E9D1BAC9 +:10FCD000997316603F63B85DCFDCBBEC37A18E0D26 +:10FCE000F15B64DD6EEC3ECDE9B441B71B0F1F1E26 +:10FCF0001ED561E3B86709E85FC6D07CBA9916855E +:10FD000076C9E10323E9BB51AE65E0DF209EDE95B5 +:10FD1000880EFAF11348FFF8B364CF56A157AED955 +:10FD2000A2E33C1B52C96F70E3FAFA7759E9FBD999 +:10FD300095EDCD53D2A99E8FEABD3E8AD793663A00 +:10FD400004AA67B26FD5C8AF20BDE7DE3786F80ECC +:10FD5000D04B76986DDF100DEB578B1D3BD134B136 +:10FD600099B87F60433F23AA970F6D02F73F98EC45 +:10FD70005367017ECEEA7CC36447FC4D01FE458398 +:10FD8000AE1F2A14DFC898CCDE764639D1CCFD01EF +:10FD90002CA39FB157C76345182FA744BB86E40126 +:10FDA0009FED565839F51309EF6D01FE955D1EC0A4 +:10FDB000BF1AF710EA39BFC0DAB7AA840F37CD6F80 +:10FDC000D3300FEA834929BCBD7FBD407813665903 +:10FDD000081F5F66C95BD18E9C2465ED46B9E44F70 +:10FDE00090546CDFEB87F9D49901F3B399ECCA0214 +:10FDF0008423D752B3CD7E713C19EFE78F2B2B664E +:10FE00002057E62F5931039F03F957F3D79975A36C +:10FE10000ADE05E84F39C42F32E80FE4AE12E827B6 +:10FE2000E6E771FBC3B3B2F1C963A6DEF78BDDEC85 +:10FE300000F9F9CF43FF017C707D1E33E4B782FEE9 +:10FE4000C2E23F5BC9EF09AD77DE0A7A02E8E39EC2 +:10FE50005FCC5490FF16B21A7A96433B7CA2B81539 +:10FE6000C11ED5D6C98467ED45C1A3A572F12F4E39 +:10FE7000C0A72AE2FBA5A0869E40D5E506A9771576 +:10FE8000BC1640BBC177AD01CA43609EEB6537EA43 +:10FE9000DB2D47C23D02D45B1BAB29A81FD7368898 +:10FEA0003C9EB251F0A4F37EE349BF35880EEC6767 +:10FEB000511EB78F56E629F40492F7103CFA13F05E +:10FEC000C5FD6D7DBC3A26FAF0290AFCB916ED9FF6 +:10FED0007EE250467F0DA61A0BDA67FE61A28AFC0D +:10FEE000745E71CCC6F99C8F19C9D03E6B88A85935 +:10FEF00057C4BF932C386FF515D1F72C911BF228FE +:10FF00001ED09EFB93750BD2E31DFA3A85AEF782A5 +:10FF1000C6E0F2A2E6E0F2624F70793E73FD2A1E5F +:10FF2000A6BEF4C5E0F777E4A9D47F29B3D3FA34A9 +:10FF300098B43FA6A2FC5F2F3384BF2E89E34D1CEB +:10FF4000C69F69D15366935D10ADB0748297C39F0D +:10FF500096152320BC0DD19CDEFEB3F086C2B936C7 +:10FF60006F24C76F34E7CF06E04F1D5FA45FE6EF55 +:10FF7000303F87F249D3E9FF94C0E5A17BBD44F649 +:10FF8000CB13E5B07ED0EEF38DE9647F794CFE0CA7 +:10FF9000B48FDC9B223494134705FB761FFAA54CE3 +:10FFA0008B437AD996C7E5B3F8F035392897DF0D3A +:10FFB000E19352BBF08104F49F7FD3C61CEC77E23F +:10FFC000206637036C6F2A9EF07CA1EFFCE14F9313 +:10FFD0000DFB06963465855628007C95F07E10CA88 +:10FFE000A1C0FAE4AF2BBD7C05EB76F778E7EB799F +:10FFF000C47F9EF118D7FAF2A4CD8EF87E543CBA95 +:020000024000BC +:10000000EB9D6C92F324BFAB56F8B733687FC3788F +:10001000572BD63F7DEF278582D68BA7AE7DA38851 +:10002000AEB21B02F816FFB331988FD93A983FE869 +:100030006BD614FCBEFCA99076EC1FE640380DFB95 +:10004000EE31C57519DAE74F387372109EC74C8DC3 +:100050004528178E5FE57A1FE13A56E03C2472FE90 +:100060001C89F264FF857AB227DC194CDD168DF607 +:10007000BD6B38CE73FF91783BAEF3C25C8DD6DF9B +:10008000C0BF61FF1B7667283F7EA2FB1927F21CC9 +:10009000C5A8BFAFBBF09603D7BBBE5550C92FB0A4 +:1000A000B5F986A27C8632AAC52AADE3D00F309E70 +:1000B000DA567D2E6A18D8E336D1911CE0EF55351B +:1000C000F1EFCC0DDFAF417F92C36336B9DCE84777 +:1000D000C9AD33DDE857C27845E84FA09F86F2DF0F +:1000E00004FE17FE99743FCD345B2139901DCBED92 +:1000F00033584FEE0736B97AFC321E77758A4E6E4A +:100100005FA85F86F7E2F79B3CC7E07CA8FF05BECF +:10011000003BA221C7711EF5A04BB767BF45BBE3EB +:100120000AC63A74BFF3F04737915DF12D73925DC3 +:10013000F10F5D9E1C3E706B14DAA7C6FB2F25D70E +:100140003D2AF0FF22E626F9BD9879E8C99A0671A2 +:100150003A60AE4284AFA2186CAB685E3621FD3ABD +:10016000158A43233FFB42F839B0CC809F7D017450 +:100170005421B7AF21BB103CA44120572BBDC1F582 +:10018000AB989FE451F59E1FCC41FDE8F435445AED +:10019000965583F80BF1A37AFCA106EE3F01AF91CF +:1001A000FF149ED961427FFCC7D63FA935C6A1BDC9 +:1001B000037600C993B67D02C5930A259BC382F3DB +:1001C00007F962E676D28C2BE350CF315226B18A02 +:1001D0007F4D0DC69F269AD55518AB61ED8F4D808A +:1001E000F2991613D9F94CDAB806E35FD5432586A0 +:1001F00076E8628FE9F38E80792E61BB0A512C7C00 +:10020000CBDE55907F96BE18FCBDD21B5CAE66F26D +:10021000E73D762BD04FED9FADBF7D3B804F27E76D +:1002200047C4121D692CF507C0EBB1957B30360130 +:1002300070DC1E45F10EC6E3BA408F4176C2772BC3 +:100240002DBF7D1BEACD53F2F2F3014F4BF4F86F53 +:1002500028BFBD7C2DE7B783B673835C01DFF33223 +:10026000DD14AFC9C9EB9F4F67E6737F29BC5DB74B +:10027000E765370B8C2B0FD46E4E3EA7E3838AFFC6 +:1002800088379BEC3986FB35F11805C9463F598BF9 +:10029000AE4BC0B88CF336E4178B66C463C08F478F +:1002A000B99F0072260BDF7BB3307E64AAB0D98978 +:1002B000EF1A78FC80DD974AF1A348DDCFEAA193DD +:1002C00010FA11EC8CF67730FE81FD0E051CA3FFB1 +:1002D000A588DE5D581654A6BA817F5ECED6A89F4B +:1002E000A7ACED1C3E585CF487A05E16E953600491 +:1002F000AC87FDA05E18FA338B1DFD3225CC7B1731 +:100300007E5762988AFDBE95CDE178CA04EDA07F44 +:100310003189F7332CCFE5C2F2B044680720BBF334 +:100320009DF7E593BE708C2539A2C35DA5D3670008 +:10033000DDBB490E86D03DC6FF50FEB24633D951D3 +:10034000446A544E20BBFA332CC3B807AF72AEA335 +:100350007174FF63FEC3C328AEC26A07917C5A1B47 +:10036000C1FDB8A7ACBE84C075E98D23B8098E9CC9 +:10037000BC76B2B3FD0FC03A0A01F1209D2E1ECD0E +:10038000E7EB60BC3F97C7E9E6E37CC763387E765E +:10039000B6EF994DD938BF4886F8ABF2FEECC5F7F9 +:1003A0006269BE3554CEE0FE1273DA489EDBAE734E +:1003B00079F2292ED1B106E79F12CB7230CEB3214C +:1003C00063169B6FA3B8E0F3D82FE8E9EDD80FF0E0 +:1003D000470DEA8FB894C963D11FCBF9217F4D1126 +:1003E0008757453B2ED6CCE3C4067C070DFAD49F35 +:1003F0003E1DFED320E57253713CC71C21203E17E1 +:10040000AEB53B08CE166ED4E4A0EC4578EF4F2293 +:100410007C57B5E466611C8079AD59583FE7531BA2 +:10042000E9F3D3F7267A241EC7FA0DC21B91ED1704 +:1004300070FD4EEF9A9AD59FBC1B22C5505C688810 +:10044000C4BC8FA8BD7410A7807E42FB5C8F23BD07 +:1004500092CFDFA7E87A2A6585932DB0F5966DB126 +:100460007C5DE0BD88E39CC82B7805F1F94A3E8F9E +:10047000CF2D8B9734B4C3522D4059697DF9371570 +:1004800038CF06F2E97EF8FC034ED90DE500FBA754 +:10049000BB5120BF7119A8E4DA71BDF018ED97C502 +:1004A0002BD47FF8F732D15D9ACAE3B411EB743ADA +:1004B0005DC1886E27FBDBF3A360BE239A7C93317A +:1004C0007E68C5B11268DD1FBC02E38483E4C9C83D +:1004D000E7CFD48E6BC338A3BCBEFD1A44BDD6A8EB +:1004E000E661885AFEBBECE4F12CBE1E0B9BA2C950 +:1004F0007E62724D06FA6D6C0AA743DB758EE38847 +:10050000FFBC8F4D34FEF94D7C9FA329B922251ADB +:10051000DACDFFD48CC6E580FE9C9BB5C533F03F99 +:10052000D2360EA7385DC43A1EA763238020304E12 +:10053000B2E95337EA1B79FD47C310948429361A70 +:1005400017DBA1DF14B1511211FE05EB402269C483 +:100550005709C2042CC7E661BB058D821DC15ED060 +:100560009C2B629C191A523C34BD49155D01F25511 +:100570009DC2E9F4AD0B5211DAF1A285C7D72B93D6 +:1005800062B6483CCE407C5A9912BB05EDEDB029CD +:10059000228FAB37E73A12B45EBBC8E8AFB2A5848E +:1005A000B902F474A8FC794BE6F2E72DA0EC467B87 +:1005B0002FFD359838BEDD7F1789FE5374FD74F426 +:1005C000A1BF25105DF7C4133DF4944DDA1ADCBFCA +:1005D00095EB3AAE0589C2CA1AA3C5AA4CECC75E10 +:1005E0004576E5A670867E40CAC6E16D13A09CB232 +:1005F0004E658286FD55A660FCC3FD899921BDC864 +:100600009BC2098FF26607521193A3E3087FF2A3FE +:100610005086FAA7F24D047767BEA6C7B141F390A2 +:10062000DDEBC8423BF6E37C57E694C1FAFE09E2F3 +:10063000B9368CE44D84CCEDEF88DA4F5EAD83F2B1 +:10064000337ADCA2EDA1CB6791FFB75E16905ECE48 +:10065000477F40F5CE5FC904B413274C1183E45E95 +:1006600000BD0C257AD92739911F653D8F405E1F4B +:10067000BB05DB4DCA764D4238AE69F049C856FB22 +:10068000D5638F14693F5E0FF4EC133ADC41790DAA +:100690006D2695EC67B0CDBDAFDBFBC2374DA70B28 +:1006A000BBC8F336609DACC82FC6FED82FD19F02C1 +:1006B0000274E7D53CDB81EBB34A66F5F0FC65F8E4 +:1006C000CF5FE8807E6BDD66D50CCFEFACC91E8CAA +:1006D00083C4E7F3F9F9FF1241FBF9D04254F0BBB0 +:1006E00068796D43C0F8B375FAAD953551C6F9BC5C +:1006F000CBFDBF73B25687FAECDC0AD5EE8629C76C +:1007000086BDFF678C076B75511A4BC6F93BB62047 +:100710001C4CB1A81BD4DEFE62701F3B601F364626 +:10072000B77FF6C6B029EAB8DEF7E5FA3A3DA8CBBE +:1007300003DC2727F9AEEFF3635ECAFB5096568DB4 +:10074000A5F8F399952F3E85FEA41499A321BF57D0 +:10075000AA7C7FBCD696A395226BC7B8964F095842 +:10076000F7BD91F179186FA9FD9F9397B31EE17FB3 +:10077000578F07BC7B264C4C05BF2406F33A06F581 +:10078000CDEB88C1BC8E4198D7E1797C21C27F8BAB +:100790009E3FD127AF6339C545FDEF99ECA8778D12 +:1007A000BC8E44CCEB80EFF9E59CEF125BB95D9E0B +:1007B00058E4A37DF1187794867C2C611EC7A05E57 +:1007C000BA6E8A48233A697A4FA2FC8D5F08DAE351 +:1007D00065B181F91B1C9F4D259A07F9AA27BE58C0 +:1007E000C606CADFE0F1C34AC6E914D413CA97AEFD +:1007F0001AD588CBF2EF7718DF793E51D7048DFCFC +:10080000D2492864F1FB1C85E28F278DF59C93A1CA +:10081000D311A3FDCDAED989D4DF7AD66E45F9D3F5 +:1008200025EBF2B23C8CD61D7A881C1D4BFB16AF13 +:10083000619E51FD04ED00CAD52E8CC752DCD11F3C +:10084000191877BCD8FBA6684702C6657BF3040E6F +:100850008FC03C08231FC4C8A3CAD3E503F09BFC88 +:1008600008F29B03FC7794EB960247605C3D945E34 +:10087000A687F0D974BDDFD07C91A4022E578C7C62 +:100880001123AFA2075E9DFF8DE77CDD2E33E8D0FC +:10089000A8F7992E9F7AEA85F75FEFA8CED75DFA81 +:1008A00073BE99D393913F501C134CFF27F57A17D1 +:1008B000743960F41B5ACF98C7051D8EA4022E17F9 +:1008C00037A5B66BB88E9B04EE476C12A09CCDE9A1 +:1008D00008FD834D42E31CDD7F5079997F972DE41D +:1008E000D3B0C7F3DAE3691F28CE680F227A1C3D24 +:1008F0007DB86FB2C9DA1E8F7E736F3EDA5524075A +:10090000F37BF2D1EC343F771D9F9FBD6DCFE5CBDC +:10091000E17970B5AAD1FE88BE4F67AC7306D3DE0D +:10092000AE8176C50E9E8FC69AB5B79D503E28E81B +:10093000F96121EB6EE891D03C94624B12C57319BA +:10094000E65F4D08A4B3094467F817485F79369EFF +:1009500097926733FBCC63FB19E722F96571F5FDCC +:10096000FB95B9FA7A34663B520B06F7C21BAA2FE5 +:10097000F78E1B42FA1258CD1B83716BDD6EF91096 +:10098000EBC13ADC5DE01C5D00EB996FD17EFA288B +:1009900034691341DF237F15EBF11419FC35C0D303 +:1009A000C7891959C8C7A17018F6CD5E7D9F84C547 +:1009B0007B5F4339323A461B87F11715552FB47FB9 +:1009C000B92591ECD1093A3D5D3E644B0CDAF197C3 +:1009D000AE7F0A499F48EF9B68DFBA52D5E55B239B +:1009E000D71F863EAA9541CFD0FA44DA713F6D7980 +:1009F000BAF7941BCACB812EDC2AE91D82F3FFA330 +:100A0000BEF909AE575F3C3BC704E6B585E2777E89 +:100A100081631EAE93517F20380D3F5551EC4BEE54 +:100A2000CEA678430DEEFF7C849FD06F37FBE72185 +:100A30007E864A91F67A781E099F776830ACFB2D46 +:100A4000D1AE0A846BF64FA6AEC1B2D036485B0673 +:100A5000F0759574E4E03A7DACBA6A70FC0A8B2BB1 +:100A6000250E96F0CC30D7A8282452E720DD4F7110 +:100A70008E71F60B3F87E76D9DDEEE8C72DD8BFD90 +:100A8000B489FE083BFA71B29A8CED98CAE7F5EF8B +:100A9000FAFA1C30D92FF801FE039B53B2EA91FFFA +:100AA000C2FF725B35FAB7BF1C9285FE9181973CFD +:100AB000DD4F5A203AE37C5210BC6B085E5B494A1A +:100AC00002C26BD2E1B50CD6F1AD653A23068617AA +:100AD0006313A4A71E10743DE57B09CB6F3055DD71 +:100AE0009005EB88C136D47F7502E9C73FE8F87DF1 +:100AF000DA04F5909E2D2C06E307F161BC9FF8C740 +:100B0000440FC6499C79BFA138C97355363BAAD05A +:100B100012A651FC723E73501CF18BDCBFEDEB80D2 +:100B2000F93D5FE07A96F85AE57AFACE4FC3C88F5E +:100B300071E64724939F3299E3FD62749041C9673F +:100B40008CCD9A2ED0BE2108878FAB60FC9BE15FD5 +:100B500028F716F4F899DA60AC770BBE87F9DDCA8E +:100B60006A4C08CF6CD648CFB9CC4BCFDB593B3D54 +:100B7000E731755F07B4FD63DD90BBEF8536B344A5 +:100B80007FB202F3A8927C6B50D800FE7723FECF91 +:100B9000177CF09980785F51328AD6B969F025D1F7 +:100BA000EF4C81E313E4D37EC403C8A7EC2C31805F +:100BB0006FD06940B8E58EFA2898CFCCB8D42CE431 +:100BC000BFEB2EA849388F42A60AB8DF5F20D9C8EC +:100BD0002E693FA66EA17CDA1E7FCC11990072FAB5 +:100BE0007A5D4EFFF25C248B8576ED699287E7DDB6 +:100BF000DE25B74019AC36C21363AEC42E28BF0B36 +:100C0000F63ECAA576C6F3B3DB2708646FDD10BFD6 +:100C1000790A869BDFA96376B473DFF958B223DDC6 +:100C2000CE683E246743F9FD5C8B5FA07DC30E193F +:100C3000F96F9ACB5613E80F1425997AE3A2F0FFC7 +:100C40001B4604978B3383E3A8332E1247FDA22063 +:100C50002216F5081BCD46633CFE60481C35FFE2BA +:100C600071D4D30501715410E4B4DFB9FD9A415B2E +:100C7000910EDB271F9CD48576536B2A66D4B1B6C0 +:100C800069DC3E4929747E83EB7ED6D4B110E9E459 +:100C9000F39530D0288CE35A98C3CCD8972B552A9B +:100CA0009F58194FCFAF566AF43CBD3283BE9F5D4B +:100CB00069A7F28242C78502DAF7AC69463F6B79D1 +:100CC0009DCC50EF2F8F58C6CB268B8ACA65EDB0CE +:100CD0004362782C6607F278C2E216CF1A0C1F2FF7 +:100CE0006D752898FBB77C584CBE0DEB3F2AD02A77 +:100CF0002E3C5C7308C9E7EC479FDF3A3D405E57E6 +:100D00007E2F907CCFBCC1115E08E31E5F3981E06D +:100D100039B9D241F09C5A5944CF55854E15BF3B45 +:100D20005A3BD7C443FFD37774CA43E159E0102834 +:100D3000DE70AD83793CA998CFCFF56673028F8FB3 +:100D4000E68E99F5F44F19CA715722B6BF25667E13 +:100D5000C120783F6342898CF57E7281312C1B74EF +:100D60007D31FED058FB59D4EB67DC1C2F1FB67CBD +:100D700048E56E19F00233ED6E0927FFBCFB4818F9 +:100D8000E94B166BBF651294CDBFE771FD11EACF39 +:100D90004FBC4F788DD4787EAF7729C25F7636CC42 +:100DA0008EEB7B0AD60D135E8D71DFD85172341134 +:100DB000E5DA6A0B3327C2F7577FD681E5B582ADF6 +:100DC00006F7054EC5E8FBD1AC261CE9E96CCF7EE1 +:100DD0007E4D38DAE9558AE15FBB2EC7F2A930A310 +:100DE000BEEB72ACDF639FB31A3BEA4143EF9B5308 +:100DF000EEB3635E528FDF99749FBD94ECF99A72E3 +:100E0000E4B3403D7F2040CFAF55B89C30F4FCDACE +:100E1000481EC730F4BC59972FFF857AFE665CE701 +:100E200033FBEB623042A3819DC9AE43BF0CD68D2C +:100E3000EC648BBA0DE05CF6FAE543707E2C29B6C3 +:100E4000DF75C775D04605945F7DE3726C3F324E07 +:100E5000D610EFDB5FDDDC9D88EB27596ACC245F81 +:100E60003CC4872FED7C3AED7E28BDB46B7DD86DF8 +:100E7000F03CBAE98DA1480FA3C01F41B938FFA1CA +:100E8000DF0CFD0DB47B01642AF6B3D7643FBB07CA +:100E9000F5DDD316F2275FD854390EE57AD92FE65F +:100EA000142620DFEF665928C6EF2FE47EC3C2E682 +:100EB0005DBF40BB2DD3CEECD8DF154F758A89D0EE +:100EC0002EEB79A11E9FE377A44AB8CF08F6E07D08 +:100ED0004897A34566C7780DBBF05C62A0DE751726 +:100EE0006A4171B8CB87151DC67317994D5FE72509 +:100EF000B240FB318CF4976137BE927CA4BB44C3F3 +:100F000001F83EDBEBAD377D88F3DC2BB813D05F07 +:100F100077972876D2DB1E9E7B7BA66538D99FBB50 +:100F20004537E57BBB4B619E503EE3743F8E78A90D +:100F300084FAE8B75766B57762DE4C65741A437F6A +:100F4000F0846739F93157094CC57956B53C5A8850 +:100F5000747F6632B30B307EF9EBE768BF91E15ED8 +:100F60002CF6D7521F3717DA3F98994779A04EC908 +:100F70004BE3B16A3E5E75EB2E0B9631350CF333C5 +:100F8000A35B730F0ED57AD74DEC782815FDECC115 +:100F90002E0BED9B37A7BA13D00F32EC8BE70B9CCF +:100FA0005B0A517FA98F50BED3170017ED735EA265 +:100FB0003DA088359497C9E2B95F66F43B4CF42DA7 +:100FC00026FF0C7A46FF6C9BCAF79F70A487695C6A +:100FD000D72EA4E7A15209F97D43CDDC6F63EA4D1A +:100FE000941F79A9E3FF32FC1F647F568B917673BF +:100FF00076AFFD367B50FDBE0E58AFBA68D73E1CAB +:1010000067816E0F31D9AEA1DDE08A76EC2F24FB2B +:1010100013EC0C91EC8B362C5749608F0E0FB047B8 +:101020002D97665F6C8E761C263C5E627D8DD99B0B +:1010300031EED6A387BE1D17A487EA23149685F147 +:101040008B263397B76F8B1587C01FBB06BB107BF2 +:10105000FB5B1E318EF8BD9EB17EF1B51FF8DD053C +:10106000B8F581BE748DC24AEDF5B82FE080FF451A +:10107000009D5CFBBDC85CFDE453194F58A72F7160 +:101080005EB92C3CA89E8345D3BE22B3C55CE27CEE +:101090007DCF05EBDDB6E702E73BB9FB48389A9612 +:1010A000808721F81C683EFBF4F9BC85F381E7DEFC +:1010B00069CEEF11BE6BBE5165B443AE9541DE06FD +:1010C000D82D00FF3FF0BBE3425810FC3D747689F9 +:1010D000F0DF2DF0BC42F6B5427E65AB1E9F6A5D27 +:1010E0009C49F938BB31AE0765F72C85ECFBD60877 +:1010F0009EC7D8FADE60BB9B511E1FB7FF4B785CC2 +:10110000B6D5CAF9A135415531173CD1CCBE6C4199 +:10111000BE97A218C61F7AFA1FAC923DB857607AE4 +:101120003C8C8FDF373E28917EF6CF09A3F85953C8 +:1011300096EFF25FD1F70C8AFB1AF1BF4489E7FD05 +:10114000B17A9EDFDC14B1ECF763A05D535D38D952 +:10115000334DA99E75982FDBF4C0706A57CB7C4F36 +:10116000527E805FA17D8481CF6DB92382CF6DB91E +:1011700023FA3FB705F500EF7FD2D7F788CCE36CB1 +:10118000473CC1E7B68EF4E44FF27E2EF5BD11AFB9 +:10119000FBC4387F10DD3818F33CAEBFDE75EDF5CB +:1011A000B08E73166CB3BA02E2F273AC4E07BE3F58 +:1011B0005AB6ED25DCAF6365DC6FFCC4C807FDAB38 +:1011C00048789AAC744CBB15F030F93F4401F112E9 +:1011D0004A1F3DF1D115BC7E5F3C2DD3E3B712C54C +:1011E0006F8D7DE3676DFDE7AD1661FE25DA5B2B44 +:1011F000443DFF52E0F9AAAF9B8DF86848BE2ADF54 +:101200006779D63B98F49A4FCF7B7D56F60DAD4665 +:10121000BA69B5523E2DF4601D0DE5B3227B0DED8C +:10122000B43B7579F92CD3A288BE0E4BB4CEBF0C5B +:101230008FA4FEBB1E80F1A1ECEBC1BB3DFEA6005E +:101240007D5B2FE8F9A97AFEEAB37ABD8A4BCF67B6 +:10125000BD0BF13F603EEB80F81469BFDB7FAF143C +:10126000146F7EB666988E4FBEAFE10779B315FB5B +:1012700091A18CDFE50CDAE7E88937570A3A3E3D61 +:10128000EB311FDDBD2F9DF064E4BD7CF980487E0D +:10129000DED91547739A356CCFC6EEC17A2D66AA92 +:1012A000F76C08DD3EDB8327BF15E9D385F61C9478 +:1012B0003F533B2202E3419F39BF8C4039F7E75A45 +:1012C000C9A7FC937CD7DB9B8FFF9D8D85A753E936 +:1012D000C4BCBBDB577C7E3BEE0BDD5E7E611EBD7E +:1012E000AF08CDB70BCE9FF35DEF78F2FA2B03F08A +:1012F00079421C307E4FF88C108DBC6A5AFF374FF4 +:10130000241AF9C1147FF79FB4E9F8E6E73BDF6CD4 +:1013100049B5A3FDDA83CFC7CDF4BD97DF3DE181A9 +:10132000F9C16FCA1C3F6F7A82F382DFEC89C37BFD +:10133000C8BE37F056AFDA2D8178BB7BBCEB0DA46D +:101340009755B67116CCE32A8FCA3B8CF1D0DA22BE +:10135000D7DEEBC9DE395B88767C35D8F148DFA76C +:101360004DED87303EC9565C9A5E5E1AD65A25808E +:101370001CF8AA75DB6E7C021C8417F61A97DBA793 +:10138000555F24C2E312BD0AE1B394D560DEDE12DC +:1013900006E56CB22F6BD65EDD378F93583E0EDEBE +:1013A000E33F281FD8AB4C8AC5764C7B42C5F74A31 +:1013B0006F7D8A2B78C80E84FACBD01E5B1ABDE7EE +:1013C000A149F07E89CD665911D3779D97B4AC6D54 +:1013D0001F3EB6EFFBBE7084C82BAF7491F3B8BE4E +:1013E0004894D7BD72DD47FB247DE53AD40B58E71E +:1013F000D3FA3A9F0E59E7D33DEBCCFBA965DC0F3E +:101400005BAD8F6FD2C73FED3D9A8CF6C559230E69 +:101410006CE779394B7FC5F36C56EBF27DE9206FB1 +:101420000EAE47A2149C87623C975ABC6B904E55F7 +:1014300087BA6C6D426F5C79A9D3ABA0FEB468FC2F +:10144000FD6E3D0EB48479283F2FDEC5DF2F753247 +:10145000362186BF47F96CF4B344F424E33A1A709A +:10146000F4193704EFB6221EA75E6DEC6B45703B96 +:1014700001E529E26D54B31254FF6C8472A703E0B6 +:10148000B9CC13FCDEE83FBE48D0E37101EB9D3AD6 +:10149000301E92F5FA2FBFDC535FE279AB78925A97 +:1014A000A74B8DDB1998DFE8FE930E1F633F1D0AE3 +:1014B00076E752E4A1B45E3CEDCE720D8DB1911E83 +:1014C00021B9BD3B1ACA99683FF3F18D720FBE4333 +:1014D000E87BD59F72C8FEDD5D270BB8DF5D5CC47D +:1014E000FDC056D14E76B05BE1FE6C5D44CE10CCB3 +:1014F000E3FC6AA5E311DC370F9DD7972B1D8EB255 +:1015000080F70B9BB32C48378B9ECAB29406F8D158 +:10151000F52F3ED7A6A13C7058FC22D052BDEC79E5 +:1015200068622CBE97BCC011F01C6F417C9FB6B5A1 +:10153000BD8FF5163E153D2EF03CE2A2E60247595E +:10154000C03A5CFE62F0BA8CF10697AFD8135CBE6D +:10155000B588D1FC7E6CBB2C5F7079FCE1E0F21B9E +:1015600013FC12E6E7CA36D16311F0B94AE1F9BAC1 +:1015700051FE7418EFCA8F1B14D48BC7193B8F7E92 +:10158000F989DD6B73D07F38C5BCFF3A1DD6616128 +:10159000EB6645D6705D6B0AC720DEF32CFE6DF658 +:1015A000BE79EAF0654D25F4BBA406E4AA7AF1BC45 +:1015B00075E39C1CFC6504D257281D9CD2F36D2B4F +:1015C0006AA73D1278EEFB6AEF66CA075A5C1C3CBC +:1015D000DFA5B2CC50FE0D24D7E4C8F642946B9D33 +:1015E0000F0A6C03D1AF7A6D2D94E737896C03ED48 +:1015F000E3A93F5F8D71296718EDDB4DACCD6747DF +:1016000031CF63E35D87300E5222F13C1075829A30 +:1016100083E720175804F24F5685FF9CF2E5CA6114 +:10162000FEB81F68E4094F6CDD22219CA52179E5F5 +:10163000651B43E0BB483EF992E77F3007E797F32D +:10164000F92CD0E193DC33C89E99A8C7E78E619549 +:10165000AB310FDAF97811E07962532EFF2E737FE8 +:10166000AA92F1BCE64A8BEB1E7DFF40BD1EEA1F2D +:1016700006BF12F173AE398AE2D2E7B01F2C3FC524 +:10168000E3CEC67995CA41FC7DE5AF05DA67A8943B +:101690004A481F552EE7F998481F8E0078911E0280 +:1016A000CBACD1D8C7F151BB25358CEF93C2BA3939 +:1016B00082F2FD7DCA0918A7CA2D789F88E6F9D065 +:1016C00041FD307EFEB49AF1B804E645077FF7107D +:1016D0009D3D6BE2FB2960C6903FF5EC92B9612815 +:1016E000AF40FE70BF6C26976717CBAB68CAE2F3BA +:1016F0006E5A9C4E7E5D22CA48C4DF237C5FB04C8C +:10170000FC80FCB6B2448E0793EE577D82A024E0A5 +:1017100076441BEDD73409B00A599447E1B6527F9D +:10172000A3F93D12BA9DCE662B03E8DDD7280FD76B +:10173000FFA8D0E32720FFCEDD3C24388F62939EA4 +:101740000F243B465AE8FB6514DFE9B1C306B350EA +:101750003B6C70A07E9EAB9F639B1B723E6B6ECFFB +:10176000F92CCFE0C07C888BBD37FCAEE357B94E77 +:101770001505C4DF9AA23D563CAFC0CA2F6D9F71BC +:101780009BEE17F9375B09FE63023F2F5116E6DC2B +:10179000701DE2FDB1B434A4C7BF15F1FD819C3CBE +:1017A000C74895D7B7133E1CDCAF3E86712CC07F6F +:1017B000599A63249E8B34F2A93FCBE2FA285C3F0E +:1017C000AF2B4FE57A519E2A063DD9141ED73B66B2 +:1017D000E574773B7316226AB7693CAFB74C71FE6C +:1017E000CB3501F0F4ECD3318DF6E922F57ECB4414 +:1017F000C181764BD92FCCC4474C3FDF71FB910C94 +:101800005AAF63BA7E34E887E9E71FE7FE6130E547 +:10181000611B72F4E274ACEF1F2E36E9FE3FA7B3F2 +:10182000A6392389EEA27BFD7F4ECF0F47F07E0ABB +:10183000F212307E84F93EFF81F50B7AF27DC82EDC +:101840001BD82E047A0AB20B395DF4B50BFF9FD179 +:10185000DDC4A9570E4C77D0FECA7FB63F5BF9C6F0 +:10186000ABBBDD00E7925F3D1AC9A0DE49B931CEBE +:101870008EFEE8B6D591784FC409D91D89FD9DF437 +:1018800048740F40683FF7EAEB8DFB80425C6FDEE7 +:10189000C4572FFF6DCD7DB02EE705E647BD51D56E +:1018A000F2D735F7019E0F811D82798C27E48E4295 +:1018B000D4338B4B6C357576946F21E7215E783489 +:1018C0004EA3F330EEA1784E0FE425E53F563D6F71 +:1018D000B263DCB3EA23C98E6452CDFC6B10BED078 +:1018E000F6D5DEA3E4A7A822F3274DEAFB1D033BB0 +:1018F000180FAD6E79F06B8C9357B79CFC04FDCA42 +:10190000D07315E5FAFE46E8BE60F9547D5FF02A13 +:101910007615DA93801FDAAF74035CE97CF989AE3F +:10192000EB5F7A61E79B00C7C94F8664E17D13A72F +:101930009FFF7D24DE0B61EC0F1AFBA8A7BDC3A39C +:101940005CFDE0D7789E5DC982F6910CF9AFE1BDF0 +:101950004543189E6BA26785C91789FE55C5169326 +:101960001D569855BCFADCF62790EEFF64A67B1E48 +:101970002A5E3DA7A09CAD101C7E218BA6132904D6 +:10198000E4BB2C7DF58BC227D1DF48905831ACDB0E +:10199000925F7FCBEB3B98DF0AF597EEEA2CBC1FFA +:1019A000CB2E5B8DA59F75CBF71E503A6CFDAC9B83 +:1019B000B7B390E2B52F7D47EB7272BFC086A4F635 +:1019C0006D5FBEED14F993E02FF955D47B5EA94409 +:1019D00089EA6FFD7C33DECCA6EF944777B1752C96 +:1019E0009ACA747A8F60989F5DFE89D9538CEBFBFD +:1019F000D072A2FBE3720DA7FBA757C7A13D5C6E97 +:101A000072C7A9F4E4EFCB9FB95BA74747023FB782 +:101A1000EA4EC0792D78EA169AD742E6223A2C7F10 +:101A20009AE7E77E0B7EE0AE7ED6F3CC542EBFCD98 +:101A3000ECAEB1C81FDF424F68D71C57B87E73FFAA +:101A400091FBA566B6F533F4BFBF6D1F2CA0FE93C6 +:101A50003E30D1BD533FDD174D719903BABCCEFF67 +:101A6000E0DB42E4AB9FA6CA356695E6EDD6F124ED +:101A7000FCC0E363740E91F278D3B0DF6EE50EA87C +:101A8000FF0DFADFF6A0FA84A7E35BCD61789EEC48 +:101A9000781CF76FE0EF8F0CE983F7C5AA567CCF6F +:101AA000F99869DD38FFA41B38FF57BF78BCF009EF +:101AB000E4B7525B4D14E0E79B8F8E2AB8BFE38EEC +:101AC00015593AC2D5FE0595997DB01615DF8B8F55 +:101AD000EA3DC1E7C0AA9FFF22846F43CE95B11AA9 +:101AE000C25B35E3F73A1C57FC0ACA03378C8B7E7E +:101AF000D3C2A6807367D8DF8A133A3D28BDEF535F +:101B00007BF9CED8C75F34C03E6628DF1F9FAA9FEF +:101B1000ABD2F9DE68CF9EEA7FBFB997CFDD84A74D +:101B20000A1373ABC83F7F32937EAAD8CCF9918158 +:101B30009C4C077A3FBAF160DCD580A7535E536CAA +:101B4000318D1A2C57CB5FFBE2D05AA89F182F314A +:101B50002BC9D5EF14F4F3E3F399DF0CF09F2AF7C8 +:101B6000086C4C3F7C09EFFBE5CB72F67F579EB2C9 +:101B70008D5F63BCAE17EFC17CB86800791A734300 +:101B8000305EBF65995193F0A35A9242FB1521F83C +:101B900035F01A2A17774ED5F8BE4B885C84BF7F84 +:101BA00065017864ACE3D05AC0DB793D2FA5EAF932 +:101BB000BF92BE02B4FA71FFB7CAF3359557A3BE00 +:101BC000A2F2819B311FBBEFBC83F119FAFD639434 +:101BD0003B4067CEDFF0732215AD827E7ED04D7E16 +:101BE0005735EE4751EDC643436303CB9E90B23762 +:101BF000A4BE23A4EC0CA9EF0A29D704D5AFD8734F +:101C000050E187847C41F5CCB5D3C8EFEA6B2F78DF +:101C1000681ED52D5F2B6EA48F243FDD0F635AC540 +:101C2000DC11687FED93C8FEEAD2FC916897ACB6F0 +:101C3000727BB14BD5CBD14699DD59928DF7B28CE1 +:101C400055319FD06FE571F12EA73F528F7F93FDE5 +:101C500055AFDB5F926E7FF5C433F43CC3AE785E64 +:101C6000DF78DFD92AD17D311D1E1E67EB0B7F3D4A +:101C7000D145871E872B902EEC44BFB1DB3D42C47B +:101C8000384C77C3B7BC2C67C430DA11E2F6E731C1 +:101C9000F7F5711833FC8239FF7512AE9BDBA1603A +:101CA000BED37CBEC4ACFC77F59118579022B20F1E +:101CB000EDC5F8493C3FDF59B631F47CA7330ACF74 +:101CC0009B2F6C0ACE47C2BC21E4BF4598C7A4A293 +:101CD0007F1CFC7D49EB29E2A325217CE4D2F72F70 +:101CE00042F9E87E838FB25816F2518164A37CA337 +:101CF000AEC33C3FBEBBC1C4D6E07C770894FFDED8 +:101D0000DDCAEDE7EE3DBCCCDC7A5E9FCECF06FEB1 +:101D10004E239F8DEA8BD79EEFAFFF2507F3242A32 +:101D2000767F3AF649789EDEFDA7917BB1FCC6BF6F +:101D3000257FCAFAD6CFDFFFD77904D77E33E59067 +:101D400074ED7F2719ED8AAE37CD947FD4B5CA4C98 +:101D500076BC7B7F049DA7E91AC6FD85FA7DDF8DE1 +:101D6000ED20BDC4EF2DDA7E03BF87A1BBF56F9FC9 +:101D7000A1BFD8DD6AD6701ED5FBC389DFAADFB448 +:101D8000D23E72D7BEEF7202CF3DFD67E763E4E15A +:101D90007445F07B6FBAA2F9BE41F5DEAB9FABC3D1 +:101DA000B841CB0105CF15E6BFF5F7B12877BB5E8B +:101DB0003BA0A05C3E6BEA7806E96BD70D85DB4C57 +:101DC0005763BC93D1BD68374C5BB3C09DD91F5ED0 +:101DD000381EBA000F382FC04B39DAE103E1E3F0C7 +:101DE0000DFC1EADFF7EF8F87A1E977F57313C77C9 +:101DF000DB8B17C1C1DF47501C0FE6CFDFEFFF6E53 +:101E00002CCAA78BCDF7CBFF65F395A7FDF7A6F7F7 +:101E10008D3768DC2E0DA1FBBE74FDC63D54DE1966 +:101E20006127782F91DF474CFBDFB5DE79FF6DE747 +:101E30007BB1F5FE9DBEDE112AFA2B5DFBFE9ECC2A +:101E40007EC4BC4BFE87D2B961E7E749F6C359505F +:101E5000FFF7CCFB913D95AC0FB23BEA6D3C0FFD1B +:101E60009DF8547E7FA5EE5FE5EBFED543D3B83FEA +:101E700055CFC635E03D076EB027B651FC7EDCDBA2 +:101E80001F603BD764B213CC8CD3D5B79688ED18BE +:101E90004F9B92345F5E8EFE958BFB5F507E7B176F +:101EA000DAEB13CD2A960FD6013C503E1821AAF545 +:101EB000FDE8E31EBD6C796F36EE2B4FB105FB5D7F +:101EC000D342FCA7A95AF0F722F65A2CC6F78A3259 +:101ED0004D0C3C105688F503FCCA8A69FC3ECEA91D +:101EE000ACB141B55D129EC8DF7D47D5743C397CED +:101EF0001E28176A2396E1FCDFD4F3A4EBD93286BF +:101F0000FB56EE8F243D1F44A4F57AC772CDF60D23 +:101F100081F8C57F6938BF696F231E0E818183F602 +:101F20007A7ED2742AC7E75BC8EE9719F8C37C9E05 +:101F300041FEB34C5DC313F11CCBF19C477875BDDA +:101F4000BD0BE03A78B559C57B3003DAD3BCEB93CF +:101F5000C65B34DB7F3D7E374FE3F73A85E2374996 +:101F6000CE9291AFAED1EDFA2972342F27B54B4EF8 +:101F7000E2370FB5CBFFC62EA35D9F6B8B96F97929 +:101F80006BFF3C8C674962A41DE313B8C38FE7263F +:101F9000EBF19C57163853B2EB5FA6D1391A95E591 +:101FA000213EF29817E3C542EB3B7FA57BC2588DDB +:101FB000E8A4FDDD43740FF8288BCD47F7803F255B +:101FC0009F0EBAA7511BD67B4E6B28AC729B95F81F +:101FD000C392A490BD3A4673E4E179F43058DF34FB +:101FE00098676E9BD5A17FA7FC1C03AF6BF5787239 +:101FF0003DF0BF0FF3FD2EC07B58373AC33E1CFBAC +:10200000612437C2A0DF34789717D2CFEA9516E65D +:1020100033F7F663B497B1BDD4B77D3EB6CFEE6D5E +:10202000FFE04A95C60D6D6F1A60FC2921E36F5AD7 +:1020300019AF8FCFE7EBFE98E75D18FD2803F45347 +:102040001002870CF22530FE110A4FF800F3290C1C +:10205000E947890DFBA7FDD80680E7FA9079D932C8 +:102060006382E838B49F8801E061724D7C60DC3B9C +:10207000B45DA4DECEA05FA35E64766270BC48F55A +:10208000D2FD9325F7F37B8C66D87CB9C6FEC62AB1 +:10209000A0E361B28BC65532988AFB17258FBC919D +:1020A0008BE5924540CB59C83FED02D64F029B1DB0 +:1020B000BF2BAC45A0FA2A53EBE17B49948FD79F05 +:1020C0000FFDF1FBFB19CA9B11F84CC374662FB5C9 +:1020D0000F9BC2CF6B82E020FA4E4BE7F098989AA4 +:1020E0008CE77A52F2D57B8EA03FBCDA4AFB5FC503 +:1020F00079DC5F36E6757F31CF13309EEA748DCB85 +:102100003FC17519AEC38C86CBC81FAFB73A2B5FE2 +:1021100047FA79359CF2CF4BD6DC31FD4A846FE724 +:1021200020BA0FE2AB19BBE85C5769C39CBB3F8682 +:10213000F7AE17ADF43E7BBA2BBF18E4C557823615 +:10214000EF7578517ACB4105CF65CCF0EE3A8BF143 +:10215000EB193787539EF60CE67D1FF307D8CD1297 +:10216000F5DFB93342C1FCF4E9DEAF658C2F4C9F3B +:102170002C50DA6EA7554DBE2B93F695292FE2C64B +:10218000625DAF59F9FE48C99A6123D3E0FD74DD61 +:10219000DF0FD5436EBD7E4ABD3D1ECF13F905ABA3 +:1021A000BA35BBB73EF643F78E16F338E85C1D2F01 +:1021B0004639259FEFCF94AD33770E8FC4A7C9372B +:1021C0000A9E7F9D9137AF18EA15A7B1C2E66CCA87 +:1021D000A3A37BF93AADA012709CCDA91AC63160B9 +:1021E0009578FED3C654D22B9DB97605EFE9EBDC8A +:1021F0009CAAE279A4F04CC7215CF7858D8286FA0F +:10220000A93397F17DA8087EBEFD33554DC6FA9FD0 +:10221000C50F57F11C458A746004EDD765F1FDBA0E +:10222000B6E9AE65088741CFA37BE8D99B81F1AEC3 +:1022300007E702FFA11CEFBD3FF667B83ECC627F07 +:10224000E8AAD8DEFB63FFAD98D3418AE41B41794D +:10225000E72AA7B3674C1D8BB1BF1CFD7B718C9A1D +:1022600063E3F4C570FC4E933A12E7D7B9DA2AE279 +:1022700019BDE2559CDED6CB5EA2678F4313DD40CD +:102280009F37E9ED6FAF939D5B008E240B93236224 +:10229000C01AB9D13517E199EEADFB0CE327F33144 +:1022A0009889CF8D9B15B4C752EA8DFDB1F629836D +:1022B000A0BF13DB5283CE7B8CBB31EF619C7FCF01 +:1022C0003ADDFC35DD6FC4544D8C4A40FA77140E6C +:1022D0008EC5A7B60CF52AACDBA3385E81D44AFCC8 +:1022E000DB5D0B365034DE9FDACECBF17CFF1BF882 +:1022F00093CA4A19CFAB4FB204F3EF509DFFE411DC +:10230000BCBC7D25BF4BE34590FFF87C19E4B80CBD +:10231000BCB903E4319677AED4E8E95D9941EF5F4B +:102320005B69A772CBCA0954DEBDD241E53D2B8B58 +:10233000E8F9E64A27BD9FA7F9E8FEDC780B5331A0 +:102340002F6E98EC25B9D1470E5CC6F76B8D7534AE +:10235000ADCB15D1CE30D6AF40CAA47BDB8C7B622F +:1023600007B2DBFEABE63182717A48AEE5F74E1973 +:1023700065C42FE26F04E3F38CB370F999C638BEDD +:1023800055D01D982F3654768844972EA6D1FD57E8 +:10239000CC49F30E43564BC0F5D1283E95E4623547 +:1023A000751C4F7CFDA6F0F10CBC30BD9F672A99CF +:1023B00046E734E48ECB904F0AA4D39BAE82F7DD80 +:1023C000E5A21DF7D7BA59C7AB6F50D94679DCC91A +:1023D0000A3B8BF7258235A449C968CFD8E3CD28BD +:1023E0006F7F5E948A76CE6DE5029303F4DC1D3533 +:1023F000563A5B6F94EFAC8D0E2ADF77A5EB04D2D3 +:10240000ED1D2B3A9FFE37E87FDECFBF3AB348235E +:1024100038B6FD12C75D1166074F05E00031144B59 +:10242000F136DA57C6BFC07BA74B1E18ADE039A105 +:102430004E87C52EA8783F8C5688F7C5B945467992 +:10244000489FE07A02FEFFACAFA7B5F13BCA73E943 +:10245000D4F36042EFA116A7A791DCFBECBEBFF15D +:102460007C5F9345C5386467790CC54559C87DDBE9 +:10247000A5EE70FE3B160D123F4F1F7A7FB69DDB17 +:102480007B9FA3BD477A0DEC3CD4173E6EE77DFEE3 +:10249000409C1BF7213EBF2BD28E27025DEB86B8F6 +:1024A00017417923DEB38CF1F056B686CE8F8B8C34 +:1024B000FC15E63605DB7D1D49D118A734CEE7872C +:1024C000677BC8DE07B25251EF9666B4D1BDA8ACA7 +:1024D000515071DF12EF27B7C4A01CD7EF49925DAE +:1024E00097DD0CEB9F389DDFEF7A75B14C74B2A18C +:1024F00098D1D3CAEC14BF2CDBC8EF2B2F6BCC5276 +:102500001606E89952FDFDFC0CD11178BFEB657AF7 +:102510007F89EB4A16A3FE4ECCE0F7A6276694D23D +:10252000799FC4D937C878FFAC517FF8743EEED597 +:1025300038EE601C7F307FEAF78F95CE9EFB3CD94A +:10254000A04C53905E8DF14A33C6ADC1F306A51B76 +:1025500073114BEC3185E7193F1659B80D45E998D1 +:10256000E9B23E2FDE6F85AEF7F03E5EB48B4EE0F3 +:10257000491692233C4EBD64E72BB4CFBCE45333E1 +:10258000E9F3255770BDCB323D39FCDEEAE07DA48E +:1025900029AF9CA1FD8F33E05FD2BE61CB5185CEC8 +:1025A0003B001FA2FCAD6E913AF1BEF3D0FD8CB79B +:1025B000777E1AD9EF3E520BDFFFBED83E92718E66 +:1025C000B8FA377C1FC4C063B5F03DEDB756EF5B7A +:1025D0001DE7EAC71EC0FDCBDA98BEFB4997BAEFEC +:1025E000141A27774D0FDEBF37F6F10692AFC67E7D +:1025F00093512EAF1D3B1CF72596D4E60CC77D8A60 +:10260000AADA6B8707DEC37C463F276C942B07381A +:10261000273C4FC9AB997E65EFF9E0F2DACBF57E46 +:10262000C7537FBFD6ED204DD6A2907EBA3DE9516B +:10263000EC9FC059DD0C93C1FBC8A13EEE5B1BF7BC +:10264000B974ED90F8B9861D63B622FD2E6E7D44F7 +:1026500011E1FD9EE9BCFF3321FB68553B8ED2BEE4 +:1026600076256BA77584F56596C07D55CCDB1DD4AA +:1026700017AEA5AF44D4207D2FF60A8E6DA8B72CD7 +:102680005E8AF375EFB8C3E40E58EF269D6F42E102 +:102690005EAFDBB5C67B8413E1586AF69EFD043954 +:1026A000E557E18CFFEE83FF7DCC7338F5D478FAE3 +:1026B000DD87C5DE5D55643FEC0857317EF855482F +:1026C0007EB247E727CF746E1F9ED2F7DB4FED94A3 +:1026D000483E23BCC8E75F09C1F7C16CD7DB6DD7A3 +:1026E000F134613AE747A3FE62EF66B21BCFB64C06 +:1026F0004BC7FBE8BAF67C183902DE7BF5F975B5F5 +:1027000084D3FDD15D2D4F16EE457EF3E6C6227FC4 +:102710001AFDEF9B6EA27A675A797E0DF3F0FCC129 +:102720004AC4EFF8403807D13D5F463BE3BCE6A919 +:10273000965F478A99BDEB576DA959375CEC7B5F73 +:10274000AD690FFF1D14E27FBCA731A3C6897E804F +:10275000514FB138C85FA9DA3393EE6F33F68D96D7 +:10276000BD6EA27CC97957683FB90DE5C3EF4D84B2 +:10277000FF6597311FC6E5CED5466CC1755D96DA0B +:10278000F19E0BCACB17A32083FAE375F913DF710F +:1027900025E64155AC13E8BE9F5AE6587508FBD1B3 +:1027A000EFE9EA4CB5FF01F588FF3D6E87577824C5 +:1027B000E6A2DF69F08DC473246C826F24F24B7241 +:1027C00033BF2FE8E8746EE77FA69F4BAE48D3CFA8 +:1027D000D3E8F9591531FCFCCD69E37CCE2CDF48F8 +:1027E000CC17AB782D81F2C54E1BE76DE03DDA5377 +:1027F00015E3F8B91B03AF15F7B58D447AAB28F58F +:1028000066E0F7CE54F52CE5E5BD1E41F7548A6F1E +:10281000F0DF19AA7CC1BA95DF83E0F900ED8BFAED +:10282000BA2401F311BED7E17B065539DA1DCF5B1F +:102830007BF2DDFB3B3FB45869E4E785F4DFDF3230 +:10284000CAC6FCB08CF33BADD3F3E230BDACCF6372 +:10285000716423C1DF6962FC9CD44BFC1CCA57091C +:10286000EDE711EEAF5EBA8CEE19EF4CF52CDC43C0 +:10287000DFAD74CF37B3352A78FFCE927C8B1FF54E +:10288000F392975F388FFAE0E4D3129D39A87F6006 +:10289000470ECFEB63A23814F367B7D3BDD7DD3251 +:1028A00013D1EE3E69F2D0F7935695FC849383F9E9 +:1028B00039AA93BF1B44E39D141A93112E97914F8D +:1028C000B7EDF164C4EBC96D2F14E2BEFAB379160B +:1028D0003AEF1E2ABF963C1F9C1FDC991A7C6F4F53 +:1028E000C20C1EF74B98C1F13C6C068F2B56867BB1 +:1028F0001F4BA379727E81F5E2E7799827E1C958E9 +:10290000CC6B4A17504EA4485B15CC6FF2E75AE8DF +:102910003E97253B1E551C7C9EFE08E00BE1E7CD53 +:1029200094E7505FC26A709EC8076EF87ECECBEF08 +:10293000B338E71D1F85F3582266DD48F9BDEFA7C0 +:10294000D31D279DC63DF2CCB3FD0D687FF29941A2 +:10295000FCBE0B9FE79E4F112FA2A6219E8B633CCE +:10296000F7605EB67FD315747FEDC9181D8F311ADD +:10297000FD360EB4273C570EE1F181CAB5AF9C4736 +:10298000BE62432535BD1F7C0D84B73EE76466708B +:102990003956D1CCCFE5579A399E966EE7F7AA2FD4 +:1029A0005DC3E3EAEC657E8FFE72AB2F12EF395800 +:1029B000BE4DB2233F2F55BC2307C3FC6ED1FB8114 +:1029C000FA2E9457467FCBADDE85D8DFF257AD2483 +:1029D000E76F9911ABE7B53D12877676DFFAF621FE +:1029E000AA2DB0DE739181F96F46BD9EF979C11EA3 +:1029F000198B79DBEDF77C0A4DBED96125B840D241 +:102A0000D279D6D0F99F32013CD978CEDF4AF76F20 +:102A10001F07F9E8C6FB27A21D0F539ED50712DB3F +:102A2000C6E7ED423DB5C813DCBE72903D0AF9B76A +:102A3000F20FF932B69F3B83CBE9CAB59368DDD973 +:102A40001F4C744E3D741DAE99A1DF1769F0E3ABC6 +:102A5000E14487A7F0103EC2B37314E99BCE688FA0 +:102A60008274E53FC0FC5BA309DE64B4B74FBD3A96 +:102A70002A0BE969492DFFBD9953D1DE6435E07D0C +:102A80000F9DF940B4E6601E1FA3389C31FE52CB67 +:102A9000C676B483F0DC41CE387AFACCFD9C1B2894 +:102AA0008EE1FEFEAF6670BD86B9F3981F43E75D09 +:102AB00048AE791594DB06FF56EC083D77C0BF3F62 +:102AC000ACF323FC69B1C6790711E1F42A783FA77A +:102AD0005F60DA6B76FC7D87BB16E3F9BDA5359B9D +:102AE0006F43FB6CA9CC8A1480AB5390088E4E2B9D +:102AF000BB7316EA8BC071D2F8538DEB9DE7E33AB6 +:102B0000BC4FCFE07642056A42E8A7A241D888FDD3 +:102B10001AF28202F601ED30DF1EF54867AEFE7D47 +:102B200080F91AF80D9DAF81DF5D33B8FDD099AA09 +:102B30003D3C39B6F75C6BF785F15131FFC43F4737 +:102B40007EECC9FF077EDC3F83F1F8DD0C1EB75F2A +:102B50000AF0219C239F0A3EF791F17C7079F48E54 +:102B6000E072664B70796C6B70D9FE767079BB3E03 +:102B70002EC60BF03E0C8C17E013E3059A99C70B99 +:102B8000B08CF1027C62BC00DF63BC00CB182FC0AC +:102B900032C60BB06CE01BE30658C6B8017EFF4E90 +:102BA00097CF9772FE927EB7B3E77CA59BE4DF9B3D +:102BB000AA6A47F9372945E723FD7E44E3FCF09BE9 +:102BC000E599FAEFD9F07D30FFC9B07ECF5F1AE703 +:102BD000E943CF5F7E29B4AF4910FA9EBFBC7BBCEE +:102BE000EBD88CC19C1E715E13877BC6631E7DE78C +:102BF000EA7746E2FD861D4204DD1B7FC378D7C914 +:102C00001930BFAAE6AFE7A1DD541DE69B87EBD7DD +:102C100051A7FDE13AC39E49C57BA99805E9DC3877 +:102C20006F7FD1DF61B8E8EF2F04D39161073E6B6E +:102C3000F227A864B74D7E06E303CB8408BA4FF5AC +:102C4000A895ADC2733FEEDFF1FDB1EEC3269EEF56 +:102C5000B351D8CA02EC49D38DC1F7CECEFF7E3C2A +:102C6000D9E33DE58D82C8AEC0FD1C31089ECB3C4A +:102C70006141F475F98B3121E7BC1283EA5FB1271A +:102C80002DE8FB0897A37030EA57F03B515F66F9D7 +:102C90004607D53FB7621DE503D3791D8C476E1CEF +:102CA0001FD4BECC3929A87EB2C0E344EC3D13CD7D +:102CB000B7AC99FF2EE9F207D6AD21FDB445A07C53 +:102CC00003AD761D9D973A6DE1F124834E80FE148D +:102CD000CABB8DE5EFE7EB7AE8A4D09E8CBFF7BBCB +:102CE0007874E36393053C17B42519CF193D3DD59E +:102CF000957923C9BF8E99D8DF4F779962E87C8395 +:102D0000EC7BE876E8A762D72056A7F5AE7FB289BC +:102D1000C7CFB64C60A4EFB73472BB7F4BE3A0B013 +:102D200011DCAF26F93282B9E330EEDDCD583BAE8F +:102D30006781944976F2B9C312FD7EA6565B44BF03 +:102D400093B7EC03139D5336E0AF18F7CE3331221F +:102D5000DE13C5C81F382DB69D5F8BFA27CB3BD23B +:102D6000877AE5892D717361DDAF535D7908F7B21C +:102D7000F7F22331DFF4DB1D26CA7AFBA2E9B9673B +:102D8000F03CC0DAC6E7148C3B2E913D0AE53FBF0C +:102D9000B445C1F300D7BFB885DE2F7CB184FCC336 +:102DA00045AC86FCC313C63D45FA3C0BA48D23639A +:102DB00069DD12A2910EB7DEC8E5667918DF5FBF44 +:102DC000A938D784F1B1253BA2E91E3A6DF6EC0291 +:102DD000A4836E6F34DD3F769B5EBFFB5D89F8BDDB +:102DE000FB667E5FEB40F7E3DDF47D2AD1EBCDDFC0 +:102DF0005F4E7ED32DBECBB87F9AE9277B0EF0487D +:102E000071ACEE77CF2937617F98D789F9764A3B45 +:102E1000BF7746E4E799B5D9ED446FCB53811E6186 +:102E20007D96BFF7212FE7323F9E6B724E9682E868 +:102E3000AD7A4A78103DCE663141E7FC6EC5E4AE0E +:102E400080F2CDC5C383EAFFE4E6CB43F87B5CEFB9 +:102E500077E2EF8941761CDD881954BE21A87E25D2 +:102E60009B15742E76F1F33C2E5FD9124DFBE8E5ED +:102E7000223F5F3EDBC5DF57ED89D6F7D7C37AEE39 +:102E80000FC1FB5FD0DF0FBA3744DF47AFC47F69A4 +:102E900018B76FA7F8913F41223BB632A383F6479C +:102EA000E2E115C6BB2BDD50C6711DCC8FFB6495CE +:102EB00032C7ABCDAEA6AD4AE8A583AA96E07CC7E3 +:102EC000AAC31CDF469E71E87790EB6BF09EA6AA22 +:102ED00062210BEDF9A53B3A158C3BDDEC4AA2DFF4 +:102EE000735BD41C1C6FAAF076129CB7EC89A37894 +:102EF0006815C68502D6E3E88DDC7F30F66166E3AF +:102F000087E164F7B7A1FD77EE30B7FBBBDF7D4EFD +:102F100030E88865F5C547E58A130AEA31CA2B808F +:102F2000F927DA3FE6E7A64B793C2D946E103F7205 +:102F3000007E12918E02BE2F641C5F0B41ED7AB2AF +:102F40007E3C9E16E13FE0FBA23D8207F34E43F13B +:102F5000B2D0D541785BE8B2D578D4BEF3A95A7126 +:102F600084F2CC77C2FAE27D7BA1785BC4DA697E19 +:102F70008B406EFBA2891E14BADFF975C18E7A5A96 +:102F80009BD0A1E079EA5EBEFB90F8ACDB0E5C8CD6 +:102F9000F371323ACF0AE3590605DCAB3DEB7B1EF9 +:102FA000F7B815EFF91F8FFC12CC5FB77C1F47EF06 +:102FB0007F3CDD7450FCB50AE384917DF15185714D +:102FC000C3C8BEF334F6A77AF483747B14BF9F762C +:102FD00055BFF7B487C619CFDCA8E7E35EC9AE0CCE +:102FE0003A2F30C0FD3BA1E7050AA46251817995D3 +:102FF000FC4EA7C31516D2E7DD6E13C943D7EA020C +:10300000D277AEDFF1F2B207328604C6075D7A5C92 +:10301000CD2827D70D8AC3EF255695CEB594D44930 +:10302000F47B07FF07B44280260080000000000008 +:103030001F8B080000000000000BDD7D0B7C54D5C9 +:10304000B5F73E671E992493E42424909000272F1F +:103050008812C2849720140F7960146C87F04A207C +:1030600009130C0888DE10B5464B9B09090F016D4A +:1030700040A8681102556A5BAE8DD62AEDA5BDC386 +:1030800043D4A2B7D457B5E58341AAB5B6D6144BFD +:103090008DF7F3DE7EEBBFF6399939C34BFBFBBEF0 +:1030A0007B7FF78B3F7F9B75F67BEDB5D76BAFBD15 +:1030B000A7718743E80384F83BFEAE13625D67FEA9 +:1030C000D070B110EFDC3762573089D27BD2074E17 +:1030D0001C27C4D9B5AE748F1E29F7CEDACAA162F7 +:1030E000147DDF1257D3ED1562D8373CC2912EC440 +:1030F0006DCF0EDAE35084100EEFC01A823F7C7A57 +:1031000040A983C074BF2A4486102BD7FE38792289 +:10311000C1B7AE7D6D829627C475370406F8C70B1C +:10312000F181B2679F8682DA9E123FB59BEF175CF2 +:10313000BE71EDDAA182FA5F416D3A4AE99B083629 +:10314000086AF7CE78A16F4C15E2FD7811BA8EE0CF +:10315000F79F8AEFEE40BF9E762EFFA70CA1213F7E +:10316000904B4D127CFEB1A4EE20E5FF493DF4B733 +:10317000F594FEB13438DC914FAD69817C3FF57335 +:10318000AB7A701EC6F581D2BD2F93C6B1ACB52403 +:10319000FF7763693EAD13380DB417A604082FE11D +:1031A000B603E26C61040F01218C1E2FC6D5ED9E83 +:1031B0009514F9DEE02E2BC6BC563829BF18ED8DCC +:1031C000E476ACFC2333691094BFAF8DAAC609F135 +:1031D000449B87D3EFB769428C10627F5B26C34F55 +:1031E000B6E99CF6B415F1F77FDA418D44AD57F698 +:1031F0004C9DDBF948882A8C6398E32FA52DD45F7A +:10320000B04C1435135CE998A93E4CF3BFE3255745 +:10321000771CE1E20EA5797798F07547BB5304C798 +:10322000A15CF3770107D7C4691D943E94F88DDD46 +:1032300061FADEEAF468713ECCABF91AACC7977A52 +:1032400085682A12FCF777FAFFBA3E8F68F244E0ED +:103250006922D506977BB26CE52BB55C5BFEF599D0 +:1032600057D9F26FD04B6DF08CA249B6F237F9A660 +:10327000D9E0AF4CBCC1567E9631CB06CFAEAAB5D5 +:10328000959FEB6FB4E5CFAF596ECBAF0DACB2C12C +:103290000B97DD632B5FDFDC6ECBFF44154E41F4F3 +:1032A0007390D64FA7F5F939AD1FD269427FB94E59 +:1032B00089ACCF9472B519EB62C1567AB7B91F5E6B +:1032C0009E65AC029D08712217749B4DFFDA48740D +:1032D000BECE2FD7D5FA9EE394DF09CEC27AC4962C +:1032E000BF54B92989873FD689A4FE7462DE32E7CC +:1032F0002482AF393C369F60DFAC479639B3089ED5 +:103300007CF84779044FFCD569993FFAF0C7C80F9C +:10331000FD6A97CC9F4D4D5D2B44D9ACF265419A27 +:10332000C794EBF236FBA81FF14B97EF714ABC2212 +:10333000ECAEA67E6EF77843F9C991F9012F4D8561 +:10334000122F484344D7480F135D233D4A74DDE4F0 +:1033500012E218D135D217DB7CFCFD176D13397DD5 +:10336000B9CDE0F4DFDAAA383DD1E6E7F4D5B61AF4 +:103370004E5F6F0B70BD37DB9671FA565B337FFF84 +:103380004D5B2BA727DB82FC7DB75F613C8B03AED7 +:103390003F85ADF5CC03596BC249F3E810A2177C09 +:1033A000421CD44419D1BF382C7A187F6167EA7B5C +:1033B000B4DE6049D1EB169B0A2283F7AC76A9F004 +:1033C0009B4EE307723D73B4F71223DF4754067A2E +:1033D000F0FD8DDCD98563099ED7D7FC7C0AE5BD5D +:1033E000A18A6517A38F75A00F2ABF6796F163D4D2 +:1033F000FB92E7542DF89E9E25343119F0CFA7019A +:1034000056EEA5FF699DBEE43CD101B8E353A1AFE0 +:10341000A17D7E28E91897EF88175A1CCD47E93B14 +:10342000A1009E4A7B3A2E15E508A6F94FC5D8297A +:10343000FF4B5ACF34C01D4B8458538AFC1E99AFA2 +:10344000517FA5721E6282100548097F157D27CA2B +:1034500039DFEBD6E308C5530BCCF215C44B52B998 +:103460007F1E5FC72AD9FF639F9E30902F8837B990 +:10347000305E4F88F3A70684B62615E36BE6FE0997 +:10348000B6C6C7E5A7A24E2AC6471968EF2A2A2F53 +:10349000C7B78AEB67CAF10F72CAF26E9A5FFB2454 +:1034A0001E5F23D7075BA5FC24A76C9F48540B52D3 +:1034B000FF6EF14CA942F5DD2BBD3EC88DA9C52795 +:1034C000B2CCF6B46054F9141FC1D45EC1BFCBFEB8 +:1034D000810017C1790A09A8FCC83EDD39ED442EE8 +:1034E000DADB799787DBCB763C550AFEEB340CA10F +:1034F000D2F7D93739BA37D2F77FA90C9CC37A3AB9 +:10350000D3551E6F8791D4BD91D6EB573FD387F823 +:10351000A8BD59AA08405E5C861E3EF9C7E8E1D9FD +:10352000FEF58D637CF7487AA0F5B5D183AF9F1E79 +:1035300038BFA392E8E122F472213D846A4D7C7386 +:103540007B530B22F401B97B28E94D83DB1B25FB60 +:103550007FECD3661E2F0428F0D94F0FCD727D95D6 +:10356000BE087DC495FECFA18771CE9E3DF81EB7E3 +:10357000D2E3C3BCAF441F8B7AC5F4142AF2E8F43B +:10358000C03AE8218D7DFA31C0378B69D3890DF7B8 +:10359000E7EF43FEF80BF3037FED7501B6BEBF62A4 +:1035A000B663E53BD35F4D841CB0DAB1CAFDD16C84 +:1035B0002F526E8CC74FFACB1D953D3BA10F544146 +:1035C0003FC0FC84846F247D60230A0A23B97420E1 +:1035D000C977FC93DA118E29475BA05F91D2E40092 +:1035E000ED785DEF843DC8D299CF5ED7E764D8927D +:1035F0009B378ACD4EE0918AF7C611DEAB04E55BBE +:10360000FC93E8F4C6E2DFFF068B72A388AA47DFCB +:103610005B4FC63F7F344A1ED7CE4A4A67FE9A2B7D +:1036200072C15F8F402F73613C7529012F8F8FF519 +:10363000AE58BDEC9336CFF3475DAC9F056645E9C8 +:103640006702FC8FE6B9AF5153591E089F3A86E0D6 +:103650004A436F017C7886D4D78A48E2A15C4596BC +:10366000C2FB99BA79FD7682AF871CD6309F2ED6E1 +:103670000B6E143D9CCE142738FDB2E8E5D42F7CA8 +:1036800007C3349FA3E7278C1B8B7DA386D6D11C51 +:10369000C4478DE109C87F430BDC8571FD2DE957D7 +:1036A000A714089FDEC008ACDFE10A39BE96B9C492 +:1036B0005F891E0F7BF2591F8DE5132F917C2D28FA +:1036C000043E04A7CF93FC2DA0F9BE40F217F08D65 +:1036D00045ED02F5A6EB8A7046E1D3AA3F432B17CE +:1036E000CE01979677334A7E9203FC1E4F1D51817F +:1036F000753A9E7A4D8528413A4895699C1BE9A503 +:10370000EA5BFB6146F1FA138E12F4379DFBEBC7BF +:103710006B861DAFD381571FF01B744218DF20BA90 +:10372000399D21428CCF9B485003FE0A6D43C04710 +:1037300012BF5CF74FD445F9D8F2027C5FE9E91D6E +:10374000EA5619AFDDB3685FDCEE089CD6A8DC87CB +:10375000430223521C188F60FDE0B0E7B567A1F764 +:103760009E43379416749E60F84E97A4FBDB9EBB75 +:10377000A94C07FEDF7074C3BEF9038648F43BB55D +:1037800075328FFFBAD6499CFEBE4D0481EF951E5F +:1037900089C70F83874A1CD4CFE994400FFA5FA9E9 +:1037A0001E4CBE96C6F7FB9DAF3D09FBCAA2DB953A +:1037B0000E7DB30FFBEDB8C3F738F6D567478656D5 +:1037C000275D9A8E897E0FD8E8D71B183C0B7AE1CB +:1037D00063B3795C16BDAEF44CB7AD27510FCFF78C +:1037E000D9E906EF7F4D8456613FDE4EFF84DE73DC +:1037F000BBE7E5E5CCD7088E23BE16AB374D4808AE +:10380000319F75139F075FB5D6333B2EB49CF5D11E +:1038100044A175403E04C65E0D7EF2CB09C62B98CE +:1038200077A5A378BF85DF38F0D5D0C81494AF7AD8 +:10383000D121BA69A82F2494EC079F0913BE15D291 +:1038400037AF1FD9ECCDA3755A3123F016EA0BC759 +:10385000670EF4FB72A1220650F9732F8EF5820ECB +:10386000ADFD7E297A8BE51B61F08D91F48F1251AD +:1038700002BE51E9F0FA4218D7EB0E1FA9EF64FF20 +:1038800024AB2C574C7B69AA18FED014CA2F7FD1C9 +:1038900025BA29FF1C1A42F94C85ED498B9F5C27FC +:1038A000FC9D5340BF86A737041D2B53157A14DFA8 +:1038B0008BD713841E358EC4A2341B9CE41B6C2B47 +:1038C0009F3231CF969F6A5C6DCB1F5035C606671D +:1038D000F8AFB5951F54536683B30237DACA672F22 +:1038E000ABB6C1439A17D8CA0F6B5D6CCBCF0DAE88 +:1038F000B0E53F2FFC29A15C9093F16AD104F03D23 +:10390000F997BFA1C5568E0A1C0D105EB289E163FE +:103910001F1576DD6B6B57E82EE6FF41FA0FF45565 +:1039200099E98AC8032C6FC2CF15AC4FB8D1DB0C14 +:10393000BA28D7A61D85182AD75C36B992ED7DFF27 +:1039400024F851768C3C895D7FBDFA0BAE7FE0EAAE +:103950008BAFFF4AD11DCC8DACBF30D77F3AAD3F86 +:10396000F8D5881DF6F5BFAADBBEFE239FB0AFFFDA +:10397000A81EFBFA8F3E605FFFD2907DFDC7BE6838 +:103980005FFFF127ECEB7FCD5B6531EBD0CBFBE745 +:10399000794D118F5C64DD2685EDF4211C9B79DD6A +:1039A0002CB93EF9FDEA8BAE5B0DFDF75FB16EF30E +:1039B00063D6EDBCD83CBE340F7253F2F1D87D6FA4 +:1039C000ADCBA3A9467D35F1A755E0F3947E12FF58 +:1039D0009F7BC06774D26FC450B2C313081E17E137 +:1039E0003BC1B266F67F04DD1EADC3C7F4C0EBDD9C +:1039F0007A32A91B76CE276A380972E594DAA520B7 +:103A00009D3C3E706B35F1A745C5CD8A2039932981 +:103A1000FC4F2D853C1FD27BEA6B68E79E24C9CF03 +:103A2000C90456D1CF3D497B3646F9071AB2453312 +:103A3000F8F79DD5925F0B5F783CF8F8DDD552DF43 +:103A40004FF2696E88C6C662617483CF3BC5D006EB +:103A5000CACF480BACAE66BE3A65C7FDE9A0CB64E1 +:103A600011378E1786F9EAB09768BF018F4E433D34 +:103A700083EF2FBBBA1F87FFA7D01708C1FFA30C86 +:103A8000F5C1FFE3700BA9C76E8DEF7E5CC177DFD8 +:103A9000A054EACF914C7608A577C4137C113DC39E +:103AA0004A176F708840947C99BC29AE598E53DFB9 +:103AB000D54AED37FDB978CC4611C96F72CB766324 +:103AC000DB894B9BB615F36915E67896A93CDE3F7A +:103AD000788EECF81DB5BF3CFEF80EF8CF263B5EA5 +:103AE00065BBA497F2F642CE38A55DF2488126A0C8 +:103AF000A74D1E168A1F81FCEDAA6FAF607CF1FAFC +:103B00003DB252673B6BB2430902EEFDBABB7B2F5D +:103B1000E4B84BE607EF1ACEF31766FF8F346BACB1 +:103B2000878CD8216C7AD2234EE9677BA45B0D1673 +:103B30008EC6BEF60867143D3F023F1CCFBF3B1E3A +:103B40007E91914F68B6FC513D99B6F6461FD06DF7 +:103B5000F9A5A1225BFED8177D3638ECEA7D6A38DC +:103B60008D2FF8A8433CEEC3BE9F68AB7FCD5B862C +:103B70000D9E14AEB2D57FAD3A4FD299DEFB97279A +:103B800069DE0D1DC374F0E5C9EFFB6DE5B29D273D +:103B900058DF1C9A29ED1DB28F187637116F243C1F +:103BA000E778A43F2107F65516F66F80F1E62C90D2 +:103BB00030E5B3BDA416D9F3538B647B642F19D8B9 +:103BC0003FBF36FD9705225C0BFD4D38C357416F53 +:103BD000688813EC37A3F563BB71D73D836DFBE6B3 +:103BE000ED6AE93FFBF54CC1E9E31EB1C8CF78F7B8 +:103BF000BDF502CA2B7ADEC6F448F933E6FEDA5A7E +:103C0000659C063FF8F54C8DE1DD49EF2FC7BE6D91 +:103C1000182DFBAB53D545B3A81DB2D16A9E8EA219 +:103C2000FB3F554B3FD24B73643BD6B81B52E4F875 +:103C3000C4D7DC4CAFC219643B73578248053DD6EC +:103C40006FEEB97F0415AD7377B9D89924BA5DD0FA +:103C5000E7679691DE4AF49BFDF2A7DFF5127E76C8 +:103C6000B53AD9CFF6F1ABAB97070BA0D7F64AFB25 +:103C7000B899E6560A3B82F6E498C878EAE738B87D +:103C8000FFE4D972FE958E835CFE5CABB4AFCF8946 +:103C9000503BCB29B2A7E18F1922A47F2781D60FF1 +:103CA000F8A73F15B0AB4B309DEF728597637CF062 +:103CB000473B5DD21F8D14FE6867A1F44703863F22 +:103CC0001A29FCD1F8FE749B8FE167DA2632FC6C6E +:103CD0009BC1F081B62A4E7FDAE6E7EFD63ACD5C9B +:103CE00023D7495FE5F2EF257CCF5445951235AFD8 +:103CF000E639725D27CD96FC1AE5C04F2A1D2F17B5 +:103D0000F07CD23555CE4F4F019FB2CAC7F293FF18 +:103D100057F3C87686188F433DD26F30C41960FEC2 +:103D2000E126BA663A37F3B39A259D13DE799F7878 +:103D300035CBCF7094F3DD01D293534D7E13E5471D +:103D4000C916725FA54227CAC247B96FF2A86FD0E1 +:103D5000934577AE98FDD25DA056014FEB93247E3C +:103D60002D3C2C9F2DF1933EDBF48306C97E9FC032 +:103D7000ADF25FA5E3B346B4BF2449FAF196DCE3A4 +:103D80003906B9BF24CB2182B4B7A71A9A1BFEAB60 +:103D9000C5C432F7C00F143F94E1F034D1AB649343 +:103DA0005C0ADAE5F92DD00B15D687DD68F766AA2F +:103DB0007788E8F7E60D31E5BCEFB1DC5F1223F759 +:103DC0006F119BFF42B287D22BD8FFB34D7D60B4F9 +:103DD000180D7D4038BC6BD6435FE926FB2C376A53 +:103DE0003F98FECE73DD3F92F06AC1FEA3583DC1FD +:103DF00082F51DD458D4390DE135A108F2A1D3E9DB +:103E00002BD42FA4330BAFB47E6BD6B27D23FD7CB5 +:103E100064EFFC12E3F913D9377154EF4FC18FCF20 +:103E200030FC4CBC0F7E930F4B4F94407FBECDB106 +:103E30006728ECD100FA2539571010C114B4F344A7 +:103E40003CB7736E35111AC6FD4462B720381CFCAE +:103E5000D1C08BD93B81B0C3762E149B5E7743A033 +:103E60007D368D33E0127C2ED7B1DFE16BA771DC9C +:103E7000E73D3CD0F07EA173ADF568C7B23B6792D9 +:103E80003C74A445F2AD732DD2ABD7AC4D97F8007E +:103E90005D9D0B7E2CF17FA760FFDC57488104BF3E +:103EA0007943103784DF53905692FFC5CFC366F72E +:103EB00095F27ACDE99BCCF30F6C98C4F0F0614198 +:103EC0003501FC73A1C2E714F31F136B13A86AB882 +:103ED0007DFE78E0EF7173DD869B7226165F034DE1 +:103EE000BE32768EC55FBDBCCF5BDA15B60B5AA06D +:103EF0002B00BE5F613BC0823FEE32E14A09DFB179 +:103F000056C2F4D7007D78B148F66D1C27E7097FCB +:103F10000CE68914F384DF60BFE9BFC13C91629E67 +:103F2000F80EFE0418FC0930F81360F027A4E04FE7 +:103F3000F8FE6E6AB91B78C5795D45D47EC3795D9C +:103F400045D4FEC1795D348CF3BAE8F238AF8BCE3C +:103F5000C7795D743ECEEBA2619CD74597C7795D6A +:103F6000342C26DE108171FE62CCB2C1B3C98EA89A +:103F700088DAEF38AF8B6E1FE775B6F602AB6CF5DB +:103F80001792E6185D3FBFB9DD567E51AB623BCF5D +:103F900023B6C472F8E61D03985E1EABF49F055D60 +:103FA0009F4EFCCFBB5C79CC3FD80FD2725B824F67 +:103FB000AE7757955C7F55C8F5EE657FF7C7ABDDEB +:103FC00012AEF40DD22E42473807AB70C97330A43D +:103FD0003807438A7330A43807AB2894E7604871E8 +:103FE0000E86EF3807438A7330A43807438A73304C +:103FF000A43807438A7330D4C33918529C83E13BF9 +:10400000CEC190E21C0CDF4FD1389AA2F81CF4DA32 +:10401000029B7D4A7468B34F351B0CBD35BA3CF426 +:10402000D6E87CE8ADD1F9D05BA361E8A9D1E5A1E0 +:10403000A746C3C367EBCC37A0AF46D7835E1A0D44 +:104040008FEA0A3E0FDFDB4D3BFF7C14E9F094C69C +:10405000A715621105739257E0BC727862E3985419 +:10406000E2F9AEF6012B2A080EF4C9F3F212D1AB35 +:1040700082BF046084D2BA054282F5FF519F667107 +:104080007EB6A90FF21FAD7BE93382F54DEB7CDDE7 +:10409000AAEF139A03A9553E025FBC5C6CFF56B9A8 +:1040A00080C73E0EA2C752F0F9D2D5DE31B053F62A +:1040B000A9CA223FD1D33ED297AA89CF8EDC6FA85E +:1040C000F1945FF38C56EAD051BE790CF8728DC929 +:1040D000A7ACF2D46219C6FFDD45BAE9C796F3B9B9 +:1040E0006962EE5ECCC79823F95EB6A98F119F3046 +:1040F00010BF31A5F744790A950B04A78D47FB3310 +:10410000DDA63E2D9AAF853D3A32A8187BA3E8FB89 +:1041100046B39D40F0A9C3E0B3DFDDFD65592F41F3 +:10412000D6FBEEEE64EEF7CB9DCA5EC8E329FB85B5 +:10413000B187EACF9E23EDDA91FB430EF4D7D8295D +:10414000FBB3DA6DDC39D4AD7B23786A14CDF76626 +:10415000C27E1DA708F0F1E1CE00EBAD83EA341575 +:10416000FAD1ED1822A5EB8B9AFDC0EFBFBB741EF0 +:1041700097DB63B03E75FB815902FCFE4BE3522B8B +:10418000D3D1CE41E12B04FD8CFB956DBE8C26D2A4 +:104190008B86E31F3ABEAF5233317E42C000A2A7E6 +:1041A0009B08C67C0201D19C4B22675E4D23E3B97C +:1041B000A84E28884BB9AA6E8F9A4EF546060EA9CE +:1041C000E877545798536B1EBE29A90EC0335D5A29 +:1041D00025C63FB35261BE41F29EF596739D2EB641 +:1041E0004F2DBDE163E80D027A85EF2B90D72D6B43 +:1041F0005D027674CBD7FBCEAC071FFAB15D8F089A +:10420000EC50988FAD5CF5C60495FA6934E37A3EBC +:10421000C8EDDE974A78F920EFA9E4898AD403E64D +:10422000D078CE744A3DA271EDF3C9380FF8B8F3D7 +:10423000C76ED841D6F94E938907516C1CC3781AC2 +:10424000B3A4FF4E380EBA21C7CE07BCCD0E82DF15 +:1042500021BE628C607EC9E53E3EE09671235D52D0 +:10426000DFB3FC438DAF0C18083F46AC1EB8BCD37F +:10427000D5E8263B7A798C1E78EB15F4BF87E79852 +:10428000E73F3EE183FEF74ECCF9CFE22B9FFF7470 +:10429000CF89F29FEB223497F97973A18A75687CF4 +:1042A000C5C1F47BAE47DF8BF3194BAFA96B2FE78A +:1042B0007D287E2CE9A8AE5D96ABFB89D1AD5091EF +:1042C0005F9AFA4B755F36AFC76BA6BE32B76F24E5 +:1042D000F38199E178FE3EAF2F8BD3F97D57F1F74B +:1042E0006AAFE407E19F89EE35AC2FC5493FE35142 +:1042F000D12D722FA4CF59CE6E355D015DB5AFC9FA +:1043000020F826E83FD45E0DF4A101A0F755CF6751 +:1043100080DE1FBB38BD573B4373D07EB5CFC5741D +:1043200078397A5752A3F89608BA0662FEFB854F91 +:10433000EE4771D445F65B43A269AF7BA5FFAA5F48 +:104340005FA4B1C0AE15C1552BA0673620E861301F +:104350004FC710B4BE49C532FFDDD757ADE87482F0 +:10436000DEA59D3AB4559EDB5A30FC0EB0AF0A6014 +:10437000D752FF033DD2DECA33ED258D68633DDBA6 +:104380005F06F30732CBF476F65BF8797D1288C1CD +:104390006E61BF84CEF3CAA179217F88539EABB9E9 +:1043A0002BACFE4468E098887FC0B28BE117007F99 +:1043B000ADBF53E1F66FDE50B847DA19C583CED0F2 +:1043C000F7AE7965EFCE25BED3725FE1207199F328 +:1043D000889B699DB02F1B52C27729846765AE30D8 +:1043E0002A48B5AD15269EA87F41735960C223DFC8 +:1043F000D8F2C18662C62FC3FFF1FAD756200E67E6 +:10440000FD94163FC615E1777E03665062B1C1E7A1 +:104410007BB1E3B7FC1023E7CAF2B1FE889B8BA502 +:104420001CB0FC65EFDCF7DC93D1FE96775CA2460E +:10443000DA03BD6CC77CAB3AB374A31E912F8FAC6B +:10444000C861793974AE298F681FE823A47E8B1464 +:10445000FA2DE2A3A0DF02867E8B14FA2DBE43BFA5 +:10446000050CFD1630F45BC0D06F9142BFC5F7BF9D +:1044700096F9338167C2389F578BA2DE871FA7FE4C +:104480001BDADC02E3B1ECE3DD2B12F8FC7FF7BDB5 +:104490006EB69B2C3BB9CE7DE2794F6E040FBF6D9B +:1044A000DDEA927C2F5488F3BD05CDF13EECFFAEE2 +:1044B00079FE42F49358EC73839F048ABB159DF0F8 +:1044C0003A589376D1B0FCDED2BB287D77AEEC6F44 +:1044D000669E947BC31CE2A8207BA876BC513C77E7 +:1044E0003CDA098C463B8B0F961ECBD6218F52DDD2 +:1044F000589F8641D2EF4BF8E4733E0BCFD3E64A88 +:10450000B97A7E9E90717DC03B9793FBA0B65553C0 +:10451000704E972DA47F2DAB4853E0679866E2DD7F +:104520002D5E97F49C29FD0B434CFF81B740FA1395 +:10453000FAFD0745EFD4421E45F0A21D63BF689205 +:104540005B873ED2E81D3E7D10C18D5D4A9A425583 +:104550009ABC82EDB9A66DF97B114FD2628E93E8B9 +:10456000DF9D0579749FA2415ECD4CD3E74F423B5E +:104570002FB9C45EAAB7F8CE4385BC5F284F29BDCA +:10458000703F34ED98C4FBA1A99BD2B197DE370BE5 +:10459000B71C19F213D05BC87063BC4D9AE14E8B07 +:1045A000F273DCDCA530FDC6C28BE73A24BD8B1765 +:1045B0005D18475D81AEE07CB2C55CFFFA3B73DD00 +:1045C0008BE1F7837F7E0CAFA3C4C31645DB9B2B27 +:1045D000FB1913D5EE62B41BD5AFB5EE2BE726C998 +:1045E00078554D7767417E681A8F8FE6EF623F48B6 +:1045F000819CFFCC349FDB8BF69753FB84C2055A1A +:10460000A812F90B8A75D14EEBB5B8B394FDFD81B4 +:10461000CDB29FC08654F728C869A7E61E42705DD8 +:1046200082DC6F343ED61B9B081F69F0A3A5919EC8 +:10463000E8BD102F8DE6789BBA52DD4B6CDFB7B822 +:1046400040CFB5A69DBFB873D6D087685C4DC15129 +:104650006968BFC929E7BDD35CE78089CFDA6D2FD0 +:1046600014228EA5B639AB54C98DB477BF497F3BB0 +:104670004DBC5A78A9D5BA5C68A71FAFDBE5BC97DB +:1046800068A142F63B79E4BCFBE9619BECA7695B5E +:10469000A3BB98D2A54EFFD087A8DCD2E02B3988E7 +:1046A00047D969E2B976C721731CF13E8C43688112 +:1046B000A1A08BF7B6CF1FCAF3DAF6900B784CF2B5 +:1046C000E9D3A13F123DB0DCB4E8A261ACDC7F5677 +:1046D000BF4FCE75F2BE7872AED44F2DB990D02AAE +:1046E000F74DD3E65F317C33ED2BC843B77846B145 +:1046F000E4D2E5F659ADE9A7DBE5F6873295C8BE09 +:104700002739D8FCF445E4C4BB66FF0BCC75A9532C +:10471000253FB1F2DF986BEA21C06F547DB48776F4 +:104720008F98EB5557162A5C551C296FF55B972619 +:10473000EB617D402F47CC7543F9162EAFDAFC377D +:104740002DF74BFF4DCBFDDF590BB9DFF294C27A49 +:10475000E71F5B9EFBB779947EF0AD3D0D989F35CA +:104760008E25A47F603F2F35E55C53E8E2FB7ADCC1 +:104770004D8157E746F96D9B1EFCE7E1E08B7F7C9E +:10478000F238F38B93B4960EC2EBC27FFE8E0B7C95 +:10479000CA1AFFE20D7B36E4A5439EA58E811ED387 +:1047A0007F4E51A4B33DF0AE39DF9B3BE57A095A09 +:1047B000AFC254D8198DC2001D64FA7C90DB969F5D +:1047C00035CB27FDE1D67A09D39FBBAB50C6D15A72 +:1047D000EB5697D765DB77B1F3F9B389F7BF98F25A +:1047E000608149670B966DE17A8B37347E07FDD681 +:1047F0005AFBA8C9FEBDDF5FB6D925FD659B0BD767 +:1048000065B2FE29F17DABA3A7E46E2AF7C7958FA9 +:10481000DF9E95C7727B28E4F612D3FFB5D4D4FF90 +:104820006E217C5FCC0F48F816F3A2F07DCB6E8929 +:10483000EFBABC9E3FFF14F35A15C7E7657FDC3F14 +:1048400096FDB60B15D10CBBA6B6678F2B1BFB6C68 +:10485000596A1AC468EABC5C9E5F3F9F6D2ED5E022 +:10486000C74D9D27F77D2CDD46F02AF7FB2E97F4E8 +:1048700063F7C36912B6EAD50A6310F6BB08E60807 +:10488000C8F5483FA9695A09E9B5F3549BBCB5F28C +:10489000CFAE6A7C00714767E3255DAFA4F6707EFA +:1048A00073769A6F28E8DAD2DF447A88E9AB611828 +:1048B000D9C790A389011DE3C84ED4D32017C6CD14 +:1048C00093F45350A05F8DEFC92AE9BF38AF22316E +:1048D00032710CE84D88F831979653DF4EE8B9AA4B +:1048E000F932FA5FC1CAF05F304EB009B48334893F +:1048F00070B0C0C41FCE01068E89E8A1B17C2856D5 +:10490000BE5BF562E97963D162A62F5781DC47D699 +:10491000FC69BEDD324E47CE97C6CB71A4DF4E9305 +:10492000B07F9EA4E3B3B94619CEAB7B2779B4BD63 +:10493000A44AEE55F5168EDF25FB007AB628320E16 +:10494000BBA1777DAD5843BC83283058AF6EC8D625 +:10495000F8DEC5D976A9879FAD95F1409F777E6730 +:1049600073E57EEECD121ACE77AFC4676B9B9420B1 +:10497000CE235CAD497B6DFBA8CBC17EDA735D6352 +:10498000F93EC839D89218D7AA788E533B9B6BF959 +:10499000378C64C8BD53C151A9382FFCA2FEE7BBB8 +:1049A0004C7AAC4B907C95B4771EDFA9D67CD68729 +:1049B000ADEF967C3EA58593D2A2F830C98724EC52 +:1049C0002FD19A2F102770AAEB6C92CA742BC7674D +:1049D00095BFD325DB15496E3EA7AEBF7396BB913D +:1049E000BED7B7BEE652280D9A743B2CBFC71894A9 +:1049F000CE7A9C06FDAB23C997897E3A527D99D128 +:104A00007A41A2771EFB59CEE6860AE077EA2D8D21 +:104A1000F741DF39E59D373D0BE3DF91EAC37EBF08 +:104A200053F19DC239BE581BC7F6DECA9E43056CC2 +:104A300017660A15FCE16C6ECFDF7E033A599BE8DE +:104A4000437F3355B101E779876F0A7C731EC6E354 +:104A500030FD529F51BF64BF5E8D46692F794DFD79 +:104A60007698DB50DDAC2F3A98AF5AE7282D7B1CA7 +:104A7000367FC89297E4394ACBD76B065E0B39B4C0 +:104A80009D836E10BFCFFE9F883E29CF6F96C0FFDB +:104A9000112577D66D2B1F887B4D4D5B2ABF1524C2 +:104AA000BE3954117EF09BDF39C3B3401FEFEF19BD +:104AB00094D61EC5D77FDB1DC7E769EFEF79EE956A +:104AC00009D4DF9F0F64F03D2661A86C57ACCF4935 +:104AD000E7F5DD3F4FCACF28BF9331488FF89D9A45 +:104AE000F6ACE77B524DB7750C47FAFE9E78BE2FA9 +:104AF00055A1CDAA48855EB33395FD79BF5D29FDEB +:104B0000082B7E55C8741C32F7E1CAFF3CB20BE794 +:104B1000434B72CD7B4C3D891C77B6B2EDC050073C +:104B2000757D9D16F817F075DC5F9AA4CBFB4B5989 +:104B30005C5EBFA83FDA4ADF6B93F7566EFBC65B3D +:104B4000DCCE87EACB5FAEA5FA2B6FFB5132DAB928 +:104B500075FB6B133495FD452F601DFBEF67ED90E2 +:104B6000F7B33E88392F5A71E9F3A257E645F95950 +:104B700062C7F1AA799EFEAA490F33D3FCF36A25D6 +:104B80003D303D5D6AFCCB0E28B673BAFAEE1437A1 +:104B9000EE160442C2AD15B39F97F5E0F71DA2953E +:104BA000CFA94C7DC7FAFEAEB95FDE4FE91A0AFA0B +:104BB0005CBEEFA1A1D80F7F489270E0B11796DCE0 +:104BC0004BE3086C53710342049CC2EDA37A370790 +:104BD000A53E2DBCC4B42745FAFF685E22B7B73C9A +:104BE000E67E9640D4187DFF8353C685E07E16F49A +:104BF000B2DF3A434B4047BF25FD35C8EB6DDAA322 +:104C00005D8EE91C8F72A7220A15C03F4A2A907E4A +:104C100013E6AFE25F641C4FD2B89E10F8DE6DCF92 +:104C2000901E24A41F02F4DDF213D7F46CA9A7711F +:104C3000B4F64A67C87D313A5861EA67FDF0334FF0 +:104C4000B9A137AFDCBF85F51F62BBDD85B9D8EFF1 +:104C50004F1D1B9C0E7A6E1CCB7761CCF2B73F23A5 +:104C6000F1102FC2EED951EBDD5894B62E9BE481A2 +:104C700036FF9115DBA97C23D6E95A6A72EEFA5BFE +:104C8000DB0B909A7E76672FEBEB1B8B5E657BF8D8 +:104C9000B64ED9DE6D45AFAECBE379CD1A20A2D6A4 +:104CA0003F75BE8BF163D5A77973BDFE78AD354EE8 +:104CB000D1318EEFAFF17DB6D6609C8638D3479662 +:104CC0007F95EFBB65C47934C4B165A40572E7B3C1 +:104CD0009F5FDE6BA37434D28BC449D5C0CF69C546 +:104CE00049755871425BE265BE1927D59124FD22B2 +:104CF000FF857152D7CC273C846EFBC5481E8F833D +:104D0000F41352FD8CDBA7BC758CE619EAF022681F +:104D100055EC6C3EFC47C4F718ED293AE6FDA89027 +:104D2000F16AD799716A93C707CA80874CC4273044 +:104D3000630B29588F8F7EF6FBB1C02BE2D740F76B +:104D4000AEF6BDB756109DDF385F93F103C5E1B1F4 +:104D5000C057C66153DE394FB0FEE0CAD4D320F746 +:104D600043E63968F05319BF7550097D87DBD71CBE +:104D70007721EEEC845A320672B67DBEDC7F9B2A28 +:104D8000FDD5988FD01D8568F723D7C95CB417A4CB +:104D9000EDE4C8267E3A78E20EACDFB40E52BCA633 +:104DA00008A12A19C249F026A1F6E25C7F8899FF82 +:104DB0003B5A5F31918AB8355146FD4F392C7A38CC +:104DC0004EBE78B1DEC5E50977D811AD5A087179C4 +:104DD000A225D907BD25DBF19723386FCFBE5BF144 +:104DE0004196349C7B8FE3814E7DBA3F1E76C7BDD2 +:104DF000E303CB30BEC10EE30CEE924E3977C0A375 +:104E0000405F28513587E997F50C14A24CFE531CDE +:104E1000BCE7D3E40CC425F60E77FE90CA7D647817 +:104E20007CF0F39DBA77E4D1C918972A7AE1371755 +:104E30009E4AC3761F8D96CA3321D24E7CD788FEF8 +:104E4000FAAC5F15EB4727A79BF7D57C17D6FFC8B1 +:104E5000A7733CFC47BD7DC9E06365078FBCA59087 +:104E60009E53E6F186104F213CAE3FF5FBD3D1DFD8 +:104E70008921A9889FE03D4D781ED821D7736A8A81 +:104E8000DD2EDE3A5FCAB7ADF3A53C72EA3EC63707 +:104E9000E2B8B18EBA2018E334EF879CF3BAA5DFED +:104EA0007A591CFBDDCE1DCC4F1197D917AF41DFCE +:104EB000223DCA71BDB11578FEC83585DB0BD27AAB +:104EC0003BA672BC09AFB7A2AABDD0C369FD787D6D +:104ED000AD7B7AD77D26D7B3BE39D907BCD2FA8D40 +:104EE000FAA680DD167EF4970AAFDF6ED0F9237D37 +:104EF000A44DAAD8AFD37303C5FFFFACDB27F1C91C +:104F0000FB80AF483C2BC1E95F249ED59F302297A0 +:104F1000F9E251E03F4BF43EAF123C4804992FFCBC +:104F20000FE28BBF991F1D3FEA55594FFEBCF1A3FD +:104F30001D881F2D45FCA8607BA2F79E24792EEBCF +:104F400024CC227FB5EEC33826E3F207E727DAE365 +:104F500047EFC9B7E24739BEB4233888E377C2AA1E +:104F6000E4AF605FCCD79A858C13143ECFD5043F55 +:104F7000AA88A7110F62CDA3C3BCC72D9C3E0FFC0E +:104F8000C2D6BE144EF137F8A71B76E7F3395C7C26 +:104F900057DCDF9E045D054773FCA65A23F7E7A69E +:104FA0003549424989D0251FB5901C1D5C9C70462F +:104FB000A1A51FEC554371A0AB651546345D7DA9D5 +:104FC00046303FFE1745043D98CF2C19CFB86D965B +:104FD0009185F3DD6DB306AAD03B9FFDCF3B4E7F9D +:104FE0001DF37FC5C5FE826DA5725EDB7E96CF7A0E +:104FF000E929B5FBE1A5A83FCFCB71CFDF5202DF96 +:10500000037D3B325FDBD144EBF088DAE5013EB64D +:1050100025A9C3778C43BB1EF66F6CCB9578DCB6A5 +:10502000BC98DBE95FC7CD4997880356E53A2C5712 +:10503000BB61B7903E910CBD93D6CFC4576F32F091 +:1050400037D9B43F689D6A9E66FD94CA459D4F7DE1 +:1050500064EA651F219E3725EA7BFF3AC876AEF4E5 +:10506000BD6B5CA0B8262392BF2DD5C8829E19DFE8 +:10507000F55CD15B72FFEB58E7EDEDA51B387E3791 +:1050800049D51E1717AED3F6B9FB0EEDA5FCC472B9 +:105090000FF33311DC7308EB9EE8F031FF003E1F85 +:1050A000077EDBA53D16BB8E61333E5DE484C747BA +:1050B0008FCFF2C30C0B9E7998FDFE227C15E4ADD8 +:1050C000F54EC029D749DE17C17C29773F31F9AEAB +:1050D000AE885E5C321F2224DF8D0F915C9D043E02 +:1050E00033347837C1E155C93E65F0E7E133721FCB +:1050F000E45095C47CE637D5C09743F565C6B1FE4C +:1051000021EFAB5FC86FF4DA687EB3F512FC66EB93 +:105110007F3DBF5986F1974C08DC56C3FAA4C1F70E +:1051200008067748B968C18FB8A55CB4EA9D56E413 +:10513000388B44AF0BF4BA88F8FC00E2F7EB6AA4B2 +:105140009C15AB63F8BD491F0D267DC4777DF2BF6A +:10515000B0EF17915E877E1A56C79D81BC6858EDE7 +:1051600092FBBAB5D288A9CF72CEAA2FFC679EBF98 +:105170001BF5A749F9B468F9BF6740EE5CB27E3809 +:105180002715E7ECD63DF84529FE0D98F769316003 +:10519000283EBEFC1F0E3E9F2A70A6EDC27C5BDA45 +:1051A0000B548CEBE5D2410C37B88BD240C75D3540 +:1051B00052DF3BA619DF647C7D762407FAE6D171C5 +:1051C000FEAD80EF2B38C7E76CA74A7BF91EDFA93D +:1051D000DA0F86605C8B5A5F6079B8C8928757C6D1 +:1051E0004F06DF775D7EAE1F4FCA7F039E6E1C4E5B +:1051F00014CD746578A0FF14D64CF5605C9DDEEA92 +:10520000CBEA4367DA7C224476F99AC412B66F700F +:10521000EEA349BB5AC6C3F44D1021E27F8BFBC6F7 +:1052200089D0807FBC9FD36D13CD7E9219EF8B9C6C +:10523000BDAEE87E16F54DE57E027D53B89FF2AB1C +:105240006F38FC4C3ADA55D9AF76A5F6D7B5158943 +:10525000D088487BD67777BF9F20C8F45EDE3FFEBC +:105260008007E73585355F16D0AFD7D60996B78367 +:105270008C40552EF8C1EB0E8EFFB9547FDBDB342A +:10528000EEAFAB4DE7F44C8DF4CB6538F5036CFF16 +:10529000D5085F508F8C27A36F20CF6B605F3ACF0C +:1052A0007350851CD79AC49F8BC6A8FDDE67ED4B53 +:1052B000521E43D67A33BF4A10A1A26838CD0627C2 +:1052C0001247070C95E0EFAC17E4C594BF3AA6BDB2 +:1052D000313170B7198F766D4CBD321B3CA84A8EA8 +:1052E0005B33E7A95568A5C1283CD18CCC76647B9B +:1052F0005ADF709E776A5F01A7D63AE06FF340DC11 +:10530000ABE5A18A2349D707210F8E2BA27900A5EF +:10531000A966DC9CD3A7303FC75FD704DC73167C3B +:10532000EFDDE9EDEE447E2795DFAA45FC7242F4FD +:10533000381BE9FB4D55F1EC278EDC83D6789F575F +:105340000B1FA773849FD379A299D38FDAC3133825 +:105350003E580B0CAA1D8F7BAC81DD692ADFDBFD7B +:105360002EFBA162FC2FB1A935AFD8EFFC365196C8 +:105370001C7F706064FCF8F34E30E72FB8FFAF9AE3 +:10538000F7B147D8FA7799FD93C030F77FF0EFF97E +:105390003658AE93379DC777C1F70BE0CF46D8613B +:1053A00039EEC2D6DD06FCEF6B7354DE07F1E997E8 +:1053B000DF6F1D644781EEFBE7D9BFCFBAE43B1333 +:1053C000596979D0470B674E65BD922C70932EECCE +:1053D00074BD0EFBFA327EC30BFA71FA04FC624E06 +:1053E000AF1AA14BFABF704E438A3FE98BB7638D6A +:1053F000FB82F68ED6A5405ED6D7AA367E1259EF2E +:10540000CBEFCF4339D52AF487CE4C937FE52C568A +:10541000719EBC96F819E2ABD6665633FF5C4B78AA +:10542000BEDC7DE28DE6B837B779987F3E60F29DAD +:1054300075C5A21B72C131AAC213F646F8E3A6E2F3 +:105440000AE66B89A92AFBC1EE7AFBB995ED05172F +:10545000C1BBEEFF0AD6691DF139F803D7C1F90ABD +:10546000A530F8DCCA430518D7D3BCFFCEE32267CA +:10547000AA9CCF061AFF7A931FC78E33B1C88EBF7E +:10548000245F42A43F81FBC5693678BD395EDAE00E +:1054900099175BB7083FBA121F94F4AB24C7B37EC9 +:1054A000FEC38785C92F02876F25F8AA8971AC0FC3 +:1054B000553A56B33FFB87AF3BCC7C1977E833F7BF +:1054C000DF0F0B7C4D98EF554FC9F7437EB85F381F +:1054D0006E851CC87488944CC4C1C97B2245E67E85 +:1054E000B6C6397ABF381347727E74C86D9B5FA504 +:1054F000166783AF1251F9B968CF0E7FD17BE53FB4 +:10550000A835E311AF11D7000FDF8B8947BCCA8ADA +:1055100047EC1EC7E32DFF4648455CAF158F581C6E +:105520005AAEE68D8AECCBEFB57994B351F1DAC37C +:105530001FEB56113F77B5E85E93003C3C26E4BD77 +:1055400052B33D77403D0C7CEFEBC9E338DF7D3D46 +:10555000E78EFC9DE0FD4FE471FCE2FE9EEA94C5FF +:10556000C551FBBE3BDDC63F71EE057A46398C77EF +:10557000DF136A15CE29F63903096917E13BB172C9 +:105580001DF79DA3E92DB6FD4BF1E7CD42AEDFA699 +:105590005AFF6BB59043C11E15F4D78F2F5FB56DC1 +:1055A0007DDFAA95766E7B8BB0E214CAD42FA097CC +:1055B000749AF35C67EEDF133581B3E8372DDD08AD +:1055C0003A559CAB9EE0F839EB7E343FE144782EAF +:1055D000C73D59F0D10C5A00EA675AF24F42B8273A +:1055E000D549F408BFA245EF1D8526BD3BEA38FF2B +:1055F0003CD13BF45F57B006375C4447C0DBCC710D +:10560000B4C532BE15870BD01F3BBD24352F436F69 +:10561000F131F1B14955F677555C57B83FFDF75A6E +:10562000F3BE94499F165D0ADFC5E5A84597390882 +:105630004CCCB874B9D8F58CE873BD49529FFBB90E +:1056400017FAE8E9E2D92C576E046E2ED2CEE9366D +:10565000E3A2FA68E5AD81410B581F9D6EEAA315E0 +:10566000ACB7AC4F92EF4D1D871F87E3DCE53DBB28 +:10567000193E19B7910DFF15C1C986BC87970DFF5B +:105680003795D79649788647D6CF9C23E3466798C7 +:10569000F17599018DE1212B032316F03EF911B725 +:1056A000F39D6FC87667142B3C3EC823FFA84BE3DD +:1056B000E3B42927C2269D9DCEEDA9831FE2CCFA33 +:1056C0007F752E8EA2CF6B1648BB688627599E2BFE +:1056D000158DBF029ECDFD5BC4CE3A7EEFCD9B768D +:1056E000E9F5B0CA5D69DD2C7D8DF66105CF5B3CC7 +:1056F0006DDB87B1F5BEDD5256B580EA6D49FCB968 +:1057000062107E1A570ABE27F350E2D063C0577862 +:105710006D1CDF270CB73FC7782D192BE3107421C0 +:10572000CFFB7327CAB88F436B0735C0EE3EFE33FD +:1057300037BFBF70DC2CFF241CAAA5D1F4A42563BD +:105740005F1FFAE98235EF527E4DBB3CDF3F133CD1 +:10575000FBFD1F402E06F8F52151125CC5F17425A2 +:10576000868C17387E20C8FD05CA69A3650BF1CB6E +:10577000E207B9FD33CBE4BB521B60A7C499426773 +:105780008234FDE027F698FAB4A780EC067CF37823 +:105790003CCEA8F86B4F5F09D323971EC8F1C542D2 +:1057A000FA55241D5D7DB39C5F7C5F31971B99ED9D +:1057B000BB7A523ED3D52AE03777ADE3C689D4CE43 +:1057C000F01D82E9A93C7912CBBBC6A0A2E35C61C3 +:1057D0005AF0A90AC4AD058229FC5E4AA0F80CF370 +:1057E000F7C0011291945F9E16E6F88A199A7CAF71 +:1057F0008DF2F97CB03147709C434567BB82776C72 +:105800008E37D2BA40EF1307E4BCAB241D1FBF2A6A +:10581000A8C0AF19A67CC8D7F2640BCFA47DD178FD +:105820008E7796ABAD52DFF043285B7CF64C50E2AE +:105830005D1F27DFE73A1E90EFC658F3DEBB4CB67C +:10584000BF01740F3B2C982FA0C79E6F76F079C0D4 +:1058500006FD5C1AE062C5C3FE74B4EB8C6A97E87F +:1058600051815E501F101C87BBCDDC47FDED15CF6D +:105870009EE6427B7EA92A543A3673FBC7E7D03CAA +:10588000F50BE9F4A766FD1E731FEE33F5B5E3C112 +:10589000EF6C2A017FEE51B99D013B02D3C00E632C +:1058A000EB5B72D1EAFFA7A84FF0FCDD6115F810A1 +:1058B000A94E1147FA48A31E5C9F087F997036E3F2 +:1058C000FCAD55043317237FBF9BFD74DF7D74DD72 +:1058D0009A781AE7F715D1034A9DAF07199E354606 +:1058E000E0104E6C807F93E8C403FF26F1B711BB34 +:1058F0003670FED513049FDF6D7075BBE0870DB663 +:10590000C7EBB8F7FFDD5DDFE7F8FEEF93DC011EC4 +:1059100047E61DB81AFED89716C8FBFDBEF7B5239B +:105920007053D4ADFF4BDE624A7F9D60AC39063CBC +:105930009538D85FFA64C991BBB07EE79B93F08637 +:10594000D625F9C30673FE16BCA04065FD6A4177F3 +:1059500037C7030E59939BAB4E94EB887539DE29FC +:10596000D7717472CF4CBC1B2BDE74705C8B2E9E77 +:1059700039C4F765E6CA775963FB3973093C9F6EF2 +:10598000CB64B8F068F1B3F0A39E7FCCCBF6D0F730 +:10599000367E7BEF0EA4F7DD924716AED897FBD587 +:1059A000318775791F05F5CEBC122CDA4BFD2FDE41 +:1059B0009DC0FB77C4F0D50B104F307CC4B2158B63 +:1059C000B17F576F11993ADA97745132C2CE676E30 +:1059D000DEE0B0E93381D58936B8C0FB67E63BE14C +:1059E000D71D1C077F2638F6B27A87754FE634CD6F +:1059F0000B69E2C23C9BFE74FAEB7717820F84DBE3 +:105A00004EEC388AFBF209E1EFFF00FBEB4D190782 +:105A10005122D292C10F4A44660FDE693DD3798785 +:105A20008C1BAE148A43C6D3F1BD8B709BF630E459 +:105A3000B60BED47D9BF45C15F19F0FF630A81344A +:105A4000AC4767DAE5ECB3A2A0127295203D642062 +:105A5000BE6F3171A24AAC67938BCF390A17EAA6A1 +:105A6000DF403B8638F1936B86F27B0B8D9D87463A +:105A700041BE45EEDF885388473AA96A9C5FB47AF5 +:105A80008FAB95D27F3E5F92A712DD0F5928E5DFDD +:105A9000E84BF859072F94FADEAF137A56221EAA64 +:105AA0004834F3BC4585A66C267955172754C47530 +:105AB000D67D277D4F308A8E67AC56DCCA68C8EB2E +:105AC00043A380D73A47E83CD75BAF088CBFAC53C1 +:105AD00011883B7A7B69D21EE63B4D5DE3F15E4760 +:105AE000A1D95F5D9C199F1FE81A0FBB73EEADC66D +:105AF000F085880F4EB6D3C98B2D0BD98E3C6EDE48 +:105B0000733E13FCD1CB63A8DD8F9B1C7CAE61F987 +:105B1000298E7FF6E028DC3FFBED4A17DE96106FFA +:105B20000FED7142BF819E60805E890E918683DF9A +:105B30007917F8F42B1EBE5F65E9D98EE2DC0726E3 +:105B400082FFCF74F9AED7C1EF9B8720CE650AD60E +:105B500081F2B79AF25BE8D27EEB70F932614F5F67 +:105B6000494F89D5873BE38335FE8BACC3BAABE3A2 +:105B70009745C7BDDF6CAEDBCD0BA53D2E1C3305B5 +:105B8000FCACEB34C1F1B52ECD6E0FC4B6179769DE +:105B9000B747BFA8BD55BBD06E6F114E7DD0AF8348 +:105BA0006F387CE6B9CA670913E47516AC03DF03E6 +:105BB0008273A1A945603D2DFD76F2422B7ECB5824 +:105BC000BC3003B0E0F98CADF52F015C9EFC30C712 +:105BD0007175987E7B5135C6A64FAD30E76FD923DE +:105BE000276AFC2B514F541802EB90536BC6BB54E1 +:105BF000493AB0D22FA08F7D157427C24FA958C73C +:105C00004BE963ED2D65F72EE4FE035F47FF49087E +:105C100044845FCA3070C3BE5F7E6F9DA2329D6EAA +:105C20009D72793FCF3A536E6E34E962832937B75C +:105C30005AFC78E6D426ECA74D55AA0E7B736BF17F +:105C4000E7B3BB2CD8E9D414D06FAA479B063D8498 +:105C5000B43369CF3AFDC14F083E668CD9877607C9 +:105C60005C77A2681EFC2775F21E87AB42B5D14D4A +:105C700079597519F4C12DAF4BFD62C07542898EFB +:105C800037E4284147A4DF0762C691EC0C0BECC354 +:105C90009489767AD545D813CD1FB74C94F37B21E0 +:105CA00053DAD5A91305CB39ADA24720AE4F0BFD72 +:105CB00084DF77D2A6A83EB204C5FD46E0844AF34D +:105CC000D1260AC560FFACC6F663E244B51B7186F7 +:105CD00089154103DF5FA83A57053C6EC974AA686D +:105CE000CF65FA57B85FF88126A6DD5040F5823EB1 +:105CF00095DF9F78B96AF106F8C3B7A6ABACEF6C35 +:105D0000AD7AFA45C4B7B8DA5396E2FDF5C30B1D78 +:105D100032AE26D32942CCA7C2ECD7DA94A99A7026 +:105D20002FFBA38E2F94F13C0F549CDB80F637A7FA +:105D3000F34EA1DE7BF9FC60DD1469FF3B3FFB4ABB +:105D400008EF4A7DD358EC067F3D36E51DCF7B5CDE +:105D50005FF6F340C561D99E91168FF8B32D55D5E6 +:105D60001AFA8BE8937A3CF25DC2C3FAE91643E56E +:105D7000B8CEAD156506E2BCBE29442FE28CBE69E3 +:105D800094850A20DF0D4F2F34BBF2AC39621DC160 +:105D90000F144B7A2D2FD9CBE7F2C45B2C1711BF10 +:105DA0006362D9E7AE71F6F5F36A76FE929063F717 +:105DB0007739A6ED0DE69BFE34EECFDDCD70D734FE +:105DC0004FEF1AD8EBA103A209748577EB704F2F20 +:105DD000F99E10F8DBD642A967C6FAC1E2848C0BA3 +:105DE000389F29CCF72B4355988F738ACAF7D29CDA +:105DF000554B43F904FF1BB5AF4C045F92FEAB84D7 +:105E000062BB9FCA536087DDF04B45D9F5CE183F82 +:105E1000D595F8BBB58F3B4DBD6A9D8BF83BCBE567 +:105E200000FB853B1D5A29EBEF442E85E988B7CA54 +:105E3000D983F549AC53CD7766843810655F7E70A1 +:105E40006B20B12E43BE6F188D6F570CBE736A0D59 +:105E50006F1DF8D6E7F4D37FDE72578AF7FB247EF6 +:105E60006837F495883EA7B39C7EC7BCD7F8F14944 +:105E7000F93B0056DC5F6C3F0DADF93B2BA2E24ACB +:105E80004FD5CB78DDD87223579615617ED6BB3BB4 +:105E9000BB5A9DBC5FB6F9653ACEC45F6CDAADF70C +:105EA0001E02FF58DCAA743B15A4672A8D8BF0CD27 +:105EB0006BEB14EB5CA6DB35419E2BE2EFDF5D81E3 +:105EC0006BD1AFD1A4F27CE2406FCC378C101F367F +:105ED00079BC45380F5D6A967F2871D74D13A8DCD1 +:105EE000A937E4FB866F37DDBC0EE7F6E73E4B6172 +:105EF000BB618B794EDF1094EF9A049C7A03E01C0F +:105F0000A1FA1C53D08EA4BF0493DE1ABC128FA733 +:105F10001E56F89EB2D5DEF9D6144DB6F773F6AB21 +:105F200034E8F29D65FC19641F2F32C7D3E0ED5DA4 +:105F30008BF53B659E132D8DA1EFA0E8E2F12E7D40 +:105F4000DDE1C3BE59EA39C8ED798836F01EE9D2E1 +:105F5000D6F5D26F43F6BC9BCF57DC52A935F7611B +:105F6000547BCADF797C473E045F3CDF1AC7763535 +:105F7000780DEC75C60FE02245005FB7987CE4967B +:105F8000D687A49F6885D01C932E1CDFDB4DD21FC3 +:105F900074DE307F8FC2103AEE652B667D71500B38 +:105FA00072BCBC195F18A1DFA871E5DB60D36F6E0E +:105FB000871705E36CFBEBEDCF66A75CEE5E496CE3 +:105FC0007D55F75F962F889D51FEF0BC4879D1F53D +:105FD000908173F0083EE2386EE852F52A6F35EE94 +:105FE000033D0E59E9DF5CC7F42AEF670760BF97EE +:105FF000229EDF5FF632EC82D7653C7FA3C71BE4AD +:1060000073FC4EFBBBB256FB96DFEC6CBFDF2C5C27 +:106010000F7EF5BB073F722D8E9AFF4E737F34C003 +:106020006F063DFA1BD9EEE873DB47574EDB89F16B +:106030002CC28D8C34D86F0E1B7F6ADA9C68D73FD8 +:1060400063CEEF2D7E437A13CBAD53ABA55D4BA949 +:106050003C87F1CA7BF957E247C46738FED869C666 +:1060600047967BEC7665A5661FC7F599036CF00D26 +:106070007AB6ADFC8CA27C5B7E4197F43B9F27BE39 +:10608000B691E36CA49EEBC6C37144671ED1C5E90B +:106090006113AF474DBCD2E2FE12F73E1284B7192E +:1060A0007659A2A92F268930D74F01492316C83324 +:1060B000FB61E758B8947419C706E586E679FA26B5 +:1060C000C17ACC692B1E67968C6BCB10012E67C5ED +:1060D0000F66E1755F07FCAF216E6F8808333C0CDB +:1060E00002D4812DA8739A2F0C7E1FE5DB2D4BDF88 +:1060F000003D158AEE93F85E96F8E110F8E3CB16B2 +:10610000EACFB820F983B7DFFE32C9CFB2F9FA5F20 +:106110005D84CFDDEB6FBBFD28E9C96571F27CEDD5 +:1061200093BAAF3F19A4F2D316182759FED48BCFD8 +:10613000E597BED43EB9643C46BD7ED1788C7FB431 +:106140009F4BC66398FDC4C663242C30FAE4FCA4BC +:106150007DF10B57778E8CDF1061C7409BBC10F52B +:1061600019979117A2B79EFD8EC4EF119F269AB57D +:106170007578CFBDC3E796F1AB31FCADD19313BABF +:106180009BCB25FBE2265EB88FDF74FABDE84F1C7F +:1061900014BA6577406F3A5D2CED630B0FD6BEB233 +:1061A000BEC7E2E34AFB2436DE0287A5D1FAD895C2 +:1061B000F01DBB1F8E99F6CD8BA67DF30B338EA4FD +:1061C0009FEFFD83BF0772E1FCCFD6BBA43CD2C0DA +:1061D0003F4EC54BBBF28B8E4FA99D3EB19EFDF449 +:1061E000F6DF19B1F8563F5FC85478BDADF7D389D3 +:1061F000C13BA3ED9AD87ECE79F7FC0EFE57E1F0B5 +:1062000036C75D7BE9795A7CC1823BE28D4C1FCE5B +:10621000BD5D179F4F7BCBF42F63BCE5C9FF581CB6 +:106220009105F7C70F399D3CBF639983F66EBC8C0F +:10623000FFF298A2DF09D36B45FD534FE27DA832F0 +:106240000478F03B1BCFDE0EBDABAC9C49472CABBA +:106250007FEE49BCAB41F6F352D02F7D97FE1F4332 +:1062600018B04F9D9AC6E7AAA4D7DE8279DC69F2FE +:10627000953B161ACBA3E1890B8D5B51DF824FD47E +:106280001AB745E7D3DF36D5AECFDD79B9FDF9A62C +:10629000D3B88BF753EC3A7F4E7D796B9BFEE0EFE2 +:1062A0000A891E9EF0CAF3CB93921EACB84FABFC8A +:1062B00080A1BE338833B5FCB503F29A47FB988FB3 +:1062C000355F137DBFC78ADB48AB92EF8C7C92248D +:1062D000BA1C51EFFD5FE30E3C80F92AC91303E8B5 +:1062E000EFEE77143E071A30D3C77E94B472E99765 +:1062F000EA8897EF5AC48E7B7BBDB4F327D71BDBAC +:10630000E4BCE53CD266CC0C75527B6B89F3C01FB4 +:106310006ED4348B8BF92F5DE901EE87F0BA0BE375 +:10632000706A7E861D5E39DE48BC9395CAB83F8F81 +:10633000C9DF843F97CF13D69AFACA5A6DABB88794 +:10634000F0B22147E5F77D4E4EEDA901DDAD555484 +:10635000DF1AEC13C3D0D30746F8E368B7165A6CBC +:10636000EA7F8F13DD95256F3010FFB4C9F0F8F880 +:10637000FE89EEB6E94FC28C5FB4FA5FEF2DE0FE06 +:106380003750FFE86F93D719C2B9C226E161FF46C3 +:1063900089B7E745D8CD255E27DF5739D9F283ABDA +:1063A000A01779D2DD1CDF18DBFE6FEAA59E54181A +:1063B0007CFFE9E398575861FF794DC63BECBFFE7F +:1063C000F8A4FC952F4735D12AEFAB66F617ACF74A +:1063D0008E4B8EE69F380730D8FFE3E1D451E8D3E7 +:1063E00031CE785D8EBB363EF06FC0773C8973232B +:1063F0008A4F0FA84A1046141FDF7495C6EF136E1C +:106400004A7A91CF8FEE8F97EF29348E7B96F5EAFB +:10641000CD4BA86DF831490E21EE97E628CFCB631E +:10642000E44CACBEF6BFB1BFA8FFEB7A3F7AFA7876 +:106430007A649E8E8164A746CDAB3078E045F84FF4 +:10644000D67A9D6C975F090F275BBEF622FCCB8F37 +:106450003CE010D1F7DF3E073E7A41BFFF5DF8E038 +:1064600047433FC7B9AFC32D7F6FC8E1F6E9D1EF0E +:106470009C243448FF6E77BDE16AC8F8FCEDFD62EC +:1064800088BC3FB1E99E448E93D884B389747E075B +:106490009DCF0D62EB653448FFABA7D9486BA0FEDA +:1064A000862FD2CD38238DDF79696C3DFE16EC8FB7 +:1064B0004D1917E717D90DD2AE7EA9D9188CFA0558 +:1064C0008B241DBCFD6A770EDE4FD8ED77EBF05BB9 +:1064D0008DFEFA3907ECEEF533E53E5EDFD3F2626E +:1064E0002EC695E3E4F7B1F6F7BCC3FA485CBC8F5F +:1064F000EDBA6DED816FE11E6A7088FC3D8EB89B30 +:10650000AAF95EF4FDBAE2835F6FF7EAADD3712FAB +:1065100072AD4FE17728F217A599FCE44415FC3CD5 +:10652000AFE414B0FD7A685C9E8278B0E555F2FD68 +:10653000F6E58FC9F7A366E68CD98758C453398727 +:10654000F91DBCBF160426086E47F2BFC2401FFBF0 +:1065500019778D93FEA4B75AB74E871DFBF16A7960 +:10656000443D65B57FFE606A674A955BC38743E932 +:1065700079FC3B53DBCD78AAED8F6D11F750FEFD12 +:10658000AB657C9BB3CF210CD21B1D7D0AA74EA708 +:106590007CEF6F802EE3621D33ED745A3FB3E7A8A2 +:1065A00013E3AF1FF136C6BBE926B70E797DFFCCEA +:1065B00037F97704EEFF2BAD506E847F597EF6FBE2 +:1065C000F59EB730CEF5AD6ED14EF90F2ABD2F61D5 +:1065D000BF0553550D783C3955D2C3EE516EA60F09 +:1065E000E10CCFC03C367D9AA761BFDEA8AE3A86EB +:1065F000F7846E7C5AF17512BC6BD4F4D02D046F05 +:106600009FE6F1B1EDAE5DC03F997F5BFD5BFC7B2A +:1066100097C9BF77CDF916FFDE10B5D58BF7779602 +:106620006F3BB3027055AB5B67A66DC6F9DC6AD5EC +:10663000173DEBD0DF6DA6DFCFB9FACD75D7C01F00 +:1066400050E6E975645ED8FF977A55118CC2DB7508 +:106650007D092218B5BFA7890136B8DC936D2B5F81 +:10666000A9E5DBF2AFCF1C69CBBF411F6B83EB8B7E +:1066700026DB60B15FBEA7476A0A8FA7FDA7092C7A +:10668000E7B73F2AE3746F8B79476F59F7AAE94B55 +:1066900008FF4BCDB8A4A53DF6DF6D78F0A6AFF2AC +:1066A000FB7E5BF1BE9FEFC277983734D8CF5DE2B7 +:1066B00032A4DEB23DD3CD74F6EBFABBEB11BFBD15 +:1066C0006EB017BE5AD1B32CF04DECCB8E9C7145F9 +:1066D00088ABD8AEF9359FB453320B26F4875653A6 +:1066E000EA8EF045F08DFA38A6935DCB857CBF0B22 +:1066F000A432905D37BC4E7FC879AC1DF7A7766396 +:106700005D358C7BE921C0EB14D12B2341DC4CCFD0 +:10671000108918E7E027561CFABE5CC7669CD713A1 +:10672000A178A0973B67AA1AF6D7C0656E1BFDA398 +:106730000F3D4A4FCBCF290F6E827E44784921BB53 +:10674000E7C1D563D6CC4D67B9CEFE63D005C64F41 +:106750004D78B00E71853DEC578F4F773259E56F0C +:106760008BB3F17D6B3E3C7F9E9FFFD8346A2F2D0B +:1067700028F89D47E02318858F5DF7BCF730F67742 +:10678000145E7FCA785D3D6619E24ED2F460501403 +:1067900047F00A331DDFE345D4BCA89E9167B0DF04 +:1067A0007780F5BB8766FE04134FEB94C05BD07710 +:1067B0008373E5794C2C5E1C7344102E4387E6B638 +:1067C000CD273F682F77A221B5FF3D55EC4F3E877F +:1067D000C98DF427CCFE5C31E373079EF0F3BB6DEB +:1067E0007354817579F21BE70EFD7D1C9F33F5D341 +:1067F00041D0DAEFCA85ED1D2996F7C23A7561C618 +:1068000093D8F309CFF7615D5C994E5DBE5F67CFAA +:10681000F738FD41F86B72F00E22AD7371D6EF16AA +:10682000F0B9F13D6E81FBF02EDD3EEF5D4932EEB9 +:10683000E5C11B641C4E3DE1257A7F96CCFC16E732 +:106840008B6524D7497EF635C873FF3C776809DA33 +:10685000CD6B89673EB99DE60BBE95B02A5EFE7E84 +:10686000AEF03D9C48709E9A2460973FE8D2B3BA40 +:1068700068DFFCF286F7D6E05C2221CB21A0B1B420 +:106880001E68DE0DFD50281EB6D7A00F46FF2E58FD +:10689000893B9C8573B65DF51F3E0CBE16FC89874F +:1068A000E51D290C798817B0CEDDD7E7BCEA69640D +:1068B000FDA895CFBD6A86BCEA41BCC9C79B1D8CAB +:1068C000E74BC9FD583DE8FE8220DF1B603D486173 +:1068D0003D2875D1E7D00B7561F03D72CB0FD1E843 +:1068E0007959BEDF84DF1384FE13A367C7EA3F8AAA +:1068F000FF59F6DBEEBCC5D4977EEEF3F0BDB27F58 +:10690000502F9AB8DC285874113DE452FECB0BECA2 +:10691000B3CFD9CFE7D6D36E7799E777DD7CDE5654 +:106920009BE231613FC3D63E8BB5633A5F97EFD1AF +:1069300077A6DBED98D1EED087880F13696E9DE3C3 +:106940002192DF67FD67AD907171E26068D473C812 +:106950005F91C0F7E13C9A9BFDC057B45F8AF26C2F +:10696000F6CBDAA277581FDF18C6AB30B49F7F7A18 +:10697000EFB0E8F8C74BB57B019DB9C401C473DC27 +:10698000B52857E22D861E14FDD8A768A730B84158 +:10699000D26FEE18F6FFC4EAF31B73C65CD6AED90D +:1069A0005870811EBFFCF3D06FA7A9C7779A7AFCF5 +:1069B00046E8F1A5780F43D2E53FAAC77FCBD4675D +:1069C0002F6DD704E5BC7469C76C841DA3030F2F1A +:1069D000F2FA6D589620EDBDFF7BF8D8F4DF890FF1 +:1069E000EB5ECD95F64B9E1A7A1CEF2C8ADFC4091C +:1069F000F8A571D6867AC33EFB570FF8DE9046198C +:106A00001FB5B1B83A7E1ACB4D43411C5BC2A8A753 +:106A10003D3897DF5E2CCFBFB7171F7E15F6F6A661 +:106A2000E2B20C458FF4B3A9F8E92A9C976E9F5304 +:106A3000E672447DDF6EFE3E50ECB8F21AA53D953D +:106A4000BC3CF023E06F5381B4E3895C65BC8A2EC3 +:106A5000E362F36E34387EB2EE178161977BBFC775 +:106A60001A2FE9247A5C0AC6B338037C7FC1D0C0F0 +:106A700076E825DB67095FBB8ED4AF6E263C24D257 +:106A8000BEAF825D7068D287D02332FC6EB9A6C2D9 +:106A9000481E3F21F27B9EDB8654F3383E2E16ECD7 +:106AA0009F9C372ACCFA72DC1CB78E7701AECFF1EF +:106AB000552C2138DD8C7B4F1461368C7F6FD28D45 +:106AC000A57FAEFF8B94BFE93BCF745C43EDDD4205 +:106AD0007A920E3DC96B7F173AB1FBD011F84796F9 +:106AE000913E6A507BCB76DAF5D1A931FAE7149C56 +:106AF0009B9720B5C7BBFF769119DF3E414C00FF45 +:106B0000B5DE27125D0FF9FF63027E67443011592D +:106B1000EF14C5E2F39F5BCADE59948177BBC65E72 +:106B2000360EC97A97DF7AD7FF178F4ECB42BCC992 +:106B3000B676699F7ED177FE97B6CE10386F5EDE4F +:106B40007A83A820A56C49EB6C866F582CEDE2B7D0 +:106B50005FED7540FFD956ACF2EF488C9E55165F3D +:106B600008FCA6ABFC3ED795ECD81776ACC533F83D +:106B7000226E54593CE87AB95FE5F3325D841C78A3 +:106B8000F7E4FF00B3188FC2008000001F8B0800DD +:106B900000000000000BED7D0B5C55D795F73EE73C +:106BA000DE7BEE052F70904780A01E04126C11AFA3 +:106BB0000A4633791C7C05AD492F4A12CCA7E1F275 +:106BC00010517CA07994F487F1206F8596E88518A0 +:106BD0006B05153A6DDA3A34499B47F3B517CD98F2 +:106BE000974969DADF24761CBD6824315FE72B8979 +:106BF00031B533F6976FADB5CF817B0FA0C4B6F931 +:106C0000CD743EF39B39DDF7ECB31F6BAFBDD67F80 +:106C10003DF6C69BE299B3933176DAFDCE82884C7D +:106C2000C63E553C73A0C896145918CB62ECCE2BC7 +:106C300005F727443316932EC9586F5D5ECF7B0C42 +:106C4000CAD1E992220A8CDDE6EE79AF08CAB7C54F +:106C5000492E45612CD5F39E85413BDE4F19DB97CC +:106C6000C4D82EA175713C94B5248175C3F7EFB9D2 +:106C70000FA5C850FF625A88CA04ECC9FF356CFFE3 +:106C8000F5CB22B5FF39FEBB73F89970D9C2D42871 +:106C9000C6622F0B4C9D0D65AB5B909D50CE13993A +:106CA0009AC6E8DFE7F07FABF37A16DAA0FF3AD9AD +:106CB0001DE282F76D5DB9210C9FE9F785B0741C68 +:106CC00087DB9D0AE361D69EB8E5618CD5082CBFB1 +:106CD00007DEEF5A7D8B3B15C71B66A5D178A7A9A8 +:106CE000F16B603CBBE2435D1A946FF744C2E4A1D0 +:106CF0003CFD677149504F8A12058B42DDAA0EA0F8 +:106D00005402FE2F2887B4DECC446CE7B796CE9DA4 +:106D1000D08F37EFE8BF5BA0BC0FE82460CBEEDC80 +:106D20001077D828F34B97FA8570785F26319F4308 +:106D30009FCF54FE74C40EB7DF1697CE4418D73ECB +:106D4000681FDB33B773ADF66E1F14996694E1FFCD +:106D5000EEBC1CCAB400FA65B3A8A0F202C78D410C +:106D6000F517C9C941EFD7EEEF5F8FEBBC214F524A +:106D70002C30DFBBE2BE1A549F69EA3B69409F7228 +:106D80007DFC4B94D9C1EF59CF62A4F3C6380BDB1D +:106D9000E982F54BFB87E0F73FB29DF5435985FF4C +:106DA00070FCD52FFDAEFE165C976CC7A01DEAAF38 +:106DB000651E2901FADDC8AC548FBE83F2DAF48176 +:106DC000532C83B1D21EF83E70BCACF9634B383EF5 +:106DD00083EB1779C2A2072640E11676CBE716FCB3 +:106DE000359AE81ECDABB093250BAA0F22BF3256C1 +:106DF000619169D9ABDFC4FD702582C61DD3B5A0F2 +:106E0000BA17CAF27C4745C45CACBFA2BA17E8F215 +:106E100009D687F7D17952109FD60BD405D3725972 +:106E20006737F4FFAF1B166467E3BE63AC8FEABF3E +:106E30003CF067168E55E0BB807102E73166B48383 +:106E4000E3ECB20FBF07FA385282FBA17F407FAA62 +:106E500022F2A202F30AD15F39E2F6A9D9386E9183 +:106E60000DDA61DC0E47739F25E31AED24F366A269 +:106E70008D76B0DF92EFA80999FCF7E571588F7F06 +:106E80000FA4F27D8E734DE1F38057C7719C4AA128 +:106E900040FB09FFC9B1C3ED3AE224352463F8FB96 +:106EA000A17923CD8D7AC2F07BABDEFE8C5FBCC0B6 +:106EB0003CB0BF6FDE1B3CEE094EA6F6C0EF13AC34 +:106EC000F0740EEF8FAF17F1FE1F2C1287C6618D85 +:106ED00045BEE0747A37B4A2FE3EA04B03D0E51065 +:106EE000ACC7B4FD017466C3ED3CEDE1EDA4ED97D4 +:106EF00082DEC3BFB894393AFF4C1D6D1D797F44C3 +:106F00004A05FF9FEBE857A0722A6383C84FEA54F3 +:106F1000F70E2CC7E865A67F9F61ACBBBE8E93F5CC +:106F2000A549FED1033B9ECEE4FC678FC35F3CF9CD +:106F300036284F713317CAD3646FF0F862132F5697 +:106F4000EFC2C1799CC4AFF5825FB0213F0AACE2C9 +:106F5000A7D0DFE4AA603AC6E6DBFAEDC08FB15EE7 +:106F60007BD0EF27502E66E9BC14B03E2C70BE30AB +:106F70005EC9F3E103480C6FBAC476C2FB23CB8130 +:106F8000C830BEB632D6C9EB43DF063F017D8EE581 +:106F90003DF31EBE6F724B8A1DDE87DA067B3F878C +:106FA000F2AE3CB1531346E10F537F23CB3D39A9D9 +:106FB000D07F6C9C55D9C946BE4FB07AAAFDD07E11 +:106FC00022ECD728A0477AFC73D9B4784B604D6087 +:106FD0008AB165C1F45B0DFC1C280733DCEDBC7E77 +:106FE00019938578985A5112D165AAE45B83BF4FF3 +:106FF000DD1AC2AA510FA61F92914F33A49E389951 +:10700000F4CEFF26BDA9BDE870A5526BFEA9B9D389 +:1070100087F512936150F3C696F32011A99F542D62 +:10702000DF8DF2C39B2ED27ACF90B4189C2F7BDBDE +:10703000C2BA81BF6C91FE67505ED9FA05D267BBB8 +:10704000D2CF3EFD432CFFDB0D2E24CFA9AD3F9CBC +:1070500086E36ADC0EBC773363BBB73BE8694BD58C +:10706000545C871085AF6B882206D16165886742C2 +:1070700021F41F95131AC417B65C57B80CEDA5B0D0 +:107080008A7C9C7F218371413B858E139C4E0E260A +:10709000DB814E4C55498E08C63EA8B5FD7E485E44 +:1070A000C3BE11127F2660FDFDB0312D58FF172E93 +:1070B000871D07EC4F8C44798DFF93E8806022FE9A +:1070C0006A74D26833BD54A010BD1AA299628F8031 +:1070D0006762510CCE7BB747D6F95863A89F2D1233 +:1070E000F3A0DC009C40E3AD59220B3B676219D64C +:1070F0003313D7333E12F5FB910291BE0B17D52601 +:107100000BCE4B64FE6EE473F7A1F3023CEFBB576A +:107110008AB708585E2E36235E4ADCFD03D4932FCF +:107120001538E8BBB65C85F0C204D0E73950AFAD86 +:1071300077DEBFA37E8F714B4473EFA4E5D4FFC508 +:10714000749080F0DD7DC01B3150DF0EFB40447D2C +:107150000B0C8BE3894E679D76289F7CC72F62B905 +:10716000019AD7806F3FD0D7B321F1D02B0BA09DD0 +:107170003A9027A8BFA2F71FACC57A6BE7325981B6 +:107180007A133A051256654ED6A9423B33267DF254 +:107190005A32EAD92EC125C03876F52C17EB914F1B +:1071A00013C54EC44FEF252E7F373913C7259136AF +:1071B000FC76F4276FA15E6E4804ED85F5C3FA54A2 +:1071C000C43DBB92986B07F29B00F810F15FBCE4E2 +:1071D00042FC3712CFA902F24BAC3B98BF56BB7BA7 +:1071E000AC88E71A6495F09C37FD5107E239AFE0AF +:1071F000EE4B42A6B1AAF1CBA753F5201CB6D6AFF1 +:107200009E7C04E707F2A693212E7B7E2FD2D51B0E +:10721000E76484CB12774838DF7D30EF4868E7D4E5 +:107220001D7EC2310DB992B203F7E9F4D2344F801A +:10723000BE4848BC3E7C06F8E75FD2627515A3E005 +:10724000BA962E43217ECD76F3383E71C07F1CF76F +:107250007C33CE9F8EF82818CF581201E7C0F7650F +:10726000FB4DBF23CEC9C0A775F87798D7F642C0AB +:10727000395F65FFFD718EEBBF07CEB90B7186AE2E +:107280001FFF3A38275F180DE7C4E83827C6847314 +:107290000A759CD351240E8DE37A70CEAB857F5B4B +:1072A0009C138D6599AFFB17C43971885BA6E40107 +:1072B000CE5146C1395523704E36E2A26BE21CD343 +:1072C000BA5C28FC8238272F18E7348C8573129714 +:1072D0009F1C0DE7B4255E2FCE71BF9EF425E29C66 +:1072E0008A31704E5BDE7237EEB7D05C7116DAC948 +:1072F00019925B6CC4794D8279C1FBFC49CB57A2D2 +:10730000DD77F10507E98BB6D5AB65D4971A303038 +:10731000D9E78CE3958CB391B4AE3324FFD33FC44B +:107320007D77DAEE423C63E014AFFBE8F4E711C787 +:10733000AC4B70613F066E7158DD6ED4AB8E14D2CB +:10734000FCA3E196A9453157C32D3D7F196E49FF36 +:10735000EBE216A6A84F4D8071AC12C3188EC76B16 +:10736000631C3F37393A6B815EBFBA7760FE1A28DB +:1073700087C65B18DAC563B577BDB8F3B287CB0FA4 +:10738000F3B8FEA9301837B107D5A545595F605E3F +:10739000CCB3787D26C9A30ADCFFA55D955228AE43 +:1073A0005BB6A307F77769D737A55094DB5B1D0C55 +:1073B000E57669571595E3BEE150A83CC4DF373543 +:1073C000E1FE505889E486799496D9FA6DB08F4BD6 +:1073D000F707DB2B4F7B188D775AA734EAEF5FF660 +:1073E000785E2DE4FDAE9AAA4C452169E070834E8B +:1073F000DE1701ED44E07A57C4B5C2BAFC6AD2C0C8 +:10740000D1C2807536707F839BE37E5BA4D630014A +:10741000F78360ADD0A2719F6DED9840FADC51C149 +:107420005CB40FE371FD61BFD1FE33AFBFB1AF6696 +:1074300020FE459CE5DEA1221FDB9264863876D8CB +:107440002E70CB2877439A2DB409603FB5E07E3289 +:10745000EF33F3FEFAAFB6AFCC7C60ACC778BFEFCA +:10746000D53E3986F25A1DE4F81B9EB42FB32F3354 +:10747000C2E732BA13A1BC18DE2B4988E312042CF0 +:10748000FB6204760394175B4E582AA0ABDEB976F4 +:10749000D9CEF1D63D33419F2ED0E7DF7B02702954 +:1074A000BCBF43B02BA80F16B0572D3E281F077D39 +:1074B000C680DF9893FBC764F80FE9B3282E18073E +:1074C000DE61F273DD66C283AFE0FF80791E2DD2EC +:1074D00071E12C96897AE2A3ED2FB073C818AD4FF5 +:1074E000BAFF0CE35983F5E0F7F52C185F18CF1FAE +:1074F0006F9DFF3AEEFB29577E49EBD99BC3D84ECF +:10750000D0274936CB5217CCF79913A2222AF4245C +:107510007A681576B2239E3971F49D74A8FFCC6BFE +:10752000B36269CDE528923BCF28CAAE74ACD728A8 +:1075300091BC7F6EFF8A3757C2F3679D0F4D78006D +:107540009E2F74EDF91A3E19A27BE8B7F4291BD9D6 +:1075500051CF364A87914F07F6264F40FC6ED871BF +:107560000F62E3F3B0EC5266C1EFFD3A2ECB2A90E6 +:10757000B91CAA8C213AB0B4CE53A8874E3F2E280E +:10758000A8BF0BE4419B80FE17ED912DA780DE057F +:107590008EC145027CE2D8F1F0CCE3D05E0162906E +:1075A0005B19FBC3D9CA9F68D0EEC066F523A4C39C +:1075B0001F8B381F9555A8BFC77D6194FF54A1FE4E +:1075C000DFC0F29315EA60607DF8E70B99C3F91804 +:1075D000FFFD87CDF3477CAF9670BA810C22BFB216 +:1075E0008DA93EBE496409E56E61E59BEFA11D5181 +:1075F000E8706AE8DF34EF1BD0F832F937998E1360 +:10760000F4F95E8BBF0F09BEEF3A711D4EDA5937A0 +:10761000F47746E717A3DE2B254926BDC02244A0F8 +:10762000D303935BC3318E705E60FE6A7816771564 +:10763000DF7B2BACD7F9965CB2834B356EEF9EEFB8 +:107640009DF7E37828AF017C8F98E842F58AC564FE +:10765000EF360395E1FD7D2D7CFF947A854E8C33CA +:10766000DCB597DBA99ECB7CBF0165C2B302F68B6C +:1076700061EF56BF144ADF9DFB18EAC1279EFDFD4E +:1076800035689FAE551D830AACE711C92D61BCC199 +:107690007F5060BBE1D305DAABC72AA1FE71D88762 +:1076A00081FB2A1FFE43FA99EDAB91FB8ADB5BE677 +:1076B000FD35BD58DF5773D89CEBDC5799C540DFCB +:1076C0008B95B3E3105F8FB55E6F6C9FCB16022670 +:1076D0007819E68FCF3726B53EE826FF852B0EE5D5 +:1076E000FA051BE87528FF02E437BEF76D97E979C4 +:1076F000747B1C3D5FD9AEB08530AEE3DBD3E8F9D7 +:10770000DA7617FDBEBE72015B085BB2B4F26B6C39 +:1077100021D8E96F96F07850AAC77100F5CA3930C0 +:10772000DE508EFB05EDADB9C8276F5928BEB3F406 +:10773000858AC568D719E3F3E4DBB49B813E25BA9B +:10774000DD7FE4A5A74B707D3CD3A6A9B85F4BAC09 +:107750001E09715731FA03E0FDEABD3FA98D87F597 +:10776000FC4E79D1FD38FFE2BD962039EDD192A4CF +:107770002227E295D68513518FD5092427968AD5DD +:10778000D689D0EED29D82AB56D13711BC7F5DB386 +:107790001CC4FD3CB584E3988B95C78E63FBE6F86B +:1077A000C410DFFC54D0F9ABAFFE964CCE3768AFB7 +:1077B00094A6CD630B03C67144AA385E09ED0FCCC5 +:1077C000B3CB3B402E94EFFD8614289F9780D25D6B +:1077D00018680F99E219E6B8455967A184726B647D +:1077E000DC22B85E6571B01D3F235CA98F433D3A32 +:1077F00095D361496DE18137713F95CCFEFA1C2824 +:10780000E79770FB05ECEF08C417ABECBEAC771143 +:107810004F7FDB4EFE98733AEE33D6ABAB84DB7B07 +:10782000E525BA7F5C757AD0BF52A4D3E94257727E +:10783000FD6368F75F8960E82728D2ED9438639E7E +:10784000159112FA7F8AA1F6BE99F0D4EDFCE2916F +:10785000F6A18AF62EB54B767BB0DD5FA4DBE94658 +:10786000FBABA0027E37E3177112AED3BA65169F49 +:107870006526E209931DEE87B1C452FFB4BF8C7E2A +:10788000C18E5603ED6CEA3779B87D635C66FB7A8E +:107890009D93EFCF75566E671B74FA7509D72393C6 +:1078A000D65C3D8EE047FB5A1EDBBE7EB698B733F2 +:1078B000967D4DF3983A2AFDBA701EA56CF81FDA32 +:1078C000CB85FA3AC144EB31EE0AF3ACD8374A1C07 +:1078D000E1ABDF0F9EE79D5766D4A3BD5C0CFC8B2C +:1078E000FC5ED8183C5EC933B7FE5E787F5EDF0F62 +:1078F000E6F12C7004E3DB457270F9AEB8E0F212E9 +:10790000C53EC2FFE230D62D6964FB47DACF15E1F0 +:10791000BA5F68B61348ECB482BD8CE3D96B217BA7 +:1079200019FF69C6BA8E629F9F5B7DFB6994F3065F +:10793000EE3DD6B5E25BF3A07CB6CAA6D89591F52C +:1079400019EBC9C6FE32E6CB8467CCEFD3B7FD3462 +:10795000C87E36BF5F0DF40B8C673E8FFA12F8E4D9 +:10796000944D213FC1A92649467BF8BCD712EA7144 +:1079700006D85F55B3AFA19FB9DF7F86D4FA20F553 +:107980002F8A2EF43B9BF1F3FCF00F4546721AF060 +:1079900035EC93C7F5FED9CBB2FA4DACBF35DC85DB +:1079A000EBE86F5E41F6B9BFCB72083FAE7CA1AA8F +:1079B000E387F03ABFFBD8F4E7E1F78B65A164A752 +:1079C0005B968344C4F159DDE1E887F57B6787B3B3 +:1079D00080FD608E1FF8535C0AE2328A1F286427FC +:1079E0004C2C19879D30304D96705F0E84BD46F447 +:1079F000F7873059C07DAE3D4FF8B9798D8EFF2B9A +:107A0000E47A1F946B747B6D04EE31DB055551D71E +:107A100088A768441FCB261BF391FE6434CF9511D1 +:107A20000EBDECA2B2C1A7253A9D993B89F0E78033 +:107A30001EF71F683EF6EF180F78DF6B578424F4AB +:107A40003F7FD0827AE4C2090BD96966BD837A048C +:107A5000F7E9C04F04F29797789FAF7F0CEDCC0405 +:107A60000BB3A0506DB59BFDCEE4EF36FABFA02559 +:107A700093DFF97DDDEF7C2D3D56D6B9E538EE83F9 +:107A800052C03B28BF4BBC5C6FC945CE0ACBDC91D2 +:107A9000FDAD46BD17B05E5F54AF5D4B9F2D2FF916 +:107AA00062FAECF1E28941FA8C2D74968C473F2101 +:107AB000CB907ED81B598FF6EB38F4D3423667FC57 +:107AC000FAA954D74FED28C0B2AE635CAD91128EC7 +:107AD000AB08C705F2A408C79531523F19E332F449 +:107AE00082795CC538AE80F994E0B884E171DD3903 +:107AF000F807F2AF9DF30BC48F966F59988FF67508 +:107B00002BDFD75DE7283EE83F65A77D9FAABD46EE +:107B100072E002C801F4C7E577CF8EC07DFF5790B1 +:107B200007DE92ACFFFAF2E00BE31F2D52B28E6F2C +:107B30001D09FF8C771D3D26FEAA11DC84C3B5EA22 +:107B40003086F2FF3C6076940317B6D8C92F08132D +:107B50009E8F72FE509BC8901E7FC47D03F3F95523 +:107B6000B73DD4EF1CFFFCFFB148FD675CA753AFE6 +:107B70007BA6C8E923EB85162B54CF6C07FE6B91CF +:107B80007A02E5FDB8E9FC57F7BF5909FF97360AB5 +:107B900024974BCB52EB7765723937216EA43F8E19 +:107BA0005D1B6F99F05530FEBAF3CA14C25BC588ED +:107BB000B746896798F1D67F757C452B73153C7560 +:107BC000ACCBB214E97BD66B61F671C52782CB864C +:107BD000BF6840650CE3EB667C66C64FA76C3C1E35 +:107BE0007F0AF09606F50FD9DCF7207E3B542DBABC +:107BF0000011210EA4F52E78D17110FD6FE9DB6C18 +:107C0000149C7DFEFDCB3FD15246FAFBC6B1DEFF90 +:107C1000A3F1F5DFDBFA8F570E4DB952206AD06E13 +:107C2000C332B113FD0693279DA5B85A5DB45541E3 +:107C300018700464721FE141980D3C6B971D5D8EB6 +:107C400074BB94C9F334264417098817AA5FFA88CD +:107C5000FCB767EEE6F13DABEE876C00BDE80312C2 +:107C6000DB59FF5BA80F2F258A142F541E9BB8F3F6 +:107C70002E65783C0DE1AAE082F6A37D4B1C4A18E4 +:107C80003C33D51C6CAF284794D17F169DAE2CC1D8 +:107C90007C544B9EA8E428983725D2FCA7B887FCD3 +:107CA00063BD38EE309D9FC2AA3EA07C819AA67724 +:107CB00019E23DADD059910ABFA7C7CCCFC1FCD7BF +:107CC0005A79E2441CA2D17FAD5375E0F79A532450 +:107CD0003F01935D8E15D3890E399DA03F6C3FC93E +:107CE0007363FF8DCAAC581630EEC6E81D8EE400F3 +:107CF0007F42A353CCE94CA77A8E52784EF1B5AAB5 +:107D000088178E398BB2D1BFB80BBEBD81F6931ADE +:107D10003E33964C73DA5F0EC5D35B128D7E4F0BEC +:107D2000E9D9A87451C3F82C3CFBEDB0C9A2F225E7 +:107D3000E60BE06F7B4A401E05E3F1E8A1F7408FB8 +:107D40003016F01ECA07D7E8799FD7EF9FFBFE1ABF +:107D5000D08B2727B74EC7794C542486F69C2587AD +:107D60001D453D1CD668E9BC0B081A8663407ECAD7 +:107D7000E571DD26A1272E06DA6D4C6A6788231A85 +:107D800073C44EF4839D6EFC8D8A76437BA644FBC0 +:107D9000AD69E5F208364ABFC673F265C06DC0D260 +:107DA0004DE59E9FAF09F0C31EA8E4794D174B0E19 +:107DB0000B3E906B278F7656BF8976EE9F239846B1 +:107DC00072AAB3B7309AE2EA248726677E2FBB18DF +:107DD000FD412A8FAB9F6DBC9970764265B0FC4A1D +:107DE00060EAAFE6C0FC4E4B9DD5E8EF3B2DB2BE3E +:107DF0006AF83E41C7370923F10D8B9B331CBF3F07 +:107E0000FBE773216EDD7E6246BE8EC8F3601047CD +:107E10009BF14F828EAFCDE308FA1E706142C90418 +:107E2000CAA730FA1FF2037978FF43F586F3298257 +:107E3000FC40E6F7C6F8F336BACFAF89417FD3F7F7 +:107E400029EFA280711CAAA4CBF55FC9247FB89E3C +:107E50009FC9F5C8147D3E534CED9CAE8AAAC7BCA1 +:107E600085B3405FECB3A9E9A20DF7E925F89E05BB +:107E7000F80D02F31E9C7368F8F4CFF3A34FEA02E7 +:107E8000F3180EA0FCB899BF5302F22B122AC5E3D7 +:107E90004F470FE7E72454821C8046A754F9050F8B +:107EA000A77B09CE778A5EDF531BAC1F92AB983657 +:107EB00021039FC1BF8F46FFA1BC2781D34D0B98E3 +:107EC000EF1FCAD509A5C08F4DB69E7CE4ABA6E9CD +:107ED00092AC417F4DA937854C857232C82F8CD723 +:107EE000273BE75399B945C6E390DCAE6DD4FBD888 +:107EF0009D7394ECE8C6BCD824CC9B7B760DF7DF51 +:107F00008A8AEB3505E997C2F33E0CBE77E4F17C33 +:107F1000AA2179AE8C9EAFE5D0E7BF6BFA4D84976E +:107F20001BC16EC6F6C7DA6746BBE6F61E2E57D3F0 +:107F30004AC90FE37AED4E5C9F7B4405F39C8E2E7D +:107F4000FBC48271C1F674F120CA616FFE7C3A876E +:107F500030B3948F7F4FBAA8DB5B1AE90FAFC2DF53 +:107F60006F2F5767617B7BDC867E69A57C37B0937A +:107F7000E696C60CFB654E6DFDDA92A9D0DF3EB0E9 +:107F8000DB905D6AA29F21BBA80E6D77E0A7BA1EA9 +:107F90002BC9DBBA9ECC93982F58C772AC023CF722 +:107FA000DC3D27BE04E4F7BBF748AA0AEB5C237369 +:107FB000B9FCAEE416315E1C96231EDC01EBF9F52C +:107FC0004C9E87129DCE0EA2DE7AA494DB0D7530F6 +:107FD0002EECE7A0931D447A0DEBC13E9A474BCEA1 +:107FE000C437489FE5E9E85897E713F5F534F4E11D +:107FF000E148D087F0FD44798EAF2C7A38EE32AC70 +:108000001767927EBAA4E324F37A34846B0CF301ED +:108010001D798CF45D6C22EBCC417C945FA1A19F17 +:10802000A348E5E703A6347E5C87764E51AB9A4DB4 +:108030007E9B1CAE0F8CBCBA022FC0061877943BF7 +:10804000586FD84D7AC262D22365A5C17A43612E9A +:1080500007C6F94F3B97935D8CFFAE04E80FF3F82A +:108060007BF4FD6BE81BE3F7ABE89947882F6C3E88 +:10807000C23FC035B2E51FD8087F9FB06CACF8B8DE +:108080003572C0316CF78E8D7FAC6C2040FE8E3720 +:108090000EBEC8B2E1B484B89149B29D9E9C4F4EC9 +:1080A0006F60A4EF1AC2FC1AC6032EDCCE5C876098 +:1080B0009C9D1AE7D7A499B288FEFB46452F6F53C3 +:1080C000440BF06F81C7FFDA22A877236B25FBDE14 +:1080D000C9E4BED679E817626956941762A80BE323 +:1080E00091F033BD4F7C9851BC76A7FB90BC087EC5 +:1080F0005EB996FB390F69D6A5B8ED6FC08C2F9885 +:108100004FC6CD43FB8AFC1517ACAE88D1EC59E3C2 +:10811000595899BC1FE35E46B97F75487EE728EB46 +:10812000F3D50DF37F80EBC3D25AC91E07BD286378 +:108130005C6C40F02760BCF89D0F5E7FD63109F57E +:10814000B2F734237DF1CFCFBE06CFA4D4F9218B73 +:10815000E079D72B0F3CBB10E584DB4AF164A65DC8 +:108160007C56B5E27B91CA5FF9F0C043885F2DC5AC +:10817000EEE7A91FAB4B417E4BAA16DDB87F31AEAF +:108180003D31601EF56B79FCC652ACBE8CF5C75113 +:10819000AF17EB3DB2663AC9C3F3E84744BF74C9B1 +:1081A0005B747EE97C979D9F5FD2E56781BE9FB33C +:1081B00037DE1B8EF26500F1BF80F537BE8DF18E84 +:1081C0003380C30585FC9E948F7C1E560AF1FD0CFE +:1081D000C947EBCC4299DC8DF9D42FF7D0FAA181B5 +:1081E00045F9D515838BBE89FE1BD5417E69067A7C +:1081F0006868DF05F83D8DFECFEFE57ECF33FA7876 +:10820000075C6EF2870FB0A92E9467E6FD716AEBEA +:108210008D2AE2AD7D5BC35D8827337E7E6511FAD2 +:10822000472AA13F0BE5D37C487966174ED9C92F61 +:1082300096DF5D1C1E118DF1689EE7621E8F990FFF +:10824000CCFEAE8114CD87E3217F974072FC93D2A0 +:1082500071F8BF1331AE3FFD2AF17C931F6B671A93 +:10826000C7E3E6F1DCAEAF2FB3F2BC708BC8D7E149 +:108270003B051E616D0CFA8F5C32070F2AC92FA3D4 +:108280001D339FACC376B2F03B55C2EFC6516FC2EF +:10829000DA807C4963BD0C3FF905DD4F7E41E6E79E +:1082A000E3CEECE5FC05FC7294FC7B2F805E4F1A5C +:1082B000C92F176C9C5FB412E8FB46E49FC13A5C7F +:1082C0004F367F7CFCE277A604F14B2A08523BFA3A +:1082D000399DDCCECBAF0E8E7798F9A760EF0D2AD3 +:1082E000F2A78CFC1337B2BF01676D03FAA90D3EEC +:1082F000B0CCE4798B967FB3BB4052B281BD353EA2 +:108300005A07533E9525D525239F05E453DDB276C4 +:108310001C7ED12FCA27A2E2233C7509F633D2175F +:10832000EC1C35707D0ABAEC0FE2F86451745912F6 +:10833000118A737D5308FA86E25FA6F98A8A5CEF98 +:10834000E33896F434730B2C90DE055DCF933E92A8 +:108350004B757D64CEEF32AF9779FC2FCB0CE3EBFE +:10836000469C8A55703D3BC28FABEBA123829FFC9C +:10837000D6DA5B16B257C792EBFEED7D7B31BFE1DB +:10838000C84BB746202E3EAF099DB61918873B1C37 +:1083900013987FE7DF2E3FB530403FA769BF5611E6 +:1083A000077EB754E1F15A4DF0B565E0B357058D3E +:1083B000C23A57ABEB717FFCBDD339AB406D581B54 +:1083C000606F823C203D756580EBA9A235EAAEB5B1 +:1083D000E4CFBDCEFC24BD9F2FAAAFAD267D5D3B73 +:1083E000B6BEEEC0F1A5BEB2A10DFD6D97BC3C2E90 +:1083F000A7D9F87E32D7AFD1F1DA6F3678BEBF3663 +:10840000C0CF7D5F24D857301FBFCD275C0D97DDCF +:10841000C87CD5F83E5E65B2360FF92C8AA19FEB79 +:10842000BE2D5C0FFDA538CD265B35B4F38EBCF4B4 +:1084300080EC19853EDF29F7FC3270BD6CD18A844F +:10844000F5BEBBC1DD4B7A203C81CA0737A847B9CE +:10845000DC1EDFBA0DD3A7F1C5F7619FD46D6FA500 +:10846000270CC987A0DFEA84DF03E495140DEF83AE +:10847000F21B465FF7A672F53738AE372679288F9C +:10848000E9E43B83644F5DD81B7510F1E485AE8B46 +:10849000CB6F45BBC61B158976644319B7ABCEF7C6 +:1084A0002C277FA0966825FFE18F7AB6CAC5B0FE5B +:1084B00073D779CE04AE9BFDA98764D5F997F327CE +:1084C000E8D18FB05DD0837138698B00D23A796C76 +:1084D000FDF8ED3241FF4EFD03D2791CF53EBD9A09 +:1084E0001E1D8A371B7AB46B7C7A7460A41E25DC4F +:1084F000F5A5E9D1AE1BB4C7AEA2472F5C438F5E92 +:10850000E81AB71E55CAFE067AD4C0D363E12DC05F +:10851000E9D3CB507E39199D9FCC703A3A6B92C605 +:10852000C6E1BBCB8670F82CFC6E1CF56EC17AFFE1 +:10853000DDF17AAA56168E7AF2FC5E8B887C9ADF81 +:1085400016CC3786BF636090F7730EFAD146E9E721 +:10855000828DBD20445C1B7F9BF9709473216B90CE +:10856000AE42D7AB7F1232FE3FDEBA160E1808F1CC +:108570004CC6F8C4809E5F6ADE0F4F6C5EDC8CFBDD +:10858000AF7FADA2E73707CB5BC04BAD3ABF9333AC +:10859000D1B073015FEC29CBFAFBA79FF11498F7D8 +:1085A000EE39F05D8C911FC4DCBD9D30AFC9EF3B4F +:1085B000296E1F13F751AF42F6AC83CE2FC6BCF025 +:1085C0007B3A7709BA88F24C87CE61AA0E3A8719AE +:1085D00063F2D7C6307F2F9E3FA817DCD9782E0BC9 +:1085E00074685FB78CF9332B7ACBA1FC6965844C36 +:1085F000DF8D72DE2CE81C666540FC4EF7A7A21FDB +:108600009EA61270EED2F0F7C3B8B383CE5D9ACEB9 +:108610005BC6E8FE7DF37883DA0D388749ED42BF0B +:108620003125FF87D3433F871963F6FB57069FC366 +:10863000FC539910740ED36837463F873962DE7A4F +:108640005C80EA09C3EF87CF615E1EF51CE614FD6E +:108650001CE614D339CCFFD4E576E8BAABE789D66B +:108660005C234FD4C8FB1B9927CAF9C85FA69F6734 +:1086700000C6A6F3585FF279A6B1CED598F93D7B36 +:10868000DAA7C7306FD396C8E39436FD1C7B483E0B +:108690003F371392C3CF634F489414E4DBC51627CA +:1086A000BD6F52783EBF714EC6E0B3A6137E8A6797 +:1086B000C5C65B98866B57C9F3F08D7331463E5C37 +:1086C0005D2EFFDEB14CCDC6FA8EB97659C5F31CCE +:1086D000E9D6A0FCB458537E5AB49EDF1F6DCAEF92 +:1086E00097702C2027BEB24EF7075FFFF99999EBE0 +:1086F000903F31E90DEC83594FCDDE83E75D32BF0A +:10870000BBE237F89C73F0A1A8C0F32E73BBF7ACA3 +:10871000E0655F2AAEF31BD51FC7635CADA39AE784 +:108720008F5AF47119EDC79473FE7B62937A07F642 +:10873000F346757F3CE2EA03D5A3CBEDCFD7F3FA3E +:10874000CB989A4FFADE29CA18D7A849B4EA79908B +:108750008A807EEE1CE5E36A3C9718C22218DD7F12 +:10876000C01401F3F11BF2001F40A931E5A1F7ECA1 +:10877000F0CCC9D3FA102EBCBE3E89C65F9B7ACC22 +:108780001A05DFBD5EC548CFDBEFD5ACA213E352BF +:1087900083ABF96162D1D50DEF1FFCB9C33F01E591 +:1087A0008C490E6F5A3795CBCD2A8E57F64FE0F293 +:1087B0003A43E6F90119398A503333E03CAD9B9FC7 +:1087C0003B6D73EF263C23AD03911489E75F53287B +:1087D000DF813539643C8F74C4C6EF77D8BD2584FA +:1087E000E2B8BBC3DC4BF01E8D3DD3AC9497A9948B +:1087F000F33CFA8C65922FF07C83F99921B912F041 +:108800009CDDE1D5B7FF0EE31BE67376AC82E3AAED +:108810001A5D4F010457A559ECBAEDBF8B250B7EAD +:10882000851776BDBBFA8330B40BF6455A8907DA53 +:10883000982B1EE59C57F0C47339EA8FC7FD7BEC7B +:10884000B1FB26635CE448A4B212F9E6FC74FF5362 +:108850006BE1BBEE6DC24C07AEC7A485744EEF7CD6 +:108860000E8BC4769AD671FBAA2087A9A3E1DE9D60 +:10887000EB75F96A55E2911FEB700FC2F71D69ACF9 +:1088800013CF0377780FABF3A07C18F417FABFDB94 +:1088900005F7EFC85EDE26D1B922C65CA1781E516D +:1088A0006A1619C6F3F66D2BD5F03CEB99F3303808 +:1088B000A81F5AB5562BCDA4E9527CFA4C8CC78719 +:1088C000E3DD99945281FBFD6449B186F98C463E03 +:1088D0005E5BF3728AA7ED9CF6D9A422186FB7C02D +:1088E000F97CCFB6B5BE6FC0777BB2F9794829CD98 +:1088F0002C47DD94972D55D927A21D7326CCE34B29 +:1089000043BC2A287D3B5CC87A1E1FEACB8ECA195D +:1089100032CA53E91AF7165C5AC7F791751B8FE3F1 +:108920005B6D8CCE535AB731E247331DBFB59DC73F +:10893000BF8C72C4DC6039DA6D1B9C84E37EEFC2AD +:108940007F3C6C053971C636F85D2C1FBB30F0F0EA +:10895000C25B696B68946F52C5C80EB36E5B41F120 +:1089600028AB4D95E551E4CEB5FA53D820F129B4A2 +:10897000C7BECCF6BAB749F9C867D76ACFA02FB43B +:108980002B08D7D1AE51CFDCAEF9BB2FABFE58F3DD +:108990007C2F0037202E0AC5A78EBF106F49FAAB77 +:1089A000D0B2525F5AE630DEF20A9D1AE6C36A4937 +:1089B000D60AC47BA17123CE97507BF43DCF3B20D8 +:1089C000396BB42F95FC509DC7F71DE12C83DF87D1 +:1089D00070565A30CEF21A7280719C65B4EBCD2D70 +:1089E00065B8BFA7403B51A3ED1B1D6F51FDA4E12E +:1089F000F701F75E88A3E1AD541D6FA59AF0D64C40 +:108A00005DDF65945FFDDE8BDDD7C05B37E9F33159 +:108A1000E3AD069C3BD2751ABFD704239A61D134CB +:108A2000FE0A7E4EA453C338E00D8C6D413B79B7EE +:108A30005051FD158EBB07BB5DC3EB16C186FE51C1 +:108A4000FE88D3585785A5A09DFCED3B33E8DC9A02 +:108A5000738C7B3522873E977B311F4536F251D28E +:108A60008271FA0DDF0F15A606E0F09014B917F326 +:108A700044C2757B8159050D43BDD28DE9D4DF9485 +:108A8000DBDE66F3A309B70CE2FBC855C1F3972BF5 +:108A9000FFACE2B9CD38B03F6E203EF369F7223D1E +:108AA000B21D34BF0835789D9C267E5EB15EBF4FF7 +:108AB000C35A41F73434A472BC60CE0F6CD7E5F6CC +:108AC000019B46796F0792260AE8FF33D6A77D3DC2 +:108AD000DF17072225F2F322DF68017432EA3DBE78 +:108AE000CE16747F87918F60F8D15AD08F06EDB67D +:108AF0002C3B4EFE93DD65129DDB9821B5323C8701 +:108B0000C1EE113B514F1D8DBC4F6CC471782D8748 +:108B1000ECE4AF38F70CE6555DF427A1F666475E46 +:108B2000FA4A35EAA93F66A771BF6E8E34AA3FC4E0 +:108B3000E87F4FDE54F287ECD6FD216D9547C9FFE3 +:108B4000D156164AED99E5EBC432A91FFD12E6761F +:108B5000FF49C76B61FA7D4AB5B94379F9A1287F0E +:108B6000568678B4F5F0BE2DD3BD641AB41FD6CCAA +:108B7000377BD8652BD54FD572421017E4E7CE8AE4 +:108B800060A3E8F7A1FEF1FC66807F5D2D57A8DFAA +:108B900089F24D8407275E96E8FD233156DA1FDE01 +:108BA0009512CDCB1BE6A6FB40BC6D16D721625EAD +:108BB000BE7FDA97DC44741FC211EB145AA77D2BD9 +:108BC000BF178FEDD92797C5E3BE0F5FCFEF999001 +:108BD00040CE238E913C0EFABE632E3F0F3D520FC6 +:108BE000F3BC55926388EB1EE77991875D00A093F3 +:108BF00046F2D9B1E6B3A49777022AB0CB23DF9B24 +:108C0000CB076C3E0DEF513920B08A5679247FAFE7 +:108C10004E0BBE37A5D1AA3950DE039F929F63F554 +:108C2000FA5F3E5C9D82E7300AE8DC55BB97FB713A +:108C30006B578AC63923CAFBC96F5BF13ADAB91799 +:108C4000F3B8716D5ED7E17CA0FFB5645AF4703E55 +:108C500090C107065D61FD7FC9D7BF8F84CCDF6AF5 +:108C6000DD533D0EEE3F2C13693EEF790F07DDF328 +:108C7000BA76FF1356BA2F14E54A24DE2BD14FF9EA +:108C800040395E49A175319D8B32FA35E633D1DA30 +:108C9000B3785D26DE6F63A13CC6B0FCE0FB5F4F9E +:108CA00097F175BEF89C40F7ED18F7851E36DD1775 +:108CB0000A72E77819B463BFD52EA3BCC47B5103F5 +:108CC000E51BDE8B1AD82EDE8B1A58C67B5103EBC0 +:108CD000E3BDA8C179D85F0D7A8FF79E06DD4B946E +:108CE000F60FC17AF80B9E9F8ACDAF9050AFAFF6CA +:108CF00038497E9BCF53C5E6F75831AEF9E7F5C149 +:108D0000F79AE6AEE3FB6899EB63F25FFCA255A02D +:108D10007D540276375874ACD6E6E98D43BBA4592E +:108D2000604FB091F6DE32A67C6B06E281468B8CFA +:108D3000E7B2C66FFF0D2E4037BFAA55931D785B73 +:108D4000EBAF8F613957B7E38A1AB3F367413B77CB +:108D5000A400FF2A38BE2D6EBABF521144E4E7D7F3 +:108D6000C170C671F75D9E5A1FA1D034ADD6397857 +:108D70000E9FF3C9DDEC536B04CCFB9E4F55097578 +:108D8000EA139B3C93CAA1DDE24FE5E35806E6A354 +:108D900073D501762FEDC3CF3F3AF89C86F3530687 +:108DA0009F427D6DDCAFD381F7EBA03F06EFD7018B +:108DB000BAFC2A6CE0A827733CF7EB70BB6F932ECC +:108DC000C7C6B2FFCCFE919B707E7F93F32F57F7FF +:108DD000D70CF5EB8C1E575EFC77042D84EC48B95C +:108DE00095E79931D68AE79B400A52B9A642F7BB6C +:108DF000B23E2ADF8079594968DF6A540EC9617D25 +:108E00003BE2291E4A718430286B54663ECB446E87 +:108E1000075B49397612FDF0F714FDF70CD088296D +:108E2000790F468C169F359E45980F1D20A78A64A2 +:108E30008E0BE7FFFCC48FD13E7C73CB8DB3F8392A +:108E40005FDEFE9B2FBE9C28C0FA9FCA7875BA9041 +:108E50003E3C4FC36F502773BF419DFC0CF9156A10 +:108E600073003E0203D7F678791E5E1993F1DCEFAA +:108E70002A4929C2F2AA9D0E3ACF5B172D12AE08DD +:108E8000DD1272907C316C878E3FDC7B91CFA6EA3D +:108E90007C668CA3CEA6F2FB7D2207C4C0FB7D8638 +:108EA000EE9979E901D2138D8922F9AF1A13675D22 +:108EB000352FDCAEDFB330BC7EBC1F7B4A05C97FDB +:108EC0003BCAEB2894FF950EB4D7F3275DABBD608A +:108ED0007D32D49E7B2B233DADEB9307267B289ED2 +:108EE0007EA65BA0F31867B6DD9F81FBEE4CF7C74B +:108EF000752CE0DEEBDF3CFEC464EC2FD577390C3B +:108F0000FBBFB08D9F273C7FF44F3625A05E817557 +:108F1000D086F185FBB63D2161BCF6AEAE8F6D7893 +:108F20000FA271CF07B01FF1B7319E82FD5B1663B0 +:108F30003BEB3AABEBF199CAF2C347BB6F3BBB6962 +:108F40005138FA3FDE6FB4D17945BF77F655E77FE8 +:108F50000EFB03417613CB091F8DFFCEB6F2766A66 +:108F6000B415D4AE3FD11D8E7693FFD716B603F855 +:108F7000AD1FE3E32053FC61DC3FE7AFB6FB305F9E +:108F8000D8D32A7C0FF9E32CB4AFC17C5E2CE7F771 +:108F90006B2CD00409DBF1B4664B480F4FED12295E +:108FA0009ED7EFC17B527A75FD5BD2984D7429D163 +:108FB0009248BE7964E6BB3393EA75560BD76EA729 +:108FC000A419BE4FC7EF6752FC1FE849FD17375A77 +:108FD00082CEDDA4B2B451EF2DCFCEFDAD03D7A329 +:108FE000C59D49F7ABEFC929A27333173345C25961 +:108FF00063D1B3415FBFB1DE7B15DE5ECDB2A92187 +:10900000D8FE9E446509DE47BA07E9C986EBED093B +:10901000D3FD3A774B44CFA81C46F46CD0E9D98FE6 +:10902000F4043A2D58E612900E51397D0CE9F041C6 +:109030003997CF61992EC103E5A8C40A86748C4282 +:10904000FAF17638FD96F531FC2E2CC725E07751E4 +:1090500050C6FA618AC678FE00A79723510CC27BDE +:109060002C5D63736339CC45FD6465D601D4DF8D17 +:10907000B82785E17D9D2175D27D5C06FFEE5BFD05 +:10908000E3A74A47F317EAF56DAC428F87F0FAB5CC +:10909000B61E2A9F965AA78701DD4FC78A74FF5EC6 +:1090A00083CD4FE7FEE12B99E2FB26FFA9E11F5E8E +:1090B00054EE1637A0FC7F59F6A1DC31E25643711D +:1090C000B74489F26A8DB89B8D4F91D912B91D3280 +:1090D000240FA225539CCD4D72DA88AF8DF7BBEBE0 +:1090E000CE531EA7FE0242105D0AE2B89E4AC1138B +:1090F000166807A731B97A1EDD4F46FEA9D812C6F9 +:109100009AE2F15E1B55C4789EF658848CFE136675 +:1091100055C5BDF8FDDC1B647E5F255F8744ED6EA1 +:10912000F105F86EFEEFC31401F47446D54CBAFF96 +:1091300066387FC945F26D2CFDE5DF1EB71FF3D100 +:10914000CE6D4FA3A7A1C70A9B0509E3DA45B2BCC0 +:1091500098CEC3574CA0BC36439FF5A33E0BD80F07 +:10916000FD2F264E267D560FFA2C409EBDB6F5C625 +:1091700070DC47FDB5516F237F9FDC6071210F7854 +:10918000D8E059F41FE6FF3EE9D15AC00FF7E325B6 +:109190004B808BDC1BD21FD512615C2DD547A9DF1C +:1091A000E72445BC15EDE14E1BE62DB1CFC215B449 +:1091B000F3DF0D1DDCE80EB01BF237707F49FE06B1 +:1091C000517FF27D96C62A16915F7F2163CDF1789B +:1091D000FF0C13556867D5612BE957FFBAEA1DB13B +:1091E00057E9A77FDD963A7CDF79979DC6D75FF771 +:1091F0006A16CABB7E9B2F2BD28979E1AED3147736 +:109200007D3084EE0B5805340B4739E8BCE910FA81 +:109210000BE66B9193CF927CE3F1B35516579C8488 +:10922000F56B2CE47FEEAFB3DF83DF9FDC64E36E8E +:10923000304F6B562EECF3B5FA7C60BC2AD55F1B21 +:10924000C6FD3DFAFB93939914B87F2D5A643DD225 +:10925000B930BD6212FF9DF39D714F494B0AC71390 +:109260002D291C4F58B361AF001F5A7FF21CCFB39A +:10927000D0EF1131DF0FD292C9F1446785DD842729 +:10928000FAF622FE3E541D8C275A6CAD1C4FA40EDC +:10929000CCC77B973BBD22E3762D1FCF11C01B9817 +:1092A00047571BA6C6A1FFBF8E7179B06183BB066D +:1092B000E541862C517CA3A85C8F27464FA4FD6511 +:1092C0003CAFB5CF9A6C3CDF782CF923A40CFC148E +:1092D00071D07E0BBF6FC288A3658038C0F9340996 +:1092E0000EA2D3860D9E27713C4DABBF9B4FF74717 +:1092F0009BE5A21E2F4BB4F610BE1461DFE23E3692 +:10930000E2EEE67115FAE2490FC2C4D9B920BF0CEA +:109310007F7FB12499CEBD3187330DE556943EDE73 +:10932000935766D33DC89F5E8960352E3C3F5241BE +:10933000422A4A8F0BA39F81FB1D14F2E744E9796F +:1093400059512FD7935FE1F443CC8572C1A8CFF474 +:10935000FA1AABD0FCD1D4CFD0F9E1C0F8C1A93B07 +:109360005CD598AF509B64ADC0F843C0F702E911DB +:10937000DD6F4AE31446B63F5DB707E05536D73B8D +:1093800057F76BD815937F388DCBEF6866FC0BF0E1 +:10939000AF5950EFA802EA8DD3F31DAE6A1C8B7B48 +:1093A0000C3DA0EB0FA39D68D9A407DC663F195FB5 +:1093B0008F74FD9ED3E22A81E2488E95598B913FAE +:1093C000069A04BAAFE7CCBE5B24F497CE6FE4767E +:1093D0006CA926F0F8B0C6FE05FD081BF5F52BFDBF +:1093E000B0AF1EFD7445711686F7BF15FF1E702ABB +:1093F00094375585B954A8D2CF7CFC9EEA6681FC8F +:109400007C857559C7CBE17DC1AD76CA8BA8D1F7F4 +:10941000C7A50D3C7EE9CFB76DCAC7DF2CA7E8BE54 +:10942000BAE2D96C2AFA3386E6F31CB7E741EFF3C8 +:1094300073465AB0FDBEA931B85C6C8A2B7FBA2145 +:10944000D86EFF7C030BBA670FE71535F12FEF8756 +:1094500039F97E9E6EED13478BE718EB60C4CFDBC6 +:10946000B28CF87B9F8AFEFCA8B9765D0FF27BF880 +:109470008C78FC11C9558D7E97B66CC720DE8B3673 +:1094800039EF5F58D0BD957A7C7EACFBF5A24CFEDF +:109490008C3053D99017F11B83EFD73B5D399BF28A +:1094A000B90DB9609E8F713FDE17BD07CFB85FCF92 +:1094B000B807CFA08BC2387FF6EBF74B9CAE3D4789 +:1094C000790B17AB803BC9FFF44DBAD7A7FF29C171 +:1094D00065A7CFB87FCBA3D3A9A8D67EFC1B30D479 +:1094E000B7C1DE13E67EF97EA8AFA11F2A284F433D +:1094F00021BF52219EBBC375D5F9C9F04B15565AF1 +:10950000E8DC75A1F9DEBABDB6E132CECBF4DED827 +:109510003F5FDF68BA7FDE393E7D92A0C779CCF12C +:109520009F1F74B717ED04FA0D3C153F13FD466BF2 +:10953000371A71B20ACA335BDBC9B8DFE36F94E74D +:1095400092601D3D9F63D346E11A7930A3C7A3EA19 +:10955000FFC2FC1FE3797272EBDD7310C79EB0B8D7 +:10956000E01766C9EF790BCB317D16D75D6C783D7E +:109570004E03CD905FAD910E3AA7E7657D711C005B +:10958000B97B518FEDB997DF630E1C4B71FD63778B +:109590007F16CFF306FC9437D031DD7512CFE77F0D +:1095A000D8129C37D081790340C7CE8D1C0716EBAB +:1095B0007903B698BCFBF1BEE20EEF0D94B77D3E89 +:1095C000CC139FEB1CAE67178DBFBBA108F8771DAE +:1095D000DE98A4C4E742F929FDBD4187DD21DCEE18 +:1095E000437F23E917BD7EBB11976BB1739C665512 +:1095F000AAF1BCE0B9C834CAAB3BB85131FE18037C +:10960000E541B4B5DC1F4F41373D6FE1C330B703CF +:10961000E3C8E75B2C32D2E35C9548EDBD5FC9E35C +:10962000066D6D1FF4DE8CED65F33C062BBAE5513B +:10963000A9ADE771C0732DFF28E07DA707CE3B19C8 +:10964000EA8D73319DD928270F080AE529BC9FFFB1 +:10965000BD6C8C27BDAF58E91CF8C992C3742EDFCE +:10966000C85B004A54635E43B1EAA0FCC491E7AE14 +:10967000D510F42B24B8799E44CB63DF1330AFA20E +:1096800045607DECAAE7F08371C5872D76FDF0F685 +:10969000C0A3BE143ABF4A7AEC7CB3407F1FC3DA42 +:1096A00076F538FF99EDFC3C8451F65405F3EB70E8 +:1096B000FBFE9F61FBF42FE0BC3FAD40409E60424B +:1096C000DE00CDC3884F76001DE87E0AA053F7A8C0 +:1096D0007460E33AFFEFD7F7613FAE3B8FFF05E5DC +:1096E000114EAE12D590701A27F191116F34E70F19 +:1096F000E23F8C6727207F01FD2EE8ED7EB491E3E9 +:10970000E3847C496FA793F2EE46D03FF09E01219F +:10971000E81E021A67DE46F7271BB386EF19188A80 +:109720002F3F66C49783EF17786392BF1AE3CDE7A4 +:109730000456B163E6C8FB06CE85F8C92FDF21B019 +:109740002DD5F0BE2384F3A9D6C4F18D398FB31083 +:10975000192419F36081B1E019B22999E8950CF345 +:10976000217960556AF14AF88626610EF25DA153AF +:1097700090D0CD5B109DBB2352C1BF433393E2F326 +:109780006F4CD21C1867EEA8B650BE544798FFA77E +:1097900078CFA8561D36EA79ACF84D5C5EEF36EE10 +:1097A0003D44031DE729188BCC3C22D0ED7DBDF054 +:1097B000D54DFCEFF04DA952C98F7566FB8C9938D9 +:1097C000BCD44D8CC6DB11127C8FA9F1BC791397E8 +:1097D0001F01FDD0BD3EE78923185BE3FDF8F6428B +:1097E00027B62F187CA2B18038F1C49CC1DB717EF2 +:1097F000E99B747BC87A7026AE7347246F4F1507B8 +:109800006FCF0DB037D2F5793107AFD72E784EFE36 +:1098100011E9D026101DCCF7FE147805BA77A140C7 +:109820000BFEDDFCF72CE66E1274F9158CDBAD86B1 +:10983000DC647C9D8B6A930EED1486CB532A954392 +:10984000B8AF57E9F37B6312FFFDDC12D6B983F89A +:1098500085F3FD48B9A1905C48681466E1F74B8C2C +:10986000FEAD1F93FD5A04760DE2840313262F46A6 +:10987000B86A0F188766EC17C46B9E9C7094CFB9BA +:10988000FAF7477627937FEF58CEA110D427AB1F66 +:109890004EA2FB29CC74B996BD62FEFB1D13CB8290 +:1098A000E3AE0FEA7C61BE9F620FE613C07AEC491B +:1098B0001229CF6F4F24CF0B32F2019EFCED82AE06 +:1098C0009D7A1C19ED16BB2EB3EA36F23C82273383 +:1098D000F9BD2D0D60CFF33C011FE50DB03992C2EB +:1098E000F3043EA3F34A7BBC16BA3FC1E00B7BA650 +:1098F0007E8F44E2887B29282FC0AEF363939BE7D9 +:109900000534E8F7397A97F1FB21CC7C3D567B8F03 +:10991000EBFC5EDB66DCEBE7267A7BF3783BA9DACF +:109920008794B7F021DEFF07FDE51FE4F7FD5D3CFE +:10993000C5A30EC371660F7D776AEBD79AF07E20C0 +:1099400023BE6CF46FD3EF6B36CA2B433CCD9BA088 +:109950005F6FB49BE202368C0BA0713A4E9CD79B92 +:10996000F524D1B5FD5E91F282DBB3EE27BBFEF0AC +:109970002491E2B987E76DE943FCF0598CD5A5291C +:10998000745E6517C62393336D340FA6DF8B68D8DA +:1099900099CB9A7D163C0FC49631DD6FA0D9F15E4C +:1099A0003A784A22FDFD18CD86CF652E418B427B49 +:1099B00025B1EC7B9600BC6ABFF79D05F4FD12FE55 +:1099C0007DD8658DE46F0853E3F47C4ACAB79C20C8 +:1099D0005B496FB6E51535CD88C6BF23328BEE37B0 +:1099E000792B8B9F3F04DC1319F8F7A4A4CD7C1FBF +:1099F00078A50ACAAFED68933042C6EC8F7F761225 +:109A0000F53F5B1E4AFD75B73D1A17789EEFFECDF8 +:109A1000127DD7BD9AEFD7D3222BEB097A6FA775AA +:109A2000BF7F33DFE777AFD3F77F338FEF26577AE8 +:109A3000AA391F58E7937E69E67FCFCB9B9797BBE8 +:109A400002EA793317590518B7B565F912A4737787 +:109A50009E48A4EC769F5888F91B975C4234F2A785 +:109A6000316EEFE4C556DC3FA725FFF44C98DFAA22 +:109A7000CDA941F700C6027E0ABA8FC9AE6EA1C554 +:109A8000D9CEE89E948555BC9C0C6012D73B396FAB +:109A900021956341EE85A0BD9FDFAA611CD891E2AC +:109AA000998DF43C1629915F29399FF387171BC6BE +:109AB00079B89DA4D792BD8B5B315F37F9B7163A61 +:109AC000F3536B73D13D4CB5D3114BC03C227FBBDC +:109AD0008AFC6E2D6041D2FEF69763F9EE3F2508B1 +:109AE000282F3FD93495E886E7827C0172C4817EB5 +:109AF0007E58EFDE9639BFC3BC81EE2C3BD973B7DD +:109B0000A96E2ADF962F0181815FE7FDDA82ED7D64 +:109B10007689B1D6ABC43FC6E2436F3EA3739C6D5A +:109B2000AC2F0FD743BB2C923FF3B6C13EE2C3A884 +:109B30001C85FE9E8E77B13B01CF8535E87CD4161F +:109B4000FD7E0DDEB7AF65029FE23CDBEEA3BC6598 +:109B50006FAC350BEB3F72AFA8E1DF35E868B9AF0A +:109B60001BE5C90F3759F9DF85C2FC66E4BF7BAD41 +:109B70003C2F27DA9510A8C70EB72D9E86F202F863 +:109B8000988317EDFEE711CFDDF19FA13C9F661D85 +:109B900023F97438C4C5E3DC59DCFFFA4A8BC4F0FE +:109BA0003E2C29BEE4B09DECE0077C27B09F16BE9A +:109BB0006E09559FD5223FBD2DB041B47B31C0CB3E +:109BC000FDE45CDE18FE845C5D1E1E91066BC96EB2 +:109BD000D0FD09EDCD13FF792D7CDF1E67A1FCE0E0 +:109BE000AF2F0CF61F200E433B3659B7636F1FB4DF +:109BF00006D9A7CCE9DA81F3BE7BFE5CCA974B3667 +:109C0000D9AB09A6F24D9BFFE27BC2A66F0EF017FF +:109C10007464DA29EFA9BDEA93262C77378BA42741 +:109C2000BBBD45AF63BEF1252807CA59F3F36D1DCF +:109C30007F777B9793BF4391FDB528BFBA2BF97D02 +:109C400048EDDE4F5EC1724719CFAF6FB0B9292F13 +:109C5000217AEF048A2B5C6ADE9A8FA2C1EDE6F7C7 +:109C6000A9B9D5422150CEFC7A3BCF473DDCCCDBB5 +:109C70001F6B1C467B1D55BC9ED73D2B6CB4F3C798 +:109C8000BFD5DB1BAA270DC6A3FFD92CEFCCED1A3D +:109C9000E59F211E4579E92EA2F6DB33178528E9D9 +:109CA000C37AE5B6657D35186BBB2313B49638527D +:109CB000AF0CC99D6FEB72A79997A7C0BE45FE9CDC +:109CC000E25E1E89FC909A6795112A3BBCAD6A48FA +:109CD00080DC690FF33C85F9E81DB94EDA27ED36D3 +:109CE000751DE5AFE5260828FF8E453E4A76EF94C0 +:109CF000C45801DB7B7433D7BFD03E97575EB13376 +:109D00004440BB8AE7275D027985EB9D9CEE89CFB5 +:109D1000D6F507AE93996E63C9A1DBD43E92632456 +:109D200077A0DDDE95A5343E432E75AF94F8FECCCA +:109D3000B2513F87E7F597E3383EFB5328E999DBBB +:109D4000595FCD18FEBEABCA25430E487FB8FF79D8 +:109D5000CD3A4CFF47626E4D50A0BDC361832B03CB +:109D6000E341437E8971EAFF658CFB79CCE7579E1E +:109D7000D4E979A95C6DDF0CCF839B19F773BCD351 +:109D8000EA403E6A4A59EE40BE9891BADB817CD1E6 +:109D9000D4B33B07EF151B3E07FE8905E32FF6D42E +:109DA0005974CFDE139B3C073707E8297BEA563A04 +:109DB0000FBE8CB56A683761662EDEA7DB98F2901D +:109DC00003EDC4901495F2931A52797ED2F1CD1C12 +:109DD000DFBF31A995E2274D3A7E4EF538E8BC6FDA +:109DE0005362DC41C4034BC583294FC0FB17F4FA0F +:109DF000EFA55C3DCFCEA9E7BB85EAB8CA696D6522 +:109E0000B84EC7372B3C2F25C5F4F7CE537A168AA8 +:109E1000F0AA49CF2B582A71F9B2B43EF2606D0016 +:109E2000EEF4E9FDFF6683FB9748BFA5B1006066CD +:109E300061BBCCB0772AD0EED2AF9EC3BF3B731CC0 +:109E4000EB8DF577676EDEA8BEBA99D68BC779F031 +:109E500042353C1F3C424EE9EBB67383FA16D67F7F +:109E600057EF2F436EA5FD92C144570DEE4B537C27 +:109E700068443CE76559C5BF5766C4A76B2AFC3FD9 +:109E8000DD85FAFB3AE3C5DFDCA89EC1F93D5CEE57 +:109E9000EEC771D546B633F21B8F338EFCC6243520 +:109EA0000EF9DCC089B5BADD79245BCD0FE4FF4B38 +:109EB0003ADD2FE97ADA9A6FD3EF69582A8F26575D +:109EC000BF53EEF934902FAD32BFA7E18A4EB76B86 +:109ED0007DFF4AB9E7CAE6ACC0EF55B2AB964A7C03 +:109EE0009D04A0554DFCF07E7C9D5534AF043AFE98 +:109EF0003FA81021C0008000000000001F8B080058 +:109F000000000000000BB5587D5054D7153FEF639B +:109F1000771FBAB06F5D8850C4BC05095A302E82D5 +:109F20001F24880FC44AD44C57DAA69892F161AA2C +:109F3000ED7471BAECD8461B2BAB7C08EB074B4D8C +:109F4000A369FF7065A2F9A87548339D6AE31F3BBA +:109F500096D8A4339DD2C649FE71926DA2FC2166AB +:109F600086B1E374EDB463CFB9EF3DD82F3E62DA2A +:109F70006598B3E79E7BEEBDE7773EEEB93BF843CD +:109F8000056015C0D6D7FF6A876280CDD6C89270AB +:109F90000500D81700D4003CA0CFFA740A1004C8FA +:109FA00003502AB49F7F2B17A04BE63D211CFDD800 +:109FB000CE7F1390BFD7CD45800310F01F0AD2F596 +:109FC000D74DF0105D0AECF300FFD7C7E741549A74 +:109FD000E2EBC195C46F900A93E66F944B92E49BB9 +:109FE000F2CB93E41FB46B8A1FCFF794529534BE23 +:109FF00065E993497AFD3E6F31CDDB54B42B4F4375 +:10A00000BBC53D6A09F1B73B2FC167A538217CCAA2 +:10A01000FB9FD500BB484100F801803A6C4FB7E781 +:10A02000D78186AF92DEEE3A6FBE17D7E9C98316A5 +:10A030009AF7CCF65B6FFE0AF1E8C9CDAD14606A01 +:10A04000BED7CF33DC477C5A15E999E3965C95D3AC +:10A05000EC84AB2AB909D7168B27A410AECD0EA875 +:10A0600098DE1FB57101A22EC435CE315A179FCF8D +:10A07000E8FA7816A36ADCC5687DDCC96843BC9041 +:10A08000D10DF102461BE3886715E21A7733FAB562 +:10A090007839A39BE2CB186D8A57B1794FC52B193C +:10A0A000DD1C7F92D12DF11A46EFF9BC5BFC68CF25 +:10A0B000EE577E64271C7FB2C7FB34D9D507FE7CE0 +:10A0C0002801D8EBF37E9D7810C3E0CD06D8E607D3 +:10A0D00066FFD976751BE9C115B505AA91F2184737 +:10A0E0004837FAB46FB3715555721F010A2504053C +:10A0F000A97CED3E970350D4AE7D87C9254912D186 +:10A100003F16DDA5881F5809BF83ED6A2B93C7440E +:10A11000E798C45C0799709B8A6711C6CC38A1C9BF +:10A12000F6DC39C5FF45F7C4735EDCEF16E8715EF7 +:10A13000DA7230AB19ED7BC1CF31FB2E3E06304ACF +:10A14000F9244E6403CEFBA415FD88145E72655C91 +:10A150005F30FC68F2FFF2E9F929881E90ED24B720 +:10A160003279BF4F7B91F0DC6CF55FDF86786D2E26 +:10A17000163CDD0A5150F33175CBF6A807C8FE0F27 +:10A18000DABD07190E16D94AB87F6289F184339E69 +:10A190005E160A19CE3D9970862B72F40584000272 +:10A1A000399E9087E1DDCFE611E0386F8781F78E29 +:10A1B000031CC3FB61713EDB2E33FB4C3CA6C32565 +:10A1C0001577B3AEA07DBFA0734545B46F39E68B5C +:10A1D000F25B15CD87AC89A0EA60F9AD9D219C6C3E +:10A1E000716FD4C1766FCB5B092CCF23A4F71079A4 +:10A1F000FE9A9EE7A3F9E4F7E3D9A3F91EA2163D60 +:10A20000DFFF5434DAE24DD07BC72FB0F3BE4DF9F7 +:10A210008EF47DFBE111FC06B54B4605A2657BB4CF +:10A22000B769BDBA45131BC824510691F2E7623DD8 +:10A23000AE43F5A8C5122CC378BFF8FBCDF2CE0C07 +:10A24000F9FF4BDFCE77C80E931765C5BA13F70F2A +:10A25000B5AB57BE4CFC635E8E30FD39E641823FA4 +:10A26000FE4CF6BCA7084D740F74E33D4032ACB30E +:10A270007FD1C79F37EBECE843D6D98F589DA9F320 +:10A28000B03ADBE546DC2B28BCF9E04286D3B3725A +:10A290005B06BD115F5B2CB5CEB65564AC3B63B3BA +:10A2A000D49DDBB3D49DF12F87BB910F06EE5FB435 +:10A2B0000E7D4C4335537548EA98A50EED7365BC89 +:10A2C0009F05BA47AA66AA432293A3BFE775E0FE9B +:10A2D000AA386D7D7176CCADBEE4D13AFFB7FA6293 +:10A2E000D8399DBDA978DAE03907D513AB7CE2F205 +:10A2F000CDAA4CF3ACACAFC8A17D4A885F248FCD0A +:10A300009FDAD75CA774E4C09918F543411128BEC1 +:10A31000820DFED7880F1EB6C95D484FCD3F782607 +:10A3200086E3FB4449B67948CFBF86F63DD98935E7 +:10A33000CDC6F8158CB7C076F22F9D6B5BF6D4397D +:10A34000EA3AF43EC245E774CD7EAEDB3E753DE1B0 +:10A35000ECB26AF018EE3FB88C8F04DDE812BBBC9B +:10A36000FDBB788E23F912EBE35C9B9E8120F9679D +:10A37000211F29759376E43D37CA7B97F11062302F +:10A380006B0A9DA3B708BF7F85066AEF47A96F01D7 +:10A390008DE91D69E42321D4EB593473DFD267D8EA +:10A3A000399997A510B13D9E1087A52F3535E07AD4 +:10A3B000E1253C101CE1C69D32C56D5629DAFD042D +:10A3C000EDFBC4FEA848FB4E48CC5FEBF4B89E6E94 +:10A3D000BF2EDAAF2C617D19EAA91E59C846DCC729 +:10A3E000B2FC91A1203725EF0870CC8F47B3F53A26 +:10A3F00023D855E0C8BEA2DD55E466C9EE8131DC44 +:10A400004F9255F80CE99102A92582F3360AADDE88 +:10A4100006C46B5059E0B451BC839AB30AEBC5290A +:10A4200023FE7D01DD6FC73BC3976F5AC8DF7D8C6C +:10A43000629606DB502F4F95FC210C5D97A49FCBB5 +:10A44000E58108D63AC8DD8AF312FAD99C6AD44F5E +:10A45000E8677BB327F35C221C2CD02715E37A270F +:10A46000AA81F975606D73FD12E407546902643ABC +:10A470004A4CA2BCC5F119FD74C2F0D3CF3AA52451 +:10A480007F4DCA17C7F23DA87F6255ECF4F3785EA2 +:10A49000C722C9D384FB9D5CE78563C80FD4F01144 +:10A4A00070A7EB0DD4DC9568DFD473D8AEDE07055A +:10A4B00079873801B4AE43F91BA876DA5FF7DFA6D7 +:10A4C0006A3FC86887E3BA10B1A18B1C4D3A4E0BA6 +:10A4D000AA21A2E03E870A3E8C8A64E7D318C2888C +:10A4E00077AF45BFAFEDB5633700E36B61F53588F6 +:10A4F000A2FC9A66F7C35AD46DD5F3A605FF1EE0F9 +:10A500003BC8D5644D7A27E441028FEBDB8D3C33A9 +:10A5100079105A1DDA0C71B7EF46D6BB23097E7B42 +:10A52000AB233B77AC1CBFAC86D5AC5ECCA2FFCFD7 +:10A530004EE9DD118C8FC159FC74AC732DF3CF60E3 +:10A54000A7CAE8406713C3EB0DBA672D53F396D142 +:10A55000FD8AEBF4FE74149A916647F74331E6CF17 +:10A56000471D7ABCBFD1297189F36DAF0247F863EB +:10A57000C870842BBC0A9E73886B68E9DD3F3CA0E1 +:10A58000FAD6583C2424E48DB98EC99F37E227B40B +:10A59000B499D979BE916FA23C392F6AF316CC6079 +:10A5A0004FD9E9E477A2396EE6CB64FE70A002369B +:10A5B0007E279D7A9D3C1EEDAFA77B48BE5E329400 +:10A5C0009570AE4F8D73B9A84053A3A826F815FD1A +:10A5D0003E508926AE983DCFCCF506D7C162C0C6A5 +:10A5E0007260A395E5BDA34E2E684EF0A366D48F8E +:10A5F00041A75E3F8E1541417345BA3CECD4FBC781 +:10A600007016B4FC26031E5A4060F5E218A7CF333B +:10A61000FD372597D83A5A40EF335D8ACA1553DD86 +:10A62000C03CEFF290BD778237090F1EFC0BD7A616 +:10A63000DB67838D90457EC43A13E2D2EDB5C3B19A +:10A6400051EA7FE8F36FAC63D9F485A3F11BC19B9A +:10A65000A8972FE8EBDAAB93F3E68BE6456EC0C81C +:10A660008B2CC8D2F3622BDF83E7BE57CD4704762D +:10A670000F85796FF6F4F9016B66AEFF0329F53F9C +:10A68000953A722634A804280FB8F677D7329CD9A9 +:10A69000FD561D58BC3F8878BF6255CB0288AF0479 +:10A6A000FA7BA3ADD61A14B09E40B7E54ECCB403E6 +:10A6B000E3C8310FDABC19FCF8A6B56145407F0745 +:10A6C000F3A49FEA4793D61A71911AE718B7515825 +:10A6D000497E56987CB63845FC589DBBE705865F99 +:10A6E000F02AC74DF6518514FF7894D56C29E6CF32 +:10A6F0008580B79F90EE970288B0F1428872F49EF1 +:10A700002F8218E31FC5CE99A81B14464B40E5497C +:10A710005E0A1AE3CB20C8E83288305A0E51265F11 +:10A720000E31C6131294A72BA2C0FA854A50041A00 +:10A73000AF0255A079AB4063FC1A08325A03DAE540 +:10A740009B78CE8175BB2BE9DE7E362D5EE65647C3 +:10A750007D01D0FB3C850FDA30AE7B0B7E2C67D2BF +:10A760001BF169DF0B24D431DB22FDF799E9FCB63C +:10A77000D7C8BFA316AF97EEA3A37922210A47DD5E +:10A780007ADEA6CEDFD5A1CFB75A3499FA6A8BD13B +:10A79000D7ECBD7BE1527009F64F76AD85D6E9C99D +:10A7A000B702F56966BFB52F70EED221FBFFAE4F41 +:10A7B000FD50540FB3B84C95CFF177C0F3F4B58684 +:10A7C000FA7DF528AD534856E3B92515E4600DF13F +:10A7D000618EFC6CFF3EF2052C8E0E913C47030F00 +:10A7E000C9B1FF7F39C07E5F18667A5D1897A1CA2C +:10A7F000295ED30CFEF48239F5EFB0D5BF9DF4CCC1 +:10A80000775D7F403BCBD657411113DF75ADF8AE76 +:10A810007B9CD93F4472D9CC6BC91E1472D2F31AF7 +:10A82000942227C5DB64FECC119FDB749FE23BF7CB +:10A83000E2C1A895EA427BF47D2BF537EDAFBF6509 +:10A84000A57B7587F17EF6197105075631DEAAF1F1 +:10A8500057C98EF1E19221CA8FF161DC19ED19EF30 +:10A86000760F9111E317FEA1DFBF28676F7038A440 +:10A87000BF77701D693525976E276C55D51AF6CEB2 +:10A8800085097A6F99F7F1F8856FE8F7F1B060DC28 +:10A89000C7D1CF856AE2CB148ADB5D0F36C08BA4AB +:10A8A000B741F29C43BD5DA73E5FBE33218E53EF9F +:10A8B000675E917B7FC7EE11AB87FA5713C7345C95 +:10A8C000E4E47B973EF4EE33CF7BEBE572E0E9F70F +:10A8D00003ECEF840C7DA349C561DBDFC97F772CD6 +:10A8E000708973645837C5DFA9FEEC0F783FA578EF +:10A8F000E586FFC8E220CDBF07F2E6E4DFB9CEEB84 +:10A9000033F2040FCA519C39A335ACCF15548FAA2A +:10A9100022FECEC63024FECE53B5BDE11EC5A553E2 +:10A920009439AA0F4EC5880F6565D27E1346DD495E +:10A93000DDEFBF2C774017E017000000000000009B +:10A940000000004000000000000000000000004087 +:10A9500000000000000000000000002800000000CF +:10A9600000000000000000100000000000000000D7 +:10A970000000004000000000000000000000001087 +:10A9800000000000000000000000000800000000BF +:10A9900000000000000000000000000000000000B7 +:10A9A0000000003D00000000000000000000003C2E +:10A9B0000000000000000000000000000000000097 +:10A9C000000000000000000800000000000000007F +:10A9D0000000000000000000000000000000000C6B +:10A9E00000000000000000000000000E0000000059 +:10A9F0000000000000000004000000000000000053 +:10AA00000000001800000000000000000000001C12 +:10AA100000000000000000000000001C000000001A +:10AA20000000000000000013000000000000000013 +:10AA30000000003E000000000000000000000001D7 +:10AA40000000000000000000000000020000000004 +:10AA500000000000000000010000000000000000F5 +:10AA60000000001000000000000000000000005086 +:10AA700000000000000000000000000000000000D6 +:10AA800000000000000000030000000000000000C3 +:10AA9000000000AB00000000000000000000000803 +:10AAA00000000000000000000000C00000100000D6 +:10AAB000000000080000C0080010000000000002B4 +:10AAC0000000C000001000000000001000009C0802 +:10AAD00000040000000000040000C080001000001E +:10AAE000000000040000C088001000000000000208 +:10AAF0000000C0800010000000000010000093382B +:10AB0000000100040000000100009340000000006C +:10AB10000000000200009348000000000000000850 +:10AB20000000934C00000000000000020000935061 +:10AB3000000000000000000800009698004000009F +:10AB40000000004000009358008000000000004812 +:10AB500000009458004000000000000800009468C5 +:10AB6000004000000000001800063010002800001F +:10AB700000000028000099500008000000000001BB +:10AB800000009951000800000000000100009952E7 +:10AB90000008000000000001000020080010000074 +:10ABA000000000100000200000000000000000086D +:10ABB00000009BB800000000000000080000000139 +:10ABC0000000000000000000000000020000000083 +:10ABD0000000000000000003000000000000000072 +:10ABE000000000040000000000000000000000055C +:10ABF000000000000000000000000006000000004F +:10AC0000000000000000000700000000000000003D +:10AC10000000000800000000000000000000000923 +:10AC200000000000000000000000000A000000001A +:10AC3000000000000000000B000000000000000009 +:10AC40000000000C000000000000000000000001F7 +:10AC500000000000000000000000000900000000EB +:10AC600000000000000000020000000000000000E2 +:10AC70000000C4C000000000000000200000C4E686 +:10AC80000000000000000001000060000020000043 +:10AC90000000002000007300000800000000000811 +:10ACA00000009BF0000000000000000100009B90ED +:10ACB000000000000000000800009B93000000005E +:10ACC0000000000100009B91000000000000000156 +:10ACD00000009B96000000000000000100009B9710 +:10ACE00000000000000000008000000000000000E4 +:10ACF00000000000800000000000000000000000D4 +:10AD00000000000000000000000000000000000043 +:10AD10000000000000000000000000000000000033 +:10AD20000000000000000000000000000000000023 +:10AD3000000000000000000000000000000600000D +:10AD4000000000000000002000009B9800000000B0 +:10AD50000000000100009BD8000000000000000877 +:10AD600000000053000000000000000000009BE015 +:10AD7000000000000000000200009BE40000000052 +:10AD80000000000100009BE5000000000000000141 +:10AD900000000009000000000000000000000001A9 +:10ADA000000000000000000000000044000000005F +:10ADB0000000000000000001000000000000000092 +:10ADC00000000050000000000000000000000089AA +:10ADD00000000000000000008000000000000000F3 +:10ADE0000000000000000000000000000000000063 +:10ADF000000016C800000000000000080000200845 +:10AE00000010000000000010000020000000000002 +:10AE100000000008000017E000080000000000012A +:10AE2000000017E10008000000000001000017E228 +:10AE30000008000000000001000620780038000033 +:10AE400000000038000016F00000000000000002C2 +:10AE5000000016F200000000000000020000A04008 +:10AE60000000000000000020800000000000000042 +:10AE7000000000000000E0000020000000000020B2 +:10AE80000000F300000800000000000800001708A0 +:10AE900000000000000000D80000174F0000000074 +:10AEA0000000000100001727000000000000000162 +:10AEB0008000000000000000000000008000000092 +:10AEC0000000000000000000000000000000000082 +:10AED0000000000000000000000000000000000072 +:10AEE0000000000000000000000000000000000062 +:10AEF0000000000000000000000000000000000052 +:10AF000000000000000017880000000000000001A1 +:10AF1000000017C8000000000000000800000051F9 +:10AF20000000000000000000000017B0000000005A +:10AF300000000004000017B400000000000000043E +:10AF4000000017B80000000000000004000017BC5B +:10AF50000000000000000008000017A8000000002A +:10AF600000000008000017D80000000000000002E8 +:10AF70000006000000400000000000400000C0008B +:10AF800000400000000000400000C02E0040000013 +:10AF9000000000010000C0000040000200000001AD +:10AFA0000000C00100400002000000000000E200BC +:10AFB00000200000000000200000E2040002000861 +:10AFC00000200002800000000000000000000000DF +:10AFD0000000E20000080020000000040000F5006E +:10AFE00000280000000000280000F64000100000CB +:10AFF000000000100000F64A0010000000000001F0 +:10B000000000F6C000200000000000200000F6C094 +:10B0100000020020000000020000F30000400000D9 +:10B020000000004000002008001000000000001098 +:10B03000000020000000000000000008000011A82F +:10B040000008000000000001000011A90008000035 +:10B0500000000001000011AA00080000000000012B +:10B060000000400000200004000000100000590013 +:10B0700000300018000000100000590800300018CF +:10B08000000000020000570000080000000000015E +:10B0900000005701000800000000000100001158E6 +:10B0A000000000000000000100001160000000002E +:10B0B00000000010000011AC0008000000000004B7 +:10B0C00000004000002000000000002000005300AD +:10B0D0000010000000000010000000000000000050 +:10B0E0000000000000000000000000000000000060 +:10B0F0000000000000000000000000000000000050 +:10B1000000000000000000000000147000000000BB +:10B1100000000001000014B0000000000000000862 +:10B120000000005000000000000000000000147843 +:10B1300000000000000000040000147C000000007B +:10B140000000000400001480000000000000000463 +:10B1500000001484000000000000000400001488B7 +:10B16000000000000000000800002AF0008000003D +:10B17000000000800000000100000000000000004E +:10B180000000200800100000000000100000200057 +:10B19000000000000000000800002C700008000003 +:10B1A0000000000100002C710008000000000001F8 +:10B1B00000002C720008000000000001000041584F +:10B1C000003800000000003880000000000000008F +:10B1D0000000000000002C440008000000000002F5 +:10B1E00000002C46000800000000000200002C5463 +:10B1F000001000000000000400002EB0000000005D +:10B20000000000200000600000200000000000207E +:10B2100000007300000800000000000800000000AB +:10B22000000000000000000000000000000000001E +:10B23000000000000000000000000000000000000E +:10B2400000000000000000000000000000002F5877 +:10B25000000000000000000100002F980000000026 +:10B260000000000800000050000000000000000086 +:10B2700000002F80000000000000000400002F8468 +:10B28000000000000000000400002F880000000003 +:10B290000000000400002F8C0000000000000008E7 +:10B2A00000002FA800000000000000028000000045 +:10B2B000000000000000000080000000000000000E +:10B2C00000000000800000000000000000000000FE +:10B2D00000003128000000000000000800062A20BD +:10B2E00026000040000000080000A0000000000050 +:10B2F00000002000000040C100000000000000012C +:10B30000000040F00000000000000002800000008B +:10B3100000000000000000000000600000200000AD +:10B3200000000008000040000008000000000001CC +:10B330000000400100080000000000010000404043 +:10B340000008000400000002000040600008000443 +:10B35000000000040000408000080000000000041D +:10B36000000040000008000000000004000040044D +:10B370000008000000000004000040400000000041 +:10B380000000000800004048000000000000000825 +:10B39000000080000000000000000010000050408D +:10B3A0000001000400000001000050000000000047 +:10B3B0000000002000005008001000000000000401 +:10B3C0000000500C0010000000000001000052C7F7 +:10B3D0000000000000000001000052C60000000054 +:10B3E00000000001000030000040002000000004C8 +:10B3F000000030040040002000000004000030087D +:10B4000000400020000000020000300A0040002040 +:10B41000000000020000300C00400020000000018D +:10B420000000300D00400020000000010000300E40 +:10B43000004000200000000100003010004000200B +:10B440000000000400003014004000200000000450 +:10B450000000301800400020000000040000301CF4 +:10B4600000400020000000040000C0000100008037 +:10B47000000800040000C00401000080000800046F +:10B480000000000A00000000000000000000C0688A +:10B4900001000080000000010000C0690100008080 +:10B4A000000000010000C06C0100008000000002EC +:10B4B0000000C06E01000080000000020000C070AB +:10B4C00001000080000000040000C0740100008042 +:10B4D000000000040000C0660100008000000002BF +:10B4E0000000C06401000080000000010000C06096 +:10B4F00001000080000000020000C0620100008026 +:10B50000000000020000C0500100008000000004A4 +:10B510000000C05401000080000000040000C0587A +:10B5200001000080000000040000C05C01000080F9 +:10B53000000000040000C07C010000800000000149 +:10B540000000C07D01000080000000010000101814 +:10B550000010000000000004000010900010000027 +:10B56000000000040000109800100000000000041B +:10B570000000111000000000000000020000111285 +:10B580000000000000000002000011140000000094 +:10B590000000000200001116000000000000000280 +:10B5A000000060400008000000000002000060424F +:10B5B00000080000000000020000604400080000D5 +:10B5C00000000002000060460008000000000002C9 +:10B5D000000060800008000000000008000060001B +:10B5E00000080000000000020000600200080000E7 +:10B5F00000000001000060040008000000000002DC +:10B60000000060C0000800000000000800006100A9 +:10B6100000080000000000040000610400080000B1 +:10B62000000000010000614000080000000000026E +:10B6300000006144000800000000000200006142B8 +:10B640000008000000000002000061800008000007 +:10B6500000000004000030000008000000000002AC +:10B66000000030020008000000000001000030046B +:10B670000008000000000002000030400008000048 +:10B68000000000020000304400080000000000023A +:10B690000000304600080000000000020000366094 +:10B6A00000080000000000080000308000080000D2 +:10B6B00000000002000030840008000000000002CA +:10B6C000000036A0000800000000000800008040D4 +:10B6D0000008000000000001000080410008000098 +:10B6E000000000010000804200080000000000018E +:10B6F00000008043000800000000000100008000FE +:10B7000000080000000000020000800200080000A5 +:10B71000000000010000800400080000000000029A +:10B72000000080C00008000000000002000080C28D +:10B730000008000000000002000080C400080000B3 +:10B7400000000002000080800008000000000001EE +:10B7500000008081000800000000000100008082DD +:10B7600000080000000000010000808300080000C5 +:10B7700000000001000080840008000000000001BB +:10B7800000008085000800000000000100008086A5 +:10B790000008000000000001000060000008000038 +:10B7A000000000020000600200080000000000012C +:10B7B0000000600400080000000000020000604279 +:10B7C00000C00018000000020000604000C0001827 +:10B7D000000000020000604C00C0001800000008DB +:10B7E0000000604400C0001800000008000060571E +:10B7F00000C00018000000010000605400C00018E4 +:10B80000000000020000605600C0001800000001A7 +:10B81000000066400008000000000008000066808C +:10B820000008000000000008000066C000080000DA +:10B83000000000080000DA8200180000000000028A +:10B840000000DBA000000000000000000000E0009D +:10B8500000000000000000040000D1000000000013 +:10B86000000000040000D1040000000000000004FB +:10B870000000D10800000000000000040000D10C0E +:10B8800000000000000000040000D11000000000D3 +:10B89000000000040000D1140000000000000004BB +:10B8A0000000D11800000000000000040000D100DA +:10B8B0000000000000000020000092800000000056 +:10B8C000000000040000928000000000000000283A +:10B8D0000000805000A8000000000001000080541B +:10B8E00000A800000000000100008000000000002F +:10B8F0000000005000008050000000000000001018 +:10B900000000960000000000000000040000940009 +:10B91000000000000000000400009404000000008B +:10B920000000000400009408000000000000000473 +:10B930000000940C000000000000000400009410BF +:10B94000000000000000000400009414000000004B +:10B950000000000400009418000000000000000433 +:10B96000000094000000000000000040000094204F +:10B97000000000000000000400009424000000000B +:10B9800000000004000094280000000000000004F3 +:10B990000000941C0000000000000004000094302F +:10B9A00000000000000000040000942C00000000D3 +:10B9B00000000004000094340000000000000004B7 +:10B9C000000092840000000000000004000092804B +:10B9D0000000000000000004000092900000000041 +:10B9E00000000004000092A4000000000000000419 +:10B9F0000000943800000000000000040000943CA7 +:10BA000000000000000000040000B98800000000F1 +:10BA1000000000000000D000000000000000000452 +:10BA20000000B10000000000000000040000B104AC +:10BA300000000000000000040000B1080000000049 +:10BA4000000000040000B100000000000000001031 +:10BA50000000BCB000000000000000040000BCB406 +:10BA600000000000000000040000BCB00000000066 +:10BA7000000000480000D85800000000000000044A +:10BA80000000D85000000000000000040000D8545E +:10BA900000000000000000040000D85C000000006E +:10BAA000000000040000D85000000000000000105A +:10BAB0000000D84000000000000000040000D8444E +:10BAC00000000000000000040000D840000000005A +:10BAD000000000080000D4C80000000000000008BA +:10BAE0000000D4D80000000000000080000000101A +:10BAF00000000000000000000000D4D8000000009A +:10BB0000000000080000000007081100000000000D +:00000001FF --- linux-3.13.0.orig/firmware/bnx2x/bnx2x-e1h-7.8.17.0.fw.ihex +++ linux-3.13.0/firmware/bnx2x/bnx2x-e1h-7.8.17.0.fw.ihex @@ -0,0 +1,10748 @@ +:10000000000021E800000068000005D80000225828 +:10001000000036E4000028380000007000005F2077 +:100020000000860400005F98000000A00000E5A02A +:1000300000009C8C0000E64800000088000182D887 +:1000400000004344000183680000008C0001C6B03A +:100050000000C6780001C740000011C400028DC036 +:100060000000000400029F88020600DC000000017E +:100070000306100002000000010600D80000000086 +:100080000306020000030200020600DC000000007C +:10009000010600B800000000010600C800000000D2 +:1000A0000206016C00000000010600BC0000000018 +:1000B000010600CC000000000206017000000000F4 +:1000C000020D004400000032030D004C0004020346 +:1000D000040D005C00000004030D008C00110207F9 +:1000E000020D015C00000001030D01640002021812 +:1000F000020D020400000001030D020C0003021AAD +:10010000030D02200002021D040D028000000012F7 +:10011000030D03000018021F040D03600000000C13 +:10012000040D400000000A00030D0004000F023718 +:10013000020D01140000000D020D01180000002D39 +:10014000020D01140000001D020D01180000003D09 +:10015000020D01140000004D020D01180000006D99 +:10016000020D01140000005D020D01180000007D69 +:10017000031010000003024602101050000000019E +:10018000071011000010024908101140000000087B +:100190000710116000100259081011A0000000188B +:1001A000071018000200026904104C000000010052 +:1001B00002104028000000100210404400003FFFE1 +:1001C0000210405800280000021040840084924A27 +:1001D0000210405800000000030C200800030469CE +:1001E000030C201C0004046C030C20380011047064 +:1001F000040C207C0000004F030C21B80011048186 +:10020000040C21FC0000000F030C223800040492AF +:10021000010C224800000000010C224C00000000EC +:10022000010C225000000000010C225400000000CC +:10023000010C225800000000010C225C00000000AC +:10024000010C226000000000010C2264000000008C +:10025000010C226800000000010C226C000000006C +:10026000010C227000000000010C2274000000004C +:10027000010C227800000000010C227C000000002C +:100280000A00000100000001020C2000000003E849 +:100290000A00000100000002020C20000000000A19 +:1002A0000A00000100000004020C20000000000110 +:1002B0000520040000860000062007800010049638 +:1002C000042200000000400004232400000000403D +:1002D00003221250001004980422B14000000020B4 +:1002E0000422C800000000060322C818000404A865 +:1002F0000422C8280000000C0322C858000404ACE3 +:100300000422C8680000000C0322C898000404B04E +:100310000422C8A80000000C0322C8D8000404B4BA +:100320000422C8E80000000C0322C918000404B825 +:100330000422C9280000000C0322C958000404BC90 +:100340000422C9680000000C0322C998000404C0FC +:100350000422C9A80000000C0322C9D8000404C468 +:100360000422C9E80000000C0322CA18000404C8D3 +:100370000422CA280000000C0322CA58000404CC3E +:100380000422CA680000000C0322CA98000404D0AA +:100390000422CAA80000000C0322CAD8000404D416 +:1003A0000422CAE80000000C0322CB18000404D881 +:1003B0000422CB280000000C0322CB58000404DCEC +:1003C0000422CB680000000C0322CB98000404E058 +:1003D0000422CBA80000000C0322CBD8000404E4C4 +:1003E0000422CBE80000000C0322CC18000404E82F +:1003F0000422CC280000000C0322CC58000404EC9A +:100400000422CC680000000C0322CC98000404F005 +:100410000422CCA80000000C0322CCD8000404F471 +:100420000422CCE80000000C0322CD18000404F8DC +:100430000422CD280000000C0322CD58000404FC47 +:100440000422CD680000000C0322CD9800040500B2 +:100450000422CDA80000000C0322CDD8000405041E +:100460000422CDE80000000C0322CE180004050889 +:100470000422CE280000000C0322CE580004050CF4 +:100480000422CE680000000C0322CE980004051060 +:100490000422CEA80000000C0322CED800040514CC +:1004A0000422CEE80000000C0322CF180004051837 +:1004B0000422CF280000000C0322CF580004051CA2 +:1004C0000422CF680000000C0322CF98000405200E +:1004D0000422CFA80000000C0322CFD8000405247A +:1004E0000422CFE800000006022380000000001074 +:1004F00002238040000000120223808000000030B0 +:10050000022380C00000000E022383800007A12088 +:10051000022383C0000001F402238BC0000000010D +:100520000A00000200000001022383000007A1204E +:1005300002238340000001F40A00000200000002D0 +:10054000022383000000138802238340000000057B +:100550000A000002000000040223830000000138AA +:10056000022383400000000005240000330A00003D +:100570000524800010350CC306249E706A98052857 +:100580000A000001000000020223148000000000A5 +:100590000A00000100000004022314800000000093 +:1005A0000120000000000000012000040000000005 +:1005B00001200008000000000120000C00000000E5 +:1005C00001200010000000000120001400000000C5 +:1005D00003200020001A052A032000A4000205447D +:1005E000022002240000000002200234000000006B +:1005F0000220024C00000000022002E40000FFFF85 +:100600000820200000000800042211080000000259 +:1006100004221290000000060422340000000002B0 +:10062000042260400000003004228C000000001012 +:100630000422111000000002042212A8000000068B +:10064000042234080000000204226100000000308F +:1006500004228C4000000010042211180000000247 +:10066000042212C000000006042234100000000220 +:10067000042261C00000003004228C8000000010C1 +:100680000422112000000002042212D800000006FB +:1006900004223418000000020422628000000030AE +:1006A00004228CC000000010042211280000000267 +:1006B000042212F000000006042234200000000290 +:1006C000042263400000003004228D00000000106E +:1006D000042211300000000204221308000000066A +:1006E00004223428000000020422640000000030CC +:1006F00004228D4000000010042211380000000286 +:1007000004221320000000060422343000000002FE +:10071000042264C00000003004228D80000000101C +:1007200004221140000000020422133800000006D9 +:1007300004223438000000020422658000000030EA +:1007400004228DC00000001004102400000000E00E +:100750000310201C00020546021020C00000000209 +:1007600003102004000205480217000800000002E0 +:100770000217002C00000003031700380002054A8E +:10078000031700480005054C0317006000050551DC +:100790000317007800020556021700040000000F3E +:1007A0000210800000001080041080400000000251 +:1007B000021080AC00000000021080380000001021 +:1007C00002108100000000000410812000000002DF +:1007D00002108008000002B5021080100000000026 +:1007E000021081080001FFFF041082000000004A8F +:1007F00004108140000000020210800000001A80F6 +:100800000410900000000024041091200000004A11 +:10081000041093700000004A041095C00000004AC4 +:1008200002108004000010800410804800000002C4 +:10083000021080B0000000010210803C0000001097 +:100840000210810400000000041081280000000252 +:100850000210800C000002B502108014000000009D +:100860000210810C0001FFFF041084000000004A08 +:1008700004108148000000020210800400001A8069 +:100880000410909000000024041092480000004AD8 +:10089000041094980000004A041096E80000004AF2 +:1008A0000210800000001080041080400000000250 +:1008B000021080AC0000000202108038000000101E +:1008C00002108100000000000410812000000002DE +:1008D00002108008000002B5021080100000000025 +:1008E000021081080001FFFF041082000000004A8E +:1008F00004108140000000020210800000001A80F5 +:100900000410900000000024041091200000004A10 +:10091000041093700000004A041095C00000004AC3 +:1009200002108004000010800410804800000002C3 +:10093000021080B0000000030210803C0000001094 +:100940000210810400000000041081280000000251 +:100950000210800C000002B502108014000000009C +:100960000210810C0001FFFF041084000000004A07 +:1009700004108148000000020210800400001A8068 +:100980000410909000000024041092480000004AD7 +:10099000041094980000004A041096E80000004AF1 +:1009A000021080000000108004108040000000024F +:1009B000021080AC0000000402108038000000101B +:1009C00002108100000000000410812000000002DD +:1009D00002108008000002B5021080100000000024 +:1009E000021081080001FFFF041082000000004A8D +:1009F00004108140000000020210800000001A80F4 +:100A00000410900000000024041091200000004A0F +:100A1000041093700000004A041095C00000004AC2 +:100A200002108004000010800410804800000002C2 +:100A3000021080B0000000050210803C0000001091 +:100A40000210810400000000041081280000000250 +:100A50000210800C000002B502108014000000009B +:100A60000210810C0001FFFF041084000000004A06 +:100A700004108148000000020210800400001A8067 +:100A80000410909000000024041092480000004AD6 +:100A9000041094980000004A041096E80000004AF0 +:100AA000021080000000108004108040000000024E +:100AB000021080AC00000006021080380000001018 +:100AC00002108100000000000410812000000002DC +:100AD00002108008000002B5021080100000000023 +:100AE000021081080001FFFF041082000000004A8C +:100AF00004108140000000020210800000001A80F3 +:100B00000410900000000024041091200000004A0E +:100B1000041093700000004A041095C00000004AC1 +:100B200002108004000010800410804800000002C1 +:100B3000021080B0000000070210803C000000108E +:100B4000021081040000000004108128000000024F +:100B50000210800C000002B502108014000000009A +:100B60000210810C0001FFFF041084000000004A05 +:100B700004108148000000020210800400001A8066 +:100B80000410909000000024041092480000004AD5 +:100B9000041094980000004A041096E80000004AEF +:100BA0000200A468000B01C80300A29400040558C9 +:100BB0000A000001000000800200A5F8000000000B +:100BC0000A000001000001000200A5F80000000179 +:100BD0000200A270000000000200A27400000000E9 +:100BE0000200A270000000000200A27400000000D9 +:100BF0000200A270000000000200A27400000000C9 +:100C00000200A270000000000200A27400000000B8 +:100C1000030100B40002055C020100DC00000001D9 +:100C2000030101000002055E0201007C00300000AB +:100C300002010084000000280201008C0000000076 +:100C4000020101300000000402010328000000003E +:100C50000201055400000030020160580000FFFF4F +:100C600002016070000000070201608000000001C6 +:100C7000020100C400000001020100CC00000001DC +:100C8000020100F800000001020100F00000000174 +:100C900002010080003000000201008800000028EE +:100CA0000201009000000000020101340000000475 +:100CB0000201032C00000000020105640000003066 +:100CC0000201605C0000FFFF020160740000000789 +:100CD0000201608400000001020100C80000000160 +:100CE000020100D000000001020100FC0000000130 +:100CF000020100F4000000010401013800000011AD +:100D00000401017C00000011040101380000001101 +:100D10000401017C000000110401013800000011F1 +:100D20000401017C000000110401013800000011E1 +:100D30000401017C00000011021400000000000109 +:100D40000214000C000000010314004000020560C2 +:100D50000214000C0000000002140000000000005B +:100D60000214006C000000000214000400000001E6 +:100D70000214003000000001021400040000000012 +:100D80000214005C000000000214000800000001D2 +:100D900002140034000000010214000800000000EA +:100DA0000214006000000000030400040012056249 +:100DB00002040054000000430204005C000000062E +:100DC00002040070000000040304007800040574AD +:100DD00004040088000000050304009C000305785B +:100DE000040400A800000004030400B80005057B0B +:100DF000040400CC00000004030400DC00040580AF +:100E0000040400EC000000040104012400000000C0 +:100E100001040128000000000104012C0000000072 +:100E20000104013000000000020401340000000F42 +:100E3000020401D000008906021205B00000000182 +:100E400003120490002205840312066C000205A61A +:100E500002120388000000640212039000000008E0 +:100E60000312039C000305A8031203BC000305AB97 +:100E7000021203D0000000000212036C0000000107 +:100E8000021203680000003F031201BC003C05AEE3 +:100E9000031202B0000205EA03120324000205EC6B +:100EA000021205B400000001021201B000000001AE +:100EB00007103800000505EE07103820000505F37F +:100EC00007103C00000505F803168030000805FDFA +:100ED000021680540000000203168060000506051B +:100EE0000416807400000007031680900002060AB2 +:100EF0000316809C0005060C041680B00000000755 +:100F0000031680CC00080611021680F000000007CE +:100F1000041680F40000000C031681240004061956 +:100F2000041681340000000C031681640032061D93 +:100F3000031682340007064F041682500000000496 +:100F4000031682600002065604168268000000083C +:100F50000316828800080658041682A80000000ABA +:100F600002168804000000040316880C00100660B6 +:100F70000316E000001006700416E40C0000000CDC +:100F80000316E43C000406800416E44C0000000C48 +:100F90000316E47C002E06840416E53400000004E9 +:100FA0000316E544000206B20416E54C00000008F2 +:100FB0000316E56C000606B40316E6BC000806BA84 +:100FC000021680EC000000FF03040408001406C2AF +:100FD000020404CC0000000103050044000206D610 +:100FE00003050050000406D804050060000000045A +:100FF00003050090001306DC020501140000000147 +:101000000305011C000206EF0205020400000001B6 +:101010000305020C000206F10305021C000306F39F +:10102000040502400000000A03050280002006F6C5 +:101030000405400000000D00030500040010071621 +:10104000020500E00000000E020500E40000002E92 +:10105000020500E00000001E020500E40000003E62 +:10106000020500E00000004E020500E40000006EF2 +:10107000020500E00000005E020500E40000007EC2 +:101080000416402400000002031640300003072627 +:101090000216404400000020021640700000001CB0 +:1010A0000216420800000001021642100000000172 +:1010B0000216422000000001021642280000000132 +:1010C0000216423000000001021642380000000102 +:1010D00002164260000000020A0000010000000148 +:1010E0000216401C0003D0900A000001000000021C +:1010F0000216401C000009C40A00000100000004A0 +:101100000216401C0000009C021640000000000176 +:10111000021640D80000000103164008000307290A +:101120000216424000000000021642480000000083 +:101130000816427000000002021642500000000033 +:10114000021642580000000008164280000000020B +:10115000030420080004072C0304201C00040730AB +:1011600002042038000000200404203C0000001F7E +:10117000020420B800000001040420BC0000005F4D +:101180000304223800040734010422480000000050 +:101190000104224C00000000010422500000000065 +:1011A0000104225400000000010422580000000045 +:1011B0000104225C00000000010422600000000025 +:1011C0000104226400000000010422680000000005 +:1011D0000104226C000000000104227000000000E5 +:1011E00001042274000000000104227800000000C5 +:1011F0000104227C000000000A0000010000000140 +:1012000002042000000003E80A00000100000002C0 +:10121000020420000000000A0A000001000000048F +:10122000020420000000000105180400006F000007 +:101230000618076000140738041A00000000400078 +:10124000041B240000000040031A1EC80002073AD5 +:10125000031A40400004073C041A405000000006F6 +:10126000031A406800020740031A52C000020742F6 +:10127000031A800003F90744041A8FE400000007F2 +:10128000031AA08000100B3D021B800000000034F8 +:10129000021B804000000018021B80800000000C30 +:1012A000021B80C000000020021B83800007A120D9 +:1012B000021B83C0000001F4021B8BC00000000170 +:1012C0000A00000200000001021B83000007A120A9 +:1012D000021B8340000001F40A000002000000022B +:1012E000021B830000001388021B834000000005DE +:1012F0000A00000200000004021B83000000013805 +:10130000021B834000000000051C00002FA6000007 +:10131000051C800033760BEA051D000022E118C889 +:10132000061D510055E00B4D0A00000100000002AF +:10133000021B1480000000000A00000100000004ED +:10134000021B1480000000000118000000000000D3 +:10135000011800040000000001180008000000004F +:101360000118000C0000000001180010000000002F +:10137000011800140000000003180020001A0B4F91 +:10138000031800A400020B690218022400000000E8 +:1013900002180234000000000218024C0000000095 +:1013A000021802E4000000FF08181000000004000A +:1013B000041A300000000010041A308000000010F1 +:1013C000041A310000000010041A318000000010DF +:1013D000041A330000000012041A339000000012B7 +:1013E000041A342000000070041A90000000000667 +:1013F000041A304000000010041A30C00000001031 +:10140000041A314000000010041A31C0000000101E +:10141000041A334800000012041A33D800000012E6 +:10142000041A35E000000070041A9018000000064D +:10143000031A400000020B6B041A50000000000267 +:10144000041A508000000012031A614000020B6D64 +:10145000041A903000000002041AA00000000002EC +:10146000031A400800020B6F041A5010000000021B +:10147000041A50C800000012031A614800020B71E0 +:10148000041A903800000002041AA00800000002AC +:10149000031A401000020B73041A502000000002CF +:1014A000041A511000000012031A615000020B755B +:1014B000041A904000000002041AA010000000026C +:1014C000031A401800020B77041A50300000000283 +:1014D000041A515800000012031A615800020B79D7 +:1014E000041A904800000002041AA018000000022C +:1014F000031A402000020B7B041A50400000000237 +:10150000041A51A000000012031A616000020B7D52 +:10151000041A905000000002041AA02000000002EB +:10152000031A402800020B7F041A505000000002EA +:10153000041A51E800000012031A616800020B81CE +:10154000041A905800000002041AA02800000002AB +:10155000031A403000020B83041A5060000000029E +:10156000041A523000000012031A617000020B8549 +:10157000041A906000000002041AA030000000026B +:10158000031A403800020B87041A50700000000252 +:10159000041A527800000012031A617800020B89C5 +:1015A000041A906800000002041AA038000000022B +:1015B000020E004C00000032030E005400040B8B9E +:1015C000040E006400000004030E009400130B8F4F +:1015D000020E014400000001030E014C00020BA2A8 +:1015E000020E020400000001030E020C00020BA414 +:1015F000030E021C00040BA6030E0280001B0BAAA4 +:10160000040E02EC00000017040E20000000080089 +:10161000030E000400110BC5020E01100000000FA4 +:10162000020E01140000002F020E01100000001F26 +:10163000020E01140000003F020E01100000004FD6 +:10164000020E01140000006F020E01100000005F86 +:10165000020E01140000007F020C100000000028A0 +:10166000030C400800040BD6030C401C00040BDAEA +:10167000030C403800050BDE040C404C0000005BFE +:10168000030C41B800050BE3040C41CC0000001B27 +:10169000030C423800040BE8010C42480000000033 +:1016A000010C424C00000000010C42500000000000 +:1016B000010C425400000000010C425800000000E0 +:1016C000010C425C00000000010C426000000000C0 +:1016D000010C426400000000010C426800000000A0 +:1016E000010C426C00000000010C42700000000080 +:1016F000010C427400000000010C42780000000060 +:10170000010C427C00000000010C4280000000003F +:101710000A00000100000001020C4000000003E884 +:101720000A00000100000002020C40000000000A54 +:101730000A00000100000004020C4000000000014B +:1017400005300400009E00000630076800130BEC13 +:101750000432000000004000043324000000004078 +:1017600004323E800000001003323EC000020BEE47 +:10177000033274C000080BF00332850000100BF830 +:10178000023380000000001A023380400000004E47 +:101790000233808000000010023380C0000000206F +:1017A000023383800007A120023383C0000001F4CC +:1017B00002338BC0000000010A000002000000019B +:1017C000023383000007A12002338340000001F4AC +:1017D0000A000002000000020233830000001388A8 +:1017E00002338340000000050A00000200000004EC +:1017F0000233830000000138023383400000000000 +:1018000005340000363E00000534800030F20D90B3 +:1018100005350000355719CD06357A5050B60C08FD +:101820000A000001000000020233148000000000E2 +:101830000A000001000000040233148000000000D0 +:101840000130000000000000013000040000000032 +:1018500001300008000000000130000C0000000012 +:1018600001300010000000000130001400000000F2 +:1018700003300020001A0C0A033000A400020C24DC +:101880000230022400000000023002340000000098 +:101890000230024C00000000023002E40000FFFFB2 +:1018A000083020000000080004321000000001C0D1 +:1018B00004321E000000003804323000000001C075 +:1018C00004325000000000200432510000000020CB +:1018D00004325200000000200432530000000020B7 +:1018E00004325400000000200432550000000020A3 +:1018F000043256000000002004325700000000208F +:10190000043258000000002004325900000000207A +:1019100004325A000000002004325B000000002066 +:1019200004325C000000002004325D000000002052 +:1019300004325E000000002004325F00000000203E +:1019400004328450000000020332846000040C263C +:1019500004321700000001C004321EE0000000380D +:1019600004323700000001C0043250800000002023 +:101970000432518000000020043252800000002018 +:101980000432538000000020043254800000002004 +:1019900004325580000000200432568000000020F0 +:1019A00004325780000000200432588000000020DC +:1019B000043259800000002004325A8000000020C8 +:1019C00004325B800000002004325C8000000020B4 +:1019D00004325D800000002004325E8000000020A0 +:1019E00004325F80000000200432845800000002AE +:1019F0000332847000040C2A0432401000000002FC +:101A00000432841000000002043240200000000272 +:101A1000043284180000000204324030000000024A +:101A20000432842000000002043240400000000222 +:101A300004328428000000020432405000000002FA +:101A400004328430000000020432406000000002D2 +:101A500004328438000000020432407000000002AA +:101A60000432844000000002043240800000000282 +:101A700004328448000000020202005800000032D4 +:101A80000302006000040C2E040200700000000439 +:101A9000030200A0000E0C32030200DC00070C4021 +:101AA000020200FC0000000602020120000000000B +:101AB0000202013400000002020201B00000000135 +:101AC0000202020C000000010302021400020C4793 +:101AD00002020404000000010302040C00020C498D +:101AE0000302041C00040C4B0302048000200C4F72 +:101AF0000402050000000012040280000000200023 +:101B00000302000400140C6F02020108000000C868 +:101B10000202011800000002020201C400000000DD +:101B2000020201CC00000000020201D40000000209 +:101B3000020201DC00000002020201E4000000FFDA +:101B4000020201EC000000FF0202010C000000C8CC +:101B50000202011C00000002020201C80000000095 +:101B6000020201D000000000020201D800000002C1 +:101B7000020201E000000002020201E8000000FF92 +:101B8000020201F0000000FF02020108000000C88C +:101B90000202011800000002020201C4000000005D +:101BA000020201CC00000000020201D40000000289 +:101BB000020201DC00000002020201E4000000FF5A +:101BC000020201EC000000FF0202010C000000C84C +:101BD0000202011C00000002020201C80000000015 +:101BE000020201D000000000020201D80000000241 +:101BF000020201E000000002020201E8000000FF12 +:101C0000020201F0000000FF02020108000000C80B +:101C10000202011800000002020201C400000000DC +:101C2000020201CC00000000020201D40000000208 +:101C3000020201DC00000002020201E4000000FFD9 +:101C4000020201EC000000FF0202010C000000C8CB +:101C50000202011C00000002020201C80000000094 +:101C6000020201D000000000020201D800000002C0 +:101C7000020201E000000002020201E8000000FF91 +:101C8000020201F0000000FF02020108000000C88B +:101C90000202011800000002020201C4000000005C +:101CA000020201CC00000000020201D40000000288 +:101CB000020201DC00000002020201E4000000FF59 +:101CC000020201EC000000FF0202010C000000C84B +:101CD0000202011C00000002020201C80000000014 +:101CE000020201D000000000020201D80000000240 +:101CF000020201E000000002020201E8000000FF11 +:101D0000020201F0000000FF02161000000000288F +:101D10000316600800030C830316601C00040C8685 +:101D200003166038000D0C8A0416606C0000001366 +:101D3000031660B800020C97041660C00000003E55 +:101D4000021661B800000001041661BC0000001F0B +:101D50000316623800040C99011662480000000066 +:101D60000116624C000000000116625000000000E5 +:101D700001166254000000000116625800000000C5 +:101D80000116625C000000000116626000000000A5 +:101D90000116626400000000011662680000000085 +:101DA0000116626C00000000011662700000000065 +:101DB0000116627400000000011662780000000045 +:101DC0000116627C000000000A0000010000000112 +:101DD00002166000000003E80A0000010000000293 +:101DE000021660000000000A0A0000010000000462 +:101DF00002166000000000010528040000890000B0 +:101E00000628076800130C9D042A0000000040000B +:101E1000042B240000000040032A300000020C9F25 +:101E2000032A400000100CA1032A840800080CB10A +:101E3000032A93C800040CB9032A96F000020CBDD3 +:101E4000042A96F800000006032A994000020CBFFD +:101E5000022A9A2800000001032AC0C000100CC109 +:101E6000022B800000000000022B804000000018C0 +:101E7000022B80800000000C022B80C00000006656 +:101E8000022B83800007A120022B83C0000001F4F5 +:101E9000022B8BC0000000010A00000200000001BC +:101EA000022B83000007A120022B8340000001F4D5 +:101EB0000A00000200000002022B830000001388C9 +:101EC000022B8340000000050A000002000000040D +:101ED000022B830000000138022B83400000000029 +:101EE0000A00000100000020022A9A2C00000000D5 +:101EF000052C000037260000052C8000399D0DCAF6 +:101F0000052D00003B381C32052D80001A762B0071 +:101F1000062DB6E049240CD10A00000100000002A1 +:101F2000022B1480000000000A00000100000004E1 +:101F3000022B1480000000000128000000000000B7 +:101F40000128000400000000012800080000000033 +:101F50000128000C00000000012800100000000013 +:101F6000012800140000000003280020001A0CD3F0 +:101F7000032800A400020CED022802240000000047 +:101F800002280234000000000228024C0000000079 +:101F9000022802E40000FFFF0828200000000800DB +:101FA000042A500000000002042A50100000000221 +:101FB000042A502000000002042A503000000002D1 +:101FC000042A93E000000020042A94E00000000EA0 +:101FD000032A951800020CEF042A95600000000EF9 +:101FE000032A959800020CF1042A95E00000000EE7 +:101FF000032A961800020CF3042A96600000000ED3 +:10200000032A969800020CF5032A971000020CF799 +:10201000042A500800000002042A501800000002A0 +:10202000042A502800000002042A50380000000250 +:10203000042A946000000020042A95200000000E6D +:10204000032A955800020CF9042A95A00000000EFE +:10205000032A95D800020CFB042A96200000000EEB +:10206000032A965800020CFD042A96A00000000ED8 +:10207000032A96D800020CFF032A971800020D01CC +:10208000042A50480000000E032A972000100D0378 +:10209000042A995000000002042AC0000000000237 +:1020A000042A50800000000E032A976000100D13D0 +:1020B000042A995800000002042AC0080000000207 +:1020C000042A50B80000000E032A97A000100D2328 +:1020D000042A996000000002042AC01000000002D7 +:1020E000042A50F00000000E032A97E000100D3380 +:1020F000042A996800000002042AC01800000002A7 +:10210000042A51280000000E032A982000100D43D5 +:10211000042A997000000002042AC0200000000276 +:10212000042A51600000000E032A986000100D532D +:10213000042A997800000002042AC0280000000246 +:10214000042A51980000000E032A98A000100D6385 +:10215000042A998000000002042AC0300000000216 +:10216000042A51D00000000E032A98E000100D73DD +:10217000042A998800000002042AC03800000002E6 +:102180000400A0000000000C0400A05000000002A9 +:102190000300A0EC00080D830300A18C00080D8B48 +:1021A0000200A45C00000C000200A61C000000035A +:1021B0000300A06C00060D930400A084000000053D +:1021C0000200A0980FE000000400A09C000000079F +:1021D0000300A0B8000D0D990400A22C000000041B +:1021E0000300A10C00060DA60400A12400000005B8 +:1021F0000200A1380FE000000400A13C000000072D +:102200000300A158000D0DAC0400A23C0000000426 +:102210000200A030000000000200A0340000000016 +:102220000200A038000000000200A03C00000000F6 +:102230000200A040000000000200A04400000000D6 +:102240000200A048000000000200A04C00000000B6 +:10225000000000000000000000000000000000007E +:10226000000000000000000000000000000000006E +:10227000000000000000000000000000000000005E +:102280000000000000000005000500080008000B29 +:10229000000000000000000000000000000000003E +:1022A000000000000000000000000000000000002E +:1022B000000B001900000000000000000019001AC7 +:1022C000001A001B001B001C001C001D001D001E2E +:1022D000001E001F001F00200020002100210028F8 +:1022E00000000000000000000000000000000000EE +:1022F00000000000000000000000000000000000DE +:1023000000000000000000000028002E0000000077 +:1023100000000000000000000000000000000000BD +:1023200000000000000000000000000000000000AD +:1023300000000000002E0049000000000000000026 +:10234000000000000000000000000000000000008D +:10235000000000000000000000000000000000007D +:10236000004900B4000000000000000000B400B903 +:1023700000B900BE00BE00C300C300C800C800CD45 +:1023800000CD00D200D200D700D700DC0000000052 +:10239000000000000000000000000000000000003D +:1023A000000000000000000000000000000000002D +:1023B000000000000000000000DC00E00000000061 +:1023C000000000000000000000000000000000000D +:1023D00000000000000000000000000000000000FD +:1023E0000000000000E000E7000000000000000026 +:1023F00000000000000000000000000000000000DD +:1024000000000000000000000000000000000000CC +:1024100000000000000000000000000000E700F7DE +:1024200000F70107010701170117012701270137ED +:1024300001370147014701570157016700000000BC +:10244000000000000000000000000000000000008C +:10245000000000000000000000000000000000007C +:1024600000000000000000000167016D0000000096 +:1024700000000000016D016E016E016F016F0170BF +:1024800001700171017101720172017301730174B4 +:10249000017401750175017801780185018501924A +:1024A0000192019301930194019401950195019684 +:1024B0000196019701970198019801990199019A54 +:1024C000019A01A001A001A401A401A8000000003C +:1024D00000000000000000000000000000000000FC +:1024E00000000000000000000000000000000000EC +:1024F00000000000000000000000000000000000DC +:1025000000000000000000000000000000000000CB +:10251000000000000000000001A801BA0000000057 +:1025200000000000000000000000000000000000AB +:10253000000000000000000000000000000000009B +:102540000000000001BA01C9000000000000000006 +:10255000000000000000000000000000000000007B +:10256000000000000000000000000000000000006B +:1025700001C901CC000000000000000000000000C4 +:10258000000000000000000000000000000000004B +:1025900000000000000000000000000001CC01EC81 +:1025A000000000000000000000000000000000002B +:1025B000000000000000000000000000000000001B +:1025C000000000000000000001EC01EE000000002F +:1025D00000000000000000000000000000000000FB +:1025E00000000000000000000000000000000000EB +:1025F0000000000001EE01FB0000000000000000F0 +:1026000001FB01FC01FC01FD01FD01FE01FE01FFDA +:1026100001FF0200020002010201020202020203A3 +:10262000020302170217021A021A021D000000001C +:10263000000000000000000000000000000000009A +:10264000000000000000000000000000021D023831 +:10265000000000000000000000000000000000007A +:10266000000000000000000000000000000000006A +:1026700000000000000000000238026902690271D7 +:10268000027102790279027F027F02850285028B44 +:10269000028B0291029102970297029D029D02A372 +:1026A00002A302A902A902B6000000000000000077 +:1026B00002B602B702B702B802B802B902B902BA4A +:1026C00002BA02BB02BB02BC02BC02BD02BD02BE1A +:1026D00002BE02BF00000000000000000000000079 +:1026E00000000000000000000000000000000000EA +:1026F00000000000000000000000000002BF02DB3C +:1027000000000000000000000000000000000000C9 +:1027100000000000000000000000000000000000B9 +:10272000000000000000000002DB03080308031D96 +:10273000031D0332033203340334033603360338F4 +:102740000338033A033A033C033C033E033E034091 +:102750000340034203420354000000000000000055 +:102760000354035C035C03640364036C036C037431 +:102770000374037C037C03840384038C038C039421 +:10278000039403950000000000000000000000001A +:102790000000000000000000000000000000000039 +:1027A000000000000000000000000000039503B2DC +:1027B0000000000000000000000000000000000019 +:1027C0000000000000000000000000000000000009 +:1027D000000000000000000003B203E703E703F578 +:1027E00003F50403040304070407040B040B040F9C +:1027F000040F0413041304170417041B041B041F01 +:10280000041F0423042304290429042F042F04355E +:1028100004350436043604370437043804380439E0 +:102820000439043A043A043B043B043C043C043DB0 +:102830000000000000000000000020000000400038 +:1028400000006000000080000000A0000000C00048 +:102850000000E00000010000000120000001400035 +:1028600000016000000180000001A0000001C00024 +:102870000001E00000020000000220000002400011 +:1028800000026000000280000002A0000002C00000 +:102890000002E000000300000003200000034000ED +:1028A00000036000000380000003A0000003C000DC +:1028B0000003E000000400000004200000044000C9 +:1028C00000046000000480000004A0000004C000B8 +:1028D0000004E000000500000005200000054000A5 +:1028E00000056000000580000005A0000005C00094 +:1028F0000005E00000060000000620000006400081 +:1029000000066000000680000006A0000006C0006F +:102910000006E0000007000000072000000740005C +:1029200000076000000780000007A0000007C0004B +:102930000007E00000080000000820000008400038 +:1029400000086000000880000008A0000008C00027 +:102950000008E00000090000000920000009400014 +:1029600000096000000980000009A0000009C00003 +:102970000009E000000A0000000A2000000A4000F0 +:10298000000A6000000A8000000AA000000AC000DF +:10299000000AE000000B0000000B2000000B4000CC +:1029A000000B6000000B8000000BA000000BC000BB +:1029B000000BE000000C0000000C2000000C4000A8 +:1029C000000C6000000C8000000CA000000CC00097 +:1029D000000CE000000D0000000D2000000D400084 +:1029E000000D6000000D8000000DA000000DC00073 +:1029F000000DE000000E0000000E2000000E400060 +:102A0000000E6000000E8000000EA000000EC0004E +:102A1000000EE000000F0000000F2000000F40003B +:102A2000000F6000000F8000000FA000000FC0002A +:102A3000000FE00000100000001020000010400017 +:102A400000106000001080000010A0000010C00006 +:102A50000010E000001100000011200000114000F3 +:102A600000116000001180000011A0000011C000E2 +:102A70000011E000001200000012200000124000CF +:102A800000126000001280000012A0000012C000BE +:102A90000012E000001300000013200000134000AB +:102AA00000136000001380000013A0000013C0009A +:102AB0000013E00000140000001420000014400087 +:102AC00000146000001480000014A0000014C00076 +:102AD0000014E00000150000001520000015400063 +:102AE00000156000001580000015A0000015C00052 +:102AF0000015E0000016000000162000001640003F +:102B000000166000001680000016A0000016C0002D +:102B10000016E0000017000000172000001740001A +:102B200000176000001780000017A0000017C00009 +:102B30000017E000001800000018200000184000F6 +:102B400000186000001880000018A0000018C000E5 +:102B50000018E000001900000019200000194000D2 +:102B600000196000001980000019A0000019C000C1 +:102B70000019E000001A0000001A2000001A4000AE +:102B8000001A6000001A8000001AA000001AC0009D +:102B9000001AE000001B0000001B2000001B40008A +:102BA000001B6000001B8000001BA000001BC00079 +:102BB000001BE000001C0000001C2000001C400066 +:102BC000001C6000001C8000001CA000001CC00055 +:102BD000001CE000001D0000001D2000001D400042 +:102BE000001D6000001D8000001DA000001DC00031 +:102BF000001DE000001E0000001E2000001E40001E +:102C0000001E6000001E8000001EA000001EC0000C +:102C1000001EE000001F0000001F2000001F4000F9 +:102C2000001F6000001F8000001FA000001FC000E8 +:102C3000001FE000002000000020200000204000D5 +:102C400000206000002080000020A0000020C000C4 +:102C50000020E000002100000021200000214000B1 +:102C600000216000002180000021A0000021C000A0 +:102C70000021E0000022000000222000002240008D +:102C800000226000002280000022A0000022C0007C +:102C90000022E00000230000002320000023400069 +:102CA00000236000002380000023A0000023C00058 +:102CB0000023E00000240000002420000024400045 +:102CC00000246000002480000024A0000024C00034 +:102CD0000024E00000250000002520000025400021 +:102CE00000256000002580000025A0000025C00010 +:102CF0000025E000002600000026200000264000FD +:102D000000266000002680000026A0000026C000EB +:102D10000026E000002700000027200000274000D8 +:102D200000276000002780000027A0000027C000C7 +:102D30000027E000002800000028200000284000B4 +:102D400000286000002880000028A0000028C000A3 +:102D50000028E00000290000002920000029400090 +:102D600000296000002980000029A0000029C0007F +:102D70000029E000002A0000002A2000002A40006C +:102D8000002A6000002A8000002AA000002AC0005B +:102D9000002AE000002B0000002B2000002B400048 +:102DA000002B6000002B8000002BA000002BC00037 +:102DB000002BE000002C0000002C2000002C400024 +:102DC000002C6000002C8000002CA000002CC00013 +:102DD000002CE000002D0000002D2000002D400000 +:102DE000002D6000002D8000002DA000002DC000EF +:102DF000002DE000002E0000002E2000002E4000DC +:102E0000002E6000002E8000002EA000002EC000CA +:102E1000002EE000002F0000002F2000002F4000B7 +:102E2000002F6000002F8000002FA000002FC000A6 +:102E3000002FE00000300000003020000030400093 +:102E400000306000003080000030A0000030C00082 +:102E50000030E0000031000000312000003140006F +:102E600000316000003180000031A0000031C0005E +:102E70000031E0000032000000322000003240004B +:102E800000326000003280000032A0000032C0003A +:102E90000032E00000330000003320000033400027 +:102EA00000336000003380000033A0000033C00016 +:102EB0000033E00000340000003420000034400003 +:102EC00000346000003480000034A0000034C000F2 +:102ED0000034E000003500000035200000354000DF +:102EE00000356000003580000035A0000035C000CE +:102EF0000035E000003600000036200000364000BB +:102F000000366000003680000036A0000036C000A9 +:102F10000036E00000370000003720000037400096 +:102F200000376000003780000037A0000037C00085 +:102F30000037E00000380000003820000038400072 +:102F400000386000003880000038A0000038C00061 +:102F50000038E0000039000000392000003940004E +:102F600000396000003980000039A0000039C0003D +:102F70000039E000003A0000003A2000003A40002A +:102F8000003A6000003A8000003AA000003AC00019 +:102F9000003AE000003B0000003B2000003B400006 +:102FA000003B6000003B8000003BA000003BC000F5 +:102FB000003BE000003C0000003C2000003C4000E2 +:102FC000003C6000003C8000003CA000003CC000D1 +:102FD000003CE000003D0000003D2000003D4000BE +:102FE000003D6000003D8000003DA000003DC000AD +:102FF000003DE000003E0000003E2000003E40009A +:10300000003E6000003E8000003EA000003EC00088 +:10301000003EE000003F0000003F2000003F400075 +:10302000003F6000003F8000003FA000003FC00064 +:10303000003FE000003FE00100000000000001FF51 +:10304000000002000000000100000002000000007B +:1030500000000008021500200215002008100000E2 +:103060000000003300000002000000000000000526 +:103070000000000500000000000000000000000249 +:103080000000000300000002000000010000000436 +:103090000000000200000002000000010000000229 +:1030A000000000200000004000000040000000037D +:1030B0000000001800002000000040C000006180F7 +:1030C000000082400000A3000000C3C00000E480B4 +:1030D0000001054000012600000146C00001678094 +:1030E000000188400001A9000001C9C00001EA8078 +:1030F00000020B4000022C0000024CC000026D8058 +:1031000000028E400002AF000002CFC00002F0803B +:10311000000011400000000100000001000000015B +:10312000000000010000000100000001000000019B +:10313000000000010000000100000001000000018B +:10314000000000010000000100000001000000017B +:103150000003D0000000003D00000001000D000051 +:10316000000700D000028140000B816800020220AD +:1031700000010240000F025000010340000C00005B +:10318000000800C000028140000B8168000202209C +:103190000001024000070250000202C000100000BF +:1031A0000008010000028180000B81A8000202607B +:1031B00000018280000E8298000803800000000059 +:1031C000000000000002800000090028000200B892 +:1031D000000100D8000000E8000000E8FFFFFFF356 +:1031E00001AFFFFF00000000000000000000000031 +:1031F000000000000000000000000000FFFFFFF1E1 +:1032000000EFFFFF000000000000000000000000D1 +:10321000000000000001000000000000FFFFFFF6BA +:10322000005FFFFF00000000000000000000000041 +:10323000000000000002000000000000FFFFF40694 +:103240001CBFFFFF0000000500000000000000148C +:10325000000000000004000000000000FFFFFFF27B +:10326000004FFFFF00000000000000000000000011 +:10327000000000000008000000000000FFFFFFFA4F +:10328000002FFFFF00000000000000000000000011 +:10329000000000000010000000000000FFFFFFF72A +:1032A00001EFFFFF00000000000000000000000030 +:1032B000000000000020000000000000FFFFFFF5FC +:1032C000002FFFFF000000000000000000000000D1 +:1032D000000000000040000000000000FFFFFFF3BE +:1032E000018FFFFF00000000000000000000000050 +:1032F000000000000000000000000000FFFFFFF1E0 +:10330000010FFFFF000000000000000000000000AF +:10331000000000000001000000000000FFFFFFF6B9 +:10332000005FFFFF00000000000000000000000040 +:10333000000000000002000000000000FFFFF40693 +:103340001CBFFFFF0000000500000000000000148B +:10335000000000000004000000000000FFFFFFF27A +:10336000004FFFFF00000000000000000000000010 +:10337000000000000008000000000000FFFFFFFA4E +:10338000002FFFFF00000000000000000000000010 +:10339000000000000010000000000000FFFFFFF729 +:1033A00000EFFFFF00000000000000000000000030 +:1033B000000000000020000000000000FFFFFFF5FB +:1033C000004FFFFF000000000000000000000000B0 +:1033D000000000000040000000000000FFFFFFFFB1 +:1033E00000CFFFFF0000000000000000000000CC44 +:1033F000000000000000000000000000FFFFFFFFD1 +:1034000000CFFFFF0000000000000000000000CC23 +:10341000000000000001000000000000FFFFFFFFAF +:1034200000CFFFFF0000000000000000000000CC03 +:10343000000000000002000000000000FFFFFFFF8E +:1034400000CFFFFF0000000000000000000000CCE3 +:10345000000000000004000000000000FFFFFFFF6C +:1034600000CFFFFF0000000000000000000000CCC3 +:10347000000000000008000000000000FFFFFFFF48 +:1034800000CFFFFF0000000000000000000000CCA3 +:10349000000000000010000000000000FFFFFFFF20 +:1034A00000CFFFFF0000000000000000000000CC83 +:1034B000000000000020000000000000FFFFFFFFF0 +:1034C00000CFFFFF0000000000000000000000CC63 +:1034D000000000000040000000000000FFFFFFF3BC +:1034E000020FFFFF000000000000000000000000CD +:1034F000000000000000000000000000FFFFFFF1DE +:10350000010FFFFF000000000000000000000000AD +:10351000000000000001000000000000FFFFFFF6B7 +:10352000005FFFFF0000000000000000000000003E +:10353000000000000002000000000000FFFFF40691 +:103540001CBFFFFF00000005000000000000001489 +:10355000000000000004000000000000FFFFFFF278 +:10356000004FFFFF0000000000000000000000000E +:10357000000000000008000000000000FFFFFF8ABC +:10358000042FFFFF0000000000000000000000000A +:10359000000000000010000000000000FFFFFF9787 +:1035A00005CFFFFF00000000000000000000000049 +:1035B000000000000020000000000000FFFFFFF5F9 +:1035C000010FFFFF000000000000000000000000ED +:1035D000000000000040000000000000FFFFFFF3BB +:1035E000000FFFFF000000000000000000000000CE +:1035F000000000000000000000000000FFFFFFF1DD +:10360000000FFFFF000000000000000000000000AD +:10361000000000000001000000000000FFFFFFF6B6 +:10362000005FFFFF0000000000000000000000003D +:10363000000000000002000000000000FFFFFF0685 +:103640001CBFFFFF0000000000000000000000148D +:10365000000000000004000000000000FFFFFFF277 +:10366000004FFFFF0000000000000000000000000D +:10367000000000000008000000000000FFFFFFFA4B +:10368000002FFFFF0000000000000000000000000D +:10369000000000000010000000000000FFFFFFF726 +:1036A000000FFFFF0000000000000000000000000D +:1036B000000000000020000000000000FFFFFFFFEE +:1036C00000CFFFFF0000000000000000000000CC61 +:1036D000000000000040000000000000FFFFFFFFAE +:1036E00000CFFFFF0000000000000000000000CC41 +:1036F000000000000000000000000000FFFFFFFFCE +:1037000000CFFFFF0000000000000000000000CC20 +:10371000000000000001000000000000FFFFFFFFAC +:1037200000CFFFFF0000000000000000000000CC00 +:10373000000000000002000000000000FFFFFFFF8B +:1037400000CFFFFF0000000000000000000000CCE0 +:10375000000000000004000000000000FFFFFFFF69 +:1037600000CFFFFF0000000000000000000000CCC0 +:10377000000000000008000000000000FFFFFFFF45 +:1037800000CFFFFF0000000000000000000000CCA0 +:10379000000000000010000000000000FFFFFFFF1D +:1037A00000CFFFFF0000000000000000000000CC80 +:1037B000000000000020000000000000FFFFFFFFED +:1037C00000CFFFFF0000000000000000000000CC60 +:1037D000000000000040000000000000FFFFFFFFAD +:1037E00000CFFFFF0000000000000000000000CC40 +:1037F000000000000000000000000000FFFFFFFFCD +:1038000000CFFFFF0000000000000000000000CC1F +:10381000000000000001000000000000FFFFFFFFAB +:1038200000CFFFFF0000000000000000000000CCFF +:10383000000000000002000000000000FFFFFFFF8A +:1038400000CFFFFF0000000000000000000000CCDF +:10385000000000000004000000000000FFFFFFFF68 +:1038600000CFFFFF0000000000000000000000CCBF +:10387000000000000008000000000000FFFFFFFF44 +:1038800000CFFFFF0000000000000000000000CC9F +:10389000000000000010000000000000FFFFFFFF1C +:1038A00000CFFFFF0000000000000000000000CC7F +:1038B000000000000020000000000000FFFFFFFFEC +:1038C00000CFFFFF0000000000000000000000CC5F +:1038D000000000000040000000000000FFFFFFFFAC +:1038E00000CFFFFF0000000000000000000000CC3F +:1038F000000000000000000000000000FFFFFFFFCC +:1039000000CFFFFF0000000000000000000000CC1E +:10391000000000000001000000000000FFFFFFFFAA +:1039200000CFFFFF0000000000000000000000CCFE +:10393000000000000002000000000000FFFFFFFF89 +:1039400000CFFFFF0000000000000000000000CCDE +:10395000000000000004000000000000FFFFFFFF67 +:1039600000CFFFFF0000000000000000000000CCBE +:10397000000000000008000000000000FFFFFFFF43 +:1039800000CFFFFF0000000000000000000000CC9E +:10399000000000000010000000000000FFFFFFFF1B +:1039A00000CFFFFF0000000000000000000000CC7E +:1039B000000000000020000000000000FFFFFFFFEB +:1039C00000CFFFFF0000000000000000000000CC5E +:1039D0000000000000400000000000000000021194 +:1039E00000000200000002040000FFFF0000FFFFD3 +:1039F0000000FFFF0000FFFF00000020000000218A +:103A00000000002200000023000000240000002528 +:103A10000000002600000027000000280000002908 +:103A20000000002A0000002B0000002C0000002DE8 +:103A30000000002E0000002F000000100000000118 +:103A40000000000100000001000000010000000172 +:103A50000000000100000001000000010000000162 +:103A60000000000100000001000000010000000152 +:103A70000000000100000001000000010000000142 +:103A800007FFFFFF0000003F07FFFFFF0000000FE0 +:103A900000007FF800007FF80000FF000000000039 +:103AA0000000FF00000000000000FF000000000018 +:103AB0000000FF00000000000000FF000000000008 +:103AC0000000FF00000000000000FF0000000000F8 +:103AD0000000FF00000000000000FF1C0FFFFFFFC0 +:103AE0000000FF1C0FFFFFFF0000FF1C0FFFFFFF88 +:103AF0000000FF1C0FFFFFFF0000FF1C0FFFFFFF78 +:103B00000000FF1C0FFFFFFF0000FF1C0FFFFFFF67 +:103B10000000FF1C0FFFFFFF0000FF1C0FFFFFFF57 +:103B20000000FF1C0FFFFFFF0000FF1C0FFFFFFF47 +:103B30000000FF1C0FFFFFFF0000FF1C0FFFFFFF37 +:103B40000000FF1C0FFFFFFF0000FF1C0FFFFFFF27 +:103B50000000FF1C0FFFFFFF0000FF1C0FFFFFFF17 +:103B60000000FF1C0FFFFFFF0000FF1C0FFFFFFF07 +:103B70000000FF1C0FFFFFFF0000FF1C0FFFFFFFF7 +:103B80000000FF1C0FFFFFFF0000FF1C0FFFFFFFE7 +:103B90000000FF1C0FFFFFFF0000FF1C0FFFFFFFD7 +:103BA0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC7 +:103BB0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB7 +:103BC0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA7 +:103BD0000000FF1C0FFFFFFF0000FF1C0FFFFFFF97 +:103BE0000000FF1C0FFFFFFF0000FF1C0FFFFFFF87 +:103BF0000000FF1C0FFFFFFF0000FF1C0FFFFFFF77 +:103C00000000FF1C0FFFFFFF0000FF1C0FFFFFFF66 +:103C10000000FF1C0FFFFFFF0000FF1C0FFFFFFF56 +:103C20000000FF1C0FFFFFFF0000FF1C0FFFFFFF46 +:103C30000000FF1C0FFFFFFF0000FF1C0FFFFFFF36 +:103C40000000FF1C0FFFFFFF0000FF1C0FFFFFFF26 +:103C50000000FF1C0FFFFFFF0000FF1C0FFFFFFF16 +:103C60000000FF1C0FFFFFFF0000FF1C0FFFFFFF06 +:103C70000000FF1C0FFFFFFF0000FF1C0FFFFFFFF6 +:103C80000000FF1C0FFFFFFF0000FF1C0FFFFFFFE6 +:103C90000000FF1C0FFFFFFF0000FF1C0FFFFFFFD6 +:103CA0000000FF1C0FFFFFFF0000FF1C0FFFFFFFC6 +:103CB0000000FF1C0FFFFFFF0000FF1C0FFFFFFFB6 +:103CC0000000FF1C0FFFFFFF0000FF1C0FFFFFFFA6 +:103CD0000000FF1C0FFFFFFF000003130000150092 +:103CE00000000001000000020000000300000000CE +:103CF00000000004000000010000000000000001BE +:103D000000000004000000000000000100000003AB +:103D1000000000000000000100000004000000009E +:103D2000000000010000000300000000000000018E +:103D30000000000400000000000000040000000378 +:103D4000000000000000000000003FFF000003FF33 +:103D50000000000000000001000000010000000160 +:103D6000007C10040000000400000002000000902D +:103D70000000009000800090081000000000008A01 +:103D800000000080000000810000008000000006AC +:103D9000000007D00000076C071D2911000000007B +:103DA000009C04240000000000000001000000014D +:103DB00000000001000000010000000100007FFF82 +:103DC000000000FF000000FF000000FF000000FFF7 +:103DD0000000007F000000FF000000FF000000FF67 +:103DE0000000003E000000000000003F0000003F17 +:103DF0000000003F0000003F0000003F0000003FC7 +:103E00000000003F0000000F00000000121700003B +:103E100022170000321700001215000022150000C2 +:103E20003215000002100000001000001010000009 +:103E300020100000301000000010000012140000DC +:103E4000221400003214000000E38340FFFFFFFF54 +:103E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:103E6000FFFFFFFFFFFFFFFFFFFFFFFFF00050001E +:103E7000F0001000FFFFFFFFFFFFFFFFFFFFFFFF4E +:103E8000FFFFFFFFFFFFFFFFFFFFFFFFFF8090002F +:103E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:103EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:103EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:103EC000FFFFFFFFFFFFFFFFFFFFFFFF00003C10B2 +:103ED00000000001000000000000000800000008D1 +:103EE00000000002000000040000000500000004C3 +:103EF000000000400000180800000803000008034C +:103F00000000004000000003000008030000080358 +:103F1000000008030001000300000803000008037C +:103F20000000000300000003000000030000000385 +:103F30000000000300000003000000030000000375 +:103F40000000000300000003000000030000000365 +:103F50000000000300000003000000030000240331 +:103F60000000002F0000000900000019000001847B +:103F70000000018300000306000000190000000695 +:103F800000000306000003060000030600000C8684 +:103F90000000030600000306000000060000000603 +:103FA00000000006000000060000000600000006F9 +:103FB00000000006000000060000000600000006E9 +:103FC00000000006000000060000000600000006D9 +:103FD00000000006000003060000001300000006B9 +:103FE0000000100400001004001064400010644041 +:103FF00000000000000000000000000000000000C1 +:104000000000200000000000000000000000000090 +:10401000000000000400200000000000000000007C +:104020000000000000000000000020000000007CF4 +:104030000000003D0000003F0000009C0000000662 +:10404000000000050000000A00000005000001401B +:10405000000001400000000000000000000000C05F +:104060000000013F00007FFF000000480000004802 +:1040700000000000000000000000004800000004F4 +:104080000000000400000004000000040000000420 +:104090000000000400000004000000040000000410 +:1040A000000000090000000B0000000A00000004EE +:1040B000000000090000000B0000000A00000001E1 +:1040C00000000001000000010000000100000001EC +:1040D00000000001000000010000000100000001DC +:1040E00000000001000000010000000100000004C9 +:1040F000000000090000000B0000000A00000001A1 +:1041000000000001000000010000000100000001AB +:10411000000000010000000100000001000000019B +:104120000000000100000001000000010000000488 +:10413000000000090000000B0000000A0000000061 +:10414000000000000000080000000200000001FF65 +:104150000000040000000000000000001E491E498D +:104160001E491E490E490E490E490E49FFFFFFFF29 +:1041700000000000000025E40000800000000013A3 +:104180000FFF0FFF00000000000000000FFF0FFFF7 +:10419000100010001000100020002000200020005F +:1041A000800080008000800040004000400040000F +:1041B00000000000000000010101010101200101D7 +:1041C0002001010101011001010101010120010192 +:1041D0002001010101011001200101010101100173 +:1041E0000101010101200101200101010101100172 +:1041F0000101010101200101010101010120010171 +:104200002001010101011001010101010120010151 +:104210002001010101011001010101010120010141 +:104220002001010101011001010101010120010131 +:10423000200101010101100100000004000000093B +:104240000000000B0000000A00000004000000094C +:104250000000000B0000000A000000010000000147 +:10426000000000010000000100000001000000014A +:10427000000000010000000100000001000000013A +:10428000000000010000000100000004000000091F +:104290000000000B0000000A000000010000000107 +:1042A000000000010000000100000001000000010A +:1042B00000000001000000010000000100000001FA +:1042C00000000001000000010000000400000009DF +:1042D0000000000B0000000A1E491E491E491E492D +:1042E0000E490E490E490E49FFFFFFFF0000000076 +:1042F0000FFF0FFF00000000000000000FFF0FFF86 +:1043000010001000100010002000200020002000ED +:10431000800080008000800040004000400040009D +:104320000000000000000002000000010000000387 +:104330000000000400000006000000050000000767 +:1043400000000123000001230000012300000123DD +:1043500000000123000001230000012300000123CD +:1043600000000123000001230000012300000123BD +:1043700000000123000001230000012300000123AD +:10438000000001230000012300000123000001239D +:1043900000000020000000320000000700000007BD +:1043A0000000000000000008021500200215002097 +:1043B0000000003008100000000000330000003052 +:1043C00000000031000000020000000500000006AF +:1043D00000000002000000020000000000000005D4 +:1043E00000000002000000020000000200000001C6 +:1043F0000000000600000001000000020000004074 +:104400000000004000000020000000130000002019 +:1044100000010000000204C00003098000040E40F7 +:1044200000051300000617C000071C80000821408B +:1044300000092600000A2AC0000B2F80000C34401F +:10444000000D3900000E3DC0000F428000104740B3 +:1044500000114C00001250C00013558000145A4047 +:1044600000155F00001663C00017688000186D40DB +:1044700000197200001A76C0001B7B80001C80406F +:10448000001D8500001E89C0001F8E800000934023 +:104490000000000100000001000000010000000118 +:1044A0000000000100000001000000010000000108 +:1044B00000000001000000010000000100000001F8 +:1044C00000000001000000010000000100000001E8 +:1044D000000000080000000C0000001000000001B7 +:1044E00000000001000000010000021100000200B5 +:1044F00000000204000002190000FFFF0000FFFF9F +:104500000000FFFF0000FFFF07FFFFFF0000003F6C +:1045100007FFFFFF0000000F00007FF800007FF89A +:104520000000000000000001002010010000000059 +:1045300001009000000001000000000100000000E8 +:1045400000000000140AFF000000900200000000BC +:1045500000000000000000000000900400000000C7 +:1045600000000000000000000000900600000000B5 +:1045700000000000000000000000900800000000A3 +:1045800000000000000000000000900A0000000091 +:1045900000000000000000000000900C000000007F +:1045A00000000000000000000000900E000000006D +:1045B000000000000000000000009010000000005B +:1045C0000000000000000000000090120000000049 +:1045D0000000000000000000000090140000000037 +:1045E0000000000000000000000090160000000025 +:1045F0000000000000000000000090180000000013 +:1046000000000000000000000000901A0000000000 +:1046100000000000000000000000901C00000000EE +:1046200000000000000000000000901E00000000DC +:1046300000000000000000000000902000000000CA +:1046400000000000000000000000902200000000B8 +:1046500000000000000000000000902400000000A6 +:104660000000000000000000000090260000000094 +:104670000000000000000000000090280000000082 +:1046800000000000000000000000902A0000000070 +:1046900000000000000000000000902C000000005E +:1046A00000000000000000000000902E000000004C +:1046B000000000000000000000009030000000003A +:1046C0000000000000000000000090320000000028 +:1046D0000000000000000000000090340000000016 +:1046E0000000000000000000000090360000000004 +:1046F00000000000000000000000903800000000F2 +:1047000000000000000000000000903A00000000DF +:1047100000000000000000000000903C00000000CD +:1047200000000000000000000000903E00000000BB +:1047300000000000000000000000904000000000A9 +:104740000000000000000000000090420000000097 +:104750000000000000000000000090440000000085 +:104760000000000000000000000090460000000073 +:104770000000000000000000000090480000000061 +:1047800000000000000000000000904A000000004F +:1047900000000000000000000000904C000000003D +:1047A00000000000000000000000904E000000002B +:1047B0000000000000000000000090500000000019 +:1047C0000000000000000000000090520000000007 +:1047D00000000000000000000000905400000000F5 +:1047E00000000000000000000000905600000000E3 +:1047F00000000000000000000000905800000000D1 +:1048000000000000000000000000905A00000000BE +:1048100000000000000000000000905C00000000AC +:1048200000000000000000000000905E000000009A +:104830000000000000000000000090600000000088 +:104840000000000000000000000090620000000076 +:104850000000000000000000000090640000000064 +:104860000000000000000000000090660000000052 +:104870000000000000000000000090680000000040 +:1048800000000000000000000000906A000000002E +:1048900000000000000000000000906C000000001C +:1048A00000000000000000000000906E000000000A +:1048B00000000000000000000000907000000000F8 +:1048C00000000000000000000000907200000000E6 +:1048D00000000000000000000000907400000000D4 +:1048E00000000000000000000000907600000000C2 +:1048F00000000000000000000000907800000000B0 +:1049000000000000000000000000907A000000009D +:1049100000000000000000000000907C000000008B +:1049200000000000000000000000907E0000000079 +:104930000000000000000000000090800000000067 +:104940000000000000000000000090820000000055 +:104950000000000000000000000090840000000043 +:104960000000000000000000000090860000000031 +:10497000000000000000000000009088000000001F +:1049800000000000000000000000908A000000000D +:1049900000000000000000000000908C00000000FB +:1049A00000000000000000000000908E00000000E9 +:1049B00000000000000000000000909000000000D7 +:1049C00000000000000000000000909200000000C5 +:1049D00000000000000000000000909400000000B3 +:1049E00000000000000000000000909600000000A1 +:1049F000000000000000000000009098000000008F +:104A000000000000000000000000909A000000007C +:104A100000000000000000000000909C000000006A +:104A200000000000000000000000909E0000000058 +:104A30000000000000000000000090A00000000046 +:104A40000000000000000000000090A20000000034 +:104A50000000000000000000000090A40000000022 +:104A60000000000000000000000090A60000000010 +:104A70000000000000000000000090A800000000FE +:104A80000000000000000000000090AA00000000EC +:104A90000000000000000000000090AC00000000DA +:104AA0000000000000000000000090AE00000000C8 +:104AB0000000000000000000000090B000000000B6 +:104AC0000000000000000000000090B200000000A4 +:104AD0000000000000000000000090B40000000092 +:104AE0000000000000000000000090B60000000080 +:104AF0000000000000000000000090B8000000006E +:104B00000000000000000000000090BA000000005B +:104B10000000000000000000000090BC0000000049 +:104B20000000000000000000000090BE0000000037 +:104B30000000000000000000000090C00000000025 +:104B40000000000000000000000090C20000000013 +:104B50000000000000000000000090C40000000001 +:104B60000000000000000000000090C600000000EF +:104B70000000000000000000000090C800000000DD +:104B80000000000000000000000090CA00000000CB +:104B90000000000000000000000090CC00000000B9 +:104BA0000000000000000000000090CE00000000A7 +:104BB0000000000000000000000090D00000000095 +:104BC0000000000000000000000090D20000000083 +:104BD0000000000000000000000090D40000000071 +:104BE0000000000000000000000090D6000000005F +:104BF0000000000000000000000090D8000000004D +:104C00000000000000000000000090DA000000003A +:104C10000000000000000000000090DC0000000028 +:104C20000000000000000000000090DE0000000016 +:104C30000000000000000000000090E00000000004 +:104C40000000000000000000000090E200000000F2 +:104C50000000000000000000000090E400000000E0 +:104C60000000000000000000000090E600000000CE +:104C70000000000000000000000090E800000000BC +:104C80000000000000000000000090EA00000000AA +:104C90000000000000000000000090EC0000000098 +:104CA0000000000000000000000090EE0000000086 +:104CB0000000000000000000000090F00000000074 +:104CC0000000000000000000000090F20000000062 +:104CD0000000000000000000000090F40000000050 +:104CE0000000000000000000000090F6000000003E +:104CF0000000000000000000000090F8000000002C +:104D00000000000000000000000090FA0000000019 +:104D10000000000000000000000090FC0000000007 +:104D20000000000000000000000090FE00000000F5 +:104D300000000000000000000000910000000000E2 +:104D400000000000000000000000910200000000D0 +:104D500000000000000000000000910400000000BE +:104D600000000000000000000000910600000000AC +:104D7000000000000000000000009108000000009A +:104D800000000000000000000000910A0000000088 +:104D900000000000000000000000910C0000000076 +:104DA00000000000000000000000910E0000000064 +:104DB0000000000000000000000091100000000052 +:104DC0000000000000000000000091120000000040 +:104DD000000000000000000000009114000000002E +:104DE000000000000000000000009116000000001C +:104DF000000000000000000000009118000000000A +:104E000000000000000000000000911A00000000F7 +:104E100000000000000000000000911C00000000E5 +:104E200000000000000000000000911E00000000D3 +:104E300000000000000000000000912000000000C1 +:104E400000000000000000000000912200000000AF +:104E5000000000000000000000009124000000009D +:104E6000000000000000000000009126000000008B +:104E70000000000000000000000091280000000079 +:104E800000000000000000000000912A0000000067 +:104E900000000000000000000000912C0000000055 +:104EA00000000000000000000000912E0000000043 +:104EB0000000000000000000000091300000000031 +:104EC000000000000000000000009132000000001F +:104ED000000000000000000000009134000000000D +:104EE00000000000000000000000913600000000FB +:104EF00000000000000000000000913800000000E9 +:104F000000000000000000000000913A00000000D6 +:104F100000000000000000000000913C00000000C4 +:104F200000000000000000000000913E00000000B2 +:104F300000000000000000000000914000000000A0 +:104F4000000000000000000000009142000000008E +:104F5000000000000000000000009144000000007C +:104F6000000000000000000000009146000000006A +:104F70000000000000000000000091480000000058 +:104F800000000000000000000000914A0000000046 +:104F900000000000000000000000914C0000000034 +:104FA00000000000000000000000914E0000000022 +:104FB0000000000000000000000091500000000010 +:104FC00000000000000000000000915200000000FE +:104FD00000000000000000000000915400000000EC +:104FE00000000000000000000000915600000000DA +:104FF00000000000000000000000915800000000C8 +:1050000000000000000000000000915A00000000B5 +:1050100000000000000000000000915C00000000A3 +:1050200000000000000000000000915E0000000091 +:10503000000000000000000000009160000000007F +:10504000000000000000000000009162000000006D +:10505000000000000000000000009164000000005B +:105060000000000000000000000091660000000049 +:105070000000000000000000000091680000000037 +:1050800000000000000000000000916A0000000025 +:1050900000000000000000000000916C0000000013 +:1050A00000000000000000000000916E0000000001 +:1050B00000000000000000000000917000000000EF +:1050C00000000000000000000000917200000000DD +:1050D00000000000000000000000917400000000CB +:1050E00000000000000000000000917600000000B9 +:1050F00000000000000000000000917800000000A7 +:1051000000000000000000000000917A0000000094 +:1051100000000000000000000000917C0000000082 +:1051200000000000000000000000917E0000000070 +:10513000000000000000000000009180000000005E +:10514000000000000000000000009182000000004C +:10515000000000000000000000009184000000003A +:105160000000000000000000000091860000000028 +:105170000000000000000000000091880000000016 +:1051800000000000000000000000918A0000000004 +:1051900000000000000000000000918C00000000F2 +:1051A00000000000000000000000918E00000000E0 +:1051B00000000000000000000000919000000000CE +:1051C00000000000000000000000919200000000BC +:1051D00000000000000000000000919400000000AA +:1051E0000000000000000000000091960000000098 +:1051F0000000000000000000000091980000000086 +:1052000000000000000000000000919A0000000073 +:1052100000000000000000000000919C0000000061 +:1052200000000000000000000000919E000000004F +:105230000000000000000000000091A0000000003D +:105240000000000000000000000091A2000000002B +:105250000000000000000000000091A40000000019 +:105260000000000000000000000091A60000000007 +:105270000000000000000000000091A800000000F5 +:105280000000000000000000000091AA00000000E3 +:105290000000000000000000000091AC00000000D1 +:1052A0000000000000000000000091AE00000000BF +:1052B0000000000000000000000091B000000000AD +:1052C0000000000000000000000091B2000000009B +:1052D0000000000000000000000091B40000000089 +:1052E0000000000000000000000091B60000000077 +:1052F0000000000000000000000091B80000000065 +:105300000000000000000000000091BA0000000052 +:105310000000000000000000000091BC0000000040 +:105320000000000000000000000091BE000000002E +:105330000000000000000000000091C0000000001C +:105340000000000000000000000091C2000000000A +:105350000000000000000000000091C400000000F8 +:105360000000000000000000000091C600000000E6 +:105370000000000000000000000091C800000000D4 +:105380000000000000000000000091CA00000000C2 +:105390000000000000000000000091CC00000000B0 +:1053A0000000000000000000000091CE000000009E +:1053B0000000000000000000000091D0000000008C +:1053C0000000000000000000000091D2000000007A +:1053D0000000000000000000000091D40000000068 +:1053E0000000000000000000000091D60000000056 +:1053F0000000000000000000000091D80000000044 +:105400000000000000000000000091DA0000000031 +:105410000000000000000000000091DC000000001F +:105420000000000000000000000091DE000000000D +:105430000000000000000000000091E000000000FB +:105440000000000000000000000091E200000000E9 +:105450000000000000000000000091E400000000D7 +:105460000000000000000000000091E600000000C5 +:105470000000000000000000000091E800000000B3 +:105480000000000000000000000091EA00000000A1 +:105490000000000000000000000091EC000000008F +:1054A0000000000000000000000091EE000000007D +:1054B0000000000000000000000091F0000000006B +:1054C0000000000000000000000091F20000000059 +:1054D0000000000000000000000091F40000000047 +:1054E0000000000000000000000091F60000000035 +:1054F0000000000000000000000091F80000000023 +:105500000000000000000000000091FA0000000010 +:105510000000000000000000000091FC00000000FE +:105520000000000000000000000091FE0000FF00ED +:10553000000000000000FF00000000000000FF006D +:10554000000000000000FF00000000000000FF005D +:10555000000000000000FF00000000000000FF004D +:10556000000000000000FF0000000000000001A992 +:105570000000150000000001000000020000000310 +:105580000000000000000004000000010000000016 +:105590000000000100000004000000000000000105 +:1055A00000000003000000000000000100000004F3 +:1055B00000000000000000010000000300000000E7 +:1055C00000000001000000040000000000000004D2 +:1055D00000000003000000000000000000003FFF8A +:1055E000000003FF0000000300BEBC20000000001C +:1055F000000000050000000300BEBC200000000009 +:10560000000000050000000300BEBC2000000000F8 +:10561000000000050000000300BEBC2000000000E8 +:10562000000000050000000300BEBC2000000000D8 +:10563000000000050000000300BEBC2000000000C8 +:10564000000000050000000300BEBC2000000000B8 +:10565000000000050000000300BEBC2000000000A8 +:10566000000000050000000D0000000C000000001C +:10567000000000100215002002150020000000307C +:10568000081000000000003300000030000000316E +:105690000000000200000004000000000000000202 +:1056A00000000002000000000000000200000007EF +:1056B00000000002000000020000000100000003E2 +:1056C0000000000100000002000000400000004057 +:1056D00000000004000000200000000F0000001B7C +:1056E00000008000000103C00001878000020B4021 +:1056F00000028F00000312C00003968000041A40CD +:1057000000049E00000521C00005A5800006294078 +:105710000006AD00000730C00007B4800008384024 +:105720000008BC0000093FC00009C380000A4740D0 +:10573000000ACB00000B4EC0000BD280000C56407C +:10574000000CDA00000D5DC0000061800000000167 +:105750000000000100000001000000010000000145 +:105760000000000100000001000000010000000135 +:105770000000000100000001000000010000000125 +:105780000000000100000001000000010000000115 +:105790000000101100001000000010040000102193 +:1057A0000000FFFF0000FFFF0000FFFF0000FFFF01 +:1057B0000000004600000010000000000000000093 +:1057C00000000018000000010000000000000000C0 +:1057D000000000000000000107FFFFFF0000003F85 +:1057E00007FFFFFF0000000F00007FF800007FF8B8 +:1057F0000000190000000000FFFFFFFFFFFFFFFF98 +:10580000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:10581000FFFFFFFFFFFFFFFF0000FF000000000091 +:105820000000FF00000000000000FF00000000007A +:105830000000FF00000000000000FF00000000006A +:105840000000FF00000000000000FF00000000005A +:105850000000FF00000000000000014C00003500C7 +:105860000000000100000002000000030000000032 +:105870000000000400000001000000000000000122 +:105880000000000400000000000000010000000310 +:105890000000000000000001000000040000000003 +:1058A00000000001000000030000000000000001F3 +:1058B00000000004000000000000000400000003DD +:1058C000000000000000000000003FFF000003FF98 +:1058D00000000000039387000000000000000000AB +:1058E000000000000393870000000000000000009B +:1058F0000000000F00000007000000000000000E84 +:1059000003150020031500200100003008100000DE +:1059100000000033000000300000003100000003F0 +:105920000000000600000003000000030000000269 +:10593000000000000000000200000000000000065F +:10594000000000040000000200000002000000014E +:105950000000000400000001000000020000004000 +:1059600000000040000000040000002000000002D1 +:105970000000002000001000000020800000310026 +:1059800000004180000052000000628000007300AF +:1059900000008380000094000000A4800000B50097 +:1059A0000000C5800000D6000000E6800000F7007F +:1059B0000001078000011800000128800001390063 +:1059C0000001498000015A0000016A8000017B004B +:1059D00000018B8000019C000001AC800001BD0033 +:1059E0000001CD800001DE000001EE800001FF001B +:1059F00000000F8000000001000000010000000115 +:105A00000000000100000001000000010000000192 +:105A10000000000100000001000000010000000182 +:105A20000000000100000001000000010000000172 +:105A30000000000100000001000000010000000162 +:105A400000000001000012240000121000001214D7 +:105A50000000FFFF0000FFFF0000FFFF0000FFFF4E +:105A600000000020000000200000000000000000F6 +:105A70000000002300000024000000250000002694 +:105A800000000027000000290000002A0000002B71 +:105A90000000002C000000010000000107FFFFFFD4 +:105AA0000000003F07FFFFFF0000000F00007FF82D +:105AB00000007FF80000000000000001CCCC0201D3 +:105AC000CCCCCCCCCCCC0201CCCCCCCCCCCC020140 +:105AD000CCCCCCCCCCCC0201CCCCCCCCCCCC020130 +:105AE000CCCCCCCCCCCC0201CCCCCCCCCCCC020120 +:105AF000CCCCCCCCCCCC0201CCCCCCCCFFFFFFFFAF +:105B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +:105B1000FFFFFFFFFFFFFFFFFFFFFFFF0000000091 +:105B20000001000100110807CCCCCCC5100000001A +:105B3000000028AD7058103C000000000000FF007D +:105B4000000000000000FF00000000000000FF0057 +:105B5000000000000000FF00000000000000FF0047 +:105B6000000000000000FF00000000000000FF0037 +:105B7000000000000000FF000000000000000267BD +:105B800000003500000000010000000200000003DA +:105B90000000000000000004000000010000000000 +:105BA00000000001000000040000000000000001EF +:105BB00000000003000000000000000100000004DD +:105BC00000000000000000010000000300000000D1 +:105BD00000000001000000040000000000000004BC +:105BE00000000003000000000000000000003FFF74 +:105BF000000003FF002625A000000000002625A0CD +:105C000000000000002625A000000000002625A0BE +:105C100000000000000E0000011600D6002625A09E +:105C200000000000002625A000000000002625A09E +:105C300000000000002625A0000000000072000007 +:105C4000012300F30000FFFF000000000000FFFF41 +:105C5000000000000000FFFF000000000000FFFF48 +:105C6000000000000000FFFF000000000000FFFF38 +:105C70000000000000000000000000000000FFFF26 +:105C8000000000000000FFFF000000000000FFFF18 +:105C9000000000000000FFFF000000000000FFFF08 +:105CA000000000000000FFFF000000000000FFFFF8 +:105CB0000000000000000000000000000000FFFFE6 +:105CC000000000000000FFFF000000000000FFFFD8 +:105CD000000000000000FFFF000000000000FFFFC8 +:105CE000000000000000FFFF000000000000FFFFB8 +:105CF0000000000000000000000000000000FFFFA6 +:105D0000000000000000FFFF000000000000FFFF97 +:105D1000000000000000FFFF000000000000FFFF87 +:105D2000000000000000FFFF000000000000FFFF77 +:105D30000000000000000000000000000000FFFF65 +:105D4000000000000000FFFF000000000000FFFF57 +:105D5000000000000000FFFF000000000000FFFF47 +:105D6000000000000000FFFF000000000000FFFF37 +:105D70000000000000000000000000000000FFFF25 +:105D8000000000000000FFFF000000000000FFFF17 +:105D9000000000000000FFFF000000000000FFFF07 +:105DA000000000000000FFFF000000000000FFFFF7 +:105DB0000000000000000000000000000000FFFFE5 +:105DC000000000000000FFFF000000000000FFFFD7 +:105DD000000000000000FFFF000000000000FFFFC7 +:105DE000000000000000FFFF000000000000FFFFB7 +:105DF0000000000000000000000000000000FFFFA5 +:105E0000000000000000FFFF000000000000FFFF96 +:105E1000000000000000FFFF000000000000FFFF86 +:105E2000000000000000FFFF000000000000FFFF76 +:105E30000000000000000000000000000000FFFF64 +:105E400000000000555400005555555500005555AB +:105E5000F0000000555400005555555500005555AB +:105E6000F00000005554000055555555000055559B +:105E7000F0000000000000000001000000005014CD +:105E800000000000FF5C0000FFF55FFF0000FFFF67 +:105E9000F00003E0000000000000A000000004008B +:105EA00000000000000000000000000000001000E2 +:105EB00000000000000000000000000000004000A2 +:105EC00000000000000000000000000000010000D1 +:105ED000FF5C0000FFF55FFF0000FFFFF00003E044 +:105EE000000000000000A00000000800000000000A +:105EF0000000000000000000000020000000000082 +:105F00000000000000000000000080000000000011 +:105F1000000000000000000000020000000000007F +:105F20001F8B080000000000000BFB51CFC0F003E6 +:105F3000095772A1F2AFB0A2F2D1B1133B7E794200 +:105F400098858132FD624003E480D80A88D558F0F4 +:105F5000ABDDC98429E6288B607F91626008908060 +:105F6000B05B252873D7281E1AB84C13959FAC0E2A +:105F7000A13F6940E87234F914A83CBF0A84AED04E +:105F8000C46EAE00541E0024534894600300000009 +:105F900000000000000000001F8B0800000000004F +:105FA000000BED7D0D785C55B5E89E3967CE39F371 +:105FB0007F924ED349F3C3499AB6014299A6699B91 +:105FC00062D19336AD01AA4C7F28510B4ECB5FA016 +:105FD0007FA156C955B9336DD234A62DA4940715A7 +:105FE00010878852103460C0A29537A588F5E17DEE +:105FF000C6B648D1A2011151A1460429F7E9E5ED41 +:10600000B5F6DE33E79C6492860B3EDFF759FCDC85 +:10601000D967FFADBDD6DA6BADBDF6DA7B54AD8086 +:10602000149D41C8BBF0EF2384DCEF22844CCCA547 +:10603000645DD84D8A08F9AC46F0DFDBDED00C1287 +:1060400026A44D63E90DBE502FA4DD494232D3A1F1 +:10605000BC3C4D4284F809A99623D0C217FB7A05AF +:10606000A4AD73E3E7607A2EA485C4CDFA27A5FA20 +:106070002B7ED6F7BB12FCFF170899931B8F9C4809 +:1060800034C0F81211FF9A08B497C8CE3F4B3308BA +:10609000915BC3E48BB534AF2B24C3DBBC0BFF2770 +:1060A000AD0A2702B97939D3B6130DE9A7AA73F55A +:1060B000A7906004E190898C70F0F684A4088CEFBE +:1060C000E1A33BFB793B69A69FF20CC753BE710568 +:1060D0009EDA931AC9A8846C4FEA989722C44CD7C9 +:1060E000E03CCD472085B129FE3AAB8C5E7F85052B +:1060F0000E2FEBDF249440B3E1AF840D5F9D915BE5 +:1061000034739479932A8A2731EFCAE1F39369D7DC +:106110007D747C4A3BB317527D74389666E16821E2 +:10612000D6F98F1F8ECFD8DAFBCE2464007020D32F +:10613000F95138DCD1446A90A624CADAC9066F77CF +:106140009A78F757BB73E341B7019F8D5FB4D24292 +:106150005BF970BE4C717EEDE1F38D4B8C9F45BEBB +:1061600095C483D67A96D4C2BF52A413F9568AF83E +:1061700052520852F995412BDFF2769E7292003A04 +:10618000B4C3A762DE98D2412E8D7DAD9BA2FC46A2 +:10619000A2E0B87244C37E3EEB4ADC88702CA12496 +:1061A000A4FCE0E34DBC7A9CC052F31455871380E5 +:1061B000BF402121F386E3677B329596A75AF21EF2 +:1061C000D2DC87FC9F66E39493F4040A37F9DB4240 +:1061D0006359307F3F59FAF279B497C58E27EA6840 +:1061E0006EA212FB3ACCDF35F27C6E87F94C84F953 +:1061F0002829C00F9DCFED88BF3CF3690F4EE3F314 +:10620000898C0847079F8F803FFB5DCC2B4F3B2736 +:10621000FCF9CA3BCACCE86ADA452A38F2BC3C3001 +:106220002FBA5EBEC3E7E5092848274FA487805CE4 +:10623000A1F3FBCE48F3A37C85F2CD393F59D710AB +:106240002F627C59EB4CCBB372706688CEC6C9C244 +:106250001163725227D8EE5E92C84039E5BF01E45F +:10626000BF8049A07F254ACBCF85D46C4E51BA76EA +:106270001C9C476AA05D2046D6D1540924C8125AF6 +:10628000AFE3EF5233F02389D461FF028EEF73390D +:106290009E0F6FCB001E0B9E8F9611D68F83FE47ED +:1062A0003FA662BE6362EC6B80CBE739DE9CF8A14F +:1062B000787BDEDABFAC337C1EFDD87486AFA6894E +:1062C00036F8B27068ED367C1110A1745D4679BF66 +:1062D000026F3DC50C5F7BA3F55B41265656C76236 +:1062E00084CA99DDD1BD5B207FA796F83DB4F755F0 +:1062F0000FE1B8D1C420E251AC9745528DF7259AF1 +:10630000DED254195E43D3B0CB65E33F9176523D64 +:1063100000FC99A67A00D2B75F60F08FA2376CEBD1 +:10632000B33B2A37A569FFDDD56B7A1A28DEB6455F +:10633000AA6A51C6982E19E6E583F91884B8607CDC +:106340000A6F67F1E7104E8A3F976B768E0F05BF95 +:106350004D315B4D9D965792D68C8BF637612789D0 +:1063600065386E640B9EA28DEE941A423CF85C80F8 +:10637000EA52E34990C5E1258340B12C1E6E697253 +:10638000233D377D6C5AAF549183FB22979BC9CB39 +:1063900008E36B22C7AA416EE65B7F7B299E6AD821 +:1063A0003A7641BDC909928675B40BBE53823C430F +:1063B000E293018EC92D310FCCE7884BF05714F5CD +:1063C0006207877BEF1A1FE3AF32FD1E8067AA8B3F +:1063D000DB1F2D1C5F39FE9AEA9A9DC38BE0AFA4A8 +:1063E0003B510DE3A875699742E72BD70FA460BE18 +:1063F000ED6ED282F224450660BC6217C9FDA3E3AC +:106400008563462FF0F73CCE07C566E7F56ECA5F99 +:10641000D1A88C782C1E5CBD84B0FC8B2A4D032740 +:106420002EF83DD84F93AFEC7341FFA1D21E974495 +:10643000C753AF1CD217D0F473EEC43C8023A8A777 +:106440005CC09725EB7A5C40D73D9E56A25338D46A +:10645000F919331E007A2F26AB2DFAF7423E5FB9A9 +:1064600094D91982AE7B25C627BB1BB77AAF0940EA +:106470003D1FC2398534727EA096069D87CAF98178 +:10648000D2FD02C04F28D1E372D17695A543199869 +:1064900032E5F7490C8E5831C0B1A758694E33BC6C +:1064A0001C03FC86DC1C2706FD8FE229C8F311972C +:1064B00007E19240D151D152A893B441E92377B07A +:1064C000FC8418499B341FE2782BA94B6D01B52F32 +:1064D000F014E2F89363E92D80A73019C8C8158835 +:1064E000A7CB01CEE275832919E6AAB722FF77CBA5 +:1064F000ADBFBE91CEA7FBB0144B19163E24940F2E +:10650000CFB1DA0B74BDD9EC012E3722A7A73740E3 +:10651000BC00BFCA01A6CF847EA0FCDA0AF4937542 +:10652000C6AFA7AB87B436C97879164E04ED1D996E +:10653000DB0C5DFAD614F0D95BD0179DB7D433339A +:106540000378A3588E7DDDC02A1917CD6BBA99EE5A +:1065500046FB2D8DEB42D8235EB08B2CF687A7D45B +:106560006E179166CA6716FB4A6B53100E99EA07BD +:1065700052939B27D514683FC134DF9D0279BB1D20 +:106580002F0748C61B0279554BAC76B94C98DD0EE7 +:10659000CBE3DD8AE1EDF2E3C531DE0A3B9CA7DD0A +:1065A0002E201BAF883695A3B593C92B821F28F2E6 +:1065B000EE830E66E7E843E5DE7E17D5A3EDA5B7CB +:1065C000A5603D6D87224AD74EC2E84E126E9B1ED3 +:1065D000934ADD2FAA68B7198C5FA2CC9E52C9CA14 +:1065E0000CB417F9B1F8C2C7F9EA33247100E553C6 +:1065F0006902F1EB29DA1FB5EA1359A1F624F04834 +:10660000F50AACBFE39CAB53B0AE3DE5FA4CE405F4 +:10661000CE573B34E41DCB385B719E5DC934F98D98 +:1066200007F406EB5F33E22C157C59CDF8B8AB6666 +:106630005998C077AD0FE591BFE7E18C3B62E5C7A4 +:106640001459710ECC93D9E377D2F45DC197A0971A +:10665000A23E9B1D2EF84DF43F163EB279CDBC0CE8 +:10666000D6414B543140FEAE95482BE88596E8B4B0 +:1066700046901742DFCBEE6226170BB558860ED137 +:10668000F2AC542F19F9C769A1C244AF85DDCECE53 +:1066900001D04324ED191AB4F08F735F79D2C5F796 +:1066A0009573C95CE09B37F4E6706694FEFF903CFE +:1066B000ACA33DC0F795CE72318FB584BCAC16C289 +:1066C0003C53CA27283E036E0DF127E6271776159F +:1066D000017DD6EEFBB16E93635C7EAD95E9F6B3BA +:1066E0007638FC4E7CD27132388E683748E1B3CAB6 +:1066F0000747FB6CBF420ECAC3ECB70237FDEE6D15 +:10670000FC6C6A32C5C3DA0797323B84CE03E4AF30 +:10671000805F8C2BE6911DDF319F7CF318AFBC7E30 +:10672000A3715B2798B2C73C46591CF8A4697A2329 +:10673000E81761BF0ABA2C5DB4AD6824BF4296BFAA +:106740006462E8802F6A40233FFDBCBD1ED6D7851A +:106750006EEF8876E058FC33C7EDE09FC64B3E10E5 +:10676000FE590AFC03F8E2F6B398BF13DF2D8D1E25 +:10677000B453F2E29BB717F41BC67FF9DA0DE79327 +:106780009523F209EF5FF08B18E7BF0BEF58FC4140 +:106790001909EDC4C9F02785A78CAA55827A8EED18 +:1067A000234A38DCE555432EE02323AE2FC0FD43BA +:1067B00073EC4948EF28F845F16A036A34EAA047C8 +:1067C0005CE604D7BB679FBEBE117014B7C82F0D1F +:1067D0005AE6174ED8F3C17A7B5E25342FE65D91D9 +:1067E000EB47E77C4D8C58CC6A7FEFF20C34D3AD8D +:1067F00023E9DCBAB82142CB7779078EC3D6729BE6 +:10680000F7C286269A0F960BBF0CED95F251AFDBBF +:1068100060F8A96F423F4798EB0F323878780AE565 +:106820007FA54226DD347B7050220ACDDF1C95D334 +:106830002ADAC84DA8E7431C36D1CFCD8387B0DF15 +:106840009DF55B755BFF51563F20FA375ACFB0F686 +:10685000FF36E5F901B047646A4D007C6635C22316 +:10686000FADF59EF2685600715CB6950FEEAE02074 +:10687000DAB732194A41AAD69B1990FBC48C30FE74 +:106880001A635F22D7B1FDBC5CD735C05266BF9397 +:10689000552E271F7F1BF858A5FB09E017B19F1045 +:1068A000E38CC977A75B0FFCAD747E37105F0CF4E7 +:1068B000DD44C5747968BEAD94C4B6D279ED772550 +:1068C000326ED0AF2B5A3FBD8DE65D2BDBA60F524B +:1068D00038DAE808A89F4D779AF969293FD3763DC1 +:1068E000F14969E8479E503A11E0ED31997D9F0FDB +:1068F0008E1D4932ABCAB23FDD21F769A0FF77D4C4 +:10690000D46A23B5F3479559551368BF4DC6247D06 +:10691000143F61FE7E97D9FAAD70274EB8270EEF6F +:106920009F10B61EDC94E8B08E7C815BD17FE4239F +:1069300096755291AB975B6FF6FCDED59D684F451F +:106940002699335D743DAC9648265E4FF37EF36125 +:10695000582F974AF73404E8FA88A8E6F56E5ABE2D +:10696000596A6BD849E9163983A0D068697FC2B5E6 +:1069700005DAD3354FCE236483F4BD2DA91A867F63 +:10698000B0CB3A9399F4CB1ED8E71F4EBF4CE77BB0 +:10699000CACDF66BFF87F3BF2227D8FE2E4AEB59EC +:1069A000F4AF8FB233DA59D5B49D55CE46995C8297 +:1069B000BD0FAC17BA6F2312EC879A8732208F6411 +:1069C0007D98DF22FC92850E9A64F75B74737F8555 +:1069D000C8FBB49F97835D96951BC9E3E500776775 +:1069E0007210D35DF220F251CA2404F8AA3BF96A6E +:1069F00039CC4F37D9B8BACCE62DDA9F27B1F98A0E +:106A0000F42DB2849820A7F57B711E3A9F87BC397C +:106A10004CBE5808F99D7F8675A7EBF25FADF2CEAC +:106A2000A93FCB25AA3F01E75C7FFADAFE88700B0D +:106A3000FFBE8FE39F9CE865E388FDBB149809FEC9 +:106A40001BA147E748CC8F22DAE9848E6BDBB73095 +:106A50003824CE2F625E4E78620E78C63AA710E3D5 +:106A60009F0775293D82670A3937C4F65FF399FF9E +:106A700058F8C34375940E56F91F1DB4E56F94186A +:106A80003FF9AB293D2C7CB437D88DFC7D6A70CAA8 +:106A9000A87E28E0532B1F005FC66A185F5AF56E68 +:106AA0008E6F8E23DD7772BEE8E47CE097FBB09DAD +:106AB000BFFAB80D0E015F3036E898871DDE00651D +:106AC0006F90A73BE3AB703DCB2B987F94AC224EED +:106AD0007FCEA781EFC5FE3F1063F2F74689F94BE1 +:106AE000F77A52D156F00B14505AC2399627D11C5E +:106AF00047BF18295E66F1071CE6EB21DBAE81CAB1 +:106B0000035AEFD724B14E02BEA88906ACEBCDB72D +:106B10002A415C46AE7E17E03700E53D29F7941C1C +:106B2000BC5FE0F375C22DE0F5F0794696AF42798F +:106B3000979D67B3DD5ECAD6CFFA97E3374A163F13 +:106B40005656CE5753398F3C9ED6965AE6D75D3D62 +:106B50003EF9BE53265ED09B3D01B7B70AD679CC2D +:106B60001D9B6A809EA83D6CD071FCC148AD751F0D +:106B700075BEB6E026C9224F0235B43F0B3DBB417E +:106B80000FBC97F123CEF19735558C3CFEDD12D327 +:106B900093AF019E554EA7AE8ACF69802F273CA2A6 +:106BA000DD55EEC47D56B8D552E6371F416F7A9752 +:106BB0005AEC85F1EA4B671A709138C8A5F640ADDA +:106BC000BEC6221FF67339744A35F7C37C9C708F9A +:106BD000579FE61B775BC43EEE2F73E3FE08F0F190 +:106BE0004B2E8F7AAA95A557513CCAF150CA0FFB7C +:106BF000CE3893CBB29E413E94B97F4037197F0A7D +:106C00003F83CE61EE3099BF80EE29515FC8A692D6 +:106C10004E81DDD1E36272997E067F4180303FD59F +:106C200044EE2FB85AAC1BABBFAA12C663FE0227B4 +:106C30005EF29EE771BFED9A7ABE908871E92F29C6 +:106C40005DAF3DEC41BB92FC8DD6B6F8CB5EFACD84 +:106C5000EA25B0CFB896FB1FAF24F11014BE4EDC6E +:106C60004D00EFEBE448689685EEEF48EC9C8E749F +:106C700079D00E4FD1FF00CEAB7A3C2F59CFFDAE6D +:106C8000D96BCF5F4D9615813D77F5AD1E92A6F875 +:106C9000B8D661AFFC1EE40AEDF71AD2DA09F4DEC9 +:106CA000E6617EEF3554314DA0FA71FD77BF326752 +:106CB00035E29BF9DBFF40F5B7A1E6E0BA2E90562E +:106CC0004C5AFE9BFE592B3F44A07DBA7332ACA3B5 +:106CD00002E6A771F2C5155D76F8C682DF09AFF04E +:106CE00023E58343DEE732D323F06D4876D9CE53D4 +:106CF000F3C51F88B88319A008E938A90504FDC7A2 +:106D0000A95F05D3ED28EF58DCC158ED6B65C65778 +:106D1000EFB5FD9C31C6EF8EA4E320CF85DFCFAB6E +:106D2000C54D8625EE9F8E8E515E357A793EF8965A +:106D3000166878CE27E0A4F6F242798479BEED3663 +:106D40002F037E5601DF526EFF88F633A5E34639E6 +:106D5000D0057AD21BE887C301E235641BDD37C258 +:106D60001FA86708CA457FB5BDDC6957AF9445FCCD +:106D70004006D759089720ECDB0219D473F5F26B63 +:106D8000D9FA16FFD4A628952B13F2CB3137D10CA4 +:106D9000D82B6A5C5EB8785EC0F1468FAB09D6CB63 +:106DA000262A8ADA6AADFD2AD8EF3079F1375A3EC1 +:106DB00087EB0DDCF7C7A240CFAE24C1388E764FEB +:106DC000FC629877FBB31201F9D55ED04ADC80D71C +:106DD0003262C0F9B05A150FE339CA3129E2AEE088 +:106DE000C204E22A8A9BEE05BF7C8BEC617890633B +:106DF000E84F57032913E2273A3D8968018553F983 +:106E000077160FD0104824A09D146DF6A8B4DD8F1E +:106E10001EBCA219F2D74517CBB0AFFE0CEFE7F5B9 +:106E2000071E9E43287C9D0F054906E5405A017BBD +:106E3000F1BA7E09CF7FD67E3B88E35FF7C835DFA6 +:106E40005802F8F9EEF9C62B286FDB91AFAE7B6CD8 +:106E5000F94F537C3E1AA547FB167EAE968A45979E +:106E6000D3A6EB55F269B093C4FC05FE34A307F535 +:106E7000E275FB0AF03C32BBCE655A1FEC449A2EF9 +:106E80001B412FDE2E33BBFFB5A0D20CF0B9F61D8F +:106E9000BC1CE1EBBBD403F37295B692DF0640EF66 +:106EA000B3F9D17A6C7F71BF2B3D9596BF76FF3DCC +:106EB0004AE53930EE3DCA1A3C8FD882F5049CDA97 +:106EC000BEDD29906F5A955E095BAA85DF7E280496 +:106ED000FBDF8DFBA40CECDB698AFB77AFE176C4AA +:106EE00081980117A5FB06CE971BFAD7A3FCDFD02C +:106EF000B703F5DCC6FD76B947F18A7EBFB5CF4949 +:106F0000B12590FFCE7D2183C2F38781AF8700FF3B +:106F1000749CD50A5D3F1EDDBE2EA0FF5385C3FBCA +:106F2000236408FD5C1BFBBEC4C6EBFFD8EFC03F6B +:106F3000BAD1215FFF007F140FDF6F3C21DBFD879B +:106F400064DF84D3F287AE7DE8ADBB5374DCD71E1B +:106F5000F9E3DD1017B0EEBFFE72F717605D3FE199 +:106F6000D5413F6C7CE0B7777F9EE2F3F5FDAA1B2D +:106F7000F8E3E40FEEFBC61D347FF2F9E9B5209A81 +:106F80009EE3EBFAE4C3EF1419B49FCD3F583409E4 +:106F9000E6BFF9D18593C828F6C949CA4F69D50A11 +:106FA0004F1AFB31F6D3FE26D1EC019E3AE872A8C7 +:106FB000FF5039C0F7FA7135066B7423FD06EB7A82 +:106FC00043DF7A3C1F843CEC1B373CB81DE36F86E3 +:106FD000E33955E2C643EE4C091C1D6FE85F7EF1B4 +:106FE000F975907A6206F4478650CF3ADB6D3C46DD +:106FF000E9796E7EFABD45FEA6809CDCF8E097D864 +:10700000B87D947EA1E1F47B1DFE98379C7E7F7550 +:10701000D0EF2DB2EEAB774061FF8411FD4262BF2D +:10702000B8FED14B46DD579E74ACDB7C786EE17EBA +:10703000C243D430F3C0BA7BE49BDFB8230274565A +:10704000634B80EE0FBD554E287FBCEA19BA1CD6A3 +:10705000E3D00F54BD97B6B9EE07CFA15E3FF9E874 +:10706000CF1403E3A4A86949EDBE9324FB6F00ECA1 +:10707000C00D7CBFBDF1DE60460DE5E8B521BDB4B5 +:10708000C908E1773C27DB9066FCBF217D70856BEA +:1070900004FA7DD853C9EC8434F3E7AEBFF7970AFE +:1070A000FA012D7475D5033D5F5C0CDFF3D153CC31 +:1070B0005F87F9CFB5D0F55EB66EF3ADCF93F7A885 +:1070C00032E845279D4F72FFCAC6B4EBB991E82E4E +:1070D000ECA2F1C62BCEF338FC08E9D3F3638F3D65 +:1070E0009FF1E1ABDA6360BF4EBC6D29A6F219F4E3 +:1070F000544849839EEAF418CFA5803F7EEC21BD19 +:10710000B4497B680E3146F0AF76807D383D979765 +:1071100003713CCF96233AEEE79CF15C1EBA9D309A +:107120002CF01C7A61FA248813F4B8D979E7B68375 +:10713000F308E805482B209EA96D56ACCAE2B79229 +:10714000A2313C0755A246C348FD2B6D73B07E7635 +:10715000BF572FF67BA9EA5E9ABFA9AA2806FB842F +:10716000A0FEADE8419ADE543FDE7DF410FA336FA5 +:107170000EBC81FE72B18FBD797EDE7DF40D9E5115 +:10718000F6D1378D73FF971D3FE21C3FEF3E7A3BF0 +:107190008CDFC5E36C86EDB3F400FA2526F375FDAC +:1071A000650FB3DFCB48660B61764F5CB39E9734B7 +:1071B0000F1D047FE457969E58BDC680F88D0E3C87 +:1071C0001FA1D640DDBBB346E367FBF988E666F650 +:1071D0001189F1739A5C1C0E1B8FC7437DD3C3F4D6 +:1071E0001285E7E135F4CFBBE60EE279CD1974489C +:1071F0000F85AF628581715F53560D5CBB06F9E167 +:10720000BD9DD764F965BEF0B70CD9FC2D37CFFF13 +:1072100060FC0307F8FCE83EFD00D0C9499F9BC70E +:10722000E967C937AED33FF04C6EDC67461A7798F2 +:107230003D7D9A712FB72F0FA19DEA3FE14239B2F0 +:107240007B7908CF3902C41703BB3010305D1E5A5A +:107250007E43398951494A3C2B523F82D0A2FDAE30 +:10726000C4AF3CB47DC3AF7E1C0579B0F39CD6336C +:1072700088D56F53673FEFD8E538EFD855F7C19CF5 +:1072800077EC7AFFCE3BFED3731AE71D52F056F42B +:10729000C378C779DE119960CE74C5800C5F5EF843 +:1072A0009368EE9C23A85CB7909D73103CD7285040 +:1072B000EE6A4FD1FE2325E6C350FFF6CE3B1646BD +:1072C000E0DC630A2BFF1394A3DD6FA660FDCF51B2 +:1072D0000DE41335A1BC08FA5C2D4D31BF50940C60 +:1072E000823D27FCA76A7322C3E32D2729106FA6CE +:1072F000F71C8465A44459DCE5220890A7747BA39D +:1073000094E079623E7C7E99C757F650BD025B07D8 +:10731000F54AD203FAB92BA9E3F79B9251FCDE9D03 +:1073200034317D86C4AB148CA361F1597BB95FA560 +:107330005D212D901E11F18D0AE3F75CCAFC2C87AC +:107340005E508BAF04B8023EB443F3C1D599AC8E06 +:10735000C1F83B93314C6F49D6C7100E57DA80C342 +:107360008EF39492768DE25997F462C877CA467B81 +:1073700023CDFBB85E938C1931D9221FE72B4CCE5D +:107380002A6627DA498AC9CA757EDEEF1C7F41AEBC +:107390003E9E5F2A3AABBFDBC5E6E7AC7F019F6745 +:1073A000CFC1C7516FFB6319E64FA7FA518673BC73 +:1073B000833F2660E7757932186FB6A78CC440CF3B +:1073C000AB6D35BCFC7E5249DB2DE5FDF8EA06903D +:1073D0008EC1B63A2CEFF2C63EC1FDEE3C2E98C5EA +:1073E0004D7679088F0B367AB7D2FCE5BC7DD0A0FC +:1073F0002C4EEDEEC2B60F23DC725D6A80C78D5F46 +:107400000EF4234F39FDE3CC2F5EC2FDE925F501D3 +:1074100013ECCC92F9450BC02E2B31CFC2B893920E +:10742000AAC06ACCD7175D01F92FBBF4A58DE81768 +:1074300073639C77497DF555ACFCBC6BA03CA514EF +:10744000B0F3F4054DD578AE953D1F1FC0736C5257 +:10745000DFE4B69E5BEF8A558647DBFFA0E613723A +:1074600013D7A50F7C29967CA1233FD951BFD251B8 +:107470007E96A3BCD6966FE3F826750AD353FA64BA +:10748000F4CFEEE475C8D064063FBFEF7130F480EE +:10749000F6620D4B5FB2F05537CC6B1479B90782A9 +:1074A00066299E4AA8BD462C762CD17C39782A11B3 +:1074B0006FE85751E5C6149CD367E5451D95173312 +:1074C0006CF222653D6FB1C88BAF00FDDFABBCB87D +:1074D00089CB892E2E379E2189FB40FEA8F54C6E64 +:1074E000E4E442AC05E4E14F3BAF5928CF43B98017 +:1074F000E7BA24754D3BF86D3437CB3FD4F9A985F5 +:1075000020FF845D2AECA69BE87A81F5006945702E +:10751000B85D1A88666C76A9F86EB147C747B77927 +:107520008F31BAD114E816E27261C718FC08FE1D4B +:10753000707A75527C40EAADF799B02F0B7339E43D +:10754000A5EBC7B0DC4B185018BDC08F62A5B31AAD +:10755000B5D09958E84C1AED7AC141678AB730E046 +:10756000AD28C3E48B133EA5ED4CB6FE29FE200DDD +:1075700044630DB0EF1472C4A3EBF7807FEDD6E542 +:107580001BB6809DB06D42E14CC0E72B5C5E93FD65 +:10759000F67337D12F9523AF001F7923AD849992CD +:1075A000EC1CAD28E3C5900C9F41D25E17DC03A014 +:1075B000722C08F6FF400AE49E1C2506F89764909A +:1075C0008BB372F352400ED2BC5B3305FF26C8C8A2 +:1075D000FAEEAD91F49D530F093867A84C1E8A143A +:1075E000CEF107475987E21C5FE0D5571DC3F8F17C +:1075F0005D1F2318CFE25BC2E2EB3BB95EDAE389A1 +:10760000BDD801FB8299EC9E4B17E829F8FEE4E314 +:10761000B89F0AA80C8FFED23E027CEF976315B08C +:107620002E52F2CE85A0AFF678993E11F5051C9149 +:107630006C3B462F279C513E9F9D79F451052FCFDF +:10764000C6E1C4981E934B19FF9454AF4451281BB4 +:10765000ECBE15A567850A7AE1B05D2FA8EB7A909C +:10766000BEBBB85EEF3EF83CAEC760692BC6CF9F8D +:10767000A5BA6C71A5BBBC8E7A548FAD3E87D56F11 +:1076800040BEA37C4DBF9FAB3279A772FDA6819E01 +:107690009A70FA7C3F4765E73B1A97831AAF7F954C +:1076A000C79CAB5ACE433AE3EBE278FEA6F1FB90DF +:1076B0005A28E50727FA83C3CEC14D15E27F484F0C +:1076C000CA55913B2F1E7E5FCD1947146FC038A25B +:1076D00008B3AFA95D7D018CAFC6F3C41165CF9728 +:1076E000995DDD0D767545CEAE1EEF39F3E9DAD53D +:1076F000E33D3F1EC5AEBE4A9D3DBC7FA75DED0D7F +:107700003446AF26EFC1AE3ED7FCB31BEC6AF2E3C2 +:10771000853F81F8A1E9E6C3900F440E2C84F8BAA6 +:10772000C82CAE47C84F17C27A8ACC25A8E23FA71B +:107730000EA01DEDF19A37007CF7837149E9E089CD +:107740009B26DEDD7C7064392652CF24163FD05153 +:10775000B052C7380207BFDCCCF9D51947F07EF527 +:107760003F427CC26ED5129FF08F9ACF0EAFF95573 +:107770001BFEC6195F41D7D1FDC0FFCEFB5359FE9A +:1077800037B2FE21CD1A0FD0658CD72F9446FEEC70 +:107790000EF476555AFC32DDD579FD42DFB3F2ADF9 +:1077A00073FFDD356EBF101F3FE21C3FAF5FE87F08 +:1077B00031B9447A006F0AC75B47C1D588D751E217 +:1077C0002B8EAA16F9AA441DF115EF53BC8A33CDAE +:1077D000E73F7959CDFA315E5647F0638C57CEE4D6 +:1077E0001BD7E93FF94B6EDCBF8C346EBEF8854089 +:1077F000452C8E7660B11BE3EC3AE7C77A40EE7613 +:1078000096B995AD15B97B0E629C1A6D0AB6EB88D8 +:107810002A6EF057771C5E84E7319D9ED6263CBFCA +:107820002C70EBBD15C3E19EACB1F339A9CD3FEB94 +:10783000DE51FC7292C2FC701DFA9308977F66A419 +:1078400000EEDBB51FFCB7C312ECEBA245155E9A48 +:10785000AFE7FD41F0E26F2CE7BB845038EAF07EE1 +:107860000C01FD23B58570BCB1E05334863FA9CD32 +:107870003BEBDE51CE85DF6FF8041E276A06C74F4B +:1078800000C71778F5803144E9D55123E3F98667BD +:107890005065F7BE63EC1EA59023728D1BCF1FA908 +:1078A0007C99A3C1B807ECF2C7136076A84B63F1CB +:1078B0006492B755033E14F71B020919F5943FC1B2 +:1078C000F49598AFE013BF87C58F2A0119E32C34D4 +:1078D0007EAE239D9F8963BCEFCC2A37F0CBBF736C +:1078E0003C769A6C5E9D87D9B95D0FC4C5D5E4C658 +:1078F00021A4EAF65575E03FA8ACEDA653BF96B7B4 +:10790000534800E7A7703CA8275693725A7EB1C629 +:10791000CF2B2A4925F0EFA6864D3F62F66D4A1D12 +:10792000E9DC235FBC97D4C0E2BDC84C268F8851E8 +:1079300037861F919D030B3A08FCCB35ECFEA5075B +:10794000EEF1C0FD3C93D263468E0E59BBBFDF699A +:1079500047313A1383C5654B01760F4A21F297569A +:107960005558E7CFF856CC7FA3C6CFF1FE1FCDFF09 +:10797000329025A06F0F9D79FB2A884330DD312F8F +:10798000B42FB5F3B73F20E3799BE02365F0FA4CC1 +:1079900019ADB7FD9F057EE374E3E1D9F9F019F065 +:1079A000278C43AEB7DD2B3C83DF1B157E01BABCB1 +:1079B000D0BF5C5E2F231F9C51BFF57A7788B02320 +:1079C000443A64E9B5249D62E5881FD1BEFC8BF67C +:1079D0007747C257DAF393799C7229B17CA7FD4CA3 +:1079E00086F8B119506EFF2ECE011587DC16A9F36B +:1079F0001CF07BDA7B8B276E216606E54C94C98FE1 +:107A0000F672627B5FC089CF2283DD0F9FC4EF8750 +:107A10002BF3D97DE04292403F05A967716332970D +:107A20002BA2FD4FB95C50C99B26CA1F3288F72D87 +:107A30009CF41074D86E303A00FD8A6979015F7742 +:107A4000DB391DB46282F18105832C0E8F34F2770D +:107A5000445CC485F1CFF3EDF857F83B31853CCE5B +:107A60005B73E05BE1717C0AB1BC4742BFBFA1B967 +:107A70006CF1DEF9F0E9A4C76B821E4112B4BD239C +:107A8000A38FCCB7D9F76304DF8E73BCFF14EB323E +:107A900040C79BF21EC6CB536FF87AB2D36B31A7A7 +:107AA00057B741F87D1EB204E855CCD75B779D9D52 +:107AB0005EE29E3BE1EB43A3FF01BD2635DBE975AA +:107AC000BAF411F7A97FA8C5277B711F61B8F03DF3 +:107AD000962BFDE807D3B27C75E0A04261D95145F1 +:107AE00062B025D806420FFC0AD71E4757EBE4CAFE +:107AF0005EE6A7855C11D8110CFE1DD165A3FA3393 +:107B0000E1FD0678B7E72678C7677AFE7A212595E2 +:107B100000BFB61265EBA678B3817673A89EE1A785 +:107B2000B4D1E885B97CD2EB12FB6FDB3D665C0912 +:107B300096F7174A6B59BBCE0A92067F787433B317 +:107B400023681EFD43059BE58C87E6A3B1C5BFC72F +:107B50007D8C9C22B00F893AE45241EBD3CD2E0CA0 +:107B6000B6B3E095F26B81317439D2A9D1FE3E4FA4 +:107B7000BEF99D6E0AE72F2F4DB5F255BA09EC2DCF +:107B8000ED988471B65A3D15852148F522185FABF2 +:107B90008F05301D6C6862F97837947F8ED34F2B38 +:107BA00065F7ADC2C3E2B546C65F18FEA884F718F4 +:107BB000185E041C61075F39F1E1CCFF77F1007CAE +:107BC000F392E55EA658276F6D266932825D2BD24F +:107BD000B25332C9507B2238BFAF0BD7558D9B00B3 +:107BE000FDB5F9ECBDA63BAEFD39C65B2886EE922D +:107BF0002CFEED762FF3B3290641BB8FC8866B7937 +:107C0000D05ACEDE59F9A1666EF5A2FFF08006FECD +:107C10009CA09C6986F51D8C2904F45EB04561EF3B +:107C200046C0FD298BBCA8F07A6CF1125979112558 +:107C3000836ECB3E50E8853BB5C46EEFC4DC3D247B +:107C400025CAEE0309BFA5F0930FC75B1FFAE585B0 +:107C50007FFEE624895559FCF4E17AA2039F84EB68 +:107C6000751DF8245C6F14B27CAC10F2FBF979DF5F +:107C700083FCBC2F9D34307F77B21AD3BB9231FC8A +:107C80007E47B21EF37BF979E0EE6413E61F48C627 +:107C900031BF2FD98CE93792094CEF4DB660DA9B92 +:107CA0006CC5F4B1641BD6EF4FA6307D24D985DFB7 +:107CB000FB923D98FF56722FE67726D398EF4EEE53 +:107CC000C37CB87E49930BE1F6E1B9A84EF5AB6DE4 +:107CD000FF77A517FDF9226EFEA9176ED0004FDBC6 +:107CE00079FC7C3EBE71C633CE1BB4BFEF704E5FD5 +:107CF000A12D5F919A6CAB7F465BA5ADBCACF52C1A +:107D00005B79494BAD2D5F9C38CF56BFB07181ADCB +:107D1000FCEC7D17DAF267A697D9F2D3F77ED2D6BC +:107D20007E6ACF1A5BB91265FBA5295DD7D9EA85B2 +:107D30006E49A09C9D7B7C93EDFBEC81CFDBDA9FB1 +:107D4000E47256AFA72601C4619ACCEE51EBE9EA82 +:107D5000817C690AFDC8B43C0A7915E4D2B9580F90 +:107D6000E942CBD9FD06D263C2DD2FB99EFB9F4FFE +:107D70006C1FE0EF709D447D74CCBE6FF010BA9F15 +:107D8000A8C07750589C0A5D279F8038554DC67A09 +:107D9000DBE120C0A0FDF8345C4FE25E2089C9B869 +:107DA0000FE43A364B57AD9464BC2017C53D343AC6 +:107DB000D0BBB4CEACC32C2FE63B3363CF9FBBDF2D +:107DC0009E0FC6EC797FB53D2FCE89882C635C6B06 +:107DD000F8D814DCEF117EEF59E3704DF5F17D63B7 +:107DE000323D17EE7909F8158A677D06A4464407E7 +:107DF0007D53C7DEDB11F7F914BA5E0D2C8F1542E7 +:107E0000AA996C5EE1131F3D0CEB41E3F6B31AA592 +:107E1000FD5AE8A8CDB7C3A944D3C817AA037EA7C3 +:107E2000BD64F81CF1B0A7692F9FB69DC4EF8BA865 +:107E30003A273C8F1BC790646A9F79CAE438C8D13F +:107E4000581D31EFA169A99C715D6F9177737CCC4E +:107E5000EFF03B9FC1EE7B93DD0D68CFC98962785F +:107E600077ED367E4E51BCB9F5D737D6C1FB4B9373 +:107E70006D71D697733A3C59EE43FBEC334B997DC9 +:107E8000361065EF44059B08C6250423328178E847 +:107E9000E07115F50EA933F0BE30B8FA00D657934D +:107EA000A4F6CAA9705F43C3F4B5A48EE9A1F20B8E +:107EB0000F7E8456DA541630C04EF79CC1EDF602A0 +:107EC00005C7F96BD9D51867A3265BA3E02F3899AE +:107ED0008C62BBED07CF74C1F99D6A9E6D3BE7A430 +:107EE0006C22D1BD03856B00E3DDD5435ED46341D5 +:107EF0005DE9F55AF4588727518CEFAD7D42C17D7D +:107F000046715D8F0BCE67767B99DDB3DDD75A0D59 +:107F100071F2DB2BC9A7978EA03F3EC4F102375BFD +:107F20009522DC0FE0BF58534F430874F0952406A8 +:107F3000CF4C79B6D1E50CF9D97A1F9C77956A3D7B +:107F40000D60A7945EA91BED06D467EF2709FA78A8 +:107F5000BC24FE7000EA313ABEEC63FE99E2788FF1 +:107F60000BE8D6FE283B677BEA854B75D0AB6F44A8 +:107F7000AAD0AE7CFD31D504FFCAEB85ECFDA8D7B5 +:107F80001F9BFB34C89B3F260F175AEF57BEFEAD11 +:107F90009FCDF15082BCFEC8CFE6C8C844699BBEE5 +:107FA0005DFFEED13920F7520B48752B4D37EA0AA9 +:107FB000DE63DC086B80CD0BFDA7B715299DD07F54 +:107FC000D124F74D904E0854209CE29E0821890A46 +:107FD000F463CBBCDD610FB66BFFB10FFBDB34B5D7 +:107FE000EF10E065D3221DDF4D6A2F30DA03101742 +:107FF00051C1F67D9B2E48A9E550FEC2242C2FD0FE +:108000008EE23D5B25D30A6425BB5DB14310F2953A +:108010009A4AF01C51F807DEAE20D51554BECA0BA3 +:10802000FBD0AF36147413881FDE219B5210ECF680 +:108030006A82FD8506874C101FFAABADE782DD7EB4 +:1080400083D4BA1BFC2D53032CEE579CD36C79E1DF +:1080500086E9A3D911227D02EC073AFE93490D531C +:108060006A1FA03D91494631BF276960FE8E643585 +:10807000E6772463988A7B2A13F97ADECDCF654BA5 +:108080000CB70971E01365A2C1FDAB92133F6A867C +:1080900038E5123AE530B5D9E7F3F7BEE081366846 +:1080A0003F5F67F2EFFC08F3379C1F65EF0109F9AA +:1080B00021E4C5FC37A9BD68F39BD37C359F075DE0 +:1080C000F813D7D9CB777BFA70BF93BA80E1D9D9AF +:1080D0003EC8E12BA4E6A4543BBC3F2A1F6CF57BB1 +:1080E0000C77CA73EEF8EDDC3B1D76EE6DEBE96CB8 +:1080F000291FDDC6E31FEE5C3F27BCC6429FBB1CA9 +:10810000FB83BBAE9F1386FB6BB75D4F0C3D6CE9E9 +:1081100087B7BF2B79B8A8712A5FC4B03E37B37355 +:108120007E51AF34C5EE7D887C4FABDCD48B7A3783 +:1081300081F77AB7814CC7C73C262E324BB15FCC52 +:10814000FFC6377B119CB3156F66EBB73850D181F2 +:10815000A2BF8EF4495CEE204373B98EF62DC5DBC9 +:10816000FF340B1B75C03BAD0760297509B280F663 +:10817000F39186DA8332CA13FBF7275C6E84AF383B +:10818000DAE35A40D375BEF89B3E38AF2AAC6FFF96 +:1081900036ADFF66BF6AC078773CF90EC6CF77BCB4 +:1081A000A368B00E8B0FBC8871F51DAE41055C9ABB +:1081B000117FF722883FA1F2F14C50AA117FB453EE +:1081C000A67AEAB650E27EA664BB173D45E56B9100 +:1081D0003A7827D40FF949AA89CEF709CFE0A7C08A +:1081E000B9D2483AB7691FC6F21288DF53697F5D7A +:1081F000F36939E8048C67E9D806F879A280E523A9 +:108200003BDAB7A5683EEC67E7D324C0E44636AF57 +:10821000D3BC657F91FD2EB3EF4463A998D7FA4391 +:10822000EF3C5D02F72C0EB8FA2054A5F8C06E178B +:10823000CCAF78FF6E8C4BD89F3CAC77083A0B7C68 +:10824000D3253F0FE27FC0FF9C76A52B5DB8B5C05C +:1082500077808A6B4C630BD02BED8941084E2AC086 +:10826000E4FEBC41DA8F85AFE7C9FC5DA33CEF1F9C +:10827000A11F03E8B6939DE7EDAF4FF967D0FCDA95 +:10828000D555B55B285DF69BB736C07B261D8F574D +:10829000E07D9757FD2EBBDDC6E3715E73C4E3AC92 +:1082A000E3F1389EAD8C3FD756F415D5C27990973F +:1082B000DD8F5A5BC0F305F6BC9033FBF5544121CA +:1082C000CD6FD8BFBB1C14F506D27339DCC3213F78 +:1082D0009108ACF7DF1F9C17FE10CDAFA779D82A05 +:1082E000AFEF9F7921CC63FD4EB71B40BC88C3B96B +:1082F000A19FF25100E20E29C02ACCA7E76C99D2C7 +:10830000BF6767E3626F19218F579ABA9BD2FCC18E +:10831000C0C59DDAF934AFE8679299905FD909FC3E +:10832000B6F602375F3F2B9F36657E0F87E62FDA62 +:1083300071E736583F75CD1ADACB45EE389E179265 +:10834000236ED413C00AF329DEA5820EAD92C2F5C6 +:10835000A76D6EB447E0981BEEE7D4C9E4B04CD3E8 +:10836000DB1446C754A78CEDE8F72E4F21D0A5C7E4 +:10837000847B75A48BC9B7D907548CD7AB6B35AF49 +:10838000457FA03E1FEDE57292FD87F1DF67102665 +:108390006FE7EAA441A6F5DEF133FD57D7BC722D95 +:1083A000B49BB27AC533262DAF77A55378EEF83C4F +:1083B000D36BBE1DEC9D57E96781D816FAB9DFBDB6 +:1083C000E06CD0F3FD5E463FA920B1E33FE03CA85E +:1083D000A08A607941E28F706F6868A266C03955E3 +:1083E000C7A03BA586A13CA6031D032037F07CFF58 +:1083F000D82213E49992B81ED6E53EFFB16D10EF76 +:1084000049F13E45A378BF6FC7D16D1AA543FF164A +:10841000B344B7E4E7FE9D4A695C9747B799749DFA +:10842000CA05B7AC85754ECB7F08FEDCC70BB95CBF +:10843000E3E5759542CE517B9DCA01690B5FD7700C +:10844000404DE57E9DA57E235DD79E05ACBC838E09 +:10845000077484FD4B5B21CC8BEE93605E67CA6929 +:10846000D0CF4033B85FB5585A75D139F4BB3A957F +:10847000F9D77C054C1EFB0A0CF497533C611CC8D1 +:10848000D0B38134E0C357D0DAA342795915DE93D3 +:10849000F4A7593F9002FDFDFCBEA94B5F8AFB1972 +:1084A0006FF5E8EF19C97C7F203BBEDF5D611E2CB4 +:1084B000A3EDDB0697A21CF9AA9FDBFD65ECFCE2AD +:1084C0008678EAA37075E5ACA1BE0560FED49C1A5F +:1084D0007812D219E4CF0B406CC6B48243903EE0D0 +:1084E000674C5BABCF5C8822B0BEEF10BA858CC105 +:1084F000629063B3A5743BF85BC2F3FB241867D2A8 +:108500006555E33CE7CFE039FBCE801BDF736D0F91 +:108510003CA2AFB6B4DF16E0716A5C9E78B8DDD0DD +:10852000467A50FE50DAB377F5B87CF1708779F669 +:108530001D6F3DA6C33DBE86601DDAA12FF2F52F4B +:108540001D9C7731EC07149013B4FE5D5EE6C71FE7 +:108550002A267D10B72B474D8271743C7E75331FE0 +:1085600057C80B880734A713F2E8C7A72D003FCBE5 +:10857000A31F2F5A00FBBB5BB2F1AF438A781F12D7 +:10858000EF4F648EBADEA5F8FF6E931BDC56E46BEA +:10859000B2F95C09ACEF010FCAAD3D05767DBD397E +:1085A000C0F641DFE7F0527D8DF2707B92DD0F5413 +:1085B0004EF9499ADA972B036C3FAF26AE443E53EF +:1085C000A314CC0AD837A65280578107ADD44DD218 +:1085D000D6FDE2A910B6FFBE9FE1579CCBE78B53B7 +:1085E000D8CEE1197E0EDF8474D99CA50B93FF9B36 +:1085F00083E62490D38F2F60703BF9E02D3EAE725E +:10860000CA857088EFEF707E13EFFD28A7642C17E2 +:10861000F315F572E56C1E27758DBFE3CCD6ABB2B2 +:108620005F62F664541EB2DE9FF6C3FE614A6E9D21 +:10863000897BDDC3E7111B80384752C5E4ECF07538 +:108640009842BB47CC5335ECE5CEB8A72CDCA72627 +:10865000D8E6F1C0B0F9166139E813BCAF29932F01 +:10866000831F603D8FEB592F51BEA2F077FF84DD51 +:10867000833F29F63B07D8FB70EBFB77F3F822C367 +:1086800016B7B761FFF5E867DCF87220E5A6F537A5 +:10869000805CA6F8EACE0CBB4F9F293172F55F04CF +:1086A0005AC3FEA2ED9B73E15EF89B7A4B31D81F53 +:1086B0007E99C939D2ACA17DB0DBCBF63FA917A614 +:1086C000B37330FA3FF60E22ABE787778069BD3B84 +:1086D000F93E34C2FBEDF09AC7999D464C390AF138 +:1086E00032423E776F83F5779B42B2F21AE2676FB0 +:1086F000F3B17C3CD0BDAD83D90928BF23FE299DB1 +:10870000A9F96847F07C7927D869B729B143B07FC8 +:108710004D3DA61A00276D6FC23A4F7DB21AF7770A +:108720001D156432E0EFA90205ED9D8E47D55ED898 +:10873000D7AFF325C27E0BFE5E2FF87939A919B1A8 +:10874000BF94ADBFB2F1F547C7EF779F9B2B7FAAD0 +:1087500060CE2189B543FF02291D285F4DF3458F67 +:10876000A9784E7097C72E27447A4D40F89F74DB46 +:10877000FD6105E402F027694DB1F7B30A6D72405F +:10878000C807E55409495BE2265EE4F6418E2FCB2B +:10879000B1FCFB9C6E9D49638C712AF38C73F618B7 +:1087A000E3CCB08D03123CFB3EED28E70FCEFB6718 +:1087B0004E792A52214F9F85FE69FA0B57A23D4000 +:1087C000C7B96EB06F31888BA5054D65B0BFAEE4FB +:1087D000767BFDBEDD87C03C385F8B3FEA9FCDE2F4 +:1087E000A5F09D2835FE8A353FDE75F56080707FE7 +:1087F000CC30F9C9D615F75B6C0EC62E84FCE65D4D +:10880000957A6A94F311A77CBC68985C6172F2FD5A +:108810001B4FB2D171F8780A96E7F4618258EF8362 +:1088200088F137179B18276459E726AC7378C39AE9 +:10883000DB6D29900B7B4479EA9A4EB0D31E5772B8 +:10884000E504F777B9F6F00ED71E9FA8BFA9B3715C +:10885000FE08F5FD8EFA95A2FE8D58DF098F903B3C +:108860009007BB51FEBB9AB52B01BEDD6E477F85DD +:10887000A2BF2EEC4FEC17E6EED8F374AA0AF8B3B9 +:10888000A701F4FFD055C4E825600FC47C318B9E4E +:108890009CEB677A5D39E5B5E13987DF007E2751CA +:1088A0003B3D37BFF0D151DF17F85DD2FEBEC0357A +:1088B00089CD78BF79AE9FF1690BDD7140FF2D77CF +:1088C00049B6F5FB2F78FF59E03D338F1D54C3D6D1 +:1088D000F73F1DBCC579E02DFD87C2FB7958BFB4B9 +:1088E0007CAB8FC9DD457AEB41B80FB3C870C5E0EA +:1088F000E9FD45B4AE97AED98F426C064D17C92439 +:108900001540FB25CDEAD33CF84B2EFEFB675EFEFF +:1089100008BE7F63A21C53F918E23DF0EDA5CB46DB +:108920003D4F11EFC574F3DF3F72967BE1BC09FC4C +:108930001DD33F4EE09E921C484497D1FCA7834C28 +:108940006F1D2C5E1C053FFAEDD337E0BDDE8EE2D5 +:10895000395190ABEDC1AB6DEFCA2BFCF7949CFD88 +:108960003F15E47116A73E8AF04B3CDE633BECBF3B +:1089700046A82FE2CFB66BADB84FFBA0E6F785F760 +:10898000697EC52136BFED5A02E3433BA3EF17BC16 +:108990001F262F215C1FCEE07DCCE0B44A38EFB912 +:1089A00085E353D43F189C8370B7172C8E025F76F3 +:1089B00014CCB1C12DE5817B4188CD7FBBFE8F8179 +:1089C000FB018EEFFC702F2623EDE3E177B1467AB1 +:1089D000A76CADC07B34817CF241C3FFE498781F63 +:1089E0001FFC7FE2FD5D1864E757DB0D3BBFC3B69C +:1089F000E2C3B5F9D78D33CEC05FEDF81D892AC328 +:108A00007D3ABFEBF05A92C5558DB5CEFEC0EBBD99 +:108A1000CAE3AFAEEB93F07C655D298BE31D6BBCC5 +:108A2000759E4CD168F721D6F749B6F98C05CF551C +:108A300041760EB5769FBDDDB569BF1D0FE2DE56EE +:108A40007493067ECCB74ADD04E2CF057E87F1C180 +:108A5000FB8CD7B1F8322F5EA32CCEECFDC6EB58C1 +:108A6000F05C18344E0BAF4E3EFDA0F1F8FF1B7FBB +:108A70007E01F0387B6C3C0A7AFC8B1F47AE7FCBC3 +:108A800069F2E3BFF0383A3C0F9C263F0A79B98F70 +:108A9000DF7B9EFE95CD472EA07AF068D3AC59F8C7 +:108AA0005E936C9EB3FC1C427E1662718CD3B91F20 +:108AB000D739DECFB87D71A469E17A8CB78CFB31F0 +:108AC00086F8983BF61F75E0B75B26A19FD3D9EED9 +:108AD00008D7D3DF0E15887B05C1D9B4FDB267A5D1 +:108AE000DAEE51E8429A245BFC2C9CA4D8E24A1DA1 +:108AF000F83E428C5D75E0475B32321C82CEC7E2A5 +:108B0000CBDF1B9DE3D2072277C682E7EE50E569F3 +:108B1000D239CDFCA224FBFB3167B1DFD7343C70E6 +:108B2000CEB2EC848A717ACFC227F63B5ACF87281F +:108B30003D9635CD64BFFB267ED75126183F74C5C0 +:108B40002D67A2BF95AC588EF55F0CD9EDBD2C9D5D +:108B5000047FF1DF719BB42AE5596D994F7558F880 +:108B6000FD5BCB008E7EC53CFB21DAFF918FAB31E4 +:108B7000D8F7A9CB97EC803895639F287059DF7B95 +:108B8000F91B1F6FCE2A66EFF61F4F78DC167BAC01 +:108B900038CCCA69FBCB0647C0DF296E4FAE4CB854 +:108BA00078DCAE59B6CC72AE5E19B6973BDB7BC3B0 +:108BB000212C3FC6E3259CE5321FBFB979F4F6644A +:108BC000C504FEFB68E634EBEFA339F1F73F4289B9 +:108BD0006098F6F79CABF585CFC27A6AD0908F8902 +:108BE0006CCC00B8051EE83EB30B7E3A54D0E9E2E7 +:108BF000921AA49380478C0747BC702E5867B2F333 +:108C0000E2421E973477A737BD05CF2BF8EFAECAE7 +:108C100014AE208E5F169E987F7CD16F44261985F6 +:108C2000F6EB53CD69E09F74CE43D43BFACEC28BB2 +:108C300000BEFE236E7D6BC5F0F93BE5D2B4BD7678 +:108C4000BE393FCCCE7722DC8E27726B59B3857E3E +:108C500073C35E6C3F5E7E7A0D64354DA7DDDAEA44 +:108C60003168BF97F2DF5180FEADFCF15BCE3FB1C2 +:108C700030E170A47C67819FF339265FF6F57EBEF4 +:108C80006CA4FDC1112E375E0955DBD6CBF225331E +:108C9000B7C14F7F527E2906F1D57FE4BC325877A9 +:108CA0002B65E6D7DEA7B496CD043E578CF5E0776A +:108CB0003EDD79087CE795A31CCFFDC7E31ED8D71E +:108CC000D4AC60FC7AC98A83EEF534BD87AFDB177C +:108CD000A1AAA59F3D7C7DEC5312EDDE18212DE16C +:108CE000BEED5DD5B8CED12FD915EEDF0EE7DBA4F2 +:108CF00083BDA3396DC59F3783DFBB5F617125CF0E +:108D00007E2988F72B28BFDAFC2091156F27215E7A +:108D1000608D129BC61E0567F2E919925807FC2761 +:108D2000E4D430B9D4B15CFCDEE5342B9D72F3643D +:108D3000EF400A7EDA975E16BEC2C24FF78615DB99 +:108D40007EEFE75CCE1F75EC1F571C67FB3B3A0FAD +:108D50003C0FFDC5F965F7C03C222D6F27210EF7AA +:108D60005ECE976FA52B1F83F98AF98B79AEE93D0B +:108D70006F1A7CBFB45972DCAB60EBED92257EFBC1 +:108D800077DEBE5A32D7A21FFD22762E24FA8B340C +:108D9000517CCD8079C5B7062B727816F85CA31A82 +:108DA00057677F4789C27B456FE01E7C77A27DF0C5 +:108DB000B3C0476F06E2E1420B9F7E356CDFF70AD6 +:108DC000FD0CF5406F2D930DCF48FA6B799334224B +:108DD000DC8A1A7B858C70AE9295070E7DA9BB7BD1 +:108DE0003C50BF99B4627A4C1AC2F404A787687FDA +:108DF00082648273410E3549781E78A27539C6BBEC +:108E0000ADF2F4056B69FA389777BFDC2CE1B9FF56 +:108E1000AB7C1ECEF12E5B27A52EA5FCB62ACDF489 +:108E2000F7AA75EC5CF7B256FB7CE8FA3B72018C52 +:108E3000F7EF6CBCA3945DEA31C895D915BF4E1706 +:108E4000CE84B8EDA3807BB03396F9C53B1DF83BCB +:108E5000A009F62779BEE98A1F425CC4FF0EB373EE +:108E6000A9A34D572C061BF69ABDE4894103ECA734 +:108E7000D1F57DE28B924DAF4FBBD5FE7B7E73402B +:108E8000DFC0BA933365975BE4E9D9857EA6CF56F8 +:108E9000B846F40F9D0587CC00CF7F492D23D977A5 +:108EA0006621C3E7257B476E6F160659F95D23EBF4 +:108EB000BB2F15F8B93EE92B03397F49F3C8FD7C78 +:108EC00053677AF1C4FADF5D06F153C7DCF6F77831 +:108ED000EED6197FA67466371CEDFD7C6731D06530 +:108EE000834B87FBAE6B261828373EB56E26C6A58A +:108EF000FC1BAFFF9160FC4DD09F571FDFF434D4B3 +:108F0000EF5F45622E23270F9C70FC8DDB2542BF4F +:108F100050BDF632E8B5083C6100F24A4EC7E07E2B +:108F20000180122E04BAA7AEC3F7B27B7D3AA33BF1 +:108F3000B57B69E5FF0B2A204AA0008000000000F5 +:108F40001F8B080000000000000BED7D0B5854D76C +:108F5000B5F03E73CE3C80016660863738233E50C4 +:108F6000510744C4C6C700926024C988A2F84AC702 +:108F70004708464092686BEF4DCB206890BCC8A371 +:108F800086B6E666A09ADA246DD0D2D6245E3B1A65 +:108F90004DEC33C4476A1BD390D69A688C2169D2B2 +:108FA0007AEFF536FF5E6BEFCD9C7300C136FDFEA8 +:108FB000EFFBBFDF7EFD76F69CFD587BBDD7DA0F59 +:108FC000FCBF95735B09219FC3BFB984586C122104 +:108FD000CE70DD7F9F4C421682FF3EA7FFBFB33DA0 +:108FE0004A5327635C06924FC866FEDB3BC4534B73 +:108FF0001C8404CAA26C7BDCB47E9F1C9A4BEBBF22 +:109000002B8BEA90DDE1712F3510121A4FC8C9B2CF +:1090100069B5248F90CFCAA20CB214FEAE2F2FF2E6 +:10902000F6EF3758B0BCAB4B0E986308A92963A57F +:109030001E0E7DFF1A6328C1661D7AFCDA2EBACE99 +:10904000ACF0BA4E962D8AF55B01FE69D16B06E94C +:10905000976BA38B994EC886BDDA7EEB835AFCBC16 +:10906000731F1B67A879DFE1EB3A0FEB321372CA6B +:1090700040AABBB269E95B14BB263BDCEE061D5D72 +:109080002AD769E75DB2523BEFC9BFCBD55D561811 +:10909000A72972B5157EF58CF34513B217C6877AEA +:1090A000F33442660E0D17218DB83E01CF8952066A +:1090B0000FFDA7900442165170888B90320ED7890D +:1090C000D269D1FEEC81EB3969E8FBF50CE087FF52 +:1090D000503C7B68FBB1EDAB8F24BB109E5FE7D1AA +:1090E000DFFD9CFF2A75EBFB47F98F34C713923CD9 +:1090F000709C30BF5D9B1EFFB7F86C683A0447C494 +:10910000670E99D4035D57285DC699940E2B6A7239 +:10911000A4F5B4FC38D682FD3F8E7561B982106F1C +:1091200017D2D195BF70329DBF33924854FE02AD25 +:10913000D1C1B194A54F954F1AA7866727D085F660 +:10914000ABD8B56F1B452BE507DFC34EA0E75764CF +:10915000B287D6DF3EB37F1BD4FFDC63B049748A8D +:10916000259585D1D3693DFF949C2BD3FAE3363BFB +:10917000D2B562F16AA37A5C3DFF56E8F8F77F3911 +:10918000BC251612B0E602D7F5E5F92687D779E7B0 +:10919000AED5DB93E93C15358FCE8479EE6C3F6C10 +:1091A0009C407FDF66B3E07CDB6D2E2C572A7CBDB4 +:1091B00016BA5ECAFF6F01DFC27ABF2605F7C07F0D +:1091C0002BBD46F85DC0757BFD7B255E6B98EFC5BA +:1091D000EF47397FBE6033205C73A3FDCFDAA6E38F +:1091E0004F81D83842D6C8F5854EDA64B68D68E02E +:1091F0009EC3E130993DCF90CCF03AFAF158C7F0D8 +:10920000F8D699F26DCEBCA1F1787008F9180E8FDE +:10921000A73A23BDA88FE730FA769B4800D67F7A1D +:10922000477A70AB3B0CE76C0EA763F1DF1A6C5307 +:10923000C27CF0D6DDEFAD02B9A6ED9AAD710C7E21 +:10924000C0D76FED066C4F5C541E12C2F2F0A768D7 +:1092500052D935083FFF9ECB955E7ECEAE97DAE4BD +:10926000295806E36306B61F4A2E964BC407F3EC53 +:10927000BDC75CDD39C87C897686AF01FA019640AE +:10928000E1F5F3FFBE73F1EAEDD174E95BA362E6A9 +:10929000C03ACFEAE63D4B42D133805F16CB1EA0E9 +:1092A000D3D97AA607571A83D1B974DE4F385D7EB9 +:1092B000BF492E0D6683DE20A8F7F4F3AEAA96030D +:1092C0004BE93A5706A91E81B25A7E17CA55F55A7C +:1092D000FA9D26BE5BA6C37C656CBE53A6B65BF248 +:1092E00029FD4E7E23333700DF173F8EF62892AFDD +:1092F000EF24D7E7A7176BED856467723BA41E3D8B +:1093000013A9E59321EC8E9867A47667AFC9970EF1 +:10931000FAEF74C7CA559B81EF3A223D635D03E9BA +:1093200073C12E33F8813F55FAA7DBE4F9B0DB01B6 +:10933000FC99ECD9EA1AC89727CB983DDB5B1E5500 +:109340001D8492F7FF63515627F80F7B83E5CC4EBF +:10935000C531B885BE20DC6EAD40D517A693B0539D +:10936000E3EC4C4FDED9FEAED145FBDF0E7AC3CA2B +:1093700099C401E32775B452F8DE3270FDF14C74E4 +:1093800010FC1B319F58974787AFF5412DBE86B320 +:109390005FBF0B1A4A83AA79AB76B93B615E515F16 +:1093A000B989D5853DDB1B34E0EF9F6D89C5F59FFD +:1093B0002AFF0EF2CB1FBE9D992B93EBB06F41C3DA +:1093C000BFC4BE017EAE65DF6AED6EC4D770F6ED38 +:1093D0003C21A5488FAB6B1F9E09EBFBB778F41BB4 +:1093E000CEB7337EBD9DF3FB1F4CBD93D5F09DE7FB +:1093F000EB3DCBE97CBE1FBFFE18B07FA25D05D759 +:10940000677FE072F0872D5A39D8A093A73BDBB570 +:10941000F0AEAAD7C2BBC56E63E36D698A04BD72A4 +:109420004AF04D958C76E794AF18F5FB5ED0EF2AA5 +:109430003C6FB94E795B2E05EE02FA938E48F4B775 +:109440001DC0D6602FB3181D3FB3307E2F8A330C5A +:109450006A3FFAF5729696EEE047A8F17896CBA1AE +:10946000A8AFA8D6C2453CDAFE270D4C8E03AD51FD +:10947000E8F7D94C0C4E5B67A42DC0F8391FEC609F +:10948000FFFCBAFECB95A066FE0ECE2743CD3F9CD7 +:109490001FF5FFE398C1E3985F8E50FEBEA838E643 +:1094A000D475F2F79BDC0FD4C733FD7683FB35C24E +:1094B0008F5973EBA4BF12CAEA57B8BC56B52F44F4 +:1094C000BFF3A4C1B72D1AE879C260037ECC3FC3B5 +:1094D000E28F2AEE5F097866EBFC2C617F86B39FF2 +:1094E0007AF9395D717F2ECC7BBA62A9C6EF5D72C5 +:1094F000259584E2557AA752F282DFD02FAF115A18 +:10950000BADBEC269CDF667769F44FC5950C1C47E7 +:10951000D8B7AAF6BBB727537C54D43F9AAC5ECFDA +:10952000596ED7DEB6BBB4FEB0C2FC616753EF66BE +:109530001FEDFFA9D5171BA7A293354E8B87D39C90 +:10954000BED00EF8AF42F11907E3C3258B659D7EAF +:10955000627E9A5E1F89F6697106CDBAC43C7A7C38 +:109560008E74BE39369BF0B7CF1350ACD95AFF7406 +:1095700028FEED9F57D75E3F6F4A9C960EFAF9FF83 +:10958000184B34FCAA9FA73C8EF1657E3BA3FBC918 +:109590005B6F403E3C55FECA2CA0DB3BF7FDE5F47B +:1095A00052D033EB8ECD02F0CBE3A2B1FD3B744938 +:1095B00049C0EF7E09FDC2A5EDAB8F25A35CFE057A +:1095C000E3EB93A732918F7D9C6E274D1E8D1DD4AA +:1095D000CBE76F004EDAEE4FB1361C9F90AE74C8E9 +:1095E0000F8C145FBF1F025FD76B377E23E6BF3A35 +:1095F0006D32D88313B18C7E74F474A80F15CF8BA1 +:10960000926284C597C5D6162916FC47DF66D00B33 +:109610007D15D1B64E8A8A0AB37701E8F1D3270CBB +:10962000864609A7453FB09C303E74DFEC7E602241 +:10963000FD5EEE93BD207A0BA1CD4C4AD7226B0084 +:10964000C6CB3B59F65C34C465956617E8FD8AB90C +:10965000BE0F65883B9746B9B6D2B6F93DA31B1D30 +:10966000F4FBA25209223F7294DAF55EBAFE67A1BA +:10967000F225C200A4B83925EA81BA1DF328DD27F6 +:109680003ABB0D56DAE3EDC7EA7658E8B8DB1A7D47 +:1096900049102A7FEBB1053B2CB3094948F0F6CCC1 +:1096A000F510F2F3C76E990FF5EE6F8BFEB7EEF083 +:1096B000A611F2B2C1EF96E8F74F1EBB63BE42E1BE +:1096C00055A4793906DAFFD3B86EECBF6449ED1DB5 +:1096D0003FA6DF9D8FB7CE57E8F8F92B45FF47E649 +:1096E000178FA1F0CE12F5C723A0EE88F2B90C397E +:1096F000843CF058C97C259DCE17E7BD9BD0FAD499 +:10970000C74B765868BDC04FDBA6C022BE8DFDC5D5 +:10971000783B1E2BD911502889B614933F5152150E +:10972000F40624D0776F16D6172B74FEB5F1BB76EE +:10973000644F206446696114A1F5BBE27F34DF6C9D +:10974000073A79735C74FC9AF89FE0F8F92B0313DD +:10975000E1BB29F0E28E52FA7BABA5D307F1F266AA +:1097600089F14F84A53E64A0FF99B1C547FCE8BFCD +:10977000B531BE49F38C433E11F52C96E7EAAF278D +:10978000B17AF756F265DF20F238CAC1F44F77E4B8 +:10979000E0DF5FE1F244D78BF21A7B86789FA7E582 +:1097A000B148D26DA1F6E63633C92BA071F1F37141 +:1097B000562E477C5E0B834BF42381DBE2409F9562 +:1097C000311EC4EFE514AEC35C1F647AB81D2021BE +:1097D0006511E865D980F03865E9CB0BE9EF0991AF +:1097E000C4BF8F96CE7882F53242BCFBACE1717F6C +:1097F000C5872DC9F4ED06FE2F494CCE697287C787 +:10980000A1F03603BC229F44E156006EA75C9E7314 +:1098100077B60AEE6C0677771CC3079DE639F07BB6 +:10982000BA7B268E6EA5A07E354E2BCFF93DB9466C +:1098300042DB453BB81CBB587F673141FBDCF7502E +:109840004410E49058FC1E9F2ACF728AE3B5E6CA02 +:1098500004129CA6F26F949009F447CD956CFCDD40 +:10986000D934385D447EB2E68A9D04A6A97F67EBB1 +:109870000B8FE3C0EF43C143C30AD45F9BEC1C8151 +:109880007CDC2D84C57F9BA2BD8971D7F07B6AAE3D +:109890004843C0AFE0EFEE5184F4001EE9EF243BF3 +:1098A0000C1F292845FBB6C9C6F4D0A67D8589447E +:1098B000CDD70AA78389AD1FF06C50D967399EF1C7 +:1098C000CD22C15FD4AE839E5B9B928DF161F77F09 +:1098D000174F5A88E36D65FCADB0F8295F61FA3027 +:1098E000BF27CE1690C27C21F841D0B33BAEBE104C +:1098F000F1B550B275BA07AE3B92CF9FEFA37C4B48 +:10990000DB27AEF4CBAB55F009BED7CB09214F31E5 +:10991000FD4EF97F15C825C47500BF87CAC36435DD +:109920001D19DCFF0E7DA6231F30FA255B83008FF7 +:10993000C0CF407E481D861F32F07B7ECF1113AC16 +:10994000B386C39978261433299BAD63032D6547ED +:109950000CC2D910C7F8BABBAB78DA0D74FEEE278B +:109960006402EC93DFAF3FA55F14517D9828EAA015 +:10997000EF5D886FAE2FA97B6009B7FFEBE3D2CD17 +:10998000CD63C2F87180918F0BC3BB83EB8307F863 +:10999000BA29FE0296388DDC9282DCB07E11722AE2 +:1099A000C613E32CE2F4F1F1B25FFF70BB47F50D93 +:1099B000E601C98311E83F7FF17A471A46EF2CE4AC +:1099C0007A87FD7E8CBAB9D02E21C1334EA23839A8 +:1099D00071BC782CF8F1F724C9AE73D4AE2C96FC88 +:1099E000DB00F18BCE78AAC86895FF452C2E2BF5AD +:1099F0002756D3C69FD37917F74406644ABA45BEA3 +:109A0000089755E5977DD226219FDD435DE92DB965 +:109A100003F9E39E2413CE73A23433D6AF868BE3CF +:109A2000FF36C8DFCA03E553D429DC55864CD57709 +:109A30002BB33BA762BCB5F1B4BECE40FCC8E7F384 +:109A40009C1A7FE6D1386D5EA1DF9F89F56E827E1C +:109A5000FAF643F93F4E88FB517E593E28B1253A2C +:109A600008F84AEC225C3E43861AA0A34C3996AE15 +:109A7000DFE248677E6205FD38353CDE49C997263E +:109A8000419CE4347B204F41E982EB2F91EF3E6C07 +:109A900074009D254F139DF589783BB7777D79B08C +:109AA0004E6714E3C36311C41241C77F8D96487794 +:109AB000AE975ECF98D009F643E8B37E3D7895C562 +:109AC000D5E2FB3169619A8DD68F39C7E7344938C1 +:109AD0001E8950F13F1D97003CAFFFFDDE737329D7 +:109AE0003D8CA3D9780E3A7FB94A0E6694B2757749 +:109AF000C6333BD3191F856549141BEF989BB209E8 +:109B0000CC3396AE87CAC3AB91FEEC7A84EB214688 +:109B10004FCAF7A02F1338DD124CAC7ED5C1C6F367 +:109B2000F0F2A7BC4C8861EDF4F4B13A197DBF0F97 +:109B30004A83B66BB552BF46D6F83504F8994A2A1F +:109B4000017E6A2DA4EB19649C1FC6B3FC0DB5639E +:109B5000B8DE817685E93FC5723203F8F8E1824EBE +:109B60001BF071B391E5E31FB6056D7183F43345C6 +:109B7000D1F8313B6C8F841FFF59D7C258D08F6FFB +:109B800072FC99789C29E0696E60F9D3982B511882 +:109B900087BE11CFFC2825EB1CD25B29A06A8676F4 +:109BA00035125FC0A6A2B7D166D0F8FF315762B0B8 +:109BB0007FCD956924187F2DBD9D8FDF4952A92641 +:109BC000DEF8ECEC528453BF2E3DFE421C5E51F792 +:109BD0006629F3880AAE42626B86790A89363E1995 +:109BE000CAFFF80BD7AB3557648DBD09C36BD2FCE8 +:109BF0001EA27157403DFFFB6CFEF0BC5124A09AA1 +:109C0000F727F1DE4FE3310E9A653B3F891694EF5B +:109C10003F97D18E307B45CB0E2BB3EBA09F45DC1D +:109C200002F26CA3714B637CE155D01FFD768EF779 +:109C300013FA24F64CD8AF9368DF46EE8F3572BB2B +:109C4000D3EFFF29CC4F1570E7717E107AA7D4525D +:109C5000EC3DA7A25B63BC0BFB1F9718DF51494982 +:109C600087FE946F036AFBADC7678243E03342C34C +:109C700007617C5AF1F72FCA1FCC9FE5972743DE77 +:109C8000B45422636931631ED317A2DF448715D70A +:109C900037912A16F473B85E295FA96D37C5C1FCE8 +:109CA000FE290EA65F86B3D76A7B216586F5541D13 +:109CB000A79FFBE209938BB65BCFFD8F62A777BAB4 +:109CC00083964A64CC14120B654690D04F1DFF5BFF +:109CD000EC6AA4F0F7FDDAE8E984610F30BA162ED9 +:109CE000DBD4A4D0DF8D5D920DB6A1FAF5D016C9F4 +:109CF000BB8EE2AF90EBAB1A075B4F8D23641A4328 +:109D0000E74FA96170A4751D961495FCA455B37610 +:109D1000373B8C9CEEC1C6923CF8DDABB45252DFAF +:109D20000ABFD3F59439987E4BE99230CF9D524FBC +:109D30001140E99CE261E35A3D41696D76789D2DC1 +:109D40008685D9A0E75B12A23CA0E75B9CFEC50E0E +:109D5000A0D3D95008DCF219677B1488F3F63ABD1A +:109D600015B07EB13E976C4B81B830EA2C83AB2D99 +:109D70004ECB0FD473E276A993E94B991C07FF0AE7 +:109D8000659DCE97B0350BED4C3FDFC5713D9F40D3 +:109D9000FCFBD1EF212D04E945701D095BC7F1FDE6 +:109DA0001746CFB09F332117FC9CCC07430AE455DC +:109DB0005FDAC5F615F47C792FE76BBA8E3A589FB7 +:109DC00058C770F65CB4330E11970A7E8FE2FC53CD +:109DD000B8CCB11CD657D3FC9328B30474E890A236 +:109DE000D02E3C8CED04DE291C0D00879E9F94B87C +:109DF000BD522A5DD7BDEB894D2643C359B345F605 +:109E0000AE53EBBB6613D2A1C3A4DD2F17FE7B3B81 +:109E10008FAFDF72FA1E8179EB0E3C6A02BAAEDFB9 +:109E2000FDAEC93F889EEEEF3F423C49D52C2EA89F +:109E3000A9B40461DD85CB14A4DB866653D04CE95C +:109E400053F3FCBE9001FCDCFB8807E4BCA66BDF8F +:109E5000AB29144FA935DEE9902F4BA0CCD6931D2A +:109E6000B61B29352109EC714AD7EA1AE4E3A42884 +:109E70000FF031F8A7E0375C2AB40624EA2F5D32F0 +:109E800006B25CF4FB2577A407F6335E8D60722F73 +:109E9000F0FCDABE9B8E4B14AFD1FBCD2128F73AF4 +:109EA000FDFB61FDAD8DAE42A0536B09B101FF50CA +:109EB0007FE41EA897345909C8C148D72DF486F805 +:109EC0007DC67D4C1ECE71BD41FFE5825FF62B47FE +:109ED00034F34F0C4C0FBD6A64702A1C4E8FC37B49 +:109EE00018F912843139BC7EFDBC2AFE79ED7AF86E +:109EF0007846699709F65337703D52B86CB7F42726 +:109F000015DDDF74B07DE094E73B2417F2F1EEC677 +:109F10001207B6276617FCCEF2221BE8F73B54FA6D +:109F200043AC63103DF236E80BEBD99EA34C8F8413 +:109F300090DF04BC828E825E171CCC5EDD48CD357E +:109F4000FE6EA274A5E3BD3A3A12C71372AD97C371 +:109F50000B9CAF532A774B06F4377B709DB5950A5F +:109F6000D2E5C8D2DBD7015D6B1DC939C0874FFC74 +:109F7000F40D93447FFFAB83F971B56D12DB5F6E17 +:109F80007BC354017621F07D19FC9A05CC05203B5A +:109F90007FFC06DA8105DD2CBEAEEDDEA7ACB58612 +:109FA000F9CF7DF1C8EDC09FB55D661201FBDE4EB5 +:109FB000178EABE73BAA1F501E48C084711EF8FFE6 +:109FC000A80F89DF0D7659E84F0F878B587D7906EA +:109FD000D09309937340EF45380D5C7FB1F14B226C +:109FE0003D472CA0FF72591C20EC95D5C9F048C7FD +:109FF0000FA1FEA45E2DD83B31FE40BD3F2917F0D6 +:10A000009BE764F688D2CDE11C44FF8BF1DDFF5164 +:10A010004E5CD12A7A009E557C94E934B13C9A5327 +:10A02000C1F194228627C5C4D6AF6CB50421DFF1F7 +:10A030009ABD94E127CE82F83966585303743A9654 +:10A04000C2F9C7B035AB9ED99D3100CF91A53184FF +:10A05000E917A64F9EF811B36F35012BC65735FE91 +:10A06000C54867E288F0C03E21F11F35554487F9A5 +:10A070004D4F57D7FEC32658C7822EC6D7617C05E1 +:10A08000357C48F514D2DBE310F970BF1BF029E2F0 +:10A09000E1584B2864740D94BB581E0FFB211E869B +:10A0A000FCB487D5E1DF6071B09857F41771F08682 +:10A0B0002DBFCC3847F5FC5D493FC712E22B884BDA +:10A0C00044BC25DADFC2E39B7C5E2EE67CB221AF86 +:10A0D0000BF5E98673F52817D65226FFD6B35ABD7D +:10A0E00025E22D421EE4F159D78D905F2F795AB2A7 +:10A0F0003591A1F5CB9DB0AF047AFB2AF58A69DCD6 +:10A1000052A3DB375BE764FCFC1EEC6BA27EAF471F +:10A110003FF8D22E09CFDF8C743C123A2501FD3670 +:10A12000F078E3D2F3C533FF0CFB307B63F15CCBFB +:10A1300007CF2FFADA9F29BC9776CFF580DD7434EC +:10A14000F9901FFA9C111EF073A97A2B8578BBB188 +:10A15000EB9518C81F5D786E6A2EE8B57FE77275BB +:10A16000F147F216C0C7D6EFBD3007BE6F084AF1FF +:10A17000E0B75DDAFBF4DFC14E55EFDE083B92A499 +:10A18000E9B99F99605FC110EC60BFEF8D45FFEEAC +:10A19000C2771F9D03786EEA6AC2EF17BFDB81F5B5 +:10A1A00023DF7BE1D07F833FE08BF140BB8B3F7AA5 +:10A1B000F41BFF0D7CBB38C603EBA8F12B6C1F50C2 +:10A1C000F0AB5EFFEC3B8C7227F86301F875C0E7DB +:10A1D000954C8F08FE3C51C8F649CA8BD8FECB89F6 +:10A1E000F91195E8CF72B9AB5B6EEF00B93350FC53 +:10A1F00025D1FE8BCBEC1DB03FBE87AFBF269BF1B8 +:10A20000430BE516C81B4465874CA9B4DDD295FB0A +:10A21000E6003E5B22494104F229242DC3FB368B24 +:10A22000DA5EFB2F89D271325567E7297FD3D17669 +:10A230007F4EF9F44D23CB0FB4703F7CE9CA7725EC +:10A24000B65FA0D8CE8B7C907C2DBBA5E078A25DBC +:10A25000BF3FC6F1D0C2F321747CB423F99B789E32 +:10A26000535AD304FBCBC736876601DFBEF4FE3DED +:10A270009135D96AFE66FD53BA99DCA754F7DC081C +:10A28000EBBC396BF53498A696EF9F38206F0676B5 +:10A290002E60D5E8B7FFE4F29560238E2F413E464D +:10A2A000210E388F5742C82923E2670F7E7799998C +:10A2B0003FE4FAD9D23DB0DFB5D3E84F9E0E76A980 +:10A2C00085DBA7DD0C5EDADF06FBE5743CDB97720D +:10A2D000719C1E631CF60FB0FE37ED66FB65419165 +:10A2E000E7C9003B05E3E559C1AE042AD1AEB84C3D +:10A2F0001EE0878BD02419F13565D5E4F0BAF5F965 +:10A3000013D063780ED359F8A6D3192E45BE454F06 +:10A310008FE404FA9D8EB324C18B25D91B3FCCB9A1 +:10A320006546AF234B2F9B7AE9BC4FBCFC2EEAA1BC +:10A330003AE07798DF7F4E636F053FED7CF15DE497 +:10A34000F7F2038C3E7507DC4688573E68F0923F73 +:10A3500051C7B18EF3F74EA9B70ACF85BC186183F8 +:10A36000FCD865CEFF1B4ADF3D0F7A6BF481641782 +:10A37000C4D3975F647270CC60407C1EEB9CD401A8 +:10A38000F685FAABC8CA75F5AE4E33E297F9F1859A +:10A39000CBD63D0A71556D35F1807EA8EB5E98E60F +:10A3A00042BB6246FCD61D7803F945F8ADD41EAE1B +:10A3B0008371EDD4EE44409C35CFD78DF470446367 +:10A3C0007BFB3CFFA325C85F39F9C05F47961EDAC7 +:10A3D0006E8179E7111B8CBF33DDFB622AAE43220D +:10A3E000701E62A7B1AD48A1FD7796B86C148314B6 +:10A3F0005FBB93C0CE932C13B76BEBD01FAE4B5A01 +:10A40000E181F86980BE78B111FDA63A5724C2B344 +:10A41000E080740FF33BAC84C12F215F2E08DE1067 +:10A4200004F9FF90E34DE0EFB2B1E776C0CBE51F52 +:10A430005306A4DF17CC637C6A9FD7857AE6B517ED +:10A44000A95F3325CC8FD13FA1FE0DADC72936C9F9 +:10A450008372B6C8ACA6679B91D9293BB73B99A537 +:10A460008CAE9909CCDFC84C30F0D2A4DDB7B3056F +:10A47000A6809DFD90D31D8703FDCFC7AD5D17421C +:10A4800039AA799EF9650EB337E75E15DF3A8A99E6 +:10A490009D14F973C8A7631E1DE21207C4C5AE4E12 +:10A4A000D847A6F443FADEEC189F0BF8BA91C3958F +:10A4B0009225611C47FD35C45BC2B2DD4A5536CBDF +:10A4C000BF0F1607DECCD7E18CF7E541DED6991831 +:10A4D0008D7E8C532E3444801DCA913C9D2EDCE72A +:10A4E000C3B8B5CF99ECE9D4C835F3F7DE4F886629 +:10A4F000740DBEAEC03ECC9204D7A0FEDCC038388E +:10A50000C203714C595B600AC40D22EF2FD61D6C3B +:10A510008CAC54EB315F02D363C109A412F402F591 +:10A52000C7AD9827B6D17920DEEEBCE1BB2CDE6E3C +:10A53000C275CD4C60FB2F25747DE09739337D9B30 +:10A54000987D8DC6753833C91AE8E76C4A929ADC53 +:10A550006A3CDBF09CD65BDCCE087FBC8ECA0BFA73 +:10A56000712F337EAC033FCE3DB47E08F337D30F5B +:10A570000B0E30BAD71D60F64FC4DFA0F7E03C21C8 +:10A58000E809F7D4B05CD7997AC7017F0A3EAF9B40 +:10A59000D33B0EF033947E28890AA2DC954C1A87AF +:10A5A000F90531CE65A30BF7E32ED3B811FD582E74 +:10A5B0000FD12F31391074D1C72F0017C481423FFA +:10A5C000B7387D81048AD73A43683B9C0B10FAB4B4 +:10A5D000EEA51D9A73FF7A7D6A5198DEB204A382BC +:10A5E0004D2AFE81BDADE85C2CF1FC55D4168E0FD2 +:10A5F0008B01F1DB9A75EA07AD68FFBB42C06711BA +:10A60000693DB3417F3D96C0F2669B25E6DF8A7DBA +:10A61000FD04884D406F7446E1F95A9197D1C3B556 +:10A620008DCB8BC0BF8833200F0FED7FC8E5A28391 +:10A63000B7FB29E73B01B7E06B97C1FF2EE4E38747 +:10A64000B23FA2DF17952712F3083B18C633A3B316 +:10A65000D84780F52CCC1EBA5DDB61A66704DF8984 +:10A66000EFAF71BFF7EB9477A1FCA1C8C3FA27B095 +:10A67000FC7E04D19CBF12E389FA230DD73E776F8D +:10A68000FBBBCCF6B1A89B01F281790410DFA2528A +:10A690000FACEF758E2F7D3F85289FF60ABFCAADA0 +:10A6A0008287FB64701C69CE20FB72FDF3CED2EE74 +:10A6B0001BF4FB65BA718682BB4597FF6FC93C44AA +:10A6C00020FF146589E1F27B15FDFE1DFDF70402F4 +:10A6D0009E85A8EF581E6BB879F4F046B8068777C8 +:10A6E000A4F46831ECAB067EFE21A707D935B2751C +:10A6F0003ECCD779889F2F25EB2668F64BAC1E57AA +:10A7000023E4876367B972D0BFE6E734A3E7908F8D +:10A7100065CAAF73AEB465C1BD10A74F0B7F62A50C +:10A72000F6BC63B23F4E534FAD4ED1B44FAF1FADE9 +:10A73000F93E6ACB44CD7777205753CF6CF992A678 +:10A74000FDD8B6224D7D7CFBCD9AF61382E59A7A30 +:10A750006B635725C8C3A4BDCB35FD62955E92439C +:10A760007F9FDCB5464B0F1D3EA70ABEB6F4E6AA96 +:10A77000E529277134D22DB6408B8FB95774E73F46 +:10A78000AF933FA61ED0F187AEBF90AF28C2F8238B +:10A79000EA60CBC7B0AF1DA597233EEE14DA6F4E2B +:10A7A000DC20E30E21275BA36E5780FF0F4145E5B8 +:10A7B0004FBFA993FF92CA58B66F74A57C18BF9B70 +:10A7C000C9C91233DB4F5CC2F715C5F7BB13991E1D +:10A7D0005E9FC8F34C23E4E7339C9F4F0CC5CFD456 +:10A7E000CD4D007B514A301EB795367E0C799D6564 +:10A7F0004A88E450F97982AF6727EFDFDE60C3F162 +:10A80000BEDD9084E5AE0617FEFE1F0D5958061BEF +:10A810003CF87B67430196BBA91F08E5330DA5589B +:10A82000EE6DF061BB671B2AB17CBEC1CFEEFBE8C9 +:10A83000E977250EEDED12A2D56B4B2BE511D16713 +:10A840002979B0478E19888F01FDE595D73C97BDD2 +:10A85000E56C61F0A8AA7D2031DA711E986A06992C +:10A8600081F1ED30FDFFD6E00D1E350ECFDF7AFE13 +:10A870002157EF1DAB3E9F23CA2530770A21B73DF4 +:10A88000D9FD40203B8CA7A1F96A70FC782D975325 +:10A8900020E89F02F647D5FFB08E7FBD4AAC268EDA +:10A8A00016E5DF13995F58C8F9B550C7AFEF2432EA +:10A8B0003BF633DEEEFF357E3D12118D7EF911A39E +:10A8C0002BCDA9A2FF9188A84A761E9DB81653FAEF +:10A8D000512FD9E6A6FC1B9DC4F6FF24884C307F7F +:10A8E0003CC686799288EBCCA7E8F02851BFD24DC0 +:10A8F000C72B5498FE92E020128CEF3184F52B9EEA +:10A900008F880CF3BD3C901FE8380113F8636B7A15 +:10A9100097833F3726C9A539A758A4C8D7D4D745A8 +:10A92000206F83E40507F4BB4E79BB0CF236E95F78 +:10A93000276F82DFC9D5CC31EAF395A22CE4F2B6B9 +:10A94000E7C97750DE04BF1781BD53C1919EC4F49F +:10A95000737A12D3CF47B89F02FC913B88BFE24C79 +:10A96000D2FA79D78BEF42C2F42221BD29A027AEBB +:10A97000B73F951C05FA155A62025153AEBFFF50FE +:10A98000F81CD0EF806344F926AA692418BF8A43D3 +:10A990005765B106809F48BBF152AF8A8FBF19E35C +:10A9A000F324D1F6078CE400EC4F5033EFB22520AE +:10A9B000DF235EE93F9F85D673787D4640729928F4 +:10A9C000DF9869650BC847EFABFF05FA228797331D +:10A9D0007809E9D624909BEC683CDFEE1168E279B7 +:10A9E000D37C519D475D9C04715411C625D2A63875 +:10A9F0000863DA08ECABB74A9E1699CE2727BA9BB4 +:10AA000000A869A58532C8D374D286E52CD2D304B8 +:10AA10005B7673489F0CED6F280D34019CA3C855DD +:10AA20001BDA95C4676A3F87733A909C1C01DEFE6F +:10AA300016C1F6A1B75858F9D5C8984E28FF16C1C7 +:10AA4000F6A5034584DD9BFB4334C69D6E837F19C9 +:10AA5000E0EF6F06EF2A8047894F73F2FCEE1F7B11 +:10AA6000310F2CA17E28B2E655DE8172CD7E47FCE7 +:10AA7000BBC3EDB02E0FAC7F731BCB4B34ED60FC32 +:10AA8000DFD4C8EAF7727EAFE6E5D7B99C449040C0 +:10AA900080E0B8949209884F46C72C4A877C4617B5 +:10AAA000C4B3F538D2299274219E7754ECF46FC365 +:10AAB0002F2BF17C8F14F291CFA3D4FC34B2F12C64 +:10AAC0009636AF85F255646557C8788DF1144E5FA0 +:10AAD00065B109CF476E96FC4D80477256427E891C +:10AAE000E4E31A493D91DC6A38FE613A3D3C123A92 +:10AAF000198B3C3D5ECAA21591129E63B95E7A7DA8 +:10AB00000F98DE1966F543C9A403F20DD50E920421 +:10AB1000E71A4D560BCA6173BA2B00DF4DE308DE0E +:10AB20002B26368366DDE2FC9DE04F8A9F679228E4 +:10AB30009D4D41E95DC09729A91EE345A2F4A642B7 +:10AB4000BB4312E30B3D5F7725893C431A930772A1 +:10AB50006DFBB8EF16FB5B0E10D6C0EB65BF4AA2CB +:10AB6000F542FB0AD8F2FB5AF2AA3285FA35FBDE2F +:10AB70002028AC8B92373F04FA7B5F85FD3B4EB8B3 +:10AB8000179212F39091CAD7BE55127EBF39857EB7 +:10AB9000A7F87DAB9074419EE94C82FF10E07FF9ED +:10ABA000AF5CC7E0EAE9BE57EFCA00FC3B8A3DBD97 +:10ABB000787F6585D905FB535D90E704C6B94AE106 +:10ABC000A1FCF55D005866F5B9B4BE4CA0877FDFE7 +:10ABD0000DFF4DF928739DBBD10179CA5D920DFC23 +:10ABE0009851BBA85F43EBEF3D44A6417E7928BD59 +:10ABF0003643D40312DEC39FADFB2EF4DE98757787 +:10AC0000BFF37518BF47C6731B5225DBEF99C1CB45 +:10AC1000D9BCCCE1E5B2756C7F6A4CE58C20E4FDD3 +:10AC2000CE1B5D4D56E0C7C904EF9F1285F1E79B2F +:10AC3000E9F620E469DE934813E4D9023B08DE0715 +:10AC4000043983FD50CF3A4AEB3C70292D41C8E3CB +:10AC50009F6C20DEE6B12AFD4A69E3CD67691F06D5 +:10AC60007736C669B348F81FACA324BC2EE4B31BE7 +:10AC700079FDA61A96B7337BA9DE05FBA7D3D711BA +:10AC8000249864C173C46E3C2722DF446C006F4675 +:10AC900069E808ECF74EF316A2DE9D4EFCAFF4D047 +:10ACA00072A6771FD60B2CC12658E25C982F13ECA6 +:10ACB000AB4B013A16530F18EAA5A40DCB9B4917CD +:10ACC0009665A407CB5B491F963E623342694D7679 +:10ACD000A33CCDB1503B301AF7ED308F97DB6EC6F9 +:10ACE0007C6A79A9DFE41AC47FA912F70A893F03B5 +:10ACF000F3C48A3F6389CA1F39BF6CE92A7857C3F6 +:10AD000065D09E938D4B66FE755A32F33F764A5C52 +:10AD10008FD48AF739FCDFBA83D657948EF7C07D7B +:10AD20006FFA1DF3C4816516CC0FEE34BAD2C13F61 +:10AD300059008FCA405EAF66DF57411F9D987F67FD +:10AD400032C86B55F3F6748813AACAF8FD1A259019 +:10AD50005EA192F3F75633B8C47908F1FB580ECFD1 +:10AD600002D8D3827D640A3FEA2F91EF5B6E473DA4 +:10AD700053422A1538C79E97CCEC4190EB05213FF2 +:10AD8000D5820F94802985F65BE2717BE0DCDCF2F2 +:10AD900020CB2397282404FE743FFC951D9B09E5D6 +:10ADA0008FE5D58731EF1F3E9FC4F6AF0B9775AF88 +:10ADB00082F9ABD6998919F793DADE06795E5A6D76 +:10ADC0007641BD6AA5E465FBB496E058A8B7BBB769 +:10ADD000819C2EBDCFEB81BC2B9D0FF3B5375AD88C +:10ADE0003EA685CE0FFB7E3755F37323D5F7F700CC +:10ADF0007FD2765EF0A76FA4ED155AA61176EE2EDF +:10AE000032C0CE2F45CE63E7975CE6FA63F08E89B9 +:10AE10006B23F104E8B44B777548EC3C32C1B8675A +:10AE2000387FE8A9FBAFDAD13F06BF6114FC1A6096 +:10AE3000F9E62DB20BCE1D10C586E32CE7F7465B75 +:10AE4000AA9B305FFE592518198ACF3637BBC770C9 +:10AE500094C9F992CA9C5EC863594ACD2E99E526D9 +:10AE6000039077B6905294FB1CC2F2236BF87D01DD +:10AE70007D5C61D96262F39290067ED067607F87C5 +:10AE8000F2D3865A9FD01BA05FFA069177A9F435BA +:10AE9000E6CFF112E41FE436D7E291A30DC06A3E7B +:10AEA000946FC00BBBAF741FB32B11CF486AFB6EFE +:10AEB00071046E87233CEF1D1DB3CD8A686B23EAB6 +:10AEC00038C352E4BB437DAE7C47A16F957A3FA95E +:10AED00089F37B7332B75FBF0A64C07CF21CC6EF94 +:10AEE000BFFB35C1F762DEFF35C527C89F6461F23D +:10AEF000390C5E865DFF3AAEC77919F6435D4D4069 +:10AF0000DF279347233C79A50B65D85F9AF6D4B425 +:10AF1000D47F2303E93314FE87C2D7EC446F309902 +:10AF2000F9ED8691F8ED2572DA8A1ABAEE4F569A43 +:10AF3000717F56D8CD5C2016C8750F0952D907FB12 +:10AF4000817625B985E03B3E4E1F9C89E7E3009B57 +:10AF5000575A88A2C9A3DA34F5D4EA244DFBF47A0F +:10AF600097E6FBA82D599AEFEE804753CF6C29D076 +:10AF7000B41FDBE6D5D4C7B7976ADA4F08FA34F5C1 +:10AF8000497B2B35ED3FA14B0AD1F5E49D963D0160 +:10AF9000A06FC0DB939D1FB6E393BBFC9AFE337A90 +:10AFA000579781FE9A7AA05A330E394BFD365AAF25 +:10AFB000A7FF6374F1C8A0473CD512F9B61B50C86F +:10AFC000BE637B5AF79C9D7F01F4F8F24A63D8DF99 +:10AFD000835EE4C18F813E1E9D9FA88FBBEF3C1E08 +:10AFE0003866A5F0551F6F3B06F2F04EB2360E2FB5 +:10AFF00091ADB8AE4F4EC9783EA61A38D411A6E32B +:10B00000273010ACFB30C17363FA75F7C7E9F22E35 +:10B0100023BEBF42D70147E3CD495A7A47B8B4F4BB +:10B020008ECAD2D23BDAA3A5776C8196DE766FD634 +:10B03000A0F88D2FD5D25DE0B780FE0FF0FB45E381 +:10B04000D39CA2CF63CC423DFB593BD7B303F5C0A1 +:10B05000624B7E580F50951A84FB51026F03F482A5 +:10B0600095C537FD7AA19DEB8576BD5EF0BE022EBB +:10B07000CA74BF1BE3CEDFAE9A910A7A2E851C14E8 +:10B08000F724FC9FA3FE0E08394F4F817DC22D9EF1 +:10B09000DE00D8895D66F427F71D1B87F1C089B1F2 +:10B0A0006436861516160FB49A18BCE352C4FEA473 +:10B0B0006F5C0A2DCDD93EB8BE41DE9BCDF8E2B71C +:10B0C000A00FE9627F07713C6C5EE9F408D1E941A9 +:10B0D000BD3F2CF4CC8CC01B18575FAFDD182EAED3 +:10B0E000CF59C9EC89D0AF33789DAC09A07F2FEC44 +:10B0F0004C5381DF0DF710722D5E9918D4717E2F9D +:10B10000DA9DB924807AF88652CF773611F0AB7E7B +:10B110009B0A7ED580783F8CEF050CDFFDFBC01AC3 +:10B12000BCEAF78117019E9D88E74529AA7DE0FDCD +:10B13000111EE4AFD3CB589C92F7C698262BED97FF +:10B14000B0DE8D7ECC7EBBE715A89FAE6571E3F4C3 +:10B15000535E19CE5F65D6BBF11CDE7EB7AF18EA31 +:10B16000A737B3EFF967FC783E6BCC16F63D776BEB +:10B17000FD2B70AFBFE21BECFBCB1F6EC7FB60D497 +:10B18000C8B1FE856DC5503FBD8D7D9F7136D80419 +:10B19000F5092D7C7EA9EB9518B0830FB1F7180641 +:10B1A000C43B3CBE99CBE931809E3C6E98C3DB8B9F +:10B1B000F8666E25A3D3BA3EDF8DC8563A7AE9FD0C +:10B1C000FA12E2C7FA4D2480E57C12C4720109E14B +:10B1D000F75B482FD66F83D09ED617129711EA4F90 +:10B1E000A76421DE1751938FF98B028F05DFD73BC0 +:10B1F000F78BAF9198F0BEBAF00FDAE27CB5E03F82 +:10B20000388A7DF85EC8D329CC6F0F97629F3C9037 +:10B21000E1A1DFDFE7F7CEC2FBE3F978AE834EF9B9 +:10B2200020F8BB8FA7B0774D6E2205789EF8A60256 +:10B23000760FEF26F087297E424F2A7638AF876F48 +:10B24000230D123787F348BAFCB212C0F8235776A1 +:10B250004D0261399052FE10C4D1FB411053087960 +:10B260002E65E52D8134E457F46F866B778A9F0352 +:10B27000DACFF74917FBDC06E4CF1CADFF7480AFD3 +:10B280005F943791CAE2E82F705DB95B0378DEBB4B +:10B29000A2D34CD8F91D9202E774AA483DD2F5FC1E +:10B2A000E48091DD4F657AA782F35D05E7A7F31D82 +:10B2B00066A4C37B774841C8EF54ED7AED0CF0DB10 +:10B2C000907E53F65894DBC59C3F7F7BAC6A1BD3C2 +:10B2D000EBDC9F7A72A2FCF9A4B0DC533F3100EFA3 +:10B2E00017BEB58AE94570BB35FA70083FD1C9EB86 +:10B2F000028ED480847662A4FAD021C6E7FA304563 +:10B300008CEFA5AC47EB19FCAB54C3F0E0E4656AE5 +:10B310008DDEAEF81B410E92489B04F574D287A5D2 +:10B320008BD8B63A33E18AA6C700F5344BFDC2325A +:10B330003ABE1DF41FAC7FC7913CB5FE33F27CB41E +:10B34000D1F220EED72AA4CD0B7904E5687FDEED9B +:10B3500013B0275F54DEED6A8A0BF94D9F7FA39EE1 +:10B36000D654908373466B0BE699F5F99601F9195B +:10B370006D1E63761BB71F6DC26EF89360FD703C47 +:10B3800054633F667A5C50CE957CA867BE99E88F7F +:10B390004E7542BEA33E0DDA1B2CBD32D88B567EB5 +:10B3A000DFA895DF376A1D27E25A4A6528BD59C8CC +:10B3B0002F5339CD5F2860F7985FC8B2E039FBEDB5 +:10B3C00009A6ED90CF0BDFF3E4FDF8BDD529FC1DF8 +:10B3D00085ED911C0FADD1189F3C0CF3D27E91B23C +:10B3E0006B1CC0F74703A532852B9E78B06E926D1B +:10B3F000CE4637E62BC7A662DEAEF7B14CDAFFD4F5 +:10B400008B0A8138FD055B5FA49DCEF3C2C1CEBD22 +:10B410009D149E4F8F3373FDF05E39609E0AF727AF +:10B420002F3DB680B69FDA6344D33CB5C0807AF333 +:10B4300003137910CE07955B649F42F9E383AFF065 +:10B44000F33A8A27437DBEE09934A63F4F0C914FD3 +:10B450005C1657B81CE03A913CF8BDE079A92CEF96 +:10B46000D0FFCE087F37E92F4EA23957B22CEE56C7 +:10B470001C47D48D57ECC41FAF1EC7C5F857F11138 +:10B48000B82769BCE2C0EFB1D49F857D87587B8126 +:10B4900002F15711B11DF54A78651CE93DE05D8662 +:10B4A000594A5FBF1F391AEC14F34331DFEB86FDB5 +:10B4B0001AADFF399568EBFAFCEE53692C2E35EA8C +:10B4C000DE75782A4D0F2F7BD741DC2FEF56BC510C +:10B4D00090175A6BE0E7AD92BC785FF291598E9C61 +:10B4E00056155E9E4CE5EFBFF077286CB43DBE6FFD +:10B4F000A05B4733952337E5DF0752193CA2BDD047 +:10B5000063AB841C05ECE8C7AEE472F4511ABB27A8 +:10B51000BFCAC6F669FEB8E3434CFBAF7E23D20434 +:10B5200048FCF24A123399F6F37F33FE375E17F088 +:10B53000A9E7309CCF218F30BFC2569495CFDE2330 +:10B540009887FBAD522015F5EE48ED467BFCEA925C +:10B55000340A6F644CD065A3E3444E7C1FCFF935A9 +:10B56000A712842BB2FF7DCCDE71EA7366EDF18504 +:10B570002569D3F11C6D280ECE5BFEA799D1F73853 +:10B58000F182DFB5F1D004CC7FFD4F9ABF18DA8984 +:10B59000FBB3E4681FDE172E063F257310FA5B3FEE +:10B5A00035001FE9F90000077B3C1C3F04006EBA20 +:10B5B0009EB53183D315FFD17AB1C58EEF75FE9854 +:10B5C000D357CC7BBDFCE9C864FAA44F92F0DD9858 +:10B5D000E1E013E78E051E8B39FF8A52E0497F7F39 +:10B5E000AF38CDC0DBB1FB7BFF93E643BC7E94FE5E +:10B5F000F138238561AD89BF1F31CC7A8FFF93EB82 +:10B600001D291D9E4A63FCB336726470BDC5F5D416 +:10B61000BF1AAE1B055C534606D747FF24BEBCA429 +:10B62000EF0FF6CCE1E1A2F4BC11E849E6F5E1BB8D +:10B63000206BE346069F23ED9F872F6E64F0C9A021 +:10B64000274888C1B784788C4932074675EF467F12 +:10B65000DF46DCC359A2505B4AED5DA489EDB345DA +:10B66000964B2C5FF40FDEBBE9A7630209D9216E6C +:10B670003F6466F9464FDF38B5FD4CE172F33F6930 +:10B68000DE5100FFDA715C2F946ADB8DD2B513EFC7 +:10B690006C10AB01F3E5AD59633AD93965B6E4886E +:10B6A0003417BEA73B3E4DD29C5316FB84DBF35DA3 +:10B6B00089E037782DD6904CEDC2F689D559B02F58 +:10B6C000E24DFAC519761E9BFAAF2A3A09382E3692 +:10B6D0001CB78D310E8D870DF2FEFCFA41F6572E08 +:10B6E00027F867A6A9ECF786BD3FB78D51E58926F7 +:10B6F000935E03F3FFFB0C2C4FCCCFE7245E1FDEE1 +:10B70000FF0DFC2727E87F1FEA7F612FEA5EFABE64 +:10B710000BEC10B5F704F61BFAA223D11E344D2C06 +:10B72000C852EF07ADE8B7D7DA7731C276FA9F7B18 +:10B730001723ECBF4824103FD8F80AFE2EE8E2B5E4 +:10B740000E4E0F710E37D4102A3F6784F74C0A163D +:10B750004179A4C1BBE81CC47BF185DF4AC373B83F +:10B76000FC3E83EF78F93915BE132B7B34F564FF6B +:10B7700099F2732A3853AB7B35DFC5B95BA3839D40 +:10B78000BB2DCAB3E07D80F4FAF735FD5A0CECFD11 +:10B79000A5515BFA34BF1779AD017B2CE47BAF6810 +:10B7A000C66D6D647C9CD94216A97F372A5E3CF732 +:10B7B0003AB6CDB2483DCEF8769BA63E2198A4E994 +:10B7C0003769AF4BF37D725796765C5B81E67B21E0 +:10B7D0003F47E4B5B0F33CC59642CDF7FDF10BBF52 +:10B7E00005F256480E6BD6D37F7E7C98F3388AB22A +:10B7F00003F393B0B7392B77E039F2FDF15E1C5FAC +:10B80000CFFF81FB67F17D2516670B7E20799E2C8B +:10B81000F83E145F1C4CF07E17E87E8EBF632289D1 +:10B82000FBD259C4E563EF980C7A0FE7379CEF3FE2 +:10B83000300DFE7D3FD72346DDFB2661BE65EF9BC5 +:10B840007C5024DE47D2BE4BD72F2F7C9C87793E7D +:10B8500062B8F7E98C57A234EFD385E78BC1DF3F9D +:10B86000187DEDF9C4BA463E9F3CC4FA4CD77CBF64 +:10B87000E51D81BFB8C1BFBFD58FBF648DDCBF33AD +:10B88000200E48C3EF46DD3B30EAB8067E1F2EAEE1 +:10B89000E97F1FF00B8F6708AEE37AFD631AAE7F76 +:10B8A00005DE451B6EFCA4746F1D8B63FF31BB1B53 +:10B8B00009363619C751D2E938DB4DECDE23D560A5 +:10B8C00098AF10710DD1C73D59EC9CDCAAA45FA0C4 +:10B8D0003F100939036AB723BF1181FB275F966CBC +:10B8E00026C0EBED96BEB7BFE382FBE9A1B7FF1D13 +:10B8F000F31D22AE8992617F6EA470F6E75BF8BB00 +:10B900000C90FF06BB3D75EE44BC87F308C46B008A +:10B9100003BF4FF108852199EA8F588315EF4BC576 +:10B920009A587D2AE46B68BBCFC8A538584B0CAC3D +:10B930007F26DC4761FB22B107958B6A7CEBF745DC +:10B940003EEDF94B24D8C749E9DAFD91CF48D9EB50 +:10B9500093002F050EC4E79417E725AADF3BE9DF24 +:10B960003F12F99E21F2C7E1F331DAFC8CC8CBCC4F +:10B97000BECEFC4CFF3B03BAFCCC7079A6D989FE45 +:10B98000F9E9D7C833998EB0DFFB3A22D02F10796E +:10B9900027B1DEDBD299FC4E48F2DE964ED79B9360 +:10B9A000EEF5C1782722587EE604CC3305F6176EF3 +:10B9B0008A85A57E4ABCB110AFC2F9E0D4B881FC3B +:10B9C00000799566957C9FB00FAE376EE7F33E9594 +:10B9D0004E10CFAD09DE2FC3FCEF9BD8DFCD783FF3 +:10B9E0009297314CBFDD95CEF4D053BC5F032FDF6F +:10B9F000E7FAEFFD38A279D759B46BE4FDCE35589C +:10BA00007CCD2AFFCEF5A4B91EE23C6726BFCFE568 +:10BA10006578FAE845E6DFAF6B7BD704F7A61E4CE6 +:10BA20002F7C0AF001ED601DEB945E13BCC7BDCF07 +:10BA3000E9FF2AC05BE722DEFDD0DFD56B5A44F177 +:10BA4000FD11F75F3E32B2BCD14711AC14F03C9807 +:10BA5000BEF029E8F7D1EC5E13D0B9BF3EBD17E5C3 +:10BA6000F0C1741FCEF7D14C5DFD165627FCFC8645 +:10BA700097F31FDACF41ECA5DE3EEADF2BDB68E26D +:10BA8000F947BDBE488BD6E89355077F8E7C7CBBBB +:10BA9000856C8754D4970F269A20C8A88E098CB33A +:10BAA00069F21FFF989EF828BD07D7D55AD897F19D +:10BAB000ED3CCC67D83AE93CB507591EBC56ACAF53 +:10BAC0005BBBBEEF73BA0EF76E9FDEDF184E9EA50E +:10BAD00083FC1C1B2FC9A19FA7C278B30EFD3A1E81 +:10BAE000CAED523DE6A555E772CFBC4CF94536F498 +:10BAF000C5ABE558ECFFBC26F5E23E5D1D69437A17 +:10BB0000D775D375C540191182BC3339A05DD77A7A +:10BB1000F5394CDAEF2ED265724B105718C3FBC6BD +:10BB2000F4FF35A407C7ABEDD2FEAEB73BC3F1417E +:10BB30005A0611E73491AFAA391EAA05DE835AF8D6 +:10BB4000C4FB44E25D50B7C17F06F877A1DD1290D7 +:10BB5000A7C23E937715C0B59AB890AEAB75765430 +:10BB6000BC67B4D6BA18F9686D8B1E7EAF09E0BC0D +:10BB7000A3EDDAEB12FC7315F407C5F74BE92E2C95 +:10BB80006B23CB8EA36CE4F5E07E1385EF12C88F98 +:10BB9000808F285E7CBF5CB4FF707ACF3321BA26D9 +:10BBA000397A9E05EC457BBCFF13584FFA99DEF3BA +:10BBB000121CD0B47A713FEAF2810B6FC2B93B7CA0 +:10BBC0002C63264CD0BBF306FA9FD507641BE40711 +:10BBD000AA0FBC82FC3A14DEFAEFB1933E01D7E71C +:10BBE0006ABC09B8443E5A2F3FE7D359BEE1499792 +:10BBF00057C9007F6B7417BE97D5B799DD2377C8F7 +:10BC0000D4D2C6C1A66140025B29DE85211EAF05E4 +:10BC1000F27E73CDECFD9AB76D4516B8279F60375D +:10BC2000F840FF35DBD6D8E1BEB478273C4132B0CE +:10BC3000BF0B40D6D8E1FD915566FEAEE557A24256 +:10BC400099945F7F6662EF873AA2FCF82E429F5D6F +:10BC5000C6F90B977D3A0DDE3148B96ACD85F36E92 +:10BC60001F71FC0AF8E716F74D63EF7832BA3932E4 +:10BC7000197C754ED3767817B199DA1B282FF07599 +:10BC80003673BB03673CD9BE42D0866FC5F1FD88D1 +:10BC90004D16C6A77511DE478A200FF106FB7B5DA6 +:10BCA0009FDABCB1B02FA07F7752F8B743BDEFFC4D +:10BCB000A50CA64FFE55EF468ABC749D5D218ED81B +:10BCC000703FB1DE3AFECE8D9EEEE2FBCB7F970752 +:10BCD000E58BA519ECFB50F1CFAD7C5D75F09EB7FF +:10BCE000CA3FAFA3760CE0AC83F7BCAFE1FF5FE0E7 +:10BCF00076AB0EFCF678F5EF8CBEE1711CF8FD59C1 +:10BD0000BECE678F1B4A3B0781F7AB192CDF33D1BF +:10BD1000A9F8605F645288BD9739543B71BF7B2896 +:10BD2000B8BA8B7A6F07B8217F3BD87C1B3258BBDF +:10BD30000BDCCFE88EEBAD42B9B0799F83B8FFA39F +:10BD400017C7BBD5EF0EFE86E3FBF27C66B7C5BB1B +:10BD50009DF94ABD047C25E8D118EFFB33E815783E +:10BD6000BF97ED0330BE1674007E76A17FAE8DDFE7 +:10BD700004DCCD7C5F49C46DC3BD935A07EF995F66 +:10BD800013FF0A7B8795C371E104F31721A296F292 +:10BD9000410F337E5FBD7B039E532A91ADE8EF5C7C +:10BDA000084AF83EDF05C2CE5D5C6863F9C1AA3D72 +:10BDB000D3B683B958E367E7AF5727B17B6050BF6D +:10BDC0000FCA666DBC23E6FB8CAC34819D5CF7A08A +:10BDD000567F5713B6EF0AFBCE10DF5D38C1FCD794 +:10BDE000AA27B4E354EF5EF01EC057AD3B2795C0C1 +:10BDF000ED8EDECFFF5E06BF37994FF2AFE71E57DD +:10BE000015F1FE3003F5B14F06BD3B9D9F93BEB0CB +:10BE10003B3351FDF77822474B9AFB4B17A9DC8F38 +:10BE2000190B7F5FC886E5910CEF4F32C08F798385 +:10BE3000ADFF8D0CFF4BACCED647943EF6BE6825C9 +:10BE4000B37B66485ED2FF34AFB004E19CEEFDF0F8 +:10BE5000AE18C5AFD9CCECA9F01F64F95E3906F273 +:10BE600078927FE1ADD0E5B99B4A717FB6D09B0354 +:10BE70007AB675A115DF91E830B0F7032D66F6EEBE +:10BE800051F0D9994760AF7D4CD7A345B02563EBFE +:10BE90000D911817E4AF1AF11C4DCB1C82EFC3892A +:10BEA000790A7A7DFB009E8CC5560F80D6EAF6E6AD +:10BEB000D854E313EE17D4715A7CE74026BEEBFB4F +:10BEC000C9C1F1584E248C3FC43D049813FC1D8118 +:10BED0002FF83B4C4475EF7362971432C2564A57A1 +:10BEE000E332A073CD56F6DE52DF0F089EE771FCF9 +:10BEF0002CB9C8151386AF66DF9E38BC1FC1EDDBB9 +:10BF00000A885761EF87FB6DE21EC48A08128852C7 +:10BF10009DDFA9E4FCBEEC208BC3D6104F06F45B7A +:10BF20006E2131068AB315C55DD3D11E6D30DAC1DD +:10BF30002FBDEEF32C5CCEF4ED2E42EC0876F145ED +:10BF400033EE4BD53D138DF9C48D863E9CDF3C8A84 +:10BF5000EBE3717C9F610CF1C2F9A7BA43E371DF97 +:10BF6000CE0CEF57E5A2DEB3005D8F81BDA5EB5E81 +:10BF7000FF7204BE8BD7FF3E8C8D04405E371E4A95 +:10BF8000C4B8DA91E9CDB9271BDE23E9CD407D4065 +:10BF9000F51CA4C65DA35A6F83F3337529D49FA102 +:10BFA000F5054F3FC9EAA37BAB0CB47EEFD32FB0AE +:10BFB000FAC4DEF350FFFAD32FB17A6E6F954CEBD3 +:10BFC000ED4F1FBF0DFE8E491D1C6083FB8A4FBFC6 +:10BFD0007E1BDC67B96817FE452FBE0F54F7D27879 +:10BFE00043AB8AEE8F8E62FAFB62046B77D1CDDEB3 +:10BFF000012759BD9A778B37F376C23F12EB14FDB8 +:10C0000048D2E0E34FE5FDD6F3777DE6469196080A +:10C01000F6AE7900CE7F1D3D389EE16514BF876482 +:10C02000EBC5733A621CFDBD7F31EF5DFCEF225D15 +:10C03000366AFF5EE6AC514C6FD3799A719E6C6F95 +:10C040000E9C97AB2B4FCB01BA517A299C5E0A7B91 +:10C0500067B883C147C7B5833F68EB9B06F6E6E840 +:10C06000D5347CBF51C04DFD3E2BFA671CFE1B39F9 +:10C070007FAC6FE2F8A230CB0837DBD705FA821D20 +:10C080006AE7EB7F54D51EC74BEBC5BFD770BDEB3E +:10C09000ABE4E37CD1EB53D1C50BFB13470F4C4012 +:10C0A000BAB4F7D3FD51CD38171B75FD0A08EE5B06 +:10C0B000D5C56562BFFBF93BF6E21D61E8E79EC2AC +:10C0C000FC4BE07FF15E1BF18EC2FDB11AAE1FFA90 +:10C0D000DF59EB62F73BC818BA3EC06B79591E5F57 +:10C0E0009F8DAFCFA67E27BA5FEE4EF5652C56FD2D +:10C0F000FD1AF17B3FDEFBC7CBCEE5E369E477B009 +:10C10000F180EE43D1A3F58BA687805387CF7E3C89 +:10C11000EBE013F804B9C57ED95AF911707E7D940D +:10C1200041F34E57BFFCBAFFC1F9F8FE5FEDD728C7 +:10C130001DE1BCB04BCBCFB5DD6E03FCDD3AD1AF1A +:10C14000B55AF7F788BAEF0E409E62E3C185785E74 +:10C15000B5F6A73FF84980F6BFEB856FC6108AEFAA +:10C160000B4A5B02BCFB54B3675B8C17F2464A2058 +:10C1700006F4E58520FB3BB17A7DDECBE920FCA807 +:10C180003A6E572E3EFBC0AD808FBFEE31DAC06EE7 +:10C190006EDC6B0E9931AE5F8FFE15ADBFCBEAF74B +:10C1A00063BE72E301AD3F74D7F7BE99E0427E0AE9 +:10C1B000A41A92A00CA5125AD6ED367A4280AF533B +:10C1C000B2874E433692BEED009FBE3FC0014F3452 +:10C1D0006CEC92579B62077EA716C8047EC7C6EE1A +:10C1E00007D0EFDAD83DFF3DF01F36EACE93570F68 +:10C1F000E1579D18A57D8F42E087049DE8C7347DF7 +:10C20000FF7B3F7C89C279E1F78939F82EE6EE5F42 +:10C21000C648F4FBA5AECC58F677CDB70EFADED003 +:10C2200065F007CC6ABBCAE8EA3A20618E861C64D6 +:10C23000658D311403F1754D8711EF2FD5FCE0BBEF +:10C24000CF407E88FCCE8CEF336CF8C1B137BF4451 +:10C25000EB1BF6191D650C6CAB9410A6CF4617F3BB +:10C260004B043DEEFAD1317C270C7E07FF55D0659B +:10C27000C3BEC326327920FE8ABB0EE3BB9D03E812 +:10C28000D3F5EE8DF8AEE7F7FF6602BEBE7048222A +:10C2900089EE81FDABF7FC3206DA09FAF4D36B00C4 +:10C2A0009D42B7BE9487ED308F20E8F57F0060C2D5 +:10C2B000017C0080000000001F8B080000000000CF +:10C2C000000BDD7C0B745455B6E0BE75EB975049FE +:10C2D0002A1F4240126F3EE4A32129F223FCB492AC +:10C2E000104CDA042A216840D4021422242442DBB0 +:10C2F00066D4B5521851E4D13371B0DFA88DFD0A70 +:10C300001A68FB3576E761C434025DA84DE38818EE +:10C310003E222ACD94F814688309A0A24F6D66EFDF +:10C320007DEE4DD5AD1082CE9AB5FABDB0B24ECEEF +:10C330003DE79EB3CFFEEF7DF6A5B9ABF2344402E4 +:10C340003483F1943F13F8E77232C0F6EBF18F912A +:10C35000004DAFBCF8FB9D71000D1F581C55F8A88F +:10C36000E1F72B23613CC069634BBC231BA0F1F9AF +:10C37000D5F14E1B3E3779E2EDDC8AE70DBF7A201E +:10C380005E89005872E88178C8A6559DA30DC5D472 +:10C390007A464302C0BD1BE6CCA0E78BC1FD38BF87 +:10C3A000F7BCECF262FBA5112AFE0D9F5FA69F9BD6 +:10C3B00003EDED8AC4F09CDE640188C2D68C4B216B +:10C3C0005C9EC3B2778B44EBDE0F5004F08015D433 +:10C3D0009F15DCFF92FA0AC078C50050C803568842 +:10C3E000A7F38A9FE6CD4FF4C839007F4B748EB215 +:10C3F00067331E3C7EB1867419D7950F958FF2DB9B +:10C40000B8AF188BD4F75200CAE839CDEF3139C331 +:10C410007274EF31FEB4FD7FAAEE8F70874BB9D8EE +:10C42000C6434327E3037A088EE592786779D77D80 +:10C43000550AD2E171F59CCD2F587C16EC2FDFFC0C +:10C44000E479820FFB1F51FF8BA3728517DF5FEE2C +:10C45000ADA9801CDEDF378AE679F7D649D4EFB67E +:10C46000804F8383D6C5DFAF63E89CA605E6A8C1ED +:10C47000E30897510AC6E71EC9BB05E16FEEFAA7AC +:10C48000F332AEBBF8699C9F1998DF3CC02FE6C021 +:10C49000733EEFA302BFF2FC2837E26B099D6BD21B +:10C4A000603AB69E28F1BE11B45EAD1211F7E98D67 +:10C4B000F8C744987859C676031E7EF4E0F7B416A0 +:10C4C0002164FC349ABC5B9F43781BDFB7383C88FF +:10C4D000DFC6174D2EC2CB67DB5E3F36AF00DB4EAB +:10C4E000535C15EFE2B44945020F448766FC6DCDFD +:10C4F00013F826FC356C2F0465BC78FE480C3D7F94 +:10C5000082F1FD99CD01C4E7CDDDA653FE207C95D7 +:10C51000E173C10F9EEB0C09D4FAAE237E5E6E036D +:10C52000870FF75D7E5476288427E867BE0E7D7FEF +:10C53000801E9DB24A0FFD3840BFD9353E80FFE6D0 +:10C5400021E453C36F283E1F09C1E797901D3505AD +:10C55000BB7FFBD765D7BBB307E3F7529BD3FB8603 +:10C5600009E0F3361CB3049EC72B0AE359E9C68DD4 +:10C5700046E1D82EB505380A41F8D4F0A8F1E9D241 +:10C58000DF35F13E03FCABF1A9CABF013E0D3DB75B +:10C590001E9FA1E34E426A6180FEA647C11381F44B +:10C5A000EFDF2D7B3721687D38FE38E2BF6F5BB24D +:10C5B000D783F8591D0677BB108E3E7B7F640CB67F +:10C5C000ABA345BF7FA4F971D21FDAF3FE30A8EF09 +:10C5D000443AF5B9FA23A36D81F317FC498E54B0A0 +:10C5E000EFF74245A7ED4A7CD8CE70F8418C97CB47 +:10C5F000B6A456DCFF42476A1EA2112E5821A93567 +:10C600008EFAE3F23C7C8A550C7F5F78640EEF1F54 +:10C610009EE425BA7E02AE635388961EA77134E26B +:10C620007591383234BCD91E09A8B216ED5A564558 +:10C63000F3EE59A7C7C762DB66338D7F098F70BBE6 +:10C64000F86953803FF07729AC637A346C0879BE7F +:10C65000EB56E6A7A521FCE42618460FE6A77DC405 +:10C660004F23F08F093081E5137037D45B2B54BD15 +:10C67000562E67FF0F20BCEF97C1426BC8D9EF4C15 +:10C68000C1737F897D9968E619C97CBACC7DC60CD7 +:10C69000A901FED6F8AE97F82E636879EF7DF9AF61 +:10C6A000450FE394C61D1FE6FC12DBDE1DEFA7BF9E +:10C6B0004AFD57DE4BFA1006CF2FDBF3CD5DA4C742 +:10C6C000FAF658189EBE3D7F497A98FA3B2D0E82A5 +:10C6D000B7EF518B93E0F5EC89F08EA3F144A43FC2 +:10C6E000F241FBEE4B397ED6CB8F319D2E2866D1A1 +:10C6F000EEFAF6A44474DC655180F4E21E4406BEF2 +:10C70000DFBC33CC0BF4FEEE4B45EE20FEF87F3D54 +:10C71000CF7233B8991F23A07E3BF16F3438E93CC8 +:10C72000CDAF4EFAF52ADCBFA96BAF79118E97FD1C +:10C73000E9FB1CD2437DDBF79A494F7D6EF2FF0A7D +:10C7400050657DAF34769810DF9FA3ED853100CF23 +:10C7500026BFE8F2D8AE841781873EC4039D0BF153 +:10C76000D240FA73287CC425FFA3E2E3FC5DB47FCA +:10C77000E3AE89202707E345728AE7115EABC4E781 +:10C7800017CFF75CCA011BD987556CF7873B77FE3B +:10C790007FB9734BBE6B39772D9D7BE43FE2B905C2 +:10C7A000FF1F27FB5438580E06F3F92B3FE3FEEF2B +:10C7B000231C0CEF35CAFF8AFF6A74DF8E748F1C4E +:10C7C0009EEE4FFDA7A5FB9B2ADD23EC16D267BB8F +:10C7D000BF4F82A0F30F77EECEFFA4E71EF0876471 +:10C7E000973505E15B07BE1E0A2156AB7EC9EA38C4 +:10C7F00003FBF56BC62A9B64116B70DCC17FE3926F +:10C800001F268B786335182A082F72DC52F637E41E +:10C81000B8B5EC3FA0B96778D6C44DDDBAF60A7159 +:10C82000965131F82C38AF7D15EE8FF3DA471AECBC +:10C83000ED0A3FFF889E5B689D486A7F7256AC7B1D +:10C84000A09EFC3FA3CDAC8B436C21F144789A5958 +:10C85000177784C16B7623D221CC6104AF44AE6AD2 +:10C86000D0FB38FFD5643B9F231CBC1EBBED47E1CA +:10C8700085E342A31A8FF14B8501BC0CE04D0C0FF0 +:10C880008B2763DCDA1E3AB711302E14E7E07812FA +:10C89000D438D2C8AF0CC69B163706E197E3CBA0BD +:10C8A00075F8BC1ADE07F0A9E2FB87E235943EC3B7 +:10C8B000E1F9E410780EB453ED1C7F84E17C44D69A +:10C8C000FADDF01CF9BBA66AB3290ECF59ED921C14 +:10C8D00084866AE83F3A1BFB502F3BB6F0B95D3DBA +:10C8E000F760FFED82F5096BB13F075D7EC8E3D6C7 +:10C8F000A7506B4F2825F84C92A3C789F0C15C93D1 +:10C90000630B36B1BBE0392597DE77EC35E2FB737C +:10C910006E1B9D47EF1F849ED211A4E7E74B3C0F8F +:10C9200012328D44BF5A107C8F3F75FB11CFB35527 +:10C930007A66A5C430FCF5E09A938F00CE6C77B58B +:10C94000B8F07CB392FAD3A283F211E35392992FF9 +:10C95000E6185DA6FBB319BEC72066B0DCCFA145C3 +:10C9600063086E97A985F134DDFE29E25D72DE2051 +:10C970005F1E71B5F8D6089F6AF4910378CD35F73C +:10C980009F5889E7B11F941D9B14C203B0BF0EDFEF +:10C99000E17B788E6AEAA706D6896D7DDD3D3D167E +:10C9A000CFA3F231DCB3B13C96F08F0B926B088DC4 +:10C9B0007BCB630B82FA3FFD483FFE883443D77F31 +:10C9C0002C59DF5F573223F8FDA1CE535D906C7276 +:10C9D000E384DAA725A7F70A719406DFFA553097A2 +:10C9E000F00D714EA586168C2BE0F3D5A788BCCD33 +:10C9F000603C09BCCC95A185E439B61416B882D642 +:10CA00005FA8AEBB507D1F88F926119B38158A3F61 +:10CA1000865AEFFD25B9268A5F914F9C24F775BB96 +:10CA20002086F84B9B777F8AD097EF47B9CB195E6A +:10CA30001407B20F6FCFCDD848723F141EDE9EBBD5 +:10CA4000203105E797BA0E19497F57DF33CB44767B +:10CA5000E958CD4706CA83E5A608F8E75D56126B8C +:10CA600082CEF104C18FFB1DFEB9885343D7F5A8D0 +:10CA7000E7FBC0000D34FE41A43B71AEEE7D2BBF41 +:10CA8000FF448AC2EDB108B14E2E2A1419E52A5688 +:10CA9000DD17B211EFE30378D7F61D0A4F037CC709 +:10CAA000CA10E0AE0241DF79979D89B541FBFF4294 +:10CAB000C5D7D1D5C2EE127E17048DBFA6C2AFE195 +:10CAC0003B74BFD7543AAE9A66617D7DAC1ABC64A4 +:10CAD000DF63EB6F617D857137E3FF5885E4E5F82F +:10CAE000139C368AA397A8727E0C445EA6F65D99C5 +:10CAF000F344EF98DC8974DE25F54B386F011B4455 +:10CB00005C6DC57F975330CCF5197571762D04F5A2 +:10CB1000695F8AAB23A9D53F0F8D9B5F4CB105F2AE +:10CB200030190C27C371E1A8ECB05C455EEC09320A +:10CB300018F303F1716E8981F3A2EF4CBB544BE7FC +:10CB40005C51996A207B75B8E262CCC2EC007E032E +:10CB500072DFEE4ECB0FF4D7575AEABDC27E71DCBE +:10CB60007E548DDB0FBB8ED84AB203F87FDB753164 +:10CB700086F3B49A9CC0D5E5449B37B41ED3F41613 +:10CB8000EA3C9CBAACCAE27D14415DE670FC7519C2 +:10CB9000E9912A8B1D674069C18244F2C3CAE5A9A5 +:10CBA000CF3F80E73BBCCD426928F8ECD923631521 +:10CBB0007CEE28787006C9C90470ACA6FCEC62C98A +:10CBC000F16762512894D86E687A70C98605076942 +:10CBD0009FD9DB2489FCE2CF54FE95B749CC1FB125 +:10CBE000CF48DE5BA4001F7DB651F0CBE26D828F93 +:10CBF000CAAAFAE7D3F3F5DB2C4A301F2D55EDC353 +:10CC0000D26D825F96556F3F984676A7E029CEBBDE +:10CC10005C22B942FC35542E2AF2E1F3D955878CB7 +:10CC2000E41F82C7D9931DF43EF2DD7F9F44FBBE13 +:10CC300068723CAA04D65B356D093F3FF622F28547 +:10CC400042F970CF8C58828BF83B87F8AC63DFE8F1 +:10CC500064923377912F99E89E1F4DEB2F7B21240F +:10CC60007FA6E65D17E3AF2D86E0D38F376C0EC944 +:10CC70001F85E47F42F9D794AAE75F6DFDA1E8AE76 +:10CC8000F1EB80DFA5D2A5BB58E4AB73639CEE60EB +:10CC9000FD5C902AE8A3B5DDBBBEFA6019D9EB02B2 +:10CCA0008B631C611FA2A7DB71ABB90D2505640660 +:10CCB0004BAD13DEA0FE1D2DD8473C25A59AF8BD2F +:10CCC0003BED1F954763FFEE04691FB50B94E41914 +:10CCD00031D84E4815FA6E5166C93E440754396A38 +:10CCE000CC6ECED3AD1B91437288FB109FA11EF476 +:10CCF00018AE60BF4BD0D93706E1A3CC1A06C620C8 +:10CD0000FC95DBA375FD5B1246EBE6572AC9BAF129 +:10CD10005B33B374E3558E09BAF1E6543BF3D1C1EA +:10CD2000824BF356E2390FEE32DB098507092F718A +:10CD300001BC20BC4F13BC0727BD37F65E3CCFE4D7 +:10CD40005423BF3799726B2497469147BC6F80EF8D +:10CD500080F97D7D8DE47D14E97C5FD562E6BB7250 +:10CD6000F9C47CF227D67B05DF35143EC8FCBC1E17 +:10CD7000D0BFC2F975CF4AAC2F974C35B15F590B74 +:10CD8000AE289F34988F564D3B5DC5EB4C92ED8499 +:10CD9000CFC51BF4E3B55533988FEB42F465ADAACC +:10CDA0004743F56B281FFEA1F0D218D203B7A7EABC +:10CDB000F3DA7F90845EF7A05E27FF6E283D34A0F3 +:10CDC0004743F8AF3955E83DAD2D97B3A3480FE57C +:10CDD0009AF5F3B4F67D8CF38C48800FDBACDCFE67 +:10CDE000B5CDCEEDFF694BE0F6A33685DB8FDB32A8 +:10CDF000B96D4E15762BB615E91C1BA49FAB5CE6EE +:10CE0000ABC951A8FE3CE837B0FC1CBC697564B2E4 +:10CE10004D8D4FF0BD8753A379FC4CF1C736293BAC +:10CE2000C0C7DDFE5336F25FE682D74476F90EF0D6 +:10CE300099C82FBC13FCDCBF1BD0A1C7760128DC2E +:10CE40002E0227E765EF857E9052C96F06CE1B9AAA +:10CE5000D25E7BCA83EBE4905D267F01439B603901 +:10CE60007955C5DB8854E793A9A4E7637A4ECC26AD +:10CE70003D7B9309C83F254E247B13ABC6536F17E8 +:10CE80004E0C5B7805FB7E2065E1FAD4C260FCB8ED +:10CE9000CD340FE95BAFC65D9CD73045676E5A9BBA +:10CEA0001C98F79C8A5F5B8AF3597ADF444AB990F1 +:10CEB000E070B03FA3C18B1644AA453BF652AADEF0 +:10CEC0004EE69ADD66BA0F58EC6831531C53BA61CE +:10CED0004298FF0A743F90E2FE4D287C428F087E04 +:10CEE000198A7E1ADD7F28DF68FC5198E2ECA27D6A +:10CEF0008D0670131E8C31F5098417B0D731FD5F94 +:10CF000055CF3F14DFE4147FBC2E9FEC6495C131F4 +:10CF10000EE991D3ED08237D71588DC772AA4E1D7D +:10CF2000482BA079B25DC2F1F51513C3C8FEAFB7A7 +:10CF30007992082F672447D843A477B6C8768E9F86 +:10CF400040D8C72555F129448759D30A594F9CAE7B +:10CF50004ACE23FDFCB58ADFB33495E4D225EE1129 +:10CF6000CF543E9144EBBC5D382A8FF699556961E8 +:10CF7000B93D7D3495E3C063054BE6AC8480DEBAF1 +:10CF80009DFEC679A737CBBCCEE98A64CE4FDF4E73 +:10CF90007A0BF545DD0699F591E6F7BD5D056CC7A1 +:10CFA000574D7BCFC6F32B4D40FEE16DF3F57A680C +:10CFB000B64BDF8FDD20ECEB8FF5EFCE86E8A3508C +:10CFC000FFEEAC4DE4196A313E7523BECB2A924D7B +:10CFD0009F529CD22A315F687AA9B64AC4ADB51572 +:10CFE0000BF2AD78EE28EF4489F45D5995524EF17D +:10CFF0006B75855414EC2F5657DCCF799FEA0DF7EB +:10D000009BE97EDD96E2FA0F923FD3963285EEA53C +:10D01000D7E37EC4FCB9DEF73EA0F3CDAA5EB16FC4 +:10D0200034E9FF2E1404A2B3372382E87C78F3C5D9 +:10D03000388E3B06E4A0C34CFE55E9E6F363480E88 +:10D0400042F50090F1A578135C0957F50BD579C32B +:10D05000E9354F2964525CDC2B814FC238A4B724D8 +:10D06000BE94E0ED4D341B459B5E2AECD4D4D76DC5 +:10D0700084D72A603BD53BBAD82AC667F0BDE24CBC +:10D08000BFED23A2D7B47ED0D9D7997E8387F8E4A9 +:10D09000E6AFAD3A3BDBE837F03D6409E8EDF73B3E +:10D0A00061913984B732ABDE8E97DBF5767CE6880A +:10D0B000C84D34EF9604BD3DEF7D733EE7272A95BA +:10D0C00009BAE7B3AC495E82F3D6CC49BA756A4077 +:10D0D000DC43CFC27632B6D58E9241E3741F3DABAE +:10D0E000B852B75EB71932293FD32F853B36215F3F +:10D0F000D6585DFAF3014C277C5E0A13F78C8DB489 +:10D100003EAED3D8FA15F3DD94D6EF38BE98E0EBF7 +:10D11000D4BD97BFBF5BB78FA3C75E466178DE7192 +:10D12000C7EBD43E166DF5C8B85E81DF5586C7845F +:10D13000A2332DAF53DB6A15FB3C188E7889A27D94 +:10D14000C5BDE68332ACA67CE92583BB81ECCB5A16 +:10D1500083B77301C27B54B28FA436D9E0AE4D437E +:10D16000FD55DCDF511645307EDDF93AB5ED2FC8AF +:10D170001E4B14D1BD6AC4DB9487ED94381E68B48D +:10D180001938BEFC2CA6336765909EFEEC67E25E04 +:10D1900017129C090BE228AF97C6F91F5759845301 +:10D1A000463C35EDC8E0FC5E5E46C942DA4F8E98DB +:10D1B0006E15F6D7D83FE0FFA6D0B8736722E5B565 +:10D1C000CA84DE815B4CACBFC20DAE4835E9C77680 +:10D1D000C87C8B6923E9BF536942DF85BF050AD547 +:10D1E0007584C7BAE5F1F4DEAD12505CA2C1575B9D +:10D1F000054EB2DF0FA5A979084AFCE1BC9A914718 +:10D20000B751BEE0545A04AF5354A5FCD944F93089 +:10D21000BBD14E7E5EEC71977D3CC2D91557B0975D +:10D22000E8DD75BC671AC9EFA93485E78FAA2859CC +:10D230005942FB3D2D03CDEFB24F1F41F3C1EB101F +:10D24000F7B39497C0A9B1F395F7C83F83FD269E25 +:10D25000A7EDBFB6F4B897CE117BDCB98CCF9B6934 +:10D2600053C625F378F29DE3C91EE1EB96A1E5F8DC +:10D27000E3752347929EAA29B18FA47A9F9AA7109B +:10D280004993194F1ED2EB760388BEA7FAF0741C9F +:10D290007F41EB03F800F1BE96EA4DC608FC8761BA +:10D2A000BF461A985F3BDDC6F9106DDC03C5885F89 +:10D2B000591B9FC9E3F690F5B4F59FDF5C7D788D2F +:10D2C0008DF06457FD61FB481731F0779725C28BCD +:10D2D000568F132E2B45C4970B0D4A0EB57363DC86 +:10D2E0009BD346D2BA8E74EA7F1CE11C352D99F58A +:10D2F000CFA7CF90FE996E62BDDE9CB98EEF0DBBBD +:10D30000CCCA8EE371544F807288CF4DFF745F6733 +:10D3100037AEDB6CFF8AE50BF9F756B297177A0C3C +:10D3200031648F16CA03E77102C270CA10E893DC39 +:10D330002D0C9CC799662579099CCF8AFD45EAFC8E +:10D34000E39BEFA87D8CF8FD1E2BD379A52AC36B38 +:10D3500063A043463EBC9839F936DAF7E23A342EF8 +:10D3600088D32E1A243B9E102EEAA4E25C99945F87 +:10D370003BD823FCCA4EA4B3930EE641BE290AACA7 +:10D380007771EA69DB785A672A7A5178AE457E333D +:10D3900028A4378CE0B3A07EE99ABAF0F5D438E23D +:10D3A0004B85C78FD33A1827966638DF4AE33A0D84 +:10D3B0002DDFF9D00FCA7736ABFAAAB9785536D730 +:10D3C0008D4C97D8DEDF942EF8BEB9F50BC62F181A +:10D3D000DD0EA26B63EB45D66B5ABF7795D0071D68 +:10D3E00026B8BB06DBC6BFCB77533E0DF5E01AD29D +:10D3F0008B8DF09A794590DF069DE707F460AE21AA +:10D40000E0D7199F96D94E84C26B7457F17E35923E +:10D410007D0EE5FE32D2B7D71AD1DED584D9E748E2 +:10D42000D8FF62CBF3B546F4CF6A12ED730CD88FF8 +:10D430001AF7ADE88FB6FFC2E0C03DB6C6CEE6F93A +:10D44000C9F677A99FB905FB343E41E3EF88D94E71 +:10D4500092A708D1FF7273C46C0FE7476C7CBF7052 +:10D46000A1228CF35F43E17376EBABBA7863D0B85B +:10D470002C097D592FF4C0B9CAD1ACCF20CD39C108 +:10D4800040FAB2766C1EE925CB38A1DFE29116C5D1 +:10D49000F8FB6794572BE2AF29BDE7AE48948FD9CC +:10D4A0005D4F9E972269BF3DBC5F235551E1F379E3 +:10D4B00059EE887194AF94FC27496F36551F49A7E0 +:10D4C000B8F28FE9AA3CDAFBD3884E73C1CDF1C81C +:10D4D0005C350F614066253FABCE9666A2F975F5C7 +:10D4E00021FE1BF8385EA9AD0AAD1B0ACA63C854F9 +:10D4F000F7D0739719E130A978688A491E47EF2160 +:10D500005C8A800BE1C4BE29AE275EF8F1DB14898A +:10D51000E43BD3CAF7C5E1371CCF715FC1AFEF6CF5 +:10D52000437B8922B5BDAD9BDBF5E920F4B0D16F1B +:10D5300076E03ACB8F03DBA772B991EDC085EE643C +:10D5400008F6DB268F13FE7A54B7C893225E1D843B +:10D55000D7B854F01990AE71AFBCB9AD5DA27911D6 +:10D560003C4FA3E3CD23A0332C26806FA48383E814 +:10D57000A0E11DF1994FFEE31BDF1D984A74FC23C7 +:10D58000C185EF77850BB9EF7F39CC4B7E42289C64 +:10D590002E159E5078175D239C8BAE11CE45147CC2 +:10D5A000140E0DAF26BF1A9E34F905556FCDAD4F41 +:10D5B000DEB4560AF46BAB92390ED4E01CCC3F9B20 +:10D5C000952BF1CF707C7393C69FAA1ED1F0A8C192 +:10D5D000A7E9852EBA3FD4C117BD510F5F34CB5395 +:10D5E00054EB1F594FC911467E5E9799B091F29244 +:10D5F000513D17E8520EDAC6A5083C777E03E48752 +:10D6000047B5EEE2F983CE13720E4D3F869E47D3A7 +:10D610009783CFA5EA4D558F6AFA731A2A00D67BF5 +:10D62000A49B25F293DD3AFFAF04EED3F98765D6CC +:10D63000FB43F25FFF4D37FF968455BAF14AE54947 +:10D64000DDF8AD994FE9FAD58E6775F367156FD49C +:10D650008DD7585FD0F5A7FA7BD8EF3CD856C1716B +:10D66000F24D67FAD9FFF4A9F1F46B6A3CFD06C5E7 +:10D67000D3289FFB289EC6767F9B839FFFEFB662D1 +:10D680006E0FB439B9ED6973711B2AD7335FBADDF8 +:10D6900048FE6B714F07FBBF3F4D751F1887749A8B +:10D6A00065F0B647203D269EE894B98ED2EDD0D9DC +:10D6B000DFD57B27BD437E56EC0119C294A1F56FDF +:10D6C000D4D7323883F2F35155FD40F5D3516A9ED9 +:10D6D00065A6111EB3207D6B6C46DF28A4D7A1710F +:10D6E000C26F24754DF7A1F556E07BD4FA7AC9D103 +:10D6F0000EFCDC43F78CD8FADC790C8ACB1AAFDE4F +:10D700003FE28FC5081E5A4F76CA7013E543E262A6 +:10D710008D64E7EB6810E19C837B5E8FEFCDB37582 +:10D72000729E68EEFE479B16E07378CC53C87E93DA +:10D7300066C73D1F182EDF78ED76FC10399B5457D5 +:10D7400020897CA227DAC879BAD0BCC96FC689FC07 +:10D75000EFCC768F1C4971CD21E0FBCD59AA9D45B8 +:10D760007CACB1C404E450E3FF1ABBD197114976F5 +:10D77000E7A9327AAFF1A8C2F808F51BB4B847E3BD +:10D780007BD4F7ED34FFC271607F6E62AFD7BF5EAE +:10D79000191C870C171F69F0EF6AAB67BED9D3E677 +:10D7A000E6D6D7D6A0F2630BF7DF686BE5FEBE3690 +:10D7B0000FB7FBDBD6A8FCD8C1E307DA9EE1FEC1B8 +:10D7C00036AFCA972FF0F39B54FD73699CAA97ACB0 +:10D7D000257C1F0346D106F841F1C055F8A131411F +:10D7E000E8E750BE188A0F308050E81E651EDA4305 +:10D7F000D2637780673CD5A1D42FE930719DEA8F41 +:10D80000E4873ADBD326CA4F84EAB7DB4061BE1B0C +:10D810006CEFDD8E6BB1F79A7E93316E233B659191 +:10D82000EF77505EE187FB17EE168263F8FD045D2B +:10D830004C0918FBC6505EF2D8561F8270AED0B9A4 +:10D84000DF7985FBDFD0387367A2908B1F0A1F46F4 +:10D85000E426A2FB70F08DCD704E492F0CD8B3702A +:10D8600096796CC7D8B82EDA6CF17A1FA578EFD507 +:10D87000305117617326D504E573A6A70B7DF34CD1 +:10D88000AC737A3AFB07BD5B7F49F2D23582F32F46 +:10D89000A171D4173D65A382FDA5507DDA6CBFC888 +:10D8A0007237C8CE4B06B6F3CD067053DD539E05D6 +:10D8B000AC12C2FAD7F4D2D962DFA95CE771C16EAB +:10D8C000BCEA7D6973EB795E7FC87183A8AF6ADEBD +:10D8D0005D685F189437589FAED6456080F8A935CB +:10D8E00080BF6BE5E769FDF53AFDF00F673F9DBF2F +:10D8F000D5E7ADD0EC107E67B92B990EF32842FA2C +:10D9000041F7034E37B5B614F793441F93E4B7D1EC +:10D91000F8B91DDFA6911F7DEEA649F61218AC0FCF +:10D92000AF55FF697A4FD3838F9BD5EF6406F23AE8 +:10D93000711328AFA3D1E397E9FAFA845039EB9B2E +:10D9400080044378FB5E16F57B7D11E15E0949EEAC +:10D95000DCF597E3542F053EBDFD765A6D5C179BB1 +:10D960003FDFC1761CD08E93EB8A27ED0D5EB7DCCE +:10D9700028E220303A32EF0C929B76B5FEE2056C3D +:10D98000E9FBA5C8F97EA312C46F3B54784BE64E61 +:10D99000078E2FE73BD90F8CB48BFC50B9150AC208 +:10D9A00068DDEF2E66D3BA33553F61AD097C44B7CD +:10D9B00051C51324F213B7C73A5F49A7FCE91353C3 +:10D9C000A339FF4CB9D6EB03FAA85CAE4A584072B3 +:10D9D00013676479D5F44C9DEDDFCDB281F2DD0E95 +:10D9E000A67728BE00FCFBD6E37BCE6EC9BE16062A +:10D9F000CBB1B37BEF71F2EB87F34F87D34FA1FA33 +:10DA000043C37B289EB7C7BADEA5736AFA25F4BC68 +:10DA10005A1EB909FCCCA76BE76F7251FB80A48832 +:10DA2000FB67E8705E87F45EDE7D3FD0FB79B2A8CD +:10DA30008FEDAF14F150A87C9F55E9D3A8EA8BBCB9 +:10DA400058B026103DDCC0FAB3AF324BC4211931B7 +:10DA5000AADEE84FAF0DAABFD4FC9A5EF5BB93D9FE +:10DA6000DD611E39287FF0457AB48883AC5FE8F425 +:10DA7000E0F2D66F74FA6B79B6E087BC76259FEA40 +:10DA8000CB56AAF77D5F26B92E91DC2DED7C6AC7B7 +:10DA90000185F6DBF0B30F88CEFB6D422F1F18C94E +:10DAA000B8E993F47542B3ADE755FBBF51272F4753 +:10DAB000AADFE3387776D7080FE15F834B8B8F358A +:10DAC0007DDDB4E7EC49B2DBBDD2F9930F13FE5E06 +:10DAD000B6B07FD64870C7725C6DCBC075B7EF37F4 +:10DAE000307E9B2A2D9B64CE232AE36B230278E9A8 +:10DAF0003B7BE5FA250D3E6D3F0DAE5E49E429B452 +:10DB000079A333845D9A9D2EEEC98F987A3E27BA09 +:10DB10009CDB71A34409C781E7D13D39F41D8F46D1 +:10DB200097FF5F7ED23C10FEF271C3AA07CC88AF8C +:10DB3000DECEF526CE2BFF48FF4883B73D02BCB4AE +:10DB40001E3841B1C7730A4FD42BE2218DF114B7AF +:10DB500089BE64DBF70DE9B1696ACB41248E4F556C +:10DB6000C17E5C6AE17A402B7470BB567228D4DEA9 +:10DB70002CB98C229FED657CCD8096B1F4FC26AB50 +:10DB800023C168A07B4691479C13BD662693311E36 +:10DB90001EA7FB0EA3D9638A27BD581BA5D66B0A07 +:10DBA0003C69F5930DF83B15F1628C06C588F31BB3 +:10DBB000D06F37217EEB96CCFD7936CDB74F653CE3 +:10DBC0006AF597F41EE1F1B6032DD5E4EFDCBEF75C +:10DBD0007F1E74E2F3B3311D9C97FD5BCFA69C17AB +:10DBE00071CED223BBF83BA8465FCF0C42EF72E860 +:10DBF000677BA4E17F3EF4707B17F473EB063B8FE9 +:10DC00002F0407B7F7808BDBC5D0C2EDFBA33734F9 +:10DC1000A124C0DC51EB4C5F40000FCBA21F2BA214 +:10DC20007DECA5CF8C637DA3DE4F69F728A1F71C9F +:10DC300035D136BE0FD1EE3B920DEEA68C427E4F13 +:10DC4000DC7F9E8CF0B6F3FD87F34EC2775FB4198C +:10DC5000E83BCBBE91429F78CE01E763FB4CEAFCE8 +:10DC6000F30AF70BCAF2447DEB2585FDB329EA3DA3 +:10DC7000A4A66F0B6E1475CB7059CC9FD6AFAF575F +:10DC80002BA02426BDFFADC2F717377F6DBCAA3E7F +:10DC9000B6650A7DC6255FF86741ACA12538BFD1BE +:10DCA0009E102FF2836ADFA2D839DFB12543E8CB7B +:10DCB000BE4803F30BFED4598B085E41DF29BBDE5F +:10DCC00052F91203CFF8C0F782538CBEBDF47CB971 +:10DCD000AAF7512BB3DD9A4A7C4A7CD9ADB70390A1 +:10DCE0007023D7114C5641D0E25909D79A1F437C73 +:10DCF000DD2333FF423FB74EB0B3DD2F0507B7D367 +:10DD0000C1C52DF239B715D0C1ED4FA093DB2AE87C +:10DD1000E1166E7038E822DB60F5C9428E1FB1F360 +:10DD2000776F954B0C94BF2EB85DD4990E8797BF33 +:10DD3000A87A6A78BCA040175D0B5EDC02BE50BCBE +:10DD40008CCD6479D2F0A2E1230CBC0984C769E0D0 +:10DD500097A9A59435BD5F826249FD327072BF7C80 +:10DD6000587CF8DAE9DEBDD8EF3672BE23141F65A1 +:10DD7000824F34BED1F45A8F7AFE4708D691013DC6 +:10DD800004990AF7357D8472C7F7C8DAFBA1FA4A0D +:10DD90001B2F18517A5141D57E2EE373CE9B17E489 +:10DDA00097AEA452A96F32FE43F4A794BE9482FDAD +:10DDB0006F33BE17FDDCD27C93036095F4F7D9D3A3 +:10DDC00071F1F643426E4111F71BDA778BED8784D0 +:10DDD000DC5EB0FDCC61273B3AD6E6A0F33E61465F +:10DDE0001C223C568B68E5541157EE6C03FECE4363 +:10DDF00083D762117E20CEF790DF36F28C672EE754 +:10DE0000DFD4732655F85E3329C41B4A3EE551D64C +:10DE100024B9CF939DD4D64778585F5FA7C2A3BDDE +:10DE200037C96676125C10979C4FE7FF38C9F51525 +:10DE3000BDD71721EE5FB5792FA8FEE62463874C86 +:10DE4000F7A17407C67EC910ED8D99CEBF675CE15E +:10DE5000F950F6A9EF133327A5E232DD964CCA1F1D +:10DE60008EF82E9DFC80CF271C79DC9F1CE04F098B +:10DE700089331FCFDFEE54ED9656FF4F7E1AD271D5 +:10DE8000D23D4E99545CDF27289A280F45F52DAFD7 +:10DE900073495AA63B2693EAAFE4FEC5C4979F4751 +:10DEA0001F317FC2F23456F01908FDB47BCF9B0FAF +:10DEB0005F27BA2E0892A3E63DDF7CF521CA5DF309 +:10DEC000059B83A6F7450AFC4CD9F5EC4AC61FD83A +:10DED000747A4393BBC9DD16FE0E6ACAAEAC7B6989 +:10DEE000DEB4232752E95C379FF0B753BAAB6FF724 +:10DEF0007BD7097ED7EEAF2E493FC68E9F56EDC524 +:10DF000069ABE033AD5E65C56E89EF6F56A8F56B02 +:10DF10002BA82E19DF6ADA6FE2FB26ADEEB4413D85 +:10DF2000E739F5DEA361C32251AFEC15FEB582FFE0 +:10DF3000480F4C3C6E0CC90F8BEF7E9B3A43F2C3EB +:10DF40001BCAAEF81D79685DCBF44CB5AE25111235 +:10DF5000F93C6ADDE750E7D7EA581683F356E21337 +:10DF600024934C7C5B6814F5DCE5F2232C5F2B12C8 +:10DF7000B3F3445DADA8435E1226CE17AED62FAFE5 +:10DF8000785E061BE3C7CCF53E1B518D1493FFFD55 +:10DF9000F5BFB09C2C51CFA2C9E37D6B24BE8F840A +:10DFA0000DB1CC6BB95B2D2C37B95B4739094FB933 +:10DFB00066E1876FDC6A5943FDF6D5E11ED2C77F63 +:10DFC00088EE1F43DF7DB78789FA323297742F9826 +:10DFD0009BD29F42F6FEE14C61D7DA55BBAFDD8B99 +:10DFE0006AF7E9EDAABD5F11913E8AE2B78179F641 +:10DFF00031BAEFA2DB553FBC80E024BFB27F8C5822 +:10E00000274C9C63EFA1DB46905FFCB2D13582EADE +:10E01000CF2E1C4D8982ABD49315FA901857C97333 +:10E02000141C5DC7DF1B153C63147851F970679BA6 +:10E03000133E3605F0AE9DA35CDE5666A6FBC47BA0 +:10E0400080EB3657BCF9EB762BF6573CC95F342092 +:10E05000A8995164D70AF7CBFC1DD0E4FDA2EE6A63 +:10E06000A75A076A49308012C45F614A3828417C48 +:10E070003402FD8AE07E84638C6E7E54718A6EBCAD +:10E080004BADBFD1EAA6353F37DA7983EEBD693DA6 +:10E09000A20E2CB6224FF71CBE1072508CFF443CCF +:10E0A000DB2293BC4DF1033C974CDF31754024B625 +:10E0B000937BF5F282F4E37A1E8B5AF71576D4A897 +:10E0C000FB5EDE629BC1F5E19661EAC17E97A97EA7 +:10E0D000273F16C6EABE931FC0B7BE3EAC08D2FEAD +:10E0E000D7D402C2AF09BC387E81DE603B045E4FEC +:10E0F00010BE35F9DA099D6CCF47BAF4781F55AFD9 +:10E10000C7FB68B71EEFD735E8F19ED8A2C7FBF56D +:10E11000AD7AFC267BF4784D5D3359377F5C47A997 +:10E12000AE9FF1CC4F74F3B3BCB5BAFE8D2FCCD3F8 +:10E13000CD1FDFB950379EDBBDF49AF860826F8542 +:10E140006E9EC607F9FB1FBA221F78F01FEB47F53A +:10E15000FB8F62C43BE56987A37FB1BF0348DFFD46 +:10E16000583EE80DE5836BD49F07A8C61EEDE1CCB1 +:10E17000FDA26E6DA6CDCA756DC83799745F7A0120 +:10E18000C21D643734BFC1A5EA99593623DB8D9986 +:10E1900023841ED2EAC942E3472D8E99552C85E48B +:10E1A00009F575EDC3DD7B14F6F874FD09474126CA +:10E1B000BB59F8EF4A7B04EE937F42DCA384C6ABE5 +:10E1C000057E773B99B789BD68A6158A5FF77F43BF +:10E1D000F9A4696AABDDBB84C659B066339FD76CBE +:10E1E000D7CE21F46F68BCFBA02CFC8F4B0637FB0D +:10E1F000BF16D27F72C01F6E2F1171AF16EFBE9D7A +:10E20000E84EC9A27A30437F2CB0DFEF17F77AD0FF +:10E2100009E4AFF50DD423FD731DD563F44503D791 +:10E22000DFFC76D5FA3A0FD78F81DD5F24D243F435 +:10E230003329CB9D9D85FAF69424E2D005C51FFFB6 +:10E24000EA258437270B449DC0FC4ECE436D8F7565 +:10E25000E666150E5F3FACE5DDB43C5C579B8FDB9B +:10E2600011D90E8E4F42F3617E83C86F781E12DF84 +:10E27000C57CC64005FC8E0B6B4CEC77801AB7DF73 +:10E28000A9D245CB6FCC57CF710A976840FB7A670C +:10E29000F75F982ECB127AD5BC488B834A3B178DFB +:10E2A000B5717D0838F31D22FFA5E53BAE937F884D +:10E2B0009F34DCF997259CD5E5C9605BEC35D59595 +:10E2C00006CE2DD63F5529FC825395D7717D6660C9 +:10E2D000FDCF39EF7667CB211DBFDFDDFABE8EBFE4 +:10E2E00017783ED28DFBE3FA4D9457F457644D27CF +:10E2F000BF02E9BE8CE8EEDF317AC61D88CF732FEE +:10E300005B8AAEA53E7C59C267BCFF89B61EA6AB30 +:10E3100076BE936DC7B9EF6FF3731B7A3E2D2FA1B5 +:10E32000B5E6D780F583560F3A54BE42931BF30DE2 +:10E3300029BCCE83B2F3A488B39897E1D20A13C75D +:10E34000AF27D43ADC136A1DEE09B50EF7845A776D +:10E350007B42ADBBED33D9D6503EE38424EE15DECF +:10E360001DF3D556332EFDBB44F7CF89BFFB4AFBC7 +:10E37000BF3290FE8BF327913CAD8D7777109E24B2 +:10E380000C2B46735DBE279DFCC433064F0ED54D46 +:10E39000BDF5DB4FEAA80EEA4CB8E773F2405ECF5A +:10E3A000FAA88EE2B93366218747B2DEAAA33AA85B +:10E3B000777151AA87F4EC94443D9BCD6FA6FBABDB +:10E3C0007F1BE9DE40FB52DD177FCF88CF893FB549 +:10E3D0007C689F49F87B7DAADFF7EB2C71FFB3398E +:10E3E0004BF89F5ABB5B95D723D4B29CAE4BE7FF4B +:10E3F0000FA0CAC275E5B8BF93EA603C7B2C9C5F56 +:10E4000009AD8FCAFB93C52705E5537764258BFFBC +:10E410003F25557CD71F776B18E785C0DF934435C0 +:10E420005E03F01E15F5A5E728CF4C727A0FE8EAD7 +:10E43000B3766409BFB4E9CD5327294F352FCBBD3F +:10E44000332BA89EA929722FE7B70E6429BC1FC2DF +:10E45000C9F1A14586C7883E4D563F7FDF335C9E9C +:10E460007CA8739FBBB7E79FB393A9BE4A1947FB2C +:10E4700068FB221C07B282F2DA1A1C8175AE2E07E5 +:10E480005AFE57EB1FA97E229DE4278FEAD4AE6087 +:10E49000374F6589FCC2091384D4B1A97803AD8EC6 +:10E4A0002D9BF5D4F75957AE63EBCB12E7CF43BBA7 +:10E4B0004B797E4B38DA8ABCC0BA38DF4DF738F377 +:10E4C0005B925F3A807858BA793C7FE7A0C1A1ADF2 +:10E4D000FB6592F36C56505E1DF94DFCFF22956171 +:10E4E000CC1F4D7BDE3F49FFFFC37DBF199F4FF817 +:10E4F000D5DE0BC52FE23591F079D8E033AB7574DA +:10E500005F115EB7EF3FCC756A1A7E7F2C3EFB121F +:10E510007B388EECDBF84D12D5ED36A9F7604DDA7D +:10E52000FD4B973EBF84F8F0509E62F0BD0BF0FDAE +:10E530008D45B51F16EDFDB146DDFBBF887445DC8A +:10E5400080E7DCA1EA099CEF35A8796DB237037941 +:10E550006DD51E15AAAA483A2EF2D985D4929DCF20 +:10E560008E62FB54A0ED877011FD1E973C9C271A0C +:10E57000B0EF6A7E5B5EB492F380C5D0C1AD454E0C +:10E5800066BB68F91038EF3F90C77A721FC7F5FF76 +:10E5900017A1D911A80051000000000000000000E0 +:10E5A0001F8B080000000000000BFB51CFC0F003E0 +:10E5B000095773A3F21FA0F1E7B2A3F215B950F9FE +:10E5C00082ACA8FC7C34FD8430231769EA93981947 +:10E5D00018B280B80888AB98F1ABBDCB44D8BC5218 +:10E5E00019082D01A47D80B80C88B70B3330EC14CA +:10E5F0006560E016616038214C9AFB08E17582D4B1 +:10E60000356F149386551551F9E53A0C0C1B7419A6 +:10E61000187EE941F83248F282FA0C0C153A10F6ED +:10E620006C3506867EA01A6145ECE6CE01CA4F0025 +:10E63000CA2BE943F800D43D6BC768030000000013 +:10E6400000000000000000001F8B08000000000018 +:10E65000000BDD7D0B7854D5B5F03E67CE9957267B +:10E660009393270384E424040812601212888876A6 +:10E67000120206C53A3CD4880893884A5124525A5B +:10E68000634B9BC93B04B0C18B152DC28041D1AAFD +:10E690008D0A96EBD5FE41A846B4BD5151B1C536A1 +:10E6A00050AFF6D6C7455B5BEFFDF5F2AFB5F63E72 +:10E6B00099734E1282F7F1FFF7FBE3A7DB7DF66B50 +:10E6C000EDB5D65EAFFD18973B9969D98C9DC5BF56 +:10E6D0006F30B650628C95C453C63A45AA3BC38985 +:10E6E000E67CBF149E8A6994B1745B9AC19883F1E9 +:10E6F0003F475AEBA78E69987AA30E3FA6CAFBFD47 +:10E700006E5E7696C5DBA9592CD25DC058137E1A71 +:10E710002D1AA731A664061FEC0058329993EA29F6 +:10E72000696EEA47D1A22C02F54749914C826721D4 +:10E7300053D84CC63CCCF80B318457CDC84FC27A65 +:10E74000CC97C2D885F1791AE9AE7AD6A2A8A6BC30 +:10E75000CAAA100EC662344FF57B2C960AF0B32F6E +:10E7600097E88BA70EDF8F911AF3691A173C1129CE +:10E77000865CBA33B80FF1200D3DAF5903F37246F2 +:10E78000114FA679CD3AD7BC9A12278A79A50D09DF +:10E790004F33CE6B427C1E03DF717EBEE1DBD9E7D7 +:10E7A000315C79F3B850A01ABA88260E3D3F15E7C0 +:10E7B00097C3D862313FD5E724BAC1BC160F352FB5 +:10E7C00085454352CEE079299A9BF0628CABB89D87 +:10E7D0002DCA8C387C2B99C6FB1F183FC8902F1D63 +:10E7E0001AA376152CB212C7033EEC233EF485081B +:10E7F000BFCE00944FC7345415057C361FBE90150C +:10E80000603B5F90DD0AA9D317610BA15EF3570E41 +:10E81000CE0F69C5D4BF01C732265BF033C0C70233 +:10E820000E3BBEF68D1378B7D17FDF3DF303374043 +:10E83000FF7588A721F062B407BCD5119F08FE3090 +:10E84000F860DF3D025F6943D333CFED6851520773 +:10E85000F341D7B6993AEF073A82F53A4A8C37B97D +:10E8600022262B3A635E318F7B334BDFA986FC2651 +:10E8700029F472037CCB0D69E55E286AF0463ACC38 +:10E88000F31FB59CC9D89FB17EE639967B4E437A7B +:10E89000CFD2DCA41A987737932CE31B694B3DCC7D +:10E8A00009F8F4BE7A37A57F7B7712CD6738BE6B47 +:10E8B000ABD79AB1DE403E6D436F0EAEB3801C9C69 +:10E8C0000070AAE94BAB902F9DE3F42292412149BD +:10E8D000C1F979703E50BE57C001F8DCCBE518C7CE +:10E8E000A333C0F17A412812D200DEC92C1295A0C0 +:10E8F000DF8CFD2CD863F0A8094FA3C272D4E527A2 +:10E900003CFC14F1901BE86C0431C272AAD80B983D +:10E910001A78B867A94CF45E7FEDC4BD8E9C38DCD4 +:10E920009F08FE61F99C6E4C0906108EE1D6E1BD90 +:10E9300080A7025ACFDD2477C72E6731E4E72DE2A6 +:10E94000FB1A16FE079CCFD85BC344872EC9E0B7DD +:10E9500000437E6A1670DFBBC24BF0348FD3F620C3 +:10E960003C2F211C8887D5024F83F9EE252CB7F365 +:10E97000DDD8E51192F107E5C82B089FA338ACB1AB +:10E980005CC652A5EE1E27A05895419EFB08FC3E92 +:10E990001C3F20F06FF07F4A81BE17E5C349418FCD +:10E9A000C0C2D6DB65C067C2C905FFCC605EA3D21A +:10E9B00014C26FA0BF7A218334B3A05B7232FA7E97 +:10E9C000CA05E53E5FF430E239E58AE351EC7A9F0F +:10E9D0001C3989FD24A46D90108ECCDA208BC0F8F0 +:10E9E0003F56234CC3F53EA73B14867C4BFA4C564E +:10E9F0006DE2AF8F051D1C01168A15C4E97CAF833B +:10EA0000C3BB3DBCDE73B30FEB7909CE0B58B1E04D +:10EA10000F600BE00F27F2874E7CF011F6A32FD783 +:10EA20005FC07693035AA3A413FF8F42BC011CA3BB +:10EA3000B1DD8FD39D55318E97E3886F9F2CF0A267 +:10EA4000C33F80A74499C37090A904D7A61B210394 +:10EA5000E3A4FB584C077C3956F37C46018B856058 +:10EA6000E23E1BDE7C025F81E2600F763536587B2A +:10EA70003887E38749007F0AEB0BA9F02141EF8932 +:10EA8000A2AC6A536A7FFF03E8AFADD7118C321393 +:10EA90003F32E0C7A9713CB93361DDE50BDE60713F +:10EAA000BE34EA8FA4470CBE517C5CCF19FA02F841 +:10EAB000364522B9C6F9F67CF5925AE7D0DF43B95C +:10EAC000A66832E2D1E9E6786C092C8E227E3E47B8 +:10EAD0001C23BE3A0B894EC073A4A7F04F86BC1A04 +:10EAE00008C590FF482ECE8CDB2BEE3C99F598E6BE +:10EAF000A9647A2D795605EC06E37D47D8306A9DE6 +:10EB000093E070FA385F83DE89214B2B3ED6E3F128 +:10EB1000630D27B5C7E99E1D8FF9EFD37846FB4DEE +:10EB20007945C4A7F6792AD80EEA48D0F06CCEE031 +:10EB300076C3E3C736DE522BBCE7DDCEA7E8EF1B7A +:10EB40006D72CFD54E61EF1BF801245E36603772CF +:10EB50003AB5A9EC90047AB629B395D8AB0DFF036A +:10EB6000F46D659CFE2C225BF49D23533EE5223B15 +:10EB700041E7FD04B8BDE562F37BA842E0FCECAFE1 +:10EB80001CC15FC92CBC02F91EECC031663CAB4E07 +:10EB90006E6FB2E6A5546FEFA6EFF64868B77C4FEC +:10EBA0002B74E871BEDA6BC31B638D04D7EEFA18C1 +:10EBB000FB032C5135AD96E462F6C630D131ABEE95 +:10EBC0008C84795766BF8479A37C805F9B397FB73B +:10EBD000B42F4E6258EED665940BB99D398D6E0BED +:10EBE0009F86D952582FD98CF3E34F203D6BF02BE1 +:10EBF0008CEFAAF3127F187C69F0A1D1FF88EB316A +:10EC00001A3A9C07F3BB42E0FD0A213758B1FA5E7D +:10EC1000BF41CF5CA26F3C0FF4FDF84E07C99F685F +:10EC2000A114DB270D2E5F28E4D042FC6EC00770D4 +:10EC3000C7248919FA16F1BA50941D39F8F6C41987 +:10EC400000F2AF830EA03160F7E04B5B6640FFFF40 +:10EC50007821E475012FD6C7FF85FC3FE6B050054B +:10EC6000969748B128F4BB704E1BF91757943A4851 +:10EC70002F2C44F84D78F9E4D09F15C4FFBA39D64B +:10EC8000EF8F21EC24972A685D19F0AC2D7250FFAC +:10EC9000BF2E96681D1F7DF783BB2E02F85E9D2355 +:10ECA0000511BE5F07FFE043BA19E30DE04B671A99 +:10ECB000E2CB3ECE00BEDDC12A940FAB35A78E72EB +:10ECC000E71647B057477A8F9283FB74FC3EB10238 +:10ECD000F16FC8C537A5D1DC8FF0C9C11E6CF7A68E +:10ECE000A314F97238BAAE5618D38A20655BFAD0ED +:10ECF000CE6631F54CBF69FDD69D6C683E6A926365 +:10ED000087A5C4B4F7A73074406621DD3EF32D4ECD +:10ED1000EA61C3F7FFA77A7703FA497FAB8F361F03 +:10ED2000550797DFE260B5B89E6E61EC3D570ACE9D +:10ED300037EABC16F4C749C9CDE72FE4BA31CF5B37 +:10ED4000F67B1A14139E56FBF8BAB7C33D803FD129 +:10ED50001EFAEFC1FEEDED876DA758ED69B0674E65 +:10ED6000A13C70A7AD8F8E017CDEF2581933EB1DEC +:10ED7000841BF59E31CEB0F0A69D1FBC23ADC3CF42 +:10ED80007C8DAD68AF34A99C1F9AD3E560231BCC62 +:10ED90000F06FE9B7C8D1943E90B03FFC007BA8663 +:10EDA000F8074786F8E6ADA652D46D6364CF90F6B7 +:10EDB000F7487CE294814F12FEFBF924477673F901 +:10EDC000F03F874F26CAE9FF73F8C4B55172F6FBCE +:10EDD000D04F642F8E4AC3CF12E37AE2DBCCACDF94 +:10EDE000B1BE3613FD62FEB75261EE52900B7294C3 +:10EDF000B78F806181FA6665D465B56B0C7882E562 +:10EE0000A4F7560A7BEA70FFD36FCE84F17E1375A8 +:10EE100004511EFF66A383EC9CDFD472F9D8CF6245 +:10EE20005B67A23E38EE2039D61F3D9228FCCA2CE3 +:10EE3000C4CF55827F4FD523A2187B17FCBC9E49B7 +:10EE400084EF2C8CA7BCABF65D0F2E3BFCCD2C3B8E +:10EE50000EAECABB4880D98C7534CE6B88166094D0 +:10EE600089E7AF6E9C5716257F664BEBA5A6F9D5B3 +:10EE70006C9442644F8719F92F9B24F1BD5D2238B1 +:10EE8000DDE067A39F1391791C6294148EC826BF9E +:10EE90008FE50122CFC3AEFA3DC23F299E2F9123B9 +:10EEA0006BB09F9A8DC94ED40735ED9FAAB82E3707 +:10EEB000CB1AE763A56F1CCEBF7FC00FEB1BB768F3 +:10EEC000AA693C0FC7EF667968BFD83E5EF5C64FAA +:10EED0007F390AF5459D142437D0DD376E85C95F2B +:10EEE000EC402700E617ADE6E345474BE47F1AE523 +:10EEF000F5384E3A8E27FCBDFFF8BC37E1BA183C16 +:10EF00006F26F4694F22E2F537AB97244568DE118E +:10EF1000D2AF063FBD7CEA6115F9902D4D27BEAFFB +:10EF2000697658EC98151B122C7CB96CE39273C669 +:10EF30000358AD898FCDEB8AA5113FA4083E4967E0 +:10EF4000E02D91FDCDE31D1412017832B45AF21771 +:10EF500003A59D87B90F1023FC8C097597814A651D +:10EF600077272E7B27A25381AECCC43824FC918F07 +:10EF7000A644C57A96CEBAD03F6521B4F733F1BB2B +:10EF8000010FF05DE056937D04FFA62CB7E67DC52A +:10EF90008AC55E7098EDA99CF87C8CF9FA8C38577C +:10EFA000A893E2059BA5EE13B87EB6B8AF2F5B0819 +:10EFB000F874F633E607BE4F4C5362316C1FE4F22F +:10EFC000C581F306FE494973C77AA08F842CE048B7 +:10EFD000A48302D887D451190991DD2BE68F7134AF +:10EFE000A45B8AA0DB96CAA264AC67F4070B4E3F11 +:10EFF00057BC4229E0F13EA5A0BD8FA7DC6F776B1F +:10F00000B5843F90AF6F201FB1E5D290F14D639C66 +:10F0100091E4E279D7034F5581F9DFC1BC418CBB44 +:10F020002539832722D0B42EDF49FA569D531B453C +:10F03000FA5F2745FE09D775D22575D9C8BFD225F5 +:10F040007593FA81FFFC53B8DEAABA68397B1FD2E8 +:10F05000405A38FA3E94BB1D0EDEFF992C8B1FA937 +:10F06000F65CCB748C3FFB82A110DAF9AC90E20F16 +:10F07000AA3B48A9E6E0EB5016A9DB21ECE310FC23 +:10F0800063EAA7C11BF91BC28371378CCB397C465D +:10F090009CADFFBE9B51EE26BA49EECE7314249D63 +:10F0A00036D905643898F8C688B31979D5ED6F7EDE +:10F0B0006F06C2C1E55547E2FE00F61B6511A703C6 +:10F0C000E79317B2C6F17DDC8F89D77F2840FE0D0C +:10F0D000DAF3B0AEFC172D7763B932C788CFD71AF1 +:10F0E000716CCD81F3AAB2EA57771AB4A3F5CA3E80 +:10F0F00022FF5D7CEF987C937BA8F5FE133912709C +:10F1000098E4A433C0E33B896CA786F6096031EF2D +:10F110006CAA89DE22EE54536AF0957ECD6F81DEB3 +:10F12000DFEA55590766BF046B6626C2CFFF4EFF64 +:10F1300081FB3FDF42FF05D2552CECC7C97FCCE4F1 +:10F14000CA6E9F881301BE3FF6CD7CB021874F0168 +:10F15000E16E1671AD390E1EBF557CAD9CDFE372BA +:10F16000403A2BF1F544FB253E2E37A2CCDD40F290 +:10F17000AA9DFB0B51F807F337765AFD879B77580A +:10F18000F337B1C519C8C7376D57C1A702786DF2FB +:10F1900022CFC1E3E137B3DA56D4F36D22DE5FA3A9 +:10F1A00031251584E1DA9F3F3013E35F7305DFFDFE +:10F1B00009F84277C5F1BA262DE60C15C4E7A73049 +:10F1C0003EBF2629F8CD8BA4E1E7D7A6F67D13FD37 +:10F1D000A4E85695F891097949ED6128E58023E482 +:10F1E00099666947F0DED06E9DDF48F3B7CF1724EC +:10F1F00034CD77CDFE6AE287E1E6E3DC2F517CCFA8 +:10F20000CE57CBC43A31F8E66F1EFF34960472C174 +:10F21000CDD33BBCFEBD98FECD931543BE684421C3 +:10F22000897AB69C713FF87789B126A26FED74A4F4 +:10F23000EF48ED5BB17DC97FBC7DC77FB2FD5D232B +:10F24000C0BF29AD338CEBD988BFB8DDA110C7365C +:10F250005FCF9B0223946742B9E31CE579E76E0F09 +:10F26000EBF2EC59E09B6AFC44FA3A9A89709D16DD +:10F27000F663AF1ABE12EDBADE371D6802B3DE6464 +:10F28000AD3580F3689174B487ABB72C4AC2384E61 +:10F29000F571479A9C231637D6CF59D0857EF73D16 +:10F2A0000E55D867FD0AEA99EAD29CF9289F7BD5CA +:10F2B0006866328C5FF9431E172A2B6D5885EDBEA8 +:10F2C000A95FABBA304EFE58D372CCAFD12F555C8C +:10F2D000306E4CF4F3F1A34FCE64005FEFE389ACE2 +:10F2E00007E157624E06E91AE077E4B75B7E96487D +:10F2F0007A77CD536B1F5C08FD483F4F24782A9FD7 +:10F30000BAF92117C1D7C4F9F7992549778B79B98B +:10F310000135BD0D621F321ACD5C024DD6BAD84AF6 +:10F32000D41B061E0CFEAD692F7C318070ED4FA6FC +:10F33000FD8E01BE57A03EB4AF8674F1107CFF4B2A +:10F34000078F7B7F94E3AA4238A5FD8757D0FCBA8C +:10F35000AF51717E5273B2F39F60BC671DAA518F8B +:10F36000E6117D448A4D80F28F1E91F8BCBAA7EE5B +:10F37000F1E4E0F87B9C35B43FDC407831E0ADD976 +:10F380005FD83A06EAD56C49CE95615E737FF6B8D0 +:10F390001FEDBF75FB1D3D680F404A76C10DED0E98 +:10F3A0009B3F12F249C007B709F973DB81B5249F6F +:10F3B0006FEBDEFC29CA9F7587D4D366B900782627 +:10F3C0007FF796B71D418C15DDF2F4C37ED4BF7F65 +:10F3D000EADBE7477AC038D54E5807C5AF2A96769C +:10F3E000D8FF172983FB03854EFEDDBAEE4D7CBCAA +:10F3F00003577C8071AD750CDA9BE4CF9FF07F469C +:10F400000FF69B3F7658E32B9FB3576792BEDB9F67 +:10F410003AA4BD62F8CB861CFAE4D09F774561FC24 +:10F420008F9EFA7017EE4FF67EF5E75DDF47FC3FE3 +:10F43000EFD190CFD73DFA4FBBBE87FAE8904B464D +:10F440007EF9E4F9871FBA1FF29FBC33A90897968B +:10F450004BE172ED939CBF65201E363C3F6F14E27A +:10F4600061C3C1B9A3D810F10323FD04F82B66E2F0 +:10F470002FC31ED40F497CF3EB3991DAE873E48093 +:10F48000A3075DD98F4FB862C8D7EBE05B1DF89D2D +:10F49000B7D5DEBC90F006F98D80E7DB1EE3F1BA4C +:10F4A000C1F88E8E950398F68CC52DABDB0E2CB96A +:10F4B000F2E2624CD5A08EF36567489FD9DBAD3B85 +:10F4C0000E749D3E3C1D3F675F3A11EFEBD8163E30 +:10F4D0006EEDA51F201FD9E9F831FECF8583E938ED +:10F4E00051B1D3F1D6DDF763E181D421F7790D3A3B +:10F4F000AE3D7855D250711A339E7BCE03CFAB25EB +:10F500000ED79F1DA1994A09F2C34F1FBA3F0DE9BB +:10F51000EC0A2E44BA3FFE79161841EC8FEA991591 +:10F52000B81ECF3CEFD2F6429B35CFBF4D7AEF935A +:10F5300083AF39753AA701AE4306EE3B0EFCF5A149 +:10F540007EBF4DF8CBEBBA127B304E61D0EBB6D814 +:10F55000A24ADD4FDF297E715B8CAF83DB62879728 +:10F560004A43D06F9D92CBF5682C9DF0B256EFA325 +:10F57000388399AE5229D2F3D47CE4BFE1E869CC58 +:10F580005F7B8E0E47C4E9DAC5D7EF70EBF4933D8D +:10F59000C0F14983E9FC89B07FD6C5A4B787A2BB77 +:10F5A00011CF678EE5E7A4979D2FBEA558E362466D +:10F5B0007B63FE23ADEF91E7F5F5F05685CE41FA7A +:10F5C00060FC35CCE372FBD739B02EE1D36BAA7E59 +:10F5D000EFB7914F5E56D95E68F2CDDC0F147DEA2D +:10F5E0006078FF11ED2893DF7F65A9D4920AEDAE14 +:10F5F0000C819ED1E3FC6A9487E738986E82E7B36A +:10F60000CA0D99B8EE8E045814E5FBD1D17CBFFA2F +:10F6100097A36F3D8ADF71DF9A41FFADF51A6EEE59 +:10F62000B0F6FA00A503E73842D914875AAF31BEC5 +:10F630003FBAFFD1471F85FC653800A8AE23A04222 +:10F64000CDF18D1302DED7EBDD64FF5D9BFFA4825D +:10F650007A5D2A7852417D7379E44905CF211C1DDA +:10F6600088C7E82D7864E2B2FCE4A20EE8FF9712A6 +:10F67000D7B7972DDCA3D498FABD5CF47379C19EFB +:10F680004C94C7C7C479103BBEFE20E46DC3E48729 +:10F690003371BC63E3EECD247F9985691E59C28F17 +:10F6A0003E3AE1E19DEB018FBDF912C5D37AEB1A29 +:10F6B0007D28977BF52516FE3B3CF90309FBC90A1B +:10F6C000EC51507EEF1571982E8C9FC1FC1E02BC30 +:10F6D000617E3FE00DD347EB754A1FABCFA7F22702 +:10F6E000EA8394EFAE2FA5FC53F521CA1FA8AFA45F +:10F6F000FC33F561CA1FAAAFA2F4B9FAD5F4DDDF75 +:10F70000B1BF3905E34C1748DD1867FA457D2D95E3 +:10F71000F7D4D751F9830AF71BB2DAC13F00B95BBE +:10F7200057C7F7CDF7AAE1AAB0097EA3DEDB0AF737 +:10F730006B7DFE489F82F1EECAA52548FF9609D74A +:10F740004C453AF6EA7F1741BBE3F33C37B9ACE4EA +:10F7500012C2BA7879C22C3A9F725F72E46DC5E426 +:10F76000C7E6B63B59CF0CA463AC2203F5E18D602C +:10F77000F7011E2FABDCA364403F8B2339BA4CF456 +:10F78000EC6E4E417F64AA285F58A896178C4CC730 +:10F790004705DC2F95D566E23A7B49E271B46B23CD +:10F7A0000E966F5AFF4B2AADF97B44BB940579E75F +:10F7B0003C8F9318847A163B87AF2317EE6B9AD64B +:10F7C0008F471F63A9E7D08E5C82FEFA70F2C9E111 +:10F7D000AFE4F6B3A6BC8FF20D70209D95E3F286E0 +:10F7E000225719786EC9F80B517EE5401E3C33C391 +:10F7F000EE067C5D173AAEA21DBF025C2715ECF049 +:10F800001A1674A23D0E7E31A537B15A4A5D993D54 +:10F810002A8FF35568B80F2C852E729C4D38573CB3 +:10F82000C6BA5F6CC097B240A1F8CC7AC91B443EFF +:10F83000681ACD0EA0DFD224D6ABD15EFD620AD30A +:10F84000010FD3D55C4B7C434D0B57A19CBBA35FF1 +:10F85000D2B1FD662592AD96F08929263F5F4D8B8A +:10F86000909F582F45C6ABD0FEAED97F3AE1403BC2 +:10F87000EAA047C738F127C59F39917FC82742FEC4 +:10F88000B9D31BDB9783F9FE6A1E0CE9A1388F4BB5 +:10F89000E009CFED605CD7E5F651DC83652A1F995E +:10F8A000F74F6FD278BCA429F1FDD1386E3902C26E +:10F8B000E1629919141DA5BF6AA55F457CAE647D00 +:10F8C000942E67DD94CE5523B3701ECBC03FC27C0F +:10F8D0006382FF12A4F37F177CF6736CD04F08F994 +:10F8E0003F30DB1D31FBCF0B54CEEFD78814D6F55C +:10F8F0005A5CCFC3D1DD90F7869CCF4A0A2F52D3F2 +:10F90000E3EBC548876B6F5F37063CC6B9BC94050F +:10F910001B5E1A07F8D8DBA9937E9A5BD3EECA82E6 +:10F92000A2DD5BF422C20573CB8897AC814023F73C +:10F9300053EA18C7233B29111E593481CBEB817A36 +:10F94000E1A9685FECDAF89907E5F4671B735FC318 +:10F95000ED8B91E669D76BF7664FDB86FBCAD9BDA5 +:10F960007C1F655BF6BF1F76413EAB9FEB812C5F32 +:10F97000ED24F4D7CA7EF7CFA331DE989514F9AE03 +:10F980006AE2EF5D3FA8CDC6F1BF524277A8244797 +:10F9900037B808442167EAB6E8DBF2F5E1F1B5B71C +:10F9A0003DF79CF8B5C33D2037869163F1F5CCEB6C +:10F9B000819FC9DC45243F7A741065FD0949CFF465 +:10F9C00041E9F5753D2AF205F07127C27D1D8BA92D +:10F9D000DCAFD73210AF37693AD16157C6FBA349C4 +:10F9E000F82BFD39E1AF73CE96B121EDAD36611F35 +:10F9F000003814E7CB12713A39E1A3D1A8DFBBD4A8 +:10FA0000A1F75D581DAC0FD33E1DD84C643FC158C3 +:10FA100074DEA11A0706D0AAE57E09D75B85B6A8D1 +:10FA2000221950B462638EB08B383FADD898BC07B2 +:10FA3000E30D9BD4C8CF5492BFB514D7AEF65D503A +:10FA400081F6F5F9CE0F46EF47BBDD58CFC67C1BDC +:10FA5000BC9167B1DF5C2DB93C594739CCE3C2F3A7 +:10FA60001C3E8AEB7C96C6C80F1BAEFF23E2BCE5AA +:10FA7000DF8BB8B0EA933A513EEC05FAE3FEED13A2 +:10FA8000C0B7F8FD7F815D81F95D605760FE9760CA +:10FA90005760FE1FC0AEC0FCA3605760FA10D815B7 +:10FAA000F87D3FD8150A3F8FF82B840FE432C1D57B +:10FAB000E464ABE97CB7381769C0F196A08391BEC6 +:10FAC000ADEA34EF2E9493A8DFDF75F273264AED8A +:10FAD000D8C5893C45FE486AEFEB41F3DB5FCC6259 +:10FAE00012C0EDFBB2164F02B3A2F78287D11F9E60 +:10FAF000E04B6EF2437AF062503860A7DC351314A5 +:10FB0000762E9EB7D37F722BD273368F9B775D0C88 +:10FB1000FF9F84E7689D44E796D7189D8BDC77317B +:10FB2000702D7CF72F6CBD1DFD86FBDF8272A09BC4 +:10FB3000BFF3ADEF637ABFB3B3DC0B747E7A0C0B0B +:10FB4000A21DEDDFFEFE0FB09EBFF7FE6F533A67BA +:10FB5000FF7778FAEC1D58FF47172F6C401AFAFB15 +:10FB60007AEEC4EFE91B2365C9901F156878250755 +:10FB7000DA77663616DE00F9A75F6E7DA719F2CF39 +:10FB80001C6DAEDE02F9FB8E6EDF86E5CED11B7AF0 +:10FB90007360BCFB6B653A9F34C59943F86ACB5CD4 +:10FBA0004FDF7F529B46DF938E7DA1CD85B4709C45 +:10FBB0001CC67DD167E6289531F3BE80D341EDBCEC +:10FBC0004E11AFCEE4F6396EA0225E95A042FE9EA5 +:10FBD0007A9CEFDFA84779DEA54543924EF17CAFD2 +:10FBE00013F9B2D67A5ED4D8B7F13BB93E29DCC35B +:10FBF000D7C1817E3986F1F2437D8D09680F1FEAF6 +:10FC0000CB75A01C2BCA9469DFF6507F4A6A22E0AC +:10FC10007D67DFFA5174D60104F035D04FA2D34B83 +:10FC20007C90E1A4B5676A9F42ED0B07DADFED49EE +:10FC3000C2F963FB9C78FB74D13E0BDB9798DBCB5E +:10FC40000E4C83D8BE80B7473B31F335EBF8E39CCD +:10FC5000FCBCE7C441E32F9671FC09627CFBBA9AB5 +:10FC600020C66D91A209D3503FAF55443C3C487A21 +:10FC7000A54420CCA83FCFC9F93E09F7E3287E1858 +:10FC8000A1719E399E9BC4CEB5EF8942D59053A4F5 +:10FC9000F7BD71794FF9145B7E8CAD7EAEADFC0281 +:10FCA0005B79912D9F44F0178A6F756817A0BD503E +:10FCB0009B447AB550EC671B7AB674A09EF6CAAD29 +:10FCC000A85F172AFCBC82D0AFA5A2FE915FCDF73A +:10FCD000F6939C0ED077D740BB68C2645CA7AFCACE +:10FCE0008CF007EE30D935A2DDCFA5E02B05281F1B +:10FCF0005EE6E70EE2F80BBBB9DFC5F15D2CFA6BEF +:10FD0000EB2CA2FA7F57A904693FD3A6EFB2F110FA +:10FD100007D0A1A5EFEEB9205358F254A910DBE5A6 +:10FD2000ED0C37E290AE183BE28576339FD37F54DB +:10FD30000169510FC857583745DBF9BE6661A742C4 +:10FD4000EBA83093E75516BE7C329076A623E49D4F +:10FD50008CF3FF2D3FE755D85B64B1F32774F2F3C2 +:10FD600021BB9CDC9E553365EA47DD3EDB52EF8BC1 +:10FD7000FEF1E7D4DF5DF561CBB9F87D03FA8FD3EF +:10FD80006D82C0DB803D21F8CE4E477BBD57EEE152 +:10FD9000E714871F97FBA507058B31DADA827CA76A +:10FDA0004CE73658F432C73C459CFB9C1D2F6FDB5B +:10FDB0006E2D7F66A0FD9573316EF54CA742E5F779 +:10FDC00038AF9CDB90076415F8553BF9B97B905B25 +:10FDD0005C4E6D97EDF2699713EDEB7EEB7EA3EC35 +:10FDE000E6F73E66ECEF6C46B4DE01FF3E5B84F462 +:10FDF0000C1F498276A587741997D4CB89B126A4A4 +:10FE0000FFD393A5E05EA853B625E44013A5FBCD30 +:10FE1000F9F7AFC5362877511EBC9A770CE36F0D02 +:10FE2000EFDEB112E5DC1DA7251DE32B47FA1633E3 +:10FE3000E467F55585E4839A167444484E15396E87 +:10FE400036D16F46BE2AE44F79C25468DF92D63568 +:10FE50009BEFB586D8B2441CC7C5E573BE1AB5CDB5 +:10FE6000EF599A5FD5D0F2B7D4C1A20EE4B7376488 +:10FE70006ECF5686121699F6E90F1C077D00E396A1 +:10FE8000BCD93CE3D750AF599B3D03F546D7362745 +:10FE9000BF9792CDCFCB1C13FA81FD910D772FE048 +:10FEA00018EA01FBBD806C06EB03F090AD24D0395D +:10FEB000EFEC1EBE5FC8BE3CCBCC72C12EBFE67C51 +:10FEC000E4B5F0BBDC6EF587B399C91F26396F9393 +:10FED0005F27A7C4EBE7A27D5CF14A120513F4E4A7 +:10FEE0006940CFB24C59A77DDF68C85706705C2EB9 +:10FEF000A06843A301CBEF6131DC4FDA8D72015072 +:10FF0000BF07EC234C0F44F9FD8D96136067C0B812 +:10FF10002FA6C9C11E3C3F7E9CDBF1971BE7660BF9 +:10FF2000548A2BBAE11F1C5F6DD6E6E2BA99D0AEB7 +:10FF30003791BE3B6A8A3BC2BF33C53E73992D1EC3 +:10FF40003953C42F67DABEDBE38FFFEAB4C6A5EFEF +:10FF5000FA9E83E08ABEE5A0F3C3CF5CC8A278EE28 +:10FF60007A871CD9BC96F41A3FE77A50E0C88847D4 +:10FF70003A5DDC7F3BFAAE8BA1FFDD55E1A638612F +:10FF8000224E0EEDB0133509083FE823F27F8ECCE8 +:10FF9000F626D0F91D113F30F441E36CEF66E4E33F +:10FFA000B69765B2559F3ABA3E2043FEEE0A379D9A +:10FFB000C3F73F181D8BF1A1437BC4BED649BE3E9B +:10FFC000371189E05FEC93CE6B697BF07C46864B02 +:10FFD00036CE6B65B8D2E3EBD73F7ED118EC675FC6 +:10FFE0008E745EFD64C7FBC936F763B2E3853FD20A +:10FFF000C3FD3EC11759E82FA35D64F307AA4FF272 +:020000021000EC +:10000000737E60D75F80FDAD64E110C541F0A41739 +:100010009D9B3F6FBB3E6AF6D3B3D27264B4E3E3F9 +:10002000F67DB804FBD733B546AC73BE767D0CEDD8 +:1000300079B2D7B91DAF4619D9F5AF087B1EF91AA9 +:10004000BF837D5EE6B2D8E7C12A3CF2B3DCF5C4DB +:100050005CE542B4BFFB0BD1A05EE07AA2C93D1AB9 +:10006000CF676A6330BFC2F5B3B96E28F763000289 +:1000700096E435908FCE81F1648EF7E8434CD8EB4F +:10008000FADD9500EFE45569418CAFE6C8FD9B268B +:10009000A13E5FC3F5A0BF8BDBC176F8F788788FF0 +:1000A000BFE9D3DBD11F5EE1E271D515828E467EBA +:1000B000B312B90EE1C7B015DED7B1C7775620D25B +:1000C00080AF57BA8CF3789D63F87D55481387A4A9 +:1000D0003FF71347A27FD700FDD7B84AACF44FCD06 +:1000E000397FFA7F56B99444D870FEABEB0B58DCDD +:1000F000A678DF1A16A9237A65F2FB33037493C13D +:10010000AF82F93AC47D06BF63512DE26D8BC09773 +:10011000913609BCB1F7ACF21CE47813F6EB566AE1 +:10012000C57EBBB0E39BA01F9F09BFC27F36E0D94D +:10013000ACD474B84CFE33E21DFDEAAD06BE592DB9 +:100140009D4F037F8DEE11FD87F19D3980EF1D627C +:10015000BDD1A1A42C110F3B5F7C1BE7228C731037 +:10016000D172BD59437999C5824883B9BE45967B02 +:1001700038867D60EFEF3A29F2A8CB1497B1EBFFF8 +:100180006AD6AFF238DC1915E75D9EAA174B74BE2C +:10019000F5E4DC57039047BE243BE7B773715FA1DA +:1001A0003C81E73F6CFBAA19CFB796E3DE1FD94528 +:1001B0007F253BA87C3C2FFF172C87FC0135F4736F +:1001C0005789458EC498293EA06AA7CA508E3478B4 +:1001D00023BFE0F2432F47D265D56932CEEFFCE56D +:1001E000885BF8F54CC88B482F8E6BC89391FCFA4E +:1001F000D75CDCBE34D2D7519F9498FCFA7B0CBFFD +:100200003E3C86FBF5E131663E1988CB357BB81D57 +:1002100023FC8A1CB18F6297D7865F91E3B1F253BA +:10022000DC2F087A517FD9F9CBF013F244BF47EEA7 +:1002300073F67C03E388A56EC24FF576CE7F815DB1 +:100240007FA43896C17FFFEAD1F9B96C21F71FEC82 +:100250004CE9C847BF61019D7862EB5CA18FCC740B +:100260009AEE0A7D62A35B6418BA7D7E3E74537D6C +:100270009EA8990E06DEFB443CE75541BF5F0B3D4F +:10028000B08685FE1DFB6D72EA14878C1EE37ED35B +:1002900070F41F2E8E69D0D990371F7AB85C89A769 +:1002A0005CDEF4897AB9A56CB69614EF77B49BD767 +:1002B000EBF3B021F75F026E6E8FF89BC224C798F4 +:1002C00038B79ADBCCF5B9516F8CE807302573B994 +:1002D000AE511A16708D2F6573B4E9F1FAF96ECE2E +:1002E00087612F2FB78F3BC91857C84F63DCF19D2B +:1002F0001AC5F18C7A9307C60DCAFC3D84108D9BFC +:10030000D3CEEF7D8DDFC8E3707A67388474EB2B32 +:10031000734DD88EF6637ABE880F86189E7B9F2D0C +:10032000E0B9DF190AE0785980278C5339006E4C08 +:10033000D53A768AE4BC2F4AF6A0C9FE9FED463E28 +:10034000FA0B1BF2DCAC8177BFC22A5C26F9F5867A +:100350005BB6EC9718F30C8792E7618877DA01AD0A +:1003600010C5D6C2A044EB6E722893E260A91E8E1F +:10037000977D5D8CFC90A9AEBE65B7005E622DCE08 +:100380006023C0737FA33344F13167FF53AFE03C78 +:100390003B9C140F7BF0A06FC105906614DFDE90CC +:1003A0000AE98E83AD4FBE82CBD9CDFDA747BAEE09 +:1003B000BEEC02A8BFF3D6148A5B19F9CCB53C8E0B +:1003C00075DFF6BB174C447BA24BA6F3EE8FCCE156 +:1003D0007E8B01FFB56E7EEEF606B7783F613BF788 +:1003E0000B07E25873441C2B2AF4E5AA417EE20D68 +:1003F00084C761E25837BBF939CAFB625C0E3575B8 +:10040000C931BCFFFE88EF6E92238FF816334CD5AE +:10041000108F2301FC1E8A63F98C3854A717E34818 +:1004200037B9793C681DCA977473FBD312A659A6D5 +:10043000F614C7F2197128DEFE36378F43DD31A876 +:10044000FDE0F1298E95681DFFBBA23DBA33980EE1 +:100450003FFE53C9379BF4DF0F05DC530E45C84EF2 +:10046000992CF03BA9AB2FC837697BDC88A7DD8FBF +:10047000EFE83F06F86CDDC9E3213F15F6DB6EC9F6 +:10048000BABE7F24F86FB7E0FB233BC14F46FF782D +:10049000E7D210DEB3671B19D179D2037F91CC70FC +:1004A00064AFE271B6490F6C383679083F79B75BB3 +:1004B000F8C9AB64BB9FBCDB7D0E3FF9B3CA552FB7 +:1004C000E071E1A9CD3CCE39754B2B9D6F990A0E99 +:1004D0001FAE5BFD8B19647F657F51489705B2BEE7 +:1004E000B888F2EA1717523E7B071F6FBFB0BFA64E +:1004F000B5F3774ED41D3C4E911DB5C679523D22C1 +:10050000BE5337DBB22F33ED5034E91298D7945EE7 +:1005100047A1F9FC9E3DDD658BEFECB6C577726DAA +:1005200071C554CFD0F11DA3DE448985B1FD4F3B89 +:10053000169F33CEB84BC4778CFE26FE80C795E954 +:100540002F0DF55688CE55EEDE5873F702CC27579F +:1005500014E3FA4DF5F07383F6388CD12FD0E7759C +:10056000A48F412FC32F4BF5308B7E00145760684A +:100570002E3E2FD9B26F6392D7044F671597D74697 +:100580007E542483F44692D04B9F551EE574AF6889 +:1005900028447D1E0E9D92CD76DF8874EFE6747F31 +:1005A0005CD05DED1E9ADE491E1E4FB4D37BA4388D +:1005B000DE4874D66DF1B924A177ED7436EA1508DA +:1005C0003A3FD178EE389E4167A3BF8261E9FC4291 +:1005D000CAE5263A2779C479DAE1E99CE4491F4C57 +:1005E00067F0DF523DE497F17676FFCDD0E3A0C708 +:1005F0009ACD7AEC318F4D8F093BC1D0635362564F +:100600003D3609F59814B74BF6EC61B4DEF35DDDC9 +:100610009F1D433DB6C9AEC7A245C750CEDCE5A479 +:10062000F85FE7CE9A32E49751A50DA3D7403AE59B +:10063000671B490E05BECDF761AEF7707DF6F0CEB3 +:10064000F5F4DDD887797827D75F63F7A590DEBF0B +:100650006FA74CFACBAEC78A3C5C8FCDF188FD9872 +:100660009DB2753F66643D36C7738EFD989087FBDB +:1006700063C3EB31A1077672393B9C1EFB8687EB87 +:10068000914A1CA064083D646A3F941EBB54B40F99 +:100690000F6A3F78FCA1F4D8951EAE8FAA847C180F +:1006A0007E7CAB1EBB46B49BF658E70B68B23B1989 +:1006B000E82FEE7F92FE8A09BB66F7DFEF88BD0266 +:1006C000E54F489D8B2F43BB63348F53D8F5D86AD1 +:1006D000217FEAC43A391215F1DE2ED063E8AF0863 +:1006E0003D3679DFD07A6CF23EC59B3F841EABF37A +:1006F000B8B81D33588FD5117D87D5635C9EE50B47 +:100700003D962FF4587EACEFFCF4984D9E4D31F49D +:10071000D83072ED43D46343C8B5298F713D36EDAF +:10072000BF588F7D388C7C33EA0DC8B7F3D463464D +:100730007FBBBBF9BE685CBE451EB2CAB7553371FC +:10074000DD7EE8718C24DF7EEA19428F7D28F8DC9B +:10075000F03700C5CD663DF6E13072CC8067383D9C +:10076000F6C1801EE3F64BFE801E7BF2EBE9319B67 +:10077000FD329CDDF2C1FF253DF6C1087A6CC05EFA +:10078000394F3D66F4B77B8795CED30E009DA5B853 +:10079000BD32ED20D099E639349D81BE1F784C7171 +:1007A00063F7A1DA10866C407F7DE8E1F14736D42B +:1007B000F9327B7CEBB3CAA521A4D370712EE33D43 +:1007C0003DFBB99D91CE052E9A7F27BF57A386FE8C +:1007D000CD638A2FEC502367057C36FD2AEED90CB9 +:1007E0007AB76F98FB91017E3FD2551AEE11F7232D +:1007F0003DDE9221EE474E0A068218074A36DECFCA +:1008000033D6157F07CE7FD197FD4D28F7B49933A6 +:10081000B09F0C2FF7DBECF7024DEB2AC36B5A5756 +:1008200003F742F1229D693EADA3AF1EEEBE609676 +:10083000D7129F3CF77D41879B9FAF8C96B3FC5AA4 +:100840005F3CCEC1BE6496F7C38C79B933F5BD88E1 +:10085000A7295EC9D85F98E24D37C1693BBFBC4943 +:100860008AF0CB94BE282F17E79929FE23F3780B43 +:100870009E5B6EC2F3CB93F05E7098EBB5CC30F913 +:100880004709C52C88E712A5826EF29B120A6A03FB +:10089000788EB56D9873AC6BBDDC5E6F18C7F7F5DD +:1008A0003ADE95685FA763C2D501F3B96463BFFD03 +:1008B00068FAD5EE7ED3BA6AC95C4CFBE82D698B29 +:1008C000CF792EDEDFE9603DA9E751AF9DD71BAEA2 +:1008D0005C2D65ED787E5F55F87C5D275D6497B98A +:1008E000586D0FF987FD92781787C7010DB8A5B429 +:1008F0005AE23F23FE679C0F983BBB8AE6D3E20E89 +:10090000BBF11C2FCCE79CFAC1F58544F07DA58492 +:100910006E403A1E9EFC10E975AF5E4BF7785D990C +:100920006116998AEF8B85199E174D08323A673CFC +:10093000121DE678B9BCC6756D3E2FBCA92C42FDD0 +:100940006C1ACD82511DEF55DACAC5B963A79087DD +:10095000467FD3BDDCFEF881E817590ADF7770B80F +:100960005F24FE05CED1685F10FB81C2283ED6070A +:10097000F53E57423FF4960C2E8FAF7F7E9F478007 +:10098000007FB75BDE9BCA17FB9C461C327B3B2378 +:100990007E9A14E57A233FDA78BB8CFA032B43F96D +:1009A00084AD8CDEE78172B2578DF693624ECB3DFB +:1009B000AF9C766B7E3CEE7F42BD09E2FD2BFA0ECA +:1009C000FD8C17EF0A8DB77D37EE5D0CF7EEA27D3B +:1009D000DF34E6B5EE9B8E74EF63609F94851EA2B4 +:1009E000F52DCE4336DDC9FD087B7D039F7536BAF4 +:1009F0001969B7589783E5AF91765AFD76F1FD8B6B +:100A000053979E53DFFE16F46DB349DF9E447D0B72 +:100A1000ED7FBBF460628DCF0C5F03F57FB2FEC447 +:100A200025EF4D888FE37FE11135672A4FF17D91E6 +:100A300065B53974A467D986D754F37D88EB6BDF2D +:100A4000B9E43D133EAF0B5CDDDC4C7254F937DC8E +:100A5000AFC6E837BE1F562E33CBBC8CF13A014EE1 +:100A60004C97D772FFAC23DD19F3011D3BBEE2EFBB +:100A70008A444FF173B85BEAABA89E41D7AFBCDCA8 +:100A8000CF4AA8953CFCFD056EBF1BF2C021E2F7E2 +:100A9000037813F2C02114CB91C9AD6EFE7E4AD00B +:100AA0009D8BF2E4B883CE23751CBE8FD6B71D9FF5 +:100AB00077D5F3FB596D788F828434B75BDCC6F948 +:100AC00005619FB885BC6912F72CEA58B4BD262D84 +:100AD000DEFFB68AD72BC743BE5D4FB1DCCF6C5764 +:100AE000387D5AEBADEF6BCC4F30ECA0CE10EE9FC3 +:100AF000830CEE463F24212FC8F0FD0F987F0EE2B5 +:100B0000D8017429273D100BE0FDC00E943F43F03F +:100B1000DB092127AEDFC0EF6B76007E39BEDF98A0 +:100B2000877406D935E43EC0E40423CEFDFF177E6A +:100B3000ABFE8BF1AB2470FC2AA1A80BE3A2F6F567 +:100B4000A185BA55F3BA2D97238509E9F41E27D953 +:100B5000C32D6A38B0BE00B7A7A297D2F9D4A0B50A +:100B6000BEA95DE950ED5A0C3B256D297FEF2E049F +:100B7000EBCB642F2606611D99E089CB81462E8739 +:100B8000843CB3AFDFE1E45AEB9C46B70EE3B5FB20 +:100B9000783CC37961B13BCF849725093CEED7E41B +:100BA000E376775B69E390E5ED9A6C39976AA47F09 +:100BB000F62A5CDEE1613B9283DD217CAF11747724 +:100BC00008E9ED2E6BD4C643BE33C8E32A23C173B4 +:100BD000E308F0DC38023CD9091C9EBC84F383E7AF +:100BE0007CCFCBFFCA1BBE3DA1246E6F0EA79751D1 +:100BF000C7627F07BDE13BB0FEF5DFB92A1DF9638F +:100C00006C32DF9F6099694477287FC46F2A8F9682 +:100C1000C7F7F9707F7BC315AB4A506EBE25CE0374 +:100C2000FB53F9FD6C03AEF712781CEABD046E5F4E +:100C300074C0BA894D8AEF03FA9BA41E5C2F67C665 +:100C4000C9B1BD39A817F3E97B5BE4B14A9C7F5B6E +:100C5000661E5ABAEC6F6AD4857EAC4B9C3FDE5A56 +:100C6000EE5D6D8E776DD038BE5392CB5E477E0EB3 +:100C7000FAFA699F9385141DD73FFD3FE071BA06CC +:100C8000161F9EBFC7FD568AD70485BC17F78C5820 +:100C9000847D9D7B464F28CC81F793A33E2EEF1297 +:100CA0007748E4071BFB9ABFD0163F88F0A887223D +:100CB000748FE5F04C2FD9317F6DE1F7264F5D7FC2 +:100CC00011C5075F976B76E3BD8D33EFB818DEB3C0 +:100CD0003D75C5E59568979CBAFEBACBB0FC94C447 +:100CE0002A25FEE8901FEF6FFAC7EB8F1F40BCB5B7 +:100CF00078289EA806FE20ECB4905F2E85FAFFEEC1 +:100D0000783101F0F93BDF67F7205B5DCF7AE87C53 +:100D100084714FE2AEA4C821844BB9EEF27C940FEB +:100D20005B9D5A16C699B6B6BA8AD0BE4AFE141C46 +:100D30000E94635725F0FDF433204921BFE2074BA1 +:100D4000F699F72D57A4033DD07FAD6B09E17BC920 +:100D50006E3D484FAEF8C7733EC84A8ABC88E394DC +:100D6000BB0B8F6A6928C7F87D06E37EC375AB7934 +:100D7000FE2DB1DF6FF753ED7E699F211703FC1E37 +:100D8000B8E2E37620D314DB3B6899E48F19743220 +:100D9000F303BE6366E607BC6A34C00F21E087A98F +:100DA000167E90CE4E397F7E7800C7043EBFFA2271 +:100DB000BEEF1A2D0FBE46EBE57595D68B711FC998 +:100DC000CEF76D918D6EB960F0FA30D64347F17A67 +:100DD0004DF721FFAF5F49F7464E493ABE97A0CD88 +:100DE0005A9E8EDFAFAA76121D8C7561AC87E5FE28 +:100DF0008175F1941FD288AF7F9EA40F5E17E85FC4 +:100E00009AF97F25AE1379F03A59C682D7E039CCEA +:100E1000650A8B26A5C4F97D59297F9F67597F03F1 +:100E2000BD87BE6CA3C44E5BF403E4DD16BC69034E +:100E3000EFC03ACE1FBF1D0BA4563C6FD3A19EA19D +:100E400077CBA2C97CDD3579A4FDF8EE7A6BE2FBA5 +:100E50002D687F7464E8F4AEA6FD9C41EBC404E207 +:100E6000EB8EABC7D279877BEA751601FCFE0E15B7 +:100E700014F6B73491F8FDEF00EF11BC5F0576046E +:100E800096C33ACEF4A5239F06E9CDE9AB1D7DB507 +:100E900047707DFC3681CE91FFF5D9C8747C0F7AFE +:100EA000EBCC35749FEAAF7746B2B502F33C626390 +:100EB000F8BDEBFE3132BD1DA48B7BD84C7C8F8CF2 +:100EC000E5DF63943E00F43F0DA4F3FA730C3F4A50 +:100ED000B4EBA7761DFE3E0FC19BE1D4F87BA9A120 +:100EE0009212C82F9992C6F05CDC034EFE4E871D0D +:100EF0009FD7F9B81C5EE2E8D4F1DC5DA92F733E00 +:100F00009ECBF36EDBD35912C49041E6FC051EACB8 +:100F1000C7E3FB2D5FCD28416770777D2FD9D903BB +:100F2000FA6B63378B24A21D13263BA6E52B87ECB7 +:100F3000E6765F37EA2FFCDE60BAFF3D4F8CDB229E +:100F4000EC9D96867020C5045F8BF04B5B0E7BC8D2 +:100F50005E4F58787D9727C70CB7C2DB8BF74BB233 +:100F60000BCE483762FD866E58DB50BFE7EFC91ED7 +:100F7000049D2DAF32C72B37F65AECA6650062529E +:100F8000118ED749F783BD13DC1ACABB65F915FF6B +:100F9000AC0CC1B7F877DAC47F06FC469C6383715A +:100FA000FF3ABDB50CE9E1AD6612CAF5EFFA38DDDE +:100FB00072918161BCBFE4579C334E80F7B0C1D2BF +:100FC000A37BD8D149FC1E36E6F11E36A6780F1B4E +:100FD00053BC878DE5780F1BF3780F1BF3780F1B3D +:100FE000F3780F1BF3780F1BF3780F1BD367EB23FA +:100FF00094E27D6C2CC7FBD798C7FBD7985FE2E2E1 +:10100000EF90B1FC88B704F172419E847CE4ED70EE +:1010100086F0BD863E41BFB99B966E3D8EF66C480C +:10102000A11853C24E25F94D9E273D9D10E0FBFEB1 +:10103000AD81A718FEFE803A3FB11DCF0BDFF5AEA4 +:101040008FD284A54F3394577B55DD915A08F06CAD +:10105000A99AEF9E8CEB9935A500FF3DE7FB561B47 +:10106000DAE6338A3F5DF314E45FF0AD68C5A31D93 +:1010700077A557BEAE53BE9AF2E3E79425F2F71D6B +:10108000AB5B8FC2C8DFC44B81C63D01803B14916E +:1010900006EE05B8F3C0AC0F1D0051CCD84BBE9B7B +:1010A0005AB7EBB81FD71D2D4FC6FDAF1B5A974E31 +:1010B000A6F64A8646FDCF9F2AC5CBD3DBAF6B5D34 +:1010C000EA31F75FDD0A5367AF9DE4F70C7641FD27 +:1010D00028F69FAB5D518CF2FC5D99F4F15B4EBD3F +:1010E00091FCCE0E904F00EF956107C997F1156CFA +:1010F0000F33C5DFB57C1E8F5F94C8F55AB2788771 +:101100004A06498C7188A4854F13132585ACEFF9E5 +:10111000790B14DB7BC0D6F792F16C3ED2EB782EC4 +:10112000A377CBCF4C76C7D0AE5885FC3C01E9C93C +:10113000D7F795E10775B43BC7E7BB8B5019F4F9B6 +:1011400074A35D0FC267B4B3D7C37E6553B9D18EA4 +:101150007DF96705E550CB5646EFA17973633AFAFE +:1011600013E67EE5E2E1FB35D5638E738FCFA47382 +:10117000F463AC2BAF339488FC7C662AA7CBD225D2 +:101180005B8D752AE33EA0D76BB5577DFEF2BD8916 +:101190004087BD821E5E6F776F2EB6BF58A1F347A2 +:1011A0006C7FF531CC7FF77E99E46C86027486FE05 +:1011B00032DAB5429423677CBC5D6ADAAAC5F83D91 +:1011C0007587C2F07DFD341655F11D813426D1BBE3 +:1011D000FE1D6AE73C7A6740E5F1C7E2D2DB2F2FBC +:1011E00086EFB3E67D4EEB6FD6F3B28476D1193F2E +:1011F0005F7785D3136BD1EEBD7CFAB819B8AE36E4 +:10120000DBDEA930D28589DC0FED12711A69D7892E +:101210005AB2374B7C12EABBBF7E2AF4928073929B +:1012200093CF1F3C0DB22B1B020ABDEF218FE6A905 +:1012300053ADAD413E703EE0A677B19C5FCD72A349 +:101240005E69FAC25529DE1F257BD3E98968F8CE8D +:1012500055EE3699E2014D9A979EE64E4A2CEAD514 +:10126000514FCE53E87734922E5688EF9313AF8EBA +:10127000E13EEE8F0E7BA8BE9AE88EA1BCEFAAF8E5 +:101280004BB802CABBE6803C81FA5DED4BC3B48E1D +:1012900034599B407A2EF82B5C675D1BB520F257C2 +:1012A00012EEDF001C6F2DBB2850CDF707E87D380C +:1012B000FAC916D9146F67A17CBCAF3E5B2BAFA4F3 +:1012C000771393CBDD288792E755B8793BEBBB9B2F +:1012D000CD157C3F1DCB6FC07936B3A3F8AEB9B145 +:1012E000749393EF96F07EA47A23FFD69C325BAF83 +:1012F000F6E1B8D677E8727CEE1EB4DF476B7C5F10 +:101300004CCFE7F66A8E885BC277BAD735BAD9BABE +:101310009E91D5D0BECD8E5ADFF564185980F98DD7 +:101320001570A862FE17FDD1DA7EACB80732D6F68A +:10133000AEDD824423FE62C5937DFEA3D3BA34B4EE +:10134000E747471502C63EAFD1693C3E9BA379F9FA +:10135000FCD2F8BCECF398AD9D2E43BD679FC7450A +:10136000ACAF01F9705C9DF5BB1DDED9155D61B4B4 +:101370009F67E72B84938B587713C6DD0DBA7B7379 +:10138000ADEBF78CCF21DE0529DF84EB787CBB0C3D +:101390000A20DEFF844E2F8B9AC69BB423C5929FF2 +:1013A0001C1B63A93F657FAEA57C6AF70596F2E931 +:1013B000878A2CF9C29ED996FA337ACB2DF992BE40 +:1013C000CB2CF5679D586CC95FD8BFCC52FFA23FAC +:1013D000D658CA2F3EB3C652FE8D2FD65BF265ECAF +:1013E000FB96FA865FC502C1BE501ADECB4A2B447B +:1013F000B965E0EBCE44EB7EB1DD8FB2EF13FA13AB +:1014000038BE47F2D3DA12793C3A63692E8B98BE24 +:10141000A72DBCC0920F2C2F62118B1EB3FA6D2D1D +:101420005F2DA9E2BF07C5EF5537A75F4DEF6AAC47 +:101430009FECA473F1E4EA0188B72726D33CD6BF1A +:101440003C81DE23BB2F39B40DE98FEFBA445371D1 +:10145000DFC549FACCEB7392DFEDF5FD98DB7F79C0 +:101460006EDA83F3E6C7681FA6B9BEFD923CB0BB37 +:101470007F541FA554C90F4751AF28697C5F46CBE5 +:101480003F43796D0ECFDF9EA8D33CB53950DF3492 +:101490000F55837E4CF37C5DE6F7BDCE80DFBFD772 +:1014A000E4F7DBFDFC88A63D7480C5FD7DF0A3E973 +:1014B000DCF89996046A978B8E5AD1F07EFD1CD683 +:1014C000E7C0F4127686D22E569B8BF6FB9BCEA8F5 +:1014D000630CB4FF56D76BAB118E0B8BBDF42E0E85 +:1014E000C601124D718053C95A16EAEBFB9DE1AD5E +:1014F000C771DC3B55867A73C5A22BDC280F564C8E +:10150000568224861938F0180FB82F25C8F5BCD09C +:10151000230AF3E441BDAB36E715E1F70CA596F4D9 +:101520006DC6724D42FD28F90DFD584C7A21B55318 +:1015300009EA3AA2462FC77A69ED2CD803F516E7D7 +:1015400082BE44FD7E0FBF079F9B3FF128E269ECFE +:10155000AD3D920BEDA6904EE741724F5EDA8BF7F0 +:10156000F43B548007F5E9038AE01327F979EBEFA0 +:1015700053C8CF5BFFB2EAC9C3FC26A51005891F7B +:10158000F765812FB432AE8F721F9818437BE02E1F +:1015900049DB457E558B2B887ED54F041F3C807CD4 +:1015A0000176D3A98CD646BCB739D9B787EE554D4D +:1015B000493BDC88E9D4CC53328667A6E7494D29FC +:1015C000902F2CC871E0F9E419C5654D9896CCA907 +:1015D00076A4413AAB42C26B2FEC5F12F979976B5C +:1015E000572D3A81764E99E6A377627267FFB10A6A +:1015F000E5F1C8EFF2ECA073E16C95F55D9EB25495 +:101600001FFD2E8D867C9E4329D99DDAD28418F247 +:1016100039D8D912EEC747CBB89F9619EA91501F17 +:10162000423B09F725B51E8F847ED4D8509F043CD9 +:10163000CFC66E6074EE2C2BD42FE17E4FE6AD56F4 +:101640003ECF4A8A48181FCCDAD06EF9EEC77D43E8 +:10165000C06FB3CCE58F37259288FCE39D969BD273 +:10166000A4F338E1A28238DFBC23FC8B17047F1877 +:10167000F2DBB063FB06FCD1076332F0F54367226F +:101680001D782E2E5A27DE853DD3E3A0F8D4771699 +:10169000113F668978D8F2BF74B7E03DDCAB5C6778 +:1016A0008E24E182B985DB5B7B3D56FFB8CACFF55E +:1016B000E2123F975B6A0768FCE9A6DF73C13FE867 +:1016C000FFC98DDC5E577FE76B4F4E02BF4EC03BBC +:1016D000ED39AD1CF7B5737AB417287D55A44721B1 +:1016E00015ED91F0082A1B220EBEA739ED18D6DBA6 +:1016F000C3B4639A295573B5CBF05C177B51267A36 +:10170000B14C46FBD87B9A53E89C0003BFC40BF94D +:10171000AC3BD3280FF53B286EF7432F43BF43AFB5 +:1017200053E8FDF041F16736A0CF657A4738CAF338 +:101730006ED6DE807C34FD9049DF33D46BD6FC8CD2 +:101740005E6BBEA4CF9A9F75C29AFF95C02F782377 +:10175000C7F30C3CC07FB2E1DF3A58383ADA43B8FD +:10176000CF5BC7ED88C1768FD5BF61C20E5A2948BD +:101770007361BFD5EE5829EC9F95367BE2944FBB41 +:10178000BA1AD2D0F6089DD389D4398212C0F0FBA0 +:1017900007FE3A81DB4167D231CE95854C03F0AE2E +:1017A000B87320BE199D648A6F6E0EBE5E7B04F214 +:1017B0006F9F70510C6D9EE3D5DE7AD44B57A93ADA +:1017C000ADBB59B7EE4EC0F8F53B2EFAADA5B775D7 +:1017D0007D14D9B1BD2AD1A54D9CFF33DE5136E22F +:1017E00075B70BFE5B6BE00B37C428EED39380F626 +:1017F000F9F4438C15D8EC415E1EF26179618FBD1E +:101800003CE42BCB18781A0A448144F82E11F627B1 +:10181000E637823E293E6E7DBF745495351FEC55E8 +:10182000C94E9DC6C249289FD1F5C67EA6093C0770 +:101830006DF78AA789FBC6D36CDF3318DF9FCD28ED +:10184000F6D13BF2F67DF42D7AAD84E55B968347C5 +:10185000025537FBC57B8805AC00E93E0F7F7F044E +:10186000F1FCA683E27B579D9AF47635AEEBD7F870 +:10187000BE5D5B8EBE0DF592F68A83CE3F6809ACE5 +:10188000B0D017DF6FFFF1D920FE56E5409CF489F8 +:101890007AC650BE77D7BB19CAF7A7EA35CA1FA8C0 +:1018A0000F50FE997A9DD243F5F9943E5B1FA4F246 +:1018B000E7EA4B29FF8BFA10E57BEA2B299F925C24 +:1018C000F6889FF6A58314B7F5161E70E33EC6553D +:1018D000D73B34E433FB3A74DDBE24FD1A106D7738 +:1018E0006E7E6E5E3AE0E3ED0D0E8A2B3C72D7738E +:1018F000F3F07D0273BCD61CB78EC76B61FD4EA1A1 +:10190000786DC40D2AE57F27E8E2FE9888DBAEE615 +:10191000F1EC91FBE1716E8CFBAA43F523E2E26BE3 +:10192000DB799C776D297F7F7F6D31F75F36B16DF5 +:1019300096F7995DD02FE6D71E68E0BF8BA9F6D544 +:10194000921F59E2137EE41DE45736ED74B3C69C32 +:10195000B83F69F89176BBDEE49F5BF40246709075 +:10196000BFBC6E89EB3F36E0C710BFCDF5F37A17E9 +:1019700068AFBD805B5BCF89785241E0D3721E6F48 +:10198000E2F9697AF29114537930BF706EAA299FF7 +:10199000EF3E55D5608A3FE52516BD906ACA1FC740 +:1019A0000179BC298472FCFF753CEA231147F9696F +:1019B000FACF53309E107D5C61787EF897E93F1F27 +:1019C00083FE2CEA2F8CC721ADB9BE60FC3E643E7D +:1019D000FF1DBB01FDA24BB4EF63D22FC768FF41CF +:1019E000E897ACE4A88CEF15C5BA58B06108FE368C +:1019F000E919079DABD199EE9C29CEF3C8F17298F5 +:101A0000420F7FCF9EEB492A1F8F7A40A6F7DD4D0C +:101A1000FD105DF363263A33F4D3ACFA666AB7354A +:101A2000FFDFA5CF0CFEDAAAF4D179B0AD5F0ECD01 +:101A3000B7354992E0D701B8E5B3B3E2F8A0F39C1B +:101A4000B998F272583D87719E9166D532EECA3AC6 +:101A50006B7EF9066B7ED9ADD6BC693CA137BF66FB +:101A60003E1A7AD3ACAFDFC30B5F93E2FA7A15CBA1 +:101A7000998F76CA8D2C48EFC7DED09E60F117DFB4 +:101A8000449D4A7150FEBB6E35E2BC15AB384EFB2F +:101A9000BB391B75F213AA0CFC44B91E770306066A +:101AA0007E77C5347ECE02797D339F97C51EB0BF49 +:101AB000EF5F63FB9D38DD169770EBFC77F4B23671 +:101AC000DAE3A851A22B8E87BF6B30189EAF37AEDA +:101AD000D1DF69D0238837E31DFA01FE56FA25DCF1 +:101AE000BFA8C1F74E117F1B59680FD98BDFA073B8 +:101AF00072D718EF1F4519E9715DAC91B624CE7FFE +:101B0000767CD72C7FA312F15D532C53DC91D5E565 +:101B1000D29A263ECCA577DD9D589EB54562A91286 +:101B20001B783FE51AD1474A7290DE7D3FDDCCCF6E +:101B30000F9E5EBE2403FD0383DE808FD31C1FFC3B +:101B40003D929C3AEBFB2337326E1730F1BBDE3708 +:101B5000DAF4BF41FF1A66B22FE0FB78B0A5713E00 +:101B60006B4BF9EF32AFC57D44D42F8CBFEFBDC9AD +:101B7000776EFDE29F1B6C9F88FE62B2ACA3BFD85C +:101B8000BC4AA9DC638DEB39CF62D00CFF3F23BE8A +:101B9000DE7E2FB30A8C1FBC81E719A1FD1BDF4B32 +:101BA000DD834F50BC5535D78DFCF17A7270AA5C3D +:101BB000C819C33D07F29EE0E30CF2AEB6D72FADD5 +:101BC000BC389EF776FC2BE5DF48D11FC0FCF349FB +:101BD0002C5A9189FDF27C9BFBF4A547C789714083 +:101BE0006EFFFE477F69C3F72D8CF58E4F07707E21 +:101BF000B1AEBF14F18E614219DB863F0903FEE9E5 +:101C0000B61229DE2E05DB49E768B7886D53866872 +:101C1000E733DA818E6935C5018D389F2CE0318F2D +:101C2000AFA01DA04512D1FFB86B9EA2A11FF49FCB +:101C3000852363A47957B36DF84EACBD1D80DD607C +:101C4000C02F0F0D7F0CCBCDE3ABE780FFBF1A1F7A +:101C500023F5E714E55F1B3EA8DE98711EF305F837 +:101C60005494DF7A24513E577FE033340E3DDF4EEB +:101C70005B7FC9045F20B2F59CF089FEFE0F6142D4 +:101C8000A50C0080000000001F8B08000000000071 +:101C9000000BE57D0D7C54D595F87DF3DE7C249911 +:101CA000495E329964F2052F24D150034EBE30288C +:101CB000E20B041A1470A8A0B182194014948FF892 +:101CC00055A7953603092141A89162D7952D4E2835 +:101CD0005ABAD5365AB6B22EB241D1428D36568B4B +:101CE000F855A36DADAE6CC9822EB4D59FFF73CEEF +:101CF000BD2F33EF652680EDFE77F7B7E1C7EFE63E +:101D0000BE77DFBDE79C7BCEB9E79E73EE4D1E83A9 +:101D10001F1B63794C890C9633E660ECBECF25C659 +:101D2000B2548DB15AC6D2E6B14C870C6DFCA12DD0 +:101D3000520D63DF9EA1A89B8AA1EE62AC2F87B1F2 +:101D400022FC7E1C6319931953E03D9BA0441F861F +:101D5000EF8B14E67654313606FB85B66EC622D874 +:101D60002FBB83D7535924FA398CAB2E1E7CC05617 +:101D7000C2D891723533008DEE3D30F9C59A6C783A +:101D8000DF250552A079AABD5B0A54305677437708 +:101D9000BD039E3F7807EB651A96D1141D9E3F3810 +:101DA000184DD1E0BBBAE53BBB18BCAF6BF7300DAB +:101DB000C699CCBADB54789E79A9128C429971A944 +:101DC000A233802F33F3E2EFCBC5082F600AEDDB9F +:101DD000D529DF67D0BEDDA1CEC37AE46B8C3D0C84 +:101DE000EF8B6E50E73540FBA2B03D60D3101F5122 +:101DF0005F2B072208D79D43925681C80F49F326CF +:101E0000405D9282BD506FD715EA37F59B6CA78471 +:101E100074624C5326217D399D53A5EE75D3904EA7 +:101E2000CB601C28F2F43D7749E98CFF4C12F44456 +:101E30007A2B4C7340FDEF057DC7B28103CE6CA4B5 +:101E40001FFF8EB101699E078A7676B03407E9CC10 +:101E50007FF2EEE0F3883F9FC3FF22D516714E84D8 +:101E6000EE9CEA7D0817BB4B61383F4CCC0BB59319 +:101E700047D68BBE3990C92ACEDCEE4C75804B71AB +:101E8000659D45BBC1C5B3593AD25BF95D3CFC4B7E +:101E900018D48D7640CFC98371755EB8916E638911 +:101EA000D250BE35EB4306F8D655B44F47F8C75A63 +:101EB000BE67AC9BF8DAE00FA62B9A0ADF4BE27BF9 +:101EC000D611640CF8D1C9029D8E127CB8507DFFEA +:101ED000027A6FFB1CCA1DD810F9A488119F5BBF42 +:101EE00097C29B82383E9B2AFA49652E17C881D338 +:101EF0000925D0417230571ECA05F0820DE723DD57 +:101F000016457E5B2731059FC7C61B64389ED39557 +:101F1000D6FE3B2FC8871A7021BC1BEDACA917F960 +:101F200019083B80F3A3045514AE36785F89F8B0E6 +:101F3000808D013FDCAE729C377A02D7D423BC2F50 +:101F4000DA896FDAFCD00EBE4B4FD316B14CFCEEE3 +:101F5000AA46D7A58CFD6A1ABCBC18E4AF7B4E67B5 +:101F6000640A8C7BBA8085AA8166F87319D49516A9 +:101F700086E33B4F8F313D7FA695B1D0F9B1FA345E +:101F8000F7B80684E711A13FA6B3403B7E37DD25B5 +:101F9000B350DCBC3A4FE7B1903751FF85A6E7CF8D +:101FA000B4BA58C87936FDA7B1902BBEFF9224FD74 +:101FB0009F67E95F4DD87FAC5FAFA9DF0D0A233D76 +:101FC00012694AA3F937BE33CAFDEAB41FA93E9885 +:101FD0002F075B8EFA80F903033AD07F636176E5C1 +:101FE000268DF783FC33333BB367137CFFB46A233E +:101FF0003C1A669728A81F58A13234CCAF20F7337B +:1020000005FFDA8023907F1BB2ED16FE0F28410FEB +:10201000C26D7D1E2747205F21E407DF48786D9E53 +:102020009A0184E7B6454ECD593CF2BD51BED5CAA2 +:10203000A6969631F65A4ACB221680BABACCB5C1CA +:102040000F75D441F98CFD518D344600DFB724CE95 +:102050009F1BB29F295BEC4EDEDF4285297555A39D +:10206000BC77F495A1DE5F6863A15EE2EBD084AF3C +:1020700078E2DE038275A457A2443FE3F9A2166911 +:102080006A691C9FBD658379E0F0D42EAE181D9E51 +:102090002959A3BC77F6D5123C326B4906CF94AAD6 +:1020A00033C3F336D2A702E1F955D968F02C523880 +:1020B0007E49DF3B06883E8B903E1523E159C438AC +:1020C0007DCF088F8DF329C0533BDA7C213C5346EA +:1020D00099AF45CE01A2CF22A44F1278A69CCD7C09 +:1020E000B50273813E713A5A9A507FA656EE7195A9 +:1020F00080BC2D5824AB921627CFB75EE5BB06787F +:10210000FA8EB4A766F8806F5FBB4326FDC5D8532F +:1021100033EA4BC18891B83E9B7CDFB73B2380D725 +:10212000C9D9B769B88EB24FE17BD0D7D76153E830 +:10213000FF3A85CBE3570B1DD17571F2BC03F49ABE +:102140000E7A210AFA07CB9DA02774806B57AB9FAC +:10215000EA8FB46A54EE6E2DA7F21F016E7CFF6801 +:102160006B1DD58D7E2A964B3ADA1F13564A7A4F4D +:1021700082F95E9D29113DEECB53AFBD01F5747D13 +:102180006AE061D413CB2F61BA4BB443B859EF3333 +:10219000A9F07ECBD5AC7213D4BEB49BC39DDD90A9 +:1021A000139525A4D3C18156A83B17D83509EA2039 +:1021B000CB41CEA7CC5D0FF82EB609DD037A44855E +:1021C00076839119BB50FFACC8B4D3F88B0B9F6FCB +:1021D0009260DD5A8CEBF0445A67F83AB742A2F5A8 +:1021E00029D46E7F2F5EBF7C15D75958AF7D41C56E +:1021F000FC9C6DFE0F6F3AD199EC996B5C86CAAB73 +:102200003C5C0BF398DD62D7A25C15D1FAE76B70EA +:1022100044FB008E05EFFE5CB5A15D54A990FD75F1 +:102220005F8A9A87EB19C8150B67C5D6BD850CC6A2 +:1022300033F8A518C733D7195B4FF83079614608D2 +:10224000F53DF2C1E491740FBFB5AEFD601CDF2D0A +:10225000CDF464E3BA0B364305EACB4F58C5BD0D48 +:10226000F8B2309B8C37EBF7A75A23ED0781464530 +:10227000B086E2784E07D753D676063C7708FDBB8A +:10228000A37568EAEFCA62F08D5106255C67C686C1 +:10229000E1791C3C2C5B672CCEAE4B86C70EE9580F +:1022A0001E1B456EC7C07CC813C90E7F1FE709BB44 +:1022B000413BDC8A7F1BE29F168FFF945F96B244FE +:1022C000F2A2DDD780F272480EACD362F431E8F1AD +:1022D000FF5B6E2A330533E1CF24412F9017797DC0 +:1022E00040C3759AE5D8889FC6644FFB5099C8DFF4 +:1022F000BF67E297B83AE02D3FF3A1A4813DFF50BC +:10230000EB219A27633C981F694305F63B28E13E81 +:10231000654C1FB403FDA68599AD1DEA37603F6586 +:1023200023F59BB6F690695E4FA5A44F6419D08F34 +:102330009B95E37EC9CF5203B81F09BBF8F3BB528C +:10234000D37762792A654C14E5EB2E3914C2FDC0AF +:10235000295BAFAB18DA3D991FFAE74CDC97651E95 +:102360000C22F81B722E2E473E5A18BE3BD8007620 +:1023700099EA65CDC104FC60ACA30705DDDEB2F7C8 +:102380001565023E1FE54F3B98599BA07DF85BD435 +:10239000DF54A1CFADEFDFC47E80EEDBC5FA7ACD8E +:1023A000AA273E7C04F049D52AAA90C752CB0766DB +:1023B00057036B74FEB2A40ACDFD57C4B880700DEC +:1023C000DA2B77E6867E9519678FB834550991BE6A +:1023D000EA9D8CEFA7FEA5E2F15F427F9D57B855BD +:1023E00019F8EC648D5C63B38D8403FA7913FB7187 +:1023F0009DDE447C6EF4B33F65703BDA292C327F5E +:10240000D6D13AA8670E164850FFED7DD5B3B281FC +:102410005FF7FB060BF07DA364EB3A0872B51FF57E +:102420001DAC171764D9BAD08E997AF9B1EFDF8B4A +:10243000F6F9798E004E6B97B06B8C71E766C984A4 +:10244000CFDC2C331DFA578E4E8793826E71743811 +:1024500099880ECD05FAC7382F00E495D5F0496765 +:102460002B0BDE0030EAB9BD29D530F1795AEF0FD8 +:10247000EF65B80D8FD6DB8AA99F4F391D3AFF4310 +:102480004E8FF5F36ABEFE193EEF5FF9ABD9D5006A +:10249000574ABF1C90809EAE5216494BA7EFE4AC42 +:1024A000B8EFF45C55B115C7E661919FCBD70A2F01 +:1024B0002FB384FDD3E6E8F6CF83522DFDEEED2A4F +:1024C0007CD7511C6D4AC477B297DBB720A63A7E01 +:1024D000D7AEEE742D896B5792C5F9E2963C3D0B51 +:1024E000E170487CDDDA54C7E996DEEFADA27D5994 +:1024F00029ABF90AC8E5A55E4E3F803B3F0BBE7392 +:102500004CEE26E7424A29C77753C55686FE80140B +:10251000FF365E960EB210CC670AEB75E17C8FDF5A +:102520009AD9D55E877804CAB13EEB3BBBBA149802 +:10253000FF1EB44DC08E9D0E75DCFFEC70401BB4C9 +:10254000F3F31DB4FE59F11A2FE0989EAB8F47B8F4 +:1025500047D0C939F8FD7BE1FBAEF18E4004E09F26 +:102560006AEB6E5A82FC74B99BD67778DE148D9331 +:10257000ABEB041DAECBB2D3F75D7F72D17B2B9D4D +:10258000CF96CFF4AC11F2A667D526E4B37A847F58 +:10259000049F6524E5B359D84F023EBB3C111DACE6 +:1025A00075C5EF88A09C2AA73B0678E97A17FB91AE +:1025B0005924C2A07FA57133F52B9F4EA576F2E971 +:1025C000CD035857D4169AC75C29F4551C871D951E +:1025D00014D4F72942F5CB6E9DDE7F9839FA384A3C +:1025E0006907EF9FB530F4CF58C781FE6F4CD4BF59 +:1025F000CBA5F7211F5667F1F57EEAE5EE10AE4F49 +:102600005385FD6DD0D5E155E8FD6B593682239990 +:102610005C5C7C06B928F60ECBC59DC4E767908B41 +:10262000AFC4E4E29B244749E5621795A9E55C2E17 +:1026300052855C147B59A4D18FF07239D8BCF57BDC +:102640005D91C2989C347FE727263969823ABE4F54 +:1026500086DF255E8E3FAA14A4CF8B357204EDBDB4 +:10266000936CC24EB457D3EB5465093CFF4E9601B0 +:10267000B7BE95E8CE0619F26B0F1B3AE044F9ABF2 +:1026800093485E3C915EDD85F8B26E867EAFED824A +:10269000BF77A05D8B76EA798CE49429DD0CE96143 +:1026A00095DF94D23E5A270DF82E14F4BAD91BDCCC +:1026B00089F4ED6183E3D1BE31E6C38ACF0FC478DC +:1026C00025F9FA0FB0BD95AFCFB45EFC42AC17BF91 +:1026D00010F866FDC5D59248BEA7AE7EEAC3474650 +:1026E000E9E7E7028EFDA21F43AFA71A7ABD7C5827 +:1026F000AFEF27BDBE7213D7EB055CAF83BCFF6B9A +:1027000056A275C50BF22E2594F79F2791F74389A2 +:10271000E4FD6F20DF4770BC64F2FD9361F91B9DFF +:10272000DED95E99E0C91672F445E9FD89A0F3315E +:1027300041F751E87D8CE83492DEFF9E50BF26A71A +:10274000F727F1EB711CBDFF33AB76D475FCD34496 +:10275000F3EDC27179BFCC1B378FFA58782F215F08 +:10276000AB7C9D60DAAD682F6F077B0BF785B0AE51 +:1027700029DE047CFE3798DF2CEF28F33BD5C6ED2D +:10278000B0955B6FE9C27DFBDF603CCD3BCA7AF15F +:10279000B6E0A733ADF7D5828F802EE77B7D23F59A +:1027A000640F9892C837D3734313093F36380BF53B +:1027B000D28E6F6449182F29D4FB24B4B7C7677130 +:1027C0003A46B3342A8DEF76287D9282ED5B542908 +:1027D0002299FAABF3FA92F7678503E0BB04C7BF0F +:1027E000D9AB4FC1EF7E9065B1DB84FDD093155D11 +:1027F0008E7A7B96D0D3B3843E34EABFCFD31BB05E +:102800001FE09B2F6309F6F71DB6715C6F733B9D4C +:10281000EB69031F5B30CA06715D816D1CAE8B31A5 +:102820007DBFE86143DF2F73637BBE3E82BE0F2214 +:102830007C8D5E83FF787FC9E06C16EB65B39807EB +:10284000A30E705E2BE05C381A9C563A9D2DBC9D01 +:10285000082F5F9F6EF4FA92F7079C639A4FEC0380 +:10286000F7C5FDED5C5EAFEC2F213BED3601FF9D22 +:10287000B9C15B115E3D4D3DE8A5E0819A8AFD6ED0 +:10288000177EE3ED2BB752BCAB67AD5A89F65CFE01 +:1028900072BECE692BC7F4E07E71AD982F2B9F0ED0 +:1028A0007FEFE81D5F5D41748920DC974DE1764341 +:1028B00006E80D1C0DE51FF79559CE881FF7B39D4F +:1028C00052C4BF04F97F16D8A7D8C03D3FA1DFC3CB +:1028D000280DBF86812F73D79CA1FD3A6AAFA6450C +:1028E0005A82E7D2DE1921FB2246476F2591CB356C +:1028F00074D05B83BE864CF28745053FC03C6D2794 +:10290000F9736793BFC4A0EBC8FEF97CD5075B24BD +:10291000A4734A390C054F538211F481309BD6CDF4 +:1029200006D13E2A05FE407FA6FB55EA2F064775D5 +:10293000B5198ECA6A8423D67F87C1378F9D0B3C19 +:1029400046BBE474E1ED0C3F4232BFC193F9A17F75 +:10295000C5798F605C07E7F5379E681B01DC726103 +:102960007002967DE42FB94CE8C3CB5C6ED29FEC2D +:1029700053E5587CFC01B4262B20BFED705C4AFA6D +:102980003CED9CE018180D8EB3F55BBCE91DE1B77A +:1029900078D35B9BA0BDF05BA4B3C1888CFE1F9570 +:1029A00091FD8843165471F945FBF07DA1E7329201 +:1029B000D87BEF0BF932F8FB9A0DD3D838F427BA4D +:1029C00058C493C5CB8C2A92AF8FBC24077C9DD56D +:1029D000AFC854D0FF6AE063E067F47BDA22B70B3C +:1029E0001D7CFFF0969D353DEEE6F855C5C1632B85 +:1029F000A83FEDF58DC4CF0AEFA1D670B0C18EF11E +:102A0000AC1095DEF074F65B2F8733A58AE6316251 +:102A1000AFC2B0F2C0F5B70108AD5248CE06B85704 +:102A20009DF7E1B703409F0157F53AF4BFAE994DCA +:102A3000BEE3B3E68F2FCA17567E386553DF0AC14F +:102A4000B86D332A9BB24943D55EDE0FFBF4B6174F +:102A50000347DD01F4DFD55EEE077DD1F672A0C934 +:102A6000074BC6BC6D999B36839CB4CD93480F33FE +:102A7000F64FA9F568DFCDE2F5F26D732E473F4EB4 +:102A8000DBB512D91313E07BB427DA0E98EDBB98AF +:102A90005C6DE0FB011F5FCFDAEAA524EDB8DEAB89 +:102AA000CA16EDE68CDEEE0746BB455253223F9A2E +:102AB000D16E138E0B6518B72AF8CD691BE9E13684 +:102AC000FDBD1724A81F98C2E373EC603DF9852F64 +:102AD000330C99F67A9AA797C49C80BC5D960D7DBD +:102AE0003D7BA993D68BEECB53A3F8DD814FB33654 +:102AF000A3FEEFD6C791F439811FDC55BC447EB6E6 +:102B0000839CCBA22EF87A26F24747B154934D719D +:102B1000705541794DC66F87CB5E1B83F614F0D597 +:102B20005CCE575237DA6103AE92CD011877CD5E95 +:102B300039E0D492F3CB48BC4FB8717DB6E2F7CB05 +:102B40003A3945728FA403E0BD08C7DD5F38D47FF2 +:102B500021F4F352BDCDB61EC67B76B273FC20AD18 +:102B600083C166A48BFE0A5FF7CE028F9BB0FDB9CE +:102B7000E311381A423C3E75F07554C03937C97CB0 +:102B8000C99E8FDD081FE285EB0EE07127E2211759 +:102B90000D16A2FE30E03F5B3D19C91EA12723D9C7 +:102BA000A3E84998E7B66C6E377DBC86A1DDCCED15 +:102BB000A664FAAB3BFB9CF55777F617D05F71F331 +:102BC000F0C01799079869A2BB5D901DAA9A0AF5F3 +:102BD000A9F8BB86F91D6CD05912E37BE934EBF3FD +:102BE000A473FEC73C8DB650C8EF9593F7FF647E83 +:102BF000F08708973D7B500E9DC3FCEC11F48B9B36 +:102C00009F3DF1F4B1D269867CAC2D03F4E48929AF +:102C100012E1AB9F069448EFC2D62E0E9FA9AECD0F +:102C2000B43FCA009DA9C4C51B32751753E2E273B5 +:102C3000DE46D554F705FDA6F6B94D9AE97D5EA8A6 +:102C4000DCF4BE6079C0542F6AA933B51F1BD64D82 +:102C5000F5E248A3A97D4967D0542FEB6E32B53F0A +:102C6000FF8190E9FDF8E872D3FB0B76B798EA1381 +:102C70007AC3A6F617EE8D98DE57F6759ADE571FC3 +:102C8000EA36D56B071E30B5BFE868D4F47EF2E0B3 +:102C90006ED3FB4B3EE835D52F1DDA6B6A3F950DA1 +:102CA000E75F4994EF0696A462CC93CDF49EE24F81 +:102CB00027803131AF2E5829919F18D86BA014F47A +:102CC000C355BC09BB4AE445B1D976CAE788C03FC1 +:102CD0005C7783F1F91DC5D8AFAAA03F530FD84D3B +:102CE000F95353453ED4544B1E543D1B97A1C1B8D4 +:102CF000530FC92C0AF5D967E0AB91784967C08BAF +:102D000005FA10AF5FF37C3916D107304F2D195EED +:102D10003AFC43BCAEC497F0DDDCD38CE2C223F0B6 +:102D200014F8CCAD931494BB11F832EE0FB0E26BF3 +:102D30008D7716FB44BC33C00218F79B21BB09DE1C +:102D400013AF825E61C9E9501F71D1BA5AAF4B51BE +:102D5000A49B11F71C81AF9FC5F804F04AD1CC7237 +:102D600098566E96434FC03F3A1F45D8A8F43E137D +:102D70007D35F8C7EDB52105E93B758AC41E2C4E9B +:102D80004EDF2B15733ED1D9D275B64FC4D1055D38 +:102D90003F6153AEAC06FAE957662AE85FB5EA39F7 +:102DA000837EB04FFA8AAF36F9BAD3EC934C71D523 +:102DB000B358779A7DF1EDCF7DDDB9C9F705EC18F1 +:102DC000581756E2774C0969E7B2BFB9CB3762DDD5 +:102DD000BECB37CABA3DBCBF99C2FDE3C63AC64AAC +:102DE00025929F8EC96C27FAF1DA7CA3EF73DA7C07 +:102DF000D67DCE09257E9FA33B7353512F809DD056 +:102E000089F018FB9E9335DE83E812FC16FA076BF7 +:102E1000E3F1D7EFF1F9CE1EEFEF8EC4FBBBA3E1D8 +:102E2000BD7F1DF763EC7F510EEC84519FCB96FB69 +:102E30007C80EF563681F2608C784C63887139550E +:102E4000EEDB8D9B3F803F8AFD366AF5D20A373E26 +:102E5000BF95CA64FCF698EF9CED9CC77C7F9D9D56 +:102E6000F34F5F84DFBEF87EABE56808F96303DFEC +:102E70000F6DECE279691BD7F1FA51312FCF8B72CC +:102E80005B0EE7A3FAF43AB26F37481ED2931BDE0B +:102E9000E5FB8C0EBB1465DCCFFC22D2E160DEA426 +:102EA0000CB45B4FF6BFE20EC5ED7BDE12F81F11CE +:102EB000F8BF7DE730FEBF26FCBF26F06F5ABAA5EB +:102EC000D6847FA14AFA1AF58C1CC3DBA1F652BE48 +:102ED000C74CD94DF8B597B228E5CA307DF68C1CA1 +:102EE0004A5327FDDD5EC8F5731AEA67A8BB449E06 +:102EF000136855CA5FEA847FA4A7455E93DD1F97D8 +:102F000057C4D06FCCF368D2585CBE5371AC7D8A85 +:102F1000250FC9AA178F1B7AD1C172B95E5CDB7904 +:102F200001E115F2C7EFABAC7AD1A81F1C2CC91D6B +:102F30004C2047469951E76A2B8DD3D799BA6AAA94 +:102F40007B1BFD6DF17976BEA0667A9FDB546E7AAD +:102F50009F170A98EA05CBEB4CED8B5A74537D6CA6 +:102F6000B8D1D4BE381234D54B3A9B4CEDCBBA43D2 +:102F7000A6F7E73FB0DCF47E7CB4C554BF6077D8D9 +:102F8000D47E426FC4F4FEC7F80BF9014AAFC07398 +:102F9000013FC6BC3ED8F717E5145F81F1FC8E7780 +:102FA000AFF1633C7483EF6A573C3F5ACB833ECE0C +:102FB000B7C9DE1BF2BBBF35186C2863ACAFB5C90F +:102FC00024CF8D469E4DEB727AFF7C6B0B3DAFCDCF +:102FD000E172A4648B7CFCBDB6779DB8DF502311F1 +:102FE000843A570AD5E6A01E7DD51CA740CB08FD24 +:102FF00085979D86F1E2F0AD67D7061BE2E831DDEB +:10300000B5D8F47E86BAC2F4BE11E87131E8ED2F6E +:10301000FB6F353D9FA57DDDF4DDBAC2250FA01CF9 +:103020006DF43B28E76C236322AF92D375A3C2E90A +:103030006CD075E3DE257EB44786E91F69BC427714 +:10304000C7E83FE7BB3304FDBFECC7FDEDC14CA0B3 +:10305000EF287C7C26FA5AE97A48C4EB1A1DE63838 +:103060007CABD05746097A2984F47DB15FFE3844A1 +:10307000D88EEECFB08E6F1D17F4D52DD8DFBF9749 +:10308000BD76E35636525FDF9DC3E31A8D36D860B6 +:1030900081DDD3688F3692DF5BEC4B1589D37C835F +:1030A0006F6600E3FE5FCF91843EFF06BDBFD398FD +:1030B000932474524091F4C5E921A9784113EAE1BF +:1030C000469F83FC778D225FC0FADD2A418FBF9631 +:1030D0009FBE301F09FE30F8C8E08F64FA5DC11250 +:1030E000EA8A5BC4016371BDED3948AFB7405E72D7 +:1030F00046CA8B757DB4F61F663C8F9FB979BC8F2D +:103100001AA2FD7FC84B765332BA6F6C557505ED28 +:103110007D55CBA0F318229F1B0C5E7F7CBEF37FF6 +:10312000553BA36EE4195ADB87F157F43FF9DD8470 +:103130001792991F3E0A9563DEC40B62FEABFD7ABF +:103140001FF26FB53FF80CE91D57A81CE906F5837F +:10315000545787EBCF139DFD50C7B881AA9E557C6D +:1031600002BE7B3187DBC1463FBFA47EDCBC1FA80B +:10317000BF4CF5ECE1FA2BD4BE90B73FDB71E2FC1B +:10318000871CEF0199CE657CACE819594097ABC319 +:103190004BC90EBB36BC82CACE56B5FE7740C73788 +:1031A0005B83EDED20CF575F5BAD623ECCB5CB9638 +:1031B00052396CBF09F971142B418CFFC8C5B6E0B8 +:1031C0002E925F1E9792C1DCE1746DE7795B40E857 +:1031D000B5A05F17AE9CD7DE1E27072E3C6F54822A +:1031E000FB3FE5CFF1FBA969367D28E71CE23D23D3 +:1031F000F1039D04FCFAB1BB341A21FE9DA6268A78 +:103200002B197826EB7F61123D61E069D0CBCA773C +:103210005DA5552ACAA15206F6563AF543F617F3AC +:10322000B8843CF176D741FF4F20DD948086FC893D +:1032300075E457233E7A1D90686D556CBC69B6A045 +:103240002FB776241DCF964ED930C6008DD74D713D +:10325000BC6D6EA31EA17CA860298FEBA568FCBD88 +:1032600001076C0F18C601D36A988A8F6CD80EF7C5 +:10327000076903BAAD12F615B90F5DE11F0FEF4BE9 +:10328000437E5B80EA2F283E8C57439DCE5A3DF407 +:10329000C2C129B88F52BF8479A62E65FB0B872E39 +:1032A000A5FC2761976C7F01D7CF9EE13AEB63A025 +:1032B0003F7B5287EBBA0BF6523DE386EB11ACEF46 +:1032C00010F9105373B7BFD0CEFDD893737D188714 +:1032D000B445687FC33C513A67F8378E2FF6543CAB +:1032E00071681CEE17FC4AA04C43FB9899BE5B9694 +:1032F000EBA0F93AEC0F5D81F3E5593B44EE8C7B92 +:103300002AB23CE83F8ECD43D4320F9CEEC1F2A8E6 +:1033100088AF46695EC6FA3F8ED4C37863A7F06370 +:10332000781A5337615D6BB7A97DF4208BE6C956D7 +:10333000DE223930FFA682A9B8CEB68978775A390D +:103340008FE3AB4EBE9FBB3E97C78357E5F23CA0D1 +:1033500055B9DCFECA30F2421B6DD43E439431FCB9 +:10336000DBC5778A695FDB5C105A911B1FEF667DB6 +:10337000B3CB018E9EF6AC2C8CFBD6B7DBEE403B7C +:10338000E82191DF03F3D448F314F0A686F8BCB526 +:10339000E0F723E64DE075A6794B365FC63E2AD9A5 +:1033A000FBABAF95E9FCABCD15BA7F018CBB6AAF27 +:1033B000B712F3A98F34C93503505FFD742EE5179A +:1033C00074E6F275618D6D2807D7DBAEFEFB82587F +:1033D000BAF6DC1A2960B8DE6A26FFCB9A7DF5B40E +:1033E0000EAF4F4B9F82F36D85E3C8A73FCFC679E1 +:1033F00098FD2727C93B3AA0D07FD54CC24568BD70 +:103400008AFEAAEB851DF4682EB77F5E15F6D6F509 +:10341000C6FE8C0D9F13953E87ADE6FCE0E2394871 +:10342000BF254D32C33C88E6D87BEE070B73BF95B2 +:103430000BFEE17E2EC43267A2782E8E98FD59CB0A +:103440005860269E1B5ADA69792EF673CB2C7EB112 +:103450006B9A62F6D04916D36FF3356E47CC0FA442 +:1034600045316F6741D06C47BDF699DC1C04FC8F79 +:10347000E0B700F79185E7EFC476567A9C12FCF925 +:10348000AAB03B87E9C3A82D5B12941C78E4D14A0B +:103490000F2BFEC374B3D061B15239D3A78DA4836F +:1034A000157FA018D17719D017F38C92D163A63C61 +:1034B000DB8EF1E2A5F324B2EFACF4B1D2C1D88F28 +:1034C0001BF8FCCAC093058EA4C178BFDD6C676889 +:1034D00077B1BECB283E76A56817870FEDBB55F8B0 +:1034E000C7FD98DA735E84138889E72AAF8AD84DBE +:1034F000FBF56562BFBE840533D08F0C78BE976440 +:103500009E4DFB762BDC56BCE688F5C2BABF674AF7 +:103510005F05DA31C772855F79A2D9FFC96A7C0974 +:10352000F5AE759F6FF05573789EC99E965868B832 +:10353000AE823D719B5FD6F05CF04093FD7E5453AC +:10354000F35C43FCFCA83857348FB93437B4BF055B +:103550001E225E57EA295437FA3BD12D35A25CDE94 +:1035600006DD8569FDD569DFD1CC9B40193980F432 +:10357000BBCDEFA07180CF3E8EE7B3647470FB8546 +:103580009F63229B782EF877E532927FD5CBFA3075 +:103590001E3224B9A23BA5985F0E7E8D3840551689 +:1035A000FB8B855ED6CDF13DD64276FF59F8E98A90 +:1035B000FD09FC7446BE83C19FD7BBDC7D32E7BBEF +:1035C00063C3FC61CA770831F4C375E4DF1C407A39 +:1035D00077A472BF9BB14E823D3BC18FF1F354EE95 +:1035E0007F33F47C2ADA8332E61B813D1847B7111A +:1035F000EBF4C11B76F7007F87DC0ADB44ADCA0918 +:103600003E3AC74BF00DD9B19FE6B0FD447C3F2157 +:103610000F68950A84EB6215CB257E9EB7B184F1C5 +:10362000FD3F8B40FBB8B84408A7119F6372755CDF +:10363000FFD87E2DE6FD74C6F53F8EFAA73CB95043 +:103640005E6A1427C53AFE88F5CB329EB5BF0E914F +:10365000E7D7E1080CE8E8B7FE855CB98ED0E5FB5A +:1036600095A0DF665AFF96B8BCBA12777EFBBD3CC8 +:103670007753FCFA6D94C677063D6376DA25FDF143 +:1036800076DA3D1B6AFB0F15C5D96991DA7EDC9F9E +:103690007E513BED6B0FD4F6E379B0536F3B695D20 +:1036A00038D1C8E964E4E32860566464D1BE2C8252 +:1036B000A52B5C40F818F9395E2D20E1BC7DCBAF1D +:1036C000F1FDAFC6E3D25E2540F7606C35CE95E3E1 +:1036D0000FCCC3D62CB507F5B4D3C5DA53B2F03B43 +:1036E0008EB731DE70BFE50149AD48EEEFDEE43F55 +:1036F000E7F8CA267F82F84ABFADE59D6FA2DDF8E4 +:103700000B99615C6291FFEBF4DCBA0FDB26C66BB0 +:103710009542DB501E079A5E597417FA4FF638C966 +:10372000AFBCEA6B1F7EBB5643FAC07C57D3FEEC9E +:103730007EF407CB6536B2CF3B8BB8DF475E27D12F +:10374000FEA54B7334EE81F2F59CFA67B03FD6A824 +:10375000D9909F4FA4727E7E3DA7819E9F7A7BA3C6 +:103760001FCFE1A4FA5329CB485E577C2FDDC370ED +:1037700058A6FB113A5219ADD71D0E5EEEF1F3FCBF +:10378000CF3D82AE8F8AB2D31E2A6FA9C07C6A9CBD +:10379000DC181D5C4A84EE19709D56E8B92CEE05C4 +:1037A000E9480D95DF19473FA35FD76910E2EA4466 +:1037B000DF3BE839E245DF6771788C764F8BEF9F0E +:1037C00016F0B84EA7D1781D5900973BBE9F74FEE6 +:1037D0005CC899554ECAFDD30FE03CBE9EA33FE3A3 +:1037E00027BD3A68473D7ABDFFD051BC97E4CC7AFB +:1037F00090C7233C9F4A7D63D12EAF97A3EB8BF1FB +:103800009E13754E0DEE07EBED940733509EEDC100 +:10381000B8D2CB8AEAC17DF92B62FE833364DA5FCA +:10382000C38F6F3ECECB8CA593B8BEE3F157633DFB +:103830007AB9E289816978CE2362A7FD48B32B1259 +:1038400045B8E2EC1F1197E6F7ADD07700677383B8 +:10385000ACA7A427B013C5BD2986FD096AE220C61E +:10386000DD7F23AAEF349C5C80E00F32D5315D8A86 +:10387000B747F97D23CB44BBE6B0D97EB2DA574BCC +:103880006A02CF7B35A4476F90E8314121B9385B9C +:10389000BB93B1FB687EEF69F8A90BEF9B392CF461 +:1038A00082A7E1151DF504D8490BF0BE9C2B1B64C3 +:1038B000B50F5A6F0EDB18EAD12D3576DA5F6C2919 +:1038C0001F3C7C19CA638DA2D1BEBC7C60FE747A99 +:1038D0005FABA2DD348043E4517B1E1F72BBA36546 +:1038E000B8BED7FEDAB5348E5FB6D4BC371ED7B9B2 +:1038F0001D828F400DBA674C8AD10FE9A39112E562 +:10390000FBF883DF4825FDF4CE6659C46318DD4B10 +:10391000E2F173799C21E2354BEF97283F6D69ED19 +:10392000917ABCDF66E90689E4B279ADFC2EFAC96A +:103930009BC366BB2DD402F69C467436DB73C2DE95 +:1039400083CE1DC8BF676BEF59ED97D23C61BF5561 +:10395000B1AA78FB25D9FECAB05F14A65F90E78BA9 +:103960008DBF44E1F156A65F45F49D211F3B7C19B4 +:10397000E077A266DC38A4C7F784BF774BF80D1751 +:10398000EE7FB77C2A939CEF7080618379FEE953C8 +:10399000BEBF0EE03BF08D2FE5FE16DE4FCD7388E7 +:1039A000F34EDADF4D4139F8859DF828195CAEB049 +:1039B000CC4A41EE53C21295C6BC78C2294C89D379 +:1039C000371E713ECB5733248D8BD32FB3F3387C06 +:1039D000996BF9BEDA57C3743CEABDBA74DC4ECCBD +:1039E0006F858589FCA529C55A15F291D13E57E20C +:1039F0007E6FE7DE7A1DD62E3616E0C0F1348003E6 +:103A0000D7B9E2701AD5C785BD54968433A92C0D59 +:103A100017D0FBB2700995E7858BE9F9F9E10BA89E +:103A20005E1EAEA6727CB892CA2F852FA1F20258F4 +:103A3000E7B05D45B89ECA09E12BE8F9C4F05554DA +:103A40005E189E4765207C1DBDAF0C2FA5B22ABC19 +:103A5000989E57876FA17A4DF876AAD7866FA57280 +:103A600052F86E2A2F0AB75159175E47ED2687EF95 +:103A7000A1FAC5E1EF507949F83E2AA784B7D37B74 +:103A8000C3DE7849C8D5DCCC252ACFAB0904707FCA +:103A9000B023891EBE278FFB2BFEECD76F473E322B +:103AA000DAC9E23C84B5DDC63CF3F9419BABCF55A6 +:103AB00042FBFB922ADCDFEF003D5008F3B3BA6C07 +:103AC0001C9DB75B9FC7F56D8A3DA21714C7F6F31F +:103AD000990DFC1CCCEABDB752C9EABC67E51FBA18 +:103AE0002D8F7FBF4389D03D0E3B5A18C555534A91 +:103AF0000724D4133D15B646D4EBF7549CA07BABFA +:103B0000E6D4EA35E867D022BD87C691BE9A5E83C7 +:103B100070FE4B1E3FEF7AD8AF6F45BCC7D6F82E6C +:103B2000BF0ADE8F6DB7D17657636A3DD6B50646BC +:103B3000FACDF0BFF4A49AD7C39FE619F6DEE036BB +:103B40006CBF23BFB48AAF23FCDC8C7CF738DA5F10 +:103B5000EE70F44978EE3E021B9F870DDD8FED3B42 +:103B6000963C8276D4B8CEC0332E1C3F12A846783D +:103B70007F2AE4AEB85B9B960200953CA03F83B1E0 +:103B800086B268685A2AD4CFDF1D7906CBF1BDD141 +:103B90006969505EB0B7EF19541F13FA06A7B9A1AF +:103BA0007EE121F62CAA81CA016DBA07EAD547F554 +:103BB00067D1BD5D3B189A9E8EF3E488B6A5033CA1 +:103BC0003B7EC302EBA05E77AC5B866D446CFE9DD2 +:103BD000AC05ED2F635E5C5AB78EF42EBC43253FD7 +:103BE000CE0E653025B362E4FCF420DE886798DFF2 +:103BF0007F50A80FD13C004F5445681ED4CBCB69F1 +:103C00001E38BFBC23E417E6E1D93CF473A5AAF53E +:103C1000F87E68065377C2FBB9136CA4AF1D1BC6B0 +:103C2000D1BA62F01DD077FC3C4FFC3CF07E765858 +:103C3000ECD464F47DE77F087D57233FFB92D317D4 +:103C4000798FFB574797E3A1981C1F8B97636B3BBA +:103C50005F3EA79395CE3D367608D69EB8F360308A +:103C600087D054CDB79D135D53F31DD4FEBF9BAEDB +:103C70007F107A22195DC938CD8B9DBF4DA66FB0DC +:103C80003FC43B919E63E4C72CDE89FEC0B182AE87 +:103C90005D7BB9FFD2D073AE3DF57D055A4CCF7D2B +:103CA0007426FD25F48C43F839627EDB0974AFDF9E +:103CB00005F99271DE687C3EDACD7EB3FF7DB34DAF +:103CC000ADC7F98B4CE5F95973EB5ED6659A1FAD1C +:103CD0008A5F7FC7489E76A4574471FE8AC15E50B2 +:103CE00060DEE1D73E2CD32A541B9E8F36F2B69865 +:103CF000BAD81F2F67C67A1E9343831FB2683F88C6 +:103D00007C8AED57083863FD483C5FE7EBF974FFA8 +:103D100098F15D8FBB90BE33DA27E3DB8DE27D4FF8 +:103D2000FB1344C7B429DC3EC868CF223ECE6808E6 +:103D3000A16513C7BF2107F2EFD27CF99CF8774940 +:103D4000FE7F8F5EA8C33D7D2DC621D403985F37CB +:103D500016D61D0DE5720AD01AFDFD7E07E93F8DCE +:103D6000F1F9D3A6F03C55A0571FFA4323360FC5EF +:103D7000E764E75003E2CF9C992AEE7FEECC0DDD9D +:103D80009A3F8A1CA8695A254EE6FAFCFA39EE3C9D +:103D90003C77A1A662BD15EA9BEBF01CE42013F56D +:103DA0002DEEC95FDC3FB1FEC1CB5EC438D2EFF36C +:103DB000F448BE8FE212EB112EFD7C95F2330D3EDE +:103DC0003ED3FA6FC8634C7ED44A437EF05E33D054 +:103DD0007F9BF37DB1FE92D9335FCEE7FAF27B424F +:103DE000BF25B767B2489E40CEB9FC08FEEFEA1B7C +:103DF0005DCE0D78EFC91F5DDEBB66BD11C1D686F5 +:103E00005FD525FC27069C297E7EFE386536A37D7E +:103E10008947F85757A27F55C273D8AE33F857A3D6 +:103E200026FF8AE15735EE47B0D2F967F9E6BC4D77 +:103E3000D4474FC4E1C3C47EEA763166F7FA400640 +:103E40009E9F89BCC4FD18C67987D9F83BE0290537 +:103E500024F223757F8BCBDD9C42165D0F70CFFE65 +:103E6000B3C47480A3FFCF329556BFEA1CF80EEDA1 +:103E7000867EC9157541FB03954E86F1B77E8F8D01 +:103E8000F675FDEF4A2407FD956994FF77B0F2229D +:103E9000CAEFB1E6FD19E535A1C509F322ADF4B9C4 +:103EA00066D1736E9C97EDEA345731ED4B791CD295 +:103EB000D0C746BBF7C43A77D81F7A0BF9D873C37B +:103EC000503B3C61ED2A8F431AFC97E7DE7318EFF5 +:103ED00061CC5BC9EDCA7C165DA7BA47F275734128 +:103EE000E87DEC677B2CCED77F1E8CDFA98938DF7D +:103EF0009AFC29E3A083BF1F8EF3855E473ED7BDA2 +:103F0000BD95C887DB033FFDE1BDF07EB613F6A982 +:103F1000A887ABDFCEC67BA216D63EE7437ACCB1EC +:103F2000C06F9486FFCCBA1FFDCFFCE17802F9D3B5 +:103F30004FD65C45FBDF64FE74C3AF67EC4BD16FBB +:103F4000A726D0E3567A1BE32F94F8FE93D925D207 +:103F500063FDD87432E9095701AE73ED3C4F4677E3 +:103F60004A9427F3624D35C51B58C02BE2987D85D6 +:103F7000F1714C031E785E9628BE992CFF606C018F +:103F80005F6716DAB9BF52BAF5B98538EEC24AA7EB +:103F9000C4CF27723E6DE6B134962EDA370736521B +:103FA0009EBA355E915EC0F7A5FDF6BE4255F83368 +:103FB0000309F833195D8EDABB292E767499CC701B +:103FC0005FFE62E8A2DCD1EE5D7B03F9A38CB17FDA +:103FD000C7E0696DDCBC69D909E7FF28E697D947D6 +:103FE000C68386DF2F4E213F7793C89F309E3716BA +:103FF000707BE726813F7346CAD1CFDBB9E47E17D9 +:104000009B80791A276A2340F72E3654BB13F5C3D9 +:104010005A0FF90D9A167F52BB6E421C1DEB381DCC +:104020009B9FED52915F9B8ADB7D91B871ACF4BC94 +:1040300009F1827153043F83F97205F187D5FF516D +:104040003A9FF3C5B329813E18DFF5EB922A5CC78E +:104050000DFF078EC3CFE9737FED1D22FE80BA26C8 +:104060009EBF9BC2AB4D7A23E5B4C4A2F175A59B5C +:10407000FC9D29A7157A6E95A30905E6B89441EF32 +:1040800064F367D0DBFADCA0F7D1C55DE5E88FEB20 +:104090004C4D6C273D28DA19756B7CDC880B5BBFB7 +:1040A000FB8698C793A1C9C45F4D8E48D9D9C8AFC4 +:1040B000419F239F6E54515E5C22EE6EC4FD3DE530 +:1040C0005914E73FD224535C22B54CED41BFC0EDFB +:1040D000057CFD35D63D237E982C1EE8B1C41553D2 +:1040E000CAA11E4767EBBA67CC63B238A2759EB609 +:1040F0001598F5DD70FC3089DC18F2D22CE4EC4C1C +:10410000F910D724B9A771A598AF93A1BF5F300963 +:1041100086BABDD6A6221F6ED1F04C25FA4FED947B +:10412000D7F4FAA74E86769EA7D6F67DF4731F5D68 +:10413000FCFAFCE9A8176AED1497E803B95F097265 +:10414000DF25E47FD8AFBA598E9649B87F904C717D +:10415000DDD45297A93EA7D64EEBF3966D9551DC70 +:10416000CF34311EB7EBAAFD4A461FFCFE7AA98365 +:10417000FA7375491457727DB63188F3DDB7F8EFDD +:104180009AC89F5AE6C844FD68F08311377489FBCA +:10419000A09F2D9B7435DE5FF0CE663BA3BC7A29D1 +:1041A0001657D6C0FE5B5A5C93837C378879AE1471 +:1041B0009F177E5E26F483F0CB1AFE70AB7F369994 +:1041C0005FF66CFDB106BF58F9E2B582C471E564D3 +:1041D000F31CE797FD4D42BDA4CD37E917431F19E6 +:1041E0007AE10D81FFEBA51D8B305EF47AC829E8DA +:1041F000F7DD175B6B289F8FCE63BB3EFBC10CBA0C +:10420000B7748594D01F5B66E8658CDF97C7E87C40 +:104210006D28964F8BE27CDD72733EAD755D48AEC6 +:10422000A746D7433B0BB87D64AC1BB83E64B9F9D5 +:10423000FA60F3C4F8FEAF5D279A166F0844265063 +:10424000B91BFB7195A4D27D4B5679B7EAF9951647 +:104250003D19D3EF328B7AE3E553E3EBCDB09E7794 +:10426000D0FBE1732DEF4974AEE5931CBDA010DBCC +:10427000E5EA85583E94A31715C6F5DF66E7F9B25F +:10428000B28D851E277B3A68CAB36D28E4F3B5A1C9 +:104290009EB73BE09BE4FF3D946DEF56FAEDE88757 +:1042A0002FE471B7839ED1CF09DC2BF8E71ED447EA +:1042B00065313B7E8B984F405F47FFC8067BD01F20 +:1042C000EFBF2B29CCA4F1D3273F31807ED236D546 +:1042D00046F71EB7A90AF953DBDD4AE32EFA8EE34F +:1042E000BDC1A33F1C11F6D0020F7ECFE153DCE627 +:1042F0007CD306BCA3C617C3CB0A6F43215F07D28A +:1043000073F5E985503E95A337601956224EA47780 +:10431000D895789F7279219FBFFC4226F8DC4D71B9 +:10432000411A573EF773494FE68716E0B8A76C115C +:10433000BA9FAFCD33E99CEE370D89F98B3B4F1611 +:104340002AAC4DD03E76FEFD5B1817AED7D8C751CC +:10435000045A9CDB33F242C1EEBD09F9E79A0D899C +:10436000F32D7B9836AADFCA2DFA81FDF6EA42BE0C +:10437000DF6EC112F6DBEDA8DF5980F7937E867EF3 +:10438000804E14D73D8BFB56BE85F88E3CEF151A38 +:10439000C4FECF968E5D625EE3E8D85598404E0D20 +:1043A0003A9E7AFBFC0C8C471AF7C558DB19717CD6 +:1043B000A3DE99691EBFA38AD7B78971B3445C7B1A +:1043C000B7A8BB2CF799B866F37B798C7C08A39FC0 +:1043D000DD851EEE57CD9FB61BE9D051CCEFE7E847 +:1043E000C834DFD3B1B4B07E37E2B353F4BF5BF06F +:1043F0006FCF381E57B0DE03B852B45F59388D4ABC +:10440000505EE3914F1CB29C908E8F1572F88DF325 +:1044100091C6F9B4A55B64D3F934635D5DFA34A346 +:10442000751FE3A128CFC9F2DE42E5EAF3E8CAF935 +:1044300084553830DFEBAF5D6F919E695923D7DB30 +:10444000E70A13E7B125D37771EB6DBFA08F79BD74 +:104450006581F2783D6BACB78396388E51FE56CCB1 +:10446000CB66B10F47FD89FA1AEF0723BDADF07D8A +:10447000EAD674EEC744FEC37B417E5B68CE7F31D3 +:10448000F26D8C3C1B23EFC6C8B319BE17C79267E9 +:1044900033E818DC900BF335349ED139D3DC85EA50 +:1044A000815CCC4F68D018FAA33A8A597A1DBEAF06 +:1044B000B405D06F9F395FEDB0433D53637853200F +:1044C0009EC78D78A0DF94A2629AFFCD91AB0EE4D7 +:1044D00042BB0C4D9DE98776194D1ADD0766F899A8 +:1044E000FBDBD7D3FD4206FE7F11F86768DCBFEA2D +:1044F000D2F8BEBB9E1591DD1E6B679C6FD2FFCCC0 +:10450000E9CEFDCF780D2AEDE303A964B7CEC54807 +:104510003FDDE3D24B797225F9D359912F263F78AD +:10452000DFDAE3717E596B5E514AD1E87945A90B18 +:10453000B93C5AE7B1A488EBE3FC5C3D1DC7C3FB63 +:10454000C4E549B17399A90BF9DF0D4AC9E67A357B +:1045500045E37165A64AE4EF7169A110C293E2AF29 +:1045600053515FB639DC9D123A6A6FB031CC9F9DD2 +:104570002EFAD19B98F47E39FFD3395C6F2AEC7DFB +:10458000839F6581148C3B4DA008D6DCE634807F88 +:10459000BAFB177FC27BEF534A5BEAD12FF85C333B +:1045A000EF636B12FFB7915F15CB278BBE64CE27ED +:1045B0007BF02553DE7FE4C197FE9ABC7FFD7B0F25 +:1045C000BE84FEDAFFAA7C32433F1D954347EF06C7 +:1045D000FA2E00A582FBB605D0E342F25BFA896EA3 +:1045E000F3059D237F063ABB62743E6AE7F7A52C6C +:1045F000D87798E8689FC6496DFF4646B48DEC921F +:1046000028F57FB5AB7B06C6C18F3B8626E2B8C7CF +:104610009F7EAD08EDC5B7BF79D2834908EF284327 +:104620001E7CFEC1DA573C987FF7F65A99EC9DEB59 +:10463000C57EA0B9F5B349180F592CF8695F91DE12 +:104640005414B71EB1B08FD6D9155199B63C861EF9 +:10465000BB65779A60365E5FD5EB35D58DF5759580 +:1046600093FBA56F79F480A300E05FB13B93F6CB99 +:104670001F8838CD077B8A7A502FFF5D914D8C1FA4 +:104680005C81E3235C689FBCB3CFC9FA482F0DD887 +:1046900019DF3FCF9672787E25FE58E17A7E7F1A29 +:1046A000F5BBEC7EBE1E2CD6F8DF3908ED5B417AF7 +:1046B000DF0AF7B2B77B9FCF07B89675F17B42B0A0 +:1046C0003D9E9B0985B9BFCB8A97755D58DA7BAB58 +:1046D00083E70757CC443DF649A7447ACCBA4EDC71 +:1046E000B4EF1EEAEF0616E89C02702DEBB6BE9FF3 +:1046F000F50764EE9B2CE7A0ADEBC79622B15F9B5C +:10470000C42EFA1CF44E9B7B5CC668E76E3F68E5DE +:1047100042F96FAD2E2A8FB5AA54361569FC1EE4F6 +:10472000BD079E2F20B11E9884EBEE9CC3D35D5F26 +:104730006531BF85D27355DF760DF952F85DC57EC0 +:1047400065A1A0BF9D713FC5FDC25F2FAB567FFD28 +:10475000CBF3316F20E2E6F74F19FE8B85488FB817 +:104760003CE88567F05F3C6AE07D11E0CDFF8EC4D8 +:104770002F3576E6753319FEC9BE5B95E45E7E4340 +:104780003E9A049FDEB06B5E07863EDA9EFEC3183B +:10479000BA4F4BE4D5C9822EB2886BC8CC9247176A +:1047A00061AFB238FEBD092F812E19C9A706BF30EF +:1047B00037FFDEC55CEBE8BC81C19FFBB610FD0C8A +:1047C000BEC1134536D439ACCF6FAB3BF37904E0AF +:1047D0003F53FD8FF6C131A8276EB2DC43F2472963 +:1047E000F1BE667FD1384E074D9F89EBD43216EC6F +:1047F00050890EFCEF807DA0743F7F37CAF72E8969 +:10480000A15CAD7AF2B19FA15EBAF927F7A7A35ECA +:10481000FA50E9CEC1F1563EBC211DF5F8074A24F5 +:104820001DBFFF30CAF59375BCC231C67E5F774BA2 +:10483000A03757E3AFC8003744E6A25EFCCF87ED50 +:10484000F4F7F3D6EC76F6E1B9B9D57B381DA1FEC5 +:104850002EAF6F247AADD96B96BB9B7F707F8EC6CF +:10486000CFB51608FA15A06A5EBDCB4E7ED5D5AF82 +:10487000CA788D1F5BC386083FEBF708C76998B7F6 +:1048800035BDF26247C6C8F760C93850AED608FBDE +:1048900071CD1E3E5F6B2CF6E2F224FE99B431C25C +:1048A0005E147C0FF4A1FB16220017FFB3185C3FC7 +:1048B000B7FDD0A963FCE8C337727BD07F726CD799 +:1048C0000BE952454C0E8CFBF08EF5968CAA2FFE10 +:1048D00028E46558FF8B7546DB0B00E259827DBCEE +:1048E0005C69EF4BBF04E8B3B2C71E88C0E3958F85 +:1048F000C93A6EDDD8EB4EF2C7DDF2D873472E060B +:10490000786E79DC9E3D9BA3E346BD6DCCDB1AE45B +:10491000F7AAD83CDDFCD3E71CF8F741F039E6C72D +:104920001BF375CBE3071CE86FB7D2757AEF01076D +:10493000973BCBBCF5BE3B13D7E5B61F9E72205FFD +:104940007CB85F62B9C523BF5FFEF00BE9D8CE9893 +:10495000B7E1791C317F7D739FAAA17694D779A6A0 +:1049600079FC08FFD0602DF1FB8F9F82F197BFE1AA +:104970000C20FECB7F7C7B3AE2F107A585F3FDF7A7 +:1049800036E4E07ABCDC1EC951A9E4CF97EFB893B6 +:10499000F8F1A697EFCCE17F2750CF4379063CF39F +:1049A00010BF65FFB080F0BB9185881F977F8F9FF8 +:1049B00043FB44618D8F2798D76D426EFEB0D3497B +:1049C000C6FE1F308887FAF857FCBC2B63B7921DD0 +:1049D000629C8B270D0DF54F5C7C9E568C31F2BF8F +:1049E000B87E5B235AADD9B591F4DBBF15E9B92880 +:1049F000FF4007939E935F9E912BF422E50DD377A2 +:104A0000A032A6E3736C3F60D753269ABE137E2C68 +:104A10003EFE1D627C803B55BA10CA9CE1FC8601BB +:104A20008463B5C4BF41FEC1FCD867C770BB7E5864 +:104A3000FE7775F17912F2FFF1AB5CAFAC8ECE6B05 +:104A400024BD3060EFCBC576D103F325D20BCED891 +:104A5000B9FF78B9DE6517726D7E0F7029523C3D43 +:104A6000F7F3BFE7B4660FD7DB376E83F671721CBE +:104A7000E31747EC79714C2E8DF8C04D96F88C51A8 +:104A80005AF5C2B7C798D7C3E1F8C23FF846F5E771 +:104A90001B76D94A7BF49107517E5F7792DDB3F2A2 +:104AA000313BE58B7FF4E8B347BE0AFCFE51AF21F2 +:104AB000B7667D6B95DBE54F2C6089E4F6A3EC20AF +:104AC0004B28B7F03CA1DC66F37B64FE66FA56CC5B +:104AD000433239BD2989BEFD678BBE053B23E312F6 +:104AE000A8FEDB3FDE3296F21E2CF435E86AD59B39 +:104AF0005F19A325D49BF0F32A8BA3A74147835FBB +:104B00006FFED12A1A67988F0D7E35D6B1617EB5BA +:104B1000E26DA6A7F5FD5AFC034DBED8FCDBD7C35A +:104B20003E1AF3E39E96E93CD8716D281DCF0F6CB9 +:104B300048E17E83E3AAA867F2FA90CFD181FAC355 +:104B4000783E94C2CF891C0F0EA567C6EDE7DEDD67 +:104B500027A7A3DF7C30CAF7DF563E04CDCCFD1378 +:104B6000627F3E43768F09E3FEABBBA40A23012795 +:104B7000DAEDA25EC6FF0E87C847392ECE811D171B +:104B8000E7BE7ECF82472E217B4A57F2809E4B396B +:104B9000AA6CF9E1B674B4C797EEBB85EE69BB6148 +:104BA000B3990E37BA7791BDFE095B4BE58DDBCC2F +:104BB000E71B6F16FA7DF93F589EEFBB82F8E86657 +:104BC0000B1F85841FD2CA47B6B1423E2B5925DF41 +:104BD00027F3BC92DB845E9B21575CD904F43F7EB3 +:104BE00048A678D1897D32EB40BC1FE5F73DB1087E +:104BF000CF43580DFC1CEFBF3C867C76FE48BA0EB6 +:104C0000BFFFA7B727DD0D4D56FEECCD89DBA13CDC +:104C1000F6B3D7CFFB17AC3FF9DA9837D9C8F6D33C +:104C2000F7FFE97AD45FC7F73BE9BCE9F1FD3F1F25 +:104C30007337D69F720610CEE3EBF9FE38B2DF432E +:104C4000EBFAF1226E0FB63D7D6AE220E9637EAE9B +:104C50007BC2581E0F39B1EF2FBFC17B754FEC03DC +:104C6000AC501F8AFDD89AA752687F7DFCE9539308 +:104C7000E2FF5EC85F8BCF6A11773CEE614D98C74B +:104C8000733C93FBAFD6FCCB64CAF35FB5E78003FC +:104C9000CF5B4CFFD7CF26A2DE39FE04B727C0DE9C +:104CA000DD81A677DD435DF7DA61FEFE28FEDEE6F4 +:104CB000CB0F1DBE12EF331E49174E87E34007C4CA +:104CC0000BE8B21CF565327A5C3996E7D9FDCFA3C3 +:104CD000C77F5C8FE3AFDC77119DF38ED145D2F9AE +:104CE000730FE52301FEFCF9FE531371DF7D267C73 +:104CF00057FD1FC3F79EFFE1FCEE1DAB117C56BEB6 +:104D00001FC9D74F7E8DEA3FF60408DEB394F71F24 +:104D1000FD1F9BEFC3FF6BE7FBB0986F8F8AFBC251 +:104D2000E34F7F36869D03DE1FFC2FC57BD8CEB1B7 +:104D3000055C3500DF1B2CBAA05E22EB83EC8E36BF +:104D400037CF6F1F985F4CE77898D857CC95F8FA13 +:104D5000ECD5F87EA28DD928EF666EF68D644FCC27 +:104D6000D5B788F37036826720BBEE914D09F651B6 +:104D7000FF0FB01A29930080000000001F8B08006D +:104D800000000000000BB53D097854D5B9E7CEBD51 +:104D90007766B24F561249C24C36120861085B80E2 +:104DA000A81336C383C084CD60820E5B5804127092 +:104DB000A34F5E331010542C414069CBF38D682D06 +:104DC000756983D28A2DE244D0C6D64A6CF5898AA9 +:104DD000188522024A149771697DFFFF9F7332F78D +:104DE0000E2050FB860F0E67FFCF7FFEEDFC67B9EC +:104DF000933C6AD016CFD82BABDCF64183208CB322 +:104E0000389A9D8C4DF2A8EF61FA34DF9D9FA8255A +:104E1000107AC67FC8209C98D25EA340FAA4321BA9 +:104E20000BDA19FDBE83BFD7312B0B168AB88BB1B5 +:104E30006B6BCCF9D3D98E540DDA9FBE4067010558 +:104E4000DA8B287FB69783B1C1508F35AE75C462B7 +:104E5000AA9FB154C6740BC005E5DF6281691510C5 +:104E6000363356D90AF9CDB116C65218EB98EADA9C +:104E7000A12AD48C9DA53166E3FF671EA742F59B4E +:104E800099A5B2B518532C1E2A9F52F6C85DBC4C8A +:104E900007969FC88BC3B8EA273018D744CF3D3454 +:104EA0005E9B6F5D07854CF377723895EFA8DE72D5 +:104EB000C68630768B185B24DEE0E7D486603DEC56 +:104EC00092F048F8B579544F54BCA93D1A77373E53 +:104ED00005BE2F17AF91F373313CA7391D84974856 +:104EE0003C87C33AC7F1BE3058E663DFC5303E0A9F +:104EF000C413F609E31BA3422568FFE0C34A00710F +:104F00007DB06CCE8601187F5C7163FEE7E5039986 +:104F10001DC6FD8ACEF6280938111EA76308B6C73C +:104F2000EB2B657FFC4A013813CA2C61B8E06FA2F5 +:104F300027DA34AEE4CA24533CD57B85A97C8F9A0A +:104F40001C537E86AF8F29BFE78252533CAB71B8AA +:104F5000A97CAF15234D7197FF3F4CE573D74F36B2 +:104F6000C5F35BAE3395EFBD6DB629BF28B0C894CD +:104F7000DF77E77253BC5FEB7F9ACAF7DFB3DA944F +:104F80003F207897297F60FBBDA6F8E08E9F99CAE5 +:104F90000F3DB4C3943FACF35153FE88134F9AE2D4 +:104FA0005776FDDE54FEEAD0F3A67805FBB3A9FCE4 +:104FB00028FBDF4CF1318EB74DE5AF493F6ACA1F80 +:104FC000E73C65CA97F33FBEF0AC291DB894F98160 +:104FD0001E16F12456E5FEC6D48EC6BC807C06544F +:104FE000DB48A19DB55018CD5A298C05B6C5B0AA8D +:104FF000C4F73327D2EB03FE3B90B85E19F665B6D3 +:105000000F48F360F994041FD1B58721DD4EC2FF2C +:105010003A21B4C7FA55E43F3BF3479532161F5285 +:10502000597020D06148A1D0118A61C164A0C350D9 +:10503000148549A1644A4F0E25529812EA49E9A9FC +:10504000A10C0AD342B914F608B9284C0FF5A530C3 +:10505000235444E115A18154AF6768008599A111DB +:10506000949E151A4661766814A5F70A5550E80C07 +:105070008DA7D0151A47614E680A95CB0D555398E8 +:1050800017AAA5F4FCD00C0A0B427328EC1D9A4514 +:105090006161E8460A8B420B29EC13BA89EAF50DE7 +:1050A0002DA3B038743BA5F70BFD88C29250338511 +:1050B000FD43AB287487EEA67203427752581ADA82 +:1050C0004CE903439B281C14FA39A50F0EFD94C22A +:1050D00021A187281C1A7A90C2B2D063140E0BFD4E +:1050E0008AC2E1A1A7A8DE88D02E0ACB437FA0F414 +:1050F0002B43CF507855683FA55F1D6AA3D013FAA4 +:1051000033A557845EA27064E86F943E2AF42A8522 +:10511000A3436F53FA98D09B148E0D1DA5F09AD01F +:105120007B1456864E51382EF42185FF113A4BF5EB +:10513000C6873EA17042E81B4AAF0A7D45E177F879 +:10514000BB1A68A35C3FDD2D8F73F0DF6EF967F942 +:105150000E42169B04830A978F0CA5DCDC14134FB8 +:105160007271E24A2E17EF8FF9F800C9C96136272C +:10517000D749DB881EEB04DDAFC57F32186B1BF609 +:10518000416627E8A73B2A8E1EBE09F4937F998DBE +:10519000FD82178990BBDFC676C6F20C07A4CF1438 +:1051A000747DB06C7F2A3005BBA3B473B117DAB934 +:1051B000C7D55987A1CDA5903EFDA7D083BACB42D4 +:1051C000E19C122EFFEB96E527F8502FA65CDAF84B +:1051D000463BB97E96E59FC9E7EDB0D8AE6C6FBF90 +:1051E0004B6FE752CB7D19155FC2407EACB0F3F038 +:1051F000B6E8F81D187E19951D403DFDA1D3D7D303 +:1052000005F0F84732C2BBFF485CA099F0DCD89F9C +:10521000E0B9F476F2FE4DEDF4BB947698E6D1AAAF +:1052200060FE6AC5FC1DD6BD35B3A07C6796C5BDC2 +:105230001A926AFDF327A01E1FA3D6F1F44CCD4DA0 +:10524000B6845A47726D36B669C09F6DB1FE7EA7AF +:1052500041BED682DCAC003D5F7B33D81325E7E648 +:10526000777A18D94DEB162B013F96CBB450B95A2B +:10527000A6BDDF29E530A4AF023AC471BCBD0AE87F +:10528000D915EECFB7F89A0F71BC3EB681EC0E1F60 +:10529000D633D8172B0EAF5A73C0D0DF44575C0AF1 +:1052A000F2131BCA867EA786E9BA56F4B56EB1EA38 +:1052B0000E023C675F53DD18DF9F6A650AC43B97A7 +:1052C000D8A85FB63E95F8E4EDD4DF6539815EBFBE +:1052D0006CF2AF39A033360BE4B607F87AFF92DBF5 +:1052E000D2912FD6ADDDA5B338C4E3328661989E46 +:1052F0000244B79D59CCEAEC87F85DA611DD17B2E0 +:105300004CB217C53CE816676B10C6CBB2EDEE5F2A +:10531000405CB5301FDA99B29D0EE49FC1E1F05DAB +:105320000BC7A37FA912F805CCC93A6B6361523150 +:10533000B6C3EBB55B391D1CDDE4DAB11AF22B35CF +:1053400066D74A4DF65F34E20B141EB318ECC5481D +:10535000FB70A52B51D8658DCC0BE33AAAB09A56B9 +:10536000210714097F2ED195B51AF26D29766E6743 +:10537000B654DF88F304702E90E555E8A716E907C8 +:10538000E6A176658CA708F257B9B87C003AF177A8 +:105390001AF4B0AE70F8D912189F8BE87731C66D49 +:1053A0001B6C3977B90CFD6339909BEF89768E2A97 +:1053B000022FAB443D8DB7E3DB9018C07AB6148D55 +:1053C000E0D3B33CD77B012E9B1FE02CC1725DB7AD +:1053D00020BDCFF127B2BB20EA5BA38C45B966DBC9 +:1053E000B06A19E603FE9806A2C3A631CD0A789CDE +:1053F000C51C63D311BE0D8A5BC8CBF0F8009EDAE2 +:105400000D0A8DEF97420E1E5BAB105C9DF72801D5 +:10541000E6227AA0FE99E63DF486A15F39DFB5A2C7 +:10542000DFDA96A76F5388CE9907F1582BFABF4160 +:10543000658D188FC41BF21FE2F7AF021FC7FE2B4A +:105440008EC67F6EBF6E6B75BF30DCDDF3BF32CEB4 +:105450001355121EF75A05E403E2F31E1B8DD326E3 +:10546000E0917838EC4AA27E3A575D933DFB3CF0E0 +:10547000206D33039D44D2976E11F39CCD68BE24FA +:10548000DD4BBAF9B3A077199E14F864D88EEC47B7 +:10549000C574A11F049D5E63CC8776AFC95CC690BE +:1054A000EF886F8633F647D7E75E3FB43F5FD6732A +:1054B0003616A29C94FDC3CF437C21E8D5166BF72A +:1054C00014C1B8DF10788DC44BA41EF97D379CCC75 +:1054D000671D22E4AD05D39D945EBBC1467896F36B +:1054E000FB3EF215AD133DD9342F0E8137414FF7F6 +:1054F0008BF6EE17F5919C1494F39B6CC4FF723EEF +:1055000022F12BE5FE115CB742FBF76312C8B3FD35 +:10551000090D0ACED757623C69485F90DF66BB41F0 +:105520009965903B09395C6FA78AFCC87126E4F045 +:10553000FA1E91CFBE85F421B44EA6F996E5A24598 +:105540003B323E36CEE20D40F9F1F7031D9FA7DD59 +:105550005B7379BBE337B67EF657A48F5A2BC9C568 +:10556000FB5671F9136E97975B9D2BF05D7769FA87 +:10557000FDC80A350AF5594BE8E463BF81F693BCD0 +:105580005692FF49ACF3B1DFC0BCB21A46FDED4FF5 +:105590003843F1F8A939A52AC45B3CA584B72F4448 +:1055A000BFB2DDAD6596CA402C969F943117C6B345 +:1055B000A5BA5E996B80334D4BF00408BF93321649 +:1055C00088FC0590BF6FF2F1BEA857F6D73AF6EA0D +:1055D00000877D2A73E094273B1995B73B591496B1 +:1055E000C77E1718DA4B9ECAF3DBA68CCD9807F559 +:1055F0005AA6AE1E86F5B6545BA3F200DEAD13FCD0 +:105600006508AF2C0FF9410DF5EE68A02C484FCA84 +:105610002C5D89A231496B6A77217ECB993BDF896A +:10562000F0F5527C867E0AC43C782AA13FD4734EA2 +:10563000EEFF90F90FE4F2797D3DD74AF87F3EA660 +:10564000D7CA7C94D3532D0E54B7C4F7D87EA595F2 +:10565000F87BB3D23910F96994EA28C730278FD77D +:1056600097FA5017B254B76FE8C0F5921EE6633B45 +:10567000F93F84BEA272C0175BA4BCCFE0F2C35056 +:105680005ED23FE90D7DB43507FD2ED7E674F325D4 +:10569000E90F6A07E0D06B18F1E326D9DE0C467CEF +:1056A000C5349F827A4DCA7FBDC64BFA62ABE027F4 +:1056B00060EF0CE457898F1B45FB5B337D33D00EC5 +:1056C000669A43C1FCCD8A4341FD3C5BE4270A79DD +:1056D0000E8CAE907D26CA49BDBDFE4A1640BDBDAA +:1056E000BE5B2E7078AD62DCA0AF1896B74EB59059 +:1056F0003EB3967B49DF5A47FB976178AFD0D37AA8 +:10570000BA6692C7721C4D392EC2FB7D33AC34DEB3 +:105710004D198E00F763F93204BE2CA42F712902B3 +:10572000F8D994E598C1F54623437C6C9670698C52 +:10573000F0436834CC8B5E69E57680A793E4AE5E77 +:10574000E6277DA2D7FCEE36F4376D0E8FCB63C50E +:1057500071295C3E5A2758496FAE1578B28EFE1DEE +:10576000C9C7C87148BDD23D7F11F37E8EFC8F88BA +:105770006FACB666607FF7C1BC90FD029ABCDB6F70 +:10578000E644FBB3F79B73012F5BB22CCCE6A4FC81 +:105790005836244C9F6C4DFA81BC3432F5A8FCBAC3 +:1057A000A9CFCFA4792BB33A51CFEADEB1E40FBB36 +:1057B0004FE98CCB41395D6D71A09E882BE37EBE95 +:1057C000B841CB0A30BC1BEC43B4976FC8CDA1F9EC +:1057D000D8386DB53D07FA8D1D602179B4C5FB7EC3 +:1057E0001CF2E373421F0E3FD1312A01F293273896 +:1057F0004A91BF64FAB0634115D3932A79FA88AA13 +:1058000016587463DC4FF8DF58F1BF5543018EF82A +:10581000628DFC64F729C1F52AC2358ED17A2F69D1 +:1058200074D0310AEA2766F27E3DA3839543317E28 +:10583000B3CA14281FFB514A05FAF54628891C2EC5 +:10584000FCE70AC2841F7D2ACDBA88FB6FA85E9050 +:1058500089F41DB4A30E1BF3D09C6A0DF44DACC2A9 +:10586000F35FCDB9AF1AF56E226BA943BA637936EF +:1058700007F22DE2D19E44F3C86A209C09746A8520 +:10588000F0E59C1CA283388D052DA0DF2C3175E935 +:10589000888FAA645F23D26325926029E5DB93A9F0 +:1058A0003C9757B05E7163B90DC25F0BFD7B8D7283 +:1058B0006B8C906BC5228CF4ABC63D5F9D81ED6F08 +:1058C000AD30EB9BD8415693BF28BAD81CB7E799A7 +:1058D000E37AA6395E2DFADB9FF01D43F812841C93 +:1058E000B84FF083ECE7740EB77764F89CD5793342 +:1058F000E2EBB9E838E65730CEE584FF634DD8C710 +:10590000EEF2290639B452C863D4F338FF52BF1FF0 +:105910005971F41ED4772D5EA705E9449697FA2CA9 +:1059200045C013A9371D020E89F7C8FC58A17F9BFB +:105930009B56B0A3F9E17455B437F8355F735C0A30 +:10594000E2C3596AD44B16818FB9051E4B6EAA412A +:105950002EEE8F525C71C6F679FF8E589FC7837208 +:10596000A36E32D93117D6F3ABA9BCB47B22F3179F +:105970008BF63C17B15B5CA2DCA5DA2D775EA2DD6D +:10598000E212F8FAC965DA2DA3D4CEB32EE49B5EF9 +:1059900016E2DB759939CA2C031C5B05BC835147A1 +:1059A0000C46B5A2F9D1AFAFC56AE4DF57A75AFCE0 +:1059B000B8DE56CBADEFE1FA59ADB9E313F24B3A8D +:1059C000FC7EECA587E21B928BF0782D1AF24394B3 +:1059D00010776AAC87E4C885F8E41C7AF8817C0209 +:1059E0007C47767AF5430D9BFCC5FFD23826213DD6 +:1059F000B109308EB473C721E551F1430B36A13C98 +:105A000092FE8D0BE13FD2AF302337D6EC57B8482A +:105A10007DE9377817E705E1728FB0201E93C598AE +:105A20000F573DEF40BFC359B7469B151BD0FE87AC +:105A3000F886152AF949804CA3BC067EB08754E647 +:105A4000490619897E08089FC871D27CDB9D2D24E8 +:105A500057ACE95CEEEF4FD848A1BDDBBEEF65A2C5 +:105A60001749DF8917E27B61DFB97239DC95365F50 +:105A70000DD90175A526FED372CC7C22E955EAA783 +:105A80003F9C7EFFEEFE309EB41AAE9F4E0B7865B3 +:105A9000F9B41A7739F9CDBF056C1AF032B60AF8A5 +:105AA000ED3C7049BB3F5AD0B9842BB25C4F313EBC +:105AB00009BF6C3F5EB63FECFCED4BFE94F58E8467 +:105AC000867F867C178FBC07A0C7D734B653BC929D +:105AD000913ED5CBB87D3CAAD7727B7431E7CB45DC +:105AE00028F7726C545FF2E355EAF9E5C6406107A6 +:105AF00083FDFCAD4AF63373A09CB4316F05AE0B49 +:105B00009896407204ECE474849FFCB74ED2874EA2 +:105B10005CAF9588FA5B84DD17B6239DE4FF31D82E +:105B20004756A3DFA7DB5E6366FB686F6EA2B09388 +:105B3000BD0CEDD3483B54DA5DD20E95F673B79D9C +:105B40002CEC51FCE943C276AB75022F27E15B37A1 +:105B50000CEC5CE86F9DC2A2F2509F4DB3707F8A3F +:105B6000E6A1754D7C799AFB2E67B85D6B19B7BFBE +:105B7000FFDDF6E0BD0AD8BD30D79B045D26327745 +:105B800086B00B3390EF8CEB37E3FA0EF506DABDF7 +:105B9000A90286B6DA46E6443FC854A7827A2A5953 +:105BA000AC9B5ABECD6DBB1AD7655327E7E178F79A +:105BB000215FA07D36D5A2607987C751CEE52BEF56 +:105BC0006FDFD7D119F5063AD937F2F840B447D785 +:105BD0008FB33A1427CD07D7FF5F45D33A6554EE0C +:105BE000900CA7818E33F238DD6FADF179D08FB58F +:105BF000DE95A6CC36B45790C7E97B63753DD9C115 +:105C0000CFC734919CE85EAFADE17EC5483AB58917 +:105C10007A36818F2DD32C51765A9F8E54709D6A7F +:105C2000CB8B2264B468090AF9CF3C729DEA9E814D +:105C3000EBCF5965B43D8172C83A1FE5545E34B567 +:105C400017EF90EB212EF73656A43D7897C1EF9BC6 +:105C500098C7F9BD45E94AC779B94F977E48EFB86B +:105C60007C287F5F6A5E29D2C9C62B0B7E8A78D2D8 +:105C70007FDC8FEC0C59EF0697CF9107E1BB23A790 +:105C80001F9A8B249253908DE3DE24E4F13B0EA601 +:105C9000A13FE51D10BEAB146CDFEBCD47BEB9EAEA +:105CA0008BDFCE7552FDF4BCC1A6FAD7233DCBFAEB +:105CB000252E6F4FCCDF5C359DECD3AD35EE8CD906 +:105CC000D09ED56925D284994A9F0D706D1EC30858 +:105CD0004E39AE2E219F0AF2783B1BABEF4847B8F6 +:105CE0003ECD758AF1025D92DF9AAF1337BBEEA00D +:105CF00076D24673B923ED3A58F77B70DE36CE285C +:105D0000A0F308389FE8A7E81272ECD35C2E7FB6A8 +:105D10007A3E4D9FC7907EDCD4AEEC47D27F224ABC +:105D2000750813707E0DF4BD95C99F736F17D2610E +:105D30009663008E6387D00F89359CCEDB6C093467 +:105D40007F5BC67803AA8BF3C93C82EF0BC24B5B27 +:105D5000AD8FE83D4DF047D204416F35D640BECB04 +:105D6000C82723F3894F800F7CC427A5544FC29BBB +:105D70003CA1F329F4CBB48DB7929FE12A958FE72C +:105D800052EDA87789D318BB36CF3B19E70DE44D08 +:105D900009ADC3572653FD3A4B5B7E23F457B73A00 +:105DA000486164FD4AB01D3A683DEC4E433A678D48 +:105DB000C3499FDF2464CAD90D831370FDE58BE7C7 +:105DC000E514CD3714E395FF9C33D48A3AE4AD381B +:105DD0008676FBCC5C76C36448BF41E1F0CC6C1E98 +:105DE0005789EBDD45826E0F36C104F786755393F4 +:105DF0009D798039FFD6E4A0F8EB4DE9147FA3C963 +:105E000049E19B4D85141EB3727D3B3399DDE0E57E +:105E1000FE052BCA9346210F1AF3A4FFE3E674D0C4 +:105E20002400CFDF065B1C3865C3268FC962AC53E4 +:105E3000E7727E9247455DD32D5F6BA6C690112118 +:105E4000E3B3BC234CF9AC7060384EFE093EAFB3EF +:105E5000D727EE40BFCB8C09C9A6F2D3D7F734C5FC +:105E6000D7E5F179ADAECC35A55F57D7D7149F15DF +:105E700002C53110C9B08CF6716E16FB938C95710A +:105E8000FC3B78D9CF1A87F6B80DFAFFEC659DF286 +:105E900023E7E19895CB19FFFFAA629FC047F3F271 +:105EA000F9A12C86F056FE53A57D20F628F7AFCE3B +:105EB000D9A6303F0C8175F9AFC77A373F68736355 +:105EC000B9B9DB54E64378D06883FE4EBE9ABFE38F +:105ED0002E9A57FF0358AE0BCAED80AC133AF33B32 +:105EE0008034E7748A7694D29E88FF1389CC930815 +:105EF000A6D48751870B6E03383FAA6AA9B720AF93 +:105F0000AA2FA75AA0FE474FAA0CF968E1B2D7877B +:105F10003800AF8B5E6CFDDF3268EF588BCA1CD047 +:105F2000DFA99DB607B9DFC6D303F570789C81124F +:105F3000A44B4FB6F7D748DF27EB032574DE666521 +:105F40002AD1F7B9F880F1A33E41BA84F67CB7C6EE +:105F5000D9F1FCC41CDD9D3680E888AFA7FC6C50ED +:105F6000062B83F21BF4CA00F97F3C13719CC75ABD +:105F7000922DFC5CD3934457B335A7D5D8DFEC0DF5 +:105F80002AE901980CBEEFB049F581ED0CBF16DE91 +:105F9000EE7AC5C77A9C3B8F37E13E20B47F5356DB +:105FA0007400517C3DF6711EFEFE1878C7670BC762 +:105FB000173DAB925DC706393796E3BEF8C3A3061B +:105FC000A3BC623EDEFE6749926ED670F9E8612C92 +:105FD0001DE7FFE1B800AEAF4F5B9E3CA2C13C0C99 +:105FE000D27C87107F0B26FA1F508025CEEC3DFA1D +:105FF000931150EEE413BA9BD89F79DECAE3CA9F8F +:10600000F86CB626F4D80ABE6FC8B4C0233F433B31 +:10601000E7AD1E26B91F9627AB383FCAF20086A50A +:106020000C83609A0278F439D9584731EE1FB48A4C +:10603000F352012AEF4420017F8EC51002DE8E0E3E +:106040008EBB8BF587F98AD8373C2AF8B94BC81331 +:1060500029F706E4F3F81CB9FFB28FEB7B98E0D781 +:10606000D0AFB58071FC34887DD6058D7C5F58C972 +:10607000E7FE9886C66B3E90F61DCECF8D408738E2 +:10608000FFF58EC49B3B20BE7867943B00F5AF467E +:10609000A732EDAF3007E27DA1A8F2A7C29BACD832 +:1060A000EFA2DF2A2C19FB0DE8C7D01EB30346511F +:1060B0007E9C04B62D4BC2F6146A7F718B12C0F31E +:1060C00064F3595710EDE3258F2BEE206F8ACEDD58 +:1060D000CD13ED2ED2EEA173738B0A15DA57663B02 +:1060E000A15D835C5AD2CAFB91F2A48169C78CFB83 +:1060F00025F384DF791EEBB60FF9B9BB169DF65573 +:10610000ECCCBE0ADBF1C6C4115C8B5AF8FE7418E5 +:106110007E957D0738ADF7055E9C487850DC0176AA +:106120002E1CF3997774228E03F283CE73E18A1CBE +:10613000D7A5C259EF6E237A8984D7300F4EE33C3E +:10614000CC671D77205DD5FB391DD4EF053C43FBA3 +:106150007F6FD4993581E8A1236FC8B9F400F04F5F +:1061600044F9387F8BCA82AE307D48BA58B82B606C +:10617000457D7C8AB5C4C7021F2DDEB66BFA30A8F8 +:106180003F7FFBAB56D4E77549C17C0B181B29FE3A +:10619000C0BD9559617A5D1830E3E1C69DE6F8BF50 +:1061A0000B4F4C9C93A47A809F790FABB42E319403 +:1061B00033ED9F2DF0333A27B0E035D58D3EA20563 +:1061C000A0DF924B2F1F5E89BFFF6FB823FD150D17 +:1061D000F97129C7F13CA59BB9D15FF1392B4EB8B4 +:1061E000163385BD73217F45F7B991087D7B58072C +:1061F000FB02E6F133CD939044723D526E0FED8178 +:10620000FA47CAEB7AA13F65FBF3506F42FCF8B640 +:10621000A7E2D12EFCFB96A7D2309C8F7AA938AC8E +:10622000976E9D13CC423D7EEBD3516E24513621A7 +:10623000F8FA8F20FED12E959D4F9EBE9FE5BB277D +:106240001FE115FA7589FA60B603F5A990AF17B387 +:106250000B7FE83867E3380786DB9D23C6F9FE7AB3 +:106260003EBEA31BF878E79E334EB02B709C0FD92F +:10627000DC28DA4F440549FF9F8071361BEC076923 +:106280002FC8F17DCE5A1E0842FE92E56F1CD180C8 +:106290001E16167494203FD66DB2917DB0F0B77182 +:1062A000B4EF7F52A9E841F6F181603CE26FD193EF +:1062B0001C7F6138BAED85DDF9467BE112F1B654F9 +:1062C0009C9B5CBAF78F87D07E553C5015E05D6A89 +:1062D0008F0D12BDEF319F73539CDC54B731B7DD86 +:1062E0008EF393C99CFC9C52E4F95FCD731CE6A22B +:1062F0001EEB01FC5FE47F72FD72E283AE02D4B755 +:106300000DD141BD07DA59BB14F70EE4B79B2BE260 +:10631000D175A88BF39B7FCDE7F6AEE2F1B015A562 +:1063200074FE924543BFAFA33C4C45381CE4CA629F +:10633000DBA1FFB830DC91E9784EDB8E7A32D67281 +:10634000DE75B156C0F5E912D54276F7622BB7BFBC +:10635000CF087FCCFB028EF7F3B91D7E229F9F3BB7 +:1063600038838E4968F7CC185B00D79D1D567E6E2A +:10637000F555DDB3EDBF60DED614F83EC0F9F05A36 +:10638000626722BFAF8E29D1517EAE49ACEF85E165 +:10639000F5AC43C7799D5856EDC4F5F59134BB5B18 +:1063A00025B9051332247CCEEB153D763DB67B0432 +:1063B0007107E3AA15E7A08F40FF787EFC48863579 +:1063C000D00CF5FCCFDAC89E5817CDCFA9B29404F3 +:1063D000F29F5E27E4D4CCD1B0A2079AA91DBDCE0E +:1063E0008B21B4E76780AF3A7BD7DA01D0CF2A0B95 +:1063F000D7D7AB92183F7FB6A67330E2AF3F5BE3CF +:10640000C07984D1EFFE2EF9FBE84963C7259DC012 +:10641000B816E379B6E18C135A19E1D7145F6CE52D +:10642000F95714E853B664421CD71E480FE3D4C092 +:106430000E179EBFB5D07C4E827691DE1832CD907D +:10644000F0B9FBC9F0B71CC63959637E4B1285EB16 +:10645000F1C8E5B432164C80F1055F620AC2437B95 +:106460002500DFB5414BB037E06D92166C43FC1D43 +:1064700052D95AB44B273397BE1CE663F1EA4B83DB +:1064800077508163CA9672885BF83D82AE1F2901FE +:106490005C275CAFB1032AC0D390E4F453FA324EC8 +:1064A000D790BE3EBE14CB2B4457B52024909E718E +:1064B0007E894EB1F090F03C41797B34A49716B8B8 +:1064C000F8791301EF369F250DFD024BC4FAF07ADF +:1064D0003B5B1387F535773CEEE30E00308DF3D44C +:1064E0006095EBC856EB64E0CF1B81BF5D8097AB36 +:1064F00004BDDF28F9FB71337FFB0A9C9CEFD0BE03 +:10650000047CD68AF042FC3153B437B380FB13C607 +:106510008938F68BF473A3902B17EA6F898D0509E0 +:106520005FCFDA68DE65BF9364FF05DC6E95704867 +:106530003AAF678D569413F542FF5A6032517F2E61 +:106540006879C88A4858B0DD60B7D1BF2D569453DA +:106550008B1E8E4C37E86FD524C7E81CAF62ED9ACE +:106560008BF0295745B9912F6AADADE4575050BE15 +:106570001586E55B643DBD85AF2BF50DDC2E93FEE6 +:10658000391BD89D28E7676576F543B96063CEB1BE +:106590008A8B75DBEFF5820E6C686FC07CD5A37DAE +:1065A00086FB23689F21FEB671F835616FCF693194 +:1065B000DB29B3D6478E8FDB2B7A77BBDA31A3BDCD +:1065C00021CF6BBC6BEDEA877AC3E07F25BBE55D2D +:1065D0000B1F873F8D9FD360293C5F13F6A9E4FF13 +:1065E0008602DD741F6412F326040DF2D63B1A688E +:1065F000AF14FD134A00E96192A7A29D87AB827494 +:106600008F05ECB29E49FCDC7D3995E3F753BC95D0 +:106610008A3F86EEB9E8278DE33A88FF1976AEBD4A +:10662000B4B540D84B11FB3BAC3CF9BCFA30D25E60 +:10663000F28F6485E43F42F9CCFDC864572CEF3EED +:106640004F1D5B88F2BA4E8976E3FA419EEF3D2CEE +:10665000C24FC1FE467AA97B278ED6BD91E77ECF79 +:1066600054C4F92D10CE4CB87522CE675DBC55C30D +:10667000509E073E2CC22F2D9DD4FF0DACF314EE7F +:10668000235D93D21187E897E7AFEFA818B80D6C98 +:1066900042162CF04DB167D17EA8D8D79FF7370F9F +:1066A000C03F15F745295E3FC503EBCB332F745D23 +:1066B0006F07D5F5C623F553705FFFCCD6AE073014 +:1066C0007EE691461EBFA72B3B8AE2B74DD100AFB5 +:1066D000675689F6FCB74DC1F6CEFC94C75F807C47 +:1066E000DCD7AB1BC94557DD7085F4CF01A197A559 +:1066F000DFADCEF23C0F47B2A065D0C5CB7D55E0F3 +:106700003D80F69F1A778CCE4D28451E8A3F9FE725 +:10671000EB28807051B5E2B7C238D86B8102A1D79F +:1067200069BDBE4EF8E3E57C1EC8E7724886EFF50A +:1067300086760787F106EDBDF543DA6B88684FDA98 +:1067400039F3841C80F68FFF90F6A55C91ED9517C8 +:106750009E03FFA73FA4FDDD11ED49FB578EA31F4C +:10676000F22CD0DD903ECC048F4C5FAB0453AF4590 +:10677000FFDB4B2AED6BAD4D3DAEE1BE24F3F27D68 +:10678000D19BA2389FA4F6E676D3DAFF7227E03ACF +:10679000C0FF1795F6BDD7AEE2E7D64F3D3174087E +:1067A0009298B4534FB5BD6975C238968AFDD1062B +:1067B000B13FBA74779B752CB4DF00E128837F6406 +:1067C00071F739AC4E6D725C188ED4DE16E1275D20 +:1067D000F5BDE708727B4B7F2A1F778918DF277D7D +:1067E0003D99BD0DE396E9CDBAF99C870C178876E3 +:1067F000BE2E6042FEF1F6FA2B7CFEEAA2B9BE9CE8 +:106800003324CEEEEC1F3E4F51BFDD45FB1C1FE68F +:106810008DECD37B70B83F592FECA7EE3ABF9F7A2F +:106820002FF753CBFEDC02CEBAA48E9BC118600BAF +:106830007EF9DF9B512E8CBF5FCA05101176DC6F8D +:1068400095F1DD534697737F29C6C7FFF289CDC8FE +:10685000D7EDD17CDD347368BF68944B9DAE188B47 +:1068600003E4D5A4BC590B102F33875E3916D32B04 +:106870006C7105B3F8BE0FD1DFA43CEF68CCC7F252 +:10688000E8CFF259399DF8FEA4BAFD304E5F498C2D +:106890000FFD88ED16361AF5B8C4DFC8DE9C2E173A +:1068A000F4E6F893FDCB7E1973905FEAD8EA0CDA30 +:1068B000B7B836AF627EEFC1E17EAFCDF34DC5B85C +:1068C000EC17865982E917EA3F72FEAA05BDCC177C +:1068D000FD7BCB81FE0CFA74F2E818537CEA8464E9 +:1068E000E631FAC3A7F634C56BEA724DE5AF9BDB20 +:1068F000D7945F65EB1864B41FE4BC5DEA7A6D2C35 +:10690000F07D02E0A5A38DF5DB8D7CE88AA37DD721 +:106910001BD78F23FF7A42A896C2C52D1007FE59B8 +:10692000129A42F1A5A1188AB747778C457DDEFE01 +:10693000BB445A9F1E5483053FC7766C71C4CF5524 +:106940003D67AE46FDD31EED2FBE09E0ACFACD3556 +:106950009538DF4B772BE407AE5259BB9284FC1974 +:1069600045ED55A97F1DB40CD2C78FE27AAD0A75EB +:106970002EE4370BBFE685F866A3E01BBD93C33D4D +:1069800026544DEDC9FCADBD734CE70CF4D48735EE +:10699000B27FC578F44E85C2FF08F5A5B06177B522 +:1069A00086E771FF54F8500AEA0F281F4B7A5FCA36 +:1069B00025C9378D431358EC85F16C13F2A756DCCB +:1069C0001379A8C8F318D2F5C4959D9A1DF71562DE +:1069D000AD0E5C474E2C1B905E6F68A7B96D0673B9 +:1069E000D23D0A66457D590BA1515EF92E704E636A +:1069F00097A07F29AFA41C678EFB695D70BDF0571F +:106A000048FA78A0B7F9BC4687C2F5B0FFB77CBF9B +:106A1000636F91EF00C2DB51C16A9E24F9D1918D61 +:106A2000EB837F17FC30BF7685D6639D742F7A6227 +:106A30009993CE9BBED43D0E4EA7171BC7EFC4380B +:106A40000EAA6C05D2C7C1ABAFEEF0E0BEE0ED031D +:106A500007A25C648EAE6F914E1BF68DC845FFF4A5 +:106A60009BBDADD46E15EEC10C0AAF171AF6C5D09A +:106A70007E4FC33EDB0E05CA35C47715A0BCED5F63 +:106A8000EC7B13F170F0B9AF8EDC0EE53DB17174A3 +:106A9000FEB1615FD4018C5FA5D2F158B03B3C6F71 +:106AA00061B90BC179A9FC184967BEF59CFF7C82CE +:106AB0000F6709BA9D2DF87096067A11E0BEE16560 +:106AC00095A17C9ABD52E9B71BFD14CE383ACF2D63 +:106AD000F950F29B8E743910E993D3E5E250A2E0AD +:106AE0006F976897F34115AE5BA19DAABE89B48EDE +:106AF0005F1A4AA672925F259F868A7C518580FF25 +:106B0000AA66E06FBC97B53A6310F2CBC5E9E42BF7 +:106B10000DEF43E9E58A8E746283709481BFBDE115 +:106B2000F3D163D370FF668DCB62BC1F135F68D651 +:106B3000CF17A3936F049DCC8E0DE6A31DA93746F6 +:106B4000B9F15C4C5DAA93E4D8F23B21022858AE1F +:106B50007B47A15E5DFE5385FC8DA86FD1DE1E7262 +:106B6000A891FCD6B2FF19A112E6043C4D09E551EB +:106B7000F8619E2F13F1302B345DE0B1E4BCFB943F +:106B80009F35AE233FDF67019B9B919FC6EC4F1C57 +:106B9000EC71D3BEA5FEB2CE1E74A21FD0A7227F79 +:106BA0009CC8628ECD0AF727A27F51FA03E5FEA3A7 +:106BB000F40BDA522CA6FDD2CFB5966CB4FFCFF110 +:106BC0000F5670BD76FA619DF4DAE2B6BF0EB1E001 +:106BD000BE8BCB437E424FB66F4821DA879303BF0B +:106BE000D6217EE33D4FC5A3FF5EE2B3550BE6E33E +:106BF000FAA515F088FECAD60D2ADD7F805F4CB558 +:106C0000F1BEA1B02B5E62DC1E9174BE28944BF8DD +:106C100091FA46CAEFA79BD269912BE5F8C5F4908B +:106C2000A4EF251AD7634B80EE71DE22F928AC7FE2 +:106C30000610BF30E017E48FB0FEE1FC11D63F82B2 +:106C4000FE137AD17A23529E4BFD34E257B9BB7FB3 +:106C50000FED2C7A6CA617E7E9EABE200F001F8B18 +:106C60009FE47C10C9EF525F4B7C48FCFC49C46731 +:106C700015791A918E2ECE3F5164E7DAFCD58CE45B +:106C80002C844639AB47D8B532FD96CBE49B398589 +:106C9000E6F58484B3C3CAED2B09FF9F19B73F649F +:106CA0003F7B8B266F281CCCF506F6BFA990EBE93D +:106CB0007FD7B82EA43F36758FEFD2F4C78F23C687 +:106CC00027C721C7F5B218EFA5EA97470AADE29C9E +:106CD000B459BF40B9E37F807A679E2D72A01C53E0 +:106CE00095AEE374FEFDD92827E2E1E0735154DE4E +:106CF000634F207FFDA8E73E38FB7327AE23A63CF9 +:106D0000827CE8D96BD398C1DE93704938FF22E0CA +:106D1000063DF458A1613C32FD87EA25C917917CF4 +:106D20001BC9AF91FC39FE6EB013719C4F2B74AE32 +:106D3000206C1732D253ED3959B49F26F9DB602706 +:106D4000923DC20A153A1774AEFDF5C62027D43F0E +:106D50003B286E00FA47F6ABAD9B872B613E1EF9D0 +:106D6000D8374FBDC5CED577638B7C47485F09FECA +:106D7000957C7A71BA7C46277DB55821BBC606A1A1 +:106D8000515FF92EC06F472F93DF5E15F47810E145 +:106D9000437B2CC14AF6D8C5E8EEF37F3FDD7D6E1C +:106DA000A4BB0BD9DF5F17723F2DD0DDD7C4EFFF37 +:106DB000229D7DCFFC929E94F437FECF9C6E582E80 +:106DC0005FAF001D11FCEDD62C92D3B5424E8FFF64 +:106DD0008EDF8FF589F5BFA463571F5F769161FE43 +:106DE000717D82EB8E4BB56B6B531A199E5BF34131 +:106DF00068944B36798F2062FE738B2ECF2E4F2CEA +:106E0000BA3C7B7660D165DBB357E1F82F66CF32B1 +:106E10000FB75BC2F3619B82747336C8CFA75F68FC +:106E20003ED56D1CDFDD780B6AD22E4846BB00E8EC +:106E3000E4EAA21F6027578D6AFDCC0E26EBCCA298 +:106E4000C7A6A2BF713A9E95213FC4E35B3C792857 +:106E50006F98DC6F213F05F111C59F786D34AE2F1F +:106E600037B3F07E0CE48F294FE8F66BE0124896BA +:106E7000AF2B7AF4B50D04373F9FC47C9D1ADF9F7A +:106E800014F141108F33C4CB22E2DB79F978AD9352 +:106E900019CFED20DD29A59C4E4CEF32B0AEB17874 +:106EA0001E64E26EC581FE89EBCACF58D12F5335DF +:106EB000AAF3C59E30DEC6A2DD53638B201DE522FA +:106EC000C0EB2FDABBC5AF89FA69E4C7A29FAD5505 +:106ED000F1A878EEA44C09E015BF483CFA8BCCEB46 +:106EE0002BFC69E6FA0CCF815D4E7D9C47AA9F433F +:106EF000F583B6CBE8FFDA727E6E34B2DC4F041F46 +:106F0000C87B39D43EE06E4A2BF71F4496BF4F949E +:106F1000EFB05896E021D6078A3AB6D8AF84F96523 +:106F20009C3E024507A7FA8B39B89E88F17E1FBCAC +:106F30006B8ACCF604FE9CE6FAC1EFC3D75DE7E0AE +:106F40004BD0C70233BD2468DE0367018E8414C5AD +:106F500081F6F8526FD4065C77548D92F4FDD654C6 +:106F60004F268C2F8A99FC7061FA7E7B2AD2F752C9 +:106F700026F3DFD9827ACA6B61A67B7A63F62ADDB3 +:106F8000F50B35BA7F46F57F5F74780BE207E68331 +:106F9000F229AE7D0FBDB746C4CB23F843D037F1FD +:106FA00027CA6BC04FFE79E4C6EB023F1F89FB0581 +:106FB0001D23B95DD991C3C3CF8BB8DDF88E9887F7 +:106FC000BF8BF21DD1063C6486E7197E415CFF1839 +:106FD000C64D789A9122C6EDFF7AEA0418574712F7 +:106FE000EBA7009D9CF9D5175BD664617DAF86FB4E +:106FF000209A3FB4E5E561505EE0E5F35F7DF59AE8 +:10700000A01B05F96C091100CCFB6EC54FE7D070D1 +:10701000DECF33AEB673F9C41F51DFA37F4FFD3F00 +:107020009E5BDF13519FE92997535FCCCB8488790E +:10703000AB8C98B7D111F13A190F98E497946BB3D0 +:10704000F76C5A9B46E7FF147A630DE4B35519C0F9 +:1070500058741F6D5AEC30A44FA7DE13647C7C1F5C +:10706000EBEB76A0DD6A945F44AFB6AD28AFA72006 +:107070007F53DC3ECD9380F4D2B8361DCF23F78901 +:10708000DA6A077EBA6ECD261DEF91A6F789D9AAD6 +:1070900041BB3306FDE6456C4F53E25E9FA07C0F7B +:1070A0007DB6448C637B44DC1F517ECB45E4F99A6A +:1070B00088FA2B23F23744C4B745C4D79BEBCF9A49 +:1070C000CBF74367C1FC21E22EC6277DFA48BBB04F +:1070D0007510EEB795F6B962EB5A30BDC737733A03 +:1070E0001FF4E815D38C742AF7696B53981FF58148 +:1070F0007E01F954D0E702745218A9BF64BE371D4F +:10710000D38F08FE60FE53D350CEECEF96439CDF46 +:10711000DA540ED7958F9E7A7D0DD5E7EB947BC51B +:10712000BE84BCFF82FB2ABBCE23FF9FEECBEDCA01 +:10713000FDDFF0F719FCBDACE4CFDA9FC0EF17AC70 +:10714000BBF35ABA5FD0CD6FBDAC2BF8FD83A6F46C +:107150007906FDB0BF57DAB7B84FB4BF077F5761A4 +:10716000FFED03BFC5FB0BFE06D59DCFE83EEC2926 +:107170007CC7E3EDD07087F13EACBE989F57D653E5 +:107180005AE3E619E0DBDF30B0DC6958F77E2EFC0D +:10719000EE6F67DEEA407DDDD6EBE68E0A84B787C8 +:1071A00046F0DABEAA7328C5786F93DFFBAAEFC357 +:1071B000E5981EF711DDC36D4EC18B73982EF6B99D +:1071C00032A7DBB19DE614FE9E841E37D361358C59 +:1071D000C793A271B85CCC6BB4C7DF12F3F84C1F35 +:1071E000F10E83EAA071031C0EF4C7DFF04DDDA1A0 +:1071F0000EE847CF1EE2C4730DD97D73F979608B19 +:10720000A31CFD4357A9EE41CCB09E9C6111EBC677 +:1072100088778A6CB8CF5F627A6784DE65E87EC75C +:1072200025DE2ADE4DF8FE7785D6F77151FF905F97 +:1072300022F6C7C3EFF9A8743F8CE43FDAD57A523F +:10724000F85D21C33B3CA3315D17F7BAF52CB6744A +:1072500032D159AB8E7CB7B58FDC97E3EDCAF757C7 +:107260006AC5FB3FDDEFE8F4B096EC81F9EF8CB531 +:10727000BA9D2C9C2EFBAF15FD5CE8BD1D09CF2FE0 +:10728000FAC87792DC87DE4841FF458C85CE9BB3F8 +:10729000F3BFAFD3990D2A3E36FC6ECB5A710EC6A2 +:1072A00016CBDF4790E99DAB47D0BD99B5D23FBF24 +:1072B000449CD316EF2674BF3794C2DF4DA885FADD +:1072C000AE12C3BAE432DFE3B9D83D39E95790F4DE +:1072D0003114EFC0A622DDA7AD24BEEA6127BA5F54 +:1072E00097759CDE4DD17F3CC28DEB966E3EED9145 +:1072F0005E8EF778DA1A92577619F8E4EDC5531CCA +:10730000738AF1BE4FEC02A4EFABBEC95C59918207 +:10731000E749AE36F1E5BE1F9F3AFB740A867174E9 +:107320000F6EDFD7C39DE897552D9D2427D8D7D161 +:1073300044EFA3126AD29D06FE7855D04389CB73E1 +:10734000B00F846A1AF0416C589EE969837CC82F9B +:10735000EB62E9A6225B27F67B9B15F3BDEDECBE45 +:107360009CCFB2857CCAEE2BDEA1D39CF40E9DBCD3 +:10737000DFD9D64B5B61B4533F16FD7F2CF8BFAD10 +:10738000D7AD876619F0D5667BEE2F43105F695342 +:10739000DD749F09E51EFAF59B62DC38CEB61E76D9 +:1073A0009AFFB61ED6009EF3696B50F9799A043B9A +:1073B000E90B79EF4AFFAA8EE462765FA7E97D9A2E +:1073C000B61E2984F7E7D5C6435C2ED869FDFCF6C6 +:1073D000E2E46F515EE97A02DD377DD7D23518F9E4 +:1073E0002FBB6F92786708D8C2E00FBB2E2C17E82E +:1073F0001EEAF7C805AB78DF89BFA774117910DDE5 +:10740000D7C58CEF37FDABF2007FFA9073F9BD9BC7 +:107410009F457DC9D7DDF5FF9FF8E4BA083E791E88 +:107420002717F1BF8EBF4FA6A7EE8933EE23F6EFE5 +:10743000CBE9A42D2681EBB386E46F912E6C6B66AD +:10744000A531A7B19CCAE5A75DDE4BBD9AE877568A +:10745000EC749DFC04408FD3801E4BFA6A54AE3905 +:1074600091DBD7BAA5AB1F9D0772F906F6857EDEC4 +:1074700017F728C3F71F13153C872AE197FA4DCE5B +:10748000FF17DD71FE1E8A3C5F2ADFEBB36D51E909 +:1074900082676DA687DE3F91EFA4C8F368EF2BDE0D +:1074A0000E948FFE2CFE7E813C97B62E65AC03F9C0 +:1074B0007D5D0B7FC79789F758E6887AF5F85E0AF5 +:1074C0009E5FEC9B43E3F19D708C8D7722FE4EFC1A +:1074D00005EF61DB7EA4D2BB46CFFD53A5731257E7 +:1074E0007EC6DF43F1AD7199DE9BF09DD6C6A27ECC +:1074F0009DC51C74EFE1DDF81595ABA05CF37F2B07 +:10750000348EF795C6177D081FC4518E8CC87AAD8E +:107510000ADF4119B13595FC24CDB7C4C5E3A2E912 +:10752000086BEC4078FD1B54E2A3669D1DC8C07932 +:10753000551249FEBC93792FBD6FF24E9E2D11ED71 +:10754000BB7A8D1DC0F74BE608F9512BCE31225E78 +:10755000ECA5E1F74E802ED915A5E17729DA2DC0EB +:1075600039A5E4DF21FA5D28EAD7E37B27E8475015 +:10757000F70EC6FD6C29AFB4C441E42FFA78CFBC36 +:1075800021486A7AEA541F8EEFCCDE1B87201E6EDC +:1075900046BA8179BF73C2BD5E7ADFD6DEE8EFC935 +:1075A000F0BD0427BFD7B37E1D9D176CD85BC1EF1C +:1075B000032BDCCEB858BB4D821EEFF442BBEA254C +:1075C000B4BBCD7CDEB0F9A75176A53F6373B74459 +:1075D000A40BBFE32CBF39BD768339BEA3AF58A738 +:1075E0005FE63B0EF7F6FDD7DE71D821F859BEE312 +:1075F00010F693DDE6403E3A9BA9D17EE23A07E7DA +:10760000F775F88EC379ECFACE2646F736BDD8DE8C +:10761000E030DF493EDB2FFC80F83E1CDAC9E17721 +:1076200060B2143FD901ADC9B82FBF4BD0C5735656 +:107630006E57CBF760E4FB0BBBC4BCFFE17429BD04 +:10764000B3B02F545A6EBC0FBE5FED7C6C28E913AB +:10765000CE97B0ACA87CEA3C7818DD4735ED97486A +:107660007B5ECA87CD026E49AF91F55F11F2AD33F3 +:10767000E29D18DF45DE89995B30F2459457922FE1 +:10768000D8FE19CC45F7750792DFF01531FFC0BB66 +:1076900063713DC2D2BDE9463FEC3F0ACCFB3C9B47 +:1076A000BBE5D8E5AD67FEF188793DB3498CBF1BDA +:1076B0002EF1BE842AF67BEBF09C12F0E929313FD3 +:1076C000F2FD98BAE8603E9E1797EFC854DAD80DDD +:1076D000D5B1FC5ED47203DE4E093B63FC465E0E00 +:1076E000D67B14623B0FC686F3EB46F27A322EC786 +:1076F00029E1FB4781B053C47D9F48F847C7FCE3AD +:10770000293C1F55DF6273E07B57C7D0CF84F2ED71 +:1077100059F18EA69DB9F17DD263AF0F74E33EC2DD +:10772000A7305E943F0736F54EC0F5E5BC7695E18F +:1077300039D625EDFC1D79F42C5719EE112EDCA25B +:10774000D07B2DF587393FD4EF5603F834B0BC37E2 +:1077500006F9546F61407FDFC8D7741512CACF6F26 +:107760005502780E78FE3673BEBC4FB5A435225D47 +:10777000DC436B88781FF65DFC4FC6B97200F88554 +:10778000E820A5D87C4FEA52E581C63C3D8BC9FE76 +:107790008FB8072AF1AD0553AFC5F5DE4BC9A588F3 +:1077A0003FE04B7B99E1FC9ADC1F38DD049CD01B49 +:1077B000E46CD3020A65FD334A9BB527FAF7FFCE86 +:1077C000E83EC0F0DDBBEE1EE1C4F28D64A47C7C1B +:1077D0007A10AD4B3F06BEE246CB6A614F0528BC2E +:1077E00072779B8AF2F8E33D4763E83CD3B9FE7DAC +:1077F0009AEFB3A7B5C0F9CE2574DFC3FD4734E5D2 +:107800004B3C9EFC11975F92EE4788F6DA1E4BDEEA +:107810003B1CE92726C181EBECF9E29CC2C99D2AF9 +:10782000B573C29EF0C80468E7C4F62969F8F8D7B2 +:107830003CBDCB8A176ADDCF56C7E3FECADFA15C29 +:1078400090ECC6808AFA7A7825A3FD87E1418D39CC +:107850005DB855E89D8874316C0FBF7F780AF719C1 +:10786000B8FF83F619E63DA3129F49B8469571B853 +:10787000243E6F2DE6FCF8C1F6A7A89D0F1FD61D6C +:1078800008CFC70FEB446F8B803EF1C8FA899D7C0F +:107890001F72D15E251005F91FE27D4DCC7F4D751D +:1078A000DB01FF4B96E91EBA271941EFA37672FF61 +:1078B000CEA256FE1EB7A4F3459E00BD2BCB049D61 +:1078C000DBE10F9E7F4F64AD77E0BDCD1B77FE30CF +:1078D000FA8EA4EBA5C5E2FDE352567A39F7FE4EC7 +:1078E000835E42FA93E949AD032A7A52AB7ED3F91B +:1078F000F6662BA373EC7E4BB41BE5C4C5DEA9BEB4 +:107900004D75BC80F6D0F1626EEF7F6971EAB89E6A +:107910009992D2399A4CFD51160FDE7B63CD369287 +:107920003B91F0DD25E62D07653FD47FA298CB354E +:1079300079DFAB59AE9353C53D03B19E90F5EF2D62 +:10794000E6F2F189622785EA400BC9D34E9D65F3C3 +:107950007BEE8E2C2C5F1D93F4393E39FEC0E3552F +:10796000D3F11C7BF588A45B72C1027CE4F129D3BE +:1079700071DFA97A60D26F7320BEB37832CFEF9FE8 +:10798000345887F8AA5553A78F86FC178A3DDB8B9E +:1079900053C3F0C97621FD7F30BD22CBB7A318EDCC +:1079A000226BEC7AB47BCE285D4BF1413659FE5503 +:1079B000851DF983128E237CEE628CCB719F3F3C38 +:1079C00053EC798CF76B4E9F8D4F06013E66FBF9A9 +:1079D0003D1AF879ED69E1EF13CC96F76AD647BC0A +:1079E00047EFE6F7BFE47D2979EFA9287C9F6BFB81 +:1079F000E5DCE73A23EEA145DEB353F6F2FB68CDB2 +:107A00007ED619457AD97C0F66490CD0537F0C81FC +:107A10008EA0DCF2DFBE13EF84CE172A5C0E315F3E +:107A200019ADD76E76F0F130DF70926FF29DB20F24 +:107A30009A58631ED2F5C46001CA8B7B55DF5F1173 +:107A4000FFA75D4FC7A39AFF60FBDF7EED87F95963 +:107A50002CFC3CEC5B3588EF90B4BB8AE83D87D3C7 +:107A6000BBD665E2B9F0B704FD9D7689F790BEDD1F +:107A70009F7D3B94ABCC1937F82E1AADE77031C916 +:107A8000DD083DF0F03482735C2CC87D18EF48A708 +:107A900022DED161FE38BE7E6578BF4B87502D0D4A +:107AA000CB6DCC8FA7B70AE6A48B7531DDEBEBFE6F +:107AB000AE84988F73E6095800DF45B4D8998EF2EA +:107AC000BE886D77A05E93F3F581E0CF0FEC9C2F1D +:107AD000E57755963FCBEFB32F57B8BE5FFEBA4A56 +:107AE000E7A996B4EBE7D5EB1FB120DDF35EB07DDF +:107AF0000EC93729D7F09A39D2CF44877669F26C0C +:107B0000FBA84B9267F67E423F0F60032E533F2740 +:107B1000F43BCFBC8C51EB9CF8AEE5F2D4C252F1F1 +:107B2000ED1EA29BF9E2FE819CA7E5FF9D4BF77C31 +:107B3000D9E34FD27EE77C013BDBCEEF03DDE152A0 +:107B4000E9BD82AA3D3D99139216EE51E85CE084AE +:107B50003DC9148F0F6550BCEA973D46F27713F884 +:107B6000FC56FDB237C53F7CE4CF83C4FB4FFC9E7F +:107B700090A063392F9FD6F079D1FC45F797A37D6C +:107B8000DCAEB38093CAD3BD2CAF00C72BEE6179B6 +:107B900059E4BD716702B6E3053B8DDE4FF7707F98 +:107BA0008753DCBFB2A55B98D3301FD3DAF9FBFD56 +:107BB00051CE68E634E0FF75711FAB59C879E6F71E +:107BC00074E0FABE46D0434C6192A97C4D6C3DD125 +:107BD000459CFB0A53FBCCC7D76FDD74826929FC37 +:107BE0005E17B63FADC67CFF6C5D14D7237AF927CC +:107BF000A427BC828EF472F33AD09B3996BE0FE074 +:107C00008DB84F1F4947D5928E8A5891F1BB000617 +:107C1000BC13FD7F0A7A1ECD1BB03AEEC77744A68F +:107C20000BBCAF95F7B4F09D702CE789A377FA24CD +:107C3000BD75A0DEEBCFBF33641C377E67C8881FDD +:107C4000FCCE90318EDF193296C7EF0C19F3F13B61 +:107C500043C67CFCCE90318EDF193296C7EF0C19EB +:107C6000E3F89D216379FCCE90318EDF193296C7FF +:107C7000EF0C19F3F13B43C67CFCCE90318EDF193B +:107C80003296C7EF0C19F3F13B43C67CFCCE903122 +:107C90008EDF193296C7EF0C19F3F13B43C67CFC1B +:107CA000CE90318EDF193296C7EF0C19E3F89D2183 +:107CB0006379FCCE90318EDF193296C7EF0C19F341 +:107CC000F13B43C67CFCBE9031BE56D839F85D21ED +:107CD00063BD0EB6261FF54E8AD3B703E59025E6A1 +:107CE000B486F47E68267FFFE4D3F6290EE2FFCB4C +:107CF000F45F3CDA4FD877828E3F67B1D75B722E44 +:107D00005C5FD2E77AEC2B15E97C02BD23FF69ABFF +:107D100042741EA99FA53D9700EA5533F49BE8B134 +:107D200033CD30EEE44A87299EEA4D3795EF51E393 +:107D300034E567F80A4DF93D17B84DF1ACC632533A +:107D4000F95E2B3CA6B8CB5F692A9FBBDE6B8AE746 +:107D5000B7D498CAF7DEE633E517051698F2FBEEBE +:107D60006C34C5FBB5AE3095EFBFC76FCA1F105C52 +:107D70006FCA1FD8DE628A0FEED8662A3FF450C061 +:107D8000943FAC73A7297FC4895653FCCAAE3DA665 +:107D9000F2578782A678057BC9547E94FD55537CA3 +:107DA0008CE34D53F96BD2DF33E58F737E68CA5F86 +:107DB0007CCA4DF7A7D91F14BABF23EDB2F1859F36 +:107DC00098CAE92960EFE3B90516EDC673CE17B27C +:107DD000F3A53D57E5FECAD4EF6D2AB7D3134B7216 +:107DE00084FDCFEDBD66BF97FCFC49B810063E4947 +:107DF000C0FBED49FC7C0ABFB79F427A9754A7139A +:107E0000CFCB80DD0391248BCB85EB9098B03D9A4E +:107E1000F99DE1FD8D8BD9A3BDD06649A5EF79A56C +:107E2000940CC6F5DAAEB1B8CE59C8FC77201C6305 +:107E3000D4E204FC3ED22B51E7F7678DB3031E0D4D +:107E4000FDBD14D59259FA3DFC3BCE7E9ACA77B758 +:107E50002BDE1751607C46BFCF4F60FDA5019FB65A +:107E600034019FC102FADE2607C5B734A553FCBE14 +:107E7000262785DB9A0A29FC59939BF2B73795513F +:107E8000FC81260FC5034D9514EE68F252FAC34DDE +:107E900035147FA4C947E1CEA605143EDAD448F9CB +:107EA0008F37ADA0F8AF9BFC14B636ADA7F4279B77 +:107EB0005A28BEBB691BC57FD714A0704FD34E0A8A +:107EC0007FDFD44AF97B9BF6507C5F5390E2C1A6DA +:107ED000768A3FDFD441F1034D8728FE6253278520 +:107EE000ED4D2728FC535317E5BFDC14A2F869E1D8 +:107EF000B71C5FC2D76BF4702FDA2F237BD3FB86BE +:107F0000327D4D816F7C496AF8DD0CF93E46E4FA1A +:107F100021721E4E8AF6F591FCFD0BFD8A821D78BA +:107F20007E34FC7E857307AE25A78B7EBADFC31037 +:107F3000F6F77C4187F27D0CB9BF315FD0FD60A4BC +:107F4000C742A2C7972F677D24D7D7CFE7F9EA7139 +:107F50005C8BB22C7EF22FC4F2FBB91FE6F91662DD +:107F60007A7D6CA3959BAB6E4AAFB271FF52D74B33 +:107F7000AA7B87F3C2FD358873D617CCDFF761265D +:107F8000EA9FCA7FAAB46FF78A1E57837E94DB05E7 +:107F90001E6E2FB198C25BF2BDFF89F07C90DF7836 +:107FA000FCE7AEF07DE049B82407BEAE664E7A9F8E +:107FB000640AF3BC809F1A9906861FC6AF657E0AC5 +:107FC00027E5F99A91EF66C0C201E3BEE1367A97E0 +:107FD000B3CAC6F922128EBB051C778BFE65786F7B +:107FE000BEF76E6CE758BEE7919BA048BBB81F3E3A +:107FF00091753D80707CF1EC27C795DC307EA5FF44 +:10800000E28E0AB18FBA4C7E67E89C7BFA945F7768 +:108010000BF7E344DED397F7EC3F6DD4492EE27DB6 +:108020007EF46F7CDA78CB50DC979F09EB37DCC7A6 +:108030009772B20EDF1929C57701ECBCDDC331742C +:10804000BF2A527ECAFDA03AB02F713DF84C3EF7D0 +:1080500097BCE2FD44A7EF3FA4F0BF6786F5A4F705 +:1080600015815E1E277A19A6F2FBDC0EA0977E789A +:108070008F9BD385FF4FFC9EB5E6F07AF05C70FDD8 +:10808000F6C401B44F08F483FEB2CF4AB8FF5CD205 +:10809000C75271BE5FD205D0DD1E6CFFE367861646 +:1080A000227D34EC1B46FBEECD16718F5BB4CFD036 +:1080B000150EFDA909C5F41E5C151A154897C3E2F3 +:1080C000E85C729BCA56EC3A8F1C3D22E6F595742B +:1080D000FEAE60B3E04F99FF8698E73744B9AAE750 +:1080E0005FA277A196B6EB6EFA3EC3A0CE62A39FC5 +:1080F000A79B9E573C746B9E81DE1BF6BCC7F7079F +:108100005867F1E4380E2ECEB77C4F59F6A3A33F43 +:1081100004954D8A76BA7B7D918378E2FA42D2A5A6 +:108120006A8DF33D186B1C47375FBC83F4887C81F4 +:10813000EB82893667C2B5007A27A010D737BEFF19 +:1081400071D0BB23B3999BC2B9CC4BE17C2017E41F +:1081500003AF7F9315E779116BA5F4A56573B23171 +:10816000DEC0BA46A7437BD3D6AF7A211D4099D251 +:10817000B2694C06C03D3930EB050CAB1F568EFB87 +:108180009DC4571FE37C752A8D6BAF80FEAE7BBC10 +:10819000626D4F489F28FC1B40871E15F56A9EBBE9 +:1081A000D30FF3776C5311F9A53F2BE1EBDD7BF394 +:1081B0003D9F21FC75AB19D18B3C57DECD57653700 +:1081C000BEDB13CFFC685DF41E66C33E5B12AE2BB4 +:1081D0001731AEC7C3FE1DAEBF25DFE0BB7EF44E38 +:1081E000E613FC1D87930A4C40E979DEB71076A8A8 +:1081F000E487C8EFDA7D69E17604CBF6A597E686D9 +:10820000F5F5494B60487C2EE9F384FE388F237DD9 +:108210001B06E07AF9D78ABB1960399918C86E8CA9 +:1082200035E9077A674AFA0F7FA2737F5CA4FD2BBA +:10823000C71109A7CDCAFCB87FDB6DF794BDF895CF +:10824000725E787DE9B871DA8C53928B70799DE714 +:1082500083638DE8BFFD1FDC4FEECFE2DFA189C451 +:10826000A7E2E0FD5CC8DF6A8BE67049BD75613C42 +:10827000F2F92AEFEFE2E704047C20400A1DD0BFA8 +:10828000A645D33BA7AF4671FF9BF4ABC975F24A35 +:10829000CD37A2FF60CCE77EB976D70779A47FBF40 +:1082A0006DCEE4E71D83A6F796264ABE2AD34D7C01 +:1082B000C522FC5AACFCFC7E47AFDD41F26F327345 +:1082C000937E29628725FEC8AFF57F4D33449A50CF +:1082D0007A000000000000001F8B08000000000072 +:1082E000000BCBE06060F8518FC08BD1F8E8988329 +:1082F00013959FCB825F3D219C01D49F0CC471409C +:108300001C09C42140EC0FC45E40EC0AC4796C0C1B +:108310000C99409C02C4F1401C05C4A1401C00C43F +:10832000DE6C0873DCD81918FCD8F1DBB59A0D5354 +:108330008C851BC18EE1A4CC2FA378E863453E0653 +:1083400006157E047F033FAABC121F82BD509832DF +:10835000BB3601F50300B982EFA2800300000000E4 +:1083600000000000000000001F8B0800000000005B +:10837000000BDD7D0B7854D5B9E8DA8F796666B2EB +:10838000934CC2E4053B0F20541E4388181475F328 +:1083900090C61E6CC737F5503B204A409088D87273 +:1083A0007AACD9900711538D889522EA4011B147D4 +:1083B0007B22A2B556BD035AC56ADBD8627D1F6316 +:1083C000EDA9D40752AC85F6DAEBFDFF7FAD95CC75 +:1083D000DE3321B13DE7BBDF3D50BB587BAFD7FF5C +:1083E00058FF6BFD6B8FCF5FC00ACF64EC33FC038B +:1083F0006591C6182B1E2CC77C4B4BF64E847F33E1 +:108400008BB112C6CC00FCD3646CCEF5C74BEB1A13 +:1084100018DBD15EADFAA05ECE146ABFBD6B7FF0F3 +:10842000A4283CB7591C7BA9D7C7CAFAA1FFF6AA52 +:10843000789941E33015C7A9F2F37118B369DC31BB +:108440008CD777B49F97CF4250EFEEFCA33679706C +:108450005DB2ACB55596AEA371D8670CFBE97FEA67 +:1084600097F52AC6688A62FCBFB98C4D8721FDFC4E +:10847000DDD36F1EA3F57EBF4B653E96BD8E1DDD21 +:10848000B0EE86C175CB75E0FAACE983EBFBBCEBD3 +:1084900021F8603D53585A658853DB7A3106E3D59D +:1084A0008BF198DEA126C28C75B49ABDB51EC6BAF2 +:1084B0005A1995DDAD7E2ADB5A0D2A37B6C67A6B7E +:1084C000C7423B3DE137605D0113DA65CC1B8E434B +:1084D0007BFF605D0F198E7A5E5DCCD19EB1058405 +:1084E000774DC0EF8D9A8EF7ABC3B3FD08FFC6562C +:1084F000A0BC0FD7E5A7728AA1BEED03BADCE08964 +:10850000C71280ECFAD015F319D40311FB151FE044 +:10851000AF3DEC35D7231D8C797FC0E73F1B3BCFA8 +:10852000DF8F783CA0FFB61FE6AA83BF9F55433B71 +:10853000BDAB10E198C2F8F3417C311605FC9CC933 +:10854000FF09EBCE780FFF9D19556D5F04E9ECEC48 +:108550007766C8BB4885F9FCA3AD5802E74BC17BE1 +:10856000090FCC77A671D1950AF4639F3A9F4BFA15 +:10857000A45B0D82EF47AD75CC1ACFD8FD5037B153 +:10858000FE376D416F06DF1609FE5F7D8ECA18C08B +:10859000BBF5717307B2FE26FCBF93197BD4D3F2EF +:1085A000CF0CF8DF3EC76BDE43F01C797529D4EFA2 +:1085B000585952BF11FA4D69E6F8BB43697987DA19 +:1085C0002DE3EDEED7D3E761FD8E1585AAAD64F3FB +:1085D000C9C415AA3D0AD65F3F1FF01DA1FADBE30F +:1085E0002723A16F7BDF07FDEA125E7323E2FD788C +:1085F0000933A761A79E8F1558DFC485F01CC69B61 +:10860000D82CE8F1E6AE00EE47490F0BFE221EB66D +:108610008E901EB398C7498F1543D023C1E9914569 +:1086200087854087C943D3C15DB6B5A6D83BC0F79F +:108630009DAD31A24F7BAB49E5CD4827286FC2A63F +:1086400033B2F7658FCA9A916E3D41D6BC07E16D92 +:10865000ACCFD94E968CAD23FA75C25E6365B42C4F +:108660008B3532E60B0DD4D3C15A981FDF9F2ADE1B +:1086700057C0F8CAC07B9B01FC9ED0C07B3B0FDA81 +:108680007706F8FBFF60DB2C7BE660FDB0BDD951BF +:1086900097EFDB3D89342B60EC7176A93531E0181A +:1086A000DFC2F133D7E7CF315E7B80CFAFACEBB128 +:1086B0006C58DF7794748CD5803C51FA62CC60ECB6 +:1086C00029E837B711C7853A48BA5D9B16D94FCF0D +:1086D000189CE7757B916D030C8B58E2A788FF19F6 +:1086E000B123A5C0F930AFB5804D65EC79EC0FF33F +:1086F000782A78FBE7D98D569B3E8897DFD81D36C0 +:10870000CEEB0BF53053C84F9233827FB4EBFCB6FF +:108710001641BDD018273E6C2C64AC14EAB516C3C4 +:10872000BAA48766E8BFEF77C82BC117A2FDD07443 +:10873000E4ED60FD6FD2FA8D235FC5F5FF145F0194 +:108740007D679735FE7226EC97509F278E7A20849E +:108750006B84BAAFC19B62C0B75EC433B08AF753B3 +:108760008D9D0A533D819B0FC6F1C5CA582A733DA2 +:108770007A3A86725B8E0BF3BD9F892FA87F78A211 +:10878000F903627EF77C8110D461DFFAE2B01E2526 +:108790007BDEF640CF0294BBB30B1BBFC2689CB11B +:1087A000AA0FD60D2468C271E20A97433A8E573F4A +:1087B000B87E39AEA7818FEB319CE3CAF1002F0C54 +:1087C000C70BB9DAEBB8CEC2EC71DDE3C036892550 +:1087D00026E13EE8FB7CF46F00FA8786A7FF7FD78F +:1087E000B81F038008EF9A93BD299BC34BC2D70DD6 +:1087F000EF007C2EB8D7FCFCA918D2D98B0F0A0742 +:10880000E9F967D14FCEEFA6E748E795FDB3E7FD5D +:10881000758C5567CFEB5E6F16FF8E701F458F4FBF +:10882000605611D835281F404EACFFB697F6CBAD39 +:10883000364B219FDC7AE02CB29336ABF1E790AF58 +:10884000ED5F79D83D30F56694BB48A7EB1AA8DFF9 +:10885000DDE196D2F34243CBDD5BC1CEB041EFDE2A +:10886000AEB005BDD06E2BD453B0418A7A41EF81B2 +:10887000BED8DAAC0617015D6FF730D2C7F0FC6DD9 +:10888000D48765CB74FE3CC09F477BB99EBC638593 +:10889000681FE6E395AFE4EDA2D82FC3AE8CCE57A8 +:1088A000999DA1CF4C6F7C5122C73A3B1495F0F1B2 +:1088B00063A187EE177AC80CB2C5888FA2EBBDE61C +:1088C0000E25BBDF5D0AB78B6F453D063272FFBADE +:1088D000790AF263D17C6B9F0EA8294B004F02BE30 +:1088E0007EEC49AD8B80DCFF1785592D40A7E8A1B0 +:1088F000F425289FBBD63DCE7C809F49095E6F8CB6 +:108900003CCD9EA53A2379BB537995E4EF0CFF91BA +:108910005711FF3360FFB621A9F41EAD85F01FCDBE +:1089200049E7D47FFA17A4001F33ECCEBEF3D12E53 +:108930006229A2837C7FEAEF805F32F0F263849742 +:10894000ECA21895CD0A9767721F16E13F018E229F +:10895000DC8793711F36291EC4CBFB8CE45C6ADD77 +:1089600077DB90CFA3BF6371AD2A7B3D4509E7BE9E +:108970009CA13BE1F9AF826311B3EE568A871E2FAB +:108980005B8F24EFC5F633849C8E26525A327422B4 +:10899000B8FD65CD08F7F91CEEA1C677C37B2BE2C5 +:1089A00093CFF770AEF9FEBBF0312304E336FCE35E +:1089B000E3465DE38E14BF6079083E4AEBA84F079B +:1089C000EB16E3753BDB2ECC94FB51EE276AD120EE +:1089D000C97F2D0A78CD5C87E8E71DCDC88FD510FB +:1089E000CFA5A2332C51AF887F1FEDE377152FB5AC +:1089F000D3635C8FBCA526DF253E990F2219ECDFDF +:108A0000A0E8E281F114B413CAEAF293A86742D154 +:108A10009C7665576BA250F764D43D5C0E49BC79D7 +:108A2000AB59AA88FC91CBCCF3260D3D8E1B5F6D14 +:108A300095F15792402FBBD81BBF870D0D8FA27A9F +:108A4000B91D10F5125F023C8A7A72363C7E03042F +:108A500009E88FB6F0B813C2D32EE071D3BD5DC262 +:108A600035C2F50FF5BEBDD28A2D42FD11CE0D9750 +:108A700007E102BC57AA5E610778894E9EA8CD70B7 +:108A8000DD005FA59A835E8C2518EA3F377CBAC16A +:108A9000F7AB9C5FF75F54A8170DAEF30BAAC1E7C5 +:108AA0001958479CC6D10C46FD226AF20B884FE04C +:108AB000BF3EE2BF9045EBF0C6E0FD142CAD05369D +:108AC000F06FFBBE196C22F60BC5D90A28BDA12494 +:108AD0009B0FEDDAA55F196D70EC93B1AAEAC09314 +:108AE0001B6FA5420FCBFAD64AC9574EFA6F5DC627 +:108AF000F5747B71FCFB88CB39821FDCF801BCCD9F +:108B00005133E8A91B1C9F5B97097C2DC9BD8F4B76 +:108B1000FDE73BF055DD64ECD74DC6376E09992271 +:108B2000F46723E3F8DB143BB46511BCEF528E7499 +:108B3000AD83F5848C3E52BBF581E4F999F3173689 +:108B4000F5D2FC92AFCED24281DFA21F6755E72F4C +:108B500086FAB75425271FB581BDA0839F7877ABD0 +:108B60009FCA636F8EA7F50FC56F9DADFE82CCFDCA +:108B7000D9195AD25585FC1755E363619D5AB8E15E +:108B80009524F25D81594FB2C65274842B88F887C0 +:108B9000F72B5461671B2D92FF5620FF497E947C72 +:108BA000576D252C8C7B55B184A5C078055D2C9E16 +:108BB00016B8D133F0543893FBD1808F6B719C7011 +:108BC000D4988DF80CCDEDB5B194F8E8B154A2EB82 +:108BD000EAB3C6EDD032EC8D4704DFB0BA42E20F03 +:108BE000A6C7C93F196A1F6E027C4D1CCB01C37515 +:108BF000469B580AF9F8467C0E7839594D74E03A8C +:108C000040FF2808CFF71426E220318AABB58B75D8 +:108C10006FFA5290F359A5B11DF57A0FAE03F9AC76 +:108C200059E06B90CF7A687F0ABC483E8B3625D2DC +:108C30002AC0B7CE9BDC8C7CA0C7E306CAA3A0D217 +:108C4000437B4F53416E8768D97D386F91C206FFD1 +:108C5000C0BCE15A7307CA859D822F8A1A3BAFC6F2 +:108C6000B8436148277C16F52FE2F1A937CEFE0301 +:108C7000C64DE039C55FA2F3D39602F396D6C6D7A8 +:108C8000A1CD7D8D37B993F03E612FC3E785402F8D +:108C90002F0C798B27C1302EE299D963A1DFD5162D +:108CA0009EC71665D8870F0BBCEB5166A54283742F +:108CB000DDA4713EB9796675606908DB05092FD5B9 +:108CC0006CAE85E355C136417EF0087E00BAEF45B3 +:108CD000F8F39AFA68FEAA28AC8F11DF8F423CDDC8 +:108CE000E2314AB1DF2D612FE961C0C741C46F9EF7 +:108CF0002A7061C25FC04F48E5F3B6AA1E9AAFEB77 +:108D0000DB1C4FD03765029E34203FDA6105B52C5D +:108D10008513E4097C49FCE4097C15C5E316D225DA +:108D20003AD15C57C5F17380F0C3D24CAF42F9DB46 +:108D30006B215F76EA2D6F7D1BC6EF3CA0C56D33BE +:108D400083FF589CFC0E89275F0CF65B0EBD2CDB65 +:108D50000F6F27707B400F717D26F503F0E96BB82C +:108D60002EDDE07C3A523DE45DAB99BF43F9A51B93 +:108D700014D7936BEB3416DB88AF4F909688AF9E79 +:108D8000A969C417B03DE9255C880AEFBD8695DA6C +:108D900048BC98A2FD20ED117F9D331EECA908B2BE +:108DA0007426DC0BC0CB83F9AE15CFBC6BBDB40E03 +:108DB0001DF4039B3808277A74380E4EF1590DD6EE +:108DC000FF95E691FDF4104B07805E1BEBEA5932EC +:108DD000831F75EC076DD0EDE0F13B67BFA1F1E2B9 +:108DE0009AEF02E73A47DC2FA49BBF977DAA4FD4A6 +:108DF0004F67BF977802E4152002A53F01F4D9E040 +:108E0000618F2AA047DB2A3A9163D906FC3FA06B09 +:108E100027E3746749D5A1C7B40AF56D1FD96D263C +:108E2000E79718E72B1FBB284D71F6D8C8F82C4FD1 +:108E3000E8D73795E4382D432F79CB0EC432F1ECC7 +:108E4000F5727B924DBC80DA774FFD461AF7B3B7C7 +:108E5000DA984ABC20F8AADB853FF0A009CE1B4473 +:108E60005CD31BE3FA23509B243AFACD1E2A7D15CE +:108E7000B6B027F8FB017E9DC8F571679C9F4F78BF +:108E8000FD69924FA19E7D4C73F069925D007C1448 +:108E9000602AF1C31D50727E48D1FC3E705C33F9EC +:108EA00054F2A11C7FF8FDD8A3209F96BEE1A3FD3C +:108EB000181DDC8FF3116FA54B84DE90F661E20282 +:108EC0004EB7A600E1E51E71EE903D3EC7CF3118CA +:108ED000BB0FF1AB2783B82F766D5E1C4478776D9E +:108EE000392F3F930EEEF27BA0BFD2E0786D073BA7 +:108EF00000CB3B5A0D2AE5FB3BD0EE82FEDB843EE5 +:108F000093CF7FA27139DEA671BDBECB9F08225ED2 +:108F1000D9535FFDD2044049ED412D8EA1D5F25BBE +:108F20007A0B4E347FC50AE7FE67DAC213AE77EDDF +:108F30001B2F163C9D19CFD1C2D1DF9F04FF38856E +:108F40009D82FB62B8FEC75AFB0A9EF6FCE378D905 +:108F500026E2BF3FD1F6ACB311EFE933496E548B33 +:108F6000FD55DAC5486FD4AE013D826D3FFD8CBF23 +:108F70001F38C7B3428BA04E2605D477752DDE88E7 +:108F800072B4F2258DA9C07763855E619BF9398142 +:108F90001FFEA27CA050368C5BB384A5D2D0AEA6B7 +:108FA000C779DE53CABAFF88767E25CB382FA84210 +:108FB000BE3B9BCE334A5DE70E153A0FF5FFA37417 +:108FC000B8E7FF111DEED07B034646FF728525787A +:108FD000FCEA77CAE20C7E7D4CF0295B1B62EF64F1 +:108FE000C8DB6D4A6F012AA3ED2BD4266E8FF43EA9 +:108FF000378EFCA7FE33D016DFB2E81B1F3D01F50C +:109000008EE2436760DCE9592D8F8FD3C41CF69A3A +:109010009C07ECB667B50CBB767BFB79249FEEF81A +:10902000F49A7D1EA0DBD8352CBE9EE8CF0EE279E7 +:109030009529E86F0A7ACFDDCCE95BDDCDE385CCFD +:1090400076D2BF7A89AD78719CB52C8E7D6B9A19DA +:10905000D92BB50BB97D52B93683EEF05FED66279B +:109060007F8C1276CB28177F98C00745C007B53D87 +:10907000C98D387FE9418DDB0CAEF9C79ABD67D346 +:109080007CC02F29D2E719E368C85FF1F5480F3794 +:109090005F8E42BE9C9C3DEF3FCA777F42BECB1B9A +:1090A000E4BB4FD8A78B7643F5EE8E177E368E5AEB +:1090B000596AA65D25F94E67D65F51EEB2C4C8EC79 +:1090C0009F11B7635F24792DCFD167AD8E0531BE77 +:1090D000BECD6B04F13CDDFE8DC650DF6C5B5D5692 +:1090E0009609E77611A7DD2EE2B2319DF36B89CEAA +:1090F000EDD2329DDBEBDB22FC9C2E7BFEF5C21E0B +:10910000E0F1A071C7C1E0999659F7BAEA3A4B1756 +:1091100065D623A2CEE1682FE67EFB981246710346 +:10912000394F47D826FD098EAE4A769C90674F1579 +:10913000CCF3239CEDA1FA7C6E9725D5CCF3F2F607 +:1091400050F52896016FBB38371E0A9F1D781E09FF +:10915000ED3B445C7C8CD78A1540D95E308FE21E93 +:109160006322DC6E3859E7FE13EE4D148E33DB8D2F +:10917000F5EB819737336BBA5ECCFBA13FA9197F22 +:10918000AE5AC4A81DF91DEEF9AAF420A7DF44FDCC +:10919000AFFD19F2013D6F926B82BF596864765141 +:1091A000A59E3C1BE7B76733B273ECC92CD586FB91 +:1091B000B925E188D341BB2FEB27533B1BCF9F073A +:1091C000DA25B9DF97D1EE7CD1CE72B44B64B55BB2 +:1091D00020E6658E79ADAC79BF26D7C732C78B67DD +:1091E0008DB758B4233B7FA09D9935DE52D1CE7206 +:1091F000B433B2DAAD107030C7BCCC39EFC0FBD19C +:109200005EF99EFCA38EE28BFCE4B7A41638F8CF7F +:109210004D87FDC59C1F9F2E9ED784FC72CD731E6B +:10922000CA63D957ECE453D9BEAD9575ADC8C8270C +:10923000690BEDA079E4F38176A11D46EEE78B87FB +:1092400068BF58B4F79F90DFDB04BFB7097E77BFD4 +:109250003F2AF67F571DE8A91CFBFF6FE23DD313A1 +:1092600014C7F0D6B1DE891972F2FF17380F0BB9A7 +:10927000D755B7BE6736B8780FB62F58EF07FADF65 +:1092800010DBD4330BEA2FD90BD6CF55FEE7C1F94B +:109290000B7DA903CEC7D8D2F573ABFEE7C1F97E2B +:1092A000FBB50E38EFB6AF3D219C1DE27CD33DEE01 +:1092B0009F85DCDFE049907CEF28FE460CD7DB5130 +:1092C000C9F540C8D3B87E1DD427B1E45F502E6DD8 +:1092D00080FFFA506FE926E9A1E1FAF927E809DCF5 +:1092E0006737C4B85D28E7DDAC73BF4796B76150F8 +:1092F00007D61128D5C90E63C5DED458010F9E5379 +:10930000ECD10DAE97057CBF74D53FD00DC7BE859F +:109310007FFC15ED2303E1AFC9A17F847CEC291507 +:10932000FAB9CCA99F3BC33D6AA67EF60B5DF6D485 +:109330002C2FE531CDB9DE1FA8C6F8E30B1AC33CCC +:1093400044B79E9E757DD30113DEF71CF088BC3FA9 +:109350006ECFC8716E037B1CF9A143E413A17D9508 +:1093600029877BCCD9074C90DB9FBCE0E1F3168FBB +:10937000CBC7793B059F740EC1273FF6703E79023B +:10938000C63761FC8781EFB0FC3ED49330CF4350A9 +:10939000C7B20DECFF24E5D7C5A8EC69355912DA40 +:1093A0006D83F560BDA3354EF57B5B1BA9BE1DFD2E +:1093B00007A8FF00FD07286BFEA492FEBFA79575C6 +:1093C00063DC7B4BAB9FCAEE5683CA9FB4C6A8BC76 +:1093D000B3D5A4F296D6BA6E34C16E6A8D53BDB3BE +:1093E000B591CAB9CA79733D646FC5F7FB015F7760 +:1093F0003F585D8FFEC2B43FE916C51BF5F853A177 +:1094000086C1E712CEB9CAECB3B19F765CE5EDFC3C +:1094100071D2BF39DA7DD90374F61FD7799C3464D1 +:1094200033359AB3DDF9D8CE3828C63398A2E71E73 +:109430006F01CE5B7150AC2F9A567CB9C7FB1AB640 +:10944000F3BCC2F1C4623C0E9FA3DD626C37FE1513 +:10945000B1BE8A96FD81DCF32EC576C5852D8B12B3 +:109460003C5E371BF165584621B62B2E6AB95A3C33 +:109470006FF337E0B90F7F5E32D8DE0EE2398D210F +:109480009E0FB4EF49E3734F548CE3E5EDBF378B88 +:10949000D13EF49BC60E3FB0D4A659DC8E302C735F +:1094A0003BD68B7DBC7F6924CE14D86F7EC0AB02C7 +:1094B000F542A8AB9328EEABA8502F91E3155A4C78 +:1094C0009984E77ED00EE0DC047515FA19806715E3 +:1094D000EA2572BC51096A77AB38EF2F1C65939D62 +:1094E000E6314D05B7C65691FF6044F9F8E3CC84E8 +:1094F000AA82FC1BE765D685F0FED6AB19E527DC12 +:10950000ECF9F96CCC078B995C1E3DE1299BB3AE5D +:1095100016D65DC6E367DD532F2AC5787A71396B9D +:10952000C17AA87EC104AC97C8F7F5CBE97D8978EC +:109530000F26BD6D805F179AB662C2A21CFBCE5D7E +:109540007EFCC21C8A9F975CA0322B87BE916574FB +:10955000BE333F66B4D5A7E800CF9F3C1C9EAD024A +:109560009EFB3CAFCEC63CBB028BC3F37A8797C34E +:10957000339A9F53DC3443C03306D60B65E4540161 +:109580008F7C7FAA8047BC2F13F0444EE3F07CAC65 +:109590005BA38C1CF6907BFDE5CDCEF58EF1B2522F +:1095A000EC3766F674B604EADA4EBEBED99D1BD718 +:1095B000AF87F5B59DC3748AA70A7FACC8CFBA70D0 +:1095C0005EC40F9EAB6DF5707B4BD2A5F803AF5D0B +:1095D0009423FF5A96925EC51FF8DFC676925E25E9 +:1095E0001F044FD84FD2B1E483D0DB4591A1E1CB2A +:1095F000A68741F408777EA8DE06BC5429F0CFD8B0 +:109600005F67CFAACDA64FCF3280371FCA00D7B72A +:1096100065125EC06F21D4F74878055D8A63006FDC +:10962000E404F00A7A15C7FCB46E49CF9258F0846E +:10963000FD249D4B62A1B733F1F2630FD7B3C3D1C1 +:10964000B56D99A09BF0A7CBF461E09839423866DC +:10965000BAE09839423866FE7D7074097A748505DF +:109660001C2180A3F00470540CC37F128E0AC17FAA +:10967000128E8A61F84FC251E1E4BF11D3E31C2777 +:109680003D8A043DE438EE7DF49D939DF22D3CDD52 +:1096900029DFBE339DCB83AD387FF1E0FE089FC24A +:1096A000E541FB391C6FED026F45026F43CDF7F8C2 +:1096B0001F9DF3CD3CEA9CEFF1A3B9E79BF9319FE5 +:1096C000EFBF2A5E50E0497EC52BFC712DD32F6E73 +:1096D000493AFC6768778168676B997E7632E9F072 +:1096E0009FA1DD57BD225EE06897C86A77A9188FF1 +:1096F00039E6B5B2E6BD4C8C975633C78B678DD72C +:109700002CD7A7668E67668DB752B4B31CED8CACB0 +:1097100076ABC5BCCC312F73CECBD8D5233AB72B83 +:109720004A781DE78BE126673D2FEEAC7BC4791D9F +:10973000D5AB06E793E3C9F32F96B4C97EBF21DC0E +:10974000F30AE61D6EF6CE9D1385E7371470B9BB9C +:10975000B9737E1B9D136005ECE990B0978F4D5552 +:1097600009AE6058A77C6A0F53297E120AF9531478 +:109770005F15E74B3A4B137DC251164F43BF700341 +:10978000CF9F71F3916C0F84314F94CFA0D7F273B8 +:1097900061BDB6AB8F973A9D07B2858A3BDF653BCB +:1097A000D2C9C7120CF3E2651EC288CFBD467C3E0B +:1097B000C6EAD06EFD260BC6F19CB8C00B762C74A1 +:1097C0005D5BC1E3E5D55A720FF281776ECBD7DBD3 +:1097D000A1AECC5B3B1EFD8A186B51307E6F8CE2D4 +:1097E000795EEC327F1CF3698D3933E9FCB1ADD879 +:1097F000E93F7EE2E5FB7FBF57A3D2C8E3F28DF9D4 +:10980000EDD27333E2C4211FF747E0FDD5484F6D19 +:1098100043F3535D8D50CF67531570CE6E31AE9EBE +:10982000D304701935A27FC510FD6BD883D8FEB85C +:10983000F7F2A774E007630C23BDFB59E73AE20790 +:10984000633C9727ACC1DCDE0EEBDFF2B592A97862 +:10985000EFA5E8CB6BAB50BE0C8C7312671D650394 +:10986000EF07EC6F65E6F5D50792BF41FC849BD20C +:1098700069CCCFD042322F48E48989FCB7B3B48990 +:10988000F9BFCDC0C75B5EC5919F26F382645DF3CF +:10989000FFA2E077D3701D837E6B6714CF45FCF188 +:1098A0008D7C1B2633CFF3611DEF22BF7CDE751C40 +:1098B000F13AF3943A312F29231E717B254BA19F56 +:1098C0003BB08E38ACA361701D7FF60A3F3A6497B7 +:1098D000925C30A00C0FB6EF9973BD82FC70B69A03 +:1098E000FC14F1C462493D137FFAFC641ACB81F188 +:1098F000A371C7F803CF637CFC817A13AF7BF0BE02 +:109900005F0DF2DD428AA7E873795E245BE0CC1F2D +:10991000CBC87F0AF98AB3F39FBEA859611FED87B0 +:109920000A83CE3598D3EF97793D8B1BC580CCBC8D +:10993000F875C0EB32F0D7891E9F42EB0C7AFCF62B +:109940009D4574FF699938F759C212117CF921536A +:109950009B906F3F64BF8A4CCB9023137C22EFAD6A +:109960008BDF5BB2E12FEAB5CB7B9CF798966E71EB +:10997000D6AF60E795E0FEBD62B387CE8596B9CFDE +:109980001F7D9C3E4B594B27C6273A843DB0D8607B +:109990007A11A8C8953FBA733AE69BC77D3CAEF3EF +:1099A0001EC60132CEF99687525E0BDEBFB377DA60 +:1099B00045A731EC9FEA2C43BD51C068BFBBE5CA47 +:1099C000655DCEF50DB77EF77AE579CA50EBD077B5 +:1099D0002B39CF11CEF0298EFCDB6381C86406F6EB +:1099E000C85A3F2FBF198CECC0F25860740AE97155 +:1099F00029066132E3DDFF114EB5D1B95ACB14E42B +:109A000087E1FA2F1EA6FFC6682A817C29F33CFC59 +:109A1000FE16D23B8A9EA073C98DB161DE57C07B12 +:109A20002DF37DC2E287969C8F37D6BAFB3BDF03CE +:109A30003F7EF6D974C6634914CFE2794E5DADFC22 +:109A40005CB7CD93A07B346D2F690CEF73B415B464 +:109A500030B2072A998972C2579BC8C7F883EFA012 +:109A60001655AB045363FE5469D34ECC635BE6F3E7 +:109A700088F8599CEC065FC8B62C8C337992B102F9 +:109A800098DF7B3DB7E36685C040827E5A6C8107D4 +:109A9000CF559FBDFFB205585F1E9BA723C9D6882F +:109AA000713EFCC183D319ACAFF381304B531C27FB +:109AB000E5C57382E57B358A9B5CF9EF619A7FF996 +:109AC0009EA5BBE6C338CA8F4E377F4FF1B636EA44 +:109AD000BFFC91F37F690B78FC8087B675220FD0AD +:109AE0008EC7CE87AE2B7DECEB785F42C22FF9C6D6 +:109AF0006FF6509ED4F2DD05943F39C06F3AB487BB +:109B0000FE3E28CFCBE1E76EF1F138E40722CF4DDE +:109B1000D9BDEF525A5FEFC51E844BA96861FF099A +:109B2000F37D47C007EDE89E927D9F921A0BEF3FB1 +:109B3000B86FBBB77A12CEBBDDBB98ECAE75C4F77D +:109B4000729DFEDDB7D8B8CFFCB546359278CEBF52 +:109B50003F10C1FB18AB766B69CC0B8492F2030308 +:109B6000A6EB1C97592105E87E15892828F7AE2415 +:109B7000397455EF8D949FB0EA51E7FE03BCC6D30C +:109B8000B0EE2B5FD6E2F3B1FED0BD1113D6F35E7B +:109B9000DF3D11C43FCCB3C89B8FF7799CE7CA382F +:109BA000FEF1C2ECF150A3209FADEABD81CFB7F723 +:109BB0009C77F17C7D956B9FBF87FF28CD3E57FE3C +:109BC0005F3E573EC3EEA211D9F1573EF0C95D3654 +:109BD000CCFBC19EF7EFC27CE615FFE7E3BBFE15A9 +:109BE000E3C24F060C9453AB7EF09F777D0BF0F9E8 +:109BF000E1A33E15F9E3F013F7EEDA0AF5C3AF8EF1 +:109C0000AF57A0FE8AD0F7871FFC4B8909E3AC79D8 +:109C1000E2AC5108FF9A87E738CE4FDDE5E1567E8A +:109C2000FF67703D291AC77C54C14377706444E9CB +:109C3000A2CB537B351680F57DF88A8FF20D56C185 +:109C4000B3B5F548A795948F80F5EB00BF57DDBFFE +:109C500081CEEFB3F16C97AB312CD3E598EA7AD58E +:109C6000DEF3BF727A03961ECA4F58C58E90BC773A +:109C7000F75B7510E8396568FA7DC23EF56232CD52 +:109C8000AAFB6FE0F3F602FD22D9F4FB10FF3123AB +:109C90009B7EC75CF4FB84ADB87B2BBEDC5B94D3AE +:109CA0001E9579012B1FBEF084F907875DFB76288E +:109CB0003C370BBFE0699FE5F3E3BEDBF36FBBB658 +:109CC0004691CEBEF87CA4FB039F8C66C01F873CE8 +:109CD000472EC5FD78E4099F81F7A1963FF132E94F +:109CE00097C30FBFE835C9BF612105EC94C36CE091 +:109CF0004F1FDA2D5729BCB26A6738ED8B0CD2EBB7 +:109D0000AAD4B94D66849E933D7F558AF3FF55A929 +:109D10007D172839E877A6BF9ACBCF5431E165E5A6 +:109D2000CED7BDE21EFF005D9546A4E7DBF3F0F958 +:109D300050F494F01B08FF291974DDC9F7ED50FBAE +:109D4000F3F0761FF9EB6E3A1F167970AB52CACB5F +:109D5000B9E83E90EFF039F3454EF53BF34524DC8E +:109D6000C3EDEBE1E1F97CF89A809BBF381B6FEB08 +:109D70004ABDE4FF69112FEDC74E8FF9B28DFCF19A +:109D80009C87ED802E6D91E9CCCCE1D7B5B7F2730D +:109D90001359D743093A57D0A3463DE546B8EEA13B +:109DA000780C75204705D7639CAE26729D2B33D661 +:109DB0004DEBFCAEC8FFBB79A65A8A571C8C6FC707 +:109DC00028FFC2987DFC400D9D0F144EE5F370BA3C +:109DD000E8CC90F792D44C3F7D287BE6BB956C1B7A +:109DE00096B795423965D0BEF9677F72B5FF04F624 +:109DF000CD7715F1BC80A5EE51282FD91F04F97538 +:109E00009B72E4400D3E3F5725FB109E77050B33B8 +:109E1000DACFE0ED996599C6749E8FCBED16785434 +:109E200082F6BCF8F385B88DF68F17EC19B45FFC99 +:109E3000982F5383F67C2F95DF11FB2704DB12EB61 +:109E4000F9ACDF184B83A5291E512CC62DF687B817 +:109E50003F7081FE41E63DFE00DB46F1224C43FFB0 +:109E60002C23FF86897B5BC3F5C7A9CAE9A3071525 +:109E7000D43E2AD72DBE3F523A0097C110CE72F180 +:109E800076145A5B1ADEA74C5359C9FAA91C834BA6 +:109E9000D130953BB98EF1BC11BAEF10606F903F95 +:109EA000A2DAAAF2D949AE7566D055D28D097FDE05 +:109EB0002BFC7937BDBFA959AF26ABC8AF7FC00F08 +:109EC0007C724C6D79B41FEABEFC2BFA31057FB36E +:109ED000F00F36879DFEFBA37EAE1F65B9B940D05B +:109EE000F342414F3DA19C9BB13F688998A7E95F30 +:109EF0003D17EFE9E37B84C7FD5CCEA71BFCBCCB21 +:109F00001737383F27013119F7377EE6E7FE497DDD +:109F100020F114AE3B5CD14B34407FB63FC7FE917D +:109F20006597B867D3D99AA4F225DC7BD0DF67F0B8 +:109F30007B0BE037FF12C783F952C837BAA0DBE7C3 +:109F40001FDF60FCDE590BD9C327ABC95771FF80F7 +:109F50009BD083F2D557C1F38C35918FDDE675E642 +:109F600093BDE3E7FE8B2C653EB2B7AC79F7763C48 +:109F7000179E1513FB3C41F18EDF093A005EC90FB5 +:109F8000BE4D11713FC52FF617338D92C1FDA5F956 +:109F90002D724E3D0028963EE41F0DF92B45651E9F +:109FA000EE1BD8479E40358D1B66FD83CE2CCC9F83 +:109FB0001FF36E47BB5F0704698554A6B1947C828A +:109FC000CF3D85FC3C3A82715F7F218F7761BD1E5A +:109FD000FDEBC45F111FB13A1E3782056AB84F4AC4 +:109FE000C4FA4AE43E5BE0DC6703FC58E0CC83D66D +:109FF000031C7E4F40DC6B81F951CE0CBDAF878DC9 +:10A0000073E50772C4B910A3FC5E5E6715D2CF98E2 +:10A01000C2FE88E787CCEE99FB4223C5911EC47A25 +:10A020009B7ED3DC268C334DE3FC3DEA865BE65217 +:10A030009CE91411A76A74C6A9C606383F570638AA +:10A040003FB2993C9E3139C0FD75DD68A1B849A584 +:10A05000A8338BC75506EA7379FB81FA44FEFEEFFD +:10A0600088874C46B873C443A604488F0C110F115F +:10A07000F6ECE801B9E78C038FEEE7F18FB3B4108B +:10A08000C989C00A309301EF9513751BFD96D11352 +:10A09000D7F3FB3C82BFCA2F67F45D01784FF6937C +:10A0A000EC5FB9D6EBF06F420DCE38B1CCBB2E775A +:10A0B000C58B07F3AE33DAA35C15764B076339ED36 +:10A0C0000FB7DD726EC065B78C30BFFA578A7571F5 +:10A0D00000F114E5E7106D85CCCEF59DA891C62B57 +:10A0E00086D2C36DB3A6BE1205FE2B796C0FF19F0D +:10A0F000A6F7E2951AB625CCEFA5ECBBD04BF1EB59 +:10A10000ADCCCFF39A5D72E1F8327E4FEFAE284BC3 +:10A11000F187067D472A4FBC6786B50EED6029178B +:10A1200095E4337F417BD68BF4D6502FA788DFA4EC +:10A130001E8EB023540656C4197E8A60FFDAD905F4 +:10A14000E8B7E6B1EE9CFB52F2C7D1353CEF5A6757 +:10A1500027E5633DB646A778566932918F717766D9 +:10A160005B7DB112BAEA447FF05C5BCFA0535193A0 +:10A170009F65DEDB2A4E188E7A95E0A7510B628E22 +:10A180007EAC9DDBB7782D8D9F2325081FB11580F0 +:10A19000B3AAEC7CFE9888E7952E49933C2F6F710B +:10A1A000FAC531916F1D73F573F3D5B680F093C086 +:10A1B0003C40BE023CC4D38887831ADDC7D7FB7DF1 +:10A1C000849732C00BE2E128E3F4AF5C04FBA42ADD +:10A1D0001B1F92EFE07FE4CF8F8671D20CEFB33973 +:10A1E000F114309D78CAAB73E2291C77E247E22D67 +:10A1F000BFD174B4937893DFC91A0A4F15CDBDEB64 +:10A20000109EBF174FFBE4FE13782A0F013F30E486 +:10A21000F3B4A298783EC8F9FC2EC1EF48407F867F +:10A22000FD25F1E2E6FBD266E063942F5166E295EC +:10A230001A36314C71E998C0A7B256F2796EFBD349 +:10A24000CDEF3A037E47BBCECFEFA9E7A1DD46FCB9 +:10A25000FE0ECBB4DB3CFE889D37194B2EB7742025 +:10A2600024DED397F705411EBF4D72F70DE7BD54AD +:10A270000FAC43C9380793A5A63353A5BB95699284 +:10A28000BFE3457BB4AF5906BCE351BF4E463DC664 +:10A29000F1A484387C6C1BE8DB8C73545D9C378D97 +:10A2A000146E6688F81FEADDBCECFD3D06E18D0CFE +:10A2B0007E27CFBC0EEC5E685463733AC2420F2215 +:10A2C0001FCBFB3843DDBFA9EE76F2CFE835CEFBDE +:10A2D000161542DE57087D50E1BA6F53EEE953D0B0 +:10A2E0003E4AAD6114EF2CB7F93DBCD16B587C49A7 +:10A2F000C6B8E5C9487C09E8F032114770F36351EC +:10A30000D0A90FAE39F702924F297B7F30975EB804 +:10A31000A735165FE2C1FB337E2AC39BCDF598AF0C +:10A3200055B585C35BB5C050F13B41924FEF6C858D +:10A33000F5003276B71AD47ECCEAE3A5F732A44B07 +:10A34000B226087C31B63D390BEDC0AA764B4D9252 +:10A35000DD65D506911F9AF979DFB8B515F1254568 +:10A36000784F6534C1E1D633E57FFBD18BF3308F75 +:10A37000BF4B8D83C7C8C61CF7596857518C6606FA +:10A380008ECB54CC13ABE932C97F3D25C8EDAC630D +:10A39000016B2A9F877F8F6728BCB9E793F7D7EEB9 +:10A3A00058B187E66D37A28E7B873BC418FF14E453 +:10A3B000769CBC3F28C7E9EC92F7074DCAAFACEEDC +:10A3C000A95A8FF96AEEFB832AE371D0A5E2FEE079 +:10A3D0003B81E497105FCCC8B8D75A3D787FB07CFA +:10A3E000656D10E5F70EBFAD623E5BF9B50C1C4E16 +:10A3F000C626A400AE4CBE62FC1344A377C667FB1E +:10A4000033E03C16485E88F8A8F08708DFA66D1296 +:10A410003DE47DB431829FEBAE63FC5E510FA373CC +:10A42000E6315DF67A0C41CC13F27E8790F7B00FDF +:10A43000E62FCA90E73B925621DDC717F257CA5B59 +:10A440001083424F99E4DF4FB8CEB90FAA855CADB7 +:10A4500075C9D56A218FAB5DCFDD749C903272D205 +:10A4600055C2E9DE0FD7CAFD308A9562DEEC276C53 +:10A47000E6A8B3CC413E91F7DCDCF6913B8E27C7D2 +:10A480009F9A76CE2FC7192E4EA4E836C56F3C3161 +:10A4900066E0FDA92DC5421FB8E20C03F64B137E02 +:10A4A0001303D9C89F42B91A9B9FA47B20B12616DB +:10A4B0003771FD9BB9FCDDE8E5FD54BFAD7831BFD8 +:10A4C000B1A2EF74E4DFDB82215AF75B6AE236E483 +:10A4D000B3A2F9FCDCA648E88113C9515B1B94A325 +:10A4E0001382C9BBB0BF94A75569A67A33E218524C +:10A4F0009E4BF9ED96D7796EB93BC2BC179F9E4C27 +:10A500002F36B3F103CB77E42F6CA814FAA282EBB9 +:10A51000CB3B56E8FCBB81F6D7CEB26A19BBF1C281 +:10A520000763C5062D276D803F74E3D90ABD7F7D83 +:10A53000E3373AD0BFBFF15C5EEFDFD8D281FED007 +:10A540008D5F55C83FFA50BC870AE5317B645E4693 +:10A5500071B58DFB6583892B81B2E2C4F714F1DC00 +:10A560001CF38B653B4D8FF37B5242BEF85C79291F +:10A570007AC8795EA2E37721270FCA1D7D05F73FD0 +:10A580003A2BF6BCB2B881EED7D37756BDFE16860D +:10A59000FBD1D77335DD2B72CB1FBF903F57A0FC8B +:10A5A0005148FEBC8674D50CE7BD7A297F1E42C592 +:10A5B0000E7418D7D042F7E97D6692F4C0DB419360 +:10A5C000F333E3F12529CFDFC6F6309E5F4FB03875 +:10A5D000B4F334B5D0F7E57CF345DCA489DF4B2C2C +:10A5E0009A6FD27D218FC9884FDD7CFCFE00DF5A37 +:10A5F000EFA3FC3A1C14FE238B2B3CFF87C72F26AE +:10A60000041347F07D558CEDE721EF91F123FD997F +:10A610002EE2785508BFC54E14C773DB1359FC6C86 +:10A620008C2C8FE526AF5570169EFFFDC213C778A0 +:10A63000ED50FE94D4AF521F4B3D2BF5B4F4B74E02 +:10A64000CEAB1AE27CB7F739D463C7EAD5C2CC7C6B +:10A65000EBEE25AC897F7784F3B34FF8CCC72A178C +:10A6600007BDE8E2E469FCBEB6B8772BF93338C41D +:10A670003D2AC9D7B2BDE46B77BB11F373DD62DA53 +:10A68000579F6CE37419DF7335E58DBBF9588EABBA +:10A6900066F373431EF2C910FAB43D689D9C07F03F +:10A6A000DD541F6FCEF55DBAB1211EEFB863C5E66C +:10A6B000800978FA1EE22B63FF07F3C4FE9FB09A6D +:10A6C000F075491ECF13BA779B135FB161F025DB9C +:10A6D000FFC3F84A0A7CC539BE86FA6EC109F07517 +:10A6E00049DE09EC8F8D891D5D781FC44EF2EFF8AD +:10A6F0006C4EA8E933A1FEBD66F57EFC3ECDC6C416 +:10A70000ECC058A8EF8AEF7F5C81F7E786C29C7F98 +:10A710008CF4016C67D7AA26C5F98C9E265CE7AE3F +:10A720008A7A86712DB99E5D15FCFECC868AC5C1DC +:10A73000CB32F0B06BCB7EC7F72176B9BE2F20CBE2 +:10A740008A90E238B7D8BA84C7094A932C85F900B1 +:10A750007397F07D1188F2B84EC0E2F5F1217EEFDB +:10A76000FEE9A99DB330BE7643053F9E93F6CE1613 +:10A7700097BD23E30CC15AFE5DA12D497E8FC273A4 +:10A780003AB7C7E4775EE03D9D7707273AFD004D75 +:10A79000D835BE6DAEE7C20EF2B8EC1DD95E1BC651 +:10A7A000EF2C98DB4FF1B05BF2849F3E8A8D41FB2A +:10A7B000666B4225384A010E9451DD97F728689F51 +:10A7C000967EAA597CFFF7C42E993468E7DC97C7B8 +:10A7D000EFB7768B38663C6DCCC14FBFE437F238AB +:10A7E000B7C4EFBD793CEEDB2DF2DE1BFA1273C26B +:10A7F000276A27E2AE8DFD3D732239DA2D15FBADB8 +:10A80000DBC3EF85768FF5A6F00339DD0A9793F663 +:10A81000CF3DF23B3144D75D971BDB917FF61CA8FF +:10A82000BE91520793DCFEDF037AA93A34B4DC5CB4 +:10A8300029F8645C53DCE2E79772BCF4FDFCBB339F +:10A84000E9D8C24978FD9FEB9D3D41900F84A764F4 +:10A8500059663CB46470BD04FF23AF2CCEC3BC8CDE +:10A86000588559887AACB0A285E1FD0D39DF9E0A82 +:10A87000319F6EDE3809E1BB3C1DDE9801BF9CEFC5 +:10A8800091606E79140BA90E7C3F766887633E5FFA +:10A8900093733EDF12980FD7EDEF5937B961E8F99E +:10A8A0001E1B62BE32099FA0DB93C77F9B87FE6899 +:10A8B000AC0EE643FEC7F942D9F3951EDFA48433FC +:10A8C000F6E737C53C4F4A3CEAC9B2F332E4D0EF71 +:10A8D000057FDC9BD8E1BF0CC6BD616C6700F978D1 +:10A8E0009792F28F433D3655A5EF9E766F3B9A4681 +:10A8F000FBF75E8BDB37058DF62C8C5B8C47FBF111 +:10A900006494A3B3A99FA2F7ACC3FDA86DE177BD82 +:10A910003760FC209F65DBD5C23E04FEDF87FB7EEF +:10A92000F47CFE4DB5D896969F4D4039B156257BA7 +:10A930008E81FBAF4F1F8CCF6CF188F1C4B99BB4F3 +:10A940002F4A859D7E023B23CEE4B91AD5F9399C66 +:10A950008CDFB07A8B293583E71D324E29CF39E45D +:10A96000F9463E4BCFCA3C7FABC17B7535188F484B +:10A97000AD43E0AA2C93BE6F366E4B7236F275E192 +:10A980001AE846764D0B3F37A9B9B36020AE791A65 +:10A9900063D7214F02FE9FC893799BC932F4D39E9F +:10A9A000CF93F70D79FD55575D4F723DA42FE1729E +:10A9B0000E36AAFBBB6435219EE745F0CAF8FD2A96 +:10A9C00031CFE6C4A600CAF51F04AD7121A8CFC8D7 +:10A9D000E3EB00FFE224EC573A9F59F81D0CAD9DC4 +:10A9E000FBA15A88A97F0F7D6318B7207AF271DC2A +:10A9F000741B8ABE928E92AE9F979EE8626B1A9DE0 +:10AA0000130A7BD23EA11D59A11F51B0043782E821 +:10AA10005ACB1244D732BFA1223DABE79AEB024892 +:10AA2000577067D0EFAB0CF1F3071FEB0FE039F273 +:10AA30005074D5EB049D123C7EC47AB2F2B617E492 +:10AA4000A2D3A03E577B1573783DBEA56E5300ED93 +:10AA500002D0E36417D8CD2ADD6F1D813E27FFAAFF +:10AA6000A2FB47E45F751788EF0280FCC7EFF7DFB2 +:10AA7000976712BFCC3CD237273F436F747BD2B16C +:10AA8000F8446C9F5E807E8F7D279713F726DC72DB +:10AA900022E5BF0CCA437905848F2DB5F39E9B80B8 +:10AAA000FB5AB7C97F90F37F74635127F97721FE72 +:10AAB0005DE7EE7357D37791A45CC96AE78A6B7E32 +:10AAC000F4C4CB9598CFF5E6E51F87315FE72DFD00 +:10AAD0004818D777E8BA5F8731CFF0CDEB34BA8F1B +:10AAE0007FA988D37DBDF56FD3F1BB33370BF9F95F +:10AAF0005EC8DA80FB80ADE57926CB521A06AB3909 +:10AB0000BFC17F57EECE43A130505FD95BE4A8CBE5 +:10AB100075ACF4F1F3BB2BEFDFE72D073C2CDB5DCD +:10AB200040F1AB433ADF0787F6566EC778FC3342F5 +:10AB30009FBC174ADC8EF3E27A902E6F3DEE13F93C +:10AB40008C7D1EAE1FADF9789E9214FCE25ED73369 +:10AB50004FE6D1B897DFA6915DB50870BB16447279 +:10AB6000B2F94A8A03B9D77DF99BBDCF94C1BA2EF9 +:10AB7000BF41A1EFDA61FBEBC06F4CAEDD4071501D +:10AB8000375C8B6C673ECC65BD577B89C9B589F353 +:10AB900046C1389F74292407DC79BC4B1FE7F98331 +:10ABA0004B9879E3CCAA1C79BDCDFF44797E4B5DEF +:10ABB0007157B75DF59390B0A7A6B35378BC68E220 +:10ABC000CD13CDE1CFD30E817D8FC9ACEFB5FAA9FE +:10ABD000FCA0D5A07243C8E4F97F8FEE7B86648722 +:10ABE000DE371DF96DCF8177F22E8157AB63DCAE76 +:10ABF0003F63FBC76D8FC0EB692C919F26B96591B0 +:10AC00007C5928E87026F39B2158E76DC27E9F7619 +:10AC10001CEA19F01DED51C8BF5B0D3B15F3F4168E +:10AC2000223E26E3F8DC9E5F88BFA77202B85F0B66 +:10AC3000B9BF97F38FC13D54BF951ABFD7E07E2EA1 +:10AC4000F7C506C1A76D4FDC3E0FF9E6F02D4A1C93 +:10AC5000539997EF7E9BF2572F7FD467683C087912 +:10AC600010E59AE453C65ABCB8BFDDFC28F96280EF +:10AC7000EF1EFF0EE145F203ECA398C8CF8AA98D21 +:10AC800039F86F987CF1C39EFED1B8EFDD7C757802 +:10AC900008BFE57088E72F2C31AD7918AFB99C2536 +:10ACA0003AF9BD7CEBA5FF0E78241FD5F31818E602 +:10ACB000755A7361FFEEF994FB45EBF7D6DC8AF623 +:10ACC000F4D4E775CAC5AE7FB87C1ADA7DF53F0DBE +:10ACD0009172AD7FAEFDCBB8DFCFDC2EBEFB24F48E +:10ACE000E919F84F331B5F673C3B533B750478739E +:10ACF000E3EB8C4F7557DE5CCF33981F5BBF53215E +:10AD00003BADFE05F77B9BCBBF1F3DF008CAE1E5DD +:10AD1000AF6F8A607EF61FF49E12A4C7033B3B22EE +:10AD2000982F7948B72388DF3FA4B49CDF47591692 +:10AD300056643E9A23FF9575D904F79FEFF1189852 +:10AD400057B26AB78FE7533EBD9CE800759E47B97E +:10AD50003777FEEBF27B6F2B31F97D35671EEC4EBA +:10AD60000F9D7F5E05FE194E33541EE0405E61EF7D +:10AD700089F32457093F72D5D35FCA99C72CF34D85 +:10AD8000DDFB7D41D899070BF821BFD18675D159DC +:10AD900097C87F6CBBCF67E379CB1F5E1BB51DCF18 +:10ADA000BF3FD8F97C04EFC50F9C5B8ABCBE0F7A0D +:10ADB0006B4EF89DE0C3424EC8FA50F9B10F80DEE9 +:10ADC000C2F39315AFFAC8DE59F1A29A3711E31A0C +:10ADD000DB3DB4AE475ED95F3209EA573EE889CE23 +:10ADE000E7E0501EACA4DB409EB2A0D3F2877E4ABF +:10ADF000F9B203F9CA825E573EB8CF8BFCE2C6EBCC +:10AE00009CDE7DDEFE500EBAF5BE3D0FFD9DB6FB0D +:10AE10008E79510EFDE149858DAACAEEDF7CCFF314 +:10AE20003C2F5DD06DE83CF4F4971F6BA07606FADA +:10AE300069C3D1B11179E964E2F71F3E06F337BF68 +:10AE4000E6A37CF8E61F5E437CFFAEDE427CBFE2F9 +:10AE5000CE8E12B43F9A3D768941257FDE7CD7B5F0 +:10AE6000C48F4B5FBCB6447C1FB594CB07BB14E1C9 +:10AE7000BB7CDB8504DF152C49FCD87CA796C0F889 +:10AE8000CC273A6B7A30075DFBC3DC8F7B77870F6B +:10AE90009D14F62EC66FD18EFB95C6F3BB5CF936BA +:10AEA000A499A0FE89888F3D125665DE931FE5C9DF +:10AEB0002AD16AD5CE0D74EFF0BD4A7E7F1FF060B7 +:10AEC0000BBC29A8F7B417CF1AC5E9C34CB4E3A942 +:10AED0001F88D439F81CDBF779ACC064473F911761 +:10AEE000CCE75F23E6877507F1DCE0DD129EE7C65D +:10AEF0005CF9D357ED5D361FF3A5F3235C3E0CECF4 +:10AF0000FF9D221F59ECFF3F1DE47205F3AB896ED4 +:10AF10007D9EF428475EB5CF115F1FCC17F6887D64 +:10AF2000ED7C0FEBA2BCE7017C3EA9905DBC6A2FD3 +:10AF300097FB576CF639E283ABF69E2DF2DFDDF717 +:10AF4000519D79D04B851C70D3D12D175E0FBBF26C +:10AF500089B6158F28BEBDC293A23C76D8B764E7E8 +:10AF6000AD78C04379C3EFDFFFD46F2E013E7FBFC2 +:10AF700057EE57A79C1DD8AF806FC45FF39E9359BF +:10AF8000AEFDFA3E7ED737D77E85E739F76B8891DD +:10AF90003CFB2F93B302FF83F876EECFA543C8594D +:10AFA0004F24CBAECAC77B6AEFFDE0CA3194CFE62F +:10AFB000C2AF94AB6E797977D81CE2DE06B78324F2 +:10AFC0003E251E259F2EFFB79534CF00FF4A3E95A4 +:10AFD000FA6B88FC7F373EDDEF9F4379549C9D5789 +:10AFE00061CF6675F87B296D5E568771165B0DC65D +:10AFF000917F87CB1FFB974895D0C3F134F2FD3783 +:10B000009F62F4BD18B45FF0FCE8D8338C7EF7CDB6 +:10B010001335B54C3D139FA3B6E4FA0ED429112E77 +:10B020005F1E421F18C65D1431A9DEAE2544DE68DE +:10B030002F9D23D19909AEB32042FBCC23FC75BCD4 +:10B040008F86F9C28BC438F13CF563136CA8732268 +:10B05000D55FC4FBBAF169EA3535505F78D3A42FC8 +:10B06000EA40BFF869EA43D550BFF4A6C9FCFD1415 +:10B07000759A075876B73DE58B73F19EB6AAB07AFC +:10B0800098472FF3D239CD8DB0BFFDC0F7ED1166D3 +:10B090001500FFE5F9981DA81F5C679E17EAF4519B +:10B0A0007BCBC4F8475B819FF242F1F7C1B0DF4828 +:10B0B000C793E3D4EBE61CFA7DAE5A80B56A709E66 +:10B0C0007A9DC33F31E4A5BCADF6023E5F3BCCD7D1 +:10B0D00046ED24FE4656CAEF3968799C2E5ABEDAF0 +:10B0E000F220EA1381C7651199FFCFE31A1F3D31A2 +:10B0F0006A078FC31E194DBF0BA11DFD8F7F85E70A +:10B1000047BE9647E764AF0539BFBC16E47C727151 +:10B110007EB7E70BF0BCDE3FFA1A64BAD794FBAFF8 +:10B12000C5F2ECFCE49A081F378DE35E72A9C6C72E +:10B130000DB584918E8AC5ED680588B810F0D26689 +:10B1400031D35B835BC8998FAB69F547D2347FD825 +:10B15000313FAB003D05FBECE2197C9F81AF4C7A9F +:10B16000EBE5465E97EB5B90AA6EEB37693D1D11F0 +:10B170008077AA2F5589FEDC25BED458CE77CE7CA9 +:10B18000D5C338FE142CA1FF642E1FF1FBBF0D6246 +:10B190003F373C7AA5234F75D587DC6E677DDC1E73 +:10B1A000967981B82C848F699F96D0B9D00B2AD913 +:10B1B000EBF54F3BF32F4E13F947335EE071BC19AB +:10B1C0002E3976DAA3FF44F2EDB461FCE494946B7B +:10B1D00065ACECF3E49DF629D6BD11D2FBFC776A91 +:10B1E000E6EBCC12BFBB41E767AB037C8EA32F54C9 +:10B1F000E763BC794C4419C89FC67C6EAFA951BEA9 +:10B20000CB5E977C94FC3CE9A07119AE7FD241F6ED +:10B21000758E4F31AEC1F13990CF7988E7734EED1D +:10B22000AFBB1D7FB7C773C0C352E6601EE3D183B7 +:10B230003C8F71FA017E8FF111F4CB31FE1673DE73 +:10B240008F0998416666E025AFAED0516F0F70FA56 +:10B25000CA7CC869FC150BC7CB1CE34C33F8EF7FE5 +:10B26000E637563BFAB3179C798CF5F8FB17B0BE5E +:10B27000F81BFC7B0FD30F3AE9AB09B97AAAB027C8 +:10B28000E3699BE465E31BCE76A7869AE89CE9D444 +:10B2900061CE99DE74D3391B9F8EBCD0A96CF2EDC0 +:10B2A000F8FB4A59F83CE4C4A7E407C0AB86F2B601 +:10B2B000C072E2B5A8C989D7E28413AFA31638F1EA +:10B2C000579A74E2ADBCF90B8EF7952DF58EFA986E +:10B2D000B5A73ADA5781E2CAACD7747DC9D17E6C82 +:10B2E000CF798EFAF82D9738DA4F482D76BC3F6922 +:10B2F000F7F211F1C1A4DED58E76920FA63CFA2D9D +:10B30000C778920FE4BD7BFC8942C47B5CE4D10E1C +:10B31000C707A7446DE4FCBF9B0F46E70B7FF173A3 +:10B32000EEF706A117301F1AED3C69077CE409759A +:10B33000A19D5B003C82F27828BBA0E0F16729AEBA +:10B34000EFCE7338A69A74FEB1594BD07D8D722022 +:10B35000A10A7CD42E7EAFF42655FD7AE6395763D8 +:10B360003EB7E31BF3C5393FE84BD48FE579CC26D4 +:10B37000BDA932C7EF834630B7837E7FF4EE0DF868 +:10B380003B9DED05FD7566018A1CA89F9EAD97400B +:10B390001F4D433F04E4FEDC7C904397A820F761F7 +:10B3A000CA8B0DFB2C05602CF7331BEF99807EA414 +:10B3B0007BDB052CAAAC9E88AED380FE313F03A672 +:10B3C000786AF949749FE768F304FA0EEDD1D0C0AA +:10B3D000F729F9EF289B71CA47F8AAF0638E2EA9C6 +:10B3E000A176AF5E8A3F2ACCD82F70C9606FBC2A85 +:10B3F000EEEF0C179F6BDE7E6B18F3745EADE3F916 +:10B400000EF2F915F95CEE5E91CFF342562DC9B3F9 +:10B41000F97D510F9D83A3DF85BF8F78558AEF6734 +:10B42000AC633C6AE3DC1DCEEF021C68B131EEB9BF +:10B43000EAF173D9C0EFBDC1F38B5FE671C08BFF3A +:10B440003773D86FD7E6F3FBE8D7E6F3FC8A8BA017 +:10B45000C0EF425D04F428C0F2D999F3707FC0F3C5 +:10B46000B402F5AF1C00930DF07E6EB2CA8348FCA7 +:10B47000358BBFF4302CDDCE3769DD17B08407E59E +:10B48000CB6F2E5D19C67603E3C9716071682FBD5D +:10B490005C607B4A406E1D395D21BD0FF3F9F17987 +:10B4A000626179078670E57CBF61C90F5F82FD71BB +:10B4B0001E8BD3B8727C86E738197271F5B2BC74F2 +:10B4C000118CB7FA551F9D437DB4EEC80FBF01EB39 +:10B4D0007A6BF95F1EC67B072CD95F89FAEFAB5BED +:10B4E00034FA9DE1EB43D60DF968BF348EEC3EF99A +:10B4F0009C1F04683FACBE85EBB1D5F78DA77BE000 +:10B50000ABC3CEEF994A7E5926F865F53D35746F89 +:10B510005CFE0E887BFC8E56FE5D0BFC9E26DE1BC1 +:10B52000ED88F2BC619D25EF46BE6E378E5661FDFB +:10B53000EE02FE3B47AC6264F98FB8A76CB49F186B +:10B540005FC7CF059F2E78BC689AB0DFFE0DE17F04 +:10B55000EDC9072A519EFD6CC2BD63C93F6A181927 +:10B560003EA45C7950D8534CE8A9B8801BF414F978 +:10B57000231FB1601CF13594BC7950D861DFD42C05 +:10B58000F2038EA90971FF0CDC488DA4C3F3A7A1B7 +:10B590003DBE4FA5B864048551C6EF1C4730595FC6 +:10B5A000FCAEB11FFCA693845CF9E9CD87BFD8CE71 +:10B5B000E32E4EFB4EC4A9A43D9780BF28DF4F1356 +:10B5C000F6C6F82DCEB8E78CB44A7EEA801DE7B601 +:10B5D000DF307E3402FBED95BF539EF729C9DF2291 +:10B5E0009D7AEBB83CEE4D07F97D0F505DFC3EAF08 +:10B5F000D3AE738F7348C895C3F95C2F3C64F032A7 +:10B600000FE46398DFDBB3B57AAA53AA28987D5676 +:10B6100031AFDBF950CE2BE2EDBDCAE13A3FC8E3D2 +:10B62000A3377FBCA16B267E8782E319EBF83B9E94 +:10B63000B0A988EF574B39F9F417F8F7E7C57770D9 +:10B640001A443CDCBDBE06D88F5C398BFD2CFAA7B2 +:10B650009FF92B7DDFE28142F39748FF23CF697486 +:10B66000EF3AA0F77BF1FBF3FF1732DE05C0008055 +:10B67000000000001F8B080000000000000B95591F +:10B680000D505457963EEFA77FA09BE675B7A24694 +:10B69000973C41411448DBA02249362FE8A8438853 +:10B6A0007634C9B83BD94DAB157110E8C464DD548C +:10B6B0008D5569D0C9B826B5C56E3233CC4C76EA03 +:10B6C000E126A96C02B3ED08B1936AA8068982D17C +:10B6D000141893C1EC5406DD2DCD668426EE46B3D6 +:10B6E0005676D973EE7D2FFD03EE64B5A8CB7DEFC2 +:10B6F000DE73CFF9CE777EEE637A1AFFDD07306D09 +:10B700008C6F3F0700C5006B15116015803D2A68DE +:10B710007A298EAA06C21C802C45592909B8260808 +:10B720008E529C4F1C2BF41F5101AEE6E2C3B900B0 +:10B7300077E5049C0A8E4D5247BE52083022682E8F +:10B740009A03C4E5400E409D0C5AC409108917E4C1 +:10B75000EEC4B14C86C3B207E03363BFA947A8BDAE +:10B7600002C00BD0DCEE65634914DFE3A3505C62DA +:10B77000E364F4A027589A5CFFCDBE795337FE05E9 +:10B78000F5827FB6FA5EC3A12C56510FE538E2EF81 +:10B79000163CE7CDAF56307945CA62661F9E2FD35F +:10B7A00073005DDC8A8B42367832827227BF92D872 +:10B7B0003A536E59F47E49710194C6DB0680708855 +:10B7C000D9D4308AC87A15382EB12C1D50C550DF17 +:10B7D00046102A01126EF009F8BE2B7BEA53C0F91D +:10B7E00054AF4D3D2A107E6DE041F95D56783C80A6 +:10B7F000630980F61B67F2B9795E56EC6700F8DCE6 +:10B80000BE04349DDECB6D70AF33F9FE6A6E0EC39D +:10B810006BA3026CECCA8E8B4ED4636A29C051A60E +:10B8200057524F60E79A7A96E86181CE9FBAF2C389 +:10B83000394C2FE5A84A7A703D2156ACBE46FB151F +:10B840008DD991A5A83E5A9FA957A81C74C805F880 +:10B85000DB56DC534DF8810655F83C3B39B72FC316 +:10B86000730AF0B73B685A7278FDA2D4398469BD77 +:10B87000B9FF2FDA561C3E84EF6519C2921FC081B2 +:10B88000638E87EC54997D32CA9BEBE738F810271A +:10B89000879DBFFF66BD1DD5A2B993AFF3E5863D79 +:10B8A000B5689FEFB4E83B8822E0EB6980D5C827F4 +:10B8B0003A19E7CF08F12BF7A18BBF8C0F94ABA8F7 +:10B8C00053E3E977F3AD38EE15633F2DC3F783B645 +:10B8D00060BD82FC38F13B115C88C3E7FF94A5D7BB +:10B8E000212ECBDEE9C8D39C33E5FD78ACF5EF170C +:10B8F00092DFDF1154441C1296A97CD2B33976D55D +:10B90000AAE1B8317AC93A8EA3E80E3E4572ABA2DD +:10B910002DEB08C7B5D07650C1718508411617F3D5 +:10B92000511ECAB97EA1E8680BC5D954F04EE2E5B4 +:10B930002F95F4F8881971DAF79C9D8D9971608EB6 +:10B940006118580828B3C7C2F9D60A830B09F79EB5 +:10B95000FE3F2B54516E42973711BF567C6C7F5C73 +:10B960004BE1DF4F8CF8FF099D8BE35277F030E914 +:10B97000BDB7FFB2D585F685FE2D920F228BEF2342 +:10B98000B3C6B7ACE6A6F279467C67C457489EB208 +:10B99000120EA1CF80E51BF4FFA15CF4E75B1F470B +:10B9A00097EF7032FD211771E9B968D329EE70BEA7 +:10B9B0009DE2B4E5A31BE5E3F8FE46EFDE3B09CFCD +:10B9C000038A85E98BF150934D71770CE3414DC6A5 +:10B9D0006D29C52DAA524AF15049F31226AFCB3A30 +:10B9E00052CBE2B447048A538C07161F180F0AE59E +:10B9F000915205E383ED2F6671DF35226A340FC75C +:10BA0000B3F5A56C5EB38DE65D23EB1516F7224208 +:10BA1000EFA7F88D0F303911C4905C2B4020529A5B +:10BA20001AC72E868B993F6F614C91FE0E494A8B47 +:10BA30001397249A71C5E70705F65EF8BBC70EBFDA +:10BA4000BC88A2AD42243EEE53381F2188F33C80CF +:10BA5000A7ED6C0FEC7BAF7A4B27DAB7EF9CC4DE17 +:10BA6000AFD69E5C873105559BDA4ED2581D88AC07 +:10BA7000B3907EED12A8E89755386A9867EFD93EE3 +:10BA800072D2C2C37905F9B77BE0BB2B64E2F945FA +:10BA90001B64A10ADDB7A63E7D13EDDBDF87B8C2CC +:10BAA0004CFEA1BA8C6FB7E36742187715A2CE633C +:10BAB0004AE326390BE3652DB7F323A5E17018158A +:10BAC000FB73B73646BC7BC6131C239E25466FE529 +:10BAD000512EEFB970D915447F775BB5150A1B61FC +:10BAE0004FC43953FE29E203EEABA4BC6EC4974C9D +:10BAF00075ABDDDB41F135D12D697988F92D83EF07 +:10BB000010D646E6236E4F70D8604FB774C986F5DD +:10BB100063B786DC423E3E31D85047F564F7CB969A +:10BB2000CBE3CBF89A695A873FCFA2BF8B08049426 +:10BB3000DF1C11749DE2573A20D2FCCB98005E8145 +:10BB4000D6C997C70D9F4C234F1AE1C52F249417D0 +:10BB50008A5A92CFF1A771B0F62A9DD348EB972568 +:10BB6000D73FFBBB51F760CAB9B7949C39571CF853 +:10BB70004B21144E4B8C17BE38F1F823C977946AC9 +:10BB80009E0C4336D4EB2D91E3837992C5D5CDE756 +:10BB900046DC83088DEED12672119F0983775D35CF +:10BBA0003CFF4C75093A8B833730AFE3BCFA33B5B1 +:10BBB0000316337C2ECC5FCDED251E55CB7C7D75D9 +:10BBC0006C318BA32A0D7C71B477F705C9A7132EAE +:10BBD00084978BCA2BB70FCB2D4C1790BC3689702E +:10BBE00069780571C17D7BDF48B73F64E0D2D83EFC +:10BBF0007A6A01CE9B2219EF0D7C4219F8FC867EF1 +:10BC0000593B13A73BDD064EF9904F3881F4582E6F +:10BC1000F10786108C05337963E243E146FCF903B2 +:10BC2000E51B5C7FDE908FFF9C3B9027FF6AE070F6 +:10BC3000B79BF3A759E3FE6FD4255D477D76197C4A +:10BC40008117395FECF89FEC4784ADCCFE6E017E26 +:10BC500021CCB46F4FA76587157DD260E000F0A4BA +:10BC600095E26FCF2BE9BC6B307068C8C0A1392852 +:10BC7000A4E981F1EBDC817EDB65F0FAF67A451E02 +:10BC8000257F36745AE008E3EFD74CCF2FBBB99F1E +:10BC900032F534F533F5FDFFEA99E9A7874D3F2DDD +:10BCA00087E5697EDAE4FD567EC28ACFF2DE3E3B4E +:10BCB000F7CBF5C1E5B9509AE445E6FE0DEDBC9F22 +:10BCC000DCD8CEFBCBEE9181C377A3FDFE5E49A904 +:10BCD000C3FD89911A4719E5BBB3B28F442462159D +:10BCE0002F84D1BEE3434BB6A928D73F2AB2F8A888 +:10BCF00038E7D7B3D01EFF39BFA3308791C21B28C6 +:10BD000063FB587D4D9C5DF26129C9195A5F49B0AA +:10BD1000B69CF53BA81F388E9611AF8473FFF901CE +:10BD20009D5B312CAFB6E1FBE7E74B2CAE36FE7CDA +:10BD3000C7EB36CA136E89F1EBD4C8BE87C91F4D55 +:10BD40006745859E4F9E15D9BAC67F907411E71B33 +:10BD50008F5958FC8530FE05A6AF859D1FEA5DEA28 +:10BD6000DDE54CF260A7C15BBF5B7DA98EFABE0525 +:10BD70000ED62F6FFC130BAB8BD7EE70FC23F53B6D +:10BD8000455AC70605F5BCF6EED32C8F25BA0498A4 +:10BD90008F824FCD3FF9EB30DA77EDED512B35D770 +:10BDA000EBBA47AD5487779AF17E98F3C4E4557D9A +:10BDB0005CDC61BD0BF3CC4836C4511EC86D56F235 +:10BDC0004BD3A8391FB752FD0E187D52F3AB97D84D +:10BDD000BC81FA7EE2E3AB82AEE2AF277B4F303E1E +:10BDE00036770A306F31BDEFD840EBF642E479AADE +:10BDF000039979E407063FEBDB339E1B7CFCC11FF4 +:10BE0000E1E3EBC447BC32604350427CBC717F200D +:10BE1000378EEB6E8C66B3FBCF8D6189F1E2FFE06C +:10BE200025AB7F67A95F43C75E8F8B1AE160AE9B2E +:10BE30003C7BDD4AFDE486D8170CBFBA58FF7AC2B6 +:10BE4000E5410836929D0FC61C4A1CEDAE1BE779F2 +:10BE5000A536666375E541881C227B137D36F63C6A +:10BE6000FCAEC0FA10332FD51BFEAD37FC518F89C5 +:10BE7000D78BA9AE7188D7337825DD3F0F2C4BC700 +:10BE8000A71678FEA88DF0FC91B04464F243A24C52 +:10BE90008036CA2F842BCA4D2C7030FF84BBF8F932 +:10BEA0008D9DE9729A096717AD4FAF7B51F75C160C +:10BEB000AFD7655E2FAE5F902AC3EAEDFB844CBF1F +:10BEC0005C34F384E197BA296075AF96EA0ECA191B +:10BED0008AB796424112A74CBF0CA985B9B3DD1FA2 +:10BEE000CDF103A3BF36E75B3070A86F8B28DC0F62 +:10BEF000C323733BA8DE35AC95C2D43FD4784466E7 +:10BF00004FE3FF6CDBE247E8AE8903FB3BF1FD1F2B +:10BF100076448AC87F789FF8824C3EBD68D78B2BC9 +:10BF200071FFE75D161FE517D03A8A285FFE78FE9D +:10BF30004B757E8ADB4E8B8FEE0F93555298F269CC +:10BF400008FB6960CF6D3AF52BA1E87FF0FB04F1A7 +:10BF500005C7404CF80EF105FBF3FF76637E7808C9 +:10BF60004BFE1CC4E1A128F60128FEA1F55F58296B +:10BF70007F629F3EED9EA54F1F5E52C8EEE1C3B2A9 +:10BF80003ACFE3BC7D9FDEFC15EF0BCDE7CD18AFBC +:10BF9000846B734C60F7D3645F384FA0BE30D17BA5 +:10BFA00062D0C3F2857B25B9E92E0FAF8FDD03592F +:10BFB000BCBFE811F402E2AB7088C547B385FBAFA4 +:10BFC00019F316F100DE4127ADC13C79FECD4324C3 +:10BFD00067F24DC16763E1A45DA03E7737A7024CCD +:10BFE000EE8C5CA6FEFA46979DF59FF5E89F67915B +:10BFF000E7BB8DFA46F303D8FFB4402BBB07B5C2AD +:10C000002136EEC69F3FF5CFCC0B93D18356E28508 +:10C01000D9AFB0E7C8A32683EF99F9A5C9E0775354 +:10C0200006BF33F95AE349CF232DE7B35F60DF0939 +:10C030008625C5467DF4C07FFDEA0EC205FB6A86F3 +:10C040008BD197205ECCFF8951A74EB87E6EF0F25F +:10C050001ADDFB1090962A89E124AEE5E38ABE132F +:10C0600005E4EF44EFCDFC20E6E5B7FA4E2C27BE01 +:10C07000A0410CFFBD6FE0BA14BD9A220E4A02DF48 +:10C08000CC512F5E3F3E9618DEA85791754E52AFA9 +:10C090001E79DCE59B259E046180F9511406D3FAD4 +:10C0A000FDD03B52404F8933B4E771CA770F1B7CF8 +:10C0B00000792A8FEAE4768FCAE62D31EE77B197C0 +:10C0C0008F78FEA3FCFB89859D3FE37D4DB891DE13 +:10C0D000DF58EC008A47F82A5C47F3FD05121CC1C3 +:10C0E000F9FEF30DC590723E08FC3E1CB24CE5B162 +:10C0F000FBE6A8C8F40B8D5ECF5BE2A4BCD7B19E73 +:10C10000EADD0346DE3855E0D843FC0ED3B9F30030 +:10C11000AC641FEEFF3DD5638C93D05ABEBFD5E013 +:10C1200057F7F95A4719F9AB77EE4A094DDA69F42E +:10C1300085CF780221CFAAE4BDE5767D67CABD89A7 +:10C14000CB473B29AE8E8FD9F43A81EEB9373FFE0B +:10C150003ED93B8CFD08CA6FE9B58573C95F9F6402 +:10C16000E9D40F40307817C5F7FEBEFA62AA8B20DB +:10C17000B4327FBC187D22F14BDCD774D141991DBC +:10C180009A7A3FCA63F5B767D54BD4CF60FFF20008 +:10C19000F533C76316D6CFF8CF5532BE1D3F5BE9E6 +:10C1A0002DA40B17F81C24B769580E101E4DC3950B +:10C1B000EFD7511F72AE86F533C2B94A2FE5A30AF5 +:10C1C000BADF523F33BC84CD4D7B9EF770BC12FD6D +:10C1D00059EC3B8300059C2FB0248D2F8DDDEFB1F2 +:10C1E000BADF1895B454DE98FB7EE191999C5F9973 +:10C1F0007C89081AE3C3313E36468FE7911D7B2DBB +:10C2000011E6DF964E0B7FDFC5478036B62F8C6D6B +:10C2100022F9F37D7A847EA8B5EA8B00553C63F45D +:10C22000F9672E06EFA47C78E6FE60318D055EFE90 +:10C230001D24F95DA586E90DC256E6F7896EDE6715 +:10C2400065FA51F5F27CEAF2C2E38159DEBBBCBC6F +:10C250006ED45AF9F71FEACF16607EFBC0A8DF9BA9 +:10C26000318FD177C731A3BE7C08010BDEF570E4B6 +:10C27000F7CDC8329E37B761DE6CC1F5DB1EB4B0B6 +:10C28000FE02AA78FF1DC0FF94BF8ADBE5B4BCF5AF +:10C29000C837F70AD5427EDDB6293DAF3D62F44787 +:10C2A0008FFC91FEE88C99D78AA088F7EB4E077D2A +:10C2B00067FC72C8A248AC1FD197507CDFAE3F3AF2 +:10C2C00085F94CC57C3684F98C46AC53173CB3D405 +:10C2D000A9CCFD669D6A29F92DFBFE73A6FFE2AF8E +:10C2E000DD2C7F66410111F26BD406716C520C5D3E +:10C2F00033F6B7C056E6BF5678388D7FA61F27A8FD +:10C300002F2F9DE9C749C30FCDCB6C9708BF660996 +:10C31000EF71E88F239B8E06883F767B20BE10CF7F +:10C32000FBBDA8A6D5D1E6E8534075A5A584F76B5B +:10C3300013DF1174CAFBA877BE2D25EF4F2CE07DCB +:10C34000D7FE4705F69DB6BFE4B7ACCE37C547ACC0 +:10C3500094978ABA77FC88E216097881EE399B8D2A +:10C360003AB8C5CEEBDE66F35E67DA6FF0A8053C3F +:10C37000619E9FE7B091D6535DDC6CD4C12D55E929 +:10C38000FE2F86910D0B518FEF6902EBA71ED22C69 +:10C39000B3F267EBF695EF91BBBE2D7F8ABD41B737 +:10C3A0007715DDABAE3F4ADF59CF945CCD275C9A61 +:10C3B0000DFEFB8AD5E8387DB77D5F597910F7848B +:10C3C0001CAE7205F9BCD0CBF368C891AF53BD7DEC +:10C3D0003537788797F2897E79377D8734E5508FB6 +:10C3E00042EBCC78F3CD838AA79CA97EE4FE33D7B9 +:10C3F0001DF5286C3C63D11751BE8052EFACF7C4D9 +:10C40000CCBCDC5272BA9CFC72A67FB8DC9AE2BF4C +:10C410006BFB82C5ACAEF49ECC539DA97C130DBEC4 +:10C42000C96C1484AD46BD4CE7DF35E21FF9FBD87B +:10C43000C9CDDF279E746F9B23A829F5B4E743D7A6 +:10C44000D214B9133189ADC7FB53D12339A97AFE70 +:10C4500088E93911E1F2D0E230BB37BDBD72F51188 +:10C46000EE8EB048F3653B5F67F77C38C8D69BBC5F +:10C47000CDB684B585688F2D8A1D6541D2EE8815AD +:10C48000989C709F4D7F8DDD0B80F573894B0AEB77 +:10C4900087011601F1F26D837741C36F6BB00926F6 +:10C4A0007EAE858844F1B20664788CE632063A8E18 +:10C4B000F7802E51FCAC91E3FD42397B1E9691979B +:10C4C000F7C2387B7E1F7D3AC27DF7832AD37C1D5D +:10C4D000840F5221BB3B127F80D24F3C4F765F418D +:10C4E000FE510A9ACD6F495C64B862F211176393EA +:10C4F000C3BE8B9B7AAF16B8DE6B34B0537EFD1B88 +:10C5000023EE7D0E6EE7D404B0EF62A65E77CBB06B +:10C510004942FDEF95C19E8DEB8F0D8A2C7EFBC6A7 +:10C52000559DF29FCF6BECFB77DCB798B52CF0985C +:10C530003F696735EEA3EF716B64BC31337CE2B3C6 +:10C54000DA7BC0CBFF5E8592FE92E4AD8BD9587F3B +:10C5500023DAC312F1BED5ABF2EFC6889B0BE554CC +:10C56000B70930467F0729E4F699F2AB3145E5FA81 +:10C57000693DAF67F44979CCC3FF9EE2627F075BF8 +:10C58000AF103E423C4F9C767C7B1C1379C0F47606 +:10C59000ED9A9AFC6165F2EF4ABED8E93101E355A4 +:10C5A000D03456AF7C76679CFA68F4FAB5D4FEFABC +:10C5B000A7DE9D2F535E105485E103415029FFCF24 +:10C5C000835714AA2F22AD432C3FC97695D3DF9D04 +:10C5D000C85D9FA1BFBE67F0EC936C9E17DED0B71D +:10C5E000AAC4EBED73EC3EC2DF6FCFAF20FE7E3707 +:10C5F00037F832E58B4F84CEA54C98ACAF0AE424D3 +:10C6000079ED00AD8AF0BE99C5E56337C1F8FAACA3 +:10C610009DCFFF3ADB75944607A66F3BEAF702C64B +:10C62000819DBEA366F173294689CF61E3FB69F85A +:10C63000D31C9D3ED1DF14038C94185DAA88F2E1CF +:10C64000C03A95BE3F3FEFB6FB28EE6C649F23696E +:10C650009F79BE6967E6F964F73DA6DD62F27CD397 +:10C66000FE99E7872DCB390E4FD37AC4A1DFC0E105 +:10C67000AFD8A1A02F251C4CFBD131ECEF5A8A81F9 +:10C68000AB8983427EA3BAA2A1DF4CBF23AE2F6445 +:10C69000731C4CFBF11A67677254F45FD94CFBFEB4 +:10C6A000173ACAD026701E000000000000000000EB +:10C6B0001F8B080000000000000BDB2FC0C0F0A3A0 +:10C6C0001E81BF70A1F2D17116272A7F0B377EF52C +:10C6D00084B00C03823D9B8381A18E1982ADA0F8AA +:10C6E000311303C339285EC80CC1DB59107AA4D9B1 +:10C6F00019189481581B888DD909D8C58A2966A133 +:10C70000C0C0F05019C1D7906660C807E293D294B8 +:10C71000F96B140F0D5C638ACA5FAF87CABF6CC028 +:10C72000C0C06D86E06FD023CDFC06A0DE4620069B +:10C7300000DAD58344680300000000000000000018 +:10C740001F8B080000000000000BCD7D0B7854D536 +:10C75000B9E8DA337BEFD9339999EC09933009437F +:10C76000D87900A90D388400B1A2DDE1255EA99D2C +:10C77000A2D568AD0EE1290A046B25AD7AB22193EA +:10C78000172410356AB43E06D0362AB4C1838FD33D +:10C79000AA1D842A9EE3ED8D3DF6AA3D68C3434061 +:10C7A000501AB5167AAFD6B3FE7FAD9DD9B33321FB +:10C7B000D89EF3DD1BBF76B1F67AFDEB5FFF6BFD14 +:10C7C000EB5F6B5C4A8004BF49C897F047D3E50E26 +:10C7D00042C8B4544A88A8F52B9012E3CB92B43CDB +:10C7E000F9D2792EF9CF27A6E70D427221FD31212A +:10C7F0007984FC9097D13F1DF27378C684C74C4969 +:10C800004426C9B2543F7308CB6B0E817C29C0D734 +:10C81000F472739CD36EFF64924D48BDC2D2751EF4 +:10C82000FF36484FBB0B13C44FEB925829CCD3981B +:10C83000459B54D2F43D5FA211FBAB3B3F3A8910BC +:10C84000FAEF9A5E6F0678C806C44F6343EF3D4720 +:10C85000C6A7BE3BC39124F443AA48E4718DA65EEB +:10C8600022C2BC5AA14FC8937EC319A4D006235339 +:10C8700037D2FC540A37F433D5119DCAF0A293A8DD +:10C880000F9A6BF87D8F6FFADB315AFF934A39E2CA +:10C89000A29F6EF13D4B4831219B2FF8DFA1583903 +:10C8A0002159622F51297C59A544EF2D87F6771223 +:10C8B000329D90CF14369E09D72CE2407CA4E04FE5 +:10C8C000C7D7EF085BEF8EB1DA9699743CE37F3AF5 +:10C8D000238F63695F0D09C278798E8D740E6D0D9B +:10C8E000C964A944484B03E91469DA26F5772F0691 +:10C8F000BCBD26E17C9B1A14FCBEE78209D9FD145D +:10C900009E1930EEB4D4B84DB99E9A04C2D9198399 +:10C910007ED7457ABFBEB18810F784FD04F072FA65 +:10C92000E0AE0B61F966C0E2D0769B6919D4337C26 +:10C9300024F17811E2AF7B31CDFBABD40AC09F303C +:10C94000A17E228C3327770981540E77EA14E744BD +:10C95000ACA2EB62D21DFD9F9FC408A1F4EBD70CE3 +:10C9600003CA09598B784AD19FEECDA7F92CC2D7BB +:10C97000A9EF522C975596CF8AC41690C9F4DFE5DB +:10C98000146FB48D4AFFFB92AE83F4576714F0AE78 +:10C9900094B2EFE6784ED2FEB1733260D982670A64 +:10C9A000BFF3C0A51FC0D49CB6EFD2175744816E09 +:10C9B0003657DDE2590FB4E2BC2E3B46E194AA1C87 +:10C9C000075DB4BE14F377CE1995C2A3F740757214 +:10C9D0005F596ABCDB892F78F4EB88B81948FFBC33 +:10C9E000BD9D6ECDF474839EDC27E13C1D563E1C3C +:10C9F000AE7E630321C989A97CBC480F5114904DB8 +:10CA0000E4325DBC80E6253D244468BD924BF4F9D8 +:10CA1000F974F889C950848EDF1EA09D1610729F8C +:10CA2000B13269D0BCB3B117BF6F82B1BF61F93EFB +:10CA30003B168A503C36BB29BF950F1DFFF7146388 +:10CA400040BF9B84FE1A529292172EBE5E2EF59521 +:10CA5000BF0A144F9B85C8997EA0C77C3FD2232D67 +:10CA60006F1573309D2F57406545847555CC7622E0 +:10CA7000898B1598CE9173605EBD6FD702BDE57B43 +:10CA800091FEE30139E9A7FD7514C95B9D420A9E39 +:10CA9000578980F41997987CE890D2E5C473504E7A +:10CAA000E1FD6722611AF7B17911B531F41D5F8696 +:10CAB0007E020C1FBF326286510EDF19FF6FA6C5C2 +:10CAC00002C05324271E07BAD08DD0425F5AB91135 +:10CAD000B096ABEB430B2781F8A3FD53FC282182D2 +:10CAE000746FA9CFE048D272C0433E122B9103CBA2 +:10CAF000F62781EE5592869FA98ED8ABD0AE29FB42 +:10CB0000FA815A2D259FECF27B38BAB1CB6D97662E +:10CB1000C9C3FF852CF962F8FFB07A342B557F50DA +:10CB20005F18D5389E64B22BF961DAF8F18BC880B2 +:10CB300093AE53FB05B2B601F8292227811EE06FA0 +:10CB400000F818FE01DFAB9AFB04E04BAFDFC80230 +:10CB5000BEE27C2A856C708DC03FF536FE3B69E3F2 +:10CB6000BFCFC8CD28A749E77CE42F3F8753AE94B9 +:10CB70000D2617DAFB201DE4C30B1766835C925564 +:10CB8000F9A093C2258712C43A7E2BF01F2562417B +:10CB9000889E017C34663F82E5A26C846A41DF4C4A +:10CBA00096B9BCEE0F7D6752AADDEFB8DCBF1F8AD5 +:10CBB000722DF8249D5CBF4742A0E79A1BEAC96129 +:10CBC000AAC73C2F5F43B449808F3A5DA774220205 +:10CBD0004D5D007451C95291A09E14F3D46DA00F05 +:10CBE000244D59A401FE34F53B9012B21EFB95CAA8 +:10CBF000CE5B2AE0F7E68F613E2289E902AD2F96EF +:10CC000012C4BBA846117E4A5F4101E050D2E96ED2 +:10CC100090CE544ADCF998D7A29332D097391F5E50 +:10CC20006F583A1C32EF840CFD59F284E50D1B9EBF +:10CC30008C34BA93CA0C462F65248169B978B4DF65 +:10CC40004A37BC5D23FCD3024FF358CE77F04741FF +:10CC5000158391EDA0F79AF3E78516D3EF5502B34C +:10CC600003C882743C98ED299EAA845CC05B0CF1D9 +:10CC700066E2A7397F4236D801C49B83EB639F7776 +:10CC800033D5D7A2C53E69964C3812CC7E2920896F +:10CC900051C0279F4F2D03B9325C3F763C368E8DB5 +:10CCA000BC1D03399BCBE80E64235F277205ED673B +:10CCB000219F8F18E4F44ED71B4891CE6321CCC33B +:10CCC0003E4F733E8D3E733EC18C70C4613E520A2E +:10CCD000FEC1EF5CFE0ED7CE0EFF70E5F1B17A68B3 +:10CCE00011DA1BF679B1759354B66EABF9FC242FAB +:10CCF0009D1FC89160CCA4E7D599E71745FAB2CF3C +:10CD00004F5415C48F39BEA8BC921447A5E0BC5D32 +:10CD100050D938837044B01FA74AB0DD0D42EC767D +:10CD2000E01F67B019E589D3AB13E85F0ED1F2F3CA +:10CD300021D56BA8ED44E27B2E20E5D0CE1B213718 +:10CD40004F02F917230B68BDF8174E460FC1CA34BE +:10CD50007ABD4DB0DB8B0C9ED55C1ED8F1F6A76179 +:10CD6000E8FB4F2F5E82F4DD35327D7765A2EF3F21 +:10CD7000BD3891E1EBF9DC8CFCBD5AD99B862FC202 +:10CD8000ED821007A550EBAB0672D94418DCDDA18B +:10CD9000E3DD8BE8B85B42C7E7C1F756A1AFD945E1 +:10CDA000E17C3337F69860996F28461C30EE46CE0A +:10CDB0002F739D5EF7219A76EAC5D9B514BED705C3 +:10CDC000218DFECC14EC24E0B7071B144C4FBFCBD5 +:10CDD000E01F8EDE9A1B483A7F7A97B41601FD0554 +:10CDE0001D91F1144EA7AF12ED7F29A055A03AD4A2 +:10CDF00005DC4F28029BDF4B36382C74F812D085A7 +:10CE000029674D7C16EA515DA5F08C25511DEC8AF1 +:10CE1000403DA11B16F6275AF0169AE930C0EEA441 +:10CE2000787915F0B22AD8572D527856CF210ED0E6 +:10CE3000A5265E3A7507AEF72D73276CB3DA471E49 +:10CE400007B3FB49790EA35B91EA19DFF0FCD84DDB +:10CE5000F1563E1EF24901EA856354BED2F1DBF978 +:10CE6000F76621FA16C011AE1B90613EA74C3B0637 +:10CE700020A6F414E77077D77A109E78AE8AF6DA97 +:10CE8000614EC76405C7DB50BA3B9C89EEC2B1282E +:10CE900071D27A1F88B163585E1951417E65099D30 +:10CEA000C445FB753A480CE58D41FA60FC7CBE1E1A +:10CEB00026FDFB4AB56D40FF67046607E65735AFB0 +:10CEC0007550FE0C7945C46B7EFF22DC4FB8F97EAD +:10CED000807E3FE8A2F9F092A40E5D8D2BED048ECA +:10CEE00021BE72F63D29C6CE001C1ED510008E71E3 +:10CEF00077B075BD4B8AE2FE4F9AD9A947CB41BEA8 +:10CF0000CC238B2C76839BAF8318247AC29B5AE761 +:10CF10006E27C3C396991BDCCBBD50CF837016928E +:10CF2000393AF43796E201E843E2F441E94071D03E +:10CF3000722DD6270BB4DDD860FF3C48293F8C0604 +:10CF4000FABE4B52F3A1DD5D3E99EDEF0CF226E007 +:10CF5000DBE3E0F24FA3FF513C7979FE0D81D9C5A7 +:10CF6000AD37327CD1B6090DF64737B37CA0942497 +:10CF700000111EC09B3F85270FE00DF01789E80EBA +:10CF8000DA4FB8CC580FDB428A9F30C0E7234922E2 +:10CF9000829DE74DE860AA348B757FBC93F6D7BCC1 +:10CFA000DF1931340B3D72BBC7C4932B44BBC8A0FF +:10CFB000C7CDFA23DB15BA08FDCD51B2501FECE501 +:10CFC000F286D2ED64806B8EFA31D22DF18E3AA7C3 +:10CFD000FE9CF54EED08C8355145FBD1C5EDC7C6E1 +:10CFE00030B513297E9D0A311C95E06F200903F0AE +:10CFF000D629F0FD7F845C49E957D61C69F6AC1848 +:10D00000F4A4EF4FEB65D67F0DA5A7343F4C02F992 +:10D01000C93948CC75E8CF1029EC1B09A64937DA85 +:10D02000D5CC5E065A657EA1DBD3F6D3AD5A05C9D1 +:10D03000643F8B84ED93812DBE2C1ADA6E78BCD8B8 +:10D04000C6BB321DEE736EE715B5A3669BE2B3B5A2 +:10D0500013C951CBBE6529D0ADC52EA476D4F342F9 +:10D06000365D8FD0552446E9AA198AE8BAB6F0751C +:10D070002731479A9E73861CC8C7538168412E8604 +:10D08000195DC98A9EC441C2E74667A63C37F5BC14 +:10D09000C51EE804BA53B87EFEBA10BDD341C769B5 +:10D0A0000BAC485AF1D32893154827DA9558AF6D41 +:10D0B000FC3C6D51798ACEDA6CF834FD5CCD0D09FB +:10D0C000DC1F108DD9D97228827098FAC60E974944 +:10D0D000BF83E396B2FD8D53E94479E5EEBC4B077F +:10D0E000FAA5DFF8BE85D32D156E401F3FA129A3F9 +:10D0F0008F04975FC3D0AF766E767F86EFD9B05F2F +:10D100005CF1BA93809C5E1CFAA0AB742A21B5F541 +:10D11000F9F742BABC7E4A9748D343ED257EABFE71 +:10D120003ED4BA14F3471F1A8FE9A1877E7003F02B +:10D13000C7F16E9786B6E2E75F7EE9A4EB5ECBD7D8 +:10D140007DCF032E9467471F161260672C6F158CD6 +:10D150002CD8F705B4C228C5C3D1B6E58524837D94 +:10D16000507B802AAE6C282F2A2419F868796BCB63 +:10D170005AD85F2D4F48BA6EC1CBA07D1EA89B0820 +:10D180004CDCD450F6E0112965C7BE0AF4978BFB3E +:10D19000611DF59712417F41F57B9786FA69FE6123 +:10D1A00047EC159057F183978460DCBD8179680F57 +:10D1B000DFF2AE2B02BE967572DD44D502CF3ABFC8 +:10D1C0001C4379EFED4A5B873D0E29CD2E31E132CC +:10D1D0001E2765541751D03C1110DC73BC54BD8020 +:10D1E0007FB35FC0FE9B389D0D911BF553BB440B75 +:10D1F0003D51FB92685E9453380F67194BCDF2771F +:10D20000B93EEB7738118E5F3962FD302F906BF5A8 +:10D2100039C08F955DCC6EF4AAB86F27E9FE86F50C +:10D220001731385B044F6403C55DCB24BEBF207546 +:10D230006C5F2AD611D82F357278E784EB9242655D +:10D240006A1EC3D16347C3997BC0DE6B69205D90C2 +:10D2500076F8FA8107C80631A24759FF0AF88736DF +:10D26000282CDFD4A060BD96F0AD4A2DC5F30695FD +:10D270007D6FD16E6179CDCCF3729DE783B41CFADA +:10D280003558BEAD4165FD046F65DFC914562FC426 +:10D29000EB910A9E37CB2BE7833DD1526A965761BB +:10D2A0001E1C4420274CFDD052CAEA6F6A0861FF59 +:10D2B0001BBC91F97A39277E6BBD32D68FBF7E3A7F +:10D2C000E23D554FB7D563FD99F84AD533D2EB957A +:10D2D000B3F90FAD4784F47AB70E57CF91562F723A +:10D2E0004BC6715B22E9F09829A5A7F39C16FA7644 +:10D2F000013D4D45F93F1FE4ABD320CA8F2BC06ED3 +:10D3000024F162CAC7339CCC4EAF37E9354CC42AEE +:10D310005AEE2C25E2C539A97EA8CDA9E0F732A2A4 +:10D32000A47D57ED7E86CC746B3CC0E85632F92B59 +:10D33000C8ECFC91E892CA892E11FDFAFD489F12B3 +:10D3400049E72733BDD4C9ED7ADBF874BEE4C739A9 +:10D35000383F9477E4801BFD91CE209D670E9BEFB4 +:10D36000C51596F984E83C73D87CD3BE87D3E769AA +:10D370007E8F039F49A9FC0FC13807BD10AA503406 +:10D380006FCA7EAF7EEF9A109C033481FC2A1F2A5D +:10D39000BF869B7F5BC3F1AED2F140C7FD987AB8E0 +:10D3A0009C688C54A820171BBD2249027F8A510219 +:10D3B000FD4AA575CB719F7BC08D7E45A59CDBCBBF +:10D3C000A554919194BD2D053BC9720BFDB94DB982 +:10D3D000FB7903D2F3462F631577FDA9AED25143F3 +:10D3E000E1F2843E44BDB4CECFF61BF6F26B9D3223 +:10D3F000976FD1DB9D20D7EBCBCF2AD78CBB287D75 +:10D40000545AE52F5BAF4FE87AE1BEC66BB832DA0B +:10D410006DF527EF01FA7E00FA9A0678BE00F1DC7E +:10D4200078701DE2A1F15D371A597BE1BCAA7264E4 +:10D430007C4BF56350CF523B01D3C1F5A7721DED74 +:10D4400004959FA30509EE83C1BE003CC2F077544A +:10D4500040FB42D63E16BE17F0361C7E5A06F1A39C +:10D460003FE2CC3D0B5E7692B73DA0970EB85438A4 +:10D470007FD9FBEE0C1CFF96838C6F289E106F9F4C +:10D4800050BC811E37E923C53FCABD40378D0D030F +:10D49000483F591C5F83F329B7CD27D49B44FB3DFC +:10D4A0004866A07D68968758797BC3992E76CEA66C +:10D4B000DE0B6956790CE7EF0D4790FE06EB8769A6 +:10D4C0007D9AF834DA5F10F96C06CC6AB05C63E5DB +:10D4D00059E506817D9E1CA4705AEC05AAEFF70160 +:10D4E0005E94B09AF6DD1362781D0E5FFB0E4ECC93 +:10D4F000EECF80EF14BF6A284FDA40CF49785E54F0 +:10D5000003FAA51DF41FCE4BC1EF9BB9DED804FA78 +:10D5100009F8DB59C4E48BC8F68B6D8470FF994A17 +:10D5200094E96C0F02F90E89D1AD582626B6097020 +:10D53000BE632071B489EC7B5BB99668A45D75B855 +:10D5400079BD08496C2B62FD00DF896ED68F9F0C78 +:10D55000E0F9C8A01C50EF467DD111D099DE24DD42 +:10D56000CA2D902FE279B113F33E59C7FDB65BEA9D +:10D570005431EF61797BFF76BCB80377ABD0BF2F16 +:10D5800087B717BA59FBE2F4FE3A6436DE4631C17A +:10D59000C6F7E8DC3E387BFF1BD56D0CFE1CDE9E1B +:10D5A000F4B0F6C5E9FD0DB76E9E52BA5E16F9AB42 +:10D5B00084E93AA5D997095C1F6FB99A562FBB2AFF +:10D5C00094566FEFBB1347F75BC6D9D75F72567A95 +:10D5D000390AF462B1FB8EBA63D79300DD9EC6B3FD +:10D5E00066C567D2BC142B14687EFBDD910DF32F4A +:10D5F000A2767BFD07F7809C5BC6E5C8F2FA4F91E7 +:10D60000DF96B52F96411F2C4B08287F9771395113 +:10D610006B9030E8A7B9A2274D0F53DD8E7AB8364C +:10D6200098AE9F6A55A69F6A43E9FAA9F621E96870 +:10D630007F1A3EA81DEF83F14F7659E5D8F2F61F09 +:10D64000201CCB093B975F0EF27D2AD48F15D6D0D4 +:10D65000FA336001A7817D3FB110E4ED21417BA445 +:10D660001EFCE9377AF0DCD28E1FF35CE561332EC5 +:10D6700083EB8F65B6737E7BBA8CEB0F22C610CE20 +:10D68000AF3ADE74E027CAEFCB4CBD45E75B3329E8 +:10D6900035FEA120C3C5D760F141BE8A141F19CE43 +:10D6A0006906F107F2DA8AA7AF88B7088C330DF064 +:10D6B000C7F070AEEDCDF25B01EFE9E7405F03BC70 +:10D6C000FCBDF474478A9E98DDB3C28376CF3F4E8B +:10D6D000574CCE7ED5757ED8A1F275A0F39A6459C9 +:10D6E00037DB7A99ED6EE0F8FC3138777387AE93CB +:10D6F0001D4F8756781C4E6ACF1EDA3F17F7F30F7F +:10D70000CADAF520576E04FC4D053C32BC1DA5FA63 +:10D71000306EE1E765ED3F78A58AD25B6D6B2047FF +:10D72000B08C5FDB5AD41CA2302D7B28500126DD43 +:10D730008DAD0CCFCBBBDDF7C62DF285E2BB14EC73 +:10D74000E96D9CCE86E0BB94E3BB3CDD9EAE2D63D1 +:10D75000F6746DC486EF44667CD772BAA1F38CDF91 +:10D760008DF39C9DEDF6A6F0B438948F7AF141BF0D +:10D77000E607797D94EA3798E7216EF71FEE9EEA77 +:10D7800007FFEB2191E6BD909FC6F20ACF3F44CB45 +:10D79000A17F2FAFFFD034CCDBD7D3BE1E8B07F5D4 +:10D7A0003183D39815399EC0782557A4518338A06A +:10D7B000D88B22EC5BFDDF5881713594C1C19E7B13 +:10D7C000D03FF3B79A06ED32EBF1FC3AF190D5DE9B +:10D7D000F6C568DE6A0744D2CB2562C91759E8143A +:10D7E00046986E3D9F4F70BA21E4C33C766C0CF4B2 +:10D7F0002BF5071683FFB65A3374B04F3E093A34FF +:10D80000B0A786A36B20C041BD82702B9DA2C52FFF +:10D81000D7142C3EEBF94A6343FF7DA265DFE0A4F9 +:10D820008640A4DCE237A83F7A1FD0EBBE203BC77E +:10D83000F8C4AB6E75E1BC36D8FC1789B4BCB37EB6 +:10D8400032EEF7CCF97B06CFE78CB4738E3677E7F0 +:10D85000DBA0B203FE751B2E057F9B79FE5AD635E1 +:10D8600078AE8876A77FCEE31B33E0014F36E0FC2D +:10D870002FB907CF6DE82E8480DFCA47ED4888D7DF +:10D880007053DCF6E1BE24A1003FFA2A99FF4D92C5 +:10D8900034BE2E51F4AFFA380E37563EAD82FD78C5 +:10D8A0007A6C7A3B525A96568FF427E697005C932F +:10D8B0004466739505F9F97FE4ACE7F062293BEF24 +:10D8C000154B5BFB582A62FC92E5FC374702B8AE69 +:10D8D00013329FF7979DDBF9EDB9D6BBBB2171CF12 +:10D8E00011469468BFAFA3140D710B5D0D3D18B7C1 +:10D8F0009747EA04B0FFC4F99124D0E86D8ED804AC +:10D90000806FD4E5558B803E4F1F14D0AF275C5EEF +:10D910003F11EC979CD1DA1438926D9149321AA2DA +:10D92000F92C6D17ECF816CB91D95EBA9E39B05927 +:10D930002820A452FA6623C4F1E49468531CB0234F +:10D9400034BE31FB75A83F46FB18DA37B74E9F3D12 +:10D950009FC29F339160DC0F3166CFD6A1FFAFB37A +:10D960007CBD4CDB7B53764A2BA56398C7A686E328 +:10D97000F701DC174A6C1F7E11ACF334886A32D091 +:10D98000AFAA507A3E32D51217587FEA3EF49386FA +:10D99000D8B9A8E9EF783337360BE6B92ADA3F0F62 +:10D9A000BA707ACDF3CE4437C49398E7DF73690138 +:10D9B000F2E91DDA3697E57CAF4E4A3F778C53F596 +:10D9C00062E53351B9FC0180E3D15CD28B71122E38 +:10D9D000520774DFDC10417F24C5198B8BE4F07C87 +:10D9E0005762E774943EBE0B7089A168F24EA00B9B +:10D9F00031867411978CEC8BE15CF43527DA2B328D +:10DA0000A9233C0E0CCFB3D0FF4EBB5829F1FD83A8 +:10DA1000AAABD595E0CFCA9982F47B47D5838372B0 +:10DA2000A418E3D5BA71DD9A76CD92F2313E0BD7C8 +:10DA30006DA9F4CC06C0FB4A89EB5152A700BDBBCF +:10DA4000E8DA1DAFC038B2A42B07BBE92ECDE371D5 +:10DA500045B43F57D071509A3CF279AF1C8E3E606E +:10DA6000B59BB334CD01FC572CF2F8CDE3FF4CACA1 +:10DA7000F13B5D7C9DE30DFB918ECDEF52909D2798 +:10DA800048B1D7EF013C970AB13B91AFA87D412C3B +:10DA900072580AB238A271E4CAEC2445CDB8039793 +:10DAA000EC07BF7173C300D213E95C8076C138956F +:10DAB000987F48276E9E7187D9798F9BC749B9EFA8 +:10DAC00010FF62D50FF638A876C917C4F82D5B1C75 +:10DAD000A2525F82F460C2EFD00C02FC64C63FDD4C +:10DAE000C7E59559AED44FC0FAAD0DDA0300E72073 +:10DAF000BC7CFF33CE941B9D97A1DC2AE03099F3C8 +:10DB0000DBFB6E8BD14EE9652B150340B75B5738B5 +:10DB1000908EC78DA782BC28C5576E83CDCF1CD7EA +:10DB20003EBF9F71FC3FD6A0DE0FE3F7000CB9901B +:10DB30000FDD0F7C388E0A8D5F425C61F70284C373 +:10DB4000C423A5D148928EA7BDE98C009CA5454968 +:10DB5000F403B82374BC0C78240F8DB00EC6575B49 +:10DB60008717A5CCF1A0A49EFE51384BCD513EA7FE +:10DB7000A5D3B908D6527830D7C5CCD3FD5C76FF93 +:10DB800059E8BAA541BB1FF7F90D65F7337FF536A4 +:10DB900005F8C015260990FFAE3216C7DAAADD4295 +:10DBA000DC142F1BC344077B4FD158B9C2CBE3EA27 +:10DBB0000656AEB1725165E5222F173BEBF61755AD +:10DBC000A2588880BC0E192C4F1714FD2605E1C7FA +:10DBD000E617E164281F50FC3DC2E75560D4F555B7 +:10DBE00083BD58C7FC215290F52B95713EEA3494C1 +:10DBF00062F0DFC569BF96F60F71341519B41CC603 +:10DC000059C1DA9BE50F9AEBA3C58559B84EBA8284 +:10DC1000F0B43278CC7ADD1C8E62B35C4FEFA79300 +:10DC2000F753A21E21D5901AD1F910074265545A14 +:10DC30003F9B793DAF118D827CA30DB1DC1BBC45B0 +:10DC4000AFB6D46BE7E3C51B220F009D961ADC1F0D +:10DC5000A95CF600EA035EAF85F767F2D9B6061D48 +:10DC6000EB271AAA30DFC4E3DFC556D65E36C82CD0 +:10DC7000D0534199C96B7B0AFC10A2F2713CD85079 +:10DC800014BE9252CA6F02E3D73BE877773BA76393 +:10DC90003BFD139AA7F45B48FFB87D2A80DC35E989 +:10DCA000CEF427EC3B38238D0E493DA53B8B5C27FA +:10DCB0007565E9F91591F47CAC2A3DAFEBF70FCA15 +:10DCC00063C857CD4F2F8F44D3CBC33569F994FE2A +:10DCD000D3BAE68C8738967EF4DBC573B502D81FBD +:10DCE0006CCB65F8DBDC40D03FF813EE676E053F88 +:10DCF000A194F2F3353784D0CFB7B1A1FF1EE82746 +:10DD000050FFF52E88F77E00FC8AF4FB16F003D254 +:10DD1000EF33399E4D7F37D597336590FB33495AA2 +:10DD20007C8B694FC5DDE45AD89F65C57A0587C5E8 +:10DD3000FFF26D99E9EF80B93F1455C1AA77BE2D66 +:10DD40003BD2FC24244CAD63DA7F13EFDF53D68B38 +:10DD5000712697CB01669F523D83E7C81AB5342CD4 +:10DD6000F192500FED51AE874A05FDDB006F3C97F5 +:10DD7000C2550EFCDFA983DF327F058B6FF246FAB6 +:10DD800074B80790AD6BB81FF457C5604F47F131B9 +:10DD900019F151B024DD7FA9CEA478B1C8BD788037 +:10DDA000CD57E6FBF431DCAFFEAA73D6F5F234B002 +:10DDB000DB985E6FF42DCB07B8FE9718AD85EFA307 +:10DDC0002E6F45385B40A14F037AED44FBE2D1F959 +:10DDD0000BD0AE702F5030AE835C978E678AFF9B5E +:10DDE000A0BDBB949D7F8FBB83AD8B390E1554F9BD +:10DDF00040C70F0AB1B5B84E6521C56A8729D15809 +:10DE000012FAB1C3F56B59BF95C1CBE0795AD66F01 +:10DE1000B3C24F09391FD6772C891970C43996C3FC +:10DE2000D72C6BCCFEB1C12992A80E7A30E7B2EBA9 +:10DE3000502E8B0B58DC21A9C91C8F37DCB9FE543E +:10DE400087DE22E3BE8E9D83360BB14D90771D7029 +:10DE5000617FAE308FCFE2F19839A33A43532C74EF +:10DE6000F7734E5783FB20C2F7874E936E09EA5132 +:10DE700009F294BF7A6416F74FB166649D0FF637C6 +:10DE800035EC41EEB5C8781F64748CE03EF2C126D3 +:10DE900019ED536945DE6288ABA23C9CC4F8EE786C +:10DEA000339E939BF6A2C2D7D5437A31F5923E7644 +:10DEB0002F84FB8155A2E27EE04F8BFA6F83459A57 +:10DEC000ADC47E06EB76B3121B07A1641F8D8DFDDA +:10DED0000C60DD09EB42BFBF26EA4FC0FC2DF57791 +:10DEE000A6D597587D6ADEFD1CBE6713FD1748074F +:10DEF000C3C4B95BE24DCF782D74429638EC74F709 +:10DF00004B185786FD9DD3120F728EF1AFC03A6742 +:10DF1000EF9FD1D190FE79FBBBB2FC32D86FF7678F +:10DF2000F95F01FC1F5AEF427FC37B0E165F628EC2 +:10DF3000B767BDAB10E4757FDB448C63D8DBE6F2DA +:10DF400043BBE6FA12BFD51FDCDF5A929D29CE6192 +:10DF5000B01CEC0B2AFFFE83CBBF4340E7345D24AB +:10DF6000AA32ECE7171945F75BEDEA4506F32351B2 +:10DF7000029E07F0BDD7542D59F7D7E6BEDADE2E44 +:10DF8000E5EFEA1FCBEE39707CF138BFDA2A136176 +:10DF9000DAD5FF41517DE37E89ED8FB91D65E2F34E +:10DFA000D06116A776238F5B5B42A27E28FC88385F +:10DFB000D00FF411F99D7FAA054F7F9365364EABC4 +:10DFC00084FE1783FE07FA6569A794E68F59DE9DE4 +:10DFD0009E5F4616E6C1BE765997441214FF37DAA3 +:10DFE000FC33A7B8BC584EEA9A613FD8C4F9AE5684 +:10DFF00025E228AA8F573DF7F07490DB928BF1E56C +:10E0000009BA8FD35C29B8567A13329C831FDE3D40 +:10E01000F5AA0B09B44F3417C0FE304032FA8D1701 +:10E02000B7A6C33712FC76784DBFCB7070883D6CB5 +:10E030005DEDE38E720969F15923DDFBBBD0A5715B +:10E040003F1AC978EF6FA4F6DF7431FEF87BDBCF9F +:10E05000FE07C7BF6484F15B834614E4D8201F2BFE +:10E06000BACEE42B93E7ADA111CAC3B4DC7996F222 +:10E07000D2B3B7873828B85FA4C327DCA727C7A0C7 +:10E080003DD7C0EEB1BC2045BF0DFEB6177EEFA454 +:10E09000961E4D03641F5C3131044103BF83AE7E85 +:10E0A000271BCED3F5379D414711672AA8FFF1FC06 +:10E0B000C7808F2F77495CBFF639A15FFDCFEA1C7F +:10E0C000B04B5F90926302944E66FE1389019D5798 +:10E0D000FF39B918F073D1408D0424F2EA8EBDDF08 +:10E0E000837E560ECC13217F0DEFE7A327774D27B4 +:10E0F000B49F1776FA4812E49C9890C14FB672B755 +:10E100005387F8A69B7EE1433DB3F2E955DB17D078 +:10E11000F185E77C08CFCCA797FF94F90B1BB19F43 +:10E1200095CF5E91BD85CF8BEE6DC80BEBB99E335D +:10E130009263E05EC42A17B901EC13130F26FDCEDB +:10E14000F6568B708F6B654F00EDA041BA1769FDD5 +:10E1500072882E25372CCCB0FFFA27CEB71F7ECC85 +:10E16000E26E859E3DD7E3FC7AAFC6F90A4410DF24 +:10E17000A7E3FDC02599F5701EC61342623C2DFF32 +:10E18000F00981CDAB77D25677118CBF55AE45B92A +:10E19000C7CE7F4C7867F754C781EF67AB81625871 +:10E1A000F2D9BFD889F27B4D8F3309FB279AE23E23 +:10E1B0006A8ED7997E8F8AE85E81D2C16A149934BB +:10E1C000DDBD0AE5E2EADE4D782F68CDF3E9F280A5 +:10E1D000E23992A4F0DFF49633B200F2FFFC33BFD1 +:10E1E00046E139D1F7B81FD6838EB348A67CF0CD6F +:10E1F00033E97E6AE8FF4CCED0FE0819C07B3E6B47 +:10E200007ADBD878BBBF750CEC833536B97302FE68 +:10E21000913F741FFD5357BA3FE333F2FA74BCD7F2 +:10E22000D5332AA39E1DBCCFC5E5D04D3B3F7BC453 +:10E23000A0E37FF8F4C947E01EC6CD7FFBF491DB75 +:10E24000615FF7925B05F9B9E6C9F71FF931C5EBD4 +:10E2500047CFBB1C402FA75EFCD94F1FA4F953EF3B +:10E260004CAC1034A01166A79FDAF5D73CB897756F +:10E27000EB8B7347031E6E7D66F6E8B3E9CB5394D0 +:10E28000BE122EABBE4B603FDAF3B4BFD134FB02FB +:10E290004F6DEBB377F7DE4280EFA3B759FCC61A98 +:10E2A000FAADBE02D66B15C6AB431EF671AB77B4A2 +:10E2B000A01F6228BE8D318E10E37708CD5FBDFBB5 +:10E2C0008A6F5F5409A91401F1B0860CA01EB2B781 +:10E2D0005BF3265DD7F3875FC7CFC8E732E07DCD1C +:10E2E0008E36366E2F5D47FFD075FC08FE71C1D0AB +:10E2F00075FCA36BC8FDBC4771EFBE3B733CB6B960 +:10E300008EAB9EF9EE59EF019EB2F1F170785EC1CD +:10E31000E37277B8F43FB9800F9FCE3242B8CEAEE9 +:10E32000C4025A76AAE9D34242E9E3B834703DF018 +:10E33000E3C08B2E15E21A16BDF8960C72EDD4339D +:10E340006FC81ADE4F235E81DA69A7C8E05F1FD865 +:10E350006D782F07F0F8982F097E8DD577ACC0F532 +:10E360005A9DF8CE7CCD8FDFD17FB23AC1F860756F +:10E3700062CF954286F59BA8E430B99AC835CF3371 +:10E3800006D753A882753C380FE86EB87534E7ADF0 +:10E39000C2BC6758D6D390906F87E3CF535B5D22A2 +:10E3A000C453AFE1FEAD3577CCC7F535F7116B122D +:10E3B000C25B99D6DBB417BEEA7DCD2225B39FD2CE +:10E3C0009CF7487C3DF2BCBE1ADE5460FEDCA1F82E +:10E3D0005BDFE442F9FCDE1417C6671D94B4FBD77B +:10E3E00051FE1C784D22DB6893EB2B8E495A867BBD +:10E3F000357FB4D94F37D40BCDA369BB1B0CA65FB7 +:10E40000ECE759B13B9C44B3E067B56BE03D8867EE +:10E4100025BF76138CE37BC98DFBAE358FB8318E6B +:10E4200079EF33A77F0A7AE6D4A32EC2F41F8BBB01 +:10E430005CCEFD97C79E39FDC8FFA5E5C7A0B10614 +:10E44000F5D71DFD11D0FB4F0402A6CB9F9ECE9E9B +:10E450004C28BFDF44EBC279F8F25FDF7E39D02B66 +:10E46000E4E1FC767956EC7AD0FFCB7F325A8038E3 +:10E470009E359EFEBF815C3AF9CB6C5801F2D133D8 +:10E48000A7A7C37A9D7CF6B9C9200FA95DA959CF6A +:10E49000296FB4BE4361B1FB6FEAEDE803FABF092F +:10E4A000CA597DE14BCE3B60BFC3F860AFDCF47C62 +:10E4B000B6EE9E9C560FFB59E31AB80DEEAFD3F59E +:10E4C0002D70E05E205900EB7C534FFAF8CB14A678 +:10E4D00097D7C803CB58FDCE02460F7DD8EE070A6A +:10E4E000B357CD727B7BB3FE5AA538AD9ED97E352E +:10E4F0009CA764A0F77F5298BEB8A9E78B8999EED4 +:10E50000A50E1D877DFFA1400CF0C3905D6EDC570A +:10E51000DF2C2727E494E3777CDFC0CC17F0712150 +:10E520000F76D6AF387FDEEC61F967F9FD829BFD8F +:10E53000340FF02AFD3F07BA59F59C1BE3EC57FD59 +:10E540009ADA5114AFAB9E7D15E3DE57FD7A1DAE0E +:10E55000FB2A5712D77B60978B409CD687BB5EC344 +:10E56000F20FA564218CBBEA05F741EB3D49335D11 +:10E57000D5EBE29BD6F4F9C0B92FF831E3FCBCCC63 +:10E58000C9CFFFE0441BE687E7D1903F3016E30791 +:10E5900086B3B7934A11DF4F30BBDBB4AF9BE03C8F +:10E5A000061CB88A4154CBF9B64858FCEAFFB1D1F1 +:10E5B0009D2CC554D8A7CA804FF0C38AB156F0032A +:10E5C0004BA1E014A0E7E6D0428CD36D2F57A700F3 +:10E5D0007FBEC4E9C745FB47FB795F17DEF350C236 +:10E5E000E22756B9E15E928DFA98945ABE17E3512C +:10E5F00003C6497ACBE977CB7ACBC1FD69EF62D804 +:10E60000E3027E3578AFCE70023F5F631E40000AA2 +:10E61000297FBC639E0F8B71561E308BE3AC9CF33D +:10E62000FF9A5AC6DF7B1765231E4D3C5CF3424BB5 +:10E630001FDCCBBFE6857CF4D35CE39DF83EE0F5C0 +:10E64000573C9ECF08B890FECE7F217AC5B768FEB2 +:10E65000FB2BC6A3BC2AEF8D5E3689E6AF5B5182E9 +:10E660007EC17ECE3FDFDBEA3024DA3FCA66B06B84 +:10E670007F24E07ADE00AE0BDA7011D164B6294F48 +:10E68000B0F80DD2EB63F9DE5C88DFB7B4777AA11E +:10E69000FD5A01CF3DAFFDFD9B7301877F78F3509D +:10E6A00013A437BC4EE42C3AEEA2DD5A3373DBF0F0 +:10E6B000FE5EA0FD3952FD0DE24F54101F29FC28CB +:10E6C00088AF7706CF770C0796A7F08BF1E8267E08 +:10E6D000AFF1BD7D2DE0A5D14DE9F07CC84FD84705 +:10E6E000FC43E9DF6E77D8F1FB6728A2FAEC84A23D +:10E6F000FF4DA1F87A43D1BF54D03F35502816A31F +:10E70000BFCAE9A6ED563B63E3F24AD0BF353117E5 +:10E71000E8AD2FB37D9B1A8FF1D93BC478B11FE5CB +:10E72000673B9B0F7F2FC584FB1DC2E4FBA7508571 +:10E73000F6F78E9FCE83C2F58EE86D0538AF25BD06 +:10E7400012D0F775A40FD3EBC900A631A2CA90D698 +:10E75000C2031225E83FC194C29BEF46F8FBD10EDD +:10E76000FFCBA237DE13603D5F3FB77B7543524559 +:10E77000214A5EEABE4E6DFFC70D005F2D251FD0FA +:10E7800087B03CCCCED064F007D51EF8E00B6B39D7 +:10E79000192C67E72983FD28EC7D074BBD343D83A9 +:10E7A000F5844CFDD07C5ABC8B3DCFE0B07FAF559B +:10E7B000D87B1619E022461ED0BDF9C7DA1F117AA0 +:10E7C000CF83F75A2E6DDB36A795EA93A772FA0A24 +:10E7D000149ABFACEDA7F17898909D74FB07E7E120 +:10E7E000343FC7980979FD7AD8872E1629AB58E2AD +:10E7F000AB16BA99BE59E866F7D469B901E597BB7B +:10E8000099DF09DE5281AB6DF0664F98CAA3433B96 +:10E810002A7E7B9E36FC3AD5B67FE9D232E827A223 +:10E82000132D389DDDE3433FC32B11C3857ED528CF +:10E83000CAC7AFEADFCD21114C83248AA919071278 +:10E84000229D9816905E4CC3A40FD3423280A946F5 +:10E850005407F367307E2B2611CC979228A63B8B6A +:10E86000D8FD8B438227027A6C243F4EDC5DCCFDC1 +:10E870008D756FCC85B8AD7F774E81778D4C3D63BC +:10E88000C78F53D9FE40DC7AAFEE0905F7FD3BD7C1 +:10E890006BB83EE6F7B89BC9C7B89BF94B77AE6734 +:10E8A000EF351C7A42896CA3BD1FF6113940E1385F +:10E8B000DCF156319CE398F59ECA61FAFBCCC1E7C6 +:10E8C000CE837397EFBAF52637C29744BA35E96815 +:10E8D000B1E265E707EDD28756BDA3B9A31DC09F7E +:10E8E000FB7FEE41BBF596BB04B45B8926209F2DD0 +:10E8F000E1EBF7544EEF0988633236BB3490D74BC7 +:10E90000DA5D07613F423AE7EAD6FE1EE6F4453A91 +:10E91000EFC7F3F12523DCF75C421531D09FBD1F13 +:10E9200042C606C0DE47DF4A9A3C60FE5EF39D2F7A +:10E93000F3BB4253BC9F58C3FC9C5B9BE4E256BABA +:10E940003E5B76BA503FFBF97E6E37C79BF61EBB27 +:10E950007F90E0FEEF935C0FFCC2CDEE9F99F576C1 +:10E96000F375A1F46C7F676737E04D366AD8BB3129 +:10E97000FCFC2E2177D6001E4F3EE1C2776D26EDBE +:10E98000B8FA26903F937AA8DD44E9E71E2111C228 +:10E99000F781C6CA11C063F579551F43FEA61EE66E +:10E9A0008F9FD4E3D201AFBF73B3B8980989B5B3D1 +:10E9B000285B93969D5B0BC09FAF41FC18F377F9E2 +:10E9C000D9BB58D1B4FBC627C2B3CEEA9707B56509 +:10E9D00058E2F180F38C34799563CB17D8EA17A706 +:10E9E000958F81B3402A27C67849D247D39D1B8C87 +:10E9F0006AB00B5AA822007E1A0B8A93AEEF182A2F +:10EA000067E0BD263886F1D0344CF3B075A5E5C477 +:10EA1000C9CBB369BADDD13B1F16FDA89BD971AA3A +:10EA200038F05ABC08F8BC55A8F35AE7DF8BFE252E +:10EA300073FE2B79BC2DED8740BF277BA6AA80876C +:10EA40002E595F0BF09C1C2B6B702FB07CC7E9EB31 +:10EA5000611D2685E7DD08EB72AF14C5B8B1133B25 +:10EA6000F97AF54C5C0AE5F7CA09BCEF49D763119E +:10EA7000E4CBCB4842C234590CEBE3193C974F60CE +:10EA8000FCF4461FA3C7493B46A31EA7EB5308E768 +:10EA9000B32DCF508451BDDAF2C4BA1A1DD7CB8B37 +:10EAA00076D3CAA086EFF1905B795C1DD735A2873B +:10EAB000F30FA7A713D03E7BE83A52FA133D96FD19 +:10EAC000E0CA9E45E8C79DDDBFF6D5B11047A51148 +:10EAD000F4075139A914025FF43821C685EC048487 +:10EAE0004379424EE07C69D69D83A9E183B426FA3E +:10EAF0003F00FE7C91E5293E75E0CF49076EFC089A +:10EB0000F050EC6174F9143154909F27C2B7FCF1B6 +:10EB10004EDADFE61D02BED6755A62EF5FADDCE16C +:10EB2000C1FEAB7B84E437693EAF5D46B992BD83DD +:10EB3000DD933D1D88ED8173E39561B81349E917B5 +:10EB4000EA815FB3D583F13E737A761582BFF2E432 +:10EB5000948110BE53E0D170DC2D5FC4F2416E96FB +:10EB6000D6C849789FE1CFFD53AE7D99E0BC0A56E7 +:10EB7000C0BCDA3C282F819E940AA433E2AF807B8C +:10EB80002D550FC63180A313DFE332F1D626517E17 +:10EB9000A57A74F2C6E2B94188F77423C993551B6C +:10EBA000E736413CE0C967E87C28BC27CDF76ACA54 +:10EBB0007AFDD6F7C066F0F532F327DDBC5E69AFAB +:10EBC0009FBD4FD4EB87F14E737B77E56E250174C3 +:10EBD00058DDB3EBB7DF80F9B72BF84EE0E9779F4C +:10EBE0009331FE06F0733EE0252600A99C0E2464B6 +:10EBF000986F5ECF56F46F0FE2A5A31EEFFB6EE495 +:10EC00007869F982D221E0A5C79584F717EE91FBC8 +:10EC10001C200F8D6709EE9F4EF07BC527BFF5873F +:10EC2000438F51506EF004F8BD9DDE4298CF3DB049 +:10EC30000FF4A6E05FA9B2F8B6EF7B98BFBDC6C3DC +:10EC4000F6375779B83C2C1F220FAFF2803C54A204 +:10EC5000C938ADB221EB723C7FBCC1C3CFBF955E5A +:10EC6000E4930CEDBE0F742C2FB83619D752ED2853 +:10EC7000DE0AAD71B92777AEC37BDB254FB2F8CE84 +:10EC8000EA9EB5F84EC4CA1DECBED7F0785B8B2C5B +:10EC900037279C28B49E5F9EE8781EF7AB26FE4E71 +:10ECA000025D79537465E263924892F01E1DF1464D +:10ECB0008A014F77F2F99BE584448ABF6BD1FB77D9 +:10ECC0007A98DFFE1E0F2F2F63ED52E5BCBD9FDF4C +:10ECD000EB2FB59733BD73FA5D365FCA1F9A13FDEC +:10ECE000FC6C7ED5E1C8078FD1EF79BB19DD98F3B5 +:10ECF000A3FC2400FCAE9A848CF3ED598BF7C35B24 +:10ED00003A7AD2EEAB9FB0F10FD80D2037B698FA11 +:10ED10001482FE291F841512572A32E90F76CE403D +:10ED2000AA8268BF9B727C58FB9DD71BD1CE0F5126 +:10ED3000036D7A2A7E4EE6E7EA6FE6C6B6027DB834 +:10ED40006AFA64706FAEEE1266C1F66DAE7301C6FC +:10ED500015B978FCBFBDDF7B1A1478638A241AA822 +:10ED6000AD341EEF53637ABC218469578386E92F43 +:10ED700039FF7AF8FB301B391EDA78BA8BAF8799E6 +:10ED80009AF54D3B562C63711C625933FAA9C45253 +:10ED9000F61E9C25DEE797003FDD20658CF7A10578 +:10EDA000028FCB7809EAE5F1388FBC1A1697B19932 +:10EDB000D3D929DB7B85AF703A7A85C3B5DDAD71D8 +:10EDC0003CB2780257D8607C1432E3C06385677B1D +:10EDD000CF87E2BF5FC88CFF3780AF57751E9C9707 +:10EDE000AF41DC0C8B3B36E38CFF3C9324CE761F8B +:10EDF000C0BE0ED90BD8BB176D0D31FC7EBC6105B2 +:10EE0000A65D0D7558DE2C44DF033C64CF3CFBFC53 +:10EE10000FF375386ECAA3739CE77677F48487EF97 +:10EE20002711FFA1738CBF38C77A87207E7D7C6A4B +:10EE30001F7104E2D6A5E1F713C62CBDE235761E9C +:10EE40008CF7426E73C4BE84F99FBE7B259E9F885B +:10EE5000AD5392E086A4763DC9A2DF6BB3B5BFB0D7 +:10EE60001BCBBBE6BE4EF781B52EED59C8D7CD8C76 +:10EE7000CF85F8F4DAD1DA6DB04FACD9D48AFAACD8 +:10EE8000761CC1F8F49BB392A8CFFECDA3BBB370A0 +:10EE9000FE5200DE5531EDEBE1E795FEAE4A0B3850 +:10EEA0005318BD18D678574A277959FF009DDCCBF7 +:10EEB000E9C3A497EC2B4D3A514DBA2882FE47A2E4 +:10EEC0008B09598C1ECAB2187D44B354AEE7185D45 +:10EED0008C72B07366FBF8115EFF1EBE0FA072ADA0 +:10EEE000D52AFF4C7998E76471F17BAE7DF25AB078 +:10EEF000575C3D138A615E4F8E4D14C0BB031E27C5 +:10EF0000F3B73EF9D7ED050B21FDDA9305B02F0BD2 +:10EF100072F9D225D585E05CB83CFC97EBE1FDC5E4 +:10EF2000F20524311EECCA05C9E2A2C91639C4EBA8 +:10EF30004D0AE72D86F3A028872F6577D6E1BD150A +:10EF4000D3EE24621DBE53DAC6EDC5B6B17FA9610A +:10EF5000EF2678F9FB6EEC7D2B28D7CE4FF537786E +:10EF6000FF2325AFA240678376E91079F58FD1CDD5 +:10EF70004F3CD16BB17F2EF7FE0BFA5B82F42CC6AF +:10EF800004666FFD63FDD175467D06FB0899DB8F36 +:10EF9000F0C4228944CEFBAF80F7FF55FB6C1233DF +:10EFA00042607F43DC1FC477B7AF27C0A754EF741C +:10EFB00000FEDC5D5B0DD0AF5964E015B0AF4CBE18 +:10EFC00092C7317A37FB7D3C8BD9818F6799FB14CF +:10EFD000B6279B30482784B4D33C5C9301F9359124 +:10EFE000DF1F2B239DE86F398FF4625A4EFA309D54 +:10EFF0004C06308D10D50969058938793CDF744895 +:10F000006F56628FC2567CB612DB067403F17CE049 +:10F010003FDC90B5FA1B40AF3FCB32E32B9369FE48 +:10F020000EC2CFB746F27F6413FD29260F8779C73A +:10F03000960C7F4F4ECF704FEEEFB8BFF4128C3F5F +:10F04000ECFDA5F3B58FD97DA481B9781F69A2B66F +:10F050000BF2BE5187E6C2BBCD39F07A00DDAF7C42 +:10F060009AF5D96FE01E8C345FC77EC90E92F1FD10 +:10F070003C339546B3B8D278E02A15E34B15768E2B +:10F080002B72BFA459EF5D70A24F1B1A5FFA5F3D50 +:10F090008EBDFFA98EE81FD9BA30B9F3A929C77967 +:10F0A0001CAD397E6390F4C2FD566780BD9F6987B1 +:10F0B000A729EBFA5E4A1983F330C7737AD9785FD0 +:10F0C00035BE96CAC74F810E87BEEBA59BF1B5A78B +:10F0D000B19CF727AAE9F1B576FC085EC64F3FCF91 +:10F0E000D23F877696B854E29D96312E55F0E622AF +:10F0F000DD3ABCD386A7DB3DAF3F8DFB4B29E0C19A +:10F100007DC27170BCD0FCFB5B9DF8FEC24955CF3F +:10F110009A44E92D7E77097B678FFBEBB2B91F25F7 +:10F120009E776514EE5F6C8A306B6353DF42F4B7F1 +:10F13000BC3FD3311FE2F912BF21BDB02FCEE27E1A +:10F14000B527FCA3701E89F5578560BE9BCE380B92 +:10F15000FE00764DBB4CE07CE6E50E19F31BD7CBE9 +:10F1600032ECD736FE4B6C1CECEBE7FB59BC706203 +:10F17000AB5C63BE7708701E9B167D7CA390CA2F84 +:10F180000B2DC4FB9617FB45AC7FA4F38AD1174027 +:10F19000DC7918040785ABABC4C1DE83341CEC9C5E +:10F1A000773075B2735C96B7E3DFCFCF4BEDDFF30B +:10F1B000B3997C5B5C25BA418E35571D4155EAEF0A +:10F1C0003EC8D24E27C635D2F45280CFAFCF1205FB +:10F1D0000A9F3F9C206239C487B17DB3A773AA03FD +:10F1E000F096DD4E32C641CEF6B2F97BCAC8A5C054 +:10F1F000FF7EDD8131C51EDA0FB41BA9FD855E16C9 +:10F2000087DAC9EF331F9362AF80A97AEC818060FF +:10F210009054BD2BBCCC2E7A9FF6CFE2E562D8FF8E +:10F2200011C8A3FD1043FF42D3C36F19E0BF699A11 +:10F23000C6E8C0DB2DB8818EBC091685E0AF8AA276 +:10F240007FB33928239CC784189EF324D6CB97011B +:10F250001E3C55743D8A3045788F3D7CF568587763 +:10F260004F7B67BE354EEE6DB8B84AC7D8CCE9A81B +:10F27000A4EA28BE0F36647D2A230EA013CF30F3F4 +:10F280007FD5CFED7F4EBF1E4E32BE2E86B7923257 +:10F29000D62E2191823C4B7B879FF9794DBAB3F7EB +:10F2A0005BEA65FBF826298ABFA7E06F9509BC33A6 +:10F2B000E3A8E2F71D2A1D914BE838DB2E4AE2EF66 +:10F2C000206C66B7468927785B08CE17374F8B14BA +:10F2D00000DCC739FD1A33D97BEFF671FEDDC7E0DC +:10F2E0003F5149F98AC2BBA5637A21BCDD78D83782 +:10F2F000100A7AA19CC1B1C5E7C5738313951503A4 +:10F30000F0FB0D27BC37E7099AB51F369F5247A27D +:10F3100000EEABDEEF9DD30CEF709402DF53FBFFEA +:10F32000F79B2F6B06FBFFF80E275FEF3AE4E7979A +:10F330001325632004FDB021E3BDEE4475E4B71747 +:10F3400000DF763830DEED78CCF4B76A1EA0FBED36 +:10F35000951BFC400FDB75B102E863815A7B3FC807 +:10F36000A18ED61C0F7C6F8B3B04F85EDA51F1AF97 +:10F3700065B49FD2EA1CAC876F524EC7DB804857FA +:10F380009BF93B2FEA3C928078D2C04CF62E73203A +:10F39000C2EE7751F9C1CE87ABD8BD01B5F3EDDB35 +:10F3A00041BFAA33D9FE5A0DDFF703CCF3F33F7503 +:10F3B0008E4CD2CFA198DE36C7A3A977450E4BF36A +:10F3C00020AD7424A7637C007B8FD63CF655FB1CD4 +:10F3D000C965D06FB9E3E0628027E839B87832BCFC +:10F3E00017CFD7D160F010FEAEFAE68B2624404E40 +:10F3F0001DE7E708F47B01F8FB4E0E9E2BB37CAAB9 +:10F400007C00DFEF53F70F44116EE3E875308FCDCA +:10F41000175D5508FE61B5EBADDBF13B3FB7B4CFEF +:10F42000EB4235FA32C8FFA6DC3C21C6E525D821DF +:10F430007E3E4F7F257B0718CF03297CEFFF88A0F6 +:10F44000BCF7C315CD1CCB3CEE307F9F83DDC72DB1 +:10F4500004598BE7E2B4551EBCCBCAFAFBB0D7897E +:10F46000F51FA9D312C0EF479FA11A361BEE9DB31B +:10F47000F3D241BDB2888DE3EB6E590BDF7D55961B +:10F48000F34EFABF7E6F00E9FCE48E4F51DF6E2130 +:10F49000EC7D0573FC71307E712A8FF700293CBB2F +:10F4A000F6E55C564EFB7FB4BE780AC411C44D3CF1 +:10F4B000C21F5DB7D1D08ECA9FD1AA47FF1A9DE463 +:10F4C000539C9F76F17A9BF7AB2F837CA9FEB70301 +:10F4D0000AD8534FFB4258DE51F58902F4BF456507 +:10F4E000F02F6F6774B83C34A080DF7469BBA06EE6 +:10F4F000B39CC78EE2F098EB5E125571DD47B50BF9 +:10F500001877040683633A37194BE0BBB116909E17 +:10F5100043FA932545F07E35EBF7FD5607D9867AF9 +:10F52000AD1FDE1C23CBDA09C6D950BA50207E6B42 +:10F5300059FB28F041916DA1C86F21FFFE432E0DAC +:10F54000E02869FD4481FABE7627BEC50A84EC3006 +:10F55000E9B638858FF11CCE40F77A1C7F7C25D127 +:10F56000D9FBAFDABF825CF777B934D4AB626433CE +:10F57000EA9BCE001B9F0CB4E2BD84990ECC8FAFEA +:10F5800062F08FEF7A6E1D9CFB2F09B1792FADE2EF +:10F59000EF3289D1BE12A85FA9AA709F22F010ABEA +:10F5A000278DA570D3719602DC420A2F251CAE125E +:10F5B000808BE2AB04EAE339C9C07E98A7BF354F20 +:10F5C000DB58949AC7623EAFC5003FD4BB8ED113BF +:10F5D0005D42E34B78FAE1CA74BEC85960E3FF3973 +:10F5E000ACBE08BF9CE1003D6EE0B8E3F979BB0317 +:10F5F000BE0B70FFE15984A3A4DD95D6BE3D7865AE +:10F600001FCEA3DBA5090C2E0DE49797C3E5ED12E1 +:10F6100010AFDE6E3E8F8885DE69F9E1D788215014 +:10F620007B747D0E7BDFFAD81419FD1FD4787FEF31 +:10F6300047C07F9B653C8FD9FE058BE74E4C917B85 +:10F640003630B92210536E51202B1A656CBFA5922B +:10F65000DD835667E6CC92413EEDEBBC02E543E428 +:10F66000E89D78DE648B2FF0EEF7A0FD5978473ADD +:10F670005E28FC3AEC6FC3B6B8039F91370BE42ABF +:10F6800094072A50FE227F4EB3F60BE770AFB3F714 +:10F69000AD7DFB1F5A08FE63EFFE6831BE876DAB80 +:10F6A000F79CBF04F5910FA247B05E9D03EAB570C9 +:10F6B000B908A63EA9C0741FA43E2F31B258DE106F +:10F6C00072D8CF9ACCA1E9CEEA28BE57E39BCADE16 +:10F6D000CF47FCE7609A84B4B3827FDF1F2B56319B +:10F6E000D53496AA989AE3997AB283D72FF03B3211 +:10F6F000BE33EBD3FFE6B2CA2DD16FDCF66F707E5E +:10F7000076315BAF4669A06611CD373EE3054F38D1 +:10F710007932902880F7B9927E662F9AE391F22B86 +:10F72000D12E86103081BD3F80EB7C9EAF6C2BD0FC +:10F73000F924BDCFB116E5188B873DB28FDA41E7CA +:10F74000C3BB08BA1FE49D1176E078EFFF867D6F9A +:10F75000095E550876D4E6522F11E8F7477D4C9E96 +:10F760006EAEDA701BD0476FB79003F2793BB7A744 +:10F77000B66F5DD50CF1811D1D02CAF197A71D9DC5 +:10F780000FF5127B1C78BF7E56BBF06016EDEFD8EC +:10F790003B6E8C073DF62F9D7550FE97F17421CE80 +:10F7A000E2A70394307B5A4FB3ABE11D78C8DBEB83 +:10F7B0007BF20FA15D37AE2A6A80FC55AB48352C31 +:10F7C0009E06B74F66C0BB287D06DAB9FCBD65ADA5 +:10F7D000927DA7B4A9415CAD1666F9A68624DB57D5 +:10F7E00097B3F384A6E0B61CB03736F688F81B5002 +:10F7F000955BAF50BE05F2B21C6E3B10B23B61DAB6 +:10F800003931C2CE891388E7F7CB6A751FC4EDBDC5 +:10F81000C9C4797BF9AC51A08F86D31727BC5F632D +:10F82000FB4E8DC9310CC177A6F4C766B55F013CAC +:10F830002FE912E0A577B2244C905F4BBA8584552E +:10F840007F04B9DCA07277034139CFE46E90CB110D +:10F850002A7F158C9F6D25FC7DE3FE56943F9D4EBF +:10F86000A62F44CD0176D97283CA5B0A4B71481F1B +:10F8700005F1764BEBC408C4152FE57AC6949F2991 +:10F880007D1595E11CDA94C3391C8E20D70FA30C8B +:10F89000A61F721E62727954174B8F8463789E88FC +:10F8A0001BE1BC945E3BEDD5101F39EDBD28EF4741 +:10F8B0007533B96FAECB48EFCD34774F990578F3F8 +:10F8C000751739E07EF3A650AD0CE934CE3FA61D86 +:10F8D0008F8B08F3ECDE8ACCEEE1F7E18FE5365F43 +:10F8E0000EC86CDABA5806795812A17C05FB93F061 +:10F8F000B29F42B0D14CBE9F2424A6A0BFAE6E05DD +:10F90000DE6BF271F83D95FD3AEE63BBAEB81AF0CE +:10F910005952D93B06EF2D771D265FA7DF3FF3F93C +:10F92000110E7F6522A9805E2A63A2B8A42AA64090 +:10F93000FDA52107C2765C4C12C81F8F1075BD96BD +:10F940009AE747BEACF47D43978BEF1B1218AF6B61 +:10F95000EE1B5A84E87B184F7301932BED9184BE04 +:10F9600048837D039313DBC7CADB800F6FF372BC40 +:10F970000407F0FD7BDC4F507BFEF6F60FE681BFFF +:10F98000C79C9F8BCFCF17EEC7DF53FBE1BD8775B9 +:10F9900080CF53D53B46B0C0B7DACBE757D6672800 +:10F9A000005F259D1FCCBF95CE2F38FCFC7CBCDCB6 +:10F9B000177A3A0BFA4BF563E07AF8134E15D6C373 +:10F9C000DFCADA2DA5EDA01F3B1DB8FD0C3FAB0132 +:10F9D000F65C90B7E976E248F1744F010103DE2A44 +:10F9E0004CFBD5A6F7C0AF847A225D1F4DC82E1AF6 +:10F9F000F4E71916FBF629FEFEE45311F62EBFE8D4 +:10FA000067E7032023200ECEBBC3618C067D4753DE +:10FA1000904FDE5ED19868F15B792BFF9616FFB6AA +:10FA20001A3AB6D0F1E07E94EF437D956C7D3D941B +:10FA30005EADBFBF71D4C7DE3D3DEA63FE4C4F658E +:10FA40005D08F874E8FE93C19B1D72242E013BF102 +:10FA50002296DF3CCD81EF36DCC6F9B33DF898BE87 +:10FA60000847EEAF81FD694B878C7665622BBB073B +:10FA70009798C6EC89DEE427CC1E4FC8183F615426 +:10FA8000B1F729B6CCDC50B012C69919AD745AE85A +:10FA9000C73F33F33EFC62F8C12C76AE2670BF8BB5 +:10FAA00060D50B66DEDECEC5FD2FF807FE2A554574 +:10FAB000FD18D92316AC003E570B307E6BA5DFC175 +:10FAC000FD7FFCFDFC848FF9D792ECF7AA4CFF9CDC +:10FAD000F3400B7BC72AF57B552BFDC83FE9E7199F +:10FAE000A6DFCE358DE1D717943158D1C7FD3ABD89 +:10FAF0004907FA33B684A2B94E8B3EECE2FE27D911 +:10FB000090995F614ABA7DD1EC67EF0BC639BC6250 +:10FB100092D1CD31AE97C58767A05C96FAD877A908 +:10FB200092A0DEA3F339689BC7C7B67934FA01BF48 +:10FB3000A599E761AEE3657EE627057F07FECE085F +:10FB40009727DE8413D77B53651FCA5393AE961B4A +:10FB500094AEE877C7436FA05FA304E413ED37D1F9 +:10FB600061F76B2C5300EE166AFF80FF3DCDBF613D +:10FB70009147803FE8B7998E0776733389AA20377B +:10FB80008C0861F64C9713F1EAEB140256BCAEE612 +:10FB90007ED025805794CF7B71FC8E4831C68F373D +:10FBA000E55E857E274FEB0407B46BE37E9F261E40 +:10FBB00057E30FCB099C47D500DA19DB2EEAC7F7CC +:10FBC000A44D7E30C731E1460EB5DE03E872B2F5D2 +:10FBD00030D7A59CBD5FE384DF412BCAB81ECFE0C0 +:10FBE0007A68E9BF5363AE47AE97ADC3EEBE597EA8 +:10FBF0007C5F6218BBD7B46FEDF6EB321F83DB2757 +:10FC0000527BB52265CF9A7AB64548FCE162E0D7CF +:10FC100027648DF923A2A13FD022E7042FDE6F7F56 +:10FC20004AECF554307F287B7F84D3E1616E4F8AA4 +:10FC30001D33D00E903AF9BCBB0536DF91E9F04D8B +:10FC4000E4A761E870B197C93FF54C11D14759FC61 +:10FC5000387308FABFD404CBAB86CCF633674AB10D +:10FC60005E06FF5011BC9F67F70BC1EFE5815EFF99 +:10FC7000FFC61FC4FD7A44EC0FA5FB79FEDBFD40F7 +:10FC8000CEEC697FBF1F88D8FC3C76BF8EDD4F6409 +:10FC9000FA75E0CFEA2FB2FB79C2703BBC04FC3CA2 +:10FCA0007BFD1782FCAC7720FF1EE77EC877BC7512 +:10FCB000F3203E5D829BE625F04E22FB7D25D19010 +:10FCC000F1BE90C96FA65C37E57C06B93E3EFB2CC1 +:10FCD000727D32A7C39DEB397F058908FAFCA91D07 +:10FCE0002F2B103F5DCEF77F83FA1EF4BC45AFFB90 +:10FCF00040CF4F3E073DCFF971F8FD12E3BFBBE6A1 +:10FD000038DC78DEC4E71B1860694E3F7B6F3140FA +:10FD1000244C3BF93BA481F9E9783DFF793B3DAFA9 +:10FD2000C7F13B153DF81DE0AFF90EBC0733E3ED1D +:10FD3000F47AF38B7E13BC8282983397ADC3603B19 +:10FD40002FC9BD12D6778E88ED2E3C9EDE2E053F44 +:10FD5000AFAF32B8BE7966847A41760E61877FB6DE +:10FD6000E2CA0C7F48CFFD6E3005FF25A1F47A353D +:10FD70008B7E937B7526F8C324AFA63205FF65659D +:10FD8000AEB3C3A531F8BF5D3542BDD2CCF05F3113 +:10FD90007F18F8CBC8A5704FECEA9A11FAE5EBFA98 +:10FDA000BD1567AF7743BD7D1C23EDFECB103A2216 +:10FDB00012CAEF9C01E69709A812A65F9D8E8CE0FF +:10FDC000420B1DD9E961C11409E965281DF1F5E36C +:10FDD000EB30227D703AB2D3C3B9D2919D3E5274BA +:10FDE00064E45E65A1233B3D5CB756427996339748 +:10FDF0006C731665A223D66E44FAE07464A7870C70 +:10FE00007484746187DF4E27FFEDF4A14A4CCE70F5 +:10FE1000F912D0FE5EFA4806AFB0D0877D9DA3D51B +:10FE200073910E86D2075F174E1F23AE3BA70FFBC1 +:10FE30003A9F2B7DD8D73D451F49942326FCF67564 +:10FE40008EAD1F1F60E7F88374716EEBACD175F651 +:10FE50009E3BFF132BBCC543D77BA475FE4FF60317 +:10FE60009F020080000000001F8B080000000000BF +:10FE7000000BED7D7B7C54D5B5F03E679E99CC247C +:10FE800033C34CDE8F49082160829300117CD493E8 +:10FE9000102084A8138818147510C40081446A9532 +:10FEA000B6F8314080840625212258B443508B5641 +:10FEB0006CF05AA508BDC3431A1FED8DA2545B4ACE +:10FEC00003F5D28088B1B582B70FBFB5D6DE2773F0 +:10FED000669208F6DEEF9FEF77D39F3DEC73F673E3 +:10FEE000BDD7DA6BEF612CC0989BB1D63239C66FA3 +:10FEF00065CC19D2074C718C393C067A3AED8653A1 +:10FF0000A63150F6C213CA9BF4ACBC13EA39CA8DB1 +:10FF1000CC6366F4F715FC77F55E28E785CB8CADEE +:10FF2000626C3CD4373377F538C602E5B2F71978FE +:10FF30003BC96C8AA8575DB5D63DCB05E34C968B83 +:10FF4000741E4D3B6BC87D1BBC0F94E9A9DDD4A486 +:10FF5000C8765FE1DF8D9AFA763EAFE97997A9E737 +:10FF6000827AF903E77FCB04D3E0F34F827FE23C50 +:10FF7000CA59F01989B199E591F5FCAB46C4F8F37B +:10FF800035F5D3D8342FCCE3B69ACBCC43C0F18E21 +:10FF9000DAAFAFC7B4F3CC66ECEEE5D1F3E4F88B9F +:10FFA0007E42B70DD8BFDA9FFA54EC327DBF269E51 +:10FFB000F17AB183D79B2CEA05D47AF1502F7F6078 +:10FFC000BD0A51EF88A827D9199FB798C7EED50D5C +:10FFD000B53E68F7D2414FF20CEBC0F5B5AD6235D6 +:10FFE0009D043F8F34C316FEEEB74BF4FDF44A3B3D +:10FFF000534CE1F79B9AB2A630A8EF6C295C87CFEF +:020000022000DC +:10000000794DC3983208FC1C978633659876BC20DE +:10001000F5679F0C1D23FD5ECAA5EFA7579AA97F20 +:100020001CDF573058FFB143F49F7C99FED3E87B27 +:10003000182F8C99131833F07F325DFCFE733AA0B1 +:10004000ABB569468F0E96FA1327AB1D0CBE8634EE +:10005000E329690CD26099D2A3CE03E86005C207F8 +:10006000FA35E8E1BF22F86F978EF835BADE1A1933 +:10007000FAB562C99FA4856F23E20DE66B0EEA957F +:1000800020C25F0FDF0BC2DFB70BF8AF91BC1FF8C8 +:1000900091FED38DDE67803FD7DFC0F1A5D60B8AF6 +:1000A0007A9BEC3AB14E1F43381AAC473F90603E02 +:1000B00006B335A0A3F9EBCFF768E8386867A27EEE +:1000C00048C78AC37019AAFE9A1B381FAE71B3E0E5 +:1000D000AAAC2BEFBFD1EEA1F915EC34527B966A96 +:1000E0000C8E90C2EB05F870FE5EC6F93BCDCC9A43 +:1000F000CC00CF751253AC28B72433BDC73F3BE0CB +:100100002F55CC73FD08F6B47C3594F5EC88A9081E +:10011000F1D79064C57E528C1EAC9F93640CC9309D +:10012000BF75AD2C900DF5D6ADB5064CF07D9D2D6F +:100130003BA883F9AFFB071F77DD9D9EE06AEC5F6C +:10014000513C2EE89F86F2F0764E6C5728EACDB5EA +:1001500007D740BB64D61DC374E1FE194B779C8959 +:1001600065F88A111DDA9D5869001D85E994D363ED +:1001700076B33E4F0FEBFB9C59BC487F6B1C0DA622 +:1001800018783E8D8880F7CBAD96E0EA2C0DBDAC9B +:100190000C851A4768CA06A08341E4C6D1619CAEAB +:1001A0009E7734D4F8E0FB6EE9FE1A9F865EC63B6C +:1001B00039DD663BB8DC60E37C66A417E8F1DD1B43 +:1001C000719D76D9B341C2E76A7305969B64A430EA +:1001D000D69134C3BC08F11190ED233C585EFDEE7E +:1001E0008D5886FA88CF23F67B9AB2A0DCD8248F6C +:1001F0002576664A6521C0335EE0AB2320D3BA0280 +:10020000792C3802D6150C64A7CC83F9E5DAE552CF +:10021000E4F323CD0FCA08E7D672C612A13F3D0B07 +:1002200005F4F8D49D606618EF91B2D3BE1CEC477C +:10023000E2EB9EA2CB4FC1F9B505F5328E77704740 +:10024000EE1B06E83F58263313F41FDF33B7920145 +:100250007E8C8E2C8287FEC4B4B30CE8B435D0619A +:1002600047F9B06B873105F546DCF5FAD33D1A3D09 +:100270007470556E0AAEB375879199605CEBB8C81F +:10028000EFADB33D2976686F61F05EE5F32CFE0CAF +:10029000011F0D17F4D3D56C947BACB80E4D7BA821 +:1002A000E769B14BA8E75999D58574233924E297BA +:1002B0005DB222C720FD9E9448DF3E0DEA5F8BB7FA +:1002C0002637E7F3C695CCFB11D0415E96EC43B9D7 +:1002D000B156C0436F650ACA0515BFD1CFECE6B26F +:1002E00078FF20F2AD5FCE990F871A35F274AD8199 +:1002F000CB19BDBD5BB6033C1C2FDB0B63A12B47A9 +:1003000099676F0FC2BD20A31097A1D2DBD169B945 +:10031000DBE643BD65BBAD5EC487E584E914CA85F1 +:100320005873CB67F86C3B389B7940FEC52E7779C4 +:1003300073601C8B27C19B3316C6B52B0CE1A15FE4 +:100340006EF47E04EFA7FC343FB1E76BE6B961A51C +:10035000DD9B03EB6F5F69A6E706B1FEAB7E5A1922 +:100360007F8F861FAE717078A965FDF21F6CD2AECB +:10037000CFED00F8915C0E265569E4F2A7A29DDA54 +:100380006FF4F8EA77364E499E0C70E89866B46FC1 +:10039000806249554ECA2228EF6C32DA71FD6DCD6C +:1003A000C51BE620BDBFA36323B03C2D376581A6E6 +:1003B000BF8E21FA9FE5E0F8DA951C7842F2A2B8E8 +:1003C00078B8E26DB08176C5049E605866DFAF787C +:1003D0007B02949129AF257952A100BC76A1DC481B +:1003E00001FBA8B5B422806547E0761964F023319B +:1003F000F51B8E4C84F288C06FD136F8938B85CA7A +:10040000B0BF2C5EFF3FDA9F6B0A203F14F0F27BF7 +:10041000AEC60A2C77E07A60FE2EE003A4E78E1DBC +:100420008D4EE49BF6AA71291EE87F6761308941F1 +:100430007F856D496F9841DEB924DE9EB1BF952B53 +:10044000506FA728DFE9F8AF72EC0FE0F3F81CE477 +:10045000EF6E8317F9AAB56BFCEDC8EF9F03BC18CC +:10046000CCA523DD93EC1B04EF2D2B93BC2D239007 +:10047000EEE16908BFB77993BC2F68F8D2608F2C82 +:1004800077489E6484D76E185F0FEB6F3378B66140 +:10049000F9C9D677CBF530DF369B2719E1B1B1F535 +:1004A0004DFEDD2DE01938548EF06C4BE6E5EF384B +:1004B0007E41F38F9E4787C193E2CDBF8279887AD0 +:1004C000FFEA3A8682C3958EFFFF71FBDBD1CEBF78 +:1004D0005CFBCFA3E4C0807EB2AEAC9FFF2E3DFE9E +:1004E0006FFBFFB7ED773BB2496E5E9E1E18D5B32A +:1004F000C8CC8FF2F7B1EAD298B91A39FC7D37D758 +:1005000067D7887A60C7905FB273E314F23383CC05 +:10051000F58609947C53B0D15901F2B1AD45F6A2EC +:10052000A8CBAB72C68C0079D6E842A90BCFBF0F1F +:10053000E7E572D9BE9AA13D5C4AE56013AF1F742E +:10054000C9E5A4BF5DB2659E66FC60397F0FF651B8 +:10055000B2565FB4097DC156C08CA09FE6B4EC8E44 +:100560000D1AFBF06E611FB43597BE91877A09FDB5 +:100570000B0FD855D3A674A15DD706769A89ECB433 +:10058000ECE61CB4D31499E470AE287B14BD178A32 +:100590006C244E1EE30176160C41FD8E96979691C3 +:1005A000FD8B460FDA55819E00B83CECA0EF9E2EE5 +:1005B000B4FF8249BC5F6605A502F68F13610D1D6D +:1005C000ADC37E50FF79996ABFDB0AE13BB9641E77 +:1005D000D4F3D60D39A80FC02E447DA9DA6723DDE8 +:1005E0005904F76168BF41B9A349AEC0F93DE6D5EA +:1005F000338C4FD82B3576171B68BFB90D4CC1F91A +:10060000BA4719830118D71A65A745DB63FDF68041 +:100610000FEC094DBFB179F688F2E727A6821105E4 +:10062000EDCDD3B77D04764BEBEBEC69346E77BE42 +:10063000CEF631F0133E5EE9DB86F639DBF4386343 +:1006400060F72E1270C891EC16740E74C30B3D68DF +:100650001CC6E83699F199237B1F2D81F1BB5E4CB6 +:10066000993D1FE6BB6C472CE163A721508CA06E1F +:1006700034D8B7A17E7DF0B1E1CDA89F5A0DDDCF72 +:10068000A3FE92D9BE0DE5E08BFD44CFF1D4E1820B +:1006900075A2FEEC7CF9DCF3488F7633D1D723E5E5 +:1006A000CBCAD18EEA95B95FCBF4BEA42AA0E33DB4 +:1006B000BB8D35DCEEF191DDB36BC70D7938CE6BB8 +:1006C0009B7FDF1C03BECE1E59127605C011EC8C39 +:1006D0004ED4FF546E79B34C4FF62695E7B4FD6ABD +:1006E00003EAC5B543D8313F7473FFA23368137A68 +:1006F000B56B4309B4DF53CA44F964859206F6C367 +:100700001A49D80DEF6D50AEC7F19928C35A01862A +:100710007B8C6AFD3F56D4D27769BA0E78D3D67EE9 +:10072000A8D93A313CBF6FB759DF44C2DC23DF5F41 +:10073000EB1B643E6B8789F98CE3F127685713D470 +:10074000D81B3617F79F93C5B3335820A39D93AD9D +:10075000E776B5F7608E6591A6FE0AA72522CEB38F +:10076000B727DBA29523F52E319E9EC5FE16F034E9 +:100770003C60B4AF02FC0E0FDAC8EE31A419990444 +:1007800078935DDD45F92EB4AFAD0C288CAD9F0C90 +:10079000AB877E8213838F5C8BF664BAEC0DC0FB53 +:1007A0009D362BE1AD6397AEFC59847BF0AA32A451 +:1007B0003B75BC3562DEEB9B8AFA6AA1DD39ABD5AD +:1007C0002E79904EBC35C8873FB11AED01EEDC267C +:1007D000A33CCB91832968FF3CD536ADB911E09A93 +:1007E00023E03CCC7D4B33DA8F1DF6CE9BB3A1DDED +:1007F0007AF0A770FCF5AE19669C57ABAFC18CF4CC +:10080000F9D2C186F22CE4DF11325B0DE3B49670AD +:100810007F21C7EDACC0F5E5AC05C743C35FA35C62 +:100820005CAE7678855C7009B9A087798CC3F8498D +:10083000B117E599C9CE8A705D86B4064519048F53 +:1008400013443F0CC48DB598588DF82CA1FCF8F7D3 +:10085000515EF41A3B7F8D705BEFB0783BE07D30EA +:10086000A6330EFB4F705A645C7F2283FF0750351E +:10087000CA8017E497344678496C31521C23A1C5CD +:10088000487E4B5B934CFCB5763E887C98576293D0 +:100890004C71D8849ECF56E238492E396404FF3219 +:1008A000614E64DC35E9C4D97FA0DF99C43471435B +:1008B000687F9DDDF7EF4EC08F294DF87F58B71840 +:1008C000FD48FE676992297EB47B1587CFFA875968 +:1008D000107C04FC6E5E5EC4ABA37C358AFA3B7F61 +:1008E000C65E403819CD2DDDBA380D5C9773B81A45 +:1008F0005BD6DD8FEB30E645C659ADEE04825F3A3C +:1009000003E90E72E863C6F901FFF4F029037102EE +:100910004B3FDFF9C718F4A77A8D3C8E40BE47B134 +:10092000F0E7B3C3F8E87172BD13DD4FA6C4EBA9BD +:10093000E5A718EF77CF11E774A4F71F2DCF2E444A +:1009400079DEA8CA27C6FB473586F871DB2DCA2891 +:1009500098FF4117EF7F8FA56150BE3EEAE2FE523D +:10096000EB1B805880C79ED59E6FA31FBAFE1199BE +:10097000754057075B78DCA12DC082A8A7DA14EF79 +:10098000B14AE4AB06BD3780F2368FCBD19DE59EF0 +:10099000E02A11670AC07C6D62BE3BD3BC161DB451 +:1009A0005F3B99D93B008FB632A6C460BC4BEFDDEC +:1009B00080ED3C654E8674CB00C632CC3F56B4B356 +:1009C0000502F7231DB4A6B1DB097E7A8F545510BA +:1009D000868755C031B61CEAA19FEC7AE5218CA729 +:1009E0007594CD602877AC2E18278EF78B444EA1D6 +:1009F00026C09735C0EBC55747D21DC949A4FBA5F2 +:100A0000403738CF0991786F13F049D5B37223D0AE +:100A1000D32A945F688F2CE47089F546F567F1243A +:100A2000D7121C8D0CF9286345E4F794968452A4E0 +:100A3000BB34A6790FE3E60E7310BE52BAB6CF9060 +:100A4000615D6B6B99ACC3715940A92DE2F841B956 +:100A5000B17E8A4CFDA696394B8D6368FF43413CBD +:100A6000396AF33B301EA6E2D7E1B24B45F958CFC5 +:100A70005E9A3B86E2B49CCE1380CE61BCD4AEBEFF +:100A80006F23FC52EAA2F73F34EBD75DBE6C30C750 +:100A90000562C7601C34926F535D59229ECEE98275 +:100AA00087AAF1FF789C551FE7D980F6165BADA7A2 +:100AB000F82CC618D3608E8617E44022F46782278C +:100AC000CA0D43A73E30320EED0FA618F17BDA3F78 +:100AD0004DDAF9EEFA593EF9D51D22EEA213F6A928 +:100AE0000A870F8719691E1F0A3D56FA6ADA248C95 +:100AF00077AE4D675E1E6FDB4BFCF3A0987BAFECCF +:100B0000DB1A8B70FAAD89A13C28EA0ADCFE16D408 +:100B1000B797318C14B3F5FA06B343A3CF60EA411B +:100B200039E95F7FB6097BA803EDA1788A77DC8E6F +:100B300078EAEDB0318CB73A42B2AAD71554F1FD3C +:100B40007646604F732DD80105BAEED166D0475B6B +:100B500036BDD55C968EFA37FD2A3DC89C2F375F8F +:100B60006C368CD7DA099F36A3DD30B49D20919D79 +:100B70005098A6963F99A600D03BCD6A79FF1BE816 +:100B8000DF371A022FA24CDBEB6281B20928E7D4CF +:100B9000EFA166FCBEDBC2FBDFDB1E6A0EA45DDEDE +:100BA000EE60668F05E9E17270EAD07B2CA83F3BCE +:100BB000101ED0BE7ED88169AB72C2764BDDAEEE20 +:100BC0000ADC6F50F1B254C8D7B5AFB34EE45FD56D +:100BD000DEDCE936CA28443C41A3121C442E6E1EBA +:100BE00066A67606ABB271D8F8CBD3D766A42FA091 +:100BF000ABA9C3F87805BAC1F7A59E53BFEF343649 +:100C0000A0FD54FAAA95E4485BF3ACA731EE5A3A3A +:100C1000327F5B2CDAA51FDE66C0F28F87E9A9DF81 +:100C20008E9FFB47DAF93E530AC209FD7F82C3CF8C +:100C3000AC32C67F07C04BAC2BFAFD8F86C508BF10 +:100C4000CC73FB2117DF57D8E009EF7345CF77AF9F +:100C500098EFDA954CEC33D9C99FCB71FB14DA27A6 +:100C60004AF207707C23D81583ED33E92FA546ECB3 +:100C700033EDB02B0CEBEB2F65D0FB58BD6F1FC2D3 +:100C8000F7895726DC8CEAEE09A1CF96D895FDC3EB +:100C9000DC18DF1A97A7D597D1CF2B8DEBBF25F6A0 +:100CA0009BFE553F648D5171A25EDDC1BC5EE77055 +:100CB000C4FF262FEA9366A664E3FBAE17176D2ADE +:100CC000413FE4573A9227AD938BC94E55F9F772DD +:100CD000FE4834FF16298CF6B5F47A5686F26E0972 +:100CE0003A7E1887F7703BC77044A6FD6C9493F862 +:100CF000D431BF82F6B02A3FF4413D7DD79D300507 +:100D000050CFE89AD675A33DA3B7FB285E3C56F6B4 +:100D10007F8C70679B40A426703589EBD45915866B +:100D20007EFA50F241D7FEB3694DC0CFBA23965335 +:100D3000D46F488C7F623DC5A9D956E8AF38DC1F17 +:100D40008C7311F168DCEB0BC56AFB177ECC979BAB +:100D50005F6A0E5CFF35FDB50CE84F728D1FD89FA2 +:100D60002ADF4E6EFEB76981AF9BDFD303FA8B1D7E +:100D7000B43F21FF7EB7F99566944FFA10D7437AB6 +:100D8000EC179FD81FEE8F003CD15E817EDCD80F20 +:100D90002B9322FA4737D0671BE82FA9CF6F3BB9B7 +:100DA000DC88C6FFEE550D3583F1E304A1BFA2F543 +:100DB000A601F56611D797891ABA30A1DE1C33B4A3 +:100DC000DE2C41BAE2FBBB4407AA7EAEB4FBC7E00F +:100DD0007A4C2EBE6E531A93789E00F77FFEBB7E30 +:100DE000C88F855C0EC6782CE5E85F4C91ED684FA6 +:100DF000AA7EC4EE55F66918B758BF4AF6A21DDAA6 +:100E0000EF3F08FF42F5571A6526EC53B903F75533 +:100E1000C1EF984E7E07F825B819B913E61903FCFF +:100E2000D0DA5274AC12EB81DD4AFE4EB4DF21FC05 +:100E300091A4F991EFAFB3FB7D08076BB94C766BCA +:100E4000306F5908D7B9A18C513FD1FE41B45D191B +:100E50006D4746DB89D17661DA035176E237B6CB4E +:100E6000B85D75A5F619FE0D6697919D48FCBFBD4E +:100E700019F1477E1594335DDB499FAB7917FBFB76 +:100E800064F2CF3B02094EF447820646F05FBFD1C1 +:100E9000E3C4B8CA0A81E7DA78AF8CFE22389076CC +:100EA000A457D9C5AC5EB4579BE442EEB72BD642EB +:100EB0008C8735CB45A4AC26825F3F0EFD342BF9E1 +:100EC000CF3B6D2F3C722DD21BF8F3B47F3A841FB9 +:100ED000BF41F053C9303B8DAB336EF2E6631CAEBD +:100EE000B998F62B771ABC14AF7E49C43F5F16CF72 +:100EF0009962DF48FDFE8A8893EE1DE2FB3EF17D9C +:100F0000BF78467FFF8568171AA2FD21D1EEC81071 +:100F1000ED8F8A765D437C7F537C7F7B88FE7F2DBF +:100F2000DA750FD1FE5DD1EEBD21DA1F17ED3E1847 +:100F3000F09DEBD7DF8AEF27A2FA3F29EAF788F77F +:100F4000B31C1E6EBF0CB11FB63B8BCBB9BA23DDF1 +:100F50004A565C188F8B9C5CCEA9F6DC65E356C2C2 +:100F6000BFC5BED18F2491363CDCDF59A7DCEF87AB +:100F7000341687FD47558E0D1FC7F332543F54F585 +:100F8000174DC3F8FCAD2DC26F659D24CF3B104EAD +:100F9000F943C3F95994CDE3695F90EC45A4BF7B55 +:100FA00035F2FC7997817F2FE4F00CC3275756E187 +:100FB0002343FD97847F3ECB21FA7384FB9BA7E9F3 +:100FC0006F0BC6AFC687E735147DB6B9B8BC57EB13 +:100FD0000D45471D51F586A2E72D629D6ABDA1E82A +:100FE000EAF9A87A43F1D72351F586E283A7A2E66E +:100FF000F7A2F8DE299EEB449CEB72F4174DC71D57 +:10100000EA3EB06336C567F14F1B6FB036713DE005 +:10101000667D11F411C7BA79128BA00FC3A52CA657 +:101020008C25A14AFAF26A9787FB137A1F43BBDD2E +:10103000702987BEABF9254D9ED54ECCC758EB72B3 +:10104000155237603760BCA346D06DBFFD81790172 +:10105000A8DF5D7EBEEF1FB6E746B891E88391F644 +:101060009C6A7FA871E71FBAC74CA3FDE9714CE1E8 +:10107000F924668A03809B91340CE364BA4AEF0238 +:10108000984FAE93C7432FB75F70B9FD81CBED0B7F +:101090005CEBB6511E0768532FEAA9293FCD6F4379 +:1010A0007B60D93B3A8AE7E76C52C80F7EA847F2CB +:1010B00068E31AEA53CDBB50F319D4BC0B35CFE12A +:1010C000317D6006B65FDBE294303EB554C4D50F87 +:1010D000BA6650FCB5A35A267BBDA3EBB1F21198BA +:1010E0004F5426DB116E4D2D456FA27D150CEA691C +:1010F0003FC0222BD330EFE6B1EA6C0BEA11DC3FA4 +:10110000D3FA1DB9F68652ACB7B3BA94E2BC8D7F60 +:101110009F644679B4DE9E1DE3C1B82FEE4BC1B388 +:10112000ADDC19837C1BAC8E7CDF5A36F87E55F41F +:101130007A2D422E76309E7F79D5E1D95598473168 +:10114000BCC959184350F5519CAC50A59BE53ACA0F +:101150000B7137717F6138F85F887F355FC4CD349C +:10116000F8C1508D93D373014602D0066000478DBD +:101170001D118D4FB57E345E99DE9B877437D5691E +:101180008F90E343C9FBA9625D0FB8395FF7E32D88 +:10119000A8672897557C05ABF9BE5BB0CB4072FBC6 +:1011A00073A05F96C5F72107CBCF51F1748DC313A0 +:1011B000B18FADE26B972140FBE887763C9884F9CC +:1011C00046EB7FEECFB40FD28FFA7C47E4E3017891 +:1011D00062D09F068918234FF846FED036F720FECE +:1011E00086EA0F1D707BC9BE1ACACFEBF7EB84BF2E +:1011F000A7FA771A39F0AC9BF26BA441FD3A753F20 +:10120000A9D57DF51B819CFF517FF267247FBEA18C +:101210003F79A5FB52DFC03F7C7D30F8AAFEE12E6E +:1012200077E137F50FFF63507C5D2E9ED59F37AB7E +:101230005825E8AF8EA97FF7539CF13B82A7EA447B +:101240009EDD649D95E8D9F2B444F1E4C5019EC7E2 +:101250005E17587D3FC681699F03E87FE15A46FBD0 +:1012600095F09DFC21B5FDE24E130B69E4F2D29797 +:10127000A1ACE1C72CC6F3C81682FD1FD2F07B16C5 +:10128000EE1BC7E1F7C8F74C37271EF18A39958363 +:10129000E5632E3F51123AA2E9FF2FAA1CBF865DDB +:1012A000437E88683F141F5D5CA9848E18306B599B +:1012B000F9D2ADE14B869BDA00CF0DA3CEE40DC68B +:1012C000CF2A5CE72D9FC4FE08FAF315A3BD04F3F3 +:1012D00040034F49E407CF13F975D70625F2CFE64F +:1012E0007DF7ADCD18E799F891D73817FA5BDACDCD +:1012F000E32A89BAFB0B1F86E76387D8DD3E51BE20 +:101300001FFD5BABE2C17DB1B902FFE70D0D857634 +:10131000CC2BBCD3AAA09F3BB75AF910F70FE6CE4F +:10132000C93723DCE676C628F43433BD05F5E7DF9C +:10133000BFA27CE07B05B6E7EA9919DF271A993E40 +:10134000069EAFB65719318F2FD1C2CC582E5E0DE5 +:10135000E3039CE226F8687E73F7FFF8AFD8DF7DE1 +:10136000FAD041CA9B1679D973F7BFF125FABBF7BA +:101370002A3E23C6CFAEDA651444CAE15FD01959BC +:10138000C6F30CDA726128B23CB62BB2FC186E04BC +:10139000025C5FFB878E611E68DF73B1B40FB21809 +:1013A000ECE36F39F93430C6B0E827053B30BFF5C0 +:1013B000957F7EFB0F0F43B9EF573AF2CF5F190DC0 +:1013C0003630C24F1FCCC0F99D7BE2C74F7D17F767 +:1013D000519F4F440F901DEA7D2917F7D32FACF48E +:1013E0006D2B03793C69F1FE0C94B717F6FEDB53C5 +:1013F00048D71FBF68A238D9C722FE77F0B7FBCE07 +:101400003C81E3BD185B88FAF9E3DDAFE6227C1688 +:10141000FDE44006EE139F7BFE27C5547EFEB931E6 +:10142000F83CF7DC8F73E7929116CCC07D79B59FBD +:10143000C52FC49C1A86748FF13ED077673EB15A8F +:10144000B5FEE237ED7731C67DA9DFF5DDC390EF5C +:1014500076D902F85CB4EB079FF1A7F40E7FAEA239 +:10146000EF8B002213007E676D5C9F2FDE658A8004 +:10147000FBC8AD9178380BF6CB4B506F5430F2FD72 +:1014800019B0075E8271F32ECCA940BD7956D839C8 +:1014900067E0B907EAD7C37B07BCBF20F611A3F901 +:1014A000A63681DBCDF57B23C7DFA71FBCFED204A8 +:1014B000AE8FF370C754231752863897F14082C815 +:1014C0009B7EBEBFBE8EC723808D80B6160B7E7AF4 +:1014D0004D52CF4BB00752814F1623716487DF2FD7 +:1014E000669A75C3787F31C775D841FF648AF95C05 +:1014F00034707E3DB732B4F923901F67562A4A995B +:10150000268F69C1D6FB8F2603DDD4ED7117514EAE +:10151000B9785FF7DCE1388C638CEEE4E780CEEDE0 +:101520003ABCE55EA4CF4E0343B90EDF13F0FBF9DE +:10153000CED7E3EE80F70BB63BE83C8FDAFEBEADCC +:101540009395328DBCFBA6FCA7CA853A3B87C3ABFB +:1015500013BAA7A4029F2DDE2A79B1DAE2CE5B6727 +:10156000DE843ECD761DC5378AF5CCA72BC275FC2F +:10157000EC680ABCAF3F30BE18D7035D54E3FB0DE7 +:10158000B26F7A01CAA5A70C94EF0CEFBB64A0B3AD +:1015900043796DC6D3B08E5D02DF1B66596BD1BE39 +:1015A00084FE8EC8D02EEE694911E50FB07E6F69BA +:1015B000671CFA2D670DD626291EE9B4E118CE2343 +:1015C000B09BF7CB427CDE0B451CBC76BF81FC9008 +:1015D000FA67D6C495609CE49F3A498F72E01989F6 +:1015E000E4C07D5B23E9AB16FA4E8271CFEDB051BA +:1015F000FFE7DCC10CB4AFCED982194EDE9EE45FAA +:10160000EDAE5F7E89F26E6130B27D343DBC9D20CF +:10161000A97E7C9E96AEA2EBA124D21787BFD72DC0 +:10162000073DA0D987A8FB689311EDF48595C6AF57 +:101630001D0FE89279081E31E4272D1ECDCA3C3CCF +:101640009F403243FFE7F05FE0072E9EC1CAD5F707 +:10165000B46F80740D24FB9713BF7C4407F49D8204 +:10166000C8C3F8D74F63295EFAF12746D21BE77A41 +:10167000C1A080752F4D9AB9AD4C33BFF37B0FC716 +:10168000E1FCCE7B42714EF4E785BD7FDECECB8B95 +:101690007B3750FC7955E7E13894AB8B3B87D17EA3 +:1016A000F2BEDD925306389FEF7D36960DC2A78BB2 +:1016B0007AF97E71B41C52F5EA29FC27E8DFCF12D3 +:1016C00094F30968BFA07305FA3F71584361C320C2 +:1016D000FDA9ED3E4FF0D073AEC4DB27EA9651FD75 +:1016E000CC64DFC504C0575269B782E785922A9857 +:1016F000770D54F9A3CEFBA07D38EA49BF91FCE6F3 +:1017000046378D731F03BCC0FB797A16D2037DCE9A +:10171000437D3B86CA04BF79BBA4209A72B6165398 +:10172000C47ED38276286BD7B35DF31DE0BF10F57E +:10173000691CEDE784300EBAE8E9C8FA8B5988C60F +:10174000AD7BE12B93B65F346839BD2946F467FE63 +:101750002AE09399ACD813E1BD34C34CF3FAF66E8A +:10176000B0DB803E5C228FA0EFB178CA3F592CF4E9 +:10177000F8BDA683B4CEFAEFCE55E6833DF2E9F28A +:1017800079CAFC6122AE807CBF55E2F455C642E9BD +:1017900030CFDB857DB378BF142A80F2BDB07EB434 +:1017A00023AE7D410AD8407FDD6B668138A4B7F750 +:1017B000387EEAC4BAB05E7C11C23140E38D4EF48B +:1017C000D0FC17B26E233F5C115C9300E32DED0556 +:1017D000D900A5AE83C5F1483F7F61DE78E44BB008 +:1017E0004B588C73209EA3E15BBB3D0ADE5A7866A2 +:1017F000231C23F1B3F46580EB20F4F69890FB27CB +:1018000099126167AAE7EB1E5B25717D11A89A8D7D +:10181000F27ACBECE262DCAF7C14E36129A2A3098B +:10182000280F999A771732C33896B1FD65FA5EBCD6 +:101830009A97CB1FDF397D2BF81B5B0CFE648CC3A2 +:101840006CA902BB97DB2D3168B754A5F86F42BC79 +:10185000CED3F98EE216FB47254A2ED1E7720EE76A +:10186000C78B1A46357C8D5D9A0863C73AC5FCD094 +:101870008E2AB0121D24E39CE0BD2D83BFB78DB12D +:10188000D0B9A944191CC941E0AD3E13F5E0AE3B07 +:10189000E9C96CF884816C5F535FB51713D1684256 +:1018A000BB7374C31EA4AFC4BBF28BD66485E7B907 +:1018B00045027E44BBF9617E5E2676FF9E502AD4A7 +:1018C0005B52EEA1F8A3FBB6137998BFF4BD442E8A +:1018D0006FE3859DBC4D628D181748023A978AB018 +:1018E000DC9ABC0CDE8F7B5922BB7AC9CB25BA258A +:1018F000565A3FB7AB631B76C838FEDD79343EE0FD +:10190000E5EE19F07EA5A0CB642BA7D7A4D5812C3A +:10191000EC27FE90EFFED7096E3CFF0CE149EB3659 +:10192000B326B49793D82A09EBAD7373BA58379797 +:10193000DB45B84517EFE4CF0FE009DE6FA381C3A5 +:101940004D6FE1EF1B719CC7E2F8BCDCB2EEEE2AF2 +:10195000B4FF8B78D9B942523A88195B391E4DAC25 +:101960001CD789EF715D300D658F5503DF490D85FB +:10197000388FC4E1FCF9768F3980793A6FBB543BDC +:1019800038646564E7F864D4070F08BDFFA94149CE +:101990001C8BFAE41D03437FC59511553F278FD754 +:1019A00017FAF673EFA47814129F5B9578073CF74B +:1019B0001AB8BF108DF7DD024FF597525950A34763 +:1019C000EA6BBE207FA1FE5246C4FBF32B612523A8 +:1019D00035FAB0F6109D1B5DC2BA29557949A78E1C +:1019E0000535FCBB37868F7BF1F7269257DF6E1EDD +:1019F000DE81F67A34BFD65FD2B100F0DE753A9957 +:101A0000EAD7D718299FB8BE49B703F7E3EA2F19D9 +:101A1000F9F74CDE5FFDA5612C807B907A4F1C9E10 +:101A200067BC4EF7D9BA7B11FF0724CA3FABBF94FE +:101A300040DFFBD773498A2CEFBD28D6A7E7FD4CC2 +:101A4000E8894339ADDAFB95A05751DEAA763563B4 +:101A50003D7108FFD37B8791FC3BBF120429C0E195 +:101A6000B438CF7C3A28074668FC83D36A5E9E98D8 +:101A70005FF4FB0BF61ED2C7293A7EBEF882879729 +:101A8000D57AF81DE179A1469533213DE2F309EFBE +:101A9000413DE693D4790F4E611ABA0AC33F16CF7F +:101AA000FAF5C33F614D77480699F2E9E35FFC2000 +:101AB0007F1490E82121DF02977E80F93C093A39B2 +:101AC00042DE61EE929A878CA4F498ACE3F232F095 +:101AD000E50FCAD2346551BFBF7DE0BFA6E3F77101 +:101AE000F9BCFD978FFFEDADD514CF107A50DF977D +:101AF000E1B369CAE6A8B215CA059AB23DEABB2BA2 +:101B0000EA7B5254398DD7BF2BBE67BC0E7C4FFD8C +:101B1000D6AFA6E379A3BB527BBE83E7B95A7472F2 +:101B2000651994E78DE3F26BE97E89E2B32AFC96AE +:101B30007A19D9B7566F8F11E3ACB1E3BC4765A8EA +:101B400057B757A27C5E6BE79E10CAA33A6CE7D1E9 +:101B5000B4EBE476715DE7296A3764FF7932C983B3 +:101B60000D79A7A9DE92E59F18D1CE6BCA5FED4330 +:101B7000FD3A56E6724DCFFC4A2AF0C7D2BD558CCD +:101B8000E7AB72B97B2159398CF3091C90681FB4FB +:101B90009F8EB15F6B988FD4FABF2BD8FF3EE6C5FE +:101BA000C43EF0D92A3DD4FFFD923F8DC7F17E8718 +:101BB0005526A21C0F8E42FD34A7F69E51F8FECE8C +:101BC00025230EE2144E1A7A9EC4FC92495B132B15 +:101BD00031DFE4A4AD271DF39527276557223C4F3D +:101BE000BA7B9E4478EE4F1ACEBFA7F7A4CB50AE77 +:101BF00048BA8B9747F43C89E5D55B4B78FD829ECC +:101C0000741DB42F0A9412FC9FB173B9F914F8D95A +:101C1000287F7F17A5BFAF4DE2FEC7A32395F149EB +:101C2000B89E3AAE3F9F045FCD0C72F5AE277A7630 +:101C30003F0370B8EB7BB1B4BFFBCCF999153E0EF6 +:101C4000271FDAED899CF4357A544FF108558FAA95 +:101C5000F8B065747B48CF44E9B97309CA81247729 +:101C6000F8B92D9B3F0F2479445CAEA1D003FDCE83 +:101C70009963F56EA0FC859EF148878FC6F07501CB +:101C8000FF109EAD022F3EB11E5F12F743E31227F5 +:101C90001FC075817F1030233EAB8C64BFB55729C0 +:101CA000C916173E13285F3A1C2731907FD42ECED9 +:101CB00043B72F194171BC7EBF6033F72F54B975FC +:101CC0003BCA2D8D9C6B5F382919E55C7B96928C05 +:101CD000F24595AF4CDFE9C678BF2A4FB1CCE5A8F5 +:101CE00044E5B0DC837A9A739A7718988FEE6FD8B0 +:101CF0001129EFEE90E07D7EB89F2B7DDFEEE0F3C3 +:101D000052F569E29A4EDA5F4A7C3CCB4976072A63 +:101D100066B4DF5A477620BCAB5266103EDAAB9E03 +:101D20008DB9273F4CCFA191CAF7F1FDED227F4E2F +:101D3000A51BFCC338DFBCCD893B30BFE480C0C3EA +:101D40004732D867C07705290AE1E300C6E4E9C94C +:101D5000F71DE6B09EEF207FFC2F9EFEC7F1D489D1 +:101D6000F0FE57F1B464F99FAE4C6E0ABEDC2285DA +:101D70000C895C6EF2B804BCC7FB20EE4BF41FC6A6 +:101D8000F9A9EBBCEBFB4B92294F49CC27F6A157A5 +:101D9000CB6F83E25D8BCEF5CB1BE66103ECF69354 +:101DA000BF35B7605CF0A4B193F4C349F05357A1B9 +:101DB0001C1571C49362DDC5DF5BFC36E54B27F370 +:101DC000FD768C0F302D5D357B7FF3F0A0F4A5E31D +:101DD0007EE1011DF903ED85C16D0BF0FBADF994BA +:101DE000471F23E808E88CEC25F67D1E27681F7145 +:101DF0009AE0D93E91D1B9B8F62CFEBD7D762E9DE4 +:101E0000CF02FA0A907C9C6DA17E99F0933FAD4978 +:101E10000A22FE80DEF8B80B65929F2ADDF6D7CB4A +:101E2000C90E229E06D2615F5C95867E3E1571C208 +:101E30004FD13E8AD7BC177109B00BE2B4F7735C7F +:101E4000EEBD4A87096B547EE074F7515B22C5975B +:101E5000C16CC9453E302573FA51E571418A5F4E28 +:101E6000766BEC71352EF0683AD1EB7A1BA7EBED6F +:101E700031FC1E0C533297F7EAF8DBC17F41FD03BA +:101E8000FEBB19FBB91B9AEF85F2DD89FE5FF4E01A +:101E9000B8CB553AF61991EEEE157103B622D2BFC2 +:101EA000C5FCAAFEB26E607981C2E3E603E212ECE1 +:101EB0009FA6C876DCEE89CDEF3320BD3F1EC3FD63 +:101EC0004155BF6D95245ADFD6EFC6D2FD196ABDC4 +:101ED000BF9CB7C898CF3C42ACAFEBEDB1F1184F07 +:101EE00057FDF868BF7E292E01FAAD87B1311E5D1E +:101EF0006FE921BF568D57F87FA0A3FB32AED3F117 +:101F0000733B7D3F93889EA41966A2B733CDBA1D5B +:101F100018DFC0F6B8AEFA1CC6AE77227D0517A250 +:101F20003DD3B7D0C238FDF917E27C4FD78C664459 +:101F30007F82AE60BC0CB283DD3D14FFAB4788618D +:101F40003F817FACE4C93680D284F03E19C6A9B582 +:101F5000F1830BF01F9E7F50E917CA018C8386E93D +:101F6000D51387F45227CEF344DBF3C43D09148F15 +:101F7000A7739897B3EB97CAA7729769ECFA687F33 +:101F80000BE1797D113D8FE8085F3DC53EDB20F513 +:101F9000E4D3D4CF50FEFAD2AD7FA2F34EB85FA700 +:101FA000A593BA303D495F49386F0D7D69FC78B221 +:101FB000F3515E9431BA17C626CAB1E5DD744F4BB2 +:101FC000BD8823B90FF54C413CD8C67532F4EBEB14 +:101FD0007B393F5DBB7FC761F4FB1DE5DDE988BE52 +:101FE0007A112755E94F9DE7C4FDAD3AF4530E7DB4 +:101FF000C2E9AEF4F4DCD928BF5FB32497627CABAE +:102000002AC5FF9DE4F19A7809EB24BA99F7B864E0 +:1020100047F9F29A93297682932707E154EAE4FB81 +:1020200028259651F9FF09CF43A7B3F20DD0FF86BB +:10203000649EEF3E4A5656207F5E18229FBB299928 +:10204000EF37949E8CF1A37D566A892139F968DBBC +:10205000C80E535678FCF95BB29C387E5332F78F2A +:10206000AB527C4DC964FF798B91BF1F4AE67982E0 +:10207000A5464F0ED2E76B96C452E4F769EAFE5BC1 +:10208000A02407EFB5294DE2B09F6636856CB42FCA +:10209000B76914CAABAAF9166E3FB24AA2AF724131 +:1020A000BF1BB3381E364EE3F1CA6352A70BF59C33 +:1020B0006CDEF400BEAFC8B179113FEF488E748C6E +:1020C00093B28506C71973F81E9CA1E80505DE19B1 +:1020D000952FA0F24609F481939E14EF816700CBFF +:1020E0005B2C2C20A11EB798C87EC1EF3C9FC3B3C8 +:1020F0001DF560A5D964C7389A0DE366BCBD82F1B1 +:102100009C4AF32F3FC075631C10E5277C57D47E93 +:10211000F977D689FCC5BC86F3DA7B9AB6C5F0B8E8 +:1021200021B40BA07CB5E1B147DE2EC4C74D739C32 +:10213000B92ABCBE3586CE429C5F6089D58B7A7346 +:102140007B49C094E142B91D5388F1E1A76DC69067 +:1021500013E67148C87F9837F985A7053DE4C4198F +:1021600043B82FAED25F664CC921C4AB0A8F35315C +:10217000801FD4CBF75ABCA847711E623E11700A6B +:10218000C385C7ED2B69A8305C806ECBEC455AF84F +:102190005843B88F1E0D97A1E0A1AE03E7EB8C1B4F +:1021A0000897ADF29EC524DF2F58BC3C3E1705278B +:1021B0007C954CFAEA24F2D752E6FF167E5C6A66FA +:1021C0000AC6B31698EEA7B86EAD889B330C16827C +:1021D0009D7201839700CF0BCF4BA437705F462BC6 +:1021E0004F719F455BAE53E3C3BBA2E2B842FF2DE4 +:1021F000C1F8323E3B23DB81E4273D59BF373A6EBD +:102200001E88D0DBE1F819E78B27B664917DD8836F +:10221000C09E882F57131F625C8EDB034A32C68133 +:10222000B62CCC2EC2384DAC9EDB95F76E1AD9B1C8 +:102230004AD8076857A8F13C959FAB524A63526051 +:10224000DC4B29A5FA14F43B312834F1EBF889CFA3 +:1022500053AD87F1BCAFDBE75886F20FEC1F578A0E +:1022600087E65BFEC68844D4BBCB244F22D7BBB9DC +:1022700011E5333A3FED73A8F1F885B8CFA00BC351 +:10228000758188E32F50E3F65B23EFC7433C69CBAE +:102290008B3478D2DEAB5757C642B6283C69DB2D6B +:1022A000053C613BC453443E793B5FF7DD424FA898 +:1022B00074EB58B143C734718BF822256B2DEAF9C2 +:1022C000370C1497FD4F4197808762B41333934BBB +:1022D000E310DE16F477F2D1DE67B5886F8C03E386 +:1022E000BD7917563225C740782D9E31889EDCB0C7 +:1022F0002FA616E9E4861439C25EFB3C99E7C95261 +:10230000FC1EED926693B0733D19D84F71B66A3FCB +:102310007A687F7EBED89F5E3ACBEAC7FE4E8BFDC1 +:10232000856929DC7F9F96C2CF01AA65757D6A1EEB +:1023300006C6A7B5F1D55BFAEBF1B830D83794CF24 +:10234000B9C5108CB997EC319F11EDB13F9FE7747F +:10235000D1D5356F21CEF3CF351686793CB3059DA7 +:10236000CC17FB627F661E619FE592BDA696FBEDD2 +:10237000AE1D3AB2D399BEE10F0F03BC7BDF1EE660 +:1023800045FAEFB7E3CF1AA3EDF800DA5FBD9DA3DE +:1023900082C2DE5224B2DF389CCE8AFB1C02070ABE +:1023A000C43D12FE6DB88FD2DBE9F6A2FC3F83F983 +:1023B0001800E25E7DF0B967515EEE8F21FFAA57EB +:1023C000D84D17E4BE0C3CD3DCDB6F2F05C85E3A5A +:1023D000D36FDF0753676AF0B94FE42DD61943B9BD +:1023E00068DFABEDD4B29A3F80653C3FF99A90E745 +:1023F00075165E6E31FB1F46FE7DC5C8FDAEBA3850 +:10240000786F1D0C3E5C3EF43625D23A103E12C564 +:102410008D6D11F0E9B75F77E8C82EB84EC7E56259 +:10242000DFCF25019FBE3CDA07399BEB413DB4FA73 +:10243000AC91ECED7D3BB8BDFBA9CF48E7427A8576 +:102440003DD91B151F8E86CB16B19E768327632C34 +:10245000DA5968DFE17E7913CFDBAD0FFE710EDA5A +:102460007BF5B57FBF8BDE47E5637C2AF53C924B5D +:102470007A80DF07B2D4CEBFA9F050C7AD17762E51 +:1024800073F5250C6677D69F5DE7A37C36C6F39778 +:10249000AF15A27740BDA8F1C90F2BE6F639ED576D +:1024A00046E57F306D5937B0FC4A3FBF44BEDF8BF5 +:1024B000B16637CE23B2BF8F0C81B86B89AE6592FF +:1024C0002B4BDAE7DE85F920A313FCFF8EF2645F65 +:1024D000DBFA62710E9EE214D77E9C467E1EDBC440 +:1024E000F78B3F32287721BF3ACA42C67B34F03996 +:1024F0002EE4C83C13B7DF19C85DADDC51BF179798 +:102500000EBE9FF2BE58874DE48B3136D384F6C1A0 +:102510003EFCA7475B8FF7731CF91C9E99BD3CFEE0 +:102520007C6D6FDF413CCB5CD75948791B992B42BE +:1025300024273E32B010C6A13EDAC6E9149785FDC5 +:102540002E98C0FB5DA003FF549347B648E06D8111 +:1025500009FC5990CBAFEE2AD1D9302F6ABBE48D5C +:1025600081FAD70AB98D7E5326EA11916F54CBBAFE +:10257000D7F540FF0B5A987902E5990575A90467CC +:10258000CA1D66711382946FA6C207F44F631CB410 +:102590005BA404693F253A8F8369F332101F983F8B +:1025A000A0B177966C6AA67C847E7BA1333ABFE0AB +:1025B0009FA648BA0944E853558F7E25E4A5AA5F33 +:1025C00086D2AB600FB1548E3FCECF7B2482E71210 +:1025D000D6C0F309845E8BB65FCEE8B81E5E606A33 +:1025E000A5A71B834D6E84738FD81FE7F6CCE5F04B +:1025F000EE4EE5FE878AEFBA5E16BA01FA4F48F54D +:1026000044F84D752B5868C918FE44BF01E0CCF55D +:10261000BD99EB7B7C5AAE40EF47EBFB68FD1EADEE +:10262000D7138D5C8FABF4A1DDB744FBE6DA15411F +:102630001DE2F9E8CAE066BC0FF1624CDC18CCF38D +:102640005D6EE6CF872C711DF8BC18931144791587 +:102650004038A39C3C69237FE6A2ECDDFA0E3CA740 +:10266000ACE7F4B3A699CBBD35E23EDC5B52B9BF13 +:10267000559CCAF968412AE79343389E01CF3DED46 +:10268000A271A7980BF5C8DFD3ED9F65E8A18A0E6C +:10269000ECA15890AF20F389DF757B6D94573125FD +:1026A000F58610E2F9B0CDE8D18938A515F032955C +:1026B00085FFF07ED329F80F1872AA35F73F51BE77 +:1026C0004E1178AF33FB7F8457767E62F0FF180F90 +:1026D000F04F32FB2B907E26334F23C603268D9975 +:1026E0004AF3D033657A2AEE7733A53295F661D274 +:1026F000EC94D71A45B7EA3AD4F9AAEB405D85764F +:10270000AA6EBF89F278A3E7A913EB5AF3731BED06 +:10271000FF1F4EFED53AA4ABE8F9ABF0895E07CCBB +:102720007B2ECEFB8BE477EE42FA7DD092D588F5F6 +:1027300061DEF7E07B98F7BC54F7D0F3D6333FE582 +:102740002BE9CDB64054FEF6125AEF0969D0F323B7 +:10275000E17C66FE3CFC09CBC638006BE2F7024F19 +:1027600016F5275B4DA790DFD6D818DDCF7A98599C +:10277000BC18573A64607B91CFA1BB1CED3DB1877B +:1027800019E7DFC0091BD9279299E781819DE2C132 +:10279000BCDBC3312685E4BDC7139137ADC6FD0E42 +:1027A000FF3E95EC9E4331262BD22BD647F97A4833 +:1027B0003207B3A5305D3397263F3A7B209DA3298E +:1027C000DB5B14A677F59E9B5D423EA48AFB5ED23E +:1027D00031EE04FDA75B657EEFADF01B27A9F08A03 +:1027E0009AE724BCDF17F5B435D23F649B1E57B47B +:1027F000703B84F08C0FC3558563F4BC07C0612B1C +:10280000C0BF58037FB389EE5B062CB254E720EDBE +:10281000A3FCCB3792FC2F20DE2F1AB8BDD9576509 +:10282000263DEC2CEFA3F3BE27C3F7CBD03A0F8B9A +:1028300061E5D8EBD3302FF675C1D7D1F352D7135A +:10284000BDCE6838A8F3BDDC3A8FA8FD45AFD73EB2 +:1028500044FBA875FED2E8FB25AEF324EB29403CEF +:1028600056A30CD1D073B41C7C4BF0DF95CA43C681 +:102870001AAE46BD31E596B99FBBE89ED1E76EC65C +:102880007B47A74C9DFB0096AF4BFF3F375B81C852 +:10289000A64C92F839F51F6E7E14EF899A72DBDC34 +:1028A00007DCF0FD2F4F16DEE2C2EF7748625F7E55 +:1028B000E52D788FC694BB2532DE363EC5EBC78E3C +:1028C000F31B306F6096B8570B50A068E363BDA947 +:1028D0007C5FA257E0E5ACD047041A8C0DD6F03CE3 +:1028E00033F0630C3368DFDD6FC0791FBB81C9B87B +:1028F000FF314BEF4FDFA4B5A36E32DDA958793D10 +:10290000EDBED4DF855C57FDFB68FBE96F423FAA53 +:10291000FBA7D8FED602ED773D7DFF3BCE0FFAB187 +:102920007AB81EC5795517F0A7D6AE3D3EBBE47503 +:102930003C6A74AB17E41D437CFAE5349443C99FA9 +:10294000D8C83ED4F714E03A900FF73969FF3B80BE +:10295000F9860107DF2F9A5CEE7DFA21781E37E0B9 +:102960005D65D02ECEB4A31196E04DE3F3EC52E5B5 +:1029700013FCB5A8F21AFA6D8D7D246D19C0AD2235 +:10298000CD44E7C42AAC1C8E6F8D9054FEA77BA863 +:1029900054B95DC9BAF5485F53F34792DCBE99F567 +:1029A00051D9C7EC067CCE605E7A7E5AD2534C7108 +:1029B00000552FA5F7EBA5745C57390B52BBA3B19B +:1029C000BF20BDF261FFFC42C417FDF2264A9E0EF5 +:1029D000296F707A09E17D7555DE49F385BC5D1775 +:1029E00020F916CFFC056911F2AE5B22FF7A8257FF +:1029F000DC731DC957FDFB5FA32492DFADB171E409 +:102A00006F4DCF933A50FFBD66E83C42F27D9A8904 +:102A1000FC2BF8D3E1F95B822F7432354F9A8B701F +:102A20007A1C951BF4D355C8F328A77A12E7219F87 +:102A30004D2D0738C685D73F75FEFA6E948B53F33C +:102A4000DEB91DDBDDC47AF4D8CF2D78B41DE65B8A +:102A5000C5BC93F10EAC6A9F83EEF799912FD179A3 +:102A6000CAF7567691BEBE7ABF670DBE9FEECDA265 +:102A7000FBB3BCA1908CF7AD54E439285F7CECDB50 +:102A8000BC7CD30407B52B78B96735966F511C54BD +:102A9000FFEAFDF6128AFB563BBCF8DD3147CFF961 +:102AA0002A47EABF675D4B0FE5EF375622D8EE4C59 +:102AB000CB253A9FE893D814683FB15A7A16B77677 +:102AC00056C72EBD9EF63903CFE950BEDE26F0E88C +:102AD00098C3F3516E9B5365C0FB2D815E1EC4F5F8 +:102AE000A1FE4F1B3F906E5EC17825C2F96695BF6F +:102AF000B9DF3FD33732B841CCAB5AABA7704324D0 +:102B0000212C5F8F4BA2FD5C7E2FD49B1F82030A7A +:102B1000F26052655619C2990408ACF3BD3B3DD42E +:102B2000DFA4BCDB2A102F937CEBBBE9BB354AFE4C +:102B30007EA4394F04E577117FD05F52B544712AE6 +:102B4000A63D6FA4C3FC3E7E3F415239A7C744BF98 +:102B500031E2FC12FA0FDAFA60E704D2487E83D53C +:102B600008F0CE13F975407DB48ED93E2988E7D799 +:102B70005E9D2F3123E2D7CF82E62C629D10E6C105 +:102B80005F17F455211D4159D169FCAD99823F0C65 +:102B900029BB1A9DD0AE6B22BF1FEA35293087E0D2 +:102BA000F3A1D5F38C46EF3F2FF2F4AE4A62E64C28 +:102BB000D2B75200E31057BD9AC2F73193F8B999D2 +:102BC000D1CB38DC2A2A2586760D6BB1D03DEE308C +:102BD000EE575F69CEABCFACE4F1898A15E382187A +:102BE000AA78A548CD0F0C1850D8D7F8FC2C04FDB6 +:102BF0004F4F625EDCFF95F325B277663033D99B89 +:102C00006F5667AF75E13C3F307A4710787C93DDB3 +:102C1000F0BDBADA4E7124E6BA498EC23BBF171531 +:102C2000E43ED979207F309E577A299685C686F171 +:102C3000562AF40D5A167A8D1C49073AF221FCA245 +:102C4000E4100668109EC9FDE50073A9BF3F80EB44 +:102C500036F710BC6DAA1D23FC2CF53EC2EB7A1C86 +:102C6000F3083F3ECEE78935BFFC009F47D3B2094A +:102C700058608731DC7793905EA0DEF14F5831CAFF +:102C800087E3439C9B7D57C879D5CE99E197BC18C3 +:102C9000522C295FA547BFF236BF44FAEFA223703A +:102CA000C4CDE506DDCB38BDBCD5807E52D9FCB99C +:102CB000E9B89F7ADCE64B47FFF393340FF597535F +:102CC0006DA2DF31389EECA7F7C7C5B99C8BBF7FDB +:102CD000E86EE497191E4716FA2B259EFB33912EBA +:102CE000A6CF7764A17CEB49E3FAB9A69C8F3BDDC4 +:102CF0005F45E3DC3A7F2EE1B9AC66471ACE4B1D47 +:102D0000E74D47F004C6F58ECD36A165CA722AC5D7 +:102D1000B83191E3CDCA87F1E07B493E1FEFD64A37 +:102D20003EDE05B1FE1935301EC0E956B1AED9956B +:102D30003BF4B4BEBCFB697DBF7137A4633CF15D5D +:102D40001C07DAE5949B689F25A7667D378E776818 +:102D5000A5C2FE8871DC283D84DB63B6A2A1F5CF55 +:102D6000751857C2FC5DF07F314FF711A3B74907C3 +:102D70007C5C5A161471E648BDD29F4F7D3E48FADE +:102D8000AFDAEC2D73713D26372584F587AA171E1F +:102D9000973ADF2E42BAB7F1732B8FCF8C27F9F712 +:102DA000EE2889E27EAF19847C2BE4725AD53B531E +:102DB000CB41CFC0B375663CC9B759E3F8F9CB59DD +:102DC000565EFFD84489F6C5A756727D1EAD7FF0CA +:102DD0004F2BEFC37A88FB9565CC477A7C1A0B544E +:102DE000DF04DFBBDEFB33F9B94B75A175F81DFCC1 +:102DF000B893122EDACCF5D58363A442E4D3A2AE05 +:102E0000BE43A8772AF31DE27785BC87499F8D834F +:102E1000EF50CEEFE4F3BBB9D24172225A8F819EBC +:102E2000C84B077CBF37F30FA5F8FEE88D5C0F8E0B +:102E3000D9CBFBF595717D06727454FAF881F87C54 +:102E40004FF07D3F3EA3F93B0ABFFDF6848FF3238D +:102E50005BD740F64312EB94F87E70B784F34D7B5A +:102E600080D1EF630C654FA8787F2B6C8F45FA57A4 +:102E70005768EFA8F32149A4F9DD13FC851FF4B3CB +:102E8000D344FB62F4DF71DEF9AA1DD4A0DA41B7A6 +:102E9000A4BBC3F34EC27903BED64CF02E72E886B3 +:102EA0009EB73F599989F09CACB37A514EFFF93DDA +:102EB0007E1FD874A5B90CE543250BACB56BE4D3E4 +:102EC00048F067F41A3D372A6806DF3C5CBE6A9713 +:102ED0003DA25CD0991451FFEABD9E88EF85A024E5 +:102EE000B5DFC7767923CAE3BB2744D4BFE6032501 +:102EF000A23CB1A73CA2FE75BDBE88F268E6977100 +:102F0000D137F4D544B4FB330BE89DB0DED1CF808C +:102F10005E227028DD7909748F00FDDD78C91FD12C +:102F20004F8138B75CC21646F4C35EE6F74934C039 +:102F3000FF108FA3A3EE93C815F75CD73C1D792F24 +:102F4000452E9E6F8EC36764FDE873CA4DE9361740 +:102F5000E20D787D1CDA1103F084BFE403F8BE753E +:102F6000170B06255C17D565A3B7F173D7D1EB52C4 +:102F7000CF3133DDDB7AACF757D0DF78659E292976 +:102F800012AF319E48BCC6E645E2D5E68DC46BFC67 +:102F90008448BC3A9448BC0E2B8FC4ABDB1789D74E +:102FA000C49A48BC26FB23F19A5A1B89D7F4864859 +:102FB0007C662E8FC45756A036E2FBF0A68648BA30 +:102FC00014F81CB16979443B159F01F8DFD7E1F390 +:102FD000D6EA1203C61B66FA0C11F78B5C295E0F4A +:102FE00047E1F54ACF9F83FC7B03F95CB573F02F73 +:102FF000D2FF1BF3E40380D772F4FF3CF83240FEAB +:10300000CC24BF89E4C1E1E49B8E38052D68F5C06E +:10301000646FAB1EF36354FB0EC305E4EFF8B93FD6 +:103020005321FCC468FF7026EBCBD00F1FA81F1ED6 +:10303000B4641984FD7F0AE54B39DE8CAD43FFF0A3 +:10304000D734CE7BFDF30F0DF00F713FE74AE565F6 +:10305000BFFCBEB981E4F665E5B7273D2C0749C83A +:1030600006480E4E5A3EC987E7EE2F1A78DE6DDF0E +:103070004D268ACF4FFA6E09BD7F4DE27658E05754 +:103080005C5FAFFAFD35E978EEBCB4D224A1BE9EF8 +:10309000649688EF4A7B65F2074BAD85E99671E847 +:1030A0008F9864FC546A95287EF9CA3F754A00E3FC +:1030B000FF6EBE9F774CE4ED1E736411BFBE6F338D +:1030C000F9CDB0BE49E21CC8A1283FE7988DE7655D +:1030D0001E5BC2EFA93E964534C48EDDEF11F99513 +:1030E000EFD2BAFBBEC33C22BF92E20AFBAC4E9EBB +:1030F0003799D943798B7D13991DF755C2FBB29D42 +:1031000021B4A3F6B567F1FD4950D2B43FD9DABF77 +:103110002FCBFDE68D05FD7E238EB36F5332F9096B +:1031200093C53D3FFBF4A0A971BE1E7EBFC13E9179 +:103130007F795CE8C77DCCB38AF25C563091171B6F +:10314000A078C5BE9A5C6EEF47E9CB7D2C90D38604 +:10315000F56B2C6AFD71EF62FDDAD1BC3E8B8C13EE +:1031600040FDFC97B0BECF4CF58F39BCE9B88FABB2 +:10317000D2CBB19BA6A623DF96811F88F32DABE6A9 +:10318000F78394D95BF5F85EAAE17AB57D84B4093A +:10319000DF57A5F8276600FDA68C94A8DEB411CFF2 +:1031A000D0EF361E1B32FEF2ADDF3F3048FCE55D4E +:1031B0001BB7CB0E27173472FF2292FFD4B8816A57 +:1031C0007F95E32F160E47F91EA2E7C0B801F09DC8 +:1031D0006E30BE2B34301E97F1E1BC2B987F7F0FF1 +:1031E0000726C5A7407E54E17B75FDEF393A0FC72E +:1031F00001BECA6224AE07911F34F6CB50FCA7C2B1 +:103200006D9AFD5406AEFB50CCC50CADFC6A4DF476 +:10321000FB33347911D39CC118FBD7D8CD6F0D097E +:10322000CF5F9C40FA9821E039C3EAA1FCE1633109 +:10323000DC1F8A86E3A4EA121ECF12F6EF64D0F3F5 +:10324000DC9E0D12FC2A8790635F13DFFA2EAE63BB +:103250003AC08FC7B7BE65C079011CBF9731881DC2 +:10326000FABE58C795DAA1D1F4DB2FD7AA23E35CC5 +:1032700043C7F3078767D710FB179287F73B45DCF7 +:10328000DFF2A69DFB0FF8FB6DC99A7CC0379B3817 +:103290007F035D905C2A17FA12C040FAD10BFFC37E +:1032A000F9FF9559FD6619EDFE483D582AEE69294A +:1032B0008BBA6FAB54DCEB521AF55E5D77B49E545B +:1032C000F735865AFF0B19428F7AD8C8AFE03BE832 +:1032D00048B28FBADFD7D1BEC0EBEEDBE6B7C23A59 +:1032E00046FE6834F919AF27DCF1C03B587E2A97B7 +:1032F000FC94A3C9F73D8DDF737FC8BFAB7AF61589 +:103300004C22413E91A57B319E9837EEC3DBB360E2 +:10331000DE4762D89D584E62B5ED55304E527E76EE +:10332000D11AE8A7CCC8A8DEF4AB978CD5EEEB1F7A +:10333000CDE071E7E9E2DC413A5E015A444F3DC617 +:1033400071D293827A3BF46B14E73E53F5ACD1040F +:103350004F63D226AB1DE167E1FDBE5DF89B22EC19 +:10336000B72C9B97AFF2C69E1A8EF391249ACF5535 +:10337000795208EFCF2F73F2EF9545CFA560DE6C41 +:1033800059A95AFFA6B358BF4CDC031DA7F80DA3DB +:10339000303E22E248BFD173FAE8C930D3BA5F9D0C +:1033A0005362C07B5F66F9785CEFE609AB24D48B8F +:1033B000B3FCCA38ED39CA3F6418687DD51378BDAF +:1033C0006ADF5CC37CCDFA67297D747FF2AC9A53C7 +:1033D0007A940FEF47F17915FE43463EBFEBCEEFEF +:1033E00060DCA78CDB2DD582CFDF453ED7C84B1FD5 +:1033F000FE03F5ED1C2EE7AACA399FCF620DC49FCC +:10340000356C133D6F679DF49CC3BA397F9FEAE723 +:10341000EF4CF4CB35FCFD57E4E35B9942F5BA631E +:10342000C71878FE46245F0F2507410EFC8DCB811F +:10343000C1F9F0CD21EDB417B7A35C9BADDA6935C6 +:10344000ADAF939D56CEEDB40172AD6038ED230C57 +:10345000A52786926B43DB673BF4C23E73678E0FF2 +:10346000C7ED357A2221D33D100EC706916F5A7BE6 +:103470006D483BAD52C8B3CBD96943D8675FB30F32 +:103480003C26F31BEC0347EF33C7252AFBB335FB80 +:1034900042F51F98CD9EABB1EC63D9563C8F57F2E5 +:1034A000FE70E8BF5EC41363BB99B203DE3F29CE52 +:1034B0003D1C1CEEA17E938C3C0F06EF4BC41F4AB3 +:1034C0002C2EEDA673397D6EB0B33CE1FC8C276DDC +:1034D000D0AE08DB71B9D0DFDECC1A2D9AF6A57715 +:1034E00070F9FCC54623C9E72F1C12C587BE986D2D +:1034F000253BEFF42346CA3F1C6EE4FCEC52CF356B +:10350000E12F31417F559959FC5CA6742809835DF0 +:1035100001B6819E6ADEEA69711EF20B8797EEFDA5 +:10352000FE62638284FDCE6F1971338E3BBF252D01 +:103530008B2395D79F96C9E779DAA37CD685EBAA2A +:10354000B2D2B933C6FC85187F35E9C6559875A83F +:103550005756F47541FB25E9563BD27559E689E388 +:1035600079503EFBB281EEEC5DF8CCCCF81036D34E +:103570002B49BE82817ECEC260A41E59BC2BB2BC38 +:10358000A433B25C1FA547A2F5474366BF7EF0A2F5 +:103590007EB8523F2B43521EE2F41FA4FC9A450210 +:1035A000FF265343EF0E58BFE9D1BCA25544673CF8 +:1035B0006F2A61735611DACDDE4CAE372667FA56A4 +:1035C000225D9A32F3C7A05D599A593997F0B92D07 +:1035D000C683FEC11731DC5FF8E200D7AFED19FCFE +:1035E0007BFB13268F44FCAF548E2FC6BC284ECFD6 +:1035F000F55BB93E853F33BFC74F31233EDB8D8A34 +:103600003119DBFD1F7EFEAB76EB7DF43B5A75ACCA +:103610009BEEC9398A7843FAD5BD60C4DF55CD6ABF +:103620005446AD82F92EF659E8F7B5F4FFD0D3EF42 +:103630008AAEC72E2762BEBF62C77BE197ECE5FB6F +:10364000493FCCE471DFA6BFAFF2617FEAB937E34F +:10365000CB550164CF1BFF5146F7CBDDB7FC353AA4 +:1036600087E132F60D2B41BF61A34C747FDF777F7A +:10367000BE99E7359677E3EF879DD968A5DF0F3BC5 +:10368000BCCD44EB3F7380DB1F679EE4F0B82FCDC9 +:103690001A344B03D7DF288544BE53771CE2E34F2F +:1036A0004F3E148778FC939ACF686FA073F4CCD305 +:1036B00010713E66E7761DDD57B9B365D9AF27C2F5 +:1036C000BADA67DC3E0ED77DA3639C05EFB354BF27 +:1036D000ABF9197AE78467510EDDF80F1DF1871EEB +:1036E000F425E605973D5A4979B23B7D1607CED7BA +:1036F000D3D241E7E0615D84B79D1BCDB4AE2CD63B +:10370000B98ECE0BB54C217CD5B6D4123E86CFB443 +:10371000905DB273BF8D76DB77DA2758B0FD4EA689 +:103720002F1F2CFE7F4726DF172FC9E4F19E9DEF48 +:10373000F1FB45A7E8AEAF403DBC64A34CF9BA47E6 +:1037400066FCF638DEFBA9F2973463424A0FCF7F5E +:10375000A0DFA7BD47A51F319F854FEBE81EBECB5D +:10376000F19929F37A9A5F34BFED0C78E9F72CA22E +:10377000F9AEABA5C882F1FF68FEBBA7259BEE2D75 +:10378000624D9C0F4F65F2DFBFFD067CD83B181FD2 +:10379000B2B4191179F22ADFA96555DEABFBF966DF +:1037A0002F539EB1D23D19742EC2E6E1E7766C1E0E +:1037B0009E5FADFF72D9AE5F019CDA32FD17916F4B +:1037C00033995288F4E6E9B397A2B96215F99C2CB3 +:1037D000879F9BDC62F0C9448F7AFFBFFD0ADE1B26 +:1037E0005A6AC722FF5B3CFC3EEFC9997EE681E73F +:1037F000FC15FECF0E32A4BBD12407FE2F6B48C5AB +:1038000034008000000000001F8B08000000000052 +:10381000000BE57D0B7C54C5D5F8DCBD77379B6488 +:1038200037D93CC81392DDBC0879B1091051119702 +:1038300004302AE2F25041AD6E2040DE41E823B66A +:10384000D82C264054ACA1464545DC20205AD460F3 +:10385000112904BA8022FDD49A56ED87B6A589585D +:1038600094670256C57EFAF93FE7CC4CF61122F870 +:103870003D7EBFFE7F5F5ABDCEDCB93367CE9CF77D +:103880009C99AD383F5B67CD63CCD4CE1C1E133CF6 +:10389000EDCE92D058C6F4B1CEB1AA95B158952DBF +:1038A000EE84FA4C3B737440BB6FF1EF6ADF33D7A1 +:1038B000AA676C18BC8F75523F669B85B1710CFE70 +:1038C0001C7315E8677DB58EDD0FFDB0AFBF555990 +:1038D00031631146467F362B73874430661CAFA395 +:1038E000716DE375EE6B22681CAA37613DF4173EDB +:1038F000D6CBB0DF4C7C5FC0D89204D5FA710CB443 +:10390000B7B35EFF76F07D2FBECFCCD651BD8E19FA +:10391000AD26186B19FCD7B73678DFCECBF8F72D6C +:10392000FC73AE4D29EB84EF963066692C023800AB +:10393000E04E1A0FE669C2710C348E9CE7F9A44977 +:1039400059569C97C391110BF330F1AED86C98087F +:10395000CE57B133AF19C6672BFB5FD7D97C7056F2 +:10396000183DA5A1D6C178AB10F0DD83F0298C5DA0 +:10397000618772F6D0F0855AF938F27B099FA1DE93 +:10398000A4B102821B160BFEF9A1CE9309E31B9290 +:10399000124C2C82BACBD6E05D320BB3DF0FE33C86 +:1039A00095B0651AD67F191A51C022E19330788EEE +:1039B00066ACD1C8CB3F098BD880CF113AA629304D +:1039C000AE41C7262BD1D83EC583DFC586C113C6FD +:1039D000FB89EA644C857A5D9BC2D219BB41C01752 +:1039E000CFBC8A02F54F54ED28B4C0B8C31A4C8539 +:1039F0002AC0931AEA986E1D86E058539C66C63E0C +:103A0000D2B3394857C178490D9D348BF0DC0A6B2D +:103A100012C7D83CFA84B1B8663EBFFE2A9D670340 +:103A2000F437AF47E95510DFAD531C3D725DD360ED +:103A30005C5D9B11E1FAB9D54674C98C3D0CE7FF7A +:103A4000E815CC723F1413987DAD9AEE5BC706B1B2 +:103A50008E4A97C2D70FDE188B7DE3B2B6C760706F +:103A6000C0AF85B793E3CECBD3BC2117181FFFFCA3 +:103A7000E196EDC31FEFB6215C437DB72E94B98D5F +:103A8000D1483F762BB60B4977FD18F190DC5C6E80 +:103A900045FC32D66D43BCED4FF46A58DE1F6A1DFB +:103AA0006E07FA98667CE330F63FCDC83A555C6FF6 +:103AB000BBFE544FB63F3CC3A38EE5D25231C46F18 +:103AC0007D63A9F3E331804A038C87F89C61207CF5 +:103AD000D6DF3D89EA772B8BFF760FE0CBFDB6DE94 +:103AE000BE09BE699FE1480C8BC5679CCE0DF4B33F +:103AF000E33F55BE0E2B601DA0ACCC2C4B54A17DDA +:103B000083D3A00B817E4ABBCE1A7A605D1B76F60A +:103B10001A583EA02061D6E315D06F95F1FAC791EF +:103B20005EDB97972422F39C517AD6FF0CC7A9320B +:103B3000D937019EDA6D8EC46898CF95AAEE4E27CC +:103B4000329766099B01F3BD32950D946762595512 +:103B5000A87C1CE8E76562426897EF5BCF5481F769 +:103B60000E8D11FF747874EE4CA0676519F027E094 +:103B7000A7835997233DB897319A1FD33ABD3A2866 +:103B8000779459ED28A73C665894486C077FD8CEA7 +:103B900064F46CB2F9C6C7E5457A881BCF710CEDA9 +:103BA000CA908E259DD8043DB547F1F998F39C360F +:103BB000939DB1314FAF7F270CE8314ED501B35300 +:103BC00013371B2FF8F60A4177F0AF477480DF24D4 +:103BD0002C4E5B3379827F99B7F77DFFF08CC9C398 +:103BE0000118E85BBE87E560A66C9D2C3B50EEACEF +:103BF00032FBDE6B09D0BE4594DDAE19533498AF6D +:103C000022DF57B53900DE874259C078FEF069419E +:103C1000FDEBA17F9355B67FFCC62919006F912C4F +:103C20007FF99003E07B481FD81F91BCF81E0B72F0 +:103C3000BCA8F4E235AB87E3FA390A91BE7F99EA72 +:103C4000FA13D2BFB5DF5202CBC1567D38AD6DB489 +:103C500015F97016095FFDF9D9A417F4B10AE90F37 +:103C60003DD0A415E9D09AB641A5F5B2BA71FD8C44 +:103C700089D6225CD71EAB42F2608C8EEB277DEC9E +:103C8000246F3234D333FB86B7A1FD9454D7C728B1 +:103C90009FE252A71D0CC1F59B9953E082FE2BCEEB +:103CA0006B0EA4F7CC0C8347817646D49379BEF58E +:103CB0000E113C6C443C50BB9B37A930D4D536D751 +:103CC00019EC4FCAB5CC76AB01FB7B46C8BDF6AA52 +:103CD000349DE2A74F559B8EEBD16CAECFEECF9EBD +:103CE000497A588B9A3C0EF5B06C9766C9D0E1FCC6 +:103CF000D3860BFD087A7712B44B6B77C5211C690C +:103D00009A6B2ECE3B6DCE4283DB86FDAA34DFB1AB +:103D1000AD9ED049B896953A9609FD9D14F25A6F1A +:103D2000A928C7F6FA39461312EF13CECDA1D87FD2 +:103D300066F686D634D42716CD8EED3361DED84EA6 +:103D4000BBFB560FE257C273BF452B43388A55D78A +:103D50005DA47F62AE7020BF8C88BEAECC0EFC9698 +:103D6000AC6E2B5C0AFD3DAAC0BC2F603FFC248DCD +:103D7000AF4B8BE274DF88FC56C818F2E5803EB08A +:103D800073BB24C966A07656B7A504E5D6847F38F0 +:103D9000092F49368DE6B157EB09B720DCCC71D736 +:103DA0003C9CA7D36445B9C218F037B48F6DE2FCD0 +:103DB0006D8CED796034BEB7EBEC99C4FF9CCFCF2E +:103DC000FC267E03EAC7CD36D748DB389C4FCFC3ED +:103DD00037E27C1ED0483E318DCBAB9459A622D41D +:103DE00023F7C5F63C5C06CFA7F4CC1D0A727BB561 +:103DF000FD5E8702EFF7C6320BC2150ECB9400DFD3 +:103E00009B4C8A8741BF63814F514EB20485F4B306 +:103E1000C9DEFF2EF67F9DF55D3BB62FD5BCFB4876 +:103E20009F05D9174454502E11A54C60A36346B486 +:103E30006F58CBB7313EBB630A73B4E0FA497BE4F9 +:103E40005103C813F8F4519DD18382213CCFA19A2C +:103E5000A17C67B63281E08BED662AD20DA86F9403 +:103E60009769D9330D0CD667411BE7A779820E9964 +:103E7000664F72827CBDC616CEF5296BA1FE49BF86 +:103E8000E17C561B3C9BA08BB45658203F7DCED87E +:103E900072DE0EFB837E0CF772399E3696AF2720BA +:103EA00096DECFB429C25EBC573CDBF8538C2BF9AD +:103EB000AC01F9CCCAE586BF7E96FAB5AFF25C04D8 +:103EC000CA83795DAA17EDBF8BE9E52780D44291BB +:103ED000DEBA5492EFBE7EFE1961350DDD4F958D31 +:103EE000D3EBFEB95F44F4C0784F743D138A787BFE +:103EF00074066868D25340F5F00CD79CF536C2972B +:103F0000FD175930CE13BF50C90E7E54E976A89CD8 +:103F1000CE49FFDC9931F3AED7A11C3D36A708E1AD +:103F20004AD09851057ABA578C13B91FF006FD3F55 +:103F3000AE008B44FBF0FBB8B2267109D48F2DE3A1 +:103F4000F88C2E73A875F07C28AA7F0AF26DFFB555 +:103F50008C6D80FEE3C3177720FDC7DF995DD40C1D +:103F6000F30C1BC3EE9C09DFAD423A81FE13E19BCB +:103F70004890D909F7BA6DD85FE47E27C1D39F1F57 +:103F800066DF004DE261EEE6687AB686623BB65CBB +:103F9000C1762B8729C4CF2BCB410FE7111B699129 +:103FA000D1FC79189E8AC65AF4F89DC6B4305EDFFB +:103FB00082E33C12C1E7334CA7DE39238FF4059529 +:103FC000A381CF37002C6B6D5104577C082BC3F9AC +:103FD000623DD20FDAE7DBE07D7CE9E2421C3F3E46 +:103FE0009D3FEF17F6D013CCB37613E235DB60417B +:103FF000BC4ECB3EF89D76D19AF8591DC8E77DA7F7 +:104000008FAD5F01758F2C9F3177017E9FCFED11B2 +:10401000E6DE669F45FA3ED07E3A772A4CA780427C +:104020003A74283D12ED9C1704BF21AE5922BC679B +:10403000D6480BC075685F16BD97E5CFFEF28605C2 +:1040400099F64AD4DFB83E5106B29F00316EB43FB4 +:104050004CDB123DF7DBC8DEF1D2FB5742E8BDB4C2 +:104060009BCE34391F9F8C024B73929C316DCBB425 +:10407000A31C027B88E472FF1E33D971C7F50E9230 +:10408000E7EE3D23AD9BA4318272680FEF9F65F789 +:1040900014A01D69D23327AE9FA983DB4792AE4C93 +:1040A0000AD4131D7B2D68EF9C61DC8E629A23611C +:1040B00056BEAF5D8B90E7B5066F16DA39F23B5905 +:1040C0004E0AE17E2396A3A0BC5BE8BDDA305E5EBB +:1040D0006D74FD11F1BFC3C02AA99F08A837F9E18B +:1040E000A7501BC00FC1FFE0080FCAE72B53F97C94 +:1040F000FAEF5302F0A3CC34929E3E56A86D0851BD +:104100007C76E2D16C9DD750E06F2F7A2D33FCE6A0 +:1041100021F1307FED27DFA05F23F131DF69E85522 +:104120000B06E3437E37BFA882FCA8F9D5CBA6E3F4 +:104130003358AF0DB46B0D11460FF7EBFA700D80CD +:10414000BEBF089D6440A2FAF12F6718907E17B297 +:10415000C5F4AC646D066EEF33A30EEC356BAB4665 +:10416000F3B56E513C561B177F3AB23D2D3AACAFBA +:104170000171FC048A7037488FCBA05AD129686737 +:10418000595BA01C0F60DFA7B9510F751C0EF728F3 +:10419000D06E55ACD58074B8AA45C7EDDBD55C1F91 +:1041A00041BF094817EE169D03FB894CE376C3C84F +:1041B00034033D81CA3D048F78B6E8855D2EC65B29 +:1041C000CE745E7CEA14FE5C8576C105FC3BD95F4B +:1041D0008B7EB111ED96FE113A0BCA992F0C8E39D8 +:1041E000389F2FA2B318DA2D2DE6C5AD65FC3DF141 +:1041F000D617A1DE327A5FA8E3862EB21BDA391F0A +:104200008476205DE8D3B8FD148CEF056D81E5451B +:104210006B03CB559EC0F27CE67A2901A65EB325DE +:10422000B05E9F66A1FEE7313BAD4F8BDEFA471BC8 +:10423000F2DD7D1A43F8970FE778D38DE0CFB4A86D +:10424000C973483F46195826C1CBE14F2B8C5610F5 +:10425000DE9628CE0FFF5D7883E11C9D96C5F11B8D +:10426000C5F9A405F844E08BE4C4FCAD21CFA01C43 +:10427000986FB646E03C4E2AFDD9A48F1E345B37BA +:10428000513B0BE9DB79C2DF2D4BE37AE2A862DF19 +:10429000EC85EF740FBD701FEAB3F90FA8456827CE +:1042A00097CE3211DFED3A61F220DF5502EE124176 +:1042B0006EEFB2BF477674F0FCE0CFAA49FD0D4B1C +:1042C000362F16FC14F287FDDA91BE063A91F21AE7 +:1042D000FACC8973CE49237DEAC945FFEDD8711E1A +:1042E000CF78447774DB1BB80EDB42495FD52FEBE8 +:1042F000DFCCE0FB6F87B9EEC4F6A7EEFE70AA62D2 +:10430000F5CDBF6FCF48A297B12D21BEFEF15FABB7 +:10431000FDCA387E2B4CE27278B607D657AE0BFA40 +:104320008EFD67883F9CD27E79D4E01A85F6E8132B +:10433000CEE26284E7517D5B19F2FB8C24D75D6984 +:10434000F0FEE329CE833ACE775968E7ECFD7A7E1A +:10435000BA0678741F36DA516EA33D8B7232D7C617 +:10436000F19F60646ED4A3D2CE95F654307F2D4B6E +:10437000E3F6D483698E28B23F44DC4D15F693D121 +:10438000F4B203ED3ED6A558509DD45B59EF228C74 +:10439000A375D948CE3624303BE2ABDEA4EBBD0C8E +:1043A000E371269D2305E9D8AAF3201DD7B733F77B +:1043B00022582FA3DEE14DB6513BF76505E857596A +:1043C00003E253F53B67309789E030A39C473F6594 +:1043D00001C615C1FFC03FBDF053F4730CC4EF63B9 +:1043E00063A55DE8A17E32DB5D037E09F973CCA98C +:1043F00073727D6C3916EEC3F7E3698E57719DFFBA +:104400008E15A07F53131D4F227E3F473D3D1AE47A +:104410005E1A87EBD07BB3481F7FCE9C423FDF1CE8 +:1044200089F69B2C1F535D3FB6003F2C626E92CBEA +:1044300055CC434FD61E4374B050635E0DF0BF7031 +:10444000B6E303B42B902FBD417CE95FAE65DD5C24 +:104450008E037F7AFDE8A716ED7CC06B9D9179C332 +:10446000F1D919F85D3DEBA7EF1A767E1BE20DE05E +:104470001B4E57F1EA92C2C588A74B8C435E6ABBBC +:10448000E3D6B6380C35801E25BDD0BA47F1603C66 +:1044900067AA6A7218A15CF7A08EF81B3A9C36AE28 +:1044A00018F514A7A706EBD4E31417047645FA31E0 +:1044B000EE503DF7DAA8BDDD0BE5BA3D668C50B095 +:1044C0004A6BE534D4AF551EFD473D7EF3AA66DB4B +:1044D000A6A2A8F99CBD65403EA9D912F8BEAE338C +:1044E000B0DCC0B48F06EC3818A7F12F93BCAFF93D +:1044F000F1E35FD2CCB1441F5666FB16F1AFDE1E6E +:10450000E9BA009FC8E7974D0EEF6B7AF0EB14C73E +:1045100051215F0CC88FD51A8F0707B7B7A772FE56 +:104520003A60FA2CC6E5F7BE24CF4DF188E2920B33 +:10453000F3E559C197E1DDC29ED5DC2CCAEFFBA1A2 +:10454000BEFBA7D06B070CFCFD43E67007E231C150 +:10455000C05A8D45BE76093AD682F1C3AB6DCEAF57 +:1045600091FE8D56196F7033B4FFDDC3B8BF21FDC6 +:10457000D5645547EB9AAC1A373403687FB40A3FC9 +:10458000EC22F4129ED7AF477CA25F8F7408EAD961 +:10459000CDA2294EECC06732E01EFD0419CF84F78E +:1045A0000CEDF899F1BC1F03B27F117ECFBC185FF0 +:1045B0005E08360AD627A43B63D209FF0EB24F2508 +:1045C0001CF582CE06E0D8A9501C4FD22DC6A750AC +:1045D0001FB0B610B2638854A89C487EE9112C0322 +:1045E000FFE62739ADD4BFF0F7E73F3482FC7DD634 +:1045F000184372639599FB210077005E25DFAD5368 +:10460000387E8B4BBA49DFF5DF0336BFE217A710C0 +:10461000EB9A9FAE04C8C1B562DD1BD21D0538FE02 +:10462000A90F8C468C2F8E15F1FA7AA789E24AF5EC +:10463000200710AEFA658CECB47AE17FFF32D535F5 +:104640003E7D1CC6BF4C6E3512E56A07C565F4B1E8 +:10465000AE31289ED2B17E34C5AF2660FF15CB5C4B +:1046600067F7315FFCAAF8DBD295651C5E0BDA5167 +:10467000B16897FBD1DD0FD2397DC9E7AD41F0A715 +:10468000C60A7C76AA84DF706B37F91FF5DBB95157 +:1046900051ACF27D1E5613CDD06FAADF3EA9F07546 +:1046A0002C77861662DCA8F8CFD32C68E79D2A8C7D +:1046B000B623BC9B6DAE99389F14B5A70AE59C79CB +:1046C000AC37E549E82FD569A2384830FD49BA8BA7 +:1046D000077A457CC5DF66F420BD0EC439F4CC658D +:1046E0004CF7D16569BA95E6912AF449EA32275B1D +:1046F00060F2954DB17C9DA05E87F879306D4A29B6 +:10470000E2AD345DA3EF06F6978C609DA40DE647FD +:104710001BE3FB343F13FB3640E5BE7DA5B4C1FB74 +:1047200036121EF9BDDCB7093FAF115ED32C3CAE8B +:10473000686E157886F5473C4FE8EF2E8D84F96654 +:10474000B47B295E138A6325E2283D0F8CC6785618 +:104750008C3601E309EB1B8BF6639C47BBAFFB2A4E +:10476000C4AFB5CD52822155ED1BCD49F11BC6E931 +:10477000ACA2DD42760FD31667A31FF3B858E75FEC +:10478000A63A96E37A94BCAFA7F1BF7890DB71EDBF +:1047900029B5A951F0DDD10F802E95A1E5A79BED9C +:1047A00037A2BD9FB63A8DE247E6561EEF6119402B +:1047B0002000AFF6E05FDC1CBEF7462028BF4E3776 +:1047C000D1B8F81DFA11F35BAC06449FAD9DE9101A +:1047D0006EF3EA993AB1F8890ABCCF6C9DADC37803 +:1047E0004CA68823058FFFBC98C76FBF56290EAF14 +:1047F00033F238709D35BA43E5FE23D14D5D7A6CB6 +:1048000007DABDCF209D63DCB36D12C5C783ED967B +:10481000BAEDE564B704CB1F297724DDFD56E3F13B +:10482000B5DF32195FE3F4D7A2E7F8767FA323F967 +:10483000932AF615D31FFA3AD145EB21E35C1E7A91 +:104840006A7AEBCA049461CB7B26BAA176FEEA2889 +:104850005D7D1EF6635F42FD3C6862D4CFEAB4FD25 +:10486000D9C827AD16A658B1BF45A9C887ECCF2136 +:104870000CE9457BD0A44379AEAD71602DD3A2E2A3 +:104880004AA8FC0894A1FD8A743D8DF7B3740E7F8D +:104890008BD2AF907DC31C85A8EF1AD25D07910E15 +:1048A00006F6111BC3C8DE336BDC6E36377EF8C2EA +:1048B0007228AF17FE7AC9437933895EEED314B4F8 +:1048C00013BE88FA03B5FB621C53D09EFBA3C0F352 +:1048D00005E82599C1BAA6ED519DC88F9A9ED3BD12 +:1048E000765F6C077E7722CEF53EC271558B974C72 +:1048F000D6BD968F1F2EB30E5E8FA1F4418FE03789 +:10490000E6705F707FCFAE63AE4E6E6786221FCCBF +:10491000B372FD23F74383F741E5BEA7BB84C3E928 +:104920003E6226F9C3D8E2D18837B97FFAD6691E2C +:104930001792FBA3FD02CFA965209F402E2CC671C4 +:10494000016FFF4CE7F1ADDDD1CC6189C6FD4ED7DB +:104950006738DFC69EC204A49FDD1171250AEDDB16 +:104960005E749FF43CCAADB7841F89E3DB008E6898 +:10497000DCDF8B19BCBF178DFB7B31B8BFE7797CBF +:1049800021CEE326B1EF36687F6FE9DFEEC1EFDEBF +:10499000D6DB515FC8FDBD24DCDF83F7A5959C3EC7 +:1049A00092BA54921349651C2FD12EE6314259C553 +:1049B000FDBE18BFFD3E338F33B42F601407FFA533 +:1049C000627DBC22D67FDF8F7FDF5E67F5E0FA6312 +:1049D000FC07E9BAFF2E26E33FF4BEEF768B88FF93 +:1049E000F430F493FA2FE7FA6CE0FD9C2C1E3F4361 +:1049F000A6C7F7738D221EC6E347EEB9391EFF78AE +:104A0000585F46348F87897D66195FEFD304FFFEB8 +:104A10005047EDFBC4FE6109C687615DFA98A0832B +:104A2000CA30B12F28C6AF4C23F898718AC33FCE45 +:104A300008EDDDE86FB94D3AD19EEF37F689FD46B6 +:104A4000B99E7D621F51EE1BC6355FD81EFC50E833 +:104A5000E9F1F18EF1197E742EF96277517C09FA31 +:104A60002743F1C7BB8CEB91A519CE49F8FD64A390 +:104A7000BDE211A83A20E2796C1AF77798E672E164 +:104A8000BCDE4FCA2E443C05C321E5D86EF15D6EF5 +:104A90003233A2DF0FBCED467B2067470EE91B6770 +:104AA000864EEC1BC0EA039E7384AECC8DEF884625 +:104AB000FDFF9162CD4B517C74BE3B2C99E8DF8F9A +:104AC000CE6F423807C3E7CC9F993F345CE5198E1F +:104AD000DB33C6F9DA0FA5BF5022217C0643E75D20 +:104AE0001447AD33D9916EDEC357F0DD3337877885 +:104AF000317EDCA737B5227F1F0EBFE3E03040EDEB +:104B00007EA3AB1AFB9F73CBB52BB1ACEC8FB12E50 +:104B100001F8FBCA7B8A715EA546573DC25D6B7486 +:104B2000A5C6010A4E8F708D8C4479EB8C117ADC0E +:104B300099EFBC20FC1C9E52858FFF86C1F5133E69 +:104B4000FF1EB31DFD19AD87BE63A661D4CF1181D1 +:104B5000B77D7AC784B300FFBE35A985CD004F6904 +:104B6000C407B735A0DE7F2CBE90EC2A8197036284 +:104B70005E0B74CE38AF1A006F0BCEA7D6529E9A3A +:104B800008747B5A2FE035097835FBF0EF82976483 +:104B900022D2F93D4A009FBDEA8E223E0BD13577E5 +:104BA000105F961BEDC8D7EBC28055C03E7A47C058 +:104BB000037E0943FB1AEAC9FEDEC4EC39281B92C6 +:104BC00043387F25AF523CB87F21E36F15CC9982E3 +:104BD000266847866B1DE2E76FE1FF390EB7509DEF +:104BE000A5661AB7E78330AEFF2770F82FB6FE8CA4 +:104BF000ADD6619C64A6887BCD3C6D203F6B81B0B7 +:104C0000BB66E213E09BC51C7A1CFF26E6D2A3FE1E +:104C1000BC85B9E9399779E8791BF3D2FB1FB01E3F +:104C20002AFF21BC604423E07FC663233331DEE5E5 +:104C300087EF9709DF46D79DB19C3E3E89A778C391 +:104C4000B04BA2D719823E808F77613FC0C71985CC +:104C5000697E7C32799858B79EE648C0DF8C385B15 +:104C600021EE175CFD355F97A91F5B083FFB149091 +:104C700060453EFA0081624A043C5C2396B0FB1C0E +:104C8000D76FD7386A28DE7DC8B13C3616E09CA2C3 +:104C90009A685DBAED2AC509369F057D09EDDE5893 +:104CA000CED7EB8DCB15D293D725AC998CA148A646 +:104CB0009ACC6E18F77387CA70DCE96B79DCA06C4C +:104CC000B8DEE7CFC33FD7650496A73954CAE702D9 +:104CD000874243FA9B9617180F98CE569FC538FD0A +:104CE000F48BC405FE9621E202392C87E274971EEC +:104CF0001738967181B800C3E825C8B31B43B9DCE7 +:104D0000ED9E70E0CA3E98F7675D36C2E6EA1C8504 +:104D1000EFAF653ACFE0FA9CD1F72C2479D704188D +:104D20001EC9D8C74D46E600DA3ED664A1F2A74DAB +:104D300009F43CD164A5E7A9A66C7A7FA6C94EE523 +:104D400029998E2F108E55A17C3DE4F84B05BDAE00 +:104D50000AE576C7D2D01F1D2E0738968EE071B6B1 +:104D6000CACEB6A938EDEA9D9D07F109F52AF840AB +:104D70006CE91AF0AC00EE05AFB956A239B4E8AD53 +:104D80009EE92856C6BDFF711CE2A5EEBCC25CC000 +:104D90003ADF643BF49930EE274DE3099EE34D0E74 +:104DA00082E76453193D5D99CEB04C989FA3AB77D1 +:104DB0006502F477C3D65E2D199E531C0AD9DD1304 +:104DC0001DCCE381F558ABE7FA646DA2D18E7C3C33 +:104DD000297FE6533F6428A75DB1F8FD4DD1F3A7C5 +:104DE000C440FDF4F1E51AB6BB05E814CB928E2F52 +:104DF000CEBF1C1F7582364EEF55084FA7F74611E0 +:104E00005EDEDDAE123CE70E87911D726E7B38F1DF +:104E1000C1B9D6100FEE9BEF36B84352A0BC3B256C +:104E2000CC8EF273774A12E9D110C1672761DD1881 +:104E3000CC7FD62BE9F1E89FBCBA55E9447FBCF89A +:104E4000C5A814A4E393D19D477E4AFB15068A4367 +:104E500003BD1E7B02E5DFF004DAA73B23E43458F0 +:104E600082E16877D61BA41DEACAC5F2C930B19F9A +:104E700002E519DF6DF75D86EB113CBF25AFE4C697 +:104E8000A3FFC586C712BEB2154DD7E817C740F8B5 +:104E9000AD237DE5DD2FCFB0E3FCB25E7C2CED676A +:104EA00000EFE6171E3FB78BE0F6901C78EEC5A723 +:104EB000929E8452EDB61561E8B7809E67E341FE8D +:104EC000ED5E13EEC0F9EED6DB8F34A2BC7FCA4490 +:104ED00071A5677F71F7473BF1F9605DD1DDF09C0B +:104EE00093194DFD54FC72EED44468B779072B44F6 +:104EF000B6CB05D89201AEBCB567F727C278059E40 +:104F0000A8524C07B26F293C9004E55FBDAA7871A6 +:104F10003FA0A8B363838224FCF533496807DF818F +:104F2000C1043F3F3A7744D92195E73706D8157930 +:104F3000ED674BB0BF17923A974401BFE5289D2714 +:104F400096C3FAAE1AF1A722F2EB443CE795AE59AC +:104F5000EFDEC6705EEE44B493DDE5068ABBE3F493 +:104F60003197E8F4F674B25F76E8DCA4B7DCF38C32 +:104F700076F4C34E3BDD8F237DD6417BB497EB0A9D +:104F8000DD1157A07FF9D70C3B50221BB1FE9A329E +:104F9000C44FFDF647A62641BBD313783CBDF2951E +:104FA000CFA6927F0F5E30FA55A7B737C7DD0ADF6D +:104FB0003D905742792C4EB593C6610D7C9CC784B9 +:104FC0003E643D05B41F43246EA5AC0923D6477744 +:104FD00045ED4B66BEF56AE85A6E43BB78ACCB68CC +:104FE000C778F95A9B3B11E37352BF829E7423DD4D +:104FF000241A44BF9659E45F5CAA7E94713BD9DFC2 +:1050000063061E4794F1BD7506AECF37813C42BAA8 +:1050100093FA1CC66DCB1CE7171F04E15F087026CE +:105020003F16C2FDA84B1C5FDA5F0DC2DF2A117A62 +:10503000794E4CF39E1EF41B8DAE7538BF05CCC166 +:10504000E3EE9ADD8AF2FA0F46C75399A467FB5341 +:10505000700EA0773BB05CAF825D96EE6797192F1C +:105060004DEF7E6D743C8BDF5F6AFB6039BDF4737E +:105070001D2B44F9FC08973BCDC2EF6C167E66B33E +:10508000B9D8487CFC9AAEF620E8E1AB780F03FD76 +:105090002E3517119F633AEC85F0B617F8DC0572D0 +:1050A000CA0BFAC535121B7537631CC901FF3703DC +:1050B000FD4C3C0F8EA89FFE0CFE1ED6EB20CE6F43 +:1050C000120B0F68E76051144F66A6E8FFD2BC27A9 +:1050D000887593F04F107EF2847387C3519E2EFD26 +:1050E000BC88E4EA50F3DA23E6F55B9C173C57E40E +:1050F000383F4038AFFA874543BE9EA8A9CCE5A704 +:10510000EF611E7F437A707C1D16308F01BABFC4D9 +:1051100079FC48616E8C9FB3B33CCFA94BC42BBACA +:10512000AAF228EEB303FD6CF407671AC8EEED325D +:105130002F26FFB9EBED61240F76CB785039CF33B2 +:10514000EA0A15DF0FB390BF9B14C2DFB3DB06FA88 +:10515000273DD5353789FADFAD78735FC2FE671812 +:1051600087F0D755CA73EC5F1E42FE6E7BE1E237D3 +:10517000F3F1FDF25C1A5FFAE349AAA7350DE54F9A +:1051800093CAFB31EFBF0DFDD2F6B3064A5A1D9C00 +:105190007FEB36639E84CCBF95FE3CD6A3DF3538CB +:1051A0000F17DA035E3F10EB7758E3FEEC61F49FD4 +:1051B00047FBF61D0E0FE493F07E5CD3C335A4FFCE +:1051C000E07AB90EB25EFAC51FEAB97DDB1ED536AC +:1051D0000CF7ED32B25CC959400773176C0A75F9C8 +:1051E000C575C235E7882C58BFA3159B9EC3382EC2 +:1051F000ABE07EE08702BFEEAFB83F3EC1D073FDAB +:10520000CD809709FFD4296EEBE0F51FC847B98719 +:10521000E79D338DE7473FFD560CCFBF49E5EBD700 +:105220006FE671161F9E785ECFD39DA378DC425542 +:105230001CE817CBBC9EE3128E3DF9B4EE65B8EFC7 +:1052400086F6C8325D07DA1C5E91EFF3B4885FBA68 +:105250003BF504EFD3029F770AF9F734F326A39FB7 +:10526000E7EE0A15F9CC9CBE9EDE994BE37A9935A0 +:1052700092E2158754C6E30FF604CC6BEA937247AB +:10528000117939226FE76981EFEF91C7733DE279B8 +:10529000C83C9E01BC819E80F2D38D3132CF49C47F +:1052A00079CCC178E3F0D7DA04DE3AEECBC27EF6F1 +:1052B000E8C9AE3AAEEF7FFB329CCF6FD2799E1633 +:1052C00098306BB1DF9D23289E22E37180B7829DC9 +:1052D000D86E7B08E145E24DC6E7E43C07F286EE76 +:1052E000D16D403FC665E071BA23961EB3FFFEDC68 +:1052F00011E73133CAA7BF34AA5EC377E4FBDC2EC3 +:10530000F2886E17F943B72FFBE87694EBB7577E18 +:105310007D07D5D706E6433C92E5B82BCB9FCE8ED2 +:10532000EB06E25E88AF5DA668892F9EE775DC34E8 +:1053300088CE28FFE2D31C81AF6D94EFDAFF8A227A +:10534000F0C5F1E97E7CA487E77778C2FDF39F760C +:10535000893CF95D9EC03CB05D32AF5DF390BD2AE3 +:10536000F1D26CB11BFDF19213E77A00E1BFD75483 +:1053700064C4FDF4CAC8924318BFA9D7405F03BEF6 +:10538000A78D74B5217F4A3B46C6634FE9BB0FEA40 +:10539000109E6597A6476BC2BAEA15E0E3135D9BC2 +:1053A00076E013E021FA612F73B97ACAE28D40B832 +:1053B0006AA06A6234EE2B034F47F332DAADC1794B +:1053C00032C42A71FC3DDA0B359DAA233402CB0688 +:1053D0005F3BA4071DC71F7B91C735AA5967DC72C5 +:1053E00095FC40E378B073CEECFC7504CA9D6A93DB +:1053F000C9B80CEDAAA0BC95EAEDABBAD30B06D7A1 +:105400000F862748DE6C53051D7823FCCF41F8D664 +:10541000DD1B71E1F310D01ED6572FDA9D12EB7B06 +:105420002A687D4F0DAC2FEF67A0BEF3680AEAF93A +:1054300033328E60E7FBAB352FF1FDD21542FED63D +:10544000C4741623BE93D4C0FD44F9AC31326D82CE +:105450009FFF5193CD8CB81E325E58E364DA157EFF +:10546000F9AC351E66C4F20E1DC81113AD9F26D6C9 +:1054700091FA81F6B48ED546669C08E56AEC0F9FDA +:105480003A4F0AAE9F846B101C4178FE5B168F4723 +:10549000AE907C613678A45C44BC8D5C6B08687F00 +:1054A000C66CB8D301F08CF204D6CBFE4F66F1FD8A +:1054B000A76CFFF5B50D8D97B3593C2EF0FCF303A7 +:1054C000ED559E3704E6BDA4472BF7B7F408DF0778 +:1054D00006194FFB6132D883354813693E3CED28ED +:1054E000742547C3F38C8ECBDF1D5150CE43FB9602 +:1054F0008F2FCB03780FA2EF7B3F58988C793129FF +:1055000023395E82EDD1E5E6E2787CDF25C63BD12A +:10551000E47DF863BD6F3EC79A1C8E8A4C5F79E1CB +:10552000DA4223D2CFA27585C6797EFE6BF396034D +:105530001188C71C133F9F7762CB18CA873B61D283 +:10554000B17005DF8F31E2FB53A6FDBFB742FDC24C +:10555000755145FEE71E16AD9DE2A8F0C37FEE969D +:10556000C0F5C8EF0C2C8FDE1958CE465B78DCF7FF +:10557000FFAED01B581E7328B0CCFA03F3AB5E1DF0 +:10558000EF9C7503EE67AD53ED585569D2B9F1BC88 +:105590009766E27CCDB6AAB4AF5669E179549FEE26 +:1055A00058558CF67DCD5F2B0EA23FB7E83D8E9F00 +:1055B000E0BCBFCAC307BF427F1DD65DA13CB1CDD1 +:1055C0000AE9B5E07C4019A71A2C5F968BF81ECB30 +:1055D000F6A7B3607A3829F29E6A1BDF7CD8FFFCFD +:1055E000E3E59D6B28BFBF6A5AE0FC6B348D2DBB91 +:1055F000A07C75733FC0E4B0227ECAC579A9DEE6FF +:105600005BAE43BAEABDA5EC38EA892B1A4BD9D177 +:1056100031F062F51FA6227ECA1F5018CA99F25FA8 +:105620008F7C8DF26B853FB748ECDF59C65B77F610 +:1056300040BB051E1EBF9A1794C757B13A088EA0EB +:10564000FCBD453BF77D85E306E7F1C97CAFEA8DFC +:10565000DF8604E6F7F178C1155D1D2ACE7F8180D3 +:1056600057DA19CC3D91CE67F023528C7D8CFFBA6E +:105670001CF3D05CF52387F9EC8D2BDAF9F7758CE8 +:10568000E799C9FCAF8521E03F801C3B6436107D63 +:105690007CB63692E2A99F613F585EA7909F501753 +:1056A000C3CB75CFF0B86A9DD8E7AA7B96C7C5175C +:1056B0006A3C8F1FE9C6E1077FAD9817D2897F3D0D +:1056C0006BE37EB7CC47C33C35875F1E432DCC0BC5 +:1056D000F3F8313FCDFF3BFFFC34FF7ABFF83DC507 +:1056E00001645CE269BDE7B9CD00A7FAF3303BDAAB +:1056F000D78C39C3903E411E71BF6906976F17DB87 +:10570000876C2FE4F36FAFCA24BF28096526EAE54A +:105710008743E97BA917F5C2DFA900731ECF4F5558 +:105720005487117EDA87E9C8CE6B9F6BA0F85FBB08 +:105730008DEFC3B53F62233F6960DF714D48C0BE46 +:10574000E3AD0379E78E2C23BD0FB54B7B96DE0FBF +:10575000B34AFB3E480F7B86A13EF910FF13F07C55 +:10576000ABC833BF55E4974B7FE8D681FC72CF308E +:10577000D4C3127FC1F5920F65BDF4876624B97654 +:105780008FF4DB676F8FF284627E28ABBCB47DAF91 +:105790004D621E302FB22B3F56785E6A4598F3FE5D +:1057A000AB117F8FA6A521FEDE1CC9F55C71892394 +:1057B000CBE28707B9EECCE1C842BBF3E335A145A4 +:1057C000880F99CF76A490EB1D3C578DF91BEF8D78 +:1057D000E4FAEF3DA16FE433218CE78B7D3C85EF4C +:1057E0009F98C73A0D6857818D4F79591506E7BFC5 +:1057F0005DE5070F8C6B443C1D11FD49BCC1BA3BF4 +:10580000D05EA9F86508AD3BD35CE958BEFD7036A3 +:10581000E50B7F2CF4A05C17C6B8BF7EEB3BC3E85A +:105820009CA0949317A74F710EB64A4FF402F44907 +:10583000F679FBDC2CA2CFA801BF5BD0E94366DE82 +:10584000CF9492448C7FE0DED63FB1FD94817D6F92 +:10585000E17703DD5CD0DEE37430149D0DD047109A +:105860009D05D3CD50F474097466CC1E36349DC1A9 +:10587000F7E39CE6A1E9ACEED51776B871FFE4A595 +:10588000472218B43BAEB5C5E1F9E5DA4D2B22F05D +:10589000DCE9A79A3B02FB3BEE51CB2E94E7734D1C +:1058A000B622E24A0E93E2B7DF7DE2F907A653DEA5 +:1058B000C926BD054562C396103AB755BFBD8AF2E9 +:1058C0004DA1DCCBCBAB689FA8616750FEE9B38FDD +:1058D000C45929AFD89D8CF948603F537E4AFD4694 +:1058E0003DE5AFD6BFA7DA912C1A58FF4A842FF8AE +:1058F0007B84E33CD06D43A75A6E881CFC1E288431 +:10590000F471C3F607CE62BCBA61FBB59FA05E0B13 +:10591000CE63AD14FB0CC1FB56C5D9E6583C7FC421 +:105920002E6397A19D08F8B17B912E01AE4CBEFC71 +:1059300044C7CDCF3DFBE22E80F7F887F1851852A2 +:105940003AB5F1CD083C5F2AF7B1E4FEDEA9CEF40A +:1059500048D705F02B9F67C43E876FFDB81CB7EE94 +:1059600054F0703FE68DD3B356EF8DB812C6ABED51 +:10597000D093FCAC7DE199CD4F209D7F1042E7454F +:105980006B5E78FD4F57A0DFB04D1F3B8D4FC7A416 +:10599000C4F9D6ADC1CAE3C4729DAA7FFDBAC19A4B +:1059A000CFEBD19E90EB55B36D1F9D230FC66B6956 +:1059B000E73E3A673E68DD3A7BA7527CF4B92F0D8B +:1059C000C89FC7F72A2CDE36F8FBCA4D6F46603BEE +:1059D000B96E03EB3868FDBCD3778DA57616940FAE +:1059E000175BC738FC6FA27733C3FCB9CA0F433CBF +:1059F000D3707D7FB194E8FE136D31A7FBA756C429 +:105A0000A1BD5BA977C759E8C9EB2BD7FF48D0A345 +:105A100023919FF37127E2BC16ACBB89E6B590B920 +:105A2000880E2B9FE2F9539F837FB7ED02EBB957A6 +:105A3000F0CB271B42E83CFB27223FDBFD4755C448 +:105A400001EE22BBE54762AE94B108E5CF851DFBB0 +:105A500070F640DE86D1DF6F6FD8B8AA1BD7E5C4D9 +:105A600008473CC6DF60FE6E812F05F321D53F4C11 +:105A700089E7EBC2CF79D077604F94623DB6EFD61D +:105A8000D3790FBFEF086F72FC1F8AF101EE308CE3 +:105A90001F7C12C7FD1AF8EB4638EA15FE4DFDB221 +:105AA000CA6956C0FF6931CF01BEDF781FE773C1F5 +:105AB000F7FF788FCB937ACF8C329207DD7A6F3CE9 +:105AC000B6F3EC9BAD903C08CEBF1774B0512FF8E5 +:105AD00039F03DC0A529FEF8DCCBE3020D621F7A48 +:105AE00061BB5FBE3FE26B5999A01383AFDEE6E373 +:105AF00047B90FBD48F07FF03A06CB839D41F24095 +:105B00007ECFD65D789FD4C7FF6EC2532DD81D16A9 +:105B1000E4DB0F42484FD5AE51294FF4E8EA037158 +:105B200097039D9FEC94FC1A286707F87519CFE33B +:105B3000AF7C799382741ACCAF272B3DCA05F91537 +:105B4000EA2FC8AF95EC7F56CE8A75F0E13D903FC5 +:105B5000170D21678F668BFC0081D7CF595EE495C6 +:105B6000F8D2529E4AFB0541F895780D9697CBB234 +:105B7000AD1794970C538AFCF029F128E995311759 +:105B80008D3340C7925EA5FE1AA0D7E07907E233B5 +:105B9000F8FD669C23C0E3FC0DCFEFADED52C43998 +:105BA0000EF7C1E4B1C49F0E7EAD45DBC1E458FFE2 +:105BB000B227A8DC19D4DE11547606B577059517FF +:105BC00007B4AFDD79C0C0F37CBD01ED421AAF2749 +:105BD000FF6AB01DE1E1FB9CDBCF1ADC481FC3FB71 +:105BE00029DF587F2F739B293ECCE3657DD6FE08C5 +:105BF000B457568472BBB1CF22CA51BCDC3FCCB083 +:105C000012E5A1ACEF0FE5F1EC3E677F44945FBC79 +:105C1000A2B74BA5F3E43D1E1E271B0C4F33F153D7 +:105C20008F88A34D514D298D6331FF3B9DCEC59D7E +:105C30006BD18B72269DEB9676655F188FAFF485DE +:105C4000F1F8CADF99F34F57E27AB81D1AE6DDCCB6 +:105C5000E74BC72A7FD71C817181F95D3CEFA662B3 +:105C600075E0BA2E346DA4739C9FB365F45CD81EA6 +:105C70009837532DF8A0725D507DD7F5C417D541E4 +:105C80007CE112FB09C17C317594903785AC50C41E +:105C9000A9685F6F8990D353D4BC1BE700FEFB0E4D +:105CA000A92C04CAE7BA54B612E7BD55A1FD4D3C74 +:105CB0007882FC26FD4689BF53C8372307E375E089 +:105CC000FD2B7F2DFE19D2C98E3F17601EC2A91D64 +:105CD0001F64EDC6F2ABFF9EF26736B87DE9DEAF1A +:105CE000EEA0BCCEBD2194B3D1B7F78D949F61795E +:105CF0005708C509FAEE0D21FBDCBDD74CF197BE64 +:105D000011DC0F68DEF365410FE9177EAFC15DA3BB +:105D1000F83D13E7BAFEE308C6DFCF75C1AC50BE4D +:105D2000EF0D27FE69D8154AFE63DF9E2F8BFDF32A +:105D300087FEBBF391F9207D667E9EBE2F8AEFFB26 +:105D400034ECBEFC19CC5FA8DBBECF301FDE97FE63 +:105D5000F69B0294A37D2F73BBE88CBE673DC6689B +:105D6000973DF7AB767D22C62B19DDA732ECF99370 +:105D7000B3DD7917C20BC7431FE001E70578A944DB +:105D8000F93F143E1EFE97C5C7D93BB83CBB8C619A +:105D9000BE830F2FFC3C7C6D9799F29161FEBC7E17 +:105DA000EF9705286F2E36DF6DFFC7E6FBCEBFEC01 +:105DB0007C39BDDF32CACAF36183E87E305DBFFA49 +:105DC000632ABF68B613BC97C8EF7DA3F879F47F48 +:105DD000BDF9FFEFACB739E75F75BE175BEFDF8941 +:105DE000F5365B303EDAB7E79B14F63DE69DF7FFEC +:105DF000E9BCA5DD5EA2DA0F15621C8E75BE67B721 +:105E000091F5417647B3D8577823C1C6EFBD127ECE +:105E100052A9F0936E1179A8CD4C47FB80A5C61A04 +:105E2000B23B4B873F7896E7CFE9089E378C576D9A +:105E3000A6F310417EE1E4E12ADD577760398C0F4B +:105E4000ED0E987596665EDF8BF553EDDCEE9F3AAE +:105E5000FC7ACAE72D35BE3D07E3C9934D817ED359 +:105E6000F541FECFB5D6C0F765ECE5588CD395E586 +:105E7000E9E94EB2A9D8DECF3FBC2C87DFBF702D39 +:105E80006B6BB198FE4B78213F56137869C9E1F1ED +:105E90004C8997C178107864DCCE09C69B66BABF7E +:105EA0009B9E0CFC583E2FF27FA51F2BF1178C37C1 +:105EB00026FC628D86F4E1571BCEF79FFDFAA3798D +:105EC0000FE053E0FBFBE235787D2E86E75B73F84D +:105ED000FD68C1781EAE156AC84F5709FB7CB21623 +:105EE000C5CBC3BB5527E1CF43DF95FEC3AEA17D34 +:105EF0003EC914A551BE987584EFFE9C64C69235C8 +:105F0000E60EC1FD014BCF6BC877E50F875811DF57 +:105F1000C335715E58E37171E056775811B5771843 +:105F2000A2B1DD228627DBCA93995DE1ED19DE3748 +:105F300084870AF1BE24DC3BC3EFCAF1B2386CF7A8 +:105F40008046E7D0E90FF09D81CF34EAD7A18BE6F8 +:105F5000DF4714D1F76E1DFFDE81E7FBF5CC92829F +:105F6000F757A6965A7E7C18FD8A15A1B4FF30AD6E +:105F700084FB0F92EFCFE4F0F36DF2796FAE559C96 +:105F800083708D423B777ACB28F24F9A439D75AF51 +:105F9000A01E7A219CF255CA57FEE0867108DF8B5D +:105FA0003176249713D3B7D17980792D737FF43E5E +:105FB000D4BBB68452FDB3B9AE1D39D0DF09C57A62 +:105FC000C72B5031EFA60306CCAF9EDEB9ED0CC651 +:105FD000F9A6CF0EA7BCD2E9ACF3F7987FCA66F357 +:105FE000BCAEDE17CD06C4C50D9D6735F4B76E98FF +:105FF000A0A05863BDA19694BB009E72B12FBC5F58 +:10600000CA85501E472E5F39222B0DEA6FC0F38AD6 +:1060100017F0773E93FC32495987FE4BAA389F24EC +:10602000DB633FD8EF57021F6FE7F0F8912CA7967C +:10603000F2F615AD21BDE9E8CFB4EABD23717F2F9B +:10604000BFE40F38CF69696CEA5ADC57B85BA5FB2F +:106050005E7A43D9418AAFAFB159D1AF733191EF75 +:10606000B1DA46F1ABDE497603DEFFD2BBC666C1CC +:106070007CEDF03CC7415CF7856D8A15F9BD771260 +:106080000BC8CB3A62F16660DCE3887D941DE3EDDA +:10609000A9F29C587E18F98D4579AEBFE7009CE5C2 +:1060A0006DE56F219FB3AF61DEC5983FCC88781F47 +:1060B000B8358C79911F7CF77B9DC8A13C50FB2F94 +:1060C0002E8BF5DDEF95AAF27CD86B911EE0FD34A6 +:1060D000CC8F053A5BAFEFA9C27E9ECB11F5D1966E +:1060E0006213A72F86F0F5EA2D5938BFDE15A13AC5 +:1060F000DCDF9B762FA737A07FA306DFDFA7B130B9 +:10610000DCE73F28BEBF7DB9E6C47B6A871B998662 +:10611000F773DDD05948FE7447BEEB6DC4E7A7F7AF +:10612000B02B709DE6AF5E43FB2872BD98D63D391B +:1061300006C6F974938DEEB193EBDB915FA2CBF5BC +:106140005FA7D90AAD0FCCC788F0CFCF9F67C4F740 +:1061500050BF0FD76F5A893703EFDF9AA2D63207A5 +:10616000EAD3046647BD7C8E71FE3BD7AA517C49B9 +:10617000F2BBE46BC9CF0037F1AFE4C7603EDEDCB1 +:10618000C4CF866E6932D2F3F9260BD33219DBDA2B +:106190009440E5179BACF4EC6CCAA6FA979BEC54C0 +:1061A000DEDE349ECA3B9A1C54DED95446CF5D4D88 +:1061B0004EAABF03D087F923303EC91B2967103E82 +:1061C0005D914F0EC8F5D3B74ED2A19C96EB07FE5A +:1061D0002EDD1B22EFF51ACA2EF8DF821FE4983B52 +:1061E000B2C887572C87FAC9492C9BA37DF3C3D427 +:1061F000C709D17E724EE3F733A03C8C2BF2CD1F42 +:106200004384E78B7CEB82DF4D0C5A37A44389171C +:10621000F8DE1B57E48F97530F625EDEB94A9D9DEF +:10622000E21FACE78557A96CA27DDF1403DB89F17F +:10623000DC9E9F9B18C64F559D3D2104CF4B552A90 +:106240004CF38B37FC607128D3FCF4D79D8D510142 +:10625000E5D89F1F7E1DC369C3135CB7E6029D1F6F +:10626000B9FBF4DF9F85FE9FBEE758BE8BE8F1D4F3 +:10627000A6C770DC6561768A4730BC5B8FE231B4BB +:10628000CF867F01F7F3BAC3E9DEBFF506CB9F9E49 +:10629000C578EE4AD58272745E0BD7CB1FE23A0204 +:1062A000DEFF22D63155C46FE4BD84E5327E1E7414 +:1062B0004FE08F72D3F83D0422CE73E4A7C9BFC06C +:1062C0003CC6A757A81691EE13788FA180438E1B6A +:1062D000DCDF47898CE22760FDB346588F8FEE31B3 +:1062E00078F1ACF6478A91EE8B50ACB1EC76A8779A +:1062F000B5F2FB8095C64394E7E0329AE8FC22733E +:10630000EB4FF9F7A734F2FBF158CFF0288C7BCA9A +:10631000FBEDC2C73A0C78DE1E6503D2CFBCECFDA4 +:1063200074CF166B532CB8AF5321EA2BE4397FCDD1 +:10633000356AB619C472AE4AF3DD9AC3EFE3FC26A0 +:1063400087F9EE73F48B6B55ACE6F74B56B4151A20 +:1063500016FAE99979A27E7E36BF0F5CD6AFCBE5FF +:10636000F79025B59657215126897B3192B2E75592 +:10637000D139E439D769387FD9FED15C4DC0C1E845 +:10638000F90D0AC361789F2AB707E7CDB975239D38 +:106390000B645603C65BE578F3B28B56627EF4BCA1 +:1063A000D5785B05DD9F4979D58F464CDD8472CC6D +:1063B00013D46FADD07B303F03EE9B7E8A19F6B4C9 +:1063C0009FCCE37CD52FFE8AF6E3AAFF1C42FABCE1 +:1063D0007A34D7BB2CCF53CCEF150C8CAF4FFED5F6 +:1063E0005FE93EC986EDFCDE4978F2B8AF8C13DB7D +:1063F000795E63707CF7B517FF1C71C1B8FA76BE81 +:106400004F78B1B8BA3CC7D7F01B1E1796786C50BE +:10641000CED3BE54C39E1571173A2787FB3A4887DF +:10642000C1F1F54B8DC307C719DFCD0D8CBF5FEAF6 +:10643000F93C59AE6C2C48C7FBAB5314D711940BE5 +:10644000D58DC5E9B86F5EDF38919EC1E7F72A1B8D +:1064500073A97D75E3187A9F95AB887B47199D03D7 +:1064600095F1CD739ECC48F61D7034AC0560E1FB10 +:10647000739A3512F7EFE439EEBEAD2AF9137D5B5E +:10648000F337207D56753D6CD0417D761E1FE77435 +:10649000D0BE41FDD6A3B4BF57C7BA699D60FD9871 +:1064A000D17F1F09F312638686AFE657E6C548C75A +:1064B000559D8A6313EA276327C543CE6DFD81DEB0 +:1064C000EDB7AE5A9E16708E4AC2FF95B05F653D1D +:1064D000C28BF0D484749EF91039E2A570C6F3AD76 +:1064E000FB7F8FFBBE27D78DA17CEBAACE6DF53C41 +:1064F000AF2DDC8271961341799816319E258FDB82 +:106500008327C5BED9C9175592C7082FF2F30925AD +:10651000F0BC5B9CF82E2E8FDBA9BFCAE57C27DB85 +:106520005775AE21FBF0CCF6EB33D11FE8DBF96EEB +:106530004406D45BC5777DDBC3E9FEC1BEED4F4E9B +:10654000DD0DF47DBA73522CF2A1EC3F3F8FFF6E4C +:10655000C1E92EBE3FC83C3C1FAA0EF13CC61FCE6F +:1065600018BA97427E27F3C14E6EFF75842ECFB7BF +:106570008E0D46772B1ECD97F78918F52E37C61747 +:10658000F43BF93DD3C4E7D07F6BB6DB89725CB6D0 +:1065900033181DA46CE57D694C9E6314E766409F2B +:1065A000BDED02F897541928BE7EC768EB2DB7A140 +:1065B0003C7E534FEBB16414F3623CE3B346730784 +:1065C000AEF3129B9DF665EF1823E44D42CF38CC15 +:1065D0000FA96D559803F3ECB64CE3E772840CE811 +:1065E000B5D9DF598576E8DBDCEEAEF5A8CC35868B +:1065F000E448169EC360E3BD59988F92027482DF0F +:10660000CF16EB78C4C0F3416BD3F839805491BFF7 +:10661000521BCDCF0D9C92E70A667AB3306FA6F677 +:10662000E544CA9B3925CF09403DC2595BC4CF0B15 +:1066300048FCD6FE747F16D25DEDBCCE6C7CDF6B61 +:10664000B39CA1FCA457CC74DF92EE55B3C87B0B6E +:10665000A57C7D147C9877D4BC2991EE77A914F0A1 +:10666000AD1FC86FE6E71D92EE3145F89F77A8325F +:10667000B4F1F30D0ACF979165392F2CE3BC4E0985 +:106680007AAE0A1365017F55441BC1DDAB67FC5C24 +:10669000C773FCFCCD89C4EE1D94D7FADC28BAA7D9 +:1066A000B2D7E659B893DE87D23D91556E85E47A2C +:1066B000F5F3215E9CD7F1E7781CBEBAA991EE11E3 +:1066C000AD06B6C77376F02CC3F372C7F56D2938E3 +:1066D000EEF161F0443FEB1E6E3F1D323F9A42FCEB +:1066E000BD314441B95D0DA485F6DF39D676C713B7 +:1066F000BC1E3D7756BD3184CE21B8A01ECFA73237 +:10670000B08B906E24BEE17D401E64AF2DF0DE891B +:106710005621AF5AF3B81FB73A8FC761EAC23B1F81 +:106720004DA3F9713E81F5E17973CC93F8642CE6C1 +:106730007F642A281FAA3B437BD1FEA8DEAAA77B41 +:1067400058259D548120C3FDE42AC6ED4CE5E75B46 +:10675000B2D03F6B7E2EB408E7D32BEE17ADFEE927 +:10676000CF385E5E353BF8BD287487133BBE399940 +:10677000F2D1A761EE19D1473EE17F8ABAAE80F827 +:10678000616338FD1E41F5AACB74945FA2723F0C81 +:106790009E0E85F2F48D24476B851CAD5B7565E418 +:1067A00095C857EFA8743F7A75E442F2033FD3804F +:1067B0009F2E20FF83F1F6EF79DCEEA9053EC17331 +:1067C000D375E25C57CD667EFF66CD4A1E6764CF07 +:1067D000F3FB5697867A2370BCA59B543BAE538D32 +:1067E000A1336B188CB35FC82F68EF42B924FB5BF1 +:1067F0001ADAB910FB5BFA4228C9F3FD79B1229F7E +:10680000E7E138B47B07B7E770FBDA3D13E19FF7A8 +:1068100023DB0DCCA793C7973E63DD3FFE337CF2AD +:106820008FADA104177828745E2E78BE27F5000F6F +:10683000C07FF28550BABFF11390836E3C171EE5FE +:106840007888F222FEA0D2BD450817EAA3459EC073 +:10685000EFEB62EC91987F59F74EA986DFBF91C7A5 +:10686000EF278275B891F0F48E9ECEC906E3FD79CC +:1068700021B707F8EE8570A2BB93499C0E4EBE3837 +:1068800092F44A6F14A71F803305F3A54FBE30B2B0 +:1068900090DFDB9340F668B585AFFBC9A8CE148BBB +:1068A000DF7B4977CC0B2D913EF09B74B413B85D20 +:1068B00056635C4DF92F983F5D5C444F6FC805F2FD +:1068C0009F812EC97F1F9E2FEC0A1C2F4EE4EF9351 +:1068D000DCEA34A05C76093BB2766B70FE347FFF55 +:1068E000B5E03F843656E66D63BEB85BA13C9A9A2C +:1068F00096BBAA903F6A16AFB90DE955C25FA3B126 +:10690000329407BD8A4A70F486F27BBF99FF3869DA +:10691000FC6989F3CDD390CFF56D58BE55DAB9AC8B +:106920000DFAA96D515653FF361947E0F391DF0177 +:106930001A0CA8277A2789F743CC57C2173C5FB9AE +:10694000BE29F95C7EF7DAAC0F4DE07A89E26FE799 +:10695000BE1E1319FD1DFE367AB203F9CBC0EBB98A +:106960007499017C9FC7E39935001FC299B52EE841 +:106970005CC0C6C072CED6C072DEF6C0724157602F +:10698000D9FE5A603906C71DC6FD7F3C6F8FFE3F9A +:106990003ED1FFB78670FF1FCBE8FFE313FD7FAC4E +:1069A00047FF1FCBE8FF6319FD7F2C4B7C631C0066 +:1069B000CB1807C0F7E5F95C1EEF42CF44F5E58937 +:1069C0005EA9EA385FCC3504E431EFAA1C7EC173BE +:1069D00064F27CD705F24AE99C983C8F1B7C4E6C94 +:1069E000E09EDFA073624867D84F4E9C6B7A3EC032 +:1069F000774CE95E990870EC4AF3E42E217D1F6A1A +:106A0000C2BCF99E159FAC4477E9DB61AE59F968C9 +:106A1000AFE9FB37F373DB5E92373DCBADEF5C2D17 +:106A2000ED1280B31CB08CF42CCFED5EF4FEDE8B47 +:106A3000DEDB1B482FD2AE7B5ADF9F8872F3E873F0 +:106A4000C6D508E75111D764738C41790FDC6F5AB2 +:106A5000F2A042F78DDF95CFEF3B387708B0F31DFA +:106A6000743AFFFC18B2B707CAAB151D9D237039E5 +:106A7000481F49BB2C4501BB0CE520CC1FF5F5C8D0 +:106A8000B5BA00F84779C202E82E774B74D0B996B0 +:106A9000A480F6A377A6059D6BC9093C37317BF925 +:106AA0003ED4D3B3568F096857E1BC32086F024E0B +:106AB000619F56A05D88FAE61E23D1D5D2F755B264 +:106AC000672AF125C8C74AEC0BD6B172A3C8C76EB6 +:106AD0000CD4BB951A73E33D68F3853E92F4566976 +:106AE000618E28F8FE7461DB66BC97B6EA77EF1614 +:106AF0005BF0FC9F32291E831535D9AE2791BE521B +:106B0000F40ECAFFADDD961985F7D39D3AF43AE548 +:106B1000754A3A49D15BC2703D3BDAB89D8F7133FB +:106B200035DAB7DE1D6D31611926DFBCFCF25AC8BB +:106B30002EFE0CF35AA0AA7292E2368CF6C1BF4424 +:106B4000E80F09EFC7C20F602DBC9F1F8AF7B5453C +:106B50006FAC8F86A53BA5DBFFC52AD453859D5915 +:106B60005EB4D79EE888BBD586E2D8B51DE97FC95B +:106B7000DBA511987FF7F9563DDD97FBF7F667D651 +:106B800063BEF4AAB6670C1817A8D63C06CA0F7DD8 +:106B9000AEC380F9D2D76CE9A0FA855BCAC96F5C35 +:106BA000C41693DFF8A9BC6744CCBFB2445967014F +:106BB000B8130BB8BCA80CE3FB9153D409AFC7C200 +:106BC000789F6D51285F78B673C6946168AF74463C +:106BD000D17D51BF17F22598EECFBDA5F2F8EE6C2E +:106BE000BECE43DD6335EBBC8DE87CF6F95CF2A7E5 +:106BF0006EF28EE2FE6B5EA0FF5A69B0BE83729E9B +:106C0000FD9B4ABFFB321057B0EBC94EAE03F9856E +:106C1000E72C9D13D4003A6C981C1E40A773981F54 +:106C2000FDC3D03763128C5F79F6B4F480F6B7CC2D +:106C3000CE0DA2EB22DF7B920757049CD7ACC31A80 +:106C40003AD75232A89E9FFBBC2EE0FB3A3633E087 +:106C50003C60D546BEDF50B73D8AF6232BC57D800C +:106C6000735CBCBE7E27AF878904F0576AA9FDDF3D +:106C7000B91ED4F3DF9810FB1273F0BFD307E31DE6 +:106C800034F7C03D0878AF05C61102EE3F10FB9AFD +:106C90000837D9BD22BE5497CDE34B75EE6E03DEA7 +:106CA0001B0278D76230AFB34DA1F580F6C69822AB +:106CB0005E5E4679DB817965D81FE667D61F52CBC9 +:106CC000914F82DF03DD71FB7717CF97ADC7F810C7 +:106CD0009D730BCAF3C47811C6BB305EE4B77EB7B0 +:106CE0001558795C6DCBB68349808F594E4EA7B548 +:106CF0009D33F4E57983E90AE89BEEFB5EC880BE2C +:106D0000705F08F8D8631D7AFE683EA23F22F150FA +:106D1000EFE074988474583098FEEADC8B0D740FA1 +:106D2000CC3A853D6CE3ED112F4948974178213CE1 +:106D300006E143E269006F41EF83F1B2D0C5884EAE +:106D400016EE543CB86F2BF1173C9FA1F017BCCE48 +:106D50008B58B701CFB72CDAAED8F15E7FB9EFC34D +:106D6000C607C597DE4AA7F852BD53E047D28593C0 +:106D7000D3FDCCF33C5E7233DE673BC64727B3A737 +:106D800005F2E74DE7E3E8FDF7A51BB004284EFB4D +:106D90007DE945CE47CA678C27129D88BCEB60BE53 +:106DA000098E472E2810798FE3D8B8803CEB21EE6E +:106DB0000D09CEB396FA3C589F94FF8EEB132957DA +:106DC0005D424FB856E8E398BF1E92F5223EB7E405 +:106DD0009E6CBA1F2565790CB52B0FB5D07981F261 +:106DE000E53C7FBB1CDA59FDEC8A952DE929A81FEB +:106DF0003EBA6FE47A37DE2775776CDC7858EFA3FC +:106E00002BF4B1F85B65B2DD472BA6A4609EC9D117 +:106E1000352173E8BEE49F1BE977A1EA76C4F3FB52 +:106E2000F354531CE6779E7E3986EE6F7AB080DB92 +:106E3000E7B52B5E89C0E309352BB85E3667BB56D4 +:106E4000178C43FDDCB19936382C1D05A8179EC45C +:106E50003D06DC8FC4BE8A483F91BEFF34D47233F6 +:106E6000F6FBE9737ABA6F0BDE3B709FE9878AF70E +:106E7000D8D5741F8F1287719D53EFAB741EB44A1F +:106E8000DD5780FDD636ED4CC123F29545A0476114 +:106E90009D4F87B89EC4716B563C93429B56AD1D67 +:106EA000F47B0A7EF1604F01C62B301E0C65D7F2D1 +:106EB000CC487E0FEF85E3C1122FC5B9CA801D8F64 +:106EC0000B86763C3ED18EC77C20B4E3B18C763CF9 +:106ED0003ED18EC7FA86B581F6DD2FC47EAD8C0B10 +:106EE000A7AA67E9778BDC252C7B31E9615336FA59 +:106EF000A74B95303BDA914B15CEE74BFF6AE6BFC7 +:106F0000DBD17D2DD7BF821E82EFA9BDAA1F6C30B9 +:106F10003FBABDFABC91F99F939EC4A202CAA5C60E +:106F2000C480F6532CB680F7D7248C0A787FADB591 +:106F300030A07C7DF6E501ED6FB04F0A28DF38FE0A +:106F4000DA80F6331C3302CAB3CAE606B4BFC959A5 +:106F50001EF0FE96395501EFE7BAEE0A28DF5679A2 +:106F60007740FB1F2C5E1EF05EDEDBDB85FE5708E4 +:106F7000DE8764A4A7BCC7F74B1DA3DF8B9A502AFA +:106F8000CE6387707DB4F4ED4C937F7CE484B0973E +:106F90001C76C7DF917E4688FBAF46887BACCE0B64 +:106FA0007D94CCBC8AF87DCE44A4A7E076C1EF27BF +:106FB00084EFFFCC0A6B79E74B0FDDA2815C9A70FE +:106FC000D9FE31E9507EF6A5F76FD140AE4CB872CC +:106FD000FFAFF1A7665E1A9D3887CAA3F77F86EFD9 +:106FE000C7747EC8DFCF62649AEC1EBDEC16CCB3CA +:106FF000997075DA6A3B8F97F0FB5F307051EC77D0 +:107000004EC668F2E27EBD9C17E205CFEB235EF030 +:10701000E9057AC6E77EA0677CBE06F45C0172ECE7 +:1070200020D0333E0F815F8AF5FF067E293EDF02C6 +:10703000BF149FBF077F149FDDE08FE2F38F4D7376 +:10704000E8F95E938BBEFB5353253D0F372DA6FA0F +:107050000F9B1AE9F9972637D5478F16718D9D81B9 +:10706000BFCB25F737E57E66F362D6138EF2A047D5 +:107070008BC2DFBD93FB9443C7013476CCCF3E8BEC +:10708000648E11A3297E12F8BB2113335C6958FF6B +:10709000BE6D56265EA47FF3F9C5AFE3B6EEFBE204 +:1070A0009E83E07ECF0B7A88B73B46E2775719F98B +:1070B000F9EFAB8CFC7CF7555A7733D253F357CCAE +:1070C0008A7947FBC479EEE6FB343ACFAD9C67542E +:1070D0009E18CBA8DCFC550F9D07BFCA624F203D10 +:1070E00025CAF25C30FDF9E52D4D3EDF5D8AF6C61E +:1070F0004493C18A726220AF82F1BC09B9BFBF4E0E +:10710000CFF7FDF7998F95627C0DE061389ECC0F2B +:10711000D8F815F3EA0A7C791657197B287F4BE6D5 +:107120003D28E77B54B49B647E9584CBACC1774506 +:10713000BEBC2909773C940D45FC9E70B508DB7BED +:107140001331BF6CE262831DFD83813CAE10E6C645 +:10715000F86BBCC82780F604F7E4F32ECA1F992801 +:10716000F24746E0BE2B6F47FBCC66F4D7F0FB98A6 +:107170009E03389FE4FF8031A0DD530ACF7B90F956 +:1071800023D83E9CB7F7AA7EFC99F14F803B027F43 +:107190008FB2937E8F7844BD89EE9F640E07E177AE +:1071A0009690ABCC2ACA425FB3D812FEBB8BE2FDED +:1071B000AB19AE4A5C776788E5AFE1C4CFE923D06D +:1071C0002E9921ECF8EFA097BAD1C3FE27E8C5C1EC +:1071D000D77F38A378DA507423E942AE77301DC9DF +:1071E00075F7CBB7A17597F4134C6743D193A4A35C +:1071F000AB8CFCDEC289B546FBBDB6FF3BF47367C2 +:107200003F9B1A094D9665BACEA37E283F6F3D88F5 +:10721000E5F96C12FD9E8D7CBF6288F7AE7FF4EBC2 +:1072200023FDE8EC2AA1C3B662FB7183DBCB76F2C7 +:107230009E11D9FF9B43F4FFA6B013DE147A6FE9C9 +:10724000144E4F65A3E4EF81394C85C57EF9AD79C5 +:107250008BC83F60266E5F5BE17F14471376EFD5E6 +:10726000E7B500BBFB3A618F97312EAFCB82F6F7C3 +:10727000AFCBBB86ECF2EB82ECF2603BFB8FA3C59D +:10728000BEBF8DD9BEE7BDBC1F70B91E68C761BE49 +:107290001CD27DBA55A5FB81E43DBCF27EE7C982D4 +:1072A0009F27E3FDCE11F8BBA92E0D95CA35CC4D15 +:1072B000CF6B99879ED7332FD9093780E2C1F28DE2 +:1072C000982205E503E1D36FC7338FA5634A33E8FE +:1072D0009E14DFBD92A7109E7AD5F5378BDFBD9245 +:1072E000FB275B693F76BF919FBB46BEC4DFC59459 +:1072F000F3F91DE8DD0CD08B07402FE3F375D0CBFD +:107300001930BF37402F63F9BAECE50CBF9B6A0D0B +:10731000CC9392DF5F6F2905876C687C5D5FF09B83 +:10732000E188CF37A3464EC6F9BE1975D9645C977C +:1073300037A3E2695FECFF01EE54BC43008000001C +:107340001F8B080000000000000BDD5B7B7894D5EC +:10735000993FDF37335F66929964127225904C42F1 +:1073600012024C6066722902D501121A6B6027580E +:1073700081600C5F48C2CD8021C5C7607133314147 +:1073800003A2863628522F1316D076D12728566CA2 +:10739000D376CA45698B2DC576D78A1B0711C52BB5 +:1073A00021D68ABBB6EEFBBEE73B99F986A4B5FBB6 +:1073B0003CBB7F6C78F29C9CFB7BDEEBEFBCDFE19F +:1073C000D789310A9BCED897F873DDD5E595E90EBC +:1073D000C64A19BBC179EF69038CBBC1BE8019C70E +:1073E00031F8D921B332C6CAEDF0270C29FF48F194 +:1073F000B278C62A986A6406C6BEC1FC545ECF0243 +:1074000054DEC082463689B1852C44F57F62CC8437 +:10741000F563718B6A6F83F9F38BE7E7617BB3796F +:10742000284B91A16E56535D298C6D30A86FDA619F +:10743000DC4713D5C90906A407F683F661F3ABF15F +:10744000E9B98CAD8F8B9FCE66609915C073B43E41 +:10745000FFCA7403B45FDB369BE8BCAEED1A2A9B0F +:10746000CDF3A97CB79DF9F34C8CBD8747C880DF6D +:107470002E2F9D6393760E669C47F5DBCD8C7E6E3A +:10748000885127231DCDF240FC2CE87FF7D1579F70 +:10749000F1DB18CB9254A70BF8D26C70EC7025C3BB +:1074A000C05F1B5CFB71FE17C7B216DB706640F154 +:1074B0001531B6CEC8BCFD4EA8EEBB91F6137CDDEF +:1074C0003155A273349B053FFD54DF95EFBD323D2E +:1074D00085B696582A9C9F71BA26C43066F630F657 +:1074E000A8C2CB0D666B10E5C18E983E0C15725A82 +:1074F000BF847397C532BFC543E3FDE6A4B0FC600B +:107500001ED533619DB212281F8C0D74E630A6661D +:1075100078E7E2392A0C56BF0CEDC3136C8118686A +:107520003F1A0B7C4D003E06A7253068AF3C6960D2 +:107530000120F9E5D8F8BDC8EFA3B1C06F9077E995 +:1075400054B50AE7BFEC383A2108F3AE638E07E77B +:10755000003FAEB71A5C41E487A13641B58EAD5FFE +:107560006D6FCC0D1E17F4C3EFB75CB6E477E2E0A5 +:107570008FE96CFA97066A96910FAD9A7C804E5708 +:1075800010E9FCBDC1054761D7B28287E7407DFEA7 +:1075900049130B407D1867607FBA14F003BD1527AF +:1075A0000DE76280CECFDABDC1E326EC1C3230A0FD +:1075B000EF845D627B80DE98749939CCE1FD2D8E7D +:1075C00058E688A027AE304957B7B9C6EBC627CCD6 +:1075D000CCD5F5277AA7EAFAC7557A74F514DF2CCB +:1075E000DDF8B465F374F50CF59BBAF1996B16EB05 +:1075F000EA135B96EBC667B7ADD4F5E7F8D7E9FABF +:107600003B2D5C8ECCEF3D5D087CACE45D6C52772D +:10761000AB6E5CA5755515CA33BFE74EDD7ACC61FC +:107620007A0BF5CB0FFF50BF3E65031283B2229D4C +:10763000B78B7106D40BD867BE7DEE71145526DB6F +:107640007119F573BE1DC6459EC75AF91EEE93C942 +:107650008CE1F93957EBC12ED48369FF801EA85302 +:1076600047D7836616F0E75CAD0727D04F815F9957 +:10767000BC5B2FFF2901BDFCA73DA5977F51BF5ED5 +:10768000FE338EE8E5EF0EEAE55F7C522FFFD2D3A2 +:107690007AF97FEDB5795F495ED784F47A21E435D4 +:1076A000FBE2E251E5B50CFEA1BCC0C45C41D0F7E1 +:1076B00072E053908D2DB7B0BCB8FCFEA7723B159D +:1076C00025B74FD98E5237D071A99EFBEF68FB17B3 +:1076D000F2305BBC67D08F5CD0FCFB671A1FB23501 +:1076E0003FD466E6E51D1ABD9F59B8FFC9D6FC9088 +:1076F0007F1E97B77FD016E804BBFF4C0ED9309E93 +:107700000CCA3D1296FF91A686D08FAF70B648A0E6 +:10771000492C9DF90EAD02FA2F4D1C1AFC0ECEDB42 +:107720006CE3FE9BB120FAC1D0665BDF76294C6723 +:107730005D266B413FFE9E4B227FCA5CA1D26AF060 +:10774000EF1FBA64AADB5C7685819FAB77326F004E +:10775000FDBD9165D515919E723DDC6224BF9A6D89 +:10776000512FE3393BFF6836E339869923C1EE2474 +:10777000C165F9206EBC6562CBFA47F197D996B91D +:107780007F46FAD79A6F78E46D8817B30DB02FC88B +:107790007568AD1CD89B83FB052D93619F3DBD494A +:1077A000AEED509D9DCD78FF7AA6F58301437DCF48 +:1077B0009682009E6BB641E2FD1BA11FFE7C0FF678 +:1077C0007DD68A74042CD536B40B981221D73D4649 +:1077D000568974ED09C8FEFC19682766668CD08F3F +:1077E0003DA09214E78C01CBE222B41BBBAEBFA834 +:1077F0003F5DB7DE8C230E5DBF3B58A8EB2F3EE903 +:10780000D2D543C81727DACF4CDDBC89F02B7BD00B +:107810008EBCBAF6EC5B5B17211E807EAF9C84F6B3 +:1078200053A95B2FFB52AC2C413F29670ADA914FD9 +:10783000D74F5800F85977472AF12B13F81703FB55 +:107840003C6682F89A4475AF02A5028CC5714AB7AE +:1078500091E2E904A0212189D365C071505A681CC6 +:10786000A703FA290E4F84F5906EE8F71A79BF3F07 +:1078700016EAD74F73903E998C804BC03F3D6E0AFD +:10788000AD6511765317037A6825797A517E8F6F2B +:107890001EAFD3D3396EAE8FD74FE376B4DFCC565D +:1078A000F8806F9D775959CE0C9C17CA40F9CC7758 +:1078B00073FCB16AB277AE9BC6DB69DE13B68B6B25 +:1078C000D13EEA66F07D6A65794535CE97403F9CAA +:1078D000E17D16B9B91D4C2FE6EBD425707AD87727 +:1078E00094C0FE9CF039D215D6857805F69D82FAB3 +:1078F0007DCB8EFEFB274357ADD26362E4D70326D0 +:10790000C44955F30017BA197BE087A50F5B01271F +:107910003DDE067C9DC5D84DEEA797F9F3103702E2 +:107920008E027AB2A119E55085FC85F2E71E03EDBF +:10793000B3D1CDCF3B626FC98CEC0DE200D135DC09 +:10794000A6501C10728C90931FE572A01D48043F36 +:10795000F454BB99CA1FB683FEE63376B03D9DEA68 +:10796000CFB43BA8EC6F2FA4F667DB5D543FDC3E41 +:1079700093EA3F6AF752FD487B25953F6EF7513BEE +:10798000D3E2561E57AD11BE08FD117CA9BA9BCBA0 +:10799000C9B1D1E4DB0B47A89259A5E409F3FB8CEC +:1079A00087CBF5313C67291F877E468CAB30381377 +:1079B000CE59C3E3845F190B77FD6F9D7784BFC6F3 +:1079C000B09E5B22F45B9C1BFAC7B013BD3DD14F48 +:1079D00099C6BF5C3E2FDE13965B84FD907D8DD8EB +:1079E0000F0BD5A0FD08FE06F2E44AE4D7BD36CE63 +:1079F00067C187539ABDDCA1E933C45DAB1BE4A525 +:107A00006A5B5718BEA847FD69B2298E1818A26A8A +:107A100071F75AAFEFA17BA17D65AF89F5417B3D41 +:107A20006CDB96C4CB2D405FBD5F1F3F21AE136E54 +:107A30005ECD7C094109E3B2EB1E17D0D1D0AD1F5A +:107A4000D7C4F83AABAD0B28DE3645C5DBD518A751 +:107A5000E3B13486E78D12877FEAD670F40C368363 +:107A6000F0539B99EE356BCCE25C7AFC341C989415 +:107A700080F10BE4437605653026291C9F1DBB6110 +:107A800091E230DF809FB1851837BB8CAE7CC7D5C3 +:107A9000FA35C24FC6EF57AD66A6E136E76F916F74 +:107AA0001FC27D22067DEC3233D987AAF57FE8FF1D +:107AB000E41CF51FB6B8B0FE91FBF474BC57A8B82F +:107AC0003FDE9354FD7AC35BCCCC8EF67DD8166036 +:107AD00030EE7DA9EF4002C8FD7DF950EACC9C3024 +:107AE0003D6A88CF1FCB1E6C85EA0537F80FD5C4D9 +:107AF0005297C17A9D070DAE0E587F9BF568AAD7A5 +:107B00008AF73DEFBB6EBA97E9EF75551017517FB5 +:107B1000C53A65D3B83F8C3ED7885F9A2305508F0E +:107B200086FD068ABFC39512D10D7ECD8BFCFE0368 +:107B300083D581FE6A06A86D12B75316C3ED144BA8 +:107B4000B4533699DB29D6D14EB1443BC5F61BAFB1 +:107B5000B8494EDFBA329BCEAB765F43F5826CBF3D +:107B60001C8BFEF966C9B51F8AA5FBD8D658981A92 +:107B7000EA585A8AF7B3180FA7BB408B2F57C9533F +:107B8000F32BBD1EEE7FC4795A3B24F2B3AD128FA6 +:107B900097ADF74BE46745FD931EAD5EC1EBDFDEAD +:107BA000CAEB2193B55B4AE0E7CBCBE7E7C312CF43 +:107BB00087F7733C1FD6F17C58E2F9B01DFD10D653 +:107BC000D10F611DFD10D6D10F61897E08DB5732C0 +:107BD0005F961B58FCF521C0BE11F675DD15332BE1 +:107BE0008FB093B92C51579F6FCED08DAFB0E7E8CF +:107BF000FABF913E45D77FBDC3ADABDF50788D6EE8 +:107C0000FC42D75C5D9DCDBC3E5CCF45F3A8D6D58C +:107C10006F04DC5E1E61D737F9EA75EB2F5DB6564F +:107C2000BF9EBA5137FF66D6A69B3FA9A543377EB4 +:107C3000459BC41A23EBE08E51CF1A768F233DE982 +:107C4000CBF3957B40BE6FC6FDF57613DEF30C03D8 +:107C50006B514F5BD7C7BAB89C7B2AB9DC65C6E5C8 +:107C60003C544372DEA2F07A852BCD3E8AFE0C8016 +:107C70009CCB412E3F033963190439637914E48C9A +:107C8000E571907339C8EF259033962741CED8FE21 +:107C90002B903396A740CE58FE06E48CE5699033CE +:107CA0009667DA9751F9FB7695E6FD5BFB1A2A5F3A +:107CB0006B6FA1F6D7DBDBA87CA3DD4FED834047DC +:107CC000A3294C17E2DC3CDDFD0FF45077FFB3EB4A +:107CD000EA886323C7238E8DEC471C1BD98F383667 +:107CE000B28EF835723CE2D6C8FA76B783EC10F162 +:107CF0006AE43CC4A791F5A21EFF09CC612D7CF477 +:107D0000E3E3581624D43F2B816BD8FAECB5354603 +:107D1000C04F0571F59E4417C441A9BCA61CEAEAF0 +:107D20009562F207D3D910E14A152F79203735C86B +:107D3000F17FD1E719D4FFC054BBE6B719F927F793 +:107D40006146F8F281A90E8EF7B4F92E66376029E4 +:107D5000C687EBA38F8BDE5F8C23FF184107DC48BF +:107D6000DCE8CFDD5BAC9EEDA04F076469850FF4C6 +:107D7000E900E0A3C5E06FA71DF4CA16E85F76D856 +:107D8000EE3638707C8B07EF2B3F46FF94121E5F58 +:107D90006064274D9EF0399EFC5ACE5E5CAF4FF377 +:107DA00073E173868CE8CFC14F7803306FCED0E992 +:107DB000F909305EF5CF2DC5F5AB148E17609F59CC +:107DC00078DF9BE697BC7B23F4FB5FB5F554FFA1FE +:107DD000A3E85F9F7C62119F17CBE73DF9443CED20 +:107DE000BFA84BDA6B80FDE71C64DE3E987F58F33A +:107DF000A7D30E060DB85F7D17DF4FAC5BFF68960B +:107E0000E2C0FB246BB933BD04792431F4DB70AEDE +:107E1000E3782EC13F31BE004CC694A4E50B4194DB +:107E2000DD857E1FF2B958E6E314B397F0D38623BD +:107E3000D50CFDFDD74B122B9271DD01E64298BAAD +:107E4000B0E477BA7313DBCA685D8A5F93FD523082 +:107E50000E8EB2C8DF713786B785FE8D275270FC53 +:107E60003EE6CA7150E861D77AC2F44DF51E922100 +:107E7000FC31273B2D5B24943B3B362E428FC003C5 +:107E80007C0BE5EE769918CAA5DA6837A1DF888EF3 +:107E9000EF022F7C827881A8D2FAB53C50EB5D5777 +:107EA000CEDD8BFEE8798E1704CEA9B7F333A8BBDD +:107EB00025F26B9F74C17503F9FC7C4C80215E0335 +:107EC0003CE1007DFC483E95BA14E6AD9F14C89293 +:107ED000815FEBC6F74D4F32101E78C70307FDC018 +:107EE0007F6CD13258E75CD773A9C8B74FBA9E5799 +:107EF000F07E047458DDB04FA3C69FC62D6BAAF068 +:107F000090F5451CDFBD057EC63B19E99F9310C265 +:107F100073F5709C27F232F5AF8C4B45BC158DFF85 +:107F20006ED5F0DDDA2E53BD0278716D14FEBB758F +:107F30004BE5BBB8CFAD7F07FFFDC5A3E5615CCCCA +:107F400045F8EFEFE46105CE039C632C1E05E73096 +:107F5000ED1EF36D0B3F6FFD2BC76E22FCD2922FEF +:107F6000237E11B8A7B683E31A768805F225ACCF35 +:107F7000277BAD7DDEEB9260DE6F353CB3F84A26A1 +:107F8000C9E5550DBFDC74651AF987AA9085DA97A3 +:107F90005CC9A072E99529D4BED8CAFD44E845164B +:107FA000B81BEF75FE188EA70618E1A7687D75331C +:107FB0007B05EAFF54AF740C61E342C443B0DE3288 +:107FC000C447E350FFEBB7A6A0FE0718E1D768FD52 +:107FD0005F5A9B5381E798522931B45BA1FFAAFFF6 +:107FE00017A4B78B406FB17DA1BFC3948AF30E3243 +:107FF0003A9FAADD53859E47DB455D9C767FB7F2AD +:10800000FCD1C8BD1E899C85C4EFAB41BC598739E2 +:10801000C0F15CE119C8D9E6E4FDDF2CDE57D39549 +:1080200047F7217F82277CDFC2BA25E27E85755B18 +:1080300044BE01A1C69C88FB2EE27C0B9FC7523D2B +:10804000E1FB19A6C8AF44DC8F7335FAC53D0ED7E6 +:1080500037F279C1544F386F20F214982F40FF5BEC +:108060006178A3228DF060A287DB2DD79FB734BB48 +:10807000FDB464DEC21298D7BA2D3F8DFD0DBD6CE4 +:1080800000B9A19DD625846E97209EAD2E66DE7226 +:1080900080BE354CF08B0519E8FD72ADBEF3B9E337 +:1080A0007FECB6129FA9DEF0DC33357EE05DF79CF5 +:1080B000BB7D485FD81FFABC6816714E2F539D5781 +:1080C0009F43E4297616F3F1D1F98A06278F1778B2 +:1080D0005D457D786BDB0BCF44E661441E0FE219F2 +:1080E000DD671E5A9CEEDEAEF955CAC3AD9B4071EA +:1080F000B5AB588B5B60178EC91C07638938D811E4 +:10810000C37130D6110763893818DB1107631D71FD +:1081100030D61107631D7130968883B1FD915CDF05 +:108120003F1793BFED31E33D98150E3DB21FF6AFFB +:108130006B5718D223EECB4FAC8BF5E2399EB85378 +:1081400021FF28EECDB5CAE913E69C301FCEB67DDF +:10815000D7C4FD5F30DF01EB2C6FB1B8D07F7F5A01 +:10816000E2BB0FFD469CD3A5A09F519D01C9017C98 +:108170001D6FD7F2369386DCB75BD1CEF83A55B98E +:108180003C3E661BD871067AF55F69DEEFE2FC4F74 +:108190004BD45D58AE1C70BF94E9C07895A8A07C04 +:1081A000EAD278FE15F849DFD7049F9F2AE6F7CC7C +:1081B000A57846987749CB13829CBA7381BE9A649E +:1081C0003BF11DF4B60BEF574F15F3B82BF26FE1EF +:1081D000FC8491F2444A9B42F963CC2B289E707E2A +:1081E00042F049E419C2FCB1BF847C1BB2290EC421 +:1081F0002FF5D68205A8F7F53D5212FA830A43D52A +:108200004B849F77E6E4227E7E5DA357DC0F9BB410 +:1082100038D7BA6B929281E3B6018A837A559283FA +:10822000D619BA5FB2EF75A05DC1B8887C50E3EE95 +:108230006BC82E1A0350168F6D3F37EF3C36F14551 +:10824000D4BBA057417A1BEDE01E22F21F0D3D1258 +:10825000E97174FD57C53CAF560BB01DF974CBA640 +:108260001C6525E6030166B43AF11C0E1DFEA8C587 +:10827000BCB987E4CAF9B113E8CEE1FB7922D65F35 +:1082800089EB47EC2FF4E0F7C536925FBDDDA164C2 +:10829000E46069273AAFE283C6FF8660C0E4427AB1 +:1082A0008CB02FD497DB0326DC6765979BF2F0EA4E +:1082B0000EBE8FDA9DA814218E32DA958950AF8DCB +:1082C000E5F607F411DE6C04BE2461BE2D09F0A5AD +:1082D000F56AFED46BF436F6242A4DBAF69D26D400 +:1082E000EF1ACDDFAFEC9AABC838DFC8CF2B976859 +:1082F000B850E3E7858D96ED98EFAFE97D395F42A1 +:10830000BD6CC9704B70CE3F69FA28A35DA484F997 +:108310005163EFA1F38CF073179C1F966CB2FB684E +:108320007DD0073FDA4D632F5FBFB1B75E7142B9B1 +:10833000CAA82A13687FCECF917D77FF42DBD7E2B0 +:10834000C27D995DA5EF0DEFEC5A9A45E7E87DD81F +:10835000847CB3B91C0B106F821E905E0A7DA82B23 +:10836000E6F627CE9F5C6224BA934BF4F624E291A2 +:10837000B0ABC61DF5CC0BFB36A4437C1CC5AEA22E +:10838000F376355ADEEE71C5174C97C2760FF1B011 +:10839000E5D951E2C4426DFFE59A1C802FE44F44B9 +:1083A000FFD73539D4225F23E6E37AB8EE14D13F04 +:1083B0002F98BFD1191E2FF6AD4DE2F3502EA81FF6 +:1083C000534AE491F1AD345ED6E57B1A4670EBC1B9 +:1083D000ADA918FF0E49945F6BBDFFD8C43BD0BE5A +:1083E0009F8E73A177FAA079FF860C0CAEC600C9E8 +:1083F00041D0D504F804ED7A9516F71A83A3DBF77C +:1084000093D3D4592511F6D7F8BDA70BD04FC2F995 +:1084100083E827DE78FA277F98E508C72B719E95B9 +:10842000DD7DE4176FD991E83170BFD88D7E716121 +:1084300009F74B0D5D5C5E0CE485F84DC8B5BE4B8D +:10844000A2F8D0D0561640DC338207347946CB519F +:10845000C857C851F01FE210E573056E16F42FD10E +:10846000F6AFD1E2C3724DEF96AF994B7E7165774F +:108470003D7A2456A3B5D734EADB47F83FF27DD8DE +:10848000790FEAF1703FE7FFF00E13CFB71DE479E3 +:10849000C20F5A5FF8CD1218F7FE437D5991DF578E +:1084A0009AB4FCD92A0D2FAE06FE8F963704FEAF84 +:1084B0008BE4FFEA2734FEE7F67FFC63FAAE16E3AF +:1084C000DA0BFB36C0EF4CE0CF0707BF67CA84F674 +:1084D0009B9BA444A47773490E3F677F9F2917EFA6 +:1084E000012D6E3BE67B376B7E205A9FA1F4B208CC +:1084F000FE623C9092C278458C477F7408E8D8B4FD +:10850000D1128FF9E68696C4243BDC17FA343D1568 +:10851000FE45D07D7E63FD03789F386FE1FADD0C68 +:10852000F3F13BCFF9B9AEAC566718CFB1E4FE43D7 +:10853000F43DEC3627DDCB61FF93F8DD61B7662FA4 +:10854000797921FA0E2B70A502FE09BFFBEC95F993 +:10855000F9730DBCFC7E6CFF9496BF81F7F29A43D1 +:1085600097911E8167058EFD99A61702AF0AFC3907 +:1085700096DF51D8BEEE5CFC8E90CC5C9D8EB09E9A +:108580008A75A2FD8F3867665CFF0F504F326F9B74 +:10859000EA411CA0C4B26E3CC7614D3FA3CF793EF7 +:1085A00087F3732CBA05BD237C00659C9914A65FE4 +:1085B000D00318D62B232EFB4E11E1C2F31DAE2C97 +:1085C000E4D358E73B9FA3929D0E653017C6D9B1FF +:1085D000FC6A4DA3E4C7754D6D36CA3F083B691C64 +:1085E000F90EE04C0801FDC33D3CFF7F5E82B8827E +:1085F000E7DA6891492FB4F3FDA379E8D74B9244A9 +:108600007EC58678AD3656B3FF208FBF836D93E865 +:108610009CA25DC4DF417BC89614E177DF6ED1E296 +:1086200017AC83F6C3DA2631FC4E3FD873DE2693AF +:108630009E72FAC4BC4D26BE3EB32981FD12E2965D +:108640006AA51EDA6F697BD524417941D3D7EC49FD +:10865000FDDEB464C26D842B3A6DAE74DCAF33D1F1 +:10866000951E19FFE3AC4B280F733E27988779A915 +:1086700021B785F83D685DB200FDCFE0EE447C1186 +:10868000C03649AEC136BC4F6E8DA1FC7A95CCBACE +:1086900025D28FA09289F1BB43227F20DA3D4EF58F +:1086A0004FE83FB20D87FEFC3AAEBB35CE8574B0C5 +:1086B0002F605FF08FF83C0CEDFA765C13F918959B +:1086C0001789CE83642B0ECA930CFDD2C0F672FFBD +:1086D000F7EF586FFAA549F79D457CFF69EABB9112 +:1086E000F20F8DDA779D26CC8714D3777CC6C0E550 +:1086F000DDD33B3F15F5A27167C543FE22CC0B309D +:108700001FFA97B78DA16AF40317FBD2923A22EEB3 +:108710003B670331F47DED62DF0BAF94C1BE1F1FD9 +:1087200049711B38991437BA1DC924EFA452EE873A +:1087300022F252DE3447382FD5D8776F1683FD1AD0 +:10874000D777166079B1CFB20CFD7DB9BDBA3C11B7 +:10875000D65DF56822E5FDCE36F33CC3BADFE5937E +:108760005E179472FB6CFEEBB1C7F1BD6013B4D918 +:1087700061DF4FFBE3E81D5873FB912C7C327130B5 +:1087800046CD2985FD6F9507965C83FE5F0A1CC860 +:10879000A0F18E51F3D6A27C07EF67A0DFEBFFF9C3 +:1087A000355AE723F9D4A21A98DFBCFEB9785CE702 +:1087B000D65DAF96D965CA1B15E1FAF81DCA8E0CB5 +:1087C000D8DD37DD47FCF3CE281D25AF12BDCFD74E +:1087D000B4FB4189769FA94AF22DA92921B9927E3D +:1087E0008C45DF9A2392EEFBDC2D8104853929AF7D +:1087F000AAE07760D5CE08D75E34B036FA6EA5E130 +:1088000019D1FE8D526E1717137AB2D00ED61E787C +:10881000380BF5FE3D1BAFD71E58FA2BF47BEABE92 +:10882000188EAF8D4CA1EF977E8E8FD99A24DDFBE9 +:10883000C6EAD2383AC7DADDC5BAF88909176C7FBB +:10884000CFC8DF8B641B2EBB11779D35069B504F25 +:10885000CE023EF5933CB97E9CED312CA0773D9B3A +:10886000248678E46CCF73B63C6B18BFD94AFA8380 +:10887000E8DFD61F4EF4F067623CCFB0C12EFC9B00 +:108880007501FA0DC06176B483D6174F2C60BC8E8B +:108890002F2CC7E4E73A0D7F8DD40F1F52102737D6 +:1088A0001FE4F8A3B9FFD04BE393516F35FCA1E16E +:1088B0009AF51AAED97098F365FDE1734A43E4BDA9 +:1088C000A130E99E4C40809B4A5FA9D905E3EA515B +:1088D0006EB3C0EE8A5F5CDE61C4D2CEF1A4718853 +:1088E00070E1F6C23374FF5DDFA5AD5778E69E5C9C +:1088F0003A6FF5B848FC747BA989E689F9C00F9AEC +:1089000027DE518DF97ECAA276A15E5EFD7E8ABF0A +:108910008FFA0AEF92B695829C06B4F8165C1FDBBC +:108920008DB8C3BBC16AC4B273BD95708877E319B3 +:108930000BE60D063E8E95A5785495A163720EBD8B +:10894000CBFA1ECE4F637E7AA795C98212E2FF4B07 +:108950003F7DB718E9C7F759CC8EDF317EBDBC1C0F +:10896000FCD2F74BB5BCBD33548C76947294C78956 +:10897000C74CACDB42EF4C7C0CDFB704B5EF8FFE8D +:10898000CF657A8F322005FF05D7F7C558BBF11D9B +:10899000CC194DDFB7E5F9F6E2FEA7930CF91EDC22 +:1089A00057FB2E3951BB5F29E3D3ADC827F12E4FBA +:1089B000F27A591BEC234B271A508FEE1B3233BC33 +:1089C000D74F1C5F49F1B253E3ABE448C618C68EDB +:1089D0003A657F0CD0711F33D3775245B678719CBE +:1089E00034F0F2E7F8FE28D370F95802F467DE217C +:1089F000B93A81E4BAE177E8FDCDE0E7072DF4DE8E +:108A0000215D3D82F2196F08153D28619CFA91594C +:108A100082F1C9D365BB41CB7B9A41DFE7F13FD9F6 +:108A2000C0E6CFE39360FEBCA1D873C8E74B43EF29 +:108A30003CFD42099666CA4FCE1B300463F08D9D03 +:108A4000B9C21BF96E183DB5B92CBC0EEB7998A1D3 +:108A50001DDDA6C51BB1DE58F32FA53BE83D25EC77 +:108A600043EFE72E59E500DEF7E60D1C7B0DCF390D +:108A70000FDF2BC7E33CD38723796BDCF7F4C444C7 +:108A8000CC53A30D7D092026B593CBF3DA04FD7DED +:108A9000F34229BFE75DD0FCFCC83B49879745C638 +:108AA00045C17FE10704FDC35685E78BD7F0FCFF86 +:108AB000F000E09D51FCAF285F45BC0338E6ED7C3B +:108AC000EF85D294B05E44EB41B4BC855CD99DA7E0 +:108AD0004F24E4903C8B1E64780F0A3DF65B89E4DA +:108AE0007919F56DCF95BD6E9473A76D418EEAFC33 +:108AF000FF2747E177D458FE3E7F2CFFA3C6F277CD +:108B0000FBA3F89FD8C939E49FD2CA52C85F9C40E2 +:108B10007F21FCC457F04B13CA4A23DE49DA64FEB6 +:108B20007D11F134ECD3D9363180F798D9D98E0E36 +:108B300023F6DFC528BE8AF79522AFDBD9368D8FA5 +:108B400013EF25371BE83DE57B26FE9ED2DF3199EA +:108B50007026FDE0BB117F26BD1714EF123B8DBCC4 +:108B6000DDDFCC685C27BE9F4C08BF4B449BA773DE +:108B7000B730F25323FB6EE2EF34853DA809FC3D8C +:108B8000A37A89FBCFF965895A9C089522BEBEEF6E +:108B90006E1B43FD14F21FAFC521217F8326FFF119 +:108BA0004E2EFFF1563988EFA1D99A726FA41CEFAF +:108BB00082B9685F3F817B8019E9AAE6EFF97AAB59 +:108BC000BD19F87DB3B73A55463CF5A3BF7EFBCD42 +:108BD000BB901FAF9808D7F6BAF9397B7F3A89F076 +:108BE000D6A01C786415CE5F62A577B582AF86F4F7 +:108BF0001B1F6984F22149FD01EA59AF4DA6F3F626 +:108C0000AE8D25BBECCDE1E7EFCDCFA575407E0560 +:108C1000BB719F6A33C7C71A7F2EAD99A0C98FEF6A +:108C20003B74BF4DBC73D5FA73C53B57E25FF87D0B +:108C3000EB507CE477974B1A0EB9A4C965A49DF15B +:108C4000F7AE1087E323F3CD63B5CF4C539B514F61 +:108C5000457F6FA23703715534FF7775B8BB0B5052 +:108C60001F6CB21DEF0963C92D6EA9F2F8FE0879D9 +:108C7000A1DAE339E33A67D3B985FC1E12710EF429 +:108C800092F4274A9E6C02D70F9137C8F69F7B84D7 +:108C90003EEAB0D0148C9F60778578CF1C44FF36B5 +:108CA00023ACB79297BF4313762CF455F8B9B1ECC7 +:108CB000596A03FF37EA7BEC7EB2DB09B071DC2432 +:108CC000B2EBEFA27D1A64577A0CD9F3E90CA4E752 +:108CD0002BD8F5C3382F59F32BBF4C57BF8F7C4F80 +:108CE000D6FCC87843600A7FF7CDD668DF2DE9FF50 +:108CF000D1BCA9F17505F8AF7130EEF9321E4FD82D +:108D000096283FA6C9A14E1BFFE647606F33C2728B +:108D10005CA1DDB7EAB6C49C437F58B7C5C4EDA8D3 +:108D2000ADC21BB50EF973B10E735C4EC173897978 +:108D30002BD6FE670AE2EB31E7872624E2FB3DF201 +:108D4000A770EE9715DF0B78CE41769EDE879DFAF1 +:108D50008B81BE739C03F93812B0CC0A38609D60D9 +:108D600019C7352566F5E765E41FE6E9EE89A7DC56 +:108D7000EFE6E33D8B7D716C02D2B33ACD7714F907 +:108D8000B92D6F98BEDB0C660CD1FFCB1AAC797F86 +:108D900022D2B7A2ED65F2FB2B84DFFF3BFC8AE613 +:108DA00093E05FF8DCC32988A3FFAFF8F6DFB0A239 +:108DB000FC89E03600000000000000000000000018 +:108DC0000000004000000000000000000000004023 +:108DD000000000000000000000000028000000006B +:108DE0000000000000000010000000000000000073 +:108DF0000000004000000000000000000000001023 +:108E0000000000000000000000000008000000005A +:108E10000000000000000000000000000000000052 +:108E20000000000000000000000000000000000042 +:108E30000000000000000000000000000000000032 +:108E40000000000000000000000000000000000022 +:108E50000000000000000000000000000000000012 +:108E60000000000000000000000000000000000002 +:108E700000000000000000000000000000000000F2 +:108E800000000000000000000000000000000000E2 +:108E900000000000000000000000000000000000D2 +:108EA00000000000000000000000000000000000C2 +:108EB00000000000000000000000000000000000B2 +:108EC00000000000000000000000000000000000A2 +:108ED0000000000000000000000000000000000092 +:108EE0000000000000000000000000000000000082 +:108EF0000000000000000000000000000000000072 +:108F00000000000000000000000000000000000061 +:108F10000000000000000000000000000000000051 +:108F200000000000000000000000900000100000A1 +:108F3000000000080000900800100000000000027F +:108F400000009000001000000000001080000000F1 +:108F50000000000000000000800000000000000091 +:108F60000000000080000000000000000000000081 +:108F7000800000000000000000000000000093B826 +:108F80000001000400000001000093C00000000088 +:108F900000000002000093C800000000000000086C +:108FA000000093CC0000000000000002000093D0FD +:108FB00000000000000000080000972000400000B2 +:108FC00000000040000093E0008000000000004826 +:108FD000000094E00040000000000008000094F051 +:108FE00000400000000000180000A0000028000061 +:108FF000000000280000C0C00008000000000001C0 +:109000000000C0C100080000000000010000C0C254 +:10901000000800000000000100002008001000000F +:109020000000001000002000000000000000000808 +:1090300080000000000000000000000000000000B0 +:109040000000000000000000000000000000000020 +:109050000000000000000000000000000000000010 +:109060000000000000000000000000000000000000 +:1090700000000000000000000000000000000000F0 +:1090800000000000000000000000000000000000E0 +:1090900000000000000000000000000000000000D0 +:1090A00000000000000000000000000000000000C0 +:1090B00000000000000000000000000000000000B0 +:1090C00000000000000000000000000000000000A0 +:1090D0000000000000000000000000000000000090 +:1090E0000000000000000000000000000000000080 +:1090F0008000000000000000000000008000000070 +:1091000000000000000000008000000000000000DF +:1091100000000000800000000000000000000000CF +:10912000800000000000000000000000800000003F +:1091300000000000000000008000000000000000AF +:10914000000000008000000000000000000000009F +:10915000800000000000000000000000800000000F +:10916000000000000000000080000000000000007F +:10917000000000008000000000000000000000006F +:1091800000000000000000000000000000000000DF +:1091900000000000000000000000000000000000CF +:1091A00000000000000000000000000000000000BF +:1091B000000000000000000000000000800000002F +:1091C000000000000000000080000000000000001F +:1091D000000000008000000000000000000000000F +:1091E00000000000000000000000000080000000FF +:1091F00000000000000000008000000000000000EF +:1092000000000000800000000000000000000000DE +:10921000000000000000000000000000000000004E +:10922000000000000000000000000000000000003E +:10923000000000000000000000000000000000002E +:10924000000000000000000000000000000000001E +:10925000000000000000000080000000000000008E +:1092600000000000000000000000000000000000FE +:1092700000001EC8000000000000000800002008D8 +:10928000001000000000001000002000000000009E +:10929000000000080000A08000080000000000019D +:1092A0000000A08100080000000000010000A08272 +:1092B000000800000000000100009070003800006D +:1092C0000000003800001ED800000000000000026E +:1092D00000001EDA00000000000000028000000014 +:1092E00000000000000000008000000000000000FE +:1092F00000000000800000000000000000000000EE +:10930000800000000000000000000000800000005D +:1093100000000000000000008000000000000000CD +:1093200000000000800000000000000000000000BD +:10933000800000000000000000000000800000002D +:10934000000000000000000000000000000000001D +:10935000000000000000000000000000000000000D +:1093600000000000000000000000000000000000FD +:1093700000000000000000000000000000000000ED +:10938000000000008000000000000000000000005D +:10939000800000000000000000000000000000004D +:1093A000000000000000000080000000000000003D +:1093B000000000008000000000000000000000002D +:1093C000800000000000000000000000800000009D +:1093D000000000000000000080000000000000000D +:1093E00000000000800000000000000000000000FD +:1093F0000000C00000400000000000400000C80065 +:1094000000400000000000400000C82E00400000A6 +:10941000000000010000C800004000020000000140 +:109420000000C801004000020000000000008000B1 +:10943000004000000000004080000000000000002C +:109440000000000000008000000800400000000450 +:109450000000800400080040000000040000B0008C +:1094600000280000000000280000B14000100000AB +:10947000000000100000B14A0010000000000001D0 +:1094800000008800008000000000008000008800CC +:10949000000800800000000200008C000040000076 +:1094A0000000004000002008001000000000001034 +:1094B0000000200000000000000000080000125022 +:1094C0000008000000000001000012510008000028 +:1094D000000000010000125200080000000000011E +:1094E00000008E0000100004000000040000129034 +:1094F0000030001800000010000012980030001822 +:1095000000000002800000000000000000000000D9 +:10951000800000000000000000000000800000004B +:1095200000000000000000008000000000000000BB +:1095300000000000800000000000000000000000AB +:10954000800000000000000000000000800000001B +:10955000000000000000000000000000000000000B +:1095600000000000000000000000000000000000FB +:1095700000000000000000000000000000000000EB +:10958000000000000000000080000000000000005B +:10959000000000008000000000000000000000004B +:1095A000000000000000000000000000800000003B +:1095B000000000000000000080000000000000002B +:1095C000000000008000000000000000000000001B +:1095D000800000000000000000000000800000008B +:1095E0000000000000000000000083080080000070 +:1095F00000000080000000010000000000000000EA +:1096000000002008001000000000001000002000F2 +:1096100000000000000000080000850000080000B5 +:1096200000000001000085010008000000000001AA +:10963000000085020008000000000001000060003A +:10964000003800000000003880000000000000002A +:109650000000000000008454000800000000000228 +:10966000000084560008000000000002000084642E +:109670000010000000000004800000000000000056 +:10968000000000008000000000000000000000005A +:10969000800000000000000000000000000000004A +:1096A00000000000000000000000000000000000BA +:1096B00000000000000000000000000000000000AA +:1096C000000000000000000000000000800000001A +:1096D000000000000000000080000000000000000A +:1096E000000000000000000000000000000000007A +:1096F000800000000000000000000000800000006A +:1097000000000000000000008000000000000000D9 +:1097100000000000800000000000000000000000C9 +:109720008000000000000000000000000000300089 +:109730000040000000000008000030080040000069 +:109740000000002000003200002000000000002087 +:10975000000037A8000000000000000880000000A2 +:1097600000000000000000000000A0000000000059 +:109770000000200000003EC10000000000000001C9 +:1097800000003EE0000000000000000200001E009B +:1097900000E0000800000008800000000000000059 +:1097A0000000000000004000000800000000000170 +:1097B00000004001000800000000000100004040DF +:1097C00000080004000000020000406000080004DF +:1097D0000000000480000000000000000000000005 +:1097E00000004000000800000000000400004004E9 +:1097F00000080000000000040000404000000000DD +:1098000000000008000040480000000000000008C0 +:109810000000800000000000000000100000504028 +:1098200000010004000000010000500000000000E2 +:10983000000000200000500800100000000000049C +:109840000000500C0010000000000001000052C792 +:109850000000000000000001000052C600000000EF +:109860000000000100003000004000200000000463 +:109870000000300400400020000000040000300818 +:1098800000400020000000020000300A00400020DC +:10989000000000020000300C004000200000000129 +:1098A0000000300D00400020000000010000300EDC +:1098B00000400020000000010000301000400020A7 +:1098C00000000004000030140040002000000004EC +:1098D0000000301800400020000000040000301C90 +:1098E0000040002000000004000050000100008043 +:1098F000000800040000500401000080000800047B +:109900000000000A00000000000000000000506895 +:10991000010000800000000100005069010000808B +:10992000000000010000506C0100008000000002F7 +:109930000000506E01000080000000020000507026 +:10994000010000800000000400005074010000804D +:1099500000000004000050660100008000000002CA +:109960000000506401000080000000010000506011 +:109970000100008000000002000050620100008031 +:1099800000000002000050500100008000000004B0 +:1099900000005054010000800000000400005058F6 +:1099A00001000080000000040000505C0100008005 +:1099B000000000040000507C010000800000000155 +:1099C0000000507D010000800000000100004018F0 +:1099D0000010000000000004000040900010000093 +:1099E0000000000400004098001000000000000487 +:1099F00000004110000000000000000200004112C1 +:109A000000000000000000020000411400000000FF +:109A100000000002000041160000000000000002EB +:109A200000006040000800000000000200006042EA +:109A30000008000000000002000060440008000070 +:109A40000000000200006046000800000000000264 +:109A500000006080000800000000000800006000B6 +:109A60000008000000000002000060020008000082 +:109A70000000000100006004000800000000000277 +:109A8000000060C000080000000000080000610045 +:109A9000000800000000000400006104000800004D +:109AA000000000010000614000080000000000020A +:109AB0000000614400080000000000020000614254 +:109AC00000080000000000020000618000080000A3 +:109AD0000000000400007000000800000000000208 +:109AE0000000700200080000000000010000700487 +:109AF00000080000000000020000704000080000A4 +:109B00000000000200007044000800000000000295 +:109B100000007046000800000000000200007660AF +:109B2000000800000000000800007080000800002D +:109B30000000000200007084000800000000000225 +:109B4000000076A00008000000000008000080402F +:109B50000008000000000001000080410008000033 +:109B60000000000100008042000800000000000129 +:109B70000000804300080000000000010000800099 +:109B80000008000000000002000080020008000041 +:109B90000000000100008004000800000000000236 +:109BA000000080C00008000000000002000080C229 +:109BB0000008000000000002000080C4000800004F +:109BC000000000020000808000080000000000018A +:109BD0000000808100080000000000010000808279 +:109BE0000008000000000001000080830008000061 +:109BF0000000000100008084000800000000000157 +:109C00000000808500080000000000010000808640 +:109C100000080000000000010000600000080000D3 +:109C200000000002000060020008000000000001C7 +:109C30000000600400080000000000020000604214 +:109C400000C00018000000020000604000C00018C2 +:109C5000000000020000604C00C000180000000876 +:109C60000000604400C000180000000800006057B9 +:109C700000C00018000000010000605400C000187F +:109C8000000000020000605600C000180000000143 +:109C90000000664000080000000000080000668028 +:109CA0000008000000000008000066C00008000076 +:109CB000000000088000000000000000000000001C +:109CC0008000000000000000000000008000000094 +:109CD0000000000000000000800000000000000004 +:109CE00000000000800000000000000000000000F4 +:109CF0008000000000000000000000008000000064 +:109D000000000000000000008000000000000000D3 +:109D100000000000800000000000000000000000C3 +:109D20008000000000000000000000008000000033 +:109D300000000000000000008000000000000000A3 +:109D40000000000080000000000000000000000093 +:109D50008000000000000000000000008000000003 +:109D60000000000000000000800000000000000073 +:109D70000000000080000000000000000000000063 +:109D800080000000000000000000000080000000D3 +:109D90000000000000000000800000000000000043 +:109DA0000000000080000000000000000000000033 +:109DB00080000000000000000000000080000000A3 +:109DC0000000000000000000800000000000000013 +:109DD0000000000080000000000000000000000003 +:109DE0008000000000000000000000008000000073 +:109DF00000000000000000008000000000000000E3 +:109E000000000000800000000000000000000000D2 +:109E10008000000000000000000000008000000042 +:109E200000000000000000008000000000000000B2 +:109E300000000000800000000000000000000000A2 +:109E40008000000000000000000000008000000012 +:109E50000000000000000000800000000000000082 +:109E60000000000080000000000000000000000072 +:109E700080000000000000000000000080000000E2 +:109E80000000000000000000800000000000000052 +:109E90000000000080000000000000000000000042 +:109EA00080000000000000000000000080000000B2 +:109EB0000000000000000000800000000000000022 +:109EC0000000000080000000000000000000000012 +:109ED0008000000000000000000000008000000082 +:109EE00000000000000000008000000000000000F2 +:109EF00000000000800000000000000000000000E2 +:109F00008000000000000000000000008000000051 +:109F100000000000000000008000000000000000C1 +:109F200000000000800000000000000000000000B1 +:109F30008000000000000000000000008000000021 +:109F40000000000000000000800000000000000091 +:109F50000000000080000000000000000000000081 +:109F60008000000000000000000000000000000071 +:109F70000000000000000000800000000000000061 +:109F800000000000000000000708110000000000B1 +:00000001FF --- linux-3.13.0.orig/scripts/package/builddeb +++ linux-3.13.0/scripts/package/builddeb @@ -41,9 +41,9 @@ parisc*) debarch=hppa ;; mips*) - debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el) ;; + debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;; arm*) - debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el) ;; + debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;; *) echo "" >&2 echo "** ** ** WARNING ** ** **" >&2 @@ -62,7 +62,7 @@ fi # Create the package - dpkg-gencontrol -isp $forcearch -p$pname -P"$pdir" + dpkg-gencontrol -isp $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir" dpkg --build "$pdir" .. } @@ -288,15 +288,14 @@ (cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build" rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles" -arch=$(dpkg --print-architecture) cat <> debian/control Package: $kernel_headers_packagename Provides: linux-headers, linux-headers-2.6 -Architecture: $arch -Description: Linux kernel headers for $KERNELRELEASE on $arch - This package provides kernel header files for $KERNELRELEASE on $arch +Architecture: any +Description: Linux kernel headers for $KERNELRELEASE on \${kernel:debarch} + This package provides kernel header files for $KERNELRELEASE on \${kernel:debarch} . This is useful for people who need to build external modules EOF --- linux-3.13.0.orig/scripts/kconfig/lkc.h +++ linux-3.13.0/scripts/kconfig/lkc.h @@ -97,7 +97,9 @@ /* confdata.c and expr.c */ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) { - assert(len != 0); + //assert(len != 0); + if (len == 0) + return; if (fwrite(str, len, count, out) != count) fprintf(stderr, "Error in writing or end of file.\n"); --- linux-3.13.0.orig/scripts/mod/file2alias.c +++ linux-3.13.0/scripts/mod/file2alias.c @@ -210,8 +210,8 @@ range_lo < 0x9 ? "[%X-9" : "[%X", range_lo); sprintf(alias + strlen(alias), - range_hi > 0xA ? "a-%X]" : "%X]", - range_lo); + range_hi > 0xA ? "A-%X]" : "%X]", + range_hi); } } if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1)) --- linux-3.13.0.orig/mm/nommu.c +++ linux-3.13.0/mm/nommu.c @@ -652,7 +652,7 @@ up_write(&nommu_region_sem); if (region->vm_file) - fput(region->vm_file); + vmr_fput(region); /* IO memory and memory shared directly out of the pagecache * from ramfs/tmpfs mustn't be released here */ @@ -810,7 +810,7 @@ if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) - fput(vma->vm_file); + vma_fput(vma); put_nommu_region(vma->vm_region); kmem_cache_free(vm_area_cachep, vma); } @@ -1376,7 +1376,7 @@ goto error_just_free; } } - fput(region->vm_file); + vmr_fput(region); kmem_cache_free(vm_region_jar, region); region = pregion; result = start; @@ -1452,10 +1452,10 @@ up_write(&nommu_region_sem); error: if (region->vm_file) - fput(region->vm_file); + vmr_fput(region); kmem_cache_free(vm_region_jar, region); if (vma->vm_file) - fput(vma->vm_file); + vma_fput(vma); kmem_cache_free(vm_area_cachep, vma); kleave(" = %d", ret); return ret; --- linux-3.13.0.orig/mm/oom_kill.c +++ linux-3.13.0/mm/oom_kill.c @@ -170,7 +170,7 @@ * implementation used by LSMs. */ if (has_capability_noaudit(p, CAP_SYS_ADMIN)) - adj -= 30; + points -= (points * 3) / 100; /* Normalize to oom_score_adj units */ adj *= totalpages / 1000; --- linux-3.13.0.orig/mm/internal.h +++ linux-3.13.0/mm/internal.h @@ -85,7 +85,6 @@ */ extern int isolate_lru_page(struct page *page); extern void putback_lru_page(struct page *page); -extern unsigned long zone_reclaimable_pages(struct zone *zone); extern bool zone_reclaimable(struct zone *zone); /* --- linux-3.13.0.orig/mm/memory.c +++ linux-3.13.0/mm/memory.c @@ -2752,7 +2752,7 @@ set_page_dirty_balance(dirty_page, page_mkwrite); /* file_update_time outside page_lock */ if (vma->vm_file) - file_update_time(vma->vm_file); + vma_file_update_time(vma); } put_page(dirty_page); if (page_mkwrite) { @@ -3357,10 +3357,15 @@ else VM_BUG_ON(!PageLocked(vmf.page)); + page = vmf.page; + + /* Mark the page as used on fault. */ + if (PageReadaheadUnused(page)) + ClearPageReadaheadUnused(page); + /* * Should we do an early C-O-W break? */ - page = vmf.page; if (flags & FAULT_FLAG_WRITE) { if (!(vma->vm_flags & VM_SHARED)) { page = cow_page; @@ -3463,7 +3468,7 @@ /* file_update_time outside page_lock */ if (vma->vm_file && !page_mkwrite) - file_update_time(vma->vm_file); + vma_file_update_time(vma); } else { unlock_page(vmf.page); if (anon) @@ -3700,7 +3705,6 @@ if (unlikely(is_vm_hugetlb_page(vma))) return hugetlb_fault(mm, vma, address, flags); -retry: pgd = pgd_offset(mm, address); pud = pud_alloc(mm, pgd, address); if (!pud) @@ -3738,20 +3742,13 @@ if (dirty && !pmd_write(orig_pmd)) { ret = do_huge_pmd_wp_page(mm, vma, address, pmd, orig_pmd); - /* - * If COW results in an oom, the huge pmd will - * have been split, so retry the fault on the - * pte for a smaller charge. - */ - if (unlikely(ret & VM_FAULT_OOM)) - goto retry; - return ret; + if (!(ret & VM_FAULT_FALLBACK)) + return ret; } else { huge_pmd_set_accessed(mm, vma, address, pmd, orig_pmd, dirty); + return 0; } - - return 0; } } --- linux-3.13.0.orig/mm/madvise.c +++ linux-3.13.0/mm/madvise.c @@ -327,12 +327,12 @@ * vma's reference to the file) can go away as soon as we drop * mmap_sem. */ - get_file(f); + vma_get_file(vma); up_read(¤t->mm->mmap_sem); error = do_fallocate(f, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, end - start); - fput(f); + vma_fput(vma); down_read(¤t->mm->mmap_sem); return error; } --- linux-3.13.0.orig/mm/mmap.c +++ linux-3.13.0/mm/mmap.c @@ -248,7 +248,7 @@ if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) - fput(vma->vm_file); + vma_fput(vma); mpol_put(vma_policy(vma)); kmem_cache_free(vm_area_cachep, vma); return next; @@ -858,7 +858,7 @@ if (remove_next) { if (file) { uprobe_munmap(next, next->vm_start, next->vm_end); - fput(file); + vma_fput(vma); } if (next->anon_vma) anon_vma_merge(vma, next); @@ -893,7 +893,15 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma, struct file *file, unsigned long vm_flags) { - if (vma->vm_flags ^ vm_flags) + /* + * VM_SOFTDIRTY should not prevent from VMA merging, if we + * match the flags but dirty bit -- the caller should mark + * merged VMA as dirty. If dirty bit won't be excluded from + * comparison, we increase pressue on the memory system forcing + * the kernel to generate new VMAs when old one could be + * extended instead. + */ + if ((vma->vm_flags ^ vm_flags) & ~VM_SOFTDIRTY) return 0; if (vma->vm_file != file) return 0; @@ -1082,7 +1090,7 @@ return a->vm_end == b->vm_start && mpol_equal(vma_policy(a), vma_policy(b)) && a->vm_file == b->vm_file && - !((a->vm_flags ^ b->vm_flags) & ~(VM_READ|VM_WRITE|VM_EXEC)) && + !((a->vm_flags ^ b->vm_flags) & ~(VM_READ|VM_WRITE|VM_EXEC|VM_SOFTDIRTY)) && b->vm_pgoff == a->vm_pgoff + ((b->vm_start - a->vm_start) >> PAGE_SHIFT); } @@ -1620,8 +1628,8 @@ unmap_and_free_vma: if (vm_flags & VM_DENYWRITE) allow_write_access(file); + vma_fput(vma); vma->vm_file = NULL; - fput(file); /* Undo any partial mapping done by a device driver. */ unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); @@ -2410,7 +2418,7 @@ goto out_free_mpol; if (new->vm_file) - get_file(new->vm_file); + vma_get_file(new); if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); @@ -2429,7 +2437,7 @@ if (new->vm_ops && new->vm_ops->close) new->vm_ops->close(new); if (new->vm_file) - fput(new->vm_file); + vma_fput(new); unlink_anon_vmas(new); out_free_mpol: mpol_put(vma_policy(new)); @@ -2827,7 +2835,7 @@ if (anon_vma_clone(new_vma, vma)) goto out_free_mempol; if (new_vma->vm_file) - get_file(new_vma->vm_file); + vma_get_file(new_vma); if (new_vma->vm_ops && new_vma->vm_ops->open) new_vma->vm_ops->open(new_vma); vma_link(mm, new_vma, prev, rb_link, rb_parent); --- linux-3.13.0.orig/mm/page-writeback.c +++ linux-3.13.0/mm/page-writeback.c @@ -191,6 +191,26 @@ * global dirtyable memory first. */ +/** + * zone_dirtyable_memory - number of dirtyable pages in a zone + * @zone: the zone + * + * Returns the zone's number of pages potentially available for dirty + * page cache. This is the base value for the per-zone dirty limits. + */ +static unsigned long zone_dirtyable_memory(struct zone *zone) +{ + unsigned long nr_pages; + + nr_pages = zone_page_state(zone, NR_FREE_PAGES); + nr_pages -= min(nr_pages, zone->dirty_balance_reserve); + + nr_pages += zone_page_state(zone, NR_INACTIVE_FILE); + nr_pages += zone_page_state(zone, NR_ACTIVE_FILE); + + return nr_pages; +} + static unsigned long highmem_dirtyable_memory(unsigned long total) { #ifdef CONFIG_HIGHMEM @@ -198,11 +218,9 @@ unsigned long x = 0; for_each_node_state(node, N_HIGH_MEMORY) { - struct zone *z = - &NODE_DATA(node)->node_zones[ZONE_HIGHMEM]; + struct zone *z = &NODE_DATA(node)->node_zones[ZONE_HIGHMEM]; - x += zone_page_state(z, NR_FREE_PAGES) + - zone_reclaimable_pages(z) - z->dirty_balance_reserve; + x += zone_dirtyable_memory(z); } /* * Unreclaimable memory (kernel memory or anonymous memory @@ -238,9 +256,12 @@ { unsigned long x; - x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages(); + x = global_page_state(NR_FREE_PAGES); x -= min(x, dirty_balance_reserve); + x += global_page_state(NR_INACTIVE_FILE); + x += global_page_state(NR_ACTIVE_FILE); + if (!vm_highmem_is_dirtyable) x -= highmem_dirtyable_memory(x); @@ -289,32 +310,6 @@ } /** - * zone_dirtyable_memory - number of dirtyable pages in a zone - * @zone: the zone - * - * Returns the zone's number of pages potentially available for dirty - * page cache. This is the base value for the per-zone dirty limits. - */ -static unsigned long zone_dirtyable_memory(struct zone *zone) -{ - /* - * The effective global number of dirtyable pages may exclude - * highmem as a big-picture measure to keep the ratio between - * dirty memory and lowmem reasonable. - * - * But this function is purely about the individual zone and a - * highmem zone can hold its share of dirty pages, so we don't - * care about vm_highmem_is_dirtyable here. - */ - unsigned long nr_pages = zone_page_state(zone, NR_FREE_PAGES) + - zone_reclaimable_pages(zone); - - /* don't allow this to underflow */ - nr_pages -= min(nr_pages, zone->dirty_balance_reserve); - return nr_pages; -} - -/** * zone_dirty_limit - maximum number of dirty pages allowed in a zone * @zone: the zone * @@ -2178,11 +2173,12 @@ if (!TestSetPageDirty(page)) { struct address_space *mapping = page_mapping(page); struct address_space *mapping2; + unsigned long flags; if (!mapping) return 1; - spin_lock_irq(&mapping->tree_lock); + spin_lock_irqsave(&mapping->tree_lock, flags); mapping2 = page_mapping(page); if (mapping2) { /* Race with truncate? */ BUG_ON(mapping2 != mapping); @@ -2191,7 +2187,7 @@ radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } - spin_unlock_irq(&mapping->tree_lock); + spin_unlock_irqrestore(&mapping->tree_lock, flags); if (mapping->host) { /* !PageAnon && !swapper_space */ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); --- linux-3.13.0.orig/mm/fremap.c +++ linux-3.13.0/mm/fremap.c @@ -207,12 +207,14 @@ */ if (mapping_cap_account_dirty(mapping)) { unsigned long addr; - struct file *file = get_file(vma->vm_file); + struct file *file = vma->vm_file; + vma_get_file(vma); + /* mmap_region may free vma; grab the info now */ vm_flags = vma->vm_flags; addr = mmap_region(file, start, size, vm_flags, pgoff); - fput(file); + vma_fput(vma); if (IS_ERR_VALUE(addr)) { err = addr; } else { --- linux-3.13.0.orig/mm/compaction.c +++ linux-3.13.0/mm/compaction.c @@ -251,7 +251,6 @@ { int nr_scanned = 0, total_isolated = 0; struct page *cursor, *valid_page = NULL; - unsigned long nr_strict_required = end_pfn - blockpfn; unsigned long flags; bool locked = false; @@ -264,11 +263,12 @@ nr_scanned++; if (!pfn_valid_within(blockpfn)) - continue; + goto isolate_fail; + if (!valid_page) valid_page = page; if (!PageBuddy(page)) - continue; + goto isolate_fail; /* * The zone lock must be held to isolate freepages. @@ -289,12 +289,10 @@ /* Recheck this is a buddy page under lock */ if (!PageBuddy(page)) - continue; + goto isolate_fail; /* Found a free page, break it into order-0 pages */ isolated = split_free_page(page); - if (!isolated && strict) - break; total_isolated += isolated; for (i = 0; i < isolated; i++) { list_add(&page->lru, freelist); @@ -305,7 +303,15 @@ if (isolated) { blockpfn += isolated - 1; cursor += isolated - 1; + continue; } + +isolate_fail: + if (strict) + break; + else + continue; + } trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated); @@ -315,7 +321,7 @@ * pages requested were isolated. If there were any failures, 0 is * returned and CMA will fail. */ - if (strict && nr_strict_required > total_isolated) + if (strict && blockpfn < end_pfn) total_isolated = 0; if (locked) --- linux-3.13.0.orig/mm/slub.c +++ linux-3.13.0/mm/slub.c @@ -4299,7 +4299,13 @@ page = ACCESS_ONCE(c->partial); if (page) { - x = page->pobjects; + node = page_to_nid(page); + if (flags & SO_TOTAL) + WARN_ON_ONCE(1); + else if (flags & SO_OBJECTS) + WARN_ON_ONCE(1); + else + x = page->pages; total += x; nodes[node] += x; } --- linux-3.13.0.orig/mm/mempolicy.c +++ linux-3.13.0/mm/mempolicy.c @@ -2657,7 +2657,7 @@ } #ifdef CONFIG_NUMA_BALANCING -static bool __initdata numabalancing_override; +static int __initdata numabalancing_override; static void __init check_numabalancing_enable(void) { @@ -2666,9 +2666,15 @@ if (IS_ENABLED(CONFIG_NUMA_BALANCING_DEFAULT_ENABLED)) numabalancing_default = true; + /* Parsed by setup_numabalancing. override == 1 enables, -1 disables */ + if (numabalancing_override) + set_numabalancing_state(numabalancing_override == 1); + if (nr_node_ids > 1 && !numabalancing_override) { - printk(KERN_INFO "Enabling automatic NUMA balancing. " - "Configure with numa_balancing= or sysctl"); + printk(KERN_INFO "%s automatic NUMA balancing. " + "Configure with numa_balancing= or the " + "kernel.numa_balancing sysctl", + numabalancing_default ? "Enabling" : "Disabling"); set_numabalancing_state(numabalancing_default); } } @@ -2678,13 +2684,12 @@ int ret = 0; if (!str) goto out; - numabalancing_override = true; if (!strcmp(str, "enable")) { - set_numabalancing_state(true); + numabalancing_override = 1; ret = 1; } else if (!strcmp(str, "disable")) { - set_numabalancing_state(false); + numabalancing_override = -1; ret = 1; } out: @@ -2928,7 +2933,7 @@ unsigned short mode = MPOL_DEFAULT; unsigned short flags = 0; - if (pol && pol != &default_policy) { + if (pol && pol != &default_policy && !(pol->flags & MPOL_F_MORON)) { mode = pol->mode; flags = pol->flags; } --- linux-3.13.0.orig/mm/filemap.c +++ linux-3.13.0/mm/filemap.c @@ -1324,6 +1324,9 @@ if (size > count) size = count; + if (PageReadaheadUnused(page)) + ClearPageReadaheadUnused(page); + /* * Faults on the destination of a read are common, so do it before * taking the kmap. @@ -1735,7 +1738,7 @@ int ret = VM_FAULT_LOCKED; sb_start_pagefault(inode->i_sb); - file_update_time(vma->vm_file); + vma_file_update_time(vma); lock_page(page); if (page->mapping != inode->i_mapping) { unlock_page(page); --- linux-3.13.0.orig/mm/vmscan.c +++ linux-3.13.0/mm/vmscan.c @@ -147,7 +147,7 @@ } #endif -unsigned long zone_reclaimable_pages(struct zone *zone) +static unsigned long zone_reclaimable_pages(struct zone *zone) { int nr; @@ -3297,27 +3297,6 @@ wake_up_interruptible(&pgdat->kswapd_wait); } -/* - * The reclaimable count would be mostly accurate. - * The less reclaimable pages may be - * - mlocked pages, which will be moved to unevictable list when encountered - * - mapped pages, which may require several travels to be reclaimed - * - dirty pages, which is not "instantly" reclaimable - */ -unsigned long global_reclaimable_pages(void) -{ - int nr; - - nr = global_page_state(NR_ACTIVE_FILE) + - global_page_state(NR_INACTIVE_FILE); - - if (get_nr_swap_pages() > 0) - nr += global_page_state(NR_ACTIVE_ANON) + - global_page_state(NR_INACTIVE_ANON); - - return nr; -} - #ifdef CONFIG_HIBERNATION /* * Try to free `nr_to_reclaim' of memory, system-wide, and return the number of --- linux-3.13.0.orig/mm/mincore.c +++ linux-3.13.0/mm/mincore.c @@ -80,6 +80,8 @@ #endif if (page) { present = PageUptodate(page); + if (present) + present |= (PageReadaheadUnused(page) << 7); page_cache_release(page); } --- linux-3.13.0.orig/mm/memory-failure.c +++ linux-3.13.0/mm/memory-failure.c @@ -856,14 +856,14 @@ * the pages and send SIGBUS to the processes if the data was dirty. */ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, - int trapno, int flags) + int trapno, int flags, struct page **hpagep) { enum ttu_flags ttu = TTU_UNMAP | TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS; struct address_space *mapping; LIST_HEAD(tokill); int ret; int kill = 1, forcekill; - struct page *hpage = compound_head(p); + struct page *hpage = *hpagep; struct page *ppage; if (PageReserved(p) || PageSlab(p)) @@ -942,11 +942,16 @@ * We pinned the head page for hwpoison handling, * now we split the thp and we are interested in * the hwpoisoned raw page, so move the refcount - * to it. + * to it. Similarly, page lock is shifted. */ if (hpage != p) { - put_page(hpage); - get_page(p); + if (!(flags & MF_COUNT_INCREASED)) { + put_page(hpage); + get_page(p); + } + lock_page(p); + unlock_page(hpage); + *hpagep = p; } /* THP is split, so ppage should be the real poisoned page. */ ppage = p; @@ -964,17 +969,11 @@ if (kill) collect_procs(ppage, &tokill); - if (hpage != ppage) - lock_page(ppage); - ret = try_to_unmap(ppage, ttu); if (ret != SWAP_SUCCESS) printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n", pfn, page_mapcount(ppage)); - if (hpage != ppage) - unlock_page(ppage); - /* * Now that the dirty bit has been propagated to the * struct page and all unmaps done we can decide if @@ -1193,8 +1192,12 @@ /* * Now take care of user space mappings. * Abort on fail: __delete_from_page_cache() assumes unmapped page. + * + * When the raw error page is thp tail page, hpage points to the raw + * page after thp split. */ - if (hwpoison_user_mappings(p, pfn, trapno, flags) != SWAP_SUCCESS) { + if (hwpoison_user_mappings(p, pfn, trapno, flags, &hpage) + != SWAP_SUCCESS) { printk(KERN_ERR "MCE %#lx: cannot unmap page, give up\n", pfn); res = -EBUSY; goto out; --- linux-3.13.0.orig/mm/page_alloc.c +++ linux-3.13.0/mm/page_alloc.c @@ -1211,6 +1211,15 @@ } local_irq_restore(flags); } +static bool gfp_thisnode_allocation(gfp_t gfp_mask) +{ + return (gfp_mask & GFP_THISNODE) == GFP_THISNODE; +} +#else +static bool gfp_thisnode_allocation(gfp_t gfp_mask) +{ + return false; +} #endif /* @@ -1547,7 +1556,13 @@ get_pageblock_migratetype(page)); } - __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order)); + /* + * NOTE: GFP_THISNODE allocations do not partake in the kswapd + * aging protocol, so they can't be fair. + */ + if (!gfp_thisnode_allocation(gfp_flags)) + __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order)); + __count_zone_vm_events(PGALLOC, zone, 1 << order); zone_statistics(preferred_zone, zone, gfp_flags); local_irq_restore(flags); @@ -1919,8 +1934,12 @@ * ultimately fall back to remote zones that do not * partake in the fairness round-robin cycle of this * zonelist. + * + * NOTE: GFP_THISNODE allocations do not partake in + * the kswapd aging protocol, so they can't be fair. */ - if (alloc_flags & ALLOC_WMARK_LOW) { + if ((alloc_flags & ALLOC_WMARK_LOW) && + !gfp_thisnode_allocation(gfp_mask)) { if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0) continue; if (!zone_local(preferred_zone, zone)) @@ -2486,8 +2505,7 @@ * allowed per node queues are empty and that nodes are * over allocated. */ - if (IS_ENABLED(CONFIG_NUMA) && - (gfp_mask & GFP_THISNODE) == GFP_THISNODE) + if (gfp_thisnode_allocation(gfp_mask)) goto nopage; restart: @@ -6424,6 +6442,7 @@ #ifdef CONFIG_TRANSPARENT_HUGEPAGE {1UL << PG_compound_lock, "compound_lock" }, #endif + {1UL << PG_readaheadunused, "readaheadunused"}, }; static void dump_page_flags(unsigned long flags) --- linux-3.13.0.orig/mm/msync.c +++ linux-3.13.0/mm/msync.c @@ -80,10 +80,10 @@ start = vma->vm_end; if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) { - get_file(file); + vma_get_file(vma); up_read(&mm->mmap_sem); error = vfs_fsync(file, 0); - fput(file); + vma_fput(vma); if (error || start >= end) goto out; down_read(&mm->mmap_sem); --- linux-3.13.0.orig/mm/readahead.c +++ linux-3.13.0/mm/readahead.c @@ -189,6 +189,7 @@ list_add(&page->lru, &page_pool); if (page_idx == nr_to_read - lookahead_size) SetPageReadahead(page); + SetPageReadaheadUnused(page); ret++; } @@ -211,8 +212,6 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp, pgoff_t offset, unsigned long nr_to_read) { - int ret = 0; - if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages)) return -EINVAL; @@ -226,15 +225,13 @@ this_chunk = nr_to_read; err = __do_page_cache_readahead(mapping, filp, offset, this_chunk, 0); - if (err < 0) { - ret = err; - break; - } - ret += err; + if (err < 0) + return err; + offset += this_chunk; nr_to_read -= this_chunk; } - return ret; + return 0; } /* @@ -576,8 +573,7 @@ if (!mapping || !mapping->a_ops) return -EINVAL; - force_page_cache_readahead(mapping, filp, index, nr); - return 0; + return force_page_cache_readahead(mapping, filp, index, nr); } SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count) --- linux-3.13.0.orig/mm/memcontrol.c +++ linux-3.13.0/mm/memcontrol.c @@ -1098,16 +1098,22 @@ * skipped and we should continue the tree walk. * last_visited css is safe to use because it is * protected by css_get and the tree walk is rcu safe. + * + * We do not take a reference on the root of the tree walk + * because we might race with the root removal when it would + * be the only node in the iterated hierarchy and mem_cgroup_iter + * would end up in an endless loop because it expects that at + * least one valid node will be returned. Root cannot disappear + * because caller of the iterator should hold it already so + * skipping css reference should be safe. */ if (next_css) { - struct mem_cgroup *mem = mem_cgroup_from_css(next_css); + if ((next_css == &root->css) || + ((next_css->flags & CSS_ONLINE) && css_tryget(next_css))) + return mem_cgroup_from_css(next_css); - if (css_tryget(&mem->css)) - return mem; - else { - prev_css = next_css; - goto skip_node; - } + prev_css = next_css; + goto skip_node; } return NULL; @@ -1141,7 +1147,15 @@ if (iter->last_dead_count == *sequence) { smp_rmb(); position = iter->last_visited; - if (position && !css_tryget(&position->css)) + + /* + * We cannot take a reference to root because we might race + * with root removal and returning NULL would end up in + * an endless loop on the iterator user level when root + * would be returned all the time. + */ + if (position && position != root && + !css_tryget(&position->css)) position = NULL; } return position; @@ -1150,9 +1164,11 @@ static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter, struct mem_cgroup *last_visited, struct mem_cgroup *new_position, + struct mem_cgroup *root, int sequence) { - if (last_visited) + /* root reference counting symmetric to mem_cgroup_iter_load */ + if (last_visited && last_visited != root) css_put(&last_visited->css); /* * We store the sequence count from the time @last_visited was @@ -1227,7 +1243,8 @@ memcg = __mem_cgroup_iter_next(root, last_visited); if (reclaim) { - mem_cgroup_iter_update(iter, last_visited, memcg, seq); + mem_cgroup_iter_update(iter, last_visited, memcg, root, + seq); if (!memcg) iter->generation++; @@ -6343,11 +6360,24 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct cgroup_subsys_state *iter; kmem_cgroup_css_offline(memcg); mem_cgroup_invalidate_reclaim_iterators(memcg); - mem_cgroup_reparent_charges(memcg); + + /* + * This requires that offlining is serialized. Right now that is + * guaranteed because css_killed_work_fn() holds the cgroup_mutex. + */ + rcu_read_lock(); + css_for_each_descendant_post(iter, css) { + rcu_read_unlock(); + mem_cgroup_reparent_charges(mem_cgroup_from_css(iter)); + rcu_read_lock(); + } + rcu_read_unlock(); + mem_cgroup_destroy_all_caches(memcg); vmpressure_cleanup(&memcg->vmpressure); } --- linux-3.13.0.orig/mm/huge_memory.c +++ linux-3.13.0/mm/huge_memory.c @@ -1160,8 +1160,10 @@ } else { ret = do_huge_pmd_wp_page_fallback(mm, vma, address, pmd, orig_pmd, page, haddr); - if (ret & VM_FAULT_OOM) + if (ret & VM_FAULT_OOM) { split_huge_page(page); + ret |= VM_FAULT_FALLBACK; + } put_page(page); } count_vm_event(THP_FAULT_FALLBACK); @@ -1173,9 +1175,10 @@ if (page) { split_huge_page(page); put_page(page); - } + } else + split_huge_page_pmd(vma, address, pmd); + ret |= VM_FAULT_FALLBACK; count_vm_event(THP_FAULT_FALLBACK); - ret |= VM_FAULT_OOM; goto out; } @@ -1502,19 +1505,15 @@ spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING); pmd = pmdp_get_and_clear(mm, old_addr, old_pmd); VM_BUG_ON(!pmd_none(*new_pmd)); - set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd)); - if (new_ptl != old_ptl) { - pgtable_t pgtable; - /* - * Move preallocated PTE page table if new_pmd is on - * different PMD page table. - */ + if (pmd_move_must_withdraw(new_ptl, old_ptl)) { + pgtable_t pgtable; pgtable = pgtable_trans_huge_withdraw(mm, old_pmd); pgtable_trans_huge_deposit(mm, new_pmd, pgtable); - - spin_unlock(new_ptl); } + set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd)); + if (new_ptl != old_ptl) + spin_unlock(new_ptl); spin_unlock(old_ptl); } out: @@ -1961,7 +1960,7 @@ return ret; } -#define VM_NO_THP (VM_SPECIAL|VM_MIXEDMAP|VM_HUGETLB|VM_SHARED|VM_MAYSHARE) +#define VM_NO_THP (VM_SPECIAL | VM_HUGETLB | VM_SHARED | VM_MAYSHARE) int hugepage_madvise(struct vm_area_struct *vma, unsigned long *vm_flags, int advice) --- linux-3.13.0.orig/mm/swapfile.c +++ linux-3.13.0/mm/swapfile.c @@ -1922,7 +1922,6 @@ p->swap_map = NULL; cluster_info = p->cluster_info; p->cluster_info = NULL; - p->flags = 0; frontswap_map = frontswap_map_get(p); spin_unlock(&p->lock); spin_unlock(&swap_lock); @@ -1948,6 +1947,16 @@ mutex_unlock(&inode->i_mutex); } filp_close(swap_file, NULL); + + /* + * Clear the SWP_USED flag after all resources are freed so that swapon + * can reuse this swap_info in alloc_swap_info() safely. It is ok to + * not hold p->lock after we cleared its SWP_WRITEOK. + */ + spin_lock(&swap_lock); + p->flags = 0; + spin_unlock(&swap_lock); + err = 0; atomic_inc(&proc_poll_event); wake_up_interruptible(&proc_poll_wait); --- linux-3.13.0.orig/sound/usb/mixer.c +++ linux-3.13.0/sound/usb/mixer.c @@ -883,6 +883,7 @@ } break; + case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */ case USB_ID(0x046d, 0x0808): case USB_ID(0x046d, 0x0809): case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */ --- linux-3.13.0.orig/sound/usb/mixer_maps.c +++ linux-3.13.0/sound/usb/mixer_maps.c @@ -322,6 +322,11 @@ { 0 } /* terminator */ }; +static const struct usbmix_name_map kef_x300a_map[] = { + { 10, NULL }, /* firmware locks up (?) when we try to access this FU */ + { 0 } +}; + /* * Control map entries */ @@ -409,6 +414,10 @@ .id = USB_ID(0x200c, 0x1018), .map = ebox44_map, }, + { + .id = USB_ID(0x27ac, 0x1000), + .map = kef_x300a_map, + }, { 0 } /* terminator */ }; --- linux-3.13.0.orig/sound/usb/Kconfig +++ linux-3.13.0/sound/usb/Kconfig @@ -14,6 +14,7 @@ select SND_HWDEP select SND_RAWMIDI select SND_PCM + select BITREVERSE help Say Y here to include support for USB audio and USB MIDI devices. --- linux-3.13.0.orig/sound/pci/Kconfig +++ linux-3.13.0/sound/pci/Kconfig @@ -25,6 +25,7 @@ select SND_PCM select SND_AC97_CODEC select SND_OPL3_LIB + select ZONE_DMA help Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+ @@ -49,6 +50,7 @@ tristate "ALi M5451 PCI Audio Controller" select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for the integrated AC97 sound device on motherboards using the ALi M5451 Audio Controller @@ -153,6 +155,7 @@ select SND_PCM select SND_RAWMIDI select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for Aztech AZF3328 (PCI168) soundcards. @@ -458,6 +461,7 @@ select SND_HWDEP select SND_RAWMIDI select SND_AC97_CODEC + select ZONE_DMA help Say Y to include support for Sound Blaster PCI 512, Live!, Audigy and E-mu APS (partially supported) soundcards. @@ -473,6 +477,7 @@ tristate "Emu10k1X (Dell OEM Version)" select SND_AC97_CODEC select SND_RAWMIDI + select ZONE_DMA help Say Y here to include support for the Dell OEM version of the Sound Blaster Live!. @@ -506,6 +511,7 @@ select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on ESS Solo-1 (ES1938, ES1946, ES1969) chips. @@ -517,6 +523,7 @@ tristate "ESS ES1968/1978 (Maestro-1/2/2E)" select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on ESS Maestro 1/2/2E chips. @@ -605,6 +612,7 @@ select SND_MPU401_UART select SND_AC97_CODEC select BITREVERSE + select ZONE_DMA help Say Y here to include support for soundcards based on the ICE1712 (Envy24) chip. @@ -692,6 +700,7 @@ config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on ESS Maestro 3 (Allegro) chips. @@ -788,6 +797,7 @@ tristate "SiS 7019 Audio Accelerator" depends on X86 && !X86_64 select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for the SiS 7019 Audio Accelerator. @@ -799,6 +809,7 @@ select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on the S3 SonicVibes chip. @@ -810,6 +821,7 @@ tristate "Trident 4D-Wave DX/NX; SiS 7018" select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on Trident 4D-Wave DX/NX or SiS 7018 chips. --- linux-3.13.0.orig/sound/pci/rme9652/rme9652.c +++ linux-3.13.0/sound/pci/rme9652/rme9652.c @@ -285,7 +285,7 @@ /* ADAT channels are remapped */ 1, 3, 5, 7, 9, 11, 13, 15, /* channels 8 and 9 are S/PDIF */ - 24, 25 + 24, 25, /* others don't exist */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; --- linux-3.13.0.orig/sound/pci/oxygen/xonar_dg.c +++ linux-3.13.0/sound/pci/oxygen/xonar_dg.c @@ -294,6 +294,16 @@ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, data->output_sel == 1 ? GPIO_HP_REAR : 0, GPIO_HP_REAR); + oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING, + data->output_sel == 0 ? + OXYGEN_PLAY_MUTE01 : + OXYGEN_PLAY_MUTE23 | + OXYGEN_PLAY_MUTE45 | + OXYGEN_PLAY_MUTE67, + OXYGEN_PLAY_MUTE01 | + OXYGEN_PLAY_MUTE23 | + OXYGEN_PLAY_MUTE45 | + OXYGEN_PLAY_MUTE67); } mutex_unlock(&chip->mutex); return changed; @@ -596,7 +606,7 @@ .model_data_size = sizeof(struct dg), .device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2 | + CAPTURE_0_FROM_I2S_1 | CAPTURE_1_FROM_SPDIF, .dac_channels_pcm = 6, .dac_channels_mixer = 0, --- linux-3.13.0.orig/sound/pci/hda/hda_generic.c +++ linux-3.13.0/sound/pci/hda/hda_generic.c @@ -2857,9 +2857,11 @@ if (num_conns < idx) return false; nid = list[idx]; - if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT)) + if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) && + !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL)) *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT)) + if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) && + !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL)) *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); return *mix_val || *mute_val; --- linux-3.13.0.orig/sound/pci/hda/patch_sigmatel.c +++ linux-3.13.0/sound/pci/hda/patch_sigmatel.c @@ -83,6 +83,7 @@ STAC_DELL_M6_BOTH, STAC_DELL_EQ, STAC_ALIENWARE_M17X, + STAC_92HD89XX_HP_FRONT_JACK, STAC_92HD73XX_MODELS }; @@ -97,6 +98,7 @@ STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_HP_MIC_LED, + STAC_HP_LED_GPIO10, STAC_92HD83XXX_HEADSET_JACK, STAC_92HD83XXX_HP, STAC_HP_ENVY_BASS, @@ -1777,6 +1779,12 @@ {} }; +static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02A19010 }, + {} +}; + static void stac92hd73xx_fixup_ref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -1895,6 +1903,10 @@ [STAC_92HD73XX_NO_JD] = { .type = HDA_FIXUP_FUNC, .v.func = stac92hd73xx_fixup_no_jd, + }, + [STAC_92HD89XX_HP_FRONT_JACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac92hd89xx_hp_front_jack_pin_configs, } }; @@ -1955,6 +1967,8 @@ "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, + "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), {} /* terminator */ }; @@ -2099,6 +2113,17 @@ } } +static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_led = 0x10; /* GPIO4 */ + spec->default_polarity = 0; + } +} + static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -2593,6 +2618,12 @@ .chained = true, .chain_id = STAC_92HD83XXX_HP, }, + [STAC_HP_LED_GPIO10] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_led_gpio10, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, [STAC_92HD83XXX_HEADSET_JACK] = { .type = HDA_FIXUP_FUNC, .v.func = stac92hd83xxx_fixup_headset_jack, @@ -2671,6 +2702,8 @@ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888, "HP Envy Spectre", STAC_HP_ENVY_BASS), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899, + "HP Folio 13", STAC_HP_LED_GPIO10), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, "HP Folio", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8, --- linux-3.13.0.orig/sound/pci/hda/patch_ca0132.c +++ linux-3.13.0/sound/pci/hda/patch_ca0132.c @@ -2662,60 +2662,6 @@ } /* - * PCM stuffs - */ -static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, - u32 stream_tag, - int channel_id, int format) -{ - unsigned int oldval, newval; - - if (!nid) - return; - - snd_printdd( - "ca0132_setup_stream: NID=0x%x, stream=0x%x, " - "channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); - - /* update the format-id if changed */ - oldval = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_STREAM_FORMAT, - 0); - if (oldval != format) { - msleep(20); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, - format); - } - - oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - newval = (stream_tag << 4) | channel_id; - if (oldval != newval) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - newval); - } -} - -static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - - if (!nid) - return; - - snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid); - - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - if (!val) - return; - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); -} - -/* * PCM callbacks */ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -2726,7 +2672,7 @@ { struct ca0132_spec *spec = codec->spec; - ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); return 0; } @@ -2745,7 +2691,7 @@ if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) msleep(50); - ca0132_cleanup_stream(codec, spec->dacs[0]); + snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); return 0; } @@ -2822,10 +2768,8 @@ unsigned int format, struct snd_pcm_substream *substream) { - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, hinfo->nid, + stream_tag, 0, format); return 0; } @@ -2839,7 +2783,7 @@ if (spec->dsp_state == DSP_DOWNLOADING) return 0; - ca0132_cleanup_stream(codec, hinfo->nid); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; } @@ -4742,6 +4686,8 @@ return err; codec->patch_ops = ca0132_patch_ops; + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1; return 0; } --- linux-3.13.0.orig/sound/pci/hda/patch_analog.c +++ linux-3.13.0/sound/pci/hda/patch_analog.c @@ -185,7 +185,7 @@ }; -static int ad198x_parse_auto_config(struct hda_codec *codec) +static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp) { struct ad198x_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->gen.autocfg; @@ -195,7 +195,7 @@ codec->no_trigger_sense = 1; codec->no_sticky_stream = 1; - spec->gen.indep_hp = 1; + spec->gen.indep_hp = indep_hp; err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); if (err < 0) @@ -243,6 +243,19 @@ } } +/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */ +static void ad1986a_fixup_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct ad198x_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + codec->inv_eapd = 0; + spec->gen.keep_eapd_on = 1; + spec->eapd_nid = 0x1b; + } +} + enum { AD1986A_FIXUP_INV_JACK_DETECT, AD1986A_FIXUP_ULTRA, @@ -250,6 +263,7 @@ AD1986A_FIXUP_3STACK, AD1986A_FIXUP_LAPTOP, AD1986A_FIXUP_LAPTOP_IMIC, + AD1986A_FIXUP_EAPD, }; static const struct hda_fixup ad1986a_fixups[] = { @@ -280,11 +294,11 @@ .v.pins = (const struct hda_pintbl[]) { { 0x1a, 0x02214021 }, /* headphone */ { 0x1b, 0x01014011 }, /* front */ - { 0x1c, 0x01013012 }, /* surround */ - { 0x1d, 0x01019015 }, /* clfe */ + { 0x1c, 0x01813030 }, /* line-in */ + { 0x1d, 0x01a19020 }, /* rear mic */ { 0x1e, 0x411111f0 }, /* N/A */ { 0x1f, 0x02a190f0 }, /* mic */ - { 0x20, 0x018130f0 }, /* line-in */ + { 0x20, 0x411111f0 }, /* N/A */ {} }, }, @@ -310,6 +324,10 @@ .chained_before = 1, .chain_id = AD1986A_FIXUP_LAPTOP, }, + [AD1986A_FIXUP_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1986a_fixup_eapd, + }, }; static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { @@ -317,6 +335,7 @@ SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), @@ -378,7 +397,7 @@ ad1986a_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - err = ad198x_parse_auto_config(codec); + err = ad198x_parse_auto_config(codec, false); if (err < 0) { snd_hda_gen_free(codec); return err; @@ -471,6 +490,8 @@ static int patch_ad1983(struct hda_codec *codec) { struct ad198x_spec *spec; + static hda_nid_t conn_0c[] = { 0x08 }; + static hda_nid_t conn_0d[] = { 0x09 }; int err; err = alloc_ad_spec(codec); @@ -478,9 +499,15 @@ return err; spec = codec->spec; + spec->gen.mixer_nid = 0x0e; spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - err = ad198x_parse_auto_config(codec); + + /* limit the loopback routes not to confuse the parser */ + snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c); + snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d); + + err = ad198x_parse_auto_config(codec, false); if (err < 0) goto error; err = ad1983_add_spdif_mux_ctl(codec); @@ -567,7 +594,7 @@ snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - err = ad198x_parse_auto_config(codec); + err = ad198x_parse_auto_config(codec, false); if (err < 0) goto error; err = ad1983_add_spdif_mux_ctl(codec); @@ -893,7 +920,7 @@ snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - err = ad198x_parse_auto_config(codec); + err = ad198x_parse_auto_config(codec, true); if (err < 0) goto error; err = ad1988_add_spdif_mux_ctl(codec); @@ -998,6 +1025,9 @@ spec->gen.keep_eapd_on = 1; spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; spec->eapd_nid = 0x12; + /* Analog PC Beeper - allow firmware/ACPI beeps */ + spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT); + spec->gen.beep_nid = 0; /* no digital beep */ } } @@ -1064,13 +1094,14 @@ spec = codec->spec; spec->gen.mixer_nid = 0x20; + spec->gen.mixer_merge_nid = 0x21; spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - err = ad198x_parse_auto_config(codec); + err = ad198x_parse_auto_config(codec, true); if (err < 0) goto error; err = ad1983_add_spdif_mux_ctl(codec); @@ -1112,7 +1143,7 @@ spec->gen.mixer_merge_nid = 0x21; spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - err = ad198x_parse_auto_config(codec); + err = ad198x_parse_auto_config(codec, true); if (err < 0) goto error; err = ad1988_add_spdif_mux_ctl(codec); --- linux-3.13.0.orig/sound/pci/hda/patch_hdmi.c +++ linux-3.13.0/sound/pci/hda/patch_hdmi.c @@ -129,6 +129,9 @@ struct hdmi_eld temp_eld; struct hdmi_ops ops; + + bool dyn_pin_out; + /* * Non-generic VIA/NVIDIA specific */ @@ -497,15 +500,25 @@ static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) { + struct hdmi_spec *spec = codec->spec; + int pin_out; + /* Unmute */ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Enable pin out: some machines with GM965 gets broken output when - * the pin is disabled or changed while using with HDMI - */ + + if (spec->dyn_pin_out) + /* Disable pin out until stream is active */ + pin_out = 0; + else + /* Enable pin out: some machines with GM965 gets broken output + * when the pin is disabled or changed while using with HDMI + */ + pin_out = PIN_OUT; + snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out); } static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) @@ -1496,11 +1509,14 @@ * specification worked this way. Hence, we just ignore the data in * the unsolicited response to avoid custom WARs. */ - int present = snd_hda_pin_sense(codec, pin_nid); + int present; bool update_eld = false; bool eld_changed = false; bool ret; + snd_hda_power_up(codec); + present = snd_hda_pin_sense(codec, pin_nid); + mutex_lock(&per_pin->lock); pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); if (pin_eld->monitor_present) @@ -1573,6 +1589,7 @@ jack->block_report = !ret; mutex_unlock(&per_pin->lock); + snd_hda_power_down(codec); return ret; } @@ -1743,6 +1760,7 @@ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; bool non_pcm; + int pinctl; non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); @@ -1752,6 +1770,14 @@ hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); mutex_unlock(&per_pin->lock); + if (spec->dyn_pin_out) { + pinctl = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl | PIN_OUT); + } + return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } @@ -1771,6 +1797,7 @@ int cvt_idx, pin_idx; struct hdmi_spec_per_cvt *per_cvt; struct hdmi_spec_per_pin *per_pin; + int pinctl; if (hinfo->nid) { cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); @@ -1787,6 +1814,14 @@ return -EINVAL; per_pin = get_pin(spec, pin_idx); + if (spec->dyn_pin_out) { + pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_codec_write(codec, per_pin->pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl & ~PIN_OUT); + } + snd_hda_spdif_ctls_unassign(codec, pin_idx); mutex_lock(&per_pin->lock); @@ -2844,6 +2879,7 @@ return err; spec = codec->spec; + spec->dyn_pin_out = true; spec->ops.chmap_cea_alloc_validate_get_type = nvhdmi_chmap_cea_alloc_validate_get_type; --- linux-3.13.0.orig/sound/pci/hda/patch_realtek.c +++ linux-3.13.0/sound/pci/hda/patch_realtek.c @@ -1780,7 +1780,9 @@ ALC889_FIXUP_DAC_ROUTE, ALC889_FIXUP_MBP_VREF, ALC889_FIXUP_IMAC91_VREF, + ALC889_FIXUP_MBA11_VREF, ALC889_FIXUP_MBA21_VREF, + ALC889_FIXUP_MP11_VREF, ALC882_FIXUP_INV_DMIC, ALC882_FIXUP_NO_PRIMARY_HP, ALC887_FIXUP_ASUS_BASS, @@ -1910,6 +1912,16 @@ alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); } +/* Set VREF on speaker pins on mba11 */ +static void alc889_fixup_mba11_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static hda_nid_t nids[1] = { 0x18 }; + + if (action == HDA_FIXUP_ACT_INIT) + alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); +} + /* Set VREF on speaker pins on mba21 */ static void alc889_fixup_mba21_vref(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -2119,12 +2131,24 @@ .chained = true, .chain_id = ALC882_FIXUP_GPIO1, }, + [ALC889_FIXUP_MBA11_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba11_vref, + .chained = true, + .chain_id = ALC889_FIXUP_MBP_VREF, + }, [ALC889_FIXUP_MBA21_VREF] = { .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_mba21_vref, .chained = true, .chain_id = ALC889_FIXUP_MBP_VREF, }, + [ALC889_FIXUP_MP11_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba11_vref, + .chained = true, + .chain_id = ALC885_FIXUP_MACPRO_GPIO, + }, [ALC882_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, @@ -2188,13 +2212,13 @@ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF), SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF), SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), @@ -3526,6 +3550,28 @@ alc_fixup_headset_mode(codec, fix, action); } +static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->gen.auto_mute_via_amp = 1; + } +} + +static void alc_no_shutup(struct hda_codec *codec) +{ +} + +static void alc_fixup_no_shutup(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->shutup = alc_no_shutup; + } +} + static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -3837,6 +3883,7 @@ ALC269_FIXUP_HP_GPIO_LED, ALC269_FIXUP_INV_DMIC, ALC269_FIXUP_LENOVO_DOCK, + ALC269_FIXUP_NO_SHUTUP, ALC286_FIXUP_SONY_MIC_NO_PRESENCE, ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT, ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, @@ -4009,6 +4056,10 @@ .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC269_FIXUP_NO_SHUTUP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_no_shutup, + }, [ALC269_FIXUP_LENOVO_DOCK] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -4209,6 +4260,7 @@ }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), @@ -4247,7 +4299,8 @@ SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x060f, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_MONO_SPEAKERS), @@ -4257,6 +4310,14 @@ SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -4279,6 +4340,7 @@ SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101), + SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), @@ -4300,6 +4362,7 @@ SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -4841,6 +4904,7 @@ ALC662_FIXUP_BASS_CHMAP, ALC662_FIXUP_BASS_1A, ALC662_FIXUP_BASS_1A_CHMAP, + ALC668_FIXUP_AUTO_MUTE, }; static const struct hda_fixup alc662_fixups[] = { @@ -5001,6 +5065,12 @@ .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC668_FIXUP_AUTO_MUTE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_auto_mute_via_amp, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE + }, [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -5046,11 +5116,13 @@ SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0623, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0624, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0623, "Dell", ALC668_FIXUP_AUTO_MUTE), + SND_PCI_QUIRK(0x1028, 0x0624, "Dell", ALC668_FIXUP_AUTO_MUTE), SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE), + SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP), SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP), --- linux-3.13.0.orig/sound/core/compress_offload.c +++ linux-3.13.0/sound/core/compress_offload.c @@ -133,7 +133,7 @@ kfree(data); } snd_card_unref(compr->card); - return 0; + return ret; } static int snd_compr_free(struct inode *inode, struct file *f) --- linux-3.13.0.orig/sound/core/init.c +++ linux-3.13.0/sound/core/init.c @@ -170,7 +170,7 @@ if (idx < 0) { for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) { /* idx == -1 == 0xffff means: take any free slot */ - if (idx2 < sizeof(int) && !(idx & (1U << idx2))) + if (idx2 < 32 && !(idx & (1U << idx2))) continue; if (!test_bit(idx2, snd_cards_lock)) { if (module_slot_match(module, idx2)) { @@ -183,7 +183,7 @@ if (idx < 0) { for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) { /* idx == -1 == 0xffff means: take any free slot */ - if (idx2 < sizeof(int) && !(idx & (1U << idx2))) + if (idx2 < 32 && !(idx & (1U << idx2))) continue; if (!test_bit(idx2, snd_cards_lock)) { if (!slots[idx2] || !*slots[idx2]) { --- linux-3.13.0.orig/sound/soc/fsl/imx-mc13783.c +++ linux-3.13.0/sound/soc/fsl/imx-mc13783.c @@ -160,7 +160,6 @@ .driver = { .name = "imx_mc13783", .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, }, .probe = imx_mc13783_probe, .remove = imx_mc13783_remove --- linux-3.13.0.orig/sound/soc/fsl/imx-wm8962.c +++ linux-3.13.0/sound/soc/fsl/imx-wm8962.c @@ -71,7 +71,7 @@ { struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct imx_priv *priv = &card_priv; - struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; unsigned int pll_out; int ret; @@ -137,7 +137,7 @@ { struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct imx_priv *priv = &card_priv; - struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; int ret; @@ -264,13 +264,15 @@ data->card.late_probe = imx_wm8962_late_probe; data->card.set_bias_level = imx_wm8962_set_bias_level; + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto clk_fail; } - platform_set_drvdata(pdev, data); of_node_put(ssi_np); of_node_put(codec_np); @@ -289,7 +291,8 @@ static int imx_wm8962_remove(struct platform_device *pdev) { - struct imx_wm8962_data *data = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); if (!IS_ERR(data->codec_clk)) clk_disable_unprepare(data->codec_clk); --- linux-3.13.0.orig/sound/soc/fsl/imx-sgtl5000.c +++ linux-3.13.0/sound/soc/fsl/imx-sgtl5000.c @@ -33,8 +33,7 @@ static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct imx_sgtl5000_data *data = container_of(rtd->card, - struct imx_sgtl5000_data, card); + struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card); struct device *dev = rtd->card->dev; int ret; @@ -159,13 +158,15 @@ data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto fail; } - platform_set_drvdata(pdev, data); of_node_put(ssi_np); of_node_put(codec_np); @@ -184,7 +185,8 @@ static int imx_sgtl5000_remove(struct platform_device *pdev) { - struct imx_sgtl5000_data *data = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card); clk_put(data->codec_clk); --- linux-3.13.0.orig/sound/soc/codecs/wm5110.c +++ linux-3.13.0/sound/soc/codecs/wm5110.c @@ -43,6 +43,54 @@ { 0x3133, 0x1201 }, { 0x3183, 0x1501 }, { 0x31D3, 0x1401 }, + { 0x0049, 0x01ea }, + { 0x004a, 0x01f2 }, + { 0x0057, 0x01e7 }, + { 0x0058, 0x01fb }, + { 0x33ce, 0xc4f5 }, + { 0x33cf, 0x1361 }, + { 0x33d0, 0x0402 }, + { 0x33d1, 0x4700 }, + { 0x33d2, 0x026d }, + { 0x33d3, 0xff00 }, + { 0x33d4, 0x026d }, + { 0x33d5, 0x0101 }, + { 0x33d6, 0xc4f5 }, + { 0x33d7, 0x0361 }, + { 0x33d8, 0x0402 }, + { 0x33d9, 0x6701 }, + { 0x33da, 0xc4f5 }, + { 0x33db, 0x136f }, + { 0x33dc, 0xc4f5 }, + { 0x33dd, 0x134f }, + { 0x33de, 0xc4f5 }, + { 0x33df, 0x131f }, + { 0x33e0, 0x026d }, + { 0x33e1, 0x4f01 }, + { 0x33e2, 0x026d }, + { 0x33e3, 0xf100 }, + { 0x33e4, 0x026d }, + { 0x33e5, 0x0001 }, + { 0x33e6, 0xc4f5 }, + { 0x33e7, 0x0361 }, + { 0x33e8, 0x0402 }, + { 0x33e9, 0x6601 }, + { 0x33ea, 0xc4f5 }, + { 0x33eb, 0x136f }, + { 0x33ec, 0xc4f5 }, + { 0x33ed, 0x134f }, + { 0x33ee, 0xc4f5 }, + { 0x33ef, 0x131f }, + { 0x33f0, 0x026d }, + { 0x33f1, 0x4e01 }, + { 0x33f2, 0x026d }, + { 0x33f3, 0xf000 }, + { 0x33f6, 0xc4f5 }, + { 0x33f7, 0x1361 }, + { 0x33f8, 0x0402 }, + { 0x33f9, 0x4600 }, + { 0x33fa, 0x026d }, + { 0x33fb, 0xfe00 }, }; static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, --- linux-3.13.0.orig/sound/soc/codecs/da9055.c +++ linux-3.13.0/sound/soc/codecs/da9055.c @@ -1523,8 +1523,15 @@ return 0; } +/* + * DO NOT change the device Ids. The naming is intentionally specific as both + * the CODEC and PMIC parts of this chip are instantiated separately as I2C + * devices (both have configurable I2C addresses, and are to all intents and + * purposes separate). As a result there are specific DA9055 Ids for CODEC + * and PMIC, which must be different to operate together. + */ static const struct i2c_device_id da9055_i2c_id[] = { - { "da9055", 0 }, + { "da9055-codec", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); @@ -1532,7 +1539,7 @@ /* I2C codec control layer */ static struct i2c_driver da9055_i2c_driver = { .driver = { - .name = "da9055", + .name = "da9055-codec", .owner = THIS_MODULE, }, .probe = da9055_i2c_probe, --- linux-3.13.0.orig/sound/soc/codecs/tlv320aic32x4.c +++ linux-3.13.0/sound/soc/codecs/tlv320aic32x4.c @@ -267,8 +267,8 @@ .selector_mask = 0xff, .window_start = 0, .window_len = 128, - .range_min = AIC32X4_PAGE1, - .range_max = AIC32X4_PAGE1 + 127, + .range_min = 0, + .range_max = AIC32X4_RMICPGAVOL, }, }; --- linux-3.13.0.orig/sound/soc/codecs/da732x.c +++ linux-3.13.0/sound/soc/codecs/da732x.c @@ -1268,11 +1268,23 @@ }, }; +static bool da732x_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA732X_REG_HPL_DAC_OFF_CNTL: + case DA732X_REG_HPR_DAC_OFF_CNTL: + return true; + default: + return false; + } +} + static const struct regmap_config da732x_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = DA732X_MAX_REG, + .volatile_reg = da732x_volatile, .reg_defaults = da732x_reg_cache, .num_reg_defaults = ARRAY_SIZE(da732x_reg_cache), .cache_type = REGCACHE_RBTREE, --- linux-3.13.0.orig/sound/soc/codecs/rt5640.c +++ linux-3.13.0/sound/soc/codecs/rt5640.c @@ -2093,6 +2093,7 @@ #ifdef CONFIG_ACPI static struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, + { "10EC5640", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); --- linux-3.13.0.orig/sound/soc/codecs/wm8958-dsp2.c +++ linux-3.13.0/sound/soc/codecs/wm8958-dsp2.c @@ -153,7 +153,7 @@ data32 &= 0xffffff; - wm8994_bulk_write(codec->control_data, + wm8994_bulk_write(wm8994->wm8994, data32 & 0xffffff, block_len / 2, (void *)(data + 8)); --- linux-3.13.0.orig/sound/soc/codecs/si476x.c +++ linux-3.13.0/sound/soc/codecs/si476x.c @@ -210,7 +210,7 @@ static int si476x_codec_probe(struct snd_soc_codec *codec) { codec->control_data = dev_get_regmap(codec->dev->parent, NULL); - return 0; + return snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); } static struct snd_soc_dai_ops si476x_dai_ops = { --- linux-3.13.0.orig/sound/soc/codecs/max98090.c +++ linux-3.13.0/sound/soc/codecs/max98090.c @@ -336,6 +336,7 @@ case M98090_REG_RECORD_TDM_SLOT: case M98090_REG_SAMPLE_RATE: case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: + case M98090_REG_REVISION_ID: return true; default: return false; @@ -1769,16 +1770,6 @@ switch (level) { case SND_SOC_BIAS_ON: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = regcache_sync(max98090->regmap); - - if (ret != 0) { - dev_err(codec->dev, - "Failed to sync cache: %d\n", ret); - return ret; - } - } - if (max98090->jack_state == M98090_JACK_STATE_HEADSET) { /* * Set to normal bias level. @@ -1792,6 +1783,16 @@ break; case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + ret = regcache_sync(max98090->regmap); + if (ret != 0) { + dev_err(codec->dev, + "Failed to sync cache: %d\n", ret); + return ret; + } + } + break; + case SND_SOC_BIAS_OFF: /* Set internal pull-up to lowest power mode */ snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, --- linux-3.13.0.orig/sound/soc/codecs/adau1701.c +++ linux-3.13.0/sound/soc/codecs/adau1701.c @@ -71,7 +71,7 @@ #define ADAU1701_SEROCTL_WORD_LEN_24 0x0000 #define ADAU1701_SEROCTL_WORD_LEN_20 0x0001 -#define ADAU1701_SEROCTL_WORD_LEN_16 0x0010 +#define ADAU1701_SEROCTL_WORD_LEN_16 0x0002 #define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003 #define ADAU1701_AUXNPOW_VBPD 0x40 --- linux-3.13.0.orig/sound/soc/codecs/sta32x.c +++ linux-3.13.0/sound/soc/codecs/sta32x.c @@ -187,42 +187,42 @@ 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), }; -static const struct soc_enum sta32x_drc_ac_enum = - SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, - 2, sta32x_drc_ac); -static const struct soc_enum sta32x_auto_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, - 3, sta32x_auto_eq_mode); -static const struct soc_enum sta32x_auto_gc_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, - 4, sta32x_auto_gc_mode); -static const struct soc_enum sta32x_auto_xo_enum = - SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, - 16, sta32x_auto_xo_mode); -static const struct soc_enum sta32x_preset_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, - 32, sta32x_preset_eq_mode); -static const struct soc_enum sta32x_limiter_ch1_enum = - SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch2_enum = - SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch3_enum = - SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter1_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter2_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter1_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); -static const struct soc_enum sta32x_limiter2_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum, + STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, + sta32x_drc_ac); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum, + STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, + sta32x_auto_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum, + STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, + sta32x_auto_gc_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum, + STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, + sta32x_auto_xo_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum, + STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, + sta32x_preset_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum, + STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum, + STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum, + STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum, + STA32X_L1AR, STA32X_LxA_SHIFT, + sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum, + STA32X_L2AR, STA32X_LxA_SHIFT, + sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum, + STA32X_L1AR, STA32X_LxR_SHIFT, + sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum, + STA32X_L2AR, STA32X_LxR_SHIFT, + sta32x_limiter_release_rate); /* byte array controls for setting biquad, mixer, scaling coefficients; * for biquads all five coefficients need to be set in one go, @@ -331,7 +331,7 @@ static int sta32x_cache_sync(struct snd_soc_codec *codec) { - struct sta32x_priv *sta32x = codec->control_data; + struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); unsigned int mute; int rc; @@ -434,7 +434,7 @@ SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), -SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), +SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum), /* depending on mode, the attack/release thresholds have * two different enum definitions; provide both --- linux-3.13.0.orig/sound/soc/codecs/wm8770.c +++ linux-3.13.0/sound/soc/codecs/wm8770.c @@ -196,8 +196,8 @@ "AIN5", "AIN6", "AIN7", "AIN8" }; -static const struct soc_enum ain_enum = - SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text); +static SOC_ENUM_DOUBLE_DECL(ain_enum, + WM8770_ADCMUX, 0, 4, ain_text); static const struct snd_kcontrol_new ain_mux = SOC_DAPM_ENUM("Capture Mux", ain_enum); --- linux-3.13.0.orig/sound/soc/codecs/88pm860x-codec.c +++ linux-3.13.0/sound/soc/codecs/88pm860x-codec.c @@ -1328,6 +1328,9 @@ pm860x->codec = codec; codec->control_data = pm860x->regmap; + ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); + if (ret) + return ret; for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, --- linux-3.13.0.orig/sound/soc/txx9/txx9aclc-ac97.c +++ linux-3.13.0/sound/soc/txx9/txx9aclc-ac97.c @@ -183,14 +183,16 @@ irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); drvdata->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base); - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; platform_set_drvdata(pdev, drvdata); drvdata->physbase = r->start; if (sizeof(drvdata->physbase) > sizeof(r->start) && --- linux-3.13.0.orig/lib/genalloc.c +++ linux-3.13.0/lib/genalloc.c @@ -316,7 +316,7 @@ * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage * @pool: pool to allocate from * @size: number of bytes to allocate from the pool - * @dma: dma-view physical address + * @dma: dma-view physical address return value. Use NULL if unneeded. * * Allocate the requested number of bytes from the specified pool. * Uses the pool allocation function (with first-fit algorithm by default). @@ -334,7 +334,8 @@ if (!vaddr) return NULL; - *dma = gen_pool_virt_to_phys(pool, vaddr); + if (dma) + *dma = gen_pool_virt_to_phys(pool, vaddr); return (void *)vaddr; } --- linux-3.13.0.orig/lib/Makefile +++ linux-3.13.0/lib/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o +GCOV_PROFILE_hweight.o := n CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS)) obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o --- linux-3.13.0.orig/lib/percpu_ida.c +++ linux-3.13.0/lib/percpu_ida.c @@ -132,22 +132,22 @@ /** * percpu_ida_alloc - allocate a tag * @pool: pool to allocate from - * @gfp: gfp flags + * @state: task state for prepare_to_wait * * Returns a tag - an integer in the range [0..nr_tags) (passed to * tag_pool_init()), or otherwise -ENOSPC on allocation failure. * * Safe to be called from interrupt context (assuming it isn't passed - * __GFP_WAIT, of course). + * TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, of course). * * @gfp indicates whether or not to wait until a free id is available (it's not * used for internal memory allocations); thus if passed __GFP_WAIT we may sleep * however long it takes until another thread frees an id (same semantics as a * mempool). * - * Will not fail if passed __GFP_WAIT. + * Will not fail if passed TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE. */ -int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp) +int percpu_ida_alloc(struct percpu_ida *pool, int state) { DEFINE_WAIT(wait); struct percpu_ida_cpu *tags; @@ -174,7 +174,8 @@ * * global lock held and irqs disabled, don't need percpu lock */ - prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE); + if (state != TASK_RUNNING) + prepare_to_wait(&pool->wait, &wait, state); if (!tags->nr_free) alloc_global_tags(pool, tags); @@ -191,16 +192,22 @@ spin_unlock(&pool->lock); local_irq_restore(flags); - if (tag >= 0 || !(gfp & __GFP_WAIT)) + if (tag >= 0 || state == TASK_RUNNING) break; + if (signal_pending_state(state, current)) { + tag = -ERESTARTSYS; + break; + } + schedule(); local_irq_save(flags); tags = this_cpu_ptr(pool->tag_cpu); } + if (state != TASK_RUNNING) + finish_wait(&pool->wait, &wait); - finish_wait(&pool->wait, &wait); return tag; } EXPORT_SYMBOL_GPL(percpu_ida_alloc);